pax_global_header00006660000000000000000000000064146377253040014525gustar00rootroot0000000000000052 comment=5733cb75d623434a3b06f497e919cca1e206cf03 sqlitebrowser-sqlitebrowser-5733cb7/000077500000000000000000000000001463772530400176745ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/.github/000077500000000000000000000000001463772530400212345ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/.github/FUNDING.yml000066400000000000000000000000161463772530400230460ustar00rootroot00000000000000patreon: db4s sqlitebrowser-sqlitebrowser-5733cb7/.github/ISSUE_TEMPLATE/000077500000000000000000000000001463772530400234175ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/.github/ISSUE_TEMPLATE/Bug_report.yaml000066400000000000000000000045751463772530400264260ustar00rootroot00000000000000name: Bug Report description: Create a report to help us improve title: "[Bug]: " labels: [] body: - type: markdown attributes: value: | Thanks for taking the time to fill out this bug report! - type: textarea id: what-did-you-do attributes: label: What did you do? description: Tell us, what did you do before the issue appeared? placeholder: I selected/clicked/opened... validations: required: true - type: textarea id: what-did-you-expect attributes: label: What did you expect to see? description: Also tell us, what did you expect to happen? placeholder: I expected that... validations: required: true - type: textarea id: what-happened attributes: label: What did you see instead? description: Finally tell us, what happened, that you did not expect? Screenshots or video recordings help. placeholder: What happened instead was... validations: required: true - type: dropdown id: version attributes: label: DB4S Version description: What version of DB Browser for SQLite are you running? options: - 3.13.0-rc1 - 3.12.2 - 3.12.1 - 3.12.0 - 3.11.x - 3.13.99 (nightly) - Other validations: required: true - type: dropdown id: os attributes: label: What OS are you seeing the problem on? multiple: true options: - Windows - Linux - MacOS - Other validations: required: true - type: input id: os-version attributes: label: OS version description: "Identify the OS version" placeholder: "Windows 10, Ubuntu Linux 20.04..." validations: required: false - type: textarea id: logs attributes: label: Relevant log output description: Please copy and paste any relevant log output (console, "SQL Log" pane, etc.). This will be automatically formatted into code, so no need for backticks. render: shell - type: checkboxes id: terms attributes: label: Prevention against duplicate issues description: By submitting this issue, you confirm that you have searched for similar issues before opening a new one. You could comment or subscribe to the found issue. options: - label: I have searched for similar issues required: true sqlitebrowser-sqlitebrowser-5733cb7/.github/ISSUE_TEMPLATE/Feature_request.yaml000066400000000000000000000014221463772530400274450ustar00rootroot00000000000000name: Feature Request description: Suggest an idea or request a new feature. title: "[Feature]: " labels: [] body: - type: markdown attributes: value: | Thanks for coming here to suggest a new feature. Please answer these questions before submitting your feature request. - type: textarea id: description attributes: label: Describe the new feature validations: required: true - type: textarea id: examples attributes: label: Does this feature exist in another product or project? Please provide a link validations: required: false - type: textarea id: screenshot attributes: label: Do you have a screenshot? Please add screenshots to help explain your idea. validations: required: false sqlitebrowser-sqlitebrowser-5733cb7/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000003031463772530400254030ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: GitHub Community Support url: https://github.com/sqlitebrowser/sqlitebrowser/discussions about: Please ask and answer questions here. sqlitebrowser-sqlitebrowser-5733cb7/.github/dependabot.yml000066400000000000000000000001661463772530400240670ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" sqlitebrowser-sqlitebrowser-5733cb7/.github/patch/000077500000000000000000000000001463772530400223335ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/.github/patch/CMakeLists.txt.patch000066400000000000000000000030451463772530400261730ustar00rootroot00000000000000diff --git a/CMakeLists.txt b/CMakeLists.txt index 1010923e..0b17700f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,24 +80,24 @@ if(MSVC) if(CMAKE_CL_64) # Paths for 64-bit windows builds set(OPENSSL_PATH "C:/dev/OpenSSL-Win64" CACHE PATH "OpenSSL Path") - set(QT5_PATH "C:/dev/Qt/5.12.12/msvc2017_64" CACHE PATH "Qt5 Path") + set(QT5_PATH "C:/Qt/5.15.2/msvc2019_64" CACHE PATH "Qt5 Path") # Choose between SQLCipher or SQLite, depending whether # -Dsqlcipher=on is passed on the command line if(sqlcipher) - set(SQLITE3_PATH "C:/git_repos/SQLCipher-Win64" CACHE PATH "SQLCipher Path") + set(SQLITE3_PATH "C:/dev/SQLCipher-Win64" CACHE PATH "SQLCipher Path") else() set(SQLITE3_PATH "C:/dev/SQLite-Win64" CACHE PATH "SQLite Path") endif() else() # Paths for 32-bit windows builds set(OPENSSL_PATH "C:/dev/OpenSSL-Win32" CACHE PATH "OpenSSL Path") - set(QT5_PATH "C:/dev/Qt/5.12.12/msvc2017" CACHE PATH "Qt5 Path") + set(QT5_PATH "C:/Qt/5.15.2/msvc2019" CACHE PATH "Qt5 Path") # Choose between SQLCipher or SQLite, depending whether # -Dsqlcipher=on is passed on the command line if(sqlcipher) - set(SQLITE3_PATH "C:/git_repos/SQLCipher-Win32" CACHE PATH "SQLCipher Path") + set(SQLITE3_PATH "C:/dev/SQLCipher-Win32" CACHE PATH "SQLCipher Path") else() set(SQLITE3_PATH "C:/dev/SQLite-Win32" CACHE PATH "SQLite Path") endif() sqlitebrowser-sqlitebrowser-5733cb7/.github/patch/README.md000066400000000000000000000001701463772530400236100ustar00rootroot00000000000000A collection of patch files used when a need change to a file in the source tree is required for GitHub Actions to work.sqlitebrowser-sqlitebrowser-5733cb7/.github/patch/product.wxs.patch000066400000000000000000000057031463772530400256610ustar00rootroot00000000000000diff --git a/installer/windows/product.wxs b/installer/windows/product.wxs index c040591a..12c3aee8 100644 --- a/installer/windows/product.wxs +++ b/installer/windows/product.wxs @@ -63,7 +63,8 @@ - + + @@ -84,6 +85,9 @@ + + + @@ -149,8 +153,11 @@ - + + + @@ -186,6 +193,9 @@ + + + sqlitebrowser-sqlitebrowser-5733cb7/.github/patch/translations.wxs.patch000066400000000000000000000017231463772530400267200ustar00rootroot00000000000000diff --git a/installer/windows/translations.wxs b/installer/windows/translations.wxs index f842e05b..0743a202 100644 --- a/installer/windows/translations.wxs +++ b/installer/windows/translations.wxs @@ -97,7 +97,7 @@ - + @@ -197,7 +197,7 @@ - + sqlitebrowser-sqlitebrowser-5733cb7/.github/patch/variables.wxi.patch000066400000000000000000000043221463772530400261330ustar00rootroot00000000000000diff --git a/installer/windows/variables.wxi b/installer/windows/variables.wxi index fbedf0c3..34a65831 100644 --- a/installer/windows/variables.wxi +++ b/installer/windows/variables.wxi @@ -40,8 +40,8 @@ Visual Studio 2017. The build "ARCH" will be set automatically. --> - - + + - - - - - - - - - - - - - - - + + + + + + + sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/000077500000000000000000000000001463772530400232715ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/build-appimage.yml000066400000000000000000000056321463772530400267020ustar00rootroot00000000000000name: Build - AppImage on: workflow_call: jobs: build: name: ${{ matrix.os }} - SQLCipher ${{ matrix.sqlcipher }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-20.04] sqlcipher: ["0", "1"] steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt update sudo apt install libqcustomplot-dev libqscintilla2-qt5-dev libqt5svg5 libsqlcipher-dev libsqlite3-dev qttools5-dev - if: matrix.sqlcipher == 0 name: Build SQLite run: | TARBALL=$(curl -s https://sqlite.org/download.html | awk '// {print}' | grep 'sqlite-autoconf' | cut -d ',' -f 3) SHA3=$(curl -s https://sqlite.org/download.html | awk '// {print}' | grep 'sqlite-autoconf' | cut -d ',' -f 5) curl -LsS -o sqlite.tar.gz https://sqlite.org/${TARBALL} VERIFY=$(openssl dgst -sha3-256 sqlite.tar.gz | cut -d ' ' -f 2) if [ "$SHA3" != "$VERIFY" ]; then exit 1 ; fi tar -xzf sqlite.tar.gz && cd sqlite-autoconf-* CPPFLAGS="-DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_MAX_VARIABLE_NUMBER=250000 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_STAT4=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1 -DSQLITE_MAX_ATTACHED=125 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_SNAPSHOT=1" ./configure --enable-shared=no make -j2 && sudo make install -j2 - name: Configure build run: | mkdir appbuild && mkdir appdir && cd appbuild cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=../appdir/usr -Wno-dev -DFORCE_INTERNAL_QSCINTILLA=ON -Dsqlcipher=${{ matrix.sqlcipher }} .. - name: Build working-directory: ./appbuild run: make install -j2 - name: Build AppImage run: | wget -c -nv "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" chmod a+x linuxdeployqt-continuous-x86_64.AppImage export VERSION=$(printf "dev-`git -C . rev-parse --short HEAD`") ./linuxdeployqt-continuous-x86_64.AppImage appdir/usr/share/applications/*.desktop -appimage - name: Rename a file run: | for i in DB_Browser_for_SQLite*; do mv "$i" "${i//_/.}"; done if [ "${{ matrix.sqlcipher }}" = "1" ]; then export FILE=$(ls DB.Browser.for.SQLite*.AppImage) export FILE=${FILE/SQLite/SQLCipher} mv DB.Browser.for.SQLite*.AppImage $FILE fi - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: build-artifacts-${{ matrix.os }}-${{ matrix.sqlcipher }} path: DB.Browser.for.*.AppImage retention-days: 1 sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/build-macos.yml000066400000000000000000000070131463772530400262140ustar00rootroot00000000000000name: Build - macOS on: workflow_call: inputs: NIGHTLY: default: false type: boolean jobs: build: name: ${{ matrix.os }} - SQLCipher ${{ matrix.sqlcipher }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [macos-14] sqlcipher: ["0", "1"] env: MACOSX_DEPLOYMENT_TARGET: 10.13 steps: - name: Checkout uses: actions/checkout@v4 # Uninstall Mono, which is included by default in GitHub-hosted macOS runners, # as it interferes with referencing our own compiled SQLite libraries. - name: Uninstall Mono run: | sudo rm -rfv /Library/Frameworks/Mono.framework sudo pkgutil --forget com.xamarin.mono-MDK.pkg sudo rm /etc/paths.d/mono-commands - name: Install dependencies run: | brew update brew tap sqlitebrowser/tap brew unlink openssl@3 brew install sqlb-openssl@3 brew install sqlb-qt@5 sqlb-sqlcipher sqlb-sqlite ninja npm install -g appdmg - name: Configure build run: | if [ "${{ inputs.NIGHTLY }}" = "true" ]; then if [ "${{ matrix.sqlcipher }}" = "1" ]; then sed -i "" 's/"DB Browser for SQLite"/"DB Browser for SQLCipher Nightly"/' CMakeLists.txt else sed -i "" 's/"DB Browser for SQLite"/"DB Browser for SQLite Nightly"/' CMakeLists.txt fi else if [ "${{ matrix.sqlcipher }}" = "1" ]; then sed -i "" 's/"DB Browser for SQLite"/"DB Browser for SQLCipher-dev-'$(git rev-parse --short --verify HEAD)'"/' CMakeLists.txt else sed -i "" 's/"DB Browser for SQLite"/"DB Browser for SQLite-dev-'$(git rev-parse --short --verify HEAD)'"/' CMakeLists.txt fi fi mkdir build && cd build cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -DcustomTap=1 -DENABLE_TESTING=ON -Dsqlcipher=${{ matrix.sqlcipher }} .. - name: Build working-directory: ./build run: ninja - name: Tests working-directory: ./build run: ninja test - name: Build Extension run: clang -I /opt/homebrew/opt/sqlb-sqlite/include -L /opt/homebrew/opt/sqlb-sqlite/lib -fno-common -dynamiclib src/extensions/extension-formats.c - if: github.event_name != 'pull_request' name: Notarization id: notarization run: chmod +x ./installer/macos/notarize.sh && ./installer/macos/notarize.sh env: APPLE_ID: ${{ secrets.MACOS_CODESIGN_APPLE_ID }} APPLE_PW: ${{ secrets.MACOS_CODESIGN_APPLE_PW }} DEV_ID: ${{ secrets.MACOS_CODESIGN_DEV_ID }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} KEYCHAIN_PW: ${{ secrets.MACOS_CODESIGN_KEYCHAIN_PW }} P12: ${{ secrets.MACOS_CODESIGN_P12 }} P12_PW: ${{ secrets.MACOS_CODESIGN_P12_PW }} NIGHTLY: ${{ inputs.NIGHTLY }} SQLCIPHER: ${{ matrix.sqlcipher }} TEAM_ID: ${{ secrets.MACOS_CODESIGN_TEAM_ID }} - if: steps.notarization.conclusion != 'skipped' name: Clear Keychain run: security delete-keychain $RUNNER_TEMP/app-signing.keychain-db continue-on-error: true - if: github.event_name != 'pull_request' name: Upload artifacts uses: actions/upload-artifact@v4 with: name: build-artifacts-${{ matrix.os }}-${{ matrix.sqlcipher }} path: DB.Browser.for.*.dmg sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/build-ubuntu.yml000066400000000000000000000037701463772530400264420ustar00rootroot00000000000000name: Build - Ubuntu on: release: types: [created] workflow_call: jobs: build: name: ${{ matrix.os }} - SQLCipher ${{ matrix.sqlcipher }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-20.04] sqlcipher: ["0", "1"] steps: - name: Checkout uses: actions/checkout@v4 - name: Install and cache dependencies uses: awalsh128/cache-apt-pkgs-action@v1.4.2 with: packages: libqcustomplot-dev libqscintilla2-qt5-dev libqt5svg5 libsqlcipher-dev libsqlite3-dev qttools5-dev - name: Configure CMake run: | cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=${PWD}/install \ -DCPACK_PACKAGE_DIRECTORY=${PWD}/package \ -DENABLE_TESTING=ON \ -Dsqlcipher=${{ matrix.sqlcipher }} - name: Run make run: cmake --build build --config Release -j --target install - name: Run tests run: ctest -V -C Release --test-dir build - if: github.event_name == 'release' name: Package run: | cmake --build build --config Release -j --target package cmake -E remove_directory package/_CPack_Packages - if: github.event_name == 'release' name: Upload package env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG: ${{ github.event.release.tag_name }} UPLOAD_URL: ${{ github.event.release.upload_url }} run: | set the env var TAG: $GITHUB_API_URL/repos/$GITHUB_REPOSITORY/releases/tags/$TAG | jq -r .upload_url) UPLOAD_URL=${UPLOAD_URL%\{*} # remove "{name,label}" suffix for pkg in package/*.*; do NAME=$(basename $pkg) MIME=$(file --mime-type $pkg|cut -d ' ' -f2) curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GITHUB_TOKEN" -H "Content-Type: $MIME" --data-binary @$pkg $UPLOAD_URL?name=$NAME done sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/build-windows.yml000066400000000000000000000235151463772530400266110ustar00rootroot00000000000000name: Build - Windows on: workflow_call: inputs: NIGHTLY: default: false type: boolean jobs: build: name: Build runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [windows-2019] arch: ["Win32", "Win64"] env: GH_TOKEN: ${{ github.token }} OPENSSL_VERSION: 1.1.1.2100 QT_VERSION: 5.15.2 steps: - name: Checkout uses: actions/checkout@v4 - name: Install OpenSSL run: | if ("${{ matrix.arch }}" -eq "Win32") { choco install openssl --x86 --version=${{ env.OPENSSL_VERSION}} } else { choco install openssl --version=${{ env.OPENSSL_VERSION}} } # When building SQLCipher, if we specify a path to OpenSSL and # there are spaces in the path, an error will occur, so to # avoid this, create the symlink. - name: Create OpenSSL symlink run: | mkdir C:\dev if ("${{ matrix.arch }}" -eq "Win32") { New-Item -Path "C:\dev\OpenSSL-${{ matrix.arch }}" -ItemType SymbolicLink -Value "C:\Program Files (x86)\OpenSSL-Win32\" } else { New-Item -Path "C:\dev\OpenSSL-${{ matrix.arch }}" -ItemType SymbolicLink -Value "C:\Program Files\OpenSSL" } - name: Install Qt uses: jurplel/install-qt-action@v3 with: arch: ${{ matrix.arch == 'Win32' && 'win32_msvc2019' || matrix.arch == 'Win64' && 'win64_msvc2019_64'}} cache: true cache-key-prefix: "cache" version: ${{ env.QT_VERSION }} - name: Download 'nalgeon/sqlean' run: | if ("${{ matrix.arch }}" -eq "Win32") { gh release download --pattern "sqlean-win-x86.zip" --repo "nalgeon/sqlean" Expand-Archive -Path sqlean-win-x86.zip -DestinationPath .\sqlean } else { gh release download --pattern "sqlean-win-x64.zip" --repo "nalgeon/sqlean" Expand-Archive -Path sqlean-win-x64.zip -DestinationPath .\sqlean } - name: Setup MSVC uses: ilammy/msvc-dev-cmd@v1 with: arch: ${{ matrix.arch == 'Win32' && 'amd64_x86' || matrix.arch == 'Win64' && 'amd64'}} - name: Install SQLite run: | $htmlContent = Invoke-WebRequest -Uri "https://sqlite.org/download.html" | Select-Object -ExpandProperty Content $regex = [regex]::new('PRODUCT,(\d+\.\d+\.\d+),(\d+/sqlite-amalgamation-\d+\.zip),\d+,(.+)') $match = $regex.Match($htmlContent) $relativeUrl = $match.Groups[2].Value $downloadLink = "https://sqlite.org/$relativeUrl" Invoke-WebRequest -Uri $downloadLink -OutFile 'sqlite.zip' Expand-Archive -Path sqlite.zip -DestinationPath C:\dev\ Move-Item -Path C:\dev\sqlite-amalgamation-* C:\dev\SQLite-${{ matrix.arch }} cd C:\dev\SQLite-${{ matrix.arch }} cl sqlite3.c -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_STAT4 -DSQLITE_SOUNDEX -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_GEOPOLY -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_MAX_ATTACHED=125 -DSQLITE_API="__declspec(dllexport)" -link -dll -out:sqlite3.dll - name: Install SQLite Extensions run: | cp .\src\extensions\extension-formats.c C:\dev\SQLite-${{ matrix.arch}}\ cp .\src\extensions\extension-formats.def C:\dev\SQLite-${{ matrix.arch}}\ cp .\src\extensions\extension-functions.c C:\dev\SQLite-${{ matrix.arch}}\ cp .\src\extensions\extension-functions.def C:\dev\SQLite-${{ matrix.arch}}\ cd C:\dev\SQLite-${{ matrix.arch}}\ cl /MD extension-formats.c -link -dll -def:extension-formats.def -out:formats.dll cl /MD extension-functions.c -link -dll -def:extension-functions.def -out:math.dll # FIXME: Disable building the 'fileio' extension for now (#3488) # If this issue is resolved, be sure to delete the related patch for WiX # curl -L -o fileio.c "https://sqlite.org/src/raw?filename=ext/misc/fileio.c&ci=trunk" # curl -L -o test_windirent.c "https://sqlite.org/src/raw?filename=src/test_windirent.c&ci=trunk" # curl -L -o test_windirent.h "https://sqlite.org/src/raw?filename=src/test_windirent.h&ci=trunk" # cl /MD fileio.c test_windirent.c -link sqlite3.lib -dll -out:fileio.dll - name: Install SQLCipher run: | cd C:\dev git clone https://github.com/sqlcipher/sqlcipher mv sqlcipher SQLCipher-${{ matrix.arch }} cd SQLCipher-${{ matrix.arch }} git switch $(git describe --tags --abbrev=0) nmake /f Makefile.msc sqlcipher.dll USE_AMALGAMATION=1 NO_TCL=1 SQLITE3DLL=sqlcipher.dll SQLITE3LIB=sqlcipher.lib SQLITE3EXE=sqlcipher.exe LTLINKOPTS="C:\dev\OpenSSL-${{ matrix.arch }}\lib\libcrypto.lib" OPT_FEATURE_FLAGS="-DSQLITE_TEMP_STORE=2 -DSQLITE_HAS_CODEC=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_STAT4=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_RTREE=1 -DSQLCIPHER_CRYPTO_OPENSSL=1 -DSQLITE_MAX_ATTACHED=125 -IC:\dev\OpenSSL-${{ matrix.arch }}\include" mkdir sqlcipher copy sqlite3.h sqlcipher - name: Patch CMakeLists.txt and WiX Toolset Variables run: | git apply .github\patch\CMakeLists.txt.patch git apply .github\patch\product.wxs.patch git apply .github\patch\translations.wxs.patch git apply .github\patch\variables.wxi.patch - name: Configure build (SQLite) run: | mkdir release-sqlite && cd release-sqlite if ("${{ matrix.arch }}" -eq "Win32") { cmake -G "Visual Studio 16 2019" -A "Win32" -DCMAKE_BUILD_TYPE=Release ..\ } else { cmake -G "Visual Studio 16 2019" ..\ } - name: Build (SQLite) run: cd release-sqlite && devenv /Build Release sqlitebrowser.sln /Project ALL_BUILD - name: Configure build (SQLCipher) run: | mkdir release-sqlcipher && cd release-sqlcipher if ("${{ matrix.arch }}" -eq "Win32") { cmake -G "Visual Studio 16 2019" -DCMAKE_BUILD_TYPE=Release -Dsqlcipher=1 -A "Win32" ..\ } else { cmake -G "Visual Studio 16 2019" -DCMAKE_BUILD_TYPE=Release -Dsqlcipher=1 ..\ } - name: Build (SQLCipher) run: | cd release-sqlcipher devenv /Build Release sqlitebrowser.sln /Project ALL_BUILD mv "Release\DB Browser for SQLite.exe" "Release\DB Browser for SQLCipher.exe" - if: github.event_name != 'pull_request' name: Create MSI env: ExePath: ${{ github.workspace }} OpenSSLPath: C:\dev\OpenSSL-${{ matrix.arch }} SQLCipherPath: C:\dev\SQLCipher-${{ matrix.arch }} SqleanPath: ${{ github.workspace }}\sqlean SQLitePath: C:\dev\SQLite-${{ matrix.arch }} run: | cd installer/windows ./build.cmd "${{ matrix.arch }}".ToLower() $ARCH="${{ matrix.arch }}".ToLower() $DATE=$(Get-Date -Format "yyyy-MM-dd") if ("${{ inputs.NIGHTLY }}" -eq "true") { mv DB.Browser.for.SQLite-*.msi "DB.Browser.for.SQLite-$DATE-$ARCH.msi" } else { mv DB.Browser.for.SQLite-*.msi "DB.Browser.for.SQLite-dev-$(git rev-parse --short HEAD)-$ARCH.msi" } - if: github.event_name != 'pull_request' name: Upload artifacts for code signing with SignPath id: unsigned-artifacts uses: actions/upload-artifact@v4 with: name: build-artifacts-${{ matrix.os}}-${{ matrix.arch }}-unsigned path: installer\windows\DB.Browser.for.SQLite-*.msi # Change the signing-policy-slug when you release an RC, RTM or stable release. - if: github.event_name != 'pull_request' name: Code signing with SignPath uses: signpath/github-action-submit-signing-request@v0.4 with: api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' github-artifact-id: '${{ steps.unsigned-artifacts.outputs.artifact-id }}' organization-id: '${{ secrets.SIGNPATH_ORGANIZATION_ID }}' output-artifact-directory: .\installer\windows project-slug: 'sqlitebrowser' signing-policy-slug: 'test-signing' wait-for-completion: true - if: github.event_name != 'pull_request' name: Create ZIP run: | $ARCH="${{ matrix.arch }}".ToLower() $DATE=$(Get-Date -Format "yyyy-MM-dd") if ("${{ inputs.NIGHTLY }}" -eq "true") { $FILENAME_FORMAT="DB.Browser.for.SQLite-$DATE-$ARCH.zip" } else { $FILENAME_FORMAT="DB.Browser.for.SQLite-dev-$(git rev-parse --short HEAD)-$ARCH.zip" } Start-Process msiexec.exe -ArgumentList "/a $(dir installer\windows\DB.Browser.for.SQLite-*.msi) /q TARGETDIR=$PWD\target\" -Wait if ("${{ matrix.arch }}" -eq "Win32") { move target\System\* "target\DB Browser for SQLite\" } else { move target\System64\* "target\DB Browser for SQLite\" } Compress-Archive -Path "target\DB Browser for SQLite\*" -DestinationPath $FILENAME_FORMAT - if: github.event_name != 'pull_request' name: Prepare artifacts run: | mkdir build-artifacts move installer\windows\DB.Browser.for.SQLite-*.msi build-artifacts\ move DB.Browser.for.SQLite-*.zip build-artifacts\ Compress-Archive -Path build-artifacts\* -DestinationPath build-artifacts-${{ matrix.arch }}.zip - if: github.event_name != 'pull_request' name: Upload artifacts uses: actions/upload-artifact@v4 with: name: build-artifacts-${{ matrix.os }}-${{ matrix.arch }} path: build-artifacts-${{ matrix.arch }}.zip sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/codeql.yml000066400000000000000000000062651463772530400252740ustar00rootroot00000000000000name: "CodeQL" on: push: branches: ["master"] pull_request: # The branches below must be a subset of the branches above branches: ["master"] schedule: - cron: "14 22 * * 6" jobs: analyze: name: Analyze runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: ["cpp", "python"] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Use only 'java' to analyze code written in Java, Kotlin or both # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - name: Checkout repository uses: actions/checkout@v4 - if: matrix.language == 'cpp' name: Install dependencies run: | sudo apt-get update sudo apt install build-essential git cmake libsqlite3-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools libsqlcipher-dev qtbase5-dev libqt5scintilla2-dev libqcustomplot-dev qttools5-dev # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - if: matrix.language == 'cpp' name: Build C++ run: | mkdir build && cd build cmake -Dsqlcipher=1 -Wno-dev .. make sudo make install # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). # If this step fails, then you should remove it and run the build manually (see below) - if: matrix.language != 'cpp' name: Autobuild uses: github/codeql-action/autobuild@v3 # â„¹ï¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # If the Autobuild fails above, remove it and uncomment the following three lines. # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. # - run: | # echo "Run, Build Application using script" # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/coverity.yml000066400000000000000000000014721463772530400256640ustar00rootroot00000000000000name: Coverity on: push: branches: [coverity_scan] defaults: run: shell: bash jobs: build: name: Coverity Scan runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install qttools5-dev libqt5scintilla2-dev libqcustomplot-dev libsqlite3-dev libqt5svg5 libsqlcipher-dev qt5-default - name: Configure cmake run: | cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DENABLE_TESTING=ON -Dsqlcipher=1 . - name: Build and scan uses: vapier/coverity-scan-action@v1 with: project: sqlitebrowser%2Fsqlitebrowser token: ${{ secrets.COVERITY_TOKEN }} email: "github@mkleusberg.de" command: make sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/cppcmake-nightly.yml000066400000000000000000000007751463772530400272640ustar00rootroot00000000000000name: Build and Deploy Nightly Builds on: schedule: - cron: '0 0 * * *' # Every day at midnight UTC workflow_dispatch: jobs: build-macos: uses: ./.github/workflows/build-macos.yml secrets: inherit with: NIGHTLY: true build-windows: uses: ./.github/workflows/build-windows.yml secrets: inherit with: NIGHTLY: true release: needs: [build-macos, build-windows] uses: ./.github/workflows/release.yml secrets: inherit with: NIGHTLY: true sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/cppcmake.yml000066400000000000000000000012261463772530400256000ustar00rootroot00000000000000name: CI on: push: branches: [master] pull_request: workflow_dispatch: permissions: contents: write jobs: build-appimage: if: github.event_name != 'pull_request' uses: ./.github/workflows/build-appimage.yml build-macos: uses: ./.github/workflows/build-macos.yml secrets: inherit build-ubuntu: uses: ./.github/workflows/build-ubuntu.yml secrets: inherit build-windows: uses: ./.github/workflows/build-windows.yml secrets: inherit release: if: github.event_name != 'pull_request' needs: [build-appimage, build-macos, build-windows] uses: ./.github/workflows/release.yml secrets: inherit sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/release.yml000066400000000000000000000024031463772530400254330ustar00rootroot00000000000000name: Release on: workflow_call: inputs: NIGHTLY: default: false type: boolean env: tag_name: ${{ inputs.NIGHTLY == true && 'nightly' || 'continuous' }} jobs: release: runs-on: ubuntu-latest steps: - name: Delete existing tag and release uses: dev-drprasad/delete-tag-and-release@v1.1 with: delete_release: true github_token: ${{ secrets.GITHUB_TOKEN }} tag_name: ${{ env.tag_name }} - run: mkdir target - name: Download artifacts uses: actions/download-artifact@v4 with: path: target - name: Remove unsigned Windows build run: rm -rfv target/*unsigned* - run: find target -type f -exec mv -v {} target \; - name: Unarchive Windows's build artifacts run: for f in target/*.zip; do unzip -d target/ "$f"; done - name: Remove archived Windows's build artifacts run: rm -v target/build-artifacts-*.zip - name: Release uses: softprops/action-gh-release@v2 with: files: target/* prerelease: true tag_name: ${{ env.tag_name }} # For reference: Uploading nightly builds to the nightly server is processed on the nightly server side. sqlitebrowser-sqlitebrowser-5733cb7/.github/workflows/winget.yml000066400000000000000000000005771463772530400253220ustar00rootroot00000000000000name: Publish to WinGet on: release: types: [released] jobs: publish: # Action can only be run on windows runs-on: windows-latest steps: - uses: vedantmgoyal2009/winget-releaser@v2 with: identifier: DBBrowserForSQLite.DBBrowserForSQLite installers-regex: '\.msi$' # Only .msi files token: ${{ secrets.WINGET_TOKEN }} sqlitebrowser-sqlitebrowser-5733cb7/.gitignore000066400000000000000000000010771463772530400216710ustar00rootroot00000000000000Makefile sqlitebrowser.pro.user .qmake.stash CMakeLists.txt.user CMakeFiles *.cmake *.cxx_parameters # ignore any build folders build*/ # folder with temporary test data testdata/ src/.ui/ src/sqlitebrowser src/Makefile* src/debug src/release # ignore compiled translation files src/translations/*.qm # ignore compiled macOS app src/*.app/ # no one needs the txt file src/grammar/sqlite3TokenTypes.txt libs/*/Makefile* libs/*/*/Makefile* libs/*/debug/ libs/*/*/debug/ libs/*/release/ libs/*/*/release/ libs/*/*.a libs/*/*/*.a # Ignore .DS_Store files on OSX .DS_Store sqlitebrowser-sqlitebrowser-5733cb7/BUILDING.md000066400000000000000000000264551463772530400214270ustar00rootroot00000000000000## BUILD INSTRUCTIONS AND REQUIREMENTS DB Browser for SQLite requires Qt as well as SQLite.
For more information on Qt please consult http://www.qt.io and for SQLite please see https://sqlite.org/. Please note that all versions after 3.12.1 will require: * A C++ compiler with support for C++14 or later * Qt 5.15.9 later Without these or with older versions you won't be able to compile DB Browser for SQLite any more.
This applies to all platforms. However, most likely you won't have to worry about these as most systems meet these requirements today. If you can, please use Qt 5.15.9 or any later version.
Even though Qt 5.5 and 5.6 are supported by us, there might be glitches and minor problems when using them.
Also, it is not possible to build universal binary for macOS using Qt versions lower than 5.15.9. The wiki has information that is a bit more detailed or less common, but may be useful: https://github.com/sqlitebrowser/sqlitebrowser/wiki ---- - [BUILD INSTRUCTIONS AND REQUIREMENTS](#build-instructions-and-requirements) - [Linux](#linux) - [Generic Linux and FreeBSD](#generic-linux-and-freebsd) - [CentOS / Fedora Linux](#centos--fedora-linux) - [Debian / Ubuntu Linux](#debian--ubuntu-linux) - [OpenSUSE](#opensuse) - [macOS](#macos) - [Build an `.app` bundle](#build-an-app-bundle) - [Windows](#windows) - [Compiling on Windows with MSVC](#compiling-on-windows-with-msvc) - [Cross compiling for Windows](#cross-compiling-for-windows) - [Build with SQLCipher support](#build-with-sqlcipher-support) - [Building and running the Unit Tests](#building-and-running-the-unit-tests) - [Build the unit tests](#build-the-unit-tests) - [Run the unit tests](#run-the-unit-tests) ---- ### Linux #### Generic Linux and FreeBSD The only requirements for building this code are the presence of Qt5 and SQLite 3.
Qt can be included as a static or shared library, depending on the current Qt configuration on the building machine. Provided you have Qt and cmake installed and configured, simply run: cmake . There is one potential problem... several Linux distributions provide a QScintilla package compiled for (only) Qt4. If it's present it can confuse CMake, which will use it during compiling. The resulting program just crashes instead of running. If you experience that kind of crash, try using this cmake command instead when compiling: cmake -DFORCE_INTERNAL_QSCINTILLA=ON That tells cmake to compile QScintilla itself, using the source code version we bundle. After the cmake line, run this: make in the main directory. This will generate the sqlitebrowser (or `sqlitebrowser.exe`, or `sqlitebrowser.app`) application in the src subdirectory. On some distributions you can then install this in the correct places by running: sudo make install The same process works for building the code in any platform supported by Qt (including other Unix systems with X11.) #### CentOS / Fedora Linux >**Note** - On CentOS or an older version of Fedora, you may need to use `yum` instead of `dnf`.
>**Note 2** - On CentOS 7.x, you need to replace the `qwt-qt5-devel` package name with `qt5-qtbase-devel` in the `dnf install` line.
>**Note 3** - On CentOS 8 (Stream), you need to replace the `qt-devel` package name with `qt5-devel` in the `dnf install` line below.
>Make sure the `PowerTools` repo is enabled. For further information: https://access.redhat.com/discussions/5417621 ```bash sudo dnf install cmake gcc-c++ git qt-devel qt5-linguist qwt-qt5-devel sqlite-devel git clone https://github.com/sqlitebrowser/sqlitebrowser cd sqlitebrowser mkdir build && cd build cmake .. make sudo make install ``` This should complete without errors, and `sqlitebrowser` should now be launch-able from the command line. #### Debian / Ubuntu Linux ```bash sudo apt install build-essential cmake git libqcustomplot-dev libqt5scintilla2-dev libsqlcipher-dev \ libsqlite3-dev qt5-qmake qtbase5-dev qtbase5-dev-tools qtchooser qttools5-dev qttools5-dev-tools git clone https://github.com/sqlitebrowser/sqlitebrowser cd sqlitebrowser mkdir build && cd build cmake .. make sudo make install ``` >**Note** - Use `cmake -DFORCE_INTERNAL_QSCINTILLA=ON -Dsqlcipher=1 -Wno-dev ..`
>if you're using Debian and meet errors during compiling. This should complete without errors, giving you an executable file called `sqlitebrowser`. Done. :) > Also, we have a CI workflow for Ubuntu, you can check it out [here](https://github.com/sqlitebrowser/sqlitebrowser/blob/master/.github/workflows/build-ubuntu.yml) #### OpenSUSE ```bash zypper in -y build build, cmake, gcc, gcc-c++, git-core, libQt5Core5, libQt5Core5-32bit, libqt5-qtbase, libqt5-qtbase-devel, libqt5-qttools, libqt5-qttools-devel, libsqlite3-0, sqlcipher-devel, sqlite3-devel git clone https://github.com/sqlitebrowser/sqlitebrowser cd sqlitebrowser mkdir build && cd build cmake -DFORCE_INTERNAL_QSCINTILLA=ON .. make sudo make install ``` ### macOS #### Build an `.app` bundle The application can be compiled to an .app bundle, suitable for placing in /Applications. Building an .app bundle version takes a bit more effort, but isn't too hard.
It requires SQLite and at least Qt 5.15.9 to be installed first. These are the [Homebrew](http://brew.sh) steps, though other package managers should work: ```bash brew tap sqlitebrowser/tap # If you are using Apple Silicon Mac brew install sqlb-qt@5 sqlb-sqlcipher sqlb-sqlite ``` > You can don't need SQLCipher support, you can skip `sqlb-sqlcipher`. Then it's just a matter of getting the source: $ git clone https://github.com/sqlitebrowser/sqlitebrowser.git **Note** - Don't clone the repo to a directory with a quote character (') in its name (eg ~/tmp/foo'), as compiling will error out. And compiling it: ```bash cd sqlitebrowser mkdir build && cd build cmake -DcustomTap=1 .. cmake --build . mv DB\ Browser\ for\ SQLite.app /Applications ``` > If you want to build universal binary, change the `cmake` command to
> `cmake -DcustomTap=1 -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" ..`
> Of course, this requires you to have an Apple Silicon Mac. An icon for "DB Browser for SQLite" should now be in your main macOS Applications list, ready to launch. > Also, we have a CI workflow for macOS, you can check it out [here](https://github.com/sqlitebrowser/sqlitebrowser/blob/master/.github/workflows/build-macos.yml) ### Windows #### Compiling on Windows with MSVC Complete setup, build, and packaging instructions with MSVC 2013 x64 are online here:     https://github.com/sqlitebrowser/sqlitebrowser/wiki/Setting-up-a-Win64-development-environment-for-DB4S #### Cross compiling for Windows These are instructions to cross compile within a Linux system a Windows binary and installer. Requirements: * mxe cross compile environment → http://mxe.cc * cmake * sqlitebrowser sources Get the following mxe packages: make gcc sqlite qt nsis After successful compilation go into your mxedir/usr/bin and add 3 symlinks: ln -s i686-pc-mingw32-windres windres ln -s i686-pc-mingw32-makensis makensis ln -s /usr/bin/lrelease Now cd into your sqlitebrowser source directory and create a build directory for the windows binary and create the correct makefiles: mkdir build-win cd build-win cmake -DCMAKE_TOOLCHAIN_FILE=/path to mxe/usr/i686-pc-mingw32/share/cmake/mxe-conf.cmake .. Before compiling we have to add the mxe/usr/bin directory to the PATH (so windres and makensis can be found): export PATH=/path to mxe/usr/bin:$PATH Now compile: make If you additionally want an NSIS installer: make package Done. > Also, we have a CI workflow for Windows, you can check it out [here](https://github.com/sqlitebrowser/sqlitebrowser/blob/master/.github/workflows/build-windows.yml) ## Build with SQLCipher support When built with SQLCipher support, DB Browser for SQLite will allow you to open and edit databases encrypted using SQLCipher as well as standard SQLite3 databases. Before compiling make sure you have the necessary SQLCipher development files installed. On Linux this can usually be accomplished by just installing the correct package (e.g. 'libsqlcipher-dev' on Debian-based distributions). On macOS the easiest way is to install it via Homebrew ('brew install sqlcipher'). On Windows unfortunately it's a bit more difficult: You'll have to download and compile the code as described on the [SQLCipher website](https://www.zetetic.net/sqlcipher/) before you can proceed. If SQLCipher is installed, simply follow the standard instructions for your platform but enable the 'sqlcipher' build option by replacing any calls to cmake like this: ``` If it says... Change it to... cmake cmake -Dsqlcipher=1 cmake .. cmake -Dsqlcipher=1 .. ``` ## Building and running the Unit Tests DB Browser for SQLite has unit tests in the "src/tests" subdirectory. ### Build the unit tests The unit tests are enabled using the cmake variable `ENABLE_TESTING`
it can be passed when running `cmake` to configure sqlitebrowser, for example like this: ```bash mkdir build && cd build cmake -DENABLE_TESTING=ON .. make ``` ### Run the unit tests Tests can be then run using `make test` or invoking `ctest` directly, for example like this: ``` $ ctest -V UpdateCTestConfiguration from :SRCDIR/build/DartConfiguration.tcl UpdateCTestConfiguration from :SRCDIR/build/DartConfiguration.tcl Test project SRCDIR/build Constructing a list of tests Done constructing a list of tests Checking test dependency graph... Checking test dependency graph end test 1 Start 1: test-sqlobjects 1: Test command: SRCDIR/build/src/tests/test-sqlobjects 1: Test timeout computed to be: 9.99988e+06 1: ********* Start testing of TestTable ********* 1: Config: Using QTest library 4.8.6, Qt 4.8.6 1: PASS : TestTable::initTestCase() 1: PASS : TestTable::sqlOutput() 1: PASS : TestTable::autoincrement() 1: PASS : TestTable::notnull() 1: PASS : TestTable::withoutRowid() 1: PASS : TestTable::foreignKeys() 1: PASS : TestTable::parseSQL() 1: PASS : TestTable::parseSQLdefaultexpr() 1: PASS : TestTable::parseSQLMultiPk() 1: PASS : TestTable::parseSQLForeignKey() 1: PASS : TestTable::parseSQLSingleQuotes() 1: PASS : TestTable::parseSQLKeywordInIdentifier() 1: PASS : TestTable::parseSQLWithoutRowid() 1: PASS : TestTable::parseNonASCIIChars() 1: PASS : TestTable::parseSQLEscapedQuotes() 1: PASS : TestTable::parseSQLForeignKeys() 1: PASS : TestTable::parseSQLCheckConstraint() 1: PASS : TestTable::createTableWithIn() 1: PASS : TestTable::createTableWithNotLikeConstraint() 1: PASS : TestTable::cleanupTestCase() 1: Totals: 20 passed, 0 failed, 0 skipped 1: ********* Finished testing of TestTable ********* 1/2 Test #1: test-sqlobjects .................. Passed 0.02 sec test 2 Start 2: test-import 2: Test command: SRCDIR/build/src/tests/test-import 2: Test timeout computed to be: 9.99988e+06 2: ********* Start testing of TestImport ********* 2: Config: Using QTest library 4.8.6, Qt 4.8.6 2: PASS : TestImport::initTestCase() 2: PASS : TestImport::csvImport() 2: PASS : TestImport::cleanupTestCase() 2: Totals: 3 passed, 0 failed, 0 skipped 2: ********* Finished testing of TestImport ********* 2/2 Test #2: test-import ...................... Passed 0.01 sec 100% tests passed, 0 tests failed out of 2 Total Test time (real) = 0.04 sec ``` Everything should PASS, with no failures, and nothing skipped. sqlitebrowser-sqlitebrowser-5733cb7/CHANGELOG.md000066400000000000000000000135431463772530400215130ustar00rootroot00000000000000# CHANGELOG for DB4S All notable changes to the **Database Browser for SQLite** - DB4S - project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased - nightly] - soon to be [3.13.0] - 2024-07-xx We are proud to announce DB4S 3.13.0 - a very large update over the previous 3.12.2 version released in 2021. It incorporates literally hundreds of enhancements and bug fixes. The list below highlights the major changes. See the [commit history](https://github.com/sqlitebrowser/sqlitebrowser/commits/master/) for fine-grained details. ### Added - **General** - Update to SQLite version 3.46.0 - Integration with [dbhub.io](https://dbhub.io) - macOS ARM version - Sign Windows builds with [SignPath.io](https://SignPath.io) - **Appearance and GUI Enhancements** - Add .NET DateTime.Ticks to date display format - Add a refresh button to the Database Structure tab - Add an extra tab for editing check constraints to the Edit Table dialog - Add an extra tab for editing foreign keys to the Edit Table dialog - Add auto completion for math functions - Add Ctrl+Enter as shortcut for executing query - Add new menu item to import from CSV data in the system clipboard - Add new menu item to show the row counts of all tables - Allow users to export or import user-settings file in a GUI environment - Add file, line number and function to Error Log - Add GUID display format - Add iif SQL function to the list of known functions in Execute SQL tab - Add new option to freeze columns in the Browse Data tab - Allow multiple TableBrowser tabs in the Browse Data tab - Bar charts now display labels in x axis when NULL values present - Scale large images in ImageViewer to fit the viewport by default - Enable HiDPI on all platforms by default - Change tabbed table browisng to use docks instead - Change mouse cursor to the pointing hand when Ctrl+Shift are pressed - Change to 'Preference' expression for consistent - Data Browser: avoid showing BLOBs containing unprintable characters as text - Data Browser: export query results as JSON - Edit Database Cell: fixed potential for data loss and better feedback - Edit Table: alternating row colors in tables for better readability - Edit Table: Change the key icons from header to tooltips - Fix indentation - always use 4 spaces - Plot Dock: use more precision for small numbers and less for big numbers - Plot: fix selecting points to select corresponding line in table - Plot: show x and y values on a tooltip when hovering over the plot - Table Browser: "Clear Filters" button to clear the global filter - Table Browser: give hint of table sorted or filtered state in the toolbar - Table Browser: Support extended selections - Add copy column name to table viewer - Allow multiple -t/--table parameters on the command line - Open recent files in read-only mode using a different shortcut - Allow selecting fixed format for big integer numbers - Allow the user to change MaxRecentFiles - Always load settings for Browse Data tabs - Always raise new Data Browser tabs to the foreground - **SQL Processing** - parser: Add support for IS (NOT) DISTINCT FROM expressions - Execute SQL: add Ctrl+Shift+T for "Open SQL file(s)" - Fall back to asking SQLite when parsing a table schema has failed - Update schema after attaching/detaching a database in an Execute SQL tab - Also update schema when clicking the Refresh button in Browse Data tab - Improvements for working in the SQL Execution area using keyboard - When modifying a view use DROP VIEW IF EXISTS instead of just DROP VIEW - Add basic support for new RETURNING keyword - Change WHERE clauses of queries to use column names instead of indexes - DB Schema: drag & drop SELECT queries - Export query results as JSON - Export SQL: fix quoting of BLOB values and non-printable strings - Export SQL: option to keep original CREATE statements - Improve support for BLOB columns as primary key - Use LIMIT + OFFSET when generating SELECT statements instead - **Files** - Import: Add import-csv option to command line to import CSV files - Move recent files items to new submenu and add clear recent file function - CLI: Reuse `--table` as table name for a CSV Import - CSV Export: binary BLOB to base64 - CSV Import: fix importing into existing table - CSV Import: give option to use system locale conventions - Import: allow CSV separator and quote to be passed from command line - Import: announce support for CSV files in Desktop file - Import: do not remove characters from CSV header fields - Import: don't assume an empty file is a text file - Import: support importing the single file argument as a CSV file - **Configuration** - New setting for configuring brace matching background - New setting for having close button on tabs (default) or not - New settings for changing the selection appearance in editors - Add the ability to support custom config files ### Changed There have been too many changes since the last full release to list separately. Important changes are listed in the **Added** section above. ### Fixed There have been too many bug fixes since the last full release to list separately. Please check out 3.13.0 and let us know if your issue still exists ### Removed - _none_ ### Translation - Add Dutch, Indonesian, Swedish translation - Update Arabic, Brazilian Portuguese, Chinese, French, German, Italian, Japanese, Korean, Polish, Spanish translation ## [3.12.2] - 2021-05-17 Release version of DB4S - DB Browser for SQLite. The basic features of the program are described in the [README.](https://github.com/sqlitebrowser/sqlitebrowser) Download release versions from [https://sqlitebrowser.org/dl/](https://sqlitebrowser.org/dl/) sqlitebrowser-sqlitebrowser-5733cb7/CMakeLists.txt000066400000000000000000000471711463772530400224460ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.15) project(sqlitebrowser VERSION 3.13.99 DESCRIPTION "GUI editor for SQLite databases" ) # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS. if(POLICY CMP0025) # https://cmake.org/cmake/help/latest/policy/CMP0025.html cmake_policy(SET CMP0025 NEW) endif() # Fix warning of AUTOMOC behavior if(POLICY CMP0071) # https://cmake.org/cmake/help/latest/policy/CMP0071.html cmake_policy(SET CMP0071 NEW) endif() # Fix warning of Cached Variables if(POLICY CMP0102) # https://cmake.org/cmake/help/latest/policy/CMP0102.html cmake_policy(SET CMP0102 NEW) endif() include(GNUInstallDirs) OPTION(BUILD_STABLE_VERSION "Don't build the stable version by default" OFF) # Choose between building a stable version or nightly (the default), depending on whether '-DBUILD_STABLE_VERSION=1' is passed on the command line or not. OPTION(ENABLE_TESTING "Enable the unit tests" OFF) OPTION(FORCE_INTERNAL_QSCINTILLA "Don't use the distribution's QScintilla library even if there is one" OFF) OPTION(FORCE_INTERNAL_QCUSTOMPLOT "Don't use distribution's QCustomPlot even if available" ON) OPTION(FORCE_INTERNAL_QHEXEDIT "Don't use distribution's QHexEdit even if available" ON) OPTION(ALL_WARNINGS "Enable some useful warning flags" OFF) OPTION(sqlcipher "Build with SQLCipher library" OFF) OPTION(customTap "Using SQLCipher, SQLite and Qt installed through our custom Homebrew tap" OFF) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) if(APPLE) add_executable(${PROJECT_NAME} MACOSX_BUNDLE) elseif(WIN32) add_executable(${PROJECT_NAME} WIN32) else() add_executable(${PROJECT_NAME}) endif() # Determine the git commit hash execute_process( COMMAND git -C ${CMAKE_CURRENT_SOURCE_DIR} rev-parse --short --verify HEAD OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) if (GIT_COMMIT_HASH STREQUAL "") MESSAGE(WARNING "Could not determine git commit hash") set(GIT_COMMIT_HASH "Unknown") endif() add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}") if(NOT BUILD_STABLE_VERSION) # BUILD_VERSION is the current date in YYYYMMDD format. It is only # used by the nightly version to add the date of the build. # Default defined in Version.h.in string(TIMESTAMP BUILD_VERSION "%Y%m%d") target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_VERSION=${BUILD_VERSION}) endif() set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}") if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() if(MSVC) if(CMAKE_CL_64) # Paths for 64-bit windows builds set(OPENSSL_PATH "C:/dev/OpenSSL-Win64" CACHE PATH "OpenSSL Path") set(QT5_PATH "C:/dev/Qt/5.12.12/msvc2017_64" CACHE PATH "Qt5 Path") # Choose between SQLCipher or SQLite, depending whether # -Dsqlcipher=on is passed on the command line if(sqlcipher) set(SQLITE3_PATH "C:/git_repos/SQLCipher-Win64" CACHE PATH "SQLCipher Path") else() set(SQLITE3_PATH "C:/dev/SQLite-Win64" CACHE PATH "SQLite Path") endif() else() # Paths for 32-bit windows builds set(OPENSSL_PATH "C:/dev/OpenSSL-Win32" CACHE PATH "OpenSSL Path") set(QT5_PATH "C:/dev/Qt/5.12.12/msvc2017" CACHE PATH "Qt5 Path") # Choose between SQLCipher or SQLite, depending whether # -Dsqlcipher=on is passed on the command line if(sqlcipher) set(SQLITE3_PATH "C:/git_repos/SQLCipher-Win32" CACHE PATH "SQLCipher Path") else() set(SQLITE3_PATH "C:/dev/SQLite-Win32" CACHE PATH "SQLite Path") endif() endif() list(PREPEND CMAKE_PREFIX_PATH ${QT5_PATH} ${SQLITE3_PATH}) endif() if(APPLE) # For Intel Mac's if(EXISTS /usr/local/opt/qt5) list(APPEND CMAKE_PREFIX_PATH "/usr/local/opt/qt5") endif() # For Apple Silicon Mac's if(EXISTS /opt/homebrew/opt/qt5) list(APPEND CMAKE_PREFIX_PATH "/opt/homebrew/opt/qt5") endif() if(EXISTS /opt/homebrew/opt/sqlitefts5) list(PREPEND CMAKE_PREFIX_PATH "/opt/homebrew/opt/sqlitefts5") endif() # For Apple Silicon Mac's and install dependencies via our Homebrew tap(sqlitebrowser/homebrew-tap) if(customTap AND EXISTS /opt/homebrew/opt/) list(PREPEND CMAKE_PREFIX_PATH "/opt/homebrew/opt/sqlb-qt@5") list(PREPEND CMAKE_PREFIX_PATH "/opt/homebrew/opt/sqlb-sqlite") if(sqlcipher) list(APPEND SQLCIPHER_INCLUDE_DIR "/opt/homebrew/include") list(APPEND SQLCIPHER_LIBRARY "/opt/homebrew/opt/sqlb-sqlcipher/lib/libsqlcipher.0.dylib") endif() endif() endif() find_package(Qt5 REQUIRED COMPONENTS Concurrent Gui LinguistTools Network PrintSupport Test Widgets Xml) if(NOT FORCE_INTERNAL_QSCINTILLA) find_package(QScintilla 2.8.10) endif() if(NOT FORCE_INTERNAL_QCUSTOMPLOT) find_package(QCustomPlot) endif() if(NOT FORCE_INTERNAL_QHEXEDIT) find_package(QHexEdit) endif() target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/libs/json) if(NOT QSCINTILLA_FOUND) add_subdirectory(libs/qscintilla/Qt4Qt5) endif() if(NOT QHexEdit_FOUND) add_subdirectory(libs/qhexedit) endif() if(NOT QCustomPlot_FOUND) add_subdirectory(libs/qcustomplot-source) endif() if(ENABLE_TESTING) enable_testing() endif() # generate file with version information configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h ) target_sources(${PROJECT_NAME} PRIVATE src/sql/sqlitetypes.h src/sql/Query.h src/sql/ObjectIdentifier.h src/csvparser.h src/sqlite.h src/Data.h src/IconCache.h src/sql/parser/ParserDriver.h src/sql/parser/sqlite3_lexer.h src/sql/parser/sqlite3_location.h src/sql/parser/sqlite3_parser.hpp ) target_sources(${PROJECT_NAME} PRIVATE src/sqlitedb.h src/AboutDialog.h src/EditIndexDialog.h src/EditDialog.h src/EditTableDialog.h src/AddRecordDialog.h src/ExportDataDialog.h src/ExtendedTableWidget.h src/FilterTableHeader.h src/ImportCsvDialog.h src/MainWindow.h src/Settings.h src/PreferencesDialog.h src/SqlExecutionArea.h src/VacuumDialog.h src/sqlitetablemodel.h src/RowLoader.h src/RowCache.h src/sqltextedit.h src/docktextedit.h src/DbStructureModel.h src/dbstructureqitemviewfacade.h src/Application.h src/CipherDialog.h src/ExportSqlDialog.h src/SqlUiLexer.h src/FileDialog.h src/ColumnDisplayFormatDialog.h src/FilterLineEdit.h src/RemoteDatabase.h src/ForeignKeyEditorDelegate.h src/PlotDock.h src/RemoteDock.h src/RemoteModel.h src/RemotePushDialog.h src/FindReplaceDialog.h src/ExtendedScintilla.h src/FileExtensionManager.h src/CondFormatManager.h src/CipherSettings.h src/Palette.h src/CondFormat.h src/RunSql.h src/ProxyDialog.h src/SelectItemsPopup.h src/TableBrowser.h src/ImageViewer.h src/RemoteLocalFilesModel.h src/RemoteCommitsModel.h src/RemoteNetwork.h src/TableBrowserDock.h ) target_sources(${PROJECT_NAME} PRIVATE src/AboutDialog.cpp src/EditIndexDialog.cpp src/EditDialog.cpp src/EditTableDialog.cpp src/AddRecordDialog.cpp src/ExportDataDialog.cpp src/ExtendedTableWidget.cpp src/FilterTableHeader.cpp src/ImportCsvDialog.cpp src/MainWindow.cpp src/Settings.cpp src/PreferencesDialog.cpp src/SqlExecutionArea.cpp src/VacuumDialog.cpp src/sqlitedb.cpp src/sqlitetablemodel.cpp src/RowLoader.cpp src/sql/sqlitetypes.cpp src/sql/Query.cpp src/sql/ObjectIdentifier.cpp src/sqltextedit.cpp src/docktextedit.cpp src/csvparser.cpp src/DbStructureModel.cpp src/dbstructureqitemviewfacade.cpp src/main.cpp src/Application.cpp src/CipherDialog.cpp src/ExportSqlDialog.cpp src/SqlUiLexer.cpp src/FileDialog.cpp src/ColumnDisplayFormatDialog.cpp src/FilterLineEdit.cpp src/RemoteDatabase.cpp src/ForeignKeyEditorDelegate.cpp src/PlotDock.cpp src/RemoteDock.cpp src/RemoteModel.cpp src/RemotePushDialog.cpp src/FindReplaceDialog.cpp src/ExtendedScintilla.cpp src/FileExtensionManager.cpp src/CondFormatManager.cpp src/Data.cpp src/CipherSettings.cpp src/Palette.cpp src/CondFormat.cpp src/RunSql.cpp src/ProxyDialog.cpp src/IconCache.cpp src/SelectItemsPopup.cpp src/TableBrowser.cpp src/sql/parser/ParserDriver.cpp src/sql/parser/sqlite3_lexer.cpp src/sql/parser/sqlite3_parser.cpp src/ImageViewer.cpp src/RemoteLocalFilesModel.cpp src/RemoteCommitsModel.cpp src/RemoteNetwork.cpp src/TableBrowserDock.cpp ) set(SQLB_FORMS src/AboutDialog.ui src/EditIndexDialog.ui src/EditDialog.ui src/EditTableDialog.ui src/AddRecordDialog.ui src/ExportDataDialog.ui src/ImportCsvDialog.ui src/MainWindow.ui src/PreferencesDialog.ui src/SqlExecutionArea.ui src/VacuumDialog.ui src/CipherDialog.ui src/ExportSqlDialog.ui src/ColumnDisplayFormatDialog.ui src/PlotDock.ui src/RemoteDock.ui src/RemotePushDialog.ui src/FindReplaceDialog.ui src/FileExtensionManager.ui src/CondFormatManager.ui src/ProxyDialog.ui src/SelectItemsPopup.ui src/TableBrowser.ui src/ImageViewer.ui ) set(SQLB_RESOURCES src/icons/icons.qrc src/translations/flags/flags.qrc src/translations/translations.qrc src/certs/CaCerts.qrc src/qdarkstyle/dark/darkstyle.qrc src/qdarkstyle/light/lightstyle.qrc ) set(SQLB_MISC src/sql/parser/sqlite3_parser.yy src/sql/parser/sqlite3_lexer.ll ) # Translation files set(SQLB_TSS "${CMAKE_SOURCE_DIR}/src/translations/sqlb_ar_SA.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_cs.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_zh.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_zh_TW.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_de.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_es_ES.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_fr.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_ru.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_pl.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_pt_BR.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_en_GB.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_ko_KR.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_tr.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_uk_UA.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_it.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_ja.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_nl.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_sv.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_id.ts" "${CMAKE_SOURCE_DIR}/src/translations/sqlb_ro.ts" ) # Windows image format plugin files set(WIN_IMG_PLUGINS "${QT5_PATH}/plugins/imageformats/qgif.dll" "${QT5_PATH}/plugins/imageformats/qicns.dll" "${QT5_PATH}/plugins/imageformats/qico.dll" "${QT5_PATH}/plugins/imageformats/qjpeg.dll" "${QT5_PATH}/plugins/imageformats/qsvg.dll" "${QT5_PATH}/plugins/imageformats/qtga.dll" "${QT5_PATH}/plugins/imageformats/qtiff.dll" "${QT5_PATH}/plugins/imageformats/qwbmp.dll" "${QT5_PATH}/plugins/imageformats/qwebp.dll" ) set(WIN_IMG_PLUGINS_DEBUG "${QT5_PATH}/plugins/imageformats/qgifd.dll" "${QT5_PATH}/plugins/imageformats/qicnsd.dll" "${QT5_PATH}/plugins/imageformats/qicod.dll" "${QT5_PATH}/plugins/imageformats/qjpegd.dll" "${QT5_PATH}/plugins/imageformats/qsvgd.dll" "${QT5_PATH}/plugins/imageformats/qtgad.dll" "${QT5_PATH}/plugins/imageformats/qtiffd.dll" "${QT5_PATH}/plugins/imageformats/qwbmpd.dll" "${QT5_PATH}/plugins/imageformats/qwebpd.dll" ) # License files set(LICENSE_FILES LICENSE LICENSE-PLUGINS ) qt5_wrap_ui(SQLB_FORM_HDR ${SQLB_FORMS}) if(SQLB_TSS) # add translations foreach(SQLB_TS ${SQLB_TSS}) set_source_files_properties("${SQLB_TS}" PROPERTIES OUTPUT_LOCATION "${CMAKE_SOURCE_DIR}/src/translations") endforeach() qt5_add_translation(SQLB_QMS ${SQLB_TSS}) endif() qt5_add_resources(SQLB_RESOURCES_RCC ${SQLB_RESOURCES}) #icon and correct libs/subsystem for windows if(WIN32) #enable version check for windows add_definitions(-DCHECKNEWVERSION) if(MINGW) # resource compilation for MinGW add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/sqlbicon.o" COMMAND windres "-I${CMAKE_CURRENT_BINARY_DIR}" "-i${CMAKE_CURRENT_SOURCE_DIR}/src/winapp.rc" -o "${CMAKE_CURRENT_BINARY_DIR}/sqlbicon.o" VERBATIM ) target_sources(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/sqlbicon.o") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-subsystem,windows") set(WIN32_STATIC_LINK -Wl,-Bstatic -lssl -lcrypto -lws2_32) set(ADDITIONAL_LIBS lzma) else() target_sources(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/winapp.rc") endif() else() set(LPTHREAD pthread) endif() #enable version check for macOS if(APPLE) add_definitions(-DCHECKNEWVERSION) endif() # SQLCipher option if(sqlcipher) add_definitions(-DENABLE_SQLCIPHER) set(LIBSQLITE_NAME SQLCipher) else() set(LIBSQLITE_NAME SQLite3) endif() # add extra library path for MacOS and FreeBSD set(EXTRAPATH APPLE OR ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") if(EXTRAPATH) list(PREPEND CMAKE_PREFIX_PATH /usr/local/opt/sqlite/lib) list(PREPEND CMAKE_PREFIX_PATH /usr/local/opt/sqlitefts5/lib) endif() find_package(${LIBSQLITE_NAME}) if (sqlcipher) target_link_libraries(${PROJECT_NAME} SQLCipher::SQLCipher) else() target_link_libraries(${PROJECT_NAME} SQLite::SQLite3) endif() if(MSVC) if(sqlcipher) find_file(SQLITE3_DLL sqlcipher.dll) else() find_file(SQLITE3_DLL sqlite3.dll) endif() endif() target_include_directories(${PROJECT_NAME} PRIVATE src) target_sources(${PROJECT_NAME} PRIVATE ${SQLB_FORM_HDR} ${SQLB_MOC} ${SQLB_RESOURCES_RCC} ${SQLB_MISC} ) # Warnings if(ALL_WARNINGS AND CMAKE_COMPILER_IS_GNUCC) target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wpedantic -Wconversion -Wsign-conversion) target_compile_options(${PROJECT_NAME} PRIVATE -Wdouble-promotion -Wformat=2 -Wlogical-op -Wuseless-cast) if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0) target_compile_options(${PROJECT_NAME} PRIVATE -Wnull-dereference -Wduplicated-cond -Wduplicated-branches) endif() endif() set(QT_LIBS Qt5::Gui Qt5::Test Qt5::PrintSupport Qt5::Widgets Qt5::Network Qt5::Concurrent Qt5::Xml) target_link_libraries(${PROJECT_NAME} ${LPTHREAD} ${QT_LIBS} ${WIN32_STATIC_LINK} ${ADDITIONAL_LIBS} ) target_link_libraries(${PROJECT_NAME} QHexEdit::QHexEdit QCustomPlot::QCustomPlot QScintilla::QScintilla ) if(MSVC) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "DB Browser for SQLite") set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE") set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE") set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_DEFINITIONS_RELWITHDEBINFO "_CONSOLE") if(CMAKE_CL_64) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS,5.02 /ENTRY:mainCRTStartup") set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS,5.02") else() set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS,5.01 /ENTRY:mainCRTStartup") set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS,5.01") endif() endif() if((NOT WIN32 AND NOT APPLE) OR MINGW) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) endif() if(UNIX) target_link_libraries(${PROJECT_NAME} dl) endif() if(ENABLE_TESTING) add_subdirectory(src/tests) endif() if(UNIX) install(FILES src/icons/${PROJECT_NAME}.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps/ ) install(FILES images/logo.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps/ RENAME ${PROJECT_NAME}.svg ) install(FILES distri/${PROJECT_NAME}.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications/ ) install(FILES distri/${PROJECT_NAME}.desktop.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo/ ) endif() if(WIN32 AND MSVC) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION "/" LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) set(QT5_BIN_PATH ${QT5_PATH}/bin) # The Qt5 Debug configuration library files have a 'd' postfix install(FILES ${QT5_BIN_PATH}/Qt5Cored.dll ${QT5_BIN_PATH}/Qt5Guid.dll ${QT5_BIN_PATH}/Qt5Networkd.dll ${QT5_BIN_PATH}/Qt5PrintSupportd.dll ${QT5_BIN_PATH}/Qt5Widgetsd.dll ${QT5_BIN_PATH}/Qt5Concurrentd.dll ${QT5_BIN_PATH}/Qt5Svgd.dll DESTINATION "/" CONFIGURATIONS Debug ) # The Qt5 Release configuration files don't have a postfix install(FILES ${QT5_BIN_PATH}/Qt5Core.dll ${QT5_BIN_PATH}/Qt5Gui.dll ${QT5_BIN_PATH}/Qt5Network.dll ${QT5_BIN_PATH}/Qt5PrintSupport.dll ${QT5_BIN_PATH}/Qt5Widgets.dll ${QT5_BIN_PATH}/Qt5Concurrent.dll ${QT5_BIN_PATH}/Qt5Svg.dll DESTINATION "/" CONFIGURATIONS Release ) # The files below are common to all configurations install(FILES ${SQLITE3_DLL} ${OPENSSL_PATH}/libeay32.dll ${OPENSSL_PATH}/ssleay32.dll DESTINATION "/" ) install(FILES ${QT5_PATH}/plugins/platforms/qwindows.dll DESTINATION platforms ) # The XML dll install(FILES "${QT5_PATH}/bin/Qt5Xmld.dll" DESTINATION "/" CONFIGURATIONS Debug ) install(FILES "${QT5_PATH}/bin/Qt5Xml.dll" DESTINATION "/" CONFIGURATIONS Release ) # The image format plugins install(FILES ${WIN_IMG_PLUGINS_DEBUG} DESTINATION imageformats CONFIGURATIONS Debug ) install(FILES ${WIN_IMG_PLUGINS} DESTINATION imageformats CONFIGURATIONS Release ) # The license files install(FILES ${LICENSE_FILES} DESTINATION licenses ) # The batch file launcher install(FILES distri/winlaunch.bat DESTINATION "/" ) endif() if(APPLE) set_target_properties(${PROJECT_NAME} PROPERTIES BUNDLE True OUTPUT_NAME "DB Browser for SQLite" MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/src/app.plist ) endif() # CPack configuration set(CPACK_STRIP_FILES ON) set(CPACK_DEBIAN_PACKAGE_PRIORITY optional) set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON) set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Tristan Stenner ") set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) if(APPLE) set(CPACK_DEFAULT_GEN TBZ2) elseif(WIN32) set(CPACK_DEFAULT_GEN ZIP) set(CPACK_NSIS_MODIFY_PATH ON) set(CPACK_WIX_CMAKE_PACKAGE_REGISTRY ON) set(CPACK_WIX_UPGRADE_GUID "78c885a7-e9c8-4ded-9b62-9abe47466950") elseif(UNIX) set(CPACK_DEFAULT_GEN DEB) set(CPACK_SET_DESTDIR 1) set(CPACK_INSTALL_PREFIX "/usr") endif() set(CPACK_GENERATOR ${CPACK_DEFAULT_GEN} CACHE STRING "CPack pkg type(s) to generate") include(CPack) sqlitebrowser-sqlitebrowser-5733cb7/LICENSE000066400000000000000000000011261463772530400207010ustar00rootroot00000000000000DB Browser for SQLite is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. Modification or redistribution is permitted under the conditions of these licenses. Check `LICENSE-GPL-3.0` for the full text of the GNU General Public License Version 3. Check `LICENSE-MPL-2.0` for the full text of the Mozilla Public License Version 2. Check `LICENSE-MIT` for the full text of the MIT License. and that is the license for the `nalgeon/sqlean` library. Check `LICENSE-PLUGINS` for other rights regarding included third-party resources. sqlitebrowser-sqlitebrowser-5733cb7/LICENSE-GPL-3.0000066400000000000000000001045131463772530400216230ustar00rootroot00000000000000 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. Copyright (C) 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: Copyright (C) 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 . sqlitebrowser-sqlitebrowser-5733cb7/LICENSE-MIT000066400000000000000000000021241463772530400213270ustar00rootroot00000000000000MIT License Copyright (c) 2021+ Anton Zhiyanov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sqlitebrowser-sqlitebrowser-5733cb7/LICENSE-MPL-2.0000066400000000000000000000405251463772530400216320ustar00rootroot00000000000000Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. sqlitebrowser-sqlitebrowser-5733cb7/LICENSE-PLUGINS000066400000000000000000000073251463772530400220270ustar00rootroot00000000000000DB Browser for SQLite includes support for TIFF and WebP images. The support for these comes from the LibTIFF and WebP projects, which have their own (Open Source) licenses, different to ours. LibTIFF - http://www.simplesystems.org/libtiff/ Copyright (c) 1988-1997 Sam Leffler Copyright (c) 1991-1997 Silicon Graphics, Inc. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that (i) the above copyright notices and this permission notice appear in all copies of the software and related documentation, and (ii) the names of Sam Leffler and Silicon Graphics may not be used in any advertising or publicity relating to the software without the specific, prior written permission of Sam Leffler and Silicon Graphics. THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. WebP - https://developers.google.com/speed/webp/ Copyright (c) 2010, Google Inc. All rights reserved. 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 Google 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 HOLDER 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. Icons - https://codefisher.org/pastel-svg/ Most of the icons come from the Pastel SVG icon set created by Michael Buckley. We have obtained a special license (Creative Commons Attribution Share Alike 4.0 http://creativecommons.org/licenses/by-sa/4.0/) but you might be required to redistribute it under Creative Commons Attribution NonCommercial Share Alike 4.0 http://creativecommons.org/licenses/by-nc-sa/4.0/ Check https://codefisher.org/pastel-svg/ for clarification. The construction emoji for the icon used in the nightly version come from the OpenMoji under CC BY-SA 4.0 license. Check https://openmoji.org/library/emoji-1F6A7/ and https://openmoji.org/faq/ for clarification. Some icons might have other open licenses, check history of the files under `src/icons`.sqlitebrowser-sqlitebrowser-5733cb7/README.md000066400000000000000000000362161463772530400211630ustar00rootroot00000000000000# DB Browser for SQLite [![Join the chat at https://gitter.im/sqlitebrowser/sqlitebrowser][gitter-img]][gitter] [![Wiki][wiki-img]][wiki] [![Patreon][patreon-img]][patreon]
[![C/C++ CI][ghaction-img]][ghaction] [![AppVeyor CI][appveyor-img]][appveyor] [![Qt][qt-img]][qt]
[![CodeQL](https://github.com/sqlitebrowser/sqlitebrowser/actions/workflows/codeql.yml/badge.svg)](https://github.com/sqlitebrowser/sqlitebrowser/actions/workflows/codeql.yml) [![Coverity][coverity-img]][coverity]
[![Download][download-img]][download] [![snapcraft](https://snapcraft.io/sqlitebrowser/badge.svg)](https://snapcraft.io/sqlitebrowser) [![snapcraft](https://snapcraft.io/sqlitebrowser/trending.svg?name=0)](https://snapcraft.io/sqlitebrowser) ![DB Browser for SQLite Screenshot](https://github.com/sqlitebrowser/sqlitebrowser/raw/master/images/sqlitebrowser.png "DB Browser for SQLite Screenshot") ## Table of Contents - [DB Browser for SQLite](#db-browser-for-sqlite) - [Table of Contents](#table-of-contents) - [What it is](#what-it-is) - [What it is not](#what-it-is-not) - [Wiki](#wiki) - [Continuous, Nightly builds](#continuous-nightly-builds) - [Windows](#windows) - [Continuous, Nightly builds](#continuous-nightly-builds-1) - [macOS](#macos) - [Stable release](#stable-release) - [Continuous, Nightly builds](#continuous-nightly-builds-2) - [Linux](#linux) - [Arch Linux](#arch-linux) - [Debian](#debian) - [Fedora](#fedora) - [openSUSE](#opensuse) - [Ubuntu and Derivatives](#ubuntu-and-derivatives) - [Stable release](#stable-release-1) - [Nightly builds](#nightly-builds) - [Other Linux](#other-linux) - [FreeBSD](#freebsd) - [Snap packages](#snap-packages) - [Snap Nightlies](#snap-nightlies) - [Snap Stable](#snap-stable) - [Nix Package](#nix-packages) - [Flox](#flox) - [Compiling](#compiling) - [X (Known as Twitter)](#x-known-as-twitter) - [Website](#website) - [Old project page](#old-project-page) - [Releases](#releases) - [History](#history) - [Contributors](#contributors) - [License](#license) ## What it is _DB Browser for SQLite_ (DB4S) is a high quality, visual, open source tool to create, design, and edit database files compatible with SQLite. DB4S is for users and developers who want to create, search, and edit databases. DB4S uses a familiar spreadsheet-like interface, so complicated SQL commands do not have to be learned. Controls and wizards are available for users to: * Create and compact database files * Create, define, modify and delete tables * Create, define, and delete indexes * Browse, edit, add, and delete records * Search records * Import and export records as text * Import and export tables from/to CSV files * Import and export databases from/to SQL dump files * Issue SQL queries and inspect the results * Examine a log of all SQL commands issued by the application * Plot simple graphs based on table or query data ## What it is not Even though DB4S comes with a spreadsheet-like interface, it is not meant to replace your spreadsheet application. We implement a few convenience functions which go beyond a simple database frontend but do not add them when they do not make sense in a database context or are so complex to implement that they will only ever be a poor replacement for your favorite spreadsheet application. We are a small team with limited time after all. Thanks for your understanding :) ## Wiki For user and developer documentation, check out our Wiki at: https://github.com/sqlitebrowser/sqlitebrowser/wiki. ## Continuous, Nightly builds Download continuous builds for AppImage, macOS and Windows here: * https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/continuous > Note: A continuous build is generated when a new commit is added to the `master` branch.
Download nightly builds for Windows and macOS here: * https://nightlies.sqlitebrowser.org/latest ## Windows Download Windows releases here: * https://sqlitebrowser.org/dl/#windows Or use Chocolatey: ``` choco install sqlitebrowser ``` Or use winget: ``` winget install -e --id DBBrowserForSQLite.DBBrowserForSQLite ``` Or use scoop: ``` scoop install sqlitebrowser ``` #### Continuous, Nightly builds Continuous builds are available here: * https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/continuous Nightly builds are available here: * https://nightlies.sqlitebrowser.org/latest ## macOS DB Browser for SQLite works well on macOS. * macOS 10.15 (Catalina) - 14.0 (Sonoma) are tested and known to work. #### Stable release Download macOS releases here: * https://sqlitebrowser.org/dl/#macos The latest macOS binary can be installed via [Homebrew Cask](https://caskroom.github.io/ "Homebrew Cask"): ``` brew install --cask db-browser-for-sqlite ``` #### Continuous, Nightly builds Continuous builds are available here: * https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/continuous Nightly builds are available here: * https://nightlies.sqlitebrowser.org/latest and also you can be installed via [Homebrew Cask](https://caskroom.github.io/ "Homebrew Cask"): ``` brew tap homebrew/cask-versions # for the version without SQLCipher support brew install --cask db-browser-for-sqlite-nightly # for the version with SQLCipher support brew install --cask db-browser-for-sqlcipher-nightly ``` It also has its own Homebrew tap the include Cask for older version.
For more information, see the following: https://github.com/sqlitebrowser/homebrew-tap ## Linux DB Browser for SQLite works well on Linux. ### Arch Linux Arch Linux provides an [up to date version](https://archlinux.org/packages/extra/x86_64/sqlitebrowser/) Install with the following command: sudo pacman -S sqlitebrowser ### Debian Debian focuses more on stability rather than newest features.
Therefore packages will typically contain an older (but well tested) version, compared to the latest release. Update the cache using: sudo apt-get update Install the package using: sudo apt-get install sqlitebrowser ### Fedora Install for Fedora (i386 and x86_64) by issuing the following command: sudo dnf install sqlitebrowser ### openSUSE sudo zypper install sqlitebrowser ### Ubuntu and Derivatives #### Stable release For Ubuntu and derivatives, [@deepsidhu1313](https://github.com/deepsidhu1313) provides a PPA with the latest release here: * https://launchpad.net/~linuxgndu/+archive/ubuntu/sqlitebrowser To add this PPA just type in this command in terminal: sudo add-apt-repository -y ppa:linuxgndu/sqlitebrowser Then update the cache using: sudo apt-get update Install the package using: sudo apt-get install sqlitebrowser Packages for Older Ubuntu releases are supported while launchpad keeps building those or if Older Ubuntu release has dependency packages that are required to build the latest version of Sqlitebrowser. We don't remove builds from our ppa repos, so users can still install older version of sqlitebrowser if they like. Alternatively Linux users can also switch to Snap packages if Snap packages are supported by the distro they are using. #### Nightly builds Nightly builds are available here: * https://launchpad.net/~linuxgndu/+archive/ubuntu/sqlitebrowser-testing To add this PPA, type these commands into the terminal: sudo add-apt-repository -y ppa:linuxgndu/sqlitebrowser-testing Then update the cache using: sudo apt-get update Install the package using: sudo apt-get install sqlitebrowser ### Other Linux On others, compile DB4S using the instructions in [BUILDING.md](BUILDING.md). ## FreeBSD DB Browser for SQLite works well on FreeBSD, and there is a port for it (thanks to [lbartoletti](https://github.com/lbartoletti) :smile:).
DB4S can be installed using either this command: make -C /usr/ports/databases/sqlitebrowser install or this command: pkg install sqlitebrowser ## Snap packages [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/sqlitebrowser) #### Snap Nightlies snap install sqlitebrowser --devmode #### Snap Stable snap install sqlitebrowser ## Nix Packages `sqlitebrowser` is packaged and available in nixpkgs. It can be used with the experimental flakes and nix-command features with: nix profile install nixpkgs#sqlitebrowser Or with the `nix-env` or `nix-shell` commands: nix-shell -p sqlitebrowser ### Flox `sqlitebrowser` can be installed into a Flox environment with. flox install sqlitebrowser ## Compiling Instructions for compiling on Windows, macOS, Linux, and FreeBSD are in [BUILDING](BUILDING.md). ## X (Known as Twitter) Follow us on X: https://x.com/sqlitebrowser ## Website * https://sqlitebrowser.org ## Old project page * https://sourceforge.net/projects/sqlitebrowser ## Releases * [Version 3.12.2 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.12.2) - 2021-05-18 * [Version 3.12.1 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.12.1) - 2020-11-09 * [Version 3.12.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.12.0) - 2020-06-16 * [Version 3.11.2 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.11.2) - 2019-04-03 * [Version 3.11.1 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.11.1) - 2019-02-18 * [Version 3.11.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.11.0) - 2019-02-07 * [Version 3.10.1 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.10.1) - 2017-09-20 * [Version 3.10.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.10.0) - 2017-08-20 * [Version 3.9.1 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.9.1) - 2016-10-03 * [Version 3.9.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.9.0) - 2016-08-24 * [Version 3.8.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.8.0) - 2015-12-25 * [Version 3.7.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.7.0) - 2015-06-14 * [Version 3.6.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.6.0) - 2015-04-27 * [Version 3.5.1 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.5.1) - 2015-02-08 * [Version 3.5.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.5.0) - 2015-01-31 * [Version 3.4.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.4.0) - 2014-10-29 * [Version 3.3.1 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.3.1) - 2014-08-31 - Project renamed from "SQLite Database Browser" * [Version 3.3.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.3.0) - 2014-08-24 * [Version 3.2.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/sqlb-3.2.0) - 2014-07-06 * [Version 3.1.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/sqlb-3.1.0) - 2014-05-17 * [Version 3.0.3 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/sqlb-3.0.3) - 2014-04-28 * [Version 3.0.2 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/sqlb-3.0.2) - 2014-02-12 * [Version 3.0.1 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/sqlb-3.0.1) - 2013-12-02 * [Version 3.0 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/sqlb-3.0) - 2013-09-15 * [Version 3.0rc1 released](https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/rc1) - 2013-09-09 - Project now on GitHub * Version 2.0b1 released - 2009-12-10 - Based on Qt4.6 * Version 1.2 released - 2005-04-05 * Version 1.1 released - 2004-07-20 * Version 1.01 released - 2003-10-02 * Version 1.0 released to public domain - 2003-08-19 ## History This program was developed originally by Mauricio Piacentini ([@piacentini](https://github.com/piacentini)) from Tabuleiro Producoes as the Arca Database Browser. The original version was used as a free companion tool to the Arca Database Xtra, a commercial product that embeds SQLite databases with some additional extensions to handle compressed and binary data. The original code was trimmed and adjusted to be compatible with standard SQLite 2.x databases. The resulting program was renamed SQLite Database Browser, and released into the Public Domain by Mauricio. Icons were contributed by [Raquel Ravanini](http://www.raquelravanini.com), also from Tabuleiro. Jens Miltner ([@jmiltner](https://github.com/jmiltner)) contributed the code to support SQLite 3.x databases for the 1.2 release. Pete Morgan ([@daffodil](https://github.com/daffodil)) created an initial project on GitHub with the code in 2012, where several contributors fixed and improved pieces over the years. René Peinthor ([@rp-](https://github.com/rp-)) and Martin Kleusberg ([@MKleusberg](https://github.com/MKleusberg)) then became involved, and have been the main driving force from that point. Justin Clift ([@justinclift](https://github.com/justinclift)) helps out with testing on OSX, and started the new github.com/sqlitebrowser organisation on GitHub. [John T. Haller](https://johnhaller.com), of [PortableApps.com](https://portableapps.com) fame, created the new logo. He based it on the Tango icon set (public domain). In August 2014, the project was renamed to "Database Browser for SQLite" at the request of [Richard Hipp](https://www.hwaci.com/drh) (creator of [SQLite](https://sqlite.org)), as the previous name was creating unintended support issues. In September 2014, the project was renamed to "DB Browser for SQLite", to avoid confusion with an existing application called "Database Browser". ## Contributors View the list by going to the [__Contributors__ tab](https://github.com/sqlitebrowser/sqlitebrowser/graphs/contributors). ## License See the [LICENSE](LICENSE) file for licensing information. [gitter-img]: https://badges.gitter.im/sqlitebrowser/sqlitebrowser.svg [gitter]: https://gitter.im/sqlitebrowser/sqlitebrowser [slack-img]: https://img.shields.io/badge/chat-on%20slack-orange.svg [slack]: https://join.slack.com/t/db4s/shared_invite/enQtMzc3MzY5OTU4NDgzLWRlYjk0ZmE5ZDEzYWVmNDQxYTYxNmJjNWVkMjI3ZmVjZTY2NDBjODY3YzNhNTNmZDVlNWI2ZGFjNTk5MjJkYmU [download-img]: https://img.shields.io/github/downloads/sqlitebrowser/sqlitebrowser/total.svg [download]: https://github.com/sqlitebrowser/sqlitebrowser/releases [qt-img]: https://img.shields.io/badge/Qt-cmake-green.svg [qt]: https://www.qt.io [coverity-img]: https://img.shields.io/coverity/scan/11712.svg [coverity]: https://scan.coverity.com/projects/sqlitebrowser-sqlitebrowser [patreon-img]: https://img.shields.io/badge/donate-Patreon-coral.svg [patreon]: https://www.patreon.com/bePatron?u=11578749 [wiki-img]: https://img.shields.io/badge/docs-Wiki-blue.svg [wiki]: https://github.com/sqlitebrowser/sqlitebrowser/wiki [ghaction-img]: https://github.com/sqlitebrowser/sqlitebrowser/actions/workflows/cppcmake.yml/badge.svg [ghaction]: https://github.com/sqlitebrowser/sqlitebrowser/actions/workflows/cppcmake.yml [appveyor-img]: https://ci.appveyor.com/api/projects/status/github/sqlitebrowser/sqlitebrowser?svg=true [appveyor]: https://github.com/sqlitebrowser/sqlitebrowser/blob/master/appveyor.yml sqlitebrowser-sqlitebrowser-5733cb7/SECURITY.md000066400000000000000000000011061463772530400214630ustar00rootroot00000000000000# Security Policy ## Reporting a Vulnerability We take security bugs in DB Browser for SQLite and related projects seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions. We kindly ask that you consider reporting a security vulnerability by doing one of the following: 1. Use the GitHub Security Advisory's ["Report a Vulnerability"](https://github.com/sqlitebrowser/sqlitebrowser/security/advisories/new) tab. 2. Send an email to [security@sqlitebrowser.org](mailto:security@sqlitebrowser.org) sqlitebrowser-sqlitebrowser-5733cb7/cmake/000077500000000000000000000000001463772530400207545ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/cmake/FindQCustomPlot.cmake000066400000000000000000000046101463772530400250120ustar00rootroot00000000000000# Attempt to locate QCustomPlot # Once done this will define: # # QCUSTOMPLOT_FOUND - system has QCustomPlot # QCUSTOMPLOT_INCLUDE_DIRS - the include directories for QCustomPlot # QCUSTOMPLOT_LIBRARIES - Link these to use QCustomPlot # # Copyright (C) 2019, Scott Furry, # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. find_library(QCustomPlot_LIBRARY NAMES qcustomplot qcustomplot-qt5) set(QCustomPlot_LIBRARIES "${QCustomPlot_LIBRARY}") find_path(QCustomPlot_INCLUDE_DIR qcustomplot.h) set(QCustomPlot_INCLUDE_DIRS "${QCustomPlot_INCLUDE_DIR}") include(FindPackageHandleStandardArgs) find_package_handle_standard_args( QCustomPlot DEFAULT_MSG QCustomPlot_LIBRARIES QCustomPlot_INCLUDE_DIRS ) mark_as_advanced( QCustomPlot_INCLUDE_DIRS QCustomPlot_LIBRARIES ) if (QCustomPlot_FOUND AND NOT TARGET QCustomPlot::QCustomPlot) add_library(QCustomPlot::QCustomPlot UNKNOWN IMPORTED) set_target_properties(QCustomPlot::QCustomPlot PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${QCustomPlot_INCLUDE_DIRS} IMPORTED_LOCATION ${QCustomPlot_LIBRARIES} ) endif() sqlitebrowser-sqlitebrowser-5733cb7/cmake/FindQHexEdit.cmake000066400000000000000000000045051463772530400242360ustar00rootroot00000000000000# Attempt to locate QHexEdit # Once done this will define: # # QHEXEDIT_FOUND - system has QHexEdit # QHEXEDIT_INCLUDE_DIRS - the include directories for QHexEdit # QHEXEDIT_LIBRARIES - Link these to use QHexEdit # # Copyright (C) 2019, Scott Furry, # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. find_library(QHexEdit_LIBRARY NAMES qhexedit qhexedit-qt5) set(QHexEdit_LIBRARIES "${QHexEdit_LIBRARY}") find_path(QHexEdit_INCLUDE_DIR qhexedit.h PATH_SUFFIXES qhexedit2) set(QHexEdit_INCLUDE_DIRS "${QHexEdit_INCLUDE_DIR}") include(FindPackageHandleStandardArgs) find_package_handle_standard_args( QHexEdit DEFAULT_MSG QHexEdit_LIBRARIES QHexEdit_INCLUDE_DIRS ) mark_as_advanced( QHexEdit_INCLUDE_DIRS QHexEdit_LIBRARIES ) if (QHexEdit_FOUND AND NOT TARGET QHexEdit::QHexEdit) add_library(QHexEdit::QHexEdit UNKNOWN IMPORTED) set_target_properties(QHexEdit::QHexEdit PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${QHexEdit_INCLUDE_DIRS} IMPORTED_LOCATION ${QHexEdit_LIBRARIES} ) endif()sqlitebrowser-sqlitebrowser-5733cb7/cmake/FindQScintilla.cmake000066400000000000000000000134351463772530400246300ustar00rootroot00000000000000# QScintilla is a port to Qt of Neil Hodgson's Scintilla C++ editor control # available at http://www.riverbankcomputing.com/software/qscintilla/ # # The module defines the following variables: # QSCINTILLA_FOUND - the system has QScintilla # QSCINTILLA_INCLUDE_DIR - where to find qsciscintilla.h # QSCINTILLA_INCLUDE_DIRS - qscintilla includes # QSCINTILLA_LIBRARY - where to find the QScintilla library # QSCINTILLA_LIBRARIES - aditional libraries # QSCINTILLA_MAJOR_VERSION - major version # QSCINTILLA_MINOR_VERSION - minor version # QSCINTILLA_PATCH_VERSION - patch version # QSCINTILLA_VERSION_STRING - version (ex. 2.6.2) # QSCINTILLA_ROOT_DIR - root dir (ex. /usr/local) #============================================================================= # Copyright 2010-2013, Julien Schueller # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. 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. # # 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. # The views and conclusions contained in the software and documentation are those # of the authors and should not be interpreted as representing official policies, # either expressed or implied, of the FreeBSD Project. #============================================================================= # When using pkg-config, paths may contain odd slash placement. Each # include directory is pre-processed here. Resultant list variable # then used for search hinting. Depends on successful find_package(Qt5). set(Qt5QScintillaHintDirs) if(UNIX) foreach(item ${Qt5Widgets_INCLUDE_DIRS}) # remove slash at end of line STRING(REGEX REPLACE "\\/$" "" item ${item}) # replace double slashes is single slashes STRING(REGEX REPLACE "\\/\\/" "/" item ${item}) list(APPEND Qt5QScintillaHintDirs "${item}/Qsci") endforeach() endif() find_path ( QSCINTILLA_INCLUDE_DIR qsciscintilla.h HINTS /usr/local/include/Qsci /usr/local/opt/qscintilla2/include/Qsci ${Qt5QScintillaHintDirs} ) set ( QSCINTILLA_INCLUDE_DIRS ${QSCINTILLA_INCLUDE_DIR} ) # version set ( _VERSION_FILE ${QSCINTILLA_INCLUDE_DIR}/qsciglobal.h ) if ( EXISTS ${_VERSION_FILE} ) file ( STRINGS ${_VERSION_FILE} _VERSION_LINE REGEX "define[ ]+QSCINTILLA_VERSION_STR" ) if ( _VERSION_LINE ) string ( REGEX REPLACE ".*define[ ]+QSCINTILLA_VERSION_STR[ ]+\"(.*)\".*" "\\1" QSCINTILLA_VERSION_STRING "${_VERSION_LINE}" ) string ( REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1" QSCINTILLA_MAJOR_VERSION "${QSCINTILLA_VERSION_STRING}" ) string ( REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\2" QSCINTILLA_MINOR_VERSION "${QSCINTILLA_VERSION_STRING}" ) string ( REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\3" QSCINTILLA_PATCH_VERSION "${QSCINTILLA_VERSION_STRING}" ) endif () endif () # check version set ( _QSCINTILLA_VERSION_MATCH TRUE ) if ( QScintilla_FIND_VERSION AND QSCINTILLA_VERSION_STRING ) if ( QScintilla_FIND_VERSION_EXACT ) if ( NOT QScintilla_FIND_VERSION VERSION_EQUAL QSCINTILLA_VERSION_STRING ) set ( _QSCINTILLA_VERSION_MATCH FALSE ) endif () else () if ( QSCINTILLA_VERSION_STRING VERSION_LESS QScintilla_FIND_VERSION ) set ( _QSCINTILLA_VERSION_MATCH FALSE ) endif () endif () endif () find_library ( QSCINTILLA_LIBRARY NAMES qscintilla2 qscintilla2_qt5 HINTS /usr/local/lib /usr/local/opt/qscintilla2/lib ) set ( QSCINTILLA_LIBRARIES ${QSCINTILLA_LIBRARY} ) # try to guess root dir from include dir if ( QSCINTILLA_INCLUDE_DIR ) string ( REGEX REPLACE "(.*)/include.*" "\\1" QSCINTILLA_ROOT_DIR ${QSCINTILLA_INCLUDE_DIR} ) # try to guess root dir from library dir elseif ( QSCINTILLA_LIBRARY ) string ( REGEX REPLACE "(.*)/lib[/|32|64].*" "\\1" QSCINTILLA_ROOT_DIR ${QSCINTILLA_LIBRARY} ) endif () # handle the QUIETLY and REQUIRED arguments include ( FindPackageHandleStandardArgs ) if ( CMAKE_VERSION VERSION_LESS 2.8.3 ) find_package_handle_standard_args( QScintilla DEFAULT_MSG QSCINTILLA_LIBRARY QSCINTILLA_INCLUDE_DIR _QSCINTILLA_VERSION_MATCH ) else () find_package_handle_standard_args( QScintilla REQUIRED_VARS QSCINTILLA_LIBRARY QSCINTILLA_INCLUDE_DIR _QSCINTILLA_VERSION_MATCH VERSION_VAR QSCINTILLA_VERSION_STRING ) endif () mark_as_advanced ( QSCINTILLA_LIBRARY QSCINTILLA_LIBRARIES QSCINTILLA_INCLUDE_DIR QSCINTILLA_INCLUDE_DIRS QSCINTILLA_MAJOR_VERSION QSCINTILLA_MINOR_VERSION QSCINTILLA_PATCH_VERSION QSCINTILLA_VERSION_STRING QSCINTILLA_ROOT_DIR ) if (QScintilla_FOUND AND NOT TARGET QScintilla::QScintilla) add_library(QScintilla::QScintilla UNKNOWN IMPORTED) set_target_properties(QScintilla::QScintilla PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${QSCINTILLA_INCLUDE_DIRS} IMPORTED_LOCATION ${QSCINTILLA_LIBRARIES} ) endif()sqlitebrowser-sqlitebrowser-5733cb7/cmake/FindSQLCipher.cmake000066400000000000000000000112111463772530400243450ustar00rootroot00000000000000# - Try to find SQLCipher # Once done this will define # # SQLCIPHER_FOUND - system has SQLCipher # SQLCIPHER_INCLUDE_DIR - the SQLCipher include directory # SQLCIPHER_LIBRARIES - Link these to use SQLCipher # SQLCIPHER_DEFINITIONS - Compiler switches required for using SQLCipher # SQLCIPHER_VERSION - This is set to major.minor.revision (e.g. 3.4.1) # # Hints to find SQLCipher # # Set SQLCIPHER_ROOT_DIR to the root directory of a SQLCipher installation # # The following variables may be set # # SQLCIPHER_USE_OPENSSL - Set to ON/OFF to specify whether to search and use OpenSSL. # Default is OFF. # SQLCIPHER_OPENSSL_USE_ZLIB - Set to ON/OFF to specify whether to search and use Zlib in OpenSSL # Default is OFF. # Redistribution and use is allowed according to the terms of the BSD license. # Copyright (c) 2008, Gilles Caulier, # Copyright (c) 2014, Christian Dávid, # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls if( NOT WIN32 ) find_package(PkgConfig) pkg_check_modules(PC_SQLCIPHER QUIET sqlcipher) set(SQLCIPHER_DEFINITIONS ${PC_SQLCIPHER_CFLAGS_OTHER}) endif( NOT WIN32 ) find_path(SQLCIPHER_INCLUDE_DIR NAMES sqlcipher/sqlite3.h PATHS ${SQLCIPHER_ROOT_DIR} ${PC_SQLCIPHER_INCLUDEDIR} ${PC_SQLCIPHER_INCLUDE_DIRS} ${CMAKE_INCLUDE_PATH} PATH_SUFFIXES "include" ) find_library(SQLCIPHER_LIBRARY NAMES sqlcipher PATHS ${PC_SQLCIPHER_LIBDIR} ${PC_SQLCIPHER_LIBRARY_DIRS} ${SQLCIPHER_ROOT_DIR} PATH_SUFFIXES "lib" ) set(SQLCIPHER_LIBRARIES ${SQLCIPHER_LIBRARY}) set(SQLCIPHER_INCLUDE_DIRS ${SQLCIPHER_INCLUDE_DIR}) if (SQLCIPHER_USE_OPENSSL) find_package(OpenSSL REQUIRED COMPONENTS Crypto) if (SQLCIPHER_OPENSSL_USE_ZLIB) find_package(ZLIB REQUIRED) # Official FindOpenSSL.cmake does not support Zlib set_target_properties(OpenSSL::Crypto PROPERTIES INTERFACE_LINK_LIBRARIES ZLIB::ZLIB) endif() list(APPEND SQLCIPHER_LIBRARIES ${OPENSSL_LIBRARIES}) list(APPEND SQLCIPHER_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIRS}) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(SQLCipher DEFAULT_MSG SQLCIPHER_INCLUDE_DIR SQLCIPHER_LIBRARY) # show the SQLCIPHER_INCLUDE_DIR and SQLCIPHER_LIBRARIES variables only in the advanced view mark_as_advanced(SQLCIPHER_INCLUDE_DIR SQLCIPHER_LIBRARY) if (NOT TARGET SQLCipher::SQLCipher) add_library(SQLCipher::SQLCipher UNKNOWN IMPORTED) set_property(TARGET SQLCipher::SQLCipher PROPERTY INTERFACE_COMPILE_DEFINITIONS SQLITE_HAS_CODEC) set_property(TARGET SQLCipher::SQLCipher APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS "SQLITE_TEMPSTORE=2") set_target_properties(SQLCipher::SQLCipher PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${SQLCIPHER_INCLUDE_DIRS}" IMPORTED_INTERFACE_LINK_LANGUAGES "C" IMPORTED_LOCATION "${SQLCIPHER_LIBRARY}") if (SQLCIPHER_USE_OPENSSL) set_target_properties(SQLCipher::SQLCipher PROPERTIES INTERFACE_LINK_LIBRARIES OpenSSL::Crypto) set_property(TARGET SQLCipher::SQLCipher APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS "SQLCIPHER_CRYPTO_OPENSSL") endif() endif() sqlitebrowser-sqlitebrowser-5733cb7/currentrelease000066400000000000000000000000771463772530400226460ustar00rootroot000000000000003.12.2 https://sqlitebrowser.org/blog/version-3-12-2-released sqlitebrowser-sqlitebrowser-5733cb7/distri/000077500000000000000000000000001463772530400211725ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/distri/mime/000077500000000000000000000000001463772530400221215ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/distri/mime/packages/000077500000000000000000000000001463772530400236775ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/distri/mime/packages/db4s-sqbpro.xml000066400000000000000000000007111463772530400265600ustar00rootroot00000000000000 DB Browser for SQLite project file sqlitebrowser-sqlitebrowser-5733cb7/distri/sqlitebrowser.desktop000066400000000000000000000013221463772530400254700ustar00rootroot00000000000000[Desktop Entry] Name=DB Browser for SQLite Comment=DB Browser for SQLite is a light GUI editor for SQLite databases Comment[de]=DB Browser for SQLite ist ein GUI-Editor für SQLite-Datenbanken Comment[fr]=Un éditeur graphique léger pour les bases de données SQLite Comment[es]=«DB Browser for SQLite» es un editor gráfico de bases de datos SQLite Exec=sqlitebrowser %f Icon=sqlitebrowser Terminal=false X-MultipleArgs=false Type=Application Categories=Development;Utility;Database; MimeType=application/vnd.db4s-project+xml;application/sqlitebrowser;application/x-sqlitebrowser;application/vnd.sqlite3;application/geopackage+sqlite3;application/x-sqlite2;application/x-sqlite3;text/csv; StartupWMClass=sqlitebrowser sqlitebrowser-sqlitebrowser-5733cb7/distri/sqlitebrowser.desktop.appdata.xml000066400000000000000000000052601463772530400277050ustar00rootroot00000000000000 sqlitebrowser.desktop CC0-1.0 MPL-2.0 and GPL-3.0+ DB Browser for SQLite developers DB Browser for SQLite light GUI editor for SQLite databases

DB Browser for SQLite is a high quality, visual, open source tool to create, design, and edit database files compatible with SQLite.

It is for users and developers wanting to create databases, search, and edit data. It uses a familiar spreadsheet-like interface, and you don't need to learn complicated SQL commands.

Controls and wizards are available for users to:

  • Create and compact database files
  • Create, define, modify and delete tables
  • Create, define and delete indexes
  • Browse, edit, add and delete records
  • Search records
  • Import and export records as text
  • Import and export tables from/to CSV files
  • Import and export databases from/to SQL dump files
  • Issue SQL queries and inspect the results
  • Examine a log of all SQL commands issued by the application
https://raw.githubusercontent.com/sqlitebrowser/db4s-screenshots/master/v3.3/gnome3_2-execute.png DB Browser for SQLite, executing query https://raw.githubusercontent.com/sqlitebrowser/db4s-screenshots/master/v3.3/gnome3_1-plot.png DB Browser for SQLite, browsing data with plot https://raw.githubusercontent.com/sqlitebrowser/db4s-screenshots/master/v3.3/kde413_2-blob.png DB Browser for SQLite, browsing a blob field https://raw.githubusercontent.com/sqlitebrowser/db4s-screenshots/master/v3.3/kde413_1-create_table.png DB Browser for SQLite, creating a table https://sqlitebrowser.org/ https://github.com/sqlitebrowser/sqlitebrowser/issues sqlitebrowser.desktop
sqlitebrowser-sqlitebrowser-5733cb7/images/000077500000000000000000000000001463772530400211415ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/images/logo-nightly.png000066400000000000000000000447511463772530400242760ustar00rootroot00000000000000‰PNG  IHDR\r¨fsRGB®Îé IDATx^í} ˜ŹöwÎ0Ã60ìû¦  Qq‹š0äªÉFã–ÜDͯÆ·Ä-Ѩ .‰QwQ1®£âzUÔÌ£5Š ˆ‚‚¬Â°É20ÌÌ9ÿóöÌw,Šî®êîê3çÌT=ÏyÎÌéêêî¯ë}ë­¯¾ªJMÖÖ­Ö‰VûäöÁ­¬È€­Ö­Ø–ZñË·n-` ÀÖkVlK­øåÛG·°`뀵@+¶€%€Vüòí£[ XÈÁ:0nܸRù¶R©Ôn¿%‰1~·ŸN§w;'Èã&‰*Uþt:ýº˜'™LºžóôÓO+ËR]Ë7oKæmº[‰" E ‹Ž Ö,<†±KˆÄÂ"‡% cæö-È€;ànÀnM 6`F×"˜,d¢°aÆâ–4ìh®a¤fÊb "šá-ösºmÅ£U°æ<[$îbXå°ëiµ ‚}q ôæ„jv¯ÍÄH$&áÊ­™ZH-ûÄìV·pW8pàn'ºý†Lƒ R^Äë\ùÄåË—+Ëâ Ë–-Û%¯×¹AÊÔ¾¸áŒ­•Z$œp e¨¹Ô²‹”ÁÈ֩ẟµâd"`‘ÏÂ)ÀùˆîCKU -‚ðDÔl­;ƒ—¿[ ¨ãd&…H ÍE¢Jh)„—À’>Û-<Àm'䃕íFÙ$B¾ûò†²ÙÊË@oéÒ<ìò#7ˆ@TqC¾ªƒœ&€>ÎVÞ=?Àlê.³©XäzW!ç NÐqÄN]Bÿܶê¦`•ÿåˆj!¥Ëd‡¼[÷#<2ÿk©}‚¬Y€IàÍ7ßt®i’r š„±ycž{ná-ೆ•Vs!ÁäÊcÖ ÀdkÏ­¼•ô­‡9ñ L¦ÔAsª‚¬€)àÛV>'0`o¢Ébw!ª:h"ˆL ·­¼Å\>XÀDW!›DD¾méó¡ºÛ{ô³@T2ÈÄBMàåÜð­Ï«%Y *ѤgŸ}Ö™ßb:%€°À·­½é×jËËU „%ƒ¸Ô€1~ ü\­¦ö¾â¶@X"0­"€~ÜUÅ–ß’-†LªHü¶ÅoÉUÙ>[ €ÊËË‘L&ÇFkšÂ€ß:÷½_›¹Z$0ž ’ƒ0¿õê·ÂZl9’B¨Ð$˜,ø#½[{²µ€¶ªP$ˆ,øµßÍh-`Ę€ôÖ[oi•UTT4iæÌ™â‚@ZçNN;í4;ß^ÇP6µ€†tI ¨¨ˆ@Ó§O×&m8ñÄ+uÖηà×x£6‹µ@@ ÄEZÐ4w¿RuÏü* ÙãÖá- K;v¤3fha[+Z"òÝjsóO=õÔðOgÏ´°PZ`òäÉÊ<è ju´à”SNQöý'L˜@ýû÷WÞœÍ`-`-ÞsçÎ¥wÞyÇ·€D"MqX¤Ä·2Ùgž‰­¯}åß¾}éøãÿTöLkkm L:U™·®®ŽÒéôØòòò*¿ÌJ¸úê«+׬Yã+ÿGEøØd-`-¿æÌ™C_ýµï…¶oßNõõõ“ÊËË}G”pá…*ûÿ¥¥¥Ô«W¯øŸÜ^ÁZÀZ€æÏŸï|üRMM mß¾]éPÀ­·Þš^¹r¥ïÅãߣGûj¬¬²`… ÒgŸ}æ{¥êêjª­­­*//© p×]w¥UrcèС4lذ,<º½„µ€µÀ»ï¾K6lð5ĪU« ªf̘¦L™’^·nïņ BøØd-`-¿ªª|ýzÎ ,X°NÀè `æÌ™é%K–(ŸêðÃW汬¬¢Y`óæÍ¸ýÒÖ­[éóÏ?G–è  ¢¢"½zõjå]c(°OŸ>Ê|6ƒµ€µ@x ,Z´ˆp¿’øä“Oˆì€رcÁ«¨J={ö´Î@•‘ìqk@WÎ=Uš7omܸќH&“„À‚ÚÚZßk·k׎úõ맺?{ÜZÀZ  0®¯£Ä¿øâ ‚J@2æ¤R)-@wÀ&kk3€×?F8L8v¢÷Íø@øìܹS©ø‘A ›¬¬Â[R~Ó¦MZü €Ÿ ÀˆàÇä|oÛ¶ !†Z7dI@ËL6“µ€«‚€ÒñâÅ ü DŽÀ(+&Ü-| UêÚµ+uéÒE•Í·°,üMý~‘ÌŒˆ €•@÷îÝ©¡¡Ö®]«–@WD`»¶Ž[ ø[ ðQÒ—_~éÖòÇ£üL˜Ô¦MG ¬Y³F©¬°ÕßZÀÛaÁïÒòÇçI“€ §B€‚Ž"°D`a`-ð­‚Ÿ[~ôû›œ}^ßfGܺ „Þ½{;J]N:d`‰À 5[ ,ð!ûý€/‹ÏÀŽAVÂor°.À?`}­­ãÙ›"ô´‡öD«`NÀÏ’_”þ„`VÈò_Vݺu£N:9ñˆ^ÂÇ+ù)&œkUAk„KËxfÔ„ðêò¸=5€¿téR]Àg'ÀÍ “ÆþAl?"À1/e`UAËCkzŠ0}{Ù>½ |—^E Ùó°2àïöíÛ;@0~ªfò4G¯‘« ZŒòçY¹‘S©^'úꫯY~9á#ñ?b˜@ |Ø7àõÍdà§ `P`¤S­lÓˆÒ§—ïå›o¾qº |7'Ÿèð“»k6€¬@%%%·øæPb8 u’j4Áª+ÚhéñíXU ®: …ÏO€_סC‡x)ÇO)pœn¼‡€— eÀßQ«´L(»\vktJŠ]9QÉñïA»zQß“×ùmâÆA¼*6ßTË0âUQ}r·@ü£è¸¨~„3 ÈÛ›5‡JR9ÝC<_&±‹ä:QóÊõꎉùrÔ^ÏŽº!«Â yn­·Ü5PZu\—XŒ¯ lJòë”À•]lñY¸9 å.‚—¡X ÒÂØA+fX_BTЙ:_VAŸßÔ}4g9¢BÄßì’ÁqN+¤7àL¼ @ÈòH€n¼º •‘óÈÄ~/•±2)„‘¡&ü Í ˆ–zm¼OV'x×ðm‘ÃôÉý€ð Èì(€®ä7A |¸Åg ËÿûòbCñ…«þgÉdžGåÁ5ðØü.F-²$ÿ/Îi@Ý‘‡– ȸžKt â0ðãvÒE¨–BЕü.įÐ%Ý|"q˜V^¬«R~ç1!ð*HL ˜ç JL &Õ¦ª2[òqؘíçd•&¶îrË8žÞ}ÃÃt¡F(³ JËîàÕ%ðòéxU?ÇŽ!U(DÀå1)Èä ®£ÈÉã™QNKS¢-˜®~å„Qn×ñk™ÄÊΊ€ãõ˜Dµ –ÉC¢âx¶xÛ+×ZÈ ÷ãFÐnÄâ—/ÈõüÃA¹é¹âUº}{Ý|* ƒ^1è×0Ù’£*š C$-'ÿÍç3Håò SE¨8¡ç§ëÐTK›ã ÕÇòÞÏŸ;>‘t»XeØKD‰[lQZûµÊn  „çóD0óߺß(Ãí|®DPél°‚©$¨V8ÈýèL+iáU¯ÐrØ| €\öˆ ºÀuΓî¥^Âæ‹€¶…§ÝÈ/Ì{‹¨pÌ*€0R^7ðÇ-ŸŸpë¸EÆéðRa”€Hr· €Ú2'ª¥"øâUº„ ›OV &€Ž”vsæùV!UK±…Ъ€­€"P%ÑC $Ì*€°R^µ0ˆWŒ€›Ò%ðs%„|óؾU´ð*1¢*“Éd©›DBª8×™è×Ðõô‡% ¯lذÁy :}ù -¿˜×«ooªe²-ü·d¡R\ÙvBê^Ïã¾(€²d291H$Ÿ)b`×á\‹ஂDqöÉ$â7*áöƒÙTE·]´3R¥²§ê¸)Å&•3©¼¼¼Ì¹AÔ¸k§Oª¨¨(+((˜Å™ÖÀ Ë~9Èí8?’ D^Çe0¹ý¨6]à5ħ£¼*˜ì³ó!„˜*`ì1õ–€¼ (N-//¯ŠL¬LµìºåðZª€·‚ø±ï.Fþ]–Ó^ ž€µ ¹Ü0_E :¾ 7àGiqt»ºùTD¤:îÕ•ó#FS„–ç`ÈY³f¹vt6¯á/ªÜ[°IÈ-$¿Lðëä…`ÐiÉÄ) ›DÄ>©Ö¨ƒ.±èæSŒêxž²ÿï`IÕ ¬”÷ò¨ˆ€ÅB½Zx¯¹œß­‚¸)7¢ð"ñw–+—@X gÓ`Šò¼…TyÑ#õíMTÈr”­¿6 ãìÙ³ ã½ x™˜ü€Ÿ@ìßëHz9¿_—ËÃZƒø;ˆB*`¿.$¶Õíý¨‡ê¸J‘$‰ªÇ|¬N㮥š 4™LVÊÎ@]B2ŠÀe‚0+[tY xý.ÎPµø*ßùxQXb*}¶…oqXTü2?óÌ3e‰D”ƒ{â%ÀšXHVnÀg‚ÁïæØ[yÕq¼º£¢JÐQ 6 íK/·¬rÎíx¶}¦8è}'‰±Ó¦Móõü‹Ê@[ðI ·aAQ ¨úöº¾T€àK$v;®ãà–]þ–Aï•— гéPu-‚VuuuUO<ñ„V¿?´øÓét) =z4zè¡®$ "Õq<kØË @–ûn„€ Å‹ÓÚµkå£áGèÕ«4¨ í׿„ú•´§t}-QA¥;t¥d÷AD=ötË‹¼”€¨ƒ=›>€lTÐ|SXÝiåÊ•T]]íl†¥ÞP· B‡öìHûöîHƒ»w "j ì6±=]H›Òí©šJhg:™©?~RÝ Ða‰×©5+**Ò&-pkýe)qØa‡Ñw¿ûÝHJÀäQ7¹¿hÑ"zì±Çè©§ž¢åË—ïrkÇïÝ‘ŽÛ«˜J‡´§Ž…/É-%Úv¤äÐïRrÄ(9|ì.C{ÈÏàä¿ù%cMȯ ÀÆ|;vo *¥äuï Æüùóð‹itßvtÂðŽtôži`ç6žuVPwú<݇¤ÐöteQ–wK–o¬¸¸˜¦OŸ®…m­LãÇo|cM-$‡ÝŠÿ8N:é$çÁ¤a‚ÄQ·Q.-üM7ÝD?üpƃvˆhüÐ: îSj¿sSæXA»B*èPH‰¢J$”N¥)½³jvRçå¤D·”<ôç”ØÿøŒÃPT¢Jàþ—ØÚiùãòD©`â¹ùÐæûu{f?‚yçwèÍ7ßÌl+™§ƒ ¢ìÕ•NTK#;ÖdêD²°€ :R²mJ$!)U—¢ÔŽ:ªßº3“/M z7½'½Õ0”vR#„iáÝîûÀ¤ÊÊJ_~x„אּ°PK( à´ÓNÃZpþe6¨p»ßüæ7»Ý”îpŸ_>ÞPôàï'Ÿ|’®¸â Ú¼y³sÝ3Ï<“~ñ‹_С{ö ­ÏßDu_Ìu~/èXDm{v¤¢îœ—ç•Rµõ´s} Õ®Ýæ‚CC¦ÄØ‹)Ýmó¿¬`¬ôT!ˆ– @n@Žãù½ùâ‹/ÒW_}å¼W4p1‚¾Wÿíß°¸±š´IR»^ÅTÔ£µ)nëYwÒ iªÛXCµÕÛ¨nãv'_ µ¥Wö¥OS}œÿ½H@¥\p.î àGi½÷Þ{¾Àøœ1c†ßÊ 7ÞxcÙ¢E‹&Ê þ߯_?úñìj 9`ÈK¸9‘}š‚‚‚]Æûo¹åÂé'?ù ]{íµ4|øpªÿô´­â÷”®¯sÀÞ~PüASíÚ­´}ù7R 6m)qܵ”ÚóˆLÈ/“ó¢kjœMþþ÷¿g”¶.›¶NSÎP>Ýĉ+׬YSêGûï¿?áã•d^ØÃ/”ØÍÀÀÇn¸áºãŽ;œKÝxãtþùç;äPÿñÿѶ™t~è; íøå‰÷VßöåzÚY½Íù9ýãk(½w£o@Œ#€ Ðu”€ 8ªã*@èŒIŠÝ'¾7ù;Èõ‚(€ÆŒÎû9r$üñNãÒ9µ™ŽßùOêœÚê(ÆŽC»ù¶ø:„°cåfªùj£“õ½Ôzµ~Dc=ÒèŒ5Êiõ½Ò«¯¾J_ýõ.Š\Æ'|S Ên€’.¾øb ýùX´gÏžJ»€Ð?QyÿÅ.òã<¤x€®¹æçï©S§ÒOúSçïÔ—ÿ¦mïü æFËo*á%âe:×™p 5ôo|1 t0-oãĹçæñ÷RºGÌgŠ‚,, ƒ>,¡­Y³†|ðAg¿Æƒ>˜~øÃ:`l“®£ñµ¯Q÷Ô&*ìÒŽŠ‡÷¢DZÕ ]Ê­ŸU;yÿÕ0ŒÞ¨ê;9¨ðù¢ ,pœ–À‰Wà غukôn¿ýöôªU«|%ä÷Þ{ï­edë¢e—ÉÀ~|Þÿ}‡±‘n¿ývúŸÿùŸFgÈöMTsïi”Ú²ŽÚõëL†tվ݌5K6ÒŽÕ›‰:õ¤úŸM¥Ta‡ “£Bácºå×™ ` 8¦ÊÉez衇œ¢ï|ç;ˆfÍñµoÑ^õ_Q›Nm©ó~½[®[-´ò‰$0«þ ú¼¡ç.$€áéÞ½{Z}ÝôöÛoü~«­­U®  |Ú»îº+ o»_`èС„OÐ`c¾?ÈÀ˲@¾ñãÇ;sÏ=—Ð `²ØùÜuT7ï9*ìÚž:íÓ+è-hçß²` ÕmÚA©‘ÿMu¥¿ÍàçÍ/ýZõ !‚_G2†Q~-iBÈ…Oÿk¯½æ¨ÔsÎ9'ãEß«n ý`翱ù$•ŒêCí µëCŒÛW|CÛ—m¢oÒíiJíQ”¢„CD>>Aœ€˜ƒâG »íÛ·G_øÑGM¯X±Â—ºtéâëÐy@¨Dýñô_&À3ϤíŸã_r`¿Ø^ Êo¨©£oæ­r®µó¤[)Õ{Ç&La®sƒUþ–É!l>àUÇs™€à£ùÛßþæ¼§ÓN;† æ¼C<ÓéÛŸsúý÷ìFmûtÒ©¦¡ólþäkªß\KŸu?’Ú•žºœøÆo(€ü1²FWéeË–)/O*ïæééˆÀz€<­?‚5n¾ùfúå/™!€ºÙ¤ú¯Rûþ%Ô~°¹~¿×ý×,ÝH;Vm¦†½ÆRí]ž!€\ô´¦Þù·ýë_Në¿×^{9À¤9¢þKS;—ÚQçýûF­²Êó¡¡"SEhùñw%¼ƒÒü Cc¬ê’#Šñ³Ï>óFW3gÎLó8~’}™>}Ç·ðªQ…»ï¾Û í=ýôÓÖŸŸõ'Û_¥¾ k©ã°îÔ¶Wqìu`°îàshÛà£_8ÄH†ñ| ‰¦3 c¦R|a¾sù€“ Îxo¡®ºê*'®áÁí>ŸCõ/ÝLEÝ:Pñõ„©{ÚòéZ'Ø£vÌE´sïcðÛ8€Ü\¾«)S¦8jò·¿ý­SŽ©môóšgˆ’ êvØ@ãŽ?¯ºVûõÚöåªé0U~aà*‰~=o“Ýðˆéép˜7€>7úP UêÛ·¯#ÝM¥ßýîwNäÆü¿ÿýïgŠíñÎê¸üßÔqhwjÛ;; Ž‹ïøz Õ|¹ê÷þí(½$¨êˇ Rµìªã¢Jà¿åo•Pw»†ê¾TÇuïÛ¯Ô›çŸÞq¸aÖ*—9¬~)ý`Ç[TØ­=uŸãXÆ+HŒ"-?aJ ˆØ˜z®Jð‘ñ"5Æ|͇ÙR:É$ ÒŽè-1Ö ßœ?Pá–ÕT2ª¯¼‘­„¸ïÍ­¦T×Á´õ¤;]副"/ð©¤:n`bQ®ÁàÞ^xáz÷ÝwéØc%LVãû=¬ö…y"ƒº8q#ÙLèB‚Vþðfª/ÖÐ?€ìiN@n@4…*m†0KŒDI¸Ö1Çã8áÈÓ Ù¿¢Dªº>(RÄ_ÐûK7¤hãÜåNˆðæ3+œá@þø?€)à˜*Ç!薣ʇ¨?8ÃN=õT'TœýÇìøíQ¿ŒŠ÷îAE=‚‡Š­3bþ-ó×PÝ7;hÍ÷® ½F*‹Ò? Ùa‘Z¶‹qÀn8Ù"0‚6°K0†9%ëwÐÀg~íÌÊêŠ>\–ÓÆ/sfn:£‚R‰‚]¦Gº]`×™sn*%ˆÒxä‘GhéÒ¥Ž³ü¸¼ã¶¿FýÖP§‘½©°Ä\wU§"2ÁAÕ‡_@5ýñ=%ø¿øâ ´xÉff¿Ã€!?D©üPaüþè@I<÷Üsß@ÝvøìyÍN›Ïx’’…™ùº HȰªÂûWµº‹C!¸][÷~tŸ °dÉg¾Ö°DB]Üç“û©]õ§ÍK‡O5u…Oࣀ£BËŸqΘ1Ãw@e$ âØ †êbÑ$ Caºb;v¬3îÿúë¯ ÆJÓàYg:ÿw;b°ŠƒÌO¥iÿ—% hÓ™³"ÏŒË €éQE ªã*b@=D¨cøæ®ç_ÿúW§Þ\wÝuN=âÔóí۩ê÷Ñ#Œ"e3mY°Ö™)¸ö¨Ki{ïÝ'Ð…?ÀÆñ(&Dî•”4:Qtˆ ŒÀ„”=}út¢#œú¿x µ©YO%õ§‚vþ«µ˜|ÁX_Ü‹Öw«S´¸$™¸f€Ww ˆ“жði§ŽÁ\×`s(P• 1åååNø/È8u›÷uúâUgÞæd3}óÁ*jØ^G«Ž¹‘ê:È\:(ðqâþóŸŒÇߣž˜‰ð›Ó"À ÀG°"I¯” Ÿ"¶] IDAT„0öÐÇ?þñô£ý(ST¯·n¥ö«çeÝ‘ƒE¶-ZG5ýGSõáª;ì„’[}9’0sT] ?¡Ûò{åø<__ü›-~2°”yΜ9týõ×ÓQGEþóŸ3G‹—TQ÷÷r€pf+¥ëS´ñåNàWt¶æ |œÃ‹‚(F‰âU¯ß½{wgR*2'&¿î`åŸ;3Ž>úhš8qb¦üΟÿuýø 'Š Ñ\ÙJ?H`ãþ?£Í{ýÐøe›–wvÊå—‹ÑNüœ±L(b^1;kÝò)*ŽS6®äsù<\ÇÅ$–‰."'ñoãó)u udÀJ­pó ê÷ÊèQD‘f+í\·¶~¾ŽvôÚ—îw®Ö¸¾|oˆŒ…_ƒß‹B!šU~óøá©‡À 9rbð"?"ÀBˆáFø/‚:¸2ñKtFE4Wü¯Ññü¿³‚Ò©­:ö&ªë yüOÕ²¯pÁ8!äW^yå.«Võ{å**ܼҙAŠ™¤ÙH[VÓÎ 5´xÀhE¯Ã]q€Ÿ7¢ÑTpñ*™@pÄðJ¹nOèç+ð"‚?üáÎâ¿úկ謳ÎÊÛûŸ¦vÕ ©Ãݨ]ßxgsᢘäLê5Òǵ)÷-€Fã/ù‹³ì‘áTòÙ Ôå“'cŸFÎ×g“¾õËhg¡~ô*Z||D¥'+¸fóÈ z‚àœAwòÕmQUA$8\rÉ%N@œ<‡ºÃŠw©çÜ»(YÔ†Jêk@€6½¿ŠÒu TýÝ‹¨¦ßèܯýö @ABI^vÙeN\ R²®†¼p1%vfE@ú£ °ªç!ôùÀã´Þ bDà‡èÊÅ«¼VóEß uÖꫯÏ×Së&u`IdÌÀ¼N½ß¸™Ú­ïÌçÆ¼î¸Ò¶/ÖSíš­´½Ïþ´öÈK㺌-7 ¼üòËÎ"2¨—XP›Ø ± ÀB %ômR֕ܺh¥Iš;òbÚQä~ àc6ŸàsÆ üèÀ/À“‰0£Pth¹½k/2@TàÕW_íŒ0`j'/C^´i)õ}­Ñ9×Â;Vo¡š%œk¬>úÚY’ýèÃpÑªŠœ4ia1ÍýöÛÏq*ó:“}ªn ¶ëQQÏŽT¼—ù†m;é›OÖ5¤hñ€ÿ¦½ç$¸%€à÷“ú|,'}nK~£;€ñ[Þ,Šð LM :Óo»í6Ç@˜ "@W¡ïÚw¨÷'ÓI`¯¡–÷z)X"|ÛâÆøêõE[÷pöFµ)Ï,ç4"1‡¨@¨HL-‡3¹oåu”¨¯¥v}:Qƒ*ýþ- «ÍC¾î6Šïj5,¸Ã{höíw üiv€Øƒ (&X€—‚°bÕ|ó»1'àž{îq 9fÌÇ)ˆë Y]ICV7F vÜ•ÚõàÁk¹¡ÌMûN oöiì?Ú”ŸÀ|úË/¿Üñ`ql,³Ï>ûPû¯?¢^oþÕy(Ä`X9è~²E°fÄÖÅëŸÑ†Î{ÑGÃ~¾›Ñ|^m ½$¿×-ŸãvnÓ9ÍãðÚüJLì`ª1ƶuÒK/½ä ëà!± Ñ„ èðçÃhµÿq§Ìõî0¨«³XÐÙV³lSf——MûLß o\‘ئü¶ÀêÕ« Ý,«„‰Bˆ,Ùø™ãPNÔí d»Bê0¸‹³›TЄ¡b,Š#¤ê.ûÒü=Ov‚~xïJ|›|Nù¼œ‚"!@ ðÚ˜ÁD€ÿ¡@ªÅG.\è ï`­@¤Ñ£G;/sÜ>%”¬¼R5‹' PŸ6½·vâ—\¿y‡ãèC Rªm'ZàÊY[A+‰Íßü@WrÖ¬YÎ`té¸ãŽ££Ü‹¾W÷uÙÒØÇLA,6£3e{Kî\»•v|½•ÒõqKûŽ¡¥}Ç:Kt1øÝ¡…ߥ+€kH¤¯²Á‡¼ì7”«ܸ¨ ð7öþó›~Œ¥žªªªv©Q‡}g8]|hg:ªScß […aíw(D€ñæ )gsÐ:–NÎV`MiËУiÓ¾ã)U¤?^ÛüÕÚÞŸä]u1OÃÊbBãtá‘}égC¨SlŽÊ“pÈ MÇ¢¦ÍADi¢T]5l¯§ú­µÕÈiCç¡ôŸ6ûÑÚÂ^ðëD^2€E +ZxUD ÙH@¿>Èž\‘}¢ÉÀ±2颡xmB66B…ÿô§?ev&ÆÏCØ£K!:²0¼˜(¶wFyÛÛv¥ê®ûц~‡ÓŽvÝQ ¤0S™-›×ˆ˜ã„ºãÖˆ@E¢î`¹yll3oÞ¾Q¦%,â=.·è^@÷º &8áSBÂŽ;pNãõ õ³o§BQÒ@ƒ‹ÓÔ¾~+­[µŒ>ž¿€êÚ´§a}oNÐòt7¯)¹" ÁíoÝãºÄb|E •äWWù@Ö‰@ôȤ€]‚eЩvðOž<™Î;ï&qý?ä×Td• .®Êç³z`;àùÄ¡¬¦Än—lW‘€ùX”Ò  À¤e7åôË)€É.â³Ýæ ˜Š Kމ/ÄíEú)¯sñ»ê<ù8Wl&¾±,±íåýåU˜A⨆"Èä¿ÅëŠd%Þ#“šhCº MGEÔòqSÕàW‚t-Z” ¥)¯Êé×õƒóáÈÁÆeü~¿Ë×󻩹¥Õ–n¾ €Ò«îÇX@2é´6ìÔ3¡¼^ªè`€–[p±O*n"®ñ<^ûÿñïyKÙ ÐMIâ }i FȆ ‚sßàEù Ð’BZãÉÀöú_Ì«sžÊé£:® ˆæ  ¥E!˜V€hA·Ëõ¹ºNA]…€†åŸÿ#ÀͱÄ/Õ­//€˜utoÀ(^%‰e@zõÙÔ“‹cŠ¢úLG‹òà Ù采̕Q€ hË/ƒ‰–2¨C0qž)°>€dÒé—ë*Ý|~ €‰ 9}nè^þ[ÕŠ2‘Æ·u¥ªêùTÇÃ* @;æ¾À8r]`ìË•ëHý°]U?Î2,°tZvSŠ$Êó› €ÖP™L&Kubøuûöºù€õÛãXÀDFÖ¯_Ÿ ðqëÏGuzµ~*bÈ€éH\-¼ñõ«OL21 B ¯RpÑ@EEEYAAÁDÕì=·ã:Rÿ¾ûîË,óíxül²h%8öèýhÈžG8OëFè*%¥"ŽD"1iúôée~æTî© H&“ƒôñu[xä;ûì³ {ÿÙd-Ð-pî¹ç*—‹ Æ–——ïºb®dd% ÿSO=•Û«ˆƒ àµÙChÌ‘c©ÎCLo\>ÓEç҉ǮÎÅ[ÛåžþrÏ^4§òÛÅ6sõ†ïŸÜ@Cçî}>òdú46z Y¼_WpÆŒJ|+3àæfÍšµ› ˆB")ÄMüf`jÁoÆŽÿ£èõ×w±ÒQ¢ÔwûÛ@tä?ÎÓ"dœ={vZn̓H}™0øÿ8 À‚ßL¥ýË”½iÎ?7GÍåtÿ_S4tPîÞ'ƒ6 @°ò°£Ó§O×¶V¦&(K$Ž/À ø*©ïµh\`Áoªüfì(‚_&S’ŸË!"¥óŸJ›pÂ3Ï<“ñ„¼¬â €\ÿÅçÑ Ç¬2S³b,åæ){Ó˶ålaü*‘´Á¨ ФJ ‰ú‹: Ð4XðG®¯Nüfìè~/P ûiCÕã?>6ÈRM*À‰ Ð Ò‰0IüA^½wÞ|ÿÔ¿¦hÏ<éóËÖŽÁüN8á„ÊF=ñàƒöôqš" ~ ~30SŠWËÏ¥PµüX)•JU=ñÄZÿÀ0nܸÒT*U‰ûõëG'žxbf//¿ÊW`‚,øÍTÚ›ïN/¿öíŽÊfJ5_J>·ün€ß†|c‘aéúIÏ>û¬oäŸü6uN<ñÄÊt:]Ê…€9ä8p` Ù€&ãrüe¿ïMß;8wƒø]Zð›!*UËF0AÈ$ÁK¢‹w^\\ÒŸˆ&º™i„ ÎF‰^­½_— Šxhæ‘4í‰Ï̼¹J™ô‡>tÔèOb(Ùl‘yþ¿¥iϹ«PtÁïåtS^q¼ÿ\°”^QQ‘6 h)Qú{U=ÀÉ'ŸìΆàÁŠ#éñ'-ø£RT 6žü2¨úø¢ð¾øØUK' çh¤?e¤¿›ÉÐ 8õÔS3‹dzþ˜ˆx°âzüÉÏͼ¹JÉ—–ÿ–{‡ÓKùÐçoA-X@Ÿ>}ŸüãÊ PXX¨¥´à”SNI«®Šn@ÿþý3ÙÀj:]‚ ]€¿?yM¯È]ð_we_:ò Uæjöãüf^AЖ߼â<ð@ÂiîܹôÎ;ï(o¾  @K( àÌ3ÏÌxþ½®Ú·o_:þøã]ƒp3&æXð+ß»V†[îA/½ºN+osfšÚ[~À’Ô¨Qà‹ïáù矧իýg6mТTJ8ûì³K‰„3ôç• MŽ=öXÏã?HYè*€žü.ͨXÔœõÑ÷ÚyÓò[ð©CÎF”o ]–_ÀÙvÜí~ø!áã—šöTœT^^mA믿¾ríÚµ¾ýÿ‘#G>ªðc½,ód6`®ƒÿú«úÑ~¤züf?ž/-ÿKÓ9ìí ~T9°wïÞ„Z}Uš?>áã—°ÁLMMMÕŒ3|ƒƒ” àÏþsåúõë} `øðá4bÄÕ}gŽC 49*2+y-2õ‰Ã©|æbí²³Ñ‚ß¬Å[øE¸ë®»àCEë¦uëÖÑ›o¾é›1ÕÕÕT^^î‹q%Lž<¹rÓ¦M¾0tèP6l˜îýï’.¢>ø€Üàþ‡ÒO}ªÜlœtãÕèðQó²q©Hט|ßz1úüÜJ´Ç€ÜõM˜hùùE²xã7¿[,¡‡Õ¨ýÒªU«C†ªá@%TTTT.\¸Ð—ºtéâÛgñ»Q/¸oÆ¡ô¤àÊ!Ÿ`ÁÙ„N&Á/*€00oÞ<Ú´Éßÿ€±Ctd0sæÌÊ%K–øhß}÷ÍlçÄänp÷cÑSÏ. RLVóæMËÿ>ôâ+ÕYµM˜‹å|ËÚ’aÀæÍ›iÁ‚J3¿ÿþûN# `ëÖ­¥ªýå1¤ÃO À@O?¿Bù€Í•áÏ9„~zì‹ÍuyíëN¶à×¶•_Ƹ暄%ìCˆ–Ý/$à$D\ÐÐÐPúÍ7ß( Ú³gOêÑ£‡2Ÿ˜A$€™ÓàÿÍ9‡ÐIüÞ¯_æÖØò³=Â<ûöª„.ÂÆ«"QØãŠø¨”@ûöíUÙ2Ç™~tìþ´zÒ%¡]®éŒãŽAß?x®éb—÷Äóƒiî{áǧßG—ŸOÔ·§ºQÉÖýÈ×™ó¯è¥W—ÄvyÇ×õÀ¡§ þÁÍÂ9ˆHAž_`D$ gk0U7€­h×®–ñ˜´2ÛLÖ-Ì:€9ÿ:à‡i~Þ¯Ò¨@àöÂð}º$€!À‡z(ôk-))¡ªª*Â>mAVQaãqÄÆDÂêªÊ¿ÝòF=_¾~.±\ùY½Ž…9Çëúa~÷;'ÊcI´þ Î!a=Œ¦°Û ÕÏÉ‹øþ³Î:Ë÷¼ àÿâ‹/>qv¡€.Gî¹-Bàõº$Ør ¯½ö•••9Ÿ‰]—+p-~öìÙ„ L—]v]zé¥Î,FÎëÛí˜_~·­¾Ãlê·.|i¤ 6¯=èüŽ»SÝ—ê¸îõ®‹ï·ÂvîÚµ«rÇwЯ~õ+úûßÿ®] þ±cÇ:Î×ñi.dD?^5ÜÇÙ‘W”þüüÆ|âôÞN:92cÛ¶mÊçBWDW K—\r Ýzë­ÎËgæn v%†­¨"“@w+Kž!f X¦!€ŠÊ Êóäø !VÀ]P´ÄW$ñ^dA,‡|=7b`‹yE€}Þlæon|œàód 7âëBl>Y tïÞ:tè°Û0¡Ž*ˆB-² ˆÖv­æ"€0ÀÇ»Y²d‰~7ÉŸU€×–_ð²BΡerU©‚0D`  µÁÖÜóf“84WwXO|Jœð£ YÁy)& # @Œ[~y‰/zü%¨üÚü”ˆß*?%s€hm%eƒÂ¶öü.–.]ê€?¬Ç¸@µÕ]Ì ÄßPˆcfE€ao9’g6y"¨T%€Ö[sÏôªPõ>>^#6º„`D¸Å¸)‘Ђc|f"Àl&Ñ©å¦ ð›×H“ò°2° ªJö¸—L@‰/ÞB“ñÑ‘ú,óå‘ÑG‹²ó¨Áó TD « ‹#„ v‹´Pi]0A?_¾|ydÃ1ðEPËÎ>·c9çp[ÿJD Ê@ ”XgŠ1‚›2€WÔ@äú×* 0AW^y¥&-[Ö¸ê¾U’^uÜ‹8Œ+·87E€ßÄß!ÙÕÕ¶m[‡ø"€ÈA0Içõ â`£üñÇ–ÂÔ>{Ž3(ê\€0Å€ Dø¨yÂúø¼fóx@ `¨ õÿ†ÀšºSŽqîÓO?m À‚9”²I+V4.sð{Z–ü~}{¹Œœˆ[}/_¨˜ðüü?È ©"ƒ°ð›ßü†¦L™âÌ<ýôӕáj˜=)'-=F¦.\HW\qí³Ï>Z mòȳýÀÊ•+°3øU€6E b9F@8¯=er@>(„Š]7eà 9¶ *Œ?žðA⑎CËÉšloÊ× tdr–üéO2JXäoUßÝï¸Ø¯W•“5€Nƒ]g´>&‰ @VL x‘øÃ.`ñ°pÁÐÝwß퀟 À«6YbÈm¦îv·'0A¿þõ¯a;^–ðn TyíÃÝK=QaâTƒòq&–`î½8Zà¦DÅpË-·„ò\~ùå4yòd§ À;«–[v«Db¤¢Uñ…ÀèQ®h‚~úÓŸî6_%åUÇu[~|ÆGܤ¼—*P)·ã ¨ dBˆÃ 2œwÞy„'Fø;J“»LòªÉªpç¨÷«çswJNLü»_(¹‰g2EX‡ÏK‚Çåå×½ž—À8N  ˆ­=ZöDU2È‹Ub¨ÝÊ*ü¿×rëÍA nà”ÌÏ-@ëÚ™ó…%®‡X0ŒÐi¹u½ü*‚1®ÂÆí€ð‘AÿEEÀ  ²²2ÐÊÀðÞÞtÓMNëÏQÐùæµ9AgmÄ •3®ü~dw‹×3…)Ѩ €Ûn» ¤µá†x^‰~$y%^¸[+-@ÎÆ¸u!î½÷ÞÝZvt°Ÿ8qHô 01`›d¼ t‚$¬Äsýõ×ÓUW]åœ†Ö F Žhd2Ðp rÏ6ot à=üœþùÏ:­?|>¯ÃÏÿË—Éëdò‚¹^Äu”À¸P¨ŽË âì³Ï&lwl“µ@k´À¹çžë<¶Jʇíä´ OÉl:ùçSè_oWÓ•—ޤ¦%5›d?Q"™lú«†°uXӟɦ…8ý*ϼÝhÍÚoY_6¸NÅãà—ëü‰ ¯›e÷è¶“ܯAçVš5ϻӆß.S–­›ñ²­×{=*M=ºÖ6¾, Þi×÷Ÿ­ûöºÎu·4ú”DëNXÀËŠ!ë ˆ wç§èô_þ^s½6{9òÛ…#M½ ¸vw5u(gÔÈ:ú[Yîî“ÇÏz˽Ãé¥×Ö›|ôXʺøÜ":á˜Æqù\L§ž×Ÿf=5'CA†åÆKåS0¢âŠ€8í,øÍU ~3¶ø×­¯%ÞØO¨B‡E2ðòÄ¢Tãû¢ ð Ž“,øÍTX”ò—){Óœl0W`L%åCËð#¹€)% –cDÄXð›CX¾€ÿ·¿nK?9z¥¹7\·ü\¬ŽÐiáUÎCã H_¥âðX𛫹üfl)ƒ_V¦Z~7Â0¢òÅ`Áo¦Â¢”›§ìM/çìÏ·–?ˆÈY€_?H€É.€¿¿9 ˜)É­å÷#€ J@wÖ ë> ~3Ö¶üæìxÚyý©ºÉáçVjÞú‚´ðÙðäøQ^«Xg®vÅTÒÍ÷§—ó`œ?×e¿ üÙð°? ²¨¨¨(K&“u¦«/w¢vžu=V¾0&8˜+vÆ}¨W·Æ`s5Yð›y3§ýïª^÷í¦¬^¥ê(>€ª3fŒõ{2!¶Ö=@ï6âšyM{‚ßDµÍðÿî¼vtü5.®™‹Iü²àÖ:ˆÀí—ߪÊËË£@AAÁD¿€]ÀË !¬Èðßß‘zuý*ëjæžò%¯%ß‹Àò·J xG"‘˜4}útßi²J€›™5kVÚm>¿Jò«Ž‡‰xhæ‘4í‰ÏrT¸¹üÆÞQK¿L¦Z~Q4•9¶¼¼¼*R ‰2~€ «þª– ª~7i}ôIî;ÓÊïïH=mËo„rügüv(­X|"W|Êþ?^–@Ƨžz*­³îQ‚ ð»²áôÑüÜŸ‰–à¿o½ôjîi®ƒÿÒ£y~Šè¢ÎPŤÓieëˆfÏží¨€ K{ù9u oÀ?µ˜zvYªBdë¤[,ø˜: øãö$‰ªÇÜ×ùÇFÐV8áé§ŸvT@X§Ÿ|®Žà·eÃéã|hù-ø …´ä–Ÿ$~e; ‹IDAT*Ó>€T*¥ÕúRÈ<{öìÒ‚‚‚J7çžNœ@Ð8€‹'îMŸ,Èýi¨OL-¦9ÞòO¾o½˜²ÿ’ÿmOÇý úvÛÆØH*(jËïFa½ÿ.N?4Îc§M›æëø)À‰Ï<óL™©aA¿.ÀE×îEó?Ý×{4Vî“t¢î%KŒ•GAüf¬j ü^]€¨JÃ~Ó¦M ´:n`ÀÍ?÷Üs®Ñªa?Ý8€|ÿ̇ºP×âÅfjWL¥Xð›1¬IðÇä þÀ]Ñ”/¼ð‚«S0HÄ › oÀÿ` uíÎl¦JªK±àWÛH'‡ið˵å'¢PàD8ùÅ_,M$ŽOÀ„`ÖËä…ìÏ‹–ÿþ}èÅWªuêw³æi-}~ÙÈ&âàíohhøµûüò}„êÈ…Ì™3§ÒmÑU—@ôŒûÉ‘´qs›f­Œ:Ÿ™-¿¿Î«T扣åç‹F@«ÿè£êï»=°@Á¯¼òŠÒ9èçèÒ¥‹ò…4w†‘#ÚP›‚]7²lî{’¯¿|U‡fY·?¨öKR·¦uûƒž›ü_|Õ™¶nï]oÚ´ÉyŒ0ûÀÙ÷ðÃGä.€ü"^yå bêp©N—>€O­ wßËýY}Ù¨tö­Ï ]Z}SÀgKSâ««¬¬Ü-^À+€hñâÅ´`Á‚ÌÞ€(‡óâoì(nÊs¾Gy„Þ{ï=gƒÏÑ£Gk× ìé6uêT:à€謳ÎÊlÍ$î4ƒ¿¿úê+ÚwïÐw+¥ÓØeûÌ8{99_Øc°;5ýß8s«) ò:ÿ7þ Ÿ¯W¸?à®÷IôÙíiéòTæZn†ŸÍ­,ù<“ç ì’’êܹsæ2^!­,ڮɨMgº†Ïqûv+oÙ²e„½±9(êQ4vìXg3ÚQ£FÑÊ•+w±»×½É÷€}5BzI©Tªêá‡Ý×÷z¶X€/öÆoxN"ÒQQhÛ¶­C x‘ PÆøñãÍAƒî|Í5×Ð 7Ü@¿ÿýïé²Ë.˼lAÅß¼%•ü;çÁ& µµµ™s8Ÿê›Ëær¼ò»U°ÓCe`¨Ê+¬ª¢zV¾F”rÜ®áe¿ûác ÷iÓ¦Þõ Ûƒcwà˜žÊ}ðÁÈ}7ˆ•ø‚o¿ý¶ÖlB·c€;³*ç"àopùå—;@/“W49Àº÷¾¸^àèJÌ ù¢Ü.±èæSÝ·×q&€ÁƒÓÒ¥ús8d€Šõº†ÊNÇà?ðÀ±Ÿ±™à‹Í;7p‘¸M8˱;1a„P àꫯ¦o¼‘®¸âŠŒÐiùe¨««s@Õ’û„X¦[>] èæS&Žrbj!]%´JÙðó›T* k>Ö€ß,ÀýàƒJ‰ÈqªÀGnù™Âw@¬p2ÅßÜTUK… dé®+…ã²_EÏöõ‚™›ÍL€›H“î¿ÿþØ[ûfë¸]¿@c8Ž@îpùÅ–Ÿÿ?餓B)‘Ø Êv¹ïïå `ˆp]o3MT¦Ÿß„ñÀ£ç¹÷Þ{›øÍªÜáÓO?ͨè»)]™ÜîæpëÔ××ûúü®R~ÒÑ4 TÒ9Û׋Ú«(Û>Dî¥Óé×ï¹çžf½ˆ¿¬ú¼”€üû¢E‹v!€n,úà… 3 À>È]À AìüødCD@ ª/mŠ‚<—.!êô¹M*/{£¥ÉçèsžÄ\²d‰\DD™à"‘ â$Ô\¡äqq*S@Ö„Jª©ûŽÓç`ŠdËû;î¸#gZz¯Æ7'€×Í._¾Üñ$“ÉŒÏà”SN‰¬.½ôR×÷€‹-¾Ü`ˆ¢d߃ø¿²Ô|oáUv2E‹-ªJ$¯QÕm·Ýf>€ÊÊʱèÛ‡_.œ“×–––¦£úÿ¬TÎ:/Eˆ¢tGT-š©;Žrr± bBXhf3EnÞx¹ßï%Õq®Ê›… ø>äï–Ö'w{>S¾7²`_€fƹçåÃÀù矿ôž{îpÉ%—Äւ냮ˆ£eŽ`* ð¦ŸÁ‚UXè}÷t:o­$†[ e²ø2…%€SN9¥ª¢¢/}ÒêÕ««àÉG"Niêã—êø¢\u¾Ÿt6 ˆ–ÚÅh8œtPjU7Üp÷Ùñþ+-Ä‡ÏØK6ADä:\ƒ!È&b@ÅqÈ¡ °ø[+øGpÙ㯚 Ð !HWÆëùâT*值©¼ª²²2•sÎ@ìùq€êÖ?þøc&G-$‰1‚CИ‚0áð# âÝr=sÓ÷ëBĦîk®¹Fr¿×h @UÉsýxs€ŽmÞxãLß*¢©…wº~d!ú‚ö•CLkaаDäv?h±RÊ›¿üòË£[çÕ8]>ÛÐ5UŽæËuj¶çž{.Cì—hê»îRû*\ &n!Ù©%÷ëC8ý2@åànKÓ5¹o¹¿¦{ØÀ^xa6ÔÜ–‚Z,×ò·4È5û¶ðû±ï/Ø@¾¿Áf½KÍj~/++K—••>'bÎ^‡½FôJ²¹òØ–òøå9·–zöì9oݺuöQÏÅþi¾¿š|¹gâ‚èKQݸ RY(‹ÇÓé´³+Qh©€I“&9Š¡)åý|ˆ,š»%^ aâE]´ôöÛo¢z@?òa%ê±cÇæuýÉë›obî²I“&Md@c­v$þ–_(^ >M Ë2åüœmU¥´Ç#Y€»™:£Sw§²²rR"‘Èëú“÷ÐD•“&M*ZuaÁ¯c¥Ö‘ÇYª).@ùÄMþ&¬€îc^§A¬ˆhLUU•#xóEñílذai:¾ýÎ;ï¼-¯ßš½ù¸,Pzß}÷9þü1ݺuÛ­;0fÌV yßò³ÿ?Õ1®5‹M†IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/images/logo-nightly.svg000066400000000000000000000245351463772530400243070ustar00rootroot00000000000000 logo image/svg+xmllogohttps://sqlitebrowser.orgDB Browser for SQLite Logo2020Jun05GPL3+ Layer 1 sqlitebrowser-sqlitebrowser-5733cb7/images/logo.png000066400000000000000000000353071463772530400226170ustar00rootroot00000000000000‰PNG  IHDR\r¨f pHYsÃÃÇo¨dtEXtSoftwarewww.inkscape.org›î< tEXtTitlelogoO–r&tEXtDescriptionDB Browser for SQLite LogoW’*þtEXtCreation Time2020Jun05V‹ tEXtSourcehttps://sqlitebrowser.org^?G”DtEXtCopyrightCC Attribution http://creativecommons.org/licenses/by/4.0/i×] IDATxÚí}y#×}Þ÷ûÆ`ν¸»¢V\Jä:¢D—i•y•(YR4µtŠÇJÉåØ9lÇ–íT\›¤JŽœ”-GIE%›´,R¤J+Q6I‘Ö-ë4eR¢È]qÉ%—{ÌîÌ` n Ï—?¸¯ÙÀèÆ9˜™ßWÕ…«4ý}¿ó½@ @ @ @Ø.`t & wÞy甦i)ÆØclŠsfŒ%cA Ó4ƒŒ±€$ç< ž ˆµ|d€¿å¹D˯¨´ìS¹ü¼P°í[æœ×câ~@Y’¤Šiš ÆX‰s^ôx<9UU³²,ç}ôÑ2ýÃ$; ï|ç;Ãápx¯®ëó’$í°À9Ÿ0uyKµÜ—¶ñéPää/ßæ8ç9I’r¦i®H’´Ì9_’$颢(ËO>ù¤BW ÀÄâÝï~·_–åýŒ±ƒŒ±+LÓœgŒí° À€Ým,2Á=V,Xâœ_”$éç|‰s~ÀËo}ë[—Ž;fÒi")É%IÚ%ËòÎùÎùÕŒ±ÃØÀCgiÓ ¸à €3œó3Œ±3’$1 ã…Ç{¬F§ˆÀŽ=Ô4í°aoaŒ½À5Þ `žÎΖ„à cì9Îù ÆØ I’ž“eù•ãÇtzv°¼ï}ï»Â0Œ·^&º ûA²æ;u?eŒ=Ï9?à9¿ßÿÌñãÇó$ÛÓ²ÇUU}€ëMÓ¼ž1öv³“|Ì~¿¡P@Á`^¯>Ÿ²,ÃçóÁçóÁãñ4Ý÷ûýe²,7}Ž­¯·BUU˜æë!5窪¾îokt]‡¢(Ð4 †a Ñh@×õ¦ûº®£Ñh ^¯[·š¦Mò)çN3ÆžâœÿsþÔüüü³Ÿüä'5€-†ÅÅÅ«cï`Œ]Ï9;€7a“3ë^¯‘H‘HÑh‘H¡PÁ`Ð"¹¸ ƒ`lûé²!ö­Z­¢R© R© \.£Z­6 Ñ&¡àG~à)Y–ÿñ‘GY&˜<Âï•$éÎù-n07ÖÈb±‰‰¢Ñ¨Er±r¼{1Çœ£V«Y¢P*•P­VQ*•°¾¾Žb±ˆjµº‡v’sþuÆØ×ý~ÿ??~¼H0~—>Õh4nbŒ ¿qÔßéñxÇ-’'“Ië6‹Áã¡ÔÁ¸¡ª* … …Ö××­û…BårœóQ‚àŸ… hšöý­Ø·°%àŽ;îØÃ97€E·ðŽê»Âá0Òé4¦¦¦077gÝï;& †a`}}«««ÈårÈf³XYYµ×Pð ÆØqŸÏ÷÷[Å;˜X¸óÎ;¯ÒuýNÆØÞ:ìcõx<˜ÅÜÜfffN§‘N§áõz‰AÛÕjÙlkkkX[[Ã¥K—°¾¾> oAáœ]’¤/J’ôè¿øÅ € \.ÏýkÆØ/84ÌÏN&“˜ŸŸ·¶™™rÝ PU/^Äòò2VVV°¼¼ŒZm¨ýC€ïxPÓ´Ï>ùä“%n¼ñÆ@4½“1öënÆ2öŒ1ÌÍÍaï޽ؽ{7æçç éj'¸B¡PÀòò2.\¸€sçΡP( 3Lø<€û}ôÑïàµòã΀ÅÅÅ«%Iº—sþAéA?/‘H`ß¾}ÖF™wÂ0C‡¥¥%œ;w¯¼ò *•Ê0>ö4€‡t]ÿ›'žxâÜN¶¸¸øÆØø¹A>ÈçóáÀ8pàöîÝ‹h4JW*aäàœ#—Ëáܹs8}ú4–––Í!è>Ë9ÿ=öØÉm)ÇŽ“~ü㿇sþ'®ë÷s‚Á 8€ƒâÀ”°#l:^yå¼òÊ+8sæÌ À—LÓüÈã?þƒm!ï~÷»ý^¯÷Wü€7ôóÑh‡•W^‰]»vmË.9Âö€¦ixõÕWñÒK/áå—_D þÑ4Íÿþøã}Ë ÀwܱÈ9ÿ^6ÛÛA1†½{÷âÚk¯Å•W^ I’èê"l)(Š‚—_~'OžÄ¹sý…øŒ±ïpÎÿã>úã-#ï}ï{¯•$éÿ¸¡×÷¦R)\sÍ5¸úê« …è*"l ¬­­áĉ8yò$êõz¯9.IÒƒ’$ýοøÅÜÄ À7ÞˆÇãÿ…sþxmn:×Ö~ÿþýxûÛߎ={öÐÕBض0 /¼ðžzê)äó½>¾<÷âoýýßÿý§'Nn¿ýökcŸãœê…ø‡Âõ×_™™º:;œsœ>}O=õVVVzz¯$IßÑ4íŽ/}éKë!‹‹‹ÿÖãñü…iš>·Äó›ßŒë¯¿Éd’®ÂŽÆÙ³gñƒüKKK½xUY–ïú¾ðåM€£GzEù8€ßtûž}ûöᦛnÂôô4ýó‚ çÎÃ7¾ñ d³Y׎„ÏçûÓÏþóÿyì°¸¸’eùqÃ0nr³$Á­·ÞŠ+¯¼’þi¡KŽà©§žÂ?ýÓ?Á0ÜM[èõz¿ò…/|á¶± ÀÑ£Gƒ†a|U×uWYþÇãÖ[oÝ0=@h\.‡Ç™LÆ­üxjjêú~¦0ëi8ܱcǤL&ó¤¦i¿àâ ð®w½ 7Üp¥'z@(Â[Þò(Š‚åeçYÈLÓœWUõ}?ÿó?ÿ×Ï<óŒ92˜™™ùsEQîqÚ/ãýï?8@ÿ&Ð$IÂFñꫯ:Ž70 cÖ4Íw¼ÿýïà[ßúºÜyç¿ iÚ'ÜÄû÷Üs%ú„!`vvét§OŸv]ׯ(•J¡'N|u¨ð¡}ÈkÆSš¦umÏ ¸çž{¨¼G SSSH$xùå—Ýì~Ñ#Gž:qâ„«]5Ù+ŠòŸjµZ×1ûŒ1,..ù „àðáøî:ç´š¦s~ßââbhh ëú‡cè¶]sÍ5¸âŠ+èŸ"F„w¼ãH§Óp⢦i ‘Hä·‡üîïþî-…BáCbU™v›ßïÇí·ßNãó „B’$D"œ={Ýø(I$IzS:þøÙ³g»Vës~¿ÿß;M¯uðàA½G ŒD*•rœ¸T×õ=3337øÚ@Àû§&ž½{÷Ò?C ŒÉ Ø»w/^}õÕ®ûqÎÁ9\<Ï”“H$èŸ!Æ„T*åØ d4M;âôYŽàóù|NÍØC Œ"ïÖ Ff€P(äQ”îKž9½N †]×§½/•JXÂá0¯Õj] ižtà•JÅÑÐuÝ7á´C$A¹\îºO¡P€iš #F±X缫`š¦¿ßÏC¡ãøäL&ƒ¹¹9ú‡„"“É8Zÿµµ5׋•¸)";Ö …’É$û'F„õõuWñÿêêªëÏt5P?À4MGUÉd2صk…ÂÑh4P(\Y§ÝWLeŒ! :ö 뺎ååe˜¦Iÿ0$¨ªjÍÔœs¼ð =}¶kS-˲«^UU±²²âzN3ÐÝò»åÓOúÓžéÉWƒ®¦÷R—.]¢þaT*×ä?þ<.^¼Øówô$Œ1D£QLOO;z"e àœsd2×Ùü••œ:uª¯ï’û98Î98€J¥‚L&ÓqTÎ9òùŸG±XlÊfš¦‰B¡€b±ˆx<ŽX,ÇCWa[CQ”J¥ž Ì9Ç… pæÌ×ù±€ s&“ÁÌÌ B¡êõº¥j¡P¡P ¨T*X__G©T²^çœ[B‡Fá÷û)O@Ø60MÕj•JÅõ ;J¥N:…J¥2ôŠÚÐÖìâœcmm Éd‰DŠ¢4ýXI’¬\®ë( X__·8ç¨T*¨T*ðx<ˆD"ˆÅb´¬aK[ûJ¥‚jµÚWcœ¢(8{ö,.]º4²RúÐÙ%†§R)øýþ B¼ÖU(BUU-@ˆa(‹(•J‡Ã…B"&š¦¡V«¡R©@UÕ¾…cii /^yGíHÌk¥R¦i˜žžF(B0„¢(M¡€ÏçÃÌÌ fff6ˆçõzÝ!áp˜Ä€01PUõzµZ­/_@”Ë———aÆXèäQž”ÕÕULMMYy€`0ˆF£z½ÞvÀP«T*”J%+SÚh4Ðh4Ëåà÷û‡ áóùè*$Œ œs(Š‚Z­†jµ:pR®Z­âÂ… Vçß8;gG`›¦‰\.MÓÇÁ³Ä@„Ü$ŸÏ‡T*…T*Ã0P*•,10MŠ¢Xc <‚Á €ëñ B/„×4ÍòFÆÀ$åœ#—ËaeeÅbÑÕpû-'årš¦!™LÂëõZËÅLCÂ}ê4ŒØãñ ™L"™L‚sŽZ­†r¹Œr¹Œz½Ã0¬"x½^k#A ôJN]×-oµÑh -¯V«Èd2Èd2Ðu}ÓÇÉŒªªbmm ±X Ñh´‰ÜÑh±X Š¢ Z­v£cV`nnÎ „ ˜¦ MÓ iš51‚ÇãßïG €ßï‡Ïç£æ#‚Ã0,Rx¦Ã$¦®ëÈårX]]EµZ»›? ”µ\.C×uÄãñ –Y¸ð"Þ.W·“eìõÖJ¥ÒTU¨ÕjM}Ö>ŸÏ¯× ŸÏG½;„욦AUU4 (Š2ÔÆ»Á+ ÈårVßË$ŽŠÝßXQd³YD"D"‘¶V> ![û×ëuÇzª$IˆF£–‡¡ë:ªÕ*Êåò†²ŒªªPUµiú$á)AaëÆí‚ìbÙí×”h×Õ¤S@œ˜jµ UU‹Å:Íž/˜šš²*"6ëúãdñxñxÜúƒªÕªµµNX"<…Öï÷ù|ÖŒH^¯×ºO¥È͇®ëÑí÷; Q&LÓ´ÂÏb±h];[iþ yþÀB¡€`0ˆp8옰b æ@a‚“n=™LZß-:µ:åDɧÝìFŒ±&A÷=µ¿> ÀaÁí·ã$›0Z‚ôÕjuÓ²÷ÛFìaªªV¿€òH’„p8ŒH$‚™™Ë‚ÛË5NB"‘°7µç ÄÖ-äàœ[®e'ïÅãñ4‰‚ð$IjºÝIùÓ4aš& ðnÁáÅíf§¸žD^IÓv™åjâêc¢7 ‹õ<ƒÝågŒÁ4MK ÄÖ- {•¢Ñh4 ‚¢(®ÿ|QNrwJ’Ô´µŠ„˜ùµõ¾xl~”PX¼ÖÛÖûvr·~É#Ä\^tõÙcøí8µÝDÈÅ4èb’$Y…øóDC‡pëUUí/Š^‚T*ÕØE¥V« |q’ íÄÀI ZV“žÀ”ì⤷‹Óvýí[BF©¶²,[Õñ'Û/!Š¢´uAc–(ˆ\‚½l)’”Fc¤g7ç&c}=Ih¯ñ«ªº#ÉNÐ>Ÿ^¯·é¢0 Ã*išÖ”ˆ²Ÿ¨TƒÁ Ÿ]DÝ™ÖL.ìÿ‹½ô§iZSX²]Ýx€A’$øý~øýþ Q»¤Ukœk÷6Z/X‘L   HÂö€MëgE ‹<ÂNç\†ä)  l=0ÆÖÆØ:•$„-‰  €išßß !@·’[§î=aÂñaxÿ°™!@;Âuz®_’wúœNÄ'ò¶tÃ0þa`8qâÄW¼º™Ðéq7ÂvÚ߉ðíÈN=ê„-ˆ¿;~üøÅàØ±c&çün–¸!¶[ëïF:í×N„ …ÉûnvtÕ055õWNlFÀ)6ïEHœÄ¥›»ßÉ+ &÷=ôÐCÏ Mnºé&À¯P6ÃpCv7ûv#o7 OÖŸ°…pZ×õßw»³ëNÀ;ï¼óÆØïû×ô;ÜÔ`t"v7«Oa‚QaŒÝuüøñâÐn¿ýö×ëõ¿gÐ-FwŠëÝXo7"ÐM„ Æ;ú™Ï|æù^ÞÔ“=z4~üøñ_(û±øö[êtbÂhÏ÷åkBŠ¢<}ôèÑøHàž{îùõzýñ¥O?ý4¾õ­od’ÊN]w½ºïý^¨nÉOè,Þ„ÑÃ0 T«Uký EQ<Ï#\ÿ ®V¯\\\LxÒ4ͦý³Ù,Ο?½{÷"X+Ï k“$ ²,[U§•nì›ýy'qè¥ì×î9± H¯•ƒ^^#ÚA¬NÕÆ(î¿öÚkó'NœxjhÀôôôŸkšÖvýîL&ƒ‡~?ýéOG8•õºyÝ< 7ù§Ù|ÉâQ0Nˆ%ÉÛ‘€˜_ò#øÀæ‡"GõÕjµi_òºu“Xk•[·VÚíEçöu·åE²ÒŒ’$ášk®A2™çÝø¨ëzØ0ŒEöïßÿk¼b…œv["‘À‘#GF²Ôµ›~þNϹiëu; ¨S8@ Œ{öìÁ]wÝ…·½ím¸á†Ћ~¿>Ÿ~ýW~åWbNŸí8+°ÇãùÕ@ ÐuŸ«®º §­ ?¨›ÜJP1w½}ûÖÏo÷Nƒˆº‘½›pÅ#ŒÊ“Ú½{7®½öZLOO[Ï/,,`ff¥R©ëû5M‹†q €/$Œ±7úýþ®ûìÞ½»kÌ"~P?di‘nä¶‹C7¢÷òš›ä 0LâïÛ·GŽA"‘èÈ·W^yÅ1W`Æ €Çã‰9y¡PÈñ`LÓlÊèât‚^r Nî~·Ç”ð" Ä›ßüæ ‹É¶"É“—ט|ãÀ!@ ð*Š2”ÄX³N,Ži_úʉÀ­•v!€[Qp;ÏÍ D5âñ8<ˆ7¼á pò´í|sÚ·^¯ÀôÀ …$'¸üe®É,°T>Ÿ¯«š¹õº¹þ½’ÜÍ$#D~B¿ðz½Ø·o®¼òJ¤R©žß¯ªª£pùúô,‘HµZ­ë>¥R »víêù‡˜¦‰F£a ßï·Š:åÜ¿›‹îTpC|*z…$I˜Åþýû±{÷y¯!q­Vsô4Msõy®À)ãX­V¡ªª(?ôõ£E¢(¨T*–WкL¶XA·]8ÐJðvã ºÞÉpÊÈ%˘žžÆž={°{÷nx½Þ?3—ËYõþn‚“×îZ¼^/"‘ˆ£¢¬®®bÏž=ÿ@á4 ‹Eøý~„Ãa„Ãax<ž&hÍ!tóܾ›Å§0€àŸÏ‡¹¹9ìÙ³sss®ó\n¹±¶¶æhý×ÖÖÜ‹”›b±ªÕj×}ÄJ¹NÌ^=!ù|~¿¡P¡PÁ`Ð"»išÖØ·Ë_÷BøNž A–e¤Ói¤ÓiÌÎÎ"¬7dmm ’$uÿMÓÄÊÊÊpÀçóYëÓ;¹'~¿(®Ž“H’„`0ˆp8ŒH$²¡馩§AèöY„ǃD"T*…™™¤Óé¡Zùny¶Z­æfŸ9sƵûïZ 8z¦ibyyóóó#ÖïªV«¨V«Èd2e‘HÄ ÂápÛ†¡^·~¼ ÂöA @"‘@2™D2™D*• áí¨T*ÈçWè«×ëŽ B} €p=F×ý ÃÀòò2fffKÄ®ë( ( ^¯•ÚC†N±S7òÓ¼€;ËD"H$ˆÅb˜ššrlr‡åÏçóŽ×šišøÉO~Òóür/;ûý~+cï$+++H¥RˆÅb›râZCá¾kЄ×ëíêR ê%&Œ1ƒAD"k‹Åbm½ÆÍ‚išÈår¨T*®®õ“'O¢X,öü=r¯o…BH§Ó¨T*]¿sŽ\.‡z½Žt:ÝwÝs˜3¨´†2²,Ãï÷C–eø|>Ȳ<ÇKœè¢œ,ˆ.rFãvã{¢(X[[sUËçœãÅ_Ä¥K—úózú±¬‚Ô³³³Èd2(‹-a­VÃÅ‹‘L&F'ò„‹ÎÄv.¡¨¹J’dm4pr I’åуAƒAƒA„B¡-%äœsäóyǾûþ§NÂ… ý/à-÷ûÆb±ˆT*…½{÷B×uär9är¹¶D2 Ùlår©Tj¬¹Qƒ°.$£·à>Ÿ>ŸÏ ×Ä&ˆÞoóÙ¤¿V«!ŸÏw¼ÞÚqêùçŸG&“,ï1ÈA ¤ÓiȲŒÙÙYLOO£P( ŸÏ·mVËˡÃH$[úÏãœÃ0 ǤKëåvÓí”\c ²,[ÇK–eȲ ¯×ÛDtY–·õùÄ/ PUÕõûjµž{î9”ËåAôäóyK •J!•J¡Ñh —Ë¡P(l ‰ˆÃƒÁ ‰Ä–ñú=Gvèê–Š¡Óvah÷¸u_ûs­c Ãè(8¢yÊÞB-D«ÝsÂãaŒY¿Ãî ‰¡Ù[§«"¼öˆšÛž}K—.áÅ_ÚlÜò0~L6›ÅÔÔÂá°U& صkæççQ,±¾¾¾!£Y¯×Q¯×­Zkë@ ÓNr‚ŠÐ?Ä„žÅbѵ«/Ðh4ðâ‹/"›ÍÕ[šµ¾¾Ã0,ë/~ $IV…¦i–؇7 ¬¬¬XuØh4ºíÝ?ÂÎA£Ñ@¹\FµZ홼œs,--áÌ™3#Yƒc¨,«T*0M3330Mõz½é ½^¯Õ7]¯×­Æá‰f1H”mÈ"¶Dɹ\.÷ßÛ‘ËåpúôéŽS€Oœ·~uuÓÓÓˆÅbÐ4mƒ°J5óóóV"DÄDö&žõõu„B!„Ãa OúZ­†jµŠF£Ñ7i×ÖÖpþüy”Ëå‘'‡Gâg«ªŠ••¤Ói„B!øý~躎Z­Ö6é!ÚuP­VQ,-10 årårÙjGîÔëO Œº®£^¯£V« d©9çÈd2XZZrÕý7Ñ Ùl±X ‰D^¯ñxÜ‚Nn‘ ÷ÂÂJ¥’?™¦‰Z­†Z­†l6kuyƒÁ‘>"ì1}£Ñ‹rÌ“ÕÕU,--õ4µÞÄ €=/ ë:¦¦¦¬É@‰LÓ„¢(¨Õj“@@333PU¥R ¥RÉJ¦ˆ*ðzŸ¿-(‰H¶•›(¹‚Z­†µµ5,//‹å¼6å·…%Š¢`uu‰DápØ"¬°öªª6‘¹|>Ÿ•@ž@©Tj ì}þ¢[L þ!A ôй*Û寒µµ5d2ËÍßì°±±BtªªŠD"ÑÔ"&M$V,Õ-s*I’5¸caaõzÝÊÔj5kÕ^á5Á±/ŸD E‚ ¥˜RQ¨ª: owñK¥ÖÖÖËå&®ësìf±Ñh ›Í"# n v4E,ƒa–Wà4pûEù±R©X›x¯ÈЊeÑ©&ÖRu«mOˆÖmaáGQ[7 Ã*q¯¯¯[=1“Øî½)~±iš( P¥cÓÇã±Ä@L*ÜíDJ’„X,fÍC ë:*• Êå2*•ŠU…àœCÓ´ U I’Ú>¡^„­Ó4¡ª*4Mk"ü( ¨ëºÕäV(,/bÒÇxlj`¬( 4M³~:ÁãñX.¿ð"†+ï@–e$ k5UU­\AµZÝŵÏJÜ* ^¯·íÀ‡Í!¹¦iÖˆM!æÃvá»}µZm2.[…ô#âd "F"ÇAŒ1«1ˆ1Ã0š¼§®+aÑ“Éd“‡ ¡“ ˆªE»²¯×Û4ÊMT=(¬èÏ]ä÷ ðH?’·“˜ùZ~;Œäœ˜Ô¸iš(—Ëh4‡Ã®‡ ï ‚1¶¡dãÔ‘ÕŠJƒ˜aIDATê!ˆæz½n‰‚ÓÀnâ DK’¤¦á¯bHl»ÛíæQˆÑŠb3 úmÝ6ƒÜâx‘×Aë¨Ê퀉«†J¥‚h4Ú×|ÂÇãñ&—¾V«YaC·!˜’$YåÉt:m…*ÂßÑËEêvî€VÁ¢ ‹a¶öá·­·âýö ‡x½õ;c~‡}h±ý9qÁÛ‡·»µ“]f‰¶a ”ø_EWŸ=g°çj˜Øâø°¬€˜NÌ,'m-ý¨ªÚñ¥C6ˆ\‚ý¢b˜.°py Ã50öÿ^Ôú·bü¾­`”„Çã±Zˆíqœ=k,²È(r öYE±ˆbë&,„Ñ^?­%?EQšJr´Èë€Nž‚Èò‹EIÅ&²Ì")eOLÙSx "ü°»—b³{$ ƒ{‰öÿF¸è m‰@ÐßIºœ¼k7­–=C-’[öðz£R+„u²[)§pd'YpqEbPÜ Â·KÊÙIÆ ‘¹o·š=ž·gÁEÂL–å aˆ€®ëMÍ,ö[A€­JêÖª€ìv!ívN $[ö 3;-;ÖúØ4M+înë¹n¯½>.îwòH쓆özÞ;‘±õÛM\Ú:Yi7ËM'ØÑ}©óvDd¤äï!‹]t]‡Çã±îwŠ‘}Ž\r€#ö„ €&2ŠûíHÛ©)FT"Dâ±r‘u%ŒŠ¢X=àíšaº5Ê8½F Œ%<%ÌU'H(@ ì4 €°@!  lI4†!YÂÖç<3°0Æ^& º6a º÷’tz`àœw3I׎pà `ëçv«¹·«¡“¶¾5°˜¦ùùIðºÖ­eî$&ˆÝM8ç&Y–¿:°Ü}÷ÝÏøçIñœ¼7¢Ðé¹v$o÷ydý [ŸzઠÀeüñ$xn¬¶Û|‚“kßø$„ GÙãñü™«<›îºë®¯1ƾ4î_ÑmHh7âwò œò zè;õ×Rð„ð'>øàòÐc°<Î_á›w#w¯C^;¼“'@d%L"c_:tèÐÿv»¿k¸ãŽ;V%Iº—1¦SzÍÈ»­¸±îÝÆí“Å&L ^äœß{ìØ1sè‹‹‹_7 ã×ðq €«ÝËg9… ½ˆÂÔ›.aB¿×ÎEÎùm=ôÐz/ïëy,À¸±ÄƒznÜþnSw Ój“¨z…a¨V«Ð4m À3÷Þ{ox$ðK¿ôK» Ãx@\¤gÏžÅ#<‚b±8ò`PKî–dn< ê$L ÄB·â:Tå ªª`C€P(ôˆ®ë^ûsÙlÇÇ™3g6MœîDênÖ}Ü!ån9Q­VQ¯×7¼¦iÚ;ï¹çžßªÜ{ï½7—J¥·µ{MQ<ñÄxòÉ'‡¸‰Ñâ÷^¬w?"A!aœÐ4 år¹ãŠU—ç©üèÑ£Gw M¼^ïÇÅb’¶jµ ¿ß?ô•mÝÌ2;Œ|€ÛR#% ›D"Ûn» ³³³–áé´éº’eù¿¹ù\ÇIA?üáÇÏ;w•X\³n¾ùfë†I »¥µ[ÜnϹ±èíÄdý‡¨ì8räÞô¦7A’$øý~\¼xÑÍ[?pï½÷þÑ<H|>ß¿óù|]ýÜd2‰ùùù ±ì0Üd;ùìi%ë{:=ïæ¾Ó(@ £F0ÄáÇqÕUWA–_§éôô4öíÛ‡ÕÕÕ®ï×uݧªêÝþÏ@àñxnv²þû÷ïïøš}škÇ3ЉäÝDÁmEÀÍüÛe0 Íä"‰àª«®Â¡C‡:òåŠ+®@¡Ð½ä/Iêõú €×ëÝã§ N,ìèõz{Ê´ÆãÝ,¿Dï”èöx+‹…“‡t:Çcß¾}Ž×v<‡' Ñh8 ËrÈɰ»(Ý`š&E¦ie>ŸÏ•WÐ)η‹B§×º½Ɉ¿Õ-)‘2àóù°wï^:tÉdÒõû¼^/œ8ic3 @0dNjÓëJµ¦iZË`˲ ¿ßßQÑÚyíâüNa‚Óc7$ßnƒ°¹ç~vvû÷ïǾ}ûú ‹UUuô8çÑ «NjS.—û>!b}½z½Ž@ €@ ŸÏ×1Ð*nÅ kï†øT $ôBú©©)ìÞ½W\q‚Áà@ŸW.—]ynà(‘H¤âFmêõú@?Ì4MÔj5Ôj5x<ƒAëLjUs{§)Àœ,ûv#=‰ÖøH¿gÏìÞ½¡Ph(Ÿ«ªªe,»¡V« G<‹Å (Ý×Y]]ÅW\1”)8T«Ux<„B!k³R¸O­¥Â^.ú~I? !—kN!Àhàõz177‡]»vann^¯wèß±ººêø¹ÕjªªG ‹9ºùõz•J‘Hd¨?Ø0 ”Ëe”Ëe0Æ …‡›¡•”ݬ¾ÛIBÆí )·dYF2™ÄÔÔÒé4ÒéôÐ;a[­zµZu´þgÏžuÿÜìäóù …ãŠ\.¿ß?å©×ë¨×ëÈår$ Á`‘H‘HápØ5aݹSÜO9€éÖÇãqÌÌÌ`zzzä„oÍ•­­­5åÇ:YÿL&3\^ëLªV«ŽqüÊÊ æçç]—išV¨ \#áD"ƒÁ¶•7ãüö!l²‡Ãa$‰¦m\„oõ‚WVV`š¦cÀ /¼Ó4‡/¢Ù) ë:–——Guƒ¦i(‹ÖŒ1øý~+™ ;fOÝXø^"!løý~ÄãqkK&“ŽÖv\×ôêêjÇÑvœ;w¹\®·0¦×“dš¦ãÁ躎K—.azzzhÙÏ~C†F£F£Ñ¤ì>Ÿ@^¯>Ÿ²,wõXÆPrn Yù¡H$⪅v°¾¾Žb±èêš(‹xöÙg{rýûAî½{÷BQd2™& Ûîàjµ¦§§›6¦inð„H’d‰Â(bAòz;W¢ƒT„xâ~0KjP¹\Î1Ô(•JøÑ~ä*Dš…šššÂßøFT«Ud³ÙŽójš†ååe„Ãa¤R©¾Ú7†at¬€Ø“Ä|ýæˆü¯»évoÌçóY}>ü~ÿD“~¯±B¡€R©äú=kkkxþùç{nÅŠpÎQ(055…p8Œp8 EQÍfQ(6†sŽJ¥‚jµŠD"X,¶)ÕQx½X-û¤)’$Y™]Aþ~ܸI5잓ȵH’Y–­çÄ­ ùv¸.z¹~J¥ …‚ëÿ…sŽsçÎáôéÓƒ‹í ŸÏç133c¹d»víÂüü<ŠÅ"òùü†Ò!çëëë( ˆF£ˆÇã[Ö]ëÕemwßé‚`ŸWAÜ·¯hß·Ûôeö}:µR ÏÆþ\ë´S’$YÞ¸do½OhÏb±ˆr¹ÜÓ\šš¦áäÉ“Èf³Ãñ¶†ñCÖÖÖ0== ¯× MÓ I’É$’É$òù< …B“«Â9G©TB¹\ÞQBЫhˆpi«…M„öÐuÅb•J¥go/“ÉàÅ_t‹2g³Y$“IÄb1ÔëuëÇ,,,`aa•JÅÊnÚ-Q©TB©TB(B4ÝÔÒ!0 Ôj5T*ÔjµžC°F£—^z ÙlvèáÛPMn¡P€iš˜šš²†øÚXÔ\P,±¾¾Þ"ØG†ÃaÄb±±7ôöÕj¥R©¯Da8þ<Ο??²U¸†îs ×fzzñxFŠ¢4 ÇãA*•B*•‚®ë( (‹–†ay@ÀJ2’L˜t†a Úi·p‡Ûϸté.\¸0Tw,¼62peeÅê …BPUµZmCÜ#˲5’ÊÞÊ+Ä@Ôæóù<|>Ÿ5ø‡<Â$Yúz½ŽZ­¶Áë횦áÒ¥KXZZ‚®ëc©ÖÈ£<)™LÆ*ù‰FF£ÑV€×ÆS 1ÐuårÙÊ”Ú;ø …ü~¿%.^¯—²Í„±BLÌQ­V¶Òªªbii ËËË0 c¬eÚ‘¦ÝE¯€®ëH¥R`ŒYZªªZáAÛ»<Ö:™LÂ4Í&10 ÃõõukX°hý¤jaTV^Ì~5Œ˜¼X,beeÙl¶©Ì;NŒ…)µZ º®#™LÂï÷[{ƒA†ayݺíÄ(-bˆ¨8ˆaÁ¹\²,7µˆ’ ú!¼¢(ÖüƒtÛµZûL&ƒL&3P¸°¥@œÐl6‹X,†h4j¹ìǪhšæ*Ž^Äìì¬*”J%T*†]×Q©TP©T¬ïí£bÛIÝfgOUx”bá×ze …VWW›Jà“€±›ÆJ¥UU‘H$šÆ[Ûwˆ?D¨o·f8ç¨Õj(—ËVÍx=3kŸ(QÌ­ ­sÊ#ì ²‹)éEêvþ¼^ zûóù<ŠÅâØ’z/ÀkÙÎ\.gYþVâ‰\h„jµÚ5ö³¸ˆ©ÁÄLÕJår¹©,£i4M³¼»§ „akCäŠ4MƒªªÖýQz¹¢^ôöOú¯M ŽkµTUE,ë8ºKä ¦¦¦,1åÁn'X’$Kdæææ iš•+¨V«†þ O¡õûŨ4±É²lÍ@Ø|’ëºMÓ¬[AøQ“ÏîqŠöÞ­6W¤< `±X„ÏçC4u¬ï‹0AŒ a‚ÈÐvƒ×ëµævŠm„vv—±8µqKy†á\‚äb6*±‰çÆ>4 T*”J%T«Õ&×~+瞘ô¸¦i( –ëïÆº —_„öÅEÜx²,7U ð:ªÕj×Ê„“8ˆãkò*&Ãbwâ¨91rÑ0 ëV×õ&²‹ÛÍ$• ¼¸Êå²Bl—¹&®>¦( TUE4íyÒǃh4ŠX,f ‚¨ÛŠ­[ h¯HØGˆŠ–^Æm‹¥Ï܈™Y–›Û‡Þڇߊ}ìÏö!È¢i¥uh²išÖ&öäÏO"ìU(ñ_Ûs¶ã„-[ F£…½AHT ì nC¢l(Vom­Pˆ‹eЋC€³Òö™‰ìç¢õ±ÉÖco%èv›Yœkш&Œ„¦iÛšì[JFõˆ‘†áp¸)a#Ä@UU+‰ÔÎrÛ“’vQ‘=ÆPkɽž;'R車¦i–Ð×ëu(вí-; @S”ýì…a–Ø7»¥ïÍIv+cßÄÅGnXb¯èºnåfìaÊN'; @!„Z/"‘¤²'¬ì‰-Î9dYÞSVI\ ¢óL„$$í¯‘C°ŸwAöv™xZ¸…`äâ J€–³g¹í‰1Q* …B~§èA·×³í·ÛI Äùh­ ØÅTÛí°€‰}FÜVqh}lÏ¢‡B¡¦äœý\ïAĶ­á‰Ý+ÕÐR1I¨=¯ÐnâÑN•ÖÉL;›¬8 ÀŽ€(áÙ/xñ¸õ|ˆé³…ØÝc»×!2Ý¢ŠÜƒÝ“hG¸Öïk%v7’öú «{¸ÕÜX»%·LT:ÕÇYí¥@‘h.¿xÝþÞNä„|d…I&Ê ˜ä¹F£a­ßÖ:W;Qèg"$a¤¹¬I€IwÝ €€@Ø~`¶$ô€sž# ¶$² cì" y„-‰ þ¿Ý µ´Öîqëkä&œóo,¦i~€¹YÐŽlž„äNûØ…ÈOØ $é‰àî»ï~À×7S:‰A7K݉äí,º[± f ?üð7‡À4ÍnÆ/íÀn,u?a…“uïôÜVÈOv¼ûÿ§øPàèÑ£_çœ?º™!€[÷ÛÉâ»!²“Ø7J& Œ±ïö³Ÿ}ÐU˜Ð .Ê Ã€^­¹·¾›GÑ©÷¾Û>¡lšæÝXÿžà®»îZð¯0æ„`':tëDÎnq|7èt,ä&&çüW~øáSnßÐS+ðûÞ÷¾'c¿µ™@¯V·Ÿá¯öÛÖ<% “öóß~øá‡ÿ®—7õ<`qqñœó?Þ¬€›ø½‹Þå§aÉÿ{=ôÐÿëõ} Z\\üS¿½Æ£ò†÷óy” LTÎùzè¡¿èçÍ}|Ï{Þó7Œ±÷XwÀ-‰ÝîÓ«å'ò&Kœó›>ó™Ï<Ôï 4ø]ïz×—dY¾ÀÇåôÚ‘çÆ’»!'A €°IxB×õŸyðÁjÕx>€[o½õL*•ºž1ö‡ÔQ@/Ößmøà4‡^§ãpsLÂQ`ŒýƧ?ýé÷>üð×å‡2!Èu×]§ÝrË-eŒý€§Gå¸IöÓúÛHP@38€‡cWýíßþí'á²Îï„¡N zóÍ7?Ã9û·¿ýí{c`vXÐ\soç~·>çÔ(ä†ä­SaÓ  Â&àiI’~çþûïÿî°?xè³3Æ8€Oó›ß|D–åøCsÃòcMDw#nãÿn9 DØü˜sþ§ŸúÔ§>?,‹?r¸é¦›*þòË_þò_ÇãñÃû ƒzÈ߉ô½Žóïä%а`Âñ=½ÿþûõ|]€Ûn»­ à/Ÿ~úé¿âœÀï÷"í<·÷ÝÄêN–¾SÈ@9ÂaxŒsþ‘ûî»ï‡ãúÒ±- rÝu×Õ|ìsŸûÜÇßð†7ÜàC~ €Ç­Àžpã8YûnBÐ-_@@.rÎ4 ã“÷ßÿ™qùØWºûî» _ðµgŸ}vcì~À¾^=»t{_§çzˆÈOx`aaáÉcÇŽé›u ›º4Ø‘#G.øèç>÷¹ÿuøðá_dŒý:€Û;yí,}'1èen€^<Jútñà!MÓ>sß}÷å'á &bmÀË^Ác»páB°ÑhÜ à(€Û9çqÓ4›VÏí¥è–ð¬{·V`"?Á€bŒ7 ãóŸøÄ'.NÚNÜâ {öì© 18}ú´À;c‹œó_æœÏÚÉ-–Õvã ¸%¼ñ) 8 Æû€ãçÑ}ìc…I>؉^øÊ+¯TD¾€sþ{ËËË?Ë»À-œóŸà+éÚÅ [Û°Ók­ûØýLQFØöÐ.»öß4M󛌱ï}üãW¶ÊÁË[å@c:€ï^Þþë¥K—BççÜzyûØZ›ÝZp·‚@¤'ØbùS¾ËûšÏçûÊG?úÑâVý1òV=ð………šð \.O†ñ Œ±ŸeŒ]à_¹!µá‚°­QðÏŒ±š¦ù”išßžt·~G@+¢Ñè€Ï_ÞÀ9÷T*•71ÆÞ à­œóZ½7ÂÐ8¶,t/1ƞ᜗1ö½P(ô±cÇÌíúƒåíúÃc€“—·O@>ŸK’tçüZW3ÆÞÂ9? ÜÉÊ‹Á@$ÛËœó“N\¾ýI>Ÿö“Ÿü¤¶“N‚¼“~l*•*âµUŽšV:Z[[[PUõ0çüjÆØ[/‹ÂÕö$ aK‚uÎùOœ·¦i>ÿ‘|d•Î΀N˜žž¾à’È'œ?~AÓ´ÃŒ±œóÄöq:sƒugcg8çM·ÇŽ;C§‡ /ìÝ»WÃüä'?™aŒ¼,{ÌØ×†>‹[ÅÀ¬Xp‘1¶Â9¿È»Ä{À™T*uî7~ã74:U}zHt F‡ï}ï{3gN×õÝœó9Ã0v˜2 # ešæç<Å9O™¦™âœ3‘s°çD>BÜ:=×Ï{ÆõÙŒ±¢ayÆXŽsž7M3 Ï9ÏqÎWcKV<ÏR8ιIv ¾öµ¯MÕëõ”$I)Ã0RœóˆišI~ÎyˆsgŒùMÓŒˆ˜¦é¿Š„8ç~QιlËY0Îy¢…>á–çj”–çŠxm¥A\Ã4Íç\P圗c ç¼dšfsÞ`Œ8ç Îys^äœW$IÊ뺞—$)?77—¿ÜöM @ @ @ @2þ?ͱÏÝg{ûIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/images/logo.svg000066400000000000000000000345331463772530400226320ustar00rootroot00000000000000 logo image/svg+xml logo https://sqlitebrowser.org DB Browser for SQLite Logo 2020Jun05 GPL3+ sqlitebrowser-sqlitebrowser-5733cb7/images/sqlitebrowser.png000066400000000000000000006402751463772530400245720ustar00rootroot00000000000000‰PNG  IHDR&Ü;r±zbiCCPICC Profile(‘mÁJQ†ÿ1K° ZTDÌ."‹PkÓ"ÌERƒiY«ÆqÒ@§Ë8íÝô´hW·5[ß Ea´‚ ¢d:w¦­ÎåÞóñsι‡ð‰ c%?€²n©µU)»³+^àƒˆ ½ãŠZa1YNR ¾so´[x¾ã³OÙ“DíqeêlzÄÐêù¿õ=Ìk•òÝ%•& D‰å#“q®´ñ)ç‚Ë Î9—›NM:'¾#Õ¢Bÿ ÏÄ¡\—^èâr©ª~íÀ·ÒôÌ&å º“È ‰4RØÀ:$„éD°ˆ-Ì’Oÿ÷E¾8Áp ( “ºc¤0” ' CÅ—ûýÛGO«*ÀòÐwãi{-àj³ 732 1062 Screenshot *˰D@IDATxìÝ mGU7ðI^^IïïBG鉕.ˆ(`±€(Ÿ€"E”¦€€ ½÷^¥(U:H! éý¥|û·Ïýß;wçœsÛ»É}aÖ{ûN[³ffM[kÍì}JiÐ8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8€;̰[ûw¬Â3(eÝŒ'iÜÚ/ q ®8y–V—•pºÒ­ü'Âní—Úø?7Îð´ñ׿_[ææEæÄÐmë/ŽÌ­¡áÇ(v4‡øë5·öKkëïÜ8kë¯ÑöŸ¶ÿ¶ý·í¿sëbÖ„¡›ý&{HÂðÀ¥ÿŒJk—ÅtÒ²2_Å3.«Ú˜p-(dЋKº<ÁIþ„‘“Çsi÷$ž$-ñò×4à¥Ì¸òÁ÷¿ÎŸt.H­üÆÿŒ“6þæÏð%óIª¸6ÿÚú“u7nƆñ‘ñRŸ¤sA[Gþà†¿ '4’^çküq'â…u±í?mÿµGz"Ûdïì¢ú8n“?p¡É_Mþlò·µÂ8¸ªëÖÃèYÿÄE–´fâuI=ÀÅ/npäñ„Á‘Î_ƒ8õyÚŽÿbÚö é ÚÍ ÐI@§Õ–øàqA:—šžàuÞYÞñ‡>7奜„SN/ô&üàH ]~¡).þÔ#áV>îÌçpã?.Ì댩6þF|ñ·Í¿¶þ´õ·í?mÿÛ'¬‹Ù+"cˆ‹¿É£ù~4ùËè˜?>„›ü… só*sªÉ_#¾ø»=É_Y÷âfþ×ãœ_zp´‘¿Öÿä X;¤% äã舯ñS¦øí¼í­âYôu6¤ã´#ÃHG¦Ã3x„¥Éâ<ŠÄ‡Oò±¦ yî¼=$-a8 t¥/T>œ”Ÿ¼è´òçøÿsü0N@s 8~´ù‡ mýiëïh ´ý§í¿Mþ˜[íæ„X'ø›ü5Ÿ'øÔäÏ9y ?O¯ÆÿÑ5FŒ§6þææRæîpþ·ù7Z Ûú3·/d=i믕dþZ+ÜöŸù<ÉxiûOÛ¬£ í¿MþhòW“¿²7¬DþêŸh[ݬ9䕸¹‹Ú¬ÎÌ¿]@³µ^Ùê›@‰U['¥-ñ§ã/_âÒ¡â¢ÈH˹¸Š—.̓–2\xuݤ+-å +Ox¡ò·v8è§~ò†®òù×wϰü.jN+¿ñ¿?³b4/ÚükëO[ÛþÓöß‘lù‚K^ˆüÓä&5ù³ÉßY¬ {gÓ?F¼§Õ|â_®þ5NÿŒìÊËÕõ¡º­iˆÒ²V+9dbŒâÓQiCÎI»ê’Ž•&>Æ á”W#jºK-?õ¯®§²ÀRʇßÊŸë÷º_ð¦‡ïqÿÛøkóÏ,Í“‘¯­?mý]üþgÌ´ýgnŸ©÷¼©ÃÙwâ¶ý§í?mÿ1KÚþc´ýçoÿÉÁ¶1°Üþ—·Þo†áì;âµgÜúÓ'®Å?©ìZ¬›NÃ|›:FgB™¼´ntP\¸üq;ïå:M:@à b97®|éÁCÀËÉCÊMþ´eX~7yB÷Š(?¼S÷VþˆÿWÜøoãÏÊ1Z;ÚükóÏhëO[®(ù£­¿ýòÛËnmýmëo[±÷zйÿŽVŸåÉtGõÍž±‹fÖ2.€Ã_ëŸI“¾f Y3ê*¢N©Wæ«§4ñ5s“'ñÜt@huQ³ykÿ0=i\‚r†åÇ ‘N•žzÅ]lù]ÖYH]â.¶|ø)7n+Ôoá%&‡7C¿0nÜÆÿÅü oã¶ñׯ_ÖÅ~rUcD8ã$i‰«Ý6ÿÚü[ÌþÛÖŸ¹ù”yÕÖß¶þ¶õwN¦Ë¾B7úg¢šü7Ãkhûïòö_|[éú+ÿRø¯¿Œí¬ÿÂÙùSŸiãÞšV¡µR ¤~a¦ø:=xazµ0“ÎA#¼L@ù••NM|ÊWfèr¥'OçgÌž²3Ðà×4ù§•Ÿö×e„.w1åÃIù·‡ÐW¾ÛpR>¼@ò¶òÿÛø[xþ·ù×ÖŸ¶þŽöÆá"ÜöŸ¹½Öž Úþ;Ç“Gæþ6ùcÄ›&5ù«É_‹“¿êoòáY€Üþ#ÔúOòe–¾TþÃäW~ÖrC ù&•/=É—ß“õ"i¡;Ô½¥¸aü•Rø Pu ³â7 ÂLèé<þºcê°<ðâÊϯ“AhËÏŸNL‡%nʇ‚ÏŸòÑOÅ¥¬qå‡6|4Cß:âÁRË—Ç –¿.?qÒ¥Õå(W½<âApäK]ÀÒCO8eµòçó1}Þf,4þ·ñ׿_[ÚúÛöŸ¶ÿ’ æï›MþɆáK“¿ú!ÒäÏšüÝña±úGdî¬)dqó)OèDVê_tÈÈ뙇]ThƒÅê?ò×å/fÿ 7å©sêÝy{?ºê¡Œ¤Ç/-ø)¿¦×%_ù†^™5I‡`d˜­>˜‡™â Ú­Óø188ü±ŒÕÊqÝC:E yâ*c8°†å ®'u <­ËOºè†å‹”7x¡­¥–N=(Ç >8@ eËjå7þÇ„0àz†ã¿¿6ÿÚú3'´õwnoËÚÑö+hÛ›ü1Mþš“'‹&ÿ6ùÿÊÐ?¦éõØŒükGÿ´¯M“á×ÙÑ¡+>~.ºÃ8ᬛ¡“ò…ù£ÂSŸàwÞYúñs“^ÓÇ+ 4âÊÌÀ¼¸u}0L|Í8þàcÞ0]œŸrâò˧Ó?þ„ãq•™º ¼z(ǃf]>ÜèW\`èÂO:w1å'ú™Ð eBsíG¤-)7®´VþÜ$nüŸK3ÆG=þ3fÚøkó¯­?fÃÜœ…Úúk±?¶ýg4"²–fß+µí¿sc¥í¿skIÆLÛ›üÑä¯Ñžj}æÄ¶?ÑÉúkMÎúÃ~ôµÌÅ.ªÇ_LùhÕôù³îÇ ½è§ÜäK™)+õKžaû¥ùƒ+/Í”ÜQê•ø7¼2ª ìXwø=:„£ÐèoÒ3(LÊšF˜[çA~=˜ä®óòË/È£ÓÒAè +¿GªþŸ›úÉ[—Ÿ2/û¤òáNk¿¼5¤|ùZùs BãÿÜøoão4cÚü[xýkëO[Ûþ3Z;—²ÿ·ý·ÉMþjò#r×ZÚä¯íOþRãå¬ÿò û?tOÿeI>¸üâkµ Îê«ÙÄ¥œŒ¿Ð¦/‚šÖæc•ÿªÌ•i|®.á¸ê& 7ø˜—zOZ˜/Ž?TM?Ø%÷ô‚ËÍ“òá€ÐW~âBG8þ”ŸÎ?,?ôS6pSoùÑMYãÚRû—Z~ÚßÊï˜ÚAãmþµõ§­¿£=©í?——?ÚþÛä&öˆÌ…åÊ¿Mþlòÿ•¡ÿõSn\qÓô¿àqÇÍùÒ¿jÃ@MÏ<ðL*¿ž'ÃòÑ7ÿÐJ‘gÐâ“W|Òù¯0Pù+4:LáÃð(vôWÐÁ˜$ì©;¼ öqq‡iéDùR>\þ:œ²¤’'„gââ%-eÖmÌ`I9uùðšÜäŸÔþà&/7¸IK]jœÄ¥ý 'OÜVþˆá)†Çá·æmp“ÞÖ8‰küŸ›Oká7qáiãmþÍí™+õÚ’¹’´¬55NâÚúÓÖã"ã!c&n[GœÈœÂ+p õÜ nÒÃÛ'qmþµùg\d.HûëòÕ7Ö0x)#åsC'i]T+†/áiú¿ñ4ÎŒ™Œ.¯¸6þÚükëÏÜzš5Öɾ‘y”4s'ûEæT[FëM[ÛúkN´ý§í¿Y7›üaÇhòWöJn`-ÊŸ¯ íÿÒ¹`¸ÿ {"'tÞ^þ®eqi¿xåâMz1ÈÌž&4ùƒ~Y«É_s²VxrEÉŸÊK_˜›Óʇ7iÿ—†ëÿ(vN_Ö¶à§ÿã†\úEþäz€úÖ~á´)u…—úÁU~òH[UPØ Ê ÃÒÐ0)nÍŒ_wâøƒ&vQ=ƒWÓ­w¿œúqå =ùÐN];oNùâùAM#ùR‡¤)œ_\Ê[—/MnüâC—\ùp[ùs|ªyÑøßÆŸùâ¶ù7iëÏÜøÈúßÖßÅïmÿiûo½çÖþ¶ÿÎí;mÿ­³mÿmûo­Ç¬ù#ëÔb÷xžäËšg„Ç_§Ã\íçZÒ~áÄEþ7|Á ÝÅèßòÔ²êòëôUñg\â3D•‘r¼42åj|ââŠÓyܼ¾1dRnP ‹éÊ‘?e&_ é°e¶¼ÐLœü‰ÛÐùÑ ~´œ|¸DuMùp<Ê«ó„vÝ)k&j6^¾”:5-ùR¯V~ãmþµõg´®·õ·í?mÿmòGä&c4ùk$oޏ1ò7ùs$7„'Üð¤Éß#Þd5ýc¾þ7IÿÂ'OøV¯?ÆWÀ8Ëcm $Îáyè$.´àõO8u™ê' 2âŽbG8ñ'M>e…&7´¸« u#W« 4LYFñ‡aqÇÅ`_^LæêŒ€4¸i‡phÁö Eq‰«ó%¿t~i¸@œòÑà¤Ã«iËâÈ/.åÆ?©ü´a\ùɯ>­|\AøÑø?ŒâNmþe݈k\´õg47Ìzýoëïäý/ã'ë­qnëo[kÉØhûOÛ²nÄ5.ÚþÓökÃZÜÍ•è_u›²þÅ5ö2È5..òýW°¿ŠÏœö€äOÞGº|ѹð=µ¿ öPÓ¨ÛŸômîªìjF…‘i¸2FÇŸÎá/yƒ‡FêŸ|é$8@žÐ ä N˜Îµy&OÜàuI=-áÔ‹›zqãOž„3„“N.¼šå§¼VþhL…éÿÆÿ6þÚü[½õ/ó­­?mý12Úú;ÛþÓöŸ¶ÿ´ý':B\ëB {gíF‡àÆŸ< Ó?²Þ&oÂmý]Úú«/ÂCnx¼þ×úé$þ'tÓ—ÊÕWÂÊuùòy‚S×Gõ.·¸Å-nwðÁ_gÿý÷¿Úúõëwîž=wÚi§rÉ%—”uëÖ•Ë.»¬÷wyÊŽ;îØ‡ãç^zé¥=|¸;ì°Ãl¾°4®§ qò…6zIkå7þ·ñ׿ŸõdˆŸÛÖŸ¶þÚ'ÚþÓöß&4ù‹<™õ ÉŸMþ6šþ±ýè_çŸþ™LwþÉ'Ÿ|b÷|ï+_ùÊçžò”§|ú¢‹.úy'îCäëžè±·bôøZ7†™ǰ@/_ëß”TqžèèÑŸC› àÀO‰—¶biË+&3@ÝÐTB¿p aRŠyò '.CCÒFCž}Ÿõ¬gÝóÁ~ðcöÞ{ïÃ.¾øâYãA-ø ¶pã@ã@ã@ã@ã@ã@ã@ã@ã@ã@ã@ã@ãÀ¶â@}H͘Dõœ~úéǾõ­o}ÁŸøÄ÷ueÖ=v]8z18OçÕ©ù¢чK‡N˜Nôí:„<1RË—òù= î(´Â¿ Ý–z*Éï©+¯, Õ¸!ü¤IÇœÀazp’Ž.ê³ÓÆz÷»ßý¤î–ÄQ:<–DD4444444444444\™`¬È­Øÿú¯ÿzÍoýÖo=·»=ñÓ®N^ƒ‚p qÂâë‡þí­„èÌ·8Ñ¿¹žèß\< ÃI>î6„·Äꢂi@*›°²øã‚<€_]~ŒpÄaHpÄeˆKzÂuÚï}ï{ŸrûÛßþa:ºAã@ã@ã@ã@ã@ã@ã@ã@ã@ã@ã@ã@ãÀZã@^ÑãþÏÿüÏkî~÷»?³«ãÉÝ“ÃùZ¦Ü&Ìý;qÑ¿'¢KûfF­wÁ>/Z±È'Ì ÝÎÛûÅÁ«Ë”¶lHÅ–M`LF¬%Æn¼¤©‹†0Žx¼àÖ.zCšÂ€uh׿ÿû¿¿ï½ï}ï'²@5hhhhhhhhhhhhhXË »zè¡7Ùm·ÝŽûä'?ùÝ®®tå TN ¢ûòGᕹvá COÃBôï.jVÿNšÑ¿Å '®ónHÅWJ- ST¼fÆÐ|~Œˆ¿ó^’1# Iy2ˆ“Úòlì>tyÈ·¿ýíwû¦«SƒÆíŸÿüçËüÇ”nü–Ç=îqeË–-ÛCµ[VÀZguÛÿÌ3Ïüánt£{w¯tœØ‘.¬7 è¿”\Otj8Âôâø;ï¬~ÎÜZAéòѵéèp…¸äáFO:œe‚¶htmH…UV¼0pSnò§Üä‹‹)ñ'/×èðÃÛø·û·÷ºãïø`ÚnLti°&9ðÀ>°vØa夓Nê¿Îró›ß¼Üä&7)\pÁl¼ô?ÿó?/¿ýÛ¿½&ÛÑ*Õ8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8°|Ô:«_ÜÙyç÷énM|ïŸøÄ÷:ª>„ý—¾K÷¡óöaé xµ®Ì/¼Ñ»éØÐä‚èßüÉË GÅ.óo \fö>c¨+*^EóHóÔÌ >þX@p¹Ò@ò¤ì”+OêÂÝõ¦7½émtnÝÁ4hX øáX¾úÕ¯–'<á ‹®\y4 9ࣾ &q IœiñËåÀ/ò˜ºª´ýªÒcøªÔ–åÎÉ–ïªÇ|ñÆ7¾ñm»Ömêžè»µ]8ºt ѯáŽÓ¥“^ëßâ࢕<Á‹+-:wÊ^¬˜@Wº ’†Uœðn a\ nçíÃðïZмÍWDÑCøá4COœ|Ü8à€ëÕ×aº¸±pÙÖ­åüw½½œùØG—SîýýÃ/NÚRá²K/*çïåôÝ£üì‡õ¿8iK…‹.ÝZ^uìkË}>óÀrý÷Ý¢øÅIk°}ràûßÿ~aœX*LËc¼×Ï8ÚÒ-tžàŽÃ«ãàÚô‹_çÝ^ü?úÑJ÷óLåe/{Y9å”S¶iµ/¼ðÂòƒü œzê©SéJÿñÜóyˆ8÷_üâËÑG]>õ©O ³­zøÿ÷Ëk_ûÚ~,Oªã¤øU¯\U@]Ï*úÂû/ÿò/åþèÊÏîgÑgœqFß¯Ý MŸ!}Ƚ²Á|2æÌ×Õ€sÏ=·§ÿŽw¼cÑäëñ…GK]cë‚Æµ¯û­ûòþ÷¿¿üÛ¿ý[1ßW´aÚšGyÌcÊsŸûܾ*ö3}²Úu«ÇájÅ~ô£}[N>Ù·æ.æÓþá.i>]žÊôãç„N(ö¥ÕR¸¯ˆvLoåòS‡}´=·eù\h9‘8pµ«]í:]{&¢ÿÒwë 9ú/7ú7=Z˜® ¢Gó÷ºòŒ+ž¾ /ù£ÃK¾”-\~ ߊ •^.‘º¢©T*^"âWŽ2áO¿Æaˆ‘"á!4X™pSwqðÐ\iòlì¾-q Å}Ú‰KO=¥œù”'–];Eä =v/;|p—µësÎ*g¾îÕ匿¿ìùŒç”÷Û¿_èÏ¥çŸTÎøÄƒË®—ý´´ç®eÃ>õY.ºðärÖ1Ï/§ÿàe¯#__vÜy¿½“.8¹õÅG—ãwøIÙ¥«ßÞûØg9ñÂSËóNxIyËñï,¯¾õKËA›XˆTK_ƒ¸îu¯[~é—~©Wê¾ò•¯¯q\óš×œWÓ"Î>ûìò­o}«œwÞy_çxÄ#QºwÐfórÈ!å:×¹N¹Ç=îQºE­ÿ×ý×òÙÏ~vÇOèÂë>[îp‡;ÌÆÇã†Æ?üÃ?$Ø»ûì³OÿºÉƒüàþ[ó·Ã!ûéOz¡ì¾ûîå®w½ë6iÅÖΰùïÿþïåÓŸþt¯¨ ÚLËÿñ—Ã?|¶Œ}ìc½Òñ³Ÿý¬S‡î—„ÊCòþ7­E¦o_ò’—”nm›ÍËà¡ß½î~úÓŸ–îg¦ÊAÔÓé#WéÏÇ?þq_.·¹ÍmJÆÖQGU~ý×}¶Ä?ýÓ?íëøìg?ûrã{i•=u=W¹¨“ç;ßÙsrýúõ+¦g iL îsŸ+¯~õ«‹} øÞÔýîw¿r¯{Ý«/¦ÿzÄê5šÑû·¸Åì¼Úí¨ŠßæÞa Û2®½Û¼`ãÀ*r€îZ_»uŸ€¾K×¥s®ufúqtçà$ $̶øèÕq်,x±HK8u·dˆr¿äŒ3RyA•N¥¸i(×£¢5³ÖH ñ ñ¬4‰ã†~]gå`"ÆHÁíéìºë®{ꎡþº Á(±Çé§•½öï ÕIÐN6–}÷ßTÖuig>ù eï—¼¼3yd<ÔTæünC0Jì±ãÉ¡þ*z6n,ûØÑ;õärÆÇTö¹û‡ºÖn˜Ë<Æç6£Ä‰ë~VöbÐÛpÀ¦râ©?+ÿ£Ë{ïôæ²a‡éõSD‹º9°çž{ΖÎ8±yóæòo|£PN }„®‡ Ì],\ÿú×/_|q/,þä'?é‹§=íi½¢ZÓ €;‘!„9q¸öµ¯}9œzþÀ'Œ2V8±  SL¶wÀÊ€o}tߦ™jÌ\J[ßþö·÷··wÂÓÿ÷—îׂz%žÀùŸÿùŸåU¯zUo€è>nTvÙe—âôõCúP¯}ôÑóЬû# ”Gß$9xưªÏ•m\1p¬&sÌ1½²dü„׌«çZ«cêÃ0aþê×ma˜øë¿þë~ÞŽS²RæÐÅ/À€–1gl »Qä„ÜcîøH/cÅ/2L_‹Yc÷ôÑRúqí¥¬Œ ”kÃø _øÂ~ýÚ¿“™ø,® `a 7þ¾üå/÷o2ýê¯þêªWçÉO~ò’çÓb+ÅÀÃe>Ýå.wéçÿ§º›po|ãûõaa)ý—r)ê$Ûrø±šíH¹W”;l˸ö^Quiå4lk¸5Õ}k‚Ò]ºÞp£¼"|‰óÀÔºµ4tº´‡^ÎÒ„ÑT^hr££K–‡›ò;ïÒ¡nÔÒsÏU8•᪨†á48•žŠKOž:Nþ0 ó&{ùЪ/]4W>ù{'ôï>M@¾ðýïéoJ ]þt†€½öÞ§\Ò a¼ï=eÓ}î—”±î?xmS"F‰ÊŽÐãw¶¯Î`±W¹äg'•ó;ܯsôX:‰|ýÞÜß”˜5Jhý<¸¬ì±ß>å„“R^Ü›Ë#¶ðþ4Æ '3Ï{Þózåêõ¯}ùîw¿ÛŸ»!ò =¨¬Ÿò”§ôÆ—¿ù›¿éßg<ãåôÓOﯜ3¸²Ì`ò¨G=ªìµ×^ý/• mN3 <ô¡½B0UþÿýßÿõÂ[÷ÑÛÙ¶MªÛ{ìÑ×ݯ ¼îu¯ëý®Î>þñï¿ûqàömüÒ—¾T\éݲeKùµ_ûµÞÀùÿñ{ñˆ#Žè ð‡ß ahÚ|«[ݪ÷¿ë]ïêOn90$¤l¼Í-J~8…ýßørõ«_½Ï;éO÷3Rå}ï{_9òÈ#‹z8møîƒ©O|âûøi|ê3,ñÕ•'–KQ hüòÌrúsß)ÆoyË[оRcøž÷¼çì  a=WR>%ÝØ_h\PH=7œæúh-%ΜÔ?ßüæ7û0éIOêç®ø«¿ú«Þ8aÜKo{ÛÛú9Ê ÅøèTÛ86'¤©Ói§Öœ°šG€¢“±í攵G(AƵ¹í”ÖøÁ7Hƒä5–€5åïþîïúS|J€Óêi¼ñÚ…¹æ‚›YïyÏ{z£Ùº¢a¢ãž0æ{ì±Å|p;ã¾÷½ïÄ_)b,•¾ü u¿û»¿K˜ë¯Â+O7~åW~¥¿%æTªîÆ—Ìþ¡Ý·‘–2¾’oÚëµsß5w´þPÑg ¶V:Öó»ÝínåÎw¾sÏÃImš4Æ)µÆ®}äÌŸÜ4µÎÚKŒë›ÓzãÍZý¬g=«ç¥q:„|ä#½qÕg~žuÖYÛ»‡´…)íæÈ~ÄÀk<™æÁ¤½Gkºtc‹Ðo 3ŸŒÜyÑ‹^Ô·_™Œ…™OÖV{·yÀX䑵¿ÌY{XÌ|ë»? @à–·¼eù½ßû½Þo,»ÇðbžŒë?czÒÅ+^Ñn{Ó›ÞÔÇõeÝ{Ì4žÙ¯j§[ ï}ï{û}ÑÁ ùæx@Ù¸qcߎúÏB}no°fØÓ­Qd‡Ï|æ3ÅÞnBÝ·ìu nïbçÜv 7\ÙpÈÞí »wõ  Ó鯵þ+¾ÖáD·æJôf~yáÄðÐy{¿88ò(®G­0„C‹þ½"H%—KD%U&•B'F~qƒËx œFq=˜!½€¸õÝ#oÒ࢑ò;oŸGùðÀÓŒ.üÄGËžÝëõMñó BáÀ].8öeîõ ô†F yû¸î¸ Á»OxÿúFŸ±æJ2ŠëèyÅnƒí‹B¡…ÐÁŸ“ɺ%hÊ©ÍØ«PkœI~B.¥P$jøÚ×¾Öß|p:KؤÐÞà7¨QæùÕO¯…òNwºSCù"SŽ þ„Ý3ŸùÌ^¡(^ã×è"qðݶ‡B``„Ž2ïÚ2ZNw\ßU6å‡àIxû§ú§¾ìî'Ë?ÿó?—ã?¾ <”^7:À¸º©{€b—×\r"Lò¾´wÌÝTq¥—ÂC@ÀCPS_‚átÜ)fŒ<^çxÃÞÐ+ŽúòþàúëДŠÇP¢ RTÀ°ßRïÚM ÿN7Snwk¬W,µg!>Õôë7&€ú.VÒŸãøã“1õ›¿ù›ýi¦@ÆÖs%å/v\¼ùÍoî㇠ÌhÔ‹€mrêL92ŽŒuÊ`ÍKŠŽ6éW§ÃÆ?剣—Á‹‚Kp§pº•ƒ.ÏÌ †§îæJý(vp•à)‹²g0zdþgŒNãne0Èüvƒ8†—ñ¬MnŽ˜_ð_Ʊýüç?¿|ï{ßë•!kµˆqàw¾G¡ÎÖPýc/ùË{í¶„¯}b÷g©ã+ù&­±LJ½ï1¸%å¶‘›SúxNΉ 2&jÓ¤1>i}–›½èë_ÿz_ÏðÞë'e^ûƒ>}Ík^Ó÷åî´ö.Äßa݆a†-аrŽëŒhø;mï1æ¥SòíUøo]gô©Œ cßc±_i»qæá·'1¼™Ó”iFå,f¾Õefí66¬Æ…½ÙžÁ 7©ÿ¦sJ>€–ö‚º ñl¡v¢åuÌ-JkÔ‡?üáÞPÑ6ø3­ÏÍsOíniš¿øœ5j@n^[Ƶw)snH»…®,dÝW>#{Ñ£sé¿Ñ©á‹—Á# †ú79ú7¼ZÓ†/¯‡Îíý~hGÿ¯itÉK.46•ª+ÌF¡«±@œ' óêÆIÓt½ßÆ7å “|5Ý0BZàRBšÅt\øƒcÊN²´x­ã‚wîâýøö²aßkt¸Ÿ.–qbæåÂNR'c–òÍÓ¿]ÜÿÐW&!ÎÐûæ¿= £Å¯aä6_ŠA™á„Á€âlÒÏR~2Ô& œpÙœèyA“ò½Ð©w>t&Å™âRÚéam‚!È5KexM‚ÒD‘ðšRCnFPP(W„‘ë]ïzý b„_JšS§ºY°Hp(mN’-|×Á©U ®[â¸Ú!?…éÐCí?jF %è§úà  “*åáUÀϽæÝßÄÅuÚH0et¡(¼q"Ë`Å9ý|\q”‚àÔiÓüxæTO™i|‚Ýbø—Rªoj ü!§êN—Û¢?k¾3DóÈœ2ôa„ña=—[¾ÓÅŽ ™ñè“ñŠ’êäÕ*×´)?ÀüóQ= …ü÷ÿ÷ûñOa¦49 &œhÏ ^ð‚ÞX¦Æ&`¸dŒ4Ÿ­'ÆB ÆcEËm%ôÌëÔ ®5ÇXY¨_ëW‡š3N£ùî†CŸùn|S6²Îu_ïOášgn0é/§îÖHõBÖ€ßùßé•"'¿}ìc{}ôÑýšAÑ1>ðÕÚB)U§Ñ1Pxå…!”ÒD± 0ì€Åޝ䛴ÆZ­ÖÏô:è ^½3*æ#¾izhä6áÛ¤1Na·>¤Îqõ'ˆq‡ßúk}úˆ2m³v*OÜ´ö.Äßiå%Í>‡'Œ½ö¹i{ž*“qí/ÿò/û½ÄµV׊/£!C‡1¢jƒvÊ«ÏÜ(0ÿìwŒöãu¡ù\7%ìoæ´W/ò=(ëš1=i}·/N¾ÃbM7&–Ž8∺ÈÞoM™Æ3 `R;sÑC ~ ƒi}NЗ ðÔžùœçrz(œŒ¸”£þž€«Ç5Ôu«ãÇùÕ'7b4Ðò’ωç$ x1Ô8EbŒqÝœ‚¡žê“›ùè%Cªu‹ð—¸àL*c±ñ©÷B|B®SôÆ&†7‚?¼­6\‹·EÖ|w …€¿cröÈG>²¯Ò°žË-)ã"¯ß¤ÿÌ 3^¸É’q嵤…?ßýîw÷· Ð  ¥Ná÷3ŸùÌ$õnú¼ŽŒÂj½™9éçhm˜ò«Î_ûë1ºo(.æ?c€²ÔÙk xŠ„:™3ðÎm$}J0Ž%¸i'úÀ-J´:1îÚ#]gWvnxüúļÓ'ÊCå{©ã«'Òý™´ÆæûB”3Jl 5iG?ôS¢'µ î´1>¤5.Ã/…0$'âÖ{û@Ú0Ì›1!>Êž¾“Ú»ûÌ üÉ>g̸9&í=Œ€Ñ<íôÊÁ%¥m¾ÕäÔGß™tûã„6yÕɯ댃…ÆÃ¸ûbùߟúÔ§N-–ÐMØÓQ&ÓçŒO9 ¦»­ƒOyÝe[ôgÍw×§Ý(0¾ðn§¸ m\;!Ös¹å°;.Æ1Ï ¹üúÛ8v['¯2ŒÃOÿöÝÔ`Œa84ç±Jx7^üÔ-žò®œ¬! ñ ¿6JÀÞ0Ҧȸ•W3g­1ÞCßm·Ýú¾±>1–ik ‘=ÑîÏbçlƶ9ŠFæ­1Âàé5k„“ck†òrËÄØÅ}b=ÓGQÒR¥Ž¯ä«×ÌzÍÜ`<‹¢©¿ô…_ýëߤ6É;mŒ‡vÆWµÞkC°×ü(¥ ÙÇu {Öæ:Oüæ¹yopS&ë¤öê§Ió7¯O„ö8מaa<`È­‡ì7òÄoï1ë8~cÙ)½ow´Ýí ãÕ¸šöªcò ÝÅÌ·:W%5ô~y:¡ŒÏêþ[h<$_'qÜôQø$.~<[ô¡×Mìu ›ö3Fb¯E=ýéOï³×Y“¦Í)i€‘ŽñÐXŒa¡OXŸ´7í›4—@²¡6\)˜1ŽÒé½tÝèñµ¡€ö ‡Þ¿0¿G<| ŒŽôäé¼=Ôñ"¤ç’AhsÅíé†úK‚4hI™fëÂR!Ii4¿†×•†§L8OžÄ§~‰Ÿ|q‡NòÍ*,fõé¤6ùkýO‚úõi–„3Ï:»l¸÷å¯1×´ø7m¹oÿ“ ~}Ç.‡Æ F‰n…-gÙ)¢‡_þã=Cz÷¾ÚÝûŸõë}Óµº†zçuõ»÷ÕV§4ÿvÀ Áä„’ŸðgìRNÇ BòPh§ë·„\Ja€°ëê{ N_sH¯ €úºÆåWGyÜÞÈÉ…‘q§!ð âZŠ¢we)O ‚IN$ ·ÞC¥PÒä¡$|åݼys¯`Þ î>fGy·@ãOŒ$N”(8R7%|€Œ éC‚Ëô9Ü ñ>~}½ÜUÛÅA oµYŸˆ#ò޽úÁÑ/N_ùÊWö¾5K[C†×1jз9EŸ’Ö81è3ïz{ç—1i±|Ò§“ú5åh£‹“²žù.‡[! ,”Â|“C{a´m[÷§Ÿé+ß ÑοÆÊ°ž+-%ã¸rRèõïÜã1@…‡\|óaÙ—¾ô¥ýOýâ30_*hj³öû®€kç”,sßiå‘GÔÞ5ÇÍ[Ê7c^Ðɸ¡¼å”4iJ¾[æ¨zá‡9±˜9c øn„¼>r)5Îk@úr cÛëJæØõ/´#ü³6àS®Ç+Ë\Rkš'^_ɘM]–2¾’‡;iÍÚHqcd5^)¿ Én$X‚imZhŒ[†7 ";yÅÁZ`<é7ãeܾ”úzÝÉ÷Z ãuÝzo¬Oj¯{“æoè] ¼µ”òêFðú”}!ü´÷Øcìæcž1àõF)¯|,Z»)ý/~ñ‹û5m¡u1yã.f¾—«ï}ôØ7dŽ8∾=”|ù1®ÿ¦y­)€QΚãª5,ijìIužÚoûÖýÛ¹€§@1®øÃûoNêsÆx‡5xoNÚ7òºU]æ4ÿ°½^6c\ŸF³¥5¬ôÚ_W‚Aü4Dú/w¨7û¦AÒFÂDÑÿ¸øèêÒ£yÝäÏf%=þº x‹†(þ‹Î0ƒX3aXQa阢±*—W3:ï¬EEåӀćAâÑA ¸h׆Fº`ûv¾ç½Ëé|_ÿ“ ~}cœ%áŒÓO+çt ë>îB°óá+§ó†î'AOé}£6Nt{yWûÊé§žQÎÝá ²O‡»–k AûõãÅq¢©Ï(Ä>‚kü¸uàFe’á¤Dõ È™§p½ô1Xˆ7ú€’Á¸#(£¥F½Ð)/n9å±ýˆG<¢7øXÐb¬ð]àÛ~cÃÚâ¦Z=׌MéÆ4ã~£“ò—2¾”—|“ÖX|öýóD9ÖFÊæcó˜~m͉?ZCíimZhŒ[††‰”#šúÒiü2ºÖzi›t{#ª62RNkï4þÖeð§F&C¾vÃÀ³÷¨½É<Àu¶Ïd í u*Ün²î2y)õ ~íJ÷ió­Æç7·A+7A€ùÆ`MãúoÚxçˆ#Žè nn0t  ñ,7Ñ‚v2¼çÛ"ðÑÏ+21tÅ€2­Ï­;úÂC¯u2rxM$cqXþ¸ð¸öNƒãh´¸ÆµÄ™¹CG¦Ö :·„ã·‘Ë'.ùk]:þС'Ž+?ÀáO¸vÑ–7euÞ¥Á°aKÉ­P B©zžTJZ“†ÀŸ²¹CFy¯%ÆŒ!íäG74S†´ÐCãÐîää‹Y »ðX¸´3"œù”'ö?ê×7vZ¿¡Çóú†›çî»_ÙóYÏ-;î7ºZ6–Hyéù'•3>ñàþgCýúƆ#z^ß8³»)q^9¨ìuç7”w>¨Ê5Ù{R÷jÈQ_|tÿ³¡~}cý =¯oœ{æÙåÐË)¯¹ÍKËA›˜L¤¥¬I00„)Ÿ,ù®‘š½_)CA>~®{‚|#ƒR² °xQã€@GÙ# n+pòJQ[ɉŠÓ&‚~ŽQf\ýœDSªœñûHâJʶ™ …ímÁ'7I(Â^)ؼyóåšc<{ Æ5`‚õ8ØÖý‰_ú*·Ž”9­ž+)¹ã‚2„ÿŒE^¯r{ÂɲÛÓ”ã€x×Êõ%ÃÃ8€ï”Ì䳯øN€uÃGa)nè8‘¤4Pž;yöIcÕÍ ?K¥b\YÓâ–Ë›i4›fÌ™giÏšj ·àX§ŒÕZw©ã+ù¦¹ÊÔK=‰Í…ڴз>„öj¸ÓÚ;Ž¿+­ÃB{t<°æ®0àL›oŒjãÀ’WݱÇgù†ý·Ðx€o ðL‚…x6)Ÿxô­oæàp2‡ã|¡>×}ó¡}¨7TäÆÅ´:ÔiãÚ;m Öy›¿q`­p€.k èd›Ûvuúq÷ГMb:7 [‹«õfq8pæ‚ä•&/A-·+:o¯Ÿsáá¯s8e…¶¸¤'MxI°à‚ ÔR©T ‹WAtUʨ+©! ¸©G˜ —±¡nlò‹“b¼¦lº`,Z©gç {½ðeå‚÷½«üäã)[g>Ò´¾;EÚt¯û–½îyŸ²Ã¡zU‡½ïöÁrÁ1¯)?=ömeë Çôhë÷êNŠTÙûð‡w¾/TŽ£Çàðž;¾¹¼ö¸7•wžðÞòƒ3Ø£]{ÏÃÊ}}Xyèæ” í×ãX·æã(Ð^e°Y/åÛ›QBG¬Ô ‘Î 5‰ëVö›ÁJ êÃPâdz!¨”Émã”°mÁ'¿®`Ü_5I)Ç“Naƒ³­û“ œ+Ä)cZ=WRþrÇ…kðN’s£D=ÝbÂPÁïi0#¸ÌCqƒQ‰f®7£ãÛõ÷-Ü.q{#?•™&óˆ-2°\Þ,’üT´isu!ås¡uj©ãkjEg•¹P¹Óè,Ô¦…Æø¸õaZy+M›ÖÞqüÝåM£±ÞO£›47a¦Í·à ]s(ßE¦Õáaÿ-4†ø5­øWÂô‡kp莋 õùBí íIî¸öNƒ“è´øÆ+›3íѵ¹ÑU~LÿN..Z8ùéÉѧÅGw]ý”Aç¾ôèìѵ•+=y:o_–ð¢!Ä¡CŒÂ¯R EkHOe’._òª<\L@'yŸ†'>n衦„†<Áã _½»1ñ……nLtx –À§y®Â3®yg­ÂZ­§wâ}`Òi %y§z5øè# ^¡*9Ê÷ 7¤oÙ²¥/^¼[^±XȲõÝžh®Õñµ=ñ𥮠úe’@IDAT“æÛ/JûWÚN·G¼†Â¸:üöÍJi·ükÑe»Ãz_íø™úºÝ@ç1 ntdÆéèîôhiøÅ‡FÒ¸1J \z6òtÞY@C|ôzáEA]ÙÅd¨ fp._ÃU8ø·÷§pj\þ„ƒ«¡–¤±¡!.åÔeº’pÍîZôg\ãjÐ8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8°=q€abæ6Òí»zß=1péÄ z6?]<Ú€Ý:F ¸â¢,Ëã‘ý<á”Ó%õ8Âð¸¡}>ôß¡, y…baÌÆÐø|*¬"@@Ý`é åGc‚0œÄÇ/ºixm|^‡6K¾xu S:oƒÆÆÆÆÆÆÆÆÆÆÆÆÆí‹3ít\Ý™nMß}NôäàБƒ;Ô¯áТoƒèóðÅ', }x¡)®ö§|ñ‹‚TjQÈR ‡¯"* ÂÕ•æSRñ0V8õÂ8tÃðÄqA…ŽwlàvßöIrjÐ8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8°ýq€b[ëǵþ=«ÿÎ4‹.::üPÿ–e9¸¡?C¦×é£g'.nâ¹Ê¨uy~å-(ïKžŠË›)Ü#œGCkÜš]Ò¬UE>I£¤ai 6J„f™NB#qò4Ã.4hhhhhhhhhhhhØ.90æ°=ú/7 :²p\m­õoiôëa^úvŒµ¾ý<4Ñ nh$,-euÞ¥C”þ¥äT oañ¨Tœ §¡,9aTmIz—< aS’/ÆnÊ.€^_vû¾DÏö§q q q q q q q q q q q q`ûåý™}˜îý·Ö¿¥Gw¦º1?ŒÓ¿ßëÑ] ´c3¨õïà¢/ú·¼žIô»¤ñBƧ^>vXÉ0@e •ˆÁ é)'„Ÿ†¦ò §Tña^èÔåó‹G]¿ºx.ÍWL;ƒÆÆÆÆÆÆÆÆÆÆÆÆÆíŠ37&¥ÿv ‹Î¬ãôoñÑÏ£—Ë㙦Ë—n¢ý”)>þλxH…›>c€ÂÓÈbXHS)KÅ;o_QnòñË€ä MF‡Ð¨Ëméaâ—Ú¾.kƒÆÆÆÆÆÆÆÆÆÆÆÆÆµÁ¿ÊÑAô]z17Pë¿ô`ÜÄËý8ºz­'óçgG‡}1Bº´šŽ8ZÒüµŽŸø‰nÝ ‰Hƒ„º±*¡Â©`* ¬¢©¬x¸\eŠOžºÑüÒW—ÕE÷€NÉE3å…þl>¿{ìwÆ4444444444444loX·®Wé¸t鋺‡DÏŽþ+Ž_<¨Ó–Ù þèÕtíZ‡+.4ù“úÑÍ…kH급þ¥&R )L%Òˆ4LÀMeùÓ(qò?ñ]Ô<ÃEè¨+\x î(4WF˜ƒþº<0éÍmhhhhhhhhhhhhØ®8P½ÊQ+ÿÑ“££GçÖ¶ú2½y¨¯Gw§;{„=Ñï¹hä¶Dh‹OBCùu~å uõ.j:,Õ0‘ÂSn*œÊ¨D$=~é*°Föƃέé²ÚÀ‘–FqÑ C:oð‚/"yÄÃ÷”öL\hÐ8Ð8°\¼ð…/,}ìc—›½åkhhhhhhhhX6f^刲Oÿ¥KƒèÇ1 ЃƒGÇŽ^,.‡ü±D7¯õùèÐèÊW<âàoížZÿmxp@ôÿQh¿©ôhó’Sqyó¤"Â*¥2)'ÌA#qip5k ÐòtÓpħL~éòÀá?ô´ÓNûX{•£ãDƒÆÆÆÆÆÆÆÆÆÆÆÆíŽ;í´SÙ{ï½ì*~b÷нÝ7ºxtgiü 3ZDŸ¦{ G‡î¼½!Aº4´’O½Ûë#¡Ñy{<®ôèóò £Ý„'º1LD˜I ä§b\P,=•ê»?ðRIqð=ÊTYyW¼J‡†°¼âÄ'ñÂ@ÍФ_rñÅ—öË=?ÚŸÆÆÆÆÆÆÆÆÆÆÆÆíŒÕA{úotæ&¸Ñ¿ù¥{èӌѩéÍÒ};¸‰ møÍäMùѽ¥âG3e×õ ÞXW¡‹•Le#BüÜTM~8‰K£RIáà Æ£#-ôƒ×EõqÒ=ðÃŒÐFãáô4%ša¢ãFƒÆÆesàÅ/~qù“?ù“eço–ËÃDtwz0}—þË¥ÿº‘øÎ;«;ÓáD¯æÒ¿árk}þ à×úôöЈNŸ¼Óôÿ”ßžö'›†£à:¬„‚@íÂÕæ$\!¤0T<—/eJKž”!œ|·Ç•&ìÄ(Ѿ11bFûÛ8Ð8°<üÑýQ[G–Ǻ–«q q q q q q q q`…ð*Gté¢óF׿ÒéÃÀ¾4.Üäï¼³x1HˆòÂcøüu^ae¤ÑÝæ*oAXŒa"R¨Š¦r!®0q¸ž46yî’z€#…ˆXxøáJh{”í—W;àˆÜ”_»Äõå·'444444444444lw˜9h¯õßøéÔº0—þKN8ú²p>X)^--ztçÕ½‡ú·¼Cý\X¼ò<µ¿ öøèäßëæÇÁb  Qa ( …§’)(a¸üpëÊ¢%<é16ˆOYâà(‡›´ÎÛÓL\êš¡ oNœtcâŸøœrä‘Göîbÿ¸JsÁ”M›6•™ß”]lÖ†·s õývÞˬþ¿üË¿·&–]tQ9óÌ3Ë…^Ø¿NÆ@ê§žvÞyg/jkÇR˜yÀõ½#0sâqhQkÂJ8°ùã²KÎ+œð¡rÙ֓˺M‡” ߥì°n—•T£åmhÃåÌOºÆùçŸ_6nÜØÖù1îIZçíiÊ/nX~ÂÉW—φ >uí¼ã!Ÿ:ŠEqá‡h,3ÒRxè%®Kêó%]XcÐÇÕ´äå÷ˆ\å%=ô¥‰ÇœÐB/áÎÛÓŸUDL‚Åܨغukù¿ÿû¿rê©§ö‹Î®»îÚ+çw^Ùo¿ýÊu¯{ݲaƱEüÏÿüO9äCÊÕ®vµyéßúÖ· :›7ož¿­gŸ}vùßÿýßYrêyík_{Õ¢oûÛå-oyKyúÓŸ>[æUÁ³’¾OûO8á„òå/¹7’Ýüæ7/׸Æ5’t…ºÆðO~ò“¾LJòµ®u­rÐA­Z®*câÿð—ô­šSN9¥0L|ðÁe=ö(3›IaØ’vì±ÇöƉ}÷Ýw,ï>4öÜsÏÙtaë £FÀØ4ÏÅÍü¾u’z÷¸ãŽ+ëׯ¿ÜÚ3i ‚—òÎ9çœÞ0«~µ¢ý½ï}¯\ýêWï×µ%½Ê¢âã”=†°ŠúÏöÙgŸÞH5­ñgœqƬa=F-ñµ ƨ63Úï¾ûîóÚhí1VsÍY˼W·ÅÈ ýô£å²³¾UöÜrײ¡ìS.9ïgåôo>³\¶ç-ÊÆ«ýFÙa§éе²Yû(}׿þõ{vpÀý>´’Cžú§*x`yЃ4ŽÅ-®q`ÙXh~ÚÓÍ-k[Öõ©Oõ‚¡ü…/|a¹ýío_þæoþf¬2¹š¬yÏ{ÞSÞÿþ÷÷Ê2E׿É`õçþçå6·¹Í¢Š~žPð€”›Ýìf â_ÇÄ‚î(Ÿ7¸Á fQ#Üè4…þ»ßýî<#Ã,rç!Øüà?(7½éMg×›O<±7ŒZ‡Üº'Ÿ|rÿìµ×^c '%5Ž’üãÿx^½z"‹üc¼|ó›ßìË¡pžtÒI}ÎÃ?|Vð:÷Üs‹› ­©‹,r»FÓ_ú‰ñoh´>묳Ê~ô£²ãúÊÁRÖí-s~“­áÆŽ>´×0D1t]ç:×™5vÍϱz!ã•¡­6– Kƒ£m î@ý=ôÐ>Ÿ°y‘ñ(ü‹ ‹‘?.»äürñÉ/;œû²÷æ_+»v³²î’³ËÉÇSöÝýâ²é°Û—sÎ<¥œñÕ§•Ëö¾UÙt»vŠïÃÛµ¶½÷½ï-ïz×»ÊþûïßgÆ7ãŠqAÜrA;Wºî,EÞYn=[¾mÇnÿú¯ÿÚï•ÖØ£Ž:ªWèßýîw—ÿþïÿî׆*²ÖrŒ¹‹™ŸÖ³¯|å+½ÿ›¿ù›½|]·î;ßùNùÜç>×ï‡vXt9¿±÷ö·¿½8¬¸ãï8/}8.Ñ}ÙË^ÖÏ™qó2/ gì²Ë.‹š;W´üøÃþpÑu[ ™k&y¥ã–Ðý6Š-ý—Î+A\ôá:½‹îã Ò½Êàˆë‰V.}oœþ?Ä‘/e¤.p‚×yûº§<áËÁb  ¸©°B…Sh×EÏ‹N>øÉ+^XZŽn˜!>Œc”H8®ü©¼!±{‡·h ˜ÿÒ/ýR/Ðçä3™ Y¿üË¿Ü ãÿq«…ƒÿ’—¼¤<þñOÖ^°D/JËlÂ6ò(×ó¶·½­ŸÜ€üãåùÏ~’õ°‡=lÁ’~úÓŸöÊëb먼Åâ.Xø@Xiß¿þõ¯/ŸùÌgÊóž÷¼r»ÛÝ®oÑ—¾ô¥ògögåßÿýßË#ñˆ+´•Æ!8Qå+_Yþöoÿ¶nþ,6EÊÇbûùª0&^úÒ—.É€¨ÍyåÔ­ü"È8¡Ü Oâ¡tÊ,ÃQAJ?:N£#h1`0,M¢³eË–>Íí B»úLÂÖïòsÌ1½R|£ݨ_»Ä}ÿûß/„ë#Èú¸œ2¦•¿=¦ø?b\øêw¾RNúÙ—ÊM¸ùXã„1àvU Þ1”2H1p]‘`ìŠ&õ­SCãÛúâ¤üìg?ëÇCc…ñqUX®(¾_t̳Ê×½Ùiý Êy?ÿaùÙO)çœ}z¹öá[ÊE[/-›ÖïTöÜ÷²Ç~›ËY'WNúìãÊžwzù¼ê­Å=ˆ<{CŸ'?ùÉÅërO}êSçÕ}±¿ø‹¿˜]ç›gÞRåq4ZÜÃú?ýÓ?íZ¬=”÷ûÝï~Åéºõ’Á€ÌzEöŠ1[ÖŽ¡Ømè[ÝêV³{_MŸÑÞM¹¯ýë×MøÖU·ˆ¬9ïp‡;ÔdÊp\’¾ñoô{zöÜy–Pæb×ä+Z~\JÝ–Ðä+u¥ãvÆøJÏ¥÷~@f<ˆ, Nú7=\éø¡Zp¢‹Ç•&¾Æ•?é·§ñ‰OìI2,(;›8ƒ…åQzT]äl]àjƒëÃ÷¸Ç=ú¼¯zÕ«ÊøÀÞªüÅ/~±kŸ+¶¬Ìw¹Ë]zEU}ÔÍ ùsžóœ~vÓƒƒrJ‘uÚî5•´Ýëo~ó›{^ýʯüJq >'~“òê§W¼â哟üd/Ü:·éä$xoæ5x+í{§C}èCû“oJ&p’~ôÑGWèþð‡÷qÏ}îsû¶:ÑþÚ×¾V®yÍk–‡<ä!å¶·½mŸN™õ“•Ò(¢÷º×½ú+å5&)ˆN,ñN™^ÛBÆ[êÂöWõWý ¬¿üË¿ìÇʸ~26³(/xÁ ж)›’䈒"eSýã?þã~¼-4&¦å]KcÂÜJ[†<†k'¸˜6Øó/ÜZοࢲSgÌܹ;ÔÜzÉŽ]\7/×íPÖÕ«YG>EN^J¥qÁiо‹Tº8åésÜz$þ–·¼eÓKŸ81¶ÔÉ­&'”ú“±ÒTʤÓíœv×íR¦ò]ë“q¤Ž”feËÏX"žáD]ÔÙ¸tRdþËÏfÝöú‰qŽŽ›5Œ·ÚêUu¦x§ÊtÃ@=˜Úlì0 |my ¦QÜÕÃT¿” Ï,[Ï>±“ÖwÆ­‘R×{­ïAúß-NJ¤~ökç×Ã>ðô§àöLk‹qñ»¿û»ýi8üg=ëYý|ðƒÜ÷ÿ4y¼C‰uRlœØÓœª“«>5w¬‡ Ö.ì-^} 7êOcˆŒëÆñc¯3þÍk}¼­è³Ö$k4yU¹Ö}û™õÌøÞ$Nºáaü‡ø‡ò¤'=©0@gÝŽËßùß)tû&Yý·~ë·Êoÿöo—Ir¼2kùŽ8âˆ^ÍÚ©îd?ë>C‹ŸFÏaC]gk¥öf?ZmùQyö’§=íiÅ+ñæ«yä‘GöÕš&?Ú§þùŸÿ¹—ì/w½ë]{¹ßжFÔm^ ÿ6·Ñu£×:8ýˆ£WGצGKëv‰y Lð€࡟ü à ­ÐHù]Ò,]eÔùN½’Wž± óBŠÀKã¹!%ŒnžT*xHCåÕx8ü$ùÃÔÔS:€+¯'t;oÂòõågˆ+} nŸ Kð#¸™èh›°ãÊP+ÛûÜç>ý)Eþë^÷ºÞpá$ýïþîïúÍØ‚$òÿ…/|¡ÖlNà-Bê"ýóŸÿ|Zqûª2Ôr@q$кfkÒ;Í·;9·` (¿ÿû¿ß_ï·@™à,eä#éo~P”ñ—’š2-X®®ýýßÿ}ùÿïÿõ J®ôiy?ö±õt?\Qã7¼á }¾i¼I¹«íŽëû¯ÿ¹²~ãN}Çõ=A݆å:>~§ŽúB…Ç„gñøÆ0@ip:ã߸¶Ûð(é;§L6#8ø™¼®ØÝóž÷ì…+´þã?þc¶¼”Ë $Ά©n6m øIý¤¯•Oñcø°ÂgPBƒqÂæ¦/?ô¡îm]šgÚ˜˜–w­‰´oœ›ñ@™Ã¯Öo*Çü|S9g‡ýÊEö+'žqYÙ´ï–rÊyë˱§–rþEó×'ù) x‡¾±Bàa”§ß ‚GYæÍÛ L„yx W òò){·¸Å-z#‚[ÆÛ°M„&ÆX¶ÅõZAÖ@ùÔBl ³Œ·â) 'NÔ8(‘ i®1f¾0ÀWm¥ PPÕÓ¦.Ÿ¶É«Æ.ÚònÙ²¥Í?é ò2ò)—–?ÒWóQGòÔç'~½œrÑIeÝö(»nÚµì±ËeýNëËÖ¶–SÎñbZ}¬ùúÁgZ»ã'{ šøÛ5æa?嵸VãÌz¤íؼysß·Ã:ê;õÁçzü0ªPîô§<ÅŒëjʯNúH?£eýKYêdH7¾´'íƒg/“–µU¾ìÿÓÚkGG>Æn¹cÙm¿nŽ]ãneÝ>7-»ï¹og´ÙP.;ÿçåëÇ~²œqüʹ?~k¹ô‚S:ôùãO×úd¼˜£ Máµ±ÇA™ð ¬uéÏxFß?/ùËû¹Ìá¶…<ðÍ þiò‚uÂí@ë„=”Üã•J2Ý8y'õiîüqµVøa®Z_ô£µÉ\ö{†=ÐúeÍóú*ÃÅjÔÛºg½EÛ^g=£SÖ0éžie“uÈåÖ ó 2y†ãò×ý×g!ÉcŒzÓäxó‹¬çÿñû?òãúàÓŸþtqˆH†cl ‡«oÜýIÚjËÊs“D›¯xD?aØV‡iò#ý„q™‡.BFvx&ß´5"m[Mw%ãÖ>ØÝè@þ¸Ñ!yjý» öqÜàÇ_ëߌÇ+ø•1Ô¿»¨Yý{4FaøÉ3,_ü‚°(¤ŽJð¥Ÿß“FÀŽ›FOÃä á…nÒº¨Y ’·NFƒá"tcÄ-éI“wv šÌ3Œ†³¨ EÉ ð èøðMÐa¾„å“îæ+h â¼øÃ½ÕÓÕ/BÅØ¢b±âÚœ}0ÓB ÏU5”Řà˜òjwTÂ|Xø"|iÃûÞ÷¾rÔQGõÊ A@Ë6Zp)Kñw¾ó{ ´òÐ!\ª“2ßµpZO@÷³ŸýlŸ>-/ ³¼ut'÷¸Ç-È›º­«áŸÖ÷Ÿ=õ-å­ß~¹pëcyÏb®MQêú‰“ƪ+ž/ÞX„Ý–¡0²ºmv}ìc{ÞØp]… _åýÕ_ýÕÞŠL‰`=÷ºˆ1S—ÉÆ+ ïå™ÔOò'¡>Þ‡ÁŽqвKiDËøIyê7iLLË»–Æ„ñ8äÙ´°qSÃŰS·B]cÿMeÓNÝGGØX®õûgßÝ7”ïœxÑåè[g(¢ÖB%Ž cc¢èŠ3ºà3Þg~×ü‡#ˆW?ʘõÈXT†Óg8„üaÛž¬uÃuN8uLyNÍáZ7Ô…Ò*ÒèŒÖ–¤%nË–-ýø2–ÐH;¥[SŒ=|ÐU¾q»yóæ>Œ'ÆiNÏåÑ^J­:Y—´{ØÆmÎÀSmÙ¸qC9yëÏÊ¥]Oë”êÎ,QÎýùyåÔ3~^®¶©SÞw;hl¬ñ]J˜SÆCÓ´vë¼(nâ´SßëoõR?~ý®ÎÒ+ ¤-üãø„>@k˜Î¨•~–fÝPãØ^ôŸ>³®E˜·ÿ zð6w}¬ÎÆ«æ‚Ûúרr££®Ë´ö¢+±†o jö×”»Zî¢äné»ã²îfÕç—]vÛ³¬Û¿;ùÝm—rîI)¯üÖ;Ë‹¾÷ùnÚ:Ów󠵺9!vÀAad( ˆ1¬‡×úέM§áúÕá‹>õêcn9P:ÿë¿þ«Ï£üÓd)øöHÊž}=ʹnœ¼“ú4wm&ôKö 낱¡_õgö%ýjßá.¥5?»òÑÖ{r¸µ!?ëê¸ò­aÆ%¹K[Ž<òÈþuŽàÇeöUe2"+o’Ocø{ÊSžÒï¡I_ô¢õòfêÎ ë¦ ùÍ:EÖÖÔ#¸Ê­ãøWS~t0ûð}¿úÖ]j•;M~̾㠂¡Ûuº”|ÓÖˆaÛV+¼Üqk¯¬€þMçÞK6  øùÅɞ̟`ÈÏ…ÃþÝygñÐQ^ è/¤ÿw(³Æ‹ÐN½¤DDT¨°Êñ ’&^8 ç46ñòyäÇN'MþÔM؇:à¯óÎæU¾x´긃ί…ªcæ&¥Ï õé“pξðŒòõ“>[Î:÷ôrð®[zÁ)ùâ*G~ÅÁÇ.dÀÚœ²þ¹%,ª6g „IoB±öY,o„zJ«° [xXGáºìÔ‡¢+Í *ÁÏ"Å*ÉOàK½L€Ú/¿EÎí Æ‹”Gô<6J+E¸eAùvj5)¯EQºS¸”t×ç «Óx#}5!íRÆy[Ï*ïÿþËzÅâ¼ Î/ç_|n9hŸ å­Ç¾ Üã G^Žÿ6H`SÀ“ôÞnÞ¼¹ÏÇO¡³˜<Æ‚<°8Ãðl"ê'N”eé;1T\|5è×\«_¨å“? ¤±üš×¼¦¿ºh»N4ûic‚ñmRÞµ4&²CžÕüúÃçY·ç×Ö¾_÷Þ¥{§³[¢.¾xÔøè5K/µtÍù…É<§Ä”RŠ˜þf¬°ÆÔÏœ ¤¯á(G8ýFQ·öPÊD7´Oø±Áã“7íUO0cÝïó¹a<«Ÿ1¡mQBåÎø7n…ţŸ ^ ®úd bŒ (7kâ–-[zãžõ†˜a‚¿®º©gžKºðµv>¬{ç‚;–ƒw;¤œ}ÒÙeM{”«í~õ‰¼ Ë° ïfx²P»_œÚ™úÚXÁ4Œ‡ÜTÐvu$H§o„á5dÕqüƇ<ꨜIG”„ºêh]4Öáè+ãÃKn=¶ÔO^Z©¯¼@\Ò'µ×lj*Þà›µ;F™žÐ*üIÛµiìÐÕ¿gÑ¥]?tÏÙžV^ýÕ·– Î?¥líügw’Ò¾ܸ¼àÄ/—ÇïÚ͹^…ÞZ݃ÔQX×ÈENCÓx£2NŒãqû£øŒôÿ4ya7BÑÐ÷hxø¬}/Œµ Wæ«›0r3ÙÂX`Ðv#4ûçb[e€ióÓº‘t{—=ȽŠ\N–²þ¢eß1†‡ÀbM{Ç;ÞÑ¿Š"z[ á×ã;ã2ë°µŽ;IŽ7æ­Ïdû¬ärOè¨[æùÀMÛRçÌaüjÉÊ#—F.P§ÈÅê0MöôŠ9ž›í¡ ‘hN[#V[§ÀË•ŒÛ™½Íà´É´ø=„}zs6íèßÒ‰ž:¾'qÙˆàE–×bÇG†‹FâäËâ)>Úò,Qþ§!*H¡¥ñuCS‰4"U‘Tô¶qâ’rCº¯í¯ÛX.¼økåíÇ¿¸ü¿-Ï+ë×m˜­‰Í€ßɰTƒ8íŠ!HZ®OØæf1l\,ã@ئ¢¿@]ÏŒ…:®GšÁ ~✪ÏMnr“žÎBý”üèëo× YÙÝö èC ®t0iLØLÊ»ÇDߨþ û+(¦§žµu´ˆYSº•¬çag ~…´þµ¡t¬x+Θ1¯ø [u>åÖaþúAŽñcŽF€J™â ú¬eËGyT§€ü }8ÊR¯Ô!~.!Ãh=pSyuý’¯Ž3æår­lWÔƒ£\@øÄ'PÏe1”‰s­Ýk!Æçj ©_Ü²÷†î{ žZ¾wöwÊ^»ïUvº¬û˜éyg”ïŸôݲc÷ËG öy)úö £ù®þø¸P»µW>¼’ÏzÁ–‚ÀîÄ-üâÚo‚3m,õ™ª?ÊBÓÍã³ý.ÎxÓžš®~âiý¢ѲªÃ?xãòŠ7F”m_ü5î´öÚCÉ-[¶ôí÷z“:;Y_MXŒü±C7ç:îtÿ.*^tn9îì3º=èWú=hÿŽoö o]¼µ<ûûŸ-Û¡ûþUX«{™ÅÞô¯>°–ÔP÷»}Ô¸°?æõ´Ä-$Kéçú†§|ú›a¿·u9¡ÝܵÅk‡oH|ª»mc-$¿87.ÜÆq fÝ÷Š‚µg¸§-ÔšÅÌÏŒQJ½ ‹¬Íêà•Xk±ÎÈf¿3Æ­»58Éù8:—\ä°0ß ~Æe\ô­½^õž$Çóöt{ŸýX[ÕÅžÒþzMN9âAÂqÅ­¶üh_¨ËÃ[7`ÔšüHn–ñÇ÷;ÈÜnf]™:ÅJÇ­þî€Þls°(Ò…éΉë¼}¼ôú‘ׯ W>®¼Ñ¥…<âjzòÁ¥«3ФÜàÔå‹“äIÐmüRÆ€ .5…(Ì#¾+¸®HìqTF9I–W8 4€F8a^pÄ…±ò']0ÿ%6ªZ"–’‰áô¦†oœðÅÞ(q«ëYöÝõêÝíÞQ>öÉw—[vDÖûå·ˆx|5Ø¢•÷#Ź^ì„Oʆï XtYüÖ^ð®¥:PV Nõòn˜«ˆh !“™å•`æ´’eYÙ®@É/Zm ¥ˆ÷Xȼ2"Í"†¦ÇBçC9yO nÊ‹•Ò5b7@|ø3é“ò¾öµ¯í_×&„˜õ›| ñfØîmžß÷]Û»!é*öùvVðîß—[®sà Ë×NxmùòO>[nuµ#æÏZë#¥”9ïâµ÷ mFOúÓçmN®½ûÇåËÌ„c›- 1~øöÈQGÕ/´ÞŸ3„Ó'xj7þºR,øÆaÐ;·Ùm‚ðCo\£c“g$så9|b4sb`¼Üínw›¥%ϸ1ÞNÊ»–Æ„ÛL Š‹¼³šË6Æ‹/œù Ínì¬Ûq‡N íVéºÔuÙE]Ü¥—ŒæÛ>…‹¡ÿõ |¡i]0¯ÓÇÜ<¡“9)Þ ®~"(ÅÀá1óœòjÌ®j!-ýLxwêlåÉ ÄË/Œ®0À ¸ÊD+ih¤>\éqCŽckñë Po%`0LÁRÐOæ/î¿°Ï(±ûƽˮö(t×û‡åY02ùÕÃ"éêâ#ùȾZÒ,6j¿@©!äùŽä%xö¼ûš…ÃbÌȰeË–Ë•Y·×5ünE<ûÙÏî]íAÃã”Üÿþ÷Ÿ'Lyä‘ýiº×*(Ã~)‚¢mÁ$èúè÷ãÒ>qá£>º_”-Ú©ÎÓòú• †šXˆVå㊠ñ¦¯ø*ý©ûþà-û–ÓÏëæŸwW~»¯ëU×ÚïºåÝ{¾·Ûïžå–‡Üérý`a|žЀÇ-À‚Íc#Ydúx߉ðEÌOËÚÄ,À>øã5·jð_óò>s÷GüÆÅ¹‘âÖxóæÍýmÔ¤è,ÔOè#~ F¹-ƒ–ù ~3Æ2n•?iLH›–w- ãy/‡üN˜0@¹¢ôàëŽë»«î—vߨu]>§3LtFÁîߎ—m,'º¡œtZg¤ÓŒ„†­:OÅGÑTnÒã&NØc,hŽëŒRÖu´aSøÅ1XKzÖÍ„ÍktÖ0ãÇ­4¢8'Oê®òaeíùÿìÝàeEu?ðaaé½IvéØÁÞ{×{C15±$þclK¢‰‰%ÑÄŠ]{Wì½€€€ô*iKÛå?Ÿy¿ïoï¾}ïýÊî²”{vïoÚ™sfÎÌ;çLy”féÃO—†4uÄ[¹¬„Ëg’¡ÜÉ«ßYQõáÀDLßö~3ñ5 $3ïŸ÷k¸Žá»º\ß Võ&[ïÖ’eKʺëÕ k•ÇF ~¥‚,¯®GyîºÛÝZ}ºüS?.`0"ýŠÜ'Õ¾þã]Ôî™È‰g( 2#íáÌ~øÁéú…õmÇÐwð"k}Iù€¾o<Ðþ]þ©O\¸ÊÄHFád¤`g,é–£ë—'a|ìJ£ˆ#ã\Ò'Õ×·VŸÖwàûNæ˜kö|y9ç´o— Žý|ÙbG•k6Ýyì7è›ßªÜ㎯nuè–ù†ø R>²ž ‚c…Ô÷ÐMú¾= šæ,”Oý7xÜIóÊ£o¯_!s‰¦qÔ®<ýEÿžïCz¸aJÀBíùÆc™ñÖ|I?I DwçX«»& ´¾CÆeFp`¬÷½ Ã|³”¤lüvªú†o’.Þn ‘Æ$ãÚp¿„oè’yŠ·_Ø7GÏnóG‹+¾”|óqeÝr%<'þúœ?*›tv*‰Ž|âøÅÇø‘8ñ ¸Ü]«òôexUÁäÑ$ÎÄÇŠŠè¤óŽ)çntt¹ÛwjF‰ùý²ðŠíÊ“ïùÂØy™ÐLM FҀɕÊ$ß$Ï Ú<ÃW«AŽ œox}x&Æè)GküðÏ(0ÙÒk"¼Q>à+å@|ÊÀ•¦NhI“_=¼Lüãò’GÊ¡Žd,_ÚNÚ$Ù¤ŽkÂMÛŸuÎåÂõO- ë‡ç²Ë/+G\ý²i]ù¼Ë¶.Øç)cYûP‘© =9PȨû!òÑX´hQh՛̻8iqÚ•¼´zú"9¥¥Ý)që±xyÓ'´-?˜ÔNÒµ:ᩬ +v ]i3õ‰IyWWŸP/»Ü[‚f&¥uñæë' ýçÒ+®.§]²q¹í⪠.ô³žWWãV5l–z_ÄÅ;–cO¿¸ÜmÏåÇ€ÂOydÛ?¼×h[Y ÷ñÚCÓ7àh_ýH›“¿¾ ¯Ä‡f×õþé—úž|Ââé×É[½ /áð‚ëèù'|¤­É´RB'¢K¬Ý&?&1ÀÉì_!ø=p„¸)th0@ð‡?š‰ã†Võ6ƒ…°xOò‹“ϳS0¾’IQ ¯ÐÁu|°_òƒòÃã¿\–Ô-º{l{Ûò˜;?«lXWGWº¤U¡3—¼x‚á(4†Ë4^ÜIô&å”íIyÃ{MºÝ¶å÷Ÿ^Úí±åÁ»&C3ñÍÙÀ9 Ži°²Û1©Ž3Ég˜îª„'•cÝ™ð'•}RÞIù”cR^é>ZvíXQ°½¯ÛvÙ eu‡jXacŸ/¸çò×§\SÖ_X'¾:Va «—¬]³N¹ìŠuj–•v‹­u¾\f—o”¼FÅM¢fò¢/&å+/ø.3³ o²abbBBéTŽ.À£Ê5W¾]º«Ãoò¨ï)ó:½l³ñ¶e£UüV¤\“êœqîšK÷Çw\ü|Êc¢jWŒñoßüE‹µ1Ããí8ú«"ÃquYíñ×VãÑ_/ë\{^YgÃÊ+þð±ú zÜMö4J~Ãíg—©E#c¹R]Æ]i]½¿—@$Àxù†ÇŽX "ú ¹…ùcºŒÁó…áþ<*Œö¨ïŸøa|qk æÊk&üIéóMS÷Iy×”lV….ÃDÝùõðJãŒú0x@ thO IëÞ A ^ôñä1‰âçJëâÖ` Ó³áé 'ŸxåA#tÄ…6ÿX€41³@Œ»ÌÎ Qa,ýqÅ¥RÞF¸\qhJOR1n—OÂðä ^òŠ­¤mPãÀ®õ|Ò—L{è%pC–k»ÇóV¿Üàøã„­€À–`F ç-»ç>W?÷žâªJ€˜Òiu<;‚(£ýؾª’½iäg°b¬²Ëƒ!Âj"…„f'ë7ˆAÊQョ‡^½z ÜT%à[WRvwLdУWg7C”^iâèÆütå,øéäÑÑ¥G·ç÷xpС“|Ãiôô.Ž<ò£·‡nõŽ g„ t ™ŠÅ zÝ‚¦2ÁE/ .ñð‚kéPṡͅ›ü*Ÿüü@Zè1Žì\/JùòêÞ1Q½V§([¬ÜýÄjuJuEZŒîGqpÙèë_ÿúÞ(±¢˜n°!; G/^½n˜°€Y ¬¥;£>]DŒ ‰‹ÞN—–ƒ€øà&ž àУшÎüpè×ÂÑˇftï¤Ç0ŒSQîHˆB?2q*QÀ8î@Ç ÐÍ'^XeRØÐ"O„P½Ó¸h¥²òÁcíÉžçøC³&5úŒ­<&¯ý–Xz¸!K {†ü†\ÎsÙlí>ôÐCËË^ö²V ¿f#n6ãÃ?øÁrðÁߘ«£/»vêwHÜè›qU@ÿè!æ/Þë7(çÍç_ó>g/^½nè,^Òé¹ôß™^ÏíBôoypèÝôj4ЊÞ]›+.éòËø“·EÔ?á/OÂ?tºi+ùd&N‚ˆëV ´’GaRpùò¤p Ž´øc0 ¯ä«(^—&èÉ<.œ~ûÛß®ö;&*Ýz ô¸‘J ¿à6þz ôè%ÐK —@/^½z ÜÐ%`×h½LõaµœgÖ‡®=¸x Ó…óDG·û}Üㄸ쮟\tÉG¯¡!œÝâáä§‹sÑ̃ÏDˆ`R Šè0“„»†x "n8>–.­ŸQ剱"•‚— ‡~\å ‹õlï›ÍŠhÅí¡—@/›ü !èÇ…›Ac÷Uì%ÐK —@/^½z Ü$À0Q®ËÃ(·z§õßèÂѹéÍ1PtñÄ¢G'Ž.ãÒᣢëwõt~¸ÁîwV0Ê0œQ€H……S®Bp‡ñkÔt|ø¡\ù† ’Æ/¤âh?þâá/c˜èÏVIôÐK —@/^½z ôè%ÐK —@/^7: L-¨Ñq=€KÿŽLæîœEý ¢?Ãîž|ÜèÚÒÑéâKáÏ .½Ä‡œð—%ˆ¡`¥„N"ƒT>F€Aìào ÂE7y¸ðæO¡BGXzW½­‚*’ŠŠƒÏä‰a@#´Ñá_Çï›ûíÚz ôè%ÐK —@/^½z ôè%ÐK —ÀM.¿¬ÐÕ‹ùéÝ ú7×C¯¦GÓ›»~úrôkxÂÑÛ£«Kn^½-ýê)W¸ h(G—Nò†Žt~¸AAf…ôPôC0——? 1 ¾B%\½ ÄÁõôàxÄ ã†ÃÊ*]|xToósÑhÆ ­Œ~pÔ…Xu#EÝN1x®«$Á–£f”ØÃV~—pø´îÛoÓâú?½z Ü|$`ì÷“‘~FøII¿Þ0 ;ì°ò”§øðаGå«wGT„ú|²%ø{è%ÐK`nhïP}kßö£R.ͯ'ÏD=K Ëzi•û:uô› OÏ’òÍmã7.\pAÙh£É†éaÃÄ—¿üåò¥/}©œ}öÙͨ‘{*(N8á„òãÿ¸<â(øÃ' wuљȤOì%ÐK —@/^½nr˜º3‘Ž=Y£ÿF÷Mœ0=»ë'ñŒ ôèÕIÏ üøcІ'}aO@Zòˆë¦gÚ‘`:b„' b@袄YrcAQ@a…”t£Bð»•I>ôï*Òì–=é¾8¸èqñ_0<Á\zÝ:íN ;'¶Ü°”;u¶¢ŸsY)ÇœW „j%°ºá¿SÊ;ªR‡ÏÚ‚U:÷ص”[o_ÊeõŽÕŸ^Ê ®­Ò¬=¾úÓŸÊ>ðr«[ݪøm`gÏ­zn·Ývk¯PsäüÃþ°›—²uÛÛÞ¶l¶Ùfs¤27t÷³üìŒG«a Ýr%Íöù{ßûÞ ®àþõ_ÿuyÎsžÓVŸßð†7”m·Ý¶<ÿùÏ_gT`¸ )ž·»ÝíÊ&›l2 ýFו5ÿzFµüáhÇ:QÍ{À”­¶Új8úv'ÐOúÓrôÑG—M7Ý´Üå.w){ì±ÇJå>å”SÊO~ò“ÿîw¿{Ù}÷ÝWÀÑÿäÛqÇWˆ×}Ø}f»c‚1á°Ãkt¶Þzëf˜pw@ëšk®)_|qùèG?ÚèŽ3N¬.:qÿ§—@/^½z ô¸YI 3o¡©Ò}Aôí–F7†K/öÈ“ôèË5ªáÀ“pMxÐNÞêmñÃüÑ“ßÂsZ‘nâVrgc˜áXARn o¸BÁKšB§²*I`ùB×qð =®8¸hÁÛÅO:ÜöXÙʘ2™Ü_Qï{ÔjøÏG—rÁ¹&n[u™%u£Ê§~WÊë¾ÛPfüó—w)e“j2yÛgDm.*僿ð›]ŽÕ‹E±yÏ£J¹o-ÇïÎg^{¿R^õ­º“¤Ö;ðáÇUÙü¢”–˜ÕëÎUn«—û€¥î½ï}o»"{þùç7Eãÿý¿ÿWžýìg¯ –«æË_þòf˜`”ðË”$Ɖw¿ûÝe›mjŸlKË[ÞR>ò‘LTÔBÆ;tM}‡.«»%ªN8ºå Ò–[n9Ö0A‘ü³?û³†ºtéÒâ3•/mÈ£ ý<°wþ_ÿõ_˃ô FãÆúgXÖä¾A­Ì`ôÔêŸøDùô§?]¶Øb‹ªùÿñkÅ01S{­PÈ¡%ÿE/zQùÁ~Pn}ë[F§7¾ñåÐC-üã6ƒÂßþíß–¯|å+e§vjmÍõ€< üû¿ÿûtÖÿþæoþ¦‹@IDATîqu ‚acõPr çøã/_ÿú× C„þõÈG>²üæ7¿™þ jïÝþûï_¾øÅ/–Ë/¿¼áî¹çžeï½÷^ì0áö ²:O¢¼Þí%ÐK`ÍIÀÎ(ïâ¾ûî[Î<óÌ67pdkm•W^ÙÆ†Øë|Ï;ï¼âžžŽb4¶Ç{l›W£3'±hÐC/^«M¦ˆôﯠ'Ó…Aw†.M8qôoSIøèD7>_¼Ž|qÅnøÃ÷€Áä}9/qÒÂCx" :¤"ðR•JAº…„+¬€›Bråƒïp%"¤¤W”F+ù2·s"qá“´”•±BÜÂáA”Âl•÷~)—×ÛÔqóáõ˜ðë*åâ+Kyûé“þ.Þ²”Íë΋М„+ K|g‹?½¹¦ß±îyÀ¥<¦.þæìAîWXÊËï]ʧnÄP/ÚÛªîv^S圫Ü%]3¿ûÝï6¥ã²Ë.+” Î3žñŒ¦Œ¬Ž«—ê+^ñЦ€]}õÕmâ"ü¼ç=¯­àn¸a휀1ã—¿üåŒ+È]ú„#QžIrM•F ̶|‡~xkC¿¼ð/ÿò/åe/{YùùÏ^fªøÜPÝ®¬Ç½‹v¼ÿýu»ÀlÛkTQõ«_•ï|ç;哟üdÛ9çŸÿùŸËÛÞö¶f´²«é?ÿó?›òÏ xà62ŽQ<÷¹Ï-ï|ç;Ë‹_üâ·ªb˜P&G?ÜMá¨Æ!‡RΪ¿FÃð?L¾á;êWž½öÚk…"téÄ(qŸûܧtPýØt@ý9ÆÑé öÞ^½æ(û·+ŸûÜçVÈõÿðåþ÷¿ÿ qvmýîw¿+¯yÍkÊ÷¾÷½¶ƒËN¼“O>¹Ëó˜ºõu¾ÿýï7|Ñv_2j<ô¡mÏê A¿dç¦oöð|µ‹háäÿñÛøÐ_Óþ·¿ýíå›ßüæôá%/yÉŒFÿÏ|æ3m'êcûØö=¶ø±xñâ5]Ôž~/›‹è·thº¸™xfãÑŸ¹pb¤ˆÎ,,ŸGœüð@ôu®üy¤…ž´ª-OÓÀW~.4áz¾°´ð‡ƒ7w,@˜ 0ñD)`‘‚¤0¡O¥ñHÅÅu ‹†|¡• ¦"5©áÃA‡;‰x¡Óøg·D OC”ªLô3ù?÷òR>Pw3¼å‡¥<¿î„p–îýv/åkÏ,å/-åÛÏ.åÑû âßü R±o)..åÇÏ-eQÝ9-ÏßÝ»”Ÿ>¯”cëùSO*e×j¼O…¸CÝ]üÕg ÒíLHúLy\çºß|Ö _©ùïvËåt•ñ³O.å÷•çauqÑ1ð캷ܢ”+k«uîòt÷¼à‹ƒFP†Õºl¼~5ÐÜ@kýÚbê÷Ò{\»L¶®Fq;m¾œÎ+î[w^¸<¬LŸ©e:î%ƒú>pÏAÚ(¹=¾^¢øÁ*‹nY¿U몎£øÃ›máÎl¿ï}ï[¬L,Y²¤¹÷»ßýšÂÃuÜPžüä'—;ÜáåIOzRùÖ·¾Õâ9æ˜6Á±â ¾ýío7Åã /la»(7”˜ÓO?½íʰڊ¶î(CVýñ¢pZ¡ýØÇ>ÖòÏôÇ6u—ð½ï}ï+¿ÿýïÛʳÚàÍo~sÛE¢m´9…tæ+kGìIY(ÇÚÙúš çøÀÖ¯|å+[o}à)OyJ“Ixú¸É±þšð‚Æõ§Ùög¿˜ÁÔ½Dò¯þê¯Z;‘#øøÇ?^þâ/þbÚ(!î÷¸Gyá _XìY]@>+vEx·(î”`ˆ`øòð‹“®<É·K'e<è ƒÚ»è}Ì#nÐëÝAûôrèå0×>à›mTßüI4à[°€ã]’>*c¡è:Öe—1ÖÂÇ(ÜÄ™k׌q‰ç;Æ¥­‰øO}êSml3?±KíÕ¯~uëO:é¤Y—ãú.óšCO³gnH}À0ཪ@Ï­Z{ªö6 ⣋”\“)ù=sÑ¿LÑ@+üÑBÃÓ….ÿ”K<îDÀh&@d0+FX¾„_!SYBm…Ê\áÐä&>–.ŽÚÕÛü“øKæ/ß ` z ñÇýÂï«Å»RÙg›R6]XÊ[R 'ÔÝ.åëÇ—òo/e‹º§ú­?,å{'—ò˪ƒ<õÓ¥œrQ)Ù³”'Þ¶*èß,å ŸTàM\Î?ÇÞù“Ržô©Ÿï+å§TJ-‰Üj»zìâQ¥|÷¤RWuØ3þTʇª’¿yÍ“:Åý~-ïÕUâ_|Z)Ï¼Ã Ž—ÔÝ!êqeµ¥]S»òÓj]®ªî»V,_ðع ±w)¯üF)oøî qÄi¤ÐÞjúˢ>·­†‘ÿªŒŸŸ^Êc+å['–ò¾ºÈ°{5ÞŒ’Û¦µ¬Ûo²œèo¨—Õ:óŸKÑš ‹ÿùŸÿ)VT(dŽ0jQê¿öµ¯•×¾öµM¡€RT (Ö/}éKÛ* …*+ÆøQÔ¬®¢~ô£•]wݵ­Š˜è8r`uÔÇÞD†âhrBѽâŠ+šáàƒ.”`“¡Ù‚³õVl<òÈ–å­o}k3´¨ƒÀÿýßÿµU#u°uü×ýW¡€úÅ‚W½êUMñ³rM‘e¼p†¾ ”å™äJ¶ò”DZ `Üê2eŒ¼)Ð&gÊ9~£ÊœI.䮆!,F@Ûò¿ño”Ï~ö³Möüà[[kc`ë)<øÁnw h3ùb`â’Í3ŸùÌ&7~Æ í¨ìVôÁ$>ÚÞêIŸ¾D·#`f’õE]4-ãÈÚG”QÉ Vý¬Êqò‡G õ!‰w¼ã­ÿê‡@}ô‹;ÞñŽ­>&îŒ&&£Œ:Þ nϨöšKf` ”3ì¸ÓÁñÇ'Ï(bGŒwnÄ)ƒ÷m&Ð>ú9ãÕ8È$D]ý‚‡‡Á‘„Qq‡vh¿8iÁ“'ùãvéè÷úÐ‡Ú "×#.0‰Nèõn?QîûÀüú€ñß8“'Ç}ƒžö´§µÞG2þêW¿Ú¾S¬üscXn´ÐuGZ¾åÆ2xÆ3FUÆâC9¤øŠÖ³žÕ^}ÇÕs„ÄnCcµ±¡#|ÌI|?}›Ð2VK—Ç·êïþîï¦ë•Ý‘òØeçø¤E–ÏþóÓ<‹ë;m|[´hQK¿ÛÝîÖî~ÊÇèâÛ÷¨G=jÚ€,_d7ìïÒîýó뿽ÜnÞr›Z¤¥ÓtÖ«jàN-¾ú·|xâö(þøuù×àd@d&@p0Ò *ËŸJ©p*Š\ ¾Â󇛂§bqSx8h„võNCŒhM'VOø§ÌëÚ—Á¢Õð¬ c„'|JÕÁßmËR~ûǺûà›VcÄG«aà…w+eïmKùñi¥\T•z;.~žœu¥µ5<ëÕ’nVñ¿wJ)/¾ûŠô%à?¹øËç”—¡dáÍKê|úµßÜÞ'<á -Åȉ‚òïVVív ¬»#ÂÏ2p0ŽXÝž-Üò–·œ¾ÑD¨›^J&=;ï¼sKcÌ0© (êOÙúó?ÿóf 1©²ƒ#0“² âoR †ʺ‹-S»lyÆ¡QåÆflцäGá¿óïÜd\Jº g [l òÚB»1Î;]ì`xÁ ^ÐÂÚ[›vAþÜaq¯{Ý«õQ þ·¿ýmóOâƒ/ Pï·ß~ÍØÑ"†þÌ$k »BÆ<}ÆÑ;ô=G“L˜Óomµ%;v€£ Pðõeåq—¸ÍmnÓð䟣Úk.ýY[3ÐØ¹ã8£÷ÏêãgœÑØï²K؆ ý„¡@Ÿv5x÷k´¿ð0äý÷N£ÇŽªQ¸îN‘.—òü¡Û¥³xñâ6™O—q"~£è§w{ ô˜ŸŒÍÙˆåÜ7šÒNYgtµØà^ï1£¹±ÚÑ c¢ïšcc ûžÇW:EžáÙXãb>pÐA5þ â(þû¿ÿ»Å3v{÷Mc°sð¿øEÛ‘füÊá^;ú à¸cȂɨ]w˜Fî%ÐK`n0?¨0Jÿ¥›–KƒÄïÅæR[†›0?ÎD<‡ùÏ¥Î)?£€Òãaõ·ú霺­ü£€bòî. ­£Ù Aé¦RXà оI° aû(¥•bd÷‚ cÔ«ÚQ‚¢47C(ö )¶Šº;À™PÊs÷&øec…¤{,!+DŒ#”B“ \V€ÝO1 ëÔʲg¤\Êæ!c@V”dw`0P¨ë8.ß8¼¹Æ§ž”tg}»[é)ëŒV¦Lâì^É$luòq¿×Jƒ”Ý &°]èÊš8rÇU~àÒNÆ »!ôàK~[€MÖgôý–¡DN·š¨­LBí¢ÑÿÑ3áµ :“ÎáöšKVf[“íÖa r熋\ÉĤø)_Çv¼ÊmÒmlj÷‘¢ ÃýÏ1að=H_è¦eRÍàÀØ¡ý¿ŒvAé7 ®×üâ¤Á+OòÇíÒñNëoÝG ãItB¯woÞçŒûö_½íÏͰhçC«ã|‘qÆaßhãµ1#é£\ã—£œ¾ñvJ0|8i÷$Cªï±y%vB¯„³<è ƒÚ±Ïì$ |}Ã…-"cà¸þÄú+µ¦^QwM|±” .¯¿¢pR)/ûêà×@ÞùðR®¨´ÞúƒZ—ÓÂq¹«¼v\¼óƒ RÜù`GÈxC~×OJùÇ Œ÷yß ?E42ƒç¿V#Ç“ªÎ`‡~UÄ çG§TƒG-ƒ_á`Äp‘æoÎЖÛá'vqüG-—û9>vÄ@&Í0¡•+tùϥ΃Ü+ÿÍêCVM(Ê”3Š:¿•+Ükx”Iʔ܀¾UoçKZ‡vØ´ñ¤Äýò;㉯û (V"lËw ½ú¬ÉÃsžóœ_ÁU6ãÈý ‡rH+7¥Ž2çž e¶Zd'„22ås÷€|îÀR>øàF'2ðâ1Ö1p]îMÝrÅDÌn;8ü&:&lvp0öLó¨u —/—u&}Tž¤MrÕÕŽÆ"?ßHÖ¶ÑmJ‘·Ý•2kB—‰ê(šdy§Oâã,®•~òWJ¼;ò&÷å’`ÉLjû-’Wÿ3fprÎØÒå—Ž ©«# &£vÒ˜Œ[ér|B=åìäpôƒaF^;9LD] Òí*Y´hQëOi‡Qí5Ûþ¬9úb°bã„°{Ir.;w‚ˆ¹§…_yò^åþ©@xÞ±aHœúyŸK¼§.¢ãºO0 ‰£°˜èÕ'ùC·KGŸP?t²ËŠÁLtB¯w{ ô˜»¼ïî±1¾Œ…Œ²Œ´ÆdßLc1ðw¿ºä½…o,áï‚Ý”Æ(ñvE2bºß8ºÇxê;Ý¥C±ï ñÖ¢×]ø”ÁÎ4÷NûÐQvcö¸<Æ7¾ñm 5¾ø¾£e¬e¤`tgŒvï„ï±´.¸Ð™±A=ÌM}3üZ`ðp12ŒÖæ4)kÜЦøÞí%ÐK`öð®UX§>SšQË[µÂ'ÍÓ§üÕiq&þÒ¼è8òV$—Ó”<éÂU³,É_½Óº:?´B/ü¹yª·ݲOE/wd˜ ¤Ò* WÂ0t¸Ý ¿F·<ÂøCC¾ªî4šÒ" ñë×GEbpH^8yÐá\8·¬ƒêç)?àü êy‰õ7+|h‡žË¿a̾\Ó Æ5»Ž8PÆÇ­Ö¯[3m^G/†aR^ù¶¬´/¨†‰Q°m5v 9Žoò ³ûÖõ^‹jŒ>¾ÊÐÕºô­&”-õ¹pD=kÖ•ä¶Q•£#Ê5[˜M/íl©ÍÏùOJíª€>Å/+#]Z”ñ&.« ÞЍû,FUZ»$¢`SVMâL~ºàpéc>Z bGžU®~ûNÝä9ù~ð˜Mý†Ë7'Fí ¡dvåïì¬I!ƒ„pr³­ÖÄÑÄn>0ŠOèƒM”ÔÄËúâÙ©x?ªÈVXÓÖúà(Pnw+ ƒòêÿ³íOò϶?ë« ä±ýöÛ³ž3n™ìš0ÛFL!`@™ú‘ 9#™¾”K8Àˆ˜ûY÷½ï}¯í ÁS_IQV"ŒŒz“`uљģOë%ÐK`~`0ôÌû=ŽŠqÞ\ÁøcÌb€†.McŠ²Ø…0 ŒÙ¾ÍÃàLÊc‡ñ´‹/žò*ô»$ŒÇòQåþ~%oïöè%°ú$àý[¼xñ#+Å3ëC¯³ò¦si¡£ÂâòD£ã&N>:3zÀäHút7]Zhð{b/Œnâãá9øÄIÓQ),\þñ@K É/ž1A£x„¨¢èåëN¡3êsÅÉÓõ§<ÉÇ•.à»S]5üR Õ?TÃÄuëoZîöѪ!hIíÝ›²–zS®Ýõ[·kêÛü£SKyÔ{Ï*—Teù¦&qVéq Â\g‚­üç¨ÂõU箬/xÓNe¡Q°‡•$`‚ÍXÂH1 ?a dŒÊ$}”a"«œ]Z¶D[u\æ¬zÌÊdÇv,{ìµG¹Í­oS-ZÔEë_]tÆ2èz ôè%ÐK —@/›œ&ê|ôQµbgÔ‡ní‰AŸĘÀ5]±¬<:uôñêÖ»“Ÿ>ÍÏ 4â•®xOütryÌ\Ñèà?dš @`0À(•Sˆ0J¡—Ê%o¦Ö¡Ëõ¤ðxÅÀ\€F„“¨8ø]þŒòÔ6\·Y„«¿{lqmùÝyPzè%ÐK`®°£ÅOѾ‹Íö&¶ËÚ1á;œ­uá¡s´3­*­ QteÍßÃh ÌvõÒ½-v‡Ä(1šZý˜Ø®2ŒT¹ðs(©Gå…·ºèŒ¢ÝÇõè%ÐK —@/^7M Líjîêäü&,Üèß*oÆý;F2Á‰KÿèÓp»ôøAtuy“ž´„3[ ÿ¤‹O´FÂl 2"†0‚]Âphð{Â~*Ê/_ Û óƒ¤qåS!®§K3 ¼@Œüá¦çºîÔÎ]+ŽOÜïŠrĹ«¶³z Ü%àøŽ#wßõ¦[{g„sGÈÚ¬eWÖü=Ì_GuT;ª4|.|ÅÙFåíãz ôè%ÐK —@/^«[v‡Vˆ¾Mÿ¦ëÒ‘ãÒ£Ï쑞pW§®ÑÓ:¶xCh£=ž­IúM^_hË;Btæ±¶¨¢\ñÅ€P½-^Á›ä¦Â™NËç‰pBgX`èÊŸ² Û‚"Ÿ'ùª·…»eK°ÎÔE!ƒPý»î:õâŸ=–”_œ½°|î¸Ñç÷¦‘{O/^#%`õžq¢‡5/^Öó—±3Ýv½¸³Â™lGq좛 zÃÄLêÓ{ ôè%ÐK —@/µ èßtc~0¹éêÄttiâ< Ÿþ¸èÍð¢kãÃñG¼0ÜØ¢ËwõÿaÚÂ3ÂlT TÆ Æ/o œBÖ¨—‚ w :òò«TèTïôî‡T,|ÐáÏïö äæŸ2·sÇV7Y¸¬¼êî—”½¶º¶|öøËɯ[®YÁìÝ›‚.¸®,Þri½Aû 7…êôuè%ÐK`–°åÑñ—wºÜÒÙùè ³rÖK —@/^½z \/˜:Dtb.=˜îœ8å‰a@ZWw§;Gç GoîêßâB»z^ôrF‘ЇÂޏ¤‡·ø”½zGÃl  À$ÌÄ'œ‚' s'†ëQ@qpSÀÐIásp„»ùÏ O´KmÛõ3I]ðkÛm¼¬¼ð€ËÚÓMëý7U ~ºó¦Z»¾^½z ¬> ØeÑC/^½z ôè%ÐKà†"© ¾£Ó™é¿Qré¿Ò7xÂI‹ž-_Œôjñú77úwõ6ß#>tùÅÅ Á]<倓ÝÄWïh˜a"Jbéq«·ù‡é*¨‚Çà //¿0º©\4"¤¤…ÒÐäÊn@zÊ~h„¿<üá_wäbÑC/^½z ôè%ÐK —@/^½z ô¸ñI sGý—®Kç.ÍÏ` Й£OæSs…óDzÕ;+>0Jÿ–†FWÿÆW¾èé\8xN„(ü“N%á…h\q©hÒ#ˆÄ£ßv<ù“V½Í/^7>åÃ?4¤4Äq‚xÂiÂe]êU=ôè%ÐK —@/^½z ܬ%°Í6ÛܬëßW¾—ÀQ\pAŠMÏ D'ý›"x\úwŒ‰¯QÓyÄuumú7ÚÑÿ¥'_ܵ‚Î.>üå‹_|—v އ(þã1–3E8•‚Cø<â1wdƒ ¸®ñ@~é1.„šò §œð“–|ðW¾h„R£zè%ÐK —@/^½z ¬ºüÒËõ»îºëõÁ¦çq3’ÀE]Ôjë¨ó%—\RüzÑê:ölE×9øÍ7ß|V¿€t3{_Õ^«,©_šìê¿ÑÑŽÞÅzaz4]Ø“|Üèóüh$pòE¯æ—§EÔ?ÒèßÝrÀÁ;ô¥M„(ü“A…‹‘°¤ÀÂhFð¥yÉ+Ü¥—Âs´3„‡ù'.<Æ+†eýn bé¡—@/^½nªð3añðçQß›Ë7pêìí*71:yü²‹gí7^³?9~ÅW¬r}z½†%`œ`ˆ8ï¼óVúåºaܹ†Ñváü’%KfýóÌsåÑã÷¸¹J ó-¢ûFÿí.âÛ!ž€ý¼z§ðéÙtl.¼®Þ ?º{õNÓà†·0ü.¯®þƒ<€†¼á'n%˜aAà„±4 Ýn>ñÂÁåÂ®Š ‡npSÙš4_¥SîiD'¯<.¿Lyª·‡^½z ôè%pÓ“Ãõ×^Û”g?jµ’2è ‘Äì]Ê•Uä«®ºª)n~f¶3!œ&4*n:±÷ô¸JÀ˜ð§?ýiµí’UM†<¶Új«QÉ}\/^s”€ïMç{Nÿ1ðG§æv¡«S'މB ⣷‹OzâèÔxÂñâŸ<Ìåú{ ‰éFÁ™8‰yb”Ph…¿ÂÂNA…p*!Hc@hÊï\iòàůÌâ M<Ê%=áàרz ôè%ÐK —ÀMK1JØ>½é¦›Þ´*·kð³á†¶ç²Ë.k†ŸqƉµXÌžu/yI€áíÊ+¯\í»%† s}ðæÙ‡{ ÜT%à;ïÝ­£?½tõ_~Oôvé€ÎœŸ¥Ç/ ÐŽþÍÒéßhÊ'Þ#>ú¶p+`uÑ)?þÊ>æj˜è2åO¥1‹q@\ŒâSQñ*|É›|ðà‹ïB ùRiað0qê¶Þ…©F­ ;í´ÓÊ‘}L/^½z ܤ$pÖYgݤê35Iék°U|œÃ'ëÎèc¿cb ¾'½Æ$À ¹ºî”˜TH<:+¼“Pû´^½f!©ÝÑéÔôߢWséÀѹé×p¢_O<ˆþýz;Яáâ‡}<áêÖ¿ÃGZôüÑç¦]£FÃl Ì@’°¸TŠ;Œ/œÊãÇFpC/85i:Ÿ0~pÑHþÐà/üàÏJ¹¨â÷ÐK —@/^½nðˆrae¿‡5+Çc¬þNºobR liwîžqC»ùU;0zè%°6$ ƨ9Ìß|ØÑ°™€‘nË-·\áØØ¨<ãøŒÂ½¾ãò^ªoïé†ÛïU.½Šñ¦>Ëêý=KëÕ^X5Ûì¼~Ù`aTù•úG'^V.¼l ç:$ 8\äjÄ ®”×_Pî³ßæÍ§>×Ú”ÀO¸´\tymç©¶Õ®Ü}vبì³ÓFs*ÞÔû„J£4åvè ëçâ|pèÄôçèÆü@GL‡]ñѵÑ/ ¯;@ˆÇŸÑ×kÔt|hÁ é+Ál¾Œˆ¤ ©|*Ó%¨ p¹è&~š6&Hƒ×͇Ö0ü Ä”aÀ7图4s6+7äs¸’}¸—@/^½z €o×Â…>w=ÌG ÉL?ŸHÆs½ˆÒýVŒ]IÙ¹Å-nÑv\œrÊ)­Ý:(;ì°ÃÈû+æSŸ>O/ÙH€qlÜN}õv·»ÝŒdì":ýôÓg4NŒã3#ƒµˆpéU¥ì¿Û¦-«j"”‘z¼¿,¨.¼ôšò«.*wØ­õZã£ÄŸßmçVKô1iî/¡5â„s¯,ß;æ¼Õbœ¸dɲrêKË5ÕÀ’>0ìÒĺq ×]§ì¹ãFeëÍæÿY[|›p×òŸ?]qmyÔFïÊÿʼn—cÏZRöÙq•è¿thº4=Z8qôhzstq;'¢ërð’ŽDWO˜~}u}Fu4Цžâ¥£ w"ÌÆ0‘‚FéG0qñ‡a âRqþ€8( <qÂÝ2%½FO ;ûìÓ ã*Þ9Û»ʸù£Ñ#“|;$<ÂŒ~“Þn—3Î8£Üò–·ì+H¶¬I 7Æ-ȉϜ˜›pׯßz'ôÛSO=u¢qbŸ5Y¿ÙÒV§QO;‚RåpÑ’åÚêÚ-qm}m³^ÙjÓõÊþ»oQ~~Ü…åžûÌÿWy|—•‹¯XPêÏvžª<Ù¥Qão»°*Eë”;ìµm9üèsWÙ8qÊù×–ë-¬•¨j3KÊvÜ—”»î³ÅÌÈc0Öß1Ź^£[;W5ùüËj»¶v¦4_WvÜ|AÙtãõË¥—_U~æ³6NL}s¢÷Æí6(Ý7º¶ôèÛâøóÄ@ oŒüðäK:?Ý:»*„C7®|ݼá•ôšÜòtãÅ„®`$ÂTd ¦’]#æéüòD Ǹ!>‚¨Þ†/m’/üåãðÃCnð ”UgÙ Š³Á©´zè%ÐK —@/›™¬jSà7Ùd“•jNù´r¸ùæ›ÏkçÂÙgŸÝ&Æó½çȤg&P~+›À„Û÷.»,lŦ”Ï.½ôÒròÉ'Ïj…u¾<ÖD¾%rah v5ŒƒQ²e˜`tð‹Ûo¿}“õùçŸßvdÄ€´óÎ;q‹-j}êÄOlÊð(zãÊÓÇ÷˜¯JñÌc‡þèøRæÈÝþ™1d·Ýv+vm½õÖ#‹3꽉X#½@ží¶Û®üä'?ic–q«ûP–þ³?û³–g>"‡awi=ºA‰oײúp…Ý—_¹j÷g4ãC5@ YIwž®ëTVÒÖ_wA¹ªª„ûï½]5NœWz‡ù®º¦–ùêJlŠ6úíwêY!­/}¾°¶øÎ·¼«3_[ýÓÚ´®¿«Qe]=õϾ;Ø)±aùìOÎ,{ï°Á\ØFÿ¥Ówé¾ea] tug:7ã?yⶄΟèÓ¡!‰ÈZMªÂɧ ݼòtËVƒ£a6† ÄÃŒ0¯’10„Vpá)„x¸)põNW†$=•ö„f—NøË‡~Ù£"jùÿÙ¼L³Á©ôzè%ÐK —@/›™~ÿûß·Éù]ïzוG—ižyæ™åV·ºU[5œ«h.¿üò6!œk¾¹à3zÄðA`H™ÍVíÙð  8qc¿²ÁÁ(9yä‘-ÎŽ†™ŽuÌTWraœ°²ì¨F¸b䂸³Å[¬Ô·ºyz/Õ)†††éŠÏœØnˆ„“‡»ï¾û¶Ý?¹'E? ÆÅÂÅwÇw,ÆUùŒ¹3Á\èÓÂoÔsmÇ0!eBíN½ î‚j;'–†3¦ÎòÌ×Õ¼á —Âƒh V¾ë–b=ë•ïýfpO œùYÝïvÛÍ9ëtòØö ±µÅ×X¿*ÃõªÐКÚqöo`„ZPãξd°+f§ºsÎlûqÇ8HÿÕmtÍøÓ»H·‚«[Ö½Þö74’.R=yÑÜê]Aÿ¡‚®ž›|Âèx@—Ï fèoÿ¡è‚ˆ„p,RHŸÊƯp?^Á—|üè§°òðKðe„HcH“^hWï´%§Ë_üX˜m‡K Oè%ÐK —@/›¤²bxá…® ´ún0JÜ€‚låþâ‹/.l°AS(€¯®ûí·_ 3nP¦;þð‡?´¸ŸÿüçÅNÏ ìh°S„1)ŠÅ1ÇÓ.¸\Õò£iþƒù‘-`„Èî ˜ð°ñbUËÐçï%0I¥Ù€Ý 4W_6^Ä¿ÑF“/ï›-¯nyÂï‡?üáôΈìÈn‰G?úÑÝ,óòoxù7êz5•¢m‚†QŸ£®]´\#‘T—»ëÆ… Ö»+49 NÁùÀ¨h;Th6ÕøA‘=㢺S¯úì¶õBl›ÜçÃOž´Å•W׃ˆæ6ºÃa‘¶ØdýrÝÔÎŽ1?k‹¯¢Î÷›dÑÀŽÈù‚€Á¯€íÒHèC¨ý¦©¶ä›¸R¾ÿýï7ƒŸB“`êW9¢ßFæ‚èÊIÇ/>º³8øz´´¸ÕÛ $.ù24¹](|øŽ< Wï4ÿÄ :–”10Ãæ]BÂ*"ޤ0h&Oò)GXÁq©4Z©Tâà„Võ6€ç| hGØÒ@øBcþ楓ÜG÷è%ÐK —ÀÍT”HFÛÿ»«éO“„î÷Äý¤“Nj»lu†ŸÉ=ñwÞy͘á‚­¶ÚªItj¢Ñüh2v˜¹ûAÞ¬ÚØæLé¥T¯NPþ£>ºï¸ÍmnÓî£`pp|%åÿõ¯]þøÇ?¶•~w"Üþö·/å;á„Ê­o}놿:˵¦h©S·ñ!×ìžX¾&£ÚŽò¶í¶Û6RüÚ4í}Úi§•]wݵ'àüö·¿mGmàÍf…xUÊ×çí%@Þùî¸Õ•J7Í».¬oæé†-Z4Mk½.ýIþðŽ{Ï{Þs,ú8~c3ŒH¸îºkÊ6{?§¦TU¡)âT†úëG_:}”#Ù(–æV\Ç=V¥ ”ýÁã÷§^T‡tõ>±Ëáš%›¬²@¦ÌíHÁ4ùåªò@Ë/øÝ|ÓYæàéæ¿>ù*»Çø;WEòΡšÓ¨Œgçž{nY¼xq9㤺q¡–az6Çñœ(§Üfæj]ïºr§;Ý©} µ}{Ç]˺\wÖq% ÈŠÄ ë¶q£;K~#XÃtw~zuòToósAòçUH^ü‡—°' MX~ÐMÄtþÎÆ01t²·‚$C~åOX!åüPŒ D·2ò/tl+añ íê¾èɃ·áé\3—f,¹ÆÅ7:v­XýƒÒ€ÜŠq~>h‹°ëá†*FŠ‚¶Î é·¥vÒ pC­O_®Rú÷³ïs•@×0—¼»ì²K»Àj»€¢nW{"€o„UwJ®ÕxF J; ÀÛe lbÌÐ`E%+$Úã?¾M /^Üè;F²ÿþû7šv*8°º øÚòzÇ;Þ±‘x8/®|Ê)¼Ç{4ƒ‹±Ò…w¹0SÈÑ„¸ýél«mµÖô•ô‘ŽºgvIhïoÿѲǶ·/ûl¿¹÷½ïÝò~ç;ßés4IôÖ´2Å'ó#iÃÊ\›×>œ®Ë? ÆÅÃíò8üðÃÇî˜ÈŠ'?ùÉ£HÍ*îºk)êK˵ÿ¬*ýÕßF‡ÛÔxiT‰åû&”±ÝC1¦ÎËsŒ÷¹c¢»áÒ+®*‹wÞªì·Óú刓¯(·_¼âÅš¿>ñò²É†ë5Ù§:9%íµÜ8@¹(LµJÚŸòcÞ_/ÞÜ¿ì¹Ýí»&ß\Úq¸³åKÚMkð=]U¾éKq‡Ë5),Ï|ëlNà;o7Üâõ.GuîXVnUÙwÓR ×·.{íµW›CÌÒHeíèÉtdÐÕ“éÆp‰w âAº¸èËÕÛpÄÉ pÙ XÍtô€xaOø£×åž5ºA—nâVrgc˜á8AŒlQ  p@ºü@ zR)øLEá%^þä…+ºÜœƒ“ôðYf":SçÒ‡ÒóÛ?ÖŸÈÙtA€( DKë ÚnèmþAÜiç-)¾ÃúeËae°EÖŠ“IÜmo{ÛÂÊ|C“í_þò—c‹t·»ÝmzR5Œd"þ©O}ªzè¡ÃI-ü‰O|¢MÒûØÇŽL¿¾"%¼ô&áü1FP¬^v'’3•é†ÞžÊïB:·ñSæ ”£|ä#å oxÃ\³^oø«ãý´ýÜ*¦~1 ¶]uÔQí}õq™+|ö³Ÿ­ãÅÒò„'<¡üøÇ?.ŸûÜçÊ›ßüæióCúPë‹ÿò/ÿ2kÒGqDS GeP—íƒW¾ò•åÙÏ~vÙsÏ=WB±ZþéOzì;¼R†›a„±[?`Œ`dð+ {ï½÷´aBœÇÊGÆÆ Æy솰ûðg{¿0C>ÙÖϪ £*ÅÖ.…aEX¾UãпV|²SCœK!­:+&nÌ@Îv®xg‘€úÚ%¢Îs©ßp{Œ›Ã .wiUzNºà¨ºbZÈÜ⎭ æ)ÁiýŸ^kHãú)vÝùp.ç‚È•žpæ²³¥7›ê„?÷¾÷½ïŒY‚?#â(š‚úØýPëV+V®¾üür‡u?[.?~ x g[°ÁŽåºMÑô€Uâ]Õ˜®æqm=6pÍÕ.έ‹.K®¬î`l ÿkjÂFUÛYžÉ[‡ )-ÊÞ”D¸ê5u\:å‚#+¯eå€ÝîÞx&oÊ37ygâ;(… @¾äMÜõéΗ· §í"vÇÍd¸^â}úéOÚæãêÙùF—NƒAtàl»Ñ»Òè剋ƒÎ „¥¡Ç}iqÍ4H ¾F‹ý?¼jRKëò7Vìù£ÑºÄ#ˆ<…—SÜTD\*¯PÂ\|‡+¡bÝôœ"?€Ãp1‰?<Æ ¸ëuQüH0ÈC½¼¶%írA9ÉÙm¡“~î¥ZÛ ³¬l³áNåêk6)Îl-ú)Zt_õªW I¦ÉÏÛßþörÈ!‡”U±ò—5áüãM¥€ÌLÔ” ä–y“ðLÚ(©ãw“í_ýêWc?¿ã>JÆs)ãªââïågTÐŽ&ù€¢F§Pdõo¯K{*ÿ¾ð…¦HP†ç U}vm·Ù¤r¯Ž÷óå/yë›ÿ÷ÿ·’áA퓟üdyË[ÞR8à€IE™f;?öq£ºüž·½ím-î©O}êœdì=´j´‘­ôé³/xÁ ÊØÒFýÑž{ÜãFòCkÒ;<ŠÞÚˆsAá{Þóžö®î¾ûîåàƒncÔç?ÿùÖ_­H?å)O)¶ÿF.Ãå̪õpül ÆŠ+£V òSð»qÚˆáW»K>ml hã#vƒêš€Èê.w¹ËJïAøç•Ã7bXy×Çgó­ ½µí2L¨…ð»ßý®š²{e¾åÓÎÞQ®þ ä[úí?6uVÜ`±¬ì¶ÝÞå„ó~WN¬cņ—o5òÝœo9ú|½&I@ÿôŒñÞg#é0^¾iÜø'ÑÎ?.z¡ùío»}G³;Â:~FÿU†j8ÿwï_ÌznS6Þý©eÃõêMSÚ›<*Î…Ç|¼ÍÿWËŽ‰)ù)À MòÜzlcª R¸Aúøv Þ$·Û¶¼A;í¨÷¯4>í¾í­êøôÛúMS¶­Çö—Iü’6Ì÷ Î/'žð‡6a¼ßÄEÄ·ß¿ùÛßÔyúeíjì\°t“Êwpä1´æâvûÓ°<»t–œ}rùÓÑ?*×\rAYo³­Ë–·¹g¹nó[Ì»Îúiî§°cŽþÔ]„èò¶Ž]ˆÊ˜yc§ëïìúÔAéÓ1Oôl/7=;F ñ𻺳8aº2ˆþÍ•?´AGà )Ïà‘:H‡þâð–7üáÈÇ ³1L($@Haâb&œ‚ 3ƒçÁ#•JXž®0B+ô…áâ-ðB-36¸ÝxùëOs&èkò`àÙlýzÞ§Þz3`fÐÀ8¬+ãë6©–Ó+¦ Ëãqüà?X~ó›ß´Éta+“Œw¸ÃÚE'“K6·TÖm«x£ê3‰’-G_úÒ—Š‹Îžõ¬g•Ã;lú.…~MÒqéÒ&¥O*×êLÓ2±rð“?–rÛmJ[õ´ešâIú(Þ7–öTvƒ—g\»Œªßpܪ䦵ºÃ³{?—•u/½¸¾Ÿ|?Y±)‚~’¬{–Õ…QbUûnúý½îu¯r¿ûݯõ/2¥Ø½ð…/,÷¸Ç=š±r¶²yç;ßÙÚ¾IÙãÿøöS~} Dz€qmš²ŽËCˆ·ñ⿸|ùË_.Î>3Ä2¶Øe·…ž‘IÉ6ïùê*»‰’Hv1xÜLßc‡qFÿÉX£]*¼‹Ò‡o §§œ&(pç³Ë©[޹ú½&NŒÈ‹-j#%aõ±›`ñâÅ Ï.9F» RÏ .¸ Å­Šág®åž/¾{ì–P' õðÝ—{!fK;ïUð6<Ú5GasÌBöÝ¡n‹Î¿ÚG'vßnßrü²cÚñý¶Ÿ»4|{·—À\$`Œ÷-è¦ç„kyºa nÁ玂qñãpCŸ{ÐABkqs¡;–ȵוmnHMVöú´:Ôú^s^¹ö2?å\¿©yª·î¦w©A²«;§ëÂê”apŒƒhðm&_:ÇïN½¢ÆU¶Ui²hÅÒƒvXžmgÈTÉg5¯ŠRÙçûgtšâ»¬,ÚfïrÔ™u7õ‚]kÜ=d™tù^TÜÇþþ˜fô¢{˜·ø®þáøãꜫÎÉ«±Ø˜éÛyu]¸ôÒÍWؽ7—•Ÿqrc”¸ð_)[.Ú«,Üy§rÕŸ.(çýè˦û?¸\·ÅŠ¿¨4[Þt ;AvBûCËÜŽ»%”Q½Ç•Už©4Í¢ ó|r„£3‹GŸ®{r¦ujzsò¥;tiE"Í 7ü«·Ñçxè ?·Ë¯G¦3Aˆ¦0a–pŒ©šòt·[!ù†+/nxÀIÞà« èÆó3R¤ŒÒg„QÀ áøÆ™çnPξhrM06Zß%hµU¯YV6Xè÷×)Ûm¾~L.kƒöu×a¿¾úÕ¯–g>ó™íwâ)÷ÀMÂ^B«*&}ŒzЃÊ7¾ñ¦ zè¡m+I·É¡Iê_üÅ_Lo7·ÍçþçÚeYÎ7[!|ÀPþõ_ÿµ|÷»ßmÖnŒþçn“|à-Þ‹âb­½èE+í~0Àæ¥1¡¶ì’ðq¢Y±4qv&–beðˆì\¬2›¨Ýç>÷)Vp»“Ôà)ÿ¸º5ÆkèþÊž³[ß<ýºrzý%¡c.¼® ÞC9dÚPð­o}«ibtðž¡‹~äÏÐ÷Ö·¾µåa'OÇ=ÈÚ1ªî‘Ž×¿þõmEÚØÐ}3€.…1ï­w˜áL9|÷ÙgŸò·û·+œv4åÝï~wSê}üÿú¯ÿº¥£âNjïð_®±Å'ýÏXG‘fˆxøÃÞÚƒ‚M–_üâÛ¤‘lǽËó)?þŽ4»%Ãw=Øý Þn™Eul×>Þ- ß±»-ÄéSÚ/e¤ì3.»dS:e-mÉHàÒD}JV'xO u;k€»%Ü•|‡¼ù•c€]fî¾ ÔÃeصe5ÇTZÆðŸÔEc”HÜ\Š=l˜×·6ÇwBËxUG’ré•%ª¹ë¯·q¹åÖ‹ËÑçüªl·éNe»M¿„²Rè%°š% ?zFï@¾“v/î8zãâÇñ†&÷ë_ÿzË}ß<¾Éñǵsn¾°ÎRu­;—ØI#Ä5«‰¤-¨¸×Õ<úÚ)mGõ\ê6\ƶûºê?8gJuªÆŽAÝë·¸Æ7ÔOó@ÂU±šÂ¦5Ûpd ¿ª26?Y¢=j|Úe«Eå¸sŽ.ç^¶¨l»ñüõ.ßSO=¥ÍoÌSÌI¦e8õ«Es}ç|O|ƒ|/íœØ­–9Ò¸üùý²ån{–…®_–]½¤¬·pAÙtë-Ê¥Çþ´ltçGË61žq!:ŸÝ†¾íÝù[7³¹"ßummÞ0-“.â”*­«ÿz‘u".]Z§5ÙêX­©5·8“=þ¤qÅË# tqÅÁiÝeÊÞÑóád0éêÿá!/AhÂ_Df‚.±T, î2VÀTPø=päÃS8•‹+=¼º®ÑÓ€_è 1\~iò†Îº&{Œê˪Ãzé>‰Ýo±a9ùܺís×Måãμ¢,Þ~ÃjœXP®®—ç´ 2+^—ŽŽæ¡ëhö¥/}iLˆl)ýÁ~Pþîïþ®) &|“g<ãåe/{YS^œÿûßß” ÛÀMÌïÿû—o~ó›Mt¦™’dBäe°ªh²hë÷W¾ò•"¿ $åGþ¿ÿû¿OqVrSnüï{ßûÚEnŒ”–×¾öµm  ÀQ?ë䨀tʪɶ#%d?X—5Eb\Ýr™ÚJZMÞ€ŒWãÒÒeë”OþaY3N˜œ[A3u·XËwckÏ®Üõ9«œ.°{Ç;ÞÑú¶¤¸Q¤^óš×4c…8F- mÉMÿÑŸìôaTs¼’%ÿsŸûÜÖÎV±/^\>ó™Ï”w½ë]Óù›g ü™ô~f]ý¼òíe“Ý·/Wž»aY¼Óvåä³¾[–mvÿ•Jò´§=­¼÷½ïm»¢˜0T<éIOj÷.£÷×±2ðþèãúº±E'[2AëÀlÆ÷®<øÁn2$yÈš Ÿÿüç·÷›1Äûêýò{ñŒB¶û¹“^Þ¿• ݉ŽŸš2‰3Ž('#жN[ª‡] ¯xÅ+Z[«³vÿÏÿüÏÆ'ïèLíÝa½Ö¼äÄ0d’ÊHÀÄà{ç;ß¹ Œú£½_™XM»5Fmqî*øŽÆ300Rï ÅÁÁ˜gÂ0‰2cÌ` ßÄ,c£1ˆ k˜P.mÖ5‡Þ(7eNcÔ±‹-4ñ ï 3žë‡Ý<É{Cv½ïÙñ1ÓN‰Èe6õñ¾“…¶²MYÍíû›l°Åà›X§@dvõ²«ËÉœP¶\ºã¼'ý³)SÓK +ãýlÀ˜£ŸæÉw"aÊãL0[^ètqù-ÚÍÝ<3᧯SçíÕ Pÿ×¹ú 1@´]ƒ„ð ­ª5Ï£î\o+¬°*¼kæF£®o–]7_Pç(èÕ»þùÕŸ{IK_žÉKA¢%å»6Óø´þÕ{•m6(έÐsüÓåKA÷]ãú>zè'ÆbFoº‘ï’ïaòg¶î8c@7ÿÒK/, w½eY¸×}§£¯ùþû˵—^4o¾Æýð¶5|°,/Þ 8úï¨N`Û”‹.ë­\v¥³âו?]}-D¿´Æ]yÍue½Ê•ƒµ±»"KÁÃÛK7LŸˆ‡c÷Ñ`ïnoÆo»%L²Yï~÷»·Õ]ž1ÀŠ·•XÊ¢Ieîr°­-ŠÊŸÿùŸ·Ýx=ýéO/o|ã›Ác¦‰,ü”;«á,œ&×&Æx&]^ýêW·m°.ƒcÁ¶’™ßÐb€W7l®I°»Ã «WÇ7ì”`”Ы֫Gu>ù‡¥åI{-hÛȬŠ3N7ÖöL±@3X k—1,õ«üÿöoÿÖÎBÛÎ,ìrF¸&Õ”(}@ÿ²‚¢­¢п_ò’—´üü j”+ù5 cßϺ¢±ãÅo.ÛÔ2,»ô«ÕQ5á×ç–¥»<Ý_»å¢œ¸CÂ;vÈ!‡´~mõ—Òθ@ú:e’±Àn }è9ÏyNÛù£Û´ß~ûµþîexȇ(òOò¦´PH©tõ6ˆ0R‘ò¢ºâxñf‚Q` ø ò^Î0Qé V¨J9ëü³êï£ú/+_¾Guo½BgòRáM¡¡°|áPøL`€’r`Ŷ cÝp?+ÆÏʘEgîú…Á°ÓâcûX#eân4PFAh([äâã@QUeE‡" ‚˜8ÏeKr×òwRÝÂkT™VGœI%™Ù‘Âxâø†Œ:Ùå—ý±¼ùó_,»n|yÝsÇrÙ¯Þbÿ­=»íȯ}ÒÇô«³ÂV)SúRÚ/?¦M¬äƒç=ïy­ñ3¬Ù}‘ö?è ƒÚj¼6§ì†Ü5£ßÏ«Êv¼¹ìŽwX¿÷¤nŒÞ² C+á18ÂÉÙ[2BD^ñ{G#Cž#X vZ$­!Œøƒ¦MÀxb‡„Ý>ä)íœt8ÚÕ;(íVt­FdÕîLíÝ2¯Å?ú,á{A”ŸA7«+ŽwóŽ`´QÚëú.òLJì(£D·Œi“nܰ_û2˜­.ÃÄ0><3î’y†ÃIcðð~z?Ï?rp§”wóg?ûY9cÓ#ËñçS6»v»r¿Û=´µcòön/5-|?Fñ‘6WX]ô²; 4úЇŽ-Ê|Ê9LÌÏ…^uå’²ôʺ…¶ª3+옘2Tˆ»nÙ5åœ?žU._pvYXóty›¯»¸˜Az¦q¿Ë߆^qÿªÕWϨGÅ×]¯}×]oA5LS{ªòSy߃uÔ£Ó묻ï.½Ùø÷­?E:¿Bô—Nøp9öG•E›ï[ö]<0ˆwë¼ò,]¾—]¶}›gø>ûv#Í_ÈÎ|lñâÅÍ(o®bîewŪðž©x ݾ\tÌáe³m¶,ë.¨»Ø®¸¬\zq=Ê~»{Í›¯Å zæT›ÞònµN;”«k3/«÷‰x½&jóWÿ:eó ––ßœ»~Ó|¹ñ³¨2©¾Sßz®5ntç„U;º°ÆÏõÎG×gBÊ…§óÉ“ž¸@òÇP!¾Ë?x)‹4ôÂ?¸Á[ÉU ™Q@ø!ŠIKcBÂÒÉ—Ê„&œ˜ßapåó¨XvBToË“ò‡y†7#Œêæû×Vë%XTmüá쪌ï2XAÿɱ'–oüâ e¯=w©Šíºõgu+GœòÀ²Ãí0Í‹²GA·²œ‹/“蜷Ñœk×ySçÓ½°¥€ŽHé1ñf$°ºmdMtœ$ü^r/‡­æVRA&Qv[t––8õ't¸Š€•â'>ñ‰m5œ2ð7ó7Mù . Õ_ÀâwVÑBkRÝÐXÓ@0ØYgX'–6£Ä‰¿~yÙo¯]ê‡aÝrØÞQî¸ÓË-¯»åt‘nlí™¶éº]¿Š SVõ-VÊ*ÈŠ…t}X¿±Ã"ʰˆþì„¡¤3nØÁ3lTkH«ùÏðûyÂY*ÛœùÚ²ãÞÕ@XwJ0J\|ôéåê[þU9ç¢MÊnwl¸(ŽBQ:ì0bôsÜHýdÛ¡U‘ÈÈrŠÙ~ùÊG†VòÅ%>®t°;Y±ýŸaÁ±‘¤ 0Gÿ…¼øÃív׋wÏ= Ži$”üˆû /´¿wÀM{7äµðG›Ñá‡ÞŒvh;mᎆ1ï5y‹®1e-ˆa–Æyã,c³þØÃê—Ù’ñ(¥#ßÔQ\»ÆßMï¶ï.Z”’=·½M¹Íw•µë%°F% Ž›Ꟍgss«qôÆÅÏ…þšÂ]çºuË¥¿úĬÈorÍ–åüŸ|¦¬¿Ñ&eóÅÝ€Q¼Àb—±`.uÝ|ÃR>qøiwýô–M7XPN:ó‚ö”²Ë e:¢oùbÄ «9`ø[ìSöÞúvsªÓlŠaÇ<É.â;m~m1Ç®f?[m^ÅHe~.rMVÀÙj§²î¾÷)Ÿü›²ìò‹Ê‚·, ë¯r¬³õÎóæÛ½Àú¨ºÈùÅ_Õ”R´5• Ì»6Ý ÞÍWï} Ì¢¾Ñ¿uD”îêÌÑ…‘tØåƇ„éÛtr¸üh…Fõ¶|¡MÿLŒ—ókU™Š¥£Â/ù±cþ†Ð˜äéè8F)0?£@˜Ç@ ,/üäávqá$ 74»y¤Kò„“4¸©ChTpRž5Fu‚eu›¿û%0:ñœ%íØÆïN»¬…û‡¯7£Ä]ö>¨l³É.e£M>W¾ú­/”Þö ˜ØîMɱcÂVk—3ø¶[¥ÒÀML´)΃3\P¢2(+pÐð"[餌ñ«â¶K³Jc˱Ë­Þ0vàmbo×…Ï(H9B“2 |\Û®\.‡K6œÔM«êi;4üþtÒS¿Iu£P\àJ~&‰î”p|ÃN F‰n{~ë»_¬Û¯nÜí¹wÛ42N»Ù B‰s¿„cC”T—˜&ï¢E‹šÂóOÿôOåàƒn†÷0¬ ;Þc¥^^}ÌÇì¨X“°ÂûùNj˵¿8¤lq¯{×sW_kF‰ :½œ±Ås«1eߺ…îÔj=#{>w=Pêõ‹&¤“%C?äCZwLÂÒÕ×;Ëà¥8»”aBzdÍ"Û„EäóÓÂhy“6N†h„Nh 32ù°»`¶›GœvÑÞêJ‘UF—-w¦öWžë#ÞŽ+—·ÚÍâøC§.¥e”p¡§q¶»;èú(×Úäa×ìb3î3œ1ŽR¢×f9ol¼½ÿ ¯Æ7“d“ãqßÌÙÔÍq­.ܥܥìý½®W ï=£ Æ÷Qi“âÆÑ?‰Öõ•víâGΉÕFuœµëv˺Âb” Xϵžwß}Üî…ÉEš+ŸÉÔF§>bϧ·„5ÅË"cÎ0Œ:®¸¦ÊÐåͱA}º°ºøÞúTÓ™a¶ü¦ð¨¦ôß&žèÇÑ…7Š_ Ñ¿éö 4¥Ãç¢Í¥ËzpCZ¡‡Ÿ›§zÈ>SQ+:QêWŒ]1¤@aÂw™&½¢µÂtÃÉ'-´‚'ÍZòEâ•SEB‡ Gø\á@‹Ÿ´¢ÄQÂ6VÃÍ6Z·l¿Åúåâ+®)·Øbƒ–å§G]ÑvJ0Jl¶ÁVe“ú“¢×Ô3jÃtœ¿§Ĉ@ñqK Éd y)E.Çtt‚²h¥Å¹}—¸Q¨MÈíX~.0õ“ÿ ƒj»*\HHyd(`‘¤,RXðdà'ü” Ǥיy—åQÆ &vk„–MÖÎC9¤MˆÕ›¢J¹ê–oRÝfÚº>ª|ó³-ÎÎ ]Rfß°S¢ÛžW^»òO¤ÞÛ3ílRä&Lyãߨ.,ehpNÒÑ‚Ïþó _û¹4õÿñ§/3%÷!ȯŸéWŽ)ý[ß]“ÊQ÷ý<÷›Ï){,ºg9éŸ/·¿ßAåô_ŸT6ØãEeÑNû—«®­çSj†áú«[ú±ò»,6w»¨Kú.צÈÀ;É(áýÒo½ÞùÙÈ¿.Ïø»|ñÿÀ>°ãpÙWŒ"Òf‚Ðtñæ?üÃ?´vñ>ºÒ%šIGGßð†7´ßÌ^¼xqk÷ná Ojï™Ê³&ÓÉÆ/éËŽhx‡Ýgâ×GROcêÚ:¾±&ë>‰¶÷Œâl\£L3 뗑ɤ¼}ÚÊð0`ûö™@“ëšËV.AÓK`ÍJÀÜl&ã÷ê*ÁõÅgu•wß~G-ßzq7¥:NªŸ¶ö%0õ]]:ú0×½˜Á¡§1(pá%íâåEŸ^ —+,-|ù»álÐGˆòN„ NBRІ? 3yùÑJ¥RhñÙþÁ¸ ^œ ¦àÉ'/¿tOŒ&Üäéú‡óÉ/]<Àw§ºeùK-Tÿ¸a8ÛÑÇ? —Ö£Øß>aƒ²Ã–õç@ë ÎHá×7¸^rD¹øÊÃÊݸS3Jü¸þÜÌÒ‹·-Ϻß_ “i“ÛAMvìžp^ÕÄш"hU¦«ŒÀ7؉ÏÙÿœWþäÅ ヸLP ’ðÑ„°É«‰;ÜÿÏÞyØYToH%’J'¡†Þ{H ])R”®€ QñDšÒ‘"RB ˆ4EQQz¤÷j*Þà›ßÜûÜÌÞ½m—$ìnžï™3gΙyöÞÍ>çÎ;o5ÁsN’Õ/[æÃ·Fº—™}øâ6b@ˆƒôaG%m¤ÚÚªÍgnêÁ„ŸÉÔ.¥Û7òŸg×ÉÂ>›Ù,<óçjë?O2øü *üìô~Ò‚øÖ™dÉ.ìø9ñ3bïÖÈ·ý¼wøƒÄ÷‚~¾´y"øÁž÷îÜ”üóÙýÁÃ6Ä{Qã'ÿé§ï ,qxÓsƒtH-ŸÝWâS:Þ¼Wè߇_;³ X3D–5ð¾Ö‰ðÙ¿ü³^à©÷? àËgñúö„>pŸ)$›ñ…[H®¸âŠ”Àd.õ„¹2OÍU?Câ‹ù1Åd-Øb§ßØò;BŸáF~ÞõæÕÖû+÷¹þÚk¯M ž¶¾–òùñ~ãçN©÷e¹Û!À¿e\|)+ ÷?ÏíÛgøw†[#0'x3Þ‚ [øæ¤ßJ¾ò[š*õ·Gÿ†"ü»o1ó Áƒ§â®WžcúN¼àã\pk„º%LRò;dÇ®âã±ZâÝÏ8êO‰ù¬4ô\ªÃÉ£äF¬&?…?œiUÊÿâ65,·‘CiqL‚::MJº¨*%,ªÕeËxâ©DP¢WI,öAin,ÑŽ JtKÆ{ço鯖˜à¦JòIüÝ3}fü#/v¦?ôb…\äÙ‘ÿO¼ygÚ)±ÔÂñ–€Í¾ìÚ£’›¤ÙàÇF…?ˆ*ý©?”*õá»Ò¸JºFç!»z>êÍK~(ëùÊmçf`8_aääÃý/ߦ̘–ï¿FØeƒƒ:üϳ×z?“–ü|Ë}϶>Ÿûí°°\ß¡×ÂBßU÷ –Ø&}FÓ'7~V»uY YR¢µói£jŸËj1y¼.Ïîf—»Z:>÷[o~Ø6b#;ÊÏ3Æ·%á6–ré(‰‰òu¹=wpbbîâkïsæsbbîákÏF`n ÀQ¾HŠ_n}#ú/’ Hž|(h :’ ðdʼ…ÚŠjcµ¹ˆÐ7ïiªÉƒ‘sùP[ój!ô!y›:¢>JIÉ•ûÔYZIEGŸ\Ÿ‰LÅzU©–,èM$E+f:!l»êVé*©c¥šljõå>\Ÿ·ðm6·×ðßúC¶j¼ÖϬV_'nÌ5ôùÜ븛ªÄ(|VélË?¯­·Þ:p+ç?蛘* ²Ú6„;,F ½!@²y^%œçUœöö3ð|@k(îx߆ÃuÅ{)IˆËŽ?†áîjcG=çß´Ñ#JTP—olñ¡6öµøìnO¾“þŠ"§;‹J‚³P„Åá”R‹P&ª’^YµÅ§…1V~Ê£P47Úd…ðË¥q±šÚùܤÃY Bâ_œ°üjŒÀ¼G€ó ØÕÅm #`ھŢ}üœ<Ëæð$£y%ó2Ö¼Z“ã/¾¼*~Ù.þ 7¦Î…À‘sNL2€>t\jËþ-x3vâÚØ•ªfü;qyì‘J¾•œ(XTyù¯ÒÔL  Ìä©3V¦­€è˜:Dzêè4–ä'VÓ­Øka²ÅB)ð8‰Rã±SÆjÎ }SÚHò"ú´#`æ8NHÌqHíÐ#`ª @2ÜbŒ@ûC€s¢ðÿ'çÿO†ùrîÎXlÅ·i‹7çü|ÇjŠ)^NRDþ±AtêWlôš{¬V–FLXBC¯¶&®>‚#ØhÁØr1AtØj‚ò£És{‚ 8´óqÒS*&¾$³¸§Þ)íÞ1!¸\#`Œ€0FÀ#`Œ@[B x+‡ø7œþ«³&à¿ô!”²£­>ñlÆ) ¯FÏÿ¦ÿŽÕ$ŒçB/¿ÔÑ)!A]\\óÀF~¥ÕÊÒHbB¤_ €0Я2VS½Ü/eâJ80AÏxÚøÕ‚°Å‡@RŸâ`Çú®bbÃÉè;ëàËX¯*Þ1Qw#`Œ€0FÀ#`ŒÀ€ø/3QR^ ÿ¿¦©ÄÝщ?cÇf,‚?ù—dPìÇNü[y|ˆ‹3.ÆRÊF¾£ª²ÈAåÞ‚§8’S-@ ª®…2¹\Ϙü¢Ÿ”Œ‘(¥„~ÍS>¾|(>c¨+~Ü AˆÚÒˆMmî5FÀ#`Œ€0FÀ#0ç(ÞÊcø/\Î+.M„zÎ,> m85%m]âáèå/VK¶è%•ø7}øÈù7q'žN‰ 1kŠ-#k‘ØÉ©JtZ¨ú„ôøÀží&Ĥ®¾XMuôØåzÍøòA?‚t:€p¸<χóD´,FÀŽÀRK-Õ¢^rÉ%-²·±0FÀ#`æ4‡~¸\Âs%âÄ´Ñ‹“ %ü[I飪4]εáßøÿ§_ãTFUÎŽ^ñ§:úÜwlVÿ곃âX‹Â^‰ôºÐœ[6(±G]ž<`<ýJ.È%vødmÍ{õiv%:â PUÕeà 7¬Þé#`Œ€˜/Xi¥•ÂvÛm×î×Þ¯_¿v¿/À#`ŒÀüˆÀ7Þ˜–]¾Äÿ“Ój/ Z­½ˆ>uȵ¬g” D:â0.¯ÓÆ7uµ±áB´B«à“ÌL%©?;(¤ÒëŒÀ|‹À3Ï<Ó!ÖÞQÖÑ!~x_ùÊW¾÷½ï…1cÆtà•ziFÀ#`Œ@;A "ÿsÏ9w^ßž«ü»Füš°6’˜P¢€D‹G¤S_ØPÒÏÂê’< “1$3hS§Q?>Ÿ¾†ã·611cÆŒf”M˜0!Œ7ŽyYŒ@‡D`ìØ±áÍ7ßlr½ýöÛír­³fÍ /½ôR` ÿ'Ÿ|Rs ¬ûoû[MwSO=5,ºè¢áØc5FÀ#`Œ€˜g9­xµJxs›ãßqNšøPWB„vUa1vJ4(i äCI‚“PÀŽKc©“|ÐD©Kä[m•ÒËzÅk(~qÛ‹ü5\¾÷Þ{aذaMNSÿûßÿ®¸âІ}ØÐ´7x"ïýæ7¿ Ç|ªÿéOjoË'N ‡~x1bDxøá‡Ã1Çþõ¯U]Çûï¿n½õÖªýî0 УGp饗ž¬ñÇ?þ±($ÃÊ¥’®ÜÆm#`Œ€0FÀ4€@Cü7úw.çߌ—ˆg«­Rzù@ß"þ]´—bŠÿ㫪äÉjF,Çš%ÎÑs[…v:È—l±ã¯4ôØ2F¤žOPýÒÓæ’ÏÜâÇî_OöèZC Æ¥øÙ£U¢ªeÂ7c]tQXmµÕÒ·dùhNYçôu²Wlï%‰ñÔSO¥SÕÇ>üðÃDŒ ;$98}ÿý÷ü‘ú«_ý*<ðÀaÙe— §œrJ4hPîÚu#ð…!°Ã;.ˆ×½÷ÞN<ñÄ4vuÔQéé¾Ã{êÔ©auÖIÝD#GŽ ;î¸cÚêΠÇ<œþùáã?{î¹gŧÌ­…òGætÒI'…Î;§:kм.¸à‚0jÔ¨°ÝvÛ…ïÿûIO2ã»ßýnÚ-²óÎ;‡#Ž8"éyjëåi $86Úh£†>ëüøéO^{íµ°âŠ+†ÓN;-ôíÛ7ùôKûE`­µÖJï«ãŽ;.ôïß?=•ƒÕ¬°Â áÎ;ïLóÊwêq«}#`Œ€0FÀ´ìo ø7<Î é§ä‚û"ÓãE?mlŹ)ÑKäCýèÑÁ©ñÇXü£“m¬6áÿJtÀÕ‰§˜è©kn±ZšõŠÂ€zÂd嘒À Â$i\‹Ò±¡¡.½tZýù<èÇ—âPg¬ì©¥ñã– ‰‰oûÛ‰P䣧OŸž¶ˆ_~ùåáœsÎ _|qJ8 öÙg“=´žqÆá‡?üaJn\}õÕÉßFCÔ(7ÝtÓpöÙgç®]7m~ýú…\0<ÿüói~$.6Ø`ƒÀ{ž ‡rHJZ<òÈ#á¾ûî Ü EÒ "ÿûßÿ>ÜrË-é33¯·úê«§Px`¸òÊ+Ó-XƒNóúÉO~;ì°4_>¯$ žº@’â’K. ×]w]øè£ >«|K~ '„Ÿÿüç ÖIT’ø¸ãŽ;€iMüÒîà}½Þzë…Ñ£G—Öò¥/})½gŽ>úè”Ü"Æûæ¶Ûn œO‘ ÉjÞ[ºxïIHI¯R}.€0FÀùâS9įÛÿ®ÄÿkþðØYPO”(m JX B› àScÐ!J$(É€MXI²A‡|Åjbs¡—=Œ“úÅ/´ZñºýöÛ§{ÏómÞݺu ßùÎw¡á̉ɓ'§ ÷ì®XrÉ%C—.]Âb‹-V^yåuæÌ™‰Ð°-ž„D?@ÿóŸÿ´bVbæ=lÞ¯¼¿9ü÷úc=VYe•Òãvyrd‰%–H6$2¸Þ}÷ÝÀ7Çú<ÌíÙ“D¹êª«Òg—[8.»ì²´ûcÕUW  ›m¶Yš6sfWƒæÇ7Üìxà| æþ׿þ5Ùñy×™õ>ëU’7ÝtSx衇Bñ”äÇ/í ¾¥È¾©H?KÞS[mµUI¿üò˧$I‹õ×_?-p‘EI»föÙgŸÒ‚ñCÒšK²æšk¦]JôñžÛ|óÍÕ•J¶Ù7Œ€0FÀÌwo ÿÍùwΙÁþ‹<[¥¸sT%¾Œ^>àîÔáÕ«©N‰h<ýÔ5–XÒá“vοé£Í$ï+h²×F Àd5 ¹P0¤Ä†à\´™$cê\ŒC'{êùb+;ùa[ »%ä;VK€áG>ˆÏØd÷ynåˆ>’°œo^!f„…oˆ¿úÕ¯†¥—^:éôBBáÌœˆ¨Î™|ûܧOŸti»¸Æ»4mÞÿìXf™eÂ6ÛlS"dzÏ3oêì–˜6mZZïs„óÖXcTŸ/“&M |Ö¾þõ¯§‹G™nâ=ÈÏ÷G.•|©ÿôÓO\#`Œ€0FÀTA@ü›nñd82’ód¸1¶ü!Â_¦ør¬¦6:ú°£ŽPBlgÄK\;V“ž¶üQæüŤŽä~ š ¯L žàH‹Ð„™BÉ„™¸&'ÐéŠÕäƒ"±Ç/ãé“?Å¥”ÏÜ6ªëÇWBãÖ ‰î=>|xrñÆo¤o]ٲ˷Å-¾E…äìºë®i+0ÄÇbÚ‹/¾xºƒ]JÒ1ï^x!í" “Ë-v@àùæx—]vI¤|^Èn§R‚„ó&¸‚oµÙ6Ϲ$~ö³Ÿn?©&œ'ÀçŸ$$·auïÞ½šy=¸p®ÌÞ{ï’œh™?`WÎ!Cš%%æÕ{•FÀ#`ŒÀœF û¢Cü›rNóo8¹ø~«ùwô!¾/DíB«Êkáëý*EuîH@ä;Ð!”ØR²D ¢N&…6%q5QÚˆêG—Ç– _kÖŠ»+ð×%û!¢o‘äcÙ¢ÎS9¶ÝÒÇ·±lY×·©8‡¨ð´Æò®Þkd¬mŒÀ¼B ïç1IHp %·1Høæ˜÷4ä„Ès&N’ ¡‡/zýÆ7¾¡!s½ÜrË-ÓY|ÎHp+[çI*°ŠÇ=’(!±Èž/¿ür“91g.ÎÑXwÝuS"‘Ï+gôîÝ»‰mµÉG /¼pº­‹ÄŽÅ#`Œ€0FÀ´ìËv84|έ‹¶x7<›]zìs6\?×xø·88þúðÉüIO‰­âÇjâù´éS|l'¿±Ú\4¡æ=³5LÁ‘ì5ƒ‚ѧ…ÅjšœìO“TRD‹£Ô8úˆG[I ùÍíéCO"[ü«M}ÉxÙºƒûÃ9Y¿\ž~úéÒ=òå}µÚœ-ѳgÏZ&Uûx¢[»³7YU[w¹g>´äö ˆù¯ýëD´=ôÐ4%î‡çpȳÎ:+íNàl‡\øìñ^Ÿ›»j­ƒÏ(g¹ð v.ºM£ÑÝܞ˜–ÞŽÑÚqù\]Ÿ3ð^%qV.Ür‘?-…'.ñ%„'Ó仃ÊǶ—6»~,FÀ#`Œ@ûC€¿³ù[„/ýâíÅ;ż/=yÞ ¯VÒ€„mx0\š:%ü™1”èJÆcËxúˆo3ÁŽºì ÷FG<›¼Ž mÅ¥]Q”¨ØYTæ“ ‚)  ‰+˜’ èµlÙÒÖ‚(•`Èí±U l4Vö#×S'I¡9ÆêÜ“Ö&%˜Q9›{³´g#0gàÌ’{ì‚°a¹å–K» *½§Ùu07“šGµ’Ïh¥Ï)ój4)ï®]ùµÒrií¸–Gò#`Œ€0FÀŽŠ_FÉù/ x1%\Z»"Ð!ðh.qeñoúÄ­oFr[tØ S]±‰'ŸiR±óÿ<~ì*ù ^SpRO4!ì4 T„’ j,€:}ŒSB‹SI?¶ù‚c³$Ä“ìÊçOcå§3D;&¢ÞbŒ@+àÖŒr:thà²#`Œ€0FÀ#0w`ÇD%àÁñ_t\¹ÅÉ©‹o«[ÆJÄ¡UJÿFð£1*ÑçñiË7~ͩЪñª@5LÒ¢è'(B§±š˜Ì$ÔG~ÚŒçR_´L?­…-vý¹ }㓘°#`Œ€0FÀ#`Œ€hwL4ÄãúÄ·!Â\jÏþÅWüØU]´¸ê¯]²“s•è•@È}RgBy²"GãðOb;.îsÁ7¶è[ß»%"z#P–œ/Qax›Qu”u´@=#`Œ€0FÀ6…@ñËv¸u#ü»ÖðoÖÌØÏÅ¿ãøjüÿU…Àõ„Ei§B~ë e`”x`\.jkwmËXÕñ©8Z‰ $¿Ñ»¥ñ üjŒ€0FÀ#`Œ€0F }!Ð(ÿ…W#-åßù¸9Á¿_\¿0«*¯JTé.©I0Q’ ÔI 98Úñ€žº’ ²×ÊÜ– «­|b§1ô#DrB}Øj òÁ Ì/•±>‹¶®¢~ÿ¡?H»(ÚÀÔ=#`Œ€0FÀ#`Œ€˜Ç¿lÿ†SçBàÈ9'V—Ú²‡K'ÞŒ¸6vðql¸dƒž6¶ÊˆËçü¿Ü7íº"ò_Ë 2 .31êŒÕ„5ɨ*eZÐ!ùDÐi,%‹’ŸX-í~ÐÂdK\Dñ©w—Æc§8ŒÕœñí6#ܾÁŽˆC×>º¡9½;frº¥£–ñ|ÆßÄ„[XVZi¥&:5Î9çœpüñÇ«Y*oºé¦°ñƇ¥—^º¤kMå©§ž 'N ›o¾yøðÃøqãJnxÊ%—\;ì0îµ)õ¹bŒ€0FÀ#`Œ€0M(r&ˆ“’pr¸1<þ›ód%è˹;cÅß)i‹7ÓFƒN¾Ña‡Þ®§tÐÆQ|é_±å?U¥‘ÄDî€ L€½Úš¸úŽ`ÃÅâ°åb‚è°¸ò£És{‚ 8´óqÒS*&¾$³ºvífÌ¿Ï'íÞ½{7sRÜVŠ÷ý4ë/Wp¦·o `TZ/iQŲi{°Ár=Óyå~òö?þñðŸÿü'¼þúëáÕW_ ;ì°CèÙ³g QIN>ù䊉‰+®¸"8ø<‰‰iÓ¦…ý÷ß?Üyç)ô~ðƒ0iÒ¤0hРÔÞe—]ÒüHX0¿O<±Ò­3FÀ#`Œ€0FÀˆ@‘sŠÙá¿"¹ð_úJÙÑVŸx6㔄€†¢ç‚S¢S¬–8Æéb¢å Ľl(%²Å?É“òøŒËã Æ7‰?'¾3fLxüñÇ;r!Yñðçd@®¯Uç KÎ’`ñ{m60•{n:0ì±ÉÀ0,^èwßx`Øm£aפ݌©%ûî»oÚp衇†õÖ[/Õ!ý÷Þ{oÚ5Ñ¿ÿpðÁÇ[BfÿøŽ=öذ袋†/}éKõ• ÉŽuÖY',³Ì2áì³ÏNÝS§N {íµWXl±Åºë®^xá…òaáŽ;îk¯½v)¹ñþûï‡SO=5%B.ºè¢””`ñ/¼ðÂt[K3'V#`Œ€0FÀ#`Œ@Ž@Cü7€W×g“¿wþ<ü›y4;âCb)t5¥‘8Ä A(Y$ VPÕ±¥N?“ž1ùEŸÆæ¬[q(%ôkžòläCq“ÇÇ9 ºZ'{Èø‹/¾˜P'k¥öRK-Õ°c1±@\ÉÆ]±¼ù¡B‰Ú·>2:•´×Y¶G«Ï˜øûßÿHDà ’+m´QJôèÑ#¼õÖ[iÇÂI'.¿ürÂ%™>}zøæ7¿®¹æš°òÊ+‡-·Ü2l»í¶aäÈ‘éÖŒ÷Þ{/\{íµáþû﫬²Š†¥ò‰'ž«¯¾zI‡í°aÃÂäÉ“Sb„„Ç +¬’"$JFUÚMQäŠ0FÀ#`Œ€0FÀ$²Ûßá¿ââ]ño¾¨GÀ™Å§±¡%m]âáèáÐèÙ¢—Tâßô)>ýŒ'.ãÄÓ)±‘ïX­,špåÞ‚Ç „C- wžÓ„X\¹ží&øËýÄf²Ó"4Ÿ'þ{*ÇСC ’ï¼óNàv°; Ò-,ª’ÌäVޏ2ÅN JvJ°K‚kø;%vÙ°pa˘Ö v,\zé¥iWu„ÃSN8á„°ÐB ¥ =ôP÷ì„Àö‘G W_}uºEäÁ Ë.»lZ7~I.°C£\ÆŽ›p’ž$gW¼ñÆÉžÛH$àYi·†ú]#`Œ€0FÀ#`Œ@B~,g¦.­ä‚ì(«ñoŽÊºÏË¿å+ºJóR²DsB_QILàœ #,–1J" #ˆ.Ú×±Gt«E>úuÑÆ¥æ¥Ì:D¶¹ŦDòøòSèùœ¯$'HBpŽCk’irŧr¤vJÜòȨ´KâÖG ;%n{ltø3×ã£ÓîvY´FØéð—¿ü%íNXpÁ›¸èÖ­ðÔUJvHäÂÚ¾}û¦ë´ÓN ›nºiJ èÞ½{Øc=Â/~ñ‹|XªsÖ†na·ÊgœV]uÕÔ·óÎ;7¹ý;α#`Œ€0FÀ#`Œ@eŠOš'n„ÿ¶„Ùś[ÿ•/ „¯3?êò©2ªªK#F8GB YIt\ù­Ô„&)±«”| N?É„òl zÆå¾Ñé«)vÍøsâV!nvH <¸Å;% "01ÉÀS9HL c‡D,užÄ®q—íol0 ì̵þ€´ØzgLÈw^N™2%%.¾øâ°Ï>û¤C-ó~nÅ@®¿þút«GÞÇ.’Ûn»mzr·}DàÌ n9õÔSSÂáÑG͇¥ú€Òn `OBãé§ŸN}wß}w“Û<Ø•Á® ‹0FÀ#`Œ€0FÀTF ø¸P:#[œãüŽ´–ÃÙsþOŽyJð›·¥oRŠô7Q–5Ê8VBƒdõ<:üæãb3µe«ÉÊ–Å0Yùe,uúµéX´æM]'ˆj,cØ q±:ç„äÄàÁƒ[ípVÌJ(YÂN nÝøSÜ)”`Ò·Çj¯²x÷øTà­/Ù6L8ðÀÓ-Úù{¸çž{Â)§œ’nç žK¯^½Âyç—ΖèÔ©S:gâC £GGuT8ýôÓ‰+¯¼2–êœañ»ßý.Õ{î¹ç¦ Öý׿þ5õq^E¥y5sh…0FÀ#`Œ€0F`>F@ü1BÿEr‚(NM™‹øs®§o†Ëv¹-ýÒAO‰‰=¢ºÆ¢S|A‡È'¶ø©)"øµŒpˆ#.œ2Q.&…Nu&›ÍÔ¦dœ#°%@ŸbàSþc5Õéc ±¨3gl=uÍ‹~µeUmGJO刳c§I Γ”Ø)òî'q—˪/»ï¾{à’\vÙe)1ÀmÙ))©€Mù#PÙÑ áðËýöÛ/=êSghôéÓ'í˜0aB ^I¶Ùf›pä‘G¦q$8öÜsϰ뮻¦C3óCBo½õÖô„J>¬3FÀ#`Œ€0FÀÅ[9”T@ oFrþK  ?–À™õhQø·êôãG>hÃ¥ó6ýðo|2Ž~.ôâÛâßQ•ƪ¤!>s¯)-MLäA©kÑSr’èµ0ô,@ã4Vã°Ã}.úhœ@¦ÍE»<>:ÖÖ…]Y†)ª¾XIOåˆSØx…ÞáÝ1“ÃúCz†·GMJsä ËÕ—\0¼þþ„Ôæ–æÞÚ3&X)Éj¢„Cµ~°«dS-)’ œIÁÙJ’pŽDž”ÀŽÃCÙ•a1FÀ#`Œ€0FÀê°=Šø/œþ«ƒx5%Xœ~øµìÐ#”âÑIQ|KcK<úáãjÇj‰+}âÿÄ×xÅcL]i$1C„`ˆQEYnO[‹'u|ÈVþd»J}Ô!¶øÐxù ”âa(mJ–èÛ=œ1âµ”l`÷·v¤2ÖyúIˆ‚ž²”X~ñêÉ…6µ¸âd8Ó¢ž\qÅõLÜoŒ€0FÀ#`Œ€˜ï(óŠ3‹ÿÂyËù7xÉN‰ø³¸1u„Ä‚ÆÊ½¸6¾ÑÓÆ{‰âSʇø:6ÒË6ŠO3i41cD-¦ -¼ J% èa,öL„RõX-%èÃ.ÇäËã@ ”ˆ•Lˆ«ùqîD›Ÿ»Ù~aÕcwò…Åv`#`Œ€0FÀ#`Œ€èÀáÐpix4méàÂðfqqvNˆÃ³±Ó8l¸quµá×<±ңñ¡„ƒx¼|É8=¶5õDÎEú±—Ž@Ô0%Š:-œ~ :{„ 2† í|NêêØŠ)¿*ñÁÕŸbµµÄ ±#`Œ€0FÀ#`Œ€h"§ïU)î ¸¯¸6ýâÛè¨ëR‚€±JfPÇŽqê§·Ö® Úò«’qùXÅRìNcr=ºŠ‚£FD±Õ"™¨&ƒž€ù‚´x¥­L öy‚q•DzùÀ†:ÒPü⶗¿#`Œ€0FÀ#`Œ€h4Äã²ÄËù7ã%âÙj«”^>зˆí凘$*êJž¨fÌ‚p¬ Q* BE™ù’-vÚÆh‚Ôó ª_zÚ\ò™ûQüØ]º­¿l/a uÆ¥ø|9iòä8ÄbŒ€0FÀ#`Œ€0F í Ý  p^H?%Üá¶ 81"[@IDATmÝÊ«%þNo.çäpjü1ÿØÉ6V“^ü_‰¸:ñ=uÍ-V›pÚÍ„õ„ÉÊ1%„IÒ&¸¥ bC?B]zé´úóyÐ/Å¡ÎXÙRKãÇ!#`Œ€0FÀ#`Œ€0í âS9įÛÿ®Äÿk‚ž'ª*Q ~Ú$ TJ¯dmú%+”H˜ôs© ¸~•ˆ -;ùAÇœ[Ÿq#`Œ€0FÀ#`Œ€0í Y³]†Ã%s‚³ûanño¸>¾Åé5n•¨ØYTâL“UAö F? Jl¨«¨I1NIì•hP,Æb‹ü°­„Ýò«©ŸRóc þ(“]£·rDûv)÷>7=Œž0³ø˜ÑøxÑøÈÑÊýXÒÅéÛañv¹^OÚ#`Œ€0FÀ#0Ÿ" þÍòÅ“áÈHΓáרŠ‹¯£_ŽÕd#Î-þ-=¹žæ!®-}ÎÙ©çüŤŽä~ š ¯$&äXÖDpG€` L¡=B>¸Æ—@ÅžG*zùE—'0Ðc¯û`°U¿â|ʶ—Ž|&I‰½6Y$€ù4¢ñÿQÆ•I¯v錯ÅW‹0FÀ#`Œ€0FÀ´u²3&à¿yÂ@˜"®M>x¹tJ`À™Úô‰Ïc.lèS‰Qüjü_±°-®ª4’˜Èç!&Oú°¥Ôbµ¨J Ðâ2QƒDCÞO_›66$.¢ZüØU:³KöCDßæäÍ7ß ½{÷ýû÷oÕÜfÍú4%!†¿üÛ˜˜ø4%aRë³hëŠ;)¨ï?ôiwE«‚y0FÀ#`Œ€0FÀÌSŠgL †së¢-Þ­¤ET%;ìs’ ؈k<ü[ÿ}$>´a@zJl?VÏ×ü(‰ÊX­,$&˜‚C&£’‰ÐÖDʃaÇE M^mÆ0Á¿|É¿IŸ’è;ùÄ»&°ÍõÄšÙÖwKL:5œ:thXl±Åâ”[&3gvJºöÑ |wÌät«GCÆE£¿ýíoa©¥– Ë/¿|øÍo~Ž?þøÐ¥K#o–D±­˜;L™2%<òÈ#aàÀés¦_쯽újü,ðë#¤÷w¯^½Rýã?|ðAªëeÅW Gÿ¨Q£:ä7ÞÓ§sòl!Ù8`À€Ô7[Â’K.™‘Ò}øá‡á£>R3•ã.¯оßzë­Ð³gÏäKF>úhòѹsç&þ˜Ã»ï¾† "ÓTÖ[Œ¯ºêª0f̘p 'HÕ¤l«¿êÍ›EÜyç¡Oü™XŒ€0FÀ#Ð(Oó_qè³…EÁi‹3£ÿæUôø`¬Æ‰?£—Nü±¥ì(±Ã"Õå=uÊ<v¥v)§šŒ‚©­æ aL¶ˆló1®|ñôc«Øh¬ìF®§N’BsŒÕ¶-$$_|1•-MNp¦·o `T‹@[ X6m/6X®g<‡x—?ßv[ØlóÍÃ2Ë,&Ošf̘Q51±×ž{†+®¼2ˆä5Å–F`Î"À/ð³Ï>;Üö§?…M6Ý4|4~|x{äÈpe|.±Äaûí·;ì°CèÞ½{xþ…Âj«®Î=ï¼pÓM7…KûÛ°Ùf›•&ôËÓOO ?<é¤ðÇ?þ1LŒŸäúë®K‰Šx ,²è¢ÉÏk®¶Øb‹°í6Û„=öØ#ÙñòíƒkÆ>É}÷ÝŒãHn¼þúëa»í¶ =b"âôù¯³öÚaÓ8÷;"±–às—]w ýúö O?ýtXƒ Ò:Ipî»Ï>áñ'ži*ë­GÆûî»o8æè£‰Œ…^XêRÙVÔ›÷ ñg{öYg…Ÿÿü祵¸bŒ€0FÀö„@ñËöœÿ·áÅ”piíŠ@‡$JKqeÚê£DÏCúe‹tª+¶x>zêñ¥W Æ"òQhÕx%x=‘Sì°ç" ¢ÅDU ̤Ðq±MšR ŒÕR–E‹$Žbá£Ò"ˆ}ÃñÛú­q-¥Ý$'Ê¿©¥¿–pÐ%gIÖ^› Låž› {l20 ‹úÝ7vÛh`Øu£é ÆÔ“_ýêWaùå– ›n²Ià[[„dÈ#B=‘Úfë­ÃÁƒÃž‘xMš81ì½×^é›ÉÕW[-üïÿ ## „ü-±øâaÇwLä ?$/Ž:òȰÜ!a÷Ýv ï¼óêIÛ,’°ÁË.Ž;î¸xËIá}}ñE…UWY%l´á†áÞ{ïM¶~1õx5îˆøýe—…¿þõ¯á¬HL/ûýïÇ‹;$§žvZ8ïüóÃí·ßþð‡?„Ñ£G§®ÍcR$….v- “'ON»/vï[va ÿ÷ã'»-¶Ü2}spL@ ‹Ç÷¾|PæI ú÷ŒŸôtPX{uR¤òðC…vÞ9¼÷Þ{Uv~œ{î¹iÞÆÏÆM7Þ¨®ªeµõäºuë~{é¥M’íá÷@¥yçëú}ü¹ôíoç*×€0FÀ#Ю`§l”vÁ¿ãöX"wß}wøïÿ.¹ä’pO¼äœsÎ ‡rH˜9SoƒÒ´\1Íx&&ÇÖ‰d¿W¶…ÿ»ì¸$þIqçÃuq×ç¼pûòÄã‡_þò—éºð‚ dî¸ãŽ°Ý—¾”j씨'$:䇲ü¶Zã™Óî»ï¶Ž;$îŒq%ÜFòÿâ·ÿ'žxbà3ó‹SOUWÕ²Úzªˆå÷ÀSñwȪq7ŒÅ#`Œ€0í⎉†øo\£ø6™Kíy¿³xÄF¿Ðªòʶ‹záÇ©’Øã=:$¶«vìjÒG,lrp°AGãä¿è°%—úbµ´8Íýøh¿x?ýmV GÏFb¬·n·Dâ!¥{Ä$%Ø)!!)ÁN É›Läà 5+–|£¼û°aaÙ¸s‹D¹°›‚om{Æ]ûp@“ûÚ• }\øÝï~þvÏ={ç%ì®Xh¡…Â׿öµdÃnî¿ÿò—¿œLþsÿý©d+>Û܇žÚ²W^y%¬wPXŒ@-¦ÄÏU·x›F-Y+&ÐøÑ5î¸öÚkK¦¼‡õ>VIçqwÅw㮋WZ)|ó›ß gœyfº¤4°B%_¡»¢Šß ÜrrøG¤dÆ19ÂgR­}ûõ k®µV¸äâ‹SC}•Êjë©d+]Gù=@"´_ÄŠÛÐ,FÀ#`Œ€hÿž„L‰äSŠÔIÏÒD¸ÄÓ)sþ­qpmêÚ €œ›ñØ#è$Š‹½bäñe§¹Ð‡?Å—­ìš•L¨žà„‰0Aìå” œ/P ÇN“ŽÕÒ8-F>±Ñ„©s Jüp±0Î0FóW|lòø²m³åÄx ÄSO=•æGR‚CóZ"ùމ›ã. vHÜòçMÄ ÿÇë¶ÇF'PxYcÉëÏèšnÉî†r9ì;ßIäìÖ[n ›l¼q¸1Þ—¿eÜÊžËIñ^üÿ>ùdØ5îšX9ž¥Á½ü’ãí %?<έèZ!ÎôiÓÒ7Ù‹Æ{÷‘ŸrJèï­·z°“眘ØÊ…Ã!ùÌ­¼òÊIýÒË/§Ä«¯ž’p²]w½õÂ~ô#5Sùþûï§<çÇ[/”l`'ÃnqWC5aF¹Ÿj¶¹þö?ÿ95¿oñ CþüóÏÊ4hP:ÄóØï}¯ô$Μà|‹Áƒç.šÔ+­§‰A…FGù=Ð%n}ü´x[X…eZeŒ€0FÀö‚€ø7Ü ¥vdy%ÎL>;DɵáÛè°¥Ž½|Äj'ßAêˆtØ+~%>žŒã‹âi¼ôK&҈Ȏ Lœ+BR€àèԯɨM‰/%b5ÑX-qú=ŸUþ_Ý_uèek’,‡ó"8Ë’İx–¥Î“Øuéý „¹Ö@­wÆÄZñ[X¶¬s?=dèßñì‡r¹<ÞêÁYçÇorÙ¡ä :Æ OÆCøŽ‹Oð8ò¨£Â€¸M>ßR_î­Ö/G’øÜsÏ¥o°Ž÷„sžÄ¦ñB倻}âÁ~ã⷟İz°«†§npF »"&L˜¾w9èlçÛôCâ-B§Åó&j »vØÁðHÜQôp¼Ý‰[“®¿þúZCZ݇ßëâEnm"xC¼Uª\ø¼<“-=4·ÜO¥vGù=Ð?&‡t Z¥uZgŒ€0FÀ¶Ž@ñ.8p£ü[]_ÿVl•âóU¡V¡ªAìP‚€ûò6ÁÐSP>¥Ç^—&Fâ!·ËûÑs‘}A-ã(ñŽ6%vŠCÙ,¾¾ÙŒ}mRx*Çúë¯ßâZ OØÐí*Ú)¡ó$´SâöÇG®;žly’G-áÖã.ˆ•ãvu¾å1¡áÉm<`ƒ8wÎà^x„Ãü6Oðxæ™gÒH0pæGñ¤‰|¨M™’q›ü7âaCNÛ×y*ÂÖ[o8T'&¬±b­Üb1õ`‡·g\À\!¾‡y?óyÛ{ï½› =æØcÃ_âmG/½ôRê»òŠ+ xȤ.žT1<& 83E²C<Е cÇŽMªJïküÉå]wÝ¥áMÊ|,çR<á‰!âáv&ˆe÷Ÿ—#c²d5ÖH}åñx´(Ri=©£ÆKGù=Àï(ž^b1FÀ#`Œ@{E È÷â¿qØé‚#sÍ3þÅfyüج.ÖÈ¿’ÔÉÒ(A ± J?¢…£×ö èÑ1^“¤duú¹´-D ÆäõòqŒ§=BÜ%ÆŒS:5ŽoÛ+=Æ’?Z·Üj«4¨½½œ6âpÌ×–¾2!í” )±KÜ)!!!±SÜ)!yåÝOÂq—=†Ÿ¸¾TUË)S¦¤Û/:egCäÆ|@¸o»|'D~[ÆôéÓS2!¿#÷Q^Ç'qõõ·Ôƹ4 À.ž>ñ Õò÷•Ñ©@{ÿ=@âôÿâm9ÜRÃ.ráðÓüö0’Yûí·_2c×V¥3vÊ}´õ6»‚,FÀ#`Œ@ûCàÆøô5þáK¬øïùÎqïÄ >ηF¨ëÎJx±nÕàŽÙÁ±ÅÇcµÄ»5žqÔ5žn-Ÿ•ÆbƒžKu89càïøCÄó ­ ¯ ª',@dŸ€”œÐ$°CÔfbè´8e"¿”\š<±”`J§[ÒtØãÁ†¤câ“U:—;ÛNÒqU¯Ð;¼;frXHÏðö¨I)9~X=ž)ñúûR›[> þõžÊ!êÝ2Á¤<)ÁØü¬å×Ág%òØR?-‰iÛŽ» ,­C ½ÿàÉ,ìJ³#`Œ€0F ½"Ð¥pþ_ÎÉ©Ã)Å¿YXü[I%Ä—U*yA[|ÛÜuD\[õ«OmqvÅW?zÅÄWEi$1Á@œá‡ybA‹ˆêÔG[±`Ô§Éæmêˆú(Ç‚(¹rŸbºZœ’Ñ,Í[|r}–o‘Ží'‹-Ò5œ1âµ”làìníHe¬óô ’=e!)1dÏhèpo/ȪðHÕJgåTà#`Œ€0FÀ´!fÎ$/PâÛpx¸®x/%ÜYü˜’  W;çÔQ]âØè%*¨Ë7qÄ㿎måªùÍõòÍØš"§µŒp¬l ‹Ã)%z)«¥Å'äŠmlÆq ù) ¿Œ×Üh³…q\«©ÏM:lŠÏ|-´:àëa;,ÞWå%#`Œ€0FÀ#`Œ¿lÿ†SçBàÈ9'†£Ó‡ŽKmÙÿ¥oÆN\;ø86\²AO[åÄåsþ_î›v]iĈ bGPM€É é(&%mÆê’ž¤u-Š1[FIÙ3†Ø²ÕxìèCšÄï艉’ýjŒ€0FÀ#`Œ€0Ž'ˆÒ.øwœgÎý™·8=õªÂ zù' òO@ 0žvžLÈ}26?pCvè5AêHžtàö ‰†<>>èguÍH“øùy…n¿#`Œ€0FÀ#`Œ€hoåhˆÿÆÍ þÍFFã‹¿çyqþª€ëv‰ª±ƒ$¤_;€ €’”ºr¿Œg‚J8(y ä„ J.`‹b2†˜ô)uÆÐO\ÙÇj²á ôgͪ‹cBïcǤÒ/FÀ#Ðñ¸k·Ž·&¯È#`Œ€˜¯ÿeÑðßœ#‹_ JÜø3vŒYÆŸü‹‡Ë¶ý؉+/óx:c)e#ßQUYÊ•¬pŠ#9Õ˜zª®…2¹\Ϙü¢Oc#QJ ýš§|àùP|ÆPWüø BYŒ€0FÀ#`Œ€0FÀ´?Š·r0qø/\Î Ñÿ&a€3‹OcC;JÚºÄÃÑË_¬–lÑK*ñoú_ü›¸ŒO§Ä†˜5E®e„c¡;σ¡Ç/‹+׳­¹ŸØLvŒ¡Oc°!!ñyâwø§rD|,FÀ#`Œ€0FÀ#бh„c#;Êjü›¾¹Á¿ÅåùICÉÍ }EÑN„ŠE%ΕLÈ3)ÒDC®3 °GÈà Óâ±g<ý”ˆüQb‡ ãhkžØ«Oã°C䓸Ø3ol;´œºóBaÙ~§ñ1¡<*´P~Z(?+–eú‘ã? = Ø:4<^œ0FÀ#`Œ€0F ]#P| CÎs2ÿ…'‹ÿÒ†GÃ…¹4Ž;ñfJ¡Oãò~Ùc‡Ð§+)â }ðï|Ø[þé«)"üµŒ´H&‹cJM–:¢ ÓÆ§€Àž>.‰ÆÒÎýiò”}JfÐ./bªM,%B>íè·r”Øbh¯À+éŠ?LëFÇê£#Ê;_õ£K*¿#`Œ€0FÀ#`Œ@D ø¸Pf‰ÿÍ¿Ä×Îô‹ŸÇj¢‡è`ƒplJìŠì0é°wÕÔÏt¶´¹ìóX9ÿWB"Æ|(¾tÍÊFLB“Öä†0Ö$Ñá7›©-[JìeËÂhË/c©k±±ZÏ¢5ïR"ê4–1~©ùÄjÇvHxø÷»wG€âŸÆ]”ì–ˆª“¨ø4ê¶]j·´›b>§ãþà½2#`Œ€0FÀ#`æ ²/ÛῈÔÅ©)sÉ9µôØÀ›•ˆ@/Þ.þM)œš˜Ø#ªWН1ËÙü]‰ é+–"ø;‹J0!.œ2Q.&…Nu&‹-mM”6B[‹ô‘@ O1ð)ÿ±šêô1†XÔ™36€Š^ñ(éW[öQÕq…Û7HLì¸Ü×ZäØO¦ÅÄ„~Œ _^}Á0rܬðʨ™áÄ ¿ºûã0S?áÆ\ØÊ|aôèº@Øt…îáÃOf…çß›t…©¬8°KèÒ™_!¼=nf˜4­Ð±HÏNañ…õëª`ûÒ³ÇÑ?h¡Î²Ü€.¡{—‚Ÿ‚u¦~FMø4,ûrygü¬Ô'Ýb1΢Ñ_.|¦_þ_…! î×%LžþYô5ûß™—ë&Nû4ÞºBî¯[œÃR‹v¯.Œ•Ïzë‘Ý![ôút §ßõ‰TMÊöô{`áÂu‡ö ‡üa\xÿãÙØ5YFÀ#`Œ€h'oåPRY뾜ÿRçâÓœ­ñ‡má×ÿV=ª“ù sjõó->G?ñÑi¬âÑF4êįûYÓ¿šÖ\ä”ÀLBA©kÑC/Ñqi²Ø²Ùh¬Æa‡=ú\ôи<>:Úåñѱ¶.l{É2LQÕ6dí¥»…§FNo6HòÑd-³™IEÚ1!þÏ ô=,¨vQ±â î%bÖÄQÆnëö ÿ~yZxsìÌЫû¡k$s3ÅîÊÆÝvÔ€°ïecJ$¯¬ÛM#0ψýð£¯,v_¯g¸ÿ•i)°l$ú¼?ßýhVøÏIƒÂÝÏN Óf|V[²kxöÝáðkÆ…½7èŽÚ¶OøO#9þÆñ)A@û×{.Ú¬WXàзS÷þ›ôJ‰Š-VìÆÇÏ-~ølß÷Ò´ðà…áM–›pé}›|î·º``Ürý»„b¢äžç§¦8Äcþ/ºxšÇ—~=ªäã¡ 7?19ŒøiXg™ná‘7¦…c®Ÿ|Œ8¼Xígܪ5[ê­G–W?4)\ú­¾ßA•~ÿ´§ßOù4ü6b½Ë:=Â%ÿš¨%º4FÀ#`Œ@»D S§Äyá‚SÕ`€éA)áÀâÜðklÐ#²Cˆ—Où"qàãŒM“ˆ%ýè‡>ñâk¼âEU}i$1C„`ˆQEYnO[‹'u|ÈVþd»J}ÔY4BñÖôðÝHÙ‘I;{Eâ·¾]ÂO ÇŸ¾>v»>áûÛ÷ ŸLý,œpÓøpÏsS+ÆŸXüÆ»´xWækVÔ5¾uŸ°ÊOÞ‹; Ÿ’Ýc’#ž,$ N¼y|z/wU|rÁRág·|÷ÅDܑ׎k†_Ïn „M–ïnz|r,»‡‡^›NùsaÌ…û.švd\\$ÂCëÞ‹ ’ÕäºG&®a1y²çú=›Ønýßúß)a­¥»æ75&Pv~çÆçrÍ¥º†{”Õb ¯¶ž|Ìô™Ÿ5û½ÓžÜþô”|y®#`Œ€0F Ý"PÜ1Áƒ¢~”yÒ€µ•óstJÀŸE©#$ÄÝ彸6þÐÓÆ{‰âSʇø:6ÒË6ŠO3Ѥšud BÅâ«9ÔÄ)@‰-†qy6¾5Iµ±áBB¡Uð™"=eÅøÙA!¹íZÿS$$$®<¨_8pÓ^i.|KyåA}Sý¼¿Ohx~…3&>Kß®’”ÌbIB‚‹o]zùãðpñâ¶ÆÔ×w¶ê69ýÃpèÕãÂfq¼D[ÜŽß(ßóÜ”°ä ï†gâ7Äk.Õ-ìrÑèôMëÊ'¿Ÿ¾æ›`Ü’?x7}C­µöëÕ)̈?-ì&ÄdÃÞô lC~Xÿð“H ×8åýD¿¾f°Þ²ÝÂ111±Å™†£¯®þv¿Ð%¾+*Å×]X+’v_JJ #!¡¤m?»€ØõÑ×-î~¶ÓÂé")&Ùež)1vc|_3¦ž Œ·|ÈeùmµÆï7Üw[ÜûÂÔðµ{”L¹äÔ] çî½húÌœ4â£R_µJµõT³GïßµÐqŸ0FÀ#`¾p*òß8+È<ú áß5âÇ®êB¡ž°0.ed°—L’Ås!è‚6u :{05í|Nêꤧ­˜ò«?ÌQý)V[LLÄ9¦o&‰÷A“œ )q@$!ÜO¾ÍÙ£šlõƶ–ÌŠZ‚0‹Þ,î” )A)!)±ÉJ³Û£Æ³cBɪi¹ñrÝ!âÖ7džDÄšZ„ðjÊå¿ñà>÷ÓC†¶‰g?” ·zð´€ïüq\ú&wÝxB¢1Èq;ü¯îþ$œoM!¹o©OÙ ®¼X—ts¾æ~a‡ÕLÿqªþÕñÖ—?ÆÃùúõîHjT‹Ÿ¹tu>Gà¹øŽ.‘ÕsF ï©…â%v9p‹B.câ!’”xÊγwåýª³k‡ kÆ[Öúùûaߎ ßjàvoI‰ßÝ.“âpk‰¸ý6j~ëç·¬¾d·¹òä ÿhÉO̶FÀ#`Œ€˜{dwhCkøw>Áø×q‰{‹Û£ûÜü;úÀò ÌQŒB«Âk#;&p‚c-ž$B@.Ú0Qìh«Ž=m„:±dƒNã¨+qA1ØåÉ|Ò†ýê‡ãÐËw¬–29y|ômRHNèð¼ÖL°pÆDa$·m œ'@ÆéÑW‹íX_ºo×øT ©..ùà«ÓÂÈ3—ŒN~o›Ð¯³ßQ<¦ð–#úH‡æ‘\A8Èïñ“ ›Ÿñaz ¶œ¿Å·Ññ¶„n¹ÐønLrüõû™|ìÍiéI ø÷¯—¦†7~µDèI&É n©¿Ü¯Ûó/Üb1,&n8¬_Ú9Á­#âîkn~ÛÃ9qÂkq×Ä*ñ–"ä°-{‡²¤ÃRqg‰‰#²ƒ,ïzfJøý}CÿÞÒç ¿åC¨ãoâ…K«ö‰O©t(c>v`ŸÎa“x@'‰ gµp¦óäv¦Q¿^*%úx,)gÒ<ýÎô°r<ì³<žžæQi=•ž¼¡x”þ=£áº0FÀ#`¾8ŠOå¿…ÿŠ3)ÕÕŽ:zqgtŒ¯W‰ʈ½ÆC×ä“r6,Ø*¾ì±aŒÚ±ZŠ/]% ˆ]I˜D=QÒ@Ĺt”Z ý\JvämQò€‰#Š­…à‹ =:ü*cƒ…¯ågÛɧbbÇùZbìØ±wh×ĸqãB¯^Í¿u|úé§ÃWoY-kræÎÃNë/¾?%í’ )±qv¦I vJHÞ;9\~Ïá¢Ggè§¾ò²G¼ÏrWíH ½"Ù+ß ÁãDuû‡ZòC©w¾b㓸ìÆÈ¥’Ÿjñóq®`Ï'1¡Uþ¾2:õè(¿îÚí¹°ÖZk5[ð¤I“Bß¾…ƒ‡é¼öÚkÃ~ûí—ìî½÷Þ°ÝvÛ5ÓÞýúõkoSö|€0FÀˆÀ7Þ˜þaÇDü÷|ç¨z/^Ó‹àÀ±áÌÐ-8:u%"ô˜PÚâì,ÙSÒf¬tŒÁ=þ¸ÄËCö¹OêˆÆåcÐÉ'õª"B_Õ và€Kr[&«~daÔÕfòŒE¨kQè‹=uô¹/ÙÉ ‹!>¢ù1FÀ¦9()‘¬:à‹ž°±òâ †±ŸL + êx$hú6¢Â™ŒJF ôž»Á.†Z‚¯ò¤öJJPg7EKŸ•Èc%?Õâ·$žmç8›ÁÒ:ü{ u¸y”0FÀ#`æâ߸O†##‰ÿª‰_c ?Ϧør¬–ô‰KO®€d„N|^ñÑ)>þòØŠÕIr¿Ò5+ILÈ1“Pp±MJ|(3C?"@?ãúðÁ…0†rå~Ù¡X诱y=þIXÈ^ýŠó)Û^%âÑO»“‘ã? 7?ø~:“u’|˜E+œ%.•ñöYÚNN‹0FÀ#`Œ€0FÀ´u²3&Ä¿•0€ØÁi#ð` }ðré”ÀÀ¡MŸø<öøç†>•èůÆÿ ÛòøèªJ#‰‰Üy>iò [J-V ‰ª mÀ!.c%1H4äýôå±ic£s&ªÅÇN·€tÉ~ˆè;œ\ôp — ípËô‚Œ€0FÀ#`Œ€0ó%Å3&X;„þ ÔE[¼ž­$zìI"ˆ;£SR!VKü[ãáßâàøGèç§ô”Ø*~¬&žO›>Ådžøò«ÍƒzÂD¸4Rׄ4lrÁN ` ,MŒ“/ùÕBbW²ÇF`ÖŠ¯8ŒKñ;òn i1FÀ#`Œ€0FÀŽ‹@ñxqæœ7ã¿…œãÏmþƒžøw1¾æ….OYSòIW3Ä ‹Gƒ6㔈 ®D%‰ÊÜ7ã’-uù¤”^–-¥|Çj©Ž}¥øŒ¯Ÿ±#`Œ€0FÀ#`Œ€0í â—í-á¿ðhqjø4õ¹Á¿åÿuñ†Ä×%°SA‹R„’äDz†V%cKÉù‰]Iˆ‡ ñé+Ÿ¿âËOgnåhä̉çõî,FÀ#Ðø÷}qU^“0FÀ#0? йs¢ÌÜ n­e‹ÿJ!\Yœœºø¶ú(±g¬{ùÊõðoDü›¾|¬Æ CäzÅOŠj/ T­½œ” !ŒÓXML±Wuúi3^ ¡/Úˆ@¦Žgl;„þÜ?ãwô3&ÃbŒ€0FÀ#`Œ€0⎉†øoDà åßeñùh>Ô«JùŽƒJ†~ˆ¿’Øà=:¤‚Ú±«I±°É“Ø £qò_tJ8K}±ZZœæŽ~|4‰ßÈn [ ütÄ«á•÷'§]&ñ©ü,>݃GsRÆÿS9`¡ná´}W ƒén茀0FÀ#`Œ€0F`.!Pü²ž ÿU)~¬6ÑÅ…ÅÓ)sþÍxÆÁµ©kƒvpnÆc “(.öŠ‘Ç—æBŸòø“­ìš•L¨žà„‰à{9ÕbéãB¯d‚Úštì*ÓbäFK`høfa|‘ˆ DOöF>ŸïÔи†âÏš¥pÑ‹¥.é<‰Ìª ‰˜ŒHI‰˜˜ D¶Z®{øúª½ÂWV_$¼?nJ6bÎV'Mœ.¿üò9ëÔÞæ^~ùå0uêÔðÖ[oÍ‘5_qÅ÷d5™™0!œ{î¹­ìQó5œ^¼ÉƇ_|1tàs‹óÎ;/|ôñÇU}=þøãá¨# ×üñá .¨jç#`Œ€0FÀ#Ð(]º¤jñ_qoÊ–òoàçåßµâÓWW2Š^dǤaú\¢°,BAGRIÕ’qJbhLT%Q Jl”±ˆúð‰bÒÇU)>v\ŸùVŽˆB DgL”éO¾d·»'R’"€I=HÁ£:êÈE^V_mµ°ê*«„+¯¼2Y¿÷Þ{ák_ýjXfé¥Ã°Ýw ߯¿¶ÛvÛ°äK„³Î:«ä™Ý/G~x2xpøò—¿ÞyçRŸ+F NñýÙ¯_¿Ð«W¯Ð³gÏRw¥÷âÌ™3Ãáßýnzom½ÕVáÉ'ŸLöÓ¦M ßúÖ·ÂRK.öÝwß0cúô’Ÿ‹/º(½Ÿ7ÚpÃpï½÷&=qR/ü­¥ÿ¥ï‹äßį ƒ-#‚(I@ þX¢g<}ÒÅjJP"Ø+Ñ€ ˆ2N§Ä&OX ÃB›C7(ñ¥Xj׌_|ækfiÏ"ºÕv@tŠÉ žÈ¡Eº­#þªÙ+ÞO<ø¦ùö;î7ÜxcøÉÉ'‡±cdž£:*l¶ùæáù^Ë,»løÑ˜†|ï{ß Ûm·]xñ¥—šl›¿äâ‹Ã¸qãÂÓÿû_ØqÇÃñǧ.@E~{é¥aɘT89¾çjïÅ câìÃ? O=ýt8üˆ#ÂûïŸì/ˆ»&Æ];Ï=ÿ|zO¾ýöÛIÿßÿþ7\rÉ%áž¿ý-œsÎ9áÐC üƒ±ÒJ+…ãŽ?>l¿ýöa÷ÝvK¶~1FÀ#`Œ€0Ÿâ—í ñßç åßeñ•G¨»|&]OHhq$„äzIG‰TŽ6cuIÏ.êÏêŠE „ìClÙj}ÂQG]òËYãâ½û¿ûÝïÂG±¼óÎ;K}®Jl»í¶i·ÄÆ›l’º«¾ã{ïC /¼pØk¯½Ò¹$*{ôÑpèa‡%ýÁœJ±Câ7ÞÇ?òH5jTxå•WÂB -Ö_ý°Ì2Ë„V\±Ò”¬3FÀ#`Œ€0-B xÁ ]tÑtòóŸ«Ë¥hJïEòÞËßkÝâû‘Û8Êõ²™ûú÷ïŸÞ‡ŒÿÙ)§„¾}ûRµ#`Œ€0FÀ9Š@ñVñoØüW$þK"þ-N¬>ñlÆÁ¯¸5z.H%:õÇj“$ƒâcƒ_m ..®y`£ ¿ÒÇjeÑ„+÷´L^v¹CtAСNãt1Ñòb^6”ÙâŸäIy|Æåñ ã›Ä÷S9€¤q)<•Cï«êãøáq+G:c¢Î½ë­·^øóí·§Û2xZÁ6[oΓXk­µÂˆ#R›nº)¬³îºsV_}õpóÍ7'ý7ÜPšçP,¿Ñ>øàƒÃV[n ‡#Ð*½yO®ß{#Šï¹Gâˆ)S¦¤]¼GoŽïMäŸÿüg3fLªoºÙfa±ÅKçNì³Ï>é£=z¤>¿#`Œ€0FÀ¹€@Cü7Æ…WCèʹûçáß,§ÑøØ./b‰®¦4²c‡8Râ’E²`U[êô3 é“_ôi,c$ŠC)¡_ó”%äCq“Çw ¹sY ´"BvÉ¿vªeVê;kØmuϘØb‹-Ò!—ÜÆÁ7ÐßùÎwÒ7ÍçŸ~ØsÏ=ÃOò“0`À€0â–[’ß³Î>;ì·Ó£ßh£J±Ž‹gJ 6,¬°üòiWÅ™gžYêsÅ4‚@µ÷â÷ã{kÏ=öË ’vë\oB8/bçv ËÆ[3–[n¹°øâ‹'ýÖ[o¶ˆÉ±ÕV]5½÷‰cr‡Å#`Œ€0FÀÌi´Ë<ú…ÿŠ‹CtÅ¿ù¢=gŸÆ†6v”´u‰‡£‡C£Gd‹^R‰Ó§øô3ž¸Œ£TùŽÕÊ"Â_¹· Å±‰FNU¢ÓäÕ/ ¤Çöl7!&uõÅjª£Ç.×k~Ä—ú| CÐ ô›Àå¶''" X ²Ô’ƒ •*¯ï¼ûa²e—E=ùåé§n½àç¡íðC‡ ÿ‹YNž<¹ÉSøöúåx¿þ¤I“Òä»W<‹âî¿ü%éùvšÝ#ÐR*½y’ÆwÝÕì½H²á_÷Ý—vûðþË…'ÆœvÚié÷K÷îÝó.×€0FÀ#`ŒÀœF ']âÄÄ@/bD‚Bv”ðo%¤ªÒt9׆ã[üŸ~SUM8;zÅgœêèsß±Y]Dü«[ÌŠc- {% ÐëBOpîQ¡Ä tLRã(éWr!×c‡OÝ¢¡yb¯>áDG\*P¢ÊÒ)ÇPD”ÄC=Ñ‹zvôsß~%Éå˜÷C+I5}%[ëŒ@%Zü^,KJÈg5?êwiŒ€0FÀ#`>/Å:äüW×âÝú²ž6<.Ì¥q”âóÔñ¡1´5N¼šRöJ„ Ó«IèƒçóÀ†ØòO_Má¯eÄdpÈdUˆ6¢ ÓÆ§€Àž>.‰ÆÒÎýiò”}JfÐ./bªM,%Bây‰rG·¥:câ”n‰» Ö” ðe^Ýœ1Q/¦û€0FÀ#`Œ€0F 2ÅÇ…Ò CãçVÔIPŠŸÇjé |ˆ1›;eqv•±«ä‚-~¹üç±rþ¯„D2Œ/ø`œâIߤl$19Á!Ž †0Ö$Ñá7›©-[JìeËÂhË/c©k±±ZÏ¢5ïR"ê4–1|5¯ùĪ¥QV^¢WØí¥íéÅÀ§üÇjªÓÇbQgÎØzêšýjË>ª,"ðëƒWmÔÔvFÀ#`Œ€0FÀ#0—(ÞÊ¡¤ÑàÍHΩs‰·ÓÀ™õhQø·êôáG>hÃ¥ó6ýðo|2Ž~.ôâÛâßQ•ƪ¤!>s¯)8©'L Á±‚* 6ÁÐ!ØQ§dZm IÉ[l¸”hˆÕ’`OöŠ×pülÛKÉ¡+FÀ#`Œ€0FÀ#`ÚÅCÿáÂâ߇‹{WãßâçðoÅi˜Ç1âîâûâÿ5¡ndÇ9 jÓ§Ei¹=ãÑ#y¢B¶ò'ìÔG0âa‹JldG);ÅÃ’^={6dg##`Œ€0FÀ#`Œ€0ó ⎠ñ_ŠÿÂyËùºú)áÎJ*ˆÃ¥íz Ž?‰¸6¾ÑÓ&öŧÌãË·ôò…âËG“R›(Ë „Z“2“ÔÔÄ)@‰-†‰äuÚøÖ$ÕÆ† …VÁgˆô”ã{ÇD‘ëFÀ#`Œ€0FÀ#ШÈãºrÎ×Å·ç*ÿ®¿&ä$ê‰$X<"‹¢NIA‰t,œ6u :{‡Žv>'õGuÒÓVLùU‰æ¨þˉ‰ˆH ä×>^zwb:ôR‡[æ‡^êÌ w¿þöša±Elw›#`Œ€0FÀ#`Œ@K(rZñ^•âÞ¸‚ûŠkÓ/¾Žº.ø4ÂXx·ø6vŒS?u¸µvUЖ_•âñ«XêCÒ˜\®¢äI€ŠE%Aqˆh‘y€ày?uƵ•Ü@/ b5¥¯\4NñGÁ^1hc+{åQ£ ·½Äª¥HJ ?vƒô“K?¼øRþ¨Ð.w?ûQøþïÿ~sˆ“àj#`Œ€0FÀ#`ŒÀç@@ü ß…û"pqÚÐ7$çÎpnÝqÀxQ‰}.âÓòAuD|x9ÿW;ñuùgL>·Ø¬,$&p® â…€GÏ"•`/ÙbÇ$Ðc« ÇjªÓ–¨|£“ÏÜâ3–øz²GJDÄ6ñ—âgV‰*K=ÒãAãà­1Ã̸ebæ¬Ïb9+̈[%fΊí¨Ûnh¯0«S—pÀWV ÇþîépÞakyçD=`ÝoŒ€0FÀ#`Œ€hÙ]ÚÁçU¢AüÏÓㆠc+Î-ŽUI°aœúQ¢ƒS£g,þÑÉ6V›ð%*àêÄSLôÔñÃ…äq š²WÔœÈ1%„IÒ&¸‚i‚ØÐP—^:-€þ|ôãKq¨3Vö€ÔÒøqˆ¥>‹hs!]:u ]:®®]©GÒgÁ®af§®áÀÿÏÞyZQ\}|h6,ˆ#¨ï!"ŠPcA%6Œb‹E1±‹FMbÁn,(6,±ÄO"T0ÆDcCƆEEDš(ßüæÞÿeÞ²÷Þ}¼÷8G÷ÍÌ™3çÌüwÙ»çìÌìîÜ ƒ_<ûc†€!`†€!`†€!P»ä¿Ê!ÿº>øßiþIPâ€@1A TO™@RñL L”wq I=‡Ê€ ¡—6q9éñÙĨ®}Úe@ ì'É5% áƒ!(á¤Ðvm—v{tjîvíÜÂMœ<=jQÿ³7ß|³›6mZýˆÀ½ûî»næÌ™î“O>©—h”»§OŸî>ýôS÷í·ßº¯¾úª^ŽÑ:m†€!`†€!PŸî2~±üdÔ†ÿÍJƒ…åãë£[¾¿Ï§, ”©³ B^$cðÐÅ!•cÕ)ÉSF>æK'<åIM³%|6ê¥o>û¶”CPeKÃl‰ø ûfM|p‚™š51úÃYnäû3ݓ㦇¥ša‘ÍÂ<©sÏ=×5j#Cîp7ÜpCÉš‹\qÅnÊ”)5W`-ëì/³ñÆ»·ß~Ûxà%ûôÛßþÖýøã%e’•uáZ|ñÅÝÑGíî¸ãwÕUW%»heCÀ0 CÀ0 †…@Yÿ×?ZŒØÏÆW¦ûßè“ÎZñ¿ó6Ð%"Ÿð0U5/¥såEÈÑa FŠI h0Ô‚¨Ô³B[RxAyÚ¡‹:é“]RéŒe=;´‘<í糟Ÿö‚¬Q´ÇDR´I£ÜRfO„ …ß“ü\þãS%ˆ7Öp€[c5ܦ›nêÞyçwÙe—¹K/½Ôí¶Ûn!ÐðÓO?¹C9ĵlÙÒuìØ±°Àa<ôÐCÿ¡‡r‡~¸;í´Ó¯„IwõÕW»¶mÛºŠŠ wË-·Ñ9sæ¸#<ÒµjÕÊuíÚÕ½üòË?kÖ,·ÿþûûì³›=›¥Y94hPбÑF¹Ç{LlKëüÛ_uÕU]óæÍÃA—?úè#×­[·p ì¹çžafÌ^{íåFŒ®—×_=Ì@øõ¯íZ´há¶Ûn;7iÒ¤0Úºx-jlJëÁi±.†€!`†€!`Th ùߤ©þ¯çË߯7†T.ç#ϱ@þwd/ißW'œúr¤ ' ”:"E–”¤€y"3”I±«ŽR†€êáŶ%Ãf—¥ì#§0›F'¾Qæzċ̀hìƒM9ƒ‡“ÕˆSÍÿœñôŸÿü'8w'NtC† qÏ=÷œ;ýôÓÝèÑ£]Ÿ>}!A ¦¥óö÷‚ .p>ú¨›ü|ÊÔÉ>2´“^ŸŸ(Gt„CA!yuHA&&ä‚°ÔYtÐNº¤WñUAúªIŽúؾìÀöís¡@‘r3&ŠËœ˜·çDMøÀ„N_z»uÖY'pîÚµkœ½¤$Sî:è 0»€N¡¨oß¾!h‘5Èôüóχ̘èÒ¥Kp(ysÿøCp>>øà°÷Š^xÁ{ì±Ì1Ç„ÛÌ Xq×]w…¼9Çy5ª?ì¼óÎn¹å–s[o½uè4×ßwÞ鮼òJÇuµÕV[£ëëw¿ûãš½þúëÃuøæ›odêÚµ¸ÒJ+¹-·Ü2ô·}ûö…~ZÆ0 CÀ0 C á ÷·ät•ôý¨caûß1ÈÅü|yêJR–W¿(È£\e€ tÒFAx H–²%¥ :Ôaê‘• dÔVòôŠùä™-¡>RoT BŒôJM„åˆ Ï,‹RDн$þñ„7Ñ8ÿgŸ}v•&ÌRèß¿¿;ꨣ\ee¥[qÅ õK-Å$™ìIJf͸ r$‡“%1½¼eNò%CÝj«­‚"hºè¢‹Ü*«¬’×jI}Dà¸ãŽsÌ2¸ï¾ûÂþÇ3jⱜrÊ)a™³&Ö_}·ôÒKªíZ,@±Ädžxâ‰%f¬6PCÀ0 CÀ¨›ä_¶Çþ/~1)¾´&Àƒð£åSãÝ‘W)~3mäùŲð§¼lcOþ·¼ÀØÿ— ÚBÒ‘+•ø‹’r+S'dPåØ0Ôydh§ „§”zÙŠìÙžô 3Ùêh+=~kÿV¿Ì}/o”G ÷U¾â°0_è˜ëá.‡/öŸþyX†£7tèРxÙe— K+(°ü¢wïÞΠ›øUVV™äŸ¸M²Nå-¶ØÂõë×/?:°Å¿þõ/·ù曇¥»ì²KXF2cÆŒð¦y“M6 }‚ÿßÿþ×}ýõ×Aû <øàƒî°Ã c$˜‚}£ú‹ÀM7Ýä6ÜpCGÊ þÕW_ ]WÌ@àZüÓŸþäzõêåžyæ·üò˧XmR+óL»K¡S÷ëvÜqǺßIë¡!`†€!`4xš4 .³ ±³&ÿ‚øÜòÉÉËßV)²´ɇV*>þ7„µQ ?¶OYºÑ©O¹R‰¿IÇ>MTJ1J‡èœ:ˆ<ÆÄC–#îíÒäÑ%û€LˆTòèFeô Ç«pÙóÙ@j¼^—ÿ¢·å•G Ì€ð¨~ºWya/qù¾Ãì‰RÂŽ?þxwÉ%—8‚¬û‡Øh’Í,!¦Ï³öذaá-u`ú?ÉóÇÔ|l”É‹4Ú~ûí2mŸÀoÉÙ¿‚¥$ðÙ„“}"ØË‚mfG¬»îºnÍ5× |œtÑ>ÑÃ&œ8®Fõ6mÚ„K{˜ýÀ>ˈ\±ÿ 3z¸¾˜Ã’‘]‹BÂRCÀ0 CÀ0 E‰@~Æ>04×øÆø¿øÇò—ñ¯ÉS¬äTF–v”ÉCÒC^m©‡ä£Kú¨“>ìÓ†ƒ<|òPš¼êr‰¿+GANQºXÊê°¯$w¹XyêÅCR Úg K5>`ƒ:õ‘¶”I×úöÛo‡kŸ Ÿ/ìÎïë 4vìX·ë®»ÊKrfdzFº{ÏìæŒèíÚ´nUŠ ŸOr—ùÀÄ6'>á^¹±gIY*Ùˆr…V¨"‡ÃÃdž.̼à“ÅÞP«!çÙóÏ?ß?^ìBÊ?Ø0“ ºµ4CÓ§Oû¨¬tÚ´i©¶Ñƒ½xJ¿ÚXZÿ(vÅK€²žs»ëÏùg3]öœI÷—¢!C†8ö 12 CÀ0 C ® ÀŒ ¿Yû^¾?8?øÌøÁ DÄeä§³i%~1êÔ?›¼øÈË禂ÇA{ùé n Bô)¥}±^äŠN9Ò@1¢àmÔI p §`‚Ê B¤Ž3øÈ “<º”§L"¥ÓLŸ mÔÙC†6*#gT —?Aχr¤åä¨O%àå§%‘ A„rA ä´+-K/¦N « ÉN±ýØ 1ŠÙ.¦'M‡ñê>«ÒÎuÀÊzÎíZ¬ûçÛzh†€!`†@A@þ7¾1›Ê±Ï,_˜!Çþwìão+Àûå’'•nüoòxè’ý4<û?Ò§ö⧦R”Z1Õa0¤Î‘W„Ey¤@ƒÚƲtXed¥9µ¡"â8ªCVc@’ŒÀð,£,h‰½ð‚\ ÒFüGç}õ\þ#:±¨{÷î‹Áª™4æGÀ®Åù11Ž!`†€!`†@í ÷·ðÎb'ÿ—2uòÉC¤øØ ò¿ñí!é¤yRt“jÆ…ô!+}ò¿¥ò¤:|6ü|•çKåÔÏW1èŠ0Bš,ÇFUïÅ ©yé"O{ê8¤ =>ýÒCŠ m'¥, üäºpUZšŽÀúmVp½/‚ |mƒ+˜I‚…Ôóòõ+lß…t4k†€!`†€!`†À‚!LÈ–/-˜”C~1‡˜‡qH‘S=~4Ÿ¶èǯF–”2u²K>.ûb ˜~DÛ’”%0AG5u¥2‚QuVƒŠ®éÔ!‡<$•Rx¤ð½ñÙ” ×ÃW[äeðUö[5ÊŠÀàã6Í*jr†€!`†€!`†€!`‹¤ÿ;ûrzIñ›ñŸñ™ñ 9üfºˆˆ'ydãöÈ!Cªûì³…nÇ †€!`†@qø¢ §Rþ¯|oÒêúßøÛ ê—²O]Y #,+5/°@§åé“× P¡2†ÉÇ ò øl¨SYÁu˜Ðü ë\Ê—!l@ÌÈP[xäÑÉ17ëRŽñ¦ï›‘!`†@Gàƒ>în¼ñÆU6ëýôÓOÃWž***Ù¦L™â~õ«_{|MdaÞßzë-׺uk×¢E‹`gqí!´È@5C†€!`†@=@`ÎÞËüm|x|]ù½¤øÎòI9ð£ñ¹UFŽ|ìS†Å/ÿ¥ÙØoG^1„bzc¾tË&vRIJS+óL3PˆÁ¡”>†@ðÙÂàrù2²í40ÚJO0êh¯¾Qf €p¨Ï†rÜ7ñéS¡¹¢ý5 CÀ0ª‡À¬Y³3ÚµkW½†õPš™ ù‡ŸÐû¶mÛÖÃQX— CÀ0ê;KB`<ë tÎe^Vþ7¾1y9ö‰ñÑ©ƒÇ¡²äñ¿Å“ߌœ|mäðÇ‘á |ÊÈ* _>öÿ“º)—%9ÿ¥é àÀ0#O[uXô¬B¤wžÚ’2(éñÙÂì L²Ø…dŸüÒþP{äd‡¶ê³ß Q8z®QYÎö{ÿ‹éaÓKmnoz©M0W[q)wÑAí]«œ#CÀ0.-[¶t_}õßw«¬²Jê@Çï&Ožì~úé'·ÒJ+9úbŸýöÛoÝĉÝ´iÓܲË.ëÚ´iSÐKË4˜Á§×YgÔÏÛ¦v"ÏD3:X‚²ôÒKý«­¶Z¡‰ú:{öl·âŠ+ºu×]7ôõÕW_ ¿™}ô‘›4i’Û`ƒ ܇~êV]uUÇlŠÎ;»e–Y&èB†c£6 åÚè{¡“–1 CÀX" ÿÆA^`Ôç`…‚¤:øì<‡êJðü,I ä“âãÿЇ¨‹}w|gù樂å7S†hOºá!¿]_é Œ $ûâɾlK'zŠR–ÀD¬#t€¾Êê¸ê0!ÃÁàå ƒð¸Ò£Î³<B† Êq;ñIe]¢Ÿ›5kŰ´4%†ž´E@9€íÿ$?Ú´I#÷è›SÜŸïç.>Ä‚¥µZCÀ¨ïŒà·'Gž|L¾üòË0£‚`eœx–$6F¼÷Þ{aIË@fŒ7Îm²É&á!Œ:–RTVVì+A]~mil65Ïl–Ÿ´jÕÊLøæ›oÜûï¿–fÐoúÆÞë­·^åwß}×uéÒÅuêÔÉ;6ØW†@ MPx(Bè믿x'² }G‘!`†À’‹~Çôñ~wâe‹ !0ÁÙ%èÂ+¿ïÉç…äUŸÍ(ÿŸÿ— „ÿKD*9ʪ“ŸM;!p÷àsðpC Oõ>[ðááK/yô"§¼|qõ¾ôŠï³é;ñéó‚ ÔÇ i‹>†!òÔ1ht49@äáK†T$YôæÓ&>¨S[ γ vâŽS¯~J‡‚Ò!ûèˆíûs,,¨2*‡p ²¦áfà î¯«Fáôä4¬°L3÷ÃÌFîˆ=:ºÓoÇýý”.åT[½!`õ"8üïÿ Ë4~cX2!§>¼á!8±üòËK4¤ðbY˜,ø–TÄ”öU¸>ÎÓŸO>ù$,=áLòMS²¯<ivD¬'-O‚/t ƒeX–[n¹ Z}O³i$Yø¢4ÿ›:Ù§žöØ¥ütRd¤ÛgÓIzmŽ‹b Ž”*…§Î«^@ˆä™n‚MòªóÙ‡\ÌWÿ°/ÔCè€Áð6€Ë´ Nx42RØO"’mÚ˜…~í¼F@›£íÚ²·Dn‰ oŸ!öBIo»í6wÀþû»æ‰üÚ0Æf¦2÷ìÙ³6Ô™Ž:†SËy;Ì:xÞ>/(-ÌkñG?Åè=÷¸¾}ûí&o¥qq^ÙïÇÐhÑ!@™,éàAüùa†dŠ4 5mÖA 6˜Œ‰`úød,©¨)0`Y :Øë‚¾¼ôÒKAú:xÄ~–k‰¾¡“%|!D³%P^}¯é˜­!`†@ýF_™ u†D¹³Ãï³ÆO¾ÍsÆrþ¯DáËÿ&@!9RüoÄ÷¬ Cx±¯ÿo-ÿŸzµSêYU|vø²O;åáǺ}±8©Qq‰ªFm8„uølÁ8BÒT¸í©×A=¤ê—"?²%ÙXl“B¼‚9®ýÍ„@˜-!$ó-šøàDÓ&~Ê‘O›ùt´_Ò1òý™îÉqÓÝœŸÙ”&“ê 4ÈMùþû·/Õð7ÞpÃz¨”ˆÕÕSp¸ºwëÖÏѧO­Œba^‹S½³zõÕW—ìçM7ÞèŽô?å7zôè’²V¹p`–kðvCDˆ™Xâ  #Óœ}d‘cŸd š½öÚk!°AÝ÷þ^ý^~ùåù²[*åált³3â¾²ÿ{\ˆ>tˆÇ§:R–†Ð?ö”` Q±¾3“Ȇ€!`Å๭6ü~ñ[Û/¦Ù´½ ƒ7ã/EùzùÄYüßêøßøÖ âÓyú&ÿŸþž¸t{vqÊ"D0’1òrEáqhfƒòB”µE¢žƒ`$Ýði놧á³Á¶lªŒ|Á~m_”iÈ^ü—¤&>zGP¢™ÿ‡‚~LòAšOu”¡®¿ÞuZ}×Õ¯}~â‰'‚ôÀÝQ}ûºÎ~ç÷m¶ÞÚ92ðyóx衇º6~¸ƒ:ÈýäÞKoýÃ\…#Þ­k×ð üÓO?í¶êÞݵó;ΟqÆ<òHØ”®½Ÿ–ýøcøÜlöØ}÷ ç裎 o •–©wp“gŠ:Ρ¦›3ˆ´kqÔóÏ»Þ{ïívØ~ûpÞ|ÓMa¼µu-òc¶ûn»¹µýÛö}÷Ù'8ŸøØý`Ç=\ë5×t—_~y°É¢æ\Ó•n—]vq&LuËù±4÷Sç•Xf‘"о}û*K$*++ÃŒ6¼$ÀuÃŒ…´,}ƒkY–]ОëT_ó p0f̘°™$ûMÉJ˜½À’tDS?ƒŠ M!£¾2û†}&Dkúk‘™9o¾ù¦XURÚr}bƒY¢b}g6 ûR0+ÃÈ0 CÀ(†@m&ø²¿­Æk“°k¿¦ÚÔ‹®,‰h&¾/Gì#WñóõÕñ¿ñ±¡šúߨ*øß>OŒ>ŠÐ—ů’j@U˜‰B2€b4&ÁCoÜÎCY²ê¬d •^Ú’§^ƒA«ß䵃¨ÚÒf©¨ÏeE`®?“Åf@4öÁ‰¦áLå–vøE2ᬓ—MÞ<Ø=öøãî“?v‡v˜{Ï¿A›æßò¦î9ï¹ë.7È¿-ÞvÛmݵ×^êÞzûmwÿý÷»ÇKUjz½zpzÝï&ÿðûO8Á=ýÌ3®Ïᇻ[þö7·Ùf›§óî»ïv{{çó÷Çãn»ýöœÀYÜb ÿO'Ÿt’Û~‡ÜÝC‡º~Gínô}>Þë2ª¿Üè |áଳΠƒ(v-ÎòÁ¯Q£F…ëª×{¸#}Ь6®ÅQ~fà Çï¶ÞfwϽ÷ºsÎ9ÇýéÌ3Ý þú:ùä“ÝŽ;îèò×øi§žZzð 7„·åcýŒž[o½ÕÚ¿hûÛ=÷týÞ]ýL>Gi´ðÐý!¶„³ÝÕAE<,°ÿD»víÂd0@rJYÁÁ[ع§ž Ô%wéîî­"‚#iÄÃÍú>Lð¢/#DåúJ DfÒ†9cB<ö¸®Xß‘¨â&–7 CÀ0µñ2,7„Hµ‡S`Ôñ?åÆÕãÿBøß"ùÔ¹qçùß1Ÿ<~3^tÈo—ÿM*¾86‘‡”W[x²¯6ð ÊèBV>½Ï¦‚å…(RI9è€øêXl<î˜ê}“0(Õ@€(C 4–mr%d_}QêáQ– Ÿ5ÊŠ½NFZ‚Ì”`öŸ —‰L0Câcêþ^|1lÊÆÔ^¨—w´xó¶ï~û9–U@cüzè£ûõ oûzç7q¥h´w(ûù`z˜iñ¼/³wS®wÞyçpS:¼O÷‚w „°×|v˜ïãù"fRL÷ÑЛ¼3ËTå|PU–ÖSzôèfKtË;t¥®EPœ0>͸ª¿6Æûh{m\‹@÷ /¸O<1l„xܱÇ–aðFûÏçx#ñ­ôß|óÍnŠO¹6¡¶~öN榛n®÷À´?uœïrA‰¸³É D²nAœyúQª/¥úJÝ‚Øf\qû8Ñò†€!`†@m"ÀRDó<Ï1c"^–Èì=f2 •½—^yå•*ËËÕÇýdÖa¼¬;l\ÜC*n³ ùüRä˜ÿ+ÿùÑäñ¿c?¹œÿžšøß±KÛ§©¤™©•y&J @$ƒÎbŒT<@ƒ§NˆÏÀ•W[µÃòðcŠO€ÚPŽ4ûð[Sˆ¢“g•B ÄâË(EØC–sP…<³,JÑl?­™µÈL†Î0 Á\ÖÎb“8'Ö]Çìq>'þ$ß:rÎÓt0½::­ë"X±”º»cž|S˜0kÅzˆ@±k‘Íã/%p]r=»^Š =íZäÚšã$å$6ókøÑ ŸOÞŠCñuþ‹·ÍÛgþÍp 8ï¼b&o†€!`†€!àÐ, žx®biâ¯~õ«€ Ï\ÓüFã<1³¿€O€#Ç2Ærõ1À,Ëüꫯ º jð\—üWÜfAóùå¡ò5kA^ÉG&åÁR>7^2ð!ÉÉÛ#•òðîÅõñ„_,øß²ƒ¬ü쫽ìѦ,a¬¡ÂFIʳ —<<ÉÑQ R¼X²êÈ$}±¼äH%—ìohl²!û*‡`-Þ™5ö˜ÑŒâ²[ùý#˜Ì~x`˜¢;É–]ºtq÷ßw_`?õÔSᦒ”‰Ë,Õê—iàH2+b?û‚õÝ|‘ƒŃ<Þ2s#b63'¸ ó|ˆìÝ·ÚÊ­â(}ûö í¹y5,ǵȵÅ5=lذæ}þÚÞÄÏx€ß¹sç°\‰Š{ý9DìCÑÂÏâZÜÎ/o" bd†€!`†€!Ž{αi4/!^Š˜HK/™©J= ‚ 1•«Gì7¡ý“ÐoaÎÄŸñ„“&G­œÿ+¹šøßŠ,ˆÿ-ûè’ÿÏŠ-G(’bELÔÙ¸-G–½jCŠ|ÔÈzž‚ ”‘‹Û¥ y"3Zâ³®úǾ¡ ó)Xn@b ƒŸî•iT—ï;<È—Þ~ûíݯ½sµ 8Ð(ˆ4£þ~­ýž½z¹uügYG¯Hg1ù“ý øœèº^–›û °ÙáU~ÏŠ]ýÆüCfmöG¢¢]|±Ûɯëg÷yF_\8à€Ü9gŸäØÀ¨a!°8®E¼æškÜþþåÚâ‡K±Ë¯¸Âý.ÍÅëöûû=%öÝwß°q+ÿf.»ì²†u"l4†€!`†€!`Ô"xIÉ,Xf3°Y%³"è…(³#âªðã%åêÕ]fzÜ ðÁËשS§.®½¿ðñ¡ñ¥ñ£)‹‡/ŒßL=yfNÈ—Ï®vÈp@ÈÊ7§ŒÍ—æíx 7GØBWRl—OlIB°!ƒr9ýÈ+OÇ©CFF}6Q=òñ`eWm#Œ‚%”UOª Eœ‡GýèPYúÖòkFà¬BDÑÒ>ß6Öoš¸ívÛ™%ýÏž¿ìî=³›0¢·ÿ*F«’pLø|’»Ì&¶9ñ 7rà6%e©dú:7 6ŽËB?ú Í—_>ˆÎœ9Óä×â'©…Ÿªõ׿þ5°‰\rƒ‰ƒQØ£­nHjÏ”{i}a¦ÄÂœŠ¥>XºøX×"£å¿"øñL»7ÁçÚÍOß“¸¥5@`¤ß7DJÇ›c 2Ä|ðÁª¶Ô0 CÀ02<¯óŒ„Ã_Š+FìÁ3|eeeA„=îØ}mÿ²“`ŸóÞÒ!PËkÙoÿp£6*[Ïþx<­ë÷û‚ÐǶXzK€bà 7,ØMËÄþIZ=þ ψÅäàû¯ÍíáÛNô‡øÛN?yñIñ‡Iãà2jã³!×°êIñ±Ñçñ½‘SЏ |Ê1TüúJ‚d‰?iŠé¨:"î ù¸L Ûä! 6Wš÷Wƒ’}t‘‡ÐE„¬äÑKT§Q~Ú‹ÏeA |ù3Éx(GÜJÜ#ª4g†BuHA ÚÁÜÏ¿qNÒ2Q#Íáãq2(!}I]*[PBH4Ütq\‹ ™vÂO J”âSg´ðà!ÀEq Uç3ži:jÊ#Øþý÷߇ýGâ l<`±a0{—°ñ×VòzçÍ÷TîÒEp&ía¨˜Ž¬}g#20ä!~Å÷céçZþ3º ›xkÆÛ4zY{œ6VúÀžÀ´ÜL½…Ý_Óo†€!~¯ Jl°ÁUfe3ë”&DùOµ³>3),0ã!¦rõ’å“ôÈ~â7K¯¬¬{a§òññwñ}!¼7Êò‹cߟ›àD{µQ*¢?ði/T‘‡haC:”GNþºêh÷ÍÓ)K`åê Z0ˆqø Ré’,rt>²ê°ÏCR=2Ò O:c=²O;ìãíb3"òyÚû¥"k^Æ(€ö˜Ðëÿà–«$õ{´‡r•¼¯Î²ÇDÂDŠ<Ôî´ÓN5jk ÚDÀ®ÅÚD³nëÂ)çm Äà ¿'Ú¬'{q&x«Ä>9ƒ<¼œ`öLZpBA”êŒ5–e§vÞί‘!`†À¢A€ á“KÅÙGâÓO? Á|z‚ Ág¾ÈÁoÁ…88^®> ¿™´Ç6v6E¿Yø¿xiø¿ 4Èÿ¦,» _Y|kH>v®4O‡êáÓŸ}´E?<ÙóÙ*þ¿øêØ“MøäÑÃÅvrœÄ_9þ v•"J¤#†ÔIÊð5Xåé2ylIžÚ‘G¿:KòÔˆì„ÐÉ ŽvÈI·Ï"9±}øFè°fs×û‚ÑᜯmðàH°‚™!hQH=/_ßií2h6CÀ0ê¼5×›óñãLJπ±ai]!ÞéË-u¥Oê³2ì(HŸ€8äà+ª¨]m§”x£E°€‹>éÆÌ>)]Ûħâ´|´¶u›>CÀ0 t¸Ÿ§ÝÓY²Í>sK/øía)FEEEÈdz‘)UϦ˜Iâ~OPB/-’õµYÎ÷Uþ­ühRH¾²êᑇ/ßòòë•ÂǯF^íñÅ¥“T_ÿðÙ +û’G†6*#G¾xÔ—¤, :+R@žQgЩ6jG‡8(ÓAHPH”xÈHm lrÀ—¼ÏÝÒC$û¹’ý-‹ÀÀ¾Êʘ€!`†@nÚ?3˜:*âÍ<Ëx@â›æ8ÄXJÀ, ˆ´´‚½NpšY–ÁÃ3 4¥”™ èfÇðbÄò f4l¼ñÆU6ó*&_ÛüR}dfQñ2%ÞJ1“€€7¬õ øo¾ùf˜Í÷‘ øA5ÅJéa ³ä%í![UGy¨e&Iü掾†€!°¤ Àï÷Ðd°`aŒ?m†`l§\=³ë¸×ó;Èþ JÑ)BÆ“üßPðe|]òð¥yHå;ûlA^:ðÝÉãW«Ï†<)¤öÒ¥¶Ø›”9DÔQ¦=×å8Ñ_ E¬ù²2 `A¬PÆd}t4.ÓIÚBäÕi ù˜/ð”'4">äEªíU±¿¨¦ŠªC–†€!`,0[ ‚>†ŠÃ+ç›ògŸ}–Lð cœX–7@ü6½óÎ;a‰u8º,u`ÙÄ›fЦ1ã€8Ž•ê#ð…ÓÎŽç<¼ñ _ŒM³ Úµky‚< ¨#-Vœ‚ñÛ,‚%ô§i/ fÇÐ_ú|´¾]¯¶Èò ÍÒÎ#c#Aª\¿ Ì€Ñ&›l–Ü€3MŒ CÀXà7‚ßÍ…EÜÏù­)Fåêãv¹ žób Þ;)–©Nžß¼rÁH_Yÿ×ËâGgõ¿Ñ'µâçí£KD>Ž!ˆ_%ÅÙ/G(R' & TŠI0@FŽ8Š¢N§LÀ8b½Ú3‡ôÒYÊØUªu0Ȫ^v~á!‡†rÔܯ=52 CÀ0²"Àž8¹¬/åM7A œ`œ×ü›”` *„³ÊW xSŽCΜRœfö=à¡Gy–ðÐÃÃO1¢oêÙ×à믿®òu‘bmj“_ªÌa‹œ!èÂi#<â¾PñPÊz`°ÒFÄjŠú’‚Ïœ£´AÎ)ý„èÁ'Î y–¡°ïˆ>?ǹ×Ò=œ2vÆCŸKõ[oÈHÁ$ —Ð ûc†@G€ ->º~j{Èü>s£rõq;d5“.æ×4ϸÑYjÖDT'ÿ›7äåëMFìøR‡_.þ7„Ï é¥¿üyäÑÉ í”ƒH%/?¾üÙ‚—´¯(e LÄÊãŽ`HÇuÈ’j°ˆg¦ˆÐiìÒÒ òª§.¶Mí3QÌ>r<É!Û4:‰ð CÀ0 ZC§”¥&䤯Êã/±ÈqÅ©ÕLfˆpPµôß.ÜrD„7ôÌšPÛ¸MÚ¬Á4^Ü&k¾\»ÞN±\€Ã{ï½ç6Ûl³Ô‡C‚Ì(áa\Eš‘R¬xÀ%h€'Ò‚ÈÅçŒ2ç¥)úÀ, a†A”4*×oÚqÞ^ýõò ä;㌯ ÉÿV{üoùà臨C'mÐ#>)²²ï³ÁϧLì#C;éõÙù)K`‚Ž@(¢3J1FYICŽê¼Ê´‰Á.é§Œ,¶Ä€'ÈI'ºD ói?'Ël /g”GàCÞtã>Ÿ¦ 2Ñ„ØxÓKm‚¹úJK»GnäÖX¹ô÷† XCÀ028ÑŸø%ìóÜ ‡Gb¦ÄÎ1´ùæ›—} ‚%þÁþÛo¿]E ›%±“Ïo"³ö\¨Ò  Zâ°Új«­,u`éÉk¯½œ|>“ÄÒ¼*++«T)@S¬*0k쥇`B2øTB<ÚÆ_`O6Ïd&³(p’¼RÙ+ÖoúÀrR̶aü´Ñ>#Òc©!`KÜÿ¹rO$ÐÏo%÷×r{}Ć1ò[Ìï cdÜQà!uHù— ±ÿ‹ïK_X„ÿKY>3|xøÓ¬“OÚªüçX—üwÚB¤’#¥-: É(/ýðÉ“ÆöK%Œ–#)UgdLe PƒC'mb@…$ˆvÉÁS¬l £¶’1Ÿß´I#÷è›SÜ){Ã]u”'ªƒ¯É†@ÃB甽& €3ªQ2K9ÞŽó ÅcÎ3ZQQÄÈ㳌€@f¼U/÷úöíÛ‡Í6e—”~aç™  †ðU HÁ’Pðx@ŠŠè³ œâ=xHdœ,S ð¡Ïáü Œ‡¾ÑÂpæ±A’Äþ l6É&bz¡@[ä™ RS¬À“ö`Ïì úËÞàUŒ0Ñ–V0 oJ Ÿ±éó§±úɹãm_¹~³¬‡å;覟Œ5>±^ˆ€!°$ Àï‹~3ù]âÌ ÃÚšéW0ä·ßW~Gù-æù Kð%ÿÛû¿øÛøÅ¤ü`kV<È{ná¯LYu¤ðiƒß Q/YxÈÀS^¶åçÃ'Åþ¿lÐ’Ž\©ÄßÜSG „2uVUŽ ÓA ç@†vؤ¬Á)¥^ìÙžô #Ùêh+=M8ù éböc[¨fHøÓ3þ›&L7qs~žëÓŸÝO~ªÄœŸ}ÙóvìØÜýܸ©;|×öǺAýºØÌ‰…zVL¹!`ÔexƒÎÃSšƒÎŒ ö€À1ÇQ]ýõÃPp@Ù,‘¯j¼üòˇ¯™ 8ÐÌ:¨¨¨(Ja@°ƒ ³]<Ðá”cBŽ·ô8Ð1ÅË$೤@_­`ãèÒ¥Køò‹´q3S‚‡Jì*ЀMÆŸæ|³}åK&"úOfA°â€Y,,!3fLÐÅÞ¥ösà<°TƒÀœƒxZ1´'p”\cÌ&¦Ÿø47Ø?¤Ô9_Î6èJê–†€!°¤ À=–û>{ðKüìí†Fü6q0NÒ,”^(ƒ‚ùßò±ñ¹Å#/›Tedcãò¡•úê@øßíÔF)üØ>elPˆ¼ìF±?IÇ>MNJ1J‡èœ:ˆ<ÆÄC–#îíÒäÑ%û€¬“J^ƒ¢Œä˜!{>[Hí± ôKÖ“·¿üÛ׿ÿ¦þK€äýiõÿ| ­°L3÷ÃÌF®ÏîÜ ƒ_w÷ý¹[¡Î2†€!`44´bÚ¸p¨y``VB’p4iK`B3$Ã[!fP§Õá´â˜§ý†ñ†e«­¶’h!%@ `›ƒå ô‘½˜Šé’Ì[øtEˆÀoü‹Á fÈv2Ò±cÇBSö(E5Å ´eçtf~0þ´ÀˆlÇ3)8¯És&9ê8·Éz–aÄç T¿ nphÏ‹´s-{–†€!°$!Àý0ïˆ/IÃ.9Ö|_Î>2þ/þ1þ/uø×äåŸKNediG™<$=äÕ–zˆ:äÐÍ_eìÓ†ƒÔ$_.0NÆÀúÙdP¢&öh³ XeYÃ÷+íœñïøÿûß|Ë;âvŒ9yîŠõ›vœ—¤|¬Ïò†€!`†@þwGL~8 ó¿‘«‰ÿNÚ.,ÿýEI3Š ø ¥ ò@³'¨ã€O½1ž]h§¨‹t2xtÑŽ<yˆ=¿ê‰g\È>2±}_4ªa¶hFÔÄ'\#NKnÖÄègå–vøeÛ¶[¶0Ã"jR£,S‚‹=ØK!Ó›y62Ê!@d™·¤£FrÇwœ=zt¹&…z®±r„,×ëu×]¦Îc›>üæ7¿)ذLÃ@€7ÞLßOîÙÀ½Œe Å6Fl£¯¬¬LÝ/¢!Œ­Ø"°„=!’û‰kc|CÀ0 C –ÿoŒÇ¦rì3ËÆ$rþ·üeÊ8vð%Otølh'Ýøßä!ñ—}Ť\$ûj/~jJG²äDÇ9b#tãðT¯Î¨LŠ.|6´Q[ v䑇4ÀÜ6æóôgµŸÓbË" =&’‚~³Ž0[‚Ù¹™¹™þ›á«Iùdùª«® ;²wèÐÁÝqÇ¡úÙgŸ ŽÎã±ÇÖFkc¶qãÆ¹îÝ»‡MÓN>ùä´e<œF¦>³‘ÙᇦÍöë×ÏöI‚¾„—yÍTkÖÃsˆ²\‹¬g=:TìZd-?×k©kQ¶•ª–6ØK!”ÐèØ« \°U²õ1%(³¤3?¸¯XPbI;ó6^CÀ0/ùUøÆYýßÅíÇöÉËŸ/ ¤E|…¤È'Ë‚/ƒÒ)>ò:àqxˆåâzøD_à#«6 eRäÈ+¥ž<ø6=2FÖ¿s=ÚÚc"Ù¦1Ó‘ý9XΡ圅bòjÿÒK/¹†eÆ s§Ÿ~z˜úÌzß^xÁ±<ãꫯ›…1#úýïïöÜsϰ£Äö}±8iêEq‰œ£_lí0¨à‚È“'ÕôÊÈ!|1t§^33|6((Çõð‘…—=lÀWÙ¿Ì$k”.z-F'šù¥üF¿Ùü?”bMÂTúý÷ßßUTT™wÞÙá òÖ‰Y]»v­Ò–)ø¼­~ä‘G¦eýû÷OÝ{‚7Wx`X›½Ã;„E©Úª±Â×´õÖ[‡”e‹òZdVTYYRûc†€!`†€!`Ôà‚ù¶òñ­ErzIñ›ñŸñYq ¹ØÍC—&ølAÙ¸=r´#Už²üzl@ÿÛçÑ+ûêmK’•RGÑ 0 åðÔIÉ W‡:©¶ 0¤t^2 ÈR§~ªÙRöiG?‹Væ|ɨ,aöƒÎLi›È-çðSå‘g–E)š={v•M×(ðFJÛ)øL“e¦Ä›é4Š72cc·r’4Æ[²°kqÉ:ß6ZCÀ0 CÀ0ù ™Kù¿ò½I«ëãý-¨ÿ]Ê>ue)“×"9:§¯€¡ŽP&O*wUyH%'½žU°E’:±­èõä©ç^ä8æÚRB5(÷UÁ^¼!'ˆ%a‰Í(.»ùæ›»#F„@Óãùš¼R´ûî»»£Ž:Ê=ôÐCŽF†@m `×bm h: CÀ0 CÀ0%|¦ÚNZ1ÿþâô¿³Øg E §¾a„ „?Ê€ãàu”!R¹|Yu (¨!=jƒ´Wßà1…vj糡÷M±^ØÃãP™6þ·xò›‘“¯þ82’‘}dÑAY¾|ìÿ'uS.K(*Gt£2¬Ž8P‡ÕIéRGiwD:bè±òè%Q¯~ªü¥ýA_T/[=kóÍ7Ã}ˆ·õñîüâ;Öíºë®*.ÑéŽgt÷žÙÍ ÑÛµiݪ$>Ÿä.ó‰mN|½rcÏ’²T2žei߆O6&Á'øöØc7hРðÝø‡~8)feC FصX#Øêu£G}ÔuéÒe¾1ðYØ–-[øC† q|p¡lCÀ0 CÀ07|®z¥•VÚË÷ãà; ÅVž‚/ àS/ÿ<‡üëÙù<<ühô¢¢ yün‚"Ô«Îgƒ¬üê”—ÊðÑ]”(G(ˆ•ÊñW§eH‹u"CçiQ‡|R€ ¡9Ê JÀˆØ>:¨G޼ú“jŸ“h”_@1$‡RZ5Ã"‹ö“È”@×~ûíçDðÕO>ùÄ <8‹ “12!`×b&˜LÈ0 CÀ0 C  _Ê‘ÉÿõÝ]þ7A‰¬öå¿ÇqÚ–$ ”#EQ4ÀDP .Bð’zqué ¢´…àÓN†¼KdÑMÚ`“:Ù#OêinÙDf©<¿‰}•Ã#Q Òz=àØä"å;!ó¾.ËAI5ÿtìØ1ì/QÍf&nÔ:v-Ö:¤u^á?ÿùÏ:ßGë !`†€!`,9,»ì² Vþ/yüߨG–M”æ»Ã“ÿŒ íñ!ôI¿üpéùzääÓŠýütÚ’JFº=+äÌ§×æ¸(E‘”j (`Py ”ÎÅ|ÚÄuè$¥HvHEÔ«ŸÒ~d¤CöiC^öý‡0a”õÛ¬àz_0:|Ⴏm€Á fR„ E!õ¼|}犕²ª79CÀ0ê<l¾kd†€!`†@]A šuŽÿ‹¯‹Ï+_š<ø>³üid(ãS“RÖ‚/}”% _”æS‡lìc—vòÓI‘ÁfI’Ã_JÅ$rRªž:¯z!>:gZ 6É«ÎgC>r1_ýþtP¡O Àœ.…Xp£‘‘·iFI3 C a"`¿ ó¼Ú¨ CÀ0 úŠ@þÙ?W$Ÿ˜2|ùß($GŠÿ­ ƒøžUh/öµñ¿Ñ-ÿŸzµSêYU|vø²O;åáǺ}±8Éñ/.1Ï(Š5(ä(€¯>ƵòÁ‹ƒ´§^Áé#E´£¬~"¯:µC"…‡}*P<ËÈ0 CÀ(€&Êcd†€!`†€!°èÈoOû¿òéþ/~²^ÖSÆÆæP;Rää7“ªüh6(S/yBàéðÙ@ÔáÇý@ÛÒO]I’Ã_JHƒ¤s(V'I9 u˜2:òÔqˆè¤ÚÅúÔyRˆ:3(Ó&–O6UÆöiûKÖ̧O§½‘!`†ÀŽ@ÚïÆ¸qãÜ‹/¾èøŠÓøñãB묳NøÒG×®]]‡2¡V[z23!CÀ0 CÀhhàûÊÿÅçUž™ä Ê?÷ÙùøÛÈÅ~7òòÝ}¶ „,z9 äc[±ÿ¯€Dô’>¼øUÒ, :¡NÓc ¢32¬NÂCoÜÎCY²¤ÈK–Q–^Ú’×`}¶ÐžA«ß…„ç©-mØüRýñY#CÀ0 C ÉÀÄ#<âØó‹/¾p|é‰ÏC(>øà7jÔ¨ðiãr{SÔ–žl£0)CÀ0 CÀh(üÂæ~9Âÿ… Ÿ—OMSìS‹ 2 DÀ—ß.ÿ›T<|jl")Ÿf_mr’óüwdËúærðÕ8-ÅŠ8PJG9è<åé,²”ÕQÊe F PG:Ù@§ôûlÈSGl‘§ÏÈ*|Ù#¥^eÉ{–QVÎö{ÿ‹éa_mnoz©M0W[q)wÑAí]«KgUmr†€!`Ô âÀÁ„!C†„~·lÙ2&´Ÿîúé§ŸÜ”)SÜ]wÝî›Å‚µ¥§^h4 CÀ0 ZE ˜PPÝøÍPìÿ’çßN=„ÏÌŒ ÿ[yÊè‘ʱOM™züotÒŽzøò·å{VÐ¥”zûÉ I¨ˆÿT70%¯AcLA x À×@á3µS[µCyø1é¨òeÊIûð[SÛüÒ£P "(1ô¤-ÂYàD¤}*´i“FîÑ7§¸?ß5Î]|ˆ'ª¯‰†@=@@‰÷Þ{Ïýç?ÿq"š7oîzõêå^{í57cÆŒ0 >ݵÉ&›¸‡~ØýøãA¶]»v®}ûöUF™Ô³ÒJé_2úþûïKê©¢Ô †€!Pg`-ø¤I“ÜꫯîÉŽâ`|ýõסžçT#CÀ0Ê!Ÿ­)ÿŸÿWùÕ¤øÀò¹ñ¯‘ÑFrð!ùßò¯sÜœ,ö°ƒ?®²ÏüoÙ¡Nþ?öÑ#©Û³Ò)K`…Æ ¢2< Š4)OYƒÇytHVú$ã« uä²èP{é •œì!Ÿ/käàœÿÆÓÄÍñ?œs~žëÓŸÝO~ªÄœŸ}ÙóvìØÜýܸ©ë³[wæïºKë`3'ìê1 ƒ€¯¼òŠ›¸ÐWê¸_0Ûj©¥– Ï~ýú…ú‘#Gº{ï½×]wÝuù´ :;î8·ùæ›§UÏ0 ùÍ/ñyå3ËÿÅçMúß 9 ðŸå“‡,¨­äáË×F7|ÊÈ!/’}R鿎ŒøÒ…ŒìS?e L RÄDƒÉqs ©ÔÐy:Bª¼Ï‚ Ô!·£óI;ئ $ »ê_aÓL‹D'a*]öq ÿ“iÖQûB¸Ô~ñɼӱÂ2ÍÜ3¹#öèèN¿ý÷÷Sº”Vlµ†€!`Ô˜x÷Ýwƒsó€Ã°óÎ;;6¼<í´ÓÂHÖXc°ÏuÈàˆÐFí5ÜXx=zôp P1¤”™¡QLOa+†@C€YO®½öZ·Á¸÷ßßýápÛo¿}b>ôÐCî_ÿú—»ì²Ë\ÇŽÝ;ï¼ãÎ<óLǽ„Yáå/ˆô Vd„YåŠ47¶!`4ðñÜð¥ñ£)‹‡ã†ßL=yfNÈÇ»CNíပoNÿz¶?𯓄äÇK—ôȧG¶$¡ I¹œ~äÅÃy¤< œ¼„­œ1¥ò½é=¾¯|mêñ‰!xäuà_C´Åï–¿íTOßZ³*(K¯Ö»H@IDATRtp¨­l©ÞWâ؇_”â @Q!_!ƒÈhq#t¢žä©K’ÚÉ>íÈCÈËed% DuE;˜ú¢Q9B>qÉ4ñÁ ×(w RŒþpVni‡ÿ¡Û¶Ý²þǶœÖªõ#†w[o³Mµ]x¡Ûq§\·nÝÜÌ™3Ýtï(Ô„ØwÛí·‡5ã8t&ŒüÛï'üƒXÿSNqO>õÔ|ƒ¬éµH;Öí§ß2—k‘T›"Îg¨£¶®é—_~Ù]yÅn'ÿïã›o¾qç~‹ÆÎ‚€öYÏÉýƒ 3’Ô¢E‹POä¸îÔ^²±žÊÊJwøá‡«*¤ PP½4=UYÁ0êáÙ†ã,×bšîÝ»‡ßž[>ýôÓð‰áø±ñƇ³fÍ*Ü;âúbƒD&)Çì‹}öÙÇ]~ùånĈa6ÆÐ¡C‘7ÞxÃÝvÛmá·êücŽ$Û³e|CÀXüäÿ½ÊÿÅ1ÃßÅ÷…ðÆ(ã+C9Ç-WÆçÖ Ú«Räc’?-Ô‘‡ä4aC:”GNþºêh÷ÍÓIFÒks\”£˜T†0)‚B=F%‹^u‚¼:ì³!/”iGY‡x!¸à ÒSmûvÓÊì^ü—¤&~s¦fM»fþA½)©ß“|öûO”£K/½Ô­Û¶­ÛÊÿ@ó‰=Ñ3Ï<x;tÑ|øüxvØa®me¥Ûz«­Ü¸qãÂé+¯¼ÒõÞ{owËÍ7»~ø!¬åFž@ÃñþM&òûôîí&L˜;̨èÒ¥‹[Û¿Ý<ÖO¥dmÖï8À±;~g?Å’é?úÈ}æ ÖŽï¾ÛnA~_ÿÃΔL¨˜þPiê,8ƒ«¬²J@-·Ür…~VçZ¤Ñ_ÿúWÇõÙÉ¿ÙîîFþóŸÝQ}ûý¬)ÆiåM<®¯m¶Þ:LÿGoÖY°æ¯~å~ó›ß8Þª1Ë¢Ø5]Ýk‘ñ±9ãrù›F5G Üý½°uëÖ!ÐÀ½ƒÀ׳%¸‡q‡G2h£öJc=ÅzÅŒ Þf–Ò#}–æ2ÃÁp¨k׿;,Ó8ýôÓÃ?uîó}úôqß~ûmp €÷›`$ef»Aq]±|š¿S§N ––   ìØ±n7ÿ|Ão"ËFvÝu×̶ŠõÁøöïÏ®E{ „´¹? âGjžÿíÈgÇžeFå%È¡”” yŒR&(!cä!Õ+/>m ÚɾRøÔ£KvÈÓVòœŒêÚ÷MŒ² 0×#ëS©±NðE(H9SÅä¥äÅ_t·Ýzkxc}Ýõ×»^x!T1¾ï‘GºKüƒ=o³ÿvË-îõ×_wÿýïƒãöÁ‡ºãO8ÁòŽà)þ7ÝÍ^†·Ô³ý›…ï¾û.è™ìð›ú©Ï¯ûÞåýtÉûï¿?ðŸòù<ÀîùçÝ«¯¾ê†ÞsO˜Æo£6r?L›æ¦åg^œà§W2“ãm¿æsm?íÿOþÍTL¨´?uoº)8ŠguVègu¯E>9èê«Ý‹/½äþq÷Ýá:êîƒeçžsŽ;Ò þæ¯kèË/¿ é40#Æõvà†¶Tp T{ßO¯e³D>-Yêš®îµÈW úû¥$?Î-zØWÜ«r²©Ò‡rH8Èãdi£öJc=ÅzF`‚½*Jé‘>Kíàámxg½xiÂï›R²dãnÿ»A[~ sÿûí·”ýgH¹° Y(«½XŽY{FÔž”2|lOóÏ;’'/9ñ,µëÜ®º} ä—rÈ¿Æ/®ëþ7}MúÿáÞSìS;Ê‘’£Ì»')À@”é:Õ&w‡H wPVÐA“ÂCtùl lrÀ—<è–ê ÙÏ•ìoYÂM©„Á‰faß /ÔÈOYö mJÑïÔí³ï¾aÓ8Öùï¸ãŽA‡n̘1áà!ÿE´Àñ{ÃÎöÎäž¿ý­ëÚµk)õ¡Ž™açüÝww>úhàá¨1;âVï<~äƒr©LÛ{„€Éßï¼3¼ý<ίùÜ×÷Y”¦_u–Ö]zôè:×ÍÏÔª{-²y3N9ùd··wø/¾øâ §ÔŸ^{îé˜Þ¿ï~û¹«}PâZ⺼ÙÏöyü±Ç\“üÃc1=Õ½¹ömwöbhVŸ¯{fVñ¶óÔ$%pÊü¼}ôÑaù {•0k‚·‘´Q{YŽõpŸ‹—n b¶W)=AÈþ†@E€}.¹äwÍ5ׄ™ ¼@!ØØªU«p_èÙ³g¨ÓÌ*ö—€Ž:ê¨BÐ <‡•y®ñ½Ü›˜yµÃ;¸§ü ÊðYVr¡_Ëo33XæÁ²Ø¸½tZjuü¬*ù¿±ÿûÌtÇ 91Hå;ûlÁÇ–|wòøÕjã³!O ©½t©-¶ÄÃ&eu”iÅu9Nô7K`B,ˆš‡Ž¨ƒäé(y• g tRA†¶Tzxd¶„tûl0ì¢6è# rvÓõHTƒÂo!h– ›Ë9AžY¥h¶Ö7óSEÌn€X²­¼òÊ!=wÀ×ÕÿP2“÷zGàPÿf’7Ó¬›,EËä×~“ªû=ýÛãNÞ±d9o"JÓ+çø·L©„šùiâwT/EËæ¯µøí×gœá^ó3vöö³&:øØÙ,±ÙµX ™EÇ×ïFEEEx øá‡Ã>_Ìàš`#;ˆ 1áq>¹wððOµWc=ìÐÏZrôô’Þj–Ó#}–†@ÝD€ ${ýégƒ²É$K)X6Ás ÷…ƒ:(ð˜MSoøÖ}ã­·Þ ³ßTÏ -–·ÆÄË–‹Ä/Y¸1óŠ¥$ÌÅþ¹çžš¸æwèÙgŸ /qXæñùçŸlƺ-ouÝ#|ïäìÓQùÉøÈPì'ãÔ ‹_Ì‹D=<ùË>Êð¨CŽ÷Üs®¹»¥é±k1@³XÿÄ÷4‚ ”Yfñõ×_‚—áüå¿ÄÁWP“lZçU· zÒtÏ0êÌ~èÓ§OX’ʽ $¤ûÊ1Çf[q?YuÕUÃL6§dfÝÖ~o¢Çü¬º$©­ø7ùeŠiÄsÕwÜáxÒf½´}íµ×ÂÌT"FÏ÷$¬HêMÓi¼¢”%0+;BÇÕy P‡,©«xV…2Ã.m!1ðuãzêbÛ”‘!pÅìûªÜ9|Ú4Ž&SaT0ŸÁÁO÷*-˜¯½|ßáþ‡­´(K7˜2ØÁ¯½&°®B@¼-¼ÜI€©8cë­·žësÄá៯(\áw•fVû@{ùeýüþºDiç˜d vîìVnÙ²0+ƒ6ûûÍ2·ñ{I0%;&¦^RwÎÙg‡Ï-{àP¦?ngùúƒ@u¯Ef=°ÔˆÍ, pþå/ ƒíÑ£‡»À?رGÊ­~—ór׳~eªÿZþ3rkç!+vMÛµ¸x¯©äÃ:A>ÿÇ›L>Ã7Ñ”£6­Û¸u×[×_SgJ$GQ[z’z­lu fPýÊov %ï'ðøÍX}õÕɺsüžEPš\¨¨ÁŸxÆÍÙç†åøe¯Øæs¡{úe‡µi³Ý´&†€!P ¢gM|`üg<0”åw+háYAùØwFVAdä«=þ·|pyyÔøàñ}â“"+û>ü|õyd”úl:¡¼Ñ…’Wg0 ŽÈu˜Ï†ÎIžöÔÑFAÚQOªvÔa²‚ÒËSŸp4²èW™|ëÉ“'ÿS7^Ök꬯+»oëßÚ9·çÅ/»{ÏìæŒèíº[•„dÂç“Üe>0±Í‰O¸‘·))K%|¦*„ˆ‰óÃçõYulÎÄz똘QÁ?̤ŽX&Î3Õšh-ÑPÓ¦õC<¥|B4þŠƒø–6ª{-rMhš½P PÁµ›¼¶TŸLY„mÛ¶åÍñD°Þ\~/~µ‚(S§€‚´Á £"ÅoF–öÔÑ’¿M[9ò’§-¾7$;ò㑉óÈP–]Ê©¤à@ježwC2&0ÔqSP¾ƒ,$YÊ© ±<²²ŒÚJ^`Ä|ò)ÔGŸ5ª¿è ûFʳ%8²¦&eùL%I%àeu‘…ÒQð‹%¨³ (4lªîµ˜vMd Ž I>ß–F¥®é4»i:ŒW»(˜]»ZM›!`‹$ì·xσY7j‚@~k‚ØÿU@€_š ¾0¾2„Í!_Yþ7uò­i#O.–…‡ <åe{Ò)ß=öÿcû^´ ƒ|IBI9R‡S'dPed R:¨2òÔÑNA N)õÈÆöÅaOzKöŸ:ÚJOnÂvöˆd$í11 ×>¢žkDêãë¡\%ï«ý‡u ߌؚ˜!`Ôì7£~œ'ë¥!`†€!°¤ !¦@~°Hþ/<|k|nùääåo«ŽÙ¼·çsó|hùÒéÿàCèQ¥ðcû”¥=ú”+•ø›tìÓD¥£tˆÎ©ƒÈcL<Œ@2¤2<å©Ã©ÀHÖQ–ô"/ 4hÏ ¤Á©0i‹é…ר0!; ìÛ)»°I†€!ÐøòË/à¨lH†€!`†€!P_ÈïQ†ŸûÁòÅgxò…å§“Æþ7íi‡¯MžÀ)røÜ´G‚'’]*àÇö%§¾P§xú$+¹ùÒ, ”Ð*¸€" –:äLPYÀøªBg4éDF€‘焦™^$´QÿeÁÓFeäŒ CÀ0 Ìl¸á†™eMÐ0 CÀ0 …@~O2ùßòÏUŽ}fùÂt 9HÁ•ñ·á!K^~¹êI¥ÿ›<$ò”ÓüqÏ$}j/~j*E©•SVPA@êùxVƒtFµ!e‘QYéDNm¨‡Ø1pTƒ!€$áY¥©ùrË•°ZCÀ0 CÀ0 CÀ0 C`#_€;ùø¿”9äËÿ•MŠ )  ÿß’Nê‘'E7©¾Ø!}ÈJŸüoéC†<©Ÿ $?_åùÒ, :„"Œ&˱QÕ{±Ð™¸¬vÔI—ä¨ã.Ú øô8H)2´Až”²(ðm Áa©!`†€!`†€!`KÏ>ûlƒè¯ýk}l@~°|iùäò‹5CB‚”ãzøj‹¼ìa¾Ê~Ÿ²FYøã7ݸϧ…‹_›[Æ›^jÌÕWZÚ :9æÚR`ÉNáó Æñß4qsü”‰9?ÏõéÏî'?UbÎϾìy;vlî~nÜÔ¾k{wÒÍcÝ ~]læDvˆMÒ0 CÀ(ŠÀ/üöΙ^ªR¶/Œ…«F<â¬ð Ï ,Ò†â¼Ôkd4`Š/Èï'ùÛøðøºøÈJ“dñ£ñÁÕ.ö©=»àcǨ /Ýè—ük_V ¡˜Þ˜/Ý´-IRZJÅ bp(%…!|¶0ø€\¾Œ,D;#=IÀÐK{õ2SPhÇ¡v>ÊqßÄCjĺQvæz´9 ¦þG;œæpñ'Wוs+,ÓÌý0³‘ë³{wÂà×Ý}îÚØCÀ0 CÀ¨<³Ìš5+4^qÅÝr~cîü[²š)\ÂZéù%ÿStô<Öð?cÆt7uêÔâS|œ( ™Uõ†òï:`áö†C†oL^·;|äØ'Î;q_eÉsOÎ2ròµ‘ÃG†C2ð)#‹ʤ´‹ýÿ¤nÊe)‹†Ã¨:@ç€x¤2muˆOмE¬@#ÅŽäiƒmɪ½@ñUUí[`H²SØO"oÚ¸‘kæÍšø7 þ …¶k»´Û£Ss·kçnâäéQ Ëuwß}×Íœ9Ó}òÉ'‹¼S‹Óö"¬4 F@A‰fÍš¹6mÚ8”È+ öÀò“<ý Oçfû§ÃYþÉ2í ™FMšºåWXѵnÝÆ9!{f̆·I†À¢G ÿ¹Ðzá{tbß°ðÕé{IÒ¬„RB8ÿ"Œ …¯²ªÃ8„ QX@VàJu´ey„ A äÈëP;ñIe]¢Ÿù±ùé'‚JFYo„d¾Aœp€57kbô‡³rK;ü›mÛ-[˜a‘E¿É‹ 07Þxc7jÔ(wÜqǹѣG/*ÓáávqÙ^dƒ4C†€!P«hÙF«V­jUoCW¦ Äß:wÕ(çÆ|îÜô2}Ëù§Ì-Z;wÊVεkéÜê«·r&|fQ,µ”V 7täl|†À’@[Ê!ÿŸÿWw;5ê ùßò‰U'?›vø×¾5|üoRxª÷Ù‚_öÉ£9ååAªðu W|ŸM'u8½6Ç¥ó’‹ÂÃÃyêh§ƒŽ&ˆ<|ÉŠ$‹~‚'Iû´‹í ÚW±o_IvÒÉMüzLfK0{"7s"7“b®?…̲(E|ªg·Ývsݺusîúë¯âŸ~ú©ãó7-Z´pÛm·›4iRàÿö·¿uGy¤[mµÕÜî»ïî.¿ürײeK·É&›¸Ï?÷Ožž|òÉP^{íµÝW\xöLj`êÞª«®êš7oêþú׿ºC=ÔµmÛÖm¶Ùfî©§ž MÒ®EîíÚµst[yå•Ý9çœã<ðÀp½î·ß~…MuÓ®Å4Ûqß,o†@Œ¿½&˜%aT=xyo²sßçÜÓ;÷ãlÿp陥d¥ mѱ +„s`ûyT“6 EŠ@&ÿ×÷¿š[[Òw_ÿ›fµöñåI!x%©¬€oB¤Œ2xé"O=Á:B;êâåâ«ÃØNäã ÅÙ·f5h®G›ó4jìƒ|‘Cа¬ÃË“—¦G>÷Üsî¶ÛnsÆ sgŸ}vøñ'`ƒG°¡uëÖîŽ;îM&Ožœ¿?þØMœ8Ññ™dpï½÷^7{ölwÈ!‡¸+¯¼2¼Ïȯ´ÒJ®sçÎe¯Å4Û…NXÆ0 ~G™1Qe_ýµû¿ÿû¿Z_®zë­·º!C†„Þ]pÁŽàmSmêãŸ_œàTýÃKòØ«“sÿ·¯s7ôrŽ|²žò Ÿù7i^Øs²<ÓÔ6¦Ï0,å¨ÏG™ØM“ÏŒ|ùßä%GZÌÿV|sé‚· þ·tyU¡ ~¨OðS)K`åt"Ø@àaDeŒk€ÈCZj·C†z”ÑCª~ÑNú|¶ ë‘mRHòô[zB…ý)oÂY(!êÿ}ç–sø$ò̲(GDäùá?å”SÂÔzöYýõ;b‹ôpÆDB¢›B,ïà¸è¢‹ÜV[ù…¢F†@t-tÐh±k‘kSd×¢XòÒqãÆ…]ƒ rO?ýtẉƒ>¸JPuQ¡SªOêÃwß}ç~øawõÕW‡à-oäcbÒ„ Þ£[ˆtíµ×º¿ýíoµbáÌ3Ï 3åjEYŠ’›nºÉÝpà )5‹æ<ë~”Ú&¸òûÇ5Y›ôöÛo;®/ˆ%mµ±$¶oß¾Uöù©-½<²°‘å4fKø4>z¯ïÜe={û«ÜA^,Cžeè?á!( Ýþ†ÀˆÀ|àî¾ûn÷àƒ†—¨1wÝu—»ÿþûcÖ"Íç7çÅO†ä±‘Biþouüoœ,ùÍ5ñ¿ý]´ŠÿO¿àI§RÏ*NY„\ @‘Hy¡NJ2´E¢ž09 é†O»X7<ê%SÖ~uè½î%šr_å¼Å¡x–r„=&jøCÎtx4O>ùä°Ÿ3$²o« HôèÑÃõë×/̦¨§,¶M¦a"`×bÃ<¯µ1*ÞH³N+3»Øg„}JtÏyâ‰'Ü7ß|S¦2ë(×'=ôÐC®C‡îøãwÇw{íµ—ëÒ¥K•@›Â>óÌ3™íÖDðÿûŸ{ë­·jÒt¾6¼ÍîT²päÈ‘¹k®¹Æ]|ñÅ…ru3ô3ž¹·_ç9¶ŸÌƒÃ?ÿùÏÀæ\/,0`@¸†T?³Ó¾ýÖïN™§ÚÒ‹:–d$gBt\͹Ëwqî-”ØÿžÜAÞNëÎ/#CÀh˜dYÆÁÈû÷ï–Šó›É¬1^<ŒPû÷Þ{/,ñUyQ¥:+¼ ËSYÿ×Ë!Sÿª©ÿ­Øÿ'ÆPèp^o\ö¬ùINÿü5ó8Ü®uËF!V@ƒ`yx2½q;_ eɪ³’e0´—^Ú’§^zÅcÐê7y^i&û´TÔÎg²"f@x¤?íç=f Ë÷fMdOä˜cŽ 7€UVY%,é@ôO¬*)›òærÛm· 7 ¾:ê¨*2V0ªƒ@±k±œ»Ë!T¿ë lóFšèùçŸóÒK/…MyqˆwØa‡E>À,}¹& ѧOwá…†)êOXŠÄƒÖc=Ve†Ú"D jO5' Èò>{Â|ÿý÷*6è”}q~üñGwã7†sÍì6é… ýýï›K“2KŒ%‘§žzj˜ÎÌ ‚û,ƒ|á…ÂþMÇ{lö'AcÓ_¾B bvÆÍ7ßì˜UQQQlï´ÓN!`Äïòˆ#Ü”)S܆n®=–ÀõìÙÓMŸ>=”yÛÈþ;I½ÌÞ¹å–[ÂRÍŽ;†ßtôBô—M²ù3{û°×ýay¨ˆ="bZsçFêÜ‘æö‘ nß»»moçZûýE“òq[ˆÀ’‡÷5~Sx ÁfûÐСCÝÀÃ2ô 6Ø`±ƒ½lÇÿ…â;Ÿ|jÒ˜ä?Ç|òøÙøßÒ\,K½xøâØDR^máɾÚÀƒ¤Yùô¡"íFË Q¤’rÐñÕ±ØxÜ1Õû&aPª#€Q†h,Û äJȾú¢6Ôã,>k”.zŒ6­[¹R:Èe^5ðpÁʈ7'íÛ·Í<,ó°ÁÃÓ!¸Ø[bª*_E€ˆdò ±ù%c2Ý”vÓ62Ê!ÀõÃuñ Ë5áÀ%¯Å¦M›º©S§†zþ0½oÍ5× e®g=4ÛµX€¨Áe8ÿ8¾|ÁE´å–[†7Õë­·žXaŠú6ÛlãøJ÷«Ø9ÆIä«Dlº뮻ºýë_¡3 ¸ÏM›6-”}ôÑð0$G›û{£D"A.KŸx˜Âi$¨¢eq|¡‡Y<|U—XBø7°ýöÛ‡û4:x«Ä-1±´Žû¸ˆ1qÄfŸ° 24cÆŒðI_62c¾–ÃÒúcK™¯š%Á’+¾ÒÄ'ÀypÄ1ÇiíÝ»wXÈÔÛÿþ÷¿A'ÿ^ÄA7ËO<ñÄ`Sýºï¾ûÂlÎ _‚Ò¹P}2e#fú<û áØCüñy`#"¦÷èÑCÅZO™%~ôœ[]W"Àï,ýå!›€oýØ;bæ›Q3û>3iÀÌ’ÄõH "à†àI;°8á„»8¯guVXöÄ”ãsÏ=7,Å䟥š¼@ÐFı^þ-œtÒIa©üãá:ã\;6Ø¥¿\gÌúa<”¹Nb"Ðø•({ÿùïfÌ㓇wãKóxjë²¼!`4,xáYî`–¿Sü.K–’ô¹·‹2ä!ößá÷g—]vqì›ÃfÿÔqÿcY`¯^½Â=ú÷¿ÿ}˜­H2{î¹gð’žqÆݲ‘Lƒ1ÿ'¿”ÿ;«ÿ+ÿò£É/åØO.磧&þ·\JlÆö)§+GR!è` Æ4xäÈ“2Ú#K™($9dz’}Bžzä©Cž#“}N®QvBŒ!Æ'|>É•:ЪÙ-T•ä¡9Þ[¢jméç6ëòÒš¬ÖÈm|f×¢] 1ltŠó…“ÄC_b6âmÓ¦MA‡ŒOÑò)d¾ø‚£ ñ5^‚<òHpèqÎpq”qøxc áX~öÙg!ÐJ™`meeeᔥO8¥ØŒ÷H¡-_6¢ßÔW‡è'³F˜m1zôèð Å<’”|ùå—UÔ±oA‚67èñ¶›/)ÑY‚7¼-?í´Ó‚ãŠóI…/á°lEË523€ !Á þ½âóFëüc˜ÁBàèž{î ö˜aÁÉ,ïÀ)wú 1󅶼ͧ_¼Ùèê{œ^wÝuáZà­?ã‚$ÌÚcÏÆ)¢ôea˜¸â¡—©Ä¾bÛ²ÉuHÀ¹Ã;,Ì”Q×0³jNL`V„p–L2}üñÇÃuK ƒvü»àÁœßq‚nÏ?ÿ|8aVç˜ßi®;öŠZc5ÂyIê%˜ÄÛHÎ ³ 8/m´‘ÞˆóD`b‹-¶K©ø·¨€2 0Ô4•K C á!tô“e¥<¹¿$ëþò—¿„{|Hõü¦ æ~x饗† ?/¨çSôü®ð»Ä=’ ù%—\êÐ1iÒ$Çò@ë{¥³Xúÿì Ü•ÓöÇ—&’RTH‘™T$CH…ºÜÌ„kÿîu¹\C\t!ótežI¦âÊyV)C’ Q4Oî}÷9¿ÓîtÎûž·Aƒ½ú<ïÞ{íµ×ÚÏ:»sžµžµ×f À÷=EöÂ^û[¶7e!û[ö97.9%Ûß>F¶;ã'ûß«ÅÇAyù$æ1”Bbº)Mžêg¥xÈ^‡Fxñ‚Fòé_˜hyüÄ2ûGJ¡„¯ÆP2!)DuGåœ ôAC.´1 …‚’ÈÕüÈ;Æòƒ› t ´jXÓö½ðõÌÿTÂ@£ ’"8-r¥ã²ý­›¬^º€D™444°i`ÕUW o=xóAd¼‰ç¨ãÞ½{‡;ÑD$`h­l[‹6x‡9Ø^Atáì¼Ý&*çý… ¼9±GÔ¨Q…†¼Œë‚묳NØjÇv;î]oË»wï^€zAó‰§BèƒTÞ–ñÙâT‚7N©%<ð@`K4ÀÃ-Ž"”µU5ÄVòàD¦à”äŸÆB»¼ùâʶa­s8kƒe¢øÿÀ‰d)Ðe~‚TæSÞçó&R"žYpN4®íåÝ™žG|Wèfë˜=ò©?ÈæÑÇcS=i i`ÅÒ@y¶ Û¬üÞ•ð"3QlS“ÃW[‰ì£¿OŸ>áû’ˆ2E2VsáwOõ²ä•ЇýëßxÁÎÆŽ¦-¶0v3ýÔ96”o?êÈÐÑ–ý @?xµ±¯gù…}ð€W>ÉO?<¡-˜Hyc.ýÐ ‡ êˆP¡M]€`‚Ðp£ÏIýŽxÚ’)¾*áÁÕd-¦ÝÙþ1 ÿñ™ÜŒ»Mw™444P\¼±å4ƼM!ô’HˆØ°.Æ¡iÓ¦¹}ò¢áÁ‡mŽÞ°†¿ë®»CŒˆ iÞhdž¤Æ—2' LÞÞ³ƒ(¶¡`”“‘‡¦ò PÉŠKr©pmÁéD"K‚}åÅ€‡€ŽtÖøü ÚDC,ÈÓ¤6ŸN"Jl¹ÈŒlrÄÀ¼âH‚¸úW_}•CÁ}ò<Ì=@h/Q1ùy7r±ÂúÁˆg‹‹"A`ÉçK…¶ªðf“¬/Œ|jñœˆam3g¢p0”wì6´l±!b§K—.!ÊŒçAÀÁÆÿ n1à¼Àaƒ…5|¡gþü? Ä™-N¬±R€‡¾|GÃÃû¶§•Í®ÙËO¨9È·U}›qJœä™Ð—ðH44°bj <[°V­ZÁ¡Ê¹í¶Ûn>%°¥ç3QˆâÃï ÛßHœNžˆ| JG-¿ü6ðÏV@Æ‹câz>Bí,½ì^••"Zl_ÙÚôë« u]ØÓc±»eoCÇ8õSÇ¶æ ž±´ÅW%<¸4V²Ôï]aLŒWâ›)HEJ MÝ$ÕdÀ#P“’Z¥ÎÍ3Q v@0®/ÐPJ’Ÿ {ÉŒH“’’’’JÔÆ8#xËÎÞcx•gÄ!‚}ñädÀ(üñǃA‡A¨Ä©<°ðV˜·.Ðf8&ŠEK”2§£Ž:*ìE%´¯sçÎÁ ìÑ£GHä'óä¾H@¬+߉ÀœH–‰#}³l`Û‘ \Ìüøñ!¯{tÙŠ‘ÿ»K>òF`̳/÷7Þ(zÈ+x0dNÈhãlÀÈfè”< äúÀyrÞyç…í3ôuêÔ)äDÀÐf^lï 'BYpå•W†ÜäÁáÁçŸ Áv’s¢s¶ã, ró;8 ˆèA×4œÆÁ ü:„½Ìšk¹H(Ùš¤äøa9®#“È Ö3¢gØ ƒØ~ƒÓ 98°ò_$fûŒ’YÇ|ÉÅ|Ö|ù,pxû?¦±”á!Óÿ¬ìO”l爯›ß6;áI³Íýè[fêàbêÕ|l%ç¯IIL û‰‰†àwï8œüq´œ´Câar#á(æ%§ñÀïKì¨å÷HQ»ˆeIö¯ËíÌW6·ìoÆ dg«­Rxñ_!û;K/>È”|x&ZpC0Ö„(a .”!:ƈ<P 'ÄtàÔ¿®¿%yRÎ Þªh¿¥Óä€#©vÈîÕÌ!S%i i i i`…ÑÀËžp1ÿ-.7‡ÁŠ¡-0`@ÁÐÞF1Ñ´iÓŒ.-«dÏœŒ°,ÚRûJ™{[ åçÁŠÓx£NòIòTTHä…ᩜñx¶5à˜(ë¤$ÆòÆÙâdbìʘç÷ã>>aƒ“Ï9 s`,Æp©Ÿ :àáµ=oØpâðæ_NŠRï“yÃýUÔ©‘/ÇÓù&Ñq ÇÝâY`¶?•¾:ÆsI ðÿÏ<ŽWjøSåã¾Ó§]c?Zô§ÂÿqÖhdT€["MHXÖ4ÀÖºbŽþbs%’miD(–üñ;çFÒ~[øNÏwÔª¿Ô§/Î|¢ýwŒ·"ßø%{œ»û˜ºJ¯†66±œ¢¥Oö4}àùaÖxÆÈ‡N~ ú#>à„§?ù«~ꃾ<ˆ'-m„ÅBÁÓfrrÐÖÀsÑ–3>àhK!ÔEš|ùÈæ/z¯†qâC ù™Vú[®Î}x´?-$½ôçµ\òKÞJüRI0ëÕªf°¡­UÛ7q&HHHXÁ5Ÿ °0·ZÈ]>ñ˜RæDôF(Я_¿ðVXF|Ì«”:W…œŒÍ#_ˆ_!Ç@!ºŠàxP‹ƒ2vJÐÇf1Ù8I*òÙ ƒBô„ôâ `;GgV4oœ‹ê˜ R§P~͉$« ã˜Òøe­$Úa«†f÷ìgvÑK™S7fð¨]¬âˆD˜gwÌŒ…ºg$§DŠK]IË¡*úšˆ²Rß®BPìw§m)8ã²CÃÛØº±Í 8è°³UÊvvTŽ^<ø!¥Ž]­1^ uJ@ãé§®±ÈY´¹ôÑf ÷e0ÑßùÑ£Ž¨*LV“P·„I %4ç¢-z5Ô¥ 9¤ˆøf+:ñáSç§F¼½šSràÇøQ:EKx;A À)qßÉ[ ¢DÆseº4¯^¥òJ6èãIvÖÝ#í⃒s¢µ&’¤¤¤¥®Œð|£}©Oj™ òktêÔi¡ [=à~úé§ó宨¨ŠØÊÃU 6Þxãb]Ë%žüÕýi¶cÓŒ³aât³iþn)…úUý‰²Žï8âQœ#†Œ‹…uÚ’“pIIIKH²¿a/;YîØØNŽ þÍ—s0^ö2h)u³ºG¥ÐF9Èe, 'ˆ¸Ÿ¾X6mhp\ ˆbò½+8+ ­}ˆà”£°eƒOСJØì 4酧梠æ*UmòŒ•ìð½ZÚ_onwžºdÎk—¼T& $ $ $ $ ¬èÀ Á¾f¶à°µà³Ï> Ç’*úS劮‡b÷·¸žéàÃö#B­Ñ7ûÀ“¨˜Ö>i`ùÖÀâúÞXÚZˆò3aa?c±é¢-»[N G:ècÛZ9 ‘ý­ñØß²Á³Va ÁñU?á)¡•|¯;_󣄕^- ¥8&˜$C&£’‰ÐÖDò…AÇ… M^mÆs×Kø‹—øë&铜d@'žð"jÚ,ÁO‘ T GBŠeL­€C"|X+ÍëÙq}rKdòKô¹Ýã&+Ï?ÿ|xD262»“Ù6ŸpØ%Ò¤¢ࡾQ£Fáè§Æ/@—Öâ*YA¶iŽZäÁ$O¥$ƒZ€IB$ $ ”¬ d"'ø?ÇI.ñsLrL„§‘’uY!ù,DIDüe I}IIIKMÙïc²¿iS`øÒ–Í ^ö7éÁ3»Yãd?Ǽd¿Ë¦¥ä{5ð§ Õ)cyЄRbªÉH˜ÚºAÝ<+Z@´ñ 1.ÿæé‡V2 ÑXÑsƒ@Œ§Ž“Bs¤?A4@ÄÄ|ž oV&æq%T›‰šxýó™™­îôÙ¡yuOYNúÄã[;?N ƒqšgJ'cz1ÇÄþ~|Øm~Î|¡ÓT*&uÉSùå—våWØ5ž`.ÁÒ×óm·ÛÎûч§ùñŽC^|qIUd-^Ô§í¼Ë.¶8B¶˜ÈbF,εÈQŒ—ûñ»ø½O˜0Áοà‚Å<ÛÄ.i i _ÊÉXÎ×Jj' $ $ üq5uRÇö/ö6v1%¶´¢"ÀØÑ²©±Ö¨«ãŽ1²äbZpЀS]²e烧Äö¿d0L«Œ¿L¨<Sè çB nD7㨠˜ ‚ãâ4iJÝ WC_\"G²àQè& Ï’å¯(á;~Ï¿ à›?f"#¶²¿U¨ê›8«úÃRJO€I=P—·™ÓY\rÉ%Ölýõmû¶mm̘1)ÎΜ'dCj§Ž­i“&¶ŸŸu>ÕåûóþûÛÀ­µ'êúðÃmìØ±¶ë®»ZƒuÖ±Î;‡0Wá¼8áøãmý¦M­Ç¾û†£ñÀs$^»í··&þ¦ü´ÓN³l6[»þºël#?s}Ûm¶ ç®C+xíÕWmß}ö±î8aÜwÞi;ø=üŒøË/¿<Áç¸c såŒbŽâ·ã;úMZ·tÈç~[úy÷W_}uÀÁ¿{·nÁ`>å”SîÒK/ 4ÌéñÇ ¸ôgÑ5ÀC='°Îâ ôå­EŽ=<äCÂzbýŒ92Döðù³6n¾é¦àLë}ÄÖÐ37o¾Ùf6lذ0ábkqüøñ¶W—.¶žïß»{÷`à3 Ðѳ¦H¨wøá‡ÛºþÖ´Ï…Úa‡ÖÿATt=Z‹’Ïš>ÊÏ×&ò!ð÷µ /þ/…Ö"º :D~%HHHHHHHX^4€-¸<_Òs6Îraûœcû_v½n¥h‰¡_Ȳ’ÊÂ8E0}ù^G/ ýÐBÃ¥v줒½;ð‰yÇò¡J–Ÿ…•ú÷®íb•ü?6'rÈAAɧYŒ^2ßxã »íÖ[ÃëkÝ) #Žþï<ñpà 7„s†Gmd ÿèãí¾ûïá¬ïðmºé¦öÚk¯ÃÂ[ï¾ûî0ö§Ÿ¶*ú Ýj5kÚC=α?ÔËsÎ=×Þ|ë-{ëÍ7mРAöÞ{ïYÿþýí9ßN‚¡)#-0ò?3gÍ2æ{×þc}ûöµ“N<1D@<ícyk ô¿þzûÙe~àÎ$§»Óƒ/‹O?›û,çƒáú/wÈð¦þ?Jîý÷ßüßô¹UqÙe—Ù¤I“ìê«®²7wϽ÷Ú+î¸H°ø4pÃ7Ç>ýãÿLKY‹/¼ðBpzþüs;Á?ÖÝ©qÁg}“ŽG}´ >Üêx¢4œÇsŒ]êŸ3Ph-‚?ñ„lÛm·µO<Û>‘B¬­bkz'á—_|aû¸3ä5O„Ƕ'#\æ»ï¼cûÿ‘Bë™qñZ„×)~<`Çv ÿ¯¦¸Óïÿ?ø»CHÖh±µ¸á†Úi¾Ý § Ž¿IIIIIIIË‹–g§DlÇf#&by™µ¿}mÈÞgŽ€Ú™V‘¿„]”8`*§ô0Wä‚$‚ÚЩNŸBFV¡ Û³fδºuëZ:uý?Ï;Ï8",cÎ@%„d¿ü²ÿ…3âáÁuÞùç‹$W²ˆålëù&NœhâO?sämøýî(¹Ì·tð&›·Ý –ŒJY‹8ˆ xÀ#vömGôîmgžyæ|"7¸C;,lùÁá È_‹8!pjÅûÅYKÅÖˆøPΗ{ÅÇè(;ñ*¶žq¸ ”8¤•ÕüÿL—½ö²–þÿ€¿ÖuZ‹ÒX*“’’’’’V tðíØ+ÈþÆúÂäQ;¶™e së²Òä|P{´Ôá%^ ãÄÃ: ô’/#6üçOóäk¼w&R ˆŽ˜8W,„I0pê×Í«M /h©ºJÝ ê¢Ñ ê|Vñ+U~”þ”¯Ì©| e[9BމàÍ(NߦM{ê©§Œìþ¼­}Ùs/äQäšàm2‘l{À1 |òã=,¾ž;jxÆòbÀeN³:U@IDATdøä“OÂÛi¶U <ضo×.œ ÀX¯^½Â[穞€“¾R¡gVÛ3¦÷vƒ•¼‡@uûLr@ Aäã”è¸ãŽv„˦ã4È›A΂ã}ìOþàpÐZ$Rh œek­µ–5iÒ$Ðúƒá¿Ùæ›Ûýîè®»öÚË¡ÐaýTd-ZÏüŸ‰×"NŒ¶ž+cMÿ?ÚE.Û9ò!­Å|¤vÒ@Ò@Ò@Ò@Ò@Ò@ÒÀ²¡l„:&XlP,Ëö7s/ÙóE*GQïÀJÅ™€³€2¿-Þ•ë§^ô´5ŽºxQ‡Ž>.ñ’óBxæÉ‡€ÇF|(åà€ž±ñ ùzè} JÐ@ˆ€pÍö©k Ôf}{>¢&Ê"fë'´ðˆÂÂ9&T Ï‡<¸£€d…Düý¬³ áòí=%ûþysƒšõ<ܾQ–‰xˆ'epr\sMH4Éö‹-·ÜÒÚ¹S‚ÐõîLØØ3½ÜA¡SÉ/H¤‰ó¤¹ß<È4ß`[Çs’ìò3ßÒ×·ì¶ÛnáMùÞw˜'1d[G Ѓ#Á'³Ï>;îNõŬRÖ"Û8Åãßž‚¨òT$­<ÚóK==Ak·®]C²Òþy ­Eú®ñµø'CKŽ$é+Û&ò×H-ïÃqQêZìØ±ãë™ÿc\ñZ$ùêþ¾ÝéÜsÎ Q:8Áò!­Å|¤vÒ@Ò@Ò@Ò@Ò@Ò@ÒÀ²¡¬cBv°liÙÔ\ÁþõRÂqØÒØÌ”Ði 8.4?"Þ–AÂ@èâmù|â6´ÈOe ?ŸNbóŠùÅu"-p€ä‹ç[ìžb>Ô‰&ឪŸßŸÚ‹Wå­E¤U°Z^TŽ(œ|æ¥~¶ñÌY3ùßAù|f-æ¯gÉŒ×b±{­Êu-©EÄL>ð™ÄÛ¹ `x`>Yj' $ $ $ $ $ $ ,5 ðüé/gI<ö_8 ¸dìS×ÎJìbJìbvˆ›Zö¸Wsv·Æ3ŽºÆSÂC< …<—êØäŒ‘së9;ŸzA`PyÀ ÈØG À„åœÐ$ ÔfbàtsË8@|)¹4ydÉÁ ”<¤œj“ÁAœŒq;¯rÁzïKP@¿éÓð>å",Ê££#¾,à?\¾Sú8WDœŸ¡,^êƒg¾S‚¾|>ùÎ/«Ì70EÏ·Ø=‰Ve¡9ª/•‹_å­E$æ;%ÀÅŽ£R?[Æ ­™|> ³ó׳äÅk\¡{­Ê´¥‰T& $ $ $ $ $ $ ,Èæ‹mrêXn”²¿™,6°ìoJ@ÙË*å¼ -{Ú˜u@¶:´êWŸÚ²Ù%_ýà%^¡ÇacÆŽÝ„£Cm †^ £Î8M6nSÔGÉ8nˆ’+æ)‡„nNN' s€ž\ÿã¡?AéPމóº>âo†3ã(ýàО¯îÝ¥ä˜(]z¢LHHHHHHHHHHHˆ5ÀÖtì_Ùߨº²{)±e‹k\íØ¦vtÎÆÈQA]¼‘#;>Ø×Þ–¡ß/ÞŒ-Ä´,"ËÛÂÍÁ”<‚ä@ðjÀ3ñ ¹lZ€q\RŽøä+ ¾Œ×Üh‚Â8.ójhÇs`%¢”® jؾ¾ÂÔ9mƒ0sœDR§E®t\¶£FóN$(]R¢LHHHHHHHHHHH(OÙ—íØÅØßØÆÔ¹läØ&††>p\j‹û[8ËÐÉÖ†{.Ñ€§ ­ü²åcû?Ÿ7írAÆY„LIp!˜‰Qg¬&¬I:*à4QÚñDć±Ô¹)ññjn †nLràH>uÎŠÔø|ùšsH(q‚Ò4pEïJ#LTIIIIIIIIIIIIK\ÙíÄr@È&–Íí,s‘c9¶Ý±e¿SÒ–ÝÛßàÄÛ«Nv9Nñ‡|hÀ©_²Ákî^- ±Ó 0Ef"bŠ .1f|,1On6N¸¡I‚ÏŸ |CÛ3pÜh,ôC'ùR¨£æ—Ÿ¿Ç‚IIIIIIIIIIIII˃²[9J²ý~–„ýM0A©òe¿Ç~Æ– (dôËi€§䤠ÀåóÅ Áåp`, ç„ ´háLÆ “>É£Îú‘+z¯òP€¯LýR Æª«–B–h’’’’’’’’’’’’’~o ÈþE.öol#˾֜ Ùîàd?CÇxËðÙáâ-@?t²¿åˆíìt.ÆRŠF¼Uò…¨` #1Õ 0!ðT]7ÊäbeŒ@r(ôkžâhÄCòC]ò=E¢$ $ $ $ $ $ $ $ $ $ $ $ $ ,ˆN†ÃþÅÖÅæÅЕýÃ<€Í,{ÚÐQÒÖ%;¼øy5G ^PÈþ¦Oòe#—q²Ó)¡Af™ ƒ¿,"ë&¡S•àt£ê—"„‡ô„• “ºú¼êà¡‹ñšòŃ~àpRx”K¢äœpm”g øØFŽ›t¦ä–qÒK%Á¬¿úÊvÅ›ÚÚuV)‘s"KHHHHHHHHHHHXH `ç dÓ/û…è(±¿åtÞQ¹1àb[ûÞ²ÿé×8•ŽšÏf/ùŒS|ÌÛ›ÅA†qŠyBa¬›‚^ŽðºÀ#\9  P¸ØyÀxúå\?JèàÉ8Úš'ôêÓ8èJpÈ—B¥G%(E8%î;yë I”9ßñ ŽàØÐ*•W²AO²SoùЮ<29'JÑk¢IHHHHHHHHHHX dOšŒí_ÙÀ°ÃþÅNÖËzÚØÑØÂ\G ìfJ¡Oãâ~ÑËBŸ.¯ û;ž4ÈúÊüeé&™,Œ)5Yê€&LžRôôq 4–vÌO“§è“3ƒv¾|á$SmdÉò[Š–@-¥úâߘ •mއLÌ™û?/çÚl•˜3×ÛŽÛ¹e ›[©ŠºÇ†vòMØÕG·I‘¥«8Q& $ $ $ $ $ $ $ $ $ $ ”¬ìq¡ÐcûÊþ_â¥ìs¯ælwìlllJèb»zÙî^Íñ@+Ù´¡eÅö¿Ðð`¬ä[JqLÀ@L`c„LF‚éÀÁ7ž¶h)¡-7F[|E«›õ®ÜxnZóÎ9 ¢±Œ!ù¥æãÕ¥j€”JËQ¥‡#‚&óBYÍUªÚä+Ùa]Z؉ýß·ÏÚ®T‰.i i i`¹ÐÀ]wݵ\Ì3M2i i i i i i`ÅÕÀ!‡§&Àþä0 .›š2†Ø¦Œ:9"ÀCÓfÀ€ÃD&ô€ê…ä‹O†rO9&„/XÊÀ/Ø™E"€ qÉ)Ád™8Õ™¬nH¥ ÐÖÍH ôá@ O2à ?.€’>Æ ‹:sRÁS×¼èW[ôŽJPªB>‰ˆ¸J%6oT Ê·•Pov\e¯p™õ¹}Z(KýóÌ3ÏØzë­gl°]vÙevæ™gZ•*¥,ÅR%$º¤ŒFŒaMš4±ï¾û.”ùzù#¬Åòt¯“Ôž§–-[Ú6Ûl3±jS¦L±ÆÛ˜1c*T.…©&‘IIIIII‹Yƒ ³[9äT‡Ý Äö/u.ì`Ùã^ 63ö·ê´á#´eSôc¨Á“qà¹ÀËÞ¦-yð4êØìùNðó·Ìkˆ9‚%T޵ål`¨AÉMèFisš”èà — ^ÍôôA/y%ËÂ^r S¥¸B´ÚŽ ²;'ªT®dU½¬êåëŸÏ´—GͰ!#§…­аˆ†”Y}ä‘Gì½÷Þ³Ù³gÛÔ©SCYl@÷îÝM±þʼnÿç?ÿi¯½öÚB±ü=ç¹Püâ |³Í6³O?ýÔzõêUPY‹‹²> /¹(²â±¥è Œi¤®e@ ã”À‰‘ i i i i i i`ÅÑ@¥Éžs ` /Šý-Û»˜ý-ûû[rJ¶¿}ŒlwÙû²ÿËü@JqLÀ€aÐöîÝ;̧cÇŽ9ž={ö´Ûo¿=Œ9î¸ãìºë®[`ž¡3ýYêà ¼nݺÆ:ã”·g̘aûï¿XO¬ŸáLJȞx}àT;è ƒl5Ö0ުˡUl-~ûí·¶Ë.»Øšk®i»ï¾»ýøãa:¬QþO4jÔÈþýï\þZYhÍZ‹ùc‹é J›æÌ™cÏ?ÿ|ø[lL³Œ*)!úÅ=Ä/i i i i i i`éi 1Ñ%ËRvòâ¶¿±ÍE±¿5Ox1?ñ„oA(—ÀGéFa I!fLœ P•À!GžÕiÛ‹ºÚÐç߈£À“¨‹BPP~Š˜(¤ªâ¸ÿù§P,¢’;'8‘C J>©bô’òúë¯Û7Þh”7ß|³½úê«ê²ñãLJz¿~ýl·Ýv³qãÆÙ&›lb~ø¡=öØcÁ 1räÈðæ{èСö§?ý)Ь»îºvÇw„±?ýô“U­ZÕ «Y³¦Ýwß}6kÖ,ûóŸÿl¡}ô‘ 6Ìžzê){çwìšk®1x!“=[ýë_ƒSâÎ;ï4ÐÀ÷³Ï> xo£Ï9çàä:òÈ#˜g L– àDbÛÐùçŸæSÊZ|öÙgƒÓ g©§žj¯¼òÊëã“O> N œe¬ ÖPh-‚?ú裭mÛ¶Ápå øÅ_Ö(ÎË/¿<üßèß¿¿½ûî» È*¶f ­ÅüuŒì|€K°ø4ÀwÎT¢røÎZܰ,FLLž<Ë#ÝøÉ. ¿þ:ÓÉ¿î\Dly²cö¿˜hS˜£–éú쩳múOÓç=-Ó³M“KHHHX4PÐþõy-Uû» ùeª By GNn§uJ\8žZhSèIz~Žv<'õ;:àiK¦øª„sT•®‘ @&b¢øœléàJ¿eB9ž œ¼nÒ¤I¸p@äCóæÍ­oß¾áÍvïÞ½C”„hôâhÀ¹@”¹*WæãÎÀh«¯¾ºñÆÂ÷6l"( xûí·á¿þõ¯`Þ}÷Ý¡MÔ7Þ8´õG ‘DOüúë¯!rƒ>œ&“DV 8ÐV^9“gƒ>Í“z‚eC»îºk˜H»víBYÊZÄ$Bçoû›í»ï¾Á¡7l9à€‚£ gëQ¿Á㌻çž{¬V­ZÁIÇÿ3œo8æÞxãp5DäQ1ÕC_þš-k-Æãóu÷¥ú¢i€è/¾Ï¶ÜrËÿaѸ­ˆŠ–p;à€‡íÁ?u'ZuÏãSÉ¿Ëfº³wÿ>ÞØ°[ÛÙg±GúóÈ·©nϘ1ÇÚµ[ÏN?}{ëÚuÃù&5kÖ\Ûzë›}í~Ž’~=hýÍOnT|ð#þÿatpX·h±¦µi³¶GžÕpgï.÷¡ oõÕW±Jþ;2qâtwÌu¶OÜÆ øÈŽ8âqÿ_Ù˜Ë/¿Ì´ÓNkk—^ºKà_žìÜ$²•GzÄ~üäGûuܯ¶‡ËnýçÖù$ Õ°Çksh›‚üp*Ìu­¶Îj Åû‰#Ÿ°‘OŒ´n·t³Ö½Ï|j"…u튇Õ|Q˜‡™õèáOyþ˜õ˜'ŠÊŒpg¾mèk†2AÒ@Ò@Ò@ÒÀbÕ@ÖÎÝ«ûW€í+[›þ`®eqÔuaOŒÅî–½ÍXÆ©Ÿ:ÆVœKB|UƒKc)‘£~¯†zŒWâ›)HEJ MÝ$ÕdÀ#P“’Z¥ÎÍ3Q€º€q…@xñ€†:P’ülØKfDú[®‚AŸPj÷MdsNøV§%Ê¢, zˆA\îøã·[n¹%`}/¾ø¢ºr%o¯/½ôÒÀ«U«Vó9ØPbôj_HÎÌ™3­^½zám7aø]tQ¯Ï ÉVX7l ‡ o¸Œ‡ÿª«®*T*— ”²Y8p:¡£hˆøÉM£Œ)M›6 õç¯EÖ#ÛˆbG?.lXcZ‹Ûo¿½ØäʲÖlZ‹95-•Êĉíä“ON§ÕV[8c´¼‰/JÄDµj•m•UªØ5ðí·“ö7ßüê΀×} Ú}¾Æ+û÷dewMñ(¡©¡Sà¿ÿc'4hh¸{îù(8%˜3ßý7ßüî|Ó?úè'mРŒS¢yó5<âì'{àOÿüçPן»ïþ0T=v«P3;ö× Aý¬³:بQ'ÚWt¦œ#”ñ|5ZÝu+ù6¦±a[ÈС_û÷úª!¢ÚAƒrÇq'ªÊ’-Êo†}c·ïx»Íž6Ûîìtg0ôWwY·l{‹]¼ÚÅÖoƒ~öéCŸçÅï4y$Gßz}í®]î²)ßM±¹3çÚÓÇ?m}ë÷µþ›ô·aW "ž=íYí÷üóèyzyå’Wìšæ×Ø[Üh ¶j`[ôÞÂÆ¿;Þnm{«=Ñû »}‡ÛïÛÚÝf?š7.žs\¯âŸð™/„±Dh0v¦GüäŽæ|IíKìž.÷ØW/}ec^c·µ¿-Ìù#ãö·ÛvûO¸·‰_N´z<`—¯s¹Ý²Ý-a|,úK/½´ÀŶ´ùÇ›o•̯Yƒóœtø÷’€Ç+Ûá$ $ $ $ , DÏ‹bÇ“Áœ["ö·ó…7ö?ÛÿL‘¿qÔB’0aËùy ÉD(myBh«=m€º¢%„Ó8ú帠N?J¢Ÿ:í%hWÿ—º–@mÖ·çã ¼UËH¨3o‚×[o½ðf™mý'cÛ†É «U«r9@C¸üV[möùã$ÀÁ@AÞ" ÄCmJ ·n¸Á:wîrHl½õÖ¶Ã;øò*F2˦M›†·Ø8'0[C^rãx7Ëÿé§?æ~ ºwo¢:th¶c4mZÛ~þyº;âªçäÕ©³Š­»nMwL|ãŽÞ ¯Ciã[ä> 2p”Ê“-:JœíþÚΟ5ØºÞØÕÖð{À˜o¾Gs;ì¥Ã‚!ÿP¯‡ìôoO·}îÚÇúmØÏ6=hS;ùË“í¾î÷Ùû·¿o5}^ãßoǼŒGþÏîÚù®Àwç‹v6ÆN9!ˆÄ1ôâ¡vÂð¬²ëùº¯³íNÙÎïÐØj6¨û=´ŸµÚ·•½tÞKöìéÏZ¯' Ÿßõ÷ÛØ>òí-ÛŸ±½m~øæV­f5{øÀ‡­±ëô g²/iü¨üùÉÖÙ@·n«þòá¶ÆkØÖ¾Mçù¿=oG¿u´ 9gˆUñH•ÓÆf_ùÒž9ù™ùDḗÓ4î /¿µ9à·±Y³\3TØNEC\6ŸÏÙgŸíkä®\¢ßù¦VÒ@Ò@Ò@Ò@E5=•Cö­ìhJÀ¿ƒM¬~pÔÁËv½ìz•౫¡×x·s<áÁ1¡h%_ôÐ0Fmh©ƒŽþ2aÞ/q2„ÇŒä'Ç£5xjŒÆ1!.ÚL€F–’tS”à /¯@&xÑÓoñ¡üL+ý-W<¤Hi ×]«LúoÆ}hyp+n½õVSw­G‚®Œ0ÑEpšûí #!8©‘mü8*˜cœÛD–Nòà0‰|À¸Œ·]` ’Ï"æ-ÿá‹qIÈ惓#ûe0_r»'Ÿ|RbÉ šg™*ˤÊ[‹œÃI“'OÉTuüñú ’'½[‹œÜA"UèãBp´‘“"æsØa‡Í·‘_hÍÆ‰ãµÏSsOåò«E@T´Ì¿crG´lym@ã¬8ÿüŽÁ1!:ÿZµ'Ÿ™KjIþ‡ØjshÝúz_³™g”'<'މ)SfåÈ7®íyx¸Ów\ׯߛÅvB®M¥sçæÁ1qÑE™ïð½öÚ0瘈 Ë“ÓVò\u[ºƒ{µjVoãzö«o]ùöo퀽Yçfa+Æ(ßB‚Ã`ewÎå@„ù!štlœlyâ98øÅG~ÿ:4²:ë×1d”DWL1Á*Uõº¯Q¯†­äù3j®SÓjxnV=2ŽËõwYß>Ë:]Âà2þ|å ÁlÛÿßö¶­;ˆ€i¾ýe´o“á¾;0à¦þ8Õ¾~íë0ç ]wä§XoûõlÄc#Â8äã$!úâå _¶µ7[Ûv»|·0Vø½cKXþ¶×ø76Ð†Ì+qLäƒ8Mù]M4444°x4=]Pö/6/Àsl3 v¶JÙÎô‹^<°Ý©ó¥®1^ uJ@ãé§®±ÈY´3 ^q væ‡sþ>úçƒRÀd5 1‘0 ¤„á\´¥@¯†º?ÑSo†±¢ŸªŽÃã#Þ^Í) >â|Æ:ŒÏ¥k ']•=—† 8܉P¯¾fu«Q¿†>ôð€›üídÛèOY£vB{ƒ=7°ÚM2[@ðx¸×öÙá›Ù°«†ÙJ>‡î·vÎúxöXmíyyGpV” ãÜ¡CÔÇëW¼n›°‰Õöˆ“iž{çÑrŒ4lÛÐÖÙbÀv›¶±ÇÜÚzÂÐÏŸûÜörý¿ÍùÍzÜÓÃÆ¾:ÖÞè÷†qRÉñŸoÚ2M~Â]pl3+ø°Šä”`‹W‚¤¤¤¤Å®Ùß0–œù±ŸßNæ‡Z~€¸øq„œìe¯†68ú £Pâ+à‡”±ú!O[ü(cûß›9™Ô˜oSào)Ž ÝŒ&¬‰ÀŽ:<" ™_üL?ã)B7Ën‹>ñåiI²¤ …~ЪÄa!zõÓùùo¼/A (ÇÄy]ñ‡¯ %çp„2®{w)9&ŠˆJ褤¤¤r4PÑH Ñöoß×§i|÷Þwö£o;iÑ­E !âd™1°‚míÎhg•W®ò9lì'™4pç 'o(™æúî ã‰B‰Ì¨V£šM?ÙæLŸ"3ˆp ‚B0Ýï1n Ÿ_¹±íÉÛ†-!³< åž®÷Ø!/bu[Õµ57\3D€lÞ{sûÅc}pÿ­Ù®ÍBÔDS<î'›àTYŷʯ¹Î9•¤ýßÛÛVÇlòf0^‚ž={ªZ±ògÏ™á'`‚Ñ£G‡¸óƒËa¦zÓ–7Ù‘ÃŽ´Nžä“Üä[ ¹%9pÜÐæÉ1 ËûÓý²¦;7 <0ü?ñÓD._÷r«^§º™ÐÆó_Óaø£ÃÃVYSg…ãH9tƒ=6¸üÔ’á7¢ž:æ)›=}vHLIôæÔÓþvÌ{Ç„‹ ,ús¯;‚Èñå‹®oÏòÍß„„—×ú¢1:]Ø)ä™ú¯¡a­ítÁN!šB,69p{ñœí¸*ü†t'ÑÈgkHì”ÈV¤rÇ™#B=ÿ’½÷žù‡d¾ÇlÓMs\.¸à‚$zÔ¨Qž«¤yŸ*IIII §EÔúhl`ìgln]´ewó£+'xècÛœœ ^ÍÙßýÍÀ žØâðžZÉ÷j°óiÓ'ùÐ0N|½º À¼<`"ŒD¯ÉH1ÐH}º1¯†É‰žñô1É̓ʼ›c¼ÆÑ‡<ÚÔé_Õ)éOÔ´ðW›úºžYú)t€ŸÝ»_(”úƒ>°= íŸ £ÒŸ¤¤¤¤å]ƒ yjòïƒüqØ:‰Éûw›m¶Éò»¶95haœL’Ÿ>NÍÀñà ÀI! Ÿ-8bZ¢'‚SÚû;Ó£ Ä~ä¨P /xÄÉ*9î“dš <$ 7qt°#–Oø(2>8>ˆì`[‡xVTvp ;¶;'ƒ˜ãsœä'ÔjX+D€S?‘ $¯œüÞöSIV[kµx2¦G‘W¬w…u»¥›µÜ»eÊil§øûä¿G>Û7ØJQÉO°úm®—>'"*>sQ! A'QD{°5DóÒ<Ã}üêQ*ušÕ Îwn|Ǿÿè{ÛÓO[yæ”glªûʱ£î™m(¿Œù%lW!æ" ÞL(ñ¥Ÿ«g™ÿâljvìØÑVC nÑ\ä9$III ðü³ÛtëÔ©ÃéßúEb'Ù½ØÕràp M¶4uJ~ C  ô_»@ËxúP§±€ê¢g¬~8%‡6uhâº7C[ri„R~¡$@7/ajkâOÆ€§ DK[7D)CL­d@£±¢—2b5°0N mçÀè—C»´éW4CL‹c †˜Î@%õØ)A{MÏÙ ˆOöˆeÄʃª±¢Ä”åÑ–Òßñ¼Žáäi?M³î·uó(eÜ’¦Ùd“Mìúë¯_Òbÿ¤¤¤?Œ²‰ÍåH­ÍýËþ•ÍmÍ-›œºìmõQÊ>÷jÙÐ*…Çþà£1*ÁÇòi‹7|h%? ŠýÉ7ì щ)B™“Ó¡G˜pÐrÅb\!zxI>JÖ„)EoøÑ†tDDHžWs Òxè«úÛ’Øó‹ÐIIIIIKZ‹1±¤ç–øg4À©K ˆ¦àÔe R¤Ä²ö‰¤ù$ $ ,ïÈFLÄ62¶1ö/ö±ìeìkê²Ï)¡SZµ©âC]c¡èƒN¶7x]àÏ.êôQè-%mõyuAc`Ážy„0)nTsðrT€— „ T§Y”RF~_.èè×Ó–b¼š›ŒnF<¡‘¨sIº xqcŠ„ðj£ùK>4±|èT@8%î;yë EÉžàü£B«øþ×AO²³îi”œPo"MHH¨RÄD…Ô•ˆ“’’’’Vd Èþ–}®vl3ËFÐr>¨½ Zê²ËÕO)ÞØßÔá ç¢]ÈwtñÓxá –bT°3BjÂr*p€&G§€„ËA@[Ž¡Œi¡QZñ„NcèÈŠrÔ+C|x8u€#¼vÞygkÚ´éb¿?E@T´\ìI “’’’’’–š²»°c#û—6—ìcÙ¿´Jll@Ùߨö€xÒ=%¼)ub‡øA+~²¿Åꔺ¼@v¾Ú ”bº@G„ˆ'}~¡à)™œx ½.M Çtq?x.œ&àusºapð¡„Nr(ŸrL¸V*çÆTñ‡í*~ÌWUÏB^•ºã€š«Tµ9•ªÚá{µ´¿Þ>"àÒŸ¤¤¤?Š|ðAÛi§ì‰'ž°;ï¼ÓvØa{å•Wûí/lÄÄbŸHÄpòäYÆ‘¢Åà×_gÚ×~ZÄ’€òdçËœùËL›1qF>z‘ÛðåZZ°´å/­ûNr“’’þ¨È:&J²]GÐéúÝíïH6sˆå{³8d¬Ìâýô@{a  M?O)ê“×…ghÔ'Zúà…#‚<Þñd|©¡q%ÉŸËyÛ JÖ@È'QWÁ!áΈà”ÀAá°ãú+Û^Õ°=Z×¶ñ?OF”_2dˆý÷¿ÿ-Ÿp9 ˜:eŠÝzë­ËÁLÿ˜Süì³ÏlÆŒÆÛæBðå—_Úí·ß^¨k¹Ä=ÿüóÆ[üb0aÂûùçŸí›o¾±©S§#Kø4pá…Úé§ŸnO=õTø>ÛrË-—È)”=·pÀ[ÕªÚZkýÛÖ]÷ «Yó_¶ÞzWÚÿýßsöÅ­W¯‡ýXÎ>Ö Áå¶öÚÿýÐwìx‡=ùäg haÖ¬¹Ö¦Í V«Ö¿üÒ í…¾˜æ§Ÿ¦Ûž{°Úµ/±Æ¯²–-¯µý÷ÈN:iP £^­Ú…V¯^ß0'êýú½ú øÈyö±úõûZݺ—…yÿío/äø—';GUfO›mº °K׸ԾúuÔS¸úáÝÚègF?~ò£Ý´õMvIKlºßóï  zó¶7Û%®ç‰ŸO âß¼öM{ôàGËÊÀãÚLw%HHHHX.5P’ýëwVQûe,6û»€üâo3œ…Œ•©VáG€” ¦Xû1ŽºÐÀW´Ô5VŠ=%ÊœÐÒ§yªÚ²ä3Ž1~²ŠÄy+A¹Ñúd²Ô•9³§D6jâõÏgÚË£fØ‘ÓÂVEX”Å|ÿýöËBÓühV®~<Ù®ºêªáVV¸{ {qÛí¶³#FØá‡–»¿‹úô±aÆ…6N‹i+þÄãÛ|»×üÊ7Ü`·Ýv›vê©öúë¯çw§v‰àû«gÏžvà†låØvÛmmìØ±%r(lQ"&ªU«ìއ*öÃSíÛo'»S ²;¥~µË/ÝöÞû>wTv@e?~Š}ÿýÔÐþÍ·íý÷¿c‚3!ÿ»ýž{>²?ü>Lž¾›o~w¾9úè'mРÑ!ê®yó5ì³Ï~²øÄ>úè‡@W½z—QÅ&L˜æDÔÅÓO }÷Þû‘á|øñÇi†ƒ£FªV¥Š~úÍÊ“=ßD² Žæ<â•#¬~ëú6g& eø7ÇÙ÷dî¯,Êz׳#‡žN8c¡ÁuÈË€ŠB­õjÙ #N°•<ßSeÿ º-ëÚºÛ¬[ÕoQtˈGGØ4ׂ¤¤¤¤åKUª`—iÿòƒ¤«¢ö7?F‹jK6e¾|påBIDÎEtLš_A.êº ú¹h«”u Œ“Cc€6@ 7ÄX@}ðŠ£‹ºxѦ×ÿÒV×B@9&ò‡Tö,˜DK=œþ@Dýü+çÁêÏûïo´ÖoìµÚ—_|ac¿þÚˆfá¬óÃ?ÜÖmÐÀúøÈÃ;̬³ŽtÐA¡Ÿy\Ýu¶Q«V¶í6ÛØàÁƒç›o¼wêØÑš6ibûýéOFCYc®»öÚ0øéMùœ9sìØcŽ <:½ûnæaûŠ+®°#{÷ôíÛµ³—_~9ðfþ;wêæÜ·oßÜ|ŠÍ%G*¿«0×\sM7pjت«®d_yå•n”]nûî³Ý|ÓM6ÙKï¼óNèãó>Â×bË-l‹Í7·X«–-­Å†Ú‹/¾hÆo{uébM7¶£Ž<ÒX;1\zé¥a<ëëñÇ+s QCí¶ß>ð:í´ÓrëýÚ~ýšÛl³Íìî»ï<^{õÕ0gÖ:¼oºñÆœØK.¹Äš­¿¾mß¶í|‘!…沪뢆ëBeŽIªTH¬§sÏ=×# „qÓ§O·Gy$lí¨£ˆQÑÖwܱ·ÏuRVu#ý‡ΰk¯Ý3´qôéÓ)×cܸÓ=¬[èÿê«Iöùç?‡ºþÜíÀ±ÇnÊg<ºg0Ößâ?úh&Z笳:بQ'ÚWt}ðâù4j´º¿9XÉdcö¡ÑP¯Þªm±J 4è »è¢N¡ÎŸ²d爲•oßþÖnÜâFû—GvÜáÑ3&ͰªÕI=e6Å0ôxÀ®nzu ù,2ìªaö‘;^Þ¸æ »­Ým6öÕ±þå>/Ûõ_è_8ó…€ãO•ì==yÔ“!rášfרÈÇG†þb2èDÞ­moµË×¹—þ¾Þ8þ‚ .N‘7Þp#Ê· qÇɵîÀS$H±¹tïÖÍöØsO~’µÚh#¦—`5€ƒõHwRñ&ãŒ3ÎXDn _”ˆ ¸% 1ÚÓáà mµj­œëŸélý8Ë Zओ¶5¢ãÆMvÝW¡yæ™íCD¹$^ÊП~úcî· {÷!ê¡C‡ÆvÚim­K— | Qf˃æS§Î*¶¿áÿÅó4üç?¼öØcƒà¬@ˆœÔË“ M Ïžú¬µÜ»¥áŽ˜mOÜÖ~õ(E6¼ré+6É.'q²ízÙ®6äœ!ah›CÚX£v¬Õ¾­¬ëM]­aۆƖÏyÑz=ÙËŽ~¼}p׆ÐKzÕ r:œÝÁž:æ©à¨/&'þc‡=fíþÚÎNwš5ت͙ÁãŽÙ³§=k]_ÿ÷ÝÿÙÖÇm¶eüÏ“O—̫ٮÍlË£·´¯_ý:ñüö®G³õÖQö—wþžžæÎœk»_µ»EÒÉ>]oìœgûwL›6mÊ“ú’’’’– dwJ²}ºKÕþΓ/?B¹Z̼Æ(›Œ§”À%uÆò‹ÊKI^ 8èÀô Ài,%hx¥}æ—z-üɧ¾²_/Éa¬æìcø1”ªLÄDqjœléÈJ¿…3›Œ¥ø läbÂUVYź¹±ðö±«×kÕªe¹ÑÄ^xœ f÷Ýw_ ùá‡üMÜ(kåoÞ³•‚7À‡zhÈŠÿïÿ»à˜aîüØ·G\æü±¾Ïž9?ò¨£‚ódîÀÄQ0ŸÚµk[OÆÐ–·Ü¼Ûߦ׬YÓN8ñÄàT¶Ð\À'XzèÔ©S¾G”{z4Äj«­ÂòqZ¬±Æ¶­oyØß†Dþà»Ñ¬‘G}4¬úˆÌà:Õû컯]|ñÅ  ŽÁñÃd÷Ýw4C³I‰èabŒÌÿwV¬Y·®m½õÖ¾g¿eÀ×­WÏÆ|õUphôð-ÐsᤊÍeýfÍB“&MB™þ,šøîÃÉóÑGù–„§Ãw¢q\ptE#%DŸÏi†Àä|pœ~Çà˜æ'Ÿ™Kj9qâü¹ØjshÝúzßšÇûóäŸ#m·ÝšÙ”)³B›?×¹&Þô­rIŒy‚š¡ìܹ¹GL|ã‘CC{¯½6ôÿ/ æ¶(OvÌt²;Pˆ˜8虃BTC«­¬vÓÚ¹'’íOßÞj6¨ioßøvˆ^ÀùT_£º­¶ÎjV«a-c«°æ†kZgúøú•¯C4ÂTßó£;`À¯ä¿ƒ@ÛÓÛóÃ7·!g ¹,ŠÉ`L£ölØÕÃì—±¿‡²ØZ1Ú·ÀT[­š ø@G 7ˇýÐI>|¸aœ`nÕªb%T*ËÒ§9M!t[>›s·r8=Q ÙýR™áÎX9AÃ0ëºQV§Npýó¼ó‚±˜`vô_þb×]½}åÎ ò °Ý¢Ø˜Ùv_5³?+ —£„·×ñ:©V­šÍt¹@uwœ8P0Bptñ†TóŽÇšKœþ,7¨–ý¾`mä¯E99ë¹S€õØe¯½ì4O~(`-ù³Å[Øem±w÷î9Çhþ˜Ù³gÏ·æÄcøh†µèë¨^½ºÈºd=æÓWÉοÐ\rƒSe±iàïÿ{H|ù˜oÛiذábã3ZÔˆ Û&ØñðÃûy4Ã_CDxõWõ\ S¦œe—y@2JõÑÖV ¶`ì·ßƶÝv™ûÅ11×ßìo½uf[ ´lϸᆽ¬­GDfœw^ÇP¿1^£Ü}÷æG"NäãàPEd&Ù?!Á£0ÖìêÀ “Ùû·¿o“¾œdÍ\0Û,$”Œáþ}ï·ïûØþ{ámŒç܍Ӵޭ‘ !jbîlAüAÄ#¸8ò=p“1aøÛ¨çF!"Êsž„ô­ëÞ²ižWƒˆœ›´i¸ö¸f[g‹u2¼‹ü Ž =ù8œ%?ûœ÷ô¹5¾úïW!’çJ ŠY{íµƒÓ3îKõ¤¤¤¤eOÙ­%Ù¿>û%a˱‘ÆlQûÛûxøà‡:èùµÊþ`z­@X Tt1Cp2IÁë)@ cœ.&“y:òŠc¡/Jháòå3.–}AùéT×L s*ê-P6[9BŽ =I–1£JQe-е½çvàÁé€Û)ˆ¢à4åšàD x_ãáï$£{ÿý÷­ÐhÈšÿÄ“O†í„ïïÔ±cãÇ|ø¡‡‚lBãÙ/Þ¨Q£æ‡IëÖ­í¡,ý¾MEPh.êKå²£Ur-òÙ·õœD/ôîÝ;Dõüúë¯aíà$ ñ!y+Ž;þø°Uˆ-!…ư„ˆ N ùä“O‚ë÷G„5ÍZ$*ƒäЬQN°W ÁæTèùÿõrö´›Bs)Æ#áNDÄÜrË-FŽœ›$Yeë×âE@T´d}û¾æ¹0^ SÂy@t‰'Wó7óùý$¢$!¦úˆŽèÖí^VûØvÙå.Oªš‰"Ûd“ú¾ínw?=£FàAn úIj¹EÖ>äGíºëÞôè¶LŽŠÍü ~¯^­Ã|Î?ÿ¥0nÔ¨Ÿ¼ÿ'w4gní=’àŽ;Üaàù €ãüôˆ³Ï\’lw ê4«cõZÕ Û.Àýà¹48¹ç[#>îsëvK7ÛåÒ]BŽ~ó>}øS{å’W¬F½!’ãE¿}ë[ûüùÏ­ÍÁm¬›çÝhîNò4¯‚\Ú‚ATðù³ŸþënµnQ89Ø:²oYA~ÏÅã n«º! ƒ-'Mwn¢ˆv(ëÄNfe#U¦ûVá˜ËˆÇFH÷ÛºÛºÛ®kßøgÔðÏ 9ß ûÆfNžéÛ{F‡ïœÐ™þ$ $ $ $ ,ë(Éþõ›À®Æ Ë·ÝÅþF7¥Ê‡ùØò2,Á• ýå a$ß’›ä†%Tuh©ÓÏ$„gL|ѧ±ŒH¥€~ÍS<äüÉaL,ßíéBìRY–PWÿ—º–E–ëëÛóñÜ®²@e??•£}ûö~¼Ü z‹£:vìhvØÁ6vC'S/wP°ÿrß®Á^~Âáðü$9äíòßÏ:+àòǰ=¤C‡ÖÅ÷דpCâ/mÁ›ïS=ñ ‰3×oÚ4DBÜèÆeYÐ×e“ÐóÜsÎ !ÿ¢-4õ¥rÙÑ‘ G{~ €Ä–Å@5ô«N޶ûðÙ•p•·Yí}m­ãI[ÙæC’W¢+Ø» ä!¿Ip¦]s‘ó8N³vî„#2g—]w ë±Ç{lضôÝwßÑ\غ±G q¬ñë!c @IDATfÙ­Åæ²ƒ„X( à%Y*@ÂÞH$ÈwÑâ‚…˜`ÜP7šGŽüÉ“¿V I*Ÿzê3wô®æëË0=òCÐÏés|[Àsn´qÄæÁéÀIô1dÈ—!çÎ òLp2dzώ8~c‘ó¶oŸ4è@ûÓŸ´Wüíüm·½çë…ܜƀÿýïB~ŠinX?ëô_=ßBß¾¯z˜<ªâ¥à¨ƒººu«—,›<‚NžÔóÁý´¡ †;‘î÷`pH´ÿ[{»¿Çý¶rÍ•­ªŸü±f‹5íI?M¤Ëu]¬¾;] å'…lsÂ6ÖxÇÆö@Ïì ?u²Ÿj²ÁžØSyÊšvjj•ý4“:ë×±gN~ÆHŠIÞŠî·v·•ª¬dÅdìpö6jà(ë¿i«V³Z˜rNz4ËÛÐ ß7;]°Sf Šn**‰ö¸­ýmakÆ-mo±ŽÿìhCþ1$8&®÷m6­öiîŸDpT¯S=8)`±¹¾$ÿdÛÊ^Õrög{Žÿ„-’Í›7¤¤jÒ@Ò@Ò@ÒÀ²¤Eòúœ°e‹cèÊþæE=x›Yö44´¡£¤­Kv8xlhð€hÁ ÙßôI>ýŒG.ã(Õ†F¼½Zba…)2L5é˜F7 AºxН&·yB^têO]¼¨gžf¼â@™’KŸÚ¢ sájàoØŸT6oÛÙ{¯ÇžïfÝ.~Û8s;;ï‰}­áºk•©’oÆ}o—¹c¢ýIƒíå+Ú—IKg±ðõr:Ž€W^yå@Îgªíà9ò±†çˆ!ŒúÀchÆÛ0èã­³NomY%ÆIþz*6—²ø¤¾ß_8¹XZCQä¢âµH›uÄ:~@@{˜ü¼1áX/Dèä¯;Ö(sÓ–!Ñ+áÌüû)6—b|Vd<Ñ$…’üñÿ˜\"‚ž?FÇ€¾éÎÏm93hçËN2ÕFòûo3”®å˜8¯ë#¹7Y–ÛÿrHBÿÉn²Ç“Фac„LF‚5IpðÇy3´EK ½h¹1ÚâËXêºY¯æÆsÓšwÎá8e 1˜šW”ª jؾ¾ÂS9m#„óz‘Ái‘+9¡"Ó¿Q£š¥²OtIIIIÐÀ¢DLT@L"ýƒj P$×Té¶“’’–i D/Û±lrljÊb›Zxh°›åˆ]LK¿pØÔÈ„P½|ÉPÎã m¹¶¹ | .T"F\0e¢\L œêLV7¤‰Òhëf¤úp Ð'ð¯†:}ŒAuæ JO]ó¢_mÑ;*A©¸¢÷F¥’&º¤¤¤¤%¬ŠFJˆ~ O+±OHHHHHø5ÝÊ!§’±›Øþ¥Î%»~›9sœSÆþV>øˆmlé¸M?ö7<G?xÙÛ²¿ƪ¤@~¾Ó$tÄ`R01Æ*G€Ú@G’›ÐÑæ4)ÑA — ^ÍôôA/y%ËÂ^r S%i i i i i`yÐÀÂFL,÷–æ˜444444Pš²9Ͱ…e/Šý-Û»˜ý-ûû[rJ¶¿}ŒlwÙû²ÿ˼ÙR"&`ˆ¡¢6}º)M"¦ge,_¼…/h$_<æ+5p>d^C‚@Ëc’Gšš8% £@7ÃDâ:mxk’jCÃH ™V†g¬á) ÊO±ŠR=i i i i`qhàüóÏ·Î;Û½÷Þk\pµk×.8)ï˜Ç∘àÎ1~L%¥ŽäŒeü^õ‰~,ç¸q“ƒ¸éÓ焹ü^²ÿ¨rfOŽ.ëǼ–ÐÌš<+ÐçÓrŒjèóþ?*KýË/'ù«3ÿ¨*(ù¾gºŽ¸$ $ ,q ´]jlsÇuÙÛKÔþ.C~™ ÁPp3\8ôË&7E'‚à¸qÚÔàèøi8ÚñœÔï耧-™â«>ÌQýAVrL¸F*g øØFŽ›’^*¹eœôRI0ëûdW±©­]g• pO¤IIIË¿Æg×^{­ 0ÀvÛm7›={¶uéÒÅn»í6ëׯßb½ÁŠFJˆ^“¸æš7¬oß×ì›o~µ† kYݺ«Gxî»o+;ì°ÇÂq¢5jT³Ê•W²™3çÚôé³ýšc_¼³5j´º~øcá˜Qh&Mšx|òÉqáXÏŸ~šn-[^kS§Î2ú9âsölxÌ |6Ûlm{óÍ£ì»ï¦X¯^ÛK/}¦Õ¶mCûùç鮳 íó϶gžíÇ–V ã9.tæÌ96cÆœÐ9òÄùŽýðîmUîa÷æºÅT–¡Ç{?n#aÏëhíÏl¿åÀãÚ.—ìŽ}óÚ7íÕË^µú­ëÛ!/2íw~`ƒÏlµÖ­eG¿sô|}Ëjcÿý²Gn5kV ë§Üw°°¾Xë/¾x¨uëvo¨CnÊ”Yáÿkó_ÿÊüÀ!qÕUÃìŸÿ|Ñ&g3¬í[oíf[l±Ž!çÑG‡Ûꫯþ_Lœ8Ý.¿¼³xâ6þñ‘qÄãÞ·rpÄáÔ8í´¶v饻äÔvo×{­Í¡mì‰#Ÿ°3~8Ã*gäÍ,deˆ öП²ƒŸ;ØjÔ¯Q&—÷n}ÏÆ¾6ÖfO›m-÷iiÿÏÞ™Z=m|Qi¦ÑÔ IE¦)B¦‡2†GæyŠg|žùñxæñáñ7½’„ iBÆJÑ$%¢4Üÿúìs¾§ß={ï¹Ýj¯ú=­½ÖÞëü~çþÖÚk¯ÝêèVÅâ×øË”_ì©ýž²ÙcgÛ….´šMkZöXÖ„ç8ùl7ߨ%ðgI ­ÓJïUŠþ+@÷•®M»ômêÈëBŸè‹Þ-}<ú©<ºµ¼*(‹®Rhp©¯x©Ý›BŸd=u9!iȉ®CŠšdÒs´“§ ²ŒÔKž ø´eƒú‰?ýÈà‹ep…@9.t½´Û‹g#ä#Œ=.j¾¹ðåùGöQ¡åýöõQsì’Ǿ°»NƉ|äq¢¢Ö °ÏóÑG F fU¡BkÔ¨‘+-)o€U9Óõ˜ ß?,°¿ýí­ pµk×À&OþÙ>ûlFPø+W.6Œ ([ lh­ZÕµéÓçÚøñ?ºgÃ/Ö¼ymÇ©èàíP¥J7 ”÷££ùëàÄ˯. ð¢}§6³%K ì}Wr¦¸‚ ˜É(±ùæÕmøð©nü6ëØqQà‡BX±bù`À%n¾¯ôsa H´§å8&\*.C¢´¯çÆœ¢ K.ÖÛBE)»_½ô•µ»´]0Lìæ sÿ1ddCëÓZ[%_ˆxß\k p¯b,ãÞå˜P­ÚáÞÄH±hÑRÛpÊÁ›è—_£BMŸ#ÏÄsÏ´Í6«fwܱ¿=ÿüh7&ôÓæÞÄxÁstÀϸaíÂðLpÿò ^{m|0Lüï#íw÷D™5+ÕFž›$ðVôçl±ßëE}OIü|óð8nÚ%ÁúŒ)}•«ëu|…¥.·õ+žÃ²V³ ý·äü¯Î·Êß`å*¦he¥Ì>ljg*ùl$çóQ«YÒyÑwÑ}tqÊúƒ@;m”ѹõÇ”þê£Ô« õô Éú€—h(<“}é“›sC>† ˆk€PÌ©g’20ˆ–pÁcÔƒ«{6ä) ÔNhS'šI:âO_øëd`ˆð2üéø'ŽVñª%IyñïÛÊÙbw™Xì/˜‹—.±E¬4,ñ²×íÓ²ª-Y¿¼t`s»è?ŸÛ=gn='JllˆXk$°Ùf›Ùa‡æ Í·6nÜ8÷ øÐÞyçëÑ£Ç*Ÿ£< J›2·ßžŒ(_={v Q«V†ô°ÃZZçÎ-Ü pc0$ÜsÏaUøÂ wu…êõ`8ÜWN9dΣv¶ãŽÛ63G”¬ ¾"zÔQ½ì…¾´#ÜÊš4©é17*ÙØ±?¯ \ß_}Bèsà {Û5×t°›nl×^ûnXA–áa̘ól‹-î+ÚOù.(î{_¿·5ïÜÜ~sE¸Çá=‚g#÷<×oœU­[Õv9ûÀ½X~ûù7Û|çÍíÈg´Š.Ç|ÆÂxÆõgCnbs¾™À­ÜóOˆ).«¾gõ5V«ë»GJu7tßAV¡j…0Nd– ÏuzÎæ}?ÏzÞÓª¹~ì+ÇZyWä¡ñðöÛO_ÿÆxØ“‡s@a•¢™MKå îý2èúAVwëº6{ülûaÌVÛ \Шµe-û3åõ¤óìÔ©y¸?+º‚|×]¸GÓ‡á~Æ=oðÎáþÅããC—.[‡çäàƒŸ3 |¦Å½`Ü{ãã};ÇOnäx8"žxâ3KòÁË£Þ°aî}à ü!“­nÝ*!ïõ×7<†’°K*ú3Ê=XÚû:ƒýyõ¿QÁÛ¡Õ1­‚ tzùs¹ÔßÛ~s¾3Í(ö{ÙÀ=F0``td<ÙðÎUïØ—½¾ Ï^´xaÔjVËÞûç{ÆsÉ[þÖ.¿Jþìw¼©c莱CKöXF=2j¹ç¸Aûaþ> l%‚ÖWíîãì±PïßÏ›‡„g{†‰~ö­j[ì¹Ex¾?}âÓp¯îxúŽÖáïB÷ñýÿŸ©çf3÷réôP'«^/uÔ}®gjò{“—{6˜ rÎãŒOg„ïy0–_Ýcf›¿ncû»QkÒ¤Iþ›Ø$×b]”@©% Eïˆþ‹žŒÎ+Cƒôo¯2öÜÑŽ. ®tnéØ^@4ÔN%uèÔУ/ô©®gC=TÐÏe¨ ?ñ¤žýõ˜` m]™f…˜Õà î²Ýwÿ¯ýÕ_˜~¸S'Û7´z{ÒI/Ù`WðñzØÿ¦á)‰S»vî ѬJ/ùêû 7 ²/¾øÞºvÝÎN8a{ûòËY¡c\iÂÙâÌ3w [I?|+û‹oÉØ{ïF¾:]Ý=OR_ÃAmi»ìRÏð°lâöÖ°}CCïüŸÎAG)o¸GCûÙ½A:\Ý!((x5×´ÃÿïpÛ¶ë¶öùSŸÛWïÜäíÕÈÞu£0ªç(ûîÓïììÏζ®¯wµ°É®H&a_w¹¯Õ´–MpãJ×׺ÚE“.²éO·Q=F´÷n{/ ¨ÇP‚Òà]ð×—þ x!tŸÖÝv>{ç`Ä8ÀäK¿»4ÞO+½ùŒ…ðeß~Óþoí­Û´nÁhÀ*;ðÆ%oØ'í`—ͺ̶Øc ûÌf¤ èÍ+Saö—»ÿ<$:ÞÜÑ:?Ò9(‘x_ü4é'ëìF¨K¾½$SØÞÀi$^Œ”–e›ú½Óî²vöé?µ¶µ 2o²oëß=åqðgÊ‹QmÞWÎ>ëÛ7¾¶ýök<{šúƒ$Æ„ƒz6ô0®]ïF&Þ‰FNÝÃÜ«lùØn»MÂv(úŽ5³ <.¸oÙ²ñôÓŸ‡gïÀ· ψzVB§ôßÛö¾aïRß7³|lïþý];¶ï±vž÷¸×g›èñìáþûÕ·M•ô½lêÞ$ßÇ·uÿ®{0À`dca¾¸æ£p¢é~Mm[ÿnñp`îxc0^ €¼$\™ XáØ(  H6Ú«‘ÕsåšñCóK÷†áÝ (:IÚŒůê&Um+÷ ažÈnuȫи|< <†Â‰nàáÊ+÷_Øzô–+ál½À“‡+µå#õŠŠÑA {™˜Ùp€+ÍÀ;¢àµQ4;°YˆAœ  4÷ Þ(Üy€±Â?àš6æ|›•6â5ƒž %}/5ÝÓ _ã}‡ç+9^Œx^à5Á6b’àý2æÅ1ÖdŸ&Á@Æ}¾Ëy»„çC}Ãýâr’cÉõsq/bÐ"¶F¼Š‚õܨÊo÷†ú6p<›àEL:þ¤ç /©Jþûƒ‡Ç¤w&edTÔ3•ëÙ(jŒŒ^ð%>ÇôÓÃ3Ôá/ÜÈõvŒ\Ô¥õr¬QÊ«%”XÁë½Vmçø–V¥NÂÀXÀQQÔ ŒU¯f(Sú{›ÏXºç .îWØ¢òæ¥oÚG|dœ¦V§Óã‚nˆ&Æ—’@+ï(“É<غ=èC'Ÿw*p ÉËß!¦¼à©÷ fýûï –mEÒ˜tÿuÔÖoåJW$£Û=ðjê3±Qb²|þùŒoáÆ*@|H¹ÿIîy‚Hj¯€PÜGž÷Íhß‚2èÆAöí oƒ— 5€×„å(î{n®ôGP{äsGß7ƒ¾ ž B¸Ox–á9[öU§ Y©Ÿ ¡I¦Îðc@ØÄ=Qô,îÖ}7ó¨8àžLÞg<_=”™3Ïbs3Öw(cX~ôX:xAäz¦DƒTÏÏhQcä7¡JÚ£ zxWU¬ZÑöÙgŸƒ(I/æ£VJÔO£ ä¹x"yhÉ'õoè‰&mÊ“®þíýÄÓ³Ä_åœé²_”œÍBà18MF?5¤ X !PN^^ }I©ôæ>ý E›è1ñÍ$®7‡>—°…ø§Ý^À‡øÑæ_6”ó?xKà=Œþ#L>`§_V³û¨Ì^ìW^y%ì³Cáš8Ñ÷ûª0–¿fÍšùjÞqþòZÓ÷_È5jøžÐ£B;4î¹çkÔ¨‘»Ongo¾ùf û¯ýËn½õÖà>‚­ÓN;Í6ÙdÛk¯½<èÚ”€×¥KA~"äÏ=÷\{àÂÞðäxBcüXë$À³_§N_Á­.&˜}߬ð£> s¿í¶ÛÜý¼«ŸDà®â[meÿ÷ÿç{Þ·pøaÕ¤éÓ§Û¾ûîkoìQëÝ€°xñb{ï½÷줓N²K/½Ô»-<‚Z·nhÝqÇ¡îÎ;ï´3Î8#äŸyæ™À+W_w£6òýÿ©UìÐ)~” T«VÍ#ôÿÞzê©ðÏîŒIÂ\• ˆÒ¦ŒA`víÚÛ½ƒ> C#¾JÖ_þòLˆé@åõ× 'c\ã«®Š1’87ºtÑEo @pÁNx)ìǧÜÏã(|âîܤŸú¾k€`˜ûø*,ÀɇÖî¸âíPÆåÀ²ï¾OO Ê—]ö–]â±0Šdq~žòsØ·>ý£é&#+ûx;°c× v]ÖÍÿœç þ´á½åÁ[O N`8+­önVk‰CÁ²gϞễЯ 1©¬«Œ»91.yìcË81¾ìýepC§S–øI%J1*´± ä3”7¶Šàq?öà£(² €•s”T€m'Á‘þSXY†îT¿Î]Æ÷ýÈïƒ|1Rà*¿õ‘[‡WÌßýôŒ.%ÁYH^¾• ÈæOWrlœFÃ} à¹Ã½Ív"ÞÉû·ÿ‰á¾kÕjã€BŒ–s}õž¸+'l´ió¨…½/Ü›ÄX9õÔÖáÔñïq5¸ð:vß½¡Ç ø,œhCz”‹ƒÒÜ7xmï[¦ðÀsàÇ )eûɽž 2ç{ç{Šú^ŠKïÞ½}Üsl¢ËO b‡þ÷P«·k=›:ljPèñ>ÀH|Õǃ¦&î9êtßñý'Ç’ý³…„­ xbàµA̼‚ŠîפÑçk±Ÿ$à¾G–3܈„cAûËÚñL²½ˆ1çz¦ ‘ýlðŒ5Fx7Fó§öïu¢VFÜÇiàICÿ%åB_.¤ÿzY@iTÖC’Ô©i“> >ÌD3‰ëÕ§ðKËŸþEBf†Eb,ßÀ@˜” uUf€L N‚ÐÁ…míàÓ®:Ú“ z¤øp(ÓG<…Ç›!ù?ýôÓËi×?žìÇŒ‚âmøüóÏ}ïá™òºœùË C­ç¥»Ø´9Ù_AJ*KÝp±Ø_¼R0 l§†åmîïºké>ÅŠ ÃÃ×_íAÑjø‹Âõ¾Ï²’uïÞ=¼Ä³bŒײeË 8¢äm¿ýö¾_ù%_A[jG}tØ£ÇËÿ1Çã+S}_tyw%>Ü»;Ùð~`7«•(<òHp¯îÓ§92|·(&ø®Qö’ã)và±q–Û†Ú·oïJÒ§wÊä}Ã=ƒëõ×_÷—Ök£þýûûJîåîÒû–+oÃýeôÙØû‰{­mÛ¶vÞyçcD‡üEö’`´hÑÂW«;X¯^½Âý½í¶Ûúþþ‡}ý™'÷<†7õEØÃ† s7÷mCºß~û­Ñò/Kƒç;æw%ð˜ÁãAÀ÷ ¨å.»ì¢¦B).ù-›5kVø=Úm·ÝÂw‹qtUBíÚµƒ!wE<'{ì?–p¨Ï{÷n<XÍ% §fp\(1&8ªà¨O¶aà¹p¼{°?‰C=nî\¬$?òH'»øâþÁ=ž¸Ôáù@;FN5=ú¼Pæd ¸Ôzh 7ì¿Çå‚Qâߛζƒ°ªÌ^þ¯}¯yíÚËV@éK4ÿ^G÷ +¯;Ÿµ³µ¿¼=Õ؈2}î¨sSo^K,ˆ·/;x*àqÀV®ýºÚ¦­7 ÏøÉ ¿x°ÂÊîÙAÐÈß:Ü^í÷ªý<ÄL½ÅZŽiicz [1Ú^ÜÖøé Ÿ¸\ñH€?A ?|àÃ8­#(`Äh ÞÞ ¬6³ªK¼‹ÞÇõ6öûoæÆš]]ÙÅeEŠ ›é+i,§rº=Þîñ°*L°B½ƒ]†l €ß Ǿxá•A¾nSº…#(1ž°…`|÷ ½Çc<íÊóø°0@üNÚÀ-¾“ÇÁ…ž½ýrXi‡Ïñ°‘ –(p¿»·ü”™ ±0À°€x¬V#{ÜÝ1r|ôÐG˜¼äÀØ8 ”ûž{“{›{¯ §ü;fú¶‡&Mî ÷/φŠzõª‡íE'ôr¸— æ:nÜ~/ ñ­ƒ3Æ3êŸ~úðóÐC{ï!ø@ƒø*Ûøö¡Û=þÂóÏåqhº{rˆ/ÁQºçׯ>(Œ!ûƒûãñÝÏû¾aûÇó]žÛXÑg;†âŒü8éG›çGõã„mÄ=(ê{9ûÓ³3F>Æ„¾^½zÁøÚ`bƒ`´[ß§ð áYAÉgËI¿sú…6I<“û刧°ÿîþß`ç„7N°GôÈŒ…“bxn²Ÿcîž-ŒlÐêä¿/ÜC¹€@´…‹‘ƒ/ßr,ÚÀîWî‚Ý·…íªv×°°Íù²ý„`´Ü+Ç¿v¼=×ù¹œÏTö³3×yf^9í•Óe“m7±Ó‡Ÿ Ÿ}ûöÍüŽ\y啹¦ë¢ò’ï/¼‹ û¸uˆwšæúô"¿Ð¹Ðѥѫ)Ó¤,ãËÚU—ÄWôvúH‡€^ MxD›:òà*«¯è*MaåøLÏѪĄ ?ÉH3Úè£ ¡á Ÿþ´ÑGš/ýh'U?ÚèO™¼p(+O*Ú2D@Z”É×›={ö«xÑ0ÄPìÇ׿g=/ÛÕ¦a˜ 3âätŽE~mW¯œíÑm€Gß·XºP¾XN&ªW¯¬ÊtV V¨;uâ…÷â°š}ÕUW…DpÈ5ʵkUÈ0‚Ç*6¦_~ù%(›úÞ¯¸â 6wX%­HŽ'TÄuFÅ&X ç~áÅ}àÀ~Nýã¾yD¸ñnÀZ}õÕW'^7”ÙN”4.`üb J À={ß}÷ÙùçŸïÝß;Ä"¸ñÆC{²o¨ˆˆVµaBƒÄ0ÁïÆÖ?æÍ›ó“5ˆ‹‚±„q%û<ðã™Kß{´³¥ùðlâ]Áœ0&÷Lz6ÒL²ÇÈï€øèY5ù;³!J`E% ÃD¹råÐ_:;é~á Å^ôj 08P¦ ]š<)z3}H©Hé.ýi£?@ž6éóÊ Ÿ¾ú/>”Ƀ“Ì{1”Å—rN@±/ Ä@“3•5p1ƒ&}¨'À„KY"•!‰®x€£¾Â—0’õäyËÒ=¡4àl^1Âqÿc€_ o­˜>E5%ÝžQòxèmÁY¸p¡¿H×ͬhÞ|ó;‚–ÚÓ™¤É"â³òÉ%¥ú³ï»J•e/äɾ1% l°AJ1Éu/rÀðºÁ{bë­·V×LJ°M@«ðܳíÚµ ul-aûÛ5"¬à÷å„ñ”ƒqé¹–'Ç*C@²Ž<[4¹pPâ¸)}ÂWšË¨@ðÀdAáò7%É'W_á’¢”¡H£°íàý;Þÿ6ßióp²€p?~äãpD +ɬhúÄ¡jZ–:oíË_Vixó_ñ¾=e” ·’´’”øTU‹h06 Äy MË*»,üÞ(a,à(He¶Q‚6²šýxûǃbÈÞ}b°/^ã&æÎÎ;ïœ1JÐÕë ø/+Ý\úó`xd̳,ЧðPZ5¶Ì¼5ÿtÊw÷GÊKcA¬Éû3y 'y¯%ózn„GJ;A]³!É'ÉOx8¸€\t…§4û>É.gß7”Ù!á ÓÏÇ ¨_Qß‹ú+e‘HÆmàhÛl %09z—mÏù¼ýBJσÊÐ`Ü Iг£ºbï372º·Õ‡T|4Wê0ÜB¬—t¡¸gªÐ³‘ÆÏ#…ø(ýލÓ(•‘@ú=4©ÿòbŠ^LÊnŒ <ðÔüðpQ‡†G^m¤ÔÓ‡6 ‰K8Ô)/ÞðÍÔËqŠ¿êѾ€h¤JÅ|.{û()ILƒC•“Œ”&ÈÈsC?!49¥´‹—&&:Þ~¢C[öøi£¯èxh_•Ú¶×F(Q¼èåŠ1‘ÝsÂãtç%ßÊ•+{„öÁc"›Vqå=öØ#lé8ñÄŸ¿ÿýï¾Wt^ˆ5!šôg‹Ç÷ßoguVˆÿÜsϲ“'O¶{ï½7¬€ÓöÉ'ŸW(õŃ#º%}÷¥5Æ2VP1.åÕW_5ß*ö¢³ZÎý l³Í6Á(ѱcÇà*·ÛɸØÂñ¬o`5–{¶qãÆ®¦žÒŽ'⯑¡´éº ­S‡œNá`?8§?$£B n‰²ÀÊj¾À³Î UYˆñRÚ±Tö­/G÷::¬Äm¿Æ©  š;ÛÄ’[U_Út׋qÄ–`{±%x1!ÎÄé§Ÿ¶s4iÒ$'å‚ .Æ âH`pSߢÆë×M ¬¬ÇÄÚ.5V/ÙÊ‘ XÍ^‘Í…—«NO¹ÚþìºÒŽ%¹2œ=VmßÈ®å(•‘Þ:5Œ =Ù2,í³›Ý?–£’H{L$udtcô_ôcéËè×䥟“‚§2¸*“D‡¼ú‚ОtoêuQúp‘§<@»pI)«Í³ËÌJ˜€'+‰˜POmI:*kÞ…"9hð’´4XÕ©&íÙÌVä– ‘¾\”Ix\‰>rÁŽ1&\"%À>× ¶ç¯hk×½r„Õ¯W|·©Ó¾·¹ab÷ ß±Þ¿ʾyÉ·S$·n”Ø!@@A<_´‚ÅwŠÒ‡±¥‘<@ ;V UNX.»2ãYŽX¬X£$}ß”vðœæA\@÷")÷¨¶#‘ç~ÌGÈî[ÚñDü’%ðGŘ(™óÊa¬lŒ‰•ã{G D D D D D ¬N dŘ8ÌÇò­_èÔèÚ2D$ËÔS–žžŒA›ú¡g“Çð :éÜ´ÐàBÑ‚&©ŒàPÐ_ô”Ò=ú‹.xEJIQ1“q>$m\àɘ rJ[ô \VÑZL‚<y€”~\LHžž }4~ñ') ð"”B!†ÒtÀðPÈâ$<ÚWÔ(A_íý'Èð %0UËwùïÝ_™ñˆ_L×L dß7¥…ŒôÓ½¨T´0˜åc”HÒPߘF HÑcB’ˆi”@”@”@”@”À:/éßèÆhl*'uféÂ+©K_¦}[ò´‰†gC?ÑFÿ&¨|ñÏ¥dÿõW}ÎT„r6&*5`8 Á‘—%DyMN†õ!MâÊè@ ®h‚§>àX|ŽÚÀÕD! GÂðªùH@1&®ëüb&ª4BØ+ÒdÞ †ˆX'"D D D ¬£¼ÿC›öÁ4;üéÃK="ŒK\Þ:ú±Ôb‡((((µQÙúoRÙ—ÒKŠÞŒþŒnŒÇƒðЛР:მì8¤ÊS–^ £{º¢§qÑ·X¡â4p4)ˆ8u¤p «KƒT_& H¤\ ^8LšàÒ¦qªÜâøÓ>¾•\ì¼!J J J J J`Ià®»î ^e'þ(XQ ƳÁå‚gÃÌ™ómúô¹¡öÍ7s|kʆAðÌ3_„ì9çììG厞0€L™òKð†áª«ö°›oîèÇ3·K.éŒ#Ô'ÇÃ6iÓ~±aæÅ!“­®ý‰±‚m ¯¿~¼í¶[}º(Ž·p”ÎvƒH_7’Ìøl†5lßÐÚ]ÖÎ6ÝaSëáÆ˜õÜS£ö–µmlß±VÁe²çµ{Úö'nºÎ=ËúžÕ×H7ÞvcÛ÷ŸûZ÷™ñé {õìWmæè™V}³ê¶Ï?÷±­»lú|pÏ6ô_CƒwÃ{na*óJb6Á½FÝ0È6nµq(÷w9Lý`ªÕo[߯ök‹~]dÍnn?x°­_!õ óÞ­ïÙ'}bs§Íµ¦4µ:-êXyÿ^&Mšd5!J J J J`Ý•ÀâÅÁð-}]Wz/)º³ôcá¡G£s« ù¤þM™z ¹ø/Úà&õvðeC(Šn²^´Å>9Aˆ9Ó•ÖD™D“ÌhSgÃÀIÔɪ¯úH`¤jÔá‚B* r±ü9†/B”@”@”@”@”Àª’û<»wïnG}´o{h¿ªÈ椳2Ähà 1aÂ6f̬PfKdžVÌ´/ô•~¶~\uÕ;¡ý w-d”˜æÊò»ï~Ú®¸b÷àÑÀÖSu_~9+ãaqè¡-‚×Ã{l¶c|ð–ö㿆¾OÍš•l÷&`ËÆÓOnÐ:ðÀ-ÝÍ‘WË3È—Äœ$ôïÖß¶pޗθÔÚø–•—NxÉ*V¯hÇõ=Φ4Ý–.YjŒ½ÀŽ~áhë{F_[´€W ³þÝû[ÃÝZ·iݬEçöÆÅo„zÒf6³¿Íú›tÿAÁè±Ø·¼`@x÷Úw­K.vÉäKŒØ224ݯ©ítæN6yèä@c_ß’R«i-›à%]Ý tѤ‹lúÇÓmTQ¡ý»O¾³!· ±Shá)ÏÉ‹&[Ó¦Mÿ°­Byüˆˆˆˆ(óH/¶K.VÿõÉ #¯6ý;‹?ceÜ%‚¬Å!&­,š Ä鋉KHžÍXZ4ÚÔ©/)päý]@¸©7•e¦­¢_êžøÈ¨A¿ŒEÃrÈ®í=ÁÆ· ¸'+¸e2西ۆ ˜u7ÜÀn>®¹mRƒ¯!B”@”@”Àº#çž{Îð˜xâ‰'|…Q¸˜=1'ø›“}tìÊHF¥M³y;¢eËûC5Æë¯ß+&„ÇÖŒ¾îE€Ç@ü‡$àIqØf›C< ò¯¼2Ööß¿©Í›÷;Å[lQÃ:èYûðÃiª²ûîûÐev~¦L怚¹ÇÄT÷®êñîè×o\! %ñNvXàÛDPþ1ô;§_hš?k¾};ä[k´W#«è1,v8iÛ úÁ‹¢’Hæû6ð¿ü­Õó¨àI±Ð %;6¶_|ë „ãúgå}+ ž Æû”_ÜKœ†{4 |v9û&m¼YÏ ,x<¬_>õjRÎe^Å=BšxLŽÚ{À›c®o±À[²p‰ýðÕÁ¸A|‰ªu«ÚN-v²·ß~û7€…AÄ((((2+txôrô_éä¤üqFÿUg3ú9müa'E禯ôwRÊÒõ)àR'ÚÔ'Xó¥ÿƒˆ?8Ô©]¼E:EB>†‰$˜ˆõ*kàjƒ9“—‹R®„+:|Ê2…ÃD%ú$û©žT<¡%XR¡B…ÌK£*cZ´0Jô¸¨Mr¶dZÞ_¸^5Ç®zf¬Ýr|4N-ÍØ%%°6J`À€®¸ÿd[mµU¡éQ~ðÁƒ'E¡†•(¬¨Çý ž7ܰ·'êCB5WĵsÂÆ¼yWùö”ìo{+£üÏ:g<´•‚-ûí×ÄFûv‡áçÃÄ=÷èA17ôø`{ÆÃw²óÎë xf\wÝ^¡@ú—¿4óú¾Uá§pµk\à–Ä›¹ xŒ ¼ZŸÒ:c¨ï[B6Ûq³Šó­¶i5¡‡­Ì^à=× ['(ï}ãÞ6Òrþî'å<‡ ÜpÀv yHoŒ$°uD€‘¿ïĸ{ÛÛv8eîÛ_0júø¡V·UÝÐuŸ}ö‰˜F D D D ¬£HoåþÍþ0¥\þR:6m©ð(£S–žM?!ø#E=ú7)uj÷lF‡§^tÉC<åÓáŽW‡zÚ¸ Kßb!©Ä…Èà…—$HLêa hÀôÓÅ@³'>õÂ!úO²ùÓ/É_B¡!þñTD’?„ãAýkùæ‡õm¼Ç+ûrz}>u±}ôí"{âB4>‹cÉúåíäƒZØOµïç,ÌŸAÄŒˆˆXÃ%ð¯ýË>ùä“ÌõÌ3Ï„qthçÎWéìJë)!|qûíïÛµ¾ÕX²¤  <)£D²O bª ïˆCùŸõð­ûîû”}þù÷ζ{á®»þbo\5”‰-A;A-wL+ÿ'žø’=ðÀ‡6~ügïpì±Û„ñ\ýÀP7~üloŸN¡bwßBñ䓟…ø”Ï=·ŸŸòN^¼ Ü)¨³U«Ý¼vðt e­-kÙ;¾=%œrá ç. ñ À_êsÆð@ÀJU‚«­œ²ñšÇâ¨å16ˆI¡zâMÌòm+-ia­Žje“Þšds¾žØñN~OxŽüêÛW´M´³ÊMÜØÃ xtTÛ¤šÍýn®-þu±ýúë¯Ö³gO›;7åY¡¾1ˆˆˆX'%—þë’A¯F_ÎÖÝWFÿFàùòþèò¤uÅB>„ ¤L’ ‹©òà’§A¨ž>É‹6õ¥@|H´kœ¢!ãƒhˆ}’ü]Ï–,D.¦ÅIqIdå×O‹©û}µ^â~ª^©‚Íým=;¥SKûÛcìÿ.I+Žvl‹ˆˆX$P»vmãà=Ô¯_ß*W®¬êU’®ŒÇÄß¾0vììø’ •¯¾:Î6uo3=ö@|Ú9cñâ¥öæ›ýÈÎÖÁèÀ©´·õ`|<'0Vg‚ãBû÷Ÿêø Ÿ#¦{ÀÊ®!Ðæ{ïM¶ÿþ÷S^Ù ÄŽà4€úÏ< %'n,ð¸ýûOtïŒön°j×\Ó!xO@|ðêÔ©œ7oâX:ÞØÑzwímCþ9$xAì}ÃÞaëÆý¾•e©Ïó)7¤ù¿#ÃV%‹–Ø“{>Êoò~î¹0ø¦ÁŸc>ñˆ þ…c_°`óf̳î< l÷¨Ù´¦mwÂvvï–÷ZÍÆ5ƒ·†ˆûšßg®î`ĺ ü o}!øæW/}eå\ÖxDàÙñå _úl!à&Gƒnéq6ð²é' ŒéíG¹v«eýë_í–[n±+¯¼RSŒi”@”@”@”À:&ÄI“(hÒÅQt¥³PO=€ö&}Êà‘RÖ%=œzthêáR/È¥Ó&þ´Ó¾ôÂ*2W@IDATK+’!G´=›’Ìrc¤ˆjÐIM–:i2Ð] 4Yæ |á©zò¢E^ Ïf&(¾´‘ç.)eÆÂµù?þØWq&<ï/D©UoËÀçŸnöÜ3S^—3Gßý™õè¶‹Mùñ¥`‰¿Œ.ö}Ó‹HÝMµ]ÓÂq%Úw`oÞØVèkDúõ×_‡`b§œrJ‘ãÅ]›=ã½Q¤ŒÊzøqã¬aÆ~â÷&×ö²6æ|î³ÇÜWŽ÷-v“'sªA]›:uª-l²²6×Õ9žÁîͰýöËPçÏŸï«öËNžxöÙg­k×®a¨~ø¡hÜeuÛ·WÌ ß»Cyæž-Î8ã _ÉþÂöp† ŒÖ ¬¨Ç³Gé—ArÒ(¡vy3$q1 `4P_¥ôÑ©J©K%(×®]9%ÈsÜ(F ÉšI£íëó7Æy¢YZÞ¡³pÌ&[3d” £€± PšæI]è—e”P=Û=’™ µÄ›ü‚ÂóI>2|„·#ðÒñ%À'¨æA÷d¯÷šÝ½ÅÝáÂkã°ÿ;,°úàƒìÐCÍfËQQQQëÒ íþ$€46R@ú2ú·ôßÒèßôIö=hKW§½(þ²Hÿg\ɱˆ6ôŠ„|RÉS !08.-•(/Ah¢¡¾ší\Lž mêé—¤MíÂ)‘ÜÊáÒ*„U²Œx—u,ço%*øöŽ`¤ð—*òn–+>Ë0—Ï¡Pxâ‰Ö¤qckß®]ˆfÖ=÷ÜcÍü´æ[niÿyä‘ÐñÎ;ï´SO9ÅZ¶ha;¶níØžµ­Z¶´Í›» ñ»‡¸!çžsŽ5nÔȃ§ý%¬‡†ôÇý÷ÝgÛ´je;ì°ƒM{&Ô¾?t¨zÈ!AQeõ‰ýºüqh?~¼uÜ{o«·ùæîVü7Û§cÇPÿµŸ?eòd_Á[bÛn»­éŠ|xÀÍç^üî»ï¬ÓÁ[#4xÆé§»;.4d)ú•ԑɯŒþŽ ¬¨þΞä1  ›,«¾PšaB†’„eLÐd NÂÉfNø —võg2´é.íâ¯~š´7ª|Qüi‹P‚ \’Ák"ÞúnœàD(HùvŠÂ Ž:›9s¦M˜8Ñοà{ÿý÷ÝÍw¡}úé§öîÀöBïÞ íÚ tÍsƒ/Ø#ÜhÀöšÛn»Í†:>Æ„‡z(|È£Þ³-çs_>à€¬{·nbåûœGø±t÷Y¿×^3Žô»æê«m }·ì{½Àu¿;í ¿ÐÇt+—cÝíÿW÷˜9kV 7וÖy¾R±åqw¥æJë÷ÞË(™Æ1S&%ð°¼ê¹Áášk® ã{øá‡÷ã'L°Vn¼9j”3Æjº+?Ç?ží†„Ûn½5àæs/^|ÑE¶—µ ƒË½îQÜÿýa Ég¾Uìœsϵ“Ü8@w’? Üû‡~¸é>Ã+â7¸a°{ذp/ÿüóϡϳgJq÷âåW\a5²‡|ŽÖ ¬ŒÇÄÚ#…ug&5×°ŠiÍ:¹ÕHu1ˆˆˆX·$XlGòÑ¥SgãÒÿÏпş´DÀP@#¸"N€ê5YµS&Ϩ>pÃÁGödo½õÖÖ±cGûØôÚ´iã®ÈºíüÆqwV²ÏuÅžø*u. ÏQ¾Â¾é¦›Úž:—ù\x±®lI€ïo‰¶»íÖÔï? V÷Þ{¯xÒIد­m·ÝvaïöOí´Ó‚÷Û2Þ|óͰ½cÇw d«'PW§â<÷˜èÛ·¯]áîðÖ^ àmÃqŽlééÒ¥‹IøYˆ5rˆ–»üò˃Á«Q£Fy €?»yÌ”ÚîÝÀ½ˆ‡Æ„佨û…-ňÀ{¨(À[‚x,×_w{‚X)Ê®&úvöþ'/Å'Y•£Î×C"oUŽ!ÒŠˆˆˆˆˆX½H/ˆ¡¤IQ#•ž¼ªõoÙVFÿÖ8¡%ý¿X!b(( $ÂLžj°É¾ÔƒK*O Úé ~Ò¨A0)ƒ—ì—kàãu±Ìß i€¯ÆÇ’{cô˜xòKƒ„ ìœW‡Û»ô)1Æ+~Ý.¹Äî¸ýö x±ïcŠÝ–~¬áqüMN~ÉïOùnS¥’À™$fA+opÏ Ì}÷ÛÏZ¹’œí{ö·Új+›1cFNúTÞy×]alÿsÿ“O>9xt‰Öh ` ;îØcCPL<®¼êª`Ð:¤sgëóòËÖƒ®ºÿhWžxlÓ¸öïÞ=ŸÞŽ;î¸p/^â÷)6 úÊ–G|ëQq€wñV0H¼á[œØBðÕeSÖÅеá†fˆwÛƒV%¬¨Çý"D D D D D D ¬Õ@ÿE‡F—F¦¬:taôfÚÉsl¨ôqéìê®tsÊè׸Ÿ/;oœÚÀ ZÙtÄ“zéôà –à@\J?øÊ3pÚÀSÏ` j?9YñUðȃ#c eµ“Êh‘ÌSGúÐPYôÌ™3çEÊ'`"îÒÙð¹Ç? Ðb³CnaÏ_ÑÖ®{å?¥`“bE2uÚ÷ö/7Lì~á;6øÎ݋ť‘Õdâ8$!W]²½¸<ÁYýÆÀ1íâºàFO9¹‡¿(Zl-a;Éh>ð€±×¿Wz¥»¨>±~Í•qTˆ A<A®:µå“&ïãì{ï R-Œl§vZ8ý¥~ƒFPÖŽ¨óÂ"âžG+¶-/ÁƒÙöÛo¿\¿#Éà‚œÔµk×€GÀÜ]vÙe¹>Tœï§ó°¥ìïn”ú#{kEŒä˜"í((((((?Gxfò.¢˜Ÿ6×ɹN÷Kôm¥Ÿ¼êIчI“ÆpÔdz!ŸlGW;):64’ytoð”Â'Ù‡zÊÉzêú 2‰nÈE˜j@ÉI$C>Y¦&oò€&›*-ûÔ¤ÄZä#¨À>t±ê¬§}àž‡|'Gæ–ÁðPÈâ$<Ú³EÕåC œ¤‘)i” Õð|áˆ#Ž+Þœö±•{ZÜí«àÖ^ ðÞ4J0Ó\u¥‘@òÞξó1JÀ‹x*x_ÜpãáÓdõ,‰¡lJ`–ŸÞƒ‡€ñ;#èŠÌdEŒÚÖ±"übŸ((((((2+é¿èÃè»è¾œtlÊIÝã@õQÒ§Eƒ¦¤þMY£hÈžôuµ%õú ù&’†ÁæÔ3ID+9D=¸°g3“!¨]“¤Ì%šI:âO?ø£Â3"Òyú·$q´Š#”$ظ®ó‹®¬¥°I×ãi2ïÍùĘ(‰çêngož=W÷0"ÿ(ൃçN„²/NXä^wÜqGðãT”»ï¾;x7¬ÊÑËÈPÚtUŽ!ÒŠˆˆˆˆˆX½Ð6bú/Zú¯ Ò¿½*l» ]\ôk@ú{ª´Œ†Ú©§:5ôè }êÄϳ¡]ýœv€<üÄ“zòÐá’|R5YŸRü³ª !"Â01 AjPš,8ä8yx ‡:õ#}Úú§]<Ä#„¾ Úèžh{6# $ê#ä!›Wµ#nNà´p|¨»QàIŒ™ÔëÒí[7\vŠA,"J”@”@”À/<&8 ¶—*åw’-x_ðã‰/+=Ïè1±Ò"Œ¢¢¢¢¢Öx ¤=r¥ßJ&¤+«:òÔKw¦|éõJ©G¯_ýÑÅE“”øpÅ_øàÐGepÉS¯:Ú‹…| 0O’A€:`¢Á@S}ÔqQf€8°„¤I‘RŽhy6<¹¨> ÐÚñO•âg‰¸ó´TÐÈ#B”@”@”À:,Nñ!6 qn€ûï¿ßvÚi'3fL8¡eU‰¦´žÂ_Uü#((((((Õ/b‘9Hÿ /Kÿ¥>©ÿ’—A€Tº³g3:¶h »“G¯Vφ<) þ¢¥¾ðW<)'õoÚ(ÓH¶¥jŸBJT-— ’ÅL ¡Ç@“eI_€¼­ ‚Ÿ¬Mê”'EhX|È ÔžäWˆÜÊ!QÅ4J J J J`UH`¡QÌ©xM*Uª²éU¯tº¢+Í8ˆˆˆˆˆˆ(‹(QÿõA£Gç«CO4W‰þæ-ù¤ Aõ…Ò|=&4HŒ aR À‘¡#iEÑ hÓÄ=Œ Œ+IW1#¨ã]ú‚K¾Jµ\µ‹ÏRÜ^ò €YµJï!J J J J J x T¬XÑh_~ù¥=à'ù°uãšk® §t´jÕªøÎ¥l•DiÓR²‰èQQQQQQeX‰m¢Ò¿Ù^A^:°¶[  hC/W‹ü:3 EéóàC“ éߤԤ—žN½ôñ¢.›?uEÈ%Ä5R ’~J©Oò§,ÚÐ4¦T©˜ÏlÅ>ªˆÂ”18 |˜©\®ä€è— Zâé ÚУ ððˆ?Ïf¤þàƒ,-ë1&¾ùæ«V­šÕ©S'5âR~âá¥Ç¸‡miÁÒè3¤ž_BY—{O?±åeÁ‹¢”l"z”@”@”@”Àj@ô˜X B,£¢¢¢¢ʘÒIÝýýXú2ú5yéç¤à© ®ÊäÑ!¯¾à´'Ý›z]ÔÁŸ>\äi#Ð.\RÊjóìò ÃÀò-Ëj` ˜¨âÔËPA½ÁT ^|ñECÙ:÷Üsó¦NŸ:i˜@ñ»í¶Ûì‘GÉ›fDŒÀ(ùÏþÓz÷îm»ï¾{0 ´=÷ÜsF\€=öØÃ<ð@ãèÇÑ£GÛ6Ûlc=ôõèÑÃî¿ÿþÐ.)þûßÿÊݺu³'žx"x*Q~ê©§‚¡bÈ!V³fÍ@g‡v°=÷ÜÓÚµkgýë_A pÖYgm‚ý¸Ç'L˜`ûï¿à?ÆA„q¾ýöÛêb»í¶›uéÒÅj×®mŸ~ú©íºë®vï½÷Gyd˜KÙ3%ÍG¸'žx¢1> 5jÔPõ ¥«ów`£6²³Ï>Û^~ùe;çœsVhüe©Sô˜(KßFK”@”@”@”@”Àj•€ôoéç*£þQÇEÝ  Èø 2ú6uà’—^®vRÑFÿ&¨|.ʹôq¯ zê¯úN5`R@ÆR@eYX(3Ê tƒôUÉS],MVö‹”kC¿XFÜ(}Õô´–_,r±ì¥«¡ç¹¥¯fž²¼ˆ†¿•_[ûµ½_¼ýwúñÇ ~øá‡p7®À#¨/w½öÚk®¬^3fLÁ»ï¾[à+µ¥ȯL-øqî‚ï}úõšJEä…a…Ëß~?¯à”»F¨9g:xðàWØ vÚi§‚ºuëøÊcÁÎ;ï\àŠP+z¡¯4œzꩾ’[à XÁäÉ“ \Á*ðm)•+W.8þøãÞí·ß^à«–®¸²—áwà 7¸¦À•´‚ýöÛ¯à駟Ήøúêp¯WÒ ¶ÜrËPÏÀ‰%-7ö¸GAÁܹs3M~œc°É&›Ìœ93äÝ«¢ B… î QàÆ‰7¬…úìùóç¸1±à¨£Ž*p/ŒBÍçw^Á<©ã™vL¹¸L¯^½Í$ÏÓ1Çø1>ArÜŸþyo MEñ+n>¢™+-ë¿nd*pƒS" ܰYàÑ\ÓÈÔñ;Ÿë÷Ÿ¿ úAzÏ=÷dÊôI¶­Ž¼{Í„9”6ÍL:>—ôφ<ö.p’)yp‹–âXøà;á„ìÃ?´òåËφ+®¸"¬ÐΞ=Ûü¥>x2œþùÖ§O»é¦›Ì_ í®»î îíÐÀõܦЗ•LháýæÌÊ2«µðÍ…ÿÎ;ïØÉ'ŸV‡™«Ç®ÚŽ;îhmÛ¶µ#F„UcÚ"D H®´›×¶ÕáQ¶R¹±Áž}öYs#\fË÷èõ×_P7ÜpC»ä’KBžUx¼ðbÀSï…âÀ :à]xá…Á«¢¸>jƒ¾&Büž-òÛH®¹æs ½ùæ›Á›H}ŠJ‹šOQøÔ—õß$ RêH©G ÆH9ÙN›ú‚/úð¤^å%^,Û€r4jÔ¨0Ȥ›w>£^ÌV—“>ªÝÆÁ(Ñe·eûÑ1J¾kÝ ©ofÌ3ú”¸‡³WÝW‘cŒ{ò¹0,°ïýÁ´_~ùÅ^yå•åHâ"óÍ7[¿~ý ÍW®Ã…¡%«Q£FáBÑŠÂÏ&Œò?Æ€û{v<€lüX^7%@l î©âÀ=o–‰ 6ØÀÜ“"ƒŠASFM¥4ÞyçvÁ„-(Åwß}w‰<’ý3 JÈð›ðè£C1(à+Ã]ÙjÁV~/ØÆ‘lËEº¨ùäÂMÖ•å߶ȼúê«ÁH‰q"­:9üµ"¯˜¥M׊ÉÇID D D D D D $%­ÿ&•:)½¤èÍèÏèÆ‹üz³ZèÙª>¸ÉþàCª¹ÇDýcÛz•Jô˜E @¡I¾ð+ ‘añì¨U«V¸n¹å–€ŸüðíÁ£á¤“NÊó£ }<Ê…/<¥Ä£ «Ö•*áa!J`y l»í¶vë­·j 8$²­¶b×—Ù”)SÂ=ŽÇR£FBmÚ´±k¯½6S&3}úôàÑCüðd8úè£ á% ï²é$Û‹Ê¿ôÒK¡©k׮ᤠ—Äná™ó­v饗ðÚðmÖ¸qã¢ÈåœO‘ȉ†²ü;€ ÞRˆø>K2B%¦µFe£ÇÄõuÅÁF D D D D ü!ÀsÝ!¨tžJ'–>MYú2©ôo)ÁèßäÁ”¢SC“²ôip“ôÈÒÕÁU»ÚTÖÄ_íÔ‹'´r‚:çlLT ‚ –‹<“ ] •j àgÒôÓäÕÇ«PHÁI OmІW𸠤@x¾L‚‚^®ˆQ‚ -öãB9•D—¶‡ôˆ]7^‡ïR7”mS×áÚ¹nøÂè³²À -«¶ËÛ{ï½3§à^Žøž÷pj€Ç™.õâÙºuë°ícÁ‚×ck‹ÍY³fUpèâ©qì±Çf\ïE;¦Q’§¼àÝã1‚Wž=(±l!JGõ²Åèºë®KV/—æ™g‚Ã_|alñ¸æ±Q–Ã[Ð%€$|FŽi¿"l7ɦMF‹ÕuúÄêú@}ô‘±­ìâ‹/FšÒu³eYVË¥õ”~YOW”@”@”@”@”@”@é%À;­ºoQú/õRò”ÿ3õoñÔ8K6ÚŠ)üE"xLd$€xPøÓõô§Muž †R|ÀA¢ÐÓÀI³L,2ž ¸¸ P-ñR¹Xþé3_½[ÙNåðÀ’¥ö”Ðl–¸U"½çÈä)ñò‡³ŒKž}GÌ2®W?žp9Éceí·¸ùæ›ÏN<¥qÒ€¿ 'àaÁ ɽõlÝà´Žeµ—Õj€º\øŽtÄHA¼ úì²Ë.Á[#tŽQY`휴¡û‡ãB¹7³¡{÷îaËF/à?ÿùOx&Qv¹8©Ã† ÁANÔ N Ë =Ñ íÛ·¯ºJ“}Ùö„ñ„Cð…?@Œ <18vô€°‹.ºÈ¶ßžx¿)c`’Û¦€\ó +ù±º~6FQ¾K¶œñý¬­°¢k«<â¼¢¢¢¢¢ÖE ¤ßóÒ]>«UÿÎâ/;B‰_F’„À%Ã}ðZÀ€ÀÄ%$Ï:úÒ.$MèPh tåëO»Æ©~à²y [íâ®ò ]ièãå`¬Z• £…UɤP¸µl—®zzœ]xp{ü\ÃSƒÄaî)!À ÑÙ=%ã§ýbÝýÌú^×AU+•8c¶x@ cÆmÁu%* Ùœ¢ð-Z”Ù_¶qˆG6íXŽHJ/‚XV©B°á«Z«ëw€maüÖä³ãõ×_Ïp’ógìlI•-4AC1€®N`»ßŠ'Vç˜#ï((((((U#Þ_xa뻟Dv˜SýÆ/tg)üèÃÊ“´ ½Z@»ôwò\Ò¯Oç©K:x1ã\€ÞÀôÚÆ ýŸ6å©g”©‡v‘ñ’ I@ŒDXe1SЗK†ð%›.eà28Рž~š¬&.4$$xÒ&>äéC;ý…ïÙ€CäFêË•åÀ— veaóZí¶Þƒ±Ølí©ç9}#Dªž4e”hºÙò^#+;ŽØ?J J J J`ÕK@F†Ò¦«~$‘b”@”@”@”@”@”Àj–€ô_†!£€tdé×b.Ý:éÏà¡cË`=Ñ—.à´ƒ'ý[v¤þÏx¸èK*ÑöªÜm@È…Q‰¨& ƒ •×D\²ž>É‹6h’ÒG >¤Ú5NÑ€>8¢!þô!/þî ‹µ.:¤ñÚ;¹8³(((u\Ñcb¿âô£¢¢¢¢\‰íëè¿èºè¼Ò¥Éc0 @g–> etjRʺ¤‡S/zžÍàR/È¥Ó¤þ _úIO'žÅ‚\„3оç5$ñ$3ê¡Ë³ëq78¢ãÙ§mꉕá_æOåðùEˆˆˆˆˆÈ)ÒzJ?'±X%%%%%%°&K ýá‘¥ÓöGèßÒå‘3´«L^t=!J J J J J`Í’@i=%„¿fÍ2Ž6J J J J J J 8 ¤·r ç«ÿJ?†¬ôhòèßI=¹$ý:+¢'õð$Æ`R@D¶¡PÇ`aFª:„F¡z&®¼úª|À§> É/@}h‡W.þÔ1·ò¸½$,L^µvÁ;£·Ys§õã@ýˆÐÜÇ….;FtÓìÌý7[»g%%%°J`E=&è!J J J J J J`íÀúë£öfô_tjôf¶oÒ‘IÑ¥s£_k‹‡g3xÔÒ¿Ñ“@Z0…OÒ!Á‹ý[|À•þõ׸èS"äc˜€ 3@•©Ó¤H³ñ)kòð# ኞp¼)ÓFaðê/¤Â?ð³…ìUk`”8f·Áø²Ô¥PÀ?RÿPêUöéßÖ{âÚ%„8›(((µTò€(mº–Š#N+J J J J J`”@Úc— M ¨ËÖÏ©“¡ýYº1yÂtwÑ¥^º6ô¨§ øñ' ðE[õ¢Žø‹F¡4_ÄM^ Sµ©OCR h¡/ø „TyÏfŒ ´—ì­l>ðG ÚâÙ ÀWãËÍL É –¥Ì7ß|cÕªU³:uê¬Ð°–,YŒ=Æ=lK –7mH=¿„²®tý‰-/ Þ+Ä,vŠˆˆˆøS%=&þTqGfQQQQQk’Ðѡѥѣ)«=½Yº8žÒÇ¥³«8\€tu•ѯ÷ ý:à%ƒƒôxÑéôà ( D\J?øªƒy1”!:Mœ¼€:|€Ò‡‹:ÊÉ1©Ý«3ÂOÑU ƨöÀ«¬&~ûí7Ã8ѲeKÛtÓM™g©`ñ’7>˜±Ãyõ›ö°Õ#/ä•Dúý÷ßí®»î²îÝ»[ùòɯu% ÇîQ¥À¯¿þj|ðm¼ñÆá9K»ÂÙÄ üYHýFÖ¯_ߪV­¨þüóÏ6cÆŒB¶ÜrKS?ÚgΜiÔ_ýµq¯'ccݺuC[²¾^½zÁ©ºï¿ÿÞæÌ™£bH˹«^³4mVÉ«T©h éÃ? 4Ê•+gIzŒaÚ´iÖ¸qc¡†´¤ù€´ÀO%š={v »xñâBü [ò8p rÊ)+Ð;w—qãÆYÆ ùµeá±Ç <‘Óš ¥õ”þš<ç8ö((((((ÂHë´Ò{•J÷ÝWº6íèÄuäu¥^~Sú7 šômðè§vò¼DÉ«‚²è*•¯¾â¥vïú$ë©Ë ùj‹0…  I&0O¶“§ 2}˜,õ„gCß\oê'þô#€/”Á><°ê¬—v{ñlÙ ÀW_}ÒÒ'ˆ)ÁöCg¦¾—Pz:¥°¬¼žµiRÅãPðu•n¾é&Ûgß}­mÛ¶Ev~¥OŸ ,œqæ™¶hÑ"[0~H£a¢H‘ņ?HlgºãŽ;¬ÏË/ÛníÚÙœŸ~²ÉS¦ØOVÙ ÿt~Œ¿õ;X;û«ýú©K yØá‡[íZµìóÏ?·Û´ óÄÀyܱÇÚˆ?Îà’)i>àŒ1Âþí²Úןï~øÁ®¿áªsÂ1GmÿuÊ“ )ù[ñ•ßUü¦ïæ¿Aï `Ý.¹Ä¼ûîr¤ùŽùM]ÓL,zL,÷õÆŠ(((((uUÒÑÑwÑ}”;騔i§ 5[[0è¯>J½ªPOÑ ‘< }~\¢¡ÏÆŽ¢àhWò¹^~é%ëýâ‹…p‡f9ÄF~ñ…1¾J•*2x~Ü}÷ÝaÜ£F²ƒ:(&ŠâA}QóQ¼204Tár ×3xšVú¹‘d›V­¬Ï+¯XM7Äœzê©6ÚÇ1ƒÍ³Ï>[è·b{7®|œ6–àqÁùçÛo¼î;]Æ;ÝyçöåèÑ6|øp«Q£†aêСCÎ1ð;P»víÔx}ܹà¡´žÏ?Ÿ«i«“DiÓ5n¢qÀQQQQQQEJ ± ýÕýW†éßôÇ—vtap¥sKÇöª¢¡v*©C§†}¡Op=[Hÿ—¡]~âI=yèpI>©š¬O)þYÕ…Ša˜ÀÐ )S¯É*Ï ÀÈÃK8Ô©yèk°ô!O»xˆ/F}´Ñ<Ñöl i’?å2 Íš5 +•(S¥ñšPŒ ?|$%H_æÞHÇô¥feÊ­·¨\bŒ‰·ß~;¬O˜8Ñzöìiï¿ÿ¾]â+“ºBÖÕ :u²/\Yªé+¶cÇŽµgžyÆn»õV{É•¾\{­};y²ÝvÛm¿\âY‘½Ï o¾õ–Í÷ÕÓƒ<0¬H/t÷sèô•c\î;;mV•1`°z|Å•W«¯#]ñ)ÎS#0‹Q  Ð·nÝ:c” I ¡¡ðs?rŸç…íÀÇ~¿ÞrË-!¿aõêvþ©­R¯¾újðjï^ xJ`˜(fÍš•¡Þ¹çžïâú¨í9§ä‘G%¼Ÿó=²K—ÐÄ6’Ü8X©re{ÇŸÕýù( Ššú5oÞܺù–+Œ¿/\ªs=ƒ=\NõÜÛä3÷ÔØh£‚ÜŽpï—ýÙ?ß ü` IþV`àÄðÜÿýÁIŒ'xbx¶çÍ~KÞsï‘gÆ=nxÁ0‘k ü<üÈ#aË5iCR žþ`K ÍF%«×Ø|ô˜Xc¿º8ð(((((U&ô–bé·Ò£IéÊj§Ž<õÒ©ÿÿÙ;x»‹2ýOzƒPB Ù$”Ћô.AqÕ•²€°€°"VQWVù¨€"а*MPš» FŠ‚°² ª´ Ò¤ZBIôÿ|çœçdîÉ©7¹¹çÜû¼»sgæ·ÍsÈõ¾ï™ßü”׫‡O戼ôÉÅe“žû)DÈÊ¿ä‘AGsdÃO¹>k©‘ÂÎsCÌUHPaã ›Ò‘ј „ŒHÚ=8ž” (qÐÎKOHP”8`ÇB²…Ýç_žЩE<»ýHL¾ÿèßw¿ý*&_Gç›^N2Ü¿¾)jÑ}ñ›ÐI–žŸ4iRJþFÄd:5²VL ÿ“Šõ'LHß ó î‘GµÌsóµ|yÍ€À;ñßÕÀAƒj‚±Uüï˜SULßôK˜ª´*ÓêY;÷œsÂg?÷¹°aLä9ñsÆ~‘^¥>ׯ´^‰Çïþm}.2¸ƒ‚¢ž ÈSX3žØr«­§(`Ô¢jû‘ÎðáÃÃvÛm§iêkýÔžŠÅ’o¼1üìg? 7ýñû1j§@ŽùÔ§Rü‡rHøFú‰¨Z üþ€vÚyçÔç?fΜÖŒESŘ¯µã¸Ù“’oǽ:f#`Œ€0F 2‹ ÷¢)ÿ%ç…”ÿÂÏó_Æ$|ê•;GV)Ç– rwÆäÕÒ‰Ã4¦‡¤Ï:céâ_<|1§‰XcŽ”¯8ÙÏF r bA¦žÑ:(cÍ ]ˆ±RQA@ä›AWr²Ã±*>²‡%Àð‹=t°GŸäZýQŽÙ³g‡‡z(†[(Jpi^3”Ÿ˜¸:>¶Á ‰ßÜÇ}qÀÿÇvÝýñÄFã-Ö\÷ÄEžÛ¾2~;úñ˜|q‚ák_ûZ‡°¸KÞQÿþïaÜ?ýSX5~«\‹æÇû&d`Œ‰ §% !ñ›_Ñx\ÏŒÇ9Hþ~·ó<ù•ñ¹¾A5FØ,>nÀ½ 9q9$ÿæ&Nœ˜ØOÅÇ-H`·Ø|óRÑŒ…÷n»møz<­“ÓôéÓÃ>Ήf(éå$·jÄ Œr;Õdsþõñ1 ˆÇ™¸SáñÇO üèÑ£Ó©†/ÆGžô&î±à~‹qãÆ%J?*í§’\ÎkäßàÆû6ŒÊOMLŒ±p_G-â4Àø(—(ý(žÐàß>Ä#+ú½ÝH ²¥žûlŠÿã-V[÷>1ÑÖŸƒ7FÀ#°¢P²]åÉäÈPž'“#KH#_fžòå8Lsx¬!Ç¢§VÀi åÚq˜øÌe>Ïÿ‘‘OÆPn·À©ð“ꆴ L=¸‚ðÔâ0Ù ‡ @䱋>k²'¿ô²™ËFv}ÿºIáV$]zÉI‰f‹ì‡;&¸Ë’ÄAñ. úÝqT:%qÀ#Ó|¿íG†}iÛL€¡S‹¸AŸçò¿uòÉé˜8ÇÀ!ŽŽëÛMžç4‰ É’’¢\&÷Ásä<›Î3úë¾%^\¯]ï§ `qNü¦˜oeU¼©&o¾(G`“M6IoÝøI¼…DwV|\€BwDäÄ}ÇsLøn¼o¢Mž<9`à„нÑ-üêW¿ª¥Òé5ì^~¦Ü*Ôñ¸I9=ïex,-šyü«ÜFµyµƒü»Ôï¿Äß<rl|Œcd<ý¤{`jý¸æê«“K>ßâ„V5ªC5yøÜ{Áïî³è ¤Íö=aïÞƒ0FÀ#P@@_ŠÅ™òozy´re’<µ8l:ÿÆ–ò}Ùl:ÿ.ÆPÉ?¼ª„ãz¤Í±qÆ =ôáCZÏO@Pd€OS%è±FÑ><Û¹>|­3¦5å?û£jë0p„º3E vÃ6ôí¢NJ\;åµ@ÓI‰ëÿüZ ÝðÀkI–7yÔ"¾¡;ëÌ3Ã{ãóù§žrJ8îøã“øþ±qRü™dãÖ¿Ž‰—ýq'…hÒ¤IáöXØød¼þ{î¹gx| o>Àî'c"HâXx "oØ>b÷ÔõŽªW³c~ïE€o﹈ñ¢xæë¯&Æ8ü{;ôÐC—åø/~1ü_|$;S Ë.½4ŒŽ÷-¨ñÊÍɱPÀ} ¢}>øÁtR×lBúo]ëôØ“ z.‘­D¹.÷R´óÆ~ñqǧ”(î86>î±Å[¤µr¼Zª´Ÿ´PãGµƒ<µÛn»…G}4¦âß:—a¾1å¿+Ä£ÿR¼âñÍ(ÆOE¢ŸÆG@jQµjéð&ŽÍã ˜'â›VzuöÄDOØ»÷`Œ€0FÀȾlWþ­[ù292¹µòo›Í¿Ñ‘=zµ¦ò﨧ØäŸ9q×$‚¯G˜ä1á@…ÆÈ°–Ÿƒƒ>kèÀ‡.½ôXÃsÆ’a®1½ls6˜5ìãŸ9ãubÒpƒwž=®ôŠ;^¹·GLœÛ‘¾{Í‹áø¼'Ü=uV:)AAbÿxRBDAâ£ñ¤„hêKo‡/_ôP˜|bÇçɵž÷y//˜pDš$ŠàÊkõ-©t9zÎZ¥Wõq”ÝF^Z;ü¸7"À7üç.NÈè)¬Ý/ØÝ*ÞÉQN\~Ê"ŠY‡~xšRØÙa‡´Ô-=¿‡;Sœè–`íÔ#`Œ€X¡p—‹WÅS¡ƧŦ7o÷’Wó¸¹/ÇE™3&—fLOÞŒ=<ˆ}dÑgMÇM³†.¤±äÑ%÷†ä‡9cdòqœ¦¹ü2¯H*T\,2倠q$gš+p9SQ¾6ƒ,$YæÚ½ ¹<²òŒt%/0r>cŠŠ1{6¥;&âwÚ`•ðÒësÃvã‡^ ÊóñÿÃæñN‰ç¦ÏJsù€N#T^”@'/6P (/J “Uô˜v ž)o”ªÙoTßrF@pºÀÔ<Õþ ª(Åjÿ¦óßåž-J W-†r›ùœ»)x-)Å‘Zqä:­:îLQB}´êž—0FÀ#Ð|ñ)ÏaÓ“KST †‘GÓ”++ÿfM¹5:äÍP. xË7þd3çyþŸûK%ŒkFê‘BNAÈ¡æÈ@ô¨ ²Æ4ÖÐSB›SÏ: Ù|ÃqZ"üÉråñ³†®ìôãZ’ñžJcVθæÙTlàîíH}óö Š>}¡(1~ôÒË&{*.Þ—0½Noü,>ÂÓHE†fûž°wïÁ#`Œ€( Pü¢E…„<¹Uþ FnMέœœ±òm­Ñ#‹®H9´zñÉ¿!ìHG=üÜ?sÙÆ¤˜ ³?ËûJ¢2ŠS"8ˆ<ÎÄC––„^%ylÉ? £ÑKÛØcŽä8!qXHúÈ#-¦0Ñ“éÓû¬Ý“·ç½#`z5>1Ñ«?~oÞ#`Œ@B xb"Ï‘IrÉÉ•/“_3V~NœæÈjÎ’ÆÒEb 9åÞðÕàácÖC¬K–ž¹ÖâpYB áD§$+ãêáËQn“1bM|¡9kØÏ7Æs.ØPöß“OKD|LFÀ#Ѓhö¤„ä{0$Þš0FÀ^‡@ñËvòçFòoä:“ƒ+º]•ÿc¿*©8PU .°)UTtÂyž` @Ì)$¨ð€^Nšc yæ]‰I~°…… H'!7ë“0FÀ¶A ³'&ÚfƒÔ#`Œ€hFó_òj¨Ùü;×[ù·ü+×/DUå§ U–KlŠª£  x€ÏXEtK‡>—%`Í‘•Í\‡u€(Nh YíA6ˆS2#²jÓ0ßÖ_ ¯#`ŒÀJG@' šíWz vhŒ€0FÀtŧÈÉEä¿ÌiÊ•ÿ2‡èɱ!òdšòo>MÖ§Ç6=ù·òù8,åꌕ˺ŒéÕâ0‘ò|Í—éä2 #ùò9N,ÁɦøÈ«)@Îåòuø4 ðµ9mvè‘“úeü÷ô;&âžMFÀ#ÐCð‰‰úÁz[FÀ#`š@ X˜h(ÿf‘S[éùwæ›rÿqZT¨.QHþó*  œ@ÌY§p 5U]è)@øBFk’e ["èáS½‘Môó“ÒkÈ?¯‹3#`Œ€hGš=)!ùvÜ«c6FÀ#`j"ÐPþ-4›ãt…åßüS¨Kz ¤êN@IDAT¢– … £*8°¢ƒ š‹‡¬ŠqXJvéi€ˆøR‘B6è!l³ŽìÀØ x:]¡9r ߬Ò/½Ëž…žH7<ðvxå­ùÅׂÆ×ÆW„V~]èÒ׈Ž]sPøâ¾ã{"Þ“0F G!ÐÙ虌€0FÀž@ÿþ)mÏsrÆÊ§•³Yr`åßú†ž›1òzrjÙQ>ln1¤\]­kMsåìò¯uøò‰­Š”vXq¥#cÆ *0Œi²¡¹#¯2FOÁæsÆÖèÑcCô´Ü¦ øƒT„` YlÒ–ôôG9(J²óêã=‹ãî—ðôñ‡úÄ×<‚rÆ5ÏÆŸ&#`Œ€hut¢Ù¾Õ÷åøŒ€0FÀÆX¸º@ÊuÉwÉ¿Éu•÷Ò—#&gLËsê8-ÍáC*T0–mü(Oùuœ×ÊÿÑÍýÉ6º5IFk a˜Bl£ôÚœ ‘UÚ|B®8GB&pd§0좯ؘséz4éÅašç±‰‡ Ô§øÎ׬>ÿüóa•UV k­µV§¢[´hq*BL~úÂX˜XØoêãxsµ"ÿÈ¿šNWtÊ™•Œ€0F`¥"à+n;3FÀ#Ð’¿lWþMn̘‘#ç9± ðhšKžü[<åÍÈ)×FŽ|šdà3GVõåòyþ_n›y]Rò_K ‚†ccŒ®V‘Uª´Àƒò@àI—žMÉN–N?hc’Å/$ÿŒÅ&}ää]Åœõ8oYz÷Ýwʼn7Þ8Œ3¦é8.*œ”øÔÖÇ5¤ûÒësÓ£ …nºé&ž‰ “&MjFͲF %xçwÂÝwßF6ÝtÓзoáWÅÔ©SC±úÖ[o½0lذï›o¾¦OŸÞ!ö‰'–ôXå•W<è¹çž óæÍë ¿êª«†Q£F…gŸ}¶Ýu× ¬‰^~ùåðÆohšzþ­m´ÑFiÌñAØÝ{ゥ˜‰\noþüùáÅ_ &LhêëíGÂ_|qxíµ×Â׿þu±:ô+ê÷@=?8ýÝï~¶Þzëô¹äATÒ½í¶ÛÂí·ßN:é¤p饗†~ðƒaܸq¹Z[›=)!ù¶Þ´ƒ7FÀ#`: Àß}‘ø¡¢99¹1y0ùož'óÇ.|Zž»£«üž¹òfæ:ðdrðÉÛõ–æÈ@ò/žüË·lb§*5R˜È à„èák®Àµ†s›C–F€ð¸²£ày<B† 湞øôò‰-Ñ¢„ À¯5‰‚ôä“O¦¾ÙâwJðøÆä»^MÀð#Tì;Îû„í' ÷Pªä²âýöÛ/\qÅ)Y›;wn*LT4Ó´(<Îô½ï}/\sÍ5a·ÝvK’6þ»^guÂî»ï>ô¡…Aƒ…Ç{,l¾ùæá‚ .“'Oçw^Z×Öþë¿þ+˜ùË_—]vY:©ÄüþçR¡âÎ;ï k¬±F²CR½çž{†]vÙ%z衈%úÌg>“nÍo¹å–€Ågžy&ì³Ï>ÉþˆŸâqÞ|óÍR ;ï¼s8蠃ˆ#ƒ>vÜqÇpÎ9ç$x`ÚKI8êíG²Gyd > «¯¾zbwÅïJ~=ŸÅé§Ÿîºë®œÆåº¯¾újøØÇ>~ô£¥ÂÑìÙ³…¨žD>1Ñ“>MïÅ#`Œ@ç(~™¦ü›œ™üWI.ù/k½ä˜kMy6z*B6§‘ÓÃÓz–rxø²Ë»Èi¬SqÀWîøqX™)L(é—A@Ú$ë8¢‡—Û%PWÁ]>ẕ« !‹ ¤5ùAÖÑ—|&ÿÜC¿_;¼•cyŠ\tÉ]tÈ®£Â•wÇ?ÔwYúíê5÷¾Üiéü…WçÔ=1±ÿþû§o,ùæõøCúÖ—ä ,I”vØa‡pã7†ãŽ;.ð­3ã|à)¢šwöÙg§DaøðáᬳÎJÉV ÏdV*O?ýt*4<ñÄé„Î)Rpâ€úÁ~FŽ8¹Ä¯§žzjâST8ÿüóÓ8ÿA‘îž{î |pê)œrÊ)Iä _øB:‘ñùÏ>Í)6Ž;6ÅÛÈLJvX ]}õÕáÊ+¯ì Kb~À„‡~8Å7xðà¤ÊÉŸüä')îGy$ì½÷Þ©0‘Û-WÛO.7pàÀTp¯«~”û‘?õ^xaøô§?]±šëò™q†Bʉ'ž?üðô™ìµ×^ÉEŸ¯|å+aÆŒáøã›m¶™\´U¯ÍömµIkŒ€0FÀ4‚€ò_dU /&GV~ÍT)w‡§üRHt!ìɾòpÙHÅu䔣åù?ñÐÐ¥—ŒlGVe*/ T’Â(†dTPA‡k£—óÑÉkؤGG$?ô"Ö§l|ÙtËüÒ­Ol°Axýõ×Ó·¦ÍœšÐ}"2%课§Ð³k濽ïµÔ3ßæŸ†Ô½câÚk¯Mßü>õÔSé›Óë®».:KަŸyæ™éM *$v$[mµU I⎠¾½Õ·À‡rH:^^¼I–LF`¥ @B¿í¶Û–Š8UABÜΙ3'\~ùå)Ñ×#S¦L))(X|éK_J*üÛàT§8)Aa¢ñ¾ŠÈ‘ sª¢Â>ÿ~¸†ƒŒ!#ùÆ7¾† þøÇ?†3Î8£®¹jû©¥Ø]¿xàðñ¼VhiBÍwÜ‘dÑ(BpBŽÇZŽ8âˆðË_þ2S÷Øct & µÙŸ˜h³Ìá#`Œ€èŠr`™ü—\—œW¹4c ð!rfåÓÈ0'§¦g®¦<¾ìÅaI¾ÛØÌóoÖ°‘ç߬£'9zdðY“”ð×°6‰œŒª‡§j ñ±<ÇMðÉXkq˜Æð‘ËùŠÿ²Á:„ x<p¸\ÒêÅ ’£¿þõ¯1äÐá˜wbÔù±G9âŽâàxR‚¢ÄA;/=!AQâ€G–¬<ÿòì€N#Té&$|‹ qžñj«­–ޝ“ÜÿýéH9 DE£]¿­L›ð¶D€#ýœô©En¸aúýÀ7ñœZñß¾þûWÏÚøÃtRˆ“Cœšøñ\×G®/ûõz~'\tÑE©ÁøUa]µàQ¡˜¯U²]m?•dËy•âïÊßüiæ2àJñqJ†{Bî»ï¾ÔxT¦]©Ù“’o×ý:n#`Œ€0F *ä¹¢<¡ƒ¯ü›…äèÉ¿Ut?²’ :ðò\›üÛÊÿY—žúÈê³Ã—ô4†ŸÛŽÓê¤Ä¿ºÄR§Ö¦W¡¾|œóÈ=òÁ#HéѳNå|„|ʼn¼Ö¤‡oˆ~¨@‰¬Ö$ž‰~衇Rp$¼¡£ÊOL\Ûà„Äoî㾉8àÿc»îþxb£ñÇë ®{b¢–î쑨z§ ¹£ñk®¹fûîw¿›(é¸7+ -¶Ø"|ÿûßïàŽË!gÍš6Ùd“ÄÿÇ?þ‘ œX7n\Ivûí·ßúÖ·JsÓ¦M |3ÏýJ†9ÉÀÕˆåvªÉæüßþö·iÊã œB¢pÉE™œ¦âQŽÿøÿHÿÎâÔ'ÆŸ›è0®´ŸMNºò÷§«–÷< ;Pþ{¨É-¶Œ¸OL´ÌGá@Œ€0FÀtÅ7M¦”.‘çÞĤ¼›‚ù/sòhÆ4éÑ+ŸgŒé0—žòjzÉ#É7½ˆ5òï<Öñ-û¬Õ$„ëÁ@›$|4VAyx²AƒX§¨‚Õ&ᣗۆǺd°#ŸqX—ü·úi ]zÙ™¢æŽ qP¼K‚þ_w•NI°ÃÈ4ßoû‘a_Úv#pèÔ#މ“5Kq_{íµ—Ôq›o?±e2+NépQwžð{àí·ß.Ý ‘Ç·óŸýìgKwEäkù˜S@<ŠÁ#K<&rÕUW…_üâ¹È c÷7¿ùMòó裆c=6=nRî€5Šü›ë êŽß6ËߊÒì޸Ȕ¢Ä¤I“Ò}íü;H' ší›ÅÌòFÀ#`Œ@ë" /Åb„uóߢL3ù·’ÃÎæßø*åßqœCâ4åûÄ]“)L¨ bË°Š Ú ÎàQL <}UM˜³.}6ÚšdY—ùЦãR€^kŒ«ùg­åˆ{¶Ûn»¦OJh#¼aCÅ”¸vÊk¦“×ÿùµ@»á×’,oò¨G\ÈG\$`Íñ½ï}ïKßÞòM±ñ¨‡É¬lxŒƒÇ3xÓ—PòJP.Käîrâ’Äÿýßÿ <ýìg?Kÿ&9ÁDã‚E <¾!úð‡?œîRán(û ‰${²Aýõ×—ÖòA®Ë½\°ÉCDøÍâ$¯åÕ˜_üâÓ/Èê¢Oùä¢O¨Ò~ÒBÝñ{€·Œð¶‘å!^ýJAŠ»%x¥j5Ü—ÇÇÊÒí쉉•Ÿý#`Œ€0]€ò½è‰\ʺjù¯rêrYôWFþ-ÿôu©¼xPIA2ôlJÅT!¡‡$Ϙ òcèævXÃ&<Öd_§$$mÙeM²ðy¶=ñY£±66~cƒ>È™3g¦×_F~"ùΓ€‹->9éO‡ã?òžp÷ÔY餉ýãI ‰Æ“¢©/½¾|ÑCáúSö«jÏ%rù‘íª‚¸|Üë=ã_AÕ,#°Âàô—X:t…ÛîéWöï—áQ•[o½u¹¡åw—›R¨áíA\Ò[N¬ë‘Ö¸•Gh . å-DÝI<î×™âDwÆlßFÀ#`ŒÀŠA€¿_ô·H<åû/ÑêKEËó‹=ypÞ”£«€¡¢€^-JN­1kÈÑ+¿f,8Lë¬åzäÙòƒL.O,¬S,AGyMR –ŽdP#¯åœ^< }ñÙ€ÆØˆðC~NØb]zè@âUò½õç›H&Pêi”›ÚiƒUÂK¯Ï Ûx%({Žÿ6wJ<7}VšóÈ|t¡Î%°Íe‚&#Ð*4ó¦›V‰¹UâXÙ¿x“ ÿÌ…•¼²xyˆßÿ%Ú™:S”Ðcí¼oÇnŒ€0FÀ,E xŸŸò_rjòf”WÓ“+ç&¿FFùµäàCôØ)O™#‹?ÖUd`±_~UþéË_dÕ§F „p ÍáiSôåò̵yü1ƆdeO2q©´Æ˜MCøCÒ— zÉÉòå GVÏ¢±k g\ól*6pwv¤>ŽyûEˆŸ¾P”Xía= ïÆ…@#¯@íQ®±šík˜ô’0FÀ#Ðf/¿$çUάü—œ·<ÿfw’S¡€üY¹1cˆÂ‚t%_¹6¶á3Gy‘üÓˆòudÄ—-däŸõe¨Ñ†!UL´™·ðS Ð«Á ºÈ½ÆqX*&°†\®Gðå~T™©ôu<~ŸÞRñ¹ï(×cè‹ûŽï1{ñFŒ€0F #>1ÑÏŒ€0FÀä¿äÐäÒäÑÌÅ#¦ \œ“ÊÇɳ‘“24H¹ºæä×<6²ôÕŒH*8(—-ÙQNlMÂ@=’q%ýÈ‹‡#Ær¨BÅœVy¯zåÞ ÷U®ÍºòmxŒÕT @WÅ ÆÈ¡§uÆäÖ:UÁ\vÕ£—ëÊ—ÖãrÒÉùð*†!9DV›$P‡ù†´yé2W%ù¼^%_6a 5ä¿x쥠áŸFÀ#`ÚΞ˜h£-:T#`Œ€0F 1Ê£)åÎåù7ú"åÙš«_6à7•åeŸ*êR^¨&̆0¬€èU¡‚¢J‹lI9€À: q ÖÅgN“ÍÜŽüÇåTÁá±ìr¼Æè%ÿ^|9gîܨb2FÀ#Ð:èD³}ëìÀ‘#`Œ€0Ë‹@ö€N0ó’ôÓÓÈ}!» 'f®G9â°”¿3†”7—çääÔØCûÈI6_ù¿ äêø“OøŒ[vÈý™/C(Ô#‚•azË A2ǹ6¥‘ab,¾xÚëy¬cK~£+y@jÖT1#`Œ€h/|b¢½>/GkŒ€0F +(¾•Cùu;äß•òÿšÐèDB-! $ÜB‚ 1'lJ¤B‚Š ðQÀ*:¨À¡B2²…„o|ÉÇa©˜¡5ñè[‚þ_Ç /¡åã‘#G†Q£G·DœÂ#`ZfOJH¾5¢wFÀ#`ŒÀŠ@`Ñ¢”r+ÿÍóoÆÊ™qE¾Íœ<[}žK^6òÓÒ‰ªIŸ’>댥«ü_ëÌi"䙳åkNö³‘„¨X©§€µŽCÆÊXsY%ÐREä#—ÛʄϱNKÈv–c]6°‡n’kôQŽ(ßåD,[l±EE?/¾øbxyúô0fíµ+®›iŒ€0½Ξ˜@ÏdŒ€0FÀô8”ì³1åÛäÈPž'“#K^¬<›uxÊ—ã0Íᱦü[|j¼ÍC¹¶øÌiòŸçÿÈÈ'c(·[àTø‰±z„!mBDOÀˆuO-“ zxD=l±&{òK/›¹ld×÷_<ö‚l·“.â|õÕWÃÃ?^~ùåRLë®»n0`@˜>mZ‰ç0FÀônt¢Ù¾w£æÝ#`Œ€èYdwL(ÿ¦§­Èü[´åÊ¿£¾ò}lAšfU~J¸Êrbcˆ¦ÂŠ,¢Òz~‚"|š*)ØB56 _Áb;ׇ¯uÆ´¦ügbTí^Rabz<±Á†úœÖ[o½Ð¿ÿðR<=a2FÀ#ÐÙFÎ#`Œ€è9d_¶+ÿVŽ­|™™ÜZù7›o6ÿFGö”{7GŠMþ™×­;ÔˆFؤ6Š<Á±i@*$ “rzôy`¡£€Ñ“-ÙeŽ „<2ø®ç_~¢hòµPÅÝMz¬dt¼Kâé§ž cÆŒI!Ý9mI AãÆK''þñ iÞÈùó燿ýíoˆ&™9³g‡K.¹$o¹å–pûí·7¬Û¬à#<î¹ûî’Ú›o¾™üÍ›7¯Ä»ø¢‹Bñ¹©Ï#`Œ€¡Ù“’7vFÀ#`Œ@ÏA ˜G*gÎóïeò߸krfQWçßòC_-ÿ'—g­&åAWĈŠ€Á="ÃG†^UšÜ6€Ñ$ËX6éÅWÀ’¥—í8,‘¯äýJþÑívR‘„‚Ä6ÛlÖŽ÷IPxìÚŸ¦¶?~üøTœxáïo(æçŸ>|ÐA É"ôö¬YáÇ?þq’Ÿ_“Jë ¢øð©cŽ ï‰'A Ÿÿüçaß~4üþ÷¿»ï¶[¸÷ž{ŸG[Î9çœ4ö#`Œ€XŠ€OL,ÅÂ##`Œ€0½bÙLþK­œš|šqWäßæÿu?º¼xPM˜Mˆ§±)NCM„,Ùµø€ÇX<ôdOÀª‡¯5äç¶ã´TiØ+>ÊÁF %ÖÔ'¬Û£3û'Ö_ýôXÇóMœ„ÀæøÃpÌ'?6ßl³°Û®»†;î¸và {OšÖ;6œy晉'¾NgðhÉ¿|ä#á=ñ¾‹ý÷Û/¼þúëIŽ»ì¼sØxâÄpöÙg'޻ホ<òÈ0aüø°ë.»„§â rú¿o [n¹eàþ è›ßøF¸úškÂgœ¾ýï„ÓO?=ñ?ì±á§^˜ÞR’þaŒ€0 €h¶7|FÀ#`Œ@ÏA _¿”2·EþQÏóåõu?ŒF ƒ(¨Ê¢|³¦ò²Ë˜uæÈ¨ØÀ[®Ru>;ž† Hð§»î ÿöoÿÎ.žŒ8á„ÂÞ{k<Ê!šdzçÌIÓã¾ð…°ãŽ;†Çø`Ø4H ™3g>‹Q£F¥ù¦›nž-îkõÕWOr¼öÚkiÍ?Œ€0F €€OLø¿#`Œ€0F xb¢¡ü7¢Õ­ùw™><Åø*isUâ=!9W_ŒÜ&cŠy±"/NHûøAަג¨àÐiÿº×!Úìvï–àñ†Š÷Gì>¶OØ|%áw—¤O+¾M4 Ð7<<£O©8±ÑF¥âijÏ<ÓpüÝwß@²ÐÁîx€î¿ÿþpÜñLJUW]5*»'>Zq—¾†Î9÷ÜðýXŒ ÈÁÛCпâŠ+Ò]÷Ý{o*\<ß,Â)ˆ &„O|⢤1bĈħÀA‘EÄ%Ÿù=È͘1CËî€0F "ÐìI É<#`Œ€0F ç Pü²Üº‘ü¹Îä߆nWåÿدJ8®GlJ'(ˆøZ_ú¤*< —“æ:Á\À¢«16å[ÈQ¨€–f¶Íø/XèæŸcâ½$éÜ í6¶oØbÍ%áíy‹Ã∠ðóžé‹Â?f £¸ÒLeÈàÁÉÊàØ£G…Ë%)@y 1âäÉn|M'xdZc5R;ù”SÂŽ;í”ÑàÅ AƒÂÇ8"1’`ö£_ô§K-¹ð““²Çýâã*"äãϽ0F ·#à½ý¿ïß#`Œ@ FóïBJYÈ£Qn4ÿÎõVDþ­ü_¹~i#•Jì+­å<É©@AÁ€†‘N<ÀÓº‚Ñœ[È2†‘.` ±dX‡ì5ê¿ Ý"?׎÷<äoÒ 8±e,NÌž¿8Ì™¿(Ìm—µû†÷¬Ú7<ñÄI–׋v–(6l¾ùæáꫯN&®üõ¯—1Enëx!篋kçŸw^º ‚G.(J¼oÏ=ÃÑñ‘Šn»í¶ð—¿ü%|ëä“ÃwN;-<ðç?/csäZk¥Ó,`Ÿ{*.»ôÒ$Ç[A¸SÄ©ŒQÞdŒ€0KÐ ˆfû¥<2FÀ#`Úâ—ÔäÀæ¿Ê—é»#ÿÎý3V>_õ£PÁ¡ª@\P€ùò¹6+‡²)>òjðhr¹|>¯÷á#+69=rŒÕ³ÎJüâ±—§…~®/„äQݳ°ëØ~a«KJE‰]Æö_!E mù̳Πßùö·ÃøqãÂãñ‰JÄ›1¸Ü’ -/¾øâô¦aÆt÷ÙgŸ°Q,ŽðF‰ñL¾Å;+ÞAñÞXÌ85ž¢à1‘rÚnûí{ˆÎøÁ¹ñìL:5|ù+_IKÜ»±Æšk¦ˆdÝ#`Œ@H¿k›-J o2FÀ#`zÅÂDCùoÜ5rjäÄ´•–g¾‰!÷§Õ ÁzD¢¯âcª4*HWNUÐÆáóø:àÃC_AÒ£GcÌ: yH tòq¹ú¬Ã‡ð;6¾Yâ†4‹?¸ó€D»œŽÉóñD@w4ðˆ]B<¾±¢NJTÚÏœø8E% rÙJ2üc˜‹î*«ä¢av¼!ä¼Ü‘‚Â6M›“.B ŒžFð’QYÖ§Öt\J:åþÑC'¾YEîm=Z/ž<౎§Ÿ~:וE Ô+JT“áCyQÙjE Ö¸ãâäXl¸ù¦›˜&ÂN^”€É:=QòO#`Œ€Î%|bÂÿí#`Œ€èYï ìªü›|{yóoåþ•òåò5?h„0FQ€ •é3Ö&â0™#K¼ ŒU,ˆÃ´¦¹Š ˜=?ç6Æ9„ˆ“Ò•lÒ–´ê£1¶?>½ôÉ'ŸL—PR¨Xž;%J†[`pðÇ>V7Š .¼°®ŒŒ€0½Î<ÆA1ÃdŒ€0FÀô.ä{ùR¾MO®K¬žÜYù1=<šœ[ó<§ŽìRŽ­\:ÿò_¶±ŸçíØR ¡šÝœ/ÛØ©I¬%„am”Ía4wÆšxqX*\0VQAzlVºÒ`ôZC xA¡@’c^Óñ¯Q¬µ‰7TPèIE‰ÖFÜÑ#`ZŸ˜hýÏÈ#`Œ€èjŠ_¶+®™ÿÆXÈ‘»-ÿ.ó¯:B]ˆTí¨%˜WY´A@A—Hq˜x*20g]¤‚ºŒ TvÑéìBòƒ=HþŠMúåþszU&Âí@ëo°A;„é€0F`%!à+ h»1FÀ#Я' Ç%ÿUN¬œ›ÜY1Ñ6•5FÀ#Ðedošl&ÿ&§®–“¯+§_¡ùwÑ'qbW=yMB°a 1¦B:¹qŠšÓc Êù+Á^n'N“œ‚–2*ftÖ[¼•LFÀ#`Êð‰‰rD<7FÀ#ÐkP¾ Ê™çù7cÉÑWË¿¥Cn.[ð–7ÿ–­h*Å¡â‡b‚_‘p\0®bʶp®; tòÓðT|@}Uqâ°ä>rÈ Ç\q"¯5ørlâyâF¶¥èúÛŸ¯½1·ðé/Y_m1}ŒTsNz¤O52G­14öÁ[jÆ#`ºΞ˜@ÏdŒ€0FÀô ŠošÌó_RGù/y²ò_æäÑäÂ4éÑ#‡.czé0—^¾.yä ÖÔ#þ`ü;|Ë>k5I -!m’`1¬MÐÓ Ì›yÖh"m”ynOÁÓC¬©˜ÁÛ¹¼xò©9¾TYÜjrP”8zÿ­‰µaúñä¿4,kA#`Œ€è9øÄDÏù,½#`Œ€0E øºPÔÉ}•ÿæ_âëdÖ•ŸÇá2…òmäò¼yåîq˜Ö±BV¾™#ŸûÊó$ƒÊsø·ìg#… ‚PÐ gÁÈ1k<ìæzð™K–yɲ1æ²+Ym6.•ôÙ´â. 2]t¸üRñÄaë>Ùþæùø*Óxb¢Ï°ÊêO†Á«¼œ‚œóöè0óÕ ÃÂEýÒúiÿ>±57Ò::#`Œ@EÀ'&zìGë#`Œ€hìËvò_Hi%cåÔô9å9µøÈs«_y;|­‹GNOä!+ù—NAriþ®Â„ø{*.™8PÑ€1: Z|¦uæy`ZìRõ†u cˆæ²ø‘MÀ`LQBþ‹t$[î?ª´é?ª>}û„¾±­>òá0lµ¿‡~ýæ¥6|¨± q)­uP®A/¾øbxûí·;HLŸ>=Ìœ93<÷Üsᢋ.ê°ÖU“ /¼0äoA¹ÿþûÃÔ©SKîþüç?‡{ï½·4÷À#`j#àµññª0FÀÞ€@ñQ Èëå¿ZåьɿəiP½ü;É¿e¹æ‰MÕ#Í‹˜p¦Í#ǘ^''eÎÆUÉ‘²;å1!Ï:ò¬!OkÈvì%ªt?q‡Ô7Vú ˜ -œ”(p ?‡®úJ0p~*NÀ©W˜¸à‚ ©§žš›úЇÂC=Þyç0gΜk]1¡øñøãÇâJ¿0cÆŒ°ÓN;…‹/¾8œxâ‰á°Ã ¼{wüøñá˜cŽ o½õVW„`›FÀ‡@gOLô8 ¼!#`Œ€0½¾}SŠÜPþa"ãD¶Zþ­Ü›¾Rþ­ü}åù çßQ»èÒÐSþ‡Õ)í°úrZÁ „Á< mˆ5mŠq¹¼Öé)T°Ž_t ¬9¼| Ðòø/XhŸ¥ÂDÜu¿~ó«F4`@,Lpl"’­&|ä‘G†É“'ÇG?øxBxì±ÇÂo¼öÚk¯0kÖ¬ÀÉhÚ´iáýï5jT@‡b´í¶Û†×_=éOœ81<òÈ#‰¿Ç{„^x!Üxãaà 7 cÇŽ _ÿú×ÓZùsÎ9'œp ‰}ùå—‡m¶Ù&üô§? ¿ýíoÃ3Ï<¦L™FŒöÞ{ïpÕUW•«{nŒ€0ð‰‰  ˜eŒ€0F —!PÌóÈ‘•'Ó+OVº¨|t$×™ü[5ÙËóuÙmÔ?ºÊÿ‰«*ÉiU¸ "£ŠI%y'@zPððCÖœ™c›ÆXsdh6R˜l²iq–öý·Ú‰ Þ¾qbbÉâUcÓÓ,>?/-Xuia"ÿ–Š•FÞóž÷„[o½5ñ( qÄñ¤EŸ0oÞ¼ôH ŸûÜçRa€B‹sÏ=7É£Ï=÷„‡~8üãÿ·ÜrK:ÕðüóχõÖ[/œtÒI©ÈÀ‰ÖË™?~zddüøñÉol¶ÙfiÌÆz¤cóÍ7<ð@iÍ#`Œ€¨Ž€OLTÇÆ+FÀ#`z9ó߈ g·åß5ü×ü¸)L°1…6‰§1=¶¡gBÄX” H·&:3˜3V*®õÜ?k ûoµÂ„À 0Ñ7Â5÷ÍmBŸE‚5n<Žßz}Ë@¿T¼ˆ{-Á¸q‚‚wX\qÅéDD¹ìï~÷»ôXÇùçŸ^~ùåÒÉNVP˜¸í¶ÛÂñÇŸ ÷Ýw_ØsÏ=“‰ 6Ø |ó›ß W_}u8ï¼óÂðáÃ;˜æÑ NCk ðB•õïß?H˜­µÖZétFqÉ0FÀÔ@À'&j€ã%#`Œ€0½bž¥TR}Kæßñ#Q||:ŒuyUb3r*4¨h "„l¨è€s2mähÒeLñA2ɶæêÅ— øò×=Þ ƒÝÝ/}”#&bqbñü1aè½ ëM{:µÑ¹-,xgt<-7×!%üµb?ôÐCà 7Ün¾ùæ0f̘À)ˆœ„q¬¹æša¿ýö _ûÚגȤI“Ra‚œªà¤Ä]wÝ•Aà¿øEâ_ýõaã7NwHä¶)<ä—^®¿þúɆd°GqB./ZHƽ0FÀ,‹€OL,‹‰9FÀ#`z) å¿åÎåù7ú"åÙš«_6à7•åeŸÊÿ±U•䤪@\`C¦§¡#ã+ú×[0nRaâ‰W?žzýè0uÆ'Cßw熵fNO­ß¼w‹s>¦ÍýlxùÝϦ‹õ‰šáSlØ}÷ÝÃg>󙊧%¸0e·ÝvK'á‘ ç€($¼òÊ+é þ~ï{ß.¹ä’Raâä“Oûì³O¸öÚkÃj«­Ö¡è€>¾yˆî¬àn NoÌ;7<õÔSáÁ [o½5¢·…pjÂdŒ€0õð‰‰úYÂ#`Œ@OG û¢zyòï&rè.É¿£]åìøËóæU)?µPMˆ€)`”ä_ÏàÆ\•櫘YIW§%¤Ç8/6°ŽÏ¼!¿\È 9ô“í8LþésÿÌ[‚T(9p·“JñÌŸöTXðÖsiÞà Âc6,­1`˜&GuT:5Áé‰JÄÛ;ößÿtR‚S ×]w]Ilûí·C† Is.È䱎ñãǧùСCS!cõÕW[mµUºØ²¤¼‰cË-·L—n²Î9:è 0a„ôhÉ™gž™Šèð¦I“&åê#`Œ@:{b=“0FÀ#Ð3(¾•Cù­òhzH¹²Öá1†¯ÜòÊëÕÃ'ÝD^úäâ²I¿ 6²ò/ydÐÑYÆðÅc½&5R˜Àynˆ9G/@ 6¥#=¢1'@,´)zxÈÈV&Â' ¾äYÀ¶ì°ÉaÖ?Ùp9 ;1ÌŽ bcåÔȉ töÝwßÒ]²Á=º+‚SºørÕUW•Hêÿû¿ÿ»4?üðÃMĉ .Àä1ŒÁƒ‹Ý¡?äCÒ8(L@?üá÷¾õ­$/ „Ûo¿=P¨0#`Œ@}|b¢>F–0FÀ#ÐÓ(>6¯ü7Ï¿óœÈ‘#íT¯Ü9²J9¶l»3&¯–N¦1=$}ÖK_âá‹yž³Æ\)n¾Ù©‘„¨X[39¤'PœÓ˜ À8Lc¤¢‚€È7ƒ®äd‡Ç:¨øÈv–ÃöÐÁ}’Ó …8o Ò£»¯ÿ¾†ãi´0ѨÁò¢D#zœ°¨u7ıÇ>ýéO§â'( NXäÄ)ŒO<±tz"_óØ#`–EÀ'&–ÅÄ#`Œ€0½åß@ <™Êód2dÉ‹iÊ×á)_ŽÃ$]äCôÔ 8-¡\;Ÿ¹ìÑçù?2òÉÊí8~6R˜a¬@0Ç:"† ‚ƒXGb Ú,:FcMvy\C¾t‘ÅžìÒS°¼Öåg1Ç^tñc”ëvµÆÐðãÉ)|Zq'ØÐÒ¾O6.ðGFV§Aƒ…üÔE¥x?ðTb›gŒ€0Uð‰‰*À˜mŒ€0F !Ý1Aþ› È“Éõ¸…rmÐa¼\<0‡˜³¦|yåäȰ¦>$ÿÕòùB¶Ü?¼ªÔHa"7ž‚#Ö¥×fµ‘ÈJ 0ü¢ ©ˆA~ž¯³–ûfŽŒî™¨æ9ŠÈöÏ>DøÝN‡}pãnÁ#`Œ@{ àíñ99J#`Œ€0]‰@ñŽ \“?“s«1WÞ­¢Ed%9ä)"(wFVE…8,åßÒ'ÿVŽ}ˆ5 äרŸYùÔç+>zä‘Q‡• zD 4‚aÆ H “ry`)Xl '[²ËydˆU’\d•€PŒð ä¿•NKÂòO#`Œ€0!àád)#`Œ€0=âõÊ™óü[y6ÛÏóoÁÑÕù·ü”ûW\ø'O§¯I&0¢"`0Gcè)$Ðç¶ Œ&YƲI/¾–,½lÇaiŒ|%ÿèWò®É#`Œ@[!ÐÙmµIkŒ€0FÀÔD øe{3ù/y´rjòiÆ]‘7šÿ×Ü‹$ñõHÅäT@Ц4G¢§8@€à1ÎÁPá@ÀªGW¾Tü¸”ÈàŸµòøå_vúñ(G#`Ι;7š3#`Œ€h|b¢u> GbŒ€0F »(¾\€§”[+å¿â“[“++'g¬|[kôÈ£+B^¶r>ù7¤ü›µ\W:ð ÙÆ_þ£Ú9ª¶_FqJ@zÒU`rˆ¼Ö³Î}m„9¶˜C™1v¤nî9ˆõ\;ý·Úo2FÀ#Ð>1ÑJ–1FÀ#г(ž˜h(ÿHtkþ]æŸFñ0®Jå'* ’ð“ø«( ÆáÃ@* h—:¬á ™¼8 <ÖГ ìÂSÁ_Z‹ÃÒæ<Ö±ÑÁ#§%P^™´pñ’pùƒo‡_šæ/X–Äy߸“>¼K4¶¾±­:¨oXmp¿°ú~aâڃ®®ú÷“0FÀô|b¢·|ÒÞ§0FÀê¿l'Ï%ÿU¯üXs (VžNŸçßè£G®ÍX#çF_I'<‘ü"/¹É)ÖT/Àžd%·LO@õ#‚AäeT›e_ÅÍt\*éi3²‰ŒcLÚ¶ÙoÛ¡£øåt4—lKõ÷¼ðnxxÚüpîë…ÁúR‹HSD‰5Š0wþ¢0wÞâ0ûÝEáÉ—æ„ÿ÷è›á™Ørï1-µcŒ€0]‹@gOL g2FÀ#`zÊ¿•ŸkžçÌÊ…Ù¸òv4'߆‡,crgوä'Ûäߌ!ñ§1¯”Gv"ù“¾ø{i„$Ç §åN( àžÖŒæôØR!“ŽtµAô2¬Cz?«ì5ê¿ Ý"?Ÿzu~ØvÝ¡aÖ¼þúòÂÔž|eaxæµÅá…7‡·æõ CŽÖ6 œ|ð¸pÿ3oµHôÃ#`V>1±²¶#`Œ€0­‹@ñ)ràFó_åËÝ•çþ+Ÿ¯ ² Uâ‚ ôȗϵY9”Mñ‘WƒG£ðËåëðiT_à#+69=rŒÕ³ÎJüV¼câ͹‹Âº« oÌ]Æÿ´81ÁI‰E±Å';» –„sX[.¾é…ðê[ó€¾À`2FÀÞ„@gOLô&Œ¼W#`Œ€0=ba¢¡ü7bœ91m¥åß™obÈýÇiuR_]¢èç§ pábÎ:›Õš*9ôªŽà ­I6²’­ü1NfÈ&úÌU|^Cþ-’»h¡EˆÂİ}C|b#$ oP˜ˆ·MëˆãE©±01ûùáô+Ÿ Gï=¶jô¯¼òJxê©§:´g¦N]F~þüùáŒ3Î êàË2"+ñÈ#„{î¾»äïÍ7ß ·ß~{˜7/#)Òï®».LŸ>]S÷FÀ^‡€OLôºÜ6FÀ#P †òߨÜlþ¿–WðO  .5R˜  d”l?ç1VÁìª!ËXºJòô4ÀŒŠȲ¦8µŽl-ÿè¡߬"wqÖ"4kîÂba¢P” Æ©‰ÂɉPRX¼(œû©MÂ6V«= ý?ùI8ñ«_ x`_ré¥ËÈ/X° Ì3'Ðw'Q|øÔ1Ç„÷¬·^ ãç?ÿyØ÷£ ¿ÿýïÃî»íî½çžÄ_}5±Ÿÿ|w†jßFÀnEÀ'&º~;7FÀ#Ðôr¨•ÿ*÷¦o6ÿ&ß^Þü»–ÖêRCBÑŠäšL_mB0gL¯"‚ƉžŠÒ‰¬DòA €¢ i ›Ø8ÖhŒe‹9cähKZñQŽÅñxÄ þ}ÃÂa¡ƒƒtj"î€1Yú6ðÇÇ>ö±ðã³ÏŸøÄ'ÂÖÛl“ÆßûÞ÷§E¶Ø|ópÄG„wØ! 6,\sÍ5aÈ!áwÞ ‡~xXwuÂa‡öÜcðòË/G¯!|÷´ÓÂú&„]vÞ9yä‘áºk¯M| ð6ž81œýAwßuWØoß}ÃÎ;íN8á„ðî»ï& ãLJ]wÙ%âH‚Ùÿ»ñưå–[†u×]7q¿ùo„«c\œæøöw¾N?ýôÄß#ÆÄ‰‰çž}6ÓöÐ#Ð{ð‰‰ÞóY{§FÀ#`ª!P<ñNŠH«”ÿÂ'ÿ…4^™ù·|ÖòŸ‚«öC µuV‘€Í¥„?ö8GŸ5ñâ0è!ä‘‘'ÐSàôå€ÁCŽÄœ¯øéUt`¬yMÿÅw¾FñÖ¡Åñ>q×(Jňc 4@YOL Hðv.vNbüío ïÿûÃ-·ÞšŒ¨øð£ý(,Št<þÄáÃþpxàR!ãOwÞ®¸âŠpûw„ .¼0üñïÄb|òè£Ã÷¾ÿýdëâ‹. =ôP˜ùS¦L çœ{nøÁ~n¾ùæðꫯ†gb1á ÇîÎ×Ð.|ðÁ°éf›¥éÌ™3#}¨Q£Ò|ÓM7 Ïf…ˆM6Ù$ o2FÀôF|b¢7~êÞ³0FÀŽ¿lYbëçßÅ•ÿ«ŽÐqCf&(¨¸€¡GâÑCzÌ9]5ÉꨈôÑa,_Ò¥‡'yôñ-Yé#WÑ+&–Ä DŸX4(%–>ÆA!¡À‹»‰Ä‰‰þ}E×ìÏÁƒ‡£Ž:*–Èu§Üw_ød|œbøðáéD… ÷Å"ÃñqN3lµÕVáƒÿüÏI;,(jÜÿý©pAÁã¾{ïMk;î¸cØ~ûíÃÀÃzññŒG~8p bBszeйMt9í€>$9ø 1„”©Â£h‘ûdžާÊXñTôŸ'½Q¶%hQ< AÕ‹"§#¸ôR =Ò1 îìÍÙóã£ÚVçB'ѯô8ËÐøXǜٳ“Qù˜;wn:4ÌŽ÷PˆfÏš•†<¢­ï} |Ê)aÇøøDABÄ#œÎ4hPøx|„äûñ„E9õ‹1éRÒÑ£G'²ÿÂßÿ&¬¿~I¹þYᢴà0F  à½àCö€0FÀÔA ø(ysÝü7ÊtEþÍAFý+ÏëÊù«îõˆ"Ù±Š8€*RÐCðÊí¢O€*8  ÁGO+ GøDŸ¬ÉctXG_òq˜dÈ”á÷SÌB«Ð’¸ 6D1"‘ú8)ltIï xõ͹ap¿l±(¾"ºŽ'!¾ïsèÛ·o¸1ÞùÀÐ^“&…ÓN;-lïªxã7Â-·ÜŽwXðˆ‰÷í¹g*œÞy¥âBÏm·Ý¦M›¾uòÉaâÆ‡«¯º*_Nã‘ñ„)¡h½—ÅË:?/º¼ä’KÒ˜RBŸ&#`Œ@oDÀ'&zã§î=#`Œ€¨ˆ€ò_ÉóYùµ+åîð”?#‡>ù5„=ÙW.I ¸Žœòoô¡<ÿ'y¥¡K/ÙŽ¬ÊT¾JRÅ`Þ´ôq¨âB¦1ë­`cƒ²!>=öóM#ƒ=Ñrù/¾óU¶ºµäÅwÂL~)¢²$¼ðú»±0Q8)Á© ½™C''VÔ'¼2sn³æà†c®t2¢\Y2\jùéO:üêW¿ [o½uø§qã’èÄx±å¥—]–îŠàâÉ8 ñ¹8ó̳Πûì³OØhà Ó4-'¾Ý;ëÌ3Ã{caãÔSN Ç|¹HØ.>öÁã¢3âÝçÆ;*°;5¾æôË_ùŠ–Â£ñµ¢È›Œ€0½Ÿ˜èŸº÷lŒ€0F #Ù›&›É¿É©«åßäëÊéWhþ]ôIœØUOÞ_“(Ô# *hdeT=<´NøØ@žc%ød¬µ8Lc.r¾âÿl°a/ß4-½•£UŠÿó§™áíøªPî˜øï[§ÇèÅ ,ŠÇ·oÄíôíï”èûøøÆ±Ù0LŸ1;¬»Ö¸Æh¿ý÷4q¼üÊ+š¦þµ×_Oýõ×_ŸÞxqö9ç„{ã]3ã=cÆŒIoÀ˜‹§žzj˜ãø×X˜PqáÐC ‡rHzåè°UVIvöÚk¯@?>ü%^V9;>&²JQFkêyÛÆ—¿ô¥0'>2BÁc£6 =þxº4“G;Dýë_ÃèÓØ±cÅroŒ€èUøÄD¯ú¸½Y#`Œ€0µ(Ï¿% _ù·°Ÿü;åÅÅyìI‡>ϵɿɭ•ÿ³NƒÔ3ÎsvøòžÆðsÛqZ”øW—XêÃÚò*ÀWƒsÝ<@ðòâú¬«¸ {ôÈa=æŠy­I9ˆþ¨@‰¬î§y … ?¹QXuˆ`©Óåÿoj1|p¸ç±—Âgþe“ÊBËÉÝ3>qóM7¥W}R¸òÊ+•8îwØ,¾bôßã…™âÝ_?é¤ôX‡ÜqâBE ñ*õÕŠÈr!çÉñQä¿XHÁn^”@î¦_¥;*X3#`z=1žÉ#`Œ€è_èç¿ÊÙ ù/ ¦¾¬gNM.L“=rʛ饣á„· ƒi«­±GaŒ€0+Ÿ˜XyXÛ“0FÀVE û²üRÁ€±rjúœòœZ|dÈ›Uˆ€¯¼]ù7½xäÔøDÒ¸’é$—æï*Lˆ_±o$ëÅÑT” X‚‚§1Á"Ë\2‡˜k35 ¬É6ѧAô¬¡ƒ/ÆÄ Pá3V\¬k.ùÈj êD¼oÓÕRkˆ…0FÀ´2>1ÑÊŸŽc3FÀ#°r(>Ê¡¢NÉ›¡<ÿeLSÞÎ:DÎ̉ ˆü[cæØ‘ æÊ¿é!ÖÉ¿±‰||åÛÌËóÅ—’ÿò¢ ü$‡˜eŒB8–S4W±Ar¬#Ï&´Qæl@A1Gކ M…†8,ò¬uÊvì¥dÐ#`Œ€0í€@gOL´ÃÞ£0FÀ#Ð}û¦´+"ÿVî]-ÿV~Nþ­<^3þÑU¾¯ü?²ªS#'&0É Òœ5mJ„\}øP^¨¬ìI9­1 ÈbƒÉÑKNþÀ†hØÐ¡ ÉYÈ#`ŒÀÊBÀ'&VÒöcŒ€0F u(ž˜PþK ÊÉyËóu­Ó“;«¨ Ü˜\Ò©ÆØ)ׯ6|æø@^$ÿô¹Ù_¶‘ÙèÐK±³l"G°U1)ISN*h3’™c[AjŽ …YÁfˆøôýûÄD‘ÇFÀ#ÐNøÄD;}ZŽÕ#`ŒÀJE bþ#Èsî|¬|»Kóïþk‚C¡©P@¡ÍCâ±)ÆôTè€ÇÆ™3Áƒ‡°'=xÌó˜´Ù‰Ï\>eW=vˆQëÉ— “0FÀ´%>1Ñ–›ƒ6FÀ#°B(æ´Ê{Õ+÷ƹ¯rmÖ•oÃc¬F> ¡KÞ­|9ô´Î˜ÜZ§*˜Ë®zåñÒ•/­G•¤“óáU¤|3ŠLä0i“ª`à³N#•.c6Ï:” d»°²ô§ø²Á c¨!ÿÅc/ ÿ4FÀ#ÐFøÄD}XÕ#`Œ@×"ÐPþCPî\ž£/Rž­¹zñe~SùwQ^vð©ü[UINª Ä6„az:2® ë8•,24(¤£Ñ—8Lz≭Å5ÙiÚöjü˜Œ€0FÀ´ >1Ñ6•5FÀ#ÐedO,OþÇG^Ý%ùw´«œyþϼ*Q0¨GŒFUl`LÃ)Eƒ¼¢JŒÖãr’=ùW_ ±Ž ü£+y>ŒfýG“0FÀöBÀ'&Úëór´FÀ#`ºâ[9”_·CþM¬åùMhò‚@5A ´Î'êŧ€Hk~VDþ­«dWyúŠÈ¿Éõ±#›Ä\•)L`ŒF° ’)gð°E“Œæ9€ JòÌ‘Ïù² Ocz@Ói‰8L¤uÙ[Æ¿åTî€0F Ýð‰‰vûį0FÀ.E nþ½“GW*4+—çߨ“Í’}`KÄ8¯!ˆß¡'¸z„!äX›‘az Ú ë€  ª¬¤K¢È!¶X“=ù¥—Í\6²“ŽäÑ_ÆñØ ²&#`Œ€0m…€OL´ÕÇå`€0FÀt ÙÊ¿é+æ¿‘¯|›ÜÒ¼^þĨj2FÀ#Ð>øÄDû|VŽÔ#`Œ@W!}Ù®ü[9¶òåòü›PšÍ¿Ñ‘=åÞMçßцb“æÄ]“ê Dm6©"Opp©€LNÈQ•Ay t0z²%»Ì‘G;õüËOM¾úu¡@a2FÀvDÀ'&ÚñSsÌFÀ#`V,Åë ”3çù÷2ùoôLÎ,êêü[~è«åÿäò¬Õ¤<èj‚Q‘0˜£§BcèuJ"· `4É2–Mzñ°dée;Kcä+ùG¿’tMFÀ#`Ú Ÿ˜h«ËÁ#`Œ€èŠ_¶7“ÿ’G+§&ŸfÜùw£ù]\òâA5a6!BžÆ¦8 A 4²Ä<Æâ¡'{V=|­!Ï8·§¥‚HÃþý(°™Œ€0F ð‰‰vüÔ³0FÀ‹@¿~)en‹ü;î<Ïÿ•×פ‘ÂÆ ª²¨@Ǭ©À€¼ì2f92*60Ï‹9²Km0Ö¦£‹Ô°& €ù§0FÀ´>1Ñ~Ÿ™#6FÀ#°¢(ž˜PŽÝÒùwÜ{žÿ…æ5a᱇zDÁ¢€ŠÈc><¤†æq©Ã¾É‹ÈÀc =ÙÀ.½òcñ‰O¹°òtú<ÿ–¹6c@Žœ}ä!x"ùE^>rÿ’S,¬©^€=ÉJn™^F—YÈÑI6 Òf™¨6­—;×\›g® ¢«11É6± ò ….ýlÖ¦ê¡0FÀÖGÀ'&Zÿ3r„FÀ#`Væ¿äÕP³ùw®·"òoùW®_ˆªÊÏF ¨JN 4œˆtªžÖŒæôØB–1„Œt}xŒ%Ã:$€d¯Qÿmÿ4FÀ#ÐFøÄD}XÕ#`Œ@!P| €¸ÑüWù2}wäß¹ÆÊç«"¤‚CU¸ =òåsmVeS|äÕàÑ(<ärù:|šŽ— +6Ô”ß13#`Œ@["àmù±9h#`Œ€0+ìu¡äÉʳéÉ󼚱rkåÍÊ¥s9ÉÈk+$ÿ®á?.U'W]¢°Ñü›€ØÄ'3d}æèk=ó¿h‘Ü¡b2FÀ#Ð>øÄDû|VŽÔ#`Œ@#ÐUù7a¯°ü;Ú*Ïÿ©Ô¥F  ‚Œ’íç¼¼`€ vÕe,]ªÂ½Š’Q‘YÖ§Ö®–ôЉoV‘»83#`Œ€h#|b¢>,‡jŒ€0F ‹èߟô¸fþ«Ü›¾Ùü›|{yóïZþY«K E+’#h2} ´ ¢"½ŠSH@OE éDV"ù G@Ñ…´†Mlk4ƲŜ1r´%~”#¢`2FÀ¶DÀ'&ÚòcsÐFÀ#`V( ò½|Íü—<¸;óïFü×ÄD -!œ¨H@Á %ü±W€5ñâ0è!äñ!=EOÓ³–,à!bÎ¥—ô*:0Ö¼¦ÿâ;_£¸É#`Œ@{!àíõy9Z#`Œ€0]@ñËö†òßè¿[óï2ÿª#Ô…¥‘ÂmŽ"€Pˆ€#ñè!=f„®šduTDúè0–/éÒÓ<úø–¬ô‘«èß…‰ˆŒÉ#`ÚŸ˜hËÍA#`Œ€X¡¯'h‹ü;n<ÏýÁA9}MLPªG$ÿ:AòO(è3§W1!·‰.§Ї$_2†°£¢Ã€Ä)ð(Zäþ±Á:zŒOEÿÈT”4#`Œ€h#|b¢>,‡jŒ€0F ‹(>ÊÑPþCèŠü›ƒúWþž× ”óWE(/"TÒ)ÖsƒèªàÇFO¢ŠTPPqBrZ—,öu‡kò^îùŠþýV`3#`Œ@;"àíø©9f#`Œ€0]‚@CùoôLnM¾¬Ü™`–7ÿ– åÿUóï¢/üëpté«Ö# ’ôçM›D_ÅÙÖ –5ôXËÇ_ãC6‘džh¹üßù*[î€0FÀ´ >1Ñ6•5FÀ#Ðedošl&ÿ&§V_ž“{wIþ]ôIœªÐã¿&©˜PKC1ÏçÕøØˆr>ÇJk"Æ ^:ØQ1£³þýV!ìÞ#`ÚŸ˜h»Ì#`Œ€è*É¿‘‘}µü›µ®È¿•˃>TüPLð+R#… ŒSL€(6 £MÀÉsœ#žN>è¨G®‡ ëj*XÐ+.ôd/K²¹ùÖf%ÙA×dŒ€0F ­ð‰‰¶ú¸¬0FÀ.A øBòd¨‘ü·™ü›œYysgòoÕ ”ÿ_ž‹Ë6±W%N$Ô# ¹³¼€ p!æØdC àXI޹ì \tC¬qs¥6‚í\>N“?ùÔ_øGwq£r :}“0FÀ–AÀ'&Zæ£p FÀ#`º âëBñOî«üWÅòoŒÐ—ôÊÏÑQþMO>M\žw#ÏšòvÙɾ!ä$Ã8ÏÿU@*Ïá ܲŸJúËØ¦¡Æ‚ 3&H3†§G0˜‹°‘ɦ¤ÏfXS“,ëò-úâR€^kŒ«ùgÍdŒ€0F mð‰‰¶ù¨¨0FÀ.C û²\j$ÿUN].‹þÊȿ埾.5Z˜ ˆ€¬Œ3¦ ¾6«u挄Ö#+ µ0"I sÙÜ'à!GÑCþéiÒa]sùˆ,“0FÀöCÀ'&Úï3sÄFÀ#`V4ÅG9ȿ͕ŠòhÆäßyž\/ÿÆNgòo|ˆrÿâ-Ó³±z$£y‚sPp¦Í#ǘžM ,s6 ä8Ø) yÖ‘g yZCþ³c/QÅdŒ€0F }ð‰‰öù¬©0FÀ®B oß”"7”ÿÆêåßʽé+åßÊÏÉ¿•ç7œý£«|_ùdU§´ÃêËiƒó€´!Ö´)ÆåòZ§×#øEÀšÃËÇ€-ÿ‚ÿ4FÀ#ÐFøÄD}XÕ#`Œ@!P<1Aެ<™^yòŠÎ¿U#Xžü[qb‹ød3+S]¨¦bA“JÖœè)@(xøQåEcæØ¦1ÖùòDV"l깚"«ÔUôï%|<0FÀ6CÀ'&Úìs¸FÀ#`Vóßè¾[óïþk"C¡©P@Q€ÍCâQT`LOÁA…x˜3Áƒ‡°'=xÌó˜´Ù‰Ï\>eW=vˆQëÉ— “0FÀ´%>1Ñ–›ƒ6FÀ#°B(æ´Ê{Õ+÷ƹ¯rmÖ•oÃc¬F> ¡KÞ­|9ô´ÎX‡”_Ë®zåñÒ•/­GÉf·W‘òÍT(2‘à ¤M¨‚Ï:@T@@VºŒÙ<ëP^€íÂÊÒŸâË+Œ¡†ü½4üÓ#`Œ@!àmôa9T#`Œ€0]‹@Cùo A¹syþ¾Hy¶æêÅ— øMåßEyÙÁ§òlU%9©*؆éièÈ8Uh§#CSB: }وä'žøØP\“¦ýg¯VÁÉ#`Œ@Û àmóQ9P#`Œ€0]†@öÀòäßy|äÕ]’G»ÊÙñ—çÿÌ«R~j¡šSXÀ(ÅïÀ!¹*!Ì5V1#²’®NK I± ŒYÇg^Œ_^o¢9?d;²’úÜ?s“0FÀ¦˜2eJSò]!üøã'³Íö]‹m#`Œ€0+â[9”ß*¦‡”+kcøÊá!¯¼^=|òjä¥O..›ô b!+ÿ’GÍ‘e _<ÖkR#…  dHŒ«0Àš‚Á¦tј „ŒHÚ=Óÿ$¢P$Öà¡1®J&ä@łܘœÉ!=âœÆ\Æañ· PQA@ä›)ßsšüçù?2ØÉÿÇ1·ËzEj¤0!à X`16tD„à ‚ƒXWPB›EÀhÚò<®!_ðÑ—®Š²KOÁBòZgžUG_€Ñ0#`Œ€0F@E‰ ~ýÄNÛ驊ï.ìyµ‘?+[>[NÁüí ­_OŽ(Çžš§oz+=:¼ð S’™ŒÀRtB-rÈó‚y29°· ±F^.ž ÈCÌYS><öiȰ¦$ÿÕòùB¶Ü?¼ª„p=Â8 òàÐSðŒµÎæÙ¿ZØ$|š*)Ø@5dr°ÐËõ‘Õ:ã¦ýgbT7#`Œ€0F yH\oûÇÀð«Ç‡”åÐ#îãhZ;a?=#„/ÜÐŽÑ·wÌ9ömúŸÏ ý8=AaÂ'¾W(¬=ÂX–Ó*ÿæŸ Mùryþ;›Í¿Ñ‘=åÞMçßцb“æuëꛄŠB‚z¨°€ ÎX1¦©8_s‚DBW¶dŸ9²¬¡¯@>C§&Íùè/lô´Äœø|—É#`Œ€0åð­î¢Ø~‹ŒM=ôÙÆ¿ÿë®fùQþ•úÁ–c¿(~}â_ú½ùÔÄСCÃŒ3Â!>•µRÿclgÅb•þˆüW94cù/såÌðá‘OÏM95ºÒSþŒmñ”¿£ ÑKŽ9l@’Ñ;¬ÁgLŸû‹ÓÊ„Óz$£ FÎ4×ó “‚,$Ù|Cè•ožudåéJ^`ä|Æ)cšŒ€0FÀ4ŽßJð@öíDãÊ–ì±,ZÒ'Ý)Ñè©€ â;Ädžᯯ„p×ß—~£"Vk;½'„ñk„ð—i±Mgqù+§H­ÂÐøWÍC‘_öÂ3ñ[ÿi³êI¶Þúo~ó›tàÚk¯úõë&Nœ‹.¹ä’0xðàpøá‡‹µB{î ¹ïÅŽ]7ã`êÔ©é>:÷¹püñLJM6Ù$g·Ü8Çžqþ’o‚þô§?¥{P{ðYo½õš°ÐZ¢<¡þß Öúlº3šìMžÿ’oó¿ôäÒúèeü’œRX¸óÎ;Ãf›m–p9í´ÓÂ)§œ>øàeäËwÜqGøøÇ?^În©9ÿrìóœÆþ•¶òŸÿùŸaÁ‚“z»Å®»îÎ?ÿüTÌZYnö¿»ZqeIh-1¯õ"øo¢xïˆ Åÿ%I (ÿ…G#·&çæ7sÆÊ·µFÏZþÏ yÙÊùäßv¤£¾tàA²­ß¨ðå? Tû!GÕÖáË(N BOº L‘×cÖ™£OÓ[Ì!Ì;ÒG6÷Äz.ƒŠþ]m.“0FÀ4Šßd’˜Œ@Ž€îP¨×s<ý?b‘áÒ¿„0éÒ¸"„MaïõCØy½øGM\ß8~I~V,$üòá¶:/„ÿOÛ]ÂŒøTéÅûÇ£Ÿñ/äø#ˆVÏ'ë05"Û•2)&Œ1"|÷»ß ·Ýv[:!ðï|'\{íµáøC“–b1èùçóÏ>Û”xP0RѨ)å¢0§("L™2%Üpà aÛm·MÅ‘G}´ƒ¹[o½5Ðî¹çž°ï¾û†sÏ=·âï›x ÜrË-á—¿üe ðqã7†ÿßÞ½@ݺÝu}_@BH \b€ ”X„K…ª4JQ5ÒQ¢t@-”K^ʰE@´(‚ c¶ b-ÐÐâ‹”ªXƒ–Q‘K („[„ÄÂ-€ôùöc?öð…_ø…‡ßø–ã·¹~LVìå 9œ¨ï|Ù—}ÙáÛ¿ýÛÞÂy$éÁô»G²~ë±€5‰ÿ4ÙèZûßMÏÓD÷õ²ÿ>‹¿/ê#%Õ¸+6 o9¤WcKñ;@X}Yüõp";þÅÙçÔ-ýµí⻇N7‡A`®€ÿ•°xÝë^·ÿªÓÌ#׆î ^±ÍëÒ'm_¦ÿ”'ßµ}4#½ïø©Ãá?ß(|Á"ÞG¼çáðÛÛŸõ­‡Ã/og`x¯üÅÃá¶7*Þ};´xŸíS xûFmKós§Ôˆë2~þÛçnom|üáð}Ÿr8üÏÛáÇÛ¿ÅIW}¾åã‡ü´ÃáKŸw8|ΟñŸœä—ù¼Šw¯ÀÁ 7žùÌglÎÏÉóøWÿê_=|è‡~èþцOþäO>üôO?ëò™Ÿù™‡oþæoÞ>èƒ>èð’—¼äÜüʲï7p=ônïön‡ÏÿüÏ?<ëYÏ:|åW~å¥.}4ã?ð¿ò+¿rð†È9ùu_ñqèS>åSö¶w0ñÊW¾òð©Ÿú©;Ú+æz¨ú/ÿå¿<üÁ?øïû¾ï{øâO¼ÉÙÈÔG}Ô.ûcìí!S¾lð?øƒ?øðþïÿþ‡¿õ·þÖ~P¤¾ÊŸõYŸuq8{¾ßïýÞïàMotxƒá&ôPaï£êîã+>þ‚VŒž÷¼ç¾ú«·ñý¹?÷çŸ÷yŸ·Dè½ßû½Ÿø‰Ÿxpô‘ù‘‡÷z¯÷ÚÓŸú©íá½EŠ`ö>ïó>‡?úGÿèáÿã¼K®êwWaœ¿I;!`¬óq.kkcãFöÓÛˆ~±¯nÔjŸŽ2Yüë¸öÿü_I6üw#€ÑǵCŽO^ÃW06ö…ÿ†ÊŽ®<_å•å‘”€¿]›ê_|:l*§;é 0 ƒÀ pm|ñ˜Å€ß”·ÐŸÃ‰kC÷§xk1¸·ë:¯ú¿zÛcþ³?>ÿC‡g¿Ýáð—)þÅOž yÎÛoß9ñÛ7‘Y-ôÃ?{8üÔ¶w|¯MþÏü(Ø4VA× —ÕñÓ÷áð±ï»}\ä› Ê_õ‡‡þŠí{0žv|{ã ÿùáð­?v8js8ø^ßÿûÿáU¯zÕá[¾å[öÃùÓúO>îã>nÿŽï©ð1¿ñ ˜ÁÜAÄ·~ë·þÔŸúSû-—õ»;a,ÖMÈG“†î?¼õßÄòó±ö¿öÊfÓCåuÏÜ^xß¶ÿÞ§Ìø0Ñ•'ËÇ–Ýíòmÿ-âÑ/þãvÉiÿm?©'ÊþXºâoŽ®_°«°È«8ªrò*Qpù—~6ÒU—Meºù¤— 9r œdtkC>€”NõÙXCƒÀ 0 ƒÀõ°X×7Í7X¼%pòò?Ú>ÆñÛOPn›ü×nß…þw_´½‰ðo‹œÍÇ;oû’ÿó‡Žùs?ñšÃái›œžƒ†íßž?×»¬Üç²ß¾ÿð þùáð/>Jþä7ÿß§ÿÁÛò¬ÃáÿýÉMþÿeßóÓÇœ\åëÜ÷CQö+>ºá‹/å}lÁ¢Ü[çd³ýIŸôIûÆ’ì¯ü•¿rxîsŸ{xñ‹_¼ƒŸ[DÞZ¸ =”›ãâ>ýéO?¼üå/¿x»ßÿÐûŽ o/8€y›·y›K¿ÓÆ—gúß}_˜éã\l– x“á‡~臾·ÂÇBú¢Prß³y“ÁGLÐ _øÂÃþàîy›qºEÃ(!~çïÜ:ìFÞÎðÖÀsžóœÃ_ûkmß°{«Àå€ÂGLøh Ò–w|Çw<øžøØy×ýs¯ØÃH›¼yò¢½èð.ïò.{ߺè3>.„ï-º&Ї}؇>äC>dÏëGî‹·L>ˆïúè»K|‰©/&ýGÿèþìŸý³ûw‡Ð«ßÝ ãßû{/Õk“ƒ•¡AàÖØ¯›|û_eWûãö¿í£¥öØÈ”âjÿmoòIF_Ê·Ôþ»ýü–Ýuó×þ;lå¥][v'6Źź=iS;÷ö’ q$ˆô¼¼M¾©í•YËÙ‘å+=2W¾Ø¾zjˆ‡üHé°¡/UŽvþu¿câÛ¶{hA`«¸îÿ¨û"E_Déú÷¶Lü—ÿá¶ù{îáðÒ{8|ùwm™ØÞŒø÷·½Æeþžµñ¿þ_e¬z.Ó»¬Ž—½1ñ¦ÛÊÈh¾øgN~^±ýr‡/å럼}¬d; Yc¼tû˜‰Ð+ï²x%ÏǼ¥äp†Øïú®ïz[øÉŸüÉÛ~™Â[#üo¸ãƒ¥ý èÁ_aç».|$E›"›ä¾ÈÓÿª;ðf‡/û<'›\8¸¾÷{¿w?ð¿ö>"À·/|ìP‚­ÍòJ "‡/}éK÷¢Ã ›ö6çéÀ¶ƒ‰6ÃÖÑêï£'Ñú‘Î|ññáe/{Ù®ccï£#7¡{ÅÞÇ]ÄüþïÿþÃw÷wï=Qß5|ì"ú…_ø…Ãoûm¿­âþ6Eÿ;}U;á}þ‹(ÊúÝet'Œ/ÓÞ p7nLší{ÛK+`¤®}ÿ»¥VÞV¼8Pè#9.Äž-ÿüÒ•*“W~-oÅV>ÿ±½#]ç`BEk@à´ ‚VÙE?;‡ •éÑÀ|Hñ¤ä‰ÔQy•“eK?ÿbâWÞÞâ’=’ÁÕM=?¬pú;4 ƒÀ p!pÙ|p!0­½)6þw#?ú‡Ÿ}8øhÄë¶%ˆŸïü_¸ýÏìoÝþ7u“ññ½Û[ tÞò ‡Ã«·‚Ïü cþ›¶7žú懃·Š%dù»Åvq®ëW?^¶<¼ó[Ÿd~¦ô­¶ëG_µ½9±ý”éG>gû5„mµõËÛÿ‹=y«“wøyÓs_w‹ÿ`åþ7ÛkôñqG>f`#nÙ»üoø½ÿµÿÍ».›¯Á!|÷ÂUä»l /ÛÜþÃø÷7>üÃ?|7·VýóþÏïÿÃïm‡6ÞŽðч3ÈÇ9¼¹àM;‘7ZøxÃ9­o\œËÎË>êæU|üÁG&”ø…‘õàâÜæ²ò½bïã-ú޶{‹Á/rø ¬ù¬—Õán^sÝ ãËô‡7\7º¥gj°É]G­6½Rûfûg{co<¤Ç.âË>;^útW{zt¤å•éI/Ûÿó›¿êÅöŽ”£;)U:5J€œãUÉtøí¢+Ÿ­†"~‘Ô¥òéh Ÿt/‹O÷NñÙ‰¹ònC~; ½uÚ´‰†A`îgÌæ…¡AàºøŸÝ»]¯xíñãŸ÷!ÛLno#ÝmŠÞI äŒäxòô\¿¹¾á×éî|fxCfhû é›þÏÞ}Ù}ßüëìsÿíöÿ?ü5‡Ã—mÿÑí#È/o|Á?;þþö…’*/ÿùíW:¾êpøâÿtûØÆÇl ›VV›ìËþÅiƒì ˆßñ´í; >‘—=çK¶…¼úT–£ûß}àñJâÍŒßý77Þÿu|#C,/ÚøÿÙÿz8üÒëŽ×ÿíã/…âñýÿÍvhòíÇ£¤wÝô?ûºš÷¦ç£º6ì>>pNžqßWqƒÇMu?8rPóO¿ïå‡×}ÑöZÉ£ˆ´Ó…ï¥èã¼zÞÖðŸn;nJ~™Â¯D¬oßÔ‡:ú8/ò¼ cÿêÏÇýííä!'i£Ã”{¥×¼æ5;fç~®êw7ÁX¿õFøœºœÇ›òý…€C³­_Z31\Ñž|xÎ6òÇ(n"êpÀHÝþ»}²}1¾ OjÏÍ–.¹T¹}³2¢‹'†<¢—‡"ù§ƒŠO/y±óÉÏ•tƒ‰Õ ï\Å“­ §qt]*ˆG7póSå;ò¥xé¬v&-&½è7œûç•,FgAº"2ùA`A`¸o²­>Þí­ãð}¯¼ÎÒéNž®–YýúºêºZõ!“¼ú—oh|À»l¯™nß?ñ’{8|çOm?ÿØõ!‹ôèuô&ÛÊñýžv8üuÿ9ôˆ"°b/¿“ïqÈ3oKÜï=áí¿õQŽöߦ ûß6¹žžfiz[vßÑÛg³k„·¯ÆwÙKÛoÙøváçWŸòíÅ«~¿ñ·ìåtÙµM@@.ÉŸûUQO‡-ÂÇ«±5ˆ.´ew*=6äìÓß²{üíÅÉÿ&ë¯r ƒÀ 0 ƒÀ pü/îãÞø7ýì_=¼è[Ï—87ñôèÔuñO~ôÑY·G¢V¾ÛÀ€þ®w~$¢MŒ{ùû™|qªÿP}0ɹŸq»ÏÚÞþW³í=5öÅöÈí¯·ìN—íÝñÚ?SbÏñ—ÿöádÉéÓkÿÝSK§ÉQ}\âHÓÉ÷ƺœrp¹ôÈ唣œÖ€,_CU.>ýìåñ]xR6QzÒ(ŸÊÕ:ù(>ùâo÷bhA`€ïgøCÏúÕÃw¼üq‡ÿý_û4éÐþ·ÞáÄÐ#ÀýŒ½·º_ñŠWì?ë'M}ìãÖ+ûü˜ˆj–~aÿk¯kÏÛ^ZÞ>²gv¥Ó¼”]¶[ö6]eûï|(£$Öý7~{õößälÓ“Ò¹ë¦ü:C0Ç5rË^8]Wùä*€ð«} òšH@ðè©‹òê«ú‰_£¶ì®ÇÇj¿ÆtöáU¨9œÙÐ 0 ƒÀ 0ûwÿÒá·>å7_ûO8¼äÕoò€ïlx°þëv~YäÛG]¾ñ¿ùQÝ”»½"ÿÝßý]êú?–+w7ì¿ç{¾û±Ü¼×¾Œó­ßú­÷Ÿ¹u01oKÜÆûÍ ý·ô|Þ^Ø~;=ûje{f¼ø[vϳÉW:ößì:hزv«ýºgÇ/~ûöì”ów%µñ¿RaTÀN]è¿ _ã}”B%èˆ ÎNJ.E+?úr zHZ£Ó¯~R2qô¾è‹¾hÿ¦à74 ƒÀ 0ÜÏùœÏ¹«Î( :<×ßúÒ²‡3 ƒÀ po¼å[n_t¢uï-oÿmŸÜ¡€ÏÞØeßl¯Œè±‰ÚCÓÉŽ¼½öª<;~äí¿ÙÓW¦#vzdw$ÎïF9O¯ „ Zðª€|zUŒ?ÄOW>èÈw°¡AF?{²ìåÙêãÿÍ¿ù7ß4oLìØÌŸA`A`A`Ç>Êñ¶oû¶h«ööõÄ_zéðÁÞÙÞ»/”GÈ:Àwá¹ØF(ôR~ö«NûlööáüI‹“\š¬tcízÒK© ý¥Â[Ì*¯XC*¼Ž×Ç5ØFòéJùbßáƒ2~ñäó§Q€È?*OF±q°Áßþ1Ž÷A`A`A`Ç,(¬ÜöÔÒ•ÚgCÖþºÿüÇ»ÓþÛ›}{my¶—ÅÏÏ&Þ©øt÷½ù-þ¥Éu&8rqªRU¯|S®¢*ƒ”ÉQ !s€@&Ï—†JÓå«•Wgù@-^òÊüü¦C‰9˜ØA`A`A`xÌ!pëö¿ëþ[;Ú+·§n_Ý~œŽ½u‡ößÞŒ ‡ðó¡¼î©Å³3ºä®Þ®È¶xù•²GâósG*È”r5Z…ð”;l8çó5]¶ìÙ‰CvNÝ€ÕFžëªøÚö87q&6$†A`A`A`sÜúUŽö¿í©ûøFûj©=pö×éhszø.Ô~ýX:þµ¿¦ë"ïPA|Ôþž<]ñ×ý;ÝkÑu&Bk… ^å:Tžë³­áÅc—®|eºHòÝaE ä#ý|HÓ_™þv&1oLl8 ƒÀ 0 ƒÀ 0 ƒÀ 0<¸õÆ„=® µÿmŒ·æÓ[ È‘ýrûùöîé“·×N¿}ye:Å—æã<>~¾äïxHÑAÁ¦w%qRE;1é`5ª"R~³©Ò*ÂÛ*•ezì’mÙ½!lPòõè(9þ·úõ »d¾ür…iòƒÀ 0 ƒÀ 0 ƒÀ 0 qìí‘íŸ;€ÀSv `ßL^ß~Ùþ:½öíô]z•é¿n»è|¿ºŸœOºw¤ËœpìjÓO®ÉPÐôU¤rºUŽ>RA:.¶!Ž´8t÷øs0±!14 ƒÀ 0 ƒÀ 0 ƒÀ}ˆÀk^óšÃŸøÄÛ¾©¤8Ñ/üÂ/÷¸Çžð„'è\EoýÖo½ÿG÷ÏÿüÏ?@…ß7{³7{eüÚ¯ýÚ­ï>|ó7óÓžô¤U|­ü­7&èÚ·çí !¾]´gî@bcí{müH¾ý7^{p{j{v¶öÓùêpß^›Ndt]«uÿ¿¯¦6þWk+)HÁFU^Y¥*WAú5>Ût6Ñ^iññø—&—ÖøŒ~Þ„>¾‹^~¶ìm½Ñ|ù%H†A`A`A`¸ÿø‘ù‘Ã;¿ó;~Ëoù-·5þ¥/}éá­Þê­O}êS/yÉKv™ï&üõ_ÿõýÀâÖ[ ‡÷z¯÷:üâ/þâá‡~è‡nã3x‡wx‡ÃÛ¿ýÛßæw-8øáþáÃãÿøÝ–6O{ÚÓVµëæÛä·ÿ–"ûoyWûïtDxíë¥ÉØØçËî>Éù–¶Ooÿ}¾ÿ?·oÿ/Íÿ–½š®s0qîH9^ ˆPeð’㡵BkLü@a×C~×XüðG¿ÒbH›úÍ9˜81A`A`A`¸ßpØpÙž0žC‡è—~é—ÿê_ý«Ã{¼Ç{ì‡ a•ýìíŸîLtǯ xÙË^vxò“Ÿ|x·w{·]ÿgög?þã?¾fœû¹pxIÆ[Ùã¶OVnÿÛž9ž²}6yûðöÇ^H‘ý÷z‘»Èþñ'ŸmþñØ)¯TVûU~[~=$¸M°p­ ¬N. ¼ŠÒ­LWÉ»ToÕߊ;_ZãèåÇÛ@SÎ_€U?¾éh—ëëD[~hA`A`Aà>B ý t%ZħoÕO7YúwK½}ñoñ‡>öÁ¯ƒ†Þȸ›òE×¾·†´O¶ÿE•åí—éµÿfGŽ×áÄ–Ýóxd(©ýô~"²¥«œ/T<þä+“jÿ,]ñ÷:9®Â*Re¤|ƒžÊ¬ÓKƇ ±˜«FÐwQ¬b“ãÑÍ?ês0øûaÄ–Òë¢#È ƒÀ 0 ƒÀ 0 ƒÀ 0Ü8èZ[O­¼ËøÖ7–ï~ÈÅm©yøÈ_ì¼1ñ6oó6ûÇ:Vÿ·]R¸Ó^ÙþÖž×wI {`{äöý/ÁFí¡k ôÉíÇÉÚÏ·''ã“L*nûz)}¾è·'/.yñÈð+oÙ«‰Ó»Ñꨊ¬k%éºò«!URº6P%$åìùâ¿oÙýàBü€Hg¡/Â|ÜMOµA`A`A`xì#Ð~ðü @¹«V*_¦ÿE/zQª{úœçéãW®Ê.eÅÙ²üíÞÿÚÁ/s ƒÀ 0 ƒÀ 0 ƒÀ 0Ü_8T°<߯[ùòé¯oCÄÏ÷|Ïý !<üê¯þêþ½ñ¤ïú®ïºÿúÆ‹_üâÃÛ¾íÛÞéÞi;ÀèË0}ñæuȡĭ7&ì{‘½´½¯½°|dÓKgÝ—+ÛO÷¶D{ê6Èí³ñãŸ𑞔žøòÕiËîùüK]ätó½e/§ó —iqÆi•)˜2Òp¼øL§Šžë*× i6çúôâ°òzQ|~è“]Ô÷—ù—a»‘OÞxCƒÀ 0 ƒÀ 0 ƒÀ 0 ÷~&ôµ¯}íþŠšíðaÛ'ÞîíÞî¶·ð×kÕÇï ˆ•ïÍ_–yN¾HÓwLôs£ä½I¡>¾ó:ä€dû5¯d´ïm_lÿkßk/m/Ë^P6ô‘?{<ûètùl^ž¬½yztŠ/ŸÏ-»ë–Ò¹+]ç`Br¶V‚óÊtP•=–N'9Ùk¼ƒÔ¥l‹Uò+?tªÿ*ÇÏÏmâç·›þdihA`A`AàþAÀÀË_þòƒ/žtHàzeo"<éIOºí`ÏÕáD()Çw·ô OxÂ~á—9žþô§ïùŸû¹ŸÛß°8{'_bo‡(?¿éø8…}o{ßÌ:`À·_¶ñu)KñPo.HÉì™#zÊ¥ñÛ÷fFûìäÙT'úò•¥í÷³¹4mc©ðSå ]åð`xU‚>¿øÙÖøu_Å×Ð*,å åCl=òéˆÁ&û5þë^õªW½ò‰O|â;éHCƒÀ 0 ƒÀ 0 ƒÀ 0 ÷O}êS÷ÈŸø‰Ÿ8¼ä%/ÙîÐà™Ï|æþ±Œór(»Î?Êÿ&ûÊg<ãq¿ïû¾oë§I}¬ÃÁÄ÷NwÃ/rl_šùÊMÇ>·ý±½°ý¯ý1¾ýq2åöæñ•éV.¯¼î£ùèʆ\­2¼^ S|zdéJ•ÕëJê`àJ…M ˆ qŽ_£ñ¤Jà•'K?0È™z(wð±Z°#£­#Gkü#gûÔÝnþûÎA2é 0 ƒÀ 0 ƒÀ 0 ÷~Ãåû |ÃÇ/ÐùÑÅ{¿÷{?@æ á2þ®x‡?ü=ëYϺx㪸wp±l‡?ºé8Lh,mÞž{•Ù¯ûëöÊûbÿÒöÝöë(ÿòtÈ;ÐÀk.NT]ÈèóÁ_º[örºÎÁ'*Â!ýœ "™ ?ñjÔ&º°Ó˜*LîªÂø®ì¤ü«ïØX;(Å«Ž~j4uøÕïüÎïüÞø€xþy§ã`hA`A`Aàþ@À èõ±7ôÆMãÒ÷ßõ]ßåç@~i»ìuÛkÛ#Û;£öãí£Ó!³ÿFöÌäl:`§‹JÛ“LµoïݬøÕ/;zw¥*~'E:®w^ù58?ô:°PN^ŠG®¢ùJ-‹‰ð«Ã±7üÒ!w!zél‡R{§¯ûº¯ûëÛ·ž>ó¦a÷6A`A`A`GoXl_Mð’ç?ÿùŸ´}‘æË·ð¾gÙKwÙøÛ+Ë·oï°Ÿ|= ØŠ»îšÊçGž=íÑóG'â¿ý½|r©2â㎽q°k_ñ‡3Ž­RUXY¾ ém¬ÛøÊU2ÛlJW9^‡ø5T}«O)]q=”/ß„úª¯þê¯þ;ŸôIŸô}è&Ÿ :ºš¿ƒÀ 0 ƒÀ 0 ƒÀ 0 ƒÀ#‡€œøu{ÙmOûê-ríƒ×T¾²ˆÊöÊ®öò$·n/M-]ûjùöá«}±ÿO/=e¤Œø¼#]ç`BE¡@Ò‚hTâÑWI©·¤ùÙ²»Œ]úRúRüNsäÙ y nÙ”é­ Š§mì^÷‚¼àÛÞýÝßýøø‘nîu¿hd³A`A`A`1Jøõ¾ð…/øÚ¯ýÚny nïk¿+ERû^{åöÍ¿¶åí¥öËí£·ìNÊý§?;útíË+Óã_êBÊôP¼öûÙW–¢sWø€}ŸD¶ôù¯Ü!Gº?ÿ¹Ÿû¹{ûFÓ÷Üç>÷£|³©Šy{bClhA`A`AàQ€C ômßömÿÛ¶‡ýÊ-ëm áholmŸ[jÌÈ^XÚ¡B‡xí•·ì®'Íž]‡ù)V{øöêtñÈ¥êQ9~“oÙ‹zË_IÝè䏯J]HåQ“'cƒäó'¯²ìòc]ðÓ¡_ ¾H |äŠòÒ|I]ˆý¶ë)þáþÜù˜ù/¶ß°}¦7':¤ 4PA`A`A`x¸°µ•ú> ©ï”Ø>¾ñw¿þë¿þÛ¶ø?·]öÀöÆ]ö¸öÞ Èä]ò.ü•ÒmÏœ%ÿùO‡1Š×¡E1ÚcWÞTw›lÙ#zÅä뎔â•áª/  ¿ U ©Šk¬¼ÊÐK¾ew¹Š‘uà°¾ñ ;T,úx]Ù¯iÁ ŒR¼·ØN¡ÞòyÏ{Þoß~òå}žö´§=s;¤x‡7{³7{ÒŸøÄ'ëë7¦êu˜õà"ÞyêMŒ^½Ùb]P~Èùç+ñò5ñOßXn+^@ «ótðŸþ7ÏßñÕ¿‹ÁçÖóâYi¬YŸ§x=K3þÌø£O }¢~Ñ|_9Y錿3þÎø;ãï:V4^#škfþ™õ}¤>Ñr¿®?¶Ÿ/ý…×½îu¿øêW¿ú/}éKìE/zÑ÷~Ó7}Ówmÿî@âW·Ë¾ÙÄì’·î`AÙ>Ù^×ò(~6äÙããÑ˧¯XÒöâ[v÷ݾ>Y©=vûÿt×4¿xWÒì*%Tb­]ü ñ‹GG¾2žŠ¹äÓ‘¢Þ~Ð0y|i”²7 Äw€ÖXòˆ¬xÕÌ[üòñÄí£‡/]ãw@¢.dn¢[û•É"±^|ö.2’ÇgOÞÅÿyÞOÒ—ª‹‹*/¾þÈÄp¥'­nñ“á«»rñÅÓ~ºüòŸ¯váÉÛ«ªKølÙèòO‡L)'+æ.¸ìOF—É.㵉.°T$pep!©F’­vòüÕøl7ÖÅYž½.~”O¾zIñøBR»dçþÔ;[Ô|ñò“½kmÿVÜíJkeiuË.¿µS~•×N¶ñåÑZf·^ìV=úH½áŸLÊŽ~öùÝX8Ó‹ŸíZζtâŸ0†S4øOÿ›çïôlÌø3ãïÌ?3ÿÎúcÖ_­[WZ3é•Kgýy\M®x„]鬿Ok 8E­¿+¯ëzð WùµÿY·¡ú_‡xlV{qìÈ"vÝ'¼ÖƒtäW¹XÊ(¾|ºü vÅ!«Žä«ÝV¼ð—-}õUÎï–Ý •æ»z+g»+nðÒË.Ù¥) ¯CUTÀ‚T2•’"ùUvU¡U§…?ùô·ìN|°•:$(ý|&—òÍZ}²#ÇË6ùÆÚ‰ÜµÆ¨®R‡H]\+‘³«³Éó·»tå×Xò.T=ó'Õ.ü|ÈGù¤—O¼Ú“^¶ÊìÓ-_èáåW®d®•Ò›ø'LÿéóüÆ4ãÅŒ?Ç1¹Òò3þûËÌ?3ÿÎúcÖ_­+gý9ëï‡bÿ¡¹9¦ýOùæ_:xíg”­åŒIøÊå·ìžϛ|¤ÓþnãŸÙ¦K)£5¾2›»íÿ豋شþ̯¸øH¾6•O_ÙÅ_ulÿ‹¯¾ù”Òc›þ–ÝuÔ™<Ýü’_‹ºéwSl­ >¹Kø$O‡Mòül¬Ýý¨|úøxkyÏWåüŸÇO'¹4bK½ÈÖxµ!»âuCò‘úòÒnV6ÒHLD¯øòQñâ‡\^'Ë{y}©Ø®•Ò)}ÞªO/YåµÓÄüõ 4ýož¿Æ–füÕfþ¹}>5NöŒÌü{œ3`2ëÓkÖ_zÄ‘<+³þ<õðŸYßlýÝØŽ­YÛßH×çÏþ«þsvtüeø“å—|õG†ÖøtéT6QzäôtõŸ{yTž]þ’iS6ù¤_|6«îV¼­ÍʈÝö¨x«oùü’Ñ?÷‹GºîÁD álÍ+ `ÊHåª`SY`á£l²Ç—§'EÖà¡øòéË#²äÚu_<€’ÉËî„Ï~½AáSüì¤+—ùŸ¯hm¿|6RåÚ“ >žOšî–½Îëñ)³ ÿ5>Yñå×øµ_=èFÅI6ñ})\à4øOÿ›çï4.{¢ޏÀcÆßc¯Ð?fþ9b1óïiýÓãˆÌñoól²YÌúC¨_è%úÆÌ¿÷çüëÞë }'‚¼«ñB~ÝkmÅ]fþ¡Óø›4Ê·r>õ=¤¿­1êü¥›ñQ±ð«S~ÎãÓAlP>åÕ!_Êdë›Ù&+>=D~>ÿÆ'«ñ¤_äÅ(_9½+Ó_©p& _…J©¬Õ0z¥dê!™Êç¯nBüu4¢/Oÿ<~:âCª\]Ö8ò«?öµ#»n,ÝüÊwmÙ‹:¦Ã†});+Ÿém¬ÛÚ‚_§(_‡Ì†òìk[vÅÒñÓí Ï÷–½ˆ/ò“;¼ü„=?hâñ ·Áÿ4ùOÿ;=7óüÆ÷ÆãGã‰<ê9JgÆŸgþ9#=/3ÿÇ‹YÌúÃøÐ¼1ë¯YµÖºlýiÔ0†Ö_OñQsÍùúƒLß²ÿŠÒi ’¢5>ÿkŸ”ÏŽîeñÕ¡:¶þ¡Ë6ýbÑu)Çc£žÕ¿™-{á[=ò'¿ÖKž «rûÏ-{±'ħÃÉÓcË?¹«ü–½;­@ß]û¨Q¥¥]ü®¬UªJ¦—ΦrÑ·Îúë4n6§Ìúëö>Ò³s·ù~ÍÃë€çÏsׯ^>½æo:(~:xÙʧ—<ûìšûè%“¯ ì\ɤló»e÷òª#¿¾A‡?”½Y‡òk̆\|evHÞ%N>•óUüÚB†Òø',à >ƒÿéù¨ÏLÿ›çoÆŸ3ÿ˜%fþÕ\³þ8­©àÑZbÖ_Íúó4VÀcÖßP8í¿ä{fäªõ÷ºïk¬âÿ*üé÷üÒ[mZÿâ7ÿ­û'>Ó¯-=ÿl’I‹/Í›âk?JƦøòø|K•ËoÙ=¿Æ'kÿI޲_}Ÿ¼<9âC]Ûÿ“ìF”ƒ›©¼+0ø¨ü¨\¤béâ×øâ£<›nD•f'ŽC|ºReùâ–n¬Ý7ê—Ÿb®ñÉ]·ì…O>\ÉÒ•j7xËîD¯‹Îyý®ºÓEüT×xR>ò#žºS>ÿéJ]ùJ¾±vÛ5¾<]TûÅZ}ÇWžøÇ{2øOÿëùZŸ™yþfü™ñ÷4o™3ñr柊}í2óï¬?fýu|fýùÀuwk ã§u†õÿ¬¿o¶ÿЯ¢pT>ßÙè7g÷L–fgþ >”Û e+u¹_(¹|~ä‹OWz«­x±7+f÷¿C™âÓe‹ø’ÏWëS²›Ì¿ô‘ØìøQçbJÕgõ¿/ê,ÏV}¤×&NoBk£ª¬ ññ\*Ê· 8äñ·ìžÇCIN_ºRàæ#}eWñk<ûbò·òÕ+Ê6»bÐa‡½z_y•ÞjÃ_õÇ×™ò›mñÉ‹!OÏÕCUÝø;÷ÁnõS]Š¿‰w*>û5~±î?ßÿˆgJÿ#&þNÿ;>_óüÆwýbÆŸÓ¸ÞØÑxÚ˜ 'Ô˜Üø?ãï—ðR Ãgþ™ù÷ø|ø;óïÌ¿ÆÄYœö_ðhãß\k/Õ|‚/ÔÜ+MαqEòçó8WáOŸ_$Ÿ<6klù›ÌÿÕ‘OmqÉGW­¿’×þêϾ¶H«뜻æ{VÖtæßûkþu¿¯ºÿ­5[¥ôQý¨ùwÕ•çÓʱðòsžò‡ðùéª,uñ‰Š‘ž4ùë¶¼òyüt6Ñê!¾¶}$íºªýÅ’Ö–êÊ6ß[öîd}¢¯â‚Và-{ÑPü^÷ÀWÎNY^ÅããÉW–FP™­AWŠÄ¯ê…Ø‹/PðÊÓÏ|eiu(¾²«øù(YmÊYvòëÍ’§—e—²”R·TY‡”²Gɳ+~2åâÓ-_|¼«â¯m˜øƒÿô¿yþfü™ñw柙gýa…5ë¯YûÀ¬¿8<–öío.Ûÿ´WªŸïذ×^2ûR)þù¾Ò|Yÿ`C7ûl”W½­¸y׺þ^íÉ‹þµMY~/Ï’ÏNÊry$]÷¿éìÂí;”öˆ?ÉñîJßUñL¡@ì«àyCT$=Ê5nË^JžO¼dùÀ+_ #>>ª]ø|áK‘|òêÌ|ñ·ì…Nñé.nnñÙº”«{ñò™mþ’W÷Ít÷_«O)ßu®ò«.ûÊòù—~øÓAÉ«;sÿÔ/ÿÛ±¨¯è#¨²|ýkúß<3þÌø;óÏqLœù×ìpšfýqZkÎúëkˆY޾沮šõÿq/Ôzó^ÖŸÆ¢ì×çήµÿµù‡¿|ñ·ìNtù@Íwù\øM¾+oðèðÑ>cõ…/fþäQ:ìQ~ù@Rõ”’Õžô6Ö/Ýdù”æcÍçKŠè°Ek¬•”Þå/€oJ*Ñ%`•ªü©Yò*Ùùøéó‘?i|ùüçsõ¿Ê7Õ ¿éæ·2}ùøÕ£r±Ü(º«y”ïcéxãåÙ²[‰$f²ê‚Ÿ¼/?Å'«~äñåÓ•–Çò«ÎküòÉKW?Å™øƒ¿~Qÿ¯_ècõ¹µßàGõ«éóü5æ¬caý£tíGõ³fü™ñgÆß™޳jã¢ÒÌ¿Çyu7Z{H›Wfý1ëËÖñê'ú²ùï9#s5þlÙ‹<>õ¿ èölnÙ‹ýY6—ÅÏ®xbd·e/b˧[¾z+#¶¨þÏçeûO~Vª½ìòÁÖ…W~Ëîòì«'9Š,]ã¯ÊÝ„ªPU¶JWÑxÊ_œ*Éך'Ïo ®~|ÊãKÓã_¹”üªøÅÚTv{õÊ;TY¾Xòn4}$Õ¾Ò•ÇõÍ~~¶ìÎ_ËxÕ±ŽVýÒ«^¥lŠÉvølŠ-Eù‘Ç«œ|âq G¸¬÷-ÜKá8ø1šþ7Ï_ÏçbÆŸŸ]õ )Ÿùg‡bÇBnæß™=£ò³þ8­»J=3³þšõ—gä&ëÏæ¤óù§½fÏŸþµ>}¬µþÇOýÏØM^]øî:Ž7Ñ•ó›âŸÛÇçG|±]Õ«:×N)â› %+ÏÊ<^õÀ_÷ßäÉèñ/嫘[öîT¥î®yÔ¨çúUVŠÖJTÁnòQãø7žT#Øõ& |ut‘ûyÏõÆ'£‡A~•åWФÙIÉV½­x¿6ôŽ|ç+?•ÙF«­6 êA&ŸùZ|įv‹¯3 5V~âñ‰Vßü®ñɳ;O/[zðŸþ7Ïߌ?3þÎücFœù·µ,ZGÄ›õTNk¨Öu³þ:á"W¿™õçqm¾ö“Yû‡~òpï?ø‡ýeø»k|‡¯q®|iϹTßî°@™M)}y)ô¤ñ‹Ñ!€øñÎýl¢Ûüçcõ˶«øÕ‘ž}¢”y”lÿ«GÏqºñ¥=ÛùMçŽ)å›P• ±'­"505o•¯ `þJÙækËÞvPPy_¼lŠÔ5[åäÅOüx[vç¥[ŠŸ¾<}qð½|t3«JŽªãšâÓK—íyÝÓÉ¿ò½Ä׆Õ×Äü§ÿž»yþŽã‹qB¿@Òu̘ñç4fÜtüŸñ÷ö¾4óÏ©/Íü‡gü™ñwæŸ}úù÷A®? w¾ÿZçßÖ1úYë¾5ÏG~ølÎ’¿lþÏ/_Ùɳ[ãoÅ _kÜæúHÊt™ÿ|“¡|d'.^ñ¥ÅŒ¿±.ö½íÓWùê@w•)_‹8~0TàȇF '¯\ãÈâÓ)öªÏ_仆õ¿uÉùC«=ÝÊù¿NütØf_]ÄpãŠ.WFb£µ“)Ç—çS™Ž˜ÊuŠ-»ÇΞßꀧ=NËÖøòwŠ_¼MíÂ×uã³­ðŸþ7Ïߌ?3þÎüsœÃ›gþµº8­sZ¿XgÌúã„ ,ÂFw[ÿÕ¿¤³þšõ׬¿úõ—±Û³Õ­òÆÚŸUåë>lP‡x|táóëù—¦¿e/b•/¾ô²ûOoo×2ÿ¨¶‰Öøx|¯:áQ}Óiÿ«ÜØ•ûÕÇVÜuJé݈4ö^H@>4©p€+ÇW镟,~ ¥ßÇ5øÅGÉ¥€/>À7›â–Òe[™]7 Ÿd®Õ_±²M7 ×öËÓwÕY¤ø®|TN'±ñ´!ٖ݉¹å~;yqKéç#Ûbà'Ã[ãç/yå|LüÁúß<3þlçF»¥3þžæ˜æŽ™N}¦ùuæßYÌúë´þm<íù¨Ü2ëÏY>Øõçºf©]6þ®s7½ú^©}]ó<¹+ßñ7Öί¬ßÒI_ŠWüdk—\ŠŠ]ÿg‡ÚŸ§tmÃj[üö¦üÙÿ²#ÃGÉóÏ’¦¯|™ÿÆTCol¸Ô(¶„ðTVgAÊ5R¹’›<ýä€[öB—ÜÁ…'ïâGüÊ…W|eqŸ )W¼ädÕ!]>ÎãÓcS¼Õžøìù’ÖÞxÉ7ÑE[Ô§ØR~Jaã.Ù㣵ÅÇ/~öküxwŠÏWqK'þà?ýož¿füùÇ,;óï¬?ŽcçaÖ_§õ<<êÖ³þ<­ÿgý}Ü[¼>÷žÕ»Å§Ó½’Úÿ¼n»Zÿè×õñ-»?ÿdú{W¾ø^!¶âE}ª›•ÚŸ_>¢Úƒ”{1éòŠá©?ûê^]¥çíßX1Èk'¾rñ•¯MUðÚgŠUXCj y t‰A©´²ÊÆKWyõ—}:É|cí|zéLñÙFd€Í÷ªK§øÒn6}>V]yWzkÅÍ8ÙÒ:㪻‰w;6ˆ›|¼ Ñ ¼|òs§ø›øB— Rï5>ÞÄ?â2øŸúõô¿yþfü1:Îø;óÏÌ¿³þ8­fýuZGÎúóêõ¿¹£¾2ëohœú¼y=\ûu¯t7üÕc]ÿÓ¿Óú‡¾¾ßÜH·xÚSÛø1vžûk_¹‰nÔ~~\Wí?Õ¡øt”‹¿e÷¼z¯û@û_eD·¶(§‡Ÿ,~mZùd×"•|0TEV[A|ÖàR|`­f“Œ^`HóM.¿ÆO/@WJžÎeñ݈5~þ7önÇ$Ÿœ¯ü§#ÍWõ.öª+_}ùæK9~¾7ÖNküôù¥¤ø|ˆ/½[ü|æïªøùÞ\^ÄQ¿‰?øOÿóTœž‹yþfü™ñw柙gý1ë¯Ó8ÐÙšq]SÎúóÎëÿ«ò³þ~äöÆòöJá¯×—õítÖõ_|)b‹¤ô\È!EcE2娘ÊåÝÿu_jÿËw>¥ù+M_YÛZ³lÙ=ƺ‡Å£“múâ#|þjO¶Õ/9Ýk'†TÄ…¤UºJÄ«réª| »”/úš¯|(ËKéä³Xë¤dÙV.¾r2éJéâU—R±]:Zõ•ññ\Õ5ž›*žrñ餿e/ìËçCY‰Ï:¯‡rñ²­ü`â¯1&>4ÿéóüÍøs fü=âÐ<8óÏÌ¿­7fýqì á1믛¯.±³þ<޵³þº÷õ—¾ÔíNû¯ëô¿ìÏÇ»µÜ¼¯´}`ui¬×x‘ž²ò]Yï<ÝoøAb•Ï7|õ⫺U¯l²+Ʀz3ZnfyÔ®B*P%TJ­T¦ßHø-rÉØæ—½+›öuÁËO1•kWöɲ“®¾|fǧSÈ”«Ë–Ý©$†|õa'ØT—Ê:W|ñÉó¿øÉ²á#;ñjW²l¥®(_xð¯ŸÔ—”§ÿûEØôÌô á{æÂlž¿fü=­<=;RWÔ³„7óÏ §Æ¸Ìø;ãoÏ~Ñ3Ó3D6óÏÌ¿³þxý¬?Ú³žãßøíþ ÏkäYf‡'¿}|ö|¢óç?žÿöŸ­?ØñC†ä«KzÅO¯¶ÐÏ^¿:ó‘ŸÕN¾ò–ÝóÒSø.UR…ÐZ^«JKÓÓx2—< 4:øü°Yíñè¯1¶âEyͳ+>Ÿk|±Š!O&­~ÉÄ*Þš¦‡—ß-{[]Ïõ•£ÚªòdM@|ã¯2¼üUϵóĪ‹4}iöé]?ùÄü§ÿžÍžŸ0QFž­yþv(ö?3þÇÚgþ™ù÷8‡ÎúcÖ_͟ͳþ|àݨÎúûáY·n»Sÿ3wß.½uü:_ÿ‘¯kyÔü_¿/]eç1Ôã¡db_?ŸÅT®.|°ã'ÞªGv¾ÇÕ–|¹è±Ë^zén¬‹}³üƒ&ï…ª$Uº¼²ÊK]ç•Oޝ>¥[ýèŠÕçgò‡‡òá3²¥Ó÷MÐI7_ñð»9l‹IŽòG¯öÐÇÏç–ÝÛ >ƒNñ«¯­>嵟ï(ye¾Š/ïBxù\1,~õ]ã¯yö—Åç;¿òðŸþw çù3*Ìø3ãïiž˜ùç´†™ù÷´¦‚źæXó³þ˜õ׬?¸þ7·zN¢Y?¼ëoAëþ îçøë§tÜ‹Öë>mÝñ­L·1¯üƺØSÉÓ]×ô‹‘/r]?½µ xk|åtùCÕ µ]å峿Sû骒ÏvgÜôJÝ+­>ªŒ X•¥G. àlÓ/ÅOoËîy)ŸëlÒ/~›è,zQ¿rñó™MzâÓŠ¯LGÙU|ùlK7ÖmíÏßÅOW9ÒâË£lŽ¥SüÚƒŸ/ivüê¸ñÖ¸|f3ñÿé§çdž¿ãø×82ãÏi~ن͋ñÆßÓüß\Ò\§™fþõÇi^™õ×q¼0FÌúsÖßÍôþÃÜt§þ×fÿ|ýSYº®ó…ßü'¯]ÖþN•¦·–Åòó2ýÆåânÙ‹õÉyüôé°Ï¦XÕ“ÌÚ†ß.²­þŽœþ]7Ù74½PW *­²ÊU–<>^ºø(2›{@†›Ð†Ÿýtó[{’¿:¤—íæââ&ÄË'[±ëŒ:Rþ¶ìE|ùøù_å|œSõ)¦”^öÕAì:_ñów®¿ú¯2=yW”m@HËKkÌÚP_IƒÈkPöÝ´äçöôÖ˜+˜pœÇ§ñGŽðM¨›Ñ¤@¯zäOÌøÊ¯¸ÚˆŸlËî”n*ñðéâ+ó]ü-»Ëé¤ÇU–gUül¥hâqü§ÿÍówGfü™ñw柙gý1ë¯YžÖïëúÙ:{ÖßÇõóÊþCkÜÓËÖ?žTpÿË_ÖþöqRûµ¿(·ÿJ'?öoæ_òž?)9J¯2HÊžŒ½˜.ö(›âKɳ—g§,ÍÇ–½èñuî÷6¥›Tú¡ *$­‚T:p”טéãÓCì&­~Ó%°-{‘/n2ñÙT&GÕkÕÇwóýêØ(6¢[›Ü´äÒÊÅ©ÌVÌìòŸOrålW¿{—Ó©£¤O]ñÙ»ÖrqðÙ¹P)ŸH¹öOü#p@á6øû<êw¥a3ýož¿NcõŒ¿ÇñsæŸÓ<Òœ"ù GlfýqÄbÖ_Çþ0ë¯c˜õç±?´Æ¼—õ§ù5/ßmÿU,)Ýæ1uÑ?[ÿ’)·þM—[üb*w%Ogí~”£ìÖö—'ã[¹øìªW~è •OÆÉó¡,ò!ÍÏ*§—ýMMÚÁ-ÃÕÏe•«!CˆÊ5 ß•No¬‹Í<Ý-ð/+ŸÇ å[~ß "GR—)‹EW[ÕQÞU}È]éV¦ƒðÙ¡Ú†—|lð\ÅÏ'=vueWØocíüÊtòÁ/º*~zt&>NØ þÓÿæù›ñgÆßãü4óÏÌ¿³þ˜õ׬?OëDëgÔš[¹|ëzòYŸö9ð‰ÉýGûÌâ»?wŠß½¬¿³sµ Ï>ÝRzü‹¯þp·ø›ÉnËN¿Y÷›—ŧO×…ò_{ÅåGÙUÝjzt"¼ê}ÞÞÊéòsÏÈ÷ê(TŠÏµ±|ããÅ—FÙ('JuãÛ&™ž+§€ÊùZëCÿ<~úäü(g'ÞÊk“Þ JWYüÊ[v¿ÙÕi­¯øñKé£bÑáK¼bá¿vÐÁW.¾2ªNÇÒé/yq³!åk5ñÿé·?óü)NãèŒ?3þÎü3óï¬?fýÕZrÖŸÇ9rÖß§}Æ‘ãßÇÊþCmõéuOvÙúÏhÿ”ÑzÿÉãk??xòñ¥k¬­¸ëÅ#_ã+w­¾ð;õ'CÒôzFKw…íÏ ½v ~Óç§8R:É”WùV|ð¤B©RÑ*(Uùd¥Å¥[ãä; Zùx$m ÄwÃðiË^Ä—¯K9êF‡Oy|úݘäÅßD»^ºôè¯7‹låÉ£•WüìµC>\êÀüV§-{Q71j~‹“Ï: ~²ê¹ÆÓÚD—ü•·'þ†lÿéóü&ÚÆcÄŒ?§±¾±wÆ_=ã4OÎüsÄ¢y¶9¥¹>þÌ¿³þ©Ox~Z›ÍúcÖ³þ¸÷õGû¬«ö_—¿«nöí«¤ëú§gÖsK–^{Öt¥®žu~/Ûmì]®ûŸ}~“‹§îR~Puoþ¥C.^c =~«cuÚXðQ ñÙ=dô:ÛjÅŸk½ *_~Qã,[` º§ ôâ˯~òA¿Xìè À<·#ÃCÅ‘_õñ‹»ò‹Ïþ<¾:°Ë7;¤¼ÚÅK_ê*yñÙÆ—wÕIå³-½,þ¦6ñÜàvð »p&üOý.\¦ÿÍó7ãÏŒ¿3ÿÇææéÌ¿GlÌ¡æhÖ?§q&õYÌú«ñ£u–þ1ëÏG~ýÙ¼vþøçë÷¬û'5ÎÑAüE«½žúÊü¬ã¥ûÏž¼C‘-{¿|ñKÙEñ”/óS}¥Õ¡z]ÕÿøZë©|O´VøžÝ2^°ÞŒIM~K¯‹ i$_R'CQr2×z“ø@xlÈ«»|nÙŸ¯bÓLJò?{§âK;á"`«}øÛ|Ê‹)uÑëoÕ­-{ç“Glò¹vÒ5~~WŸòaU~ÅiÕø§þ—Á¿Þwì³ÓÿŽ8ÌówÄAï˜ñç4þÏø{ìëœÒœ£¯”Ÿùç„ÓŠÕÌ¿3ÿ¶þÕ/fýaÔ8Ò¬gý/ëOÏ“«9ZzÝý;tY|kÁö|¢õÙ•¿éþ«º]öüóu·õ'»êzU|~Ȫ«2»uü![ñªL¯¶nÙ{§õ€àÞ½=Ô •F5Dž ‘­@(×8ú«ÞV¼ÐÍé(³­#”'ïFä/ÛMt_L6H¥/Ÿ¬8ùX}Ó©.|ÈË^ܰlñØ(_Zü-»û&/>Z;b¾ò']ãïÛüüԮ▮ºt&þé^…ŒÿS¿žþwz¶]v¿¶]|â¯~”¯ÿé­c¢ò9±×Þ|òUû×gŸÚt^·lòµ©^Œ¿çºd+]V§U~ã|ÿ ïb ‘*^^Le€ÉHÀn¬Oç@´Jeúü²-–<ªôå×øÅJg/Å‘âumÙj÷Ú Îã¯qòÇáɳK·øk§ëÆg µ-ŸkÛ‹™Žx—µŸMüÓ½‡U[¸vÿÿéóüÝ>þÎøs?gü=â`.™ùç4ÿë3ÿÎúcÖ_§µê¬Osè6<ÌúûÖ©_\wýMÏØjýš¥ÛùtïöüñsU|{·Æñ5_|ó]ñåѺ.’ŸréuöŸlŠqÕþ·8ätQ1ä³[ãǯ®¥êõSÎrǛêá kðÎã㡉?øOÿ;>3Ç'âø·g§gkž¿ãø7ãÏi¼­¿ÔGfü="2óÏiÝ o ™OólÏ \fýqÂÑÌ?·¯­gþù×þëѺþh|_×=Þéóƒs$Ýì”Qéj+¯ÿ{»bmº«ŸMåbLͽâàµÞ_íòÅ^>ÛÚÓóÇ6]T¹qíCNþp“†D+HxÔ ¨±é=_.¿v€­¸À"6Å,ù’ÒqÉG«œMu)&=‡ß‘ú­ñÉטkž/òb˯ÄWö—ÅÏþnñÉ]ùC>û‰Äcð×3N4ýïôÌÌów3Œ¨ñcÆŸ#þ^6þÏø;óÏÌ¿§±Ôs2ëÓø9ë¯c˜õ—'ãD³þ:–õWÇp—®Úÿµ¯nÌ¿jþïþöüKé"ÏBrmo͵®¿²IÞúc¹™ìötÃ/ÿøâå7_RüÊå¥.¾ À‡Åù-§çYÁ±¯qô„ÂCÊÙ©³<Ýøå7Öm@ì*gÐk|¶nz6Êçu'ë¥EyuYué¹êâ#:ôksñé¢5>ÞêSžÝy|åê²ÚœÇg&þà?ýïø,Ìów|fü9ö‡Oóß:—˜;fþ™ùwÖ³þšõçq,lÍ=ëïûgÿawþoœ|¨ö_V&—Í¿íi×ý']ÔzNºÊù¹lÿdžŒÏæýx¥ìò·ú È È­ÀÚeë¦ÓÚDÑÇï¦Ë¯`u£Ò!KŽç2˜DÊê’|ú(™|òdk|zÊdâ+»ª >yü¾ë"ݨÊáT|>ÐÄ?=<0ü§ÿÍó7ãÏŒ¿§yfæŸã˜8óï¬?fýufýyZW[;ZcÏú{áÍþ#$NýäáÞµŸ9üë›x뺦ý>J¯y.^{¢øô\ëóOv¾ÿ¥ƒJåé(Ó—†Ç–}øè‘:˜ÐªÁrUymq:ÂÖU9ù꘮H>;¼lÖ´›I¾ÚÒq‘ç§röñ¥Éªßƺíæ*Ó9A?þ¹ŒÍeññÑÄ?ÞßÁúß<DZbÆŸãØØø¨_˜Pãì±tzfâÏø2Gl”fþ9ͳ1¡4óïÌ¿ëúÓ³2ãoOǬ[—ÎüsìͳõÆÓøÖù×3íVßêÙøW;¤l®ºÿü­vÊìPó¯òUñéñuÕø“¯âå+›äüDñŠŸmò‡%}$&ºI AòH£Ñ*Hò]¸ýQ_§>Ònö–Ý)øäª¼ú%ëÆåŸ^2e¤Œ”]Ê}ÆHYŒt;yÍO²ìªŸ˜t•‹/Ÿ4ŸÉ•óS|zÅØ²'¿ùIÆŽ|4ñÿéóü_ä7¤3þl l>3þÎü3óïíëãDk ÏÊÖ?³þ˜õ—þ‚fý9ëÏÇòúÓþ³ñìnãŸþ®ß§¯\¾}×ùþ“nÔü³î“I{¾ò£n¨8Ïküö·ç2vì×øxÕOþa¥*ö°¹Äù 1ð€º‚TÔM @ºxk*ŸŸ-{Û§Ÿ?rT9[þ/óAVät]u„s›èÂoyúô²ÁG•Ïã¥'ùŸì:ñ«—ðŸþwzžÎŸ¯yþŽã^ãß9>3þœÆØÌø{z–šgz†àƒ柙gý1ëãAë]cªÜØ1óÏíûŸð]û¸Íüsê;Í3õ!øàÅ8çŸõ>\_=ì)Õ£û¹ewªŽÙž÷eDo½ÿxk»Ø£ó½kõ“ò±Æ“¯>Ù)ËGÉ/‹ŸÎÃ’¾>&ÄÖà@[Ó›Xò(éwᯠvƒ“'[cÊÇ—£zðÉr2|г±.âÉãÓ)ǶøRþù.vñ×xxÊt‘ôªøÙ·´8ÅÇ/>›•èæ§˜•éMüÁúßñ‰é9Rò<õœôÜ•Îówûøn5G4ãI](\åñ¦ÿAâ8¿èwhúß©ŸôÜ•ê3æP¹¦ÿq€‹gk¥xRšçï„LfüÙ»ÅÅs¤4ãÏé9iÜ)ÕgfüylŽ¿Æ¾u?v§ç?½>ÖqÕýO^¿£q¯ü–Ýóüâ#©g 5É÷üÉ·¿=Ÿmv—ÅÊ™ëœò_{Ïu¶rïÃàŽÝ”€$êå×›†õu3’x6+˜«[§ExÝùì¤håu3â¹É|¬ñÙÐËrub‡*«;Þy|:Ù‹ÏËâ¯íÏÿuâÓ)¾xlW»‰Ädð?öE}ŤÁ¯þ?ýïˆÏúáô¼‡2yþŽ} F°Yq›ñgÆ}Â¥/è.oÆŸÛ×?pAës¤<ãÏéY Íø{Ä&úÎÚofü=õ™füíùð¬ }b<;füe‡òÏ/ZŸ¿Ö‹é&/¾ï,vcý:¶á¡U‡/:«Oòóø붺(çGþ#•}}Rà  Ý €V|õ”OO9½tò£Œòï¦"ò|f£Ü +þš¦—/~ÈQ¶é¬þɳ9O†ªoò5n¾èñ“/åËâÓÏú•ó¿ú¤s.Ÿø'œW¬ÿ.úÍô?(Üþüë/=Odóüð˜ñG8âѳSÙÜ>3þžÆ™OãìÌ?§~á¹é’6æÎø{ÂF3ÿœðh|]ÇÕw’Ïø{zÎV¬fü9á¢ß4þ\µÿ¤s·ç¯=ãeó?¿áO.Ï_qK‹¿‰vÕ/›ì+“Ÿ/rey:«ß­øÈ“ ¼¾ @ ¨ÊR’ª«$ù–Ýó•ÊQ7/þ‘{äwÙ–/~7‰Ì…ð¼-Qü|§Sý鮃œ2ÙJl‹Éž>|åâoÙÄï«/‹ÇOöéÄç)ÓéÞW¶ÿ„ßÇà„ô‘õm¡úÖÚÿëgÓÿNÏ3ìÂEÍó7ãÏŒ¿3ÿÌü{gýqš#fý5ë¯ÖOžýáÍúëô¶úùþl?ÖÚö2üÛ+õ¼ÒÁCݿ긮ÿè·þ“fŸNåÕ>Ïï?ÝU?çñ«?¨øÍ?|ÐYc–§ÿz¡*÷z ~IP ©Ó î PW¢ß½õæÐã'â—~tCÙõø[éê_¶ÅÏ”ß#äÙ·tcí¶Ù)“ƒ_e×Úr”Ï»Å'§[}Îã+«ƒ«0›‰?øOÿ›çoÆŸÓØ8ãï6Ql4óÏqn˜ù÷ØZÇH×õOk‰Yqšõ×õYÎúû±°ÿÐOÍygRõ®¼ewÂ;_/ÝiÿE?Zcôlà­þŠ·ÆgŸŸóøé¯ÏYñòQ™mmL¶úMïõ’šTM  V¯s€»øŠ [öžœºHÊ¿I¿M¢ë6¹2›ì‹qÞqè%“æ¿öà¯ññ]è:ñ³§§øäâhÛyûù¨>wjö›úÛŸÍÄü§ÿÝ>þÌó7ãÏŒ¿§ùéªùwæŸÓÚ.dü@3ÿŸ[C… |ê?3ÿÌücŒYŸŸOÏÇý8þì·ôƒÆŽ›ì¿Œ3póæ:_.¼úØ–½Öøs§ø_ùR.†ô:ã?ÿê&­nl•KåQòcéQò·Îù(©ÎÅä ÔSÇ@ Xà¢ôð“á˳w­mìÆÖ±”É¥ë”×a¥:‚Iév¥G§ødw‹Ÿït¥|e—_i¾·ì•ñÃh­—¶÷²MFwm1é¬q{`éã#i~ª3½‰ûý‡Óà?ýož¿ãs±=ãÆŒ?3þÎüsšKgþ=­õfýqZwÎúˬq\[ÎúóˆÅ¬¿O눻ÿX7ö|óÕX¼ŽCëþ+ÝãÝ8í—nºÿñlw/󩼯7G¢|˧+ª'üÅ·ÿ¨}xH™.Yúç>7ÑëŸTòÑHu”À Hu l€®D|€KùA«M>Û<(óÝÍ£Ÿ]ºxòbäk­c¶é—²CéÒK&>x(ò×O—?äAâãºíg7ñÿéÛƒ°Ñ<Çñ3þ@á4V—?ÿãKgüùgæßYÌúë44´fn¼ÄŸõ笿mûµŸê«×Û/ö|“ãëÇ­o:þó•}¶ëZë/zÅ—Ëêç;þè»ð¥:ÒˆG;­Ë7˜hkG@'˶ò:Öv:QöÊʼn'-¾ÎÉ×*ÛŠåâ=˜øü¢óøxçññŠ%­>ñŠ_§—â•ÒSŽŠ©\>ŸxÿˆK÷&a=øOÿëY©OÌów|>fü9á0ãïÌ?3ÿ׳þ˜õ׬?­"Ôš[©|k ¼Y?²ëïuMï>œãß½‘¢Êçë¿Êû¥—éækMÏã‹Iÿºñ‹·¦|<ê¨Íù£®bK…ºQnŠºÞ„ÔÈ\tlµUFì]|áÉg—/|ñ"6½‚ŠW=êdìr¸^7~¯í{õµ;ÝþàUçÚ@¶Ö[~âþÓÿ<×þçù;â5ãÏqœñ÷ØÖùo柙gýqÚœ´þ›õ×iÌœõ笿ïçý‡¶»Ì•= ÇõÞöŸÆßÆR~[·‰µÆ“G­gäÙ¥§ü¨¤60ÊÊU*VÝuåxL*ËwCØÒ—âe·ewYþè¬òsûüÕ Ïão*»>JoMW™üv@"’±—ÝU~Øä7]¼Uÿ¼ýdŘøGŒ½æHõéóü5¦¬ãIã ªœ.Þª?ãÏp‚MÏØŒ¿3þznfþ1j©gÃsÒ˜²Ž'ësÄ¢rºx«þŒ?3þèõùúØŒ¿3þ>ão}ËXƒøÔǤxMôêäòdÒ¨¾Mþð”㱩,Y|¶zÒèǬ4ൡr7IYþœ²Og½éÊùÍ—K¾ÏóQ¼-»첩|”žþ«ú±É?[×Ä?â–á3øûÝô¿yþfü9“F‹ÆÛÆŒÊÇ‘äôwÆß#3ÿœæÚæ—™O˜è%=Ká3óïÌ¿­=fþ™ù§}б¢ù¶1£2ÙJ3ÿÑ8Ÿq›¤hÅRþNãoÏc6ùßm”3ôX<˜XÁ]Á_oˆ†,9™ Iµ;™”þúÀ¬¶É¥&èF~ج~鬤2y×–½4¾ú¿”n±J'þ “Áúß<3þÌøk¦8öƒ™fþõÇi0ë¯ÓÚs'Ï׿³þœõwûŽRsJûŽÒÙœ0y0ûÆ#xÊ£ÆëpÇOî¥tÖç8üàg›ÿü?¦È€ô†BnF7°›× ªøÝÀs]:ñ¤ Ön®r¨ÎP'Éç¦ra/Ïníéæ3=i¼ìŠ/޼AAZüsýMtŸ4ñý$šþwõóþ<Íówófü™ñw柙gý1ë¯YÎú{öW¯!í·V²Þ¶~j ~§õ7»ì¥­?[—òÓ~ŽŸîƒüj‡_¼-;ôhAÀB¥n0*•'[¯:¹Ýn:ýäx«==_žeSŠ·ÚÊOü#NçÁjð‡Â±Ï„Oý¬~tÔ˜þ.á% ³Òda7Ïߌ?3þÎøk|8#Œ3ÿ@aæóDý£y¦9dhû_™ eSŠ—]éŒ?3þèç}D_™ñ 3þ+ê3;@oHjèR›ÎÛÒ‰S§H=èÊnl|'RÑzãÓ#KWzî‡<ÒäëIøùÍçćΑÿÓâ¥~™úŠô¼‘Oÿ;b4Ïß©ÌøsÄ¢gçü¹‰?ã¯äH3þÎøk ]ç=£geæŸÓø 8¡¯Æ™güÕzvêõ›ø3ÿìÐþg査Ï?'´Þs÷ÃÁ„ÛÖï½&&‹ ¼&—Šó‚W>ÎË›h§&§ÊRºü®¾+“MüÁúßö l´>#GÎia3Ïߌ?3þÇÊ™nŸ+fþ=­wÂdÖ³þj½éù˜õï©?Ìú{ö¥ýWcú¤oà蔾íÔÀ”Q¤céø·¼êT–ò…äó‘¿8峉Ÿn¶ô"².¼s›|‘ÉçC>ÊF9ù´ÿX†M¸IÃ><ò²tîÿ1X„aø„Yù0‹Ÿn¶ô"².¼s›|‘ÉçC>ÊF9ùôÿb6á& ûð ËÊÒéÿGÄ`†áCfåÃ,~ºÙҋȺðÎmòE&Ÿù(åäÓÿˆeØ„›4ìÃ3,+K§ÿƒE†I˜•³øéfK/"ëÂ;·É™|>ä£l”“Oÿ –anÒ°ϰ¬,þD a>$aV>Ìâ§›-½ˆ¬ ïÜ&_dòù²QN>ýÿX†M¸IÃ><ò²ô¡êÿkÜÉÔéü]4%|´vÊ5OFŸ^ÿˇGg-ŸûÌo|eyvñ¶ìÄÂF+ækž ^ð[ñüoÇã¼OMÿÓsNÏÚ<3þÌø;óÏÌ¿§1ÑøØ<±Î¹k¾1”žk•­å™ u¤°R ¼fü™ñçôLx><hWÖ<™ç¦gj•áUî9£Ÿ®||¼‡óùkhxÈÐiëÄ:{x ?½dçå–õaHWÚ•ݹßÊùÉ6~vñÏËÙMüËïãàûá¼_U®ÕÏâŸ÷·órvÓÿ¦ÿéõ‡úÑ<óü5–èåG*Ÿ÷›øéÕŸÎËÙÍø3ãÏŒ?3þ64^Ìüssgü=aÑ<ÒK9~ßÏý=~?êÛöG»Ý—çï2–[éçŽ:|-϶p^G@êàB†C~¶KŸ7?ËGL€á³ô(¨â\!.E8˜b…»KHœöųiL’ISø#Óß:]QÒäd4Ê!lÅ*T ËGx,§Öƒ¶Õ¤nA5d «yØnG³\Aö³ ¨Æh}’ÒÁJÊ-® °hežo¥/aÅÇx‰¼„´þÚÙä˜)¥G™ßƤ¸]HÿÜJ”Æ…gJ…”È}滿r#)TðÁÒ ’¦„›á„QjÚ,9â™ôQê1ØÜê›^çêèúœqŽV¢èÄLš %yÕOdôkªFº¯Îð-ÅŠúغ!ë3ÛÉ“’Ê$¶Äð‡¿^§¡)œ¹w!`äl(FÅ.d)ÂGT ŽÖP2œÅ2éÍnÆyVŒ>†Åª n*È–QÈøéÔTohý ÿó3®|éJøê Ià¡ÑâOÕì+1¸`¹FÏAíR¶Q-’êþãÚQp¤öH#kcóôÃX¿ŽHbS¥JgfjVåŠÌ‡V…çNéÍ䯇evÄOLôO |3+™¤ g#ò UÎÚ‡*Îr‹Ïl c–ù ¥éŒú¬ìì|6¤Œšî ÍÏjÀ9ýü+sHŽŒ2m·”Žú§&yûHqFà<¸NáÇ-Ü’ò9 ·­~òñ®åU"±ø3PS@(7Üfs9¡¼Ph L8Û¯èÐ@U^ÿÙ²äÖuÃÞÿÖúØRÛä·¿Áhzïy¤Ž-Q$€>í2žº^‰«;0@/– ´ÈN<±{b’Â= ¨}èh…Á-©où)lêûb1¢•;œÌjvT”ÀV`Û#ŸŽ*Ü’d^JÇU®ÈvŽ£µ—Ù‚ŸäÙEˆ¶~Uè†ÀÐÅê{)¹cÔ„\QcîsTNÆãcMö”Æ“©Àж@…§Jû÷#›©st‚y–¹F”‚Ñ™Eë).{#tÅèàÛM…#˜/3ÇªŽ sÀï0­f¸Ô×/[-ç¢ppÈæô™ÉWŸ ç+%CÐzÒîbÖU¡uÔš˜Éƒƒ{Q»! ®Ð‰Hݺ¶I¿<ÄĈ|ÛŠþ^5TÛ95#ícªV;>Ð>R‡O¼íÁ€&3I–ssµÈÔûјe€FÄŠ¨¿ÈûGàÿrfÛ\Kƒ(˜9wÍ P—‡æ XZ¿Ž"aI*‹Ù{y¼k:@†syíN‚Ë|»œgÑíÕl‚¶ŽÙd?ÀŒ´É¸Ãâ ÷ËBÛï›Yð5(íOn‘àëjuE kùÁ/ÿ²q'X“Ô:Fs9=ï–¼‚%1<‘_ß”ÿs«++=Èr("ìÅØÖÇl—b½S¸®&ƒÜ<ÀÇÕ㔓¦§µŽªŠ/ð=Õ0Â0&õÀ4é~KÃ(D^Ä^A‘j_;]Ìgæç.]5Þâôéoõ7Ž®Ú¨t? P‹¹À;rBog+-5Gpõl„[µKóÎ\°e¶pŒÿ^™P«„À=UU4ãü…ÅØJ©…Åž9:ðQÔ%¤Åf´=8;ÒÜ-öù·7¢oQИ%Dî%Ù`#`f(?”ÊúïÌ¥£ÉiV–¦ ÐOø)1¹‚`¹”èî%hÀ1¼.‚€…ÄY‚ùzÞÿ»lGl¬·Ö#e³¢L@ê㪠=h`,Oñ,èYÓ‚Mu“°ÐV‹F¨Â¹MÞ^·:5‘-ûÞ`ï©a¢‘•ÜUÒêiÜšÔŠ;–aíŒo\Clñ<5(ì9Z~†lqìöPÒî®··bmL…” “IëÇ¥’¾d–À“àMù5cé÷°dœ2 †Ì$’­¥…h£”Bd¤”àvëHr¦és6úìÐ>Ö@+Õ†º´Ó4}ë)ލÕzìÐ cêsMëÐ÷uÙÑ«µÕîn!ïÿ] @%Ð:UVùEI–Bœ*!¯T€¦ÂqU6êIq9Ùêïüi©§ç $þ£Ò'÷戗lAó Ï>:žv¤D×Ð&²‚+I­½·áþçxÕk…Ú Cý6ÝVEÃ<}å"Œ|îù œ£äx¿eÑS¦ÔS‰Þ­ÂãZyYžÃ"º8«‘æôÞ•t9s×¼´P‹i®'ÔCÅü í[RìKI¼ù=F©¡ìÐ9oO¼R P“¸“Öhä_E| ¡e¬[½Ø®@'™S0,y­h–ÛþW ]0­ö¨w­a2Žå»‹K°!~§Eòl,<J¤Èø¹£8‰eÛ&Ú ~¶:±j#ïB®îo” –Ø«J(ñS!A(à@)T?æ®(»W_Þlx?ÂÆehJ¸Àí“s[fMú²Äò¸¹Ñüýw¿}!Ì.鶯–·º„è²Ä‘rÝçþº¨§’!â_¦Ì 4•û—YË]À‡±æwȹv3Ð:ª$0ÜN)’ {[ÉËW ¹œ.#£NõŠ Pë)‹Ë§'zobô‹œ…í‘7øªÖ[féíÉ•­.köÍ¿±x¨¿Ž¶Ä—qûwŠ…*©M׊„qÊiì¢rCЬãÖüo¢Ó^€ÁYoNŸÞmìíjÔˆÕÚ¹#¢>–d×€K:>m™Ãš³ŠÕæÎxsõõÞ;·"ØPŽH•˜õJ¯ÅI_8FI/fl`#|7¥ßœöpà¦?ÊV¨`î¨ÊRäªP\ÂUÝ2àÈèó<é=ÂÔÐÂàу‘9ॠo£Û£äýŽ+‘ëéÕÿôCfÛÏwmˆÅU<~ZʆRH…˜¡¯Pj]…húö›–ŸÕM¨ÜÌ"foè!Ü{ˆ£O,lî+_”âû+FÞZòÄ>®"¬„ ²~Í(Öå÷~DÚ=*3Õ4Ûu¯°Ii\V©…Z`¡ý#}kLZ&û¿y\?¸¦lŒÖÅRë¼M/Zø×ñ:U×0Ô¶®²å4àÚÞ%'ÓÆëcS,C*Þ·ûÁspÙ>öÑ“8†Pyî%ýÒ`Û ìâ3ö-aûý›MI3SçÚ¨z¼™jÍ8ÊŒÚ]ä ÄæVEb-s ë,EÌÚ]4ìÙŒÏ!83ElxîI=HÈv ÍGeªç}l/é´‘¨E¦(æÀR&ÕÇhTm.Û\á¾”±è?«Ýf]%…j(¤¡µ‰yÌRû]ZŸSÒPfÞ’Iø§ôX‡C+€¦—N-ƒúÌM-þ±–¹kÏhñÞZ¨UÆ ñçè½w¾ŸƒTm]§甆ÃZÞBêdZ%v8‚A@Éq35ìŸí Zòí& ºŽ»Höi,9¡hàÕ§1ê®"Îk¼™Ç™ABnŒ­+™náá¥ø…¥mó›9¾åFÔKá”øA ×åz­/7ƒã8ŸÀÂ5ÒŠKÜÛòã¦ÊxÒÇ|´ù7}«^¾´^Ÿ‡~?VX’ÒN¥`?W·,˜‹‡pî—M}³S<§é‘(«d¡’`¨ïÔå¦R“ᆘZ˜‚ù¶±gé àÑm ¹<‘åz³Ï+âóö††d…ÚmnºcÌ:ÓËpñ‹H=ãĽ¡"h¤c(Ã—Ùæ=ð‰Kå÷òƒþhú’û-·{]3ª¬lÄÚJÞçÉŽÙÌ[™µY³ÁÇôH‰X˯“~ÑìòpÞË×Îu4kÀ)|A‘Ö³ÚC¹MÁ‘Ùžwòà:Ð/HÇûKPTP4 ë¡ÞÃw…€’.\uz l³Nö%ŸV,w‚,(½6¹è5EˆEž(64æ.C»»_j¼Y¾Oi%»™ãÒ6ùê¦÷Œ1Œ¶ùLÑ.§¹oÇy•·ÞD½/­=y1 d¾½ˆˆD‚ĤPÒp»U k—í¸¢9³&öNtÝY´D1éòÞ¢$`÷5:_’éËwÕn¹½† ÖfŽ"µÕ[SŸý< 9är¡0éôm › ãžTà’\ž ÑZOŸkÛüÛ$™J\ðÚÀÿÙc]onfÐ $©Â½¬]÷ùÎ]ò’Eí}JP…‰AäŸm”vຕ9Å·´øñc1êTAf¶ÏOµÇ~¥å2‡÷ÆŒe¬'‡k|sarW‚ÓXbý'œt•EÃ2í¯IÕRU„Ô¼ÈÚú»gðŽ’Öx‘¹6Ë‘®(â‘FÒé(Á‘ú]YpŠ"aUv>ë^ãÛÄœÒÈåÎ*ÙuI‘¼–I&3 -"E…IûƒûÇ:ï¦ žKãñd¯ ÇÇ="Wñví za¤E¤„{5}dlSp9š5­ ¦_ (s¤´0‹°ñŽe.` 1­©="&’¿>;¸ù‹å5'½©,Á6tOòòÓ.íÉÞ¦v”üË…¸ñ§Ò’Ù±ÇL!;÷`m'Ö§­m·.¯ªlÈ*E*WœZ´ãf®T®4HfÙ’XÔ^ÍâŒ/åÜdZ™òéõ1±gróÅÉU«AÖgDM•X)OE‹ °øÔ!Õö>Ê­*ëض¶&è¡ã팽H*Cº ‰¨t91ªÐƒçñ- [‘ÐtøãA‰íýF×iéOñ¡.iw«‡ô¼^d`œ§+sþÖQɰKÜò$ ·ù|؆½éQeÂ’ÂlÖD”‹&ÃL@Z™ u˜¸¬z<Ñ«cA'_©ªÕ²*Ž~Ê»!ÛôܬΒ|¡¨’Þh2­Î­KDrüý·¿¶  ~O´nÜûSÞ뀜ž¢&L«™˜¢Q•*]‹­YÓ_hÖ((u¼qƒGpæ¸AP€s¢^ê5C]ž²©_T黎€lÞ¨e“Ò't XʆÜÈ«g·8,¬`°)¬MÙô0Ú·“=u¶ Ráô´ŒPOs ‡uÊbu\ÑuÛÉä£ïòkƒtF»ùŒæ¡dúþûßÊËÉ õn še%h#o²œ5õÞ:Ûå •3P¥ë‹ÔöÔ¼Iõ˳?Ž^_Nku§yd¬1œBVs”×6©ñÀTI4¼ó}ÛxïE°}' Ô–|Më½gÑ}xieÍS@[{V¶BåÍ}Q”uV³rò숊«ýÕ#Ä1#˜9Ý·kJAíqILwY!äB§»YraÝT=ØïŸþÈ:"–•ÅŠ¬§42ÚµD¿ö­ìª"mí ˜lž§TÜ3ê]Dó¸f“Ê릯0Ë!5Ò[ŠrÑ\{p5¯¸þ4\sZÞMf$låе2…cÆ<8Ñ£¿* î²mZ†ŠEœ’¯P|Óì$ìà`sn?ogÚç<Ã’½ÂUÖ„"ßì¹î,²Ì¥ƒ¿+…ãRX†4(Û‚ ˆc™NºíŒÚWÖwÎóÞOC]G ëHPÒ’f˜pú4êR= â¸qJÍ .ƒ€¥y‹ËgzÌÿõÆAq_Ûò¢»a®13š×,”úoY}_„Êê¢I<Ù«EìP4@õÒ<&¾¾[ÜçŪ)S2ï³õ:g¡/ífw„&•ú ’Ý# ŒÉÚ5âññ„u^…¡G­Á_6•Åý55n±a‡ºô‘·}Søˆ½s¼ïWqʵº…6tSÈ©ñÐV=¸Ët¢«À’ÚˆÝjk^…&n]vš|žöîçqÅh Ê_%i~ö9£n'‘¢‡Ê¹0,="À]˜$ñ{+ãé’qR´ï„* ²Ö•~ØH¹:‹í®íêØ™K¸e.—Í­‘†ìªV"¯=3Zq†ŽßÎhCgÓJß»œ[2-÷Bm$°¹ˆËÅÊÙ`U”bWJºNéœYgün0FF@­2UIG´»¹JS8znW5µÛܲs³¢Ãñ^Ï)9µÈJ"ôˆ‹;ݳȔ&¹Ä7*¿Ùƒœ®ðÕ, 2HsmxÄz ò½Eˆ!_ÎÙfð ~i÷2íZ.DîP©äUÀô:Q¡u¤ÄÑy7jädÔh¿¯üÖñ‚Œ•š ld¡^„¤ñvZaHÄã0懃î#0nžýG¨¬j_ÆÓ˜ ¾{p.m6bY ý[/þ¶éÖX¥ÛÒ]¶ÛžUY"ïÓ3o8J&mޝ~øV µ>©ÏâIÔ ò®Ú8–ŒJ¯UèßZ'… 4×M U UµNÆ>ˆ\ν½tÎVç²ú:Xdaúu³-"Èc÷±®í¦åúX_º3À›…Æ<+E¸«y÷¥2‰â¬s£=wi.LÓ`ó¬ÞòØ]³šÑÂÖOeÞp¹~9«bR*#?ÃU•_i"‡;¢ñ‹agêcá÷ÅDTȺ½9(PÏÍ ‚¤øú™™¥tû. êht ÀƒžF ’Ö§y¯…5l_†MyLKHý°:{¼(uÉ_©: Še‹w»áÓÙ;IÜÞþ*ØKþ 52|ÚjñѲôn hmà³ Þ„µ›³@¾žš²ÛKÆAß8{þ]wA‹Ê¸Ç‡ƒÚ¦‚íE•§ßÃÂ;pA™PC¼‰"Ì;ݧË>°®RK¡Y¥Û2_Ù’Âý¸e¯L`_VÃ,øƒÓëB]†ŸCLa ’T`ÅïkMnú<«,Õ©Ýó¼£Jd3¤M9ú8„e*—ô`€¡Ø˜õ•Á«œ—¹¶Y`õ¢ª^•Ì쪾åñÝ ¹Jø·In“Žº9NUOYË‚ÛmÕÏk›pG.¬n%ž5¢¾Usw̤ßS™ãúIÝ褒R¶¶È’5Ç;cp¡>§¡%qÑ›??hAD‰¿9; î8’$Zëß<XfffffÆñÚƒ;ÌÌÌÌÌL¶,™I`ÉÌŒ3û^¬²ûó§ÛZìÓGGnWU§²²""oܸѵ¹¯ÑÿÕó{çØuÏ­}dm›9¼íù¥[_°ù®þ—>±zÆM#_;qÀÍ¡ƒì0‘nÙzìÖ_{øì¯œ;1†ç×=2¯Æ°õå¡c¸ìÉÕ3n©AF…Lq÷g?ˆ¤ö¬¤BEG‰Ó™”bÙ-™E1òÒH$¬{Jnž®6g«UDñ½(‡SëA‹ÊI¶ü@ÌÁµŠ@6Z›ŠGß`ë4B© Û£¢_B-àµà pYÂÉ 'h’‰ _t™Ü™6ËŒ{+„Ý‚Š­5E˜X§s |{éùÊ„sÄõq&ÒH6ÁÆÊlÙ™[›Î É ×€ç%ºà˜e“Ñ ”8p!Á u$áMÀäUI¶×VÖ¥}8º¬—y $24dp¤“1kw}ûÑo=jgÐ~yϱs>yʼ/œ½ðËç.üÔióÞsÜ—«·}æ÷/Yòÿþí×¢U»N¾wü53ÌšÇdÃ{‘@Xí|ƒãÿÑ·1LŸÔsª½áNÑæ$ªCZsœÓçfßdýÄ487ïy#Hµ8¼8Ÿ³0”*4A“¥?µx2ˆ³:KĆ&‘™Ø ~MðH'î0I2nLœýÍ‘Qõn,Èõ|Klïbæ§± È1y±r–²IHiu´ DÒÞB: Ûä>œÂpp68c²ŒÊ´Ä[B5ûA󡼂{ÝSÓðÑLáã1̧—7Sš‹,‘-/^J…VTÀÔÀ•¶o^îùˆ¦Øìаc™ŸÏ’ÌÔÆAêÜ‹3~ï álÿßA8NnŸ›OæþM¡ëýõm/¯/3÷ÜÒ­Çß=þòðö{^ùG¦pÛ®ýÏ,ÙzôË_7C´0­ì÷?÷á¹›8~|㞊ܟX¸åñù›+pž=º½Œé¶ÝyýËŸZãŽD.Fiq ä]<»ì÷0/ǰtë 6WØþÜ’:£4ů“WJ㤜r )‚†€ÇDÙA0F¢Zü„ûL¢Ç •˜èÞ”<†Ûa‹éÌ6aæ;†¥‹ºD²µF“1+ÞÆjœA…Nà¶ìÒ´µ"zÅjŽ(Eћ𼭱êw$ØiÍÚ#àeôR-/RGS>CBX3å-xë"ÕàÅ;‰:Aÿ]Ö†Jýaí£žž‹„rŸ»qß¿©ìY«ú5ÿ×$ r˜á\ÍPêE¢¼fJ´Ó«ÝìÞ€¼¸AÉh[OÔÞ"_1 G÷‡Eö,°E*t"k(ÀÌ-ÜøB÷ÿøu÷ì¯^×Ìôñï®nüáºáÞÌ0$ÈOŸ±àÜGVíÛÿj'‚^½“fÓ³WT"`Ä“ S}g ¼~˜3P[“ƒˆ±©Èf‰…$ª&˜#¼²¶«@uÞöÚ¦‡ ·yATÜñùĤú %÷WØä)0ôŸ`ŽÖ£ùÁËO\‡,boí­7:®:$¹C#JÆSãI„zPʈOS\Ì¸Šƒ;`tvðïmgmLñRBÌ-óô>q{û'ìo uàνÇúŸ¿y¸ Þ„,Œh§…­ É] Ò!‘ ²Köî ;¹0Õ™oÈjJ'Z 53±vÒÑBÖ9êLºXšEñ“S&¬ÞHø;‹¢ î¯I®tcîsÄZ7¯ šˆ€g†õêÇÕf+8ž<«ÄõÞ\ÜøÂ:LöÊM{¯~fí¯¯úä©óÞrôàDàSìϱƒß»déù®^·Ë&þKç,ŒÖõGܶ¼ý×/[*º É\"ë·ímÇŸxÏxl…Ì3cWKÔÆ"°èOƒ}¿e´]ó—Ö¦.àÃÄ0(W€ƒE ð®×íó¿Æôúü˜ËO°ìKi^•-އaj,õ;AÓ¦{Í$êÀeˆÒ_JÜ˱1£4öÔ`ëÌ¿…1賡AäpÏÉüðy-«é,t”€øÄ,'Ž|oØ ­1ª|Ìf¼)ïP]é.æ6»²@ëξlî»Â[ªœÑ€ŒÀVbD@F±Ví˜g×Ε‹vã\ØXêÜ VŽ•Èz£=‹P^Ž6ûé!¤”×:ÒÞN®‚2ΘQ§ˆÅÉWï>ò¹\+¢!ßK·ÚP8?ù¹²åµn™,þÏwŒûO­AFŠ˜Ž,wº‚î+w`ß?}úü¶Ôš[*»}^K6))¤©†¨7u]KùÈmNI‘p}5ܽU6'ß·¢]³en£ÆÝÖ§w ÜÖ¨¼$×»ü½~R4OcO®æ…¦éͯ!&óOo"•ãE²$»EVM$(ƒž ;e¦˜ËÖz 5›“ôêÖU³–3ªVNdê.—*qšjߣ>‹à¹)xâ‚ 1•aNÚhÖ@pSz¤9&XaÚ,ýf#¨H¹S/‰©™0©¡RÛ.‰âD'ðÚÁÆ7lFŒÄú«)a1OÓÏu?¸]‹5šˆ¢È{Pbø%´Ž£â:»u÷4Aj²êqCè<=‹n‘Ñ€»é#Âr‡rS¶rîN¡©<¾#I¦ÆsˆÜ/yb5–…ýi Ö¸þ¹µí¬­»ö{c{ÎC+ÛçŸ:cëÒjeIÞ|ÄÀ¾WþÖŽÿø©ó'áQ~¢|f€Ô½l™sîŽáôù!=H¨È·¼õ˜A?Ÿí^4°-#ï„]Ê"fg&k¶!ue–)æþ»'ƒþ®Ì6ó‹ŸsWÒeÞÒNFÞ0Ä-QXÍaÀa‚]šÒƒZ“#seh|±VΙs{ÕÜ |1¾ÑåÓÔò°WCÚ35|üf‹ÑŒ·ÜíM§! 0*±¾ìÈ îDˆêm+û3ÄDyÐìwc»ï1GÙp¦1ý·G3j’U~iÚ¸Ÿb(²IÙmÚ‚Q]ÈAÑà—O‚o!, °Tf6°Á¬új>²GïÓ \Œ¢EÂr¢ˆÉ˜”–f£oË´•Æ:áXÞBCnpãó÷5V_2[À{´â¶qÕ–â¢ÇW·ßwÂ\ßo&—Xèüß&^upýõf!R¡g• ã8YP=ÖûŒ:·ùÝuCÃA扈vÈ´þJ!”éw‰¯¦HwÔ6:»ÿðyCªQÛç(á½XF6£\Ã:·\mŒëc“Çõ]laSÕÐIãÜ)Ûeš(eW/%'xì?uÚüšaöþÁásQ"yt\¦#Y¬‰ã’P#qûÔnOÎÉ”Dþ·g§¢Û‘ ‚EQ€a $Ç®ŒH™mJ¬½^†[c Á!¤c÷ÉÝÇ£lCrLY,Jx­M0Í/á™Q2cì¥l²ñ1\Óå4xdh™CxÆü÷¢-ß‹˜FWöN9i޽àš×<¸ˆÉt"#há¸L9MD ¢­x»Ž#÷5” ã“lNöÉÓæ·¯yz \öäšöá§÷{Ÿáòßß];´|ýîvØöݯ|öŒù¬O’„*²•¡Ç@S½ÛŽ0à{ ^¼Æpýðò Æð¹3ç³þïtÜÉtpžœ0—ù·¤å×Î_tê}+îêßÐ?º}Éê]cö ¯Û½|Þ/ž½kfв½evß{ÜàNœ{jkK«Äð±µ¢8‹5`§Xúšh×¹´ÝeVŸ>mþ7Î_T¿x$ÖHBnûÇ þøò¥ÇÜ1VópÚý+*MýÑ“æò½íYeZØøãÂÅ×<³vöèŽÑõ»çŽï¸î¹uß¼pIÄø´é}xÞfî—ñ™·=øûëG®zzM±ž¬Ü9²nw]³føÁ9›F+ˆm¢ûé W!‹IZÇÆH” ‚8ð%öõ^®ä‚CoÇêÓõîMEDþI ^ßž²w  ^l)mäxÙYY›ØpÏŒÖeÉNìÁtЬRôƒS>#ÛÉ%:¯¬¾m.xN¨L§²!f-"}ƒc:"ojé(iíã §"å€Ùì3ônÙÎ"ÐÕI:Ýiq¬¼ûã«ñEmÅpO¨‹Üöì{¥N|hî&üy=íj,,¢à_]=tïÀFçcÏ{d+ &"ÇÓ‡hÝ®‹~¾üÐçUÏt £ƒ]yËfç &˜nO¢é°›F;¡þ ^|Ÿ>}A\-^U?Åmr쉬ҷ/ZRVoõæ½>«Ê¾~zŲ^¢Ñ»SF­2ÅS’:kY™ås)ëû/7´ï:ä/Ó„û?wÖÂ[^Zÿ¨±ï8fÀÙˆƒ•µûÖ‹WoÞ3åYk·îýÕ5CÜn,ìæûÛo;jÐyſޱ¼Lyïu"å#zåd½e’œZZŒÎ\®²‡HqJbOY¨€×%§—q‰ÈˆÀ­Ä梟ú0-©dÆÆbÀ´YÛƒeO¤A¤TËSZÝ;Ÿ+—¥<“mšŽ©)Õ7Úìú0Ì—ëçEyœ]'‘b'­eév¸-†a!SxæLt«7,Ö×Û5Ô„¼pwV'³Ì—Õþˆª<Ò2Œ‰ÀTÈŠÜúam1s]Y@Å®©‹üΆèÚç:®âsgÌÿÙËN¼{ì–×ÙÜäúmûNº{Œ¼B^lJBCÜòð[KÏSqí³k;c8sÁO¯XZc¸õ¥õcS¡9^b ¯W·õªÀ¼Uè|ûð½'Ì}©¡Rz•«[·uŸIôÅî'4ZêŸnÙ°}_\a‡,éü;Þxä€9y_>gaû¯:Ë(ŒefƒÎNºwÅô›FQ{‰êo>r| U3r)—³xx-´¨©_ß¼`±“«È6\_ @¯Y#ÛN¹wü—W zÿŠek:×|qh[ƒ‰Å—ooÿuÌËÛ ¿kìÕWÿ_Z> n\Áh|ò©SçÙ3™á`ã⮄ûÉÂØi¿o[Í"2kjT„0Pk)M¿ ì½M«CþÌèM”ãš­R'†ïA]0…viQßÂ~""ŒøÛnDgM?í#ã鎖 U3ÐßÖ6±¬åy­À>IóGÚËž(Ö¡ûÎ3E„­^-ÁÁ«aˆu"Ãßg_í¥À> ³ª‡!žÇ¼£*KÊ­ox~-‘;w‘ ?‰c”%êÈvâ37à÷®™0¬~üzc·+Ÿ^sᣫê1®Íþ‡Nš[>)Ò ^+NZºËI(|]óÜ¿CQƒ.|lõÑ·þ} 'Ï#R0“ ™·*ÐåÜúð„»Æ|µÂ ~vÕÐÁqŠ=?½rYÁ2¿¸jHEýÒµ­ E7zzñ–¿Þ9ö…³°àfÜ2ÚÆ_̓:ù¥Žƒç¬ò Fœ8wz—Zø‰Š¥@¯îîlêFDñ÷kf <»d+ßòÀàÆ?ÜPɆyo>jði³ÞvÔÀÏZpÂ=ãåx~~å2&Ÿµ^¸J;q×ÞWO¼w¼¶õàYåí'W,þۅß?ØÙÕ^á-G ˜q[Îò¬W~t"× QÖ•O¯Z»Ë¯ºLÞÀ,R´ßÛÄZ ^„ec/ñH«Å(¬yh Ò¥²CI‘aç7ªž»¨‘ƒ ?㌖ pl–™¤!Ô÷ˆ¯#õ’­Q\a :Ðs ™VlzO_« p*)ùó©n(c0¢î“‰g%–Áô~çæ5¬ê•þtÃÅ“@"ÿÑ«ìà /¬+å†Í¢g¨1­­0ŒüŒåÿû1e±oÆd¸øˆhk^]sHd`Î8Ï/I ãZqÄ ª‰sl!3n;Ûd= hIMÑÙ¼>¯Ã}FhÚæ|d®¥åQvlìðàr(„”ŒƒƒU!M¨í‹Œ|Þcø^‡ æsqŸo|CÌ8‚¦BÖ? ¼RÒ ÎÛØŠ+[€I\ §Ôaò¾–n+Û}öC+«Äé7Œüòê¡ÊU|Zæ Plƒ6õnKBÇöر4âÕ‚`^Ë–È ’’Ï2}›úI47üÉMRöåi­‹qpñÜÓig Vži4ððùÝú°‚3Ò q!²©y}rm×ôTÊËç=ºª}~ýóë>qê¼Ð¤¾9jåk'^ vqil"Åf‘™PJu•#e Eéqu2‹€y 1ûÖ£.š<?±Ã“Óz_:kˆm*ÝXÕYÌ\Éø`m°üG~±‹°åüEâAÏ.6î¡&Áî|þÊŒàžjõö-å̺Éáj,Þ_7y‚ºA¸¦Ëyxˆ4ð¸ë¬vú+¯þ­‹Ví,à¥ô|[°ùéE[–o_½eoŒí ‡Ï&®,pÌÿU@A÷ÄØa›È’A¬ôO0I¿m7o=…$£_Zj‡1YÉb^µf@CT9F©È%—ÁÄ Ëð‘Kd?8"ž, 2« 'áìy)œ«äþIØàÌOflàæì-°ÄÈð÷¤ßVž1ÎuÅ[dYÂÿ„© º˜³c*­64Ù÷8ץݻzåô¡G!K‘ÕhÉQ%gEŠ!eø‚R:¸_\ïÈ=rP‚ºD{2õк“Kýrz—5xê}ãüñ®ÿ6k;ÜÕçÏ8–ÞðÜ:[v‹ê9¿„™VY|aew¾o‘Žtš…ÚZ.H`[¯ÚmàžZ¸™ÏÏypâ·Ä’×T /­4~?þî1GI/wòÀ?¹l‰•ð€ËkGuÚ‡ˆpÙ¦®N/Êé ‚]ýìZ§(«† >Ä=0o6Öi¦Zö0|†Óe˜Ü‹ÕH…±×@®QZw*Ø¢ð™ÌTÍeÉÝñX9×ç«UÔýƒë4G£L—Û1™ýÉ„¸ ­«lšU” "{2Ç1^þwelo7z$ôеÓGÏ?î8—§/hQ«§EÛnŠfzZ_˜ܱ≷lïÎø:"÷Ʊ‡½Gµ†;mî,…@®“øSå+2t5æÞ…ÿÓ=ºû]*íø5[ö¤Æ¾ml%-Ùþ÷ºgעɇ:_fÐ3Sõ&,-ú&Æx_(öáϼ8îÎNZÈF]Á¼Ic &;5½˜1ŒnçÆß ›)æn'Âζ£dœÉdþ›¯ž4·=À•8áÉ¢‡É{íè¡rG|{"‰3Ê„ V­¶ ,SñSbr]Rh¹H×(ºžÚýS[G,,3¡HGX¿ Ñ@…0O†JUí$Õ_Å6jaË çšá²)ž°Ö¨ç2õÓ¥Ú™Ö°¾ýÂlð&°;ùÜJV»)ltû-ºGDÁ-œøF MÉš ›Šþˆ®\‰3ë°­¼U*@rÕvl0à»’ ¥ÍÙ©Píz$$êwÌ¿åD:eJÀ,îøJ¤Ž)Í–© «O@í½ê¡éW}©ñØH¸ÉÏÿ¦‹Ø,\¹3ºeŠU9“/ª)ÃUB)+sèôþصMYl—˾Œ1ò=W½ÂXˆ–Ù*;ÅŠü‡kAF¸*$›RXˆqÄfnIÛ„VK™+ÈY ݨÈ1nÙ¹ßôôY½eO‡o~ÞÂ:ñóg@“>qÚüöçÔ¿µÀ–"×w,þo¯â‰%ºyDZsBõ³*˜Jâ¿t„*Ã|Ò½ãåívOx>¶m "oŸÌÛ)\Þ:S„Q¦ÊçTq=È9=y¶ÉG7Kïñ©Õ$-ÉlGüHXm,›¿³›t¸mc-7À1šä:‡¢,ýÇžžò ¸O ØfÞ›ÞrxtEšé­)äÂæà¼‡×‰&ÉÆÁÍ¥ÆGöÒ=Öƒ)#†jT}©&È%dêÂ[žñ—u2:Êâ‚^4“e©Ža¶1&v}2@¦º+g(Чªe”GÀY"˜Ü(bªŒ¸<‹é°‡ Ÿ4éþá¥K)á{ý¼ùÉ$X.Ð,¸"¸‚¤ýüÀ I)²OÑÕ·Ô†³Ì‰V½waúk C“ÆàDYñ»qŠF¹ñ˜ƒz+®×êÃcU‰vƒä©€»R;“_!kÿ슥ÆëàGºýI^}õUÐá·3gRsÆŒ.$*zÜ_:gщw—ìsi>CWà5ž ^ã~Ø#If j²Š·»öt.ò‹—„Ðî”2ª œfS¸p—¼]]mo 6^‡ç6 .{Ûºˆ‘D´ÌßÅÞý-"Kâ ·#S¶àqPH!Ì!ðt'ðCšBK”z9ÊD˜×£ú(ÉØ%“;€åìOÂa&?È‘f"t¶¡¹$- {l˜ÀT“$ðŽ=D/}KNÑ)Oû€ &€‘QBCTô`q3•üyÆm¹À2eµAo‡úÆy G×w‚Ä27UíC{“‚غf©ìbMp¼\“m,aTñùnzq§ŒmÜýŽ¿º²N jx¨Þ)è1ðWõº79yÞÍÃxƒÛƒTºò˜AªC]>GüB© †X¯ðqo"[Næ€o¼}fgqè´YVep/-¢ìï^´˜Á5¥m!Û_}Â/miŒª-ª_ Cå“Ñ4˜m˜ZhüYíª° ¿ûD7Û\½®Üå@ãSg™þ<³tó‹P_®” Ž¹»»oûÃõýmR¤]Ó’R©ai4¶}êÄho„l4>¥ÌZØV7†°»™Bµ°_„ˆ[ÇŠá-\XDe|2ö.&‡æŸÂSÂëƒpiÄ&Pþ4“hAê-"ÉÂ$ &?22«æÅ“º³ ´´ã¬«¨`˜²²¶¿öö$#±6äÏ#͵Ð޳ùÒ^Y´eˆsÛA–§a§¨…w—̧Îh³b*¤¶ß\=4¤ôFývGD° ;ÉψñR0.³¥§#\ðèªñ’îÒ묇VZL£¡óí)â'ÏžQÅ:Ø‹Éc(ÎI»SÏäLŒau™r¡Ò’` õ65˜cÔ9Oà c7¦])r!TØ·S0Ö&É+´jVÛ‘UjvvÛ˜s¿rn™Ú|£ÑÕ¼uäHózýúÚaû$šrp§›9Gß¾¼íiêõ‰Óç3`—ÅÖëÏ7ޏ¿°sMß¾pqI}ùHoŸáÂVáÒyoËŒù²wt5œ„Q®‡ß -Ô¾(” Ý!3h½®¢²ÐÖrê^„‚0ÍœåÀ.@~†ÂÍId»ÙqAzGôäê˜@…’l;R>!…v»ò/(fä$xÓŒ>`CÜªë ˆÙYŠÜz–‡Ç½s6ñHòT’œk‘å( °8½O"¬Á ô9Œ¢Â8Öeô¹îÕucáŠn•t]>4[¦ø-Ÿ>c~€}ws›«³óH$…EÃ*9N|ß„Æá[Ž(p¶”°ªjÿÖ—×/X±£×$Õçå  ý²cµíî +¢Šº•wÅÞ{Üœ:àÍGÌ®6ß•©«1”Ö ÍFüªÏ_sØL|jo½ õG¥OëÆž–ñ’Å.S½`Ë‘·VünÃûüãuÃÏ;`û¦•퓘¸á"µâŸp<$ËÈ }°’¨z•`KT£À‘uVÊ»ø8w^·.·ˆ:ï8f°ÎÝQU¯çnªÍD)‹½íèÏŸ½ð¨Û—W–5Ô Ž¹}´s7§w䌛GaÚð SlÁ?{»@¸ùTöqçn‚÷V¼Ã3e»ï {çÈI=T9×Í~$ÑbsH /ØÍâ+¢ÓKDi8E•pkpX-ü'Uœð±hƒÔÉF÷'ÆTFS*í$œ÷¼ƒñ¾Ü“ïX‚N$ ]!5ãW—îƒóDn,¨ æÅöt;qË¡OˆÄiHîï m)e-Ú×ëê©_3Y §ÅÁj-ÝÛX† êŒÊÂi$]¼27ï’ K<Ͻ¯Ê¡ùàʃð¥SbŒ‚ô1îs†}dr+gð®cÿ³1<´ò`[ sÎ/ {UiÉ( CÒ+é¥Ãzýp#ÀhlíÅ'À_Ÿ?kÝvA ˜“cðÖO ñ%N¸R˜!ìTËõ·c>yú‚ê6Î4– SRe—«cý¬Ù«9ÇùýóWy¸O>¯Î:dúÄ·t*eúxÙ’vÀÆû:Wî>Ûõ{\NXÀþö.®mÊdìŒÚC±‰J ¨Z³E•;ú<£¡qìªI(ÈÞrJsY` J86ããÀ8Ù—F—r˜Mƒ'9l8R1hl»ÛhÀ0©·-ö‡oQ‡I™wå¬PsˆéâpÏKRIuÒ&uU]#þ Ƨ¥$AÕ£*ªàP¨¢Š÷'Œ»ã|òØ‹†k»U“¢§ìi)è Šˆâ5åKöËÏ^iZUÛè÷;ÀíÉÙÑ|õêD¾áˆÙÿòñ.´§xÕª‰‡ÍŠ®J@MÂYoó¼ì˜™7`òþ骵Æ@L‘m¦I_ Â)÷§Ç¶ÂzucìþÈÙ3G¶õŽ*N+@tP;Ù‚D.~¢z$º–¥ÅøÅòœ¸l+;°.Ä\7ñÈ#o_¾xÕ.®\jbï=¶®Îb-;[?™øÙ±ÎõÏiÿ0P€™Zz“Ýê’‰Ÿ&»™éññy]Ë^£êØñ‰Ÿý|Þ>¬7Þ¥ýRoþW¨:"g7ö8x‚ů„n&’¥¾ù õEœ *½ãY )C£S`³îC’f.ëTŒÆŠZƒ=$"É ÖH—k”4î×/X\ 0 Ñ™t«£¹µ @'uº4Ï+¶žóJî¢ÔÉK`«Š€Ž¿sù7Î_̺œ QjûS˜1”ûó2øÈ+´N…´Åv/Ä©ðëÃËÝ1”üoÓª5':;ƒÆvõ§Ì­¶eæ~vå2oëls“&v™E%¯ø»k‡O¿Eå9Î{xå±w}÷â%‡´gC öjüÓ[TÐTòKçP¢ñqÿ§Ü»¢«ö‰Ê'öFXÆ¿oÖë?à¡ïšµ¡F]íLç´¿Ÿ…aÅÖ7[\‡ýø²%ç?²ª‚†{go¨[P¾ð.:¤{ñƒë=½ã›K6²ÞÍp×å>«ÏIýü?œð=uä4VtÎjf½t€Í:¦¿¬cZ膥÷Á&&D× vñtÛ HÚ©!Ôõö¦œ…Á‚ÏÒÿÐðBÁ #ȉn/îuaY/¦ìs-ÑA+#±X:Ò¬v+£ñ9ß‚©5¦ê@;dÑì,ãD £ï’p7-ÜQÄŽ³…Û¦réÅa%¶»½£¤ ܤ(›`îÄSjÏÚÅæ¹g2ò`sc oW >p…âË¢¦ËjιžÀF}nG¬ s‰_@I³\T»ûÿù:‹oK–í­žÿ¹ïUݲßëàÒÄ¡Eéà× wwwkѧE‡s®áîîî²2gîÉþðßö—'#£XÉ$À%8û!úò‚…Æ멟e.}ò4ÀMÏoüŒÇi™ÊPpçÀ¹tv`ìTfø´ð`ÓÇ©ŽnÇÀé@g*ãrÃðor—å‹°&€yp}À˜ãAò²\àM¡wVó¦æÏ=]wï@[ÝJÑߟŒó»>¨±ZΧÚX¡ö¹‡øNH)×l `o·w#yN©9§ÊPc¸╇Àgy•R+ç¥sV@®ý18ÞóÏÝ·§¦õk-]cH¿\l'‰cÞÚ+<õx¾ °Öbï[?ÔYÒ¢j£u–¡U¿@Q[;· ëuª‰³ÄÆ©-W9µpJŠ;°ë»pTxVZÁÐ^òÅí°ÜQè@Ÿ7ûcc±fJqé£>¤&DåóR+®úÒy/;Xì/žÚù(ýÔ2ŶŸÏLƒJ7+{s¨V(ª÷ÉNPAq–(/µ‚Ùã|`ƒ´½!éè ²§…B‡ë/˜¶ýœŠ¨==§20Mçiß§'3œÀúg8N·)3–Ù&;S1³’`úП±`ú”ÊisG>o}ÔÁýY.ô.e\ûûŸògü)«ÚQÿÔ­=¬|Ëc”Ê?ØÍÅz€IÝV ý@ðwêÌUJò” B·[`¸#= ]î%ŸbIYyPò)üAAO{¯®¥ µ‚õ’›†êâ&ªLsHˆæ ‰âÂr_®ÕÊZ¥¾£TŽ8éîº%Å–ø½gûH±ѤÅÏÈ´Â¥¾¥üñdï­ÀË‘ÖOPÿâ•sÅã¹T¡^,fTm ÌÖ¦ÑüJ•ÿ–ZÌ©w·3u(Zþr|Žª]2NY¿vŸGwðTsñú)®gSéXL_£/­öF¤ˆVSåË`W.Ö;Ú´T{S‘Êô9Pþã'tjRx¢ü‘-Çáªÿ¯¦ñ@öi§Lç ñgBfžžtÖ‘ ßöÁ€9Ûé?íg9f¸ú£Ýc…Dú?±ãO·Ïr%s$ñׂ²¨Q'ŠR^MúÉr>Ѿ˟X.3íÚlºn>¡`‡Ê²s{åJ ôÙ!“û·¿ÜØÕâÈ€VÓhѬ§ v´e¹b˜Ê£é#<¡ºÖ>988< ÊõJ‘qʇAIôâAIÐsú¥õS :Oeš§ÂéÑííSÊŒ¯+JE¦PK¤`âçò4ûõË‘l›ÜZ¸ ’Ѝ¨ü…69¥(.X—Àñ£,òA·bc‰{*¯¼5K'á ´*QXàÆ šÈÂÿ Åú•ÚL _[¨Ãª™ö VtÑ¢P\ÉdVª“J`w]Öv wºqÌÞ ¬ÿÉv2œıRž™Öj3†ÛC&rTÅçÆrÜZ.%T<‚잊4‹Šó‹31ê0( ;ýOàžÓÄçxë âÓÎü‘?—§B‡ˆ ÷T@g@@|Ö(õ3\¸wNïŽx˜;®~ÂCrSê‡úï"C|g‘ñÁ°HÄí|Ì{į¥BØ­–Š’Q³Ûý Õ݃WÖ#×v[ZyÕÕ©ƒÅˤÏô‘•4bAEiØôÝD˜¥ƒWÒà#Øáõ^kÚ ê«o‘Àà§2`N¢àYF8º)é³,؇•®j*–<ß8­šÕï\þÖn¶3ö¡9ì¹xTÓùJ&·\»jʯ¼µ‘S%ç’ö¥ ì\4,¥SÿSŸºÇFs脧įËS|êü¾µï» 5¬÷v*õà”¤òÉË-rßÚ¨{#ÍÚ"ub»#ž¯@ýénìµç!½]—Š€ËI @`Дüá>©OöäL>…Ý>*â»O*Ó.þC§ˆÎ‡:ü3þl¡ùFË 0@ŒH8Z¦\-ýéüñ-€ò4¾>fH±^Õþö0/xvC<Ì%:C‹¨ .q4W‘yòþ| ¼ùz(ò˨þóç@Rê]ZªÝõ.¾Õâ/0­Ö,x9Öxòq HY¦àæ .¸”,Ø­ìçšé¼"ò-ˆ¡ R⯩" ¢J* ¾”!Ñ–(Ûs¿¤v¶~™ed.¦3\M¼ÑLeŸnä©(çÞÌEnfÂØ’´8£Â4üXݱwÁdzåÈXÙ²ôbû MOˆ”åJuLQI]RMÙ«{¡žÞE÷ú¨À“zDÑÜ÷mV€•nT¼Ñkj÷1]¾„Ú Ö™3¡ê¿<ÕJ¬ª¡V}–kè­ÄÁ©{%êkh¥žÝø)R€otpM ’ÚrèѯÓé&[2˜hÝòê,/>z<*§ ÿjnôÉÓÙ>mÒÒL±²êj‚*$ˆ|™t:W]ÆÂû˜²‚[ßTéçªç¢{*<ˆ ¿óg¤á±fwBuçÒ-ˆi™nmYQEQcG¶ò´–룸6TÚÇJC¥Nu •ž†«‘É©«/bVŒ«"\7M¯o:Ó¦‡ÕÜ9}ì†×AÈFÝ Ÿš”´]mb9#6A½© TÏÕ¢ùÁM¿\¬}S}ž'jL]`ŠCºdËˆÝ QÛ5lJp£’ ÜPä\\³ñ(gO@vÜçÁÜQ®‘ç8íÔ/Ì=‡\ƒãGgÒR Ùôá ?ï{húçÀk†8Ü«Ó_¡2E‘à#}(õ?3Ÿ(ò26.;@.#\ÖÈØ\¢Q—M),@а~TêûoÀW·ÿºC%{äšéþÅ"!ý}Ü-]¬+BF<\°•߸¾a%…ê}õÔÇY8·«ôH5°íY¸´lÀÑ_º-Ѧ²ò5qÕ]Â·Ë §–rèé¶üVî 2Ug­oy,c C¢ø? ï6ì§DíÔ+Ú° ü¾¼÷k¡Ñõ{‰‡ˆÐˆÒ8L^wQ'tùFãÚKlÅX­TÑ~D zît£J»d&bH?BHTueê÷ìg¿¯»Ï…ÄXg–øÛ¦WIóz‹âzÈÌ(ƒj/º¸hôËz³vê >H- Z§ð]ˆ§N9U]1—"ò‚§@-Àúâ£ã%àæøx*?ëËW?ëË9sɧÃì¡AW9iça¢éƒæ<ðtÄ™ð”7<ç“b†–™~Z\PºzaÃ+Ÿ·¸³úÆä+w#“¬Vßèò0<±»oÅèÇÅ^©¯P%m/Q+¡×ºìsáƒ>*mº'4ÛLû/S¿ÿŸÕZ´âúxMçâÂ]ï µÃ_ÑFÀ |e)@3ñ8‰ðЇR½x:ÒQV¹¹4FnþãvÈÞ›èRU'—{ë¦4oñó¡S7eÁÚ¬Dr ÙÄvä´-õ窆ˆˆ©ò¦–^üõÚh¼·îRÃ>vXË}W#ŒLeöÖŠëR )ÛD.ŒV¨=S_uÙ±âõö#ÞËÛüö®‡uÏ/ñR2ÉGŠMøò\¼ù¡ãÅhˆf4tPòw<vÑê,:ÒÎ%’¤œ í/~Æ#P+[‚: ’vƒ˜hÓ 5—`Ìi¼€ûD=°Õö—·ÛÑèçÐO ¯É¨ˆœè§…§½®BÁc+u8¥ðv»TþÛ—Íýt´ûõzLT(p8Öç/ÈŸQý~ÊŸæªNM"—ò>Gõ‰múüoSMÏú”z­E§†Ê{OÊjl%Ž“’® ž"Ò3Þ&Y»mQº7˜ÍQ4w?wÞ×'op¢²d9"7oLr¡ï|ª¿{G¶†Ñ6þ\¹TÀI½i7“yèµ{Øx/C˜¢àU[­íkR“E¨2ˆ›s©¦üš·S;Öö¸ùý[öbŠÆÆÔk³®Ám\iv2OýÆø;8«Ê/¦O¦;œK¨ö3Vć=-ˆW?»ÑÒiæá^Ü…ˆ©Ÿj;w¹ Ÿr{Yz"·®#÷õ•ÁôrôSN«¬d=v d­Ô¼Þœåâ:‰1–¿/l›9Ñ^DhšÛÄEj#6DŒ:âȽ_ïŠk£¾2©ÝÿÖ š]Ú½y1Å™Ý"ìzu)sõYú§v¦n#c"Û|¢°¿/Ž.Öu)4£¤.pÃ_%Ž™ë¯Se£êWßî¥J ÓþЕ÷á™ú¶ý¬¶ýkc› FnàYªŽzñº<YðH”¥>kûn¸¦}Ë—©÷NZ*R=úÌ.žÝŸGÕSGuKqŠæjUÏ+Àø²:º¨ûštÞ™L‘Šå„uâtn&Á ÅOÿ³00À·®,1!>iöÄB(‰q@ZjønŠH hNOѽ^0E•¬UÆ_~ôHËÀ%W2ýç¦s¤ýõm~éöú3T¾ä*:;—¨£¤OÝÊ<Ž7Ètp&ýç|ML¾Ztiy­ÀC¼ út¸üúG¸>êT¯M5͸01ÆÙòe…^¯½^¿ü†vï>$þ·,}o§UC²4<‚ »mÅ}:òúÈsG ¯ôÀöž(È$¨",ŽÅ—ß¡³Å´ ²Ë÷§.7Û8ÉízŠÛ³ù–urS¨,» ÷ây¦ô‹I²âúlg ªº“wÿë½ån‡…³¦à¡¡ð‘úpÎÊmAJôôs/~Jdçmç˜Ë”ÿþyúçÛOîþu¤©shwzÒùä~ˆG®–i±›ù´ãÛÇ!.yWÝÜÿ±…l7M:ï€Îù" ¶p„ê{›ì+h6¼ùQ©cŸš»Ì5ä‰.%Ú /@Mx½!׉w¨Õ€iðQ}\àžv ]xús€>ðñH:vThy5ûnÓáDù£‘Ó›–}< í ™ûž‚„>3Š!ÓgêSz•'áË€ì06Ó"+¦ÂûZG*0dV<ƒæX}Uðko@ðl »Vèò”ù’h÷Èf0Ìé úu‰FdlͰSQMNæ2ñ+¿šìÞø Uãå~³l}ËÕRQ¡öãlÜÚßò=+»Ù›çÆÂÑZf‰’nœv~ŸAÆÆÏRi$ˆ—ŒeTQ® ~£»»è±¢HÌ×m6i¨øà+Éj&QÛ{Ú¸ aR rõ‡if‚þ½k·YÁT{?„““‡Þbßz%d‚–¸Ó+V­–™ »ÿÆ•–fñçe•½Ìc‹–ôµÁq_­~TŠôµµûFÊ^?lù®®ëA„ÙDZ.Éu¥0¼H\â…ãÅçêŸåÑè|Á̺hñ }™7ÏvƪùÖOnä’Ð#§l¿@–9Aá1jO¡ý(Â7=3¤plËú—ò~CüótÚÏÊqô§‘#3ýÂã9sÎDDâä"nÂÌ…‹zRÍ16¼üú"pÿ«›©7 ëˆ`™¥çRâc§ð€ßø3–Æ%]³9• Ðqö,’;|TBßܯá6úËÉo,}ë*°2He™]­6Ï×Rã„ìû$ŽXÔU……iï_¹zäÄRÅÓ&QHuä§*mRRH¯¿ûmªªÅÖOìZ"§™–š¤ßUÀõèàÚPÝ‚ ês×/kÛL)¯ä§wž½Pð”®[xlO•¢§úµÒ•–{•\~–ª$]õÿý }^òÙ¨/¦žŽµpÜý•eÌ–Î>¥ Uõ9² âñIþ4âE§"ª„àÀ=Ê&hwŒy"ÃûeúÏéë÷ô¡3ÏpTÞëç.438'â„»øûÈ3C@¯sÉTÔñ%²@|¾36UÝ~¨hw=ŽúAàœGÓ4ÙŽõ9è'…Y…¬>æµ×oRÇùÚK ¤,™pŸ¾ [«yF›Ì}iÓË D¥fÿjÓËM@jBŽ›>`n½$:­l† èqsJåRš/ö‚~aa»*¨é‹Š+œnªíÄâê{•ª¢¿_©–j[4ø¹:ʤ‡•y®ÔÇr ¯›'ó*î¼7“” ›Ð|¹[U?õ½©,ÓŠtQ+¸E¢±½”ÙØ¬,tX®ý]ô­DkÒj%²ÂÓy—bº•+aC7ïw8}ü{×a™KWä(ì&ä2Å9¶)z7j£ÓÑÅÊ`J#€ôtAŒäƒ&Äz‰HLŸD‡xMÿAöi§¦]rãàŠÚ€¬°ΞR°ž WQºßN·³ˆéàþ!"$è X£ÂÏé™Ô~Ë ‘°4T‹l`* tÍYÊa–žèÐorA6˜®å«²vÝÊZ+”÷§îµù”Ö^Îc¸Yšñ1Oª ]k´»rì |»ÕÙSAZ±¡t’à^õ9—/£!ÅXÊEÉ/¾"Aþ9ð¢¡ÓnOBT>0æHn£™ÜK2žO½>-2¶Ó¡ñýº–«d‹?Eżº9-pz+Çè齄Æ7¨ÞS¯¢í)-3-à²êsë·«hÜ(ÔÖGé¾îsÅÔösMðv`çŸKïÏKÜwŽŸ<‚éB¼¦+ï5x„ÇMŠ_òÒô•y¬N$š" $µSÇ=_¯¡×§=våZÐßæ¸teÎÙÍ*Ñgþò6_°ßÈÙÎp€¯* õÛ½BTõªÂ ;nÞÅÊb™±«/»vw úÓY‹ ˜ )úWgR¬˜Á•—‡\©–(°lA*ø,ÅT¾Z~ÂFêù]×À¶aÀÊå–‰uBÍ*¸Îå;ÛÕ[­a2ê©ï¬Óý¦Iôƒ*Ý(ÓúÏPw”È®42‹iiœ{—)ÿ÷4…@´þu3*rÛµàµÏéŸÇ/¾É”Ê?‘|ýT:-G¿-ÌÀ®Ç iFÎýEAyœ%ÐÙ/ÕL ¥µ¿þCVW‡£è¢âÇ8íê•°ÉÊ–ÒÓR+´SU%7Ð%?¿4ëi™ž?ë‹w'4SŸFS¦ç`·Ú÷pùœK¯?}¢Û ™y˜„òN&ÓN}úГáŒ=‡s/Àý˜GÝ_1£ày"{xYx§‹úÜ¥ìµFXÁ<«éU±Š»=âW"Û:ÞÛ˜)ý)ñà4a±i(fô4 Eƒ]%6õA\ÛœÕÿo—ž¡°æGÚå¦ûó¤ƒT»¢ÅXÓ¥ð®UµD®ð­¾X[hýÙ+äxu“[4qª Â×>¡äóI¸Ô­IïãÞѳA6+¢®|çî¢c5c.Ïto¬Ï¦–¢˜þÚJÔ+àšRý¦M;C{Ñ_±éÕ{&ýCU·=:Dq·þüË‹K±×z±zËX¡Rm]Ù@c ¶ZS×Vî°¢¥þ bDcRαožŽØ’0Ðë:ÒÉäv½¯ÿ5aœrM«"w¬k ô‹~&œ¢_O9*ŸIvK|)&B˜©Ô‚Œïh÷¨PP½©Ó?¨}ˆfÖ9ÁÑÙïéC#Z<³Maf|î~̓ÔáiÏK ´uÕyx›rJXø&Ú4,ë¥#I%·óá•q!D®÷7¹‹œVHëlӤǷàØ'O'¦++¤¼vWl­s”·1żd‚œ‰ œ¥‹ràuïåØüRVÊÆÅE(->Ð2 %8°â`„¬ý#]¤ÊJr¥ò® Ø9pž#CÃ>¹ÅŒ¤€š,S¨O.=^j¡ÖZI‹îQ!,ÖìÔEFO«áJn€×ͼì²EùÜ?€Ø-¢ùÇ[{Kžš¬ß ‘/e½qºgf>Jí-wnXÛ˜SÁøÿÈâÒW08»fdsÝ͸¥K‡ó$z¬›šq:?¢Oéü€’Þ´º¶ë;ÁqŠº9ŽŒºTã^èzmþ£ß7N„|ODUn)°àÚ ÖtAp0ã`.\]ˆÿæÒâ§óçï~ÎQáXÿ¶ãôóˆ)_RŸö©Lç£ñ‚òÏé0—fÚ¹ÔQjô®Tç§g£Î-¦Ãùެò±ŽîLPݾøâ m²žˆnZ^ ³ {÷ÓÏ“P縗¢ÖÃÖCÃèWÌ–‡šbVe4wG´¸09éruaº¸ü]~á×?òwüÕú›þò‹%W½¸;ÿéôã„r#^åC„œÚxíÒr%#[ÿKü‚ ÒØŠ%å#q;‰Zšë.§öÚ7Ç8Ò³’Ü/ÚK“ œ]ÆMpc³æ–I‡?y ‚«ýiMŽ‹ ÇãˆqÞê©BÕ/E+¨vÎ÷öÉu4Îéôñ* 9e xê æ 0Ø @O™ÊÑù3`Ú«3Ãçs4§£,èàÓŸÊ;zžÃ©(¦r»”Ù:ÐG‡vÏ<ªù_€ìžÿ—Îíð9؇åñont;ÑÄ¿UtêçÔ8)B¥ð7OΔ&°¼rB\A,ææø2É;!å9^û^»œë`CZù©ƒé;Gõñå4b®yNeYŸR#n¼«Šj35z—{oq˜Á"ž²5Ûjÿ\ ,?h¹ÝF” åDxU[£º\ùŽÊ‰Æ?ÖHëË+i£å÷¥ÛÎU%.è\ºè¹8~ëiз“æ÷ü%_ÿåøþWþ}ñ·ÿÝÿmEñX†ËìψœîlëÕH]I¾£:“]Ë%ÒvÚѤóLæ©ø¯­dê÷©UªÝÄü†?Ï~w95è0ð-ZÀÜñ¹ê9{Pè÷âòÜÐG©•R·Ó¢ã¡Þ¬‹ÆjRo`hE™F´Î:)åÙST~§2*¹ðM;*°º3˜>õן EsÔð³E”çêT¼ 4ÜÓè<¯?yBN@Î 6èÏ SSa* •1H ží~ÞÑUÈm‘çó¹¶Üë+•a´ç¨#ÐT,HÊ©”òšr Ú/ ­Â¦}B9)”ø«ó‰òXËçH±Ê»ù蛋˜Ä, 9žÆU ÒÏ]‹Ë½ÅÂF€øª'¼ÆvgX9š¨Ô²Úw½Lì­…ZAV÷wÇQpT3ó© â;Z3Þ˧®XXÐ5ˆxÉnÓªª¾Ó2Rl‘E›ZGp×F!îˆbÓøÛ¼õíÿŽI! ’Ê›ß/”â|r,ÿûÿøŸÂzÿýù¿÷ï¿ë/úºòú`ÊœËbnxBóéô¯BѾ±-Û%Ö\RùYL‹¦?|Õ£ÿÚiLyë-*5›ûe $»Ä:;õàݨ‰¬jûKý[Þ›ýŠ32Ñny[£üá€rc;)Ó¸£†ëÖ"µ2Ó^Øt–€~*ãp_Ä…ú2ºí(ªŸ<¼G‹Ð|–™ ȸ¤‚²|ô|µ¿›§:ëçÀ¯Ž©fÚ³Û·~ÎWÀôôyw<ÉÑáíð63jÐö³ãtêÓ&œÊ1ög5§<ÏëOY ÜSnžð¬x­Ž ž?—ä¸V*òøJ2h¥®T ÐoÞý~üH;%qUÏ]í#ðI ÛÎÔŒZŸLÆÃÎÝŸó÷ÿ±”ÿ£õŸÈoøËóßúüÚ¿ô›ÿÈ?ø7Äÿ±¿÷¯3çJÜÿ=>a ".uoÆå£)Ü[¢YëÇÒ-=ʨ« |~Íu3ŠK €¾Î§jô’òËÐôöü/ÿíâßù|½ìÝèOÿS.ýä?ø7¸òÅÁÒß—Ïʈ¿YrêÖ·ò>‹÷H¨±V‡FÓbñû,Z†Ç[©…¤ön{,<–éÆuî8Š_#ºØUø}vÑmèãm[ üä4µ¹ÅŠ¥róh4@tP%ƃ¦Ž‡‰‹ªºæÐqFñ1oJy‹R®†Ð9įЀøT¦ÄTh{¢ð4 î 5*ùt›úÙÿ¸tNx gA6p‰i½é;&¡ÛÏ>æ§ÂXrnúæ“§9³¯,M/‰Ž×T½9§tœc=5OÛì)/¯b¸ì< O Ç›¿ü=,G3¡¹nÌL©_§„³Ý]vŠ P8¾qzÇ»3DâJ'°~ òìÝhS˜S+]Žwwm5t8êŨÆú+ œvíG¦ömç¾Õßß^›ð«»=û´)zúv…,íš;â©qªU@•‘ ªeÕÙ•ªêuͦ4aúzÏÞ»cs¹|ï_òç€ï?ñ×þMã Ïý»ÿ¾ï¯þ‹—„ïÝ»"“þ¾Û£VDfˆ¶Êd(6\YÎÓ_§´kê 9‡øxþ+ $yJºÊ-IhŽžî~Ê0Â:?9"V¤_pZwO íl°.nsaÑc !62¿ÚKÔ>¾ù«@ O•0H âj¬,ªáEvtíiÁQ«¿yâñ=Àúýi¤eðú@j`÷çNσŠLGUÿÖϸ?:À™}>{šF¸unJ;3|›OuŸú4‚ìªóÔw¥Èq¯ÛS!„¼ 9A4•Qöaœ\¸œøN‡CNÁ8¡[ý[ýý7{Ù6h¹‰^b}l'l³;$/1¤p ¸»æcÃ)Z pÅ}dfÒ¿Áº…ug¡~ëjÍz(”=¿ßÚA÷k•HŽRÄ"l̘6fÃz[¢bbQµžÊ²²ÂqÀGY¥Ëø=³„–ÙL–ý8N{Óà›Ñé—¹wÁ¬¯ÎCc ë‘£_±R„¢Ñ{‹ûÛdêR$ c¾øq¿÷¯ƒÝ¿âÿýª½+Þçýº¿4þä_û7Ë‘\.Žû¹M%Få^p†šhdQšúÙÐ8e{RîÔ½3$÷‘ô¢¡r dù2ž%-þÅØ©æxÂ:Þëdƒ9+Ç÷†nüÖí¡—gºàÓaf뿈žþ¿I; n;Žk[ëç<æ÷ÌIn˜™™™™”ëÌl'™Ù!û𙂶 -:"[,“À<ÞÜýÕþ´RÇ~xFÕÕÕÕ{÷Ù=kÕ\¤û% À'v?õÌóO|.&í=€©s‘=µh®(¯2¬`nrî! |ëi+îßðäW/Z "7p Úް"PóÃáÀ„¾Cß!|†HM§c`ƱZ¡\ïòÀ„9ËøfIùà fàÚ|~ÚnÜPúôð5ùÖ|M†¡ø­ªc”©ámx’¬£jbG ŽªýÂjdÙÚ8ë²l¯¨`úX×@Ô_MŒéa«p7Öÿ8v [L†à4‡Š5¿^à¾ÏïX aËVžÎÆÒˆ¶X:V¹ª3œ÷*£Wˆ¬tBŸŒ¾€²‡]ê¨ÎøòP$«…v‰R¬ék˜j(bg–®T³HXÅnoWdvñž•kd4–›5À‚Ϻ„è“4 —.€þÃ*£TµÆšÐãøë·î_¹xNhÕk”ÇñásWxú¹´ç¯o†Õ÷ŸÍMÅw9¢ªÓè\m9«>k_¼z“ÖÿP_3”ö Ä{9Å €û0€\X¿ õàN‚xŽ]š©–›îòÄ\£ÍÐmËNáEG:–Ði\xÿ1K×YßP-’ßßߨ°ï\±!‡ºÓïI0Ø…mH4¡˜å:báú™óÖ³x¶ÁúB¨s@f|znçÜnÍö ²¨ ^¦Â´ýÖt"×6jâLÅå|6Äù)¦æ,8Hô9›vj¾ ·ðîÃ)`|¾ªÚ\’š•LæÇFž i"øú1K#îkTý¹0¬d•Àÿ–­•¶óØ4“ʲ¨×P†§·‚=rC”/iuo†ä©_á SHÇh†?‰xaÝí,Ùˆh÷ìG™5Gébó‚Z¢¹v€•r½«B5A–_­¶$Õi¶:“ëFS‘°Êæ’ vvjR=ä Ðmfü*«c(9ðrá‘Ê.c|€óìAtAîË:ÖOa©ºJ¢èÙåù ;~FÄüåÛÀ‘þ|µ¾z^é.ôÙóÖ¥D¸§îwªF7J¤ôAÒ•¬Uâ×uÈOâ¿ÙuNè—Jª²@ÆË³«¯'r€Ñ`†’ Q½º›‚ã5-0TgtÖXá/[2sÆ-OÌ=ùÄÁç^x¡)¥£^³mÿE÷nÛ+1z`]°eLÊwÿ.®úÖå ˜y€>ªñ&cVCr¸ìÔŠ¥¡íS>X@³k‘ yôé ȧ79EÚ³Åt‚õ‡§?ótPÆ–‘”\4Ó¦s&‡)€uk0~42}*a— å|Fó¤ÍšÁM©ë†€éÏ´ôôâ>—÷ú”´cèGs›³UÉÌ$˜5¸›þ§ï>LOa¹¥!ovHã=öo0¨CSVãÝóãAž@ å{ïevÝ6n}¾±ãŠ&‡šÓhO=tVí¢/‹>J‚ugÎ`£Ë[©÷Ÿ×Öt£uç-@U%ga ã!Fy_¯òŽÕë^aÎ_Sø’JªW1LÔh²ê!ꂤY½×rI Dl4-N-è–µÊj)üš ©.h ®”‹°H,”ùzE;¹–,ß·7ÿg¬Tš.ÏN½Á„ˆv©Õm,ÀÓz#íR+]SŸ‹›&Çh/UmiýÊe?Áø²ž—E^­©&«ØàÃ-™Ž¹ÉÔHï9kå ×o¾~jÏÜ®ƒ óÞ}ÏÞ0½ˆÇ'¥¥y÷›‰z^õÉë&w ¦/õ÷—5¹h„éitL5ð­¿ê¯MrÿêÅë`]`04,&€3é©’©ZG•Ÿÿ2¹'S=ûÜ é¬á@GðpÏ Þ¤ì¯Ô”—Aää¨nÖ2 õÿX8ÂñÃs nþáTú‡’öP(·Í2àÙLÈ$ÌF'“°f°] ð4øœ).H`¯€˜¥(áAÉ&µ=<·ÿš MyìÚòÓà¦Z%¥M¡Ó­Xj¼¢†eª†-Ó¤­ŒJWø=¶ñÍXËØdHôØJB!jÖ5ïŽûyˆDÖ%$¨Iªª¯Jú6Ô£Z«ëCìÕ`®EÇÈ:¾s!¬I©ô€•éÖíF"ºóþQ9,^ Py+Õcâr!»®|•×­5(|9¿‚<‡ ¼’Ù æÕmTgû=»À2^å£;×X1—öåivo;}E§FÑ…=“q6Æ×«:V=E\nSÕ´2ÕHp7p³Aty5,{µØ-ÛÆ.€'Ÿßê˅DÖ~Ð\HGützé5›ØðÄK!r\صx!%L?øóUPÿmÝãK®ÝôíË7¤üàê¹ã¯Û’ç¿°:Û[N]®èWuwi\9÷/]¸¶!K-˜µL…_®vŠà»$8¤à¥H›Šàþº“–¶ª(‘¾ém…fFFúN-j4«@*p>ÕU%­ÌÞå"Д•ž:Ø‘ÜÂe¿ªPwë.oÊW/Z75×czý[±uÿi7mù¯%Y]+C$E Ú>wÞhgž}þýg¯ÔhVËŠ´¿}ņ½ûžA”>fñLóŸëfòŠñŠûù Ö4Q}€fíÍ)à‘v,­–HQE ÀÕS ðL ªàþ®3WÊ«¤_ÀE0/‚vadö©CRö¢™Ñ᱑»§X4ê¡3%cr*ÿ‰~2Ì3“3 (šÌÀg` ö )YKÒvi©m¬ 4ÞÃÓàá €Õ¡Àø»ïÑH?6>|ˆxyy81¥{ôÞ©uŒ¢d¤ä @\o@ÊñÚÅš(êGëÁt¹zš,?•‚õdU½¶]©Ò°`<‹#Yèd= ‘Çüù rDr8n5R·‚¨hŸžpGõ(~©yž•¢¡æT]VzÃï (σÉ̉—¬Â;í «q+U·ÂÛ¤Q ~’C#‘uVX ¼²<ü †’(Šçõ¿K-)d×XAµÇÞS OüéõÕ4j¾tÈõ¦0•[î­æ„ãÊõW¥h¢mw•ê("ƒßEàÂiK"[L¡Li•iý$½ éa·(í.<’û„™>|@ê(Y¿'Ÿ²Øw—¬•&+¦£5ü›[*uÖ?»ý‘¦PýÙª²fã^ÅÍŒÚÙj¾éJ¦×Ð?DÞéh5‰ø·Ÿ¾"!HÎ\-jêzî±&ë¶l*4R#¡p•»THɼ¬?$­¯|xÿ‰×o~÷Y+q8Â>7*ãÍ­£Ÿ!1õDßóä3Ìóå‹×‘C5)oò8Ââ!O™×œ0Û$å³Vj‚‚œ~ÉÜ?ù›Ø&öR H J£§;™ Äðʱ€ï^$÷ýruÀhFˆX)9£ØÁh€Þ5`À÷Œ ‹21Œl—p9Ó²$x! Ñœ«X3òIœ™S™œ—Ú&u%ås¶’íC~O)5€0韌cÞì™ÕZ¯äݬqP*Òeư§³w¨á*Y½Ó{Ãè£;¥sM—Bñl¹;“è Ùå©$G—˨ÒѲß]Ž'u¶B±¹¬S/èÌ Ö~ˆ¢µ@æq;u·h¤SµCíTWÐ¥=al ùÙóÖú šì·-Ä=ý5DQo§ïý§%3¯>a™Tòæ^Ë­o[¾·ú=IºEëøí+æáî•£ÞܸëàúoY¶×\ªÙ‘èggŠKǼH»žhX¶uïSï:k’^<’´R0›¾Á”­xýξõa¦ºýéÔ]*Ö¸.ÊqDj»ôÏ;Ü©1R¼ø¾FË|ôE¤ûîb9Žà™göYÓ@-õpˆZøÇWo ¶‰´ÀbçŒÜ?ý›5Èæ¥je£¹ h–u9r8üÌoºêo;g6íÛ¼û©[÷ÅŸù³¿YsD v˜< .9"— (|äÐ "gL:é¡‘;¦‘Âäò99äÎm¸—)àžŒ>ª”Oí~…Sè/zjµ¯òõU~‡æâ»#à>þ\¬ÓÅĨ ª jÞHÆ 7ŠgŠÙGfZð’èu¨i à§ÌXi?»ÆÒàÃaü;¬$KVjÕ7°îUçsÞýZD©ZÛ† [ãÚÊ\k$¢M]S0Mú¾BŸw¬¢t±Ò–5ª.ñ}j‡ú¸°j(mÈÒT, áׯd„ø^g¯ÿ'…©‘”Óè|¤Š\EÉ¿wņ`àÒõ•01ª¸l‘—ç©1¬ªm#ú]þ—ÛåïÁ O|áÂuÚ–º\=º¿±"G-š© Ø%×nžÛyðÁƒ¿ãÌ••ÂãK$Ï!y1Œù·ß¾?¿ï[—íe’Çö?‹ (—ÐL1v«~ƒ3à…ˆ„ý¢±ã»Ï\ñ_ÙV“ª¢D¨%=p/ vJø ¡`‹ÉF’ül5’cÐ!µ¤ðØ$ýSé¹€§\x©ùLƒyÊ [$µÁDÅgÁýˬI¬Hà2p LŽ?þšqIÿ·óñ§¿wÅúÌ) ç*fHOÚÂwæaZ>†ý£CϺT èß&æ”,úíÁ}û³{€ýgÚAÛ@¼R7‡€.{ÃfH·,íAÑ‹UG97ÚÁ¬Da£Ngic‚*¼Ÿ´…'24c¸1Ÿ[ ä9D±¬³¡$J’{ or×­ýª&’Hñ5ˆmÅ»ªºÇE¤J£ˆÞ5„dY0œ­’Ò5‰A˅݂΃&RY¾(…Ω±ÇÀ>ˆ±=Õ3–âgö#çd¥©~‘©ëÓ[À  WJeHË€³tjÖÝù¬š?Gýb «9ž>3hó·ôÚÍÕþ kÿ.ú¾‹’w©Ñ¿wåÜ®'Aáß¾§ž³á.ïl—Ïln$‹¯Ù„®ø¸k7°Ì¿¬™„jà~ÆÊás3¡½#æ$½ƒv4ÁM~ôNòÇwåð­ìƒzJ{Úì‚%FGŽ$ñ…¿›cªu;˜S”w8¯n0Žw{ «{üu›sá3Ï=OØ,£µ¤îçïý?_ Ä4idÄöÔZVò™°ƒ'áÑýêÎGÀÁȹڽ€†ï}Š;ƪçô›¶$lܯîÚö«;·]öçW„ëÐöwÍÇÊèÐOœ}ËÖï^¹áì[·nØyÀå¾NrñRóAy“&Æý¯C}È®&µD<\¢›Nx:[¤š¡3$¿*ËÝ4³‡Kâ¶“hà/@gÝúð›N]¡'TÊ+›½ðÞíëw`¹NOK2Õâ\“Sxx ™ÿ[÷"&!‡Fw²SÜnó~xõÜQ‹g‹tC®ƒì:.és*¦-N¿ŸK¿{í¡˜¢«Ò×ûŠ“oØÂ3QA—qu>x÷Y«$Ö˜¦?ʧAx×±áWàÅæÜC¡„„Içq×næÖþ½ÔéàÓσžHЩïZñh;õÌógܼõè%³éb …6Úû¥È†kÝ ô;ØÚ xmM–]mNt|Õ‡ˆà0F(«¡%+îu¦ŠÝ­k0’ ô¸Dà>Æ‹ºõÖ,cÀW™kK—¡ª V¿UM•kð¿*PWK'ñ<~ ½ŠÑ4^7µçžUÅ4%¬ÈK wçÜö°)L ælâ.>by•ï=§¡áÏ]ÍRô¹óÖv¹ýäÔª[lu©à${jÄvlÕ ¢¤*©mH‹s) •QG/žþÖÂ5'öËü/›ÐŒ¡æ¿rѺ¼cp2Fåë)cn_¾7AHÒó©àŠ\ýän9YÞö¼äyÎìuØò£µ£ÚráO]!š QB%˺(rÂÀŒÐ­ˆ±)ŒÜ'7> Ö‡m£^Ê=³ÔqÇì'$»«Ã|TÝk£ÉJâ%\Ê_×<¾ló¾÷*ÖZ:sÔ¸ƒãÙߤä©T§g¨s˜Î2(ÙÔéTrßY„(¬.édO@IgaoR÷2>ëâ<{ Î^3 lðóxAyþ´áÁ´_ªšÜèå‹›mL'©ƒã5ø0ZVÓ½bN¾k4 Êî2ò-0ûnÓ™µõÇ­Ö~Æ´-PŠÏ{¤•dŠ¢q…¹.hA _è‹>m  5¨T·/·]Ù¡2þÅ"v•t¦ý‚DÛi.Ëï×p7¦41ÏsÕ8Váµê:w9Hîe{‚ŽX=¬DRÙ¤šÕG‹v¡)Æý޳F=–ÃùþUsö÷/¹[ßñø3ü‡wæ7k¸i~(xíñ³j¥:$ÿE~š þÈÜßtòòꑟSïWf”1 uн#&S5Õ$ …Mdªµo1m¤QÃ7¦¤Ñ¢6~èÜÕ§ß´5Bn‚îÎßU$¨€ËaœUB9Öè]$Š;ç¶G¼vûcO¿|ÉìHxG¯=8Ìo)d½ô(• &;'à@SqC@L¿«4\ i_ˆp_»íH¸’Á@ä®ÞÈ£=ªp#€l_}<†ùÿ§Pü!3Ž3gÚc@uŠïÁnÆd5ÒŸ:Ã}®j ?fiø òiöãIæa•hU)иíSÓ(‚|ñœB7 Ö§¡ª#=0fzÿ†m'$rë$5 à>¹lbˆ;ý×ps%?"ùX8Öq¤H=JÄ7ÍP4iWÝYÍÐÍKa’ȼ2ÆYÒ©Õì¬BSE[ÅmQϬ8Z= ¼¤#=DϪóëà»ÒîUü­hËËB©'ôE*Só“&¨† 9ûlWU±ÖL{Æ[àè~©ùÇ NT­2+ ]èWÚ~¥2œÛçÎ_«9à|áDB·‡c9õ¦­_¿d]ȇøõéQVwOߺlد’OÞ}ªN‘¡Å±9m9kX~¦Þú¼{¶×™êj¼I êAkÊ3ŠÏ>˜Ç¤nI¨Ù~bE€ÀÎþÔRc Tµ™^uÜLÖ¿«ÿ¶3æð~Î< T¦çÞѰ;¡`òZšŸ-6qeþv£6›¡—/™~ùä¯×´Eñ¤å‘ÑŒ½…$xëìžæïzüîå ØAvpg@§¡ÅÕ:^€~çîÐGc"{ G £W2îxîÛ¯EU,êW²ª……mOQ¤;–?š˜h÷¬z4°þÅ Öæª0'`±ó€é`´8Žä^øÉ=íòc½õçJâ1Ýä_JÆË áö`<‘‘ƥϲÀOIÁë XÉ÷¯B-¼;½Î_”Îη³&‡  —Äzw·¬öP× ¸FøR³˜#°hº£ýŒ ?Ÿ&鲂t®O^àSÀ>T³Mi¬šã¿†;p®Î&Rÿ#¯…áÒPô¸k6ù~Ê*П^)r—„ΆÇðË;ºý4,|á‹êS3I½q¬Sx¢AŽê»/\¸vS6…O–; T Äz5Ý%<®Ø´ÓµkÖʱeؤá™à1uŠF ÈM‰ÍàãzåÒ™ôG°:éú†ww,ß‹_¢&1hÕ`Zsâ{(þ y^é€`ÿ¾þ‰ê+/½õ—¼â¸YˆôÕäТñ¸F„ ŽœÎCÿ¦½JÃÐ4†Ã\Õ(¦_ßµ Xg€tB2øîZùèQ‹¦ÇDÊÔ0¬Áw£Ã%Àô l¥'§2,5—ÄØ&%ô Å·«†K8•6¸ŸO2j»6Œ2<)éÀáª1‡“†K…t šP/¾Ök‚9ÖKc2c“†* 1x™†TC¯¾ÄzÃFï¢Ù«¾Ç8@Gž’ÃÎæ 4®=ø>ð3%ÒäPë_}(Ò÷&t½FBEtI)Íà;‡è´wŠpf¤õš‹­föµ®ùæ1‚¾zZO0ìdç^ì+úXÆ3¿°«}5ÇQS$*^Y¼:€j"©ÍÏ‹.B^¸ RQÞFñ^0­ñïÅJ1½WOk-dœ-ÿȱÎðÉo^¾!ƒ‚¢Œ•ëžšLÞºÕˆw%&W_MYbÔfðÓÆ”b8¿óñgÆŽïåZ\µÜ÷飄 ;?Á‚ì˜|acRU§=øpgØà«Pƒí0ïC ï &h„䥽iWó¨J,š¼]¼oC°0Åg³jÒÌéÊÞeCaŸBÅÐ~ç™+Á…Ô@ž÷“sOŒ³Ú6ÄQWÞD0‡IWK‰¬*ñ’6à£&0±IÁ… 1hÛ?ݽô¤d@<»ùIô\ þfš+Lg’Ö«gi¬øÉ$Ï%ôж]!¸|¼„èP7ƒ¶vád>|äi”ïÂJpÈ(3èÜÔ¶E!ÌvÇÇ ¡ú•uþe¢| ý.Ï òìÆq’«à`&“”΢†üÕ.íkjsr¡tÕ:ÓxŒâk*W á¡ãz ^–2#މи¢¾¢a½Ì;^øƒè­³dQKNt¡W:+rÌÆ#I­çQµâ…éÔâ@ÕdÖ»Äô^=¥ÁQ*XswÛœ*øÖÇŒ¬Á2•¿½œ³~0ªz{-0™××|†-¨f‰jÖ…³ÑTÑdC ð–U¨×0<åM§,?zñln!"?÷\ã—ëjɪ‹Ãn‚å³)Dâ‘ò¸ªÚö3 ª TƒàôÞ]ÛêÝ@¸1,QO[Ó\¹1l¥EëÐ0‰ë.˜Dk49]ª}lN€Qp{Æ=ÜðÖ$™¯:qÙÖ=…æø|ñ¾u*Ó÷Ç•tœ€Ô”@’°©ßxò²ì€ìظh§±j÷ÔãEWɘ#åPÿKcŠdêªuTP=¢Ê§cpO¦qÌhÂidsFΆoqf±žJƒ»4Ü_8É[°ºpmåëÓ0ú…xæD-eß>­%§ôžÕÞ¦pô3¸‰±6·€ ì®ôBÀë)~HŒe¼vRÎæ°::@Ú˜0 ­°Jìxñuk±Ð-Eˆð}ÊÐ4fžA„'tðP¢oò;º«ä±yà?™^8rU:aoª6WDã.œ4´é:×ÖÎβ³”Ö(¬Üý_óþ>ƒGI´­ а"9*½Q3¾¥ôPŸè­}qUÁÞK¬ªJ»ÅVÔN.P-Ü‹õŠÉ¬c5›’_»2òŒ™K¦ùÅ Ð5y͆áªpìÓ_| VÓøù\®y°) ƒ³5®PìsèÿN¶C¿ŸP3v÷€{ñKjq«1p¤ÆHn‘hJ¨˜ŒŽýéóÖþâÎmøšJ¯“×8=†ÛN7ê¼»·Uþꇿ3»4ZÓ+ÿÚö. –À{û_š"uá$qѰ¥þ§ã—±¼ñwÅ_w4Ÿ#E¡v#‘!#°ëß”~ʨ3Ä‚„Bôvƒà.*!¬Qf p‘Ó8öí_Múƒ¹¾gþôÐcRíé?zñL䀔ÀwJ:Aí„2Îî$†F“sOæò¡?e:c¸ê˜\B 934èÉaF"ò§“%FŠ‹h®˜/|ÓiCƒË €DJ›¯qŸÂ*¨y%m–´S¤¼hàEOÆàe4m(ùïƒï†ôAÈ)yÔ-$Ï"â<Â;?À¸cd†27:ˆŸÂ{'ŧ¿3§á- `MÀ 2ÊÓ]\@0ÿ÷ô´É]3ÔÄ’Äæ˜f5F5Œ1E¨’rÍÛgLéõʹëRTƒÌˆŠóâ§÷ù5S¤¯Íý-x—mt~\ÇË£T:DýA v›¶²¸ôN]ºÔ¿Êìu+a[ìöö½½gY¯ª1”½‡Õ ¼Žq¯î[O_ŸÏjœŸš|ÞõZàþ '-oÒÜ7jWT.´Æù¹C"7‘•ƒ‰Zr`{¹Š»ëÔ):Î ?5ÌØ ¬w‘al4Ú±yy¼çœÕ¹Q,ö°úó>˜%ièKg‚q]¼”wœ¹BŸrÒ–²›Ž«Ö߯>q™‘ÓkC/ÇÓnÜR§½{Õ£o:e˜ŸF X ¸‡¨™I0¥Ù~è”ø0-ˆ®´Qf– § ²EmÊâîYrvÚ¤<4¦—UMbE€Å@|œF0=Èã±½V”1ܘþœÍ°¬"Gñ9z¨‡I(Ã!TOêýSé¯Ó´3,í*Åó¹CÉú± ¡Ññuï“Ã㬬—È®–‚a@<öòºÑæ*c¤Ô¨qÊ€xêïjÙÔÆE\âÒˆN À5Ç㩊ð²4°Ž)†+‡Kªvéñ#ÏÕ‘À#ß‚cxhOÐ1 K\ƒ„RFN5V¢‡®tV/}WñÊÁÂ)a×Áu?Fe{*ÞV¬ç¬ –º!„û\ÐŒl€Œ;®ME½Ð)aUà ÍèŒÆè©E*Š5ïJÅYÅê‡)Š›kÑ•—uxÃŽí5þÃÆüd+9óš—}調ۖzÕü» ¨VD Çlï_×>Ñ…&FB'iX¯“çéJŘ­F•ijEÊ?ÿ¾Ù®d±É+S‰°“òªãg£ˆåOÅßD.½vÓ àÒé¼Ù9íÍ'/«ÁpnžÝó•KÖÇ*†7ÓpTýåC· 60Ø›G]Q.ÙÛ|âÛÞJÈ|ßѧŸ}>V7ícú·Þ‡¶aÕ?¯yüî•åÙ %–Ã%÷íœOÁ>§zåñ#à;üÇpåi£¨üéÜc÷æ6„M‘Ïì.ÛŽøåkfezÃ)Ë?ñ«5qs‹–µûÀÉp’«Ž¨’14ôúO§Y2“’ùSç÷ÊÚÔY3ÜÐ9”¶Š°Dår–ï5ɵc(Ÿq"_ŸÃJÝÈÎ3RôO§K)}A|Ý0–ˆð9mVB£7oTšÉyU*ޤ×bMÚhéÙ,ÊØü׺ ‡8=©12 { ž´ì¤t‡œ$_Îêñ”·¦é¨Æé>›pdõÕc[IÚ}8Æâû#Ž n5p¬‹ƒ‡abé‚j|`Y Ï ›5õkQrÖø½}´€ª€eòÞ.óE²J ë&S­šÕòläN—R¤ ½æ0ƈÖ<«~VÇ0'B´Tµ#/3ùæeëû𓔢ËèùÀ¯Lù{©X%¡#Þuæ ©öºÞ|öüµŒITôÂWïÓæ5çá½ÁºNwˆê2„ilãz$d__rœ†ÚŽÝ^P)ÚBpÿ–oÝÿ½+×G\BýeM,ojÔ§¯:~Ypv¾Qit§Áâú4žzöù®ÛÌkÿæS—>)÷“©œÎÿÏ¿—!}ØêgˆºåHH@Ð9Hèù¿3 þSP+HÜ.èùæÓVxúùÿ“[Gÿü‘_<²ê¥™jÔ΄©_¶t„ï©Ó¸gØp¶aýpß6 h椰H4Ö~ááv(ãó[@m„úÚh ^ù•´Zp¡ê5m=§úЕƷip5êQ@üY^ˆŸBÅŠ3ÅHñÄ ÊÊǰ®Æã÷L>íÿôý±õJ1e+qÇеëÁ÷ÿ$‰p£àµ7‹6õAä$R ñhV±^K-OP°³= ’‚}Xò*ªshiñ ¤ éÆD©°¦½yIüÐ…!+b¸+м5 ZãxaçmêHQ”"K³à?ôÙ«¥öùV,VÎÒno'PX)‘†òèP´Ã4„÷QRØ:œO#—Oº~K°¸Û¤¨J6Üe^Ý—ò„"FLÅÝÕ­ íXû‰†ü?ð;õ„o4¾sX=b“v.ÐQáÄoûXxQƒ»Fi¨ùˆü·µÿ/›#6bwL¤'‚ (IË»‰cã°Ùl{Lsøþ/V?¸j]êÞöd^Õ„ñð¡ÿk—¬Ëî!%"y2ü­zxÿšm 쳄lÚýÔÖ=OElWT "ÂÇ€'6Žç÷?õkIhñDò É=¤²@CÃ{(³Íb@öpz¦üPx„¿Ù‘üŸä—øËƒMÞ×\ RsùQÇNƒÚ yJ€{h´N€ž5€e mêáî£~®ë‡ÙfsÈ®"ÿ,©üÔðøiúÅ}u¿Eµ«’V%pSHà{%ÜcZ*&È®†CZŒX8@áaž…S9ýj ~ š±n~HU8a:Y‚}¦ÐP€0˜0\ у1”„‹ç÷I6ãMæ§>Øz¡e6ß å`SИ´¬&hÅØ ù½³‚ÿn Mm:') ¥®Ñ}«çjá1J©ö…Ô5°>ÀZÕ¤Ô5Àã ~*ÔWâÞù+^+@«Yå쇗¯÷ê[ºB,pRGHšEÓÐÛ×…%u}ÌÂa€’¾ëLðóCyí ³ÉŸùš—Šˆ_Š]¸©¥Œò2Dú;ýæ­¿¹{Û¹·?’€ìñәʚ+½$Í2³ h~ËìÞd{HyÆH'åÙÃÀð{2³ŒÁÒ=/Á¬ÍFf4ÇÔ€~J Í‘ÆèeøÚ¥ëϺuë÷l?çÖ‡c øŽ3Vü÷qÌ/·À¦×1åtÛÓÖŠ¹í¬ßzÚŠcÿ°ñ·?âå—wn[tͦ¸¼ŽÃTw˜±u³¾H§Î‡ž˜tÉŠÆØüMiÈ2Sƒ\JèIþ÷ùó×BbŒP/<ÉX*OhXÇ!k ¾§×  éI¡‘L°çß»ý†é=·-Û›ð gÝ´å ¬ˆÿ'_çÉ’#QgµÞ­¾œóŒÖóµ<ÙÌün[Üg=ð"^;“kk CFe‹Å¢'Ò8îuaØÀ:ØÝ ž79D gâ1c|ž›•×ñéYùéÆûlâ²ôߎ¥ôÄæøÖöPaég®ÆúzŒL5Ÿ-àn¶#¦øeò½š€5xß—vXxÀ²–^ _- ~ù-|Ÿ¦9 · h¨‚Ö;âÑv'ê}÷°'ó«»„l÷:ÙÂJépþËî2Ÿÿüë¿âCÇ£Íg±(oÄ©\y³ÛÍ\ã´˜Å~2ã8Ò5]•h¶ÖTº¸…kž*'ºim55£ Á›š÷ \ŠýÕX”Âî.:Â`ºí³¢y˪u ¹×%e©Ð{¾@Œuê#E¾ãk^ÔKEÿôú »Gó‰ lâËpéûÁéë 4«³Á¨q>dŒo[•9ö¨É’ ®ÿ픫ώ³Íøê33“1¦L©Ã}±È¾ÖSíÐHÅÚNB Ëq¬RõüŠNHhË>Ž¥vóC)„Z žœ’.õDöÂt£rBi±r(ÈË ËŸXœ“`g…ó99Î~cœ(çÐMž²^mÞÀ¬ëGôi¼ çsŽÐŸq¤zŽqyà!ž>¸/Ü7­ÕÍVvÒZ­Ïµó1*m¼`rñ¬ *9JËá/¾Çö$)jáY—³§Š·¶p¡¼ò?÷œ ®ÀzV£ùwBø=È÷ÌãåcN& µ•|•ÕÃFñ4²òï¦âÈžÕºµ©T^&+"F‹³Eʃ«tоdz=ñßnZ<"ÔÔlÙKn<3ź˵ä©Ò—T»+ÀòÊÆæŽã–QŒõ…¢eaTy4æeÇiUˆdåý)<¥³ÉMB‰Ú= PõrxÒUãÈLýìÌÉ„`OgI³iÑ´h>åt[0KésEWÄq‹-b‘GžXÍ…«.ßr‚9”÷ñCƒ²ÁA¸”@0˜›PsÇgsùœæ£§Í î€ìûÕ„o¬_g_|ý:ó{¾×çWÀzc~ v¸°‘]àC0cl"—ÃpY |ÉEÅWgìr²ÊÈSl5‰³CMd[^Áa›×8¤(ùxF…¼im5õЦµ4ûÞpçk ÊÓå¤îôsú6²ô°4L›ATÒùLIµ úo†~tŠ+kÍ­ŒC_!+ý(Ö„„…Înz+/÷ ÚH´|c·/u¶S`µØ¼ë¶EóFjüŽ8ëA§Fÿ&^ôšú÷¹ü ;tâÙêúÍ‹4°SªûÍ5J6gä»T7¸ÃeÝüÙs?4æ—wE¦‰lcðÇhޝ®±?ÎÑkl×Ûtú×Jvº“¶´À(@ÈÈÆLN‹Æ›èâ;ßÔo¨¾ >Ȭ3Ýt ØùŸ!\¢©$¦ì_Œ€½§-›ÛåŒ8Ê’,_>q\ŒB \Ð<1û›]¶C?Žu~É‹§‹>ðÎpТ•Ñ4ñ,pºŽhË m`.EüŽÄuÀåÎq>}™Í¬ß?çüè³—1^$›Ë³)¹Àøú^²É{ˆïî÷¹#úCõ@Ýdå¢åa 4Ÿu§:[k©¨‚ÃÀ½½Z£™óÜ¿Nì‘’%;àûÔYfgbù›#ùz`‘*B• @wBVŒï›Ú5›|?äL|.`º+J“°4ΣAY{-ÊgŸü*,üV‡X'|üåßr¦7Ê$TÃÏØBHàu€«éͱ±ü“Àñ¢%ùþôbÐ8‹cðnZQ4ÙĽ/Âɦ›ë:t¥%[¹/ð3ýÆ‚Øw {Ï”rDÏa,ªuBÄ¿±KMaw6u”í-F¿3G´v£øËŽóJ„õ‹¬ Ö©Ñþƒ]¯rýš<á0þQî]û“ÃAfZ‰˜-ô(!8?U\+fçK KˆÚB¦:NgÀÍïŽv¶3N™LMžj|‹¡b²v ¥Hˆ²ŽÑ ‰–Κ¸)€ê‹7õ*ž  *íBië¼aûÚªÆ9…çàu˜àl“ׄ´˜‡À1Ð ¬‹¡Ò)€>È ž¦'ýãÁè±à5þlæûÑÙÉázVš×âó#æ„<ôbÀ=_6¶ÐÞ'–ÛWßoÌ÷,3 ¤ý9äL8ýæ÷ýè,Â)˜?q=Ÿ¿6ö‹¹æˆ5xye‡©·ÙOü®^І“yçKEë“Þ$c3—ºfÙ®ÓµÑ ¾EiFZƒ]Äìðï¬ÿ9möú™eí¢ÿÇ¡´ÁYNà;ÈN?VEëñ[ ݨ®©Zp¯Ukå®klŸÃÖ/ í¡Ké5Öô„n°Â.baþD}VÑ\6‚¸<>œû£bǼ †Œµ{©ï¾ÃaÉz™)V¯c"¸¹`†`t%WŽÈo¥åù~«œ±1øEÙ™V4.0òN}!å|`á{|RUȪ'«ƒÌ7‰1PžoaLý/0|—“©¡ò|éW´ÛÊ'1%!š_{I @ãReå­|0Aª$,‘ûPF|“0Tàí)bº”ÔuŒÙ‚ÿ°Î  ¯ =ët“îo€ú…x6ÙK"Ù&.@@a‚~EÖ„óΉ©ÁèÍ vø|x£lBõXâ°ðº.…Ý8¼çóS@ÿåçmpað'ºîp™7,uÂ÷ôsf>`ÝDns8óØ9Eíü|¤DôÙâm—U«Ç»+‰…ɪ^ž¯ÜÖåï8 ‡[Ì`‹ˆÜ­È‚ôk=²ììàd/þ¯´‘;_{£xÛšè•£¡»Å€r)xJ$xÊ’\=*Á3Mƒ…ÊA8îr;ê³³ — q]úÑùš~¹¯ø‚Qµß\Šém°+“Ü,·`XƒNzdB±ËïÔùò ­ ŒoLí™–ô+{æ§ÓÅ6¾õ˜—>S/$Y­›”-éTF_²zÆ`sjÚËö°ú´” >Ôþ‹×µ1|Õ ÚO“} zfÖ“;í¡òÆéPí8ΧçƒÛÞfc¨m‡g'h:ul»éÔÒFc­šˆÉá;OŽ&x^Äô8z©¬@²¯•æLBK)uƒ÷ •&á"Ì:v3”7?î9 >|í ÓDÜ¢0 Ÿ•àšCCržnž4O1e`ºð}y±üë¥óY ÿY{'&”ãóæá‘.d‘„~Ôc@ü.¹¡|žÈò›ZsH- ìÊ6•&î¡e¸KCÊy‡ó], žEñ»±ÙºÛYÅzêgv,2£È÷9¦¨$ôã–ŽÊË·È7Áßü[ÍCë\+wÒÎK¬c›¥¡ÂÍÞòö*Ôîžyœ¬"¯¥îd¥—©µ»ËÉt“µAµQH,í¨WŒn¦tjþù*äÕÑ*p÷ C]ž,DŠÔ>_•1G™¤V Ì·x¶ø½> ¯]Ä"G†ã ‚¨¨ñ¾™j‡êÔ ­oÆT¾Üë©t!Êç¶Q|—a·ƒè•G›°- ¾“ Í&µ1Æ8–ÀfBÂÄAúÃá8Ü, Ã4;¨v× èP ãl#gÂÙ Ù#жbWʼnö‘å]õAt Ê7‡nyykøv”Œ³"q|-tù÷?µÉ²~²"ëàulž~Ïëð¨Pǰ](çLž Žsòò?ºÅ÷1(çJG.ˆ·äëKãÄá×$[ ÄsIØŸ¤|WdÜ·ØÝþ|Ýâk,¯ &zg*£ùη‚§ç03UæÎï>FE ¡ ð ² ß¸ÈS®.jÛûc¢RÊ%†Ï¾¼G €Æe`‚žYYœœ¬æ¡ë£û¥nÓcç-ï9OŸŸÎ[âd_Y¿—òþ€gÉÝç·à{•’äÙ'ôqšÁ·,Çϰ¬¼pÊÏ ]³óÕ*ðøWsfˆ‚Ãûo­z0;ú^øÿ'ôKPÞ>«tM°^IùuIB‡=-›&;Yx¾ä4:¡KŸŠ¾öÈÑÔŒ§8»Ì,~µŒìèÇ ¿,iÛŠ­ò$Dñ—º1D@3úÖ8YƦg´uä.4É}_f[ÇŒ•e¼Bˆ{2–±³Ó M}•¢$]i˜;ž,r^—Ý({ÿ(·imïCª²)Ñp&3Û5õÎÁ‘Ϫ{ vü ü,Í«ÏíBÁ¦¿Bx|µÀwz\·ú˜Z?°Ž\« ”»ÃŽZxÈS¬q0ª$E'füŽ“• JÑ`Th ¶ h,‘„™¡þC‚÷iKµ¯bà˜ÙDØ ³‡R4IÂjù½Hb—Xw «}AP¨/ þ  wí&)I±×:o³ž2øªÜùþŒµ}Obw·ª µÖÕ4ëâªz™9’™±VÇçM£³, d÷ýø9¬âôçû¤Î¢•¼)9IÚlögåu‘ ./E¢ý'P߸ª'^ BÄÕ-lQ:eVLštåkc_+•‘Nà¢I±x¾»L‹ž˜Þf2@ùØëHäÇ«ü;ä{Šg³Ï*²K(jdšT)‚·¯pýY|ŠÜ²2—5ÿàÿŠB<гMËdXD¿fT,€±êÆšñ½‰ûæXšç0À嵞Èeä{ú6Oô> ¿„àwâÓ¹ÒdJ½Áß…uVÉú.ÒiÔ6™»®uÖ±aÔê?-`ï+ø—èù)¾í‹”ÎÓ‡÷<}Ì4+¶S³b„øˆ]X$³”207’Ëè>uüؤRO‘ï÷6(ìs'û@ë)lL5|—_2 ´IÑ[hÌ…£ ¬ƒ~ð-]Ï §ÝÔîÓã+nNµëQÈ"ŠDã…ŽMHä.”L—æÆ9DöClø–›•‹»ˆeøn¬Aæ Þ뜈†ƒË<±ãß¼Õ9 ãüúþÂwžëiÞ.øVÙùþŸŸó³ÖE¥"̰Ýòž¬°7»óöP4Öûcô@•ÐM OѤÄZÛŠÆ3~ßC½±Iº¦F6vC¬s.%’Ë»6²Æë÷ýe| `(<‘ûng­¡}d\Q„§a5Y˜?ƒÍ.~ÏÿæožIÓ;Ï’[“d1Xx“«W³Ä­{ˆ±ÙêÝæizG‰\+ú¨‹˜Œ¯àÚÐǦŽ}ÁšÉ«-^Ÿµ»‹|:Îq1ÆI”db­-#ÄO½RNÑ)¦îtF¢ó«ÎïdBþ"ûUÙ§˜©.•áÅ›nR"@Ïmšm¨|øº8`s2]ûHîô @ý£øÁzªw©!}Ê ·xÄ¿( [ ÁnCe¿ŒÖÿ§ª6²gµ÷dvâcfMXãUú¥!1q˜Y§1Ô ÅR4ê#v|Çð»üœÒòøB”t¡›œõ>4žjãø:ƒÎÐYÇkAm^dÚìsBö9‡—ŠÏÉñ³f““ãä0úYùqYÁô½Ã›3;P@ÙäŠÂÊ£YðÁ½Ÿ€éܬ楪¸.æÃ$®7~×L\“ç@Èa«Ò¼{¿eØ^“ï»brŒø]išÉVˆD|“=k⮓ü†Q ¬Ÿ>jà¾Êá‹ìš`ËñŸûd~UÎ3!¼™0ÇpLJ/%rGBrUCÒÓ”@ÞÒ‰]+(Øñoµ¼¨` ÞLﱂþž›jýˆ/ž/¿/6öáÓlb‡óòäe[f ¹Š®‰ÄñõïxŽ]³ýVl µm‚‚Ñö°ïY.}C–â˜#•W±Gþ¹¡?¾o€ÓºªI!3†ŸÎ“Š)ÇTd§Ð ×‰Ö³ 0=;뱉Ü{B^‚ Hvv:•(üвã#Qü¹“¥/ ˆ‡µÜôüçXÏžb`È]ånÊØ‰¼bÖà ƒrÍù·Ëj ;_ë2Ò‚³o×_wûeËi5±^MCRêR.³±Ä§†½¢d|0‘¨à†ïÄÅq4ç˪,6ÊùAs²å±òy4§Å¯÷¶~ÄzÔKKvXkïû—Jâ—ò‡ü|Š”Ÿµªé­Ü÷N¥¥uŠ ßl…3³êP«Z:ø"ûrX½“ˆçP¹¡‰ñé}C¦â¦ m«vTÐË WCתv²‹vYã$Ê!Ä!Ëz¹}Ëá˜ä*ÈnÅ!1V%à·Pð“hq:õo*‹mîB"[߲ūÆqÓ lK&¾øfª‹á¬®q°ÄމVߌ g?jCùåíÉ®ó wþ24áøþ.µñ¶–o¥›èkA&MµR;u¸÷pýªóéëÌz•=Àð)iG¹·Dc öhP²˜=ÆÔ­Ì®fïøƒì[Ô”øýÏã8J8‡„í´ž5ù€ºÈCJ»s§;l·4Í’Ç!a`Ø›^GÖ±¡Ô£ŸCÿg¿öNÊq¿î9 »½”­’hØžGA+ñÝÿj‚1·|pc7çc!4„{=°Ê@0Ñ=XOôÍ뀶 þ[¯GcñçÌ03o}ñò'Ÿ¾ˆEøÇŸ¬s–3çäóOÔÿÀ+ò¬ß÷Æ™§p’Íåsÿ?&q¾ëlµ6«×ç°#¬WÖ¥L’ÛƒéG’¹ƒ* ;Ä>$,‚²³þ40Å—zAµ}HM×Äï1•¨W~æÁ!39fÒ,kñ–Ò2;¹ ÖÃR–²3øŒþU$‚af QSOÐf«9a;ÝÖÛ¥“™%4‹>D<§J›F7²Žr“Öò5¦7Ý “¾}Ž.z·‘ •¢®Åë"!o˜‡ ´÷ÇxÝ„µoˆ~V_×}¥¸¼(ùæZ˦ÞIVøh×']nvZg§?%÷ÍAûšÎ9Ùñ¾lÝ~e«©0+é•Öå÷FZ@|'Ñ¿2þ˧„1+„»:ìûv•Äa$OêÉJa÷{¢c²úŸ³%À¸Gž5Ò}Yí2Í Ž[½NPÊÔÛnJü.±žCêÚJ·@§IágÌ‹~ô¬Um€i ‚t®¾P‘=Ï5Ú˜[õ'Bÿ"0*a’MVÝÞÚÐü‚5‡1@|¡ó§kG'ë¼ ›qêd^êã^j_gæY¬ë„â|¸*ðf²â‹òçAd_˜®õŬ“±úUÜ™ôì½=´vN½<°¢æÈÔ(€Ì½Ã/Óýuëú(Ä„ýÎð½Ê!)"t”æv`AÌAÀ,cÖ ÞIþטPÞF§*’â{|Çõ!JG÷2‹ß‡üäÿ.9Õ8¤ÁZ¼oYœS9¾[Gç9ùUXx¡F§91‡µÙ’®VÔÁš?0Ì”ëZ5 …®fk¥LZŸÜÒÒË@|Ì·ž»±}ù÷ÒÙ½‰o)þáÄ{b¬5EnÑ:;±Òw¼4ՕЇžÖ½È­KÊ_.Hž¬œ?¢`È@ ñ~p Óa{¦)!3@4²Ó†Ê·k}Ç<»U´¡³+FnŠVoå¶À!zÚ:Ý•/¥ïô(8¾¸jðÒð"ßZrTñÍËi@|ÎQÃeÖÚ¸SŒa&f¾ÂúR€h›«‡ËÿðaÍC@-à›(üsî<”u9îð¬øƒï\~ò‰;ˉî>ÝgeSôç½}ƒò<ÄSð…xYûM¾ŸChý˜Ÿ«šw'Yù ä¯:Š×á÷X>k«•añ!Ób*Ο¦3þÜÓx ÷ò§çÎT! Pi’iPôFÄÔ¨éÔ½ßLæ52€—ú÷”êª(iœ^(VA ¾ÛrÀýƒ‚Ã]2¡U˜Rj%sèxË])?s2jøÌä“ñ –¯©R±¾qL|Ç. „5¬ Áq,¡q-\b§°ÝŠå3üA¢ÖÅ)@Ÿ@¿Á]ëJxsŸxÚSÅKJ÷ñåÿÿªàÄ;â¡®<Á>Z?”®m÷³“ò×óîIÆŠFdò*Nêß…u†ìbG»'NŽ?ªuß 1À9JÜee€¤Å^Î;ñµ&0GT ¶by¾÷N.åO5ÿ0DFì=GyIò0ìŽÔ°_1kžâ¤bvØvP€FÓï-¢‹ÜÊGŪOŒÅàUÑhŸN×´°Â·,ÔÎCà\ÇÆtÉ *l-^…H¼@ˆy8(‹ÏSbockÿÕ[‹áðU @çÐ—Í Ù4ðÙW¥Í'8Þ.øÐZóhy¢”Q|¢u}+,¡¡¼øe¥îSXWAaÃ:²hyºTX#ûUÄÆ„…ìŒ éŠIÅâ1ËáñC»ó#ËÚiUú*ðßë/,¼Ì=>ÉUâ#÷Ñ' Á¢ëªHâë³#Dƒ“hlS4ŽmúÕ߃ƒE¢Ð°^´±äÐ`ð'ŽŒ…ÜKQç2WŽje‘-ªXš.<Ä 6jƒr ¶r豆Öa퀵g3_Î]´­œ@°cÝqk›VÇÝ:œyírT‹ÖFëÜzt™''´\ƒÅ3jýô5ëÌ<ƒ÷¹MÛ½Ëçoÿ µ1;3…¬#CêȘqŒÖSÏnºŸÈÝ‘òìñ)y$­d’=~V•ñ/¾‡ƒ5@s”üˆßU±ˆÍa›†]ßåðüÁ­öÝy´¾F¯q9ø`‰ÓØr‚þã€éÍØ#n,eÁ· ü°ç›j'Ú%Èeî[.E¾eÃýÐ#1ã€Ú4¸üNœcô;ÀúzÍNËùÀ:Oé3¡ãcqxNã]ÅáÂÛYûqVÌèþ ”@‡ý¿íœ{KõÆ`` ‘â8#IG4§¾Íqß9CPÙQ–$‡Ì» Ê“„±1’Z ìäy%d01==;`}G ¤Ù¡Þ<¾ˆŽC^SÐDJ†È¥È^‰ßrà@_püÉÙ±œ‚ã/Teå0'æŠì9<~Bu ¼pŸ+çóhÀ}“9ü ò?;ä—ü®Yá¿àÎb!?MOöOYS׬û¡`ih|µüÔ*IÃy¤Çz a»Ãǹ‡#“•ê)­èÒ´b0D óu©«!àˆYIÁ.cŒ¯=űFyåÆlqòݦ©¥Q¢@élÀýTÎ!‹ã|>œµ¬SÙü‡Q¡ òýt®Æˆÿ: oAI"[ÒœÀ×p¶KÉ¥¬/-;jsɧò †¶ôSÃ-¾%ã[€ßiNv?wç¯Á# f:ÊîyIܰÈå‹¶ýìÜÅWC¦ßkæ¦ú›7Óç:Ö×7g ú,’;b“«# ³ªØ¿í’Ø5”ƒ™^^öƒé|cÈ£2¸£Žl²½|{æ_VIFœ<Ê×=°Î(%‡lÀ¹+èÈM®AºU1Þ ;Ï+ÿŸ!d¼õö˜¦°£üEªMZ¶wYú&"„Ûü/€Ÿð@ŒªF¾ÅRE z3'`â!µÏÊap–U&šÊk€„óΗÝ[ŠóÖ Æ³³`z9óè²wwâä ‘u_ ¼<Ì}ô€.²óÓ-óÑmýh®Û¸G‘Êå?!xÇ,ÓŒõvK™w=4Îùœ%mbMË(RÏŸÏy³ò-Dß“ªAœ£h"–·P2ûˆ†R\ë¬ékUžM껼gEa&>µðL ƒ¨$Ê¡rÆA4Pð¥¦×õï«å;Å31vµàq(v@—Ûÿâ˜úÀüL:ÜDg@à<Õí²¾)uMùõ8¢"çK>_b]”RáXäÎS(¶¹(GŠ„r5½4í:÷~À²Èë0£bZ.÷-EÆŽ½ÿó¿v>ºÅwlà4®ŠõË@ß+ÕÖ¹YDQ4Åûƒã {^Í¢¨=•(ÂÝïÎ.¤Ýެc§s I¨î¥uhî(Äâ6ãôP ãÆ¶lý[kŸÑÕY¯àÞ£“±É}mæÙ/'?(CÌÞ,-›Ø©¹®QGe—1qjÞ ž=SsÙãJ¹™®8¨ž±ç±6}R¥¦IöÐw ŠYD &CÅdæP׺ßþãóà;¤tüÖ®aOñq3Ѫ>Á·NüÎ +½ßšûÚ7J¨±wˆx*‰ið†™ÙSˆ‘eͦ"Û¤Ê¦Ž™6ÃÇýM&ÕÞ'³:<˜¸[4(þ(ÈÕ=ðXGÐfb%¾/Å)Be3õ¥ ÃS8ÜÏòÊÑ2é— Ý{%î]Ê´„ÃŽÆ 4¿E„žcÛkc}¯:š£ìx74=u %úyQòÙåŽ5‡Õ·6g×ÂF=³šd'¡ÊZbvœ¬TÅüÇ›ö¥­ Æ&öŸUøÈ7 ‰GfTŒÁÆ/EœÝ)h=:/¾2PnÍ «¬ø÷nJú¿à±ÂÀXÚ\õ0”«ÿÀØ­ÉY‚¾1¤ ­u1T_Ö’¹öåWã(0Dõ7d‹ÄzLݺCÂóø‹E‘ Á‘=—y\ðÔ|9AÞ}˜Ó@áœ@÷EüæÜyYvîy…œÆ €þðù¡8œéËÂÏÀíð‹ÀÅÁtïTøàè¡æ;T7¨oMJ?gKK/’5ôŽIÇçf dwY𠾓YUc’,„êŽß²¸Ö>gFsŠ fÆÉØ&írBnÌf½Å;hlGBÄ@Ô#0èƒÈÝvV‚÷zJ$ôY­m£‹Uþ²7ØvlG"‹ÁÜŠ0 _"Og gA!hç8ŦV»ÇÏYU¨™È-!ªú+’ÝAFGýG&ûSY~-Í3¡*Ó/ÚJèÙ—2˜¾¶°cõËÓ:/h& eTˆñ;$ßµ’5FÖô‚)ß~ÍÎx ç«q­Vô± Ï…Ý+Öš3uY)³eµ©ÔÄŠ—Rcíãæý¾R fÀNØÎ—þ4(1$áF’JB3ÿ?§žý¨,|߃ñœ¤,aJÑÛ^áÐõÚ ¾kfDw`„ îÖkC7kÝ%€ÝíiY!&¸cT•‚„瀻!pv·¥MÞyytèoöèeDßÊúï~5àûÕ«·°/Ÿ^Æg?>à‡ó³™Ã8Êq øã,ÿ¬ÍüÌ9^«ÌÖãë÷'›ßOìòq ²¶ÐCÄã0\0íöµždø AùøUH³â ÀJ[˜NDOº•û¿¤m,‡7]¯Ì¤Z’1ç8r‹¹ %GK26~2LÏ6 /¾W0øNÅfÌú Ta)¿ÿæ• ødò*ñ»ZÜô“Ç(k¦¿)ç  …¾ˆ“Xÿ ñÈž¦dé!ŽÜ:›Ná/ÒäYØ$Éã0˜¢†ËÞ=ø”¶ÿ¶¥²Ëaß1{z?νúä0EUùî–Jñ­“)2]ó²Ñ7 Ý­Û£V·üoOùˆù|Û2h‘@ª_ª]h,Æ8EË—€¤Í6М€ •˜23_DâwÒD1F¤ u ÉŽQûhîTiÒ§œÁÀ€ï20¨ú±ÒtºQ~â/Ó§”Ç8ŽYL—[Ç‘XÏŠªWúô‹B»¬híÒ¯O²Ô¨s5‚ñ–3N5áú8¹;o‡ Ä4¦RÊ—?`zbð ý¬¢vœ\âñq0bgõëêò¢±>úgÅ9OÄÀú¾Þàï­C§^c8–ê³RüCW9d/“p5?:Ÿ­Ê”‡¨Y>Žb'³êŸu©Öà»Ò`Ì—(þ{“ª±L–Y"Ð|Ùitêáé";Z4e¥ŠÆA åQ¦éš‡ß?åÿ‹âà!åô!±Éc*5¡ü!KYÖ¬1„ü¨p£¹É²wèh™œ•[ù(ÏlÄ/}“‹¢°Ì¸økòO8¶xćLXvZ‘I­O±˜ðÚ êÏêyÙÆ`uJ!²Ãî;²®6Îú0~;=]OF?yÑsÛòè u¹Š”Š‚a^NøÅªûÔ ß^ú@üGŠÌ¼¬†C¥‘çâ ¸ƒéRíÎÜp @ ž˜}ú•îw§‚Qƒå›WCòb°‡{l ©TÂvd7ŠY¢K²“AyÇÒîŽC³ÕNÚ•b?“oì¬0ì†it$±JÈÚcùã.vlEõÒNÙã$R‚»$Û‹ºñˆéˆÙY©u‘ã†'<_Ž:;ž (ƒãøî´*çóÊ‚>çó íy?‰Öyú ^°ÕÓ\?¼Çß¿~bìϯŸJJ¢xéøœ xN•ÙôÝ~UÔȼ+@Æ$ØšæªÑ³ÑÁy~Y—™S­ñè5´+ÇsG@ÊÏЄ1_lLÅoXmkÚ\eÌÑ’‹É\úØE¾Ÿ *; ÀQÄÉIô„ñ¬†+Á;±<› À±p↬­€« ²°(­Î(˜¶šN#uë麌ó(Ç£˜ÕÍ…€æX‹øÎPý?ˆuî;êT3í:^~̃«8\¿^ÑUuñ qˆßRôÍïÇñŠâ9e&xgå/4= îqàÙɪ+÷H•°zöúºë•DmÅGúëª ]bvÊ @êt­p‘FšAÂ’dÏJ º1ÓTrÏÿ¢NÑTKò½'%¹;àMpWÊê2@®­utÕ~9ݘJ¬Øé#í›L¹w#Z•¥7ű1‘#q’t†~‰ ¾yè¾|7M<þÞW¯â¿õI@?›ðæëE‚à9Ì£±/×9ïæ„yAÖ9!/5‡¯ü‰üP°ž ›c×ÛÂyËoŒâãȳ³, ¤÷5‡—úQ$ÉŠ…Wc²ÿ|ª.Ë{ýfÌ!¾ªŸ8Ž÷ëF§ vöž†gp×<^V¾Õ÷KçYྀõ„5§”@¥¼µµ¥È#ìäÔU³¾S®Fs¸âÀ´—£í¾•Å6ù>qsxPžqšÇ?…¡ÏñTÁƒ{:ŠA®2VMŒTsÓE’ö2©¢‰ÅÏEp¥´px¨y¡^»ÇStm"]òýÎWÇ(ˆìWçZ¾¾«—òw:aÔ> ØY€¾Ùv’¨NCÝÚ5°±¤ÁB»£å»‡‘{ÄnoPôõ^6+)¬ñ-V8FØœïý›º8™q¤2 ØUwʪ<7NUù |w”þV Df‚5Êã¬’Þ ;;4¾WãLͬèA»n¸¡²[ú@‡^ b%/:õ‚»¢1ç€ ‚Ò,›)J<•ZIXm¾à8ëè€5~ößúè¶ð}žËiøçP^g^„(>+QùœÌ&Oß×ã»6ÆK й*økbdw ؉Üafx)Kû!¬¬·Ýj Ëà8q=×ÝãD²ï”AgÀ2*û›Ÿ!³*Ê«ç¼ïð…âI±"DSYV¾“hÒÍê×5ûŠ•òe&lß_uª’3'x§~&PónñŒ°N—• ´’PŽìŒbxTìü/‹ÃÄ4 >°^á2$–G\+.„ÎÓð ­ôF…;1W¸ïM±°Ç4‚zv°V(Ãñdùp_ÿ%{í¹³à„•L¦yËKàŒA² ¬;Ò‡v¯ °¢ó5[©aõÌÔð)×yT5”µé#V¸us#ÿj*ubójYÚ%íKÅáÛG©}œVÌ®)0€ö…2P„'#tSÂ×ÁÖ߆ÑT{=ÖŠ¢€kìÌLÐä=}Õz—Q ³-PÎ¥ÛwiMT,(OPÊ;TZf«Pñ)+ë°´vEsƒ1ëFH-†Y(†pNæ&=¾JâåX LÏÚIN 9ÆSe1‡ƒÎ)߉è=™'[ñ¾àþ‚ÞÆ¾ÀúÃØpcÁÉ··óμjod“°ïS³O›k ž ËÂÿó©ò±C×(¦F®õædká»UIý˜ßsn-¤1,·÷í»=ŽñHIcŒ\—Hîó ÇB»ñ áÑíÛ±üzBø˜Ü&û&ß³W£Þª²3t B¢".fÏ*¦ÎkÊärh§ ·øÒ2Yé6R)KV¹±HÕÂFB œ }§€ ­]¦(J¥p~ϯ„Eiõ‡qîx¸ó“Î’öÕ|×·J˜îASì ñþbUóœíW‰\jÞ‹Üçu0¯Wœ O[22Ù§Ž5ÕNPíñ›gWiÀh}R©7ç7ÆQÑ";3 ULßµ1äQãPòh¿Rׯd¥Ø‘u—´KÈ ¦Óï·©ö Û³†Ù$fÏ¡7ÅJ‚8v‡ª¢0se5e5H?ܺ*`Ä€­O»‘"«ä@‚Ax˜ & „B@S±N¡:¨GI 5é$K³Æšåþ`ZÞc¸Âðì‹Î8œC ëòÞzèå{_¿âœøÙ9OÁ@ç³ÿù:9~ÖùAà~ž¸6 íù)ñw¯1ñ9ä ½qoؽÃÅÉ’MØ'l>´Í_u±?‘»Ê”H +D,¾›kß™‚Ÿ•@–ÆךµÂ÷ù™u(¸Û¹ Q£–¤õ3¤ýQKY— $ù‘%x†ìãXÑ·ë Ȳ†ŠßOS·Jù_‹s’«÷kÅåm3$㺛WY!Z¹AW(°À=Èþ¿økVDJÀ"œf#Œ#;ÇšFöQs­ n¾ˆ­ªÝ-Åt'¦îQ>Æ‚{±Ëà¬^]ZŠòÎ] ÙHùzkÀN'BÛ¾Ÿ xVÅtÔ!T—¥jZŸM^Áwé°Vs:°1 ;‘{¨4Z–haÀ‡do¶ïAŒ¯E®üpy{îWÌfè]Þ¸±›Z]HCø™<¤˜µ¾ƒì«2LÑG‚tTÀˆÜWÌŽ\ŒSt²sXQWg5ÄWÓQ”GpªÇýàtîô'u›¿|çL‰°Ëª»xR%"í0);øµô($€5*¸ w|mln¨,†"?ÐËS@óõ‚ÆéÀú8&±ÅŸªe,hÜŠ¯l*;âo¾¼”ùÎ&Qñ€¦äx. õ;ŸÅÙq´œL Àåœ÷ó⟾xÿ«×qÞûâåû_ôO^4;Ùÿéׯ³Ÿ8sazà;›û¡×ëü¯_â³QÃOLtï•ãÑmÁÐ/’ûÞ|ú2þTò€ï¢<åö–Ö˜ƒ•ׂ¨Ííì-5ùeŽ´1˜°Ó§Œ¿g€¨?Á>>ùUÇøQáNÒ>ß@Z+&òÜÖ­âE®|§d †ÏxGËÄ`‡{de‚SuvK•‘”E²Ú³¬·LùqOÓ@ùUï׳R9CÕœ-Ø‚¥€§¬CzYª@äqG"¾Q±Çq`ĸÒñζ~Š{@®e9–z[Â+wXÌ£vé35úŽWo6FÙ3K‚¤¿ŸtOµPÌU…ƈ»«…J̬gD5µ„]3/ëTûQl;ïdÔ˜l;Tû¿þúÙ›i×56‹¿Sb"{ gâddNê|ÿȪ.Ò›T‡“YÃf•˜&Zg½œŒ Uü¥ÿE¦kC< Žf÷wd…¹ Âì‡B0¶®–•öEÉsæQ¿Ú²æ¨!ë•q6Ã`/ÎÖº[–-ʺl4$N¯/€þÎ<%€«½?g¯Ä uVpÔ¬o?Någ?‡?'ò\0=›ûœ'o€×á,ˆÿÒ•;™s¼Âúìpƒ2%@FñVÙs£ÓÚ8$*”'káùà>û”ÐÈϼµžÜ;õéÐn|º(þ M×Ïwꬾû§{ˆ# Th²’¢jˉ۠<9UîD‰ÜJ’ßâ‘ Ù—²XÀc*Y žšwêШœÉ Ê[Ñ@Ý…“-›V¦ß /v³.¦&0(¿5#³Æ6Ûñ{Vs¶Àú¥¨±§Âò…ì4‚ì…àe©Ù/ê\V] ä"½.ú›¡´è¤½ë»ñTâå:VD®ë‰OaõMH¹t =Áô½)pû‰Èù\¦rˆ3ç›û¦|¸¬1gé"$T2ÐÊËηÊÂLjø) ¶ü?\d=z6qΰ‚¬¦ŒÜÐ1u²VÕ£cϨaWʃÿ1ÎÙݧңÿËÖ_pÛyÙþ°>ÎíÿH'±Yl±dŠû2SÀ±C†e¡17ºÃ̉fJß—:±-°“ûuÞ¹Ö¯Öï”¶2F5j?:::’öžO=³fÍJÌ*lkɆV½}Í©zGà AnÒdÇ]<¤5£vZTŽžÁ#ñ·Tßš]$Œ]Ð$¼ï'9Éàx@™Zh»“ç—’€Ë׾ÄçŠá×'á·p=W¼=x…{Frî9|ÏùlñXߟ9F€òŠp–$Äçoê¿OBQІsÎȵgX§d}²]­$T'³ÄÝ‘¡ä²¯ñQ¯C|q} ôïº×ôœñà¾ÞÀ—úöF2dg MŸÊ–¡Š§Zr©T§%Ô´çC2*r>:ˆÔœš*Œ«©«:±kxl¨^ »$}φ{÷Ö¤3ò> È ýEd›Mêß¿ÿdý™EÄ箸t÷rU,Ì‹ô÷€{Šq$BÈh"‘„[·œ T~ aŒ[«xg¯öqë |0¦é#œ ¹¦¦9}ÌÔØzçUÎìTîK |¡ŒÀÖGÁ™“ßû4è'Á:&ÑxRfPU᳚¾U«)ÕÐîó Aµ^Oú‹ùe)°rõ„}—‚0 ¤¼Bñø¢,¸˜[E,ŽÓ ÁÅôÄÁë³`ç%Ð,~÷ÿ|ý/ÿÓ'ßùŸŸ:|þÿ€àœóûäk6áûƉà#÷»µŠþÆ…û”7òÒ;-Êv(D8 ðbJ±3´’Whäs7íjä™üêZšâ%×?ÁψòÛ}!÷@·ËZrÝ‘ÆÎ*¾Á”èqQÈÐÒ"xB/¥½¾íw®EN|@(Û©ÜMh®s1—{8¶zÞ…#G”̇´V,œŸ_®ïnž‘ôØÞùà빂,’½=XÐP¶Ó±£f§jÌu÷%i "wÔÚðOlKò!aí1dpèüJKdÁVLv[†òqt2bx÷–©_0Dp¾ùßï/qQcoÍÞÇP½M è‰.¾ÔÀÞÙ°öýs5PÆÀ < µ£?žýJ¹ýÆA‚‰$¸u¤2TîÜÉi¹ÀÐa#3Î5 wz$6è©Ù]³³$ðìø Ôr¥%óJƒaœ{Ð<Á[¿–l4cUžì,ÍÉF¸N‡Å9,Ç\SŽQš­O캢ÿXuÂÀ¸8© Ôb¶k(£ºCÏ€ 2p!ìðc‹€¦z¥'¹Z‘ÕÌ$RªÏs!f¬E÷Äe7W@gÑܪ|@öŸyûšÿõ7ïþæ~ášÿù×ïú¯Ÿ¹þ¡çn |§~ÿ̈äÁ÷•pnVî[/×$Ÿ1óĸUðÀJ‡_ÏßEá&šËú+/Ž^- íbùNmá*ÜJøÈoiiÊ€ kI&Z]“BÐã%Yÿï ¾vcY—˜¤wh&²×|S׿§Å:ý‘‹ï¤œŸïÞzMn‚r£$T¿p’*ßw®†*êƒí¿>|'3CÍ)ÍU¼æN.ôàÌgÁŒÎ3Toïå,2ÏšhµÚÃx&tìô„sOX’]Ò¥Û"§5n—6öÍÏ–³þg9ÉÊÊ;%îŠi¨¯›ŽúŸ¾ NÆ[_·¡îÜPš£xÙ\îÑ&£È‹jv1|qâªq¿~“^·ÕÐwØÂ‘è}Tι ãPíå ·Ö*”í@¼£n £ñhcp§£z]­HŒÜVjéÙAöæ„gðXŠr€Ugµ@<ªa—XæŠëŒQÈ C޵/b5>{WÙ²—ö1¹¥™a6Ùüäçt35&ŽWÍýGÎÊ@wu˜Î F]J_Ž‘O€³å¨²B¼y°{I_ ¼©‘åÖ`pœ¸q]$¯O<tuæ†ëœù%ê,:QÈûµlX¶3ßáŸîKR–õÚ®²Ë˜Ï ;¡\º¤a-åiJvvÄ싇‰ÁZW]ãH"h¸ÓJÕdNbQÙÇv˜ÿ䜅ª-SFFKNN@y…Ð)¯ h´E:_Ê[’.ÉÛï¹í+ï¹íË;?üÍÝÿÞ®~w×Ç¿ˆÏÅ·ýÓ‰O]äkòIÆoçÌËú£ùaFÞ>"ð•p5à8?oð® )46ëÄÓCλ€{ÊvíÉô®ÑAž^HÅ–2äL7*@¥ÎµL&Ö”ÃÕ°ž·Wl¾Z©§´æ9ƒìîHî}KŽx8møK‹õ»™rj…]. ÞÏ&ä D g‘ï,²çÃË’5…ÍsæJÙZË7ÜÞ¡eÚ š w¢öò˜Î¹“t˜V˜ðz£zü-ÝF¦ÓêPdiH$vœ•ݦÁ˜žS‡ì¾À ¹^1g‚ÛOÙë{+ÙÇ•ï“Ø°1àzÎBöS®=äÿ 62 l7J!¸/ !\@D"–êÈž—¼?w}•£ÅÀ÷‹öN ÙiøÌ7bwôUéÅ;˜š=p/”w©M„1ä>íR³3K  Ÿ«¾['Tœ»ó’d£WÆx L«>‚IädQY$ÇÄÑÍÔà…+‡HÐr(©ÉÒæ®ž—RÌ çK“H°‹“ ¯ä[~ æ„b\”Ð-Ûoú\~ï"XŒy1 žØùÑïì¹ûG{ïùéž»²ûÎìüÈ·¯»ý«)ê?ñ‡ñ{Ÿz‹/ÎY÷†Y°ç—„{Ù›üøÎésWø1º‡f/¤Å;­…”ðP7‚»-eZÍË.-Q$Ä11¢ iøï;4çÔq"”аàiYÐ$Ñv¡ds‘LÂæ&Ù¿yÝÝ^(q™§c~U‡ ö løGî©3S†‘*gøÈ0ÖTô¦¶À:¬—ÖXzŠ]‡,ROàw®sƒÒHŠEek>/‰Ý)áí°­f©Ö²(abB{1'Ú L“3 „#çÆr"0ótz¤±\F„î\hò£S}Œ«†ä—(á“[•Ü,Î¥Ðø+øúä÷}õº;¾¶ëÎïï¹ë'ûïýžûŸÞ{ÏÏöÞýã]ýÎu·íÚ÷ýÃñÇÿù²›Öo?ñÉË Ó ©ùæ ;ļ’DR¾s;IÆíG9æByžKh´v)'Ôü⬠åÕJ&Ú˜«»J¶TIZ³áꓳoooÄ”E^’ˆÇ7ؾzNbÿù Ë:´ô3ïtY]¾j£ÕåìcµorîçW—uÒù>rôcÍùU‚~!h>ýÕQ¿ãÉš‚l £œÂ¶õùE©í;Љ<¦SÈ¿kHe€uÁ}Áºüj¨&‡™Iôæ*Øh±+ô©s·YªØÄ¯O(-ñ³Ê‚e¢ÒÉ%K T'Fz‘¯l…?œûâd(»NÓ&@÷ïÍÙýÙ5©ñ'î´”ìáÍÍ› ¹f.ñêÄ»8ˆrqNa4@ÆW§ü±’€g'Þ WK“´ö l{~ïÉ×FMÀî!’Óó’±&Æ—x·ïmõû@y`Ýa%4ËLX_à k‚:³ΫÃJÈ`@y+ôžcÓÙaÝÇs„1²1ŽÉ@Ñ@°¸ÚYù$`º£Fº}Q³ãËÈhþÕsüzPϵÝëîÅÌ”&Åâû8·èòtÀš$žØóñìûÄÏ<ðëý÷'~”%üǾ»óޝmßß:õJ=¿%çü½œÞ3þØ]Yý‰O¾µªu`}K„;”†_É_ù Œ|®Œ„I×Çǽ­t5jÿ×?2nÃ:Óç°ãª°ÑÇY)áAv´ðZ7ó ×é;×䎄Üí¬ë]gÍ|× £ï×î¶‘à».x…ï#¡5|ÜJÆX+ãa;µô€Ï0çLâà;Í8·„4|´1$¥ÛÖDÒ\ÊÞË“71šy§Ö°äL¦ÁÀH‚Â}wGwUéU¬u-¹Eú†¼ èl?!k¿A èÀ¯,ȶ>.tµØ¼ÿf¿©ÈÞL,7 \ ´Z¾jynHükh㟲!iï“M°1˜?0ŒÊRfzåý‚ö1WX†‹ö‰¤½uäSã†?…í üò¢{“2¿ ÂIkÝ߬ZãÜhŸ²îݲ}„j0<•³lït$ÁZ¥æ.p ÍŸ"Ý ¨œ©aÔ¶ØZ—G>É û¨Ô¬ÖÕ8¶•oà{Q1OŽÄ…¥.›¦•ç2#Íu‰\ÙaØáš!Ù)`Á>¤É)Ø%µÉ·ÊáI|ß$1OäËÆЙ˜Ð X§l¸ï½ë‡ûîýÅõþæúŸ9pòÙëüíþûžÞw÷Owüû;ïøúö÷ýýõ÷?}Óüýy Ðîó'~Z†[ Ôü¼¾ª{oQü-`äóW³À‡¢IDxÿ> 6`GÒ5À=ÿþýnªKƒÁ irFßÁ]ÿ™CÍ"¸†û•aGs±ëß± Ñ&º×9AóAΜG<ˆ³/ìô‹(¯Xdg$Û!má-wNÏïcϰš)šæöîÄ8'ÏÜ­¿êª¦‹ÈÛG”'è…±fC‚òÁ–9=Ö—šÝ&éoɆND _ÖÑâr·ÛøÕþ­l[n˜J’l(ë…Go0þê¶.ë!6Ä0 W/©˜$Ùpë­+}ïTo¨öª|©ÝëTÔ¹rÉ©¥<\FÌËÎ G޹!k4X×)l~1ÌŒMTѶk€ÂöýE<¦¯Zž‡öQ%oâ’AñN²:¨úÆÔš›ÝgçÔÚ‰º¹ÂXdÐõÈÙŒÚac ß3…(²[¶;wŠy,ÈNäºëž üÇ“X¼ÓîKN‚FÛ®i“Ê< fFÁxW¿ˆj!µAö$PÞ0ãùJ^»àoN(š\¡`Ond|‡pßï/<øÌÁ“Ï|ø…C?Ÿ<øYäž»~vë{>øå=ÿ>˜ÎïåîÂË|gN {³ÊvÀˆœ”ÿùQž¾ëÞ¨JtjŠBÞXGE“ÜA§Ökµrçîët+‰Ë¸yc6í“β"žiK?|ÈkÂÙ‘m‘z<¼iüÈϠ͉â˜w›«ïVîÉ©u´Ïs-ñhÛ¶:ÙNÔh ³>A[àEÅŒH^VÀÅÉT„qeƒG~Ù»mUñ™’Y>á°¾³‚Ll•˜Ës¥Øéy6òÃ"^ÇÒ Ó˜¾rNC¤öF"D_½_ÛY80·IyÿñgUZß½.ɹ¨8Èîxm8CeÓÕçƒî\ÌÀ•ÿ:ŠdÚš«ú†<¹ùšš]²,‘+ŽS°×à°>ƒe»©y[P¶ÛSµ"°‡C¸'qEj{¨D饇ÌEkvÄ0¨€çE'QiI-•‘<ûj¢âÞçK>x>GsêøJ—ì0L+ÈŽ”™u8ܶµÙ¹S·I@ï‚‹<»&YH¶S‡b€-—F»Œqæ:è öɳÛ5ДOL”ŠW}]O̯¼ùs¼ùó Áý¼ÜÂýÃߨwÏ®àé=sèԋćž?xò™5¡köÞùÃÝM‹õó•7æÏýìø&7/ÁLGü$yIÊCÍËÂsJÖ;‹ˆ^ ¥¢øœíVÿÑ|ÒV¯yB.^'N*wÀ»1ïÖÁ÷ÜÈkëc…é¼PL¹,7‰ÈÊ»€Üò‚¾¯ˆÉK%^‰µ$”g9EËŒXkâ“ô…¹’ÍM 2²‘e¦A®X¿R¿K›,Ý /-ÀÁe(r¿ÞªxËuñZN»[Íø}¼ƒ–IÚLR}éñZÖÑû°½÷¼Zýâîw´Ü¾zi·ƒHôvÅnÇÔoö›ÒUëhkL)3Á@6/¹Í‚ïùŸp®a˜Ì\3ÊBµ'p’¹ÈÙŠI]øD4켓0«ÛÙ=d¨Ü—Ç@‚j0©Gß fOP­ðFOØDMâ²Êœ„š3>K ;°îTÐÜ<×KÂL[µ–mr棞϶T,ÍLàƒpô´Å ÓùÕÇœfà8ç)EÑÀîôN…¹’yjjpêߢÑ=ÂYØŸ_x(XÏHÄsVî»>ò=wý0à~ðä³ÙO¿4·øg<ø›}÷ü<è|ßù¡¯âoøÔ…ñ{ñó Žóݪ„_´þüÆéKþðï7Âàó—òY¤ßÌš(È{ތ澀i%;FøßONQï„Dã¬L9qŸæFÎÉ=>BR4`=Œ¼o*ôWû#Æï½D÷|z\ðÎP ‘Ýf({÷mŸ|'(qÈágl\Q-Y»ûl,ä[ëqÐ8Œ$Ùó™Û±&dï¨Ý?CÁçŠM×g3Ûȶ&üßõ‘½rôÝ%«–­JÚ¨t†ÝâÕ.&_cµ^RrJ{²#íà%cù:H¸sR÷ýH‹–飮2*ý®Ò9“e…ãoéš«ŒÞu${¿‘8X%Á$…¤µo‚[èìr\H$MʘڊTÄä×CÅS‚Ö [8r:ŒºÝ-K¼“|GlK7•©Öì ܉‘S†ÀÀP¤È3¦k:Ö¢>âº2—çè–êuº 5§.íTëРr£É+W“\[vLÀ!Ù“Ln]Õ#¤­“J5wšÓU¨8Ä€,î#=1=a´á¥}Ú§Is,£"¦kšS±ù8©—\ròN<‰¬úÜ Á·|>õòe9¿j -yÌûž”МyùÈÙWŽœ~ùðé—Ÿ~ñÐÉçR¿!Í=£Åš¯ßqÛ—O<þ{ï™ïOEŸ—õ²ó@)Pð½öðµy‹w gt›Á𽘙33²sëð3ѹwòoäR½^• è]®ä¤»?zvÃľñÃïéE‹ïNÄ3Q¤ºFÞÛ_:÷n0&Ñã½ÂÚ|C®¿Ùÿ½b@ ÁL¥½r›ÇUVÈ]`èË"±ÀÐ!‚”íä0€€ª‰-zšô÷›ó<˺½Ìt²#sÌEÞ:Û³··îã´l/ƒ_·pØZÛÅÖì5ok58oŒH[•2GÓG^º0«&>W";îNIzû a œ ½Îx*ó,k}O•o”ð`º p¥ÿ&ãØëtú†‰º†]Ë-U1 å-g·yâ©y¡YÀм´r[9Ý$ù&óeÎ\ùS®<¿ú¹?îúð×w}ä›ûîþÑ~uèä³Gμ4ñý•#g_(|O"þÁßxàéë?ñÓÝtºãk;ÞÿÅ£üŸBóùCò‡BñpÀ-¤ã»U¼Œ?zy566 8-䓸d“HNZå(\<Ä-‘ë}ßÇ>Õ)5¢òÃPp4W—ÅØ¡yEYþbtk8aöKg)¤eq%l±æLà63ò¥#±ÛÔîùž9GHÑ$ÿÉz ¤¿Å;Éââ#­Aµ©áAÂÇQÞúô·ÅʬS¾øJ®ÿ‘hä¥à¬«œqS’'×Ö•àËO ŸP,{=Ú€»†ïM<£á(ÃM39õ|Ï Ê¯'Ñ:!ÙÝÙ´óôJÅèBaéBmÊ£@ƒå„/-C‚µÇÃHÛ­Ôg #ÑÅyÚYÕçݳ&cÈOS;’\ À¨¬£ººdå`f÷øõë»D¥«à»Ž\™øÎõ^õÃÚË‹°Âé6 ‚í^:¾Ô¥ò}\Jhö§Wºß%>ªn¸¸©Ý¹ê ÅãÝš†>ø>1ÇBâ4PÝí¼\fhcrO'à s>íšZ‘ —þêX´ä<*×(˜Žä‘"=t ú¼$àa¦ª}$ÔìÉèþèÔ ™ì[%Ì ;Qì¨Ì¹>*TF+ÉÆîŽœìäu–l ;þìUš=zQgö$ìÊc¨ûPU»ø-'sd¹h çdÝ`Ÿ¼LÁNîh¡eÚ¿õ;,Ph³·4Ѻˆë)ØßKÍžs~ÁÀ÷/¬*>à~û×vô›ûïùñõ÷þòð©Tî/¦T?zöÕıóÁ÷ß9õòÀ÷Q¿˜8ðÀo>0ð}ï?Øý‘o]wÛWrÎGñÇñ%ñÐo -ƒJg"5ÐOQŸd^)@ÁAöHk´Ê)F~™ #UEƒs<ŒKÃs2,F‹›_uÑÄZ`§±nN°aéLH»Ó›¡gCPÅë<à ùÞ ØÆ·wŒœ‹Ÿ„„|<$¬„«ørJ»Ó²Â0²/i*'튶̷עc>ÂH!Kð^sª5Ž3ƒ¶Âí=ŠgÐbèCÈDç^»"&…Pnbï ¦­9…/Bà.æ”S~B4y¡5·§ÈÞ7H‡5éÓH\T‰¾M‚.ÙqÃÓÕÛFzç׿˜\ þ†ÄGX·}ÚL(%ß»³¼?êÜs²"•U‡CÉŽ¼ýM¢›yªc•Id^þ›Ýµ”XGÛΖ%È»ÉtêQËÌÅ1 Ú§PíIv¯µ¿(Ü•ñ²A˜àª½ù>^´• Ûž¼Ûù’hЊˆ!¬'å»…ˆÂ˜,Mfª…ÓéSQ>¹‹=µíý@ôúqê’Ø%1òì 0#V•ªø~ƒD#ê— 'p` 7BmˆCÅäW“Œëã—²ßò™·s’ïþð÷Oüäàƒ¿:ôÐ3Gξp?6ýwwãè¹W=ü‘Sßóe‡NþöÀý¿S¿çãßÙuûW7}êŸ?‹?ΟÇ'°¾¸xïL¨9Ç4×K˯4^Ÿá$š ñ*)¡¼ hæ µî²¶XØ9>†Ú}Tå³6Öq‡œYÎäC:Õ÷{Ù5O9Ï; 1ʈ$mœµlß ê•3“|we¶×¼Û?Éü6“Ûs5üÎ3³x‡“i²wÔîïά&ÜÃ‡á»ÆPîYåyFÇ͇ÈF¯7`’åì·M>†ijTUîAÕŸë;¬¸%Rú¶¼ŽþÍR¡J—Ÿx]>\Ú]oö?kB Æn3ÛX®$4£léžï½H»…l^v›Ê ªG ñýêǦTîîr28… ÈÜWgZ†ÑÓ\×Ý—© ¹Fþ9‡¤"¥m§rO‡ì%³U$ãÒ%d¹šúÒšëfº%ÞH8'C9ÏÈìd~uºûæÿü0êÈ7ÚÑ®Q|9™rHw@ήǃjG"Í"D2¬àp4f9‚©¶–ð…dÏujv-bôXOP¡“趘 wÜŸr~ò—faå@Oh–? ¬î$`z*ôå ®$¨è?3+÷}ß]?:øÀÓ‡~6•ûÑs¯,@ ˆ?rš*~PðGÃÛœøžúýÀý¿ÌoÜ|ÿð×vÞþ7>õz~†ü¹þ ÀºÈ5O—<, 'MW*wxªÐ5ÜùÖ?šÂÿge¿k~ øîªnÿ_Fâ ¶}é#Q¯B¸ñàûˆyƒG<ã2ÅåùN2Z <Žr5¼Aùnû>‚F+õÊ’Í@9öåÀŽd×G¦‘ïn+ÖZ½çGG:9wü·ÇBã|*­Ò ÞwÌë˜DºxÏa ~Èê¦:ƒÊô¨ ûS¿5ÍôÐbŠw}’f*¸lav‹Gh Ëj¾þj#0+}Ùà7‘:Ø‹­ff—a¤ªy-¶ºìT­ Û›üŽ]šƒC¼;Nk`Ÿ‰d£c ËcBÁ¦ÿ ÊyÞ&ÆHÀ÷R="…L޶}@<·_æ•·c§û€uèhÛ§ÎëGœ ÑÆl¸;–S˜ûóô Z§Ê€1d‹˜l»°NâXªÊv}S1Û“ÊÌKB¢SÝ‚ ÛPKÕ¾d˳?fÍŽ?{pÜ ¹”5X´1à;• {>wHvµØÉS<ÚDòšË°#v´k ¦;DjÜÜ`}âæMt çà58n”“xò·ÎÊ}O*÷»”Ê=´L*÷£§_:(?7‹wN^ŽxmP4Á÷S/ä‹|&ø¾ÿ?ÝûñïåqÝ¿xâñÿO¾¹q‹,Í*êó§HÏþ œ7!¦lÄËMíQ&§~g–‚Opï¤_]Fcå»éíV‰drƆٸ`Bõ"Of´Xm·p³ï[¶mÒ$Oè œS±ï`zõ]$yÏÃÌÄ“p¿ú£añާ^©e晀yç%ÈÎXÓ†C$A!OÍÎS8Rweïîñ@8§Zšñuú«S3Þ&§gô‰\~Vï+i¸\â@aP—ÐÞpÖ’q–UB;RÐÏFNÙÂï¼ÑÝ´´ßf³kÕ}jïM[p_G çkø†Ù›êoÑ[§ÏÝ‚ÇÀX×rÀÇ¢wxƒµåšþß=¯Ö¾p2VedèFWýMwéÁ¶ã7Ó]äÈ‚GæúœÅîfaêþkßÇ4QèX%œd˜]J!³_{&c¸·_¤D’gç„%wÉ5 H v¦–ø$»²GwœÁ‘Ç['¨€;³‘®•bذ‘“éyjvëjxR"B…®Æ1U ®¾åÈ‘3&dBÀÓü*gà› áž‚·ò’Ò>Io'Àtþ*i¾4’ò:_¹Þ/ o·ƒþª^4ްQ£ Ìëú\\ž7Æ|{\œêXÉwêƒõ˜sì#Ü mg®½S (›yŒ”Ÿœ;äÌÄñ¥œÙE^’|g}6%<âcê*÷41r¸s}fÃÌ`öç¦ÅDW»ãΦl8BY$³2Ì?¢Œvp:¡x§­*[°v9#gç6úJQS¼e»¾ÁV÷¥0ßÖ½}ÞNÌax ÜEUü %;yS+²ÝÕ?žòß ~1!iÃwîÚG]à]ô¡Ú0f—–»ï©v ùkÁô\ âŸLð`5Úß þ#Ѻ&`ßFÙ~vS¸u·jó dïl\JP¹ãJ:ëwÛÊïxø àGbÙ^ #Ë7ðW*a»º1v^ÃZbÔ¸c CÅä‡ ïÐèˆdÒSÕʵ d\Áá*-µ+|cX؈ƒ‡Y H¦O)ÉŸZ¾äk—E¢_ëu}\YŠog;I@s¥ëNÉuPÛ€;n¾®À³o~Aðp¿>œ{tî>V=½Óãç_=¸ç<›²=Iêwb\¾ÄG÷õÔóÁ÷Tý×ßûÓ}wý`Öï_ Ã3¾9?7˜úLR¹/‰}uzíîIÔì;÷¾[ȃïœ$Ì797@‡ƒà?ÅG+uM8tÒS¹ÚÖùô–ÀØ™²[¾c‚õV .äk•;o¿Úæ±úü(g4Œ$`Þ¡Ñ èö¾¶9=Õœ‰î ÐSEåLyŽþ=‰ÌLβó›Õe¢tƒsŸãŠä0‰„ŸQMåùNu¨C$È>½GY©‡•§«’^q()±áò(Ë­µ€”¸•{¯ú9-ÿí’J˜W°‰‰(‡r'5¹íS¿Ì›ÁK€¾{ÑH0õ{‹C´ÌÝv_…æ$Ì"=Ì6µnšSÚ:Aòÿ‘@¾Švå ²§Q¶»6×Nzà{½ ÷D(šÕJÅl ¯„£›*E³v ¸?lZT%ÂEjvŒñºÉ5QS© ƒè$³é4p‰àeeû8åÙ“»"Y»W8™­IÅeôÈY6ØõCžS¶à X*Äö8Hv¥{Iúö¢œ‚Pà»ì3¢õx§P¸ñSƒÜ€Ý¬o|ê²5ûVȶa?õV ö[èßú×Úý‘¯ï¾ãëûïþqúÈé玞Ü'¾äwœ`}’cg†>òXð}Hh¢’|&…?ø¾ç£ßÚyÛ—÷|ì;<äOä$ â)äsOßw5Éê÷e¨¨ÓÛ”SÛ 8ºÖÃ7ØYVJ«Š/p§ÝMÜE½Cçn-íŽó œ;ô].®ž*-V8÷‘¤’¸ÂÅ«wrÄ‘ë¡S¹ïgXG¶iû ›D+‚µ¤©ªø.˜Ù½öÞ YȧÏÞ(Ì_'»ìÝ‹™s®°ž ™Ù>Ù×ï!…\xR34(#ñþ…|I hV½W„©Lpž%l·ÏcAW_¶œS!<¹8lç¶q5TÛ&ënjã~3§ H#œŒ†½½9ÀƒFFL“\mo9Ï÷T×Ù×t§a'¦rº}Ô®i’è‰P9A²N¯ þ‚ HÞ1kø­<ç¨Ü3 çvÇ]5G‡ñô›tt÷%X‘Š6F¶=§ólY"G!㈃K#¨’ZÙ~°Í£ÚM¥†˜B E3v"Dr@ù3甾á}R‰²½{Å ¦µtüÚr"ÊLÇMÝz¡ ME'?)fáÖs‚æ#xI9Ÿ²}(<;ØMµ.“¬ßú…?þÕ_ëõD¾~χ¿¾÷£ßLå>h™“ÏÜjÊÝh~nÀ:X?òÄ”Àç‹Sìƒï©ýÜ÷‹ïûvú«©âoùô%î7PCÞr’CÄSÈ'’$r?³]ÑÅžJv6Ö"©ä¥ 4/s µ ÈŽ{;¥:§ê~«^uÄZŒ[K—æM›XÓ§»?ã <˜NL‡w'ž!d€øð€”É}xÌ–C:ƒ—jÝ5ðèd“–¹¨ ^“`Õ¸³Ä²kcLjAÚ<›Îa\q¹ZÎ`· Q *t'Q³ (Þ†d’Rp/M^>v3, öœê@º/ ŒL4(¦såpÙ$’é âßCAüŠÏßG2}`ýˆtS3¡zàÞîGN=wìì ÜS˜Ÿxäw‰€xÎÀú‰óãePZ&דG1yü‘ä/çwM ÿð³‡Oþ6øÕüÐÜñÕúÊMŸzÓ¾.ÍÞ[Ðç\÷ªêµæäÆF ÓÉÂsr;9U¼ |%©Üi\óŸâìXF™€uþ×hœ0Ùšìr‚yÏɸQ(e9o'X>¶ñ]óž—}s¯²]F™æØjÜ€k9g®ÐsâÑNF­¾ø§b8“LÇ~€%XI„u‚oÌBfEÏÀjN§™æ£yN·áã3ƒìæ]ÍûœužPAÂým`fˆR½,øREȆ¨_¶ »äå-a…Pjee)7OUó\÷Ϫ„³LnÓˆ@B§ó;šúz_ÚSR¹è:’~3 ´Lë¼¼ßÓ»ºsO@VWúäü—M`,ÃdÁrú%ø¿q05k÷ø-µŒeûÈ-ÛóÒØI.aN”@øèÉ`4M|Ö-‰ì윻u’¡lWä‹ä|™p×°])­}“Pùü›àIö“D×!x˜¥º%#©G—飪g=(P“¨«•êò Nxvœ{áÙ±‹‘^‡jÇMEw7MÄTK†Ò1Œ³H½M:IíœÕ,5LvOâ%¥z`4Ï˺ò¹ÉÏ|æ­Ô×{>ò­Àñá‡~}ôôóéã”íAóÁÌ$‚ï#É™+‰V|¸'ÂÏDc“ª?šÃ'sðÁ§›„æK7~ò÷y¼ÖsÖÈðTdŽâ)g›h¥Šç¥ F,ÛeµM͹––ŠÆ›ndǪS7æ2 ^³i˜‹5[±·-nâ%ÃÌ •‘x¸ì%y÷ èm§Õ UúIƒ–)æ}™åUÿ©˜gýxðÅZ•žjŠ*7ç%/A$ú¼-s.5´;\»÷àÜZÇ œš}ÎB¢˜LÂ÷K Vó¥V‘b4‰k„½yéW»‘S ´ÆoʞºøÉÙ‰“RËɳ+q±Ûí È}Ð~Öý%”G ¡\½†À¶JÉ2Vë=”x=yBdâÚä÷ÿa©eÊÒ‡,`Ú]y;°2m;]–.¹e‰è™r¦^€ïKÔ>ßf{Dé¡Q5ÚÍ«œèù #K¸æ†+óÃ9g¾­ß©¤–ðñ²°Ž Mw0^â!sØItÊvÄ3AvÝ0™N`„&ì9ݳ1à–&Ö!k;æ*aoYÂA·ì aì‘äé#Ÿ Y8>ÅŽ¹B@ÿ«/Œ¸užD.îýØ·ö~ìÛîýéá‡~“îè±s€{Ñ/Ás îIÄú¹’ß"¾§üOýžžêûBÁ? Ûøû|+ZŠwnQ@¼êøqÎð§Í¤3º½~×>(Ÿ„l"úwð½=Wá§Ï|S#gh ¦/&°f÷Êw)V¸@Î>#"ÊêFÓÓ[C$­€Aöu¢©¤†·uÆÆê]ý;´û*¤°ŠtZ±œµgUÚýÔ›ŠßD.程 VªÖzU:«I\üÀ&έ MÕhu?s·zßµ"è“@×W™*RéJ{Ø\å¥Â›Í¡´ëÅ{ïÔ]¬WØ\íÌž“ ZÚ}Sñ’БòªÖü’ HïH8¥:нÿ@¹È-‘½zì3DÉ¿5 ¢¥úoÈiå>ƒQcD22ïÛ—»¿¿ðwºäŠl̰£›Ì;à£_Ì –aêdÄq9ó’ª}Ï’¿Î¯@åÿu’…æy)¸'ß÷ñïìûØwÞ÷³ ò±3/?÷ò‰ó¯žxä5*ôĉœÉý@?=øž_¢®‡±Y|Ï>õÌÁûŸ^-Öo^÷8ôÐoáýsyìèz|©'F[“HLñ£cpB/x|ÇÜÖ]ÿà<-åÒȘÜ…øO×¢mŠwlÅ¿çþí›!Êw{ï6TÉUCîÕìéKøÌ©<À÷¶/L¦G '±Q»»¡©‚ ÚVaÄWå~¶N?tîΆ8Å„ —eIØ\»+Û¬±‡Ä)–‡~Â!ÜaÞq•'ÎFŽÑ\â”EƒP™zº—“wÂÑåÜýAmذÇC[šö”ð23Ýç]û£’ð&wUSÎ î¼íÃÏ0¾W«á5ç€Ì<Ï9[¬(Ð(ê]Ò´Øv>ŒTfyIâ7Ïâ0ïIòy§˜Ë‰Á{gnrƘõÙ+²4"ü àî`è䨢qCah)¬±¹ÍH%éú¯x )‰xÉpñ^îK-ã~þÈ[£ºÍM7ÇI`H¦ËAo&h“¤ÿ1“TD3 óbͯچf ,a[#C}Ø@"`Bº¤±Œ­p8‡Ó0“¡Îÿ}Â]©ȚBä1Wïª$Î.±l‚;ƒK„[R ÚGðŒü’;É``(Þ1è¨ÁnGR‹m×Üß>E2„^퇚 àîôyo¯év|2ïŽ,A¸3,#pÐ2u…ÿà æÉŒ%2m={m¢.’=Ç  ;ÏIr¡!d:Õú8B¼@©S¿ç忦kJýZf¢yÎ\ÿ7óÿuâ¯ÿ”óÀ=?>xßO?øtÀýø¹—Ž~1•ûÀqÐ

v®P¶'¿±^ŠþU‹ï¹O95ñýäoößóÓë?ñ£?»nÿÊî;¾!Ã_„¼ñ =ùëã½Æ'Ñ\]1 ¸¯¬Ñî¦S¥êÜ%Xô¸âgÕGØÅx†ÏäúO:Új'ëWÌSvh{Ç™FD¨Ì 9W£ö¿¼ï®PqÆL…;l“ÇÜ®%àIÐKa÷d§fÏÃoº˜‘&ªsÏ»¦ÞÑâ=ùÛ^Û9Vm¾·/ ^Ñu2ú…ÁTR!/S™¥œÕÔÂr )d’8Dîò<ª°+÷üL}“–¡â[váj]¨¤­Òî âsÞ-Ø:öѵ1P1ÐÓ½lÖ)Û¡×o”€>0=¦”çe’Àú¡û~ôäožzîĹ—nxd {úÆG~—8‘dBü<õï€;}"_?ëz¨ù׎ž‰~æåð3ÇâTsú9$4×ßó£=Á÷;þi×íÿtó§/B(q£ê]bô?Öïªà)䑇ö5 ïëdßeš«ÉÙo ¯3Áü_SùNsuaý’E:Ö@ý~ðÑ …ìó ýÕ¶Ðão³n;*“pˆIþ°[‰ßú¡œÙW7•À^)¡&%Â’$,+‚Źç”v§Òri‹÷X‡Éc7OäD¬Dè±½'8>’ÆÌ¸~û)7x¼é†Ux{Hi™‘ÀÌ´ÚW(0Å7=ÅÈ-sXr8êî K‡€®Ò!JÉýΨ·uL÷«û¥ÜU”Ðð-úœ/Ùïל‹½¢'éI”Õ_Ld/½ÑÌ[Ÿ:9,XNÍÂ’'Ü~›DN-ÿÚüf5oÜØ«‡± ÷ü„­Tžì¸XøžzA§éóhÛWº$¾Ë°;•Ç£hžI«³äráZª—¼žda0kH¤^R%)‚±<¸Éð™¬I%¨v‘]f†‘ô2Âö‘LDPØ®ÞU»Ã¨A³B#°ÄĬ¿xïýïø÷çßõŸŸ¼æ¿}æÚÿùù÷üï¿MdŽÇûÿ~Ç8ÿ. Éœ†‘_M\÷Äß“'1Œü‡ëÞ?Îøû]·}q÷‡¾´;ôí_Ý÷ño]×÷S¶9ùëcádB¸§›zö•€õÆ£ãÙ“ýÐ' ЯŠþü¸ž$úÜiñßO=O‹5šœ}w}/.™rºñÉßÛnsU³ÓPÞ rS.–bl)G$pîKBSÄk §Õ¢Ü ojÿÂ^Á û‰ˆg$ÍÚ䪋ËùoEêšDûO„°õ’QáEQñv‚B!§­iw)× ëŒO+ H¢Ì­{å#æâŽÇ!dÆK:«ðœ¸S9<1Ù—íÆÒ¹3•‚MHáû2ñÜ1þeñž+6“ •a“ín]ÎY»÷Àw’Y³‹ìi±ªûØ‚{:•ªò[Ç\ ßNi(|T•&B£_ݤõwé¤ëmc_G•Ýëtð-¡KLßËAÔŸÝoJ|e½LP¹7'„öô!?o* âË KÊv×aCµ»…»Èž„‘T—lÑTÙžëëÆÞº©p•)HEW:A®fNÞgÈ©âËLæ;:šÍ¯Ê£èdœìXÎy‰\9Áé¨t2X è³J¹¤û#Oï‹Ï!#©µDM;ß9¾Ê÷B¼"…Æ*VpçÑž“‘HN-|å^œ¢ì¾``“æ½×ü÷Ïì¼í+©Ð‡7ú]?¾þþ§có’mv;‡Jü&û1rN’(9òL …ñH$ÏIÉùà¨ÇÌÈtÒ±‡Ÿ9:¿&¿D©æø©gŸzî†s/܃ì©Ù÷À4qâì«…à«lç4©u“#aÊé|Tð£Å:ñ=?Ưã"YšÛ¾tàÞŸÝüi&W'ßÇ&c‚âݱ&Ígjã ë¶Ó1ßýÚîNq )OcŸlchìz<å|r®û`W<^NJ”W9Î*♃ÀúÚs¨øwQ^!@Û3ÄÏHân¦AQÒ—Rùþ€>]f†u7Òr:?8‰šäµƒ‰²=ç¼a1VÉToI4K(²¸–Ujfйsê8»˜hĨò ÜeÊ)áÞ bÂÉ!™ÎN^IÎiyÝÏÞæì, _¼ ®œßIßi ȬzQ/µäȬ_œ‹Þy8ÿâ¿—y·—9Úôæâ„u6ZÍö_Gïüë#…ÄÑX~2Ö«Zâ‘?ñÚùÒxaY&sÔòÌ+¬³t‰R‚¥Ø¬ŒIR‹°qHÒ\z=ÜëÍÛu&³Ëf`ž„’2å19­ÜõrßÇ•$!ܸÙy¸æùLÇË;ˆïíÚë}ßg¡'SÌ;’vã¡ÎFÓÆèÙSTmÿ__¸îö¯ek]v×Ó£ÏÒŒ±Î4TÆÃÏǶåHœxO%Fžs&ã V=óÂÖÉWž|64w8–¼ ždD’yžà<÷Ò‰3ГÜpîå°1ÖYþØŒóœîEùä¿JOµc½5þÐØ ”ŸZø™¸Lš‰ï÷üp¸ŒÝþ•¬sêN–Œ³&ßÝáç‘DXO$¡¹¦WÖ”‘Õ# ¬ZõÆ?SíSX8Úªy™‹8ø#˜Áó=9>3ʮڞ¦yjdš)A!ßw3Ñ%bø[S}"÷ñžçã°ЈJ°X•zÈåÃÆ|аrJ,ÿª½þÌòúµ[•O±äL-Ξ"Wäc‹ý/K~0øÕ g¾'ÚD^"ˆ "—(Û­¾»Ã®PÆu·st"Äbš°…iÓ•/óŠ!½ÞE(.‡ÒOx›ž÷ ÎfïµéöåÏa™„Æ¿@¢s2½Ã༸ Uà'xli[hq ¨ÕV¡hxžFN¶/ÁŽQ³ëüoá†Ù÷g¦t™è3lÊcñ¢à’:=×yc9¾Ä(]\Rœ‹H¦édfïˆn*Å»Óuàb÷ÂèY`FåÞ—_÷ô>)K¸}Ôê¼@»;ÙÅèWÎÉj1•:^‚ì8´qÅɽÊöyê”G-É5|à† ªØ·¾(LßY¼›ï6¦¢p×wtl; H K±¢~p_Ží³•ŠýO£¨ö¯º†Vªe“?vHòÅÏ,f††ª H>™läH0ˆ˜t„í}ŒÔwð³Kؾ­}—é#§ óúr%HŸºp#Ú˜w|cˆõûÆ¢»Ã§^d×݈³Ä«C\d ¿‘˜G-œ3/gv;“GѺ$ Á2Àz&äƒ%O·óÜ+FJõg_ ‚CÅܔĺ[(/|çWs½^æ;‹ãVô'R§¯ßˆr&(^¹ä(áÏÇ•ì¥ã¸ ‘¼÷'{ç"Ö)¡ù²w4ïJ$óò&V N9M-_ä̪ßÇiïÚ…Çž¸„ጛ“ÓS¥­ê„*qtZ£™™VeBHšS$˜‰cMcN<@<Ü`Us¼wÒ}ç.à3£2ÒÅÙ’3€xÎ4!YúU³*‘{+ÞkÜ•Ùë3¸šaÝÞ}9ˆqÚÝày=_£;ìµsQjBµû8áddNMff2p pÅW+Q)r©aàŠÆ\Vî«L)—‘ŸhÇÂuîWÚ ØæÔá}Ùö»#ª^ZS_‰òíwq è£.C1m-¥“zt<íÎÁ¿7C§Âª¡êVòi¨jF’Ó‰Œ*ˆìü¿Í5ày»=y‡$¤®2ydo€õ¨&,ÛûvŽä ªJ·? âÝù–®iUÕ»™°}TÄJC ?TÅŒ2mÅšfÂÝ7Ì*ÙĬÌàܱÁÇ{B<ͶSc%»UUH§,ÙŒe;ebÛÍDÁŽŽÁL±ÄIˆår(^m£tÐ2œ/¦÷W‘žû{ík¶¤O]~% ²Åô®7ÇXFµ"ŒƒOr5êöm p…}uwoS9•ÙXé;µD+5Á‚ŠwؘÐd´¹²ÁÒð_Uƒg³lg÷y³˜ØAÜlj°MÕ¸Þ9÷r±˜¾t– ˜ÕaF«$¦0tgOµ‹|¯_ºDå ;bñÎKØöÚ®73#îm6©²"Hm §H_·äs:Ê ¨ö)‘ÎéO`e™ý¢Ù8‘5{îhÝÔTñ³eH'ŠõtS£ =Yõ°./±ÖŽýGšª“åºwIS5S#‹§Êâ+B6@Ÿ0±¿éq¯ø[Z~¾Î^ìÓbíù„?‹÷!‘ w*éÈ’À篿ïÎïí ¾¿ïïrWcÄ)ç*ÞG"›A%Yžn惂¯&öS(#çK)š`÷“e+¸3WÌ`ZwM„pžàa.aãÁûÑ’ZÕÖ—Å¹× -ÙPÖÅ ÛN.ÓHÁ>53y™È›UâðÑÈ©Ÿ Òa!LXG¤ÀË!ž9S>ÛH˜>¡O¬Ï lg%jwl[ÀƨyoÏú]C`Y9àh†QÀ~I!b­ÙÛ~¶#ѽ5j·SÍbÀlìÆã:£Vé¦Ê:5õ>üTnJã˜J>Ïåñ›“UX½r¿°¾ƒ Kþ·0æG9³Î}ÜÌñû…j7ØÝ5¢:ò#èÔc`T6aê;`3™²ùâwŸ½¾càžÈ²`ö°ÝÜÕ“ñl›SY$Ï¿ø\d‘ñȯFv9>«4ÊØµ”¢~&¶¤ˆ³JgU-]Ð¥‹å€¾í6TM ”?ℿY¹;´Ì”Ä<>*ÆýÔÖã%Û3*Ù'L“2æ …ûÚ_‰ã ”“ßüx^&ø~Õª\p÷.Lo ],KƒŠ|ÿž‹XŠ Í¯‚ïqËοë>ðÅè…´)¾;¿¯Î*ÑWi»„Î*NËk!Åû8m«b%–ÿ÷ñ¿ìE$R“š“£³rwƒvM3-C`š=”ðh"µÁè²®ýsÖg$f\Z0¢üd’˹wÇÄf ò³ìŹCÎPxa׺¶ª¢†L'³¼QåÚ@ƒH×ÃÍÒP¥³ºLfp׃¯ålûaqGÌ¡|L Ì~§à„jãÕIsK[ÂÕ©Ë/ ¼M®œ"jßÇš›‹Í¡L©å6®úERø\ìÃMÖ×äÞ%:potÔêûþY~h΄£%rW~„[›l» :Î\ùÄw—šyûZÍA+•<à-£Â¶*°N“}vSß,?™óž¨n/à:͆°äèd–ímÝÌÅÚ4F-CÙÞ×-5w޼ÔÒ ôä)8ysüÀã—ž*œ)ž!D}hÝu;àžÙUCcÚ^9C©¾„Õ §%s.dÜE¥Rø%îQ¸Gýucnî°1m9õÙWSª“(GŽßKÓ•wɹAȘ^‚ß8D€{«ßëWÅú‰ï»sÑ/Ê è}‰8¬Ç¥ •$?$ðéÌE}q¡95ð=š}wŽE}×Ýöå½ÿ>†.™Ò6µ ÓªÉádüGÖ Á4ŒYÂÿ2ÔM<„$±4‘GšÕ;&ÀkÃꪧU `-³ÐH¶h¢„WIÕ2%˜/ U3¡æù•dgÐ;U},F™ò"™ibw&”_‰ê (á¡Ý1v_΀´R‘Ï%·¡:«Ù©ÜG ã Í$ p˜a9ó¬/Á%À=W L‹ˆ¬öœZYŒ¦#Ú%.\å±åNdï~ øéݺR£[¹k F\eâØtîÜUúM©KhB¶·‘¢Úîw)‰<8Ü¡ewt9élÐÎÖvjÜqŠÈITgü,ÿ»“zSY Œ Ur.–Yþsè wœz#9l;V,åÈ™w¡"w»N½±·¨FÞÍ~ÇTV7Ú„µ¥KŠgþÜGêÞœ$Q°ÍÅÇãˆ'”:H£@yñ}xà6[pÚQ9Úš'4€¤lÔ¢VÞ oŸ`¶pÏÐé¨ÜŽêpîÇ)Ûk§‹î$d\šn¶Ùò™d7©ý5kö¼L¥ž¸y•û?ßòø?ÐyIŸ„2Ÿà@<<'eûBùÑ` ¾G4§XŸÉ~|Ï?H¶8E}ŸÅàO‰H$D&¶v65·wxlÚèy`¬rFçŸäø¼'`ÞËÆy-Ѧû²î÷ ;Qjwv«®Å{Vîà;R™C}HÕeÙký@-þå¢ò°Ç%$%¡Ù}æMtú vgdÄÅù¬1 n¥•û« £rO¡–O.œL¨öXÀ¶:ïÝ'_×rJν¤îÉ·v«®9U`5ö4v§§ XA#hÝK@d“?ý]D*%NbÞ¼zvsÃõ»>”[Å:›˜ Iœ˜ò[lREíÖáEXo ±©åì?œ%®ë@>o†ùaþð®ä ¬zë ‹Ð¹kã²ë'““'©yfÙù¸ݦ‘»®´RmÎtZ¯¢  ˆØZ‡=* 4[Ó/ŒêcVSλ©`žÈ~ÝPC£©§²z©o×£xï~2,èÐæWw¤Ê*Ÿáö`N’ ²[»8æ ìÚ²_ÓÖ¥}ÑA†@™€^Xà¾ýýíî+#©‡æºŒ ´ Ü ›írÚGmàN冿Ê(ê¯FóF’$oèü¨˜>ð=PΙë2 »_ ß úæê ç`6E57,NÆú /—à©õ<üÐ3¡àGý~÷ÓdÎ"ÖHhnúÌÅà»-VpŸšzÔoïë‰>PÆ ‚>Àsš Çæ„ÎîP$’#•!'–0Vïk™BÛÇyX$4þ­9Ud»ŒRƒòÞq9Íé‰PNånÙÞ[¬˜Žá$<]$s2Å/ɇ4øû~¾o¸H~+õû{Þ÷·7|rºŒ%B²“Y0Z«­š3(¯êŸñ]ˆO°^5Áÿ¬‚ªøbÛ—/yŸ$B»÷Î ‚Z‰±Ð1'‹À„ø*á±BZÊwùÆâÜ]ܱtŒ,iì>Â6ðœœVîIVë‹¶òÂ='ÏÜ8¼93¢ìe’‚o* P<ôz¶oF‘+xU‰'” ŠwÈ"gö‹u6é´Wœcj¸¿aŠn™ß}\„ Ñm˜Ô?‘}vÞ-l¨¦÷íz·¿¿[YŠþ*|Aÿšæ7¯¨m.öîÏ/`:õ;e{0]?eÃjv)É‚uÔî®K•SC0”»œ¥8w*wß fðË©+$O‚‘½/ƒiDZ{ðpG-ÓûB˜…Íò$z§¥ƒDö»ä Êvµíø…ñ!)Ú]ϦEz¶K¸÷ñ%Öéò,W“y§Z·›ÊK°@Ë0 yPN†>ž#©šÔì%ðøÔåQ¹îÿ{Ð2©Ü3žÚÀ½t2ÇXk·jvà¾hkˆšsì„°>¹‘åÝ(wJâÅRý–Ç~wKÀýÑu>ñωä23Þr¥ëâsnêgÔÌôŸ­yórlÈóÙýôÊ‘S¡¤Â¿?ë…á®sgmé{÷}*ÿ³rÿ£²vì³Ø±])ˆd²)Ñ ž‰bÈ÷þ_Ùñ}N”°FCà{¥»°|}·×ÁAR[TãwÒιÏrXoø>Î ©{N»©9ñHÝ™Y®Ú fSç ¸cì>®ÀÆÌú=§Þ¿Î²pBÌ2Í!ãœêbÊ3$¡rñG²+˜ :á553 b×AnTÙK­¸¹‚K;ø‰ÙÒDÛ™ÖÉý%€Úךû&¶mìZíö^ÚÜ$×· Ÿ(Ïs:Ö„HF'üËllzòÏým@ãØ@ÁžœÖr•9UÌÌlz\€#Ó“€—ó¿„ÿ¿7G¢ñÝÔµ¥ÅV*ɺùƒìÐ2œ<"Ì¢‰?NÆ—Àwµº€{Nœ EvÀ6RÈlL01ì·<šISM¥ÚMÕOF¿j…]6¿N™'\½ä³¹N¿pîèdFåN8½ÂÑcÐMu>'ø>È÷¥“™œŒª¾€×äÜ÷˜÷³/ÙžI厶]BfE:OäŠ`Üì´{«¦ ¨°®Ú<àžxb$#\|ŸWæ×Œ»Â#òížáA"KÓ©BM$MBй1«…>’ù¦IÎ|3+¶¯ýŸûËöúû~|w;Õ-Ôì ßõ™ÉKº©'>ùÕ‡*F™`ÛÇg=Î]œ%MÎ1á#†ý/szÌ醿JÎ=WÖè\=Jò¶$´ÿÕ‰÷szªû¦r†7|‚þ“3}ØrŒ\{ÈåF‹ú"ÔU ÈfÀq‹°ñ¨ Ä»U-ÁǼM,b÷}ÍIÛâg(ÞYÂŒÒ9&‹ÈœìJÓ¿s§xïÚs5å4ñRð•—ºIôŠÞoK®ûguu¿éTË€ú}T‰|ÇN ÓÝH^Oƒ+yžïÐ1šf³ÂÞqyi–Yœ ª Ý|\ÓáÎê¥îI«YkN<árj枓٥TîºÆaÔ9aô˜žH ÊJ@»W}¡D·Öt~f$ ÊöDß¾dèá¾ïü…+T6q1-uÇðì";+Rðp­ÔÝ•”lØË°Z¯šl3™l{H[Îj¥Nd…»ƒ©4ô02dvI¤ØD µÌG¸‡sŸN2³rOÀÉœMþš$;8¸ë©|Ó^¹sE D MT‘=a…ŽS¿'À÷÷ëgOÂׄL/‡ç€?7•‡~Œîä0ï —:q»B9˜™ÜÛâ¨sèÁ_¸ô[;>øÅíÿóóùÎåŸh*gþfÚ›%«VÉ)Þyxj«¯þXànÐJe7Óðºìú’£‰¢bFhJaäJŠhÞà6šš='£L¬ó•<¤~§•š‚±àÎ@“˲sj9@ oåîîì908NbÏ$ÜS¹SiQ~á Y[™h«ÒE›ø.íž’kü…Ê‘;=Uvìéíž ~ßru¯eª$¯(Cç“Q]|)ÏÝÍÔvï î[þê"pÓÎ7AksÝå«¢®\·cIï6%ôb1¡ß‹æŽþñöRðZpz«QW#ˆóÛs*O°Dåe­N-i‘™‹|zBùÎþÀÅj|¯e,^ÙðûÍ•.…  ûn裠¹¥Ak‹5ÁTÞu€žëà;ïWÜï†H¦*”‹ëý-¸WýÎG"Á*àÞÆÿX‹Ó,eæ¢úÚˆ¶ü@àÜÕ>o“Z…œi+° ö.)o V¨Ç/Ez`‡“ …û8—/ œLδ UË´Ê= Èzîı3¯ÂY;ÐOÁ®¤|S©Ä¥ [’º{àþ-³6‚è3f!_€>‘Ò¢¦·X½m@Ëx&|˜h.ðI Ü]Êš›ÓPF†–9S´LªIËd³Gh™¸æ¿=uôÜ e\¥ J3C+n¨Ú?$qq¶ÞÜ•™G ¾³w…â}˜LÌò<ŒœSÊIxž£f×ýW7x° †GFšùy²4†³ë»lõ§RLOÜc“ê’BR¶»ß71DîåCÐ÷%Xˆ¶38Îyk¥‚ì¹^4+÷YÒñùõÐè܉@jwÌdÚÚŸ ^¢ÃÆrÖïq¾ôFÜ.gÖ^ƒÈBi£B›¼´zô×…V¡<Áõ¸=&ßXö$‹·pîÜ+Táø˶[b;eÚMÎJ¶éæ·zçì·z w.þ/îý}—gºÛ½©IrîïTëîIÖ Õrr§ƒJœ.XŸÛr/PÂç?X/÷f?—÷I½ñ•\¤rç\ÛSQã–¼ýoV`÷qçdx‹3­‡x©ƒÝ‹]ÃÜI´R)”4ûMè:À‚´ÄÚÑQÌŒ:ü»sщQ¶³)yüú8¸‡™qïR<Ø€$M€¾O0AµÃ3¡šå¨egˆi¨e¦÷Àé±rÚ²=I 2å­òväµAÒ B¦‹ƒËù‚âU¨ÓsNРç%°(ÍzˆxÊyhw4”[üL“½;ãªòÏèùŽf&ß"‡§X$¡>13¼§¡ºãÿíŸüCï.ñP ‰¨wßâÜ9õ+©{YkÞ‰ƒX 1é'AñŽüýEö§˜d¾Ì3Ÿbå&Ícâ|×Y¼«† ¾ïçY3ᱜôTw»Ms| ±½Í^&•µ U·v$¿.Š]ÔX Öæä,cÈ¡Œ`¼Ü3øŽÅÛ4齡­ lÇ›—^HBý¬çºCª…B8£Äu`B%‘—PÙmEjñé}×…xÛ=íÁ¹¹ [m@]ByÿÎ#×Ͻ÷KDªQRõ0Ý=¦÷pgîE;¼Êï d30õNèöå#9Y+nîÙ™/ÀüÙùÕu§ÝŽ‚uîµ:µ†˜”F1›Š“{‰¨jÂFü¨ß-Øwœ~ÃÇÜÓo`˜DR€äÄ.ƒÊ]=:HxF• îyÇSû`/“§]òò[‚×¥:»”dŠÜ/ò™<!£™Œ¢ˆL*òÙ¦dÓ,ãï|Í“— ÝuH ‚Ä·$â±Ç/–Ôzq2 ÙÙÿ©˜¯ëS¹£– aån75§QöŠ€#Ÿ—û '/óE›¨aGäN™ŸBfÈNåþ»÷æÌÅüÞó¯å%àóN‚læf(xêw;«äD›?àN¤fÇþ,7³¸½dÏîÀ½?pþM"… ¸ßôé Átÿ¹Ti©àý´Ð2؇ñ…P•ÊûqÑîK™“ž g9ˆ%IèóŽÁò™ë—f†÷ϲ½pƒ”íÍØ.±vï¡þÊ•¡èmcz°‘øåá#ÆSl³cJRÓ \IP.ð¡S-SÜX?-æ5ÄâÜ…kN¾>~‰­L28ÌÀÉèç93“5Çô:#rÒíK5ÔÉac®$‘šºËÕOj…+ÊQæÊ`{ðÜ`ÈAE!Þ(ìík3€{{¥y©·Ì…«mãMú-bÃu^Q?«Ø­$ Œºxš Gòh ûP¸ÓMU0sꪌŠé÷Kåáf¦ìPË,ÎýÚfÒï^lwì…mÇÝ?‰f¿ À*€q8ÊvÖtÀ¼ë]Çö%Þ£¬Ö#\J‘Âz=Ÿ&ðûÜ àêàu%¼«õr¥M.`€›ÙTÓnå¸JÂòGuxXá &×:R™äU!ºH¢€bsò}$Ü™®LCu7•;RÈ îÌ Æ/¬édê´æÍéº;Ëv1½s2ú³º£· t~mRêU¤ç ç­Oþs–†_•y´Ì*ÛzþˆBö.žé¢šÆ¹f 6†=«yX9SAÆx ûmcˆ è,­Ä¨Ù!»,Ûr«æ´­ÊÜ.žôÆág0s&hŸò@™ã8™œÈj]é¥Úö£`½:waÝi&ØEíð\É”@6ÃŽxPs½¢e8—o6–M»gå®ñ¯Æì1fÓ^X×;LZ†ÄUÉÁ¥—"¥vg¥>›!\É ¦[³î—ržvú²Ìd\·¤Ïø¨’܈œë©ôåj}¤JÚÉÁdµËçy¹­ß:@X¾uw³ Ö¡P¸‰ÎþyR7Dý©+£ÚWêQ©pž‹³AÁ—Aˬ5Lr2«f§ÑMÖ÷§`äÆÛÄ÷7øïÅû º©´UK'S©j¥ºÛ½z¼ŸBÎHº,†ú‚%¿µsàl’åêN©¢f†­£„ Φ„ϳmêËlߌjÈnª‹Ü^Ÿ3@ÏJ{¤ôÍ|—oe»&{Ø t@WG¢ÎÂ;ü¤e.Ûú‹—!„ ÄqòÐ2H!ç¥çwkvÂíþʦNÆ¢XHõbNc–Ø ;Éôì“XO‘ŽßZæ‘×r‚ï”íãê~â~N9w']уé^q­‰j¨ŽVjžB^=ŠÃû©g²okCÓ‡¾¼ïîè í¬»ÄûÕš=€ék_Ç–Î}9¾ù¿I_&ªe¨Ùq3èaöàÜwÕ2ôQs]Þ–¾W¥e¤y«ËÌTuB¹D%# qxWfFC• É÷QKa?°ö(¸Lµ8÷òû[(?¢>×nʮ٠ÔTîìóYëXÅX·­ªff¹þ&™Yš™¹ŒI{™î¶ÂéÊ ÜMxÝè¥KãíGR’'·ÂÎyÕ~‹´§+$€½ßð¢»;n¯€PÝÈE „õŽìíBÛû¥+Â{ WÖJU8h†˜xb¢~ÇnŸ&êj¨^dHÁl{`ÿïOp@¹ƒ©ør%™õÂ<¹»ƒ)<Œ–žmÇÞâd~A;¼k)Ôv¢o_Ba¦CÆa©Ü9©Ü°4ÁûôÓ2,çJ0´Ìé¬ÚP¢779$ e~ÐðäedkéO@¼¤2Mꎄc ×\NåBÌGO5¥h*÷LcZ& Õ¨eN£s¿Ú2±jv8°r¶UaZLô{é~‰TܪÔQÈpBÈP˜ñ«Š—«ߥÝ)Þû4Ór5Ø e\¿7‚ÚÁô1þ{E^8üð@ö,zqX=»³ÓPuYÇÀ÷µ¯#9ÿn\¡A-34_ë;Ø×QŒA9¯ƒXNvié0ãÊÃç9瘰@çÎàÒÔAÒM¥»3Ÿ#—w˜RÈ.uçÝkâÖžM×FxÖ¨R߸ð@MdÕì™Á[cG™83d#6e;Ö§©Õx@GÛ> w 9™3‰ ºQi/³±Lµ÷yDÙ“€ìlŽsr³›ô&Ü?šp$µÓ$]×ÈEyrNù󾤉ÿ }†ékn£ºáoì’÷Q4-r@]?cÁ®Çv÷ _º™ÏI×Í¿ÏüÀ½†˜ÆH»Ï\‘{ò>¡ÊZF?w–l;Ö}6.&p§~§`qØÀw*…õoΚ]K÷K5JGÝAäeN0=AOuVîŒ_»˜†FSÎn,ã4Ó¸2€>W´@…v cUá´¡CL\Ä ]É,ؤxgˆÉZ§{b’0êíª§‘5{õOu¢r)Ü‹œ©Ê½tî/Ì¥K/£“qjé8àN²ö`$úþÒ …Œò‚¹ ÛIwªòXÿÈ8…þQ³·o’Àw ±ùW?C¬ ZOLËãáÙ#iè·ï:[¼÷ß5F–²5;ñ[ÇÊŽ·Ùšíâl¼!±ÒL•9Õ-Z†a×3éêÞ·î±foï5i¼Vfj"néÙÁw v½Ãjrur/€ž Œà"ËT›± çJP0´aÍî+µFåN,o™Þ_­›CçÐEð>tê_†¼Ëïe]d…¼‹ˆé’õõ5¤ÝT¸­&…œœ{13ΤrωÈ]÷áîHb,Ë0„S¥ƒ\–r{ê 'ÇW zÀ¼5õ–)?Huî.{´äì`Ò^¦øw¡ªf¦·UQÎèú ²Ë¼ƒïµH³XW§ÙÎ!瞀^RÈi2³ÄÕzN¨®Õz‰ùr‚{ 㿜P=p߯äÜ1ƒÄ/¬»Êè½57•²°ëRºÍ/ÁEmœJÍIî¼ÒFå>ñ}È>*w9™$Í…Æo®àýêm!#Id'5{=‹a§™û¨?þݘ¹g^éÆ'ÿ%òпúëñ/|ÏÖì`z’ñÒ•ª03©Î kÍ¿9SR°÷5ÙB¿<—Åc‚]±v?Ò¼eÜš­•Ó#~)¹ÊÝ…;ˆ”k@<˘¹ÃÌÔ<ß\ ¦Ó9&W=øºjHE2XB]ýñg¶f—J¨B}-xÚkuÚ?ý¯q³k¹u¿†_j¼Í6ByC^+úͨ$+}ᦤ6Se2v ºÑk!ÙÝÎø÷ÒT“b=àî4AËÌÒÂýšé`&'R§ñÉ;çx™j|/uÖ/Œû? Hü+\îåÆ/Šw\e¢“1ÌI›ÈýÃÃj°—YB<É&xÈõÄGÛ!¦ cvì±V~¿èòÒùr°žâ½æ›Æç5d’‰ûzÆÖζ§–*|™¹µdß §om’€Ë:†ýÀ܇E"Ë:®ÒÉ,ch»G'd¤¿»ƒ£ €æГTguégF‚ø}þj%sˆ © 8.3“àæÇ „øÚöwþ•ãùÛeìéçÒ>=tÿ/Ì5{{>üÕ]·åæO½qëþ˜ˆã$cýžóæÏ¼Å„*A7X‡Ÿá¿@Nþ;|¨bÛ­^žœ ®”íÜÎëéME,~¿MçžD¶=I½Çʹ‚‚cùÙ­æ¢iÞ]û^®¿-¨ÙÇI 4?)¹â²ý D Ùð õ6T¸k I‰F¹6 .ùŒžÉÜ8™µ©-… „ÌväÔ€IY‹ÇÃêõœ8 è³Y÷—Aaø‰…évSís*v*eN:÷bå*6†¼K!ÛHq÷ßNî¼0œ?²ìï”'j¼ßVâZÅÛ,ЭÍexÄÐ=8AÍî„*ÌLNDHKá°xb*© ÓLº†¹ [Î=爠|dïËFŽ>ûNí‡XâÊ/]­„;ö2N¨Ê¶€m§ûï&tU¹s®qeŽ ¾ûœ“™¼T™@9e»ë.ùGIñž@ù :; 3® ™q6u¼d*•pŠ}Ê \ á¦fˆ‚üŒf¿‰x˼w.K Zf¬ÙûÉÁèÜO†jÖ¥Fä>çzØ«GḚ̀šcä$R1ÖÈD'¾ÝÅ!²«R—™©S}drÚ­´a“Lp÷û$ß2˜ÇÇ82ø…¨ÝqûXŠ5ž¤Gí5ºeà»:È™#uŸ~î >ìË$’@Ë$”Bº [š7œ E$ô¯ wÈaÁ})Arª“QáÝ ]Ú²ÕuuÎ ©=lÉ%TÈ»ý¢'»Ë˶Í}N¤Ðõ»‘‚÷ƒ˜ îOl÷Ö_âW7 ,öu­ÓafÞ…)>RH‹(ÒùŸÕz©—4ˆ¨}LþÿÕíZ×_]ÃrªƒìËövÌ7½÷{1ÍÄ»-/±„t²Î9¦UƒŒPí¾MäE3¼ÔÒ½•BB|âRDbï>´Æ˜ýñsSÇàOu½e$Ü·6u”«ûàd4ƒÈ^«—pŸù–}˜„Ìð¿#˜’O⚎µ+nDüÜÿ:öXûï ¸ÿòàƒS ™qž3âç¢ÑèI^JKÙ;%áÉc ˜_"NŒxe\9;®@o˜o8?#É#¯7žâ¿’+9ƒõÂ=²HÊð 8 R yJõæ ¬™ I®teý•%|1H¯òƒ?ûâ±SÏzàéƒ÷þtÿßß÷±oíºíKøÅ¿þë?ýÕhœªý–ϼµÊöqÞôÔåëlêø\‰ 9‡yrp2ú=Ô¿Êvm;o\›ö!3œ‚`Þø/>òøE*÷ãË(Tk ›4aó´E9[©—UCB êg‡'~î¥q“*ïjßá˪á„í|@vŸ¿À‘I§Õ§ß̩޿îQ7ìÂ;¬Y†¸[M23ôÛÀ÷“$ðŽ¥fg¸VjÕïîòtGÐ)Vî hkTûŽl·Z‰-}Í)âõ\iíÌÕøT‡b-¿A„À¢›¤ÀçJ!ö6‹nð·ƒ2ßœ¢ŽIúÀê†Ó@’õ‰ßsÈ©/š‡¬º?½ã^#¢Ù|àL‚åd| ”w·Yf,ÛéŠð?Wäš~¿kB5$–¿‰ð3(ÜË5ìÌ|9§–Ñ]i ɻ͞ÉÎ3o¶'HtÌHìãÄO#ÕM÷!X¬ç1Öu”Zºçzw…Äëc‹“á¹¼e¨Ü}ôN²½Ð\ è›—}aÛ“y/|±rdT²Ùÿ"í Þ„8Ä_û??•HT€q=ŒðÐÃÏ r&šÈÄÃ/›v+™ËŸ5o%DrîŸyqF.¾@$=qöÅI<‰3/ÜôOœéÆG^¾ñüŒàþ¹W& CÂÐqíNîZ'Dp—uHñNTö)TÌñ3/É.Ž)y¼þîïï˜ÈTêÐÃ|n°ê)ÛÁ÷Ú›ú™bÛ-Û‡ÂÖE˜™¶ü¤ÌdÀúÆ2­íá„*„{Õ27oÄQÎ'× ÄóV©{ík´ƒwŽº†Ùä§ Qê¾/°évÅSÕ4œ˜s ¬GqÐÏ ˆh?@u$>.£s_´{ÎÞÃõw ©ä‘i\.'È5ϘX˜ç€uÕ}G6ûÊ8ì¡Q¼¯í©o$˜µ\•û¢Pº«»–ë,Óh÷ñV¤Ð `Ùöi{6g_£*ô«~LlÓåqƒ!á{éS“Ü ß±S<:™5µL[5B,¾¤¼7’þ7ÔÏò=wQº44°õÁÚ7‰Ì{¾¦3‰¾Cµ¦™°0ºåï¥A»Ÿ…¤³½^*+‚eª¯àdx`´çS«dp5ó⸎ N¦©!K0#¸¯ý5ª! ÀÝâpßrýM` 9p§fçDýƪû•ãû𳑴RËò7Á£} ZB¢sgY„"k‘`H5x¤)yÎkÿÇgw~è#˜Ùw÷‚ïi«&Ʋì‡~qä¡~}8’’û~•“È ëHÊ9’NÂ_=ùÛ£?sìág’ÌøMÎc§žI’óX¾ìÁß{ø·3ž9~æÙgž;qöù`ýL¬äÕ›©â5ª'iÅ;ñgwtèž¡Œ’œ˜5û¸ßœ~>?5ûõ‘<ÞñµüâÿR°S¶¿wàû ©v}ÞU¸»)Þg÷¢ÖìqÁIÆB9S2o•™{£e(ÛÁwû¨œEّФYõAú7‹Š¡3Ï)ä½É²×p†k ²'ÇL†ñÔš™$¸a×Úƒe·—sÄšúÆÕ}ŠÜµühÎc4Èî¹S/ÀÉÐS­µk3™œûÚ¤šHÎîŽY¹î9ÙÉÌ2¦À‹Ed7–ÉEçTSXºsZƒžCDî’ê¨K”•kïNÞÐ’+â~5ø*o³pU4nödÛ4!ë[ºýeÃTcr圢<ïû¹33’Ö˜~€»Þ ef`ˆ€€mÏ©…nm@9·\M¶@gˆimê˜oydcž[}´S¨ÝkŸ:¡ÃL0Òîë-˜È/éVò]o™½@9Û>‹w‡÷¨qºp˜žª£L¬™1eÈ”ð,îX&úXŽ Í2e»¢xvÄ3,ÈÎKj:Ô2nh+‹’q]B€‚"˜­@ã%æ´¹Bí‰àýÝÿù“×½ÿÒQ õ¼÷Îì»ëGhJd\3qpœ?X0I^&!¿*~z辟‡ïÿùáûv8É??tßO“'’~àGþòèƒO;ù›ã§Ÿ9~úÙñ©ßƒïú¸†I% ûò¥I²»¤{–M†ýµIý¿ÌãÂÑÜøåÁ{²ÿãßM;û޼ù©×S¤§0§fGæÄ˶k9 ²îJe0í©11W£Ð𨧨q2ž “V›˜”´Öø’c ìÜ—Ù/÷{N昒¸fý O!'CRÌ!œ •{M-sLŸžbˆ}ßÃg)²}Ê]%¿t2 è͵zžOL¡b– ø~ÚÝí˜ZBš …ä#/玶äöy–`ƹý‚à”ÃŒš¹„ŽTråØgªŽq…— Z Ô¶oL•òeRåÚÈtZ¥(qénv¨ÊÐsÖ½§ªZSAäÆ0j³¶‘EºÂô ý½kqD*Úžƒ0†D-“@Ä“Ì1ÿ¶°í)ÞÙwŽŸ;6îy ¾»{: Í„Q¦Ò¹'6ÕµÎËÍÆåMŠNFMä8µtç—¬ÜK–DB¦»«= ø,‘ÙÛfz>–z½ŸÀô¢ÝK&A¼Hâ„‹‚™ªû&Û¢V79‘@9>3®Æ¦¹Šh/@ãÊŽwþÇG¯ýŸ¾Ç'+n*±BŒIäÞ¡ûgd‚{ï è$/ûïünTáûîI°’¸þ®ï%ö~äÛû?þ\¿þÎï¸û{ÄÈïâÊ÷Üõýƒ÷|ÿà'~xè?>|ÿO<ðËc§~›Bþ†³“¥ ¾?ÎîS°[Sš‘ôNÝÎñç+÷G¢zÙ_:vê¹ì>Éc~°H·~îÕzÎŶçÜKþHP¹W^S©˜óŒ‰°x90 †‡OåíƒC¹tŦŽ-4·•š& eœÐq#–—͘ªädt kÌL’ ;Æapî>Pê“1i÷"d¬Ü‹‡dÂc)ǘZ¢ Ð/èäŽÓêO:BdŸê¬ Çò¾@•âŒâ}PÀv‡µƒIKwžò]ÝíJžÇvÏÔËþ×0t2,ÈÆ;,'@*²mÈF:]ᯠ͖¿N™nr÷}ºµ•)ïÅÞàÛz1rÞÊ=áZ¥V¹×WjEÏwßÔf6âI¡Ü~„ßÙ1v<9ád&¾/¶}mçÀð!¾?[oŨ¶¯ ŠvÌÑE±‰‰ UT1ÀýøÜætro¦Ej³(á•åjæiHŽ#×îÈÞs® >Añž°ƒê´ªRΨbxnÅû–÷o[ £åïÐ?X •m¯*>ÁÊŽ)…vT©ÌÚÙÆv7É5×$Av[¬4ÿŸ¿zè]ÿé±kþÛ§³’â=ÿûoâFpÝ¿˜xÏûþa&_ ƒ±ó¶/]÷/îLž¸mœ£ØŸÉ®Í/øÀx¹ûC_ÚíIBÜ>"ÉžÛ¿¼çŽÜûá¯îÿØ7®¿ë»ïþAÊù#<–&Ô|Èw$4Ž›:¤ž}sÞæXl4<£g›8–Á ‰"fÿù{~´ÿÎïì¾ý÷~ä›:LÖ'ç>§9Aó›?=½;ABÈX°;¦Ÿ ÏL.PÙ“óRc™Ù5™}T¤P”í:ý.c—/¢šåQÏ<B˰`‡™Õ>½Ä°4f¥´R÷4ŠÝpGGÀ¾'˜PË r‡½ Ðó‘êLÍ„ruSAÒú"1'QCÝ<…û,~Öš}TxlOMè=঴r¼lsC•ìäi¥26Ÿ35»mB+ñ Sß®Vͯna:fÔñ–/Ûtî’ÇVÆ¢FÑö':wa]Ìå7t%{·„×׆pàÊðy¡øýfåa“AöFÂ}$ìkë^ͦ2<z…õÔò§.è@€¥»ËT‡rý×òÿr'eûé cQÈp&Ö¶'âF¸÷KÁ;Tõ/u_õ;j`à»+ƒ%xÇé—}{3Á»ƒi@L7j:üÑ‹@¼b¥™¡.cÄcÈ„ÖQOm™`üÛ‡_Ä‹ œŸÞZ­=$•»‚ÙØ‡ìÿ{â‰ßü_nxâ÷7>ùûŸúÃ8?9"WHnJ<•øÃMŸúCò›ó5OŒ—I·|ê·|úõœ‰÷&yê÷ïI^Þú™×ßûÔïoÍ/åüôÈÿê3o$¹õ³o¾÷©×ÿÍç/ÁÒ„‹?qæyÈ÷´ -s•tú]X'^£f/ÉcÚ§'Ÿ9òÐlŸÞ1û·vèËøÆë”í ܓȶ3¾”Dã0&¿@öïì.P”î“q*•ŽÓ ÌìØËtûOؘaãžDWñ})hyÿh,¾'œWJ0ž*çî>È©€DPïaù€ÆyT9¨Ý©ÙLÅR†én ÷$ÊŽuœÜ­ºáÛn‰,NreÃÉÝU¦Œ«š˜¢˜•»`_®4šåß­¬-´WN ïÆuoP|A·JèzùŽþ=Íó’Ê]Mä%·M{ÔïÈc@yþŸ°`” ãßr–ðIm¹þR¹ÏºÍ A<˜nGmV×ùv,ÎY»fìîF1ê÷¼,ÁÌe\±‡,BF«™2$¸ÀÃïÁ)”P³^{Hª”]È–ÕBÐ7ãI\µ; 69$X“=ã_'Úgž3Áîøfšàd¨1YÙV!À´jltó8å"ä(‚}…Åù2XùoþæÿÞú¹·s&ÿ×ý“ü›\¬ù¿ý›?ýë/üñßþõ<ÿ¶~5/s=/ ²þ'GOþêøé3/Þ0ÉwAüjX׿—\ßÇègٽ拉 ûÑ“¿ûàžìùð×ó`‘Á¥(ÿü@v ž¿B:¨#™’û¨ú p1Á?‘ø¬'q$UK™š~ª[,;o¹sjó©Ó/† mSë–ÖŽlÖt$–÷–¿ì< ZRPmT2TíƒRç"à^°^òöå*Ó\ÝÔ– lJ");—¸|>¹ÏH¥ER–a©ÜáQ5þܧDB&':™¹ŸÁ/l&eX’¤feŠ„aáþü2ªÉàONÀ7*wýÜEánÞ«ìÐ"¸/Î&ØC×ÅèR+Ò/R„/™„ºÚ\Œ+Û@á^Ò7cIèîœ}-ˆÁ¯cŽÃË$Š: ®ØUðnÖíФ«h¨ú¤C×BdWêNO•°rgn8çTË`ÖWe,J’ÄL>Þj œøüAù=¡ÐOÐû$Aó3Ï {’ {"ü{bï§Ÿ™É—i6áÍD@×ðàÈŽ˜=íÓSÏ É~ÏO"yÜûÑoìºí‹£ílÌôCø8sÑÜÊí€; Û—ðõL:‰´ 8î#S–í°1ØÈÐJeŽéhŸCNL|Ç_ˆî‹•{`‡<{6G©ß'!ã×e¸7lܳ@ÜõÛr ›³KÖ/â9ñ­p`1¥eù›X¥–MR ×0ñIt=ŸSmºµܹ·.Jæ˜]â„s_n% IÓ¹×^ jvÂr3¡« LC_-ôQÝn´$‘»ôP^h½å¤Rgxê+5Þìn®äJ?wÕ—Vß}ìȳ›È®¬Voo½vM~Þ0”eOÐÀ”çsË8!¬ó>Ÿ›RÍIPÅ—Ú}*d$gò… ;TDBÏ)xwÂM[" ž Õ¥†t@Q„Ôï©Ö­A`y§ÒJ] °ªbè©*¶Š§üaåÊ7eãÜï”WK¹ÌZ%ߺ†ñÆ~ I×Ì”ýïS³5Ǧl&bæ3>øRšÈZÆ?¯ë*#Œ5ñ ûðŒ¼ ¾S±y–ð\Âc䤸•¼¬“|ÿ›ÿ¸§rÿ×)Ò)çg’—³~(ŸžNì`ÞOþæÄ¹ƒïbêîÁ.¹&/‡ƒóÙ_KÙ.²Gš9ý?‰ËãÞ=€›žü—ü02ìIø[\m3ÛÉŽÎ=¡Ù@N vÎ’–NX§x— #Ïu ܵùÐÁwÖìÛîSÞ-\˜ØÚÑ¡°aø,ÞmÔ¦Î2ƒtŒ®Vc7‰ °NÙ¬C¸#ü¥²Ùo ŠÇ\ÍSë&hb¸} DvÙ^‘¥Í5 WWö!ƒìè&Æ'™ÜóÄr`œA —¦€¥´vqé÷¨0ﱊÕf— v¤9QÈ•ä2’3nĨ-µ;¿í÷ñÒm`ñFo“z¾E5>ß7sIB¹âÚIª«W÷ñeMcï¢Ø¿+”´¡Š€4Á?%½éµIuË8ìÝ3÷6ˆ¿ï£ßÜÿñoe¼(šÅ€û¤Ýݸ­SvúùðæáXw7äñ’„…÷ákv67©Ù=c~°÷cߊè>6ƒ;ZÄý’;ÓV*’]U;¥úzj óÖ0ÎtõÒàap÷e¡…yÃqjswýhq3’ºþ¿h¨2Œ ²;­–8J”.Ê®læl¹ƒé®ÃÖLƆª5{.Ú*Û ðHM“Jy d‚ &§–8~djpéÌGI|Öˆæ¤lOŽ’MŒœ{Õï§ë‰9wð´Ò2Áñöèߨv fhU˜R®¸Úã–Ü­å1tq5‡ü;­GðÌ”2¡žV¥"#Ò˜=`ôs—üm­Ð&i¹”:sLU¹2y-kt”ì?_©Ø>ÁÊ~eû8Ù··‚9U¼•™) l¨Ž¤x´±: ©;„{þ/mªä\äŒ[;jTÐw«ªõ;ƒÎH²Fòˆo¾r ¨&êˆÕú÷ñÓÊ}&e ‰êùZ/é(áðjrŒÝ-ÞÙ–`U• Î¢ìª:Á}tîÔï¹86x”lcwʺ„Mz—©BàZ¿3ÇÄI¸ì%M…ï®ß£,m䃠&¾_© ‹Ç ¶FUåI(çULBÚ$É èÜ÷~ä÷#ýúèÃφsO=ìÆFB†mì ëOÏOd?3Æ”Âç ŒÉ÷ ²;÷ê{3ˆÄϲs7"ÿkUc×<ÌH¦»¦`xïäßûL¶`ñޤæËtÏ?ñIØ&Vg{ Ûô½CÅp¾ǧÍï[<œ1ÐPà 39ôèEv¹0æf×pà9¼_^ŽjýÑKÙó>T-s° º(JppEÁÀtP—T pGÒ®P8‘ &žwa8w…„aµºJ+Aðõë¥{šgãSÌ”â íexpׯýšn5zX¹;¾$²gE<Õ}³Ð©‡€Ûd#mÌ;GÉ÷¾ˆ”¯´ îg'À·¸î+4òlÅè70v[Wµƒ÷ž"»³R¼ÔðKЧO^Ù±í뺉«;˜c/Ó Ø”-“…“ä ÍN»#x·’Oš! {–eoç¾]Á2Õ ûš"w>T9 ³'Ô\|J¡ÝCž®U —Zxc¥¶3}ÙÇü:%¡û²•WSW26 Äs‘f`yÎÌ€™Éu_Þ¢8rÎmŽsàà*oÍÅe;»¯Š†6&%3Z ù\OžB|ßG¿±÷£ß<ø‰ŸD-“Žè¨Ü£{Á"†5Üì~bÔØ÷jœ‡ãò˜2ì±)Žo„1cIÞozòÿ›»ÃJTëül·NLgútÕìÖ¦¶â¦Úoa™É?·@Ä£m&heÃÆÔ¹4K<6ñ?g7Ëöã.ÕÃÌUûá^½tŠw Ü ûð<óÜQÓ–;ï®9@ǘjH&0@v»©L\[³ï…p׿º+Üyœ]6DpãühkQ9ñ¬¼Øvª.¶cböËÀùt…¼ÀG8â€{®ƒììM¥°CäÎY(1ÀÝwöwâ:S´LtïÂ~|ï`zNJxI’έ‹ì¾Ì¹iãžX°iY,HvÈ$û÷$亯ómãÉõøPà}ƈ>‘ÝÁ@ ûæ¼ C±h€ønv_»ƒ|grXÆD75>ï¸ÿIpˆÄä!£L9Åtö`%'p˜a#âˆÙEbC-ã²=Š÷9àð&:*îüy#’ÄJT“™óc]¹:wˆB‘ä(vÁw:«$(À ¬­L¶U˜¦®Î꬞Ɔ&­´'¾ËÌ$XgÜÜfx¹L"!ß¡Y«³:bt˜D¢œ£~×YP&WIFHˆI¢C!€MLWÙ»(6¼Æšf´Yžî¥å ¸¯åÓ5$]“Jä…-ùד—•{ÀýÞ4TsôáçŽî!^(ÒçšÖ‘<:\c5ÌúÓ {$1º‰eñ®%y|ç÷~æm0ŸDîhù"’yÛ¿!Z¬ü•ùPØ™>ŒŠZFí£7NËvd¨ÜM `Ûu•౬¬&&¦£rì"ÍvêwÞ$rÝ¥©”íUF°•—ó9)ÆÔ®‡¬Vjòõ®NžSwµí »ãKsñ›<ïÖÓ9G)§râ:À‡±ê-FçYáV¶/Á³_{ªÌ~EvtîúÉÀ­/(oWš¶x‰Âd0p ¼8+ñÒÊâÞhÕ7Fúšº[U;§áWv†ßè÷$˜„rßpÛÆÎl®^½ÃÚIÔ„•òˆæŠº™È®ê¥gÿWð†ÓGU‘Ê yÇÉn‹ª%x§ïA²Õ¹8r–—ÏåSN+wnæÈ`Gà]ÑGÝxúË»j6Èl«l_ Užé¦îv d|Q4øfŒ+m/pJ¥î$병ÍŒ&ÀÈŠßR®Àq5ÈNä“™j}Ñ2ÕVE3CýÎ'<'t|UîX‘Ì¢/gr­flÜéž—ªñ’C3f[VŸýLÎà½Äœ°Ÿ5;'SN$TÇTÀf¨íÏ•¼””§r?pÏGå~æù±$«&½NÀÃäâÜj6æù ûû~ý=?Úû±oïºýŸö|äkïýÜeyXzpJž <¡ð‘ƃÄÔ-“^Ï ƒ®ÔÖ4ÿ’â;wÍÄ÷Zš:FÖþ¬œƒ™q^i `øŸ…™ÁQìRÈ Z†©\çò’Ê <~QCÂûQ¹/@笥©ä$«fçdpi?ÞaîM¥Ö™ä$eûÒAê*X/©ÌžÕ>Ž݇æ|‘9¸ZžãnÜ¢ÔÉ$q‘T $ ²3êȕѮK†@¯O½5ò ‹w;')Ë$WmÄ&¸7ŸŠŠTî²+ò®Ð˜<¹Å*öýn]uÓWñÔüÆmÞxÙx@€õ‡%O’³÷:O佡v¯¢}oD$ë†a™_`O‘)´û[-S†Ï2ë;Ö£V‚ÿÈ Á ´{+ÞW“}´U“ſӗßw5N5¤kb¨Üiñ—Úý‘ªVô™A-€½ïþœä®ÜCéç'øÎK7à$ÈÁwŸ]©Š‰˜>! ª ˆ`"Ñ'tÀ½ÚnOé#VšÄ‘ Rª£Ã›>ïîiš!-@gU¿n3‰JÑ4¨ßSêÂJSË'„{©mhz•­× ¸KÄçäÊîY¹§?üЯ?øL–„Ogk+Èž$ëý²*/û¡ÂÆ«”ÆúÓìýÖ®H?ö-èþY­+àIýñ’+ôÿd©îþk2l¾VìOÙŽ];7›Š}ÛÒ>‚ïh‘9ÖµöåiL¿ß#sJ9'BØäœ öšJ}ª|èw×ÂPI¨}Ü™Àp05¡^‚7¶Ãz ñÕÞTŠw{ªŠ gàY»°W-…¼}ÇÐ>vBª=ÉßGä:TÌ꣎Jn&ļSšHØÝµ1"Áäj¶c—Â=P9es‚”:O‚§#Àšû[8…l k6~ðѼ€¥'zñòý·õØ} ”j÷n.¼¹¾ONF!ÍFVß2¯KÓ£¤ŒÒ?î ûØzGž€&Ê'ÖÊ«ñ’e{4@N3龟‹€û `½¶î1ÍDñΨjŒåòá‰Ú=á(SñìëQwé6!]>¾MG(xgvcq2œ~°"ð³ás®š4g¬JèÌ;äŒÊª-8|þf>*w Á ŸöìÎ ¤Ýé©ÎÙ "S©ðŽþ*Ë" ß¹.KSú™IE++ˆœøžÈK –)só\_E}’å”[*É6x¥®‡‘úƒïÜoß÷pîckR*ôú#îæÈ>×û½pøä3ù²!Ù#Œ ²èK>ñS¤™ü)P1%ãÙ*Òëfƒf_#°äé%ä”[×r K®ó/°Z~=7_|?5¤GP1Ôél¯¹ÿò9ÑÆŸ&ñ.ÅQc k¶NaÓFæOrÔï5»ôx­lTá>g寙#%ȕζ»!Rp/¥@™ý¢„¹Àx6vL4T“èµWŸNW)ÞU!'êIšÕ©Ð2:…¬s cÂá†ïužZÕ£¢ ˆ\”ò…v‡9¨Ùö‰ŠIÀn VþRæÊLtÿ^!Äs€îT¹bÅ­–Ô܉­ÍMnbR»bÑ Ô ÷*+5ƒ×¦ømv÷p'TçÈÀ¬ß¥5Zÿ¶Ýîþ³®$5;ÿ ®:t`5ÉÌõhv”iDy»Û]Ù«³ªñï@y5Ôï3 =ë;ŠW{w”¹¼G©Ùs&\¦ZˆOiu j™bÞ%gòe\â±ÌæÖ)Þ§›˜²w½Ý'9óèÅY”]Â3DÙ ýÕYÄ]*Y$@€7$eûêËA¸s‚ò…ã]6#ÊwrF½¶Zx./'«£ù üÌ䣋ÊÙè-V5ãÈ`zbá~½ß÷|äë÷ýwÿ(¨=ÖsŸz1PžRâ=Ò—cÙà:Wý95V)Eò¸ïÎïïùè7Ò>=rúù‰ÚÍ׬{Å”ps$ä}ùo|ê2F`º§%Ñl9hVÜ)Øô¨³xGC` sÜç-ζ)“‰>œÌÝ$9 Öìµ.ýÕ¤pW TR1î`JIÃîR½Æ:Ž$e»“³NMdÙ@Nú…š·‚.T;þ}ÛqrE$Ã(¢K4óv/6ã©yI <Ü3©ÐÎÙÔÄÚ¥—ÓMŸ[ü0ø®Þ@/¨$®œJUtÎIëñÏ’õܼ„2!W"©1LëßòÝò÷jk_þÔ‘lèaÔîèLÖ·¾*’!ê÷Z».Ä_" ‡¼ÁpvøêG'ÊŠ ™Ì` ¡³àÞºÞ˜5oWó¾Ø7‚­®T­²½¬DÙ¡>¢z803sW#Ñ»šTKpOì‹™h°}Dß5¿©Ùm:©$““ñA˜r‰p_¶´{r¦³¥±ÙG|’}%€“yG?3ûo%ž¡¬¦Ü—©”3ĸ®8’2³¢ztˆ§Šg~ÕÕÏ! …?Xø”háWèXÿ.5/óiShï¾#{‘¾±ÿî¼ÿé#§ŸÜK4Žç_=zö•œ!Ù÷GO?Ÿù‚ì„Úûñï¥Ø¿î¶/žxìÿ8”²çûw'ž´uÙs†VÜùKñ7Zœ ö £ƒê~¥qr#tX‰úsI’ܒЇLçÙ>y‰E©ÚÈHµsë9õÓ‘‚uê »­x8=68bQ—XKõ0ë–ahf.Z¼K*²Z/~aÉ ÓÇKЩÌÊË)ìòpoŸKo4Qwœ˜,N&µL)}T?§ù8OáƒT{@{r6¦&ðý^Ë|¦¥ ˜0è\µ1€ ¦³ËR”§²,rÆÕz Énô&ÒVß Á•òe¦ d âD·ÐÁEúD3ÈUŠ–áó1ÁÊÿj¹¥c¨‚¯À-µâwè¦ÃÚØKÿ·I(ëú&"É×똌‰·S ¾éddfº'虄p玽˜îçc#DNr¦\å‘ F ´+ÒØ©;ïżM! ©ßm5d/M$†35ïÒî®;`°Ц‚ÖGƆ„tY)©ðþÝ\¬Šàá‘ ÜÁ÷”ó¨ÜçžVÛe€òtPqá†Õz»éKµÂ}@DMÖl™w M™û(H"¡!æõ‘,U P.óÞvÒ8|MQ(ãÝÉî§Q¹zðéÃ?{ôlŠô—ƒìGϾ”Ïë”óÙ×zðþ_^Ïç~¨¯]÷Á/ÇMžoL£¾÷鋾lsX¨9»×ÂøUx'[x7œl j ã°øžsêdœ6 r\‹æ¥qrÀ8˜Ž™3Ïg<œY³]:GRî¬ÀÙ\Òà—uy™Äj|gµ^~•jw/e;•Šë°÷ {ÙµS¼ëÒL°£ÃM–ïyøuåíNœ€àÅÆ<²D2ZþõO4ƒŠˆ)¬Üi¤rgòq¹†±g?AÏ©(ôj|‰B´<¥Ê溤E§à½fÅè*¾Í U£Xªû;w5NNÇ•¶Y\ûçõ;†P’®xéÌNoJÈôb\êÏvy¢Ilü |eÛ—íêqM"øÁ¶sï告!¦µ„ÏM‰m+ÓZ¸å@3Ê9y‹0Í„t•³Xعé|I{™ðƒÊr÷ÚVÅŠ aåž³Ì#/"Ã…Z&I×ðØK•´Å¿ó L2?fÀ: ©2a8N*w´’Ð2pñ.áÃúµ‘3I>ìxŠ9)Óê÷‚'–h뀔Å;ÈN À†™ yæ3©sõøHÒYšŠ·ú,’$¸Nt•ûG¾qý'~pO³ôèé€ûK)؃òGÉþlöq¸÷ûïüaöüíúÐ?eàÍŸ¹à½„oÎ7ܸB3@*Æ_ʃ?9‘—ء׹¥¹U“5þ• Ú»’ÕŒ;©T¾íí)J6f4N&js{¦›ZöýËã6‘;°®¤‡mÎÏÞ/9Ò[}+.k_çQi¥–¼=ofwt$e;I¾_ªsÆÀw¤ ”êz:1%žbktÅò©¼rAÇY¢¬]Å£@lÜÙŸ 1‹pŽ­]ò}\…guD’ 5nç@-ƒâCÂà úm®±â›SDZÍ4;ÅÞƒUÿÒËnI¹b›pÌ7UZ/ncWsT÷¸ÁXóKýVÓ5öW‹ù“²4|?OÉHÝÍäÞ“lEQ?¬—³¾šÈx1>ø¬âùÙˇ€â½’ò™A3ƒ´šÈ%§E ™ë-”W<³µ»£Öì!öÐ(g°—ÑŠµ»³ÚA}½*~{03{< œSå“éz&Š÷!‹l»³•½®Zyk ÊwÎOp¤Å ¬S¹'ÑFœÖaEð™ÖúC¿&WQjƒï–ðm„°›yS6#W’1 FG?CXË ²íeÔ2Üï´Lú¥GμH~øùò ²ÿlßÝ?Üó±o¯ù¦ŠßM>y5H?=]qxÉO;9èz§î¹Ü<©h #¸cÞ'“žÝr>'û’Ç\fR‰Ê= £Å2É‘Ý ÖòPÛMÈ$F¸›Ù¥Y&² £ÉÛçÈRp I;†äKë‚ÛŒä,þ¤ï>êÛMÛÀ&á†&k­ºdcܲ݉ñ AЏJ”ZF:ßz\d÷[7§`r,’4qd/ÒÛl•›¿˜7(5ür8Záä—nõ¸‹¢†ÄG?Q»;r²ö09¾ûØÿb ¦óNñŽ^J< ©Æò]"Á²ž*„ ë;¦“Ð)bŽiæó!´¶‹©yÇ7}>Ò:Æ=ÂM“!.£Œ„–Y3&£¢Ç£¬ŸÊå ñSä¾SÈ£‡slÕUW5Q #f²äwì×omÕ ø'/mÙZ­åŸ(Ìä­ú°ÔÅåœR>‰¤õ;4·ÍU\\’ì¼}TîûîùÑî¿Iµžú=Ȭ²G³ûÃÃWàÀ¿ò÷’`ãÖ¤I+ÀÝ díA]£Iü-\…:é©’€é,Dõ)g™æcú¨];÷Qî¬,A<¾ª0€ìÎq•d‡™§eº¦¡Üï/‡š»/ ì. ßiïóÔ¸jv+÷,|¿Pl;5JéÁì--6¦M¥Ú\% Üñó@Uœœõ8nÈ)dŸºŸ§Õ~ |çS\#,çV@ÉŽ*^a…{Sk½ON$íU ,úƒéoî,–(`LM܈eÊgñ]zÄF¨ò˜uÏ¿ðD ¹¨l»2Ų]Ò›ðvºfW)橲×ÊS°Û?FÈîõ5ß·`ÍcÀz¼»öæƒN“9Õ÷¬•{‰ÒÙÓÐAŒà%‘»nw7&‰'Ü_ÁÊŽ¦y߾ܰpuK0½ìÝ×zÆÄz3é-3óüç©¢Ñg&¿$óÎÖ=&L•ímw‡&ÀÄÚ;Íá=Q:\”ï‹1„sw  þ}ê#õN!?»©(#ç*aV¡Ýsò)¢h²PÂÓ#g@ç—f¾%‹Äþ .•BÃwJ¶œëÃE{ÙgyÝÞAù| “«šG"ÕX² ´z#Ö'JÎ>çæ Ó<XyÚÁKR»¨Oe!D<'ºËg mi“ {h÷P.×gèô¾_^ï/ƒòû?ñ“=ûî¬Ù¿tÓÿ‚mA›bg‚²‚ѯ8ÈÞ~X#ÛÂéöK»µ=~™9Aó$zùòp“ cå ÕzLìc·þvþËtôõ,î…&¹‹YàdÜ¢ç~TžçfðrµR×X/õ¾Kµó2E‰~2¼{)MP‚ñ £æ$|6Pí!d@ó¶zžšÖÉÕ"Ï#œLso½´ü ×kõ’.R:Aâä² {ùýÂÏèÙXŸ`zÜP?ôxZûJ‹wÈ.W?Ó[’ºØõxù]o‡eò æ£+·Ù&µìߨޤfÆuzÍçý*S›«¬"½bÇ•SÙL¯ýÇ=pÞß¼mŒX+™rj¦L°r/'öîe÷sªîÃ[ë;r½Ä‘*¢Æ‰ÎÚÂ_Ð^¤Š‡–©Zd‡þ›&ï”}wÌû•Ní#‰ñ|ê;~_Á;à^ÄekUiÌâ›É£Ks¦Ir¯mÇšÀôc9Vºj*(PÁ‡a4@µ'Ä‹ê²Î±UÍßñzjä PNå>c¬Õ¿Z¿Æ2kk…4å;6¡”4Õ0í)¢Ö‹±]LìüÐWwÝñÕÝûîþ{~¼ïîŸ†Š¡}š‹×Ýö•›>õ&ÈŽ˜¤ÎÙz¹òþ0#´íínŽ$DR ”ž¿“¨9»q¦ÂIv“ØÅ Œá%¥z^ò/¬žU¨`wYƒ9²°|}¹m˶s›‡“¡„ß©ß)Ûy­'?ÊöK}^É\žÝ7'çZN0\ÀFÙîH¶œ;UNòeé.²ã®Ú—ês­¯Lâe˽}œ\ä£Ú< ×ì6î´ÙNÏn*<ÌD4ÓTÚüÂÉH¸w×D‚B€¯Ü·@´T?c½Kn•íu(õö#]AJlÁ+yTHãlð?Ü!¸ç¹¹óÚ»P§T¦÷”"|¿RĦÿbxèô𦪽Ký!ˆ¼Ù` З¥rò“e²ì™-ï\JÃjÆ­Èf ßñÞ1`='~fé¬â6“DÛhïy rú]K~/“€æîVU9L± Ŭ€”½«œqIÓò¦8N0@¨É;ÁÞËX…¸Š/g[Õ4‚©êßÁ[¬#fOÙèòU ß a¨û‹]µœO×”j´r²”$pYh+Ö“wøUÔÃÎóRÚäºÛþqÇ¿¼ëöod:)äL ö]þF`=ýÍŸ}ë ®¼t8àûlŠrÖš'iEs¹#—lTƒÁ¡Sn`“„¾SÛÆÁúEˬº„JÇEƒÜYîUqä/÷p_ •IÖéyS§~‡d§ßN‡†Q8øt[©É¯x›9f‘¼—íO úbsdazÉ-ÛyZuƒüÚ¥§Wöî„N|Φ¼ŸKP¶×òKÝÛ;-ƒ°=ÚÇœ.\KLg.×0æQi¨‚tSRs¤Ã4EÇÚxª’Å $}Y){îÀ1ªxÜÞ“ˆ¢–¿”‹ßs„h©!AgGÚ¯ºþ©Ô2ƒ â7¸œZW„“W™À÷7igßÖDÂOæOLÒyvòî@é7áìNö6`—ûÚu;]ïü7`53X³\‡sOÀ¹ë¹Ì%Š™‚‡•˯>ô:7ÿ꬞®QU ÆE·îÕîl ÁZúUO—„”¢=ÕDà>SÚ<^oñÎ*Ö’©*s·ªëUûb3gÝÃǼ8ÌŒÏÚÁw*5|Ï™èNR„* 盜{ÔðˆY²™¢ƒ§×Øe‰êt8‡¼\€Þ Øê(Ò]Ýë$¾‹¤úÂÏ×ÜÒ#ʃ3Ïûÿa×í_ ¦XÿÐWw|ðK»?úmuô9 ö.Ι9׫Mª½å²âݳº &*9ÜÔ8Ù€*ÏÎp";ÂöI¯CÈðlT¬‹aºƒ%¸.Sÿ_ðì÷r»©ºC/¯v¥úH¬ûÏÓÒÏz2œ¶coœÚ ¸;hŽr Óv=§EO.úaáawí³(“LNN†ú'霔íz„ñ8~ÍÉ7F­¦õsL­È JëÈÛat1ªB©dã²ÁðôT‡B¥Lˆ¼\·ËØKl¹ |™m+tÆ|Öaðm«¹­Ú^:wþ<Ïèâ5ßW=»¾êF4Š—Ùù%>~˜ä —ù\T%Šöˆó/Û¨ÿ *#1rÓpû_”3Ü®ù¯íÌ —„zX½)ؽwï M «‹`ÜPO‘Ì4Ñî¯óÌx7Op¯òD§¤œ{N}€ù`$\Ï”D©û¾|~ÜwÃÅÇ.ú¤ìpÅWMÃM”í ŸÍ Q7`V¯Ù\ëÁ \¨GfñUFºy€ŽË"ªŸV×7Ã3°Ù >@Ÿ¢fc÷ÈHÀDMƒyI9ß+wòj`ñ!gàåê_û¿þfǾ”ú=zÇ÷üï¿ÝwÏO)Ø!Í-ÆI(ÛÙU½Vßñ§óá†ex\\?$e;d JzÈŸªÓ%y 8jÑêC¸ÅßMú¨«}*Ï^žp2ËÑ7¹{qµ”à† ÏÖÿ£Ùš@Ë.Ž èTî ù%«ÇPåd`Û#åJÎ3%­TˆDB… {\Ù9™DÅ Œ!&˜™‘ €¤l_ÊcèGR‘B2CžÓu©2‹yU<œÌöõ©wA[ÀXw7'³K8V%p’Á ’ö€®x$ìè, Zéò5Êä[®6€ìþ0l< Õ¡Ù¯H’™Ñ[Xêp UozÓ^o¿M¦©ˆ”^õK*™s½YBõd_íwð7’»5»ºPð½ÎÀ˜ìXµ¶ùo{ˆ/|OÂEÄ3Û×ýœf “#¡­ÊxÛÀî*Ûsnø h¾à»ŽE€;šHXšÑM¥ É9ßÄ,V…¨‘pdlÕ5ÁБ,©œÙ*ÞµQUI<±¶Uaá—ëÓr‘Lò¸%¼é}ãd–¿cú€Äs½ØÞå.ë~>ð= •€CH"9“P¾MB… X †ïU…Ûk%ɯÒqÅiƒIJøänå&Ùþ¾¿»æ|îÚÿù×Ûÿ×ß\óß?{ðäs·ÔW¶êÛu([>M;"èrÎ5{‚ÄŸ§»¡õŒæÎ»T1Nã¯ÿÉ·(Õ‘®'Ñ@F@·KAkìΠÂÉðïO0Œj|`L{rIÚ×Âë^°Ap‰g;*€ëcLi$ôQõK.hKß]K[„ 5;'–¾½›CjN vÊñT÷ Ü¥±l/dçz®³w…ÊÝØã%¥ºm¶¶1asì*/P¸'\Áo+ZYGM´ŽdeC§Øm~å-_ÂLɃœ|AyÄó”à¹Á¢Ëuó•XºoóçP¬£N^ŠÇÛ~›ÒNÁZ[!£w''W7745wߦټ…ô¹'¦¢vŸÿ¾ÍágbLCՓ↠7aÍ úV)šÄ¬Ü9}¸sO:æÑõör‰ÇšibŸ€>bØÿ®Ï¾¬Ã{Î*Ძ‰ä¤~¯hŸ(ëtEi\A!A‚u—vVg,çS[3«Øyã:R(ßuÜ‚ãÔïHàQÎ@¨¹ÎE- š^>§.4$ýUWôÁf4sŠò8È+¿úÉËÔË3è¯ý_ŸçzâÝÿí©wý—§ŽœûgäçÜ ˜œ’ðÁÒ ¬ß |´´ìª,ø]ÕKð\%¹vùÄ0ãzqVÊŠh–n-%ç 1L5®Çï©hØâÕ¾xüR!C[¥&×pô]‹vac´k?4ët¬èÀtßW&Ð/lËsÕU‘9—õ#1I}6•ÌË$~(zXg–³Oì”ðÄr²1Ôã®KcAˆÖdÛ̯P½Y³—ª=œíë9KyA²žø-Þk?³Â$‹0Xß‹Î+8Œ>JêJ"‹z»‰Àº ' Ÿ¡dC`à»óäÀr³_|/všiÕºŒOðDÎÝö®(¯mq×;ö^«¢nzë\½‘#!‚ûGl“©ïñÎY­´šÁVìdý'ÁÌŒôÙàAœ°Î-†jvqÊŸ)¢& »÷BÎPÂ7¯¢IÑœ"™Dlê@v‡›¾egyBÁ‚0äŒMÉ"ÇKh™¼<½A3`˜‰ õŽwöÿåÉãý‹6;Ò;ì¤foßgä`½àîiåŽI/EzŠ©k`´àÙåØ˜ðRì8vžàÜ«X¹;¬j†=/áÄ”¥ºíÚ>ê°{ä¿po†BhÛ‘KñІïí¯/ƒ§ ¨?,’«Š©7¤ŽíìœÙ’?Ò8Í´GNVÃSÍ8ʧ MT4fËÔ×5g`ú`q €Ùåß©°zÐëä;%<Ÿ`€åè¬ßGñ#iÅûÈ!jÊíÅ»\|^ƒHÃÃÒŒ“ˆçœ`—ÄE¬j½ Hj oJ]ÿ”wNu) Ù’äïüÏO¼ã?~>9 þa àNœiÎ^_¬Em;[äÙñ¢Ùΰ·Nß0ÉQܲlƒŠ!aù5õžÕNäío{Çä!yTeÔc’0«‰Ê'LOÒÙöåÖ§ÅøMJÙÎGÕe™Â:ÂÀ}ŠÜw$ÑÅÖWìŽ/ét’ó³Üžq…µ ¹/xñöf±ðrWiœ6[¦7¶R[ïzr'0ï.c÷u)¥Êym 6¸rŸ dá{å~µñMxz…‹\élí4È©>e$LÀºŸ1ÈwÈ™}ç/ë¬Î¡'æÎÕ\t™}­·œUÈãtaS’ <õ{¼àn!É^'hbjy¶z¶t ¿àgˆ‚¼ÖcÄ]Ré7§Òx6À¥ýFQ/‘²ýý_Ìɲ:¯“x@e/å"Í ó(5)Ìû¦$ž3’÷‰\Îj×ý¬¾=Œ °Ž—Cp ÇW¾ ú‹ÛgYýp[% d¸ïŽ‚Ýÿ²-+²× 9e;Ñ÷v­¥âñØ|Ý-%w»úÞG yG2×S©tpÇ›VªÃÛùh jw´[§&§–°n糆»/£'å˽FRãæË®Ô’v ~yXGÛžÀ& dH¢å€¿Áh÷„ ËœK'#vW«á¡O¯˜Þi¿Or‡ŠÄ=XÞª¿ƒª^ë:ÈodÅq¾¢ÿ|†šH“Þt•±qâ´ûý:a¥ã¥· ï<ÝS›xo-ÈfŒõL¸@ ^ ¬ûÀeñN %åÜU%щ7ê÷¼oR) u¯ÚaMR$ØÅž!º2&M0…aU2 ’1/ âçË„Êù@ü‹êß5œÉ)ù>ê÷‚ò­¹A‘ÓOl­õ(O‚2æ¦r‡er•µ|%ˆ¦xG(͹j'²œo <æ3É™@|ìÊ3^-þVÏV"ЗÉLé…ø ó7ó^8ÓwM“ÈÝy¸KªNÈ\ß2|é3yŸ£vŸ›þ"ìÝqî•­Ö¡éJ¯>åpÒª8AÿȃˆÙK®.ƒ$ñ]³ ÖƒxÍ ¨Ê곺gEO¿ê›"â]YãÜŸ9¸îõY…ì3¸Ð„ ð½¶|ø÷Ys,©ò!>íÜp8sW|.>»‚ªrJºÊ%šûÀ½>EÑX#pŠ”s"Ëí`¶´}ƒ~òÄʦ’åÌ:Ž%¿—IôÀMÂtî±°î×ÎÞ¹ÊDZ>#Ã䪓ÄïùÕp'Ãþi‚zˆõožŽÿŸ¯Ò§ÏH暶SßÕˆÃãŒU ‡ëóò#…j¬v¢õ¯uÑ“(J!cvm*xw“Rps[`ûàû/.y•¤¢Ú»˜]ŠËúêdf>IÔ:©Õ›ž=Ëœ¢g©æ(d÷г ÛîÃút3œÜL†ys¯šž¨›¸Êz±2d¿[6*nc²cåíQ€ÿ"‹¾´2hf²{ÆÕÞ{YÕ´q™LÚRyÕþœæøú}óÉ]XÿYéþ~'ÔLél,Mñ;“wy’Ý{ï/¯0–F&=r†ÍÐÕÏ gèg\ úW•ä׬‹8ˆÕXàåû•EçI¤<ßK¨zÅ«µã9?7?UÝ•5E€Â÷ºi—bue‘ªæãð'~¿›*SdQÍÙ"ßi0f”Çûôí{æìMPðg p?c­Jêg‹Ø6#²VÌXç…ÉÖaîjßGÿSªÄ¢ÄàÛa¹3ß; ÿеCùú%•&=]”ÌM ûl‘)ÍÖQüUo‹[#Vudßbö—$æü"Ð|F'f¡ºyF霌æ0Ýߣø ž×ì|³0Š“ÙQ13óõVÈä{êª4¶]ÀNûHÕþ"÷JRˆ;šDK.‘Õ—Ì8©f{ò¶¯É'Ö6YÿS¸TÿëgqÙJ#+IE̱ ÀÁP"6‚›ºÍZg"V”·úâÖ š§¨õl|›ïv3€}µQõ¢½Ÿ/Õ£n]NzšM!å¹Yx_¢þ|bÆKò®2ÈÐ_—Ø”Ã8|œö!߃øÔ×ÝiÆÅôR¯5Ÿ;3ß(\h_‰IÚ»e³= ^f6âX>,׺»¡\èÐÿ& œ>B  Å鳞³WêuQ9X/Z?òߨÁz˜Aêý8q2gW”D«ªíÆ(YCö˪í°ýï«Oï/Îý3ó¤^0xËèqFýóŒÂˆÕ/L{wN2õWB²#ÜW>‰BLÀ>7ñìKþx}U¹3¥=»‡Õ· ·£~=ݯJCÂåå2çÐF´>Ö®‡RØÎªäÄìBuÕªÈÖí#Ù mGë-±­7 ž™Šía)YËŒMʇ™!aÏcØRk½à>=²Þ5Áâºß&_öÍ>æäÕŒu?¸aûËÚÆ:ù|ð½=*±HÈìó9™|§Í…ï|–Eî3û…®/¶Ý¯øsÑúÁt³!¹Z ® >‡Èô33 {5Ï_í³'3ÊwW”Ôî$’â”LMç¦FïX•{s0H¥¢k@ü9øw%ݲXð¸x¯¾+ o8oAÅ||º ÞÏ¢ Dxò­‡ `}@$g³±Û9E/ÌŒŽ·QëžÎ¼Ýá‹mSƒõ ôc?X'æ`SÀ¾ãnòù[Iô:„õ6ÚgÖ½f0}”V…ä½AöZËÀ=㬉Ö'0Wt Ó Òç&÷©8]åÁ³ÞUÖ`ÿ96¦†yHöŠÔ y Q«n[‰SÈ~XõoõaÜ j^íâ %©\N·ëg0õ}‚´ ¦ñ+E9>ÎâWß|G\0ãi›‡–™ÀèP4èÍÁq&¬3Dzqéü‹1Ñ`§ÀKž¬ÌYl»ÔÚ$NŸ.·Þ,°1.ë1ï×™êæä„ípoÂä?*¯ _hi|ͺT*ô£~ÉRæÝ-o1øŸú€uñ{Š•u iáIzZküÏ<üK×÷)œ5 çß¼¹ÝÌõ\b÷¼=dÃúnÿš{}hNÏî=ñ]Fš¥žÓžgXø~†Zƒ9ëºÂryu“ã~NÛoöõžØg†ûÕ;H«âgžÅï¾wø™o·õ¬Äò¹»ºÔM933û°¬ï »"½]ÐôO ræ#ˆ”¶úÔŒÌìH»™®{ÆÉìV«fˆ_sÉbº™)(Šûæ^Q|Q¡¸~ÐY;Iµà=ÿLÀ:>˜…>þt†|ÿÎkøAÃ*ïfAÉ!7àuî+EôÖâÞû ¨Kr&BÏá†ù¬¡9°îäQ[j‹Î.†·ä Ûb§ÏÀ¡‹Ð3üôÛ+¿ÖWbsÑúõ͆Ýß(†ýY<©”ÃÀm+ _Å 5ß8€>[êô’‹oÜK[ŽXrÛlŽ>$»P}÷‰fìž×—‡ù$Q¶+ê&=¨ÇÌ`Ú¾ÏÀÆhm¶ÿå_ý±NÈ5Á©ŸgH'sB=WíWø¸ ~™>> k(o,ÑvÄ0ŒE1âÖ7 †ãÜÄâÀƒDx  Ï·l&|N—Ø—I×j½zEÜä.½¤§‹Æ‰Î™*ô¾·u{~“ÎÿíÞiЈ®YoÆQ¹ï«ßê'_¢¡|âçù)N;³º†Oô³ žrÖ7lŸÑâo®Wѱîr>S|G9Síþ»÷:ôÌÖ€3?œ{ýàgì&ñìô$©tö`És¦àýßQûð3š{ O;hcf¶ô ô˶ á¹€xC?sU’³ñHîÅC%UNÏü‘Æ#åwŽÅaáQýeá3þï( ' ¤<ð=ë8œÝNÈfÞ²³µ›ÐŸªQͤUÙhv”Ó å®n¦è÷Zbö»Õî.½ÏHGTN¢oCº|©/³ÜéQ7^d¯½õ¦ÚUœJŸXeÔŸ:g—ZŸ¹’¥‚€+®ýë¢eDëÿúóO ½œ$ö'sÍ’´[WÀÁc b¥™‹l𓵠¾éÓÙ.<èü ¡ùãGC«æ 5 Øë£éè?l{|úAù¨ÚÙ¨vé¦O?í–>N$y/³A¿*7~•A,#Ö‡¼@†·Ý›X'€Kl…j³â¤x¿Étî/‘{Dü¢Sú KØÞuGg›•jèI<üÕài™AöŽïÇ^ĵìhÞ)é|žEiÕSÜtÛwÌ(m2í~}à>úVMVáõΦ£`šæfš&œÇô!ßégªVh Ýg —PEÎþß3²9ůTIã ü#›ùQ¸$~×a÷lŠ‚/#¡9½œ”8mˆO?7á;Ü¿Ñ_âè¡ *ÀbÐYŒ¹²|³hp§Y­‚ò †n黣)–@~Ö È²H¬ä'ƚϖôòpù)ë‡é‹º)ÉÓÍ¡v ô£}ô–Ú4úˆÍz‚z*õÔ>c>_EuÅK‰4߆¯qÎŽå®w°l@7ã^bcnW–Õ§E}ƒYqÃ,v%Ä TÌnËW#0°þ¯¾­×Bïþ¥ýŠÛå–>Â0^¾7/)uýd–AX¾Í‚JT×ÊöÙ®Ç2øåå;ëhwƒqØ×]:£–>3 „à¦+wOլ®|¾0Sè/Ä.ÜŽo¨Ð´H:ÅÈopOOX#ëô3îÚÏÙ)Ä¢gØHþØxÆÎ^5Úý•SÓ>á«áuxÖ¡ÿ‡fêdõ6›ìä¶¡¿v¦7I{¶)›qS§$u6æFP‡Õ|Þñ3%͋ܵXL{Õ²g Ê×uÍ÷›ÃýmVMø8ÌMÍI+·;Î3 ÖU3ÕÓÃ`0WÖÉÞ`×ЃyäÆwˆÏ¢ ç÷UådÊáarô΢`K$ua-ND ä<ót„˜›iià»Ål©uk1ÍÐFàsI¾èå?7¨/ÌŸ¦Ge¿Ï EâÿÝl?KÀ-J\?w:´çUÿo‡+?ð}iŸ"ô™?¾iõH°;]Yè>¯¨œ¯Çh÷ü¥^wâ¤Pbè8?Öß}Ýv~—[ê‡Ó­å£¹Ó;—7 ÛW‡/1»ûWu »ÂiTÌlabZ¢È蕺¯kÓ+(pýúiÁaL ³"¡- ’03 dGŒ@‚uWÒ_g¸¼NÊÜ%8p§~iwJ¹|/¸R7BæÆ”ðþ˜nŒz×£>;Ï̼ “]¬#¿-|#'úÄï¥R·`&Ÿ®mÓ~F˜g–L§ {éÐíº8l#»iÿ-±|ëó{g¯ÖN¶T¡úI1—ö}·Éö½7‰ðy¾•Mg·T¸ï¹ògåüI®šýEræ üpy÷ê/¾`†ðaið3gq9™S¼zˆE5ôï3ò|Ÿ¡[Óoç!¿ÿ/ â$]í~â#ÌÌM´JmÁwQ¼Ê¦ù×?0'ÐÐcXš¥¹ÊH2‰ËÉ îxˆø\Ô‹ÿíßþ?#6¼^—«yäwK 3g{Ž’”µv‚kƒYå? Ø™)M¡.é$°þèm%èÛIñ3×3„¹ 奻Î'•άã¯') ºô‹N$Àú?W;ê"#Lu[.PV? v1«â´áügÞ—AT1ÿ{§ÒgKE ƒà˜÷z(fÈî|èµ”¯Ë1Æïž˜}æk&ú‰ÓËÏ× ,V\Óm¦‚;ÞçØhžçíò3‹„ÂD2ôÄJRçx™¬©Êpü'÷r‘¯¡A¦Jòej—4ÄŸ-Žhí.›jnv ¦«#Ç…Ž3ƒuf'2«, ¦ÓDÞ¾ mëÑd»×žÚÁ`€Öˆ…nÁ^Øùc)×ßm0¶²ÙKvsÊŸìýr®±¬í\@ y½ãÁ¥•·Iävñ±dñKgÙsJÆzu™ÕyžÚw<>ÀÿËïu¹ÍGlh¸Úk•rAÊŸâ¦KÛÍpYÇðEÀ «>M¹ÓEÎ…¤kÌÆuD2¯F‘U®fû®wðs³j¦(xéÓYÔò¾ügÔ…ãßw–¬š”íR õvø^ª-–†8z€{Fýµ-03.3 ~ _Œ&ÆÈÏP³f<2®Æ ßA¿xó33ôÌÄŠë«}¥­¬T*¤ÚÛ¸°»ò½¹‰\w٘뙓Mðý2 €ÉÝ~FMM…íè‰eg¸dEÙ ¡×ÏVõåìÈÜqIbœk_J3?À Öû­“ÇhðR1sŨ(ÞY} Pó+½2öoŸ»0)¶—/6²?‹zÊ Û™f‹„ž¹f ägqœí޾c9ç¦C²C5Â;Ø ¢8aœ.©ñìsdáRzh¡‡sŸQ e}±u›!ý›u yß)É2‹ïЧýðÈÂ÷1Þ½¢þw2£pÛÆ/?µ+FnNôšßéÚ=ÖY(¦ik?ÿìÅHɇWÛ&s'ƒÈœ¡ºìÉöù®Ä ‚Uü Áûð3øwiŠ˜âßgñŠWU@„õ"úH¶ª'2$˜ùŒYriæ‹vÏËt™"-å{=ùHh6E“vú“%d ¬ÐÉA8”hvÕ7UyÖa}BšÚëLxŽ“+f6¼¸‹­¢ùÿÞE\üÄïèJà?¤MT2øÅCüYl¾bÆ4xzæÅËßìbt $ý »nv¯TíÀúìö°4Фf ?±¾UÇ}×éav¸Aö̯s‰³Ke“»8EYؘ…@$ÕÅôÕËj³çVb¸ê’|ÿϘ… ¬åFÉ®gKÛÃ÷¤Sê™SÅT Ǩý0~Ê””¡~L2¬-†^¯Ûu„Ì,°ê”¾(G®×ÊÐ à^;3Y«9¾GŽ©_žCL¨>³ðg¿ûîvY³³zÔÛ…#pzé}'Œd°cb¥OgKB»œdpTí3ZXT¡bSØ(Mh¼``îN¢î€‘ä1eÌ^âeA>×B#$¿öAvŽ]2¼9 {¢»e_Sl7öŇþé{|ì§G6F=îR¹i‘çLN¿6–NãÙÆkùÍñW6³®¹²¡‰,¹š@jþ ŠÙjâAV5k‹™]º0D¿¿"wÎb³>Y~¡Ç‡œ¹IϬWäŒÄ3‚'GŽÎÌ#%W±œ‚w†MÏ–ooØnÄÂWè¦3q-”“RËy4„ù"Ç¡x ®ZVà~¶„_ ëõ”òò‡Ö‚ú« "Ã÷ÕL.½ 7pô÷Öð}f̉á>@?gNôË3ýÿûuæ¶x¶Ù8O’ŠqF¥¤%EmA¿äÄP‚tf°^†9-i lSÉdTw*³}Í¿ø;^=ŒyŸƒá8LŸ±êNEèë¢ G'w Çë@ˆ5s‚ôì™ÿv­É~Û¹ã$j:™´1þÿËô‘éÞ‰Ög\K¾` ÂQsÙöl”,Í¨íµ &Ooî`ó<}b¾XÁoÚàdfŒá)¸«.ç…B!Ø+sñ¡ ·P0à®î©Ìê~fù«‡Ÿnû¬ðÅ«†³Ô—¶–&0½0ý¶5¸»UD›ß]é)¶»÷uåòòÜ1ûœéó{Û4ïâwßãó#ÍÏ6ëeÐ)±›õ ¦K»mò_YVc´nÙ”C ôÝ„ï¢p´èÃ÷JœfN‡¢Ù&'åWSLZ_ºÙúÌ¢ûÊvÊF+Ln†Å©Svº\\‹rá¾*ª×쌒0vÛbìwb»&õ‹å³ðY;7‹ß?_ˆ9IÌl¿J˜­Gz:(Óg_5w ºÕbö#mÌ1fÖq2ýÐ[ c]¦½V×Ò9ú;Bó’¨Ýt¹z»Ã÷Œ|ÿ¾…í#d¹‹ÙáûÂv¦ªHöמïTí·×’ÂTÐŽA~!S{8ÇRæ ²‹Ø4O6ôZú -–ZœÈýIȱ{Ô—ž¤j_šÅúPç‹þR¾š©èòˆå÷Î@l“ØÑAënÇ 3‹ž7±áÝîSÂ;"RbWrwqó] µnö\Ö›‘— ð{†%ây ÛäT8°<ïß/átâbÊðSádfá7Ž|ßnAÅïNòaîf®ÔmF 9zMVEüŒÌ eM3ÀúõB’PÝ-€?ÿþ$’ê>„U9E¾ÇÏþõYïüjý=p5BøM§®ºD‡7ó™6Þ²_.~¶(ŠYZø³ ëwA… ŒfQûˆÕ—uPL”ZÐúɸBÀK3Ë=‚TI×W–Ç]=bgù)žEÝ_ïÎ÷j  gYйÙp©áÉB,·ìÎÜF9åó^¤ß'7»yvªÍõ¥l3á ë¾YS˘á{lZ²¿è–F©HvùfÙg ²sЍÉST“uâHÁ÷ù_VJ';D™95ˆ/§„Ÿ)ÀaQ°ûÏÜñ3i«”33o] ò7úñSU¸É™ao~œ-®ÊìLE°4Xx5PðKã2ß:d¹éÖÓñ£ä^Å“³ª í›#—gœõôïü§øhy×-™7ƒþ«·P/nÇ€‘EÓÖè`z]<ón‹“Þyâ6¥êUnTîRãO)‚MdŽà»K–†SÖ³&72lœÓ¤oõO±í1cµ?­ K-/ÐË‘ÒD‰Ók¥´¹„Ìl×J)÷˜üÙ¥v&½_ÝÌ*•j›§ ‡ÿªŒÑoNî'ƒ{Ôd˜c»Pã#õÁÜóXÕÕò‘ÇP;¾ð¢Cµkº@¸¬6åSd~©˜¸Ö|Á0±!{8@!+ôâ¨(²PM{Üí¡_õ‡®‘ šª!L-sùŸwMh0ظOÛ #þçˆãÜc‘ÒK: EÛïâÕÝm£Ø¶ç ¼]æ²àÕŒj{ÏH=¾{Qw½¸õ À6×_¯©È²¹ ÜEîª2«ÎágèÀòõÊ"?1¾nMJ–¥ãÑ2ª$¦ÜYZÕ?3p¯rU{~FL¨ëç?­´úfÆÝ"p¿mù¾­¸é ç¡6ó™ƒæu”?Š4Ì̙ѣâwü)ºFçÕ®¾éd áy½÷%`ó1†ý´É§¨ ßÅX`ršá `}ÁõšíbU+=ù™ë7¦[T®ÄÃ}Á~Pk;t.¸î|`ÏQü¹¥Ë $^|æÆz­YüÔQÇ¥†ÑÄxGxÞgÌg ˆ÷…•›ÆqÍà(PÊt×ÙQ2ü&N¶æŒùe¿ý1ò ¸w.¿:¿ ÙøÙ¨áÆß|e3àT»G)ýâ‰ú¤ŠéG s÷oÿ GßOϼùÏS0þzs\šÅÑ¡sÞF`¾“-”ÙR˜:ÅJD2ŽÇ„í?[ͯ¶3÷.Œ;÷®.z³ØÈn¼„ÜC³xéÒ„í&Ò/Ø}KbÂ⣒Vrë·üäÕà©}2@;ÎÃÍ/žw“ô!©:Ãì—‰‘7{ÒAv5²?u¼ì±^H‰mW"»»`—?qî(þ­êC6»—Å*f V3¾}oU$Þm~ÝÿðxÓKÁ÷ú4ɲºÐËgNà°XšR=·Õª?(ÃR/—œyc»Ì’˜¸sËK9ã:×16ƒE ¾HJZõ'3ÖH±Œ$aýrŽ\ÁQ7YÆÅÏz¸Ãwî%؃<& ( B0òt“ÁýŒÔ“ƒ}9¨Ì"éHþ*w· ¼ž®ÅË· ú`·`üÙ’¬åâû"ú=§Ñ“lù¹R[;‹Ôxö¼Ûø[fìZ$BõÙß7P»«Îy³¸¥InBó°_kOÙ˜¶ÏŒc‰[ ë‡~±¾“®÷0ÀzÚÇR8(>™Rûî‰JÏn#•— ê,îØUéÇ.¸ç‰M·ÎcvÏ $ž¡^É1%`ŸÙ3ÑZî`Åì©PȰû¾ïŸ£›f#Gߣ¿È®ÝbQÄy Þ5”£/:!ؼ®“t2¾ß#UDÒQ‹IËáƒÇMø¸«35h½:÷}-`±ãüm ? ¨~Na}øm ß¾·X¦òß¿û˜ôF=ÿ>#%-JT÷tÏ®Œ¾£6­nMY½cf´Zuá–Û ‰ä 9CàùÇd â]÷7‹ :*‰Ž<âÜÅÌ”#ÒG{w^Ýâ÷“M•}šÐ†ì¸›Åì36?3£ÿj$)Õcâ¶™·î­DëÄqz2Ûsk”Y-„(‚¸°þ´Þþ»¯Ñ5›´4¢T £c8ޱÐëPQ]~-,,JªOï½þ_:¶Ãtlû³ÅvÂTíT$í«cðqÝÐuŸž¸ÿÐA1Á;6æÜµ Â4¦72g]ÑúY=›AíÜ9¶WÈrN}€~ÐüÊ+Böƒé…ÕÙkÍ¿Š;Þ ÍšÃúàu ÒsHl·ÕE·oZÒ­Q/Cõó¨¼eÂâ,eÞÑ÷Þ³ZÛ—*³’ªÞ\™2ÄÙ¥°q8-ê#â÷ê­ïö¾©U6æò ¸Ïpñ5ñûÌ›t›íšhK£¯V|‡­;ñ»‚ˆùøwiÕþv”‘:~¿Ï¿vÀÝ¢Ê&»9X¶Àr­ø›ò★ÁŒ‰7SWÇŸKæŸ-©h.ÄkñÑÕ÷=žg‡àää’³~õ]()» ô]<ÌWñ’3LûÁë´Œº†¢õÿïC ×²¿êÑjvšÌÑå—Îé1ìÐ\Õ›€=žývf?eJå{to?Ž«¶îðì”]ä^þ´y(_ª *Æp!K!“áWÌø>„ÌÜkñSŸÄìI“ ÏèØÄ° Ñ0®ÙÞb—ß}‡IÕn¡>3¾6¾mãB¹Æ"ëÊŸ/¯öW¸¥^„ÎL—åd³ýþÿ)Žú¥jB‡òm !»Ú¸~îÙ»¶Ó/‚ňìß±:QH/8ÞÑwëˆ*¬xw3<¶ì@øÞÙhsAø™Ü;ÿâœØ§b²X?áûµ+Ð_1§ÐgfFà#½â |i÷þˆG³Ö ¹$Wgп‚W gñûï Ç(ø‡Yty{Òªæÿ¬ù$~E³Z|ÌLHƒ«Q¼úŒMÑpâþxû]|ŸE(0 &ÙÁ[LMc/xàFoè/ŠÖÿæÛ¯³†_à̺ˆ5L¯Ò5! ¦BY OÛŠ²‘!ûí=»ÍâssFåûÕRu†è.,J.Œ3Š»àÎZšôs³z=œŒ$Óî(W±Ùu€u»"¦Ø‡ž]ê Žw:*æZlâÙ‡y/bÓ+_#`—Š+l¿UË*ìîúþ4{[2º …Œ—Ux4¶£"h¶è<Hn.¤-¹þî:¤(þŒû´8÷]F•Χãß‹ÙY.Æ«¸¶Ïæ… á{sñ9Ñèž¡üª7Œ½Þ"/J«K˜íeüR×PCÂ÷™s›™ÜÃ÷Ázz)´»s>ÃH×tƒûâ÷_œR7â÷QÔ&›‘Þ™’¹\òsWVvÐô^…ð”33[‹ÜiÅ\ÉD"â¡|Mý=êwƒv9ͽv>9Ø%‘tè¿Ã÷3 áso   ¤¾°NO‹l 9“`§ž|tÙqÊÏMüÃê,A%÷kÞŽ£?3ÐÖ qiÌA|ÈnÏò´¸GõlºÜµ‚ÑÓ¸ 壶wB¢i±ðYz·¶o«€Õe²_3kËÒÇZÞåES {1;/ gäSœnö»«Nê®h½ –/B¦æ(Á2ü37üEÞ±˜ýö0€ïâ˜gˆoHÚõGuŒ¬†×ìWþÍÍ ^s'e¨‡CŸ™À!?×8wÖœß.$sø ^ä~÷L}I?‚Ha5+Ý7mCs¾å±Ä!Ò‹™ WwgÔ4â¨é¿t©Æ_][=y<ÌËþ‰Ü½HÅ÷×C£hß…ÃË+fc·-¯žyÿðøInÒÕ´sÒ—)~eŒ-·ß…²ûÙº>0ò+„ÿ‹yþùÀÿëøD~ÈiUÄÜ2ÒhѨàí "3²È0òÓvµ`$ﺇy?žï¤.·/øïwóUÊÈ(øú‘ŒÁ1¦~u¶Tå”§G]‰‹åIÙHhêh,p»=ìwú2îèxÝY‹›Z@„;†¾.pϦæÙÓ"tK¢ä•Òf /F¾4lÝ n*Òqî)Ú´36"s rÎ-«(”˜'°³ã×ã¾\ïª3MÉá™Wš”ºñYŒje>Ô|pèßξEa¤¥æ³# Ê/ÿÞ™uGëyÍ Ðͧ`Ý Êÿå_ÿ˜Sb]úTà iѺ@A‚GôqÈ ƒÈk"Ö¿TÇ­ižpŸY{ƒØ˜}‘ì.jêRKzÚÇúÏa5|Ï®5úi öX?Öø²Ÿ(-¢µ¦·Œ1ùã?;´màn½= wü*⌮‰4¬£õ(ñ*8B²C°€qŸ‚ãà~‡ËéíŸU™ùïïÖ¬R•Ü÷~+†%ß9ßÚ3í³GØêþ—€øß0ºÂ-Û-lO`ÔÙl“E/Ýhà¾{¢Õºì¿Æò :9–lÅtX5?‹“b¥|?àŽïƒï‡«¹==f¤yÆffd⟰4êWîqŽ¿a7vC›ªøh%ç@¹›‰ÏÌG>ü¿ýh]9‰Æf·U¦¬‚²'lO.I!ŠŽWÌÂCjœ(þòªŸbx_¹;Û³+lr󣨡ßf~ÁYa;Ùß@Ø–{ÏœÊ[êUPÿÂwпÂd€•ŸÊÞ™ã+L÷*ë97vÏšáe슷tƒôsúÁžŸùð*š}ó õG^«vµõ½²˜ù=ÔÝÔÎõK*H‡ï]W…gÆ¡MÊe›;Îú‘9~{¢õÃËÕ>i×¾UGe;úZþì3³±S} Ù‘ìuŽ4ðŠèu× 0]K2¬‹ì(dŸcüqÜÜ%_å ê˜:Á{’ÇÛH#ØzؘŸ nÝð³õ&y ֵЋ“Q¯DP7‚T±là¾ÉwH=÷nÞÜ:äYžçï>×aT|ú»¡G&ZmYo@4,߯a{·ÝÎèË[N¾¨¥îêµ#ƒÌq,«ûߎл+™w6uWÓvå’ee_߬wzºqÍì÷GêýH•LmqÎbÙŠ ¸_ó îu¶»¬È}êÜ í7/_AS}xÿÞ™`þy‡v'ÑÕŽ}]·_מ“¢˜ßf1v.T³ààU0ƒ9¡fÕÅw½¬Ä‰ÈA65g팟 (–‘gãéZ;§ù]Ž®úuáüîùL¾¾ˆ~PL™« uÆÔíSl cêó®¢GÙÀ Í3M ‘±ö¡vm¾¯ ó²%w€ø`ÝbF‹÷·?ºixžý–>Ðì_:KщúÔÏkñ2Ïû»²°î$Ÿþó‹ìîçî%]Ÿñ_6ÙØíÿ¿g¾&½+f?ùÒ¥‡!´%ÍêêРæ:ãT$•DÕ.øC²_“^ÿgzö²M®nÙeÏP’Eû%6c~ýT¥æò$ÆÂ”ÎñøøxxT‡OØþýj‹ú km–Žh}ð¡ þ Y°2¯®€¨;½IX·ÃâÖÅ£ »-[Iøª,}ѱü3ï=½™ • ¯¿”ÞE¤[®¿jp³ÑYâ¡•a°±TCŽò›Ìé©:OÚ¸ÏTûfû÷Éw=˜êY\O‰_±ÙlÔÍc~×­é áû“í™ðlÉíó>ŸJë,†ˆfVy3ká4‹òQŒàqî.gþ—Õ:ð@<®¦>ôÜkÎw…nŠSªu*„·Ž¨IYQ•Ó.jV àôgQL:‹R¯«×ü§gQ$[áë4ôL87g{±þ‰Ög~˜ýúmsXsàjÍàÅ«ÌÊo¯ ‹,X3ºò8§¢É0íÌd†à7ɼ»×#é~!`½ï*ßWE—ë Z÷j ôzƒçÿ/T;ž}6n%ᣀýòxýsúG©8ýÃs ÏMB@9œíHEƒ9;æ<¬V”ìÀf\X§$>c×Ê :ÊÄì†LéÏ)aÖ1;ý¯³Šr,;®)ddPIædÝžøý5›æŽ³ÜoÅ‹Q\ÇÒ™@»°!XºÁbíøóæå{ÛCÀÈ>”®ûtÏJ_Ë_›¶[€í{dðRPŸñ¥ØÏ¢ ÷‘A/ŒÞgÂM¿l i_@4¢éï›7vߓܙ?Æ@2*CºÞ+3ÿgîB·-z‰šçoD©¬é«ôpô:~Í,Ý*Ūr•€7~†ó{½*§I«’HR‹ßÍ”d.„~ó û ºóåÜ\‹«qÜfcÐ>7Q4Ûˆ»º7µG _Ý“;®Ä÷5xÛ®8Ö ¾ƒ¿ùÈCϰªîù‚i-,ÎÅA E_^ÙX¦»Ï½ÌmOÇb·–ô‹vxÖæ“(Î^-@w›‘Ëæ°+Wså›!K_cöôM¾ ¿&Ëm£Jã2%Õ¦GE¾)}ÐÕÏ.q ÊÑ,nBóÒòyØÅõ¥‡ái*9!#fŸù2göÇÎë1aÌ_hÅ@¸+S:‡R¶}§J|2Ó3¹<{)6&¶¸µXâ–ÝãlÙDñNàÙnlŸ•BÏéS/–M$BŠžh2»;ÜEÐoH K·Gú–?¢h>RúŠ@7›ý€{Oa¶_6ë#IœuŸÊ¼¡|WpyÓ2 Û'!†§±óÝ cëè·sq»iDê'é¦|É"àóþŒ®Ý¦ßõ¦°ñGœL%NþaÜ*èm«„v‰%lTèÄ|† Äçôcf”h¸Kòƒ•búçRZ–uËáçfÉÕýYÃ÷t÷`^œÌ lQ›.x7€ÇàAùî²®ëå2?)2=[dbkÓ-„áÚÅÙ¸ ëád²¥$(L‹¾£Jlt¯-(`|KçzêÜI¢Kô$û¤’®?ºÉÇi{ѺOÑ7oOå©glÅKßðîqêò¨€=I+Öe™O e ØãÙ¦ö§ÿòÓ0OÙóÜUØîºPµ í^æf’Gã…ìõ¹þú3>mm â°{Dµ”i“ÖR9xû\soë‡c©ªY; {NO„þMÅŒƒÏP°[è…'ÁZLoHjK€ÖïLf\|[ hæ#z`ÁtÅMïæ×gìøÝº·¦»¹ãé/]zXŒ÷FõÌ{ÌE…áU=¼µÅKÈH²S*u#û¶3î3[é8sðýâ›òßýH«PˆhsŸßG3Ãx¶”Yýù ¼*tó@¾µþ‹aûaÞÍ2B°Û˜ÿ;/šškÏ"јã„ä€5Ço…Nô‘¥[³Ìþöð6ñ¤'ë ­efO·skõÌ$”÷Yÿìaµg«ÓÓ&SÊÛÈ꜕0Ì>^¤_Õ«»n;¡¿»­þTÀ;뺈4>hj?³Q T¸©9.<ï$áDʽÊN;èMÜ|ÒÆÜt»9‰Ìô› Ò¡n+öY¯ï”çT=ZµHÏü·4Qj•s­˜1 ûŒõ÷Xþ§H¿ÜIg‹öa¥O§>ãþ9+MúìhFÆJ´1§­ƒxzöjDæêÂ÷¦R·ÇÀƒï³¶å8Ƙ©bà>‹v©Ôt¦Ü¿µÐû€À5‘…6‘%- Iº«X6ðIRýQ\yûl6&®xйçÒÉ^Z ¾¯ö‰§Ñ2=çlùò¢ù_ýŸ,¶‘MHݹ¥v®›ñémþ‚ly¿ï­ß åg½>À.úzQ4}xëNt,߀{žbRçè¹/)gð3 #eV‘ïµßõág¾gS‡¥AË(«c Lÿ~+­œgf!œ¿ŸÅÒ×â#åÝ5o*ËZ£mv4z}ا¢'¼kpѽÄdWÀñQð…~3¶ép‰(ÄW¥ûÕoDLjû‰Rg{1,”_Ô “a÷ù^{ƒ]*åU#v ó{ˆð Þ™c(òÍ€Kxz?u'¯p­{ªî%K¿4”Ê·e%'2 ØéS_ÝþJspôm¿ö»IËÀºP=Xfen«å©süU¯‚[N1hþЀePoË_C` õJ®8‹Ügþ&|DEÎ ÜO‚J ê³.ZW²¦k¸!MzÛ¢Š´´¶‚÷ËÃÜñ°.œMä.¡ÏþÏuj›ùè,²›ÝÎ-Áè¦GB›¢Ò/w¸·Û…ù[øh£› ã|*Ø$NÙ„s¡°ý_­¤cl¬S®Ùn AdLHgßËëIwè”GÄû­—ùí]öµöü[½þ~*õ>ÿ*¦d§Ó¬|Å3\ ø™®Zðå/&N‡ïˆú÷ºy‰ß³!¾'žAÎþë¿ ŸQ{=cb–oå{š @H$3Mýí1' ¬ÄI98@«!ŽœÁ±À]¢øDñØØ™·oTø°cUÆ€;a†ÜǼëÇý®¢d\ÓM(æ–7Ž"¸¿ÉØZx×uhuÑ=ü}µ°0($?ÊtbüÅ º[ã‹fi ¬;9ùÀ}ŸÞ}Ín•»ÊglXߘÎÇñç' l•9Ÿ›ô¯5N‚ï;cž!`¯@‰UoJö™+™Þ¥ìÀ <ûá5Qª^‰Uê³ÑÈ,¬&×f áQÔÜ„ï³ÜEZ¨v°.,ac”³Li‹Ëô¢:"ij¦_d!d£ãóF »^´Lô¬ƒø¸î—WAx»‚ÔŒrƒA Ú>íÍ%8»ߌ/>C}ï)"é=Å«ì.¯Ú ÞÁ;ËEß÷ › u®ëÞNbôÛ¡lGúãsv7¾ê›üØâw¶ÀO¨Î7.åŒ@>~]ã:1–F‹¾¶ÏMvϼÚzäˆD*“ ~Æ%gNìó‹SòZ—_|óÝ,æèñŒ(Þ|ó«7×*x?CüÎÝi…fšöÍ?C÷ú‚:dî 9Òük°~5vèøÐgå]?#甆x8~†c`Ð>…´ Ñ+ˆwb8]sß‘ž½$*µLý7  .èýÔÎwû5‚£ DîŠu°Ï»¦rkS£€J(Šënc“"åá~ž/Ï2ž]Ý4GË07ˆ¤w’ñyBg».×Fxê®n~_2¡ëŽ®2 ±½Öîþú0;«Ð™ WلϦõ«–’Xž N}++"¹¾Ï:š?¤WÙÄ5Ôb ÇÇB²ëÇ;ÿbwn‚ûU±ú×ä÷™g\s±ËB¦œ¹‰ÖZÕü¸Í•Ý‹â™w¿F4"t±|íœ^Ýsf8ò±«  ˜¯(þлÛÄW € ¤¼íDÑÇôÛȰE!|\³íÅ¿ Q°ehYßÙYØý [ËßÚ¹‚Ïür ´n;ÌœZßhÿÎÖÕŽ& â[GÔÍN{Åæ¾‡ùV_ÑzeóU?‹3°.Æ„í³eÛKܬé'¿R_ ¿{’ª‚w< »&JöÚÈÕ—ƒiÊÝÁk—’€ÎŒyïcœÜ)ƒ…5Td|™ŒY;šÔ âa„PÜk¾áj»þy‡8]v¾™ Dº~VWým@†`mk`’–kÖžÉÉYÇ\Ý`P¶Ý»6%+O?ããåQÒõEEÄÃê$›-ʳüÍÙ‘|rOö(°ÍûFDÐÖ›¨2^m¯íÌ?³‹s_Yró´/¦èÏèC{àÀz„{ù"ý2®ÁºáO€œ©gÓîØò3*$àÅw»q­dESèq]ÇyæfŠH¾òEâ\€c¾ýh>ÌŒ2¿jC–øŒ\áV5r‚òXx³ƒ¹šòèL!b½Óæ±$4nuΜHpà@ë†(x‰Öù7GIÉ£&`ÚÊâÍÙøw€»z¨‹nµ•hk1ÌxèÏŽø‡<²»W”›Ö6@/¬.ÞðÝ=Œæ… xým¿ðí^$OÍL.vß1W$Ê­å!Äïõº*K‘ØÑ@yÍ£2„H®N½E¦¸T6e|gN·Ðû‡ïÿõ¶í˜÷s7ĺì˯¾ùN³WÄzÝŸM¶ÿY07å‚7H"@Ǭcfáß^Û Ç…™öÌøÌ*瀪,<æg†¦K¡yªGòe«]Ž7VÏë-n‰±(Kg/«FòesòÿÒ;I\?·†p¡vᲑªðE“l-MÆ2áðçZÄ]†gþâMð~‰¾Ig‚×/qZQhªG¹dœLIçò]õl~ÿ/ícm¼N€!þŒ}‚Y-[?õ}΄&|w?§ôuù6ŸîþO‚w%¬Ú¸°z¯¦ Ê[ÜG3 ýñÒ…E(wˆ\jîñ±±Nÿ®Å‡} áç.œžurIñÔ@ù¬ ÞÑHƒ¼YøYp‡ŸõŽÝ̺¦ ØÑñÐáòï—”ÿâ» e5ÂÉD5³h6¸¸Xƒ}Mh8ã%ô¶¨„çµX KgËGÛ»_¢rû”Ã,wòØa~æ—vÞo²÷ëwvfÚŸå_ýÍ5§6p/Ô[ËèÞDëÚhˆÐ¥¸k}ž3LÉ'ã9[ÛÈyB#çõÜ)pqßÂdôŽ–¤!´|U$Ùú͹© j‚®_z*õuš”O­|ûÛO*a I»b%U#÷8Êðc œéS#¾~Ö_¶ÄpU«¾¬]|ì•È«=iyˆŸâÇÆÎuF:Û×–r³¶ø$}TóÛFØÆõõ9EÅ#½ZdõBEUðÎ.Ο£Q÷ôW³øT6¼ŸøýîFù¾Ì RIj%“¶÷SÝZe‡d—M&/Ä×âo3ƒÐ˜½j.+/~ÿ8ÿè\hæ€åg 8¸á¼ëú„ðõJF œ(c0Í@”Aåj2`TàùÒË'£ÈÛÒ‘PoÏ·0j¡¿ÙÍáMãlj;¶"¦~)Ê[·½^/£…Ý© ˆ[oôŸñ¡SÖºw¶ôIÁ÷öÖo£íH°¤²¦~².¤àûìÉ67K˜Û™°JF=× 3F…‘,Ž™0†@‹<¦: <¡öx2¨ÖêNgAæëÚ´&6{^Z8„Ý9Òî*8.T†F-À¿Ô–Fî¾±^HÁT¨k~­Å_¶äÑ(ª·Ý|ÌÏ´ÇsW;ßÝb‚v§×¾ÓÜÔ,’-¶Ï; Ýû¾…HïÓšK´ÆÎ»ÙEÍ+ë»Ý|êªå«\y¬Ð@xþD nF _¾ÚXS˜PþÓì\什E“ ]ã–ÅØ¹¤ý ܳÀî9íÂ+þ¶(ì¢sPlB­üDjjY;Â%WŸÿa]¦ðrq×=Š Z²·K­Á,~!{Õ’ £‚õ×ç|÷)ÿ€©FèsÍ]™dÑᄪ›Ö°% îfº…æ©moQ²×zëô·ü\IQI‹Ê7ƒ½Žb¤¾UŒõEz6‚ïãÚ(½‘5 ÏÖu7§S:ôK¦góVª-ŸÆ/Ï‚­Eâ+ð|f©ûâ‰~Í2k=•~þ»ïnØ¡ð: ›é; æ©út¿üß Õ ”Ð/ÇìJiØæzúzCmž}ùBÒ Ð‡$ˆÃÀbÁ¶¤4 ‘˶cÁ!_PÚ9X÷n•ö U·Jý%&lS’,'=%Åd†ٽܗWcÒD6¯®}ÍíüúRf¤…DŽ엵ëá  Öÿô“o/™[ìlƶoYävÔL—êŒçÔ7[Æ‹9ÙL?'üuø^Ø~é<û™i°è#õÀ JßÓrUÅZŠ•B@'zýù¶Ù)#šcˆúuÖŒ–ñg<^ÁHÏHù¹9BüÌ@¼-Õ²?¨#w1¾ÙUì `Aú¹ñn ‹â!ÎSpÑhØ”–ƒkÍŒò®p-è?èϧ,| RI j?˜¸êcoE¾ºÍq¿ó½¾ÎÍçþÙLï†ì¶ïÆâ;¡úÌÏ:ÃUÙ/¥þ“Lià.Ãfq²¤b‚æóÃÍ5–Ô7O纊’<ö0w€^·^v5+ez©vˆ‚‰úý–;m& ˜¬ëN)¥:”Í èI¯„l¹3Q"”;MÓ¸U„¹øL_^`ÏÍ0Øqf¥‹|ÁhðÐ,QÒFàR68n&9@ß'€X‘BïT3·Ý¼-oC§ýÒ¯";©öR‰6–âŽwž8àÞ©`½t-©'œõ5-ßÐG*"à¾Ð¿çÉTÞ½kì6†A|[vv+ û*s¡éQ½ç:Ûîó›§:ˆïn=7료ñý“BpiUsyéjÄú <‘ûº¨ošEÍWÍ3˜©oJHã83Õ{Ô}ìh¨ÖP¥iÚfaíf¢·”p%Ü.3{‘bŠY~›uNÿb6Ü©®Záèá”Ô+œÂÏz¥¤Ü‘l ñgÔpU,?#ný¶p»à:ÌÝíŠÜÜ¢ò¶ô$Áz¡úÄà;<¯†ëÓãß‹˜«b\v›ÌèÌ7¡}}ï¤F×EÒÙ92ý\N¹ÙO3^Yò§áâí¤á\^K^ Ú›¡9ë}™‰r:ª÷@ª˜?™ÉyçBsƽèüÄ+ ÿI–žVx˜ùÏÏš†ÇÀŒ'$O˜pÖaú'}zh™“÷š}>Å(Ï ‡Iêöƒ#–;g¶=%Eú‚ݵ‘ñƒžˆ|Àك͓TÆÿbÏeûR îs†‘:3@ßDˆ‡¼\$wÈ»±#"ï/Áú~±8Uvõ2*ÛüFÀ¸ÿ|Âýr¯nRK;oûnµ-ãy5ìîàÖ]¶ä‹ðò|Ç—½{Úž-Nøóü8;sF4ñ3Fw‘87ãß ¦ë¯=¬±ïÌR¬hG ßÃÅÿ–àòŸFNð]ÞG¯H.cähj¾Å\u°” »¥äŸ p(_ubE­°>iMÒxÔü®‚¡›d?†Š.1ÕÔ¼C:@•\Ž1‚~‹†ö”o¬sÈ@vÚüKNÂz<{ ½Í›äù0>Ý|¿"ðMž„~©]âI„üXE¬“«Æž¹ê²è­O΀¬;‹g_Á"F'ëMî‰ÜÍUJ—,èçæ/ÿ=’}`]änÞJö[©„™)lÏŸý£z„ì3ø³oAZµ&]6•¤'ƒaŸõç˜¥Š¹éSŽÏ®{7×{'ó ú‰â÷ÃôÖAöËíëeW®-R/±Å …wªv«!wë¾à~ãd¥×[fŸ‘6(âûÃW  £ÅÛd8“—±wÓ(ðß§¸lm^æ‘›ÏÚgÔ>ê–÷¿^¥/ÑÍl9ɤñì@«_•n½úÈOOùÏÿJs€þŽñÏÂ¥å {r.z€ŒÆê )ÅtÍ#QAZ¥}0j8GIDçÁý@|¹V^é‘g&¡ÞÆÁ<–Eôùd]ðÖ‹ [Ï(éú¡2«ÅÇØÜ4ìÙ /±cUª¬lƒ=/ cÑ–ä-¹Ïz3ò!2”âÛÁrôš³Óãj: ͺ´u° åí3;ìÔ(7t¡zf¼¾1`m1sš¥|¾™âß’ýtK¿‹Ç›÷û¤PúŒü¿¶Xöžæ5ï5ˆ{9?u§´[1ïɺ¤ˆ °Gp¸UÌAæøà»ÿ<ÝúÑžÍ`ȇYÇÕHûèÜTÌ,(dÒ;nF´Ò²‘º­Ã“|V@DÜw£ØÿåÛ…ó_¹ácûâ9Àfƒl¯H&ƒ¡Ý»Õœez{Æ­Pív¥P:¬¦£Ú³èJtˆ£_E¡m¿òþÄ65ŸíÃÏXo÷­Ïß?@Ÿ0èKóÞ××[* ¼%«;»½…¥Úòþ7@¼O!«Ô¼¶/ˆB„`tãz1ó¶€×‚3“ž>ì–8éõñÍ•PÑ ßgΚCÜ$~LÕá×ÖåRm!X'p…¸³ˆJ]séx àþarnä~"J]{>Á~Mô‹=ñ6˜2è¯À2ÄßVͯdl¶YÙ‚ú ßhî÷(On±:°Žfù(ñâuŸÎG¶o _æEÏ–4£ÖŸ‚ÒHPÓU»ó¤Ãôßæ¦áŒk¥VxnAÓô¹ù1±°»ùD (¾ºâ Ïi.ƒ*Ãß_1Û;=âoõš)Á|þÞôÁâ¾Lc®0æÅ'8ˆèï1ÅÈïÌ9>ª-Ï»¬OLÓKÎÚœ©6alA`´sQv#Íw`šÐ£®Iª5·1@NbÿJDsåϤöö6&oks*Á3._ý¥èÛè=u¢KÒS/@|+õ5åó•}Ÿè6øöBÛDí§_ñX!û{•,Ðd_Mºá²¥s`7×ïñÃG®â&’ZlË¯Š Jå‹;ò¾0>A›š\h¾—AÂÃ÷Óø°“é¨ò@ÄÏ‘ 15GÈÁú¢'Ûl,µå˜t|^Ò¦Ö¬çÀÖ‰û²44‘xøÙÝîm,M7cs5/›šœÁáN¢}!¼Îü§îºÀw»D‚>g…ºÕòü«¿ùñ@í"èW8.Û+7Ö·pW8¾of9ãe—¶_´&G]”̰ƽTóÕI®kŸzuϸ=UJeCsk_ZI‘™/¾ÇD®ûÌ´ŒÔ/…í³ÆÚÀü¹˜Û¿\ÎAå#˜ØåuO¨þͪ»”TzŠ~É“½€¬ôÜ¿áÒqµŒñm€‡a7®<Æž°æçðdáûû¹+½#mûŸÁ(zö`}³16šaNôH…£…Œ;( ‘c&bó‹£_öãAPDüŽÙslÜ.¹…°Þ†›‹JZÚt Eî!i'èª5ÞÏÖüG‘²ÛéÆþ¹¾l:>N*Ê©¤sŸöeÐÕN'³ ¯²;½‹~†)¼êòÂ7(‹b|þ1ßoæPòÚŠÝ•kFx äHh~&0Á¼œK-êã>)¦©b¥ËÒz—ækÃ$nÂÂw±,¤ÒàÉqK3€®”‘:‹¶s ž…ñ›Sî„«CÍH" Vbí­s2™=þ$c1 Åì.\³Î¼pûÖV°S¤oÄ,O+F®¯¿ÿï…ùͺ·1w¥Þ1Ûî…z 'ÎIÞ^Ôy9ÒXQ˜óŸ £çÞNŠ™!›¯Üµ“åð-}ù`}F ¹f;|o”e‘2M15£òf$Œ€}‹aT™ª«ØJ\u‡‡y’¥³[W(uÿá«áFz˜¬O¦jn^c>˜îáÙ'qêÈÊŽ{†‹é$2¨Ô̪»uÏÎ4î`&侜 ·µ ~ø…ž<w'ƒd)/Í^ñwX¹ˆšP·HŸ*vTÚ\©®¢êËKìùº4¨È][úã|¸ñ}‚ë•vøœ”ÖWVuRÏ`¤Òß Šž¯&«¯ jª˜}–ÛŸ¥K¡Î.F9ƒ‹SËù»ýµéºÍ æ^  ?heMGÉ•MW‘¡áÀ,èÀ\¨®^«ÝÕÁY“”ai*qE<ÑS—Ì|øn·„3ÏzÀc#QÙÅkÕË­ëlF@Ƭ13ù˜YDÔÄá”n%Îs`•ƒŽˆ ÿæV&òåB†Î°fq3‹P¾³‚í6ÆØˆé”°Ÿ³|¯Çv.á¹8sýªzl¯òŒ6fÛ TOè‚{˜¡¾­e°îƒ[—í ¡qñ¤þ€¿3Á-RÛ¡úÇÍQ‚½ÖÕµ_ÇãøÎ{Âà^³SÑÃ\Dâa~¡!ð_ßÌĺøCÑé¬ùm$jÔsc |;³ƒø¹YÉ7BFDïjx žÅÓ£Š9å#`ÿý²ס-ÙôE›wÆî¡†ÓÎlÌ_¥CpcHW\£º]³Y5i, ~kç·W¬x{ÿæÏXežÍh™]‚µU8±ð)Öûð‹Ÿñ’wNþØuÀ>×­´íû‚bq÷3:ãy3ïò×T•;ðïÛoÜÚ'z ¡^åQIàý`œäÁg/'×J{[ouv£è(o‡ÄïÖxF­·×ö纵]ÖrÖd´4ò®uüX}ûØL®ÁGûã/„· ÀºÒÕ¤zÎW$ëW¤|ºIëùYä*Œ.Þ³8øR(ji#2=\Íågª¤'¹AãÐÔ—§…ø‘ò»+ÅŒÅãGm y…êÁ}½èâ‚wÏoÏžw÷Ý4³”ó>/\vSI<$+â¡ßW!`ÿ`ý5ÒzjÊœPë„îŠêÜ,MR«E?Ünäù)·]fþ8ôòao>¡ƒ€ýóÿQOÜga‡[vG¾U8ÂIi >6ò{ö$3Ïßž„ìÔÖãìGc›ôͨ²DTD([öñDœ-Õ!ò g"Š {µ“ÛŽ‡Bdì:U‹˜æ°¥=·un”Æ›ix³»³R\üÄlçjèrŠAó•ŒmÜRËlRbùý¾ø¦Àú}ðJPt¯/À}y{½R }ƒöé¶n ÉUì_G§·ç}ÝÅ鿜…ÿ¶¼ì*»øÊÏ"ïÿY$Žœ…^¬•ª¢hž±Z°*tJõõI(ÅÏ< >§ÐéGDMl&9.s³²‘ˇ®BÖY»áñïußµL‡úôÓ©“³Â3‡¢N! È.ÙÆ ᕳVJ33½ü–c?³üêö¿‘>Ä_›XéOPŸ@°š)wÊh“X ÉâVÿY€ï¦Ä¦Q$.ðï{ˆEñºfÏŸµKõ\f…ç]µpz™¹~‡‘0¥4:MÎûÎóãÝfý3ñ®½æærë½áùØç.sþ(Õôñ—Ÿ¼}ÔÂ=è¨Í,tÛßõF6f¿qkúHÅ(ª9Ñäîy]îÔ5šoŒÄ)yL¦ÁHxWHp^ø Ûy¥C‰Ë$ǰ‡xñÆ@o¡¹u½•éK¹p·p½(ŠÒíÕì±½áËFñÙ®,ûUûäoå|Ûß]­ßþ½€xW͈¬ßÐþÓY®¦ž¶¯J¨zŠ'™ èAüGŠ# {¦E|iþù_}W Bùnצ¸‡ïfvèšG93¡=Ò&ræ\ŸÄ á!ø äsƒò­FB·.ɯb2p_Öéj¬ë»&~¿ä}”rƒàTÍ(¸:½©«¼)Ö‚ÙyT<5Š£¬l$õÌÅø€Õnö9}ž¶ÆÐ.´ü—‹ýÍëFžÔì"Þü.λM¼˜ÙŽ3“/;ZR´Ëú¢™£eŒ`}eMs‰˜=Ÿ-0ýò¢Ôë”´¹µzà‘ÄøÑ-N{¯[þ†x™9ƒþN@Œ”Oÿ«âôŸ&J7c”$̬›¸¯ÎJœ~îâ!}?™O̾kÑZ‰SGå›iI»òRECÀw½ æ· q3Ãbg¯ d$^ÔØ&›yë¥aÝûÆÃpµ0z¸'o/Hß×UÅ*ò—Pµ•6…¿Z»î³â«_Rì~s!óNVôü¥zg¯š©—Öeç—ï¼@<޾þßÛŒ~»:ôƒqµ˜>®ÿõZÉo<-ò]#Vëð}†²UQ†«Hú­Ì1W½+r?¸_fIkJ˜™Xøie ®•”Xè4è¯øÛq(ÿÔ²~º5ŸHÍÎéâY¶ŠÙÁF~蚉òêv¿q/Ÿq|ŽTg`á!ûš¾ >°‹—ŸÁ%}HMœT°ØóØr°»Ó7„…¿ñ$¶ê$:tWä>´Ýk0È6?[º7E>o^$^½è¦žÎ>ÞýÊ·§‰MýÍw3Ãô})Ö}.ªë2¥WêêG½š\™ñ›D“‘ògHÀ¢hqý–N#6!@1ù›±)„?P­8¢èÈzý«Q緬ɿ½µ—éè—”Þl€ãËÅkÏØ€ì:%¬@Û›á’æf¯¤îÓnÙ´,Þøî.][•Š„J&cưê¡<3ÞѶt?Åú@sù•,à»süÍÊ”§æ7ss{kÈñè2ùO'¼?,pÿ8j0ÕÐ@¸êS”ìüav£Ê¬³3ï¥J˜ñG¶Ìn'ËUO%ò.… ^~êŒøâÖÍ"HÛ0?:[ Ö%Ì+Ê´ç ŽÂK¨òz&Ý·5Lœ»bî·_嫚vãcñøÚmmù̯óÛá¬bT'½·?C<ϾJ(®yäoî¥ëŒ1Žú74ÙÖ]L‰ŽîêúQeEÁÏ–Ü¥ÉÞ RÆ%ƒ ÞÅií¶«xÂÏœÂÇÛ  Ÿ™^¸ã*ýÌŒb«ú!\Gøï£n޾mæ“X³6ö©¡ãåco¶¨&sAsè33X…HAÕðê 4k*‘‰Ýe]²`ÎF‰lQfyK–,/ÎFåbù}¶°±ºPîÇwôörNÞL‹4CŸ‹*´oÀi/Þ†SKß겂!j´SŸ§^kI˜ž[@pÊ Î ñûu1³ÓÀÔ Ò5ß”×ýò¨Ú·ZW–È…¦?çò»¾²1[þùÿúGMU¦9ªž8sÕûG!Ñ?û_ÿH¦: É.N§3€ší‘'{±=KrÙú;Ýzq9É>fÎ^LýÁ‡7­ÿNu®Ìz{mÿ¤FËÜ:7ìÔîöKxY4¶qÓM…§8÷ý´„ò¯ÒÛ¶ô,EÊÁôÎ üT$¸¿dFÑ)ý0Ù`îΫÍû§M+Y& ëµÐyUèîóçûª§L?jë.h*a}>BÅz÷rAÜ¡|W dÌ Rƒé ¹=7•å¦fí@‘™ a32mfvp"Fs,˜EN“«ûEÍò38úÈÑ2Ïœ6.F¾ U¯b–¿àRRBy_VˆŠpØ7ã;ˆæ ‘éLâë)èõ¹;\Ö¥ø™; ÈîBÛ¾sž â^f´§üAÞÈ;$·ÝÜÆø¨ ¶~Óˆuë}²ü—û”y¶Óºœ¦‡LñË “†p;¿øü²4ééÖgÆÃ<ƒ­EkézÄzîÓþWl‘0 ‘" ÅìÖdŽuÛеfxjP»“QÌ3–ZáLŸjR1û.5ªèy¾K*gÙè\Èø.IµeáÏ®Œ ÊàC18EÆŽ_WéÌ·´½ùåqÛ¢¹ôá–ͼó‘Ázh¾>E9a_ÎUËt& :“Ÿè[6N›Ùµ‰³ÛAÍ<ý=qŒJ¥BéûEtÚÜÕ¤‹ðÙDÒËgØè Û3²N†³ÑbŸ–2½ â;omE|‘>d·¥F¬´ðIhfàâ“‚‘·Ïz(x²ñyÁ£,EF(xXO?3Ç[m˜{Ìp92-½€^t¦uÎÜ»;=‰âsÁÏ΂Û&$yÃVUr/Kƒê]g ”Ï~ÖW53íüð9ü 5Ù è!雹þþ„˜í# –×ÝÌ~ôHq·yvórEß]1<óuIÑ Æ°ól1¶`ÔgÏ Ÿ>ÃF_WöÛðG¾Tw\[@ù,ÙÓ5º´ú(a"Ù–h}¶/7G ¬êæ Û?¶E5õEôùGÉ÷ Öis ºÌï?Ëaé\}&ˆdØëfF`Ï¡Q:êxk—A-ñs¸Õþž¾´+¡ÛBÒw›~ãé[„0 zÎá-\:ú¥&žw±;ýT„¾_Q¾°í!°Eë×ÇŒŠ)œÚV-õe?×>Åb÷QãƒvÖ´÷:¡oÊé%›éRåÝŸ0Õù¹T)WàôÐì!yFé2÷WcíT´iŸˆ­ú÷n«{égá{]wgÈÝÛ˜&ræÛ£=Ï£‹ïÑŽ?Þw‘Þégp'ÕëÕÑÕâƒ\òd¾O–G’|ÞIæzÓð ¶ äÓ$UAvGfmZgÁ·@ŠlXxîc3?ÿ.ÜÏ(¾3Cù·B¢BÆdby#yF‹l ,JÆb[P_¤£à ˆÙ‘gvf=âfù«ˆ¸Ùƒ×:ƒƒægvo$K„3z¡u²y½:‰Kjól¨óѹY=ιm Ç |f÷k1Ê`/SOTX®70Ï 4h¦ý‚ÎÙ³>qºŸ[]R8^§$à®4éftDëåKOC± 8®¬ÔUf’˜æ:—©í°eò¥™/9(ê©TØ~ýY?¾2 hárájÌê&Ö_¤ü‚”ÀÝÜþ/ÿðÊY—“Š›!bCäÍ áLwõÀiÛ†l×Þ°›gÞTRÒóÕ¡;4CËxs{«v*èÚ5¥ÅÑÕz¥Xßo×qR ËP·[É£q6Ÿå§JÛ¾¯Âýý³ISl þ&½V¦˜qGÙ–E«õ÷%|¶+€FÁ 1êøè¯,„Ÿ›»ÞŸ¥Æa¥a¯VR€®™›P » ©$Åïr­Û}l@ÍESËÖÌ ªt}Ö ¾[ü54Yó‰(õ ©I÷¦×6n®&ò³æ‰?# Mo:qëÙSŒ¼5'enUÙn惈#LbKV³Åt6ë4S’ kˆ 'ub«V 5úÍZ{xÎÌŸ¯×ÅÐßã8‰s¯þ\‚tW]”‹~>ý¼Ðk³p^wõV»ê™±êÖ3âú®µ«Ìß}/¥ÏÍôq‰Ö?°NË{;áÕØ€ªöŒLcÎY¨%ù^É÷½éšx=–øã ¿Ì36z¼@P× bJ#ª9ÐØtÇ+ Ÿ5¬ø3jÅÕ¶ÉØÊñr‰I¾ÃÐMNìJO7ý(ÎÛ> 蕆ýÒ ×ö ôøܾ²·´ÞµÀÛæe§}âW!e£-þº„ɤ-Ë—ýÁî·lŸnÚ¹7¿OÚ‹eÛßH\ÞÊ î÷ùñï¹}ÞóÍåý6Ïv.ÁEî²IÊ©%ŽŽlæ jŒ2®É%;NBöt“ø*ÉôÅÉ%™l&Á}‡q1š0mÀš^"š÷V2'Õ.±7ƒ™/èÀZýe1˜UÙMÀÆ_r#ÿ5ÁŸÅF@‹8 î=аDÈ,F†×Ñ8¿þÃ÷Éu’£ÄûÏÜÂöb|Ïyïú€8ÂÄ‹îŒ1öÉ–²ÊNTßo Ô]?)ƒéæÏ¸zó{©Ô×»LâÒ;‰Ù+X+¿â÷}DSªÎ?¡Ä)˜sÇÅHœþ¸õÎL‰{hÀ(aŠÜ+7ýøE*Þ€};;ÎØþ_¸uå~ØK–Ö»›q1û· –uã§=>˺-Ÿ’?ïøýB‰ªb¥ôV/§7:>ûùÁ&=%T|’aQ°Ö"ÖšŽÅUdðR]p×ùÉ7Rz÷BùÂ÷l̪9z ‚æÈî·ýÛgÓ˜ûÐ߯Þá16f{öÒý`¼˜Ë¿/ÆKm9‹—_B”Î+=ýÊ›/§!ÅMv;å¬úÅÔàQ/„vÿp2Ù3°þ4.Øu­T’F\ç•HBy×ÎØÒ(š™±ó]ƒ Ü5p¯÷BÍŽ»®'ˆ† û»ïÐñÑ5)7¦åæ…üçÜP Ћ¹:ªÄ îg¶ÃoN˜ßÙ"¼§*ܶNf~oF—OÍúñ÷ò%¿þ‹È«¥‘Z0]S”˪Eøü¯ÖmA¬åð…y»vÛ€ûg˜™§ciùåHŠßã #‡%1pó¹”ÜÝ%E0ª:xo0¸È*ÁÆLu¾Ø¡zÑz‡óŒòEÁmÜî6 ){5ž~IÚm7ÜÛu|¨ÛëîÜ&$\„vìÊ‘“,qJweð®Æß[6ý°øðHw_Mhh>óVþ\p/P5: ÷Pl÷,Ý ÛG}è¶÷²ØÈع!ô_:úžª'_Ùá}å²Î„ölô&kšº3À»êj'^º,èìå.c³7qm=vþ¬ÓŸWa´þëÓe; p§öÅÂû£ÿÓÿå?Âo ¾¾}‰ÉHèh%g-„Ÿ«æ¹)¼º2† ÈfÜX^—œ%§©?=_o5+â{W½†ï«a7à€ÈºÈ}Ö˜„a™/ÆM|½Ü¬fT»‰{Rîj2³<\äÆìsn±óçá34©Áˤ"¯+â¾bØ-/ìYS齓_ÿá‡ç©Næ¬;E¥"ícÎî© _d/›M˘‰çD7»Ò4ãå"çWêÏX}M‹Íqw’¥ó/ȾþB™•>£†¢õ.+ë\cá…ÐÃŒt]œ>ë=ú…mïmo¹ˆÍ­ia_µåÁ߯Í:¾Ù-D î7QQ{QsÅ«5©bº¯ z¬ŠJ7egøìñ¦Ç¡â°dë)¿©ž’ e\/I#—Ts³þo¢ÇÑIu_ìt>¬vöý¾wäé÷ü¥¿—O[ÊÈ%]â_ŠÑžÓbÆêãj»u*Ì’ øå_RÎ2Ã÷×Û(ëž³ñ:ÂGIkü{Ù¤s³À§~’$Ï]¬iŠÕþ!â™ÄÈ]D#gnWb¶Ú¨›ƒÈ5ºÄºVÕå¼Xvh 2[êú$Mk„:?@«›T•9œý3ô½ÞšX7Ë%:âb®–° rÌ‘!;ø÷!øœZ„í!õ³p’°q^h=§½Êh—#ø^~É[¥C·fí"Z§Lǧgé“×Y¾·ûͳhîjÉ¢Ê#˜r$Eë?ÿÝ÷³¦Ñ )n]Ø.Ìge‘ æ™EèùÖnýÓû7ûRój¬±úŽéR0[ X\òô³ž-»Ü/d/"v3ü ‹_ÜtAXpúw¥Ëïw¾‹ZŠñƒ&ë­«~ár>Ê2VÏ¿¯„>Åë$Ñ–eÚ~UêmÁ,y†7f.5Nè‰|vÓé/}Îíõžà½v½ûð:¨}ž,†ÏÆ€ò•^˜¸¾ˆÍÜŒ.¦º¤({^öµ¿B_ºæøÓÚ³íö‰/³Í}†Ø‘B;G%E—©¸®ËMIWC,?îþôaý,ŠÜ‰‚÷¡’)MGÝì\j+ûì¿ø«?r"›÷3xr<  "a…xa½ÚEN]郞Œ'ñò€~cSsØ’J÷‚?¸Y©ýÝx"ýâ\ۅó}nâsÒbÆ~ {õÌoÿåŠÍç„á¥.‚ï Ûu[^¢ª¢øq{&ö}¢TFÏ"=€¶¥˜}¶ޝïöG9,™_äWÏL¥~Í‚rÝ;mŸ_ü‡TU×¾qºgœz‹ˆ9É›ù#MÆÌËÊñAp—ŒÕWë ßE§”é,8Ž0ŒÿW> È;ïxèåï´9ÕíáŠmJ6¨‰u š÷åxÁï«éR0µÑ -ÜÖ I6ʽ‚åŽAsp3›í`ýŠ}wxúS¥c@÷º×…ü_v–5ög{ñA½‰ ¾å1ðoÝÒÌ$:7”±Tõj¹Vd½³ mÙt•ýó‘Ø?CÒ—W\ÐzýÌwKÍ›ÞE¯6+å~ý-\if9=3C?Oò¿þ‘#Í”__Mkø£«{_­ß>÷+®¸da䛇‹k@?;TdÈÀ@åa}\·9”9°&¡3_ŒÞêšÕ¾g€ãôîyð%jx‘ÈÇ+¥ÔþU‰sñôxÒéï²{Œ°ð'ûµ|ŠX¶9^(zùK´#V ä-†ù sm·~’ýzL7Ïn¾¶–½ôÖx.Œîi{zû¼ª~3e~‹V jX¿ õÍíl~%µ_ç‹Ww¥úsüÜÃ÷š~®æœ˜Âçdý¼·È@u^‰q=ü5lÈÀº®úæ.ÛÁ½ì«´ÛÖM6’EÛÎ}P…¤µôÈkKžî½à˜ª¯S’:¸ÿ þ¾ßâÌ»±Ø³½œ'*²µ½ÂÎT%¶Ïb×âÊpÚâ„inÏ™sÆ÷æ½\M0ÒºˆÍó[îÔø«P{ÙBl ë,ƒ(Ó#ÓcäÁwÅGØ6¿#¡ºK·UezÕ\yg¾ÿÑÀ¤Ä›ªI»‚4Ã÷ùgJ–Ž$fÖ`ý ÏûW•›Î]uÅÓdc…™e æŒ-xI¿«‰Yêµ¥y«×/^íúÁY„K;5Z-çn21ck]ZC’ý>÷«¼ìn6doºx·c5¶5‚ù°¥6ÎÿrX6ʧWúIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/installer/macos/background@2x.png000066400000000000000000016014661463772530400262100ustar00rootroot00000000000000‰PNG  IHDRèXñÌ%ýIDATxÚ”irl· F{3qìXÞYæñ=f‰§(Kz)ªÍ:Ž>¢ôƒ%u÷½@ÄŒÇwë¿_¾ûç³½üã?_¾[¯_¾ýûÏûóÜVý¼ß}ùôúöÿ·ûùË·»¿ÿÿýókùüõŸ~øò›¿þT¾cìöüòøûݗϯ{Þ<ßæSžÿÛÏŒ±ïåó¼¬?÷ì“Ï}ôû«þ¾ûŒé÷ßöá¹®¶ž[­m .ý7`ÄÜhÀb?'¸}ó—¿|Óöé›?ÿ¸ç~`¾ÿ2ÿ¾<l×/ß{'ö8|¿Ÿg¿€…÷б×kýÌ;—½ÙÍð§ÏÝöÿÀ¿®yÏûô·aH¿ Xó®ñÿ¾?ïW|ݰ¾y._ÿùÇó¸³ÏFŸ‚£>{Œ;`þ<Ï;à{ªq[4h€÷j=ñçùýµJSÜÀ]èØ/{`phãn¶/ì¿qî€ëÞg϶Ÿ;Í®æ 87Pö`¯íàúùnßpöùçUçûßʽÞio›ù 7x^¿‡ßà°á+züî»ë†ûšÓõÞ;cýúßÓwûC;~ýÇïÏ÷à}¼Ú=`»éZÁwÍsÑçià8}î=†¾—_ÎסÛ/‡ö—»Ú½ïŸÝÎ}Pð\÷?÷øÎù|:ÏÿÀžqs¶Y°dÍ¼Óæiæg½Ïú¸×ŒKKô[g㬧Á‡³&Þ'Âgϵ½#¼Ñ|¡ìÓáñÆ;ÂtÀ÷ø‚Þqö^o }t£}æ|úÚ}À§®õÏÄü#¼ðn…‚VßÁ‹r¾x÷ùÞ[¥ýô»°ÆÚcÖ(x1%˜êÝ[3ОŸ3´ûûÍÙ~‡þ7üàÜÿØ2°of^ÅsÞ÷žhíY;{%<ñž˜ùÙŠŸtî3²wð‚Öf¸³Gàp5ü¿3¶¸“ ŽCËYGàÝøìµ‹&H® |{ 0^ígÏÿàP¹¯Fosnx¤ûð|æ9Ö(y²¬§Ê.3P&² ûÂ(ŒÝioÓD¦ `Qá¡Îa>A˜Úíwν°ÿS³ÉÿÀ¦2“ìéÓ稜ê nîSÆaÁEöm½Jx‘2o)·ïHØs}öÞfÙ­_ã)}í³ƒrÍF>7%üp½ßÃå¼¼£Y鋿/üѽ9)Þ mgÏñ¿ïBø´Æ~õF·ŽrWŠÝ!<[ïóã™2h Š^I eE¬øŸ¹eá:ó{Vî _83ÿAÏÌÃáLc$z|ç­}6¤ÖïÙ ¢½>ŠHxÅÂ[—w´¦uUgú|â* %ã›å¢ N6&Ò¬ª}ê3÷”Ö$¾¶á“ÃEÙ¸¬€á¾Bþ8 :ŒšwäÿÀ ú겈ámx=•ï?ƒØ/¼ìzòÃ1:7ÍÞ¹¤Ùh~¢I8*ÏK¯/-ˆ—,Òù@2ÖÛAÔEñÕïÿ}€ÀÙît± uÔå25 6¼7#; ánwfe¢!FÈLgWb°ô ûdjÄ&/†#Xñ™Cº÷ 8WÆ9X­ãcf»KÒn®A‰µŠ’FÊrxÅdHh’2 ¦§š¶”ÑÖ·Ý?Œ”‰QÔ÷œYï]Q’‰= + ™ôI ÚFÑ!ŸŸSˆóMx™5èÆOèÂ?¿¡h±âÈÌ8c%Ó,×VƒÐ+ZMcÞÅÓ¦]LBë,B²dMA –•tq?­÷‚fñ>©¯ÿøƒà(K .¾—G g)1x‚‹½\Œ[Ž|–wÏòüݳ#Yžu~Û} \±ÊdEÂbÿaLžx(AÇ}Ø›Çðò&x7)K Á¾–±³ÇŽp™}z®›ý©ÞcO¾ÞcÃGÊ·rrGÔµÑlüÀƒâX³Œ{x_Hy™¼¾ö\_ž‚)Ï-<Ø,X‰Yå9)/3ÜmÔàlótâ©è¡µ»—­–âAʹ`Ac]œ½³Ø#¯SÖvè¸sx¨³ž²/:7kôæ?ºûhëtæ‹PÄ>ñKù,ø ¶YyÉyæÎÇ1„Üx =ïMOÅ׎Ê7Óˆ°Mhç{É2pÈÞ<æ1Ù¯­07ígŒ{ˆD)Ì¢b™·!ÀÊ)Ó-­ÛP|5P-Áp8š¼ËÜ.^â+ó‡-!Ù?!ì!P–ƒ}4žàBЋ‚»]^ ,6Mä,4p¹jã-8N‡QîümBDr¿_áÿì*cךçzvÿ>À¶ SF’£±y¹<3e¥€‰¢7,©“%&™ýÒZ¾úÝS¨·;p„¥¼š{ ®˜Ç’‡Nín†”xx€U!êÃh¥—`(á7+›ÌÀÁH´>xÎZ].’v™ .b^cx Ï\…•ù÷L‡°ð±ÿ¡m+4¼O†ñ(·vôC0ŒQ!X˜w ·™ŽNÂ=sÁzz󔨥ƒ—Ý …9‰ÎJ;~¿ €ËUIb%–ÃÑ+œš¬.(bŠ$úZ¼ ,üs?èLÛò„²rÿ=aEòŽ Fð-Ü-EX×Yö>ð Bˆk¦#0XdðPbÞgp‰5›q[VFÁ˜žwø-ÒlÓÓâÕS\—'ºí0õýdÜ3í¾zy˜–²7W!ÔÍçÅc¾g)4óŸNK®·Â;,Ñ (|D¸gº‚pfOO.Ø{ÁPwó¢aôÊ2™÷kŽö°bnÐ蹡óÛÆkÞ4Œ‰°x µ2N€û„ó0‡2.wôªy ˆoãsö6A!R<~Ä›Üú´ûø6Ò`‰ïéþ-Ô­Š×À x·9ªoèªBLtö¾íý:kÈ!ÂÊeòý ËšÖîµ~öŠà.yâ¸Éøô)ïÒЮ@hUÃ7Ý™º¹‘1¾ŹH(¼#™‰ ‰š wÖnÙåf  #ä6-J8ÇÝ62ÓÌGZö­¹ª ~G‰ÑãÞ›wÜ^ìÚ£xYdÐÖ~l‡qï{i­¨™%þOš0Ï£2«Š«›ü Qcžº¸Ô÷1>šÝn¼÷zö!Zfåƒ>Æ‹Wn"pœÕ䯯ÿÙ»ƒ5·5ðh™šú“rHûfXãY#¼ÜrƒK¼´ýðq§-.Ö<Ã%*A`(ÚÀ9‡)oÌ¥c s+n©4+Ï^„W7:ðŽw¡sNYÕYt-)[ ¯?26û%¥ô·|ᲯÙRâÇÄ ·l±ô=ãÿYWfüͨøûþC y»_ƒ‹'wéå^XCÕ·sy<] q#¾›½N¸ të¥-+YÉ••ý]ÑÁz…§ŠóÝÎ6 ž„ïrº·¡‰ÞaŽÛe~ ÁšûY7ñØR(Ž?[ ¬Sø¼Y’Açx S¤(.e½“Ò1¬<µÐÀ;öÌJ8Æ;óËnø~×¹+ÖL+ᯠî;ü¯+tyŠ'%Êí”CêÚá3'E0¸Íw^žuM!¼Hcg>˜;Ä J Â÷J¡Õ”—„€à¬pÏ÷yÆŸ|Ç·÷F†~f¡‹Ü“»ÓwñºFðØ(nÚ|Ùï{X…q Z¶ì…¼§qà{îgtÕpÍH$fјYPÁ#>gâ`í:sä`4„D¸e‘X=y7 +f€h÷äp&N0è!Î ï+™Ì`rÃH.JZÃØ%þ×û>'R8J÷,«S›’®È2¬ÃÌ\4~Ušl«æ}mÙUI«\aÌŸJ–„k{ÄRÊÃ8(T°æÿ»¿Ïø óqÇiðTLá±+™ Ä«!Jº×»’ðCëIJ‹|.e1l˜—Ü~yçjAJã‹ùõ¸|†±ŠÂRJ–(mü=A] h®iòvF!§‡”³)Q™ûõySüzØßä!… °»Z)蘚ñO°¤7ñ:á¹Õrr\bŒ¡5Zƒ-ÂöJJ£éÿ‚Ù“• ÅDȱ›òK8q[ +º)<í©–™ó«b•5óÊNö&Ü­s³Åúæl&7=R"T”W¬o7 [,å5Ãø$0|“»e>p=BL²ð§®´<á/ó!lIî»vi%3ñIplžR<éÙ9YVµŠ—SÂ7ã2¼·”±W¯!ÓGçYšK@áw}§É㈦PÀÂÎäDÆ×|&ö¨4Þ<¼0Ø8üÊ{èOà!!}RðÄäd´c‘†A«,ð.òÌœsx€¿*ì±i<Š217r4ÁC¤gFÂËÝ‘C¡9O4xR£rL½öHVüf(Ÿ—i£•dÞ‡ˆ–±€«ØÍâtâV' ^p·Á”`)Í.ט-Äe—P_æÅ¢À㸲“‘É+Æ=ä>ŠÏŠ`adG‹I¶x+&@tbWÎXbî墙] Ù;8 #n>,E#»“/´¸­ë¸¥\­Á¼MJ%1>aFƒJ\ÿ˜Ì !®0ËÎ=°îÕøÌ$ªP* 0Ÿfú×iÒ”w«>ñ™Kù À³~¸¤xŸ±+,ƒvâ-º£‹…DŒÑkLJ4¬6à¹Â]r.Á/žÓ´ì¹´¢e§à±ð!^>…œ€›à2¼ë8wÍq´Y+í,õ´RBƒCœbÑ”°i·u]ê̆²ÎU1kÀ†8âŠSà¥=a–¡·P±«µÇ^Z¶¨ã–ï{–5¡Ó爽``TbŒ³é£²7oXH¸Ñ¹°BÆí&àCîE˜zö™=b¿¯ 7x‘}æìäÀJgrfvIê;)Y‡ñÁV®´6)”‹uKÕZç±Yÿ·¬ðaè;ƒ–­Ñà5÷m³:^’FÞsù@’]aHøÜ’Š?²žœʃb¾Ü|åìÜ92*ZA?¢‘ÀÏ^§£E9TNÓ —I!òVø=‡þ1/,õ4‡¥²G«çÕÁªÛà(:,¸;é}ùÊÍø– Yx¶¬x?óæù“<9³|V)xx“!0ãÖN;!˜.:[ùÞ5~oÿë6‰y>WÝLÊWGëJ7°BVŽnQ¼UŽ¥í~Ðð¡ñM–Ͳ˜«Ã9Si>8 éÓ³S"¿à¦ï5BbÕ:’ÏB”ˆö‹’扩ÎYï³Ë× Ÿla²ð«3\¥¨ò¥¢$tÁ#mµ³ôgBˆg K.d$JˆYp0ÁsèÉn²îÖÀ#4;.'1vZïè)â<|gmôÕÕ|7„oX9é›K×mæ9kÏ­I×å{f&U Êã13˜:¯Ä8 o}7чΠÿGmv†a²Ï0ÌaR½Ÿó>¿)\ƒ8\¾ã™àᓲœ×RMÀë–9Þß-1à¥ì‘,^›’:M¥Û|Ÿ¿–œ„´©‚AvSä³á†2áü%³ïñRÌ{ž4ô |ygfäÙÏÆ¬ŠùÌÂ94) ¨|7Ä)súáïðvZ¦äŠíPçDp8Èõœ´µ)÷8Ä»Âgõ7{JIÇçÀ›Ÿ» ºþͱ6XäÐ9ú‘q¨…„ ÿ’‡5%^HkО‰X1«òfá Œ^{y¾§µü$e=–“ Uðµ9ä‡d‘A©¹+Fzäig¼–\¸›øOó–ÉÐãDÛVBÜKåú¼[±‡§Æ=ÏÉRk)†¡· U‹^b',eÓ笰WõCZd gÔk#¡@$žÂȳÉ}[µEãaQ‚¤É5’…Ž®S&Në’¨fÒÏgw+̰!¬´Ã%ËLnwÁߟ,FF8Ç6[9 áz¡†»/5—Ír"*Yü(ïÏ®1ÇåxýþßÂ8ñ9–Ù<¯Ã¹ dmŽ0±W­¢kzš©wóoŽ——R â5~[¢¹ÀŒïÃr1œ#]0ñM!)^÷`¥tâ!…°86?ש…¨ã•¡3$¯5p‘J]û‹b,æ'Èg¡1F±z‡hÇdÝò|˜÷è™beSÊ+bÚÈwôa¦;àÛèÁ¥ó§0Ÿaž ‚`•µë¹ñL4ÍwŒ>ÛÂee•…ïø}"¡é’¢uÄÑ9DKøÅ2’Êýäh‚†ÛÕy¾3h±4¬RmÌ26[píyÅyö¬å]K­•/?}ĺ=å;²Àȹ™”CcŽ Ó )dg!Èù‡Œ»Ðíõµ’‘ÏÑ1AS0¤…PÓb¡×ÿÙv2ê¨ ÀWއÓ:ÈÒ¹¹ò sÞki4+r©L¡Ò•ÏA™aå?<Ǽv{8%lª%¶mÔ¹…Më\rF‚Gî=D¨•®ã=žÍwIï<¾½‘Ù3Á0„oËzP.<œeÖ–çY[÷š\0(‘Cì ˆÄ"æ[ÌË!0Þ Q«±4)žD¥­Tr ÷Ud6Õ.Q&J³µÎÙ8ÇX *¬ ¬±ž.½í"úý™ƒö8®“9Ø›€D$ª›:ºº¬,$YˆJ W&pì–êÆïÒNÉòðb¸{Ïržÿã–“3Z‘jë¯áEÜ“,ŸzAÆ.ëÀUvpºÐpÔL¹nâ}@ÖûÉr ¾Vœ{fì×…~Ú¤²gÃz?äÿa$-ä†2âlЪCF·òùÏ.‰‰6_›×¬\dëUXÍÁÇ&,K`×üÍÜH¨(Ls ûÒE¾ÌD9‘`¤ÿôy ‚ÖhoÅhÓ‡ÏOfjvB˲B÷(ܼàÅ]-¥ç:f¬¨å;+B 6…y,.ö’9ÓL#±¦ÅXô·àµ30Øçìë[]ÁW\âu~³“íø©Ü\_’uQÊ•sIÀ¤íFq€5Êðºø9K©C –ÊŸÈšèœâÖx^1q·Ì¸ùbuÒÄÛÌû®&bÁxó¼0 ¶œG Ù\ýB¸-8¤p#¯I rXg€5çlý®³-/) ff÷?Áóà2}ß2ìs?J 8x¾¡¨‘×Bñ Š)î3hHK¼ø Ò^WòþˉKáX{.$«Õ'y:Åäk+{7š7 Jº?ù¤i¬™DLïÆë dWj9+»øž'_‡N.éÚÓ³G¡/Y±Á÷®=MH€r¹$þK ¶<ïòˆÜ×M‘«Ì^­âaÆòƒ³ð3Ÿ!žß{íòxòJÒû\pÕðÙs0í–«~³âÖ¾çòŠXÃÉÒr‡à C߯͛š0Œ»öpÆëZ|ìÍ;g’QÄ·Jèž.’'üW ó³r™~B‚`Ñeæ€ìPøŠ‡-?¯h±”Ió,¤…¨Ðdð#Ž.jŸr6>mi­Í["¬ˆZÛ!lB þÖô Ï'AѱøÀ‘ý¡„Ä]ÐÊ'˜óÅ‹»Yv$Ó/ûÉü"“fwº¸~YsÖåÀ¸ÊrL–.³ý ±kͺ+–+ppu‹¶ýÓò%žk¥:Y‰á-É߇Y›Ç¶fý{l·Ö)Nø]’;Šà–“=µÌ ½³E©DŸM`GYyÅfZ'íorõ4‚æáÂÖJøŒ—-ûàÑÊgÜ›JåqÌsírŃ'+:g.yšëJ¥²=Ð1gÃ÷ïV”¬X®FñÊsi%Ýew£»’‚ +f'Ÿ¼Q £¾·fëuÀ£•C欌ÇÀΤºò(©Q„·Wž f/¶À CgÆ_}‘DCÑ2Êuqf%p?-÷õán1œT¸‚SèAPæj6®MîûÌ•Qâ î´,Ÿ5¾“ÐGÈ#ž®ÈClÀAø SÞƒ_QÏ5s/ïô¢ãù¤\~1†þê·ÿÒ^· 2õZ:ûGGøkÖ^ 5´U±IŠÛ¬tù­¾qÙÞdšîû†¿*×ëpÕ)Ç„é †B¥›Œ§ê ’ý¿i×(Ø ï(\Oøa^r.µ<+†piÝQHRñdz\-,Yø´Ù€5ƒî ™|²&ÖY“¥å²ìD„U6Zk›ÁALó‚IP}y. ²¾XèÇ*s€iÀi „• ö2ºxL1ô#£eAõô¼î™U fªìøšŸnqVòÂ@£É¸Æâö´ÉR®$Ë.Öf4rU !ZÙ«©Ajâä÷»Æ²ç£`NÄn"¼ œÁÕ4äC±dï1º' [ŠmÍçæ(1¹úŽïyÿb¹šk3sægøž“âÄBR2ÚÙÏœ¹½…e8Îa?[Ø#­€-–è“EöÌßþ9Îô¶ÙÊa?7…¡|š;î9 X¶"c9ç.Å­†ŸÐ ¹µ:|Fã‹ÞÞ3èÞá‡bƒ†{âN<ýƒæŒ‰K}¿Ì÷ ù ù¼kwPb8lmQ9T¹ §° =/æxOšqF` ™`ÿäQ<ÌŠÀïr»%a¯ûCÉKYÆÀ4„+ ¼q¹§{Æyß+ïY±§ð›³'Ϫð+"r™·#üÛ8$CP´jÏ÷/ÏÍÉÜÎþw\áí}²Jÿ){üœ\Ö{ÀúƒGB³è©å”9‘_©ÿßi2s“e¸”ÜŒ†,‡\uÏ_ KZ£B2'e­h®øMæ-—| ò1ImJôª ’ÑôžjÏk¾À;ï{ùòšŒqööx´d4X$H&AŒï ¯ >Úöó70côs-{d¦ÒšYÇŸ#ìZ+t­xmfS²\@H²€v1$¢A`wu]"ž;ˆ‚`Jœ”ë"‚Ê—MT7û,"–=h5F®dè-.Æv#õ<-dܲ|ÛÊ“*|kÖ1Ö¡±ž‹³Þº¦o´@(ÀqT-v)ª"ÃSJt!˜«|“ˤ!Ìcœ…›³ö3ÅãgK¢÷ëÝP ˜IísÃÌÌ pK8:&2ô^Iqn˜aî8©´ÝgWgð?^ô¢Eñ£ìhç›6†@HIúw ˜BÎÖy3/X+]·•ÿ“;W²¢%FÄCÖYÈs\®[òšk¤$^cÂ''á=g¤fL”.0ŽÉ2CaØs9L?Š¡D1Öþ ¿±gŽù‘@(wÀ;)×$ Ó^ì–{(x¿sfj+ÜnÕ’åMgöžôPppýMÖŸ À›1T÷û&P@¬…Ì4"ôê‡'¦jVÐp)–ùÊ:•¬|ì­ª°‡®•Ï÷²ìºd Ì/I¢D#±4x*É–ª á 8é÷¯ùW+±ËxÚVž.JXd‘9@‹Ò™–„Ý­† Ì­T)tììMÎìÆ«¸IðÓóežjŠg¿à œ^e7÷¿TuÀ8Ö½Ñì.|¯™ºC}|b“ƒ;½ð€†¤ž•€³”Ñ»ÑSøÊ« 7¡ ³àí{¡áHÌóâlôsÿQhzé–KóYqƒÑ'9RœuPNY¨€¾Šˆ~세¬]{%X²îXrt'V&úL CV²ôÛp¢ò«àîG‘ÊRØ™×>{?‡öœÐä5(2ÀŠvÁ®Œ[i¥Kâãå\‡? ¦ ¦”ñå<"gzߥ°¿ñfÀ„uȘb~CÆ h Þk¹´d1äøoÙØþìCÕê™/‘ì¼§c_úh„W-$ù꺦ÖãòÕí‚–]yhÁò«Ï" XàœÄŠššhËÁËñ¡q~Ùmµ%ò£ïœEÚ0ëL´ˆ¯ãŒ“uF.ʉ°¹D=)Þ÷HˆÍgéò\C„w>üÀËk±Ê%Ã'û"(hýÆP Ɔ`;¼Åãeüxõœlá2Cê½ðKq«s,ô!yWP.¿fÍÊ“[΀s¦‘=,§LŠ|¬®Ö]9|v;÷³Åvn¾ßc(ÃTF2½ %?¯‹ò©ó¦k4&ºO7¯o¦ Þg – c£<Õ\ƒoFXÌ,`­ÿQvw9vìFFk.í6ðÈŒžA¯áOªqpA|—^ÚÅ«‡„¤£L&3 ÆïŽ &SjÁ6ÒðHÚ‰Æ>ëL5@T«Wdiæ(L ¥T}•«„o÷x(Œ6+´!xÕð‘>|y–ÚtžQ”*‘‘ßýƒ]"Û+pxÙ8*ÇÐPÝQ±ÖÇ=—#áb´Ñ¨÷÷†èŽPóÝÒ¦ç_laRì»äkfƒî¿C{£²>xa§e{qà¢½kåR–ðT7/d¤ Ò÷Ó`[´óï:²F4àRÌ ‘Ëû[¤ÍC'i©ßË9T~i"¯oy'GDsËëG-™ãp-”¨‹'ý5§F|ANÙK‹7>§Ö²gÙÛ”Â'ýSÔ5¬nÙØ{Ù¡SHÑ»„g—ld€ãLº÷˜c†ð^ÝåÙÖ¡ÜL¾ÓH´CðÒá¿Ã`vœ^ÂN×;  s~ãÎ\û³ó\–»é Îú~2‘Èg<úÛ5™K.m#JÚì¾õ:¨©IöüT6ˆa¿ C‘Ôy€´HçWæ=°Ÿ¢3ÆK]¾£± µ~§ó‘d€=þ\:ÕÙM‹tfÀî8™–³,.ݳs`ðfc ÛÛ ÐFÉÍ.u’§¨2YS:ç¼D8†Ê™•¢¦wþ©Wv&.§¼1iðåp«CUs;¿^­}²Ë:ß6Ê{¿e §óèœÙ±_ƒa sTî.ÓEì3~ @û¸ªT¶gšËþC(CŸÉÇqæ|ŒÛhÓbqÛì r=‹ûˆ’rH‡ºÚ\¬‘ø0{ŠhcBG‘SrÍ,x®:8Tº¤ JåâKêErŒþ/'ÓFkì ìÙ ðçðä9°TTjû‚°ºøäd¡XÚP$:  €ƒØWÔÞ'úõRù´‡rï§Wë‰f¬VÂÚË(IƒO\_åüÈo¤qdCùŠÆ·‚\Þº€"¯¬ƒq‡‹‡h‘õŸ¯GØÌ*Züu¦Ì€Ù®ë/ÓÃùísû­'<1¦ƒ }yfGô®Óƒœå!ðÆ&Xoµ@îßíí¾'éÜa“ Í7yâºJ{Ë-}óòZ%:ï›ewêO}?À²gu‘¹²ä_mÖ"ü@—pp©”"¬LWcƒÅqòFèw]乂¸oŽ(…¢Db˜îûÚüÔW” =2Ñ:A/ªñ)=8‡`c¤,ºñZZQ:Ó×ô› Í<2}s§¥|£"w?¼Ûüã««¶Å9É^Þ?¢åðç›T¬¨ã½øã½–'#ªLÛ¢ ’&ô gîíõöoû³ºÓ³SUœõïV-Ãø,ͯ{|Ù}ýŽâ=Ë5RØ»÷nÁUdtsÀɤñ¤òùa»¢ ñƒgîŸí)E[ÿ«™&ðû’å¥óíñÈŽ znøСûŸ;ùÏn])Eõä)E‰À_9ïTNX_›¬Ã‘6‹qœ&_,ÿÄ­tnS¥ƒŠ‘ßâ\·â-w”-º©ŒYZö-õh©” NÍYWþvHlym© (òC§å0JÒáfý¨X! 3ö[Q^{; ºKfpŸÁž}®,Gð; ÎR-×[y§®'Øš(ýé¶e9>A,¯wÙöK} \‡åDª3 úÑ¿é¤ÃÚz&üÄIãíý£35 ¸«óUzT"{mO‹žR`k¥¯€Lˆ=>ÞàŽöè5x GÜ9ë‡C™–Çdô :þ—Ì"Òj-Ü@zÛ5ÚÖÈßf/q#¶nLÑÆ/"ÅaÀ¨žg)¤u¯q!k~@Ñh{þöìãâ°z¦ û{)žõ‡M9èßÑ^Ïß)PÙŠF¶ÂdJL4ö¦Š«8zQ‡BŠ-ÿ'ÿÛg^Á¦â±7QƒIE\èñgÏà8´Fí-÷¸4@墽ÿÏwP7ä~ÃÁ€CJc©qRT£MF |µk«ûh—óðR„ÁHÆÞ4R^Ò‚ìïǹmªå÷»ûSƒs×\ªè"ëÇšåHÜékö]€•®¿¿zñ¿=×;¥ ƒ6§!s¤-Ìì¿[Ô#e*°±/u LJOz,ºå¤E‰{œ;ÖK "z x$FÑ’“üÆy~æaïøÎî+h¬}ûrµééÑ( ¹èu $dçu]`¾âþ€¹sæL™¬•i°C¿±÷6€¥çò)§(t¾ÈÒpÖ<»&d½ÉŸ´âÛivÏMÄ|yaÜHÏæ4Ú÷ ùcm÷¥¨‡ÈÙsÖ/LtV˜ê„ñ˜C ‚ŠðMƒÓènáD×­_öPv^F›Â5O±Póq•v|‚èÈx)Ì(ƒ™‘Pi37ßÒlRb'¨FóŒÎ¡ò ÜGF·ôx•ph<ÓéaMTï…-pއG‹¯ÑÌÐÏ«]NãŒÈêP>éÏO:¾­Ïv„AP<Ÿ‹^µ«Mä9­áÚY:†4FxCÊkš®½-b®ÈžÍ³Ïö$¦ ÓbOž}g†B<»pHùEŒøÍ=ñtرLÑ 2Ç/Hÿ€Î¹&o¾deÑUÆtµK„Ž–Ý´ßrÆBG¢eî‡ÓƒÜl‚îÏÑ%­t8JÓ¤u÷|5w4D®±ðM©™«œ8÷„‚Ïœþ(ﺯ±O˪+‚Ø#ÊŒ¹iOŸêôÎÏ~h•ñGD{€±–±¥ó"€ÌoÆ-«W}ˆ.bó4ÏÞž8#“ÓÀ÷1èã €·wËjïÌ`k~ž!‘¯¬(Êùã8¡í¶$íÎ’Ù9.Ïï‡>7\¶`ðç×(¸ dïL8û¬ïŒ¼Jhà§dê¤S¶v¥§c—1u"…f¯¤=âʪÀz¨U´-ì ¢äÄ¡­°™’=g»Ç~Ø¿w'­i¿º¾õõ(R¯*¯î0ê4Lr{zìµmj!ï³n Ja3*£‚lÄýuÑ:—mͼ¤4%êõQ¾®ySqt_mç Q]FঠTïŠâØà.YhŽx5ßuH`[+]ÑkZsÞ£4`Ò :.—aïÐ1ˆÁÅóµ ÊÐ?éègŒóÞ%Gqê²öz´qd¥çjü¼îÛÈ>÷²ŠCÉnʦiãb˜L˜['«„ˆÙ¦u“)Ñe(\qáyv¢É6.ZÏÖÍgïÚ­·[žÒøõ0”ÇŽQ{hh»™Œlª•«¶¡1úž€™EÚÚGD/Ó‘n¢ k„ ð³ -ÏÇ^†Þ(Ë­ÍDoHÉ$:â!7qpà,!Ò-Řñyß/ÑÆ#eƒÛÙÅ<«A.…Öõ®íùÛPG¡<Êv8úWi&Ï8ƾLq5£‚(äÇ ëÁûl=¬S/|tD¿õâïÖÜ\f'z…›•¤#üð•ÈÆ¢mtxàžŒohì‚xïKÝVÚ)»¶Üaììí;íŸÝ˜ ¨ñ‡ÆÇá3ë±ý]:[ùè¬qík‚:Ã9Bú·‡³l÷Þ3½‡5}¢¦;®g™÷ldƒ³Ñª.R”ƒÔ<—žeOPÚ¯MßH™ÀõÐo¢nÄÚ-hà¶È§]Û‡ù›O +õ—LšÂWÄèxÀ©;J¥©>Â׈-ÞU'Šoš—¨–:8T®ûYCƒ çXoæ<¢ò£ Õû²ÝSŠßLÄࡌ4½Òþ£S‘µÒwI«¾ö&ÊmQ~›§*s¼³÷`h`´´ùEãJvÓ”TÈ£œ£mñU©­x|IÅÑGZ[ã¿å…4P†ÍgüíþŽ-ÏøÍov^‰Í©«6}DÇw8N)À9ÁwïZ¨ƒ&k-V’ZV‰ ï·´ïÌ– C¤ñmE¶ÀÎpêŽ÷w?¼Žaí·ë,ºÏú»àn¸è:ãì^¿áHœ­k¥™­–ZϨªÏ¸´[{~x»/‰déätý:‡uâÞ]·z‚Ä@È7u)Ø«¦øÇö¦o#L^P'9kvŒÃÚ÷<:3Fœ<ÓYÑþâÌ…^«ë%ZD‹º¤èø­ø Ÿw”UGÊóÈ÷@~ôÒé$^J{=ý’s‰toudÈÈÖ¼¿I}±±Ù¿FÂË4”6ˬu°Ìʳ-½ÃyµÖñÏ4~{#™™sV9pxBào@6'NÈ»m0¸ 7˜œQ÷¯?m x+.ôüžÙ{,"‡<¢8gvˆèu Ç­8Šœ†ãQâBe³æ¡÷ƒìÞw+ø¬CêfYŸ»§gZ36¨ÌHg¼Ã¬%ôÄË¥ê&(­«ÝÅÛ¸êmL÷ŒÞ^ wê™oü{þ»'¯hê~3õ›G‘8kÏkFj£1­Ï…„R8~OA”^ee˜Vl‰Iu¹"/Ÿô$ö×ï¡…m"}ìÛoS¨÷,)Wf#ø¼å>W4¦q22_Ž â6J<%Ñ ¹ôh ï{ˆáœC(9ýFp7-óŬœdxóÌ´¶U"ÆEw.ó‘Û]9*R²šgШç½Öæ¿O»™îGM±Å8˜@Ba³„vÛŸ¤«¿°òtFöù3ã–¢‰bÝ}øñžëðkÝHF†Ú«Åà+Tð@;­s­ŒƒµåœkJðcëVvÙ‰GtŽëtL1º/oFS÷X_ÖC<˜ýÏ*Û£‘Y’–<Ýû½r/Pí?TzWã£3ަǡËGƒâßl/å»´ÓPßÝš{czrù‡µw=·ý–K2 ùx9K`ì>PcrîXö0(#Sq¿´a¢ãvHh€ä=`Übo ÿö;zÄ…r2Lü¾@뤑:>Ý;rúòm¬c+i³vy‘=peþÝ;÷Ô·bÌy ZïJz–€;‚wµ,ô#7Æz)ç!¿¢4ìhu@Á3. >×IcΨџñªYÏ ‚v¦ý*8/¥i"+ïCÞÍadTò.ê†Ú¸E¦kƒ'¾6Z7[dÜ ³&å „³ÓýþëŸÿ×ûIc|§’ó›-Îâïjv1zj¹ˆ3ÁˆÏrF ÉKg{º@ÑÞÉrÑ!6åc§o‚•R9a²ü,ѯ5nïvŸkc#ŒöNü‰ó}èsKÑq€l‡ÖêÐÄ ®ïжÛÏðP¿a/¬µ ¹tåJ Æ|8ØwO2"ã¿HÁÜõÜÿp´Ÿ¬åæTé©sµÄ7Yß¼œÁõŒp•ïàIÖr´¡œ5ï!Ö¹‹ž Í_7R±g©~å ëA<ßçoO2i“»æ¡Â÷Ò}#ÞD)²]ý5›ÜSq¯ï‰>‡°2ðê¦àuÑÏ›QÃ'ÚC×Õµom³Ðú-vEq(9ð’&¦ü0ßå=t“ìÌ€Þ—ñq#BZ÷^OkÇ:0MKΉÒxDÕ¾¯"·¥gÄŒ¾²/o¯ü_[¾Ó4Â;³¥ƒ .£û0É Bú‰ž~™Dm‰ðšgOWøšIø ïƒwÉ?z“’f1‘•ãI¾äÕ™rîF?üy9Kïª]#‡½N¶:©‚¢ß÷ yJ&ÄN»ëŠ—{wN“±¦ؤgS{4þ.ÕYÅv;\à]»] gÎ~Þ™¬ÜÑ=åûKæ£èŽè-†ø¢ŠuÑŽQ÷ž’§¼¦#FüÑ—ù¹:ˆ’†ÙwBk…¤ôy¶±ÛÀ'²Ð¦zôÄ ZÞ£¼n ƒw½Bgd=ÔöR”Ž+rƒ@œžÓæT:Xÿ‡R÷¿ßhQd´'of<êܶð(ÊuTi@:vôÏOÃxâÀNANY(Ëa o$ìÈXd¼ç>òò¬Išß²@ÖŒ9?dLϵ†ŒûÈ‚zd²pH]ò§/e0ÃxÁ òwãá\ÁHC!Ù§¬†~ä€s‚¤N— ³rä%æÛ;pŒÔs]ùvd¨ãtý½¤ ®QiQì{7ÝÃ@býä•Ö }d@ ¤_ÀÑØÔr”¨ô8NjgÌ 4+Ðsps›×ëÁÍÜåywíóg¤~G­ ¤DO²-pÐÐN)#3õ’)®üîzö DRÉ !­ÿºwõ?~•D ºúÑ.~Ë^ß^>ùÁóät•@ÿ?:ИÏÎèȉOTýœùOÀËõ>.#ð¹xïphìïëî`¯‘öïÞ²;L‘ï­W †y=ï. uíox|Øœ©Üæ iì¶“ö»Ìˆ{á}qžà:xK¡l³³.Ÿ².줯67çÕO7 _…È…í:ÂËhFɻǪ—©±×ÜÞ”ˆ*`Ï…àû“!iê¢挭² =å—Á4ö/²5çý™Óº.*_|0Šæ¸RÎZô6üEä&Æ!jšp)‘‡0’ô¦ÃÓMÃûEiÃtÕÝßïïm4 Ưވ9Ý2ièÌÓ#ŠwÌ~7•Ia^½Ï•¶ã‹®lhj“ksÑÅv9Q nŒèÚ†ƒ¾‹^}ÐrÐ7м Á "Áâ2ò%5²òì…~­0æ6øõR·U˜8€ÞÂFÒDÅ$ja ¹Ý9™5RƒI·þâ„>)¥Cî¼ÖÈHTô:|BÜD îßý¨_¦.l~ÓŽ&MP7ž3*°ùé*a°–3ßíÜÞ—tÄôDbwíà“Yβ3,NÉZ”H¨SÃg¬[®“yýˆÿPfNƧ%Öuk¹»‘Œúåìçz97£¯tâ÷êþYSÒÿÁô¼ßóz÷ì?søGÙ‚êKf4>Z¨ñ®õ>¯ýŒk ½u2þ¹ì²Œ6±+N· a¼„UªzýY£¢®8Ê i¿0'ñŽ.ÙýµÁ÷~Ý9I¬^ÜKÇý¶û+¥9’“ÓD‹+é½Ú©iŒ›¢­±Éwwæe5ë±oÓ‘k{»y6ž5KÆöÕ¾uÏí¬B[‚R¯œÇ®ô²Lëóï0XÀ»³üTG&|:‚©]¶@4“£9½†½ÐóÈÇyðÑäFcFäÌPqŒ‹Œ©õè%£ŒÈ7dcÐŽÕËè%Æ3ïÛqÓ8áêXÿþ™×9Ÿ»¿ºt0fÌþ"BÜ|¯sþÄDAuŒšIBóXÑZÜn£`ñ€éî]Ž“ãcGj=ws<¿Óµ¥C-o^km3¸‹~G‹²µ^ýåL9χ.ßYFˆÒf$êPÚHÚÝïõWrÈs ÏßÌ®KGºp'®ßg9“÷,ú›îo©Ù¹XϦMÃtwñœó`ƒxí’³SöaVGëF°%}ˆo¯„²³‹V˜¦#[óØn·m&˜dŽ(öYßWù,ß0x}ð6dº €¦|;e0éþÉü‚º8¾Ž²Ô†ëßôIþ®ÏâBiAI ƒTtSŸ<ˆ+¯ ½y–1¨‰«Í’‡hs{Ø|€$Vn˜í…~·(²øwž²…¼ùIg9FWF& Q „Q3æÅAÈ@,3‚¶p91T4KcSAIÈË ¿[‡¬á4ê¤FrÚ5ñ*¥1AÀ\¡1¼Õ7#´GŠBƒžÉDwÈè¥ œò©X»Ýu±8a] ïeA6q8U^ 2ß;à“žÍÁ†qþÃçQ‡ç"]¾­Ûý‘ÿPFS::䛞A¹,ÒÔÞ× 0‚ñÆ(ȳÆðc«W=ïÌè&Û…ì2èuø{fv\NÊ´Fä ù;àuœù~Œ¨Ïw^iŸm¢WO™ÈéB¿g 14@Z/é7ÚŽhº­ZsJæÜZc: Ì•þÊ|™›ó~ïŸKÇê”üÔrs–=ÞÎGçWÊ>{U'õíÙµðÎs§Ì'Ktœÿ;há‡.dE[‚+ÔƒÏL&uTd¾ú,åF\Œýî²/i4±¾»@ÛÐ &0k<úû—Ñì'm4x•Md&€Ÿ± <OÉÊŸ²õêMá!ä̦h²ÊÌ« J»÷Ôûò^ V³õĸ˧:;IÝ׎hí™kç|»m‡ä·ßdࡵˆĦ5“šÌÎAÚ¬à]_k½¯.ô»µ„ù÷¯š¸SÛÛÇ4¿÷†ŒÑÛX*N ¿Æ[õƒ/6éHQÄȘŒÐý(G‚5=‘D½|C³ïÜïðÈ™SJŠJ ïµq÷á´ýc=•„ #<àbrÄÇyYÓÒ;-³¨ùáÝ ·5Ïy ¿{®J»ö…÷&ÌÉ@˜Fù=ðl¢ )ºy!™SrP;>"‡¯Hªôó»k•˜sÏbÐêóÜé‘O¤;‡r†=ÿ)ìPhr¤úÌgN"á*—â¹¢<ÕÆÃþÕƒÿùÞ/m,ê_S¦Ú£ÝNòŸµ¤ ‘Ðx•3ÍÈ`ûº¡Øgà5ûŸµ~õ»¥\d¯è™Qßéb {²¾”ßÖCïœ8ñ^åuÙÙS^ÝñÈÿ3wo?»UWÀ÷Ó&^“jLªicðÂÃ…Ö c¼1õÊS{c£Ð(µ´¥4ÆBÐFƒÖB­¨Õk[k[R Ð弑CÑc–ïÚ_f&¿ý8Ù¢…¬ì½¿ï}×a¬1LJg<›¥C®¼Z›×dó‚`[Þ§rx„‡¤îï³4ùV¦d<&!Þl„dN&¨ÏʸÂçÜbb ï­±M3· |,%qäXü § uæišg1/ŠN3ó.Ù¿`Œk{_CŸG2W?§Þç;&o­6[”8‚T¿±ø+ëñ[rMèßô)O­­r¿žI_ó\Èä û~Û™ñÌhSÒóÌÞ„\@…p=`ês3î9cóïð˜tsäêäÛ! éÆIL‹;ùèã÷"ôyµsîå}¯¶ŸÞâM!0=ѪF}JìeÀ8E˜úËËH¶ø¦iïm8˜Q 2õT¯„ %»< abädg¶G£•óÑW¬ û}%膩8ùb£©â>õóØ"OtР) "N|'€Kæ;çØûXDŹ‹èl!ãã^Ù¸@ŠpʦšªÙ+㬞׹¹ÓupN¢Cû&?Þm ™ë‚q3é}J¸ìÔɸ2gUUP¬ œ»5c«ÉªdÔi ÄðL2õ&&µ¥nî‘{f´ºá5û¹W¡Úh¢æŒõ`ÂÖdø%zó³!>ã¼È#‘äa¸É®ìüYž‡3 ¨FH*ÕÜc2r–÷ýX]æ™ÙýýBj?³ý“y¯§\ÏìX;ÛMF"iÖÜ$&|“ˆÌ“xÆ6̾‹ü¥"#O‰8 £$/´ &oàãçá'Y$ ù½·x"Ó‰Q¾œˆûú;'M¸ñn²×qn“]‡˜ÒB›àÏ5dÑ|ëÎé¢]Å*H©åføÅR 0šµâ@Û‹•uàèDuTÒ¯ïÉÞcñ-ýÌꪓ@ -‚Y Q{1¦×EGÒ{êçÀ_ŠîkSŸkØç·…³LÊõñ‹[{ŸýÕ+XP7¶† J*eµeÎ uÒ`² ŧº)y ÇJöFN6 ÎÚûM–× P9 ÕHva„X@­1ÆÕAœ'¼Ä©Õ1“Ñ2ÎÝÔ{Š~(‹T aî¯}kÈÈxÉÀò®x†‰}øœž‰‘Ê-ºç° V›UY*ó»F/€I’$ Eœ6~íðÑ“Ø;œÉùô†Îo!Ù@~Ñ­¢÷öZú¯ ,㓘zy5¹Ç­ßˆŸL¯LãÐá‹cÒséwKø¹‰lÖm'+U~Bs±¯Úz¯Ý×!¶Z¢>ލCçÛúo-UØ'¡,Ï.…’0‹=€ý€56  [ÅÑ?š×”H—…ìDg…¥8~€ó´ÓÊHo%öX½5A,*c*ÜÌU)æçè#äX§üžªZYCg0–Pfúô'8 Á~ðb„maÓç Â˜$W&)UŸIÊè5öKbQ0È3×:?d,-¤±åÈ)Ï‹oÁzH0Þ“¹ž7òŸ}®ÍÏ÷{©Ä„瀶[Ø1te ;Æ1%Uã{-'.Ä>HüÉ3XYŸPÖž#²ú2_ËJuΛâDtw±fñÜŸ²^ü>IÔ¼;âÄÄ^GNÑ'‡=„YÜH$pëÈ ˜sD±=˜ÍS¸=²º˜Í.ñ²îáÒ2ëe,JÝ0öÊ¢À‹M"½ÚBx„ YÁ.J¶«£q\É<Ö¥À´!h@ºÊ.¸§<¢sŒîbƒ¨sPc &DpO`vÑ¿ò™‚\ÉŸtôù¦J`U µÊ¯É£ƒ¬Õ瑤h`~·XÿŽ?Êû*'DH=Ú¨üN;'(Etc¾ofs“XJ%îtü8Âò$«R挧[Ãå ñlIÙÈsð;‡]â¨õú¢C$H7àå ½†œ': lwÈq^*;~9e‚ýÉï¸/ä1¬$$e$`±‡<ëvfÔ:£±‡¥·}’SÎW‡v&0üÃQ‚d;EìÿËsè 8y¨TËårr ŽÿÇfÃy³B!èG™àÑÁ'ªn² u"@ˆÑ€êO‰Øc}•v˜º¬Ä7&nõ—:òz-½˜¦@A.= ¸£&»wD{©=öcÕé-5L|ÕÖ"ZHO¨¨=°ÖI˜â(q xô|£ÌgUy¸PÉØ'J¸C“AX“MŸ`ò îy,!öºÔ€¶Wž»Ãc–2çSF9ÞðŽëd·°K iõ#ב+ï ÏÑHÑ™ù6”Å™¦$"‚Þ*{Ü řƸaø™i[f›õ³oVÃ6Ïs³ ÉnÒº¦maÑ—|ÖªQw~L¨¹×YŸ™úþSM“èÚê(ªPîQõ›ƒ¾asF»Æ¸Ÿ±éìÿ¾ idxzÌètƒ‘;SAžöÈÙóø^&‘óÍk‚w}·âW ¸Tf—dCœ‡ê`KÞŒÄ&è©0COW§>ôõÑY©Fp¾Éª•$¯Ý{ý޲’¤N®ÏÇ4–iíºçt‚«˜œ£TcjV–uAª5:± gŸ{CFâ;alÕßá˜xý$QZù¾|{%ÐÞ`×{YH†S sNñú|ëê~Tônl"Ï]Ú8Õ5‹8èU'*,“D\¿Ê½®Av6pûÜ£É#‘¹ï5'NçÅÀž!e\$\Ig‰Lþ(#Ú(z³ýô5$Ç…:“Ž‚´ȸ¡{è0ëdÑâG ‡¶XgÐÃ]ƒíøâiëM$qj?çºêw‘#~Nk‘Ëû¦úsgjM|¼ØAÎÁZí†þgzÚ~î' +]c²L aó7eÿÓ™+«2}Ó‹9‡ÓìVúó\Q¾^ˆÑR*¦ d}øâ‡< ›5 bÚä‚9¶àmÍè[‰×î‘ÉœmG쬮ã^qÄyÎ‚Š _¾²þC~\րбé)Æ0F²¬j)oÙцcÜFõt™7­?‚€UÏ•d^Y;½OÎC ûZˆfHò¬×Ñ °éâ¼… r?‚lb:õGz]Ç)ù~kBG¸a6ñr°®ÐÇR­V½¨œÂì¨.åîû^Þ§ã¨Î|l¶d—–aL’<™Y†{¥U˜q“£ºHTÈ’"#gö³¦°¹ØNœ¿ƒ¿·ê<G¶”r=¡ÂYŸ}ì]Ö×ñ÷Á¿ò(õ¯WI“dÏ‘w‡y¿D¨(ºþà/˜¸7œAŽþ´6žì=ðטÄõÆþÌï¶0K`Æó•¶uÎäo×It#IÌœa3ýC¥s”ž{äJ€€?ÀþhËE÷…ˆŽ-!›µƒ]ð}ƒâv¤è¿úCÕ/N˺ÔìGG‚dofÿ°…‹@y¾í>{+îû„Äq-R‚,÷X æ™ÛŽÞ›xT0©OöIu˜ÐgÒéiRÇwG+{èbϰU±"iY¨1I’™Û‰eÏ–p$˜R6°JPå¦K6‰RAÁ,˜éCÁ0åÆ:®ðV¦ôΪØcQÎzžy4›O“Éÿ¬°‘!†-›hËÐa :DFs”ˆÜhã”´ã”α„ÀvgÃÅÕŒ|™×_¾1: [ä>¾Dl5fÃ{®óˆç¾Ü?ÉRÎ@©ÕKëýƒ>³fË{d´YáÚ@~ô¦ç~ô} a;¢GÏkHˆRß‘N:Ûô„s!rÍIÌèžõœføFÒæó’;×ÇPö×ôž ;ðì ˆÌQ9Ú7§Žù}å¯Ã#âØ6Ž:‚.‘\î_îôÚMh‹Š´ÃÕþe×)öipiŒÊÓDRÊ~¶ð\—58C…%%kë´¶<è[Ù—8tÚŠ²| êOþ¡dñ'‚±µfJØrˆ i¬ú¨}>ŠÄOÕ1²Ú¯ Ѧdd$Ë>`-cxXäCê:6‰B²V)e}¦w[Ĉ>úeú‚Ï‚Œô¹+iÿñXe)\¤Rü²±¥ø™;O•¹ÖDP*Ó‰MÚ÷}‡“,aÚßҧ'DfA§åú¼öÈfõ{ùlÐu5æ€íb“—(—¶Å¡›¬‡<ë4}‚#ò¢¸qÚö>‚膨[æz{iìyi ˆ= :iJúÈkd’.rì{ð ZÙ·‡ó“R}œ»(ÙÄÚ÷ÄÐfƒj™C…0ó™`<Ûcm¯™×Òù’œNGé"ËýoÉT4®€!»¥ãÇSVÌ$OüÍvix³ ²ñDZÔxçì=ìÃp¦–…èoúu,Ý@o̼­+À/©R4O d8û$dh{9€AÉí€2DC ’] ´›@©Þ’¨2€Ø!/ üö¹vû+Þ‰½<$qÎ&Üi|!ÕdÆk6Ê Ž…ÝàYR¥‡¼È ¸>/ãѨhÇåœDñ—G3Ko,÷åBþ23öV~âhâò½\?ûÂnÿŒ~­Ã3–½¤²œä™ Gìëm†óXß…ø 27m£$ks’; V`m·Ï=yt¤›:* §Ußúan«ÔþÛ t–_‚ÓŒ'e†ó” ªÕ1¹SìY- ÇÙº]ïÄ~ hFE”k¨ØJ‘kXth>Šk‚™¬ ýL«Øú¯ –@16DÏ|nP#Y²"ï,S”ë[ŸÃ ×~)b…°ÄTm’û#ÑÑgÛ‹Žígô#„žeÊHÕep­OÆxº2Ž@þMŒä´†¿ܣ²&¦¤c“AÁåÙ[ÂzØlö>cÚÈÈ6ß³€“s(Û¾6–ÄÝiõ;qÉj2 cùf™ª®ŽÚÎ#çÚÜâpbªRçENŠQ_ˆÁJaýFH¼$T‹9×b1®²ÏÉ„E &ˆ[%¡rF!Pò¢(ÞOŸ8 /•pzËqta"ä:ö††tç-ï½iû™ËnÝ~ùcßÜŽ®¾g»à“÷l—|úävégØ>ð×÷o—Ž‹þòþí¼kîÝ~ýOïÞ~ñîØ~î÷oÛ~ô·lo:ÿ”"“)ÏõYÜc³_ÉšÙõcS1X>Wìú:ßÀ~ãdjã-ݸýìï}ãX¾î²Üeú¡¿9¹½ÿÚ{#ßO¾L¾—ä{nY/Â4tIlÌΪkÝ! :F•ÄùÉ»ïcXE’ ‹q7°L8•NN¿¾za•@¦X²¨yO y ‡:Ú[‘¨âìäCúC3‚g¼'‰¡h%É;wmvä‰÷¼¶Õ&_¨&H c E쬓+å»|p °·$?‘£ñ˜Í3Ï“œY޳eõ)÷§qÖíÜgäÂ,ÙÞÏ»ëÇ~Bt5ÝiëL]qýRXê`·…Vxj'ÉÛŸ=ȶô-b2¦ª•ÖJÜź‹“Y×ìšX΀_;ÚÖŠ:͉ξ¢Ý›*îܾëŒ~àc&œû…S¿ŠÏ"3}Ž>áÈûu¥ŽxXe2@Îa€8s,ìm‰>·'ÈÍZYhÑ^Ä´‰Ê+#"–ñ›g õçz»Í"‘?|’æL(; ÓâÇ>ÒFl–àoµöhÙZ¡HDoe_)£ˆƒh‚¨7òà=³‘Ä\#wÕáßfãÒ6°äwpägçŸð\«ýC¾¦½‚ÎÂÏbÜŒ(N PêT3sÃûôBטÎù?Ù(´Í0nY»¹?µùšÚÓ?Xú­T›¥s~;pøtϼóE'cþÃï»y{ûå·m\{ßvõW¾µÝtÿw¶ÇŸzn{5^xáÅíÿxf»î¶Ç¶O|åÑíÝŸºo{ÛG¾>ôglzÊœªL˜ÞA(¸…u<º™ °ÐY£Ð;ô»öűõà­|uû…+î8–ïA7Ý÷'ßùæÛǯ{ø”|êÒ[÷$;ÉVÐï ¡õ™%¸ Ä '´ö Ð?YYÑ5ª0"Hõ•M•sÏ2É®BzÙ’’#ã«Ó¬ü­ØI84-ð5ç½âИ¤ É0d¨îØRŽ Ð,ë„ë@ò:«Âõ”9„VÂÜ"GƒwÑ>ÊÉw7UˆA0%Æh›c‘°è$!9Í}ÇŽ2fÓ°D©½‚(ÒËfþŽc×÷oí”ε•¸Â|Ï÷ËázR6ØËFºµ"-c·j•o ®¦¾r¸.¨š'Çæ§Ò×Ûð}fVþ8ç; „u&"qòC`žŽý)í2&ά`fÝ‚º¬I I` k~BBZn/ìà… »@äû<íªè¥•~[å“‚õ."9»—ˆ¨1¡šD…kSB6žÿÕp¡ôÄ?•â$öÄYÚ:G 2—J¸r–óF~¸ï¸£,xcŠPøy(ªD«ðúrpíøLÙO˜{ª ü4)æ%~M‚î% ÄÅÈ ýN!Ôâv’Ï#@‡¼ *„BoÏhzLâgSŸèý€i3Αð¿‘a˜ƒ³d¥'r†ÆÈ mÕ×9æD"ô²X ò²Ù’ÍŸ;(ˤ¬‡ƒ‘d.MÅBcì³íÕÙçžqûnýyü©ç·/~ãñS•á³/¾ yáü̲–q[ÇbÎ~ÞÅ8·9ÖjCsCM3îõ€.¸ç5ïcÛEqßö#ï»ÇÇCG1Æ#…|.Aùþw8#â\Žõ”õ’w¡Ü]£­“ dŽÙ8cá p ~Fr‡äšìqTѨG¦©xêà‚̘’ˆA,A8Uy LV–d¿c‡“y&yÀ¼i ³Á"GòóØ* Cã€c³çÐÖÖ1ÎÂ7¡8Ý}/ @n³³œ×}„OÖH…w.ª \b…¹‹üê÷z^>3äå•DÚpFIÈÁk1Á'§äöKtÄiƒ£„¢=¸ ¤Îj$‹Âè­ÏN­Eª¡ž\¯NßéÕl???‹È“ V Ò")äjf&"›ê‘MÚ à`ìéÓ2`jv˱ŒãVðQ@dšÃDelDd”„Ý€æÂûa;K/¸(ÔÞúÖ#y˜Á¾ýÃ=ÉŽÞÀ¡S|ñ™íîóæøN’E»oF|jåeos™Ö’@•$A·Ã•}a¢Õù‹ùYyæÑ–6|„†S€ñb)üåš J0o+{ zµ˜Æ‘ïs®$%¨ìq\ç¬À¿+³•{ƒ x¾$,ñ¼'m¼çõ81^D”Œ 1Á÷"h)0*ÍcIB¡òÝ–*lX¯8%» ±€‚²bß|ÁÛ9Wݹýêݹýäe·ŽEQá©?ðž·ŸøÐ-ÛÏ_~ûökWݵÿç÷n~êa>@™/ûÌÉíwÿþß¶Kÿöävñ_ݪú¿{{û·o?þÁ¯mßÿ® ¶60J"EúM¹”öúCö»÷Ç*ð^ÞáÛß{.­ èZŽÓÎ ¦Eö÷T‚¦~_³Ó+¯p,*ƒ×ÝñøëC¾¿Ísĉ\]›,FeSÊ(,ÔõØX^ÛïÐô½Ù˜]ß91`•–ÙȧTùU¶?°Œ\èfG‘(í)} eS„ óõ3Ü gm‹NH@Å9éÃ!™*b:ÙŽ¿ŒÃ4ÁÓ9¿²˜dIøày¿:ŘöuDm+X9L˜¬&x$„Ó¾`Ä~½u•‡Ÿ/Æ}š”ÑÖ¬ã$uëLÑØÞ$ñí`YSê@®G’ùøIÎÒfgPxrÈÇ Ü;:ÃJ9G}ß ð  ™Ð$)ÒÓø•ØÒý»iË|±- ›=Ÿ‚KI:é뺎ÚgÈà ÛìD%ÉN;k>?ç=CøLo4ß'˜]$VAÎJ¨>K㙲ðè¾”B`AÆ’׆S`+ œwP[oH%\Ýy½¡ßãgèð̵ø|ƒé¤à· 'Dø0¾µ#Ð/… ¶Ûè¾e;QÚ=§µE •­:I<ïö4ß…$ÎCVe²ÏÛµ Óú¡'¨Ð0¤ÉDM™zu2³åsÀcˆ¨œEúé|} „n9ù䨟úÝ]xÓ©€è¿øðöÏw<±=òij¯:Ðzð±g¶ÏÝúØöÑxpû¥C¿ò÷½k1ú¦5¾â m/¾øâöZÿyàÛÏlç^sïáÞ )úÄ3Û3•…cËB²‘#ž3@®øüëC¾'ÿý¿†|a©vö-k £i²9±thç„2è³–í—œßÍz&©÷.מÁº»lΑŸSÅpVöª J¦~دè*"YÌóû±±òy²Àaó®¨"7ÇVÏÆ†É»Ã™Ì¤Óíè‰òzf}Èo Œ»ìí}+*YüuJ`Ò*HS5S4U¡o¬`áVx"K®Ú£8í•‘en*¿u*B©ºÈE€ãY˜àáRÀX|BO­>Œ¯òWAÉD¢K‹–‡EœkœChpdI9A3²žÆÝMï*"¶ouG[›NÚaftãCõÉLfö½7öY„ˆ ”ØËØxõÏ„¼÷²Xƒ-í¢:ß“NDï>ö û6Äq¯lêÖXƒì¹}ä]d8!fHTö>Ýæ—ÄFõ5¢½è4<$ø4#ÀR†¶ÞÉ®–QÉ‹>zŸ_D¬­Lt*\ õ0Am¢8+½ô$¼ñ‡¦QqL°ØÛpÖÏ1!kb ÈAˆ®Þø6Ò^"P_Œ¤mcNbYävè,Øž INŒ¥Œ¤+81 ‡’ÙLYÄ{ŸçÏ õÁ¸¾í²[ €î?@_½÷;§ª–ÿßž|æùíó‡€ý·>qÏN¶^”qüañÜe³º}ö–ÇN{­gž{áTöªëÙ>| ‡»ðÚûvB³ýÚÇÇ<îÝ÷û?}@üÝÛåŸ{pûØ?=¼]ó¯n_ºíñí®GžÞž~ö…Wúh» Ƚ—z®˜ s'ËÜáòS6=? „¨Þ˜7Gg)¢Ïo:o!ß;ò½þX¾çÿÙ]“|óOîÚÞs@[ìòýðqqù!àßå{õ—¿µ}éöÇ·»ÿòý±K¾frìHB%ç 33¾%÷”4*µ=mA¸ÍÆ„!›¸°Øˆ­áEêLÎØïÉ`˜(ìÂ9ŸìÂãgÙä׺ siÎG•de­x5{\f· Í%¨¬ÒÙO e}Ùó=œdü>6ÕvÁìh¿>•¡÷yb¯ø?¤t«qLqÜ@Jõ±=qì÷CFÿIOôó€¢ÒÖ–¾º ‘÷ÆQïÌ ùÃXTܼîG‚=NኈLy+¯cÂÑ>þµ¶–Ååxí ;zRÒ%#® ¨JEÒžSt¦ÙSåH0Ef£`"çøH’Àª†^pÆ©* 5džiŒþó5¹çjj*8ä$YVªYgŽF^Œ§åúègdÖŸ7û½¨ “ȬŸ—\;çu_`on­¾"¹´Yžž`\[Öå¹$P]ëÁEÉÑÑ cÒnG[†Aª÷'šÆdLµ…yfônÅ©4Ù޶Á 3iÁbŸ£s GBÜ'èBƒ•İϬçG™ y8pªéÎM1¢€jF+^½ Â…QÍ¡×b?—D8\‡ úkùçÑÿ|vûègÜ~ð‚Û"0c(kø9÷\¿ù¼åfßG6Ì’:ûâ›·_¹òöíÊ|x»ã¡§ÿÇgúö“Ïílå§±õ†w\ß >.Û"„ªèh<Í0"ë© ØäûÖ÷ÞÌf9¡’Ø:m6îìß¹y{çß¹]ù…‡ò}êÉ·÷üÓO×gSšáUW–,w¾»"y1ËÜ«pZ;É;“ûÔÿ¥^š´Ð˜—Q0$ Zâ€*vz.¬¤ßÞç]ŽŽ´*f’!™ïhlÖÅ ,‰ŽÎ‰ ÌèMU-û–6ÏQ@“윽ºS.Pk§˜Bà¤ÓBðÍž¬5\«~Ö„˜ú¼;ŒV’»Ã&Wް=÷J&ÐK«;ú|§V"t R4Pú‡iCQž5Çs9e#²<¾¾c/k’´(º…ý.³·Y“.’%´pþÒ‡Ïù¼÷>[ôLG ꔓÄòžÃØìj…㦛{¶Zr·½Á;>ž4­ýGÈf¯0è˜à·ìo«‰gv Gt™vív|ü ªyu”*xIP&±8¡mb ‚)28ª®‰Œ¨JâÃd-¬fÂëç}ßÌ•`2žS–u”óÚvdû²sãg¾‰9‘â$.|# ®î‰ äcIšG.ÄT!ÂħÙR˜‘=÷â4Ì7„“ÜÝ@ß‘*fÃü%•ö°üƱ2ÐB“Y2ûk²²¼ô×I ¾C˜Êÿߴ݉ϧWUðùc\bb°QÒD4¡BQѸ`TÔ¸a0 ÒŸÖ–‚ØÅbÙ÷"ЂP¨Ù¬`Ûa:Óv:]§¥{™¶Ð¶&?Ÿû†›o/ŸçÌ}Ë/y2íû¾¿g9Ϲçžå{¾ç«+~ •’Í´*.ç¼èÀ=(ílî·}ß}îåØö+¯»j{Ñþ{Êç9rÿ£ÛÎ8]’­# Ã¯16” EG¯4²°N3fa"ßžèŠqÄAÕØKRÄö»“/Á 9ŽŠN“cnÆêh Õ8æ}fC‰\Óߟ «7)à˜ dK›\ ‘ðIUÙ`·pŽ©sûeÊV‡•!ÐãIfŸžÿâ|ôgrœ›;ãÎåBöu9ó^°¼+ìGˆ¨à¶¨“&ó†¹ô"SÂÉ€¬ H̼Ï&9޽«Z$ì­÷Æžá3n‘ Žý~–`2C d+mH$¶Ô·2S˜»}¬ò`Ä(ôkRA,lÄmAkòŒ®‹`¨/|ÓªwàÉrT rΫ…¨Ÿ1•ï†\n=ÃøÄŽç×vE§x¿èXÅñ#1kŠSí¨¡Ï›¦6C^ämÀ]j%™>a'™„¤¸Û ¿£½/[…×g_uÍ ¾/v­&]„˪œÁor“}$kdv¬Ur •&”M&i×ô½ ±äøÖ²¼÷µ/$°–p’÷ޝ§Ÿi2¥¶sÂÅ9ÿ ”èØ°ž“À{<*aл=ÙŒYlYÀUG×l$ý+¡á72;®&˜Rx™Mþr2¬ùîh”í‘WQ¦âÎGóÞïßž¿@¾!\ëOÿÝ…î¯?¸=q!ŽkÔ§.=åÇ¿òòí3–€é9¯¹rû›o<¸o~ÃE·n?¹ïÈöö¥}·Ÿ/.°ò§ºÅѳƒ®Ï~ùÍp®^ú ßa‚Àñ=fQ„­9 WV9þr!Ä{d‘Ñʧ˜«q¤UÆN6C ÈY@B€5–ž#‰žž4êÁÒ0b"½Å¥|©¸×•G3VéœÉ·CÉÆ~Ñìn„¦!l£™Jy—3£ip2‡†/zÕß;2,`Efº7@¶YCÀ =· Ÿ$+ÉÂàê` µ¯Ûû€d…¹¶ôÃŽ 6"¨µ&ÝÎà ÷cóa/smƒpš&θ^wÒ`¬M‚$ûIAbÆQÃ̱"F¢ž „a¸2ÿ/RÃäutÂjAÖþÙÅE`ÎÌnfÛæ}ÎNTÓÐ'z q±]¦q0íµ•›Æ«T!i¿ð]Ì‚Öj,R·=èìn+䱉™Q#l…AÏ)Û.Øÿ{—6˜J<ç.!âtn Ä &i} Jnx±›8³È-ý…$Ãúçþ ±%Yd+Õ@¨Ë;fšÍÄç‚Òkûœ®aí=6;–µê^£Ô çó¦ Cö¤ùßzWHz&ñ)»ÒM™r?qÃnö¢51†¬êJ{~ê.œ.].djû[ê…²—¿€µC+™Ey»CÝ>8$£ºßÒGmî^0l¶a+&+5\ç'Ž|ÕOáQ;`:œŸ…<q ÷UÁ#ŠI\õ¹v7Øù ß|uë?†´…çœû50?wæ–÷+o!Ð:}ÇC-øÏ¹8 F¯»CØùû/¾ E® óãœH ~G[Àžd!ú+÷Õº2BÑq£«=¹ÇŒÃá*æ@g2’,f#{IœÀ¦+òíÎ ïÃc…/ša%!q4ù¶ø[tumî³gÜé#Êwû¿TPâ0¤oiG&½Âa¦šdb®GU¯ŒŽÙÚ”°OúÕ'=s®'ßañž`cFF’ä 0Ù$¤BÆSõFç{@ †”­UÙ¶¡¤ Ä÷È3¾ˆëãœ'ÁC•;Äï$vÒIfi‚¬$JÐøs0èŘØËï[Mõ+ç¶ 'òcâÈ1¥€êcåäê< ò$õ½ó÷¹'îq6*™ò\—™Á%Ã:I/~E+]œ'åeÀR²™gö}*»Ý> ; Âè·ü¾@Uèû¥}OŽóBÞ"ò\9Ÿ ÚŒ.¬ªSx . Xç&'ô%c›”ˆ¡Y"tMlþ&Ï,>I˜ži3ÓžI‚™=wö\&q¬¶j’°10 ÌZû–dçácò~ö~A”¢·~O~­šœˆwKt,À§H2©×—àÕ~ïÃT ŸÓ™žC–ú´j„齨د쉠qR Š/šˆ@äJA(º®¢Ï6ö¢wýìI²ÚöÂÓÔb¸þÌá³ò»ÀöÇø0qËž¨Q r_0‚à†ökÄéÃðGÁú‹ÈÃΪžÐê³àkhÚÀzÔý×邨9 âut°³€ŸÿšÛ¿üž£²ƒß|äáíOÿýþ5ÃÕ”gí¶{¨Ò7†w+ypM‰M<}*á@ Ž]}~õµWÕ®ñÚ‚Zîö–9jjåss {è9§oê¶{ ù&‰Dö¸ÊtEgv¦c_öòE_ßp°êç„eë×÷£#½A&Å{ $¸êóª!È2`ðÎ+jžì2NÁª†Ýåþ°\?ã†1'è£ã¢¼_åá]á\ÀÞïý‡™5IŽþoeÉ=Twj5zŸ'#i`ðTK$rÿšA¼Eûˆ°i?ïö‹ŠvïYä´kYݪ+h°'S‚¡{‘äKy§U”y%d‡ƒ×”K@?ÃQ;uõÃ5al ä&ª|žªª3³m㸓)Úšqt°Øî?s–yÎ!"2U¥i"3h'Q(Y7ô¶&™A ÔVzf%TžêÒ„‹v>ÉLMR¢#$x’œ¿ÝìzÅLõaÏÍõ¼~FfÏÐ6 ëœ_DJ¸š×vrF0§G>IÌ@ÙG„HÍ`€DÀì›°ªZqi»{\’­æ9¨g~w$M®«ž«…,›‰XL멃EÞ©k"úa‚\;l‹’þúq’¦±e 5ýêC¾‚îkG#Z5²×Ò†º’=cJLJ»ËžáíÀ9çE+ ÙÁË (3ýoËTµ£í¾ß»ÌW_û|ó¡Ç¶Ï<³µ ”Î1ºÚÿ-3îŒnM0 å¯úœºN´ÚõöÇþæ²R¾B¹N z€t½Q¹ŸÈ÷Ë3ùJh•Cfíj< V\Fþ!3X98jÎÏ^%,#ûÈ¡'޲>`d$OìÙ´U¢fëg”“³¢ Ø&D<è}鸥â¼Þ¢ ˜œlbö›Žœ@Va‘~ŸV7F8»/xÊ}m®uÕK§z=¨•0Kí8Q&ÄQðyØ'›ªç<è5ù‚/zN5¸d ‚èh®‡:`½¸}H«Ù𜹷È;ºÇµ'U 8¬*®Ãn!=µV$sÕ1×eÞ=÷Æ3eþ´•¬øÑ#û¯•Gž˜8ßUï@-ô$h»öN²n3 9I Á#aõPù'i(iÖfBÐe¿n’hãî!¨B ìÙföä¹í c>„h a«ÞèQ)Z•5¼fÓnî›LŠ òŸ»lÙp¢Ô€È Ò¯üfIŸœ¹sõTä¸!tF®µlDeaÛxÞùL÷êù}Ï»î±õp×ÄW`Ÿ,t¿”$߈ˆì÷=µC"Ï]Ã#Iœý59t”²aS9d3¢7*Mÿd*pÈtáüêÜÈêjå !P4`s>Ç/ÂâN€>#Ý"l5&7µÍ“Nºt{ÉõßZ½§s.¼9ç\©Ä?¹ ÿâý׋.%æ0û¶CNöß×~sõº?ò¿Ûß{û5B‰e×&ùBõ žoZöÕ£ë’#²¼¿Ï¥|ß×ä;82´°oäl¼fý‘÷T¾ï¸†¾Ë¢' ãVö å¾Ð  ÏRò2Ië(Léòü¬jdL~®ÎyïôÞö:TØ»NRñ`ž›è>ömp¤èAÇ,nŠ~bGúwy†ûr=ä^{–9N÷IeDÝÓ†çÚØ‰º\锦rÉDþ^~y‹ Éë ÷†{ž³£mAò¾]»5¥J\&ˆ5¨,øX"ë>J‹é2Acy8)!h›¬‘&«Tq¢kåù"¦̹´=¢T²!/P5j‡õobÄÖEßH1þ› ÷S†a_B¨È#ïv]Âk’~bï-?s¬›ãùX'Ø(Xf#‹š±ÿ¼hßÔ}YâÇõ4ƒ®Gv&µõšµ‰XÄmë0)ÉD;²éG$ëe˜õ òbW÷›Ù;ȾÀßåúÄN¶áÌùº´¿¬‘¡g:Pï[y±&‘ºî£$u}ÓeD+ƒ€á¾¿) <¢ibûMêºJdÏ^Ç–¹ßáÚ&ùóTÝCô·fS /ÌÉ“ °¾dé‰à»5 8G Ùü¦Ã)ñó¯…1Õ׉²<÷ì+êý´Ëý¾ …•êCî#²WÙÔTÜŸ?ûÊ6Ö{:tÛƒ—;‹þ©'¯WÐÿðÜk¹÷ik=ºWët¾÷dói?ÿœÇ 1ê#ÀÁ}ê˜ë|d‘Çà'Ë^ÁF“5+çÿÄ©û*ùv’Ûr¯f£70rF¾›Ë¶¯^Øþkù>¶ý·ª¡O£QÂ×tó—–dÕÇ÷ÙþÏ’jcãN›W<'_ 4TäH]í£ozÕÛ0ž®zÏ&gà«‹tDý•7Ȭªq(ûQŸ„²KÇ(Rä)¦ÚvCJZµÃ‰bÍ{뾈 6í< xžü¼‡ìïyǞˉR¶ê[Tûš\ÑÑBχ$»É{‘ L„‰¬àð¹eÝŸï°$Š îíGo ÒH‘“N>i¨j~ÞCßÛ¼^oƒ"•¦åQ ñ°_TìûN U»#G}¾î›=å‹5ûªS$”9¤? ²Ê…NßQNÌÒ]!@ òƒñòÅq #:rþçþã£ècoÉW}îš->×w±J>•ïõ€6o}• ì)']Ú³Ò(ØñË=¯}~ë-‡¶Ù¸øxžÑÍo•Íð¸“.ÛþÝù7mo¸«&µ;xëƒÛÿaÿØ78 !Gfþ{J`Ô3ZÙÄu4”B·5pö 6ù¾¢”/Á÷þÛ/¯ I p.ßeD߳Ϻ‚ºÕ@6ð¿¾.pÈÚwný.öÿ»¾ùH›í?u/ ‰í¼ÉcSFûðÔSömyi)ùÓ÷\ׯ 6æûØþ‡=¿`ï7Ú±“8oùÿv|à+wmŸñêýõ˜¿zc©a®S =¨\p>œÖò#ìàÔï@Ö*bš ìßKù4¹Ö¡v˜XÝ®ÏoœêjífWó/çC²“Š py6Ë8®Ân{V{ {r:Â`!¢ßo…ý) È ¢ÏÓ–„å¹_¼cG§?¶èsÓï×\øõí‹ÞqMÓÿ|_¸»|)$«µšsP ¢ªW2}­>ï¬ý;kõ•=<¬Õ_¶¬Õ¯ÙI |xY£ç}õ;kõô±ñ!jë2¯•}§ªŽBH»ïóINU’ŸÕìÄìMÞ‡³þ§$Y±#´ºÅ ¯ k¥H"‰™BE¬”õ¥Þ5ÑþÅ&ôç±uMÆSÌQ²Fr¹'ßÙ䠥޵É#„€‹&³ÓynÈñ“òñÍ‹„”<³qoiµENÀò^©Š›T ŠÈö¤ ˆ±qmX¼UOëÞd²²ë­¶Ú‚$¶ª>D:Ù`ØÃà*Ù ~Ç3Rí^Õe|‚ÀÓWÛ¦fÓ®úázª'µÿ¹eä¨p,¦¤ƒÝuDoi;Lp$~- j†óeÌZ°óÌ:%S4@áŠÃ„2̳AŽ"¡ß °'È…¢ÀæÕBËÏ ÚéAŸTÐ1nxQH¡/,Ž¡oèùo¼ùêõqZ¯»ªË“sÿÔ+×È_:çÊöîšqjÿˆx¸`ž½TiÞú¹Û·w.Î`õijoÿüímf¼Œ:eÆZ‡f$&ŒŒM(©Wk7dçµ!î„ýgÍ ^•ïk¯2 гv¿WùþMGDN’œõ#pÓÖËÎõ>´8ß«äo²(£O šòù‡·ç/Ž|C~<¶$—æ#O*ªçÚ¨PÕú­þ™%±ÔÚþüÝ×l_²´.üÑ»®mˆ–å÷ã8˜>¿_÷þôâ£ÏØø´a7gtÙJ·òñÚuâôl­çXmìßG—÷û…ƒ÷n_üîkË`&v„€K8|Q‘zÒ"ÿ_^®÷׸aûŽ%`üüU÷¶DàÎÊ{xtgm<´´|Üý­G¶W/?_ÆW.ëé¶í¯¿ñ ŽgIíR}"{ÿøêÐq‹{éÒ:ôùƒ÷í\wöyt¹¿Fòø—ÿrÃö8¸5ÐiGW­Uô¯xïì­OÅ×¶'øÿ¿VôedÃÞEzm T‹ ÇðÔÏ¢¼¢¢#ÄÔ@)½‰ êÄœ£»ìvªŠ÷`r9 Óz0ª*#N:[;°ç~ ’Ì:üÊŽ!àÍEB¨çý”39=$Ëvùšðkº/ÕQ ì‘“~làçŒ8­×0AuÚbh©a•ˆXmàÑ|mý80i)b/‡Çª£Ëôiœè‘{qT¤zcl LݳvCXë‘$Oׯ‚Pmà8í’J3Ñ9oϼ½Aô¨ô•E¼¥eÄÑ€Ú˜$Œõb'DœÔÏÄ{œÄ¢r›¤²?èñ±N°õ,{Éž!ë&œaèí²‡Z]3’L¤Òè L%=EߪóL(¹n²µf÷„E1œUПvÊ݃u¼Š*'§î†‡~ŽúØÛOîëWgÁµàbíóÌÓ÷ °Cpé}ÝŒÙÕg-UÚW/ å—Þ@O<ŸÖ'ýܺJÃg/¾ÁÕ8òj6˜^–Œ†BîèXñmwsñ<B•|›œÈаóaNé³Î\ä{Á.å{Ý7·Ï9óÀºÜ„íhÜÜ̆ŠM vÖ-éÓÂ1±¢mxú2¯ÿ/¼eûµÃ÷3ÛÿX?/þç맆ÑjºAp |ù›_*Ÿ|î5Û÷_|×vßM÷'ðYù¹ÿÑíÇ.ýF ØÝ( µ@Ø´Ã?±T'ßü·m?¸T/_‚Í?yÇI””ȵÑ{h˜iOÏ5A1ªeEÛ¿ùðá!kAêÓ^ÞŽy{Õ|þüñ‹î½ô_®ß^°TmïÅò)É5\Ç]‡ÂÍÙ¿iùŸøúöÎû9fþÆ’D8ûßoi•jåb@‚<ÞúÀÚZ¥Šžg9z2÷¬å9šÞ?qkõ:Ú€ o@ÚTsuq0ƒà¡rI%ôGÝóõ ÓfTN5ï$×DߺPKÔÅÒvK¨æú”pËBÍðL>! î¨APJ’br~ªÎV—û[dnðT¹r[p=+²±«¨mPSÔ–¡Y‰ÑrèCôœëÁû!¿ù¬ÇUû,§n[I+'þõn9€@M)¶!ã°Ò£“ÝÈMäÍ:vþ}ô‚W`&$<6;k Ë®ÞIâ ŽñH~‚ÖÜœ¸ª­{ýXI‘Û" x|TØ1Áhº‰ d7|ƒ|Ë=éû²¾ùý¨ÿ½h ]ò|LÚJ=öa$}âÅè%ÈŒ€·äÆ(ÿ;?‹3‚2œù `œ_*déÿPq4’í<ó9è—w凼¦_‡þ¤ Ž,™I`³ÜDV_¹Nr°—þëý½°±ŸpÆz¡9cޱÏó¸¥ïù…o¹zÒxÍíl«Ÿ½7~kû¢·B/J‡S#™™\"3ÌßEîÈïÿìâ®;aNm†'‹°„¼dSK5¦A®kùÂÞÉ;oðõ¾õÐ÷&ß%Øýýw^ùÊf™ƒõVKÀÐ?·T$×>§_psÞQq´9þŸX`¯-z¢?¯»è–aÆÑÊ“µždcô¢½ƒ—-Aß—ÝÏÃn?7ÜùÐö´»iû”“£#½«Õ«yÎÕ*¾/[Ö4ý#*Á9Â"$jFw§]è¬×Ä‘¿õ†«zp’dÐM«ÌáŽ.ó7m|rßFëç”ówg’‰&Ú!m]ÿ²âpZOŽácÒçUmDã¦ët’éYÛŸ½âžõµºÜãŒô•µúÆïßZ}í§n ÉŽI+FV¹~qîyÐüž"B¿‡Y°…î⼚4€pl:5B{Üzì©ÈÇwAwËQÃükyñ'+s®+ßµ=ïòU„dm´Q˜jÃlS:Ú¸.È^é71‚ !P”?’ ±û6“ 2 Y÷µBP›–†rJdWŽRœâ:Ègª—®tsb稨:{b¾áçcPé»÷¼‘K_—¾·bü™íȇëWœ1ø#s€É>Ÿ•9òJ,@¿6ÓIû}ìPâ¹Á·c„ª“ËL`l Fwžy†Ê´]CÝSœ¬€²„93Š˜ |\Ù_C¯`®!´¤ehúù˜Ã–I ž0yq”6/N…Þœ$.s’*žÇ@UönLØ'•û:õ£7ñ>ºüžuÆzÙf¬ËêxÙö„W_¾ý“¥Ïðm ôÒ%Ð.{ᛓØHàz¯÷»vnúxâ,õÿw4ˆpduNFGuÜï F `= ?2'¡ó¬$@¯÷ºwû³§ïoòm°ôcï½Àq¤ŸžgeDÄÄ!}ß—îX½—/ºo\{IBµýý9û7÷ÍG†VãèGƒÜ¿q©\·€ø‰ú\çC æ-Sx½Q¶åõ ò¼Ã:n°U ýÜ­e¢ß“)X¶ûzV´ÎbKp¾ûáÕ`óI‹M¡òŸ^㉽w{ÒoØ^½@¥ŸàO{ï¬{ {ô÷esm„˜ï\Ö°•æzýZpŸ>pO[-—ïI¸Ÿm蘡j7¬ëVÜÅZ-+;kõÊïïZ}Í g?GÎù]˜zé)…W Ø@¥rMëT1Q‚5Àñ,rúKŽ ¥È½=zz­<w…ø7(F¾ç:õ-rJµmë¯ç{Ìl‡Y¹n}KâݱiDŽN€0Ÿ÷¯Ÿ‘w,,Zö{ ¹¬âµC?V"ÉÙ|óü̪5×O`ï{5X¶çV½%q_>çb/ƒ<Ú¢—1D¦t¿ÙýeëVüŒÈ·L0Àœ:ÁaŠ;ò±â=2¬[N’'ßɽ†$Ù½^’èÜ7¨:Ið”Wd¹w¿tQO†Ø>¤Î«ËõQÇVÇM&!âÃȹ©?ìS$o÷äd|Í HvVõ.ÒkDVb„† #2˜')逯;Y~7 HÎQûœu<ïARæûqœÈ.át€ ¢Èp|ù+è{Þáþ}P'ž¾¿tPßõ…Û·ç-=†ÍilNpѵ‹Õ¾sGõÄæL€Ôº— ¢dâîP]˜3ÔP;‚k­£Ê÷ÝKàÕÈÍvä{ëÇ,ßw-ç9ñŒôß5£Ñe¾KLŒ`²ÏyG½é¬O¶Ê®Ÿ~lÑá‘4è'(sëymÈ÷ò¹ã¾o7HíN;Ä.Ë% ´¿õ ?øíAV F'£I·Ú3Ü‚«3@{ŽÝ}Ù¾âë´àª`Ò´øUK5Øma—àÚ§É µPˆ ©\ÞÄ7ÉÖïÝ!óê}Ïg^pó°AÉ'6®9ªµ¼äSô@o†Äj»¾ú—æ4úÚ;¨L?aŸ÷þ×öì Ñ5ÁÜÓ–É Ÿ¿’ŠõêÔŠÖÿâ÷^¿}ÚòNÌØeØàú§|ä¦íþ›(×þóϹ²ßçQùϺ°\«Ëߌϸ³V¿r×1¬ÕG¶ûg­¶ÑŸ Z?[«aIeÔªk )öùÕO7æ¬Öç¡ï5ÐSî*c•96&Â2eÞ¿•6|­‚è’þïjLÛ|l–ßÓ¾lû¼±gC{òÖé·JgpªeÞo=WÚ¤ Þ"8tŽó¼šŽnP±® 5ð&#3×ÐÑÃ’DÑ÷jKaZXGhûxo&{ÒVÈQÛ7Èëzà á˜Óüy–˜’¥Ù¾‚ÿÎݘöÓn¶Ó»1^±ÍפZç‘ÊÏßG~ƒ &XKaÿ§Õ_QûN1éA~1P³¢LÚ\O\©ø(ä¾1©Õå“vìľUBs6-ŒäïžÝd„H•33¦#Ð ~H´ªÞª–(L?ÏdSÍu¼60ý®¡§|œƒn€nVå‰ñUiÝ+AHw,š3@{‡}ŽYEé õLz¤õcÒ¶[Åü™ýÔiû–gº$ï'èdzÔYÙÈ…¾f²RJù{ @p$C¢?Z2`q¥‚þDË÷î&ß>óãÿn‘M Š7éß4Áfo¤³P“xí3A_ûï¿Zú¡«Ï §§º×FÊÝvï·wõ\–·%/~{AðíÇZ`Ó×yONÀ4\‘ ýæBÖ*™~ lZ²à= Šà¤ÝØw힆 á¯?ت¨eâeó¡ÃBðEjìðTŸw,çì2Õ z™ÀÐ`Æ$>s[tÜÄg6ÊlÄM¾À.›LªwÿÌÝýó§gUðýcÚ§CM¦V¬ÖŠ¥Ö [°-èP‘Q S⧉h@hÄ%" R™ Ìl1 "&¶Ôvc6 !²yÂ%ÔðÐiØÞç;^óæêë>ßkC¤Ÿ™{v÷»ßÏýpîsë<¼ÏûüTTì+N»°ºïßôªˆÓVŸÒ‰bù¯ íÏldt/ºæÌùÝàô…xîvü³+ï8ÿ’­ ä²Eý=7>Tœ<þ÷o~t7Ñ;óq«àüÔ?¶R^ÁëËÞóÙêM§çvªnÕZ¶BéÇ~xìZ­Jü°/Ù ù~ù×ê–8¸ê†³Gkõ™—êŒ ‡üÛ·uüü+ï¬wÁZý®×-ÈÓ¢ÛÑå¾õ¶&÷AÐåäÀ²åËd"K‘ðîD³­ÑsÿmÆú&©2£©zîùHL‡¾ÑWºý?cØšÀÛJÏ,~ÏßÀh5Nˆ³ºJ¿ìÚ’”Nä®ôšH*Ðß}+ªS>¨žC„±…«`¿Š±™œÃBÑ„j„.÷§¾„hO3I€¤„ç_óIòÇwH`µmy–è1-¹Ü'­;|O¤Ó 覢#0~Ï%šErU+ÑYWŒ4åž{BÛ¡ƒØúĉǑ”Nrâž]÷ÞOt—ä¡HåèoˆèäÙk£œb¶ÑNcB2h†ñLIF&=ñ´°â¹@5r>­1ŒQ¾¶eä¹€ õ•PYv=Ì+Ćmt]A'{DæÙÍk@ûãø†`n0¤æ™£8’£Õ¾!«a¸Ê9{²>Õƒúðæ¬Wö±ÓmÁÍ#çùC÷—SX½Ú!ô¡ªÐ7 – ÇQis“Õ莀'¬¾êã³_êI•o9ñ%ßÞ~®‚Ç’o"5Òh¼Q ½À¾@Œ×OŒ©~ª÷¶Z"¶2ðl>qÔ«bY„{×"9¨C{[õˆW¥½ï5Ž«£œ£ˆôI7säë>_¸È»(ÉjìØ†¹£îm—¥ûÅ[:ô<÷hûÍ!ä#@{ú¥=åG=Ú»(uß2º+®K@cP5 nß±ú1ú–“o$M¥=ÿŽ> |ßáÈKÆeòÎú©N¼c8PÖvÃDCŠAÝȬO9:UkÒÙú™kÔ‰íÁu8¦Ød[î3ïs=É€pÓZi|qt5¨jÞÑH0̨ªê=âÆ©¬ü+îÄüføL³«=³ialÏáÏUpU¿ ÈwB…¯ $êrLŠ÷)œÃûåH–ü èž·';ÙG$Äñ@©U†üý×>z¶nƒy·£¯>F.Y­gSá}ê>Å@_Ìãå(óõßyÝIFäD7–YûcÛÃWG`Oe¬ÿa2FI@÷TËwk¨‘S‘o7¬$ÚvÝíÙúäC1³ßx×W–Îþ;>ö`UÑšÀ¢íG϶I·ôwÇYÞÖUýäOUykNóq÷ù«×Ÿ-6õœgŒLé {~í§ ò˹Ï<ôõº~žybé~½)í|Š0.:hr)¬0õLÏ-J£’0±­¹§=Þl`¹‡ëoß…z—¼é³µ=öêÊTùùÔüÿ×\[m »‚1µ#ºÑ~»˜×W- î?Gí*;Ÿ‚¨W¹­ÛdF~Þ›wíuU±£:Ç­ÕjU©t˵ZD•Ϻì¤<íp ë17NÇÈ–ñ¸¹Cú1_Ê×ë¦EÈqèR*d±'ØÐI¯€ì{ýöìñø ‹"ĺV»ÙUûW,èN­‰sM?íÄÿAû^Š#ˆÝ–$Íb?# ô µ9øªSu7.]ÅYnŠCJ&0ùƒ‘zŸBM?ÉJpOÆiRm¯í²³úNµÊ\½é/ê\’p“ÿA¿yö*ø)¤ ³‹{ãwX¤¨Ép€ðÿ“k¸?KyÎ(ÆÂ±§0ç_½ýkˆ¬[Û½ìg¹¶D|ÝoçÜ›˜ƒt›D|¦Òà_å»Ëõ$@cûÜØv‘=yñ‰TŽØïèGYdŠü™™Â®"©A8îa­b¦÷ ȽlÏdèPª†´…ôfÌÚÉÙ1?½óPŽ/3§^Gœï‹/¹¥‚qîé½[ÅoÞ„æÌåß§ÂûT~¬r j.ßúuÿÁo'AÑç,ÖÒup‚{ðÁ½€‹Ï°ûïý¥“ÿ_Ë÷æ-!R=Â%_2ófªÚô©.ɱ>²‘~ßnÇ‘„¬é0‘BPÍ:è‰Ón;ÝDJÆõìËOuÝÜ«´Hbsÿ_rl ‡Æ¿´7::(=•0ûJ¢#¹/Aò”XóèqÐ FléËÚ†£'I¡è“b/#ßÈ>HÔèYÉY,da2«OûûR‡m­ƒ\Àwñ$qI‡œhÖ‡Ã÷˜ŽP±lÄ’ËðÂþœk,ôá¨f‘OϘ ³õ}öeÉ’_ÐÎO£›Êû³¶êå_×§fBW5«à‹øÝ´1tc¯¨ú.?±Á?‹™|A¢ÕBD«÷ão;L&uìZ’+4 5Œuëß‘²ï&@ÿë•ï ›ó|$ßÓ›|Ï|eÈ·àØß’|_pÕ]y>3ö$*ì‹]c½â]g0Z³3ãkån¬3P²$'øóóáÛÎMPvÖ  ‚™ðÊÄä6ÇüÞ½ 0ÉÂT¢Ç™Ðàçyo¹c52db9Ùßý¯\Ð;ûo÷üí{“Ý"‘“û#ZAøÎ§&TðN›ð¿í¸ôÚûÚs¼ì·îÙ«â×Læú·{ãcìSÍ4ôe¼kžÿû.?µ;ÿÔý_-ýÉøœF×}‡AzüÖ»0ôBí9aÓÜÝõZµ¥ãçÞ{/ðjQý+ê:OpÉÄcÝt6ÂÊS‚¾èBCPÖ´Ê¡3-Üòµ4Euí¾÷ÜdWÈ»]MûÛ%ô'9Ì8+ÖT¾H(+VnÙã¨û]’ %oÙ¨ó³8¿"#sÝè{ýáKŽÇü½UW¼ž³ôÕuþ­¬#£¬;+u3aÐc|[i‹ŸŠ[@\ÁZ"¹•=&3¼V=/:@;,²e[Däš L²±ŸÞ@¼Ñ®b/‰»Z]ÛMh6®ë>±‚\'ì…ÌÖÄHΤÚmÒaGÈ®Fä ›ƒþå}ÂᄟiFÜÚ.¢>gµÓÞ—]â 6Mô¼x2·(0Ù! 1ìq” .aÓÑQ`„¢qà5 ,–ć‘ûZ²B’ÉIæµað,’ =¦Üï|l–»ÏWŽò ®>½U+pyû§ÿ·ïû\ͳ.B°ê¿DV²~æû}î›ÿ|ƒè~îü»>þ`U+/ˆ9øúSç šßê°xJÞvXr-Œ 8ËÓfÒ²‚}$ãù„å[ÁwÉ·ˆÒ†|«‚;ª„ÈV‹“|zæ–0*‚¾‚@¿çO®ùó&ßUþÙUQWW¹†½Õý§FmýЯÜQAl?úÈ‹j’ä~êNÏQäaͧ’”æïãÄÈVÁèÜ•]T¨Î܇1‘lÁ„—ì`ª2f²£,,Ù‚`ás»e9§УT@éH$ôäfÌýföfÎb¢¾\Nz㎌ÎÃÅ[²÷ùËÍy¯ŠjA'z d~àŠ0ýJ°‚±k)Ö¸‚ܿ¯¾Íe?õKßõ™¡ÃyŠBµû®íír¤Ï!ÌbDO?F¾×m‰†#ù¾{È—QxßÊRBMBœq4ÛûÂå»ÝW· Ž?í1îû„ëÚ ¨Y»›¶hdc]:˜(4pB¯hWÆJœtìâ÷<øµ" “ Ók¨÷‹£ \_ÿ¡û§|JTU¶­v>㵓8¥Pã­žèÔ€‘DÈfÛ]¬/döù éÿO_ ²•êEôýnß|ÿðä¹±7Ì=jS0¡}¯kå;&´ëy¶Ïë-Dü‹ç¾qþ“Ò¥^EWUîšÑ_#öþÝïßW‰³bW¯DÜöïÏŸÿ¥”ï­ªªäÚ ñÅYðeZ"ö?En÷·Ã¹ »ží: ýZ½üTÞEï¬Ì¨‘™™º#Ëé¸cfƒ#Ii÷„r [¯½çŽæ2ÈMÉðáïØ‹nœ•ó5Qí=|Nh¨ ú T¨jý¬ï³ÖDT$HÎ×=rùmª´Ó‰edªã€Ñ‹©­J”˜ï0œ~bp‚^ý—‚µÄ~%"¡DuêCZ»N6ÆÏ•Àj A$½-J¢‘߃q½‚õ‘,ZI›$2 šmÛkÆzÆn•ÜZ7¬¸ãë|_<;#ßV…D§;8’´ïíöšÊšDÀHô,x» ·Þ~ã(þ~oütG%ö †$œfNš<ƒ­/®‘:&ÿbÈ8×od–óv"Àöat"•¬Å R’½#@i`3(ì|½rÇ «ã³ŒM({Hf~Ø/˜$Nc–¿ƒàÞ†¡ éD6­f\ÆÕ[æÎ§ »‡&¼ã`Ö¨ 6œ|'ŒûÔÑ‘õ´Îi_Sîù§7ëC=,ó¨ºöâkîé8æ±3 »ž )Hœ w׃ìL†|¿»XÇÜËT— Ötf¢¯&\ë•xhR•ï;îÎùv`M¿}ÓÃDN÷æuïŽ1ŠSduÓgU¿úyÝ}õ¿HßÚ¾æ{ûÝèâX£Ù,¨lÌßI¢›vÉû Žk››¤ý®¯þ½~\Ö¥ø|®ãF1ÝãMø­?5wü;^«¾ÅAˆs«{GÞøZ-éagùµbGzÂR ±Á-ì¸exñ;¦iËŸ÷e¿¹‡ñ[Ÿ`6`§56­ëuyb;{/PºEUÁCˆÁSÏE™qŒVÌï¢5÷Óì sÈBe‹ñ\ÍAGV ”ÒÌÍ,Ÿ\3½FÈÿå¿ý™üÁ ýŒK§€å8eÝÓ\±ßMÛ@D˜7§Mß 7‹ad­3Ó]NÐ÷¼þöó§¿ØV{«¯2ðoõi ”è#õp~ö@z¤ºçsö°¼ãäëf>éŒÝqm:St—40‰³TNè«ù çÇË÷é¿ tèæ»¸søß}†kC¨¤ÞuêHD 3¡ÜáÕ0`æ|>pó£¾[ÚNor/©RÐü«ï6¡vãÃóæë0Wüþ¿øFÇŽSX‚¬".l‚ßå¼ú òâô{«ÓÎ=š@p KÍHßû>žL" xúÌ«r˨ªI–÷´ä-ò¡÷¡NøÀs6bÀ“éˆÓ;x_ ‘ŽÙ’Ýšq> ËôÆô†Þê|k,í;âþ¯uCìaÈ=¼Á,éØrÿâ7îIßùL$¶õùž6ûy˜ú§@û±­j²C¶ýÞ-Y€‡xŸöOêDÓG ÷ Šçlðï"…ê>¯*"£Z$& yeƱ›õIhn‘ì!îV®cÜzùn¿së” Jø$h2•TZ­0¦¬3£üªbvŒ|+ØçÄi~ÕTÑõó'w}eT¨È®ÇÎÄ™b&§(te1—ÊÏKóî–Õþ9Å,9’TXO¤ ³ zá¹oÕ†¼íú:[E&»Xß›0ôƒp¶+6˜õΧ’E67" ª>çoæšÁ¿ó)äBœi”œï•ïÝðoùÜ_ %Ñ%’¿}›Ï_ä˜ÕVR}ÖÅ·ðw_w2û‘çƒ ²þ]°ô'ÿ#WÂEÅ•@%UgçUSÒ„OyIaöòUÿ¬{ß°·ù; á-ñ’Õù${;¦}Ú°©Bx½ž•¤\·Yï:qÞFw£<çìÎÍwIZ©Óñ bpl=ìa¶7Ú i Ðò3FIÍÉt ìÓó a\÷•ÓäsV¥”¼sH²¢"“ÍTûI> ?}F~@ï)ȬÆqýáæóþL|Úñ}ø8I¬ôrMB˜EyX ò>œ’®™ð¡€ ÃôsÈ=•}Ö †¼Kl»~Š ºÌ|ïøÃ¯«)Om÷‡Ÿ ZE™2ê’à\7òĶS,”s ¨¯Ø‘ÈÆ„ŸIg`3¹%22nžQ¤ƒ$.™1‚4Ž€óZ§Ì?»›é€/ÍP 7Da7sµ»3 Âyb °•²ª s¯ã~ < é˜Ö}Î~Õ]ÕüÛ'ú¯ßu¥,9&°€¹²ƒ‘×x¥EÅ™ùžèXàÂQbu„ë^wªïu¾êúb uAÖ7£ì%_ÌðÔ±© F#›jz#ßmÌØ)6¢a4E’÷8ÿ€R±WˆÌ£YácG!`Ëlü‚mNöqŸ]sf±O^öGw<Ö“ó&|q‚Wqo# 6u#uäÚoÜöÌiôëï…hx¤Ñ©Þò¥&ÛŸsžnÕ÷\¿óÆß¿ìQ~ú!p佄§B²š®ãäñûzUèAÞ7X«Ç}àú-ð~ņ2ºòú³õlEhX--zàñoüïó·Þ÷x4Vð>ÉŒ@ðÂù:¨¿÷qá|5~²’ÌÛgïI¯þr­þ«ß¸›$ÔΈÅ)Úsîù±Q YU2ßÙ/*¾è×NkÅF²=ÎÛ>5ˆ^W ÓãÈþÂï:æ ¨I83jvº¿¸fÈô-HQáÓvLýÿta­gÿ¢mf¬׫£ó± "Î$ Áó~}ŽyË”)ÑïÌ|5·Ûžà´ ħÕ#Ï—'$Uð;P9ô>g?_¤¥É6mà 1g"Ãgªk•Í~¤ !¿Î3·“¢ß=}ú­ãoÑ‹}\¹ßó-l˜ ³•Ñqký¸¯Ž5[*I4¨œˆ¦"íLÆ>][.I…>ß$ Æz :h"‡&é3왉O8¹@!ÿBÚêD~`ã³@ ˜×è$k¦A÷à†È^gaøòg%„¢¯ÕáK*»ìA¿ì™èÈÌêßšáÝÌãO¾óÌΩlá;*ûÓf8ׯ¼ ™­D@`3AS ¹$ ÌbulAãXQ4ã7-Î"Xj>E¬4ÏôŒ¼4vW²ÓÀ¾x¹IŠ|7  ^¾?zåiï7ë!¬ÏnÞ:• ×¾—f)ßz—ïÔϾê5¦"[Áý—± FXÓḙc`V9OàFV½ ïÍH©åfp˜œ}á°§îG~õÎýþññ3–';û†¦ŠþõêG¾ìdÛ‚ñÜ$øü›ß;šM^ïìh\ßô’ÿШÞ—Â."ãÞG¾¾$GÌÌn-8û>IÜ–¬{áVÅÿž_¼õüó64¿|ÛEºvD¸xíÍ_ªqŽ V¾•¾î_ø@æÓ;êdLûyàÜÿ<âøÙyþoò¯Dn}¿ÎU²ªþñêÙÿ'[5ÿŸn6¡’/Ù0 nþšmÌ\ÝÇÏ¿ÿ¾-ÙðÙmlæ]õõ4̶ó·Z«Ûý|ªô3º*ÉLçNO6&“-ì÷=>YØ_ÃDß% R0¯/YW]´ßÒ6œNÙÃmû@`Òº’={Gå¨MhÂSàýÑ“MûއŒÏ!¬s/Õ~âOtUÛTW›63Û½ Pâ¨OzJUÒw†SOÛ„6ŽDTîÙE“˜ÎµòŸ×¤IÖ_}wš´,L,+§…: (úÆx[Xò>“peÄïŽgÎ}·fV6UkuËB¿ôçËPeh²HºÑr0O3˜|”——þfªÒ}5ÙïMYˆüSzg5U =ö‚±(GÆ å÷DÁŽÂJ&Ìô0¸w¸Ozn‹Ð<0ÌXÈÀgƒ¿æœ ´f´;8¤„ÞÇvjc|nÑ9©™XÛ'dô%ë[™Ö“ÃŽÖw†{h2p  më´(…θr¬âš°5¨F©ÕA ë€ÂlkÜÏ ªŽ ÷Ú ¦Ã¿áNq¯\»)’Åotlæøÿݶ…TwÙ8Ød ÛÎ1Ž(O²Çf˜³ˆË “9\3™Öbþ3G i´zfhõ qÊ,P„ö¼7ÝÞèéA÷ÙT ùŒ¾éôdBòQ/mêê1|÷ûΪT½âwïµ°õÑD‰„,5¼‡äwb\ÂTšÍVt7‚,Ô‚›¶ó¿P×Cº‘©ÇÐ…euõE†znñ˜Ñðôºò½¯•o6vNÙ¬‚ IìÛg¼ ¸—ï—Žä{,,ôì—÷‰ÅÞ÷ßÍ5G¥·ˆÍÝ@ÝßK î œô$ªZ¹ œ~L£ÜoÖ8ž°àÆüŠd]UAͳ;?xÏ&×ìë¶bû·^}ó°1ùÎfGhæNMm˜“›oþÈñ¤bwoãè.Þ_ˆ<ˆä3Mtм#í{*?7½æ^¸aK(Ö¨¾¹òz[Tˆ€Ú®öªÃ”áwmöß=n­ª·îÇNJÀÞ5k5çëF‡tÓÂÐäç±§ØÒ5zF1ƒóz‚8’“SÏ jÇ÷áèC Ï© 1 Ç;ïžV¼~¤³Ú§ÄA“ì`¼‰ [ ™{JÍ6oûXã`Ã8ŽHà½nñŒ¼m»p¼A:™wy‡ÔŒÊ"2H+\tLôG3z„Wýl·õMÂL¦‰¼}Îè6\;ÛA` ²Cöwü;|özô­k׎ò® yž÷ჳÀgäëÑûIulˬ[¤ñLE=Ïñ)þïTtTe‘SÖ;ëu–ó’¬ÍØ!zA[•|ePßË:]ûo¢ºÒ¶Ü Å›½\Û—äTžeèJõ O›¼ ~sVE0Ó7úNȲE&–ãÁЃ—ûƒ‘3Ñeë6„9³nfÙ¾÷õ˜µºWƒûdQæAú}Æj‚%V¿áÞçÑ ZPÏåû2ÇW þôžý‘KWôìx¡qVS<Ãë6¿‘ô™˜ãA@‹ª•ùÏn}˜ég¾Y‡ƒ .ÁU Sœtô¦ýÈž^Íãäûë{yd B¾3³L°r“y^—nE¿ï@`JVÜÚ$ Þ}S±KOIU2Ù±¦;4Éå8ÿ»Œ`ý½’={Ÿ7üÁýß¼™fƒ?Hl„ƒPØ/õóÈoú¿ôáÁ-hÊù²Á–=Ï··Y~Çp?ÚÀÀ_¹‚ gpœû'ßÑ÷ ¿ãcó6¦cüj^þ¯Ýp¶ä1%ªß›¤ÁöŒ±Gí¨ ôó'©Àx°oµ^ô‚ÍŸ{üÑÿÝ>ßu_̽efòœ¼©~K\Ég>‹Þö/ö3g±w!ÅÌùkÕs¨/ì%SÌ/¿Kµ•ç°‚™gqî·{nz ­nŠÐ@3-n°òödZ©Ð o/ ‚G ˜GÉuBp'ÇÌa—ˆŸ eŽoÅx¬$4X«õLÜ#púa1²{öI¦“ïnqIOÿŒÚ˜~K\|'ïÍÖÖ¸è§ø«r$A©ì¼f‚9“ò;Yñî`ðë9ýˆè”ݿР8®qÛBLvÄsÚ"Ç0Â/´Úö ‰„=œÑ—¢@úØ×làÙ%¹sŽ D‘ñ,‘çá¯*éN†Xq2íóm,d€. Åï^>&)ÉD_Ùä^¾—dItÙgë¸E°©pd„»¨þ¤Ø”]˜¬y£g¸Q¢ÜK(+p% SÃnÆkY_ÍJ¤Rlœ£ªôüÚX³{‡°1NT–eý&°¬yÉ_ùÚ~Ÿã_üjUÝdéœ+ÜóðÙ.ÉŽ>øÉ/Qu`‘ô3ê³ðs Vîù[p^Ä]ù@ˆePÚgªúlbšÉèF~=ä}ZÔç{ÿ+\k¬)7å‰$ âŒõá‚ä{AÌÿåä¹Þéä6™ð5R† a½®eÐL gæ9M€þ‚·ßEbd$ °{aež~O[t¶`äôg9·p0*WüçÝ@±P1£…`èã±D‹/ºúN8õ½‚x)Ù1³ò+i9ٹ΅Õýa¢¶žÀÕ1lVñpÞ¦—º ïüøƒGùnýÜïÒzwsîâízÅÿ“;'ýçóÒt3k/ïãê-¹Ö|ŠŒMRõW¦ñQù°Õ ú'|š'›kçÿKîǬUÇY‰nËÞŽãL…“ä;•áœÊ †b÷²Æ¡} qn÷Ðr8ÔøTR©1ÑϱøªOÈæ€§R–÷#Z-çÌ}Ïzö:­TÙ¯ã¿d;w8ï×¶¥>‹?µbì6™í^íìÏ™V©¦ê~~«“\g6¸†9¯uÐu§žY}?n´"…6î÷èÈyl Ä6N賾ʚ½">òUŽ~%1/p+«ûIðr¿Î߉Že„$½²Hç}çÿ?ŒµMAk šEãhèZžÑ«dNj8‚‚›P¹êûöÈ÷¦„,ɉÄkuýøÑŒ ç;ÃÖb/I¸7½ê',¬:NÒ˜ p5+.k©/ÑŠÙ´±Ù,¾ tÌœärSb f]A/¹ž¶ú™uµwÚþqgâôWYÝñü1µÓ ¥v¨¢-Z6Aé2Ôj—R ∢_BY†„XöÊвYA„²´ RËÞl„€‘–¶µË̯Ϲ¯g¾9ó¹ß÷ Äâ¹ó&ïûûÝûÜsŸçŸ¯–úuœÎ †°W÷ÖZu(Þ˹ù’‘~PƒYbî%1§ùO^‰ Q̨[Þ‹º_ Ä ;\e}·i }D&xm*á×E?ùôO™“¦Î?W‚Ò]¡„Š# Ã˜h‹Êx “»›kÎ&Á9og<1õRΚ$¸ bo0duõ5J„먎Œã“BÎ ¥è7FôµàÒ`‰³ï ëZ‚Ö*#—D“ý8ú«¿9š£’E °7<Ø.ãÄ„ú‡^t5¦yí]?t¨¸ W›=²ûúœÆNá’öŒÑòÈ÷Ö~5 “eUû@'I6â”2[Âi. «Ã–6%ÊÜäû’—ïDÙn¸¦Hô¡qÖk˜õs,²®ÿQ:°wùÞ§¬DM´‹/¾u¼æøº6¯ò;‚`! è(ú£Z&ÜQÈp‘]1"b~-Z-®0ÖýšƒÎZÓºЀ£¢‘ 7ßž»óºe…£Æ_A´ÌÁæˆV6§ß²Å±§¬æ„‰¯l%„_ê ¸v0°ÏuƒzŒç»EAl>.ç…™!BeIXÃ^Â4Dq>öêM¾¼£±¨;ã}YÖÿ3X!ýNg’7OƤàcg?Üwa”•\kHß³ü×ÕtŸí”ü@È„ýHc*€:VkVÏ΀³'©Œ;e?µP¦L¼6 ÎŒÖ.œ'‰èäd@ÅÀ®ÿ§3Ï@…9hjÏMò –NÖóã%ŠFœ;¥³ü »ÞæÞV•<`KÁö%j•zÝÞÖ2Œƒè;Û ‚§”L¬^2AéëÞ©û³ŒGÄwE_›–z‘‹À.ß™°K/±cȼB%gÜ›Í.’É›Y*Eºá|d ͳ‘¦ÁÕ\ǵ÷¿-˜j-_qÊ•ì)VBBu’ÈH=/Ë0²WüÐÊ7¿å„LFgüqÎEgò]4g{ ´@ ’‘#z«Ã(Ëï¸dŸA•5”€{vˆÇÚwE†¹*j¹œQ'Ù³ì éA¦=ÍZÿ¯·Zqô7õíãâd{©¶Öžid~cLë·¬òGÏ^S˜ëÁ…pÏvÔ¨å³äø#^ìÍ}t#û·M¯ão-8PsX+dc-ÏIdH ¾° œL|&³çÏ{sËÒ‹`‘°º³”ÂqÄkܘ‹Þ­ç($RcDlI(sHkÙvMC©DÐ'Ðxñ†1vÛ’9îÊcCŽ2'É´†ønè®´` "ð%GÚØªå;áÉöZ;Øy{dq‚n2ÐO¢'–yHu¬·¢O R©¾÷Z=a»5•Jݶ«¥(ÏHù¤c¥ÌlÂÌ¢þ²Î±íêÃà¿Ek ›‡A(0A’R:ÍÒ_è•>RbÈëšvfY’bŽÌܲì ºŒcŽ£­§—/Þt˜u6  »»[ËGaÉ‘d§±(È«qèÞä y%ñ²!Yoi_M‡Q2@«jþYfòaL¶Ÿ=™çgX"ÀÒ£¢óÙp-Àùs}k=)¨"˜û¯ªY_·3§.Dz`<ÐÏDpŒgÄ= r7]( '8šWœ)·!Aj$²-7@Q£âû¡fÄ;¿Ÿ÷B-6f)SlDü,…­(½2õý :¡&#Áqß~ª´9Cû§ŸýOXµç{„ÙØöéd49óÍ–µ7GËÌè>žµdiØ4kûQË×´'*Hvîï?† ´xK'ˆ;IúâZsBe°&[×U=,t¢ÉFMbt Y͵fpÝÏ\= XÆŽ ¥ü@ RÁàû˵wÇ«wd‘Ð5gGú2žÈš@[Ûî%Pÿ[‰î†ð{B®%Ë<÷Z•£C‡Eu•¹· è¦yнd¥ƒ1Æy ÒËdÅûÄžã—5Éñù$Ã8’¾u/­+†#kä¬pqd6 Túȱ™¦Ì4V 22‚W}oOîMÈŒ§¾ÍumuþMºZs¶A´zTf¾ÌieXé„ÒfE]ºä.¡£8ÃVQtÞÈMãkÉY—Ëv|Òi”¯ô”Æ/x3‰ÎŠþÅ„Œ]ˆ]fFu"Bà¡#®ÏjM0O[]{T§D_ l@Äfü÷}éÊW@Ç ï5“¦>HH¸©IR£+\û0‡êT©‹ rNø“2ö‰(’<—òs@vñY=ðÔIÚû„„Å}}y¯/ž'ƒS‚W¯cÓ&¼‚p Qí#ë•ÐÞÓCâÅnŒŸ. ×ãóh[¿$A˜ÕÛü«M' ÊþØlýtpË’`S‘̰ 1‘IãïÏ\ÇïÎÑ¡…B*1ÔiaÒ)ËŸÿ>réºpZ‡zÍ]9îX³czÀ«zLÞé4æ"A4Q7•w`ÜαԆ6ƒ– %“:Q4·/_}GÐQfªQc³ü1G#è²ëò]½£µ”Cë;¯K˜&eòá3WÛà’z@k|§7Ën‘/ƒ?ú!èã_7Qê=‘Õ@§ŒÀGMöý#Yå×›3„uFÏœNzå9îh•†û°}3ßû†ÍFQ0œþÆé«QmúÌfgŒ†©çS! Í‘ 4ö9B†ldŸõ»XÑ3Î2œ¯\ûtóœï@jù¹gD¬i"`3ýD?øìpI–Þ[Ë"T­g3ë Ií¦G>ËãßÔÙÒa 2¯G¾ç3Q»”3ÈXÑ_-~‹-ìщ„¯cl»®÷|i ÜDtúÀž-é«d…tt3èXø[z5à<‘ r„žBEiþWßI¾l9 JœíIéø  éŒÀaÌ×EÚ·õÚý®_¬½Ÿ ´E{ÜFþj;ˆ9A’8.šÂ¼¬¿Á!D¤Bë]gC(Ì=`Ü0êbüd¤Þ;ëüÌ®dЭúø’Á1Uk$sDÛ«Os}ŒFälP 5kà{NO´qqó7”`AFF'YË» £ð+-Cy}«IÞ ÓQ÷ú¥¨Õ;åBS"àå"!,#”S”LG]D2zLèð7:ozïù~öo7J )ÃFèY^‘ïÝ•oe%ÄÈ•”©"´%39Žƒ¯6~ŽQvx6´Eb0Ð÷æ—cS Òù3Ø»1Î PûIJ,!t¯dIË~-{ÁÛ¢¥×轎»æiÀàŒBw÷E°í3—@7u•›ßHýŠ TFƒî÷WW›Ì±9™N8ûcœmVµ~”ž×œêKïÝnÉòþµq[ìújcxFÿ÷…»ƒï±MVc(2ÖŸ·ÃúPÛOþú»[¦mz­–ðÆz#â:œ73v­vþZçLŒí©ØåxÔRê-íïÖ–s¢ZÛ²Ï0C^þÏ ZÇóW¬IøZÎà‘™#3NÇŒYK2ãóÐȤ'××8ƒ×š—dôf ȳ8QãkÚ*:^—ñÃw°)eWýúyvŒ¨™O¶ï:úØBV™É•]‹ïˆ?ôF:e°s!w8`%ÜÆ¡^ÌD¸šyüÏK;û½tœT@ÌI î=v/ùìПȸR†®N?mï¨@°ÏC¸‹.Õ³b]Ô5@Ý`šÃ÷òúÙRö“ÆGýïNE~%$]D"È>ÊDq’Ñ)®”VþeåÏñ{qo἞¶~¯ä¬>èî¤H`jXll¤ÂÁxpAss¥ðÓ‰ÄIJ›u¹Ž•”ܧ–ÏÙf cÌGÔ+FÿÙž‘õĶ7¾X•œÙ °‰ØH>ê4ð;ñøêu›Í¤•Q&8ÞìóÓ ÓpNþiÕŽ!ƒöN^û¯éiß}fºÇI@!‘ñõð‚å)s6_ôX¬††]ðy ¯\‘èÉ×Ìç”^ÆõAg¯™•ï[£eÒ»“oËžvó–`¨6ÙמÅöù´ãøZ<Ÿøìf¾0h×;;Œ²Õ(ÚôÌ>.’ž`´oï¼ JP 0Áce>ææöˆßY²npÄuð]§Ã‡ÎÎÒ'u[ȶUuíÏ ógéÛ¦?ý:zµ;/þÞãØ“¯€Yÿkž²FŸŸh:_÷Û©‡öídOÈ +µ#Aᨎ ó¯ý.‚× šK[{Âë)®ùÝÂ…"ÝX¦ž”Kº Ž,xXP#ZO}ß×C/ š]Ö)!çÌü{neòjÉ—=]É9óÈ3߃JA 8)7&Gt½D˜2³¹@èf¬Ë}]kJœ$ãÃÚb™™_¿púwÊ‚/ a[ÝPHªOö¶¹>:y¹V4‰L!Úƒ¨1!»pdö°çص¯kNãúýàŽœèòÜ!È­Ã@Ý01ΨwÂ9YÞÒã5õYŠ€ý¤ºþ-(äß%9Ë2"¼/{~$ÚÄŸ¤WŽwÞh=8!rYaçÆ1(ANùâ¹yÉÉ÷mƒ#ejý T àìéYl@î8©>-¼qótùÛ–½«pÐ Š>¿í’+²IŽÕ•m/ÌIµŸµŸâÀVìŽ%·owmÝÙÔÚ¡fü —oœž|ãO›“¸-²HŇGìóïò¦soÝ"È­¢U4 –œs+eˆ›é·JҲ˺¾¥„òèŒìöœòµµO#qûís›|[ßéÏ_úäôä6AÉ÷­_ˆ|—ÜölÈ·ôFŽùFæJ¥HñRÞQ·;žA½û9GØæ`áUI²%ÂL–‰¤b;Õÿžhæ|©}ç¡—⻳f:áxÆn¿EMo¤ŸoõÛg5õ›|qºý•¹×{@¢3'%ÌW»–á\ ³u§ÑtÉ´2†CÊ •CÌ œ8Ø ÀGÂõ®ô®EÚÅM‘ÄoÌà0x‚¨ÁÏzmfºÛ;iº¬<ìgÜ8ÓH¨„7g´@"ÂÏÐú­/këùø†œøÓ¶¾fÿmî,úÇg’η––ž'Âϧ›n KŒgþN™óù‹Vå ù¸µú­{¶3àAR_Ï?`Ée¿#ÑÌû´×Å0Úòú)Gfdé/0dˆ “Í:¬¨­‚ÆB6UvºNéî!„—É ðВͧ#રRw %©{W²\8ÈpPØ=c™u£—s_V)Z-CcŒŽ`\ÍNš î.:­Þþ¬ü4˜÷iT>‹û8Ljeê>Dn$ÁüÁ¾®Ÿ¼Ïnؼ(yƒ½¬k¾O0°SÖìÝ­{•5g°‰Yo5À‹ñѲ@ºS²ÇøØr¯Ž›åÇݬ¥úÜlþ´¤öèfÓU?n׋æ9t¡ãÞ£“ï[ùô†™óµL~EïÝôõHÿï‰Ã`dI Ï“bvÑ#ÀÒ#³m`|û4¦þ}Ïg8Ù¨ïdreý !ÌG.^:èýÆ74Gà“Q7Xe“›p‰†Çæä\²h"BQvZ …SHän$eúr@­O^IIh[2³ÿxF¢iè÷!êÑgáÖeÃaf‘ѳ¬ ŠëÔõ—/ßke7¦"sļØmo_µÃ´úÚ1žÉ–‚ûgà ¯¬AÆ à(²&œ&Ì‚†#ñ€«Gí83›ýc]k¿õ‰¥ë <ÝR‰ÄsœøÆ´«ù›ÛÀ0q²S¦PÆTžx<þ¬9¢zZÀ…c»."2鎖v‘½V ¾÷ˆ ^ßëÎ1‘ç½'‡‚º‡œ·6Há„—3öp¬ãß¡SãgÈ1~†ûj³V×¾¢ëè»ñøYä=¿ýlgþ>Ǭ@K\™Sø ð\örfMF{NÓ‘R6Øepà\à3#ë;Eh¬r`ú³ Lc–Io(Ø ¾é`0ͧ<‹sÁzËꬳL0`ÕLøŒ“ÝiÞôåª{Ò=ÉÅ|×1v{vh«ó^´ hÓ0£îmoÇyFuÈÔÚü¾h’2WÆPký@Rž”=ïL-3û¨ÿG&VÎAÓ™2XŒ‡cD#9šo‰8Þvx2Z¶êSÂÔ—Ñ'ò¶s%`M9öϦ»‡m†,Y㦞íÍÙ‰¾œ1å*=G‚B¬M».8oÄñˆîÔ‘3´S&òí4g†AºyUجï܃5¹|y4~ù4F_b ,i’›Z#O¯ÏzÊ$?*“4”%ûïé;ŸÜM=ˆáÎiYâž%,åJR¢2Ñ]{:WqÖÚ:mšèŸ»bÓô½>¶îøÏée­ôÐÅ«5÷¬ò),ôhc£çËÿcΡ~Ðlf}¤…Ï"0 üsBÏ]¾ñ— ߟ ò=rùÈœ`ì u¬­©ä42Êß½ê¾Ì|³2Ür£¥ÑÄöD¸_)Ѱt\›œ:OˆÕvû ÜÒVŽðëmªØùÿ+š 2¼ù­t”w»†P¦˜;²±øÞ¤Ñ r6]hJ N¾ïhr¸Òq?€ OeiLÈùl*ùа¾å씜¹¾›[~~H>‰NÙV¢ËñwàkØuŠ¥ž„¨¼ž®%§½Öpû..êƒ- T0Úε—½‚o…ƒ"í«BŒ {!L[3ô‹GR¡Þ r@ A‰´DÙâÝð»EÏc½ÅøòÝáe.4•Þ ‚—óvŠ.'|ÆMvÐÆ£ŽP²gþnϸßਇn{4t8õrÐõs›ÅIÇ÷toê© ½ì ® 9òª}T¼†5õáØ»¾BÀ8IŽÀ‚È놤‚ÆÔsFê8Xn0Q{!3Þ¤È=ПD2À!ëñTãvbƒÉ¥„ÍdY;Yàr˜Ù¹.Cr ø5’+’¿Ï9böOÈΡK±6:(®Î3©TC×@™Z±äðk å¸JÉP?ÓßGa÷á;ÑxécÈ™Ô5•pNJÏo à´¾@psö¥_C,dp{FÙe¾W¨ÒZàçɺoìwñø^á»ÓAâ¢AÙ.å$[ð dTÇîHú ™lÞa/H‚}Š|KóÊE©¬|4Z7BÛ‡_9þ~YQme]L¾¸ž!d”ÓáMáåƒ+[6@Dutu3ù¢ŠÁ|øyk¦½#à°Q7|VsZ[ú8'£¡Žü LÏ0ê}O?LD79ŽX&c~÷Ö^>ü“7"ƒµë=åk Fz߹ȱA±ÿuȽ°}TŒu0Œ +ò¨÷!&M½fqÁÿŸ|zêõ¡VýSËÖc]ÖŸ–iÆaF ÿ¤vÈ ð°öŒcÇ-[ £Ôm´Trü.7*½¿¾‘a Z޾hýôîu¯ˆáû]Qªp_«»>¥Õ4ïj ‘xImJâd6CÌÔÆÎÁ; ËÚº3Gô§l5>2ºÖ>æ9Þ@€pïÚ¿På ˜ Ä~Í$¡mŸ¹tcô—ïr3Dýùm3/K:©á Æ™N`B‡½‚ŽfœÅQÔgV§rŸE³ðæ–éÞÝã'/¼= `ŽX¾¾Œ'ætÒ•ÝÖxtêï餾̯U~—™ù[ÊQ÷Îy>è甉sÂCÞñ.ósÊÎ+ûïŸCŽ>O[|æš Åv–ÏwÊoºPacwU§~‚öu•{Å£Mè Ç)]tŸÛd^=<]¥8|Þ”##ã8Ý L§ë£\Ñk¸[l Zo;„0«m!å}ž Èï @qíÜ|––rsÎ>¯ßAÝRZ¾Év‚&\?@‹’í¿Ì7Ǚñ”íSj#ȶм‹<Åf-ƒŒQ‰,<J@òº¥cŠìV_­¹æ˜„a;>ÔÊ—y#y‘´N×õúR¼ät@wÂ×AT;4õIËKp—Íäö ”k !Lò¸‚ ‘X-HÖ¢ha1¡&k~éÛ¾ðsÓFùÅ| Y£^`)Ÿ­£3WNhêì ²:êö9Ö} ßëMfŒãÎ&½¹çô팹²Áé F«º¹Ž·áßí=¾táÕétËñLçOžp8}Êúžî€Û_ò/ÏMhmÒ^}ó¿»ýè75‡üû-pú-[ZÀëñt¸gƒ AËÓÁÿ罘±–êg”“¤Ñµº`$›=ÁõðNôùa<ù»tèë¸ÓaWÙ@Œ‹uï И4®¼nBëó{(ˆÏEã)óÌ:¡/RÝñ–m}”Ÿ1úÐ~+:5k,}Ø9ièz:x *T™I8XÞ)î>ƒwÀˆNd0±öÇøð¹Â2Ï28 ¶<ë=s=ß¹%XÖ˜ ÉàXÛ÷ØÖ^¤¹†ÐŠèM”ɲ‘Vg÷kŽóoè Û—ùZ"qȧ ÿ»{€{7KMä(õI”¨”;âpo¯É‡|Q öBœšÊê³=¡thii>i¾S¡(áüÃ6sÇ”p¬ÒÕAP>çDÁ ØF É„L»u÷óÄV ¢&0GZG6I'ÑgF…1ÙPÿ#çßeô¨0Aª=•¾#E@a¸Éîûâ¹±ˆ˜ÉÔ¤(Ȫ» ؇ö×q¨!dÂÏfÎ[f, è߸á§ÓÅ·<30¯hÆf´ZrÛÖèÏ-´"‹„L9Y 3«hÊÐÎ\J”Ž8• $üŸ\ßD2wq¸ró+Ôg­äûõë7m’–µ Ï·Z¶,äLöƒ|¯—| µ1 [ ¨—]A[ Õ¼é=2îëÜ‚A<œô[VÿòVÒDbG¯Ø rº‰…kaÜî³Ù[T$€’‰Þ‰…úûs èÝ>“•CÅ}ÅßJK¬óŽÎÔ26%­s;&dÏÙ„ï<úzÇûØù¸îÁ—X'§®qo#Ô?Øì÷ÊVð{ýŽ2”ÚA¦õ{9¤qÍ{‡ÀûûŸû³Óß\ôXq¦‘q®™×’iÎïü®sHu}9—{ÍžøÞ‡Ûšÿý ×Oÿü²'§Ç\¹qúÅ«6E)ÀКrïSgâ;r®óq­…ílãJµøwünøüÏ!Þ{ésñoüŒ1ÆÏ|η®9é¯ÁƒË›Þ9áÚ¶V/ÞÐ>FÚƒºOÈ-aíñåxeYæï'r¨SNú ¾‡ëëÿrÆñ™¼G­‡ç5ªÓ/¨¾‚zÆœ˜»Ê"ÎÁMýP‘„t¢¸'Y§Â÷M—=÷¾D0O¬Í‚uæ}-i¥ßgŒC¦ôÒAåìùºNED‚PN)a·DÄÉn 'í©S#ã:rôlÊpw³ÙÌ\Î @¡RH”‡¾S’AÚdý ™û'ÚXî6ƒ€ äê·ÞY+(m…lâÔœvrös£Ä÷=j• ëDkÝå»GW‹ æãÈ©#;—HôL7§ïNá}ƒ2ß)3 LPŸ½ÔT@‡)Ûš³vüˆ~ÐÄëE”|ëÙ%¯|øK˪÷RWcŒðZÀ/ÅeÃãôÌ¢Š0a2Âð7D@ Ô\ĨËÑY£#R­ S”%åã±=ã,•\ÙPäTSö£/YŽ¢eÄÔO‹P©Åõ¡Õ˜á´úÉ^®k&2î …ÍëB©çز:‚?$¿‘¼(ßjÌ;«†üƒÝð³0îÆÉ¨3{ÙúrEÄÙkdÞ;eqø9ã õ©°A(…{ {ÝË^â˜sÌ :+Y#kÝéPF8ehY(g²0[$}cõžä+¹ÓœÁ@ûœ¤ì >ù§¥½J h@?„3T3¢3 +Ÿ’39ƒÕ¹®pó-Y;”½üÆ,ÿÂ_¼>³á wÎs]g¢=ª:çºî^õ$l;ÿÿŸu~u.~Ÿÿ—£g8„ÍÁÔßx¾¿RóóóèÚƒ#>©×¿ç½æÇ³ò3yÿg8ÙsÈ9q}¦Ž{aü¿Ü«\K÷áóæçS¶ù÷|öÈvï…Zu@rþÄ)µì m¯ÜI:§2`FšW¼w1ó÷jCÖCl?Ç–UÐëÅ Àu‘lP9M®eê»(ê>êo0{—k°e3q´[úœ, b¼¿˜ 3Olf±ØWiÓu‡Âúoõ<å¬8äkÆ©³ËŒ^¹˜ £Eý[´¯= ³çÌJOÒR Ùï¹’md‰ f¢=‹×à|UÒŽœ ®¡…¨-±Q @:Ï&!ÅwA;”kDÜ(cA)§·´ÇI6'û.Α@}Ú™ L›É"¼n5|#°7uúÒ‡Ô‘i;Þ¬G8Ùú¼tlE$p¾Ä™¤q(œeL%›7wšdÁÓD.ï*'ß/R5µîQÑØ>K_»Í Ï¬¬¬cUH¬·ðÆ<2Ü =-aؾ~ò%r‚P&(°§Ò±çwódoV'Ô½á{ÛßcláÐ'Ü¡C‹š¸ ÀHîáñZÐåÝ©¦ˆc㯉NZBž”-‚='>þm â’!’Q¼I0¶'¢¸î£}RÂÝAJÙeN÷°xn’$þ0ïäDˆ›ZÕÌzc!6…‘³/]>Ý•'„LÙ9æ`ÄÖóË LzO9Âr†”™uÙíü7œ±tÄæý¬Ý®#Éq„ÏËxeiÇûség’}#È0–‡ð…ßÍÂŽF"ôH>ÙtàÛÄǘ¾(lvWUWWwWdFFþëÿ#âi*п]ßÔ9`sÀª=Ñx¡K1xÔzŸ' ä àb©çïŸþãKö£¿Ô­6³ßœçp à§ÎÒ&ûpþù¶ÞñÎS ö12|ÉùfŸé_ê›ÏÙx§Ÿ€y@óx¿3¿î„BÌõèμ#á»ÿKcUìØùw¼ÿÌqæ;Y*¾ú,°*ìÖ¹ÂÏ/œO –aIWžûH%¼ÎÌ-öéë;v½"ºÚsOMVAËV™@“A[ì…^<Ž%œ¾ Ê6Ç1&^×Ë!¼K¿™ÃÞgÀÄöçØ¶–VHuX‰?ÇIE¾¬uÛÝ6s`ìq3Ð<Œs ×»S)«ƒ¹:f(€Z,`§R×vã‘… obL;¶›zOáÊ‹^t8yÈYŽJ:m©úò|b.aªcAhß >æ6+z‹ ¿Ô({+Þ· M~YÒ,A«²6@¦£üib7”-¼Ð9I Ò”–£ú“(º™è‡SÉ©\ƒÚ-ºpžH<:ýg)¢ú|ý@ÊoÑÝ·§¬³è!{{š¢–Ð/×a @æ´ ¶h1&'Bóa›ÅºT2GÉQ至 N{e!6¦hl•È–«âö‰Ò˜ëitŠ£„7¬*‹QQ|SÇ)7nJ]äùÙSUk¶é‹€QX-ë¼Ðg›©];Nõ¹øúä¦xg\é?çÊ~3=ðË5waçíEÞc¹l„ ` Â[ùŽ—1e©‹;Þöñ\ñÃÓÛi3ÿ”¶ç{ê€ €ß€Ñ €>ò?`øÝ€t<ÖÏqÐÊ}õ'Ÿi#Û¶±à‘íù. Î~ó¼Áù|~?^ënD ÍÊ×yÅ£Õ~דþèՆ؜ŒŒÙß×ËTö€é//úÌ7ŹßY<ÍöùÌ<˼Ì1ÏòXªút_³F˜uŽéó9@Þ³Ò³xÈ‹ígšŸ%~æöXT?‹ÏZŽ­ìDÚ;å°'ÆvõÃLQ@²~-šJþ0ädÊ:pÎ5;„SÊCgÚ´Åå¼Fõ¸©í’ŠMýØ1èXKã̧¼¿x²óÝyÔÝI çœ"KÆríŸy\BÞã!âßR×wê@Ñß§è|`¾¨Ï+|·B>+­_Ç·Ûf¼sS˜K°“𻲠€¿æÓ¢ß¹‹Îqã“f•ÿ3 ߯s}é§³5ü í§ ÐKübŠr¤gà´ô¯{¬±ŠÊÀZùÿg€hq;Qö…òš BníG‹Á-ÖëЩ€Q}þÍ àõØž½ï¦`8Vppè OÙýäFÍø<÷5à‰Ø˜Ûu¬>c¼¶)Èt+®å:6mÈ;ë1])§ ˆâÆÂÞnr0æ<°K¨Ä©ªQF}P†VV‰bx¤ý\_+€ò²¥n꡸Ï^d™ÊÈ1ž‹Ê1ª¬â§Zø‹/2V=jCi‡»Õr!G» 1i_²:ªC}¸ºµý\nÊU»Î3Õ˜@6æ.j{͉mq3ÄÚkœýVNo@ßì;Ÿ€XïB)çøÄ€w¨ãª´·AíêôoŽت³]€Y±ä¼ðô}mO[SbX(ƺ=ÎsqÚ‰Á íˆVʾêÕ63¦Øëï>ìkÇyËÏ32ó9ÿ;ìZû´3Ÿ9öš—Ìa…,…{ëPoˆuŽuƒDñؽ;>«àziƒtímd4K'ÿ+«Å% žÚºº2€Ii”À¢Õ*†´´WŒãÄ»¿[T·B ³pÏñMMÚ±²ÿz]iæ—R”V£ bdÒ~Zã"»Ö¢©fxECà§ÆaœÝg˜vjxlÖU] RßWè°þ?³1t-‹ÞL¾Í²­x¯¥˜ìãCÜO‡I¶t„~fu¥~ÕÏ8ðƒäKð-^ j%Ü»±=ô ¦/hŸœRî¦ýY¾¥Ól/Á­4ÀÀhQ;¿»eʘAóJ‡; \Ûõ‚ƒ6lq¯^:(÷ï6èSœ|ÿ\$î¶D]ÿ,ÒuÃÐÏ3…Þ/w&\Ï¡ŸV:”R:/rƒžæŒ˜Û÷õ ¤ä”–Êè1ÜŽ+’Ï0´´´d!î†.Æ0€Pž×õ€–QÃñ8ŽKR‘’¸Ã”PK‹¢•"Ÿ¥4ðO[Þo¾ë~ 'c”Å(nôKÏ5ÙbNœÎÏ»âÒh#}–•Ô•>®{¤zv ê£4Q59¿ñ,Ôžã¸ñnÊÜÒÉÍý ÌUo¸€iâž0©Ç :6ÞqŽ%N;çxm«ýK%}{ùùþSŽm ŒËëÿÓG)Ó<éœ+ŸÓÆ#}l3Ÿch§ŽikŸ§Ç…mÓSgŒ'ô ÚÚ€*?ûŽJû/¾Þ1RØs¿™WA¨.ók¶[ì.Ûö¡Åˆ:^†TêÁÀdO=€Ÿý ¯¨Ê <ä¡úžýSä9u]B´ec)`‡(å>?bËvœ6†;‡þ‰‚š~õw†Û—SgÈóÞûd}=³yw(ãHså¯å0’Ó¡ÿzžVÄärßølLØMË¶Þ ý§Þâaç›A±Ï(›Åê”q;'&Håø+óDF(ÝKøf`«óÌÀu'{“ÒWkÿ~ÝvÇŽõ¦XéžßÔU@r]ÏÓÏkë] ÷ÐBø˜ÏÅ!Gež ©oÚQyûX$Rj­h ¢:wÏ^ŠRq,•Ã[‰ÿ<¨r/‘&@½ZÜ `¼c”Hz¬D[‘ðhƒözJ=Àe›~ìx`ÑuËͧíG퀻ú«Ç6?_{a¢TbP†'S…ØnʉsBŠr'Åo¥Á0€ì@ š>mذhÆp&ïy gôAñFG£D§( ¤R‡c mÁdÁàñaükñ5íRùWÅDX÷˜>Ù× ¡a¡¡ßvÚøköðÐ>Û>~ÿ-@|¶çxÊý‘ÿr®Ï6oOëø«gÿ3†Ï¿2RØ 2†xÌmx˜zè2>¦ÇÏïPú1”PÔXš Ó—ÙÆ5^í¥ ænäzŸ•ƒ]÷Ù6¿É«?ã½ûóY ƒ–½ëܧ¾÷ÏThk€T#ìù}ÐCiô\;dèlþÓy©(N1mÑ€=~n Lû=γ~>µåVØhxÜòŸÄ•¥@K¢Ô%Ð9kRײ__kZ|Pò3{UuE•ZX¢Äµ;4k§bÃÀ^ Ul—Z¶Bé`´{Bé¿(hê ˜[¼Äe ý’ânp¿ðP[#ÂOÝ.¹Ôe$:y¾*›Ö“ :Wê"ܰĶ LûœaUøyØ–Ö:(N3ؤÁ©ÂF2â°÷ãßb÷ßX¨òÀœŒÀ¦‘Pöç·ÕÌQQ\ }°ô˜ |œÐ› úÕܼƒ©—óøp[Ž?÷EÙ zå;X($Ž8×FØc9µ¤i˜"µüž®Ìíài\–qTœÓXÿ9&}C '~iÚÏ©{'óS`ßc™—+1Ú=ÜsÅÖ{Ú9X Ù^(‹Çt!¢ƒ3RÍ´WÂsÍ!g#ú#L½†±ƒ@žžKýž¡žË@ÔÝö‹T‚"lSêÔôf‘c¨ËÏCæÇ”-@Ç‹ÖéÍ6à]w€DÏÞË´³Åà·ÐB ¿€YâŒñªZp ðʶP¹ ÚøVݵ'3Å*ù´ó9`÷Ù—ççGÿžˆ)l£Žj€3ßùd»ëÍ~Ô;eíO[ì?c¨O]c„ø’m3sNSÜÆ#ç0eê1«”}ŒÈ=ÿŸ¶Ô³Ohôb1äûÿi3Ç,cIgN4<õì´yÜoà|¿JÍNìäWjAƒuþa«½»ôì#&»‹¹ù=Ïö³È,éW쥽O^+ºÞÞGƒgÁhY³¼ôpL¶±Þ*LÐÂh‹¡x•O,J³,€·RbùýAûã,’Ǽ(ñ7] >n²‹_çqhÎØz®£°v+÷u'Ì{RÐÑOÇ÷õ7u`d*kD^_,ø{Œ—¶–®´Â×eNwÐßcÂ'¬à³œŠ‹iCºÿçÜ2#:zcÙ¶PRýö6p3õ±“AÆ,ÌêAç䏸œŒ­(†Ò@‹–~«jˆ«ÓÅ’Ø5í©³w^ýÖ€è¦Ê Ê‹»¼~º •NÝá6>ÌÄL(¦hõ¡RÙýà×ÿ>'Ñ×5ù])Tù®Åë/4ÎÊCÄžì´OÁ¨QÿÏŒÚì ‹t¡<Çò˜N-#N-©7u,á6º9Ž}-t¼ÏÑê½uí °Ý‹‹Ož¬Å^„uUX[°aEØØÁo•bl’¡HãÝû×S öãVØ€ò0ïÔ‹J)÷ÓÞmeõü¶–K…÷YÛ§+Œ/êûƒ<Þ%ƒ)òpS¯ÈfŸcœ³÷3Àýaý€í€Î/kÿi;^îl~¯ãfUÎø¶o?^íM=sn«~Î?Æ×çûïsÄxÁùü¿®C /NY7óêbpí$¤—²ÂØw¼é³€Þ 9}k Ä›ßîŸÄ«#4gÆI‰Wç“<íÛðe¨–U„§TZÃG´cµU½óöœ§-­-¬6~ÏéFm‹} hr{àçÔ©öÆãímç€zLO7³3é¶æY÷\Å—Ïöîd©`v{.}­ã¯ú16p8Ù)áÄ‚;+qSGÅC,˜~õpFâËͺhMB«óiã ØÄXÆb\Ø*´|1$tÍkN|—Ž¥Sê2¦hâ”%p),QÖl©ÿìl„wœeö‹\î@]â•¥]`×Z~ǃ® Y¨Iœ&«• ‹ji[CI¶ÕJ‚ëJÑ ¨”_¹ ö¤óœþÕbzÔ!C›OnA¥h+Ö2MN¬PÕEÌ¡ ŽØJÛ¡X£Ôå@T›½tß½­-D)ÀTºÅºL«RlYö''âÊ–PsÌrn‡±€‘Rî¥Ý²%º§Èq=(Ýkÿ)¥¯2‚•ãðÜŽ”ûæꪞ½¾Ã~Ýx@*¼zÞË3þ­zg*ê^ š.jú¯’Šõ¥žØpbu¨¨;&œ˜myJQ)YÏgÞë{Ò[ꨦ–Îÿ¤9Îwyè#Â&!Zp5„[P˜ùcD p‡vj:yÿ^Lam÷Y ½8³äñ=…’¤®\ÀøÇ{o\ §È|æ\%ng÷ÓÑÐIt)›;ΑH§zß*¨•B)V‚hüO<­Ä3‰¡…ŠÚîï ¼.þ‹Tbz ²éCKIævDg§.}Ê0¢‚¬O'ëjüôSuྤ ?é&ôSª–½àvð­´3¥ÿÌhùÅâ:Í΀&ñè>ªSYV¾ôÝÏ•‚a Î]©u$Î(Oô2zWOêSêŸ#RqTzp£Ô^<ÊúÏ*ÍÂká[eé ÷qêå|ñtd“±×\јïU‰v¹Ž,&J-hi•ÚW>h5‹{yù’ÂìI±%½eÅÚ¦N+zÛ3>¥{(oˆt™^þ¤žÏçwüŸ€÷Äo3{WÍz]Jâ¹d xÏ÷?8 _xˆãuÀý±{ÊñÓ—”PáicàÐåé£mÿ ýY¿Õ€¶Ë€M{þÈO½•þÎØ½þ¹Fik l ]θõ<©§ þC€<ÇüóPX7‹nqºÆòHz·ÅXò¾½ñxÌCGd®Óâç?Råø•šMÙK,,ÊþGg…ÁÛ-|ÀsV€n¶Ey:ï­€1>‹žÛm¼  c´8¡”6ÐÃ> õ c­öeì%ª[BæèKé³¼ž•âß©Ìßoê°c½Oia=.9F@W7fËü¦>³u«“ŒíY‡¹¹‚Å#ëã>8¥¿Ìyé  \u ºW_uaˆ3mýt %Ú§ùh °YKk±º|×~b¨Ð†ëõ½a¶ªÏ-˜‡óR:ë|.V€Çš8uµ“õ^Ò?þþÀèyMf?çA¡\…T´.¸-)Œ9UROõE ¢³bæš|GpçüÁ­¿(J€­Æ69HO|ŸSŸrU—\ä97nå<Õgµò¬ã1Ô«D1hŠ©­žLö]`ÚU ?àS7w±TúÆ'ÖWc9Å}Øcm , ™^þl¯÷W»/b”W)}.c€ãOêêÚqE)Üë:óà·®ãöVZ" n¼h¾x×Ë4mHœ§XÃ+› mzñ` Þ~Öþ-ÞìQ‘ ÿ¶àÅ}êvŠómøÐ#"†0"h³ßÎÕí´c¢ª<И¼ú¶F·§ÀêzMÓžóH{ñþ&Æ Ø5ñÙ)¡¯;î<ûâQŸzé‹ÁêÄn'N@¾¯Ž‰ñàê?õÇ80uæ÷ó.–€ö[ý¼_¡ò¨ÓgŽÝÿïsȸwÚÿz>O;k¼ž€)´[sÁ“Oµ|¶¿_ªî¾‹·¾„XèsŽM¾þh>Ç[Nnöÿ+(Ñ;^4r°_Þ°Ïär2ˆEçÔ=3™v´Ìw½Ûã@H|o÷¦Ê˜ ÷§Š]Þy¦Ã¶Ô­ W±¯× À!ÐÜ-Ü×}CÅ_×Ô¢{ +®ØÌ"”_d|Sü"UVñ^ÈvðÄ$ä¡iP\DK,0– Áþ%­/÷Óýu©ö‰ºðz1Áea%ÚŠê´¯ñãáB¶¨Ô>'¬Ò­u±NÕò>UPÌL^àýò¨¯~:—göï˜oR$õ¼á!uƒâN 2PsÛPß¹yý J8I·|[aSmòR×|¯¹ym¼"ÏhI”Å›¬Ÿz†Ü ¿½dø…ßž{¨Ó옛ç9âq6…ŽEu{=|>ŽM}_§ýizîSó9}bÌø_Û³Ãñ‡?ýú¬k €Úñ÷ÐÜͰ‘°ã×xÃ^8]«ÏÌ -bd¨gþ"Hè¼ñóÝ1ôÜ#:7ÿKu~>羉ÁëISWŒú죰“ç¾OP»™õÃçÒ2EiõŽzÁ>rŠÐ,Z‹þŠ´Xx_9#ŠS%ùyÌ1KkÆ*нëàWç¬vhxšÐ•—á·ª^[ÅéÉ,bÅqÍã)–aúUÇmdèñµÒ9Ð(ÑTÒN»F§¤ ˜ "¼Ï•ë½ÅÚ{íjý¬v=‹óÒýŠ“!¬’?Ä•w½Éú·¿¬q,ëï6E'/ëén €pÖ3ÓXÌæêK<¨LÖíší߬xßöUÖ9Ym\PÎu˜Ñº¢¸[5’› p`ôlË€êæ;(Z Ñt ÚoÊCÚÖúEÜfy¡bƒ4ñ$„q,¦Å˜–™âXô’w´¨€¦ñ´×aM  MàsL´¤¼¤¡upéᕨÞLýå9¥§IÉ8¨`éMýSØ(uÇ7 ðík©Ô3xy/*¹EçÜ–ï { ªè¡çÿŽ­'vMiÎ4Ö¹æ›Ö§~6*Þ¢§=7Kèc~·´¢5ª@¯²˜ Œ¢æðxš™9 ¶€”7ÿqÌR}~H¸- uSÏ€ŽWpSÙXHO¦œßE); Ðu C›ÞÀ0ûg5Û§4EóïÿôZwú¾cÀÓvú†G@Å ôòÅàÏïùÿо<ý„7¸èÈ(`ÝRÝÔù_F-ôH³Gú=®rlÒè™"1C€ãjy‡13Ƹç>%ïÓý\Á…vˆ<™E\NF×*²å4Cvä-£}úÆvúœþhÍwÐÉéTíj>Å·Ÿ€G½6Zlºƒ¡¿­ãÎù¬a˜ øS™nòÝ,RϽ£³îaœµ¦Ò<™ã;:—æ¤ÞÃ+BŠ”«Ï}êÁ SîælÑRv ³c€cÉCn†íÎþ0s¡ß¬Ù§åÖïÀØaºkô;Ø”-Ì@ñò¹.Ô{ÒÒ;¥Ý7¦ÀÓçí»9þŸöåÐR\zÓ˜x›ÊkJ¸(¡²Ä™†ô*Åšr>Ð]œAQ½ `P¹Ù$qðtf‡²0¥›ý@êq(Õr½ âRÊŸWiÎxØ×xgÒl:¾,±Y¡]O.ƒ¼’˜€¶öûÍËŠotúé9ˆšióˆ2Ï4þGk®ÞÎWš:EÓC}>KÎÉ%âQ€~wꃯÿ7VAŽ|·9ÅýNšs}ó›ëÕ-ý¦ÒS:7¸˜ì;yË_©àS˜ƒJÉQ€»B$"êXò«Æ9GƒoÔŸéìó¤¬>¢æ\ÖMÝ¥” 8”´X;76ñÇ»³}ÀËÐkŠ1(ÊИñ¼ÏvÇ){Ò3yMÒ¬ù¡<ÚŠ·Jéuenf1 y~+·¢éÉQíߢ"çÜÖ~øšx;çs˜¡¸>Óg(¤,ƒŽv[† Ï=ÂV^‹ÿñ¢f›X ]YCWO|­"ðϘ{ѱˆPÛq:•=7ºd1˜çZfaŒÆÄ“b u¼ú¢§.àý¾(ìÙ¦ýíYóï ̧pwekÊÀ¶A¹ÕÄ-š&€­cà—‚øÄ:C“Æ3h-ÞÝxÁ‰ÙÖ1Ä·Ù&o4Àð 0"ÐKì7; ùóðKû©;ý·Q€ÿ~¢ï«/Ÿ>æbñd Ìg_¼þ´_ \Ž13 õOߦþ\Røþ1>¿Rw½~ëÚç|¦^¶!47%¿×Üä»çj¼ðÿlu~Ý Ü[ÐÛa±˜'¤$à=û;‹Â»”èóœÐóå2¾¯íÞ—çP¨ñÚ¯¼O=„LôÛâ½ ÐÅ€ÚGm½G›[ì—˜Õo/ý8êÆ¸¼©¹|RLÀíZ_Xo1`(Š¡š’ð½-À»Þ•¬ [*¼[1üó½yð lýF`ð:º5gò{1ó–‡c’­a‹´€å¾[`·³‘Ó8  ë€íý·žî…òý #Tñ…üIÃIÛ+ Úk»¯ ÔiΖpdÒ8[عPâ©C!°Ä­Ç–Ó·Céÿ‘¡â­¥%bÇ"&à•}ëD‡àdàTû0X&ÃC¦Õe@â>t’­Ð³Ž MéPzÊ©O™Mi0o@üZñû¦NVÀ9N×Vñ¨4ÊäÕ¼â€lÐÕ6N-éa zVºþ9s@ó'´@¢2‹^-F…heŠ“’ǵ;ä@ŸëÆ)ÐÍBiw[°M XóûpßYõÖ^–oSrí/“^ÜN¡ö‹$ºè%ât3 Ýž«•â,¢pÊ5žB 2r0g‘Îçö”ïØòÔEóúˆ»^ÿoÀ ÀÖÿÊo Š×;ŠãŠ×¸ ¤­xéÛ•7ÿnòäï|¥ñ8ïz V§-úÈäÿ§gÀŠ7xµ{y–ÿë¡Û‡>?Û¦ŒWú¹ý Ìg[êË>iúýr×9ݯcíñ:ú4 ŸsáÜÖøS´¯Æ‘ý0B0¾½¾ßöQ€ŸvRß1|lýiœóݪøxó×þ*ñÄÆ/ðþ VK€|7¸½oÁ:<ñ(‡ÒŽR<Û¦m±y¤‡Šû|!À¹¼8Ì ³W•}(W[2è›&m†£cà£íi±0öWú(Ú–Á¾hñ4y…ƒöãðÆWÀeem媮^{R,7ñ<Âã ¸¿ªŒÝ±‰³_ê-¥WqØ=’¯CÓ¢’ø1ãUCä¼ÎgêÀ L/ÓžD ½%Ý1 <}å7øˆ”¼2Œyýù¿”a®äFr„ç0kcGšµáÕ±öBk6úåÓÙI³­=’_’|H|.ëGl²È"‹ÕdEfdäïþô?GŠmi±¿¥ƒõïÿIžñ>†~MVž™Á¼ã¹»áÁØŽ1Šf—ñäÿòÖ‹ëŠå<w]xÏI| Ð”—Åa*nX^]Š_Š%í´pÿÏâ} ì²_Xì”c:ƒ¦&}V%ôõ{X…’ÜÏ\Ÿ­û9ú〈‰-QÜ“©lÖ¨{ÿyý›X¨ÞoN{QÆJF.Pí,!¢æËš(jØPŠÍ1/o…І£Žéça†…®]ÆŽj%53ïû–¯mùè,c *è¶Xn€Ÿ¹î°Ð;݃~Åx¨s¿[Eý›ý™Üâ/é¤x´ˆ½WŽs±-@<Ǥ?f¶·l»êÌý¥íìËõ`HØ×Agµúgm]¿yöö¸Ûp] Ãc0¡ocTÐXr þ¿Ç üü/ÛÄ +eœ½ï븞Îïäsìü&þ½³dØ~cyßCƒÇ@Çû@^qD'£ýýþÞ¬øõep$ Çßf@^W¾¶b¼@«ò7Ã,b¾ãéä<ŠO%åÇ*>ÞsW-ôÊa•€5¶*v—nÖ7g¶ßb°šìþâÛÈ:šDjÛ†ŽEw[äF÷<‘Œ%€ã#ÓŽû«)·¼|%Â&ðWÁ¡³.IóÉôé8Íø pÛCçLjBœ{-%ëÊè#–2㢅¡JØ[a¾³ô\ÈbmS`@JôPŒÕ‚õ²4Ýq÷oC\×_=öŒÆ-žnå5¯ÌØ3öjÓj£‹Q&ÍZ:µyQ³nÅA,š[eû.j¬ñËsÛc-<¶z¥¥R”Û“BÛÜ3çáeŽÓ/w¥Q“Yƒ ÚõŒ:Pal–PYw+µ)Söó kZyÑ9^DÊa6(*zS‹¦h[ÝS‚X®SˆWNó—© ÅJÐ T¤ââãægæ1`úN¿’ÚÍ}C¥ª…žÕ2©oêyIÝóÛ­îô$&¸b i×c>-ÓÿmÆ8“Û´ý‹é¢¤J²=t÷xÍ}ð½Ô›ˆÛÇï¿Ä£öN'ÙNçô¼Ï°Xi¥.¢”½½„s|êË»H}Rœ]€î4`xyW³½©Sïë¬ ÌÂäÕþ«•Ó–=Ò¾¶ë²?àÐûìr€0¿Qb4»làžº€ûÛëþ4ñŠÏ2ë©Ë²lÃà0mÖuý\Ç,§Ï0íb˜€©ðT¿Îµ˜ðk<ä8§”Ë8=Ñcû©õßaï½ëN%G¬ú2LÜOi€=FŽgÿS´`¼-ÏyÒ¸){(ô³Ÿ÷ôzR/ª(OûL4³í›ùžßóÄ+1>ú¾™brÈP20š·Õùte¦ã’¥<¿ç·gó›° eÛ×qÎÈÓïM)ºþOBÚzV"ŽCÅu6Å:ç¶°&Î…3R’‡<@–sñÅšmG}ŽÑuâ #XÆl/ÌàÜ#ab›Jìk~Æpãzg•ô-ª«¤³,š×X!-kÔf½:îû.î÷æìËh:KƒyjH&Î2®qÏ—­idcaósZïõ.s¦%î!Ž;Í)ͺ4Öø`Ïã€ÕrÈksˆóNÎj@ ‚P À„ô'í%$P¥¸_§nRF´(fJÐA^p@14(úµ©–7ïmݰº(ÇØZëç›—¾“îû¥cvEÚö ÷‡“ÁqÁÀíÁ‹^ƒÛêœÒc諦cãxYÚ|`PTç·©àoƒ¬öE„ñÙ(nùïµö;¼}Ú“NÃJè šQœë}}Dò’®ñTέnëï±à_b˜Ñ‹NxÇ ÷¤ÖJ÷>pÓÚçãö%뎷'L%À=KÓÙç7:Ñsç7ªçˆ\MÈ þ¡Ä`îíN†žL,òòv'—÷l;°xÛÓþnEó8ïí_ ¦ã5&µ™ö(žsâ¥6¨ ¸¾ïc€!€>ÀzîEžq€îˆÚqn€ržA9ÞqŠêè|ëÿ0 ú`ïu~ÚIêÜíÎ=¸}„÷–Ptx¦ß~ÿ“ÒÔ ¡3Fd I{#ôgª?E^ri*Tú¨»ÀÎÅ>YŸÿ½=ìwJ·ç[Ý´ø¬ÃÈy3ï:)¼¿ ¬ß"—·Ðuû˜14ò{ m:ííSš ò†ê["ÏZc¢øÖo GñôǸQærb­¶Øæ9ßñJ›ÆX!)§/6½Zó¿b0‘x™E¦ißÅ"l€X{µ)aÈ ü P{¾<×Uôáu¾OöɳÏXLé µ-v L†‡Žyè_?Pù?„ŸbÀxŸqý¢‹q¥4…á2ŸëÀV]–ÆyNç›Ò™Á5=¤ÕaÃÆeÆl• Ù™ÆsDŽÇ?»¤±­+@{ßCÞE¥rhÀàµsÒqŒ=^Ÿ l•>à‚‹b!‚{ yGÞ1D¶€9åç‘ÅKƒ)ëú˜òè«;ֽݒü þXÁ:=Í€Íç´åuŠ™'k°t:íÄÚ[ˆË?ãÌ ç¾ïÔµ¢ûJe¦k§ì¦ã£þ®Zž¢ÿ}rŠ‹‚ˆb/V`ί1÷]®Ÿ¶{ñø÷=º¿{¸©ç–‚,!©{ÝTQŽK¡ÎLˆ'ÆÛBoC‹ÿi&ÏÄŸ"uo#¾|&êÄ¢¿c^§ÎòüÍz¡ñ~ºZ@)´’ÒŒxïY Ȉ†°žó¾â5]4ó²-VUõ,ö¡–Óö©K®x³P ¬ ˜—"ï³÷eIùÜÙ–ûáþØg›í‹6õ}]?çåzá¡ÉǸ°£Ž®ïüµL‡úöÈc0à¼z4îlȉÁ§ˆÌ9'½YN•·×ó›ì1p¸Ïrî¨Àç˜ üUÀN÷žÎíMƼ ðV1ôxßg[<åÖÐÀ8I»Œ–å»,›³ù­o™tÕ Q‘UÀ¸fqY1ÜÌYn8N†ƒõ½–··)G °èütª[(çbú¥Üóü>g#½V~w¡4ƒè—uI ,G!ýá¾S˜¦úR :·µ“ÍBeÆÞõ¨×ç(]<‘°Ã^aij‘©ÉH§«gƳɼYÌÐwb¾×~¶ÉPˆ·P_®ìc†ƒBQ¥ÈÞ G~NçLìsØë2†qå%Zù¡ä϶ô;`¬{¯Ó¸è°,ùãRç·–®hp`ë†:©/#«ÍcQç^±8І3KSå»lÉ×èßöà–ôdbFhœôöLñÖ>>:b¬”{ÉIÉÿB9R%ç¼ôfmÏUÄó »FéölÅôXs¶‚ž¯­|äòžÇ[>V|M‚]Pc^ªêü̳Mv{õ˜ô“-tu `5OàÎå p‚ |Nõ…';õåò¦1Sä5€œ{ã7õj‰ÇÎ~Õ9Ky˜ B²}—÷˜ó¼Ø:÷ÑJå|/ïY·±`M_=®g£˜sÝ7 Wž÷Ûð]ï‘úÕ@rƒvöé™ÔS ڞ±H¬{bÓ3þSczåCY?ÿ§*òÃl±ç\Ù ö¿Æ È·V„©ïN׿ý§ò°O‰g=jòSò^ p/Fʤ´3uÐ_‘W[ßpSgŸçgðŽW»}?7cëèX!cqšv/»Ãâz*'ë,á=vû­È¤ûv¦žì·AÄâ¼ '˜z¡Ä—>ÑñµŽŸ_wF€Vü¾(ßÖ<’WÜ)¹J 3éý(ÖùÕùäMµîó>œjÏã€øòdòÑý 0†Y°›ù)mïTnqâìØŽ%R5ÓFɬƒƒ úû–;€ÿ‘p :8tFÁ5 [Ðç~Y,‘qylñó2¡Î‰óKÅHð&`Ö@s§ 8-€¼“5¾Ø£vŸÍ= ô`Á9¾ ºx„­¡X$iSÂÆ ÷ýCƒB–¼x/‹€WÍuyιY@žTÒŸ/UÃýlólôÂZé=³Í=ÔÔ,«ÐžÄД™Pê˜&®‰œê‡X›ÔáÃ'ñ^À›w<êüz0.  aZcyÎWnñÌ?Nýë5•š% ̾#@ïb X7±2¶whúÃmÓîƒóu,‡dÍãPÀÈòì0¤ÌR÷k§ÓßÿùË}ï¦Mk=õ$‚ö€2ßÿkÛÁjê¸ÚXµ¦Ãê÷o³­ ƺÒèùÍWȳ„é¦T1Åž%iÝ3:½`/&Õª»W[ûAÞs*¼ãXW[-ŽˆTCSØ–ººË¢}2Ùh¿Š'S&·ûöýž³/oÓ`‹÷‰<SÉiŽW‘ªMGŸ4^-Ëìã9¼Ót=/œu–lßOê,7ÝËy¥g}hÛ8›ßY·Çûk£˜§}ö_ë}(ßãx¡›§=À8åÓ_~ h˶”éûYîXùÇ“}³|ßvÕ¿Ï;Àß08/ Î1çs›9>¿ÓþªˆŸƒõ”e Q=hò‰í§¤ýÍó¥ÝÍ¢˜%`üÒXÏ CcÞ÷˜‹Ò> ^€[À^'©ÿG˜Ntø[ÅýYÜ‚p×öoßï;ÿƒt1hfŸ·c„K[¼Þ.O}¡\…w×Êë¾ß›üžåˆÉÍvÄ4É|A=¿ƒÚU4A7eÚ‚Äv"ŽöG/©Ä‘ZŸÉß!+½Ã=å^·Cáܰöá˜bxnIhª(û…8îš}èöA´–Fs¿êß%h3CÀ&[ {!è øÇK\²5)¬²†Q89@‘6OÅbh9gÈo£çŸÅ éKÄÖØGû!î)ó¦´Øø`¥=–;¸—qÆóuǽ3ÎÉ[¯~ðo±ŠÊ~ !ÑzäÖ’áC&ßáþ“È]4Œmíp1`¶Ç çX)n×jë9 #ÀËúL;Æ¥ Šñ¾f½0cáœe¡¿ÌmÎ@[Ê~;¶±•õ _Y-\ ¾­SrcÐN¡ŽcÁf»âÂDOVß[¸®€r—W(ÀZeD ßêÄ™?žxËÉ¡œ”j¯T¤³\ãÔ h1¨x¸Š@Å ÎKM ­û+ê/´çXåm-tèF1xŒC5¨ŠEÔbûã€gÚx hÅ70ž>›ñÀLYxêr¬êLßÀûß~ɹsL<»k=û²mèÔ³}ý¦nî…m·àݬ§æ^ÙÃÎÜû硬g;yÆÃÜkùM°ï¯ßQ}‹Þ•qðÄ ãaÕ‰Âü”ä¨ßÿ“«ä·@<Ûœ Îûøï"îÈïxÂÑ™˜˜óçÚåYoa+1ä=tÓÚGémdƒ0x`Ÿw(ÀzêÈúƒàœ½î„ åxåT¸²!vÓ ˜\ ЖçOŠî5–£z@Y¡xÖ5'ò\¹ç÷f¾¨0Ê´Ov%§¹›ÒÒý6GSwÆ 5mѤR{GÑ.„Þ*Þȹe„YýD_+}ë9d´Ž™]ì¢q‘u…°ºUOuzv£Ü“(ùÄQÖ~±€ålq*ªíçtצø7çbÃbG—6ó>‰sZϬ8ðä3ÀVј;MЗʡ/‚—jî$]ÄÁú) ªÀôAm|Tÿ1yØËû‹šEäú53(E—‡*±,CMÄ¡SŠ<𬬩{Ù/F[?Ë`sþFï/âcë×E38·Rvtu÷Ôç…EIîãR ã|ê3Öûïg”™ž{H´ò©ûˆkH ø …z‡;Ìv?·N“*ºÁ9Çð÷ƒ?‚Uɳ¤µPQèƒÿKLN~u’|åk]BGã홲÷Ç+Ž÷ ¨„ÞðN±>“Ö=±…æ*OyQsN¹&Õä'ï9ÊE)éœÑ(UK%[Ôô’Ú P„p`l§ÔH‡ö­ô`ðàæÜ+(Íl€`Î;m°nàšú#û:@”cߺØw?d}zÎŽ'ûœ›m³žmû·ö,C­^mÎ5&–¼ äó{î³Õ}Ô—ˆß¬¯>ÎõÑÇ)ë\uÛ ¾ÆUÚ¸Bð¯~–*§Øu<ô„nöC :sߣy ¼ï³ 5žøôÅ@I†ƒ½ÏÞõİó*T÷N‰ˆg}ê:SƒŽ[©Øf}–€ô¦Ÿñ\¡LŒšxÐå5g `_ëÛ1À܃0º2ßrzÒW,-Þßýé¿û\°[·ßAêÒâÚRV›¤k+`ÓÔfǸ3×~V`Vʼn6ßÓ°qÑÆâ]W' =y3>XÅŸë8A)©\& 5Qèw¢ù51ôp?P»WvÒVfõ‡ó¨ËÕ»Q™^ÔÅsbQRljÎÅ«ÚA@U~dÚÒ@Õ’bi|½tëA0è5 QDìm³Ý‡ëSܾ<íò,«ß2IÕPrú% ÌGLtø¯k@WŠ)w¦06_ ­üÝ?ÿØrlç¼>6'9ï«Æ‚R£ÄÀ$Àþ¨ÕnÅgÜž+ŠÑâeÏËz}ÅœÐÿ†¥ólbü’š+?,Ò¢+yÜg›¬âÊAO»¬ãQI±ÇÜñ”»m&ƒL s-+…` ~ñÄnÞŠçÔ‹gÏÓ‹üÉ» %€>ç¿„Þ.õuå/ç :ÀYÀaö“— .€¡4cŠf_óPžDMÞjީ฿ú:ü¬/Eñ€âbT€!Ûn€?M¶SŸ¬(CE/íp ”xÉgÏûœs®yJ<ò96ÛRcíe9%,€dŒH}ú"ÇÉ+ŸB¿â5϶ëZoQ·9_@¼Úš:——Þýêûm@Û;>ÆÈ´'*½Æã*ㄺ>ÆÅûÖ³Í&<ãVÌÿ)4ødEÈv‰Öý;á%ICX–XuÖ§\4z‡ÂÌú¢Öç½X¿¨êa”£—pwÁ>õ–ñSÞsàgI‘ÙM]€õÑ©¹ÐŸy¿‹Ýåoc¬°NøèGTéŒKVÀ\Ú¦B§.@‡”ÒpÉ›éë(àܪé9–c¥gcNbtUä×s;æVí³!a?Þ¢I/MÚ±U¯zÓåQÚYX¤´/ZukÝS+FiÚ‰×8€J˜HpÇ,=Ÿ4ö¼×é-&ŒÃÕs`Œa2F!Z·ð„ `fÅßu,zKéNª–•«Å¬Ðaæ‡:7!œnŒÆòðoÁEMö ã%ÇC ‹¢x£±øwÝÓŽMÉ×±%‡ºúc }ßãSƒb[pdpPŸcõ*^qîã@ñò=±OåŒ×çEj¶DWkôt½äEb{ê/‡lsì“|ŸNÝÖiÝ||îbÁ:ÎÎyÓ¶cºrSüÑ“EÐ&ÖõqZj¸‡˜¤2Î[ÌWɃ}Ÿ-ð²=ä3‘·GfÚd"Èvy…{)š§‹ê¼ŸÜi‹ÐÔ㯀øÏÊc žã¨I•úU í·ùŠ{¼Î(Oçx<ì“jø\—Rq±Lû"ê”Hó5ï7à ezƒ¸½Á祬YN{òÞ¦.Å Ÿ"ox€ê>ç àÝ4%ÏEæ,³¾ŽÃÀ§NâÔ|ul»Á?}<ÏG}ãþy@Q<×ó9xNÔ_÷7uèÛœKÇÈê ŦË#&—}¢Å“7]TüÙ§ó©ˆ&?`|…ŒL7j|7ë%ÅB’.¼Wèc44ÈGPnyÉE{g=ïO˜G÷»vŽzûÑ¡ô®8vPo°î÷5ŽháNmë >lC-z¾óNKëüΊöüBzJ©[Øy£Ì?YWÝ"H€Ãuöä!¥N #$ôî𤯸GúÚ"^~{;G!«G‘Z®«‡Êî¸o3=O`M¢}bCxnǺhãJ«ªË¹xî_ÚŽÈ´þ3•y AëÈX©‡T‚pj©1OÊмÛî?¶9WéùŠâ9é>žë ˆ/"Ûf4ôLCI³Æ \: {u˜<ʧüçPX2 ˆÇàá;ŸÉ½b{œ€:ÝÅÖ4«±C;1E‚9ñÊQPœq(ÐY~ß/¦ êSL7ñ<@¨Uù»1†¥ÓÏõ?/ÜSžÈ¿-j¿>˜Xá XÑÜËzîR·:?–ñ9§Ù!„ì©©;Z¯ÙðH‹Æå—-4)αŒˆ»`”;ÐÀt­i ¯=–0"$žSŠûÖ"~Í@ å´7ëPÙç·…«;`N¾q(î«ÞMe|G9ù›÷Ég&·î©—üÈËC5Ç5zûLœESÿ4€{©H“þ)1ºxÒ¬*¹›÷6@Èö»nµr‹q­ót¥pÇ;î[€âIÍÀs–ˆ¢-  X 8\@YiSÂí%ÿî¿Þ X±í«ÎÂpßýð+í=þ:uÞË´õ¼×é—r]sììŸzÙ¿®!u³ž>E>ËöÐâé_úÃt~ &.ô}nq:Ú!–ŸþÝÆ„Å^ÐuYÄŽ1Š@]×*03±º›À9»a ÿËi?F1ç[¿µ&üEûÁíÙ¯<ê1²MøiS@>qãA¯ÆË·gö³=ïË„ %ÝÚ~W'Ûù|cv4Ûæ}>ušk©œ\q®à![,°j$g_6ÝdžœpÌ_î"ZrÕ£áØÒV›Û+ŽWà_€ý•QÁ)ËœŽ•y)qòÄù뜢짔°<Õô)¶žÖ:§Í“’ÙÚ¦ÀÂÝa%VeÅ=¹'æåë™lÇŒu‡4'Ö8B@¸eËTΙѠ3k–zL {·à½‡ûŘOsàš=ÈuŠÃJso±_—¶ÝÜÅ5ª€&äbdï­TíµCÂòâûåvèÀ–öˆ ’e‘eI3'VB£V³Obu€®‚íŽ)'ß­”*С?Äï¡lÌ{`ò'ö3óº?`SêgŒ‰ê.ƒ÷™mjû¨*ÏuÉZÜ?âbuè·ÔÏ-nÈr‹Sœ cmüÓ—6Æ,Áò‚­1Qþ(cÄ‘±?w…™,!F2)(Fq§ð±JûÜ_&wÛãýìžqoGàí‰í§LV—€Û¢¡6öпÖ%îÆdܪрq&ø)ä|¾×£ºžTS»l2e{ ÿs§Ód >ˆß]ç/4ë´2UtÝ Ì‚g€p@ýÏvzêÔãußm €õúïãñ;Àý€âÈÕS7`yÊun€6à|ð,Èö]Ø>}öË:Ï”i;mÎ5_çšñ0Ÿ«þ¨ÂÍq¹VÚ~»ë§­óOc8Ø×¡>Ìq¡º‹^¿=å¨Ï PgÿÜO˜%F‚„ ØÛÏ3uˆîÍx¸ŽNF(<í0GØ6uçø­8Ÿ>ºÆ·cÑ?þËKÐqî† ëç¸ÃRÖqNɈj|9 wÓ•²í΋?õø€z½O§þ 2€W¨Pr¸“šm•ñº+Tiê’®m zê›YhËlç›ãüϳ|°”ž†ì“1Ú 6{MõݾԨ}|Mìbk‹R?ëv>,ÇÒ™¥züôr±.Kº-?7Ú=1"{Á#ë6 ê¨ãùMsnd¼Ðçª#Æî¢‹ m6‡æèÂn\³³qœõÈŠÏVßûžSטm»øžì2û”{X´÷âI?Œîrœë•ž­Š/öМt<€L¸¯ØbVΰnË^, XÊ tþMëØ^Ú&*¦tåUAèY¿[bGʵlMãƒ)/}èBëy9§ ±4Êó—%/ÿ&eÆÀúãØêj1ÚÓ±¾Ö‹<DÀ?ûxÞFˆhk¹ŽòñQ,´©ïÐÖÃq¼5u ¾¬xi—£¥Ž ÁQP͆.èvs½ ûÃL±è›÷§ØÂÉÇ@ï>fRLJv% ®Øò¨KhQ3ãg2‰‡GÞ!ŽŸ}Ž'÷ïæ`GZn{Á§à¡œ"5v–K”m–‹¢{Çð.z¹bÉñ¾ ޵åØ,cx—kmòfOYÞrÂ}= 5ñµŒ²ú¦QSgúùÙ µ ˆÆ‹=Khp+€Ð<Àwö¢}¼ÏÏ:ûÞØ—ßÝÕ ¼ÿû!éø÷ïY!mùø«/ÔN  žkäûº¦×`̽äy¼—0†€u¼ûÙ'Ê{ÆN~·swÚ½hôÊ*½Ýqè;ìcÆìÏ;ÌqÏ¤Ž °Žúüïw~ö’ÃÐJ}2+P—wSâW&ˆ%B™íò½Mž÷¼C—ÐÜCë€ùçˆgÞïxõÐݳO^÷ÔÉvéï¹¾qg0Q„Ų›bFÞÛᤚ57¡4ë}wèsø¡‹RÅO!z²ýÈ9|l™Ôa-¶óLìòEÞïîÕ½éw×=žÛ žç æéi`îš2ÇŠÉPâÒç¹0¶é+gè 0,^Î#!;Í }÷«œœYq9 ={>»pQ4ñðÁ@iÛÏ-³b0#Sóižae±ˆ¥szï|¨ƒ‡—F‰‹íÖG×­ƒ^)¹J®g½@ŽC,(ÿ×@Âá‡Ú)ÛgµÎ:PLM>x¹ÎUê²@³*`»Q©k¿šîÄ@O?38ÕÝ"IŸ :g0FÒ×R u¬!« ’9Þ´‡Mø^v˜`¤=SçNgüÊ@B9äx•Zº %/¾¬™z§wÆýµÒoh[lpžzSîÉ÷L åÝ™ºIqg_&®£àÔLXsœâ>S‡í*òte])›>ëwr–Kx ,¼ÙÛûm=à õ³„’»À‡Ó¢…JLʳP å ø(;û³Ìö9g¼¨öŒ¶thøxsg™ó S ¨ý›óøR'âq_CA¿Áé[ñ€àÏ€tÎËñSw–ùÔŸý¹†)ä~s- r]sì,ÓxæË¹§í€ýxìç¹rn® /þ6<¤^„ï8÷,y>ó|çZ¦MчQ1mgœ™Þîâ}Ðþ ÌîÓ,ŒCÜyÒÂ9—?ûgœ²þcSÖï¿Ù8‡dÂZB{Ï: ý-ï bÕ£[¡ÜêlÃóÎïEÇIˆÐ¬x/‘Mt=†yÔ  ³®uÀ:¿U–ÊwrÖó}ï§ òN­‹Â8Έ»_N8¡cW# 7jÎ D®4®åû\Š4¢ÂÞÔ@†ŸÇu·cIý(”Ó :»Zün, rzäþP2ãOs#c…Î6¥xïï™d¯NÈ N†,滜³Ï™;óð*ÑêGÍj#‡ç6ŽÊX­¬ã ¤Çæƒ_@}e‰à0Óœg'ÁEá:QÖ_cÝ„… Ô7Í gCêŽ0œˆtòøqñ\øYD!ŠÙ< ¦2í•ÄQ7Tê.^¥Ti9žNaÐ!^щýþd9”í¿â¼ÈøSñ˜m2RSœ÷ TeÈzFœK/éž– Øõ’?ÇiûYÛ’®ë·1DK¥ ”ÅÓÞéüÎ@Œ‹0Hª¡ ƒmóR€VßY'Ї)FêCêì:–c¸>SÞ¶¡Xê%PCOΤ‹ ›øÛõ¿a‡ÂúšøMòWÂn¿ÿ¢íC½âÊ7µóÊü‹'²]¨ Øžzü~s|*©–Øžúxû›°Ô­Èóg/ßZÚ# HVAé@OÎmDŶê¸ÎwŠEÏù ~ÿÇöäÞ ÷yÉø½½Ï¸ß€Và˜ý×ó ¬ÈÀ{1Õ=ZÀ6O8×ÿ¿¬K«néU…ëÏ$R—T4uùþÿ€-E‰u ä;»NÒµaËž F´adžhÏ–(ñœª“]Œâ *Dl¨ Ùî¹–ƒ‡É³«¡&ëö®w]¿µß1ç˜cÆ)àȺ¢Û+R­~Àç«i£kßûŠ–¯þ8§ló‚óŸmDâÓvÓõÙ¶@¸èìzQ½ÇhÏ6l•Á œ³Þ¿¡3C) '€žmsþÎc/¿Û-|ç|t8N:ÛQ¹±»ãû±¿?Dç¤ã•£ …Ìi;ô= Ý{ uâ€`\–­ý'@Je­•r ]— ¢¤+Ú\Ƥq1žÙëcŠj2V±V Ë× Â)dÎ=ǮǬ­t._P‰uüËz×ÛVo³U¡‰¸öRÏÞV’¤õbW@˜é:O¥4®…jQ½œÚTmCÕ¾HÃáž;ÞM©ñ;Gã:K™¼znbWJ ¶;ãuë€1N§?t¨ôžæÚYvõî=Q¸‰H~ÇÒ€.Õo¼DicoQ¹aÜE1óÁÛõ˜%—/~¿h:ʧUÄ9T^™i1ª{8¦²]˜½cœÏ¡¨ÑÂÒwù`؇î‚ù˜\¦±p^éS÷y¦:§jÛù#OïYs³î‡ ¨•H©ªŠ&!tÈ;v¿5ûø^ú‡‰¹±+ØFé kHžíü†äi5­ Ó‡Oíðæß”Á¹s¼b0q<°Y:GWÓn_H@èÍâÉ_<Î?”È€q¢áôDÌSžHÎLgŸ÷(¬Óÿ‹¥¯ °Ç¡ðK/=ú¨iì€vm[Q¶PhYŽ@ëìˈòeÀF¨ÃDEe€/4eÌ_}vÚs€ä\k½€é –»Ï¬ ÍüÎáéËtoîE΃m¬}›×åã—9× ªÇèƒsg]¢þëžÁŒ¯xQì Ì×¶€ïuÜãÉW~}sN˜&[ûå=Œ±§MžÀ;ó¬ãƒ]µÞ¦ÿ(úG0y*d9¦eµgàßq„õ-‘±-)%ÒµH„]ôˆ`†qÌgØl›¶K\›oí´ÙŒ&ÊRfùhCÔ=€=ƒêG;ÇYЬgyÓPàÁ9i”tк(èi1 +óÐFÚ]íÈíEÉ5ð/ŠÛYÖøÈ4f+µ£~¡ 4ôtÆ¡Œ®Dº”+]Ê5³Î÷Õ÷¬k üöçBV`ýbÜn+`VUlÍú;"#ý~©4}S·Å®\À“¶J3åÅòUT;Sýß%%µŒ3›Ém\òMi¯º7¼[Ù·T"ó³6­Ý¸ÍF?¯mñ7G3¿Â¼ czÅbê©õªk¨¼tD¿f½@’r¹YߨéªéØ^¦×­®íbç‘;œè¬¨'Í«Ëõkû*›·HyÆ”ŒÇtjQˆDK©ªÿ(¦Ÿ"-çñ¼O©xFL¥Ñ¯ÃšH_šFÝœãåÇÚ´w?k1v©—ÃòJÍ´g—œC³Í ê´×»×´\›Òâ{þÈ‘NY 1ó͢ؾrÎГ_>F>ù îf ná¢ÙFDGàzGÍï`_TwåŸoi‹z¹¢&òÙ™žƒå;EÅœ Kä{,Ëý¼ºùÜYfp¿úAæÔ“î¨"ÀÆÈ^;ÜTbïØ Eƒ&P<í²>رe¿D—¤ÞŠ:3¿#íÏ9¶@õLµ?0,¡5öÉqÈq,ÇY±öyw GÓiûÞ±= 8×ÿîœÛã4Ž‹ä¬/g ΋û1 ¼¢ú9çØã@çº`Ä|/ÃNàþcÏ~ ¨ãÈØï©UþyG¿hï|-éGŸ¨ç+E$%éòû‹„J¼eS~»ŠÐ+=‹7¾þ‚õ|{`âàD$uçîþ°s^uÖ—GÚ:Õg vQ¾Ó±,5×o÷¨¾»ÂFàçûŸ§€÷¤?e}œ¹Û² Ÿö‰Ü&ål‰ &éŽÖÒ%WkðªñcÆ„ ºÖëƒ)jÌø p=còé´1 ò&g¿ò§Ï9Ÿ8ê [Ùß±1;·ÀĤÍ6=S£)Y‹% ;u ½@ë8é2Ú‡LŠÅJ[f{ð„h× ·Ä2(ßøíiܨ’ô[œoÒç&Œ&M)˜›Áü.6÷^Ýèæ2ÛI†Ë>þ]¿¶x.[7W]\8ø¦í˜퇼£Ïòü%rÛ5•€c ’)ê6Ëä‘w¬œqÝhy{^N?W (ÈÔw£‘²æ;áù‹†m`êRhxc}=×xy ¥LÙÛûGÅñÇûÛï™=¶þ!цTŽÅ²k¨‹6µ¼ê—„•±¢ó•ó‚¼õ)!æ›G±xCu^8"n»´ID3Ž(ù)ð†ÈÏÊ5_‚oÏV4pŽI¤hlÑ(‚s]`(ê‰í6[£Ñ´“P\è¬1 ¹-ÐM¤\µŽ×`•ô¾™~Ž].dÝÖ(»E„|ÀûÌŸQqTÓ™ºž76÷ð=÷ô†îœ|i@ÕˆqDTeÀvœ]ÄŒÜj‹±¬s^ékƒeƒú˳>ý€:Ôõ0³ïW?ùl¦ØÙ>ËØócÝÜÇéŒm9ÎÅþïÜ}‘ˆù´IŸyb$?óþ¹.@yÀüÊOï =«ã­_¼Çq‘6qªð Ê1È»ÇQrƒV/àV”ýŒÆKÀ.Œ–^›ÿSý-¶ÈÀ—²p|,N÷Ö‡/e§K°Ä+Š>û&¿=LŸ•n3óPÝmGôûÜ~‚yU¦ðü]¢ëPàý-§z|œ«¤BÑrRŸ°q—À¨Óæ\ÿ¸‹É¥Ác¬´]lÄ2vÞ%³zR•{J óÙ?yÔ—U¨»Þ%[÷µ¹4³Ç}`­t»2n$€u³€æÜm[/å]Æ–æª!ü¸ µ剬+÷S ›|ÔÌ“î;f¡)Õ^Vgÿq.œû¦Þö¬¿9ú—²TÎyÕ½¦ô•¢ŽìcÙOe¾L§6g=öÆ×¿ëç;×5SŽÅþs>Ù®ãìãçܧŸsÀN{1# Í>QsSþ) —ånôÏ»E®=QvlÕÈ/¬~C8¦ò“`b~_ ¬Ów@sTà÷ïÙ߇PËúc”ddiaÜ(ÕÈw ðž68kú«[˜6Ÿi@Àz´BÌUiã_ WNûéÐåʱ @Oþú¬ß ~–©ŸA×,‹}Yr»/hè-#ú»Ú–(uª²dýš2fh`^QfE2›yü–©8QF ¡e=à¾3І"ßqtÀ,•2÷•¶ÑL7-ÚåâÎëÛ`®œ{ t)e6Ç‘¸ï¢t¥xV ŸÐi˹7=E˜ö]Åݳ.˜Sµ”«»¿ ¿ ƒå™ë0¥š€°T±Šø3ÖÅ!UÞŸەδÿkEtgîÿêH ƒ|峺Pþ:ž><ÐpˆÏ°ª&Æq|}—e\›¼” »ÔΡ䓸VaÍû3à女gÐ×Ñ„3Z®})¸ŸcP‘——¶~q÷qM}†*Têš÷È?ïáÜ÷åm“—Ð"vVö¿ÉKˆ£;Š:å›ëw;¿c¹où “΀!¹Þòˆ7êP¡hñ?Qÿ~]Vµo êÈþ¥_ø®„&ÏÈÇ\ãçœÛf»J¦Íù²¤eÔ‚E¡„Ž™Hž s”|GÖ3¨XÏ<Ë((Ó ˜Îg„q•I[jÍsݼ uñÌ“[NZÐŽ” P«ŒÕíþì³iééûSmOyª±lÇVn0`lƒô®h`Ï~Ð¥Q§d˜À~Àa€6”uÓG@e"ÊÁ±#ú ]|õKGD´÷1™Àœyì£GÄY?vØWôù°ÌµÐÓß\Àž}9×d§çZÀ»îsæóÌcâH‰š}×¼Oyö‰°gÞ‚~þÖ.ð»H»éÇyéo“ ¢w@¼J¿ÉRý`L€<ß…Mq Gt’4•8çv‰¸TTxEÿw“¶ó¹ÅåNÇc{©û;fR¦ØŠ »Ú†¿ùPáÙÏõÔÚµåarÍÿ¨¬ßB·€´•2IÄÛ€˜v;°Ôu[”<¶Æ„îà ‡uÊ¡uy6èJå™.~,¦hcÊxŒ€—K_9€—€œ#oÚÑWwZ¤?®S=ä%ºPýŠmzXW=o‚c͆ªÎøpçhí5°Í8œTQJ+<%FȺj‡Õ4HÿFœ"ëygክîOÚÉu 0÷¼çrÉ`„î(bÏ¿°—¥Õt¿"è€ìú ÝsØMQj¢È+ï:í N˜ïŸ>²O\뇽d`NÈ|ÏßøèeØR©Æ8 Ï:XU0¯ÄÐjÿƒ^?#Ñ+"Ÿñ†+u€â€µ²Y߃[P§E­fŒ<Ö©òê[t`›£§#;kuö¥û#¶Ÿ‚VŒ¬ Í^ã·ZRØTý+5U¢iH|î;rcúl©…°tËóˆ.!¹ »Þ)ì”kÁ²y9J‚=”âÞó»d<%R«¢ä<öž~Ñïô|1žÛo’ˆ¿DíŽ~À®buëÞ/óù¿¦“·X…êL‡³¯`IïïÒ´n8?âfò(•‹å<Écæ&n*ºÁJ–igàÖÏugÝëÐÝU)vÚ’[t«"žçÜPbç˜[Ü%,˜Jì þxJùå¨ð;ágµ¦½~%žJê\ÚË=ÑpƒW3&œ£]ËÄÙü‹ÙÛh³ø Á{¼¸¹Ãc¨Lôÿâs>Ý¢mId¦8[-ߴ‰\ €Ÿþ &žBAŠ”˜®Î`ì˜ß¹åð…ž>ó¨ŸËÝ(3d€ Wmò™j°+¸c Mžh¨©™ÐwÔ O¤ å9fWCÿT‘r ðPàŸ#Ûs}%*OÎ;zÚõ߬ú!b>ËvÚ¤óÜk®‰þrÝlWD`ÿŽ@?`¦~ϬúOtÝÎ$ô‘½™®w•y9˜(·ÁøX–Éeïªòcž£†TÚ^r¢ŸŒ£¤g2×! çñ˜s¾@ÕG®Q ±¥ín¡à[êà¯ý¨{•Ž×Çë=JnlA{§E;×óöÜ“¤xìk&®Êêø[ -箾0ÚK¹³Õ^é±¼cÙ¶1˜™ë7žÝ÷"ù^€®^˜¬“â8€AÔEìKĺ€ ß$¨(Ž>mpD™37-9/‹>D(zÎôJnyc°þêBk^PÞþ¥3¥–xˆgR®ëm:",º8α%$¼À2r¨õèc§ë*Ô,ׯ¥J×àõÜ»úÎÆ1»~ØR tý•Ñ’vb6È)ƒ‡SUõqêëo7,6虨ëJ>ú3T×E[$*.eß ÄöàNjÃ+o<ëï©i¥ó§2½[Tö€ó'ÐYÖ[ *ƒ`œœWmuGÁ ª‹¢Ž°Ó1jwÀ¶úI»µ£ã‡Â³¢y=‚ ›K}Y\-á€wDÄáK¹åPpììm µ‹ÆWq´Ív§Z0……ÎòkÀ@ç$¬¤ÞéŽ\lœ«Î‡D7ÐÆ1}Nê»äzܪŒ€ûäĈ¢ï¦¡#ä1 ëêfë|–(qVk»³Ÿkz;ò¾ó9Î2eÔ«_?PÕ¹´ç¨EYåµäñã9ç:îþ@Y©wéº\ƒKv¬|£<]¿ÑîNÛ© R销‡ÿñ1Fïó½äzi[EFâÜdÎO‚rñ¦UÂâZ$O,Œ \eÈ@'ƒœlO‰›´9BÐX WMÜ´ƒÖHT&"o3À›å€íY¦ >ÂD%Ÿy„‘¾7P-Ð=ƒÇr)$'’Dž8ù㦚.úú´0}3¨f;tÙL¡¡‹ÆnEi(ïî-²­üÜ1"“µn7`ÛæH¥(ç t%W€L”=û¦3‘XÛsõd;6”òYW@òÚs `>Aòã³`9åМål›uòÓ×L³.6ç2Ç_ÇIÛ¹³<ÓÕ¿ÏYýâ<0øÇB­Ça’¾ }ÇHÉS/@¾§*àøÈþa7Ä!¡þEýÏ2à} Ñ‘çŽÃ¦Ûà}ý6\'ÿ^ý)Ÿßþé`;ülãw½«%@ÛÏò2˜=€vÒdfß|»Š2üéø›oÇÌŸ¶rÝÍ(2x§ŠTù¥àGäþFc€u¦8^aJ½þÁ‹TìØuÕŸMŸÔ(þ´Çv”ô¬U§ý øúxõ:æºÊD—*4@ j­ÇÜän3ž7ÝÚ@Êeå¢ÕK¡¼ÈþfØ´tÁi¶õȺéΨÙ:Õœg¥qò˜Î¿”ÀX•˜1Çà‚z)Ôg;Óé'¬ úÇaÒÅ]²Ž¾ZYçÿ­°Uúa~Ò7BÜã‚,²#¥§rô>=Ž'` –ÜÏÒN¯ÍZ1X_´ùDÈs=[ËŒ”n(î›Ã¿/¸Ôš«‚j~˜±i“h!¦\Ôô 8¸k=_Sb¬$©Ò3S*°ì{7°E¬­y| û…ë7@rœ)WÊçË+Ë9±]`ݹ:(!²O+ ¢·Dì¤Yæœ(ß&o_©õ+È3ÌU4ó.øÀ³Uú@WŸœåx׊Œ™+xx}=>w—-ãx¢ÕºèöܯÈ÷Ø}r=?¶¡Ì•ÐQq ¬fy{ß^Jí¿¦BÎ4öÆ/ZÞ9Q¶"?ZFÜm›K˜h‡þžuXrÑ#æ4mLAwžê žGe]ŠÒDÎg9m\ÎèàªýTôO¹â¬CK5¸¡@ÔÎ2@Z€+ ÚòIÃÎòÞ¨)VhÜ´Sþ·Žm¨«Ÿ ÷¾Xæ§/[¢Õã`›m@3À€-À8ÇfÀqúO›´[ÀpξlÇÀÏú9ƒpŸ‡×Û|½7Ož_Öó|$N§gåg¿ß'Þ™®¦/ ½"õyŸ ‹$–wžíäâ°ZyìØ\Œ¨\J¨ÓF ª<Ìš¬_ ½~‡œ4Ó]Rê ÛÊ ;)eÜòíÐMTêr²ÆæÿÁJY²çÝ`üX7\þ÷€?CÈt9왞ù蟾´ÙÔÚ´ù\ÿ£5öëÌ<_L£Ïö¤ömÐk/ùÝ€äκä—ïÎ:Ö_JúŸ"³•ºF  ʹ€ÉŒo2ïó/âØXgy2Ó¿ *Ù¶0'³0ÀW´÷‹ J›úŽX³J)¶6ÄH[S—!£‚q¼ðœñmxö8™¸>ŸãÓ]t²ÿÞg„ŒÞ1óDúeMÈožÇ0ÛtÎKé ½¢Ã.³FÃhÎ%JQøú…ÆÎÒ~M¼B9!MÕ²åð*£ˆxûâ*bÚ•¾úW~ððéïþðá×ÿèG¿ó⟾óÇ?zøå?øû‡Ÿýµ¿züGý¹žÇRÊvt}•ädî`—R]©÷Þ­+Á›‚ÞËrqNR¿bÄ9‘}ôÃtt\ÑèR"a)z6±=Öã<ò–k$×½Ô»\é¾×¶d¹ü³°8Üé&ÜwÎÁÞGÞ59 03ÈãÛTA"ç›6•ö‹’HÞøèk™¨¹¢+º“:ð®ñ›è7€[ÌYžÈPTÙë ˜G Mƒ^å‹×mÌkàPXj;£ZgÄ}Ú±_"cψd¹ìØÙ.bmŽø-stœôUæjús¤Ò¹Íï0¯Hê¢(()ß8 Þm%¤&pyR´×ú³Qjìq£ngß3b°ŽÐÛ±žˆõçÀ¹dýD£s®é'm3Ÿs›ÜuO@öŠ~³?×Àñç˜Ó'× Xæ|ÎòôÃa™Ï+††À§Ç9žË\ûLÉ?ï5áõŽ]˜µ ØoúUžuî,$_|úÀ¦¦ÿ*÷'`Õ^Šñ™#&߇üοêÊ ¥ ÈÜ»œ#´öaïœ`Ù9î‡Hž²ŽS‡}ö‘0¦KIÚŠu"ãéɃX×|lö¶ã˜ ð.Šð‰¶g;•?p:¼PGõý­°Àv9·]»(çÚÀî¢LK w—ƒ JŠçÅÖäôÂLdŒÔR‰úê\mR`Ÿö2j¦ÔïE»DÍ4N/cPc€¢˜½aÆB?¶gY¬CÎã•WI«ïñí5e^%¥=ÙT˜Ê=5SŒé>æ_Bxr*5Œd–zYQÐO¿øÁiÔ¾fÞeƿ‰~£½¦û\Å}Ÿq“€~ »A¢® ý/i"š«Ô€) ŠÀ5.R^‰œÉ,±êGCY)7öúCÉúnºæŸÿ¿yø³þÛþûÏÿúñÃþù¿>üÜwþV‘×Ì T•uZ¦Žö˜èɉœîÈe†VÒéBµd_÷󒺤‚Ëîež’ ]¡ž¼ç`÷Üø´å~_µÎEÑò[LT«.ú†Bè˜úÕïLl yCM?â|ÒŽm°, ž!®¡‰~·¶/Äß"ú¶hîÓç'ŸÙÀf@¹,ù‰É=$ºbÚ#Ñq¨‘·D¯ï[¤ÇvÇ r"=óYFðmÚ­~”C>Û8 È£‚>S´u¢dŠ¢™Þº€·úóº'ïš.‘óVê,À^ù×§àQÀéí_äl%RþhV%O;~ƒµD€ð1ò°Ðw[@|FE¯½®}‘YÑß±]ïœ; 7 'Àõñ¡6U¾ˆÀÌoç´ø8ì¡ë;òîsê˾.ΕsÁ’}` 9Ï»ƒ¼AY?¿ Rž ðÇ)¶ÃÓeð\µ`ö‹`b¶ñ€#V·cÑhPzȬ[ì;`Ó OA;ï³Ój ÄOÀ}ái X¯);÷+r>eÛžR€XÏô¤ö¿šeÐæE_Ñö8kY¦5K–¶‰ÕàI³âÿUÀ÷üÏœ±yéé\“·>ÿ++Û‘ñ–¢u´]QhÆZB ë:ˬ<¸³ò\þj×›n Dì?©ßwóuX¼lŒm01KhG€9ð·"jW-ßÑ`Ú;RK[92¬ЫõxÜiå’ç/ãšU)ˆñ&¦ëæýàã+˜±8,`ãÄ5U¿fN CY¯áÚy&¬S„ÅUai=Å'ÇÞ9èýÂèÌ^‰±FÛäÄ\*€À¥Èר ݤàÈúx Kîîu^‹K3lÀu €|íñŸïïÝÿKäýï/þñ?>øí¿›~–3¿Ô³so1µÚ& “vc¾?¾Æc}«0͆è*S^HÕÍÎòÚO5ÖEM Mо9Wýh”ßι轓çöÐv8Ù¤Z™\7•¸ŽÄý!2Ý‘w>n|tÜ\÷ØŠ°[(Ãÿ|v‰¸ÀyîùÛÏŽzòÑØP-ŸXÚ e1ƒ¦‰JL;ÑGñWà{(‰¾ŒxPÖ»Ññ gšb„ÞZT'9–+ÚÄ`4ë ½ýl0œò¨8“oŠ{Œ|αD©bGŸDÙ²¯A5ŠÔ˜?ûÛ@ ûSÏCãM ¬Ô¯µ°™Z½[ ܪëM[ç?W„V‘ðB±¸œ~ªcÎ÷^À3Û­Ý\QçôI{Ÿ'`¹€ÛœÛÙcl?Žýþ·¿?×{(´§ýûßú~œ êG@óôK¤ÝŽŠ´¡ÖKä\yù_ýäsݽž}¶m=ƒç¤,Ïn•~”ïóN *8N¦òbˆéù7p:¬Jµt"ø½1Ä×åݺ1øÊïùn,š»zí®¹NuRuÎv­Lälë¶5?–ˆæ˜Ä6-*G”ýî> *嬟‚ Ë),}¢é´cûÿ·vZ×ÌOîûË^¥„È»Ç =‡¶±7;˜«$ÔEÙ_wí×UªŒ¯œw ƒ“ãÔqn¢ßºZÚàl˜N)Ìàó6˜6v`¬=ÛC¼u]IçƒÎ•0‹Ù¯ßÔø°‹ ÷Š di?Æ·îß–ñî/ÇÐÑRŠrË7wdè9ÆžÞ,¸.ŽˆòÎ o´gàºðÆ®ï«$ø¢¸‡v"Zrziëk¦Wë$v?ìãh"h]ôAý6úK øµ6]÷àcS¿ίþ~ðÿþð3¿ú—úXª¬Ýõ}h4é°]/ãºï•åsÐÇç’ …ÈFÖÍ3˾à:çF ê&VHŽ£ò%öf„@mÊýá™Ú¨(Àylå÷xŠõÏtÞÃ\s~7k—wè ;æº:û³Eÿ[‚q³ÜÊ¢‘GްO@z¶¹®Ö”M¹;@¼"â)A&±·Ù‡õËX¯D¢§¯+&Ud †@¯hÖŠ‚Ñ~úƒê~K„Œ»­ÖÙÀ ûW>z²"|ïžÓDá“s›üá™wŽxöÏ:GÚ!?(Þ¥^÷ÇŸþlÝW}úpnÀ¨fÝ3ÛæÚ¡ºÏ<ûŸÇûϰ»ú¢­r¿µ>}¸u|ì<Ƭ Åýl{2„ŸËwé~ü]Ì~Žd‹_£é´¡0ÇÐ>'[aï˳ €¼t@ÿ\SËw¿:?­¯N"îPÖÑAÈ–ƒIbwl·Ð¥ýpˆ™‘b•xú(¿;šþ\ùêK q};´·A[?sß©*Õô¤ó°+¥ÇeÜÔ. <>•2õ}©¿› ¿…?‰¦³¬ÿˆ‹Þ°}þ¯µe:<ëH³"}kÕSÿÊÝVßb‘RZ,lOX­¾•Œ¾ q>4EýölüÚž–R‰5~7ûVÂyF¾.×'Z½Ž­{kVµ–Ù¯–´6“•ߟâ›~o|ùZ­Mˆò\ÀUT¥Qq_tÑ`šÂ¸…ì=JÔ¯R·¿ô‹zŠ`Ì´üÈÛ‹æ`gÝ´Z@ Q¤³ý£ßüë‡ÿ¿ÿø¿~ëOþi yèÏÄmw¦9F,ˆAÝaß´!·Òboùˆ&¡Ì.¤Y·æ]òè‘ÿYòÆwíq,¥˜Û9¤äŽo5èEŸM»Ý¦)T[´ 5lçwGñZQð`Ž„SÒì`žYVµò1S͉¾² ýº€8ò°ß…þ-°Nô°|‚OS´ÁfÀ5öÞ\ëÝa x¯v05 ûÑYÿÎÜË9ŸÇ}³<Û§ÏÙ'ý§ýÜËÝïl?ÚM?Y—ýÆæ˜Ó?íéOç8ç=ÇçxŸEø­1 P§/Δ²ß¬#Ä8õ§¢ø¡ýÛ°sÙa‡ìwÜ‚ƒ§C%ÿÒœŸÒl+¥d"æóÛžÔ¶ã€cy—†H—žÅX¾/Ž¢ÛÈYçïÛ’›mãH ³é©jIùÉ·xhí3…Å´O1ÚÊÏ a[¡;’íb[%¯}Žÿú”íš\õÛìO.ú2ʶÉé|V!ÉxâÕí(Àëÿ'réÉHÛ‰éuôè²ÀÀ´úÕX^A…:Þàü™f¿¤Ù‘’çH¾RõµÜ q¦J‰”®(ä]`kSyÌG…ÀV33FßÓŠ·‹ã@Ùc‘Ú^jÅW€y«ÂzNkîNc/Ú-ÇCÇdª…/qh—@vê19âåEŸLçXTûÿ‡¶3ÿ¹í®ÊxÿãØ2Ô(‚JTŒCÔ1DqˆÑĈ ÑsßÞ (Áƒ@Ô ˜’à'p “Eio/}ÛÛÒÖR,¥X;`[J)Ð)ǽöî“OV>gqÔ蛬ì黿{<ûý>k=ëY_ó ƒ*OépëEYLÑfÌ ¶ÔA×´/;À? r d.Z²j©û„-uŸýÜ»xn˜-årͪ!ne‘ò!yýú‡pÏC_A÷nyxÿ‹ïüÔþ¥o¾mÿ¿ÿ¯ûWýÙ]û«á¸O?8ïsÇ}ïà·?ÑLxºü10¸~RËTqæUÒ<¹Êœ›ëcb.mÀ¼ŽãÜl¬9h(Aq<œwgÏP>E —Àª¢ 1?/§X=ô˜õ þˆ%¼€tË«k¢o <(¯·ªµCgÏÀ&eo’ã—)àCeÝ ùußÌGÌ ðm«ík»ˆÃm9åRb/˜›ÒI»c¦(¸h¤l¢4ZhøR‚®ùÔ —95`]m²Ž¨ 9½@(}U:/Ô`S‡YF®,Û¦å!ÿØ€/íóËÎð]@D–k ¸Ž­ëÒ¦æÄÓŽ}wÙ÷¦ÐÞÓ®í“~b‰Ê×~um9V-sM'×Qmsœô¼Ú·Úæ¹ ¹ñæeEÿ€Ü òÒóÜ" WëÒ†m-U€õ9nOy@ë`þŠÖqj¡Ní¾·µ%šA»¿èAPÆ-ûù;(?ÒiÓ¾G+à7CñËL1ÀøÔårpÿG¾øäþg¯¾ó r:÷aT_7u{®ù-Úyæulýñ™Î^H>XÇÀøüÒ»LÝLߤúŸ•ßF‚Íêò¾_6 ³µœ!¹<¡¢à0å}P‰“Ôu ß´œóFáS´!­70?eqÍ1?a0Uíf`Þ•€™”uhïÞ¦Jè`’‹‰@‘©o(ìDÂ0 Ïrê”·èy¯—œù2ç­Ú ÈW$® š,µ¾ÇºÓØ«,V¶‹RîHµË€¹m™£ãDT'Åp¶¾kàÒ@³îs×±D³7P{²N‹JN_ç„[Ÿ=zÍqгNÛ ø÷mοõ·øÇÄ ¨ç Яcø{{À: }µ¯æóÌ ˜Ç1‘¶´Oþ¼€~@¸Ôém(äãRäƒ  †ç.LîöÛA->9åùÐãk}û™ÇZýuÑâ{º‹¢ïeE%ßrÖ»@e¾S|«j»‡™ViÇ´£[}3QT·Gg$m,¥µ/‰Å… Um*jn^m6G+û¶”§ü/ Eff%Ïˬ2Êý?ÔIíÀfõQÛ®•-iˆˆ÷EIU}× bÙç:yúG¥Úí·ÍàåŒß’ã§H:ÔtÀ9yå@…¾¾ ¸PK—àP‚cžÁ[„ÞÛ58D5U÷Õ mnƒÇíÜèPHå•ÞÖ‘ßÉzÊ!•IÌ-üÒW]וÖ;0g¸ê'%ÔªÆ9Ñ<è¹Ê|:”WKœå€ ”´h’¿­²a>µN´ö²´a …<ÑX€TŽ•è*‘ßÅDï =·N7«~Lë ³¿ìòå¸ìjCIg;`šs¡½ÏE å]Ͼ€z·Š¸Ñ?¹êÙ·vèö€{®¥¡Éw|¢ú'ë³oŽŠôÇ<÷b;†®OΉºç[{hú¼;ÐÓ{Ç|ÞÚ!|7Óâ1€x[ç|u•|;FÇÉU9ᥠÑÀw(ñêDÒY.Õu¥° &…wl¬2Q˱ ÈÇÑy‚ÃsÅ|/IbYßã€øl po4®¸y秇%Åÿª}@qÕ²óÖÎ-•– ÿÓÐOI´Bo¸ÃãB³œ’@duv°€‡|ýÜk±hûs£$]½`1‚ŽÍí8öN ŸÊN;c”þŒ•’,¯‚ñ8¦°¨YÅ€|a%ý¦¼ÜsЇ—$?ZE›§ê5˜›#óó È 3e„—‹mö€øæð€¾î—®ã#åH&µÃ‡šcã0¨÷ û/~å)ëÏ?þÔþ¯»I€‰ã:Z_žá?¸æ¾ý“O=Óúzü+Oïâmw˜ŽÎ‡¶AÏ;çZ¬®Ÿý줦iÊÚ0$ÊDÙ ýA’YèCâg®%Ù¨ñúÐÙ•çK[ÎaÈi˵¹ï¹Žäl­^eç¨É)à/“+Ü“ªí¾öµ ÚœŠÆŽÀ óQ¬MíØ²êɯeÔÚkjÚ Á7Š»ï¡)¦tQpT×Ei?iƒ4GÒObÛC‰ — €gÝ ~¬h¹ºÙ–5ÔU¢å7’_ð}U”Wì¸z>´ôÍάe¢¹«uPpGeõZN¿(m¶«ŸZ X"ïØ(í¼ ¼·Û”¾ ¤)êðØfMg€­ÜîD³Q¶‹  HvPMߨœSõ_SúÀ‰°\mêzÕÒ«_®ÅQt¦ì“kKDƉòW;îW;QH¸Oÿ<#¨ú8 D›OÉ{ot}åòoÑ÷\;ÀÚiaX”å}›#îªàU\ÍyÈC¼Þ6·=þqd§t<‚"”›­öa ª²Ò1ú¼õyŒ+8Ù~ûXXÛ=ÅŒŸšmŒ.´1)º¾·Y”n.»ìÈ.ãh_§0]XÀŒ¥;nó± ®}¿£f·r¿…ïxÁRNÏ«#8ß½•¤èñ`¥©âSU:\û]ÍC”‘iYèÁñb´ˆj÷( \îÁ€³‡(`ÅŽ=œ ÈSËšë˜òý˜#µ¯xëm£çòÑûÇ\àþ¢ù%ÿ©·r¥·wÀÿäþ%o¼ùà9~í+¯u®úì¡Ò‹&ÝëlÊáâ(qûÁd©¤ë‡´£}MÛð!A‰ýÑŽ„*”™} ùÑ(ç\{—PÀ°Mõ“s:&t¨~ýá§<˜xnsœ|HⵌÚl³Z‡“¬ áP–fÕ±"{™Êß@_O„üÒD::H¯ùFL$\¶EY":Ä@ÏÑåDŠÆ¾)Ư$:^£ `Ô+/%äPÕ«J!Õ>C=r­÷< Ýõ—¥Œ¾E°²‚²nÁ7@8µž‰–©¹ @ñ: ´ös¢¹ËÈ÷¦6x€]"©-îàX`0è.UwÀ4m:»G“9¢ß ¼¦MŽÝúÛœëuÏZ]3Ñðz–µ>–~–6¬_úË´ åö¢Ø×z¬#ü£€ÝîŽõÚØÚo;€=óº·€d;9ì¢ço˵ÝQuŒ‡êC÷Õú±Ï.4w£ã`eä}6¾m«õ샑†fBµo»~‡/«m—' %Šð°[,.`‡Jßë¯é-*¼Ë¸õ:ëÏK©6Àx¾‡½Öú•| ˶ʉ²·ò”rŒÖ7¸úaýªpO{j¥w†ÎX@9´÷²8wå~nÏaoã€y€û²/“ œ„P•«>”^Ã)Ž#ÜJ˜y EÌÊíÖéay«Q}‰%(`hb"è-P•K¯£Ý®MoúVάmÈVδËýžÊé0ÞßÙa ¾&M%À(,—|fêòÓÂ)²kÓ×8•9u óàÌ3Žs îj[Ï:˜ \â÷3;Ë…q8'‚¨+£L X™JGƒ‰,L=2!,È}¡ÒIêZ„§/°í?î\°Ð½^<T?EÄ1¯mPQÓýÆå8Êý H¯YÖ1MDcX1øú¦_>?(úž6!¸ŠªdðV}¹4ÑŸ² ´ˆ[èÍETô™Z M½¦‰'2ž’h”K 'ÂpMÙ3¶ešA|-=ïyå…SÙ±€oÞúW^8àFk”uúXÎ~<¬M¬LÛÊåîùÔÉŠ*`êØR7á6ڞϮÿš/À[ÓÉÒÎë:X(æë|b޳-ßPíØŸmëu?oqå«_(è ?.°_ûdÎ'íÊ8f›§]áïûý?b;Èüé«Àï¡cá8KŠEŽ»²NuX]„ì`wØj›çÏáȲ¨ñãè9ÄR»ö6>ÑsL¥¥i[§¯ß€x]¾Žœ{[ÖA}tóý­¾ ÓÆL¦îlu*Êð݉[ûFô.À½¥Z]?%õ ”ü_Z(ñ Ê©“žuõ?³aµŽ:é=eŒuN'k }XPœ¥ºËzÆ £¦ó&Ýoƒ8 Ó,ef¥o•cQUzb @7˜²Æ’(ØRïf ˜¾Ûx¬ÀÇ•—„’'pq¿Ø6)é³½=Žô¾"9}˜w Ž–-|¬4ð¼ÜÔŽå Qœû\cÜâ墲"t”´+œ&¬…öÁA š²Éb>‹ý<8oT#ÿˆÀö%αØ"ŠÉuÔ“y¢zÞPf§}´üpl¾ØÐÔ³Íù ºxÑ?FœŽÚ¢LüÙµ œ?µ”J»üìL§õºî¿áæýÿÑòÒøÛ­ÌÝ©Eþ0DæzxÖˆô(ü¬rŽÍ%÷T¾Á4ÿö^(ß_"!:–îŸ)ñ•£-?ò¡|‚®{övZYÔ ™!bg—M¢Šq¾Í©g ³'M­}£Ô-mS¯5”½¨­g¹'ÉQ­Xæ«=‚n €'"Aßµ`dʺ…Þz›ê·Ö{P×ꙓYçXëÔÞ`s^ùv>Y_9Ÿô­ì™ÅœªUoâþÏ?±¿ûs_Þÿë¢;qÓÝí¯ûÔ£û?üÐ}ÙPÞ9‘¶š'ªF›A´JÑñYAH"BZ´Wi³Ùp]:4g"¯Ž¬†]ê×þòÓûßxÏ=û—¾éÖÚ^ÂbÐÃitú4Ö4N ç‘÷rç³ùÛÊD£o*PO¶/3ím¯Í4Qs@(û¼ÙwÍ‹¯ið²:fÞæu¿0.'A®¯À?ïío纮§mÍçØy^i¯ç°<€ílƒ‚U~ôш]sÚ@•Àçf߸éò¢Àˉ%pî²~ÕæØ=¾˜)iPŸT*'ô:íÏU½õÍ!Xß@»Ø:µ-i4©Í^†æßň]*šÐ ¾Ö[—ê»E:©ž¡íJkºt›kVû+ªžåžnõuhŸôòž: åaT¢çˆÊÕúè¥çRÀžù-—½ÚŠ­8d\ÇãÙci;ˆ‹5!J±ZÜ‹ñaOelîˆæ—);™qˆëoW ßQÕï~Ý£UT[cº#*÷ó¹™Í) \&gÀåç8êï:ÊÌÔ&œ#;Äåx”ÓÃ!p¾Uˆr'é© ¦êǼýY«`tR8éߣï³ëŸ[«€g­‚ˆÄe¥<¨ L'*Êp¤Ot:¹s“'ÚHÕ9UXyÊP®­P PÝŒÚue*-/U]/´›‘ /_^Ô¾ãóèÿöÀ—ŽäCs®=o Nîá‹^qÛ½_ÜçïO?öÀìÌ@¼,çHÔÁ~Êgi–¼eå–wë`Ö§ P¦­¼º.kÖ5åц÷Äï4Ôyž…êPæ\›g·øÖ¶YÏÝï&ÏÓ{ú½½=ÔœƒOú¸†®¾L×ܶL—ßﵓǾ@{€yò€õê§)¡–ˆy%zSt¢¶“ßWªÌ[Na¶Ê¥ä›(Ì*ä6ç9"LD>¤ÚgpÀŸ¼óZ—Áf­ƒâÙŒA-‘)•F"ZŽýøRj‘¿Æ±¸TöêЀò䛳~·EýÎb”¬!ÙÍ×ô2ïÀ:Ó•œÊ¨jôê,ýðTºxìËOí_ö–ÛP'šëeSÊœÈr‹v7`P¼D¯çô]ý˜r¿COçX™f=Çã˜ìc«mïë@7ª9ºÛ)£@çm\ûæÀHT¿ú}Þ׋ pàürÝœSØ€|½KDÄ)7G; Òáı…êxž™ç>QU  Û9éä´¯´ø]ý&Úcé/Û „N·ÁÎë÷Iuá„|o€z¼D,µm±5ò}§%ßIå¨W}tʼ¡ßÑ€yáÌSò’uã”ÓLô< Ü÷žRÕJ"ÐÝ~•e𡞺„T3†¥: êïÍÄÞ©ÌÕX¦U”fß ª¤l®zÜ‹H€NàÜ,¥xJɼÖ1¾ °30u#}klFî0àœ32 £™”vˆϪéžÎ@r§ôa•f;šïí`¦ßÇöÓ˜?ísíS)8"ñΑoqÂsf"B8Ë`$Óx„y±.t¾=Ê/*1­ƒmhÓ1)ïÞTî¸GЩ¥¨Üë©>r¯[̓ U¤¶Úù1SÛ]:ËyH¢NJôº‰ ¾ÌûÏÂú¢-`\í, ]/ôp CÅð>/^Äæ>ûlõkï|4`—çÉE=ò†Êz=H@«>|PY–`×Çß³Ê?ùx‚gQ¶å:ðZÕ}Xkl’—¥V®w`¡?)ÐÛZÞ÷L^<ëØÉ GL =—äèçxÔ(ÏeÙÌk0 E”×À"ó‰ „’N4Š`¢äYguöº¨šå䔯¦ˆzJú„ö¨Á–}ˆÄœPÊçØ2´u”ׯ$Ê…SùžPFÏ"ø–uˆºmöò·Üz øöGTî¬ùDÈem}Í%7Å\ªÕi@Q@Bõ£±ÀÞUí`Ûv U֣ݮçA5¯é[Þw¯îÕ[߯¨ØuîY‡9Ïš(±Ûz_@xŽ€Y×-Š{< ;`=Ž€´ 0nýUÿÕ–}9ïuÿs,7 ÝÝ9é[{îà;Ôm–q4<{-\»-bsº¾Ù8þ â¹F9TVá¹sV²Odà}±½‰.¿õS&UúDÐs €}"ûÉmgÑrʶêÐÝù-n÷Αy(ðqŽ5ÐͼrÕ³ÝeÓf™ªîú œ¡Á«tSYJ¸I3Æ6×\¯éla=´;WÝN\ûöÿ Ïv4KºVJÄë"$G5WáâbD×Ikÿ;5_5]ø?“uÆ^`<3”È­i¼X¯€Á¤ànpMJhD¥ëð"'~ 8ylÅ9ê¸Øø Ö˜ÎQ¥a<9×Ïöx‹íôYãOQWF²Þ€¿Æ7ÐßçóÙ§ížÓ>¶Þô¡`‹eÍø•c’Ñ¥:¾Ôìgk»‡º?›ˆbËù÷û6Õuç<ô;ñýÑ}—y_"è)aG^„D0kÚÜ–W›óD¸ÈQYQE/S«s-]LlçmsÝk*œÃCè òáUÌ­ÿ½ëÂçòq`FÅÜ5+“¯@T™óú¡%'ýÑ/=µÿø]_8$F1Q¬í´c$mý¬wÛQ˜B‹AíR”í×ïÛè¼`êR ãÉ9Hö6#xÚóeB×Ái”ã ˜síêr–ðq`žT‹æÁ“=g»§‡½ïòZNI˜:_ñžK¾Xí°Œ×€g‹Æ«}/VmÐTu—É¡¤NÏ%Ì«hå%apFD½ÚÊ´‰–¯Ñ¢o{ÝÅňðÔ4‚H›Z1à<"n5…þ¹¶Q¤I¹›Z&/¼(î‡þ®¹íâDÍ«æ2Ë Ð«m€<ùàDË«]Ö3à¿Ry厨³€ÿìV" µqr»_¸°|ξë3KYÉöoûÇÿØŸù«»÷ßñ벉rªÞw-Ï5È œ,cùÞ›.€ìÀn™Ê ¨’fG®¡±{Zf°È6 KÄÇB¢Ûµîv Ôº:Îê ɶ€è~œiO¾;l¢×P·kJ„¾ÿËÉ#Ï¹ëØŠô;Ç^%~{–q†t§BÚ•e{¨þœ/ Ûõãmfsð^j½úâýU”<€]5þí(CTÚ{kÍ•>lé,Ñ€â¾nCH2móíÈ·)œœôY˜—CÙç Ø‹uTl¤ˆÇÕ:œœ ÀGL³úŽˆgMm”tk ý²W_ÐNjÔ‰*~H\”u]Ø”ÿ]”¨ËH+¶Úk>NzeIca¨…Ö>EÏ7#5-æ1Ÿé¼}ë|XÅMÃHqÛš’{켈œ{Ìf¥ó²fOmu®¦o™kNÏ@]¬î•ÁgYôŽjLM°E×+¶ãàPÐ>.¿vHÔlHïT^µöwŒñûþ0õc0JÅ ë`»Rƺ°°åbIPŠòpŸí(0汃‹©æ»ª9h”fÍüñ=Þ="èÍå+Ÿ—õ2%ʼM^¸!ïXm¼Œ³€%‚v}ÓaÔ'/^ªÐ#(Ýði¯œK)œîŸ~ú ¯þðýƒòŸ®Q‹ŒéI¿øÇÿ¶ÿ‡‹ÙË5?¿dŠ&sŽ=º+ lÏÙb|,xVÃ>PŒÈ!1……}æ|lž±m'ª5âùê# /f¤@¥Òbª3 3A^5×Éñ'Ï6åTªÿsÛ¶Qê^ L¯æ:ÛNt¿€t¯?ƒOè†D9¨›ÛG´aPÅ@ ºú¿˜h|mÉU·ìOþúîý;>|ßþ£w¢þK›cbCd>¡$}vŸ€þÉè²ìSó™.ÑÚ\ëW;{ã¶ßrNÕ¦æ³\S–WÚxÝúï}ѶRúu×rúœ¯QÖj]×m[r¿¦u~Ëü lç{å¨:ý¨ °å¤`*@ïþb¼ÛûA¹úy`Äz™>ï‹M«£¦ãu_`„ܤˆý؉Šc[¼ƒ[ ö–>ÒsÖYnTøR‰¿â¼#1¯íYžRnŠ›iñÝ ¿P½'IŠxnùé—]q}RŒ²>ÎQ"ì8\Ö ‡ö!»3Ò%¥)Î&.pLj—‰õUÖNè–ÆE¤|«|Òèí«Ã»;Á×e´\òÿ›1ösÖÿû=7ý2GLC«•ƒßBeSá4`”´;ú,›+›ë­OcL¦ÉZp޾fÚ»iñôc}£ÅOJívD­ãšfm¬éù­»âæZóô·S­ø©_Õ‚¯©Ò¡wm[ŽkM)ž“¢ÒQ€×»À|è÷29A,$=b¶a>' EƒÍ(IHš²Êw'‡þ°H\¬rÝØ?{ÖÚý’Ôh¯—Éæ|›sv}¾3ðo¢eGûBËé òíº^¸ü“<ô÷Ö÷Ý«‡Š|?à8t #eÐ|ñëoÊuÛ“ø…~¸—ª.ÚÌNe8ôƒ“æÀðb¨=Ÿi&³'¯LžÓvŸ\ÞÍ}õRo³ƒ`6”ýê:^k–ý@9QÜ3Öc(Ä 3Eˆ&BpxûWO~­WË>ßê§ûï* v® %ÑÈ/¯þ²LT„ömPæÜò+·`µyÑ­ý­¿ûìþæ{„ÿ/ÿzì‰ý_\ûÀþGßr[@x pCݨëÔ%ޱŽl¬ ¢kðý²ß9LqïŇ"öTÇìbo©y^¹¾¯†Æži„Ý «j?¦ójµôÊ}Mû.äªÔ@ML ¶M?õŠ>"F_x¡^ž)ùçû–‡.š´"á,W¿áZ#ºÏ>LĬ{þ«ÏÍÝ@±m˯ùLŽ›Õ=ª¶Ýû–H€¯ý8VÙ ´3PÈc>FíSF‰¶­¯êc;n-‡joÇ‘{?«Óã±#Ä}úYÁ€Å¶Aí+åxå¤Cc¯û€ží.û†©6|µKŸî*õ†Õo;¿eY­ç7¿‚íDÝ+j½Ý@¼ ÉQÎmH™!ϼ9/}ÕuÁDƒCßÄl˜Âr]‡Ádê;ÛkÞŽY‹ƒR½#º"ü/ÁpþvÀ^ý×rÒ§ÐR¬Ÿ´m³kŽiåÇî½T)û³ 1×宩ÞÖ%‡ýh* A—Ù›ÍXãÔc`uηÂ7cKçÀ§åÓc1GRw»›kZÏLMW÷¡ßIw+éÄŒÅ=`:?ƒé>+EuºŽ®;w¨³.‡ŽË7{lGÉ7 â‚ ?—žËS;¿ > ÔƒŽàΤüQ'm¶Ç÷4³ËÅQÊÁ³ÙKú¦Fa,;I!¼¢vÿÝ’Y¦×X_ëE¥¡@}½L~yfÑ–m“r圓<+2®Û¿óµ7˜^õ·÷pw£2 ©qÙ¡ ½ ñ–úãóí/̦T©ëE¢éäå¶gGí|¿ä”B¤AhÏá™KÍ òØT»Ñ‚¤|$BÏGcVaõ^J”°.l88ÒÞÿÔœþÑÔØ+ZþKÛ€òˆÂñ‚ËÄ0ïRj”?[ñ^¶ÔüÿÕ?¿kõGîßèÖ‡÷Ÿ~ðKû'žÚñO>½¿ó¾ÇWù›ï¾{ÿÝo¸˜AP djšyd$ÿœR:`Î×õ5£TZQ ˜¿ýŸî[#áÿwDØ?pËÃû¼êæ–O¾ÌGTNy™+Ms«—œÜñš*´îã¡¿¿¿é!¨ªÎN^+@›:Ìä´žµX¢-ë¼Lmu€~}T¶-`?é5 #Êž>ì6 až%ݧú€"o Ó nÊ;ë騻 °;7ýduòF·¤ôèäz(ލÎY~À¼œÒÎaG¥Ý u€ù8Ðíd§\[£ºð»>@Þc©®“Äò†éÁàÛÌQ¾8ý)Úkp Ó}mô €÷u톈/Û'<2ÓŽûùs]˜J [´Zp0I×jÄ6¬$¦ä~g<(vƒ*n5F2í¼Ïuò^-ÈBÏÚ¾®Dph?êƒIÓGÃn2õ:þT¾Ø×Î1Sª¾=W 1ú^¼f+ä<½FÅ]6{¤X?G_;½H+4Ó_& “‡‚çÎýT[Eš¿6`‘ºˆ™è@"˜Ù‡…¾¾ç7.8¾á=÷´Ÿzzc´þ8ýÙâx¦=ãÙkÂb¤7ˆž=¨È€tR’äãh¥UÌ%íTcRµýáõ{ëív–øð\åýêùáözÚÛëhýì`ÊvÔ2Ê¡Aƒ›éíñ¸W—Fóà€È:ë_òÆ‹ûW/`üÿ|ÿþÆ¥ Ø—ŸxúpK›á;ÁÀúÂÀ7ÀÎzrÉCiª½€õZ÷šåÜXJ•ýÿÕu¿ño>“HQ¬h€ó–^æ¨T€w štˆ ¿çô?ÓÆÀšÜÖD¿¸·è÷²_,6Ú:’ÛàDÊÖD.$ Wå ÿô_Ü?‚£dY~`ÝäWcím¢­@/&ÂÖ¦ n¬·è7BlË·D”ÁXð­Íº ÈåN¿KË}» }kÛ对¾€q€<y{fi PŽ“#NƒáôëööÍÖci»}úg ‹€}ÃèçÁvúçÙË_SÖ5ez@¹Dòòn± q@À¿¼«i6ÉcW¤gU'®Nàtö–C×8¿ ³‡ê¾-Cƒ—³-:¬#Ÿ…yU„˜ïìäÛµö_Sû%/‹|Ú9g½Àw¬ó8=™£¢íDÊ­ü¾ô­ÈzÖ„«,g‰Çµòlµm[Þ¨î5@ÇN Ã³,6ÿƒ±¤›Õ|KM«)•WHwîú8¶À®Ç–-JB0¥ùM€ÔÕ˜ < ¢ÜÆý¹u_È…—ÈXîé±û©íj£ügú~(äP¸Ÿc¹3¢¸KñÒ`— ã™ÅÛ*¯ªËŠÙ{êÒ PwUtÞ÷¶È®1L&!ÞcÚ˜²TS<Ôö:ãy åGTöŒ¯ÿ8Ï×µ†—iW”¤7š]¦ßº è^ùÎOíÿâº÷w-‘ñÿ‹¿ïû­[EÏ (Ë]YnevÊ¥­Û_¸€þÒaøjQ?½û±Eýóûk±k€Wlµ|ç¿°æ/ß÷ÈWŽÐá%J¶ ®[ަòË(§&±J½ô͇ú»Î?XíkÐl·9¢VÇ‚¶¾EÑiçŸ#„W®µÈ“ƒÛ#‡ç,ŒUÓj—åD¢+ýGÐü½WÝBù.ÔÓœž겄È"§¿Ÿ^4^ÐsÍ 0 $½Ý} ™Tû2`WõšrÌš¯}¡ºw+ê: ›}üiÛ1›í[džœô´›öÇøôµ1ØÞûÜ¢Þ5/€®\{ö«ë¦ ×¼QùÃŒ¨ã[œ.ïi#<çv.g·õWû¢’¿·ÜCc/–̶_š·¼z¦ù-Õ<ÔvÔó©¬pªònª²pÎ¥«T"ëÃÀ¹±©½_Ž0¥Á:í³>Šï‹Á$Š]Þ9)?gûúéÏCL.@XJðÏg{Ú–2;ÿØ¥¿rþ ò;Î_*„@yg*;)c;bq™'²þM˱×å xg;ÿsϤ¾÷ù”6 Nc©l-ˆ`P øÐ:˜yƒø™)ê.ëœ`Gꎧ‰KoíL3 ÓÂbÚR[§Ï仿m„ À*R¤oíuŽÂ`£R½ûi Ó¯ÆêÌ8–þ•qÏÀ:8¬m ñl§«ýd\ÿ®Ž»×ÕFÖ,æ(¼Ê¶Õt¾æúik,lgŒúœYÀ*‚E„-SKÛÏõ 99ݼ)âÊV'í $7€==øô«(¹ÚAiàAúÚ0Êšµí?Lþ¥:ý÷2àì-ê%Vʸòµ‡úÚšJôlçÚé¼@“zg£M4¨< >8"´>÷_TïIaƒf>… 5¨þ¤ßl×1æ.¿Ý1äDâù²|,— ¸ejP^‘ ¡´SJ-û¾ŠÜu™X¯AÀšoþ äÊÿâí\œw;«úž¦—)*Ñ1H°b'¶Œ-RµNikk­´h¥€éï$' „P.¡ D"†‹š¹H1ÑHÂ9É9''÷ûý~!„#qæí³öÎw>³ü¼OÞɘñY³oÏ~öåÝï~ŸïZßõ]xçæÒŸØ<3(ê/æçüË–ܘªDÚ$¯0û¡Ü[¿·s®KYC}žb_8ôØæ»I¢C¡M.Qš=ê’Eþ?rÃfßgoß|f8&nÀýù>—‡?zF«M ÈTÛ‘·Ú¡¾nAÿƒg`MÎ) <û+š>¶ Ð×?*뢯O”ªí‹V¢“µNu¸Y^îA¢šRæˆr~1ý§MÙŸ^³ ÿ·Oß&0X…ß6Tî²s@&ÛÕ¦=ËÍÚú0F¡ËÓý¬¸¾ŽÏþÀœ¯üê,'×=ó¢µsïëZ8.û‹ev€©þ¢üçœìœàÞ+ `Õ´ÃzÊ¥è0¢êð/gûÉD™ÇîaʈUÃïž÷@è%7€>‰¾·²k²¼¯Óùã:ý="tÑÛ膈&@h»*\T[ÞÏ‹µwöB‰ßÀ/º%i‡ª{‹ ‡må;¢£8­ò€Ÿå—üÆ7Û¶DÚ%œšJ'ªµ>K5ËT"s5¯œôX¥µe¾þËk{ô€ùÊœŒMȧ¦Ó63=—~v3nçcp§Æ[eÂ!Tr.>¦K6ëx;Ç}D¯í˜c‡ëqù4ŽiaeŽ©ïÐ*Ð `$M¸á¿ÿk—sm”Svz zd¯ÏÕáaøtdÚó¹—Ô.Q~³ˆàCsúnÛdô ¬ÓVQI3–1ß$ÔÍÎ<¥•@÷¦žzªŽŒ³ì|s©sÓ79ÇЄ~L„J{®©˜Ü‰g_»âþ…»ç •6‹‡Íi☩ßÓ*ƒ†-ó}Õ' ä¥îór½@ %$]tå€ó|p?Ñæ\q4518X rZఘܩžNÛ˜mbÏž^ëñkPŽ€LÖQGµ,НÉs‹·¾æ3XÿÄè{ÓïÞZùÕ•7þ¢çmó¶'7ÿåÜ[T& !K±D%(“³¬o¥Ï^ÿÁ6{;¥½”ØßðÁë«èÛ¨éèäCÉ<ñœk—ÛNèó_­ò^û©?^âLß-|èÕ.ƒß>ޱíSN‚µ´Ù•E%m)ÕDTSþ+jëKÀNd;Uu xµp» \b]£FôL‘½hBq/µ~€^åÉ_I™:n 7À”ý˜–‰º@Pª+?zÖ –J¶'=>W¯V}0¼Î)c۰ꫦ˜Y¿ö{ÜI×6§Ò_Y¯¦ôÏü˜r_8]cYÝßI4œe¬"éÙ?ì¢ðvv°Þby¹¿ÙžsÆwSSí7³°g›Ö“ŽÑö—³i±ì+Ž€skqtÅR!!û&­$FËâ¬SÙAåËB§>ï)ß9†vªJHÈRïY–›~G¢éýÝ›Èùߨ©¾¤:™úÞ—%6‡Ã׬¬¬‹C¸JwƉ<æ©>BiÏ0¾P„'O½Ê©X·™ò^õ”m£lé8]Ú0àÞK§Z£ c $çþºBŽÇJ™ïc'"ÏÕgÁìWÓZ†á6p0ÀÑ Ü 3dy°BõœZìí\Å4x92º[IÀp¢ïë:^†N”õ¯vUÝó3A%¥êîMÇæœ7ŒO¨êÆhÆì ÔãáÝÕÀk5çgÖ¯ú˜V¤¢ïˆ‡ië 6í;Sº³É?&^…|É·.ï›:«ÕM[Oå²@e‘èY­ŸxöðŠ0O(.džzº½/Ó¾¦ô…×¾ëèfÛç]èûxÓƒ ÚªŠ€°¶ÊÐgÿá5ïûñCÝ[×ç”ï†ïÌ%%¦ÓTG–Û6y6Ò9~Ÿ÷3 OèDÌÄÞ\ƒm9rýú¡ã$Èú6ïoõIŽyýÁŒC]c}7þ¼M™C½ýeTžý¥{6÷=ö—/*(¿gô÷¥‘;}úwm~òÝEi'¯EÁm[Oß?îS"©_þº9¯²]Û>Ew?~­{›2>1½éSè˜ËÀþC_»oˆàÙ‰qΗï…Ê~Jà&_³Õ'ÀN$ë§ß»=5æÓ—=Ôi¬DÁBi¨FYšœØé:ÖÔ©Op À¢¨7 g™$ŸØÑr¢ã1À Áñ Ÿ9˜JÉW”z¥æE§<í»À¼‰"žS_Ÿö2gƒó‘“~PÛÔǸ¶ô1·>O´y¶×tœ3Ç^¯?óYÿ#c]õÀŸcÕuóݤo~ú˽ æüø]‘t±bö´c¹ õ•Á¨@µžÜvæ§µÝàªÓä ê×È÷Uê8²p˜¼ÏDé^úÖ¨Æ;ßÁvY"ã”jÛªŸt“ö”v àN`®ö°…,l™wj ¼9DS¦­ç,@×Àw®e8mãÀ%—=Z)»/eBCOÞɪÂ^Öªˆ´åUWyPç°/@¼–-·ZÀ{¢ìV}OäÜsMÕ½ö=²nÀžmΩÝhsê¤ ý;˜ÔÆšÞߘAm%*LMp€O¢§ô¦Œ£“ú8ËwÃØÖ™½6]Ón1jßgkyõÜû^ÜÁWƒ{Öú¸ÖåÈôcJ°ÕçÏ”ï^í¢¸O{ÁÕ²ÉsÝ[Æïvt8íÀP ȹì³Kæ9e\¬U,0ë»"èJ·Íë@³,p©m}"ì8ó~~°É1¥Fô÷ ÕÄŠˆ»"ܨ‰§åUgnègùžm_²i2¥üV»’|Œ Mh‡@‚ Rt :Î À)*S{¡JTÇôýU—M£-ßu;†Å•Ï£{ƵÛK7$t½ö­ ÷ʹ—R¼©Kä‘„W^9qyΉ”ãaïTöeÛ:ÿðšß~úÙ¿UdüÞÇžÙ|ýæ'6¿÷õ‡6g^x׿ß}ôÆÍ+ϼzUb߇2û g±€÷: Ͱ ¨ú€ìUï<º¹ë‘íN… >2Ú4:;Æ`pnÔòͲēe>âgÇ æÁ(ÃÖ¦t‚^ŠÚzɱß»=‚þ©¯?¤¨×=ë9­DÞBKϺžëºôZ‡(Õ²Û‰ ” Ô%7G#Sz %í¦Š•8Tì²ðÅ|ÐßóÇwÏiÓ,“ßLßåâô,M,J÷u¬¨Æ'ú?ª'Jê±ä¬ó;Xû°LZ-ø€ó©(gì¥ÞÊø §Ÿñþ©wé)¤½ÈÙ÷ƒà¬gÛ°œ¬öµ>NEÑßE‰¯÷ Ûר;àÜ¥(ý~V õr’æÝN=õ¼¯Ðq¯õ¶Fo/#r†™UáÔ1R´BsÏÿ ½þ)? 8‡âîme=Ò^@=õÓA'-­vEË]/ƒY‡Í‚0 àMÒY% —êJ55SY*ÆGM€ÎxCAŽà„®Ñùdªê;âùupŒýµ-eÑ:­Þ÷p·[01,×ß6Uuc+¦N«t%+—¯cïà§Sb…;týt%ÀÎKèì =< ±mcG÷Ùq)Tuùîh7ù~&þ†Ê„§ÐNqeÖø2ˆMᢡ{Ð®ŠÆ§m.^yíª9nõ"9CÐ q´U”›´‡êmÐNBSËí °½üŒí*îïûʽºæDÀÄ¢¥p=SG=b» µM¹0º·RŠ—À òÈÿÞ›/÷qì<ØÇcA¹¦|©€SÚógªKÖ 8ï¢ãt»Î"±ókOç¡Ju\¢æ––æ)µoxÕ.ïŠìû\gu]>´h!<Ö"Ï»?<ùW›KozbóÉQJmïówl~þ#7ŒÁw J©g>Ù[^ÞKÆuC¡2€¯ûXq7TF"'‡7—¼ïmŸ·=Y´ñ´w„|­%žySÚi·Ò.Q[—âñ¿bdß{¶ Ê]tÍãµ-fuå%º¾Œ»ÀÓ—œDÐ?yÉcû2Hv}e¢m™Šš^ã”Sg¹ëP—˜Ô[®( k NôpAœHáTis]V^5¹Õ+ðië/¢zû¼ÿOîM}îj§h.ß#¸¬Ì´QÔºÊ{e_c@i]“ö7ðUT^@˜õËñê¸uÌô•ãq k$˜s M"ó9ÿDÒù_·÷}³M XLk[õÑï™®ßô|@=Æw³æ´Â-÷²é¬B¯õr(¢¥`´H¸à©<Ð °á:hóRˆ_ï•íw»¼ ÄËÑ6–%R§;,å­×︎Z±°…ÊB{oÑöÑ^Tx*\$*î÷ðh×hï¶bFÕ´ÓÚ±ìbO2œD×ëú »·”«—²^‚r{Y/Z4÷b~¡µÒ©î‰¬g™mõ]ÛRo½º¢ê/,ŠدÊöuŒe÷¤ÃÕ:"èR}oùÊhúÌ¢áŽ~: 1ˆô‰¹ì˜¨À 8 ÕàÓúEžZ\ @ˆ9:K߸S<‚“œ™7àÓ¹K¯J)¢Ü'9r}ÐÞw–ž3Xž÷NÐíûÝwe-0é‹èù›šËƒï¤¬Ó·¸˜j²ÝªíÆ=ª£~LD.B€Çb?LþqŠ®0•½çØñ^\|QŽVº¬BÛ.PÈquü´•z:û ¼¡dÉË£^Þ[>•Ã*Ð'ÏŽjâ0¸ÅSÕ…í8ÛyÔ“Ümy놹‡Ô9ßÍʰ…N^ºN£  4ú½7 %žJÖ¡þ®}Á÷ Z÷ÇÆþPÙ窩¬ µZšþ\ùc•}ˆÃ䛼󓫺ÀÑ¥4Ú®OÕ0/UóOüÙ›_ÿ½[7?ñ®£5PXtÙɨÛÆk¹NP·]ìùDàIÏ © ²’ƒ˜å³¿x÷¶Ó®òj£ Ü5­”O9#ZŒì¡Wc øÃµÏÛým ¨«,Q9,toxÿu-ŠtÜJ­l¯O¼¯+«ÿÔ»·3o>ñçÖ@;ìÊYÍ@|;ÍõT"kÙFDm˜òÅ[mð©G-iÀǬ~5 ff-¿@ À¢DTgÚÌsÐ?4Þ³ Ðì”PÔe‰L—e¾ö'Rܪ¹yÖà 5ÝøNu_Ï6µ/××€}ÖÈ3ïëÜm¦ó'òOÿePÜå°È9õÛVÐs‚ï$m|ÿ¸îeM»ÈŸÀ| Äf>`|‡ñ¼–…‘A*„rÙ1SäàK4/ëÊz».Ôˆ)žvÙð>Ñ™ "OˆÀq"êW¿jmPºñð´l[µC{ƒv~§FLî°¨yg3ýæ‘u×RïÊ憎״À<š'oc¾EÓ†•=ÿa°ÅÂK›´ëbq{cÛ¡²Ðà›p/G<øÇ2ÅH‹Sþz‚ +XP0N){V>¹Ò å5ÝQýGTöœ‹¢œq0õ¿hOJʹÎ]8hìW8§)] Ýý™'H—u‚:A%†½«„°Aå Ïs¹•ó½ (Û\ov>»A¯±šËÛ P6ÃWUœjcTÞš0˜M‹—(]R Ë𬀎‘""`1œ}ò98°é |¡D;L[s.–Ï1<õ…È7ýX5¾© ëúò²¨û°þ%æ<üàoÚúøÅtá { ùÁ¢’˜shù'BÓwàüh/öÚpOÖkðò£òy„®È}ê¢R(gI­P7«aûÂÈg>pë·7\ùèˆ4^:Jžúd~JAÁ  hIü0å(ÒræmœÛ\ où£$ržçšòhµ­TZÇú´ }=¹lxسœ?ëÿ:J¥=¹ƒÎ~Ù ªWóN;ÐÌ@ƒœº˜sNf;4ÁeSƒ¦Uèmb¬í Ö<5lWµÞA¼Bb?¥t>«½þ–ß¿­å6&R^ÓV­`o=ÐÚ–­‚n(¯ÇÈ#?¤HЫßqXQô?<øÈözå”5jTõÌÿä{¶GÐ?vñXw {À÷¤g€/€¸v¹yº}G-«¶÷ j”Ûõ¨§ÀØÌC Ÿôÿé} ì@|zv1"ÂŽÞÎ~ÄéÇ& Ï¾Ø §KTº¦+P]@[€î c[Ù²ÚäVkýÖ<À¼æ{Û’cuÜÌw¶}×>\Ë+Xæ8µœ6L-T'ðŽ3GFsš° ¨'ï¶À)ìË3¦ºîÌwÃA„(^KÅPMü8œX‡æ‚”ã±|ûW.5Ýû®¢q8à\² °Þ¨ðbÏЮœ†)»¶]%~}† Ï%ùrHóˆ ûa"avY×°—u!¹€xÚ:š^à½þK¢š|­ïsÐÝ¡¯óû«úDDnW½ôšVD|ö²qÎÔIOä\ ðQ—ŸÕP¯hz[ÿ’q¦Õï’c=Æ2W˜æÎ£Úd½ÒøZÅšf3îË8Ë£¨¾›a;À>¥À5E+˪ëŽ([”Yóv땉®å¦?äÀ£®_癯ÌK=³@>Mõ´Ú~Ws·ÆØ< g ë¶s*ìZž!T죦 \Fµ-Ý›ŒóCƒç{éuÍÁx”ã9Kxæ\°¾AßΡyü1³V´×¨ƒiÔŽåõÙ¶ E×:jØ™ö@AþxþLIiÔ©ØÚÜöä‰É¾Û(Ä#O÷Áfå@ö{Íõó0è›ÎѼŸ¢‹ˆrƒº”'­¢É}Ÿõ'Þô%¥ÎS©÷=þL»¥ÚýÏ<ªcè¸=2/ÊM–kÐñ/‡Ú÷›>yË"0õ :oäý~þ›lþøðceåå®YìüËQåkä t­N©Ó+‡+‘ò1ÅÛ½H_hìˆÀ4±ÀxÍ/žöFwËò¾Ïݱ”›}.åÔ~ö×…^—ƒkÀ&‚þÜ`Ç¥húúDÅ-—|»Ã+hïb>XÕ1³þ¢Iíë¢ß/‘qlP'§TIŠÙA©8ôv©—iÇ»¬Óí+7½j£'@îÒF§®ÛBgý'—à¼?»¢Ø¡ºœÍ}€8ú)‹b{¸rij”£–^ÛVá«Óˆ–/ײW`ü^Žër€×ï·Ôïc_>òXWó> 6[§l¦çÏÂo]t@\[}t³ydpÝ#æäª÷ãÔ}öʳ®ÞüòÇoÚ¼{äŸwéƒõîX®ù3—?TÑýñž¹y󪳎Xè.p^ËÔ³\Æú—§f]kÃ>µÿ:]– |³_€—ö>V¶Õþ«ƒ ž‘õøëröU4^9øe0¸§¢ÝïÌí8´‚v9W޳@ÏÙ,ç½Í”»ÝT/u8™RY EÑÅ–¶CØ*])¾±aHaéi.½Lb{?¬é1é´}A}'j¾æ¢«´[½Ë\¶ ê{¦Õv¹é“šëôÝ¡¼'j^û´ŸÈ:wôLÄ‹ÆzÚÀøB¬TŒ¯Cÿeù Pã,"©5…}6Æ7uòÐì5]TÞÉMO:Û¾VC}Ø¡uýž©ðß?Ž»®ƒæŽµ{•iµj:àÏÁ¹ÝéÚW´nõW,Qã´h Apwð'Àš JÍσ6Ú8 ãñž…êfQ~­ë€˜c-©¡Ü#±h£>ïªM¤C¹÷ùdç+ýwIç¸mŒdlEþ9 ͳˆ‘ ¯Š^VN·Ó‡TçZfmÎQx·æ¥—µ[l±¥°Ê1ÄTÌäcr"x„DOï¹²ö\Ùü@Zà‹úÏR´‹·&ÛTÆÍbtгÜjïq.Îç¶RýžËÁ™®ÜÛÜñ°¬þèÊGEÏwÊ÷8çÉÃ¥IÚpßÚºÖ·î+}û¥Ë´õíèv¿†WýÏ£›_úÄÍ›_;·ì–Í`÷§Ï¹nl;¤óLß=ÏF–í[…Ì>7À3”qcßÔKìù2ÕöLJÀXÕù®HçM÷×àu÷§ö«?¶zÁt†‚ËrŸ,¢ÇŸ¤ÍÀ<@Ï9¹çü)·åŠœÏ®ï;ùìæ­çßÞÄi°Ê3¯Ü»aï5eç¬O%Óöi9ƒàý—>~óÖëøë!VW–çÐ"]é¹èsŠ%ƒIo#§rØ5جò‰:§ÿ0~ RR 4yŸ5¥6ùè×LSc\YåÔ]S½ñÐUúLí.Pá¦VxÏïM9Û$zþŽÞýÔˆÐPT=û·¬Èuò®Ë¦9èç^ú`£‚G=eÊjßôÇü)¡—9»À+4÷Ãöòn_Ž¢§ÅðЧXƒ±òí;Ïß¹9ᔫ(fàžéq¿y€~ú².À9¦}ʼýëi_N†{mÕ×é«ÐïŸ?ý¬‹6_ýˆÝ°lƒþÞÀ}õá=ºRÚ÷ÖX´íÛù¾c½ö:¥âÎIç ?ðî<ø¶½ÿN” «E–ˆ¸t#Úo· D"¦Mâ-O½[œb¬#*G4½XA¡½'½'ïÊäŸð®mQ…¯)¶\9ìµL´}›^HÞõ¡ÆgÁO—j3>ó´)#2¾oZ}¤ÓÝÙrÔÛ4ÖrÏQxPXOÔ½þߣ _ûXkÁX±êéèÙˆâ»TªUÿÛA¸Rþ8¦h6€£Ÿåˆc:NkSN¹”1ʵMõŽ:84½Ÿc)b[m zs¿¸ÞÝ”o‘lî=)´S¿óïØB¾£ô¯R|¤²én‰5kÞéÔvFL„ós§uµæå¾çýûùŇû&‚°H›¨é0ë' ×ê‡/*yÏI!Þž›Ë‚ItÍB sÖÓ¹÷f}Ø8¦â#w9×÷OŽ>®~|Ïwä¸ý.ÊŽÎóÖQëx)¡ÈùÃãÏöWç–ͧ¿ñP]'ÚŸ…IpáU`X×96vƒúªg½-Oº¢è<ôMÌÐÇWŽˆÕ{G¬##»ÔÇ_ŒÏ›Ï»Mç,a§2”SªÎ­ µ¤t¹åy©G]õË3mõPÇö¢µÕ´œ&31¸¢‰ÿ¯Ã[2 k¹åe.'ãò5­^ù±(´Ë¶ †j¹TMô'ó߀fÛçÿ]ó8jÀû38#r~ì ¶;ý½Àz þ,²…òIé´Z.k”ÏŸûð *ûê½^J-sh¦ë¶ä•¿ú¬£3ѳ ¨k*@~ì[¿©Aüq”‡ªóVÝæ´#R^ó“ÜÝu¿ç€øU.‡å}hc€^ÎK¢¢˜ò°#¾–Èk€Xò¼Cq·óîaÜm',`w‰ŒŽé$2½ß`ôÇSâ}åÕâßñÑ;rDÖ«2ö:VŽià[¦õDÙ« bol_×ðAï =Jîô™óªsì÷ˆ©LQúaq4`f¼m€lÀ5Qurâåt©v)/G_i· îŶ÷‚ cŽ)ý Ò©™ïß %ÝfåÜäD“ú{RP¨–ÐÁ7%Û;( ŸRn-=&윈R/ñ¸Çu¡¹UPÓï>Ôà—ö¤ e§h–‡%=Šð¼çk¦”Ò•j¾M÷'Ò¾üïŒèõöŸcÖV•@RêÓl0Xa>mëÆ5Iá½/W$ÝŠî=šà€Î2tx Æá¼G<6Ö9UaÈ[_ÆeôIljÚŽjo þX´ÌLÊ9ÓÒtzEy³+bÚÆ±VWÊ') æ<¸–Œ‹ rŠý:ÏŽ¢¿pCïIÚKx®YÆüTFXÂÅ¡ WßÜ à6 ºµsQª´Óp™Î鏯™x[?¾0B7ÎŒÍ(Õf¡ç¦1•ôäºg;t¾¼Î÷y¾¬”7­yª:[}øÆX¤Ì‚dÐÓ†î단c¶þ­Š^íõ…JÍÞæµ=%bqã¦áÞø„ÄÚýòwPý¦fyYjŽ7úºóº¥”8{¨]ïê–ÏQ³Núì›KoøÖæòë_Ðçö‡Ÿ.ñúÃäzùNä5Ë9\|ýöø»¾x¾“ìû…ܸù•  ðb|ˆlêÅžï ÑfìÁ‹ÍŸ!õIë¥Éö2‰ÀµºæûBo/:ÛÁÊG[þÄ?5"‰³ÏoÿùÕ¶ÓèRâlš¯5xX–ñø×rÑúÞ”ˆ™€õVª†å¨³ŸB”ö=ÊcõUQóˆy©u=DZa€ðuڗˤÄųà‡•ÿÕá4è*É(Ç2`~Í;·ôs¾tò˷䆷iáÞÆüºý‡Æ@’òRDʉ*.ëÚZÚC|„>n€þè“•ÜâµJ—)·[ÔgJ–M#è¥WàÅþ°!À¸ üb¬ÀUýîGaJým??õ½ÍÙ_ºg€àê‘PÑmD¯9?€m‹Ž« ÆúêË‘{–‰˜û<ܶú¢OMG{Àx=k{WéÜBÅûÀt5~è8sÐØeÇÆ™Óíz4>åݺÔC{?.%ûúv™èñ¨Çg»õF›Fg§B%ÝN´u>N¹çÞ[µÜÁy¤#:—y;8$³\à;¥Ú2U9Ȉ`Ø31˜J¤Þ½¡À7ÖR½ãÃZØVkåj§+ž*ùc÷’2…“¸¶å¿§æ“V•ÿŸÅ:0Î 6ÚC…W%’ö?:¨õÕ>Ë5–KêãDÓêõŽÒûɘXu^®q$XzL¡ÀÏÆ1±.¼ëu€~W#gÙ1r–¡›sJ÷,{>ñ¯°P l›5V·j@ÔÇÎñ„3ÀEn» ‰¡Ufp:çP̽ðÝÅUŠ-©ÇÚ'F[ßëÐß´ZQ¹f°Œ¿g?§v Xë>;EWúmº^çæÓ¹$eּʗŸBõY¦õÓ ÕO‹ñw/ùáú‚ó0»õzŽúñåÁ³ˆ—Kl1¿Û£¥¾\j »ðУ€]wÏSº7Qøž«7ÀtŒyäœrYv»¦b¯‡ùÇÏ::êeß¿”Ùz±>·=ôôæ p%¥¢çvØ›W5¶·}þb÷N×Gàuç\»¹X¶÷ó¾ÙÌKYy[NP)7hfåm£dZ3<ß©…Šjû¾2â†íÚå5_ÿøŸHn*ç¼@9e^ö4PH´\ùå¥R°­sÖ©žì±Ë §ƒp(íô©ã¼öЇ·^ÇÕw'Q’ð²P[ô;É—Žc²ŒËë>Ñ)õödö’h|ÞùHj׌ß:Så€V¤ªè£zúš¡@¿µ®÷pDUÑYŽò6"q¾3¸/#7©.Uê¶^Ö©ÀXr~Їƒ/Tõ€.ò½UjÌ´ó¹HÜ׎>–¶”5 }Í`˜ü³s®í`”¨u¢Ï?öŽ#›ó{hÎÄq Æ-~·ræÇí­=ÝöÕ3=XI?ó¾k9gÌ Û€»ò¯[ÞzÀ²£ñóÌ'Ç\ óyùœ|ï9·ý¢ç‹5PÛÉϧoEüUNîHæm鉭‘yÀ¹ËïE0ë²Þ |9SÜ’CË݆œ{ÚóÛ6]¢ŽçzÚª<â©ä«WºK(í€x¬Þ!ÙÆÆÃßË»‘4”Þ#$×k¬·\uïðî@%r¾€óžÒÄ<ëUÒmà§,S‰Ä)wRlRpÏÿaÒ¼ÔfÂL‹Ê»Ö§†:QòÔEOd]Öœö«µÚéÿhŒ1"'¥w•\£Ìk­«ñU–“7¼€!w ¾(klf®ƒE5¥D/}öØs¤Üâh —¨Ì3e}Wt:Ç®c€sfëœiÄòÆõw!n]¿ún€™sp0Ìû cMJœ©òˉ=:0ÁÚš•e?_âÙàÓ´}¾ IyÆ]•ö­|Ïu#ZhvDŸW:2AbÖI?MŽ&;©Žitr~XØb*ñtL°”¯ÓŸ‹ÉË&ŠåêíŽÊúα¨|¹òòLÎeG=¼s/qô²@nÚ¹`>ý4!;l¿HLËßM­ðýhºU/û=#šóÔÈS~!ŸÊ¿¼v€“›øî BQ?kDÓí°X¿Ëühkzö—ïÙÖEÛØ¯—ª¨ÜÀÊOÿë˜W^âUEׯúÚ6€ÿÁÛŸÔú§6ß}fyÛù·ÏÒ dñJ«´É¾ü)¢¨Ú¶CQKä\Ä ýõºþy¯÷¤ÏÝ1øãÙß:xÀH4JŸ%'£ß"ék ºüh[SÇñãªþÜUm40‹%Ÿ‘2iä<ªüƒ¿„“;>Ú%ײE‰Ò€ÎóÔ"ÞEÑ,€>SZ.{õ™Wo½Æ3ÿèÜPÓïåÏfwÄÙ  3-h¾£_ÀJÔ¤ø ó)!µmÀ)Ñû•n|P èµ-óŽ ¡?4ÊÞ5¾“o=õ½ñ~vó½qu±äû¿õL›Îán”ïW–Ã7FžùŽÏx÷=»ùâ—üe0#Ò/ óµï¾fóÎ ïÚ\wïSÓkxãoÝØÁ2çæ¨4*íEïßæXP”ª;ýý.ˆÏv€7}â¨eög_ŒõSBx¶ÀöuÎÛ_C'«Œž•âIˆ^ää°Ïsç;KƒÒ~üV–èzýVz‰·ôÄfðnÇXs¶ “˜Qu˜3~Wd]–£Ê{õQæmÔqŸU¥ œ$¢˜è-â^‘ñ·ì¢r䫇å¤÷tQéãLMä’™G°5—½úªm= ªæ÷S’³ÑÞG*‰¨Þz£" sDã²:êß÷–ìðï,·ä×´)½×v+½/ûR7eÆ ò€pÄã$°nÊòd¼Ü#¤Mp0E°Í¬]ã‘ MYZNä`–êÇ`¹'"³ô¯}¦ôvlY…r®spN¾™ ¾ÏR¢W /ë}ÏdÊ—;6/)§¾‡MUš*ûþ§‘_îÉGÎÿ=(êo×Z„­yQ‹(Û?g8 n}ði®} ú_þŽ«õüÇ+ẊÔ8 ]=^è2ÊCäO?ÇjŸ?ÓðæËˆ˜÷hzÖ•J«êª–`ß®O—Êß>s…×½ïºçË=§dÚÀ»á1JÑ$Á ëjZù€5_à:ƒ¤6ÀzÓïÞºÝ4œ'¯ ö é ýÀ›Ç6ÀË6„áLe³nU0¦Q¶ßÕ©ÎUÒ®åt6ËúPEG_‘ú‰@¿ðnQÓ3ˆNT¨xÎåè ÜÊÓY×JH¥}Àw¦ÚZ?æwEô9—çJÈI„nb씸c›¬¶ÃÉïGÎ0~l×ï”Ò…làÁUoŒšrd~¸7GË0f ?à9@'m¯¾*º¾¨¼HÞ·Nïë˜O´=ŠðµïJu?\ ¿@»Ë_²¬ê§7 Ÿ¬K 6¨ï±#ë”ê0mÿ{ìG´:,²¬/pžë°ÒT-%ËþN4}bqÊYgû”öþýòŒÊÂÌ«qÈ0Æ+™vfŸ¢ãÎ÷íµž§ÑuÒ*§Qܪ¯ÎzÔË ÔöÜ; ge9ûøÜœëliÎKÕtmsÝ-¸ŽUT\SrV® kÂÛP«þ•2l6BtÁ”³ýØÊÜW„ßf¥Ÿë•ú\mÃÊÖ÷,kÀzæH1sz^ ®Ì‚åDû…×¶•<&Þ ÕÂãÍÁ0²±ó—…› ±ÄnA5IØï4T m¼‰dO®Ññ¬Û>ÿêƒ7T?8¸¿Èù–}L(#¢¸gûä¡SDÓ…®,Ú6ßId¨è¿øÑ›êžUÔ‡ õÃzöµΓšñ¿ÿØþÞéo3›} ˆVýãß?m¨^νji÷{ͦœ#òJ"8rUåá/×ñ«çÞbVˆ_TãÛ½ÑkT¼j›×2|¯)µ«¬ y覹°¯iÑpk€ÿB>åÜø¿CÐï7Ï¿m¡ÿvµYQØU:MQó(åŽöò!G]—u@}¦ÑÛ%7¢WÔ`­@¹xæ9O4}U8'¯²–Ô3¿ m‹É1Tšǧ>y"Q§ÌKUß?5~#Û>§]p§"`®•¼Ìת,ù­ë³Zã1ˆ!žhàCÄÊ{EgôÖ#rI„’wÄßÑçúÁv6âÐÉ_1tÞöäÖ>*:_¥ÔþÅ®¯}rmggþÄñÝßüÀÓêûðßy>0^çVS€9›c²Ü·×±C—?­“Î3N…û5]Žu†œ9§¤è«ýrÞ‡”Ÿ¨y¨óÙžH~Œ ÖUþz¨ð*÷ÄëTîmꀚ;§(瀯ßR=çùÂÑõ2ßÖó[–CMج3E@.óÕžeÕiGbÞg0ƒ² §#å Ü­OõzC}´'ßXM?DÊ’ë©ï_ÚñÀ»Š;yëf[%=ê±¹ €£—"£}+µVÛŒyÑß Ì+…¬ÒÕ`µõ\u(ï58@Þ„äF^zÄ_¡¹ïc~ž¯^c“›€þN*^Àºl"p¬œqå CLD¡Ýž-ïÆ¦&7¡5Ïi¡fæúÚ]Ʊùüéˑ콖«¶{ã$€šž6¤ËÑÁØüUm$5a7Ë)S!X 0*¬Æý“` eöŒßjôtd?KœŸ€ösƒñ1lj°ضÛÓ•ôù¾6ÇÔ¶7t™òKöÔ‰l¡F”€œ)˜¡_ˉÏÅÚI@¸r ø±¦[<Îgr=öˆ©¶`òÞ³ºŒ´_ÑÜmŸSþàŽ\cå˜XH`î:y¾gìCD]?°šº!÷/êUïûùÀíû¿roýÙë%òÁÖš¯»m[tø:þ”VC}hJ™ý’žØ Ì?úµûjpè+êŽÊ©ÒK’\r¶[Ôèû ¤ ˜›B¶PÃêxˆ³œ/ôõ,-×rý ã9†g}±ÿøÛ7CÑŸ¢Åÿ“ƒñ+C¿¾»Û .”¬5^f!e\êÎ"À“ˆÄªª (Ún­ X¯(çփ߿­‰½%R>¦€ðÚÞ8*Äû[tœ²AòV:ˆf凖!¼D”gnDÅ£†Ü"R©AªiЯ=ëȶˬk£µn­_N¾8Æ@ßÖ€üßÌ‹¥TT‹&R kVºÏÏz9嬦>Œ÷ÃßÍçª;ž W´6ÑêxU‰bÛ§(êÿzPÑ ¼89é ËÆÙgçç?°ÝY0V@œc´þˆŸQÖÎ!ÀÛû mÛlÇŸt%ËXö[Á÷š§.'ó9'EÿÕñ¸Ò-V×@uö OûìSb{é‹}Vñ·]i ó¶›Q#ª÷…s˜;¸'|â#w,‰JÀ͆ý·ÿtñ”·A%ÙçéïÄä¾?¡uT~4È'Þñù;ê?×!Oð,§|¥PÓeëGUnl”[¼x'FÊþLÇ>¡ÅšóÌí•Ö<êáäŒÕš¦„38'/ •×bÏj¹èr€<ÔA@_ôÝ·}åN½ÛÎ¥s”\ÓЇuÌc¾RÙ)‹V"O}ûµÓ:ÒglÝg.íNVæ$Ò¸á·Bo''SÓÔ.W'Tà›Ú×èMµäˆHY‘™ˆÕâìw]?KIÕv@vÔVFÜ-:ðÐk°RŽ,yã2|Ð’`$Àû ¿¢Õç`2EÙàKuÄâ ã5¦¹çÇT‹\\_MøÝùE×¹²™*õØ·é@*›ƒV+ ·±^Öõ^Çq>ôÏw/¼í)íYy_øè¶Çv`-Pïè8ÇPÏhï§eÝ©ÌÌwÇÆì€Ó¸§ád°DVÖi /Qø‰ ]Šú±}Úvù ìY¿Ú²Ä›…éÊ»¯å9Í|wzÞm»ÎºÍ8Ù Ìó¿Tø—³–…¢è5O½²sË7+"è_öméÉ"gýÏjÕiŠö‡ÓxœsN e3;XW¶š§¦´(÷7ÛËÓñ»F;ý>MÇŠÈÜ -ÂY"ë[mOs‰Ó[¿¥._‚qWd!ºÞøÕ¸§¤©úŠÚ#6 +Oí©tôa†‘s¢ík¥¢SŠ…¥×<7Vo²viP­ýga" }"à,©á3ê7mCl.TëÁ8Qn-r¼™vžýœ^ˆ–•¡r¾¿2v”²í±qC¦@s?K›u|‡Q©Ëé­~FhÔà¨Ú+CÛx9í€Ó9Ssöe‘2<M÷~‡l›ßÙ r}·Aq°·Â ¥pÒ`ký¦À§–,€$ãh’xUœ¢Q_ …½úÀâ\¦…ô=>µ• ÊcöC£½Î¥‚h–ól¬rhð|NSCígn[¼­)=«tÖÕÒ"g—<Šó#JÑGÛv²dÑQ Æ ¢æÐa\"@¨Ô@IÞ×±¹ŽQ 6rƒ*H×X¢[Ç3¨ƒþª‹o…S¯9Þ•i~JÒ¯p&¥‡s.²²ÝÝÓ"䨴GýÒâ-—yžh:t7×5WÔbG‹Âê8þys:¼œM¯múÊ/vƒuhìi€slk¯Ynp®ùW~êðTC ë•WpN'ŽˆÕ€ ¾ÿÀå2:˜2MÛ¿##ß7ùyÛŽN±xßv\îì÷'ý —Ü^Ô™³ó¥š&Qs@¹Û @vXQUŸS}û<ËŽAÓ%·¹LXÉ]Ö·ë¡wý%ÑdǶý‹'¶üñ§¼õÚ–û~ýRSâÙZüi‹|?³©¥;¢ `>½µozq a>nÇ8åÚû«¶3iê÷À´,â'¿s¯Ú ˆÇ~¥_®ã:L'7HøBC¬ãŒ`Úvœ2;Ûu¶H®Úh}Péë¹xÚ`Ÿcïäž—=÷¨®ƒqà±Û  KûÀQp òÕyÄôô>[TîØyîUO @ºÛú`Ʊ•«Ì]O£}VL3Í@zë²â´C˜Žtm`çÛ“'À¼"û=s)¶J{×þû1p`Zõ=¨ñúþ ¤“:8gìHz”k{T}Ö‰o¿YS²ÞÃa›àËc«}²Úÿ³š&É»Úÿ""ƒ9¼§ Tj[ÞWn•{ë@[ûÔôÚgß_מßã´®q-óõ©L÷DcG´½mkcmïl}ì{ÀõÖHºÖ È÷íßç<ާeô¬Ã´ÌûÀ¹À3ö»’ÌCŸò,÷˜M»iû š_„âj-æGFÙ¶ZÊ--)îíÛ‹®„|7¾€tÌåI¹N:‚qÐÝõ;D 7Ö•¨úFJ†Þm2-,ô\mÐÖ¼y7‹±ÌÕú;ÔwÒÛd°êd¬{¾í7tm4íHºÁºRñÔ®äŸo&È i‚³Üô9À¥ß‘ë›fËíë¹°U÷iϹáM³:7>"Ú`›šÏ}(@Ümƒ ‘㵉 ŲçtýÕBq´Ëàb²NîˆÞEÅ,ðJ¤M#ðy®™»9p ˜_…eaGTÎ: !q0í&x"¯eƒþØRüèg½y6.j ž8/ €§o mí!›ˆŸÅòIÃ<~ôá5{Í ÍT0ÏöÞgœŸ¢Â£á}—ßÕD’n\<¿ ­Iy\QÈí-©z㟻ú>ÕÊUÞ­¢•êYž ×Þï…<ì÷LTÏoj´hy¶Wˆç•¸Hˆœ¦?»û‡qÌ]æ>´¯;ÊÃHüYç_ÿhÕë*”3Ïž,èU| æòr³<‘ïUÍˉ Wúº£åôZµçv#&“¦õ©Ûö÷Ô·¬/ÞÐÄï.þö\–À;ž!KDý×âËy¡RngíZ^ÇTg¦Ô¢ÚVòÕÙº|’z±³•èsŽ¡ÌevÆJì2¢æ‡Zt›Q·O÷ÞÅéÛz§õõ¢f, àþ’¤“ë£í^FÝb,:ÁÊ+UTw0È™Tõ0:âaª²ºzä‰gÔ»,wé¨ù3POjpÉ–ú»¿và‡íb{ Ð=pýãB”ó/AÝε û5@”æ4…æÈý¿”SJ¥Þ–qŸøÖ=‹÷_y÷âíÿðýÅÎ&ê·íóÿ¶Xkb‹ú®Ÿ×œ«*Y©ï»D*Ål’øÛàÜg e±²:0ßñ °^F±÷vÝÌË ¬ûrÀ¼ÆÞN¦ë×¼ý.ÇýÞÖÇà~y]5özGÐÙŠ{FùóÞ}GòeóKL•ÁNÎ7XXâƒ*r7Œ>{\lÑ/§í¬”4íצÏ/Þ‹FÉÁ¸E· ,Éâƒèy1äS°lnI¡Q…Á–Aû‹!°?<^™_uçf,=j5g8vx8ÖHô"”USûaÚy<§ç½—n£|ïg½ûº|y‰¢s¯ªAãHJP‰\¿1UîEÑßÇÍ3†,KÔr–¯‹gE'>ÎQ2£Š|ćQc„CðÕvç˜{¹#䎒—ÜrÙQl‡’VÌydwÓÛð¬¼ë¨B…s.[(ÍbêÐ\üùE7/ÞÓÞ¯7Ɔ÷ñ¼Kë­4Õ…WÞÝ(Ň'+BÒ£îä´é>–©ƒãN“¢×|ÿgcõþÆ0•EßÈiŒÌÕùXÃí÷=°xÞûo,´MM»£)ÊfHR½á®€ü7WI»KnÓ5iÊhUt€ŸÛ¢Â£áœßlðõ’ìŠrí‰H›"_AGOa·±ˆ“÷5±+°ô5fÂllÿè×î6ˆ…º(•;WÜó²õdÖè}­ÑëžG-€–ÑÖê^‡SðahŽ£§½ý:^ƒbGÈ °¶È×=ïíhüèõþ3ÐnÆÝ)°s9¯±#ð¬äǾ|nSµyžm¡ê÷õpƒú¾|Ö¨ÓËx¾5'+ þ¦¾@ë½+ÊóŽXW‡’)õ°³ÞG\Ž1±º÷¥š<ÓÞOî%ºýÝì³aÑwèò秆`ëjÉÇX—¬#Oc]Xî\ÖWÕ÷¾Œ(z8^#WT%*v»ªs¢îY‚(:½Î×r¡A?)£ë¦Â—ºéf¹yÞ¿ÉjCe(ñÇï»#é¨ÂÓ‡ G]}Œ•3¯2÷´¼÷5¬ün÷“ª®N˜Ûɤ ï4eÞª }ÈZêlžþȘå`˜Q]n{"=]³+>H  ¥ï6 ú1 mKѶ°ÌY']7(×ã4ÜÀ5qŸDËé7‡£ ¯`=qLÄõĶÖ×xœjMJžÁT(AcÒqÇ8Ñ¥¾5îûáX”òŽÜv¦+~ˆ:ô\{¼Ãt”Ò#J8÷| $P<Aý¨ÿ|)|Å¥¿GZÙ/(.DöYô#J‘ïÍu& „6#Á¨ÚxZ‘ÿkû¤º+Et´¦AÑunNàÔ$d5þ~ïõ<¹glçœò wÀ„ˆò|Øò?GQGmÃ~QÏ_Š“­Îùä­£ZœˆŽÀ'úQß><€‘ƒ…A_߬õrFˆÞ^ʘ4Ûï踗{ZÀ]?Šx¶Ãˆžp^£æ€p–e4òÞlt¼ÜmÛüïµ”-—Þ±øìÕ÷)ý¿­A-@ýoÈA# …ª®›tõ)ÿܬ! pesÙ¥`Ù‡¿æÂ`PúˆÊéA¿ÜFT ƒÞùíC?ŽzØO:ï #J-QæˆÎ2eÐ/úð˜²ýWí{¢Ntä›×œòN¡­€;ò_k¦ä–Sæ J®§ƒæKѹ½€ìfQÞ Š{¤(x_à õ¹,ûn:A™&Ò øsδç *K^¶—=ùüõ%8~˜套ȶ@qàºÿiÍú<€C=¾o¢×Zæc¼kkßç´a;MãབྷéyØ!Çt÷sKåø`8Cbem÷^ ½ø|— ð—h0<Ès?ˆÐ\Míðÿ‡£ê­§¾<ÿ§Uˆ1g¬“Xçÿ½Í#§s@—y™ròÒûr„ç,$gàMκîæý­ó:1¢æÚ·KKz» Ã‡Ý–Ne—¸§Æ3Q¹tÆÖ¼tÊ´¡ubêûI¯ßƒ³·-¤k]˜£‹¢hxgmiÞ4yÙ¯oÚS{šÀxT6)ÕQ¶DT=,×aÏÕ¼u@}èÕ gS¦Õ‘QêÕ÷aO`Åê;}¢-¾f´éœŸ‹õånJäH,’ ÒúXÔ7¼Æ9E.˜%˜ÇÓ\ó*r>Vâœyä?At¥É s&þ–í¸Ïcüvó4QþésN«÷:°F‰B“2༫ÔWÌ2¥¢OÏ'„Æ'µõËõºLÚ@,qòi©ëŒÄoˆrAÛ#CÀw^ÿÚ‹—l•šülމy=’ÕåßX`ã|9ŽÎ1$öyAeŠ~©Ó èýˆNÞÓŒJýc=[.9Ühó7/žþ®ëÛÇß×”¡—µNÿ„ßj–_Nø˜fÎM8Z´Øë{lÇG_ŠšÏÊ ž~Ô^Óh¾Ç¾yèßg^ÆôR®…'±”……6ûƒÊ…uPH÷¸tòË]”ܯGµûBpiüÐV@>§´3¶g¾ŸCû‘FÐîVfï5`·"ü&;c׺Ò3”w®” èºÇ™‚qÉU÷©scñ¶P^G «¿óÎë7íŽˆŠ¦©]žæÈÌ[¾|§€ô1[ïRYÁªJ‘"u²¹vÄt…*º¼M]ç ¦ñ´4ãK[¹¼^'9òÌKÇ\ëY-gYˆVÍXˆÀÂë ÆµÚÒ¦ØÉoØ;èŸoN@ tXÉ›¦äËeW^—¢r?ùů"RJ~5 rh;º¨Üy(·?\ƒèóM%¾ÓÊjeåbáq66à`®eÐ⛾ûŠÈ=9ëq|Ÿ›A8ëØ÷àœ[Ïòê0èÆ6Lãˆ!ºž‚x^o±½H•à]¬Û¦S¨RÚ+€?ì’ø?°ÛÄ`ßmC1ú¨k®´íj;?œ~Ѱns7}·.Uൟ"dé´w™ÚÙá)€^„åäšN3­ž Kª»°, ÝPÙ—´ø}ÔV'Ð^ °NjwÑwhíߨ¿]osrÔ¡·Ë ·“¯®åü.ã”ç÷Kì´Qž¼"á{ ÕÝ5Òg``ü•Ⱥ§éÃÖ)›à\¦~´ÆÃ>w‚ å‘·Ëèß8 vm–¶JVlÒêpr޳èñ˜Î…‹“–ŸmgÛÆñÐQJÆAâ Áõƒ×’á\.ÐȹodM1©ÉS¯Ï[F»|_8p–@;ž×¬ž:‘ï(Ó:v¦i€ƒ“†tß<[^ìj î‹"b àVÐ[¢Ú쟊m8þ¤4[ä§T‘:x*¶'¾ Ý¢Š¶8wŒsÍÿOÄ·¤H¼§ÕþBëо¿!E1ÿ¢‰Æýv(F-"ÏZE1£Á onžU>'J”FÏûîmžšµÍšü‚jŸåe•øØ1†}¼yú’ÏKÃqù‘ÎûF©4ò¬´ŒZ¡,ïeG*@?áÕ»=ÍÝfSÑðN£ÄªuÊ™NO98m³Æ4  .ÞÅä¨[Ð&Õj­PëõZ¦}´Îè3ß{ÃâÜ–{+ðuK2ÌÒx9HHñ´ÍtŒ\ÃÖ6+“uv{ÿ ÌÚ¯í{Íö×íEXð®yuÕITnï*å “#¹#ú¦ÏåW# äH—>ÛA§¾L Ñð’Ðôó‰â:Ó°;öÚ¯ÚС}`ášÑ€u‘ò©t=‹ ‹>ž œ<â1`Jñ5kD z¶­àûôví¿ q{]Ç÷?$æ×|üßü}-·}­1L%ï"kß“iê÷2Úrc›Ó}O Îv™›n Õ¾Z‰è—ÜùnÅápJs8 E|>½¦:`[m9/œ;”–“¥º<÷A:–e”¾_3¥è(§ó¨“>Ìo€îÿkÊÿŒ*˜:c-þ¿³zBŠÈ; €uØ;«'¡À©îä¡c´c=TùZz’œuèï8FmŽÞ»;@¼š¢åƒj<þ}!G}vMËÞ½ÍP'…Ⱥ€v¤o] ¿Ù±-ã÷Tó€xõï² Ò£œiÉÔ݈õ'4±Z;ø7:¢ ^}O{,€£‹Ó§Í"´nNW5÷%–hÓ,Ó¼¦;}}oôË5ÆÀÓó)<–}Ô´ºì{E$9ÎI€7ÄÜUvn?ÒDC×k¥@[žg¥‘ƒë†,h¢Î ºiǺ¼æ¹±_ž­ðb¥ÉsïQ2ÏûŸeÔpØÀüÎsJsÚp.s&÷ƒs[2Ãczô ²]â” !#¿ž‘ˆ:ïƒâµ*žÌ“˜¼àûgžªØo*3†za¼\éšS*(å…;ëÍ×,ÞÚJš©ÌÓCîh9¯¢i^Ú@Í{¿zç’ZûÂFu•z{”ªÀŠ×e•Ä?†åú»ÆçÎŇ3—c5«"=ƒ,Ú3%¥Þôé[#%ÂÀþÌíûód©9ÝÚú˜QNŽePRl970Þ ¨ìúøí3POŠ×ƒyç”K«ÞfEËOhÖúþ…sÊõšÝúq­Þì-PÔ6*êýà鯽òªŒ”oa:Ô_ވЌm”O5/Tj)%#êŸLëÔi9³å{¿¬Ë ÿé.shªò7ÕN©&X7Ðøžëdzµ^v‡ˆŠ©îE¬È¦ètDé3_úuB­d¼Œ Y$é;7Wе O{Çu!žt*bN6•KæÛ_ts§¢÷vÑ!'oÕ¶ìŒEïy§¢·[!Z6¬ M”¯GÅOˆÁ h ê¶´ˆ‚ÀªXµÔ ˆ¼ãiTù+®½”·m0g è1(°ŽUò¬µÊ4æÃÝM,NÂooúìmË*Oy‹ö×ièú­#òï¾añ'Mð…í=icIœÓ*gÈ9´ís·-ÞÜÔìw6§Ö¦OݲxQ[¯m @}Þ§Õó {š–Wiä2-“‘Ñïʳ=¶³; pjˆ==¡ÕëüeŽèçq{úAy=¿µ]o¯ÿÍýþêØZæcùþx?S:¼Ž×®…6°8Ò"÷=öÓÞãÎÖ¨é Lë<ó(ÿ÷˜pç[ ¾íZiQGÓÝCø±–H¤ ›¿CžÆ¢l££é¦¼S§±Ë¾n{e ¹=c¾ÁÙDȉ–Gô¼l£Ôœn8^¸<¦,*wh:rÑ Ø» ©DFÌ-> Ýjï6‹Æ•èù–¢òÞå”ÈÆ¹mÐmG·ií’«tw§¦Á„{#©l'¼jw)Ѧ}áèÏ’lˆÒjìô9 U¼VËjt%w}£Úwò¼sxK?<“4–çtÖ¯ž бÍô2íqç,àPžÇ±àñ~YÌXXT¢iÊ‘zJÿ˜¶¬“:ïcù|ÇÇ&¥€u,³x@™Èt\_Q¦—Ï´„|6‡hx{?³qº/çúàá’V€SdüFÆÓA"Çž <=3Õ¼5§,Y‹âæ3϶¢xõ¤qÌ’Û\ó"f*ïœÏ\n?½3DxãÁ?9åÁâ Ž=€OM}«?Lå¹ø9rùtÁƒ½Ã2m?{àW~•ê‡Ô‹_[Q†A¶þ ¼Qœ2/ûxF ÿ²1"g„—] 2ã:W×í'/ÞÇIÏ"÷ú:V<ƺæþƒƒ’;žgʘ„MéìsêYäq(mÕ“î.xà{©3ý¸¬À¾*wÎ : s\çëi¼ëKsÊð9Ÿ¸Å"G34–IøoLûþØ-Ž»Ž.w"'ØÖÞÁ£|E•ìZ•šò±oý`á§·Æ{nšüeëG‰”¯.Væ7ÿÝ£CËa§Nµö[èë¡òlÀ<¢Çšªjð€1‡Æ}½èÜnÑA€5cµ¯ô½dPT¶ÛQÇ6Gí ° :¿~ýGQ舺%bÜç4‘ÀUÃ] ˜¿î3‡½o€«Ï]û=¯GcèÙjèÕ˜è2€øô¾½÷c£½Úô2nÀµ_Ûp ¬ß‡~N¹NÛë3ßÛ'p/jñj“9ðÞ†y»Ú:jïûG¡žýC‡?ÃÃûÄs¨öBƒÏ¼vÞe¢ñã÷•2zDî'jñA‡·Ú»¬üJ…çÿŸ´´%ª0Ïï†6„Ÿ¼ö=ƒz"ê|¿ˆ”ĵ"qDÛµ~&*×ÙM]¯ƒšêPß5À÷6jK>zFÕ3õI9ï’³õùm³’~#'] ^Æ<Ó²›ö|k;ýVÊÈ=°Ηí–9ìè¿@ugÙÖa>ºéÒÞãÚôrÜ·ëAÕ/‰R­í8ˆÑöH»ÌÜÓ+O]@½æ¤“úgö``}5 å²c“È¥…¶‚Õ™LÊTg^ã(/6W)Ï`eZŠ®!.VÒv ¦ŠûênÅ…@² 9ð€ÝrÝ•²vÓ¼ ز,¯#ÀöŠóŠõyí¶¨0KKÖô8Лõù©Åž8ˆce9êÕeù6¤w…‹è/Mm‹˜Ú\“š¨~¯Žl"î%+ 6nBÐI¦uð¢¶{ ø>øXß² Ô ŠãÕ·þÇbÓ'oY¼õËc`²ÞÔ©qxðÏ4™S¥Ä|.«ËE¨ã1ºÇQ§/žOÐw¦‘ÿw^vWÖ‡kÏ}Ÿýs«´ÑhøÛ«î[}~ùާ3¦:€ˆš¾Ç†yœ«E$õYÏ<­ÿ°úÇ3½âÐܲî%WMmÆuWYŽÇ_ãèH”õ¤S e[êš³l) 7ZÉÁCËÎ #"7Ýýóá6Û/½½vÀÎ P®N`œžç˲g4M„ïG-êOÕÝ7; ýÝý&¯Kà4IiÍtËI¿.ôƒRä¬k¿Єv]Úœ‚ŒàÈW§Ôó =‹ Ì6#";j qd o•ÞÆ~sùœzÎyEÖi[S’=f"k%º.âB–³]à>‚İ"° õ½cXú[Ëf¬Œy³Ä¦:¦ƒÚ± ‘+QèäÔûží§Æþ“.?¯¯WiAé^µ"æ†Z7Vþ™ë|Y_húœS8T“xNwl5Å?ÐrÒUÇ/±r£ƒÀž©Þ¡BEA%²Ð9|½µÆüh‹>?Îo΄ë8¥éüÇÿÔ<;”ðëK)ŠkÜ»úáòaåfކ~óž×àžrì`\ŒS(¹S×3ÔÚ™w©´½pè`«£æÎƒÚî1¹ää”…¹¼Š¢ç2gç”kŸÎ5?I׺TxíÑpÀº:PÖ±ìPÐ#ÏÂ9V·-¹z/ÿä­M“šéÿ©T­IÛ¶wÍÚ+&¹À—îùá(JR”ež6•’š»¨k:ƒ¢¦:ò³c3_Ú{«v/ü຦Œžo«Ñs(¢t(¥ä€ª£ü×—+<÷ý‡¦¥Ñ(µD'J«¯¬O+ÇP©¸Ô!×ùP6 Ðbm8 16ÑÛxœƒ~øÞ_Dýq4ÑO—þ8(Ò¼@š£®ÿ¢ïH9À\ä0Šëº÷5 Ù Ô 3 ZùºÇ- ¿×jæD˜ç`pŸë´?1Qø2Ö=Ò>||¶/Û1 V½]»På9·J‘Ïst{€3çFd—ŸU€x–ñLXÇóÑ8mgPú; ¿]© Z–eä̾p$¿¾'éhÒÿ %ù¨ÅŽª¼Ú—H¼ÛÒ«Xâr©Û@E„\ßÇDÙm¨·÷i@8ß§½¤†óoôöŒ˜;ÈQøÎ’Íj©oîm¼ì1f­1Ô÷ƒN ò7ãÛ­¶² Ä“« +@Þš%J‹Ò4‚qåÛ @‡ò^É8©µ/~û\NÔâr(¼ãwýt;ÅM‹€^"èL÷yD]S4¶Ï¤ïõÑíîq… ƒÆîãÐÿÑ4¦ †ÌÀ¼;Ô‡:‘>–ûôb"l– ]7€áŒÝ›àã³_„ˆØ³ÿ”ßOž±:mˆs¸Ø~R†ã+Žéǽ<[3ž·ÇyúÎ;ée I¹©ì:ƒtôöá½JÓ¡ÒNÞùX½]樸ÇRX­”vÖuš?°Î3Cµ•u祌Ë|œoé´7úƒ µcb8Í—Õú°äài{wlþ¬Ùcäx«ò€:IöŽ|”šæï˜0Pî<ú€)‹ê`%ø&jîZ»u=Èbgî:(QÆ•õöÿ FöURñìw\Ôur;QM¶»A´:Áê°9÷FÃ_pˆv5¿Tû¡Oç•&"G¾8í µË²Nµ§½±-Ô°×½ .DâÂ!WkuÕº#¿Ùónû¯7ú™Ð¯S$­–"  ü‘–Î0¤´¯}9̾9 xf~à׿ûàûXAm©g^£ÝÑ–pƒqÖ¡šî±€´¹­:z®‰çã(<‘|Àù–ßóÉidz-KG–w*½sÑãYâÜQ;RhË{4µ¡@ïúÀz${mŸA¼æçÊð]Αw£"B¦—hûÌjuczŠÊ(-&«>`.ÁØ+6ôïÖŒŸIÀ»¾ÓÝý›Ý…Þ¤å¡1ÑtÊ´iìè»èèáp- t%íÛ%Ý ½WR£ê:‹¾™m9óé°~ ôwŒvZßì ½v¦«•Üóúý×<¿ëŽvSN}…£ï ã Ðg•GÓ©•κutPz_ö+œ›kP =M}FÀw„£ÿžÔk–'SwÀ²I_zfÑœ¼¥\ p;¬wžçe¢WÔ\7Ȧ=û™¥}ö2×~4Ž}dÏÏPJ0ÑŽ‹Ï[…(å¼úþí^ûX­o€·Ú§è÷/Ò¡#Ðɾg¢‡á¼ØPs“œg­óôùöõD,±*(§õ ÆÓ"!”òÆÿ|Yª;7%Ô `¦‡Iõ›E«>ï w,|+M>óä2(úHǹŒº>T<Ðâ]s$›ó ¡‡|ùŸ°ýÀètÈæ‚”¨zÜ“µü‡Å©Ó•¯bù{/?Ç~ñGnÉEU:œvœ?ú­{ k@6£œÌG€ðbP±4m°ŽçWÏ\á×S×\Væ»Ú©s»–?|âÔ%Õr(fü˜B[×´ÆÁ Ö.Ñ™‘ûÆþ£ %.à4v ×4ƒq:Ðׯ)m à_ÕØ&RÔž JYP)uŠÎ-îVD~ž}Á såþ‹nRwØŠ± Ú¤§ƒN`3²¾k="÷+†ýnÊí¢ö#¼¤ãT ¾¨Ô(7ôâïÜ;Ä».£ç”eÊN½ó^MamÇý5Ä«².s´µ½*_C5 ×Zå„É’Ò¾^¢Ÿ2ç0»ÍUÔA/ÃožWsõÔ.úúÐQ¢Ê’D™±D£“.Ž%ˆ¬“‡®qPÐ R Þsÿµ¬Y®.ã¼yÞ·ÎAçYÏ%£ê(¯§£ Rþó<´ Ï 3 ÕßçæóÀyÃqŠóÃzOÏUæá#‚eaŽŒûZ«`œ¢íþß0P7x×òY 7Ö1ÔöÓj´½8æì¨st]ÿóï" §å|‡ ËÚ»ê½kZß Ygê@o÷`NÝuèïüý3X7Õ]눞Ÿ[S’œÃþ˜×ï©N×m(¸»½ö‘öÞ."çVœ““n@o x°»œ¿)YPÚ˜W1¹ývfEÚ{/qÚ#ëþM¯Ž÷þ»ï\ôiŽºuj¢ª Q÷ý!"—†œ¸ú>Z¦±Ì}ƒõÒ‡êŒÐòy䫯®}¬i¦ON0}Ý?d«K{ey²´Á²ÚÏ4ÿ{FWÏm¼…¥Ï€Ÿ TQ¶7];Ž­zà‡,c¯ƒ=êïÂ%œ×â{°6 ]®g*è‡ Û¦huÒÝsùN$k€k—E9©òðÖö;±Îi Øm6\˜)ªcœ¬F(øáÅ`Z6•¨ÏáµDൠÀ­"ñ™[Ÿ7&–MA3ó™¿ÎqK˜)¾?©ç\cIÃ9Ú‡c·Ûê%–ƒ¤Y¿~áxfÉŽxt›PŽõÃU…"8¾·Ÿ8G¸7nƒ·¯z6Ÿxþúâ§TÐvû}4zÇnQ£êIí7ÈH³(øÔk/Žs<¿¢AÀ2ÌÑr³œÏo%y8âv€ÿ6íyµÉwgDèP†ÍLˆq*íJô½-/Ìä¾ÇWåS‹2ˆQFq &'Kª»¬;ý Ê‘˜¾}2‘Û×ešîó6v.»ÙQ{G°ÍË<-PÑó4ë~˜%Uêªãü]ê978_N/­ü9Z¥ÚÆeÛÐd©qoãe—ò¥í.Ñh''ÝQò ¾3-ë)p€r›˜y¦Ã»ÑØt(»‹ê®}ur"ÑóG¶¾ý£ÊÔEu¯¥ØdµÒ9Í.§Å²ˆJƒq«õˆè¢}âFs¿Z}mD±96>Ä6©z>  ÆgìsÒ^“^5¼Sªu=‚0šeh3×;ƒ¥hN 6Tä|•øZ€ð½›=ÃL‹ˆÿ.òv«,ñ!…©#†è{¦f`EÇ-ÚlÀ“¹âlGMÂxh‘7ÎÍ€Òž%Xz¡|c¡¹s±:È— œž1T ny‘#êÿ‘Âýàx|( ýÜí[4n,,÷ßÔ‰ï§UuÆùglc±Ž ‹Å»àq‹m­ÒĨµXdøÍ0BQqTª€bUÔX nuÁª(¶aæ÷›FEE6ã5 Í·÷ù^ž|ròÜË7£ØÄoròn÷ÝßïûÞçœç<çyÝ\ÿ¬‡…{2»^N36Î)iþw¥½rÓÝ.Ì´y]?rR¸Þ¨¶çŸ×ã›¶îjâyÙ¡~Ã¿ßÆ~y¦â™S ¸ÑOµëË8}=©O„^íD¿’º= JVuÀ8Tö!H€;rîqò"÷ØîQ¢ü ’k>±W]÷òܦµnÞ¨±ã¡'Ï|·½øÐÔ··¹ÒUÚé H£AµûW–<í£‡Üa2íÐ¥;çSsÑ®¼üд³vôiוÒ<2Go<<¶?ÁÞ‰¤c´óáï®ß_Ä• ´G´(D§7¢è×¢H^~Ï~çM“N9‘3ƒîcÎXŒcZß \=Ql ¾+PwY'ƒu] …Œî4$uS›iMp°Ço^ï‘K@Oä„Ëpz|Ëõ6¨[§#¨¼YYÁ²I `LZEþþúâoyß:GQCø à«e{:î€Xã 0wëÇäeË’mW4‘*k¨äÛKßwPÛQ¯ëí¶k·»o›|os ½\Ãz €qo+–yÜCŽ—cåúâèຬ:[ ÀçTýB“gä¾WŸ =œq”w+LžÃ>MúÚ ôÈ“³^ZÚOä}<+°Žþ‡ŽÀþ¬aéC×VÏ š† omŠªiÁ¸¦¿{¨mÑ+”v•£4õÝÃÈ_×´¥è}ˆeoÇÒÁ}œSûÈe¡7"³Ðœ–G$½ê—Œóz#~Ä5GhZü1¨:?½¤‚mj} ?½Ìà\ÎôŽcùcH[ƒÎŽú Þ5Ý£ë ÍÆH׸̚6 "ÐOÑúY¢Íý‚²åxˆÈ5Õ÷6®ù¥_Õ:ÀÝ)„žžÕØ6ÆjvÜì/Ó6l °‘ÔB×¾ÕŸ$;#Ç‘f"Ë à5nA^w >ÛiËXþÖtrm[ç›9§í( Ÿ:êÕS1+u çü9—ùþ'¥ôp>Ô5#`zÀ°%V£¦uŒÚŸ®Õôø8°0)É™|uÌË‚,c¨ÑF}€\ü|xV{¯2¢9«18÷PdéÝXYÒסÊ{X¶ %¤ç]˜% `Ù¾/¼çA]MZw–à\‚29Öñ5ÂA2ôÞ}syzõG°ÉçÎÚ€ˆ§¯Ôó¡’÷îÛ¦Üýù •iåâ΄›âcÖC^_^x| 6ó`Ø=Åþx$8ïˉ¦Wv†Ð×ûxDÒ‰’ÜsÓÑø§¢«@„Ëž|áM%—Á·=U‘} âà˜rÞvÔqµm碡Ë˼¬Õ×½Ì_F›_rñubÔ)êQ ggÉ”÷Ö¡Û½¸}RGýžvžÏnç(êzãÖ)‹DUè6@.Ó´ÍÓ(ŠœJ‰'RNmü{sS`g(Ÿtf¡‘"æÔi£ÎÝ}x 6O:/k()<òJ‹%ÒÈnó2ª Bí¶Â4@Ñ:Ìæý)çîNÊq?!‚fPmZô®É3wÒù7"–ÒãÚg€¿‡½¦9[¥5°6P6@fº``ÝÚÈÕ¦ÝÞÅk?~›4ãyûT« ÐAü®–eèîdþÌ8Ö0Ü8Þ~ý ÊKt=@?­§}È4®¶:×>†ƒi(öcš|æ¶› Ë„ó<ñ,Å6±Z¯=žkÆkù8Êåì‰ä‡â»‡eçÿpGxÎÀ[À¼*ÂwÇ Ç‹£®­Ç°¿ôN™•j Ý‹lÇ{Ï%Ù<<®drÓÑ㨕,0½‡q¦ÊÍ|r@8Ñõ–.µ®a‘u@<¹é»,§ñJwtº§ Èù§T(Ñr‰§Öï¥ÆíüNÓ2¢è|»Óαémµ~º¬ÔV·óßÝŽ~§Ôɲf:)yçzýŽÒ¯IV!9ê”jœÿái×S¦Åw×J«²/'Zé~=à-Ó.G<“Ë¢?ìÓÎëŸÏÓh{¤&0tt¼*ïË!5Ê}nÑÞûÓõôòdŲ €èJVñÜéÇ1q$K:·eÛÅ<ÄÃSÑ]X&Ù1žûgûsAÂÕeä²ÝJñ¼TqÏ<˜+JÌùú œ —Y +pR fc¡h¿A:@Q‰¤ðç±Ò¼M޹l¿ÛÛ>?Vg>ýŠÃå†?âUߌÜ~€'¦=x¡Yþô¨5¢€Éñ]|MF?µq/×£þéç×¥R…"¿Eög­SyÝ-áPn¾±‹ƒ…$8LêɃŸòœ òã¾ÎsªW$Vâù´³GxWÉ+§´F޹ÆC|ÅùYšWrÍ­ætvu„à4 S»ç^tse»ðóß)´kû›Ñ¸DåÔ±ˆ2iˆJžŽ±¸Ö™y}3{-š¸ªö‹èÿeKqpt¼SûxÍ$ðåºuJ™ÿ^‹ØËyÓ;l¡ì(ŒéÚv,‚ô`ôý á\ÊßgwÝÛ÷÷Ϊ¢==ÚÔùÙ˜–cPÞgeÞNzÇþÊ—Jìç #º´sƒmhµ=:>ÞÅ«¢o€q”Ï5®È¢:ùõ.:f:ð ?£hTЉ¢’ßÌqÌ(âvæ¶¡™}œ¨7 ±YšOižŠ\Ï~gþÇmÈ>6žD°;x^Û `wTûÜç¼óÆÅû[Þ»„óF¿ûõëÅß6Oa pܯûNö çí« à/ú½Ì ¿8 à ^q „@Æ1Ù\z—zk­~1¯ùéÌ#U`KÏ~aIhZ²Ä@ÜϺÆ×.vˆ,VDãQ{׺þŸ"Çÿ6 !F·/õãj…Ø5,Êx$s°}ê…ýÓÖsÔ6‘tƒoR~0ÍÓû–q€úàÝ @'ê^Þç•+*xœ§´ ”óÝê.m9‘¡ÄSK½ƒó6­¡¾ª:BɶY¯ì³­)®ZæzîyO7ƒâÞ¦q¬‡ÓÝ‘túÒ•)À=ÚL˶Êé[ P—9ݦiùçô‡b¾ØˆŽ®+ð‘Z?C›ìæBqL3´+£Òi‘Æn—i¶%¸Èµy®4ÀxÐ+x€ù —Ä9Ã&M½-,¯oìïRuÏõ2}™ã²³Ç§xŠu NrMiǹ3ÀžugÁܰ¨%?/ɬñŽSH‘(BÕõœºEð²j`y:ºFh=þødòaÏ:sõâÐ~&¾^&,óªQz“K¡3¦C ¨é* ÒŒüúf™þºFáž”5ˇ´RSˆ^ËøƒóPÌi;I1¤(kÏ¿úßÅÓߺ}§FkRLÐЇìüïûÙÃ}½òÆ+æ2éXÛiõ÷ì¿}ß,Ÿßóc­{Úè“|s ¯0—Iw™"äÓÚæZ—(ùÖÆ{Ãy«f€oϸ€vÔ…ÖµêyûÈ)çÃn/½çCe«â7'¶ˆî…_ü€rÅOšç6šz ö”H…€pî2w¨4¼üw=dNûe×ÞÙ:½ê¡L§­Ò(+¢³ ³v2ϼòðÊ:jî¿Zæß?³Dud¡Bw7åÝËœß9Ô{ùoY¼  Å=çÝÏjõÚåxê[ç„¢sù®)J…{DÇÝÆÀÃ`Ö5¥£l™Úi¢o%7wП×ÎGÑK«ŒÍP±Œh¤Aš–ïÿîXŸàäwݹÕШ‰d÷Inë¶ß3Ø*Šý¯mŽ)@lÙÆ(Tñ§·÷ÕyŸýn+ùSOãŸêã—õ‹qÜAY¶3P®ö¬W¦ÃØã€¦{T_Óv¶o@®gÊ<η‰ãl€f<À<à{(FW«ÚÕÆmqT _kñ³Qäܬ[KÏØ×cwù@¦ʉFŠ âŒü÷ÉU78ïÂqÍyy(À—Zìc³ã1Œzz\šžgN^úÞ±—ÕÈz}wÇ<Æ‹ú{ˆÄ9g|™—nz|Y'¿MI‰×|/ˆ+UKeLo`¯%ت¼¾ÑS°nç7ßa—`ëëEÍtÀûrHɵ”³þ €ÝãhÜL­ƒýuõ[dEÝ]ÔõG¾úzO«®º£ê# îGDÚS”·Õ‹¼ôÌ‘¦Ú‚ry¬ÃT16ÆéÏÖ fëZFì¡FOËvÆb»I{Oì´ëÈê”—èËÊU‰µ2M,«8/v”dŽv²Ùqsý†ç™÷ Mz@®Ÿ–5ƒ¾l¯bÊ<ŸUN‰¬U ŸÐ]ïN]­`ÔâÜY¥JÓÞCç.'ÕÀŠÁÊ:v…þ`ßÔ¤µè8F‰Ìwá!÷Í3°áwÇâœOÞ¾Øú‰Û—ú¯ùØ·¯hN‚xß·/yÿÁe9Æç7¦Æ)ï<ÐX-È+2¨qò½ÉAÏúîÿz ·IÌKêÛ³bE$‹‚úž Åý” öPÖ0"ßçmÖP¦õN¹ðÆ%ç—ï°ÿh×ï¯ÎÛ3À Þÿ®]·÷|åû‹·ý4¯IþôÜ5GØuîbpåÀš×iäPîõ¿7Øö0òÒÃj„?hüƒöì—¶àtÿѹ ØÓ€åyL8`ôü­¬V:;Ñk=cVž7¥^6¦Ô³™çQÊmN{ïÛwdülrÚ¯Þk©ÇvìôRúŒµ]D»ÐdRãIgQ{¸¦û:mØS~4]"éiC@n#²N›1S°Þj¦£×@§Ò…¬‹Æe^zWYOÀNn:9èk;‰¢ÏÊ´Q–Wæª'€x+wœtl,.· @å}OˆË1^híͪ£Ýã6˜vìvþ›}çþ„¦ÍÎk”õõ¨™~ôk¶›Ý§é¢™óG¯½ÁÓ%(Ŧ>S–Ëzz¡½k¹S#ZnPÞûdE´wX–aæˆ.gÉÝÂúѰ§ØÇÛAy½²‚;>ŠRgšÖ±uõðó€Pœ sv2i¦¡Ò“ŸÂÞu^eÀ'9ðÙ–²Í+œ&ŒOöŠçˆÉ­`I„E9¹¼§yî1ÏRsQ‚¯:’-áÔ,W^¶çÅ8û=*ÀðY;ò•}ã¢\V߯ÞÚàq4“DÇÓù°L 䛊^/JýR˜^Ó“í‡8#éêÌ~ê zGR+jtO ×,þ3UFEÆÑÈÖá¿jûÝ‹úÈ!ÕLo/Å<™ÔXŸyÁM‹S[§]zÕ2Ošf›—}ààÌ6|P5îv"så÷Þ0üB!â»ÀãGûc•*rÐÕFÞ^q<½AÇ«ÌÇ  NÎ90J§%(71oY”OÁcÎÇù3c%ð4àºvU‹bLJ¿wðìcŠBžóéï¨äXQÞ_ Ìøµô”®ˆB(å2d>åÒ¨QîiÊ¥uŠ÷5ûî[ \ÚÞ€©ê¬¿¾9NnBkÛ¼CQúžù`Þ ©VY?ù‚…ù°Õ§çüí»~±x¾Àek-º®rqü’~ÿ¬öѶ¡‹’3n ê‹øý=üÉ) ÷[–4æ`ôÔÜ’%ÀÍ„‚^iÍçiÈÜqhœ·ÿüwÉ9pLµó·7öOþÒó–3~qÞ§_q[c;È‘qóâŸ?vhñæ!ÿHÓ¹¾½³$ôv$?Qì·´g넲 ª„û´æKÝÝ Õ¦åZÖ×ãAÃb¬Ó§Ÿxör†5´0à~æ™`ðmÓž=+r¦c=ÊôÞŸ@m´³€ž€°þLÀ,ŠJ¡wTz—ŸC†“ïzF©­ÞÞOg®k8Ww×óGQ&°¸ÜÞ2mÆ ´ø6N¹C[O1§übˆMÎô-*}~¬ÔJ—•ZëÝÙYD8@ÓXFnzgÙ‰êv¥4[eIu19õK<Ÿ¼ó>®më;b`þØ3Ö¡»o܇h)ãñ²º=Œ“§Ž¨œÁ¹Û[¿%•ÞmýÛ¬vz3ß ÒõÝ–xl)•ú¨×m(º5o4 ïDÒµ-ú$fú±õ÷­ôsšy¼0Í´•Ô@SÝÉ;ïã˜ûj€ó%€[×ô*ZvZ–…– Ý7ÚbD— h ]±O¨¬þJ0‡øÚÄœ4­T3¦JŸ1 ¦ Ûmô¤smÀv“ê\«pUûÜÓyÏLM÷²¤þ3Oé»qm’i0Þ\ÃÀ³šÎÀ¤#èkQ£-6< GøçHàìe ;)ÞxçD3'€‡ž?¹Ö“¨{Þ´QäÝ"ní܆áq>­åÝ~Šf>Ç µDÔ‹W-_̧¤šójZY…ë‡t‹¯…rô8Z$°roëŒ+j¨hæéOåæž}ÁM<ÌgÖûìsK‡ ç©èßèwu›Ïq¬¯—|Q°Cq·%0ßꤲ.šÒ¦ãajïXÉ;oÖ?xèÔË"bn3 ×[t¸'¿y_cFü|Á/óþ%tué×~ ðÝ"¤ß^‹³>qx­ûøuPè^éOÂt—|ù{MW`ï€@UÇÞH‘×´-%ÑñHkÛþP«}Ÿ‘íÕI=ÇR]¿­11´ÅÈSIu¹êË/Ó2¸TöªtH%¿zïÜiðö/ÜáöêY*­Íû}ýITM9º¶ŽvS. €žÔý[§ >ż Q[äM€ë+ûÇõê_øž›g´ðvPÔÌ=ýÉ&ÎöÿýÛhö¶úÿ'èüš—ç±Ç YV@¸–»Í wYåâ½-Û9~Ûn·ó6ÜÞûq[_Ï×ñè>g¾z’c^Þ‡›a¾Œôñ=ŒõËñàPP;¶Ës5+¹×ÏàÍ|R/ÈôÀ¥§®?Õ æF;€{ÖL8w£ö:zÞ9ëžfœ¼u¢í¦Ë;GÝ`Þ€Ü:€t¬‹`hò€ó=_a3fTÎGdT'Á¸.(Ú¢à^Ö€ûFw@}§ôgXáC{LÒ¥¾zœ×ütGÕ·¬gMu¢ä»¡¸w»ºúNiËþBoÛ£çk8øé“d­t YnË4¾MV ¹ã6Yåq] ýŸ5þY@ž™AxhYv­¢ h*xÄ/ÔÁ-ØÅóˆô¸ Œmf”}¦ŠUæL‚9£]¦0gÙ±i©å\ Éñ’ §H`±µiÜÃP©7^‚é\Οy'±PÇ×ø‘ÑÞ9Ö,%Í5XêCV‹í5(MÆÊ<4NÔ ñµ¬oíåqsSÙ®8 BèÀQåayµØVäÏ]©,+Åï¸Ø/õñè"Ú8è¢ÎÈ;r¥˜íeä•£º3Mu”–þ}¥ŒóÖùÞïvdÝfà>“5¸6µ½èظĚKº"V[AºiðÉ};ý@|+|CéGµ>V‰¨‹±¨ù©ê¾‹Š:ôÛz$}-R8¡Ÿ×¨¨Á6bfDzgi¹©;%gx¹¶FœDxC°~-ø+pJg„ìJj«,˜²Z†>ÆŒD'Pe]¯7 FÄ\Ûb^9–8oÛf<@]úLÑ]­pŸA:Ž/µ‚ŠÎ½È¼ðf¤Nςڮ^Ÿ›ÕõæeS÷(šîñ¶óò*2¢Ò–9@m3x^p(Ê‘³îq›"È Ó£–…pLræ%”ÑïÖ;nHü©¢,4 ¢å+è&²‘r}}ûK÷ò–‹*@ñpþD뼬u˜ »Ôô”‡Jôq~çþç˜vzg‹‚ÎrØmó‹¾FÊ Ô3bîó Ðeþ Dé4çcÙô¡Ó|}°Ä;¯ô1¬ÓÔJmóîéÎmQqe\öǧïÐPÊæÊ;~Øï«ržÿ»‰Ñm¹ò¶ÅŸnÝP§¤P÷m0H7=ÐJ¸nÓsw™rèº|(Ÿƒé¿ThðRܸ%øáþ)²þÁ¶íFïÍ-;ïÏÞQÔ¼Bë<¥µ=¿EÌ·\uxñÌwì£C«N¨ë#ÊäÈÔ2Gü÷æGé/]ÿ°×uÚ¼C c%Åý¥—ÝR QÖe®ÿ-µÁ•ò“h?©ž «]y Ø:¤|Àn ^¡Ak¿§7–© ïo_º;«=/Oê@WN À¬s6àÕõ¼U/€º¯ãm,ç©©íʼ–±_;.Xîm⩽MçQ#þ9Îý$>ÍQ·³Å¬ æ“Z¼ïkÌcþ¼“Z¡aÒδS²¯¯·‚RK¯ÂcŽeYB¢åÅØQz'_ÝÂaOÐ{º+Ê;¢î¡µ©ñ¨·íõª¼)ƺ{Σ覿£öŽàbr˲mÕ,_Ž[µ}wFÔ{MvÏಇ9šŽmwIP}ÏdÇlá§y_V¨í.·Ö£èíX°oØ;jî¡Àñ¦¶Ž  NÞ9ñº»çTwÚÞwðpXGÝåÖdc!9ƒx"åž.i}´±°\é_Ɉ¤ký½™@ý£ XÒßk`1#Ú!ú<_# AE¦WætǶfâlÉ fÛÓ|åÜÿäfyøìOó‰ø‚ÿÀÁ˜dJÝéþm¿Ô´«Ø”f˜±bÍrа[ €‡ˆâÖÐÛcÿ-Æ:l±lpÌ¡XÏüBÕ O<3ƒ"R | ãÂö€n¦±ä×0“þGù ²Lô'*9(zhíFi1)óIeÁX',ÏG/©ÁO"j–5Ðk¾È<ÒN[¦«ÃÂ%$ì´(¿¿¹ôàâKû~´¤òþ¦?EÞ6_yX¯òBDÄ£Ù˜%á{Þ% _<ãü›†ûUi±t¹Î955µ À¡Ú¾+¸;`¼ Å‘GE”¼}<õñ9úuÛ#ªþXSÒ¡´[¬ÅÓPÆfåPæó|9kRÿþx,S ò#û‘Ï}sS$ñåÿvPâF•®'Nžž#æihB:­MèP ‰¬7Ñž>M}ó"äè‰æK+á’–|Áßä§ô€¦Â~÷â-:œÕÖɧt´ÜC"Cä•«céé0r@{ËQõ75¥î‹¾ô½Å{šP›ò™/m’—^óýæ|h"nÍIðáæ@»ü~¨{ ã“])»gqeÓŠöƒJ$~fç½­ÔÛ}‹Ïµ¡ÊÂý×Þ-Óh®iöÕ–Öðõæ¬ÑS9Ór|³1x¶ú©¢à¢U«¦¸D×`ü™ÒQ–"s7ÿà狃íšœÊávøî_.u^rÙÁr7 RjôP¢íÄu5uVƒ&6Ú@}~ú;n¾¯þþý“ZÍú…¶Ñà" pm'¶T†ó¯¾c)Â÷Ûþ·mÈ)ú¢K¾ÕöI[ûI#šî|qGÑ=OÖ§dÊ¡±ÖiWÀ~ 0m'ëà@ãÁçàyZnKOôÝmKívSÛƒneÎ<@_æ61­mú ¯m˜—€ž|wGë+G@N¦(9Ë¢¬ùë–ˆz·¶+ýݵÏe:–:†6ãÐà‹u0Ï´@¶Þ™²Ç½a0ÞçñþÌZëZ®üñ97oÖ¶·ÃàÜŠðú~¸mÿ~dŽ:VEåp 5O`ît«fšîß2í1Õ½¦vÁó·R€^¦éÎ#¢îzê+jî; Þû8‚®ƒã›¿u·iîêg¸¤*Qo³ïBѽoÇÓצ_ä¬;êû>bMt¢¹­5~ÜÕ:Ëy=g]CÄz ®lé Æ#¬Ñè )Ô3ì^ui~òPGšn`0Ä8(³“c!UÕ9[ÔcOpô>t.ƒ¨z”»æ|â\Gj윛l5ëuUÙ6Œå óLǹ2ºŸTƒ¯˜‹rß0qa‡ JêÙJµ¬]ëäóÙÅlX7®î0¼º Q ãáâòfV~rFªì•’õ{.3^ åÏ-éðé çÄçšþ§¥ÝjNý©—vá -M¨KâA^}‡TÜ3o}©¥w›ŸõÊÊ’•S{V‹L]ÑÊEhÔqåßïN0 M9Çê|/é¿ïjÊÙ§¾ï`{i×c˜‹ÕñÇ@ÅŸûÎ9…N c"¹Ÿ~±‡œæg¾ùš=¹ëxwùpHmTÞÝ*€ÒóÊUTŸ¢dºœÇ‡­tàêG®(³{ºŠºômwêY-‘¶€âžQu}¨5ií:Ÿ/9펴ïõ¶ÕŽãÖξ’*/êå^?3àÿDwž«¯³)þ²ê$À`Ø¡ãgÄÎæ“‹>ï1Ð?Œ£öžU:èî5Ô—Õ :(¯´øcð, ^Ë#R€Gí=ÿ×öõ]R;ÔwÞ)õ½SE櫎ÆROÝï2ÕZ÷{/ÄãpNÄ}"åDÏëPáSlÎíM7ÏRlmž©ðÎK·¡ø^ØY6¾G˜öað-@®a¤w¾ÍuÒ3_}S»ÿšî‘wƒñÈ?¯¢rÚ༲èvO_g”c%yÅ9 pôkw¸4¬tsÈIG W}(òÎÑÝ¡ªM³®¿túY¦¼ Ùâ’eëÙoÛBžº¨Õ”ÇQæv‘Ÿãޝ4Þ _³XƒrÖ)ÀŽmìŒí'!  ˜#Äy>YÝ)XÕ‡Êòvq=æåŸ³<5Êûso®g„. >Œ‘¶Íù±~`>Ð'5铦Ÿíjä¿PñòÈÔE4–\Žõ´7E v(@MêÇS4#X  ¥2éµ—‡|‚‘ú_üÙ<Ìm‘˱‚vNÖ uÉyd<§}é壯žz³´þØûãq 4XÀíØ®äª‡©E¡ÌX®%Ãl¨Ç1{)‹àšgóiÍ `uý­?‘J·ÔæÕéU~¹Ž á7­ãR[y& Üý²ß¤Üô6“ö×˦áå…î>~ƒâÅGÉùá#ãÃÖi륔ZZÀà…9cÃÞq¹g¼sØD•Ó‡]•NÐÞñ?¶« à=/SÄÝà}>F¹Tq·QVfaÛ4Mdcs{~!/ ešg°NÇíìZÖGÏ¿8oŸÊ™I}ÝùŽ:º“ÂF™WI[uR©) ïm:]18ÔÕŽ²:¶¢‰’WÊPF½r—Y2(7`V[ûpÔÎñ*4Õ;ú}ž–EY)À54oוör@Hˆ¹€{UÒ–%à6Hò2mß ÉC/+몞ËïÉá¤èÿsZ™4@œéàÇÒMÍfÙ S»g4aDv9Tã´jå5oY<÷¢‹'¿eÉ4ˆ´é“Þ$ ,GKŸßM {iOêûÔ°¯ PÕ8¦ùºÖúëÞéôöXÁlÇF›¶~æû<Žï€¿__¿æ{Üç…Ó£n G ÷Ç´ u˜7¿O¼)5GÔåÌÁÀnYÓž¨x­¿Nd]Û0_ê·³Ž­ù>>ç²cÏØQº¶é!€½SÛeÎ=7/Æ»ÆÑuϼóÈUϼ÷Ô ½ƒÍBJG§¾'gnhÜmx/w@Ÿ5Ô Úê^ÇãPßÏžÔU‡‰¥é‘#ªŽèœ–Ò»ú4V”£®as`SRÔ`Ý@Þî6ì Úé×7¸ Qv—•zéÚ§—èÕ†>|hM{ùJfž”á-NkðM´ÄÜ8.ÄÎ. =JÈ®™Ë`äq@É *Jzš¼¼,ÑSVäà§·(ñ\å>|<<ÐqmðNË3XL¤ó¡­¹\¹PŘMkK”M«Ì1(îIs.ùæÚ^¡Ÿi™¶ÏÇÕ@y1ísÎùÀgs—s9¦Òî”35Õ1¯u6ox~Í냲.³XL9çUüGtI:U²-wÔàÒa¬÷iGf Úµ/Íëë‘ÙÚôi¢ä² âé|Ž;©ô ÔTT¢VaZ¿ƒø ‹>©³í9 +àÜ Ðò^®i@‘>TÞ=§Wëô} ´Ýóƒ ¬¡•°3'˜šÞX–èx¤v'ž»gqâ[Ç"h„hÙNFr ±T7?nóº#ÈZGCÔÖÐÅ´]fO 8+¬ùÞilKm™7mÏyšf{Ûvq,gí¬íqhZçû)¥ÝØ×+LŒöyí¹·Þ/ŽŽ‘qoHmHa¹yvÆ#Mb²N¯0à’oŽ”óßA¯ÁÀ^ÏŸ)®Ñ^(8Éà°_úª“^ÀÕœËÓ5#IºèÈ ÃGz.˜)ûô#zx;ý绬EõQ÷Hù>Ñ~œO¾ŠÁ`Ÿ¡ýUX dÁ7£{Ǻ÷ðžÒϹ^'×ïf*ÇBP;ptùJqŸÐÑ™ÇãtÏ@ª'Žò¥³vxîgþ‡`}=d¨ e Œ¡uDî5ž‹ÙS6¤IÌixHBLÏ ½n3yÌŸÇgŠÆ\-q˜ËÁõª/˜²m_ï#3ÖÏùɬEZÊòc›×5—YtÄãE ¤Ñ²*q\óå€öªÒnõÓ­‘_.³zªEXøà¥WÛI>®š×? ¢¯ ˆ»¬ ß.ÓÁ6xÍ÷Ǽæ³Aµ“G_€œ|¸¾Lóe€oòÉ=îœ;E ´~ï[ePÖµ^ˆñ$Ý`<èˆD?œƒH¥×8_Ž»ó& nîvê$Be‡žÞ×e¾;’î\Bg°½ôÒAûT§Xyûwç—H8ãRZîmè4÷鎓ÒJ®k˜®Çæuµñ´é³túuœ€ˆomµ€;Ѽ)Dº‰NÊæu®É1šßDTµäLˆ#oš:ÛRÕz]¢¾€NY¬b­„÷È5 7íjÍöu_¥ DDÝÑð²¾"çr"æÞ–ŽÑÇk0¾ÂA€Ù!¡qo‡í‡C"õ5bž¹ë “] ŸûêöSËå<—DÌK¾Ueâ‚âqþCìü¥á$ƒÎnyéä«·²kYk½ J»K²ù=• 0O­t¿/ÉS/ Üâq.ÏhçÙÞ«zÇjXÞí¡ýa0^Eä4„Ae‡lŸ´Wµw"çŒËª’»†Aƒ×wINh-7 †æ TwÊÎW(½'Ý}[æ§³ e÷^‚5ui¨§¾[ËC Çyê6èìèê§Îø#[?»ƒyrÒ‹å<¢é•µ(ƒê.38(ñ8LýDú½¡°@)KÓ¦ ©1?£ÝŒ( %0Q0~Ù&Às L‘¹8öijéD+ •ñ©C`nàœz:r¹¾s‘×1Ž‹v¥;Æ=Ìó W³Í´\Ñû‚A)ÝͱDº~¢T—N6ˤ¥­E-8osb‘¨oKÅE.Fz!°¼9™ó`z}æ„@E ÚÌJ/çËöSð¬¶Ï›¤ñ¤y¯¦®@KçE¡y¾NœÓÔƒåýFÍ@ÍÓë3:ïêy‹þcú˜Ò˃"Êdªƒ¸#æ”ä`žLí{ÛfÔ5znµ,ºrË-—7Xf`^£âÐÁ¤ È ÆÕf@+ÃkM^—éfQB¸ŒmDËýñÎü5yè¡ÚmƒfW­æÔ9*^ËËÐáð|µuýXÑ÷t-üÌ%²ãˆ  /%"æj'ª»#Š`8J‚ˆP¤]Øh‹ŒN\ÔçíVó%esÖ!"^:£tD‰žCso »D©L#F¯æPÝãµçpW;ƒq:ú´íÀáOÖÖµ½ˆŽ{ZëÅ| ÑLjˆV&ÓIYøò|€X ‡¤k;ç“CÉ.¹Ö¦\[Ñìz_o†.?f è&O` à=¾ë)0¯‘m€>Ûà*Òn0í’h€â!g#BpÖ¾8†±ÓÁûFÎuL>; 8Æå<œ œoloÅ÷sÀ²ö°9ØÏçIÏ‘xÚ!9ÞÜ1Täq4¹œß\còlÖŒÐÿÀˆÇX§Ì‡Îî(}aÐÂRÁºæ)}Bm¬%Û¼n§Å·qÞG¤çÃîw"ïEÌÊðˆb:-( p^ÙKç(Ä›ö¶tï,ö¾¬8xó{Ãr}£˜SËåÙ h÷<›ºT,×0¾¹rrWPŽ“œè:µÑí|7P/F›Z†íšbDÇÑÁqýtÛ£e]CrÒëèê”`D-?Ë4­DÐáU¨W&–£§-×ãéšN°Ôo”À“›VóÃk´TëN€oU…ïÛè*ª)I¨šþlöÿ+m¾‚9Žß˜ –mà™) %•›é ~9†9Å{HŸ ÁE‰»(Û†“€ëà:¾+_eäzzÁmɨŽ…ÕÁ\¶í T„ðtå ÎåyPœ æB­á½áÀbÛR„'J<b‹ú‡eÈq†Š¹¦¹—)óº{Ùi-ø¹^R¾“ ýjíòa–HÏþ(e_Ü›`>Œ”gÏ@< szýª<ûii¿¤ùs>¼¤1ʪAeW¾9ÞZ>úXH¼¤|@6uOpæPDÈ£tÚ£Ú~\âÄË‚:Ö£ä‘kŽÇ›çÚ§:Ë¡¾Íiì€ôVoõEË¡ÓašWç ¬Ú磈:ùy˜€9@:»£5G0M ¼·uYe§hg)·£y%j¢ñ* d°êëÇl^‡ÎÅ=(š9e~&yœ>AÀÿ¬]æÊ)÷òÈ97¸•còü¤±€ŸQÓÕ9¯|Æ™Æ´Í °‰”‡E$’y€q€ð 8•h6h‘» Í ÜË¡¶¦ WG°ƒò (gí‹6€ßÕÀÜ"h€–Ïéñe¹¦#jMD;·“€>ÖO[y­æmÙ>ø%¯|t¼5m˺î)·ê½R4¦Åœ?rXç?u×hÈ÷:YÃÈú,={çf¾DÔüx†,c:ÌlÀ74øÿ£ìüwì8Ž+̇‰˜¦-Å‘DI–€mkªµÒÝ»¬ß6ö¼c2À»©ï8_i,ho›1‰Áa±…œoˆAËñh0m §m• ­ z#œ'Ð,Å9£Èn08r­ã,5ƱÒùÒ­Y³Zï<â#NüÍÝqÚÜ+ÝO`ÎóòuXS ëÁ1ç—³šÙaJiü„3rˆ¯¶^BßšX~xJ}A¾Ù€T¼Þ=˜ë”v 0.0§‡ô”oþ?³&<4˜\Ÿ_#ÀjâÙÔm Ùu6F4 hé¢høqŸñaàLþô‘ ýQ"ä\•âmxóëç:| žM2]¢³˜ÚîßÄ/é¬Ûì-giÓ†Çüôõš“¶„åÃâݦ­–õzÍ)™­â,€sYÙÓVÚ|3ƒª[>õœçÃ?ó´6å˘½1åÁQO¾ó,·nó‚õzؤ®©Õ³‡—|ÐÝ'pŸÀ;ý ·ËÐñΔøqçíw*|„èu7Zž£k ¹á™únå*î 7žõÔ¡ÒΠ{y®nS¯¸Å¢F]hèñŠŸ)«O€þtå+ŸéÐP®} ÄÛï¢OÏ"*ë)«zOP½£° ¨ÜªðŒ(S—;÷á°`H=l{Öµœó°Žög,85žq÷¶Btý¯¯¹ÖU÷ý_Sßöؠܳ?X“ºÞ6–?¿ºe^×·½&3bc}Ë&Öq£Ï™˜&wú¼e™ Ò×¥.û¯Z}EkúT{ºóó<üšÀêrãл-ñëxÓS2ù6JǯWƒ¢ï—šRµ5ŽýñÒ¢ØQÜÆóþ‚õƒõ“÷”¦´÷ªwiÚðÇäIÏrB”$ä X¿kzQFÕûX't[ž‡L¹> Þ´l˜•ÞhÕ“^S ¶ç³ý×ßü¤¸ôX'χWÝVÆ¢°Fí½@CýýW|E ¾{ùëhád]Vá¸G÷ ïq~Ó±á¬X ›P@¼è¤¬]™pÒþ+B ÚcS¼7Ëû­0Ó!þ;”UvL, ›ö ˜5V‚oF©UÜ$cÔÓÇ1á£ÍfVìe°kuùáädÌ®T׈ƒ­{Q\Ûfœ •ø¶ OZ?+¦c:.\iÃÛ_"~1ã°yÝ]ñûº';{Сî|Äïs·ÉR!è]3Uì››±ŽaŠ· ]êíqßÓ²ÓŽù˜¦]pîøíëÉýhc¿Ë°‚U‡ åˆ1ÏÄ‚)ý #ÂæÉÆÝ3qæ!ðÖþ¶IýsŽ}ÀÞUmT Ôݽ§®/v€¹^øi+m=ˆQƒ‚>©íO›B Ú{úœÆrY©¶Ã Ð%Pž™öeù/+½Æú ç¯½éì„£€¾1@ûê[ï„R¤iÐòÒf”÷l·h‹/—÷œAà:cÊ OþéÚÆêÁ€öÖw mÝV@Î`3r+†S)Ðð/0Žrû{ ˜ñ€©]Už´”¶œ;žsL©ÑµwìµÀpžöÇOnö^Äk¤€’my=¿r:­'÷ÍòT`ÀïtL”m×MÀ pÆ m¹>úÉ›Îy(ÐºÚ ® ¢­üÅÑ~}²³MÛrŒÃ²Üú¬wùÔ@_ûÌëï[Ÿýv½e¬÷,ç‘ú^[ÚŽÉ‰Ï ʼK{÷mžŒ°õ8°Ë³ÖÏß»ÐÚç3„òüé0EÆQþCiƒ"ßÔmïP_“>PÚa LJµëØä¥ÃƯÑj§þrL=éßÉ›ÞíÊòÉúã»óœûÖØwbÖ Â7s2Ë+Ç9Y,𨠤SGøQA;¶OÑV€¾Ÿ¼mf¼èŠQ߈ȑ€>¾} #TLâª„Š¥z¼hîχ'}xÑ™¨_ë)GX}Èø2ukˆEG4. ^c– ×!9Dqñ·×wËÿ#k΄ãJ?l¤¯] ðõ §$.e¶k[S°Õªê>=êŽ)¶û!!¨Ó³<·c<=ØÀ+|S`SšQGƒ'ÒÎ3‰1+Ç%Û÷Ü0SÉwbÕòôr­Â{Û ⫇‡X×+<°¥ÕãÖ±ÏÄ´g–*–i76ݪ´áxFüÃøE¿µúp¯ØïÆnw‚Ý¡i€KΪxÿìŸÿ£4kyÄ7ôƒjÚš(>fñ9~hdÏdõÓO~bBN@£fÖ²}=É›xŒý,ºÖ¥”Rû¼¶Ï°`;+Tîµ&BÛKéeÌ/‘½R¢—·rÏ)ûCôŽôŠ9Ÿ–ö¤^+•½Æì,€ñ‘08/x^qÀ9 \Twå@=3毫¾^`Þ™íÔUXnÅ¢ã5OßpêX>fÄJ™8à{¤w¹EŽ´j¤{žmã¦ïÉìÿ¤«Û{žAK)î˜i…çäÀMŸ”µ‚óÔÇ{޺ƜãQ&)Ëv¥··.ƒÍ€ì ;`Ìz<äÛôBÙEݦçPNlgMÀ\ ÜtöXÎÔl7½SÚí9W–ßZõc>à í¢ÊnK;é¬ó½rp“Ïûr|±<èA<²‡½HcYTtÇŽ×;üô0±?ñµ–-0û½êÂ,ƳO÷IûÜ˨|Ð÷¶ì“}G@nýµ\@þŸîì+uxàÓoîŸãpôÌ71þ° Vì¾'\¶àïÚý°o)Ëg}“ËtwÂë<Ëhh≜ëï[*e ì@¯Ð1¡¦4†²zýK_O^rÞ7õÐÚׄ¢=ìcr1å|çÙãžý´ß’{Üwì𦬤dCijuØ ­Ÿð~§žc0¯øÎ¤O¹@zK¾a¤ ¨;=@þâ„÷GÇX¥ëùç»\¡Ö Öàùö?,ºØæßÞT0¶cŒ²ÿØY>N<ê(¾³ŽCâÖ)dŸŽå^tbÔ³¿B˜1[¬Ž•–±ô¯ýÆdÆ ?Å{žõ¤ÏM)Z2àŠrÇâ„b.k¼óV5Þ ¼ÌUë±›ÇÊ»×áÚÜNiuw v& P.v34¸w6/ÌDgwÓx»ÖKyÝ}8?ß)ð{Õa+L¶ÅyO=h"ý˜ƒû/ý žjÿ‡‰¾dÀ\é観ë"ÔO´Úöî›cO¿ .•SÜmR\Š·ù˜0à~æ·›W s†(}j»?J˜¦ì,„1Ô®A~/Åz¤dŸJ7_Ƽ|Æñªgùêv(¶/AåÙdF—8©)j²êë5?â°^õ£3?LÐßS–¾^Ó.–}Ð+- ”³ÎõCqå€t¥`™B3#¶ïì¾R¨?·Ïå1Ò­ÀùH¿zS:»ûó Ô}]ÏIöQq7×YÇÀñ°%,7=:»NžsÚ=Ý+·/yËhZë€pÀzûu=eãÇëñ²€Ôu×åQÏzÁx½nü¯< »YJ+¥Xs<â韲9ÎSO~l"o¨Çõì;ÛAoÞÇ1ÓgYÀöe½Œý°=à] °™e<Ùè©O)ë>òöztËÀÍÙ´Õ[?Ûñ ¯ãÞS—¾ñàwÛyŒEÅo®P^ëö½½Ÿ«ï¹Â;Byb2(t ¥Pë üé3áÅ>yê•“ýnR…Šcw ÀZ'¸F,úÔiX~õ[¥R ÎÌ -«îÞøõ„¹˜%Ä¡4~ïÄh#c½é}wÅ–ò»³RÌXöïN¿S±l§Øô÷•KýMÓa ¼“‰ƒúãûËŠÉÜÆ¨£#¬jŠ–bù¶ôõ=õÏ“¾€x¶åÛ˜úôç›9<éÉõûÚ1êЇ™ßôØJé6bÒûýÏòÇOn ¾ÃÎÓ8ãQ)îÓ’)&ó: êØ¨CÙ=F6Ö­ê>=éJ] K–Ÿ²¾À¹R³ 'N@öpR ˆ»g ãáíøÚ޶¬{üŽãŒñº1탪½÷dïXü§^1”m¼¦ÊO¬Ë4öôA¹¼i±7,koëØ~µÃªU¼ûÀ;gÙ˜:³¶{”×\i<ãxΕÛ|ï‚ñ™4u|ˆS.¥v ÊXg²³Ohh]&Ž\ª­›84@w<ßò‚õ•&&¸š*-e@v—;Ã_°®<±Yß(´£‡7‚P–¡´g0Å€ˆÕðœ;}Z 0>€yŒ¸ÆAsìÁ!F^žµMŠË‹tO_7‰rh ÿð§W¢‡þ/Ï”€{A¶rŽ—º‚Úx¸ ̳ÞåîCÆñèœ' :ÛŸíãÎË}›2×1ϵ€¹uë~íÎÁë=&Û«ïømÅ|Ø«¿Ïº¡N_³¸^ÚM‰”¿œ±é.üŠzçÅG_¡u,Tº¶®j2t >ûöuÖÕúŒ[ÿ’¬´Óƒæ~žªñ»émÿb¥ŒdÛ]¶m= ~f¼xKéåZ@Z<ó¦w;ú.“ò{À|úÕ[ŽxèÚ©O9zú ”W#eL.œ#s¬ì±~ÿºÞö¡çå}vØj¹Ëù€“µ]´wÖ)ѹ©Ç|ÑÜ©¯ „Ç©ÀºÒ°áxÈ:Ôw–5®r ¶‚õŽÁ~ñ‡3V‹Ó¥vRzyRÜkŽIOùÔÚXw[@^€nàý³Œ{Ó¯zM·\pÒõÂD·6¸7h¿”¬ ³\å0`MXɯP½¶ª¸w(Þ´–sÜ»MxH{X0§žÕucVp7Fºrø@Ÿ5ç´§o1*îWÎ}>w \çRícæAá®åìAâ&^Û¸?¢Lè÷9Ú¹NÄÛæ ˜é8Ù¿gŠP~ß…2`6úYpoú! ·QlÔ1¹û—oÚb¼¨õO¿‚ô®7¦ýh]ÖþáÇÒ¯JÓJ 83ÅxÍS§¢Ù6m¡² ÀW°%ûkìiPª¶ %-‚/P× ÖÇr•\g [½ä÷ñéÌÂ+—yÛÆà e o9^òÖÈJI“} ¯xûÄkžú `²ÜöízÄcÓ;®t:õ 3hCä­JíÌ…®[ƒ¹´ÅHùƒ½Œ7=mP2³<œ©‡Ún/úð*i+eê ±¯ãHʶö[ŠzuÅÅÖÒ‡êz€@âˇ>Dᤎ¾rOg›®+v¼ÞÄ¿}ðLÊ“ °‚NÝv‰âNÚ2êÒÝÚ‘¬ ˆ*n;WýY`¼â½ ß ï5tó¯c¥¨ÛîcÊåÅø?¼ßL˜_àÞeú“žr à¡ÕûÞv‚{Ýó_âyãPàyN7؃üõìöù‚} ðŽ×\yó ÄIëGn|wÀ< ´„¶ëØ©£\X†%Ãd\'êÀY¨¨#D‰‘ª-ŒˆÉåõeûçx;ï63m[ÊåqÇÞÒ¤«,XÏ„(ôw€xÙPäQGTl)³¯êLò®þ¥»Ç˜Pƻެ" Íb":̱.Cƒ'ü pΤ¸2¢ä»ÝúßÀ†[Ë–†LÁ{ÚPtŸ–úLÞW³¦cŒ†Ó¥¾c²+ˆÇa‡C€5t÷¥ðîÔk¨¾SÂP±é±.§­ =LÉʯ(Û˜ãQÇ ð³¢‡ÐÚSmÐ6Ù”5›Á7F<Þà’ÍöÐö‡ãK˜ÉX ³gyª”›Q<1®ñ¥ï=ŠóÂ>“z?Û¼¬Ð^õãxÖF䨳v„3³î•âêÅ0VÀíÀ®ºp”¢[̇ƒv.L?€o:<|ÝØÚüC(9¶Ó Öïb»« 'ñ‡Ôÿí!\aÕ>  å\óg*k€óøŸÅ°,ÀÍ9ö>Êã,úˆ…,ál_áØ ‹èqÞª¹r)Úeè2¼DzíÝýcß qP< ÷™¸óÆžÇó½–õÎ˺ÂoŠašôzϱGîØó€p¨^ÌOåÓ´ÏÙf”ßM#Ë~´Žk@ø¢·ŸzÒ¡ª›ײò1‹_ .¼æpLUöU6åÌÑµÛÆï¥Ì~¤Ž{s¾Òá8uŽÁyê2ð©Ñ>±é ÒPpÇ“ÞÁ!Km¦³×;¾hðxÇQn_ƒVèëï,gÐ ­ôèkš©¨¬Ù†6é˜<(¯8ÊÒÍÏÜ8òÆ»n©ëé¤FƒÖ.O¢Á‹@JÓ“¡¼-¥ïù¡&Û§/óë>ŽSŒš†þÛç·­7(Å«°7Eݶγôñ‚Ô±ýŒ9ø|3àæþð‚w]TôïÇ9*¶]¢rŽSÌ€åɯ~³Þõl£ûÓvúùú8ÆÿxáYŽzý¼ÿö¢ã=ß?_Ïí¼Mûݵ˜ó”͵¯¼ëηϦ9ÿW8Ç[èëf¸b‚œ6â¡®ö"ÑÈ“ÞwÇШPFˆXßM}wU¨2ë¼»ð¸ˆúä¦ïA{Õ7¡ASÛvTx{ÕK}W®g;iw)ÔuÇÞS–ÕÆ±7ÜÌâu8£}=W‡ˆï…ÎGJÓùÀ­—ÇøtÖ…X _¤S¦Ùx“q“2’‡0}¡bøGÖûÈqí$®¿Â£Í6м÷q)ôÑLî”±¯÷¯ŠêÊ‹.¾g_|?­@Œ8÷³ýd=‡–PYØß¨ßüþ¢Ô{6ðòdƒ' Àc·ƒ®$[¢!1á¾yu„á$±=#þ©T÷¿Ç ² Ôû"‡9Ö:¼éY¯çÏø°Ô¥v(íäC•Þt÷~ %—’v(ïxÉ—¡È>©íå¤ICô¯ËCî4ÀÓ·À·ƒÊžõ 0À{="€îÃâÕ@ìvqŸ7ÆœÁ ËgöåuR i`Éà“ºÎ÷töcbÏiË€¹ôVyº†Gsz)¨»1˜GEz¬O¸U¸(]xÆÖŒg»b㥌]¯bêñfÆk€ƒz u}—¼bs©«gtÆ\ë)KÏq´Q.—¥¯¼ÏVM¯ú¹º¶Íñ£2 ­µDuØeQ-H¯kˆé\R‡žvsú ¯7ûdmm=g‹áé>s_ âëڸ漢©ð½cð¿©ã4‰p¯øöÒâEפ& Ò·ÿ‡¦eƒòŽp}Ö‘öæ®õ. ÷äu¥ºŒSjùýT{wж“Üéxöçd™È{`Nuø„‘Ñï&ÙmSøu ÃÞtTÝñ¬Ë{¤D$n9!¨ WLyAyÇ>#¥´]&͇’–  >Y‘-k+2.L^ïŸR€.ûj›w«A¥ðW…žñ7œ^²p–Û<ÇÂñޏ ¦`xfnoOüØàFpŒœÝN1ØÂ£Ý_'#ÒNaØlãk¥ÎÎLÚÔkÉež˜¿7¦2ÀÉ`&í1X:Ö+ רòô¯  |‚phŽxQ¤‘ÆgÐ'?_tsÅ=žÅO†š X'0ý¦â:ËpÀ¹ÛëÉ’]H›6èë,+?³h³¨´cM&úù´ô+ø V÷,‡¹©æNEæ³w›ûñ̓bN,6×Þè´ÖÕÎ~ñ̇êºéÜÃ)G¼ùo/Ÿºá9^6„ÛVÛÜvz ÎÓ^q7ìÀ-¯¶ãÄäuŒzØ_¼M;@Ü^oÌuœ'”öžŸÒȉæO_&èíØ +`⇰‡;Q<zÛìJÅ'º|ÀyúhO¿þ¢£Þÿ+¼òk?Ê·~=×÷†‚|–?{òú„Ï Á\ƒ€ûÈaA¹¼ÛÒ·a9µÓô9éy:ÑY/¹&POs§³žïHó£Ë>¹ºY¡N„AÅŸBH®^õäP¿oCå= \ ïÆÁ|ßçNoXØ›ñÍ,`o´÷zÅGö”Átó÷]ß}yÍÖÉ“>¬õƒD.˲Œe¤¥{ðÌÖØê‰Eu1@ùßýþ‡€ñŒËÎR°ÅÑRÇ‹²ótüc’˜ó˜ó¤k .°-‚dn·'y‚YÙb z{lÌ x‚ÉôdÀ¸qèºû ð–7Ýýñ|{Ÿ¶»ú^+m\ã2êÒ×缿—;JûY‚r¾×sN½Bæ¶LüÐO¹bÑy>54Ó»!^˜úè“N@¼ Oº'Ì ÌMƒ'úÒˆy’CýzÙ á=D¶‰ÕÿÓo_gYl ŸŽ}vuSïy…6«å‘º¾ƒ±j¼THRÞõ}ßüéeGÁ¦Ù=bý†”þ¾<ãäE—)^}ŠÆ ¤w²õw(IÆ7ö4ýÚ]xÚú^·L¼é _{¦´ª qƒX¯9ljûÐhã „¯åÕ9ñ^wŧcMã–¾¨Á‹æÎúãÍØ“åŒO»>•݇#gxÒŸÞâBÍElñTÕ[2îðXÙahVÀo,ÛnS_é\ähdâá4 Óœ€ðdôu{¥À”^ `œ{¬”Ô{|ä~ž`®Õñº¾q¾vÝlî íÎy.,,LÞ¾„›Pq'¶üv÷pñ nfFPÃs'Nì·¯éyXfLó•f0Óµ¹Þ–ÜîRp|{Õi7;Á¹{]ô¡M¹û2â!ªøû»ýþ³êš>-1C}öåÙõqò››ÖÎÌj,/u ‘d†¶uµ| ÈÓV@¾N²>@ú»Ø ¯‹öÅrã¹,Ì’¶¬ç|rß¼ÊÇÕv<ççñ¨+Ö|ò•µ9R‰Yãcžy€ùÊ‡Þ¾âæ¬Ú~ôëúbðXf°Âz=ÍkÞTiÐ ­¬{FU$Ç•}c„Cp(ƒCõn§?tL{xV¬¥zÖʸâ‰Bði5‰Â@ˆxSòg^·öË>F¶iéÓ[ï{© <îÝ>gÚ è§tœë11'øÝy^ëÿäÉ) ÕÅüÿÊvúÿ5†}ýçˆOoÉö¦µ3i×òýJŸHŽõâÒyáUç]”¶)@×÷àÁ@^ùÕÃ.ºzs?!YzûPy¯áiïä+"q}w3Éêw}¾áLìâE—As_iÙÂú:ÓBá›5C¶š‘$uç¡ÝãYùÑ[*N=€mDâ¾ñ¨óýÎd;JïU]éÙ’}„Α &õðuì„m±³p¿ ̇ãbc­zÕ“Rm0Åz¼Ã-kò¾­Ë¿ˆS0ãXÄâ2Î$&ýé¢Îg}làf 9žfá(¥B¦M±×—EÍöÞXc2á ‚í4CëËŽN;üÌ|´tÝ0AL¡¹Á{r":†½×PvðÓ6wúì›sÕ96V¿÷¦zn°¦2dŸÞ>YÞ•S7“,ƒ¡>Ÿ™zЙ1Ú;ÉÉè)Ùº¬±jG–Þ7“ãðu;›g…°¦(û!¼RL…€o'  B ‘¹>ý!^Ý»‰_r©ë£¦/€ßúöÝSdëZÎóÕÜô!çÊç%Ê21C¹þWJ§VE÷¼ ó¢/h@x—[6­ZJfqs_È¡¸W±=”vͯ~©“ Á·ùqëá–_/š”PÛê=Ûý‰Mãlûéï|äñ”—F×u Ä™§,0ßx͈0 !—ìÇÇï”2´ÀªåÞÑôÞLš;ô”€r{ÕSZù÷elxÏGÜy)“Ó[³(ì ?ùÙÿ¤­WÜhywö^$Ýw±æÊk¾Ëï" ‡ª:±¥æi;„#e𤡧gžúQ×õxÈcuë] MUuÀŸiËäßNÓ€µ Ð}¸îæ¿ ±ëòÔ:vÝ0>šÚÞ œÒÀ±ç˜ýÄþñßÚ'&ZzÚcݾû¯—í9wõ[çŒÇ½÷áb\ùóÛp¶ñvç\§ëbówÜ3Ì8oGMŸT{R°g‚§Z“Î^€ÝœýB4êÌó¿¸ÛG'Ë À“5a°^Ž~¤rÔ÷RÛ™ÈË»ˆe27 &NÁô Ã×F,ºë—þ]—Õ&}ŽŠÇ}™ï@ä·7}ך]¾ïu4Eœ}°ŽxœèîŠU‡¡5ãÓ ÈÑC™žt„äò-\€» º oãø¦n,JrfK=VåˆÂæØkÒ¾‚qթɸ%÷š±”÷ÁÚK‰áL +‡zs¥£ÔÞð¾0+&×ðÀêøÔ’±WÚÚŽ€œEäbͺÃ8P1é·-KwÇÁƒÊû™íY¨6gOïlèÏ80ë8´œ¾”šf¾w¶y¬.5ûz½SæüÀà'€²)â¨Û£-geLbl{ü)<¢kò= 4Øfhwà–bFMÖÔ„}g›=Fƒ.?÷?z:œüÈ;JAM [^ÐÍy¼™™?6 —´^îÇì‰Àô%ÊHï…îCLç;[×?™î…â6€íuêú²^ª" šÁÚYãâsßèN™öÎôèAÑ1.·[C€ml«°„ñ‚̶ x·^0T§ÚÌ­Ùr*„Îôic&wPÛ­æÞjä6'õÈœ]~6×™‘æãˆ­¶!Þ¯úŸ^”ãEWìÙáIÏÇyÐÙ;¯=b6RePŸ"6oë%¨r-@=íä<ï2ÔÁ;°Sµö‚sÇ™“Ã<ƒ¤,;–pŌ׋âØòu î V¢ÎþOzŠ3§¹r £Ú>úP’£8ë¤Y³ )—ÝS½•vÜ9OâÉm€ïƬ˛§xX@7Þ@À‡<‰NQ5û-÷ÛzOKEÆs.@)º<¨Ý'éш3’vM ÷lð'`¿”ÐßRÏ5¤¾}“œó, N™~kùh_}VÝ¿²~”ôa}Åv¿¸Íñ³žmV h¯±?€¼êºïX·ïù·=õc½×î{Ðßð_1ó¦Ü¿O|÷7îñOo6à<¦Xø<«1ίÝ)àb]ž@}zÿ7ùû%z¸é§¾gêð²^D€oÞÒ£xüäf¤kÃd¤gÄk>ÞO­œ4xô5Ví'w‰pŽ#±˜CªÒ{€y¿(ÁcäxÕ;!üÉ“©¿÷Û¥¸t<è3{ `Îr¾™ ùB$.,´Û†”‘O”mšTÿè˜_YWê÷%@½^õçt²V^–e É+½š;¢q,?E,.õäJ—h\)탙ˆCd°ç.:&6e—˼,€ïxqaB(å:k–VRëë”–®ñ‹)ã»ô^±gÅó84Ùàì>Žƒñ¡ñÚŽN®4×êgç䜔À)Ùs*› ýt.RÅO©ûgg¦™2ŽÅ¹:]ñÿûiðŽâä‹5©P!Áz˜¬ªí‹óì ”ð´ûâ|1€6Ý\<¼­¦Á·$-YXRšýý‰¢ <íÝúùïMäg¿ûÁ1â¬ãE'Î]ñâ3.~äBDùû®Øy 4~Ÿ õãþÜ/#\á4iÙß°®&9-lÁ~971.¦hG /zmÌ–Æú"nzãÏ7/õ[Î:R§ A”µÕgÆ—›Â~¯îHG¡=q_‰çêÇòÑÒ,vs›¯¹s¡–Înõ»)@A]ò&¥ãÎsbë,”ƒHÀ¼†ÈŽè‚UÌ%]Ž} ·§ý¸Ö£=ä-Ì€+èÆyKi;§©“ZèeÊe¦¶— ŠàÒÄ–º~¿}Ávê º ȧ·+PÄ¡+þ< ½4Ø9x/ 7ñ.§O•£S_o`Â" …Xr<÷mo=@‰4Z›8b€ûh“[JçJIfår¡)è©›rŸ7ë˜hçõJó] w€WÀõÝ2 üåÛ”].ÈÆzŒôdÇvÇ9âÃoé  Nßœ{€{—gŸ˱Û°~Í9~þíëÔsNÒ»¨ ν½Ø¢ªÐ·Â4#qÿÏiC¥bð=ê屮ÛÃ>Ju<ìŽE'T¥åú/7êvÊîžðƒò>ë€ó¼·sŸÞ¤l¾t…û\°{é~|q9ú*mc ÐûM¬×«ð¶èhê§®É Ýañͬ³\zs¯À8±!ò]¬¢tjŽ{¿…bŽcwRáa$£äþdãUï½%–_BæJÝm|¨¾Ô¡ŸåÞÏìÇ}ƹ)¹*î{Î>^^‰ìdõ× àÇÊòæ‚•ª`Ÿ®Àm \mŽ×ñeŽ­à„=°a°—˜s ÀÁ€b¡˜úÎ ][P:¥(Ðï¶Ѿš5ÅBŽX×1¯¾^”¤UéÖæ )ëÄž“noyfDÿ›³3ݱä8®0ư!‰Zl‘Ö òë°µÀ¦Ø³ˆCJ–ŸÌrzzH>‘ëtÌÁ‡ÀשkøG «2³Ö[·*OƉ¿{Ýçð“ØlZà Nˆ3wzµ§ãÍ6mQ×I¶(Ž1yÎ+ôV¯y„Þ–G†A`½?²ÄÓfñ·ÆcšŠ‚2mKgù߸^6ƒq{ÈK…%ÏrÊÒÍ% (8·+uZ=–öŠ ‘O[âc”Ä“úlƒcëÕg¼ÑŠ_U]^Þ£‚zrÁ>`¹ä¬hñpc¡³¾=ÏÔØSŸå”Ý_ÕÒÙoy-}“†-õû€þ‚ûµÝöžs¯³ÜãwB¢ e<ö9oßΗ‰®»×é¸ûa”1³èÔ“9ÍÏòŸ­w€ºü·¦ÛlÕ°O¦ÌDb‰ïÍí¿CEì=Ÿ~Š]¿hòü÷÷û€‰¾Ä¥Å#&wšLò>ûfçOg›IÄ.Ã"&}Ot2¡9í€òõa;fÔÉÕ–1xå‹Þº Ì.uÕ•­õTÎô´Mÿñùž!vZã›·&±¡·WT®‚©ì™ï·8mýö*[Ê|»eÐÝŸWHޱÁaß-šûØ¢´N€ybÔ›;½L¾RâÌQxŸ±S¬õPÙcé)Wœº…â›Å,gá¸dÚYâqJ±û {âÛ³¼Ä‡'W:cOƸòL kˆõ;bØo[÷7_>åQ]ô$lžr<üßu¿'/7NXpûÇ+ (.°;8MãÃq RkN‰¶ÙJG¦û0ml«ð„³ÉÑØ²éµ»?ôÐδõ,3²Ý1˜M¢éèw›6`½ÄÞy,ïÒ7½`s÷÷3=Á›=µ¦}ØöÀâ ·ßú ­Ù‘¿ù—ÿ¾-è€ÛžtÀ®gq`ÄNÒúã´ôäÂùúÏqç~<¶i>ïÒÙë)O93™Ë£Þí€ñù.cÍÙXó÷åÄ—÷åíaæŠûU·>¥±;Zú•®…";Tv*î|ôrÌùHÚä1½[ñeÓÖ´+¡Ä=(F­öÀ}„hò‘Œ€ Q“…â~}«Šl€wx+Áíúñã Ï€¨ôö‚$è[iÔL_Œ ¬§?€{ð ú‚s¬ãÄI®rÀ´(íÐ5;HÇÛôÑ7Úk^ÞAs©ëõR·~yì1Q`éƒG}¼èS#eÃíñÆ£2ž:rPS_ðŒ˜*åm_BpÔ8³/ƒæÒÙ³ÿ`€Õl«mæ ¼Š žmäÁ¦´:û[eéâxÍSÇñº›rÝšõob¡´°í-gß”]¦àû+@ùiŸÝkYÛ@½÷¹¤÷nŸÁö6éàe'üÀì‰ÆØkbȱçÏŽ@!Qæe}–©Ù\—cöÃ7«°’@\ñéI7{Uø«Tø œêdðŽ5wâÒ§\’³L{ o:ýóN…]”m%¾wÂÚJ{,é+3¹Z±9bÒ‡¢Þwëvl:ßúÙÌâjL:%é×.º|ê¥Ór±¾î+¨ª00¼å¤;N=m|ãñ¨€6x—FM™xÇåܘè”?zÈbK¬vÆ:xÍÊ»~²²¿ÿï_”wüTg?Ïé±a¾=¤YÛâqß‹°ðdâÉ1@_!ÏÞu Yºûx̯º˜2ÁÛXZM`ÆùÛA(Q°5þ/Ps|xëaÀr<Ž!&ôÃi\~ú×ì\áË™ˆ°[L܃ߨa³”©«¸ŠI@,Ç£·;/]°ƒÚ:àß¡ÚÛÓÎùÍñ¸ë>×ñ*üŵæ~ûÞtÛƒÐöþѹåÁŸÕ9¡¹Aœ8…Öáüç±µýÔ+ç:ëôõ 5¸Þçdh°ÉŒÌ~@œoÏ`Ú?ô­˜v?8¦·ô~^Át ­ó‡R¼üYeÑT•ôÑÄ‹¯éFnõ;?”}6Ö<%ÞóØˆ€|ç7¯@KýJÇñÃå©ïÌî´1cÛ2¶ûl/EöGÚÕPÖSçx,hìÛH¥668©¶×VŒyÎë÷¥ª¤ã©ó‚ôÖoõXÏÐ×:ÃÊ}y¦¤n éŒ;Ô?<æÓ¯tÄ”“æ&÷GO›©c5Û¡ÒПõÞiË )uiŸº¡“€£Ø=à:}MÉì€2}R¶.@;u¬h3P…"`¿;‚M œ‰UZ¤Ec%ç‹8r줈#8…Ò4xSn¿ÊµÜÝ(`ܲ!Ô`àOz€O€ŒrYŸcŠËs\9íëí›óAÔ,ËÄkGuƒRÀt–^Ë¡`к@?}Ö2`?ÇYÀºçªýä©sŒyA¹½èÞ_Ì÷¹Ïð³-÷…öl·bçñ¨7d€kÎ=jÿzÀ9'ô¥¼Àg2ÆCš¸-ˆÇ³•²ž÷†rä¹NÙý¬ÿÕ¯\ù_Ñ~Îx°UâG0.^ò¥ùÀ\*ñ SŸw"sšÄÄÚ¿Ù?ŽC_ñë˜2]H<N›€ú£ò{½éÑ É7㓯êMßßk’¬ê‹¿X['1R(íŒËòšˆn8žô‚sXi+WºÒ™ì–'=c†²æâ¥[3Ì»ú{ê3–ˆÈ\Jtq ÎëU¯=f ^ðž1Øï¿¢ž±SÄr×8*c«ï^c»¬xm³³ä(Û¦¸ÌSWv$uPÞÏ6‚–îQ=„Yg@K.€à–7{9ÛÝö> <7/¸öMÙØxa390­¬n#æ¹ë y¾-²­¾¨¡ƒÕïdœ}-3™½Žéœ ŽlhCúô…™Ìð½ðÄŽ±çíóÿ@L™î‰pžqlxýhã!á‡òÎ8ÂÑǸ;Vê*‚€eŽyÇjÓÃKûùÁôŸÐæm{Ý]Þ?0möü[pÂìOvX=ñ< Ô¨9j2$mЇA°aýÉDmO‰×|f5;Š\(ë_ÎËõZO[Àw½æVýœ%‰Â ðæƒ 8tRƒT¤¤9=SÎŒð}¨†{§8ô¯êwµ¤Vk==à» >@}>Ul­½œ`K߬= »½ÅCŽ8\Ú Ô º‰Ÿc¶ß9^³<”SŒyêg»¡»¯¼åJyÃà)¥ô‰§ú:yÌ­Üû Ê"€º¤|[Ô̓ÇåEÇsžeêMõÄ£¤ö€mÑIS‡güÛ¶aˆEÙ;6ÕÆ1¼çË—xï´¥üÕm/úx§®ÞÁÒ{•‚«å/ím\Â\€ ƒkê É+uýë%ULò€Úœ/ýsL€öŠÛ–÷¼ç°<ÎÈ®öŸ?»Ÿeúôx²Uïý4(³>”yhþÐè ÆÛæcûø½.õùõ_¨#~m»')|ÍÞîepÿ=àk·ðÝ-µxM渤¿×û;J´0õósRÉMIR·ñ¤/€Ÿ[`¼ÛuRõ÷Š@Vðq3m¦M¡4]GóBímsÈÎ7õ–Ðy7ö}Ç$çå¬c´ëÝý¼¯¸ôˆÆˆ?ßú$™x/0Ï7 ±8l¾GëÛ–ü º{ãÔQ~/{- îréÁ¤ì¤|,ËèÊìê1˜x/gŒÚ{Ú˜]TxÄkYÞ(wvÆ@±  'ë€ñPÚ±gŒI+Gܸ@ØÙñfáë³¶cµw:cÈÚ^JãÔŸ”Ð¥ku`ä˜)…%tLÉa sýÅë:ÁgiӲέáÓV¶ß¶Ï±m÷s=8fý£ŸYiê8Ÿ†(Ûø;ä˜ë7™âî ´9ÆØIà·€\ÁóØÑã{H䀴åîÁ-+ Ðó=‚}ؤtï?•rêzçGÙ/úêG>æ^ä¾ Îvƒ°‚>ªõ-Þv'õ},£¯‡ÓfeE”4ç¸ëÀVì¹í»×ï7/Ûˆ4þ18}fm³¼û¢·/ÅQ¹âÑñŒO|yh\Y¸Ç³®œ¨c´bÌ Ôik\ºÒ§ññž¶¥KÎÕÃl=3ý¥ß},UÚohì3XA(ÇÔö剨Õ3î´7¡©?Ú€mñáYo{q¦­C›\±ŒßI >Jï4*ˆ “N½cÉ\WømyÊs¬ä0f èÎ`@¾èî»Î^r{êähSÌ-Àøë‰Ð^oy­ëépRú{úVt §„ÁV¼ñ9Õñç€Öé Ãì)Æ·mp‹ÙÛ°[Ú¶×мö ›sn¼z©÷¿N[lõ}œ€˜úkmzß—ºû ð~×ñS®~9·Ã>V¶Ï2Luÿð  h„§Íõ¬³Çó?åõo›ãï­߸ý6qô”gõx¥êS®uŒç”‰(Dy~ ¼¥>ëv{γò°×ödÝ/&æVMÊõy‡,Š<¦÷¬E§ûfý¼1瞨 WYþù„ṳ̂çà ¤W NïóÐÞS~tmÀ;êîµ~;Ø¡¼cį÷ÛÄäñGw÷O ËåÛ6%iØú TJѲÉQ%%锨»CiwØYE\cßÿíë.#w7ªí+5Û0ïPïØ!õKϦczÌ­‹3À|öÍ$åÚê[½…÷é0 å=v­g¬µs¤oO:sÆ|]þîu 䗷ܬËôÙ¢Y'½¹Ò%‚;(w+\T´îÍ&…,ü!GÝx×}Lœ’´•n (ôwìov3us‡ë~H_Ì”|°uÂ9/X Ê ŽÃ–øíSÊçcx®³gyY¬`4Âä(u?ëÀqßy‚€xö ˜:î¼Ø·i ZW€üí›%º¼û¯eÓLý¾‘«N³b­sì„s!Æ|}ûAóƒå{ü$KÁÛè~Ú‹~p¡Í[ýÝœ<‰º§Çe^D­`ÀKÎóìsŒ¬[üÍjíÛcþü!”øyaO.ôÆ#¡æšÕŽ?Oû|* ·…M2ë›ÙÞ¦VRâ®DkG ŽeçÅ~ô‡ûù8öÊÇ“:âǪÖZNÌy洆 Å<Ƈþãæ;f@Þ™þ% ·½ä  z‹%Ÿë›¡ BiÇF„‡AÏxÛ•¿|­Ë–%¶€i€: ¼±Œ¦\zP8À\±“ÒQfÇÒÖ>­Ãó4ƒPÑGñZɶç˱§›ž>æÐ ˜×Tï:Åè–Êïx–Q`Ø4uâÒGJëGÚ°…àz|¼æïÔÙc+ÅñlG=BoöZÓ.úöxÖÕ7 sƒkö—ú€ä€Ý@À½,ÇiÙ>± ®SÎùÎS'Ð Ðö:Ëz»=~õ—ûZÏìÓPôÃ^FÀâò›E0ö…DéÙƒ= üì³D¦­§u6§êã™ÖvKDñ} &*´ƒÿ!ÞsQÜÿ„-@¯t‰öœ)ÇzEåBaˆP],û±|ëDugÂsyÓkzWr¥gB”ý¤$nRñé®$µ÷óNêÆRSîô5q|ˆU˜Æ›¾Âº°“^ãû^Ìm¶¨_åÒ~ql:t–çûŽlöîŒÆeå¥,#OÙ`Žš8) ÇÃs~÷P€>àæ`EåF·ç ÞðhÜJw;Z@+·úVu°hêîñ¬¸Û“Ž`Ü­4«³^Ï–òJ—ºS8e; mNív[ÜÙàzÛÓuö›N50¶r¹gùˆ90úÒ¦ý# v¼n³œo‹…ó¥Û£NÌ»ûß éíúõl789Jy‰•§Ï)¹ì²à–æ\¬hðÐÐy°t¡6onÛ|ƒ¤ÿ¡¯q{ëió¬—A´ïé$‘tm°ˆ³w~EÅ·¤Ÿâ`¶)Yþ‘jƒ:£îÃÿïÞ;Î¥×.=‚¦@pš‹Šë ¦<ç¶Ò¿3³¦±H¾!Í Þ<æ)±y‘œAíʇ¦±ç‰›:(ìË^¾Ã“Þ4(Ÿ¼IY„àbôúÚ¡´Û®¶;¨ì¥Ì} PG .€¥ÈžöÔ ¸3¸È9ßÝwð‘B˪¸Ç£PÑ7J¼òœw°S ¿àäõB;†Âor›· }{ÈJÔ?+é†2x4…3Ç®Øî·®Ì/a'‰¿M»A;žðí_õ*·vo[ú6þvy z¾–M_'_vÁMê S³/ ¡nP½iè6í£pÀüÚoÞZÀõx Àù²åín®púȪÅß¹Ÿ±Ùõ³Ýç]¾îÛß-ß²@=åòòÛ#ߺ”µü0 Äèïj1:ö/_<ÄÓ×¢~££ýîñnGÔðÏ¢p“úÎrÿô'üƒýÂi=¾b‹Ùõña³8s´#2£^a0¨½¸ÿr³q$2 08çݶ=êRz§T¬úÖéÈúΖÁ;x@6ïbºÍÖxs§ãÜ¡R0µ˜4^ÞóK™gr¹ß5¨íUv'}hê¬#&7mhÍv›™V9ÌÀœo:¾±é¢½ÿàw_ÖÛ¶BqÛ1Â8 R>9n‰eÜ’>Y¶£bƒ÷Œ‹"ŽKÈàz>ÏVêÚÖÁn´Ò{)î- g,£òrä¼âNcå:œŒ ð˜0ÙªHÏf¥™¬Ž6u_;eeÆ ÇÜðú+¤×¸Ì1éf9ßÕ%õ´îíì‹4ÚÒf…sßMõG¬ãûúÌð¶9mwÌ÷Jÿº×xæÁ9´ÏöÁê©æÁäêåæv_•ξbAÂj]®_J?øéÚhó½0E\)ϬãÁWþÖ!BáX•ƒ}j’â¦IÐÁ×ãY$çD\ô|ÎÙàôó>?­G®q t4þGùÌ×zÛKorÜùÐßï ´+§fÀ8uÄïTjC¡b&7³¼ˆ¢œÙ,7v«¹B¯eÅ G}f®_`ˆ¶Ä¤ÖªõzÕ‰9·ì‡=Ç[ʱˆÀ9Þà-Êž=èÈé …ø¼,ïüæõžË«±DábG/0Ï:±åP3 ðÞžô‚n”اdÐgÊ{iì (»^OúR*¶Ç¼tÑ ~ܺTõ/F™9V•æSbOö¤5-Úò’h쀧2; RIaN}¦üâÔw¿·•vÌþÏñßé_A4‹\áé¶È}g¢h* ¼1úxç:Ïùø£Û,€÷àAß}h?oâÑéSøÔ³½Ï¥ûnÃd¦ýìÉ,×/j¿XÞ7´~<åý=-"‡È_'²îøw{ÖÛóŒJ|0¥u¦­Æÿ†ìÔQ²Ìy×±÷.ï¹€{s¤×³¾½ìäK_“žÔ·þÈzþ6¥Í^óXHמøäÜRŒ§“¨Ü?ÞÝ oöŽ9†€{ÊÉö‘˜ô‰MOº6ò¦ë{Ô<é)³]X^)É@P„{ÂCÃegI± î3‹º¦Œ•Wfܨ·/Zû¢»œg9â±Òk+ýÚ®ßF:áy0­î^Ð^€XÇ0ô}Ʊr/5vÃ.§È[ k,8ãÅ–äEw¾ti!ÉÒ~küH5ãy4¹Î™ŽN 0Zmòj»Ý@ær=êM¯¦|ä1íŸÜÝšÊU7Wa¿„;ÛÔv²2}̪…·Û}À5‰ïû¤TãO2H!¾h÷º§šˆáyÒ=ú ÷ÆBFµ€ÊÍÙ ZJ|ž©°·Ý`ÕÞõš„Ú²ÏE  œÎ«õöŸéüY§?Ôðp(ÿ[Âk½.î—g­¹Ž]'õ‚ÿ¼(⟮ÕmžrßÛ¿£i7(cŠÞþHyŸvTÙ÷(85‡eôÔ]ë({náñšCmÿÁxÏ­J©Ó†ž 0ßž;ã}Ú2)«»¿Ù[¯¾xÂw¬¸ÀµÔÓÛ¾ûÂæØ€ðxQ‰±n €µH±ßk³Á´bÎë]î>´lßãþó]ëWÿ”Ø\c—óûÍòÙS÷Ÿ³íäm(Ȳ-”vê6ˆ³`ݪÃÓŸknÚ7&“Ϲ7'{ûú#\7ÏE&-†™A»ùÊõvÎCÏ<Lç ½u.·|Mý È³Üm Á+V]1êñäÚ×{Æ!5¼“2٘㌇ü¡ËäO·<å§þÓë=>uÓgÚ–½¬&Þé)_<ÈÃnÕŠ[g™p©ï|?ê=hoÆ&‰ñ”§<–íRÀK,nõ™4Ÿ¶;2­è»œ2ßöóÝïä{Ö•}êöD>žôŠÈ¥nÒ³䳜±ƒÀyS¯eyyË·½éckÊM9!€Yž´²±° ³ŸŽ·l3ö S1ý&Wú€ìMy>qí gD,0þá(¼“ÉÇ"q)m+úVyoˆ&8eê¾€} †2VÚi“7Íûì·ÙÛ;÷)>Q:mLÇ ‚¢¼c¸ëý=ÓÒí眩3 }B þí5÷Òô÷´ëúoà­7¥Üž€YçfLfzýY?­xûŽ4ÞÚŽ¾N³H5XÜJyGp{ûâÇÉ…+Æzí; `¸ºPÝd?Œ¹ÎKy磿c Èá~3ßíþñ [˜A|ìFJÑaÔ®¼ëjCâX'±Œ>¸úÃÓ#•ö”îXÂp¤VãEºÓ§ÌÏ:t¦ÅÝNÝ…Jjí¤éL/(쳌RéØU?)Óî·R;²èŽ+O~óñRÎø¨Ž  ]S×òáÎöã‡ö¦jXÚ4sßÜç´áÀ0ûn]–·¨Ž…u "Ä#1¸î¼?‚nºR8§.¥t¯Xþ8“ƒÁÜ¥¯€ù¶æ6ÇfзAyËù…Û6V@_ùŠcPÝñt ­xr<å‡ÔhÉ}þì­=æ îñÜáI§ê»ãrÛ÷:æýn³:»Ý  Pý¶’wÚ•wÊzõG¯2ÀÔf ¾<Á´ÍzMàÚï^_Àñ´ÿé[ø_˜³°Ž 8Ïù¦Oû ¨S—óÌ=c죠½F?ï/å:‡²tÿr\êJ{oÀ\€›u¨ðbdû‚÷”­ëoªßLyç_‘^iö¶˜Äê”VN µo-&Gœú,Ã.AdñÏÛ‹¾ÿ‡GVKL §mÓD]m@;ïŸ?p®p›æEß9Ô ÌÛ¯%Jîb%œcëÝ›‰Ø{³Ì|ŠI nBœ¾A“ÖUl‡P!G¨mˆÈY;¥&ê;ÜI[úö²‡,?åE9-êïËõ¦+ï;¶=éäFÏzÎc4l Ö%§õ¿_9Ò'Lï{¿}åæJ'„-ÛâÀ Žqc®dÊ©=%¡ŠXÂëQ§D0®žózÒŸ\ãKAéÛ¸õa×þîË£7ýûŒ_o€@çC ö»œ'°{SZfá x ¢ÁæÂ>€V×·`œcæ}œžì7nöú†Å­°kãC©ª{ÿŸ nøqªÊÖõCžRÒ}Àl I\‚DáÎTƒehó~HRAµMðÃÞ™ñù5sÔ’¼æ˜–ÿúŒ“h ‹’À}º1;ã\yŠI?›é˜¯oçŸ'=bfAЇ?¿~g_ô’Xg—ä-·Æmä±ìËVö\ô¥”OtÔA‰;¨ÏÇ"ñG¿ÿ2u7¯iUJ·b{×ãå&V+DU^Œ}{¹Ò›ûEÚ´€ñ|¿ïÐò¿X¿£óÝÄmÎÃþ”rÿiBJZ ­Äë¿2ý˜ »´"îÃt!…ÿiAüJÓ61ç×ïRÖÆS‡€ä,‡Y0¼¨îó^Ò2a7é»3R˜î>Ûå}“7}B‰xÇÂ\bzÅãÊzJª6+Ág>ýÈîƒê.Z{꬇òªmï è%rúÿñpÎw° >ßNBÃ(ó-¥ïRyßà|øÆ™€p/g¼àå:Òµ”w¬ëã-Çö:lÁÚ0 Ê“IgçN1㥎Ūø¾(ïŸl¯yAûŒ×¾ª‡=Ƹ›ã×AT`îpÊì—~0?³ý´Õ‹Þz;áL¥ïì§°^©ôN:8D«Ô¦2ûöXßZSV¢?§5óþ ÊÙfÅá+t üÂùù^á½ß `Êî1pŸ3Îb+¼ó[ Ñ/窴۾WŸû/|ŠHqÐ1yrá7ó,€­?°Òžmïñ1—yã´Sž)Ö\”®Å7"j'À9×%Mº0 èé˜1QÌõ@Яê=†ÿx´s‚{¨:ߘó³7-CKÿÖŽ³ï¶·'4B1¤ï—Ýã>ä!g}×Ä™e¶´į́ cèYVÎs>& ”-«€Ü3ÄJIrÕÅ£Þžsâ½d€ðøýí øsýŸÜ/ïyl+´ï˜µ‚ö¬C¡“'=‚5‹–GIü^u*â+Wlê»<À›AS§])Òî%WË6õ~°—ª8TÇ¡>¦„)µöó Æ_"jT*ûO¾ëùÉ .9 ë($zh¶ÊYz)ƒã ¼Á z¥M#O¹Ä¢ 68ˆÖM9ß8©ª*çØ\Jlo–mxÅC Nß0„ÙS½µÞ_=”hÄÖLM°ÏöxŸñäÖóܶzÆkl ã9g}ì/¥«ÝýxÀ²À|Êô›íÚî9ïì;uÙ€qíó²¶eýÖ{Ÿí{ŸÚªÿ·šPàwóïŠQïÔn,su?ž  o`ÏÄÇ_!xÐÜåAOy¢ÀÀçHmhK&Õæë‘Ÿ÷wÿçôа|6Ïr,í)ØçýT¦OA¼óÖ{2eEä`¥Î1êó>ßïçy/gûsèï€÷˜&aÌ-ëgÊÏ”ÎóQà @P‡Ÿït[ÚÚn ab1gQÉ@ía¯ÅøÎ[ñ=m?¾Ã{*{ÊØhÞL;1é2 ÉAi_†€ÜôÙêòõ¦LFR°½0‹q×=r)½“©6e•ÜS†UiÀ>ÌΊÇ´bÓëQ¿ú P/|(Ÿ¸õM_Fðëì-6øàk Ø–9-r0¬dƒFDœ›¥ Á8;#»cÉñ€ï¸t«ž·Žûbüy4ã9±¼—ìÁw&+›î3ŒfM$È«`s¶g2¡ýûÛ"'—¼OL`]3.ÎgàÚ¾€8Å(Eæc’#0¥àƒwW³%§8Ö5 º³B!žþÛ Öí›.aê»C ¸ÇÊÑîÙ; Ó#ÿ`e{„ øm4ûc…Cò Þs®øó¶//¹)î˜b‹d+…³«yýAJ^è+ö‰ÙZ `…åUz—DSR§œçÌBC!Ãs¾ù¢§QWuvÀøç#-pî<ç³ôxÔïÞ–Â(gà€2-éÓLe¬SîÁMâЗjîGŸÞ—RØzÔÙgÀ–õÄ÷5·yö•å¶IÙWiÓð˜/A¢ô«-°N̹Ҧ-çäó­§(ë NìÚ¾póÆxþêÑ#ßxQ ª;Hµý2öY”·®ëYVì+^¼ ÒD$n(Z+OµS_¥½q¾jË9hêöxC‘Îù6MX–K1?ÅŒTg0 °N¼ËÏË»\¯3àÀ¥´ŒµŸžËuÖ¡Å÷|d·&¸ÎݶÀ¸÷:®klÑã}|­¹ÎuMèßžUå7PŒã‰'å<öJÅgÌgb‡4|‡>J#ÈÄYJþoį§ž‰0¥d[ñꥴ¯‰·ØRG<ñó¥üîÜêS–úžmaü8dÞ¥ë)EwÿéË f^ïð‰A'e½ê™¸„µ=êA¯ç<ïál+ḫì÷£4÷~Wò4ÞÂ;+×4b¥”¤ožŠ{ú§ä; H7MÞu¼é² Ãu½ß{Õuh6ݸt<èuêÊö+(×XåÌíe⨡ÜÔw¹õ1r¨{L†W½±ç;åZÁù´€KÑ]ŒËÚÖ:Šá"?:êî7FÕ}ã»æØža–wг)-¼ ÈXí1ÌÐDË¡¨¾Å+¦†¯ÄÑt\0çJ¼8˜É¶€àÀÞØ¦óÅò¢§mê7(Ÿ4mÏìõ®{Žb{?v‰%¿oÚ´~übxÏ1Ò§±L R­Ø^NÛ´ÛVcÙx<ä8lc ò„PNRºÝwY^òzjçÆ7c‰ú|ÃKÒ´jOæ3‡âXzoc ðÆKƒÐЊ‹\bp“^Hñä2@{ú ŒÇX'ΰ^À-ªºá0ÚO^q…¡Ç fp/eéÖ±~•“MÞò7N®j Àmzñûc7î|{#³¼Ô҈dz~¿ãÉ ϲEͰxtÛç$¾€——zßìo-³?bÅœÿ¿bŽp.8/€­w[ñ«ìrÏ ãZ[Š’Ÿ}z[¶çü9n=îø'ÎK@žö9FØÔM¹ï›¼ÿV®Ç¨CŸxvż¯g$ÏVžŸLútR§Jï˜'ŸÔvëÒ1–¾ŽQ·^Cëé;i7X÷~c„Ú®÷ŠÖ©/m¾ôöN$VäÒžöÔÕ‹~`¥ßÎb§üb,é]<©,ÑÿèrÚFS@NlúÊÞ!6VÊ‚óX<éùf(6ïX`Ī#*Gµëð+TŒ¸ôx¯ï•†M)ÖAË:iÙ<HßNâ_Û<ìL.0ôÆt‡Òžõšú€ö¬Wé}+º[k' ¼à]ÞóZ™‰îõŒ—îÞ±X@öb<:/ºÍY~‹ÃÑ“ü祹‹ÉIæ´áh¢í;¿ý²N¨:îÆMYßàóoÿõ”]©Ë7-h§¥þ˜€«Î[ûW½©8/%˜]k•âe*!Эc<ÛÆY§¸sm¯Œ`ÆŽZ³…â6>ô=ÃaáÚ•f­361:ÅiË{ì@ø•ß.^F?ˆç|éP¬ŸÈJ=6àš‹/ð›muíðrãíØx§IHÉÃfϸ&#L]ׄ†©èš¨€BÏyù!ó~ü8+#Êé)Þ‘^m)³à`'Ú,ÌåAWÞËæ='Î|½¸ Ôå/1ً΃^ÊÖ¨†^*â¯Jqï,q–¨G,Ž˜sâÐñ¤/p.Z;4´ÔCeÔëº9€ÝõŠ¿In­¶Rkµm rÎË]ß1ƒC˜Óý¼Jߘ€¹òæÖ”37uxa2¤n¨•J¦i(³”§Oû9¾<÷c¶ýð`a¶ô/pßÂQÓnÅçæ`Ö >TØäå/@À»Wc:z·íº„·&75[×:jÛõjB?Æ0O‰âùì»í¢8£Ê>Q±æ9fÍ{<%4ï´µÝà㘛’ŽM½ÔØÛö¿œÿ’%Çqù0RXiÒ$@¢A†eúml‡i2LP³ÃÅJ²L¸;»ÀRä>“{âÛŒoÊ×ÒU]UýãÞÛ·»NåÉ“¿úÇI½Þ÷l×ÖâÀ¯®òjËvuÇåº;Vûÿ*ã¯ÏÔí}=³×A;Ç–÷=Ÿ! ‹/÷bç÷¯®c-ÆAÊ´¯ïª¡Ä´‹ üº<÷©ŸMý¢ÓÛ»®xõ.Fõ+PO–—`œÂGbôŒ§­ txÔ1„!•‰ÁÏ-¯¾¼ä‹TЯ:c ¶OŸÄäh£o‹ÅÙsÞþ–ã$ ‡,`}žóePåBhÔsêx¬¬®x¼Kk@ÎvË.2Ã,`úÕU.º;bªó…©6à_4÷[©Ø²¾ÞckNÐÅú”9ƈЃ¾¨ïr ǃÅ};R¯ª;rè5±–M”öÚr¤àh™pÇÅŠDå=qéõž_4u„â>øÍ7{>9Tv9‰~4ô÷XÚW¨fhî€u浩˹ÀÞšÓƒ™p&j®Þmi@1N*¯>ŒcpŠ…YÔ›c¬Pà'À=é¶¡w7ß8ŽDοEÈÅ̽•yJÀ˜òŒk…éê´,› ×e/98*fLÊoܶ3×ëz±¶åAo£òý%ŒðØ¥üV¼Ûõ½Ÿ•ëj¦}f ÿ3Åë*œ×€Ü9©ûóû˜PÁ— Àüáø!DÕ?çA\Çm~ùs û*çßÑH#çU2›¿CçOŸx(AxÎñ¨§t®óg+?ec̉²%­FVD÷JêýêÛÈqþÎÛhžã,“K©”— «ÁèéK¹)íä;_‚p·_poðާXo;«ÞÏY-'ÕJioSV¹}¥NËçH^õ\ÃPÛKkÏxRª½ ÚØ·ÐÞÇ+þå)À£ž¶Eï+è¸V,_Ú Ïöò “Bmåµ­Iè *{΃÷oË”6ÆŒ›ÊÏ„P É«•ØéÝΤªz¶1èíž<‡rÞíN´‰A]”ôLÈK-H8@4ÎùÎ –K½€Àªõí—Ä—·na¶RÔÉÝ]%p<Ÿ)—Úw·—·9ãLËp( ¦¸ïÔGh­mì[Ï0m+Æ{ÿ œ©çØ« ë1º½ë/çm›þ€è;ó°ïÐÚ³(ïl½äœkÇ ‹UÐóìñ²· c_¨ÿò¾#6GC bý؇toÒ#Mh⢽ϦÇAA‹N„plÄØºï~÷ª‹Z^T~u¼ä©óŸ:åü·ñÌw,ôwÚ6Ça4ÔkÑ¿``£Xuê'M+ÂqxÓcÛvŦwÎå½@О²T÷%"'€žùY¸œ'Ô‡Ù˜ùZ,ìɆ1"<ôwómtbÏ3oíܺ{KOÐß3Ï5ØŒI${ÙæÒšç/º»µ¦8¶6 ˜óS÷ýpÓ4W[©ÚÐJ‚¿HÜöúq–€<в®¸H©ýknóMëÓ¡ÅúˆÍÐùñª‹æ¯{ÄÖt½^ã¦U\ÂA ¢cú›ußxöå;edÒè;Yb}ü¦ú7íDbæôíŸÔk;‡ªT¸¡E]qç“#}§PÍýƒ_Ýz^yÄ `%?èñ>ðûÒÁƒ^Ïy^R¡Œ -Ìâ*}ÁÑŽ§üþuë²ig5üûíIÿÉg/£Ö6½Ìe/ÿ–íÔcêiG «ýòž/jŸ…ß2YÁÓð.žoõ×(´ïØòmmcòå8ó Æ­IÙÐÙí‘j{&ŠÉí«Xò¿þ»W­;}§ Bð ê§TÀC| šûô}‘I»h«õùÉå¥ ¬ã-_Ç€“í$þf0£ýŸôj P}ú‡‡¶äåäȉN \ Ý ‘8òzÝÛ®±óxÓ`6ˆ6HgÜÚŽ1.@þ» Òb//ôŒcÿqƯó´cc9–Ƹw[û÷³sŽ.F¤Ž@Jó)kÖ†}ŽUÏý©pƒýþþÄ¥SÞ0‰Ðu_Ú¦Î=¯œý¢Æç³ôž_ÞôÃÿ¶åtÂJЂÀË¥÷CFǿܛ!JD&Y<$nÊϺ–èiØð¦cK0n Ë}YOúbïaÞÁÃr£}…£™—¶ì”“™eæ¡·Ïüš”þ^`ÞÜèË«Nèî8f;c@ˆÐSÇ$W…÷ηêÑ\ /º0Ô[¯÷|m¯Tk÷cG Žº;×9í³›^oú2X·kSª‡0 ä:¾ÝXí˜KÝç¿‹áTë>>æònØ”’yÆpÞ³#ÔÛ6Îyˆs_cq ›È;Oi¬[œG 9)´ÿåûg³…aø] Ñ>JcMš5Å!0˜gû¦šº¼Èž]©©¸›RñôÅ8Û8ŸŽÕņcƒ…¬ŠX ê‡øLjoç§  Ìx߬þŽ ªoÛ‹/ˆHØ@f¶…©íίx(í€ñƒž˜ Å ¥Þòû¿þzµï‡±S«‘ªã•èSãEVuMÃÂ[Ž’©VŽïáXW¡W×ò’]/×Wjo¼Yržî¨Š)@׊ú“töÔ瘧xózÐKaÚ*íR¬!hëÙ®ý÷N‚²O˦Mí=Ç%½Ž¨3†‰Þqlyb2¾éÓ¤ÄnÃóÓ¼ÁšŒ¦ífÚ´”6¥­%“åÖs¬Ø ¼ß¥©f;ò%&…×»uR5J­•á)½7ÞÂX”0frÒ§=M'ޱM:4âËF(¯c¸CÈ ª4†ð› EôŽá‰àÓH­—|\ס¢g1âK€5`Y&°œóŽG›c×sÇrmé×ë-ÕÝ€»çᘭ»- ›kÂ8¼ô^öÅvhÙÅâô àû›äÞ]qûÓØÿã1÷›bÙÑ:8õ´sÏ"n˜¾\+ì‘IUHö7,VQÖÖãqOyfÀO¯;Šï›î†MÇÊß^@,`Ÿôj«½÷ĤŸSFæûù›2‰ðœŸ<ô›€ï¸O;óÆxç9ÒAþ€òÝ·Þ/Kûd€÷ê›Ee¡ç}Çû¬ï½PàYÄ^MôÎ”î  <†hùÑÛ¦¾§=»brWýaã¬SS ®ùG=è?¾ŠÝ¶×œ”±ñºOÛãd¶þ~¤º3çÂËnÏycщQÇcnº{ÊŠÇ!7hOãÓ™>ƒâÞÌñ¨3Ÿ HÅ}t–D¾Æ]ehÜrNh7@+¶¢ô>Mz9•­À¿ŽAáŒqêÅ:xê šG¨ŸÛæZÍÜF;KNÈ5þ䨴Gܘë AÎ9 ßÑáÁÔŽàÐãZ?WÃÁu.(—›~„Åü!Œ€¿ÖSÚ#Mê6âÙg_«J@ˆ´oðj³J¡é ¶-sÝç}Ï1 ¦£œÖÍ“ò¦ùüvgA‡<ø{²àAX9îЃŽùÎ3ÎqO¦T#vˆ¸óŸqC‰—šû€îû7詤ïùÑs)¼;N®`Þ¾åXÉ-uÍá𨧠Qàmm'}€;óHbÑÈãDr&V¦èÊþý‹>ÿA-Œ”ZzæÍ ì°];&š¦Íjï ÿò¿ÿœngÍ/›çþJ¦lUŒ%ÄÙÀ=ÆŸ…ãwAà ªG|æ‡c_Ì©±3›á–J»µÈLp·óÚÇÓ1û âÎ ý à&5? Û?>å¾ û…›Z6Àþ™¡~¨!P¸Éᮜé3õ XìÐÏ‚ ÷úºÙéærÏŠË×ÜÙþ_Ÿ€ùþXÅÙŠóûf"Ý7‘n臓ºSRä<Íw…=uY”â)û­ý¿ùfÅœgL€úRôDúP¨Ï‹!ã–§œ\èÊi>F½±Vû%6ÞôØj«—½à¼õ17'¯ú¢Äë9FÚH=«ìÞôm©îÃóu‹È5Té!õö¨Ç²è í]~‰ÈõÝÀ¶=ì„P!Nêü飿TÞC}gQºûl—öžw¨<èÓ`UÍ}YÂÊò®}xm+#‹ßÿ™7¤D£†¹DwˆÉ–ʾ€:ŽÚ'ŒïÉô­«Sf¡<éÿþ·ß”ßT´ˆð¢í£øô£¨/N–ƒ0Ô÷l#<¼œ<Ë“ð&çxË3.Û+`Že|渙óºO¬Wa›1…^Ìm©ßpðá±u¨òÆ€?tj¸åý7ÛZÖ1£ƒe-¡¶H6k×XÇfü 8öo`pmªº¨ÿr‚!ŸN½‡c·}ú\xÐí¾Ïû¥5÷œ©ë9¸)ð(ð-Ú5 3ûå\Ù¡5óýÃÜþîŽùÔë1/CÉüòûú,ÿj/¶9 ^‚mN°O¬zl+Ù£`Ï>N_À1XQÚ;?\,Q`®ELiÔŽ}§¿xY18€úýÎoîÓÛäÔ„µlbË€Ï>¼ HùžIÊØ¦´ÎWœù#ÈÆK++ÌáêW‰×\9ÏçeÉ U´4å7Üz1÷EýÓxË_@#Æ|€xêyéWQ6õ”L&Xõ¯­Ü¯¤OCÝïùš¨Ô:¹aòƒpOÚ“>c,öS÷zFªÎ }}úZÆ”Ï|úZˆ'öÀ>±Ž™$Nûãñ¯ã}þÆ+Ǥ”tC)ôˆÀ1É= 2å¸ L˯ÿĤ^ûƉO=ÇÇ~þìUÛð Å†* ¸Æ”>íqìJ›¦ÜÔˆn¡À^ 0‡ê¾úVJ°ƒâ¹ìœ›»€¨9ÏcæSV±ýªçAüá³cä7GË>]yü›¼’£³@}ÊoûÁs^@? þ=ÎË,cÇûÞ—¨ì¶qÀ=Ç*`‡æ6m¨´XïKy,«ñìŠ;9¥l€¹yŒ¾xÊñNÈNérð|щ®ÄABLÿwžÄmúúeJ£:{'‡å'á£Ä]Ä1ŘÇRW™ãg’»bÆ“éô¤?•/“ØÔ¢Ë¯˜×¦D+¸‘ûyÇ›Dª„Wp.UlÇ”ˆÆ¬|ã#´õÕjsŠ4Ú¤:N›¨Û)˜¤0ê¸òšبÇ«]€Ü¸l¶sþè€æ÷Úñ‡×Ò˜@6Û-96À<ç˜í·W}g,¿é‹×jïw‘ý²`þ”³Íw‚2üª{Û^ó›öé³WŒMyö¾—)Q÷*ûÝ¦ß ŒÜkMÿà70×6 TÐà雡â<ê,|¥ì,Ûüß·£sŸ“Ñ ÛϘ_’¡iØ*"7cF¼’±<ß.&ÎCCwÚ6€_é!%–Ù²¶•ÜkyÆB}ó¾˜Qyþã9wæŽncPÛsØYß-ªûŠAw¼zÀuÅãšzÍïÂí-çÊ;t‡1æ] ù«¼§y7#רôŸ~÷¼¡¼Þ§ýó•/=ýÝÎÕ›mæCDp­¹ó‘Ê·÷è!šyÅ”˜wÞº¼æÏ&=ûà´’wU˜é']i¦™Ó \ ·ÕùV秺¶›¾Ö7»aÎ8ø¬ÏuÓÆ9vn÷ê^×ÔÅ€Á\·ð©ªO f/Ðîs]¡¤[àîèõFUŒÿVÅ6㚎ã3@?R °åU. ƒ¯¯ècíã¶Ô˜ùuƒ:>O2æÏÃùzƒ«ãòI˜`ƒøµÐ¨?ÅM,Eõógvj‚Šê¥lè7ñ'ÊÍ.ï8 úÃn n{û¿Ê¼ií«‰Ï–œ-t¢xÊW*Œ¯³t÷ýpµ×|?ˆoä8o:µoê#fÊ••HCÙzìË8„R²b¼_XÔk}É}t µ  ³ú]pNLzêã5o½ÛˆÇÈÓVoùå]‰ÜöšK©]žtVÿ3få2O™þ•'ö9ƒuDyÐn`]UßË«þÊtö™àeÜ¢LÎd‰_é˜xÁK[ßôv(ö&o¾TØéDzßp¼æ¬OügʈO•ÒŠPÔ¨[Ç:¡_ÂSKð¸X  ±Œßñà+_^C@7yÉklcÖßê»em<Ÿ X¼ÛVÏ*c±Þ˜cÄÊ»`}ªLxÇèpy“¯ß ^îi ÐHçÞº@ûþ×ø´ ¸O_Ï  O~σ­céú—G>íxáY( N^qñöžãÁ×ï6ß7tüþÿ¿÷Ž5 ä]WNvÂ2¬þŽb<ñêÖ^ø{Ä…8ô2Zxñ«ôINmèÿäLË€ôCJ.¯XE°jF_¾TáÏc¡^û†4x?›=Ì^e© xÏyŽÇ,ÐÎ8Qd–Ó±o˜©ù˜o*þÌú”r€öcê8ÎýÅJ§P#gl ýîÊc¬ ½´õ<àªØ¾¨GW[zèé]Åð˜7ÿ¹DÞKÍÑèìÊÇùž(ÜÔQ#Í>Kàdl½¤JûB(nŽ1žs¼çWû¨£öÅ—rò•ÊcPÑ Ð¿}'Þ†‡¼–ñY9çÅü&uVÞ[‡Æ¾½çxÅc©p ¨“>ÉHÚjÓîTi-§m©·ŒÓ§}|y2–í—ñŒ Ê8§må*OÝ´öLã‘év¨’P0;Â›Ž‡zgö{nÕã=yÅcÞtHSw.dO´³ÿL°%ð07¸'ZAønKJ§€ÒB"ˆ£¥´ ûÛía/¸Á‰P×ôØñ «¿@)}ŸÞ?@SŸñŠ[¸IQ]qá²§sû¬1@00ô|MGŸñ³c¡ :zJ p½Àñò~³×Ó}3¾×€·?ûÐøçšº ú‰ À €üçóÀ>ˆ‡¼}ò´7E]¬ßo÷„$8Þ]by³ ~ÅËëå>æÍXÄèv9÷tÀ9@ŬôÕÞÿ ]´÷ÿX:ÂQ¾jû›•ʰ¹Öêî Pïú&äæ]ÚÆ79Og @>×Ïzž{g]míMÍV¶ÒßtÓbjì¯/àWàå½ÞðËðœÔÉ‘nÊ;áRS·™âþ…™`‡†~›Ìú+¼+¡¾¿§îƒò ^…÷ª¯[ÔݘØhÎ\¥m ÅÕ“ÞãâI¤¯œè)1hî­“­¦"¹8,2ÿi€xÁù¢+ôÙˆ^å«Ðßûq”Ÿ^gJlÔÚ“­g¼æ±zÏÝÝìÊKéxpyÊñ¢ã(*x¯Xà|B5S2—mÚµç×<8cÄ0½j+ÌuÓ'1ië͸îq¤Z¾À÷Åg0âØ¼ú97†ªºÒrîý|­ÎÊU`,j:Nc;"Á‹PÜ×¢áÕç„Jm{çùÝ$Ü'/9×ÍþØxÐßÿSÎÉÇDï¾pµê7 OTq© :@ßæxx%É— =ÀRùëJÓGl Êxöe%EéÏäYO]9 %¾Çߤå!Y~=ú¦xEJ7Û´ûfª7`ãZڮς¢>ÂpÁùÝò¤#‡0\€xûb}fÅÍwÆzΘ0B)e?øŸóp-PoûaÔÞSGÔ´v “Ï:–¼è¿RìÕôe¹à»ÊíØçÙF,.^uÀøÕ¾·c;÷iŒ~ÚØ^/tòM•kÚ´ˆ×Ê_Œ`úV:Ñ÷Bó#7ìP¡³#¼Sû$ýõ€7_mJê | ÿ äCªhí¤L#¦ev uà5Y$]}‹Á‘& O‘UmÙwy¸ïy0{̱ÇíÆ©.ÅöígLyéï[üíÏ{°`õjÒ§±M}ï·€Žl@ÆYä+€)cœ¾ÌžÖSNòµ/`» –þ‚ë‚Uâ¹äÂ¥ˆ  äwœì?%¾yâ¸/°· (îõ^u¼Ý¶cÏËxÅæ±µèôoÕ]8`_Ž·¼åôë\\?TüÿŽå;÷?e¼Téc7ýñV¦Ÿq°: ¶•¾/÷dmõ;½ŸâÑ¡»ÓfÛiÝš;=Ê{ërÐÜñ÷€ð*“¾¶Úýü±`åËq¼a¤cíxË»ð‰Ð&ÏÚYíó;Öú<ß)c¤f Ð>Jï€n3«&, ž±+SíÛ+ýZÞqëFüz³”ˆe–}²€¾ãÓñ¤³ÑÖ¾‡éCFâqØ0çœÍåEìÛÎ R6_:¥hÓÞù †³!¥s£ž¹Tx{Ô-º;T÷Åfô¼í Ü€uã¶`ü~Ê 8'óé{wLúìÓ9©z纰DŽ#“QæÈ­3gÕ3,¤iàk þÐGÆ&{úò[À™>Bš·0¬pc®Ÿ4ÝÄݨcÂuÆJ6ƒbyÊX1ŒÎ Ø_1üý|me‰ã¡Ï~ŠyÿA1¢cõa9;=ù΃NÀÿZQé;F+€ <®öüÛ$òï¤<îý”£“9Ý~/LЈu̶WC|¯`)‰þAN1ì €ßÈ÷'ï¼)úNu§›Q×WêºÔ+èzÕ Å,ÎQoyÁ{Ób ÊyÿÎxÈBwr*Ž´_6óÆ&èã1_t*ydzÝ6R‡Äã/•+ ¥H™\¢ßâEG=Àûœ·ÔêíŒß/ànI>RVÔ›ß|Å¡ãIß+÷±. ì:*í)Ki'Ï9õN`Þó8 @w¾óå)ÿÅÿYìm«¶Ç¨WPè»zÊÓ·Ò¦  K´¨HÓ.xC)m¦³¯‰ñx¨2¹Í¹S–VJL袻+•ÒLÂi“mº:±­JÑT*-1³×g a`Ž8àDÞF«eWÈË];ÆØiÁÚO Pß1äRþZ_^`Lq×õãݦÀ(zz-ÞZ(çŽ Ïö?°Î˜\kÚbí[ÛŸïmÛ§NÛ¼?õœ?eæi¿®•±ùŒœsÇÉÇØpŒ›E°ÇåôÙòÛó}±ãì¤r3廕öèÑé¾–:üüÏJ•W¼zõßÎv@ÿ)ë<@oÉÌ—o¼éëù‘ÔŠŒ ‡gKÇvL½ë©W#£O:éØ.ÀÖçaŒ:‹šÕæX ¥/$§çriÓ>ÏíU¨O_C¤vJ¶ÔíNÃÖmŒ}$g6íÙ/´öõ0È•›¾X©í+}ÒªÅ+Àë\éééþžhyÒT¼·EÿxÏÓ#”Žúsæ+ÈE{Ïüf؆xÏ12ÛTš;ŒÄ† ¶-àZyÒ«Þú¦ºc8kf»`\ÞôÖYØà€À8öÖ ÃTúvé·Ê¼Ãv«lZPÇQj?… ãÀ{r<îÖÓµ „瘢ç·4>Z \Ìdð«Î±ÆX)~ºÐõå¡ôÍ µA%´— à¸/ +Zûþ@ì ÉÎ)ðnÕrǺsž[²ø<±ÅÆjØŽ·ðgÍqøL¬:ùO{wþ£eßž}×§›×4˜ôñ¹ν:H¬ÍU¯G}å Hjí²‚òV:Ó†(\ÔàÓ—+@%ÏîÓí€óñžc}ð·¾Wjs¼æ—B'YéE%¶ã¯PmÏ9T0YÚóÒ㥈¢ê¦·gE|hhsƒónóGd¦%wb܈‡›Ôi¥²cxÎ Ê3ÚžhíÉ œælg"¶òÒ~ôÙŸFü‡tj‹²˜v9©tο:(“Fæ_>–ÄJ~Þ\æocPbÝ·oEc 8aõžûxÔSÆJa¯á)/%UùŠÓ®É{'îÄO9FZ§´w}©²oÁ7€ ¥ ¯â±Î‘m30w½€¸ôç¶Ç mb´ßŠf åñ´”[}Å|×R3ܺÀ1`/uñÓ>Àwár ”ÿç/¿M)úþ+ûÛÙ·@:ÛÙG×ÍÂÀ`{_‡=úoÇSþlÎý]òÝ/{Uè§Ÿs$Ûù@Á¹½él¿×ÇBÓÓ¶ï 4‡± hð(nx2%l†KÅâžbUxò®§dÑ+•=ýŸüÝËЇ{èvÆMxÎÐÛS–þÞ¶©³€i ˜ò)ŸÌŽËØ)cù¦Î /µ]@½¶uJby¿´­êïy‡H4[,®,(÷ÞÅhl<åéµ½Ú,0ÏXðþð÷/78öPåwÞÇ0ßš5B¯}¿ ¸³ÀÏœpî~Ò­ `-4øûu4üt<ëv2ÖœÔÜÃ윩B»„¦íùòª‡þ®TkÌÓºMfžÌ ‡^ïúrÜ8þœ9dÆÝ¿î|ÏyÓþÞWHn9œÐXBí½–¹q™¦öGÚ÷KâÒÏÝíh´³ni…íýâ…¦ï0æ DÞl/giÉ;?ºÍ ÚŽØÔÁS`9í˜4ÎäÔe€}}÷Îáž’¸|ÚØOøñ†ûËCÅ‹n‡l]œƒö•N¬7ÊËë^ÊwÛåá-íý$¶öOŒ—z€^ðŽa€³<åû…@öÁ øáœçWMŸFÛÉ:žãpŽ€ë^/ç̶¼îï•ËÞõ~/,–t–í*0¥S°mšûýŠI/p¯x\ÛÈ ÐÃ>L'š?8Qð §oRävžcÒ懗'=X'.=Jð„Xj®ó|6¢(¤Îdã´Ž.y®3vM(æ¤3ØwÂ+Ç´ÌÆIrþ)Ë9Ï¡Ä#îv¶ËøÄ®ã€<³¢«……ˆµ§í?8‡é?~Þ;>+}ÞV>tyõM—Ó5uáB3„¿— '=æ’{Ú {¾IòÁ ª`µ/@»å‹×Ü ì¾FL7ç:&àZôx{óé—GûèÉæ¼÷Ôáþî(#² v@Ç5N#ùË3ŽÜ{þ<º¶±“èJ”Xn¦?¥œUBFÔÉÉC+¶úPØïÇå“ó¼õYý\‚pQa0`uV\m;þ‰œç€u(YP¸¼bŒAaç%Æ îêÿÑo¿‘\¼ä樫6- @¼õÚóõÙs>Ê®±Rßób7 ÇÒWy¬Â6)Û>ÛÄÖ5MÒ¨¥Ì„%…QΕ‡‚6¼3©b"U•vÑÜ[ —ÞhPŽçü“»‡”Ä›—ÂkÚ3¨í;Ÿï¤@ƒÎÙ:F®a{ºMgÐ.;ã“+(Ç̱æUi§ cR_ÐA+<çä+O;iÓæz ºñ:ªþ è?(%ÚRHG¡š²)ÉT´Ë»ÝXqSª¡¡Ó.ºûJ9†G·ôŽýÜÞëiW@ïtÀîò¾Ümϸ<ç»o<Õö¬Ï9Zæ<ëk±ñY‡Z_PÎbcŽÛf°Pïw¬ýŽÙ—øö êúcû^’)7¾ÄåNQÐ]j<¢q)¬w»cC=Wžÿùß½%_ºôl0dÊŒ¡Mõþj[¡2“žqƒvÂiZbÐÜëI¯ Kɽõ•†­©ÕRWæŒÙ¤O[€zÛ78/[Êí‰EwHTÌïRáY^ï$ÛçõœË£Ž0\ê-ñ¦_à»abcö” 7+Ã-À¾ïò¤_ë;O:ZPtoÆ–€í»‡n3Ÿ 7º(îPÝ—nΊA¯ÀóÂs¤86bÐgÜN¹¶Û*·çk€õ‚ôXãÑ¡¹Ã üÉxÂa^ÞËá3}fkLzÓº•âCÍ]žó #CiG$ŽytëKHMÂÔÑÄ*‹"-‡)&G'”mcð€½Â' èë`?;y½¯Ç Ü÷Új¯y̘ÆvV™_*o|ʸ.;9 ´éíºnÿN>þPÜ³ì ›8÷MÃxZIÐëØëAÄî@éð*LéÞÜ@þ2z-< ©ãµÀp °jü€ï¾kXó9Y”P=åXØþÎÏß‹› €H¤èCǪíñó€ê ﹩í€ó”Ï8_*í²û¥Ü^*Ó6bÑóÐÝýò«­{^ P¬¦ŽŒ#ŽB»_+Í¥„‘O4àýQümŗ۬ĺ۠¬Çì1gÌX&iC.–öLº: ”Û•2&ý޽KY“Z{R®MyˆÏÏ¡’»|O –ÀOÊÿ/eç¿kÙQ\áyˆøe@ÛØG—!‘"öÛØcÅïØsg<ØÊûd¯[,}Sùnë’?JÝ»»÷sÎ>{÷êZµêOñˆ_m­_–ñËÓ2óp¼5;“AÛTMÅ3™µÈR©ë¯?~@Š;`R­ÉãU/OyÕž™çxéÏÄ=`€Ôiˆ¼/…vÒAAy(¨ŠµbrMñu\ùœ§Ôó{ãéÙ.@b|쬼~c @a6õ7Nœñx¶ –m°ÍqFù<Ç&n|¬ ïªÓ°ÏD}üÛ#oï¶÷K½”ôާ>ýûxOÚß¼é/æ8|¦3í ÿý½ŽÙWªøR¾ ¿|ãþwÞõuŸ-ïxÂ|™ÖíwÿÇÎo»hðŽU?i;T7¼$mýo÷?šRBxÓÇ Ð3.eŸ Z$Ï.žEäBÇÖdÂu$D×vâÎ×bgÙGÔ3†øó±¡¡ólŽ-o;Ú"yghvñzÌÊ›.›ý¶x\Î7‹Î,HcĪ÷p½™gNWjõ¦dÃÃNL:`XtÊ‚p öqé œÿäfôf˜YÌÀ•=ÛÄ©7ôyÑPÚ³Á«NÜy+8HÄ`„ÞN†€9a‹ i̼’ÜæbU¢›ôºÙFL.û3ÅÚ†ˆÜAþÞ»_¦ÄâÖi¬[À Ç\qÉÔ=¿? ï F!ÄVcË¥k|dçªTÚ»ŸpMý/J¹Á}ÃnûÛXTøLá^,à˜^”Pš´zÊÁ:o-ýúŽíàE4°ÎØGU+ÿþRÚã¦hŸâÈï€*ùã$4fà˜¾ÓÔÑzû´ç ïõHùðöØs4+%(Rç‡_ûÅN7âó1§5CÉþœRÁßæó’Ü¥Jqžƒº!«óÀ¸MºÎ¤•± è>¬"ÎkÄñF­ÛÐÝ¡ ¡ÀI)j |[æ¥D½r]gꥴ·o©ˆZ¼¤uÀ¸ ÅRTÛä5¶« úL^ôØ/ºWJ„ã²/twÅŸCmƒö–m§c¹¬i[HåÒUú;!&¦èµ~GŸùI §Ô¿æ>'•Í¢°Ç6½ÉÓä¨ÝBp¤ÒÙ¢@xËc“^gÅ›§}½=Ù¦¹OÜeÕÙ%W/‘Ó£µ í¸ñlgL꓇ØÞ©ÒÖßÏÄïV'ÛñÎ ½¯69ž—œ<ä˜Dâ’úiyÑ¡«”Œr5±ºí[1ç&¢ª¬ŠÛ§8áÐßëMÝùÁ­BXŸXå˜SžEtîùÎ/^‘3(ÝË» ˜¿Œ~0žíöÏ6 YãÒ×ãÓ7Ôq<éä×1X(X ùí„ äü´ °Ëûžc²Ù¿ÇØ¥Ùí¦Å§Ÿkä3n°Žá)ç÷²È¿ÿ!ß<ÀZÛ1Òò­û2¸w8F½æXUØIÑ5Þ`ݱéçÅ34M¿ÖºmÆ9z)î ¸K ’úŒgQòëXÛS*î}QÝ•‚­Ûô¯ÅS4øê…4efžó¼h‹ íÝ ¾ÐÛÙ.(?Æ 8ÿ`wAzÌrd0)/@§.^P_nÆ[ÚÆÃnáהģ¸¿ ÊW.ôf{‰W=Þuò¡gü »kû56ÂrÌs¬¯3žr³ ¡¸§ 0Þ´·ÏP¿ÚºÝ¸ryÐ×vö¹Yó”´oê{3ÿ\ǾÍÜ2Fnt9ÂÅï‹éYp.«‡=øè%wÓÞÏmf¬A2Ts9R’ZÀq…ùJMý2‡Å+'£±˜c¸…‰Àgº^eÐâ8žºl…Xç|ú\²£àÝYaþÛÿñ—õýž…õÊÖöõ·ùÜ@ù‹Û¯8芺¼ÏÉ׊Öù€èÚÜdç|èÊ/çX<÷¨ÑËSÌ"ÊìíÕ=Ô…ôÇv’ÿù¼¥Fä¼ëf¯€?ÛyV_ˆ‹?¨Ú;½›o”1­6qÓùæáX63 ˆ-¿LÒÝûp:ª·Où´»æ?¯•Bd^:;žu)µg4‹³M.L¥SÛ¢#õx¬ }½(¦=9;«DºPxùˆïíQtGµ=/;V«“V­ùI7-ÍV°žñÓÆ‹ù”ze¿Ü?r|ý€òugiƒÂž¯9eÀûä†M½›zÎ;ñ©·¼ =õŠ÷”º¾=óì c&cÝNj‹Â-eö¦Usš‹½9MÐì£ØI¼H€ñŒ/µ/µä˜êRe–Uœg ±å¢È*¹U¤Í ¢±çä‹vZ©OG±}ƒíi·›A9ýÜÝä"Ïm€âq“'<íö¾N}hêõŒéâ‰_70ŒâAö1Nžîœ³×"ó àþÛU¿,À;Ûs^ÚóyR¦­ûfóBAß –óÎØ\—®OÞü\CúKÍÏøØÔM¯ú<ß;ÇRüüù»”I3ÀùâY¨±0Rî)ô‚Œ É Üû ¨7;Aþ3€õ£ù¿Ét‹ÇMÙ¼êŠÜqë+6}ž0q&|†¸ó«Î³ª´÷Ø ÙÙ ”<ë8NS³ ˜‡&ßgiKÌJî°šÔÞ8u€:!Nö¦›æÎ;ÐÞÔ}O§\ï2üIÍüky7Ÿ.`aÕfG‰èî²Y€Oi€žE÷õÌ*&‹ÖÂçÒ¶(îäI_ùÑ«àÞz¿æ=fâM¿Óñ‰W:{ÊZÆà4™zöåCŸéä?Œã5ßÞô™3–ÖN:6,óÑåDBÕý‹lgþ‹ç¼©ƒÍý»¦Qhè€r<à9Æ8Á”‹‘N«xjðó\~œ©l#l-À{ø=LBØÍ€Y±é§ôqß–4ÇC¤ÜÔpa®Ÿkvè®?gSɹ/Æ0–Ïß4ãPãùÌØôÛ!Ëy—ø^cÐW®:[F}@<ùÄÛ® xòywœL)ÛÞ×Qf~hâª:禸ßTí“`ÔQî1Åú¯êË)FÁ9ôNñ6ïÛ’Ï }zûûˆËƒë´š˜¾E *0WZµñ’o!›Yá\"q€óÆšg\ qš\s¹/ë4i?s»Ôqº,Åv;`ý¦žpœ?¯üîYJ@7wíÍ~õߎ€qÚF[éÊ&ôTªîÿtyT§Ž5{Ñš?ǺMV$æãਊ@›m-Þ^wöµ÷ØcýœF¼“£ïÌÚµ÷8í`ËX¦ Ú½Æl Ì>Â~©ŸEµ©kÁv‰ë;¨eNû`¹G÷q·õGŠ=?Þ • ÿ9wù^Õ°€ÁxšôoÆíœr1«Ê3~y•ÂìtdžËüãØÒÿ­ßüyQÝcúNþg8ß;Ÿ#í¥Å+^&^rsDཧ«‰Ü ÀÝH#­E–3—Ϲ쇀ôXê<ÌóÜÂ$m‹=ž}G±|æCÕ•`yÍûBRœV@9@êXébxÔ³Ú;éÖÎ/SâËb+Ö<ý(¼BgϸÔíMÇ[>±èóMÅ«G %@Üqçš¼l@NÌ9‰ø8­Ú¤Ø)P_^r‰Ä§E6Àe=9C±dÂøÚͳŠÂjûLNSÆ#d:¨c3 â³"Lðíl¥ýÉJ„Œ²û3pŽWüc(ëW;^6âÎ ÖPԻʾïö<ÈIw–Ô]Óo$IÐí,ä–±®ã)Ïq³¿b´ëåÍvû0›ÅÝHMÖ>¼ØõL ,×NÛ糜} ˜Óß1¿Œ߀º < ™v®!msü+Û€üZûbë¸=vŽ×ãÄ”•ñ:ÛœwÑçI9§ï¼«,èÖ¸ýûÒç’4n¾àûƹ×Çû¾Ú~Ñ2ÙÈD E§OŒòþç¿e;6 ø—„¬4lŠ𠧃“}7ë&Ö}_”*¯…ÄXÕÚ+"×PŒ{ýæžuihŽ­ ’tõ€túñ‹â¾Ûx?Äš~m@zÞ5ÏõŽx†V<æ)µHÜ~Þ[Kà4ï0hñ9_¬},(ý=ï↎UŒÕ©ÙH³¶ìÕz-poˆšCݰ¶›‘—¶I¥FŸS¯M}µÏÜgÇ¥#&G zúa¦œ¾ý¡¾£«zëeD6].ö˜Œ–™×ÅÊŽïŸóÌ5»Qï”õ¼+ÕÝ#èúA7à,H6Nÿ 03Æ\¨ßNÐnsŸcÀ­š×4-þ¿Í"j¥¹CÍgµ…E „àtÃêz îO" §…Œª=öØ1ºqô'`Ÿg>žó«i¯Z{Ìé'–0\W.còž7•Ú¯ëC±}<êÐFP$ÇùÞõ½ßÔû Þ(§èhÜ~ìGˆ–Ä[^0^ëî—R½æ‹)Î<Þó¶ÑðÞjíi+5­/J@ùe¤UK=ç›:/öñy9ï«€t&¤€Ù±çˆàØ ´OIš™¤@¬\·È¡¼ãMoýçXÔØã1©—d&]l§„“ã<xôRÚœK­8O8€CH‰>¼åܨ;½Ñ“fê²oÔ™ߤg¬w²N>eÔ¦ßzTaa¸íÝÛpÇXòÚ›> (Y©Ð¦ÄÛùÖõtQ¶:ûôAOßK€ZÞZ<ã‡üá€pb™½gpêöê H/ ý‹xÌ3ð|Õ ²'O:íã}ÅX|ë1<âó½¤Î"½çÇöuj€ãésíkåZZ﹡Ê+çºâô Þ‚Â|ö¾/ n ú+ß4ø\GÆ”¢Au@¸íÔçtmΧ^ÞEºô—.Ÿñ}®T§°OŒz¬lœ%|)£¯À½4yy} µŸD7k»üê˜ØQC‰G_ N½ÛjÊ+•ÚÊÞmDI•=±çÇ—<õv¼éÓ—r·wQ¼¹Ñb¥M¢q¤\ëÂ{ßéxÑ'{‹¼é#Ë!©‰ÛJïP¬E/—ð4x€jÜcÖl5Å6v«­|ƹ³FÖ€ûâÕ¦Ÿ†Eн° Ûà®ÃùéÛ&ìY`r¨žÌ6«æûzl¾þG³3GÀÌ6´ósŒWaðìúÆ­]ç[«sïyS–r/E>‹!äGðuø³Õî£*(ÎÞ‰÷=þ[ÿþ—Ò¸÷5/ce…ës<túýœ(1”º¡fuª‹š,ä;ÇS^P^EKÀ¸­*›PÚ,0·jû÷ß}ê‡,«¢¥ÐÊéUýL[Ljí¡Þ^ïº)Y}™¬Ô"Ý;ÕH)ï³B¼^xbY îͺÅàëòP×kžc€O]^rèr6yÊå=‡Öo¹ò¾&¶®´¾ƒ§a{ÓŸ4ý žŠ«¶F\:JìùÄ·ÄC²ÅÞ^ýýSOê˜*þQֱĚ „k;qèõ45Q¬`Ýû Ä~Š>Úç©2;Ƥ½ÛõÒU´ª`3@èx¥£b›tSñÖKžízÍߺSpt#æ•qÊ=Þ¼â×y_À;-ÚÏ”sã—øYÀx@]÷”güäP€fÆmïµA)cb³ØPúøÄw’µÿ¤ ‹­v^{À]dC•Ç+?%^‹ ^ `QâdÆLŠþì߯¹(»P2Þõ ä¥Ä“þùü^é_^ôÍH›ÕìÏzÊ_OÝ€½ C,$Áqè†Ížwrÿ|³ø•íÍ^ñÿrÆWÌ1ϼå÷Ÿ?~Öøô´•þ¾R2âM_l¨ðÄ”×Ä Ô?qËû²Y„òžþ½Uݳ«®g1sQÝßä0üÞ+ëGÚËÒb1x‘até½ó+}Kð4cû.[t÷¾#¥Õ[ïZ½ƒkM·6,¸º¶ãS_sƒÿö‹ÖåYgžhßÛÊûö¨“f9)bSÇîÍ~e÷Æ¢Û6H žyã{ÕªÈ\bË'žüÚX¯(óHÚ–í¶€íkþ9úH²›%&×90eúïk>­yv³#ÁÁg|‹³08§N:‰°9í:V9Žc¬Sʹ)%ùS¾tÛÎŽ7^ø2ösY‚yÒ3C»ØO‘|çx±u~~ŸÇæÏETF·²¨=Ò ´ëFÈqœXT ¶½šà‹w[@¬WÈGǾ€S‚óšÙ‡ÊͼÍàWjî[8O²øúÑ[fß‚ðÔ›Ï>þ^,Ø÷§&ðD»…z>©’"4Œ¿.°0oŽÈ§#ÇŠaêCB³uV'®`Îñ«š ˆï첌QZµÔ_Aýs Ä­}èîÙG/å?€~ågÄ\ñ’ªˆŸâº²:§œ—£-}ÐÙ/Q¹éˆYu^ÞŽU›¾¨¹ßgNâΙTÆk‹ç\©iˆÓ#=P/Åp[':ä¸M»(íñbZ@²rïõ Ò?\¹Ñ»]Š;ŠîXÓ³AwGÅ=s»Öa;(—Â{·g>ÙÔk©Ï€ú(Ýf‚Å=å´ü“ß<@9”stOž EU,€¿êÄ#¦”úïÔ¡K^–ÏøþmÁy'†È—`;1–Cå$¶œtCmûj ,al/¯øŽ'?Ú7Ï–gŒó¶y0ÇC‡B;Û5@úxÃãËSŽšõ×€s¥½úÆ ŽÈ ¾´f§.ƒ¶ÃóŠXÙ˜Ó…-…qpƒKy|(´ÄUoŸì¯ ¾ïêß xžñ¦ßÙnÛ”t›íîëúôçó¶=û¥>%ÇNßÚε糦}‰y/x¶ù»A]^ûä ÌKn·ñû?¨@:µ• ûEJ{Õ?[‹M»ØvÓÞÏyÕõ¿©x\ÃE0{ÐSµ/%ÌbÕaÒŒç|€|Júfìדg}ê)1b×§ŒÍ1¨ó<¤ Ý+$é)í¨«~ˆMo=qãÙ®å™ý áKi'v]ï’šµLæazíTŸŸÔK-5wêõ¶÷9À›÷æR~ÿ"¬µ K»öoØt÷Í;_ ñKéîÃØ[`¶Æ [@.c£@îœé“Ž7=ÇŒó"e)¡³wûÿ‚sbÔåE¥÷:bÐÚ™{pØ@qW=!“3×\±ê9NEЧíÀí6tõ¨¾¯í‚ôcN 3UqÈç O¤¢>9X;}ÂÚ?ûŒWù䕨~H€Mç*V;ŠàfŸKÇ”PÛŒéç©ÕQ å¾NX¼øboë3ÚYë6˜ `Û˜º ÇE³3`­pœÁåŠw8 ƱÊðò¼×+¦ÜÀ|Ú+ ŠˆÿÑ:6ž£úá8ês‚ü¡“Xèí=®µ4D º"£Ï©?’®Ù¿µi7©# —’”iÆsƒ(\U/Qn'Åš¼å×ÃEv–ZõlY•Îék,Šíæ?Jÿ¾9æüƒØxÓS¶ ïyËyqd\_.FANyÏ È¡…5g:éO¤ÖÞvÀ8%u^Æyaœ×¶\Û”ß\ƒ™8 l•ò§€O‰ç<ªµO‰!O±z1h„ˆ¿¥½Û5Mž '¶/õãÊå)o[&lÓÆ¤Z»­éÒ[.où›×ñšÓ\jí)¡º[(N@|¼\xÎCK}ž:ñ Ç”i_7Îüð·Ó KÀzÅ©iÕðÊ+¾Åß¾I=À ;Šê—e\ó–/á®±'ô‘ú,õ•vË ô(žwÇ$ŠÔÛžrÅJ3Ö3½Çx5¼Ù m œkgŸôwì(§Ì¹ /ØÏ~mÏw 0ϾiO}¯¥e‹Ç>ãsL®Óãs®E]Þ}ÆÒNÈ C\vÞéw;â±;õ) ò¤a¯8‚q}‘œè ¨ãe7cïGï~‘r¥eÃÙP»[± ÐMm¯êûWMÏæÐÁ‰A/p¯P\Áxë„$~@#”öeÌIÇ»ÝÇÜõ¢ÇZ¹˜Ìi;¿…!ª¼èÌ¿óŸeû{8)óë‚ôÚfå.<ôö°ŽôÖùÖ¦¢ÄÙˆG¸Ç¸Ïîg¨ÜOÂwìhq÷ÃVN?ŒéÔìq~æ\¹ða=ý)úÇè8a:ÓóÚÞ}ÄçØí€þ~±@ï öìinéÕécнQ|çË8ˆ˜©MàZ?Šê¢Øw5űï¢öÓ HÞ?F?§bï³1”Å«ë@éºY)ÏŸY*„äù< ¤Ç&>F"pã9ÚmÀx0ÚH_òK¦}hí7û¡øJÎû;âѵò™1ÓÞ‡%yÎw¼yÚRÏñ‰/zTîŠAgUw^&Íщ¡NšR®±€kôŠ­ @‡ÒNžÑÔp¡Œ¨Ü3hìwà—oìÇW:’ŠÆ°¢>ãKm_ñæ+Ú(»Ó>åµj N¼ùÇÎóº=ž °ò:ÿ Þòô/uöx¿}c{QÙ·Êo¨ŠKí—ü»ã%o}yÐ;©T µenÇS$÷7êu—à›R¤¨ muöi‹%®´ž°ÐÙ Úåq#†uò˜ÕØm•P/Àx+ ÀÒ:ÛŸÕ×gœý ¸ä À‰?g¬<ç5#~8¥¨æ…5[Û ìO;Tt€6¸^žp€nèòÏåùNÀíc‡Î>cÔ¿JlÀiΗãÖ£Þëé>9^= r;ý± âc¨Ìc^ÁÚÿÖãÛ‚oÚÏãnn •~/à@SØë>Æqç˜Däläðï¢V4¦nª{=çíÜ×bZÆHí]ÿõOiÛB‘Ú–ü§|X¬²@^ ˜§gæcú¹ùÚÍms¥Wx³aE‹Ýäôl3æ-4G–IñÝbq%N=æÌ"Î0‚€œ=ç›òþ²¢û ÓB8Þò*¸#Wަ ïvó€ñ–“á%ÖþiÖDs/(ŒKô6^vÂü>lÚÙí¼p<ºâÒÔ‚è4¸ÔcuÀÄ!3u5ħþœrǦw>i»¹ÀR<àãi×:±Èê'Pù>F$G´¿©#Çd§Š·SO{ø¤Å1­àî楷؉KUÞ ]íº$M&›i›I#ÞpÅR2evêô£š‹×©ž©3µ}ÇÖ`w\é;ÐÚ—™ÂŽ}Ô¥ÓØŠìÀÊè¾€‘¢ŠXÝÖ3&À/À§û:žœÜÛ¤×ó9žäzщwüòÙPb¯øXAúâㆮ›J¾,}Œ¥­÷:~û¸Ó.ºzÇäšbxß Þ»çà ú7Ï8ƾ`ÌqY €Ÿ’kÇcßcÆú½àåǦ?Ç`Ë [Bs]Dh<9^uîƒ1@7 Š; }{ÚcÜÇúo!91E^Ê‘?‹Z#¦Ø6¼æ¶%Ìè Ôó\‰g\ñë°fÛ¦¦8õË”ŽíŽÁ³r¤#Ç8Ä0ÖsV|2L¥rD7Mso=Ïü,ÄÒ†¸\ í‘دo]Þ!°°RºÎ"²ãÓ1Øbd Y±èU]¹Ó Ò§ð°´/mr¥„ œgŸÉ´â|è¯VDZ¼Ò¯ÅQ 9E @^߲͌ÎmÓ®uŽÓ¹Qð_×—:±éG€õýq©ð‹ÚN¨âU’*7í1Ò°eŸiË<3ÞöMqÿÁå(2XÁâd*ÍýxÑ[ÖÙ”r×ob3ŸTk‡Øô}{öÁ!åyzK0™qÏÙ¬—[aÊxÙ˜Æ9º<ÒÛyê0dc$®»X.v^ XX³c÷7îÜìdÙK7B{ç˜Ø™Õ`¸¯ôc ïÕup‚Ü„}'‡÷—±€¦T÷ ZàQ7 \f¾;&P,%Bð½hpŽ£00'žƒ~ê˜Æð§X«2ý³±HÂw˱á1}O}î3ÝB1ç¹&/¯öá!/P—•æ³ãÎŒ#v§"¬T¦üÎEEi,ú)ßy½æ‰A/•3±ç±¦\ Ï•v”@ëaϪíåy9DLŽ|žÙθul”Hâ÷zÐc}‰ï¯°zR;4öm€óæTÍKº@½ñèí?¨Ã¶-©ZH³S”~·)í…³W½Þ”rå}‘x/ ¶-ýx?¶Ç|MÂÒ›˜s&r¦µ³ýæP,™,:¥ZM¹ Ô·½öþ­¼NÄ 3É…BŠè[Ë_L @GjJ¨ê´‡›zú%2U þ¯šc+Æü²9鹓Ï~à·n0`Ú)ÐCx6‰EoÐ…w›˜r •á9GxmÅ•¯ÔeÏ“ih.PWøÞ~Œ>Õeól;Ö¼ýê û ®e{Çò³¯<ãÄ­7 À}K¶ö™¿çEÏ*ðã÷Î~¦¾“:îÌ— OÚ¶u¾J?YX§ýë–½§”@v ºviËqú_-{e‰8îÿþŠW]ãßR·ñžw.«ÜèÌË2ͼ¹Žb©gNÝ9wçߥkÏÜ»`Ç©EÐŒ]Ìòu¶&¥l;Ä‘û Lg‡©Û Âmï®óa Ú²ÎJhýôùœZ„X¹É¡õ÷áé—z<Ûþìfoà /ެ(\ñR›Cq×xæÛ[´í»N›n°-qKl¹U ')=^oáÓRÊû¡·7À¯´e«nðk`û¦*x&†žó:íׯµûûƒA`:Ї³y5‡?Hzb`j¢ß|/v6]L9Ûä»ÚÜ^Oy·}Îx‘ë1_ç¼^~ZÕë©.h5¸ÿõŸþ'fàNÙkxÈö9¢qÄ›:yÙù<\_Ç8Ÿ7 6‹Ÿkd,ªó]°Ý ¶D¿ã›søþØ÷Z¬Ç½=†&BïW~®Û€œxõ€é ò • ² Øøò?¬·üe±ÇõŸóƒçxÝ·'} É!4I;:yU £"q ¿/z΀eJ¼èibÎf!FÒæSSû‰ØpC&+:ܾÌ7Òv¹ÞcÃ}ÎwæÅ©·Œ­kPܳ=´÷â…u¼éÁ_¦~ˆ½°?ä`D$ õöâƒK#Xu¨áis˜3çäƒ%sn¸ÁR¢Ž“:ó¸ÙFðÛ¢vƯg;Sè³øþÖwjÖ9xLÍõ´ª¾1á£C|àå–çÇ> ¢ó€cnÕ=§AÓñšÀ>%‚t>ž%íÉ{þ­ßüyÅ•+¿8«1§˜qÿ ÄÁçH©”2À½o@Ž­ã½Cb~ˆ§'ž}Ó7ÎÔè5Pk »Ïƒ…‡ Tw¥”`%@ÇSŽÍ˜E!º1€zë¥% Ð.µý•RÚI±±R¨5þ|êy)à9çE0æØóå%ßÀ¼6/­)s­¿{Ê‹ a•µ*Ý—Ýé”óåIï v¼øŠCûc·éC[÷ÊûÎÞø¸»R–ñL ÀuO½ž†Ô[þ,@¿@ÝŠíÐÇû@{'Y5|2 ý-@øÖÏ ¾“k?&0ß}ÞNú3„íY·5…à¢Â‹êÎÖôwBZlPßóÿÇ»nº{ý›Ž§ŒzŽ)OúµAú׋iÔzEäbŽSŸÐ£zÒ+ ×xóË`Cbûö¢O©Le\µþ:%Ž?ßáU€øYX¾Þa·Û‡g Ú»XeãkaükYç]­÷yùÎÔ’²ulg|AÕ´­l+³ÌŠ?¯f ÏùÕ#pÄs;_úá»_´WÕ ŽeŽÕ9s±zÌ /¡¸«L[€zãÑ Ð) Ü›>Íñè(¸£‰T€¾ç©¨ºGO©ôqZáQo(gÀ8 Ýsé”xÑ‹KF$„䘿#&gÛvÆ»ýáTb¡ÆW¦Š»³xœ°ÖÂY6DÓ¶ð5Çáv…ô™µsÕŒñ£.˜Ã’a?Ç Ðo.-4ºòq;šƒ¬½Ò©¨ä:–E È›÷p¼çðjz¼û¼Âãq¨Å¯…â Î[oLzV·ÏÀ9)¥DèTt,\ä˜úQ-8ððçõGš‡›|Ž¿ÞÕ¿{ ¾©:±Qk'zJ¼åó0âÁõ¬t R‹úð‹Ü”yÆ3>±@/yÒ§­æ•Q[iíÄ(áEG±=m Œ ¬ ·×œ•àIB~Pè^«-õõRM¥$¯yÔXûÒL= ¼/ã”5OÙ6âÎäK–ö¦U[“„Œ!&w<ã`nq8¨ìõKýODcøä1Ç ¶Ç2#…“®P ™Œ9^±^—”¤QƒÊž|çÛÛ¯Ñ)ç¡Ò5É% •½±ç­7¹@xÚè6À8tW§Nû¾Ô£÷dÿÚwöC¼ šyÚí%´ }88oû7ä€ïz*©§ï˜+|Àö7ÝVš.<㨶 ôM̵½à6+¯S"ŒFly­Jé=GÁqÀo€t¬@;íט¬±Œg{Æ©Ý6çXÇ˹÷±æï®çî¸Sf|Á¯•Eƒ^s?÷±wžï,ýY˜Ž‹3% > <ýùþ:Vñù›ýÀ=ð@®yÆ¡9@Uø}ßNu/4ßþ¹Ò°ÍB¢q¥»K»a{ÕÖW*ÃäXoúbÊÐ •wèôL@4n«½ïÅÁ¯i1J€úNÏ´“RrŒXuØEyNz!Tl&åJoyª/q¸)­Wâ<é?û_Îάٷëªîú2)Œ,Éjî•,cd£r9ÎCú†„NBZª\.@Ò½Ü]¡”ÆÆé*T%<æ)/ÉSž°t›sù>'{œ©Q¿šúi×%<ÌZk¯Ýü›ó?{¯±Æ˜cÞxx´Ãž§¼ÚOP9$‘gÜä¡óì*K>ãä¡—AŸqËܳ¯e׺ð­È>úöˆ!ðœiÿ86­ð™K¤5H§>:sG€õ’º¿tœÛyNK®]‹™î­zôlRãp2— g.6îí‹0 ¨Ï\,ã0éÛAÄó>9Nûc$7$Òv â „i1ûg1 ­ØòÖYþ¸`œ¶ ý期ñÌ—›Jºk¢ÒÌ µqŒqII;ûl•¼£Ì8"ð饭ƒévMö‹ÈÉQëzÆZ}ߪ uNàšh5q ~,ר˜­d§UÍREKÅÐ럤0¦Úë[¹È¾|¯‰gžÛ y`HÊŒ!H_onÞüw>Ú5ÒÝ:üÃX?,Æ—¿`˜Ö΄®ùíä}ö[º±]Ý·A6Ç´þ?@×9´iÀ–²|tV¶ñÓºò2šPIµŒÔ‘ÚL±äÜd¦Ï*}ôuºlmIr{¸¬Ï87ÇÜH§¿nœä·êÚÉM[e9,•’9‰Lá&7ÝùS8¶çÁ³XròÌ—ìýìaGþùäšììNK§©†ikžwµœ˜ñ%iÓƒ|y£†4•³g»Ò÷e wý¡ub±ÍßéÔ›Y 2ñ¹öÖÇÜoIaÀøbÑaÏU6'Q¸L¬”‡ˆ!.ï=¦òÊ0Fí#W¿¼'`Åœ[뼓ÌUb(R÷Æa›\R Ge@¹óÌ»ãf"næyûýÉ;¬ý»³Ýhǵ²M æn‡ýKÛ gv_±÷öÏv̰080Ž›¹,ÓkNþ°8&a•>Ÿ™ŠþÞS6ãHµ†->>[忀ñ³¶’wÀ¯0À8Çf¼¸ 8àyÀô˜¡±¶< º »ûÃçø5VP^pM,À®óú:Ç÷0çr\^;qœßñùžï,j¤¯2oäë#ß—ß‘}–ÿ3^ N›8«ÝŽk¿À{~«iƒŽGBj²¨·¥ÆzbJªö?• Ĭ·$^ö÷ÿÒ)&8«æzþß—ÏÄû®à@”)Gµð,°î˜ãXx S.2ÇПJØaÕ¹·soüêÜc5þ•ãÙcNdÛ8Ïs%ý°à3FžúIÅZ?Ó¨L2Žï ¹º§Í8åØj wNîól¬{‘|òD·RÔMNz‚Eý(8@#ÚÇÕ!ó™’wyíœEAºÕ‡v‘$-k›y¾ó¹û2·c~—ù ùè‰é×§ˆ@îÚè™Ç20/ƒ^‚é…–X[ŽîCH•°jXmºÝS†­>O¸ºc·æõÆ.Ë£kUŒ‚ì,)Øc–„Mã `ÅZW¢g1À‹çnï^oçÌ›L °.N5“ŸÀ»Æ]L¤© ¹ù~H=®J¹ßµJd‹ˆÝXÕs[ýMŸ±Ö?aà7,®\ËÉ!ßyÎó=.ö7a`ËB«ìã=n¹ŽB®ƒ–ãsþ’NðåuÌ&u–’自cÎsùyŸ.«ÖÐ*—ƒó þ÷??7†²ôåB¹riU¾¾nT•µ°Ãœ7$wL]²#ÉÜY%EÎÄ.Ÿ‰l'X‡Y¿F윧qŒß¡?ã-6û %GîlS^ ~€øæu!ã˜`ìØŸ$)C¾N@9 2j”N“Ì}b›Õ0a€Q‡=/Hßé^†Ááp hß2²疵c —ö8†šæŸˆ Ã˜Ë`H2u¤•lŸºµw?€sʘ7_³Öôigž61Ús‡ö‚í͆!o}ïÏd·5‘×äž¾\Ù‡=—¡Û[îüò%€r‡7øî¶ËY-”¾q@ýš€±Þ›ªÖÃ$÷ò´ @P‹¹`ýJˉ7ï]hL±¯' Îõÿ¤c¼—ìc¬÷²é=/Ç"ó7c/y¼b-.lðŸØ,~b±÷è zqÚDÙöu 0ôÊÕ½?m;êËÅÿ,P¤¿˜w~ï˜&î-ª $òOú?† ¼Ë¢~¹ZD«)6Ͼ*lìøžëpÀžvî=bÒS…Bé:õÚ`Œ6 —]Ø4SŽÃ;û´@º÷Q†­iJªÐQ9|ž(¯0Íöä¨SGýˆaÅï^T½Å3éªæùãôÙéG[pËN©µíËÅÛie— ÛÎOoŠZrÎ Ô“«>r÷–d[Qvûa· ÄaÍ3/ºñpÉÝs<9éÒwÔÛ0Žþ˜Ä]lŸ!Aš—ž¹Tç`iÛ‡UÀ›|¡ùÜwT&ýè ßÔGòÓ¨4 +6CúTáriTžžËÔCR™EoÉÚW$”¬»Ä1F͉3âMë)ž£/êbަð!'•+ÍùgéÑœCø}©XlpZ1¯c|'9¾ðž6NT æéÓrœË‹o2ÔŽãÒÎõ8'õÚ3¯tÈ --w‘÷ó\g…Àh™yä]‰ ¤Rø.p®rÝqËKpž€µ÷Ĭ#K ¶ù9s®™Ï®¯Î9»vß^IJß2{»È7 ¾Ë—=g;%ÔXÁ30§|Äæ­ýø%ç¡'Z®¢7º‰Þ¸†‡=3¸:mî’jȘʞ°só^F"ÊGßùæãð^7ÑŒ‘wNð€Éy•oŒcWyWÇh‘Œé—ñµŠ}ôÉc›ç5‡S¾YÆø˜+V=óÖe -£Ú®÷˜l”Eh› GŽm†‘²Ê™UêÞ ß|&Yuß]A>¹Á¸£Á†\ÛêÙ^`\ön«Ž¹¥íÊ?ÏD¶¬¤¶µÊqe¦äÒªq¾Àv¤°8?3· \å³öaò`ø†©ûÄÀ<Ç÷œyȳ¯ã7€¹p/tŽ‘tYõÎq G^>,¸Èó9Ç€3µ2ç˜ ¨–]_’sÀ'yÜ=†€}`+^û—tù?û=—kÚ÷Øì/Ã^°<ï ézÛŽ÷Z¿’ÕþWT¶¯ÏÆØ)àßßå¨ ² ȳ°!s:ÊÏàg¿k²#o/³Žó¿sØ©ßñú#ð;vð{w L٥ؼ(æ…1ÀºBÑûFî].µØmî'2‰süIÌçºÍý …Påì(ˆÂÊwŸ9?ÍEÏ{œvB ½®ïÊm¿zvܽ V:1côÏŒâêY5VŽS‘pû–´„˰Á¦¯>¡t²´<“aØÓ_j¸YˆïXAúŸ¥6zÆ|ÈÅãfÆä™·´ON:ûíîNª_äî%,ÆQ!&\v­à¼ÊÆÆJA|þ0Ÿµ*r‚zè­…¾æŠí—9'/}æµigŠ?RS0«úl¢*G—2ÄUæÃ%­êâÞ2kMM»òÏ?#u§<Í P *<v®³7—ÓèŽwx/Æ…\C¾_ ¥?c&ge5áE >/×áµ9^ß­TiOdfnœX%BäQA“ƒÎêÅ釜ú¯óì¢×/ÂL8€bw]Ü`L«GŒÅÂOØ­½c/.8Ïúâ3.éùégÖ"E[ÿ8ý7bLûõÝÄg`ÉÛ%Éi®L~¸Ô=÷Š!ý¶æH„¨7‰ÔH±ÁúÔµì¹Ô??Æc7.í)©Q (?V@?® jZXóU^mjv"eoÛ\ôîK4Ï*m&ó”•·u¼NA:æpô_Ë5Çd.àÀŽL GöaÒŸqew`@sns8êÊ5ïþœ{D:Œù˜Âh# ÜÂqg¯Qϧ’ÁŒÝÃn3æóŽ-ó·ûÓ܉Nò˜ø)\2(Ç’;ö¨€½×jy´Œ/°®2Es&¹3©]“ÞìiS˜/d럔íêxsL—d;4¥šÈ7/èFrK5¹O¸aÉ•“Ë8îØå€oÊŸx+äÈ=@êÜÈͦo}Ä™\Z½žçtOˆ=Àf@òôDMÞÌŽh¿üíï_þØ_þÕ˯¾õ¿³¯ÀV@°½_ï[rÌ·ŽcŽmÞo>ëñ^p\o€ h¯T¿×i ÀæûaŒcèó9éóÞ‘ñÛ\~WT›žýlÛé}™ –1ïï¬@Øûd`HÔ[¿ÿ$Ê” ¨§ealÒ[ô¿=-RwT2;7¦\9ê6™ƒ5ï}é+7¦­t½lºB‹‘T¨€I·gGûR3½ööÇÜgICR½ôlŸÈÜ©“NÙµ>GÖ6‘1J¯QEãöVqðŒ¤%Ÿ†]Ï^û=¸¾>5Îû¬Ç[fJ©¦Å8'w©ïrLæåS%ö¼à½eÙŽ¹ =ÛõÔÁñ=Ä…Áúú×Q& ¤çÜŒUÚ>@\aGwê¢3N]ô2çaÔÓ’‹~Uòu')”Ëí}R/髟c²Ÿ:èªNíôó´™Sg.­y¶k£—,>+FH(åü±ðŒÖNI®ƒdû©ì³)¯m³ð pl³LëÌ^s¥ôê½Û©½ãr¯ß„éʧ‡±Ÿq«”G/eµ•¤cŸ>{4ý)2‚uI ˜¡òsío@©@·- 8/ônöÛÀ›s| }düÙîgÒ{òŠÊÉõ[¢m×3ä{uàlÈvÎÑ‚HúüÀTö…j®!ܪÞÒ íÔ~SòvsmSë|ØsnlŠÜ<É¢Mé‹\ëå¹QVªãVHY1-H÷ ›œ¦Ì_|ëÁr]ÀüÎzˆ {O ë½™s$^Ä^HOÛ\€xú}8Ƽ¥+×i³=²÷;󠬜=ÖÒ1ƒÁ¥ÝÎí-›æ<·´ &çåÓÈE'oj¨kR’xõÆ@92÷«|ôWß~°sÓ_µÍ§¤Z]Ú‰™ŒÉ¥Ý³¼·‡ÐÁŽÃæÔ®€¼ãæôož¦rÊ—Q¥ÔêpœÖÎÈæ_]£ùè_G‚Zv¼ÑqrÏ*0Kß“öó€•k¾,@}u€6ǺÙ'‘~¢¬äÎï8ùÀ+ï¼¥³\îL.ácȨ)ŸÆñ‹–¡›- ^Róæfï}H½ß¼÷XÌù›ï^T.c¸ë—¿ýƒ ÿÊåþÊ[—oÜø_—ßÌ1Çþh'tÿÖœl7r\ûÙãa {n^«ãì=§û3–}šä£(ÐÃ\?Û=6­¾Ó¼Ÿ‚xçÆ¸o¯’r*Ñ6}9õ«îûOÝ»ˆé`Æ6@Çõ]J Øø%kOð¿‚©ÜŒ;õ£Ç!u§R‚rÖß„qßlúF¢ 9ú9vÉâ)ͶË0¾ßE>މŔËP.×WÆyÈý½*¦Ïì°ä÷§?m >}ÌSþ²mž6ŽÛ±ýL*'0Ž“ai€û¨ÀxŽ Û 5ù窋.W÷³ÓË ÐÛý.æ®,Ä„Ó?•¹×Á}@ü1å÷× ®3©<=D‚=t¶Q.~< ©{-æW£>ú2í´çØUgˆšÇ%gZ É3ý·Ã¨sõ¦Íˆ#§šPç®_<æÏ;5#dTŒ70‰{T&½Ä×Ñ.¨‚JU¥Œ«”3ùΛ!G},XxæÇ¾ó#ỔÓÛ¨u]™Kçw¹Ÿsm@îë˜ì,v|‡mòâ;~Daý´÷æ8Ç“ª”{ügÅš­ú¥¿GÇž¨õ—PE?Ú§ï‹éÐ3f›yµHhýô _+û:«æÞSsßÍð+ÿaÎWNÂÊ™¨,ÿDÁö–ñ/¼Wµ&ï^96àsóRPëœÒj_²šù®ö-.P^—öU÷Ü@ÀþãG®ãbÐS238ê›TéÖwJgÈ ®7ë1ŒCµLàê h·[{ö1¶Øó®§69Òvf.Æ 4¬yâ.ìy¶WýóôçAªUðÄõaÕû~#¸ä©uØ»ôko?°.P'—.-n³HdVýg V<,ywúŽ‘±Ã”×÷ˆôÚ#mWP'1¯%ã§LФî',ùLì`ef fž(ØNß ;í\; ü“Ÿ~ÐÏyòé§%ôú‹MOLȳO\ø5N¾?àŸt,väo¼rÑ¿vûQ~Hàn»mG}Þ—$Þ)ÛÇ—5'G=‹Xüo¤­÷BöIþþyÿ›oÜ~<×›\vÊ­Ùg·w‡™t—fHo ú8w•Š´Ä7Çx#{ѦÙtÇqÕWglƒq§> èn[æ<Ï1éí縗Î3ë±ýQˆ<#+kÇͽÏÔ-yÏþä´§í1=OqbÔïò<Ïâ{âúG­Ô2Ïÿ*éîâOÓÖê» \1ùêuwhoMô!0¦¼Zb¶å".rÌ5R'÷<çԤϳçÈ…XÉÜM÷R†7 }Øõ„ …™S¨çøšÃm‚câÔJ¯Áq¡™+‡Ÿ\s¤ìl/£dJ­Qn ¹;,:`û×o]>û7o_Å—é^³?ïÆ< @ `P7òþØæµÙŸë÷Îõõ®€ô“é;ôÔ]ÒïÌæt6™KË¢ û',«Ï±ü.Ò_* 1èRY¼‹M”ó;ny61ðü¯¬zþ1S,‹Þqú+Å©{BåŨâ¯"÷‰îgÑjgLú9P‡M§„=8ç¨lþ;~!Ðþú͇í÷þÞ1‹ì²›*ÅvxÚQm±|°çO;¦r#{_ÀüË·e?Ê0@:FqóŨ¤wá[ÏÖ Ìw:RwØrG:ì:Š»,Ú—Qc¸˜ÂQ)&ccQPò !ÿœá{^ÓÜ5'š}°êñîi-ô¥PÜÛ0æÇüÒ·o?œ~Õ’”Ô ›^‚¦ {Ó!ÔOÿjŽù9$.îÒÌKÓ0Odßô5·¥6ºtæËÛx¹ólÆn<(›.#çìK{Ž­,Ól.‚±ã%^í™uŽ“ØoÅ3}\ØM¾ä§u ¯tHZÈbá0â™é–ìû‚Än2s?¸”ïˆk‚k‡Hf?І ÈîõžÂ|ϬœåmË¿å•nÀ3vÜ õèùùYßo@ì/Ð?R¿]Ó+OwBäx½FÎÝ«XÛ!žU˜é}-1ó,PÈpnúJEPž†>CÀ¹Œ'À92œcD áæ†3€=m¹dîÈÚi—Dˆ|¶‰sÌ1‹«Ì]9Iô?‘³XÇx$cì8¶§Å®Nì P>Mà<.VšW,iØÈÖyÞŤ¥ýæ‘tç›ÛN.°ãûIÌߎ–}aÏ™@Ê¥…-ÀN¹æfplOT¾~œ[YavÓv²VÃ&@aÓ¥µ¬qIÚ%eO¤¤Ú089§¹ffŽ€ßòöÐk—H_€|&´eï‘·ˆã´\Çvú¸¶l—=ƒEÇåyÉÝa¾™Ô'jô¶úeýʆg{Éuçzês]åëþT¤ÌHÜNfŸ.`µ ÞêнjeÏöæÍ ·ë9ýóšã{l€/×-øÜ2sÀrAä«ÿk˜p®‰û¯@ùÿÖË/þô½Ëçþö»GÿÞå+¿ðûÇgV:yäœÏù#×b@ †mÎß*lî»ÝßóøLÃhëó9`·ý€õl¬÷ï‘Hß }Ëë1¥sÝwŽgÜj‹Õùý¤ío(­ó×·y!þ ôÓ¾Ùß5ÇfìÌ3E¥ž¶nð•ÂφŽöœ(Ã^ÆÙ{ý²?e{oiîzÂ@}”A0çV‘«Þ{Ü}/i?­z £(˜ªlj ¶´0éä«+~â8wòÓíìNNÒ§ú¬ÁïDø”ò _j¯•§¾rÎgQûˆô5)ûJÃë¥Ê´Œ!sïs7Ïí9¦ÏarÑÇŸ`~o/Ì©,ó‰)å:ði°S9&û·’}™»Œ‚ðQúi×ü'}9·ö’õò©¤½ÌyeîÝÿò¨K¦¤?=óº!{PL.s`”•QQ¦ÜÚäWêÊ+sb\Þ‰0晓YÄÜ´Sæ¤Ç¥m˜°bŽŒËû°ä€ôlïy÷ÍrØì5og~B„‚E„7ÑK ŒÒâO Po_À¾åÐzŒp–±– Ä}¬pçŠ@ƒ½ÁµÊÖ1éìk»|çØX8%6:è*E&‰¶åè ]më-)º®EKèpZ>Íl3ìtZÜÏ)°ï÷3_–ò$•°4]¹ ;æÚ.ôϪK¾\µp¢ºç”lxöxï °g%7ùýÕYÕ«Ëdóeªmž1J­åÊÓ©)Ü1IP˪Îg…3ãÛÁý†Jdp3¼‘À®ùGÜ s3}¸nîÇJlÛçxôʵŒÛ½=ûaÍo÷!$×ÒJÚsÝ´} aw§¹çs YF*–¤˜r y¶é'¶{{]Õ©»JYµyÐ'^½Qæ|ròÍw ׂñôÓ¶_ö À< Cò÷ZZmŽ/ÏX à²]f„ÉÖ’¸¿þkPù;¦Bé+¿üÔ ÎÛLäš”ýîãUß\aæ|˜ïûb®ãaœfÒ=Œ· ßFòºsN‡=#®(ëœö ˆ3FI©ÕàN™h›%§e¬Æj ¹¼ûó~{Çœ)‡\¹ââíGÀ»9¸£ ó`Î/N»€o^'í0èÿåòÙ¿qç ˜?ÿwÞ»|þïþÆe㥟ÿ½ãý]ä|À7¯g¹ºû¾¦öù3"c7›®øîëë4—Ý Þ˰ö@/à6³n°ÞcãïMËõTG}@zÇ›î|*ï—PžzÎmºÆ×î÷%=TŒúg€3åÙ`Ò§^ú“´M Ê}²9èÙÞ.ð¹7׌s¤ï-Ѧ{sû(¤PC¸¿QÅwKàG±Eh»eØp~—¼½[^8XuTfôQ©å™š¶cª7ǽYdO`®J.,âÔ³]PžÈv™u˜òqzo™WƤ텈HtîÄ~dí5ÑM¿ÛqLã:F_R÷°äC´4½±ŠÉÛÖ¢g›¹á”\ƒ¯³ãç5~›i™—°ßxœ¶JÏD9àýל‡þÅC’ž~À7ódUGZ }TÀay¤Ý%ß)6Pn8¹ÐàÀãî¯Qµý¼6k½ÉG€¾ô­š~›mØdkàßñs£5%œ¦L­xj¸sMåâC`rœ—â¹ç)/eùgYßÿ3'l®ô¦êgeŽAï?ûX™U/@Öªƒ½ßÁ8õËwÎÐ5×{LÙj]÷/üÒ/Ð-ë}úÚ_‰B%ëuçGÛííŒxn|'‡ü\Å?_1jÛ_sÍóÏÞüµ*×iå#·aµOÆp€õ–\í~œ*aЭ‹ž^¶œË$NyCÙ77ZJ«a Ò|óDú›m¤Q-Õ1ùésßòu–¶œgü8'-¥'»çSœN߸š³ÌƒÒjËqµQÀy\áò¶!\Zú÷“@NÍÕ[LÊ · 6L8` S ÃP^`^Ö¼¹ç3ùE·«.¬¸àO[©»ÀøzÆ%‰d"Ø@Â~&g‡QÇݘÒiô‡¢†ð£´L|瘴LŠÙ_ðàÍÄzôÉ=O‹ù-vú+Ï<»ºeìfûNð²ðÎÛu|“þ–¯çü#²-6 >1Û“QåÄä<.™ô”!›j¦vñDYÜ–Êû.ðÄØm®Q¹¶Ÿk/ üê?ÿÃ+pþÜOß?@ùû—/üýß<ô÷/¿ô3¿yù¥£ÿÒÏýÎñú_þ¥ãØÄ·Žë¤e`Üëgœ×ÎûŠ3{>ƒyßgãÍ»?€¯ëo0o@Þý€óy•Ëw¤ p ê´‚ ]ÇÖ8eâˆ.þ,SAúãŸmÆ54¬‘áZ”²ó; ýÔ^ï1ç䜧m…‘à}¥£ —mÇSbÎK¾zŽÓ‚}zî[÷Qé4¦ýŽçø:¼?e²,{B÷Mbî¹5‹€®û²ÁùTã€]ßiJÙ¥T¶”Y¬¨³ hǜԠ >@»íD—ߘÊ&°ç,dsNžÁ€tÊÜ_S5Ç£vûuË૜ £{>åYk—ùF¥î%²M~ú石]ÀÁ±ÑÒkÖâ.¿vŸŒãf~Vr„ nZLâ.¼S*W*Ê/½õ`ú5‘ó|rúÄÓ_@½FÅíÓŽ\ȦÌeלw溚OjèCRAëÈ›I'2woK¹µ0íÀœî±ER~á;!&OÈB³±ÆÚŽ]j@û„ˆDSÌÝÀžsn ì6yªêb`HIÆÁz’à3¦mõ‘¯o¥óÔ+hñ>siÓJCH«÷†‹;«O—°Á˜óÎùÕzM¹nx÷© ~@ò9p5Ð?ÿÌb¯ýãµY‚eöü!{­–GàŸ…k)'c½ž4ø×5âOmôqm¼d28Eʸ‚¾Ï€ó_<ûݵþùÁ°”þ‰¤}Ƨ_p.9ûŒ³&ùçê¹nzbr\¼|ñgÿíÑNý¨x5þæíÿSPNŒ)ÝÑþßn'¦?yæõ€÷és>³#óÏ1yŸ|6÷)£®ëísù~`èY é1­A?îø*§¿'5ê§åw¡ªŒ5לmÅÕïã³’vT'’Ãoß…©R0ç¤ÅxÑ‹d¤“|0ý¤j–FþÏÙ¦4[SZÎô•“^ó¸ƒÝÎý¤ ¼÷ ªyZUÖü~Á:÷¶ƒAO̘ïŸã{œ€{3ã)û¶sÖ ÔÒ§¤+½`=iRbΑ¸×HŽÅæ»5=m5’ôaÖåÔ›9Ÿgmú­œ’t1çõ})8Ϙ€yK°%ˆ+÷<û1½bÏ•¹·:LƒQòmæ<ã/ýòGxåäRö`Õé—A¯™næBG0–6Ò÷™{9/`~‘¶s¹€}Å•œAU ‹Ž£ûøUI;¹C1@~DÚQ‹ 7`àO›1Ày·76ÆÌÌÃaËUz Ð.<%QÌ0 uå¦ Ä³p¾Lßz^¯¥k+eº€»øç´”´ƒ×³+zýå$O¬RnfÐÅ´sìfèù.ó7åØ-oÿ`B /ý1¨ȶçARx×\ç·ï4Ž@ýöu{˜ô:½ ¤§ö?b§°´âbÒ'o{åØ:–(p_•[ò޳»bÉÚ©®í¯ïhJаܿ^<÷XrÌ Ä¿ü΃íðÞÜôδÔTÔI—Ó;Š,¢ ÅI™J‘ûæù·ÍOÙÎB4ý€Û›¤†!y¯Ô½)cYwySª©xq†=1`üÖÈÕ3? ¢Kb1æSŸ>óŒë2°…Dh\×ö0æçà›ú—€Î¼)±@ù‹a±}Çv}`ÑIGœÀS(Ñ|ô„ã6yê æ•CµŸ0y„²3sÖaÐQƒX¹;9ëZ€t)O+mO iAºüŸè¤¨Öä9óò-×^¤gÆêØÎ1¨sOÀ§Jƒ‰$mã(z]¥ã’Ïëà¿Eà nÄǬØSŒÿöƒ Üû Kúó¥-~d “p,,YÏëfÐ1i{Í ®¯#9€øÏSOnç0¶¨À&?ƃµ¶è÷ÁòjŽ[a@Nx¼ÿ4ý#i%‹‹À·ênƒ:ƒv@½Ê©MÏ0OÛD®O-tŒ€òl'ºª¸œÚ³•Ä“rkåêÛ·v±êÛ¹=­# üáè»Üˆc[9Pî0ç” I0> ;m#ûe7+Ô•Ž­€OPóÜùèä•õ¡Z`NzA9yæÙn¸¤+÷-ÑÿD'ôaÕëÚ~j ÷.2À0æuÐ-S¶@en"º”ZŽ;3v´gâ6¾Ù†¡|šÎÏ$ñ+7Ð-Óó#£D'ª´÷Ù®\´µˆ‡±º€­Ú‘€îæ„.Pžm€:ìùš¤;2á«^Ön9±‡‰+@xãÖ£ »·e¼-ÕmB•£ ¨ »^†|Zçÿš5¯q¬wú”8+(_à‹ZÝ›E$–uXŽ©Ú—HÔÏ8ý§æ{¸ ° g\€øplÿý·Â–€üå¿ð{—¯|û÷þ÷._ùGßOÿ0ŒûÞXñê_ýîÿȹèâ+Öý¾8ŸñÇq-úÙ×m ìêßúëÎOG•À÷ÈâIûä¸cz·Rú7h§Œ[÷ýœ^_„Qp4Ciã‡à2lä§³ÿn#—‡)Wàñ‰Éû6}´Ãû,Ø‘Ã.Ó8U|°§TÛÅ.ñøþ¾7e,¯`¼å$›—¾ƒ¡«{(þ¹ß¦Ï~ÔLÍM§ŸÖÁñf×ó,iÔ¹UÞ3’ú'Ù?Ï%ö‹;Ï»JÜ5Ö2¤fÐË®Ì'¹çMM[Ư÷6‡EÏö0ãÝ`þ(mÀwý‘¾OY5ô‰ÖQŒ;P¢"Ìë]$võÈmF½Òö[€ð¦(6»> y:)”˜Ò!‰æQ€–±qý” ÔsÝç\ô⤌Fa 82«€}9*Uuæá°çÓ‡A'=Õ@Ü$Ì%ìE_«LxâÇu àMv 3¼!>OÁ<×3ÞñûË~ˆÛ„Ú´r«7UÎþÿKRçý.‹%ÁÆ"€ýzݾ—g0#Û/`Ûy ±Óï òAùrNeåg?&;ë%Øv8ô‡×µ äS‚LnôúÑ!à–˜ WèÕ•—½èAðùãùí•͎Ͼ£:è–·“CÿQk:†9§ÎcÆÇ£7 Êv2Þ›WW+↧Ý“¹ùQós8¶ ÎUó|VI—AœäP5‰Ô½ýʨ–¬ªý©•Þ\óc;ùW¯ØaÇ‘³/£¸nO~9‘ó»*ÍJuË¡lœ“c>-cbÌeÈÜË’'®¿ó>õY1„›í–’a’œ=“ô2êÔ:_ι™ð°wß¹!Üœ‡K»còͯŒãžÕA?ö¸³€—ü²Ç$pjwÔ‡…R=s\“Óv,¡s¶ ÌáþT,Zû‹-ŸÚäé»^y_ç èWRK(—E3c€_À»ý3–¼û9o®‘8sTßÀªž}ln\c;•‹œ½åÀ¶yNæìŽ[IËaŸÓ6®˜âO¦Ÿï÷w9öè깯%ÕΓkþÊa 7 üPÿþåõ£FúµüÇØfüêñ¯ý‹?ÌB@äéßÂ}âxG2þ¸ ›cr¼ÁûŒk¡Á ùl]á;q º¦ôïÓ1©ô ÈQbq±éÓ`¯ ZS{_ÇD-2ÿ;Дl.ºË±Y־Ůs,@½ }úŒÂ¸ºSº÷V¥HÌã|/k¸|$}y;%+ç5Ž>á{´#çQrM÷øŒýd€õ§LúyŠTc±çòGIË3êÌ4†½mº¥>{w¯ò¥U±õù+À^P®ÔµIS .“8Ìc¯õwÚ\Ú®…0/HO›’®ã<-®Ã¦¤g•må¡3“PÆ)µáÒ±ö\c•µ+…òÅ«ûzæ²%“f~:`ºÕ…ðU–Õ(&qÎE㸤ˆö•Y+a¶Ê®Ý ÃûÀ°^34c›UlÄ;¸¶ñ˜¿ý‚^Js«úJÍ-Ö„Œ4@w¬×\dh_ŸãP´/Úd¬?c±ïþ~ ° ¼gïÝNú|žšÄ­‹»`»k»°¼B¡/s'ûËš~lÕ wB¾W‹ú™T:@¼~A®«§è>9¶f»0:v_Ûõí¸hÇætÈ¢‘ï|s›NPƒ‘›B@öó;f›Ãáâžc›—.Pž>AôfG«Z“€ó„Ìâ@o4‡hLBXq-¯(y绌Zª…Î*/îíikG¾5Îs½—ßz®zçWçO¿eÕº’ÝÚ¤åaݳò݇)’5€øÈÙË5¨Ú–Ü59µ_ûÁ”u±Ì½’¼5É öyËÂ<˜ï<=@û}åöMÜÇ¥½ý\gIÚïK’ƒ¸%qt:ûUÛ|ŽOt|å–瘌Ö Ê‰Ù¦>“Ó°âcòÚ:çGl;òÑi—lýkw/Ò*ñä¦nikºrZ3–<Ö‚òŒMÛ87‚P'ïöüÍÖ’†Ÿ€l™´éä ³ˆ ["}Õ0WùºÅŽ"—žk¤Ož4ìxÎk9ûœ[öo ØÏu,ÍÃ\@g»Àµ ¼€6m#Ç©ÿúƒþáÈ÷ „_û'?<€ù¼|õ¨þê?ûÏi;öýÁqÜ÷æØoÿð`¨÷5y?ìÕÎçý¦O.»dõO R¸Æß Ë}þ øöå6ED>[åê-Í–X5Ùs-©/rÀæœj.ÝÆØÈÚGâžÿýYyâÿ©x7Äã ÿ¸U ¾‘Å·T"%Ú²ÍQ9;¹ç9 Þ{OÌ,×> äF¤EÇöqv—qf·â¤©nú{],õ}vÝ ¾æp³ßûê ›¢æ:ILj7xÞsòÐe®:¦¬€q:Û(ÝÆW‰û”Z°Ÿ”]mÀ.‰; U ûm€yØõE6 ™Pg”ùQû‘®·´,äf»kN–c¸1ì=su·iÜ ¿ü1 :fq¨,Ø+m2‘~ƪâ|)c;>IiQƒ¬§mŠ'ÞKÓXÒ«ýs‘dÙ{Î~ÆHU-)‡1š1ÃÙvÕdz¡¨†¬}JŠ²Âªãž“ó·”ÝÆäøjwüyð§TÙòöR™6}wúè6Ž{œˆ…Û²?’ùe:^]€ÛobƒH.Êö®•®zzÿ±3]Úíª®3WãÄe@X-ê°ÁEðE¤R!®8¦Qé ùHXXEBR•2v°éZ 1„öGRùëè4:åÜÏÉßÔ¨§f=z#~ÌZk¯Ý¼Í÷½{¯±Æ˜cþ“Ç@_r.”usÞµ4žH&/À –½ßö礼€ëçq­|¾Ê78žïoIÒW=uç.X:bÉ×™kg¥­ù*ü¸]û\+vïxæfócVɈ՟¶²÷¸µ#q¹{oZ«-Ãžè ¯¦pÛnúŒÝ±c;@G÷aÄ䛯X®í»¤G¥î/”³ò‹¹ eÕTל~®Ût™­ôÁÖ•éäŽ?„Ľmö­|±‡eÎkô’>à|ú%]6Ï6¬yÚî+cž1ØtœÜ Ì ¶“{žVõ‘^ÿð™€È‰ìÃèn™ïº´·]Á„®RÉîc¬“Á–‚=—9\ÙqÀøvnÏ>sµÓw>9“fúÎ3¯ÄY«Ë1Íy›;gC*Æ Ðmz唿ðA¾9À… tZ¢@S¯\sʯmwn˜Ï 9%̶ÅÄ0ø¶AYZ`€nè ºÓ ˜Š½vô:m ‚é‡AÿÈw“w~÷_¶üK÷îÿW‡5ÿ£€ó¯ß»ï_~õŠ-ð¿™íõaÕ£Þã?ðò ÀôÈç1sž±~–qœp«EØwÉáÃþ+O»¤îHâùœþ>朹–XôîùÛá¦O.»Êßq¾€>@VÝñ×5¥Ëyûÿ×*üÏ+—}ïË‹[D@ð‹·Å¬ã+ŽüÝyéõöRÐþØ ·Êœ/vÝä¤'¦ÔÚ 1êýéíe×þ¹§¶OŒ*©åÖˆñé=˜|t%Ó,p·µÏ¬U^öø2ˆk¨Œ€ÌdÕá\—'°šÀ‹þR[vÀŸçšdüÍM@ÂÁkL_?&V›8Ù×wÙ9\Û¯ÎSþÊ;iˬ"7‡ÊreË‘çÌ ê9UŲ锓o~ÆÎßøÜ8Èó™(sžÌ´9.7ДºPÞ9}ØôslƧÔöˆÜ*«¶ä›ãà^¦|åNíiŸ§¶gWŽi‘‚9fß°ãÐ˘¿‰œ]ì9wåÔ`Ы–yºÛ;f8òÒaÓÅ4ßüÁk7Ó—K{Âà<Á¾ Ê'ˆñÏ2~«½æoø´Ã”·m¤ÞîGMóÄÊ9ï™ÌŽÑÀ%¿2‘ f™ó%éDÖ¶§ö=Ù “åò_O~ú·ï=ø¯Oû‘o_m?ø'ÿå˜Ê}ýÔNÿjØôÒ¿xŦ¿ïùÿ=×tÐýÓÿB^ã·žï¾€¾ûXø¿sLö5ç©ûZœ@æ¿Xxö‹‘'rôZÀåP>Çå}„U—!•Ä•Úbü`§]s Ì/P^/…ç1ÿÔk¤8c£>Y }ÉØû{=ÇTõ"i<‹pÓ'=÷†]b‘E?•^û={^ôÞ…êÇÆqí˜ÆÁ¦Ï}О–*M ?J ã¦ÚFƨ#¹ß9ébÒ;>òv¶ ö{n•\”í4‹Þ\–)ÜìëvŽEÞ~®Ÿ¶c÷=ûÚ~"-kyµ†j›·¼ZÇ'̘?x>_Æc(3ŒºrÚ Ò‘²7×9;†6i3QqÞŒ%:©™ ‹A9òö\/ŒÆg—1œc¾Õ½WãÈ‘<® ÙeâJb9rvÕ;WN¹‚Zç[¶þŠ$îLd= –+{· ä4½œÉ:5ÍçÙve3å·xh-眗6ÑZÒ‰€ò°àiÍ”Ëp« #L%.ëÈ‹]2Ë œÒgbOµÝ£± Ê‘˜Œ,"ýÀÚãŠûøEŸý'äy_ÓçœGžúþaÐÿÓ½²çü›o„58?àý»÷: ûÃ?qú{èì;lú‰Ò °¿ïõ'žûE>KA7Ák- ¶¼c=.Ÿ‰ã ç¹NÀ·¥pÝv¥,æ6žVnûZ€‘ã¾ë»³= ùÅò{«Àüóÿý¾—n§µR¤¿ÿ&r.Xù77às9~¿ä¢çÚW,û’ˆõ˜tÊ­-%BõÒ­ì¡ßûXsÓW@žK 37«^pÞ•HÞaÖ»¹;ÀœÖŽï~6 ˜r6¼N´(\Ðþ˜]Þ›¢U/å Ã¦·ÛݘÅíç+ q¶U]%Ñçw^cJ¤âð¾¶'­|ôåYƒêN}˜õ¹éW¦·#S_%a»˜ ¨·¿ËÖN «.øÎÓêò®ùÛ™ë P_ÄMÜ÷¸ ‡eGÝsû%MU#ÆP‹®<ôaÓ;f.Í)†uro.:q=Aêbæ{­—Î|àÞ¹aT˜ißu®W=LûbÍ æŸ£­Ú³ŠÐM2‘o~)\f- Ùû(YOœüó*X—asÇ,uo,wrÉÊ›ç¬áô­ÈÅLàUáØ8즪T(cºV=İî;d>^LVspXqÞƒ€½Lã„+»Ûk›Du.ƒz|Ýdö~qÊmÖ…'Ìp+m ؇Î眾V?”rã{΀gþ¸*?–¦Úyé{Õ£šý—ÿI­˜èuû^çšþ>w­½½*–¶ßMúYPAú±9?äyÿÔQ„-ÏÊ\ÚÈÛe '`¾sÏ‘´ß–̧ìwo`]qLTß}bÊ 1å½¹2Yz@þ«ÈعA—E×Mþ=yÍsÓž1$íÛóÁ¥ß•^‚ܪéó0zϳ7Óˆ'ºª¶9,ºË•²œ‰*p;ZNmäSnMÒÒ Æ`¿È1Ï$<`¼Ûé×ø­µË ÈÓ&Ìœc"u!–`¿óÉès9V2á´1sËx‚üòy}€º¾ê¼ž¾b˦bl[-cŽÔe˜¶Ïeì8LxYd\ú€báôÿÛô8·ùúןøÖàü¿Ý{oâ'žšvû÷âôGò¹ãó¸/Ø÷5Ò hkÀžãóyù¬\‡Ï~)ÖkÖXïƒç:K]À¢Iÿ&—óÙ§ïíái7X϶•.ïÖãˆüÏÖt°éa̧}1­L Ôã°Øò*N(3Hå¤ï,‚™U_€6ôô¸ÀGÓ{À}Ê3.Ðþdrï/;¾ð΢eîßc&—û^Ýßä©Ï¾Þ¤uqs«’¶×‡Ë[Ú ϱ-Ÿ™~ZUõ€Ißùé§ea¸ÕBÒ7“ž>éX•¶“Æ•ütÇ])Önçé|ôƒ.€^ÓÖµxîmç g›RªÙÎ1”`eáŸ1ØòDÍã6a¹Íµ›i—2p{ëÄ Öñãa¬@oŸ™gµ^úÎG·Ì½c¤.ª[=‰ð%‚Ü©>-óÎÙwÙû”< ¨†€b.‹*Ô€|VSn-•:‡`ŽÔ]¹çÊM'ï\qÔJ_-ÿ¯sŒˆV瀃ùDlb~mF39ÎU9³ÆZ`»`›E@¶6yƒ*]ªÇÞÏíÔe@²Ó£‘Øs ïGØ6¸bU>mÆr7ûu1›[×êë¾íKkVØñKo梡œ–ý²õµ®W~¡Úáü×u¼’±Ç¼CÁûþAs|4.ø²ñú\|6Jð–¾W,ùÐ÷·dì)Ï€¼½,~ àVîK¢RwJ¦a—(c»®Ü›Ú×\#ÛbÍŒ_`Îs–Þ€9¬çæÝ|ZËÛ‰2çëHÙÉ?ŸÕâ\w•aöŒ“«EîyäéHÈšYîKž–`Ì |Ɔ=?cu}̓ùŒe"X&§œ/£š™0àÒ^·Ú‡Îµ‡=OºgÂBz랤§0÷¶L~ßriW”1 —‘a"Øí¶°=š@  ÿFpHÛ¯&×ÓRoøvûõW–|}93Þ‡u¿=c€oú[ÆkŽéÛ›•HËX€{ö'†'϶ € Q/v cf¼Ç=y&úHØg¼àªìyßkîF,Éó€@?•>@>îê.f9zÁ7 u˜ù´0ð‹ 7ƒNÐÿùãÞ°}$íßöüŒ?ô'ß»÷Þ§ÿîÞ£ŸüQ"`ý°è'žúÁaÞ‡M?ÇGŒã¾|UŽí¾Sªí¡}çÑ%aßuͯÔÝ9ëÂßÑ€o3ë’Òs¶UO¿™Ç«z°ñ!¹Äë¿$ðéà—Ã{ú0é.ÿ™|"ýünTO}3諞z~s—Éʪwï-X7wýîaÈQÓ¤÷ž"ENÀ3ìzë¦ã‘v³éÊ=¿àìÞ…ËDî™5×LàãCÞÅS+œšâDZÒªÄqúUN1†O 2xTXã˜Ë,:Ì9 }óU#ý:r£M–pÀ¹k£?ÜÚèsUU9Û°ñy–gîóìÍ<÷ì®ô2་ý“Yó“ªúT.VÛHÛaÒZ0-{€Þ”AÉÜIIÄáýwž~5.ìUCf,ÛTëÙ5ÒÊWl¦|äíŒ/0}W@ð'o,É{{Òj§|˜S[<õ›ÌǤ;˜ß›MgŒ´]ã»ÄVCor”°$0éÜó†UeÛl3@õŸ>IyÑì›1m¶ã³`ÖÍ8çó]aF×pÚµÈX}v„/(76½Ro^ùBò»ÃqÍÒyŠ²Ã˜³ª#†sÓ$—¬‚Zu>ŸÏëmrå w˜^3ïQ΄oñ>,ïèß|óqx°çºË±›Â„€¹"@>íäØÜöûÄÎCŒ³Ê˜m‚²joZJ­u*ssÍS+¡¿ó©ç1wÛŒ¹ëŸ÷æH¿~§ýFäžãÚ^Ò®×ô$ãÔøÌ8 |;¶Ø[N y;¥Mú@Œ¼lƯ»¬Ú€óÙÇê9†1k<2:ÆÝªÉ {ž¶ýäе¤ZÚÊöâJK952À„êÏv{•XCÖÛñÞ”]Ëë¼Èdkq3 þb`åÃæÌ8ÌxÎÏu³oJ±o¶Æ™˜’s>’O1å™´Þ]NÊæàw`ËsÌuúãƒIßníÍ)/ÇŽ²O˜WÁ„¯üñìKßr^€KXÄæðŽ¬šÓ˜Â9¦À)rxçš«vvVûU–©;Ï™ ¯¼îåë╜@‡MΘ€&¬xÂrqŽ#×;À˜ã†ÙN°P©úƒh?|˜ñ€ïG?1ìùcŸüñçÿýÞ£Ÿz#ž>`= =ÌúˆÿΉoÖý›“—> ý˜Í}弯{ÊkŸ÷6áE„qh/ FP` ¸Ÿí‚sñóþs-Ëèùüÿ^\I¿¥ìZÏ=Rõª ÊÐל¯uÝ7·‡-ûÈÚYT¢âÀl/ÐNW,°ó{c¹]rm6^Þ¶¼ ˜sÊ(6²= ùgï°HŠL÷¥Û~ÁC =Û^¬ä~Ƚ3=÷Ýô9nŒ9 Ú Òw….ÐR­#Ϫ󠻆®[)Çs?à@é3fž Xg,’wLáéaÖ1'&Æ'2O†t ж¢´1ŠÓ!· ¼f.±ŽÃ¦'å4û3?O›È¸A9ŠÙi³ï˜V’lKÎí'&×v¥ôym±ÌÆÂ”2sØåXŽËu*‹~¢´5,¸%ýz¯–»cä­Zé]´[n`Ÿ¯±Kyêþ.¦ºÝ×/—N»œ§Ð“èïez;½²ß Ww¿,µçŸ†\zœòœ#ð›Ë.|ŒW}æš’ÕûÚ|vÞó…E$AÑJÿåÖ~ê³ 8G>3Ç•Igsê66jŒNÉ4@zÎá¦e÷ËÉãiýIØóÜ㨙~¹W@aÏ8çÆ|ÚÜŸŽì]†p1iz÷зœýÈào,Y{ê›#Ùbü*ä›óÐê6åÔ Èý0Tîy¢ýY1W}sdmeÑ'X‰ïÃÞ5Ï™äx¹Ëf){úäÙ!ßs95\pË@tŸrÍ0Ïv‰b&XÎ?O¸ö-eØÈGŸ˜×Œff¶ÇÔ¨†F¾pËyçä› ¤O)¢ëÙ¿Ì—^aâZÉh¢à¹)’ÔÅ¤ÏØ’³vl™Da.•¨á”ÙÛŸcÓ&ê*= ¾ â•2ƒ6‚‹`"¦œ}”S«‹»À{dÊt…@¹6]1@¯í‰2éÒ›î~Àû¢ÞQƒÞ\wÎ=ÇõÜöœ³s@ö{þÅô‡þø €þ±ôçPþø3?9€ü´ŸúûÞ”±ìË19ÿ¸¾Ö= =.ïéþë€ô«Rlð¹W¯û¡"¯É{] =mŽëØls¬”×ÓnpžÖ)9¾'”ùî©Îß§}Óšø½(w¸<[ÚD!]xZ)Ù®>a`n°NÙÁµp–6¿CÔºgÿô /ÊYY{NêÌ„»M+Yd\ûrÏë½0Ñ~#îìM²Çg[²оj¡c"§í)«†Ô=ãKaE ¶ì‡=oùµ7©"Â3 ×öñWÉ>TcQ…%(5`O?­¢9étú”A ˆÆœ5Û®•îy`ýn¶e4›í0îÈÜ«æ#íN~å¦/}¢ Ýùè/Î< R„8à¼2÷ÌËÂŽ×?hÂþAtü‡ÎyÜ»À_QøMʲý5%V™ß¶0äÌm g;óÖUy-æÁË8yUC h_^O­š”©;Ûí¤ ‡U ÿ[ý?Í™ù¶º ¬&.á3o»àTç©,´ Çû~/U³ZŸE•¶`¨ÅT«®»£à~cV¶ˆg^_»­ÏC._ì,¼L™5Ò®{2¹ >i9Ù™-—ü€UþH>K®E3Í2WãuW½<Õ›8ëzÊo@L>8ß—r$‹àº„ëñ9oa—jÓ?i‚kïšóó#=ßi@zÚ¼K`p~°NÞ97ÆíDo*[Ö~ÆÍ!çfÄ1€rIÝ—{&7Æ;’·œ'È?Ÿšç€ô3¶$ïÍ[ò>Lø-9‹Ö¬$ûÊ¢‡©k.“8œÙ›{þF}óŚLj¥yé¬F»ÌIŽ Ûµm¸e̬˜×°ç”X“k{Û®Ä3漺–S›hî9Lùi Â3¹é6y蟜‡•oÅåò9žlµ1P@÷fÍóÊ9'ÏqÀøm³:Ûàˆ‰&ùçsÝ+#¹×—¼s.å:/í}ÙS»œ~ãÏGnºrOÎpÿ@'ãÜê)á„dv2ÚaÇécwŽPN-ò¿€8îì6†c¼rb̽­‰ÝcÒXÈ ´Ë„—oÌvö“û9@¾Òïö¶ @Å~ØÅ’ø ˆø=àùü6ONùï'öß=îS^íÛÝWìyÁùãŸþé‰ÿ‘–xæï“þã°é96r÷€û€ôs¯¥dÛêÿù8ÄÿŽß{áõu Ò'f1"ï—íÃ\÷ý]ï}êôåÏ÷GŸïgþäñ‡q7Ëþ…ž‹“> þ^„¡ä]Ž_ÿI“ƒ8Êß¹@c€wúJ­ \›¦¢QŠG~C5Ulp®2mäõ‹È¸ÙÓÖBŸXÅ>ç§oï\t-:ž{å$ ÒYÄÜ*$$îŒå>°­¤.¢Š=?ãâô»ð Ãþ9o•§®T«Ä:¥×ÒÆ›¥ ú] ãös´Áb8Òö§üô õÑ)Á6@<.î©Þâ¹À晃´ L:évÙ_ ¾¶'æœÈÚé( ¯O0*ƒ¾j¢ §VzÎ'(½Ö\ô–Y+@O_mKª…QÇ`˜È¼s¥WNŸ±F ò(`üÝ›=ßþJ”[ÃÍ=ÛU§2Ï®´}Lš+qO¿à­¨%’o®\•w6Èu¡%?fÇÙ?ûrãqC»Œà¨w>77¤ì‹AHoiŒgµ3.ëÙœ½R÷¬œœ·NftôºƒiU äÉ;‹Îcê«|HxÚ¼—OßȶB©ÙœÃ¦¯•îšÂ͘òÏgu=}IÞ3þPK»\ŠÏZfGé—)³Ö‰ÄH÷Êš˜—•ý g[åë¤Oë2jéËIW-óÈÜ-ko^¢]ÚÉqd,RÈöapˆ02™0JÖŽŒ]9—8dãæ(Ïd¸àœ¶ÎëW.ÌÔ-ïyfÈÒpÈ36×A2PP'?²håБþ^û»ë¬—AÑ8w‡õDÞα>ÃLLµ¶*÷…±:ÇøÅ…|q;²×=×™1äâ;gà›PûXiÎa;Q€þÀèÇ îíïdì€ô0èÐΟxög+Îxõ€øsüæ‡yÏù¹Î©ŸþõÈÜÒCÿ§ Û/ózå Þ/‹ cùü|¾-Q€Sâ>ŠúYÀ 3þÀ|ÍéÒJþžcv¹;û Pƒ½åñú?Q©¼z#Òùõ¿ç}úr}·Ã;1J“I Qt±ëª›¹üN;nõKÆìsŸ© ®ézîg/#{78'OÉ7ËÜ[/]÷Å'–Ù¦ãɹOO"Û2Ë¢hÁwÁzú; Ôm.J<ü™›QjIÙEdùŽË¯½\“¹.FÀG ýçoåÙ9|ÀzSÇÈ/”KúNjšóÑ8ï}Æ)½zÀúRÓ¥¿tÇ”Y›¹Füç”`SúŒ1OÚ€½y锤…‰¼=Pž±î¯Ì=­Êä6O÷!mÒäœgþ˜°§Ñ"‹˜ƒÔCBá¡Ä|wÍsßqðó_Í•-g¿Æ6RvT®´óúÕ/s>¥×ŒUÌj3]b­Uâ £5{3Ò–`-ç“;|mˆV¿vÆý™‹Ñ̪û:´ô7Ž[µÙô[R<“_/7÷¯ IÞ㨃¬ñZuaÜny8Ž÷Ë‘=¡Õ>ŒÙnËÚµ àkë‹`Q|„Œ-¹…sÝ-ó7óN™7í'gAßW_WßÎõ~>¾?œð°âcg°Î}›Ã•IGÆC¹Hv²¹EÆ#iÏöÌÔ~|ûQ¤%XM|ÇÓ¯¦„'פÖùºž|ô¹ ^˵orãpÞˆ4©û0Éj)7箨¶ c~Z•X+8O¤o6=ã8‘¦Ív#¹UãJºóÎ2‡; |ôwêFÚÖŒ³²MØ­µ-·º¶Ö¡½¥Z¶3Öñ´ä™cL“æœÜ¹É›cŒ¼óaÔ·qÎ9`>’ÊÚ©w¾$íHÜÏq­cûèõ;o*c7kâÒ;eJ`Ë[}9«^/«s&—8Ã1 %Ì4!­Cû´ò«¼Ðøó]«XòÕŸëu»mråœ72†UÙ;¾‚‰Ö>o¼D–øŒÑÀNé´ªIÝ€QGêSn93RiÀ7&pë«&8ùÕ˼ýìï¶ò§]jÌl4¼aPž0ýÔ@ÿÊ‘§cúaк€~âôO”ÿìÞ“×~qÀöÏOü,À=û¤?5 =ç>òÑ€ô0é_?ýo’—~^ã‹Ù_à]©úëë}—MÏqvzŽÍßòsw=· "Êi´/Ö½¦|Ú·˜{$ï2ŽËØäÓ;íáƒ÷U¢¥òö–ëk¯…F¶Ë¢+/߯rwOÈP_Oˆ´o¶à¦Š äï;÷7)m²˜Å@ú–¼§å鯜óÞ¿¸¯ÅÕ=­Ìâ€pOT…TÓ7TJ*¿ÖØ ýʹýöbÈóŒ°ÿH#Ï’Qkiw›ë$o] È‘ÀóÌÚUI¾Ûà&GÅí*Ïp _áu¤íD¶›kÞR« ʯQEÿ´sj¤¿4„™Ӕ@H[–P^}°¾RÿÈKOße×`Ð9ÇÒvØtú[D˜ów>óZÚΕ° ÈÜ\_›yoç·§m„)_*Òwží(L3ÖtФvœ¿öf@=soÒOƒW>ñꚯÿö!úÊ c -’ |!.€ÑÁ,60s®º1“]ÜÁO&o9>׃‚‘hÍ wÁ{(ÎC†Î¸dïÆœ€j±ù×D, [™-×wãj@ô$Ú5ÍyAÀ<ÆáÎÀ9;_ŒYqŸç?²ð‹ à-ûüÅz¯U’éšØQ}™ÔÏ{įk©µ¡Âz ïëÎùú§¨\Zŵ¬¨‘ÓB. µX¸öfWô0¶HKþ9†p*+S»Œá\ãܬyâl×.7ÓûÈ!BòN ¶¼ VOíО}¹±ÃžwY{û5†Cе™óÈÝï¯S)¹ç Äåu& p0ÏðÆ-ÈÐÆRÓÔrvjŸ°¯ÜµK¬y@ù×^[®í¸ÈÞ°3©h,ÉùæDLqÚ/s~A>H‹Û®ÛÙ^c¤‘.Ó³‚Ò?maÒO ¡Û€þJ™ò€ül“wyØXu¤Ÿi¹F&³ÈÚgl³è”R‚%‡#˜¬“SÎö¹žÊ«Ík¨–sy˦ÁŽ+¦œó€œ´a+çDÓ/3ÎXQI­·6C¶ŽŒ=ìx J µŒXb@¼\Íç\@à‡ Ïu ÆÓà.ðº·Óî1ï?€üûoô/Gž~Xðïýƒ¦ÿ.2ö?=`<¬ùÏ8ÿååÓ¨‡Mäý±§¯òÒÏùaߤ?|Þc<÷À}å\ÿKyÈàÏû®Œ½RvXò~¦ó=Àžh^à¼à^ŸŸ|öºÛwq$›‚ï.¢ s¬y¶Ú»H(Wy¶ÙßÜôYÊÂÁôÉU§†zúgŽd8×ÿ÷þ_‹A/Ãþþ9?㻊Œ9‹a,„˜w;¬=¿åÓ6º·õúÏË(ÎùêíûTW÷FË<˜ ¬' s_Ì=uQ9|}>ç£Zªr ¿Q“ܽùèN}‚='ú±:kLIsnyZ”wY6=û†AÇÍýõ•†_‹rÓóü%µL¹é+'}¹º³ØŽQì°è(ëÔ1“kÚœ€€q$ðБ¼3>ƺä _OC\@úì¿nŸëêcw®…Ä]K·CÂ$W½iŽMold{R!©›Î˜ÝÛ]ýÿW2xÕF_÷gnö¸n¯ù´<ŸrnMá¦ÝÁüž’kaÍ)­|ú€h˜oLÔ¬”N8÷›Òb‘Rå×âCºÑ½ÇÑþkåE(ýÚÚ¯Ð8Òî´òþ#:ü%ÊOIþ¾–,ý©x{× ¤4[[×û61¥`âëëûÕ÷^ù«hÔIl¿ ² ô€on°ç–à|“w^PÎ H7®¶5‘C9V$1å ÔExó„²/Œ¹K­µþ%Ž˜…Îëø™›x·ÓÎqSǼî¡íÛ0î%äíãFºÆ60Ÿ\ó‹.§<èÈïš„“@o«š§yÍçn"swy–äK"W†¼uÎoel¶‘Ý…5Çž±L6:ŽSûô—Ô/!`>-“íöÜZ²ö‚÷LÞÒÚøg³ê0äôÒϵP^‡vç›7ikCds¤Œmp®hh¸r?Ö-_Õd»“ó2ç‰Ù–ó3ÎìHÙÓÒWýfÀxÁ7Fp˜d•Dö ûX÷íÅ”ƒºj—b©•Mò‰Ñ ˆXîv`KÛéôŒ+;}˜ä%oÎ:foDA-çÎÔ–A?rô¯ЯÚ8ìø'rÀø€ò'žýå½÷=ÿ뿺÷ägN<÷ËaÖ? |AzòÒ82ù”k;9ífþ˜Çþ×Gî>ïÿìów÷çã½—Mïv™mü%ƒ9ØtÆO›}Yà˜mŒáúÝ×`þN9_€¾>+¹Âgÿ%Õÿ78ÀK•ƒ¾?@yÁzÚåôîíüFº¸U¦iûü~[¨ª…‰§ûö1‹»Àª/Iû€÷ô»¸—&§÷´2©¼¼ðˆã{ªOt;½-¬Q e šY Ýe-×Âiïåy¤¯:éÙÆD ¸ŽY NXò¾MHóL[ ü¡k7Ù&]`Ý%׿ØÎé³05ÏfGŽ1£Þˆ¬¶Ü®î”]« =ýÄfÔ6ŽCâ^ ;óžä¦_ªÞySú9 ~9:Ë\nu0¸ºcœó`Ðg»äNÛÌ9K…ü‰z³sÔFH"Ì©ƒ~BþJ•À—ĂЪyœËiücyi;o‡H›kNMtȺÅ›!Þd¥ðœ%êȰ…©¸Ep½€Ùö%Iï{c ¹8)ÄòþRi3×`ç8Ãu|]>çöÑËþ„p+XP kÕc·/ :À’ïžØ¾?ÜżÿøÍQníRy2ƒk ç|ü’+œÐ—¾˜~¤äÚG¾ûj,À*ïÉAÞ8Ò«~ëc«Œ€£ €ì }jŸã䈋ûÀKÎ]À<ñü”„87 IqÈ­aup݈v µÜh#à¾éÊUýŽ < Ìß­ü"€9¹ç”VK¤OÓï]µM캜€óŒ;cÐO¼a–ÂJrV‘»÷á¶\îíçÚäý×nm)×¶¬’c§²,-ɲæ1Žƒ-_+öÙ®ûì6¹Ih»ŒAä~åLXFæ¾K×ÌñÎA×ÄJŒ¹ö«öùbÚ—lúÄÔ<ð™ó[&îì«„Ðkþ N•"Ø—Öl•£Ç”â#wÇuKØéïÉ|B&p‰÷Ú<$Ê®x0ß`<}K™ñHƒ•ë[°§ökÀ’œ¸sæ·†9L9 \Lwú„j—ôØ7¨DÃŽ+0O;Îþ}]åsýáy¿'S>9èýðG@? zÜt<óŸ„0þ‹€ócøvâ´O>÷«{ï»öëÌÏøg~q¶Ã²G ÿ“HãXÿá¹V@ú÷›þísíHÞ¿zÀyÌãþêÞýþÒ½?ø³WPÿǼõþð?NTÞñÓ"Ûçsl/eç,à΢FÍÞ¸o'ý7þ¾°â,¶àw[eîçË‘_ ¾Û¸¸ƇýÆ@ÕÇzö_Bµ“~·L{ÀzÆ×ïðüþP³àä£ó»ÞÆfÓ€'"{_÷î#€x›Ämw÷æoûþ¶™õíâ>2w‚{j€uS’ Ês|û¹/³¯îî´ ž Z¸eŒñ>cšREPÝá0“¾zZ«ÐH›°i\¢cà<ì9‹ë#iÊîä¤ßRÉÕ‚öìâ0ç˜Ò6.8¹C.Ä4>@ù2Åa3Œ:æqÍ9wLzއ9ŸtÆU}tœÜ‡´!ý±éðÙw"¥Ö:×Ti5 QrÏÐ¥0m@d 8O?sí#cÿ‡Iÿ¤ÔÚ”@FêÞù{Æ Òäg,Ñ1bÉÂ%Ï.Ó[Y·€$€·íb”Å'l& fFÛ•½.šÌè¼u®íŒóÞ`²wê19÷=W€<ˆÀ9ù׈ŒÙ;ì2îìuߦՈ À-ÕÆ¡ýÒs±8½ùµß+(«î¼oï÷§òdË@À1ûÜ’d¬1ÿ£Z>bÙGóÔå@È÷„¹]Kð~0ŠÈx@zZÉÞétrϳ¢7ñÀ:ãRô{pô<¾OöÙ€.¯çüóeà'W}J´áôÞ…ž´uûg›xÿŸ½¾œßë«mÄ+¡À]¥ÛVE¤í+TÍÂïP ikû÷'mÅ‹s^ Û ú¾¯l93è ©|6@Ï9¯¯ºé_¿Ý2“âêí'͇û(*&Ý/ç¤ÛDŽày ÀÎó#ÏÀùç6˜oŽë³ &½~)yF¥]þ+g,m¢µÒQ e}¯g{ž¿—sÒy~­‰Î˜ªº8^Òü¢&qíãðþ¢%îMÑËø}ϼ–yÎ äí'š“žÿÌ⬇=ϱר¤ƒç=Ìëî”Iï/k; œ¾«I™‰ºó¦qe¿¬æÌiÉOg^< <íñaº¡êGeÒ1e&Å%랯¿ý“7P¾^I{sÑÛvîÒnÚ`)ð”p€Uä)•½ 2Íb_.• 62žªX«ä´TÑ’À;Œé6f¬ø©iÖÌÚ8VÀ²™qs7R™À/\«¼|}w¼N:+6ƒ‰v⻵þô9^ yëäéCúlYDÂ勒÷–-ëutþ×Bµc)ŸW.îHø>ôáˆ!ß.C EŠ~­õûu>Júg?ù+Ô=c5ϯnèô+KÇÔb3çÈÞÍ1ïÍ‹}é§¼DrjN’Û3æs«´«š‰9f@úóUë’¨„öúú2‡ ã.Y{ã¥ëê¯L ¯<ãÚއܬ`_ЇcÚ®loÎÃö=Ÿ¾‘S—_)ƒÞkÉMÃÖ+ò{› w"Œ@&)eÏfbÊ3€ú rÿyáÖôç‹EŸ·L¼:‰:“/À95X–DL3k>€wvËÜÉ1y\dšH3³~wv&«íßÐÍJÚ™(‹1_rUØ/1gbÎˤ¥ 0/K‡¼}r__‡ùKîìeË1½ r}i°ß¬÷0ŽÍ=îx€Ò°¡äŸWÎ^–°L}‚šåÈ ä0Þ‹f¿qgWÄɽÀ±Àà «ÎX˜qóŽ)ý¤{¯nguÝù2iUP°ÁÆWŽ/¤‚Ϫj5. UBmŸË6¶Ï)­e’?TÔи N¡*!²M+U î9ÞûñuNçxÇúijxUFýc깬õ^÷~×zÆ3ÆsòÍïû?] úßÿ>ýùè/ÐÍ ¿5ã·Ôçøi~úèŸ$ï?™°ä}\àÅÄÏ&Àäÿ`Ú˜Ç Hf@ú?ûúÄŸÞ}êì½3éÞDÐ÷ÓŸÇÀ]¬{zÎÝ*„ÎÁ¯|ýÙôà;Ç?ǪH'*º4ž[àS¿>>¤I`X¸rÓ;ÚáÏ<¤pqþ9ÀPn5ÊQÍôyêwbè踉iýÛí2ŠŠ ÒaÊU"×—ŠT– 0–ÛÕ)šIG ?Á\1è\WÎ;œ—q'¹çê7‹þȵsʲÙNmõIsr{•TªƒÍßNÍ"?Ó¸¤ymï·vxç^ ƒ¾€ûƒJU;;)kô­tcóÝþ3 °?pù–úfÒ—Ô~€¹ÂëÔz+r,&¶½žY$a]Ì9¥×Nfº!HÊå}ö†9ÿ¬¬Ñ¼vS¾yrЛ„ ‡È‰ªò~­‘ä²®DâBhÚ€uƒôé¯rk¬a›A¬ë9½¾º@»Æêwmtʯ5@‡AGâî|ó¤¸[T]tÏ˲aËø¬L¸ÕR·›óë¹HRpPW ƒˆ<Âb…Ã’\x†½âw®X)ʰÛ7äõ]ËìÛ$-¤rΫ÷ƒâo+xv˜ÿ`I÷½‹Ðò‡£q¹¿³ TùãíªÎëmæš/;ý€híøPÈ¿Ÿ¿ÿàë9?A; ƒz^Þ¯9òõS ]­K«Î1@F³Kª+¦ËÀYÎU;X¦]yè_”ó$ÆpaÐ)­¶w&}Þß\ätŒÝIJ©ÅçÍ1Iíó¹ðêÜ\|5vÙ ç6åb½™sƒvdí»ö¹ç¯fÇwÕ<÷M„Ë–ru°ãÌ -y讇NÞ× ¬s£œÐ˜¼ó˜Ã‘Oæ:¦ÞŸŒbª´¦oûFwϵ œbÍMdñ‹-÷‰ÈØiãènöa÷¸î>6/©¡Ó¯1€=ܱsÐ ÒO¯2jŒO¯)œ»wÝ ;ùç^Dª¸H%Ã%Ê©uYµ9åùÈ Þ)»d†¼S¸_dñÎâ~æ–c4}˜=äë˜Ä‘«k0žÜò/HÍXVýr Þv9´-GhaÖæo´œ‹ÉÌnº rœö(æú|¯\fi:6c÷™‡•αG'W\l6½tô+aÎßs¸é_yK@]1Ç5/°n€>9ëzÜ<‡rØÅ¤ÿpòÒÿrÚ7Ò‡QÿÎõ?Ÿ×´yÜÇ'/]L;`\ï¹7ÌõYz‚¾€wúo6K*ïݱóÿ‰Ëui lÚtù·K[÷£°Œ^ýúŸVÐ×oÃïGmæ4Þy鯖Ùb¤ï ÍÊVɬß,ª—Åš;Oýedð yEJ¨a>ylÐ÷õ«™ôÊSw¥‹p¼;v ®ó–t'÷ºNS¥£™sm›½a$0°Üêß‹C»ÇÓO«ewß÷Ô®ÒkV~Î}ÏKŽºBý´Tænîq¥¢Qfm?6éY+˜g½Pòw@ºâ6k”~š; 8ns8· °S¶|ú–®ÇˆwæÝI€Vçøø™‰—-y_uѳ. P_U~"q·*“œt@û-+?aеVÅ,NmE Säí•êù Ð;5rwúxHE=»ª9©U·S oŸ@• p.\R ²Ê‹¥ß,}JñÅLslÍ…|mÇósqÞS¥I×çjUõ¨‘²+*§¾*|¸÷÷R¯‹ºÍÅó=Àä —}¾Z=Qêwþ‘¸«.\Wò¼Ó’û°w#R—\mdÞ£‡í¯Ü€ðÏëm G³ãØêÃÞÃZ‡-_ =_öAý÷D½WrÊÏûŸ¨<»¾çý~ÝÇÁQß™~ÄàbÉwË•sJ7\vîùÈgt®úŠ\ Ô¯Zçù"rwŒ0`Ëýœ+4^Ží:·%îºb‡¬]Kõiqé´QÜUóé ÌÞk&RkfÐs#ø.ýv¥çK´ÍœãÜÎÇS·”R#Jf¶\ÛÙíæfú ¥gvkÝ7Û•—¦~"%Ób@óˆ¥tÜôq™U`^óÊ* Ä\sÀ9õ`·œûy7 ÖïüòcŽc0+®‡> Ü@š|ó Ï©ŸÈbP \lMÕ6§®¹"yé-e«Ä”`Ûl”Y²Ž#»Ð;7”k ØqZ™G¥†1 ÷ È#•U; ÿ<ç¨oNø£õ°í¸²«=ùåîìÌ—‹7¬hIœ}žÛ‘[w)4@¹XrµaÌuÀð5dÌfÉ‘`¸L7hµd]ÏS`I;`6¡ó‡Ù~CL¶œÖÐ'^V}úþµXpmåŸ|‹-?1çÌÏÞNœ€ûS×Þ›>}÷Ÿª$›óÒÇá}rÒø‡™ÿ@º6¤w@ú·OŸ˜2l#wWÞº¾ý½ên‰=†AŸ@-ÀyÂýü%‘GÝÐùû Ô«ÖzXqÉ×Û›pžÇ(k>Qÿ“¿Õ)~™G!Rõýù] wïòkŠ®¡ž|ó¤Ÿè±¤¥tìÍ:WaȸKµ˜ÿ{òÒǡݭ+LT 6µ˜É•ì}U©È&¥MáØÈŒò}…ý@n”šÉãî“Cn&]-^#>æÍZjÖöŸåäØÞt.³Ô´·™K»Ë®é\ߣí€s”nKæî¼ór˜õHÞãA“µ‚úÙ̇E¿½óη)­b Ús©{å1‡Ó8é‚«üÚýZÛœç¼ê+6c^&À[YyfÖÝNï&yî7³N_TšžóZo$‡ÇT2!…zÕ(òw¤í Kᓟ¾ܯn=)¦ä¢cðLôóô©‰n\ îh–{c©¯Ç t—M¢¶Ñ7¸¬¤õ&ÞàK€w{˜uJ2Ä-ÇÉgÓÀ\ï£ÆÏ0P¯ïývm¿­ÈMNΧºùigùýêž·);ÝôçxÃ!s×͘Rk×鵯ã”RÓâ‰ûŽ%g§Œ lp”Sƒ]Ðã. Î;·<†pÉC¸Ã¬;xLœÚ;ïÜLj#©$†q0ä„‹3¿“f¾µxõñU÷WDz]Ý›¶ó8i‘µw­sx-¼‰Å˜k®Ù%±-a¤O¼º@8, €dÍÔÒß-u÷8 `EMëåÔ¾|›}0÷×8¿ÏVÈ 3v®5çÖ [cµÄWܘÍÜ€Ö_øÜyO @] yâ@ÿ7ÿM ¸€¶qƒîç#eW;sïÜ}úÅÿ¡ÐX!†}Â]îîé—6HÙû›'þпøÞ0ê¯HÿÏéο9’÷aôGöþ›×®÷è÷íï„tù>* €cV#ø±§ãHüûüúöxm»ï¬'8FZu×sÇ`Î9·¤î]…€Š Æ©åŽÓ;å ¸ûø •g;WšJÊ &ZöîóæÍ°;'ýv]{|]¸ÇKã`£Ñ©5ñÚxãLµ¹F¢:Z9èuíM?¾ ò¨Ÿ(ˆrJ}¤í„ï°çs|îŒôõxKÚ1“S[÷󇿸Ì9ºìZ›ªFÚîV <á1Š3ˆ'r×9%{oÏúéµ–pÊ\ò×-k¨³FѱpóCF˜EgÔ€uë±9îô¤f¾@ù5)#YçiÍ0Gò¾eîäžï˘ÇÉìz§af̃d·f½³ŽÄ]L:ŠS·¬¡[nì}j¥Ãœ³–לÖó”V&PÔêøqnÆÔ4/Yý Àp=o—kãî&AKr™Œ¢»<Æèéükÿò3Àf©Ä;5ÛxØø´*¡í÷x?4ØÛÊjØ|$îõæ©ÙÚ©Ðå øí7w,uà z·óC9À¯}þïî óÜGÌ~œ×ùÍsê3®’lGNòÈàK^QçÕã—ܤë¶wy¸åÔ¨b:fä©èXʪ•Ô A=t_Tþñìеœ>‘uõG¾þnŒâ"i'ϼeB-moЮ rLàØ%o§´š=W µýÃwaÏϦ/Ü^ÛyèÃùæó€åð™[ýmjâ硜Òv³æÜ´Î.2Ÿò%ÜøÜ ûæÈM`n©šÞ˼?Íq#.°N\'˜‡I'0¬AÖž9$îYTT뜺–ûÁž»%ÿ¼‹”ZçÂŽî˜À±+°C!sЗŒÅ"2ÌYPzùºûÞmŒ„#ûé+góË€ïvQ¬/@ž6vÅÁŒ™UÓ¢p~ñŽ‘Í®ç;·œ{ÏØ Âfp>¿]«Íîq, ¥€LÕ.ßRö•g®`L¬»üY™ˆ 0'×yŸç|óÉŸ·ðnÞ2wÇuÞå¿mÆp.ÐN›~ºý÷ ?k€.†ûqôÐ#oWº˜ô§Ï Ð'¤Ç<ÎçÛá}ÀûߤŸŒã>51 ]l½òÒÒ§Ûwœ“þÏ¿1 ]ï_çøY@úÞÐØ@Z}ö*)ǸSr\cý-|žÆ˜ÑÙ#I{1èûÿ€sôÄù-yos9þo.Ë€®`³Is–±'=ÿûúHÇH.æŠä  „SŽÍ}×N_åØªìš‚>sfÊ‘µWP¢­zWŽÐfä¹ÚÍ ™vvÅÊK/—wõKò.‰ºZJ§€rûЏùǫ́ûÞ€ª*@˜Sî¹LàÞÓ¹”S;®*âÇÌÍœ{Ü5Ñíñ¢À›°Îxç£/6€1Ð’õc ¬êÙE ã&]î–Ú•“¾Rç¼V‘”“ZGޱ¶9ôÕ1@×zÉyè•Ùá>¥m9`®ùôWÃ_¥9Б¾ÇL¸ âf]*Õ¤Ö˜š?IÜ—jÓÀüªcå›_aü$îôk^›179µü›µ'Ì _ {Ý“®ˆo”úfÉoª=Š`0Dl‘ª…AŽÙæ%y?È ×<}ØgÂç@ƒÅô8Ê›8æsl¼‡ú»ßo¿öqtî6Èû9yŸßÑÕÑÀŸ<—•Õô<9`‘|d×ÈЗ|à w¨q'0ï7žDÿ.Ývôeç1]ª­k³/ α~Þã?P#Gƒsp?dáyÜ2ïëÏœšçìžù9ÈMœ¨ãI^‹åìÔbÔ8;vÙÍÛÀ9:»†„A;yçH‚(QÁœ[Ì9pÐôÜÙ=°žüsµz“›d=¹ç´…`—yË¥ÊaÔ§…QçFÑÑ :Òv÷qkŸÈÎ2`Ý®î•nh)šwÀë0äò-so€®ÇpcO]ó®o®|Ìk»„ŒóãJÚ^Q`ݦ<Ÿ¼|s³ã ƛ需”T »Þ%ÕØ¯¼rú×ÅÒØ—l“…'ìP»¸wý` –Üö¢ØæLÈM³ˆ¦-y;l}1é)£“*õ3.–|.îš3˜X2ÝÔ.tì|Ü—§^¹˜)P®s§F¹K¨8‡%_ü5Àl) J縀g®äë ÷‘cwÞ5€Ñ€ºA*t]¡×…y6Ø_@€>@økà ?üì÷î>ö¯m÷¸sÐ\ “ƒþ³€rºc@»;'Ý,úÇ ¤Ël. }ÀùÔçuÞ`~2›×ÿî݇m'™»Ìë¨Mç/öߟ‰<`Üó÷XòþþõfÞÿJ·ÀÃÚ«ˆǵؑ½ôóÿ•”‰yÿŽRwèܪŸ®ÇÔÿ¹Æ]C  ¡B,yRK*Ni'tdíiùÝWÏÛ@½sÏ»`'Jî.•lú+nŸÌf(¤ä —Ä]£;¯æ¾G„I¯àž ódºï5–’¯®¾Ûmhʼ\ß—¼]ãUŠ @®o³Uç£Ê×}Øóæ·0{ý`Íö%qwææ´6+òåñ­aMEŸÃdB€¹µs{¹çT…+<ŸõÕÇ(‹ ame0ôÂäOàDt­åç„çºÜZú.Ï;ŸÉÏÑÇ\Èq£¸¨>užMäž»knIºÇ;ä·dÀ~÷öÉ?ÇpÙ•“¶Ôý*@ÝwøªÀ4­äìcøŒšœtÇIšm™ù!è&PC—á7Qã­NÞþ^Ô>s¿UÑ¿Š¿%âM(CÜ6Feã€÷«çÊ9ϧÇô[Ò¾LÅw±Ãï’󔃞/©@Aùvg\ÎzáʧÞÞå2hã9\åùmI¼ `DÎ]Ñ_Úϵoé?íÁ?{¹®|ùw[ÀN“ÚRPã~ZÊ1È7ƒ®¾Û?,³6$5D›ÀuMGØó Ò]nMÏO®Îe.j+46¿ˆÄHó)1çÎÅ y{¤í%]Òn)Ò¦ä+ÜŠ ~íÈn·PE—YèŽñ‰@y;•"÷"Ïüô˜snh»¶¹n‚2[)&<ó; =7‘ò€î•oîó1“qT tKÛq‘ۆpŽùvjßFqËŽ…Ëb;7–F‚(iûñÂhƒñ€õK[æ8±tÍ-÷´z²ö‘»«TÛ ìÔ§Vú„J¹ Xÿk•YSÉ·‘Ù¤?4æqbõp¶aØßèÏåϰ”bÕîc’çØùê´ Ô Q.¨DÛmÎQ`ô§óów†mG=ÁÿöSû´ Ù¢´ OZûî;V…€xZ3õaéq†Ïo¨B¯ÉïŽaÜü6cÇïsÆ«.úSþí¯ß»¯•‹N {¾jªÆË@ŽÀør1èî£&’/fš\3ÿÒ¹6:s¬”K»ìš¸¥íjQB!sOƒñÜìs/‘‡‰î Êæ”fó|›Ä%’’õdéÓ·jØu§sÙõ]}—U÷ͦÎ+½ì¤PsË&û…ÂŒ÷ÙE»¼+ìÔ®ó`_²ö¬/^Æå]‘¼ótÒîè—¼Ã[…ÆYët…›aq‡€9WKÔSŽ ]q¦ù]qg›ÅUɵ‡®0éƒÌ]®îö>R °ç›Qò“èv¤í«´prÉ ÌÉKHOµ"õÕ²ÆÆÅÀ'Êkwµçµ¶» žÒËÂÂ`…-¯2Óô!7£$®ôäÅj{¶›cŽ6¿ÞýV0Ù ¾±ç—š¹vE±âÌ+ 1•[¥ÕGx±æù,~L½åÍWÂzKÆ÷øØÍ®XâbÓ-‡XIô½ƒÀÎ…íë=|Iõ0ó`|å¸/I¾Çí¾®qåä§Ïs5g®ÙáóñØe·Ãà<Çö÷Ê®›˜·ú¿A™Ê9èÂŒ]ãõÌäž#qGÞ®×°ŒÇÌxL5VIµäŸ#o_²v]3Vßì9UqU{ý]õß¿¬‘ãÔ;Wë‹=%=}£ wøæ¡¾žKmï&ŸXö{’1äï×/¹èÖr_ÛªÙóv½àÎúÿ’¶íz©wÔê†î›öõ0ï€rçÀÔå-m—C­ú òï*”Ÿ×=ô»Ä 9Åx”wTnºžöÅã8ºëyajԦߦpÇ›~˜›)“^fpéÛ®™spŽ´&Mv s9òÎ;¿<À@RvÊ©s®c3K5ówŠoðâþQ¹´DkŽ;{ׯ.ɺϼÕ›±5#KÛNí‹é •ü:ýfÇ I¼P}ì+u~ó9GïK]rò2‰€>`Ú÷§®ÞcÐÏÞð- þ³»ŸþÒñåÓNüÏ„€ºçO,;æqbߟ|AeØô\êÿÊsH—¤^ïþÁó¾/‡÷qvÿz_2“Ü]frzïõ™ZIÀwP ÷’½óÝ“›ÞÎðëïÇ{}9íÞU_KÝÖ‰öT¤;¼áU@ÝóñzïU1“8$ïU?]ç¼ÚLºç¬{#ïÒ\ûÌšŸLæf|¾7ýprwdžj\ϤÒÜ{\çŸ3ðžuÖs×EoGw‘7åy@7x†5¯p70§ÌpÆbÈ)»‹>á>eŒSÖ¸óБ½ï5=}µZ¿›1§º`Ž;x— kÒµ£½‰Ù-Ë.µžÓLt½vçõsÏëüÀ¥Ò:Uº^ë ªY¥³ÑPEì6èç¼Ù‚޵Ƨeª£‹ôÝÙ¬·‚94ùb‰¾¨Ã’¦üaŸ‘IT»‰=ïk;ñ5«~Ä|·tÂíq3ü¼>ßrˆ–dè\½žp0çe‘Ý2rUv¸&úÚ•S;N??ÍåBðë#…I)˜t?®Üê·ä‹» aй0V‰µJ5s‹9G¶D™å«´@¼Êxèxå™ß÷üÍ9¶%W)¡Öò-?v×=çF&®í+ѯÜs껿ʧ¥~ªçuS®·Î‰<÷ ïÒcJó ‹„ék×_`hkþÉ—/ø­of}ÉÞ#‹çúR\®k€ó´”~tA¹ûyêº.’{î¼óbÕ›Iïzé»Fú©¿®éž½gF]Á}Dc¢ºÇëDŸ*#Dꯛ1ßj±6‘S{ÃJ´´2y£üZ˜s\Ýç~¾ÌãfÞç qO°/ðŽk»Úö¦a=AEÇ2¥Ý%_ï068_ëœûŸ» ƒ®€Y׺ˆòj˜éª50w«0(Ÿ–@Î~ˆ”]iG}s”’íê‹Ð “Þq¦¸X$‘eîÌÙĸ€y ªR”q@xEæõÜ^Ë€yÚ’·[åJúiˆ6È7é#mÇ£ /é°yÄØ<·àAp–Õ–Ø“ž{DV¦T5XÈ Ûfl¤+—¹ËÀ-üR—öìóøž¯(̺ñò‘C|¾Æ†½A@‡f?dÊ;/ £w-Ú‘IA1Þµ›±Á3óH ̙ïó È÷?eÉ –‚/­ ï\ª ™ýz6Dè憎«eWÊzƒt~¸ ¤«ïzèóøéG:©{ÕbÔ\À¹s‹ˆu÷EE’u€¹Çîoi»;»‹0çž«rj\ÏpÖHVȱ=; 6ü¨òÒKÒNÙŽ}Ì7$V€õ˜’À–c§P;’ö/y>`|•5¡?¼}—E1£î(7cµqf_yh]’…œµ°æÊcÓqÄÍžw©˜2‡£äŒ]ÝaÕ`/½‚sæ1È×aH4¦ßÌ ýyÍôÍÊT˜mAò^l9cõõì2wßRÛ9wÎ1[Ny5rÈ„Á¯ƒ¹–®ÇýšœóÚÃz~ú• µizNµ \¸Š!wÀŽ[x»„ÃÖæ½G~®Í€2u£(]_@5}E@øçæµÖ­Àú¸¸¿!‰»ú³èÿÑ_ÝsZ QœºÊ­…A{.0îöìÔ:”þÂ[:GçKænöýìí€}ut•a›síð~éôº?°.Éû ç´qðÞW ýë’½Ïwõî–î; ÷R ø<sîJ @ö¾Û­ˆ žz™Ï±a‹þ)Ö äífÒKú. íå×PQ­Ö@Ü}pŽ' ãu¢ÅÌÔÌ›=·?Kî}ºêÉ®~r= 4Ôhe ·sÑ ˜?pù¦Z‚R¨ëåM‹îµ…A9ë ÚÅ ÛÁ}Í%UÀ@޵OåŸCl@vx §U`âËú9·HÚ;Ì’ëÉØw>úÙ6ŽKZ%9è(8§…Pr¹µ”¶\]ëZôíêN®úR¥ê¼DÖÕµoÉ»¯*¡–5½K¬%uõŠA¹Æ:G}a… §ti°ã1pó¹`6J¶5ñx‚iƒáÝõúÑÐcðí¶Ê½­×/vIË/¯q»Ä3ç~›ÓíÒá8½ó¸–õs O6LâZÚ^lú:V Ôá'^²õõGØt?îç™/P PFJ߆š/¹Ã»~,) &ºƒ/ý(O½ÌèªTåÛº.çƒu¾ƒä–dglZú;ôãÅ<ÐNîŠÁú)ꢰj5RZ9.@ÈÜ+JÚîÖ,ù–µ+ªcìq¶¥Iæ”٤æûñÚ•“ûäé´ÙÍÅ^ó8ªÕüܨîþ¦v™ÇTe1åç”Y[9ç1v!È/Œï±Ú°è‘Äíè\sõÊ}óŽ¿%vHóîî9——=ØåÖ¼¸@¶ÞÒÁs®Çä ²¨ªXùèvô%ß¼âX²($ä"¬ÅcʧéܰågÞŸür€8€ÝŒ<ã*côi$¦•¾ÎåÉ1%:tn·DrÍ×±H× ͬ6ðöX »æPv"[G:œc À5±ŸžÍ-aÞ2wwIÔWæ˜ `Lnúʧ/Y¹çê 4rÜófÚ§Ï8à;`\‘¹9îsÔO ? w3èô/Zâ>àÙ úµ¨ž¹¿Eânæ¼ãÅ÷w`ÔÏ,¿¤Ç ¤û¹¬O\•ËûßÌkþxòÝO }úo¤Üý‘‘»ÏæÁä§ÿùHÞ¿%×ùaý¿z÷3/ÿ¯|}®|§-q°çû€;ó1€c¼K¸‘–Àß´û¯‘Ÿ¾À÷ì Ò=¯Í l05‹î¾þ·ÓïÿýÞ´ hïò„;*‰{¥¨h “þ*.îË@®ûuMÑu&þnaÌ}­úE”>Îæ$cj¦;ªâEÆDv¢tZ(_Àœq⤺zO›¸Šm"š{Q³å½iŒì}õéÜë(1šÍjî…HÛ×f7±¼`RþTÀÛslº§E—cÅž—ql€¹äé]~õU ½¥î^Á˜»¿Á;wÅ}ö—o‘õ—ûTäY¬ùýÎMWd^,}òÐÕz-H>z3èÉK $ð-ï#P€tØsªO¯Õ¶Ì¶œðZÚ}H®*'%Ý4¥ŽÌ£nLq³”±èrHÛà„`˜ê´ ÂøF«ð`•#+?²-_Ï90ðåõMtRN­Xé*gÝfÜ›9oÓoÜïËŒïÚåúõ!†9}ÞÔ; µÈn't#Çeœã]> 9B»ØBë5ø‡2ƒÚ88§¿(äU3ïJÞ òå;= ¥"¼nïžè½À¾ïóЛ=§.:e^À,îÍó¯²jHÙ÷’÷]»1¡º‹ó=ïrô1É€%_aI™ô«\¯Üó€rrÐ#e"ßÜ-}Ž0çÂNìàVÞ¹ë¤3¨çFT.¦ÌqcSþ9]q[ãÊ3W?íÇŸ¿ék‘ªÍüª{î{,÷ןFž[—s¡zZ0t¾Ò¼-cw^ž$qµ=Ê僭PKžyÀ[±ÊçSˆ!ÐZ¸u„u K£ ÿœ¼™GÊŽ™QòÍw sƒøÎÍLMt—Eóùµ¸eL­b3çY ‡á s¾àt,säžo³)³æ©«¼rZ_…¹ëç8ïˆ)VçܾÚ`&@GA sjTcìã7€TÚb=aOOñ™aÜo€t· äÔžOMn—ö²,Ý€Ýí¡<v\çh´ÿX±€7Àõôú¿Î¥ïô\Ýý_Á _Àüä‰Ùþïè’¬›)7H_¹çégž¤‹ ]ýy~µ3ñ“ÉQ6] ý¹i“`6 þr$÷o Pÿ‹ÉKÿŽAú3ß㸯Éá]2|Näþ ÊqzwäУJ ­€Í’ç»LÛ®]ïV=)Ÿ¾~E†Zÿïq^\Ýðl.¡¡…u_¿‘ÎQ_Ê’bÒ;­Ä¿Ñ1‚«ß.-m°æDj¤?1 ¼A|Xóª‰L9¥½y¨ L9¾Szf¾¥ï»ê…yU’¥ð”[û”:€Ïµ^ç ”Ú™(2w_‰BŽìWnm&}æb*‡'JÝÇösW.ñf5ï‹A×±€ôä§»äa&üvuuIÝÎæD»¸÷ZÁã“Ò¯îÛ€nžõ‹"Ƹi;£8‡×WêwMtKÚ¯ ¤§ÅÅ}r×ÎÕ÷šðÅôJsÔq½ŒùÕ•6¹ÌŠk]ÊÜ*<Ì9æqU°æ0ê äí¤Ž6`ﵸZõ-w7P¿²ÝäÆ –»£¼…Ü+‚µpI™{Úò. 6}¤v^¬¼ŸlÆñC^煮ÒV=›EÆR¡¬åõ°Þ ¼[!ÎæÄ"Ÿî‰òG#»¸#=ïØyÛh·€Æ1QÓ›*pzPGœ^£¾µa€üÞÑï—8–¢×k”SaS9øÌµM¿¢~3ð•Ÿñ¦Öûú.áüßÍ®˜Þƒú‘®+ÌÝR=±$í#‘‰1œ%7}Á{çIrÑ}!Š‹ûÌY¾£1.—êWîΖ!1¢Ïng‡Á»bËÛ÷0N«ÈÅÝz=†][ K`Ìw=Oßlè#o¯Ðü’‹iÞ-Ái;»Ü ±éçÜh‰—É)¯pÙ4uï®Ã’ÖaÖgñ€C{‚z®ç]㜺° rÏå¼ëÏE6š˜/F" ¼ÝÞ À½vŽLñßÚ«„Z×;ïœFÍ_¤knÕê1y’iqª…) ‘Z¿­>±ü–³«Ý€œ>yçË©=‹g@¸úµˆ—,0NÉ&À@Ìúm³zÀz@(7è o×ãšrhg~ú”Ȃ݄ñÌ<Á¼yj—¯R\×|•A£$XÆGŽë0ëäHëÜ ÊÍ–«U,ð=cÂeÞ-}KÞ‡Aÿ/è#ÿ3ôa«_WººtIÜž ¢Ÿ{.™:Ìøu³åbÍm§ÒkœPß’÷«fÒ‡9ÿ±^{6ÞH׆Á¼·ïŸØý‡˜ôg¿-&ý$uÿÄä¥ë\˜t7ó½ÎwÆß‰ûR(¤¯àoäsµqBi6dðÞ„¡Lž@·úe*çˆä½æ?sã¶Ú€ïÛRxÀûfÓÈQ•¤Æ:ÕÄ`K%‚jÅ¿=ÆüŽ] ±ß3&çœÔ—u®fÍ Ì}Îä}9»?Éun—ˆ´æR ?Po@~ƒÜt]o5—þ“ûº­qRáÛgÄ}bËÚëÙÔ­MáG½±œúèïíÔJ_l;®î ¨·Qj±æéÜcQ¶åžœû´¥ëçKÇÆ»Ïq%UïÀ¨øÕÌZÓYW•™v•t]*¿µ†!uOQŽî^­R´j£DŒÄ½™ô¨‘¹ßó*äG¾ðw¯tE‘7/fÍHù]òÐJY€ÜHfÒ]þW*Î.ÌÒŠjFê8º¯ôN%¼™ô›jw\1‹î4Vj£—RÖ`®ÈXfrÍ*_Ðù…wÓo¬c8òÍ«ªV›[Cúæ¸ÎDÃä<Ôô0ÌEø±rœ/–ò;xPíRy‹áçs·[{±á vLêcÐ6Ç>ýýŠeÅw~zIÔ²~Ì’3¸¡·ÀNº'úœõöÜá˜hÓ¹õšžïsûyÖã+ðW¾Ä~ zKW0†àŠã£ØtØs¢\Ü?væ°ä]^m±çž‹§Zi»ÈURm_$)«6}×>‡I[ÚäÖ»¨0èÓ÷ÜF#€t;°‡1'Ì’/‰Õ–²çó^@»ž§vsnZ6ZÙ zr¹®qóûÄ ·0‚›9·Û,®zïŽc"ã±oÚ>Ç7t hVàè.о8¶ˆ§_εt@vÇÊõÛÌ:s'ðq—L«®qYHÙgq•[Z"ÀÜÀ[L¹~+ç8·Íðìšæ„|œŒ—|ýÒK:ߥÓt¼ â|l> 5‰éãÂÞFpܳ@¯ØL[Û Ð‘Óvnì6¹ˆX’ß8¸kœ6Ì8L#%c̸ã„_òÏ®È;GÆ^ùÆm,vÛýÍ”/3ˆûø®ãMûOæ1€Ì ÀvyƉ JÝÌØO¨[,×w3è÷ÿÓ¯NI³oIF>ø»ÿêdØvé~ŒI\»¸Ë(.ùçê/y»Ž»üÚiÞ°×1òÒ§u ·€ôŸšIWNúó6›÷4,úÒÇ<î{6YþƒÏ|c6¾>Ær¯[¿?oú xp˜;ÁÜ#¯²lŽvå÷qIéÕ.UFjë#qOP¦ÏÿÇþ½¨ÕœÍåÄÆßŽ„àwâüt»û)WˆìFÿÖÞ÷7™²kæ”JœØ¿ï\#tþfÓ_ @ÇÙ}s׳÷às\×1]Ëèò‰—o¼—²ˆ@MÔž„Í8/Ò7“>ïC×hÒ’läIô —_³œ˜ð¨®Pam<à\J. ã;±/€~p3èf“‰{@ùÚèVPÊÔMi5ʜν•¥R À:†°®³Ö ùŒ·JÏä7+ö|ËÝ‘¹/5‹NÔßÞÒvœÝæø ‰EWþ¹ŽÇ4N²wå˜o@ŽÜ]kHŽ›J5 €ô¤O²=#4@/ø Ömð¶×ÅÝ6x³«ûfÑqvÏ<òv­ñÿ/agß³ÙyUw™)@l¹‰mìÆvd‹ _¡j ‘ „@p°‡±g<+©ED¥¶Jšª4R "AiiÞÝ—?JÎÌã™–~w¯{ÍÒO[k®ö­ëåœsß÷órŸs­k­½ö¨N¨'uÆfË+„æ˜ ¹åOÕ±M¯ÁX$Rý µñf‡=ßÑd)¹éE.õpŸ“hc¸íC¦ DYð€ÿì OŸßCç/01éù`]>ñîNñŽä¿RœcW:ýsðGüÀoüÍÞíÀ-]@ãÊa¨¼ó%3(f7?@û¡è<ÿlU'<ˆ³ ¾~öÊÏçɘ áÖëappëãܽ£u}™"Ð;¼¶Êª90…Óür‰”K»›=W,ÆÜòö•{@®¹èž·¬ÇöåtYÎí°çÜ<‘¶§}Ò7[GKÛÓ× 3‘yOÅ6{¯MJ̨3¶Œ &ýVåžœ“—5q%‰»Ú°èe§ü¯€õ0æ‘·S—TQLù*±Vòvà>F» â–s{ät,Ôbbs³N޹Úc`¶ãÅ‘¢qä _¹æn³@`§.®ZEjœ«Ei ^qaÎaÏÍ–+×\‹Bµ¯²Bà”SsÀÓ·$”`#×ÞèfŽ`… 3fÇ0ùB„@=œ€Iw?`yûûro'÷ öüqʱÓËÒ™SPRäQŽíŽû0è€t¤bð<‘³¤ûÜsÂ&r›MÇ¥½Ô©¡ª‡ûÊ= '´ƒ¿dxÊ[’Ñ5Î9¶¥¿(äÙúx—Fkæ<Iã°—š#߸˜ÒaÅ„—dZÇ6‹^ îÎ;ŠM§Ï|¥Ôñós°O @Ç$Nwôa­ +]ñNrмä˜×±\—V,º ä&n(ýaÓ‡AÿŽÞßï_üOËá}rÒÅšÏgHÿ·þô¯þ›ÏWõ»˜Xs( ø{a0w`Õ/)ó½¹}• ˜Å¬·‰\t]ŸÜôÈ)Ä cTè÷Á” bP‘`—ïŠÇÚ«’BÆcW9ê:'é*”`»ÄÌßO-õá°éôÍ”£ÜY›‡˜ÆY)”ØsIÚ}¿›×Qûüë÷²‰©s¹?²Áy¬¿ôã ¢9Ò“öf«7euyéj s=3¢ÀRWYÏŸ°ïë9`/ ®ójãZÏQÆÙø^ÒöD6¿g#ž +ì ù§>×Y!‡›»RÚ4ï|ò O°É@hnÕJO^ºË¬ah;m‚uýU’­òÑMxÐ'´S(Q-eØd7ë8ƒrL~‘¹Ô'Â13ó¨ºèîÿÄÐÙ¸¸Ö§¬mì6[¤U˜óôàW*©^OÇà ”k¬ót} ä'/ÝyèC´íµ>ý¥²×*°ÞØ üâÜèÊÃÖø?ÞØð.«þê’Ù] ²sç€7VÃßlo\/SpÆ\«s „ƒC›¤Ö|cÐòR+ÜÛø¹k¦?Ð,Àxtlkèm—¿÷:¶vO2·>ƒç¹–¹• ?}Í—1[þ¹|M•nƒÝ'¯Bç(,#»ð±sž†bxέ¨h÷¿bÊ Î)ŸÀsI]Þͼ¢K6ëRîíËÁ½û›5¿ÜX®/–<7®ŒSc²ò}Öc¸OøJsT€’”ãøó9}cg¬›¾€|œÛ%•Rkƒ’ƒ<‹Rk;çªc^ÿ'õË\¥J¬½á‡Ê®Qê‡);âUï0®sÔÓJæ®s—LŽX9o,¼‹_Ñ9çä£ÃŠ ³)#žUÖÆóg§vŒáöâ‹Z¸-i'ÏÜõÍÃȨ0ïè8Ö7oÙ;ÒuÆŠÎ;¯…q×7÷û2žëf<²ÓHÜèºn×M¦¼ÚÛ8G+´ÈO9¶Û•´',ÙÅ0«JRál VR×TžyÆáäW^yO4›ã‘©›}í8ƒï•'Ž”kq«¿ÏÝÀæÜçeb®Í±ä©—IÜßÀfÐ_€þêrqó¶ï‰õ–C;.îbÑ%OŽzÈ‘Ã>¯/ÞeØÌ¤O¤ãðž2l³±ð° Û|þüÓ¯©dœòÒÿhÿNP'LK:Ž=Rí°Té \‡]G6/°ýมƒwA¢òÒ‘»ãüNø,9ý”¯^NïUíàm+Xœ—~ލ\(Áæ’kä Í%bùq§à,§wÝGÔ¨SÚQ±XtõS¡/}¿ÓØÆ–ÓîMËn݃Y¿Dô¥\R?¤/ú^ýèX÷~ªw´;ÍÉÇŸк7y׿/q[òžçµÓ©8°nù;Dzy:è‡Úè ƒiKÜ©œ"PNežÙOÏz‚òk<ëͦ›ïõ€Ž+X?‹-OαUrmyéèÜ Ü3†À@Y(Àí²´æÅœïúè.‘»¨$kAjŸ'·Ã¢w¸+Õ²ý^_À½ü”~V>P2i{Ea&¬2T®u¶}›(ßvé³FßkwŽ‘ÊŠs;c›È ƒ*ÀW ¾7ÎÃî‘$"Êæf¹¾ï{6¶jR•÷Ãq½ðháÏ6¡S0î×^ì9Doð qçÊ¥Gqq¹´C8óÚ`H¿Çc&› š]çÃqì IÈ›;Ϙ÷$W Yë5Ÿë9ÿÄÈï_Žvm|måœTù%ëÜókc²WåòOS‰ç÷£Oî9±Ç)§@é â"sw ô/’Ãò8²ö|ù¹QààŽüÆ’œ)¹ñdÎæ\Ÿ}vöæØº‘ 8ggRÑqÜ,ÙåìÀ N ]ç…9_&pòiíUw³ç†qùӰ䘜¼v…$ ÷v"ùX1[µD)U²ëŠRw´v±&#—’µ?­\õçèzP3GÔŸ1À|ZzÜ/`×¹g™»êÂfÑbc8.šƒuð‚‡ð¢Æ"ùæj#CÄ™·Àxd0(,à`_pj×ëµ1Ü®Ó+£s±Dg8jŸwŽ9,: ÜÏÈG;ôA ž:‡&=²ö0äj‘½z¼$ìkœ—”ÖààA™Z!ud¤_’vÆaÍ Üߟ݆A‡Ù ëIô<å¸Ô„ÛtÌæ`Ó œ›5 ÂÊÓv×säÉ=×ñÌaú o6]¯éù_œÏ‰ÄýÏÐþëKzúsŸýVʬ HV9´ä ‹õ† '=­bÉÜ}¬ºÏ5ûŽÜ&}^_†tó¸€t}¦çç?êó¥ ›Þ)Ã69õvxŸ×[uàõ·ZJúüîØH ø^Fgƒ?êÏ_Î3 NZÄ©v~rÏÕÆõ‡®±`®~þ÷Ý’»¾dîònXJʹÑÇÍ=k°ìlªmÉ;}oà}™¹åîŽ2'àÜÇ»´£æ7Pç¾Æ&$ýŬs<ÅYÚþR@ú¥LæÝHÜÍžc‡üÝòô*¹¦96qåºÿûÙbÇxXô“‹¾aíèÎ3Î󒹇M'ç$ó€ôQ²½µTnýì¦lª@´sôÚF©5Ëæ>ýeP«X%ךXP0—4?µór~_Îîq}¿µôÝgíEŠ!!‰>yð®¾Û»Uº÷‰Y#{=Ù)˜Ï1§f¢­tÂ@K ÒôͦoÉ»Z©`Ý÷ú<ëõ¬áÝ·)´˜tõ«Œ²Ž WJ®A»pˆÚ®‚Õ¤d…^cårä·\»¯ïÊYc ñÚä0þâsqžeú-k?:©çg ÉûßüQ^Òw—Qã}šÈ­”îrËyu^—Ïð¬òŠGËÓécwØ YßænüáÎuÉùes$3W¦tDåWÞz—X×Ö5ü.êVy .îϹ(×Fÿ´«¤}…þ‰¬q»8ι˵¶<Æ®ƒî];nuµaÎ'gý¡k$€\ã0êäÓÏÍŠv®@8O‹Ü}Ž¥î¤˜qÝã^Xtݬä0è”縉Œ*À\-ƒzEsœÛê뎥k·ØcrÍýpÚý¡|}Ú½ƒÍÃRsÀuÜ.÷ö2ƒ ‹ŽQÜ{˜Î@zŽa^ãþ’³{!’qXõˆ¿…,0lùÁ5×휫kž3ã÷Ují™Wþ®:²Frc,D칸µg1¨Vk»Ø›«å„ÎçØZ¸j¶iÆÔfLŸ\ôÍ¢ÆyLê?'Öñi¬Û—C»ë‹—C{åÏzì°Sèþ–®ܘI§ÝŸ>¼˜Ï6ЦTóaPÅ´ª¿ëš»ý…ù™¦Ð1rT›õNŸVך߀Ò\Cpm®ëÅ Wô/^ʬ þë÷?~]¥Ñ~`÷õaÏ ¶qn—[ûµ7¶Äø´KêÎ1ê¥c'F½Þe'®2ló¹þBŸÕeØ>÷FžÿÇ8¼ÿÚ×ÒUÇ݃Ÿpwß5Ò/`Y<%ð(Év6—sZÄúŸ‰Bí¢Ùu)=*ï\-Á\úR‘ uφýmo”©Å\ÑÊ”ÉG÷œç³‰V*—HáÖQÎÒ×Üöý#9摼£òqØ;£º71ŠSŸVAêOî§«%q÷´1ê1±À¹ú„Á´û~–”ª*Ò÷Ú—Y\‚ç“Z$í¨½`ÉÕ¶Yç(oÜeÖ^{ijr§)ÇFIÔ ÎaÏ5Þùæ€vÇüi¦%t ƒY˜tüpÒßfq®‰®õ ÷²W̹ƒ¹¤“NÙZʪá4áuÇ|ܱäí;–›;µÐ'P]âkÄÚ’hugœÜöVêÈü–¸{mÌ }^[qªþ³/ÈIOEÞþ¡/ o§zS•\/àèR¯p‘°Ê"W—)êxUÖê\ì¾Æçž€ü͵òþ\n›©n,Wì~§;7Q½û¨©SÑ‹y^ÓoˆÚú}uƒÎIõÂ'ç:ŽP‹M¯ºàŽ#åý`ëöøüB ä çó”kÞ™q'0ã³7;ß.öl¨ß9øäxL?Ê€;çFª’ÐXÇ-[AÒ’/.åÖ\}ÉÙÅ–[&Ó ºÂ7{ûF1?¿ûï)tãˆdG玬‡Ÿ™‰t™ÃYÚNiµ‘ª‹-0W¿tÍt˜Ëa3Lºû*¥Ö†q¯YâžÚ™ÂxËÍýIɘNu »šóbn²Hõ Sîy?¸ê4;Ë’i‘îú¥--»½ådìfãÆ>­ƒñ䘭ò*ä¤ùÁNyŒf,£Ëü›,0«Á,îy#k/À®V`\²À÷`¡ã,z(iãcqj¿r߀»ÊåDº8Ö$ev\×LKô][º¼žsPÓ·A:ìÓ×Ö¯Eª¾jà¿´˜*·0[«u¿sÏaÏhµXO{Î9߬Ü6€SŸ|sÅ'Þ´ã´Ž+äb&êÓO¹©äëòàä™rŽF_°•€t€wòbPqnã¸>€PXQÀ¹sÐs- =[¾<ÇVôî Ü*w;9è€þ‚º Úg@ó÷§ÿÝæ?-0ýߌÿ÷÷¯]Xñioý‰iß00ŸV1çë¸ÛKæÞ}}ÆqêbîU;] }òÒ¿ H—yÜïþå|æ?Ÿxèð>?Ã3Ÿù£8¼HÿW)<êþ&™k)|)`Ðõ¿0³ Þ̻ΥVú6…Ö<©Žü?g¬ã‹E§Æ?=Lz“8óõ½{&}Æ« âñûß yùRÌFÞœ3gV}©xzC‘MÆºÏ À—‚€`N)6rÏg|Ÿ²–ž“ƒ»Ç]&³òÑum6i+xFL«g àœçŒAy˜óy6yLZV+Á¨ëù7aVçc士6‹sÕ€ù90‡}³ÒÛ4'fc¤Ç9dH«Rhk=r!ÔâîNŠk˜Ì=ñå>o¹º?ù{§–uÕe]öhJ¬‘Žywˆ˜WYß%Âc sn"Ç µdîO|áÇì#ï±ô•wk—¹äíÎéZÆp—¾ñ°DÚ®)&/´aÇ›Iß,yœ`=®k´²ÃŸcq¡-É^Æ–Îçð¶Ì],D± ͦä›+`ÐÅdVeuº..H/àXÐi^-¥ÕJê>ó€vÌŽˆ.'´™$/`%5]‹VŒáÊŒ)}-”ÍV}©Àú^PÙçØãê¬cË#)所‚6C†‹|]cæW†P $’`—ÅÒ5êo×öóÎ)Ÿc´ž' F mõ?åÚèŠ2ëÒgˆ×nßË<@qÞKç Sˆ‹eW ß@ßÇs]]ûËÿâÿ\dâOú«jÿÝÜ>;9Ý ÐÅž«nùHÜoüðÐ Ä ÊÐÕÚ4îõ‰[x]³¤3?àܲwÞébñÒqxÿ½é/ÿÕüéäþOççøæÈÝ/æq)Ã6¬ú7æw¿ô¤ äwp7›žãqvOɵ]Žšõ ¤WÚDrÀ»çõø™ÛåÙªšÁbÕ•g¾@ü2\L_ ùœGÚ‰€¸À¶ÚŨg©;A.úRÕèš ÈcpŽ’'-åÖ¤ª]Ç'ªüÊ!64;l,ç{«A:÷[Ý{1ëôñl®ÚGDçœóщêò7ÙeغÔ'±YôôËá¼sún •/噋QœºXt«Ù¶wŒäëšw‹Ôý©ëïz=À†ýCcØ+@ùíbÐÐÕb÷†Õ}꤫ÿs&%öZF¡>`²kž“ܽúÄHÓïÆlu"%Ö´6›u”eí%{¿Yì¹æLÌ´Ä]€|ÂmÌâ$Y7á3c»%ï°ç]iˆ\t;´³ÆE9Êúx¯¯©€ä@¥ªÖ•“(»öÈúç䡳ÞÿÐpê·ŠÖXÁŒ9²v@úÆ1õwÏ$%äbÚ€hŽw{Œ½Ú˜~Êx.ý—àÔJ#®Ï†Ä¼v§R7qËï§Ž‚syÞ³Õàô~dé:# XÕ˜sw.öºclô är.Çö¸jð!KX…çi¼GÓ7¢ß·%äÃ#p{ÿŽ(’_’þÎï¯ÏÔŸå‘uϽÆ—o›Dü¾7ý®Ö\ǘÛ%ÕØÕCÆžÜß\3e™Â%4ï›Vßà$ Bæ~¥X9èê>;å4”7÷Îæ6ñ ¾¤Ok®`¬<'½.»»m§€ûfÐõðQ_±¥î€óÊß ;þ níå¢ÇÕìr/c—Ô; €7èn n)ýÅù¦ÜÀœ¼¶Hë ©ÑêDJÄ„=ÇìfBs,:–{»@ºjÆb¾cÓêõžGÒŽ™-w\°æ @¸À±Ïqí\µŸ³œƒ÷1†E®M¾êûî\tmƈ2kÊW_ QîÎí„Ò8¦o:/lVÇÛ;¯ôãóy>U‹ñͼ¥ùTçÛ(ÎfrvR#èp¿\¬€Ú”®â¸¶ÖIåÀ„Ù¬8}jdÊÚ(. o1ÜWþ8Q ÷*+^Œ¹@x äÔ„O¸Í먯 €€>ñïßÿØo ƒ>scƦ:ä„¿€>yôKŽøÈÙoÐ#u7ÈŒ˜_æœçkèóÿ–ÐÏû(Ý ]Rw×I¿„Í㜓ó83é¿uévxÿõo\@úSc§RrOÃû/}ùÊ›1z–¿Cþ^úÝZ ±œûù_™šç()<ŸZø¨5øÿ”{Óˆñômw’»ïM((>H?±âä{Wi%Ü‘½+’³î9÷ΗiÜKo\˜ÈIÑùî뾡v…îwN¡ÙÆ•šÛ% FòÍy齉YF›®ŠAÕŒTÌÐx¹¹ç¸UPË4ÐŽ£{‚Š3¯°ÂêÞvo¿ƒ³ûl«P~ݧ‹5׳,)]뀼6µqvO{gù¾¨¯ù•‡Nh]pWø*¹6cºÖ.Á¦ÒªK}›.–Ük˜ô.½Sn²¢ŒoqÖPñ÷yrÚ!@b‡ ïÄ&ÔAÇ NcZ+%‘Â+,]ÇÁݲö2^kLbv»«¯uë˜È¸{}«µ¯Ú=ÀÜ)¤ÉCp79Õy躎Ö䘣ÖïžÓ?å’5—Zèj«:,ú޳Ä:7êeŒ¶ÏÞcäSSõÊc€}¹¢¯’ÔMê6æì2k¼n¾EÊžJmwã@áNLÅyà¿Æ½àÀbûÁ±ñóA G¸w¨áýè8 ¬÷?ïŽ,f;àü,ƒ?Øî+6ÐWëñËÙ ZIÿç_꙽?Õÿk ¾¯oYFv¿¶ÑC‹=gÜ»oÎܸA  cp±Xô”RCæ³Áz€87º‹Ôþ“˜Â•yG‚Z—t÷ÿÎà›='§ ã`=€»LL<Æ­ôð jƒ8µûØ6e¹]Ää‘…A'Œ’kåÖŽqæ2)ÉÒîí©qî¹p˜Å1w\`(Ê,GÀÉz³æ0é›=kîö"Atß`[‹-r 0#ôŽ”X“!P\‚ÕƒN©åB²È´4“fJ­QFÍýÅ$mfÜ1׺EÒŽt½Êªe¬Ø51†#¶¼Ýລí™GFëØ€„wN¹.lú€šmª•c0Ô2WMÆ€óƒŒÙÇ-‘¶¬] zôä£oN>y•ûù}¹ž<õ#¨” ˆÿáüÀÙ yÊ­  Àæ°ãw¤ïôi' ¸ÏëÊ!~Øt9Á_$õ–ÖßtNú _üδíðþüoÿåû/¤ ÛçFîþl&}äî.ÃöUý¬ÃŒÿí)7_¿oÍaÜW)”dãÿ 6kò1Žó9+Ýr©¥áôôÕê:&r]*pµ«ºé!;œWŽÓ{ ¾rÑÔ¸OPj ƒHînÖ«Ì€1¦,O î[j ÈsO4;¾ŽÍ<÷Ϊ™Þ*&ƒòܧ5§±ZîéøŠ”ä}?Œ+0x×x±çÞÇ|ó.ÃÆs mù´ Ž%åê§œwzúç”Y­¨¾RìprW0¯€A§BÍ|KÜÍŽS=åf ÖU^“Å =R÷ä¥ã‘4Ç Æ ÖÓj®ŒáèV’VÝóÕî5µ×çä¤cμÖí?=%€#og~1æ…šà»l¡q3Éà°o²–´Ü j»ì˜ÛœG©µ“ŸLzG›|›<]› …#kSòµÞólêÝ›]îHàíx–õëØÅ½˜]_¹3@Ez Ú¯±ÿ˜ìfú 7ï"c/c¸€o“J¤·”Îe޹óÊ Î¯é3ݾÒb^ó»LSÂut©¨°‚+¯6%¨È×õ@ù¯úÈ‹wêkw®*ï<`\’qX×6‡M_àÛŒ©€ÕÛÂvk¾À´ë›)o&}Í+”—®€'ô¾èuÀù„úvr U 6.îè#qéÕ¿žxÈ ›¹@ˆV¸o9¶„ <}ƒor×°W« Ç=®õïbõ ÒUNlºê¥ ¤Û<î[bÒõséç³yܧ¤O6©òûÃÙ¾k¥[¥°Ê´9=¬úDuqÏOk§ÿø¸ ï l&Ù`NQ¹èšk°—wJÆ­½K:m¤Ëº¯ïóç»»Mâ¶BÝsuªAD½Ã˜9õ“’³õiËÙ`L^ú’·‹%¿W÷ÕéÝ—Ú*÷xÍ+ÊïËnW÷Ū³Vuù5µ©ƒ~6‹ë93áKÖî>áÚêKî®ë Ñ̦k¬µ½ZÐÍçŠJVóöúqÆz)»¶Áº1`— ðüj¬uÕä¢÷5༚û©ísyàmòÏËûì„¡óyÓ®6òú3Ðnf»@ûOãû‰Œ>“¾äÎ'?€Þ»ÜçzwƒãÚ.øÎu¥ó¯Ý > ¯A^„Ë•µ¥¿Æ¸½·<½Ùù%qP´+_]ç×ç} ¨óÚ¸³ó9)p²Þß žóp_¤–¡ä+ë»´‚Aô| ùrÎgis 3».wöÉK·c$¦7æ½æ}tÈî7”íPis¸ÎÁ!l 'FœÉUÂbƒqú1í(wvE1ŠSžøáf P¿µsœÈo¢/³ÂÌÚ—œëœ/]’wñ’´;/Ýs·pHýè|æô#/›ëÐ+wìYÆàz½›Wîø«MUòÐÝê|d턤pÈÛk§ÿåÓ¨«- {5ÏÓ–¬½êŸw>! ºáè䟯~Ùdõ-Çù9-H‹Eÿ¤ëSª¨c—@jpf¨ÈÛgŽñðUß¼BÛ°t‘ÐVÀXHûƽ€Š°ƒ›k¦°ÀËç–ïñÛaÕË™ Þf7ugæÅžS|¢Ýt®¢óÇS&MætòÓ °­0(7`Td¼Áy³çà ÿý€Ù‘¸ÿÚWUf- ºæ`РЈŒ%;Wù2ìäŸRØÓ8úàîós¬òÔ ÔÕZî® ‚ÉG×gȳïÏ÷ÝaÔ'7]rw9¼‡÷K¶ßü&zéÿä_°ÿþÎÏÿ ›$‘´¯ºôfÆc"ÇqO®ú!õ7ø ä+GО'ó”n+gwÆ|‡4/­þ©êAx˜sÀú¼§L=®@!ÃæÖüWFµêe›Ž‘%q½óÜû“ž\ó÷¦£HºãMPî±N 'wÒ—ÇtÚR€úbÐöw…{•˜M×q‘fóWsî׳§óÑ‘±ÓÒ™g“z;¸ÖÛ,Ž2§V¸¹Î!ph·‚N¡k+åMs1Ëâ#cÔö,¥ÖVúæi}íŒaÒñÒI¿ úV&fìôC:a@øê[¶½½†´¤zæq–¿ãwDŒ—Ñ»j+-Óí•Úã¨H½žg v…ÖÚ!ÈtÝO95k®­u¼É6J'CЩ_æÑ”g86nÓ82„`§'/ö—cýps"à|¾`B@,ÇÀRC!<…×ÄÎ×ñº |Ê{WäéÇàõ굎éÕ˜å!ë/€~º°ôÿ'»|öoü ä\À3sg~ŸGÎû‡Œb_óúøšëü‰”=ãÍë7w¾ÄfÒ[æaiGÏ×&DúlŒPb LBÆWÔ—9ûú¢#iïØ¦qûfc÷ö‰×î!®–ÜÌVlã ÚÓŸë#9Š»¦vD8s"sŒ—a7tv_°éŒ+çœÚçâã/Þ¼»sÑPWI6§ç˜EØv‹þ­+ÝçtN6+c´i(¯ÜôÈÚ70×üR:Ә¢—?Éôyö0‡ß‰A|ÜÝíñ]zMs3æ¹æçé]\ãØÏN§‘Q®9»æÜºkóÜÀ=*ºxÈh-39J±©J ë"ŽîÖ=7!Õ_dí¨ûˆMBÒŸÙ,zÀ¹ý}nXú¾ê¡£PT_å×¼nóºNpv)\cNdÏõ{+/ýñßÊEcˆüi2©£ÖëKòÍ5V`Pì5ªƒM€úë ¤› °pGÖîòÄ[ļVüž`ÓëÔA·V¡u»‰ûŽŽÎ=ÿàç~ä>ñÿeŒ›„õÜVýþm€ùœŠõZ ÆymÆ6|;Þª#žJYäŒe稲c¢Þ¯kC.ÃÀ+–{;رÉðzݽuͶ ³[%Áâ4¾@ªæ¼!¿Dj¢7p¶,`þI`ÂïÕléÏ5ô˜¯®C ?ÆU®6,Ø”è÷€ýßyyýƒB¡ÍÍ+ü9·ï–zˆÞaûàgÿ§¾Ìš#‡ÅõÍ«ú©Žœ}Ý\`Ð}îbÍ;ÊqlGæî›£™s§Äµ*§…1'Ø©Ni5›¾Ýegu—íð¹äŸçÓ’Œy˜G5ó)±V»Å<¸¨ƒ®“¾€xïPû˜û ”Û$øä[ÒFmÓ8¸V®yIÛßă/lçh@îš®1Œ+€ŽÄ]Ç"õœÃD¤”Mr›ølÀ>×<¢îy»ëá΢ċ4õòH #Œ ‹>~wv‡ÎCÖî–Ðqsaͽ0÷ÜwËÙäžÛeÕÔ’WÚ¹æÅ¦Fü“wî‡3+÷vå›ãÈŽS;ÝHÙ— \±‡ô›9ø8pfß,9@Šà¼¯àÆÀ€¸OÝóœ'S#Yß,nŒÜääbÐs¼˜ñèέþƒrü‰—ñóŸÿ³÷ŸFùÙèÿpêˆ  ËhM]@Wý~%'@—‹û5KÜОΘ+|sì\ Ÿ~3îÈê#y7›Ã}ZKÞo|odîÿ% ]JIöÄŤJàOf3â*Ç÷™ÿÖü½¾åÜþÞJÐßJ}€8íÚQÐÏÿRäí0êD6…¦ÍF*°çù_Uà“°ÌWŸrlÙØ:sÊ&÷Ã8¾§Øt+[ªFzúºw87=r€÷Kš mIÜaÖ;E7÷¤òøÔCtŸ¹ûK€ô‹þe€{€ø17]|žk°æƒ²kk#÷]9ÞUG˜c3ÀÞÏÆýL%,iÏÆ¸Xs½¡ÎæùÚX¯@ÆžµÆn&³Y+õèßf-ÂÚ¿rж®b£6óQ*œØk&ÖY;4¯µ™€zËÛoZ=i¥#k;˜t‚ê>¤CÒ²æœõeDŒæß^¿z ›œôT, )õ3“'®–XÎí +è³î¾ÈéÝ~Ø-òvKÛCºUDâ^ÑþU0ê”q.Ž+ìíhðÙe© _U™ê:1ºA=©Ëà.ðÜ™µ?‚t^‹÷–-û®“ÞÕöÊŸoŒ¹ÌÏôHË‘6 m‹A[3ïÈ呮Öw4“½?¢?|ÚHZª®ö Þë—¿ÿÇRrü,ב†”Ô£wt4_ˆ\ßT¾Hªc®kÉÑ1¤íÎÇ ®¥1aÔÜaÊ_1(g'O7rÍãFI;±nD•¾Ü5®Éì\Ô@wäæÚ‘<£•{®ˆ³çfÉuãæ&ÿä+ïÚý0AveÃ9KNº€¸ØqnÀy¤[íÜÎÃlGåxQó\¼Ê¢ì¸“¶V½z•\ˆ»‹{@»[æÞ€=õ_P#PyçŒ7acžHÛÅVg~\uïßI[Øò Y¤Á¦XYÒöºÌ·¡Ñæ°F÷bŽT¥ˆ=G®§Û æ,mÏ<wÀ¹b—R£ ›î×vò[scª0uaøÂšclö¦p ´î«MzB5ΩmÞ¦orÎ.6r—Lk€Žì] ¹êc§úå͈—K;@)uƒìÅŽtÞ aÆÖÏ!€þçg™Òd#o úϾ.€.sµ ƒþbúõ @‡A¿õ_Ë6~ ØV P~'À[‘ù®á¼[ û„Þ3±òÒ_“ä}âu@º¤ù ¤¿üÒÿ\ïó3þÉÈ=,Ãö™¯ ¤«?ÿ ¶b¡kϳɢß_Òކ}k“'®î§†ú’½Ðuÿ³ïhŸìéŸâûEÌq¾o•f²ÇNO “®È÷Þ^ÎS§ŠÃ÷VîyâšSdÔú¾¶7 Õy›‹šã¶ûøÊ_º(ONºÁšŸBL:ªŒÊ·yÜCp~»ï€EïÔªzŽéYhGÃ>çúYx× =lyå¦Ï9Ïc—Q«R§ÎÍœ;µM.îaÍÞµÁŽ’îV•]Mžºb»¹ïºèsÜ þ©Þ‹î4¼^¿@.Gw÷쑺/iûŽ•FPp·Ñ›×r˜øvܬtF½–¼Æ+çü#fÉCî`FlF]ÁyèÎQ‚VÀžÇdÙkdÊ —)܇ü Üç;æ3l&]®ìïj­Ž‚M­æuœÊMÆê{Ϊ[õMŽjãé.1ÍÞ˜n—E«²Ò•Ê Øûá5‹Ý¥°y­3‰–›Ÿ‹Ÿ©p[G§*wœýÆ×e¸®¹ÂÏí|è®Ï»}éÐ÷;vÙ´sŽB»å-ý>Rõª7α•[ÎÊñ—Õ;EÍœ÷îÈõ¸Á×ÏwØ=ªÝ—’Ãóþ®{>ùáaÒõ[FÎIgÇÔ:ï ǼÝÛ“_þ¡Ùà˜;n žPO?½ÁùÅ ÓHƒ Ì[Þþºw+{î²iÛÁ×vƒqµÜpÝ^­]Ôô7xßôº–Üó•ÿ4±Æ<`ÞÀ¥4̹d[ÈÝeÕ,ÿ*Ó•HÏó£³@ÍÒ0Óyç1~1(Ç .cµÌaF“EA:íËï"wg±²äD3çZ± ¹ƒù[Âc3Z y1õà` ‡ùÏKŠ6‚cLYµrw}^õ=gЮиsÍ]˜ñbÉÓg\R±æîÊÛäIŒå”4.Æì¸BÛ©Ýõ˜Yè;`ó2<ÐêBÛ±]ç” ˆðP²*Lùù˜Bù¼ç\ó&1ŸXÛÄíξÛûü_›:àMÇWnsKÓ—ÝçÊüí Ôà3ß­¢Ç/pý¹©Ïþú”Xàú±Ï?”¸“ƒÞÝ9áq[7¨–´Ð À†Q”of] žc·8·Î×û¼Î{O.¼BR÷‘·?>ìÿü Ðé“_¯Ÿ1æq*/‡w1êówÿ †qü {³¦ûõ7‰Cÿ6úë|í{ÞíR|„U‡Eß©¨Gë®|°]ÞI˜3fÓÌ5ÑéÎG×käXÀxŬÏù”dÛU¢ÊU_JžöÅXòö¤ìxΪ#·Ñ·—Ri®nQê¢Ëùçä¡#ƒwj&ž»U8} &Ý̹7zêÆËÇdç“R• ÄÚÞh–ï‰áÅ2æ§ÉGW«ly6æÙ™gª€µBï”]sPMÅÕV“^%SIa+“8Æ(óV t”znµþ±¼}IÛ+\Òk„æ§¥ÜìÓ—Öc3éaÏMŽ ãì~•VÇÒ+M‘9bäîþ4(-uLm ²ÈÄH$k×'\}h×HGêw"wòЭN”+'ÝÇt~ÕBß¹çj1…v_Ñ ºâ‘U¡ÈE?›€/<X=Ræ1Ò[5èÆãÊ—%MšsÁ[Œž pßøëœ Þìyú¤'_Ç$¯ê¥Ÿ;òöNeïúõ¹¦@ûcœÌ V¹´ë´Ï ûð½‡kûÁœM-îÏtÞÃý€[^‹_Øa¥Á?.õu>ýcós£`C„ÉÁ˜9€|×…ß}~‡‘>Ô—¨Üý¥Š!„㦑´ÿ¾ÆÚmãKœà ¾jëææ¹»Ï]e"Ú½ý¸¹Ç\©»ß7HWXB4}n’í©gö;7Zj\šíön*wµŒ åC d‡=×ûˆM7S~®nS8ïÊqtÈŽS;ÀÜ»ÌHÜÉïªxÎ&-«Õ.v´˜½¸dÍÆsHÚîÍCÛ;î‘·óPŸàï°O`f£@ξB5ͽ؀Yùû0»ÄšûÔŽ°[:`¾t"`ÜLÈsÿ—²s¶ì®Ž;ÿL’JÀ–‘F B °])§òrÇØP`\€xJ¡ˆ™A±‘ópž&<%$À PW¥bÄŒ *ÉŸs³úôt}²ªgOìV}{ïsî¹÷ž½¿ýí^½|îz@] <@\‹5;µtðCÀ˜Oˆ/É»e›¸¶—Ü0N9µfÎ'çóʪ=`^ùç˜ÃÈÝ5Ž1”bF™=‡30¸¾c»dïÀøÀ0r÷8°ÃžÃ4¦ä¬yyËi-gÿûÇ®§~ƒ6Ÿ+©9€@îö£È×GÎNî¹¥ï 1ò0ä v¿~ÆfÓç=®™ûè5€þ–Ï£üùÉщû»¿>uп‰ûäšÿ`$äÏȘ-9èÓW(Ãžß ›ž;Ì8íî-çõ–<ÞåÝâÏy–» ¨ËiÞrÏØ<îÁœj¹ß)ó¸û¤ßÿ„Aú»¿6ÒöÉKûÏοõ¿9/}j¥ ¨¿æáÿyýúôŤ—r9ûcµ©sT®ÏL¹Yõ0銒½“‡Îÿs©I*íÃ̺6´Ø +©»Æl¦‘‹É»æ#}W›û@6íÔ''I»ØôÜK–*g‚Úè®*¡{©7ޏºÊw]ô°å˃> ºÚJ'bCÔmîßl®r/ŸXlz ¾ÕT ÌÉM/ÖÜÏ.úÞdFÊ^à]×­úè>üô˜Ãe³ûô,õ¼æŠ5×¹™K®ùRÃÑ׳½K®1—5B•nU,³83äá'FýùJÍ×¶€:òvt@:Œz”Š[ò Þ€n‚Å »®/bFÒuþÈÙÓR ˆZçYk¦¯XÆqZ³NN{€8Uˆ œ à „•óu­©1s¹b×DGÉz¬híHnúRÔ¾ÈFÑÂU]¸Á­qr÷rr?VPg ÁY}°Q¹å]nû@7àn7vÆÍb3æÜ;w¾ww¢™r¢Hîžoú‚þ 8ôÕÕ/œ„ü–¡·½½ÚŒë8à®3×?ø Áîô¢ÿydj—düNü¿aÎû6Gè?’…½["iH¹Å«%`ÇÅ–#w'/‰;†p/¦c8u@¹"ò˜”fðü6‚c×Î-.“+_ÆçÜË$ÎNðê{§Q± 6¶Ä9ÑÖ‰K; £HÛÅ /ƒ8ÆÞ™U”Ô]s6)!÷üÈUôƒ»øy`Ÿ›Íˆ]û)"Îí·Í…>ŽÛì Xt-6Š)wk7÷ôÅ>8`Îç=c‡qÏÁ‚ªƒÅÆpŠä$®ÞÌ1vŽº»wÅØ)f-85§qª€ð‹W–QœsÑ)¥8/çvrFå¼¼e©ŠèY”â-Ã7€x\ÛOeØd0ç|ó°r0‡!€T cˆ¯k×ì”OÓÖR×Ãh–¼¹r¨q ºç`b;`ÈU¯\ `~’¦ȉ¹¶Ør½^³ç0ë#ebäÝŸpþ…É=ÿóçßÐÜÚ§Î^-ö|î]ÐÍž p (KÞ>ýË€q±ç¯½LLO û’±3æø«?ðlƒ÷c‡÷‹‰a÷z6%Øìðþà3’é ¤[òþ¾§æó=9ßœÏ; ý_ÏH@¿õ Ÿ˜kÿòЉe*'@®ÿ«>ç÷èŪwž:ÿË€ô6’ó1ƒqÀzÆUÙî-Éc‡MߊÎù_èܨw^i/sßÀXò#êÿ"÷òÐ;ìæ>€Þ©;+O=÷J@ù#ä¡Giä–êc©VãHÜmäi0Îæê*•¹óÐ1£>­æ#iÇÅ}Ω Þ›v¥Y|ÛP¾@7ýèûxØô•wÞ•R¢j˜³‰î9À¸Á:ÒvÒÙ–¼ý˜U¿^ÆqaÉéct«`½ƒÜݺî€Û³¸¤bW FŸ£uë5œÜ͒àYbGõUBöD:‹;ÆpQƒR6¸I©Cjeíˆ÷“âÊæ&ÍXŸãµ‚|tóŸ®T×2$¤ú©ÚT¹èÂöЂü+¼1)Ÿœo…° Lz_‡’lhR¶”سÁ8¯RÚ [z2Œ&‚Œ¹™üñ=«Üùƈ{ié7ÖD-Þì¹°Ÿ ô2OTå06F^p‰dä …P{ôákl”Ì7@jß)¸Þqâ»°=ÇûõõZÒ:·Í¶›a×üs[ ýú[êÀ•¯ó—G¿Ç|qô»öŽ—¿\+ß\}É;Ñ1¾Àô–ÈXzÓ5[ξ£òÌ;ØâDnn’ …U?ºAZÆŽ¹înåàNëÀd‰’÷ÙP N3ëó2‡ƒ1§ïpé5ƒmIº”“EzKÜ;V^X$ëŒW_çFÞ“ήy±æ„`cDƒÄ}®œOÈÅ’›5¯ºç,Fø™Aß êÃÃî2vON¹b1çqâ=®{®ˆAPXtsroK&½ °Ï< œh`sî€18ìS­Î[ÝpÅ’gœÅo›Á=º¤îYt ŒKÆÊÂÛÌyÆjYÄw_Ñ@3«è8°—–òÐÕ'§|–b B0–Œ¿A t€6zRc«V9ãè°¯ºþÃ.‘¶ à4œÃŽ›EϹq@·¤ï%]ÖÝ}BïÍy'Fø—#gbäív©Þú¥sØó'G2þôÛï þ ì¹ó½(ÿÄà<`<à\­âcµ:ßcæî~Pl|€;ó¼+t®{õ‘ÏW^º˜}1ü2²SDò&]ïóÙžžÏøt™ÇI1`~ï—¤~ÔŸ©»Þ?©<üýwÄ­¿=ëéSë¾#õÐWhß3ßm6‹µñT¬:`Üå™[µÓ#…W”RÅà~¥ˆ qž0ëäøR‹.pî ü ]yçW²yÈýéÑ2K~: Ý÷ÉbÐÉA ëþZŽî¨–,uŸs"uŸT$…ïçlºŒë\\Üwä™á\ò¨c6z²vʯEþÞ%C“k.£Ó#`^ÏÄD6¹ÉI÷ÆyÚ—“޹+Ït+åV.ºŸó Î1Œk`®kaÜæ+¬ès©X!#¼Î™µÌ: Ý$E戃2kçÄ^§Íü.¿¦q· ÖŽ"z-q'bVl¢¨€zEÖ±É!(×ú™ÔÏÎ?¿‰<ô€öÊ=×ÚÔ;Wèæ¨¦ì}þ×Þ÷Ô€óÏ›ü•³;Fö=’wöaÏ¿;Ìù_ 8þá€^t±ÓbÏïzàGçbѺéŠK ¤Ïë<ë>áë`Û âèÃtÿXÀÜyí·ž–°ì62l©•®¼ôQ,ó8ƒôQ ¼|@ú…ùœ—yÜÿëðþ®qx·›{þæôý·VŸÿ“–µ/—ÿåôÞ¹èøaÔ=‡:„`N̸¿3°äŒû;ãs¦UùBý½<*ÅFTù5úå6öÈ;‡Mg, .åŽ}2èô}ÿ ³î}8¹ÇÍ] zvj¤¨•®]«V÷óç¹WÄ#•“¾6k_éqžåêŽÙ(›Æ]Y¤sÐ=îê$‘¶Û@U•J®V•“bÍ?ävy¾8€úiã°\=òz¾³YkÞ¦qfÐ}žÆ»ÔÚfÑC0\Þlú–µw.úKfÍaæüùc€~œZ70¯j<‰EÌPr °4~¬ºô›îÿ©Z€9r÷ H%ªÅ@î9µ‘µc–lðí50—6¦Ëê9ƺ»º}£ ÖÒÏ< Ú–Üy”¸Á$U%ª¼·ÀS™Ëx³Â`¬b– ïÂLÿN«>4ßöæ£UÛî78çóÄ7xµáu™ñ•¢]ØóXª<·Œâò:HÜÍðvñ*2Ï1\Ö‹>N˜ïZoÛA¯þ¨õtP×îÆ²¢÷Ú ê¼‰vu?Î/€Æùgäx©ò±:lzIÜaЫï/-@¼$1nÖ°9Ü ggíz7†®ÙxwîÌÚ!ìKã70§¯›Žw,‘ iL]Jäíèì|®XL9uÏOf!–ÆO»zE›ÄØé¾jž3Œ70w-ÏURmIÅØ™ž‡$¹a1Ž#_LýeÇN8F1ä¨õ;5Î[ênù\-€ûfÑ›]°ü}æÆD‡c0 ‹©kÞa¤í‹)¤Ó/—v‹=jî^¯¤}€¸[+Î"5Fq ÚYèšMtT¬’æ´(^NäŒâļ™±Ô?÷|ŽEŠ>-ÒXØ6úHÝÃÔ¹Àö¹XNÍnÕ+0‰Í¢{þ ÷wö2~;fÒcÛ]€¼ÜÙ÷89Í«–¹ë¡ÿ2s ´}}ƒîî ´+ð:6Ÿç·tLïñ¸çî¼ÿ©qoÿ”[ûó‰¯ê¢¿Jòö,o¿{À­úÝÃD‹=¼ýå—ŸrÄKÞnÐ^sœ·Cì¸Ïø7˜—t=à|¿†æ–k¼ê¤+ß= ]Lú0ç0þ2¸“®¼ôrx¿ïÉÙœø†%ïSbN ]ïª {ÞÇ@/›/aÐÒóÑ;8ÏAÎ9Æ„TÐ1o0 °/?qÍ5“þ8ázé(O Ü‘ãíê¾ç¬¡ ¡ñÞ„ [>Q`}q*B¬úèá2{ 8K^Æ–:~Î |;Ôæ¾j6=ól–¶£{îáÈÜ™Ë}|ÝÿÝw˜)w¾yY0è ºÁ¸ÚŒ Ò·tÒö.§&p®ãƒ~z.º é¹Qî±ñMhÊãð@Ÿu€Î‰´]cô€s¯Ôךb«ëX;(vÞ¹Kº†Ð˜Ê2›EÏzfrƒ·»…Ioõ!ùèÛ¬»i¢u\@yG änuhHõÑ_<©{ã˜Å)"uWXênо@:}Ôž+MS„~Jrp?P“âéÔq´x@íüs»»—ѳÖüë’¶Ûjuò¥ 8P÷Üa”<}r®ÁDGQ%¥1TƒY<Ð Œ9°Œ?š±c¿¯Ñ9ã³^¹ô`Îú ‡M ×g-‰~oF°éÑ9è|v#xqXìðýKê0 K|¤é¼fEðÉã¢õ€a™¿¥o¹œ×nÉzÿÁ–ô€~«'EK4Ö{U¹:ï.ñ¹¦¹"k÷‹|’@Ìq¾ÑaË+nò1¾ø:_9ëïQ%Ö|ÓX©NçÚ8æ|Ü,aËOQ܌Ǔ ›ß÷3Àú„ún¹©RËÒÇ4ÖÍÜ.îm §ÒcçÏèä¡ûÁ°Ü»dˆÏÇ(E±:aÆ\óŽ#ö|ó<`éGÞnà0hW»rÕ”—¾ús€ú^$`dÜZ@ö®uîEI± ‰mG½s3éÔm0Þ¬¹’Íž«m6Ýçî…9èeRÔý’³â-ÙTT`§–@Ò`Nk@®E0FpKÞž9Ï#mc3ãíÜnp®ëæ}U÷œÅýÊGOŸ¤žhl8EÞ[sЏ^/†Rs€s$ÆJŠåÊm™2Ì™€-‡=¯ÒiÚÞËÝç©/9Ç(nr·HÜ7h÷uò* þÇÿ‡ø8}æþ·bôïŽ{û©þ9òö÷?íüó®ô“ÄýÇôÔ€mƒqú1wSh›U/¹{€x½Ák­×“¾K²!uó“.¹»dú6&ýUó¹äðîœô§%e—1Þü¾&nó¸·˜tƒô7üÉä¥zþ‡~>W×”oN)>L=vË8çµÃ;RwÏØ5ÊܯœtÊ ê8nî REÜÎYs¾›äœ×w˜rlU½Yu@yÔ:uj¡—Ú £Ò|ùpd\©A%×¶¼½rÓqoïû¸Xv1åŠ;¬ J‹äÝ}ËÖyŽÐßl¹"Ï&Àú\KY5·l`o°Îsö’óÍèî×U¸Òõ<ϳ€NµÀ¸2@ ÿ"æ³I·“7NȵŠ[‡1ž6‘kNóCE˜¦\}«i/å˜Yôy-Öa¨w ô‹k=7s6Š»Eì:iŽèQRVY^Æí «1ܽ&]`ÔLH¦‡Ü ÀŽzÔ@[ýD“^ôŸk½ <òömÇZ]ÒvÍ7«n ¾ â,gN d³ÚEüIâ®s L70'¿œs›©F~Èlwb¶eõ›\'2L/5Ûß ¬‹aªì š‹H=ÍC$‡…WlY?ð;:—=yꋼ~!oFR;ô>ä*¢Ž£ú~ÖÀv ì¼7Xo—Áþ#òz-?pÍk§¿âJõD£Á7Ÿ»åöüã’ÿ¾rÐWî9̹ڒ¸Çµ±tòT0ŠÓ±|ùmæveØtͨKÎîM€Ü<È-ËÁäâXt$î‹MœïǰäWW‰ ßaÐåÄi9’o¦ä¦sS6k®XuÐ)¥¶%îȤtN±ç]fÍýëÈÜçíj‹MÇl…þ”31KnàcÇÃD@9,:çÌç3žã z¹Åž{ñpî–úç͈ûœµéPÎ^³å d†fÖ¸Œâ&ŸOý,È(§¦þvð½.Û¢HŸÈ%k'ôº—Ÿs®~ÌŽ ÀeÁ®’ljòmÐfp6›Šƒû¼w9Q`µ)œÁŠ€;5¦'`ȯHÛ] C7b«ŠÇaʹ^ýªaîürÀù>®yÎ]9å‡òu¹ÇoBçœOιÏæ|£œl±çwL.¶äíw¾÷ÉašåÞ®üó&ÿ|XõP–IœÀpòÏâ¹èàÙ‡Àyûdóô/õû$'ݯ‡wʰ݃y܌ͦ¿úý?¤Ëá}äü#wG÷¯S†íÞ¯Èá&]æq¿ÿÉùÜÿ ]Þ­¬àS]áq§=éXmüÖB×µNÝš¾æ°]ÁDLúbÑ æÝš)oUÏÅcu’öøÅRÊ!uÏs=÷ 2v­)æËÝÝÀ•Þ0æ ˆXt…ËQüÑ’‡^kžw~ }Î/V]ÛRwzbû¢„T_õΑµcL<$òç¹= ÄØ©Ô¡ã{¬è’Áè‘·'´ÖŽ‹»Ú%oß’0ƒƒ9÷ÚœÔST°ä¬õxQ  ‡ŒûÇïúØsJ4'u¶\ÝÛ­kË×!-àƒcØVŒñÎ/o\¥cëÿèmøӟ׭÷¯|÷úL»$¶òÛyÀø¾–hVÚÁ”¤67^g zIÌ\®ùc€[àw1êG–ôÍ®wð¡K®Þ6ûD¹Æó‡­Ü¿îb²˜} è×g…çP’¢åôaÌ5—V‘ùÊ5Q›]2·È`”;ø2»þùüì”Z³„7w]³$8‘Þ¸D„¹wË$Ž17.dítÂ;–Ó"s³&Ò$·:wZrˆã¾Y»ŒšnÚ)½6á¼£–µsÓœ«h70‡5ï°ƒ{•TS_Áî3òö#3ÓCÑ-5K 3fnÕ; ¯‡8w÷SîååîÇ(Îö µHÝÉ1éž[ùw“gg€îk5/C8ƒ°Œ;çœÌFLâXDelàNž!‹0êßRŠGçX­ÜEº†èZ("ocrdiæ€g3å1…ƒI§6ðHF‘µ·k;àö§eÇáÞ÷`y{J.©v›JÁšo@ä˜òf‰y/JD¹õ¸¤ëî#ÿì c”˜S.%ŸfÍ©O¾ù 롟À8ÒuÂsòyÉÚ5×òõkùïÌ—´]cæ¦=1â+ ®cîûºk}‡$ï’±/öü}–·Oy5Ä­üó×^¶{€¯óÏa¾_wibÚ‘¼3çy$ìoÚͬ뼀ûí’µ¯1`Z铃.ü„?Ç€ôéÏœÙt—‘H¿ÿ»r®W6Éüe7}@ú½_²Ãû›?;yéŸ6ýSÚí¯Ú©½TaÌË× ó˜ÍyžŠ€súDç¤×÷›Ylli°ž¾Ãç軬”ÊC?Í!u׹䡀Æ<¦’sÏP?±$î”\[ý˜MGê®{bÒxtÏK™û®x±î©ÚôT_ŽîÉ;wN:}m²ZƾrÑkœzèKYÕå×H›"2·$î+ô,òæ±¢6¡Ãºo֜Ԯìã8¹Úl—Tý2ê6ÂÏõI[£d*†°TpŒSãÜÀÜcümrœð€&Ýà㞇ŸGÒ{ݤo&òƬyåWž¹âµ:Ú]¤=yÉ›WP§|€t꘧~9¬9 ¿kØóWÿ‡‘~ß÷½á?Ðý¬Zƒó‹èÔÿ$@|Z‡rÓïS8õ9F+ù¹Ú܇a“9¤òqvö¹î]/=µÒï±qœ>·Á;ï’¼Ü}9¼O>ú—¨Éï¨ZéŸ6ÝïÛ ð:e÷sh sNðNXÖPW«9¥ah³Iyä>®ÿ{¾¯ÙýŒ‘½—Ñ"åÖºËõý—Kér`7é*WS'€³Ç÷ÜÎ5ŽîEÊEGònN8µ&%!œ´\@ÚuÐ#qç~HŸ NÀz;½HiPÚè½t5,:Ñç §>MÀ˜ ¸»|Ú|Ö—?te?K,y÷±y† |Sî°n¯^¤l92–oŠË©mŸ?7ÉEßÀœÍðsH=gU›SÐð‹97›ãjËs†7—Zc½@ßëÔz€ñ æg^k2µ­(£¸%{¿ò´¬¥ÌškM¦V¡õÖd©‹Y²ó´·¼1ÃZÐÞCééS ýƒ-qѰԚ @9®îjUýÅLå­$0®u-uÏuü*ã¨Q7(g=­±ø%mÇ<PΚÞcõMÂUþ9a î–°“»A)sÇø‹hò³LÝŠmr6òðeÖæ?‚;ë}ïé\—ŽÃœs¸à7_Û?[Ï—ûÆ@Îýþ|©ã`ÏqE‘¾‡Ao«|¨öõâ¼ðÊŸNŸ~Øe> »|°þÐm@Ý ú”hÛìŽ)¸îø—Í®Mƒf®ÿ;»òu´¥íâ$pWDba Êü•ƒ~ÎùòÊ<"Òv·Ž½;‡Ü=csn(άÇÕ½ÙóäÛ˜]G d7wòÏ'4vþ9Ä©™rjW’‹ŽÄ½Ã9é—ºö9;¯8Ä”oi;»¿SÛÓÇ]N­ØóUûœñfËé<·œæ™#Ï]ó>†! ’vÊ­d¬@&çÒjfÏ©m~Cs¸gNPß•só° ›•€Øùç´m G„A'²x—v±çôk!¨r>ŠÌ-V}/.í莄0¾:cKéíÒn™{À¹û зÉùæw/¾Íž/ó¨W_¾ê>ѽC¯e‰;y³åÚ þÂö³ý‹‡Î~å_]šöòÙ¯þë?:»ùß>zvË¿lâñ‰žýÚë?~ök¿÷_Î^òûjßð‰éO¨U>ñO1Ç>qv+cBssnbæhóZiõé+n›~ÂcÇüž×Ïðú?®s+|îjç*n›ëÏ]ÓN¼éSgçÞðɳۧ½ýÍŸžö3S:ì³gç\¾ô\ïü”T{ùÛ¾ s>ÒöWÝÿ;·H½[æpÃ,¿fØsô[">€6pð]Á|ÏÑàÆ$NÀ{1î KåaØ‹='ÄâË4Îý-y—Ü]ô’¼ë³Ø<&}dü.Ãfó¸'pxǵ2loûÂÈÝåðHÿM—Íc³¦ý 4>L•ˆ‚ƒ  ª0@lV};º?8ܽ*|À®`ž”Eª)”oôuMòÑ;]¡{ˆ:Žî+t<÷¡{¬ê¹^]t÷ Ìêg<×¼—‡YwÒ‡‘½ë~ûq™xμ«s\¼Zrw Èýl`ÃVì÷…Ÿ¨oöÜ@†Lúünõ7¼mþÏÎÏfÇoRï¾eî} “8ƒs+>(Ǧ~ËÛ=—ïÆt÷m$'V|Xn$ðÍœoàN©¶íÑêÔ1Ä]s¯dpN>: ÝlºæR#Êu?B”{f—º©_®î¯üà•Õ·\Ý›w\¼©»æÓGµ$ >ý¤YÝ´˜òç”Z#ØÈUT|Jò\ñ3¹»Øï2Œ›ó ¼‹w>º¯9ÿ S¾*çu™ž£ëyèkŸ_ ºƒ1Ïm…ÜÔ¾Ì]§eC¾€ú2–5÷\¥ÍiœøµûzXrMï(ÿVº€xdíËÁý\Øt<{`Óçü!?2Žç9è$ËC!Y0Œs,‰»Ö‚5';ëÈ’ºGÍ©@áéù%sÇSiú¤pzÞké ¯k­<×8Ê0.sKÖþ¢Á/FõJÚ*œûñšBò8_Q ºÚÊI5 ‰Êå2˜H¹åêškÛ/ &›èëRµ«°Õay3Àõ¥æMÞB:£°6ûŽÂz)­!‡KZÚÜ8XÑRøfð×k¾ÄNqvj¼€]çñÔ¾¿µú3N±ö½!Ð.òns×Ë¥/?}ýº„­úunÜÓ tog½þy8ÞeçœSQQÒçˆèsþtõ9Fž¹ûB m_R˜ŠrZŸ;×EÊnYMú¼þ{Z7”qiœ=­€º¤>äê<„ó%}Ÿ»: ºnŽè0çK¢ÄNèÕ˜ÃÑÎñôS7Ssj³ãªqò™Î2v…z.Þým0®ù•‡µf/™ /µtl=o{à9±ã‘±Ã”žÏûms8ÅèõÌ’78×qÛîíHÜY((âØŽœ…,ú{N,§\@:à b3éê’0 ˆcú“~X'÷N¯óæ=©yn†&5{ÄÅÒ˜9'g2‘…æè°FH:m§¹’´+"#]’v@¹Žiñ¬|SrŘw½óíì<óÉ;'dúæÅ=ŒãYøK*«~±åbÒ“#{÷ÃWÕRïyêHÿÊ¿8ÿOg¿úÛœ½øw‡1ýÇ‹éþÔ hßvÚŸS 0øþÜÙíR‡ùT¹¬ÄŸ{óôçœ[ßøYµ§9Z®‘«÷êû<aå);NcõÂÇTÿÙŽ«6¹b^ϯ9Áœú:Oíœ;eÁÄŒë\3äŠ18»0ùÓbË_!PþNò¯ºÖù{˜ß÷­aͧÞùûÄœ?mpnc8IÚÞË.òv$æè6wˆo¶œù°ÝÓhÎ1òÖ5ç×âzäð¼.fq:7Fsš;`Ó)HW¤°8·ÔÝñÌóïO{rxŸøî°èO^cÒ¿9ý«ÊKßï£Tüý7½ (ßåÖæØ/Sÿtìuó?žcä®WY¿mr(~秬ÐV³dl¦Ü ]‘ª»Z‚¿ƒÚT‹ì½œÞÕÖFœûþþÛ02ç­\ô»F~?÷ÝS`Ö70ÏýIçIO t…/aÑm”Ùé?ÔAß}Å6“3;iHVF­ Ôl´¤»ÖzîóÛÎÏ ·¸¹ o¹»Ø÷y.‘ƒÞŠ/Ô^ë9— Û/ËL•ó‘»Ïy°ç»½piœUoô ÐaËÔ{£~1ç&0šÝ©uêã…“~‘ ë p…Ö;V¢$$¼–ª\t¤ï(•s¾Ùt¼‚ÎÓ¢Š4PwKîytR$ö9¬[æ0{n€îÐü·j+¢*¸Îºøj¡³Nn‰ûžOñzòú¼˜tˆ7÷‘·»„²¢Sa‘¹ËHNCxãé]'=ÐE™p¾eà ° U´8&—ò®ÆÕÑ š×¬œí…Ÿ¨ìVà˜(|»q-¡÷±wZåÆwýõ+¥PŸ÷+4 Ù)³Æ Ò.©7Ì5Žt7þ¥Öî@XÀo™ÔÎ ã’ð‹å~ †[Æß|õWi6·òåsÎJh×Ãì%‚”r¬Çaq÷Ø3§±Uã–ݳ´ë‹œ2 ó3è¾uX%ÕpžttÍ󖸓o~“dîÅžãÚÞ}į·ãéè±æ¾yÆ%ƒÊÍ=&#%kïüÊÀI–÷ñUZÍ9é:·Øó’¸û¸ëŽn³ŒâÈ1ŸyŃž:è×›EwËn<ù€öéÛ$®ê±ŠI×k\tÛŒ¹" 1æ°èUf-pÅš¯26%=¬°sû#)§Sr÷€rÉâÓ²Œà܇M_Æp-¿Ôkv9!˜ æÉ7¿N.:`ü#ô7`÷â¸òÎ[æs¸’¼n†m™Âu¸³¯¼ófXÌ>ó›ÿÝcg7ÿÎÇ$]S>Œæ0ÐzO`\ Zµ¬œž{ËÚ·+øË3÷%¹sëù¥9ç‹ê;Fî=í€.ŽS_×e~Ú/fNlªÆju½b±ç/ø¸BŒ5¡kçµÓO{a®ðXí€é‰Ó^`ž¾cøDÚy½iäïœx—A¹äìw lIû“ÈÚÍœAÜ÷8ŸºáaÎg|ÁÓjÜ2õvXp]3]í1€ÀgÞséäàç:€8s#Qÿ‘Ç0ézÎs”Ã{˜t奇IH¿sJÐIî.&ýŽû¾m‡÷Ùà˜2lrx×&‹”£šøÔ‰QÿõGŸ ¸Ntõ JñU^ºçWMýÅ¢Ë! ĺ—ì@žïM×H'øžQŠÍŒ9 °þXæ¨Ú0AYE÷u½Æêc&ih§ˆ‚‡{¹èí¥á°cðVÊ"6<+^yéêº×0ëçͤ¯ÙT÷Ø)PíQ¦°6ž]'=e×v VG—Xsõ’ ž{z¦õ³%šŽÃ Ó.pNôæºZÅÃ¥ž°”Æ1—…IGÊÞk‘åâîv­k\ÆŽñ–¯Ç0άú6Š (guâÑ F=ŒyZªò„QOÉ5¥8î’»zÝG:dÏ´Z'¦Ôš£Ó.ñS²;{H§ÔBW­tpXó)g>€|tŸ§pZ©æQ¸®Ö€ü€Ó¼¢zpìÿ!ýfœ¾sj0J›¢!ï»­ò`µ¹C΢0ö<ñ¾p^¬õ~Ï®Nš3­@}©¤ƒM[¶\%¬Ïã3r¼HÝ•Ÿ^nù;¾Àrê–¯£˜œñ‹‹„]cú2I«â÷Á Èâ´ÙIøeÃ`ïï ðûM,™דÎë‚kµÈé÷.ŽÚ€svŸZ:¿w²ã´ÎC÷ÎÕ¼f rÌ_8;|‘»ìˆ¿pvÑŽó\®(È9÷ dZߘró¡¿Í1ãô Ú“‹¾\2ºAf§²êVΕñ¼‡:1qp#ö š’zítà\-’ªÛ îe@²J€ÐGòþ’yÏy»Á¹Ç‰™7'çÜÌw×B¯¦bÖU‚ÅcÆrvU_£«óÑ—9Ü\ @/Ù´ JÊ @tW{/XÔÏî¸zßÈ ÚËY7c½wtó”JS_ ¼MášEÃâüô]k—`¾€¹€¼YóäŸÇ½ÀÅòj,\YØÎç]½™+;¸s§•Kª×xøÄ€YÞ®9sT뜱çÄд m §Ý†WôÏnsþ;IÒ>àüO®ÉÓÅ’‹Íþ€ô/ ˆ€š¸wÏwL]먧PÿÞÿ>ŒçW´u¤Ë_W¸?Çç˜Æê;æüisÞê¿âtük2säúwúZ5¯±ZÎs;QÇõ~w ¾c¤çj K¬Õ¾Âç8æµ¼¾éß91,¹Â2ö 1ææ’³ ˜;çüûè“w.p~÷€ò»& Èó-S·Ðú+µbÒÕ'.+Ë$îu}þŠ‹jK¯~XöbבïñbïaÖ«^z‡ßG ÝaÙ{äî“‹®|t±êÏL;ñ Þ Ôqx¿pïWÒ ^Š;¼¿éÓò)P¶2\@ý£°êKöþx1ïë«>ú¯Ï5·¢7°ø¾ÈL.²wÍé;P7£¾Xôõíœô¸ÂûâÊ,J}ö\¬ùõ &ÖòaÍÙ¤‹IלYôÎC·‰õЭD¢’}TH»ìZJY†-‡=g3O ãÂê6u—[ÛŒzJ²Q¶sUÉ£¸kyè–¹ï/@y)ÈXg¼y›ÇéY­gþè<Ï£šÃ½]ë€<ÿuž»úä¡?¿%î—å…c ®1k—vT€j;]×Å,y»ZÂLyÀºÖ_cGȉ¨#Õ*”jˆŠr¼ÎÅ›ˆüså—‡ê<ô[\ßó7‘¼os8Ö¶‰bÒà“þ)³¹Ÿ9½dîö°ç6rÖ¼â wŸ¼s˜sÉàƒTz2ΤԆU 0ÉÞ8(ø¯ê”ÿC•'g{¬b^Œ4ÞeÛji0Ùªu¾1jÉÜóz”rklH¿UÖmV‰{lô͹um§o#©§Þ:äu$î Ê­€Í†p< ©}ž€1œãÔ~°›O™³Ë•v-F`Í™/·ö^ä ]'쬫ŎŽ S×69…kÁuœ—h¹ä´‹5WYµ‹Ervϳ€œ0ƒîEé2Œƒ-§µ,Ô­{tr?ãÊ®()»Ç‹ƒ%X§æ¹Á: 9`оA_OÇÕ´ûš%Ýuúi<Ìù£2‚³¬ýÜ8º}ò‚‡õ0Ÿö+'À}AyÃïãiyò+$S~ï·§ïvbÀñ7Õ2Vy-Ú„®×ubQ¦¿é¾_¹yçø€â µŽa¹¢÷¼Î¿sÆwÞÿDbÀ·Àõôçø´™ç¸®ØNè<Å{ÍŒ¿Rí°¾w¾çÛ’° O+Pþôøï+fî{誟±SûÅO<+]à|rÆŸ(WÀÅbÎÆeÌø¾˜>€}Z‚ãÇÒøÐåºbòSo=ùèíîþ“œã¾˜÷0é<1évwP.ï?pþC™ÇÍßé©ùý>­¼ôùÝÛ<îeú›M óo“.Õ†Þ?-#¿‘Æÿ ˜ón€:¦rröÈß›MwýtÉß=gÆ\ct¾;,÷ÊAïˆÔÝqàÁæ÷bs‡Ólwþ¹õVù¨u¾¹k£“îÔž¤ø”?‡Ç«Ìš‚¾7@?âT£äfäÍ¢»hóåÎ=ÇÙ=¡qÉÛ=&¶9\|Spv€Ã¨ Гör·Ç9å~½”M“3ûæü)ŸvÛÀü:¬¹bØnçžOÞ¹¹Ú»®yí–þ„@ô¼÷ßú\1ìwòöÔX×ûËßÏí0‡=wɶ9N^ú23£›>yø“.&ýGó·[ïRJ¸ Ûg‡M—wÁØá]ÿrx— ^û®§¯Qyæ ÒÓr~Xõ%i/9¹èÄÌ“*BjI;¹ÏXAúIÒR¶¼=Nï½i— ;ØõæIáÝ—œ¶|Â)7º—:­ÆF—óºl@®À¹ýÎÝuŸEi¤ë¤‰9WTZÑKó~ÔCŸãá¹Wsß³„ÁøefqlôÚ=Š­€u”[É7×8õÏ[–úçä o9mrGq6Á±Éu‰Ó7wžç{LÞ9^4™„?"H§có?€6É{Ö*›hhOÏ_Rˆ[ûù´ZÏíTBÃÈ’w*J;,€îÇ€s·0é©—þ ŽîtB öP.À-’ȤѫfÏÕŠXªõl‚õ®½šÚ$.s[Öîµ6Áš¼<¢æ}ÝžÁ–ë5¨‡.< à~Ï@|ζ0P§>:9ç&9ºrLø’w§%ÈïîÜmƒN˜jꃗºš(Æš¼w*hÁ›+PP'×ü ý¹ícß³ÝD§<¥Ò®×¯ßÉ67ÅóU-’ñýK'ÈOO¹µ¸8ÖµûúýJÒ?tФó:­é×ñ˜²-ÉDýØÑØŸoׇ_Ê€²äçgœ¶œ ˜v®Ú+ØÑ²¥ëŸg·ŒÜòÆo~êï›/”våÖàh‡ qŒ³“Ø :cäïaÑ-*³¸Ü<+ý¶vH/-±pŽ«§]ß3§]SK¨·‘O­Û‹s ß”çôœ ã·[še@“N°Û,ðGwIÂÈAçAè` 0÷ô¥î-c £®±¸ÚõP¿úo~¡6Á"`õknïú3&0„;’¼—ÌÝ9éïi ‹ÑàÜ ÝÌly1"›1ϘF@·‰œÆ ˆ³`$R^Í L€:y—§>yšÓ?1Kͨg\ Õ è0ë0e{^nî°n/‰ìfê`ë26s>ù±'S¬rmö\¥ÔT>í«2€›ø+s±æbÆÌ'_X€[€Z`Z®Üj§Öµ$Ë7~ vÎû¾ZEÎpï9ŸKüæ™êdÿPáþ¹M_¡œe±­j‰9¥+ÒU{;c]{MqÆqµ*{¦6õÉÝ÷xBã„äêÄÙÛfÉo+4§6 |âÜÀ\rvÇO ÎÐ]Nr÷ÌÖqfWßÀ ü8ßã@º€6ï±%Î뺪Ÿ~ðn Hä}þÊE·Ãû˜ÇJA*†¿‘ì}òÑÞ0eØ&¾%s@;¼«ÞU@ïbÒ²U†MÇ Þäô\#¦Ür÷ÚÀR‹±"Æ‹§1©%€ñåã; Àô‘ï¼â šƒx—^ãþbµˆnWÿÚܟIJãÞ¾€ºï“_p>:¦™;£¸¹¸k“ÖŒ{«¬–q\o ¾}_íª‹®¶úl^È7{Þ%ØR = >ÏÜQ»=È&9€}o°ëÙŽ!¬Ÿûaϵn ¯sç»ú LºÚÍž·šo Ißc“(æ|å¡W˜«.&¶ÜsÛÝà P'®z¾<‰œ£®÷ [c®65è“SnÎ̹Á¹ÆY›–¿­Ó<½¾æ±ÓIç·J™ªV¹ë¹¬Zú‹P @”Sv-¦Ðò¡Z¬ù-Àù`Ü uÐ ØI'ÆÈÌq\víÿض¹X«ÉÛ¾ŽsÚŒyÒ‘Cª·®k‹Å‹þóç/Å7uØW ÷zïþyÆ Uñ,׉A7;Ìɏ޷ÓyéäÁÇJ®|2òö¯ zĞ˸M¹ß*‰5Àé£b¡o>æ·~4à[ú­ìz *”gL_1LéMŽkœ°y˜û´ 7Ë¡wÔíñÛiÅÌËíÆA\mõ?F Èv«:å{^ï£9±à3>ˆOèørØòksÜyæš‹œôbÍ]ó¦¼À8L÷–¿¶Åzÿ;Ákûõ1žÓk̹ŸqåáN²vƒü*Ǧ.P/ö~9÷’–¼Ö4áRÆ,®¤í°ç0åKÞî±Xò«°æiùNÈOˆ5ë:EŒàt<ÄÍU¼‰¨ t¾‰Ÿ°èöFªõiÕCÇWɠܽ«=ÅšYkéô½Æ¦.úö{¢Ôñ޳Ìàÿ£!ïBÈÍkâ9¥¸8_å™/:¾3[0ƒo p‡Õ6Ž4àËmÌÓ 2ÀØý’¸w„áw‹;»‚ë˜yÛ©Õ\¯1¬ý6Ì#º|cÑ.µÖlùìÆ«ô•#л$ý‚´:†ášçAÿGyßÌñn{g„àçÄp‚öø€‹ ?ç.W»";¨qÞ××?Cþ8IH1ÿÌãâN¾yv¸“ž]1vÆÄ Ç¡‘/+‘<ßÈÈ)2%0çg‡,ºzKvT'}Ý”(Gñó nrqlgü*NîHÙ)‰‘xÆŸ•W”›±û)ØIÅɹoø »²ó0(3¸0é)¹6­Jš[¡Dƒr›Ãé!Å®íz`*׫ÜcÞ=lù×=O=Ô•³–þ3ìsþ–Ö©_ìyê¹jÎ%×` Z˜xŽ:°GæpsîµfÏ‘jQc¸b3Šy-RÅbÏÛʼn;L¹û°åÊWÜc¸ ÌYŒªÕ‚4L92wŒá¸¿¾XôôŸ³XÖ"õîCJ#-C§yù„çÚ³±T‚´ŠË\Ûê´SZM÷?›ø²J©‰=Ÿø–ØóêbЕS>1L¸Áù[ ƒó[Àø€­éËþCñ„扛¦ЮÐü™æiש©­¾@:å»|\€Ïá¾€rætžÚahßJ©3å…»Ýcq_{û46(×{hì\r‡~¦ùìîO”K®¾æÌ”OÄ¥ý­ë–7›}] s\×™Wk¶°Î1ü´«_ þ¢ú0æÛùÝ-ÑÆsÔOwPŠM?³Ê´ÒÏ]'}•acãÄ›*Êã—êbR($w—Ã;eØl'®2lrx—êãúÝÿƒ)ä}ƒrŽ!Ç0nƒr˜õ 6·*šI7(Éü{ U‘a§¯¼çc”ULß ž{„ãÀ4NNïqr'}5Ñ¥²äeÖ:-Èmy©”¨šA:’zÝÇ ÌÙåþïvîãЋA'æ+åJAîyž_~¶ÔsÌÛµ½cƒs¤îòŒ)‰;åQíê>ŸýÙÐ>¾ÕtjŸ½ù®Öéº`~—µ¡¼õiwHÜŸ¹u—XƒŒØÀãÜÌ7“~ÇNìê_½ {®~{•BR}ÂäM­³F¼BÍs¥RâkDþ9L¹I%J.½æ~T¢g0ç[)ziÚg˜u÷à³Î®0 GÖÕk"Œúûÿí½Zó Í¤­´¥¿«D‡•Å7Á2!<ñHúsKÕ9‡ ™è×hå±çšt+ªÜ[c´v‘<ƒáõZí·¶ˆZ°0xwGcÝ#|Y½’é™ïh ¿Ú–°»m=ïyd*p™c:’uäæé3G¡zÞóè³e~åªk\ÿhUs½-ÿ1CPËF¿>gêÎy‘¹Û½Ù à|Î×ø@]à9Ruê2‹ë]¹ÓyŒËÁ}æ`Î}ƒ©2ص³ý2Ý‘¼˜õÄÅ]s•Àp _ê S'3Ží•ŸôìÉI~Þs"7ÿD•VKÀ’;.ü ’Y V(,:‘dÀ9 :á¹-Iˆw‰4Øs€99h â¨ëzµåË"9púÌÁ(çü1‹”vn×1J®…)'ˆö0*­¦V?j:C8µ¬›]A&¹CÇJÎ^Ñ ÍÈÚ Ò§Ÿüs¤Ÿ%ÿ,¹èIïkcδÍÉ;gm™ªB ûZ€ ̵a0¬S\Û=s¸eFå6,ŸÛ ½§Z+¿ó'_:Õ;w½r•Rû¶ØóHÛ'§üûb¹Ýåì¿=¬ú¬q'w9­‰éOè͹?çØÉ[õ±}®Ú:W@ÜàZ`|­úÄec¾ µzý3¿Žçšó±Û3> s÷#Q·¹ÛÇ)‘&'v…y"L9yæí¹ÞÎí 7H·´¦üÈ+8îðpžœrç—ÃÔ«Õ@ýQ¶ß5H—š#ÀÛ€G÷OL^¹ú™_Çö;÷üÍ•“ŽaœôþN½±6½t¼$îbÖ™cƒÍ,9Æq0ê«¢Ãö«0û=Š£È¡üšÙóä¤Sr­6¹îk× Ô™S c/`îˆȯP,Íñ(•Ò_¤¨$OŠ’Æò Q¥ž0é~F§G­üó„ǤXåù5­7–-k‡Q/c8R¾t~Z@;¡×9J/{þü¡ØòÊ=Çð•ò©³áƒŽÂ.Šr°®€=§ºú{eY{¤í‰8»os8\Ý!aæúTö9—DÞ¹è!¦­˜s’ZI…¡é+¯\f}§kÒ ÖËô½n†ðjCæ#÷c8IÞß5û~ÃkýÈÙ'ÜwÚ+Œú6‰[µÐÿ¡ÔÂÔ?7&A½K©Æz=»d7Aª¼â †Tü(ÜåΤp®÷>ŠÀMÚBŽRÚ ŒfDAMhÞŸ6žŸ¿*‰•qym@€9\Ü[z>á_ÌA[í–ðA*v.8µä%ìs³C£è_îï0ìÇ;äŽÃÖý¹»”Ü‘™A°ï?jÕJŸ‚äŸk\²…òÐ×N˜çÕWT}DË]8_FþÒç&a¶½wú>HvvOÉ KÝqr÷ÜÎÙ±œæ³; @‡5'ÎíÊ 5’&€97o¿óÅ=õ¯¡×ÈŽ­Áü«~`s¾Àzç »O`¤B~ ]9è:§˜òõ`Œô¬eî>N®n­3ƆÝöy€ûޱ »ó;ín lïÅÆDæaÏ y ™11âétWísÏ/PžRkņàÜî–àŸÞW ;½Ï¼?õysŽ^ÏRwï0êTtæñiÒú˜Òkj ˜ïjI€÷3oä “–j`.°}/¥Ö’ƒ® ÔlºÉ¿?¤Ïü0Ϊ‡¾¼Ä&²¸ITHЪº•ù–¥/R¶Í¿Ì­L潋åov>¸•ŸE¸k™ÖuJ7¯ÝJp1æ!u1#×Õç(ƒòs 7å^®y+鿎Ká/wÞÛÀ–¢í)ëÖŽxõ^ýP¤}øc™1êä/Ô¹…ò}NJÔçÀ(®œØ ÐÙKMĤ.›5wiµ˜H40GB3å Þ-¹®]7‹–í¬›Nbí$žn*ïn e+ˆ°ë®S^yAÓ*|Ó½Ð]lº A¸i#o‡Io÷Žs€xj / ùÖ‰AŸ0s¾eîz¸ ýÚ%J`Î׃/2ÚÌýÐÌN8yf„ÎenKâRª…yç¶Ý±ûr‘Ý5ÐåÒîÅE³äa `ÒÏ„%ˆ1\< 剛^&=Œ1†#—P-̹ûbÁ³kG_-ʈH&êÇœÈÌ6‡¼Id›°AÌGêY`½t-i!‹”à0Nè}æ\Å%’öoÚ9瑳““¦|ç¡KN›\Ø€ˆé®®ó,éƒþ´êMÿÓ¯É Nîíè#-žºâ2†»)×õ·†-~{ói:-aö<ýwÔÎùšÿ)A´Ïñiu^ò•UžË}Bç¥ëÈüž{ä<>1ã Í;4°·]RlÕ*8Ÿ9‡¥½&F=fo›·~Bmrç—Wà¾xÖXàUc€sEƒpŸ§÷/&¾Ž5(oÐŽlÞeÜ.Ì·äs9EØúëçòô©“®\uµŠ˜ÇyfÀøébÒÏ`ÒÇ­¹ûDú&À>¬¹ä4{GO7™éD9Z®üó§`Ë1ÝhÙ»nšbØ-CÂi36}›csÃt©J¬)§‰›´ÙuÊq”|Šüsȱ£Ûæp:&C”k…‹{•VËZ¢—9¶#{çaénr=t‹QߌùzwIEËä¹_ʪ·l :Çaî—בeÞ†p§9³nßÛÒöiÎͤ/ö\9† ʉ–µkNAÉ€¹óä<"o= J˜qEæÔ˜—´]@žë¤6ófÍaÒwÄUÏXŒwu½†æH^Kæs8ŸcYûì§~ƒA¸€…Bs‰ë³€èP¸ÄÚ—]ÿü3ß@ŸÜóýɵ]ÆpÈÛ ÎgþíïUÞ?s @«ñ3¦/à3s:A«#+ù³æ˜§U^´úÌ ì©M,§o0®–¨¹b¼‰ ºwýr®iæºû}ìØÅ½çÖ0èÌ]DF_¦r‡¬ÊÁãÛ÷¼6²ÇÏbÓ#wÏZ P®X }×A·ƒ;k´å{Üi‹=0~VyÞdÝzÊOg½JÕ"Ö¾ì{}Lî¹¹KW cKÚé‘i‘»CÄÙɵ>ìºð€1C—^ËÌ9åEîʳÁƒ±Z®ÝfqÍv/@Šd’”MÀja4p ï¥×ÛÊfTÝÔ]oå2€¹ËÈyî¸fz—ï& —.“¸68">D,5yÔ”ãEé—…|³ÖMóÓßÒÚþƒ=Nn^QõÙý9bpæ¸6tmú–L›ôŽî„ü,--é Þž¾l‹9' ÈÏ0…{j‰µóÆ|×U̱ˌ*Ú$NÒ÷Ëë [æ~ÊQ¿Pž›–òÒ}³;¯É–¶ŸãØNDÞ¾o¼ve· ˆÂÀ¼jbºÏMŸ~Ú;q ½cÞ ]ÇxØt„Qß&*t2öä£;¶´,;ÙÞu.÷˜Ã¤ [Ò¶™ó°çåï\ôŽvÞ¹g-Åc^Ò=Xú‰-i'çÜ-ùåRwËÜaÐ#‹°fÏaÐÃÀĹ(IåbsN`æ\¡±û,6©wk.à 87Ãö\-AŽgä§U©êÐ÷¼ZJ0‰ Ÿ¹ÔN^îíæš ¸¦Ï`^ã•W›tôgþÙ_ ØùúHÜÅ Ë î¯UbÍ%ÔNní䘛!7ð=íÏL¹9€z@×€°iÓG­ÀÚ„€·ç¯ȧø0¶ÚP»\ÉŒ¯3pkÉ6l2À”¹×c®ÏãõúxÞC–¼ÁuK[ç€nÆý-w¿¶ÿÚ æŒó>HÝùÑ¿î¤k3çö´銀t•Û“qÜ0ç-ó8ôaÒ¿#0nó¸ß·Ãû•ßù³_?3Õžûôׯ½ýa€·ØôÐëõíì®ï‚ZrΫÜÚ0×HÝÿcÇ«½dîå¦Ã˜«Ÿï÷amt\Ý)ɆçE§Ô ø!\i"R÷ÈÚ+¢&RT:Ð6ŠËœ¤îTÍàÌfêéÉAGêŽßHÀº¤ó铇ޱtÔ[{¼CÏ'b.·ÖùçfÏ#q¯œt€{Àù IÛWŸ4µKM`ýü¯Í{‡ÁºóÏ-e¿·Àù´Z„(pX¶>ÇaÕ ‡|XóU Ý <ìyKÜÝ·bñ‚*;Ïz'€¾¼‚RÑg©#=¦µÂÒl9NîZGÆ®Lˆíîn%gÀù„Æ©‡îqØr$q³À9iœ H,]ê ˜Ø+÷œ”RÀß‚1ßãäUN™´ÖGXaá‹ c!öÆUà&4Ágœ_ªepÕcMÉUSl¼.ó¸ È!P«ÊUº Sâ~í2ߌ«ª¬>ØqÏÅÚ/“qµÏAoà\Öð]÷<¹°í-ç:ꃷÝ=ùíõÃöÏfYD±›l©D›Ûq^Õ¨c·&Ê€üÁÛ^Ÿh×Âþ=’ReÖôžì‚©ï±j.Ó9-iGêŽIÜçëìÔq£°ô&cÊ­-Ó Ÿ³Á¹_9»{ÄÑ·¥ÕΑ¥¼ónó€vò’otÑîWÍœs³÷9ç€w;µ“E;‘üsŒáÆìdÕüŒsû´ ºr½ÖŽt€y€R·tIÝä'ÏÌ|--r¸×(Ͳ˫Í{ݺï…AóÚÝoÉÞãk Ô¹çÅ ÇÁÝÇøäþüO›ZTEÒî×ÝÓœÇníÔ{ñPmBŒ;cI g {^½™B×–9œZÖ\ƒ;òÏ0O0P§–HÎyîíaÆaÌ,ºÚY¤Ú_v9ìâÄy<Á¬¹òÑ<ÐͬŸÚ0èÏ~ú/Ä +×w€ùÈÛo|W9èÉ? ô¶ÀùŒ|’­o þsÂã€ó€pâýk§]qŸþµõéÀ'@˜:Ü€>LÍ`wŲ/ó3☹ÔwŽv_“`|xn×:ÿ­×&>¯–˜yZެ/ß;rDoøœUV­Î÷ñžËÏÍF‡ÿ&GNð€sú‰U†íes§;HwMüœâ£2,üCÉÝÿ§óÒ?'ó¸oüúù?“þÕé_›>¯ý‹bÉçÿ½Ü%‰·ëûôå”^{³ç>> Ÿ´‘eW9è0é¥Ô¶B楋êàÙÈÓ½¢û0èÊOÇ0Î÷*ˆ”ƒ°ëþ†zÈ÷¾Ú³LâH/ `çÞÛ¥-‰ðžë¢n¤ŸÚ¹nÝ÷aÓì,zÀ; ½6ŒQ|ÏÇÈÕ Vwµäîñ}!W-ôóg^¹·dïš»:,¯žÿaÒ1“e. <*¾%u70a)|‚ÍžÓ^¹ñ!"vîyÉÜŸeãÌÐQ&œ¯2l6‡ƒQ§ÔÚ&].Å{jco!ÇZ;RVµ§sÐä Ç¹öœ|óQÆ—+M ä=·YóÊCÿà«[›E§ïõ¾0¬¹çœƒN¤Ò“úŠ'íân,ãœà$ï7!oÿÁg“Wɱ¤ß>WŒ¶ðŽæÀb×µüœ9¢®kxµaØ—rº¥ì­÷ÆBÕv§­ä‡$7€¾ê¾7^4q¬ß¤¹óuÚv¸»°È$Ýë5ç sçúƒç稀²Úç½Ëh€À9·õãâùwuïÝŠßëŸm³êU÷½à‰ÞÁ²‹;ã–µoi»Bîíø‹’¸¬Ã–€/~ƒsB94nõsX`NɈ ÚÅ”cg÷K1ç¾™a¾ÑÁp›ÂÈÙ)³¶k\ºœF;{²»ê(yûª³Yìy9¸?¾Œùæ kwˆÏÜzWým7×/°NÎØr_åáë¶À9L:Ýsíàθã56°Îœ™rç¡¿W@KŸÛÊ9§ïH?*ÓuÏàS÷\פŽ.µÏ—YÜôeBTq§> GËÙ1;*°Ž¬¾Î%ï\fL'©h¹Ìµs{×)þ=)ö"·wê!#s7»¶œ “ë:绿ë3ïüóÔzV&ýé3ÏLéªçd¼%÷ékÞÐo»ÔÙ˘¿™WlÈ3˜g|½¢c»‚ F2­¶Ë€¹í(Z€@~ ä· ¼ÙèÔ\ÿL-sŠ»DGÞÁ|Þ—÷½@Ÿàš¸Qæ­~O¼~IÛݯ±Òæ\Ê®ùo¸K³‘îMKÞß‘£ÿ.Ãæ¼tt±é#yÿ®Ê°@úG>÷íaÒÒÿRïcvø•‰ÿtª—~íâçt3áU=ã´“«®¾U&ÞìZßEWFð†uÒ÷wÓAjŠçqmoö•Î?(¹F_áû‹î#ºGƒN.ºË ­9Œ0QqO\yè6Žûs;–£»#`|+ â'BÆQSQrÍùæ~68ejù›,“¸éÿ®Ÿej³©¼Az¹º+=L`ž¹.¹–÷qur>SI+ÖµÝw}³õ«öyËÞµ£–/ÚÎ#™ó4Fâ8Wè˜ZtúOé5×N^»:×ýÛ«´šÜw í÷ŠƱÁ‡ç…€9›‚(x4¿@Ùhœ;>z~Ýó¦¿ÜÜ#gOàía³Nî½8¼¬WÞ¹Ž«¯ Vw»Ä&Œz‹R~ Ã8±å/œ?œïlÓw…‘˜Âm'wÀ»7¨ñbÑÏTâ=ÇquWîù!ƒ@w«0H_ïÍ–;7ÝépY4HÐk-?·K²´{ƒb1êu^¥”iÜ!ŽYÜôÉKéŸMoYînw÷·Ô]wÿæÛ'&ýEy"ŒÃ;æqäî;vxŸ¼ô}æëéÊEŸÿë?W­ôÓñvn7HGîî+€ºÜ˜ë;SÆq0åù~)JîÞ„åé_@)3-,;^¾? ¶ÉýCm|/vë´›èÈÛã§±ïuxqPû)Õ/`Õ©yîù×uÏ}YãÎA÷ù˜}Ð+l(êç¡g€½ª‰¬ëÙäPÿ2@N:×Jû²š ¿ò͵N¸}_cWI™kíæžgpo¢Ã¦Ã SÝþ2Ë­Ýòvʰâ쎟M“›%¿@¯È±^Û˜|xú•{™Ã ά:ÀTA‚ŒÏuñY«%'ÝaðžÔEEÊä¨ïê>Y'jlÓà£8p—–É1 ÏT‚Aǹ½sÐãŤyaŦ¿Oé±cüüº {~»| ¯á­‚}e±ç„eîjaÍ丹+U»î{ &Zîå7ÆÂ\­€1æØåA OY p΋ù€¯TæÂoýsŸÛ¥âúµ[ž_8ñ3;Ušß²y›ÄÕ.I9¸#äÖ/fKâ ìÀ‡içšfÂC$þrÏãÜ’ ¬¹Žä”«˜ï뜟ÁÎËþ¬ì’p¬óüǾ ˜ËE1îî«ÄÁ—.€\G$î•¿"sn@ž‡çØùóN`»S&t³cÞòŸ0çi=§:è0Ÿ›­ÚÌ €çæšmõ’<ùFÎMœššÈÚíÐ ¨ŸSZÍA\5ƒ.Ó]}rkKB&ð>¹ç”F™V\q›½ È68`SNÄ.Á PþøÀ$nØö‡׋e~6" Œ¼y †bKÝKÎîÀŽ9à\sîc,Ô@ˆœZ"c³ååDì€%´Ó‹Ò2KÚ€œ2Ei³vèÛ$ÎFq+Ç€æÐo|_w¤WÐ…Úƒþâ+ÊMç4¶1Ü;ꚬkÎ \ýmgð.çüòÌ#‘¦õñçÎÅÞ,:l7€  ›¼$êÍ’± ëœÎ'ß]Ç}NÇùœóñ­9ð^c‡®qôÏÑ ðÆ1÷yÀ<±$î Éýg3$}bo²À¦'.¬ãæo¹;õÒGînž¼ô[‘»OLºAú¿úöô¿r­ôþ_¤O¶ùß¹ûÈßÿÛäšcùzÆ‘¶+R® µ‰Î练›»¿jžg³œó•žâ8(§8ý€vÍåþ€ÊÆõÏì/]À\…êëØŒë㨂0Çä¾@_ê£öòPÙ´’»·Ô })&r¾ÇóP?e8{³7à<Þ&QrÙ w{€¹ŸmwìëÊKOÙRm’[ú¾ý^ÌŽ#q§ìé)`Ï_£UèÜHÝwýsúk *Û=o÷wÏy-d`¿»·OÉX÷Û(®ÖNñÂë'ë0n€:ùè+&dXó©O«Xîíæ"Žnzm9$QÖšQp*Ì{-+ýRR)¦qvlgÍV]­z­™e§9ƒlÈ0ÉÖãù¤´Ò͖ϱrt·ƒ»Õ´uO §C¬êO`òÀÒü¼~^£|®²Õ0èbQC/©y¥IK‘ ö5Æï »ß£°ayùVž|“¬ÌÕç£üZpæ*¥½¯ÛrÿfÖQž7ƒ~¹qÙËÍ/‰ãüb“wà°µúŒ1˜ÃèmŸƒñÛž_r‚ËvYòÞ.ÿÖ×÷nÏãàÛy°¤ n‘Eð:K®Áµop?¦ {Gˆä´3&·d99¢KNÍss÷vZÇ“‘¿o©Ž¤8Œ« NÙ ƒóHÛõ^]WÀžJÝ —ÄhÅéX³çî€rPžúçC“މÊÜð=~åž@º^GãH¯¼óKMtv|”´ggø¼Lá,»à!–è ÀºŽ»/À{矻9ÜÝ“ó{ÕDDZ½K®µ¬½À: Øó5WÒöλ‹œ%ðHÛ Ð‘³7@‡í¨ ܧ¯’k–¸/)£@; ´b[XÐIÙ‹?ŒáÜÎ90>n Œ`Íí2OÊø¥Y l×;W¤×ä.³Ö9æäHTÉ)›ŽAœÚZ¬cç $0—¼Ù µŠ•ƒþ¡1Üza@ÎG¸“ƒ~rÕž8'wÉÚÉ;?´o9»ÁºÇfÌÔÛ»<Úõu–V+¨É]q4åî[,°ª¹®a—ÂMãåæ¾J«ÁžË¯°Þ€œÀÑ]±{Ö#s™¼Ç2¾ÍZ¦Ö9Ïù˜¤î»Ä }Kà“6ØÄˆ×eÏÛÌ75Ñ‘´#k7 gî<.îUf­Õšç)ç Ip>í¬Qß…Ew~úq.:¥…MlUºŽIÝZþOGÅJú©ÀzúÈÞoký/kþU½i»È:µr³âÍ +Í6à[¸vø˜nUt᥀)$,ø°AòÊeî {þX€ ÆíòÝMËîÏÈ{‚§E"D WÉ8÷wêõ•äî ÌQûÈÖÚµ{ÑFì§_5ÔK ¿YëÇÉÊëço‡¿þ#rMwèú ÆÍ†«MðEBšBº~GóÏ@ŽÄ…þ“ábâgÓB»qŠ÷À_;rÞÁ;4¬ † Ü¥Ô¾Aµy¦p ˜õ”¯Ð°Ê^ =R[f=7ë6Œ»òÿ;û^ÍÎòºóa*EÇÁÄNŒ1¿(/Uÿé‹JÛ´M•ª Jb{cj¥?{í[€ôW:¼Ê }òÒÒçZÆqÞÿíÊáýĦÿìgï<ø…7ã+]¡ïÛgÞumô(Q¦äÝîîšïô5Ææ|+` Î KßIo‰¤M½›%‡9)¥î_áaÌ‘»“—¾î}î#{gC³¤îìÝÅ +ܹwx»}7mÀøŠ=G:›¾„­çÏRwÜ]Ï9m“›@ßê³6ˆƒQ_ñÁ«wè~kCü(½ºÀ¹ç÷úà֮𢵄æÕ Ô³î .ª{žþT·¿N—ZSh-e“¸ûNÔ:Ëýw”‰;tk5Gç¡Tï™ëÌ #c'ªúbÍSvÍëL³ì®>k_&T ÔBW©5µ{ík&}õݬ‘ÅŠSrÍkn‘º¯ 7P×úýmõaÐWÌñO½c&õ¿"D^0@ÝL9¾W[â¾ØçUi«¶æ—Ç.©%ÞRõ0ôJ?¨Îu°Ö?2îÔhÔÔÌ…A›ÜíÍú/鯭Á„´/7kÞ¸Vß÷þÅu—%KÀ˜×<~ðzqן럳Xÿ:×ó˜±ñN>{ò× ¼ë5¢)áÖ?G÷‰ÎY'l Wu3^»YÈÏ‘¨ð¥S›² €s ãtÎÚ›0·tF7ê/²£77w(³æ’jz ß\æZÉà5—]B 2 ¼ÙU4C®1@ü|™ÃùæêØnšv_eÖéÎ3Ò9šïüsŒãÈÝŸÖá¹-i§¯ðg0žÍì&óà1 owSÍ#c_¹^‹EGÖ@WxÎf/‘°Ðéô ˜uÜÛY §SÍófÓ0ïˆ[1´8à6(ga´äíf?´ðy—9ËÙSçöO_»k„E`íÌÁ¤[ÅñÇIÙñ-ôIÇÐÿê_Pÿó8¼O-ÿ¯N]ÿÿq23“þGè2ÓÿmrÍw61éslZXôþþ8œ ÌÍ–k^Uä;ñéûîgÓ ¦\­Ùt§»ä¾A´É¤Ri|*cÊUIÂà|ÚŦ#uß2w;àœðœ¯/Ó ˜S†­˜tûbÎSÙCmLD˜Œª%]Jc©±RºS›Ð€òÊA¬/æÜaux…Á¹çªÎ±äÇÉÆ}€ù´ihIYûttžñV×e}£¸µ‘OMôÊ3ÞDA§äé˜Ö4ŠÐ3Nºß0ç^;) ¾SçæÜl:Fq–º«þ¹¥îù1T왵% ] É»Y#6ƒ.0îu`äîJ¹œõé’º;`ÎéºÆæÈÈÚ“æ‰Y2òv¢Yu]ç2Å«´qÖé¬Ý b埛1ß>TãaÒä] œûŒ£{ŽÊœã²Ë¹§eÍö+·ªþÌù°åo¯¼ó´aРΗ¢/¦Æ Ì=7A-t׬yØwr;·“sŽÔÝÀ’j[ö£¹–¶˜+rÃËŽ¦À<ùçìnÖMöWîîÜ¢ë+ïn䎾Ù'/}?,¶#ÃÂè¤Ë­ùxRíÎÓ¢F(9è€so*êóL.z¹®®šç°éêóž6ƒ»Láî[2w0^òvp/.Èh—ë¬û¯/¶<q0 ÎÕ“¼]Ç3fQ@g!äó=W ½Ë«Æ+¶ÛÝÝ9ФîH*Æ—“» ×ìú¼÷—¬ÝÁ‚Öü‡YÌÂ8‘»)¸Í¢¿Q̹æX,{Ñ[«®ó‘±;âÚÎ|Ëc³Ø‡…k&OàY»M®ºtt±Œ“¿‹Ä}rÐàP—Ìý;0èåìyùÛHÜ)–˜ùžkpN´¤2]X+P.c±%qo€Mœõ1¢%×´Õïzå0ï9gæ °ÓæÃÐWÇÜ+òúîxs ¶½jª'œãD}îHø‹%ÇÙ½BL·Ž/O€vwÏÆ Jˆ³%wWPšÍnÿñfÒ¯+Òõ¿èøè•7Òg“è›Îÿ2ï³Á4 ýE@ú©•.>S_Òë,Ó¸vs/€o÷ýk月ÈÚ3×9èæîûúfÌORxLâÞ¨²ŽníŠk>©{æçÞ‹ŽÄ=s%i_%+÷&)÷æÍ¨S÷E”ÇÖ×Ïqr'&¿üÝéÔ@WˆU3~¡škÏÄ—“;±Ó¢23H×ós9œÆi?xížžÑËÀÕ’÷¿#sŸ×Ϧ»ݳ> Ôßu;p@‡¨ÚçM$\`w""Ün);c+åì°Þ%m©¢³Áx€:•xJ5¹eïrˆ¿—5¢ÉÜÝK™©H¤W `È%ª©%ÈCÏñòkZ€½U«{-~ wÅZÃ:/9èuÁ€sãtµ1™ÆÍ=Õ¤'•XLvÓ1m›ÀMׂ‰Ì…ã6³Üå¸;Ÿ½Ò©Kš^†Üœ¿S²AÁ…Á¯?YtrÌëXa\páþÝû@×ÁPú% (à¾óÄ9æ¹>üÁÊõØO²}ï  ¬¥-S °ýfõ×yUð^çyÜïqÌ”³y¡1õÓyŸ‹Üçœ;ÞýJ\Ź=åÖ(½¦/¨Ê±ÝY5çóX®!yg—ŽòŒçËØÙñs9夛A·\½nXîš‹£»$Däï(_.€ïf•YÓu€óÅ ÈÓÇ$®ã§aÑõˆó'q»¼à¼Ûì(Kò¾Ê«Å,.yèâj«Æ¨Ç䈥¿Ë«µÄ}Ím¶žxú€=Ô}®Y9qî/ ;QµÑ0åfÊýÖ9è,|Ò‰]ǹƒÈΔX£ôšb›¨‡AOYr7ƒcVg¦§âžEÖN‹¼³r6Gâ.ö\ |rÒ×b8îæaººï|ÒÈXêop® ¤Z¢òÐaì"kï°)œ&Pàã'>þ»蓇þÇè’¸cgÝýUµ“+IÇ™ÍódÀç1ÇÌ7k.Ã>nî* þ'̦ד“®ÿŇlºÊ°]yÓïWߘÿãÿHÿäŸÌÿ÷—aÒÊÝÿ¥/Ê£8ç hœWNzrÎÊÙ “î{€K¬Ý<_õÐ'R2q½ƒ ¿c&= }1猷9À\Á1jŸãì®{¤ú+-`Þ&œºç¢x°§Õ\@:ýå⽞ ó°è8»§¬çJ.Ù{G|V&ô|€³Ñý®"©c´sŽÃÌý3‘·ûÙ¾º7Õ Ì'¶"N¹çî;Çü\­ÂéqfÌ=‡)œÖ°æ¤+ϰ6Aênö<€üì´þ1 A=tÂêC…KÙÞp[ùçg€õ¬Ñ†E¨{Ž>‘µc¯ïKîþ½åí^wjM¨qTžj'.HÏœ€Œ²šÔjÑÅ '4U”èãó¤ÐN t¯ïÉ?'l0—5½ð€×ýt‡ë¥3à]%\‚i\À8 ^GpI“Ž[þ^8/@–™ù"A·˜Æ€|@u•ÞvŸro»”åßùâœþEiMË9?’ 6>#–±Ÿ=×)¬Íàê÷Àâ®BíûÅ©œ×Áëò€êr»Kh>mç4>¨OÎü2 h©=†tV p^ƒûšÃ@ ~Ž#yÊÑ]mPI;òÜÛÉC'vÍóÈ[Zæ.`žšçH¾N]ô•û`ž ‡Æ`Ý’vrÒ»$`Fù#£8J­É$nåŸKz„k;L:,zÕ;a7oÕÛÜ7ø2{òŒ‡¥X÷2†Q×{áRºdï%q7(“ƒîÖq“9’˜Âe7;ýÉ«÷èÆ!{÷NºÆÈÞˆU®…Ü6{rÍÚã辌o”_~hxc¶Üç$OO¯ : !b—Ø;gÝ «Å”ÌÜæÔ=G©(`d”%¯|ζgéš”" ™QßÇŒ·¹ÒÎýLÞÃRÕ¸9‹]G®:ãô9Ýí®‡Ž$–|Ö˜OüëLª"Á]ÝÅÍØ&q¿ò‡r¼óô1ÚšÚÒ/~ýÁGÐ_y€>à(kßEÎn·ö ØábD;÷†œpµž·„]Ql­@`™—²äíÈÞ¹æÓw ó¾!'·\@ûàV4sŽ”ó`Ó3ÏyHá¢@Î?¨¡Î“¹½YAƒô€l©ú÷LŸ¨rl¼Žþw®R#Ï·rr×ÿ ÝÒù¸»?§‡wäîª×o¹»Þ?ò”“.¹ûŸ…I_9é*Áö“¿ôÀÿé|þÆ€|Úe‡ÚDßµžó±¥VyþÖ}\ÝoÇ,n+^:]s8EÌ"aÓ1‹ôÜq´’uÏÎ;?õVUåŠbÒ º—AœS…H5Òq›Ä©´`RkÈÚu®RËÍ}+«šQÿ’s?WªôÚbËc`šÜt=aÎ Æ;"qw9Ñ®vb“9æaÓWúØ~>ë™n}€8yèŒW-ô¬”§sÎܪÓq‹v÷vˆ…s¾ËËJ=¨ãIû›öÜ:Që«´îëØörXò®õ›Uq­íÐÕgýG ô'¶Y PNª%ë΀ò-u7á?¹®¿Sk]𬠴ÏלƊbÏ[®ó!Ù¸8àÜNɵíeµý¯Ô£¼ãy0˜£™jbëˈKŽúG9üöÊk¯üv~Ž_Ž?W~8וAº"j2ûV¿Ê‚ïë ëa$N¾=ןçœúýQö›öÒÞ`ÿ’¹§½åXÇq>PæÊa=Ǻ3ßûÇ {m@té³v(äY;@ùù1’ãZò%ßàçô9êËä­ Î1X߀¼úúb*"u'|Î åßÑ ýê’¹WDï¿ûíº.mÂ…MOÙ5˜s€zv'çFˆi‡™vÆ7tS¼»ÌàÔ6{.à>Áî©ç192¡lÇ´qrÏN®Ûrp_ÎíO¶ƒ; ü&ò/rÞ½vÉ´sddHÞà'æ!ywÚÊ7(_õNOröëHßÀ/€¦Ü}/yž®óÜ6¹ñ%Õ–¸Ç4G`¹»cÎ?C{圗¼p3è.…#@¯…̼oÕ¹µÜfPÚ½]h'¿±¢ÜÚµx;»Ÿ1‹O3éÈÜ},Q,“9éf¬˜ß®í'î€YW„!£æ1LúbÐ~Ns>>ýHhç/ÈÔ*òZæ1†Sûùbƒ>ô’¸Sf ÷e §¶óÎ=çq;¶¾Â¤Ö·Ôñ’±3.ö;ÑnåÄ ø6¥x58WÀHÀձܗŒ:×ÞaÑ™G_ïQ`¿L澓£ÎçÑ\ýΚegŽß%5æ Ü7@¨°¯Òk(&ø»uHOÚÄéÿo.&= ]eØÄ¤Ò_´qÜü§›ë¤ÿ«ß{ð“Ÿø‚T$vxÿüê˜*~ŽœôŒ“þy6Ãô€ôçç¾8w\Ýã=‘ºç]¹!`=æ’xXP¾±º@÷fÐ=çŠ;ýYd¥íÀ §ÏøuR†f¼ZzÝ—ËÍ}u·*Óvëû™°ª|”O [£îØ ý‹A×si™ŸnEìùqƒŽùêbÜçy»€¹û+H_3£Ni5=¯½¨H°/B@ã–»‡Eßž9™Û÷ ØãÚŽ‰îDƨu.„‡ç<†Y†¾+Œ»RåÖCè¬ßÓXkHIÝ[æîœôÎA?¼½­ÒkkN­H(ËÚm·Ë /9»ÖÍ^G;äã4sHÜ€:àüÀœv)gÊi‰J­¥Žxæ '=ö!œ–ÜýWÀCaÁKš~L€6øn“¹Ã [D0¸PÏÙ–ëÿåÏwe±Æ£»D\—¡+Æ^cKáïÀ /@Þh±}çE:Q_ŒüÒ¼ëªÇø 6Ð?>ÜrœÖ›Å?–,tnù–ô“×P9õÇfŽÍ~©7H Â-1 H?_î§üv¿Š1§:_ê sþKÅ£–ϯ¼triȧ±„Ýý БýŒt9Ð5$îš8_ ú7ÈÕßf×ãÔ>±ã]{yM+ýñWîªO~úÊ¥ÂôdÆìãhЬÝR÷´HÚÉ;wÜ,ƒrŨYšúç œ³C>çØÑUmÉÛ©¥ŠSì í°ȯE‹ ±êÛÅÝòͽp ¯R4%q/&#—Rs~ eíŠï ¬ÃޏÍ" öd•YsYµÍª—)uÒÛ¹½#ù–ì%ï„q8/s¥Urm™ÄØ×“8›ÆE抔µâbs¸öÛ^À“û ‹'`àþýer%€"pr Б¸ËM€n“8·0帷7h‡9w¹µ€­€±Í’ÛhLL½œÊ} àá~Æy€¾25C^]ÒuÆFiU¿ÜNìÌ ‰f±<ÿÂg$Iÿ^å—kNLjõ:Ò;oñ:ß-› êßä5ÈGoÖû…ùýw:ÀÎGßyæ™§ÔÆ}Ũ h#wßnýkgþ_,‡Wô‘Ú¬[î> }Xó7éÎI}úË6ŽÓÿ´äìOÿú€ô_û Îî³Aõø/ñÁþÅíâ‹ã×p¾dîaʉ Àùm€ùŠÛ€s¾»8¸w.zG˜t6ûâèî`þaýsq|0\]bÛ* KÞè0çË4Î })‘*œƒþ-/W÷®ÂáçŒÛ$Õ>2NÎy©³ôlI/”§çÚ ÔÍŠg#ºžm~:6ø¾(5lÉÝ“ƒž æ9Ïj¹úÛfÕ78ßkG9e\ñ»‰þVH„DâÎ\t‡½É‰­0LX}Ø’vÌyç|楒¼C:¢rÏ!Z²æS•|‡¼þ[lù®öÓFq6‡+÷„ޝºç& –,gG):s›¬ 8'ƒE‡ôrº¨ÚŠUVMi¬nnm r6½:Lºút“ƒÁMÔB÷ñãÞv!§åü¾í Våµ/Ç‚¼¦6LÃ+w]8V˜/còæ ÉO,¦\íQÙ4ô—+r½åë Ë^ÈžG&ÿžr?xóðßT|‚Úã ~]n³àã¨ÝñÞ™éœxØñØ6àZÞk½§Ïm¶è ^×Üñ—ÙIv½:åe‘9ƒw3à°æÇÕ®uÝÇq’`g0Lytú.S‹»nrn1ŠË’°;g˜tn¬–*)d¢Ð°éìžÎµ‘;áæ^ Ý×8ì*êÚµ“k.ðn0®À…2"y8íºç÷Õ ¯Ò%0æž#JrFÞLù­e‡ LIÞ0Ù`¼Æ™Ã´ÆÀ@½$õ¸Ä¤Ã¨_§^;¿×K ä¼aAN:ÁùÄ~ívtïºèAÎú¼/œt¥d¤Ûß?ôÿ=,ú×çÛ,ºÝ²èÿæ÷„EìŸÿ΃üËÏ=xáÓ]Œz@y}‡ðsØFq8»«‚BùGÐÚ2ßñqdwIÅgoÝ×üfÔÆêkã/s»y_mbòwÍ ¿^%Ö*]Rõªƒ¾‚ô ç\ïœMP]ƒNy5ªkŒrêÜ÷ó™wË&ìÏÈ$®eíºŸë¼ôÉE' Øñ:Ùê®6‰ÛÁ³-yèk󚾕c‘°ãôPGÚ^•UÛå]¹%Òv­3ÔÆ¹üô€nHú·ÈEŸ¨5ËJ㻉Ä9·¬“Ö‰Çf+Iû&FÔjcÈõ/2ŒƒAGÖ™; :kFé(0%{׹͠£Þk½,æ|Z˜s 1‹+õ¨Ú ajß÷ÿ6Ý>N+=ëí÷àǨ¹ƒ2j-kǃJdÛRݾOXfæNcû\Q-*Ô ]írxWš¸c#/öøÀ#Lq[jj¶+ti~UáÚêå wÿì5¿”´õsñûÑqp-Ÿß?ŸúG²zÎà?TŸ—ˆúÀ>ÖNíû8€¼Lܸn1é”`Æ%§`L{I1üÔ¼‰ehç¸ Äoc†«ËÚaÑ+‡d“®P¿"n–²Oø‹«–ÜtKnìÄÚí{äÅ·›î¹wvHÂó˜Á9çæ™˜/7Í”ZÃ&8ëøÀKw–Ô©%îz󄹘sÏ“•àCÄô$ã*±6Çfω0è<KnFŸ’)ÀøÊ-Kß.°÷‘¾áænšc`Û;ûèö–æ¬{¡³@Ùú,tš=GJxÊŸ™Ï¨€ŽI%×v®yäìÔ°åË„h—YÃaXÀ€pdsË:½HUÕ?×BSmG× ÆE¹sD;šA´/—ö,¸3gNµä³Zâ`0ˆ¸m ¾äí·}Ý*³69èOýÚŸ ÿÖ_ÜLéÿ+À3á:è;9h#qŸ ôÝÊ•“N¹5˜óçö›IgÜÒv3³‰“?¾K©…u‡É-`érioV³™S9µ лŸãÅš¤7è¶äœ9°N+@¯(†½ÙôúÙÖç¢_uÛÈ[æNÎû<]ˆ ,»™t@zm̘U/èÓw«ãä£ë\o}W†°è'þM™Æ©ü,ú¯urΠËÕýWO†qÞ¤úÅ/œÀùOüÓÏㄵæ|^û ÷œÚè)©¦¾¥9„ÙxÝ„tÃZù7sç_r;Áî#åÕÒÇŽð1×GGÚήèÎE·ìÝcXsÇ_ y»Æ~¬÷CB’+Ê„(_ªË‡ ñ¢u0^.îµF‹5WØ ¥9ã[)·©[ÇfзİøfQ‡PWw®–Å ]Rw€; žÐSö#qlß@½j×"Y ;¢sÌ–°h» \?}•î™¶öœðœ9¥ÕŠEWhÁªsÊ(. Ý \  é,†Ã¤;ô>·ÞUÛ lm-À³(hONº¢ô0q€ô°éÈÜ3†–¾˜õq²Fâ.éoê  /‰{ÜgüV˜ó‘½¿µrÍÝ7+n`E:ákTpf—oJqMàžœæfd‘^§F·úÍìÒïÖ ²ë™›aVP‹|KÈ+"‰‡ ?1éБµ âø9ß2uΣ>ºKÁ5«®À8n9Ó˜q‚?+wvmnÃ^±ŽùïG}ôõ7SÔæÌ ñ øÿ!=Bÿ_Ç ¤_{kâУú0‹.€þ tIÜ#sŸ¨/Kæ.ÿ•]öüö  ¿ÿãŸ}ðè?9{ðãÿèU}"uϦàœïVòÒõÝË÷°£¸%ugüCØrtÆJ¬ÌÅÖ“^OÆ ¨„^ç~—tß™à.÷Œ)™vQî9¬ºÛ³ÙŠRjtñò&I8=Ïõë“VUùç2•Kåœ3Nn:æ©öháy (φ7¾-Üó<¦œÏjžé³ù‹î6•[b +µ]Ö jµVpÄãè^9è¤ãinÇ/ß…à¹Á9`¶\ÜÝ'º´em+÷œÑBþ¹¤ï]R7-DŠË2‰KÜŸ`޵*@ý±+wÕ ”ãäîÀD™;Ì9åÖ0e® Š’×󑸣~%š;W¬”×÷NMî"øP {ßÊâR+3•:Y ¹äâ«_&Û—¤6S «Ë§ƒ6øG2Ϲ\›ãó yƒƒïÀ¹Í¾Jö}îÊCïØ0èqÍà D_Ì5c¬ä[(Ò‚ì2”I€Žë©s™WÐgî ^ËÝyŸÎP\.—`\s?¦ßUÞçS6®«÷cg%?ëD;ûe'æÑ-5Ymʨ­/×ÕsÆ–£«¶áÞI»¹{™Kè|Í)ÈqñÍÃÇ–«»â~9PN? }b1æì r ·ÑÆk€õÜìFvÄÍQ ywÄ‘SyçÔ˜~´ƒ;7nGmÌäš#u‡QŸsfžÜ§U= ùìâ.æ\íbÎÉ;O„=§®(õÎó Ä(.5Ð1…CÞ®÷ˆ\­`fλêyX·{; ½À9¬º@¹"à\õX}|>¯0#e/¹{I;tM˜ôfÐY8EzXA[L°L®ù6‰£¬¬ùbjÆ5Ø ÇÓ5?ˆ± Áyô°èa˜R’h¹ºkÞ [tÊ«mé)Ñq-cõœóÈoï\Uú ˆÃœ›±pœ[’kFùÉ»ýÒ°è¿? ý¿Iâw—Y#}Àú›è[⎌=Òcƒ©‘È{çž#k'0ˆ w X[îVç¿òV9¸–ú€3S;s>^’ör9ŒcÂÖŒõà€èfÄä@ýøc0Ï1¤ìzÍê+=­Bó|Þ‹Yñum€P’­rÒåþ@÷F‹á]ï<ìyþöä¢W„EŸVAËÑ]^ ßõÇ7' ПùÍ¯ÏÆÓ)}äí’¸ÿ±º6§Ðåæ>àü ôç7¼÷^•»{z$íR¬ï¥ï€ðx@l&üs‡™S,—vŸ—ŠlÞ)JÞ¾¢Á9f–8¹S:rõ?zóþÜãr?4X'ˆ ehß[¹¿ÈïªË#dG)¦"m—âê\Ï3ò~V¨E–žj¤ãy‚ÔÝÏ% M ³åÞÀ{.¦\ç†A×±¥4ë|ôfÍÅ’?í2§l¢·ÒMÀ;9éä¢ãâ.ð¾Òß Ê§¤«Õ±ö½q;R÷óZ«¨u ØŒ[1øäÉÁ=^<Ã)Ý/k&˜túûgÝ !â¶9D‹‚µ_›ÅQ#¢2¾HâQ´« Qf R)åSNÍ©˜&£2Mì¹ï&ÇΜÜWNºŽ)‡ii®×6^è6¦h97HÓTšïf­ßn 托3næÜÁ±Eþr]xHæ&i3N ïÍŽ«?R×Ö›óÁ˜àc"Jó®ÍNÉ8µÇêm”ê0èÅn3Wt=Á±Î)oÆ€})@.Æûù=À›?BÕ!WTþr…|Vå(´\¡•-¡¿$ÊåÐò’|1Ìœk.uÑ Ä¾/*¯¶ôExœ8úr#o¿â¹u3Ø;{É¡)GJÆ€óÍš³#ù¤ßOOr4ÞL:r÷tƒrvDÕÀïÝÓ3ÆtƒlrÑ}­æ6kî–1l¹p¾'w‚|-œÚ«dI"¥Ôžb¼v·wmÓ”\#‡4Ž®»z3æjèfÇ×Cæq:“ÞõÏ©wÞRwæaÏ}lÆëfŠ5,qÂ%šÑÏrvîºç’]¨Ó²ð3+Ã1ï·dî0>iY€z `÷5YÀ®šè#÷Ô‚VàÜÑŒUj ‹£®¼ÐÈÒÕ ¸ ÏXLZÎÕâ\}ó+6C×±¬>g€>¡~˜@É{àhùòIüa1è/™A#€n‰û«ˬÍX,¦YôèäsÀy*:,èrn/¹³ÎÕ±HÚ1‡SЀ à&¸Ö- ½bËÛê°è͔à#3?dÂÒn9N®9¡cžoü­=Ï&ÀfðçŠ.ÇÆ&„"Œº Þ,9æq»®¼úÔ>0ïZöö àï­vIÞùÿIÄ}®H{ž<ô ô7•ž!€>àüÏ‘¸OɵÉC@`þŸ]ní¿kýŸý¶týŸ¯rk?o÷uREˆ|ßæ:Ÿïgú|o“¦’¹´»äâg®£îC]j­Áú’·§ÝýU ]}qÔKÙÄÆ)¾"‡ )žlÞvœÒ¨Ì¢{xÚåèþ¡k6‡ëøÁé~^©]q` gÏx$ëwÙ §F:åNíýB)T ἩoeÜÏùRÚQ}ùÚ”Q\ËÜo£î6aU!%Öè—Ê0åÕ$o÷¶ÜÀœ¼s {gŒâ~cIÛCÄìv¯cG:5Ñ J¯©]²öÐmg0>¯¥ ¥3%†‘µ»<ñ‰›ãYK“wRLýbÒaÐrÍ‹ˆHè.6}Î V€9Ÿ9÷‹è(xlr¸Cv^6Œuá&EÜÊ CNäšõ¾×}†å‡†çÊ1óµ`áú¹×ögïh%@~‚Üøõû _WÚ¨Írô;·Ádë6Û\%ÈâxNŽ<Ì<×óAÚî¿ôÿ›ÞL9Ñ.õõžxWž½býÇ(!›Û(®k¢+ô¥S˜5/‰ŠYrvÑ:ÿdËbFz~wïÊÁ”+]¹é>ÆüæÛÉAç&¦ýeƒö¹1…5W¬›H…rc«Zè€qƒô8lz~€69E8¶û> Ó–:ÐK­)"µÂ¨„tå¦kç—‡ Îír-¥¬Úað°Ã15sz°ÝóC‡cØtžÔ=‡E'7=뙳“û_=÷¡ùERw‹Â¥_0µQß]-ò=7‹®sÓ§~¬8ìD›ñ8ßÜîYl©­è3'–Ä€üÆý°#:70O('Îñ–¸¿«07OneËܸãâ.V]}òΠܽ€†MàŽÜ=ÒVzJ¬è«×Ö5¸·³ÈŸX5ÐAº%ºHs :>žøåß{ðSÿúN`Å úWe¦…‹»Lâ,qwúÕïPf ÇvúvÞžþHØÓW˜/Æ´òÐÏ\#;@î¹éþ:—9m€ %ÔŠM/¦]5Ì‘U2m׃Rff¿iêÀú?0Ðv K>c‡À¸®qÿ{Í”§¥¯sÒ^ö3/‰{JÈ­üs€ºòîaÁ¯_”wÞùèbØÕò7+ ž¿¡¹s¥1h\÷Ò¯#o?™Ä½fy{L⦵¼ýŠK­Mº†Lâ íTÝ.îÿýÁ“ÿnLâ~“¸Ç>n“¸goüÕÃüó‡ìù|w“Ž ÅÀôõ;}WcHÉÄ”\ÓXlyÝ ªï{ZÏÙ©=sŠ(zðÄ |_{= â£gcJǦeü9Ô¦6ú˜Í”Dô×¹§² Ê=9ž»ÒFrrÑQMEÚŽšÊnïÙØÅ瀞ñ2‰›ˆÜ],ûôýÌSU͹|è…¦q<y^Veð€ôtžÑ†®yÎǵ½k¢+ßÜkRâèYstܲb¯Ll©BcòS8ÚEZØÛÇÌy”‡´:¶äí>Gë²TÐAGöîvG»Ö“´0è]š—¼ó˜ÃenE¤aFæ~Ï =íµRŒÛÁÕ)îqcÛ=}kWÊÜ™`­¿ âPÑÞ kvP¨jÔ`7tã \ÝIµmì¦Á—«%ãVGß;“DúàÉÊ ÷cØí"š9ìÇÏM+ö?2vÈÚ×:¾‰èv‰ë¾Êv7ÍùÌ‘ @/9îí—Õ£ãÔ}í,È© ¿ëÃQ>ÙBI l—°ýÿì’D’@!üúÅc’ ~ç4Ä5ûóz÷îRt~MzZÂnî|±è+"aQÎÝRváå–;è:' ý}S†à1½û67Xó{Üdí«îc3èóºïÜä\b-fqå¡“äþQ©ŒÎE?K»Øt_?ïé›=N¡$í;*yéÈÛGª…LKav=².bÉ¿R¦àP®6“ê¹Ú–ŸQÿœÀ$Άp0éîË0Ný‰»¤uop>×ÝK9˜iØqqzÞs@vÇÁ,x>c-B~DísŽi¥‰»Eî³ðJcXµÏqü…y±{°¢sÏqvǸˆE¤Æ Êýºä Ä-o¬ ¤¯…¯eîuØsò9–HHÛ©e+ì˜M¢ä«"m_Œ›Yº’ÓÂØ90²Z¥Öd~%à1}•YÃ$î%rÐÇpË Ý.î Ð u¤Èªæë2‘3Øò\òŽaÒï°­½Õ÷q@"ãÊ;'÷¹¦¹ó·ê´r `sŒÐ5’‹“+.&ÜÀùì¸𻵯éËÞc3énšW«÷ O»Ê³­zèíòŽ: ¹ÍŒßd|ò÷»”›)ú›j.ñ< 0¾ý {ÈeÖ¦o .i»Bé–·SfMòö—ÆÁýůŸ|>üÉÿ9æp_@—AœåíޟʬýâíÓwáç~ç^À8ñ…ÔF@ÿET( õõ÷÷±óБ·oO‰í¾(ÈMW»6ùþΠÍä¸'Õ¦áŒÌhË©}ßãœÒã’kÜ1Òt.ú ¤W™5™Á¹Pß¹ç LâRZ\t·®‡NíóbÒ#o¯çJ@úoH‡-`Άò<Ãó<#–rlU.œ»¿ÔgTKÉ9¸º£h kŽ«»ç<Žƒ»À¶@óä¥ÄåÚþÔu d1‘ 0ßDÀ“Y“èyádL©5¯Ü[ä„úaÏ+¨‡NÙÚ3Ö]Q.>~å.ë2ôÎE7_²võ1ÎÚò»bÎíä®ÖçãÜŽÄýÑ!ª²öœXÌùD€ºúžßëß ÖÊ&ËÎèòƒzç"‰;é©0è1zÖë¹u´It”¶WÕ?6›c3“žXªärWßã#‡÷bÓ Ãi¬¹HÌò kR·1êèïúííS…Su­çùY4öÏÞ’üÙ…™£(—1&qùÐ8£×.Eý"aÇ—aÀ@îzë™ïrgìPT<²_+ 7»üÙiI>ƒâr÷ÎÑ'4î?ÀÞô ø'À±]ç5ƒ¾»Üw@¹óÐÕwоÌHdÒOTÌÎ?wS ]‹ÑŒº‚CúÄbʸc¾Ö&qéóžn”HÜ“w'ÎìŠêuuÓ•¤Iý0æ:nƒ¹Íž?ásTcSc\Ü©ƒ€ž‡Úž(Ìž#}_Çò°š‡Wdî€pœÛ)iBlYû–Éð‡Öíêžú¦Å–S;uíÀ+×MÀœ|6—t kžÅƒæ'`Éæj‹!08³®v;¹GÖnv@£®s/vÖÕÜ\[un¯ßS»™sL„26ƒ¢÷30W¿Xä—€òrp÷µa‡âV,»çÞ#EYµ´»DeÕ`w©¤™ƒÑ²q\ âèfÊÝHZÃ’Gæ®Öc;`&]¹èqvî9¬Ÿç©….‰{ô‘ý~¥ê ?ó[ß ÌÚ€ »¸dlbÀø°”ß /³8XO–ÇÈ•ÊhUb­%ÑÌUi5!ç¨ïðõá°É0éDØqÅ1ƒn l6¼ŒàtlñçfÍv6îlê¾ö¼î‡ÙhÜ÷2E•$÷Ü€Ý } ¾6=åùÁ}·rÏÚ”Õy(£|׬"Õ:Öf­TUj ðäžw¬œs=÷ÒçY…Ì 1äîûØËñÝØ Ö“JƒŽbMAÚÙ.¯VÀ¼s6楜³ylXs¯'´ñ¯1åÔ¾¯(b`1çZG½rWýr÷“Ì]kž¬‰l¬{¶×I¤¦5‚„5Ø"Rfýwg÷ë”Ô¤]ǬšÜî:/ëG·¬7é«zJïôÌ+NÏÌz¶<—¨Ç¹] Õ•‡>Rw³ÞNMEÒÞùç”ck}ƒókŠ]f9 \ð÷¾HºlÒgÙþW;À-… Ùq0!¸±lê—AwZïrd>Þ)Øý::ÞïÛÎñ™ç}ô°æÌþ `]â(Õ;äñ±Ä½“üKšÀ.ÀùŒ9Ö¿Xv@ —©çr~K(ökðÞìæ¼€¼÷,ÙÁôÌò87‘÷þ{ÿþ¯ëwçcm¨·¿ÈM"qHwþˆçÜÞáË Pw w÷ù/-ö¼Xt$5ìà%æF‚ó¤sÙ“SÓ9è ÆºFmnlaÒaÏ{^àÜÆî:§˜sÆ„Ay›‡ŒËu™{¤íž¿¼}v_õpP?…%îœø¡hïòjš;1î~XÅÉ4 :21@úAísŸ;–|×@7`Ç ŽþÈÜi1™‘ñ[òÖÈs#§\°®¶Á;fqŠb ³Gø/÷vEŽ_ìàN}ô‹Lát<‹3ËØ5›®>ìLsæÅ¬o€îV‹C÷—[{•J_çàt¼ÃlTç}jq ³®E3l9&qföQ`Ýç“—ŠÛ³Ùõç?ó®Z [®>Lºcð˜Ã9¨ë,0’t$îvqf›ÄEâƒ>ÀŒÚçß3(÷ÜyŸqÀ¸\¶g¼»€ý*­µ€:níŒ;pzß /ln³îm‡)š˜óªw®@§Ö¹Ú½çn70×ùÎ'èoæÜ {óbÐ;üþêHê5£»{9Ï|n~/òŠþžuzA«Üqï¿Ù»™òþ–²³ïÕì<¯º¿L‘€vRb»1'~•‡P)Ÿ µA4¤P»6­gÆ3'g j4HUiB´U±Z)!+j“Ì€ú8f^œDý<æZÏš¥Ÿ.­³sÚ?.Ý/{ïç9Ï9çÙû^÷Z׺¾Œ´]þæŠWl^8*ï›9¿>yç×-m8ñoá¡ÜÛGÚþÅ)#øÅ?™ÿõ”WûªÌáæÿþ󽈌]üÇ0ç°èúÎdÃK­pŽr%J—eäˆ[{yJ0pÞ,:æqóÝ?B¡s”rCp?sU ÆæfÉÄͤ»úrn_¡¾ÿˆGÖ›NÙ5rÐÅ”gÖcç‘§¬š7pQYM›zçõ‘¹‡IGêÎsJ±^/cλûèOœÙÝW¸Ï³Ta#Vž³€t`ެû¤¸y­€yèWsì°Ì\ > 'wŸâ!¸Ófnå ò­Wiµ¬Ÿ¬‹ÿúYƒ¬{> -f¿egZè Í“oÞ€H«|ÌÚó–˜t­KÜí™tD0=í@Ij㸔\[ zùæöÅ¢k>}—KöÚ `Œ«E-ÞUK‰ÛÀÜcJ®MD! v!팴 áÀ]EÜ‚ËP^ƒï.KA{2†á7¶äü#†¦~™×5Á´|Þ®d¨vu®&pß6aËÆdµz•L»PϯàMjÈ)?mæëU©¶-¥W‹|œ?×¶ {çž³°WuÞ™y™ÇiN–÷ÇL>6þ½KÓL‚Ÿò§ÏVe׊-‡Eg÷­Ü—YÜü,’­ów ›Q^º®©zŒÇèB¡ÒlaÏÜŸÞŸ] =€Ý,?4긹Ðy@ýÂ;—£;:@ú<ôâà®VDù_¦yº%lí/iû…qÓËÚ‘Ð °w­ó ÌYŒ m÷x^VAkŽŒG]@yu—Á¹Ù¢zÕWËÂìG‹=7@gŒÑì’[¾0_Nîä£H‡1Ò"Sárjä¢;" Õq á¸ïÒkÉ]õÐukÛ‰™œóÊ5s̸Öc:¥ˆ¼ýõaË2™í6…s»rÐÍ Û$î‹ï  ÓøÍé߉Äý ]|埬Gæƒîã>É{ZZ%ºœÓ>-òèC÷/Ów[Œî:¿XssÔ•k®¸vÃyñ˹½J¨ ›ÿ«%{wÎùòó–ÌÖ}]@þ*å¦à½éÏk4›î`p>¯é ~«Î<²öúvzʇ0æÊ;œ—ŠBÀ¼díó¿tÏ‘ºç×OuÏço{Àù· οô§'c¸çþ¹À¹ÛŸù¥ß³ ® +…úâqegó ‰û2ŠÛßC칎%½*5Ì}@ÎXwÝ?’wŽñd;¹›5×}&sûØ’¸+Ô/Çö¥22xç>ªÃÍtE*id“U÷æ€õuŸ?;*£ésH*CÑb͉­ær?аmãSƒh7}òÎÕ/uÙ ŒO°±íüóÛ¨Ó˜Çù™Üa0®~{ËØ{†çëgãÊQ°Âž«óN.ºåí¨_o~Y$½âJ±æŒÖ—®ô[$çDEŒÖšT}B†˜/r¶mKç}nûUŠöÂ}EÁiTSJöü\WNs:ÿoãá¶%íÆ³ª¤¦÷,üùT½È±vžYyÿ’|L2‚¼†ÎãñúÕ¯ ýÞ!éÚè»Ï9j×ëóË¬Ï £Þþ«.^ÆS ×‹m?Ÿ•×ìœ5×ùç×%î6xƒAO©µ|Ù‘È`<¡caÍ#£Á¸÷ºÉŒIܺá`G™ À{Œ5vÉ íL*ê˜Ä=Ãx1çŸ&ž±A{äM¹1ÌaÓЫúíí*ã…v}u®Ží‡ }v…Ù5Æ0àŽ9\v #Ó.ók';sÏi×Ù9dÇáפ.ê³ã€r·Ô:§Æê´™w.ºsâ•—þÜüÜ‹!Ðq€{Lä`ˆ™‡™¨hæ N«æG%Ö’ƒ>¼]ã%y‡‰)®¾YŽ—ÏÆ}=¬¼ò.g.HÓºÌÐW´ÐDîy:ÿ|6n£ü,vÞwI5ϧ¬Ñå[Š £ž¼Ó×ÎgCãìÑ.µ@N‰¦‹~¤í+ôº· Øó€KÜÅ&&=÷Í _Wºò{wúëÎ!‡A¨/pþê;WHÜ5–L^}›Âæf©iNó2ŠÃœì¬‚ù’\Ú-qWù¶{«ôˆ(^åÕÎ7ƒ¾ñ·)ÇøM-ì&]²ùôuN‚ z~†Èá[ÖžÜù|sÌ)ª~¼•B±é%GùÀ¦KÇö.·÷Úü]Ô¯IÞŽ¤}þÇî)ŒOà|˜t9¶opþ9¶ÿÚ×ö?›Í'»¶ë=à\ÿÇÎ-‡)¬]ßobH'u¤ÝÜ%ko'÷»Žƒž1›nlЀw•^Kžy¯‹9ß %ëŸ+Ü÷=n—‹lW÷󵩾¤òêoy»ÏË'w3ãewlWÒ÷Ù¼…9º €®^Í™9gcXAîù‘_ ,º9)](ÆP• ˜û8 =Þ.–¸ó¬ÕñäšÎg žýñåÜy{æñµ Ï|€úô™+s[Ö:ËîÙY›©Ÿúè;Ýk4÷ÌÉ9_rwðjmµ˜sú´0KA `¿M˜œ±ƒ;U€ 䯼9u‡í_e×ðG"¼–ÕVç/‰û€r\Ü ÚÉ7ß¡ã:vÈ |?!¦sÅ”ƒ~"Ö*ïÜ€’í€ôbÑÿî¯ Žj·=°B` ‡˜% Z ìJŽ9sàºÕ3ó@‚>] Ü¯q$ŸogúÆŸ9¿R«ñQS îxoKòS»=ï])ÒôWÄUÞ}'ÄóÂì* Û/³¶vkwKþuÉ¿ùÀs¼-ë®aÓ×ëPOÏÒ Þ«>lç0v é_.„Œù™ûu:Ç\× ç5øGCN2ŸQ¹!úB8ôÅ™Æ9¦õϵo¦î¹Áµû䤨å/õÏÎù”nx¼¥4×Ýä]7½VÝ`˜#߆kzmµ)3¡sæê'÷ÜÒwÍÛÅ=ÁnfrÓ-gbT@]5Ñu“ Ã^®í1ŒËî+ùçÝ–·ïÝ[úÄÓsõÐ=¶AyU~`!õªpsÅ’…=7@ï`^@Ü&.yМëwvÑ+/S¸v‰uîÚSŽùçw,ƒWh¡,oIú| I»Úͦ›I`áã…PœÝ5³êѪ֬!cX™;ÒvZrÒ™AGÙl ŽÀ€sø#—áM³C¯Îçý]må¡ΛAWnz•@2ÆœÆ×âÐNî9­íKâ~í·Ûfù,LºúKVÆ|" >y´Hs§5@ÿÏÐ_|kúo~W}\°ÿBqHÜoÊÇöHÝÖ3®šçó¯ÒZ•oŒºÊta w ©.V½Î[s€rú”sk0ŽéZØfœÛÊv_›  &š1ÿÜ¿5;.`®þçæ˜Z…€}xÿA]tê¦kœ²qù €ôÎÃo`Þ@|%M÷\ÿ ¶ƒ;­ÔÙ qms1æïZÚ>à\1ó*«v_¬ùò¿œ•T³¬ýÕs>9çoœGÖþÂüO_UIµ_ý#å™ œË N)|+×\}Ô%î9pN`¸èØåÖ´kLƤ»ÅX’”j¡ß]Ó8ç¥soÑýK9絑(P®{Zäí÷¸º'vtÝ#ÕD§mÅÓVEY-åñô­¦ªÜs;u÷qq§?m€»Ü+kž-Õ/×vÌ:Öz¶íô¯ÝÿŒMçÔÕ¸k³ýö~Fo€Î;uÐ5¦¿*¼ÍžSÒµãœ0ï~À»Yrå›#uŸqúaÑ“¸|zðôYùæ˜Åá tÌE¬h-·“€òë;-`ÎZ¶Ü¦qËî£HUëþ‡îû\ϹúqŠ'kfy7YÖŽŸ“‰2båÛʬ¹:ı™r·Ä}"å×âØþstªB™t¥z¢±RÆDð uq³âø=ß8ê2¶žÊ^àPp£_#¯³˜ñøé+Û¢•ÕÈÒÃêCÀ‚W xã—Æçãµñ ƒ^Ì4¹°Ë Ïõ/ÜÇ~‰üàü`ÇÞåÑÊ9¹;Œ4ו±@IÑùù§â½•kñÁ…îíä9”«=Áçãs­<†Þà‹ ?¾A9KÞ&quƒrµ;þÞLYû#Ý*§cŠÊ=˜'}u»QÞ$ÿ¼Bó:×Ìv€y€¼€ù\7M¤J˜~pƒmæ\A> zE$SÈÚ+å1;½«´šÀ¹w~Ó¯¬°è#u·Ì8Ør¤cÌoPN‹«F9ʬ‘‡V¹èrs­òjwˆ«n³H¸úî#ÜÜo&óªä OÉ©?óžºë   #q¿n€îó Æ\röÔDìý"y»ûÌ“oI³Øöûî›q_€NLzç•wô“ ÏÖ9RZÀjçœ;’›Ni3j•S:­À9¹çKÞn0~>Ý€=Á9u}úr\ã{ŽŸ›Hy5ç¡7{NÙµ”N»¯6Ñ›]ƒ>íÄbÒ5§P_^ñÈß>À|@ºÚï+Ç\̹À¹6‹ Î¥ìPÎùüŸ œ¿,pþæ·ÄœO=ÿs>àüO>~î _Pþ5s•U›ZæÿO›SrêkþHæ¾¥íw½i–q+Ù «Ø¹è”Z3(·Qœ™r6î4«nuLî!ç¥Ô©û‘sÕÕ÷uÍšÇH.+¸/âË‘1ùæV*5{¾ý@’~´îÓŸ¾ùûzÝëaωK%îÉEƒÞ«Ž™©™sžo”]Òöë‘Ç“žg/ÀÍónyÖ+Ø„gÙ;9èT{ £.°m×v@¹ÌãX‹˜Hœcr›c›€ ºªÚÈaÍí^?QÊ–Ø%×Τo€^ì9±rÑÄmÐŽaÜ3ò RƒôKJ˜ÆÑ¿+®¾õåÚN{sBëpʪђ†ª9s€û’¸{¶\Q)¯àÛîzÚ˜O W^&hÁ6åÆ0oügCq@4çÜ6ùÉ{‚/Áli Hc`wXŸý²üt^»ãçöµàP°+3lzìàTý>ÐÑëƒÞ‰‹~é?ó/ÿÏJ쯜ëfå ø;Wýaç 4P¿Ä)ñ¡IÜÌ6¯üýrÆ6=Çê=ÛÍ©{Ú”VCN2ã´ÉÿX€\sq_h‡%/7÷‰åéMrY7P¯ýýiÇ­ýä0Ìù¸µ¿0¥ÔÎSNMàü¹éÜpƒóDJSÖ¼BÚnîþ¾-Æ\Ì÷“NšJ×C'È?’†{‚•3GÌ9€¾gmæËHàã¥Q‘Ù¨T[šÎ5ǵýw–J '÷vqßA¹Ì–¶ckNyµèÁó¨$îݸ·ã¹]ÇœÞã·Gr<[Ì1`Åûe±ä:†W }6ß—çŒÜÜ—²Žúç j¡+>5.óâ”XÃ'§"yæ÷^³TYÙ´Š°åZC™Agý”u•Z@:e×+%‘µóD¤ëçj“wîv¯!'NsËï(kO*…-§U¬2kåÔCwsú”) ›äb­½œÛ0Wk¦ÜÇXÿ«z“ñ96p7P' O‹˜VKøx@#Ä¢¢jaœÂQö]ŠtŸ ) 1L qãÌ&š pø…v¯ôlòÆcW$r®åsðõ™íŽ&`ÐXU»~Èè+§M¬ÒfŒ«Ä™ Äë-Vœ?TüfáÝv\ô©±^Nîõ fžþцÄñ?Yý£âšèþÈKÒW$wDmv¼È=oƒ8sç¢#‡ÙÑf•û¢`Žœ·fί¼úèË Î@];oþÐó®y^¥Õؽ kîÖΙjÉCG²ä2»ï¼#WýóÜØ}Ü7qÏÐÕ¿P¾ÀºŽ[âNÞùÚ^ýË P“‡¥e—у3 »zIÝ%1_L;®ªîˆæ «o£äor?쑹kÌœú°ãêxïR0m“. ¿¤ínqs§®¬Íá  Kb¸òÏé3"û˜ú¹ÍäÖ_:3WÄí·òatf£ô ŒáX"Ør·¯…y" ÌY‹…J_eÕ ÆaÏSËxbrl sµ’·ßUPŽ °NŽëA,¶| ä™ú{ ÿëo,€þÊÅ c)€>cIŠÅ`ÞßuÐqtw›\sbÉÛ] ]Lyê^¯üs ´£Ê®µŒÀ ç8ÇÊaÜ@5u¾°´=Wçáì¾@±uÓù|0éÓš»·¤ê ˆßa,0®Ölz±ðÊI@Çt®À¹Ù{zu}äû‹=Ç Ÿ o¿ ^ó¾ÆÇ*¼ùÃ~Ís[ÖnÇöaÐÚß̹Ú·5ÿöäsþ†™ó«S.pJ©Mœ;ç|Øôç?‰\ñîfÕͤ—“»Ã›^¤‹,Ž“»®oy»¿Ï]’ö”ïy@8*îvsWj }„ÎA⎉åéÓç~Ƙ¨”«50wk`^÷SÔJäŸÇ\Ÿúçl¾²1 ƒ®òœEmµË­~~± Üìy+¿ðX©@Q¦XÏFÀùÞüvýsõôjvæóií°åËoæùw§ÄZXôN… ƒ®×/÷Ríi­ÅƶuHˆé“îëfíc§öT°ÔPKùÚëœUâ–uXj +Jõø¬ÂŽúåæ(ïȺi{Jîʽ ®pŸµk1çßÓ_€ü]Àº¥îrÊ‹]TNîKÚŽÔ8 –Ê]=À-U &LðœSâÙ˜$õлR^^ºÎQiÎqr–ƒeGML èÄ7qìe5€¸ÕÊär/V:×esóR…+vÊ2®õ—±îí<Åöè1M»À‰YBQÿÌóG˰¿Úú»Ôsõ˾„I'.«U^» —ì´ôFý2ÀÉ~][©|ö‡‘“ìÐk;ç<]y$ì€é5ßhœÇnÆê‡IG&Cz¹/ï´ƒûÏ›i œMá¸Ñ¸?ïa@žÕfÍa×aÊíÞîRHÜg |…ëèêzôȵ°|i>‹šb|´}Õ¯Ù ¶\&nU+Ø _·ä{v:L:Õ“ÙS—Q"`Õ² ïp©%ÉÔÍ¢o@ Öqw™[MKž­òq#q¿ê:èr¾‰Äý“Ä}úßCâ~ËuÐÉA'Ê©ÝÁ˜ ¼àÃ0òÌ“£¬œä®s+ üã‘È3gr^WQÎíÉI—K»@p€8Œú¶íܾk¡oI:¡×U+ ®ãÉ=w¿y¿`pŽYœç#Å?_yóá-o´°IŸ~n67¶[>Áü’¹Ä—iœZrqµ6ÿ;“sûfî¾ÙóSš… á$i78Yÿ£oGà<²öÙdR)µçÿâëªN0ñÕÙpúÖÎ3§¤ZGG3ç‡.S9}WãþNÜ‘¸Œ«5h÷÷™T¼)0Œ3P/PX¯òjuîmŠ×S ÝŒ¸î‹Ê3w… ›ÅÅ4Žû)ŸIª4£œC:ì9ÀœþlÂ.&]î®…ŽY\ú”íDÚŽÿ lù§‡-¦¼šžUú ÔalJól¼Ð©ýù›yŽ’—¾ÎÝ2÷WàIa[}6ï͈¿`œÌk̺#¥^èHÜ! jýò!i}êS~íGç8¹³nJx/ÝaÐî5NîÈÜ©ƒžµáG]fÍëCdìß"-òéëB(6çWÞú0²vR4è. AE‰5Æíànæ<­€z@zWQ‚]ßd›rÒke–¼BósãhÁ”Z3poe2ø c6ò­ÁJšß¦Úî GÖ]ؒׄ07#+¿°ÚÁëØ2óœ¹%ëàeúòi‹¿¯i²;}<Õ’Ÿ‰ý¿ ÷œT€²>Ìð*‰€-¶½âØ•o±èØûéÿø_^L߯Ó,wïî쀾¦eú( ´iA>D×Ú [®±äìƒ~y°K¦öƼ†[Å|ýE^Æp|Ñ©cnWw@ûvŸÌø²yVùîÜœâ«Î¤n|?ܬ: :5Ð7X—I\Øòrå4h豈÷§åüžR¾N7öe<"°Nís{lG÷3EkN߀çzñ…ܱXt)ãÓD°ê°>s>ù‘i—t3ýÌ+såcã`']@\à\-€38jÎ-MÏã~Xôíà|m3åyL£b §cÊ{lÖó€óIÜéèc÷‡SŠª$îÐÿ‰ûÍ ê +ž‡9_ýÌ;º´–æ,m瘣ÝÛ¿lð€Þ‰³Î_GÖíxýú}œËÉÑ&xÀ¸AråÔÊ0wvLßmäíûç¦ûó€öù9Ãö—\¿A9&yôÝnÜÚiµ©²9ß¼K¬Áš;pkwÜ8ŸM¡Ù,¢Æ¹Àù°ç#kWiÀ8pþËÿqÀùïφÒ`ÁiÒÉC7{ž ÝeÖl¸¸ÒGÜ/E à'w}GÉ=Gú(7èÖ¸j¢s©Hô]îñîÓžœÝ}oûŠsÏu]yéÅé<î“ä ¯jn[É„_ùèÎE÷õÚLåžNÀ”ûYaF½sÐe:Ês¥*ˆ†µâ P?òÑyNö&v Ãª÷&: z”qøÍð¼h›®u*ÀdÝ vt@x“k£8ÚÐ?rÐÒ÷›&0BPÄç©‡Žœæœ:èmGy5ÀºáâU¤ñQºÆøágähï#ƒt§a¢ú”ªóé€r¿orÍÖ—Ì“d­»+¾zÖÓV£Â5·YõD ãÖx6ÒZ©à$ à>U b—ôXòЗŠw3êq!WÛàø¸”µúÍnî+ß¼ U«°Í*cÀ¶0XºÇùäàÓTÖjìÙÒ}|ËÓX³ŸsëÇ?óNõnlú ³ØêÌÅî¾j¡çÚr8ßÀ¶Þ˜úsÔ/¯ð6x=®/F¿êÊå59Æ?NzÈ2ˆ6’ãØwý’é_hn‡ÝåVÔ«JP~ 'w·–¥\w.‰Æì–¹/^d.fÕc ‡¼Ý,zæçÔ=ßq“~d=aÊ‹='],yv"7@§Ìš:ù@º‰ûåmýà&ýL˜rBî´0è%·RHâ¾4–kÉA“8òËyhí:èz°éxt»»—›j…®§®é’ºÏÃñaKßæu“—Ó˜v†]æ3Ë]ÖR=KÝYL0¦tŒçÝz^ì·Žáènv½<‘½Ã^=Qc/ÔpõÅÑÝ,ŽÚH(— BJ«Í"'wê¢W.º ;ïr(¹¿b•W³¤ôÐÅ]ÁÂz®eÁ]rw-Ìõé/]}3oaæ–)•Øt\¤=DÈÜŸ1@?• rú7l÷öÿ¤ÌÚï ¤‹=·Ä}L» ÐÿŠ<ôcNh~³ëê ´)÷\!°-ð­¹e(°^Qu·Kº˜lü-3É”ÛÀtKÉ€XÌâÊE0¨†I?ŽøóÍœ€#eOŸ2oe—þbÏw¿:¿ À7æzJ 1ýöPÛ76f ÐçõÉ7œ«„šòÎåÒþê”Q{ù-±æÿcþ?¿mp>ÿ¯Ÿvµ‰?%È×g³iÀùç¿:  ®?÷»§@ÂŽ9áM-9rw:Žíò©š0ǸS÷Ü`Ú}bóRÁœ'}¥ÌáŽzG@¹7í‹ANñ’¶ÛNe%Ãšëž Pgnoxf¬¨ê¾gsŒ¾TR¾·×3 šè¥ÊR¼xþ‘Ìç ”£ðÒ†3¬¹žÍ¢+Z}Ö€ü$a7ØÎ³]×îüsEÀ÷HõQÆa‡znŽQ½ØôUb(ýyrÔ~n“£^DHŠOY9‘8' ÂSÖ¶”‹!IänS‰'­Á´‰šmìvæåÚŽÜr‡uæè™#ÓAIàëHÜaËY#wWàÚ®Xùèa+ëÔ ÖïÅš3¶¢VêÛ¤Ê:?ÝøA@=}…™k¹wçx¼ÚÕœãÔ&\¾º\% ¦Ü¸<º1$órôå)Ë€r½_Ÿê^éW”iyGäù÷‹ê\‘ãO­ ßönı![d Í #{où¹ßà ¶sÆ#h°àí?ˆõ¸ës5{Ï//á9vüÈÙS+°˜ö£†|1”.™„ºÙô%i‡5gþ@ÚÒsÉUÙyé1‡‹´¦ +pžÔµ«d„ç}œ›”w§/‰%ÖpÀdŽ@ÒN0wkÉ•d6pî›q@:Ò'v^ ¨#q_Òvõiõ 1(GâÎC†þ¼ßÊË h§N(7·3*Œ9ÏŠ¸®bö¢@òŽQŒûÙYw~švÔ”§-V½jŸó:kÇ?r¿«7VÍsµ–¼?iÊÛ|GsŽC »îÅÖÎ+t?,ú^´µ›»£XLŒÔ.yû\ËbR‹î _&qÉEïô雵Â%™üO˜òòÌi’À„#‰Ð"Þ€Igå¤í0)ÿä¹iŸýü¨2kŸ~ã›0è–¸¬øûè37­ôHÚãÜŽQœ7¦pWɵÊ9o©{œÛÉY´[òhÌ<ã“Km°i»$í¨i# W¨_À|×A§-°~ÌãÔÿ¬ÌÛvÍôé] üsÿœÛôî|o>¸|t y+ÛÜ/`ž¶Ó'½Aòyô ¹µGÒþšœÚe Gµæï«ŒÚ„˨½ð¥?8ŸV5ÎÿpLàþ˰æ_;ôÏÞù0ÀüÄŽÿâï(ï|±å ¬c(§úéûã °€t¾[:OãaÐý=dÓLs ô×ãG‚ï>eÕ: k®ö¦”ªu¾åìl–á¥ÐþÚ‰ÏF%&š§{%0r/U 8ç~» âŽ*n>.þŠ@·Ÿ ϼ‚rœôÄ6 ½1·QéÄä)'êç*1W9©g$àœMî‰5§H‰Sìùéz>'÷¼•r>GöUfíêÎK{Nnù篳©r°ñÐñúö¼Mqå®vƒâPó bÌÐCŒœ-ž5Z¹¸+JÒ~›Rkn©‹.w<Œð.2È‚Èq«ÌŠKÞîðW ºÂäT€ÜkgT¨½ÞafVý&À¼Â€_}¼¨\Z-JÚ œÜ ;„=×5tÂFÕŠ…ÅÄa²×¤õF ŽDâî2Ùà£èwÙ±^î¯òg›™§¤¯[l¾ðÖú ¼§=Ò¸&sù\»T8Ÿ¹q_“ÔضÎS©·§šý.s8Þd»ÞÑ•§Î›ò>ýË:¨wìOôÆïK^þ€Ì‘?PEå½;²vd0ØïQn}{|l€ùÁœg0î:è3/p޳{À9í•åÆ˜rj?Ts8.ŽfÓýå×ød2/#Š]—1¹è¹±”<çïÿú9¶s‡÷”©X±ç¸1>Ù¥L?@üY·ßìŠr£ÖÜ®ƒ¹Àxç¡ç† Ç,Žü¨é«ÞçvnÏXÁƒJ™ÊQ]¹ZÙ…® 6:ì¹Î cžìÈÞÈ+Îy@ëº%u߸HåÀz9Îf§?³Î™#Ä~k×_í³-7AMt#sÇ(޼ó%w#òÒœ§^b1è´š‹Îb/‹Aä“ä ìy‡åŸÇ,“}å ¿“ºèÄÁªo]}˜ô L¡Âª#­8(µæ6%ÖÂµœ'蹸¿( 1wÅôm7eÖ¦­ô€uå§ €Êíê®–Rk€sí9ß× {7ÛÐ}hDZ%¹`ôöPYPJ躛©°Ð5¦äì6­Aõƒ²kÇùå«$Û´~}@¸^s9·oýB@dïn+_agw-i'Ÿ¿€;×Tz›1nO »ù{HÚ‡98w}s—Q“SûKoýw3çãÔ~uÊÊ©]5Ο“Sû¯|m\Û¿>¹æ„ÿµ€¸zÕ4W°«ýǨ+ß\€©{Øô|¯ô©–àïæÕþTwÝ{γYGUÀ8.î{£P÷dìíâž{%Ô‘º'ÿ|mTJ9¤Ð8t…Ùñ¤í:èÄË··éþ, î{y;¹{¾ DçŒñ2™èšè œ¸¸Kaæç€}¥qUÝó‰°ãTAñXåÕå(Öt¬%îËÑPÞáM|ùÎ?ßõÏiwô:Å_òÎW@JP½Â¬zÖTj[ÎÚ Rd¯Ñèš§º¢U””ä­”HÖ“ZƒšM_kΰë?7kë‹Lâ>¡üô½ÎHI²™ô›[É5g-Âk4cç5¸Öô³Îþ¡ÖêÓ¯2Éê/¶<} ¤7¹weËÝA¶) ]S µ³7†¬¼ &7\gàzd0þÓÙi¿/t nËÌ|á³]v›þÞð5E¬¦mY~døû¼®oÞ@}ÉãËDî©¿ó¯>Xwa§¬w’>Ž„^¿“áÆõ!kçà0ß› €ŠŸùÒÿeL´ÙÛŽ’JtÑøG«>z™´¤‚ãÌ«­ß^S¸¿u:_F…ÆÍžÉcRœB@\¡>7«¹ù¹™ó<ù7 Ð5ßàüñê–͸Ê^ ß¤öùiî–oº«:àÜ8çFß[î†û.⼪%ÏJŸôUÿœz ‰-i_2wç†Y6¶úå™OÞ¹œXÒ×Cš±vÆ Òóp¯:«ŽçSûœÅ‚jŸ«…Y§ÜšJȰàp»$€gþÈ× …úåà~Ø—Ä= }rÑŬÔ›mɘ@.™ó´XDî.¶‡²@Ŧ“s“N ¥Mi¢-q i4§:¬×O¶Ô°C3yë[ëy×G¿»£ÍŠÃ¤K ïôcy{ä¼ÿàŸüîE}Xôoü™·Þ@—Ä=eֆͼg]a&¼€ºØuÍÜw£.(W+°®6 zyZ¹k«~³¹êÄe^sÛ(ÍóÖ*µæ9@:-rs€z‡˜ñûÆ»NºAwvs1ýþ9šÁ·¬ö< ÜçÖ/fÏÏaÐÝÙÙ0Iˉ6[ÌùŸžÀùóÎ?õ+ðñ³ÿì÷ç÷ψÿÄÌ91sÝÓŠ÷ØŒ¹ç)¥¦ãŠvo¿Õ‰dí?PNz¾gÈÛ6ШÈP±ÝÛͤ£°áÞÁ&Ÿê›³ñÇ=H€[,yWˆã§«NÚ.G¹%îÎ=÷}°®(€¾ãĹ·¬°Ïx©«0 Èe6ªðæ/lz6‹]äeû¦øù„ì}ž‹ð[¹ƒ×ŠÚò ]w¶Àx€{6ÁÖ'>2H?_*·û­±eíË$N9ç«ºÖ €sdî–½GªŽIœÖ :–|õª4ƒ cÜ^ó„˜Ðº«rÐu®b«›5§ÌÚŠaÂ\Ä 'ÚYʳvTHªî5$,y­9‰^·~âí½~eÍ;m•V^z€x›ÅݰA³Z@¹@:ëy“f¾¾dí¸¸(OjkÊ­YÚþ×v· S{×…W )+š€,óì…‹ ° Ïë®ë¶ù8ßïC*òöãgèë‰þMï r÷ñT[ì>Žõ%½Gâ¾ÞнA*¹Üç|óË<Úùøi,;ó€wÞ ©DvCÚ¿%õ×÷¾cc;>{ÿSeéx7D-¿[¿N~\ÜmÆ>’ç™Ã {¾êþ<%×ÔÏnš˜sÕF<Î_¹a™ŒwëdÝ7ˆ8¶Oé´sƒAâN6ƒñi'œ«„Ø«¬…ÏSD^D¤6ºÝ7-_R.‘ÆÈÝͦ×M:Àœˆ“烔ë¨@^U!ÀޤPî¾s¥4FÚ®8#4_À|ÎÁ(‰{€y•X£LŠZÕ"Ý.­rÉר…~‹~Ït:‹ õ1®i×vŸç–:ƒm;°7ƒ~ 3¡óíâN¾yL|"jñe‰;Á¢rk«^n埤yƒq&}>‹û8+^™ùe†”E¨“æ^¼zQë1²vÜ“ó9˜s‚ î1câˆi X8Ì=íÊI¿Ømºæm÷…ÿtª}ujG ¿0}1èè7ÄnÞ3pˆI\uï€qsmôìÛ¹Ý-±AyXØ=ny;ý*­`V swð€ðcÝqs?è›5ïüraÍÕ÷u€ÿ€s;\çœ ³å{³\sT÷¥T¨ß©û;P8¸µ3{rÍŸ¨&´ñ2›8Ê7¿iæ|J¨¹ÎùïM_²öï*ßÜÌùo 8Oµ/½gp>²ö“¤ý—¿*p¾ù|¦“.¦¼˜tÅgÅžÐqzo“8êÿûTC°s{¾Wó½ã{èñ´U Ñqw ¬S‚‘{AõËÅ=çŸ6 ]æ‘`ã°^Š ƒu÷¨ƒ ЭF‚UPÏFè„ï©Ur­zEËÛsŸO tƒrž ìÃ:è•vSSÀ¹bæl@¤uŸ ö³µØrÂså5ØX†²« +ÿ!Ô÷Úät,kgý²B׬ºç;6(GÞÎ:ê`Í…‚¶|å¡{}ç–ˆI\ƒöÛ0é  ›’žÖ`ÝŒ:kÐä›Ã «¯PŸ ý€\t…‰+ÖÉéä¢Wy5õ—ƒ{™:_N˜`Þ@ü0µÕÇ›Ü3¦pùf“„amÍ ;ý·Ë¬5X ÞÆÚÛÞã¹ë 7½1FnCÞÞ; d70&?~›Œ%½±mE©ÄKÎ繬zí^ÀƒüùÀ5§(õ2€c÷C±Àÿe; bù™+Všh£9XwÞSsþ\”áAŽ/YN«‹EÿÔl4hwÜá0,úÚ]8w:rw h¨žˆ¹¤íÈòš H»óëppßwXuñQ2÷Ãyè ”‡ù xK”Rk§>¹—é)?çcõ1©Å„‰Å°Á9Žî:¶˜.L´&Ÿt@;Ì™k£Ã¦#{âÜþcØtº@ì¹úfÕ™wíHÜ ÐÅ ÿÃ/¾·%î§RVÃb —‹»rÌÜß _LúÌÙáÛ.í+=Òvæ*9c¢Ë|ÄÅä$¹0ÙÀ¼£j¢è‚1c[@ú°«ï12ö˜ÉQÇÜõÊè—ÇúY$Ñ_ ÿùjåXŸß)ŸÐ ¿½@º¤íF«,ew¤?àܹæfͧ¤ZÀy á^zs6‰†9Y»œÚ Îõ¿~|õ‰Sûs_øƒ8u®û-pž±Lâªö¹˜tú´¨Às½¾/úîh°ÎfW¾{•îrkTvÈw{WkP oÇ,NH˜Ô͸O[à|ç +Š9gŽûŸóÍež‰qæŒÉ=G™P·b)éFä¡kžR˜ÈÛŒk³PŽêªLâ(»FsÉÕKåeÀŽáé°èzž%÷<бUûÜ-}`|³Ñ½}a’’Fþ9•Y ¬»…=¨Ð3‡B¯$îóÚFyç€ù Êk¬èãbÃ+=õÑçóÆÉK´ãØ®HµEú œÝ ”k˜±òÑ]ɳ8BæpÒM"¹4p"DµÐ)1Œƒ»óÈänE|å Wj)ˆÌÝQuÏ[ÞNÞ¹ÀxúÁvtW;¸/yç8º¬‹ïbË »kHÍfÖ‹MOÚ±ÆKy ¯´âôÝåA;5ÈÛØ¼Á8Ñçõg^ï¿?'*&›Ÿª%]¨–9çk3×€–<…²µ_ýŽfÊ™W,iòλÄÀ õþ캴ä©Eÿñ0)ÈnRæÊÅ}ý³8¸/GEòÜçÀ½wÌ>Aîy›J(î;`ÖÈC?•_Ú ûvŠs‡y•ÚkîY†»€»Zô0è’¸O¹*¹¸§ÌÚw'ž0è7~@wböK¿9àêÌ€üÕ{j5o³8 âÔš=_¬¹À;ì¹æ60wNúí’¶ïÀàm3äôwžôq P5û¬Èœ€2yÛçŽ%÷˜Øà<’x™_€}¾eLÿÜŒ¾7ÖùzmÎÝ®í2™«¹ ½Våïq¢ðI`î0V¾¹6tî€ù5IÚ›9ÿžÁùõ¿œ¾Íà^ù­÷§=ó‘³ÿ¹ÍàNeÔþØeÔ>ÿµá—¦ŒÚ€ó’´ß5H‡9_!ÖS¸tØvüvT)56ËVô ™Ì%…¥+<¤×’ÈÜç|÷É5w©GÆqsç~–ò‘й‡>.i{ÆIBÞî{±B,{³ç”Ál™»¯MýóÉOçÞŽÿȪ}îÍ[˜už#tÕ;·›;Ï!žQSzçÜ  S¥Díá†6ãíÜþ‚}\ê1ˆã¹¼SÓös^•\æd‡ÂNë+î ܽ¾(`^™­úk½bµ`—”ôÝë$OŽ,<̹æJÞž0_êÅgHQœþð饘ØnöÜÇÌMßÊÍ]û|ÅžIU…säô!ª`Ï Ög>ùè&­Â}|1ç Øó%kW+6}t…û0ê`€¹ZÅ€ø uu{bÁ,SÁj‰#çnÙvªqe|Àޝf`«ÍŒ3®cÜaÁe+§\AN|ºôC®Ïª×‡6ûOÛ8%@~®R•‡Ø@_ìȾכþ‚Çænyc$í’WÒóÍto7¿þà®› _&wÇ› ý3²ÛÑ ö×@w®:»IŽÃ€åÄ9ôÅR-ófÑ·+c€ùÚMS?m$2É;/ ~\Þ!ýel±\ÜsþX­Î‹Y¥ÖÈ;‡Q§„Å–·ßZ7ÍÔ®tÉ íhŠi¿‰‹û¼Ð޳»95ÐUj-·Ôêt$È0¦'í1ç] ]€PN:’ö8¬ºOÙ“Ú·|í£8³úa­–\4»ºÏ¢ÀÆ1+·mŽ=^;õìæoÙÌlçU6†¾óóê%q_‹ $„Ì›Íèòje7¹éÅ Ÿò,Ÿ¾KäÕÆ„(`]Œýt JŒââVC¤°åÅ41'æ|å‹©Ò\‚þà|Ý&ˆ?f´¢îù%¯x3XÄU¯±šn„ð{Hu·Bƒ|‹ {͹9¶×«}i휃zNâûÕ”’žZó7+Tn‘ódÜÖvÖΗЈ­Ý°óFß¶¹ š«í"Û„ÅùÚ“| ½&CÆ]z³õ!ÓWP®aU‡~xHé–“!ç»ÍZÈ:; Tw_·}m–’ž¹PʹÁ¾‰ûVË]‹¾jÐ糂@8ÂG¶¶£œ[I7A¸[ÉÀmCw[R9݆ óÙ:{”-Ü:Äšæ;½=ëÛô™Ý!qtÎ +½Ý–öÁpÛîžs:$n‹ Ô kÞ6w‡ÁíÎ7ÝÖ–ÞèN®ú&߯iL¨¯0ó/u¿·Jg¤:Î˨éô=QOKßUfIKµrµ^³ÅÝsÄ('ºk4Öý² À·d6éþ9O‡L“BnÂN&µ<Öø‹ÃKÒ2yH;éíš›”'0Zû[Ew«5­SNPÔ¥¦Ã•néáÍ~•?ƒ&»½×©èË YÊ*ÓëJõ†ÃV{ï5Ì+yàu—zÙ(þÇ­ô«]ùkáºÃÓ„ý$d}cõÔcÒšš¬÷턘ü"ÓŒ¥z¯M´«†}ýPÊ÷Ãýú²5”-,2î¯W}wH¹ÿÒÚí‘ü±‹ˆgT¸CjÒ ±mí:ϼUÇ’9uæEÈA[Ú ‰Oö°øTPœ•s_ظØiíQÿæùþ+¤ƒy.´`^ç5ý!_íy«‹j˜ ê ’ë'»|„ŒCÊMÌCÂoš‹}'›b}Ÿ§Ç>g·˜cy_5脸„´CÆm5㉸ÇXÛÓ•ÂâŠã©¼ÇÁªAßµè[Ig¿¬|‹»½Z©ê(ærPêFæV3¬¬—mQðžIüq½ˆH:Ä\ç£ìx’^d}PýQÑ=.õûh”+ÍmWçÆúp#ì!ß`¯Äö7ç’ðœkXÞ!åê¹U9·„Jïf¿‡•sjgôßúÌ¡ú-c¾ýý_‚þ ô±º—8'¹AÕýG3Ñ2wùÌ¥–k®0¹ñ‚ûœZúBúž›œ›¨§Vý‹®_nRî=²ž2‘tȤÏ?FܧùNs¿ ?+æ€&ÂÔ¦›ÐWxȶ¾®I¸Uo_J;˜ã(ï:ŽBŽ ßût¡Us@½ýÌ—eýhÏsÐpþý`or®qˆøókûýRÍÏ diWYÅ#Âw†¤klíVÎoýÏÈù-ï|JýÍ5Ž~åô_Íÿé_ §šçn•6cxÙ×k­òóÂ1RŽÅ]D¹•s¯ý7¹z©é"ÖÕ^-× æ¾~Ü7j·Æ²¼ëœ`ö™w[5a_ã¼N&‡míÄÝyî%ð„Á¡¢{¾¬îØÛëZ]×ómqÿlîôç±>gloG9×Z »íí&Ü|®yT抠ù²¬w?tŽÝôÁ5*ˆµŽ™¤û3;ósÜꬣ-í›°q{öµ>R’§ÑB‚ú£š›¨ßxr%< ‰ÃqHOtÊ}_æ5H9¢Ê •$»;!qqGv-ºÉ=¥ ÛÚþßqÍÝëüœPAǶ¿Ï8@ Òù(ê¶·Óª˜Ñªy—”ZüÒ±lÞ3йöBÎC䣖oå'-d\{®;OŠ»F“qÔó¤¸Ë®½ùŸÖEÔ!¥xàü«€2éEþKµ†×–zÞs°¾AçÂ+{wãk¿W;µ®ï ë;Žíë°¬7f¾kJ‚×>Š;Éu™×‚Úßx+⻈¿ûÎuü}úÿŸ´?ŽûuÕß¼z±W2<è8ï¿íøe-ñ@ÌMÔùcÛ!rÔŸû›þ‡Øb èmoß­6iï`8ú¢Ó}FÕÞ`k'ÅÝ7ÏWtÏ'óEz¡“¨ .ÔE¶q€×k>_sþ-¹ps§&'³ÚÇf¥º©”:ÇfN(h´‚r¶jZCÔg\ýÎEÀCÐ=7ì/9nÇau°·ƒŠÓˆí:8%ÆR‡®×`ËÃÞ.°1o«{,îz¿Ýÿ¼•u,íÂât³‚¾H:}ÐÔ—ì¶•’}·ÿ‰jÞ„]°ÂS)ÅQÒK=>J-:7»!å«Õ‘Ö[1ÿØ vRtí-Ò-ÁqX_[u‹=–°8’¢c{è#QÎ(é«óßúgCÒÕžÊ!q·ÿÞW‡˜9úÀØ‹}ÆAqRÐO¬¢¯Zt&éRÖ5ìùø…y{-¢nb>çÎ(HyÍÜê+}²'€›¸g¼Fºg­q½÷œ/¢­QûÚÓ(R®–^YûÜY_ú‘0äTvtucÞCç°I2,…x^7{‹¨¯5í̬xÏXíÐPÐZ¶mû:Éìîo^=Íy8PéVÏñêsN¿w½>,: N?o¯=ߤœD}w·ÎÓïÓÄ\㮑óæ<Õk|^äüPo~ß´Q»÷Ñkäü¿Œr®¤ö÷}eêÍÿjêÌŸ)ŸñS"êCÄ_1—z.H Ÿ¶i¯®p¸BÆÿ¸Èy’Ú›ˆkß5ç9¯ÿ~ „·ííÝ2QnȺ¯em/’Ng[ÝgÚsí›7θçܵž1äüž‹W+.d}ÀµóÐ3õ||BÎ}Í…¨{¿”t®çìÅ]U}p×èU{AgŸ‡Ç‡1 úí_ÑZÊ·?«¢˜Ï¸J»ÒË|Æ‹£|Œ=A =Ööà–±s³¦<ÏöŸ¹w9޹¸çªþ|%¹#øõ»}‘q‘j“ô=n5ÒÁƄҾ-hl¨l{­“—$Ь¶¶¯5Úwaß»yN¾Pç%¯!‡tÈ»ï7‚\¬ÑX–v‘tlíó^ãøœuÙÛÉsµTËZØÁp??ê°Uu©á•âŽzŽ0|¼ëЛOtݹÉ9­×âª.žS½È‹È Õ ¼ÔòE '¨å<QÁW?õ&ÿ|=rÖ@“~¸l‡ˆCÊQÉûßÖât+îm˯ ×ÕAêÇéÖ J-GMn´½jÖ½ÏJáÿ §ªÀç¯Ú‰²Vðd†ïiï»—:é{õÂ몯èŸÃɲKìÞƒ!éóÞ ÉVŸôŸh A÷S°³UƒÞµ's®Ö„Lþ°m“ñ~Z<4¨?§úyÖ »õf]œú‚¥ÖÝ^ T Ð &ö¶å))\[”²Ö(ø<| f.û’÷©37!Ÿã3·‚Þ!qúÑèz(jÌ­¤ó$ØÁq;$%}Ï—Åý6ùÞýE÷å¶žžˆ£ {^V7+êVÓµ·jÎMÀ“䮵jÎsÜ}Z…ØôÇ&è†H9ýa?BˆŽæUÛÇÚ*ÆEï-û!ýЗJÛ»šB›5úç°M©…¤6Eg)èÀ7œ;NãéívÐŒ‚•q«»çéÎ4‰Ë—_áFR^éÍ«^Õm×VÙRîD$¬ªC.PÍ µŠÒÞõ¿ññéýéƒÅýÖ÷|qÔó!è²?<ý±g†¤q:ûܨ :$]üœçg†|-\8´d ›õÀçŠd_ðZ*ªF­'ˆ„KyÕˆ€›D«%— õkâç=8ï›ùSO¿ßÃs ’jˆü3IÍZDYÙdݘ=׊GQ÷ˆŠ6g¨é sq–znÒ»j×!ñ¨äea?ÛÔ·bN]}Æ‚ øÅÜÛíéª6vkÊy~w"çôsSw~vþ<¢Zs¥´‹˜Kä|HøOi£ö—÷™qy|J!q&å"ß¶³)w›´¬!ÞÝçÜýЋ¤ëoãI‡Ã½yþF’ÚNæÚW[Ãp«å8YPÒ縉{® VÕ£€ ÉuÁó¸p¹Žh´‡\Œj¯¦Ñ„\Xaqéw¾­ìÀ{"Ø.9 !O¶ÇRÏckïäöýpUeKJm‡¨û½ø8Ú }9³n;yÑŸ'ûs¦ÂádYg=ð¾FÃÛstjSƒ®ÏVí Þ#ˆUJ:ç@ÈýY’ÎÃvjÎ ˆ#$޼?ÄÇu7Ð}‰ÆVÐM¸ÉÈAT¸å°ÿ3QÏÓ¥F6ö²º/×á¥W‡ÓùºßsëÎÉú |¿FoTuævv”ôÕïœÚs ržœ£_š¬¥!ç¹Õ1•`Ö½êVÑÓBXŠù*õn»¦ûf‰[!ç hv›5î³Êoíw÷%½>‚[Z«8]› é+X:ü!ÔìVШÖKm±G´…I;£¬z“u©‡71.˜oÁeû}ûáÃvAó ÂçↆÓúaÄ}·(_|u¹ NJ0^Ü“wN(âÚDżÎÛußEÐë‡Míû>NYD’µÎ9eèo¸Tëê_×ñþ¸:0¯¿N[ص¦w Or öþÅ.2¾’ÜÿaÔäN[Ý;Â{ç\ƒ¢K{”ô­¢{½È9ûgýÚJpGM§­„°ì?+dƒús“õ$d’â~–š tˆ¸,KSŽåË#‰îƒºØ‰’Nr(p?N,î„ÅÔXau'Ù4k>Ìm³5þ¶ªö|+è;(Ü:cìíÔ£—rÞaq!ç‚Û«A¾MÚ±¼»& Øø$#ª:–@n‚f­˜Ëu¤~æéQ{Ç|«ç[é¸OÐ׸xUçÇö.Tïóó²¹£Ö1_jOÕ [)j{»É¹n@/]]¶P+O¤¸ik5Ý䜛j€%57æŒ(h+(nµf²ân22@ý¹IX½šEÊeçMèÕßòñÓÆ6|ó‚þî¿–‚>=п9d蛊{ì{cwÿžHúöïÙî~âT÷!ßö ƒ`¿ÎÌÞ`zæ@ás÷>öœÂÂT£¬Q¯ÉÞƒ Sú·ŸˆŸö†$Îk>ø¼×¿àõÉó Ÿ#’žãà ¥ªÿ¡õã?ôüCRŠE·¬ "áF)êÖÖk€M> |’Þ©òºk‚ŽZ¾].9W‚{ÙÜuÌ%©71òûΜ9Wµ „{xTs‘s%µO@áïýJÈ9IíSo~ÏcO‹˜/åRN½ù(éC¼ÿ!ë„Â-"®¹HúC—_fßÊ9ÄÜJ{ˆ¸ÿf æš§ÕÚ¬©?a§=£ÂßVGà‡w•C±»;¸ç¹ö¨C747yO' ÒiBǼŠÎu­ƒáp…´ß;éëº^†œãL„jîZtí‘àŽ…½ÝP\×»ô @—Í=Î,\ZOg°w‡l줹/4AO&ËËEÆKE§¥©Ç'êó:ÔvßýÏ/Ñÿœ6k¯ø˜€K¯¬îRÔµ¾ñ䥭¼ ÛîNé^pÃXÐ5ÆÞ^ªù%Âti±frî9s¼¶²ŽZ~%óÜ»‘ØIÏš½ˆ5:Bˆ!êíÚ¬ûÖHp— ^¤|ÚÿDvõt/‚ ïk¸Vè²É¸1¡ÌIq¨¦ýE½Fç¯ô#ýÏÁ¶¹Ó’Yøýÿ;ü!e²B‘rxÉÕãáÝNík\Äy §„m#ÔB˜uþjo ·«ñ¬;7ŒÑY`'GþÝì#˜âOW®VÚ»ô´_õîðÉíJ‡ÜϸÅfRÜöœëø#߸!Rzü‡A/¹²¹Ï:?²‰cogæïœï}í÷¯úÿü}?á½Ë}>¿¼ã?öµÖ/U}“u°Õû¤µÛfÂÅ€?”C½ˆ~Éz_þ¨bs'bÛ[èØõç šXvv,ïWÕ]ó¬CÄ]SÓ‰î<1ÄâS{74DÐuÁÃÚî±; â¾è†°—ÅÝÊy.àà!çVÓcoJn%ÝõS}9‹˜/‹;DÝX1©ìWBг'(ñ½‚áQÌÓpž[i׸ÒÜÕ®M#€¬CÌ+6©²nA7ó~uƒ‚"Ðý\s‚º@xÎÇ>hR®9Àò¾ 9£PmtÜ/=û êгGŠ0êÌné3„œ°8TíQ£^ŠÑت™ôqÁkïå÷}/O¼¼úsƨc o’UtÔmìîK-¡×óé>#bí9ÄüqÆÏKŸcç< Ú{Àûìe}á0²'ˆ ?®qpi¾æÉs!èýbˆúw©ëö÷hHµ ó"ÜI|טcÇ‹Ø ØÝ±«‹„‡`Ï:=Î=´P«ümcrÅ»{×ü XÚý€D?YÚϨÞ\äüÄäü®÷Sä\=Χæü«£žaÈùœÔþ¶Ož¾iJ0ôãWL´=Ê~î„v–jâL¸+,.ŠºÆMàßPmÔÒa¹RLÄ7ü@MsÒÚqÁì‡oVÊ æ"õÂÌÓ~1mÚ4VݹI8™ç5×0XÙ!æhv œË‹jŸ‡§>·“öumÕX¡ŸÊÆÞ­Õ4Ïç‡-ëGƒHuÜŽ¯MлºÏËgœ÷W@\ ÏL?Ð&»E¡q {“’^ù.|&„ºVíù"é·±¸7rï·Koö½v>Žön¡zJñºÍšUwBã´žQ˜÷£5­×%„\aMšûNp·êîyÛÚIo;]©ûLáA×¾s‘ð*É PÏwH2ÁÈ;·iß3S"Š Ö ìt`‘m¿0¹Y»ç¹…9#5è…­¦kvöR~K¹¯9𯲴— â8nq®Z,N«µ”w§1Ôìí¤îóŠoVÂ<çÁ7;(œ}:|Õ÷ê±x2Ž‚r§· ݶ´û…ée·~˜ýô¢ë¾9°5m§?©‚|`‹@?ÍØŠµž˜¼†Õ~§þ³÷ü/Íë—¾ÒË¢¾¬G”ûã–ý¶OÔ“«†EÌ+É=AùôZ~u?U‹UFŠû~ZJºÁ…@£Amú&嬩­©p8Hzú®ð%×íÌÚ5ç$dæBY4‹œ'Õ}ÎQv¦ô Ÿ¤úBŸäö„“è¼Á§‰Òÿ\Ç4õ}ÆÝR ëû‚ìí&ãþÒèµ[”‚n²ž=ìf|ˆfŸ:²9žyÖ·ÓvE4ÍyÒ.ä¸S`õšõ¡O[—®c­1°õï–yÊ}gÕ ›Øk¤ÜSØ7C´W³1s·ÁyE{±,îq+™/Kd… ªŽ‚î`¸¤ºkNý9m€¬¢S‹îšË¹ù¢¶kªÅ|¢ŽòäÞè:_ÖPnŒm'Zåãy¿ñXQi·}@ 5ÍÓZÉk”t­!è(p(é„Ç%Z¤BÇ&׿eúÔöÞôÎÏŽŠþ9סOý¯mîß9½K}¨‘’þìu“ôé.E]d]È\ý¨5NP+-µÄ;ó÷5_{Ϩ6yŽßóð÷5µuö¼o’7Çd‘ÎÜ£løëõ?òø<8﵎?8¯ &9<Çïó:½Äÿ‚ÆçMè­Ðkyi¹Ÿ×?/r>dÞµé3ºÕ$ݵâ&ÅmKg/çeÝ)탫Pº]gÞÀâÞjùñÔvö8n¥<£Ôsg(Ð)í&è?8r~¿:LÙÄ=zðó°Ãà&©}Ôó¯Œzþ%e! I—r>Ií`ø/Ÿø{©åÀйÃá¨=_éí3ÏþRÎúð+®)‡3gôÕJÍí QÑsìÁ¼R¡pËábµÛ°½½‚¾Ë^˜co§DÔtáŒI8„¼ {‘s®kGz{!¥A;l“k©¯½äH;óyŸÌ3—ëûVÎ=šPg+;õç<4LÆKA߼ÔqêÌ…kp»¥iPj¹ÎeîëCÊq«ÝÚ ŠIuPέzk¤%¬íì¾ V‡¹!ç<Î}‘Ñuè)D=ç~+B‰ÖQÊWÝ9µè!æô>ŸdwÍÇ)‹$T¸ˆzÚûVýùë>ðSˆ¸kΫºD¤Á­öÂôC'« bî=—‡jlRnµ=ó5é>/aÐ †ÆEë>çâ ¨å *•…kX,7oqÄÎÅ¡VÛ x!*:ÇÀ«<\©÷ó5؇w›³8š9^³bq7A_ îåÛ]Nf_ê9¥bs¹ÍŒ¸†“Ú¥¸§„íÂ+óÙ[6w·O¥®kШIgïrcgè@È ØÛ}”õ†JIq¿Y(¢û0¹#¬ÜH»5aÅý<ÁCÌïm‚.Â]™G‚ܯbs§ëP}Ð×½îVÓQР‰ù £ ¶F \OT·Î§lRÎ×÷çjÂP¹q:cKß|WûBqÍeº¯ûëÒ÷Ÿ©zXHf'7| åYpâj»mïÔ‘¯öc:—`xÀqìý ÷š§Ýã’ß­xmÉ©ÆÁvv¡TqÀ÷[µø»Ù¾ :Iî<Ár :í¨'ɸ,.Aq²¹A*úÔ£Y$]Jú¤º[¡q¢~×fœvXCÖ5*Hnð¬0$ݸûpüÍGÿN懜=;Ä=àÜ™ƒG…gtLã¡7ö}yO£Ö÷Ïy÷ÏXàØõã¸ÞgÈ"ëyïûçß¡ù}Ú?yÖ˜µç³?ç”±ÁÅúæÚµ$¶†ÛJ@pëy×¢¯s\S—›È{ ã¾³ z ¬‡3¦Î<óRF–¥Q@5dŸ¬4÷N îtwzÝ`rSÚÊ‘°’Û—þÁ MÒ\d?IíŸõü©Ó›ßñ©!ç-ÿ·zn’>€dCܳ®À8‘ìXÛlî"äÔšç¡ÖªKObûìñ÷†š®¿×ðXÎäü`Nð4§õ"÷m—ßד²µoTŽq¤¹WKµ(èÁ½B¾æy0ºIw”õôŒ™ß=×Ò{Þê®ðjÖ"ÙË…UŠúnùéq}>|Š’n›zYÛ»4Lï[{ÂàPÒ/ÓfÎ*î´B9Ÿã–wöv ºóh2QÇ‘×Y7”à™¬³ŽAÛØ”ôy8+»DŠÜ­€¸€²Â ß{Q{nQEŠ¸óƒ¬žëž°D™5:—rH’ݵµÝÎMïsrû`…Åy]ÄÜJ·SÖ£ k®nGqž.¢®}§·_m‹ûº?Ž0¼'övóÌ5V‹µ“”»Æuë±ðJˆ8n^­-ÂÃÌqÊ ]aÙMFC–ymg|uÖ\)éç„~ó°ÞGÈmÀ›B›ÇVvNëªK¯àïœÇ^õs_.ƒ96ï]5ò×U_;ÒÕe®FÑ.åÛÀñžáÍ_çAž«.¾ž<0v7Î×ÓšØ8{ÃŒX45àçdâ]5é­Ê£ø÷“êþ'„¤{¯óóÔ–èõü8Q¨êªKo‹»ì1ÞóšjÏ­ªS_ã:ô‹sº;¶Ç©=Y÷I‡Ä…¤3?@_ µJ¾¸óDVk]ø5b³Úcµÿ¸TÕ'Wò!þ–ù [Éȇ {“ÆÚ~ãÉ‹WŠ;=ÐwHœƒãø°Öy7} ‚Ž…½û«z¿o,š¤s¼÷bwo H?ôº¢}^}× G]71熬ۮuô„ …¤71çf°’Üï¾xuÝd ­ž[ 29÷)¯Ð8›àÆzu…¿I úEÛ¤n­ÖkÔòóuìî+œJ#HØ•Îq|ˆ†ÖCÐÿëéõ¿þGCÒÿôZ-úScwj¬î_8´]»mΛß5ã{MÖm}ÿF,ð £¶ƒ9g0‰Ü_÷ÚÇ§Îøk§wÍhˆ¨éœÙû}­ýº»uîû¾î~س6©wÎ×ÖkŽiîšýÃ<{óÚÃø0köŒ;ý>ÓwûëZÏqïß;ök㛂þMCÚgýÈ·ú!žßrþôà™Á³&ë'&ê²Í§FÝ¡r´hS?õe7‡”gE=¼lêŽ5>ÇxFË €[ù6Çæ¾Ž›¼£ ÷žŸïÏPÎ]—/bž¤öûÝã\õæƒo‡œrþ¥ÓÛôL„Þé6j÷ÎÏñWÿôEÀMÐ $µ‹h‹”kÜõç­„«žÜ¡p+0®jÐÙi §-áüí¬^èy(¦=¹X¼^HݹÇ'‘5¹šöv‘pÈyÚ=ÊÚÞdëX®a"æìÙâîìKWw Jäv•ežqÀµ7ã@=ÍWÿs)ã«æ\ש؄ÃÚv(Ü“(æškôg‘tÍ;(ŽÏ/º’¬zt¬òyØ]O@XYÛ©F0ÜäÅx_à³Rnïl“ôóW¤’S‡>û „ æVÕQÌ]¢·_òt†Œ óZ…ÉeÍþNp7IŸ9Ä^çXÝšçžK{tÚé¶k7nX”°ï? î5!æ{ïñäžôv°¨Œ¨çK5wz;D} `IoVÛcêα¹k~Î{K9ï–˱µÇæ‡ €úHim‘Ùü‰^åáA+Ëì¸ý^Ù°6·‚ã n‹z¸âªwï„øFlæé²uìÜâ©ëÜÇsÔsBâòB”a¡H0uÙNË[­Ö@=É(t;·ãÑúeÝõðõ ÙÿÚf¾Ëš’Γ‘ý½µ²ÞέËJÝ¡pþ£ÚOÀÛââuÕ¥»]ÁpkŽZ‚~¬åZ«ç¤¸WH…d˜´ûÂ)B®~è»ÅšQV£&æQÑc]§ÛÉ•EÐ!î´Ö pÄçBROv±\Ñ DO„©;×ñùšó„8á)·Pƒæ<êα­Ñ­MVŠûìè²lí¶§I9Ï1-Ö>„Å}÷L]$È¥Ö;{¥´cá£>Ýã@{:·ú]ÚOK5”t,…IØ%Q·ÂãtN©æ³çê‡r·åÁêþJ©çHd‡„a@ úh]Š9m×|3©ãEÈiSÄZªÄ|õBÏM´í¦Ä•õ=–ö“ú”òh²¢k-$ý@Èu³$PÿÒ¿ÿÈéþãGµè7¼u¬îo’>}§'Õ]5éc{…sTÍYï—UŸ.u]cæsî_Þ.?ǯ¨ŸzC-´ÔÆmÏYkÎq¥z CêZ¿OkŸ“cw škO¯{÷—†lUàØ¼V£‘c ÎÿræCÌÿæônøÚ5è!ÀäÏþ7EÖGM•}Ôûû²ÄÛÿ· ”K<íÙDÒ/º.}ÛÑ‹°—eã=g¤Ï:$½kÊ›”cgçV÷·Q9ÇÒnåœ@¿!çVΟ‘³aˆ¹\Nj§Çù5rþȹÃßþOó²µÓã|'¸³O9ÊyסÛÞ®sXCÜ]k.âËû&àƒ‡>ò3líé¸Ðií{O "A‘ÕÍ2®9X‰íÛe6žÿ¿Jy=dx‰Å]Πr‰@sí¤®Ü×ÔÝÞ’L— ‰xÓJÀÏ«èõ9Ë{µYÃÎn‚I rN>а :„|·¥Öœ–EÖCÊíDãûXÛÛÙ¦Ïf>Ë!ä¬ý°{»‘Ž/ƒuo¤Zî7„Uv§–kž›œCÊi!«{FtJÿ*X×÷RÚ³«ñÂ"æB9!ç(àKxÑú"D=ŠyæY‡´o;ûËŒ¸9 ˆûà¡ö< :DÝB%žsœµï¹—jîuœ¨ë¾Z Ä´0$þ%"çz¿­œÛ›õÃý›»¹„Âß:ÁKûð©Å?]î]­+¼ÛxsE°yX·fëzp¯ãàf¿Pd½ÕñÍY¿f;ñæ ˆ½û=}~ƒöÜ­¦³ßs}ϼ?¢øuþáò‚úÇtÏ;”cz}Çæ^?èjÆN;5Ð*ôV®Qñs{XæÛv?(‹Alöš³Wè§9´ø…ü@ A¨ð‚j·vÒÁz±ô¿=p`ƒ5î?®³‡tFæÔ¢¤åš-.ì51çB Š"ä$IÒ—1„¼pŽ ÈþàÂê%¹mC\0IÓ iÔžŸ8µ=ÄÜuèõ$•=ÚãÂßP?sTQÁ.¥œ·ÓÝI6=Ì!æóuw‚»AºÉ·kÔó!9kˆºGˆz[ܽLJõœ»‰9â;Á}áX µEÛžG^»È¹^ã‘à¸Npï ¸u›+Ö„1.Ân_7s$¿öU,–ËÚ^-‚€Ï—Å3$k'5è ‹ËšyÂáæõ(Wéƒþjöh‘dEÝëÃë4ÇÎ97YG%o4ªVŠ{”=R¨g¶Q¯ûw’þ䤿á×ÿðô¿ñ'{ǧ¥¦ùþ¬lï ðaWú¨3õSVxáVáÝà6YäƒQK=Þ2¤¿7T›,è¼Û½f>=Ûï˜ñŽ÷x¼õŸ›÷ÿ¼ÖsÌûRh5 w ³ç{g Þ3_gÚze=ï£×rÞï}ñôöwéøg.âÿåÁW®Á¤}Èúõo A—ªþYà‡œ> I?ûIïtÕ¡‹8Ïù?„¤“¢¾Ôqíií½îoÞ 6}Æ"äR¾WspŒœ¯08§µÿh`rNœSòEÌ¥œ»ä@¥ &çIjŸ6jNj×ÿ±w|rZèýX䛾áWÓÏÿà.žotO8F¬zo~ 'B‘yŽ7vb`ÿ‚óÃä=øžëjæ9F¯tþU³¾ ì÷% !Jz4œõž`5}F'4†œÛ¾²Ãâ§ãš'éR®÷y”Vkc±á€ŠÎš^èTñÓýð¬GÁ]Dþ§«õÄ"䨅x* )ïštjÏ£žà6¾ønõÜs›;í;Ô>Åj5|ztÚ­J]i¥ë¬kÒun…ÂÍkbyÂqžÛŠ&=ä"ÿ /QÓ/Ór% ºû¡,S­ÕHeÏ*ù1k»ÐÖ<«â‚ÖÏáFFÈš:>«–rQÏ~‡­2’~WÍ"x²,•`‡öW2ñJt!ëQšPÍgÏÊVQÛIô]£žúQácÜ|ûœ0¸‡t£î”g ê(sËú®}XÛMÔe¿ªžZÚ^iüÿæÂéëþíô_ûðô”ô7¾õã§7üæŸ Qÿ¤lïcyÿ´Tuc» @9ᆷ|ÊsöX "bÂo3?¨ó¿#H¥sÎੵw«~Gðü¦·æ0ÞV( ÿìö™³Çœ=ãößýKð®kx÷ç¸ãwCìïx÷_›°¿ÿ+§wY¿çý_·þÑïÈú®u“ô!ª“ô>óçé¡n‚®”v+ÜXÙÁ‡„"ÝÕ&sBª9·H÷1&GùVÒ 'bï@¸ó(çÓ—~޽ 08ÛÙu@ßs·Q›²€;ïo†œ“Ԯ߅ڨI9óGþ^dœà·?ΈÍ@ȧ.}^çZô!Ü:_k׬7BÚ¥¬ca×hÒž°8½×‚¾‰:*ú.%i<4_gÆj• äqËÌyÙƒ¼k¯4wÁ„<Ù«ÕÁ–&åsrœ| Ê{|VËÉXÛQÑÏçøa‚.çÒ ˆ#½Ò¤Ášßyñ*$Ïʟ츤ÏùËé ¢9Ÿ/3&EÐç ç¥–Ç\ã‘Ò/>#wÂûr¤Ü*T‹µÔ¯X}¾ó.urÞ­Õx¸OÞ ÿLÛÊ9AqEÎgÌý‹ÖQÖWïó%hPo.z~‰vk³·zž;OèÊ"ê×+ìí"÷{ogfæÁîø3Àm1ˆ¿XÝIkŸóRй{¡“©t½•s,ígWz;Ê´$vMúÂF—B^÷ÞˆiiÌpM{ÒÛOh‚^p-"¬nÅœyÛÓƒ~ $¢\¤Ü£É¿më•ÙNe?hWt‡Å!wË´5×ë/¾\¯Û<%ýˆ <ç›úû¹®HåkêúÁçé[Anõ gþÚ‘óý‹¨sf@XÁ IzEàƒ~©õ ü©§?¯­šŒ¶xô׆ŒÑŸ¯½žf&äg©EŸTÆì%$n%·ÓjáJ)èÚϼ€ZÎHz…\PNHFÕäPK{ó´·ÈE’‹'A:žýª+2Aßäšsž¸òDv)éî‰>çÎR• XóÁã’ewõ=Çè ê:-Öˆã 55_+ NÈ`YÛ)­k‚dh¯æ5¸³É:a4^禂Ñ{ ¸ÑºlðÙïè¨ì·%_kH¹`åœà8ßT%Øg[¯çœEÊ´[“š#Õ%{€`"‡¬kn«»-í5hÛÜ5gmõÝ-ÝJI×¾o~mqjî^è3÷Mq)a:7 ˜ÔsíÑ=aP¨jZW-:¶Ù"«ºÖk«¨€¿ø¯Ï™¤ÿÚåkJúœ^/¢.5ý-2¶÷?ùLJˆ‹°B¤â.üæ¬ó‡ù›Þz 3uÅÏuŽæ:æý!h@çÎ×üs¯uîÛ>qzóÌ…@ïu“ßSXÇ ïøä`ïÝ"ü6Ð9™¯ý·Ïþo}zå_\ÃgO ™‰ÿÜô/ˆ¬‹¨«U˜íð"ê|gæßR|ÂãdwGEr»jÑËÎŽM]£o4a/ëzô(ænàýÔšs’ÚõïqÍ9ÊùXØÓ‡þ@ÐJÜZ?ç LR»~6v?|~úgý;xçSC„¯ÆÖžÞæ­š{-l+ûAMÏÜã¨ä"ࣈÓ2MäûºŽ“ÞÕܵé+8+»È:¡ŠZ'nF?K§„eqw/su]ç­p¸ØÛK9Ͼޟ¤vÉ”ÐÐE Œó`Q%BC„@=? [Lr-Ô^;ŽL¶q͉>d¼ñ¤Ã?£”wËÍ죞CÔyàë‘r«õ Xsp¥¶wðiêÌãÓ³/á*« 7ŸÍWòÙêÚõ' âéy΃t“ó[/t‡–ÞþJsÍw°l§·s¿a1À =¶©Cï–jòuŒÊçÉ=‘Û©-Kûô.×XY?+Ì÷"ë„Ã…ŒOYcį-ܤý®F*ˆ8£`’^Ê9-Ör?{>ÖvgÝqºæœ1AÍÅHmï®IôCGHÓ½=÷ð;Nˆ8gN@+fs”ôÉ­"Ãj £QÜ%sPÜ,ÁiÇ»R¡Þœ«UlÔèr_ïƒxg¿íð¬¡v”/—€}T@>^ÎÝ-Ï­ 7Ju6 ïÖeÇjÚòÝÖôýƒPÐE€óƒ0ʦà±ÑØõòMø©/GñöV„úÆ9õ4¥1ø9–àþóó~n³æã>¬tH9õçÀ‰‘Ûêî‘‹ý¹°žèÔÕ@Æû"µ ô­ž“Œ©ý„s$nc‘ðÕÓ2kZoÔ >ÝíØÚv¥svXjù‘ ¸›õuI7¥fë°®šóõ„šÀ–Õ›TÐ1?ùÆÎ¾Ò~‡IzÕ§ !ë·Îûèƒÿ–sWVPܼ†›ˆÙƒˆoB¾í{$ÞDÜ·jÞíרG/õüŽ W£|Ðë¶1ÇQÍ·úò*D}«çì·’|žÞ;*:J¹SŒ5ê&U#j :À*šúsìîÞ3Ê¢:kצc{ß}c{ é„Mid¾ ºmî^g’±”ô»}fÚ§©UÚ÷êg>½ÆQOóL;³ÁX—ïõxmþüé}çsp2xü……{?8m¶.Ìü¬Çûgoàùyï z¯3ª]žc…{}Nã¿èõš úïÀãk-—:h4†|Š`þ@£mèÓìyõñξÃÞ.9©\£È*–o‘äÿqÀ/<­ÛF9Ž’.»ûµ>ìçõu7Ø}Ö›to¥ ÷¼ú”_<Ö¿œc¬+¡=`ßií †Kœ~Þ©7—3`~†ßOܸ”¢ÿ-…Á¹š”óqH99W)¯~üOÕÄ;jyƪ;7 è©=4BÄØÝAïAÐMÌ«îœD÷!Ó¯† Ó1a“tzŸ›|‡”«ä¤þ¦´Xd}¸®¼× Hy,íms×õh®ºFéa¥(¶½§Êùatë4êÍéƒ~I}лú¶µsEA÷žˆ9ýÏ!㲯{¾º}¬Ï‘þLÙövTtJ®ô™åà8jÍq‚¥ÿ9XŠ9»QÏyÐ- –“ Ã:áoóõBÈ5ê3;Ÿçš{Uì ê'¯•<ÝafÔýÇjõjK{·5¶SЪ¹æ©5o\âé ~Ë¥x dæ&î&±´k¸"»Íšïã¶l§⚤³Ž}‹I¸?íE”êþç¶³ Y§íÚ"äIr·òí1áqé}^õè:Ç}ÐmUÿ¿ŒïfgyÜýjª¶H1D²]vmðºk[&DŽóª*R‘º ¸¶åýÑ]/q(2HQš¦$8A!XÛüÛïz°Îëq¯yfG]Ì6ŒîûÜç<Ï÷çsΙ3sÍ5Çj¾âà "êžo„˜k8y±­7géÎ\XÙë¯üжð&ÃÍóz­ß¯2Ó2È|¿¾ô¨Ùˆ°›Oj_Öº­›ÇôTç!ƒÝÙ­Ä3·‚¾žDAÖÄ\„S_»ýó›ùóT"ß`ùñ›”W}v?éèâþ#‹A“qŽc^arýGrMÃaÀÀ&äì@}×'dކ•¦hµ|«è´MX¡N]Êò2jûû÷ï…>¯§¦eŽûÂû3VÝyˆý"å §¹QÇö³aÛP,C"âõd’àŽ}5q/›{‚ÞÜý¢ƒâ¼ÿ6J;'ð}²o¢> ý ,Wr°ûŸgÜ€;D«»× a I'-Õß䜚s€Ê¾/¾ôHÏzÚªu=zÛç’»“Ýe[ïº9ÚÄ H(ÿd« QÒ ‰+,¢nµõC7`®Q×>’Ø—5”–Ì!ç‚Ö£ž÷M¢×uœÔrìí&äQx´î@8TsºÓÜ½ŽŠ>k¶¼ ç±°ÛÖ)·½}·[XܹI·å]dÀPYG™£m ºÇ ŒÓq©‹•,ûn‡È5ya›ÞÒ‚¾ÞŸÜ‘J9‰Ù+h …r•~Õ!V‹ Éº|_õt¾Þ:§|Ïûh|~Þ_DOsAû_˜ñ½×—ïzœ÷aŽÑz }¿;ãïþé 3Ÿ×Í÷¨1óìûÏÁW}ŒæÁoÏϞ׊ˆ+HN ðªIWK¶§OýÒï©è&þ"ú†ÕíB“kú:¦{˜³ÎqVÑ9>Çinr~…}Ϧ6Ýä|¶Ô>F4èáÉO¥œOû»Ÿˆœ«?ýróIí£œ+{@äük"ç"íú{æoÉß™ºsH»F”rÀÿT,íY—*ù& .µæžèNr;Ý#í CÂMÔ e¤¼ä šˆzˆûþ¼„D&§"D<Øç Î1Pé2›¡–:VÛÁ²´ë<—9Öö‚ö—#é¼ÑaqÌÉñÈœôegWú»æçÒñc_G†ˆß9w¨èŒg/ÜX‡—£Ëõçz8l=.±ÝB´Bßž˜÷žã«ýÌ¥d¸Ìú&êáp™Ë‚^5çBìí¹8‹‚ŽÝݲ+Ó¦ÃâPÌyåzÙÛ…íôA_@¬HK59 »%-儚'N–w‘um‡˜ÏØmqMÎwîÐo9¤,²Ut AMÐ¥Ì3·h´íí÷wKáYß½¢A_¸HPÜsÍ7 Â⼟6Ë!ésüέòøo_Q_d\<kû$³@Z»ð¯ „l/Á•òJ‰s‡°uØ¸Ž­~æ…â¨Bu ã¸ÊEëßG+ì<€¨c@Ç8Ó,d^¼ôþë—VJ0$·A¡»Þ õ™÷È{—•  ùyr¢½­çXß_àóć–ý>&ì‡aoXé5vÏt¬’ÏÏ0äÜD‹;ó÷‡Þ ‹;5é©1Y-þÝý§|`AWEòØftµ/žëõ:Ö5è—rÎ G æ\dÞaÎÐ(h=µ=<™\½%!çÝ—Õܤ\'à¤s¦¯eNÎú:ý”2rAG)—ú>è®CŸ÷YÏEF#Ir7|A[m×<§Ç9­ÖBÌg¼iÅÜá,QÏWÒª.ÖUcæ6k^!Ÿù²·óôЙ гª®×Aȉš.èxï/œ¹pÃ7%ËÞN¸ŽUoë†Fv÷Ns7|åQjEÃÖFHzrÎ×BÒ³ÆÍ¡¶}ì¹´øyƒ°£¨æ:U¨Ú­ ¹§S#­Ö3ªÞ-×PÌ¥dEY§vTs#ÛQÈr3-¯Yµèêž~˃yçÔÃ>óú­(}ZÛäÃо½-’¾·Ch²ˆyæ¤a›,©rëM¼DºCÔ!ëw—’*B÷Û“¼­4 ã"ñÿ"¢y7f òý‚H÷c²>К·ƒxÈ»÷¤–+DÎIïßWït·`’.‚.r›¸H¯‚ÚPäªï1s€¢Ï>ẟùUƲ´{î08ךG9—Ã@îµQ›Ÿíí{äÜIíQÎ'©}ˆ¹êÍß+û_ÒFíåé*K_sþþ+µ;»°Õó„Á‘ÖN*{Z«ùôn)è¬ÑbÍ$= æ|FJGPÌ ·R3 ïôvl£w5+îÞÏùAk:Gh®2™ÃžççÙŽ­ÌùMoXÚ]¤±× èçt¾¿æsnJ:àÓÝ8§dwç Gïs湎hv‡ºþxÛ-CEÖt PÖ³-{ûRÍi­ùÞ¡«ëºš˜W zyugaPØUêÖÄœûÁ¥vìCA÷èR½Õ½A{µ5étÈéZtïKÝù륜Ÿ¬íí‚\½Ï£¨{$±õ<™EƒÝZ K;î͇G¬Òý¨îQ¹WåÕó[!æ”vÒj-÷ÆBÊBÁ²¶O®“²ó¾Ï¾‘,–öv¾æÞµæô ujÐá ‚xBl¼]V+„ƒˆ_H0¬–Ú$Î|¨„Ð^È©_×µÜdv5x¯ˆ§±ÚW öâeƒ~ÖÊÆ^¼Χ5ì$‡p×÷ ÂZÎ÷T|ÙB­Ñû!èæ„ÃÑ@½e‘Þ.àïý|Cï®?ï~×: Çk[Uï§EºwÒ;õãÝÝÇÉŽÀ׬¯[asl÷ÏÚÿˆ±š\/‹I>0;˜”g|XïšÎ‡uõG´Íf>ø^ßuèXhV(œöÝlÑ=±ñhÿ¶ù˜¬gn̼ëy´Î\võœ@ ^—ʽ’9Báêä­“»t“ò£1 Õ£\âÚ©Õ‚m‘ò‹+Ñ}+æØÜm{¿:LפCÎ}1´í‹¡`¸Ò¥êÑ£šÏqž¿¾ž®ë}Úæîš6ˆ¹a%Þv÷¨äÚ^µs]S—ž®(êg]gînd¢ºi-¢®Q¡JÏtò±Z¥]ð-ïmeåÝÜó“EõÎ Šr*Çi}Õ£3R“îú× ±2±`»C°¼FŸç²¯žÑ=ç8‘*ž»O5ð1› Ak‹³W“ô/…¤´¾öCÀMÎ5‡œ³Í¨×öQÁ5üRÚMÎKU×kQÕ³O}ÐU“®zt…Ɖ ŸWŸtÆ]øÇ{ÖðwDÐçØwboò X‡P³n%¼mëWŒ²¶Ç~àþæ—eçÇÒžÒù¾•Ö.rî”ö—~$Ò­¤võ8bþDΕÔ>¤üë+©ýÙy_ýmBλ%›°›d›˜óƒÅ=ÉëA‘𙯞èÝrmÙ˜óY@UÏg bŽ¥]#aŽžgìÏ06vÖžžs„Ï&ý&æ~¿uêÍCÌUVƒ½]ç¢MÌûÁ"Ùuû>_æÁ¦F,îZ7ÑŽ‹‰ôŒQÏ9w?%Òx»:Äœ5·i@9ïÖkÞKûNqwÊd[vlqŸã!åIrO¢¥Þßi—>Áå„gÂ>ëªK÷Ä|žhz{µßøü?ß Œ“‚^Ö%µ_£ÍšO¾ëä­¹•rÏEÊ…}AXõæ}1yõ†/:ôBwš»•õû×hÙ®@«êW±Ñv‹#PêÒg‚®ý:Ž¾è±¸[I÷ë¸pS«æ5¬s$¸¯Ú7¿Îa6(H:ÛôEß z¬„ÆÅF(ÈêGÍŸÉz÷Ag,›;iî('(éÁ]C_ïÒMÈ: Âôà•⢵«fæ„Åi}Yz®Qð~‡Ð™°û=whSzkÝq¹ÙÖ¶R—±ªºÝÚêZH:7ùé™\ÀJ^”óÔ©k{¥PäÜÇ,b‚YV÷çæ}£ ÿÏ5¯zóQËEÐgÞuÜü,Sk¯0¸±óÚ¿;$¾›¤v…Á 9wR»úg¾øÿô÷PB{Á‘Ü>Þª¥õæúzî;(ä][¾ÕtÂâ8Æðé7ùLäAUHyÒÛQÍ)#IR;Ÿ1:,Ì$ÝŸ1>×§yÆQÆÂ¾•[A`œ×Ž»vr*rÞç0Èù`=˜ä¼çî3âD‚´ce‡ oË;-1jÑåP iÇMåóÿÊ%!O¨¨Ž“E=£`©æ±¸ß?Á2­$·‹d×j÷@ç¡6„|…¯&(ýT.æp8o£¦Û gg×r¬ïîæÂƒ{FøS*‡3Oó3º·yíƒÜ“l‚ž{0÷<7€»HûRËÄ ‘q‘nÁ‡‰üðR{{åÅÞŽSÒÛå–ÜmÖTþ¸êÐg[÷‘(é¾[ÓóKF:µ¸dK{å.E¤¢¸¸D­XØânñ AŒŽK9V—X»pÓå«ØÛ È¹aÕ\ÇA_ʹmÐä´ ŒZ®1­ÏV}úz›q´æÍ ‹o2eÒŽCáà‰•úNûð#»>xŸ.­6XK {ý¬iÇ¡ÝkR’RÉQá;=OJ‰VØZ?ÅXµó_½Ìóõ°ã£z‡€Ç×/’}ôÕ>¶±Ý õ´ÈkãšóúÙbñ@mç©–F€õ¤kJHx7!¯ZtææN@ᜄ®“éZN<œ .m²ží€ZžœðäxDÇÚnd`y׉yN¦·xÚ˜ã°Á{{)ê®Q‡˜+E4Ohc©J;5]Ò½ÒGéÎIûI¢é)î©9ßAìfÞOp O¸µ&¬‹ëã\„úéº0¯—5þÊVΓ a÷ZÙØI¬-ržú;Ââ°¢8ìÞèÚ§Ñõ}·sS¤õ5 +ØgŽ#à"^€¼WÝ¢A]újóÃÍ#sYÙIo_-Öôšì+«'IKAM”^ô]‹îã£tô3–ò¥5À(æÜÀË[Äü Í]D"Xwa;Ä¥È 9µéIÈ.3 æ¼S¸ûÂâèe9÷X„¼‘î'°¸ËB£1'aõf¤ÛÍað…ɹjÙ!ç÷kµ¶ÛVˆ”ótr'i®0Û‘ýÈ(d{õE÷“QNØW¨UG1—ê~ƒž›&îÚ–J.‹»Æôç$i”vk‚¶£žkL¢iCÄÂî Ÿç~JM€áp¯ %ýDÒ!ãë¢ì‹4ûª=ón«¶á¹£: pš‹¬›”³ó=@Ô˨×0¿ŠÍ] -s‘ð¥¢CØ3ÏÍY©(¹™+¢Î àVÐMîß nŽ‹”Ñ*Îìó¶P]p=ú´+:Ÿ°¥(èÀÁq™{L»5[݃¥ˆob^µªQÕ œJŸõNu7)·å½’§=§¥”ŠæzˆyÙÝMpœh=ã"@„ÃEÕÜ$0/‘%j‹AHÙ&æÌ÷¶ÕqAaq±»[YÇþ®1˜À¸ÙgbÅ\`–%ž:ô' |jÑCâÏ}þÓ7ý­iÃö7÷lîªC7A—ýýÙ±‡K‘vB|Â×l)'‰¹Ö—ê]¤údWçXÖ÷ûñ¾ÙÏ•Ö.lrþÞ&çNjדó/@ÎÏþÁ7¤œOÜ_|ôØ´Þ;3Dýù¯ÚÍðÙ)Ixþ°ŒÁäÛÇT;5¡RÛ[!/TùEzŸ÷ñ«ÎœwPéì‚æ€ÏÛïrÈ:ðç]í ‰sÛÄdRlbž¹ŽéšµÍCÄ:?i$±}•ò¬ù"æçäj’zýÚu?Ô\êø‰”£¤›€k=ö½Ð«÷ùÚ΃Ü7êš!]êúVÎ)½2nœ£×9IîVÓEÐ5Š€Çk¯ï–k²Â˽–¾ç®AÏ5gÛ¨äpmîô(é±½»õ*„œÀXvåÈ€²»F—îiùV̦Ûjºî—ßS­¶¶±²g$¼÷•ëž/Æ€¬VËÓégÆÁAgînBQЧü!ÉÀÎî>èÞÖè’N‘÷"ää6-Gjò®÷¥ÕÎW¯\²l«Æ\@Ð[­ÖÄùÄUDšß_„|1•˜a!ÉäÇE‰GD]ï·R×…Úö×’zðj‚‹Çâ5ý¾¿¶¬šÄöjÁ&tîØ^ó6ûêk·lGú:æ¡%å—m½ÄsŒ}öNGúû¿&bÀÓ†Jjß ñ£àÛº>‚÷)¥¼lNÏkò\ô㉕â^ÿ4!ìýõ©Cׯ¡÷úìñ²Í}Ö\ƒÎ‡Os+ç|X›¨›à¨ç^ß î Ÿ` ?ñ£¦h-O±ÿx»zlîY['LoïPÒÙ¶±0aur­Ç`gôFG5Ÿ¯ã×¹˜Ì>­eüdc+êXÝU£nrΓfÚ¨̸÷íú±$¼s é‹ó|‡Ä±-R99¶:ä4_=Ђ[Xøöþ"è ¾ÉϵP(+b”lî@k!å[QaÍ­zf=câ¦mϪÌ\ï¡ð"ÝXZ‚œ Q|ãYê9IîÚ‡Õ½¬£O]½¥2î„e·8Ò¶ðeZ!§ã"N˜””4‚â’-Þn€E"l]?Ϫ^•6l"楠+ñÚs:€¬£LŠt+Å]ЉÚ]£¾Õô&d„ÆAÌgÛ¨és’Þ£¨/Âþ‚ç±´—Õ=AOz%º0gÌqCƇœýžÍýÛCØÿ~íGiþ¡ëÐMÐißfÕZp õâ®ïÀ8­Í{@ÆÙg<}Aï³ö ¤¶ "ð!çÂ}ýŸSs9—­ýTorþäÔ›9Åüo?zâE“ó3ð–Âà”Ô®}󷸓ß?· ƒÙ‡•]ªø/eeGM{EPbÁ¾y{ž»$C£ôw†ÂW¥+wÊŒ†Z§íÄvÜ,înÇKÀ ´U\ùîN:¯Ìe½â´ßÊû:/Y5gÛ¥8ôg|ÜÖv!à~(©Q9»/:6vtνiYŽ'§Éà–ò9^ëtaŒžŽ3Yçš“1×%,퀒-½ÇJgå:ËvÛܱ¶?‘ÀÖ„¼ê^BíP!åéƒN»TÛÛ…ÚNý¹ï ÜR-÷sík‚þ ôŒ"騨S‡Ž˜A¯ {®Ì)+œý„öָÀAÄo#ÞÔ½"©ínå«ûOmâåãì¤ðÅ"èå ñþ¸ÒÓ¹þØ” ¦û‘ö‹çžy136º 5@%Ÿ÷d¾ÜÓš9Uâ)‰Å­‹zŽ8xØJM<¬H.íÃ4ó¸šû5ˆªôEG‰~P ´c7ßÓÎ k@¿7"ráqBv‚Ã'y°Q®êšÍáá"è(Ö|S<åèo¦›µ×-Õ¼UrÒÐIOßœ&¿Œm‡ m_ÿ pÇZ^Ÿ?b?\ †žÆÓ“’Ræ…ýsÔÄãØ*z=ÉÚ)‹óî…>ó,àiœNÚ¯‘§rÇ=ï½[­AØAÒ-z ½AŠ;ÁŒ—²Ý½Ðs~H¸GÚp"B€œ‰xû„ÎÑsSÊý+׃LlÕ¢¯§°“ÝW-úh¯F0œzަ]ˆ-´ Ú«å0:Xv9ƒ½PßÌ®¯$©úaeT¨O¯m‹»kL5f[¤¼lîZÅ5)ðºiêÒ [cQÏ5io[-ÛIv‡¬/²9¬u«*÷†~ šÙ-¯¨%~“zô 6lîÛÝÄÎ#-×R‡îÄð¨èâmL+6ˆ:äÝjûVØ«=[jÒ³&2~v¬Ý²¹»==Ñ<ø‰êÐOmúÏ è(ÚRÄ©/ߊ8 0pœÆÃ$øgTë>sÁäÜ Gü{Cò¦08‘ó(çó³ü@ä8®Zgã¸6÷´[IAWPœ¯ÓÐ/¼›VkVÏÝÞlÈû¬ 9—’~\C¾lð½¿A°Ü`Ôòù†ˆ‹¨ciw Üàük?“¥=ä|êèÿ!=Îç¡Ãw‡˜ORû´Q;û¹oNù_M½ù_œ’ÚŸbÿ¼þ¿Þ&µ:}Í©/?j§¦¿i¹)Ò’ON ¯•u]n85 Ïf˜ùuç'<3dÖÖvBµÍÃ,“㔆a7!·J®Ïl}ýÐ-nˆº¬ðRÒ»ÇyÂ$É¥ˆûÆÊøRÎÃÀÖîsSµ„ ïúslRÛ!ç)'š°8tÚ©5Qßi÷{ôÙEÎzˆëkFZvî,“¹æOdSuý\²Sh«V%ZÛ1æ}æ~7¤or®µMÈ=÷ubî ×MΫÅZ2i*(Ψ’9ú¡—£o·€5êFÇ[A÷vˆúêÞÖv:˜5ï羬ñ¨3ƒ*±½îñ.[tI«6Zñú^rÙÜ}O)ÐÚwF\ CÎA‚M¢+£I÷ÇÂr«¶‚^jù¼F÷ì^jN‹µþý(öRÎíð¸MÐ?ö…÷MÒ`•< zFZP£Në¸&¿­r/Ç5"gu²êdx·eó±¼oTvŽïäv/ÃÓZ…ߺUvÀ:s^[åˬ”}SúLÐ^ýn⛄`S?M!ûq‹°&©Q™ùUCú¼®¢ìA+÷û}Hr§¸žÐ9ÿâøçª¶kú'â^Ayt@¯¿ÕÛ¯môÿÓ¼ ù°¬8s“s>l ½öÔríúqúÒÞË:ƒå µA^‹ûJ«+Š9µ:IsÏ:'ÀyÍÌ¥‚Ónͽ)cCš'›«áo—Ü~¿ztž®òÄuõ>×h^£ëнÏõN±¶_&mt¶WïÎûZÛ¯ø5»î[˜êÍÿƒ~ÆùgvJªá ¶3TÈøÒ=D\ e½Óbiù"P[*úV×çX¯mÅÀmÖfô{•¢.œóš^Ûjú¶´“ÂËꉔ÷æº óšÙoU»µ6J×0®€"ßL²}"¾ˆyæÙFaO{m«åÀ¯¯'¢ŽõÔÈôS£àd¾ƒâPÏQÒHy‚¢>\©íQÏ5xN­¬ç"!+üÊjâa¶";‹˜g¢Í: ´«Ãâ¶’ZOÇØÜ½¯ÕòuuFƒ¶kÇõèzßA棶*çuú„«÷Ô¡‹ OXÜw´&’«tÅýÓôB1îVk­–£¤³¿-ìæ1Ÿ¹ ¹Uó󯽷’ÚMÐQÎEÌ…§^ýñÔ›ÿPÊùòoËÒ.å|Èù7ÆÒ>äü÷þ—lízTó¶²k­Õsû"äIö‚žÿ ¯CÀg¤mÚþÿªÃ¨èÙ!OoóvHMÿPà³Áç'¢˜kûsI© )îdMxR.ÐŽÑ„Ýû±²ëücGŽIºFæ'˜¤?u妈x¥¶cs—RŽëhFÀÐEÈí^b]Ð9ûÉ+·Ò sÕ¤CÎiµIz»¡ëÈv`Õœòªeq¡ß¡p¹~mXôtáÌ…Ýf dT|\ˆzÜmRºmm¿Váp¥žïr7g3Ò¶5jz°Ëì9/‚îüœÛÛòîúñ•Ú¾Ââ6)×ýÖr$Š Þëý †›9q ur†ºÒssÊ&WkßÕïk»ŽÉ|«æYK¬.&©ýÖ¯.®óê”äûk\®jÌ—ø–íßÅþÝ›Üë|÷B·Õ]'Î\s$ÓÂ9ÒYJœªrº„*I.nT䞇K»‰rqwYtö£ÜçkAâ7q^ï&èðÕó‡ÿTbqlÄlÄã&ó{Ü(wzy»¿§‡òMT¾ÇX:ÈíøIÍ÷Nì«z†MÞ!ÄëÙ)}e¹àÁB·Qãk6QǦÎ?ÆþI$¼Ž‚ÞÿpõG)t/÷Rÿmq×å»»ó|ÛU<®°¸õd­[¯%¡½wë;Aq;É]Û³ž Œ´Z‹‚R“Žz.Òzî ŽÝÆ2~¬î z]V²çRÏu÷ rîÚ¥XªxÊ 1ö…e@`õWZ 9l~Î×V½–q'ápg.œ&é<Ù.r¾{˜¦¥õg`'¿^kË;Äœ‘¶k¬¡š«/ú­ñ Žs0މvÕ £BIâò­¨R044—úBŽŠîž¶Ú7ïy;dÜýq¥²Pƒ¸’Ü©='ØIÂôØÍœÉ»Z×¼n6=®íØ=G%º­ZMnbMÔ«}ÑIÑš1¶ÒÙŽzN Ó¶½CÀ¹o¤æÜêÜj»F»%­“] ú@ëVΩ™Ý}œ+$« Ë›´eK¯Fa)ëÔœwŸj5¾”RF5ÉEôd~”ù;]‡V{69î…N|Dȉï9Vùs/}_µØ ŠS’;ýÕ·?¢ÕÚ&è&ÔŒeeÏûû˜g –S r>H :ÊùÓÞU’ü|RøÿqÔþ±´OR»zœ›œ«•Úw†”ë£ÇG9?óû_?%µ?úŸþlȹڨýb~Gÿ9wC)äQѓ޾۩ 2 7cvÕ–ƒ_Ó“ßc+è±³CÔë"N‰Èa8œ”s>÷¥˜7 è&㔾4BÆ5Vý¹9Çá“9ä=q ±M8®#ÖØv¹Ñ÷4wyç[ŸŸÕsÕ¡S–„C õ¼ÃâtxâÒd–˜°ß·µ'àZÄ5ª¯](ér‚R­¼'¡ýñË$¸×îNm÷èö¦™Ó^íÚrÁAä÷uŸ{BáôzÍ«3ŒÖ, R;k!í%4‚â&m½yZÐj|Ì„›n8^ÓÐf튊 ð˜RDü¢G@ŸAœ• t*DâÔ]…¨E‡œoìî§àe¥UÊzÜ©—(•ýÀæNæT‡Å©'úI]ÿ˜ÓÛu¬¶ã²ýá„R³M/ô.^y^[¡f»ÄÜpŸ¬]9ö-¼#~v¨7mÙ´Nø7d¿ÄѨò[¾y“V?'Aäå¾n´˜}_NÜǧz¼“ôÌ–äÚÞ)îÇ6ø"çG5[úϳ<û•–¬_ècqdÞ¤Ÿí~=`ÿÀXÚ[=ïø~B“‹Æ8è=3jô$5¾j@ÐA¾ŠÛêü!Ÿ'RU ˜ç$³ŸF×÷óÒõ¤ZV8Ü œðvø½'W}[`ÌvˆûåJr_pbçõtÙ™ºO¦Oð$º»æIH[¨ä+êέ´s"(²Îh¶¹(6´2þØk7ööu‡Èâ^poT[äHµÓúU¶ §¬s߬pßt0AOXT¥¼ËξRpmÔ±®í+‹{F@ÿslŠŒ+ÍÐ'w)3ç±LBÆIFÍÁ†‚N/_ÔóÀ7¡3î𤻤s3«ãJQf¾_m“è^à&ûËÔ˜J1Ë<¨ôvF¿V°:—:X`b°æ!M89b>ÊaÈ j:D)$½•LHy×sŒIXµÔB9¥Æfdnb¯y·d£[ˆäVÕçusœ¶!éoˆ¸F«îcå¾í5¬òôI4ÿÔ‹7–ðïŒÅ}Z­¹ºTtº@H\ˆzÅ¡˜[Ÿmö'ž}£‚;>µæc¡"þžÖDÊE·„¿ã0¸‹ƒ ïŒbþÓùþdr~ߤöoþZíÓ¦¿ùŸIÿ«ùÝÜÖï+Šx[Ø7aÏAÇAZ®mzå‡x9gNg€ýÏáù0ÿײÂ÷C)Ê@¢žÏkh±¦Ï”tÙÎ^ª¹à}|fó¹]ᔺ4!ç|ÐDüYwˆ´ÍùÇöv!„<ç'±²×ùl+ærAk) òùÔc@k5Ôôî®9xrH}:vh >-–¯A“[Âu‚št­ÓÚó**úJooXI7²ëÝQ˜j®™ÁRÔ!é;$î±Woð`Õ\ÁpôDwóê{A‡Œ›tkÎ}Åc>ˆrX0àþC!·$¸_­°¸ìëÄv»P‚GHz‚y»î\Áq§ýtÜ™Q÷‚n¹; ÝZÆypËãEwð‘;3-ÖÖ(~Sû³ 9ç>U÷¬QÖ­˜#<ù^—û\Tt+ eJI§ºõ!qùrŸŽ v숵rn=\`ÂáV§'æ"Ú×áÔ¤KìÔ:¹Y/A\3®²]ÖC”+Ø{ý敬µU¾ÒЫCWsC2È4:õcûµÍy«§9Üp’p‰×1‡b2h.ýP~‰Ôn“Ð^$òM¢ûIE“ßmñƇßvv^³±I<Õ¯OM:>ú³}ü°âþ ôo,XøK)繿þ ÐaÆaS<‡œ|hi­¦c¢¤oB~¡æ²¨gÞ$ ¸$ºcqyGAO«5è2_mÖž“ØŒEÖEì±¥¨Ú­e',Nýѱ6¡¢XŸ¤ çd;•’N`Ü 3Áê@ÄEЗÕÝ#OQÓ­¸S‡~§ãHy/µ<µèÚQ÷Ë;@-gy"oÝä„=ö“]&'"îýôþÅJr§ž¤6=û!ä 7LºÙEäfÔôªK÷ú"éQÖé‰B>€˜£ÚH¡‰’.,¢>Û!룚§':J:z¾T&§W`RZ¯…¸t”u“sÝ_½E8TDUŠ;ué&úE PÐý>;(.£ˆû/"[)T·î­Fˆyãžð*”LlÈGáqiÇfb&küªGO\Ø&ê€íN|Çz­ícyW­ôJy7hÛö Õ\£AÿtõÿäÔdA—\]µÛJ?·eüå·O–rlå"ê m ùÞÖt¶Ë®.•œµÿ¾^£qH·ˆ¸Þ;Ê95ç„Á½3d~ÈùÔœÿG…Á½òãù~H܋߾§œÓIí¿ÿµ“¥ýñÿò­$µw}yCÇ@¾Ik÷Øå «;Àg¾t—^çü?qŒyÏŽóëBÂß´:n^9 ´ÄY¢1¶vZÚõÒ:¢°y]ˆ¦jÍCÚµ½TrçYLgˆÛ¬ vP%ãyRÝï÷pÑéP‘ÐLís— Ùây˜ß–vÐm0;Í]uæ!è +ç(å×LÒ·ÅkÊ…sb{ºÐR^²û&¸÷ñ8Ö(1³j~À¸Ù'{{µX[x‚.œ±/–÷„ÁiMdººÂÄ!a‰*ùûoïŸÖ}í“q»þ4ÒÿüÒºÿA¤¸*Áƒ{ª&ä´[£Æ\"‹FjÐ ŽhÓ÷‡nÁÛª9Ä¿BÐIs·2\ª™ûÙ×4Ý]kËÚnG*µè.uPœI»¶·‚~¡ÒÛ½®\±›¨ßìöj;¯J$¤\Y÷ú1÷©¬-¬ÞMÊÙnžØ„ÎXüo¿.uâí–æ{‚g! w08¼0„>NjŽ„„ãð&L±šµvJ¯~ò›üo¹æÂCõd£±ßìêׯݤ½æ¨ð­hcŸ‡4'Q°•yH?ûŒØ+X;hÑvXkqœ2¹O¬¾¿wz¬~ñƒúyqðχ†À¸‡§)êEÎçê´æ$»ó¡ÏS@R%ŸD697y÷öîë˜ÁnAšNú%[ÚQÓwíO‚:Hs÷>ìí>I§“¯ R?k©AG1¯zôyÝõõ¤væi³¦mEg[ó²¶»7úRÑM Ö•‰¦Õšä‰õM“ñ«§‹(O±£žW=ú ‘Ó“v]”!è ˆ[ules×Üv¹¤Ãj- žü¨/ºŽan°Nt¡Þ_ór¬ˆV9 æ÷Ë75!ÇÖ¼îZFÔs¬î—›ÈÕè.ápX6µë3ž”ôÜÌbs×ëf\¡KÜK¹’j¥÷ñ>”tÝX+,JÐ ¶¶c{?TÏDžu³N/dú(;ñÙ AÚãNuÿP\½^û‡…WïMm× ¿iû{æ&;Ú†EA×zÖ "] cÝÊiHZKôQ¢;k>n©èU‡>ëmwïu¯³Öö÷ÏþÉ¥¢?ùGßûè±ÿüç£4¿5ý[÷ÔçïMðïùý‰Â×ÔºÌäøâ»"Ìô ‡„îÚLâAˆ¹FלëÁÀ©Ú»®7W]¼“Ú‡”ÿ`¾ç¿Wœ“ÚÇðøç¾9¤ük"çó³ýÏYûÎ*-ðï™ð¾ã2ÂÿžûãÛ~½ñ«´¡J"ðœ3ê8ÿOÒ6ð9%º£ 8CŒª5I/Âî’}~ü€Ë¤[ªºæ[5×çs¹aøçs½ò'²Í=Äy;îïÛÝ$2¯ävÎe]¾ÃáHoŸ9çHŸg…ª;ß.¥ÝRMc@[ÌÞÝêùQ×¢£’‹d“æ¾jσjï‰Ë tnÊAK5Aªù%s¹Ò\VD~sÍ®Õi¯–©ºÞÏBž.©7g¼½Ûª! “v¶CÊMÄ¥¦ktždTg›9vÝ7}ü~QJz¬í™d "Þu­S¦¸úJq§ì±œ–qVù$jºÝ›Ü‡ ™[<Š ´Ôò÷}Ë~î…Ée’€UmÖ’ÜÞyO„Á%Èy€Åýå}Ÿß¨|*õsêËQÓáh-^ÒíH¨=²‰³Ý–ø[·,rŽºItHmö¡ú·ÐË×Y´ûy—X£®·›àÁ"vîY5ö¶¸ó!å$§‹òÅ \ËX?èa;¶CBó:“ÞNo¯?N³¤ø‘„—Ô@þÇ!t k Öm™zŸ”Áê ÂoRNßóm?!´aµX›cDÊ!èñƒ ‘ÃÞŽzN :„Üã'Yƒ.®ÞçQÓs[õ9Y÷¶N†(æIqç$i<ÂÉ2uBû©çÌs⥓öA¯LVб½ó¤w¾Öa :"žŸž›Øw­–Æ…²– ¬­vk»M º-îXÚ€b.ä©<ûö«U‡Í}÷9ïÀÈ{¥×œŠK[Õ¾ÆäP¸NuïôOé†Ìí× à³]õ‰:†À¸„ ¥]OnW}z+;z/ÔŸ®C÷þwm«u›[aqÏèµ;¨TÊÒn"¾Tt±º!—j–í/“æ|þÚ$>û½…Bn⢮÷ªVl!Ï‚¬í­.ZQ7±¡V›ñ"ëÔÅq;Õ]ØïÇhÓ&â×*ú1a‡|CÀ ßõž¬Ù_ª:Övtõ=—ýÛýoEÐÇ6þ¥ O÷A’,%ÛmWÝþÌ ù"áC¤·²þŒíëÙXQÏ<„_ïçùŒ²´¿ö®ÉùÅ!æó!æo; î^óOþ{Jj9Ÿ ßP5ÙöÕFmŽy2îßq‘õ¬Sn«ºFH8Û]ÒÀÿðZ€…½a²Îk°·›Ì§Ç?uèÔ¤»ÃA}´žN&äéu.¢,R<ŸMUœFçÎ i“˜>ç9Ö¥.)}ÁÊ«zC’á4wRÝ+'ƒ¶‘zÀèóê¹Àù¢T µu@;5פCÈ5·MžcÖÃ×½½Uo@Ö—²¾‚Hcq÷šUs®YVÎg4yϾ*é’²ùö±CεMmúë§5_CwîKH9­ÕÜ.\[s½&*9¡p»¼Í}ÖCΫÍ>jÏÝòUc\n§†À 1ÂÄÛÉíΖ¾éá‹ç °Ô¦gCV5ïpíÊp3Aï49~ñ¯ `µ÷¼Ô6ºž ‹í± B“߀Ü«ñÝón‡Ðõ?óL`ÞŸþzù寶XÐB ï#x^v“Ô†ð¤K¯§}Ð ú±ÕÝæQαÐÄf³ˆ¹·«FFÇܯ]ÈšOZXÝÙ†” œw/tp9'Ò ƒ˜_Š’~»Ó;Ýš#­6l“"`Dó´W‹JÈܶµçâ2ûNs«å!夻‹ä'Í}Cû<÷Ók_<¹HÖE3ö4li7s¡õÓî\˜_ÏèãuœCdLÒW@Oæ} ¤¼Âj4–}ºtÃm¢¤"@Î7¼®“|]ð<7SÔžïDÞ]‹þi·Ú)¢nrž›Ä¢¨+ hß@ZÑéööª³\NjÔWOtãK(QN{× ´±õÜ,£v‰,cMm„”?ýÿ);û^»Îë¸ëË4)°%[%êÕí¸H?BÑÖHR#mT1d’Š Bþhã¸uä6Z;°Û¤‰ß G0‚¢¨%‹â%)vÍ™;øey´!ûÁóìgïsî¹ç޳Ϟ=³f½v߼êRQá¤E“âÂN=:dÕ˜`„À£ SŸKhÛ…´!·š9ˆ8ˆ]ÒÅq;‘‹ûŒEÚÙž9Dq¬×&ìE"©…®ÞéƒeO›0Yä³.üŽÛ´? ´,î_‚þ …ÄÙâ>k"è _sû²7EÐU~"ÏÔŠ/Å|ˆó[(ä¬Càw-º@Íù0æù/[5r.K»Èù(ú?”r.r>¯sììƒ!çª7wR»ÈùyµÇÿÍW^š ¹>޽¯‡-Ôl9׸Cà…„Â…¸³f¢¿;ôøÿ0ÿsµoYØ!å mÔ<‡ˆ‹˜£–kôÚÊwð6 úüL.ØÚù\š|gí ·LÊW+è³–jÆê"1ç¶©ç¾uÏkEй¹øÜõ÷>¸ºÎ‘7ïíZt µ\Πem¿xåݸŽFù¾·jÍ!éKM_ÊùºéŠ»Šw»ª*êíÚ©q3øóYÇùÅÍh=G«èÞW Jõ>Oz;7ÇK9߸…Óí)Ú¬Dª¥ª_Y¾Nrûlçš"­Õ€²wÔ]×ô=z.B.Â.!>Úªi—üYð»|Ð×]¯nÅ\HX–öóåŽt=:Ý|*<8빞TݹCáHrWºçEÌIpGl¢­ŽQAí„#\k\ÇhpÍ€†p¦m)çÚ"~¨œ›l#ÚmŽ@8ÁµèðŽ$¹C<á)!Û&Î1^£]YÈnÕ¥>îõŒK7v=8öïìC(渮ï oø§ܵþø¶·!ýü°…å~þ¸¨WÐúÊm+ÎÙœú‘åç/+C1}°öVÀÙw(ñw-6‰éØ r7fÔ ÔÌk,‹?Ÿ»<­ÌóOUoÖ¾ÃRöîxPûyynnPäuó;s¤E“ô+ÅRnèq¹«†‚.[ÌRܱÏÌ:6¤üØŠó(X=½ _ä<ë:Ù5–­èQ½î—i ™×¨žé+0’»Bî ±¸k"¾ëÏgV+“óǾü®Fƒ/•$½s·Øc€ÅTêÏo®;Ò!äܹž¹qo»ˆtcs'íý¢Q-V„„ÌÔ±)t&wäû‚õ¨K!¦Õt+ r÷F×k¸q–z>“‹žÔ²k>@5÷Hš;Q¨æ&é>VÄ\k´Û!ÕW=¡Bš‡”kl%Dë%˜Z .¡¢/b~I¯éÆÙ².Åé¶SÛ絜ôäûʶ¨ÚÚ®Úu“ñ(éô?³–±¡W«Õ¼t€²å}[Ü»>‚Žº¸ÔtHºíê»Ar}ÓS·þ HX)ìôO‡”‹òšuÈbczžßÏòø§UÃN=:!r^)ðÔª‹p¢´k{ˆí_MOð¯IuV¯ð!»ßQHܨçÿ{ú•’>ÄXªõ›©CWÂ: ú"ß Ö!çRÔ¥²úgb®q“s§µ_º2)í×WdåüË$µ?ûÅŸêË/|þŸøý¯ëw9ÙÚ?ûß™÷D)ûV_ú£¾æ$ðëfŒ-èEØ}3…9nŠV¿oÓë\8¶·ëõɺ]R·w'@íùm¬í"ó"ä|ŽjÍ ‹£Íaìíôsn¾‘CQIî„Àí®AÿÅ ¥,›;.žj©óV;ù>Ï-rN0\×™cm_%F“àžù&æ&Ü;½ì>ç{~ñêÍi­vNä/Nˆ)ªzÈ9î.2R ê|A_Ù,„Ã-T—”Ü O0«°o¤Ÿ…œîJœˆ5JºQ`apßrRûó±´OÝùCtÏ!ïóRÍg»Êˆóؽò=ïm»2¨+÷¶o½¾sÏ}cɵàÔ{Þ7Öÿ½ƒßDêïQAµ½Û© »¾¼Z¬%3BóØÚ× 8“ôçÍ>oø\r{‘ò>çÜ6ãgFYÛWô¨æô>·{hæ+£Ã¥D÷“ãQýÏ5¢š“ ø¹­†!o{;°Š^V÷çiÞÆÍ% ·Û«i{‘í§®ßÅân‚žc2§M)¹-(å·vi®´G…°óMÛ½Àk CfµÝõç €ëÞç´ƒÕõKá¦Z®}‘r;†ÅŽÝ¾vÖTnø^²p3Îqlí.s9(EÐé⃒Žó’`8…HâPuŠÀätö»ˆÊºó”ƒ^½‹Û´A8œ`Rnâ.ÂMXœÆl„ÁAÔÓÝmÖæñª5/ŽàíÝV-Ü”¾Èd·¢g §Ao¢Ü¼¯;! ·Ë9ûôš:)pÄX8de’µûzýŽBêÙgÜBn¸ï1§­yÀc©—ÏÏL‰ôâ‚dG=aóדXÁëéã¹[àmŽ sÌÑ] {Ã>p\¯ÐÖ‡nD¿kr7Ç­ç’Äwø¾a™øYßüÀ²Q©ó!åRÃÓ—PÇíDwà㙑0êy¡îÌÙR3­~žmNú²Æ+€îŠí5VÛç®áü£ÏsQgC-ºN\K1ÿÈKÿ/ÛÔï@Ò'ÆðœT—-i bŽÅýÊ]m«­F¶E潿?…ØÝwPœÃâŒ$¸§ˆI¹,Uw;'îÊê•$ÓRÑEÎQϱº‡œg®ÑÊùî_jòouÞk©C'͈Ìï/x­% Žõ¨çóôDW ¶lo‚®×rí½½qíµ\° V/YôRÏuìRÒÝ:'5éI½`ÛÜ!ë"é Ò¼UôsuýéWÞ#ÄhFú¢3bs'½XÛ û¹ÐÕnê8±¹s±,K;ýÑ«´È9ð~×¢Îi¯ökÕ¶IX„"åüòŽXsUË®Q€œ‹hèXÈ9EAW÷EÎ5¢žïztH:€„²½x¨ä‚NÍ3 » a oÕ×û°j—šN¢»¶QÑ©]'…øöÍEÆÕ\½Â'\í[Ÿ}êºCÐEEÐm5¿6D}tø&â"á&ãVÚÿažã”ÎîdžÄßÐú(å¯L]ûΗYmVå°{Bd{·Wû í}a‚ I7PÏo–šŽkp¥¶wk5œ†3ÚY˜5RN©¡®ïLÜ=׺‘¹®£ºøWÕ–í=Ú­¡šWíùˆ@rfBÈ]r Y'NöU‡ž.E‚®“­˜SꉫÔÛr‚˜µ!¿«Ç¤ö\;"çF‡ÃY°c ú17¯Ç€,—8ÙY_GJ9Dî4#!m”üj½Ú<¦z£#Ô¶¢‘´2Õ4çõð:S?ÎÈ1pNHyø/õ®Íïñ»»mÇ tž° ×ë%âþ“úŽmWVk±²&ìd=¯©ç:¯ƒ1d¶ÞèAÿ|Ъz)ý¼ÆNo?ú]ù§Â~Á{ÇZÝÍ©ÒàÀ”t’G%'@êÏç¸XmÝY&![û±•¦[¬yí¶¹»µD”t䬘“r¹Â5¤¶¿Ë 1d]¯Y-ØÜúbõ¨ŒÒ>'TÝÁüÖk"éçõKsÔt'¹ç:tF“ò•2ê‘þ賦/)mWª©ë¼¢žÏütGšÚ.îb‡œGM'ÍÝÇFE×|õ¨écmb}sº«kÍ ˆCM÷¾Ce°Ü¢`kÿo'©vצ[™ÈE õz[)×1VÞwm:uèX¥j¬D÷Ô¢˜¬BŽ¢¾I;E²gºßîjïƒÚæx+AÌW`Ü ®É$΀˜¢Lm()Ê&ìuaß­–”öžù¥Q÷S§*[<ŠÝŸ«’ÝÖ¢ˆGIɇ¨ÓZ¶õî#­×ákÁ$Ë1hÂm5”žèY_5Ç[Q-¤wvÚ²-BRÞ*0ÛU£¾l݃ImbN < ð£˜O–p)è"è£J«}t+Úפl¿%‚nÕ‚"2.EÂÎ1&æQÏ•ÐîjRÎõ37?S?ï'$µOµ7‰ósa”~…Á}S¶ü©7ÿ¯û—ÿiÈúŸßWötʹ¸éá÷F.†ÜY5å»¶ÜàïmU;»1ëë‡7|\W¾{Ÿ‹°CƱµçp#ŠÿÊ>2²hRÞ®”õ¹“ n¢^ŸÉ ËWBÐ…Ü ÅÅ…³nü¬¬‹€“Üž¹ö±> ±Ývv3»ÃEŸ?wÙÐ3¯Þ…œ"'h»‰¹çºÉŠ; •¼¬íó=£c(…B1Ï|[g˜~Ep{µÙ¦$K£ÖýW%_ú9®Þa_w?ÉñsÒÚÈñ9A¯áp&åºnØéí ¸ðpßQsž–®XÜgm 1ª9·8/D„h$0®¬í9JºSÚ){e~Õaö›_˶”óâ%E8`xnåP¾EÐ>×Áߦ&ÞƒXÜÄ·…eHðqÒÏÅÙ¥š ïým}(Éí»9^ë~ãy4^'È’þQòÔ–(èÛÖîš”AÆ|!åRÉ×];ÕÔlŽF߈Gª9'+ëÞeQgî íígîn{üœWXʹ-ï‚UòW¡æÈ–§ê‡° ¼’Cõ>Ö7Z®~&*ú wÖ Ž¡žmF¡ta×4Y'Ñ2®1iîã'õÜ„~õDß­×hec!—‚.°¦ ±ØÜ¥vøìÔ —¾è³?ápÔ,¾oж§È9ÁE®´’^àâS#!q«ÝIîï/8͹‰ø}«X¶¸« Û"íŸ-â^ß³ïTsŠ’601Îö²ÃÚÊnK-v÷‚jDz±ÁÝ’íòkg3_ÖÞ ÀºÛï»;$}‘ Ô¦ìì&U»Ozm («$wCÖýœ&q‡}Òk.²Ž…=û6AujÖ7Y+L.}ÖÞA_5è²—cq7A·ê-H _Övæ{=Ä|žoB߬Â7vv)çIj¿4d[7žùâß( Nä|ìì"æƒ{òþRä\¯YÊ¿È|%߯÷ÒWÛgƒ‰ùoÏÿÎn¿7p Äà²èò=&wúë[1¿üÚ=n$&ä \œ×R] pŽè± ˜K¹>KÀˆZ®y)æ]vBé s=ÿêqθϯåf!•„RÒÒá–(æ· ˆ8°ÉçÍóRÏQÍCΩ?·:>„^ð¶RÝŸ}õnós¡õr!7i¥¨{5ÕüAˆzJªúž3껥z™wj{£»™@ȶ¾ceA7i×zBâPËwIN;ã–àðÙ ¶²³îÒ¹ØÜojŸŸr>Û´]³ÀE‚Þd6µÉæI ¯ôr0¶HBón¯†(cÄö®k¹;¹nùÖµ¤Àa'µÏcãÐüÀcãDºänÅܤrnbþKíÕ~9 —*uæ&ãÂNoo]$]è 8‘ò!qU ·8sáU›c+æ…%ZâH>æ†Ì‹oÔl×ÏÏ:uã¾9,?ÇÇå1ØûA·Þý<*GhÜ.anù—º{ÑöÜ}[³ý‚ý„µïí¬mâL:<Öö m)Ç"ÁÏÅßwaÞ Õ‰S/À’Ÿ±kÈ>¦~÷#«óUßßwƒúø9&}Ø!èÔ¡kžÞ…+­‘úó ƒá´Î¶)Ÿç™c9ˆèéÝœPꮟæQË?:Ç­¶9&ÁqÝ/’Ú•àΉ‘“äªbV ƒ:ô(êÂ:±SË´¾XâùJxVÍ”y%¸À„|%¹VŠ;=H5' ŽýÜ_ýLãna‡ÓyÎTË5RÞMà+ÁÝöø™£˜Ïþ(籿ÏãV_ô„è,EBP.t ä|×¥GÁÊH{5.̰¾c‹4Agþ«6VÊ!éÛnéð7+勨KI¯°£ʺ-ðQÑE²Sß©šLt”t`k»çå\Ç[I²-;«êL“î¸Î•@¹´pZõ®+Õu,ºôÌ‹ ,ôÚ&tŸ€¨«Û ûfd©è>?Þט›™rgwH%×yRçáuîu˵÷ëœýü>kÛJ9Nª@jxæ©;ïþçZ_ß=©E_£PÄ\(Âζ¾ ;—%dÜc@•n§VýÏuãïxˆyÒ7‡Ø­Õ2ÎщãO!r•â’NkY— jô6×H¸ Wßs”s·TÓd]Êx¹-ë7pKj›ë?Ö½†`Sêyp½¬í£ Z®¤öw×¢Ó+&è#h-5½úŸ;Y]#)îÝ]©lî"î}èDÔu·*uè§dw¬,±ÀÔ‡Z¤ÿåQÖ«îœBס.<Ûæ)hMŠ¡K *ȹÀô@íØ×ýЩ1õ±™S«Šúl¥E1·Â.ráý;½`Óu›(Rß7a.£1€¨ÓrM# W:½Î!WŒ(¥:¾­í»nò¶ë—‚ûÙ!Ö"äÂVsKá=°¯ äž‹”ËÚ¾ö‹ â_ýÙ‰ ?¥¸?üŽTë!ÈcqW[³—GE¿:¶s¥«¿jõ[ý²lîi·vJa'.-ØtŒ ãµ}ÉapzAuç³=Ï}åÇsSàï çsƒàõ9Ÿ08‘ó'?ÿMµQ›„ö¿˜¤ö¯©Ïù¼_?¯ß?¿Óo‹Bï-uÿ»Mš@ý?Éú$¯¯>ù•E`R^î pôX;6DÀ!á«coËήã5Ò^ЄZ£€ËD„ÿÄœ€¸ •rlît^˜×åüˆ(á+ø14®ÔöÕ^Ê “Ûoë1••±Rܳ›Ž€LŸunLȦæK1÷1!ã]f–b>`.°fÇÔþXk¥RßC&ЧÑ-Õ¢œßÓv©à™ó=Çwc»çŒÛ¡ÖqXÙõÝ{¯ÝnÂ&æ ‹;)á+.=Ï!î›kŸ ëZ¬ EÈ¥žßT[Ù.ñ#Npž-ï©Içš+6÷VÎ;ø¤DÐ=)îCÜu 8Ïtýèða W@q\:öwê’Í\ׯ5Šrþ .Ò#¡+¥£&ìq´^FU4ÿ§/ý¬á씽{6vÍåžuptr©f­x„¸…·…þÍ{+Æê²ÙϱÅ-WMxÛèWIñ?ù÷?;º°ÔóÅጃ×@_óÕE‹VÝÝZ\ÄB-4Á¿RïÏâ¹uÓ}õ8?'wv[ ŠˆÆ^Voïã ÂB°ýú<ϺKó›/½Ýd=¤¼É4ÇðOÁëïcŠÌ!o¦À¶À›ÚGý}ÕF°m¤ÕZ½†ú'ZpÅÍ:*>x‹ g°8àV ­¢ú¡ûä¡ZtÝ”R¾êf¨E?w{FjÐq] )su¯!OHœÀbž;¥²2I=×¶ˆ:jºGÔó]‡!/ø®®­RuiwŠûqhŠö=®ävÝÇiÌzÂá¬´ß Ù=D½¾|µ®Q7 tw}[ÝV¬ÇVÔ÷EDÛðPÈ·û"Æ;K9w 6o´YÛ„Ýé»X· ‚½±R|+ѽrIò~Ñû&è®æÇý|]—Þ­¾ÍH]ç®MO¯t!ê– ùn‡¤íw²¼›XWM:d\ä=VX¿ögàp9¯!…óÓ1´Pó¾×Úìyž'c)—X™Wà›¶E´MÒ!Ýšæ¾·’ÁM !‰(¹ÔD£¢û5dͪ¹I'Ä})ëXÖX·‚.Ò]uÞ"è"Ê&èW~Dú'²¦B¾¥ˆOMùµŸ† k[ë`Žô¸(æê©.rnâÿcÿœ/ÿ@õæ"çó:þêT ñ¥o'©}^ãyøø$µ?ñ»¡6jÛÎ^Xïc¹’¾’¾Û¤™|;¢Äõ¥žÛQ¤üÐîÞj9 ç9õæ >Ô¼zßÄ:B>Ÿ¿ØnÈ:û(Qaî6‰ù€Äö½f"^б9Qr㛫ÿ9D½s“í¸… é&䞿̂ât³49¤Ü:&ŸËõÌœ‹5V‰Æå¤Ò ÜÜäEEßx@8­?g¾íí©E'Áݘ㠆óú¾a ˆ¹9¶öà öÜp¬F·Y›qP7ì±¶ÛµçuȹÝz¥¤ëq\›¬v±ÚGi_Êþ²“Ý|°ÈùRÌ!ï®)ïºóOX%tÝç9*º[ê¹·Zö.çÝônÐä"®Çx­zvGeGAÖˆ}ö£ºÏètx”ç!äßµ*ýûçmÖ^Ú]Ztt+ßôË‚)†d¿•õ#r.’/r>Ï?ApÓßÜäüûúyºY è&Á¼Ž•Ô®纠›óº!Û;äMêù}¶Y¯÷—¼€(çl E´__ªºˆ¹×w0ÿOï}×sC¨n ®ÿåEÆ©Ao—‰>ŸqyI‚¥¨³ŽkeߣM¢¹Ž³ †íÝï|«ç:W1×ZTóœ[hïH@ÜÜlL6FµV‹‚Îù¬uÚS†¼wŠ»ƒ6u¿y9'ˆ¥ü_¹û»Ž…œëf®ÖŒË÷Æ ˆ›qžcJ¾®ßJ.| ÕýYw$Q–Jn:7ïï?à@ÕºéMÓ ß,§ú"ì(å ÐvÕcTñ™ .Ÿƒ„·Íý¥xFˆºZ­AÒg›0¸yÌ`DŠì³Ãpõ?×Z®ŸD¤CÔ)9ôõYA8 i·¶s…vÝyºÿ\;l«¶{£¿JzZ¬=æ¤ÕZíQoeqïkßXÞq¡¾¼²$¹»ÝZ2£Öu{Ãöõô%Þ™˜·µ]œË{—»;ãn±vè¼nÖä–vf[ÉåØÂËj¾ç¨ç¥Ü·ëeZ8jÁMò¼QBq;ÀQÞánëyÓb[øÍáj%Ó¿÷•:øLЫù¯ðGb›õÁúƒfÎ1Û.ÁHŠ:û»7_—ðZ×ZuæXÝA­ÅÔF­%­ÝÉŒ¥žëžñ#_|{YÚ¬˜ÇÚ¾’''¦Ôžc{OݹGÀ ¯{ ëD©yîb¦¥Ú1ÿøËïzÛ¤Ü(ð`"nrNz¨À]ìZ»Å_::îÈˆz)è«Iibs§UJö³ÍpâloÇ—í´l)b«»H=m`ªäY.TœôÎ…IÖº>‚NjÏ3 ¬í0ŸU;ÖÙVÐ&Dô²HBÌ](š ­Ùºbžm=·.4}1Jíyû{¥$kõžªS¿¿ú£+,Ž4wlì±µ$ÝúŒ ,´Qæ<7ñ¨Ô÷j·ly}c+1Ä›»G‡Ã¹õU‚º4.²^Öw«¨UŸœmHÚÀÄïˆôAè}¼Gž'À¦½êÔ»†žêõ®I'Õܤ]jõ±‚þòŠ _ºúÖ9醈ƒahÔ1i¡fKûØäõ\îo~r>ap£˜oÈù)©}^‹ˆù_F9;ûÔ›Ïþÿ©ßGIõXÓÄŽ2N2¾ö-W‚à>òë½ n®öwèŠ0ÑW¨ÜƒÁÅ‘A;?Ï“} í…Ô– š“Ô~®ŽßÖœÿïY#µ}öÙÒ®ÇiÌgÏaqãR™ÏA,íRÃÙ‡j^mÍ >ó g„xktót@t‚,« gŸÃôúsžSÚºÚ¤9,SûV½yõ?÷ãtÎ ÷Ü ä|´]çqÏ©GOP(ýÎ_# Në«ÞÜß ‹¤¯óý]'W¥µ·s ;»¼ÆÌ’ê±Ôól”ó”šqÝ7×uiqÛ€@ØÔžÇ²NFÍÍó`Ù[ñJ;Èœ–°´ˆ5HpOømùn3›môR×s­ƒÛxÌ¥ƒÙ®Ü †÷ €ƒ¬KÌùøRÈzJ'K Jh±‰y'·3gí†5"Z¹&Ý塈\é~5}õ=7A×V™êˆoi¡¼jÎ\µB¸Á"éÔžgÄe~ç5´¸Z'·[‚¦ÐŠ<¼+ü.TeÕ í³*m;:êôNˆçxñUÆõ\E´KÙ7,ЫV½H8övîyÔ¾,zœd:Hòþ#.ʼžçhm"ñ+ðÍÉwàîyýóêXH2cÙíy¾ª'/T‚}ßiÕ»]MÔ©;×\#¸Úµè2ÑÁ›»ök¤íšö³þ1x18QœÈ4RÇ…=wB9 ‹KUÏI7éî†èŽÝÉw÷¿œ“.}µ]#”Ää\övîêZa÷—m×rg¤7( ºHù­ ÛnË©îQÌz£CÈéy># ¾ÌX!qU³F𠨄÷ ×Þ++^ð”ûµ&É<«Õö(L‚®9ªÅZw"|×ȸ­Ž\¬YA×võBúú{„YA÷…âÌRe¾á€Õ"¹hÕ…ljÏõœQ™¢:q1 IÏ<ä<©í«ìu°¼[A×v«éQÙPÍI†Cº?:^h¼NûµË·Î´Fºˆª¹É£ç"ô©)‡ÄeÍcÚµ-µ„L.‹;ÇyNM;ê:ªyžÞ¥ƒçù´/;·¸‚>kQÐê…þ“!í?Éâ=„ûºÈ7„Üóek·þú´OKÍùõEÎmiÿ£¿MRûÔ›wììÿcð­´Qå\¶ö¯ê5ìß©aâÍû3Ç–­]cz–kÔßûºmï*ùí¸ êïÍ6S°ìêŠ9ÿ_«žœ,… >´š¾mì ;H°«“ÆÞŸ·q  8ó(å·QÈs.ˆúÎM;ÈùRÌg›}ä_¬< TsYÜ«;!˜¬=w*z_pæýÎSDVv¯±Nf7P3 "ôtìÀ9ås½ooCÌ3/<·ƒëOh¹&RÇבBNY­Hs¬ö«µßÎuybsÖ.Zÿà›æ¯¥}êRËQÔ5o7]È:Ií¾¡_bØöcªç9ÛÓöŽ®c:×X 0A§ÞÜ¢†Õór!V;5njÓÝV-" ¶v:eŒ³/×~äF|…¼¢!ðU" A¿{®¢ßÑhw\ëZ-¿:Û¶HqŸ¹àëæAÖ²¬kf!ä|°Ú£ ÏörÂn—ìê*½ýê*™](EbûëðµîäÕµèl Íóúgvëk£k¹‹'$÷¬œÔýüð4ö-ηnbäæ@JÅS¿7nôû釠c3¨‡éS<Ϲ=ø¼ð"ºæÇ>¤ÿwú ǶrPõôRßéíMˆÛŠž7µƒî(€rŽÃ ¯‘ ½ÓúŒ]ûÞïãZ_– îty\Á´Z[6÷Y£]á_x{Ùc>šúˆxìí·íî±âлÑãÕ³sZ«Q‹®ç]'³:ѹî¼k~˜ÛÚn«;ðIum¯ž˜&åÔ)²¾Ús$d„“~‘ñÌ©‹âË&/ö]èÞè:6ÄÝmJnxN!Dý¼ž bN?t‚â éÔ–¶³CÒû˽TôZ‹/}ÐÛ¢çÇX=З¿jËg=½^W˜\”=æÔvMëÞN@$Ý=Ó5b?<ËE•~V©éG=b¬ ¢:éÀ¥ÒP´&î‹HHús7Ζ²n„Œ¿¿­ (è̹ Ðõ|¥0_¶ò%ßu§\ÀkLŠón·&ØöîuFHD§¼ë˜Ý~ h-cì½YÜzmìùØÝ9¶Z¬¡j¦/uÕ§7)×c¨KfÕ’­ö›ˆ÷c!Œ]OÍvÛ½ý8HêmĆÈ=s^ƒ~Á!qJq—š}"èÏéûC¤MÐM°ÿÞŠø„¾II‡œcw÷úOEÎÕRm  ¸sr~åüù/ÿÝÃg¿4Ií"ç_øî´Pr~ÞFí‰!çzMŸüÜž›)ÿ'uâu£bò²¹cûß7?¢°” Ôû­=ÇË*^d5=)ý~ì‹7îÚ±1ÛiéW½øMÖ!蚣”{¾Éù"æ©§ušƒ_|íŒcºT„Ï—ïmæþŒÑëÜûPÈ )uIz\79wD)׬óÍíEÖ™—ˆsÛqewtÏsʆ‚¨æÁszœçœ›Ý"ÓeH”&íR¦Ü º9‹ZÞn+íKÞ ¤\kYŸŸç±L®ŠK¶Š¬oUÝó8Ï–½Ý£\oÜ0/‡[°o¶›p‹lŸe»RÚ£ž?y³;Ÿxùçç‚Àk2qôø¤¸—30#Ø6öî^™?±´oåÜ×}ñ!Î3*%>\£Hýà½MίcgŸëÈEÊÑIBû5ÛÙõó´½®=QÌ‚¯£œTt‰VvÐro[ÔŠHF™)-×R»žkk✠!_íÖ´æ:tNy†u[˜ƒ¬–(‹¸ÚõåmÏø«v¾b.͆~¤¬ö¿’»Ñm¹‹;w©u§ÚÛnï÷ýËBxs Eí‹äòd˹@9ˆk%´£F7q]¤X¯£nTM@©Û$ñuíy½Ie÷`?7,<ç©ï(ŠÇgÛGBèy Ïcn@Ôƒxî”­Ú9õ+k ã×rR˜9­Ü‹±­íœdBÈI°ôã¯XI_wIÁä„§£p¬ /$ÑÝ¸ŽŠ.H%÷TÿLÛ¦jm}Q4rWXA'Bän|`@s«àBµ\s¯ô±ÙÏßëÖöe}|·¼ ºç!å¶ÃíÐ8ïsÍ›/ZA1ÿ`›VËQÔ©9gßJÃiY÷<@Þ­š9×ãeU¤uÖö ޳ú’në{@"oˆ¸¶uñq/uȽҩ¹œ¹GñÈAؽ¾/Ùé1æxjÑõ¸ØR£Že]óî…\¤]ûìíæ†M0hE‚»yaµb#Ù]Û^ ¬x»UH#ê§I=ªêNs×ñ;µ}M©M7ÙKË6æ­¨+¡\Ä;jùÌ—½}á3:ÒºmÞÞåú{ÿÜŸRýõ!ÇVЕ þÜ(Û'‚®ög"× ‰»&²=µä£ Q̵&rîuêÍmiÿûßTØœú›Ïó~ÿásª7?o£öÔô89¿ ¤ö;õæNj—µ}”íŸwË4~Ÿ ÚÖåýe¬÷°Öƒîg.ûzÈ5ë´ñ[„\ó´\Óv·UC='ÎýÎegÇåA8¢ÔqBáNkt8ðZæàTµ|>¿š¯ç¨é•A $Ÿí†Ž1çÜÀœ–jëf @G ¯;ð-ç+¶s^»D@œÖÇÞN+Ëç·Š^¸8k¨æ~LÔtÎÛèkît¯QÖ´Èx¾#*lT6vß¶-’+«çzò½]csu=ÑAq"Þ´(f^ß« j3­È¹È87ÛÙÖõ€öG9‡°‹¬£”_?Û7¤´§Ü.cÛF€°#Ðõç+oGä÷Ê#X¸ M-pqm˱ÈÚRs.¤´ÅÜ£…õ<7ÉíRËcw¸¶Ü­Õ臾íìä)é¸\ï"Z™˜ëZXsog.e'ãôØÔœhqìñ|ýüÚý·þèç&ãÞŽz1§­ÚgmÝU2[íÕÜÆy)Âp$ZnC²ï¬NSÍ¡°©ÓNû°5w+Ý^SP8ëðÒì‡ÿñœ8ÂéqöÕ÷žZäü@-µüàgüŠnÖ ‰ëŽj ½ìwóm§àË›KÓ{­Sÿn•›ä» Žlù½æãûwçí:_à}p“€y}ùýýêDwHºRÖ­¤§ÞDár¾‹FŠ{‡Kxß|°ï´Å}Žå$a;ûªŸvû5÷CŸyH¹t3†°W@\Â7Þ78 éÜùÜaq²9i[óê‡~@Òck·*OJ¨æVηz®çÒÿ.$\½ííޞǮÞèôÔ Çʾêη¢ŽÍ=„þ»>¯å!¨gpn>䯸å›RêÇ…àÓ·î ÏúRÍÓzo…ææ‹`Û:Ž‹Æ¾é“–iü4Çâ>p°áõ4ßÛ—çó¥×[ª96ö"ìé´vˆ¨ìý¹†´¿xRÉM²CÄ­ž»,Fç‰ÆQ 9.ȿи-ït¢¸ÿ9Iî´‘¼úqjлƙ.ê…¾,ïU{>Û³Ïð9¾2F˜{}õ8÷¨7ßàÇFAÕI¤¾›4êÿ3v®=–Õö '6ÇÆÆ\¾ä7¢(…‹1òefìÏØF ‘/€®‘Á‰1Á!‘"EQöLOö"«º¦ôdQÞ(½ï~÷>§OŸî³Ï®]µj=uƒï/ìíÕr47ªûûÓ„ÝDÂ>N4ÿ^œOTíó<ßÝÔœ›¬ûÚ@Äܼ®J5ŸõMÌ…û¬†§äN"ADƒ`ÙÙSc}†éh.CÌ=ú8úŸ›h‡¤ob7ä*3¨SÛ?¤m\•©Çî}®âeq°»#(%/ õœ}¹î°µÕt;LßáLdzPyN(çZ‹0æÇ¡”CЭ˜—µ}Ö2gÄ]kˆŒˆ&¾@µ÷Ur;—ˆ N‹2s§â:GyÖàn ¯¶’°¿ù.hjÈëØêàeì¼µ&Ý¥œÃO!ò)ôÚ§ç­2î;ßÔáM*»¯[Ý¡8²‘s\¥Â÷œÞãÖQÒëµ`c¨Vf>Ⱥì+}¾~.xÆ8®ƒçxÀB.ðŠÍÝwÆž¨ºuíó‡ö0ù1s9 m9[UçÎ!''êrÒn¢Â5tœçÝIœËöNïóÌ!ê5èŒé‰éþès²×vZ­e­Us·+ÖàVxé¤|1Èùeˆy¬î;$ŽdTö÷ò|™jÔã¼”­‚Η9Š9}Ò.HMPA5WsaQwÿEÔµ­çr€½>±·Ç³¿l…Ï0¯DwÚæxÄê® ´¶®ãP×£ÌÅN *ñ½êÐÛ¦kе²Ôœcù…ÀY‡Só;(Ò)‡ýªAÅÅö·är»WÄ’4xS$QÇjŸ•xH¸¶3‡°“r=ý¾±¸Oøh¥©¿tFªM®_‘‚.â=jùÔ“Ûæ.R>Ü„=äüò´¦}TóWT?>Dÿå!ìVΜúöÔ>?ëGn£öé?õæŸüÆõïÒ#å<¿õ¸m’®}í>À…PcýMöóuR»RÀW©1Ïÿ“IwYØ€BN¯s!¨µÊqˆ#².h^Ž‹¨“#AOs£UsG87èØíºñ¾ÝïœvjοørTômc—%]à†# ãÜÈÎå@J½ùs·Ö"D1/ˆ˜;_d»¤¸)»óIÊ6‘‹ê‚þ\lîqk *ѺNŽ -C !å;Uß«!ß§”‹ù»3µç±·£žWÙÙú.+Î-ÖRÎvÅx*z!)ï¹ñ«´vÍeqל.5KA'µ]ÎBìí…ja»ò},š äqYݽÎu¡p"ÿgDrNF‘ çÎ6×™”XRfÙu欨¯ëUȸˆ¸ç`%´Ó÷<Šú.-5Ùçú[ûHq×ÜÄ| 97"Æ ÖÎw0\ó Tó?$?¬ÈdæÇêïÞ÷ÖëÆ(øšÖAnåD†ˆ¥ºŒÚ+׸žsí'4¯¹-Ü•±À±åA¯„qšñé7H¨7þ8ä­•ío9¦cíA?¬;8+¢¿Õð.È?î•ÞÇð3xÝý:W{:šà¼¼ÇÕȦ!ä&è~¯mq7¨?§ºxs,ðEСé}Ü©J'¹Çê3'ŸëÞö±› w†îIéz :i:}ÓÛ´]ã„{†ù¹Xœ8ißsžNø 9Ùué—©‰òˆ%+_$¹¬µ¶¹Óv#+L;X×xÔóÔ¢“´ê±UsæÁ&ä~®Mίº—jÓP‡nø¢ãØ—–j÷>qMd›‹ ý(l»ÅSá£`Ä~èuät…bn”uQmi±fð›^ºÍÏhõÕFnä¹5ˆZI_P® Õ’ÛŠ*zà‹bTt¬¦n¿æ>éÝvÍêùW¬žK)Óš@г.ê…EÒ½×¶ÒžõM7Qe/ª¹F!‰ÓVÕiÉF:‰ÖÀ­¦2Ú¾B¹š,9dK«t¾>.«s25„¼k—I}_ªlˆ$Çóø#ùgÏœnb u¿u!¹mß5艼pF¦MÐ)\]–uôMÒ?|þßMÌmi×1²ÄÏcDÎSoþ ~ÿÁOCÎçg~o0Iíý-…ÁåýÅyÝzî¨þ”î÷§•ñ†oº¬ã¬¼>§[ê9ÅÝÈ)hû},vöXÖ“‹€rn Ž›pg¬›PscJÐ>ˆ¹ˆï37«eáÜÐ2Aß¡!çz~+æEÊ•3áPI5sm'nóÏÁ–òš÷¹NÛœΕž'Á`ÎÜ4Õy×DüªÉ:¥G&ãäŠ8$N#Šº¿+ÊiåÐÑÆ­î ÷?)+;d=ãª1g\óûEâ}Sš¬•ß·ÅWyXÝð^¥ejqš9X¯ÝZf\apW!æ·kÒ ©íäv`[{מ Y¿kRÅ Ñ%½ÝVw“p_;ÝâP´ðáó]vxÙ‚ŠUóº¾CAG˜Éuà*\$úóçZs°ôÆS´ yN œƒÞfÐûÜX×Í´,&Îclî\‹£š{Ü¡ÏzåIQƒŽ8GPtzŸ_ÐhžaÅÜp+çâSŒMË~ÈË ¦<ŽòéCñ¶ïÖß!ÁGÇo§2dE°û1†H¼m—4h4çÃ}¾9+íÈ·Åuœƒû)‚É)o·Ú‹UšŸ×x“»VýXÕ/ÛD¥ïucüóØèë®Ð®[ºNý¸Ž‚‚FÕÕ÷ïåç«p»®i)¯:VÐ=R{i_õ耾‰¹N8®9ÇrÓí×PÍW»îìÑ ¤Ýó!÷î‹nrnëmט¯°:…;¿ðª‰·ŽWÿKÔóms×úÓc‡š/’Š:wvwpœRK=&”$w,]¶³k޵]Ç?YiîôM}_’XËPÏ—å!ß¡qú‡Ó}×¢ëA!êÙ¦¥0_êzÂᬤghŸH¼Ö±¹çBh€UžÖjÈ}€õ"åÀ>é¾»Ýãæ6ómoïZtÏ!æV|d“¿^œºEÊöj9´-îÿ·†E=йÁE³Öõ<ª˜æ"éÕF©.æÔ»ZQAX ^µZ37a·š˜cB`°cu0IÚ.’„å}µ´Ò>ˆ<€ wØW«éIqoõœuYœm{Y„ˆ¶;\/r®íÕãu_d]Û"èªA’þítÕ†Ûâþ„”ï[ý" ºb.hýC²´»Þ\=ÎÇÎþ²,òó|/ªž]¤jÍŸ—…~~ÎÇÎþÝiŸ&K»“Úe{ÿóƒ°<½Öƒög8 Èà½hê»æø»¼5¬œþîô:Ï|Ú÷i¾r4Wm9ùüŸÅÉq¨”ësÑûÖͪùŒ®øå¬AÜçÆ×j¡f«z;å(3z>D_?»ÊVv>Eƒ}›„·‚ÎÍAçi´ãǤÝÛv)_#Ê9Ý¡™´M3ì4šs:¶w’ÛA#œNœßA¹«€H»GCÒWÆÉÆRÍ«ÅÚ¸Å(ãâ{Žï<)«p8È9߯²³û¦8ëRÉ…|wü·œÈõêârpÓ>d|]Cˆ°§Å«,íV̵Mos­¯¶kIn¿7®À#<”þTõØÙ>Íï>¯ì ‘jHùB…üZ€qM:Ë"åˆ9B‚…i­&ÂüèºÞtt«é‘L¢+GÉuç´R"èå4MÖSÔp:(¡˜ Å5[Ù!è Aù«¥¤ß‰ýÍ_º¦¼¹N+ÈUJ¼:k±ÖÇ"Ö™×1ï8 _NîF­ã¤îl1r‡Òñs7ÿ¢%ZÄÖÿ—#n®Û¢0Üø¶¿ËÅðù£ôöùÃâ{Öšˆê1ÔôÝŒãÖhÛ)éÞ>Hã+bŸ&õµ¶ë¢~Á^ÏWV [ä£vçxH9ü¶Pêÿê¸Ó ºèÑdZô¾ƒvëÃÉš>Èekgù›ç@¤=Dü±ôT‚{Â2ôܾûxZô©šIÐÜéîz®óôD—~×+8¤ ºGjœ˜ !â0šú)$·wÍ•‰96÷¥¤§ýšá®i$¨:é=¶5jÅòE›»áegsH _Æç.œh-YfMwÝõ¼©cb±ë>¬gö´‡Áâމ[Íì ”ìð¾`‚”¿_8(i¿F͹Cãt1†µÑapÔ"º]ŽÖ„.T„œù­ö˜ˆc×ܵ•(E»ï/¬&å„Å©ïLK6מ‡˜S£^d]ÛôÕ+¥•‹yì²ÝŠ-$`«z!à^GAÏ(5PÐUb¿ëu=~l~ÎVÒ±¶‡É鶸A— }HúφhO úù_ŠtI—*nûzˆù‡gåüü¿©VÝÊy’Ú÷Õ›ÿÓÔºÿDä\Ií÷Ý!èß™ 8%µ}ú¤ÿGÕ“xψ²þûuçêy^ê:ná±öó8Þ£uÃ¤ÛæyäomwE+ç “ÿRÇõøõ?¶ç]oîmF×¥gîZrõ8·sEóº¹5¨Äö úG¥´ó9öÈ>Ï·«F“¹igÅ\ç‡]o>(×#çžeoÏ<ÄÜë.í 9ÇE”s`ÂÑfó«ÔóÝZò£œ»‡Xç.¤æœ9¥NG©í8²ò}šÂ^®¯[»Àw˜oBCØŸuh\tàá:nFÂâ:Ôìôvpä¢sÿs®<ÈÖÞJ¹A»5@žNÚÈžmCØM¸7cˆù¬i_œ…K1'ÎbH &B”uB}5_ʹǪ5g¼•c”}ï}ôµ¤¶çº2Ûãö|-uç‹ckg¬Úó÷ŒÃU¢”s›³ÚoRŽzõîy>om«çy mZ·Š@D=)åš§ö<õè–Ø´q/òÜœQ‘ l’ÎéG¾ë¿K˜=°¥ÃYƒjã'­Ì1¡º‡é5›°s\ñGP™ed§Á#Ëßh·wô°zˆo'Ù~xÞž£Õlæ­7y¾‰¶ê^Dú¸–»êÊ×]—Ã:ù~}îgÇ]È4x^çq½Û4¯ïú Ò×͈XÙA^/ëRÏ»}ÛÜ¥rï>è*º¡n†Ç ˆKmÌ ŽóÉÉ'*¯õC‡ ³tR¤î\ÁpËŽ4d= º-îVÝc]Âöd%]P+Žu_=Ð X£ü¥qbB¾z¤Ó×Ów‹ ˆ#0Žp¸`¶Á¶’9œÅu拨Ó=wÍ=¦g©òŒ¤}‡ÈµEÜo[»•õ™‹¨Ó'}]µßSƒ®$õ÷AU}ð³ß=ôøË£¢ÿrð¯"çÆ…ÁSRÌ•zsÂàli—ò> úÏÕFíì¹Þÿ°È¹Âà~`rþ©ïŒjþMýÜiKöŸýZûæÃªÓ_¨þñ©Qç=O8ߟRÀû>sÿM|LZ°ð×9MÆÐžý&Ür;3°·ÓYU–ý?«Ç'GÁ©¦¶ü ³Aû*•܇"îucm@KEZ«qƒî+‹¬›pG=‡…îobM‚»çzNÔœ+w#ÉîÆ Íœ3ßHù7A:mÄÕ$«ûRÈ!æWÇŽ| ªúVË·ÝÝ©í[AW¨\•aÑuÄÇÐNMÏq“ïº"å}SsÞ0 ‡¨ã|c¾Uó¾a¯k_? ž£¤Ó=&åvVÉ““³Éú°²o¤ñb®¡°´Ó=ëBJÈ8X*yò„î~⤠: ºI9öv‰:Z+ágF¯AÄCΙ?%œ ç0äŒ[A§ÓÑ ‡[%£wI©×<‡€;ºËSéÞ¤ñÿý¾®Oú‚RÁ…â5c®×¥ÐÌ…ÑÛ¼õó¶2½íJA/´C›šö#ÞIàù[LgÏxЕŒðt°_×QŠ{£ÉíÑÙ„]ǾíoþG?ucèvt”ki&Y°‹êù£P#Î1ô·þ;×¼³¿Ñû*€Î¸½MBpȲ¶çØló{¡ ¡¯p—> ¼ª¸>ÜÚ/R޲N8ŲÞö›—öj¨çmû™cWËŠ' ܈è úVÕMž£œs>q«îœZ%u­£®BöýÐg-_$QÑ×Ýá•äÎ|líN;µâ.’¾ÃUbe÷hèñóú²~ŽÔv¡êÈÔ3=-T:FÇÐr­[­iìöj:†:tˆ8½Ñ¹ø@QRµúæÚ¼¶i=C›5‘ptjÐCÜ+YwFH;JI”up§uÛ#Ïì®9½x«öù¸yÝR‚¢ yDAÒ1„Æ K5§.Ýkˆx“õ”,¯AÊgôE85§­¢s‘¯p©Rã’M ,©îØßW°DhêºÆ¥2ôJ‡è˜ð£L&QreˆxùyXP‡þÕ꡾{§‡ÐëF³NNG9QzCW{¶ ‹b IïTxÆjóÆüQËE–ïuHÜi)èJXqlî/T‡þŠtrÁÊùEÏüâìw5‘y‘ú±´ÿ\ªù<× ÓºmˆùçþaÆï‹œÏÏúÖ`Úº©Ús¯Éž.¼^ãAM¹uµ’ó1¬7þÖï)ïï7*yÝñß}Æ´GsÊ¿þ®äh·N£œ"‰ìóEÌ=îÞýôõ§}•nÄΞ<†\9Õ\O¾ÊF´2¾œ*ì_ŸM \3@ÇçÆAx¤Ï)=uâJÂà4†”ÇÂNœÃã²âÍ(T0Ap—ˆk¢¾ó?èw¾×ÊÞž:t¬ïek_Jº 8ß!=ç³F¥³coϾ„½±ÖpfKåµó¼®Cgm¶UrÆw´ëË“ä®ÌÛÛ·Rîuôܼïšsy³ß–v9"A®CôrôíÖ±\ß(¢œSw®¹@¹àÝNrZ9GD1éV'<îÈÙ·:øà¦,›ûBÈÙæz3¶ö;¥ˆÏ1;,NDºlí ûâ)­Õ˜#lÑ1I­Ð¸Î.k{;çZÿyu×ïâºn@k5ÏøÉ"´ªù†/n'h)•XŠqž§z©3‡ˆg$œ ñ3¯©J‚yÝæ[èL°Rçëf@?¦Üâ·ã’Œ¸ZÔÖk(îJ›5“Aˆ3 n½ÈÔû&û+ºžq«ÞßäÕx§ ùQÚ`ãîe—}!ÿ]ßzðõïÔôXüZª'|?n%¸w?t©åWOt“uÐs¢c5²N½ùêƒ^„ÅÐv-É•ÛúƒªžÚóŒtÿlÏMÐ¥¦µ\kSFlîÓózYÛCÎ #Xßu2Çzµp Ç›D„}“ôJgï2ÛÖ!ç ,픸›¬…ÒÛÜÛÎNÏsáìrzu”s@ ôçÑjSiø±9¿>䛥ÂJr7ñîúóÜdÕ¶r+ÜQÏ ‡Ó>lìôßGžïíAˆ;¥[ª3_‰Å½nZ;±Ý$22}ï2¿rSÇP›~éFœoúÎY×Ht‡ÁE9'Žó³¹ð8(³÷r[­ÖêËqÒ çf%¸;0îtµ¼µ:~=×jÕVí¹¶cý²…‰3Ç$ýF‰?3¢¤ûúsÕœ‡ £¶øtØ9úÔ ˆëëfpfp1„kv£ ºJXÓó\ÇÚæ1×üŸûµÆt@š{Y¾á~%(†HÆ®-©í&Âð¹²| ·Wž§‰|«Ý~næÝ}ÞY¤>XÜîg›z«÷p7¡ºŒº¼¹"ÛVÐÕ^?Ü‹õ îN]/ÞÇ×e7(+E‘⮨Èý {[Áse×Тû±ðÛ¦ßoLê$òF—k€”@ÍûNàø²d”Ub…ðég{› !ç~ζ½s÷löÛò~E]sêWÀZ{ççB¼½ƒá·Å=' mçDPœ•ræ~ '<«æ3ªæ§‚8î y¿¸lHzŒlJ´Wk¢N¢û¥EÎÙ¶ý/=÷&ì!ò±b­úóÔ¥«ÖJ_>È{ôsÅQgŽÕmÛàà’vkUîuo£œkÛ(›û²ÇiŸÏšÕòJtwÒûJrî½pU€‹Í»åÚ³¾¸Ñ<½dé^E\4=c²ž@9­ZÏ…× rÒ»¶S.r.b^ªË9'á]ûú®ÇaÕ¤oo]ŒZ5Çú¹zSljbÅÅoæzœ/¦£˜ÚS]sÊ…: =5ç´fšÇÌš-²g@Ì­ô1¢¨WMú ÖwAs¹É<ªzÛˆ!ì&á:>D<Áqªm…¯°0'{Y#P@Ú!ÕI_ÊùôÜzŽøÎvÕicý.û¦ýá¦ý%îQÃ_¶uÝuè&èÓ>MÛRÖ?xþ9lȹ”ó/J9ÿ‰¬ò£ÈO½ù<ç<÷Ô›K–v)ôós_·âJ%]λ5‰ë;uÝ¿óAÝ9võì÷š÷boJpIà•}àýoÕB-ÁpoàcPÉ™÷ÿ)ýÈ‘ðü?o+û p¶¡7çóäím_£e«QÇPšb§ ㇮œ†Œo¤—9µç`öáÆÁ¾n¼‘óRµ‡œ7n6¦ÿ¹mñªºÛTR$@ÖQÎ=ιä…p¾ÎùÜ#7j…RÎÇÉ•¼ìí”L‰Ø+P4–öØØ…(æMЛÈã*Ëw!h‡šIº[ìš›è]švUÓn+æs‘lÈ»íí†æ‹˜ÓB b>Çh.„€'ôV¸[ýÆQÔ;‡g"ééw[;Ù>\cY 'NŠ»®ÍâjT©¢€¤¸ ÚG6‘„™÷ÙEYäÜ#±Ö1€ôžQªSš9׸u;uçØÝݵ(å + å|ç>Ý%ûôçƒ8¶úžßØJ:=Ï!â»sSìíð„usÄÓÛäpe¤ÃT»¤º_Ñg|ñÇBµK;õÞÕåªÎXÖk_s>ž§¹'kt8Óü¨U8Ø¡v«¿yÕÄÃ%õüÔ&èíÎ\ÒìŽ#âKÂõOPwGÚâý–BåJt=75Þ¤üñ&zýÀ‚]¾Žk’Íïapרÿ˜J)ÔtÍìöeŽ¢î$I,€”÷ÇNªuD…Çœa‚þdi¬»‘ ‘CM¯¸lƒwH:ó BâæqœÌ¯ zZwh´Š»·=Ñ Ž;•"ŽZþtê±*½´{‡‚î‹®µu;Á.7Ë¢œ»x‚rn{ÛjÕFË5ë“|ñëùR‡®í‡½}×xûõÇ-Ûûì×»z]Ä0²Þjú¶j¤F°ñtÍçÂlPjz©2©GÇb¹t+:»]Pê'?’9ˆ:ª’¶Ï.joj˜œTs…ÈUjòòeèÛUIu'Í=kQÔPÑ A_„@éÒ‚-ïÔÐj­lïæ;¹šQÇìÞèžW}zH”ǵÃ]WŒ%z¥}CÔ¶M±Tg_©¾(¨ìMâcjÓaÅýžO|cH4w­©~\ýƒ®Cßj.<ªþæÿ¬P9‘ó ™;#ç®7ÿ”ëÍegWœö¯Ð;z˜{ͯc¶õ¼K¾|›÷‚}9ÞD)á+à¯kͽŸ¹ÿn*Y˜šö›«€°ìëó&ètèþB—rth¢ÿ×å I8Înj5AŸ1 âujÍ©?×ùAën©ˆZ^í)ƒ)b÷MÎ)(å´OË9IsÃûMÊ—Åݤ€Lsiè{qÏ9ýqŒ!è!çSwþšÉ:zõN,=|!Övao¯ð¸!ìiɦ“J»ûA–Í]d\ûd‚¤ƒEÒ+À#kOÑ Ý6&ã8mÓzMûMÐiÃeÝ’îµÓ£VùbápÖÒj %½îCÒ«~ËðqSo޵Ý`ÛíÖL¶=V]_ÊÙïç]é®»þ<¤;5m«’ž¶/7r1ñ檀æF]Äœ{âZÖ›¼S“Î~Öt,vw u ao¯Þè„Î=˜šE O]: ëË[YŸ}>6›ë"´Û±íw‡Ãí‹Z죥¢o«û #eÝk­¢)ÅÙä¼[¯ÍczNº•:[ÜC&¶E¥œ9$\½Ÿ!4¬/ë;ué]÷[-ÛPC&`VN{Ÿ{`Û­q·áBŸQ€¼3Ô¤{i¥5[! ð(ê|öyýþIqW›5i)è&è/ˆ ‹xKwË´³döjÍ¥]ap/9 îaÕ­ÿtZ©M½ùgF9ÿôß›œOBüû>ùµyܯüªMÀ÷ØÇYÇP¤¾Òò£†Cº±µÏz)éq ÿGþ_56 ?èÝŸÿWJ7º¾\7  é`»Qøü0O+¶sTt}Þܘ 8Z®ù³Y%-vCçnטñNrÞᜣsVn ´M›cÛâÎy¯á}RëIp§uÚ›ÖŸwvHÅ™°W\Ê›4JA¯´ö¨ãËî®ï4‘룞çÏ£²BOŸY7›!ç”é{Ï®³ô8×ó@ÈéƒnÇZ+åízÛöÎ1¸>èúNt§[Ìvî-«;ýÎ]Ú·®eΈ?âÄÝS#®ý"ë\‘åC†e‚#„h#¥†q7zNøï ‹ó²n¥Õ÷å¨\5æ§mkŸ5@8q·&;ézÒÛ‰µHúVÕgPjËß3|#×ÓZ§1¸ @ΟŒÀækøoCÈ“3…rî¹TrólŸIj¡º,·:M•KÜžä¢<‡K-~øŸþï¥Äk ¾/*…Q·KÛÍíy¿Ö®O'©½ÅäægÝb­ÜVÿÙ.µ¸ª¦íîJ@ ±dWñ|ÿQòæóËÖͼÉó Ïv…ªí×è?ܲš÷㊈cgÀ²ÞWȼ·+8=-êºbŽ¥Ú,äC|’¹¬0þ »]ȇßsîæ ô@÷É…”IŸx 决‚Ž ^'-ÒÜŸäncõ@7_D½“Ü­œ…)й¶]“N}QÚ¯iMµJ²E%(Ž;¯¶SôÝ„°o@ØSGµû½ÜIN»‘RÒÓbí})é¸KnI¢mYÙóYä"NºIxÙܱ¶©ÅÚõÜY÷ã*Á’N:£a«žçõ]o‡2à1À28ÏE]:mØ=g·BÁÖÄRÖ!ð¥žÄ⸒}Qd1÷ó4!}ÏQ{BÒ}ቲ®m‘îØß5ßAJ„ÆíöE(Vic´íîš?§ñŒ\p¯ÖlÄm²Ž~æBYÛEØËâ^Ûx™˜1é 67uì+[A^(èÔ§{ß³ªA¯vkGL„<¤]¾É7Ê-–xRc5ï^륈·µ]„4ÉðZìÞRç×­CpG-—õ|ˆô·GAÿþXÒ$‹ºêÈö&>óŸ+,nˆø/DÌSo®ý£œ¿è¤öÏ=?apó$µßý_ûÝÇ®ü×zýic–×̾¨âMĹ)¡‘ýl³¯]¿ò}»@?ä°=àoM àî—_Ä}·ö£l‡Zß5è>6äyŽÁ2À-’Zu“íJf_7°PÓó9<v¶=ꆖvßt«ºsÖª†sÅ.‹±:Nö…Fw˜`4Hk_p´T«vj®9×1®)÷úA)Ñ<®zž'„ósn¨J_™#Z÷|ÙÜEÒiÒÉíFHx'² tiÕ¼¾ß|³x{|¯r³{ÁÁp8Ý„ålŽ»ìëes_Ap:f•Å%ç’>û™ãäÃʾA×="è!âvêñ·SÛ]›Þq H_¿A·rޘנkÂó»ÆšoR^×–´UsRû²·ƒ „+=âåŸ×'„)?6×ê„ JQ_¤Ü„ÜÛ„Å™[A¸Î·P'^?˜uÒÜ»|8eÀÑE|»®œyÕ“¶£u™òÃà@8šK Ü®g×¾ÏvÙÜÅÙvc#Œ"Æò3€÷1n¾ÙÈ,ѸKÄá»U½QåùYXÜyAE¬èõD‡’< ìØPÝîl˜ˆÞ®ñ|5zïtÀÛ“ç·æ×åûÏï³ë¼¢Üª{߉Ùõ¼ÉÇw›¨‰à‚ÀcLÎ!æÔ’xͯ—:ú£§.–k€:ÍW - ¤ü,©}ˆyÂàþNä|á¾1VõkùÙy‚Ès÷p÷þRÀQÖwk´ÔüìêÍ¿z•CºQÌ;}}9ææÌM+ãÏuP as§ýô37Lˆ[£€“bn½2Öÿsç6è8æw¬î´J‹‹…‘Ïßv´ìÏòÚNä>”óFû¥ŠŸo¼VVöt¦Àd<ðäÉ:j¤æ|×n$lîr‡vbgÏ<`›`¸Ê¹ïüµ”6‰`G5×vwñ÷Qê¹ÆmiÏw–÷9OerX´Vß}l/•h­··j~eµUËv}·«œ-„ÝD½nÞ7\k¾tæÞ§k¬íÂVÓ5úÇ„}wµ‰J^µæ(é¶®‹˜o¥Üˆ‹QóXÙMÔ5>ukäØå¨4A¾Žœ1½Ï½æ9‚AÅ´Þı ›»ƒ‘Uw¾kÍAÒÛQÌç˜8Tum®õ´]Sïóã¬(Z¨Ú^¡Ð‹˜ Ù‚$neq#¸O·#˨ü²®ÅñŸù~ú£„ÓR‹NÕ]³ŽTï"¾GuáBsœì^¡oð4~·8¢yL;»7®Tø*^}ÐÊíÁ›þVÝmCoâîý<ßRÉý¸nE|‘XÔå£7^ØýÌ5$éݦ½\ÈûA*|õ»«V#Á±à4wÕ „”Ó=êúÌ“ù®ù§ I¯à8.v²{RܵîÀ8¡ã“ñY×`3ÊI”p¸9¡êøÜ=¸kj$(Ž;­¶»{~JkŽ•Þ¾ˆú"îçìZS‹žztˆ:}Ñ=êXjÐCÌ­“˜2~EÄÜ„\kÊíôö(ë÷<~»äÔ¢oÛ›×Vôgí†æ&é~YîBÊ 6Źáò$éîñ‚•îä®Z>ú ; îÔ6EZs8ÜVQ–‚ÞápôC_ëZ[dÜsZ«iþù¹¨EXÞ5f®‹Óó‡æxÍ×­DqqLýy]<ëXíK¸°z¥qYZ»FXM¯tè„„Ça« ±@”žzt«æóXm/“°8“ïó² g{’Ü+0nõmEÆÎ ßðñEÜ(æZt¤·×qK‹íºz±ˆyÃýÙ©C a,è&èC°E´Õ·Üý‘MÄGAà‘—DÖµ-K»ö‹œË?ÖøZ}ÿÔ­08?ß¼Þ!Ì&ÏGvuÈyxÖµ«ßµû”[1wyÕzjÿAÕ— &îü QÇõ^ó·öÿ̾ƒ»Â® ß̉KC£A™EÖT?nª+GTuùêg®1ê8­ ½zsÏY×Ü\¤ü¡'Of„”ÒJÜ jÊK9×ͼ¿¥¥ã®5²½û¡CÒiÉq×±*Û¡«…opj4YÇyÄùµÎ±‚ÎËæ ºŒéª¹óÕï|¶QÌYKÍy}Ç4Y)G9·¬Ú«=`'Ùì;妵•tÍeqWÈjßäVÍM²+ NóÀßѾ™I¯26ݸÏÍ{fé3™574®-D¶m_'½½AÿsH930ûBÌ\cŵ8$|Üô:ÇÝhk»Æum#ÎX)r¾Æ?zìzJ##ôh>„úÕ\cúºóÌzmwQ§÷y©æl¯ÖÃt>‚œÇqZк”uן#šA¿`(±P8\²‚ ¹xÄ«ÕV-û ‚ž¸¦‹³µÒ»K~…݋瀌w–Y œìâűÄýô\o‹àzþØJŽ=Ýc‡ˆËòP–Ì¶Ž „Çñ|߂͟ywPãw6AÇ1¯zk»^K¼îˆ$z¿ÒëxÑqÈh½¡UßþöÏþz=O½‰Wás¥lï;XºýHùgׯ;IšóÏGBÕ³ózCî*Ð`Âäô¼ÔšûgùCG]ºîÆÑjAÏA˜d}滾ÅclîÝÿ\'Ô¢sð=¼¶’Ý3wjå:y%tn%_FA×zYÞ«½%Bã8!wP\ö•-j…Å…¼/å|ÝÍÕÚj·ÖÀÒUuè ’KàÊlçËÏ„žéØËêúA=Ù¡q dž ¾ø«íšÂàVhœÈ»kë¼­‘„wwÛ ¬|Þ‰º.ò¾¼RÞQ3¸ˆzH@5×úVÓ»ºUõç²N`ÜûRÒ!í\ ¾I˵õ—©7oÂN@œëÑ!éš·zEt{Íë+ô©”²'D“‚µ ‹¬Ÿ_„!DA0€@˜D[U,ÛûG®Þ9É~öAÌ—‰²8À _Êæ²£®›dù1oÞBË­¯PÙ+, RXiáúÙ&ñzž&’MF5ú1[9æy¨;_ ´ ’­¾äçþê[coý³?ž·ç¥¬‹„+ümæ/ª}Ú¬kíEõIw½y'µë¹ôøù¹&Ûó{AÂA”oö1)‡Ø»>Û>7/ üþ+)¿íì¼wyŸEäó·¢=ª9€°£”S.±’Ø &Ñvÿ–óCÛ‚>Qȳð[ÿwFCÒݽÏu侑¥}d?„ŒïΠʥ ž<õæ"ßUwÞVvÏ ‚KZ;ç’…¾ è9Vöª;‡ W­9™œûâ@¢e%9Çê|›sòv4})8³¼»ÇlpI…°;N7pÛê¾]ž³F¢»ÆMÈÜœ¦Ì‹àTH8%d"Ù—n² ·{ïaC{z)è÷Y-‡˜_ÁawŸ¶ÔNýyìíW¼ŸÑ*zÊíV8œà½”æmabgð$n‘q‘c€S1×_"Ï™´TIÌœmº 8¤Ý¥©I¿ÔÈñï}ô5‘ó‰´¶j醛 '±Ývöëµ6°%«;Û„4co´@ 3‚à:߈ŽUÃDÚi¹vþ°­X[¼á‡[¢-ü1¼ªöƒnâ"õ¼¦æOÝ–­øDšãš"؆Ãi<~ÞÎ2Ë ]êͱ!âËž×{.¾Wõ¼^ÜzB~$ø å}Õšwaþ"÷S‡P‰îyîƒçÂþ”â¶w.ÚÐx ê6ú ü¼oüó®÷+Ûy]7ìà÷Æ’Þ5ãÜà8¬÷÷ïN}¹ÕuíÃí Ç—"¢®mYÞ[A÷ßû>^ûQ÷:íÔ çb^ë(á$±»š »°œ#¤³£/’.°­±zœ‡°ëœB¿ó(æ}ŽàæŸo†¬7èBQ¨šs²74ë†eÚ©é\»jÍ™oì^çžSwŽb>„ûÄ7^Y«pÐyL•FyÒª ,›œcmw]z×›“ÅÒmGËâ®›Ùi¯i?5‡œ^97Y_–v„v“p9ër]¢®ãPÊËèb_?§ñé"ë ·ÍuNë$e]ÃmHÀ®¶«¼°Bâ DÒÛÝn &s+ë"Ø}ÙoëÉQÍo›'ìÍõçØÝÅä6jeuŸcÊÒ®d¶ŠùºŽ®p¸w;Äyv‚âV kúŸæHqÖ–оÈoqøGÕM§yõ §S•¹\ ´ …C‘o®… —#œŽŸþ$g²Õlçná é‡{üÜÃ:sjÖ‹ëBºkÞh.WݺpUÓWýŽn¬1æ`¬è›ƒ&ªÝx¾û…7nÿOCýB{÷oÛ‹NãÂëŸÃ6dþøoü[ª™ þýZZp€°ó¼Ô.PW’tw:°õeöÇÞNpÄ<õ.•yÞ$>µ2©9_©“„Ã.’p¹Hº¶± íôÌ&ê;yÂ.¬¤ÎõjÍáQ6,Èú²¹“ÊZ·Z ’LŠbËWRJ!ï5]ZÛ ïÙg Aq‹°ËîŽRøB.ÕDü™‹¸7†¤ÿü…?úç!ß?«û¿‰¤Ë?­Ó£´Ïö¬ÿÐapsœ}Ú¨=ý[{~íÆv?rÂá åùÙœ?•‡q¡Up‘qRñ©÷‡Œ‘ÁƲ.PÆP5æ)Máu‡½ÂIÎT²/ap©3O›?ÔîMÒu¬×¤Bß9K¨\u38ÄÝG$×› çíì“jîõ®/ßjº;3Tè[µ^œùµ[§¥ÏC;ŸO¶['ç›G ,ïåJÏóo°/V÷VvÍ9—1×øâ¼%HÔ›kìs¹÷ Ÿ˜ëè5ˆxVkmc§ÞØí•`¸ªGä®p ”å½®Ÿ‚ç’ÛÕÓ|®ñ§›û9Ë_¦DíbK{ó ñ+Tv¹òëëŸå^£Ê𰺯î3›˜Ï:sð(èOEI·1$úþû¤´‡°³m•Üã“"ú;NÐÜDœ’G¶·r!G=÷úÅ=ªáûO“ta‡Ã™|k||î›!ës/<6uìîQÉ5âL'«Ö<ª¹:.¡œ_§„Õ!q:.°Í=|àˆl.Q*p”ÛZ‡gÁé éUS¾Ž çÕ^m”!êr;©×û:´0ÇØ-ÜŸó÷å½Â¯­®`Âe|WÎñ̯”Ýú’fôÕŽÍó ÕwærÛÁjô'×ëPÚÁ±¢ÕgÐ<ïAMûú–£ ë:Ð`“òÞÇûÄ Ðÿ ´”ÎWu%•ê¯:t­„Äñän?áë“ m$´~ôôÐD܉îš7DÆgÔÉ›кã ÔsNמŸíô΄ ž¯°8·[›‹£ÁõçŸÜ¶‚NÝùî‡n+Á(y*ý#-Kh¹F‹Xܸèj|Fí\²Ö*:¡1^÷ëè^v÷ív3æ‰ÿ²»Û²Wiîé“IÇîN;©ëØ VÎ;Xn%»—½5ìî®QfRŽÕÝx…~»º9%Ô¨AŸ_«åKUÒºÞK(#6wnˆ7 ï¤w»õƽþHEâ°½K<$\ä$J:¸ ©Ðñ]ƒ L€²r´È¹×IyGÝÄÂNK¬"ê´dc+;èx”Ò¶M÷ëCö!ÜEÈÚ‚e ûäú;ê…>D[mѾ/Ûúà_Ï?öÇ?Q‡¥}Âàžù7£œ›œÿmÉŽ·—%­ý BÈϵ2èQ²¯“ùŸ±Š^!‚ù=’]À¯ !Þ]sÞÇ9gõœ5;94ï€8JLøÆÃ­Ý^-Í^J}y^G¸£Ö°·›dûüðuàò`.¤=ÇQcÞøÔ1VÈå5•9³ˆ:¹^—kBÎCM‹û:³›I# ùZžŽu-ðšP½ð5?ë¨ísý¡É׸ÞagÏ8X¸!ãºæÒ]×ЃÔvÂZ­Ž[1A×mT›qÍ)}³ õ¢Î¼}"ë‚kA"=Ï5&Õ=iíÕù†ÖµÜc!Œh›t¹J› ß\=ÏåšœRÈ„S¹bN;5Ïð}/âêù®K ç>Xs•yFä²=ïE)AÌ[ (EBÊõžVÑ­”“æ®ù&çp‚¥¤:Œ/]SÊÛ€ÃõûG›lÜÉ{ì÷,TÖû#QØóâS8¸›Üwð÷æ{tc‡eù_\yo˜çë„ 7ÁDÁ­c*` j°?t:hË9_·mòž—jÎÔ5ôBšï—r^¶ÝèþEæ«Áü`­‘Ø×?×±Ía·¹cô:£]þ烌Â#GÌ«»·oøIÝNt÷ëVZ¤kα»S7CÍù¶÷¨®;Ï"âkè5žg<=JuWhÇÔé$ A/P‹nü@ÛB+èmiGIŸ‘·MÞ(5½Ú~P»»eeç5XÚ+ß7lEoÂí8ÈwŽ×Ü »×æg;›‘¤­»5_ýMˆ<3²fëyZ«…Á´ ÜéìÀeý{[*ùô?Kû®?OÈ" ¹G@È£ÿ¿³ÿé(èü¯ƒ<ÈÓ9# :e3„Snûúk+Ä’ódÜ."ž6“ôCÐ5fTiÑ×;.£Hx‚@Îï&Ï[5¸®^ È8Ñu¡®?u}BE_Á¨z@½c›”/[{¥¶GJûm?Çêžëz9ãÅÞ.%žímÓŠ”'|v)çÏGD°¸9bWSEÝkqjÑo…¨CÌÝ:í4Ýr¶µ]ÇPŠè²Cýf½“'»õ.dœˆœ»·ùˆ@ !!é¾9Ê96vÕ“‡¤WP\2—¸¶û4Ê8#ap"àÕ^íDPÜ[šÓúø¤jÏé}îûz o”¼FIOùkÄÔ&è Û¯ +ÝÝnlˆ|íj=¶ ‡¤µE½¸ÐÒÜœ%°]ªúqCœ´½æ=ÕÛ9gU‹ÏÏ,”º¾,þiS×b.äÿJlÖ¤ëÍ‹ ¼ýAtýu‘]v×ìÞêõý¾ì_d¸–œcêg©~yecoT“ý¢ã=Û&¨xþ9:I^XIîeiñÓµ±p²Ñ\Ÿå|®ÚºÖ&Ä]ÄܶŸœÐÒ_=)ﳆÈvøÎa;{Úch¾N²Oð…ûžkß²:íök7Òrí×Ýiß5R<õM{]¤dׂ¤çâÅ…«ðþ!q@¯O’;uaZ_iîÝ^-Û­ «:ñN|% bîDY,wØòV­n&´N‚{Õå”ûñ¿è›"Ýìxß) úêW‹]±ðê¯Ù Ÿp¸²¸{Tú;­}DÈ!èî™Þ½Ñ­˜£iB¾TtÝBÚ­vi_…ÅÉÚNŸtz/Õœ &Èz%»£¢awÅöN4d½ :°JžD÷wD,ÚêÚú«× yиBµî†˜¾uAŽLžŽHÓVHc¿n®5Žc-ÛÛή}Ìß_E'|^÷®× ”—² aµb®±hj»‡ë©ãÓ«üÛ²¨›tO?ô燤K%!WMºæZ{~,ðÏý¾Èù÷æ5>þ3¯Þ__»ˆ:½Çµ?óXØëµë:kýóègM ?Ÿe©æ¬y,rÎ:¿~üîQÇ5<À¡oyÁVø÷”ܾÿÖŒ«zr£Ãá\ÊÁÿEú˜çÿç%<Ü2øŸÉvëC­™˜ ç:tÿŸ¿nBž„öüoëu™œ ãò,‚•º^½Î½÷ùÏç;ÜBìר½Í=EÆÓjmm_’%âs»¯[=‡”cq÷~”ñ³\cq~-×»)Ͳ}&t«ÑÝ~tŽ1‰Ö55×ά%Ï%eeý€|°á2¾Ãuýe¿g? '0.„<ã®C‡¨?çÛ'„¤Wbûm,íUƒnÁ·!#DácF”q\!rRÐ…¬‹ˆ§ÄQHY£óˆhÅKÏsæXÜW0\¹7i¼Õó¬?>d:÷À鄤íšL»b \¹§IfÛÀÁZŽV·SûÒÅ=:÷%È”¾Š¼µ9KÏW2û. v[iDYê¥Ä׃öÝÍx¯c>Ô¥¿Bñ®R¯›W¢„óýÑ= •[Çñ³ÃÃê!RäéõÞŸkxu‡°—¹® xÙ-µY(¢z ¾óÚZÏZ=]˜í•Ö¾ÓôÚ–Î{£è÷‡(¬'*ÇÖüN-d¾QŠþ1úûìzøË\ üñiôƒ‰±Â»%Ûjµ6£þؼæ4÷&êÞ·O´xð‰‚Š·¯‡¤Ÿ l/¿jor¢ŽÝÉî«.}€Å½Û­y½-Jª' Y·jbŽÕ=ðÀO_«úºl{»¶•à^Ö÷¶j¹®ÊÛ\ÈBÄ…çw;¶ÕKÔí×Èzȸ±¨êÚ.¢Ò'Ýêº.š7ä"ï5‡Íå‚¿ÈyÁ넽L_ô…EÈi9S˜÷ ¯ ž¾IBÙÐkPÔ¥zh®›²´\ã&l“ø¾©IuW:°Æ)Ú Ïê¾`e]dà8ú !çìÇÞ~lï`ßlÓGv+gIsDÒ£ªCÖ·J'Å<>„]kcÃ]]©‚Y_ê:}Э4Ë2!§f¢Ä>oC̽-"'euö9›uà5BæDþûÍ ‚þÔoü­z˜ÿþØØ§Æ\£z›ÿÞßZþ½Áwu¬öO°ÛD»mé ?x(U_Šùzx@ë9ÂÝlíø˜Y3Á&¤^äõÌåV¨µ$µó¹vòºîü^±®·’NK´O©5 GÙÆÚ^s‹Œ¯@¸»¥œÓŠPÀ¶bÎ6]- K1Oð›C!çÿÓ…ôrÙ ÇuR;hpN£´‡:ô8‡v¨&}Gᜯ®1®' $¯ ¢Çê®klW/ôrd!Ÿï5A¦WožÊåUýÙ? w×;‚QWy€M7” Š[©í »ß¹É´®á/¤¥ªZ²ÎÚ¶»§lm`’ æäÚ@؃ª3Ob;*: ùÜÏ€&爈r êZ—Ëñ°ûŽH¸Ë)×ý ç3VÒUzùÅ{çs#®Í÷ŸÇae÷6ÝÄzöYí®èVÆSwÎ=3ä\kÇaÍ¥¨Ïk;ㇾp‹û ¥Ä‹ w‹5\ÂZ 'ÑvÕ™׃¼G×°²Êûµ˜™ý-|v†X‡Î !Þ<hðu›Ë²ïˆWb‡·]<؈؊Ëü¸þJ}±&‹ýAö1±šW¿q@ÜëIÃòç‡L·å’‹ëÕÛ1ýï„GZ{#õ­€óõbëÐq½¿¾ÿKÉ¿€Û`}vmo¿Á?eÆ9að”w=3qßÁ‚Ö5ÜÎÜÖwÔrvôE7y¯ž‘Ô¤ÖþP“ž6k²º',Ί{jе.BÏœ gí!ês,T†Éx¶Y¯¸ˆDQ×1‰Ü6É^-Ef=O•éj’ŽÝzóÕ~-Û²ÆGIz^!q¶BaÔôW0³p‹»ß U=JúntA}]eß[6÷F+ë­¦£œïzs©èQÌ£ž«1ÖöºI¬¶kƒR`„ª}ÔȺpÐvuZ¯QŽÊ„ÂD¯t[ÚËîNK6ųnXe×èЧ¨cñ™ë½'ÕýеªRø˜³?J»C¬šhìjÖ‘Áá¤Á Ó¾ôR7ñ9ê?}Ë&/bå}mk×>o·ÂáG‰ B»ÂÉØ0Ù¯×A†M>)î }ûè¯ëüÉÏýÕ„Å}WV÷ eüéß~C¤\„},í§uÙÙ§Výo†Ôÿ 5îØÍQèC¶Ù_6ø¶àdôCŠOÝ>ÕϤ×-E¼K’Ô>°…}—˜ óû¸»ÇOÏC!H¹êÊ! ñŸß3íþDÔõºX×ù{2a‡ˆûïÕk]Â!°nŸ`:Zª¡  ýÿóº`µý¥AºÆ`ð(ä¨äî{îJ].Ã>WŸÙ¯ó˜Î7!ãvTs«ëÌ—z>ó Ûki·¶Â>E–©9¿9ÂM:»Ï÷̱¾W=9ד¶µ ^ËC⇬½RÁpB9ÆLÖ»ó Ä=*9„|Fm“ –r^èëþj±f{{Z«¡ž{Ý.=Âà áEÐh[n@; †s=úVÏQÓW®ÏtÄ‹@9ö ÉJ‡ôAok;dÜÊ3ã–ï ˆËœuÈø€6¿Ú¯1€vlW¨Å(Í©??Ù®Òl?¦–Äûþ¢Î}7°£Õâ÷òÆNo×ý¿»ò "xOsÛÛ/ËLÏñ&ºÍµZQçøJc/U½¹!à½ËR>ÛÅ7rÿrs7ŠýÛ-^%Ñòú~ÀuÞ»]Öåê†ïBÐûÉ 5ÑÌMœù zÖe½ð;A“ÒÔš e§7I­tÁc z÷D/TW¿ô¥Vç{©×è×yŽEâ VŸõ>æò¾èý¦ÂÖv,-sþÁ&é¶´CÔ©Ao’Þkms× ‰9,B½¾’Ü QÍOmuŽêб<™œ_§.iž®æ$O2¨ÉúRØIå‚¡}^C5Ÿ‘¹×W0ÊQ ºÃæÈ·ÐéìB©ç¿¹óArú·ÿ¿P̽/Óp¿49×~áèÜÐÎJhóššsó9 b¾ˆ:çÃC{;çR©Ûž ç<°²úœ{^%O•ëäv¯ÕµäòÃðÓt/a­ƒáÖüb;ä¼Áuww\‰®I:×z²hØÞý«K9WoôlïÎ2öl sïëôö[´Ÿu ¤]i¯zsokD]Ÿ¹[âr¾É9÷v¬UÍyÜ–VÒ±»+ßr~3#*z߯:0Žd#ý‰VÐ‡Š®c‰S[5Ýk£ÆG8s9Z=§î¼P¢]°8I•öbq/!²-ã`‡m×þâ—!ÁNÙ‡HÚ¶P™a…Vþc—-=Ǥž!´ká3¨§o1µùðæª¸‹óYT©u8ò•"¶>‹ƒŸ@ÔÓeg€Ìîèyêꉃç+¾Ú‰ÕOÒ]í»ì¢Ÿàô±<¹àµ­‚“´Î/·Á×á«zßýS(—C¥·EÖŠ7½­÷Ÿ§lIsÿÀŸþoì1~úq§ß¢-éÙän›;ä¼[­au÷qóýXu¿_!qªi§ýt?Ù°&uàÇÞ'r]'oAd=i¡Õr (0ŽZtˆº@½–-õùÌ…¨ž?=<]~k˜Ö–Å] º/Ô%¨ÞØûó'ý›"郿¢þ!ãƒß iÿèoþµö)©½rZÌ-RýÍ"Ô¨ÝË~žïëÀ9uÇñ³ÕÏ} ø¼;3À»Zö(Q:¾IºÉ·Ë"â¾ø´,æù¨â×Ç*Ópë4lì¶/‡ˆ»È¹ ÿµXÙ³FY ä{;_RoζæþïŽ;½s uåVØ3¾º]š×q-Éážç3áFEïö•sŸçµÎ¹Ö]8|n'ÍÝêø>çSö´3I¸V0byaçÁ0DZ¶ƒáÚÞ®ùn©fëùnIêÒ°MÈéyNýù~(Îu|¶$¼Õól—½½jÎÓj @ :BÃ"èÜË$w‡û Fúž`ò :åDIDÂÓç<¤Ü„]÷Zõç¶· 9·R®û6í§µÚÍ´é%Õ½’Ûo®ì£rÃÍÚ²·û~·Hº’ݽÏç~×£ûƒ×°Vk5úVÑ?,.°ËZÞF $ V  v©ÏEŒ­Ãé¾%Çr„Ì-R¶^6ôÃòhø䘚ùv>s§¸ Ÿlo^Ûp¹¶/-}† ò¾áëçÌüJvhŒ]ü ѼIv£?ðm9è|HMV!öÁ¶Á3bcG§A>6„úà qïtx·yëhýƒ8ý¶ë{¼¼o|¯÷¼Síy $ZtÏÝ3½Û¬ñÏŽÍ«HtêÐ5^jºÖ Àð{tPäÝä~@²û£“žNŠXÛ±åi¥Câ÷à©h‘tÈyÈ:ã jÏ©KRÝß§7:¡q&ïEÈÓvíY·ÉÅŒ‹˜ ýslYŨó29§lÙÑ2W KujÑW?ÔÆ®C׸֨yÛ=X3^5qÏaq…²î¶4ØÝËf¸úÏj¿o¼°&jQHáJîEQ÷{í>í^é(ì&îz­nÆnžÆæ®À¸(=!í‚ê,Qïy''õ86wêÔÓŽ õübmuR™õ}Ý9[êØNhöM~Z-(å±jÒw{'lgÍaVQÒï’ä¾²Ìê”wHŸ&îcR¶Âº„­¬“øî1Dа/z©£ØÎ×)²èÞÙ {X$_ê¼ö·ÒÞD5½H,Ä~¿vàþåü#¿úêôפ¤_ØÝ?ú"ê3>ñٻ矼ùß¼®êãI>_жFÂñDÆý=°_ĵ».HºëÈQÈù9ƒ¼WŽ)2;6u’øÝ&¯Ãß8®HùRÁÓ®”vTö8>¼¾”qAßµæµ|YÙ5*ѽÌq•€•ÊŽZŽš²~¨–³nUýÚ­39o±®/+»ÃâÈÈàá!•‚ÎK º|ñÖ)ç&ºS¨æÓ=ãÆ²´¥µëÜëò¡GDÝÛ:×V­yÍŸã‘pÎõ&ÞÛÖ>ë¾vQO¾Iuñµ‡l”´E)Xs -Ô ëZßk*#¡]dþ´jÏÓF-*ºIzJÙ<ß„<ûh©æŽ/Õ &á³VйÏÈ}Û.ÍË>£úž¯jÊâñv“ó­˜{ 1„ÃC<å0`€¸ºßãÞ‹;x 8Å=ƒºíZ9–ö£’lûž˜í¤¶kMê9¶ö„Üçž½ÊU?øù7!ê}ï¿Z.ïp´vð¢ì“؆°¿8b§‘·0Ú\Þ‰#Û¥ÄKŽÅ¼„]¿_ ·B9”û{ÂÉݳ€?Ÿ¼OsÒpPBÉéµnå¼¾>|²8r¹±¯,ÒLJ‘ýü=}@`HúV€½Þ=Û˜S·Þl(ÔÞnP'Ñk­|g\M‚ìç—Ù)ëmÝç‚õþz[µ—µBðH=zZtÁí4O@\ˆzR!g?'ƒÚôVÑ Œó8ð‰ÊdÜ'*Ö4wôs=ˆíÒÎSͶ¼Câû¤K[ ×!ÝÒø`«é¶Àg¿ñUá Û{ƒ§» J¼Èú?ñöÅ>HûYÕ¤sãI5½RT© £&½.¸º ë"½Ÿª»î¬[´xÿJv·­}µ_ÛP›jv8Îà’ºt¥V¸Gú¡b^=j¯žÜ׫»I¹ç¨-®Mß¡BÌ–vRÞKIÇî^\ý!æ¨æV°²Æ~Ôv,ï´8bÛ©Ì!æé…Îøêy¼oöµ«{¶IPõe‡©èúZrÊu}zˆvr¡‚¹Á®&4μ“ºÓn«ãškß±ªAl ¯ñSwNEEàÛÎýÍeùž5¯c™‡$+©ýÿüòùã¿ôµ!êß8âs¯Ÿ?ùÙ»CÊ_¤ O«±·ŠƒE n è Ÿ¿Vüqxl{?à=©ãßî„ýÙïp·ª9_½î·"’Í6‰ë™‡6<Z£ Ò­äu„!¶rN€âÎaˆe‘òÆkÔ˜G5Ÿ×ÍœàÇn·¨m[Û/éuŽÅÝ$f)—Ïn±¦9Ýd»Iù£v”UԽϱ¸wˆ'Q!ê&è”1­¼‘¶ªãι][}¼ñc’-ò«k_'¶ &æŒ×IÂâ(%ãº:ös¹Õº=ê ØÜÁmœq³bîuÏ)£m+÷±·§œ.÷V›žæ “«3ë´¦yJû6ÈèÉ}йŒj­ö‘/Þó.G—)ЬNXÚ\2¿PÆï§Õn’Û VMyu«ç!æ"ÊÛ±IXܶ¶»z²“V(ò¬YÀ"{)û4 9ž6Å_6‘? çQзӕ’UÚ(Ÿà”K;$}‘ÀâK ÖÛâ«Ñ“cQäÛÜí°y‰E¼…Ûxí-Þî>ç|}Ès¿g=x ¯9¨íê#¿·iöK·µÖä¾íðôAGV?j÷UDUâ"¼<‰ÇÏOÍú9EeÞ ¼Àɯ&òÌymÈ=d–m­†óº²Û—r]ö÷F[Pq_L]'±ƒÞ¦6‚ºúÕF=Pys)ê™DÿÈ_|KÿÔiÑ@‹­í€'{Þ>¡}D’¾Ãâ€NbÛ:tÒ֡ǾpOÄ}=Ù\-לÊE ¬×“U°Ÿéõ¥ž›¨?Ü ïIv§fŠZ©Õ>DXä<§Ø¿òô™Ñ¤;Ľìe¹Hf¨G÷EµÆ=;O²¯îD×$» <…Ç>ǼkâöM… },ïKócb.4ùFÅØ>±"¶êžý:Þ6Gß´iäÆ-¶ö"ãï–¢›G9/‚^éÅרÚÚàj@÷¶%>k¨æªAÇÒª>êZ7 ßIˆæ¦ÿXMŸùn¿¦÷ÔëQýšt@Ä=†¥yyˆú&IÇàXTR·gÓ˜vY ŽÓq(ª»¾Ý$¯‰wúu«ß7Ád&÷­è2Bö™/@œa^mÉžÿÃ:ìo_ôüŠHú«øðö§ç»óó=(²¼˜`çëPÿYgÎèÖqôŠq÷ÏV$¾ƒÙx`á±~>³ÞßG ê^_仳¨?¶µ]ÁN0¡:hÛÀA ¡ÔôXÒ$‘=N‘OÞ9Ó¨ý‚Öå,IýùÑ­<ôZ¤ý“·OSnÒd<®Bà:$Ò£‰ºë wÏ.›ÉÈ:6uBßÈΈÛÇÖø”åt2»`{;û(²=}%¶fÿÁS¯ŸÇ ~£¯9](‡Uº~Õ™×_·ÿäÄõêÝßüê{îÐÕ‡eah©¶`µÝĽ¯×/ƒg&ãk»CeEÖUîVéíÆºÏX}Ï/Êëª÷yæ ½eOCsg;÷H"Òq«å²¡s?Å}÷d”$†ˆ ôêܳ‚àª2÷‘÷¦«s[ÜeKIßêy#÷Ð[Èhµ†ÐlUhbe€ë•±3¨ë’äÞöòÕ¼¹XÔb8as-@Ÿòn³½^W }‹—.n,÷õ}_Ò,ß;J4œ«ÜÖùJš·ª-ù½n÷ ùõ?|­Ï—ùâÛý`äʲ\§çÝVwyºá…˜ÿ"Ú²]ORêÖySMëw½:#5ý Ÿ+}õŠ8S“~øÄ©ÝW°Õp¬!ú<Üì¿4+ „Ü#‰Ž~ÊFý ÿ䬅˜Ÿr¢PÈ„æuëN¡||þ˜’Q¡q<9dÜ/2aûä§¹Û°Aد—’ΓÍRÐëÍÏ é»ÝšßcÒSÕRÎ鱉õ‹ }Ò„"<ùg÷4‚[VÌeib¾ÁÏÄÆóì!WÐËj“¢í­¤ŸV}Úó^ÃÖΞííVÜûÆAÛôI物nÅFmºop­G€¬Óÿ{{×R/ˆE±I;@E÷|v+0™/RîuêÑ«W/ÛØ5mÑÌͪ¶ÝŠ-JzЄÜÖÒ¹ÁöÍ/‰ïÇu¢ “ñŠ£Ý–×̧ý4êœoú ’ƒ¸ï*z§CÜõuMÔI{‡œƒEÌ_jU²´j~»µ w^£}]Ÿ~P—¾Áx­ ßVnýuCQÌiéVuÐU8D3$ÂN Ú¨ân;öÌï}úÍÁ_œ?ö ·†˜¿,²>)îß›Ÿ9mË à]û^–úØÝW {í Pà!ɨӬ™$wŸyö7áæ³8>–ZôNî÷v~÷ðRͽ/·ûïlygü„ >D=',‘ý¸N6)×Èœœ‡÷²e&ä5æ+ÅÝ%,(æ!ä!í`…¿ <®6Ž8vtî §æÜïNzMó†ÛçK­K)G1•ÀÎ&é&áQÉ«”IˆCjÕ–×µÂðuˆ0Ò½ÏEL°_Y— ®këôU×sýkÕ  n¡æép‡Å XÜ­”[]¿Ã5„€Ó–õ¹}ŸPµæAȹÉú"å[M²µÓnÖÝl Ý—ÌvÂß4ž’`Ò÷R‚kÏÉÒœÑ%ŒÕ•»½: @ð¡ß9e•Ü—Òmè‚XŸ‰¼ „Ái}ן ÛÚN‚;e¢»¤Ô÷Üó™tŠ»°(æk^p  8ú€ƒb £EŠ!ó%0¶ª¼úû} Z×´…¼B×àGËr_€•¢¾xϼ6ïÕb,Yi›3Úr*ñˆ×nkü1wÀìOÞd¿¿ô¸ú§ÿ¦cB¼óýxN-|c©÷B¶ù¢.£jëûÛvt”q¯WÝ8ëyhÖ5j­æŸa­’ûŠ9d·D>Ÿíú{9Â>Ž¿Qÿ}¦ž\Û¤Ýdžt¥²ëo_k„¾Qk®ÿÑ(çÀDýý[¨½Ÿ‡qÝëpN˜¹A+µÝ‘:ô´P³‚¾ÚCʹ£´vŸ“HkÖŽõçQÏ ˆC1' dà‡ 8£ÈÙàüÿ±›§ºFè½ì¶Z=Ð&ìØÚi£æ±BOg\y,_Ù×B?̦Þ÷ $µó_ÛQÒ}oaÒ½ÉúV›Øºñ½Jœ‚•Ç“{&€à¡DöØÞ3€PÍ!ãRé[t¡“$^s@½yå·ÿNrwB;6wîwÉ[Zööv™F!§”TiîóG]”LÌ%œ‘¥ñ:6wÅq¿¿Ü³²»—Ê{ ¦šOÊú&¡q5¸ùä|½G5^_ ì²Y½¸ßs¯Õ‡wøû"ó9òšJ»Gî–n–w“sZ°™°ëç;¹¯í²€2¢¨Ïö²–rƒì핞LÍù"æ Ú'­›÷VÓ!êRÿB®Ý:Í\¶Z‘Zº}ƒðªm¹´ˆÊvȈH}[|»]¯Y„}%ÀCбÀw \ˆ×REòΙ·mE.‚×ø²¾g²H¿{iˆÜV¢!Ћ<‡ ?ó»o 9ÿ³óüô—Îâ+ÿYï¹Uíýz¯ñÞª¡!G©æû¨èÙ.ð5úvÿ~oÜ Œs„ÛõÞ´?«‡'¶³kÞ¿³¨Þú]¥%šæQÄ |ÛŠyÂñ(€”«6]ãÊNPÝy¹@´¯ß*“a·(„„/Õ\ÇèÿPÛªkOKµý@ B^Û‚Ï "åô8×q^ëöjQÑ9÷th¥Gû:¨æÖžsdÁ}Ω9Z.PZ$`yLÄyèJ¨3A?†\[_8y`2NJ{·T3 o ¬ s{HËpšçº™ké"èH;%h¾¾çÚ­µ€R¶³twÁiG‚»È9!´yã9÷(r÷iܳäÒÛí 41 &åì?èª³îµæžŽ¶¹7ªç¹DîoÖ} Ab»îWÉdÛecO 5º Q~©u‰PÝJx!]÷ń݂WÈù¢šË²>ó‹²SܯÓ옽à$‹ Kë µëp‹JïVÔÅ A•ÎÉßÚÊt‹¥%ôš“í®‘÷׃ñ3•å]Äú °»‰z§Îw9€ÀCÏ‹ˆ÷öÎZëº÷+]g½lê"ÔG¶Ã®Ÿ’¬ºl¾ÆåýãŠ\—Å= 8¿"ø—u¢I}Gßg­mìñjOPß×NðkUž’ëåL(ÛIæGÁ ´WÐg儼cw¯Ökë Ž•óùºCú!ç<$<Žùcs¬ÆÕ~Â'6Ž?©“¡íAâHx‡ÕsÒ7±»w@m×Ò†Ãcze:$„'¯KQo›=9]/IÏ|. RÎsáA9G=×XO˜EÈe !WPœà8]0£¢à²,hºxv:+óõ®G÷û뢽ì캮n‚l“_=Ñ}Ãñˆ°/{»×l÷{'ê‚F¥áúǶwÍK­x¢ŽBº;a>¶¹w!äÜä~TZ®‰L¯ä_2~ÇÍ&!GQ’vhœSܙӨ#ǬÄdÒܬk¤Ô*zjJ»> ¬“Þ!äzÿe%pÊ_GÚ(v™0ñ àJsˆy…ce^i×;û®ÉtHºÖB°Jõ¼Û$½IèÔøMê’m¡/BH-|©¾ëýŽmò!¹¬%Ík÷½óþÌ—¦Úa5r\Ð:$¹¿nH»Áç×VýE¶3¶Î>Þ[sm¾n…¶éóÑ1GVvˆ8dšuˆz?œRÍ?õòÃø²¾ïZò÷ŒÙ'ÄÖþR—_ –7”˰PMX\¥´“é@ól£˜ ÞÞ¶õwü†zn@äyˆ§‘¹Ý7RÆ5_ápQßÕV眗.³´¿H¦FΉ(çk¾È8éìÁpý0@Öuþ'Îï™ó¾ÆBøwDÎYËûpm Òû<‰íu½ÞŸÕ!ãBr]²­}\ƒ‹ /ò­ãòºÛ«ÅÒî‡öUú¶ç»SÌmß[DI×½…îGRsþôÿQv¶9v\çæfìŽ +²$:Še[6Œd1ù„J’CRv$KÎF²$²†œa¬%],jùQ8§O÷½óu§»««Þz?{éyÖMʹW±ú=ÎÁÜ÷$Ümȹï·Àµ…D’ô>÷:Öö[úŸß×=¹Óýߤ·kvVøÑ(»;êù]ìí(é•le'¹Û ciï 8#áËt©çÙVΓæ8[8“ržŽKRÔãš… SƒNæÔ£ê>õÍBgiìëzímÝ|f‰7_´0 17:w3‡g²oD[T|Ʃ圀¼ðÍûZgãÞ>ýšósÍ1Ãwép¶Ân]ƒ~)ŒŸ/®4»"³Kj‡¸O2<øe‹rß俬 ÛïMy‡øc“àØ9ž_$z‰üb?t{ü¥‡Û‹~[Üìî ºŽ‰§º¡}Ë;uço;Ý‹n«ÙMÎ?y¥u§Ubù!Ñ»»°ö!½ŽŠt‚d;OJßÔ½o¢>vvãÝãûÆ6e’9­ Õ”sÁèV ®G÷Sãêík×Y»‘\ÌÖ*ÆZ_<µm¼õ Ònì™¶*†•óËÔE~kÑýÚŒÜ$˜|»vÎó±¾›À‡„w«™ß3j_nr¤fpÓS=ÊF‡Æiô:!?o@Ò;½ÔUcxWr•ê8Y¸”t¿§jÑ÷F’îð#©âR‡¬ùu{CK;"€Z5jº-𞃩EAçÆ»jÏ£€O-:¡R~¯(ê!áuÄo°Ãcy‘}™CXLÊ…±¾(ëŒ&j[?Ü€AÈ!msì¨ån‚ãCæFa×ë’OX]ä&Âÿ^î"ØþËüﯟýçÖy/én 9ë(æ®s¿ÏžNw¬ùì_eßsöm û%ÓIDGEO›3úŒ{{©Vjô.ŸÏÀ¤ÿwiÄ~־ޭѼ^“ôùU âég}·¿²žõJdg>ôÍ«3Ôç¶Šüwî¶aþXr®A5[{TòVξ†E(ä:­È9apKÔ­”çÜí<‘/æ<žP8?°m%ÜÛÛçÜ ºZ«”CÖS{~ØÛµ¯®sÉZɺfÕ¸½Ús0Vö©?øä•Kظî7úž@€´ÖF0AG8ÐHÿóšœ{úsîè„c49×\¶wm› ûLëCÈ…Ô¤[piq8@îíƒøFà™ûHðcí› 8©/·J. §}QÏ ko]drÒ'Ýûpo²N0\'¸#Ì™¸ZòZäÐ㈵Ë—XzN úm¿†‡pÈEµQ>ïÃÞ?×*×Ûk õôrt+;+çöȾåcXÝé¡>Ç FAïFÕrŸ5g‡¼. ÇŸäIª§ʇ¶³‰<‡˜ËÚ¶µg¶®ç¯9‰î–v@º{Âj¤¸å‹öàyˆ8íew§5Ícs7¹†˜;HçñK,ðuãrm:€Ü‹¼³FÝb0ÛÜ(®Õè¦Q$<áqCÔOz¤£¤ë¸ÔlÒ¢ÍAs¥¦;¸Iû¶6ð§¨èöV+ízÈ:7ýõ&ò!(å ůˆ{“rTÄ•ŒÚÛïß»î72n»1­­k(ëó!ä(î™[IÍX’À4<)áo­µÚ»dRh[·Fê®I)_‚<©æC¾—ðsÜöÎÔõz?—q¯‡ ^ÁD}ë÷ù½Íï‹ß£æ³¾9ähnR^n†S%õ÷çAðq[^á’ÖüZý,ä,ãIˆbõi“ö%„¼ÿŸ¾ YÏÚ1–2ÞD\ =X;e;ú¯PËu 5é<ðk"Žzž J)îÙÎùê»r è]s—Œ3LÀ_ßãTê0Ïžßv͹æMܧ…Ý=|ŽÖµ uæÎ*¹ÿšñáÓÛ±²ljE\ó.éPÎ^½„€S&Ökºrm2ÞA­é{."^öö~ðnGÜÃtx¡ NãAà_y®c®8{€{ lîØÚ_@ÌCÈûRÛøA‚¶j¾/ØÅØ N¢ÈfY5?È÷AÂég÷£˜º{OÄöÑ·sÿ'áÆ©îí¾4¸Ôˆ`tÀ–öº/+ûZÛ7@HM¯’ÑÌ!é·eqO€ó1Ï(TZ{î÷Ó‹\ãrеæËÑà”‹?%h{ ¹ÇK¼ÎEËµÚÍ5/ж”!ó~'Öòulkðå¾ý: ¿gõÿ·;$ÎÇj»xåOj¼«v Žcã°t¼K¤{±-ÇÀÕîÛ¨ÿ5éƒæ‰Ò$îï«qE:þþ³tózYó±ÐÏטìì“5Ú.DI…¦Û70 „V<&8Nvlð9‘Xù–”˜pÏÉkHúÓôOnÒ§kRý“Ü™“yÒ?iÇqŒ÷ן¼l‚¾¡q©9¯À¸£—'kRáckoK»[êk˜/~U—yG)·ú®xÖ ò¾ ó”õÜ[„\ô(èEÌ—¨‡˜c±C]×ëHëZ:! HûÔœ !ëvöBBãØßĵÃÄ®Q‡ŒK-÷q¨îºIÛ¾¹µÞoÅR:ÈHã*D_N’Ô$ÍQ›Z…"diÞ±š~i²žÖmÇ3¼kÐMÔ¥ø_¿ª}*ÕjÜÔ§{½‚ªš¨3Á(Ñ5é!+ô¨òh‘æ~1êºÖØn@¯bNpܬG]5©<0Ä1€\CiÖ*zÛ±3úý›Èæ5Bj©§µÙ”Z-œÔ»ktívÖ·¥Ù×:ÖátþÚ¨â!ëcûϼ÷M°®„éSNêºú›‘€ ŸzòUËQŃ$þ£’{ÔZ>|Ž >c«¢Ûâ¾—ôÙÕ\à3 I%}ÿo6|±KI¦9aŽ#!òm2~ [¨UJ»È8óuäè}72mÐh“fôùj° í>_f<ÎÏ!奚 CÐÁœ«)Kòv¹¬&‡¤\UÓ!äçÕj­ÒÙMÆ©7YG9Ÿ`Ôš§Çy\fŒd¹ˆT¯¥k­æ!åɉQU©èÁ°‚ø¹Š.býÉFßK¼@iw[µp@¿s£šGÌxúF™’N=9å€Û!$sÝéuǨ9bJˆ¹Î<ºŸæÚ¤¥ï¥¢+`Xd^€¬“d¡È÷”©?‡´Û¾7¥ßù±?®P%´û>ؽÊ>½­ý%r ž¤õÚyr;›ÇÌk¾bòÜärKz7P›¹EIÄV½$þ,«ëLžýÃ-Û6¿ÄŸc†ŸˆÍÄžr}M½.åÆca®ºÁw8¬§d`ùòZÿÏÁƒÑ“£¶Q–!“X& µXFÝ>FyÔúI+7aÿ%~^°-xòÃ/¸{Ü­+°oÔô =Xlü¢¾.Áõ@d<¶ö²¼ëøÌ!çÔ»hXÝÒý­æi‘äɃ¼‚^ÛSƒþ‰Ž§Ý1noô@ ›Ô¡/ÜC$÷>Yót•Þè¾@”½ <–n’9D<]”̵Ïápký¢õHõ?ÜÎDOq?¹É:64¬h¾X²ÍpÁîÄ÷%ä‹QÒ÷æ!ý\ur›Ök&é½Ïs£Ò¤•ýÀö”… ë5´ekD£È¸F½¦oÊ<º=í× ®]G¥ù~vŒ_¼Ybx_"HùGÇkG=2±.µ‰útR‘¹!và±·'íÅËÊ:7æ(f"ð¾9gŸ·C¾E ê†m³þ: ˜[5ÚVQÕ!+`ͼÁºI“ÆãëÝqBÑlÛ1rÅ¥UÇFaM2õɼÄÑóU|›”s|Èmåfß$ÇÚ’_c0_?-Íxh d«¸Hª÷í÷ÆÃ¾Öb¿6£,Ô{ïï P΃”¿s þöÂC˜ÿ§¸˜¼‚>½Î!èúù¶®|­í´ôç‹îõ`J;LþuÜñüÏyÍsý?ižýF¾U £Ö,ízw;íÓ÷³Ç7}´T[‹»^3ö&æØÞMÈM¶yHé5@û´:§2g;mÔtH/ôäÏPö†ƒ®f<ø÷º„…WSrRNÍ9-ÕÞ7!´fÝõå]kþÌȶà\Z­ ´êÌEÈ_f®¯Ñ.IÒÛYÇÒ>uç󋱆”_Ý"0m0.R 5Cs·Só=ô')]zz+gköÇw©1ç^¿ n1<®-èÍ-–Ÿ“G¿—L²Æ|Tna9`‰œq>û˜%̧"f‹¸ÂENÕÜwß/s|¬ùó³Öϸyg §›ï%}×Ô’\¯‘ü7µÝ$•_®G燧®+Ã9ÉÆpÞ+o•ýRÝ{ÿ$³ÓŸo«Ú z³³ù„Çm"{Yð÷Ãø=Ó7´Â_LöŸWÛ‚ëS4—UÆAÇyLòä¶x[uè„Èù‰¡F}]‡a„¬Çþ®“T…sdnÒn"t[‘ò4ôÑ·šomºOÎ"åšë%ý '8NÛBê˜tqA§''¡%<Öz.Dõ”ØÝöuÛÁŒ Ò=‰ï¹mS‡|ñ̘@¸Vн[äüs‹œ^“¹Æº9@EW›—jÇFP\ÞpóQjz!79[×ç±HznªÜ–mm‰÷†‹3‘i¾iãÆÎʉÉ9–É©O?m½T­å†"ayÿØÖÓs«h«èäŽâ¥0§´AŠª.«kTõ©E5yŸ€©@ëB‚¨+t&"äôLÿÚûMÌM6¶ÆÖ€Ü 2¢>’¼G)‘mA¶Š¢UiÛ>Žc!xš ۤܮҽ9NûD },¿Ð½Ô!ØW¶­_ ùç-ÅLnÙÏL‹¹ØÐz«ºÆ~øÐïyn9ÿõ‹;Ïù~±›×?{Þw‰´£ö{Ý ¬ù½x]ÿ-×i‘n<ìás•ýEÐ…¬ó@©z›Úuܪá½]ŠzöM©IH9îB7. ºu9g¾°=Çql×”k\Œm½æÉ¹Èöpz—ý´:n{;ÄœõœwG1÷ºFœT9Ÿÿ,=ÏW=bŽËÁpãuã沨óИëÒXÛ÷Z¯©k[µ!hI*t8œÆëÛ jÕ\*y®×é´"¨Þ\ãI œñþÕËØÛy°ÿ •<)î<ì÷=‡Cá|üI[ØäéØ a·èÑVv­ÅaXÐqq,îv:Øtñ…œ“¹ï{×(¦È9唩?/Õ<¡pš'ȇ¨”÷ºçÕ>îƒÁªå­š܃#¢j©– ©]šä’­5jÃWHe„—µU|q²¿†@Ye¿õ>ë2¦÷x ³¾C°¼Çfš‹¹±þoˆys½¸ Â[ÿ⟿ñ÷ºÙdÎ{óBoƒx(ä«j—¿¿Høü€nIvç‘§ï§)ü°«Xw;3Z·M¼ÿ¿Qƒ1¿¤u 7:¶Ÿìløàýƾùú³¿›Ú÷‘ ý³Ö?´ýÂþ£#m=dœ“ÛôjD=ohŸOF²·Q$4îûä˨õ"ãOQÐuwH{úUòäS#'[Ú®¯ß~˜š§-êù†Žè¸®A‡˜Wtc/>ìG9‡ Ûâ.´½½me{q¤:Yí÷XÖ6]ÜÓóÔœ§êmog¤.½êÏCØ!èÞ—Ûžë줪 ZÃîÇh°ÍÏűmrŽE±õ!ä—kÕ¹©ë>º­ ë}´¦÷@1§&Ý@Ibg7AÏq{ëuÓ[J:ê:ÊyÔ­±¾ëï3i‡”¢ªAÞM~ñìÕ’¢£Ü³Ÿ8o™4jÇ®U_„°{r|…vyDmé]+|1Úo• ¬r æõ%™"À¬wÿnúpCŽ»ÎzÕ÷U® Wãø%ý–ˆo@Û}Ü|Ÿ`jë9žsð¶Ë[ÒýÇ ô#ôí€ñjÓ—‡8o>kYq] ¦§Ÿ? XÙßJMà‡ëõó¿ðûr\r@˜£ÿ­¬C´ùü.*¹Ðe.XÝ“]¡QèJo2÷ùTÜì›’l/IU~K…L”Y»×Ýt–Ò©íš [•ë@·è4Q¿ÔN ‚¾×/úžwj»×Ÿcm?ˆxFÜf(æÓçÜ×è ‡#ŽËÔ ê®?w-:D]÷ º îÜáo¨éèsîû”î.œ„ÞfÌüöõ†2| ßO;óGqLÔîÇ¢”kd^j¹È8äÜêø1§ü‘ûC@X\RÚØÚsïª1Aq”]Sî eÚ¬®×Z´*»;ÁÍ€µÇ®G—‚þ–F«è‚›ç[Îu_ˆÚxˆó†[ãÜEÇÝ;FA÷¸©ì Ê_Ä•£}&ïZëz÷6×9 Õ|ÔrÖ˜wZûghR‡S»šF!硬Gö¥¶<]·Ïy‘ó´Uƒ„×Cæ´…K¯'Çq¾V¢ÓÊ´áëöë&èçåi Ó=ÞÏ£îE¥vŸYA?`åü…Û²ú¾¡æ$¶WÙ ú"ìˆ §ÀQèû¥+Œî–cÕ<÷W^ó1&´QÓ§cõ:g¬{?+æô>×}£×y´&¼ë–iIk‡´Ý«Î<J"ÚÛN­ï……tº!…À{-è<¨&èBHy‡Â‘à^¡Üô8¿ŒíG^bceeÍë8ö”'ýåAXÅËàAÔ¿/„˵¸‹ÊZ¸ÇP’ ?ƒ¿½—ÐǶ;_Ñ>ýùáqe{÷|@N@ý b¯GAgç%%½ìÞgÖ‚µ«§¨¿ÿ ~:r5Ê|À´.ôV=¾Z¹iÒNýûå„yz÷íïn­Ù† Wë‚Þïﻃ „oköCÌyâÖÿØóIv·²½Öö]ïÚÚw…ÕR.‹ÐK?‘|’“WµZóš{¡×SÍJq‡”k;5ERÏ \¸n;”ŽÕšˆxTt?>BD4¦þüšµôæÔS_§“bçòkhœtä¨G§ÖK#ýÐ!æµ^µdÙ¶U^ë¾HW Zã½Oo¾Ò~§TØ„Ç%á=ýTK5¯§ý;'Å]_r~lS“®ùG^«¹V!Š”GÅ9VA1‡œŸCqu³–Úó†{ùÆæ®Q7!è^£-ÝHo`ð¹u€\ÙHü–ZÏ_ž¤${ŽUU9cÕžÇú=£aò Qо­M÷|QŒŸÕ§‹¸d-¡q(˜¨ç$w´¢þ˜Üc{9OÐW“7”vÈä:v>‰Ò¼ª®Ôܨä"¡CHǶ=ÖílëgN°ª6À2š  "¾»2?${•vŽ‹Êßù"ä†{ÖgNþlÔr õ»™çxˆ¶ö5S¢5}[øñ7‰2žöka‡ŒC懜—u}UómHyµNKÞCZÿOÒ6µ<éìz£5êÌ(æîAà¤Öq÷®''î´XK®‡ÀÃKˆxÔs»–xPÊ8¶vêÍË)•±Î:ôuzF×—kò”öïGZ«Uë´.ÓbÛä›ëçÕR- d¬Iù„ÁQË«-jYÛ3gDÒSòFßónѪûòŒVÚ§ýÀr;{œ€ˆ Î߀7!—ÐQwê;#¢‡È½ ±dÚã oÿöO&êÞ)7ޏ?¡ž/BÊ3êþS„;÷ž“}DÐq·WÛÐãMj7BÔ UÖ(Œ­6Ç•Ö^ó!é+¾ "»ro€ÛX¨µV¼ãÿLê9=Å ;oË6ÎèÓî±–O»ˆ,"'ûÓòÒæpÜ¥–âpܵ S=at—Bñvî÷Ù€: Þ>îª-/˜^s׋m¿ø#49"üC}’¦~lG=&áüb;7¿nUe€mcÖybá÷xóºËánü±S¿?w×6>¾ýAˆ¿PjûZ&ÆzOV€Iøs­&ÇI žà•²Î“¾'ç5é¶Q{ÎÓE^Ÿ´Ëíž>~Ú­•ªÞ'Zϵž"ÿ²4ùD 7iç„ÎÉ?s’Ý_8Þø»º€l_ô¾ ¬‡@ê¼Iº.R¾H. éý„»ÕóÌÓ>ÅV·'·1 ‘øªC4£5ÔõmÿÒwˆxˆzà”w…½ÁY%BØÚôEn€œæ‹µZC@m¢Ž¥:S“¾!q¾™´å$”$‘|u#Ö÷ØÙQ­ØFµ‚œg~_¸“Z#…lG)Ó67ù([ll²"Ù×6[Ò¤Cà^B¸dÝaXÚZ›+‚dÒe’„yþcýœ(î"øØÜ­ÄV¸Ü(ª«¼³Žò}©m›Ž‹ê+˜Hаi6_’¿s@¯ulÕÛûë’–>uðKŽU³î‡¶±ûgð÷j%»~¦<\àáæO-é­p³^Dœ÷Ö¸ 7¹ów"NøÛX׳?È>lë&âVÊO‚ åæsì}r±ÄI‚ÍÝ@7±6ÉÖççÔâNË4ÛÎÞä= ír½ÆsÚ¥‰ /)¨1»çî6Qå;9§ÑëÜí µ—pEÄ«]Z»Li­ì³Ÿ¦gw9÷«<*n÷ÚReVJg¿³z¾Á¦t#éµ ‚;s=¤®ëŸ 5áoÓªôw¾þ ±¶kD17´_ï[×è Ü+Ϊ÷ñ:H9¨µ„"åÔ §Ö¼Fvï÷œ¡Ó÷?ÜEЈ­Ž8l Yç>Œû2Ⱥ7¤FµUK5jÏéo^5ç²µ[5©ûSzóˆDÓVí)!qÂòÛ"çVдB>÷Í?Ææ2ŽjÞ÷ã¾—GdÓ¼ÊW—Âp#SÇ-,aÜ6g-^Žš¾œdyMê´çØ>fläÍûNQ©·×øi™5¼¶ÊËýà’ð)pã' ö(ê•›Æ÷3wôØÿœ¨àþFœÚ–W ÷Ǻí÷Ò ø!ÀñµÑ71ÞÔµ2l’áÅ”u¨ñ©yçC¯}|çû+R~õÿM¡çCFHÞ…à”ø&èûôkMÔ+Ýýwö0u7X{8aAÖŸ„Œsb‹uHkÂXܽ^Ö#Èùô³´ân‹SA§.}H¹Á¾w»SZ}„œgÔú{²¸_“Lš‹Ru]¼”Èî‹Sô¹àÔ£'ÑÝD]€°Ó#½kÒß}t£1HH\_È gkOìãu¬¶©E?@Òl)Þ‡/c«°#°†2Íýó ‘£gúÕ˽IKÿs’z¹iÓ1[›È~T›¤Çn©}&G« ÐjºQÔ{ÎM®Š˜ÛzÊͲ‰{)ê•ð®ð8÷K'å½”u÷Kök]“Š"WIðk³¥Í‰‰ßVR[ð!8"ØÚ¯m}_£ïÉÔW:f•M¬É(œd{ZiùXײ'`Rè-˜à£n›ŠpEfµZ ù]%p<¯Ýp4À~«È´’_sÆS½à5Ã÷Ú?_«ãXüQÃóZÃ?_Ö©×ÜûM¢Ý²¯û’¯3B¯‰ "Ä]¯Ûò‰¯}îôÐã5Îíîùœîçò­¯Á盇S&á_A¼‹€ûÕû=&ˆMe%ïSäÛÿûåž™¤v¿7룠/h ybkTÐIB;çR[Ùµ-L@§L!ßÝß¼“Ú9†´cy÷öI½ù¨éAâ; íŸ>~Õ¥ OTúK»`‹{—‹q-Õ1&áÙnÂż¯å¸æ‡-!_¤Ö‚N@Ü{²Ê;™½ð }ƒ¥ V ŽGøÐZcCáÒþVd=ä_k¾ï{|›0`jϯDªo¸/¤þœ5#Ä1Èd=*:dÜBRlíXÛ©KW—#½~líîyŽÛ4ÎS½>kUþQL9Qo©†û·ß:+êøç÷ñ!ëð•-/¿™¤tæŒ]û &p[\^¦µ C,ZÞ÷X»××¹ŒEž »áE›9v[_ó'[åŸqsk,±{Iü¾/B5]˜_Ö$µ¯L¿ýÓ[™€új×ù7ÑŽ÷ÝýìÛÞwK–×j€µ¼×·>`P¿7ˆ|ÖæIËɇ~›Ô³6-ô~ü,eÛ7Ê@Ûµµ¹g]_çOi通þf»¬ïôCw-êÑ!é´“ÈÉI!o Î8ê{^j-'»Ôá`úŒþès².Ýt²»ÑÉØÊùõ]%ºŸ'{Þ ™[I×\Dü¹ÇvíW˜œÛÜM ꦴ¿.N>Æ !$žþ H@õšðÓç¶3,îöWýØq¤Ý¯ A´^jº·OkÐ!îRÍ!è‚û²>~)µ µè鉫_+êî/K]:u|™KIh›;­oôÚVÓõIíEEaÿ›{æ®UÇjÉœQ7™´ ò6cÝ F]—Â]óQÓ!ò÷ªè}Ã,2®ø³žé&ðÓë¸ÓÜÿŒçûQé°àBÎ?~q‡š~Ùò.ò½ýŸ!ï]§+Ò`5½mï¨ç*F­Ç¦,ÔkG]@!ô£ÐV{·?BDOÈ/ 7ó%挛r½à¸$¿×üý%±~¾ï²®7Y×ñr è5<œ`ŸÆ²ö§¦]s7Bëu0L ùdtª¿ Ͼ¨è”@ ×víß.üf½pÌ'Nûjÿ=5æ¹m}ÏÿÞᄹC·Ã¥¶ç–ÿuð‡&èXÕ{np¾q¨û|Nâ7 :5æVÄ›˜o¹¨Cà>s.T2 ‚{]°muO®Tï)ý]"8_+fz_Úƒx©\’Œ0ÚåÄûËóÈó÷ºÂ©yšELóApÑNaoU}x"IîÅçúûö{L/ùácò¬-ÇÃOä—?iêD~~Ä“Û^Û–kŒ{ìªö#ðƒ@b붉ók_UûŽì¼žc7©‚X'€_·mø'+‡–býù@òþta71 »ûÅvkOPÓ«:§0Ž©ç IßÍŒ£OG¯õžßž'uŽ¢Þ""é $ѤCI 瀶 !ïuar?óôcÛx8V÷›$º[9?ÆÔ¤ÿäÓ›Äi®Ñð…x’Î8O×­¤{›'ì –yz—'ôŒ¤Æ un6ê©?=^©A´¯Õ…VÑ7!WÖDÔs+ê"õø@ÎKA·rîm½ÿõ­çe•DilÝcú¨ çQèÀ8í™S{^„Ü*y­£bU}(#h5R®uwöce»ÓÝ,ò(vØo›€xd"R5è(èö•Øë(å€9[ë똲ė_ªkȰ²n²_‰ð(¼Cø}Ü«¾:îÄÖnâJ7r~HvÕvWm{ÈñëU»!é}Œ±ŠyëÁÿŒj¾Î<ÜÐ\¿Äíþ}¯•]ãÖ7·‡9sÒØùìÙ5â9Àý1¶÷üßA¼5‡¸No§3Vö΃ ìÄíÓŽqCá*©½‰yÞŸ‡vœ/6±Ýç Áû ßÝ&Rë« —ÝçÂñ¶õÍúÀ¥ 7(_bí@ZoRgNº¬êlûzq¿§Üj ú]$coÿÜn1jÍ­¨ûa4®3jÛÞ¾Y.<×qÕ\cˆú ‡Â©”-½Î U{ƒ –ÕþÔ›O8-Û¾7™P¸gÔŸ,¦çyD‹wŽŒŸÜ3¥­æÊ â~Kð¼|µæ¬¡¹‡{Õ<íxÙ¶Ê^mÕâÔŒ‚>)îˆH”a ›;Jä.iΈ…=$]–·ÝŒµ½ç&Ý"àºOö#)êæ/ÙBCb‡d7Š$GÑmñî)E™±~"tÆÖ†y_Rå/Ön¯ý„ž†Ù­“v[³Á‰s,ãvûÓ.|[eà¤ý>ú=?≾ÔBìâ†t˜ó >$£ê³N˜ÜÖÆmCãðýlià1ër>‡²»£˜ãî8#·8>&åB®±¶ “kæo4ÿW¬íɆh¬z!g[p-ºÇÔœ'°²ëÍM°¥Ø‡œW½ù¶PC5ßdöûŠxco¯üšÛŠ>çòȹ\RY ‹ûˆ8Á)í^ÓÃ|ïwB¼_£ž°‹û°ç ÛÕ½”‹Ôž{ ä&ÜÚŽ×ÐRw„Hzáì¾ò¯þõ›ã^òD\°Š®1PN$\pi¥Ë9Š,Ç(½Ï­¨[U'|YèûîÇÔŸÝ“Ží꼤9jù#¯'T|¦[š-‡¯,Ù^±ì×Cä…cA|‡Wò5 Ìù~KÜlAµÝÄÍ5+0›}Ÿ%y½¹UmƒîN¶jù¥qÄðÆ•ÊZ…À7?*qHnGÈã½§·ÅûÆzóO$}ˆ²Æþ°œ+ïýï¾áûÆn€ UÒ Açµ  òÚÿY/þ<Í©?Ê&®éï ¡ ÖC…ç篾ùÞ7µqøuMÔÇ&ézRÂ^ê95éÇI£Éù‚:ô@'¯$¹¿uö:Íךçã>øì¦Ö áú:·ž“îˆðÛÎÞ½dcªƒZáíXÛ•èþQ·bKÍyPGwê •‹Â2µ9ugƒã€£Oº×T‚1D½Õ'æ}3‚ÎÜíÙ.׋šx·šÎÍûÞÈCʶâ–þ€‰džúrÍMέú}±J"d›¹^Ÿ:ô¬ ¨˜^ÇR|Ÿú‰Rîc[äQÎ>vB7JjìÛX§×nmÂÉZÆ@ÂÈ^J¼*<ﮚuê´ÿ¸áj¸°˜wj¼Sݵ¿ëÔ32Õ€V´y0ñµCèø9IѪÅYˆkÛVMòçëû»C¨§ñýØÕW¥?ùÀî•÷ƒø/¤»÷~¾gú´ÏƒyØÀ÷Waukyynsß¶kÔÂhú¦S[Óv÷'(ì„eÐr¢O^z*éãÇÉp,HRÓ9¡BЕòØ™4(å~êªÔÏŒÛ"î„Âi'éî×Bµ_ãI°uY×?=Æ~Ât8ÜÖsåéôÖƒmR½‚¾d½^(¢n»û¤ºo¯ÕE)Bo„(êcm_P‹îžXÚ…ØS‹…t'äÞ ‡­ý»SE…›:‘uZ÷è&²o‡œ/1ïíÔ¡§ýZƒµp§ÁK]¿Ò„|uz©£¢£œ§ò1Š|‡õ5éÎ& &þ:cµ5I 6=¸G)GY'\®÷£B׿zîqH¹F,ï00j*Vu¬î±;kÌûˆ\†4ƦÎ6½Ó!í¨è Hý¬-êA€”eÂÐêuèÆ>pÔjÚÎQgnôÜÄ?ä>Š·È´ã¡…öñ»a~nK˸¿'æú›ñ:þv8 –x3hÓ7ÉìùL%iÏd•¼H9DÝ·Lª)ñ˜ÿûcþËw]VÂÿØ€lR¼oõ¿š²•ç ©ã>/`eo›»ÏG‚È·rr­óã¨9å8_NH¦Û©ñ2Ií"êz½]F:~þ ó‹4I×öœÛ!æd“èú‚z^Apà÷”긓ҫŸj·µÇXÕ¡»e鍿(çÓ:‡áïz©Oܱ^mTéä²÷¨èz½Žáa?´ãðCH€¨3o‡  aÂm×6©´ö*D)’>ê¹ ùm ."~ôòÀáÂ>tÚw,í™CÒ!ï&ò©;—b²®møj­–ûf”óÕüPÅ%„¹¶' .‚[ÜÉæD£êz¤xs™µ™{–ís/Ír ݪšý| Æ`ÔQ¾ù¹R‹ÎÏ„bž×ƪ_ÄŸã«n>Ûá‚Þs¬ìçíÈW(îcOIüƒú#kSŸTó·°Äï/«Êz“ÞK6€¼Ž?¦×ù -ÁçÖ¿hŽc°oT{×vs\jN‚ø§-ÛÔg@®=òàx~ÞË8¯Åß0AD\²ž€í5Xnª>†À‹>é84ŽÄÊUÍ5¦ïd“qÂ8BÎ9ABÊ÷D &±SÈšI{ÈyõGŠN-úsFBã\%h^–vƒ'ÃO\{®‹“Ž!Ù´ c¸‚­¾èEÔ»O)ÐÀØÜ=?@ÂûOMæ!ñ®O+Ä—mlu·{a›7 vïskµƒ¤¸–2A}zwúŸëæ¨Hù&én¢»ç¹©i¯zÄÿ#ì\—,¹Ê£=7ã¤@H`dÀ˜ðåØFHôôtkDÛ_è»0[Ìôa@7äÊI¥ŸHg—÷ŒµjUíݧÝU••ùæûé¡RdMÛ?»¾Ï<õ麑]ëôH7I'Õ}ˆyê'5÷knŸÚöî`—‚”›á%ê ûЍ‹”ë›@9CÛZÇû­È€ÖÆÛéíòRøLê³M |÷IOØÕ"-iU¶_&C¤H}Ï“‚½\c3Æþôk{v¢7ʺ ºŽa4ÉC FÖþ%ØmÓÞºö&ÿ(ì«®çÔzÈ0 óN*;ù¶˜[‹~À÷ò„mß)éªÁïà¶&è£x×~òù}ùûöØIí­²ofÀÂ?{“òM]ŸºrPvö&Ü[fáÏ!$b°´½uçqœÔ· %£ííÙWª¸ñRÎE´³ÿgˆy…L^îuŽu½]=^ךG”ó(ä:×ÕyNëÙÖ<ä<ùMÔMàÆyœÃ_= 1ç!*ÜÝ9ÔíÑ9%´ÓÜ×bc—â]× ŸªcÊïïQͽo¶bš‡Ï—œ;½Ýc¡,ë\C;œUp)Ë©)?'çp£IºÃݸ?˜Ö­¥¤%?%ØÖ\ë8 §­Ûâ~=Áº«žß–J>äüP̵- !¯\!¬ì ^»{“ê ÓH@@ÊÜv÷ Ãà4÷1±´ÓRØ£´‚âtüƒÏÞpÿìuA÷Ü8U¹?ºÅšÀº0÷ýË ¶úÕy ™Uɼ‚©ÇxêÎi=6mò¯ZQ®®WÁpµí6Bäyâ{©áqPC²—÷r½†Ó!Œ.W„»­C!¿‹-Ø$xæ]jAçàQù`@Ø@)ÑZ¯>ãüþe\´ëx:vŸš`7XÒêcBšOŸåõýÁÝ?ƪôÀÞoªvbZªql÷lëüZ5¶ÆŸù7?ω=¤ó–‘s¡õØt*…²ˆùŸWº{…ftô%é´³&æŒãP‚û},ð{B¾™~éwS5M."âÁ´cÓ…$Û¶t¹>^é„¥Z±Em§MÉ+cÛ¯¡¤W͘á§à!৘6k ”AIíu÷q%(N 8.sKÐWa7Yç†tw,ƒiË6ŠEì†vÛ7XMÖÝsýúalŽ'uèls,ûÖŸ#æ©ÉÖ\d¿ ù‚\©TV¥„±¸gttjÒCÈOžf­ììŒU<ìï„Ë5‰@í±ãn}úÖ£CÞýº²GÁ?é1íc!ñ¥¨kNÝ0êjHZ5VxÙÞ[‰Ík õ:.­ß„ª!w-ôiTlˆkÞ!ñv-d;ï-Ðn ‚žµ"õ7”­ÓêE@©£÷úr¾Î9š´§ß÷ü!AþšÇÝI'y=kþû@Æýšé•_ao!ÚþÛY¡ö:Ä[ïbžùñÞ(íSOþuùLGO·m'Ëax1ŸÀÆÌ(‚ú™waq:W¤MÛò…É8ä\H­º×°½s¾ÊyN„»[§mïsÃçÇRÏ]bäí øwEº=ÚÎ~ô(éªý¾´öz ›pQ¤·ÇÁ¥ø¸Ìq~†ªmÖZ)$Lu¯“UNfWšœçz^Iogl]æ¯ypÿãÏÓ~".p/!xn"þ”lœ÷6匫» } †ëÄv«ôª9!×ëPÑ´É…¤k¢ž,"Ü“à†ûÀvÔZíþÀƒ ;ê¸ïiVÎsoŠKT5çj³†c´sZ7ÈxB›þç!êÛu}„HÆ)ç=#ÁB¾eºË… òeã¯A¥n>¹dÔ8q&w£°œ¬I0Â0d@ä§Õc}§–õµ¶§5p¨ÇÆ¿Çub~ Ó/ÊžÎf”ïSU}[|õ/k˜+Ñ=Ák|æ¦Ö õ%°|85ú=ڢіñùÀoJ Ê78±7̾E}ÏÕ ‹þÖ퓟ü|ó¡ï5žÎPËâcŠ ¯ý&- dÃÑÜŠùZw 뤸ûDG¶¨ê±e D¾Sïã÷yy¼î ”tÔt?ÁôšÞû^]'^NÊ/!ì?ü·ob•Òúó­:¨At1HˆœSÞWIïVl·eõ oË»I”ôjzZ¡ºê§Ú±¨u+6%Î_?æb­÷ö¼ÜiÍ¢÷ßzôs@Ћ¤3Ï~Ãk&Î?yoÛ{'µÂ*ÄÍã$¿Š‘9*FYIy/¢¾5餼 §­y~z|zÖƒ 3:¶Q†ØçÐ8Û>ÝvhÈyBT*á¯ÆþþËã}P´ á—Áͺ ø´cÊ ÿ¢É8k`EØ•÷5‘1Á/Å|ˆü5XaoU=D=-Ü6TŽyj×EúBô €Ø¦“yÙž±]£ k2~ öo¤^ÈCêái=¶äµ»oSè7mzr°®€ ÃEÕÛdÍD;=Ë…îs¯5C9Bý˜‹Ü‡¬Óbq¯ïç*„¼m »·ÙÏçš<¾QÊcGö%¹üm›´ Kh£ëÒ­ž{¹ÖÒ^ç’y hè<–ƒÙCÄ3†”º#†ÔåÛÇ:_ž¹—´¦î™w8Ü“çîìAkM£CDïÆmÕÛÁ×]£Ò4ޝXΛ¨£¢ÇÖ®ãûš¨uêÈ¥küÉÕ}`k¤[ŠC]õð\àúÜ­RµÏj¹[ªEEÇ9wóÄþ-“ó=öva õäYÇÖ~ î…Æm("OY`ñ)…£1.GÔsõ´_÷QÎ#â”’^yF$¹©C±È"Ä=%›ˆNNµ6­ÔJÔÒ}t§¶3âÏ·WC9 $pœ·Z[>Pîfä¶ð »½³»ÜÏüÔrßÁo©zNù®¹ž·9fÞõ¾Ûý+Ãےͺ•ÄecNã½9w`”ëÐuc?Š:6ÙJy‰Ð8iï&¬³bÓjºÆÎ ¡aß‚ÚvzL¤|Z·E“óÓmÒÁ› Nov¯£®ŸØ® ;£_7À^^ t¶£º ©×¸Ê6¤uÝÛ¬5 ૘ÿãÝ»lêï[]ç¡Éé&ÏÂi²¾ cì‡%}ëËß¿_mû¡Ë`s ø\ šóPGä?ûì¡-`å'¥¬?eNh"D½‰¸ÆþŸ8ÆŠú:üOÚÕ2!pØÚéÀ ÿÏQË/(èª3çüÂ(è<–9Ä|RîÜ )é•ÈιrÎaq9¿Bºï¨-wkLú—o=ºÊ¾–öVÎkMáq§›s:‘ЕD#Û™*®ë#Û5:‘‘ß´5m ;$˜œ§æåÜ6øcK»Kå=è·zþzíì"ä ­E4èÌœOÜ2¶ÚÉ~â8!÷4…µº{ŒzNKÛ!çër¼ñèävõ6©ÝkÈ'š6½ƒ&âÌ…ÜÃNÙfæQsOœ€8¹J="xµ;ÕkÎ}*µÜãK·YË:ä±9Æ÷š×„øâô%e\Û1fDܶå=³¯¶é6µj5öú¬_®ÑîdúŦˇñ;ú¢˜ o\ð³´€ OZÔÝÌŽÅânrmœH÷óñÏûïù@<ÿ${=÷„<ŽUCu,è¼W’åg?™˽pVßeŸ9jôüì'Àþ¿¿ÓVñ½¯Vlª= ûÂQûñÇQêõ½Aé9!i½ýÿ[N×£[ רVkéûXö,A&è?ø7,A‡ˆÑ 0Žþ“êÞv÷¨çÕ+=ë[^½.D]árûBâ}SƒÞÛ\Ä2ºfëÝÚß ‹ÛÞ£_ ¹˜V_t¬ï¶¬¥çiµ_óœ‹6íYŠ”ƒ‹Jz…ÜÐT;6ÒÝGuAŸ}ÛjÍÇg°uFÈz¶=®­}ÁÍ ¤¼^Ç\½ì›?€ › £>šs¶wòÜH šç&ëûùM:ky“€Ô´°ºËFÀõâ¨ìÔÑŠàdNê´‰çPÔ£BÎ7íšýñb‚¥Q䆾ê;Š»ÐvxïÃ_ º·Q|‹œS×¾¡d¯cb­m+ÌÞ®”ñUÅ·¦;mËt\ú¯oÙOÚ:ïCÛ´¬s|ÛÛë{-bÝdÚxæ!Ç?|ùxö;€÷ñï„y›5íX×Iþ'Η¬5L¦O×=ú!×cr>dübðûyX¶ÿ‡"ãsýkôùÂíÓ¦1çT@¸ç¡ßv’àœÃ9ÊçÂJmßVjžÉØÞîÞåõàSØPÏÝÇù‚Îõ°í uÙÙ•i¢õqÚ©ÝýÏCb$ë:Ç\£Ñù+™Wò:.³\Sk?Öw]“7¼U×Ф¶W†Ìq]÷uÞµäÚ¦ß9pïA WÝÛüîm‚áÚ¹çãDÚs_Òe{Œ‚ˆØÜ7¨0ûBBÒÉù šœ¬í"â×ÛÚ_¡Â“aä{ÑcÄ¢žTvZG!¥œûÚmA|m弉ºî­ CÒIpÿáw÷åý›op´BÐ!í&Ým£›“]üž<°ð¢tî¶ÞeÃÉ!+ÞUµÜËÿŠÎ÷´-ü­Ûgwþس-Ô¦[ÿ¼ð«m{Mév¸ðæ¼OÿœíŽÖkþÒݹÎlþõ;Íø¢Ú£]€ˆ^\ï¾âAÓ|È–¼&ö­ðw Lw?¹@É/l’ßô9ßCì |yX°t]Åy\­3’_ÛÛÜ¿bH)ýoÆÇS:×½@ÐîɨýÝfÍOÿ®¼OÛ—“}"Á¦fzÛ¡qÇñoû$+B®Q¸®6[ƒD’S>ÑOd‹”‹°£¤ƒMtWV¬[zoý¼Ÿ½á‰1d½/lØÜ“r*džRGI?p¬Y×¥|jѽ­¯ý RŽÍ‹µ.ÞiÃæúó%å×=YeËó\0IG=_x_ï/%¢Rp³¦6jš¿ö Ôqó䦻UÔ¹ ³"²-t|sµä'Ÿ¿ÙzGoÇ6¹ 5;<¯£WºÉzj,‡°Ój­UônUD{6‚á&¼‰4e«é¬‹§wzÒâ –ËþBZ>ÉZ°5wmñÁXÝI‚_q°=£½Öjú¬a!þZû«n˜>Õ¬k»{÷ÉŠM[-Èø·m«¶B>¤]-2)v¢Äž{ð«ã÷ÞÇÌë¬Z³] 8ßOïÓbL?öt­ÅJN-wæy”îVÊ5öC¾–/<à8 €[û:¶óo!Ü8)ø»6ø ðÚÔ‘ëoÈçÌj¹uêij^ ú¨ç(Ûõ9NKBöAÖµMý¹‚Ÿš“Q¡Ž»]¢_k'K0a‘JmÏÃ9‘vM¼yØçsÌÖkôyŠsç²é_¾ðþ„kæ¡æ&´W \tjεÝçdÆ‚>%|øú Ñלd¡“‚õü°©?`y§¬ë¹úrö ºþâFÓˆ Í)íZ÷u˜çšû;­RqÌiÔ=@mA‰o{»‰½ï3 8ùÔ™æmTrÈ8Ð>•ÿÅU¸*:÷Ry+(N÷a"àÆÁ=[È÷‚à (ëÕíG xxCŠÏñª:uHœÉ÷¸HÃeóu¦n‡¥†¹ â)š2_”èÊ£Ûºoˆ‰E6« tæ±¼·¨["¨FøÚ¶ô-=f+¸”þÂW1o58×Úò ó~pÅ -Âùù.:§_ð¢VÑùÃŽ½ü¬Þ»#5ßgõмöx¾ÞÂ]$ºThž@xßZ ØmÃØä=@¿÷nfÏ…g•ýýÍÏÁ¾í—Þ_‹÷<ï±×uy}ÕóWûíûì­ˆ» x[Üžþ‰ˆ[IW@FÂá4 Ô§_=TXÜû6'¶µ é=µ»‘Àü9‹’_—íµ¼s’ÖÂîúsµ\«'²Ñ~-­c»º-½ì[CÌøÆÅêuF©ß÷QÕGE×z[Ëhu’þ¥B,îK€\‚^BØ+É]cú¤raw¸\n4~üÅ}‚iDS„}-orŠ˜[©÷þ ܉Ý+<ê9aqV?r…%‘2jCÚ¥„°íôßjÇcòî¶m¥¢çÆ~éU©ýÚÎxvƒÊ1gué(ìF×°ÿû¨^ª9ó‚×ô^Qà|Êþsuì¶Ì·Ž½Õ@ÔÃM©f²ñn@”VE‡±ý\˜ÜÔKÉÍ6„ØÔ*—…ÞókÔ`ˆu©ÉÕÖ 2›µiýµ€Ð“>¿ûŠà–’M¯w‹úÜÇú÷.{uÙËSû=ª÷¶µƒ”›Ä“‚¿ß;míwóçA»Dªù›Øfà†¨ýÂ&ýW¦öµJ¾ª9ÉëÔ¡§‡y·S{q”»ä×éa^­Ðc»ý"Ýi§¨ÑÙ?e=ao>?È™Ãüå|Jpþîå};}\Þó]’;%=:¯m 5Ê} Ø>¯é=¶U7\vT!ŸÚ'ë{xמó€RÞnª\BÈ… ûéÕ½F`’Q"ç"éQ¿!áÒ>Éì}ÊÍô5èsî‡ê¤¹WbûwY3\óõ@Þ°]dÝ÷m«p¸[׆û$&¤Çù1:.Ýh2ß®6•Ó$Ã'œ{¬sÕ<÷k:^ǺÝÚÞãi­ç¹?´¾ôi«Váož‡¸ÿ z^?µæVÊ[5×vœ¦Êp’ó«û#½Z›OµÕž(;5¤×ï ‚pQ¤áCDy¿^r9 xsCäáMlÃÁ¨ßžs¶/Ï­ÃÃÇÕÜä}ùÛÖЯ º.g8icÝâ²ä¿ˆ²Ë‹úC`Ëk<­°ß#ñ³Zûô Û’YJz{Ž¿ü—ÿòœ¶c§O‡¼6‰ö5ç¸ò!ã|¨‰ëçCæ^}|NTÜâï„ ˆ €EˆyÂ⢦kMða¶â\j¿¶õèó¯ßÈþÎ m!â®÷t0œÆ&ç¨ëCƧ®h-O®Cšõœô«¾Éêz VÛýòþœÝýƒ£€ð8_àŠcy×…/ûIBµåLû° ©KwÜ^|!êyj^©®Bu½÷hïûè³?j-ë²×xìvkÔ£ÛÞ÷•·±øi^!r€¸ÅÖ«WˆÏ$½“ÀK¯ôãg3™wʯ-ñìOÀªÍŸÔ²§Ôü¦1–Kz¦—’€kÔ·Õ*íŠ& 9øùËûØÚ“ªÜˆšNÚ»ú¨Êökסcƒ·êžc ”ëthWæVÝ5nBsíg}‰–ˆ*)J*°"+Uu Ýy+·zTöA‘ÞÝ·ö÷&ßi…Ðåë˜s<½Ü”÷÷„—ãE‚«ÞûWí^ëcçŸà<ŽkðýúÁC¾7ý\ù~æw»R„ZÛ×hÍsÖi¦6eîÍGÀîîõÞפ{¡uÔòRÊ5®šîCtOZo²NËDýÐ-sðË/“¸^­Ñô=Ç¡£‡„&߸| Þ•\FÚO¦íšæúq&Qz”í3Õ\`›‡³Ûõ`6¶õVÏ«…gF\]À9)‹£Mèw×·÷F£Õo_/5Æö~àQÛàõö@ÿøó7ÕË\ï›­ »‰ù„Á Ôž¿ÆmÇC{JãÈø–ÕùþÃ6ò„݆”“±c7 ˆ½Ö€÷¬YqÏk*ã'sTv(¤yTô¨çVÅÙN¯sî ‹¬—z~Go4ÒV D@¢ ÓïÃxrÏRžûâÍu¢]ÂØ‡Ê2Ò½ÆåEÅ!P±›”|LmÓ쪸Îr,¯ÃÅ68|2¸”c”þ¿ø§ÿÜŸgEØl3_Þ3®eDJxâíy9áož_ÁåÖÅ Ö-~® Ê@—Y¿àÀùf =èiÊ´)ð`¾±%ÆÐÆû!߀!¶ýÞ°}ìk:¸íõ «{¡>Lû3ŸÕò×öÖS œçÉ’Ær<”«a’à+Hîƒkÿ5lŸYÜM¦¿wïïáNY|HxÇ-HãZ†ôº¶QN:dœ:tu·Í(B¾õI©M·uŠtPmk¼ÞJú>¿¯ú)x:aqéy-ïÝ=üxð’%ÛØÞ{~þZÛörâǃ þyhì¿Dú<â­"k¹x>Þöüz’D} –šê—~Ì9‘GO6ÛRÂ@]‡”/A'x#$–kÔ£‹¬kÿÔžÿ8y•m銶Q—Þ¶(úhö“YU]‘0Y@Ì5òä¸jÒä§Ï\ôú>Hvç"zö´ÅèÖ ŒóÈZmWxÜW Wá4—Ö/"£„Ý`õãFDë[“îQä:¯_?`u_»»ÆäL-"AAuc‡e}{©6Vv¨EÏzê%7Ln$æXBs“«ñRu«ï&æ¶Íèl`AÊ{÷J‡°{.%ÿA„À¡kÿnB ‘Ðè:õQÑMÚ5_{¯ ’0ä|”FƒZ`ÔÏQÒ½^Ä,_‡×ò^ÛšÍ(™¤E›Þ'Û}ù"ìEüiɦãò¾ç5ØìC/Eüìu›~N›2H4#Š|‘lÞwà¶rõ@!$?¼ÔŸƒ'­œ‡ˆóûü–÷ÿöØÔ…³nwþâ‚ÈûÁõàS®±k AôZœ&zŸüŸ|›–†ZÆÆžÿ1ÿŸ6)'ðј"è ƒ; šÄ²®sI—Úð`0йPä<µäUºsÀëjʧ]šÏ›œg«—y£¼‚UÏ5o•ܤ¼to—Rž–Ÿ?XÚ WÝN¼¥]kÏ‘tTt,ëÞê5Ûc]Ï(5œ`8jÍs uJà|?E½î!¾tÞMF!êyà€»ÒX|б!´>¹t¹å>êÃß¾±‚~à°»[yUbIz]®( ºHpñÜd¢îmÔóRÇŸœ‡ôÙ[ÖpmšˆKÉ×½ðçÇ5]ÛXÚWEg\õœ:tlí&è/éo ë¥j{\,ÇZò 7µü9òé!ò\\œÀoZ¶ý¡‘÷Y¾‡žÔóâRÝíªöMF\ö.'µ£¢·=ÿBeÆý¾-à®ó™¤¸ï/ÞãDã_Æ>±Øæïü¢CpóÃV=:a‹ó:ñ!ÖóAëzˆwÌvy§?ûÉר^x>ž¬Ï¼Àþ“šxͱeÔ‡ã/þù¿hÇß î¡ðßFµ2‡zÿ d½êe »°¢î“GjÒ,B×´_>±u«‹Ivï~èÞÞ–!ç¨æMÎS‡GQ׈‚¸ QÕuáÙ#!ç·Ó†­0¤ýÆ=̹´¯Ú¯awç‚ÝkÕ•¶,´bËS|žæo]$}a÷Mˆçw¨í¶þU¯G`Ü×õéEÎ¥”‹”co·*² QÐ|à:ƲRFµÊÏ1¨B`9§µÔsÏSÇ©ñ Õi[1_e+5¥£†ýâæ±kKµÞ-Ú !í<“o"&Á£øi^ Wäd­îÿ¯ˆMŽßí"êÕâjð÷·SÏÎë Û`²gÉdhÕÅk=BZ ©ùvüëÇJ•‰ 1¶RÜõî9VäTóMQ§W8J}µ†Kk²êIÎ{k/·Áºp*œp…m¿v!êõ·æï©÷D=ÏvZ Îñ©=/âÝå&ÇÔ’ûø>.D%\.ÿ"K{;ÐLÂý~¹Ö~rõÐÇ[1w,5ç)w“=Áp¨çýÀ^ãímNr;û~l‹zÚª¡–#"½CÝyל“åCb;¡pVÖ­œÇÎ’.r^ʹ粲۶[»FÂà°¶"üdÁæ}˜›æÔ—£’?E ²$¼DA/Ë{ÛÚ5š|Oœ•s¯y žSÎEØ£ªÔEOÒøp³*¹EÅ&=}ò­JUžpêQˆGR»Âè Œƒp"ÄÜ>~ ýdøX ÇS£æ˜æ[v/ã0XëüI-ÖGxeû„Ô³¼Õ|°D?Ûómmðû Vp‰dïûlï ÆNàù©€äø­]ÐëÝ¢ {;Ê;6l kטÄ>bû§Ýüž¶ÆœßuÛŠÁk±[ø÷-œp¼ívk9A ia·5çuéË®S¤Ü'2%Y¢°“è.tpœmGî)©ý¶$ YÏI×'aZiÐÉ“SŸÌïð[Ís‚ï'¶ß'¼ß£¨; Dó\\´]¡qIu¾û}¥®WmØ€‰ulgs1e]s,í‚SÝ ‚é ˜ –iE=ýV!é‚-v ôE?»ÞˇU î¶'ºûÄVŠí±æz=ää©úsYÝ!èw«¦w«5cnîÖî®íVÖ©UwÞ뇄m"üw7šQ—~öû·u#{ܨR“N²±ÐvwT­òŪfÛ߸GºÆSRà㱺' >¤ÜŠy©ìÚ?ý›!Ü&Ñkö¾_¾z .½ “ ÕÖœUkœZváLM-±Ã¦½jù’uÈå9¢;uí¿º}ð«|æ ó¶[€ýoÛ9Ǿ~jKy,÷¼wŽBú‡([~Ê‚u ìËnƒ©ïßòˆµþ>ÚŽCÂïÇþIXŸ¶i_ µícppè½SŠ¡ÏØ–`¾ð±<¼òôÿ€•rH»sçBl)ìVÓ)Qy¾–ÔZÈ{Ââ’u¢^þ H{ú›·#÷Ð]¹€¼ßÄ[àA¦G¼¡’CÊ åœ‡¡¥šëµš„À‰Zù$Õלu#Ü×mÓþ“¹¯_!ï¹v׺û8ÂPÓ×ÊÎ6qÝ=å{»ÆŸ‰ñ–mjËÙ×µmpíæüªèÞ÷J*ùÞOè5kˆÜ›øõ§Ñ$5]pEØékN›ÚZË:!p/߇À9´W‚Šö%3ˆ:rˆ¹Ã⚤SêHˆð¨ç²¨ÿÑ÷š¸7SNIKµkÂŒ»4ÓÉWíÖV=¿¢îäÞ›0¸Mn/†hÚh±íÓÄ ŠØÈ'a=b¥Fa8„µ›Dy8\h_Ëk&0|xß–2 9åË_–:ï „§óæyߎ¨âÆvûê6Ù_Øq΃–¤mq‡l³ˆ ˾*õüZ›'2´Ø_Pð®ƒàã—Ó)~Q²7°ìâõ¡)K…ŽK,”û²:øø øœtAHð|²^d~9š­êÇö¹­…–nûá™×œ·v¸²Bÿá5 9OÁ´] ®™ÿ8!VÎÕ#u@ØÝ+AÓ£É:i›i©öd‚ï:£À-Ù^AÒ±·»_:­ØHÕšÆ~{XåMÊÕ˜ëB…½ÂMt‘1AG]WÈ\ó™sñs:!,&øYK»µõº~|ý 1fž˜›¨ëu&é$·r¡$w=ëÓ#½lw_…°›4×Íój+çlÍ»Gúr“uêÿ_M ï©’N-:¶öµCêf³Ã‡˜Sé›Q¿;;6Nn@I*Î~ú¥cg'4ëè/nEÐ'팺îrÒ™÷E9PÑîh·ÔéÐgÉï´‡ iA¯dwˆúï/ÅÐê0kšk<õ%òdÉ¡ZÛ¦-¨¤mZguOësⶪ*äšù ÒÞÍõÐ4®íÿ³®Ú}¼9Â:B?äxëáó=ˆàWm½^^mê|LzŽ›ÚoÖ)øûW÷þ:Û¯¯×øïìumƒJK·í|ØÚ_e,é”UdD ‡dsü÷žlÛå’-÷ð¨ãcyG1z ?‡ wõ7ïvŸkDÀµ6æ´ i¿t>Ù„´‘”ÜT­yµPÛÚqæÀapœkÙ¦]U}îV‰”Uó¯B¸“3BZ;ÄÜ$:× ïÓñvm!?æRÝ£–òÅ›éF¢Q__%Y­œW{5ˆy?ÈùçTv«éöwÚ¦u+5Tò ’Û?>„öOyÛiï*’{u_„]Ÿo¢ýÿ§×¼Çþ^x­ö;á^ïòŽõ_ûò{i›¹Urÿþé¯÷«@·Ì5¶M]dÚëzêÑ7q]ÇÛE‘m²¼ÏŸ9ŽßÏöŸ=· žÚq>ïkwÇÊ΃±ýÿcMar7ð¶iì ™¿³Å=%/RÁqâ ·’nhõ)Ëk»r”njÉiM PÓIh‡ÀŸ»—PÉ9_7îƒ&ÐVÖÓ¦“N ®IY*þ¤@R­™˜§Î<íѸV‘Òîm¯íCju=ѵ«¯“¸ÑÒÚTH(œÖ°¶““N,Ý&2¾a±ÞöÜ×ö"åçð·¬åžã'éé>“vi?"Áþç·Z(gáÇ'Å}îµ€§TñpOÞkì{º½ÿ‹#ÁF÷”VÁûž2áľÿ¼.¡h: y_…Á¾>QÏq™–û”òQ`÷kÖÇõZ|b-Öá+8sɾZÁuÝË Þ{çÈÁMv ·^5ygˆ®‚m¡‘ lêÓ—¨G\õñÕ5Ži¾¸§ƒÑíœ>£· ÷Ô’Ÿ?|`ǧ¬uTû~Í‹zJæ ·\?i~(ÎmÉXÕw-ëàÂ:êu)ó‹oÔþ9vì Ûû}Rõá_›±ÿ J× õÁþÁù=׃­ñ„ ‡ÂY¨Þ´ XÂ_6 ýýPÑ!ê€8ƃ‡¬ƒ ‡«íaqåüÃÏKM?oñJë÷²¿G-/5¾—'hèdÿc+ä‹›'Ú¯µEKè„÷´d»±U‹þèEÚ Œ»¥}I¡Þ!æZ³ªN ¶Ú¯qaö1Þ~'sSÄ{s¬qßÕ¼ïùèò“5Ê%qeJÔÑøƒƒgXeXáˆp«}ð¸EÓŽx-íˆZÏórÍ]Vj”»íé̇MÉn'µÃ{X÷Ê5-ÒàÂqp]ºz¾7ÍY‹ý3BðYÉsó"ZÍM@ÊzåYÛW§"쇟”t§€¿-‡’®ãDÖ!ä&òØÛzOçË>d»‰ùWôcýt[¬¡°Q¿¬lx¾0‘'Ù=Vô¹qzîc,‰±/6AÏ6jIÐaqwVÕsó§}"ízíÏõû¸z{ªSCi•G¯Ó(pCŠm~Œ©×$\i¢®nZ²Yq?½ùn5}a«¬í°º™×œ›jÑ æ){l[š¼ŸÚsÊøÖüŠëØ ê¢x-Ëk“F‘¸3’¸!b“¿$ž„úm I†\O­z§Å ­´ghBlW–rŽç}ækC¼×Ê.dÎëøYZÉöåšR‚Œ€}§D]ïÇï?® È9A”)øs‘¯NÀëy¨TÎj8ù Ùµ6ÛS.²D}0î–”¯¤¤Åõ䣚kí?ëæ1ÇÎþŠ¹ÉƒEÝ:móYcŸëÎqq~\u¼òCh£)ô¹K»kijÏä^$œqþÚ"Ÿ:sØq|AÖ›œoÍ9–öXÝ‹˜£”{žò1¯·zNn ʹTx”só¬AÐ%Ü›ˆ“ÚnܾsÛ4êÌ[%O’{¥¸W¦Ž,캿©0\(åÉðažû£&â íÖtÿ•\ •+ê¾LbÌtâYÿˆÖ»ô8§ÝÖvÍ·ïù³¢ÏˆºÿyÈz»@QÑ3"®:uU">5ç¶¿'Õ}¨⬟s/„×O‡0á^ðþÛñ*<åLÌïjòÝÜpEáËàkM_va„eö¯ z.T7Î;’eaÇ6/n;ýÔ[ðª®÷¼(vžr´­â,À-D_Ò¶Û×íž`6^·„›Åoÿ*âK†Gm^âûĸ6ø`û‘é§}ÛÖUð}¿žzwÍQÎ+À@k|èÇfÏköŸ>ëVT‚äÂVw[ƒ¶ÔJììÂ5#É—§­×:5’ž“&ÐOU!éDœõjÝarþ ±ÐýÑëb¨µ‚„[QßštÂXv+æmMô6íZ4ž/¸ð {#pûNóØÛ;Ìf•ôj¹vV“îcšc{§-MõJiÁfâŽÚ~Ì+½¹¬ðVVV9¿ÜŽªCÀ7”€5sÒ3ý uè¿;óK®ó†ÏÃb9¶!C–¬e èuHk™¥!+èÍ’h–îQüB)Š&~ ØÇ7§êÔrowß¾U,òãçb;¼nˆ­¦o›¶QÔÇ®º!O:FÛ­¸LÖCÌ]o‘Tèk4¨I-2A d},¿_9d®àퟹ,g}Z[AØ!TsêÜMôŽ©ßM—¤¥sûêØ ¢3ØŸó/º7ÖùçØècQQÊW‘‡\W°P7ßamô÷Ï×}æ± –Ïú” ìëóLé@¶3R’€[áøb‡¨×ç'„\ä]ëú¬ãÐàsª÷ÐIìKÐíh ÌÔðyðµ¤ÜŸùÇßN®ˆ{ï‡#1ïïs+Ù¸{¶Ö\dzC‡~ç³}TR>Ôß“úΆŒ“!Rø"sm_×uÁë ’Ú»ß9á¤)ÝÂÒ w¹•×tºpÚ—eÚ©%ø …üº×ÈuÕ½®Ãª!÷~=¯u®áÚN‹µ¹æ, úׯ»ö|òÇž1qrõi¿îRãc[9ÇU´’n¥\÷Wª/÷}ʹ¶¥î|qmW껈w—uMjže”ó÷ †³­V¾º—TOó­9g=íÖÚÂî\$æÖÚNg#wAbÝ)áˆ_u¿]\'}³Q~á%”í²¯°¢àп/¶¶(yWéÆñ-ôZjÃ=¢ØkÔ¶æ)# ÃyšŸæaÁ†Úø][× æÖéý B¬­î«âcS'Ð{[•§åðºOb÷‹sðYÞ¯?d½©UÐ!íü0„¿Ý°¢³˜ÚîúàÕiTxPÿc‡àœCú'ŠŸš…óS2¬9¬ê±ëŸùfn[ìûÄFÑ©ŠêÀ‡–”É÷ªè B/ÔZ­ž†¬G=独Äv3µû»æ“èžà8ÚcDi¯ùSúvzgV}ºJ^cµbsˆŠk­– 'Ý}ú¢W­–yçIu–é§žž¡Ô¤Ÿz×£¯zîeêÚšœw`\n <¯óß¹­Klyš£ok+ ŸzÿUÈ9cc’ÝIã…¤£¤G·Ú^„B¾7}I†ÈsÃY!r€@¹QÙ©ÓœžéN02ÞË(î:6mÙPԽߨé(í¥ª»6UdåÜVx‚æ2¢èm½z¬·Ûª­Èˆ‹Þšloû©%ñMŒÊ¾Ò¥q‰WÙäG!ÝzcjÕWé½ Èé_!ñœB_ê;ù"¶ÔÌgŸ`ÂÐt,¤¿Z‹aQßQ¥9â;¸õ€aÝŒMêëçÐ8ï#Û ®OB?/`þžÂ^ŸF¼|ÉOÐÿÉ÷÷Ô“K÷ûÒ6YÚ³¿ðX~C:%ý?´Jú’í „ cQ?…¾å!]Ê`ÊdÈÀ0ïï!ïÿÊ ;cÜA¶TÓÜg&ß…÷r>曈·â|S„\É5Nå ¤‹ʾ«†#X~ÖS @»×‰@j¾ÛÔ)³Lëë.Ø õ£kà ÔAQ¾ËòåR¤·i=ó´1Ûºl~IŒÏ:ÜlIåí†÷XŠˆcŸàØúÀ”Mak#ú}óËÞ œYöuƒØ?¯u+ÉžVós‚f?Ž­sN߆Xôò~i´bUÝ#þyÝ‹˜O`\µÆÀ¾Ôó«š{§«¾t»ŽNt?ƒÐ8êÎ}Ú‹“ÆK»ë¶²\­I4®Õ½jÀ 弈¼Óç_v¸¨êÝ’í¹)Pý7Y7‰'Ȇt÷$Ðê ?J:dDM'HgrÔô™WÒ®-Š×ö¾ù¢^]Û¿8¤úR“^öv‚†Hw×xÕ¡¿ÍaÝl~¶)îtSçdâ}¬c7Ü&I7Ú¥–¯z´N»暌£ªÅâ>arQÑ åÕîÇQÕ+T%ýToÛuë½iUtÂÞ¾œ:â ƒ”eBN ;êk¬ÎçëšåÔ®“®ó ABžuÔoꦤyú²ïÓÐ!¶!þà©ïc­&S/Îqõ—P—’_tŽíÔõ¤¤{»0½Æóûwùuâ"³:N를Uvï[ûþü .ŽŒ·‘ý H:£x :®;XDæ½Þ-Ðâj¡o¹Îuþ/ùŸPË•¼>SK.2nlû´!ä´ŒÅ<ûE-Ïw_Ù׫…å+|z›S{Î÷±ˆyÕšÿÐßÝyȪ¶iþÞÖH&Éç.—ªn øäù;—Wé:ûÝ›"â´ÝëYjÕ³/„=*ù(ç]sžýâxëÎ* ‰x’ÙӽŭXݵ%õåj™Q'LVðº`Ëú”ÕAÎW@D¬½lñÇàv·q˜®Žëž©TsÄŽv'&È7îF¢>îHe¹½®Ç€ûB–Ä]ˆ“SжԢ{NÛ!éS¦)Ô½¯–5öÜ ‘7â¾·F Û’ÛU„Ï–ñ æà5ËwGÃWƪŽ@¸ç!¸{ÅPÆå˹8g‰”Yî4ú#Éí”x¸ÞrÅgz¶3 ÏANÛÎk¹ÏµŽíS:?}åQÐó’TNøÿ³`ÁÛ7ÝX;ù¡æ¼^÷w#z'–ï+#1þ§?rŸƒ§$yR’mBÔõSÃû šƒœO’»ŽÔ³=*zÙV­³@å硊ŸÀyyÃõæ\®yïþŒ´и¤œ/%ð+ý¾)›{¬ïѰ…ÔSLÚ[41ç‹×Ç{Yª¹‚EÆæ>*:àBàP9÷ÖÌå\µOôD¶ÞŠ$wæ“ê.$ÝrÚêî–h…¸¸GºÎ+5=Jº–óä<$šœ'4R>0Ñž›T/üâ•ᇺá™ö3ZŸàjÔ½/©»Ývä]æ è„Åy¬›¸ôž ¿n«8 n,©ËÔˆj™¿Ýx·u‚2d}[²ˆ7ˆºVDýË%죖«µÉï ‚¨Øn…Ðs«ªCNÀ¶iCAßxÖEêé²7é‚ÐCÔGõ1›Ø½ÄoýG¯mcÔn”óQšÙÕÅ>îڗ㮹ZŸq‰f¾Û‘¬ãX¬ê>¯ÝäyÒöý{d¹Ök$Q}~ïXÞ½c¹0æs•4uæ©ëïslõø/Òrμ÷½^ÀÖºN»´¸Zh¡Æÿ4íÒD´±¬ó@Nó&Õ"âÚ?õãθp‰ þüÿ9?cŠø?½pêhÑA˜&Õ½¿^‡ŽO»œHëQÒ½mB@Õ¹ƒŽVª£´kÅÜ׉ô7Åý“gµG˘ba×|Ê´Àä­¤”«Ýe(æu>í«eh®«v¹•­]êû\³«û‹oßL[U\u^޵@Òµ-÷ „+ë:%xˆ@seðØYÈ}ómm§\G"¹@/+Ì—u‚)ß ˆS¹¶Ë!i•üÚ)·@»û A”M \÷Ê:7J¹¥7^GEÏ}oá²^ãqRÜs]Dmù϶™Þ¶d-v.–¶Ø8eÀ„ÀQ¢® <ü.óg7ö™gÑúWð¾ï®/_" –4SÆÍqûNn„u”—Ê>nëîr¶¼°÷k>íýèÞõD¤V](ÌÓ¯Žýˆà?¿è&.ÙÕX’ÎÓž¢¾! Kú ó¡ã¤?jÿ·ç@¹ý@ºiOàn?­áIPtáøáe™¤V¸O}à÷iÙº‚%ú©U/‚®ã5ÔÖhd=s"æ¨èe Ò¾¨ê/ ‡£Õp0‡ŽÁ¶Dýºç;ÝÛ“×}þg÷\¨wŠªÞvwã"è¯mÓÚäQ.F\¤¢¨Ó~ÍHâ©Tt½E¢âÚ/žp“î~¥¯¾Í…¶RÜsQŽª.T]ºg¨CÿKÆÔ±iQ7IÇrWжÜX  5›æEνþ}© ,ë5_šÀ¾ÒXímŒR6‚¶¼û¦-jˆÔôô%ì?GM¿ö39׸V÷iÅfU’. ¼ßIÅO«v½Û}úâ-ó“ú¦.0‘·‚vw¯m,¯Úi·ê›ýrì¶‘Ûí&íåxû¦†Üê¸þ駱£žo©‰‰8!‘Éõ,c]†”Sþ 8mƒu·ƒÔ97ðÌk;,ã4ú"siqYdÜŠzóÏÝ’¤Wmc×6]G(]Š“ŠPRâJQ¿÷:ýÌ=ò0Øð6Í _r.'Ù[®mA)ä„Äi¦žJ˰¼ûš]-S½LýyBa[-wïq]ë=úaÕ”;Ç  Ï%x Ǩ¹ª+w)߈YOèö§ÅšÖe]Ï}÷^&òÁÔ+é«–çž0°˜3ÁÄ{ŸI_óVѽL§"Ú0D¼ð )~£å½‡ßNMá„gw¨s&Ô+ðÁ¹ l?æ‚-GàXHûظY¦ûVáb}æsëpæ¥Ú×qKø9~ÕË}Ày/5‡’H\Yf]‚@/wÿm!íûsñÚO"¹OAÿñØÚn¡ê³ê´Ç©±örÅÑûÜKÔ ÞK)Ï?mÜ„ù#2’’Îû)×(L´þZ&°‚èw]¯·äz”oÞ7ä™'jýØÞo×}B¢˜“î.$ÈB_,ùâAI§ä2nåûZ¦v'O4CÐe3LÚ´™íùÒÕˆªî'Ÿ ý¨Ztr֭ʧ͛têœLڥ—µ RNêèá NêÑWQ§N]ËRÒS“n²ŽºNº{ÆQ“Îv.Ê A—½MsÔ§OH\‘váìt©LxwHúÀ GȺCxDºic“9êQÕE¸56NqÝš-$~[®AÖuãçå±¾7ØFý:õ–ܬ—›UQ§³R¹‘ŽBu<ÊW[Sµž¹!쥒ӆÍû£È%í¹Qø<·aU(îzYï¬UѨUûC¢t·As"k¬“ ?±Øî¿®yaÕøìÏ:çXëµ­äÌa·ÏrF8êýjÉ!ülGÍ6¿{ˆ_pR|'´ÏŒý½l(¿—!ãv5D&]ý:lÝyJDÀóú!ÖÞæÏÅ*âtЃ Sûpölßrj›ˆ³ÞéìkSÇ­V]/ç‹p.cáaµã"Õ•cáuîõ6”ð~P¸á–|Ç}ÿ@{4€õÂ_¼ãAç&²÷¼97Î íBTñ(å)ƒÚn!tÁÎÞ®-®O[c®íÇð7?¼ž¾çB®µY6áÖq”™éÚn¢~êÈòX½¹u×yèwŽ#O÷ BÈ:@(‡¤D²'ø­tÚÎRcNø®‘e«â‚”n‡{÷`×âµOêÍ‹˜³.Bíyþ9:ÞuçïÒHsYgÔ6 B ‡£Åš·³˜€ï…u?«‘ÀäÛxT„kmZ‘I,½ÁµœpøÉò¶“ËyKx!£â%°+4ò¾8?ÄtFmcŽŸóàÌþ‰“™y`Ž ¿‚4O1ú•#¦V^ÚY0 ¨™ß…å¸ðÔ)©®ì`UÚýòŽD·äûQu7†~!|Û¦±Å–q+©pk9t^È-ü9G‚Õö ¿?a\ìxÿuþ è×^{F·À¶Â±^¿©¸óÚq¬íîNš;¶öŸÔÓ‘úGýù´«`=ap÷¤gš{ü–/ÔzRe+SæEÆ«/:)”sƒõ•!.V&ìCÎ5BÌ­ Û^¶éîôux õèvŸ“>§§¾éºP«'*$ý/î•^$Ý7Y®¶kƒ¤¸ï±Â㬲×Üggh¿Œ¶vR®0xbžšô!罎ÒâåVÖ£ªÿmK< ÃÀs}S¹VO 9ÁêÛÏvÑé3 9÷ö@ç…¬›ì&ÇH=:-˜ŠÄëßûI-˜@¹(éQ÷­Ò¼—µ¿×·—óZ©+f¾‘_7Dжö¤j‹¸…Œ…tylëü¶lÓ¹åX¸»ŸìB©¶CNÙ§@ºúªí®Ÿ[|Ÿ{Uf¡_bœP<“nã`+ï‡M¨éμ×ù¹ü>û46Ù¿þVú~eçB—9°éë[‘óúKΫ• ö;… ~…ÊÎÿÅ´(¤¤|Íö/­” ›!ØNçt”s9^ ä”ͪìw£j‚.¥™—£H —ƒ8,ì@ûjT)’F»œ°°§#‡ÖjXØ÷û?wTò(è‡bÎu °N† Ä[–vW2]Éi¡ïùvJÁÒ%]×_)è¾^o\®ÙØNî˜Ó>dØløIíâäó:ËÝNmkÍ-L@Ø5¿ÓXíkE¾5Vy!Ýup7 sßß±¾–w 4o5Æ™™Þç•iôÏ×ý©Ë'©9—h“}°²ß§$3ËA‹QÛfØs@5èØÛæB¦‡O ÛòÙÙ^J0û/–ü•®¾Â©±ëKFQ£Ï<NÖm¤—WªŸø™Ä£ž¯¥ß8Y×ó8ž¿«Þ[€O¸¹È;?ßþÍkÿ']œ_’¾–™çDx=õʼIHô)@.cÕrAÀZÌm>?#Îu›†~®O‡ôò0c_{‰ïZ×÷ý”úŸezý}ç§M£ØÓf­߯P¬%¨g]_2±ë˜¼CÖÓfÂ=i-±q|2nªûF}‰z~ڮ鵺íÚËSëµVøô%FY÷|©cŒ&õ­ª«F5ËE*ñE}­·„Z‰dÌ7 ©l.‚ýÀ:#hµrö)µ´Öؘu.Õ&j»åµÕY«ßUÈ§È²É óÝŽ^Ü!ΣXñíZkÖ‡ð÷>(ÿyo¶¶ïgü¬±SZ`û|íëeŽ_ÒÎy æko;ú Ð"-£ «;sü]Y‡\ë÷1Ÿ½îJ ÔöŸ)Í@O[A£ÃÜ ¶ã:1gœà·ÿÝð7Ú'‚n—öh:;®ÍAÄyÈ÷è–iÝãÜÕœíÔšUkþùÚÛRÛ’ïæq7}†ãiZ¤éº  ÑzXëë…Ηë × îR$rn‡˜ ]¨L•ÖÚnå|[©5)s5TºFë4_›MÆkÌò¤¶ÛÂ^­ÓœÜn›»—qôÙÕ7Ä<˜´ö‡[ãwß¼¡îÜíi½wâËju , pïÖbKîáèîóRx"®9·äÕA_¨ð»`3“¢¢oÏsg!‰h£ªoû4Ý;¯Ý½{‰Û ì -áè2fÛæHmî`Ÿ!”ËAÃÌ×Fo¡†Gíû•¿ þíúr:xµ¬ùóÏÈà ”óî°¥1øÀŽçäšñ{%@®Ê›ç½O­ü¤ÅßÔ7 úH÷§'"g_ÿ‚7¡èùV{ûõ8w[Ð;Ä.v¶Utû5× œê5G²ÚËSƒŸ×[:޲=-Ó*$nKÎ-ëÀ’ìM—ç—p½Ç~þÔžûwìºt)äú±ª~­ ¿ú÷Ÿªö\ûè)£¿¸î—¤¿ l£à: ó¯ß†”kŽÔÍç±´caÊÓÓªG÷ÓVR?ÿôÚË]Ï4J:Opua¨Þœª+×ÅE¤\ËsQB=¯e£ÞMºïŠ%XŲˆ:ÛPM —›°VXQdQä½Îœ@Zrè„ÙVƒ·Muö£|ŸÀ>]aeÓRÝVtlçžo…Ÿ9ÔüÚ§Tôk6¹Ï¹¼¦ùŽ¢=+·êÓ>¸&X2Ÿý+Ï€ÏÙðýÌQwŽJÈ’ò!ì·€EÝ®–ñ/Çåt›´ìÛIìqÖT»´ô)‡Žç@ó³û‡¤v“ö|÷ýñå»"ßÝÖRc•ÅÅDBû݃–O€ ÓBm]S!ßþIï¾ç(í\—´œ°¸$¾{½R׺RÉåZ+‹ûï¿yãm!çtXIZûßjÏû:êøÏÀ]%n¾àº_ê9n<Ï•8À˜œœ%ç`È:öv)åo;¥ýš'»'NÅIp1F A%§u.÷nÛnפ=" !Ä›eÔÁÄ‚ÑeSÿI㥴¿‰Ó3$]çD!ÿî[»]¢™³-®ó|7Ì!šD¯ ªÄ·:A¿YÅ1ˆ­GEø,DÎC‚)±eßÛ¢(méy½Q¨oöuð³S#>èÙI¼Öu··ƒÖ­°¿.Õæ¶ÒsHÜõƒ%kUo==îF)‡j¼Ý¸½lècƒ’ íc@‘à¬oà±ÙÆü¯Ò~h‘vÛNNXK<ä|Uøsy@“{su?Ö‹úP—z¾ªƒ÷BNv÷“ÄØ|”âe]c=‘|>Aš¯z н)3BÌ«]Ûó•'¯Ç-^tX‰öõJë&ê©Gç‚ÃEK—ˆ»/TZ—M½’MõTY›–%VÔ5–Å,Ä[ÐrýѹøÒ=ué•ìλHølO(M¶i”=>5qQÏKE×þI©R‡'ݵéEØÓ÷uÞ³^sŒ³zÎ UÁj:ÉîŸ9\hmŽôT7I'˜~éÿɶà3ß(.1‡¸g]õ•±²sSë¹mË6@á²v¸aî9ÖQؽ¾öVˆøôL_B¾©ðôjîžÌAlé¶ø|õÅËwi¥õq!FQ3ÕVšÞµkÜ9ˆšŽ?)é]‹l2wVÖÙ/‰Ýçø&ÝMijoÛË‹ðžmæìï^ä&ÁU#¿0)%éÜÇ L³Îëu½9Ç¢~—^ ;ëUgÎ:Š9Ù¶¦k¹~ï̱®íUÆåð"úëKÀêÉQÑýÙÔ˜ÏUH¹ÃÜüÙ¹ ¨âùüÛ!°ô¿†"^à›ÆäCPzrï¤vÜ3C̵97 D|¿sh9á•=xÂN Ï/"ë!æ§w÷¬È9®¦}pJ)RZªÉö^b#çÊ/ñö÷ ÕµB˜¿?û7 !Y'Ì´"Oíùö9ÿ$–w½® yFJÇh±6 z@KTÅüv#±ÝËy€?½Ícq/¢ž\›XÜï ²M§îÁy; ã8Ô½NòzT¿Níy”szžw©aî×È’u«è¸%ÝÁ¢nØYY}ÎJkOxñ¯ÿãuÂÙÂ~Ó©hmî][û¾²Ü†ù%|ð©QdÉüÚ4õ=Çc{n¹UóŸ}00åÂÙ¿8–Á>×r §÷ég:ÕäSül”íAo[îÅ{ú¯ùƒ]=µú|+°æ¼åbrxc}2ž>Ü~R²?Ô’{È:nóc#|XÝKÉ>Û Øg­Xôžd}LÄùÃYÞ%¯µéî(å:G¶—C¡ >˜:~ÐùìS™Uÿ HÈ­í0«´ªMAq-<<]”¢®õvÕºbuêÔÎQÕ¿’ð«ÖH ºÖËþ>w&î¾Ø^¥c;0Îó@¶ªg\dh¹Ö°•KÖöŒ´# Y¿Öu.ú‹~ó¦ú¡lf:/=I¬ÝÓ"n‚½–7ècqEÈo(שï¹II_tn^XÆæîÜ´^Ó:€›(‚ ¾æÞq³EÐrÈ:õëÜø1 ¯œ4¯9HûZ2I žm!èììîüT7¤Ju‡¼ÛzªÑçÀ–Ú„íòÜTOÒûæf'Lôg/Þe»¼ u¯!:"2Ä}Ãä†Ð”MxÔó%ä(0Vä>dÏDšÑËÅÀ!ìîÕ>ißQ©kßZvÈ/}¹c_gÛûU¿*|¯ó&çó`GGqïp7a_gÁkaKmç÷ïÒ¤ÖD|ˆômIn·FãïV®>+83˜;’õÊC Ìbȶœ#™§¤ÃÇ@ÄÛIr*/Ñÿùnk@”¯Ÿá)Ž·HãAYG9o§NÚ°ac‡˜'ׂ9:jÌ:„ÞðœÛM¹¾K´õæ<O“v«š‹ ßëû]¨°Ù.»;¶v¹\]ƒŽµÝÙ)!éiŸ&|¬€;pC×àçÔ™Wïs_'e''ðë(ëVã™#=n6TtÏkô5ÜÎ;\r=N÷Öý¾LÒ!à‰#•]6u‡ pAÏs»é{Ž+±Iy‡õZ%'3hð²êÎ7ˆZtÔrtÝ; %N5Èø7VËA¥µ#:=§Œó£˜»ß¹S»G9?r¦Îš¢v¼Éðlx ê:ä—}S»ܶÀÑ+.‘]â¼ÜŽvmEÀ·lùþå¿j>9\ž›Ž^(ÛØáÅçò;#m_>º.‚‡ûØSýðHÊ¿oç¹=É/èP×àtw¬é&ŒKz÷nJ@½]kû–ÏŸãP¿Oûü«^ôûYr»v‰ªcàŸ€}ΨüÌ3ÏS×b`ÿ¸0?×íÄÅY?¼žÁr‰ù–.PCóË1þ‡9OÜ#ýÑ™sÊeÆ='ˆãŸ®ÏµèF<i»FÍ6wã%_ÚþòÇ;í×|ðÓW}Y;Õý»ªG.{üO™çI°^3O†ïHq§?(Ë¿ýóõe}£,bÔ '=U‰ì©Z©t÷ö\€5BÄMÚ“äJô´`q˜Ì9ˆ†^«"ß¹ÑÈÈóRÌ…VBÚïÓvqïî©ëÓ±¶Ág¬›,Hù¨éº1¢ÿm[Or£Ô¤/úuž “sMätn8³®mÜкo:ÉÇ›îÞÊ:j;7Ë©ýüî~ŽA=·2ÎMº”6Ï•’¾µéVê±ÞB (ê!ãÔ¦Cf˜kk|-Cd íšÓt 7Ô!Ô‹m!ŠÛ{=[ÛU¯ Ï>Ëo¶ ©¬@:-·ÝÚëœå¹ûµc½Ÿ¹ÂEÖØûCâ ð¨úAýœ^.U<ÉñÔų?èßÕÔ|Ÿö‡X³“yÔs΃ÇDJT(¡ÿû §æ €KºÏaâm;ΨäY@Ç'—aJ<¶~¼ƒàB´Yg;¥*Áᢩÿoæ Ý!ö&åÌi»Êe<×€ O*;õç·¯9ÙYfŸ&äÝac‘œœQ|—o8h¸•u“o_;è B¿s)ëgõ|ÀÃæv…‰¤{=Î-›ˆûAùfºx(/áÞk²IyœvïÛ€XTqÈ9íZ™÷uçZÞ{“xˆ8÷4v VXœàVkBÆ1ºd°líîq¢nRžû5‰.Uîåï®3Ñãÿö?ØÛ+ÁÝ%”Ý>­ðÁŸ~Šz޽}Z g,åÜ$bnAk‰qê‡KX ›¶­~Q¡cÅG®m^¦î»zœŸÛ©!ÎÎ>{L¸Ñ´[Þƒ…}œÐÏVð\Þ²Âi‡…÷¸™÷—ýà—+l®Û˜`îsÇ.¿ïi]û÷„çê¸'Sãl•™ýY«ÝŒCÆEôõaCÖo‹;ovƒé®‘Vg[üþrÎ6ˆy¿ƒü|X؈ªÖ7¿ÞÛãn,ã:ÀÀùg[Ûuô"ï|hÖ­Ú–ü8Ž…R÷§&dƒê´½?d¦Ï#öžíé9·¡ ÕÚâÚͱ¸óKÏJR;M¶;DŽ/÷tî(ì\@LÆ×†uWéíô½@¹° I_÷E+­×艾#ar>˻αOËõXáÒ œÎ£ á×o¢¤›¬CÐÜTŒ€ùnÈ|ˆ»Þ¯[FÙ– Y)"o¢ï÷¹Y{» ‚¥qÛ[eÿÆÓ_^ÿg9È}HßõþÞ <KìÙ!Ý_/R©Qä›=e‚¶-IE5®ýtœÆì»¶ú„¶ÕöúYè)_©è,÷Ï»j´ m~vΞ÷2¯múù±ÙŸÊÎÐ9t>'¯ë¿3Ÿ‹-ý? 1²\ûæ3te#„ÔS^á×á!J¸Ê5P˯íQÔ5:†zr•zx¹êÊéW®sÛ1ëùYFI'NËrÀœSÙ±²·;B^ßCp )¯}Ê®þK©P¹‰†¼ËŽ+iÔó„ÄÕƒQí/‚mÕügê˵­Ü)}ª¸ATr@.JÞÆ5,!pŸè:|‘DÍëá³F”q®‰t‹—bNÜûÌi½ápÁ©ÞÜdÕ$߆u+ç [‡ »L”rr/x‹!$®Jþ¯?¤·ù«ê ‰ûí¥\»ÝÚCF)Ø{Ÿ†½½„™ßÚ™9íÕ$À@΋”÷<ˆP„‚nؾî{W- ™£].NÜ»6õ¼BᎲx®ÎdtÓÜkîì|†F<µPË>-ðM–˜xàùupKï{e9ÛÇYÐ|-¼ìpÎì»4¿ßÆ OB¥§m]Ÿ7¯Ïr²Ð"n¢·‚ép.úþá¨ß^ÆJÝ/’ñ¤F·:uÂ?qú!¥m¿Øž~l«¹ւfö7Z°ñ>ô³vmAÙâÓC÷{¬M÷ñ7ê'ÎMú9®í|pûüç'vmk·‚žÐ‹Œû”Ñû²Îœˆ8wž\’œi"®$w¾˜y*‚®e¾ ½þµÐ Tã‚'¶:'õPNn¿Îñ:ëFÒI¹ •íýw×1¶¹?tí–—u mÙ¤h£–z~HpŸe퇥Íužº£²Ó;Õ½ÓËòNPMêÒuÃÀÍE÷pÕM v÷Aÿ¡ÆnACpܶ³Á^i¤]ÎÇÏÞæ¦ Û¢-ï&ç? a/EBnU«å¶öY»;Ð\€ÊÞaIVÖ=&H®ô¬üíë&áÌ„†íÝ7ò$»á}|ÓM7Z5-oE}•Ýçòœ‰$Æd‰š]Tv`²ŽúhÂ_Vv!ê§u=ÐzHyˆýÑÒ Áƒ¼§îršZg‘gTsȸó{:µC]â¯ùXÕéñ­y½Þ(Ô£òW ±%ÆÞÇç^µZó¥öÇêáôü’ðÔ™wïqfoÃŸ×æ¸k~Ðxîé÷÷ý`e5’þÜÒO`þÇq|Ü„1AÿüùÛ&ÆÞÞ™­†_˜w±´{,R>Šøô11—µ]ÿ£ìãï–Ë…3Ë®'¸öcßuæÚÿ©¿³ÚÒ…à"ê¤öVË©9×wwHxB<…íÊaâÍw¶Itˆz=œÍòö5ïq³P°³SŽrþÑw×u†Íu“‚î^澄À±L0+Ð<.6Èzœn~ó¦B_‡°»ÏùæÓ q?À–ùô·eTnŽ 9bCÛÚ)¼Ì½’É8Ýt’ó#¤mëÏ ƒ“`¢}=ßáp¿þÓOqO ­¤ tþ1úþQç›äö_]Ê{ˆz¶©-[úš'ðØÀÚnržû`r›>è{äð˜`8PJ]…ÎãZëôÚÊI‚ïýÄóRwP†otÐ —I2ûcÝ#òzXöol^aYb‹Ç­¨ÓÎßížû6a?ç~Õßv¸ ÷Ì‘bÛ›TyzNˆô?aïIApN´C1žþ}yÓÛ9µëÔ!½¤¢£Ìχ§lø>–½Þ¦Ùß¹kË¡ke#×9H¬‡õ»\²]ûMMJ¼P–§‡ Ûy²4ɉ6w¾pPÍiÅv½ç´œÈi×q×kxÛÖ¢«¶Gêºk‚´ïëRË­à9בÀÉðØÜ]g„º^í::<.)ïCÂÓö#”ê‘."ÿúbª‹Ùï©U¯ÄS…±¤&=$>*ùïS›ÞOµ©Qïð—rêÊè—®‹øÅ}øõkžÊKQÏ9î*$NûŒ¢þqöAMOˆ\Âo2j޾èkĈR1·2‚ÎöWMÐ…XÞ ”m}û:=o!ድ¼¿ŠJNxQt–Q‚ ßÓžmoX5¿j9Ê|¶£zÕ½-²G5=!V=ßµìŒ"ø± %H®É9s¨è"Ï—Õ=$?$Œn ¬Î&á“"¯s̨}ˆèb­Ýà&\ ¡/%{z°áÏû09ö¼ eÍé5S{OK²©ùÎØ 1ú”×ëOº:Éðnƒ”/‡|×úlGY¿Æ¬Ïñ[{>Ÿ¹!à_V-9=˙úþéó·­”k¿zˆÅÿ€P}Ì!ß!ÛX×;;‚ÿKº4@àù_½õç:ß:q(Ål/<¢ŒŸÚ§©=%CùÎÌ2ØïV«å„½ôÅó!ìðSîI#šCÒ½Ž’Î5MhG™ö逸Nl7’“úòºÎB¾½_óÌwsÐký%n;\yÕFm[»×Ù9 Ýa·iŸ&¥ÝÄœÖj*í“*BŽñ—¢B.T ï{{ZìBÈ!és©ç´WK½9„]âŽÎUÔcc_pO‹“4¡Êr’Ó´Üh¹Åº{—§l85Ç=ðšqߦ†uœ}`Þ3*2ëæg'u¼9á:…Cðífž÷8„zÈó’Œ+Ún=<þ,€n;·åÐðNrÍø»k¹¹ØfªIAÿ?ÎÎÇŽã:Â|™dÇ6娲)y ’ø ¤ÌgKd-wÉ$/”)*Ÿ µíKäƒîéé™{÷Þ»3S]uê Ø[]}NV@tÞì‚{ö/C½ í|ðVyìuŒ¬@‘< ÎyŠ3ç\ŒñÃt`º¶µÿøáíß¾&sëÏ—ºÇ0oTŽÁ{dä˜ÆÀ¾û–µ§OI6â{ØtÅg×êdú^‘ä"ƒ^Ã8ÍyÌ(N’¥æ>€} Gœw^å;|q £^á±’q Œ‹9POmt¼¥`阭\7Ì ÎÉ“4=lz‡r¤m–¸+Ä¢kÜò9Vâ ƒy˜t縱MŒ£»'Z;¼«m¦\}â÷ßÝ9W¯Üp«ÜZº™Ž0ì©W«yÅP~ àîö\Ä}€-›4H÷ƒ( Ærêkß0I´ë\La×8vŽºtØ«y@nC§äzW¨ŸüRø›¥hÇhŠðkzNÀ,úäÑÂØW)(ÀHr×—)§< ~YKµm̵sôZçõ¼>Ll‡÷åØªáþµäÒ)éfà«q3éžæf€iXkI­Õ/ »€y]Í)?Ç6Œ{ÞKâñƒ7œ×ˆb ¦{¼N³ü¸ëûØ\qö³˜é9 ¼¿›Š¨1J!™[æ$ÝBãÓžç´fÊÓê· À†)pc®˜ý™£`NÀ8 ÷öw,’9å? Øq«\Þ>ƒs”5Œ?Cº^1Œ:×"U©cžë×xpx»‚Ìw–­ÿA×ü×ìÂ.9ü;]7í²®yãbæ–Ü×êTìh/õÉ5O94Ý©k¬ï++~§1o‹­þ^éRÅŽsê{Y˜t˜s@8¬9OìîÎ}TÕSphï}šßÆ®VÀqïV߀¼RÝ䣮[UµÎ¬Û‘ÝÀÜ@üX2¶Rü¤DEXåÔŽ†»lÜVÝ'<&å$žC6 ^Y»Ô”Œ9 Îõj×ö-Œ¼ÝæÈ"ÔW@2ñfª2klfh ³Ì1ÑùÕf]8ä@wPÞYXA ò´ð™y?GΟstŠòªÙ&ãý7.j“oƒú3@·9jîÆŒ`Ü6ݦdÛºáÇv¯û]†måë;·eü0èm½ŽKxŸ49æ«—ÇhMýÓj’Ž1“˼fíÙÞDûÏyd®ð7Ëüý¿ügí Êã¶ÌE¢±Î~ûåÁV7‡eO¾B—’k9‡£dñ#“8ý£2FD"Âø9¡•˜Æ‰9×E¨Z½Gƒtj¤ÛÞ%Øž¤brÕ Êé›c¤svú÷§D×G'`Ò÷Æ`·»"7'õÖʹqIÒ®€N3Enš Ì¿»ÓJwʳ)§,ŒyŽ¿Æ`Øqzw<ýö§äÈäX™wÎÛý©6ºcËÇlPÛUý­“þ샀99èÅhºÝg_Üß—-IÀ°k›¨¿04Ïl0—} jñ¶ëûÉ^l‘YóåÞƒm2“%j¥ë<–¹ë÷—QÏ1N0ßsë¸g2šƒ‰kúÉÐlÀ/ÐÂF[€ù–Ç/XI’ÜåÛ_½|?óÛIv™sƒC•áœ@q1æú”‚3˜4èÓû.§zØâ\αÒpgÅ€s î2l{=çdñ¡^ŸÏ¨ò»Ï¡ý°Ý ²Ðo òeÅÇ´-òu§4t•gÏïεOþS&-àœÚþ¿óÚZ\ãwK¾å éŸÒOäfŧo®×´D½¥ëvdÇ®Mâ2ÐC»rÍs½`ÁµìfpÓ{,V|C CÎ+´çš,ð>îíWk0þf¤í€õìÙíuâ~À»Úä’‡×1[ãœ(·ýŠÃ=pKª­¿‹€vÊœ†)ï°šM¯—û6 ô€q˜ð®ôF<%[¥Ð“­ú©£9:ö /Å @=Ï;[NY5‘!2xKßà€^uÎñú`àí¶Ÿå4Ž´ÝiôCøKØ‘¶°#k¿Ó¾ñPrjfÊ© ÆJaZ ö¹”¾™FhŸäÝ;Ž ©¹`/HD̳Á‹Q"Û¾mÎÍ8á™L¬¿[m“‚¤Ã, ›M ‰^µ· ¶oÕ®Æ m!Æ›Œ~ãÜIÃÎ6ßᓚ4  Ð;òõs]>$Ú ¾Ø’^äuÔÿtiÁ®Â°R‚K ¢ÌÑꃜZ•á8ÎUæw½jU+4]±2o !?êÉÿ¨scŒ›àŸ@qTÜ.€Ä˜ºéYyœš‘¨_ý\0=Ž{¦Æħ¦å椳ºìº@¾VjßäƒbWq‡9×¼Ü`ªv§rÔoóµÅ¬§T¬AºÀ»˜óÜÅšsãôŠ÷JÓ´?²wt÷'_òkÔOU{½î] äYÑGÞÞ­÷!e73à‡ÆÄ(gÏLÆ8Ü g\Û•—ž\Àç]«Ömú Ä=÷ÿ˜tê`Éy8Թꕣ~a&˜ƒŒs™tä nÊÉ-×vÜÞ56ŽïÚ®>¥r59’îï=§Á|þ†•ÿµÂù;8¦>ÃØ”ÍÓbŸ‡û:ß‚{ÌáœÆ°JŒ”þ+vö{ª l~C>¶yrÉGº^Ñ,9j³åÚOÛõÊ1rÄü Ï‚LyÊ£={u¯÷˜9:f]Û{Ý`›Å¾(v.výAå½My4®c´ŠfÓ¯V9åj³¸)€íüò)o‰‚ ðÍm®Í‘±¯Ü*¦.&üNsÔWʔǔ… Ëû®¾Xt•_ŠÆŸ¿÷6¡¢×|×b4 ÜÛoÍœŸK™²?÷€syÂøþ<€}%í}'0ƒ«ª0Wje[¯~ž1¾0yàó7&òLqàyÉ1§­qÅ2ä¬ùšÈàçÁMÒEýÔ¸åAŽRl‰¸#¥Ì\;›á1ÀVß`¦(½™öe–t¬$¦:b¥ïj¾ °Í®ŸóÌ·Oä<íÏü´ŒOŒþ:Ž|ØÜ’ú²]¬b1°’€¢ª½¹éfÒcÎÖ ¦`¯9œ©¹^9è1'[ƒ9@<ç°úQçdÞÍ8ƒþ•€ó(CW€xƒúó#ýŸó ƒ}Êgá¡û•ã\à`Eß5 4|—ô© Pi€r*tm~$ìÔò/íx‡tý°ð¤9Šç‰8«“W®2‰æ€õŽóí'ás gL œ9ü_ŠžCn9íx]øDTs½ÚEG|;0€‹l½ÆTU#Fp¾Æ¦EÆ>¾ Ùw…Ç-—œ{[×úl¯á(uÎw±·•],+Ø÷örbOøþ(À=,­H£ªJ€¹]Ü+ß<­À®×põ³âkõœö+¼? œ{.àžR­öÂiY{?8P :å ·}{`ί¶dî”Óž+0‚ss@wHÊ­¡¬¼Ê«ýµž MèPÊ·LáÏš~F ×6*QâEsõ=Ç`@|È7gûf€£š}EV=¯Œw]ï31WØ2‘ó¥P,{½¦áMÒ.»ìX;çžóò~‘ôx/œÉœ¼uèkAa ÔëCR¯1äó6>´Å¿ ²Ö Þ`˜7tüal~€éÈ‚Ùú`ú ¾Á6¯©Ã€ôÃq|V|c&§~æi™ºÎ»†}gù–¢0Žãþ~î|–ÌïX÷z^‹ Ö ¯^©eUQ‹6?b÷b 6œÎ…Så,t1U߯q%GªòkŸ_ŸSö\s‘U \€=ã–4+|‘¿Ž¹9è¬þ²2Ü}\Mk•ù·ßÞáxúÚ =ýwß¾oÙ;7KIÛž6’°ç†Ë˜æù5Öì䦳ÿzAy;à¼fmh£‡ƒ»ÿ¤¿|€Q8¹|j×í]rÃ’Æ?ûynr÷2ûCrª“n©ûø<®ùyéã"l >æqí1÷ʵt«=KB‹uG¾nc§j–©/ßJ+{·4vsX ¼fç Hpu\æÁøÅ¹]±9êp´3‰txÙuå…oþ°·§4VjSk<óÖ¤.`Ô|o“»®(€ ˆ_ÐË~@4@–ºíË,/°e.䜩9€YçÊ6õÂÖŸëO•³÷‚ÄáÞË¡V>%Ì&F5Qã(.¨ò~ä,ÔˆQæ·§(ÀŽ„ß%yåüÞ‘¢#aß 4šÃ¹ñg¾`z "õì^|ó@®¼¡Î!Ý…ðuÇ×'¸¶1¹T¤_¦p¨‡èzÀ¹YßßéZH]ó³ig1技n±â\ß[枀GÎÎ"ïÔ<ïûOš–A\Æà¾MJ—•feü†"T2ßk½PnNªYÕ8×½] ÷»;pîí”S3È~MzTvåe³øæy#`]ýD _Dí÷:àüûÚ™=äFúÙÖ¼¢Œê€óüv 3)Ž¿þæÎσŒ´€éùÑoœú‚rÇäp0Ö ”ó¸Dð9ð›…)epp°wjÀ¾§ÔÖ«‚ùýþÖ ‘ý[rnÕ £ºpºúj‘÷P}äîaÒ7Ž&qµâ™’kÎC*SÊA˜§¿á•Y_ä¯ÕZƒr»Ä«TÛ¸Š„—‘œZIÛÕ*p7}ýaë¤û¦&39mâÛh¥n’6Œ+&=²5KÛ_$$Wÿön™tíÃåÕ«îzð|µ ½brГ›®}€ô°° ìºeö~àùe¾_Ë9`0òpµ,È5Rlëâ›Zꀷ”2ç@òNþ9¬Î†æÔƒèäTR»–]ã Êm¼ô—1^ªmçšD—^s›U§~1ó`Ù<ð;|À¬ÜÝ#_y®Çè[b†}@âK¸-hzw*Ѷ€­Áž;Aöa\çó•«÷€ä¼ €öšON}1ʇ$¼Ùnê¹sœBã§œoïÛow毴½ßß¹þòúU_^û¶¬?Ë×ó]Ò®"bU )*®¿Éçâ|i9ÆŒ7 œßà´qfŸ}°æÿmõÌöü$„²h,:¹äÙõ?º‹m䙳o¢Ì&é+†5†Ú8¯£èiÆœ¹åÁÁõïú”Q˾lù¡LBÅd™; §¾–cš”&Kè¹'4kþ¦¶éà®HrEÛ Ò)»¦ãd¢p®m¤@×¶óϹPþj ;XáÌjgZÌâ\ë©{Æ#gÇÇyXk…>¿qI¿¶ùË´M±ßƒÂ¿ýÖ<>`ZÇ!cÇe}‡Vµ¡ýêë·øø¼2v;;°Sõ`ÌÕïÔâÌ–ï˜^¯Æ(¡Æÿ쥤ÑßOŇwÙ Úä€ñ¹Ð˜¾)Hûi‘zÌÞ:È)O›…Ö¤K;ÒvµÌ¡®ù,ÚŽ‡ &¤€ñ+¸ÏÄ#%Þ*€oKלgá9œ>ª2®K¦þ'F@7Ží,Ö·GÍÖ6PNóZ³õfÉctësžaÍkö\Û¨ Àä„Û ·Az¶­j´C»ž»¬ tuž+ÇüÇRDæ9OÇ5{¾JL@ºAwúz=y'¡ì`‡9WŽBÔ¤&ÉÆ4˜b­þ¦ÓžðE¥Ð dîkÜ’±CŒ¦$5x©Ï³%£},¦×ü½iyý½;¾2sÞßë•+ú,Dpî£L–ù|ŒmŠñ_Mñ‚«†&úæ´ŠüIý ¶VÜ|I³*3/\Ið·@l€a•hÐÎ~J‡MqýéϗŇÖÀvßË!ÿóYvr$ŸM ¾UŸ¯VwP(4ó¾n‹ÞæoÈ߸9+ÌY|~üÓ ïþÁÂcõÍÏ!²Ùyè]Ší%Îè’8ÍE@Ž1ˆrbÇEÛ2)µaÌéòuó <×}q˜óßè†8wŸr"ºqšA¿æ+p;•üý½Úuõ#93ó®E—SÃÝݹ蹓—>Á üéw˜ÉôŠ<ΰßÔX P¯R/Šy™mï’ûÝ-ã@Hf¯)oó§e;²p¾gfÇ‘·7_'`Ÿ¯ay–YO^:uy€Û¹³$€ºöÁ8Ùp.ÁCqõ0YµÅ/ÞûaÛÒ÷‘Ãùü½úÍáúÌX×D@ð vó0Š„ç0Þû Ö5øÊ¹îÞÇü³¡×²­Ä”êòœðj3ŽÑ€}ÏÏkÙp¯nÎ ž± ^V¾$æc—œùÙG™³ô˜ù[ï#3¨†7€<9òŸóÈõÄÎ/«,:õ{1P&_<¿Eo2ÿÌ–oÊ…Øëå½ðÐü!¿ö©ªP©$S­cÕ1¹>æ2Çüñ»Ÿ8Ž8/þ‘OžëŒXröíâbm£ð©ºÚre×ü½¶Ö"j›{v˜ã+²ÀÜU@Ô&¸§{^¡szßAõu¾‡€»¬lùu|ÜÚµÏ`]ê¸ûÜg#q¿Æqp×ý}ÛÛW&ãŒ9È9G1§~žãDåžc\ÛDÂërk×ó êÀ+DRäÙ§…N9Ĉ—|óumec']2—g¸(& ÜÝ’YfpÈÛËÌX{npÓ7Õ‹äEØý¤í”k|Xnºkƒ\Ÿ(‰Ý.ÐL˜ç¼ôQ#ÃÆýl2Gú-Õº ?µ+úŒÿÝ?ÿï“XÀºø&Û“f<˜çH‚Îg„Ľ™vÅ£*ðÍg?’Æ0ëTþJÿ&F~ÂŽ­w΋3¾lwï¹?ˆH2†­/tõwÕd2ÿ±¾çO^Ç0ÒsþqŽ?—@²²?Æn™ÈüØé+ù_©Ë¸¸Ÿ F½à Ÿ—Ï–àÜõ9Õ¼HÛ£¾øvÉÌ*f•³ü=ÌùÔª|3gt Ct‘¦…)oÓ8×´äà±êçaÓ‰‡^9Ίñ«-Æ‘Jt÷ n”ê;×Lá>7Ï­“þv=9ê®kZ¹i³Ý@]çºÏ±?oSî¥ë§ν_-Nïqv'œ»n@g÷´‘òЮèœtIá1«Ú¶j‰Ý0®Kcà‘½/û“‹£óZî®×b$íŒM©¡ä~Â^‰©ŸœÏÚFªªm›¿ÎËL.€ÜûÞ_¦€ü ?FUëS[ÎÕg'x]@ÌÊâ7'½ÜÞ‡9çíÓ¾úO$Ô€Io#eŸ}ú›Å pEÂpŽ¡ÝJ¹Ofi+ÓL¿˜þ¿{NþÞãk‚÷éó´c÷ü oÓ·ƒ¿Î©sÌ÷ÀßT@ZáïZäëU€úbü ü›p”Ükÿ8­³À4ic^§i$›'S·?¿¼÷<ÌÞvጶÓ\zõ ¸Z‚qç¿{”Ao Ï”_ï5%Õï}d1“±´×Á‘~DéLP8µ­–ª’œ ÜÀï¤bú–Ps WÆ”_î~—>åÕ|¯Ã±½dìék÷Ù©k^ìyž’ºFnùkäí Õ9‡Q/S¸eÓaÎÜÂÔ[æŽBÐà\ à­q…SIP˜Ô`ßíZðS¦lâüy„·`ÿ) ÷JfÕ뼺„Óû¦¬™žæñšÔhôgïÐxV'aБºk\ýó˜y„EHW_Sç«ëbØ‹89éqko î&\ô®N¼¤Œˆ@9.îÞæF•\-µÈÍ 5%×|ƒ|žÒk“ž9€ô®¾ ºAüÊâ>úæž\ôeÌÕ'؇C-!¦ü–•S¬œ?5푟K‹®úó”:L'‹¯ï×ØÏ‰÷Çb…¿·w|Ÿíª>&ƒ£º`{eÖ´ŸLÞ6]·uæLn¹ÆGš`^#7³|!0süŸ(eTÙÿwÒ[4ÿõeÇO)5j1Ó|cÃ7µ»¹™š€N¹4÷‡-§÷_×Éij™§Uèú¼=@>Ç£šš|óö€p ¨3æû‰Z¥aM¾9yå#u[¾á{¤[­÷> (ÏbzÄm° Ï=ÝeV·ªKÆñ¸ (Ÿ–ÅLl)©¶ÑÏ:kh—!Ü–RûÕE)†Q7îür;¦ç9McIS<ƒt\Û‹ÈQ$~õï?a<,úoªI$þëïô<éçÓÄáñÄ0¹'³íÞîçñ-1Öq2­^ö¹ñÙ™\CïÅ'€Ç2gcÕûg. ºs°?úYNÿ19|cÆ-ë­˜2áx~UubÁþÆb½ªcÏgÊ¢ÂóÎkÛ$n âj€í©ë}0Mcedþ¸3õ¿ÖúËPŸëù!tî*QzÖÙ-Òî5_ã§÷äs×뎙Ãü]kÈ6DZÇÙ¹:æ˜;Ôñk(WîýkÒ‹¾åö0Ñ`Õ ¼æi•Y#4VÛ徉<É!€~æÊ{z_54KFõjäSnÍž¨+,·²«»$ì¹áâ~ëƿÌQ7S.°]åJÒG:F¤ÐYÙvÌSß´do¬¾·TÓEsµç GÎG‹cí0ìäïU`(@wl 6À{\ਫ਼”¿…EQ?‘í€ò?<¿+Ù¤@9ú5‘ƒ‚­ùŠÜI x¨Íï2èoõ€Šã»Z¹»Ì}Ç÷äs¾(ÿùÕ}€süµÿêkwµ~Ð7wt‡@/gø?=Èa_Ž™Ö/rr T7xܯa:OuÖÙG)¬üS½ê9oäòžw›U&·ZÈÕ9Ã0S·›ã&ޝÕçe.ÁbÂHö—Ñ?ËÈ·ž¼_ bÊ7x]µ|”9ó8%Ç6ÿû¶‘À[Ç·C»þ^€:¹ä]o¼Ã yÍ1B¬RiüÞ«:ÂúCS2qbSR¬˜ùa*10ß×™qg¯ºæ­ÚÉ8¥ÑªÓ_ Î~Òy|Ý€O~ù—¯î#w·ikš§ÚF®¿“’¤ò›è¤&i!7ûèRi TœOiϰã^n@®°WJú+iWä^—{œ[˜uíëû¦‚1ú+iïÅu*²`òú§vr˜òªÞNí+k§)\ƒó!ºÌ¬Áº¥èjVê™ÈêC\Ú‹ôˆéÛJÚ}`Ü}“3É5OŸtFƒrµ°äˤg¼ž;ÖCµA\×6¤3‰„*ârË(Ÿ EZö-¨ô6x„ñU ‘Æ9˜4Ón2psÊÁbÝÙ.‚nñ¾—Æ”¸˜=¼k‰þ¼óù,û{9»Ðcìo€QzG}À¯‘ïiüÄßûOê‡3+0ã°ÎwóWÎÀØÁ4`\ adÛ=2h{žœ¿óÎ.ˆçU›>žÎ32r±[°Ý–þ¬­1Ä2×ÕÏßÃ91ƒû$¶žÏfÌðNÒ|ÏÇ‘pK | <’ õÔKï2Ú'ÖPn'MµÄsJ¬]aÆ|%ïÚg9»¥VÖÒ1‹¤÷6ŒúÓŽäS œ×¦ùƒt—_s4O)õÓR¶¤%ï2™ZZËÚHÝcƒË;eZë+£+Æà>r¼bËÉ][ź¸;蛕ðXJàuÌ'¸^¥¿àfÜ©@¸¯{ÛNïÙ§ë)iD”M›Üò\kÔ6G ;×ñY|õñW_Æ£®Â}ƒm€v¥…bùhŸß«ŸT-ÝZ-¶ :ÀXO—Y 'Å,L9~1u_x빃2¬µ@€Ž"¯9áý. ˳È!bW)}ÕÍXÌuÅ‚Kâîí2…CöÞ*F9Û:Ïtzv€WË©Â7¢¼˜_l¾ûrÌâŠLRŸ’°竘E>eÉ‚u"A3&ÀÓ%&CScolk•Œf@3ó{®ñ,Ûy;¾$ïDcŽ›²Ö•_Nÿ”Ó¾Ä/³½ó"Ã’«ƒ%Ó*žJ@­qHÛÁWâ¼ð®°y~pÄ~€šï¹¬Ze €å×oŸ"øÙîúìw¬!-ÉöÖú‡qìð{!¯Éq˜<ÀÖ3¯Jl»ÿxGõÂÈ×F §mZ¾Û’ÑDq0+‚lïû¤L¨Â’£¸g:è¦q‡:éÚ“Îj) úæ(MÝôÉKÕå<’…\ #9m#}78ƒþßü$¶\s€©Ý }Ǹ¡v Y3Ë>åTn®1—‹éL´M=U³ê˜Ñl]ô*%(ÿÝ7wj‰°€sÉÛ¸û!ÈõÒÉ;‡=×9ÊTnj¥0Çõ‡»™Û’÷lO-Þ¯\¯7_ \ck~Ôe„òPé»Û–‡n]uøa¿¨S¬ý„åu4f°H÷œ·Ÿ ¿¥¤›¦r{ŒæQê:ÿ‡ŒhÉ9Úùº]âÉe;<¯Q9¾Ã‚"Ç Ö4 Go¿NvÏ¥]ÐÏ1HïŒzKÒ XôÒù0ÛHÙ5ö)õÝ—Yß 8@½€>çé¨Ï©öE²_Ÿí­pO^ù9aý´]çʱ:·ÛßùàÞn »ÚfÊ÷Í`–÷ÿc¸ð‘¢ÏqœëëM[IsnöškÂñŽÝ× œôœ€sJ«ùúrº¾‘gn?¨ˆÜä–WìõÖ×ä)­‰œö1®×,9»Ë¥©çv*‚h\À0/#¸Œá•B=s™›ê¾‡\û°|Ç\u¹ÎÃý5€0~íGÝæøB@æÜàœÖá{9®í~V0PG§6̸ŸU¾½ ;îqHÀ;„CIÙë8¸S¢6íÇl[…KÅbÈ’ô¥†t™\ú×ó%uÕ7¸ö>Xrʪ) Âqj§‚%QzÎ3wßû—æùÛ"wYñ•¬O=îz®nâpà .‘Ç{¥ªUÍûè·Ý}XcpŸC¿/7å´ÿ©Ãø´ç.à_Ó>bTÑ…çÖäŽ}yïGåù–³ÃŽ~ LdÊ~Ypdͧèúå›ß®XO0Ölö²¸lÓÞŽÍW€ý?ê·ó'ˆeüÙ^@Í—kFúìx8yË ¬DdKª)V6êÛ:úͼ{% æ½êErlY{ËÝ cð /‡Îä”^c–¾@·ö|Cç´¬}ÝÝYÖþ-½FnVÊÙéýÑ"uÓÕÇUíó ÷5ŽïÔLl§¯vnæ˜Í¸ßA½tåÅùÁ¡äíG6ÙßÙ8ÇŒDrù¦žì–²I¿Jäh.ÒEXvÚé‘1j ®mSOwYd˜š×lÏAÒyˆ<ì¶ì©hú”+z ˆÇYyB&O؉QÿªÞ×{Ö¾Ò„ÎÉ~Ê·‘›Pïöä-7³+0dpê®k ‡xdð°™Ôž&߀#yÙy€-ëº ÆýlJ·Çèq,Feçñ¿]â‹<óu&7[ë×ÇÍÜÌ÷‚ÞçµaðJžw¿‡a¿Ç|íÓ¥éu¬·÷sóû˜so }J™µI!¿¿±þ]0_ÁbúŠÇ¥hé×¶¿Wî¹Ë¡éZ‚Ú„èóž*4œý*è×ÙWÌ8®ë¤Ý(2žþášf£·¿Œ#;qeºé…YäìïÙ®@ÉÄu¼ªw ŠrN¹Î3éPÿ(C7@»ÛÜÂ?š)ï{Ц_qÿRSîq–ÂGÒî00ߦu§£aâ ‹Î<˜rÔrÄïýŒåØñYÔWüö[—l½žAÜZí÷”ç—T§¡‚Ÿ‹ŠM¿Àx•SS BŒLýXë<ÄHKÜ7â;¤Üòò%ÚôJ—”BSröÈEHÐ3®¡=‚ÜMÅm@¹îæ`µCx¸až‹ä›(l@ÞÒqà4Ï9Êç³aü´XÔ-lz°,äéQµp¨ö¥‚[±U¹ÀlcÂR;¸ïÉüº|žÌßÐóÆOÅâ×­•„|xóÃâCŸöÌŸÕ-øw{LçDl>ÇYšÀk,8_'yÎ3¡÷•ÏX1¯‘c7ÂÎô-y?9'.hŸãfÁâöß ³^ß!¯c9»ÝÝŽ«»W;×4NrxƸèR†@┕ÕDç£{õµMâ`ЕÓD9ö)X~U9Uqw×y/”»&z Upu×Ó9é¯qt×*vꊪ[»»+ú†»Q€üŠ‘»§O„Áo‡wLäpœmIž 8—<6]a Þ€}e€quß|? å¼s¸ L~2ÒÜ©‹®6å{æ¡`wp^r÷°èφM"ï6ɬŠÌ¥¿LÚæa&Ë ›}fÄÃŒ#ƒ§$[= _û ÈI/`®\Zú¸Ã?Z ª[ÆKÏvXÅ0œ–dÒvƒÝœÈüdfjÝo6|YµÄh¨×±ÍÇZîÃü®éYƒ~·8—Ú˜¨tkßÎÓ¹r¾ãûëŃ۟ ²g¯É¼Ãçµùâž·ýN‰Ð1Çã:•‚EŒí"Sço.9> ,büã`Çé&sͱ &¹â›þ’kJÒ`PÖh_¥Ùl]óç ÜÙu-}P;Àœºç(Žn0åãÖ>iJkªóööú–èúOUöÙ‘æ°äo|ñÕFX`®ûX™Ä‘‹~6ƒË½1}äêîŒi! c£Š£rKÔqb×µ`ŸÅ|õÞ—Ü]c˜Ó9ûä›+¿þ_ÆÎWŽã:Â|˜@€$[¢å8”%å…$€,’/(œG $J÷’Žž(S(>ê6WvOOÏìÞÙåÎTW:ß¼ aðmB¢K¨Ò‰vnWó¼õ .Ÿ±Â>“3:&i~ý“ÆDähÜû¤jÔ³«+ö¨¿>G~þ yd@þBø§ªBô‘qÈ(w1®^pjÂj¹bºƒ7Öë ²R€Çªâ„oÜRêK£­L~Ó{9®q!xá,?³ö‹wn™äS¾ ,‡ºöíg6)×È­W Æ]<µ©âOr;[¹È“k¾swåd£çð2xD°9Ò8ãÝ|-÷û‹; §pœíWÖ2ÇÌë·…?Çì4¯7¯3 »HBŸñ¤ ¬âë¸?|ö=—ˆ’Û0Xz®'yèäòhõ'émÖ1à}M?\B#Àý:¦~Ü‘¶ç^ñ0ß7Z¢]Ý]’- ;ûp7•Ìa |ʯ–˜!sǨEcj ÎÉÓ y¶Ùçà&®VçþîãÝÌ}ƒ8‡}× û_ßDæNÀ¨O«sPG]ÛåbëÐCDIª“£§ˆÜp΃”Çèw~:ìúDœz¯è¹qú]² ÷`d™ýÆÈøk܆qÃ.QbÈûôüÐ '0o*ð¾yè˜Ë1>òWæ®í£<Àœh0±øfˤ§dld˜IæÂh¸º„!gkÞ%ÜüZÌ+Fµ¶·´Ö€ÐȰÄi'È™Ÿã› €¨ÕkÂ.‡Åæ\˜WþM,æ8¤ßœóëÈÖmåײý6âSÔþ5l㻡¾Øñ/_> ˆûû5æo9OÍk¿¶)-X zö±u†Zþ0Ÿ…°Ž_ßÝ ¬”WFýFŒ‚ƾÿc7Øq£ØÑ~ïƒe¶–<¿_3'~Š2|£u’ŽÃ¡ >‹¦fÈKQõ§»{µIuRLY5{ ¾ÄñB™zç°âíÒÎÂs ãÖð-uÍÙfa»=`P¬-cŽ+;)lßÛøõbЕƒž1/Ü?Îì ÷ ¤ëÚæ¹ã•[žQ̤[ýWµÏ+N*Ã<'IÚN!ÁvÉÞó¬¶%Ô´“âøÂêÊO`Îyf4S)»JúFâ^²öÊ/0×><“4§r´Û(9ûÆ(N}@&ûåÙ$¬Sûè¸Î¹ú|ó¤ŒOÝnµ³¿k‚÷ßwC6^À³=·àvÞ8ã+ÅÇØNäbž³8c±c·°Úâ/Ò©‘Á›&yíÚˆ£ýä¼ à¤ZðõœÖ°ãý=*‰P€z¤CŸ„i;Zϸî1!œóD$VÀ~иÆêÆáyv}ÿĬºú{¸;l˜¢œô.C‚ ¾¶¹QŠ=×MI{öi\c)…H}âé¥, OÕx+Œ¹ 䜛®–‡„·Š°éz8àÄ@]û#娯D§Ým5?ãÍF˜%çÉìFµ‰ýÛ½Z?„Á˜(ŠQIŸ¦¼ò'/=’ôÕÊð(µzwýöôçA–Rmô;¶ó0í¾âÀ¤×Øçéq‡—$ö, ½J.¥E û {§Ür;d¾8Ç40™sÐsbaÖòÉM‡•`§,Öäq}6븶æn Þa~©få LÏ  s®VÑ ˜côY@ ˜sÎëÿ0y÷Gæ›q]Ã{ÿ=g#¶}½~ߨxÏ7¢Áøí¹VaÔ¢Ž¢¤ëƒäIÝ H ‰¿AêÇW¥ Ý–;;óqgGŠn ‹j#a_ÐNÉF~#`È“[NÝò.÷ˆ“»Çˆ§ŸíxnØÎû5¦¨–ŠüÆN‰KúžC‰´îÿp`Óø´Ä}gÊ#]‡)•}KÖaÆk±™¸UíÄ©ªK”*ph78¯±‡Í-ÿÖü*Ÿ¦m…Urf¾ÕÆ“f€¹ûaÉ=?9ç”}­g‘ãóÜܧZ €lÈ3zúD?O¬ùAR<~ûã® ”.*ʇè–·—‘p‘=‰HÙM ©-Sã<‡vTÉå·ynf˜9‡zÛÄ!=ù6²ðS.ú©ìrõƒ,q¦˜mH¿ƒ×Õ– ³»9æß¼Ç9ÇÑ´À? @‹]¼½‡—Úyÿ>ÏcœzìT0ë´cª~Mz2^¤^_eÇC@BŒ‹ `WœÒ¨ÐûÀuQ_¹'6œZxnXf+àH÷o?Ç •qcû‡vnõæÌ<¶sÎÍ=Ÿ•³2JHžÅø÷?0ºûÇë¸ò ¾ÌôOŽ‹õeú'—Ãc8´7Ó¿ÿá8gçë+zuÒÛÆ·üšþF×§Œyœ‚ÕÒÎAÒ¾ô‘DQ’#€¼Whaѽ:û‘üõ€ðO¯c¦›cʦ8Öé'´Žš«¬Èâæ\ãbÕe\CNnîÕÿì»_&O}¤í-ƒwœ0”ûãuíØçñcnàþCÅHì €0>K».𚛇K¸ûœyíÒm[–-±Ì:9ì[gØLØ—f¾~À««žíu}§ìÆsÊUï9Åæù˜€óe™cPn Ç<®ÉH~~_Û7 -àøI3llw¥Ü[™ÎM9-ƒ;••kÐîXPЬ{J¸!Q?3Ô~ƘK[€™íXF2C?ŒöW¯Øg9ý”ü’‰º^¾î|Va¼s'ös=¨)¨e.EFƒì¿8žïà,ñÝÝ´V”(¸wÛêqŒ¯Vaz˜óG«6À˜ÖÝÇã"çi? @;Á1ZxdQÑïaÓâݽ;ªÆyXuÀ7uÌIEjÀ®¹V4å7Ý‹³øl¥v×øMûÙfŽ·˜¿a›×uÊ2Æ=¹ó€rß7×|+²ˆQS8Kׇ5ßjpEdíHÝ©>ÓñŠñ«-ÀÞŒ¹sÔ1…ƒ'Æó§ç„·Ú‘1=³uj£U“V`ªŸTG™Ã‰%sÎó# MKÞy6U<÷3³ûä¯ÿ•âX\ÀlqæÈòÞàRÇ“ qÈl°´gÐ ®žHmsr® #ÞÿAZ~HÑ]‡x@2ÆuÃhÃRâx±ãb™Å&ë¡¶×aÎë',µ‹ß±rú2\¢ª¦Žêû‡µÔà(ã`l@ÿ°ÙjÃò. «×¾ejp¨·Ê Ð'˜S~ä7­ÿ×/Ð. 4-åÁJF^rÌ´ÏŠMþsž®‡¸úSbnYv~$r>Þï×ÉL:ùè/pŽÌ½J¯Éìã©ñô©©ów‹®–›+»•NŸ9H¸`ÎaÐsƒBêŽA\™Æýî/otã«Îøä§k»€úÄ‚öaÔ{e^ÏÃBVæ½Oㄺâß’—þ²óÒ-w0H¿Æ`Ìu콎Q¿Y J¬QŽ­jÓšý`¬@|jÜšÓê˜RIrÐaÌë DKèØäE2Î9sŽï Ì=ÞÌ; WrBî:‡ú1™»¶ÉUŸøaX¸Ùni||¿ß£5è9˜a {îroHƒ  `È[:¼Ry@ã ´V_왜?Š5ƒ®<øœƒÜv¿ï9o˜}m;º¤úfÄ9?`Þç>0Õœ£ê¯áÚ‰Gþ?ùàÔŒŸqÎßæi[;|Kå¹¹öÐyêsÉßVìwŸÛc”í+µ Xçß´‹ ÔîÁ:¡¹k0-eÉ€öîÝ·AœØqç‹ó0û'øL5”1áQÈÒaÓW…Cµ@w«{R†r%îäŽWé´ŠCmdùºKYvírºöÇÌ“ð¼6{SÄ(NÇÖ="¥ÓÈ7'}*­#L¹‚ºæ¨¾Þ¥¹z›¦êÞŠ{û3˜ñâwí¤³`.9»Í^‰°çê›1ïûýÆ÷àcB‹1Ü+€»ŒßHÃaЀÿ5ΉöåÉ3—Ÿ¡’oîðÜs›½Uî9%s ÖCÂ@À$½” ž÷y’ác%©÷ð8‹×>ý¸Rƒ•ÐÍEgEÕ'˜u$îHÛ»üý¹‰8/=r÷22E÷Í©;²¯ôbÌ3þ2ýª™.XWÎ×™I×L``Ò}ÜÝÛ.³Ö@}Lg”³Þyp)û’hÐþ¬CÆ6ýRR÷Èyð&]ác  «×wbÌ€þô·û’¿_5qäóhnV²lÚ°O½ô ³P=Æü¯l0WfK)ÑÓ®×#4ý•·ÛåXÇâ /v 9k˜6J´m~ú‚X99¹çfÈ‘¼˜ÛÞ¬aŒé÷:®Aøº¾Ïyøäª+x-æÀÙæ¡wÀ¤ûœ·ï)ïÆ1˜Œ9()w±Ñ€Rd-D¾/ÜïÃàß㔈Û÷¼ïóË;'‹œ³ÀsZdèŽ,^ôøá:æ¼»o¯á:§ÞsŸ ™:ï¯8ßz'¬\ý â ”sŽùž7c;~º»[±àHÔ‰ù?µËTjsnMéÆYȳÇÅ•þ¢±ŒOÕ çŒÛØÒÛ–³gWvTGê8_>Û°ãÍ gû‹€uæµ;;©MÜG•å’e#`Åã-sgûÖ<÷º6QµŸ ÷SNí¹¿¿ˆ?Œö„Ç7ƾ0 ›À…Eÿ÷¿hŽA¹ÁµÚçOSãüš5^zÄ™ _S[‚Rj8²§ßc/ó,¯p}t+¿ù9ªÄ€sÃæÀWT%ï#­‘<ó)£¦Bg0n¹{‘DýUxåMžM`õ—Úž2ÐQÞfG­ ó^Ïûñ— °>I΢ÂõøHÐÁ €pï?¹•/Þ#ÝùÆâ<ëb¿±†â‹×d7F:G»¯oêvæ ZµÒÖô|S/™ý“>il× XC½³@/QFGºf€‡çüå–·…äù#[–Ï\ÎU+5ÃÀï97ÿ»c%äü=;ç=ËDhŽíw¬°\dcÍÚ"Q?çÁô|µþ +§búÓŸœüþ!»Ûë 8of=ãí²©>ñ±¥Kj_z•í Ð_ó0† k®ü¦¸º'¶wnTô‰ÍGGú®òkÔ5sžüsLV|¥ý§¨ÑTc6nyyëjqjeŒ’*Þ¾rwâõ„æ`jÓA¡ó»›ž>mX‹÷èïRòFÆrmçùjë!M}bÝ~]z1ñyx<Å:¼|ÔU«—>²xj€‡½²Û;ÒxdïÈß)¿foÆÌóàó`nÀ>Ìùí:Éë¤Ö%¢Œ4~ª×,ó:±…p”¯~$[¾¥¬È ðO~ó2ñêãÆ ZǪ¯h|¢Á€ï0ÃÞ~ù–cŽà“ýa’à#Õ¾éX¿l6,þ죄˜cK•ñº¼gØóÝÇ÷{Þæ‘3Ö±×™k¬sMÍýú|Ùw–¦³?ûV¾åû=%’º ÅÿWŽ)'ìclζâƒòÁóqÈÚå(nH¯é¾öumsá«Àm¿‹üÞ`(Ç‘=û5€N… BçŒw¿Û€óë÷Û‹®Ùï’œºWè~0^&ÙöüY³äÄ7k ç¾Åâ3-†p0ë^Ü&u c¸¹Ïz±œ\sõm7ê7îñ˜Å6ƒîšçï´vœÀ°¾’v=‹8%`îmùHÙ˜äªÒâܸ·ë|ß> ÿDcä–g¦ü9 ºÚv…ö—êòÎDÏGðþ”\ó¨6£êt:&ùÇOù>;{{Õ²0ÀaïMù.Vjõðà+bÔÑ ÓAl`ŽÌ|¥óm®€é ­ñ6¹ÞÅ7V8_/@ë}*s5Øï­Jy‰éÅ|‹oæsçØQJ¿ìÿtŸd%™ØØ8$’hØm}àÅèî<@qÃaä7é/ÂyÕjJÃÑ?ÊÖ÷ïbîêqm)ï–ã03Ø|o¯a¡1öåë#9¦ ¬TcŽ9Í~ájÞlgSŒçãG’¶Œ=fUÔŒzÉ›%}ŠÃû£õÑ?–ļÙuÅäJ=ÅÝ=ýÌã†åópã`Çá½W§“—ޤLÛuC ÿ½ò¿¹áj<+àHÛ×µU8è£\VîóƒÇG¢g¹ €N¾˜ÆÈÇ#oÏ:0 Üܳä°ëÑ”óÐeЮy°ë0éw1ŽÃ4HíÙR}ìß(;m_§=žÅæ°‹ ½ð>©yõ³‡i”G»,BíwÖÿGðgØû{VuÌŸ¡ªßÂ-ÆïŸ¥êøhÑ2é@Ú©ºÍæ~Õvúú=7@Ï žÒhßc §mµ¾ŒÙ›Æ+Ý ÐNdí¹¯¡ã>'€üâA€ÖU£UIÓ0æ«r[˜–®Ó×â}úbÞ©øÒ¬¹Ë¸Ö˜¢]Û=‡|tªÑh̤à ¤îÚOE áH ܇!ŸTÄ1>õyî+‡ö‹  ‰“qJ®=w¿‰¢·)³¦Ì€1Ø ‚ ÌвoŽ£=Àv<$Ñ0;·êÆ~–Ýmã:T´QVs˜£1Î[±×`MâP/S²nY|>Ÿ³£; n$û‹/Kð sÏÑØÅ‰UX{_aï'Åb¯»ÜäÏÞ–•™eS°“‚üýzħ?“õ¾eÛé×~³ýUO=΄Ÿ‹vη X-rùY1ZyÉÔO Þᅫ;\§SnyQzafslæý‘"p(}ÇØæÇ›1÷äófÓ—YGöNË·ØŸˆ—¼ýÜ Ê1%yá¶óÑunß0<¶¹éܨ¨š~·°éj•ç•í0ìÚVÄ(.åO´ML>úĔۻåpÎ_+`.PYãšk@®cxÈ€9÷öq¢ë¤S+Ýã‘Â\¨]¹aç ¾®ímk$çÆuü¥äNS–mêð&àÿôÝ/€ø-¿&°ïmöýà ‹ŽäÝÀü5cìGî®lŒ¡¨k[,;c€òaÐÛ\uÂò[@ ùç>Ç2þG씨ÚÜ^bÀÛ‘ñä¼Ã Vÿ«©o ›«×,@ @.¶zäï”ðÚý»ÝzXh½¿ªÙ¹ñ¥8çq3nÇö­+>‹ œ§€ôÔ_'urè­zàØHîo.ÂhÞ´Ã`SöŒk¿ ¿·IÙØ£ªTÀ÷|Yuò,b=®VÑøŸ}.Æ1ldœ¸p€9 oì+àŽ‡ÅD»²oÚ}1JõS jš³~°å€ó6|«|trÍ5&†ý^ç˜EÕ§ùѿѽ/,¹‚æÜ'XÜ…/ > :fpx¦`‚JkpîóQnt²1‡³Ô¾Æ1oU›¾:ã¹§{ÁýåÜÓê'¶Æ9@Üç®|s+»ÒŒ ¶©q_çÈi ”w5žÃaÓŸZ¹ˆò@\ <ãò"Z·v"€Çvµ[RMÁv!/u·*Ý´ªÚßòvXdo›ôÌqƒ%Ö|úGÁ\%Ê£5¸f!‚}]…k°Çqn.{M4?¸l¥ù£ˆ(9üú±¡:¾ÅÄíJ·Jæ'™<9ͼ`•ÕÂQ°Wm`‰’pƒ¿u=Ü•¤i9Ž"ãç‚ú½Bä~¯š,PÝœµü\émîÅ”v»µqΩßkžÿ˜½Pì9üíäÿ¯É_¿nï/ÀÖa僷7ÇFQ+qàúŽüXà<ñÑ7?Ð;¨géy8»+ìæ9Ì:9L]Ý yécGn=F(Ôͪcxý)µEå¯Þ7X@;N¬%s_}WØæ×8·~:RŠ-fqÚÖ¼©“®–…ÇìêW„©ÐqaÐGrØ9Éùƒif}óÓ1г$2%Ù’›^‘Èc´>,аålO0ÏLa39ófØí(ßóõðî~ Ÿ’›ÆMûÉO5€˜‡U÷m›¾pÇTnÀýÙåúvèüa&Éf|€Óä¯7›Î9fç÷ÃqÕ*È p/~¬tãH´'{eèœw÷ôšÍVŠKŠN¿•Ì#V!pìþÝϰñnÉ_ó¸#®ˆ,¢˜á¦Ôg ¿ BaÜ•nñìzÏZ@ò÷‚y1nkçuž õ©÷ßÿpboóÅYä"·œýÅ‚œKR>U´mOþ9 ¼sÌYÜ2è”J«2”8²SÅbeíƒÁ›Û:W•²4ÀÇ/äŸß}ôYdU kgaÖ€:}ÜÚ}ß? ÷·‰2/¼sŽŒ…fäì ´õZj î£öæäεnI:Þ2òNo£,kWñµÏ'H¯#Ÿg™· Î ˜g%ÊҚظR ¯mÏ ù!€f½Ùïþ1¤¨têbžñ>Mθž‹¿~³ Wö„¶­ÔļX1t•¤>\Ì]Rjq -el3©Æ[w›ã˜GŒ_×ïUÚžkƒðÞx ¯Ëbž9wbqçáuN :,;Û\ÿ&Da±©¶µøkä ]—D]²LwP<él¾s×– À—t$ýe]Ùü]1Áçœh¾t¼&ÐÞÅòç? ¯C[òø®#È6Žç‡Búïÿ`T|1õÙ÷¤ß’ŸYìób~ˆ"Ïá?ý¾+^»=FÊñÁýø^Ðß«˜j#y—wXt˜stó7œÝ#o¿æi»ÞSèÇ=7†¿~Sùè%»ŠdëŽ~V‚½¦åðÞ/–Ý73\NÕbªâ@Ü€=ý“ë|ê?õyÔ;^íʸû%u§µ >7ò)«F ›nSØófx2Ái󜸹Kö§v v[`~.{Ó€œ‡4j¤ZLëÇ߀ôíí¯9äG>s™X Wñc|8‹ô÷~Í3ëô^#%KPaµºv:lú±lðÏîò0ÓfŸ>’ùfÔÇÌŠñ-óDv.ª÷l“¹[¹åcB·Á±}L$ÌSc×Ìg®ÀšÇšgnµ¿rÌ2ûì[¦wó‚ßbãkÛò ½9ólÏw¿sÓÕ⬞×àäg¼cYë–sm¾¿^Ó‡CQbÎÏö¼×ÞÇøŽñºŒ­yÝú Ìþü‡jG÷ª¸Œýùý²ï´ éGÌ:mæ9œ¹â(gúðëŸö‡ÝÒ¨ê/¨[b‰»B}ò¤05YãÏU[ì9î¦ÚϾ—HÈ>S¼P¼ hçÊM÷ÈeÞRzeåïšhwžš¥wk‡äý㸧߼©qƒZ®DØsröï+‰ŸZéËË`.`½Ø’î‡]ïØº¹ Ø·¦º#Ó¼¶yMŸ€U÷Ø'uʲ͸æRvÐ>ç£ï¾(wé%Bã 7J´ñÀôó0:GÖLŸÀãŽÙnc/´ì(}ͱ4þ]³ë âÉ…÷6yñ_Džﱓ;~Žœ«Á&‘1íß90ä›é½Ø_JØÊéøÎû͹ÙöyuÎè·MüäÏùa©ëµ5FßL9uƽ¯õ†Á±ƒùÇÏ…Úú{ýNcI»@R^ ï­Až@Ž;»úÂS?ÿëÿ¤ÚŠ•·›ñƒþÊ}ýNd!Òhô2‡ó¢á²à[yD{Ò|œNjPdð“4Œxú„€u©›ÆÝ^'êó[ß`òj›{žÊ!Ť[Ýõ˜q€ø¦pEE¶%Ô¼h­ûñxu¥z1æÇ\s:eÑJ·‹î½pÊNm±æ ÐaË5–íãÖŽrv¼zR[¼ vÙ¿%o1„S\¯%#·Ÿüœ†’5¤^`~Œç1ÞÔI°7xäd2ÝrçŽõ§ZbmŸ×Ç„­òÆ—´>,Ó†fÁH`ü»F<ïys±!nÁ\ª°Ô{­†`,qÍ–Àwúî`¬ùàœ/Óg ‰ !]Ê_ËìØr ÏÛ@ø\"Žk±.îL<3¸ÌÛ9ÿ0Àfü˜Ó¼çã rË=¾^ÿƒÿ„µc"(FÂRnñ´ãúÛì×ü^9wÉ6ì3Ž„¿¤÷+g?qß³˜à8¯X‘‹?ðY€ï­5ÙÛ¥é[v-ùAÛw÷‹5çÇùùä!‰!Gön]ûuÃð¸æqÓ(Ö\ïYÕ¤›ýþÔå=¶­þ’Õç2›Rl—AKå¥Óçæ0¾+äl@¿‚lºÑÌópðÊ`ý Ü©‹>r÷ 3܈·¡\Ìã,‰(wwEm?ž?ˆ)ú:.yæ \ßy@äGølç8Ÿyxúäqˆwî&à?9œ“óI½âåÓ}p‡·œÞ@@ɰsq°»TÆ2¿äº RÜ/цv \ºÄ› ¾^Ü{àzU€>¸"å•7‹ «ß±€}Aêžc`ŠoƒøåŽøi ò·ì Doº‹‡‰ïsíõ=ý-;—×FÁp+úXÔºÆz÷«´Ùx Tù?÷ë¨0(y6¦qfÐõ]wu×#Ÿ…¨na¾-Og_)VÌŠ'ådÿ_j?­æ¢tÁ™:,úìÏý-¾•)2Ç¿WôíÓað]>Š•µKEÔv@÷÷—ò˜š¯ã’c.àÞ•=Ü:0 ¥v9¥Ôé7hGÕÅ}¨t‚yé¨ÉÜjÛ@œ{ápRÉ(¯¦1õ_qÏ®Ê,v`wŸ°Ë©]Ï÷Ô;8XrrÀyž/È;'&mÏcê«Z ÓÜkLªÄŸÆÎ%kaÌÕžeíË ÒۗȤ RwÜåD$ï&|´`êÒ_ŽÁE#7?ÁßÌts\¥ ø«Ôâ%G7­õÌ ïØJÇo§÷u\S¶Âvþñ+;˜zŸ å%Xa°›i{rÈÕÎbƸóƒ•NØt<3ûš$õâÄ“£\ú¼"ð­þùÂíjO.„¤"k¼Æêç?›Äí…gçšU”¹ˆ+ ¿+ ¸m9ÿÚãSQów±bÏù_ò–Ž;ZN37òù] bÛïëF¾Ç~¡ÖE²jÏ#ïé/ìÖo¹Ï:P¶’@›N¾?¶ŸFRŽË{×L'×¼sÓqÅ€$.ïW+‰`}€;A^ºpþ²j}ÖŽò$SO4%L Æ5žudðHÛ5G7`¶ÕbS7ùs|zÉéqW˃BÉß딀1PGò~EÆ0ÊÁP. ÅÔNþCA{³è¯èS’íµÆªöíä§«Ÿ81Ÿ;²óÒïÒÇ!Ø}·]è 3HSÓ×—Œÿp¬Ÿ>’÷ù.g4%ݸ#Y]–lk—Ä]¥ÒÄàá ?A»Æ¸ÆÃ–/k˜yW¬a‚ZÐpÂ~Š-?”oX)—Ƴ¢ÆÚ Ø5€ó~¥÷bS@ÅújF{£Kzm.{1ô°ëÕw0çý€PݯÁ±[»>mKÉÝŸÜ~¥í4æë ÀUn69÷¨y-rߣˆPß-יϯý X$™}>¶+÷u¶1"Ô÷8ßC,þ_©VbéygáŠ.‰æqÀ7 _žŸmÚ‹"†9'Mþ+’s®h€¾,¸Ú^„tY4Ê©¼Ý?«†ºß€Üý)IÚQ-ŠZ–^ñÇünÌ)¹É"íÖ2Ç‘]ǹ… ÇÄ”ûÏ– ­è¼)ë¾}Z`Õ¯qÉÑ/õß×?Ê캗j¿ûܳ£tS »oºkÛc¤¹õ3@çž«Öøqù©k®à¹Ãrvø)^Ò˜¯ œ‰$íõ e@N_¯u£sÊ©¾£ãË¡=ÏnË”Û0®ŒâãÍžS }½žø-ùDlìóû9vΦßá%•RcÇŠUmí±®Ô©þâ:^g¥ç{4oÍóβmb{{ µŸVƒß%qcÍ¢Æ[¤ãàËU…ÓrÔOà-0ïwËNÓ&žpà)oy ¬ïEõ‹aÚf:r¯ŠpÑxÍÛ pº œÉDr7¦–8s³ŠÑçE®\rd!|Y×€XÊ—åTüúí‚¿ù*ûEÞÏlÿœíÿ{áãXj®ó*r™ËǯË~‡öý˜ä3æÖÁò‡×˜VNÉM›n âéÚv_‹1ß8©ûÜXÔb×ò®ó±ä£sƒ›O®ùå×"‰¡‹ŽÉÍØ`þÚçþ=²¶]q÷¼W¹É{Lh¶îê»<<ð ATmô’¸ûáEýq¶}æÀTNçÚºé€ô×HÚ Î+W ¿u”Ý™q…€»™™2 Hç¡’òläªÃ ­ã»ÝÛ}>)M¤ãÓ¦Ï9m W9íb½ÈY78Çñ=-}b¢ ã´Mítõ Ì®^$Ã5Øðk"oó«5ÅZ&¹üÊ…9.Ö€.Â¥ÜTkîv5Û·™óÚ0õìÇ^q¤ ÈÙ¸ïqú`þ¼H°Ñ¯µ`ŸÜö}}dëÃüЯ¥ð>$ï³Á5ëë‘Ьù”>@óY/ã®1Ū¼M?õ÷©"@¹TjSXb»Nì‚—K’\FüŠ‘°Ê—)'×åLW€ nyK×c›ÖúdpéÅÈ3HÇ¡½÷—q±äqbW4h§oÐí²i–¢[õd—vñþ]oõŠ,͇=‡‡=§ž9cÄ”Jk#¸ o3æº l `)÷׫tö\÷k˜tLã ˜SBMÀÜʺW*§>Ží˜Ô&~§çŸ»· ÆÍžÜWÖ ÷s•Ç®ýR>5¨®j9e ‡O¶›`éy Wù´< jÛi‘¤KÆã€®ã`-C@ 3L>òmrºæ9J]ŽÙjJg²t  ×skÔ®g¥î2ÌÁCŠcçóªsÎøVÅJ vZ¬·¸¡qÚbÌÅ-^3ÔºãÀ¹Á«EáZê ˆéþ,Òö «qŽ~«p~´Žý“.|ßùWZ·yNì/“¹Í;à5(~[ìì¼ÙqnÝÒsZ©aõ¹ø˜²Œ íXÞÇphëK<²ý‰Ûމ+Mßz€›Ÿ°op,‡ý¾F:Oç«#39_«ù[ú}¡(à‡´äò¿rwí ‡IoVÉ;òvŒä¿§,[~à'Ýn ï4žˆd„Y÷Šï²è“we)¼eñ õU¢DÇ•i\×¹^ùž’l°çuÓÎ ;@Ýî®aÊ+ž^¯Ùc>ŸLk´Sª->ÎîãzpÑë)&GÏsý4×ÌE±[C½åìŸ]ް˜ýèuï[ W^ô+0” Óv½Ç›ÝA/9¦ÆÙ¦v/ÌúµiÒÛ•|â?LVØ«/0™ƒÍ²ä3¸Ó©›Þu‹aÒ#m×<òQ' €»ÿ¥òb{ÿÁ Š9a½IðÈa-ç 1ÑæZ_™){¾`¬MèNÆcH¦ÿÇ,¼¶a²9N@®û–­‡…ÿw€>qdÅËèlóÓÙ79ÛcHÇ9ÜÌÀ­×Ä4ï\šI<ûìðŸ1õ™·Á¾½Žgöçs£¼_®÷äÃx}(y¶eÐt\ú,8â Ïßr¶‡QO5‡ý&¼oØóÛô˜øç¨t¼ˆ;;àºK¦±È8©<(‹­cÄ©EŸ¿˜rbLÞR©ãs¢¥ìw.ùŒê<©‚;yæ63eáXcî“?î@6= ··ãåòO ´»·ëÚngöøÈHª>ii:g¶W¾¾ioŸQ*í>®æ ¶mþ© çŸÏ`ÈçÙ‡(Ö<á”Áç8·|ï#·¼bÍ}OÌ9Ïze8¬¾Àä›"zô {Žty° aÆËìmXPÀ8øvd8¡ÇÀ0K:gþ€@0ZÚ3ö¼ÞïÏkOI5b¤Û¥>»Ì)<ÄíÝ Ì±s–ø¼;Ouþ&ðå~Gx½”O…«Ç*u­ƒý9u€~°ëŸ/W>Œ]-ñ Îø~ÁF.rÓfŸUÑüÏ¢ÀY¿9 ›Q¹ÕãHÌØ*¯Àù»þ]>tα%˜“±ÚæµVâ‘tæÓ×1Ëb×9ëApbèÈhrݶ̞s)J£¹9>-+–¬.ý?gç¿cIq%áy[Zƒ ƒ€±l?Ò®W C7Ìünë™ééA~£íp(ø6*´eVVVÝÛuoߪȈç7ÿõÏyÆ;4?}@ºWUŘ—^cÞo)•Þ·ü7 ³f&.ÇVyS}ƒJýNqqÏ«Uiͯ:ê–Ÿ…1ç¦6_û1‡)€Nß œRlÞ¶ŒN«í[®¥£rä±át·]Vf·a `ÜÀ›±ÐyË\Nû=Ïû‘¶«OtS2.¿ä.ÖCãÉMGòNIK1æåï<ÄæX€¸ÇÕÒ'ÈÃHÁ\Ù5™ö§É €W«íŒ5Ó¦høÍMõ9›÷yÈÅ,Îý€dö¹%§””½–g¾ÒS»?þ põ Eë©ðè÷}@·Î#`]åÐ0nd!ÌU°“Æ¢1ýoºÿ:U&ú·Cy߯l'_cªì0é5ÿÄ{»B¬ø–L‹Ü\t€¹ÈÎÖcçmE×._N•æ4ߘo6‚ýã ñt1Ϧkûϸ¹òóåØÂò€÷ô9o™Ú-н¹z¯šO_r¾psÜ(ª¯ó•ñ^—•c\ó.V™t.lȧ¯ˆ.O cr< ³óÇzø„ˬÚë‡Xó‹IŸrb³½Oà\‘¼ôÍýöŽ\ò¥Ò:¼¯à‘µ“5¡ãpzW‰6V­¹žeïÊíÍÖ¬uå åÆM×þlË0Ž|7L嘿Dš&½rÔ‘¹«%æç^­ŒÄj y' ¤×øä”¯¼™t M=ü5H·¤œL:è¯ûóÏ%‰oÙ;·°nƒ8үǗùÒxÀzj°SÖí&ôfǸ üK.»¬:"Òv@ÇÁÀªA{æ‡lN;5Õ7Èñíó°öðåÚÕ|eLûêÖ wj·Ãf3°©œyjhòŸØð“#Ÿ÷ѹÖÄŽH““_J‚-Và@ŒSùàüͨÆ ­9OŽ7¯»Q*½†?°è ¾Wž¾f…°áûÑþÛ.íqZç{;ßùñhHÿÙ÷wmøF,+Žfÿg €kNÀ[ã9þÏŽ€ñ•¹¯º&<~ú‹tý$oÇl³};¶Ž9Nî¸×…}TOeøÉïþ8²Ó–ªjî+Á½´Y©¢Œàº¼¨—)¹ÖF©¯Ê³Å÷ÝH{·gŸÂröU²PÏþÏH]›\svúŸ&#¸zn ¦§¦ùÄï¥*à^–\€¾É Ê£ÙËç›;=‘.hÖ<ó†-GÝè×ÃÉç¹QJîïoóŒ¨gSXrƒØJœTL€Ò`œ˜gþ±\ò8~LË'ºìóª€-ɉbuAw´Å‡H;TÄÚçsbËM“Þ»Ñe×Àïf×ó£[`Ü¡÷ðNsô“n .6=,ºÂ2(µbй9Ìë1,ÑüÎ:Ôò¬l[–M¯éã¹ nø&—ZêÒ0nºåòþ‹œòl^ö|ÝÝ-ÇCF7+øä¤¿$.ý/̦‹1ŒP×TÌDèé˜ÅaÜc‰£ÚÉYWûŠ0±!ýpv@¸Æêû`Ø ½ÝÜOuyU+½¶ÿÔq:Þ€Ý {sÕ-‘Ÿ²Gé·Ù %ÛúAßÛ€À¹·yðWæ]`P<·\¦×Ø c,°Ó`þ19ñ²åSŸ½€X3ð îg,€¸]ã=öÿ¨Á¾²ë66 `ö~€{ØyæÃ†ÏÜ>÷HÉ{þY>¾Ìõ–«c?ï‰k´ÊTž¯ãsž~ÿý½îŒ«ÕwlýÖppkô#e_ƒ7¾«èð¸ŽßïmÀ¸¿ïZ´b|rÏ5·ö¼«õ™ö¿û_>¿ëÿOÏé>ûSrqrȵ §`¬@û”{DÊNË¢¢Ï±‹Œ]ÕBñÅ÷ïãÒÞLy¥Ït<ª&q±ÉÏïÔ¶;»ãu̘¾a(%9í[077ÀfÁ÷¥Z• }3ùærÍ1A­ý“þ•¼ó§ßݱo™s”lN «*+Š?|ýN‹æšcX·vuw ¯|y×0f‚@ígb­Ítc\kö¼$îf¼/Xsžw 4xÊ8à´B…óñ¸'v=Ç¥¶9 Õ$Žì]RMóyn2 v{€àHÝ×,­ÌP<jG=[Ìé£ÞM+o¿*ïvÊÿ.µÀÁU]oÊžqŽ#ª¹© ®X‚Öqå<¿iÀÁ ”‚Ö{T<ú»$B‡¨¾ruØÿNçø ²!M)s^U±JâÞEïϱ²ëÉÿríRoœ‹u\ÚÂõ,/¾õð0:`_aŽ«Øp%åìߺê=gÁîž{$fa„ؼä3¸4ž #Φ0áœë<ŒûÈMõ×ë¼§Å Æ1þ˜¸M_ ¼¥OY¥Õœ®‘îÖ€=^ýÜt¨“þ!ý–n‘“£þ#7¯ôŸš%Ï 1`|åfHß}ƒþé{9[ñÜÀuœÚ7 ÐFrî{»Lå6¯i¹žúàlc&çñ€qE^7㡇2çj¼˜s‡€ºØö’'êܘÀúFî°ç“ÓèrlzÀ+†çóçwsµ9&2xJÝ“sÙNÇ€òŸ¼¿Ø+Úz°FÒÎØäš¶ë»Á¶[í/€^¥—^~ð|X»Ì Ð Ãö‚”1Èè‡E,5(§_±²w¢çŒ„9¬íHèȶ|žm˜k1ó8‰s u¹-ù?å³ýÚmž6û=OÊɬ»4[Þ³k{ßc †Ì`Þ`ÞÎëë]H`Û2@ý~-ƒ–±|f”4›ÏxnŸ¹´,0ùû°2õì'vÍWä;þŽ©yeÚh`®E°®Æp{ŸÅ°IG H×b…$êñœÀ,ò’õbƽˆæ~ïgÑ 9‹‹ýÛdu‘úÈ×ݘW‰ÊVå÷õµZXó‰R4­lÝŒ9 |ÔSèÚÏ"o”Ò:… Àí>ì8à¼"s¸ººIXóG˪qoEðÊ5Ǽµ«³¨¿ î͚ϳíS«÷Ô÷s œàDäÀŒ£QByêÚFÊîøø›wIÄ ×ÇMÎysŠH*õøùìCZ¥Õnc ×¾E=§É·.ám›‡>d—æáEÕÁk]ÈÓ·DµpÁº»¯’yñQ{Im0¾¯¡È¹/ÔÓ°é£X8á¡!ïÒò¹HÇUøn¥¯yÊ\ÆT+¹Ög\³&p€}Æ+ždâÁèm ÙV;½j±´>ó”yõG:^_¦e²oÎç ’™3ý5Ž›Úu\'æK|q8'Úx®r).òAõeâú$¿¦Wí<ÆçÏjL{A¿‘ ]E—1‡h3»³s%AŽ‘VJ·lF9ºkõ•Zé0ë àÆ-ãrtÍMê¤{¬ØóOïÄ©œWítÉÛŸ60Iœ^cÆ1vù¿&qô5þ‰ÙöÎQCò>ίY‰O=ôÄSož« ±æfÊ‘½Óºîy™ÉEøôïïÔ`Ÿxaà]yç+}÷8@ü׃õ× ¿F€wsõ_«oÉãæ¦ä Ãܫչèk0wŽä—ªM Ëžw¤ð¼†À" °`ா"À À<à]a@ÞFXŠÊQ·™]¶̧¤•çýÓM0oÀ–Ùóä³Í~@~—Ä 8;º®› >@Ø 9wXqE€jjæ•©Y燳¿kºÃXËË-+½,z1íäto£=c-ýÀÏß2@çö˜Á;óêÚg1aUæ‚W±‹3 Ì‹17Ð÷÷EѦmÉ!×vû2Ð*Æßíü/¾Û/Âÿ—”LóÇ0ßþ˜FöÜcëÆžqøpd”ûw­ù÷Òž[¿qé7HWKð:þÍä7•ßßM3Z`^̹bÒ˜(¥&¦\å4߬{5Í©:r -(ËTN÷AÉØ1SÛ.팑RÆ¢xKÝ‘¶£~cÑ\@Ü÷k€¹Ç¼Ocõ\0@`Ž[û¨÷’b·¾:ꇹÎ~ È ³æ‰’½‡)'ÇüNmˆoÿ€±/-} âÊ]Ï€èŒ;¬¢Õþ #¯ÉQ†ÈZP̳p³Òl“¾çÉ<ØÈçÏÜ ãÁ$K¶5Ñ£¿DàÑï«YwrÅMl²¯S[Õî¹j,ämÎK©åÂaéÕ°àjg€ÿ¬Áž'üAj.øuæÌû¦¿ªqJÛ‘Zܽ>¤cü»v*lVø´¢ÃÜe™7ßýœ¬ßFc+õØ ^»>\¾`õ…âØý`{Þ<÷ñÄæŸ·ë;ã]³¼LÔFæ¿? mÇ—Ïl7µÒO×x¤0ÇrhíGÀÜCÆi!gç\¨ú0rvEVIåÔ©¶MBn]^ÍŸüØ؉ß}ý.,:²vr¢†I÷êò{m+×*9êZ!¤;prg¬Êµ}vaØo)“ò K«.)fr¾Ñ’³FP·<‰yo˜×|òwÕI4Oއ— PW]Øô äyÒãbÎØw=ZÆÂ¤«_\ÜݨwîbÕMO ÝÏ¿?ù_ª4ùë‘dZò.àÝŒ«8¼“·Ù(-A½áuO¦Õyô€íÖ¬xÆ"s¥ œÆ`Þ \Ý ò •³Þ Æïüw]®glsuaÚ \Œ!Y.cº+ç8³ógÐH 7ÜË(/+Ýš8á {‚ólÿ~®MÞóÅØ¯YåÐN.ôã&ßl59à²=Çñ9Ñ.‹Žù›ûò´õ½zÔQÝŒzö‹=×õ×—¾âY¤ê€ífé¬8‡I§OèÂÀ;Œ7¾0Üê;ªŽ¹öÇßB v1ÔØ—qbGͳæ•ášsß*ŸÆ<[%*Çô|ò©u®6†ŸrÏÍ1¥8sŒ³Ø‹JËãZL¦<(k®xEÛ {sÏÚSÛÜã.V÷Pƒußû¾úï{·÷Ãý·îÛåÔîÅú´yÏ3C™Á¹ŠÌϥУä+Æp¤èÍàÆ['í&0Ô nPþíÉLâ–AÇG¨Ù»Û[R 1“oé·‚]#üè:žmd¥ìÎqËrxgîÊÍ'QÕªåá€Ã Â{¹ã<<ïçï¡®:íG†Ý&soÁwéÿ©üvk=õÇÝŸë6çœÑDà8²Ï9ŸÀgë˜RÝ㛯_øi*iµ—Áô«Dÿ 5']™÷Y¢@‹i˜"ÅÝ‘w”ôÙ²€ÏNë „ûbðÊ)œó^0ç—f{ìÁ¥ñü _&ùgž×tÝQ ûüŹ^•»øòmjÄoÿʵ¼äîãõqtI6Rô™®Ì½VP#gª’kµúí€ñaÑÐ3þTÁ H œõXI0“®~J±EîŽi œ>¡¹e W26%7] síWÀ¬k|ÙtŸäð™;²öçÍQʈx¯çó~À>ù§cÀ€iœç`.Äìë¾÷ã;€¼€Q3ê:ž|ö€JWqîbáÌM‰7Ìä´"¯æí1ì ‰T@¸¤ð ÌÝ6˜‹ìpÞ 9:sÎ.éŠÔ“ïù˜ó彉_y9×sÌרþóä‰ÇÇ`ý~=Þ—·9ÖQUÜFÆ~.{xßE$öIŽîcy¯8¯V„t%…ú1qÌ‚—æñ?I KâhG®î>ì8ÿ…ÎÝvÿ4Ï]}S±Ã7ïu ÈÕÝß Æ9cÚN”¤ý‹›{õ¯%í¯ËWÄ%5»JÇÞz©˜¿iÓÈ̃­À¼» ²ã“r0þ[‡…ЉÇ^ûÉ!µã@ÈñhP@ÿì|¸Ìy>ì*¯±}Wÿl m󀾨H>ÚâþÈþ_0âü­Íõ§xVªºî¯ÇöÀ_)JÏ×ùÉK9(\vmóòO’K ÌŠâ1Ÿ%ûÛåžóO~ϼÞöÓÖ" …þ Ä”] Ó±ÈH¦vÌ7 Vvo¬ôÒﺞ°æ¾YMÄñôÓÛGë…¶ãûí‚r¶›n@ÿplnÈóXûÞë†í¬ÈKÇMÿE›Èi¬ºWó[öÞà=@[F60ÈeLl:µ`)³6Ñ¥ÚÈÝókåÁ ö\ã–ÜãÆûÊñHI¶€÷a`6wqó [†i)¤ZÊ´•Ô“<ôŒ#ï¬y<ìò-–+Æq䦎qxÆ pÊ¿üþŽ1Ï¡E›ó™‰·\vL¬dÇN.-}w˜AE5ÌúëíkÎÕ5ÚÙ&tì”ÅZ0Htþ1ì;`³(¬|ƒÎenéÛ~™½ã[2lç *jœãÄÀÞÃX#[?ªvüú}oìÆn$åêÏb ¯µ Ÿï‘÷9¤÷ÂÏVhpθßÀœôŠŒQ¡ùþ¿¨/ó7Í—¿C¾uð C®ð6a »û´HÜ1Šü5Êùÿ¶|}ÙžŠŠ­[Ne '5WfqùÝ+žßa-ìŠÉ¼}dêÓ¼Q=åŸ}{§1ðüÖÛ§Äl÷”íŒÇI*†h{‰'¸%·<Áât¹¤Ú«YèNŽy-r3ûpîÑjIQ3Àh¯{; ò¸µÓ{ÞÌ9 ¹»Õ~~ŽÁGçã[»ú%‘5cî9aÓ |0hN˜u€ŠÏ“:µ:&€)y¾êî¾sè äp1Ÿsd›c`Þ‹M·øžSw½™s@{ŽGN½`¼æÃè®y#åõÛÔ¬Àw×ùöûʸÏuRd{Ƙ´ñ¦{!h” $擊–c\›|Jéõ¹,°n9¬Ç×@Ýfk Ê×¹ô™ÊÕ8}qRAÚ”Ñÿµ°Vÿ‹Û%]÷\u¹4mO™Ægò }ªÁxƒrÉÑ©Vá|ô•´{žûýû•´ ·]Æ2éBü–z±“ÅQÇÂÉE}·ç>°å8͆g\À\ùã]> C¸°æŒ¯|’ir˜u/xWéR3âöyáÞÙ¦¬:Æ÷d×3ÅNíf̵ï~ÜØuŸWŸ}/,ö\ž-~4@*‰û-fðʙѴ>À9Ï>~?oÈ}¶*à®XâDñA¬y€9Ì9Æoô5>ÏÜËÞÆ$º€ô·¨kãMh¶Q²æ¬\Û-ý` Áé;¿ÌlT¤57±•³fü]QÀhÄ7¯V"u^\9ª„SZ5ö3¾º yëo>+#‡„æµ'2«}i÷ýƒ«ýx…ñFÉ ‚èÕ9ŸsúÃŒ.CÎq[pkÀ­‰Á€<>Ì:þp.úebû¼k"Ð_¼ü}.Æö=,cœ•><˜øSþÆ|!Rçđ‡ŸsÇ‘­0Þ¦o³ÒS¥ùöú×øšÓÍõ¬•:V–†Ýç\‡•9u@¹æÔjª[~ôÕw´„ É{n"ȱ¼âÛ®ï8–b„rƒä}Â78Vªé%'˪¶\TÕ¦ìZòÄô:Y÷깤jï gµÝ¥Ø¨© ‹^+ö€ròÞü Q¥a<ٻ맫oYzØoµz@šœ=ê§+R‚­ ztîO¿yW²÷òæ€wòÓì’© €Yt=¨;ý~êðHáÙǸ¹˜a“h‡QÿÉ –ÊóÄÄ„™Ü–ksì|d±ÈhÐÙ†™æ.̺ú‡šé#{Pb’qI|9ÆmpL€ìäªsL±òÃ’.ÈÏù6ÆT`9íÄÅ~¿ïhnë×8î}€úG> ¶$ìÌŸ×?ô–”÷â°øy-ÎãÅÆ Ï{àí²fÙÖõ«:üeÖÆgM®¸U¯…Ÿåš¿ruó]íU}Œˆ,еyoä›kÌ‹‚,¦ñ®¿‰ÚåÍšc§ðþ€ô©ùûØclÙûú7MûÉ'Wœdë€uEòÊÝJ¶®¾Yqç‹kq6ûÕÒÇŸÕ+º¢J«ä¢Þê´*òËK_Q¥D·j‰Æ|oüô»÷jqdIŠXWÇôÍ¡±ª´â1XsäëÁeœrjU¢õç¨ï’B—0ˆÖœ~öh_s[žS æŠHÓKö> ’j•‹®þ<­IܘWÉÝÛ°¶9` òÇ ´£Ü¼«çðu ¿t&o7ø6žÃ™sL>üœ«ç5±‰Lž€¥åYœ×³×ç<gpl- P·2évïTH¦¾å×tÀ÷ʨ̨ëxõH¼JŽ%ð>ãܘŠ1ë{Ž»…E?‡¹Á¸ á²ê­X‡÷aËO9i:>¦rc÷É·ï3ã@>ºAúHÞ©é Û&ÐN,;{QRwmÃptÉ›8¾·¯€¸ŽÑ•eðžóÓ¸ÇêæRKÝŽó<#äv™õ~íÛa×ÙfžŽñ<h¯™ãv?°×Ü­™ì Àl ¶©-,»"€¤òl#V«ñ?ÞÜ—‰–æÔq3œ×èîo/Øî±5œÛ퀩/3ãdaüö.ïìoþü8šŸÎÇy‰£Œ?ýaëG†#¾1ê©™ež¿1¯]òûCþwçŠg†± ˜qÖý~´Íx½­Ì=fˆŠ©=Ž1â àbÀ5 NË"•Žç >¬8€œ`AmJ¢•T}Ì&©[n?Š^¸k°ÍoΙmÆ Âéô7W?Ìùkªb(´íq3èù½Ø.9;.ìk÷*éMÈåäš»OÙΨ´ÄžwnyXð€nÓJ/@ºêškŸú޾u.y3åÜ3Yì®…rÝ{³`^‹æ,¶›Ÿ{¼ŸÖy&PɳwHؽϠ\‘ò­¿nÒíüÓŒyKÙí»ããZÒ×s¹å2Þ]pÞeÔ4W ?Ïa ÷2ÿ¥¯–ç;òÑ›Ñ̹ïˆÈÎAçƳù8Î1^ǧ?t |Qƒ|ìüq"œ•“½(–„3Ç!É~°€iÞÿ2Ü™¿î{z?€Ï]mZǹì+ðz ªWÎû¢®;§sÓù[ œÏ«eœ;×ÎÒT}Ý—ŸR 9?ùúµú7éä¼Ï÷ìTûÑçÜt ûõÛÔÒ ôõÛô›5×¶ÇèYIÖþ×ï`Ô½¢¬}¹Ái.R±¿ûF•›¤Úßý÷?5–¥—•¬åü£¼JŒâVUú?|ó¶]Þ_´Qc>` ñ=æcÂ@¨›‰ÐXEÜtaÒÇ^-P¹»÷Ø>Ä™å¿Ïƒ ˜sµãaÙqƒ °ÇX‰œA;cUçé»s4+dzʶévê­k,Ênž‘·f»$ïôS—Ðý/€à!ý0ê>†ùr2“êrmÚÏv ú?p‹^,$rúç¢_€ÎǬKwÏa¬ÛÄÍ:Ÿ_ŸzØ9߀ct¶a‘/€x€¿[ö%Z†~ó~¤æäɧ_ ]PnFàÍÜÃbÇûýù=yûüùÐGVÎ>>a¶=Ÿ}ÞæsY–Õ/xd4ÉW,k¼Ž‚û3wç]çäýqü j·“{¬œý½ÂH§`Iø¼îb˜)¨Ï—¶ÏYµÉáXõ¯EŒb`Ë×ô±¥õæ=lž?‹ c¶Pϱ[âîfVÔÒò^ˆǹå3㇛üt…û~-÷[J Þ`ýû¬àT °ç&Óæqr}“RlUTñ1ùZ ò·úæ3–6˾ª[Jžz@ùÞu7{®¹Ú8¾«‹ÆÄÒë Ì9 µ’ßùp°åk†³ùu‘÷•Ëmî´Ã°{nå:g°LäF¯V¥m0“#ÿ0™Ü–p£–º‚é<4êaÑól·¬=¬9¦[ë7ý?9·\í)4?]ìy笼7×Tû¶Æ±Îwì»,:~÷5 L0¥ŸmŽ9¸`«- Çk×\o™sKÜÐ Ü`[®¡˜ØÙ¼—‚×Ìý8ØWÉ/½YcrŸÝ§n;‹Ë¢{œûHÐü˜ì!å§ö|1Ýä÷/ð›¾"ÀÜàÚ× v{A¶ÍøtÝç¼½:A¯ß¼óqf×5ôþfÅ{ágrÆ ¸WÞ¾ ª#»€Åv‡ ø¿×ûæÿPc(c’Žbæ®(™;ãYÈã÷B¿7ú- SžvsÍ1¸ì´ÀxÀ=¿‹ ÜØÍœ«Í6Òõqfo€ýÙ÷wf˽ÀÊo|ÿ¾k¿¶J¬‹Úæ€ó­_žqúŽWe¤š{àš¿Ùî!ýŒðr{ à4×,¸Ú€îR¾½`,ýÄ©â‹KŸ½òîSžñ) »µÎ1‚£ñ@IÚçfÁÅœ‡ÌȳS™¿Ý–´]eqõü¥c3ÞÎì®y.–]mÆìE½»DÖµþ”Ë ¨š}-ÏÖ\ž_=vUñ*ó&¼bÓi=?d.ñž»€ðŒ»†0ëŇsž¼Ý†°¼&WÅÜ8ôèÁO' ½‹3àösÑY,‰OYãV ¯¯Ë¿mt)¹@_33Å¡S"<à‰7.¹±ÆXYš/;z~Vtæ¼%=ÁaW…ì.(IÈ:òº×% |-æ¢Ô=ÌnæÏÌ6ÞgǬöäý÷gtÁx/˜†•ç½Ö±üàp}Æi’sœrÿ5~4±Èµ[Cj¾ïço¹>†ÔÏ5ùGDÞžþ0ê¾Qh¿Á¹~üÝwø ä4Ç,û˜œPŠ-+Ê ;½÷ÍÍsúF©H)K7מÃxœÞ“[öñ×o“›NnZËäÈió <«ùä¦'¶žºÙy3ÑÎAÏ‹¢óÔ-ïS~^3å/yªq@|±6‰re¯g‹& R™ÆÒw³å³JPçQ¦œ–²µ¿ûêÍ”¬}Ø ?kÝjãÞÊ7÷s,Û §1ÆÅýÖ®ÙÚ P„Œª¶b˜mdßí«4¥»ºB“ÏÁ{k C,n`0ËþÍsLE^:¯Õrý‹RÚ€Þ“z™êÙzPóÒåã§…‹|~òÝT9³¹Æ?2Ž¯à‹µì~öO ¸ÛJ'˜t⨔#qŸÕŒÈ%Ô°´ô÷b÷>‚IÆyØ’3ÞJ;öƒÓ´´šÀ¾®_®¸®NnŠ¥ä?íÖŸÒ Þ7swõ öxþ&¾Œù|˜û‹;î‚óYÔâ ßÿùœçGàQGÅÎÕ¹’´ÔbeGǬ¬Ý}¬'þã«7-»2W«‰uç7}㛒ƲZ\¥Øœ×EôoÇ0.Æ*ÔT?»¦Â¶û&§›qByfbÌæì»;¹ð1”ÑØÏhÉÜy€“nP^æ@ f}b²oqùè J´ÂÉDO^úÆ€õÏžß 3€¶§¤˜0ïåŒÁœÛ¨(ý òØó ]ìzÀ8ùŸ´ ʵ\µË±) ’̨uŽ*óF{HtsÎóÚ§Pÿ$›Ç,k\°Éýíñ€ï]Ìk@eð†|Ù2üƒZ1ÞÛe€dXmµ€Øül‡5ç0Ôôx.ðK]ùó}¼¯ýî;/D,v„]+¾×Ä /ÚwéýZ׋ ›7^ŸI”#;W«÷é9|WèïwÆcn9G}ó}CnžÅ2G§)K¦9¯cà9Ǩ[€+¨£pqŸc<¶Ê›/oîÔkLq¡Ôý~6²õR1f`žÜñ⤠ݫMÈëÞËŒÌQg‘–\sdíþ­÷>åêaÃçþ³GÔÚÌ 0Þ9ç/ñf½@z·ÿíZ’uƒsZ*µ„ ”}˜sßç½Øtž%èÿX¥Ô–³ÿí- ¢¡$îGÊþ ,:A^ºXôqh÷1 €{=›Ý"e§m²‡’Y÷UŽ8鮺¨d´8§™õΙ¾À „8‘ß1oYæ&HÍúÏó8 äÓú»¸eH°=ï`>¢1–¢ê»WÙãÅÕ&j¬ =–¬»ܳÆziæ–Ül«¸”¶£â]Ü™}ë'À1ž3NÀW<6²ÙЕ5°ßÁÅññ0ß%wÛà´Ë,hìƒyÇúž×êU•SŽÂÈ©Ãø–$„ ¶Ô×ÄJ¸º{Ž|س˜1 <ç]ÉM×^w¿‘Œα×ëœ[±ÑRšsNúókÎJ×t_Æ£ÿ´¿ùÏÿÉ÷µBÊnÀ¦Ã¤ß`üñÉJÞÒ%»š|©fÏ呹“ƒÅ ­nv+ ¯•ë0é¿x}µÏj¹Çtƒ÷M›1P·ójJ´ìмÃ<Œä"Å3ù;µÑaî Ê òq±½q~ûðêµ »úaÏͤ/p÷8Ìʺ»· ^ãUW]ñÇÈß_ÀðLޤw‚Ò@1Oý`ë}ÔVÿþý0ë£8£ö”'Z9î˜J}X¶mƒc6 àƧ<ÛÊßÍFî8 %¬g̺4A8ÀÛþ—n¸Âëø‘$[&½@~窛׹氰®v§Ì ¼ÑoE©o¼Í‚ uÒp`ůt6ƒ3@óÿ ¾ÙÌ“ßeØñôõ¾çló›¿iPfÕ·‚ÈSw·cœ6i[¨ÃX|NŸ¶ã¼ŽÙ[)Ót_­þ2‚㾬{y™ÂÁ¢WsÚ°å×fÕÈØÛôt:ÈÔfÇ¿¥„r ÃŒW…›%-È/GÊî¶A»UŽ!EL„ˆ— \¶N]¤S½±ÀoëNï9¶Þù¨@Ó¥.LùVqº±Ãžk=Àn'xGùc¯E>·”ÿ"bö ãÿñÁnŠ‘xƒ«=xc_Óc·¬ÜãK:뜵M³é'¦s VK¿e«O£;3è€ìaÁÏ}Ø ¡•ŸbI_‰üæ)¬ô£óÝ÷Âà 8Û¿¡ÊÆÁŠß¼OÍ@'‹ÅjoÍðb² ÈRw>ã¥Sëpd#ëPÙæôõÈ8×|øqZvþ®Ÿ¾ã+õXUíçòÞ÷ÐN—œ—覿"“ržùèw»õ^ái u=GÆÕ%Eš9OÛ+Ô6–óØÍ¢Ã ÜÝ_Ý펔g#¯ V½ë¥Gþ`‡5ï¼ôaŽœtÚ”™‰™œ€{uƒq$î¯/·w¢t?4°“—x÷ƒ8̹ö©•+Ùe17Ý’J¾Sû ¤–¹wPX§4ó|ópMýÚµO¬û%‹eßu”åd®-9í°|üè‹a,pãö–m[ c 4 è.k…¡l)ù°¼_Ì¥FuÀ=Îó@鹯€Ö˜°î± ˜oÆ'‡°qܰÍe’»Ÿ÷ }ö;n£µ¼'çn‰û‚{ç¤GN?×ñª#» ‚±qXÇlÐ}ãÞœ3Ï IŠ|ƬôÀ,Îyâ/Þ_~ »8Õãñjì7nëä”󢔚ûªbƒ¾:·¿Ç¥¦éÊ™ ˆÿžÜrÔ;äšË¥= ‰‘´ÿS¼7í1ÏÌo_Œ7ñô€1×±Ì-ÅRÎQ}®¤èòh-[o†Gv~ÿI¡jé:,ùko¿€=O9Ñ–°gŸ:çik~Àùš® D¿ô¸@º¼_rŸýô?d×ý™2jS¥å!ÏΖœ»Mh³ø?AýóÝV-ó Øð(ú–)Oî¹Æ ÌI4Ë®0'Ï<Äß»ì_F¿€w Æ(Ë¢Ò·±¹ÎKÈAò,¿ æë5 !íê5ïcN%n@âÈ·ÌtacA”¢R0né<êûø•¿8Ør0¸$©Ç`Ç%ý¨?TΙñ]ØGzŸ±ªøõÓåï…)ùb<»ØzÉØ)]ƒn|.úT_0uKÉÛ)æVÿ!u_¶| æ¼?f hÏßµ¶ÿyVZ ôîkßåú57v|äÙ¿ãKF.s6GÊB;ʳR5_ ÂçšU¸?åÃvO­È5¬1ú{¥³rÿÏ4‰{<%8%Ÿ¢,[ç›+j¥WsdeP>yèÙ¤ÈÛ{»uGu“UpN[c½’þjÚ–¼âÛdÆõёӱŠï~ò˜ØxÛ =%}Gî>!&>yëäë™U÷Ã9bÍa5pz'šA³N–î03ãqr×ar¼U®¹˜v¤ïH7Ãá< ëÞŒ:ì¹ÛÈE#…ÿyüwß¼Ì7 Ï<íÛí]ïõÕOÆ™Ç1Ô+öœ„ÊQÇZóÐ5ÿËçï&ÖÇŒtP²Lùc¤Å{‰DÏüÊù|ºM-vÀÜ”ÂR0×ûœc™|ƒp€û‚ͼí8®Å æ<#™ï1$ߌmÜòuÆ6zþÈËûõJú]çEþ^Ë,¦üóþ_æÌ#awœ%ùî\óùß ŒëÜ1<(W¬ëºÇïϨß#æn Ò‘¬_ÁÂW—LôXrÅu.Íç{Mª ÛI…é*ŠÃ#çu~—Ö©ÜqÔDùýK@5Ê¢ȱèwvrÊ#9ß´#¿6Ì9¿ó>.í¨¶Î¸P¸¸k [îû¡ï—ÈÙÕŽœ@9åÑ*íL÷`SÅ󹻦¹ârjgÑI» …–²;­ÎÏ+÷¥ê£­³ÞÒuƒðìO8ß\ç–ÑÏOzÍ´Ý1‚œ}JåŽoÐãàrÃ/`Dæ_‹hß,ü*O‡¥WÀªšì†¢|[FŸgÞ§ÄŽ$½‰·{eŽ©”Õ{ÁA㋇–-v_ññ cÜ}*ŽŸ²xŠyßc€·yéKèúØÁL‘Ñ3~.~e¤#8žL~Àh¯.tm¿˜w ÛÊ<â0iØ7L?9#¼Æß&h›÷¼1¥ÛÊ&Ùóù‚µìÿ1iûehÀõVpÍNiÉÍ|c^ ú„:7,2lí_ï'çÙ)ïùù²é_‚•¶C~2¯ûð¿ò{Ï9ë òÞ4o|æª3ùC¯ÎØ  [ŠEN·©ÑY@œcõÙ ©; ½Ã7ÇuGEîžÒ(ÈÞÎuÃM?@}ÁzÕS€ÿíKvG9É.7#à6oY æ³·AmuÍÇ4î/䪛E¸·™Ýû<œÕ¼6R» âZÖÆ[…æÃîSÞ®ï:W³Iɱ$Ú|É&qÔf¬#yæ9. œí–nÓ¼aÑÔ'v ÍÖmzú¦lÓö ¬ˆ­¾\Þc°Å¾EïSW=¡ó!)ÖqÌëàÃì NŒyØ5fù³ÏÁŒ.9Ëi/ð܈$^ç)7tÞH¹¿þNóÐ üÞÆ:mÆâÜNÍøaã› ×{äš%®Eˆ­y?cl§?ûâ?Å`þ[ j†¹ÎÉóeXÈgI[˜jµ)YÆ1#__°Îç¶^§Yr3çjßáïóz@¸­ïjêŽ `Ï¢[öµH—v÷é=£Ü±4s· @¸çÔk~ól €zL᫘TÊ2¿‹º—5GöNNz¥2Ô.¯²i–žç~2÷õ@i¥ÖÖ.ïØqÌà ÒaÎ}ßô}”~ï+žû°¶tǺ´7kþ”*/‘¬Û`–\óqf‡U7è´=õÍ+Ý£,@^ÏB•6HÛÏ_Ö“‚(J<€skÌýcÌ|”®²½“S=Ç™Õ@;`\Ñ Š9…kÂü¨ƒzŠlò“Ïä†ç4K½^T‰ö¦âo\…+‰×-’nˆÏæÁ—…¯.¦U2ŠØÁwÌ鯲tÇÂI°Ïž›ÿÎõ›ªSµÈQø÷Æ¢›‡¿ÊŒÔA7¿„îêÌÉlrqVÊ|'ËŸÀX—ü½°çÉû¢\ )ZŒäè'"QûT¹gܰYYïÈŠ|¶ºA““ޤY—š­Þ ¤‹AÐCE tȵS¸œL1y˜’¼Ý@ÞcryÏ<=X ¯‘Üxµ›Qß2;BÉm4X”ƒ®ñ6-ò¢lú<¤â^¬};À3k~J݇ᢼQå…ÎÃø)o½òÕ5f (9Ò[Æ`Ð-¹­<Ùž/@¤qÜÜ ¢¬o˜1ľæêX€R$û¼Lù°§Ã3>¦c0¸ i7¨|3&dÛn—ñ9ÿ°Ä}L_ú‡}Ž [}°ÑU*LiæiÙ*r\IÉ-™Ÿ¿[`›}bÿ.^[ .—k:¯]ïuÒäô”OeÆH£°¡ÜƒŸC!rlŽSýXwõñ}I0ïc꘿é…7ú¤»` ×^[* kðɨÌæ˜ÈÙõ[¦\û í“C.æšßME-‚nÙ4Gÿ†{Žúè¸ÓfqVómú`÷þƒ>(7 )œf¼­Ùú‰Â,ó:§üÚh! Pú!Xp¯…x™åöø]>­ÚyæP$Ç\áç’¤ñ)Ì´«€Þ̹çâÞžç$˜rdî‡E¿X÷}oµ`“¿é\‹þl–”þɰ™Uƒî”p—!ß¾½N»ûuB?%Ë}SÏæÃ!O'}ÍÆh=Œ6—‚/Nê€wÅ‹[’qס?Ùo$68SÎ{ÈØ±@0wmïì”;Kíó£¬Cý_‰Ý÷¸ÏÏê[)/PBð·±HÀ «z¼¯š¥ÏãcNÁ:n /ý:Ú'w~úŸ¹,HØtÅ€r±ðÎK7ˆþLyaÎA—#| â\/)[1çŠÊ'ó˜o¢ä¡p³/ ©{nº´ÀîÓæT‰˜q{ðÆ`.f:Sv·°êŠækê |ô”α9nïaa.)$’JÚìc\¤­%wI ãžëŠnž5—¾®)Œ± †}èÄéåðì|Ô7HäuN@D1 ›Œ-(ÙÒOØúb. àæ“£I2À ü°ô‘o?Ç>  ˆ2gÀ1@uKÅ%Ï}ÏÉëá:Ž*`@g˜|³s´} rÎîþs`±y¿€âv>_0­×œrú§Þš•ïeÍ"HòÿGÉÐc, Q»«ú6 §JA§Z4¨FBÿr»Ç}œ¿ŸŠ]XÃä ωèfÉžëß–òÁ nÀNj òuµ£ÊcÉÕÕÆµ=ã´ÈÍ‚—B‰EÑüÆÊe]}s4}['vöQI}t [_uWóaÖiKºŽºŒ¬SšT÷ÚÈÖfÒ³Hþ>÷[KÙŸ÷=ü·É1oX…Áõ ÈÓ‰{™ÔjNoU¡Ñ³‹ŸkÌxk^ÛpÏëý€q|~Š, ÷óD,êsµPFY-H&pó?*¶òÒÆž÷º¾[7 ^"“gÛ[V߬ó.:ìõº± yT¯žcÀ~U[ü×$*D#„"ç8üÍÆûl±*Œõ–Œ«¼þœ sù=Û³^ýV²b>ñd.ŽAåäÀ=c»Û?$s±®úza'&7ü`kO+üfg«¿‹Ýïù7_dmý9Çä_ù‡|œkߌ:ÇŽ:ã‹ñÏ{ÆtáfÁ÷C„”ƒë˜2°j5ŽùÇëEÀ+ò’{uŽ/óŒ] EüÝÜ•ë´qƒô—0évow~:†)°ëW;20nЇÃ;7KVÄãŠ랇äý6£n*7{­à;åëônæ\<Œ99é¼'ç.¬ºØõßy}ñT-u$ˆÌň´Ã´O~úÁ¨ÈãÍØÄH. :9ÆšZ#9×õUÛÛežd€÷àNþæä©ëaùéüÃ55Š ¤‡Ew[À·÷ŒaÕìyæâ ØE¢K~:[dóÔM_r›˜²nyšWyËâ›9ý—Œyßs¨Ó®þa«  ;NðÖ–­[`Úl7çm j0œt˜¢ÌëöØÛ|­+<—í›Ú_ö:}»€qý½¦0ò0âVB¸Ý%þ0t›’eÚ€_9ãÌÓØÒwvõ®Ù‡íÆuùêÓ{Μ§_ýw—P{ãï#»Ãß]ÒZˆ®g®È"œÎÅwŸßƒí3×\Qí/¢'¢²I& >~ùýB-„É9àË'´à¹ä™Ã€·Œ|rÊuª-ù|smµ8“º7(4oJ¥qúüOï´M îzM95îiàuÿSøžèþÈí]|óaÍ‘½ œÿF¦q}ïÖ½öœPßs@8’õvk/×vE›Ã]é{¨õ<“’³ÞçYèS9²¼cÔ){Ì{ Þsï;˜s˜ϹOÃìfÄ*MQ'j¿«TM-r“N“sι‘Dß)« ø÷t ÀÇ_Ç5÷¾ÈEõJû&wë¼´Á×ßÎv =m1rã˜Å à—ëÿëóð?f1F1jß%¢ç®Aßž]O²“Ž8ÍI™û 0›•Œï ÇV mæÎcµ­¾ì79öeÛ Äá„è Μ ð¶ü…Áqy'N@,4ÐOT¾Ä™#α—SkÊ6£XùÎG›wpÌmè°.ö0ããbÉ ¤¯“û9þ·©¹‰±ÝÐ%K×–ˆD^¯íÒ –x½*&}N5nf]7³2ŽCê^ý´÷&Œyà<@æ|rÓg%Þ7z»½wyKôJo0oЦ@¡¹ØjË¥6 ÞsÆ€à@F>pI÷˜5c¾Á$ྙq@eØÓ ÙûgMwñ€cXoI¿}¼ÛS*ljx¾Ù÷6l·¯U½§«Mø½äÜ¢›/> €äî7xî÷Ì5WêÄû,Ú,Èö{ØÅûÔ<~ã[·u)JÞ7;®ãŽÏd<À³XŸÿv?ô[öliO0€] ’cÞ¥½à—v˜óŒÛ;œö„çÚ3yäÞŸzåD÷û8vú×è“2iG ªBI5÷†Yà-™:éZ€pôÉ3€W9µe̹o˜“2…Ú0èÏ0‰®ãœ7S8=_ˆ÷"¾ûØ:?»¾çYo'>ïjÙHs;$ÆËƒñ3\dìyNMî²ÆJýJ]í3ÊdúTÞª^âòØÂ¼¥Õ}üs÷_¦oWú+ï‰çøQöÞÏÝ;v§…qà3gÉY/ ¯Ð(etíƒùF|¥ÔòÚÆ³ppøk)VY½Š‰ô/NÜRà‡âÀsŸìJ‡cÚ§‹!Ìç!Á>œßÝwŸ·ê"§îi;›³ qÜ:'uÂúÏêÈ/t`¿^{kùmNžÅ‚ëgcU°ðÍbëÜó«³$½¢ ®U´sµ‘9aŽ!êǘUF ûnÓÀÉÅéúŠÌëkHn9O–^ùF¢×óg‡÷ V‹Y1Žkª€»or¬@³u?lºŽ¤ÔaÚssÅ8N<26¿–Ço ¼òÓ5Ï@^GnÜ´>v|ÊË<,û£|[±æ€uêÏÚÍ^¼?ï0r )ͦ6ÁxØ@¸¶ô>ü@ÈÀ=ǧ¾:,PÍQª‡Ú3VŠTÞ`ÞÀ›ˆ´”:ÄÚßüQúâà çá_l[€Læh +Ç1îƒeGv þ@Ýswlç°o‰pJ´!?dóZ è0¡ƒ™_ð·†_e¦¶Î¥ñ/Ÿ¿Íœœ€fIÞ¼œ¯ýÀeÀ7ïv0>yó èõzjO^7€¹búGî¿à¼êÜË« ®1&€Ò€÷fÄ >#è ºó¿1;~ýoSwü0kËöo‰;Üøö[)U§ü ß»/¿}¯~mÕwøDL¤šö÷e8ðür±ìéó8&o„ÿÂ~{»%Ô˜ãs±[/ZFm„[»~ä ó§z;¿Ã«EÖáaËÛ‰œs꺯(Ôf+ðm•^DvÿÜ×È?Wž¸öņϽT÷]Xô¿`—­Ó“Sž4´ ÷†Æì”^Àê0! Ç]Ñ礲S„–ds~ž±,_¯K,¹y´GøM©¥¯ÏsaÇ©EþûÊ×·Ný¨¦|FÐ|Ç“º{üGîûª¹ù¼ƒŽÎŸPvíbÁëCðÌ àúíýûŸ¾Ì3_–Õý#»®|çYå`%†/ðQw®Xíñž|õ1E;•r­ü‘Zå\Ûʱ˜²j·Œž•¦suŒ÷ìöë¯/û˜,ðc²l;>õz:çéýE[ö¼WÕNJiï:‘÷b ®—1¬ZéãðpÃ8LåÈK÷ʱúJÅ@»€yn”ÈÒ6rS•!œ{ôrw÷͘›ýSÀ9`ÝʳÝùçiÏœÇ| qÄ¢O ucÍ1€/6Ýrß¼çA©J¶éxõ°7àFÊøum5FéµÉC×9#Þ‹ù‰Ìý‹~Ø ˆ/¹&ù–ïa£0Y ÛÎÃðøâ:F °Î¶Ê%u c›ÕU uʱ ×¾ÇÉk‡ýk ²}+•_‰<àG¯Ÿñ{µ=ïO¼fŇQgXôä#Wßá2OmkÙ–Î;Û3‡ój3§k}vµ N®9»@°Š€6T Ð~¤ö7?‹ŒûZÓæ>ï-ýÒÌísÍü,€dÑ`‹z\Ú/Ã6ÞOy.Ðמ Ìw»Ë–[šÎ~Ÿ`Ù©Æ@Ú l9ßy{UÄqÝÛ•­Ø”³Å}½tGõó;èßÒ‡ë–ç7ñ¯Ë{EÓ×–ª_&Ÿ¸µS¿ü÷:÷1€Sßš¿‘S~‡çp/JÞxXóIéÚh7v×2Wö´1gmßÌ]¹'¼“gN¨Pþg9»¿el¥ë6Ÿc_ÇÓVÀ–Ð{?Ÿç™à¿þ ýýõ~P›€!ùn—¸u?ZrÀÀïq&Z ;ûT[fxÀô!çy{æó ¹¥ÌVujã0×\FI0ï¸Ã"P?¤û þïØzÝ` <«FövTš3eµ%08ïdÎoXçnÕ²Œ§ƒ!y¯§šwñU›U/yüñ¾k»Éï)eˆW]&më^¸®}˜ ðB¯˜œiÀ¼ªÁ&¯Ýù%73¨çï#oè’r·œeÁð,^œ¦l÷yÏͧ®ú²È~ÏkêÀ‡k¾ ”e ï^1Vzó¹ûy`•‹•«+Ÿ¼]Ú7}ã†ý_¯)×î!·É+¸ÖaÔÉU×ÄÒ-VʓΠêgf黂œô.YÒ9bô}þÍÿò¯Þ&o,&/¾¸”Zäísf–g÷W¾Yk[„Øu?lÜ5/5Ô‘Ã[Þž¼s³é”—™°ó;cÞqLå`6¾„ñÀ÷uÓy0ƒU‡Ù€¡a‹9ÑÊâ—5"O]ÇWl¾:ò÷23ëM™6Æõ:o°ÎÃzÜ–«|RÕ3îöz´•ÿZlûï¾~«ö†ÇiàµE/©í×o6oЉ´#¶$Í–Æ Ô1ã=à`ÜÌ仆Ë9oòS>ègãȨœç–V'èÙ}÷ì“Ãï6æzçw½î],X¥À‘M­ofÉÎë°P¡m®ª«>öï žùzÍ#—Ü[bXo¤æû™L3P~³åiLÍŒ€ó½ Ä!Ç@\Á‚[ºþÝö‚_XòÉ%ÿ‚›ðÎ_ÏïFšbï³I;&p½Xùì›w¸{ÿXôaÎ;·¹ûC ;©S¹§x¬=O<¦EîÞöM1Ð5r÷Î!羨…òô·—KÇY×8ÜÙÕ0o0þÜ;}´ImÓ}^ænQà©õ€M«3Q ¦üóŸ•ïHÓ3£> œ:æ1çíÍã4>$íä™ë¹jåî~.ÌóÜñ ; ÀÎüU¢à$ÂhNÉãÁ –ÏtScŽ)Áæ±e¥—hsŒl^Ûಀuju¿£ÄØx@1¿ ¦tòämwªê–&k7ÇHãçú Ð-0VbœØxa•ÆÈÚ…1ýÿNúd,ïëv±ßE¿GÌÏùœÖx¹ÈÇ'‡+aƒÌMö?>È“;®¨,`{eõYõ"ß9CÕ]OÌ®Àä€÷ôô¥Ìë ̵©ÞÔÈ»k`·±r:–¿©ÊŒû¢9Wv\ïBÇanGîF¾ÌŠ5®[¿E}6Ö÷ çBÕqÖY省ßOû¬/¿0wÔþÖé4{.Àm£¤î¹Imî–op”&áf¨m¸˜1/ó¸v‚›³Î­öÜÔ5ö™\ã½ÒÐÞ9ê»’ï-̹$}ì ÒÕŽ¬Ï€sØ@ù_ÈÙSÛñ·)æè‡-À;Òwï׃šó~°{Ý.ð™³@œy§±\ ޹©œ¶Ø‘|jN9½Çž’E§S2 Yû<¼œ‹N®zƒ|ŒæJÚ>¥ž0èÌÉ~«‹-TL²4 ¼,ûòVo(WÕÀ¬^Kùòš`æÛãËú6˜ £ÎŒk»„|¾Á9í¼¯Hô·¦v'` °¾™dÞï)8caœ/Ö_í ´§€ÍÆX|P÷ßx-\)Í`S~OÑ &¨Ã¼±ó·@À=òûqlÜ/3Ñ9è“BÐÒú ¤_,=×õ6iCž‘ÜóYà¸Xñ^1LŸÚ7ûßNü€òY•+Vÿr…¯þ¡`Î8aª}JSÐ|I¹‘P§3«ÀfÕ×å] = ]à–½ô;^!}w™µŸ-qO‰¶HÖ5'L: ½¥ïä¦S35yì:o@¹A:óaT.&Œzäí @;ýåð>¬zïÇéFýˆïwy6ƒtrÒ›)Ð÷ûÒvjîò€ùH©6õ7«6 ÐNÝõ©/LN(Û)y4AžúvʹU¬“»Êëîê<[9.Ó–î ?^ hà^À{à #9úÎ`àÔ9`öeSþ¯ ¾Ô?ñ€Ïlk`½˜lÀ9ã×–¿ï?q¨Èv¾îÖö¶_9Øï9»™vÞóUÚn.Ö'« `æìœnó™I?©€ü€÷œ“…Î…Eª¬üœÏ?}=&½¿C ÂQ·,cŽAd@÷ÎíŒè&Ænk³ÀØåÏîÀt³J¡]šÙ:c›²$”Q.›YNì|nìòìϽD¯K?‹Å¹O „—»ÁùHÙ1y«‡AG¶Ž2Í÷ÜR²aWŒ¸Øõ‡k›{^9´cövT‡1£.@n†Û²õêCÊÞÑ5ÍöÚ7¹ÇÏK?75ñ1Ïý]n·U¼Ó¿,å­Jý‡ý¯!Øê9qYч ²…wæ™Ùc©v=÷)à pí–À+ÊT;qy81¯÷“æÚx©È“² ÖY¯ûÿÈ|°C³„°‰Ç&AÁ„S škT`¾˜üû„na ÎVÛXü ƒîƒ:׺c×¶8þèí“Û­•^8}sƒþaä×+Gw?çYÀ¯8òÓÆxífŽ×9S¹½¨—·\e]óô1[_´ƒ|9Jâ£öæÀkœÅ—Ãü¢^ý–è¼”Œq͇åê“ÎÆü(£»Úzæ*¢UâãžÙž$Úz.t <‘2«±’‚OY»ãQcfØê~ßGÁ&kN6˜çyÆF.✱l<±×"ûSþŒkfËö¸.·»yðÛ™«}å¢ÛÄúßÈßX†oÈ7xMæÞŠ‹Žëo]…_ËÌ/ÎMßv8ùõ_9¹b¯–ž›mù·cmôé»YÍìï‡Óµ;ìÍŠÎá ¸òëëƒ?±+0Hc’o]‚2Z°TÌù?«5œûÙÔì«/ÄäM&ngðaäš”ägæû=°`Àÿ$«£ÔZhÏß”Úc|?[|^¨¿ò¢Ÿü©©™Ž;éÇEâ¾5AË0Îí.ͦó˜E§nz…¥jÞÙטWØ}ŽÜÔ›]ÇÙ•‡€:AŽn²ý€Ò]Áx;ÙR#vÞ“n¶ùáëfÉï8À:òÈeÏ·O1FrH2‡2€gNÉ:?ÈÙàžÛ}ŒáRqç¦Óç —Y<ýY€¹C:»€ óÖ‘Ñ:p…Î8ùµó0Ü%‹‡4À‡U×Ü’Â_€þتæ€Ö´‘1W)-q»Êû½×ùt á>½ù-Óf¾Ëzåï hGúÞeÉXÀí~G×ýÞ…ƒk! {¿&Š‚1Wëk¯ùÎYÇT/ã¹6ëê#õÀ ùñ•™WF‚kÇñf·NÛHÏX©Bv|Êæ³Í÷ïŽsö;<àÛš~¾“É-GUs±à”?s0ÖQ®ë+Y7ÃmµÆ]FrsÒý9Š¢üf'‡\íì{>¥3Ür“9fÑù~m0®:å󻿬¹æ—„ýå¾¾*. £þÅ(Äh;¼X-0Lø¾Ç=Ó{ʲ+ÀÎB»ûik‹ZÎ^5É)Oh¬x—Aí«1†s_E)Íšû™H[=¿–™nÀwž‘ìЮýó™>ùÁyV–¹²A/êÜQ°[ÉsmŽ!%s+‹O'ì>L,,êA`)Ö¼Žçõ­ÜÔþL€ÛU'OýnP°Ì>&Ï7(ß÷ÝÀöµ­°ÝêM‡Ýwu¬9í3º 3 ŠU.lürs8HÔ&Ÿ×øéö$;œp.jÆtE¼]ØÇÈí~¼V䩾_ͼs;¦twÎ€Ž—ôåpa¯æñ…·C¯Ã—â8nsoHïkì‡÷ÚïrcHͽEª“¹Šb¸¹æ5ï^ºk·bãvž¼ÕÍîÏê*ï±%ôûcÀ‚“=Wv·ÈrvwàþÉWo½Ô@Þ‘¼ó¸£NÍÑ„V³3þTaf=À·öÈá)ÙVlºÜܽc9Í ³®þ€tJ³a—•~oæ€#qßR3ÔN'¦DÛä©Ã’ëÁ*¹çëÂ˃™Î©9û<ºëû€÷ß8¼ó£÷¤òlýPZ5Ô-‘y¨ÀùÈÁFÎå‚Ü’w¾÷Á\,Ö{ÍÓ±ÞvNi6 3ãaÑo¯óëø m @"1¾7P,¤v›Óýó¹°ëé pϹ‡u•QyèÍÊ.Ç,2è›áUäéßÒrb" ³Mæ e GJä5GÑïmÞýZ8Ð ÂKÒߌô¦ p }§×@;¥O¬ß@÷#]_ÐÎç‚×Yù¹=Ø×Ô!cö–¦l; Ê1L¤B¾K•J²±j–òž€×÷\ß[ÿ0þìëw5W¯™ùÊI«á÷é»TœèœŒÁ¬£òù2Œ¸ÝÕý;ùB’ôqÜÖ)_ î¨Ô#¶½xúºÕN¿|‘ÖJ¬,ö*ðD‘|üG½'µÇ±{*1±êþ—{Ù0è¨Æ4¯Áy@9²÷lµàMŠZ‡Æb‡nìàyH»A9fo‘µKÙgrÀ¿Úõ 쓲—~jœ›˜ |wúK•Ç3Ý/uÞž¹[Eªcs·çYw¾óÞ:Ê@[ç¾Ë9Wž³›Ñ÷ ~á<`Š%»†<ìþ(Òòî_“é35xSKçpúy^o¼bE-ÄÚ^ûõ2ÛkÎ_ôvRÜóãÔx3цàp¿{ñFÛ;~NcÃsìùƒ{/‡¤©Mã~þqaÕxnfÚâvºuCÓFNV¬ù°èÜ ‡A×yô>zoä '8¾]`yˆØ‰ÈßÉ™Û:é䥀vz*ŶθÞb"Û¾ ³Ÿfr¯™·ì mß²JÆeâôþì9ÄäPZê9 ;Äõà+€«óhÛ¥ÛÜf®¶ñÉ)†E´0ë:Vmd°°äu“Ó®À´jâa µì\Ìøc¬dR9]?ûúmÚH¦¿7Ci}»fc/@»ÁyöÌìøay˜Ñ¹øù:°Èô·l[cQÐ^6kyãœÞŠØóH½%M¿Ï‹Þ2tŸ¯¤ëv3ßEœÐík¶×š”‚QD`0H¿?òGÈ|>7^\êÏ‹=aÏ{‘(‹=Ó§cû˜fÄù>)lÀ…‰>·¨OH#‰Äæ¤Ã„G®}m=ßã|—̟̺ÆüÆPBuÏÿàÒîýRüŒDÏï¦æoþcü³ír™:ÆyèG®9wIäë_œíòifŵÕ÷)ÚÊ.Ïëüró—Nû PO;`þ¿”ÿ²%Wuƒçi\!ŒS T^ŠÄ6&ža°y¸Ø¾×˜WŠeEõEÑ]u†?Vu÷Þ»ûôéó£[[ZZ¾oΤ6íí¿˜鑹+ ÖõšsÏgÉ3'ú©ã •.òvòÌ‘µ“®·îíªZ• 逛ž0CŽ‘±Ó½=ç ù¶†Ëöx¾Ùož¥ïrd¼cR0|™1J‡EëÔN¿«<ÝØc+jݤû¹ã·ô½€²UíͰ{{™æƒ§ݾ~å•“ÿc…˜lÉÛ!°oòtóëI›¸½Ãм¥&»Ç%º.Pšr÷ÌÆÌP0¥½AxüʼÌ(ÅŠÞ%ÆÔ—™7-ù€Î‚ø>Þæ!à ƒ|å£×µœþ¾æ{Ü»&:ѯ?móžó`ÒÀy5GiËö5àŸÜï®q¿L:í}].Æ~ÿø/ Êæ¶³®sÇ­³ó©ˆwÕ6,{Í<ÿYÀ|J“xÆÚàœir×ëîOŽÙÀ‹FŸÆVmÔä´¥ÇVØœëØç_YJ—vm÷ÃÉ:Û’—ÎÒû¾ßˆ™@ú®‡(…Úè³®1ÒÉ9$¦–ºe‘H'‘LjÙrK6œkPNæé#ÒWù›oÍ„m-ጱ´”6”%=ÍC¸ÚÀc0׺Yù8Æóo[®öu†€»Ml.ôº9NLØp˜LƒêÎ[`Ѱºåɘpä—´y:Ró‘\·${¥ÒD3Ç{ŒÛwþ;À? :ûpœŽ=îJù9n_‡îëvƒR÷Á~_ þü¾äsÎÿ{úàY2±ð’`ê‹“&ÛÍ$N}þ’š'u‚šáv¼ÆÀÿFŽìZ¯ïaŽÅ÷Ì*‘ýÎw;j“©¬P©,ù Í\»±gÛ@]me éRfü¯”FÚXˆVŒº¢ Ý6˜œÄ££'.߸ ÈÚGíkêÙÕ7ö?ÝÞ$0äôOä~½CÁä/“ÁÄ0â³ý5XÝ㠤Ŗ§¤iÀ¸+©ØˆµÜÚß`üÅ›¢Ùt§˜ÍýÇvo«¿>Ǥ¿Ú*­.mê& jIàµ#7÷ù;HŒ~&S<–—{øÉ¤+nÉô ®nÐ}´ÃJwÛ®Cø@t’î;,°ÛžB°¼u–¾¬ß„(ç@z)$]û{•Ó¾ÖW ;_5È7ïzI3ú®S̺ßiÏ7Q·Ìõ‘Ö0˜çÀf‹su~üû¼£šÀÅݦë~û5Eû9ÁsŸPú^s^ ZÏ<éuâ» `н]†d¼‡Óµï–Éð¥|œÏŽëá£/ÓË(³ý_*c0Šà˜9&;Úè3›VžÃêç©JSkcùáèø“»Ãu¬¶ö؉ -eçq|/}à c>áþ°êaÒÎ5ûŒÃ{ç§ëF©:¤Zj|ÍrO„5Ç©õrkUÝS-àŽ#l±éUCýµÊ« qw?¹éÔkõC‰¼¶˜wìƒÎŠ6äAЍ¨œÁzèúÐoʹíXWî¢Æ®Ûû欻žzëyõ©A³Û’Θ’všAOàæ_³þð¾ Þží.­ó_wxS+Öwù§%aÑûcÀ}ØÈ€ŸÊiÇpÎ@ À^yÁÃŽÖöÅÊwº€žRò¿ ÜÚí}YsØrµ!]°_á}ï¶>öJãW~œœ‰r/I¨×Êë³ìã0>ËuX÷õü@ßõÈëuºmäëÍlÛÄíR_t›?¯2s£¯¢$îâ)•Æ„Rÿæ´)Þþ×jpÛ$®™õünÈ5Ž,ݹæó;ÖÿD•Hóo S8ïד};á—²iª`®ÿ¬ÉEw4Cn?òÍȵ­ ý‡°¬]@Ÿ`“ÿ[Éö›/ŸµN9µä®Ï¤«Ûjiùº¶¥Ê‚§zHç˜;È3÷p³à€ó2Eýå¿‹J ©;j3Ö긫ïý÷/Y0×ö8µë~ð=%Õ» ¤ÀaÊ+÷¼€;µËÔÏ3K˜ô€pBm˜¿±.jӬĠgÀƒõÞím[3ìÈ‹a:Op* -ø¦”ð¨V—0Ú÷¼£èv&%ï‚eˆª©uþš}n–|‰¿´,³=2y˜kâ0àã<öZ ~Ýry›’»q¿.˜FÛkÆŽ:üÄy?:‡½~Kò $œXpB²¥öYö›7Ƭ_ð}“-AvOÉ3 %ú˰åâ8Çͽ_€†² ØÌ,fš`o¤:£2€y~4sÝ2÷,# ¶J¸E´µÏ/鯲ÛÐÇ¡’PÛÎþ­Ó!*ˆV2ìñý|oöÚ=R-p¾kDbÎ È7(LR”“î¥ä_€òò¼nž©•®àfëÙoËÍ©[G÷Å퇃÷€õ¬§½Li\=.³åôŽžv3ï1‹+SòöÆ„PByx²¡œvÌËñx”‡(À?{n3êÀ1™S¿"`=,{Iß³Ý%„SN(ë9=õÊ3±“rs'Ói¢öW{¾÷zÝ£¦yÖËÄæü èçý {»Öa«LZ ÞŽªÓN~yýŸiÒîƒf˜òŽ5ÓÔD€%êÀrmOÉ´´íw¥4)Hi²r*ÿë•kîÔ)¹ÆT%‘¾äþD‰4ßË´ ¥ œÀ…],ºî™ ­sŸ¬{nòÏÍœw>9 Ào¸Tq™¼sxÄ–QC®yûë/¬ÞÓsŒÛéSDMˆb°À¹%ï0¢—tÝí ž†ÊúIdÁZ6è¹I­&g8×@³ßœ£bÔ© òלíVsn}wŸû[ ÖçT˜èÀx—*·݃äÚ7ÎØÏð͸Uiïç²"³/í¶†íú¾Ç]Ó¼eþN%óâ´Qƒp•‹wÂ~ÍR ]§­?È´=”%Üôo}ÿýFË Ây,[Ì~ƒ¾þ!ô©Ë‰­‹!ëwäÚ®q]çË÷lÎæ*L ÙŸër~ÞËæv¯k?¯{šç­$¼úþ§\Cöi:lÿάqìÉß9eùìsçð]sDÇÁKÁ×­ä\¹)‰5—iœÚÚÓ¾R1³ê^ï>¤hãòîú¥Ÿ}¯õ´qcæ®efÚ‰–²‹ñ¶OŒ} Ü~•b£^:€<̺Žaoae‚2Ý©º²ZŽìðêÖf€ºdó0.ÔÀMÎ"€]À_ãĬ«$PÊm®ºöý™¨ÎUÇ4n€:,SÅæ¬·q\±äZ6¶eXâün&òNèbÉÿ}¥´»NI7Ú.£+ƒúioÃz€~–Îyý‡ú³m Fi»Ý®5ž|t¯¬jü¸p([`^1ê­À {?@úðŒÙã¼ø”0Ó:s[|ñ^¿óðïòf\(®÷ÃuêÒy¾æ; qó×ú\×߸§æøš¼ÅŒpXwö]÷ô5NüšÜñ(BJ–ÎoâeP^¾ o§¼YØs›:bä¨cj½sÒPHk1Ø-yz¥Áœ,º{9°'Hß { 7ƒŽ;»Ùsµ¯ñ!;àœÀ•m€8`»·åü§›5wÉ4XëÐnE÷ßkŠ ŒŸ÷-c”d63 §ÝŸƒtõ_á´2Ørƒûçà¯?†%?ÚaÅèÚN:ÀA\q¤ô 8°7–8s©›PCõ¹nS!ç  Î²A1@òNLýìFp×qß|ìœB:²ÿe"·¯¿`c®Õ¶ ·z‡d[l@Jl~ÚžW|—Vžq0Ù1w+åB“kK6r=Zq@ÇP q ·Ïºól_Iœ°y€ NxÀ2³ ¶ÖtŽX­=‘šÜŽ)"ï”.«¿_D.î€Ù˜ Ô‰ËU|YaΩ7µºwé2'Ø}3æ³>øäT‡õï2 ÈrΜ >sœÎ³ ˜w?‚öóûËÝpþ¹Ç×>¸H2Ž>@»âJWÐÌ37ª ™~‹ÔË |ÌV$={­×Î,:ã4FîêÅ ã²úwfÃÝ—¶ë”ckŸ¶_ÜûúaÑi£¾åbj»þØFr0åxë%¬Å¯¾|NLKEy3&~“T±ìÄÀ?Q® 3!=ØæI¥˜Ïê 1Aó@9Œ:®Äoínì×L5ƒû¡·åïô „ô9j=lσ8¹íZÏòï•£:˜dßÛ°êl{ û (°ö1à‡úìxÜY^là¬u@—Ay\¶1óB"íºÕÚwîþi˾Ÿö óZôÒ 3®^K,öNÐϱôž¨ÛÍû…áÞ\ù67óDrœðÿæ(í÷ŸvÊÇz¯šÙÉ J‹ÑÞ Zû1ޱ˜°åÚÔqX¸ñ3à=#u×¶Ügß#=ß<ñMà 2i¤e«Evÿ¨JbäËíýFÂNL~9šE}=q§ œ¢–ÉãÝÞ“‡ZFÂðÖr|•Ÿ\óMÅ]>m™r³â¨ì'Rþ!oaÉ_®ôñ`>1’ö•®G¦Þ†§%{O8œœÛQ®qOMÐN.ùòÎ7w ¶SŠœîç Æßc×àÝ)xfΠc ‡|]ÄCÀ¸H?{5k^ò÷OþãÛ1^&FÞωkF­¸žÙ¯gãGaÿ\5¢ËyU›WÚð]¹h Ï]W¬ä;ÏáSsI Àt*r-ð>'eµåíॉÛÙü$&_0ö#F©\¸ŽôYðß㉡m'>žñ_|ØŸ%K&ü›ÈqTR°&3^’çKðeV£ÆLqudëjsßÁ~i$q>uÏÙ÷ @·9ñëP¸A;ûïoÆWžþQ*ì<÷‘Œsþ(žSõ[_’#Ö™4©Æ wÎ×d%$Ú·ê¯ó¾ìÊDÓ*Ô†Óå­ ¸%-uÀÜË—[ËvL˜Ò×òxm â8*·+|»ÃW¿‚‡õ3€]mè Ö9ž2NÝF4ð °y™‘$_w€’Ö3Ž’n;ŒèjýÈGOÄ)`xoõ.ݾ€Ƹ™äf˜Ý¸ô듟cxr©ëi罯¹“©ñzÞ÷Rø<Öw`Æ&6:ýø íQ80yÑ`›¼ñjC²> úÝnßï"ªµW®8LyÌ;<¦/(]X×d\~o5!‡Ñ[±ç«²a›ÿ‰0âþWýò7zÒ’ obRxécøFÊÿ•ã/¤±\™{˜sÖ²¤ÐzÀ÷䘫&]fkOViÁ’gÂXûj[‘uʆ2áLjàœ%J³1f­Ô2ÆTL>yKܽ9æÇóÏ ¬×ó2v?“Ü5Ïû™&yÄÞŽ1R÷£SâËO•‰S'›çÿuvß`¿¹<ÈÐ'=.µ•qØ·}ªš`oÝðŽÆXwíî.½æ:ö*•Á:§ÃXjÎã“ŵ>SE í¿ ÷0Ía¢Ï÷!vãs,eÁbMœôWÞk­åQ¶î4 ü°Ì9ß%uk½¾Ÿ¯vv¦€K.âë{Æ+Çû®ÁGÜ5¬ï·1¦o™E‚mùÄ•s<ò™uâGÅqê}_ê³üWùRküÌ”4ý¡·¹›¿  §üÉåà‹®9ø5q1¯¿¥Æe295›2IŸ·Û|pg̺~ù²ù Ô3{†4¥Ïs »|ÞëV{\¦qÌ.Ó®Ùè½)Ú¹Aj™ü¯w“W×uꦻ}oôÚç«çv}Ï6 9檣ž<¹î°çêÏúË¹é° kÄc~Ká„Ûá]`šÚµ~À «þz÷!Œ;ûÆÃe½àÙf¼·-•_@n‡bLÕJá¿N˷ɇo­Êo™kÀ>Ì8€¡Œå"¹8Ûg€Ïþ‘Í÷ñ4Îu<Ë®«^l'ì'ã+Äx‹¥p‚•Õ¶Á* :LuÉ¥à`Üh£9śϿk&˜×y\^€9Œ{OLMy¹û¸uŽ?/µã^NÉ=Ž«ýÜ®ãÎäÀ™6°FoùL¼\ŽqFk°Ùs<΀näì2tãûÇ2Æm«Øè2‚x4˜±ˆ·œ=mÍŽÀßÞÿ6ƒ„ñž~—M3ØÖXT5^*oüó6¶'˜TŒÉÿUVYšîIÊ7šÄüÿi@ÉUïòhGó©Â¡%e1©ºA›cP¼G¦ ¶¹úQVU)´qÜ×KÆî±¨¼d~º†ol«?2wOtãÒÞþ.H×_bÐë> ÿÑcÖVcÔîçíC‰´çbÕýÌ`€´:íO•lç›»zŒÚ~nqÿaŒkF}‰©5á´R1©ŸµçÙî4-&·ûx äÌ6#‰nŸ*”® žT!¶ÖX­ã1úÏà›Jºä©Þkúهɇ®”ä±#Ó§×k¹d!Ç8±¬=Ç=Yð»D÷î;øóÌߟ‘ƒ}9¿C±Ço™|ð$òÇd¦Û#ïIž37½Àrc PÔìUÆLž`}ÁÛÄuN S{ƒÙÝ·.JË»·DòÖ²“¬¯j`¿,˜ÁE2®}öå¶ìï?‡©M~I1rŒÌ jÙµ!™ {qòá“ßû¸ õ‡ô‰ ¸þ[ÿoM!ØÞ¼ô-yßÙ'3¹(G™º(®< ^Gû ~ö'õ£\O/}þùƒŠ«)¬ºÁ;uÓ¹©Eú0o木¾šÏ2í^fŒë¡ææ¯¸¤raÜÝŽQ\€¹äöÅðà[-@ÝñégOµÝìRBÌä4¦Ùt­“¯n‡y-múS ç’=~úÙwZNM[?zŸëì°+hóÒ »AxÚôj ŽÉœú¶äS®Í¥‘š©ò§âGjÚì™— ÆÙþøˆ9U–k¾ãºžsïG^|o¤ñ Ð=î Æ.¸RP‡zVÀaÀ~XyØo€7ëÅ’#µ—1™Ž[ýËnW›ö)€ÊþóÚ“[ÝryÚˆÍÉ_—trú¾û\@v÷y«.èó%Õ @< Ù`ºS满ÀlÉÅYm€Zÿ:¶¾Ÿ¨:Ì~wzÅ~ïQžgu€ò,5±\÷+Ö=éŒt>/ ó­–bß—w®Ö“7M˜kÀn™;ëL¦ãIÇõ`Ò‘´gâžIö‰)Û¤ÂåØ~y÷`nÖeGª}Û•ÄßòðM…D¡¹cFª•V߯h™í%Цslð½Ì®7î¥ân±Pooêi™ro9¶z½³KŸ0ù+)ßÒÔéŸ*Q—z˜kø¸Ž»Û–dâÅ.çzM`€“9枟ÆÖþ™`xu4Ÿ c?(ìùŒ™E;dRo ÄÌ·Ø9µ÷‹Œ¢k*Àøý¢®€›Sp«¦ Më;Yƒ¿ßO À.v{9 yy4DU‚9œrŽ—ï½À¼Õ-v9/0îßbrOn17F‘ý?‘²gòºH“¾–½ÿ-[ZRí¸®SMý³OƈAã×-†Ü õ’Ê]&ÇüW_<€ ר’©¯š*@]㣜»½÷ ‚>7hÿ0~*-]w:Ø(ªâIÒ»ÞÀ¨w‰4Ÿí×OwùµÜ:fXsêšoªÛNü+\ÇÜÛ”VÓ3ʸ²ó,3ÑÌã ìýŒTæ^ží3ùÇT&º”°S V!®6í±=‰ˆ7µ´Ó>j^L‹›Ìy\®ãµ­fDT7šgsÞ tÍ“3nSy÷3Üë0à:çrY×ÝËÛìí«»”ç^8“ë¼$èB²þš‰’Æ¢ZÏöNÄ€/Àvƒ{N5‡Æì‰ûÍ \/>@ оè~¬„}ÙÏ[bñ8Ÿ} ö˵†k Äùn ½òêÙ·>Ë}Ìž=#ö»Ú,¼öU&îíÌøˆš°U7<ŸãÚ]‹4AžØ;@|;¾»õ¿ÃžW¥Öœ×ÆÂᯱ8ÍÔkßGLÀ·Ày$^§\:ÍD¬ƒîÀzÀ{Ö©¥ž‡3rSÛ6L‹ƒxö”©}ÌØ“ƒÌ’u4µË®õä\RÏÉ»t˜¥8À+3½ó>©KÌX$¬q_pp©#•Uk3)$ð<ìG2›6ÆÆ±Þ²øôF¦®ú´{l3ï,a$µ- >uŸ h¥M’×?=ÓÞFs-]†§oÍÁZöLп9ô–zä©¡ (lÆX}©ïNûå,Ϙ•ß/P¼Ã¨SƬÁ8rxΛ×U[]üfƒb®ÍÍZ£ŠÀ °÷ËgD»ú³c·ãÛèÐÛúÎUþ·Ç©¿ÇÆéÝ€YûÑF=r­m˜nçà×ïï2r3°ž>À|ýOð¿p„ú£À¡†¹÷u>ú1ÐD²Þ yå’¿eÒ1ã˜àĈ3Ë©ªñF c¸ÄL®N.9 ¼ûÞÎQdýè&p—ßÕå×´ýV/¹¹µ» ó¢ÆÕùöþ¤¤?ç|{vA6éÕÄÙàŠÅ°Ž\Ë[¡æ8œë1|’â˜É7ðÚÄ_õÌIjLÛ•ð¹³É{†Î ç‚Sç ㇼ1õß üÄr.È;n° nàúœçÐøÀÖ´bsÅï@F]ç1ržÎCXIþ0ÝeÆvËâ‘g3vå5÷Ö âV1ð¿” üHî<˜Ëœƒý\Oq3Çö–h˜k°Ê dB“—ô8§ ~Ýø”ûE¾úšµœç†ZL»nÚvzGâN¼W˜ávŸö#ÇMñŒú/ÿø=å[ŠMwÊÅø5Êý}€º_«ä•Ó×N·yj> |$Šo`ßo¶å.ÃÃìNƒrJüx›1¸³„…¢Ý`7rQ·S+à­ˆ»rX°HL3nóL)…¤mXXuj¨?”ºÈq‘ÿ¶¯òiÐRœë>RàC62•mÎEÿ‚éôÓ¾@¯·‘:kyåÉOÛê À(,~1þZº¿sŸSrn_°«ëË>ÕÚO1çîzöŽìcÏÚ8/¤á3±`¼ÙëÇצÌþú½3Nëè÷{×ûäøÉ÷~îשõ¤ahìäŒ7¨§]ãÈ!¯”,Z²N;1¼{°çþ= `¸[΋Nùãïc½UAR¹Ÿ‰ÈÈLxåQ×3ïò—«ÿaE¶Þã4ŸäHÛÝžri–¶cæ†|cRØs˜ð䘨úþøŽ‰æ¾ÏÊ3y½®ìœÇ1^Fp´ë¾ @Ç™]œ½MáªÂ‹xšè÷óÃóKL:7!6R.ÖKÀ|å•<p8ÚtxçȲÇßhS!OÕdº»Ó€º5LÀÆûHs,b@%xŠ÷a"R4ÿzAÝ`œ‹°Ì<¿ïµ!Ú/&~×sù*nâ.8`'K6ý(Ÿ<ÇÛ× êšûÎg»òóÆ:`€rÆÏ:éøR±GøšnÚvá¥W¹Èa`+÷üQä@]- îcyü¾iÆnЯxXÛ{™fÆqñF´Fþ=.ë»Ï,?jöÝ/±Ïÿ”ào¹úçÇt`ûš%\/¥æ= £¿5+óÝ©ë׊‚ØÈZʹ]Û”.Ø|¦umäxÇûIôiâg½˜Qݼ¥ý|Ý°ëšÝÖ2¦=Îî)ÉVƒ^ë öHÜÜèÕþs vXôŠq‘•\0fr ØôŸ÷´«/€]}aÖ•[—‡ Žëz XçAêåØ:Œ:ãä¢'/ñmÕW¯>m®ãîÃå€öu#öƒbÀ6¬ÒÑe©Æ|ŽþfÏüõ–¿§ŸõbݼùâûbÚk6G8w6.ñ2‡z¨ÐPþW‰©‘/FSaЂ›v™Ûár­m€$ìy;ÄÀÀÓßRê;8‡€ßbô™é—k¼–V lö:¹Ø§L›å‚^TíH»o`Ý9ÿlÓö± /à\ÀûEwþ^ríx+¨ ®èñ53DªŽôœ~¢Ì‰))ÈÄѲ¿.ɺË¢ßÑc({¶¿eçz›©¾œ×Ïöþâ¿IËÓ…}{Ò€ÊËF¼b'<½-s·ÇeÑHcÊ:÷›¾åÿ_åÒÜn7õ×=„Üs¤ëcþÖ}¿¢_ÛIëúi\ŒSWA–{ íLpsoMÀÝmºWÆGæø6 ¹î§ÞZÇ Ž Ôê;hrÎ5^í˘{)PñtÕ5w)¶/ó\ŒªqSQãÏx™ç}Åb´=4kE'ý&çùtúüZ1ªöŸôÏ•o»oø5\ƒ^ f¸É·Ä}íí€?ï}ñÎ~‡Ìýðžâ³ª}ÎÒyûÞi¿'p˜\ÈDG ›ë¿eðÔ–\ûVÿNÉçËËŒÏó,ìôg#qÏŽíNxÈ)p¶õæÌUïoƒ}'¸Ðl78ãÇ8Àé‘÷y9ì›Íu_A¶ÓßRû}‘Hh¾¼:~áË­ÿ£J6ÌLàJJö|»¾ß¹ãWð:3ip—f Ýà¾nœÓ£z—Ùçº6)1%@²¯ovJs°¤LãÖlÅ7ÌùÃwÎCWïä¡ÀS?Ý€üÏ©kJ.z–Š8¾ÿëO¯ýé—Ï8Å–c$÷¾òÔ%w÷8„z`ÁGãØ`oÓB¥ÝØS.¶½K³éá+ÀüS™Äp ¤«/¬º^ÛRD×YŸlÞ O%xÞâüθ64XÎ2ìÆ,ënxrÕæ’ŠšYWüÅ9›~ †µBï}lÂæ@ž|ÓbÕµDöž±ÚßÇh“·î×I­eú\´{¼ÇzœÝåɽ­²R2À{¦ñL˜iÝõ¢‘Ò#‡w; .9ì#ƒ7ÓKû˜ÑáÞ€r%î{ÀíÆö!û^À{ÙÿUÌ8ÞO€æ^—‘®W S2ñL<ôµÚ2gÏ{œc_@ßï§¿I+à;ávÒ)¤úx™ú¤^Üž *ÀÞ©'8/ùº×Ín§-¹ç:Þ˜8Æä‚ßõLÈѧp{”;‘«“jCÙH1ãêKÛT¦P$ÍvðNäîj#·< ¸–ßfÂÝŸ´¤ò‰IÜ‘C¾%´cHj•XËÚs_Ò6Fq‘´¯ \–Š®p‚ >÷LßWaÍ× Nã¸{}™rÖ1ŒÍsAK×µM]óvb¨§MÏ$Rñ9`´ÏÇ©p´¦¿G%¦!­.¯¤˜mxEè¾æâéoâf ~Ëê1…†jY>ïs­§™6išM¸¯Ò_Õp€M®õbšQ"“ s}ÏJIíš?é\;Ú¶ìöÃ2حи±Lá¯z_§9!çö´:'Æ®íyœm¯ßoÓ4¤ÆÈ¥é÷ˆx&Zcõa4Ç QÛ x×èàf…wF%ë€/fE†©>s6ÖM¼Íïhës\™w]/@(Îïë#M9J¶ñ§÷4Ÿã¸Ê²ŸkpÊ&4ð¯ë<Ì3¥é¾»®¯£•wù¼–¦çš¥of«Îší‹´?Âqþ?åP“´jƒ}Ÿý#ï›ä'¿ÿoc6Û7Û0鸺ʵ PÀ[Ïɲ¸•Â#i§nºgó À#Ï+ð½Ò¾–ø‰ÍÈC‹–¾Õ'PĽ%‡nO½ÚÿópÖNïeöÀ<.ïò5ç_1:ûÔ¹Ž8×:9è/±FŠl÷ï‚ð Ày$ðHÞÿºOŠ.ËÓ~1j|â „³ÜœÙ°„Ú7¦V @ÄLž/,;`K‘ßÁLŽçDÀàÃ(ÈÖKV^•®_G)Ûƒy^¥„Ö! ¿ƒ‹z”\{ÈÄŽy×9¾í ®ú‚“ ðP‚éÝå:yçËß5û*G}JÜ ËœìvÈÜúUìœÙÜôïÇ>+ãæ‡v[½6ò&®/°{KáýGT0¤*L)¶5m˜Ù´•²w>= þþ8–syê½jûPô÷•±kǬ5Ω?«>žµm ny[¤kã7ä—]¯©iWŒ#¼'Šm‡q/&!0Å2L u€ºÖÙ¦oBa<Œh×z1)åÞö¹$W¹ä©üF3ìŸ|Ê­±nÐN®ºŽ¯uÃݶ€jj«»ÍLVKQÝ¿Á»ÞÓĽ?sżˆ7àöúY›òëϾÀ Íû|ô“'k†} ²œ#|–cS´µü‚rØùƒ™¿$÷Ôk‡e…™D»æû°Ê­X&Þ íÚ§·™HÐ2 ]ë䬈s4-sœ¼>€z öüþ8ßçßÔdB\øü€fXkŒÝúšª?û3 ÓŸ)é1¬œñÞ0ä,ßø˜:–û8§LNÍÄÒ$:­#©êW|3n€¼RI`Ëa¤5™Ð}¤±ì¶ÇhŸ²hŠCªN`\ zú†ýÖÒnë¤Æù̸ãùÏe”¨²™•‚Ôyä]»Ü¡Ù&¢ª‚ €È·_ÇÂ}#¾-¹Ÿ‘êe);c‘¦ÏýsÍYËìõrd§:ËçOÙŽé[= TJ\ÒäPéi=¾7Ú¦­€ìCÇö&2.Fw¥íwóì[^ k+ìÐ6Ç8”›k½äšú—HÄñ½1Ì’j‹‘èïsÀzNf\&nœÓ»r ¥)<$Tçþß~NÃ.ß×û!‹|©i7í S8çϵ‘ÚãÀlkrÎõaŸQ'/Á|›QÓÎïãL›xÅŽdê´—<½ëÖ­Ô‹úªŸW 7,0ÀµóxKRp”ìŠùÜ䳌ìcÛôt˜Úaºç˲¬êÌ×è ç@ÀflÅJPKäÔ°§Æ{õýÅ¥$’Œ{Ÿsû–¬7Ë͵ßR÷,&Ûý冽wû|†õçwÕègÖ‹Ïä(‰×^1F´Lg¾§ê©Ï‘óeÖüçëú¤T‰¹b÷"0ïÈfÝY¯Ø™x;½W^œÖèk¹{°9aÉ=±05Ô›ÑP”ì=NðjÈVn}ÆøV¼þŸÆÎpWn,¹Á~™ f0;FvóVÙý1AfqØûv½ÞWŠy âÁ[Q~$s¤V«»Õâ!‹õ]ºs ›YênVWxË*œGm6.Â>òN€v3GøßCûä¡&}z“ïùóþ^ÀüO€öZvY·°¯ÜÝFoÖ\ç¬ñó oæ ªËÌʳØÕ’<ð}¼äŠ_·æ]é3(¬œvœ¶û¸èA/·¼–ÙM@"å´p?9ÔZ§ùþéa­}]°ïús´¬]çUÆtY'> 6À:òqò¾µîsä3É÷ƒkŒÄ|Êñ´Qèxé}}ÞOì÷|/òš’»›åpýG¼ ª÷;EHJÍw÷_u>­2 ŸÜòÖ¾×Ü’õ Øt"¦‘aÈ+UF¡jcòÆ=&c¹·ø¾´“ŸÊÔ­¤ë€tûxd6|zu§EÚîeÉÔµtž¹~÷%¥)¯ú(W»p;°kL×8wÿšÅùÿñ­œòZÿÉÿk™´€w|){ƒrÿ7 Äk}&ÎÕ®ÿd•DS:Zþ¿£¢38ÿP>ÿýVÚyP>uÌYo`ræË¶²´€–‡#ø{ü%‡ÖM|»b”—­€pÝÔÝ®ÄÊ®yïŠL*JÂ^Š\ÆÂjó>ÏëµÆÓw…#®Näç¾·iÛ\ç‘íCÊ•©µ±Ì(¶Ÿ½»|­Qi¿,Y%óY<ºŸ­ÛæÚƒ-¢Þ}f×G=ñ&O}ïH쀽XHK¶ûÜ 5mí8è¶CÖŽôâʾ‹õ#°™ÝŸŸ¼)²4úp Ÿ—3›¤œ übĹNSžà‹Ì–÷úbìÌYŸ¯ÙÀÔÀ³…½y÷uXv> w%óÎmé›)×ðºùÝõa²ÏôÆôw9¾íwøœçXë^ß7óqHýÉm0ìô ì0þƒdéÈácw7rÓ7Ó{^Æq^–T/ãÔóœ‘ÿi\Øö< àˆ[¦=YÜ;G=ëßz¸ (÷CœsÊÕ_²øeÛ‘Q ˆÚ7xxÌ>+sWûa(·å‡ô°ky駘ÄUž(aÆ=åYˆ5À޶$°W=ä ä° ÜD«rQFí§s 8Ê~ ¢}s¬Ø€¼ePanËm©ô:Ï(l2žãšUn©µ£œÁµM•û7³ÊZç8f_k¬¶-Ù„J&;R}·Àõ::'O:À$à°~ézïY2Y¡¨Ry –üý\»#ÇñçÇë,9ÊŠö!ðñÖì°õ¶éÚlýŒ.Ih `:û×oQUæ÷¦m·bRPÞ¿î‡úŲóaÅS‡\@\“„]9v]ëQöLÅŠR Áš{üV¯x+}¨Yp­ãûANyõ$—tÝÀ™mÌà:¼/©S¹üO<Õ7gb™fœÐË—VŒE–N•”Ê/oãV·¹LÚÉ’SF•\ò0æã%rv=D™°«g³å–µ30´@­óºÿÿF_/¨]ºjžýX ­Kw?¯Þ,íHç[Õ¸j\üä­_e/·× eËþüçFÙ”SÅ:Ïï³ìÆ÷=ÇTš:ú昅ó=뇹øÆÊÚ—p;Ë7³M¬ bqj‘„c†] Œ]Ó}R©ß1Cqšm-øÞ~b“å×Ù°%âÀ €¯|Zý˨"í¨úìŠ.ÏÕ9îHX<®íñ«¦7Ç´KLžåè²O½öNFÌë5 ·;9ÿ^o#®ÙJ1¦Þâm(Q(]JïNS¶:_¾#núç»qJ뉩×?e×ð£çG±±Ay4—L)r|Îccº!gŸÎ û0R3bAz±éšm§MKf×½YÜ¿| ßÜt¯Ç1¶zXçÏ}–ÒkÅ:¤M±rAÊ´ÅLG¬»óü0ì!¼ ~p~wÄXî;{ÿ¹âtî<ôC£ñÅšÛÄf]mYÀϬƹͬZ‡aoWãz(ŽäUcÆMyßãÂlpov¯Âaéˆa+ö|óÕÍØû[cÒH`½Ê° ø¹ÛaÑ}8²# ÛYl} ¸Gçxäþ¦ÿúe%ïÉ˪¯‘XƒÀH£Ol]m-s®ôqNÄmz–ra¥µ€cÆ8R»;òpú½ I¬sìLˆp¾ÉSoµÁîÇvËçu|އR¡^ƒýçœS".Ÿ Íjk9ÀYýU¶ ýRƒø¸ÏÀ\ßé.mFÚæl=9öûûúhнÒuƬû:c÷^ûXï¯Ï“ˆS̹ï¤)*§\}sR†¶lZO výrrÎqe7óíu….‡—‚kdì™ néz«¿`Ëéc¢ðN0™­ãk\@º:ùèÈÙQ®‘†VåÕÌ¢ÿòÙ õ\–“êÀí¥øä—¿åGåU‰Èlðár~ÇKë<þmd=ϛ㠱0ì.*P˜íñ]zÌk/Åè–ómÂè6€>€Þ‚X·¯Ò™TÐþ,?ApÍd~Wó ^ç­ˆ¬~ë¶oÜ×sÁ3KüªŽtá~/8ô»íLÅå½Ëxïœ #nÜÀ_ÁÇRµB}“Ú;Ÿd™J¢/î2¿y£U;ð.ëuÏÈ`p¸36Àœºk#â´È@§eŒÎ<¾Í6oœv¤2Œ‰Œü®Ï“˜ÐM6×`%ûÇñëÇqî;†sk#8âaråx\£½O&|÷øûOãÙµ½¸×ŒZÇNjÍö|G÷sªÜ/ÿÒ¦1ÉMw? }åm8ºþó_~sû‹J·üþü‘Ö §„‹Æœ«_ñfI6K ¿Øaºœ Fr’­ó cy ýíŽ+†Ž¡Oµ¹ö¹€øß#ƒ§_g<Ø.¿ ×Îrm-{o'xuåLÆ€.%ÚÔ0_ hÉàõ ˜÷ÒÁøk€ùc`É"{í‡÷)ßÄzäïZ—Ñ€žüõÈä1šòoa ×,ëf4+u½ë³o®;m¶º¶ 4sõ^À-±û(¿jÏ;8o~ò¹ßÍ à™¼ Í#_uǹÞÄg&yÈ'ÊA]ÒÃýÈÏêó¬ï„*Øjª(àÁúUölÜÚY'(Ó¸þÙ <á>…ëç~‘}m\Iõ ‚è>O0hòÏ÷¨¸³sÞÀ{Ãǵœý;¨ûåó܇› ·WˆåëÜÇäž7 hNy&oÛømƒé/üGy¶‰î7ó®q€m›½é5ô?)v[ãñgé *áú_U»þèKn9yå–´+ÎÒ«?Á‚g ÷1òŒÑñazNý§ÿ …$rc-ži ¡`iϪN)Ç«å­~­}‚·™pG³à;³±Ôäiª+ +:@ý”s@O†xú§üì[åþaL«–Oìõ»òÎï /ø6†jÙú>ÃcÌPŒqIó»S¦×TƒgúZáp;çsî¼§=‡3÷â/='ðm˜_¨¾´ô?³éÛ¶îðˆg–i™øû¸ËbÞÎÚiãC¸^£…•˜¯«úþP¤cÆ6àxÒÝßnK+ÎÙ>J©m ù¬¾®’+Ǩq ¨wv‹ë¹æ~·[äÞèŸúšÃîsÍÙwäö[A ©\§§Ò|-wÇk¡reÎ}é»ÍãpwW)6Kᨠ·û{™ÈP‚¥ÜÜÿæ¶W†úéHòÂü úí¿p÷CI3í^oÝåØpÊM~ºsÝy˜Ê>ä£o-u÷ü;÷œš°èäø'€ÔaD§|{;q»¦°o0È/À{ʱicœ¢À0Lòä¦/€ÇÄŒã°_KÃ-£nкL»b˜æijßÃØÔ'‡{ñ9Œ9Û›ªL÷9íRöºÍŒÇFû龎’¨ïu8±3¦ë˜{Iä^íø˜1Hß­€òýþÊs"Yßu—æô„ïY*m¥F§•_+þ_¤z”g²ZËM'ƒ5_©{RÓeô6åVI‘›¥â0ƒÈ?Åw)²–ß%ÆðŸâunÆú¨©ÝçÌqO¶{Ÿ)©×Þ¯³R~€4ϲwE©(†äý·Ìù"MÃ%§÷úý ÌïôUÚíÞš²c7ÖÚgí­FùTÃb]Deòè™ â±ïÇh¬qiÌÆYù|Ö×4q?/È>Øù‹,|éå;hþré[Ð Ó ˆÙY µ¯ƒàþpS¬˜fµíØšy!hcßf)ÕÏèvÜ/w¯ï~†Ô}œqø¾g¹x?Ïnï|Ðä‚4 Î@Lù˜mZGÄû3↵Κ/Ä’¤ë>Š{«êÅW´a Γ2¬ç÷G™;f 3nˆìDRýˆ5™Wö9J°ñåužþˆ4É»Y€ÝcÔFMS€yòÒ=ãÎ<Ëu}j¥;ÞÞxXG¯z¯+-t¬c®Y@ú<ÐÚÀ¤K"Ÿq3Œúô# º‘qÔÙÖºÚº–o ŽxÕCm€wËF—Árn¼Î_J–¢–ó;¦r•§Ó]}ý ¿íÞ×rù|W¨­»nB[Éuûx€§eÃYÿ[ƒ©Œ 8Ïz³¢äÊ%®²~F¿þ2»¡ Ú¤Éo_0 `¥îöæÆ«ïçÿø<à=¬ü|Î%Rðé6nc¿É9?ÆtÀ|;zbÞßÁÞç¾Þ¬óùò¹;ÕAíÉÕ¯šãÇŒ's¦V¹×a¹àn›õ˜%"WoÀ­cØFêN‰C<4Æ9åa¹ЮßäÈG9#ƒI1ùº/h2¯ÌÜ^·?9E§Ój6Ì®GÝ£  åñéȲê—ï„eÒŠ¾`¿Þ“¿hÝì8÷ᙵÛúW³±æmS*M*ªªü‘1žÔ} toøÿ¢&Žöds¹rÉ1OÕÒ\ÛaÑßÎGÒNúl¹&Æ+½l™ñ¿ÚìTu”¯;>6Yop ˆhYuàžHë ¾·Ó’kÿg.ðøcÏä-»_¬pƒ~˜ëf>Ç'ÉcHM÷ÉåßÏÐüì9õ­Yvð*ìÿóÄ©ÏûìÞE‘½®ùgÙîU/¦ywÈn£³_&xåß-Ch©®ŽÓ?fÌàŽÙ ‹y_iû2á¹uà.yù׎g ô³F½ŸeÇý…æzzüœ—Ï'õÕÖ²·-°‡ù]ùy#7¿ç9pÁ¿L ˆ•rT wÑí]fbÙ}Žø\Ê߃ˈ~þ°Ú8q=ÆÕtg‘™ìP¬2 ŒS®òHÝ=SÛžrl—Ë»ûÉO×:ùo˜ÅiÛR÷ê³2F}J³Ñ&]Œ샎¡>çá‘‹îqÌ­‡+˜Ç–Ë ‹þ*«·¾òy8ô’èRnäCN”Âͬ“—Ié •€²ü†S2 ½rÔ³u‚Œ£”[€}ʨY®.yjIÜÓ¨_†2oË´#áEöp&]A=g™^ý®ãª=À¦Á?ÀIcÔ 3`»>Òdb˜óq—÷˜bð¥LÐñ²®åëB¼.5¯›×lpß »™^ÚÉ W»Áwƨ Ó4Àõž;¬ú²öLœèØ>g€®ÜË5 ¬%&ô «,i •ÎxØp-5Åñy{L÷1A´2óçXÏvUJ@U²ý~Ýr_¯ê «r9óÊ[}ƒÇ÷€ú2èê/ÅÎ?rïRÊNU®H{)‡È+ß1LRÆÔ´£ ÕØÜwÍ‚k?ääñQ»@u©¦Ê©ÝíÍœ¯„½œÚ?þòûz¬`‚Z%ÒŠ9ç’à¿Rýõã–­£jÓ˜ªiþ£Ì_çJuó?2uÖ1„Kc—Ü0ÆsQ§]ò\ÚàvÙë[2VX’Jç ÒÆmX¹½‚ç2dÈàuëšÉQž+¯³Ë3yá$H @÷]x<³ÌîÊF[«%þ´+nÕÁ³tžs\óH”õ¹î°Û³T} çwº= £=}g ôŒ.•÷`½ °4¿ ÖàäïÛïØ¡ÀS±€²#'ø1sá—Á¼r-æMÀŸoøébQÏ/î-ß÷Ë»µ9V¯¬ß2ιœÖuÎw´¯¬b¥÷ô±NðÞË=rÁøXf—çy -1h[Ьö盹›SÏ8ÅS½ùYÉÜ´O>õÞlóÏÄVyŸ/ëWåͦ÷ºƒ?eÂà°Þ@vsŽ.îä«70—Æ1†aŒs¦~:Œ;ù}Ú/µÓÇU·˜íK{IÛµtÄÈí#W(Ï]ÇÅ<Ž<ÇÈá/†'‘I7²Ïf’‹ô½ë6GÂÞ%ÞüZýÚyì¸[g›u‡q6â²± 9ç+<,û·'ðŽ,úcFrM?zµÏ¸~Múz ¹òØï~΃÷Úï+}[6ŒkQ¯6š1s}b‚Vǯu²Ë–ýú{©ú¼êó™k²åɘˆiuלv™Ûa—I­“òïPç|¿Å’ÇmÝÀõK,Ègâê2w¼A9¿Õ¸¹k[`»&Òö~@$W\àÙ}£ÊaÙ%Ò”ÊÀ­íܵ$²—ᛘò¬müö¾ªjÄ`~DXlîå]MË>'#eW{XìÎ5GºŽ*Ìê¬òYQ4“þ]ÍöÅ%ÑtìéÜ1f­‰t‼ÒÕÊ@VÏ1µª*0j‹gMÚ—a^c®(\Q~ìõÙ4[÷Î_ÎØ9怴;öÚ¾ Ëî …¼ú–áCµ*% vâ—óx®ª´ò¤.av}nwå'ðÁ”Gãs<lÀp¥LkÙjÚÌŸÏåíüíçkZà—Ysã –ãñÛøó_„ºV£L?kðໜ ^çž×½}s,‡E·¸*ïd~H+¯€µ‡ÅÔ²ÆNàŽ8€p@øSn@Ïz ›]ï­kô& ˆ³}ù€âÛM}gÔ`rÏòŠ|?Ö™½¿´íœL œ“—ZáåúS¹ë¬·Ëú“±ÛmJQ6‡1Þ¸ÂgÇ{¾AU~Ò¾díÈÚ–¹Ã´oTï;@6òω5±ÑúæÑQ/}¦||K ý ¥±WÞ ú3 ~”Öñ?üiL¸Êñ7ÎÀ,”SÊÍùéH2¿-Û„üÓAþ:lzj²Ûé½÷ëoí?j°Wß'òO66ýº¯¹aV~†TØò.ÑöÆÐça¦QmÙ·XtÖK¯}u,@ÓÔ–ör è²lÆ€¦Vש€{•™k°XRìWc=€t˵˜¯lwŸ3LrgõÁòšãì1P ¨ ×skŽÃñ8ßΟ‰À9ÛË´7¨÷r_3û ¸ç3¨üqJÍxÜ%‘ž0_@ Ï$S¾eâ†S:mý;ÒýÆG©’夢ø}yéœr€w©l¨{ñ}X37î7õ€ô˜aÊØ{Ûv÷m¨ŠF@÷Q{pŒ:Œu¿ÖR÷à-½©õö#±á[Ê™­Žã:ì9²õšîüò6;e9¥Ô0âZºfyñìÃ’J*/%Y×ýÌzÆTÍrƒôš˜7h§  sÈž×üŠho$Ï}Oàx#ÎÙSz­I¹I¡di0x>^ëô;~p’òW»3Ï“sò+…² À•F/;½Îíäe+ âìçSOfzƒZúRoÛÊ;àbñ9Þ­P¾ý¦Ø¾1 }¤û‚oÀG÷„ÇÆ¦"œçp§KTmü3e‚Ïw«ze¿wn„á“øâ`WÿXà¬÷²ößòXW Ã+¯ÃK¤ä‘í#•yyfö·¦52ô™%Z À>3ÿ¿î)À‡Ù³]f|ËüãTÙiûãáÇ?y45 Â9ô¾ZGFÏøëËÿòPÇž™¯[ÚÎM‹ÓÎÐ]Çè~&NÉ 2”‘´k9’0ÖŸse¿®MÙy0×w´rʯçûúý‡Vå©ëOP¾ˆïm m\Ç5²wE${‰Ôí0m ÃCý„÷sÎà<`Á–À”d“Èû–ÍÔð¸ÒwÚüÀéqÈ5Ä“·9Nðj(§Ý¹ŠÊoÏÃpê£[‚Úøl§ÍRø*‡D¿Ï©Ø³7dï@µ™.:§î䧯AöJƒ‡yœ½Á:ÌbÚô^ \q ½¾Ûüž'_8 ¿ãÁ®/¨_ðŒ|ºÛ,‹É†uÖz³ÇÜÉ}3Óò{{öé>òÂ9Æ|¤æg=ð’¥ëÚFþ^ìúy–뎮cebGíSuà~¯bÿi'¢5n¾eÜæïX¾·äùniß§-oÈdÑC0ŽßÐ-qÿT,yU~Ðú¾ßëmîV`}¹ä죞 BîO1´<Pn•‘ð“5§ý?ئÖyÒÞ“CŽÔÝm€ôü/àOâ dƒÙ–³³®q©NòVù3·S†-õËÛ•Ý“Õq"eÑÔ? 3-£bƒ!?ÿ‹Ãž£l{0Å–—’޶5jØ¢è2ë2W«"]çuÒ[—4Zö³LË ?†eì’Æ­œ¼ š5B~Ž^·ÓiÇø.åÚöu‘ï3þ‚9–âñ¹@¸rÞ0ü«Xb“öaÐç:d{µ,1mëkp…Æ.q¼çµàú®ZÅ5rßNŒ`üÖ$êËJáwûöÕêßÉú&ü/}`¿TZN|IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/installer/macos/macapp-nightly.icns000066400000000000000000010053161463772530400265740ustar00rootroot00000000000000icns Îic10 Æ jP ‡ ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cÿOÿQ2ÿd#Creator: JasPer Version 1.900.1ÿR ÿ\@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ  …ÿ“߇s`9o´‚(Q¥œóÀ±ÆÜÔdcÕ%¶!šyÅèm-‡XrÊßV­ íp\ëp‡ê^ôm•„¼dõEH;eÕµ¾ «|†}Ùþ;ùc«Q–þ#j°y\¬7 µé=Iývý½˜|Ð7·¶ÕŒ×WÊòÃ@¤ 7¸Èm‘æÊM&Él‘©õQÝm§î” €ª¯:%qư)Œ,ƒØž/]уêXÓciþ²Ë*wö:h´ÎÔ5rļü¼x]“v[Eç®Q;Üì‚MŠÍTƒ¹¬‡ÀQî1-ŠÓµÄî:þ™×ÛºQ –%*ª¨;ÙÅTRíÞB=áºîOÛA FÇ#­ý$|a,]ÚSÈþá඘Iö‚l¯{Îë’;‚$@–$Æ3€ðžb{ŒIF2·²—˜Õf\mvD7÷ÂÎKdªƒÞë‰ùšÏ$&Nò[K:ä\ðèpBÿÄû¬°úd¾áp"êßÑS[›?2:â°b– ¦2~6‘©½ÆH_éK„úS0Ì5Ÿ¾§ÿrÞs®®Pu}úù`Ʋevaˆ`p‰nΪ|–5ýåºõka §Lø»–÷6¹ÐLÐWC줂A%>÷Ël‰Lë ]MQ©èºw?··ÛØÉB?FØÐ·ÆÐ_«»_>ü#ÕE»èðêˆW0 Vã“]2'·6Ò[:”'XÁM|¹îàŸ`i?u`}:Rdˆõ^í 0 Ÿ "<ÑDÊŽÓìÀž­ýæŒÃm‰¸\¬¯MÓs¶»U0å2Õk5AtIþäƒA=t}æÀ›Ž17Ö°q‹k3jª¶¢Ÿkñ÷©ü/Äæ{OfÆnŸ9*°(ßY‡àžæYR}€y×T¥þ8l´€–}®¯¡áÓ’ølþÍÒ½,°Þµ¡|Í@5ºð ‹Êð1¯PüXV -LêÛ3ó B&ocŸZ…ËOF¿N³µNÁ!ít jaq_´¯•ñhaG© þT8cLUhYuB–ó›wMD"ûa«ÝÀl²ár® ô­Ê¬Lö!¥˜lµ”Î%CG•ÄúÚ4ɧìü5ÕV{2SÚ?v(»Ë¡šIeòI4äoaÒ6ÄŠ=ÙÀqå- ¾dJuˆf_ÓŽNĘ>=h/XœL¢‚P.Î"iÉ?ØüžÆaR_O н6÷$߇sÀ9o´‚(Q¥œóÀ±ÆÜÔdcÕ%¶6úëD€»ÒÑ7“UÜ] îÝšDu–˜Ë¥·Ûž›$½íß=ïa»3ËzfV‹@¾w+Â4a$R‰å‹FkCÂÃñC ‘ôŒQA”OQF!YʹrXå"w§ðCI6³4¨@¸ðr~ôüx;s}é‘> <"—º—»7ü] öÒMÑ[ÅYnˆ%éôKÃ,ªyŒ‹ø²¨˜±‹E¨ŠG5:‰$;ņc&§ ËÝˉélwšlÌí¤ äN­ÑLC` ÛtïÓ¬€Á’Ä¥UU{8ªŠBÝ¢ÈG¼7]°yà„_/ÌÌ£º[#÷Sú–Ûö&¶cÑ¡Âp+ÏWÿ‡™ ËjNÕlׄqÇŒ [ôˆó ¡qñîì´5ç%ƒÿJ’2 œ:K¢¼·˜=–§­™áÐà…þî²Ãé÷¥×Í{õƶ*ðË Ð€Ì wsQËg°X7p³¯êUʤæT öðdð訡¾Åþô4Såÿ;Ñ]J»ç´*±ÅT– Ûf>FÌþÅêç¾áN™ñw-îms¦?Q]?²’ çŠQ ÃÂGMž²úaáæÓ(ƒÁÑÆFîy‘û%—cñ2@œçœÃàW×m6IIîËñÓN&/ÎȆ}ÃHw;ø8P0öVÖB\Ra¨ÐûŽ(V"Á±Øî˜­ûÕ{´|0À,B~€ˆðGE*;Lc³z·÷š3 ¶&ár²½7MÌ BÚídëâJ">8Ë]¡V‚ &ø ,îªV~Èu „%õ- à*Gü럇ëĦC·»ÉËΙJœsI` ç;¯`(gpM7ØÉíÀá"¯“fÁ#ãó=Ô¥þ8l´€–}®¯¡áÓ’ølþÍÒ½,‰Š¡xñ|Í@5ºð ‹Ë Í*ŠL;ˆÿ@Ĺ;„˜£¾„¡IpœdR*ÓÔ侉 }½fb ü,שҾ¶¢ªh &¼Fˆ–ÛºšÍDjj6zŽíl³ÀG¯1‡Py“Uˆ™>r)Ù«ÝÀl²ár® ô­Ê¬Lö!¥˜lµ”Î%C$[b}mdÃÓà†¢ßªÂxµ[µÙWb·«ß.ÉzŒiÂ?;[ëê×$sõø&,Ò–[µ$P®,¹J3¯¹8rƒTøõA+ ÓxFxÔ—ñŇj£ÇÌ,Ûü£Cvúê_߇o 9o´‚(Q¥œóÀ±ÆÜÔdcÕ%¶R ‰n´A%KŽ•yMв‚葲L²Ô"ÝF埫8sþ*â -˜åÃo wÿd«†QYu·~á¿{ (èŸL")f$F‡?p}ÐÃqúÑÏËïšá’U"bƒ|ÎŽ¤Ac`£ŸgW30)ÏwŒ:nfÇ BtÙhW+M¢d_l`G=¸VOpk€_+†n®âºö°s"Yh ÙªdÇP¦(€ €Ï³ð.õΘhÜÅW=âDèFObM|sñ¹RëÇ/Â%áºíAôé5ϯêðà?làkÈò C'³„þLŒT÷ùˆèñ I/ß±¬˜1—}`ÚDÜ‘M¨,øRõÀÇn£ÙÐê‡þP•ŸOH#qòƒ-Oo‘sáÁ ü6'Ýe‡Ó =ëÉTÐòýÁ-¿ùÏ–ÓBO)ÃT+›äëÑ©ìžÓdÄz…u"p)çýѤËkO·ívçè"ÀÑñ@õïæ…²>=À—ã¥p¸J_8†„F©ZÅñZ"öþka §Lø»–÷6¹ÐLÐWC줂A%>÷Ël‰M¼7 ›Í°nê‘I»o>Ç‚ÇÁ]Ö3$îלßð‹5œ+2^¯;ŒÎ C^‡‡jI bÍWQ»£á0=þê ôßϦúÃŽ¬Füå11ê½Ú>8¬VE?@õ‚‘)eGiŒv`OVþóFa¶ÄÜ.VW¥!ìÂ-®ÖoØKö|É5š„üÙIÂ$eÃdÜyþ4iù¨°#u/#h2Ó0 6G…KQ#·è¨ëd’”¯V2óAµ9×4’þDtL­u"ÉÞ1g%sã&ÑGî¥/ñÃe¤<³íuxu˜¬—Ãgön•è@ùdLU Ç‹æjHkª@<¯ƒìHÒs._à_Ûåü¥¬º5oƒ«y•Y½Ó ÖR†>\W™ûq¥²fÒ& à8uñøä¤µÃ#8£uïô|Yã³Nˆ¨ñl)õ¹‰æ /5Wº5€þÙeÂå]Aé[•X™ìCK0Ùk(!œJ†H¶ ÄúÚ4ɧìü5ÕU¦‘k,Qw–øalÂáCSQŸ?çÌ7O&}g|‹(&ÍÄ$œK>KZ©ÞÌhcc‹Ø°Ë[AµÄF)§q4]Ê„òl¤šwÖ#+nŸß‡@@O §¤„Sd|¬€ÑSx>JBoËI:Xßuÿ#KÛG0çf*òáô–’kg¹ƒÏpµaØû1ƒòõ§»ïtìrY'+=ÑÑ£*½7÷1$@Vx))Œù½¯¬¿Ûìã?#W8¶»uGs¾Ç×`¼ßšßgmå.¦e˄귱ÍíŽÈt3]8…P´ €H bº_#É‚ñ޾¦Úü= l¢ LÖyœú0ÐÍú0{×£Šêþ¢¨`EÈÜaA[ÈL "¢P( Ò¸PDì¯bè€;è“"%dvóý©ç´bj¯ky2 „+¯¥_žÊËK׬,ì A \Ä ¹|!7Æø8çúy¿Ð¸é¸´eö€,"}ƾkwke/™Ê (C°OUo~R«ðbÑ…BvÇÃèìdl‰ hV?Ù^¨A‡¸ð?¨kç X…qÒÍqMï{”_®ŶÂnv€[&†e=ëÆî:FZPY¾ ×kBÎÑ&b¯NîBÁô¬¥€(ÎxK°~ _CW§i°·ÌÜP#lBÈ…¤}íÄ%¡2•þ<9PKÚø‘›ÏçÛóëŠ~}>€Îx*ä?” ¢K¬¡xHIïòJ¢›Ëq*¶ÀZö7 'tÎ ¤ðö³Ñ¿Ç¤~LtöQqÈ©Lqˆ-‰7GÞ{ã›CQÛ:EªïS=ßó?Ã{l R˜Æ';ˆ$…Ž´œYIŠìáä³—71#ÿT(ñì±€Mvgù®ˆÕ›i ûC÷…MÙÍÛŠø ¼Pö£ânåÑeÕVLSQ•ÙŒçØ½Özˆ[eÙ¯>Æ‚™¦šÖ@§òÑÌ aQJ8% ýýñàëLÐîÔ›ÉìïÓôËCvÉk7›HÚBîa{*mJ‘YØ@Jt)+~˨ÀIœkT2€ ìŽ"9Bð§|„’›E¿r=óûú²˜‡ ­À./Ïm…ÒÜ€ù€I¥J3)cM|ˆûäx¥àjú"&Åš‚«dÿ}cš\ê_“™ÍrÒ-dØä@՛ɦ¶Í/E †xŽ s—éæÉŒ«öC“¬ I3—À»°7Ë“àšÝˆÔR0RqbàEÛÍ04Kòº;O,½‚«Â-ÜütG¦•¿® ì׬EZ/>£.Þ ØÅü%Â09u^$êϧΊ$€†ê†l.ÞkƒýpÖ\‹ âÿ-·^¨y˜ÞÐm¡˜¸'L#ŵ‚©V½4³ªåÂj.þn()åúEyÊ "/ ì{þ£ÐZG[Îe ¯_ë| ›P¾ö±BŠËs¤L”’;x "‰üQMYâóiÖ)&ÔgÉì˜')òÇt94q pX|ƒÓU*ž¬úJøF„£œ(jepPÂÕMl‡ÒBäu3J—¼Gܶøþ†ø¹Ó$7„®ë¬mEtSã'àé$aÅçGyO© Ÿ{ó"Áö,#”yÜ {ÝÄÄn:ÖÑçøMøXD…h¨"Ã@–ñÈŸcÁ ØŒ'©1¿é<—owJð†'¬ÎºÌ2ÚOÑDñìwïÇègì×ød?,î.÷Dϯäƒþ1>%á¾oÒBG¥OÂBB•£‡±õ"íYE€Vt.ýຮpÙ³‹P+¾˜Fžõx`}QYhÚEÄQunòin º ¹µc!I˜óg/ß{’9㣵’‰h“ë„GÓ2üô¢|*™¼¥“cK7µôË¢çt‹ÖôYY6»´û¹Ò ® Õ [ñx3U~ú­ïW³Åo†<ö8ÏÐ8Sw&ùÿFücŸ´BÐgñÏnDñ,A•Y–ÅvWbô‘ê¹òõKêåo«-NSnG?Ó|Þ4‹âÓbÊÓ:½á†<¬)ý%À›ÈTS&ŽÎ¯K¤*-}@ŠèÜŸo@wö°ãöÞ.Ÿq뾸4‚gcˆ-„?!‚H* Œ­™å4–ÞߦÄîÕõ'4NÉVçÖš¿#›2áß›4Ì“ïhP»Z§y”ú0ÄÉ1HdHÛ}½Êfi¤…B¨r£¼Ñ>ä´ëHÈ6?_¼_é4ࢄ°›@”]q½‘ñt‹uQònkìb»iÅ›bôϦ|³pÇØW÷Ë © i8·½j#ªhÀ;I*Ï9cHl7w†Tå:ë&©¥“Fý ļ+¯cÇíniÃwŒ@Ã-¸ ¿Ç–eDˆº´û÷#yâs¶yÂrI*õô@ò¡ :`÷]¢Ê eæ u Á…‰“s@'UMܱj3Z#Ûȼ%p¸m]d^ RÊÆŒùÆ ú¥‚Sè_Ê›!‰êo2@I) ‚Qý‚u"À%˜Ph}<¬7;oSïÑÍÚ…Y¹ÓÍIÝ¥ òÏT´8¿Åa­À¯'„s>Å×6¢}r´ô #g§* š‡j:´ä<°4Mφ  Ìȶ ‘ $fjknd[•DPI'“ žìÞ .?ìóƒb½<¤ 3v.¶Ÿ”¿+Û ž£ÝN”‹¾“(ÂóŠòl>‚“C~–Ç¿*FÛêë›gÑc_I»ÛæÁMœ›Ï`_ì–°ŽµûÐwhÒ†ÜÑ?­{; uÑ9ó‘쾂ñˆÀ¹9òv Î-öäzÇ›2÷ïSÌ£t‘1a!ì?"IS>¾Æ`]H1”'¨HñQÄI²ã÷²™áãjiö¯¤èåSѰlBÉÀ«%«ñdHVDЂî}r²=ð,I0¤« ì‚±þÕOÍ EðK¤Ë‘è˜þ lÿ#å{zÞz¼N\EçKÝ×C žJòÐE4R7Ê7xËÿDlïj '>-årB’Ñ÷ÔúƒÅ¥GŸ3ÿdêîs~.IlZQÒo¨lf¤‰<[èßâK%+á?žÈó%Y뎙hÄÔ'Ø&øðÜ¡Øæ»í ’€ @± ¸Uzµ „„7r÷þ¹ „Ù’\ÌQòMÎüqe ´aµõY*ﮃ7Žé‰X÷êé?Ç Š e×Õ—QÖó‰›ÛvÏ%ÜÆ.1ûØ|ECSš-*¤LÓ UŸ íš5ÚJ')¿Š£—±€“å258¶}z£ñù«(†~j êË!ð²ˆ|W…ˆ7 ïbs„~aFX=(Q^ÂÎä Wù,ðëWs˜¯Hl»Ñ/XqâÈÊ5ºÕ5Lu€ú;¸å)~÷zNø‹ÏçKóëŠ~}>€Îx*ä#ªZ¿HýäFËÉö£@¢Ó‹EV?»è s ÛoÜ*ùf¦¹EHY{Ü6ÔÃ$l—,•åV°dÌÀ[æÏ#,»ˆ8yŽ9)ä¢Þ]ÏX¼Ù¼è‹ÞŸ½.²ÌzLµàX1›‚êÎyƒXv܇m~cgšw[‹nGaT”™ÛŸc]{AÆÜ‚¼Ík/Bj÷yp`§Ð۱¥_3ižÈÄ'Ö'L—T)~,Z—”IÿÑ1º°XÄû°° Ƹ€ï˜i)_Asÿ'e²MÊÕ0Џ«õ³fnv¡Gk“9k¡Ö·«î[m©$tÍá%­q·µÏl-ÙO@e à ±âbIc¢qêrùƒ39bÆÓãÿióq/Õ9Û(z±µ¶tÞ‰”x·j^×±_UêŒ(Ùvx;k¦ŽY2é[¶€<Ö.1ÂŽ¡ï˜ao0°Ï&^ñÁ5ir/W•Ædâµ;1Ö–íV€þîº×\W!%С¯1Ÿ¹'z&ø˺³ù0úúQþf/ R'!hfÞð—ÀPåÕx ¿¹b Êk­óµ£;÷͵²‡ ä 0ÙÊarã ÿ=êS'mnඦIDÊâú¦÷í·â\¦¬ªUÉýÊ)–^R.¨ðµDƒäod{gt‘Ç̈D‡¯½Í‘|€8ÀmØ#1¶5+TšÖr²š®¶íxÙû®1!ô<Ø‘É'ÑþÒà]^ÛA@`5Öå ‹¸U5uÍGQºŽÌ'ކ„þ,Wåõnzµ µªw™O ˜êLÓƒ»âU‹. JÄ–¿„ 7oîRNP¸¢‚õ¹N²D±|™­¸NW^ÜW¼3ýÒû>øB»™WCû]á×ôˆ© ú3QÅ‚zsÒ{« è§ùÅüšá†½»àð$÷‚UžrÆšøvï ©ñ#àìTŒõk†ÖšnD¥ËûÒ*>üô¡êìè×[˜c±»;|W˜-\;Z7¼÷…Ni…ø†‘ÕyÌqi‘ÃŒúÕÄ,§!á ø 9Eð $úø»<@Ñ·ðn/ÜFRÀ²1Û¢”ÉL8ä®j´›Ïma Xp G-qDCžþn4ØØÌ==\èi|Õ²¦Ã|ÚˆicÜSàªT¥Ú@ŽuîÍùH3Á±o +ÇÅaœWCýQI4wUgÀ\Åu#SxH &^ŠJ—xŸ‚Y€ng^ƒÌœ„ú!±â½ÛQ<•ƒ'¨qi@ ;ë@¾_!Ç*Â0m¾ÊÑøš³ƒc¼¹‚͈H‰SÞp‹å8[;°¶*Ó]<Å+ÀïRnAãr Zù~aSò¨,€Vº¹èÉvQ{ñA>?íÌ’_¨7AŸ!`N‘Þ®¯âG±¼%ÝÊ{¡('À3Y$V:k!ÔÊ©0jw"ÎÕBM•²Öo?­ËÓM³ôfP$áÖþ ¨w.raðG&²sFw.°dÎáONÚz@‡yý¯RÓ=£:&þGM>Zgvš94aµÆFÅÜ[E,K?&°~ûk¿BtʳÙE|ÇM+á> ÿ`hîVm ±lû . Ñ)s ~ñ²‹Žp‰×Úw¾û‘1ÕKv;[áo8Û9Ê^>ôÕ E» AÿhWZøZkƃ†ÓG­A•{¹ÐeðI,~•iGÃÒW¦HµŒgʲ[¸°›;“ó¯f…ÝaU†‹Ñ?&Ÿ“³Ù£€ðï½&³“‡BÝ¢<`hºUï=ÑõÒ5ŽX!Õp+=r¤r¨ÁÜ‘\“MNKZjÁúR®3¢EI‚“JyIÆø oùñ–)õ4‹Wiø4°£Z3QCfß‚©>¤ÖrKʆ!¤ŽÇ*h vYÔýFHd©ã ¼ŸzµÃ TÔª20V÷?Z'±9Â?0¨ÏTbüd:ÈAÿx}ÞìVÎÆ&ÿ?¤|¿ìeKRrÌôÞ‘#Õ†ç8 s¥ß.Xz7¸ßwä@QÏäiøuo?>•Å‹ÒVqï×vmÝ9ÔÉÞÙùÀÅFõ+ûrÄ?)RéÞ~¬'x¹âuÿk› „,æ‘nçy44=7Ëo0sÜ7 l õu2Õ~)0¤¬Ç¹œÜæ—ùm DYœD'_Jo†U#щi‡á ¹ë†ÐÍ¡¨óËd2Ž©Mžâ·0`ÿ!³VÛl¦âÕ£FT ɱ…Á¬3KägÆÓŒ;ŸZ»žím!4–€íêA"ƒ·nòµ K“8źÏIŽôcj~cÅä=8æ€ (Æ2ow !²3|–N#à‚6 u)ñØli‘¦¬DÖµ@˜cð½pGÔë–z\Ý[‘ç°Z6@-¦¨)F£ZB¬›,Ê=‡~п¶3p¹kSwU†jšéHv©äÞ&ü¯¨ù˜)ùEÁFšîŒ|ÎZaå,h­}š}È"f$™ŸB6#ñßX ‹rfɰ ©7Sœ Xsü' ÇG•Ð#]z6¤6k(J‰/%¦wLËþ% ó£¿íË ¬øÎhƵSG_`‹$špQk” aI ùÍ„xVß ëˆ4ƒÎ·ß‚*k§~0µ–Sj¼jQ“×PgòÐG}„0WÙ±QçáYU=i÷oú]ËcŒ*«ázM0`-WRPÞ¢g–ˆU1A;(mS‰Sñ6HùGI&öÿ(Ièc@à°õÕÅÀG³¹_%äÇ!zkÀ\ Ëx3+ž×\E×P:mLy ”LjuÐn,gËjÇSÄ0•Êáv[Ëfr5^šå[þb6þ®ÖsJŠ,þU}ù³LÉ>ö… µªw™O¡$ñ(dˆÜZOUÉA/`´\É©³€1¬5_=à¹bYÿ3º ë’•#ÊRÏuêñÐ ×åÞF JOvG2‰}FQ~¦®RŠ×)]ü&êa}hÌ£† TÒ¥Äx{Á*Ï9cM|;w†Tø\N‹ÊWuöÅvµ0*ÄujÑ eòøˆÒî;^§¹kŸ!±{»)²¨ïª¯=G¿ ¤,ZÀÃ:Þq”‰r< ëé²ê×ß K^h¸B›Ç£nàÜ^'¸Œ¥dc·EÂ!¤Š®j´ˆ‡Dâ‘y´—4 ‡«ñȯÑú˜‚îgû‰ˆöZBaÛèÐ`ZÛ÷&méK ”c†_*ýœ?y©®…çP õÿÅaœWL0¤g`n®qo6¿n*·h %^Æȉ•% ž3¢ú6œlŽŠW¨ˆLL÷"dD„Uñþ.È ™fy:"•Ü^×Q¥Ý™8v–rs@iægÌ£bY·ÎÆÉä)ßezk£Õ¸ÖÛÝÌT¯ƒƒ0Þ…v%µ_$³ÐÛŒsÌ„¹µË³º’Tø‚ÁbÊ­ñD`ü"C·õ¥˜â_W#t_åÄŸ™ï`Ï—ˆ‰rYª”ÌŠwj ÏðÁäH0&ƒ{bj”êc7…¾CÖ˜Á;—Á‹9âÔ¿¸Š·ntÀØ–¼—ãÞ0ê&„V—Ü´ya†i(¨KÚ‰Oý·†ã¢ä¤CT‡mjÊ‚o[»R‰ºbÖw­QHgçŒJý‰¥ièÒÓçËãá ³Ö?n¹"w³¦;Ë›Qxèè"ÎófbUøidÚQóNÒÖ…µô©÷י飰Ȼ+åVâeŽK¹×h?eÆa‡Ú2áµBìÓwàqSF;„‰Š*v˜ a¦ã\¤&fH×Ec¤³ ß‹‚Äcýmmp96D믺˜¿Ãùõá\vÂëEô€øgÒR. EÛ Í³ÅËð—_oõ43]ü#¤%î꥗$±dÞyªÍf ¾$ëöõxçÒoà ˆÈçÅV^ ¤É«õÊïý«Œ@o6bÉÁ*sA¼žÖv »“}Gø«#ù‡î/5Í4)« _hbn×Ü) »œ~—S¦4³ò}Ç` r}ŸHs¤/—ÏÃB'ázÇár6ÍÍ>žµü›¾3KÒþE/ ‹ Qè ygi"ðªÈÊ9к `9›’3à¿É+§ÞâÂq†K]€mA÷!Ôßá8=­­.çñH®Õ V|®`ºœ¸™Ú¦–%ZÄ¿o>&cl]›wÈ\îçБ·±é‹XÕ3Ôý¥„ßËn™˜u¸õ„‰„g¹J½c€rj¬ãœ¼w¸~Ø5Lg´‡'4°§ÑU•ÿt*t¶h\!‹ö{½ ‘ÈÏ ¡ûefCÒcÖ20š•jR#—o\ýðÀ6{wvZÿuï½`œ½tîFÐ6À°… A¡žÏï€ïéä^pj%‰i޾;²±šV‚o©§ÙÚ£ˆÄ¡2ý×TâÈŒÌôQ¸]÷Ó”9ÐÃ#!ÞÎ÷£w#L:A¨N“A&ÚÀO¦L•äUëÒÈêükxi×W›v| |ªqey&;Jz&š?vz¦©•ü±Þá/Q8‰oŠ «êý;[DŠ¥‰¥%ÐþŽ=¾ÕÅËÆbÊÁøQw{ÿ(êtéLñ’O«!Ÿ CŽánÂÚÌÑaPÃÚäÉM{j:º1sÀ–£¢öô²„u[¥Æë^s>Cº¼¨Ò8ƒR­ÇLT¨þм’õG´jüˆÊ§Gé’óØr1öºhàœGFüÒé¼€V ÚT‰]ŠE-§͈ òŽq꾟H_KÖD<\CšKÀräj;CJõ ûÃpÕ_àBòübm!‰'§Yƒ õ¯v™Ÿ„faQRÒ&Ý7n14Øk ÅýAº‹røu4õ^/Àð÷ ‚Tíÿ†XKô‚˜<ìtåê¥eнqtOB('õ5^ûƒå_ºÇ¹ÀŒ<~¤E{8yhAõ)ìzü)+ßäioêžÆ95%mlªÐêªQØg«à·OŽÎ ,BÞP]EXêOs»S0³Ö·A²]Ã#á °šF’áäï( %‘gyKõߟ³Eùû«OÏ×4ðúC|ÄfdË£u…'£·[%žújÖm=?€C‹Š;Ì8ó2ÀÌKç¤0·ÿ#Ѿî-)]à¾ez&âO#ï¤ITŽzr“¶«þ”Ár¶ˆâ¼³h½]’òƒ¢µø#K½0&SÂØnÖC®õ)ZIm°I]ëf7g€i†øht$ÈÃN±ýó 蜃GOõÃ&Óôcdå‡61Šqµ+$ô'ò…Ú €I±YPQΡåGèùк ÇtM7R-èÔ™,YúyQ¬º‰~A,¸hLºxÀ˜¢Ã5‘p±OC³ 2£O:jŸÞ9Q/£e“çIçÌ„@´«Ä;ù*Ì×:˜F^v¹a ÝÚ_r _ö8ˆhÝôñg`Û*°ox×(dMÒ±)C¿¾bõn„DT{“ "ÔÑW^´â“ ˜OˆŒ¾õöDªª`Æ—²QHšœ$¨€—L¹Ä&Õ%EzóôJ c1·Bïd¢‘Ü7m–òèÚ7Ã{”Gá8‘ûµÕŽx¬¬¶Ñ .ÊÚôÙ½£†ø¡?7¤¥z>I“+ÕÂÛ^ÏÉטð9E½­ír ïÃ*«ØÅ¨䚩8XžXu±–û,Œú™™@u¶¼„wû£¼2êgRgº3ÜFƒ B²bïã PbËïÏb˜±Iå]ÚÈ”àÎø~#?£U3Ðiª$Ä·v«Çð4(Sü¥Öa >3e­JÙ­àa”¶2V¢å5„ªë+ÞIú$XÇ7Ϋ »5,#Bóiõô¿‡”"|w®ëbÖ ß}D¾’¢ÁÏ‹SÔ®òd¡uÇ[Qá²{HÆnòñØÝ³d£V\Œ Wµ‹(³0ÍB.gmÚ}=Ðù¼"Ï‘ÌS÷¨`Â×Á>€¹¯óÀöÎR 9úLlMû!°. š{÷Õ}l÷üwék›ƒ¹Ï%~Gô÷¡%µn#kN„{“Ÿšgfš žÚ‚ûÁ Ù'×+½PɰÔÖÉ«HñÛ¬÷{ ò´>é'‡O ª 8?Z ­þÂTìl|•ÞÞý‰£þ|ÿ¾lno”}j0‘\eä´Èº¼Ç÷.Ű÷áq dørb ŸÂ¾4¿µZšÚþœ6"|Ì Å§!ØÃë…„çQ)¬æþ‹€Ž‰Œuöçã`ÃŽU.]?òŒÄŽq·soÓ¢5‘&î“Im8¨cbö{Æõ¶…;H§RñwBÖ2¯Ó He¼ixl„mW܈ñ’’8´…Í+ñ±¡(Iõ[R%í-¡ëû?™k¾¼äRh8œ‚ÁÒÂN=ž3.Ƨ¾Ly,¼õ¯=ý(ã„G§§sƒº_Æ®°ÕÖ†íaªèÈ1rÔxü ºPÂòû§0F˜éâi,3ˆ˜8dó.”@Å–"råP‘7žwHÇ-×D¨…ÜÈiMìb†áö÷7ôù¶Ð¶§ p¦Y'R‘ l)¦—òDó’Ý»¥ ‡agýqÒàV—ËcËQä¨Ô6Ñuºm,B<i‰Õ£‡Ç­ì,ÿ±°¹:*K¶;"I AÒlDx´ÇaÊk'mʉ’ÀÀÃ7¸Æ ´ÑB=gJ…í¨Ñ¡µ¯ÂÜþè¾zÄ0×ÏDxH‰à¤ù·F|È;Á'f¼Ø¬a{?»B¯ŽÍM‡’<ؤËPG©‡2õ™½Ó¾f°O1i—lü•0›„ð/i8½«*›º­ž/ ²í"LGú{wM5 ”™ÓC… ÒoHåµÏ}m„ÿC¤­é\F³RË™QH/á0Èn»R+ #iiIüæc4?4¼‡ñ6ûI ºI ×"BúíL5¶µ¸KÈE¨Æ¢C­p_Î[m7Eƒaó'e® Äí¨SLñóXOO’å‘4OŠhû䣙/ïùÓpËbüy×§KI k1r½РŒº{F¾ô+_Þ.à ƒ¬m\º¬zô¹íù,ÍÙ³P ?·ÞTcùs!kó^óÕâ'A)j … ‘€Aª1óùè<µJj,Ø+™¥a2$Wø^%ÜZòa±zKðB/)u™i L‡‘–ʃ´Ž#aÒXxá¹p„ˆJ+›O*q¦JÞ-Œ?yßõ•v,§=§ñ{ön˜ÚFÌŸ½_äÆ?yóÄ´b®¡ä>*ª×ä~ Ä3c–õœÓV7ròkE@W?d–GcŸj@¢¾´„Ü èQ!ƒØùHÄ‘ ãvŽ)š¨’ENb¥Œ"al ‹‰MýÈHWòmbÄ*1¶)[µýƒÈtz=SE`WÖ]s`"·¦Æ\©zµuM>:q!`fé¹`£ý4kÚ;BAÿa¿Ðò0Úq.=¨³a1Yû èÞ–ò÷3u(Ó®¦Ö²·tàGsÚJHã€Ú™@àÖJÁ kèôÀFòa™Ó²>U#F­×I®ïyY«zÓ’íR²Î&Ò£z“&ÈÍ¿ndÌuàr'p€X S¹­¤„Ï•rF{)è™þƒÁn:§„žvÀ@3ÍΕÁªúÇ‘)§u‰èÙ€Qâ.îù'fßó4‰™‰)býpÛ|&‚h™5ØC6n‹gñíŽCj÷ä›¶n[­²ó ØÓÂÌIÈšJÂ/(£*‹ZãˆE#!ˆ÷§œ™ õ»Õâã¥(‚™ÝN∨'ΰ/žÑp1G¾y¾ÈúÕro¦Ãæ3ÌÖ`dMoéÃSÍ ßáx¦àevBÈR·<ÁX°ÚdU{ ;¨w½45eˆt¼%ž’î@ÓrB^¡þá'¾ 3²æ­¾!44'Úr:Ž~ê*Š ~qÛµ Oå‡at¾Ã‚jvôG®}z  •[nÜdÃè_vÖÀu†¤³ßо(É· Å$åáÎX<ÙK’ҥ텯хr¸<K`ƒà¯wåq1h¢Aã›ÞûáJ/Tbƒíö,–¶Ÿsˆ}°”P²ߟ³ùû¨ÏÏ×Pðfм³Öóç‘(¸£ìË-pt2+§Zô«ÐmÁ;¨8â´1鬸}u<à’¡Ó–uƒ²µC:üs§™ë¬ mÛ¼úQ‰œJ|•×'“ŽÖ‰!S¡`¦KøŠÃPõÇiÍÖ‰ÜN¢˜yOJ<¨À‚eÿe™ßU—Ÿmœ ÷Áƒå1k°r ?× ï5úY=v½6Þ ½#kIã³ËË*|"ï‘«¦~ÄQU˜ë‰Q¢žþ ‹À…ªg.šXñI‚<Í‚[i/4c½U|¸•‹[¿zP…Exæ‚OÎÍ…MV]åxzŸÃóç.>¤ %‘Üó ðÌ­£HðçÙãT½Æ!¿DÖÉ»§Ã©,¼Äk¢B£~ Ÿ) ឥà™*¶tôJG™¨:z†˜„ß'÷v¨|~>º)ía­:'°š9,²’Ù­tìâÇóÅ&P˜‘¹G+ÕÏ7>™d,´ÿ"P¸º{%ˆ¦\ò¦Á °Ç—EŠÄ .á©&\ZÅù-âqNÙ¯œ‰¯HÐéÈôåîV›ÿw¿DåÖÔ‡ŸÞŠ/ðiò¢ &+4pŒ°cfyØ~böse²ãÏt …±Ö%œ‚ ¯»H»aŠA;CÁ¶>ÈÃ~%ÕÊÕV¤ Ë.EóåÐïýûŠ˜Í&šŸ@‹=¢û„H(ªÙwé›3m¬þêÀð¼¤Õ$ê}1ñ'rî]O&Ø©ª¦cø}Ëa½þ(K¤L äd”´2Ðþ¿‹PË'º2ÐI“Ä÷§A26ȳAë”n¾&qu`àžG:dUï—+9Ž¡>»¢Ëâüòxûí`6Vðâ›°ž$c7˜êIºóç—å41¶p®«„ÂlM JÎ耡¶Éé•vÊ啽¨¸Ú¾j¡~Ûü(Ô.æqÙù.ÝgÜçsí“™ $åĬ•]ISÖôÚ? ø ÐX¥Ü—þy0Ììv) ©í¨/­†³uÅF¥R+äð–yÒÌ™SPž*Š{çD4l·nóÃGâßã“uÓ¢?M¶aµzU@Cçì¿=SJ2%´Ž)«ßYƒŠG9À°g'(v9c• î¾ªpÓ&Ï‹C¤ ¤OHˆ`hOí´å±qb0)­Õ`7aax>ÃÑd5ŽKtH4—ŒÍmG\êšÀ«}bUßSsTO;¶Ä!@ª²ÆÃ04"u¢ïcáó¦þ4Æììç½¢² ƒH¨ÙüQ< ØØ†¯×e‰6¼?Ù®÷Pd£ ©ò „¢–IºçŠÞ4kêöò7î t6nèEu6ËùV2u/J°-³vàäW…T}ÏTÖ4TÉ„çKKâ3™ô‰Ò­äBùY·é!£#ªAö6ƒ¦I ±ÂŽÉ¼°åAÝȲY“† 4Ú×J׿O¡`¥ìlUÓ^ŠŠ#´ N Aî-Ûq¶V³ò±Œá45ú0úe_à²Á„ËÔàNoØ àâÀ¶;’Ón‡\&Ö‚­‡ +–±¢*½I9›ˆ|‚KÕ¥âEì#ØMè5zIi㣤;j½zµð -æ¾Ì5û´—*G¤äùÞÖap-yþJîõß…õ”WÄ奸uE ðBŒ’Âë©Ùµb£9ÓÍÉTaÐçq°ù™¥i nŸ*úÚ§ClZ65–Rv0‚Qö»t7‚Ó‚~Áìó¯â#˜1M¾¼Œñ+C@ÝåeB°%ÒÕ¸ <ÒÉmV× <ÓœV£* ÓW+ÄoMX›ƒŽš“2Þ[æ<è¥ïlõI@ pVË*ÜÓz"Q¦l%Å6ZpzÛì“<¿(1­ Fw1½ Àñœ×Zñ²Ýž‘ÚqhùZ¯ì¯G®LøW9AhÐ-–al\­¦QcpŒ¡•-³­—¾Ô@º%iy3á%Þz¼Y*‰I™DÆÊ´{Œ!žÜ\îl XDØ[Dƒa7þËŸ¸|Z¯W¸e^á:g²ERÃ,yjJ#'drløIkfÖF ÅÉÞjEÿ‚|\Þ‹J—Yè–¹dJD1°¦š_ÉÌZKvî”6…ŸõÄ?HìEçj®–è<·»+s*й¤+ÅZ¬,“Z0.êÄ@yAµTªþw· PVŽb-Ëûö ênà»_¾óáü@Éñ^úÒ!zN@`Xår•âXÛà"Ûö ²Üb2ñå¹Ð~"1IY€eþ,Ì=g…nÖ—s{Gï÷ãÝ‚©á¨(=€Ï8þ• ÕLàuD¤„JÕ`WðB±›oÈ{b]ÖÀrZíËœ|FÊoÇŸ[—`¾nÜÙ×KˆñH ]Y!ð<ø9iÜ)0~ñ“^äñnm¾ -S±¤àMÔ#Íä0ÀÿJßÏ#F u1le£¤o¦8£[¢n Kbä ø,ìª0ÄMOSÿ)2Y¿ž'¤u)'ÃPŒâí­¶”Dý'Îìð vü–¼º0ñG/j2ŽÀ­Ây€¹÷ÀŠ ÈW¢6×ÛtÁâXºd¶åäÔEc$Ÿéç—÷ißÁ¹ÔhÇ4Ä>ô¡ž/‰5m~›¯·Ä 3ekg¢òD˜”ÐŒÅgÐBkelpaöåíå¢è ¨ú( ]³šWa—0Iì"Y¸{ħ`lÞfkŒ@ÍDÁ¤…\Ñâ­?³]t.,جá BÓ¸æÕ£®’ZÅÙI”¸éméøØ¼*Xí±ú¸›øEÌ‹Áâë€v[»•|åÕÌÜdÒsÑ+óXÔó¿Xö’ÄÒ[P¨Ã]Oñ“CÇ1çÂò öì"7¬‡Yç“0ò\q4§<½$õIÑ‚'#iØV2¦ô×EÁ©m*ØA¢fÓ¼°ÄÓž³²Ô_Ó–`XL¤åZÜH‰ü¥oå˜×¸,HHº¦]ÄF6<•2oš~z—s.ZKª¦Ùö‚n¦o†ºaG BõÝbx¨4†´¢ +—Âç¹U‡jÝ:L¤š$²nœ$¨ÈÒÈÁE-ƒ¦üî(Ý"Øbó zí`FG±#ñ†q´:‡L¶RëG}Nš¯\nG¨ºPCwIŸ@ž?Âÿõ¸‰u”ˆ]c99dÑ×3p›ée)™†tɈ€<ÀÃôOsÍi+ggM)«·bÿkCŽ~覴œšo&È|Nâ !ªV’ºtŽ$LQƒ™9Žç±­Üþ‰ž(¥SÞ$ý†d3"SÓ]GÕ¹l¦uT{»]M¥«6$5Ž å‰ÐÌxùÞצ¤?O(ºrñ¯ê¢£‹ ò`$x úÐÙÔa+ðÂTW{w£YY­ŸJ•Íš–ôÄ:ì!Õ¦Ö7†ho¡Â™K1 q2”vX@†ÄIË"OJÉR‹ý‘&]pó-Ïëæj}¹9Ié£d6ÞÕŽ!¶Îqpz‡ƒ!åÉÁX°ÚdU{ ;¨w½45eˆt¼%•ì—O2îp:;,Ã6nýI°ÁxëßÕ} ;ßžòö»' ¾ÊHs´È¹{oU嵯t‡B±aˆ>´Rþ™Ü|¨> …Ivz\Ý‹óËçÝ I#®ÎÙ’É?HD‡øZýW+‡T/‚@ä_rïò7$²æóärx¸{¸!#ú4JÛלôýAh Oߟ¯µùûjOÏÕÀðâ—Wð—§·ôMoÙ8^Þ`¡ÿ»×¶‡UkË„1ì,³…ÕЙPîÿXJ^€Hm•ÑòÙFõ==3<ÊWá9Û=ÍN ‡Àn$À—Ü—%©AñJÂØµ³?9ÞE8Ó£ë•;ÑÏ) Bº .-MŽñfé<ÖXC‰/ê>¨•€‡,‰ÉœŸÃ _ Ä`Ño ¯ŽcòútÒÞX, ¸PV¥d`,€#›I¨ÕPxKXºì1Ä¡Ó%/†íÍlªç•‰!ŽÖ‡¯À\4Rx±)i 1%±÷€/I­º$×´ƒá­ Tö=Û¦…KêÁÿˆìÊMoÈbÖl–`•Ê¿ë}CD¨šGŽ•+#S]Ü|Ä‘½ý¾È†Q Mg##(ùBdMœÑÓýq!ÝW1hê7yø®3þjñ1>n6 ƒ«!%·ª=¥ÏõÐ~”17-] /Ø¡çd{ÕWˇ• 0“ãä‚•¹ËWËó¢“xÁÖ`+ÒO¾ ó ãØ{X3Y2L }íÄÅxØ¢Ý;½® 2–$Ra&ª'Ø|ÏÖ»þÌ„ï!ÁòA7MŽ­F¿.¾:ÊÞ›Ù8¥Á†wV]ø¯7gDD.w£(³Ê¸ä±x©8u\²2,òògÅ Û½ÕÍBáD—a €×í$ÈÌbK6Ô«5Œ“¶® Þ¬±·Bïd¢‘ËûÈxû—Øõ¢ñàÌ h=*ŸïÍ-jðÏ0RgùÂÅq[mBo£ð|îdŠ0D‹œ?"Õí©ð5ªÚŠPÐê>LÏ“‰3Û¬žñ s<¥?q"<Ÿ/®0P^»Ëg‡@Ô(8G€¼¤uº{7 ­Ó¢Kµ*Vÿ8KV "ðÝÑéf«*-NÑEWÕõçý’%AGNí8”oË‹ßhuœÐg`ÄèÆ†N[d±þÿ'ž´ž+ñ¾‹˜b5(ŽËÚÐQíökèG…>çÚP!O&AêS–¢wïO‹ÒEiÇ‚‹ÁáGçç=ãë9Ž¡>»¢Ëâüòxûí`6Vðâ›°ž$c7•anëêñðDBÈ1ñ µþð0"þT\ÿL°\{mÆ¢œ·à~@W´:ó«{¿|Lzœ —3a݉‚€ÅY:ÏAðïÉ@ô‹„9M+vïÃììv) ¦¾€BÍ)oü€nˆÁNÎ䯔©Ö=?ëFîˆØ$gwHhIÚo¾:¸7`aöƒ‹yt™Y`m(P5'bo™÷&²©yØQlka­ÁçÖ¹{¡Ø¯P„q튷륩–JŠKõnÊB8©Ý?±ù‹'oEÏû*›_< e¨SèÑï)ÖÃz±x>´îO|†”¢Ðå#í”7ÓIØá¦(vãI»PàÇgý¢5–!hG7žY„tuù@)CÑ ­»‰ ]FÂÇô œñÝèŽ=€RƒöCçÎ˼R›0Ö¢µieŽç)k8%£ Ñ<¯„ÙÌ?Ÿ€áéÆræiÕ4X ÊÍ2¾f~ß±…YÈ=»Òßš›ÒWùÜæ„Ý%‹Jw_Ê÷ðW†=¡ †Wxÿc”1So>êܸÕr•q­ìD@Z·f,]ø‚è'ª5Oÿ·“àÜ(DG£ôSæ|Ÿ–Ý<ÃÉ!3¡:¨a’’Eä#lßÊÂ’„V¤ÄWz/OB€Œä •ƒ†ÿ5Þ‰+™Sêø,Q ‹'Ôs¸ 4r#MJ—ÏÃÅdðqæd49é°í*·6Ëû™<5«~÷•0þ{ûÁÛœM4=‘(f\º‰”¦9 gT‹ -kZ€Ù°%^ÖÜ~Šº5mˆ¨…ú°ÝÚ¦ù?€ÞÞŒõ½¹ñçÒ0Nz£”ÊEiåΪge}{ VC¨9—ˆãØ´ÍsØÛ„øò>u„X¶%R„Æ×ºÚ絚¹JmrmW”rö@¡ýyç†ÂZUŽ©PzÚ9j.ÌCn—ÑJñ̓#0Š7|vÇï/phØhŸ´I¤ìâ«ÇBìk}¦DÂË-d…Èk×óý)h^¶„í¨pWd£¡?äqkêïÉ9•ä‡äT®.Ájï³Æ ³O6ùg­æÛ*±É¨bÌïü_¡¤¢)-yŠðGH)¶åß õ5ÆÙ71¯?Yy§WÓ辯ó¾ä-ø©1ë‘;ö&^xU˜Sݼ¬¨VºZ·šR-±dd:ð‡¸ú²ÞÒ‰xOM1±ÂƒÙ~«¼–„cñ¹ª(=žhêÜ¥Ìñ&ëZ2ªÓüÄ^5.ÁÉÝÔ;Âi|ManE{êÑã:·çc::ИòóLÑ«)®¬6oH+Ãþü=r4Qƒø RülÊ9•JøÕZØd›Ê3¢ãŽæÃ€++[<ŒøÅ6Öýü&ª ä,w²§б¦ÜÎ9kp°à`J»™¡§—ì7— obOB(•÷û_˜å£‚9ø…A#êdÑ #„ƒWApFJ¦AYÓ|Ö¤? Qw÷4;7öÂjËOvTM/䉿-%»wJÂÏú⤹҂…²Aû•Ll sIns'y[ï `»»*mQ¾MCù.í¢ºÚú=gúœK,uhÃØOܳåâåÁs[c^Ã<Ý~°¼„S€\Y·Äæ6‡Î4ŽÙý Ȥw•á]”Ž#r[ KŒŸÍºCÂòˆ´Í>Äì쯤 ¯1îy«C›A !Ÿh­—lOô{ï0ùàM&Âufø©Âr`’5ávAð³2¨™0ž¥’;Ñë)Τ¶„Óéöì'†Yƒ“¥¿€n¥SsDãR‚Ú=?èEwèÎ</_»t´š‚Ñx¢oÔ¶šËØIy«ñ‡º&c™ 8î()Œ‡Ïàö#Ö'R¦J]ɘ|1ꦛQBœ@àþe„yï° Ü|3ùH@3*¡/Ÿ·Ø¹Fϯc¸"=1x·^Xf-¡…üâÊ:ÿ'1o41±b\ê€ŽÈØpŠä/°±gLGà¥ÄêèƒÉµÌ‹“ö²M1w>ÁÔd‰µ8ŽÕI'%<´UþËxm±tãE¹¡øá7ÜUÛ!ÉÁb#&BD´`…šÊN{û^ yÓMÝbW+¿‘.|HDEzhu-f…΢¡:ãè™ÜíxWÑbåμÓwõƵŒ„5=ô³—ýآ· N!ß÷Gœù( MbS/©»\7¦0ɾȹ3?xªË&:‰®’ãí>_ƒ®ŽÛ(æR4E&í;(ÕîHÏ*_ƒù©)@Èyøa“B€^2éíûЭ|u4?C›œÞ7f4N AG=m!ï_÷~v º1/}ì›ìê0¡p“ËdqÅ3l=È)Ýh;)°Ôy ã]à}»øZ‘¾­{ÉïëШ¦Ò)ǹ„ø’‚ix4dUƒÂ†ïÆ8½¦¼t:NgøäŠš ÄÊØ€•'Q¿C±ÐŠíõ²Ñ#œ§j떃єš£ùOoz·ævºbšÐÁîÕ0¹míf½2'(¯ñî{«†¡Óç2âo€+_„UqWœÞlD•tÛlh|:ì–EPP`´g32˜È’áS±¾SG _dÎ|Ÿ =±zŸ¼îûŽÁn~žÌ2»"ŠÀ¯¬ºæÀEoMŒ¹Rôjêš|tâBÀÍÓrÁGúh×´v„ƒÿC¡äa´â\{Qf Âb³öѽ-áÁ°,:º±’w·Ò¹)g§¶i§¢Z(]bÛ”çW\Î-ó…Õ4 ÔZÎ#cy!¸W)ÎM½ˆëÓ{ó[´ô•°kgëVISM`–Y«s±¿kƃ~ãâ"£˜–évWžÒ¼6ßU^ø8øãñ SP^SÖ4Æj¨>:ÍBË|c {SÊ@ÂðgÖè0í‹ÐRô‡ìª0ÄMOSÿ)2Y¿œ c«~ó¾0…>WT:™—5vç H?¦b)l¨‘ Ãלúc;FM |zðæ+ÉÆú0켟­uL»f,г´¥Î«¶·‹ÓMåC`iTUâJ3™è˜Ñ®ÄIr`åï4ˆƒ %I®“«+`\¦ ¤_Šw–ƒŸ‘úÅ„Ö*ÐÊ?Åqê(†ê}bÕ^ÿrŠÜW™äµÞÉú\á™îÇî¶®AÅ’ñÏÜïFÚSÓïÔ*»¿u[nÞ‡™#gÜg…欆œÑEI)°‰Û¹ÄÉ6ïnšÚð;Æ©}ÞJ~Áyé•¢b”p¬Yù}J,¹iGßÄØ!=ÐÔîÎeû5÷tñ–¨±@5“£ù’Kâ#‹æ^¯¦*å`´}±Há†%©ñÖ?e 9§¼™ö«0y§0WÛßh,É:Ê>|ÈZÓÏ?Ñêω¥ÍÕ]܆qûñEEÚ-ð1 ©¡b4‘Ç ûã4æÐßÕŠ¶L…dß.¢Pç:XODá¤~ÒH;.à×G1~6¯EÕ› æEäR»±` K{ÉOø­£$ÝF°¨ÌíÐsn&/͹YdtkýQÞÍÇ òaC­Ínecµýþ 'qo®ÌРæëñuVKZ%ú»afW{*1hI©lðwE[~•ë5=¼÷^G³Ì91Ä_ Z;Ïΰ)GØ)wLN_ým©ÊM!$˜aEõ—àÍÕ,»˜ &wÂ"ü—Lû¡JPk¤´•ÅGëÃRH““¿ë´^ž±âu‹ ’eƒd–MÓ„•yY(¥°tߍ[ ^m[e»ÝRÇÁÉ×w|ïW›äW–‹ØÉ7Ç3Ngp|à1Pžá§»‚þ“›í±8VE[@YdJ'ߌթÎÓ4ìÕ$—¬¥6áØÝ­ÖYõZ³mx¤Z]‹º$x¶7(s9ÖŒNåI¼°ñG1¡õ;§”iIéYÌ]@z}æC½ÄmsH¯66&T­ðdáw$wïkþ»è¬ÙRÍ ¥=‘<ñ•ên»Ã['ЖÃoeœ¡V-LÇD®€€>ùÇ3¿O¾¶÷žÙ£GÐH\V|0¾t5:éöÒ ´® .sCê¶äH 9Ü«uõ #Ï-\¬ÎÐeÍ6“˜›ñHªîZ]æÆ¬¿ ¿Ê`qèáßßáx¦àevBÈR·<ÁX°ÚdU{ ;¨w½45eˆt¼%ˆk—ïh÷mF±äñ”Ã:2Š wî0=è²Öj_ãq¿=óÜ“AóÕ·Z`! T3F=a‰îRß)êï‚þªžÝ£¨8FÄë#µK#ø³b¸nê¶ÇEóÅéúü:2å0ðµú0®Vø®Qá’±`-XÊÑoµµ¡-}CAsLK>¸ÖVÓbþTÖÔ&ÁZ‹s¹®Ïà ønôüö¬Í\}|¢›2’DІµþ$üV̨v¶"[i€l»c•¢¥'¡g=SZÏö¥=ý¸Ÿ¿Ô)8ðB¾ŽRza{ G )eZ•¡ÁÚøÍÛ‹»Û{´x•ßH3~ÁCH?dšÌv\ÛÈÂZÛ÷€×AÉ€ÞWõøÎAŒ&33œŽ*E²E¼©’SQuËâ²",W ¢Íø°åô¯˜K'äï`õåT ©Q„½¾Lëܦë ZÛ…¼`:†5‚¿c,r¾} HåO*M9Û  è\un5Þ5=(¬è íÿ#+-ÿF®`™Ó€ÓÒµÙYNßÀkæÒ¬x`©0 Inx¸„‰6‘‘HMœÌÊ¥]ÕÖËGÞÑ·áÙ~æŽÎÍ&ˆÅ.—„áËxéQªàAÖRß¶m0=EÉÛÅÏëÉpQ_-€ˆ- "×8Å­®¡Oû÷ë—5]"ûî˜bœšC·é¾°®0ÔÌãÊúÚMöãªNõ'³Qd{þ§þÍh *B‡?î£åp¤Ôoì}êXÔ41E¿ä¬9\(° šÓ`ôìWxuY°iël÷3ënŸélnÏry’®¾æM>Д+ŽßÖÑG\f'zL$bl&ÔGã•ÍØŒ3lî5|µØ†Ì(úl¾Êššyô•ÿtùèÑ©Aï„|-¹U“Ôó—ô.€>/Yà5xÝfÒzø ?6xnÖ%›BÑÛX;­ƒ”ÝlËc6KK¿÷ýoB7RikI{£¹ÇŽt­³&ã¤ÇËô°&¤Ô´Ÿ€èr`¥®ÎP”Ñú‰‚½ \< g4º'µ†‘|_SØì 0ô/TE|Aî$_ÓuÿpóˆžÅ/ÍÄÓÌÿl¿çðì†ûzçþ‹ÃÑ>ä/ôïçêEüýD1ü; þeÿrö@ø^}¹ù^r3LÙ;ø”­E9ÊÀá¢dÄ‹kVìà‹uØÉªE%$ò4cÿ7À‹®jqºÓA¢bÓf'ƒ~³o£š.ª­\l(1oÛFX†HÕg­º³g^IüÁÕ`^C9T!O”¾ÂvÜ¢Zúf.`?© êYGî¿»È% ï ú2k'ì6ô.Œ<0ZÄLÙ™Rs²úì†I`öÑ‹3îž>¶ÐØ =ìEÞZ¹Ùâð~ˆŽzÕcs‰ó`NÔí¬n ÃšÒ cUÊ‹´N³Ú‚|h“x¤ØÙÃH‹6›âM8 ¤[)ËS;¦úÉñÙÿfà>nå®õÇê8ô¦ä;„“¥Õü[å»Í¦Y”Dbü @ ?ê^5K¢s.Yh<:©}RéW²¶ñà¦Ïï<Àiܽ§¯êüØK–‡&~ïQ²5ιi™LAiÐÂ)º¥v"”Ã2ÀY™gJ1ß’zUÿ# ¸ú?ºFĨŒþ‹ÈmÙp„Læs,uk²ÑÔ¾ßÃt<6|™e–ˆªö!<ÚÖ£®y14x:w÷ÄúœüGäBªƒvÅ–rÖü“tþz5£n|V2Ÿ„æÔ78o“ìq`/úÈ ¯å"€V ¿µÊ ¬Ã~H¬rÄ…ö<áÊ…h@`z0‚Ãß"BsÈÑjÅ®C³¢Zú=íòÀÝA&é© ,'ì,DBi-Ò¹+Wäê“a`%lɵíN™ÛØ^aeW é†ùVð± îż\0þ^HGíP” deq°¬—¸óRi˜°¼§jƒ\eæu#[@ýYñǬûú«O½M¬,²wÚd ð‹PðÒ®ð©í¯ÆÊr>ßB45Õ•"ò‡$á~çE1äc :óQ|óqÓNà½gó€Ér­‹:ê‡gð5ô:–7yŠ6O ʪ¯E†ÎøaÆhnÆù@#G­pï‰ì½˜Aôs Y¾…‘I@?5Š‹÷TXãKþL’SÔ$t9›_ÍY¹PžIPXºöÊuçG¥ß€ûW÷àîÈçh Nî*©’“švÍ“öcÿ^¸ÂVâÁ?wîcéWcظÎ3áÖʆ8ܯ'Ìá~š]ÖXÀÚC9°î­— ÕÊj)IüàÁ®H6ýÍ_#«Vȯ;ÃÄëfQdX%Ï Ð9‰î‚ѶtýNY§)<²€¶â:*ÝÑTXà%8pèD'Æ£‚ôÏ=ÛzÖ¸—‚ª±4ír,Ÿ«ÿsÉQsî„À0êÐ8Þ’²«¼mÐf†Ÿ.&äÂo…Å ]„Ïý ðañ±”ÃÞ›Éyˆµ Pè8a™èxöš}A7¸…×Á´þÚo#íBuúQíC~G„·§kwŽL”'óc˜¶*Ëáq5‚ÿYª;ú÷V7­s||½÷wbædÐ<øP¤ÙQ[Þ„x‘¾•µaŒñãé„|}Ÿ±Åq3劰çGÙfò1ó’S[^yÇŒu•YÕàµj‰ïð j#™[—)9ŒÛ·rvKD…eÈúcuöäñXMŽ2žZ%ß9¨EêÔO¤¾)˜1ÕLMRE8Wš%ưβT¿ÂX¯ \çU`ÚŸðÿnt^k¸`È’,l”¯æ'U3¥ÄôÞ6׆-w˜ÿ#œQôŽ}™šÅ(9°|†T»›‰†rÀãDQ¬S «š8dyz=!´Ü–‚bŒdêÞ —ühƒR·d8bð' Ûpb;ÈÖ.äg¡^"«<",ŸNtIƲ7ÿüò£1ߟXH•¶202òE‘7ªáJvݺ2¡÷ņ–vTH¤"=f ¯]B;¬:ÓƧvr,/yÏôTÃÜNhOqÞžN+žx=:œØý0i¦‘¶¹1Çø¼g¡Ž@vªò©K3ˆ¾¨jí7:”V•Ô33[Â">TÐH¦œÜs¯ hvÁ5 R‘醌s(+yù Gìõè˜BPd·+ôZV+I×Ç{Ç÷>;=ê08ýléögÚÓ¹(Œ¯{QRÞéÂç>+v&|wΕ3õ†Ûû#àAæC¢—çû‰rÛæ.ºú˜G{a3™à\!0¼N¼¬”.XËí³ß – ï"ç^õZ½ÒB½†ú`d?íî=…Ìàâ’ÎÕ1mÁ¥œž­Àõ>":/ŸJ£ x«÷=±ƒôŽL'JÃÃbr5—:;b3¸3.¦ ø´“{9Ujqá^†÷Ÿ/<ΪOξ»/õáo´nn\ O>W«·Fþ(£Òë¿êUêúü’«˜‚‚î´€X:^ ç«Ñ£Çãá°çþ/¿<ùŠð ÓrÊ{‰õ$.$-^ÝÕ´º¾õÙÙûiÍ‹:!Fš¾r„5Æ{祽H@¤·u¤ûì `ôÞ¹ÃaÊÈRÜg¢¥ì>ÆçšSc³Ì~L‹B(¬bR’žÌ¨ÏsÍ “­¸¶2o¶ø¢wÊ…'EÚU”<ð»óe£3›•˜BûÓÄ*|V—{áWyt{ßf®ƒœ¡Rq¤XCÜP¢U‘c3æ©z²ÂwíÒW•Ý®4 bTö–B^¼r õ7¯ ?GP!Ÿ ]_¾«°E‡d‡“P»6SÍ0’Ó” ú+pNùKäÀD!5‚ß.u2ƯÑFÈ71hOBËÌØ'èN7aš×ÂG ^/“:s13n×Iù±îYðvN¥|ˆOG’†?aÁ>?vï7 À+jØ. Ê[¥ìëÛö1`ýfòHÒ<5!”é»|Y³—ñ ËþB¾½îâÍBÈœÊú%ËÆT9X¹…3>€o³˜ÍŠå)¯h¶ÿU‰0|¨ötšBt;‘.Þ"•¼B5yŽ]Æ€l¦PÔ•¹n®0N ÑYlšM~É´ß^_)ÁrÄ `î\’IãÔµˆofbÆ [û@Pس΢ʷJ® )7ì·¾fåÈ Žˆ­¦Ù$Ý (ý¿ã'ûiÁwí£Ž [»Ò Êíñ ±Åi. eô˜Q1Þ9Ö—øÂ#j ðùGB£bÇï5× ]3†LgôÎ8{Ý6(@î­ÅuSaÒb´´ .Ý9ÎXá ˆ ìœßñÂPE‚«7±M%ÆÊ× ôÁÔpZl¡QÇP«$wAÊZ4ÀüïÖ¾ Mò»\‹ZN²³6Î¥ô/MÓ%‘¤Ú×­§zC,zÜj©˜`%€ŒgÌZä*Å0ËÅ÷çÅ>°Á˜n)é¶p—!.T€ƒª%c¼ªÀÉ=~9ÛR:±â#ô«ØÓ% 5šäc3ÆÄJâ%ÐÜ) iq±MΪ*Ž3›š¼hZaÐ^œ$¿T9KIK¹Ñå:!Šm'G ¶‰Ñ¸ ^É]˜p¿uËMûJ–°»?ÆZ“¼’^÷ô—´¿%`¥#>‰+ÞD¿]}ÐÑåP€G+µx([B1ÝÐ%¦ßô¤;B,žÙ*‹lÓШÁfIu ¸¾Ñ8ÀÜËé}âþî,¥Ù>ãåJû?8 fGq¤…–Ó¹B„¢‹ò4Ÿü;¥k=¨-õΗ%•ÛÚ žCIñaBb9ÈÕ:D ¸:5Bg‘ô¤À0¦¬[g =ØZlžíØø&ºÚi¾Í'ß•ÒPéw(§¡·c̽xBoïyÍ·Óð1“I/KÑÑ‹ú·ÊÝS›hgÍ.í}P~[xsê\xQÀ]Ž­ânf «T¼Lgõ ôÁp]³‘˜WêÕ¶o Á¸Söl5!ãÝOÆb¹nŘ[UVJsu­ÏÔæ Ó«F’¦û~ñ!çŸâ" un›‡Q%KÚÚ«vbÈr¤¢å ›-’´ß`Èê;ñ­Ã⮹vðyI÷¬Á æÓbhn<ìcÏþ,xJ+úœ~,¾ïYp0°Þ£,ÛíÄX~+Ðp­ÇMç_ð ¹nq£Âf +!ºzLÉ ¨›!’ǦC éC’È×ws®˜%ÕƒÚµ¹ÚBAaQ.à•±{¡eï¯]í/·”ÅlU¥žX·ƒ™Õ©R2Yu…ÑCˆ¶EÞ·9 ªõÔEÅb8qîšVñTÝ_1Œ rÍ~emÚlYUòƒõ¥Ié'1×Í»ëÌE¸«°äZ9È›^|—Ïnýªigv- é‚´‡{Ã쩉ßÃh¾Ù”¾6½FeÐ ‡¬&½å 9ôÑ¢Z©öþ(‚ Ý#çÙÞ ç>ôÇ ×Û‡n( éqö»Rš·îßëå=ø'Ìv>r½)rT?t×åaÞ£Ÿ¢ :õoyÅe§¬^† ‘¡W•ôÿ­Ý'ÿ:¶d;5ÙÔkhr¥Ðn çÎùGiFPâüNж±9‘\h]zK2 ëöDÑ!5–É•‡|<ˆR¬÷ã"Þ‡IË‚„þãBsSÅ¥g†V#4½ZRëǯ²ÄÍaˆŸ•/îÁrƒ ’0Ñ„ePßëŽí~„'¥J‡Þ9€u̽àÉö ­?ëi[åÜð@5Ðîô8:àÑYò|1*‡.¼(]áÎ/c¬kzñú„çðÀ—E°Ñ˜™û—…ŸâQ^{Ø¿÷“Y(ÿGFº‹ai΃ Ú$"0'cXÕ9à»È…k]‰nÞ®§muì;ðþ0wÍ0üØÒ/q½0.óX8z4®àêₚ,­aB5 õ”¿DMìY䡎å<™d$ƒÚÄs8Ô«B¥<Ç‘ l’+IÄCwÙ['AÀ3Pyß²é`c‚äœ^á~cRFÞ¾ÀË‘^ŒÑZª$Iÿ[ôÛ“8Ž3†šx,Õ2§¤/rcøëH¨uòê °æ·o)3tBÚÞjº²GaZSÚű°ÿ¦FJºJv•›°0íüÉ &±Ëx?X>Ç‹1•íëö™/6Þ>EÃd5âû/]ƒÈ„M'^´Ò#*Ú@çþ£Sã« þY%ÓÁ‚}¸«zÎf-ûˆÔÈ;²@±§`³&úeŽú2¸)à¿·„£ÔlàN’DbßúÔ[²ˆªlœ“á‹3þ£gb__T…ÿW€ÜÆ:ìãíåȩތr-:© çÁ}Å‚²qðÉêàQí×-ü• ÜàäÈ.÷ Œžo[¸‚T6°ÈX¥î‡Ûm¿Ë°ni×rýò„ìPkËã]×-°«³éU•У֘жÂ*„#áQâ]2ùtx!ŽöSh±§]^'ûEÎÍ4ïr²J¡ ô£“äÀþhSL½ãÈT2ŠsøzÑ€U…žI†bËœ½^‚*ú ‹Yâ˜}s¬ÉT. ¡Ð­ô5?tçoÝÕkzÔ³i°=ØñƒÒ.,Ρä~¢§·’ÕÔÙÏ ¤]UJxÓT‚¿› ±ž]Ñuòy´X¸òC–‘´¥g¡Ê¯ƒ™ÕF•õþX¦èªOçªÒµß\;Ý Ëx©ê ¸AËzÎuå*òUÐc#$þ·#ޝn’f3e r¾êe¤JFÙÇóÓÇkÇ&nL8/>¡Î$¤g“7Þ­…9²ò¶ÙpÚ.“_x€× ?ØYRwÛÛ=J>ïIdñ\k±_«MtŸçY€%€Ó8Û±ok`K>®„E…|¯ô#O+˜àsÕ÷ÎpÈÖ=·Š¬œ§µûÁ½I©í£yq¯(-égÍJâp«r² hÇœ¾CkQ 6¢÷Ý/.ÈéƒÑ™!رªb÷ ú}‘zŸÒý´èh'RÆ"ÔžyÍ–y  BpLµºß-N n ‚N•²à-³uÑ\À#Þ#¸B<ˆUçÐ 2ÕðGk›/h°d<é¹ÃmâK&ÝÝ/ÌPn„¹ÉúÉ2#ÅI¹ ¡y¯úaÎ/µ6F-z{ƒ5°&Ô5û$)Æ@þXlëíz—߸f›y4,föëy=;Ò>M8§é/šóC²ñ¬¤dðЉsž(‚› 6ÙùhDCÓ¬ìܰàæL»€¡÷Yò%+®ôÂ;Í{Å.L5Ho*û[m-J‰V„ŒSŠ ]Ü©1õn@CÈc¦udhŠÀ˜7°ÒQ‡tí¨ÇÃá x:¬ È#R¯uzŽ÷ò!µ~0.÷30’œgQ(΋PZ§2û‹¹ÌÊëÿ4ÞÖ¡Ö 8ãmèÙ[û.çyqË¥Ÿ3¨Ÿ‘Ä‘„ÆIH —ÛÆbŽî á¯à&U¦&JVG^ x|fz+µB¿å»Š°¨ÂÌèŠvtl·óÈó6ViEÛ‡ŒƒÌbT6nó(ׄ“Nž‹ˆÐ"­ÏuÛ+ÊíbÃA¿Tá´?ñܾÇç4“ñŠ2ÄÆÃOÜø‘DÜÚ ÍI÷ºÐ-õ«Ð÷ÉÅÇªï¢ H¬óDvmCD}ì¯ ÕC*UʇÉÄEÑÈ ²MZÏsl-ZîŽÀ51@Qü¾éC„b¯2èõ¦dùÍù Áû°§Æ¹¬*”0>Uþƒ¿äšË>k›9©ö"1—ˆè™ÑÛ¡ EVÇ×W†7¢vÈ+½7€;-^úù™:御Ê1ÎÞ Åá7{Xâ߬v#nή̞º]™Ín¯¦7„Áµ£ÌqÌ쮤­Ï› SJgÉ|ü©âmÑ—$*üÍó¨ïlÐ9N¥£Vºk‡ˆtLœÌb’9XÛ!s…V)>l)K”NÐ:ƒ×'ºÊû n0Ý™·@˸$^yámë‰2sî íËlêzá‹3VtC›ó¿]Òë\ˆñEê” —óºPƒåÎÅ&òñšB¡Ø.Äoíå7f©¿ÓQǧ±{í½E`sԳϟP„˜º!–EÓv‚“ɳ%è½Èˆ¬³¢Ó(l±¦Œýd‡ÿM’Ÿ`¯n>™ào×7¹ˆKâ’Qj¬Novh8/}¢]U¡ì*j²á ¾,¦ú¾êÕÿs÷û™âºC"Ȳíäü!Ý6BÕy°³‚âýÆšlhoø_€qÇ;.O—¥”;7©0RæDàÅ á| öKìZ³²¨‘Îȸ&y42_&N’ꌦŽ×=Õ3¯»}q%€ö¬U “a(×rm,Ÿ-&FivMвÅXæzhî¬g¬‘|®j鯆¦_Îh9Vwò|aÞß8-¸µ¾å$µL­G¼w¶$ßf‰@(î ¯²íº^ÀkJÔÒý$P.‘ãÌnô ›Í“lÓ-0“In65¥Y'ÅÛgöàög·Ú²Ž€HF¤ùu¬{[â¨(áͲ6ià[™»z½×¹š6©nî ?ª'!0x!«*~)-wݰÂÝ,[sÊæwv[Þ×Ý9@%!í†JãX☜?Jßäm rA,1úš”>¡&«ë_€}§™éáò‡^É|ˆ8°r Ä!+§Ìïå—‡ÞûÍf9Ô‚‰á`U¡}vléœÎShú¥T£ Ž¥ÙˆO‚‘¾Bº ÃwêØXï÷¬`ck£@¨>E§êxn—“<¦Të™Ñ\Q¢ìcÑÙž'Ò'ɺÁ¿ÚÆ×¼V MqΔ&„™<üuæq…øÌ„` Ð2p²§ß‰ùŠ¢ð2§Dµû:‡¼ÓRøð»˜°6^yáb# ›f¢JEôÙë·ynM8ÆÜ!‰zù;‘¬¡Ìõñ¼§Ö!è\6‰âc7á­ÂõZ±$_õ×Z³lhÓ7ó“%ècµp̺ íR:òĶ­èè6’Ò[¹Ùé¨ïHm0 ’¯<%>øüÜY¡tSʥ ×2þÒÛXuábäbÄÕ£×ÿxáxÛv]4hÊúW•Ѳqļ"‚³TÚ°q™æc؈»ºútñZB§Ï0õM^sc¼\í–§8´v–Õ+ìÒ]›Ä sX4œI$XäT‚Çî[ï[©üšc#¬¡‡/J¤_ò ÇbÇuèÚÅ]›ýœµêhUXËÑ—¸ÁëëšZ×­ù®£ËDÈø­n¤º„fQf¶$í'4hÕÀÞâ%#è²ý»(çðqÁŒ9Üë„÷¾"Þà¼+½çGW¤F{:65×â@^»ÑÓ½QTí1',®`P6€ÞF× .›JShÚˆÙI›r5ˆæØÚµáú‚ë„9ù1{‡žÚÇçâ8¶nÜ…=ņÿe’é A´tfœsCc®Þ¡W­O+Ð "âàÌí' —æÑ!É¢³˜‰ÜFÂ3´Ð q:žG ¢xiS‡ÝY9"73†Õ@œ{Âc¢gYÒÐ}'Â2D²»ËËÐe¶¬<»]÷2÷`e YÛÂÎÏ%åJ™œ_ˆÔ¼§ÆU¼¢¸g©›»þ_tf-gŸðþÛë{Hž¥víA‘rh¸"RÔP¿zY tÏd®™ Ú-è$8G¸CbDËÂ*ù~ܦU…“õŠSãäÏ'„%Ö~êoýýÑ-=N¯…UÅIȃÚdŒøK›Ñ¤|ƒ·EGì€oðk€`’ßÜk>Æ*LËy¸ß¡¿9Úÿ?,Çxî÷ÿsXõ½ )àÃ3œ7vÁG;þ•®û–OædóãF Œ-zöraÖÛÕ„Ílœ½k’„;Ù’ôó:O€÷ø|Òþ“dÜ(ß%@d8«Gñ|,l®®nhZ<}pPªŽ‘óèNk– Ê< º'&ÉŽmÚx'›ã@ô °ä[òõz(”=­\'Wø«ö¼ãj èÔâF¯þ8¤@Æ.¡-@Ü'30H]ã~dØÄH½«çFÑéa’æÓ7÷à F›×y/ÕHÿ=ø¸¨ÞR5²cf$ÝgÖÿGOŸoÅi­Ý ¼ƒ›|áB»ð4rÙlÝLÔƒnÆgÊ¡ ¼B³ÀE;`–9s’ªãJLu›¬‡MÓéRFw°ûO<À€× mzYƒG°ò‡äxËÿY9”<ÑÜø]'éN2^Ä‹å-(#]¤…v|ÂøS]8ÔZ¸4½öCªþ¼» Qß9¿>%Ê’Rpý>úÀ¥üéøñ)r„å$&ŽRÅ_΃®1ä -Àt¥ï;õ:9U šrF—q¿Íþ µ—9­òtvå8“ƒã0…–]À#ƒ¸¹¬b5⹨µÉ\ö/Ž¥ßûÖù0=ã ¬ñ¥ø¡iþÈÍ"XG_Æ`\?ko:‹ô ¦ðÕJ&” ‰²Ñ[~4b-½>@çD&U\Hb~“˜Ü|”Û4rÃQª à\ÙXG5‡ lžafj‡ÌG½Dp°˜¶¸IÑA¼÷3QSìš‚)7TE¨ÿy+rç}(‰+Å&Iác&Öâäb˜¤ÇWàžÒÛXX‘Îh×?-Næ\舨‹°6 éS5ªc¿=]_ˆS€Ê,Ïç†2Á¿$)ó™\1“Î3@Kfñ°ÿ&v³ŒOöUÈßãT•¥‹æ*özŒä)W6â‹~[[õÓ•ÄË1þp¢ ‚,e,`榈Öĸ›4çŒÇƒ‘]ªáº +{™BÑ"x¶ù?Š™ƒ$]ÂðœA*EÞ„Ll&)ƒ–Ù–ÛCÎ38·¦k£¬JêÊÊ$—Û•Ë-QM»rxö龈•2¸n_$íSQ¡Mððüžã–AÒ¶É–†Xb?ÜuI ŒŸñ^±*”Ì€{جÜ!Úù„û›ŸÔÑñ|Éãh.ÆU&bÿSR<¸;HŽn-ùž:kþÓ dÒœËR½éYâë©È°žÃޯТúv&©ë"@¾Z2G²S`Û ? äX5•¬Î1¯uÄj5‰Øš Ÿ›@ Y!OXQ)Xöˆ|ñ¶eSóÞcÌ|6}Ø“uÕñD,ÆUl¥u†œVvZ6¼Ky™ƒÞùàŠ}@J}:ÅÊ8欤ŸÚ$JÙ!þâšÒÎûïîË?߬.¿åõyévžzä Ey`¥e×ÌÊy]uëûÎú¾¿ØB&wíÞ/áý>x¼Næíg1É3 ǯçM—cº70¤Fé›n?þ¨ê™×1³ÍL!ìá”ÃÁL$“fŠeZ.î4,1XüÉ;V5iÜ=9VSÌ“¤¥°æ¦é{R“åa@ïÝâ¥DÖ½–ªxc1ì®X*#ZöÜQáÌ4d¦j:u®#RäÜ!_ÑÑŸÖr¤]ƒ\7ì(•éÔàýð¼ÖAï¼ð`¬WBª5pûC¤ž 9©õ¡¹»éà!Ø’D'›ûW¹÷z~¦n4BvA½BÜ ÙÃ{©>-ê\^Jyjl¿¤ïJ)qeæóL§îÌç‚;;ÑŸâD_šC5NwvQéËõë¿ÌWoŠ-ІÏr …dcÈY·År KÒ€:N‰¹ƒ¯ ½Ü± ×ÉbÏ1V!§ékõùîi-ш ¸~àÝ$‡ÙS é÷(î¾ÈeËi"6Åa©G‹Á‰ÕÎÊÅK4©¦ü¼½pêRr òí‚§²~¬õ²Œ m×A°i¢®”¦æÔ W6!Îa€ ñ®|7Aï°µŠÏ!»µ y@çiþ³œiPzƒ@Lö+†Ì{_v.§ÜdžnåêIø> %ÛÐ V9[©Œ!§XZƒ ÷£9Cl)âþ¢š¼ª½\´g‚Å¥‡3#õô‚+A(,‘øM²|_õ]EÊ'gÛA!YónÿoË9´%Ì pP;ëôL ±&RmóÝm¬ß¸ã?ÊÅš£ü d„"+JyçV¢eÒU«ÛÔ$‹…ëµÑ_';Öm1fì↳‚ýè*r%Û&=«z‚S‘¢¡ô€¡dÓÕf ÷6ÍRøSò{$‘Hw‘oÌÖ Î陑Ðt¤Ì¼ä5h?âß][ÚA³w¹çÁèn®%ªZ°„5þËK¾I¹ìÁ&cõ©3Ï>êžRO§Šo?ßÅükªñ´¾º„+× Ÿ£0ð¯õ ÙxÄ_)ÞH‚ôt€\»’2PŒÆ±iüsPS˜Ýìb/ðx¯âÍ%SƒAƒ>©ç¤_åX¦ô ³JƦ~Qˆ¹MÞûÏÀÉ(ŒUŒ>éާ· 8̪ 8ˆ1¯Ù–z8|ѶÁá,®¨4ORû×=¶9_:q¨}aø\ÞQg?ºÁrS%Á‚æïK÷^&*+žt¬:bíÙN_ŸæR9À8sžðÆXe =‚ÞÑ‚±£ª°Â•-ù#çkLïM€)ƒÕÉN;;϶Eˆ.ÿ~äAŒHb)Ä|§Úúõ3ï><—Ávd‰#õ3-ŸÄÃÄ1+|^Ÿt@M]n9ùˆQѬ#ÿK;HÊa­<@wLj\Œ|þ5ú5À¦…"”5hûbfCbž­ÍR·©ZÚ´‹‘—m_bHeï€÷?GÈ($¡,¼>ƒ‚Á|l.µJÝ ¹¦fQN\ ºÕÕÁ¿©­GÞa 9+gáh³Âpj=E½ C8ÃG0<2‹4y¿]+$N}HÌ}”'³j£+û“P½štSuVb© û^fÉ«OëDƒ_°+;~ŒõN¥Z‚“ͯ/}øA”€õœðt»I¹´ÂLŠuDåñø¯Uýº ÿHÌ%öcÀâPLËFàQH±×&ÑM¦Ýלê)­‹…*†oׄ²9¡ð„€ áÑÊ€\ò g{îui¼ÊÛ–wÂÌÀC²k³gª‚î³cXZÅ;¥ò¿§vcÁ€”Éï1ÈÒßÐìJ‚»ûðI£ÈTZ“Z$¯·ÖVÜýˆBs¥£MãíÛØ ©¢Ù­ªÝ±H#HY!¯Êð £ÚÕÇo gX+{|›ºáÏ7$bè˜&Wq&ˆ–¸#í·¸ü#ƶ²#dô|'Z…‹æw/ñA*J¼¶~ëÙ¦•€7œõ¥ou.¤êâÙöðNöËÇLæzæQ¹ 6{AÅx¯æ„Ò6ÛÆ tÛi™*99Ë÷H '½&3/A4ÑRÍ+ÃÅ=? R®†a_-C‹bÊ“Þúj$ÿi[O;{Øå¾z~ó¡Ø@%ð£•B³ì:—Ñ@ƒ¯Gê" ›zq¦XUn²ª—ʽÑ.è…kàmugð¦È% ô[ôÆ\B±¥êNõqfÇ«sˆ6‹ÜP~þBñ$ç‡þ©ðZH»ùËú´‘ DLÅM“˜0€Ô¡™Ðm󰇇/ÓmÂÙ"ÁÄöš³Å” yTŠ)„"ÁÁMÓjÑîäHF ÇÞ© GØO‚œ¼‹Ž5NˆÂ¦¥uOH²¾i¾Hæ¢ G 7KÿNà°„<”.$ìŒî7éµPIan­9|°¶$ 7ñ#H]M`ˆŠ"^džrŠS 5Ù©ª2;øùñŒSl¿éz¨ î%‡K¦æñ`œ@àĵ6Ý/o.Åp®fÔFU i‚S„xâº[|"ô› ä"^¥E"Ún{U¤;ùøá¾âÜ3míÈjÇ<ö5·Ê8QÂ8SHjþŸ4ˆ"9jŽ m ïÌ_íTZ‡Jzs gªydèÛQ¸ºzŽ¢Ïy¨—ìò`pžt9å9Æ­Ê"’NÃ8O™D>RüâTìymOªP£â¸.˜¶ø½ßuû& k¨\<­X̪Š-D:\!¨œA-3à,¼äVîç~Þžý€oiÅ!X^|è,ÿ ,"v–ßÛ:ö¬üK¨j.+ÌÇ{$Þ"ÿR—™±+QJ©æö!füVþ£•.»Ûu§\b#üŧ•==„+²¬ôX ÓÊx¿VýcwôÄJÅW?úù¢•^ Œ”ºúrîÒ­(¯Ï±[›™/÷¨Ä¶”lŸÜ9‚Æ–J1ØhÄÛ¼ìÃ%§º^a‚¥¸œ¯R¾Z0UÐ 7Y’·ŸGy¯‹û£FOVt'š„M§ð¨®Ñôq˜¥éV}Ùœ,1[ÙYØÞ0I­~¹ô_'oD™…¹x’óA5FÓC.hM@puÈXQ©òEî‰`Tœ`³È L®‰ºíLjð Œr½»…j›„Jl¹-ª¤„hVñãóµf»^|/;'SÆqŠc“ObÐÏ¥.]qÒRŒb­n!Ù5ÀÏ{öÚR”e³vOodí&WO)çI¤ê“rÏN±èˆ›Ì†ðFsχ ~)鿾\™­ÉuR€B›UÿxÍK䩸†H39;€Wøzq&ÊVÕL‚›ñÚëD{^Õ¸ù†çOŒRÔxh®Ý“ÀèÅŽc–Ì€¢Ebšö£šʦ[Ìùi^¿þ{$“VÈ'AÏé s~ãöiôš"¡žY&i߈.Ÿ!Ä/§JO=‘‰½é=۵ǞÖüåÃUÇMJ¹FÞ ¡#£ë…ÉÄýíò‡À¡éœ>ÕO;âzoеŠ#£ö_d ‚»}3”ãý6—ç`é‹8•te/ Uæíõ‘D4 §TAÓíŠ;ÕêÊyä²óöPf÷ð‹wEªÈ(Õ0Ég†‚ öY„4…Y¦°¤º;²f ¾ËyK]Àî~#dYÒQå¬ÄÖ]²ÛËU2#ó– ]ý0IZí–:ÓÔ«질 †>s¿¦4Këû o­½ìêhÈœ £Do´Œòû<%êêÏRs õøÿg“¡\¿€á8+ÜÑQŽ¤Î•r{;¸‹Lé“—=ó5X]žž´‰ŒóbÈ4ëøvÃõK1ÒPvxöæøó©M•¼ Ä”ÂùiJˆRˆ‘ÿ ôû!Že/3û@ù+VOŸçðìöûzäþ‰ßÃÑo?‡uôÏáê?ü=D±ü;%þfáÿCµ ø^}¹ùa2¹®ØÙw‰tMDÇ–‘Bù;¹½à¤FÎÔ²f~­’«•¯c&Iíå W±=œÝÀ k\žˆ;˜×>‰úçáR<ÿK!Û(çõ¿åB5ÌûE©Ÿ]¼£^¦ÓT”ð? 5-/uÝ^B1ÕzöàN€”Ó‹!ÿ`z£{ªæûz» œ;‚¶Kˆg0€|µ•…b‰]ssÅb]–PrçúþÈd–m¹PZ7ÿUËbôâ Í•|ȸµyãÂòVò“*Ûþ©àÉ](CÆÒ™ˆtß ÂH³:È¡A”{Ó0 ¯žûøÕ+Lÿ{L:ÅÑ×û¤C²—²¯ê"—b´yzÁ#+’1Û ¿.XŸUK¯Ù›‰hFÜö€2ßcÔ¼j—D5ç%Þ¤éMߪwÊ¡p30Ñ 1òŽÕ‹EQv0H–AUå€9!å "[†ž¼àndˆ}œÀNS¬i…+¤…Àìü CÂgÊðxë^zÍ^“›im/þ‡¿lu㟼Ê;_令‹èák€|v*P*ߌý0ÚÈømrÄm¤ˆOìK$›ô¥»Å9F4{5®ï|Ø{B5=(fª¥áë¹3×ù篯ƒô&2öýí}Y§ô„5¥•‹Ê꫸¿Ú\>–|ùkH¯Î±­ ®vÑ“Ïä’ÒË¡¯ÍÝ­c¿—éE|®êN›>Ã%†{ÈåÎÑu Gò‹Q6&fÆõæ ²¡ÆðK/rLŸéT-âà”zvÛûEÉ3ä=M`Ma& ˆ5(—å0KúŒ{^Šž<4¢2[ä§þæï;CW4~õA¿ëY˜´<™¢¾¦«q¬ú1É4—÷EN…¯ñhsÜ¥“yÖwÌ&hWÁ³8MGõ/s§›8ãX¼‡6.”¤¬ vËv.y¸é§p^³ùŠÀNä¹VÅ€uCŠ3ø€zK¼Å'†åUW„u·Çÿa† Ý8¥ñEŽHÚw¾ÜlÞ_,^ÞÞ”õ³lþšÅ^uIëx)k€ì›b ´ùiwüœ…—»úÜuÁßARÜÖ8ð4Juæ&¶{9÷îÕÞçh Nî*©’“švÍ“÷õµâ«T¥s¾¥Qó€ùŽ‚CߣMz´§Äq“¼Ò8ÿyøFJ£Œˆ¯ÃÅ~GñI¶|Œˆ¶¶'R=¾"Ö~Çï~D½«že*(vGTp›÷ sxâ 8åsÍb‚ËÀ9W„Äd=°­ÜXWW’ŠðB[ëyŒfw…èPä}¶ëpC ºËohÓWK÷>¸biXuhoL£³Ä5LTê¤ùÉ ú:sŸ<™wÛ‘K”VS_XÞ¼Qh°ÀÆÙœwºRæNø DMäÑW„òk¹ U€Ëáb!lªŸ/Pz$WÈ÷„qE“è40°Ý_høÜÑa [Ç?MóOcÎ ø­imæ|½÷wbÛ1–WŽì&O>änð ê:¹Y…aŸÉàA#æìd@³WI-Dùì0Â0Ã7/þòsÄÕ½)Mˆ˜kÉ}¡±½TQ9M·„%©ep\¨°¾ÁA‡ÖgÌ$^3j* „dßçpã–®nIÁŽªbj’)¼„Ñ.5†p5z¥þÅxÜgez‰-—º€°œÉTºˆÿÝeÿ}­˜zˆDpønG®?~BãÀ) ¸5ô™GM†B|52w·$ ©¬T›‹áÀ3¡ôIU;ÛW ÔÊä$µÒ“¬™rQé3LÄÊ‹wû˜ÒeèeûSÇ\TÇ“Í;QÉUsC`ËøVÄÈ; ×ìrWí,ÚÛ¾d[ç¿.»r«ÞÐÅ;±áïèìQèh"|^ƒ•d¼¯gè Ÿµ…`°¸¿Äˆçû}9’5§§Ó¯ãèß­jÃ;¿Ô»_ýñ¥ñ¢'ôŸ]tùχ,au䶇P`i*fî¶.2Ò¢ÕWÊ èæï@{€Ñ~ÝEÆÀp#RÍÝÙË>ÂÇsÏÜÆÛå3HÑ5Ͻ{,¹r¬Åe‰JëÍk©Š~ òéÕ‚œå3BENÚ„ô'€¾Êvge}Ñö1v¢[Òãó­Ž!µn†Úá¬XPÛ—Ã"ÀÔoEi’Lúv-Æd ¿ÞòbáÛëÁ Ä™F}Yá!/ýÏ.JôÑÅ@KYJÒZé‰Í¹‰Šì/’ÛÛÒþ(7Jé0Mć1cŽi<7QáYêQ§¶D:MÿÛŸ[1^½± eÿtž°R}‹_™Éú—°’g¡M1VàtßÛÃxî<¤Öªë¥0”|žÚ¨†Pý!’ű8l=úp“CÐ ð˜yvhߺXm½NWÓGH:ׯAÑêqwE®¥þGIq$WI¿ÝÂjwX™ßÀ#Ÿ'ÙZíc×Jpå`3LîàõBˆL}õÞ¯äR›ög¦Nvó~m}x¨Sä§6‹æ1 >ü€?/Óßàû§}_'PDÊùöÄAS°݈”Žç¢^[Š6A=½‡û²AyÃ÷±?Ùq3°)1Àó”nZ Rêeƒú›v¬°O5þHÐ ˆBìer²¶ƒùXýþјâ—ÃlÎ8Ì v‘0šó*Ö¹3üPÈ€.9§‡TÓL’É5l&Sù~.&g†o{ÝâlR¸ ÍÿFæ\no ¸4UÂV­ªA&^÷*¨ÆÞ&sRÏ@-ˆ ~'çý!Þ­Ÿ tÔ|ƒM[Ô¼Š¶&ÂŽT# ˜:r™ñ%ܽ Uª¿“xÿÄ `î\’IãÔµˆofbÆ [û@Pس΢ʷJ® )7—>YÈhEmÝu“Ô°¡{,xIÐÿ ¦*9²³mR0®¦sÔùd<Š\œ¤ol’›È¸uQ©|êO"V][×ü­ïž‡ˆ,ås¤LO(Âòzw—æÃ8(N¿YŸäÓ‚éiœÈ Ü|Mg{xÉÖ3º‡Æ³ËŽiZÛ~fƒ´^Ó¤Á" SqB¹³éïë1ù[G [Â8—S dßJìAä\#!/Üt’™a¦@pÖwc’ÀÚÚé§ôã…RÅ1ë_5iX÷xªìŸ³T|U÷pQú™¨ý,Å7·2Ü£ LÖKš9ˆ²¢€tÄ,_ÂsxòÞëøK;hÆß[|ç¨ÞGîzñÙxö‡Ç£ ˜sdÇgƒ¥ø`ôí©®% jû:ÑcDM¸Î]ºÕîÕ„ŠÚúªÞÕðïTîÂ8‘¯9±¤Ûy‚ìÎX{B½7~‡Y“Y. 9÷§Yd < ÒZ>*¿Ýìd¦ªÇ!}†S¹}6ú“q?r’kÁ—2ÚKdð¨ hНVð¨-»CH,%»×Fé—ÆöXÊn ³Íœ±„>îá§IK%:&&]¯Y΂“LÆÁ¢w¾¿¾ÉÞGÒ“pš§zå&Nܬm™ÏâHHåáä­ßl1 wÊ£‡›¯é¶¹a“…vsA÷£âXþžwAo½—’æX ¤Œ’I›º'XQ—–=*>Á5(ç‘|ƒW^!ö)¨¨²ÝÅÂò%ëú¿{;›¼û@ v]ôJáÔŒo¦^hÎ9ûÔžòjN\¼G¸@“¡¼!K$Wëó?ºrFü/Ör`€j3m„ûZLH™µµ`åœà¡ÝëÇPr’Lq´D@ÀêS ž\¿"nW÷Y&>÷ºú ƒqçcñ`¤%Àià}ŸËôÔl›>º°Žn5d³”fl¿3XÁ´¨ôjÓqÏ{vü5¸? §`¤E¦e(DûcÐ /NН<Âø8Ôžk5\ébԆ Å$ º'ƒ“Mf|‘Få¸@Úæ–«q™=?èª=ÒìÓºnãØ½çÞ}6Ͳ?I¤û  ÖOã@ö—X¥ø aµL½ B0Ó€¥ àüyßÄ3Æe+dXÖ­2$L-ÎÍ×4ú°ÝtÞ¶—йѸ´ÕXhâÇ|+ÒŠµ|ïS@ˆYS¿îòx+ü¥ôy¶ úô6€ )É*Èí_Cá”rÝïuÕÒÁu@O§º¦ãþsïLqš y ¸v‾—"Öû€Ô 3Ää„ÈVœ·Ú†g‡+ØãušI'>Ò¨‚hçÐBD]*JÊdÙ^1_'»æ®qç%.f5ª²…ƒ[ê€rC8Ó'ôœÛ v©dvE:}€ÙD=ÜÏű„@Zz®êoÑ’ÌÂĈwc 19‡zØëÓTÑ+Œb~ó.5 ô/6H¤1áݰK'fQÌ_Ä ÃH²‚πغ”æˆu'‰û^šÁ…Z€†jEtßÓ/!6 8Ò©«>¦^ŸÔºåî®Áø+­I‹ÚŠâ÷ѱhKÉ?fvÖ´=nrÖ!Í njv¥8îm’±¸F0 xYjIX¥%/%óÓZÍ’©µŠÙ‹)‹À…7ÍCY(ÿGFº‹aiÎEÈS髃Qx R,q{¤Y¶¢üÄ´ âÊÍŒa‚ŸC’êà)ÐJìf¦V1D6ó•q2-_îž–¬] Àš`ˆ ¶´e£Ý;-š<ÒàGMUSk¹&’MËMàøÃh-ÕPüÙ"ðkÏÊ4€O2°6û rÞnFòƒÖ‡™&ùN)!eH­EuîqÇô³ð¿1ƒ)#o_`eȯFh‡-U$ÿmúmɈœGÃh OýFS2Ÿ í¹Ÿ%5Ðcw âȪ¼•òÁ©ˆ£ï~~ê),rÆ#† £­•„ yȪ0 O3¸(å™Z†Ì ÝmD/Õ'ò~ZìGÑü:Ì#ÉZ“OíbÜîÍ\RÔ½v"u4z6ÓHŒ«iŸúOŒ~®€Kùd—O öâ­ë9˜·îB#S îÉƂ̛î\XhÈÇ<º+\ø¶Òi\à ›DŽUnyÏ^:°«§Ozýyø35§ªt?Jút¹Øê&AŠ’ç!©„LÐ@/õÜ_&ib‹H: RþY²/VsaJwS-,‹®|b^`õˆ/T0Ýöº¸¥|iÆŠ4~1A¬™%žt×-°«³éU•У֘жÂ*„#áQâ]2ùtx!ŽöSh±§]^'ûEÎÍ3tºÏ9,x…WþÏ©œ}xòÙù¡dÒ•é4uÉ!™ßÃUû0otv\öϽlÊë²§ñ4áéD55u Böǯ*”'F[e¨“]RçFŒpÙsÉ&-ñ7óÀ³V©ÌbupVQ ¬â6‡e(i64 º.¾S6‹Ã HrÒ6” Ìô9Uð`3:¨Ò¾¿ËÝQ¢ üõZV»ë‡{´o=T79oYμ¥^Jº ddŸÖäqѵíÒLÆþ ê®ÙjüÀƒ*ëñõÂŽ½MÉðˆ·±Ð{Z%Üy…¡ëH+—Br)­ ضK?YštC *‹ØYRwÛÛ=v‘›ô‰¨„q4#:%ýHß²¡ÕBo}–¼ú²î…Sêñ iíð˜r7—!«æàͨ—vÄO{ܰ¼˜ŸõIÙ·ð/ÿ¡r'¾DÝßBð±ÌÀáVådÑ!O X^ÞTJäð+ÆÃv;Ooéé_kd§¿7§Xæ`BÔZ¶Þ–oƤL°óÒ)÷ [ó+oL£h¿jÏ}¨î§Üõõ“E=—õá\À#Þ#¸Bè¾ "ãD]ÌfþpËLjîU¸­ƒèq%mˆá‹Y‹Óº³ÚêwDWm€ÀMIi•h™Dæ%.íŒ0Òr.úy£FJ·}™Ø–7DÇŒQ ö`Ú´õ™ÍàKœÜX±úër¿¸“õ^{Ÿï¥¯ Eûû-`&”²‡­ž„ssŸ–€„Ad8×ý:ÎÍËdÈÛ·ø uŸ ‡›Srˆ‚ßU B„cõ·ãÑ[y§yÛ3Æž;ú çô_×°ËŽ‘[£mQFÒÙ·«_€T/“ÅâÅ! YΤ :úßx¢‡6“5JQˆ#¸ÕP \ŽK¶ßÇ ï1 ¡kb/¿€ÆêÐòþ°UÒ³¥…×(K¯ý¦öµ°iÇoFÊßÙw;ËŽ],ùDüˆ>$ˆ“ùµ\Þ•e°Ü…Uu Øsâ©TgìïÙ9Y¬TSÔý¾°ÛŒEÜ ;_;ã¢ÔjÊvq»‹Õ=ßò¸z|õó6ôQÀã4õ-dº[˜¾Qæ¬vñ®8¢6žÕHþg\×&>}íJ³÷FgØU§›-¨tÃ)ÞN9Éçü”Ë; ?sâEsh75'Üzë@´sÔn¯CÜ[$«¾ˆ45"³º¶·®m_îk”^ˆ@¢á²PµödyåâþA:“˜š"Hgä8˜c?ÙÊ7eñsë’Ø [£ø7ӥ㞩Bå G2€×À¸˜1S ƒŠ'›©‰˜ÍýÙ­¡”+{²­Æ·öX½õºÜ®u4‡¬‰5hì•Ö·E½ /A½æ†þ M?E걄Áµ£ÌqÌ쮤¼ ìæÓbã%•±©ï®<Æ4F¤݅ú„Р˜¦&äivœ=†m4eòñÕOª#ê, ’ÛBõïéÎ5C¦Ÿ8bµXŸÖþú—/ƒkê{;6-PŠ÷dö¾o_é{臷l;|eKôR²ÞVÁÑöTöËŸÊâ"'ësè˜ÖÝEþå »¼Fcž´È©hÉÂd×^ 1Ã`‚÷¼&(ËÇ>">hh»á\'ÁkÉ77µä·#Õ°OÂM:GDbb]ÍZA«Ø ‰Nqbôb—¿h0*{àõ'ÌÂ.>í¶m ìkÁ”ëfåzËôÕ!&9Í÷«Dq½Ûu‚·ôšRØ«×.Ql ½@ý.P‰‰¹ÊeÓ YÖ}gt$ôÕ‘FÂÙ1þò.Š«ò\>­ »8}>3Or‡6º ZnåU®_Æx]=išš§âr8‚ºc¬9‘L?Ë­&ÀІ:œüœÓ¸Úr¥i»ÍÇN­=†Ç†¬Ã¤u€#OÒNÅ%œî²{RÖ3ÇAS$ZÀœÓÑÖ"Sù ”‹Ç2ÙŠ’û4<©×¾ê½á–N?{:RBCÂÈC»¶õT¿CVȼ«Ì=ÝÙµù¡ÏOy•qõvâUžŸÎÂÉîfô@Ȍԫ|"ºøôÛÍÈ=]k¸zèü\•:Õ4ƒìz)>æÙçx•šÇù…¬}:ë‹©•o¿ü-· hŒEj&Be¶FÞÅîå0ÛÇß@£]5/7ë8Õûç˜~¹,dÕn*]# s£iæq8g!Ô]>Æ.å˜1b›Äêq’ßԫ·½^µu?)šÁ℘8m3®ãò?Æyî€þ@ª-5%ãÓG7_U»þ¥ $3¥FNgD€9N:¸Œ4²^ŒøíWlfËuÐDÖ~.s÷šÒ÷èÏç.b% • ’ÎÒ‡Û6½â°pJh‰…c¬‘¡'E‰Œx½¤ñéEbê„X“v.×XàYâMð&·+Ž)I›™á%„il÷õÔž‘ ¤µµÒp×ä+mê,¿Œm˜]ÎI£Œ—f.X­fÔ/5»ŸîÝùÉSlÍ$°ÖázŠ­Ùuñè?ÊÏýá»°<<4ú? ÿc[JÈ™Óð+ïlÐWݽx¨øÔ‚åt/ùOÇ/K«ÏÐç…”W`§x¬¶-œê;»=oŸ¦€kÑDªYSÙ\%³‘,ùI1a½¸¿çtÕZ»äk…—èøïG™OéŽð«JA:øŽÖc­nËS™´Ö€ˆ†ÈìòôPÜW1EäÐIĶȷ¼ê™äÆu­Bû™EÀ™V=°Þ. ,]Â3ºu¶–`ì<CœÊP ,#V(4P\ÄÓµã‰o]›Ó ¯õFkbé *WŽçàç}Sù¾ZÙ²9üpböÛ›) —&VÄ.…^‹)$}]¢Sܦýw©§vôƒÝ7[f»²¥‹@0ÊÖ§ sånÞÍ[îçPx‚J"É¿b_â"nùéÉ ŽIF±EÞnæVWç2„j•ËÔĺ =æU$ašsë~'l¨:¤ÍY¨¦á&•{Êi1 yçA'ï>šÞ). úhØ, äF«cRæë(»ª2~Åè‘¡»y'žÁw`…£y óÕ3r‡]2Ç2¨e©? VP“Ë¿Jaº¦ðFÑ$ô"ÑÃå ,d-¸WÝ7ôÒŶ0á°? pb‡V/o·°o^#àÞ³­8  OŒ¹5/£Þê6Ò «‘ d·þ?¢¬Pæ‰eœké"÷u%œu€¶ˆd±\9ÅÓ—†FÉi¢ Ë,ºó)¾Cÿ]êž±ÎdŠQ• 1Nâd£<}Ø_S—"Å”¢–4Ðà¹/1 €ùvŽºÌ™¹’)S!ŽÐï¼Zq•Ökç¥×h$ )î3åP›b±F`ôT[­Â¸°ëeù_õÆh޼ïÌó'½>kÉ"lF’:Q¤?0zøÛN戅 z“ЫŽI¶8f€Ésá qˆ>ïÐcÔ¦¨Ü^ëPh^Æþƒ;_ S¼â}(KŒé¸Ã&ŠM¥ùŒ ¬VøÑ“<ÂÈBÆ\ö^3´8ϑۆ57ñ£’«¥¢åHÕÉ÷>µþ—¾Ä1Ñ€P‚¡µÄχý0íhbÝëØÎqІê$9 te—–®VÑÇÑ}Û 0ÌõÎÔ¶§åO`HãÑá±ÌÜ_rzå^§ƒÿ,nÉÙ¨¹h®ú2Žç2'²©\­¥ M«Äk‘××rOs.‘8(™î^»»A²óÃw45`K7?ÖO0³5Cæ#Þ¡vœüêRz‡>Ádçàt“ÓÿFoeÊјøgÉ[•ÅÌÚ,µïZû‹U“L¥±5D:øsŸF“x“}œhx«ýð:($åÄV- ñeY*ÁEŸOƸ‡gÖ,—ؿОúë‰Ã(3A &Ji~‹|âv,JÏìýT0dß2Ä[Y¥nâø‰Sq¢‰Â{gÊD/ñÄ2!݆VŸðþ¶T‹C˜íôòHE2ýKêtë»_f\ñ—¹2<*ùIEœK8¿¸,x!a­BÍö=—CÖ3L;ÿ&©ÕÊÔÃ@YCD’ü)9C®¯¹L’ã4¬°­i=/@Zcb#dßÙQBÍéläc!,ߪ”íñ[ãÔˆä Èw©» ëû§7:ë7´ØfñÑ; ›üYO~ëÚ³EQ÷…ÛsQk‹~bÈ«çL¡ãcéY'‹bXi}@®™B½È3i§œŽ'!þÐñ {3ø4Rî?Š@ lêßÙÔñ’ÄJÖg 𧮯6‚|o—#ó‹á+#t…•h‡ÏfU70ÕRŠÚ ö ûuv0j®%^ÊVýÐ!&i"Œ3õÌ÷ÀÓ 4T×=f+ÒÓ;ªª+bßd‡ûˆ§k[•8&¿߬.¿åõxQ0[)\H¯, {5 ŠAØ2zšw¯ðœJòÁ¾o“|;ëž’Õݵ/ŒýW°à¬I|‹†·&må…ÿeÇó%%¶ÂÎiþ§„Ó×h)öS1÷QÖ•„家Ǥ`ͤ£ã«:ÊP|K›Ô}ú<âËŽÃ^VàŽCBðpá^q™b„¸$£‚ÖÆúC‡%7±k_õ ~zô)¹(ë÷8³QÙ!šÛ;ÀH ß Ã÷Ÿã9â[AÿT$ Âß׳_PAo½LÇ)†«¯S lú‹dà‘£pÿy5I9ƒÓV° ¾}Öû£¤8ÒäLy'7ŸoA£ÅLÀÛ—Ó3­9ôÖÑBL00HÅÁ»Á}QDoÖö:œPæTתæKÙ3ÿ.Ágxj¡U¬^›nel"0Ä K*YRau7ï5®ò×s±lMÃú ßµn@Oæ¡/,´–Öé¼â®qÁ}©–U`ÔNðÒÁjoèas¹\N*“’I؉_^T£Ü-mÂæå)Ù ùÈ®ÙRê¾)¡‡dËF:1úŸÐЏnèÃ\ ý…ÔVlÊÃÀ ¯ìYòˆÁ*:¯†[ `@Ùÿ(¥ŸýÔÕ¯jO‡¢ÉÑòk'Ñá7¨b#Â*S;YN»l6勤8²@ÜÝÒ|!¾èÏAïŽ?”m^çÝéú™¸Ñ Zþ^*ŠÐ—^rì†õéøØ- ÏÒçñ^ÊPá/–&¶èvÑJÛ¨oÆ`Ž4&R†Ü*ÓÛ_ŠâK/nžbÖ®U€=+?®) ˜™]¤±«}èñ/²]ŸV§Šý ÷ØZÅgÝÚ< s´ÿ,çšT„!OȪoÆl•`Å0×;h:~£í_+Vc ‰Ëi¢ªA®Eæð † Ô ”ÏBc‹™/O+±qÏÏ”Ƚý‡âþ¢š¼ª½\´g‚Å¥'öÖýtÑ«såŽyö17¦m÷¨„Ñnƒû¬Â­Tn·ºCý±/©´v~  lÔ Ò@„;þ‹,åŽÀ€´õÚq]±¥¿£5}.;vëÿ Cªí~7W¨h Ùéz‘ σ茔/ÙN¸/GI{ØèyÕgPy4¯…$ò7Õ.NW!E&™ªWwc±é…êÁ¬C4µQÈô@…,Œ«Æ<õ²96|s»ZQ(‘{”îLž¦”(Ûy<9óêí¶qðI±=÷¯ðò,S³EWŽóýü_Æ±Š¯Iĸ70cÉý@×ôÑXm•‘þ— rPîëºv~P=@ú|Øå#ª2ßën,”èj#ýú rq0½àBØ­€((þÑÞ6uÐþ£Îð+«/q22;5âlIw ;¦¸Ù±kÇqý †ôþœD×’ˆÁ´ã‰µÜr-È3±tùK KtTŽ-Ó #jHVþ{É‘’ÌRaÅ”¶2_³j/g¼q tÇ\]$Þ›?X‡gŸ>4b\„<ˆ†¡ÖÙ ¼;|O.Akˆ>ðÌn²<êl•kghj$µòñ DÇv®+¤¿mšTˆv: µüÜš&Êþ~,Yè#&!N’ô=zeб=Õ÷Nv š ø"™Àž¼[†Ÿà²~À„Œ2ŽrÌð¨=…D1Meh‡ ðÞ"j€ë´£b6åC¨MCˆÇ€IöÊá³Sþš;Î&rVÏÂÑg„àÔ{ ‹z@†q†Ž`yžFZ×X3ìóv|©Yím=p¯|O»ÁÇ.ãw¢€¿Í,²?}Å^,àƒýí÷'$Ô,3ÒƒúËcô„BnäŠÍ6ýÖÊ@xèC¼¾•Ž3Ù¾&jšøáV¿Y¹1‘ï¿C~A.™yñzŸÎŠ3Lo‹žè7i–ŸÞóÞIÏá#+E+çÔßKý¿¾ˆ«#g[ɉœn)´+ïÈh-È©{9¤ùzi×—¿ÓÇÃF½¾Õ“#Õ åÇ<Ãþäµ1¤|"VÜa”ƒíª<™‡ÎŒ$Á™ejâ+…6µê„b›->©ƒ`¯ÿ*/xš( Ú:ñ—HêEÀc`³j±@ÕÛqŒN½6áß2º|_rG"7Ï0VëBù‚Ž-ýÊÅáØc? orK:Fm‚/™ã®q<=Õ[Ã<º'ýŽõ´¼0JgÖ¨«Èän™‡ðz¹3nçqéé¿‚RècÏw䤟 c.#Æ6š9¤:rƆ³‰ßàË5EdÀrp9[ÒA¬ãD5"{Õ"Šk¯ãÃ[®rþ¨ &je~!„3óü›ã02Z….fà™°/ðê #÷²B­ }³ Ø­gÓò%þvaIÕÂo;ËË"€¹ëDÓ¤K¸^xŸÛ@®³äÖnï\¸Äçû¥4ï˜êóA^/·PÕªIj·×´Å–¬3ø7Q’ž®ƒ ðyP÷<òtm¨Š³[ýŠ~òy Júðð‘Ì]Öøúú[–ñ÷º`Ù‚ªÈB›3-x%( ’Ϋ¶ˆ:ƒ(·â"÷õcø À×˜Ž…ÁìÞH¥Þʆ0noŠ-D:\!¨œA-3à,¼äVîç~Þžý€oiÅ!X^|è,ÿ ,"ZÖt|%?xP™Øß•ñ˜ý©‹ð\Áó¤e¹…CK‘Å¥Ÿê0¶â¬Æ¼¾ÙBù–Úñ®,.†skµ!3NâDÓ¾'£ ¯-1ž­ê„A©¿×ƒgC²èIß×F,¡µšÝS!†¡:‡8eÕe¬¤:b½$MJ¾1î;ŒXâþòrlßèžDa¥¿ð%ðŠ¼¢©ØœEQbA/ÁÂÛ7ûy›e]þ&’ÕÕ»…«œˆòEž®Üiæ,Ä®e€mÁ3íÛ(´€syå[_^¨P2±R/®ã¢=Cƒôª}úŒ–z°Ù²kfC]—6Qœ™çÿ}º‡ŠTyõuàcûÝ‘áòöìÛ‘ªêÛ¿?c­!!•oø±÷^4X—eðƒÓ0E!;(‹ 5ÓwY×ÀÆëÉo*߸5½:r& 6]¾Žç¹A„ha{mº*á(,Ý&û•Ù’Ø$DV¡»€à_©eð ñ©È3.XUˆb6MŒ¹´÷gUÐêÍ-µû a™•45ˆ~SRê‰ —N‘ÚØð MØ8g³…„ú»æ`­£gñ,Ê0ŸÒç(%×5±º7ŸÞîíêá“ M Iâ¬tE\b >ÔíùŒ^!ìô{ù†Ý$ŠvéU.MÕ‘^ĵK>Àüêåµ@T „ÖÌ#Å],VAsØ€0€ö„<bžÃáfâN¯ß(_7ÙHWÇ ¿Sq)ãQ(ón/—žÌ;#詆{:˜Œ·Â‹±u"~ËŽg -‚ªEÑ Ô¬I÷û—¶¨Eî°îßÕåŰ üA¹ØÖ>æE:ÆU̿Ϲ[œ¥¤:qïfÌlK#$¯à¼?}:ÖÅÉãiU ¤Ÿ‹þL©ïýÈÑëñ[+„±¹;kýí6ùÌÄË( é‡dй;Uôî,÷^J7X(/ú5Z}Өݿàð¢ÓšÕ:U……i륙 V›ölýB1Ùœ&×åiLœ¹ï™¨˜ÒÃ.™™ÌO·¨#l¦Úmfø?ަ">æ/#«îqè@ñ£V\€SqJΉ¬szU S¨š¨yÕ2ýÜùµªV¡(‚°sçðìþûzéþúÿ|Ùü;ªþªÿ¤—ðôyÇðì—øu—ü;0þ„€ø]}Ê{¸ýÞZ³Í8hw´ ¯˜¥¿ö›¶Õæ±l¸¬ä1;{‘‹ž˜ª¿Ã䪰ãR«ö—aw‰le¢Ú ¯r_£‰è·à–øð:Ì„E9³xÈüÎLk "üÃk‰¸Ÿ`†ðÕÃ-êûˆ0o`^ñ0V9DHñ€û#PÌ5¿uÆjØhúíÜZ^Ý•ŠGJFæQÇNëœɆ&¿‡Äý_  Ê†2cùÐHÁ>Hix&È<›½ ­<›å¤½Ö±é1z‹Í@µ»æ¾±ØU™Ï” B8qnÀÅ`.ªf„u©û1ÈÝšÆÞ{¯œhŽC'œ³X²È\–|ÈЛ&2jÀ©#)ÀÅå4·²É ]Äà>B¾r¹ÐÎÐç^eƒ¿Äú—€ÍRè…"|®†Ôàǟʸx‘W#T½$ÖÒ‘^-ªÇ+8~nÿoë„®aÖÀp ®—9·8P‚Y_ 7‡:£ 2oê [ÆHç„¶tl—©4£ÉJ“IlÖƒ¿= h3æÒ¯ðÜ|@(µKå,¿1è‚»Ld©ót®„·có^‚–T””YvoƸ¬ŽŒhök]Þù°ö„jz>PÍUKÃ×rg¯óÍü±ŒJŽÊZê¸s(®~xBÚæã„¶±Æ=šKï}Ùç\×= u¦ÏÐû-¡^Í™j¼¤;È©Uo*1 ¢¤ð-®c$ÎfxlEÏ’ujG¶QO :½c…‡âRq^™è~#,¦•#L…rÓ'mæý0áá;í„`4``Z#n•üÛd\ÇÇ¥ß ™"¦™FU;È cõaQO¤oMô¡Í‰m¸ò¼²Ñ5ÞiÜúpOˆøtRQöz[7”sÞV²|§{~Kè€Ó&ÝEW5¥,¦È…û(°ÊîqôSF:©5Ï74î Ö1X Ü—*ذ®¨qFp?PC©cw˜£dðܪ«BÿH¼­úûWún’¾•Ñ&Ú^i/X•¹Vnö^Ì ùt*ñæû+Ð#„@^ÿ/,Ü‚¸1ՋѬS8K½œP*Lk"ÄÀæBKîðð˜…gz hV3ÿrçh Nî*©’“švÍ“öã_Âþ/G¬F#‹éšU‚i3¦ò€î@%ò ¢åm|prq„ùG#>®hâTM–HSev¯ì<ÍË÷ã]EdKqX¾¸L€ªGÇ#ý?«ýLÐ9Œ¶¿<:ØC@äôF¥T[qâ­MiϺmáÜ7Pß‘šýƒãtˆÅüí¯ZÙê+ãÛ†¤{øm«SI(N6”Lê™YâÙÒjû®êùõ×÷ctüáÁÛêONžËÊì"‘ ]‡4§ `w$sxi& ¼<÷PAe„÷( G  °‹zʃèâÊuåqÏR¹ä:—d\š¡bÉ&ªßc #NöL}Ó:ÌcÉÆ®d ÷´Ž¶ó>^‹û»±tÞØ^™ûèÜÐdZ¹~»‘—¬“MÈ6íJp‰Ž½™:v2løhø_¤¥”°“ø#`ðhÙ‘Yb|óœu¯–åç¾Ô™4Ò=/½¥fió> ¿é`3ñHeÚcöãS5‚(Ìɸa¢ú–†A@&z]VG§ òD¸ÖÀÖAê—øKâÁ!m&Ñ.µU0ÆJ&[Ö²!Ä!‰gým ¿Û@æ 0ì™ÖÒE"Ï=L¢£këY}^,.ß^gŸ¼ð¯Ý`-æÓåçØ3Âõ0åÓICmxÃ2íWÍ(/ì%éx@ÊÁ.£|¹íDîâ/ A-|•$ƪ€úý5~àr·ÿÿÿÿf–y9-ME‘´T«Çà¶Æ«V´BOôñìÛ çlü˜ŠËd3œ/îfÛ‡ªsÄr^£Çh`\i ŽÓ -½hrUó²CÎÉcÁ䄞wL‘Ƭò™Y»‚qû§” 8|Ï4‹ pƒ×ÀìƒhhQcH‚³:ÊݯÜ^î¡øauë׋–™qTÖUñ¸ÉPØqR¨á¿ESô‘\ÑýZ‚ XÄ«in?„Pwø PÝqâ¼ÇïžDD‹Â9y³ÐÁù¨ë)++ ­?Ó”7ÅQØPÎï%ióöUo2ΟÐW¬„(ç7±6WBL9 üR±3}Á‡6ôæÊî'Pàö>Ðb£¦ã·¿Ë̵ÉcX}?Ûpbñ¦j‹û#q¼” 9r,=¡ÈÕ9&€˜æ,…Öi—p‡Aܨm©/Ã:4dÜý_éÎM’ɸ©=ÎÎCòâÛ\U³¯e)ØP â¥À¼=Q°£]¤ú PìF (‚S7Z;FÎò¯iy8Àµ×HŒ7¨måuRà1 “†såÀñ°gÌ35ÞùLÃe¨¤'â!ï¬ÊÌ×IÇâ~ùɹ$=Y@8ÚÅOFïKSÃk¶bö+¾ÿ4ø|$\¹‰†®ÛëìGU"E¤`sî·€¾ÀÖ)‘ó$WÎ>;‘ÔWº¨xª¹†yÑžà8—±YŸóïÆYÛÎ~˜Ø›ÚéCÈp,X:ºùø-†Åšü”©%ÃuiÉ}ÂäKµÿé¯â¸Àã™­ig”Ù*†·âÎ,ו¤1‘—ËM_‡RkN0Â]YÃ9M)z)“¦YƒiÎA«>k'9 d$ žU<ÄB®&u]ª‘&³]J°M–æ°ýDTáfÂM§‘LR:¡ÅZÒ˜ý`ilNTw­ô„Yçò¢cb†Ï#HÅYø§;äús·LÏýE( “Z¼$žFƒÿ&šíh™Ûâ0)þ6³4¨ÄÕmYhÝDœ½BàîÜæ5ÕÀw$1ýÖ‚Äã&Ò¢ð"ô½ÃaÛ Ž¸š”’èøQÀÖ‡²WÅc~%ûGJ׃xu lEAà%ùb†âŠùÔ“fæb²ËT£i.9t1„x®A ¤©•£‚ߨi¨¼0k쑾³ÔkØö=Iš«Ž8ðÀ˜rÌ©ÄÅIH•.ÑR¼XÆn«_©-"}ªD¾ÞIS-¿SQ$9šJNYíÁ ž.ž%~JFç'?Oª-Zìÿ„·a{ˆ0kÕŒ|D€mùÁ¾#[^ÑFÈ5Èw}ÇÝÏSk„׬ÝÕ@ð…2{+hŽx{áaþ"¬Ê˜Ür÷b+êÜÂ’ñ·zv•´(nûŸãŽ+ˆâp½+×~"MD _’›,‹TVt=û†ö懣 ¤–ÚV{o{¯ç’ïͶî@J›¸fùŽ1Z²É>Ò"_‹÷útÔ|1b ‡Ä¼7†\!²ÎQiËXxb•ød.€!¹7‚2zzý­”ñõÞímº8•¾æñ%ÕÄ `î\’IãÔµˆofbÆ [û@Pس΢ʷJ® )7´ w¡ý‡¥¯Ó–UÆãŸ$O'd4ȸà£õI²(!ð$§€v „îÅgÙ€Êßx?µ!h>äú“È•—VçuÞ–™ŸNþ: B`³ÛíËLš¸XF1L8õk'ÌÒ}ò›Ž0¥Ûui,”kì¦uD}±;„b˜eâûq¥PeV´2ä³PdŽ ‘1@§]4 Œvy^£E”H—“Û¾Ù9]†/ÙGÐe·”ÐaÞãìùŒkë…:aB@[‹­qœçÚ¹ä[?ØÅ²‰Ìè|u NÏl…»2bÆÆaÔ`¦¸Û^G½7[›ñËõnù‹xœ!Ý$˜׆¾ÿ[I õïԬ²By¥ÿ{|,ű#2–Ô`=¹7L:lìw®Ê]‹Â"5À¿Ö#?Ì‘œ»o(sÓtFGñÖe´WXÔº?²~§uÙ¢‚Ц™.âîSá²<ãªY^Rz:p¨øbGÕž;ù}ôeá™%ßÓds w|£¼“¢'×ù¼õ8ñç¢n\¡ãžÔmv$Šd¶È{a|T)+Ø(¼Ý5Å´kȱùµ:|ÆŸFG£Ó\šB zÂpš X.,‹ú°£'ÖbDŠ‚ùžÚ¥Î mïÞ€ÎLBʘÿ;Éà¯ò—Ñæ×=z$#coÁGî7–ml'8=Ýg€=Õ7óŸzcŒÐkÈm÷ô¸øsFlÉý£nÔê‹(-Œ~Eíž3« †P÷™LúôÅéçÑ­Àõ’neƒt8U‡Tú,ªSƒ÷µf`ìa“YAv|O¢R¢³ƒµºÎÇø;Î5¬¤ÛÐC_[¿Ñ’ÌÂĈw])4ß>Ûœ)'ÑsÂÜ:÷HŒŸh‘×X”D὚îê3JìaãÌ÷°§lI=“ ©¾fò¿ëI8/g­X¶an²[ä¤ü®æÒ¹b)R„aê‰ ʤÕ@Âõõ#Ä­îÑìx7lJ”ú@ÒšoBÍYÉ«g÷1ãÖ,ó±KGPKÄå.Vû­¯à䂹ß]e\yåÛ6JxvëøsåA CKpì©-ÕG%Ûi†d'|%[PäeK‹U#³`O±s\·~>«X4gpچϻÆmµ‘æ.»HÚŸóô žÎ.Q‡øžÉñ…¨Qƒ2$®‚DµÎžöÅ7mVw9êF2²N§S±Æ?ZèÚy{À†HK VKùC’icˆÎQ‰P½'ª0©Kï,o‚&î,‡ÅaÓ^é · ” éY±vJ`˜<ŠDèê›K@¸)Ò†5ÈQÐëíDÛrǼ”ðO×_>Mnr}ñ¶&æG™^Àšëe䆥ÇÈÃÈ„M'^´Ò#*Ú@çþ£Sã« þY%ÓÁ‚}¸«zÎf-ûˆÔÈ;²@±§`³&ù÷üŸ—§S·=Œöo4q’Ÿ™¯$8=£ÜÓÍqRïó?Ûö4CГ®¯0f~ø ±ÁæN+I’Þjè¼ x^PÊÏ;³™‰}ŸdDˆö²Üù„‡&£Ô㎠zrÐÝj9Y@0A½ž†Š>Ê¢Ò!UDÊCÔ¯8ÑFÂF(5‚Ó$³Îšå¶v}*² :zÓöØEP„|*uÍ.äë@B´!Ѳ-˘´²ma¶“c@Ë¢ëå3h¼2‡-#iJ ÏC•_3ª+ëü±MÑU ŸÏU¥k¾¸w»A–ñSÕ@#p ƒ–õœëÊUä« ÆFIýnG^Ý$ÌVú™%ÔÖ òzŸHf†¦}êM/IhQ䡿ï0o¡PÄK5ÉìÝ«µž»V ÀÇÕY'”þúsó˜ØYRwÛÛ[OªLe9Ý=¥\ž­›óÐÕŠ¨ÍqÒüºuëT™ÜÅÂ…ÿ|ªí?Qü¨³&–Ï~ù7+&l†ËÙLrC¹-`í-}Í..¡AP­ÊÈ-w8TÑð°Fˆ‹!U­§KËÄš (zóZG â¦í:wWnXËqvèás¹ï›‡tR*¶h}O‘ëVÇ"J±/¹møTJø —ïS_qÁæ–Vè¬Q‡R4>0m“ü}<‘xŽáo×^pƺÑíµ©2Xõu¸™¬‰ÏbíÁr'XN/ë§ÝØåO”©¡%2äR^ðÑ)!Zf·†B¼T Î›·“„Àgº0ù”~§V­ç®¾ãÄ–?ÅZüåÌšíá85ËwݦfÃÂsòqB"¶eÞdÄ`S¯\£†d.«qxlì­u›cœ>M,éYÒÂë”%×þÓ{Z‡X4ã·£eoì»åÇ.–|΢~DDk æq­@–¥##Zfä šÕS¸ ö6’ÔÆ&H4ø-Äj­_0$øÁJÛMßS´ÚS íËˆÈæ:nÂs›¢¥²Åb´ 8 ˜mN¦R´.õöùã][£D@¸û·$rç r_Ý0Êw“Îryÿ™gbCa§î|H¢nmæ¤û]hŽzÕè{‹d€bãÕwц¤VP12‰/Ty›ŠõßLk£ÛJíéy$¨6ÁM7°žÛ*"{äì¸äþ¡UM„3ŠG|÷¢eG_éÈËdÆ~¥#Ól¹j{ô¼ï$?s–’¹‘öë³»º€2Ù}1ðkÁ‘Û"¦ (Nz\’Ë-^úù™:御Ê1ÎÞ Åá7{Xâ߬v#nή̞º]™Ín¯¦7„Áµ£ÌqÌ쮤¢=4Ñ¢®í'äüÉ%VIcBg,4(&(Á§ã­Á†m4eòñÕPÚj4ùÃÚÒþ€3è¾½?RD@ì¢YØí8§°¯aUt ¹T æÈäŸ;‚·ó?u!“‚‡ˆG´Æ„ÌÂt䮋ý\…ä±¹V5Ï+ô›"³/‰úñ ý>R4ÖÊ‘va´ùìœÜoW}ÌÕ' s q†¬Éºi}鳯–nרnÿo¡È˜ß¾žN<!H0Û„ˆþÏ’”o ]@ñu\çνš‹u-I‹iOö2ÐXèý¹š„Îçoî“€Ã쪥ì§™*`¦Ô›-/äéF¥}žT—?CxñZ¦Ž1ìx0y"Û_\nêk'nåO«}= ùw»‹Ûˆ±a]°û”Œ›Ns¦³¹•\õÕOÙärUx¼sî˜#™@ج¨{Ë¥‚ãOrmø˜‰ŽÙÏ=Vrs<ý YËu ù€¬L Èžj; ém¹ˆ”bŸhpa:B ¦Ü7cHÞVïÙR¾ëyÙF|L·È°`Z.±ñ^<§g6äx5í×+&&XÄŽfRCÆsmuÀèy1¹0ˆ®Ò|Û¾Cþg±ÌÙid™õàb‰qN²÷ _úÈ%÷¹²QGrÑm>-ñÜÒ~ñH’oØá8¶@2öÅM |5覈€ƒ4ÚÞÙJüÊÁÃ*§>„ßÊ<µ%Lük÷+ýÀæoiÙ²$Û]†N=2ƒ‘ø‹ò÷meª€mÏ㤣‚#o­ØË@qRÌþÃQ8¥hëÈÂ[6ÉÇ¿ÀêŠÿO8=]”•ÝmS6§ý*ûèÈ´jÛÚc—¶AüÖXs^Ì>?Ì*¯€<Û´=då#ª'Uª>¼pé§ä~½ÍÒ.œádCS˜ ²xè’ý‰‘ÍÑ%T³ºFk\¤ÛݧvD骆lP Ï5Æ¿8̰3r*ðƒl‘Cëæë–É’:º¿Š™pÚ• »‚v O›8nøÏ¢mçWf+²¨µ¤EºG ‡•œszklë+Ò™™B’FÍʧ_-:OƒãOÌ „äÙ]<úÈÈ,QØäÃͩ 7L-/Y``¬"`®‡)üPè‘ɸÖ/¾– ª­Àr]Š6±Wfÿ3–ð˜ÁHAo¬ÐÓßÛuÌjÊ÷Pa Š‘¼aS]ŽÚÖŒÞê|ÖåVÛà å{#ŸÁÇ.¡3Æ€ÙæÊê‹ü»B\ º¶ï±UÎuÑûÙ;ØÁ¶æü5(CJϯiP†ºíãoSñAPO[¢:ãáÃqû^†îÊöˆËß €¤4úºòû)²år¢aTqk¡·¯p]~|žV† Ú:3N9¡±×ˆy† S+Ð "ˆ5¨iZúº×ì°¤¦œm­˜‚E[A×NÈ-o ù4m²ÍƒL,FÕèQ†óÁ^‡ï}'2Ì’øy»œ¡þ%k€þ^^ƒ.;±0,zoåÆ^6_—°‚¤‡PßB‹t×!ºž÷¨o z‹g!7Ëùf}Jóv#€<´» |¡¡mðì¤ñ›Ú0 S´e»¨R—ÃÊÜÑÚÀÌÓâ#B&讼,pïW7"pˆxÁ„++¸×©`8¯TÚÿ?dËŽWÅÆ«‘;§CŽv\ê(† ïÖ—{k)±¢‘²€ £ÿl$&¶^ .Ú¡†ľ0/•_’T¦…`£Éj/Aç¹1²vj·“lX}ªGáÌ#þs´É‹¸90ï}€? Èê¬óÖ®H³4PÉAv„”ZÔp÷ì#b ‘Pkÿ[mËœº¿å#´;ù¹Ý@Þï‰Øý–H Ͼ~é³aû[ÏdRHTÞÅÁÞ³€ ¸£ÿÚ=89G{ø> ’*soÖîè8xžWÙ–cÅrÖŠô®¥4@ÁïÃÅDË¿¿° p+Sé, Ѻ1ßžÐ+¡t»ßB0áVI礤™ nd÷ÛïÎ!·Ï÷kÝ© ¤ëäXÜí×ã=õÚ1ÞòŒ,5›p>›¢¡{f"Tú•¾…æ’Ûø·5"¦©%xÏÈæTzhѽòö…k^Ü ŒöÊŸ£MJp´øô ø¥¬tÑ탛5|Óߊ-41œÔרG÷/$IþŠ59…‡À[[Í…R“wCûz8o’LŸ@œ̳|˜îÖóæÝ®ÞÕ†*FF•—VN1UµA<Û ½È0Úýú$uþIÛ¤mÜ)âmzd|âöÔŽƒ ­±õ¦è> HG%‡^‡&Å‹?åÁV,¿-QÍ­åàK!û"a‘—ñrmŒsÚ7bL–#n°’÷](¾P¶&ÈwE?@‚%ê r¡¾0±Bf&\’*u ßs¿6yF4±¼ã<ÂÌÕ˜zˆiz®™Y4;møI±Ã™.÷@\ ]d8]SÕ8»oí ÏŒÕqcó%¸rϹ y‚>ó¬»R$¹E/G"\V¿Ã5D! ÒbK¦X¤o ìŽØ‹fqeÆ‚ À*Ž@°“Lþ}ÔvhÒf½VБqEHÎ$]NÔ3³¨ÿ!Þæ­ö*’®Éêj¹nŒ¹”—V* …-/ø¤-ó‰nŒÔ…ÇÓB·¼WßÊMᎅäp=ž*]U}v+$@ÌáC®©Í'»Þœ ¬ÝÌÈÓ²£“Í”lE‘itÏR\¦ìßmSyØ‚EgÀ÷Õf’—Çʦ=ÀôÂQݬ•æ?ýÛÑ9{dÑ®J>N8ú:Á–ß7WÙ"»ÿI¤B6ÇÄ/f1ØsšÉ(¯A»ïá§:ÑïˆÙé– ”&ª")$ñ,ÓÑ6@xã\;øïÀ.øl­QØpã9½¾·ƒåæ8·MFßxW¢F)-‰åÓ­¶Õt §Û*»^Pêh¯:ŸX´ôY’BÍ)ÕËj¢ÄL¥›IE”Ê­;U¡M6ïËœU÷6ÒŒ*SD˜~ž3¯žžFMDÒ M7Ô@Œç2 ˜kœ¥`‡¾è®mä,¨v Óî]žÁS{wLòm({h‘´ †jnÎ~XÆl#ÅtyÇ&EÚˆzeÑ¿V¦‰¦² µtǨkz"Ä@- È~¢¢†rÔD‰*_”3è¯äY"mH“¬RèkTÊ@oµ2ʬ‰Þ1ÏÝ`(>(ƒŸ·Ìó×CÌ!óÐÖț˒}2×W0$YfšÜá¬æ—˜rÑhz—–ÂÐ7›‘¾£BöÅŒçÆâ¹ŽZó¹ÅQ½o.î?=[-5œÖŠÎÉòÚ6ßÞ±|³…B’Ýñupy- ½Ä_ç&FA½»¤øC}Ñž‚5ß(ڽϻÓõ3q¢ñâ5c×{HÝÝÜC…ny¯2  +ˆ)úR#KRÇ S¸)~ûš”i+ÎÓC‡FÍhµoTEÿ½ý‰1jðO]+pçaò}¿hßœP 3B‹Ð;þÓ»–Mþû¹5)¯ÜÊ×tA<œð©ï]93Ð’ÞäÃcë@ í=Û·! F1ø¶†yÒ±Á꼜i%Ph©’×÷sÕ_i¹…nTi‹ùÛbè6Û®ƒ`ÓE])Mͨ®lCœÃã\ønƒßakžCwj@òÎÓýg8Ò õ&&hÜmE/X„-·ˆζw:¿Gb„OhøD¾G‡ÂŽæ ™hïÿ_†MwÑÈ$ ²Î{N„¦Œâþ¢š¼ª½\´AdBœ0"V{ðu±¢íòðCæŒìèw¼k¨M@ejYä¯zÙRÅWâàxÓz§ß[ÈT蕌œÜO0,˼ŠÊååb†•Û’»ÐXW´%:²µ˜õ‡-q®ÓíêX$”m, Ðx²Ïÿ,»/W¬Ñq ö¾ã‘ošíŠt$úúጾZ÷ø=!¿6BÇŸH,Íôñ{ƒ³¹MG»™QÚÛ¸$/ð'o·ùF°8DÇ·¨“v±´Îôؘ=\”ã³¼ûdX‚ðQx»ßÐRCÄ8»/¹íùR•ce®†8,#^)éôþ,tP‹2ÿ$Ô‰F‹ 󭼟vñ¸à Åü ÃâMS+Ž&¤q+uŒÕÑ—]EÇÛL×ćqº¡í_eOÖ—l«%ÛÒ[¬TaJ³òÄô€ ­÷ÅÍç– ’cœW—â—3,N “ˆ‚Mu@0oêkQ÷˜BÎJÙøZ,ðœdoHÎ0ÑÌ•öÔ£^Š¢ýí!ÊÅ[Ä%[Mʱ¢™ÝíÙZät»ÑaHš²¬H‹öóc ‚t'‡ÙbÆÒ#+.¨šw‚à,ó=•e²èuõìϸ¸Þ&ªGNÌpug"Àli¦*8–%§á¬ß×- >˜u˜ J·°*…až8GA®š['1'Yé }ŸÙB‡ž> 6òŒx×:t tA¥‘^rµE–ÅÖ•-„€Òµ;茹«†¡wÖ¡ŠpáR¶¨% ˆ£ð5T‘ Ù½œlípâS¾úRÙ{$$ðÍ^)z¿Ì#"t0°JDÿƒ{¤À¦³a¶¢N'¾í(>ÉFÔnQÙmÈ2b`»@Ti]±Ù¸Ü<¢¡ûvN¥82¼:o ËW·jyC¨g?g‘`Yšf§>ù»B{^(©àã E”b’; ï8'ýL1‰üVE3‹dBv²¸wiDd]x0†O/¼ é½së-n§Âï”9]Â~RÊ,p~Ý£Ý,fçu:76š„ñêÖŒw#[_Q:Ènñ;Ê÷Æï&Ì?_oE.šñK`$›—0ĩŸ‡ù›&Ÿ‰K–Òìb™¸¾|îâèÁíI»Ÿõq‹28 ݱ§çNÁ„¦‚t3Šoôí¹>ôt[CoÅ@Ð/÷Bž¾îçyìq"–k:ï=€HÑú“=r`0 Y[¶½Ô>ßK›ÐÅÏénÒLÕ5ÉHb$¼Rð. jšå‚!‰Vºú¨c‹Ï½êo~Qhh:’‡>ôÜi`útÉ,¥8âP[ÔÁhÉ?w¸‰ä49~”³ÒMñt‚Yv¨dYÅ‘2óoÝWJ°$sÏÿCy„¦î±ŸSl-ê=U|÷@rSȪ¨ô5ú')!$YÌÎOvçžNµT€ƒƒÜxãÄehMº!švCC‚;gbIÒì¬+d„éЭ3äBµ8¹; î>¤\OSÎ4p ê‰ï|c€‰ëøÐôÜwµ6Š,³Io À¤ÊP[ò2—£Ç'ºZ¡oòÈóZú³DÈÄq^pêqEueüJÂ@‚¢·Ä?x›ëÄ?¦94Д…Âä«_Þ—IìÒbh6eåéñèëÈï•%þr!¸káqГòcC tv‘8öÓà2ʬÂÕõ~;¹3HåXxe‚Ãò&8*ëñÎküc <ÈE]x‚Õøö›Ñ?.§þ k… ©] >â{ÑshÖB„vÜá³ðqR‰ûgCho®mè´†Ç:9îÐµŽ¯p°Žß^©„¶Fµð.„ZüÌO”„ÖX®˜B¿Êz’½6±,:u³,7]U ²3„º@âö˜ÿeéܿ;> ÌÃ=fxŒ½Y”÷—[6©ê7É ©ð^3Ézd¹ËƒeI{ë^ï; ½#ãÎ6E@iB:àÊ£Ýͼ%k£ê–Mb¦Ö¡UÑî’‡*‘aUÃ^Þ®Na¯¨ýEGÈ@`F°½È:W¶qFnÏTàwblzkgââyq¾ë­ʿ°‘ß& ¢M€†Þ\ Ë.o¡"bç¹áFhK€¨é.žÑaߥ€·À,&) cuh4Úk¤ùo‹ŠQroUð»üqr+KâI7¼ÒGX äØÈÐ`ós­‚¦óH9ÿ&Òüì1gÔ®j9ÝlGnR•'d^UúZ«ŒW$ðÀ Šlñ¦·ßÆrüè½ ýsû…"ÅqxËDý‘y™uæùd²öŸ=¾Ux>‘¸x*;Û#v¾þð€°“°{»—#‚w-3 dõ.+( Xøl»üGãäÌ%OÍ–(áãqõÿnЮpMíêV®tûÁ%‹nÄT… ³|hé”¶Î`-õ_ûŠ-ŽÕzi&GÜF’ (VAúŸæ‰š¯{òŽ4¦N\÷ÌÔLia—cO; P­ >@vÿì˹•n©si¾o•sŸê{T“º×>²þ?)]#¾Ù4åê/sèCA™> µn4«çð¿?…Çü4ø_ü.Ëð¹¿ßüî¬þvWó±“~Xãâ¸2_ÝëíŠ~qdÒßÙѳ{Š"_üšE89¯!  " ­ ÜÄ-Ÿâ$Ÿ´ÐAüŽT—›’ð ­YÒ×ô£yûôÉf¿ÂFI– s½5¦ïÐÝ¢M;ÛØ™¢Ì@[áïEñÔJ~$qМ£iŒdªa°Öw„ûFÞ:±M\—–©WÛ´ †L–ëÖo¥ Ü(µÕu,Y¬SUy{¼ß7Íìgˆ¥ û :>ÜžqÕzÀ 4X&Ù|NSɸyÒµT‚ÀèSf“Ø—(C_þ[ûbí¸Lr^ùý‰x\UÅB±ûL0_ÁTmKúèŸçeÒ®v¾¾m'T&M-.º7ð~iDëEkv$G昮1'+ô+ƒ§Æo›, ä)îmƒ;åÛ†ÐD‚=ú|Ñåå G„Þl²u-sâXTÙˆF¥‡ƒ©ÖW(žÖ²aât#b‚3&^Úþ–[}ð©y#„Ûã¹Ë"6ý¤àžóß C{Ê\ú£ ITfçQž[¬k¤lñ_Pû™´Æ!n³—tx)”S2‚;·dLÙÕ.Z©Ë å·qyìÀQ¨R¸€·(á1ÏûV ÁÀRÆ ZÝ{̃Jwªrõ!¬P8Z#v8çh=Õ†ôý3%¼=\Ι\l‘oYY ŽÚ«‹‘<”kè@ý;JÍ^Ÿs С?݃´0’^kÒ\‰òÁDæyÍóy–°ÑEYp=TÞ\þj}]T—ãJ¹ >æw5o²@´õ›WÔ4·//*/ÄžP×ød¾QP˜Þ"2Ð}¶È[E—®Œ¡2в¾,½7HL*ª[¯ù~åæ3 ‘p Q\!ë (¼ÇRÐb` 33e9Húœÿ©/1wŠ7’#l€èÐŽ†„wذ§+„KĂċéõ¸®5º:¹–×ÄØÉe@Â"uo)ð]V-ìêf¢ 6YFAš‰ùWñw¹ª@lDi½hÕ6 ®o€oðvÔÐaMÖi좇§Aþ¦‡ Aï:¤ݱ< Sa.¾UøÁHðÚoÀù= ¶™©oCm žÁ ƒ–ýÂ5äêo­o+ϱçå¥Ìœq/®ù0OâIQ²Á ƒÎì #³¹Ò§mÄ+ ÓÁ¯‘X$©/šfî\qR»xo椹‹íÐPöPž™ð³õ«²® ÌD@HbR…ý„?–ý‘‚ÍÔz¡o¬Îà/zõ}‘@ߎ߀q³¸´ºi·ê‰õ«ë$Ì®ØÐ(=;ކcC×BÇÖO¢Zå=V)Ñ_žRî w›§ü`ÂÄϾ* 7çç³6í¡i±X!øbYCÊb£U/ÓÞGLFdͯèëÉ=pkŸ<žÉ’ÚSºŽ‘d£ep ¢ºAÛ H‘ÐD‚`<éÀU$E+~Ō榦[—¹>]gÝ•„8^…,ѲÖÝÉow‰`üÿF…^á\]‰ÀþÖ9|9¶ó:œ~`Né8O|ý•ŸÔ·0Ooè÷(Âwn€ ÿX©ijÛ.ÐÈAn?€ê!gò¿¥° o#äûêqU6ì÷-Ù‚…cÔ©ÐåiwÒ–+nŒ÷Þ¶j¯rÂÚæ ¤#þEr0A¤Q^}Ä¢Ýö /V)èr›Y»vt*ÇÙ°)7ýj~¨†üÚ ·n ÷ûAJK…¢YT þ Ë¶¢Ÿ5“ñÃóX½›¡º˜·^æ·©À9±‘ÉÝP&Í't½N—öyÄn1¹·J÷ƼõP¨p[+b?SoßWÁ*Ï´0ö,Îû?_+¾ Ðæ)e²–ØV‚ý¨ž|5$õAøtÖKŠÄÖNþŸxЭ$^¼–=d¼gÝÇ>s‘ÎÐöjR‰oK>àÐùC³#—qݦ‡ŒÏÞ#öµpVöhPY [†}¤µ• EÛ¥,¦)ÎÒèîEN¨,:e‰A´§à"Ôáò°W-fÒ¬~8záü¶ò̧}$ÂFõQŽøOĪ0­A_ò˜6cOåÕXåfTº±x_²ê›Ëb5`Ã0ÁtÐOÒl+H"§JÚ3¹øw)Ýgî/¥´°êå!΋٤‡Ö¯öuS:¥£ÙØ´Ÿ·økï$V9ÿdfÃð!€¨­ƒÌ[ _‹¢À>ç;Pd‘¶sÑ]5èWiæIÉ"EYÐ?ð¡Æ:ÖOüé« 02Ë!úl Øýªòkœ\—&÷ĵÚo¿^V9Û¢¸"øC”õ2-ŒébÌågû'¶¢m¦3³)RG»‹ßªQ3ŒÄ'Ií‡Ù0èøÌÛ‹öººÏmS •!ÙBß§ ç §šÆið>{|ô‹;zaËJº]»ãXqÂ¥?YJýññÞã-;_¦¨SäNÍj‰¾QEjfØÙ÷º=š÷Îk¡ðÎÂZ6À`KÔÒQ‰~m ©•È)fí÷E6môPÄupâjÒ`§ô&Fµ¤Ÿ@뺦9‡ŸS®D!'ë*·/à™ææŠ0WØ|RPÛñ=¯ÃÓàA¥‘Ì«Ï(³LQ««lL²0>ºDõò{¢w¶K5všnÙì'óß~:§TÔ±-[Œ®i 'ŒÒ§Wó}»½>ªÃ_Ugûw_øv¥?`n©~Þ˜áÛíöí·}ºçü;:þh ±þü:¡ëøo]ößûoßẟðùû>­þ÷á×Uøv;߇P7áÖGóèÚü:›¿”¿ŸE†ñ_m]ßmqü7 øu§?L?†—ÿ@ÿxt­}»Aÿ¤ÿCÿa·¿Ã^†£ ˆíxŠàÕ~öŠÞÚ rÞZ¯º”ZÆ9ØÔý³ý¨¤ÓK£ØìÁ4+ ‹á¼MZŠ DÛq÷üäóù˜‚s6„!Ê‹v .“—ºˆ–âñ<†N“ÅÀýáæñ,"Nß7MðLkeDÑ$‰Sµ"£uÔ[Æ¿¡É•wcµlÏ%‰Á JÜXÄóÔ™ŸÙ€êèq¦¿:4Œ¸†UvugM¤Òë0kbäMŒååÏ}§Œí€¤¹ó½JaŠQï‘fÄ9XÔfîà1h Ýçˆ÷6y§å˜…¾BÕ™ÞXÍlb-iÎæc†1ÀÚé–E¦˜@‹SäŒzÒòAfÔiG_ÉÉŠ©S‹ÿO+¡Õ]ÜŸ‚ –÷)¤ë,žÒA.²o~‡^‹{fÈ-}§ssº’"Ì@ö|fÉËkÙ¨Ál ì7?N¤ˆ5'ÚE·íÐ¥pò%í*#tCMO÷-ˆ—DTßv‚J¿œR.:»1Í~\nfeBtA%€»&(LÊRü PÓýQ6ÑRZÀ×–°o!3_rœ½]yÚ2óÀsfÝóȳ58Èo-Ýœ7¸±‚3*bAŒQÙ›–&í#êAt+x>CànÙ\=^RÐ0H>5ƒF~Ðoå¯çÍòôf<ŠÜ´¿®ÝæÍrÞK$ ¿oÝpÅiš^‚ÄçåUè®g$Ô¾ø>Q·õl ŠCò{¯*0+cËÒƒÓ¾>Û…ËÍì±1Ü1ÎÝâ¤KaYŒœ¡F™HàÍÇP@¸hG6?y5Ó˜™kzljµ÷¸Æßä– x==£?è°}UbÁV´þVó¾&¥rPlÛZø ,‹Õ\píG{³gñBÐ|÷§[M÷>K½A«½KŸØé:Ûq]c­™L£„ׇ0W½ÒÓäËÍŒIø—ÿÒ³roœï_Þ¦ä)3S³ðxŸ¸¹þníîü ¿ Ò·x tüÄùÅ»abnZ[ÿ1BÕ‚:èBZžDÒÁýê€×4G©zÕÇÅîmÊëÁœN†¬%3§KjøÑèœe¾PáB9Û«‚b÷›`$·pmÚ—P¹ÚF¿Ê¹Æ¶ÏÓpëÄI–RŸZ^¯øÅÍÊ ÀÓ‚=ïÖ©.ØËDÞjÆìBT4+üRÕücY$-6ÙIÃÐ`»ýSþ„%M¨†n#¬“¿ñ×8}Ø…ÆÇoÇ#×N)›cDG7"›©ÍœRU `lX›kþq ¶åôÛ×¥@ÝŒÚÚªEdw|ôΪè× 3oØÕo!Ðaöìõcœì4ú®Ï¤ø¦¨Ç|Žã)0æ Ü<<7Ï*”KóTØ‘§šQáøtË'[H€w žÕ˜1tPÕ:<Åc†PÁ‰o!f#VDƒŽh5¶]…„H¶‚ !ÃlºçݧN éjÂèù·pÓ‚® jþãéSO´‡c}s=9 >ätoŸE MÈø›8›ð½Ñæ ?._ÙœNÙØ(È#)«1¦Š«-S¿y.ÍõIàz àFÂ1££Àù…È™Í gØ«‡:¡gcAýRºü`«xåêÊyj!æ¥>)Ž7zÅ>åés÷9*®[’ÞWÉ®E(nNY`r¯å1­™·ì9ŸÉ0“}wªhïù4þ´W¬åÁ<ÐãÈy¾x9”¶_Š‹ ¨¸¡¼‚sßÝè íú(7x/§“þ’í•C!sÿ-•Æù‚…9‚úSöa‚³ÌK1c) ¸ôôfU‡à#YƒºNl0B? +Ý3€¯,F5>~.P§FSêÒòì„jN;X÷ûz¨šïÖQåj'Ôp5χ¢Kiaó¸¶Ä"äe†?¿3NQÕ›åçÞ óŸŸ9wsç·†²f,Ê(%ùcÕ‡#¬»¶KžÀç2™0¬y¬ xùbýèóÔ —\KìÄóg¡£ûü%h蹕“˜£@U†:í1vç¨ÄŠÿw¿³a°ŠÝ­fˆ–ŽœlTÈNþÐ> ;yu¬±9ýè¹lLKïß}}Èzk€¡ÌØW{kfyÈÌ!É·‚Ï¥ ÿ ÐÕ5³ ™ƒì‹:ÛÀRñ=œØŒ,KXg—óð½CöÑ¿ü¸M–Ò %…›2Ÿ²X¸Z1韢ûÖå…&Ÿ©ÑÙv¼QS‚¼§3TZ?CqÕ˜xz#“ šqg„(žÇسŒ2èF,ßËAdÞ…šŽS8ñëtce§`y2·c«ÿBª»R¾Ç)Q°,6=¨iÕ÷1ïpM¹áÌžgf«t©5»Ñèõ( Ù”Ap:ÃT„%±m ‹®Ê¼'XÉ+§IŒÜ‡\[jsp‘^;F~ÉE¿øBÔ®wÜ‹‚Púß Èñ¸ìž3%¡‘ß"Žk>Ûh-ÐG ¶ktX©=ìABÆ}ißCn ,P…ˆV¢KÜÍGØ~!„à'ÍaZdÙþ[}ÃI4 ¤CiLÝÎVA‹¦ÜI6Õåð]yh¼=øúç8}¦Öðô¡áÞ'/騕ìn)S63'u?=–Fila$?Úʇ®åïÁN®²EœI=˜ÙTÎB×O½Á“ì(tš•±éXÙ`R4—ž¶Öƒ.ñj¿Ùâ"±óCŒ vG—?CÑ‘­k"b_ø`Š\€Ú%³óѼp*Ô(ݘ{êâ(HŸ&¤dÿhw6N”VÔfÅÆà€bœÇ<- ‡iÄŽzv7]„-<{¬ÊN·×Ž#—}\ô¶Éhÿÿ~@²by²¸ìN$#b-»‚ò°CGUÍ€Ž /ÿpx?¡©ÀÚCýÆqqÿÿ `,xýÀ5«Éÿ‡õŸ*Æt & !\f™yH¹œ×ïw9ñ¡¶¾€·÷Ûç,Rè·mê€ý€ä˹zÿ5ôX«Uúõ汫LÂ2Æ£äÚ G•³Ì‡eö-!…KÒáÍ_±|ÁÔH[‰"i'ã]¥>0ùéjêªa+è·I^Xïò‹áÌ)|2ELqï0Ìf4Mìý„BjëWÅð£BºB_ýûÚiwÿøtr’òÔÏ0mt0k$4™6Ûë69Q ÁZõÙóÉ”Yý¶:ZIÓy4Žw?ƒ[Þaˆœ³*Ù©z€UdŒ—u±1izÑíÊ6ù4ÆTÕtÅž€Ž©ö&¬-`úzÞaJ/ø²šbª_v„èd…F°÷VoŠÿÿÿ^ÐÉ8ÄxïŸ|Ñ@R§¨ËQë넃…Ïf6”‚GÔtþÓ¤Â1MÒÑi¿¡†ýJè%À/Ûªe{/}q×XÒ¾owÑ!ø Ùî!ñ%êÍÕˆZL^˜-9¡(Ãe¥ÆD±fš™›sܢͧß!n²oì ±l:h^“"yÈéÁ64yuO9Ù%,íiºd–ô4-I[ïjÞQ²X/…¬Ë‰Ë[…Ê '¤*.(YM…òã¤ù4aK„–b¢BA&Ö>l#‘Ò!˜@V©\29à´Ý§ÁCJ§M’’íTUvê£e/’\#«ç‰á2r3€/q‡þFá{ EÖ.&“°ü@RMÎÏù ó|ij]ž DQmc‡Æº+Û$Ê•ù\«„ܤg”˜=%CÇñœ ¯´¾ÔÅwõ?ÅOÇR³õ€K¥1D”ÿrÔÁS¤óaϪe@|ûôÎtò -¼Ó®U2 ÔðbÝ|ß4ò°ÏÕøÅ6s–˜2Õí™iºÖùäû€hè8!)xj>.¹‚åb8E„ ?3¨Ð *S"¢GŸ"½¿Ô1­Ò? L\1ËŠC®EˉKÖÚsådNF|j\06»)Ïïÿ'ÿ nR¿sϘTç<´çÐD&~F •®æ ¤¨b(8ãŸElCªŽ7r~ O5ý° ÞT?ÿ~qÇU«Èã”ÈÆðT†ŒiôÞ IšRCP‚œ7Ê5ã!áhc:¯×Ÿ ºÈŸ*+»v²&$ye2€@‚UŸ•îƒ×÷°¿ ¦gõÊ7øþ¶suõ0€£:3r|.—HBÀÊ£3Gòµ?õ!`á¯_{Ë­þñW»¯1`c(‰e«·ô¥Íöâ&6ŸŒiL¥ýaë“— ð°‘hÍŒµ9r×ÅgXpO Örqó¯Ìr©œûÞÜô}´é£ÒJè0X@=-¦gßMÛÚZC7Û/Ö¥ŽúÛ³çÖváÞmç^¼O]¶P•^iÄ÷OÅæÏ…œ$‘~?¡½!¬ p1&në¯qâ :ï=Ö©~ q!»-ú-Ú'Õjû’JvÕKƒ`ÎuoÍòÆ|†ÒMW:F4úìSv¸Õ©ßhñê Sýi/¬/›Qï„5…™Í¡úë ãDZê-* œ2ቤÜ9¦áëüùw?U úÖ~’•à–ĸÅXxóW&—f-†’Â.>åm;§DÕ =ÀÕRçœ5cfR{¢µp}Ç2v®ã7¹w´5{Å a7Ñ ™)f$`ˆ#¬Ýºê<ñcþ•3‰¬}}|Äd ØÞ ‚²ìØzbB€ÚõÌÖæ$öï.nàæ!"ÈUýuù° Óp“Þë©1O)ô5‚z3kàÖvåÿŠt(•ª49Ýõÿ¼úö¾>¡È2Ð"}«±Â7CÀTýŸ—] öAOîØ¨>hÚËú8oþu}h"ZŠ×B®RjC¥\†î7ˆ¨”{êWQzgì59—’¢…k«„ë|ö[Ô¬ºJy x^núõýdP¶­ÉNreOµ™5Nà rj/ß (®y¹ŠFþúÊO´¯w‘üÀÚ+¹ÓìÑðbE.–Pùqó¤ë\yÊâv>¼|ÖMÇ‚²b.ñüŒÁ]] jÁjMHÑ™óKà·™Ð?‚5(—‚±Héá–p+jƒÜÚJª«òÓß[DèD°®arñ›µÒ[¦“•_ó肵r„bìÐãu|Ñ&)ˬ®B©Õ‘Z5l¡¬šÐ“?üVJ­µ_ò_róvàí÷ŸCç_zzR™ÁíHˆúHžŒ ± ‰g/:bÇ‘“HªÝ7Žò‰â\™‡z«ë_Xoam­‘ /°H¥Ÿ;¸üp<—†”³x†aÓãBÀyËýJéÃÁ²Tëß±–Ýð™õ 1uný¯& ù ÇŽ×î¨àmIö*¿y;Ÿ0OÚŠu•“6M­t3‰}›Dø§y_>îbßªíø‡ö¹9pˆfÜÞ½In;Ë4 òk³#–ÿžÆk#¦»÷Ìov‘l ©«Í/(‡Ñ¬Ë³Ϲ½E4SΛ/ãK©V¹°Y (jó-|¬"ÿ_öCÕv½58ˆËSyƒ°™q¶ÂPìúo3iKD*{6ŸŠ¾¬1 FÚƒºÑ1²S†É’L&e) ñïÕnN@c˜ãÂâtí£ÿ`àÑ5®Ú ð0ƵI­ “¬oq8¬7` ”81žzlÜóO·ëýˆ}·"iGo’Ÿ ®€Ö…uì-$Áª ýW:Ïõ>%â&˜QT|IMr'Ï ÍýF‹»( .$zÌn²X'k,CÿÿèÖÙuþ>K”ú-[¡®d{¾„[—R ŽŒ[ÛBN9Ñ_ͯù:ìæÒÀŽR)‘â|8?ðl¬Šcãñ €`ól>RÌ Ø_…øZ’áæ)·Ï¸®.ƒþxfÃW/ŒIð+Ü.š"w•í9qgåõUf“\[v!Ô²Ñ:´»ÐXm U3¨û;E¬4ä«‘±Æ·[3Vg±˜³îT‡ ¶=»©…Åü'·þsâuL7²8qÄ8°©ØÜg~%£%¬ýŒn ˜5ÄŸUñc†A䂌\r…:Ò/D±˜J?aU‘|];Ƕ+C_K‘$rÝZ× ƒ±ÅŶéF-2´M*h¸pmˆ®V¸˜Iú"¸ü0?/È´?&›]E8¦Ï\Ū½ñéÛJ„.…Ò.l’5©›\™MS[Hcj2¾ã8©âš:Ž x¤ã´0ë® 6ij΄'ÊH1ß;+k+˜Ïÿd©GÔ‰R AÒr)z ȵ:ðŒt¹Âä¬ êjB‹è©5Xø:É6oA÷§áÕ÷^Š€ÀÍ·´ìdt+v¶æ;ÞI‰–7‘c{‚Ù‘íŽ;mUiµi„¯3r…é¹RUxÎ{TxŒí*Ó=©À:ª`Hú)@ Æ4:,ÖÃxÏQðaóòæë3i§ôg Y'|*Á :©Mê?’,à’z¨q²!¯_žiªJ.Ø Äãî±R9mƒ”õU+ÎÊŠ^M¡Kp@0fæïâj‚õs¢G…°‚‚¹Zë….‡>–íÜT[œÄÎMæøÐÖÑfŸoÖÌõõÊÚé€dÕSâÄGG7î|Ø’¸.2§¼Mí,míZ sV> uÿ"˸o·`áÒ§I¡é kTÌ[tØø–ÐOg­?ÿUñk3ÊùD WꪟÁ«ldQpd¼!IwÿŠ­dÓztÔ-Ø_ø‚(åøK—À=`2Q¸n¶°.xX‰¦Y𙊂&ÞJ&v,uÀDf²—HöTž yõûu^Wõ¢oÑÿ@Š~°¢<܉ÔHày‘Î ”*Š ¸×0ÿ ]±öâ×áßvØ[•Õh®”ÒÓJƒc¸n4k…{’3‰00Ðâºßò_®áÉëšXk6ßï.KæRHII›{QÃXlG¸pIûy±­‚€b­D¶K>í*Ò<áh¹¢!® 鯃â‚ÉvôkS펟‹í‡”E³`[¦ ²ø…3rT´!9ñŠv©]þÊJ0 ë/Ã8zVŒ"Ÿ¬ Yâ¤È†Ê)@B!þûwP¦‚ŒA ¶ éåfåó·]—ñ€“ªz7‹tlW†G4è 0‚B驳R¢Ôȹ¶8¸ëó삹n‘¼_«DÂâŸpu‹§·Ø xN€ÄúÛÃ=báú—£â´ƒ?áó’£ß/ãŠZ·­RãÔRçÆnk%јÿ&$Ȱöùø}ë"ý{¸åÿÿTHÀg%?2¯KñÆî¢ƒ»øOV É7†U¤B¾¡€[O3nÒó6¦Í6t»—Ci¼¥´åà›TBBY77$1)‹dh$}#›\Ö‚x?¤'ñ«Œ1]5§˜^ÃH4ÌruÐ+˜¨Ÿ‹Ôñu;Šró8$¸MçÒx¿@@–94 t@©Rÿ…@Þ°~iñ؋؀Ø\ÃÀ+]Mæ'î´áæ{³{‰î¤ë«`®íŽo׎.TÓçCÎýùCLšrq(‰K…Ìæ ðúø‹«{ (`iŒ]ã&B|! ÕiíÆ=½íÌâZoâË”àÙÁ‡+Ô)N,Õ:LÆ6Š3k¤)âÑê†"dÅŸ"%…ªÁrÝ—I»¥Ü®C÷5r)~o89ÏúWšÄ¯¸n,9$K›âèáF| ˜KdÜq,CÏÑ‹5Ò¬æq™Ë&ó‰æAZ—Å9\bã y_¸Ý?=%œÃ6¥ýŸyѯ‡Ç:^z­a{û…Ž$÷‘¹6”TcÚQ#ùÙOÕôfÈc[›ÿÿÿcÈèk¿¼ŠÎ8ºåJÁ÷V(«‹@¦Vs‡df'tiqh0ä¦à$øpM+î„碽r„*HåÿtŒßÊ v Eê#JXkàPy/lOýÖÎÜÛfÞ۸⨣Âü¯C<).Žøè²Žãéü˜sl)(_ :šàËzŒ²xþ ÄÎ6ä¯khwöÜõ?Ú  v_x¿L6\Ì!ëðe„¶ Tí¬ÖÆG4šw₇¤ï7ÇgI€ÿvIc.‡Z¨§LG0 ÒT÷ú…äôo¿Ð?J@÷Óê‘4æ;J¨??BÙ^ùeô¥H$Ôm­kÕÔ3 zœ1½.f‡»·v„W!{ïf®¨ö‹½$²VVM ò«9Wv86 iÀëöŸ$;LÒV‚¦¼ð²^v$iž,Æ§Ïø¦•±‡¨–v gº±zšìÙP/“®Sòv'~ÉóÐhñ=_†ÛìXx 0ùŸÚ1ùT'S<íƒ,>Êö5Ô-´]ÙœÂcò(`_3ÇxEÌCû/içû;Å 1)äç¤ÒÓé ²L­£ægmNýÎ ?;i›É(+^µcʼñ^Vg/¶_J# ‹1O«úÎÊ[›Æ áLtJ}ŸÅƒtv±p,Éï£ Úõà‰Çà6U“RÖEïeTtó0Öæ 8CeZ÷nõi)!p¿ C·¹•ÙÚŒ›-êãÖ9ÕŠÏ‘yüéd´»uŽÆùôvÞIpøö*B³7㬹µ¯L¡‹ötÿU¯#Z "œ0ÕŽh¼AdZÓ-â9Dê¥"¸’¡/ø§ê \»d‰ÞdQ W!  Þ4ï÷8ä×fË^,WóÅòþr!ˆìÚS&øwû軃{E)¤ 2ȇŠúÉ5÷QqáÒ„Úß*¡òà‹9njÓ+qçç²!é{¦8ö¸Ì¡yQK›¬ˆ ß„!ªCã9 ›4ÙÀÂ9•ù<½IoGÇ©>=¾ƒ”>Íb…À»ß]&•Ç8ìb«¨uÑ8Kæ$áA+•wWjzi%Èfýý>iIPà/DŸG¦É\OþªÃ êëÛÿrœ\` 8àå /æÉµ#±4ézdƒvGÉ_§Ì±¶$~/è|8°ôbŠ‚dóA¿»º¹,˜»1ÞáÂÛK’ÒÉTÕWhC9ú ›Û_øñzþ» ѳëI…mL:nÿZ™@òlûå#˜·T¼ÅìdUÛ|™ð.‡€ šV­×Âåä6ìD>P¥/JÓ•Ç|ù”$ª8±C×ÜD  ôÝa†yõ l `o”17/F*Iˆ½ïǰçÓÉóF^ ˜ôMª_’wÑ¥UvŸ§Š\ÐæT20çº%µþå('úXÆ£—Òës½‘ë†S×½]‚~Âñ¨R‘› ®©Ò¡,õ`{Š´sO¹×T-›]ý8t<ÉÉÔ =5Û([ /.¶Á·«›`¤áp`á@‚™>«'û‹©[&ÁevTi1°p¿o;X°Q ëtäù%`<:'¸§ç—/‘nUR)®ß*AZבÔA‡°Æ6%– ïqòTWd²!e;$ÒY^Cô§£j¾äV÷)”Þþ”§i×<.;íÝ~ì4$½/"®h ä§–Ø›žÉ[ñfäûyœbç*aSë²,•¯ur 8)vVí$áì_)¯ÂÿGi=ËdÁ?ŽpŠsz&âW†á²l$:6lim £~ts!~™H—cÀª ZÆìxMú@6,Ù®´']t)waê:…Ò‰6ÕÝ!¢û…ÙÓo޲_ô5ˆEú°ýÆìÕÞ¿.Ågš™üç9~ÃÖXqÏê=‘¢9I€ÂQûÕqÀî¢îŠùÌb¶Rx¦G*»6Iw ůs³ 9¥ëXX“}êV{ÈêæVÙÿ({TJߎÎÖ½m)ºÎ·Ê RØ‘1îm»zL ±'Dâ¦ã²iJÔ Ë²[zð …À=` FÕ’Ù]ª2Uß}CTë…ÖO_WGt}Á‚˜ãýuH3Ú9ƒvboõÿ)XÁV™Ì¯ÏvÖGöGË㈷CÐ’P~š+ÛDAÅ5oŽîfŸÑéñ©H‡mK<8ï8Û«géû‚ê~mqt)•‹¹7]{ŸÏɆ4»Vñ•ê l­é,˜fÛÓä!y¼€ÎQ1ÆàêHzÄÔ­OM󑬳GŸB—÷“¼åØû¬Œâ6™Ðå?Ü5±*Sýþ…¹tŒøõº-`GöõÚµû·«uü–GÞŸ·Z<7¡@Á´sôÅñµ•=×ܳHò/ôTíÆ¬«xs´5ü#;ÉŽ}Ö üPŒe"$âåoßzøx4úª¯¢ƒlÙi²³sˆÅQþ÷I(æ¦íã:tÌÛ@ôD< Á—ù[/˜Âå{×M¢EYbWÔ±Ó ¥•4,€<§ßlt((6Ëp‰¯^ïÆ/ÿf˜B-}÷òbú (»ÎôÁ×]¯*èͼ„ôÏõ†ž}äk¿¥ìŠŽðÈ䟡m–¿Ø4Œ nRã$;¾·„Íá±ç‚|Kà(œ‡Ov®ûÏz*š[„Í–¬ÄãŠí»í“{O7ü\r%¾²RŒÍ€ÚÕ‹EtPÌÀrµ)ÔÅ=H¾DÞ _—‚$Àަ¿Ü¾J‡ÇV>Šst?š²#4¬±Q{ùóÓç,?áçÆ{íÆæ£œµó=æÎèoŽ@€.ezùôäñ³ˆÜÔÆ¡ñL¤a·h952²|CI:NÚY]2_/5ZE‰Ù=ºö§ØÑH¤p¢”ò¬ƒÃÕÆÛÞG.ܲê„] N±ûíÏâpæIbìT´†Eoðæ±0„Æ‘d£…©Ë?ͬޗsH0½ˆŽJOã¨:’>ä«GÎÙ_rð'j¦M»õņEÌ„Ì÷à ÇXCcbÃ%¦~·Ï7í®2QŒ)Cái"'Û]‡ÅßT¶ÉÏKW¨\Eà`<Òhж-ȾÉù¨šÙ6€Yvm›VŽ9åÕ¦ŽwJë„IY«u>!¿Yïáašµ=Ÿr<Éño´xÍ?8ض´J¸ÜÂ/2¯-–Œ#(eºñU³I E$>Õò,¢Ï‚}»˜®\˜nyê¾²Á[LogjQvõ"¤å@Ðpl"?eë Øq !g‡Öåø°ÖO+ñAV±<ì—«¶GæJ(&¹ 7Ü8"#K¶‚/4áMdÍfuÒ¹æIÆ >2›Ê¢æoÀ%^ ×tePÅK¶0«;àÇnÜ <]3ü¥·âŽu"GÒ§‰±^QÝb¤øP”ÓcØ{M&³—éJèódë(²ßÈsßÐ"¢a¹–%‰]Žì[ƒðŽ‹a«s—½"cØ2¤?Â{ž†ž?WÑEB$LÉÑzºûúÖin¥­4à?®½¥“÷oû—å£ç±ZüÍÊ‚Ef¹Äi.BH·Nü¨dùa: !£cÄ9w¢îôÄ‹[²<Ä!'ùGáŸMÒ^ûKàËê²?í”%<y§ ˆKèr[QÑäE@^¾c¹ÔxœC8v¿j±ñϳ‚ZzóÞN™ð}¦gεXÜwù©å'QYèàÖt?$@W&k»>ε–FÎÕ̦¤Yó† û»Ç+ã¤C+:äJW³eV®Çæèyz¸~V£ ártK®±‹[;â¹Hk&¿ûZbŸÈ­=÷íuIùÞðRlU!yšÚU>¬£«qÍoe\òÔ‚Ÿa\Àºëe28×&Á‚½9TÉÊ&!-Ëol®ò—Ë$éõÒ)¤Ý¡– 2µ7SL©ŽPùà|ct»L[íO…§î+ZLè·ü¶|˜Êx˜VÎ+¦ïL&B…ŽÁä¸EÕÝ$ް;Õ½±»wŒ\9<©ž°¤ûµ9ÙøÕ¹ÚióÓ_æ3ÔU”¶Å^¦ŒìkÇ»mª«$ü.Ø-}ØÆÜõ°ÕÍÞC%ߥ6ûßGÈ …j§a±)W®/[£¾-+ msžWã ŠgôõM½¢Æ¬Í±-÷؉µ’4g=R]ÔêƒZË´5ú*3¾6š…¦På²qÓæ@_"4¿+3²ÃÝžáÈe¥©€äMóOyì>3Ðö8;è^¸¼³¡3ã gúe)Øôú«/íbÙá^‡Å²2‡ó,•m[êí?VÊý±Él¼œúßUƒ×ádÁj¦K“–³`ÅЙ&¸þÉá&ÀB™Œ0©d‚ïUÙ{ªõÏÞ{OÂ{·rŸ¡KOón=h5xK<ËR/¤7ìÛØS7¨@ iÕz0œÉD…žÒ5ê‰`nŽoj«¼â‘Þ’iÉ¡{㔢a)ãoÿí±¹]`Åp¹Ö«‹¨8÷ >ùá½ä¹=u‚Š)PJ:ÈáÑÜè+»$Ÿ*d½³×µ«_·¢°X=ã’—“è]«CP(¹sÍK8‰$’!u`£&þ4/©Ð.òÌ€æNj‚Àÿ”äŸßTj|:—¨Þ•üKâûð+âÐÙLáRÓR«ö;r˜£àãð(Ë ¼NêôuÅ fØFJTÿ‡2 Ê÷um¸>»íd ´/Q…L‰LÙ  nËyôú‹?¡}“‹ªÁ÷«+­÷<¯²å7èCâ­D¦|¤Wªë㮜ãOcjWËØ³rò–â_äsrE(Í#·qzjQÊ/FÊ´PMFnÇéV‹¶*ð7‰D¹á {”Á‡ßÁ5Þf¡Ô×ÁŽ1Âõ-;H¨Ã‰iþ¡~”'°¸÷SˆòuDÿYjÜÆáÊÈÒ,=tßò¨TÃæRSïe÷Ç+Úý4ÙÂO³È ÍÜ¿NþÿÏÐ1ûì_£‹UhúÞ)… E`‰KÍÏYRÍ #…˜$ƒ]…gøîp¥`eò446•‘#Uùp´u±Hã*pöxöí©SΉâ…Á»ØPUI¡ÈŠí}ŸgÁFà?‹µ·Ù–îVôÑqï+ø–>ŸCàÚW‚<ÝÐqô÷Ü ?ç1—Ï‹þìû<¢ŸZ¤o¼Oý³Aõ4lä‘Ïw5ÒÈjŠ<‰<ÿAøò(h@Ã7ùQd¾#hüü[`ǯ‡…Ú~göŠôï[ªäóúÌŸr+b*9/衟@-ñ{þd^ɦR } +ñ(uU²V€ÛM~gÒw’$6‘nŸè¼'‹€BÚBb}/hm8 €^UY1¶À–µÂ<öý#¥1V<ï”gˆx,YêÁpCÊÝ_à_ÃÓ™·Hó>Ø4€Tá4ɳ‘'îƒà€ hUœú±)ó´NÙŽÍŒ!¼Ë Äí^#2b³Â¯ôú]a°0Ô€ …×K­“Þdóƒáî'¯~$1üƒÑ¿1‚h¹sèñvi/72[€H¨zørg¢™xµkFÏàǹ]ï9°§‡ˆ‘ ;ÙY—Bå…X¹©–ž÷Þ,›b˜:VFþ'ö#…qä°he G%?É•tØÔÑ‹ïHsz~-aÔ; "ËCSÅž>šÆ] øE7µÚò@>¤Ö³Tçuòð9¼ Á©ü5òz¼Ô_ì-?ñþæ6ïö¼œÚqËVÎ!Å$Õ:åæ_oŒFÔ™¸ÉEFÍɪ8EFÖñ$Ú-Ðü:øI—Ó-09ìi>‡,q*‹ðT?^+½'´›½ÿ9ÍÂpƒƒ½ôî²’oË‹áêÄ ØˆZ]JÖª5°_“ ¼ˆueRX'®xŸ e²Mî$€i@ñ*Ås=1ž®QŽk Ø8Æi,~é*ŠÖøVÍ«:–Ügk{®Õéöã6LÈæë% j8»s>„ÝéMEJ'Í/Øn…L5)pø#F›¾ëŠ Põ£X} ÒÁ½Z“Ò" ¹,j6\1†J˜óq~ªŸS¹ ~<;]‚ê¹ÒPY»s‰®ê€1Áï@k\ ÑKàD„¸ñ‘,©eÿ2ø÷‘Ô̦›V?V}Ç x®?’Œö¸B§}GÛZNÈÆdVr"hû>cêòÿãR{jN0QRzQñz(ò†;³”557k!ü™,ö8hˆp@1ë”_*·±ŸûÞ:üç9Îsœç9Ùü¸€Óã~>(¸Ã“f ƒÿ;?Æìwµ<ÏbQÔ› ÂÚfÓñ±5þ|*ôx±¶#hö½`B%øoªS·Ê²ð<óù´ßW¥(αL erï9ÆÐäV¨Ó¿h¿Œ±AˆlNwƒ¦ X%µž•qm¾z© jVޱI¨Ó·ÑPŒA!‹Þï¢ÄoñK‹XVªlŸ¹Èƒf¸¹§Tëú6ÚÉ"“Þo•Cƒ¢2þ•÷ëºf ¿pêDé¡-”ÇBD‹ÖõÊ|Ó yºÝ–µÛ+8^N ÂK™(Þë~A¤p“ƒ+EÉÚ°èÌ̸ŽL±>n.d]®›fž;߇¸e)u£c¥ì€ØjâMJ®+à~vGŒúöU, ç •ÉU™¾4õ^rve~ sp/Œw¢ðÿnÞÝFWè¨x×Á²8Uy'(‡I_XGøcŒÕÎÚòªÛéEuJ1AjÞŽor»0Ôê-5z‘Ou?A„?Ò9ë쮋3•s K‘éõ Þ—rˆñRÃ$b·‹.ðPS£Ê<_ƒŒÛ®0%»€Þ†+Ó²–UíÙ©2þ§¤/!ºû¨¬—“½N¥TÃŒ =›ê‹Î*aJhDºkв“Ï<`!`8õ`PXÅôa[j£Î·‘ˆNhŽ €àó?çBU°x”‚ê&œPIÉá‡Êaè¸ß/epè‡%.µ•˜¥Ù ë^-Äa5G–ðñæ5>·3 ¥X¶¡-evìÎYTù®rß*A=Z6@Ìa0½òö „ÖÑ~ÎxŸç$%I>µ2¦U€þûFu>‘dÉVKä¯2e^äjšû hÿ|‹[dx–ˆ´ɔךï"ÚPÿrÛÕü°<à6FCÛ¼M#¶,tO ìIxÊ"ñÑÚ¤À˜ÈŽÇ>™lÁB—-O´ŽkÙ¡Œ›û ñÃ=%9ÆÏòxf8(¸a"¾É¥þìÍ­²v=÷µO5¾ò›°]µ©qC8“ *ëIâÆ c?Á(Âê…©;(õ«‘Õ»ÜO |Ê…Å¡ÏÁêàf³1œç9ÎV±wšUfBÍ$κòjnÊ{f­Ã#<9h —^,\L°w‰ÝØ‹àjÙÔs(” ‡4 „(F{݉2ˆü"Û )iU–9TÁcJ68 07`ºµêT€£Ÿ»gõG7ŠËƒ\ªRÖ `öe9Ù–[!´„Dþ Íš I0I_ïûP •üÍx?%)]mذ йì­"©~½%„O‘ ’Nsœç‹_½é(‰`l ¸ IQÞÏkwˆÐ×#ZÙŠŸ/%ä?ž~ôöû£j2@” X^Sù:I5áºO–Ug)qü/JÔ¾à7¤YxÐÁ• ¨v’`ãWüð=œƒ`>[yÒ¥óZš´.ë¢È›éù³^–o©‹¿¥ ƒpº¬ç ÕY Ñj¬€øŸ+)_vÌŸ.hµ˜™L$S¶[È…Y"‰sìÌÅhD²ðGLÜuÈXŠÌö3ß b°<„4;º*5¶·àYÐsÉÎZÓØñ0y34Å¢ßî/ C4§Œ@g9_,{äñ—J€E»î‰û‚-«OÿcÞ-ËN“Ñɳ80÷o¶{ë,Ÿ9„êÅ?¨d÷¢È%ÅÝÇ/äå¥hô°é@Ô8Ÿù— ÐHÝ•œØÀ¬V cÏe.›°J:J\BM“¯d»2Í `âOÕ©·‡q†d!/Ö¿ ,³ }h˜Ò¥­Ê4ÒÂ(¡Ç×Ã÷bž­©âlÒCBÒå'óKuV­¡qœ ÓA×Ç4ó\€}R1%Ööá¸WK›úS±’—uãh5ÚX&ms ½tÝOÓ=ªOápºcI#͆òh¹P¨ÌŸ_Ž yÀ¨¼NFÊD²û1 +)i`>›çjå})+ÎDZ½có0éað|h¸º8† KÉ­!dä<,€Oø—¬Ç¼sO'IXÔ‘5áÃ¥“÷Cñc“KüËO±s¸×§Y9ÐN¶i0©õQCª"sµ €ÅQ>Ç#Ëc¾“ûqô˜ÜÜ’P‹±]î[÷x~ì- Ó ÖÍG›¡+Ûê¹+CŸÄÉ&‡7ã‘(€\—\ãè–žóKSñ.|ÌL¾Îq\Wý,ƒäâv-síŽÜ(kc3k›ì@΂ÐT]?8 šÖ}a P‚Á0á“Y@nÇ:2ïf#«/Dèn¾¬TøŒ`JÆÅºÂ,ý8ëähÿ"d°¨#¡ÉFÍšJ¦6áˆw, ÿ‡á»ñ>{IžÝõWkòÕrj+7y[ãM,(Ѥ?Ì`üøÍÐüéÂ1 G„Žº&‰¢¬² Y²€Äu¥²Í ëš“WjÎó#²ÇÆu2÷ÉÏBYœ 4å}/M d½=DH{õÂpœ" h7b@{6™Y¡ù„x;ŸØèß>=ˆHú•“MTtY§)¢ë_Fñ8EÖÔéu‡½JMI>´‡9« ÞAË÷2’gòs8üÌu,‘šÀcïJ*Þ+Îâ)ë³?ÍQ¢ÜùÔ…ȉö¤ÆÉðy!îé›ð®f(_°A£GïêÖ,üŽŒÂɀ͑‹ø¬½‡ô¶"»°ß5¯+Ž-ÊaöƒÕlÕ ot​‚~O/†)©îØP#pYÎÖ„Që\«†pŸÆów»ÃǸ¨ãФA€Žû̹… ûµ˜TîšùU›p—¨ƒ"+ëÝmêY®c¥ªÎC_íYnÛй=¿;V×´Bîy6ð¾m£TH‘©;—L€8ʆ0j±nŽ^¿ù¾;ÀÀ®à'°« ñq>ý_iˆìœ3ž¸žÁãhòM¥?,XOÿR*·èº0†ŸQÛÅ8R•¬œÞ“œçÈ$é| ) K¿ûŒâ­ÓÎ#uSÞreëáZA+ﻆ1;õji…]ÇFC(9×}U•e· uwñjj¨Ö3$µþ`º^3ÑUtRP‰1— Ï´arš#|Ù+xËMéôùlæ 6'ãÙé<€Éª‘ÆßøïƘ|q ‰Á‹éþî X§B®Ô˜óI!ôÂèR5ŸâW$ ¥€“¬da’ )weøÛ[K°úyjÑ€]ÄÌS‰ *\_ÊÔYƒý…e4½3ÛW.îwæ'·ý €À Šüm¦ÁhÌ̧¼ºxÂÅæ3Ä0“Ãä=¸;hŸœ#çýLN^džd@Êå*öã:§—©F„¼iDE‘(>þ]L}$ÚÀgÃûÎkE’4lÜöÈb°‡j›ðׇhÙ}î„\¶LãðÛwÄuûj˜·è,ýaν–Õ4'‚mŸGäc¡HÜ®io-¡FŠ™X3;µËU-Ú~Aï‡3@âtIˆ |òºª,p˜s­õ‰¦W¬Ž[µv _›„wÇ JÓ–;Ü#×¼8ÿ$0ÿxY‹]ÐO* éý?ãŸ\ ïÙÜ‘:䦱+¨š—\¹èóÕ þÙ¸”›Ð1Ëþ˜Ë‘™§äAÔº°L#JÄ·€‡w x€y3¼'õgõ:ÝSB3Jk=9x¨D®¾¼‹ðˆ¿*äÔ9äb‘ŽÎ* ôGwÿ1„ÈA£ò­¡à9Ìö´M[SH,æPÜ,'(¥¾-‰Áº ÿX|Y!}MïãŒÁœê{ëèý'ZÈQNÜ@L9«~´çîZÈ:V ¹ýdw4”ʪªª£‰ã-$鋈³Eå'½«)AªqOvÖâLj:%U9­…Ýh•,/£e:_=0F¥×Å´Ëæ¹Sõ;Qˆ½[Tü÷Hø½ºAjŸnÁ'»{Ûw¤4L¡šMèxŸ¨œ9ñŪ©×VXò[æ° ’¡fgluw›ŒÒ€ºÂnâOÜÍórˆ8µÛñbÉ‚X/ÿuCýüJ›Õq®^Ü"#7º¤fëë.èè•ÚN1Ò-“¸,Š=Ÿÿ",s‹Fc´R5546“øI~ä9g²lÚY®‘è bÚ][K1?Oâ%cÔ<† ¨æÿypÒz-§ƒÏ‡þ0= äôŸWÞ÷# ’žW«W¥ Ä*ø×®×Çöò‡jt#ˆ8ò´{ŸÝ зŸÉ,“ªc‘(Îg0ø:s˜Â@½1„B”}ZJK¦^Ç8TîÅÿƒñµW¿‡ÿwœ-«èãUpry·áÏæÊN·,È7ØîIbÅÄ[ÛþÊN )`LÇ݉'¸U ¦IóêXrã·œ>`/„Æ®] *l|‰jÉ|¸"ƒ€Ž*ÚÜ›,j+Ï(MÑ´g<›,Q–K•Õ·„Å8öû¥·ØÞ¸²ŒSÿSt÷‹Ç¾¤Y·_†,ådXíYÅ#ßâO(ŸíåUÝ]ã«ê÷¹† Ç#—Ï%/&ú¬]Ûˆdø¶l’%¸GA€Xñ·Ûwu]Iå ‡¬$÷ÙXÑ/Æ3{pøxG —}Fºr:üo7ƹÑßåOEìo°™tÖL!]ߥ­VÖ+˜yžHãâ«eûTðWù¾Òy„–ý˜æ•!#vsŽ-èóëæwXWýó`õ6¹·÷ždš.r×Å€Z¤~w{aLãòØ m0A¥èçôŠ£ ï6T¥k'pΘ»Ï”œFþ›¬º\±X ‹›¶!:Ÿa U~aKR1ð­aMà•K¢?FŠÍu΄›!ÎÓÕ g5/ë:TÖ6Ÿ«íu°¼]—ÊŠ½*믎ânŠ03ˆtìE ßGÞ–šEñ]è-ÔàÐöA÷G:IBˆ2ž;†lÁ1ʨ!g®ú•õC¬rcÈG¬ˆñy »Þá[ Íto81-Ð:%´#íÿ7!×’°² óÚ\Ò5#fJÏ­nåù-ž=·JÌÔøtµ?íþ:c±o¦Ý¬HÊ/›4Eæ¿}9 ÉG|-ÅõäX†˜O ˦Ÿ)z Ÿ¹_käýZðØ0*À%³*úI½>¿N5iì%œÀ“Œ„ЛÅóðçßKJ²š\wdÌ†Ì ”¨o±H¾ éq A+ò¸SÓoŸ 0–µIƒËò¶q†ý§nTs'ÿ–X¨ƒB+ÖxlÑáKªÐR¢îàýg™ã}Ûé·= Èãœ!ÞHÅJWå2Á¦SìUì1Ž€ÄˆPÔ”Ê1Wÿz?Œâ/€.…¼ V²çÉÃî 4š­Ïp¶}y§*[Âe½¼;…Žv° i1…ÖMe«\}¢ïÚóÓ@ô)Í+„ÏPþ&| D·­û‡›±îöÝ­À–ÊâsLƒÙ‘Ðr‰iDÛ6ghÏcäÔ‘0@íM2’Dy>ØñÓcSlnI(õ°¿-$aÿÏ$§²¶— ùH<ôlÅ•ýãd‡]5~Éè ˆ"ÄfÃb¹œÍ•G<&5ÖW3ôru¶Z1ÇI‚Â}Y)*`²´™€oê0c9Å+sY>2QîIo&ùQ¾QCn­ gÀ³ ˺¢[ÜÏ ™q‰Ø#‘Jý;Ï_%?Ú$¤…q‘&>>Ð\xRý#—t`Âx:C€¨¤DЩ¯t0½tdcø²´Æ:&“tÛÒý4ÒÌ‚™€BÇìü@+Ýò? VZ\'j7X`esG%gŠïœöX!jGúà(6áÛ™¡h:ÿ\Óö±•Öq:ˆëÜí²MÈYTÅr,ŠÝo-,©E¦ÞÃ!ê€4ÀtŒ¤i ŒQ€Äˆ|Á8§ 6½í˹>!oKd¹=L‡=ñ›‚k¯sø‹3…`Ral]ß/¦Oöêk­$D‡Zãû(só¸z¼âN÷âqßä'5 ç*D€ìº% ©<î«èBÃiÑãe±á wIˆK+Aoi‚×XÌïN…Ìzõ˜sÆ—4ëÏ¥3ÙFŒdäø à4 ­ÆN˜:°À[8óè˜\HÁ8GDëïâ?º¼3‰YȰ€=C\¸'É\÷4ÏJôÁ>qñ5åÍøÝV0FxTì½F\G#.'çÔÏÁ ªN…öôéÅÀ?ßšÈbjšvO’^ÍçЃw§Û {ͽ²¿g€úÛ$ÏœiZ°¶f†Scv „ÄÉYé†xd9ÍOçÁ»Ò©+Õc[=;‚m9´¸½#šê©ÎÙò¹Æï®OÛÝÌÌëÂDRàš¢0~Ú%ݘä¨k"´ÚÀD…ÿD€ô€ž­òæ‰êþ%šÑ³ù¦ÇôÕuä¾Ðy±³šÎk²n k/rš Êr”F=eúìxe‰L¦sÇßúÿ]ýì /•Æ¥`©|ÎEhl%ÝU†æÞ<4«0e¤FDÛ|r÷k’iàìµ®‰™Ýýj<ÃG¨·ž‚gùÛ÷isìøPsöxP?EÒq›ÓØÞqUÒ7ã ¤ô’TÛ±%ˆ|]êÉXIïña[ï™DXó …׸ÎH º1oD {.V£‡7á‹•J>¼b¹'ïMaUèùÛ ñ}Ôjž@„xRþlýš«. ~“Ùædt¸ —§Þ–ü¤X1ÞO¾‹'¦kÇãÔjËgÎLYµúÅȯÝvÂÁë&›¾9TÐúиõc«¨Þ”7(ø©’Ë!eD â!y×ò©ãüü>й൴Ó4â\vø«"¦/¸xÁ”5#„1JÜo]2ÄFõ¢ºHâ+ú½æ-£ý›kc—´ß,V½í‘úG†[’EºFÖ&-CY–S3–ðýdÆ2l r¹û%º¢Ï “’q/§$ég4ƒþâuá' '½ý B½W_žÅ„u¶= ¼\ÇzZ4 ʼq·ü>Ø%Qio_§½}±Ö: !d•± Èîn#“ƒ…¼5q×É8íÆÖãl1Þ-¾øÞjÀ?¸ÏÐã¾\¯ž¼¥o+,š½¯ƒÿqø] Æk#va0± jºâcppýma_¤ÕÓô×Ñ»?«m¶ž15jrzä`¡YòÎEHôË8xòB$.n}˽º(¯]® i-’s½ÒÁG¢›ÜÖÞ•F”ïê1k êúÊïO%WPòÉžRåÍÜoûEf½©C¥ÜNóÏvù¬mIOn¢ã67Rþ®Fé×áÞ —ò'^»vÞ>®0hÎÑ„¹e¬ŒlÙ?ˆîŠg€H;ýEjjá¼ÈêÙL¥YÏð=Î":=Žê–€Ú”Ah¶<ÿJ0N闟熒VKq$jNΠµ‘®VƒÕÄVTÌÎXj™÷[|#ê› N‚ïí“7Ç®+ùñ6÷F'UBüÍ”dæ=äñô9ÕÅ.&:gø“‹°—´Ž'N.ÍïUÀ?øÓx+ZfáN’Õ<6à-ÁÕj°öÊ#¾í¥¹<Š9=lP_Ð þÁä5±U¿M™tàé¼Ý‹9…é 4m85ÏåŒ!Uñ.†t Ó¢€@ï¸`–\÷Zú©ïŸñ™º1·waûoƒìª>>ÐYÇeþÄ; /~ü’•›w€^ý£°ôБ©=è/âxÔ7¦ïM5î•­º¿çƒ~­¬OUT‰aTˆ±Gué¬e Ä2[¯Ãó]&C[!Ÿ:þ©ðzEK‡\ÍVpšÑ‚£(QŽh/Šµî –@·j:upéÌŠȘdn¸S'r¹DÁQ?æRRÇÈp䄊œîÊ@‚RB%Q\<ÕÏÿ ¥%Ø%}z RçÂh»>$¿ðýIœò^2Êuo_{‚ŸeZw,bfÆ>çžÖH[¯­ª¡ª¤Ìÿ”3L È?ˆhÒbÞpŠº=Q凙Áùù>mŸ$ŸVšÞÓqXä @R)´Â“ O¿µ†XƒýÄ«u›ñ æG iR¼ôšý®’™ÐߺïÅØuùÈè6¦ŸX•jꔈþ£ÆsÀçš÷%Ͻl(Œ„°¨x-šÿs™>Ý·à kÇðuèÜPÞD‹ø—ö·Æf3¡íÕn«'R“˜…‘Sî´ÛÓÞÓb’Ÿ¨B°Ø8Å’OÇuJÆ^æèt¼õp6l b.NQ‰DŸcæçÿd>D¨ ´ø¤©Rd#jÆbvë9ˬX&<ÏfµÓOùJ\2Øœc‘ǤƒmÍvâúÁål;_ÆQ£Ø þ¤-ή8ð… U™w’}:Êùié¬Á¢÷ƒ’ ÍF½^ÚXÿ ÀÇÖQHØ`’MÏ+Öá¥2P~Tˆot6ÔEióäásDD«Ò3=‘Wxö`ç Í1ÿVèù5Ùb]¹5Á]Ÿ!uŒ‡S˜ÄDáô‹S.—Œ§œDÓ¡t½"Ÿþñ9æÍ ¶ú„™DÆ•.Ýpª0é{MH.À\&ŸÂ@°ðဠ&?Â,g’‚¡ô•˜®Ÿ¥Úâ%ýe!ò?™þFÀ<)F¿Ò^P ª°a6‘dž„‡qA‹ÛŽhyºá½Z€“#ëë²¹¦µJkŒBAZhBDÝ\¡‹œWê™qù©¾_yØA‘ fò<Õ¹ÚMp¾éâ¹Ð1  Š8à3ƒÍFÒú:GÔ–ÐN­œhÑ'ñ_íÉWà*¢{oô¥_Áa­'d0ç쫳ôäÉ퉆Ç}ŽÞM_ÐðmõkÒ®Fœ` Rƒöu:êù~og-‡…yýM9 N`S­úljËI¯:£ Øþw“¡¼ƒ¡ {䊌î­ØŸS˜â•Úcz –¼)CJ}Ýäך¤ó‘÷bBßêжyÙà Ž8µâ“Tâ›FàÒ¹ ½;³}BnR*,Klê¥C»â B­°+H’Ô"yíäÄë³rxD¯-߬MU©Ì,Q­½¾ÊãDPD.q)’rÈ26$Á5¢¤8bßýzt¥¢úsµÒóU~YÔ¡¯ zíåÝz tDA¦. ?<-º\ºM³>"l\ARtMªÂDú•þ†«f½jm Èr¢¯ú†IA#ÉÎ:)­UÀCS-žôÌB[òyÞôÀÚ‘žW€aKç°ûùïeúŽ"Võs ¤õÔZÔj½ö¥‡lsÿÀy‰¨r2™Âžž9Ëšùμ¼4ÆO¤3_·Ø«¿+9•Dó¥œJkÀÄÚLÐÍ·„Ö86óˆqB2ç¸eª…ÞÇÛ‚0ŒÑ˜ ‡nlýظczí‡}~ Võ%H Ø—[3}Q&®Ø”ü‰”Äb?þ#QùàÊ]<’úÙ£%¦ŒÞ2ñ1zÌt#ô¨Uâ;?[ªÛDä)ð±g$¼¥B µÁ„q`·û]¾Î얥ݞIîPá3¸L0,Ÿ°OÍEàgáR°pÖÁ| 1»SJý¼Jñ˜ §*Qé a®¬.Kûí‘V«j×ð gM†ó¸D?þ›M6ù Ø;Uö @<–n†@¶¥  q•“bŸy¥ª¦Wõ¦pxÃxÀ ¸Ë_`Ü@Ê5õòl· ·…@'`‘ü{3òªÊžc\v·OÍÂäþ‹¢K]/? „âµ.â&‘˜\÷ï—†úV—oå$ó2YÁ(üx5¦Òï…¯¨3rD¡5B ©×D=O4qL|]YÐlIMI3€x3ÂÇLjÕóõ¡B+m¤»K'5¦ºP®õßZ¬N`4ýì&¦s%PôFL š¡úþºÛZ9IR.ý‘½é¿_54ÆÈb\*~Bÿí±Ã.üÏJ‹í¿.Ù¢ÝþÕ`£Èñ¡‚¾³cY%cpøúPøO! Ì0ÍôÉpУä]*â” Z+|3Ó@n.Ž­÷¬õÆÆZØrÞREë*-K2kqIí°Yºmº4æÍ…Ÿ« é|VÊ;#ÛÛÆEE<ûÂRµXkcÞ ûÆ?,=æå•è1ˆTÐ_T•Bu^ÐLÙ/?;[ßA9û ?ÚF…ñ:-¿éPTÉ!Ã!N¼È‹iLjAÑ |6F0‡ÜUÚQßfs’Ú\wI"ˆ¬GÀxU²‹G¶µO9&UªFFú$èàüñšëZ Ç/Ê'i¤XBe¦@ qÖIûºMÒ¼%„™$½ôvné#±Hퟋ/õù[v’è˜aW:dæ Ñбv+ ÷Qª³ñ’a Þ Ïæk.¦sP5"Õf Á')E“4¹#Ý/×ù”36?ák¤ˆ‹„à¤Ô x‰¸pÊ2SËuð%ïØÄïæÌMIE5†.<÷ò¡´‘ÁnÖ=†€0þuñ Wah£s×VT}×£ñdQ²ý”456n¨Ú%ÉWbFÂ9)–@>kôžbAwƒ:éÓÏÄ¡iM>a.þòà{€Ê?ÇÁ–~ƒ ZªR’-abïÀwiFóÑ^>úUoöNl.`º |õ‡u‡NBqâÐÀEÅM˜ÿ\ïQŽ©/YÛyS¸–ºßv²©m¶tq˜âc*5æz¤\IAmwåG{WrNÿ`U'O"7,ƒÈ<£nÿ„ÌxVXçbâ?ÅÜýDÞù‘çTÔœ¤~YåÇ¢íª{+V:]ŽRYù "g„ ¯<ÑÀÈbÞ%>ƒ@mµNÐ…çÎN>ˆÞÈcM‡@úŠ´GÛí¨òaqqå‚ ¦+»ã¥(a|Áëp½ v/R¶±ÂÑ^ÿC¼ÕË_©¡žÆ¿01nåÊexìßâ¹|Œ‹„à¤Ô x‰¸pÊ‹½Â µXç%¡»U9tнÍh ΜÔ{Ÿw»Õ–L¼õfz¸ùº¼FHÂÅñl®`”G`t8öèÞã×Uÿ„ò&B<@Òƒ“rñéEš[@Þ6},Ø?êÚ1QTÛf\ݙ͖>ÑŠìSžRY:<ü ZAÅviPQö§ëJlĘ͒&‘L À°2éI“¶ŠeT·xíêmW½°Ú•R4Ç·„Ô¨üÉ^Á _3R5ø–˧ŽBÞ=;Ì`m\`\gûuh¦ñ_¥¾Ê¨À#vEÛ{ðîw UøP™MPÅIÁ$8X*å‹C‹†ÐÕ÷¹íÁÁº–ÛÚÍŽƒ|7®`ò¯ŸN÷Û@¥pÑ“X‡ÖgÚºì¡U7OÿáÜŒ‹„à¤Ô k\¢À¿¥‚_ý c•®ûæHÁ#+¬ÖóƒO3‘£kØt’5mW«’ÏÇgCûÈîlš¯¹RªÂXœšßïå=½U-ýžŠÛǵD­ ªÃÛ™ôéâkcÅS=pˆÕ0û¨(º¤Çz†i|Ó¨¡`„w(o•ô³æIÇÐÉ4(Ù oõ,D`ØO|%¿a~eEUì&õœÑcE=8RIs¡_$q—©«Y K aè(Z;ln ›WZÕbf$·³œA2‰Äý/0äwÀ€…ð˜7”ð:Óøö o¨ÞoòÅK“ϧš†hâCŒˆ1uO±~¹,âéÊk½‰ φyÜÀBÃE¡F++B8 PÙaž_]“*«¡%í|`êEÙY²<ípþ'=Œ¼—‹Â7ÀLÝ7¸ì±’Ðú³n½Ǥft£°[ˆÞÜë‚ÌPR[øÓNe Ïn©øçå­S¶@Poüó}»½>ªÃ_Ugûw_øvã}»]ûuCöô³ÿp7Û¶ýöë¯ðìëøuü6Ëøkïðêg¯á½wÛ|kí¿†êÇï·gÕ°÷Ûч~y_‡c½øuA~gÿF—áÔÄûzJþ}ñþÅ}µw}µÇðÜ/á×…öë7ðÒßáÐWü:Y¾ÝÿCP¿‡DŸÃn†¼ =þíxŠàÕ~öŠÞÚ rÞZ¯º”ZÆ9ØÔý³ý¨¤ÓK£ØìÁ4+ ‹á¼MZŠ DÛq÷üäóù˜‚s6„!Ê‹v .“—ºˆ–âñ<†N“ÅÀýáæñ,"Nß7MðLkeDÑ$‰Sµ"£uÔ[Æ¿¡É•wcµlÏ%‰Á JÜXÄóÔ™ŸÙ€êèq¦¿:4Œ¸†UvugM¤Òë0kbäMŒååÏ}§Œí€¤¹ó½JaŠQï‘fÄ9XÔfîà1h Ýçˆ÷6y§å˜…¾BÕ™ÞXÍlb-iÎæc†1ÀÚé–E¦˜@‹SäŒzÒòAfÔiG_ÉÉŠ©S‹ÿO+¡Õ]ÜŸ‚ –÷)¤ë,žÒA.²o~‡^‹{fÈ-}§ssº’"Ì@ö|fÉËkÙ¨Ál ì7?N¤ˆ5'ÚE·íÐ¥pò%í*#tCMO÷-ˆ—DTßv‚J¿œR.:»1Í~\nfeBtA%€»&(LÊRü PÓýQ6ÑRZÀ×–°o!3_rœ½]yÚ2óÀsfÝóȳ58Èo-Ýœ7¸±‚3*bAŒQÙ›–&í#êAt+x>CànÙ\=^RÐ0H>5ƒF~Ðoå¯çÍòôf<ŠÜ´¿®ÝæÍrÞK$ ¿oÝpÅiš^‚ÄçåUè®g$Ô¾ø>Q·õl ŠCò{¯*0+cËÒƒÓ¾>Û…ËÍì±1Ü1ÎÝâ¤KaYŒœ¡F™HàÍÇP@¸hG6?y5Ó˜™kzljµ÷¸Æßä– x==£?è°}UbÁV´þVó¾&¥rPlÛZø ,‹Õ\píG{³gñBÐ|÷§[M÷>K½A«½KŸØé:Ûq]c­™L£„ׇ0W½ÒÓäËÍŒIø—ÿÒ³roœï_Þ¦ä)3S³ðxŸ¸¹þníîü ¿ Ò·x tüÄùÅ»abnZ[ÿ1BÕ‚:èBZžDÒÁýê€×4G©zÕÇÅîmÊëÁœN†¬%3§KjøÑèœe¾PáB9Û«‚b÷›`$·pmÚ—P¹ÚF¿Ê¹Æ¶ÏÓpëÄI–RŸZ^¯øÅÍÊ ÀÓ‚=ïÖ©.ØËDÞjÆìBT4+üRÕücY$-6ÙIÃÐ`»ýSþ„%M¨†n#¬“¿ñ×8}Ø…ÆÇoÇ#×N)›cDG7"›©ÍœRU `lX›kþq ¶åôÛ×¥@ÝŒÚÚªEdw|ôΪè× 3oØÕo!Ðaöìõcœì4ú®Ï¤ø¦¨Ç|Žã)0æ Ü<<7Ï*”KóTØ‘§šQáøtË'[H€w žÕ˜1tPÕ:<Åc†PÁ‰o!f#VDƒŽh5¶]…„H¶‚ !ÃlºçݧN é³÷Uçü21 í‹cÙ­•,oº%m©ÍÉfÓF‡¯:1ºîeN¹XœÎa2W9õþ˜ÀeKËíÜ)º”E+Ë«çsñ-ŒûßÄ*~PGͤµ 4L ˜‹|Š;Ÿéؼ!#’i`€Š›äTVÎöñ*•«-*a™vʃ°2¦lÑÀñÈØñêú|£%Õè;§ê²îZ n`Gã÷ÂõéAÛjkîN¥²ý‰Z1$º™bóáeÆÉS-š’r·œ–í5L‰Ãìh ¨xYœÒÜÑà~‰ Ç^G“%(ƒ è¢K|Z(Ë¥ÙDhù”ù}ÚRˆÝ¡ká>4RéÃeÀ &Á—fã¼röŸƒãˆuJoÉb 膶û×eÀAÜ9À]%g^­^0YP É©ƒ†“öêÝXÕT£÷j¿^:–`˰> {† q‹?ÿÿLÈN‘!ûˆ²»¹hQáþq5»ÜW<]Qß>f$,ñþ¢8¿ÿ~ž£ÊëÙ\R#â*?õŸ*ÆÙo$H>Ÿ4‚å}¯®—hyçZâB¿¿oOxèc,̾:I+BÁŽê$Ëî¹Zh6ÀǬ·æÜ…Ó¸<¢¶Üü˜'ˆë¹*ëˆEhô‘ÛO<kKŒ€ïQC¬ =¼fæƒ86&Ë™8¿0 ê÷ ŽøÎOާ‹4ó?Ò9_hŇÅ¢#";_b;l2\]]ðö¿S† —ŧÿùö‡@¾‚‚¥—p(º¤ªaUR‚y­Æý–5mk_‹ÿ(½ Ü#S¤Q_[u )6£0*ت’ \ó¡•›‹x!þ”Æâ+-æ.2QíH¥ß'¿Ô¿™p[iÇ3ðËt…^†;” Eæ0}rÆ€'{kÊA‰7ÀkÝzŒpƒ^åÿÿ¢çŠö)Ìí'Þ’ù‡"]xCìD¹]Âް¾è–~É ¤Â1MÒÑi¿¡†ýJè¼í¬I™ûÂáÝÑ¢“BЏðÖÏÁz›¬§VÀ¦½9&T•3ž¨Î²½pLŽlm´V¬€iã¥áfÑï 0ïfÁ4½$ ÷á$g“`Ò7š–¨gmrîšg÷†\¢pMﯙ;ÈI@ÐGYÅÖt;ªnMǃ0iNìûÕ¦EÐÅ`†Ë ‡“¦!~ÅÚè[Ž7ÊÂÂnM6£}4÷n?/x.çZÅ~Ú¨òKú‚ÝÅ25÷4;›LKDÞMàëø`š›Q]Giðd–jKgp%X†kõ) ÁчlÏËÝRÜÑmSé@€Š&ÕK!»“f®(IOé $ŠBâ!—)k!æzE܃”ÑéÔ?ÌÝ _ÙKI>˜wNPž&àç’KúÅD)ì݇›æù§–=û‘³3>„.•(þ‡Ç´'Ù· -3MøÁD5ÖI,°¿;*Uµìnøº6ux>ô ù‰Žó'Úºʪ8QÓæ¶»Û¦Û¢ÇLË2JS|]‘îÇŽ^²ç¾‰ãlaG®Þ_ÿ}gÞŒ¬Þ}àj„7È?µ¹r´è^½ƒ¨ò’»ì˜ÏZ [c¡,DA¨ij|˜4—¬Û[Õ©¥W¸…;‚ßÜzÀÇíOg-øp7x#G ¹/1Æ×gÌ^yJŽ0ƒ2Å=σà†þ<)ӫЫ1}UdV U±Su‰QxM– N¤ÉPw#é2#îÑŒŒ$b›Þ<@¡—Bÿ}±ÿGéÈã”ÈÆðT†ŒiôÞ IšRCP‚œ7Ê5ã!áhc:¯×Ÿ ºÈŸ*+»v²&$y¥, LÄ@Ë_ÞÂü.™Ÿ×(ßâùÜdϪh.©ÐqmC Àú+{±ŸF"2Õ .”)ƒyVDFmšqxRHßø?ø8xä>¡;æÉà‡ö^0 Ã@ ðË?¹@“VX×RAë¬ßíê~ÂE 60nÅlãï“g¸pY¯7èW‡°:‘§µf¿ªÕÀ*ðT–]Åñvì÷2úž¸7‰ØþBõ릖QIHÎF^EŽ÷˜=©¯l®ßèªDÜe¡þ&›œ$Ùá ïÜ OzâyÉ5j€IîxFD¸­qö¾õÈÁ1nU+°ð85Ç+¿ºµžWp4í… Ð¢í†º¶^óâh´€5YÄ··Sò#áöÆ|\cÔòyæëXfSŽãÛ]>']´¾ËªñNñZÉà ž‘œ{'ÑN‡ÞO3_¶ä˜ n§‘”“£%þˆêúù 8¡Ôæ ßiKq´»v˜ QÅEl{Þv±Öuªèúo†R œÀ7N¢‡4ñŽ3\šõiàl|&CÛÛpH”æ`â§ê< ‡ÕÕÓµS¿õ“©J3K¶Á'‹5™Q¯÷±ë¦J!’éв܈Ïzml±¡…‡`Ï+©Z-‰ýP.]¹¿š Sº~Âü7Ë5½ýÂY˜ž"ò隷‚8£”‰½j¹¾oÊ“öÄÌ‚ÚÈ>`éwa#=­ÒªÓ4˜I,ˆë ÝÃá£$±`7ÝU­fXOÅU*p@çŒS<”~ßÃbVb eS&p#Gx .—WKžÚ+sÅÀC7ô-²ñß=ÉÄ¡p'þ°Ë¸ÃÎ}1Bs5gׇÀñ?ïRSÕ3>ŒŸaÉ=ùÈ&¾â+!¤~èá¨u°Æê¥èšÑ’ËÆ¹oêR0LQ/LIìñÐsXw±‰9àôh×ÝtéV¹݇ïOIz!®U2-îV–ÁàùÙžøÔ>|ö–ÕŠíÃñzvcF¨¥ý¾Ð% æ†""yl»J£ÃÏyQ#—‹›ã¼xÁ(?iGDÃïÇÓ¢kFx'ëÉ]ˆÑ€{qfÔot‘”ç#uŸÄ…Hÿ~ü®ùgÇÜóLVùD°¨3·ÜÂZ´Säga÷ßÖJz5W בÿ <ºÃ`Ö¾oÒ-’íÆ-†!mê_µg%Fȃô²s(Æ–øƒ¿]£›Ç4é©úät®IVs?8Û8éÁô&…øPúY¬‘¸"]Üol¼ ª(…ÿd‡áS”ýrô8š˜çÌr©œûÞÜô}´éyx^U‘9Ç1]KÓîÑA€\β^îÒ¯Æ6Vz?Çàëéç!Öù' `0…–!TµÒkáë`?Z 8;P+>3\\ÀÝUõ¯0Zlk°\G7nH¼÷ˆ[_4g  ÒkK­  ¨yq™ó 5JñEÖŸnQÉØ]K°Öq€bÒ\6PÆðÙM¬Ž»¡Ãå”sÒ³Aƒb7úsa‘KU5[C"Ïý™Ÿ[¥)½8Ž8f£ šw‚/Á•µœsKjAsòA¡Öâ89Ѓüï{Ÿè¾6 a[ŠI܇ E,©¹ö9ª‰F·y0&þ‚m:D½Ž­ê0H~©@JYJLî5IvJ>=ƒAÈÝ@ñ¤ÄZµöxÃóêIzEÒ~‡zýÜfÇQÀ™^ý Uû¶LÀ¼ÕÛ19ËÕå£@>/©}úîƒÇ'êk (ɽ›+øwXך®!@úO4"ÿ;/nD5-K¼úö¾>¡È2Ð"}«±Â7CÀTýŸ—] öAOîØ¨>hÚËú8oþu}h"[‘vAEc¼œ9š`Ǿ¡Åu V~ÃS™y*(Vº¸N·ÏÞÊ_è¯Õ8ªR¶+/!9UרC3qÀîÝ8Ç='4¿2„êÚ²Á¡+p,`¡Ê鑯çOêz}elàVÕ<תI¶*jÙ¼:]¯4>\|é:×r¸‘'›i¼ð¦ËTÍ&Ç(*̱žq‚çW FÇ¢ðPƒÇÆ 2áÕ#ˆWèxŸÝmn%ÞYq`&mpô‚ƒDx[ç\thK<Ï»÷kÞ*™rÂ ŠªjÛ>H“åÖV!OÒÝ»ä.¸±’Æ) ª6NT׌Ã\“ùÛÈ€ôN‰ó¹£­T„~DeüóUã(Z*‚l–“¡pÖ²½ÆLͶÓüjÚä2ë%XÞö­O ÷¢¢ñk¯žÜTG×EqÖüeV ¬@SšíK3GvX†*‘KEV¼Ê^ ”O‰¢B—ŒÜþ9‚ßð}\u¡¼U|ñ³¾ÅWï'bSæ ûQN²æ*ÞF)ûÌ^ÿ(äT`Si&*¦º™U_i§Š™Ë6[gœ„4iE¯üüNŸº§mê\L<u}íë_–„Ò1BV¢žÅÎySC˲ô%žUá…˜búNF‹Þlâ¥Äùè9oŠ÷Z6þ{>ú‡úBö’>'Ð×L(ª >$¦¹ç…æþ£EÝ€—¬ÜWµJ„ŒÀÿüû/êÞÙuþ>K”ú-[¡®d{¾„[—R ŽŒ[ÛCU:ž2-FÙSƒPR*¹Ü Šæêù«¿®öà Y]FÁæÞ€Âî¸k¡:Öñ¹U+'?åiE˹NÿdϺ¿ë?7,¦,ò¡Zd¬ݼ$`JPþñÒësyâ8`2¸ŒÕ\hÅÖg¼ó…·DÍ“ô9δw>2Kê©?‚dL5j׉˜™}–(DêNÀoÇ«iëûÕ?'ßå››9âïþ×#‘÷xHá¤MéÎþ: Ý’sðö©lLra"¾úáäô¹Â¾4S¿ï’G÷ßZ»ÍRçàØ¬ä•ü^G}Îo&$ÅÉ•nʨ­¿×Žax\ÇVÈ¡¡ó":Û|öªÕ†ã(Òr /2’rKÖ(Эê/íÎÓkÔ\:Ž x¤ã´0ëºhì˜ûãºÀxyy~²I‘£tÜŒG¸ÍÝSP9#ÿ|àÏ›§Ñ篅eƒÂ+FXR_<¡o¨ñßáÿLW*5†ôÒˆCåkúÁMß¹GË+y»·£*¹þª—öà•mv½±þ,hx´ñqC» Oà'ÊzS@Ý0 šª|Rˆ×Í„mÀÓbd$(Ð~µÁ õR©Á  ©0 _Kmh#x˜ƒ¤ØzBÚÕ3ݶþ%´ÙëOÿg•|WU¨Õ|“ºÛ¡] ëV’°»Â« ݤ¾š]w:`t¦lWø‚(åøK—À=`2Q¸n¶°.xX‰¦Y𙊂&ÞJ&v,y©ÊxVîZPb0£q‰î~‰=í;w>ˆ´ØKÒ°•u•pâîj±A÷Âùj—]*³™}ËN¬¬ Ƨ9a;Á bl8ñt¤¿ Ç80ÖŠ¿ÓÊ®fŽÍhœtj´/3õÆÈÏ·XõŸÒ¾7Å‹ÊÖËq+Ñý"6á0÷ O†´wnQp1jÉSDØ2u5üB`Ä2a~èîžð)èNòUÀ'8uq^Œž:ÝŽs`WЇ"ƒÚeXAyô_óKãOº2e+÷Õ ²µÆtåBÜ–àþ®iN|&%ú»¼Ó$áäô|ऀøHë—PqQ›é±Ès‚œ‘ibʃvh.Ã9ÈËW¤b"/7†~Ö E'àå )‡S‰´ˆÙkl£*.}|g[¿‘cë¶"°äWÜ™ä„Êв¢Q±?ÐÏ7É>Ûÿ/´Nûì˜mz4™”!âੌ9™ywê·\`ÛÜØûߊ4€ôÁ}â©–6QÜP":ßøOV É7†U¤B¾¡€[O3nÒó6¦†‡Ö—%÷iéi_-=õ—³±öËndqcŒDŸØƒúöjÄëîÓ4 Ü]JÇ¥'ßá;<þe»õ®­§?³‰¾;º¯Qˆ¬%bØî›Ú[óø ®è&’eø*kwÐVò+·‡˜ÿ*ùG¾T[þZ¡HGULÈ>3³ŸâÐ1cwɹø6¼nu‘P쀔¥Ó+5GKù(ü©WtÚ<áë+ )<ûs2Ÿy³³Ó„g¨™aGÓ¸Ikäˆå¶ºF€rŸzߨ ›ÉKÐ,K]]:H]N\á¸V,aЧ~‹ÑQDq³Ì¦šéQo§{QÔë ûöX{¡Ï¼Xm^S¢cI"hmº‘ÔŒ´NÃÛk¯ŠPŠ4 鵫Ü'Å0@+©ÂúuŽvî4OÊì¡I>VjW©âÛE Ô‹GãØçËz‰ýk}¤8~wÙMæ·¯¯ËBW n?&«R€¤­O?ÿÿÿ~ ¢ˆE¼ŠÎ8ºåJÁ÷V(«‹@¦Vs‡df'tiqh0ä¦à$øpM+î„碽r„*HåÿtŒßÊ v Eê#JXkàPy/lOýÖÎÜÛfÞÛ¸ôÐAëX¦Ç"¥`ÿvXIØx¼×‡äqu< µ>*ºJ’Lþ9çÊ+×=q]IÊ·b%k»ÅøÂÀ“,%´d9PÁS4¥Ëö‚‚‡¤ï7ÇgI€ÿvBÁ½„!é¡=Öâ=Áo7ÀÚ/ÆÍ½TÝäÎ÷‡¸Z8 쬣v:3Æ,ÿ!!çkcøX¥­©Æ‹¸F#œÕ‡'¢¾ÿHa]N8½Ý¸dî§þ¬"Ä%Ùl[R»R¦øö¨$-ðÍõy±dz/Ÿ«>fÖÍþKhŸEH˜ñüı¤oK1×/©Ò“Èk÷ÿ?A¯>Òð~Öoa·ŸÛ\+Q}ʤž‚‘° ßC³¹­d™7ÁþØ2ÀCì¯cQAòÛEÝ™Àì&?"Eƒä$á/¯]«ïÀ5ŒJèZ† vC=ˆ|Z}9´½ÕÜkCµð-ÿbÀÖΦo$ ­zÔ ’Ñh¼¶bÊäh)ñ‹¶‹JÆÞþ³ñѸûŸÀzõƒ¿gP Ù"AÕT³ƒÇ‚dèTš4ꈻBv½w­AüÃõ=ê7ZÝ~ïe¡ÆQhH ñãð̓GÛƒd°±9–4š†ÓŒöéÔŒhhžF²N…˜øríƒj†]Gf=‘›n¬‘ Ë›ZôÊ8Àgd­s` Å J€ؾÙRcåKbGT)Aƒ”B’â!R2 -‡ž”ËÆ-¦ù–`Xðâ¯ÓŒ¼vi¹·0^_ÆZor—ÿmÑÙ€TlŸæ“¬€7‚\ ì>¸’¡/ø§ê \»d‰ÞdQ W!  Þ4ï÷8ä×fË^,WóÅòþr!ˆìÚS&øwû軃{E)¤ 2ȇŠúÉ5÷QqáÒ„Úß*¡òà‹9njÓ+qçç²!é{¦8ö¸Ì¡yQK›¬ˆ ß„!ªCã9 ›4ÙÀÂ9•ù<½IoGÇ©>=¾ƒ”>Íb…À»ß]&•Ç8ìb«¨uÑ8Kæ$áA+•wWjzi%Èfýý>iIPà/DŸG¦É\OþªÃ êëÛÿrœ\` 8àå /æÉµ#±4ézdƒvGÉ_§Ì±¶$~/è|8°ôbŠ‚dóA¿»º¹,˜»1ÞáÂÛK’ÒÉTÕWhC9ú ›Û_øñzþ» ѳëI…mL:nÿZ™@òlûå#˜·T¼ÅìdUÛ|™ð.‡€ šV­×Âåä6ìD>P¥/JÓ•Ç|ù”$ª8±C×ÜD  ôÝa†yõ l `o”17/F*Iˆ½ïǰçÓÉóF^ ˜ôMª_’wÑ¥UvŸ§Š\ÐæT20çº%µþå('úXÆ£—Òës½‘ë†S×½]‚~Âñ¨R‘› ®©Ò¡,õ`{Š´sO¹×T-›]ý8t<ÉÉÔ =5Û([ /.¶Á·«›`¤áp`á@‚™>«'û‹©[&ÁevTi1°p¿o;X°Q ëtäù%`<:'¸§ç—/‘nUR)®ß*AZבÔA‡°Æ6%– ïqòTWd²!e;$ÒY^Cô§£j¾äV÷)”Þþ”§i×<.;íÝ~ì4$½/"®h ä§–Ø›žÉ[ñfäûyœbç*aSë²,•¯ur 8)vVí$áì_)¯ÂÿGi=ËdÁ?ŽpŠsz&âW†á²l$:6lim £~ts!~™H—cÀª ZÆìxMú@6,Ù®´']t)waê:…Ò‰6ÕÝ!¢û…ÙÓo޲_ô5ˆEú°ýÆìÕÞ¿.Ågš™üç9~ÃÖXqÏê=‘¢9I€ÂQûÕqÀî¢îŠùÌb¶Rx¦G*»6Iw ůs³ 9¥ëXX“}êV{ÈêæVÙÿ({TJߎÎÖ½m)ºÎ·Ê RØ‘1îm»zL ±'Dâ¦ã²iJÔ Ë²[zð …À=` FÕ’Ù]ª2Uß}CTë…ÖO_WGt}Á‚˜ãýuH3Ú9ƒvboõÿ)XÁV™Ì¯ÏvÖGöGË㈷CÐ’P~š+ÛDAÅ5oŽîfŸÑéñ©H‡mK<8ï8Û«géû‚ê~mqt)•‹¹7]{ŸÏɆ4»Vñ•ê l­é,˜fÛÓä!y¼€ÎQ1ÆàêHzÄÔ­OM󑬳GŸB—÷“¼åØû¬Œâ6™Ðå?Ü5±*Sýþ…¹tŒøõº-`GöõÚµû·«uü–GÞŸ·Z<7¡@Á´sôÅñµ•=×ܳHò/ôTíÆ¬«xs´5ü#;ÉŽ}Ö üPŒe"$âåoßzøx4úª¯¢ƒlÙi²³sˆÅQþ÷I(æ¦íã:tÌÛ@ôD< Á—ù[/˜Âå{×M¢EYbWÔ±Ó ¥•4,€<§ßlt((6Ëp‰¯^ïÆ/ÿf˜B-}÷òbú (»ÎôÁ×]¯*èͼ„ôÏõ†ž}äk¿¥ìŠŽðÈ䟡m–¿Ø4Œ nRã$;¾·„Íá±ç‚|Kà(œ‡Ov®ûÏz*š[„Í–¬ÄãŠí»í“{O7ü\r%¾²RŒÍ€ÚÕ‹EtPÌÀrµ)ÔÅ=H¾DÞ _—‚$Àަ¿Ü¾J‡ÇV>Šst?š²#4¬±Q{ùóÓç,?áçÆ{íÆæ£œµó=æÎi3ôWÚˆæ´Ê"Á3Tµêoå¦[û—¢½pe\è=j‚Xƒ¯€“$­kõ}6tJ3}äÓ5‹ËLEÏ(d¢Éi¡«‹Q-¬=Þa¸}¥Y‡>å[oy¹*§Ð¸›Cí~îo1×{mØÜªýÓ{)¤1±¢*ˆìË­CRÄ&¾®ðCZô­C‚•]Í ýÌDZ|+‚ o4&6ólÓɇøçÒ—E|;YF o¯ŒÕ늬B[Ü[ì'šŒ6Õ׫'!oBbÖ÷憮[“ Iºõœÿm„}*q0¶—ŠAÜœôµvÐÑâ¢úŽá͘±šQöTÒâß>ªÄ :xgÆùææK•'y@(m‡zLH²­CÞ=Çà#ÞFwå¾-çÒèð].ø7w3Z÷fØQ4M˜=‰ã–6c÷ж爗݄’Pßy’úh'4;3ŽRÌ`ï O‚<ÃØo:g@t©™í—ý‹†&·¡ ŽM‹­Ëðè8a¸=ü® ¼8,þöv0)Iç×Ûl­ù,HÌ¿ïbÒJœ]‰5" pkT&™Çß ‘BM¹æ|ž6ÙÓÑæk|XŸRc¢6(ܘϵ­'kXŸÖî·]VÕuœØø¦¿TQ+¶ˆí•ÌÍtäWºÅIð ¡)¦Ç°öšMg*®†_ÑÚ¡Yâ]F m —.Wàæ:<áÍé=8{^:CVç.>ê´8ÖY±ß¼2Y¸­ö¬0&U•Ù}lCF¢søÓ Å>jg'.us’°>à¥ÚÖÉçí+¥i¾ã;&6Ÿñ(Ü” âðº·YÔ%¿ý¶X!ÚSP¥ó%áv”ïÄ·ï{ú»5;OÑIhG­tÏb[¨ò`É÷Ø+›©Âbú–ÔtyÑP¯˜îtè õ³î‡µD8fÃqLËçϽÄ<3»Ž<ÍPበÞîÊyIÂ6oãϬ¸rHV±¬ù· î]'þöuÅ  œÌþ—tëA™ÎáéJ$ OÈ G›b”Yµ"U_½jÃôYj΂¹Ûò`vǶ12é8}Ê[ò6úEŒõj^ùù†H ¾¢Š³ëù+Æ™p‡Òß×ù*6ÅS/£à¹³¬Ñ¨Íaª·A©{Ìãúp(%¨›B™uj–®//Ù?‹!KV€ÃùœOá…\|(´[y_»@@hÎå<›„-Ëol®ŠQ9PÙñööàsÂ(D¹/.gÁÑaæ‘°sÜ•Úos)+“õbHN¼ŽâD¯)L6Šc^‡ØŸBבtšIP·íçØL1uùý6uwI#킬Æ*ršŒ¾Ñ]#–ìUá+r|KïI-Øç,,Ý,uw'=qß ÷ãÙ¤×B>òõü>·šö,.UÐïûQ ¬­ª×MnSÏ4Ýç!ÿo0ó 0KK ¼ÞÛQ‘§Vyî:,àþ&µò(êGîäHŠ{cl§FyÊwQ¤hn3×]»¶ÄVÙë\í‚×'* 4Þ?ªWG—‡{,›ñX]1íŒâ’¥QsØ>×][?¨(И‘÷r­L¬ÖÐ[Êc §>G{ Ó±éõV_Úų¼‹deæY*Ú·ÕÚ~­•ûbþ+Žàˆ¼f¾´%¶Ž7ˆmÐñ½¡Îñ·.§pG .Äîé_2õɯâ60H2j"Åf7Gï€Ao&ÇÇón=h5xK<ËR/¤7ìÛØS7¨@ iÕz0œÉD…žÒ5ê‰`nŽoj«¼â‘Þ’iÉ¡{㔢a)ãoÿí±¹]`Åp¹Ö«‹¨8÷ >ùá½ä¹=u‚Š)PJ:ÈáÑÜè+»$Ÿ*d½³×µ«_·¢°X=ã’š= SÑÑ~?@ÄÛ¯žnJ¶å¤ö6È´Ó4³€2p"y“„Ú °?ÇJrO喇Rs;/Q½+øˆ°_ªLñÙ™ì<è…É«iÂè9Ëlí?úÒ¬tΛ?B‚AA"T$á=øþ0Þ¦#IEp§;Š7'®ûY­ ÔaS"S6E‚ÆGY!LeÓ(©½ßA9<±ú­Ýþhrš…ò÷„,ä@Ü.2ß"¼2DÜö†Ú;ÿD:µÃ¬2Fºû—ÓkÎîÏ­PTÜ =_J–kÐc’­lUàn ‰sÂ÷)ƒ¿‚k¼³bØêOÍ ‹‹'tÊd”Ú}§Àý$Ê*½ôj­òY2¡ø: ˜{ùWxû‹Õ”þ 0ÒöÂñ]ô@®¯cåu«°U®yšùÄ"™`‚œ¯’¿=Ûõ£3xÌ•p†Lp¿jƒ5…­Y.îdÚ’ª¶b¥ÙéaÁ½-JLšß7TX¯:bé8WS«jÆÞ‰\&T-ÏØŒî{ýÑÒþÜíuŸjŸRíAç'o*½Eàjü¼jHš‡IN >:˜ ”eE:<Ù£É~íÖ̺åDÔ%y†¥×$·y UEL©‚ˬç>…‰‹ÿ$"okuUY¯ÜÚLÅõëÀÅ;ž ’û Ñ:ÿ_X2";0k½+£wç%ìše ·áaWwÄß äòIw;ßåýòÏ»¤Å×¼æ wdoU[oáÕCšÏñÄ8‡ù:s ÄÁ2YŒ¹<È5lÖ&róE«RB³J2é«ñô#ð ØcR)ŸB\È_ýÖHý.{=<ŒX·’)?lgVІ~óñ {ð½x g×¾PSŒ¼'6$DžGð‘3Mƒuãà¡d¿Q‚¶ƒþy£ÁY<‰i™pŠ'$vþ侌!õo: ›âŸ‘+b”'(qÿ¼SWÒ£þXç—lÇŽ ̹2XZ9å¹þh{TäMÊÌ£¬xukf¾Þèèæ'ãÐ+%ŒdñzýcÿS<Ý\¦Ûùþ2û’œ e±ÄŒ‚;šÊ¬•È À ø^qô‚'J¶ø 8¾U#—æÎL§Ãƒù¨d¡šœ¡0v>´cšõ!‡:@ûLOÞîô|D$¾üù”A¶ðÃ7÷u‡üó‹-y*Ç.TO!úú¬Ù< ‰L>–í¯Œ‚UþC’Îð=_)Š¡ñ~)²Ø/<àÔ ?6êb£°ºp÷¸ÖÏoÜÒz&ëzmŒFôSHÏleP´šû±/Ú¤ŸG¼ŸÖxjüªS3[-î´d¿ÌÈÊ+6b˜º®«‘œÎ)ˆ1¥o»Û<$)æûK;ü×id– Ko≠q3frÁœ6æì[¨˜í¡ ¡kÜö#G:\l!¢4"'=_#Г¨»y±“NTýA9{Dää‰\ÂèÎ"¬W$bLÌø¢>­öÅÍ®àì6zº’" CYܤw™'Ëx‹Ü@ƒá᳸7ÌUEÃMbYn¯ ¤$´„)4í ™KSνðÐò³îe/M?{Ÿ±x?`ˆï¥*¢¸¨es7¢®„bHÚø» ñNb—ÇÝOþöFE~ð0Æ,kU0eÌßÚSÕ”3Bá­iž{dŽ%€ÑH~뾘ût¨<Æ{dÝûÖš÷xüŸ}á®o%Pa»¬Ö)ÏIÖgó(;wdz~G.¿«’¾Ÿmmÿm~»xìkœÿ}G3îûH(›OdZØÅávcã÷oAþ¤¼²`-nÌ¥@æóI‰Û‘-KB¿MòPv›ábŠIí€txbˆ™—ŽÏ—“ÿ å²r¶Sä3ÆEˆ­6iƒs¹IEˆ/òÙ.Ž÷ò7NPz>{”£&*ÌoVýÖSEe"·ð眞›Ei¬×úðy0…ÚŠÝ,Ísÿý±)?=ƒsTœ2r¸^¦¢é½C÷%‹LŠ ùwàÔÃ;Ì þ.ì6Ìhj¢Å9*g…"ÑNNÚU熪J¡wThçÝT]WÁ7ŠœÌö1ì7툳ZÀêèBͱĭòDé#Œ#ÚTÍŸ#éiêSÕÒaɈ‡Í„pÒ÷¹”©ÇfujÃy± Y톩 òèÚ|{ÅÖû]Ž-èÉŽ…VÐô5|ã^HÃ%R‰0§)Øq@{ŽIY¶`‰Ý7†l‡BFÍÏqê#°Øp» Mï ²2M^݉M:úYÍ^Ÿ´«úL]«2õá”'?QD_°€çÄŸ†©D÷UbÑ×01Зö-wG+hâôÔï~›OQEmw¦‡$ÿIOœB«úོ^¬èˆúcz2 ‹Óô‚!µ2lƯ…ÆÂüEÔ{C%@‡vÏ lÙ¤ ¤ŸÐPŸ;D{2Þà€æÂŽŠN®›ÏýÈ: $$Ãø˜ßÀ§|”ËÂÒ\Z è Úµ^âh˜ÿTê•8Ò«^à5óG_&%ìù«Êü÷“ÛRsù€àzŠ“Ò‹ÏÔe­5ÞmT|è÷“Ì1îßeyžŸ_Ný ç9Μçýï{Þ÷޽" ;nP؃èÉøWI±¼ŸQ¿Ýí¦“ºovV]D˜MášÞIÝ‚6 t&µÒK$—]‹èÎo“0)1$žŒŽ*OÖƒ»‰ácg›ÍÍD3êIæ&ƒ)OLð0Ññ–£"½<(;Ú–þeó$Ö³ÍN·Ïço•££lRj=L¿9@kŒƒÇF 9½•Éþ WKÝé¤.iÕ:þ¶²H¤ç:zG6Önõ\¿¥}úî›rè}I1å´.æbþ\Ï;ÝØ³)ù©bÐBW"©º›&~Ã¥èqøloÖ¹ ©:»ìB´,‘EÑ-Æ"߆{áÄS®É¢Û[\rˆÍj•î¤ÃWjUq_ó²<`ײ©`W8l®Hª¬Íñ§ªðs“°Ã+ðc›|c½‡þíÑòä ák4M õo7`¡Êxà 9eÛ‘}d¨ÿRy#ßÕŸì£Rsž÷Èð lLBi®|Å5z‘Ou?AuŠ´}ì¢üêÙc†ñ+ÿxS“8iSØm5¿Z0ݼ– rî|?)ïÊÙ™üÐã’yÌ@QÜ"ßÔÒ%i2$N… r±açL£Í«)P$vül%;)HèlŒ2T+Çb!`RãÍOJwlŒa6sãh>'Jˆe“âGàxÎ`­ºÓ–d¥”ݽ§õ)‰jŸåÂL^\®öiráG|Ü¥ZG.EÀü?`ÉÒÑs§Khª­ W ƒ¢’Ov½ÛÓôk­«AâB0×…¢ÇdÎÛù”벊TÝ¥Kd¨ÅöÛJ“¨ª\§hkYÍïœ!ćN‘Í,çœTÁs˜ºšy¡Ð\ºÀ˜¿Ý‡Ž`SV®XAøEƒF²£sYlê÷vgKø®Ã¼0/M¡2H(ÂÎ &S^kÅ 8‚‘>ž]Æ‘kgÐ/RX<‘†L„Ó&gü³Ýª ÞtäJ^t[Õc—nÎ?.¢‘Dm‹‘ö[N²u„áß¼¬Žs§‹ *•‹}=»SãÎwŘ¿’ѬŽú~J}§û´üì\㟌ÉGØ7 ªZW`ö0ËÆÑV˜ÏÏ&ŸPl»4ìÊÀŽÃ0ÄÓ5™ÛäïÀ1 Ù YÎÏûÚsd_StÃù!«§ ‹òukÖ{î°N7t¹^À›UÁsŒkÅî¡Ý£ôÛŠ»¥-1á.³ºÊ|ß±‹žO•_à±¥JhCµL4£c€áÔKÖL‘¾½ÇX¡Û@û8°ƒÌšÕ×µ`}l‡¿.ô©´„Dþ Íš K´+{WѵTòdŽR¬D0B—º²Â< Ó«Ð:´Š¥úô–½11’ 6Åhd7hÛÉUˆ=²r݆Žö{[¼F†¹"¦“çíôi»BtÛëé+ýÎH•v ˆöHhbÀÇR#P+éü¥ƒ‹DŒ}˜Ÿbߎ@7í^r­þgt`û¯Þ³0#äX` Púgæ×Æ4ryÕ™Ýå4…<¸'íö58”áO;Ëƒí½Šö<­l˜ÁùÖ‚pJ˜Ô± (yUþÛŠM€©^¦°»[ñ‘..±#.ªv]Ú+€gàî25ÄÌ`a¤¾ÝAÃæh¤Éï”­k_V°™4þ(…&î!êS——rä¸dî«KÌ¢ ~Ü!æÒ„§Zç,áHèÝ!Dúu/3éÚ¹û¯Žwê¿¢â¿È.  £ä­Ñ½3wÍæ/Q'"¥ caì=Ð*¼+£…¤{æ½i]à’ÓËOéå1[vXCp÷IÑ4Œa•[RDòÌ­¹ñÊ@ƒÁÍÎuä áï*ìc‘Æ+S29Tañ®»ãh€°±¯ÛKDÜ [¬5ÃoJGt$Y2 ¸ÉÁù +üo5Îr‰áI:JxEçZ»›û—[{ÝH¡’Ù'¥sÁqia ¶¥p¯"?Ú1æKÍõ…ÎÖ†Â1YšúA{|Ao¶ez,2Ü]ñ`wøŒÞÅÖUÍÃY\ˆ‚Ëøè™ªÛÎL¦ÐŒNic G|ñ~9Rú-‹n««t¤˜>”¶…&UƬ%5§æT1Äv Ý-¶¥R“ QÊh†)'„&ãvÈ„¬]ðpÌ3aòe´ÄQCª"sµ €ÅQ>Ç%_h¶e܃aFœ¥uúD¯‰@®¿æ_I^á5‚>kBÑ =¥)¾aÅ äO¬І©Õ"6Î:ƒP¥EðๆšÐÚêMGtFÝg3\,ÿgùU­îŽÌ# :HÎePDô £Ÿܮáó@l-`Ì´²òËUžÔÖP›[þX÷³Õ‰—¢t7_ Ö.øŒ`JÆÅºÂ,ý8ëähÿ"d°¨#¡ÉFÍšJ¦6áˆw,! ¡£‹_±öÏnú‚«µùj¹i_vÿháä®VÏÔNÉG¬Q;´²öfnúŽYÎûúª)8MC”å‰@ébIKbríYÞqê"°·á!%E¢ÁQOäÜaÏh2¡ö_nmùl9•!,þ)«Âñ<{Gý1ð¾?ùõ™’‡Ü¡?ȧ9TÁßV°w5·‹¾é8eãÒ,j¤RžCiF­$ú-Dù<Ûßx庠:±ë†ošàóM¸~›íLɲ¢&S˯^…&W9MýEfÃ)÷Tÿ,b€ªƒ–¦ëãìr 9.¾ÿ2 õƒ´î•ƒÙùrŸxÂ?»ÉÜ=mçèªéË<¯°Þ‡@Í¥ìûy¸ßȈÃ:r_ñ Ðs | Å0ã* Drd‚¸‘ò(Ì'ÆÎÊm"¥¶ÏTŒh·´ *Cï:Mݫ܉¼ÜˆíÂ^¡óJDRM=¡²ŽÙË‘yüˆÇsÜDBžh>Þð#Q|ÛF¨‘#Rw.8™q•*d5ªÅ¬Ei“®‰h˜õiq+o×çg§ã󟼥J΀F¦DÚK–§«zcè¨7»­òÛq-}÷§ÔvñM‰ÓIo¹P•½(’\õÍÞf³¿åÏ©ÔÔjêVvv’½ýw!XŒiܲÞÝá÷pÆ'~­M0«¢ 8èÈe3£Pv aUpôa{ñjoÓ]ñxj6Ú¬[<ìín-`Ú…Ø gþ‡½àe©ÈSé´uÌï,jKÛ£"Ho‡iJR=€Dj¤ÍC\›ŒMÆV3á6:ÞÒÕ¡’WÉpí-²—¹ÅŽ;߉ë|Xïd‘àS òyÚQ¤a’ ¦XK’ üK‚”Ò¯,,ì"¦© è¦ ×…k܇H°(Ûò'<‡š÷=Ã<;¨çÿ5óXõ×Y¢46üE yÀ¸9¸ÚÙ70?û±GÇ«_½ )î÷ñQo³•¾„ÆezîàS/RŒA‰ìï`‡¡L-IñçPa#â•Í*Ä^†ò¡DÏNu\öǯÿB¾CQ'—@ÍÎBòd&? œ¶"5=BòŸü ý[ÐvÀ0VÚÙð> Íÿ}(JE›À-p—™c‹Ž¢oÍ-T·iù¾‡ÁR¯+1å-¼²+W7ænu"àŠaR©ÖA@¼p¥+=Ú£Äô†þ@#"'1AÇ“Í4Q*‘°Â„,`ÿ8¡<ߦPÒ–Ó“A¶n%&ßô rÿS9r34üˆ:—V {*kFå§l&„ðŽs°½Ÿ‘ì =çqñ‰Coß:õa×VCðq®“? (ÝåèÓÀ…L_ù³|Š!`*±WÀ© Ì|æÓ@ûŸÍe­Êz…ûäRQŸð?ôämyüŠ—GKÝçܱ6¥ÇS~D]Ú{ÑÇÚáVÿv×-@ä«HÜþ²;šJeUUUUø—ÆØ°©N+¶½tºõ0BÀ-¼¢]ñ€—ÞSKµsôaN›Âa¢—±[ 4¸ë½·1ÚWW­JÕð/4…ß™hý—Šh{©möt¨€Õ£÷È\JßÏñ¾bá¯}Û¢`7߯¬ƒôÅ3wN¨5'6åÉígœ 0ßrß¡™=‘JÝí€ÂB^J™ÿ;Y͈ÚÜuàôÔà#=ðŠÌœå§ùÊY¯¿ý@ŒËÑæW3%Y?Â&r ^`H M ¢p0Ù$ªäD§$Jê 55„„„Hø<»-nôM¬÷Ä\nx^ ò¡þ%PM10 t¯}Á Æ©Ë?ûaþnÓ€¯Ïžp“tÕ›kÿ<´ù¯e!É£vƒÜ|6ˆ¶^žÄ,#ÚC›Aj¯cΗd@MÅHþ¡î·Ê†½cÿœ“ ʦ…ðüùÖ>Gžu6çÎêYõˆKaží¡˜*ï§25¯4¾ =>æ‚@r1‰±·ÀÞ¬˜œI‰^îúò 0t})ªÊ–bœSÿ;Ábô`ë±èЇWüœÖ|£4ôtHBBN·q¸êB¿Øñp…ªs/ÝËùö«8ú¿ Üÿÿÿÿÿÿib ¥þbÛõt¸‚Cµ6D$·É¤Û;ñª‘1ÎK›< y”ˆÚJ„„¾ëi±Î«ßÅD-é¬ÌCÑ¢Ú*Ê#ü¾q¡ÛÁ+bÊX™" ¤JÜp™ f¹lIÖT•DSƹwJŒGIK…Š*uÃêýs±bªªªªªªªªªªªªªª«¯ÔæØd¹D šH-ÈJ¹¸?”é'2Ú¶ŒPÙ“®ÜöãêªL†P#Àå] ¿C·a2~p*LqâÚ¥øS¸Jù€\ðÙµÒófÅ©FðO *½§©á€tÚ¿6q‘Á¨i–›ùÄþé!ób»Öqÿ+æ£%ÞÍ€4Ùó|S…¶)U˜ÂeعŽòbÒ‚)øœ¢ C˜ I‰_ÿëðá2G´²èè̹ ;í+0øY”R?³_M” º¨ôyè†a“t«ß d·º$ó^(JM®ýArB½{èÍàó;œXR²ŸÊ/ë"̹÷†r:•eÜæ'p"Ÿ×ƒ `Dsܳ“0íf 4Α­Ñã"Ö³1> ˜&Î|ßõÉw[aþgD³‹A -¦cÑw=Q”Õr*êW5ÓØö¶/¦ÅŽÕ˜R=þOl{¸ÿ`X%¾³ Φ]¾žD  ] Ƭà÷î>âCÝ=4´L ^+˜ä¿Vç­(€Úøà­§.TU8%U©k•ãÐâ¹p¿±añ¨×NG_ñæøÕâ7ü©è½ö-SÂ]©êþ4Â>UÜïÖ°s¯šãÒl„¼vÀN¯ô âOy[Ó:#«»ãaš ¿â¦Ftº&h²”|&ßC…`"Bq’/Qûõ B‹™Áà çU©SnrŠU2b¥{<ü¢íß q[øAP IgÝwtRá{JËôßX<¥_» dµ6xöUùj ÒÓ#=‹p“Ñ ‹¯–µ’`õšë!! …6C§ªÎj^ Öt¨¬lí_íu°¼]—ÊŠ½*믎ânŠ03ˆtìE ßGÞ–šEñ]è-ÔàÐöA÷G:IBˆ2ž;†lÁ1ʨ!g®ú•õC¬rcÈG¬ˆñy »Þá[ Íto81-Ð:%´#íÿ7!×’°² óÚ\Ò5#fJÏ­nåù-ž=·JÌÔøtµ?íþ:c±o¦Ý¬HÊ/›4Eæ¿}9 ÉG|-ÅõäX†˜O ˦Ÿ)z Ÿ¹_käýZðØ0*À%³*úI½>¿N5iì%œÀ“Œ„ЛÅóðçßKJ²š\wdÌ†Ì ”¨o±H¾ éq A+ò¸SÓoŸ 0–µIƒËò¶q†ý§nTs'ÿ–X¨ƒB+ÖxlÑáKªÐR¢îàýg™ã}Ûé·= Èãœ!ÞHÅJWå2Á¦SìUì1Ž€ÄˆPÔ”Ê1Wÿz?Œâ/€.…¼ V²çÉÃî 4š­Ïp¶}y§*[Âe½¼;…Žv° i1…ÖMe«\}¢ïÚóÓ@ô)Í+„ÏPþ&| D·­û‡›±îöÝ­À–ÊâsLƒÙ‘Ðr‰iDÛ6ghÏcäÔ‘0@íM2’Dy>ØñÓcSlnI(õ°¿-$aÿÏ$§²¶— ùH<ôlÅ•ýãd‡]5~Éè ˆ"ÄfÃb¹œÍ•G<&5ÖW3ôru¶Z1ÇI‚Â}Y)*`²´™€oê0c9Å+sY>2QîIo&ùQ¾QCn­ gÀ³ ˺¢[ÜÏ ™q‰Ø#‘Jý;Ï_%?Ú$¤…q‘&>>Ð\xRý#—t`Âx:C€¨¤DЩ¯t0½tdcø²´Æ:&“tÛÒý4ÒÌ‚™€BÇìü@+Ýò? VZ\'j7X`esG%gŠïœöX!jGúà(6áÛ™¡h:ÿ\Óö±•Öq:ˆëÜí²MÈYTÅr,ŠÝo-,©E¦ÞÃ!ê€4ÀtŒ¤i ŒQ€Äˆ|Á8§ 6½í˹>!oKd¹=L‡=ñ›‚k¯sø‹3…`Ral]ß/¦Oöêk­$D‡Zãû(só¸z¼âN÷âqßä'5 ç*D€ìº% ©<î«èBÃiÑãe±á wIˆK+Aoi‚×XÌïN…Ìzõ˜sÆ—4ëÏ¥3ÙFŒdäø à4 ­ÆN˜:°À[8óè˜\HÁ8GDëïâ?º¼3‰YȰ€=C\¸'É\÷4ÏJôÁ>qñ5åÍøÝV0FxTì½F\G#.'çÔÏÁ ªN…öôéÅÀ?ßšÈbjšvO’^ÍçЃw§Û {ͽ²¿g€úÛ$ÏœiZ°¶f†Scv „ÄÉYé†xd9ÍOçÁ»Ò©+Õc[=;‚m9´¸½#šê©ÎÙò¹Æï®OÛÝÌÌëÂDRàš¢0~Ú%ݘä¨k"´ÚÀD…ÿD€ô€ž­òæ‰êþ%šÑ³ù¦ÇôÕuä¾Ðy±³šÎk²n k/rš Êr”F=eúìxe‰L¦sÇßúÿ]ýì /•Æ¥`©|ÎEhl%ÝU†æÞ<4«0e¤FDÛ|r÷k’iàìµ®‰™Ýýj<ÃG¨·ž‚gùÛ÷isìøPsöxP?EÒq›ÓØÞqUÒ7ã ¤ô’TÛ±%ˆ|]êÉXIïña[ï™DXó …׸ÎH º1N/ºùž…½®Cê;·u¥ð€ŒzûqXO5€ÁÁ j÷»^_ÚØ*D,qöÙ©Í}§Fñ˜BË>k5_ȈW®ÿ7‹Ç¹WûñNÕ/(Ã9¼eËÜu·N<àÛåøÙ‡]þ<—w@†>áà”R>þ‹Þ@py7Ò ·Ñ¥¥'Œâ)ì7*ß϶YÑCïˆÍñ*\m5Žñœ¸‹«ÁëLÃC¸AbM¶iĸáȵ†) T¬â§Zæté4ç;ÊÒ;ÙetÕhV¤Üôßo<Û]Ô›ø¼êïÙ4U3–*Z¡^èÚŽišÝüœÏ^Eü1sOF|{ÏFÇ™í qõ;\3÷hÓ±F'DF'eÇèÖµYÉüÙwÅò£×¸†mAt¡K„™ˆÐƒ*ñl@÷>¹e|K›ŽEõíí÷±ÌàðU/Šè Hi¯Â5×l!v.ps&9àP„Bz Ls‘0ymóÎößCGeÇWwö )ú­·fï\_®3jÔðùS)þä+ÞÐ!e\“rãiæ‚ ”T[‹”m_?Žâº:jl€>íGÙ5 Sv!±‹ÙËÓ„ÄõôY±÷Õ"íÝHÿ}9V¤/×…[þõ•I3(2 §P `¡ã¦¢Wÿdd/¥ÑJ;l`JVë禪@n#!âû×¢ËäqF;w ‘×€ ’j«Ä³Ú€£Žš»âÇ£‡ò \2hšï¼Ø_Ïwv««g6EçÄØ+zÆ“ê¹\ר+EîyŽê´sì5ÅБßþ0Sø:±üê3m±CDý—0Pó ßÕòöÃ+âÖ3iŸ>ð._GäN 8mã²A™„RH‰<ø· š|¡¢hvVNãcÈ5®”Y™(•ÔŽþmÿŽPeeíd¤¯-:âÇ%g ô#QénXWù¸Öß\¤R„!fOu,¿Ô2?*ŽÒ8l-ó•M~÷—„WòwªîröŠ€D`?n—lºƒÀ…*êKˆ€©Ä7â9ÕiUHkÚ,!3|n,äÈJÈU~ëCÖ›ŸÝŒäžT§”§ÈQ¾ªÈ#å †(aGo§ŠÀbB%á ßà=}o®¼ê½«†W–·ž8>î0ïv”œýoþgNxˆñhž•×òŽjvÀ s«<§— A#B ±üŽGÉÕ TcÚ˜ƒFwtÊ(6¤ýpolôHD±épF!àö"|12!‡~€wFUöûŽc`M)gŽ9…è@ÊgX7‚Œ5:¥)¹êcTù†ã^´Úu¸sÈ£BNëÀÆbrøê‰õûóÖ鉘…¬ì5k ®ä³‡F°Or¢x+ê‚%Sˆ ø“‹°—´Ž'N.ÍïUÀ?øÓx+ZfáN’Õ<6à-ÁÕj°öÊ#¾í]nÃÈ£´ÿWìû1ÌÄ2ÜPc½kQú@2ÅŒ8ÀôÍtù *Š[óÉ MÿB΃çx±Só –%{œŸãè û. b(ö-ÿiQp˜&j¤+W–‘›K-¿³´EèëÞvuhäZ€4Š€ÌÖ/üù®„Ò¯¥ƒLc/¾7#Ù´W‘ß;/aPê¶ÞMާFìϜڎEà¥bDDz‹æžKÉäÓ} ,¡™BÓüß¹±¯°d³òBÖ]1Q›Ñ›Ð¤…¤š ¢1wŸ¡ƒ2‹>|8Uß…V¥Èû9^Ô‡j’›\¨@r2Ù\3;ˆ7¦ÄÊ‘b¥ƒ|7v\± ˆC¸J¸°hd[ßÔû£~©¯Z0ïVh,4Î:U†3U~ÁZTJ1Î¥Q ¼øv¦^‰ò"ÔËá§U¯¶ùîðZWþ–<³‰ŒJ{A“zŒ3ë<ê,©èåÀžþ=Ô$V¹½œ&$À÷@bOÁñ8ÍÑã«ypb1S°£¬NËBs?)õ¯h‰úÂíf71ø¯(¶à%¦¶HYî“ç ‚.ãÿƒöEøO(ŒáÐóÜWkËùžA=f™k¶°=#ešp¹¨×«ÛBqîÌfç…ìzTù÷= ;z)å=&qCË*XjW)Ÿ0öQ¤JÇœ?Ѱ'¸¾~^£ü‰öj'³ÀðZz||Xê@ÑÓÈ <¾:j .{UÅcÄæ ÏJý”D¬Ón  ÷Å[<ªįs·Ô$ÍZ¥Øt¸ ]ÞÞpÚýÔ%ã¸ìÌC##†X„B̺½RÕ˜}‹YY.ù{èe(Ö:Ï™þFÀ7 ”œO(×éŠðñBñbÊPº!wšŸB*Žè{:w7ØxJ0Ü}W,£O´×4YÙà}eÛ-ž©¼? o]X·%hƒ×e¤ÁѪUÈÝžq4bt5 ã~úÉ]-ÞÛa压ÀYŽk£sr¶è§ ¥´ÓóÕ•CcÔzט£k4´„D8•&95¹Ü>ŒÀXJ¨êÑ¢> cœÒ”s­1À8¿Ü›„´'Ä8ÝŒç¢O w·÷Hj´3ÍèçJ÷í—Øzb±ï®ú»B©F^¨„@'Œ©?6Y2¿$‡â73óÁ«¡v幌*œ%ÛÐŒ4LlàÊÚ\ÑGtºWž¹EcΜç.Beµní ©)Šó]ÍgQê©KÞ‘s[ ÿ€†/û˜äŽ}«‰cÓ÷ªMBߌWÌ\Îq<Ò‹§eKοvåÇF .w™î L.1Ž>‰§‚‰ÃžV¼(¬:€trŸh?é´ãt†& ßÏt*hÑV£Dø4í€ÓÇQp'Üg¼ Ívçß(µHþ¾¸>¼9p—ðèñ–Ë%¯}Ë‹1ø[ Ä…`Vt.Y6Ënk„ Oxà󣎋A°,ãeS±Ó%¨/©±ÓWvͺ} RÜÃôÝØ %¼‘|èÆÊyØÝ/Sm_µßeÇÔ?¡ÂÀBË(zãº7’=IFþì”§ª„y¬ªBqµN»îåÑésü—,2?·… Ê%® Ä/V_J$LÓ"µZ6^8¿q)È£a÷æ9)¯•¹°àF~áÝ$`]/?×ÓêufìFmï¢@bÐIe º­}¥´ïDÖ©~)#B§vcQägAs B=x!“â>>V¤{õ6Ú0ÉÖNO³<í )[35=ʬùø°ªR){u‘Ô™Z5ŠQkP¬N»Þ ¶¦ÚÙZaÆïý'xnÏ\n±ñ]M(ÈM§ŒòBv®5ÊOdšÚ™©س¿ÝÄ0ðÓ'®r”Ìn_»|Ó ¯WŽl `޲ûzË£½‡7)¬4ý¨âY Ïâ]bÉ\x e“ã?ØY=ƒ.üÛrµøjŸDÃ#‘ò4C5É/,GÐ:ÉÐºà•¾òhJús‹\Œé¨4ËcH0 …®TJèŒoê?üÌû¤"Ùç£=¶“€¹4wý¨+±Œæ¹$‘A‹ž‹=ä+3,st*Æ5…™z•¸\q},x!ð1oάE_ul_` ¾RÒÑ|HÅ…o@›[<²³‹†û9ÿg,h»2·ÎoÌ_üušžÞ3‰þT¬¼æê¤ñ ÛR€kªÛDä)ð±g$¼¥B µÁ„q`·û]¾Î얥ݞIîPá3¸L0,Ÿ°OÍEàgá!,Cqm¨éî/Q²i¨é—4n†6„e ÜElÖõV­Öõ`]˜Oîb«Ú®Ç÷mKØ`qW……}[iÜ~;ÀãF_9UU%!àÈ„I?r.óZ– ‡T ¼‚cäw¼§,ò¶–wG\Ò¾ãÞ]ŸÿÉ1O9ýLÅH·‹SOsãA9†Ñz=í¹èF&˜²üÉ ·ÉÝØÄMí×…¯øPðg@}71K`”¡ ñ±akÄRÀ„ÇËÞ „šNïZrÁS.³3ÈÄÀ:—ÜàU*-“„éIkC"¯VºLÒa? XÜ@7"1Îæ[ú4Kk2UÚ—w’øIú&Æ„~³ëôÄkÁeÿí±§2Ó:Äó7½ÓêBÖ\$uXae Ì\‡gGfñLËbœ†RRÿF‹ìŠ÷sÝ‹{ŸHAwÝHE^jb{âu`ñUw¸4dnyl¯)@‚z­a1+U. X/K±`S-ìVL*Ó1;ºöôÖpp¶ÕÉùUæpKeËsYaÎ}V™÷TÄýAìãô´N`ý«P_hžþ¹©ž—©ñyƒ”0}Å7? .UaÛ¦ôø`–}$æä8”Jgæ×ÃU`Iã ^ë°eq ⶻŎ ðõûòoIè+¾h£&\°oÛ”âÁc­óÿ.ÂDk3ÀŒB–vë‡iUÊ(èØäàâ¦ýúß"ò g}@µöv€2ù1?¾ã’#¢ ö„Àâ±N–€%ÕO8/ƒ±÷í­pø‚OM#b´,û7Óš$0¬š¨»&×0_àu…™´-†àðò桨ÿ]^uΑ_C«&C–¾†Üë¼ËîsZŒ¯±"|D©fΨGFÌÑra«……ש¨N&Ôyák:Ôä¨Õ#(›ßäf3Y¶ŽfÔ›Z øã°T&8ãfÑ]o%"zÈ©S°KÃOLºâ “æ$—Û|þëlÿ.:lA NT•HhLé•«™Uú*^¢Ñ2º³šî>ׄMæI"gÅÎ`ðt« ’ÉŒ+LtÑ­µ§í¶}ú[y—±Zš^|Ê»nxqkå¯N´`§ø‹põC 8Yxn±×Óñ/ ÷%+Å ³^‡ð“'eNAåÄgHû:ýdõ÷Ô1/Ó{mQ¯^¬8ö± çZrZ ôºuþ±údßõ—Gý¼Ì9RÒÄ’Ô*a÷Ûø!FöÖjÛŠv+‘ñ²È›bŒ’Ùƒ£@X9º×ÿdËúéC2!Z?ÍK`J[Ô¿šý½ێ¯…Žq¹P{`«>>k|dq‹ìÁ)!5 ñ‰¢‡Žá% ת¯’¡Ù­²ý9‚ÂOœO•'1ª[Œê VÆâíkì ]»ÅÈž…3g½1÷…ZèÀâ.šå÷Þ6¸[ù7òH!ëõ5˺IpT§u"±ÝÔa ü[žœH3³6ѵh¾Ûœœj’lW×ÿ0)½Ê2KH\€ŒÍݱÜì3°&¸@g4:yQýÊF€ö Eîçæl¥ëk³ }üfæáÞ×Á"/¡ŸÉ{• ÅZ i•¯FøL€‘òîÇ]ŽEz‰±§}1ÚCk‡êža4{¨á$'bv‡Ðs:NY±íEÖFö”ñ¶ 6¨éyã-&Ù^š2‹OåQ2Ó?˰¯6…i§> î=ue潆æÓmŒø²/†¼ÇÌ£ÛRäAœùGþEŽøcœöJ””WÊ,‚îøÌb€ÍLËu€;VAtCÞ–ÞRyWÅthêà°,†, “ ,±èìûÓßµÈ+ãðð£ <•’.</,~ÿvŽ?`ºÙ¯5“®Í€0\ý3²Œ ›ALàšlÝøÖWç°(é'¼žyÚ(ÓìëE63óbã}ÒÛò£Øøˆ²À,³É¬ê¯l›O󿙪QU/þ§Ö(d¯lzX0FËz‰þ¶q q”lšÈ‹š“uj:Ÿ“ñk°±¡Åüe15ƒÈ×Ué:‡ÌªËQg¢÷ÆUFIÁYr×ït«¢»Gÿ…çÉ—oUä©CiÊޞħßXÊIwnilt!÷F³ xÖŒ%~·Û^Mmv0…^2­TEÙM–w:A~ þrü7¾Ú†×Va†ê /i~rCÝl§ÁœdlùÄdÓU\"©Ì4wR ¹<É*ÝLN@tå< Àå€ô®ùmß gä¨,«ãEÓîø®?#·¼ÓdFÌ;ó„ k¹KQÏÇB­æ4€)³5$,o¤ v8Ú‹[UrO€ü¶Eg5õýÕ`à ÒÌvòëŒÄà­òþêÑ+¢,Í84d¥íHÈUÀó@Ÿ¡W>\ÁfÈE.躒‘Jø˜²eo‡U ›±˜ÛsͺíñÎîW‚iV^V3æàNÌä„×VŸáÜŒ‹„à¤Ô k\¢ÀK¡HW} ­žˆ¨¡›ÀHÛ[81uœNåSÃ,g:VÁaGÉ`ÓK$kȾ›»~SarÖ¤rsíA€¹¡E¦Oj6wt¬ •ÎÛðÞI/ÊTñ‡€4]™ëLQ2]Æì-iLhÀ¢¾Ç$p8ÔøåImWá² ­É‚»«w&Ćœ„oòõèóeƒá¯Ã#Œõ:×2ËO,KS:ù¬É‹ÓÿP„ô€=gÈ58Aý†^*غÎÏ.;8e[dô÷팀ayÃÇ ¡WÞÅÄïËê¢~ˆ.u£›Íþ]®ñЕ–§Ú¹º­Ío3ùºÈÛŠõAÞ£ ñA—-þF…ªÃ_Ugûw_øvÙ}»aûuköôÉÿkwÛ±]öé'ðìGøuUü5³øjßðê¯á½wÛ|kí¿†êǯ· õl•öô‡ß‡YwáÖ/>Þ„/éïçÐøts>Ýüþ}qþÅ}µw}µÇðÜ/áןðÖᦟáŸøt}º÷ÿ‰‚?†Ë_n¥_nÿ½€íxŠàÕ~öŠÞÚ rÞZ¯º”ZÆ9ØÔý³ý¨¤ÓK£ØìÁ4+ ‹á¼MZŠ DÛq÷üäóù˜‚s6„!Ê‹v .“—ºˆ–âñ<†N“ÅÀýáæñ,"Nß7MðLkeDÑ$‰Sµ"£uÔ[Æ¿¡É•wcµlÏ%‰Á JÜXÄóÔ™ŸÙ€êèq¦¿:4Œ¸†UvugM¤Òë0kbäMŒååÏ}§Œí€¤¹ó½JaŠQï‘fÄ9XÔfîà1h Ýçˆ÷6y§å˜…¾BÕ™ÞXÍlb-iÎæc†1ÀÚé–E¦˜@‹SäŒzÒòAfÔiG_ÉÉŠ©S‹ÿO+¡Õ]ÜŸ‚ –÷)¤ë,žÒA.²o~‡^‹{fÈ-}§ssº’"Ì@ö|fÉËkÙ¨Ál ì7?N¤ˆ5'ÚE·íÐ¥pò%í*#tCMO÷-ˆ—DTßv‚J¿œR.:»1Í~\nfeBtA%€»&(LÊRü PÓýQ6ÑRZÀ×–°o!3_rœ½]yÚ2óÀsfÝóȳ58Èo-Ýœ7¸±‚3*bAŒQÙ›–&í#êAt+x>CànÙ\=^RÐ0H>5ƒF~Ðoå¯çÍòôf<ŠÜ´¿®ÝæÍrÞK$ ¿oÝpÅiš^‚ÄçåUè®g$Ô¾ø>Q·õl ŠCò{¯*0+cËÒƒÓ¾>Û…ËÍì±1Ü1ÎÝâ¤KaYŒœ¡F™HàÍÇP@¸hG6?y5Ó˜™kzljµ÷¸Æßä– x==£?è°}UbÁV´þVó¾&¥rPlÛZø ,‹Õ\píG{³gñBÐ|÷§[M÷>K½A«½KŸØé:Ûq]c­™L£„ׇ0W½ÒÓäËÍŒIø—ÿÒ³roœï_Þ¦ä)3S³ðxŸ¸¹þníîü ¿ Ò·x tüÄùÅ»abnZ[ÿ1BÕ‚:èBZžDÒÁýê€×4G©zÕÇÅîmÊëÁœN†¬%3§KjøÑèœe¾PáB9Û«‚b÷›`$·pmÚ—P¹ÚF¿Ê¹Æ¶ÏÓpëÄI–RŸZ^¯øÅÍÊ ÀÓ‚=ïÖ©.ØËDÞjÆìBT4+üRÕücY$-6ÙIÃÐ`»ýSþ„%M¨†n#¬“¿ñ×8}Ø…ÆÇoÇ#×N)›cDG7"›©ÍœRU `lX›kþq ¶åôÛ×¥@ÝŒÚÚªEdw|ôΪè× 3oØÕo!Ðaöìõcœì4ú®Ï¤ø¦¨Ç|Žã)0æ Ü<<7Ï*”KóTØ‘§šQáøtË'[H€w žÕ˜1tPÕ:<Åc†PÁ‰o!f#VDƒŽh5¶]…„H¶‚ !ÃlºçݧN é‘™»ð°å·h9©Q.i]½ØUëŒ ¨1üs¤”œíMçõÊîý¦‘ºDc§’ZHÇŽç"[{CÌ,×a‰è£ðc)êö¥KI]›6s¯ãô†»Å(³ÜIœÈ´ò§hÊ'Ôh´u3vþˆ K[R Û¸5ù% }£\*×ïVS¦œDŸ‹e¼¦ju‡æ`†vÅÖ„ÄD_Á^âIzQ.û¯hºÄÎs·"(¦Ö«¶V‡ŸX¥8²—ÿ^¡½iŸÝ³“øëp¤õcš¼Èö‚rçÓ¯_%™/zR“ê=ˆgOæOãW¼òÆm´3Gɰé-¶TƉ ˆW8Õf{ØÝ ¼¡ày#N˨„y&aÕKÃCã>@ ¦Ýr8Þ 2ø„‘צrÅ•C9 ý§zM–²°¨TÍ·;áÝ'6!Ðï?‚¶R[Ǫ"ó+ Œ}—†¨Ww›ˆ3:¤Æócn³Ër¡#¥FnV»-ô”£ÑãâOT.ðÇr¼È RûßL‚SeŒ/á«¶ ¼ÝWyaVÀÁßcC Ó–C¯›¾Û³Ãc;îVäªZ(}’ì„,>Q€ ðÑF¯pŒ›»°¡œ/wéY–úþG{`êCnu<þ$gô®w<£­Õÿþ¼ÁãÍxH}Ç#Ck·4¼)z9XµFÇ`ú04¥W`Ѿà“WøúJ1ª/þÄ~ì¹!æÏÖM°Œ«ühÀ”¥Ã Õb)hâÌÓy··J©¯è—æ£núR£¤Œ™îuø\ðç³Ã™›Ð#~±ëÄÉ%Aeâ!ѽ«×"€õÿ¶RtR:fàÒÔÔ¦ 6S0ßzV]|IÆÙki2!2N-‡HÉì}‹8Ã.…P¥Œ¬…š°ø°O–ÂïD~7ul±­"˜i-ï¯uyŸ“’ÙPDÿ$à}!8#HI´ŸŒ3À»7•'èÀÇÞäZ5Ø%@æ¦T\WòU!GVÿúÿf‹¬/ÛyA×&¦BGZ®¸Ð=O Ge+ôÕ­pÉíz$|wÜžD—]¦Á À­ÓuMÎ-¾Un…Ë×PÖJ¾(R-~ÅOâï; I:évCtOÌ à¶õã.éÈeõ5œç Ü»#Ëä±ê"Ï·qtý ᔊTÇ0˜rŽ•CJ¶gZËW¹WrҨNJ QŽ%–@ÇTÇ©ÿzÚÖÐ0*¤ pæaâ‹9‘¿1–E"¦Eôn))µÊï.âM ¹ÁÀCÓd¹µ9FœÁ<@q5½y5Méõ·øpÍê•»dF6³’ {×!ÿÁ‡ €Jßf¥*§¥˜4~¥&„½f'm•ÏhÞë#݃쑕£ØzºfÙ_„¹7ÄñÌ.P Nw•S¥:I¦„Ñ5d>#¾%ÖÃÙÓ 9²Óø‘T°?vsáü5¼xºiá±õǯ Ão4KÂÔCssÛä„ûîÑJgVæpyÏüAd' C?Ìd3ÉOê<üNºðÙ–0ÿÿ°"ù+’'¼@3Qc?ÂýXs~e¶Â* 'ý€/ÿÿ.ðú2NÇ]]§ó$wõŸ*ÆÙo$H>VÁ¨…^Ê E ¶ý->x!j[æ ¥ô¾}ÚgKî…G×Â0v\¨ìÅÊä¼Qž váź+¬ /QÍ7 €VÛpHœ:˜«°Z\-=hó:J˜ª¡Vh>çóX®1è8¢)ofùâ×NáÀCGÓXÚ´6q‚;Óþç¨Eذ3Ô`÷^ÈxéÎâ€lMÏÚoËýA°õ(œáãÆx™8ß]ü`?þrÅð†1ú±ç««Iç£&¢?ó¿EEøyBÓ-"ÞÊXÉëžfàžmèâWuTSs"Q{Yy|™ÙxîÞžà¾ÍOˆäjà6-ߺ»Óº0Þ$Ë„qÌZÞŠ¡¬«Ël¶þK«oRxj/±Z‚[TU©~L[.ëŒ`ryoQÿÿñËNxkoá=[ä3ŽH|.RlR<‰ Ôtr]Ý{^>!SHw¤Â1MÒÑi¿¡†ýJèN¬âÝëV2â« m¹(s\‘‚Ãxç/HÖ˜™u•GÏäpp†¯/p7ú‰:ç úoÀ®!½ÔQBÌÙÐÊü6½Â˜eÁ(Í‚v'f‘äÕqµåÙmàñÿIß’¦ƒ˜‡ç&“²Ñs[Çhˆ–ca0”„"}…[‡“fu–%èål:027AYxcìÈû¡Îit¦iÿh)—Ü´Ú¶çAØ)5˜YÏð¬ªC²œ›Ú—×?~¨¢0¡Ê‹Âº™2ˆhŽÇ+óE&SØãèé½ R*âPØñSy¯ÿ;æTêÐçsò$8Ðõ)VD¾8g’žoôm±¸¸¾lmÐÜ_cmU“úU~ž{x‚ßÈ~à÷ÄAï›ÀЏ|0æ‹4èÎÛ((hIJªG÷i8‡¸¬Íd×ÐäÙÚ¢ HôOÞ^^ j8¾2ÛëÀ¸#E²ÜÚ½´ßÀˆi«ˆ£ó/Æ.¸Ex×eÕŽ>¤W¢$ŽÕ GT€¿bvÕÙ?ßç½ÄÕ¬XuöAÜ¡3©Qø*Ìæáø[Šèlr¦ÂDP8VáâúK_ÿo˱Õm”)¶û>NtE!aå!ð×ÎIÆ ÿ:RÔæ„Ïj#5GHhE9?|êІïì»{ý¸çMlÖ’äÒÉÔð8sý}œ·áÀÝà&ä¼¾C>Á¢”«ÞÀütÁà'˜RJŵ®Ë~ÞšÁŒYY?¿àôé*³…ËšÔ.Xé£Ðå´ØéI•-ÆFÕMƒ7*›rŽø¨b?ÿ|컦jð*ÏÈã”ÈÆðefù³9Éb‰OÐ`%)»e~Ë„ÂØÕžÜ›‰¶ŸƒJ€f&Uçò$±K’ˆ#œJ_ÞÂü.™UD´ÏP3ÿ8ß¹ß$jzôåbåxçeÙáy÷Újñ'±B;m Æ_Àv\Ýi96Žd;%@}b `«®›9Üù¦ÛãéÓ‰•òÄó§%ËUr.¼ÜuNB.øäÉå¸7Yœ_,Cÿ îý1~;6ØÀ…Ó ËþÆñ9ßËTNv!öwë^÷†ëdÜe¡þ&–¨P† 3EÛëà…¯ 4„,q‘.«l1vñOÐÝ^r¿´ QÊøÉÒðcª¯Eµ_zÙH?1ë¼®ºÙ-pÝä3RãÕh€Dd6¨M6«¢ÄfNšgµˆ#;‹ŒÕ°‹{·òk“hú¥ƒ)ûO¬4PT@:v¦Í€êsõé ð#Mš»\9å\ž‡ Ì-¤Uòƒõ}O^%}uƒ.hŽp8õBÝa,-OÒƒVeäeº]·Í:aÚ€5°&#Oµa@èýÖ<÷*dÕQýPj›ˆöø“ƒx:ŠhÕ»\¤úÇŸO^ùòã»z,¿¤´ˆõ_D$ÍQÞµñÖm†C(@ÞÙ"ãܼ}VT6}taÁ ÏêaFÑ…Ô|ôe‡ËìaÌè¿3ÙÒšV×ZnÃ÷¿§®~“³AøKÚ>²L3ã›Ã3ÓÄî¡óç´¶¬xÔWn{ýØñ¹ñBî~~0äjJ]yŽ”.\Õî§0¦œlP˜€a—‹‘¤¿N‰­mà\œ?®C; mª”ÙEÿ‹˜ÿ’ ÐÿvO®ùgÇÜóK ´JéJ»_Lj°û4G?§Â#ͼó î[ª“’ÕÜ¢DçÐCm&0vü?ùô1£â~©Â™¢Nß6Ø:¾¨E¢ÿeƒ '›Lt§b½5Þ?ÆpË–8LÒm/3PŸmÆkÔzb¶LùÊM—½æèPE¡‡°½‹ÑVÈN]NAƸS>OøŒ 4è·N«xÄã–¿ÄQ¥T]Þª¨ºc.\~V]0ac¸øç@µÃ±a™TÇ®Ü7¾ksžW”q•á«S,,ú¯ÏA!‚¢§Âú<òü½“ŽÑžaÜTÎ?Ëj6«ß—&pŒ×èÀG‚é5‡nƒsߟó´ U§h¨ ÿbüPž‚\,˜|&¼hAÒrÕ#Â{Hî„G¯S|¤ý@?þÀõ·æ« _7`F翹ƶ»î|8›kÚ@žô™Ã¨†zåDŸÀ•ñM\-S¡×*Ñp·Ùb¶²áY s/UÍÆ¦eù?ÿL¾ ,½#vWoÌr©œûÞÜô}´é¹ÌŠÈN¬QÔ>¹ø—)¬8G­ŸôÖpeM+-]N&ÎË^…5gÔÆLôw§6ÚiF_ÕN;áûŽ€`9ý¿hÖe!KÏE·*ý¡È2Ð"}«±Â7CÀTý¾L+1HÝÿo\ùõ ·lןùÿi‹í¿f%[Ý0¼-‡5‘Íj!R5y V~zI*ðr5ÕÂu¼}–mÍÉRæ«çÎiš›ÆÈ`.mõ®ËrcÅvŽÞì¹X›ç!ƒÿyæ5õî[)‹ù@$¼Ñ ÄYØ1ZãÎW´g®,þˆÙžéдh Þ䢬ýܳ¸Ñò9iÖHR3†ƒüLIíºt¸/coéÁìv®éSGÞÞ„ÞUŒú ÕC"RL¥4ÜP:ã*ócºË$WGBâ tï}è½%5>¸vÚï>‡"H²è¶E”O¿ õSUÙ)¦| n‚¿¸HúŒÝÂç=ë5ñ’,;³uU™|Ýq7pZ ?8¨j^Ú+7«wܘ YHdߤnËÅR)hª×x… 4HdAÏ ÇתÂÐnO±UûÉØ”ù‚~ÔS¬®æ>/œÔoë>7ÉläùxT¤.ÆÏdçN8 7™2ÖUØCÅ %ÒCÙ†h\ y7¶™—l§\‡£?Þ@\ëË+³U¶2ñäìÍÙ…áB(@°îÂóõÚª½Ö$³ßñQCø‹jé!= ä ëæV‘ßöx‹Ê œÈþ3xÕã)VÆú’ ”ì}“ÿdÝØ@It:üSTJˆ~ÿÿ&ó×WáÙuþ>K”ú-[¡®d{¾„[—R ŽŒ[ØW.MÉ÷gÈ&Knð™ý8wTVÉ&`–ÁçsÆ>ƒ ÄxР¾ÄWÞp„Æìëc´uÖÜvœ3µš’¶©àƒÉž~ð˜qÒÙY*×fŠ ¸ÍUÆ€}1"ƒå<‚©lšo]µ«WîÖŸ8Pqã)SiwåÝ&Ayas:Þ‰½"øä7§¼2³Æ¬ýCÆ¿¹ :|ÐÄž¢->ßë]#‰æø ÅX¸ç™e‹v„L©Çø=$!­Îc¼¿ÓX›ånq3å_so§6öÛœ…)`‰îuý™ÛyVa_×à"7Ž(»sˆ-Áû`˜±Vc\oî#®£‚ž)8í ºäéÅõSõíì¿–ŸžÃ ’: JÙ3üÿW¦¥úÍ'÷®‘Ÿ“5ÃsUäÁòiûÏÜ<³Oæ$?1¾H;Ò«d­¶€`»LÄ\ºÐp­ÚÛ™)Í_ÏýƒXûÍÙ*Æ©dQOKú|€~O  æ¯1ÑŸr¹×U©R\:Uƒ;]ÏG—FóB–kÄÍ?£o?I…C¡‘`¢º ½pé­ “h‡‰'`Êú–ÖÞ‚(Ç|žˆdZn ²·5ã¾ÔíYëOeí·—¥´9X•™•Å>ä tõ*ŠÒÌȹÉù}WÞ}Öð8RO(­sP†£é—MëYpËB7¥’ÎBwÑÀnü‹Ñ†h°?ÂM1Q;$ ná™MtÀ2j©ñHb#IjÏMÇY7 ·E0_'ÏǺR1:D>¤(åÚªŠHÑ©v¦XªF„¨zBÚÕ3ݶþ%´ÙëOÿg•|ZÐö.M$7~oÀZ2€ 4MË“ÿx"2¶Û.ŠR Gø‚(åøK—À=`2Q¸n·u7…°øCå Ž*¥e´B& ~î&}Xù§ªÑ?Vhàyrëqµ„ÇáÕ|ײ©—ŠÖP9~éEï/è¨ó?WIs4¡úc„˜ZP óâ ˆ2·Ãô©ÖXú\ÔËd%%vc½× ]À ïƒ´…\vz8C†NÉTüÜÐîDLH» î© ò¶éýí½avŠ5‹„úÄW/ðŸøLk 9ͯWñVÐY¡Ý 7åV{ª—ÄÖSp7¶z£ŒHç‡ðdCCP<¥|ym¬&x§T4[ÒuÕUõøH¾à—tífÙ+/Æ43òkªëc¹ ¯Å]øêÔ°в‘Ë#½~ÌwK¿I©«À©Ê$nÀA””dYiô  ×ý¡þ*×>G†/~iÓTÿ ùk) L–²G³ÓÖŒ…Ê£¿ÿÿzóÌ PòÚ‡öÄ5éq7¿rœ9÷øOV É7†U¤B¾¡€]EPtz9=£kˆŸ½8goÖKžyGW®\L÷Ä$žíÕÇü´ŒÅJkÉ!‹B߯d—܇ÆáJ`\u~áSwµ ,¨ bgÃaHᘫYÎŒu!µàxÐÇÛïþDJÙ Èü57€Š\üUÂz¸&—6Çá.¨ú¸e¨K ‚Ïbpu%\!˜x™ÜH³‡)þrÝZ!T/K‹ÈZ0€ñåùUm.Ûýü(c eÍW+¤ ×_àŒF¹1:.¶ê®æ„Æ‹»Ò§;k¸Ô5¿½Êµ’—?íœwÅ«a¶Ê K©”Pu7AMwúø¥£@Θ`ZÓè¤nqÞ’ý~í+›ñlƒÔ……þ HAKGŸåtÄ FwYpÎí2àn`rÍ»ÎÍ=7VŽ´E¿¦rô^8äXD¢š‚/?ÿÿüÕ~#ºÕ¼ŠÎ8ºåJÁ÷V(«‹@¦Vs‡df'tiqh0ä¦à$øpM+î„碽r„*HåÿtŒßÊ v Eê#JXkàPy/lOýÖÎÜÛfÞÛ¹!$”ÿ}1›K”¿Ê/H5D¼^ÏØ³'só à`ì•l¾¨'b?&XKpªJxR(Ødè:ô.C³¤À{œ-y¢?¹m;ûh¨‘Uަµ:/‹ù4…'ð‰´À@V5ÐÉf4µÏ[²96ã9üiê3 WËAŽ‚«\²Äá××Yé£qÅîí¾Ž‡Æ|ô(ˆY­ƒ§A ºì?¡ß¿ý÷¯%K¬¯ŽhœUD²AâÈ>N >O7(Ÿï©‰“öÔš¥Ìí4Ï,± i2ʾþlyJ ÌN x¼xó ½ êVþå:¤·;ìyÛ͘p'|íƒ,>Êö5Ô-´]ÙœÂd—%³Æ…FK$«‘–Hëб1Ñsôµø"<­ãî²:hi‹àÒj‹–Bµ!Í,êå1 w‘1£N6Ó7’PV½g>­x‚@2áSìf1'6(Ls-`6’$¾þœeÕ—˜¡èè”þû?‹èíbàY“ßFµëÁÀl>¬I"jöŒ•¦ÿ#÷kLôZ‡ ~‹ÙQ€Á­…}©ÄMn\É# ^ð³á-‘Ú¢*ðwÿ Þç&‘H½x9¸â.ìðÔ\ߌB²æÖ½2„/Í“¤AÉNLoÛš±æÑ•7Ë ™ÚæI*(Ÿÿ5ž^)Z2ß Q¸’¡/ø§ê \»d‰ÞdQ W!  Þ4ï÷8ä×fË^,WóÅòþr!ˆìÚS&øwû軃{E)¤ 2ȇŠúÉ5÷QqáÒ„Úß*¡òà‹9njÓ+qçç²!é{¦8ö¸Ì¡yQK›¬ˆ ß„!ªCã9 ›4ÙÀÂ9•ù<½IoGÇ©>=¾ƒ”>Íb…À»ß]&•Ç8ìb«¨uÑ8Kæ$áA+•wWjzi%Èfýý>iIPà/DŸG¦É\OþªÃ êëÛÿrœ\` 8àå /æÉµ#±4ézdƒvGÉ_§Ì±¶$~/è|8°ôbŠ‚dóA¿»º¹,˜»1ÞáÂÛK’ÒÉTÕWhC9ú ›Û_øñzþ» ѳëI…mL:nÿZ™@òlûå#˜·T¼ÅìdUÛ|™ð.‡€ šV­×Âåä6ìD>P¥/JÓ•Ç|ù”$ª8±C×ÜD  ôÝa†yõ l `o”17/F*Iˆ½ïǰçÓÉóF^ ˜ôMª_’wÑ¥UvŸ§Š\ÐæT20çº%µþå('úXÆ£—Òës½‘ë†S×½]‚~Âñ¨R‘› ®©Ò¡,õ`{Š´sO¹×T-›]ý8t<ÉÉÔ =5Û([ /.¶Á·«›`¤áp`á@‚™>«'û‹©[&ÁevTi1°p¿o;X°Q ëtäù%`<:'¸§ç—/‘nUR)®ß*AZבÔA‡°Æ6%– ïqòTWd²!e;$ÒY^Cô§£j¾äV÷)”Þþ”§i×<.;íÝ~ì4$½/"®h ä§–Ø›žÉ[ñfäûyœbç*aSë²,•¯ur 8)vVí$áì_)¯ÂÿGi=ËdÁ?ŽpŠsz&âW†á²l$:6lim £~ts!~™H—cÀª ZÆìxMú@6,Ù®´']t)waê:…Ò‰6ÕÝ!¢û…ÙÓo޲_ô5ˆEú°ýÆìÕÞ¿.Ågš™üç9~ÃÖXqÏê=‘¢9I€ÂQûÕqÀî¢îŠùÌb¶Rx¦G*»6Iw ůs³ 9¥ëXX“}êV{ÈêæVÙÿ({TJߎÎÖ½m)ºÎ·Ê RØ‘1îm»zL ±'Dâ¦ã²iJÔ Ë²[zð …À=` FÕ’Ù]ª2Uß}CTë…ÖO_WGt}Á‚˜ãýuH3Ú9ƒvboõÿ)XÁV™Ì¯ÏvÖGöGË㈷CÐ’P~š+ÛDAÅ5oŽîfŸÑéñ©H‡mK<8ï8Û«géû‚ê~mqt)•‹¹7]{ŸÏɆ4»Vñ•ê l­é,˜fÛÓä!y¼€ÎQ1ÆàêHzÄÔ­OM󑬳GŸB—÷“¼åØû¬Œâ6™Ðå?Ü5±*Sýþ…¹tŒøõº-`GöõÚµû·«uü–GÞŸ·Z<7¡@Á´sôÅñµ•=×ܳHò/ôTíÆ¬«xs´5ü#;ÉŽ}Ö üPŒe"$âåoßzøx4úª¯¢ƒlÙi²³sˆÅQþ÷I(æ¦íã:tÌÛ@ôD< Á—ù[/˜Âå{×M¢EYbWÔ±Ó ¥•4,€<§ßlt((6Ëp‰¯^ïÆ/ÿf˜B-}÷òbú (»ÎôÁ×]¯*èͼ„ôÏõ†ž}äk¿¥ìŠŽðÈ䟡m–¿Ø4Œ nRã$;¾·„Íá±ç‚|Kà(œ‡Ov®ûÏz*š[„Í–¬ÄãŠí»í“{O7ü\r%¾²RŒÍ€ÚÕ‹EtPÌÀrµ)ÔÅ=H¾DÞ _—‚$Àަ¿Ü¾J‡ÇV>Šst?š²#4¬±Q{ùóÓç,?áçÆ{íÆæ£œµó=æÎi3ôWÚƒýU60 ”Š‹V¦h)09[·ËS þëƱÛô­ž ¾äls‡…é0ò8Æ)ÕÈ üºµg¯“Ì)ƒç Ì¥.?ÑÌ‚ŠFç[2ÑXŠSoÆÿ×xndœ9Ù꯭Q 9Û…hPk/oyA–ÎQ¯Šy" ®ï0ëâhýzOûqÃ|kÕ¡|²"—Ö>g4¯–>iú;Û¢šBåmd ƤÎ[(áÒuÍW|1ãKÑQø³S^9®6°O(V„3½p1ìQrAi"‹aüê–Ç›ÛR2CzZ»D%•ýPv^s×ÉÞŽÃ/9–UÑ·uö]¢W¾"Ñgœ÷¡œhü÷qpï8bxx§u˜ËF¥=ƒ¯* ú°cðøeÃz>s¥ˆÅ€ÇR”±TýšªLìsŠfú¢pž^‡’W¯h´ÍÇãZK1ƒ¼>òê¢\ôÇÂŽÜ„cÁÚ¦”TëšõSý›Ò¨: º’µ_áTÈr¦èmL׎áÅÃqÚ4&ý}˜k}Üô®ŒÊdÉgŽúP‡¨Œ\ƒdI†™<„Æ ú¼Ôû æ!tÞªE\ó­È±ca†àøïÇ#(PåUúm¥Z«M*‡#tÚHQOÞˆTàü…gÞ€µsPHŸZufÈ cc¸UG²†DhÈÈd¿ïWP®ÛÓ®£ü¡PÞëehW ÷%ʽT‘[´bsT>â<Œ@ï8€’½:ÉÍo¢~Çò/ŸØ0|}4ÕÄq°ã Ë•1¸Í„fZ"öu(–«-iñ4¾8—ýð_»«{ „?ŠGm½vSÆ}ö¯5oÑ0•EÔwøŸi.¼ùœ ¸¼‡S„Ä%ô9-¨èò ¢ /_1Üê`B> dÃC:Ÿ}t½ùR>"Ï;'G/í3'9"†þ !‚6º³Ãq·b‘a4M×(^»ÀxaS¶á-‡šDUˆ[–r³êQ¬gÿUº—ð¡Õ&ÝN³ËÙ„â%áØßHÖ«•õ·h”¬™NCŸ` —ò\[{õŒæà•GFÂi‘žH¥§`·9©7ÖÎòœ?!V$5 é~9zf‚RKVocÖˆ"kî,àÞþÈI“`­{TøEéÈ”öwùîËDÅ Ÿ˜¿ä‰ÛŽŸ|Œ€=2{ï»B8ã˘›wl¢Œ%^ú‚¼ BåˆBܶöÊè¨. òÿ>¦PðÛªÏgiðºšHq7¢Õ¤ÖïðÔ>{ Ʀ4"[€8k`|§˜PÂUÀž¼º(̤¨[öóì&ºüþ›º»¤ƒ‘ô/7lÒÁ”‰PÕÌøì<ÙÐp†¦jÆLÅ}ï4ñˆ..U8—ßøÀgMÍò°;—†ë˜cÒõ¦=X`Óûj$üðïÊ 5?!é }€{P‘|%žÂÛÛRÜgìϹÀaTÍ·¹”Ò“œÂ÷3ïéä!Cd);‹ÄŠŒ}ôÿ[,Öúò}˜¾Ð’wœÔ럒M±µ ’~oUðw8F´W0¢8%,Ìx÷T8‡èu(nx-'1ÖÕÚÙ<±Ð ô[+Pt@B¹´„ç {òq´‚Æ„—g?kÏ ð|>-‘” ?™d«jßWiú¶Wí‹ø®=£“Áz»§5/Jçåü0pjÿ9\OØMÄ6ÎFÉ»:rHTdÎŽðKl)ÍÖ©Ê%8é¾;´·?ón=h5xK<ËR/¤7ìÛØS7¨@ iÕz0œÉD…žÒ5ê‰`nŽoj«¼â‘Þ’iÉ¡{㔢a)ãoÿí±¹]`Åp¹Ö«‹¨8÷ >ùá½ä¹=u‚Š)PJ:€”xëÜè+»$Ÿ*d½Å±ùù6KÖ¼½ó{áÓ³¾~PLp¦Ë{­Dè%I1±9À’ÆC€'Eiœ„ "ÕÐø­I̵]x¿÷ª5>NËÔoK)L)4½–Âàˆš´\z”ö–3{ê4¡±S^ ïFX/ëáÏ ·•éñV ®» lIÜø?–¯__Ȳ°©­¹6oo/Ùé¬$l20´šf —(‰IåÕ%.&ÎîéZ¦|Ðõ6‰Gß5&Õ‰£‘F»Šãý²,Mzãáét}ÛBô'^ëEôWdÀQ•Tl]Ø&M“Æupôä«EÛx‚Ä¢\ð†½Ê`Ãïàšï-űìë@‹G$VçòõÎí¿¸ž8½¤7E²Ž Š[ŸòY2¢Š½¹N˜„êÆ;€ŒG].É(ÚªF²ò»ÏÄ/i6çPŽt%zÖ„R&óc„‘FxE^'û·éâ¹'U¡A•ÜvŠù9˜Í‡¤¯†xw$† üùšÏÝ™ _sǨµ­²bÞÛÿqÃ<|{pžr®s€ŽÅqƒ~«þû “)µî±ú0š\UVMWeÿu†2—‰šU"¥'HÕ‡²ýþg°§"5”cG’P ³äèõKsv骡’w;ÙN—+(›Îvâï•é$!·²ËV.ޏÓÑOÈJ9_·]«<‡ ¯QþJü/Áä ÊÙ½) ?&Ü:5gè´uP!ßÂÇ¡VÀgÀ8=ùâÝçŽèÈÒ™.àpÊ×è|]¨ƒûŽ xEÂ#‹˜¹Ñ¹Ú ° ±,6,u¨ ‹–Þåò\7éíXî²/üG£Õ>N>Fý^ö¾ž{6ÊbìJ]’ê®D‡æ l^´Æ6, 7}kB¬çÛv~§‘ëäKÞ3X^¤à63ØK½ÏECJGàndSÑ“÷^ò0FžÉÜ.Çš‰&]f {Ú‡PfC¼ÉÓÉ”mþŠòH1޼˜Àr•sí¯¶$©û´asØOZ²"êx²õ"2EÿÄà=Ú£î éWQoôÔËO{ïM±L}jqo½ ¥¿Æ¦¬ejí,N™Â3tø¯åmûZût;{óÉ0m”ÕÝzò©eÄß^nÛ ø^qæÝ¾2kfªHl5¦öãj_Xk£X"WÁæ-çŸËø@uˆ£è`ÏNâÒ«Ø7f¼k\©WÁ2)™Jo±=¯¤‹Ëæl`E¡ oâëÚ?8a£ÈîOÁë;¹Ý‚ÌEÉ]ЬÚ÷ã0‡ûOü•DuŠyòÿYýM+ÞØ8» ‚ð¡ý0`,ÿ3º–˃*$Æ’)´ü£³pm³¿øž·OqU–…ÀÚè59‘e2t­Î:|°qÁ4¤—–”eËh ú ¡ó¥¹8ö?“1o«}kƒ“OÕ"Ó¼7BBú¦»Kžqc{Xµ‹;7„w­*Ñùâ]_V¨ˆçŒ#c¨TµõþVÑÚ\’C'Ëëº$'´îlW{y ão†’€¡è»'¤¨t‡9Ñ’ŽB¦h‚³ükÈÈŽ+÷lEÒ¾<¢ÚC¹è7*æ¶þ%_ö¶Wú+ù[HÒµNäßnaºLÞ/Ín’yšƒ–Íówws ‚ 2 Ó«~äÅÃaØ'Z´!¥{•09Zýà’eJaŠá›xGÛd y=›«¢±ÌDúq-6"LàL@ø¿rЩÿW€Dçß@“4çˆ0Q½áÕôûp@ BÈæ ÝèbhÞüs>ï㻇À&ƒúVõuÃÁ³PL®áˆ,ÝžˆÔ¯ªô[šü2ƒ™'i¾JÓ|,QIc²¥øS™U+¨>´ØOÿViÜîŠôu»iL¼õ‰8Yç™ÃeN††®&`MgÒ,? ”’`´ŽÒ'î"ÜkÏ+\%G¶£‡ˆ{¸½ÓßX† ecÞž1Z–?Wø¾?¹tuÿ2D2,˜jWΧ×}ŸùßÛv(‚\Ïý³ñÂö3B}H*Õ>ÿtwŽà¤¼,%)­ &çQ¶Ìa¶¶uùËâh§'m*óÃU% þ>äî/‹çÝT]WÁ4Îe!š÷í—áBõ ¶‚šQàG8ÿ )Ó=¹S˜‘œØqÄôúŸŸ½*YâBFV Â=¥@uͺ­°÷¥z´hsKè>»¬Nò‡Ro·ç>£l­[r•ñÌ’Æ ?rwâ $•ÇÞÛ׺gŸƒ]"æeª3Ý㣘›Î:$ª‹a[â 1 =Jl÷ÿþÆ»§e žœ?4ÎxÚu*Þ£€!@É5.”@$²!?@ìtM3{IòFŠæLjfr²Ðè+}œñ³©*r;›gæ"˜®¦ú¡®à¦†ºÝñm`hA tRff Û_4ˆ×îøn×í¤7?%S4"Ý›½ö¡0ý¥Ñ ·$5š –cêòÿãR{jN0QRzQñ°Â>¯ß¥?¸”|¼ª0οÃDý€Ä¢ô5ï¹OWJÊ„S¡V [¤Gþ®ûLï†ntð54„ñhù÷jølñÉÞüïj£ )?BÉæì•MΑÕ,lãcXH·G6ž†§ÈÔ×»Êå0=`°•UáeÒ$Aµ©Æcƒª&Ëã¸Ç<ÕüY)³[&‡W·¹Ÿ{¨iË»môBCø›!í¼ây €áØÀÀõ¯FNVÞôãDšògeÄ¡v0u ÃÀe<î©äP©Ûg(ý^š=Ž sŸoI˜ü¦‡‡Z„¾Û"œ&§¸mÑ+ü«¥Z¬^“Ð4]¾¸>øEGü΂"€ ˆ‚fV†`‘Pî€k &ˆ©–ÛŽº°B=sOÖð)«‰5*¸¯ùÙ0?ëÙT°+œ6W$UVføÓÕx9ÉØa•ø1ÍÀ¾1Þ‹Ãÿ;wfD þ„å01Çà]ljÛ]ÑyY‰(®©F("㊾OfJU!!OáÑš£tÖÌÑ•¢eÔñ§¬ºÆ_ÍüQ:wn d§ñrÚ,> …ÿ2¿……Þÿ48E-Ä'[p Ua!$½Qþèíø°ÚÁ?i|ä¥ï¢Ü™pocOÞKë[iõC£X™æÔ9:WëÚ"\ô/€VEMQæ^ °ÒF˜½Öêï:[õ>ß'Vž {Š„ãaÆ`0µ DÓ¹®~ˆ1«PÆr©/pþv¢2›C°‚­1)@05 L¦ÀÔPH0'8ôM¥¶ß’ æŠßªh'°ŠJj/0\)$(+5LSµHétéÆ>8Wʨ²Ž UÂ03Ô‡K¼þIùÒyM3%’ š€2‚R:— -¦Šý¸Cñ¤Æ¡0UxÙÚQß×jŒ]a$β%ÎèèOcì¼gýiŒÿ+ ¸Ü@Šíîõ• »êç¿Õ q³œç9Îsþ†w€{¦ÒDÞHƒn„n?f¬Âc”?GkÐj×Ê„3(Ȉ«ÿ(6F†6îµ1Œ´ØJïü‚{IBa•3¢ù*|ð´¹~+Aî¶€‰ú5cü$Åœdï¸æp8F©KX)ƒÙ”LäcfXal†ÒIÿ|3›4—o`ê!õY¾õýIKõé,+`¶JNsœñcë÷½#YQv­ƒ+R½ƒ‚1ëjé=†³5T‘Ùå(Ä”W”í¿­¾\º'ƒ×ðX`-ÛŒ³ˆ@zà›Ó(¢a“1xPÚgšËoÈMDçô[;)³qßgHnn{F©ä¯•áiB¡¼]0ü¬;vèÄé^ƒýÿ_¬CGÕ“å¸@–yœ+qcm>c2RÍùkñÎ1¥X°ÎâŒ^—¼‹O}Öá")íaóÅ!wz^¹Nî¼ÛÚ¤2^Îê 1Ê.˜’Rç葌 Ï×N××~‘4O‹P8A·Z^]!ÖÅö€³—öd> á @½!*¼yÿbcŒï)ÖL“{ÐW’¿ôèLeý¼°­x_ùÆYc9U+†Õ¢†IW_#ïI4 2èýx‡Um ®çÕ-ÛR$‰“md.þ‹QÅcþ¡+>Ø)²¿N=E»1d‚–€o/N™Ÿš Ýû‚<ç+o±§*“E| «ƒ8*‚êoGÆÃÄUÐN|¬-Ì •5ñ;P#>Ø(¿.Xûó;)šd¬pèKjÁËGîÂÙAkeÅçÛ #½ãqgw÷SF8$cg¤3Jš}Æ;“ Šëôšx¯6[}»˜@,h¯¤û²{.ÌÙ+tG¯÷nÆY–x£IÂ…é‹E?:Gµþ(ÜÉ/¿ kl•b5Ê«©Œ®ûé5YMÝT¨Î£Èv£@ôª'ØäÃÇ„ðTnÔˆh?®ÖÊlˆ†L•Éøˆ¾u›íôØ­ «$£!»—üØaC¾´²CÆhª¡:ž¡½ÙI”'nê—Dj@œ#¢P#¥2ÆKr½Þ ¬b„Òð¶6hóðÌ׋ ¸–вYöÿJîQM%6ŠÎ’¯è_ËŒ  7Ü^‘83±,%ЉÐÝ|3X¶øŒ`JÆÅºÂ,ý8ëähÿ"d°¨#¡ÉG‡ëÁàôæçù'Êöó—ÌÕôxÜŸ=£in¾#…]UU `#ÊŒâz¯ ¡‰¿ƒ' L_¤ññÃ’Z´üT¿”C> +ÐúúRíâ'.Õç¡PáÕ¨tj™N`¨bßvzŠŠ^_ÄǧáµHó ê¦ŽõÏíF–n î`Õˆ/<ä3•1ðÐ)BaàÖS°£Û¸9”I-ÇBx|_ƒhò8–'2Æî!8ü' ?:Þñ5s¬t‹“E*âgÅR¿2q–Û¾3‹²¹çFå¸Â9Ÿ§&ŸŒ^Eˆ*Ý$pîùg”²õæ#.] :SøÌ»sg¸ÄrŽY:0bæ¤:“‹=*…’™šÐv£È’¿ÁÀ{w„Á§Olã¿%Ÿ¦3szªî•íº¦tKK`,ë)MÌŽõvV(J`ÿykàc&þɇlïZÅk¥ãw”ö§l0¾m£TH‘©;—L€8Ê“Xœ!tKé¿Yo%6HÙäÄV×›ºØ5œÓ(µIMTlIl…©Éœê8_)¤´¯¹Ë$:–lÝÏñ„4úŽÞ)˸äsrRsž«à4ÅÝÄú¼>Án’“Ôtþ‰ß瘼cì¥J¹¼l+HªT‘,=¶vp±Ô0ò¸Ú¼®®¼œÒÿòZžÏ3?Ñw7zž0‹ÕQc½YÒsæ•óÿnùØá2 ÁéGÇ0pöËã 0¨âÊàÀµv"O-Ý8°SËÕ^¾H7zðJéCN¤Øî£}Þáñ}_%‡pÜK@weƒåû íÊX©¯ Í];%A0$%ÿO½æ°ØyRôç_S€×²MðKaŒS‡mWð=Ï*?‚@Gý ‹52PÜ#Hwæ•“˜ËWž–¬Ë6ôŽÈà=•œFøyÝ®Z©nÓò|?UbAÃO‘Ja I'Ã:âÔ[${œÐôI¢‹hÛ‘@ìt©X?Zr³W›ÒäÎ[wÅ”ÇÒœ7ÐS¹&$÷Õ\Ä*?PpÍ]Q¨³D˜hù À£"óí-Z´cÙ»°Ís~Í0ùx†7——ÿÿ(´¥9ÎpN‹"—a! ãÖ¦ûÞD¹K{—ÌM(ýEª˜.@@]ÿ2à.~tP;£—=0%¢"Ñ<Ï­„TiÎ.o„|GÇ`%|}Ä!›I­ëTõÜpðL;íÚBŸjóH$ùþ<‰4kKÖÖÕ|§->× ´‡ÿ6¹j DèuX @.çõ‘ÜÐ S*ªªªªí·,œ~%8®Úv6À,fQúM¸IâlïfŒRA{ÿ ¨ %ø“+»/WŽ‘ÀO©…µrÔ­_óP]ù­5†Ý×Gúá®JmWá«ìïÜ$òUú¾¡86_x§g!ø·VØo‘Lï{;턟©A¶ë$\-‹4â;WÙõñõ×í@€1®Õi¾Ý°Û©ìõÀ“Ž$[Åe ¯ãFÐø•°y÷ 8Qvšêìñi%×oèçMŸZó·÷ƒ:32HBùþÖ9€)l" àº?$]ýx´¿Þ÷b}ÞM¶Òz´ýc¨‰•)¿$x @ÁòæP‰‹†MàÒÿ+× Æ!èc=f¼×EVXÉ—Àñ♌$ ¾ßÿ ø¿^"CËvxZ=ꢧôÈ–ó»²á³áåAè,[¤ø(E™âŠNL¨TšþîKÂñv'åv8ýÏXÑ/X;‡zÒ.`¤bhXDRDot{þÊüݱBI–AÚ×~A#i}Ó=JI®î'.‚I$’I$’I$‘õñ§Ÿ4~BáË`Í—SÂÂ>Êöxó)´§ýÈ{PüçA¤Æ&)`¸bç– ¹ibÔQ}˜ÜåF À2ŒŸ H\M6›­]ÄöÂû-Û¨å³ÌãRGãåQ¨üU»íWêQŸÝ®U5yL©×  À¦ø:2ʪªªªªªªªªªªªªª¾ì¼ýN@Ò»á3”Ê~uG/zÞ j G.\›ÆðxÅ h«´èvì&OÎIŽ<[T¿øS¸Jù€\ðÙµÒófÅ©FðO *½§©á€v©+¸Ýúª*PúcZdÞC„þÿJ·û$ªžÜ&¿4 ŠcQ‘˜V9ƒâH(‹H€±Ÿœ³ ±Ôai: NJ•Mž½Ý»W/ÙCrÎ"Ôsi¹Ë*·îùuÀ¯Éz¤—ë^üáE{cºÊT\úáiÝ-|¾'P8Ñe£t~Ÿ³M”¸µu¼£”û:s”|²^Ó*ùp/‘ÔæãáÏ0ººðv‹]Ú•çà¿lXºZuò¶ž®U'X8»Eº` é™ÛèÀÜןu¸àwÄò KIóë$í¢Y8—ÿ&S­tÊ©\)JçÀ rLÿIE\ÇßV;¤N™,tº6¨½ßù–2 ‡F”ô§çÁtå¥8Ôkº41Ç 8 Jœò•æÅføjÞ‡òuß²@ù¡æÒø‡üth'E‘ÓÚbmà!X{È>þÈœ°r©güÓ–Epp9îáðJŸÍÊCp¸àÔ’¶Èµ¿ëtš ââΤô|`t0%Ó—PЇ[A̵¼F‡Ò_ñÓ6Î èÌB Ù)ùûƒƒP,•ó<Òx}7„Æ3(ëÈ`?e¯ ª‰ÿÍ ºµ‚åTeÁC_•ŠÍpȾGˆnviê…3š—‚Æõ*kOCíu°¼]—ÊŠ½*믎ânŠ03ˆtìE ßGÞ–šEñ]è-ÔàÐöA÷G:IBˆ2ž;†lÁ1ʨ!g®ú•õC¬rcÈG¬ˆñy »Þá[ Íto81-Ð:%´#íÿ7!×’°² óÚ\Ò5#fJÏ­nåù-ž=·JÌÔøtµ?íþ:c±o¦Ý¬HÊ/›4Eæ¿}9 ÉG|-ÅõäX†˜O ˦Ÿ)z Ÿ¹_käýZðØ0*À%³*úI½>¿N5iì%œÀ“Œ„ЛÅóðçßKJ²š\wdÌ†Ì ”¨o±H¾ éq A+ò¸SÓoŸ 0–µIƒËò¶q†ý§nTs'ÿ–X¨ƒB+ÖxlÑáKªÐR¢îàýg™ã}Ûé·= Èãœ!ÞHÅJWå2Á¦SìUì1Ž€ÄˆPÔ”Ê1Wÿz?Œâ/€.…¼ V²çÉÃî 4š­Ïp¶}y§*[Âe½¼;…Žv° i1…ÖMe«\}¢ïÚóÓ@ô)Í+„ÏPþ&| D·­û‡›±îöÝ­À–ÊâsLƒÙ‘Ðr‰iDÛ6ghÏcäÔ‘0@íM2’Dy>ØñÓcSlnI(õ°¿-$aÿÏ$§²¶— ùH<ôlÅ•ýãd‡]5~Éè ˆ"ÄfÃb¹œÍ•G<&5ÖW3ôru¶Z1ÇI‚Â}Y)*`²´™€oê0c9Å+sY>2QîIo&ùQ¾QCn­ gÀ³ ˺¢[ÜÏ ™q‰Ø#‘Jý;Ï_%?Ú$¤…q‘&>>Ð\xRý#—t`Âx:C€¨¤DЩ¯t0½tdcø²´Æ:&“tÛÒý4ÒÌ‚™€BÇìü@+Ýò? VZ\'j7X`esG%gŠïœöX!jGúà(6áÛ™¡h:ÿ\Óö±•Öq:ˆëÜí²MÈYTÅr,ŠÝo-,©E¦ÞÃ!ê€4ÀtŒ¤i ŒQ€Äˆ|Á8§ 6½í˹>!oKd¹=L‡=ñ›‚k¯sø‹3…`Ral]ß/¦Oöêk­$D‡Zãû(só¸z¼âN÷âqßä'5 ç*D€ìº% ©<î«èBÃiÑãe±á wIˆK+Aoi‚×XÌïN…Ìzõ˜sÆ—4ëÏ¥3ÙFŒdäø à4 ­ÆN˜:°À[8óè˜\HÁ8GDëïâ?º¼3‰YȰ€=C\¸'É\÷4ÏJôÁ>qñ5åÍøÝV0FxTì½F\G#.'çÔÏÁ ªN…öôéÅÀ?ßšÈbjšvO’^ÍçЃw§Û {ͽ²¿g€úÛ$ÏœiZ°¶f†Scv „ÄÉYé†xd9ÍOçÁ»Ò©+Õc[=;‚m9´¸½#šê©ÎÙò¹Æï®OÛÝÌÌëÂDRàš¢0~Ú%ݘä¨k"´ÚÀD…ÿD€ô€ž­òæ‰êþ%šÑ³ù¦ÇôÕuä¾Ðy±³šÎk²n k/rš Êr”F=eúìxe‰L¦sÇßúÿ]ýì /•Æ¥`©|ÎEhl%ÝU†æÞ<4«0e¤FDÛ|r÷k’iàìµ®‰™Ýýj<ÃG¨·ž‚gùÛ÷isìøPsöxP?EÒq›ÓØÞqUÒ7ã ¤ô’TÛ±%ˆ|]êÉXIïña[æís\ðÞÆ³Âl‹d]%ÕÖ%5b¾vÙWù:-8‹#Ö‡/Oܨ‡bù}´Ëvh4‘›ìnÜu²Fwdäït£¦x§/Mû•:áþ?×Þ&…“’-"ƒík'c%ºj w„ (7¿±–†;$hFgØvˆ­=—¨yþGr°óx$>sðe:YD›€S“qÛƒ¶gJpîºfõ®ju8d||0¶cÍQ7Y£M lwÍóýÏ k(ÚŸ6^ìv¶‰Y˜ŒêØ< „;6±À,87Ò1Û$úÂX 1)¶ŒD¦ b“Þ£‰ùŽC¼Š{PÇm$€`éú -ÕüGaxùj/ŠlbòâõUkÇ!qô1rp<œ lúÍ•ÜçR_&b4 ʼhÓ€üpOļu lBÁ² 8<ÇÝü°(™ˆÝ¡õÚv­á:Ë¡Âr]ÃtFʰýࢰãS¿bú+õep›p›eÍtò‘ÞÃOMö€CÓ¥)Z/ç–Å B³³*¡qáþ0µ×DùÎ1o ‰ŠÏb¿™'Oø“‹°—´Ž'N.ÍïUÀ?øÓx+ZfáN’Õ<6ß´s÷H£ÈR|¯-ØJœÒy~åâbؽěÁõ¾~x®&µJÀšéŒ†#‹9†Îh˜ºõ½tDÙ'Î%RšºNÿ=3@‘ý‚ •C1ÄLcY¼ñ×PÌݘC•}Øgê€ÜZÉ&gó²ß5÷„C ¤>ÅõžÁ†gý%‡Ÿ·àôèȬ7=ñ$ÔD¼¥Ô©Àz€¡#ØÖí}o·êpàÍÁpÔ^ ®Ú&}gV…ˆ{×P–°G©ï‘‡kgGÒ•<„RFàx?Sñj?%K÷ÞL×§Ú;6+"Ç…kB+]ÒÄ/«éĨûª:†Œ|8oÆnS=CN-`~Ìipñ ¥?ÿ}cE**Í •.’0¨íAðýIœò^2ÊuobóÖó|É®iA£¤•k9zÛ› DF÷Ôø.ʤœŠÙ ÀOÎxpøM»@*'ïZ ˜æ³Úé*fiˆ%µÚ¸\•{–7( tÂuža °ŒÞ•‘ZBqV qïÔ•´còºg&,©E]C™n ƒƒäffMOÉÉɹ°# Ò(†Îƒ…^MتþWð%¯ —#g­7ßXfwÌå¦O^š§†Œs[ô¦˜NN6¶uTXÂü/fÕ¡W˜Iצ„E›¡“r1JÉøÿ ¯h€ûÞç˜wž0žðk‰]XZ ~ Û V¦ßùÖˆèdº´“F}võ„oEdTÄågÛkgçXVðÎ's‰ƒ’¬Éfߟ†ŠÚ}`Öo"këByêê²›“ÑÂU£ó®T´ïÊFîõeæýü±ólבµGÌ<¤Bñî÷£ÒB·q á¡:’±YîX`t*¢m(Ôxç¹¥üžpÈhÀ…s,Êh[<%S ßV U„PÇ)¬ŸNÏɪμw¤élǽ³t|ÌF©<6‘æ»y”š´û&öïzk9fLKÂoî/N{¿„»{kF•`¾épßÐVúo!ièú‡ÕzãQ3ÆfÏ©qÉ`ê¬\d ´þ]Š£vR‹ϵÑóAE¡ƒ€;Š$?¶©ø4?™ù›dðòHõ?]Í{´ñ4cÁw¾v"cÓ@V6jVü˜ö3f½Wº—=žh:1½ÆÊpPN–‚¢XÆJã)²ÑBG6?èŒ P:” è´»J5Vñ;§kÕþÐÔ _°s@G9£UM纞'©qmüu•Ì&Іv"šD§"ú[_ý3.ý< wªPQáÐE²’uró†'ÂÈ˪XtÞ•l©ž?à”·Ítå! úâ` î\÷”bñdû^?xôét™ëø§hE½ìõø¦CÊ¡η”®–ðøìô3¨P«Ô‰é1EŠzV½ÔÈ&¥FgäëHW°éwþr„åù°eA™ï .ëW‹öxíÈx3rƒÐ$kìà4$òï1þäCÇbÂÚéŸéð´•Øê$Èý °¬”²O*Þ*É,uXêœiX8ðöUUåû¤púh;¼`Tž7ïf w@Ý¸É ÃvWLÆãy÷àkµ›BHúb× ŒÏZnÔ=ÛA&4n’;qXEÍ©ó2²&Å3ûÎÒ€Œ0ØáU?íòXŸãìà ѯÉüqyl a³üåê»;pì'ëû3ýzäa˜tT‡ÔÓܼˆœ( Žpÿ.…IÎ૦»Â×SŒ6JaÌÊÁÂÓû.S Ã[=k$UÞ3¦ ‰uɧ0¼QÎÍ€S ,·Šý!“€ƒÀMXïž ÷²hP6ã—ýBÚO•ëzeÉ@Þ-ÐñØUlF ýgFmäW7d&ÈÜ1ëD¼[”bIå½ázÛ 3‘F=»*XíŤI¸Æ>W2u“„fhO'að™—ÊiÌó@¯Í™+7š~ŒÏ%BÈD+išøã1u!tf.ïßÀôÌ7µl£˜eW»=æ8°•joeÅÐ;Tmh1àûÌ<%Ûñ¢±Æò '•ñ³}·ß.Ô…M6ªXHbJò°Z@s~˜jœÌu¦4:>'ÑtHð¼Ó.>ŒÌ¹¾Öc«æ}Êtö:Jª¦K!Dxζ–„8­X„WÆŸ=çr壔)sO'pþ»ÈÊ}Ö?24{Ò’a„€8A{&r^2$7£j?Ÿ³&¤I³VÍ»Þ)ÿ'c–›;¢»>‰À¡õVüô‹©™¿Ý·.XôŽSgµãWi¢î}ìeRѼà+ÕjºT܈Y ­”¼Ã¢Zwc´Š»eîÄý§ß£ƒÿûDÄ€@Ö+Šë¥@÷·ªÛ\š§®^½oɵVLòQ6ý}¦tÓ•~ É5ÅŽº)«Ÿ³E(÷ðÒn$²Ä ©¹ºƒ y9óyý5Gú»_Öñ¥  ‡+þ-‡ÍWîx”?8Ky9™9Öj‹Lù.Ùäµ=’)l(9"›^$‚+mÇlæÇn®‰„5"iPËrЯڀ%¥k³]U H/€§4fÚü*Ì4c˜L­å?A£)…­ñI ®Ág4?‘]“J7$ÄÑ›OùDxù"rã^\ù»O c¶#û‡Y‚÷C¹»ñô­Â_¹Ä\ù-àÞËòFj:4ŒÿG÷­›ÎKÊ?R§„ý¯0\ÆCJ ÂúéðùµâÕϲyóä¨Ü Mn³CMB¶l<„–E–Óâð~öÝãŽdŸ<{Íu»2FT ©ñ+ý4 ¹Y4*±fäñ 7ÍŽÏá²åÄ‹`C]˜¤ŽÇ–ÃEaõ¬0Û£8cż8xFÈ,l þªÐ¥€/\\ÝÂ5£¿×›9ëžHÅ×™–"E±äPªï`,Ͻ æàÂ@±­­²1ÇdHÇÄMÁ²1Þ4è,wm~U|‘*e”5u^—ÂÑâÀ>q@æT)bNk‚Klë© *a¾¤¼{)ÜàÍMO}Qgˆ8•Gøj²µ­ñLœÒæ®êM^ô¤õ~]ù eIæ8Ò§{(šg] q¿$‚̼€_¶¥‹® ô¹_J0¾‰aItþbÃ,Þ§÷IÃî84øúÕ˜^Ep‘…švׂç䨌›2¡‘P‘[¯”ä³+´Ÿ¬ø¡:±|r˜x8–Õ~Ó7èx‰áË´JÍEÉDF;¤“6‘ëá «Ao…‹ìÐG¾áŽ¢¯ûwTqô× _ ’‘ô>N†AÚýx*™]Ü&H›ò¸cb‹àÏÔðsñ<ø¦VZñ Sb9¾%8nsÍñ8ï:ÚšÖþÕòC{•—ã·*@M2Q²¸Ú€«Þ|Ðè=åH;ÝæH—!•Œ—9bt=uñ]ÐQ@ó®£H¤ð³XûãjO0ËTz©¾H9o‚i?ì!á»ÕÝŽ»†\\ÛB½­*'þœÅ)ÛxÜ"ãG†ç0O]ÿpÞ!­ ImmÙJ'V•—¤MfôÑ~›ÜܨõùßåÞ8êL çxö±Oï¡îvø¢¿=Œ­3͘Ͱá^Ëñ6†6 )ßçD°Ì—á=·ËŒ>)*³×^®Ù;ø(*®—Íz¼â*´ùÑqÃkm«n—vhõ‰#"©îpà>÷ï›Æ™ÉÍPíµ˜›uÌŽû!]‡ƒdo:z¢z/]›LË{Î@Y€µxÚlZí÷WÑ—ªbŸh±C™ËüPn:\À])‡™äÈÚŒk²Ïx¦7Å*è bpz» âúÆÑÔ¿+do{¨B²X(‡Óˆ^ÿ%gHC"ˆõèG•…®N,ò6 MYö˜Vð¸¹äL,!mÐ5cΔÔ_[ÐmçPú¿ªü¯7{ÖÀ^˜{K·%›—ø楴éª6ûàÚ¤r´Íï]¥2ê$4©+þoÛt°ö±R1aöä#•íE[ŠrË#ªÓ‡òõU_˜xÇE*b¶oË D¼êÝ4][?€ÆßÅ[¼šøïq!]6ýƒ²ÅÄ!žÌµÒó"h‹˜“…µ‚ªèä+h¸¼D¨à2jž9±L RÝèø §sÑe7.êÑy£= W§ÍMäï°Ü“Áß(=Ÿ"d Ýo‰Vh5‚ûûéu‡Äì¯ëcnÇêcà ¶s:˜ åT²•R6‡ük€ZÂPšKv¥² !gÿZª|L z-·7wÿø$v¼©¹‰V;µÙ}qSéiÞ\\öpžE.زbŒ·aU$Ü=²Èž׸”/ 1QÏš(tФgìòë¶cb]ä*¼¾7CÄ/ïarnþZ¯¾o?D@Œ^oSÖŒŒVN êǪÍC²Y9¬óË|û˜>ú`ü@)’Ù=†›LkØg^ÎO®+áØô,jtЏ#ÔZóúý¿Lèó¡œóóF¯·æÔðä´¤ÇêpßbÓSÀJÍ\´Í‚mÀù= Àî°þDâ£ýÓÓôL—ùœu ¿”ê9³jŒg½z, ½b‚õÆÚôݲ¦½!-u©Æô© PÃÛÜÔOôË ¾*êHhCÖÆOVäÕ³¢i१ê3Û>ˆ{t.¨aY‰}Íum$$Khá|£9‹÷U²ÛràêãÌÿT”v4¾«tP>íÝje–oðö ªÉtæq¹òÔÕ¨®Ø)Bûmíj^e~“³Ét’}‚pá}v )KÄÐQjAƒ„H¥XçÚ©G ICzxááýÉ’% &’TZÒ-å‹§_†ú¾øIÄ ö»2ŽN3¡7y/ªsîA!L¤Ö”²Èóü.>W‡ÉXþð£àõÿ$¿Âþ}­ÚÙü4 ¯áeÿ)¿…%ü,ÛíA'Ô}ϵcêAþveøSwáK;oð­#ç¯qóØ…üà‹ÿ:ÿ'ð²/µ–}Lÿadò€ú£OBë·ûOˆþÒŸÔ„X*—âˆ-f¨Wðôý[¸"~§_²T@ò ¶>ã?ïóU8†ð.©WñÁˆke<¾Äõ 9¬º)ì‘«T÷C*û¯Š Õ<ׂÿYU0m#›ç€9’ºœ¸%&þ7Y"-¸§Ä|`Øl6Î*ADÖ:bð¦g–pD +aŽ}ÿ Q/!í,ªIk÷»ÛJH^ëæù»ìjC‚¢dH}È,|€š“ÐŽ‹øj¾êž¾<&î%¢‰¬9*vÐð?v-6xe§ÝßÕ]×ÍÿÎWÚ;M‡½;ÆÍmphÉÖmƒ ~iÙ]GCè6,FSæEŒT¥çê<• õ’¼/² ;Ï13í=þ£¨KÈ(ŒXì> JDZ\T^Ñô¨“_âøznÛ :ÆòÜ^ŽOžÈú*È£ƒgoù¶d5ÿ]-v£zJ|lÇÀ#¥«gÝ…_Ž©÷UG[^™»~n¢ä—° ‰•|BàµT;ˆã^—Ò3aƒ$ÕóN¹ïÍ ƒË]Ø)„¨v®§þKÍÎF!Ûº¸[Ö×Yô¹”?c*äo„±hq¨+7e^V½m`zö›D˜ŠNan¹å§Âœ«;mšÌÜ–)˜ôes·:Y¦Rß³N+Møþ­›'~›YÌ•7È\º{¶$¦NAÊGVO,¬—^Óà‚Ó›ˆ½É¤àMæ)ë(çÑ¿žQoéú Ù;M1}“ðV®¢öŽê±T¶×vÕæ¼ß?+ª#}qËã+T$7ö!z4À ô‘ šÎw¸\n$»±ùN&|ă5ò³µ§Jà™‚&•:^IÄuÌý#KÓö¬1- ºYmà_O»vQ OÀ¹kžåÒt”…xMáW3×îÛ? ”— ²vˆR3Xb. VÝ|ß=Ä/=—H=to<¼Äzq`›1þ»¯›æó)z¸»\м¼ÇªOeEN²òòðe„3ß䀔TYyyïs’Jãòóš9õÀw àN%/·ê$˜Å„#¡¾FrÊ`Ѥ>æÿ<#zV* ûZÖ”!•±â‚Ó@ÚÇ]<¬»¬U¹D—êÄè ¯ûŒì¸2ø0u9þTä´Ç4£&B$Æü I”ƒÌ-ù'Îg‰–£5ò³µs Àg5Hj‘má7™Tã|½êñ½Ø¨¤çô&OQß4+zQi“úë5§·—¶k:œ¸.%ªBÉž¦b¥Ð 3>®TŸ@ÿ$y¼ß7Î$Öª¸l60f1ô0›¯›æùÈ„‚ˆ¹µ.^^»Íd¾>)A®gÕÒ,>A!Í"¼hbÆB)Þo [¯›æ)ø8ü„ýãÅëÒûp°%½Ó™í5¨¬&ì]©Ri}½ QaÞ^^]ƒ.79öÆiò6¿‚” ÖIߊró-®uç4ÚÀûëÃò1€MÐòòñnðÅ8~qÔÌ¢ÖÀ€}ñw?v±êÅ}Ý</2ë@šXLümí¸ÿCîu)PýLø´z߯4³ûJ;œO²ËLõö<Å3ê¦U§ä¹e£’ú†ê[;œšÓ Jªf·”ÖHÛ¹ ¨)Iú6F“ m}Ê„‘ÆÓsßyh -~¿Âýóö)v¡ÿM E‡–¾’T¨¤]Ý7X¡‡b/cËhæ[uVöãUŽœ#xœ…áyI:ìÀc”@7äF“DT(@š’ß»uöJ±Lšv ú$è$ÞߨÌéʈQÁ÷ ü…›s?™å2ÈŸ"àÑ -fC%1¥êa„ñ wêU`ͳq'$ø÷­³J¤í1Ë»·¸3¦B¸ÓÄûÿIîOû×#³ßÊÙ‹.Š=p !e‹ÙÛà€›ÒUÜE؈›Õ”‰ˆÁÛîèÀ úïê®\¯(‘SÏçË›oãü┳ùj¯â“W¸±\Y‚ –8ÃOqwN§4¢¼º Œ†YézÈ[3ì øDû¸Ï’Ì––öÖ)°cùô+Ïv¬¶Õ ÿS&Ô‘)…ß7› íÊQ„oj¹Õ_5LµÀêkãxÕ†Äà/w!›6û•‚c<³'ç ýŒT -»‡vR³Œµ¡ <,"óW¬›0€Ð”}’¿ŸREºóµhð}€r—?âØ‹(Òц¦áÈÝB×^4›oO%‘ŽVæOZ•.IïmÝ׬PÀÓæ‰2Org?˜–u”‰\÷:ô–ð/(`ð#Ç{™`dLI/JUýïeá86§ÞàãïÙ¯èlfÝÙ“?à ¡;¨^X¸`ãyÅ‘äÈN«Ñ`áf2>pÛìóG˜{¥rØ£žnå÷}I5àCXOLR¢qH¡u¾ñ³IG=å\_" žÖ­.5­Ù}þÜ¢Á?³qWðo²›¿m9ŒpÍŠrVï˧κ¦éQ¼ŸÆ×KÍ.HDÿw³…>õCÊÆQC]69(dëA2¬‚ÕÌynVy)ީվê¯%áqÝÕä#È:ÙîŒ`úCñ‰Ô¶¾Š«g›’d gÖ†fKå@+šN@4“uËÝâ=f‰Ißm¼4ªOÊŽyæÏ`¼sT[f¿fm{ ~¥å€aµZ¡8uŠe®ž[ØRrõ7ý%4IÜ­wÕuQ²ù–›~¢A÷Á>ƒk,E*Fö/g8#¥7d?ÿ-H§âÎźçÆëÿ(B±‹±.ò]ô݊ѾÆyñ²I哜㗹DUûÄ×ÁX«Á¨3<Þn†üú*•¢çç«Q*Ø>Éh(8î}>h“jl@"›T<ÝçÏûšQø˜¡ô=Ekûƒù­}PaXfµT!?¸\¬-CŸÐ,ºŠCÌ´ø8C|jâ—F>³ SI•Xøò$gaÈ‚x…nìŸkêSô²ç:®'‚§¢YM2LðÈmÏjô¯løÖ‚/öýaÁ<þÇ£Ê"êA0Ú4+l¦  UVúãtW‘¾ðR2s5¨c¯[^SÐg4Ðp }ÈG"j,>YŸÙëÁn«'¶)ܳÑ'Og¶®mi<’ T{.ž~TVÝ@ kKbòc€*ñix¬öš$Äo #þ{³ló90v——ÔŽÒöb°$îlüVÇ/ÝOdŒÝ›_´ ¤ Køý-nyäÿ9ðþ¸Ã4Ž5Ö4äj>¬¨ ÍãÉu V±(ÆànÔIl¯¦E¼sjYzûA_—üåÆ ²W=§ÇïðG}SŠžL¬$ÀQa¡¡)UXTÑ•U¥-6/IÞÇá¿ ï¨íEgJQqmâá+}x¼»Qéº=Ùø$ˆ!ÖÜä¨/?ðôG(ô4ü4VGcÌZƒ]:.d4f7z>b¬)Õ1ArI‰››·ÚóøO4œ” D®…ú[ð¨: ï\ú+ø‰ÿpg´*½¡ÕYpXýˆM{@Vj=!ï0’OÊ-IŽì“5i¬ÐY·3÷Ða«ïiª]$Jm«5u…íMÃd›âÿG”¯e4pª”×oA &b€òªŽÃZîÀþøÜ_NôÔ+ܾÌz©¸ÑSEJ|?.cH~ŒÁ©|WJSï#Cœ3›{g3ÀIOÖç]ТCÖLÒÙ‰µÞø"†½ïmk¤„%ù«TÜ5ø™cÌmDm¡ÅûFsMÞ¸ !bž¿õÌËvïÂäzú[ڞËÁÆÕ„èݹÚE— ˹»¯2¶Iï_`‡­\¨è´a¦ñÛõ/}Ñbb@øÖó®4bRµÒê—wºQa6åéÄ©Uf tÜoL®¬ª¡/Š ¡|èWÈôñ3eLÈšÞVËã¡Èˆp/I>$ßr Òbhx”UÂà†Q>X*x£ÀUžà»öÃyÑÎl&†ùüí3œD˜)(0ó¼[SæžZ©ct~xN+¤±ã Ãíh \i§M¥1§Ö3ÃñËC먟HÙìdع2 ËuA‡LöfIv¼FSOoX¯ûê¢aêÓ!L.Jk%ß’ëh¶uÇ BC“–YO(¦d`ùá©óV+cæ1UH÷fQEèö\s¬èˆœ Ñ)Ī÷øTÍë‰33âÅ™3„ÊwÊò5ÛVH]úÎrpM{Šilw4ŒÔóVm/_±Š“E\€Qv¯½„N½`K#×›VDçS / fHK¢“”»ÞS»éø{RþwèèòIòÓ¦zɃ˜oö«B…å$~éŸJWðÇ"øzV -€Ìû‘H:Z h-Lð ït~‰n$tÿ"÷;l·s*Р <÷ˆ—Çuëôv¿Ð¯´‚ƶ³Œ –>èH6â+[1µí‹Ââ“ݘ?RÛI KØ$w#Ct¡+K0ðTp¬’÷4(Üò­íéå®U``mý:C×µG`z!µõj@ÔßÓãë&t«?„ è=¨kT¢œEÛ.µ¬ ×_põ£X˜PäØ%·œ!­©ì--bÅ@ áçâec¡¡)dÃ}ÓYúøÉ¢‡4å|G¹ë*Ö8!a"³¾é¶Ó·‘Y‹h¯íÈÐÓ ÒÍ£a“Ç÷« ÇË9Ï´ ŧ=Õ_H¼h˜‚èÿ,Ó“üÕi_Ï­×MwB™Rµ£Ö[{Ò4!M亄Cº4:ZÙý¯‰+N±b×oë˜ÍÐÚÝv±3Á’äñº£I¬·Ã ^D>Ý'r‘Q1%=÷c!\ï"7+à‹hè=¸iØÄ­\jnKÏ4‡˜†á(däÕOdXNT÷V*ÄOÁò­ÍGíÑóôeÌZ p÷€öwªœÃS Xz’ìÙÞúØÙîÀ1t£ãÁr¼§F7¿ýùW£X8õÄñ©îŒ9¿²ö9<Ö+–Z_2§²ÝÒÀÕ¬ú¨§ð[oÛÑRíZ+þ¿„ ;+s–üæqK©ú$ÇHÙI½åvVÑÏÀèmÌ2 "mÇWØCÏu^”Cvî1³Þéë=G ’>Wvá%”òm"*hÙúDò=ÂUÒ;†ˆÅÐ%®ëkî÷J–ˆµ©êAþ@gÀµÒSG‘FrMÈÊ:˜×«eŸïK$»]B—€P<ð>¥ê}õh¡t!0¾)nTHÉtì@Ý#ÜÂ@CU*¼ìl—Bb:ï!nÅì³üÚü9^=bÔìšÃ}ÊäH_Wé̤)Ä0¿ðøàqÞ=¶›‰z”Õ1%Ú)žzæŠ?Dv(ÍB½‘ÌíÀ,Ôò?"¸2.])}zÇšu½‘&¨Æ­|Œ=ÎLcð=Øj*·íÎ…0Ai8ŠwJ*Ç᳎ïH*ôfí­Í×A0E‰L„óAš•êH#ÚºPû(@Š'¦“PA‚ýÁ„*/ ?ðôO•S¢ÈY M°3SdlåàöMl"ÍñˆÒJë§ÇÞß5ÄA4Ä€¶ŽeÉkñªœ0 úÄfà)ÃÊ|ß üUj—ì—æP æ””tÿ#™¶êaïB²‹N¾,´ze›_Îí=Zj{°Û¶x}¶Aêq(ÀÖu@\Ý0‘²T¬–™€Án»¸’›¤~ËQ­/À?í¡V¿!ØuÈ Û4ÇlÌ¥ .@“¢— †•ãè]ªò6(¼ruàï©DßGfùL e¤))ú®ˆÜßµ à6–»!äí€-qèN`ÆÉÏÚ&"|¹>ífÔFÄ‹ÅÑ`‘R¶Œî3Ý]B2éqõÄ¿;Û¤jt™—lŸÒe6wÅù®L†;ÖÙm6Q§âÀ,äâ>TwÐÙ±ÇG'ÿ8ØÖ÷¦ WÎMƒ·†±™”#"™Nº„л^ŸŸ’¬`f)oùÃË%ªË)U'Oæø˜ð˜|Éyy·Öf܉ãžC^XkRT•¢A ~F5 Ñ›È7cS× s¶]Ý’Ž¸ºst©C²}¯ Bß!³GùìØWûeNçåVýÊŽo(4p|€ˆå-âmÉŠ£À¬QäŽÆðó÷ê±§¸ÈTÃd±²:e\Ùjv·HhÇ£c0‚w.¢‹Ò´lt!? žu@Qø @D8A¤f&½ È(¹.9_Œˆ!»“Ya¯o̯yJxœÀ]…Ž¿]b¼Ë]y6PEÙYdM/·”¤ò7¢~…ÐøÓ(?Ò“} ¡ª“êÕž5§Îì— š–Š<¨ôü;Ímz¹[ò$pz—p?—ürë&®=HŸÃ›Hhkòî¥P[&Glô¼Â\ù¿mûoûhßÚ™ïÚûhíût ö½~Ý¥‡ÃdøjnÃóêª!òt·ÉÑ)Þ…Ð/Cƒ»—ÃÑ7Úéü7>ûzÍü0‹´v¿·fçÕ´ŸÃh}}Uwíß­ûuú©?_S¯í¾÷íÚ¿Úíûw·öê‡íµ¯ª…¾§OÛ_~Ý1ý»KϪƾݞï¶ßŸS·>§kí¬ûíÓïàË>ªƒølGðÑ)õ7O©søX?ÃcÿB…ó¾×¿á ;öضŒ÷í¥?m}ÿ…ÿÅöìT|ôÐÝöêÖ¾¥©óô³/Ÿ¨ªÉËçµß>”ãçÔÚûv[öõ>M»>F7Ï@ýZÙ}»Aü5Ïßµ[öì6ý»EûtŸß¶Þýº]¿nÕþÔoÛ´Ÿ·Q¿n›þÛÏöÛŸ·Aÿ7E?n»óêVþ3¿n´þÛû~Ý ýºSßn¦_jú–?†¢þݾª3ö»~ÚËøi×ðgñÿÇð¹÷í¡j¿jçí¢ÿpº¿ƒwðÖ|ŽÂ"ÿpÓîûV¡òmŒ/‡¬ï‡_Ðv¾·Ã伯á®wÛÒ?äÙQmÁ׿n¨O«^ÿCT¾ûU/·Fwí¿¿k·¿kí¬ûíÒ¯à}ü5Þûl¿ÛO~×/Ú©ûií§?†¤óêR¾Ýß¶Éý¬½ö³ßmCßm“ü/µoø^ÿ[[~ÔûíFþ ßÂãþ €õŸ*ð"Î>^²ý—À~6%$r”$ƒêŽm¨=xISugÀú…9»”õe¹þø„÷G™s‘-þ襳¨X}¬…SK÷ʹ7@iCw[B§MTí ?={Ë1f¿e¢Š†Í IÇ×6iBzˆÇe…ÕåÕÇÒs-ljõ"èh~§aïÆ[‰ÕñôÁ˜Pbx¶×E“O?zï»üÖvúJ ¡JDâ8W#D¡ü¾çõ¢D5 /Ž´‰Œrú¹¹)cR>Éð %¶úë²Aᬆ¢%±Î˜'É_-^.X#/è,Êã @Qó4j„^ºD_aVv·ºÄëŽ{r‡ì#m¸Éϵ9–@+¬¸QŒl§¾X5ú‡&ßž˜¨›u ¦ÿw|Ó\åC])GĈ0üu Ì~· ö©ÚÕg63g£Å}s¾:5¿Ö&þÉù2ÿxŠã±g>¸ð—\*(A‘odÞq!”5¯`2D8š¤ƒläÂÞ`×^•bçè¿Ö¡CC8 à«$ŠUï$æ{¶BË0FI¥ñ:‰¸Wû+Ž3-ŒØ‡1¯x×õæ~K>Ën•?‹ ݯHÙ§íËP–’ò¤ï TŸ£@ÇWG™>؆QMu.ò*º9•dÉ·ÁÒ®,‰>b…¼k„ Ý™dcÒ`°N“¬žB# ‹Mo06L‡äq½å ¤5y ™HR™ïÁñü¥_í"©D†Ã!üY\û¾†ÊÂìÉïIlÐpH±{ìI‘|›møÃû¸¾˜AÚÑÄ×­[ ^ÿåOÑWù›L\¡È&ï=‡EÑöž%QYè ¦°8ƒpV×΂¹ºY‚À­dA™éÒE’­½òŽ ×¥¤Ý ±lÐzC|Ë»úQIèñûÍÞçòŒ÷9`rÇq]Òø:¢èQ²“\Fª«\':#…«rUÙZLŒ'Â@£þ}s`Qys”¬¢U¦ i*óõÏذ/ÐM¸ÕÁÈÓ¾„®Ò–³°\˜ûµˆ'‚óG.“GQ—óò޳?þ§îŽ1»`'ÇrI? [>I´“]{˜é?ì:]6M[Ÿ½.½:D"h¥Pe¶gt›†×ÿUÙ@?ØéùªL„))šw z² ¼‡Ê•íÔŒV³ßâÆŸ’"|~¯£øNí¥G¤ô‹Ýì)2Î7Ú5í^¡Ó''‚[q(ßž8waCÑY 65Ü’Þ§<ÛÈ@FÁ>õëÝ[Wµ*:‘1Z€mäXƒÀýf9Ô÷ ceF%ò÷ˆ¨ˆ<°V9TC Ätݺä®ðef òµ¿ÂÀRG¡-È ¦"? ¾O:ò$¤ ÙXóà}`’ªâľŠf—ÞÂk6%ªñ<«Íúi?Í’‚‘TË‘P¡ò@¿ôª&ªBº½`9@œñ½3¤¼1¥¡ŒQN+ĽߖM±—ÿE;ŸkÐÓkÁYÿ`új+Æ#Ò¿ÃF”§ƒ0YÔ›iN^<}€m0Èñ–¤ÆÏoÄ`ŒJ49z È’%øsäaÀ³³9 08.…{7^Ûi³¨QïÙé¿Á—>äF<ªÁ.XÙ÷½6·ffð'ÆP­g €I‹ þŸ*ÿ÷’ĶÓ’Sêˆ~½Bs:r™¬øÁPü).^¡y›Iª¡Øçr;͆"0ÒVx{üÚ‘W£Ht½x3k™xºm"[{oÈo§|­é)­ FCOô€ºlî óú3 ”õ7²5•Ü|y}?ÀÂ"A'Õ•îK[ßD€f™Ï {­M˳V_»£S# Âq]θáá§ ­R åPAÇËjÿE®ý2®À"]‚v9*ÍKg+~Æ?ݪør D{R6sOð%R)ˆãÑ×e î ß2Ñ ¹%nYn4˜K} ¦=TgÞtgÚÏüˆrÎMY6õ`AŒþSëM}Õ2ŸææL0à9ª+Í4Z™>Ë ;ÄF§®=>ÜÁœú£ o*ø˜,tþ°4—¾û—YL´O6CÏŸµlž, ëƃŒuDöɾꞲæjæ,|M.?ZÇ1:„Š#,†„{$Y±ûÒ öíIÐä$Ä%¶t÷ƒ›¾Ro“"l©Ä½Ý¸ž/6iˆ%L1z~ÄÓ@AP­÷üYýä¶|¬J•Ù>öR¨D•¡YŤéóÒ; &œ Íÿ×ì_DYŽ%ëzþ»ÿª¦èyùgl§š çÏ[…à Ä}Pb¹¢¿  äh«ì¼$êé@‡~n®‰\%µ¸¨Xr8;Õ³h®Þp|Â')¬Æ—xŲNÒî2YrVphP.Ö!FöÏH…}{Â}“ÉÿSŸ¿°ýsk@þÕ@DäXÜœ¿—¢ÆÓáÆ•ÓQ°Óº;½üƒ$H=æ¾ç| aÜw´¨±yß|ç$Ò£ºkp&Ôt±O9áR™ûeq;ÝÆOÁÖ¯ßëê¶ðrð<$(PÚ«Á*Úw$èà.Z^b–IóµIˆdsëu:93R5<õU§|¤?ë<”µ­›óØ $9v?.·ÇÐi¯[‰/XO8+Û!#ÞìùAÈ·‘1I~Ë]Q•w*Kh…ý#Z S¹Ä(ïQ‰™…Œh[‹htÅþ«WBÙeº^ù]|ï³M\XŽvŒ÷Ù9Ï*6²üÀPë`Æf4 Ì.‚¼\{h±Åpø_¦µ·ù3àšd¨ÏžD6ß ƒv›‰‚OAËÔЇ ,\Sç ”øó…EŽjnåÖ%ri‹ÓŒ±‘™ƒ½8Ê7PqŒ›Sé+Žò?Ä 8¢Ž´°Å#ÝbL‰øþ@ß…†éf²¬Q˜Tð…¯ÿ{&kÿÿÿ¯5iÀ±šiAYãv;ÝÎL|/‘…ˆN[øE.|Õ@á>¯Ù"˜Œާÿÿÿì³³g‹°9Yp™¿ô*v¤½>¾óU˜RÙádŠ~þ¹ÌL–É«ýÁ¶1cÈq#iþ?9à÷4Å-½#¸©Æ2Âú# oˆ:°Î'Ç)ã§ø¿‘@ï‡lÇ¡Ón lbA byí´eÇQ»ã4ÎÞtó»éBDöh9}L9ù1eBUuD]†SáÐR}¦òošÒ8¦B•³ã¢Igð†kj²¢Ã(µy‚9¢"=¶]¥¦[4ô¸Õç^â”#„Ež©A…ÉßÓ£»t~_†- …²¼Õé}`_Cǘä\ßv\âøIÔ¶ÆÌ‡KjHž¾¸'Œ‘ý‚Bëfsò)¹µ›‚'Hÿÿÿdº&ï¬ !ˆp¯èÒµbŠø&_ëCõ‡Õ.@5®\û‚çí·òà?æÓQ'éVØ £æ_ö=àbñO9ßpPÄÜBúR¸pó˜[`=óö„Dž¼‡põ¶¾…ì^ÿAJ܈-FìÑÎPЧ\º!ÿ|9ÍPT”MyóùöL-¸#BÖ¨Óÿä;í²ûŽ­-qA¥ÊÔªbŸ†ÿp™@\Ó®D¿ÿ=!©Í'료N©llõÿ~~wðŸRVWŠ!&±ÔOÿëͧÞ“…¡>´€ÓÊ©¶‹ÿÿ{+kòÏp2;’q/¼ú¦½©uº¡zÙr5JwjÁQå º^2¼$¬¯Ï àbýh¿@ãhÄÕ‘ÕQ´j4¦ÆçÂFã²YâåÑ41[°RáËKv¿&>±“3úµÛYÿVŸGþò—þè_åÃ>ð$Öç«"j8—óÖó*'eÓÝS‚|i)WM‘Xdá¥É¯œðƒQP\áÈ“´&Šg‚Ìé„å-пÿÿÿÙF³ öV¿ùßµÓ°ù÷…(Ì—¨0*»6ðÓÔ %"òýë‡ Ãt·k`ÜzÇöÖ_žê³–OšåÆRb)‰ê)6 %ÆÞô6Á‰XýHWÝ/ã´£Ö JegázÝ yQäx%/ÿÿÿÿ¬œ¹ÅØWéáv -ïúàÃ}öÄwÓ½Ay’J£&æÂõúà$EÔbž‡9ÂÃÈ"áE.5m::ô(³¡,–”žÿ {ÞÓßw¢+·Äª«=ʘqÿFÚÑ^Ûÿÿÿz¤AŽº™þ€e›MÆÜ"q!fCœ2?ILû4,Q›ÿœ>1Oî{3€ý€ò†p(Ø=‘‚-éä” ÜûGÒ}¶Ã±ò%çÚ‰ü$×” Ÿç¨C†As3a%ârä ÕJ8Iiô !»øÉÈÄBMJ 8ÿ}º^逎Óþ楉 ›3wWæ¶À ´Çª?ÿÿцŽÀ¾V¹hNqR1G†yI߯1ŒdÆ1‹WiüôYyÿ¶:­´0,¶uq䶪۾-e“D.‘x;„Qqh8ªBøÂu ¬;jbÆ–léMu€B¹Ïöä—¸îýD·Ïé4%ô—!¡c’˜:§¢ßÕÝa`õÉiÎJKTLO¢l¨ñÜÚõwµ²€ÃÔW‹2Ë?¹  ‚]ÞÝ ešã1ÙåU‡Þ-0Ø xÙb_CÓÞê ›zõ1pøiωR]ÛN¡x!ãƒjª¯+= ¬Ç׌= Ä’KÕ+åüMÙª4û® ÿ'Æml©Hÿ}Jß[ÉŠ±µ\Ùª‹T« »è±oé(Ò=YmÐPøÄŸýL;Z”ï’YBdp¸Ì#QæF¸löÛ'–PßÙƒæ !FîDܽ/ÛB5/¸Z· +dùbï€Áëeb ‡®Ø*Æåú…·›®7fÔ&áØ^´Û/ 2p¯£7rЉã…Hö²aý¶~cí‘HøªÄØú íš„Ò<è´¼}ùK‡t”Ì7]FÑ·vþ»>(r²QFrì€Õ>0’)übz܈3©’´‰Ïçjc ä¡à±h¹œ…ŸÉÁ ·~nªëø ZÓdù« JÀ—´æ†æ{î$¥ÿsKè!Åú(ÙŸ4ö±6)!sÝØ WÓ'Iú2µU»ÐDTp¸ö¤ÏO²µôq[‰µqj—&0W2”eÛ}Éþ~ªd/È>²Ly{fòÌÔÏ&°ºJîæ‰gÙ쌯Ѱ@GN÷¬’ØæØªþ4bNnÊyLt·—!«µ(al1r4p×XÔªÄÚãS³D€­:E•¤!nÇ÷xu\UÕ0¼ï0ÍlNhÙUNÉd´Td>ßW'CËØz"4úÉîG]'j‰È?–øXŸó¯þXø&?ÿL†Ö¿ÄÐà°lnØÿÎ|ìbØÀ¨RáûòLæÝM?ÿɬ°Uz ¦UuOÜ~åTúÕ¸ÿÿð;…€ÎtìׄuêDA®?Âk›]-žXÀ0¯ÿë>­`×Òœ‹_ PôCô²¹¹2²-sZ•¥%êÏË+O'8Ô5Nù‘zëêeoÿ~fÛ‰j^5^´jˆæñ¬ñ•d={t!Ûõ+º%™f8ñÿô`Ô…Ç%ÓÜÔ {>äw^•4´]›ßÄÐe(bë¤HN2¦XêòžS` FÚýíÍ6”Ã¥ÔªžãÞÓ™¢ŒØIéLàä"³ê¥¥g¹ó¹mW˜Õv 91ˆ¤“‘„7 âZÚ´ÉÉ0YŽ^Jí|HŸè⓼A·í½l\â.ÈJ>Ür£o2T¡g…þê‰Y§ÛT$‰ÿKÍYÕëLÔü.Êà½" ˜•rÕÖTZ Ú>e¿Ú›ö1'Äçï*|‡‹€9POq—å3 SQ¿ `’d/‰:äà”`µx1»{F× #íÉIÈÐÙ›Óú[H×╃•æîgÆmû(ä†H>è~Ëþ­Áð–¾wR ÇC=xø¼ñ[ßÍŸã¥å„:®šª*E¿®=°¸ÚsÆPðUü6”lV~2–$LBOê;Y‘Vz3Ý‚/nñʹ£FÃoÝ/g4'iPÊ3–|Œã°Ól€­ýaÿÿæE0>³OËAKePe VúIB©†;§[8xk—Â…¿ë"ì¸ЏÂ0ô#Ï ‚†ö½EŽð’š«^T¥b^òLÌ*…âóùP_ÏÍNô#Í­”#ÕP—ާ¯0p‰ÇŽ×ãÛ‘)þW‘òèÐ¥0ðw- N÷ì‹ ù%òÃTH£†etꞣx ›!–(.F‡§Ö<ŒÖkœ‹­° ÙóÖÒDð¸k#°Á•«õU¤ðYɲ}WÑRìŸm>ZŽc#Ù $.lÞòÀpR<ÇJ~Õü·g`v—gçcˆ­¯»Íl¨Ö–Ç™—YÊ c(?9 «¶¤ß§}üÁ’tç(1çoÆÁŸz››ýÌŽl¾RFQ¨ô¿ò˜(ñ”ÜÀóô<_Rl,þ¾%(ÀéÇŒX”QªGfÝ9þÂÒ xöÉ; ¾¤Òq!ôm“®¢q{:©š0w– жv»–´á¸ôÈî†s΀Rj*u’…ªH²ÓÎFÿ5ÅìçÇðDô™âDØ#²€`†²–ÑЀíræûk?Ê–éY88ΪLÎ~`M}‘ï?âvd.’Dm‘ÊþP€SlÉÔ– §LÞ·?! ¶ÐÌl>ä‡ÿ,š'ÓuBtW•9¤'‰FŠQ>ŒwÖ³Öä„Ñ ^Åíþ:D ±‰`î¨Î„c’Ew©b  ÿ:5¼T5Aà+©ëöœVøöÍ9j›Ñ(Ïœ%qdYÜÊxÊk…ŽS鸇çÃÚ€þ>Ú$}¸5·Ír!xÿk!ÕSqp}‚ykj?¯ôqU³’"ñhTîÂg4A§¥µ“àVÀ{ߊá\Ê ?ÔþUß’bçísèت•Nœ^Û$Y¯ú»—}Ñg³gz°yÃk]%+(¶/VýŒÝþ¶G1“”ä«À¼gF÷Ì LÈ׈‚sF–]$~j‹[«›~o"›œn=šo‰ü .œ˜©ò¬4Df:ðÙ[9ÇœV×wFycŠ+ÿcá AœŒ!u`Š˜#,]”Ê6 3¨u˜Î(L3ÃÃL¶ãõv‘Ô-ó—~éí€TUy1ÆÝž5,$*¦ÌaA•\…_Lùø®Ÿ_¦µ·øï­iXw™…°¬Þ~¬o™²i3œÒåü¦+„ì ÃTñ© ¨¬ÿwÿoA¼Ô‰G÷ZÎZµdműãÉûëO¥õÒ¹1¶&ågY·Q†ü¹‹N09þÞu‰SîmçÐi;ÙÛOfJ‚¿rÛ˜m£›”}¿ÿÿÿ×c». )ïtÑ›f…°¾(Cž«ÌZ¹è_øá©¿ÕWÉØô iÆó›GÕu×N/ÿÿþ ßã[·Äh…¡É9qêp0"æ˜jläÿ¥N&´RQœ™UÜ è&ÈŸ||ðÎÊ;"6!ïXNô&)úÃÉ ¢Pg¤}”ãšÎȆŠË±,acL{­“lM­¡¤ìzTÍz>Ÿÿìçýw’_Lú¨²´_TFU –/]"”!nhª)“ü˜m[Ê:<¤,,@x;±§²oè(ެÁ¾å=¶ŸÆê¿ïcOrÿf êžA¼ÔÈÊ[蔽mƾËâù~•*’î.á­ñƒýY^Ì^£ð·³QAX© oŒ,R¼âlÈÝÛQ©ª†ÀI1£Í\vbD³ƒð»ÿ ÆWñÉizà¿ü_y6ŒŸ¯åÑøZa ¨Âº‹Ð-m®W–‰ Í³àæ»&'¸Ÿlƒ>Özdú¶Þ‘Áx.²®¶ Õ¥H°ÿg&uY™Dt¢Í>ÄMᾜO‚«>ójõš]+|P°®ÀGì˜U’GmŸñÕ5)¯59Ù tmµ :M|ÖRp¡ 3²Â™¤ü<Õ²¿äâ.Mˆ.â?õ¦ç*àãÀ1|´Lñb2`ñÿ x+‰Ta1Íõç½~wÒÛ-» ¢Ÿâ„Üš,/®¾ ^‡W‹u ¼›-<,©r#ð5y ZÓ¡ñÇCÍÌ#aGÀ /†í ݶìLdÕyá·Øö¸hׯ9•NÎàæ¥ ˜¦$ü#zO„vé€\ý¯ÐQ‚B¿‘ŸxM+ï>‚Y*ý5Þ;Á¡ ³|‘BüЫ˜´{ä½€Ô‚Oþÿ®Uv3|ßP@/Õ>OG–É„Ø?øÊb°Ïñ3ø6úKS”¿ÛF5 Ãož{héµ÷uvTùýáÄÿN)í%Â!`ºèeåúÖ^e³ümÚ­[¹Š0$2ÜèØtxùªúïͧ¯ON*Ü5*@(e`ìýè³U/¢ÇÙ<'Tø¨Ž=¹H§—l'ÇÂÍ9SÖS‡ŒËDj=¤èA`Âëòó*‰‘|ñ·A`F‹rÅkF1h+b*¥6L5dùФÂc°ˆT¯þ':® ÷6ÍU)·9È/Gpj5èÿÿ 4H,´ùµbõÌÐØöÒC‡¹Nw$ìîŽC›‰hø B¯æTÑA“&¯,âš«'4ˆãÖÈï›J‡£Àÿ%’þ@—øŽ4áYÉØ'4>‚)¹³‰ai¬b‰“D±ð7”Ü +QDa¯hŒƒ{Ù‚…bPÀß²wÊc »vP%[¤@ÙÉ8óà€ÿÿ8@ =tA AIö#óV=Aã¹°BŒØ§ŒŠJ3Sù{f F¦¡ó\|óÔ0Û=ÐíF½)©m¼º°ç£kT—š=ÂÎD0'ìZŽmjöÒÒP­„­Ën‰Q÷Éä3¡ X˴ιhRÿYBF² ÿÕ$±ÄÖÿÿÿÐ;4ì=˜ÉÌwUˆ¤¡DÄF*˯©S¤©R­®x£G¹¢Zö%3òNkô!šÒú©m’±¥nAݱµQZ)E·ï¡!)ˆû?TI0qKöJ ÁÛþq¤=ÜÔßa:sCÐyÛóá?B7‹ÄmW~àd4¶µQð¼<ÿæ  bAòžŽ\˜4±$Ù’ÖYÞo€n_PPqQ€Øl6.¬©âG»‡¢k6æ§t”Ô·Ž;¨ºáXN4ÈKOÒ¥ûž’8Ì0î»Ð?¢Ó炇3¿ÄŸ†‚"ïË"üµ`<î:œ¬ùŸyÿÿÿ} ÷ú –[ÍiiYñÛ>Ž¿¼ iÃ0Ÿn×:ÂKmfÕC&Ëu…PŸéô¤U°È¶å¬[¥`q2Àïà$C·¸õýÛq؆VgˆYWî²Íq\€tˆ6êð¥Î¢r• Âè¹*½ùüÆšb[PààT•×&ÿ`àá] XäQ/-ë )ï)f- ‹Þ𠩬a—?ë@ÕÔãĺûÉ_ܽ²{»g h©ÿê(€Ðqùí@OÚôŇ_”Œ/ƒILÜoˆzÜo"àŠö2èHÐÔ?¯a%eFÀGñxFOàtågŒ¿^ʃ3.cÏÿ .",ï×^ZŒï½²¼Ý UXHä°Ç—ÙÞ§É9`›E»7­áƒÌ6¤.â"•E îÏàe3ßsï“9Š?¢¬ ¶I~€îïñZŽË{aPÿ48tA \—Vd"ò¥zg^6ö’,!CäpäÉÚM-jLE=µÂÿ[)wrƒ·¹~¼×#Þtz»§µwÛ6\b©Ôú˜Ú«PD5ñ…Ö[¬·VžyUœ:¾TøÂéåH¿œ+Î7-QÊNöÀçœ>1OíTÁ Ë_{>Y…`¢ÎôKÖ%Z%ÂfZ‹H@W¥}µœQo;wxú0`pAN™ó¶˜¡ÜŠƒË¡µS­{Ÿ'Æ•¶¼ÛÖ/q¿ÐúH0œÜ×+¹#ó*¤-=€™+&á÷šoJµÁ/‡ÿÿé¸5×1í®ü)=Rõ’a56ÉïžÇç•±ê¶ Úºçþk•D~ÒÙúef{ˆw¬Á“ä zÿ~mÇ%$,™ô!®g?«–#Gs.ƒ8s*±h9"œÎŸ#t­vZb8]IÅÐ[ªýp*:¨®õ§‡QW;#¸‰ÎK2ZQa³’Bïg­pä õ.D$~GÛ¡àSs:ššvJÚÂ1ÄX…M4°å|wä?°Êá1Ÿãx÷š2#“¬/H&a¿²ÈËLD `ùÍIDBjŒÑ‘·x¯¡Jº\ˆ“ }Fy4R9‡R¨]ÐiÀ›D8åô(‡ü¶~)^%ŸÜÑÛ|¬-J”öfôÒqµ·lâ:mh˜¼‘ý-H@Áïõ·¨g›Éâ}¿æW†›ò<ã… "™Ò*›¯¬É½+²ÊDƒç²aY°–Æ5^4d5¦WTòÝG*²Rˆj!AdG® ±Ç™¬}®Û”yI^ úô@ã;Ïa¾d?Å iÿyúÃ&Ä¹É YJ¯ý$Ùé¼ûB0¯ãÖª+sÙãä*bÔ9´@úÂìj%I“êPñhØz#AE!LWƒ–¤B6ì{Çwø IWÿB´öº²m ½&Vˆ²È& îè¿b·vÒzJÝÚ ïX›Mú@Ý›•ÙtèJ@ ¾ÙÝ$H$ xGó¯»ýƒø -¥³OÃ=k*CëÀ ,¢Xã²Æ£&IÁCÿ{Àâ±*ÑAJ²ÀE3úÎV”Šù`èò±Ñ5õÃG7Ù‘Êà1þÒoúÎÇêñ:Š´º-{F q‡†Œ9;í%ÿà±"'2¦wðˆosËNyƒoÆ“ÛmÐ èê¼lG‡jaÎWr¸óªC0‚ ºfdÏŠÌ@w—t5#¸$Ú-Â+æ=Æ@_ݩݲ…•Þ»»žù(¦a‹~QÛ ÅNÙ)gG– Ûdºc¯×LW 2}MÕ ¯ËçàÝù)àÈ/C£Ê°ñ²O“°IØd%£“˜#iÏ­ÀÆikø¥o],²%¦­ð¿Ëg`~#òYi°9k,_ıý-&4㈠À:u»¹žp¢CDi!¢4Ñ »’öB?ü…"þ lPÍó¶LSC…F$ßÖ3ä^~UUT¬J0ÒY0A¯lÓrx²ßz‚îxÈÀX _h3¨ÄÖÖtÍÖûL¹˜‘àr¡’,Ђ…m4 *X»èX&! T Âiï@âã{õ€ôŠUÇÙ·.}šëŹ҇ÕHΖV˜å˜ù—ŒyŽaíµÄý…X-þKØÑ(4-YõÝò(Ù'D9u…2 {ÿ’¶Ñ‘ ŸüÒ¨jl\6•+ˆ.@i;ÞHªKM«tÇ5©²jèБ:M|0¤IL\$—»&V i?¼`6@Dp½*}ã‹4æKmÿzS£zÙ}ÊÛLïzlwN ÆUn‘ä47´Y•¦Þ"Ð÷#.GÁN§™Yä.‘1B/áÛ¥ L N²¥ƒ¬îÅaßZ9Ì•@á°#Û“|øázV¢+4| N4‚_A°.IøÖ£ðCGÿÿ~,Œ6šYå ŠÒŠCÙêX»8å  †ÿCgL2å³oñeœLsÿówU«\p“7p~ça~.m,=C“³‘ˆ¥IM]»ÎzV÷TÈ-|¼IÃûß݆ŒaJhÂB. @0(´»{Ôüä#Ý>ݰZÄ«”t Õ©A–gØú‰˜¤ô†.ŸxQ½¤{,;†®~vÁؘ!Îñ\ ÔÆŠX,¥K«õ.YfaïYHfŽœ¶]Eååæ+“—9·&9ý‘P¿Œ…´ëËlý•çØR‘py™6¾ ý á®;Ù6VUW_ëâ[å ö¸M³ ‰F»ùcbî°’6ƒ€a=Y^˜çÎJ,Ë[x} sÎÄ7 ër³lÒÓ*™’PI ”JqÏuýY ~«ŠâŽ™¡¯þ5¦Šfež…K/–Vº4ãµM<ÿ=Ò+ÚCy¥HZ$ÎO‘n–Ae1!¹^LX®l¢¨ŸèrM¢ãÊ tâP/yDÎ#ЀÁ[Ãr6TÝþâä§DE¦2^ײÃFl¤úâÄYÛ½æUˆr–ný+9\yÊãÎWrļ±n&NB/éJƒÀ‡ I­ŒY gS Þ(L´¨8;˜$ØenÎ|HˆZ‚L,(5©Û¥1dÈSŠ¡”y0cu–ë-Ö[¬·Yn€ Åo‰„u®åwé`y)WÑ«#öeÐ[ÆCa¤…¢+»hÿ*]+追‡¾dŠ›×°«®üBÙèS°ÇÈvŽÊ¤Ü¬ŸB);+Êl±hn×t§×ˆÕ ­v>WWîDj¾mÔÏæû<Ì€MHc4Þ@½Ï‡ŸÏÓµpÙ¡yîë÷¾ð_’Å·¸Qúï¨Gz¯ê0L¥3ÀJÍjƒß·øO°GSÕ?¢Ä†J+\†zàðѾ¨@ùH4¯$[^¶}x°øI…<6 G$Û²íIèM© Á‚À5&Àm£Å…oÄtåeù=ÞÏXÄVFqu5LzÁ¢çí2°1|£ñ]˜ä˜J·û|Ÿ;õ* oÀoµYm;ݯG@SVµˆ¡>TˈCUĬðåìîG†x8©LÃ5_°_˜ë߇CîŒMä̼ÝÒ“óur¨Ô&®àu<¼¨Ð¿J ÝIÔ$ÜoÚ~„×¢xˆ\èâÄufyÓLpÓè4JÖþMYøVgvè$‰1–w«ß 0o]ÛÐ GŒ¿ýs6ý>ö_¥œûI»£ô j»„ELq_¦µ¶‘¯ oñ!¤Ó ΑÝè¥ø˜1TY/6§ñpAýì4h FÓë"Ë›ÿ}¤")ð¬~®`-I3S1Ò¸ìŒÀ¿ d@Ã÷×;ádŠ€³ÅwèÒ0Úg±ûŒÁŠ‘y{æ§#ü7½pãŠçþj1ù{"’aíò9{×É«SôÔÓ?åÇ£·=ø|ÖWøj5AjqÊ„R>€­ F—läµ ̈áè³:”ûu6÷‡ÎŸŶ¢†˜ƒÿÿÿÿª?±°uSÅ5Mê&à_ÁœSCê ¸3…<¬FÙ TÌ•‡¾yxjã†/>¿°õ>4ég’Ô]¼ • r tTø€F±ç,×\?ÿA¸±ñ‡ÿN‰\hïWÀ=\AëZoC¿ñ£¶‘sÙ3‘ÕÈðâ L/òçW¹›îÒrú²ø¤JÉR@«¿w Ëéöµ ©zæ¾”¨éÀÔ–\óTNËë÷ýüú}—«]jÃ;òèÓœ-ñê{ó«œl²)/«/ŠIÔ¬•$û8&´“bŒÑóQbcN넦° ðçºægÿ]bð`z|À,.L"ì¹ Oí¼G¡/zÛÙ«<öIË—ß~ïX€d‚-É{ò´Å0‘cC]6ð<¦””‘´dj;]i„ÆØ2I‰'wTœS;Ó¡C™iQÿO½4© —°Ý„²íg)A÷Ÿç$ ü—ùÜì~è™óBˆ˜ü±;‡äÿ]ïLsÞcár ËVºKÈc„<3Þ=â‚•h(²¹«¹~X ÜØôé‹`kók4ذƌÊáí"Íœ‹eh3˜ :‰PÝ_>9ÈL¼ú‘>8¡ÎúæÃ_eM%™þ Òšµxû:B,haGpÞâV¦ŒÏlêo^McÅ_ÃûzÒL"²ÕNÀ–æ½Q„™Å4îaOÁðå—¦ÒÚSm‚2ã&w© 3t>%‡7w%OwÚ?† KäPÎ?=ãÍ]Q>ÇõYQ¬„ „Œ]8H‘ËJ¤06ùÒš!;Yàw• —”|ÒÄqü‚B{?Zoa¨úi­œô¯{qvHªFo*?öÕç'Ï“ÁÝOr³$¿*á'kP{*·„¦%ê=Æá’zˆ‡«ËÆêG%éºí¹#ªÒó[m˜}g”~ŸÀ(8r þy0âúöv™Zß|çÈTYr‹ºò#r”ƒËb"ÂöÇ­æŽ]*-ôfѼjå¨ÿí>|›|?+òø>RìOÚo5A 9•Ì*ÿv¥C‘ˆ´ÀÀÀÀ\5UñR©±gÃÃùunÙšÀÖÁØ:üöŸ’àFTBUfè¦6g1~®ÔdAbD8Ù:ýÇžx´ ìÖaª‰¨þßâWÇ8Ùä}fÿ­G­žŠÄ ¥w7œ,"!º›~wIjR8 ŒmÙF6ì£vQ»(ÆÝ”c„Ä)#ä4Ö¿ÿY)×üF2å0(ëì ð”ë²Qk”†"Ýl%< NÅ©“LVÁ¤ 7 “'Þ ?Î'¸:çí œ»B¹Ö^gÉdýÓwz4¿sîaèãúQ²F  ;¸Uu¥Kà'ÀZøÂ Y÷öqTÔZ×X«J(J1f®õýÞR}&Û¤$Vs"µ©QAÈ oä=XÅÄkŒØë ˆÙÈó\tEɧ„K ‹³·’Û=)ô1™ö‰Ó<¨ðv(ñ™È«àDÁãœ~  ¬8ÐÐ3$\jaŸ…¶¢R!AÇofÜýj;èpOÏóÿ^Ü?öî:é=ÓC.'aT€Rj:æ¶ ~À00§€)H/ê:Bµ…h §µJJe&c¿‡Ê^Jþ“./ `vɤq4úéûáš:!à8ÕÜ!þ¬‰_“'?p¡dƒµÄ®ô²ù K1cf*/ÛK7GÁ®®­÷×{¦†Ÿ»|* ·c T©lå _=¡¡€žX‚„Ò…óÿ–!¸) 4.ºj‡+¬õ)O°L‰ ‰PÐ W­qûtÓAÕå2-l_}Dá’–ˆ d2ý«ò•¨Tû©ƒ¦&dqê°Q–¨˜ª†p‰ÖÃù{zâéäÛ5¶èã†èôåBöNüËí1Ü2§yοņW#SÑŠI×h`íéï5ÕzõæƒM˧øï8s«+¯¢zJáóË“ú Fê:G+×N0óIÉvÒžyÏgÍÑ[`h×6(éO4iíß²Ðw~ŒÙ»'(^ gåPø¿A[šÏÃý²ŒÍŠÌ“ùŠíLå¤Óç>ˆä<’¶× 0[g¶ûD˜ÙŸOzÓO•âµÉãÛªrÓ †7cþ/°ß*d{ù´n…”ü¿âø‰U’¦¿ßÀŸì»<=€_i†É(å™pJ+úÝQ“2kDG˜ñ¹BÉ_}í~è½KC™äuŒwmjŠD)"ÒUs¨q»ÎêF §_«è$·L®g{‰ÅlM¹í÷i±êá†ÎƘî—ÔUJÂôËÙS#e ›}ªÀ*JlcyVšnŠH¦Î‹–{ø.¶†1ùáWa‹k«b2oºªÝ¾1„²%Î"–p<Ó4÷Y»(‚1بկYµŠ£YûT¨Ø¬†×3@7xIV¤üóaÃAvyIØÏ‹Úàs¨7c¹§÷Ú鹹ǕbQIb)ÁÛëåTØÎL”ãû@Å£Ô½Åø6>S0Ç,ûθË%Eî5É ò\ uÀÚÀȦ`‚vˆM€aT^¤E€´Å om‡³º•äOî¶L÷÷ÞÂpª÷Üw (>,žø½õBÒ^¡ÝñÏñˆ‹Ð‘!´^¾þ›K“l‚Ü9!u8g¾Êæ}]Àcè÷yfmÁ³û7ÁÈ"›8îÍ%‰¦šæãT_. ¹JÚmï±6 m6ð䉓F$ ò“‘ÇYô)ÿ>ÌÎu—ùpHä7ýŠT Éa\s^é©èp!WM£ž;ÿ:œº©õ]Ÿb–þ=÷ tRŸpsÀ@Kß’R¸ë³ªçܤ ·¥Ì¨°G^ÄËŸ¼ i{hÐIš8ߦx[:l¯O™sɸDåm±[c›<OÊ8þ™ÆðX‡b3¬ · Þ&–O5=rÂTV äû5Æ­C“W·È{¯–¯š™¸K…¾¬ý“\£‘ÆæpxJâ4è†ë<~å,ÿÿ{ ìÓ0õ¦GŒðÞg³ p#?õM çÀ1²šÓøµ†£V ËR¼œì’ä6rU®²ûìéè꡹ͳwËl.À °0sÃz8Ï‚ÅÊh]i×ðt4ÿÿÿF UÐßo×Ará‚W‰XaÜKþórðv V;v[ŠNVnØsÀ˜–;è AõaÑ[Tªy‡`´ÂnVuU `v´’$…s›ª‰ë¸@I0HU¢×J'Ÿwˆ<çÓ…í·¶ywH+ò±$3…L|M¢4êøêëR‹ƒæ³Lx¼B®¢ü”a…{GýõñX- iî!S)#^§ù£µAöÆšÕÀëæù¾o·bnÂÐk\³ã®Í²³$cjëqñÇêÁΟ% `ÿÿzDTœPŽSð§€=Öuu1¨‘5À¤ämÌ©V~J8¢Œ§ {5¸ì`’å~VTÈloèç«ÁkþBX¸÷Eù/Ç1ÃwìÚ´Ð`qØ<àüdþå¾{MA†ÎlñÚÞ(>'5GEoª¿"ÍàÚrÉ{§k¢-)Öʦñx˼.ò€÷ƒˆmÌ‹ð<Ÿêãj»Ád²Ž¾Œ û%9 ™%³Mú“7¯ãc7Ua§Bí¶+Zy5KŽëtñ‚ƒ¢œ4WðåV7Ïl]bèÓ`IiZé%ÙZK—mÆ|‰ÍÏ5Ñ‘ÈaB¾l»‹ÈU®¿ìwè3µƒ†‰8£˜lè¤Ì-ohl,©¢¶6þ•Çœ²4ÎkS cOPïªhlÑ‹X^ÂÌÄrÜ-…J2žY¶‚»‹.í9'øócæd7•ƒQÄ„˜ØNûn Û‰ïkž>`-˜ÑWï•uHƒ€Î÷v°â³¶¤ð¥ÜfªâÅxãKQ=i¯YfrÂ?:¦ÇºM¯î~ïÓô¯øöûœZŰÁQ-JWZ@ÆK,\‰éaõ6X¡ýØ!ÕAŠy|»¤"Ü(G98kпÈ,FY"Ki¢:ŒÅ S¬êƒÆeO0k>K[†”&~-”I*§«Æ*g6áòi Pç žAÍš ²®Æè ¬%²)ŠP}6ŸõÛàO¿õšÝ7…|~·*Û¾«ã1ðá§²4KBóð=w§ŽwI½¡ÓT€ÈÖý»Å;ÔzÄ"xS-(GýÙË‹Š5˜&A‰’6m²¬_%5ðª®MvyxO6 äy?m¾ï©˜CÔØÒ<ÉžÁê an@ÔHe2ÜëqÿNˆÎñ€ L!(Z›  ûÍ:UïßS5.G½çÁè§uïs'zHº¼Å|³9â?æ,±ô.ãBÓ,µyUEü¬&ÆÝ9Y+$'A^¥—Àd£AxäþrOl¹„TCÔ©JµeÜ`±úåé[™·›®ò~ÿrO7­Ý/™{ȱ»^°køÃKBȉ†Xáe°ô篋æ¶êÕÙ ÝÐ0Rô~»\^¾ œ)3,Ûç>¥¹¡×¦l|xT¢!½S­aÖÿ_Öa DejÜ^8ŠŒ£T½i«¿¾~¸ÞXHm¶0µK@–Id—÷Ê&LÅV’¾¾'áù)8E¬ò£kqæl@-Ti6!̬·FdâŸÚ5Xõ°•oòPPÖÅÕpô^äNVÅ{t¢°•W‡;Æ$»ýEàÿr´+·¿íÍ8H_V_£%©¼­ ÄLes—7Ä`Õ;™g´Þ9\؃§œÀ?i™°½ØbjgÈ0×1j;ͪ‹/òÀði;|™»i¥›¤xŸŠòŸó7LÙþÒi"=¤ÓÞ#dYäjV/ «%ª–ñPèrxèô"€¯q{(ð¡ÀăF̲Þ[•ÑŠÚNTû;×J£Ó¹ ¢ÞÎ-¼¬_:膵H]À©ks2Ö´ 7«¨…$Älþl6„oÐEâ»Á&*ËCg‹²ã1˜íö†È ›|±¯Ø¸M£ÛX<2N 0ÎéÙ§r&ó}ô®Ææ`ñF(V²àéºB¬ò—/A-ÓºIÓë=ä{36Có±·ÅÈX„`Ͼlä-'Ã¥ñÇϱŸãj­z—Ÿ? ÃîNõø2R–£ô<½@¦´tPòíÕ>l×fwº2d°ô§%‘6eƒV Úi:ÑÃΟFêßž9Ú™žl›~ÏÕ²æÁeê¹[tÝ5/€‡9rjÎy°†ABî rõ¡†F¥™/­1B0;*°ÏäWöšï1‰€¤H+6"X&i8´¶~”ŽKG !½‘¾îm§¯ÒMYÕš.Á8ÞÝÛ!(Ne´*RYÀMš©ÆZ¼qèü4éŽJ:Õ›ßì¹1 3®¿WÏYînXOf(Ï,U®ž~ƒº5·dÖ•]í9L¤ó ¿u4‚‰®‚š`o ›€%XlTä‡mÖ)‘jª‰ÈÕ{ϲÕéZ½Ó£„Ç|¯_§†ç†LÔ´f6òâL¤Aœ®~$ÏÔ›&.]¼2]Ñ0$o ”ÓJWÓÖg‰Š*4'ã­ƒ4—ev0\!,‡/ÇŒt7‹†tÕ Cú§?º‚H°_œØ¯­) ŠÝ ¢x†õòK¨ów°æƒ¾©RÖÈÏd¼¬¹Y¶­/±=7T¼h…Uó›Ìg¯ñûœè_äž œ_#™N jD]>þÕÍЬà#ö¥Ê ¡}蔢“8‡H èÆDܸ4¸yÝÉÔ†þx\‘£cèê˜U[5…4ëøœý'À'ËÁIˆöét>Ó7­ßz|ÑÔìfåöþÖÅëWZî &Œ¬JXOŽ\¯i¦Îãp6„ºÍóúÝy¯¢’)æÏÀ5}DZ,Ù½¯u ¾„È“øm­6ªÚ^ä¬#¡¯ƒ/ø{4)ŠSe¹q]ØiLЗH¢¸lýL¯¥A©é¹SÈ6=q¼”Sª‰L¸ ž·6:ïñÈ“F„î’d:ÍhlI|½ƒf›Ñ&뵫¥˜›ÿ|ä·³XÚ¡œ“ó?ÙŒï=´Þ]˜+Ùw8dð¡ÂÈCOÎÞð)íÅí66íEôÓ¸U'ö ÅùÕŒ(ÊgÙñnЈ¦D´ªQ~»Á_À¿™Ž}rìHoôÉ×5e½ÐÕo >btu£ù¤.d|ÒÃöîs$þÀéñÙRŠÒ"ÁÛ,±¨¬¨ë·Àê$»0u±U„Â9A-{£Ñ„üÒA™íÿl7rS#l8PV€6¸þÇ‘ÒW!>ù, ÿ ^ïçQuˈÎåÇ pÙÈ~î‡`Õ¾*'©®( w¼RMbòú/ôxN<8b„­U3…YÿDÚO,ªøëÎa:ÐüÂ%.ñœ 8?+ZǾÂd‡@o”(–ÛŸ>i ­UZ5u’aÄÁج0)>×n'nÞcVðªpœÛþ¯neÐÀ3‘„éÄnA ÆÓJýeÞLuا<ÙþýIK0I¸–- j.ÏD×CK¨:aéôD ʾR]eA€ëþE#£þ4 rBXà^¢b¤=d<ý»>n:V–!YJ…”eˆ¼‹„Ù.8Þì=º€Q0m¶Ì³ŸRâœ>òÞizîJ'Ê^î N]Ò-òÿ8 á»ÙN§ /¥“i¶u¾:-8ÍSL›9‚ÕÌX²Yƒxüg ÃZŽ—}³)pû¿q°%1{1LŽRq¸›ø×;–½„ìÆ>ÃA§i§Ç˜q‚<Ø&M]«Í áIÕËÇ€Nÿ(ÓÛÕÑVá•»»‘Tñð[¡!ÃÛs9i(zû_{„ÀOÆ¿`EœŠ¸Ä½ÿ0l©,LŘ¡Û•ô n7KyËû÷·BÅä©V˜IêØ}B¯å¸¨·èmlLkT¥Cwö$`$B±‚%—él·2k(ÑC)–þ‹tÔ„ôŽ›­=°e®ÁÖku09³GˆØê?»ÁÒyø—4€aod±«WÇ-iÞ†—©×‚¤È†SÎuiCíâ82å6¤! ŽÂÝÎ9•·§ç×#;øBsIÎ|„.ŒÓîÃsÿE÷ßv|p¨Ò³à'N(h»ë¹8Ðä—ål° yÖeØÂ”¢e>ºü‰A\‹È÷&‰ø)ªžÖ œWè™TE±Hb%µ”V¯r}Iå#Ããd˜ï©GûóßêÃr 3À­ʰv2¢o«Bâù~í:G¬î(ÌCöÒL}w¨ƒ‘΄ýà0§Ûø uÇ$|û~I´m¥âaå¼[¨);ãWhrñùcAóekÁøñØ1†^í¥Œíœ ‡¾ËÛ‹-²HŠÜ“àÁ Ò‚Ë-õ‚BÓKÌ"Ĥe…ž;.ô¤¸PÇŠ7™¢-Ä›=†ùÑlÀº7“K(›ãxø>×é*Q³â(yFlZAÇ6,×%ØjQ½ë#?tLír4YåÂͼ üô °ºÌ=µh`¦8ÀœÒ•ª›¿ÕÎκyw^gô¯ZG;ÅŒ»ŽçÅy¯ëWEuÂûmôfÕ,eo¬—c-5éxµôÒŽ.~`ð|ÓAkPaZ-ŽÆü‘ùŸbƒþ—IGÅ=‘A]²âïÙåþU‚ƒIëFö„È7)(Â)òmYçÁ½–¡ÂäžJfÐ2/Æg:¤‹‡ÕcšR§6ú¡C¯¬Ó[Ø4¼Dê¼C¢Äg !?˜Q½›þcWþµïU“‹Ò£²’a•9"nMÕ›~XVÍê(ÀÚP*€öž`ò¢©U⎌‹ ©´Éã®–¡Úù5œ:‹9E7QÓè­ÀTyWT\×¾¼fþn‘Ž„?Ä-V=J–E¸ž­¸ÅÙFO¬’(,„×k/Bÿ|K‘}UóF ñêa“ ´ynÌ€y““%{ö³ïå¬1®²*UˆÁOáÿSÆ®~Œ4U¯ûÐ)-Ÿ UNÒY«äÍ™íWAˆVFÏŠvN©ˆ]Høö¹Óß²e%ÁÚý©R,/é"ßÛ ç Ås ”cá”yþÒí'AvÉ8wgÊÁAÒÛ;__ë š\.Ü›`à¥÷6)×S’¦|w2Ÿ°ø1l{… °A÷­ûªKŒmë‰ÛrvÀª©2ÂЂ9 ™á¶Ë>;.°Äˆ¦÷‰ŸÖSˆIú7 ôvâˆaÜÇ«ßÁ\߀™öŽ´P«lžØ\¹÷´ •sñ±5rû /m±œô¢ü~¼z{Vù³À[LúÒ ëë¿¢px½ã¹ð7y¹â¸ UE™Áž8ÉT­íq.Ë “õ&w‡Y§{¿|·‘‡ù~ 丕ÄËž÷çf‡9"½“Õdnw£š9úÄ*ŽÝòž@Þuðñ !ÕóàºK.aަoƒÙÄÝ]mÜÝHtâ…%+†{¼¦ÏÕ#l)¦AqýŠàAï$MÞvíþÚ§HO;-°¦ Wyš›ÉD|0qåàBþhˆ!1’ø>P¤ÔìºûšÈ2m”Å4tØœ¢58#ÿrÇúý®âyìd?q£½¡+î&ˆ‚@€…iLÒ£wˆ›ïï;Õˆ”ëзV纺U=f,¿¨cIƒôýá øÃ_SK7Ê{Fgâ9„þÀõEïu'Ô{¡©§åõöÔÝvlY!fÀH£X†ÙñǺ;h½á˜ÏlDPk(õO#õ€;9`Ä_ùö1€#¸áC¬Lú¢B›s©J±ûÔaÚç;U;¹11°ªk}?Î*&ÒŒ\;.nœòP/•š6 ¿â…ˆr;C’ì–(înKÒÜ?ñ%y0¢#á×ÂÈZSÍ–ÉWsk†×÷’Ric ­ÊðÃCû6 d]vœõ4:Ë’Ó”I£ Æuµ-•Œ=o5¶¤œh8À0ÏP>ör:™ñIQ˜wø«§ŠhGñÝin.rîÚ©pÊVmX¿ød5²ã]D½¡®![™ÿ(Îðéw4Œ²Vn?Àï¬6Àí‚--c6ÃÐs+ÉÙé ±`jœ%rˆ`‚zß܆.Ç!Ãÿ3~|sÞ¢cùC.—Ô³b~x!k-|C­¯¿5S§h&u)™ˆ>/µÇÔl…ÏlBò(I­ÏvD BÖJƱ]"y’؉ &î}Í„çHlçßÙÉÁùYUÒR^w-`(ü¶Vþ52-×±ñI‹þ{\Y{+±õSméW™°Eg¾Î·FÚ}zÍÉ&LÐåûÔÔŒ+¶CF³P¾þ¡Œ£'áÅ/c…çù$ÐÌ#€ˆô‡­Ä˜»»Ûʬ–~À,P:⺠žå0fëïyÂÝÚåt'¯ûžÛbA°§É5¼]ža'ýÏË„¢êbâÑW‰‚0hD^"ÜîØ@)xá‚(îì+C°“¶´$÷$Ú¾8£ Pþ!eäU´Oþ÷²?—qäÜ‚*"f?LÁÙL—3íkÏ…K³¬Xtºð¼ ±ÇpG”ƒFìÌujç: –]{ÔofÙN,‰Îys‰²;߇è]ŽNf4è/wx{´U7FÑämì}J}l- ?âxô“N¯\Ä÷­2ºáøÃè tfëüÜx€¢ÞópúGhÇžƒŒé`ÊËÔ&#yF+O·N#&<ÅòجÝSbò†ZZô«ø™¤ R˜ô¿Õi±ÿ rçD›cñ­‰£Z¼ÿ2s¿øwmy1ŸÍ~¾ñ¿2ìADè¡Ë#¼ ¥,Jß.KQ >ûcì ÄH¾hFi a—KhÄ£{ˆ>:7m¶»íTƒÈN !%‰ËAý‰°É¸_i$Û Ò<;}È^zÝz«Ã•PŽå8•È]Áì|÷ £FÒƒè$OP‘6\î›H„)f÷¨Iœ‡®Í‘sXâjƒêÛžËÂ.w„p™N13†ù€ÔhèŒN Pù`öË™VïWgÏÒüAÞ@Ái«ïÔQá±ø…ÒïÈüº(vŽ{|”n>Œ!*ÄTéôtÿ°£cÃâ7§ÔûûTÿåoBx(y {W7ÕD¯oüÊøm,nnàÓJ=«?®ò¯ †ebÅÂŽÿuG JX>0YHâ#Ž qI™(3³üØ“k<Ë:ª­÷è¡Ò/Nð)Šâho/…½€×5½œÛXØ>¼L\¡Q!û–hgtÍŠ[öë»È ^m¼‡¡üoÖ;(‰S¡@þé>-ºÕ~X0Ðù^Ⱥò?±nº2¹k¸ø×9*˜D!œÊ%¨ $ËE·ò´ÛµØ©n XN×&ó»ýü‡ÒB¥bˆÃÀ rÞäÿy¯~íûÏŠ{é×´ˆìAÚ¶´°¯‚Av—ø©ŠI½E7£kõ¯å]¡f]yd¯‡©E!ÐV Ë Oý QÕn’ãGôIyaåJñß\Ö“(2é6MŽ–2Œ{†:’ð4ãS÷ªLïÃNL#9‹Àâ@ÇÖ©ˆ/-¤Rmî=‹Pë·w'w€çCõá%Êúã’H·•˜&c÷/Ðí­±V'kF´vûBº?(ü÷sLLÆ;ª# "OjÇòÿ"ˆuÞTiˆ5u— `oÀAlÓ˜?}"K gž2šx?XâàåNÿ››‰Pò«ˆ‹OT7äå6çuQ'¸lªÏÌÊ*Ѳ]oã>ìzBǨº“F¹‰·l=J]is—´áB˜"cÜ“À•þa•“´>‘¶7þƒÞM Ê#æÖ5íbô›æ$úÆ}KÍUϨð~ŸŽÅû0–Ny·Cª‘\ùDp[áœL‘î=N½/¦¼û„•Ó¼ 9=ËÓʳCâlÌÜÕïpº<:YD¹Ó¸.´ˆ9 GohŠ*¸ÄĮ걠(WdìˆKÄòXé"ptžTSN°–ëYJ]ÐŒ'6öm{Yö£Áb¯C&ÜL’’=`‹°K¸LÆ «0)Ædg´¹„Ñd…ì…†¶rÖ§ÿqÿJ¤Th£€oßlâÿš$D*x¶ÈD1äX åë*·`žzQ˜Fß j+¾ÂÀáæ}ä k‹äSXF¾õ„TÊ„{wZÜ`¨êí_T#²óï»,¦ôÏtÖOTI]&ÝÑ+5RýZÑSdìñîq7ÄOJ{£ë åH º„fAÝÚY$Ê•aT’ÛhÊ-Œ\aÃ샠 D%®üÆpo‘'|ã¼gqØ_žÁV–×@t×¢sÞ®O±93¡øR¬ÖU“‘{ð뺬AXA:aƒjÖŒ˜BÿVÒÌþšÌ]Ï^Yb3DI¡ÈûÝ*JúŠd(ÛÎSW°u°œ°Zÿ`Ë¿.LÂ}1Ø'ˆNWFªá’¸µ½ßÄÜùÃK®•+¬œ’)?þ4@‚¾§­ª¼Ö\›VìúóTw—«´Á*¢XÌd4JßwpOÝŠˆ³rß÷|vBN™2òh¯HùÃ_c‡Íì4ŸÌ;7è"Édð(!¥Ñ7 f0Û ”Ü û– î¼ ÇLgdyeòŠ hï²€hÔ:µT t­Õ>×|þ‰ ¸( @¤)!ÙhGYá;4¢ƒy\3ŒÒÿÿ,]–¾´ýϼµóMšºHb&Wnh›Ìåë< 4¦KÓ89¡|E‚Q>a¼Æ:5ÔB±uÐef‹*»mƒãàà™rµ¸’§öGÓýŠDz~ œó^Öì;5ˆ³-ƒ-8¯aÿÓuQ#yb¶P~ïçИ„¨B_#à`P‘e‹‡–«¬XÏ¢µ‹$-*?àÓ˜Ã4ƒ8 —´”@>ÚÎÏ H "'3gû⮘WèŽ9ú3®ãA0=“Ç!!c±5ïmÈärÆ9b¯_âzµˆCðØÉ.ç²Åæk]Kž¯‰âF_ö•õ9¿FsØPÈ£¡6=3"Àã×Îãn%:ï4¬fÖf+¤Wì·n9ý†½" œg m|…Äuð èÛô7 5UßÃyë"‚ »ŠÆ L §† xñ˜Q°|¹Jx¬‚ŠÜÕi#º‰£x`UL-Z¦ ­ÚÖà¿»Ù:ÚÅàð¦Évž(‰ÞáeŠ£XÿXÀPuè¸É©÷–t”Sm¼7Jˆ^­A,þ!TÓ´!Fñ°èϨP&0cçÍ^(K#aøPÔB>ž¾¨ï˜*åFÁïpû’•ŒŒÐðÙMh~Y 4ªAA†¿Éç½eXN½Ö$9;Ãñª ò®æ€Œ‚ @ (9{Åä¶å—ÄÂS~C¤ž´òa¥{œÈÂŒªB†U=ÒîÙ.WTxõÖuÉYïS(ÐÀu\—í (k…¡w¿æŒ°Ç”B¯P »S‰]Œæ -ˆ¥4¦V%q“#½ê¹æ#3bêTœXAâöËŸ.ïN®]t֋LJ½õyÄ}›¸AÚN5®‰ENÖâŽCP¬êû©/¾[Ä­i­ ¯Ïeò}$²Æ€¯›îù¡wÍg›8aò‹ò@mÄSO¤ów?ÈHÛ Ý…¿6Ö¾AQJùŸƒ|œØ½ãwè#Û,&ƒÔe¯ò_•?èÅc­~{z„tŠ­«¡¡‘3ÉÞ¾ÅËèü(Õ“4H_LÆ“¦äü„SEZSILjîæÿdïˆq,¬É@°™àý[»Mïßþ÷ÖUW¤Úä^½ ÿ}»É§ªeP”ÄýÂps|†H@‘¾ÒP -v•ºÂ[®Ažimo¡—ê¡G¿@Ìl›ïaç–^h léšsVçŽõ`ÝQDIL?"‡¬Òd3Žr¹·ä¨ÑC(t`ê°2lÆXæe®?™téÍdmÃ%UIÞ¶Ôô˜…‹=<¿Ë>ðŒl+üŒ2Tq†¥ˆ.¿`lIj€™ TðmØ£(ƒàï'ìMÕpÂ` F ‡hfœ<æ+   亂z{ ;þF*œ£ |™Ô<àí[(ý¡ñ‘µ?ž†k}¬‚cÌ 8Ðë÷,7FXº­Ø"ˆE´êtËNLþ´|%—3f.1Äóvÿ+ÿEóUÓ*Gøj§1愃s„*©=¯„½Õ€à8Ÿ¶:Qæ¢Q(”J%€ ·òðd%ÞùïÎç·êÚ†¦èهà vˆDÏË÷O¨î’(à?0> 1¿ð°¹‡oP•³©AtT¿%µ¡Ô ܌ݒ¯àZÚ²cšÂ8GᎰalIéAÐýYU5RwÉЬàÐüúÜ–* ÓK¼Ñ2ÅãÐ TG0|/x¬é÷‡e8™ÇV¯¸î)ÂlVtÛ(‚É”4ðŠÏŸ%ýLu/01ˆ@škÙÄ13ÿ_»ù\wk…z×ñ1N³iÀÿ<+ Ÿ2P„„œ¨Dja`ê§Õ¬¼6U LuôVDîÓþs½õ©¶œP-M_¥Â HÊwß|DFv>ñ}tzìf°YÍBÿS³”fŽ“Îf©ª×Vê`PaÄõlVÃB0Ãÿ›aÔ§rÁNÒŒ`<ýûª¼Ú|uV—_k…ä„”Ò z7Ý,OŽ :ÞgO¬ Tîy=C¯7æôú¿òý±g*U£B”a!'ëœØ€Ó°ÌM!Ô$ü·SoÝÇEyö¦«vBLÉç$ -v—v¦þëBj­=¼( ÔtCZó?ù²U/+þnyN­üñ=È—à·>J…õçîFÈ'= ÝiÅ–ƒš@ëÖÊ)»T¾À ‹GzsNȨÅÔc]dê¤O¬².Ãiuÿñ1N¿þÖ™Þì{AµÁT;úÚ¯¬€Èk„¾¸¨PFÿÚTâ×Þã”î{{¸—ÏfÀçEì5ôÝ:!š›ý‚) ¾p–ਿ”íÕŠ8ð‡ž+f± Æ\³ÞòH`r,‡å½ç5 K×xLÒÛ™R Im²0ÉP ‘éÈwƇVæD¨5ƨ>Ÿ£QS**)¸Èý[±åQNVóÂæxÒ`@~;†ü¤ZîÉ u—–ÐØ‡­¤z4££Â8Fü”@î½XÛ¸ jþ-#½½œ‰ ̹1bÆ€€=F(!ƈMmÂw<Õ¾,ñ1N ò²½…óßëÇóÝ}€0,yëG(ÂuBs$ƒ4Áý›5%:éÆ©Ï·HB®'çÅTö}Àœ&qÙ?ÿ _›ƒÛrýÍð±gaƒu7&ƒÞV׸[€ Ê{BeOÓä…ãüò¾€V¢¢/ÎaNŒÀ€‰…âÓPQ8¾ ºu¨à›c´Y6 tѵ¢{r Ô#†tçð÷åFšÙr0ÉP»úá3Î|•ù™SêìrKT´—&•/;ˆ=#!O׎ƒÈàzôÏ Ùd¨›VΈ¼)É,yÁ<•°ÒøÚFFÙäú“’ˆc|R€<ù*IÂPK}Úq³kƶƒH¡WmÜxá[ãEåüSò¸þQ~5«Ñ¥_m3*z'‰c£ažÓ² 'ž-±ƒ Õìß¡s宜»jKZN{é£$öù `jï×^&§U@±ƒWšaBbXpñ‡Ë©‘2¬ÄZ¯•sv÷ßð2òMl¤þÊ ¬›'©f¯2~~Cÿ&£8÷ 莴:ÁÒ™údž¾^7À‡ÔGË¡:¿cV*aý7ÖµëÀ)Õ6äKØ+0*žº_p˜òpø5>3•þ„¦ûb<†!‰®ÎÛ"v y¦8š_4¡¼HΉ³½CE‚æ$A3”%Eßö)¦Ìè¾ÀØ«#*ôo=Ý@j¹ë¨1¤î?GüçqnBÏÛeÀ3ïY“qÌéã`% @8”ãÅ ¶Z2É}›te…‹æ~ˆ_:›IèÍæš$é:wÜ>=4çuçÄ‹Xl]L û–Prsÿbe½Fy”[Ÿ‡Sý„ëž|Ø–h2¸Ï¯Çó`ÃÈ®ø<óÅU&?ãQçÍž¸¹ hûspKÈÑ ŠñBñþ0¶ºôÝm_½ÃúÏò!LGÙƒâÖkO®­{å$Cöv¼±{¤͉iY®'`¡õq‡Æ¾z¡åÉvØXò ŒÕÒ8“ŽKEˆÊ¼•Ïö/—hÖô0Ù-±«˜i„·Ûâ ôg-5’óÍ ’ºäÆÉ»Õ¹›NÕ´µÙÕ‡0iVR8¿÷£%á:A»T•XLàѨÃÿkCk‰ã“'dš£auû‚$YoÖ‰îVÊ+ËÀm¢µ@K¯AJñj+Ïy¤ê«k4¬ÙÃUî+ A#g\>I9‰Ö$Ñ~ƒ‡ý ‰ ó•t'wª÷2¿e÷¢h“F B“Îõg–»Ãn¡~5'ÐûÉPò,@OÔB$¦óÔ‘¡sÿ.ø~‡þIjr£B°gŽ£8“hѱž]î kš4”[‰@DÀ¡Žæ3+y϶]±€Æ’ aÞ‘º“CÏêœi ˜4뱪úæé>Ó«AM=%+ï7\ƒ|ö›f-dÐ yè-ñ8ÐqeïDØêmÉÏ0… yÏ…¶`Зû'x;« §`‘¾Z¼?ãµTp×ÈVXeÿfX©Ãàô*áÓQÌlƒ&Úeb$hËœÆþ kkAšFs¢f¤×%(ÿFµÕGdmGÊŽJÙ!`ñÜ~ÑÇìéàiÑê›Øïkw©*H0¸ñÏŸÕݽ=dœ©F(ŽÐñp9ôò[¢¨\*®ÒŒøA`?7VüQî ylÿQ¤™YÕ(ɨm6c‡÷îMCݺ`¿ŒÔ\¬”UÙרÚRQ5¼’zñž}vϺçˆÈ1á‹Ñì/IhbûßÛ\âG‚†‹€%™pöeAìŒ.qó! üøÝM¢ŸS·çE´Õ©kŸmiÌ[ï¸=¡Xú?ÿt¯}TëJÌa’  |"T?…GQž)…½mËOµÀ Pó)'D`-)"-:%¨½è˜[” ÃÒ³5BªDHÄ»ë’Ë>]Øb5ÝíÚ?è.ìK9f).ä~`ü.ST]ÓR›í¹?L þ}Ö“¦ŸÛâŠzŽ]D0’æn*ÒÏæiî(–÷jc¥‡Z¤¢lü‹¶¼wªÇ)÷V«f;< ‘†J€ú%».å^˜,ù^ÈÐS×ÏüÑA%¼Ó•T£)ÚÁ›õé¸àlŒ2TEˆýd]ŸÅOxSÝ=×${j„xƒœÖÆ&»À*ü±¡eNš´ÓÜ"°g-“ 9Îs­ôœs7ú÷¡ÖѬÚFÈ«¨wúì7 MMí¶¿rö³çË,J£%v!D+¤u™¯ÿ!aÄ_Rž{ŒKý1ådÌbø¾«²öÐ< òk7Òr×´ Æm:d ?-º‡ŒÈ’ÙÀ¬X¾Ôg“ÿ|Ú6F*/'ÙuUceÑÑ÷£ nÓ#ÈÊë ýç¥ÔÓQŸçúð€²5Èvvæ»þTVÏda’ mù_šI$îŨ!5laÛ’«°Ž½׿- !ÁÚñ Çï"ªrßÛ.0)³ÀÙd¨eF Ò~ £Õ²@Lš¶±wj · ¥m#d§1Íà`@‘„„§Õd8䘘 97ç&Ÿ=³üèh^2Bû5:S†0Ó|£So©ø,Á6=É ÇÉ6e­âbÚ!“†Ë9Epç&´»µJúå~Ó±­Ãb§0/6R´CÌm[D(Åå¹mæ0ˆv91Ó¦¦w]âTÃü±¤k¡"V@F ±5 ª«¡@·kIÕ‘ÿ{vhc‘Xÿ}9/m´Ì¯Ž öU"] ^E@;¤ÛªtË¡†J…F3d­„ jo‹-»Éò€”˜qjÈk’ûXœUÐZ¹ØÊ?VóÉPEøÝ0ÁO®_M©änÛÖÝnç©×¢Í×&ªrg¦]­ø]sÍKHxÆz[\„±Ú„„„fœGœ½“¢ãç4p8ÿ Ì€¢Ë^~dè[5‘D¿‘.u$£evúwjÄéZ›¾]Ñq¬Ç0amÅMÆ&â-qˆ­ÎvÏÙL“bõmü驨úM¥0¿|RGöˆ9ŠlÅÙ|¥Ö¯2ä\Dú‰p¤Ö"Müèëªcǰ²¥»”[FõûòTõ³G,µF[Ê›ÇÀX—*ûÞô!ÀlÖ,>g´ñS"Rö­‹V\0؇5”Î4*ë5†L°äÉ|%6·ü 2×ÁÊ ò§Ø¼îSfGÆ_®Ãz@ ‘\ €´\bó‹õX|6×ÉN ¶Ì¤‡ˆK(EÁÜ2DRçæšî(åÝ¡@~¼` d¤„ýYæŒDèzŒJ‚F¹¹¾`‚6£Ý©Hÿø5ë¡÷WB îT1®ä•—&†¯‰c^ƒµbªNÁJmœáEoj[x›óÔq â/†ôöBµÒÇ6'¢+‹²ˆ½$’{Q{Vlý¼Y›+"Û.$á¼Lou'—ÿYh¾•Ë7§›ŸÞÇ!ö”nΦ+ ?œÉ¬RâûrùÈðͱ÷8eŒÒƳݺ…®?q› ¡kø’l€ü\¥Bh^Ž"`h6¡oàÒ.‚¿Ñ³{ÕKÕŸ ¦ô´¯ý†ÎÇ)à I,Þí Ç§Lv‚/Ä:‚ì Uî…–yÒ`_ŠÐ2ޓѺÑ~Ó„˜¦§(WœpÎØÀûÇ1¦crj€ÙŒðÈõ{œbw#;ÉÕÒŠÉÅb'ÃÐø¡¤ª"€¬`Æ/“.XÿAûd ¨®ÒY©™<þÊ畵™rŽM¦í *uÆ 8×Jåô3ü»_ðý—Ä¥´ÙQ5þßaä{quªf²– |ºÍCu[v[ðïçZk×P3¿õãxÔñXJ¸Ûlä9Ò¤÷C¢òVÄGI¯+ ´ä-ý=0?Ùˆ8ؘ°ãäz¾]«M^¡>ZáVþAY"%0íßBö8zU\/ìX»Pi)2(í›h)eŒž¿ªØzØ‘aöéèöW AEû ~½ô ¯}>¶â¿l°ÉO¸¼x{„¥šfí Ã)ká-X"ăzưDð%bi9ܤvä¡J{“lW#z}.Ø#ËKÝh2Þ@DÝüçÇæ‰z­¦º ‹¼µÀ§‡÷VZD NÙ~vñ£kËìuÁóÅ8gܰ._ІÁú©bÎ^Ñò¶Ô‡;˜Ÿ†Ÿý›ÖÄî'Eh½VÒß9¢¹bYÃáã…Äó\ŠnÛþaÌ;C~ÀFðFå©;ö¾¶C±U:åŽOFFOÑ¿áä¬_T™sɽx ÞØ)ÿ-RmQ¡‘¿Þ×Þ^j^Ï…[ï#€a¢›áÏ (èŨ¡åd%.â€6W8Ò:4~X‡¢Ã[!¨:å~(¨ùSe¾2YON휅Ëp‰\³BCÐ8¨ê7d¬çÚmã1*[3 'm·¦‘X¾…EÓ”X/B¥ôͪq_õ3v$Œ%Œû|Z°ílˆ¦¤ËL9ج"X}oxÉ~’´…½hnA.UävŸý–½‰¹Ë!!ûçÛ– Z/‚ÁÿŸºh„€Ê[ÓŒ6¨´â)™ ³ù­ Ä[ZPõz%ÁáþÄJݘÐXٓաܪÿó7:Áy[•¢jH–ÊkÏ>Èåœÿ¶É(ƒ)¿9ÄßÓì´¨ÿié¾Hy_µìÚPÒÇ<ª”t}Ỿ"}ù« GåE‡Ps!'X¿mbþûÑ“ž:XD“ëò_½!'»€$ ¨9±’þ™ r$f‡ô¸³`Ô“$BJlrðZ¡Âg4é8¦³rëD1Ž3/»±Ý7Ý‹Ipú¹ž©9å;=ÿ ¼Ró‰É¢`£ØøŸ•ÎŒ#ëùú©¡Tˆ¸ŒÚ€Wð†fµÖÿ?ö¤•FÖíέJ†Ç>ìç‹¶øtÒå^®ð¤Þ‚ŸÝ) ±ÑE?ƒðWéDy§} #(<ü ù~.ÑÊü…&ÙIzã€C¾ºÝË'À9Øäw~@åÁ‘EPÅôK䦡H5»f¾¦>Ès4Æ]/ò @ïðü5óæû3ŽoL8Í!’ßEüÿql «àŽh0Pä†4ä¯ÖÌ)ëIû38` ÅÌaÙhVWÿõœ÷‡²ŸAo,+…¹BQèæ‡F¤Þâ|y§âkI›v†ñ&;á âdïpÌL{„£Ð~˜ŽPÇ )7¥}ªðzÍ÷én„(Èè²Ûñ¹½müp²câú›H:,u¡­æZ3Í<°7ÖLI9\]z!™U pÎê’Lãc‰wsîãfk<áxÃÝ’;& »jhé¯ Ö–Ò3*$cjªÙ樮tLÉ£æ­p Í·¦'XƒBßû…yýÍÃlÕ¸€yïÿqcox>?ó á±ã÷æ€ ˆ¥Z­º·Íb™¶ÈO>ÃPþaáN¸Tµ†“Ý º ~AñSäÕÏäA·å‚ÍÔD–‹Hnn†ø`¼5²jm’‰°ªΰŽ<ÁU4©kŸãú[ÖýÎ0 ìVúã hóìÆ‘®Œ—tKI.Ÿ¯Tß‚VØk}a¼Žo¬T¶ê@  d­ŠÍž¹œÓöV_ç ê~ÎÁP8Gü˜Þ¯ÿæîwynÑâ¹ÿ‚IËkôŒ/Š“ý‰z¤æÛ¾=rÝ=~„A> Ø¿e.³€Õ`¤¢¦´óÔûÊ©¹I µ™·¬Å ¥' S²ÖaãÈdÅDo«ÖÃ8ÿãÖ±6Û±‚£‰œÿÚ! ø'sã¥.§NÒ¶J€ÈUàfÔØÚD­*Bˆ~ÝÕÔ²îÍ_5Ô²üÆ{·¨rw þiS²›þ­¾íií¥  ÛÂÝ„óWÈRôxáÁ ÌBç×ã…-|…µ1% dOO‚Uñ®@œíp~Ò#ãŠöT©$¯Ï@Ÿð^™Cct_PÞa½·ƒQkR=3 ©éN‡`±š³ÑÖ _zoCœbsŽÑlZà¸á‡Ce¨ºRòpýÈsòZêk €è§ NÒ ìŒH,%U*CE¹v"?"C4ƒ?AVá%ÆÊ`ƒ0%¾Ÿ%çËz+_´­[óˆj|’$£–ƒÉµÀÒŒë5„.ôŒíF+L·3йF­{Ñê«ÊÍ]è¾\ºN¶SàPV:j3Мvö ,‰yNÊ•d6ð—m$ó; 42óM'´"!e”ÎóÌùQÐ\?øgÜ5sæ±!ÿ@ òôðîã!}”µ_§©‰í‹_}„3»ÃØp»4ë&/(‚Ðó8 »äî…î8d à÷©¾@èÔ‰NŠÓÁ^Ä?|¢0à`ïågòÚÏ€¿U¢è›üÏ/‚ÇÙ2Æ8`çñL._•Eùx''¿+'D De«X¹%0{Ø,èú”¨ÿjäµE €ðŠEMn ~ìu²–º5—pÕ¼\U©#£ðãá#íSž¢ä2°¨}Êéú-­+þÅ·4Zpë´²Þ´q\Z¤=rĉW•çü@Í2÷õª$ö¨Ñ5ðŸ)OçP¾4|‚·ÓB/x /Ѝ ˜¢SλÆLÑ–Cª·LðؽÜwwê·…ÚK±„&1À§ÚY\)0>|gØõ²î“¾ÇÏt4îsœzõâ¯6~”áHµ”ÔLÒ¼O°/œò¦÷G Ù]™NÛÁ]¾›Ë˜U¢UÕžÚWÊŠ²8¾‘Î3ãzŸ¦Ë·ÜÓš½åâ ½áÚ¿LNÂ".ë{vâ¢~Ä5÷|w·? ×bäÑž&#ŧ‚®‹ 1š‚ݤñÇ*²(%´t„£ÿp?Øvg³À5Ò™¤Ô–ø0}Þè=¯E÷}–hÌKŠ®Øâ:P–&?j›™Ÿì#•éJ=Qš`nQušÑî³dY© /–y<áÀ@¤13x¾êÝW„îIdô[åžœ‹šÒ;ʼ†™îytó¥þ?§©WÃÝ)ÒS`ˆŠñéÐýÚâ?)¿ÿåb–bÝ¿NÉéê!gñ¤ÞIö¡r㡯Bøõ+¿/Ü¥¸Ëi!²Ï­¬¿ÿÜú}SÝÑßÔ^¼³ÒeØàð¬;]¤PŽ/À÷7¾¼q<Ísž‹hbKŸ×ÍTn?x*Z¼’$Ô@òïVþB1ÁÖÌ—P·@{¡Ÿ—Ó¼ná– ÂOÿ«}âowVGåèH7ãNœ ¬ùIýæ&Gl ¬»²9ÿ8£!]Ê ÇüSÛ¸™õÁ¹f^–¶+Ñ·l‚½ÍƝÄF=ù a^²LÐAUØ'Etz Æõç¼ß곿zÛ+6oåˇ}‰täÑ#…ß×Y3œÏø~ýÒ—›ŽÒ\{í³ûR›â´·.w÷ßtμlŽ×!,29cã&fW A”è®Õ\B©ñÇÖ,ŸƒBaW_S#q„úgQòAød b¦ö&!Â"Öý¥ëÀìò¼©~Ù„6%jÝûÓÛ¬BY¯Ù pq8ý]˜±9 “hæ#„\¦Õ{{ðÔ@NùTA¨ËïRE2“̪>füÉ/_\Wƒï>â¨Bè6)™<35DA,ĉöÒÂB²Ø_©pÇ(éâQ¨9¦*©ç¹×È~")`#nx¶’œ›ÄtÂj¼ÓïG?”¢ü"§| ä„–*ï=…­Gãö]‘”ºZ†þýAT¸åÎŠŠ¬–Ñ ùUž‘:Ê|Aß¹¸ h*+% ò=õŽó‰Œ tcHMî&´UdÖãõèéB@Â/Л'ìî?ÒZás*gøß9¾£Õ—C5û‰.” $”+¤ŽÚ+±½ûµwŠ AŸÑ{pÑëߤªØ+]¹;i/\=æÆ'í6XŽÐ]7”,¸|£Ú¥*`µÂï¯Ûl³k›3Öæ+§á_Uh"MÝi8oÁG?áIЬ/Ê7™ûÇ ð•qQùÞB,½/ ¸“ΦO1ý’CDW/$-(ÞýüN-H€5ÒX?é,“7’æú6;Ù¯þYäÜü'¾ìô_zÓ{MrXxìWJ‚‘•3sS-¦Ú]G# az€®×ïac™%Ïm2Z\Ä»?æ•ï1€$hƘŒ<‰—E‚ì¼y“€‘ˆŸ¦á†`ëeté÷<Í4ïI³`Nà fœíúR{T:ìä2Áê”àóZývÂðUÓVˆø §"=Fº×` ¤p>Fþù>I yBá*žÿtz¶hÙg¸€€¼ÓŽhºH6²™8MÄ¡EVGj¸Ÿ˜…ÕÝuófÝi4±Ø鈆rWþ`¯ÐOh`Ä43ÛG¯©Ù5ñY‡¸+ Ûu#h”¼è¾®5û’˜ØDJ´†Á`äãªý!Pت•/)ÓCú„%¥S}1ãä Ñ[ ¾ [ö#2úB4ƒštÚô0]?Au^~/ȬwDÓi5Žt™>ål í8&Œ˜Œ,¹šÙ3ÿ+ » ˆ¹“ŒO¦{Ó£Qnã†ÏȸÏDì [Àó¨¦, Ì&g5ùÅÒôÔ„÷ŽÖÝíðnÍïp­~žµçÑ«©ZÙ¬S¹½vÀ&{bסšPivUŠÃaƒæˆ¨Î†™Æ{3Úm‰ke²Uó´-cDgÀ“'Í›üŽ"ÅáYàvÒGM£’Šð^zkÃtNŽù^]€Yx²BŒÃ Ëðd/þËä}8êýø¿%ьϵÏå'éxÚX+ÁX¦íÕÉü*&ÙÆ’ÅšüõƒMõÞÍ0ŽÎ‹pÇ僶O¢$OmAÎTL͵–ÂIÑkQI烜”ñ•lrˆÛbçéõêá+Å«Ëý¾ž}Ø.f¤_ ;ßöæš“…k—ê,Ó“.M0„êè­Y¡ÂITUI¯¦BQ¾ ?¨¨î¢Ð'Ò|±žž WáêŒÅEb÷/d‡†ÀBØž7Ÿ¯}9”_<½ «…ù&V¨“õÓÿqm•С0+“I¹cãÛ‡x+ªÙÔãanUö›ëÄ¥·šH2¨‰«Í­!Kd¹“\ÎøÖ î5_øF~žÁu—KßÏa¡úô#Ä’Þ™ÐUyeëåé¸pG°CÓ:þ´Ì¡%u±Sø²ÂTHCŠ‚aê9Nq¯ðT@ûLˉ‚n¿2[úLœ¶¶ê—£Âû²?ÞäÓÌü3#VÑÄ¥€mw¦ul5Jöd.ç_¼FÍÃJrÂçXĺ½H¯üˆŠ,—§ŠKc¬øúV!ðêÃR@­Š2i†pÑÚŽü€dlë³6èySZ{IEzˆêÁ¿ãímÃGäÕço ï’ŒË޲ŸP/ ²¬‹j¯lîõ‘ñä*pÆ¢ü‚E9q¤¦ü°Õ ‹zç̹¢1 ÞÐ7‡ƒ q¦ÞP%2Ñ IË8ŒçOÕô¸­G/…ï9äßgîˆnážm¦<&ð«åÞ{,±IøîXa0ŸÈàVSßÏÒ'ú E<4ÿÑ ¯^'>Å7ðs>™)¾O[|Ÿd0Õ_7Ë»Ç$@_hÎ'Ó½ÈË€ûÒw‘(&‘ê¦Cœ•š1N§ø_kjþ TæñØÓ bÉm—¢ÅãEÄûgÛ”Ò’ÇÒm€¸k:e/KP"IRH¿ê77'ûп4A…Úue‘$’òâȆâ.…€n4ÓÞ¬k“;85ÿH\õì)Ô*œ¨­àìM• 84çP»g12ÈŸ´HÜ¨Šº½îjëÆÙÜÌ}0fã±ÄW³Èb¼ÙÉݼ‚?øµ-üWb™Î+®ö:fˆ¬;Âu¡Ë©;{¯i…€CdýJ'”Ú±´M™£ÿwNEÃ<ö~ü®·öY×’ZÎOìã0ÖeOíZóõŽmÄàV®ãÍö•«‡Ä¼‘Kõu:ò‘ÉæÆG¡SKFb]î¯ëý¾\á\wFì«H|2ëL:y·eÒcüŽð%‡†*“5ty/QlÁ1bøÇÆ-«Pe˜ªÒKônØñ„òÄ,Ñ‹˜FXdØ¢ÕÁÈCÀ¢aK”Uùj£Ú<Ë&p©§Hn,¬àOà=#¥eÆÁrìû¯MÚ˜N¦¤g±´©Ý<–/áœy©«¹ª%Ö•оhTnrˆY8Z³Ò˜ÐÁ“ÜwþùÊ£µbßw7䨯"2"³U£LÒ¤4‡²Sƒ̯ÿU:_¼úÒ„gɵ®M V,ym?>Náhy‰x¤`‡7ÂÏxrq´÷ä=“Y%<ð_ªšdhÂËÀÏŒu±ô «‡ÊPRëðYžÝÐ94ÒÕZ©ÁÐ{3å£;lÍ¿ÄóÔ^õò¶bõ+ eøÕ»€WR¿ñÁç©·¼Õ¼¿ ."°H§Ñ|*ަ`¿ ®(,°dgþ!Ø$(·lž$´Ôýeàj¶r1 C}Î.Nì|}+Ê­"Û³*ÇkÚ×$¤¨H}CPD®…FTÁjت¤Z‚ûn?9Bg±çíñA ãZ‰EiŽæ!ï›ÐãDܱMý×J{ •‰Ë-Ý*Ú¿YsÈ>Æ­DË tpä­=§ç}&ª(^%Ch…ÜÙ“_·ßë‹„USM‹µFO-N`›ï3G›Urš§:m6%5“Yȧ A%b<“Œ²ï(pgóÿõÍOÆ7²Yj`°ÿ/ÓËó¹Þ°é€¢tî«Þpâÿ6uƒGùÁ­äƒ³YX‘Oç ì'Ì—ÙP€E¾A»©AíeîÐüÒÃö;éy;OìJfÒœÅ#Réï] þK:÷ *¾˜4"á ýßÛ")µúö#ÿbìSÕ¨ÿ6=ÐŽ8š3yl€™bG4ȸy9¬àDš ¦ Îå­x1‡†ñ»SwÅ/YË\ƒOx¤„¡úà,%eÚx¹5¾ P ª÷䔥zvbxŒŒéW™¤¨ë~$áøl–êü°cöÇÏǫ̀QÑÆ8Ï;{oîmxs=ì³ßàÆav^¼ÎÒsÀDwœ•¾¤ð3Ãp¥¼ÈÑð°;Gå}ýQ_1Ù˜4¦ñUç„ýÀÆ´èDù§mȰQ?GoS†j×/þw†L»wúÝ#ÒÈy(Âê‘XHÒjÖ‚@fÏAÐm{µº±Ž;ñ’3»¶](9š¨Lv‘è7Œ"8­håq°“‚*ÌVX™“DvMK³üüÃ;nÙ?öÈ?ÅØ§«QþØüVüœ&v¸\A(Ö߯»0Ü¥ÖîaâHkæšß—<ú¤†%Qç’ª°ÑäšÐõàWŸFëCJÈO[0ó 4J–§M!€/•¸ú¹—¾Ê¼¹š¬zä3^Ûà6h°ÃÔsý‹ðe¾5~¿ëÁÝ++唌ÇdÙ3ìÚó¢šy§“ÜP3 L½† †jj–‰ÀPú2ÌÍŽ!bÒ=|DBÌEÕ;K8þy­ ã=Ë¡I@}ãþƒDc>–˜jRïÿ??„zÕvy™åÕí%»µËE¨ 7ëu)/q÷£-„œT?´c¾.q“·ÆpªY‡ÊšIm—Íœ£­yüŠŽXZ‚›|k%’AäŸ;Çöu¯\ÝxlƒÄÀ¤ãÓœ ¡ã®—‹¡?øzþ{M˜ˆf—6ÇkˆìØÒC^]l`ú™V7Ó/‡L«FXFm‚ãFXªàªöci…[×YЖê&=ä/,ÒI_‚1áng޶E§Fáã õ8w1F™q¶V`*ÿbµÚ À‚w«*Ø7®ç»T£øæ—„2r–xAæj³ˆg*v”œ±*æ‡î›RrÍÒíØàþœÈ½dÄpŽ”Ï©ÇôiîL—EP¦v@ïí(ùŽR‚õJÞ˜G.áéâ“wôHÄŽ(³ˆog! Mø çiT5!ËCºí.49H‚ C´dT©CáÉGaаf£ÿ\ï˜3nV Ð8'oû¿Œ†œø &F²-Wc£=¯Âø |}PI…@8ÃÎt­3Á*/]A‘ÞÄ7™{¸/B -¦Di6x¢n^rÌyкgÙH> .o×Õ¨ë•ÚªŒ0Ѧ’Ý™¾Ý(u/eÃPdÑÏl7ÌÖR ‘߉(å,Z—>OâQó5ßYä¢sH¦¸ŒLü¨È€™É.ÉbË=Ÿx€ÞŽ@¤Î×|«ºh‘¸ÍýhÄ€Ô¹­#èSëÂJÀN’666¼¢-êÅÇq¡œ&Àÿôö£»3õ k¨È´ å@‰™äòW‘mçxÂ=¨™Mðh“õ²¢4ˆëã)ÈG3ñN`&UÉÀ’¯ã‚õ>ƒïÎ]–; °±ßeûïñ>,@¾‡Ù-÷_Œ'a“H»cŽžÌÖÁt@™œšûÑêo­÷ï2#tâpŒv”Oµ"GÞÉ Þû—Ú“Ïÿu׆2~st«Ä@Ei\{æŒ(.Ç:þ¹elžØ¸Ãjî2¤‚~~6é?ŸÚÊÀN’666¼¢-êÅÇq¡ÏÓÙ\*‘PÎPš%eŒžQZ¯ FeOÁw2Ï–”YºþB#"á¼·òP¤OØÄ°ÆIw‚~°éX•Ãy÷¸ú|D C|·Fkw‡•ŸöJù¡.¿òÃñ4y™^éO,ø²aG:qÓÙI’Ü>0AàÄM®âÛM´²:#Å(óÉŽW¾™'Ýïä³g³v1V¸&ˆ¯ÿ;^_Š6URÎ ½éÒ<@>Tþ7Óá É!AÓ8Ê×þªáT < Xïc1‹qlãýÂ=8ÁÒF®,2ÜÌ+bRvg]Íތޔ_b…{'HòhÜÐ5oþ¿otáO.°Y°a(xr?»×ÎÅhÐÀR¾ÀеcÁŽ~»(xC 9ÈPß|ŸZ¸¦l ÒìšIè¯ V¬TõK:^Ç‚ ^ÔÕ±gFÔ zå)¸3óå[µô·í…>JÀN’666¼¢-êÅÉ?×ðiÿUÅšÁ‰8ÇáÄ’<+}CÂ7ð$ÍljS- „z$´€-G'Õî|4isÉúw§²fP{´óZ:Uc[€½µ#µ9‚&£÷Òà¾iΓ[}Æ ņããÀC¦ñuÔP)¦¼‡s÷ä;ulìgºU?¼–FJÀN’666¼¢-êÅÇq¡´J`>óÌvÙqæž ŠÔ/~ÁZÒ¸æKBçQ-cSÕáeoí¢‘å‡³f­˜”m§×g¡$ÄPÔJ%Þ&ãøéÖÑã*ÇÐâ¬im²úð¥D4µõEOìzãÔ‚ÑV‚H±K‚ª¶ó•g‘’‚›iØ8†D@\œ)޽Üj„:¨ßW‹?”6;àÙ½}ZÊ– ’Û•îäZ c ·l™0ŸÕcÑaU±ªy,t÷²F³@²†Ã))¼E·ôÑâüógþ¶Z[š¸Õÿ³SÜ/ö?zˆ¢ÿ& /oc¹¿¢ãÏ÷bg(ŠÀ‚ȓΫƒfµÐ½äsxõw5Ë”#ÜYQ[ŸúžÀª ÄÒ©åÓ.«§7‹míÎêT(ïµ#³êmÙ qÅ4#ÕAÙ]éª Ò¥ãP¢x‘úãHnA’¼¼©ð±ó™‰Î+9$y×N%‘ÙðÉ7¼).mUÂJ܈«Þ?O˜N©•úõ¬øU³eIq7zïõ4á»;aÆ y‡~ª¥ú_û_/ î+%ˆ?×ùZ÷Ð…O&“5ˆŸÜsÅIrŒœ±*0Yˆºݵ]XJßÊ"1Û2Ì< àm’ƒôé¯çqŠØv¤cqãYP½%oÄs뤙k_X\,^NÞúŠ) r¹I»€&8*Ë3vê?{_ØË4ßÐaßÌvÎÚù»sKÈW|Äiˬ©øÍ¦‰ž‰­NÉNòË£Îî·¿j‹•El“4™cMßþc(Ûw ß÷ó›WœÓ+”ͲWÿGѰ³:·—¸:8Î6H¢;–ŒÖ,ëBÒ8üS/ÎÁ¶²—ï JíÝÚÅ“X¢?:U~+ûª±T¹/Ý ¶“Áy\¸¨¤´„™«È2 ù9½K’ÿKü ‘¬ØK¯~ç[þïfE0Zì‡.°SvKË\}i=¶’Ô¤’ÑrðÝع6ãÀÓ­´#?WÌ»šÃŠà¯é-¤lüØ__ ä$éËBúOŸçxã¤ûß­ç?[~É ZOueÚV@–ðyW AâýsÉ<.ÉLFÔá$1ùyè”Y½ˆ0pU#¶¶Ñ€?ÇÉv¹€Ì(^Œ¶ê*L vÈ)åêþRí6UFQ"¦›²¼‰{”¥U36x²4ÖCÆŸQùRAÕ¬*êfÂoâ”Y“hÁ8<Ú7ÔŠ´·J­)+ÔjiD& ,½ jBš'Ø—É»ŒgúiUàÄ-ìÀŽ~ߪDvbrz"î¹Åü`©¸†/è §D!%o-€ÖùÎãNÿEÌCär“«™z(0 ò²,•¸ˆÁ4§ˆ-GIúìþç—†µ)pîêÓºÀ|ðêt<¿7PÈú,é³dýí×â“Í€ë£æéÀ@.g•ÿéW'D ¥Û©!–n ¥¥Î'ÿ1–kyzHÊèàb&é,î°FsÁ×I I¬ÒVdÛ‡ºø¯X+¤¼W…RÐŒ\.¢?W\LËb†o[ð·–"Í)¿3€ 3Áñbš¼”ÑðŽ¥Ð‡„>ÝÛœj#žÀTF™ 0{…ƒEzÖQK'ó¦G,hÛpͲ2ݨ8 8¢8›ÏåÇÙfÍ”âÔ˜l1Èä³ÿá:Dˆ-ÁìHÃ>y[ƒq5F/¬ïyvàÈ/¤KÇ¢ÇìxWa­”ÝC±€"]½PYšñC>s„ ¯(“œ—Õ«Šu?8Ôþ=åÞâ1Æ|ïmæìNyÓ¹u÷rD6İ…XLΦŽÝ(Asfâ¦jhBteyó †Wá*Gð’;ÐÖBµxøþ{pŒÇ‡nšf&–4çe ?¡³_®ŒÊ·$NüÙé®õwö¸‰…IFßE–ÎlÕUVZmz!~¶SêõsÃí¶ŒƒPOvÃxhÄu^O«(¾²¾ÖZeß­’Úkyøán &7Û¡]nÕ‹–ßjS@Ï#b©ÀŸÝbŒX{å"‚Rª®¯¤A-ܱ56T A$œð÷³·íåîé!~qñ÷³èû„”“à€_OÆ:)wP†ùèÑ>YQ>AU;5BLñëŸ3g,±4èÑqØ«køMûòà¢,@z’aK ç±6ÆãÕýk™gÜ{Ø%¥ è§yÇ'Ãñ¤ŠòÐ~ˆPÇ$‹Më¿i‡kâ°ˆ¹_Iú.ºÞ‡¥„Üq}&é°á¬ÿ;Šü0/r…ÚÙ–¸YUÏÓ^ö*xñqÄ;Nv+S ͳD–Ê÷,‹Ã[¶>"DðhrY-h©Ÿ (:Ùë©ÍxèjFðj…—ôŽäé:.Ãéh¥—E„¦6*ýë˜Æö·SO+¶¶xˆVgåÝ UÍâïðþô„Bq¯Ì{£=¯_òÛáE¢2¹ÿv0‚ÓÛÕç{‚ 7…>JÆâKèà´W¥ÁÛž±,î¨Â0ØWäè‚°ËPÞ%(̧‰ZX•ŒÆþ`¾7“>±›¢Óê—È–/î_ýäã#0-k{s’` }©ïu;[;Æãÿ¥µwsB*xLL†Þ¢ÎíaŒO’;mœÃ&¼˜G|Qáv-a¨ÝHsïkŠB.žoÆ#ÞÄŽ '°;|¥.Ÿ®,*Œhe§ƒÏÂ}>“l I ƒvõ¥$‡þ‰<­~Jò%Z™bJ†âfÊpƒ·@ =¦ße£‰ƒŽB!#×¥5–™s<¦W5Ô³Ò˜WQg–­‡Mçíxcœ õÚDH9–¼ k}2!qß¾ò¹F›þ{­—°Zݬ…Ž\KrÑêÕQ!¿¡)D- Œ§|TH3¨¤ã!­wuG§„ˆîÒÂAû‰§—Âÿ!6ìû™Æd¾†˜øNñü-w¾ŸH`2)ŽÄH€¾´Š¾ZD‚¢‡ãƒzÎ >{$«ª­°ü5ã…›•äy©÷¾‚V1¿Ì¿ì³Ñ™@O.iY’šIYæu %Hgt;ä ,Ò†º©•ú8Ø4ýª¡=ýÅë‘Cù̉`sÉ¡xªÒ¸P x;.óÇ«þ?Ú‚õs¾I{úqé~KŸP¶‡`â¡9Ârݰw4R9kûš¡@÷ÌRsð¨£7&ÈSY‚UK³uùãÉšÛµÑ\×âGÕJþ£áQ¾#ä-ìì„°1ÈèÛ&Y#qÒcì¾Lë/‹/“ò’èówõ‡ÆÞðZ…«ÅR¿ÍÞGû\EXµñ€X"˰¥®g#R‚–;ká£{Dš±©5ÓS‡»bõý¥îÔŽÕÈ^â* ¯÷þ³:rd5Ÿä59í´'‘7+ixu@²ÙËHÜÿn‰§FŒ ³÷¸ý4>R¶BÆZVÅÕØ—Í0ø¿¯À-U9…ª^B×P×@ÒâæÃaaᨣ^Œ¡²¯}‡;]ê´À·¸šù¿mûoûhßÚ™ïÚûhíût ö½~Ý¥‡ÃdøjnÃóêª!òt·'ÉÑ(w¡t ÐàîåÁðôMöº ϾÞÄ¿VÊÁv.×öíú¶{øm¯ª®ý»í¿n¯ßU+ëêxýº¿nÝ~×oÛ½¿·Q?m±}T-õ9~Û öéßíÚ^}V-öì—}¶üúyõ7ßmißnŸÿ,ú©ïá°ßÃDgÔÕ>¥Ïá` ’þ/ö½ÿ€ïÛ`~Ú3ß¶”ýµ÷ü4/ø<_nÅGÏMùÝßn­kêZŸ?K2ùú‡ú¬œ¾{]óéN>}A}¨ÿ[²ß·¬¯Õ©3äc|ôÕ¬³êÙOá®}ªßÃd·íÛOÛ¤ý¶ßíÒûvÏö£ßnÒ_n¡þÝ3ý·—í¶ÿ7Fn“þÝwçÔ­ü6~Ýhý·~ý·ÿvé'}º…}¨sêZþ‹ûtfú¨ÚëûjÿpÓßàÏãþÂçß¶…ýª>ý«Ÿ¶‹ÿBêþ ßÃX!ò;|‹ÿCO»íZ‡É¶2>³‡_Ðv¾·Ã伯á®wÛÔ‡êÒØ-¸:÷íÔ‰õkŸðÕ/¾ÕKíÑíût;öº{ö·þÚǾÝ3þßÃ]ï¶Äýµíkýª?¶’¾Ú_øjO>¥íÐÍûlŸÚÉßkEöÓöÙ¿ÀâûV¿…íûkÚ¡}¨ßÁ¿ø\ŸÁpõŸ*ð"Î>^²ý—À~6%$r”$ƒêŽm¨=xISugÀú…9»”õe¹þø„÷G™s‘-þ襳¨X}¬…SK÷ʹ7@iCw[B§MTí ?={Ë1f¿e¢Š†Í IÇ×6iBzˆÇe…ÕåÕÇÒs-ljõ"èh~§aïÆ[‰ÕñôÁ˜Pbx¶×E“O?zï»üÖvúJ ¡JDâ8W#D¡ü¾çõ¢D5 /Ž´‰Œrú¹¹)cR>Éð %¶úë²Aᬆ¢%±Î˜'É_-^.X#/è,Êã @Qó4j„^ºD_aVv·ºÄëŽ{r‡ì#m¸Éϵ9–@+¬¸QŒl§¾X5ú‡&ßž˜¨›u ¦ÿw|Ó\åC])GĈ0üu Ì~· ö©ÚÕg63g£Å}s¾:5¿Ö&þÉù2ÿxŠã±g>¸ð—\*(A‘odÞq!”5¯`2D8š¤ƒläÂÞ`×^•bçè¿Ö¡CC8 à«$ŠUï$æ{¶BË0FI¥ñ:‰¸Wû+Ž3-ŒØ‡1¯x×õæ~K>Ën•?‹ ݯHÙ§íËP–’ò¤ï TŸ£@ÇWG™>؆QMu.ò*º9•dÉ·ÁÒ®,‰>b…¼k„ Ý™dcÒ`°N“¬žB# ‹Mo06L‡äq½å ¤5y ™HR™ïÁñü¥_í"©D†Ã!üY\û¾†ÊÂìÉïIlÐpH±{ìI‘|›møÃû¸¾˜AÚÑÄ×­[ ^ÿåOÑWù›L\¡È&ï=‡EÑöž%QYè ¦°8ƒpV×΂¹ºY‚À­dA™éÒE’­½òŽ ×¥¤Ý ±lÐzC|Ë»úQIèñûÍÞçòŒ÷9`rÇq]Òø:¢èQ²“\Fª«\':#…«rUÙZLŒ'Â@£þ}s`Qys”¬¢U¦ i*óõÏذ/ÐM¸ÕÁÈÓ¾„®Ò–³°\˜ûµˆ'‚óG.“GQ—óò޳?þ§îŽ1»`'ÇrI? [>I´“]{˜é?ì:]6M[Ÿ½.½:D"h¥Pe¶gt›†×ÿUÙ@?ØéùªL„))šw z² ¼‡Ê•íÔŒV³ßâÆŸ’"|~¯£øNí¥G¤ô‹Ýì)2Î7Ú5í^¡Ó''‚[q(ßž8waCÑY 65Ü’Þ§<ÛÈ@FÁ>õëÝ[Wµ*:‘1Z€mäXƒÀýf9Ô÷ ceF%ò÷ˆ¨ˆ<°V9TC Ätݺä®ðef òµ¿ÂÀRG¡-È ¦"? ¾O:ò$¤ ÙXóà}`’ªâľŠf—ÞÂk6%ªñ<«Íúi?Í’‚‘TË‘P¡ò@¿ôª&ªBº½`9@œñ½3¤¼1¥¡ŒQN+ĽߖM±—ÿE;ŸkÐÓkÁYÿ`új+Æ#Ò¿ÃF”§ƒ0YÔ›iN^<}€m0Èñ–¤ÆÏoÄ`ŒJ49z È’%øsäaÀ³³9 08.…{7^Ûi³¨QïÙé¿Á—>äF<ªÁ.XÙ÷½6·ffð'ÆP­g €I‹ þŸ*ÿ÷’ĶÓ’Sêˆ~½Bs:r™¬øÁPü).^¡y›Iª¡Øçr;͆"0ÒVx{üÚ‘W£Ht½x3k™xºm"[{oÈo§|­é)­ FCOô€ºlî óú3 ”õ7²5•Ü|y}?ÀÂ"A'Õ•îK[ßD€f™Ï {­M˳V_»£S# Âq]θáá§ ­R åPAÇËjÿE®ý2®À"]‚v9*ÍKg+~Æ?ݪør D{R6sOð%R)ˆãÑ×e î ß2Ñ ¹%nYn4˜K} ¦=TgÞtgÚÏüˆrÎMY6õ`AŒþSëM}Õ2ŸææL0à9ª+Í4Z™>Ë ;ÄF§®=>ÜÁœú£ o*ø˜,tþ°4—¾û—YL´O6CÏŸµlž, ëƃŒuDöɾꞲæjæ,|M.?ZÇ1:„Š#,†„{$Y±ûÒ öíIÐä$Ä%¶t÷ƒ›¾Ro“"l©Ä½Ý¸ž/6iˆ%L1z~ÄÓ@AP­÷üYýä¶|¬J•Ù>öR¨D•¡YŤéóÒ; &œ Íÿ×ì_DYŽ%ëzþ»ÿª¦èyùgl§š çÏ[…à Ä}Pb¹¢¿  äh«ì¼$êé@‡~n®‰\%µ¸¨Xr8;Õ³h®Þp|Â')¬Æ—xŲNÒî2YrVphP.Ö!FöÏH…}{Â}“ÉÿSŸ¿°ýsk@þÕ@DäXÜœ¿—¢ÆÓáÆ•ÓQ°Óº;½üƒ$H=æ¾ç| aÜw´¨±yß|ç$Ò£ºkp&Ôt±O9áR™ûeq;ÝÆOÁÖ¯ßëê¶ðrð<$(PÚ«Á*Úw$èà.Z^b–IóµIˆdsëu:93R5<õU§|¤?ë<”µ­›óØ $9v?.·ÇÐi¯[‰/XO8+Û!#ÞìùAÈ·‘1I~Ë]Q•w*Kh…ý#Z S¹Ä(ïQ‰™…Œh[‹htÅþ«WBÙeº^ù]|ï³M\XŽvŒ÷Ù9Ï*6²üÀPë`Æf4 Ì.‚¼\{h±Åpø_¦µ·ù3àšd¨ÏžD6ß ƒv›‰‚OAËÔЇ ,\Sç ”øó…EŽjnåÖ%ri‹ÓŒ±‘™ƒ½8Ê7PqŒ›Sé+Žò?Ä 8¢Ž´°Å#ÝbL‰øþ@ß…†éf²¬Q˜Tð…¯ÿ{&kÿÿÿ¯5iÀ±šiAYãv;ÝÎL|/‘…ˆN[øE.|Õ@á>¯Ù"˜Œާÿÿÿì³³g‹°9Yp™¿ô*v¤½>¾óU˜RÙádŠ~þ¹ÌL–É«ýÁ¶1cÈq#iþ?9à÷4Å-½#¸©Æ2Âú# oˆ:°Î'Ç)ã§ø¿‘@ï‡lÇ¡Ón lbA byí´eÇQ»ã4ÎÞtó»éBDöh9}L9ù1eBUuD]†SáÐR}¦òošÒ8¦B•³ã¢Igð†kj²¢Ã(µy‚9¢"=¶]¥¦[4ô¸Õç^â”#„Ež©A…ÉßÓ£»t~_†- …²¼Õé}`_Cǘä\ßv\âøIÔ¶ÆÌ‡KjHž¾¸'Œ‘ý‚Bëfsò)¹µ›‚'Hÿÿÿdº&ï¬ !ˆp¯èÒµbŠø&_ëCõ‡Õ.@5®\û‚çí·òà?æÓQ'éVØ £æ_ö=àbñO9ßpPÄÜBúR¸pó˜[`=óö„Dž¼‡põ¶¾…ì^ÿAJ܈-FìÑÎPЧ\º!ÿ|9ÍPT”MyóùöL-¸#BÖ¨Óÿä;í²ûŽ­-qA¥ÊÔªbŸ†ÿp™@\Ó®D¿ÿ=!©Í'료N©llõÿ~~wðŸRVWŠ!&±ÔOÿëͧÞ“…¡>´€ÓÊ©¶‹ÿÿ{+kòÏp2;’q/¼ú¦½©uº¡zÙr5JwjÁQå º^2¼$¬¯Ï àbýh¿@ãhÄÕ‘ÕQ´j4¦ÆçÂFã²YâåÑ41[°RáËKv¿&>±“3úµÛYÿVŸGþò—þè_åÃ>ð$Öç«"j8—óÖó*'eÓÝS‚|i)WM‘Xdá¥É¯œðƒQP\áÈ“´&Šg‚Ìé„å-пÿÿÿÙF³ öV¿ùßµÓ°ù÷…(Ì—¨0*»6ðÓÔ %"òýë‡ Ãt·k`ÜzÇöÖ_žê³–OšåÆRb)‰ê)6 %ÆÞô6Á‰XýHWÝ/ã´£Ö JegázÝ yQäx%/ÿÿÿÿ¬œ¹ÅØWéáv -ïúàÃ}öÄwÓ½Ay’J£&æÂõúà$EÔbž‡9ÂÃÈ"áE.5m::ô(³¡,–”žÿ {ÞÓßw¢+·Äª«=ʘqÿFÚÑ^Ûÿÿÿz¤AŽº™þ€e›MÆÜ"q!fCœ2?ILû4,Q›ÿœ>1Oî{3€ý€ò†p(Ø=‘‚-éä” ÜûGÒ}¶Ã±ò%çÚ‰ü$×” Ÿç¨C†As3a%ârä ÕJ8Iiô !»øÉÈÄBMJ 8ÿ}º^逎Óþ楉 ›3wWæ¶À ´Çª?ÿÿцŽÀ¾V¹hNqR1G†yI߯1ŒdÆ1‹WiüôYyÿ¶:­´0,¶uq䶪۾-e“D.‘x;„Qqh8ªBøÂu ¬;jbÆ–léMu€B¹Ïöä—¸îýD·Ïé4%ô—!¡c’˜:§¢ßÕÝa`õÉiÎJKTLO¢l¨ñÜÚõwµ²€ÃÔW‹2Ë?¹  ‚]ÞÝ ešã1ÙåU‡Þ-0Ø xÙb_CÓÞê ›zõ1pøiωR]ÛN¡x!ãƒjª¯+= ¬Ç׌= Ä’KÕ+åüMÙª4û® ÿ'Æml©Hÿ}Jß[ÉŠ±µ\Ùª‹T« »è±oé(Ò=YmÐPøÄŸýL;Z”ï’YBdp¸Ì#QæF¸löÛ'–PßÙƒæ !FîDܽ/ÛB5/¸Z`®Õ|ÅÐ É<ý€Œ$WzoÖ ÄÉÌ´¨„([Z÷*š¦GÂ:EÛ¸ÊAÓÐþ¦yxÅ­s©÷ËÚ Öq³<²ÀJDê‰`bÄMê?ú\KGC¸åêk¤ÏÛ¢“ ÁH@»¹nŸGôFÑÙÓwlÕÞ;Ç«¢ }ú`$²©3È*Ç™$|çgüÆàR4™Á2ç!¾tföp‰÷hØðíKî ¶íHÖ*ó'óx"“ã&cµ–ø2ƒgL´wT:S˜`LξÎ<îq&!§l<¸á]Ù ˰¸Ç¶ý‚³ô@nh}O·Ãè’!Õ>ãqž¿;(Sä& Š›ªWÉ’^É©™OÐ0ƒÔŒóÚÛ¨ÿi³?Þ£Uüo\žJÚÄÏžã,íÑ(pЍí¾{݆“¨]¬Ín=bšFÂjµ¹‘ ]Q'‚?j)•¥¶x¹q³0 À´’:V°ÂrèlMü`šÛYóõ5ä•gõñÞÚ(šK§eM ò6c/ =+ÑA¾bü2t“ŸaëA¨AFPÓ5|ÇIÀºb zøzîÎâ ;O%P‰~ óÀrg¥Š¯ÿgç6ó“*>‘‰„Úüϱ& à•n†€l86µàc[s`‹ôÇbF†Ö]eD—‰*à—9ªÞœßÙ7ùŽþ–è«ÖFßÈù}TÆâ ¥¯š\΋’0‚U•å[Xh¹aŠWÎCªð«–ÓÒ·H!^Ø‹ø_íPÙñ ýöa3§Ò.:-\”„MNpù2ëaÂÿ2€ úìÜy]Aû=Tâ½Ëol5¡köâï=¾vÝⲩ4iDÅX#›ënÁö-ÐïÏÚ›¾ˆËÕ+ÕàHap- 0|Ý%\¨N¢þ{§.··Ö'¡Ö“Nу93@)i‘›©¢!ðŒRåt8®ä?NŠØb®D¨s!¸· ªÛø_Á÷(ŽÁN 'B¡éJ/­æÿWOÊÝßôÁOÊŠeÏuÍŒKù^¨yÞHxõ0'Fª:™rõ„§OûײÑë–Ó³A²»L…á_Ú–w\€Ç‚Ú@¨”ø|QÓ/¯ õcÃë+µFȧw$õ X‰®* Ž~µ=%í>öñ/]g µ+L=Ò¬'T¡>T¢=øêÊ-,~ ‰$ÌLõ¾Jft|/µÕ%Î~+ð²º,¨ÄsDfÍ z.ªÞ­3ð2Ñ'd_±ÚÁ›! òžà|Ap grÀ,ôG Á ì½wý°:²)ô4˜)±àBzD_HŒÊPÏcV¤Ê-ç0ì…„¸0-âJŒAØ`)ò[‘ªøRØFà´.ôÁb)Àv}oüªNË©“óZêc0Ü>uS¯É äâà’€ÃÐýÛ\³¶ÿÿGÙßý­¯Qþ¼ÿÏOuíij¤7ÿ”5„`ÿw•öÁ<Çÿÿ`è87pÜnÄ4¬VÊ ?Âk›]-žXÀ0¯ÿë>­`×Òœ‹_ PôCô²¹¹2²-sZ•¥%êÏË+O'8Ô5Nù‘zëêeoÿ~fÛ‰j^5^´jˆæñ¬ñ•d={t!Ûõ+º%™f8ñÿô`Ô…Ç%ÓÜÔ {>äw^•4´]›ßÄÐe(bë¤HN2¦XêòÆ-„þ •÷ÂÛý>ÃÔ¬„>Ç$è Ö#ìF°0• µS¤\†Á.zÓÓ[_Æ“ƒH0CFg«é©ƒ‚Ú< ½îO9méè‘Ë7þy 笌CÑš?DòN ˜ öß\è ©‰”Y\ÉöÊÕçTb¹› 1‹‚è!@ãiA1¾#"é*?‡!Xø ¨:Ów|&þÍÅè}—À¸¼‹‘PAW”)½Ð6âgƒñt&GÓ̳:„­±ì€ÁÀÿ*{ÿ0¶â ”^TÒÑg7Àãql L-¡YL‡œ²aîo&TJ}ÂMW·×AðÒ/$•báE"xí›~tW0jq¼ì±a¦ :Ó:~p¾¬šÀpcý‡‹ïÜfÆóLÒ°î`©¢ ¼ÅHÕLZ;ÎR““ñÿœú<ðÛÙ-ƒjP‘/Ûít@& vÜÿÿû5$˜«Bø¡> V¸)!—·Òÿ&¢´Î3Uæ‡Ûï“AeNVë‚“‹~ .ZN2·odšåÑœÉ'A nÏfMíµ¨½¾&X6:8î|HiaØ€‘±û±Çeô¸§êúà•n½–h5ƒ"¸Ò¿·¶ŽäýÐN? ŸÚÈ@Çß¡Ü#¡‡´t´å“0GxÁ8õôL¾àŠ” ν¢„€(xAY¤Ø”Œ”›ýL…U·iœ$ˆï„°$Z…2Ô ó1=C¯ù³©“H³SFÔ-@"µ›£n)fe¬ÓÛ\ÀÀ}ùd):kºµfw[€òÜ]í»%›ÊäY)ÓÁULF§I® ѵG^~-_Rm™²ßÓþ" ?ô§’`|…ñ×ÙÊŸ+~¶WXä©L;ÐÄ"‰Wx‘Ë’ 3˜Žé—¯r~‡\9…$®VÚt÷ö@¡¬ç%]MðD¾¡£Qê®×T*8Ыƒ©†öt]{ÒcÐ&°a‡±çu'SnjÔé=]›m<Ø¢–4×NË'Ä‘£k¦Q¬éÿ`¿çd‹•ËÙ›¾ Ì·õ¥¼$Cçâvd.’Dm‘ÊþP€SlÉÔ– §LÞ·?! ¶ÐÌl>ä‡ÿ,š'ÓuBtW•9¤'‰FŠQ>ŒwÖ³Öä„Ñ ^Åíþ:D ±‰`î¨Î„c’Ew©b  ÿ:5¼T5Aà+©ëöœVøöÍ9j›Ñ(Ïœ%qdYÜÊxÊk…ŽS鸇çÃÚ€þ>Ú$}¸5·Ír!xÿk!ÕSqp}‚ykj?¯ôqU³’"ñhTîÂg4A§¥µ“àVÀ{ߊá\Ê ?ÔþUß’bçísèت•Nœ^Û$Y¯ú»—}Ñg³gz°yÃk]%+(¶/VýŒÝþ¶G1“”ä«À¼gF÷Ì LÈ׈‚sF–]$~j‹[«›~o"›œn=šo‰ü .œ˜©ò¬4Df:ðÙ[9ÇœV×wFycŠ+ÿcá AœŒ!u`Š˜#,]”Ê6 3¨u˜Î(L3ÃÃL¶ãõv‘Ô-ó—~éí€TUy1ÆÝž5,$*¦ÌaA•\…_Lùø®Ÿ_¦µ·øï­iXw™…°¬Þ~¬o™²i3œÒåü¦+„ì ÃTñ© ¨¬ÿwÿoA¼Ô‰G÷ZÎZµdműãÉûëO¥õÒ¹1¶&ågY·Q†ü¹‹N09þÞu‰SîmçÐi;ÙÛOfJ‚¿rÛ˜m£›”}¿ÿÿÿ×c». )ïtÑ›f…°¾(Cž«ÌZ¹è_øá©¿ÕWÉØô iÆó›GÕu×N/ÿÿþ ßã[·Äh…¡É9qêp0"æ˜jläÿ¥N&´RX°6 5Wp€# ˜"}ñôQí*rW\éI™‰©ˆ*$N'J+Ö‰F ·È{aÖZ‚Š 'f–m(eć›äàEÿs> `Ô?­}í/§ù-ÿ1r¡ºÂ©…W–côÒÝëoaqŠSŒiž[U‡ð·k‚Øftø <ª«GòKjpl¯v».³ø`Þ@Ÿs|IAU·åfȨI`˜†b˜˜gš¦ÅÄü—  }–;Åòý*U%ÜYp°*` v¯i{â¶)c¯_ËE_Å ¸6X_]|½¯êy6Zx\¸  ‰C'6ù(¤/u¹“+L›ÝÛ­ô20›¢|0ÖŠ|žf­feêÉw½ ¶D5$ tÁýÈ6@®ÚômrÕLJŠf†‰ÈÐ6²çæpg•4ã„ç}"S…¥’Dyü+(^„øSxóƒw€¤®×Ëïž>d°˜XŒ¢E)"k„XÊ£>dd]8ÞlôÛ…¦ðòI¯07±G4_›!ÒÀK’Û·˜ÄÓ¦_™·äeüötÒ-<2Î/ 0"À æˆõ¡’·'ð’Öù„ÍŠ€+äê-ë¯ÿuÛÜ SÉÿa²…9…Ç噡ÿÿ~ˆ<—"Ç«ÓõÌÐÚM1àfá¦Þ£,û±Ö½Ü|³ÏmÂÍql/ˆý#ïéíñFnÔï™âÞ2™È„7/ž\ £Úòxù˜„tWƒ»?*Ä|id%iÄêŒîcõ¼QGñ òWáÀB/^øû‚fAü—ưù‚çYËœ²Ê›Çˆ"ËßžŠNÌfÅæQÿÿõ Ëh%Óòt¬ö#óV=Aã¹°BŒØ§ŒŠJ3Sù{{ìµým°¼§î`ƒàÒøç'ÊT»Q=«"/zÏ%‡¨YBHã1ºÀi^¸/Ãè¥nY>z³×"3¨m™8ô? A@E/22§¤tîkÄßf*Ïÿÿÿy|[F¨ ÐÌwUˆ¤¡DÄF*˯©S¤©R­®x£G¹¢Zö%3òNkô!šÒú©m’±¥nAݱµQZ)E·ï¡!)ˆû?Tœƒ°Ýs4y%û%`íÿüLpãånZ¶Ò‘U)Qy»@düHHà®§pê Y/n«*bëõqgîi ‘¯ìVßjoy´E„ÊN¨ÖÅÌh5Æj7R`ØOÓWÝó|ß7Ñ‹ä:­nÿZ$ÂdyjçÙ¦ <âõDŠÃ¢øÜò;àî]0¡ÀÍ™ª›®ƒbå ¶ÔˆÇ9Ò1Ô²Ÿ´(™œ»ƒá*«ÊÉÿÿÿój=e¢ŽÍiiYñÛ>Ž¿¼ iÃ0Ÿn×:ÂKmfÕC&Ëx rþ{«ÎZ¹‘Oˆå«]½ØØžóÏ€AéÚåkKþ0vùUoÁB&‰8Ç"ö·#~rx&…ϸRg2; ÛÕ0&ßßU-b!¨:¤– P·*zˆ‰"ƒâÎWmý®VüMTB^êÐ+«’®ýZ©µ,Ü`uenœ~zCÿÉãßãKª¯+ ±®2W f'KqDoKtŽwø‰/âšqxu¼¯G²_†‹aHm{œkyº»rUkƒ±Ÿ?™Tƒ4%sppø§Fú³¤* á莭„W³&N¾ÐËvbÑ^ñ ŽlgwRo¢b¥fv8«™Yz²k­PѦ [Eóü?Oé@´Kwòd-WH0þsIÄß/û^ÏÓ‚jð–ÜÔµæa_mˆ?ßÚQ—9Øô¤^—¹É7}m~þæþ›ýäýþ=p«ˆPäaüx]¾8/‘YÅ¡‘1ÒÙ>Ê+/®Æ°oS{Ü'ÆYn²ÝZyäÿa7¡Õ Î·!Éóòššƒn`7³?œ>1OíTÁ Ë_{>Y…`¢ÎôKÖ%Z%ÂfZ‹H@W¥}µœQo;wxú0`yArÐŒ›Q12¢èÉÈTs­{Ÿ*VØnóoX½Æÿ!ôa9¹®Wu~_,@•ÀL•‰‚pûÍ7¥Zà—Ãÿÿé¸5×1í®ü)=Rõ’a56ÉïžÇç•±ê¶ Úºçþk•D~ÒÙúef{ˆw¬Á“ä zÿ~mÇ%$,™ô!®g?«–#Gs.ƒ8s*±h9"œÎŸ#t­vZb8]IÅÐ[ªýp*:¨®õ§‡QW;#¸‰ÎK2ZQa³’Bïg­pä õ.D$~GÛ¡àSs:ššvJÚÂ1ÄX…M4°å|wä?°Êá1Ÿãx÷š2#“¬/H&a¿²ÈËLD `ùÍIDBjŒÑ‘·x¯¡Jº\ˆ“ }Fy4R9‡R¨]ÐiÀ›D8åô(‡ü¶~)^%ŸÜÑÛ|¬-J”öfôÒqµ·lâ:mh˜¼‘ý-H@Áïõ·¨g›Éâ}¿æW†›ò<ã… "™Ò*›¯¬É½+²ÊDƒç²aY°–Æ5^4d5¦WTòÝG*²Rˆj!AdG® ±Ç™¬}®Û”yI^ úô@ã;Ïa¾d?Å iÿyúÃ&Ä¹É YJ¯ý$Ùé¼ûB0¯ãÖª+sÙãä*bÔ9´@úÂìj%I“êPñhØz#AE!LWƒ–¤B6ì{Çwø IWÿB´öº²m ½&Vˆ²È& îè¿b·vÒzJÝÚ ïX›Mú@Ý›•ÙtèJ@ ¾ÙÝ$H$ }\4«îÿ0% Q´¶iøg­eH}x!e”KvXÔdÉ 8(þð8¬J´PW¤„V} 8(`ÈXC\ý3…á}Ÿ`žÿ/\©˜•fuÏ*ÐËDì ^EæÕaQÐlVxøÂèD‹KyFÿyKn?‡Æš_Þ¾ézF(b'òèKÜÀGá(å’ z(Ai°Ü8ƒSr¸ó•ÇœíRG=É!À/ìÈò Wê”Þx4¡°" úÐ; 37q5bׇ•û¸N]oW,˜¡ô5‡¤HÅÈR€‰¼<*ß Šs’{.bÛü®„ÞõÖòÕd5}ñÆzïk+Z8ÇÂßݶ`ŽªEErXƒôåJ¹ãêñ ò1ú¢_ až¾÷óø—òYi°9k,_ij¡­ÚóÅæýtó[öÖ‘ÃŒˆ%Œ¡áìŸù³ÏÍÏÿw5>Äòb7.¹á‰‡ÚøĈ65³åh¿x˜… ŒŸÐ~:=ݹ؅±ßªfŠ"Áª#„pût±^/A}—_ _Í.¨C;û- ÑèMಓ ÄFÏ @31ðD,ƒµÐÝ'qÁ r„}zÉ5\‚r'¾rƒY™¢ÑÌÍO 3k°Û+€ÊÜ{‚sö ò ïLktðhyîÀ%M •Ä\Ýò(Ù'D9u…2 {ÿ’¶ß>ŸÿiQœ9¶??„< w¼÷Tûdk˜1h¯IA'Þ@$2R¥×e´ ½,'N?~ÍÉ„§Ê:ÈÉêîo¸ëêÑ˱K…†ñ™…Ve«t_ÿ˜JIû[&@éžÜ;£õ%,Scý°Mk{ !ø÷)m/.GÁN§™Yä.‘1B/áÛ¥ L N²¥ƒ­?Œ•?Ò:íT¦?A'•U¿zôÀz(þôW øj•X¾?dŒkƒ5p’Þ_ÿøsŽ}(]Åþ/‡•žø’¾¸q•–H¶Mè-ÍÉ4†šª=¡kówU«\p“7p~ça~.m,=C“³‘ˆ¥IM]»ÎzV÷TÈ-|¼IÃûß݆ŒaJhÂB. @0p?"2íë½Ð¬@w›RñÕýزÕ9¤[Êüƒ­£‹†ù¦Œ$Šk„|{ÖŒF…ÍÖÓx®Â8Fü”„àŒd¶Ú$¸L‰,'dGŽÐX,éE³«k›e¼Uåååë®a3—yt‘Ë*ôš˜”Šý3dœIÔle6î/†Š¾¹¥0–È1TßQØÒëâ[å ö¸M³ ‰F»ùcbî°’6ƒ€a=Y^˜çÎJ,Ë[x} sÎÄ7 ër³lÒÓ*™’PI ”JqÏuýY ~«ŠâŽ™¡¯þ5¦Šfež…K/–Vº4ãµM<ÿ=Ò+ÚCy¥HZ$ÎO‘n–Ae1!¹^LX®l¢¨ŸèrM¢ãÊ pý£ñ6üâ1 °€,0#eMßî!~JtBï2 Ì-¨è{´‚œb ü‚S7(ÝúWr¸ó•Çœ®<å‰ybÜLœ„_Ò•$“[²Φ¼P8þµ_xšJ€t| èÚpNtÄùDd‹b ³›8ÒE©êÈÇ8’H¡•T9PPåAC•T97 „@A-È‘„u®åwé`y)WÑ«#öeÐ[ÆCa¤…¢+»hÿ*]+追‡¾dŠ›×°«®üBÙèS°ÇÈvŽÊ¤Ü¬ŸB);+Êl±hn×t§×ˆÕ ­v>WWîDj¾mÔÏæû<Ì€MHc4Þ@½Ï‡ŸÏÓµpÙ¡yîë÷¾ð_’Å·¸Qúï¨Gz¯ê0L¥3ÀJÍjƒß·øO°GSÕ?¢Ä†J+\†zàðѾ¨@ùH4¯$[^¶}x°øI…<6 G$Û²íIèM© Á‚À5&Àm£Å…oÄtåeù=ÞÏXÄVFqu5LzÁ¢çí2°1|£ñ]˜ä˜J·û|Ÿ;õ* oÀoµYm;ݯG@SVµˆ¡>TˈCUĬðåìîG†x8©LÃ5_°_˜ë߇CîŒMä̼ÝÒ“óur¨Ô&®àu<¼¨Ð¿J ÝIÔ$ÜoÚ~„×¢xˆ\èâÄufyÓLpÓè4JÖþMYøVgvè$‰1–w«ß 0o]ÛÐ GŒ¿ýs6ý>ö_¥œûI»£ô j»„ELq_¦µ¶‘¯ oñ!¤Ó ΑÞ,ràœc[v^²!ô ­N?íg¡FÆ?[] ,á[vLKB7Á ·v-nKÛq 7#_šN}25¸ÎÖ[ä.1‡‹Æ‹¤\#ÃÑž¿ºâȶ4Éê{¬“•— å|»ñ¡ÒðÿµOÊ®#4®²s­‘ÍÑ9´›J±(NæôÔ>3üx¼ŒÃ¸v¸óh\ñIËúMËX¾ØÓކuJæêŠ#‚/ÿÿÿÿª?±°uSÅ5Mê&à_ÁœSCê ¸3…<¬FÝž ©«T狘A(FYÙ³(SÅc„{w²2ÉÀ䤢k gnrõ³}ÜæÁñQ³u>*õª6> Öÿx9ñ¸RÏ{†$3´°ØÝVúx6’ÚEÏmcB˜pDÑñÉTíš~!Æeg¦C—Œt¥&iè5*$·X»¼¬Ïä¸f³¨ ®¯ùÙ'@Øph*?öÕç'Ï“ÁÝOr³$¿*á'kP{*·„¦%Û\4¯á¯ô!t*s¡×”sY_A~CxÑ«jÄÇ/¸xi¥Í”¸‚ “|?”Q&ŸJåå5ûxa^Ï.ž™Úæ¤é/sÌ~VÆIÂVß:9Xmz/ÿí>|£ È\¢Ã7й‹¹iU1^K#Ëù&8¼SÌm=*5J:\ò¯’³§g"R‚¹Ñ¸ƒ¯Ïl̤r:À–øÓ;tw)8 oýãÙ`ïyV{wÓÊoà fYìox˜ÈIì:ÎÃxQšçç­G­žŠÄ ¥w7œ,"!º›~wIjR8 ŒmÙF6ì£vQ»(ÆÝ”c„Ä)#ä4Ö¿ÿY)×üF2å0(ëì ›pIŽì½¨þ«?âá”Ô+Ö‰Œðó êÙ 7`¥Ã Æmÿ:1Ô5b'veÂa)àbv*X#^ ©ô.²ƒ ´Ê§S~Ûî¶WybÓT¼`¬©ÛšbV¼–dÓÅHF§íf«ážï*¡}ǾX2·"µ©QAÈ oä=XÅÄkŒØë ˆÙÈó\tEɧ„K¡ô¡­ÜP&çTQø#ü ùºi[»¹ Ë=N T{5&“„áoh±´ý B©‡!ÿ5E\!<,ìoÐ b‡‹yÚŸLl/ ÆÂñ°êì°ò–ùK|¥"[ŽÖú^~ÁÔè p…ëJSFûI¹·àw_þfÝ0 š½OnX(EwFá-Á!¶ ÔKÌl½#ÆN´Ì^C:Ǻ—o¨Æ4Ù4 è)b¨ « %çÿ~7ÚP¿ÈvZÜ:–ñn Žªiaöܱîœá_Uÿ‰…¤†8×Yn‚¢s+Ч™GŸ)YQ‡Æ_ö‘/jdŒ¿Sü[ê!î‘Æ3\`xe#'ÒkwLTJOšŠÇgÞcØÇk a Àžœü.|ñ\­ÊSpåϺÔ¡s’µ)ØÀ>.ºj‡+¬õ)O°L‰ ‰PÐ W­qûtÓAÞi„Èf$#'¬Nj=±ù©Öyãû\Úü­Að«n¾ðÉÛq»ÇaJúõ4Ó½õQ‡W¶LiŠ8·ÏÎzù®>…ÏȹLë@’,ùÞ§òÊùå3]Ëq”DÔ«¯Möô X†3ºÕg6Êv—O ®-x4LÒ‡PfO+;į®~5í·¹Ïngˆ?•Í¿øÕL À½#¥ój=Ñe¾]Ĉýø:Ì6qJJLn¨"äšÙއ]Í,yÛMƒ‹ª£–¨ˆÙ}áH,I _ ØEÔ—+G¿2@5]ËnS¾ Éz'Þ!ñ}†ùS#àµa{Œ;îA±¢©f:=ÈS?×tz¢F†)Ù©;ìN+bmÏhˆ'»LXÂB»ö„y2o—ýÄð†ué€.žÙ³áS—h³rV黼[7bO¯4<ÇãuËþÝš|ðœºCáEµÕ±DUƒ1yL3&DÍé0…Ýi/¬ŠkrùqAõ?»t¨Ñ¤°?µ;€p-òC|IÇ*õmË4€yi¥–BXŒ§ÃlÓ„Âü`8 ñ&ÒÉöÑÇwH£¢IÁÛëåQ¶eCËæ¦õ¦`¨VÏ 싱c™k«Úp°Ã!ìåzu¼3ò\ uÀÚÀȦ`‚vˆM€aT^¤E€µo’˜®•øtk«ÿ+#ŠÒ|¦Èk– ¦ÐÓÿp—á>ƒÐw7ý7kÄX‰0Š;®áíúbˆÍ¤–ÏŽ^¸ÕÊ;Ñì}3‰Ödµwˆ»Ö–Ò3’ ËY÷.ÃNÎÒ™‡ÆA‘R)ÁqÒßÁ³…* g@¸Ö,×—¯P5`:?9iõ]Ÿb–þ?; @[Ÿ´t:)5ïQÂ`g϶4 h :wç¹4Ÿ¥Ê#¹tÞáPÔS¯•x<Œ©ˆ":>_?`Œ÷ÿOüÌ›pÈ}™sɸDåm±[c›<OÉÇQ½`±ÄgXn¼$x‘ç”ïGö`ëFõ5óqù¼Sº»)¨ì/%˜æ¡yèÐñ}TÚGq¼ÎΦЕư㖃ÿÿÿúhy7´Âý¨yeÇ•BõM çÀ1²šÓøµ†£V ËR¼œÞ*þ`´Kn§“"y\µD©–3î:Aô‰Ï}h–nøÇÀjÒò²ÿÿÿb³£¢ðçÛ0{ý|Á®Ç‹RÚ‰órðv V;v[ŠNVnØsÀ˜–;è AõaÑ[Tªy‡`´ÂnVuU `v´’$…s›ª‰ë¸@I0HU¢×J'Ÿwˆ<çÓ…í·¶ywH+ò±$3…Lƒf~kñÂÙÚ6•jQp|Öjj ’ÛQu‹D¯ÖWâ cÇV‘ù!À¡HóÞoR/6DBL›æù¾o³QÛÛ\µZß,øÝ2øv)%u8˜½¾dTÁ¡ußÿÿ~YK¬µªŽ'ð§€=Öuu1¨‘5À¤ämÌ©V~J8¢Œ§ {5¸ì`’å~VTÈloèç«ÁkþBX¸÷Eù/Ç1ÃwìÚ´Ð`qØ<àüdþå¾{MA†ÎlñÚÞ(>'5GEoª¿"ÍàÚrÉ{§k¢-)Öʦñx˼.ò€÷ƒˆmÌ‹ð<Ÿêãj»Ád²Ž¾Œ û%9 ™%³Mú€×Ù–/ûú³Ó0bK”²§2 j—Öè/ãD038h¯áʬožØ¹˜Œmhµëk¤”Sei.]·ð'4K[†”&~-”I*§«Æ*g6áòi Pç žAÍš ²®Æè ¬%²)ŠP}6ŸõÛàO¿õšÝ7…|~·*Û¾«ã1ðá§²4KBóð=w§ŽwI½¡ÓT€ÈÖý»Å;ÔzÄ"xS-(GýÙË‹Š5˜&A‰’6m²¬_%5ðª®MvyxO6 äy?m¾ï©˜CÔØÒ<ÉžÁê an@ÔHe2ÜëqÿNˆÎñ€ L!(Z›  ûÍ:UïßS5.G½çÁè§uïs'zHº¼Å|³9â?æ,±ô.ãBÓ,µyUEü¬&ÆÝ9Y+$'A^¥—Àd£AxäþrOl¹„TCÔ©JµeÜ`±úåé[™·›®ò~ÿrO7­Ý/™{ȱ»^°køÃKBȉ†Xáe°ô篋æ¶êÕÙ ÝÐ0Rô~»\^¾ œ)3,Ûç>¥¹¡×¦l|xT¢!½S­aÖÿ_Öa DejÜ^8ŠŒ£T½i«¿¾~¸ÞXHm¶0µK@–Id—÷Ê&LÅV’¾¾'áù)8E¬ò£kqæl@-Ti6!̬·FdâŸÚ5Xõ°•oòPPÖÅÕpô^äNVÅ{t¢°•W‡;Æ$»ýEàÿr´+·¿íÍ8H_V_£%©¼­ ÄLes—7Ä`Õ;™g´Þ9\؃§œÀ?i™°½ØbjgÈ0×1j;ͪ‹/òÀði;|™»i¥›¤xŸŠòŸó7LÙþÒi"=¤ÓÞ#dYäjV/ «%ª–ñPèrxèô"€¯q{(ð¡ÀăF̲Þ[•ÑŠÚNTû;×J£Ó¹ ¢ÞÎ-¼¬_:膵H]À©ks2Ö´ 7«¨…$Älþl6„oÐEâ»Á&*ËCg‹²ã1˜íö†È ›|±¯Ø¸M£ÛX<2N 0ÎéÙ§r&ó}ô®Ææ`ñF(V²àéºB¬ò—/A-ÓºIÓë=ä{36Có±·ÅÈX„`Ͼlä-'Ã¥ñÇϱŸãj­z—Ÿ? ÃîNõø2R–£ô<½@¦´tPòíÕ>l×fwº2d°ô§%‘6eƒV Úi:ÑÃΟFêßž9Ú™žl›~ÏÕ²æÁeê¹[tÝ5/€‡9rjÎy°†ABî rõ¡†F¥™/­1B0;*°ÏäWöšï1‰€¤H+6"X&i8´¶~”ŽKG !½‘¾îm§¯ÒMYÕš.Á8ÞÝÛ!(Ne´*RYÀMš©ÆZ¼qèü4éŽJ:Õ›ßì¹1 3®¿WÏYînXOf(Ï,U®ž~ƒº5·dÖ•]í9L¤ó ¿u4‚‰®‚š`o ›€%XlTä‡mÖ)‘jª‰ÈÕ{ϲÕéZ½Ó£„Ç|¯_§†ç†LÔ´f6òâL¤Aœ®~$ÏÔ›&.]¼2]Ñ0$o ”ÓJWÓÖg‰Š*4'ã­ƒ4—ev0\!,‡/ÇŒt7‹†tÕ Cú§?º‚H°_œØ¯­) ŠÝ ¢x†õòK¨ów°æƒ¾©RÖÈÏd¼¬¹Y¶­/±=7T¼h…Uó›Ìg¯ñûœè_äž œ_#™N jD]>þÕÍЬà#ö¥Ê ¡}蔢“8‡H èÆDܸ4¸yÝÉÔ†þx\‘£cèê˜U[5…4ëøœý'À'ËÁIˆöét>Ó7­ßz|ÑÔìfåöþÖÅëWZî &Œ¬JXOŽ\¯i¦Îãp6„ºÍóúÝy¯¢’)æÏÀ5}DZ,Ù½¯u ¾„È“øm­6ªÚ^ä¬#¡¯ƒ/ø{4)ŠSe¹q]ØiLЗH¢¸lýL¯¥A©é¹SÈ6=q¼”Sª‰L¸ ž·6:ïñÈ“F„î’d:ÍhlI|½ƒf›Ñ&뵫¥˜›ÿ|ä·³XÚ¡œ“ó?ÙŒï=´Þ]˜+Ùw8dð¡ÂÈCOÎÞð)íÅí66íEôÓ¸U'ö ÅùÕŒ(ÊgÙñnЈ¦D´ªQ~»Á_À¿™Ž}rìHoôÉ×5e½ÐÕo >btu£ù¤.d|ÒÃöîs$þÀéñÙRŠÒ"ÁÛ,±¨¬¨ë·Àê$»0u±U„Â9A-{£Ñ„üÒA™íÿl7rS#l8PV€6¸þÇ‘ÒW!>ù, ÿ ^ïçQuˈÎåÇ pÙÈ~î‡`Õ¾*'©®( w¼RMbòú/ôxN<8b„­U3…YÿDÚO,ªøëÎa:ÐüÂ%.ñœ 8?+ZǾÂd‡@o”(–ÛŸ>i ­UZ5u’aÄÁج0)>×n'nÞcVðªpœÛþ¯neÐÀ3‘„éÄnA ÆÓJýeÞLuا<ÙþýIK0I¸–- j.ÏD×CK¨:aéôD ʾR]eA€ëþE#£þ4 rBXà^¢b¤=d<ý»>n:V–!YJ…”eˆ¼‹„Ù.8Þì=º€Q0m¶Ì³ŸRâœ>òÞizîJ'Ê^î N]Ò-òÿ8 á»ÙN§ /¥“i¶u¾:-8ÍSL›9‚ÕÌX²Yƒxüg ÃZŽ—}³)pû¿q°%1{1LŽRq¸›ø×;–½„ìÆ>ÃA§i§Ç˜q‚<Ø&M]«Í áIÕËÇ€Nÿ(ÓÛÕÑVá•»»‘Tñð[¡!ÃÛs9i(zû_{„ÀOÆ¿`EœŠ¸Ä½ÿ0l©,LŘ¡Û•ô n7KyËû÷·BÅä©V˜IêØ}B¯å¸¨·èmlLkT¥Cwö$`$B±‚%—él·2k(ÑC)–þ‹tÔ„ôŽ›­=°e®ÁÖku09³GˆØê?»ÁÒyø—4€aod±«WÇ-iÞ†—©×‚¤È†SÎuiCíâ82å6¤! ŽÂÝÎ9•·§ç×#;øBsIÎ|„.ŒÓîÃsÿE÷ßv|p¨Ò³à'N(h»ë¹8Ðä—ål° yÖeØÂ”¢e>ºü‰A\‹È÷&‰ø)ªžÖ œWè™TE±Hb%µ”V¯r}Iå#Ããd˜ï©GûóßêÃr 3À­ʰv2¢o«Bâù~í:G¬î(ÌCöÒL}w¨ƒ‘΄ýà0§Ûø uÇ$|û~I´m¥âaå¼[¨);ãWhrñùcAóekÁøñØ1†^í¥Œíœ ‡¾ËÛ‹-²HŠÜ“àÁ Ò‚Ë-õ‚BÓKÌ"Ĥe…ž;.ô¤¸PÇŠ7™¢-Ä›=†ùÑlÀº7“K(›ãxø>×é*Q³â(yFlZAÇ6,×%ØjQ½ë#?tLír4YåÂͼ üô °ºÌ=µh`¦8ÀœÒ•ª›¿ÕÎκyw^g£‘K-JªÜ¿þcXº×K=â„HD‹Fè°¼«z· Æ31?ê†0žºtJ”¸-Õ¥ùxÔ Á1Œ0¢q¯§¾³²ƒ„—]]>°mÚ×i”õžŸ"—Zê1h6f&èâÕ·õÎLëÜÂWX“yæ»»eV:øka•§JëdKçÔðY£íw’F.Ñ<Ý@Œ vÙL“ýÈq›³'Ofu úµýj¡>¥¸ ´[u)ÆÀ,y²åRŸGüg/þ \$V}‹é$%Ë<=e%å™Õ¸Ê 2x–³úõ!˜sN3cÄ-»Òcþ‰œk}r£¸ò°(/!qÝSÏÝ3Tê‡lú§+f‘O B[ïÉeý^š×™¥ ×p¶¹v {|“vÝÔ\v¤·»(¦CJZüø7ìJÖù¡·ž‰±ðv%“XТ:ÑðÜÊd©=÷½ïŠLïH´OQÎ9,`ôJÑhë· {…3,¬ìñ Ó+@G"kKÒkŽ…Ñ)$zÒ½V¥å½Ëi$E‰§±.ž!å³²§}¯”ÙZh¸¿yH•ƒ3„ù®þG‚¶T1ßY¶3[áͰÞ4ÚØçÁ8È£¸“/Üš²KÊ”·‰4G/¢n̰U&ª:¡=JOqPá^EŒéŽÌï¤cG–KÎìqIôÄïašŸ·µÊõGw§ðÆø ;GAëÚ3‡¬Ó ‰Ý¼ˆµ”ÛJ‚䞨J?Ad+fèjy•ˆÄ¥…ì/ªõ!›mÝ•q1«%½k24W€_y×ßÍo¼d¹Q˜†2â•÷æü·=»!_šÏ!‘‹l¡¼-PÜBå' 4%ˆ{Jú¼ƒïŽŒf3ð=7}™ “î)oÝôsƶT žð…œð7;bKmÚU´·×kL©öµg3Ýà¦'d÷Ќ׾H‚ËØôÅ-JÃÐv®i%0§:7y¿ž½½tl…f,h‡6˜Ú‡Ç&ÕÈwD—™=Äõ<æ¢ r e“#y;u³ê“«t3è]aô3£äÍ÷±YñM\,J…ñ¿?¿O{|®sº²#ÖîSý£žŒDÀªõ ?HôuÐÆ,­@!Å F †QW9Ï —â†ÝõÕ[ó¾&0T£§°ª.öŒߩx9˜úgc¸ Ð íú%_ëgu:‡gxo3¡õ ›Í¤’i½ëÖm©Ž¶«Å”˜ûóüÄ3ÅÞò$tR‚£Ãt!Ÿ®ZX"Þ®]]ûƒþuÕ C"3o1ªnxòl²yϪ‰UC38¤ÿuS£rA†t¯ýÄŸakõöÔÝvlY!fÀH£X†ÙñǺ;h½á˜ÏlDPk(õO#õ€;9`Ä_ùö1€#¸áC¬Lú¢B›s©J±ûÔaÚç;U;¹Êè¿xÿD·Væ6¹x†ñu7kqq¤>¥H¤ø&IF\‚»FÒMòëhƒHG8ç}éµ$¸r¦ÐËFžoeµ¶éÍKÙÙ}C*5Å4=o3=k‘ÇÝ¢æG0ÿPK6ê«R¥GºY ”»œcuéØ{× §ûy*û}Zoñ ×‡j­,²JÉô°(…(ôùdD€~틺j˜ò • "Âê¯Á ¹,0ÑÀ;àÇÎu‘à‹h“ñ.õ QKÐÕ+7•횉 c®%¶§«"ÿRncÈ­cŽì”BWÓÌs~~t˜:[Y_G¶f Wûcì ÄH¾hFi a—KhÄ£{ˆ>:7m¶»íTƒÈN !%‰ËAý‰°É¸_i$Û Ò<;}È^zÝz«Ã•PŽå8•È]Áì|÷ £FÒƒè$OP‘6\î›H„)f÷¨Iœ‡®Í‘sXâjƒêÛžËÂ.w„p™N13†ù€ÔhèŒN Pù`öË™VïWgÏÒüAÞ@Ái«ïÔQá±ø…ÒïÈüº(vŽ{|”n>Œ!*ÄTéôtÿ°£cÃâ7§ÔûûTÿåoBx(y {W7ÕD¯oüÊøm,nnàÓJ=«?®ò¯ †ebÅÂŽÿuG JX>0YHâ#Ž qI™(3³üØ“k<Ë:ª­÷è¡Ò/Nð)Šâho/…½€×5½œÛXØ>ÆÁ³:* ätÝ6“Æ ÷–ý¨øйñ®…õ€ôÆY†p ¶Èab+°Ññúü[©k¬]Õ˜›=‰Ò“¸HÌÜ0hjD3L+uƒù`Õà=F¸ZqEdŠ$2•µ†ÑòŒlpqmT®‘DOì÷¬ÀŸb}vk’ #)^Áw¥Bß¾l×p¡ŽœÊ2[åŽhso5„!´ð‚^-WÓ¾tÖq>øÐ+º:H0?'Úµ.{}BŽó£i]–ÕV »dð(}U‰LðßH|`´é›E¤zµ˜<„üô†¨(áÐé D#wM:7“Poˆab3ÉÏœ#@J½¦#†:ƒ}•(Ó+>ÇaÖ·$”à‰WÊ©5fM7”è´>èX›<¸å>¿¡÷²OĉX+Íš›ÇÓB8H8[‰£î/mKžá:µ9Þã3±9¹<ˆ¬ÅZf.…ê gÓý¢{µp¯+fz ÜÂL ë¤ËXeü–d†»ËË=Û ¿s ƒz‡D‡»–kÑ ½ñ“)ûõÓŽ¾§h3é;`__yœ}€„„p; ÐFÅ^@x¢v.·þ,in¢úfÛÁ!¼d蘑G>7ö4¦“ƒÁ‘ïÓÜAtNQÏð¡æ+ta è§jžÕÉé #‰°¦©HK$bý^ñËïP?ô[1¨Sb4È ë %? hÉ–,£_²Þ¶ÅÒsioÑNþÑ2¤%»ãw{FukŠYšþ©+”ÄÂ¥«¢û£Ã«Gã½1•cš¹F4ÂÜI&¤2#–œù|™–0¼Ïb¾ÖFâ FvŠÄœ¼…tF°}\æu*LÇ{çÀò‚½\3„‡·¥á­¶ïH)]´‚‰”G9 ‚™mw¨Ð}æ8èR¾ØHåŒf$K8¿õÁN;€_rJ§Ü:°‹­Ä Oj'¸¸Êû)Òîð.i/“`¶ªŸ Dˆ³Cõÿ{¶µVKÓO3‚` ÂAÑ=Â-$qÜcžnTk²;ßMxÝœ«¦KÒÆ€Öb6ÁSªæ‰Ý»ÔZ¤¨v›Ý—CÖ—Ë„– dzpÝ=`{…L€Ë|ïò—+\"z!H—ÑrÔe\bbWuX‚S?Go®¦óò" ý8f9ÁÒyQO<µi³žÝíßˤ†LÔÝ›iWõè&‘M¸™#ý#÷g;’Ù|yVÏ«0)Ædg´¹„Ñd…ì…†¶rÖ§ÿqÿJ¤Th£€oßlâÿš$D*x¶ÈD1äX åë*·`žzQ˜Fß j+¾ÂÀáæ}ä k‹äSXF¾õ&×ÚD{wZÜ`¨êí_T#²óï»,¦ôÏtÖOTI]&ÝÑ+5RýZÑSdìñîq7ÄOJ{£ë åH º„]+Ô \R—T9MÒé~+$=ÎF¬>È02!Ôa9 7ç$MhÍ,7Å%7”žbԸ嵭ƒëÁÑgÜöÁ²î#æc«cOË”ï®gVwUˆ+%*&_§kÙCŠòQ ³¯NHSnzó…e{qÌŽîüi•2(]£lqÿ¦¯`ê a8/`µÿA§eØ'ˆGí ßHBÜ`¼}Ì48MSZ«^ÏË ]{Ï7¿ [vïaVãʹĞÑ>(p:(WcŠ ò""]¯k.q<Ï%¡‹È³œ0¶Œ˜×á|_#&t7o VEe Å Wyvw½Oþ¯ªÙÖæDH?þ/¸Ùñ‡boŒ{9Î<.”$OÍÜ]çlQ }\™xSe%â#ÏïtåÑcV§{œG©ý¿¹È­nËv¡“°?‡¿W0±A+ÂÅYÛ3«M*3$ ^â‡éèidý÷k»üT55îÓÝ \ІÙ¶ÁñðpGÏÒÎÁüº¶¶òViMlSðK GNFì[Àn?™Î>ÿ9²=YŽŒÖM®¥ÁÎøœµ:Þ"Ko”_Q/BFxÆÂ>pôÓD7|ÐXL|é¤95GFT¬½i1²·H¡(õÖƒŽ^D0Pö‹{Z ¼$ “ÜS5<–Œ—ÅxY<AÌý‹g"ƒnL ŠGI³5„*X#ƒÜ }‚ßö•õGPBw¦!a ¢=«§š~ ;O2¸ 1mž^ñÇ•j€RJÝç™-}5¤\zÃ[ŠhçÞá‡m² ’Îúª/‚ »ŠÆ L §† xñ˜Q°|¹Jx¬‚ŠÜÕi#º‰£x`UL-Z¦ ­ÚÖà¿»Ù:ÚÅàð¦Évž(‰ÞáeŠ£XÿXÀPuè¸É©÷–t”Sm¼7Jˆ^­A,þ!TÓ´!Fñ°èϨP&0cçÍ^(K#aøPÔB>ž¾¨ï˜*åFÁïpû’•ŒŒÐðÙMh~Y 4ªAA†¿Éç½eXN½Ö$9;Ãñª ò®æ€Œ‚ @ (9{Åä¶å—ÄÂS~C¤ž´òa¥{œÈÂŒªB†U=ÒîÙ.WTxõÖuÉYïS(ÐÀu\—í (k…¡w¿æŒ°Ç”B¯P »S‰]Œæ -ˆ¥4¦V%q“#½ê¹æ#3bêTœXAâöËŸ.ïN®]t֋LJ½õyÄ}›¸AÚN5®‰ENÖâŽCP¬êû©/¾[Ä­i­ ¯Ïeò}$²Æ€¯›îù¡wÍg›8aò‹ò@mÄSO¤ów?ÈHÛ Ý…¿6Ö¾AQJùŸƒ|œØ½ãwè#Û,&ƒÔe¯ò_•?èÅc­~{z„v’Q€)GzÒ¹àJx”2âA)ê`tn6÷Ã)}×ñwÿD5“ ƒrdl.dˆÿ÷8Uh@ôë_ºêÑ–ÙŽSÕ¤þþ_öàE‘ÿD2}à1]ù.kWI>$ | ¤¡@Zí+u„$"·XÒ¡\*‘¸XJ¶¥%²8€Û€ô[š°ÚŽÌ@KgLÔq˜±qÜËÊ(—ý}¬Oñpu^¸Œ2TŠ@cßzZŽ:Žä£ŠÈ¯Ïu%½•k[yŽ_Iå*ùîA¬yû:0ÂB-ªþF*1T°þˆð˜å}Ómqœ…éÿ P°œ¸Ž˜—­!A’‹,‰r`Õò£]í7Ǧ—pÊÿ†J€'(Â@•îvwç6–;ÃÂñ‘µ?ž†k}ÑŗƇ^‚õ‡H8­¢B$râdù¦Z>HË™³Èèºqöä"fbw‘; B6í€4D {çWþL…ƒVC†×ƒ÷§_d¬ /Ì" C½9­¼£‚/F}î*¸íˆT3høÏ„ ]“ÿ`hqJ²š¢VÙû^i}ïNvy$¯¢ŸºˆAR »L‚(>è©~KkC¨µ•´}‘ür½q.6ÁØ;  Ò.eÓp³¬66Ë«{án¶Q²C4&|Ziwš &X²zjˆæ„·£BPÜGŸ‘ŠÃD;‘Èw¸Ðör½=†Û€äß^<±<­Aä¨55EÒ,¬8õ@æ&÷ïa1!úP•h­¿ñ1N³iÀÿó^3 @”~ã‚ü• ¯nF¯FÄη~‡·ìDB3ƒ•çô6F* ”'A ÷§¹†(¨ÅÔb5à=+ÍÞ; €òC |š/š>Ãýì©¥;– v”cà¿èÝUæÓ㪴¹¥ÚHH„~ÈÑœ8-û`üü¹¡ivÍip/´>(^p A"‰å‰Ø$RÏGÔ#) =¸í[w/ž‰ c΂ª1ÉIo`t”Pù¼yÆ®NJ×iwjoî´&ªÓÛ‚ÍGsÿ)Ìç¨÷³bXzUü®â(v£Ïnü• ëÏÕx'ÙË¿^J.u¢>‚ù¤Õ¤ÿ0H½ z!.ëëðÊäÿqG4ìzŒQmF5ÖNªDúË"ì6—_ÿñ1N¿Ûœ7Þì{AµÁT;úÚ¯¹^¨0Šl©M/€®*hÿ^Åør ´.øå;žÞî%óÙ°yÑ{ }7Nˆf¦ÿ0E4ÎÃ|òº±GóÅlÖ4èPŒÀH2m½>˜§˜6c$ `Zã š[s*Iü²ÊþÈÃ%@ M¦ê¿¢§Sù³Í‹P}?F¢¦TTRÿ8ÈýPZT¼i¸ÂB^ÆÏcÚLÇpß”‹]Ù!N²òÚõ´F”taÂ8Gß’ƒ³¨ע⋜Ý:Jù¢”‰ €'¾a©ÈqêzŒPCšÜäÜxlpùVý Ëñ1N ò²½…óßëÇôûšB5‡Ù¡Ý­£ Õ Ì’ Óö{Z”ë§§>Ý e ¸ŸŸSÙ÷p™Çd ÿ~1~nmË÷7ÂÄ}†*´`g¼x8RcÌ™†xæ³LBèðŒKóÊ÷c­ED_œÂœÙ'r‰…âÍPQ8¾ ºu¨à›c´X¡¼# Ö­Ø«f¡90.:ÅüùF0H?+ä¨BÌÒŸ…n4|•ù™SêìrKT´›¡ƒðÚË%©Í†ñ¼S«qιd¨’\‹Á¨®fâÐ3@Z“«F÷Ô¨¤YxµðS©:“©:‰'*ôT¢Ç.7z2T “„ –û‰*wó™ƶƒH¡WmÜxá[ãEåüSò¸þQ~5«Ñ¥_m3*z'‰c£ažÓ² 'ž-±ƒ Õìß¡s宜»jKZN{é£$öù `jï×^&§U@±ƒWšaBbXpñ‡Ë©‘2¬ÄZ¯•sv÷ßð2òMl¤þÊ ¬›'©f¯2~~Cÿ&£8÷ 莴:ÁÒ™údž¾^7À‡ÔGË¡:¿cV*aý7ÖµëÀ)Õ6äKØ+0*žº_p˜òpø5>3•þ„¦ûb<†!‰®ÎÛ"v y¦8š_4¡¼HΉ³½CE‚æ$A3”%Eßö)¦Ìè¾ÀØ«#*ôo=Ý@j¹ë¨1¤î?GüçqnBÏÛeÀ3ïY“qÌéã`% @8”ãÅ ¶Z2É}›te…‹æ~ˆ_:›IèÍæš$é:wÜ>=4çuçÄ‹Xl]L û–Prsÿbe½Fy”[Ÿ‡Sý„ëž|Ø–h2¸Ï¯Çó`ÃÈ®ø<óÅU&?ãQçÍž¸¹ hûspKÈÑ ŠñBñþ0¶ºôÝm_¾­q"ŠìãeŽ>}u!¬¤Â%Êî¤3E¤ÖˆÚp š#Ý¥ý?юƾz¡åÉvØXò ŒÕÒ8“ŽM)¹ZXݨŒ<PÇ2æIÒ—šnÔ‘¶pB×i^ëIáådñ™wÌc^Þ‰øçÛ%9€œ«ßž0Mïxhîc+D;èÌ8 y„ûÛ̦¢)s·-€Gyì•&dzÓ*•ˆn’•¾²V(ƒÿtaÂ’²†Ò¹õuœ{߀Ýü×Üë‡ô@¶±kø¡åsø­£ã^….Á³œ!£ªpÅT°Ì‡â|w¿b±\‡>€¯ÞJ€“Š­%¤Æ,hF!o[,Á§C}6k&„^‹ŸÔÊÕ) ɦ”/Ë6f#nS´˜·mõ>/}ì0ðè?v†;˜Ì­ç>Ø5lêàÀÙÒ ŠzoÍdq›S% Uɘ„ÒJ4¸G=¦ß`Ô˜»4Ñí“'çít#ŠûfxÞ‚ßC^ôM¸ÖèéP;‘­ïc癌ZŽèlÍI³GÜ'¾5¦ºg?ÁÈãµTp×ÈVXeÿfX©Ãàô*áÓQÌlƒ&Úeb$hËœÆþ kkAšFs¢f¤×%(ÿFµÕG+%! fD¬¶tâÉåÞÙìv0QÖHºR¬SÕå_ æIÓ©á÷êüU …UÚQß,æêßEÐÅ$ —êˆâ„±?ž-0„Ûrt8=Ú±©äî?RլǗ³WYÄÇ—ŸòfÛ; äï‘­¢eè@XÜ…z$¥b8ÀÑcãØ^’ÐÅ÷¿¶¸(07Ä K2áìÊØ°—ºädâ79ÚQ=,à7ħ¡WrôÊØ'zN‹»·,o™o‘ÿD ºW¾‰ªu¥æ0ÉP´œÜvíw³ û'ª1VôÎUN껇ë×T¤¹o±ª)‡Û¶"ú‹0BðA)1K+ù•P $QAI‰ŠæAˆZíªq_è.ìK9i€`øöÓÁU¥[_šñT(jz¿þþ¯bþfä}€a!&WYØH9#H>*ÈŽNÙs»®‚ìŽÂåÑîÆSÔý_„@÷Á+ë‰Ä]Djå?q¦M´S›oh6Œ ·š#b±:% $%â3 ä–ìçÙUf(wIñÙclNNl°ˆGª>6ï¶4ñ?‡…•:jÑ©„»ˆÀað¼ÌÔ’{ª‡=•ѭ哾ô"?X°u›HÙtâÜ }C÷AcöoXçË,J£:fªi´ÿþ€ò›°ÐŠVÁó\ŽJ•=€F”\EAŠTîêÒ+ ¥¥¯h@2a!/'»ÂB-Ãa»GJr¯ò•ß•pJX 7œŸô…ÀÈ:nõ—ùXáaÉà^I¸Ð†ýé„<%eç8:þ¾Q@›ÔÒ“>yš÷ÖŸç+Dk?P!sìÄ+o®ræoµ ”n¶õ´,¾MA ܾ7S7Ã7Þ` œ-á’ 3BÌëlñL»ïXµ8:ŸÌuW£E´’œÇ7€<"²ÁT¡@Tq].Ÿçç&Ÿ=³ýÓš@]¢—*.5°!Q–¬€a!à!dg¥=C†íêR¢羉¶å-:Ô„Fü¬rm5nê]"wŽÚchFÐë f•®ÕÈaL=±ׄx$¬i«±Y yϋΰ= Xž õÍTÅlÜHˆ^xÓ%ä­o+›&Ù{ÇšFßFE™!óK‚†„äב¨áŸŽ6Vo~™!.f~¯"J w˜°b&P=±ÆÊÔjW7k<ÓRíÜÙˆ“d~à/SLe m|d¨D—Úq„„œ8áI¢gB|úV{.ŽLN§RK? wËĠ¥çÌÿà]G<Ô´€·Œg¥µÈK/lŒ2W ÉA£0–‘ãç4p8ÿ Ì€¢Ë^~dè[5’²`Á#ÄÕí½?ðõ]¦+Çq6”ß¹kkòWµ¸lÒ‚[Œx*šº¿lô¬.”4Nãà°ì²9¨– ‰¤u–ÅÙzu”ézçe‰»Ç!ƒ]™°Ùd¨ëfŽYjŽb‘¾ìýO '0µ’`˜ÙQzÄ?Eòkz¦°¿ÂL]»3MÖýSáPEÒþ»ÿ74)ÎaÕÏb(rǼóD/K;9‰D &†aø.Þø+Gyf"YÀ/}™X¶X' ¡™9BÍ‘:)©Ü˜j8Â*†TGñ™ÎgöT'ù8žZ)ôi‹ëM“häˆy³´(׌Œ”Ÿ«<ш¸€B¥5˜S„u £’ªßø5ë¡÷WB îT1®ä•—&†¯‰c^ƒµbªNÁJmœáEoj[x›óÔq â/†ôöBµÒÇ6'¢+‹²ˆ½$’{Q{Vlý¼Y›+"ÛI™… Ùlfȇóöó i°­öA ¢ÏëËÅ•üR4(“ü\Öð(º`avK0ÜsPdÞ^«Øw†Ð™©Ó"1º…®NâEPµø’l€ü\¥Bh^Ž"`h6¡oàÒ.‚¿Ñ³{ÕKÕŸ ¦ô´¯ý†ÎÇ*ÚºoJ?„ïàrQõ4äG5h¢}¦t˜⇴&áM¼Âüb¢:˜%iÞBṳ¤b‹9†wûQŸåÀj‰m<Éå!¿‰q?•ìè$gy:ºQY"Y-V ¿ŸÜÏ#g3v⌤+¹in¥Cû¦Á·eŒ3êíˆúUw3 *uÆ 8×Jåô3ü»_ðþŒï‡É {rйÈ'ÄÈöâï‚¡€ÖÝìÅgÉZÛ€ 18Ód7\ö˜k¦å`’«_Ø ãSÅb*ãr3—|ª¸\tsï‡åôèV4•CÁý¥hqì"k‹@éîrÓ/0ƒ ¶â¿l°ÉOï(áŸÇkÚÔW¿'{X.g¥ !˜£9-’áuL $6äôJ¶OÅ)Fn©Uª„À0Žß?µ”`ªæÔ²»ÿ@¥”xM@fb+[’¶{9^h”qEI|È Ìë"מ¯zÑü2C0¾œûTPä‘0ÀƒJñÄÞ‘d*}§gÏ$ðl]å®f~Û·Ïv”?l 8C1h}B¹.¹(.@BÑ€ý1( >÷3bá’ÄA†™F3 ¿ž5!Xë·#³¶Ã æŠæuDG%É£RV 4œLvH¶CÀVù)GòÃ’¬ÓØèñ¼òPTÁ“®l1¥¤ûÍÍz¦Ìª™sɽx ÞØ)ÿ-RmQ¡‘¿Þ×Þ^j^Ï…[ï#€a¢›áÏ (èÅ­P ïqýñ_<…ˆz1š£ 9fkYQã)V£K2zwlä.\ë„K¨ÆÁe¥ó9èu²óT;ÿi·ŒÄ©lÌCI‘´Ål>‹º¶Nrðj¯\¢Áz/¦mSˆ¢õ3v$Œ%Œû|Z°ílˆ¦¤ËL9ج"X}oxÉ~’´&¥ÐñÂʼŽÓÿYkØ›®èHˆA’6åˆD‹à°ÏOˆú&0K`Ù‘g ˜YÄS2góZˆ¶ÎŸPäZR •»0  ±³'«C¹Uÿó7:Áy[•¢jH–ÊkÏ>Èåœÿ¶É(ƒ)¿9ÄßÓì´¨ÿié¾Hy_µìÚPÒÇ<ª”t}Ỿ"}ù« GåE‡¦Þ/mbäC¿L_=—Éõù.gn‰žéØåþ6kïŠÇ¡B$q¡ý.,Ø3­™ C3$lå²g4é8¦³rëD1Ž3/»±Ý7Ý‹Ipú¹ž©9å;=ÿ ¼Ró‰É¢`£ØøŸ•ÎŒ#ëùú©¡Tˆ¸ŒÚ€Wð†fµÖÿ?ö¤•FÖíέJ†Ç>ìç‹¶øtÒå^®ð¤Þ‚ŸÝ) ±ÑE?ƒðWéDy§} #(<ü ù~.ÑÊü…&ÙIzã€C¾ºÝË'À9Øäw~@åÁ‘EPÅôK䦡H5»f¾¦>Ès4Æ]/ò @ïðü5óæû3ŽoL8Í!’ßEüÿql «àŽh0Pä†4ä¯ÖÌ)ëIû38` ÅÌaÙhVWÿõœ÷‡²ŸAo,+…¹BQèæ‡F¤Þâ|y§âkI›v†ñ&;á âdïpÌL{„£Ð~˜ŽPÇ )7¥}ªðzÍ÷én„(Èè²Ûñ¹½müp²câú›H:,u¡­æZ3Í<°7ÖLI9\]z!™U pÎê’Lãc‰wsîãfk<áxÃÝ’;& »jhé¯ Ö–Ò3*$cjªÙ樮tLÉ£æ­p Í·¦'XƒBßû…yýÍÃlÕ¸€yïÿqcox>?ó á±ã÷æ€ ˆ¥Z­º·Íb™¶ÈO>ÃPþaáN¸Tµ†“Ý º ~AñSäÕÏäA·å‚ÍÔD–‹Hnn†ø`¼5²jm’‰°ªΰŽ<ÁU4©kŸãú[ÖýÎ0 ìVúã hóìÆ‘®Œ—tKI.Ÿ¯Tß‚VØk}a¼Žo¬T¶ê@  d­ŠÍž¹œÓöV_ç ê~ÎÁP8Gü˜Þ¯ÿæîwynÑâ¹ÿ‚IËkôŒ/Š“ý‰z¤æÛ¾=rÝ=~„A> Ø¿e.³€Õ`¤¢¦´óÔûÊ©¹I µ™·¬Å ¥' S²ÖaãÈdÅDo«ÖÃ8ÿãÖ±6Û±‚£‰œÿÚ! ø'sã¥.§NÒ¶J€ÈUàfÔØÚD­*Bˆ~ÝÕÔ²îÍ_5Ô²üÆ{·¨rw þiS²›þ­¾íií¥  ÛÂÝ„óWÈRôxáÁ ÌBç×ã…-|…µ1% dOO‚Uñ®@œíp~Ò#ãŠöT©$¯Ï@Ÿð^™Cct_PÞa½·ƒQkR=3 ©éN‡`±š³ÑÖ _zoCœbsŽÑlZà¸á‡Ce¨ºRòpýÈsòZêk €è§ NÒ ìŒH,%U*CE¹v"?"C4ƒ?AVá%ÆÊ`ƒ0%¾Ÿ%çËz+_´­[óˆj|’$£–ƒÉµÀÒŒë5„.ôŒíF+L·3йF­{Ñê«ÊÍ]è¾\ºN¶SàPV:j3Мvö ,‰yNÊ•d6ð—m$ó; 42óM'´"!e”ÎóÌùQÐ\?øgÜ5sæ±!ÿ@ òôðîã!}”µ_§©‰í‹_}„3»ÃØp»4ë&/(‚Ðó8 »äî…î8d à÷©¾@èÔ‰NŠÓÁ^Ä?|¢0à`ïågòÚÏ€¿U¢è›üÏ/‚ÇÙ2Æ8`çñL._•Eùx''¿+'D De«X¹%0{Ø,èú”¨ÿjäµE €ðŠEMn ~ìu²–º5—pÕ¼\U©#£ðãá#íSž¢ä2°¨}Êéú-­+þÅ·4Zpë´²Þ´q\Z¤=rĉW•çü@Í2÷õª$ö¨Ñ5ðŸ)OçP¾4|‚·ÓB/x /Ѝ ˜¢SλÆLÑ–Cª·LðؽÜwwê·…ÚK±„&1À§ÚY\)0>|gØõ²î“¾ÇÏt4îsœzõâ¯6~”áHµ”ÔLÒ¼O°/œò¦÷G Ù]™NÛÁ]¾›Ë˜U¢UÕžÚWÊŠ²8¾‘Î3ãzŸ¦Ë·ÜÓš½åâ ½áÚ¿LNÂ".ë{vâ¢~Ä5÷|w·? ×bäÑž&#ŧ‚®‹ 1š‚ݤñÇ*²(%´t„£ÿp?Øvg³À5Ò™¤Ô–ø0}Þè=¯E÷}–hÌKŠ®Øâ:P–&?j›™Ÿì#•éJ=Qš`nQušÑî³dY© /–y<áÀ@¤13x¾êÝW„îIdô[åžœ‹šÒ;ʼ†™îytó¥þ?§©WÃÝ)ÒS`ˆŠñéÐýÚâ?)¿ÿåb–bÝ¿NÉéê!gñ¤ÞIö¡r㡯Bøõ+¿/Ü¥¸Ëi!²Ï­¬¿ÿÜú}SÝÑßÔ^¼³ÒeØàð¬;]¤PŽ/À÷7¾¼q<Ísž‹hbKŸ×ÍTn?x*Z¼’$Ô@òïVþB1ÁÖÌ—P·@{¡Ÿ—Ó¼ná– ÂOÿ«}âowVGåèH7ãNœ ¬ùIýæ&Gl ¬»²9ÿ8£!]Ê ÇüSÛ¸™õÁ¹f^–¶+Ñ·l‚½ÍƝÄF=ù a^²LÐAUØ'Etz Æõç¼ß곿zÛ+6oåˇ}‰täÑ#…ß×Y3œÏø~ýÒ—›ŽÒ\{í³ûR›â´·.w÷ßtμlŽ×!,29cã&fW A”è®Õ\B©ñÇÖ,ŸƒBaW_S#q„úgQòAød b¦ö&!Â"Öý¥ëÀìò¼©~Ù„6%jÝûÓÛ¬BY¯Ù pq8ý]˜±9 “hæ#„\¦Õ{{ðÔ@NùTA¨ËïRE2“̪>füÉ/_\Wƒï>â¨Bè6)™<35DA,ĉöÒÂB²Ø_©pÇ(éâQ¨9¦*©ç¹×È~")`#nx¶’œ›ÄtÂj¼ÓïG?”¢ü"§| ä„–*ï=…­Gãö]‘”ºZ†þýAT¸åÎŠŠ¬–Ñ ùUž‘:Ê|Aß¹¸ h*+% ò=õŽó‰Œ tcHMî&´UdÖãõèéB@Â/Л'ìî?ÒZás*gøß9¾£Õ—C5û‰.” $”+¤ŽÚ+±½ûµwŠ AŸÑ{pÑëߤªØ+]¹;i/\=æÆ'í6XŽÐ]7”,¸|£Ú¥*`µÂï¯Ûl³k›3Öæ+§á_Uh"MÝi8oÁG?áIЬ/Ê7™ûÇ ð•qQùÞB,½/ ¸“ΦO1ý’CDW/$-(߈xc(Z“Q{ý˜§¨²Í!‡Ï`—Þ»²ŒÌMû„¡¸ÑÑ '%«\”ä`§ÖJa£y$2G¡‘o‚‹ŽCK…i|ŽU¨È ¬•DÙ2Á+zô=¦Oí“{2‹/²¦¼Ùr&?öб²„Ô%­ èQ¶ŽqkýCSoç?G¡ÿ:>š’ÿNBn·ÛÖ7Ñá1c‚öú%¾Ž.vg”`þ‰0“²üÐfß0:ćÛ4ŽŒç4ÕÍ•Ÿ"“~“…k&,hä{O6ˆ=gÓeJ§ËÒ°wr¡ô=fú¡jÖ2MK§²!/7§ ‡ §Re g-I V1™~*´à¼öÕ•ø$®ë8?æÎŒû¶oA ¶Neãçºò©’"/Ã>`-RŠ¢ÿM;†!l±Vc¡‰<ÜŠÿaÊïSň«xÕ°Ôè\¾àe³‘cÂc©¶¨Ê~¼wÖJý~WR㸿D¼è™Û÷4³È”Mõd‘€P¸.L¢‰Ÿ ´¬±,IkY°ÇÆ<».Ãaëb|à6x|®Æ›)cU_qg9ìñýÊŸb²@P Æë´ŽáŒK}ª»ÕË9^bFôºI\®ô1Fõÿ2c ‹÷XL#@ŒF‚ˆ«Ó6ÚdŽô“§ ©fÜñ[úü¹{M«dmôû´%¡¡ÛV@‚õGcÕÇtè7òñ[#!JŸö© Käy¹’@—"+ž … º®Bå¬4‘è*kéäu§·bFö™µ;`ÆÇ1“‡)¾aÇ+òV‘/Wàg¢Ø5tÔHB<ë°eàvBš±=_ü °5/ySñ9ž«^y·Íù»ñí¸•Ò§/3 A{:$Uòç Ô<ùÌ•oç¥. ÛÉpØu#ïLÖ?›¢™˜ nù<vxÖ^”5èá?œ«êÚÉ )ü{ajÖnJ7cJÆNMïÐ+ú#³´ ¶txÃùû0áYé{>êç~ ±œað†5øœ|¥dL«ÄÅÔ•J˜è&+MfÉP2{òIïõÖ’*œ3Ä5ÓÒm¸Zx™AF:íB¬Hè]ÿ^±2~O£Ý´§cX!… æ­ Ko es°$ø­KA¼Ô¶‚eÍç!a²^ãÂŽ„²ô|¸éžnòt&ǿĊÙf®s>TÃü[^¬ÜüM¶XŠv¹öŸõÓÿqm•С0+“I¹cãÛ‡x+ªÙÔãanUö›ëÄ¥·šH2¨‰«Í­!Kd¹“\ÎøÖ î5_øF~žÁu—KßÏa¡úô#Ä’Þ™ÐUyeëå‡ûï®}_P2½ñ‹Á Ëš¦i¤ûM/¨~ÛÇ£PV˲LFÚ ÌˆŒšF#ˆc +„º®_ Q¾tMýÌõƒø,‚æ½k 8OÔÜbSHsŠ v6pDþ&й65E™ã6šG-˜$ÄZž {Í>c³IÑäO(F2Ocð*$]·–½¶¬ôH‡YNC)="ì¡“y¡ (Ò¸Àà;i]jÐzép-Éçû[.{´ñü8À²KM»ÿ4e¬«UD |‰œqdnW ›ðó’©?Gc­YŽÈ|¡þjã® à@ŠºQº°„ÉDé*8ê ªp,{Å0*™Lîêd²Ž…Uh9ª<5Náhy‰x¤`‡7ÂìNT'Ù%} ß#dÕêtÁŒ„,;ÅþW ì©ÅÿJ’Ò+ˆ‹xâ’•áý„5­ýü€]3LÎŵŒ^mª»B”±þð&¡Ÿ;Ê6§F,ÊÁ‰© Êú÷ÏÔ ýþ䙢؄ÍÒ4…«Ò X †ïÔGAØŠÇ—ÌP×ÐÁX/ÁÍ¢ÙjT}Šë(iÄ]‚¦aÓfKü wŸøÕ»€WR¤­¼}ô2Ëú}çVçgžéBoÉ] çIY+*€6ÑŽL5þp@Šd=èÚf wŠäa\”K¦Y¿ÃGzXæ×Ì¥H $óMëš°Çë7µwžûy:­ µ*˜—"nG†Aá¤@~<ä2;üZêÞ.Ô”Ã%Pcƒ–¾"±¯‡›žµ‰UX±.»!ß•:–oâÙŽ`‘&Ý=®Š`9J„4„\JÔ5|[âcû%ÞØ3ã‰4íÀø=fÐÂðOš?áÂUÅ©€‡Ñ/’µðöúPÈ\¹NÝ|Þ·650 ×>Ì ´ㆠäÌéPniÑkÄˆŠºmú£1³ˆ ƒAõÍOÆ7²Yj`¯]†e=]ÀãÛBˆ"õú–ÝÀ þ·¡ñíb%±R]OÞį6Ü{¯Ÿ2x (æ×î¢7¢ÿ¯Æéà–ô‰¾ {óGJ•ÈðÀ;êhê‹!»1NÇ^É<}\þ“Õí‘Úý?ö#ÿbìSÕ¨ÿ6=ÐŽ8š3yl€™bG8)΄»pJm¹ZÛ•u’ÕG‚S‰Ûl€CJ= 1× [ß³Ò¶h:ßßI97X7qïè/Š”®6&0uW¶…¤ûÒ_5gÖ³ÐרQÑÆ8Ï;{oîmxs=ì³ßàÆav^¼ÎÒsÀDwœ•¾¤ð3Ãp¥¼ÈÑðµKWå}ý$‚‡¢œ¹Z.J2x¤€l{Žé¯ðé{‘g,ŽŽ—‰i˜¿ô*þoH;aå_½^/ÀC¡&qˆC{Óµ´ŽÑßQÐ=Ç+&†´ÚÜ4_¹3Mð¤WyDBÏǘ´MõÁf]ЮŸ¿-f2HTÏOzªÃÃ9çéóÜbp öÈ?ÅØ§«QþØüVüšÔûœp 0ö0ÖœµíÚ£Ãü‘K±&¦<Ú;>•­(Öhԉ̌.{·¤¬ÀîÌ®®g^€k«DÆ#fºÏNýÞ]T2ÔgÚáW5 €$w®™cTµ$”Æ¿6Û½b‚-†É„?¦ ©©´K·Õ J äÍ– {’y‡‘^‚€Û‡çÞTyKÅì·ŸóÄw6ÞM,‡–/Ao©JªçÙ¨EgO·9*%çªgXcŽDfS4;êÿ('r¦,Ds쿸y âo׺ڇíCL<Žy©°<§Ì”1¶ð=òo¥÷ÜIÐeúÁÐö\ÉøªA ;ÍC•©d9³LFÉóôÖ?.§¦A˜ÀhRÓ]¶=ø+!BÛéW–o×ã¾Ñ 96ÓÓøzþ{M˜ˆf—6ÇkˆìØÒC^]l`ú™V7Ó0Øÿ4‡ËŒHœº6¥ÒŽ%Ë ­»‹l='Ö(t6éæ¿»4’7‚1áng޶E§Fáã õ8w1F™q¶V`*ÿbµÚ À‚w«*Ø7®ç»T£øæ—„2r–xAæj³ˆg*v”œ±*æ‡î›RrÍÒíØàþœÈ½dÄpŽ”Ï©ÇôiîL—EP¦v@ïí(ùŽR‚õJÞ˜G.áéâ“wôHÄŽ(³ˆog! Mø çiT5!ËCºí.49H‚ C´dT©CáÉGaаf£ÿ\ï˜3nV Ð8'oû¿Œ†œø &F²-Wc£=¯Âø |}PI…@8ÃÎt­3Á*/]A‘ÞÄ7™{¸/B -¦Di6x¢n^rÌyкgÙH> .o×Õ¨ë•ÚªŒ0Ѧ’Ý™¾Ý(u/eÃPdÑÏl7ÌÖR ‘߉(å,Z—>OâQó5ßYä¢sH¦¸ŒLü¨È€™É.ÉbË=Ÿx€ÞŽ@¤Î×|«ºh‘¸ÍýhÄ€Ô¹­#èSëÂJÀN’666¼¢-êÅÇq¡œ&Àÿôö¡kƇҷv’›×1l\…Iã÷¸ª÷lÔí°v(ǦËçV.$±êóxœ¯4OÌœ¤º—îQ jU bL!bÉ8ÀCÑ‘‡U…ÖÀgE%3~O{<6‰r¿nlٵܾ„Lr¾$•–ȉ¯*d€šxµsħ¿ƒÚ/¶¼nA§r=«/YApä—óB{cÂeæX˜·qz'K9ZÆFû„àžõEŸÚÊÀN’666¼¢-êÅÇq¡ÑÂÁÀ‰Ô¢z8Âáô3¹ÕwÞl>ÑÝêKYßÄòMNÁ€Ø‘à‚#”éD ü¢HFXYh-ÑŸ~/"»£–÷ézQuï º\!2Ô¾°ãD¼T–º•÷ªË‡ŒèÜÄŠ x#ºÄÅ•ä‚zëýd#ÚlP…A»²Ýä÷ô Ê5äŸÝïä³g³v1V¸,Nê­ÇN'а¥7B±ù¨Ü«‚'t/ °„\Œøo!ûžÚqºZrûÇ“r<õîZS|="{häÏ •kK¼ÿu\h²­ºÒ;ùàªú(D·AÌŸÿ.°Y°a(xr?»×ÎÅhÐÀR¾ÀеcÁŽ~»*¦ðE×ÞØyöÃ5–Ê`áNˆs¹ús<ÃF£*¹þG™”;õuK‹àé÷¦É|”GCß…>JÀN’666¼¢-êÅÉ?×ðiK–?ÿåsqÈ#$xVú‘1hñòêû8JÉ“2aÏ)næ Ö©¬;¾@^óyµZ¶åOÍ•`èÄ%Û&¢Q¶CŸéd篤íròu¥jßÐTNÈGÒj?YˆC9Û+)õ¶[l¥û`ô}Ú 0ìÜ k·ƒ•`ÿ–FJÀN’666¼¢-êÅǃlâ§¾ïðéçVÂÓv¸t6¨H=ö²žÏîú ÂŒDê°Ö‹ªÌ46°§ª‚aÙp>Ä7¢[y öD«Ê WæC(£U²çøø´4Xò§/Ú :Äý:ª­#¥g Ûéãm©bÇqØ/ž™BŽÄN½Ä¶îZèÇ…è#Ž5O!±Ÿ”6;àÙ½}ZÊ– ’Û•îäZ c ·l™0ŸÕcÑaU±ªy,t÷²F³@²†Ã))¼E·ôÑâüógþ¶Z[š¸Õÿ³SÜ/ö?zˆ¢ÿ& /oc¹¿¢ãÏ÷bg(ŠÀ‚ȓΫƒfµÐ½äsxõw5Ë”#ÜYQ[ŸúžÀª ÄÒ©åÓ.«§7‹míÎêT(ïµ#³êmÙ qÅ4#ÕAÙ]éª Ò¥ãP¢x‘úãHnA’¼¼©ð±ó™‰Î+9$y×N%‘ÙðÉ7¼).mUÂJ܈«Þ?O˜N©•úõ¬øU³eIq7zïõ4á»;aÆ y‡~ª¥ú_û_/ î+%ˆ?×ùZ÷Ð…O&“5ˆŸÜsÅIrŒœ±*0Yˆºݵ]XJßÊ"1Û2Ì< àm’ƒôé¯çqŠØv¤cqãYP½%oÄs뤙k_X\,^NÞúŠ) r¹I»gžŸ ‰ŸîF¤ÀÙ9W!Œx£Õ«)-o¢)µ¼ÄaÏzÝ[®Kt\_JWW Úxtptš\ƒDBÁD¢à3â£ÖÍÀ¯u‰õ´òÍÚô?å׆~V`8´‘¸È~Òz_¼§™0Á"ûµ*è §D!%o-€ÖùÎãNÿEÌCär“ª„W]*aü?X’­±»Þš¼GÑ6,³¨| ˆ¦) ×QÛ«í–¡(ì(ïÛ})JW1nï±¾£½tÛ×o§ÒhL ­œ%ò7í=dˆ‹„à¤Ô x‰¸*£ÊŠªäùÅk۩ΠÄÅ­ñ%¤†µ5D{,à±<¦ïe"ˆä’“ä¿ű,•€…·±¸CPÔ7\Ã>c_ÝÔ{ÃºÄÆ a*Ç&Ù‹@ºoyH‡ÿê“D ¥Û©!–n ¥¥ËXËÛ€‡Œÿ1ÌR2EVé%íH¬{v g, vš§UïÞr1º g~ EW^žNÇ)¾ÿ|^nþ`Ô,¶kšóvhÐJˆ¦à–ÄK›+Š‹S¿Tà‹M±0>ÂÖ&D½n7Ëfö´è^æ›VDôê´ôÿ53HÀú*ž‰.ªWÌö®®~Qgÿá:Dˆ ò°1hm½B4~ºPáÕ³Ãcª[ʆþ:‘Ó»†HÄ.CýigÇÿT_Ú.Ô4k´†¿ ~‡?AR›lv˜hšB¦iµ"0àaõí¦[ÅBïNX2ºÇ”èbc„(ÖRÊx|!Nuí]øn Tjæ=ñ :Ú÷tѬ¾tfvÕ¹Gµ1^Îz¬©jÛµ»„¬>)u\ê¾¹-íãZ3I²<À´ü0³»P$·g˜Òè "‡&,ÓNTzfÒ‰Q¢Ã <Ï9¿õsÃí¶ŒƒPOvÃxhÄu^O«(¾²¾ÖZeß­’Úkyøán &7Û¡]nÕ‹–ßjS@Ï#b©ÀŸÝbŒX{å"‚Rª®¯¤A-ܱ56T A$œð÷³·íåîé!~qñ÷³èû„”“à€_OÆ:VøàêÐÛÀhãó“Ñ’ ©Ùªëø—©³–Xšth¸äE‹øMûòà¢,@z’aK ç±6ÆãÕýk™gÜ{Ø%¥ è§yÇ'Ãñ¤ŠòÐ~ˆPÇ$L¯s˜v±N+‹•ôŸ¢ë  á±øzPˆMÇÒn—ûŽÏ÷qxS[š¡v¶e®Ucóô×½Šž<@ #­ žˆ(øv)¯âÒ7w!ÍÈ 4Š7ôBÌmÓ% Bm„ Ò?f’‹ÆutfŒWÉØõncÇaô´ÒË¢ÂSF†æJìÎ6&Hùö¼ÏuûÒíÙùwBUsx»Áü¿½ ÷›“·ø–]íÔÃ’nrîù-”T‹VŸ&ÏŒþ¯VZÝŸ…>JÆâKèà´W¥ÁÛž±,î¨Â0;ïû³­^(ãFˆ…nÆûó'>áÀ¡F*Ÿþ™k/ü ˆŸâdM÷TÊêãø¦?Ε„{ˉnçÑúʯü §WöÎ7Õ»+d”zÐÝè]ŽÊ¶Ý–~W±$bÕ(y“’èÒëM'ÀÊÜ&)îm;¢±Lº#« ‡'iŽ  r6N»cÖb=j“ñzrÎѳ»·Wôð™bJ†âfÊpƒ·@ =¦õww‘A©Ø8ä"5 i¥oSäYÑÁ-z€ Ézàò} ö}ሧ0‘Ë|+ñ)\+&ŸÏ¾Ö¥„MúKÍ·`rvÿ­—°Zݬ…Ž\L "qêÕQ!£?±Rç"ÑóÞq´HB~ÜÎa÷«WlˆîÒÂAû‰§—Âÿ!6ìû™Æ¶â=ùŸÕøNñü-w¾ŸH`2)ŽÄH€¾´Š¾ZD‚¢‡ãƒzφ.¨N66¶çÃ4àä\T™­ÅM½¥?ý¿…ËŸ`Í-^#ÔÄ©óŒ%å–;pnÔè­Â*ºxþ9z;–MèbB†bž^( ë‘Cù̉`sÉ¡xªÒ¸P x;.óÇ«þ?Ú‚õs¾I{úqé~KŸP¶‡`â¡9Ârݰw4R9kûš¡@÷ÌRsð¨£7&ÈSY‚UK³uûâû>Y6C‘{T+û–émðP„9¬À¯ÞÖUzÂÐõ!ü!«fB¾ÀP,ðû¹a.^”÷P>„×6 pÚŠÊ© ͱJí\²¥¨/?øKEV´¤ƒ8Ç2¶‡5’6Xthíý¯†íh8tzck«žwž'—T=ÆŽÎÜ7JW´$Y91µçä59í´'‘7+ixu@²ÙËHÜÿn‰§FŒ ³÷¸ý4>R¶BÆZVÅÕØ—Í0ø¿¯À-U9…ª^B×P×@ÒâæÃaaᨣ^Œ¡²¯}‡;]ê´À·¸šù¿mûoûhßÚ™ïÚûhíût ö½~Ý¥‡ÃdøjnÃóêª!òt·GÉÑ(;кèpwràøz&û]?†çßo`ÿ[³ð.ÒÚþÝ¥¾Ý¼þCëê«¿nùïÛ©pøz#ÑòZ¿mÓ¿nÏþ×Û½¿·P¿m‡%Â>K/í­?n‡~Ý¥ï¶Í¾ÝRï¶ÇƒáÕ8>fûjîût—ø2ßmEü5óøhdú˜§Ô·ü+ÿpØÿp¡|ïµïøhý¶í£=ûiOÛ_ÃBÿAâûv*>zhGÎîûuk_RÔùúY§ÏÔ;ê²rùíwÏ¥8ùõö£þÝ–ý½eþÝK‘óÐ?V»Ï«pÿC\þûU¿†ÉoÛ´wÕ¡>¾«#öèæý»CûQï·i/·Sÿ7C?m‹ûl[ê¾ÿ6ÿ~ÝwçÔ±ü5S~ÝK¾ªß_U¯ûto¾Ý$¾Ô9õ,ÿžþݾ§ŸÚÝûj¿á§ßÁŸÇü?…Ï¿m ûT}ûW?mÿÕü¿†°CävùÿŸwÚµ“lh|=g‡_Ðv¾·Ã伯á®wÛÔ7íÒØÜ{öê½öì¯ðÕ/¾ÕKíÑÝût ×èù+ß¶¥ï·Jÿ@÷øk½öÚ_¶˜’¯%&|úûhßá©<ú”ï¶áß¶¶¾¥}KÑóé^ûk?àq>¥áx~ÚÎú’§Ôƒü…ÅüõŸ*ð"Î>^²ý—À~6%$r”$ƒêŽm¨=xISugÀú…9»”õe¹þø„÷G™s‘-þ襳¨X}¬…SK÷ʹ7@iCw[B§MTí ?={Ë1f¿e¢Š†Í IÇ×6iBzˆÇe…ÕåÕÇÒs-ljõ"èh~§aïÆ[‰ÕñôÁ˜Pbx¶×E“O?zï»üÖvúJ ¡JDâ8W#D¡ü¾çõ¢D5 /Ž´‰Œrú¹¹)cR>Éð %¶úë²Aᬆ¢%±Î˜'É_-^.X#/è,Êã @Qó4j„^ºD_aVv·ºÄëŽ{r‡ì#m¸Éϵ9–@+¬¸QŒl§¾X5ú‡&ßž˜¨›u ¦ÿw|Ó\åC])GĈ0üu Ì~· ö©ÚÕg63g£Å}s¾:5¿Ö&þÉù2ÿxŠã±g>¸ð—\*(A‘odÞq!”5¯`2D8š¤ƒläÂÞ`×^•bçè¿Ö¡CC8 à«$ŠUï$æ{¶BË0FI¥ñ:‰¸Wû+Ž3-ŒØ‡1¯x×õæ~K>Ën•?‹ ݯHÙ§íËP–’ò¤ï TŸ£@ÇWG™>؆QMu.ò*º9•dÉ·ÁÒ®,‰>b…¼k„ Ý™dcÒ`°N“¬žB# ‹Mo06L‡äq½å ¤5y ™HR™ïÁñü¥_í"©D†Ã!üY\û¾†ÊÂìÉïIlÐpH±{ìI‘|›møÃû¸¾˜AÚÑÄ×­[ ^ÿåOÑWù›L\¡È&ï=‡EÑöž%QYè ¦°8ƒpV×΂¹ºY‚À­dA™éÒE’­½òŽ ×¥¤Ý ±lÐzC|Ë»úQIèñûÍÞçòŒ÷9`rÇq]Òø:¢èQ²“\Fª«\':#…«rUÙZLŒ'Â@£þ}s`Qys”¬¢U¦ i*óõÏذ/ÐM¸ÕÁÈÓ¾„®Ò–³°\˜ûµˆ'‚óG.“GQ—óò޳?þ§îŽ1»`'ÇrI? [>I´“]{˜é?ì:]6M[Ÿ½.½:D"h¥Pe¶gt›†×ÿUÙ@?ØéùªL„))šw z² ¼‡Ê•íÔŒV³ßâÆŸ’"|~¯£øNí¥G¤ô‹Ýì)2Î7Ú5í^¡Ó''‚[q(ßž8waCÑY 65Ü’Þ§<ÛÈ@FÁ>õëÝ[Wµ*:‘1Z€mäXƒÀýf9Ô÷ ceF%ò÷ˆ¨ˆ<°V9TC Ätݺä®ðef òµ¿ÂÀRG¡-È ¦"? ¾O:ò$¤ ÙXóà}`’ªâľŠf—ÞÂk6%ªñ<«Íúi?Í’‚‘TË‘P¡ò@¿ôª&ªBº½`9@œñ½3¤¼1¥¡ŒQN+ĽߖM±—ÿE;ŸkÐÓkÁYÿ`új+Æ#Ò¿ÃF”§ƒ0YÔ›iN^<}€m0Èñ–¤ÆÏoÄ`ŒJ49z È’%øsäaÀ³³9 08.…{7^Ûi³¨QïÙé¿Á—>äF<ªÁ.XÙ÷½6·ffð'ÆP­g €I‹ þŸ*ÿ÷’ĶÓ’Sêˆ~½Bs:r™¬øÁPü).^¡y›Iª¡Øçr;͆"0ÒVx{üÚ‘W£Ht½x3k™xºm"[{oÈo§|­é)­ FCOô€ºlî óú3 ”õ7²5•Ü|y}?ÀÂ"A'Õ•îK[ßD€f™Ï {­M˳V_»£S# Âq]θáá§ ­R åPAÇËjÿE®ý2®À"]‚v9*ÍKg+~Æ?ݪør D{R6sOð%R)ˆãÑ×e î ß2Ñ ¹%nYn4˜K} ¦=TgÞtgÚÏüˆrÎMY6õ`AŒþSëM}Õ2ŸææL0à9ª+Í4Z™>Ë ;ÄF§®=>ÜÁœú£ o*ø˜,tþ°4—¾û—YL´O6CÏŸµlž, ëƃŒuDöɾꞲæjæ,|M.?ZÇ1:„Š#,†„{$Y±ûÒ öíIÐä$Ä%¶t÷ƒ›¾Ro“"l©Ä½Ý¸ž/6iˆ%L1z~ÄÓ@AP­÷üYýä¶|¬J•Ù>öR¨D•¡YŤéóÒ; &œ Íÿ×ì_DYŽ%ëzþ»ÿª¦èyùgl§š çÏ[…à Ä}Pb¹¢¿  äh«ì¼$êé@‡~n®‰\%µ¸¨Xr8;Õ³h®Þp|Â')¬Æ—xŲNÒî2YrVphP.Ö!FöÏH…}{Â}“ÉÿSŸ¿°ýsk@þÕ@DäXÜœ¿—¢ÆÓáÆ•ÓQ°Óº;½üƒ$H=æ¾ç| aÜw´¨±yß|ç$Ò£ºkp&Ôt±O9áR™ûeq;ÝÆOÁÖ¯ßëê¶ðrð<$(PÚ«Á*Úw$èà.Z^b–IóµIˆdsëu:93R5<õU§|¤?ë<”µ­›óØ $9v?.·ÇÐi¯[‰/XO8+Û!#ÞìùAÈ·‘1I~Ë]Q•w*Kh…ý#Z S¹Ä(ïQ‰™…Œh[‹htÅþ«WBÙeº^ù]|ï³M\XŽvŒ÷Ù9Ï*6²üÀPë`Æf4 Ì.‚¼\{h±Åpø_¦µ·ù3àšd¨ÏžD6ß ƒv›‰‚OAËÔЇ ,\Sç ”øó…EŽjnåÖ%ri‹ÓŒ±‘™ƒ½8Ê7PqŒ›Sé+Žò?Ä 8¢Ž´°Å#ÝbL‰øþ@ß…†éf²¬Q˜Tð…¯ÿ{&kÿÿÿ¯5iÀ±šiAYãv;ÝÎL|/‘…ˆN[øE.|Õ@á>¯Ù"˜Œާÿÿÿì³³g‹°9Yp™¿ô*v¤½>¾óU˜RÙádŠ~þ¹ÌL–É«ýÁ¶1cÈq#iþ?9à÷4Å-½#¸©Æ2Âú# oˆ:°Î'Ç)ã§ø¿‘@ï‡lÇ¡Ón lbA byí´eÇQ»ã4ÎÞtó»éBDöh9}L9ù1eBUuD]†SáÐR}¦òošÒ8¦B•³ã¢Igð†kj²¢Ã(µy‚9¢"=¶]¥¦[4ô¸Õç^â”#„Ež©A…ÉßÓ£»t~_†- …²¼Õé}`_Cǘä\ßv\âøIÔ¶ÆÌ‡KjHž¾¸'Œ‘ý‚Bëfsò)¹µ›‚'Hÿÿÿdº&ï¬ !ˆp¯èÒµbŠø&_ëCõ‡Õ.@5®\û‚çí·òà?æÓQ'éVØ £æ_ö=àbñO9ßpPÄÜBúR¸pó˜[`=óö„Dž¼‡põ¶¾…ì^ÿAJ܈-FìÑÎPЧ\º!ÿ|9ÍPT”MyóùöL-¸#BÖ¨Óÿä;í²ûŽ­-qA¥ÊÔªbŸ†ÿp™@\Ó®D¿ÿ=!©Í'료N©llõÿ~~wðŸRVWŠ!&±ÔOÿëͧÞ“…¡>´€ÓÊ©¶‹ÿÿ{+kòÏp2;’q/¼ú¦½©uº¡zÙr5JwjÁQå º^2¼$¬¯Ï àbýh¿@ãhÄÕ‘ÕQ´j4¦ÆçÂFã²YâåÑ41[°RáËKv¿&>±“3úµÛYÿVŸGþò—þè_åÃ>ð$Öç«"j8—óÖó*'eÓÝS‚|i)WM‘Xdá¥É¯œðƒQP\áÈ“´&Šg‚Ìé„å-пÿÿÿÙF³ öV¿ùßµÓ°ù÷…(Ì—¨0*»6ðÓÔ %"òýë‡ Ãt·k`ÜzÇöÖ_žê³–OšåÆRb)‰ê)6 %ÆÞô6Á‰XýHWÝ/ã´£Ö JegázÝ yQäx%/ÿÿÿÿ¬œ¹ÅØWéáv -ïúàÃ}öÄwÓ½Ay’J£&æÂõúà$EÔbž‡9ÂÃÈ"áE.5m::ô(³¡,–”žÿ {ÞÓßw¢+·Äª«=ʘqÿFÚÑ^Ûÿÿÿz¤AŽº™þ€e›MÆÜ"q!fCœ2?ILû4,Q›ÿœ>1Oî{3€ý€ò†p(Ø=‘‚-éä” ÜûGÒ}¶Ã±ò%çÚ‰ü$×” Ÿç¨C†As3a%ârä ÕJ8Iiô !»øÉÈÄBMJ 8ÿ}º^逎Óþ楉 ›3wWæ¶À ´Çª?ÿÿцŽÀ¾V¹hNqR1G†yI߯1ŒdÆ1‹WiüôYyÿ¶:­´0,¶uq䶪۾-e“D.‘x;„Qqh8ªBøÂu ¬;jbÆ–léMu€B¹Ïöä—¸îýD·Ïé4%ô—!¡c’˜:§¢ßÕÝa`õÉiÎJKTLO¢l¨ñÜÚõwµ²€ÃÔW‹2Ë?¹  ‚]ÞÝ ešã1ÙåU‡Þ-0Ø xÙb_CÓÞê ›zõ1pøiωR]ÛN¡x!ãƒjª¯+= ¬Ç׌= Ä’KÕ+åüMÙª4û® ÿ'Æml©Hÿ}Jß[ÉŠ±µ\Ùª‹T« »è±oé(Ò=YmÐP­⢤Ö=ËäB‡ rULôÜS:à5£¦ŠÈI·0ª{½$ÄØ9uE ééÿ€†l„@œ6!Ý{gE$R[¡ìCÝСÎI×h¸­# Eyh)F…èMÚFºi’ZD@k.Q ùdAæO­jm,Vü¹cœ7óßHlƒ·¡‹Í!°„1ÇAj´³Q]ÝÎÏO}@_Ì)¹qæ²_ø½Œ/Á~LÓÌð*1Ï{. ÌÚ‚Ü|ÌëFéCW•]1Õm°¡Ý-‰DéMmsíâO\4&”-ë<úYy2Xì³NMÒ’Ø®èUÌ žé6#ÌŒ±´`¡šŠ§ø[·c÷6ü—N©?žÎ"5M¤o{¶…Zö¯àÇLÞ…-±D´ìš/žÌ5ª]uSÿU @gããs2ãD„q.Ää[4¯×nœ¥7Y—“"ª¶_£Ey} ¦Ú£°±Jt&’SS:…+lb¾­9ŠÁ»¦Y×ÊqßQO°ÕZ{¨™[³ »0±‰Ýªú™$)#»€ÛÁëÈd•fƒ4޲ì³F_u¿ zP Ñ!žY¶}—ú6°¯ð±WÖôŸ£áþíÑL|l3àÊ]ÿT¤/v\ˆ&¼°jõãkhV/00 Ôìùcv;4{Omí!®³È†ÎŸî è²7‡åÉfý t¡¬ÿß½!0ÆŸQ²‹º Àª÷– ‡èÒª‡…7Ø7(´dÈKž`¢i)X*yŽchPûA{ØN{°ŒÂ}C‘ ˆO`¡…-”™x‰ê°€D!‚5qÀÿѰ¥xÚwhž­¦ÿ<‰J›ºoc€[¡1iÙ¶RÅ„#A§Á$gíº“×¯ˆüÖ£¸Wcͽúîè—º©{ÊùÀ0k-‘廘_9]-pvë&ïö%ËKTl…˜¶å¿‹£°Ê±p“S£1÷HË·¬ìZd‘ÝþÏñJ“C‡ÁÊîêy0%¹bŒ ‹a݆‚PÝ¡:pƒaëÍ ¬£)C>ëe0ãƒ] mAhˆùCÚÌ äã¿%="CCà‡Tï;D¹ bæ‹XS"È®ÆÆcqÛ^Yãbü+ÎÔÍn]½îŸÈ9¯³é_ÿÚ´TÁ±‡„™žÿÙ>…®Ž¿¼yû7ÿÁxÄøAÿy5TÇ÷¯±ÿÿ~Ž”„ •Ç(Ž„¸êúÓÂk›]-žXÀ0¯ÿë>­`×Òœ‹_ PôCô²¹¹2²-sZ•¥%êÏË+O'8Ô5Nù‘zëêeoÿ~fÛ‰j^5^´jˆæñ¬ñ•d={t!Ûõ+º%™f8ñÿô`Ñ ŒfvZlKrWË{M[ñ2Lî ˜5§þ U-–oX°”zOC,#kw†ªiaçTvú„Ú+SÌé‡y—Cj¬n­ƒo£\€…t1‘Và \6©K›@Œ¢Ð4†GNP™?³$cK‰.hXÎɪã— Ž`šB‰à±¤Ô•’Ý_ü*ÄŸsm‹u¾Ï{ahÛÌäÒ…„'-$ÿg `¸>,TlX•æÊ<‰¸WÓY{ésHã^1VJÄm.w¼NûcF”` E;îÊ@ÃTgµášÐZÊ N˜c}‘ßÊ‹Ð22¥M…1CABq"‚:–6áâ +±K=Âí*/᪹–À%b§bÞ»<ªo¨mõ’M>JfEëZg¡¨ÊÁveÖÊÜ4¿©F<¯à#úÔÄvîŸo‚Tÿ‘v0?šfvÚjb&k¨Cãï¼]„ ?éññ†òAý7ýÑÇ+ܤæE—ºtdõkÑAÿÿ+ÿ|ޏޠñð¢×ý.ÿmV4Ccº¸‹Åç^–Š;ÎGï“AeNW&U;ªü¹zŠ3œ?>§Hšg «§êö‘¡íØ¡$/v4g)ð’i¼äæ m¤Ÿx>Ó;Ò;‰ÿ5€cWú>yÎÇðóÑûâí}Ì4»¾í€®è*ø­Ÿ ö½#ùË‚O)"Žyt6ÑÖ‘y—´å—]ì—žIŸ&C„Å6N*6YsN‚ø—Ãmq‘KÍn¦¦,Áv€œ½·‚,ÖÂÌøð4QÍDÛ@wlÔ#/Ôè•ÉM”vc„÷OÍu~ yØKÒœ¤êTÖ3m†g0ÞâSùŒ ÙAlà5jAÁܪUýžÍ`ñ ¸ãn«×[ÑFþÄÐ=¯’–µò³«üëÖØN…W =zÈ“[õεrOòHî°>#”RV)}UMî}Æ~w©Ÿæw ^º0oc ›²NCºý?Ò‡tÆöÃ"NÃ>~uA±ÅØC7Ôªa§tÀG¦ßiW&ëë…TŽêìû'É@":G’(†pé< GwIºã’{÷kàÑâ:d€cÚñ¾LÒ·æZc…³qgNfÅýåPÕ ÄkB³›âvd.’Dm‘ÊþP€SlÉÔ– §LÞ·?! ¶ÐÌl>ä‡ÿ,š'ÓuBtW•9¤'‰FŠQ>ŒwÖ³Öä„Ñ ^Åíþ:D ±‰`î¨Î„c’Ew©b  ÿ:5¼T5Aà+©ëöœVøöÍ9j›Ñ(Ïœ%qdYÜÊxÊk…ŽS鸇çÃÚ€þ>Ú$}¸5·Ír!xÿk!ÕSqp}‚ykj?¯ôqU³’"ñhTîÂg4A§¥µ“àVÀ{ߊá\Ê ?ÔþUß’bçísèت•Nœ^Û$Y¯ú»—}Ñg³gz°yÃk]%+(¶/VýŒÝþ¶G1“”ä«À¼gF÷Ì LÈ׈‚sF–]$~j‹[«›~o"›œn=šo‰ü .œ˜©ò¬4Df:ðÙ[9ÇœV×wFycŠ+ÿcá AœŒ!u`Š˜#,]”Ê6 3¨u˜Î(L3ÃÃL¶ãõv‘Ô-ó—~éí€TUy1ÆÝž5,$*¦ÌaA•\…_Lùø®Ÿ_¦µ·øï­iXw™…°¬Þ~¬o™²i3œÒåü¦+„ì ÃTñ© ¨¬ÿwÿoA¼Ô‰G÷ZÎZµdműãÉûëO¥õÒ¹1¶&ågY·Q†ü¹‹N09þÞu‰SîmçÐi;ÙÛOfJ‚¿rÛ˜m£›”}¿ÿÿÿ×c». )ïtÑ›f…°¾(Cž«ÌZ¹è_øá©¿ÕWÉØô iÆó›GÕu×N/ÿÿþ ßã[·Äh‹0mŽ¢碧Ò 2EóPá˜jÍÒ53Ù ÷ `:â¢+ÓD[Yó,óø6|]ö[ö~¦§Ø›.22ñÿƒ;SyÿMûAQ’y ÿ$à8' j`ã*œÏ8¹aŒP`¡d›`䘶ÿ*Ûõ¼`)u?-G¬ê‹Û±ï4ÔÞ¯?—ž~Á·ÞÀþÓ{ôÞÅm 9ÂIÉN‹:æþHªuj¤QòÃßã¼_/Ò¥R]ÅŸmD_³nS¶r[š.¿öW”<óB†”¶|v‘DÍÇKŽY›ÞIÊJ%3ê+–mH†¯=›UŸlú¼5(Ú%xîD¢ Ù‡y°ó¥ë€ÿx¾òm?_Ê3£ññ&µÆûž;Î~uµPtìóƒÙsŊƧ? 1¾`§è¿ýá ’ûmÈ8L -ıÈNâ²,%0²(%ø©þù®·Wv ·4nÖ†€~Iä*ðŠh‚”B98~Ú v4Œ=[ƒöÖ-|€ù«ÆAÿÿÿL8 ªuÚñà.'†¨V6žÖÃJ¬ùƒ^ÕjJC”°ø6½Ô·ïYŠtVmÅ_Å ¸zXоºü1yZ­Ô(òl´ð÷8†,äÅïÒdæÉ>ÿ9;©(òõ½áÅí[‹.¿Ý¶ìLdÕyáÄðk èê®ö)7ׂ?‡Ð­XˆÜâÚZ¦…9|jòŒ£¿Ó×ílÕ•8æZ˜¤×7ÇÚÃq4bÖ,°×ÉäaÏ#1kéÂ_м„:uÛÙíT-- rª5Hŵ•K¾iŒ#ØäR|0v‰™úwåªàJ”h®o…‰!pÊ@â 4f^†I5ùeéÿV?‰:¹CÒ&]Lúg‚þúTƒý#N¢¸BÑB lâl%¸´‘™Ú )¾³/S±^Ó7¥ÿ#èB5‚ÄJžâèÄimZ !˜:”ì›XñŒQ“õŽ»Liä)¸‚ÐüF$Ò|ã; HJ´¿Žc„tauy̘˜«*ȸÔEQ7§ÿL*¢Eà ¢N&,aö†ûéœÄ~FÔ5Kbå`”G¤vkœ~ ?‰¼~JsÅÀÿÿðä>á‡m_õÒdKS‚Ëç!–»T’Rä:A3@0º;kÅ¥Ä:Ú%Éäq!h]A¸¼˜ Õ äzÁ«ÇÃRËÐõ?©O²Y$ î{‹TÃ=tI€<:Îî0Æ~TN[Ë©)¼CJcâJ½ÉS¨ D<Éë®)p ¦ÿÿœ.¤2>õuíÏö(fÎt‡á¦¦RgjpZPlC?r¦œ6 ®’%À¢¯…}J¨àõ\Vêûœö:VF¥ÁïöHÑÓ=}ó'DŒ‹ÊaÜ]/@`5~oü†~‡*¡:„Þ†ãu¿ÿÿÿR™ÕŠºôÌwUˆ¤¡DÄF*˯©S¤©R­®x£G¹¢3&œ‹›Û¦âóú«oá@8ôZÔœöÿ/^¡°„ Àr!*‹GqÁZ¡B®½¤ `è_ï/•0·2¸`ˆèéòÿXBi‹«íÐÀDžV›Ð Ÿ§‰4(ì |¿µh¤…Ar†¦5B™ZU£¨–fAÇ2‰6c„ †Æ.òÒ5m+/{§S3øû•-)ˆlT1k¡sÒ#?ÉOxR‘ºNÍó _à'L'ѧäh¦Do›QÅUä LØG[Éi“QÍ´³JÿÿýÝ ß4FÍiiYñÞËs‚jq‹ ¦Š­úâjՄƃÞH~oL7Ñ ç: º_Ô9S-èMØ®¹ÅúJÍs"QcÏ"§sèm ¸!Žßi%ñ'ÊU6MÓ,ú¾À¦ÄÅ…ž.»ˆÕy|‡nï°—#<Àbþ«ɨ/1ØoþÑaŠm±å~0›Å{î ÞwÜ"ˆ žÖ›äÖÝl›ò³X¦·[ "R¬*ùº)­{!ÐÞW_ ˜ét̳ þ¶,Ù×Eÿ~¬VÂÚù úžÌ´õ¶7†¾g{‰€î”I»¥ÝÎé¶M{c=3ËìïS䜂°M¢Ý›Öð¼B5w×%O¶™t©s°BDÛFÆó~ö Ý©fŒÂß>!ÙXÞ¶Ý)ª‚€¾,¹œYØü¶Zï‡À±%ÄУ$í¦Qs~‡óá–³2ïS¦dHxÅÐżíí쯤ž÷ü¸ËxÊDüÉmRm¸8Q÷@"cÂEœ££å%À¤þ@¾Q`΢B÷h^‡}ÊÓµjƒÆ¾0ºËu–êÓÏ"6bÇqÒæºc‚Áœ>1OíTÁ Ë_{>Y…`¢ÎôKÖ%Z%ÂfZ‹H@W½o¨äjA[& 0/Kpa7©š¦wpeDÞÿ_Špi[\Àg¡‹DkŸ<ÈZyí¾kDÌ[u ¥@_¸$ ΖMZ–êCå`Ãÿÿé¸5×1í®ü)=Rõ’a56ÉïžÇç•±ê¶ Úºçþk•D~ÒÙúef{ˆw¬Á“ä zÿ~mÇ%$,™ô!®g?«–#Gs.ƒ8s*±h9"œÎŸ#t­vZb8]IÅÐ[ªýp*:¨®õ§‡QW;#¸‰ÎK2ZQa³’Bïg­pä õ.D$~GÛ¡àSs:ššvJÚÂ1ÄX…M4°å|wä?°Êá1Ÿãx÷š2#“¬/H&a¿²ÈËLD `ùÍIDBjŒÑ‘·x¯¡Jº\ˆ“ }Fy4R9‡R¨]ÐiÀ›D8åô(‡ü¶~)^%ŸÜÑÛ|¬-J”öfôÒqµ·lâ:mh˜¼‘ý-H@Áïõ·¨g›Éâ}¿æW†›ò<ã… "™Ò*›¯¬É½+²ÊDƒç²aY°–Æ5^4d5¦WTòÝG*²Rˆj!AdG® ±Ç™¬}®Û”yI^ úô@ã;Ïa¾d?Å iÿyúÃ&Ä¹É YJ¯ý$Ùé¼ûB0¯ãÖª+sÙãä*bÔ9´@úÂìj%I“êPñhØz#AE!LWƒ–¤B6ì{Çwø IWÿB´öº²m ½&Vˆ²È& îè¿k4þ¢wÇb¯‡çü?<ÉÎ@@F7Ùæµr¡}Zú43>ñ ‘ /÷ÉQzh”>úÓ‘ @ã_lh]¥2dΞ6£žŸò‡Xãså: É…N¿ÒÀño»«™ñ¢‡FoMtôtm"I$çáßUžt½6mrÞ\LÐöÞaàiì¡‘Ížÿ2ô‡zs «å£†:Šj•XôönØ Üx´"ä >ÂíZ6ÿC:\7 ÔÜ®<åqç;Tšx×£UÉÞ:dãš­ö:Jã,TƼ0K•@Ñ^=þt´X=™të^¢¨Ó(ÁÑîxÌÕ‚G=ýzf·qIîX‹KÈÔ$åx£¦¯·½ªï.#9on’—eH÷‚F{Ëþ{&ˆbKZctÉÑ€g až¾÷øm¦³çòYi°9k,rÍÐÇ×8/FÝ/kùyñöýÒõçÖp¥©õ~> ÜšàÉQwÔø4`¶ÒåÀiµKl3$©ú„?ß’5¶‰²ç,®»âѧØSo1[ 0dvÉ Öñ„þ:“"BM”K,BÙê)Ø2çÿ 57餳Ü“ÃlTX½¥Ul$ŠâÓ¤¢£Nc!YÁÖÞö%ÄÞŒ. ©·Ý Û¥=á‡øW\Ÿ:]ȯL>±ÿow;­^01· 2è²ØÝI <÷,Âë´˜™ý.üÎNw 3öq÷œgL„.y–ë¦Ñ«P¨smñålpO¹c””ïA¶ó`e&ÔÃX·u¢`>¾Sx`?ÿ~Çåçïuà,Åö*S£_û8¹S µL¦@üŽX•‚3ÑY°aÞÝùè'W+!v`«`ÕÿGLˆÆÿmc$ïÕƒ:…r4àm»+„ð‚p fÜ$ ÌÃpÖ«ÿÿxòâù¤Š ²ž»Rz—-eŽ`§5æ*^2!9a3Ð#,‡ònœ}ÿówU«\p“Ar¿Þôañ’¶LA¦©WiÂ^Æ•;Hl6nÈÊ™$ØÑž,œ|À.[{6Ô1·-¯Ó¯¶žx?ÓÉžáœèJ(Ñ_¬æ*ªlþÜàŠ"ºJ‰V7ÿK(*m¢Ñ7ŽÝÉ7á9› Uõ×MWWîDj¾mÔÏæû<Ì€MHc4Þ@½Ï‡ŸÏÓµpÙ¡yîë÷¾ð_’Å·¸Qúï¨Gz¯ê0L¥3ÀJÍjƒß·øO°GSÕ?¢Ä†J+\†zàðѾ¨@ùH4¯$[^¶}x°øI…<6 G$Û²íIèM© Á‚À5&Àm£Å…oÄtåeù=ÞÏXÄVFqu5LzÁ¢çí2°1|£ñ]˜ä˜J·û|Ÿ;õ* oÀoµYm;ݯG@SVµˆ¡>TˈCUĬðåìîG†x8©LÃ5_°_˜ë߇CîŒMä̼ÝÒ“óur¨Ô&®àu<¼¨Ð¿J ÝIÔ$ÜoÚ~„×¢xˆ\èâÄufyÓLpÓè4JÖþMYøVgvè$‰1–w«ß 0o]ÛÐ GŒ¿ýs6ý>ö_¥œûI»£ô j»„ELqëÐpþ”(¼¸Ž†Í(ø×27.Jº{Â:‡â%çg¸¯¨ûš»ƒdg0ˆBh|_Ç£~ÌÈ×VªÉ.^§“6³Ñ£œ8‚ ˆêëIFÐûd¤ c_Š±ïšµqFewW“±K­@+ý+1†ž-]îã|ÿiý:—ã<xÓüÁÇÿéÒWœVúO¦ëD4Â*9VîPž•ŒÀBbÎ3áÚãÍÉsÅ'&P§ªs¿×È >OÏJ‚ÿÿÿñª?±°uSÅ5LçÔ rtIßÞˆ†çešn~G$éã…uM+£×æ`‰þÊä} 0]ÈžîõfÖIŸ7…±b ðÒ2šæE_#‡h_iߤn»qôAíù£ÑÒÏ#YªridRÒÈÌG.±{ZKÿ587£=ÝJ ·‘'*j£ó¯òб÷i,QÉéfîDp£u5€.MHï¼'ps/âLX8P±Ñ_î²Ê?#Ÿß£pŠ’¤"Èé‚gŽ€Ë L>EDpv<}ÌúIƒ![¬yz²é1ìØ_ ŸÙšöKâ hq>ÛÿB.~p ˆ¥³Ó4¡j#Š+Oê‰óÛ!§ˆñcÝ`~’› Â-^˜`ý*£`·a¨vOün­¾OWדàß )Qnš1¿ ÁĤ¢OðÀ†îÈ£”¯GOk4ذƌÊáò ñøÓ— «DËÂDƒußÎõ· þ8ºß|fÆFw<˜Y{£±Wý]9+bñ|¯lXGÇì2œêк”í‚1“ƒT¦M‰ŸÊ®’G@vñ38â\#iÜ„ånWدAaÕZ‡UÆ‚já¾Ç"þT‡<"-Ã§ä‡Æª>ºƒ G»„0ð€½"k´MÍ•¤Ï¿0I¡d­ä@l>¥œ†ÕR2Y¸¸*Áç7`â^êhÿìB¡³1Õ1µ/¯Éjˆ Gž;?:ñѦ²ÓY¹ãi`Á-…ïÌi Púqi… ˆ$ܼÖ!•z/«Tȉ¿58 ×&ÜzÏ¿õ ¬¿ÿégÆÿoNÕiÌ-ØÌ¶Ð¿¥mÅíÃ'^YâMÞïŠæÙvØ çàlÜeûdvƒ‹1Çÿ{zP ž¥¦¬ÎëŽz¤»þ³RÍøá0}^jmTœN­>oo­G­žŠÄ À`2=‡X’-¶ÀP¤Ø×QÚ›ÌåÚ¹ù¢f]œkÜÙõ×b$Š„ä!Æ-u4ñ äþ©Ï>.–¼˜Ñ/-ÖÍ…XšVåhéT®‘Q(”Lv”îPlT¸)ý )T– avÎ$þ&]â…h'ï61) ²Oòr’Î$™‚ý)2 ù9Κ¤tW‰ôdæAewÙŠ€.·ÑŒ±`^ôû«Õªß"µ©QAÈ oä=XÅÄkŒÉØÃ[]4 ´µÞã¢.M½&ë{åã,r7ꖊʨÂýK‹sGTh®z1[¼XÙõ+k^êð7 xNãØ~™ubhÌ÷p 6AÜòî„M9©½ª•å+M˜ñ°Øl6@ _ 8<õƒÇCP¦ž‹l8N—B3÷U±úïü Ÿ'Ü@ñ>YnûZŸ¥wI›îS™Gõ`ò…gqÒ–é5¢#'ÜrÔvîÂdoå¤féˆ(q(g̺8ÈôFÙÔðïp‘üLz5¨8x-é£xÒ¡¥Zƒ 4@VÈ®Gθ[šJŒØhaêTRcGÁ chº™e(þqþ¬gncÖ-_é’†å¦ÈXþ…äö‘/jdŒ¿Sü[ê!î‘Æ3\`xe#'ÒkwLTJOšŠÇgÞcØÇk a Àžœü.|ñ\­ÊSpåϺÔ¡s’µ)ØÀ>.ºj‡+¬õ)O°L‰ ‰PÐ W¬`°L*÷Ù± „úÖ2~]§ýã*£ž¨=*¬Áe÷ <ýzrÚã'.gC†ýÀ>µ»ÌŸ p¶Êmré5pPo¸{6làÂKÄ;?ý?) ÐnUC>Ë.=ŒCŸO7Û*±„#0J|‘­Hâ3¥6TÆÞÝÎ_õ`ÇðÖ%WËjGè<:`":sÒ$mΑù–­‰Òýåz²¥NJΰŸój=ÑeÂu|Ô_ ¿šÌ’L^šâ‘-JUcÔy:ªâðf—ÙÌç#XàßÒzûiP “ }ãÌM˜]éh4Š“ ⸲ðÖÛƒùN"EƒÏ,;€°ap'Ø-ج0Ûǯ²d@zîïæP§äÄcgÿóÁñ­df™¥i#xQË¿[Ï«'¿¶0bã ;ix{¥¤0ˆ2h5æd‘Å÷ùoç·aëº z ¾[_{DA=ÚnÅÕ¨7ŠòËsS†åyñíÐ,×]•³ŽTÉÙÒNKMPÓZ¨˜Œ©¶¡–‡¶a"Ÿ<#H Öb¯ê”褕Zu?3ôxP• R‡•P­9îò‰ýëK»[Œçº¢ «(…Š?K—=:«6 ²WrU%G0`¦å}ÿ4?ÛK,ˆ_,‘¹Qg÷c¹§÷Ú鹹ǕbQIb)ÁÛëåR»­Ù±öF …Zï}ê…8£XVÙc!¼Ä>»¥r¿€EÍVL'ò\ uÀÚÀȦ`‚vˆM€aT^¤F »ˆ$Þ¦ñg‹gü+†”ŽýãKºs@¶„!á´õ•¡ûRñà†}¢b Òd:0É£-âЩ0.“ ÇP4±1Ò%€³\ ô\aùÔë:\ !“Rµ¾3Z÷f"°Œ)«p‹AV¶¦[ýK{KœÄ\¡W§ +"%íƒ\é§êƒK„£¸Ÿ¼d]žéþ«S[³ÙÂ;¶»T­ïÅ×gØ¥Š:|¸‡,¤ Ü@#ŠB¬ê¾M÷І:eŠ!€.Ûv/”Ä 543Ýœ#ƒ@º³.p{óÕ¯Îè™I)Ðv¯ô®a©@:‘Xtÿ/ Ö¾tËEëB矂a  Œˆ¬2HÜ<ËD¬Ü~9d¦ÑÅ÷¨š£,u—­;š8`«!µƒXÚpÿÿ^Çâs‚½í£½$>!+.¨¹SõM çÀPÔÛ ”)('ÚG–™:‡°#ëpÍ&eW'¹HˆÄL;\!cRv³“YVÛIpÏCT¨Á9¡ì~~>qÿÿÿ±œ±ë¡k'»ç0™&JÅj!ŒcS¿órðv V;v[ŠNVnØsÀ˜–;è AõaÑ[Tªy‡`´ÂnVuUL-­öþ’×Dµž¬i‡BgâžÞ›#Xºd Âù³}žg*…¡Néç¤Í/¢·!cí´"ø#[0ÂJ¸ØD‚!ãYå«6Ç_-±„—^ã€aþ|êÄc±;nòòòóм<°´×,øßYÔ¡¬åd”íÿTÊŽƒ—l›AÿÿÎä*ô‰Øµð§€=Öuu1¨‘5À¤ämÌ©V~J8¢Œ§ {5¸ì`’å~V¿†ü>¦†Šf_eû‘…%¨?,£ûǰ¸ƒ7åYÉÍxngÙ£$Óè¿!, ÒHßýâUWäRˆ2ÁÆ×Â<Ð&D…eS²›Ž?/)ÆæãÄbój‹=ŠY–5ŒÆ<‡¢¼;^ÒÂ Š ì¾dsŽ£×[·¯ÜQN{DÐaÚ—‚A³-Ñe " ‘󛞮¨ØÄvÇzyè8ET$“ÙÆ%¡ö[y©~DæƒçèÈä0¡Nß ¶]Åä*×ST¥S™2ôá`(`«Âd+Ý›ùø„’Â[ã•ߥqç,3†ÚÔƒÔT;ê¦[0äbÖ°³1ÊhyØmí¡+eòm>‚¡üø¼Rð†g*XÜ‹LË™ƒƒ¼çû:s¸‘A¢¨ù€¶cE_¾ÕÕ Bw¾Ùv‰ÃlZÜhÛŒÕ\X¯iaê'­5ë/ãÌÌMlð÷´|wÉçQÿÓô¯øöûœZŰÁQ-JWZ@ÆK,\‰éaõ6X¡ýØ!ÕAŠy|»¤"Ü(G98kпÈ,FY"Ki¢:ŒÅ S¬êƒÆeO0k>K[†”&~-”I*§«Æ*g6áòi Pç žAÍš ²®Æè ¬%²)ŠP}6ŸõÛàO¿õšÝ7…|~·*Û¾«ã1ðá§²4KBóð=w§ŽwI½¡ÓT€ÈÖý»Å;ÔzÄ"xS-(GýÙË‹Š5˜&A‰’6m²¬_%5ðª®MvyxO6 äy?m¾ï©˜CÔØÒ<ÉžÁê an@ÔHe2ÜëqÿNˆÎñ€ L!(Z›  ûÍ:UïßS5.G½çÁè§uïs'zHº¼Å|³9â?æ,±ô.ãBÓ,µyUEü¬&ÆÝ9Y+$'A^¥—Àd£AxäþrOl¹„TCÔ©JµeÜ`±úåé[™·›®ò~ÿrO7­Ý/™{ȱ»^°køÃKBȉ†Xáe°ô篋æ¶êÕÙ ÝÐ0Rô~»\^¾ œ)3,Ûç>¥¹¡×¦l|xT¢!½S­aÖÿ_Öa DejÜ^8ŠŒ£T½i«¿¾~¸ÞXHm¶0µK@–Id—÷Ê&LÅV’¾¾'áù)8E¬ò£kqæl@-Ti6!̬·FdâŸÚ5Xõ°•oòPPÖÅÕpô^äNVÅ{t¢°•W‡;Æ$»ýEàÿr´+·¿íÍ8H_V_£%©¼­ ÄLes—7Ä`Õ;™g´Þ9\؃§œÀ?i™°½ØbjgÈ0×1j;ͪ‹/òÀði;|™»i¥›¤xŸŠòŸó7LÙþÒi"=¤ÓÞ#dYäjV/ «%ª–ñPèrxèô"€¯q{(ð¡ÀăF̲Þ[•ÑŠÚNTû;×J£Ó¹ ¢ÞÎ-¼¬_:膵H]À©ks2Ö´ 7«¨…$Älþl6„oÐEâ»Á&*ËCg‹²ã1˜íö†È ›|±¯Ø¸M£ÛX<2N 0ÎéÙ§r&ó}ô®Ææ`ñF(V²àéºB¬ò—/A-ÓºIÓë=ä{36Có±·ÅÈX„`Ͼlä-'Ã¥ñÇϱŸãj­z—Ÿ? ÃîNõø2R–£ô<½@¦´tPòíÕ>l×fwº2d°ô§%‘6eƒV Úi:ÑÃΟFêßž9Ú™žl›~ÏÕ²æÁeê¹[tÝ5/€‡9rjÎy°†ABî rõ¡†F¥™/­1B0;*°ÏäWöšï1‰€¤H+6"X&i8´¶~”ŽKG !½‘¾îm§¯ÒMYÕš.Á8ÞÝÛ!(Ne´*RYÀMš©ÆZ¼qèü4éŽJ:Õ›ßì¹1 3®¿WÏYînXOf(Ï,U®ž~ƒº5·dÖ•]í9L¤ó ¿u4‚‰®‚š`o ›€%XlTä‡mÖ)‘jª‰ÈÕ{ϲÕéZ½Ó£„Ç|¯_§†ç†LÔ´f6òâL¤Aœ®~$ÏÔ›&.]¼2]Ñ0$o ”ÓJWÓÖg‰Š*4'ã­ƒ4—ev0\!,‡/ÇŒt7‹†tÕ Cú§?º‚H°_œØ¯­) ŠÝ ¢x†õòK¨ów°æƒ¾©RÖÈÏd¼¬¹Y¶­/±=7T¼h…Uó›Ìg¯ñûœè_äž œ_#™N jD]>þÕÍЬà#ö¥Ê ¡}蔢“8‡H èÆDܸ4¸yÝÉÔ†þx\‘£cèê˜U[5…4ëøœý'À'ËÁIˆöét>Ó7­ßz|ÑÔìfåöþÖÅëWZî &Œ¬JXOŽ\¯i¦Îãp6„ºÍóúÝy¯¢’)æÏÀ5}DZ,Ù½¯u ¾„È“øm­6ªÚ^ä¬#¡¯ƒ/ø{4)ŠSe¹q]ØiLЗH¢¸lýL¯¥A©é¹SÈ6=q¼”Sª‰L¸ ž·6:ïñÈ“F„î’d:ÍhlI|½ƒf›Ñ&뵫¥˜›ÿ|ä·³XÚ¡œ“ó?ÙŒï=´Þ]˜+Ùw8dð¡ÂÈCOÎÞð)íÅí66íEôÓ¸U'ö ÅùÕŒ(ÊgÙñnЈ¦D´ªQ~»Á_À¿™Ž}rìHoôÉ×5e½ÐÕo >btu£ù¤.d|ÒÃöîs$þÀéñÙRŠÒ"ÁÛ,±¨¬¨ë·Àê$»0u±U„Â9A-{£Ñ„üÒA™íÿl7rS#l8PV€6¸þÇ‘ÒW!>ù, ÿ ^ïçQuˈÎåÇ pÙÈ~î‡`Õ¾*'©®( w¼RMbòú/ôxN<8b„­U3…YÿDÚO,ªøëÎa:ÐüÂ%.ñœ 8?+ZǾÂd‡@o”(–ÛŸ>i ­UZ5u’aÄÁج0)>×n'nÞcVðªpœÛþ¯neÐÀ3‘„éÄnA ÆÓJýeÞLuا<ÙþýIK0I¸–- j.ÏD×CK¨:aéôD ʾR]eA€ëþE#£þ4 rBXà^¢b¤=d<ý»>n:V–!YJ…”eˆ¼‹„Ù.8Þì=º€Q0m¶Ì³ŸRâœ>òÞizîJ'Ê^î N]Ò-òÿ8 á»ÙN§ /¥“i¶u¾:-8ÍSL›9‚ÕÌX²Yƒxüg ÃZŽ—}³)pû¿q°%1{1LŽRq¸›ø×;–½„ìÆ>ÃA§i§Ç˜q‚<Ø&M]«Í áIÕËÇ€Nÿ(ÓÛÕÑVá•»»‘Tñð[¡!ÃÛs9i(zû_{„ÀOÆ¿`EœŠ¸Ä½ÿ0l©,LŘ¡Û•ô n7KyËû÷·BÅä©V˜IêØ}B¯å¸¨·èmlLkT¥Cwö$`$B±‚%—él·2k(ÑC)–þ‹tÔ„ôŽ›­=°e®ÁÖku09³GˆØê?»ÁÒyø—4€aod±«WÇ-iÞ†—©×‚¤È†SÎuiCíâ82å6¤! ŽÂÝÎ9•·§ç×#;øBsIÎ|„.ŒÓîÃsÿE÷ßv|p¨Ò³à'N(h»ë¹8Ðä—ål° yÖeØÂ”¢e>ºü‰A\‹È÷&‰ø)ªžÖ œWè™TE±Hb%µ”V¯r}Iå#Ããd˜ï©GûóßêÃr 3À­ʰv2¢o«Bâù~í:G¬î(ÌCöÒL}w¨ƒ‘΄ýà0§Ûø uÇ$|û~I´m¥âaå¼[¨);ãWhrñùcAóekÁøñØ1†^í¥Œíœ ‡¾ËÛ‹-²HŠÜ“àÁ Ò‚Ë-õ‚BÓKÌ"Ĥe…ž;.ô¤¸PÇŠ7™¢-Ä›=†ùÑlÀº7“K(›ãxø>×é*Q³â(yFlZAÇ6,×%ØjQ½ë#?tLír4YåÂͼ üô °ºÌ=µh`¦8ÀœÒ•ª›¿ÕÎκyw^g£Šà*HÙ;’ßNMØÛº‰,M£<›,Ž`â=ûø³9DåýYÈàTj·¦Ï.fähÇ–Œ–“Çâ)£A×Ф8EÌÀÑÒÝî_ê‘4èÖ_ñFï.耎ВRc hõ®È7ëà^ËŽ\[&Òrdcþ¹4yVëÁAdšÒ-ÎTÆz›_ýo¥ð('a›˜ÒŽFì»RßSg«”[”Øy¦IýD)ZmóVж¾åiÍ Ûš=jJ*ŒódÄ×U5äXˆT=<ʱ¨[Ǻ,´2ü%a§;Él¬r¾ƒh7¬…líWxv^Ï+ü–C(ÍpWa{LÈñïåìHG6–ºw Ú£‘Á ”˜‹u´ïÓ«2œ„Û>iäÿ!¾ÂJI> Á¡äM˜ƒ¨YÛGeUqQÇÀ(ºòH¦ÔE'‡ŠŒ3 ‚.o`Zÿu?¹¢K­Mt ï†`4°^`3\­Éß%rnÅß"¦‘‡Fü¹{èöÕŠ+õÞH2¢o3!·¡Ÿ.P4§\Uô‘³fÜþUƒÀ—•²ÂiéÜ2y ª‡ô¡Ñ"æ`þ$C=Vý@–¦ù, Œ,…íË!q줖;F@ó~X¾Î¨v–As íîdÛ{öŠ`ÒÍ<ª‰êDíÙƒÓ“—bÈÆ'Ür¬Jþ`™¡ho•H3õáGŒÒBWEVÙd]íà–fÂyîãHW½" ½úk.cq;»¤Îÿ|^MifÖk8Ÿƒ&òGìë)T¿-¬–úplƒ_fèt?ñë‡Ãž¡Àhy®¿¢YZ :Læ3ëEVø9t…¬4ѱÝIôÃn5R¥øÇ0't!±ᆤ«Ä æ[EËÿ å¡fÌ·œOIÑ<ÜY86²,zºäá©ãäMs¾wä5¾DO”·ÚäÁÌ× Õo¶¶/1gLðžE-øÂï.’䦉 k†cT*"tÊݤ&¥W‰Ä)줰ÀAaJgH(yÌE +ÅM¹ŸU¯FU=Íà–ª 9õÄÿ%߬vT œÞ~P²ê1Ó¿X+±*‘`†òSŒ÷ æøaÝ“eä{ ܵ^k2Ø/>$jú²UÙïÅsëcjw—™ªroè§þ´?¦‰´°†YZøA-Ò5ƹKn›UÄEÊd`窊_ëü‹°Ó‡Ö¢"¸ ˆ«0Y˜+m‡·W ¦Øb-Aø¦÷S÷2GÖŠg™ÿFþ)k3!Ò£.™7' B«²:šJtìx:¦g&ß”{gv nWñ+b1â0Œjù-òú¢Šd‡ì”„qrµÁw)nai@”¼Fc€2bd²ZEm±)R×@áM07õ+õöÔÝvlY!fÀH£X†ÙñǺ;h½á˜ÏlDPk(õO#õ€;9`Ä_ùö1€#¸áC¬Lú¢B›s©J±ûÔaÚç;U;¹ÌÌdl„É»zLöÂ08ê¨tÇÀ~*˜ÉäÕ÷°Š¯^Ï|®Å$Nõú^æÛ,,Ôª÷& (iÇæç)Òð¨ãa {;üNu(†Ô3\7>»HPäï}6Héÿâxô“N¯\Ä÷­2ºáøÃè tfëüÜx€¢ÞópúGhÇžƒŒé`ÊËÔ&#yF+O·N#&<ÅòجÝSbò†ZZô«ø™¤ R˜ô¿Õi±ÿ rçD›cñ­‰£Z¼ÿ2s¿øwmy1ŸÍ~¾ñ¿2ìADè¡Ë#¼ ¥,Jß.KQ >ûcì ÄH¾hFi a—KhÄ£{ˆ>:7m¶»íTƒÈN !%‰ËAý‰°É¸_i$Û Ò<;}È^zÝz«Ã•PŽå8•È]Áì|÷ £FÒƒè$OP‘6\î›H„)f÷¨Iœ‡®Í‘sXâjƒêÛžËÂ.w„p™N13†ù€ÔhèŒN Pù`öË™VïWgÏÒüAÞ@Ái«ïÔQá±ø…ÒïÈüº(vŽ{|”n>Œ!*ÄTéôtÿ°£cÃâ7§ÔûûTÿåoBx(y {W7ÕD¯oüÊøm,nnàÓJ=«?®ò¯ †ebÅÂŽÿuG JX>0YHâ#Ž qI™(3³üØ“k<Ë:ª­÷è¡Ò/Nð)Šâho/…½€×5½œÛXØ>ÆÁ³:* á’g\©E„“ùÚµK»ÉˆÝW¯oþJ¬þc‰“v阫^o:%îuŒbR47î¶€S7£²ügN{'2ô ãЊÞÀ/54fnÔ¡Y£D«â.7-^#­Q°«î2jÑðç[X‡gù¬£À»ÏÂ]Ò4®lë¡°N]D”Ðaò(¿)ôý³wY†#mS÷PÚ…ÑÓ|ŸóÓ4ø§1y#y„DþÌyùÿÿD‡ÒE}¦'_ÛÆd¼æ@ÙKÜÞž>€q+b£a!õ¹£.qv:k£ ªzón}Æ%Y@ûÁµ×?]|#6X$ŸÕ…œµS&@Óñ›SZÙ“·šœ-"|Pª®OؽàyJAùÒb6 hÒËõÕų'¼ã6Ñ} ‹Ý[¬0-ä½YÍC¶aaé¿qNkùK¤¥ÊS+ßô·6†k%ÂÓÈ48AÃ×#N™øXê;:R¾Çn÷ºAÊ Â< )ZÉgM/a ê0ÌÀ0ËáºY†o~c?ƒŸZýüzÈß@s¼ö;‹ íHÊ€£v1C‹Ø©Õѳš#sñ1™D›¨;ƒTJke!Û‚I`¼,¿ Ao IMÝþé„óz%«2Âc´õw¦ÿ)Á¤Öz9ºúk’o8â ¡\U,@ –„V2ѰOddëlpó…®Y €²”x‰r>Ñù¢ÉVHýhY¹\´Ó.¹:‡ç˜,I ufqFŽY§‘QvW•§ç“¡æÇ;†Ø¶6[°-M/p99ÿo£WXAú´9!²*‚Y™ž™6}׿ý6RéÜ6Òöƒ{‰¤?€!^ uüì`7²3"•Pá·QhD{×) DW|ä¬ñ>ÕQWRþu½ùØW¿.æÀœ&ŽŸD† âé+h(Mâv$<{F¤/ $ß’†ËdÄÙ”¶¶29¼‰€D¹ˆÐIý®ÀâFA&4Bz°TŽb7ç>o¸Êù•ÜPzâ‹á«Ùîý¯Óº Êm ]”w»ÉŒ½Û ¿s ƒz‡D‡»–kѵÏ{óôú¿«Îô:hIÙ”“6€y Zñ²8­ÂG±Ö4#©™÷z»¯ÜN€YÓÒsÚHûoQ[1Öžã¿>Û0hypsD´,·•G³Òç+8Žê*‡w½wbAÚ@ùXÌgúq»?äœÂ¥U¶.”ƒ›K~ŠpUJ²Æ#}.8foë©S`)¶µ`î¬Ô” ¬}+o¯‰ûþ ·Ÿ‚ÁA¡iÂÕãPà!Œ=¿ï¾ÆÅ±óùŠ0(ÿ%3„Ú°S…d³íY¨óâ!ëoSpb1’)è‰íưfÛw¤®ÚADŒJ#œ…ŠÁL¶»Ôh>ót)_l$Ɖ#_ôú¿ž‡¬Ñ[¨LQº¥˜üªþd¥6VtʓÇ»~ôtË-_B½‰pÝó¨ˆÇÙ»Ä×&i°àkÁðÉ*}Mà¨ÒÓNË×Þ:'´FQ›fºÀc«8¥ùqq6aføÂ÷xV±h 1†Å ¶‚F"N‘Ñ™ýÒ\id1­WXø•ÝV ”í $Ádã)bµÅpà3k,ºú—ۂ٢nöïŠåÒC&jnÍ´‚+áÚôHƒ&ÜL‘ò- J½9ô®Y«0)ê‰W&öÌ Ž\­RJÞïÛžÿö• $ ‡:.o¯l#¸3‹0 ¯±œ¿–üè<¤,Z Ÿƒ{邎EÓÚ9Â6)kGŒ2ôˆû¼|ÑÌÿ{íà/É%ué€DCKnm1×7õd,µÄä÷•å=åçW]— äÐßAÈ®»àY?üŽGFxÕÐÆþXQvF°û ЮËo¹eç¬I§}µ‘ªN¹EŒàÃ:åQh‰}ÖÍ&+«YÎ=WL¾5&"J 4<96ÆŸ—)ß\ά:î«V j”p‡v©U£%Û_-i¢èYfebYÃÐÖ”RÛúFÑÞ‰Súÿ ngCøºõͨ-„ག×þ $ |Ž€H?Ø'ˆGë‘AÃú±›AÍÓcíniJ²d6Ù:ûûêÁìÉ_N¹™ï›âØÀýƉ„²çµÐ}8RO í6·“‹í³‰d _u²@¼¦cø€eRƒGWÆ´Ñ!>²ô\€ÒK×S‹*Û£9ƒèšÆacW´“#ƒ‹x€òÓÉ#ç­ ¤×ïÍ5Dc:äX@âG²õ+Ò^T4~½P'¿†œæ3 Ö(½ŒÿüÙ&U9¥9éÿy—³ahòÉï&±¹ô5°ìNyø¢©¹Ï4 ÷â+À\ŽòfŠ­HXããààÚùh mn¤@h‰&¾êõ2òŠ4aóö©ÐpÞ½sùþl7n /¶hêäu|ŒRnãõîÏ|æÆ(.É AJ—ø4À Ýxj™aþ)©ÆÄ :¶ JhÝÓܨl›Ñæ?‹õ-Ý#Ñ¥ô³(Þ$kÀÂ:üŸ!joÆròñÌAŸ«5е¾oð»%ïQ:OÅ`¹íÿIÁûCËú®Ý2§f°…p 5å¡?ö•õGQb¨Mš×¯F×04YÅÍP(Ä·pi¬Ô2 ¸HªßÔŠI¹¦Å+¾ƒä‚ûÊR[ÜÜ0ô‰ÿ׬‹‚ »ŠÆ L §† xñ˜Q°|¹Jx¬‚ŠÜÕi#º‰£x`UL-Z¦ ­ÚÖà¿»Ù:ÚÅàð¦Évž(‰ÞáeŠ£XÿXÀPuè¸É©÷–t”Sm¼7Jˆ^­A,þ!TÓ´!Fñ°èϨP&0cçÍ^(K#aøPÔB>ž¾¨ï˜*åFÁïpû’•ŒŒÐðÙMh~Y 4ªAA†¿Éç½eXN½Ö$9;Ãñª ò®æ€Œ‚ @ (9{Åä¶å—ÄÂS~C¤ž´òa¥{œÈÂŒªB†U=ÒîÙ.WTxõÖuÉYïS(ÐÀu\—í (k…¡w¿æŒ°Ç”B¯P »S‰]Œæ -ˆ¥4¦V%q“#½ê¹æ#3bêTœXAâöËŸ.ïN®]t֋LJ½õyÄ}›¸AÚN5®‰ENÖâŽCP¬êû©/¾[Ä­i­ ¯Ïeò}$²Æ€¯›îù¡wÍg›8aò‹ò@mÄSO¤ów?ÈHÛ Ý…¿6Ö¾AQJùŸƒ|œØ½ãwè#Û,&ƒÔe¯ò_•?èÅc­~{z„v’Q€)GzÒºGpäÊÇ~Ûû×]ãÝnNÞoŒ‰AÐÚT ïÿìBă,r·%kç|Å¿jŸWnt^r@__ÃÉÐ#!xcyä™)àŠ¡Ijô§‰Öh@Z9¹ ®Ò·XBBT¨Ç¦tn³×:uáW!®Iq¦þN&Ä`‚šèhaM½·ËÑ¢‡ÝN¿=pƒèÈ1Yhc{E cHŒ2TŠ@cßzZŽ:Žä£cqÙ¸ˆ‰æxÜUL…Ú#wIYë58þâò Ť¤a’ ‰×–(èÐí±Ø0Í(äTÇà\•³ô{Å/fÜ{¥)„½_ ÿ7·h.)Dëx¥›ÿ vh“¿äa’ ‰Ê0¦‰f®ñÎÕ·¿òZŠ¿!²tƒ€·ÈG3ÜÀT¤/ã¢Á¹‰û+€)|}¨ÈA†ëºÔg·LA‘_W@–h8p^KsµGͳéáö¶eÛ_“üˆ©/> úø™…GXUÚSóbL‚ð_õÌ?á’ÚÐêì¡}Ã&Ê _|óôbCH4®;¥‘Y]†Sý³g>Ž,cﲋH(ög§9è7´ƒÌnïj«(¬éžõ·ií`̼;rrµ^¸÷ðî¤ÀÅ`̱d8ôÕÌpR¢qm8"¸ÄâÓJ×ôѺ7q¶…0ay9Bþ8¼Ö Ì¢’BX ’ó~²ã­ŒBÓ^Î 9‰Ÿýû¹Wµ«ÈÅâKKŸòUú¿Ög¡{ºÜqz8„Œëë(@Á²bfì"„[ÿKAaC^B)«­®–¨m]ëCšdðHçº:5&?Jp•†jošw ‘†J€CùA·ÀÎÀÑq­åÌ £¾bÿ£b§ÅDó”sõkÞ¡Œ$‡} RxUü§ù*ê: @2é= ;ŒoÓBDÝrÅœqd\+÷ƒþóö_z˜FÓÜÃÔb‹j1VÿmPé¡ûÇ]*òUú´ú¨ª0¼D$#µüšÌmɨuØÒ#ñb‘´4ÄýêÂÁsÅè ¿Î a!+d‹¤”­”¯DšÙm|Z"ex[;«ÕˆÍd¢JÁf§Œ$#Rˆ$@N~Š©ÈwMÁšŽN¾ê¢mñêÌ ›Ž™ÿ…3Š/…„%Äx-Ï’¡C½yüvÄC%?Áî´Îÿ<’;m7>T6üŠÏ„l/Gÿ 9§dÔb‹j1®²uU¼³Ñ…Ø0ÿòUú¼ïÍ_ÃÏò‰Fôˆ¨oš‰ÿ5BFAâ³âöd =Ì¡Ã<Š [kñ;a7¦JRH $%Êøá êF¤(–EV€Ê9Ñ·«QZ'¯ ÍìH „†ö#Å„º²°¨ÏÝ ¥ÒHYfwñ´±{NiðÇCæêMÜè}¡ðNÄ\j€3èÈñ˜%ž…÷Ga÷”€sŸ¼”¬¿¯ûú4ÿ$+ô6D'(J?qÁ~R/¦`öC 2ÊO Z!EDÍ3™]-+ê°«ÌwÄDÖ ÈCþ!‡¡X3‰JÚ'¢X3‘!y—&,XШÅÇté³(ÐÙ! áwòh:JÓÀ€|w–HÍ%þŠó7pL-¯:&}³¡N×uT(ÌÍ-åPÆ„©ü$% OAÓŸ-Ì<¢·žß¾h£ ‘@úÀ'ÒŠx7;&ê/e’„¶%O…'$À°ìî^¬_’ _½‘8{4’V64#†c X¿µÐ9—Bÿ5Êu÷3北 •Ì:±Â/"A©›Oà€àÓ³ ?kŸ77¨\2/¡Ì{÷K_Ä•­Bäò?" G;tÁ’Ī™VKcõm_ÛØ†¾hxU#ãÍÑrŸFLÀû09x£%@ 8J oÙ¶¬<âgƶƒH¡WmÜxá[ãEåüSò¸þQ~5«Ñ¥_m3*z'‰c£ažÓ² 'ž-±ƒ Õìß¡s宜»jKZN{é£$öù `jï×^&§U@±ƒWšaBbXpñ‡Ë©‘2¬ÄZ¯•sv÷ßð2òMl¤þÊ ¬›'©f¯2~~Cÿ&£8÷ 莴:ÁÒ™údž¾^7À‡ÔGË¡:¿cV*aý7ÖµëÀ)Õ6äKØ+0*žº_p˜òpø5>3•þ„¦ûb<†!‰®ÎÛ"v y¦8š_4¡¼HΉ³½CE‚æ$A3”%Eßö)¦Ìè¾ÀØ«#*ôo=Ý@j¹ë¨1¤î?GüçqnBÏÛeÀ3ïY“qÌéã`% @8”ãÅ ¶Z2É}›te…‹æ~ˆ_:›IèÍæš$é:wÜ>=4çuçÄ‹Xl]L û–Prsÿbe½Fy”[Ÿ‡Sý„ëž|Ø–h2¸Ï¯Çó`ÃÈ®ø<ëâ×£œÍùò% …u±ú¬ëfk}ˆYW³®åÛ3ÛÜ”ÅgMO#r£u RÒ¨•Ήô¿ÅE8ËnãåaG©¼¬K “©ËÒÙ8~ ´ßt‚(ÿ‡drÜ5P¿åÉvØXò ŒÕÒ8®kÜë;“cÙÐ÷û¿k·\êŒÛZ^ßážíê²#|×î¹ Ÿ¤Û@Њ,Md0„NšqNŸÄH¡n/¬•€ ç(€Có÷ uçR©#…/úñ_üîÅæ0¤vŸ] Óá.7ðJõSšXÒðùVZ¨¼Á^°Ðغ:ÇŠ¿œ°Ì¾½Tz“èýä¨ù˳ErØ,Ä û#Ì/×Ú뱬»Dá:·6f—Ž`=Öž'ÒQu×)ý­—"WS̈½ kÜÚ©{pÐô­0hþfûîû¾“¬WàZ4D¿ 0hc¹ŒÊÞs팳/v—´ea’á%J‘ ÁÔ»gg©Ê°•&ðÔf,Ó=̉^uð¹Fí¢¶ ‡+ni_[ÈSÑë8¨F{ùŽt9ÜS"yéxv|.è7ãµTp×ÈVXeÿfX©Ãàô*áÓQÌlƒ&Úeb$hËœÆþ kkAšFs¢f¤×%(ÿ|Zº_­ž‰tQ‰Àôù@!õÖø?í]ñT .WiF| °›«v|;_Õ59¼c¿SÛ]èטÔcAc€zá€Gªhp.|ØŠµý³æÍ›œL¹\Cí×áP2~IH1á‹Ñì/IhbûßÛ\âG‚†‹€%™pû5ä·WÕ‰ØÏmiÉVXÁëÝèþUG&‰ÈöØK¼Ð\¼ÒQhØÞYeYSÔª~ÞÊÜ€€6 “Ù5N´ p<Æ*öçÕå{8{”ºÕöÖCJ6¶½†AeÒ®xWŽtµºÎÓvâÅ·~ EnP,JÌÕ ¨ ‡[§€)´evËQ­­ã¤´pÿ'c‡ Yae2¸ýßàµ'Jh'ºSY¨¯`igõÎFeŠ5Í» ŸË‘+„ z&›é›a!ÃíPn„ä»PH ˆ¥“ÚÐ¥Bÿÿ P×AÌʪ»ÿWɱ€/å ¤´·.Š„!eNš´hWÿvn„IR¢8UìúÝûiäÉX,hïså×<€Ì]–¨óγ¾ô"A¿ ë6‘²*æ ˆe÷°§n Rµã¤´pÿ'c‡ ¤/êg}ðxÆ€pnõÂct¨yh†|ô1bPÅ>° q6ÊÒä®|sBLÈì,_ @敻˼C0–‡zzg{dž°#$WÜáìÉÍ7hÛ`ï(ü‚ÞÙvpÜ<Ò’» ˆx/ÚØêòp¢)Rö,âýþ Œ3Œ¶{Üa’ 0”µáÏ}"]. Òâ$(xŒþ ؃·ë>L›ª|„R¶‘²S• á `<€˜HJÔ¨˜yz¡=¾ç&Ƽñx«›Þö°ô ×ÜŒ/Œè9à¡Áïóu{½LÊŒàõé¿æ|‹üê÷½¦ˆOM2(ÛX–à2u2/"VÑŽùè(£e{ |›qX¤‘µWåpdSlèaé\¾†ƒ×kþž ›Xn@ Y$½ñv!cqjy~dØt©(„Ú“â˶K9¨:)»»ùÖž£k„>:ßýxÞ5ïv9íÈ(§)ÔÝäù{„>#ÑlAi1,·éãRÅŸ=Ù=˨ϱçT*³²…4ÿd•3¤ã·£S(7Îúß3·åæMB†)ÅÃ+û—²•s8æìâÌ“ljt_‘ØôM”µoŠU¶˜¸#‘àpX²ó*Ún [_¢ \Zƒnöú°¥B£ø #öÈ[-ñ’Èñ›ŠJÔ¿òŠzxFBè $ †¾]!×ÉÌi¥¹»Çþ}¨©;Nx ‘ŸvH›Ñ|)Y¬]Õ²s—ƒUzå Щ}3jœEõ3v$Œ%Œû|Z°ð]<„¢,¿‚ŠFÉkEo*ò(‡ö”DÈåœÿ¶É(ƒ)¿9ÄßÓì$ý'YÞØ®ÝÚKZHhDÀWÿ`é“yÔK€ŠI0kêOøÛO÷ˆö‚8 úºÜŠ£dÈ`Í6Ñx¯ý2äD§—ÿXJ&Ër–žÀ $%IJDeÜ&sN‘E[˜˜Ë­GGsÈ(IÈ;C´b BGd,qvåš—æ/rc!Ú*¤9š[Gë“è‰75†b3Bi`3­‡l3N•ŠJÁÙwÓ‡„¬Ién,¦Që9Úâ°OäA¸:œ¬üMÑo‚õ»†‘!¬zÙênK~iÏþÇÏ‘¼€É\E²˜jÔ9¯r"5+5f¹¸‚Ù|¼ûÎqªôúHAVõZü˜5iNUwNYaͽ¼ú´³Ó=~ç<œ™uë†ðüæ•,l̽ó®6@#dq—ÃF–ÆÈ“¿ì§v4…*Ú׬¶¸'—9Í\´*¿€säܼ˜Lgʱ‡¢Óž×¸=tGv•úCåÖ£¯º!=¦hÃ(öŸ%Ǫ́b: ±ÑÙø“U릪lÄq”Ü?j†úùJ0ðtÙP£«ªÅDFOŠ‘»1H¯1B¸Q`Y$=Ôic(Ž:€ä1öº~ï]6á¡ù ÙC©|9]лâ÷ö åµ÷ýœ)s”ùþÂàýÔ•>»±Ý7Ý‹Ipú¹ž©9å;=ÿ ¼Ró‰É¢`£ØøŸ•ÎŒ#ëùú©¡Tˆ¸ŒÚ€Wð†fµÖÿ?ö¤•FÖíέJ†Ç>ìç‹¶øtÒå^®ð¤Þ‚ŸÝ) ±ÑE?ƒðWéDy§} #(<ü ù~.ÑÊü…&ÙIzã€C¾ºÝË'À9Øäw~@åÁ‘EPÅôK䦡H5»f¾¦>Ès4Æ]/ò @ïðü5óæû3ŽoL8Í!’ßEüÿql «àŽh0Pä†4ä¯ÖÌ)ëIû38` ÅÌaÙhVWÿõœ÷‡²ŸAo,+…¹BQèæ‡F¤Þâ|y§âkI›v†ñ&;á âdïpÌL{„£Ð~˜ŽPÇ )7¥}ªðzÍ÷én„(Èè²Ûñ¹½müp²câú›H:,u¡­æZ3Í<°7ÖLI9\]z!™U pÎê’Lãc‰wsîãfk<áxÃÝ’;& »jhé¯ Ö–Ò3*$cjªÙ樮tLÉ£æ­p Í·¦'XƒBßû…yýÍÃlÕ¸€yïÿqcox>?ó á±ã÷æ€ ˆ¥Z­º·Íb™¶ÈO>ÃPþaáN¸Tµ†“Ý º ~AñSäÕÏäA·å‚ÍÔD–‹Hnn†ø`¼5²jm’‰°ªΰŽ<ÁU4©kŸãú[ÖýÎ0 ìVúã hóìÆ‘®Œ—tKI.Ÿ¯Tß‚VØk}a¼Žo¬T¶ê@  d­ŠÍž¹œÓöV_ç ê~ÎÁP8Gü˜Þ¯ÿæîwynÑâ¹ÿ‚IËkôŒ/Š“ý‰z¤æÛ¾=rÝ=~„A> Ø¿e.³€Õ`¤¢¦´óÔûÊ©¹I µ™·¬Å ¥' S²ÖaãÈdÅDo«ÖÃ8ÿãÖ±6Û±‚£‰œÿÚ! ø'sã¥.§NÒ¶J€ÈUàfÔØÚD­*Bˆ~ÝÕÔ²îÍ_5Ô²üÆ{·¨rw þiS²›þ­¾íií¥  ÛÂÝ„óWÈRôxáÁ ÌBç×ã…-|…µ1% dOO‚Uñ®@œíp~Ò#ãŠöT©$¯Ï@Ÿð^™Cct_PÞa½·ƒQkR=3 ©éN‡`±š³ÑÖ _zoCœbsŽÑlZà¸á‡Ce¨ºRòpýÈsòZêk €è§ NÒ ìŒH,%U*CE¹v"?"C4ƒ?AVá%ÆÊ`ƒ0%¾Ÿ%çËz+_´­[óˆj|’$£–ƒÉµÀÒŒë5„.ôŒíF+L·3йF­{Ñê«ÊÍ]è¾\ºN¶SàPV:j3Мvö ,‰yNÊ•d6ð—m$ó; 42óM'´"!e”ÎóÌùQÐ\?øgÜ5sæ±!ÿ@ òôðîã!}”µ_§©‰í‹_}„3»ÃØp»4ë&/(‚Ðó8 »äî…î8d à÷©¾@èÔ‰NŠÓÁ^Ä?|¢0à`ïågòÚÏ€¿U¢è›üÏ/‚ÇÙ2Æ8`çñL._•Eùx''¿+'D De«X¹%0{Ø,èú”¨ÿjäµE €ðŠEMn ~ìu²–º5—pÕ¼\U©#£ðãá#íSž¢ä2°¨}Êéú-­+þÅ·4Zpë´²Þ´q\Z¤=rĉW•çü@Í2÷õª$ö¨Ñ5ðŸ)OçP¾4|‚·ÓB/x /Ѝ ˜¢SλÆLÑ–Cª·LðؽÜwwê·…ÚK±„&1À§ÚY\)0>|gØõ²î“¾ÇÏt4îsœzõâ¯6~”áHµ”ÔLÒ¼O°/œò¦÷G Ù]™NÛÁ]¾›Ë˜U¢UÕžÚWÊŠ²8¾‘Î3ãzŸ¦Ë·ÜÓš½åâ ½áÚ¿LNÂ".ë{vâ¢~Ä5÷|w·? ×bäÑž&#ŧ‚®‹ 1š‚ݤñÇ*²(%´t„£ÿp?Øvg³À5Ò™¤Ô–ø0}Þè=¯E÷}–hÌKŠ®Øâ:P–&?j›™Ÿì#•éJ=Qš`nQušÑî³dY© /–y<áÀ@¤13x¾êÝW„îIdô[åžœ‹šÒ;ʼ†™îytó¥þ?§©WÃÝ)ÒS`ˆŠñéÐýÚâ?)¿ÿåb–bÝ¿NÉéê!gñ¤ÞIö¡r㡯Bøõ+¿/Ü¥¸Ëi!²Ï­¬¿ÿÜú}SÝÑßÔ^¼³ÒeØàð¬;]¤PŽ/À÷7¾¼q<Ísž‹hbKŸ×ÍTn?x*Z¼’$Ô@òïVþB1ÁÖÌ—P·@{¡Ÿ—Ó¼ná– ÂOÿ«}âowVGåèH7ãNœ ¬ùIýæ&Gl ¬»²9ÿ8£!]Ê ÇüSÛ¸™õÁ¹f^–¶+Ñ·l‚½ÍƝÄF=ù a^²LÐAUØ'Etz Æõç¼ß곿zÛ+6oåˇ}‰täÑ#…ß×Y3œÏø~ýÒ—›ŽÒ\{í³ûR›â´·.w÷ßtμlŽ×!,29cã&fW A”è®Õ\B©ñÇÖ,ŸƒBaW_S#q„úgQòAød b¦ö&!Â"Öý¥ëÀìò¼©~Ù„6%jÝûÓÛ¬BY¯Ù pq8ý]˜±9 “hæ#„\¦Õ{{ðÔ@NùTA¨ËïRE2“̪>füÉ/_\Wƒï>â¨Bè6)™<35DA,ĉöÒÂB²Ø_©pÇ(éâQ¨9¦*©ç¹×È~")`#nx¶’œ›ÄtÂj¼ÓïG?”¢ü"§| ä„–*ï=…­Gãö]‘”ºZ†þýAT¸åÎŠŠ¬–Ñ ùUž‘:Ê|Aß¹¸ h*+% ò=õŽó‰Œ tcHMî&´UdÖãõèéB@Â/Л'ìî?ÒZás*gøß9¾£Õ—C5û‰.” $”+¤ŽÚ+±½ûµwŠ AŸÑ{pÑëߤªØ+]¹;i/\=æÆ'í6XŽÐ]7”,¸|£Ú¥*`µÂï¯Ûl³k›3Öæ+§á_Uh"MÝi8oÁG?áIЬ/„ WÕe5DBoø òÎÅëÚHoûþqùë’»[y$n§÷ùfò†}¾~K?ˆÔ%Ã-ªÁ=)ÑYRJÊËÅæ½xð›¸+Ž$ÊëIT†o©+E=„wPç8„mZvO$´“m¨¤ö°ÿ9Â*.ƒG’jö°%¥ÛMZåØàD¯å°ø¦1}‡ZÐ"ÃG¡–½v!í\ö $XKLPÈò|B•¸w0?ä{DIÕØ‹F°¹/·ih.„ùX/x;HCüGý&”ÌŽw«2]+boîa78¤Îb¸?içW]*—"ô<:dN»o{¥p&!œ´vƒƒ¿0ÊÇñµ&Õ“l ¥GÏ{ûN~¡–²¯–Ì#/9Ãfð ÷¤_ÝY©,sCÔ—¢/¹×þ@…gYÙ*BÞ6Õ%ijºgj}ÇRæjvq3Úû_˜™''-§Âôêj%º þö½7‹£Û—ñah ë¥;G±_3»‹\,Q¦½ÖoóZû¬ÁÁ#‹•Çib'°§dû&úg¨sð}= Öô"Åe¤êyo…}܃ÿ]²¤p¾Ä!k i±¼š Dj! 3²ÔçÐÅMDmódæ^á3>sÜZÁþÅZîü8xY‚“ÀYÀî×?%Äú€¿Æo“b½,µôªçâsÇ’œ3ÚYïQK.‹fgi»ä†p¾31Ôæù8Õ7WÆ6+þT`*«Nl]0ˆ»m*'ãq8}§yê-ë·Í[Û%¨gFP9·¥€ÔNÌŒ-N3|ñFˆ æ—tÏi…,ühYÉ´œ)µ¯ÖuM»KI’rTÍwÒŠ`Ý8ÖX"îÊ9ŒÇŸ—àvB›-Íàíâ·y€~Õ õ1 §m!yÃÖÅ€?‹ëªà¾\Óˆ«‘M¥r4–á.z,fÛXÜŸA–”Þ©ÖÃzô‹háûµQ+g ã³Ê«|©Á¬oxùælÂך¼N‘Ò#Õ’&ºE–,çG’è8±41 é¸!ÏËÄšÐ"kwïŽJׯ"¡A’“¹ÃfÌùù±þ NX”Š7ŠÒŽ";-E’h#Z@°•o‘+ËÓÛ"nf]ÖN*àõÅ‹¾Æ…4ñK©ú¥@ê`›Ò,Ò4Ňџ’çÆŽ!.0{äLÇØ³ýÂPC)¶…€…ÐæÎq`*!_öH§Cãäèÿ5yÙÔsLÜ"æ6|<ê“«ÁAb«/ŽNáhy‰x¤`‡7ÂOõjˆô— €¼¦d ßùŒ5:àÙ]Gÿíp»€w¬jþža?Ì\„ÎŒÄçBÂ[é5[\&·2z%pï…+‹#ë}_šç¡/ãšwò„ /­—‹õ}“WèçêŸ[Ý—ëìS½)Ä+‚Yˆ³‡ ñžé_©êö˜pƒÑGïuúQÞ[eSkôö(9ÄØ§«QþØá·µ˜u¹nGSc‚V>ç¢)‘;ØF+S2B×1­æØ¬ô¹ðŽ ×ðÔxÕH˜‹úy’¡eÀ8±V+]>i _]žŸ—Û¡ê`Žg¨QÑÆ:Ý<…°á0(õ Ê«)%q/4€m¸t;ãÃ7ÒhåÊz˜ì÷·2Ž¡•Ñ/é=}Ù Á—Ël8/ã”·sVK‰j²”Â4p~EôÕS~â€G/ÉôíïÙÙRøÓœ§¿ÔÇ¢ NföŽQú•ÁmÖ¶ôìå\hND¨‘]MZÄ› !XºX )nãÚå(ZV6Có®æÑ†Õ?!œznò½¢«Ò<z¬}Î$Gï+¼Ì–“®î|ýŒÁºˆŠ‰É‚ôfnûÜ Íw,ÂûÒŸ½œaÉ3{ÚF@ëÚ ŠÄ^Íë¬yxîà%ôÛwôG˜=÷G ʈÎmÓÆÂ”¤aBîzƲϻVgQ9YþNê%ízŸ§;a¨¤B8B¼Cõ?íš”±ˆqå°Øúd)˜40ÚÅ»è‡Áôáä¥zr†4« ÿ9ªŠ~Olá! ë\Âp'wæ²¹f‰wí--Å4õÿSë– `ˆt™‡³LÖ…ª? 'þN5¸¨•ó#7#x;H«8¤~ï¶ÅÜKƒÐ\á¢÷gµþÝ'*oÔ0Å8ÁüKSþâÅZ¥ï©•©²¿ªF Šê±ãøzþ{M˜ˆf—6ÇkˆìØÒC^]l`úšw˜d¥]Ã=BË@ÝÚif‹šÜÌ(±xĬpyáíÓÞb»³Fo‚1áng޶E§Fáã õ8w1F™q¶V`*ÿbµÚ À‚w«*Ø7®ç»T£øæ—„2r–xAæj³ˆg*v”œ±*æ‡î›RrÍÒíØàþœÈ½dÄpŽ”Ï©ÇôiîL—EP¦v@ïí(ùŽR‚õJÞ˜G.áéâ“wôHÄŽ(³ˆog! Mø çiT5!ËCºí.49H‚ C´dT©CáÉGaаf£ÿ\ï˜3nV Ð8'oû¿Œ†œø &F²-Wc£=¯Âø |}PI…@8ÃÎt­3Á*/]A‘ÞÄ7™{¸/B -¦Di6x¢n^rÌyкgÙH> .o×Õ¨ë•ÚªŒ0Ѧ’Ý™¾Ý(u/eÃPdÑÏl7ÌÖR ‘߉(å,Z—>OâQó5ßYä¢sH¦¸ŒLü¨È€™É.ÉbË=Ÿx€ÞŽ@¤Î×|«ºh‘¸ÍýhÄ€Ô¹­#èSëòWîž®#5Ä|›ØÐ;—¦ðÀÙõ/lCû¢cÀ‘ŽYf‹ç? ×ûòâ‡Î}ÇZ`+餇a0ÂÁYºâ˜—N¹ÅŠRù ^2oŠOýŒÏF áNu “¶Š Ϭ–1e2xT :ëÏË!ï°ÿ»›[6•Æ;7»ŠƒÞ±%{tÏ¡*£6ö×w.\´¡gåíƒ"¼æÜà—üX¦7ÿs¯øý€­ ¤þ£EüÌ­@¨îÚZöÄÉ$\Ûƒo&¨¢ÔæŸppÂŒPŸé¼ß6Ó?˱ŸëxŽšôqñY±ç¦Å‚ͽÑLŸØÔd˜›¢ÝIvR,lŸ!޾© ÙÄl2peΙcbÌ9¿ dŽI0R˜ÉOÎ~¥‡eðUj ’Vça{eeóþºÚÝ@Þ¥jÕ8¡8QŸï2añËÑÍ3.›óŒûM)\?δ‘5\SñtJ¯6®_ˆfTJRÝCª,÷,Âë´˜™"—Ðe±LmÇZˆuJðAi*C¢ÒRúy©ÍðrMW¥b–âÙÌ”šõT_5õq ŠZ—žB½’(©±8™ÙbûÇÛ”µž7ÿ4_*JÌ [Õ½'Þ#˜‰­?ÖËn XÆ?»ðêƒ øÎÓŸh^~ì2³àü¸A¨H6*Ïýšw!»{š"Í¿€;¦¿ót÷B€up h®úSÆm8B%~¼(ΧŠüh¨%Mäb±"%žÞïäOè÷íãp¼ߨDb6«ëb¸â ŠJ(†–*›à¥4+—THNmc¸À±aP®ˆMXK‰¼D±]›‹ âx!»g\×ÀRÆ2õ?} Ðýó¬ ¼ÿóvøvˆ¤)Xr´( ®"°NNþÅäöÁ†êsD|Üs0ÿ‡’_† Xò·Åb÷Éþ©‘SûT»ÌQˆ"¸˜¸Æ3¡ðäÚ¾r0ý2骶>)÷·¥‘OûҪƳçLJÀÞc¥cm7Ðiÿ"Ò ž2y[«Ìü<Š /Kug_²vB¿V‡¿”6;àÙ½}ZÊ– ’Û•îäZ c ·l™0ŸÕcÑaU±ªy,t÷²F³@²†Ã))¼E·ôÑâüógþ¶Z[š¸Õÿ³SÜ/ö?zˆ¢ÿ& /oc¹¿¢ãÏ÷bg(ŠÀ‚ȓΫƒfµÐ½äsxõw5Ë”#ÜYQ[ŸúžÀª ÄÒ©åÓ.«§7‹míÎêT(ïµ#³êmÙ qÅ4#ÕAÙ]éª Ò¥ãP¢x‘úãHnA’¼¼©ð±ó™‰Î+9$y×N%‘ÙðÉ7¼).mUÂJ܈«Þ?O˜N©•úõ¬øU³eIq7zïõ4á»;aÆ y‡~ª¥ú_û_/ î+%ˆ?×ùZ÷Ð…O&“5ˆŸÜsÅIrŒœ±*0Yˆºݵ]XJßÊ"1Û2Ì< àm’ƒôé¯çqŠØv¤cqãYP½%oÄsë£ýmJZY¬†)2f/ÉØÑÀ7ñ ñÙñôº×Ô©~^Ô¥A£ y´¨ÚIò«„ËQ_¸ü»;ñüY³3ã¡vw¹øÛ³K.Ë“´uÁ«çh–s[kOûo¥-†ýÏÆž ‹æÇ}ß~•½MÜTC“f¡¡•ùíKWöïÕ¡Õ§ä² ­øzâ´Á8¨!~s÷z)`°vÉ·ëTðð¯ŠíúVš%>‹0G¸n{ûh†, ¡Õ¼Üø/ÎÉz.b ˤŠ|_dæžÈUgÕ×fŒÕFŠ&gJŽÜóï/ò©ß‰ÌhÒ¸òwŒnA?Ð{öz勞x)B)ÁAo˜ô;sSÀ/¢ˆàޤg  ß‘PWzÍ)Zõ}ã¥ÍûZ3‚_áÿl÷à©á5:© ò#MìÎB!2§œÑƒé¢<âfpPÖÛ¥ß8bþë¨k·¥‹Àºÿ‚nî ‰+ÃÚþÐIœ(ÝÏ&Ç—ëtMGÜ£å õEü<&0'®×æO‡qXtAž˜Âë4Ñ'´ÄexÚHÅZÝls€8íp¾;‘RtΊU™¡wxÚZ¾÷8tQv²Í6º×׿›Cf3½ÞZ€h/öÕ÷0b\/Ä/hÍNœ×ä?YËI‚HEvì%£«aò:g@€¸ô«òsSˆZ#Ùe×#ùâv•Q*7g,ÊæCÜæŸ²èà[ßéXH ¥Û©!–n ¥¥Î'ÿú‹¿!*N¼§Úyùp=óOð MH&N_Žø”¾OÖCJFžÚ‘÷¹Ò­#Ÿ‡@ Ôá%Ps‰â¨¥°÷u§Ü;IÂéÎQ‹ÀQÿ纭ïÊö” ÃÄgq¢¨iœp¹}v#’nW‘f=³ŸL«‘-Rˆœñã,HŠ+}Ǭþ¢)Zà+ê,"IÝá*ÊšÅó1+ W%ò»7åZûÉVIâJù)©³³û%Y4áž ý -´í…뜭~-Õ^ãtÎëâ<-Öê=çs%TôÒëf·®^€ÿá:DˆŠ $³ôC”@δtL.² ¾ž'†ÍDN†Â(™i·´Ä3Á¢¨ÓŽø“]o œ€D|§uŒzÍXs÷pˆL¬þ¤l©52Bl²ty§x<;ï(:ÛU±Ï¦÷LÌýé ­ÏTFA?QSû|2ÆL. AÉqê°˜t•å “Rnþ•9÷r-ÅYûÓz×'PìfÂÂ2áÏq‚ŒØ;&²Åƒ¯#2‘ŠáÿõsÃí¶ŒƒPOvÃxhÄu^O«(¾²¾ÖZeß­’Úkyøán &7Û¡]nÕ‹–ßjS@Ï#b©ÀŸˆÔUÍ3¿öt%E»–&¦ÊQ'xOûýýõ‹°É?m'Î üK¿¥3óÎj.|»pEĕ箛GâÜ|Bo…ìÞ3Ž Zši_.A'o'"?øMûòà¢,@z’aK ç±6ÆãÕýk™gÜ{Ø%¥ è´¶­¨KÀ0¬¸6Ó^ûðÃAòÑ™H›£KÑ䜾Óø·EXŒº¿ËäÅà '=Çn!ŸBù¡€ øŽí<¨ŒG ƒ ˆÚÌ~ÂhêÂ@‘CÒ«Á®)©$Mº²¹0D(þÑ 3Sƒš­¨àQ2„)®÷ÙÑðc eh'#Ðäð<ÅqÅ<^Ÿ†}S)nM[½íø¶×ó•æ áD7RîÝÝd«›ÅÞÝ}ö= Eþ*ÝAp‡êä²õ!FƒûÏOðªâþTÕM§öåâm<Ÿ_ÔT²‚M¨g™ˆ*ZklqT£"²Ú)K"Íy¶y¹6~q÷®ÚI¯Ö’g|0ž›úµ@ØqГޛüGjÎ%-]D®K¥^2«4®ý|ë;0UÊ VA¸r ¬¾h+%Méî¢À3äÒgí–×(xú£üf%¨Y¹CËÔ;Ožzÿ\ËÛq’µÃ0¸l>Å¿bêilØ8Ÿ¦æ4Õn]´Ô8b˜z¢™wÊÆâFâŒßj%ÌÊ”Iueã˜önFôŠ)¨cÚÏ®ØtMÂÂ…ýÆ :<±¢ (D“Ù`„dÎ;¿—má™Ùü«?õ£u(o ’RKi+$>Ò(ΜΊoŸf¶~Kóbë¿…H(vŸvÙ[¼)ŪB·ï†Ä²mj?FøNñÙs##ž‡UøÂîÐâ-uD~o¾'oÞÿ'ð‡73ŸÅi7È,…2xÈk:WäˆímÒû}tí¤¨•È úóc¬}Îgå×u$¥ÁBiÑÎ"ÎÍõXiu—WIoŸØ²`ØFf²/ë‘Cù̉`sË(,^¹ÅFŽrÇy¥Ìž`Z®ÔƒÍõtAdª„ÖV\Û@¹A Û$g©J g),¡ç$ãæˆ(\X|˜à¿ ruä±AîT@Fù®üe45;¨.¹…hU1!@±Ìv\r‚Jƒ}öªcÜÒý§$×"÷9?6²,\]ÇösK9¼Æ—½G ( üÜÑ»Òcqåðç…m{%°D-åbQ  \2Cý[Ü™åêðQ*{SQÙ7Üéd/9âÙoNÇjäG¯qWˆ{ÿ,Μ™ÿä59í´'‘7+ixu@²ÙËHÜÿn‰§FŒ ³÷¸ý4>R¶BÆZVÅÕØ—Í0ø¿¯À-U9…ª^B×P×@ÒâæÃaaᨣ^Œ¡²¯}‡;]ê´À·¸šùÏ©’>{Æçþž‹á¾ü•|÷Ûê]þ€~Ö^ûW…ý©ßÁ„ý«ß}ªÅwÚ«üOà·¿m’ÿõõ5~Ûý®0øohùþ×í°§ÔËæý­Ÿ¶ïµÛø4ÿx6_kÆý´·ífý©@~Ô­}FŸ¨ßö Ÿ© ÏÔvV~£Ôt~£~}H‰,úïµ»øU;í¡ÿAkü/¶€þeöµx¿µšúž³óÔ¯‘¿‹ä{ùê|úŸïµwö£üÚd+ö›~Ô#ö¢ÿx•iÕö´ç~Ô4—ö¡~ÖÛIÏÔ¹>J>GŸ©göÓµø0"ÿWL'>wÏð”æâÛ#'.Ó­ìÖ¨2z†Ó½×ÔÝìÌ&î3Ö%°=}®f±þ)†ù#¤ù™Þ::ìˆhºà{ù@AC¸Tý ëpJ &™qùX*%‘V¹×ÿZ2¶¿òÄÚ…¯©õu ¡È¼Ä:†X¡ ¦B»&1ÇËhQänÜpiPnÆÁ ìtä!|V…±Àd`ˆBñ¾¢3[}/õ¼¥tíN hˆÓù/Kò؉+Â(–Ÿãž¹î6íˆÃÄa­o·á{èƒ9ë4l¬Ó#ŽJdhÓ*†¹®^'’üG|3Ižƒ Ñ»?ïÈ5ýg™ePm»„>³šYV¯sæ*áeXB'«ÒN &7ò¼ŒiÞJ“þ?7&0J0[…¾¡Ì:Éõ^ -®†±nßåÎ*fÑ…ŸJ܆‘Týçôk%X/2\ôe€ÑASšµîüÐó4’#û8³«Í´É!=1Ašp£ºæpZÅ¥ jWºÈTî¸RF–Ðç£ ”—Ž/NexœM*׿yŽKj€w}+uÂ}NQb¼×£/¢XS@p¼.™àл•,T6ƪì!Úøn0gI¿`|ÀŸ›¤/ø{dJN«kŒ×¹*Üt,¤}nÒºG¼Š—‡¬ÏÙP•l„Áª˜³RªquºÓ¢G_”V-“¨_I¢<goF.اÁ’z¢Ìú>77^ëó¹ä´;hý*¬,Nî+<ÛJžÇÿøWØúsϳq~çéRª‰d՗DÌz ž¬‰Ý¨°…Ûpüy6öð.ªðÿ„­EçÙVCuïG3„¥çStÞ€‹AÇQ[E€Uÿ}úmFFõr~üûÐJD¿×Fžx1»ºwx/ÑGŸÇóÛ÷ÿE—Ÿ·‘.-c›gâ»=n²,¸hnöO3,Eô¼ëÙ—Ò×GœŒ}sªÀ“‹L>Üœ¬Ù²¸¹}°oùÓÌyD?“ÿ;ë˜iúàÒñL ¯^ú³·øï¯`zƒ6FË,ƒrðÚG çÕg#_¢Ê÷1Þ¯ßÖ ÒÙI!FÇi‹;u0™œ5F±Mo¦‘$hÇ xj]??@ù/Ķò]gäBZ®‰U^’•õwÖíkÝ1~ufåÞõN0 ™§v.ÐKÑÿ~ß¿ ©Ϋ2—¼¥#ˆ­-0}®©ÚVV¨8’ê+oÞ.ûGåj^A ~œ˜¢0{ä¦2òÈ8¹Y_¸ýCb-x‹läù¾ÜòZà0Ò2•ÉèÒ2‚ï#/ô8³Ä^YŠ ¹zÌ™2èÃõ×À‚bÅ^.Äúà²ÔIXn¬Fôs-ÑÎØ˜Õºàê;¯á"ÐZ ”’Gö-iïAia_$|ÒJC©!/ºík˯i\”gü͵+Â>öÐL,ÖÊèH EòKÔÐ0ÀˆÉ³APš…ŽRÓîDŒ?@š=²[V[¿ EßMHeûŠ«ÒÑrð^ú³·õ„E~É*<çëüÙXv[ ]»‘%Ƭà%š™É½½†­ÞbÅ@´»É…0ã鼪;(=Ì(ë,AÐù¦ÓÃÂz”úéð!“k“Ù ìôR$ͪ­¥3xħ€W‘ÓŽý8rì¿ÿv«&ý òB·tðVc!è-WØ€ªp šÝÍÇí¡h†.X-‡-nZ`Z ±YŽ7Ð6AåYæÂôÜÚEpuœX!¤6â™ó‡ eÖk s’òÛ3Š/Û¬~ ¹ÎY(êlV¿ÛÈ“›mvJ*9ûó32ñŸ#¶4¬¬4ÃÏÕÁ”ç-@Z^Åa ñ pš2ú¼ÈRùòzD”Ï™°A‘„}?ù±ÇD(¢VÒ ð*kn‹*?Ûü½’ë´ë^Ò.¸d [³кæ(”ãVu³âdÀÂyc¸Ïe U®¼õìd gvís@:dê¢;¶"ÖñG–í{vM…ÈÆLd…Ø2%†¬ŠÅo=“»ÉyÏéäŠÅËŸZ‰ò#½å¤Møø’?*̯Sjº$òè¿«^ùÑ:$Eqè0>Hˆóˆ¡9úø…_Æñ-+ôÖgøA§Ðÿ‚Wï 'Äùo=Î}RfŸÓJòX}Ì3-·ÊQßµyJ‘PkƪI°67ǰrô§„ަkÙœ¹ö4@ùÓÏÓ(»‚Œt–m‡ÖyYôáYÝÇÂ03S®gÚž`ÞNü‹õÉÕÂ> ãÍú,ràî“Æ~¤s>dÐT•ïôÅ0½Ö.é•ï­¿6Ê ©êiü./î-!Úv–ÀÁ±¾–žš&T†ÐDAª*‰uÙ: cº×õ ”ù7 T›§¹F˜[y¦ŒœÍòitw|#g÷° Š8Õ—(By3‘Ó–hdËxtIÌx}Ó?š §xyùÿ7óx®glÁhÃrà²Å 6Ë¥dS•ˆ¦l2"t/x×51ì˜{ ¹ÿ.›ü¤€X‰ð¬gýœ (S×!F@QoHS„ö™5˜’üK)꼿Õã$pk(¶‘oï>û{LËÚÖû¯˜ âÒæœ¾gð9·Ì"NŽ• ¼8u`l0Û,¤ ún­ïk ¯–vý.ºx©h×EÒð•Ýû’)ð0/ñØ9,#^U¤mKTƒXu)—­ÄÛ9ì¢C_iªsò I«)@l:„ Éh¢;éd¤Nþö¾ãú«nkç;ážžôÏ6Ïþ0´¿;Ãq~Ð_½ÓQõƒÒLȰqÛÁ87¢Swœ—ˆ>ó’õuq_t¥þ©LÁ›ã¾l” ë+gâí|{p>ÉÁ08\›ÖmŒ‹µçùOûž ãj]ÝÊ&6CŒð hAhW©{èP)AqŒÃo"5}­&\šZU‹å¦ãwëñGA¥,²Ð@êÄ A®­ƒ¤”i#ä«<8[XsXhjHù¾µ?4{ „Mi>ó^ø©Õ¨MF*ï#8GÆé·yQ}G Gr„û U´øqÊ:Èõ7…Wi/’ëd /æ³^ã,|˜}l[¥è™ö¿Ý&9aø¬´À¤'w R£”[¤ ôéð?v](§’3J`Û¬ÀÝeCz\Ôº¸æ´Ÿ•†ÚèÚ†?•¡R´ˆkC…Ð ù«GIu/¢¦¢ŽŽ½ÂC†òØäLⲸ  ô}Èç1b.”RÌ¡I”!ù1½-Çˈ‚‡¬ùvL|&áîÙÙ¸`nåô¾ššá8ŸoäwAWžW%:.‹GQ^ѳϊíD·»¢[Ä—³Èÿí«õ7fK²ÜR1Œ…¸;özNèE$ñº_ò_QêätCÉ®e֩ݯ7¨« XÓšúáø4zíû£ „iÍòµ©]=êÆÏ€¢Û4—oÂÜÙXY\B¶b9Óê$é¤Xãs#ˆIMíµ3ƒ*^žN–åœáÙÃäMëD=ra‹è^NˆŸ!©®g·æ?ôH|²-ÛJC‡L½Eô€;Yxøå‘ÖϨR”Ã0ˆ™~^I˜âc1 p‹î˜Œ%çÍÎ õÐÓC_Oxwø/ü Ö{÷GâÔ ÎwEP5×*÷Üÿ(³\ 榱•&/”ÿÕ^² |"äöÅ›åšÕ)å‰!Y²¼aç°¼ÔŸ<2Ïø3aÎH£Ž˜Ê‹í)3˜òÁQ;ßP;®F»‚´ /GÒ0µ´õuãˆ\ýÙ+~™Á*³Û ®,/^ö6Y´ìA¼Àÿ‰K³ÉRÈHùƒ}ú|k\|ôÂ:µ¶ÐÓ¤Ÿ‚gád1•M?ú[Ü·#ß1ÄÛXiBåAÓÒD T=å« Ô ÈÂчhÖ½ ŸYŠ̲JÉö!¯>ûÃÒy@Wk÷gÇÄ­Y¦yé\&ï$.‘„øzð÷jÙ‡‹UáÅ3lŽÒó£Ö5â“üu\¢6zÎeÜi¬è ÇmþGrmç úıQ–à&5õ|lvÎ’úA¯º›X‰—á›3Ç}e­ÊÛ KxĦ 67uEéÎù•«Vk5à•AOX4…†S³‰ÅgܾW(¶åìù»ÉE¢ÍD‚{¹qæÑ^?v·Õ˜Þ’ØkXþQúøWKƒR)¿òZ„ušÅ0Ä -üèF'¼´C*Êf{ M»ÄõëªÈì¹üu²¸7rlшîó³|>Ñ„4T~Ë3(ñáÌ×ÅJ7þs&I•*LŸàÄÞ4]wp®1Ó~lFúõp˜9 +¿;íĪÍW<°Gµÿq…÷6Œ—ëù.Â'6!¡ÚT³õ±À<óÇ (:ûr!ëÀÍ6q‡‘Þ\àÎ&š9ݬ>ºÃï¼~%®±MEúpêQa·N«|×Ç’íR÷pO¥ ¡ K#q6áˆRs×@ÇXF=GuIêïõR¬Öœ-‚âzû2$8¬Cé7ðY‘R(¿ÔþÌ#çRÓög&_ ~F;Yp‹+ÂyÚö<Ð1Õ¾82 Ì>ý…Ãʬ´lò¨ÕÒ åígñZ0Yo¸Õ‰§³‚Ê?ó.iÑÝ\» ˆÝ2­4…W žO; ~ÌÿM¾¨+ÓdõLVÏ*Ø-˘<‚ ÿdïÑÞZTïÅ#F †Â½DÓ|ñó °{ò’%³–^^Tñ¤pÄûÊ f€…KJ0Ï{ŠmB ˆCÈ H~´›± mW We€«ÄH*ÂøZ÷' û>Ä·ALCh8Çý@ßc\VÙ”çóÆ ·dlÍJm“:L$É Œ&Xt€À™ò„1ÒÄ‚QÏ Êª$æ/óÚyƒè\ó%ËŒ‡êVN{É¿<¿vµ¬váŠÊ#xÀp PuÖk{?2ÄN¤0÷zÇ«l’÷ï/àxz»U ] ðÓH2ºï’5òFUÿnIqRFLb/§;`Ìa!ùŒOŒÔPLÞ1¾¡z­EaVãó˜-vríŠ]{LL®ZØ©?´[Â:ZxôˈڕêÉÉ+yñÎC4šxé0åmÓ¿h´ë"s£â¸þàô:â0šzõ˜­θ:³e©MÇüøàð6·õŸœ£' —Õ³œßd]% ˆ‚bw™8h>û€£v Ú}‡(JD×–©ð•3Èg˜Û@76™ˆ±»­¤Ñ¦Puô­Rªÿo'bÍžÂਈz8K&¤¿"pWC=O* Ci«PAp›eë1ðÁš¿ë¢d Ü3í <Vø·šyýïB0Yj[¸§|ÿZ²Áä*×—¬µW=êXCÅ•1+a2gM]JÒ+‚ñ%˜ïÆæÅ:¬¥plk5ƒ ñ7EXRy6*¦¬ºJ}ËÏ(j׆ÿx4XÛ8¶Ÿ°"ùLýñœXz•ó‡çõn:™|«ògáG­™CàG+åÆŠëRm’`à ¦‹Æ¾ŠèSŠ‘¡gHútû!=âª6NX­ýq¡),O¤D—mÔZlOñqÿIK KŸåÃTûŽ@{“ ®í᯺¶  §â¤ùþÝ» iÚ±±HéB±Ë¼ ôÎs\¬Ü"ö__åOzi«™TøþçÒ®+,iã5ç#´‰Îñ@}½ŽƒÝSIÀÚBÕ_Èý`“R’ç£,  ô=AÌ0g¦Ÿä&©?jÉ>0{Ü–ßWdqš@A.ï÷±ýôˆÖƒ^A-šk¡Åe°|©H«.8å~ÏÝ>'íA½pë]Õi¹*>ûéö–éÚ±Â;„•ü"ðf°ÁKÓpt*½$Q 5¿;õ`ÏNbk¡îŸ]¹šØWÃËLd7kX­T$!`0<6ÊœhþøP¬Œ§h¦šµ`3ÿP+ýxì;¾Ð6V2uïãÆ$M„kjûy²’ (=,bç–Ã{ôPFHÏ!*£ì+’…Yp)ÚçýµÈ H©J2ô²RçŠÉWéya-s¨;Úáã5HÌ¿ øi},,´E¥ž*¬-ÀoZÆpwÄŸA®ä£Ãvc·e"¾d$àë«výÅQ^{0Xœ 0Ъy½j§IoÁ°Õ”L‰ë9daƒœÛªïÊ>#|¿H,'ùÐÉä¡ý&PÿN¢µ¢YiC ýÈ‚ƒîIÔ.3˜17Šñ§ð~1Aµò²ÀŠ¥¼Žôà]ßâ5¥Ýaÿ+ðô­ÈÑØVÔž©OŒXlQvyOM¿êÌcϽ ½”Œ\0šfÙz¨èw$H—.Ï:VãOŸM˾Nø»R”x²¨&†³%^¹Ûá^˜3hn`/sÉo>Ä|iÝŸéñ˜®äÿs"1ø7[A¤#ã.{ÜüäûE²®OUxÕ@}'+!¨£S{¤e*°,™Ø²Ñ‚œt±¥Éx0(âªúƒ ¤LÊ|ýLò) uÄlºã³˜1.éZü °ü÷þ!ßGB;*’Z%-l±,+½Üg é½C¢;iÝcŽR2‹ÿ‘xê5ÌWÍKà –ë8ÆûÁÒÐd†· Ù»½ÝsAòÝ¿ M0 ³ì(15àäcoâ÷#Z î]z.~œr¨ÃømT«§{ÂXâ«å¸H¤'8[ͪì°FkÚTU@IÙcc>ÞyØ£îÙìi &}Þ¤9îvít$_Rø4€,^–ƒ‡mµ+bð*S76ÀU¯·—Š\=F­ïˆe7±$¢ÕCûÓQevRë{‹ÉÆ[ƒ4Ÿ1>$B b+—瘤ù¡3o– :jç± Xb)x˜ËUkïй¨§ÍúMef×eÇÃB«ÿ‘¤¤š=6²Ųq$«ÞY­™þ¹(7" 2Ý”êd%ókô"u*ú¥a‡\Íñ!Ží{¹÷CoR,‹ª¶šÚ*½<¹ä4š@3˜‰9ж¤#˜nþ†kÊ+0GUQŽ'7+$Å›åTàÑ Ê/Í'}ŒõÂÞØ÷§ ¾ µÕOyŽNµ`wê2l°&"ìç}ÍUÁ!ÅoÕ0Ø|+¶ŽnLSRï—®B® ̈vÃÿO䳉¥ˆÄöî݊䄤CžPGc§ŒƒÙ¦ýenÒVC"¶ë/=nIU•‡™¯p?Üì ?5ž{¿ìkê½mZŽ5óÞ‰yj>%•¨ ÓžWùQ‚v^õ\ʶ^u³§Êa‚søLÓé‘ê* Bõ)ÖXË–VšiìÂZ2¼É¨5${Õ_Þ6Dò˜D ö_f={1B™Bº“´­ô ;=ëA݃B5Ë‘@åmo~¹Lã·|<|ÝZK¶ò‚ÝøÏz¢M®Jö®×r?¼6‘é)õ’’uÔæœŸø‘b¡>à?e™¸KC¶³»+¿7T`Ò×WhÀ¸Ä"l¿– LÖ}#¹»&Eû¼Ì"Ô<ÜqÓú'Á¦ƒ•ÈÉñŽlVz#¨÷¹àó´æ®VtùЦùxØ~äá+*†ËƒB§QV;˜;Âi”‚""!?Ù™ªäã°B½Èxº¯ò“ÿmbBY‹Â“û‹~a:zeÌżkÊŽ-BëU£85…V 6áwÔÕø Jˆ,T&'‘v耴<‡®›JÀ³7p©-_á¯$Ò\ÛMÒ0BÛèó¿(W•W-般i,Œ€¡¬sÓŽ·†ÂOaÿÙsqlitebrowser-sqlitebrowser-5733cb7/installer/macos/macapp.icns000066400000000000000000006551701463772530400251300ustar00rootroot00000000000000icnsZxic12 ЉPNG  IHDR@@ªiqÞsRGB®ÎéDeXIfMM*‡i  @ @FQB° ìIDATxÝ›[lUYÇW …–{K¥å~É€ 1# øRçÔ„„x ™ ÑÀñÅLŒ>`œåÅh4LÀȃÑp‰!a“1yÑ qTÊE(×–;¥´P þ›üqíÝ}NOK/‡ù’uÖÚëúýÿë[k}kŸs*ÂKSSÓø©S§ÎÖ0õoI^¼x1µ¢¢bœâÅ• ¯¸KÑSåõŒ7®ûùóç=zn?zôèmÊGR*†£óõë××UVV¾# _Æ/ IJ¾¾¾yê»¶··wÚPÇPÏÔß}µ¿®pMÄœQÞg¥ÿ-‚µo· ÍÍÍ+«ªªÞŸ‰uJY€Ž‹>€-ù‰ƒÁ¹Ï3GÉ›$ø…>LÔÆQ:{öl?)(Å™Àü—-[0\N”G˜/_ÎÂ=‚;wpp—ÀCÄ}Γ~P ö$-Á2ñHyÕ…ãÅ›,ƒ¶èÎÝ,ìmº¦6ùÓKG€àúÈìsˆývÊì{3²Î¨9 8\$Ð7 Ý?„c‰˜7¯î˜ñb ‘Ë8˜¼Ó§O÷«ž"€RÀjcccò5_=1 ÆD¸'ê³q²‚â\dH¡®ƒO ž=kˆ˜TÚEÌl³œÞñ2„ü¬äŽ€ ˸páÂÀ÷ñ»Ï€•Îv˜÷ 0ƒË+Ž<ôõíýôæ"È(d•¹ÐØ/Aô¦8Y¼ÁŒ¸åÑ1lzv1Ó<ë Ÿ‘£#KÏ–Åš×ËÏDWž‹IAhD§ì|Q·¿Ì:À2Ø †Q ƒµI:ƒ±Æfi0>¤Yf¾`QnAtAÞI¸Ë‹ÅE pCÀ±±û³@àÈÇì …(B>ib›K²KÂ3ï?Ž!Áã8y´wÛ¸þ@é’ “˜qwjÓ7ãGÌ”÷Ò( (K>1ùŽé×Ádè—ºôe ql}†¿yzi… šYˆ<~ŽA9?ÎËïuóRw úrûÌé5Ïrª% kÀ]jû¼>‡9/…1E€Öç? f3Ëç˜Y+w‘®)o(E€6¦Ýª{nÎÁ€“oS-g¤o·ÂîXÇûöíûשS§z–òJ“bòÚfû«g-Ë.éÙŸ"`Á‚¿’¿\ÕÒÒ’€Œ+f  ÌD˜¬  à’ÄI¤M¹Vúý(Æ•:äæ6áúâsNÇ€b°N¼còÊEðYøaÄÒ¥KÉ'’_’‰„-Òï#ë˜"@à+iÄåÇ;:i.5¸¿1NCV9ì8h\äø)_üN€[-ºÊM®1xâz™ðPJòŽ/ƒå,'àåÙ¤Cb ÜqR0Jx–x¦\ãqĸ³do‘˜?z3±—.]Jý@"E€|ø‡ Ì:WH–C|ç†ümÂÕ«W÷ØÞ Š #¹ÐÅÊ­Ô?çÉ޹ÇUçrÄ’æJ,2R_§ !fŽé0ÛsöýãŽIãé²b20Gò~â}"¶ã™6ÄÔE|‘~ŠÍêÀ²å"Çì3¿Ðìg«¥—¥TÆOçÝk‰N¸a‘ã4P” Ôf8ÊÀ\׉ô?þ|2¡ycô³*Ñ YO:BXäñ›Ä¯§<ÛIæ|°,™0£#V„þèÉ[` ¯äàÊ0‰°á±ÁˆÀL ³ÅD ¬SÌw$°lÆŒIÌò#m³æ!¥p·)J•Ä¿a§ 3w~õ«(žy ‰R˜>Ä{={};¶õÐ_PÜǪcÀSÇB“Àd1î`O¢ `@£c  ð®ØÈ·BJ r°›(ùƒÆ… úgÚ{ ú$`ÂÓ·ë–D•cöÝØ13‰ùÇ3Mš£ŠY±©„´€ F}ƒsìúÅô±^¥ÄÃB@<³ŽŸ8À;må1Á»,î{$Ò©Ëà?8¹2Z å>Œ™Â‘ú_QŠ™òáBcyv "ηÙj_Fù¿‹uI ãã*<WpÐ6MÒˆ‰ˆIp™Û•YÜ"Wú§±N)vìØÑ«5ܬ ÇâJ¤M@LBœgL€¸l?cõ,½É­oÞ»wïÿ)ÓoÔ?E©ò×õ›oªü õ( °BÁàYÔqý$1ö—¤Âw8ðÛ,dø(øxäÈ‘é:e*tcœ"BÆ \µâÅÂö¼Ké§rŸ»·mÛÆßçGEþšGÎA¹®ËñIEND®B`‚ic07.‰PNG  IHDR€€Ã>aËsRGB®ÎéDeXIfMM*‡i  € €HŽwIDATxí{¬WUvÇøD¼D‘‡¢t0ØV0#4ÓQAãhSÕ?ZM;˜tŒÉLÓiKúOŸ˜šhCR+£µ8Œ‚Õ>&ÆI§ ƒv@Ñ"W¤PÁ ŠŠ]Ÿß{×osöùó»¿{¿{ïYɾk¿k}÷Úûì³Ïï&IEZƒúúèo¹å–¡GŽ=hРQ_ýõ¹6žÆÏ2>ÜÜ0‹~<<ØÂ'™;Ó\Œ>·„CÇà·²­ŽýæˆßûÕW_í6¾{èС­\¹rÿñ¼}–µ;-\¸pâ)§œ2Åq¡¹ñ¦ˆ LÚÍ77ÖÜéæZE_XûÌm7÷Ö¿÷¬ÛÌ~gÿþý/½ôÒgæo[j˜¢/8餓f™ð¾aÒºÔÜÔãnhÛJ¯~ÇŽZ–í6¦ÍGÝd|ƒdý!C6šõ8R¿xÏçh ÌlŸef{® eŽ å*æ,s#»3\Obf9u§vZròÉ''ðSO=51 ’:ÕO|H_~ùebæ=¶~%Ö¿äóÏ?Oˆÿâ‹/’Ï>û, :t(M Ë— c9Þ40¼jãÿ™µ·æ¹çžë(YGS²÷ X§M˜×Ø€¯µÏ·žÏ0Çš\ˆP؈#’3Ï<³ÓqÆÉðáÓÓO?=6lXªèB•5!@9|øpê8à>ùä“”›ÙOöíÛ—|úé§e[úÀ üÌäóoæ}úé§ß+[A#ù{ ×^{í›y7[§™CéCêuEŸsÎ9ɹ瞛Œ5*9rdröÙg§J®W¶ÝÒ±{÷îM>þøãÔíÚµ+ùè£Rpé«á Ë÷¼ñ•Ï>ûìkEÊ4’§©X´hÑÖ‰[ü[6Ûç›c×I–'9ï¼ó’±cÇ&ãÆK•~ÖYlÞû7±´|øá‡É|¼÷Þ{ÉŽ;RK’7jÁV“å?ZžÇW­Zõv^Þ²iMÀM7Ýt‰­cKL©w™y–Õ D2f̘䢋.J&Mš”*Ÿµy “)6µÛ·oO¶nÝšÀ±úÚd¼ÖÊüímVÙFòئ%’¹Ht·`3~¶)ñ/¬Ã¿fP³|âĉɴiÓ’É“'÷IS^DˆÍÌæËÐÑÑ‘¼ýöÛQë`²Ýe“îOÌŠþý²eË¢ˆ©×·”V¯é7ÜpÃt{”ù[ÛØýzV~Lûå—_žL:5Ý eå©âêK€§,›o¾™‚AO)¾¤a…ï·}Ârã_û´"þR¸ûî»O±ÍŸÚŒÿ¾u®f}ç1lúôéÉW\‘š÷"WyŠK€ÇÏ×_=Y¿~}ú´–4ùÿáú§žzêÝ0-/\‹/ž`ë΋6ë/öbæg̘‘Ì™3'}Dói•¿ùÀ lذ!yå•WNxÔ´}ÖQÂìòÏ‹¶\7ß|ó¯Xå/Ú¶fƒÇî}Á‚é£ZÑ«|Í‘{…5kÖ$ëÖ­KX*<Ù!ØjÁb‹«»$ÔÀ]wÝu¥r¬±OV#Ìúy󿥿žÝ}E­“”«W¯NÏ|/ kgΜyõÒ¥KkÑá3™¿fÒ{¼eqëÍìwâp´zã7&—^ziR)?”Xï‡9 ½ä’K’;w¦§‘êY… v5ã­·ÞZ©¸,ž{;zôèglóÑù¶™ò/¼ð¬ºª¸I€w vÜž¦ù.Ø’ýíÛo¿ý7}\èÀvü“wïÞ}µ/pÕUW%\ÀÛØŠÚM¼ü²s™„§1‡Lf½´e ªçÎu]…Äí,þí…FçÏ©ÝìÙ³•\ñ6”/ÌfÍš•lÚ´É÷nŒ(]g«}¤üQØZ?ËŸÍó’†õ¿¢ö–Çìï¿ÿ~g'±övò[Qöšu$¯_E¼~­¨ý%`'´5ç1À^Q‹õÊ‘¿QbâÈJ";ÂaûÖ]´\Ó L!t,@‚ÅBh-D˜‚º˜M €@jGŠÈk³Õi(Uæ_ãdô½·Ê¢é(;#˜•2ïX Ê{`` A`¤Á N‚•Ÿp+H@„ËüÓw9ú-ekŒ­ègØfËvHa Ïs ”tœ,Š„/Žb”G S{ÔáÉ+K~•U{Ô§z§¼>ìëm7ÓÀ|³¡{A–ÐÅIWqŸ8PI1¤Cð,¥)_,ͧ§õÑ?mf3'‹Rv=ŽB½R½¿¿(­™Xë‘÷¸ºYîÜ›UoUÏ1 D`J<ÐBªÐ}-˜ £·w¢°f;mº u4ÚÿþVΰ56¦(¬ÐOc…êÅûu—¼(Ó+Ô‡å÷eñWÔ} ˜ÿ9VK7n\e…ê_*˨YÊ÷Yˆùtù³¸òW¼! üôÉ'Ÿ|9V2 €¥ö]¹ÑXÁ.Åj ♹YŠ$Nú}þ°¼ÊT¼´›,¿›W* Ù/ƒü‹½w.½xeÊï;!å+-‹\EKÀäwÿŠ+~‘WC.î¼óÎo¾ð ×ðÃDeH õeù¸<¿òW¼¸xç`g(ß›7o^îYO.l#¸Â^½üòËéïÑ‘YÊô]WzVœÒ<÷ù*¾/Ë8@³#ð‰vuï¯òJDpï½÷^gïæÏ×ëT~™Šï yõ¥i^y¡ßöiÄû0~¯¨˜ÆŸ‰#7éÍüßá×Ùc5D̓Ýàù}ÝÖ¡0¯oùuFà—B=Ç:)^Q¾¸ªÏï3¢~5Ì/Ù&×SÍð31˲j‰À^ÑNá—èüóϯQ¾^°p #¤P™>L^Â!÷y¤|Å¥™«?'H€;ü"+¿¿¬‰É-+¯7 ÙÝÍ_6Vv¯눈K!éÍïó¹íëÁà•'…ûòŠó\eÄ Η¨~dÁd¼øâ‹ÓßaeCØ_¦A†öàˆ˜¼¢À*9¬Y®Â¼WGÙžP@Áq¡ p±ƒ†uåŠü^Ñ*/E‹+a)^‘ý',3ó&LH&Mš”.Ç1™psÊ[®š(¢·<|Ì«W)޹øÉ?sˆ‘né°wÐ¥P] Áàëb<Ö^ŽGgüòfsç•7òg’z À7y€)ì õË÷Ø@ÊÍ#É£ŽÏ”± |*F}l&¥hÍr…CNºòäµ×_Ò ßYðÕ.kÙ•ÉÊw^7œðä–GQP“® „Q å‹ fv¢Œn¾‚Fö tÇma ’|R¸¸Q¤¾–‡+íL f+Jg¶#ïF¡hf¿ÙÙ¯„¦2U\Ϙµ( ó¯%¤ÑëRÎò’Õ^Zwßq"„tçŸåê`,;3œ‰ƒâõdÐ(g–3)Ñ'þÙzªGu€ÿ @Ÿ&Ñp0³ùô‹Át‡Øl†Nê\z²ÀO_ÚmIh0d}Ù¤ q£³ºž<ÑWåüD¢ òá÷ø€"TT‚rhˆÇ>î@ù|ãÇž€A8&Læ¼HÃEò ð,`P–™…C– ćñû<Ô Á½#N@£nü8ù#NJÇOzoýEþ|9¤q©}¬2ÿ]¤ÈÌW™B 3;Le½bÖÃ@ C|Œ%`McÓ×[‚Q;RŽÖß8ÊÕÒ*ž±²¿â"ü¦½ˆ €ÊÊÆ hfòˆ‚e¤±1CXëXóÂsƒ"ªò“³')žåYë ‡(øqöhYéaþ0\ a˜žO1ýX:Ç€cm ¬O¬C¬¼BñŸF~z܆gÍvJ ~ L™F©4hˆË&Ggé$0À @`¦Yp,„:1k±¬L"6Õøc˜éì»8l£l#³Þ×ߨ€†1ù¬M(\7(6…œàè<æ 00–,@ÐΙüZÓ}'û“y!#)žIcb1Óy #Ì*4"§† Æ@.ã¼@³s‘æ-yp œ„p€Î~_GÙr(®¨òë>“Ù"Gâ$£T€MúÓmÐIg,‡(G'Y”GÊ(( Œ8Mœ,åY.üã ÐÎ_¼7@B¿/Ë Eã3F8á²³‹Àøe%©ƒ¶¼š¤óšjšÕÂ'„žP ¦ 0Ž€gðäa³…éʃPòˆ:¨@Èï9e ãBò–Ÿ~à‡ãPn3B=ŒÐ˵ی6ÂñÅÂMé< ÐÚX$\„‚H€…Í%‚àÁ;òùöð“OeÒ‚-üCP,ýÄ16Ì9qyüz»»-@Ö ™¹Ú J8†L+Š•yÅOºã…, õ¤`¥8õQ}§Ï8ŸOþ¬ñ·*®mÀ`½gý÷À@˜„ÙgÀ½“ Q€fð(øQy!qêáW;p凫=âå”_aÕÓμé`° Y„¢X'®f~)PÖ®8ñzJR_¥0¸W¢÷‡iÍ_«ëéà©åq^é­n_h?ú]@w:ßL µcïNߪ²µˆÀŸ—¨¶žšP€q´C ëöMЛ(,_¯þ@„@ã¹üAŸ«`I ØdŽþû(l½]aí4´›CqYŽ~+^cðaùÃÍ—òV¼! |nrý§XÉ(n½õVPó“XÁ¼x¯@ò¡XÏå—³¸êH V–€Év¹}"¾3VA0%ü®±=±Â±øP¡ä#.$–!\ ”X¹°Ép³¸~/¯T.ì"¶Ùáˆ2ä•'Ū¼Âpȇc~•­xq —åý>úè¾¼R¹¸í¶Û¾±víÚ{žþùôX3¯"Ÿ–§Ü0_Lé>Þ—©üõ%À„åìÄŽÄxÇw{Ã)– 3?²SµÁ\ízæ™gÒW¾‘zj¢½òŸAéŠSØsQÖò¨¾Ì9å,²3ݰðcyòˆ`É’%³í^ß½kç>‹ÌH‘jXañ0ž°Ò²¸òW<..ÏÌ™3§ó•»ôf Xl?11V2zlW¿¿Ãå L›6-}ßNŠŠQ–Ãü +¯ê$ z_Y˜”Åó’ŒOÅgΜ™*¹­Y³¦³…ÛRp—EüYg¤óD`_Êûx@A•ˆsy˲Rž¸Ê†²¸òz. ¨|Å»$ÀÒÉ“''—]vYªx¥pÿÒëx»Vö«Jyvwo(ïÕEYŸ8¡ ½n%K")’pèWœ¸Ò=—òáY £ì@$.àò/|'Ùï0ûCB†ºw©4»Lý’÷ÄŽ—²J \O„¹ÉÖ€W¶ÜÖ\í¢s(NΗ¡“îýŠó<Í<€ÿ ϱcǦ?¡ÿ»»oЙäU& »°¹ ´1EÜP7nœ‚'p¢AWƹôÉ… ;<¤`*‘?ä´íÛ?¡Á~œ0åüF¿ùƒŠ®y Àæ=¢°N|’ü2@Üþõ‹UŽU`‰c@ºãÇ­aüR¶”ìÃò{k§?Ä39PŠæ»Kfy–yÏ+räco¡y$ä›Í<Š€BìüQ$7lDXãQ¦´'¿n¿ê·Y*°´cƒ)… â±zûb<Êfܘu&rÄù vÙq¡#>e‚Š%?áu§4Ïs@Ff,;N¾õQf?O ¨,Ñ9-*‹•õ8„¡%Cé}3@ÎŒDáp–B߈ÌbãGŽÌüPÑ[¶l©ûó0ÔY( åL:µóë_”igÓ‡Éb€Ý%Ú¡^,¬OB#DŸpÄc)ð÷  )EKáX3…{²?ÌzöY,ÉžŸ‰óáhª *¡1>Fdc‚ÂõÉ Àô€nÖ/¿þi¼L”ì …#t¡‹yáÞ©¼â|8\¤y×[@ÓxBN¿‘?Êg,ž˜<˜}Nl‹R!P•Ó(;SÖ,Ö/Ö–_¬‚|â1s­ívg=-*¸Þ·‰gêœ?l¥3óý¦=Ì“. 6ü6Vaó˜Bk@HZïEEI€ÙÎæ™g{x~ B›ó¬°Aàx´„°X—IíuÊB`à×£ZO?}0VÀêc#Ìøá„Ë(‹¼(YR–•ø2õHVexS 8&ž³‚˜Ñ˜yÒ4`Á 0B連ˆ¹¤MA T˜4Úð!-²f(ñšu(‚7C!ÈÉ[G/ЄýIîÁ?Mý,* ÁÌe߀ qÇLÂz°\ Õ ´¿€“W K3ÙÕ¥p+9}a,2ÿ1q¤IÙEeÖci:í$3S뾄#ŽÀ‚Ì+ñøášMãðg£Ñ¾e•Ci´/G?ÔGúF{%“·•ÊÎG ÙƒdÇ\#@@"AzŽ_a)G³0a™tõúÃ:¼°=µ©:TO–ÐÛ)®í€ÀY#áÌ(¯™&.¥VœW®W¢WŠð óiŠÏ+ÛNŠl´/} (µžÓÌlT ­\ù—ù$Äìiù]{³ê¬êé’@ÞïÊVÎW œ¼z!wí¥×`6»|¥¼Z?Ëh<—¿L=UÞL lÈŒµÈ(ìÔíÇ–ÞuÉ,VCF<ë0$ ˆ+.äR´ò…/òWÔ°ŽÚÔ£±ÒQ,^¼˜ë¤Ñ_–ˆUH<Š”ö?$…gq•'­¢Æ%`{¨?ñÄÑŸû‰€&Í |רֲÍKiR,å'¿O ã”&^QCØnçKòJæàúë¯ßk…ùÏÓ]_‰æÕv< JyR&IÞ¯j—Ç•·â¥$°ÏfÿM+W®Ìýßq¹ ¹E‹­3åÌ5oþ®o(Sä›çÓc~•«x1 ˜âwÚœÿøãÿw½u@×]wÝvóMóþ¼^…¤‡Š¬W&ÌO "+R¯|•^#ÿ0³¥­ûëkb#B ìÂ… ·Ø™ü\C×÷-ØõÙpFÅ^¡$û0þ0. Kñ*gm¦eª?¹Øoòºgùòå¿‘÷«`a …@ÁùóçyÍ5×ü¥=VL³à2s™ÿ® Å…J”â©'ôÎr²”©(*Õ—ÙäœfÊG']ëo´HWBCïæÎËg'÷¬[·îïŒÿ‘¹Íuýz„ )õX([ñÊ'®2ž«|Åk$°ß,ã?ØÒü×<òHáýYM hªäÊ+¯ü…ù¿ýꫯN´Ë¿gþß17Ú+Ïû)GXäÓB¿,¼¢ ó‡íBÌ=öرÿÓW“\.Ð-¨©Ù³go7ÿšÐÑÑ1ßü¿mÈ¼Éøp]»"¯”/ÆÅ@@¾Nÿkã_eòùáÃ?üZ3eѨCf’Øðó²?±ïÒ‡Xü›ÉØÌIùR6eå‡kæ+n€Z>Ãþ/“׿›{á(´£G–e©©ðÛÕo¾ezú¸ãƒ†ËL©ß²ðÕÆçš;%£àP銇Ëùºû¡Ÿ§ªWÍ­µñþ§]k{ñ¡‡ú´7ÆÙc;oß l´8ܤÙ÷Ɇî9æeî—là³ÌDá„ÀAþ~D(ûMs¯›Û`ãý¹Ý~~íÁÌ}´î©ñ÷ÂØ¿‹Ûbq¸Î_²´ec¢)K1ÝÜÈTKŸbn‚¹¾F»­Ã6†Í6^ÆtØrø–ñMK—.íúÉ•ªOœ°lݺuˆ-!ãmO1Î2ÑîýáknŒ…ÇXx”ùG›eá!æ:—~§EÁ†Ëäµ²G,?¿ž¾޳¸-ü¡ù·›‡õa‡Äm7%÷Š ï.~úÊ Ò~Øú4SÆ03«#¬?\8Ô3’: (œU¤¿~iŠ"*½c˜zŽùXYÍÎý–ç°•=d7‘÷Ù/‡ï»ï¾ÃÊ[ñJýBÿ5ý]„ôÉIEND®B`‚ic13BX‰PNG  IHDR\r¨fsRGB®ÎéDeXIfMM*‡i   gêI@IDATxí{ô^Uyç_®r ’BÂ=@AP«©ŠZ‡‚ERR,PvÚ)v­ÎÌZ:¶Nÿ(½èØ5ÓU[W«bÇ*"¨+ê’Ku¼€UPB \s'$! ˆ¨0Ïçðû†';çœ÷œóž÷öû={­ýîÛ³oÏÞÏw?{Ÿ}ÎÛé„ ‚Áà@p`êq`©×åÉÕãw¾óÓ~þóŸ¸Ç{°Ï>ûJï^|ñÅÌy…zú /ìiéÓƵðAF·Ùç̿åýÂÂO¹pÇòoÛk¯½Ìyág¿øÅ/¶ï»ï¾ÛöÞ{ïg—.]úœ§ ÿøq `ÈcvöÙgï}ÀÌ4¡›i<Ó„l– å¬=÷Üs¦5m¦ùq1{à„Å€>Øì0Í Vù6³ÛÍ>;á~Öú³Åú²Éü›¬/OÈO{à 7à†2ú8]tÑa?ýéOç™Ï·jæ›PÌ3÷(³ ÌÎ6;Ël¶j›;Õ à‘¹kGkŒ?«Ì¿ ¿i«M³Yi@°„éz`¬ ø¾&àÇØ„=É&ï‰VÔ æ.°0‚޳J‡éÆË'§«Í]ešÄcVÔæ_aà°âµ¯}íê+®¸ Ówá…ÎyþùçO± x‚M>}á„Àmþ½+$ýág+&샃ùï7p¸ïë_ÿú.çý©~üK HÆÐÕæšpŸi“éLK’“Epô9°Þšx'ÖÆóN…e_ýêWýf¶…SLØYÉß`Âþjcûéf_evÚ`‡`°µí·ß~¹Ú!]Ç´œÜ´I¹Áúr—÷M›»Óžl|ï_ÿõ_Š)k¦ \~ùåû¬_¿þLøEfÅ&Á"uáFÊXÛ:ûï¿Aµ§™_a›°{R¥ábí‘\ç¯xEǧ©CŠS¸®û³Ÿý¬cý²lƯŽwd A¼­¨;éÇŽçž{®ƒûì³Ïvžyæ™Q—‡­ƒß3û]ãý÷®¿þúåæ1ëôø™´`×ö;øàƒßh÷ͼåkÍî?¬1EX­=iÓ¦u:è Ì+!ÇEèv@`²4 @ (ÈO=õTfŸ~úéÎöíÛw‚Îx°ÙæÌm6ß5÷›gžyæ“ù qRÍ´w¼ãÇÚã£smà~Í&Ï[Íò¼| Æêízè¡;-‚.Ç`‡éλ Aî“O>ÙÙ²eKgÛ¶m\Lê^P{OXQ7 |Ýê½i²Ý_k`•Ÿ>}ú›mÒœkƒ„儾o†•¡FÐ;ì°ÌJ艟Œ+wߘٰ`„ëÖ­lÞ¼9sm¢Ïæ›kwØ3Î8ã‡ã®Œس÷½ì°ê-6ЗÙ`\`n_nÃÙ!Q&èGqDgöìÙ;-ª|˜Ñ䇘O<ñDgÆ ™Ý´iS«sŒ>´z³•ù%›‡Ÿ5Í€s„±;; @èí@ém†º¿eLþ ³­ÞžC}GÐçÌ™Ó9üðÃ3Ë „op@  €Ãºuë:7nä}‰V;fss¥•ùE³Ÿ70øQ«…÷±°‘€Å‹Ÿn ý}³Z;±çÀmîܹ#<2³?'æa¦Ð‚µk×vÖ¬YÓ±§Cžl´h´²®±…åŸí1ãšËm½¨‘®×Úý¦ ýZoßÐF<ðÀÎÑGÝ™7o^&ð3fÌh£Ø(c’p€s´aåÊ•U«Vµ?7}Åæò?šVðMó·«v´Àÿ‘®Û _fªÔ¶~q—¾±±225¡?öØc3¡'.Lp  4„Gy¤óØceà`B\%kÍ +ãSVö•v#qKá Ó†.öèîTS¿ÿÜ:ÍÞ¾±Îc¶ãŽ;®sÌ1Çtü¢oƒdnÔ598À£G€@€À¹BæiËûÌ~ø+_ùʆÊi%ëÐàüóÏ?ÆVå?µ^üžÙF‚Ï ¸ã?¾³páÂLðãЮ•9…”pág›°lÙ²ÎC=ÔˆçL#ø¤ÉÀ‡† |Þ‹ÿ3ãñïš­ý&'ö ,È„þÄO̮ÖŒW$úÆ®F<ð@çÑGmzA‰§|Ô쇯»îº­}klAÁ;Ü›nòþÒ:úÖ–} ÚSͳx»xÑ9餓Bè ¹ Ãâ—î¹çžÎ]wÝ•Ý`lÐŽm–çÏíæã?~ë[ßêiQ§îAÀöÖÝo›àÿoSyø Neã9Ô{ŸÇva‚£ÎÑ ž&Ô=<49Yn—~ïÆo¼}}í+œwÞyGð,Ô:òŽ:á9½½„Ñ9í´Ó²—eêä ÚàÀ¨p€«Ê?þñ3Í ÎÁ¡Æ‹vžõQ;|üÓü[[ïZßÀVýwZ'xìQù¡;'÷¯yÍk2á+·­u8$ð†ãí·ßžAkÉ&?«íÑøyöØðÞ~5½°‡ôý±5øš:S©|„ýÕ¯~uçu¯{]ön{¿:å†ÉÞlüþ÷¿Ÿ[…Šæ¶~ÿ—¿üå¨H_‹¬’€V-ÑÿkìÿµÎñf^W>°¿_´hQ<·ïÊ­ ˜,àÍÅû·ËžTí“ÉÕµ—V¥¯Jר…žCm%¿É„ÿ¬*•sªÎ9çdoÙU¡šàÀdãÀŠ+:·ÜrKåט îš5kÖk¯¼òÊÖ^\hÎ=÷܃mÿ~»íoNé6H\Öùå_þåÎë_ÿúxÛ®³"}Òs€/$Ý|óÍÙ]‚*µCõ‡í"ÒÉwÞyg+ Ð3ðòŽZ~Ó^àéúâ×um›]ä©ÒÙ  LÜ}÷Ý[o½µÒÍBûäCvïàTûôùO{åOÏ/¼›ð²Šðóžý{Þóžþ^G,òOJ¼êU¯ê\|ñÅ•>gòv¼}Oò6¾“Ñ+3z€%K–\b¹¬[#x ÷’K.É>ˆÙ6ÒƒS•\v»ôÒK³Ævã]C~µ \Ù®[zc±ÇüÓl?òmÛ÷—~#‹mReŸ¯îÖ˜HLu°Mæ·ûï¿¿ë7 ìÀý {|~—]A~ )ßk‡rÈ'lõ/ýê.â°÷üCø›ŽNä›’àC³\pA×Cr.٠ë.»ì²Ê—íR†6Òx±ÇT« „güöI¯Ž=¶HëŒpp 8Ð…úÊ4ÁWØ“µ}ï½÷Þo”Ñ¥ pQâ탙4ôÙ !/²¼µÇk»a‚Áf°?Î>=_$cÄÛ!<ömQ>¢I-µßǧ«ð7˾¸CøÝ&8hÎ;äËîËpk°‹±;xû¼Çhþ¦ Ýnɵ5€?ú£?:Ð^P˜Í×xŠ,§þìc‚½q€Þp–V$kÄó.-Ê7©©6Ìœ9ó|•§¬AóçÏoÒ–È$@Öø|}™¼Mhã§q6—d﬽0´9“Æ”{BP–iÁà@  Mó÷geÆnîi[ïS†(ªlj€!ÒŒn€J&8h‡Zý»•fgµ¹ÕÛ¼Ø ê|ý¤[§"=80Õ9`ú²-@&žðQÒÚÿ“Yì¦ÒÓeOh$ÿý&8h‡¼1X&sv!/«ÈîÔ~¹¯6Ø›HÏØ‹¥×ù_wn)ñ#Lp 8М|m˜¾L놦©© TÄ-%¾sVføêIÜ,ãP¤ºs€2.~JèEãnÓ¦M+Õh_Då/¶C €a‚õ9€êÏê^hÚÝž”ÕÜx6ɧ»©¼Ì€^¼ &8¨ÇþøÇbÛr—fä]nrXV@# @„*3¤ó%T¶ a‚Áj`Ï °Ø»‘[ëâyåÔ¾ ¨BPí«<ïç, ÛyÊ 78ètªỄ>Øu+ÞŸ€‚ùxù,3 [þb9Lp 8PÎd­¹›nõêÕÝȺ¦—Ko×ììE…nûŠÕ°a‚ÁÝ9À>~Æ •´e¶Öü)‹k¯¦xƒQ±d¶Üýg;À¡û’"ƒÀ_*óÐx:PÄ¥ˆŸj@&*7h¡½ãŽ;Jå¬ÿzÖ¨ ¡ø6,;°¿ï¬Y³¦ÒÕéHÐÆÈ ðÖ­[WIø¹ñ÷£ý¨ëá{>ô¬¨2‰½‹½.Ü™1cFgëÖ­ªŸN7ÙÃp8m`¤y#˜ `!ä¤_×x»õ µáïåÖ_^­…s#‰Ç\æF,jÿ¦M›rN§Ö®]›}.œmDl ò†(â&xVý:·÷XLÙóm›V€Æñ‡‚¼¼ÀÁÆôéÓ3‹°ƒxtÞ^àGs ´Ü h{˜£¼as€ý=s_wû«¶‡òÈîTÍS‡®u r:Ê5`4¡ ùT7õDÀ«?H‡Æ€6t{ÄX§£A|æ5 \ùÿ Àá _0ë”Q…¶/@Åtš½>Û@@×Ù"ð›§ÐY„ü@På1c•ÎMp`P@ÅGèë¨újçc¬ú~TZÛn߀†Â¾ÌÁ ˆ†À{4óZf :òcy‚Ê E°à¡â³¥m"¼È·ûØ*{9ég_û 4\×€Vr\B®Ž¡Ž%M€îð$K<  ¯¤*¸ÁarÁež³Úu óœ—zØïKS®[FSú¾ ƒ1ÜrBíç%"V~AŠtΙ3'³¬þhœ ÀX˜ƒ hBlšäkÊ$„ž¿©Ðr>€Ðs/* MÛV'ß@€¡|$•á‡T#PPû±|fKø¦°Ê\âN¸n›@8™Ã<–ù×Ô>–Õ‚¯¶ ¨ŽsÀÁ€Ç}8~Ô¨ôŒ@äi‡XÀ@š.` -ghÒ2˜83íËæ+s’E ·‰zïëdž®_¿¾óøã·v•×—ßÄ?P  ‚ òñ¸h0\ûÿ´S€î0 hº`Ae¬Â”v @ˆ­BÊÍ{07R-F¬øm¬ÎlcúAîù~•ùjŒÔ(´Vm ‹°¢À|€[d¼f e¢°5` <5М3`„ÐàÌÔ4Ò5G˜s½®òâ$ÚÏðÙö–ÍaÑËÐaVy¶Ü@]÷AÅ¢%H+À-3–ËFТ  `À xP‘† PÀ[ˆeï4´C/ðmöð`µçê;.á64ˆ6Û˜–5T 10f¾ìñSd•G¨9퇡 +=jZ™Ñ*Ï“òi« h{á5´ õ¡`\CS(ãöè¥1ŸdoŸ mÃbîðˆ_B?ê‚/> Ô›bðæÀ ÀúÕœ¼e O· h0ñy2”)ãA0(¤`%úpÇ挷:a?¦m·†¹ÇBÂÂ…àë‰@?ël»*od€!|Ú¿s X&`œl`¼Nkn&@™áœ‹v@^„͵  Ä£yÐÓ8/äøº~ ºo=cÏÜd[É/ ËãÉÆƒ²þLIH‚P XV{ Ç[V „=5¨îZbe ÓdcÂa ‡é—€œ0Fc*?€’I M_++«;“M.ÂîUHŠt1IUW   Š«I*ºp‹9 ^‹ÿðŽqÀÕ¥nqi‘Ps -èdŸ¬ZYpp&¨·Ä)útû@éB À¤¦¬©bÄCžàÒ\YñžxÿTáQÛý h‘£:dcõgrbü$xWéÜ:$^aå' H­V@C´-v¥µ¢ÔõÍ÷Ýûé‡hÔåMùØZ㢠ñØh°ú޳¡ý)HäMr €‚'>N¬¼r}ÏT&qâ3n¿òäÑú:Â?šha\PϽ" BŠWšâäJ½‹_a fžpçã©'óéÞm˜àhaè1B&¡•›§´"WÂÚBÓ¢ˆà@)v½*VJ:ÜÄQŠt=\NEíÁê¨Î«  L:Œ Œ2çCåщ¶•q  ôç’{Y+--¶]ÉSž&#ůžp§6Øj·¥ ¬¾F2ôµãQxp "LF6U$ÝIVìäzÝÎÜôŒ2Ä`€!ª*ä€]2[[˜XPìõ¿”Õ×èAuøzÊÂJóô}e@(çÀÖ… ./'Ù=µ6\rÉ%«­˜‡v/ª¿1EW_Ô/°Ê›Ò¦ñ>œç å`„‡Ào^qÅõ¾.c¬ »zÐDðd$„>NirE£0n}­è}ùE/××þàÀ8ð/Mêmö¶Û§¬²fßÁjÒJË#a“ªΣñé>O·xŸîËU¼\•np`ˆxØþsðëMêo‹/fðñ&6Í#!$¿üB…ë–íó©,•/W4JWا׭7èƒ-sà|ë[ßjôx¾ÐxûÌõ_›³¡åŽç°¨$AùóH|šür=½âp½õ4á ˜·^{íµK›ÖÙÎ?ÿ|ž9þ~ÓŠëæ“À‘¯Ì¯r¡‘Éóû¸”Ni¸ÞBçÓ|Xe„ ¶Øcùÿhõ½<ÙkVިǶ7Ø øßÖ¬³y*x¢8ï—Àú8üÑËÍ‹SšÜ,ãÄâR×Ó„?80 >3ñµè=ͽáÝï~÷œ^êl †>¿cÿ‚sš*¾ñot~øÃ*ªuWBIÁ©0Ö©,Í›†}YiáÔzúðúÁä‹ÿ§äƒ¯2Ú|­…-·)ìaÿ"Án¹å–]ªô^ÝÿV\4Ï3söÙg7ú¾g£LVáŸp"_fÎ:ë,. eÉ,£«“&&àrâ/×—‘—¦+ìËË‹+J'^Vù ´É#Ž8¢³hÑ¢ÎÝwßݹ뮻J‹¶¹xìœ9sÎ5¢J s€©'óO6E†ÿÄ;î¸ã²dþ#aÊ $t©ð_%NÕæµEeCãÓå÷é¢QœhT~¸Á¦à¯ãX<‘æôé§ŸÞY¾¼ü-߉yÈ… ÚP{ ð¡}èVÑ^@‘=öØcwSÿ% MãóIà$€¤).õ+ŸOWœhóÒÒ²–«2Ò°âà Ôáÿ7ùÊW¾²³dÉ’ÎñÇ¿S~¦OŸÞ9üðà eM2hu½Å^®-ϵ5Sýß\¶úÓi\d8ÈÐßcÑÅKØoˆW\‘zÒd¼_q¸Äû´¢°âEÛ&Àùö„rsÁ·ytN=õÔ—gfÏžÝõ¯å9“3Ma¡å/W’ j€ ïün°ÿþû'Õìä‘‚ƒ ´MØ•ª8$á“ÐIø‹sä§HxIU™¢¬öå(¸Á2 C'žxbç”SNÉV÷2Z¶ÔÝd09šgåôL¸÷-B*u¢Š@@ƒ6€å$“CE ËŒ„ROØûÉëÃÞ¯rUF¿Â*7Üà@f̘Ñ9á„:ÇsL¶øåѤqÌã*2gsû°4o·pm À²£ñ袎¸áÄ}zÊîÖYÊN…_ž¦UmåyS(R:_Føƒp wÞ¼yÙÞÞNëk3…›e2‡ü`LÊWМšk€©#[PñQß‹ Ï-›Ê@ë7zaCà%´e§U»|YiœÊ%>¥SX®ò†H9À r ,èp(^&Ài>ææŸFïýMå2j€ Ó |p&¨¾ÞO£iÔAä£+û.ýá&—!€¤€-«BɃ!^†¸4¬4¹E‚œÆ+,·[~¥‡;µ8€luÔQùóçwð÷j6oÞ¼Ë"˜WÞÆó¢+ÅÕJ6mZ©͆ ùePo,gÀ‚f€0JÀÓƒDŸ¦²pSVZ·ø4]a¹*'Ü©Çæä‘GÙ9úè£;¬úm; L{`þmݺµq•€™U¾l ûË€E[†:·mÛ–Y˜"0 =0£6 ŠË«¿Hp/7Í«øÔMé">öØcit­p# „ŒU^+n^­4Ð>WÜ™;wn‡½|¿ màm),õI3Ð@ÒÁÊdâ0eiyí}^ZÄ/˜;¨ó<¶CèYÈe8ß´©ûßü±ÍîEý§?€ÌœÒƒRexüñÇ‚šjmÂ>ñÄYÛË@í©$ÌÞU™>®È/ÚpÇ‹¨ôøÃ;¬3sæÌÒ•·Ÿ½CølæX™AûíöŽ@Y~¥õ¬¬€@·çþlX™u§Y•ÊÕvý†v£%h2‚Ó6 {Ÿæ‹ðhrag!@3d»hß³ÌÜôy­Gígåï&ü¤ÿä'?ÙùÊ^ÚÚP13i<4T*Ðv˜†¶<õÔS™U;À€' rÓ­ƒhÃè©‚ΜCðy¹f„=å ‹ÜU +¿³*ôe4=…#P<á”uŸ7ϰWçd Fi èÖ´&–¶rŽ!×Ó…x`ŒÐäd¥Ù!ðù¨´cVý"™IÛÿÐCuÖ¬Y“F7·ÔÎi<{'Þlbueÿ]t> m•GÕ j1@yO;L@ü¸ØnêÛ¨öu”Û%í FÐÑ:%ðøáû¸æ r‚ÜT™3ЬX±¢õ¯o· '’€*ApSÃÒ@l^XeÇÉ Í”= Чt€(^i¨´,Îbð#è²ÄA7™ #‚Ÿ·°äõ“ùsß}÷uÖ­[——ÜS\«€@°7á9)~Ô0,‡„Ü  Ó©ÐÀ ¶]Æ Š¸Ï ¥‚­€A“Ztrá, ©x\Å+®¨îAÆ{í‡-’úǪí?cK'þš´¨iœð30ðèŸ<Ær ÈÉìT9€“Àt¨¼tø Xâóâ|¾¼úSÁ\…Ó1ó¾ÛÓ²´$ä„•¿êù@š¿J¸u RÏ$Q˜8ܦ²-@#5QÉËeÒЃ¢göÐNu#„ð6Ìèp€9ÍJÏ>¿ÎŠOûPù= ÷£w}JÃy" ȨútLFÛn ¢Þp*„„yºÙúXqĽpG•Ì{0ætúT©J›Yõ9ì« UÊΣéP‚ÌAÛ„µŸŽùŸ•‹C@¬GÐ hX´Ád9'ȈO0GYíÙÆúù]µ7ä{øá‡³íqÕ.a°¢Ã¬ å Ëy¶ )¨ X@·¹¦ÊYü 3Z`ACp™«MV{zƒ,ðǺhËýV÷ó¸×wP¥.d¥×3\T~Vý<ÄL·Œ†– G”G€`c,n‡Û/ è=[TæaSƒà¯^½:»"? ÁW»T(¤ä®+7«=`€6€Íc„ß"  f!ø `ˆ`Ù;ù "qx¨!·0ÇV*l/BO;˜çk×®Í^øa¾ç-~½´·nÞCmbKÀ-@„”ƒ=­à¤ÁdÜ<°•À‚Ä€ Í@`Ày´‚@&´ƒ<ŽF\XhT }BÊ\åTŸÇ”×F™ym¯7p /§þ<ïGø1VpPæ3EŒBƒD° ) @`±¨jX e8r2¶Äq€ù¨ÅƒÕ¾hªË,ÊåÕ^½3J‚¯¾ ¨f °0›Ý?âã(ÂÊ¡¡¸lP¸¸¢ëÇ”  °MP> 0ub¨C`€‡‰[¦ÄsBó—Å¢-£yÍǶtÔü²¾ Ô(@Ú@ºoG°u!ˆA’J&¡VÞHx\ˆÅP¾î  0@ÊðåÝCPÈX5Ö?g\­îygM½t’9ÅCàQñYù5Ïz)wy‡táfßÎvÁõÚ€˜€0¢°m`‹ õ¾Û¡ «;–Û‡ ¼À-Áƒ†dd  íÈkŸò„;0¶Ì/èøû)ˆÌA]m§î~ÖÕ/®Ž¨s¨û0u>ÕDƒË=¶ ÀÁsª}?cÄÁeüð+Ü~m»–HÚ^òšzúq|õl¤€F¡ °OgÕFýïvX'áC¨„UÚ¤Ì ´º…Äc”¢½!ñЦá Ðnü€~¹iž¿ÌÆÞ"hXï—Rب‹yÀ¡[~´–øA¶ãeµï9P^PVñª¬¬Ð@ÏV?“ˆÔA"{À2£ Jl0Ò,@IXf˜´»xh“À@€@‹v’ºeuS‚Œ6å]ù%ì¸Ð S°¨[s…ñ–V8Ì6õ{œGè¸m ®aæÌKh¼lpu~€–€@˜Ún¤[ƒníShG7X¤ @œâIKý «ì4L<ùŠLº}BH½!]B*—>¥ñ„%à¢ó匊Ÿ¶i,q[ú#;*íìg;FÔq¤ ꫊4È‚0³r—i œK`L òË2ŠVÿºí§}Q*„uË ú—8ÀX1¶kž±"£ùðõÔùR++$j?+=&ª>… "PÐDñe°šê£âÉËäP°€C[  :Â-ç É8À <®’©*ìy\›ÒÇ@A‡w·&‹&KûVù}9äõOH#/@ @ÐÄÌ_VøË9ÿá­€š0~ÆÇ {y)S;5 âø³Ú£þóä@ @V„X€€Ë„T.´îéíF_´\¬&³§›ª~ÏKñ!ðúqðþ©Ê¯&ýhÂ5—A'ú„&".ÐD–KP!/š†7Ð ¼ËÄ÷ª¬Ï3N~x#È¥ÏX8ñJ|_é§âƩϣÚÖ€> ¡G}{:‘Æeâ+̹Fqj&é‰_ µ"*W‚}ÛFezW~Ú‹!Œ_Va[´¸Þ¯|ŠË ŠŸ¾r`,@a𬆾¡H(äÇ•‘`pÎ € N«%†_B†+P@“ð A¼ÊSÔ£8ïWºwóÒ§2D¯xÜ0£Å±€ÑbÝî­aÂk”*N®VDïBëÃN¹* 7ÏOÙÜ*þÝ[¾kŒ/#-wWÊ;ZAn,r€‡à Èyn^\mï2ÏßB¢ˆ)Ê—õËg€&þ(6s2oMF‘ßѦö8Ð/Z`b1 …íQip`48ÐÂ8„Уˆž9`gGµŸùÖÛ‹?ÝsKg ˜Y¦l!ÚZ·ÃµÀ*ÙT·’6èÚàb”1É9P[6k€]L¹{LP§¯·[x|‰:ƒø¹ÝYV—µÀ*^þrfÝÒKø¼@RTQ|•j”W´i¸(^trEnp`X0ÍüÇK—.Ý^·þÚð®w½ëy«ìúºõJ°ÉHð|œÒäŠFaܼ¸¼xOçëP¼\_vøƒÃä€ÍÉÏ7©¿6LTò/M*ë%„·ÈˆÆ§ÑçŧùEããGŠ7@ôU†?80hì°kãŸmRi#¸ð o¶É[“ ›æIOåH‹ÒEçÝn´¾Ì<Ú¢t_GøƒäÀ?˜ú¿±I}`¢¢˜[¼7iMI/t)\’e—$/ÈJPœ/Kq¢ÁUº\Åy˜à@›È›‹9åo4 ôÃ9ñ•¢À’%K¾m5|¬R--yf´åO›¥rq½:öþ´ŒÉŽ-ÍhŒb…qxÑžÊý§k®¹fKÓ7*´jþ±9µ=4ml*˜^½_å+./¬´Ô-nšæÃøe}žðÈ\}õÕ_饾žàœsÎyÆ þº@¼ô—»½´¤K^/lÄ¢,UÓEç]ü©¥O“.jKÄúÄí/ÿ½×²{*ÿô§?=ûk_ûÚ4¾8Óo#Á¤žT }œo‡è|\]¿ÊÈsW·ÌQ¦ŸŒ}e~×mŠ1áÿ©üíúÏ-u 2ú½äÙ™eñâŇØç©þÝþ7íÀ5kÖtŽ;î¸ì“Úì]úaù–>‘¥ýQž›W÷ÎFOx4É«¸ÐYŠ#uÊŸçæÅU©;+4~‚@øùļiÞ§œqÆ/Ü{|Å56=ivp•­ü3¨}Ó¦Më®».ûcÏÆ­é’QBY]áIé}UiZ®BëiÂèвùÓæ'Ö¿x÷»ß}v/u5»¸Èþ ë|_ù–-[:_úÒ—:k×®õÑ­ù%˜*Pa¹uãÓ|äWœwñ˦4>^õ‡h“Ì1Ÿ•ßÓö0PøÂE]ôÒÿÝûÄŠþÆ`ßÀÿT^|Mà¶ÛnÛùÌ<º&q6ÜÔ(-'œG/:¥ùü>®ˆÎÓ‹&Üà@›`Ž™gÿL]tÆfg‡Ûg繓ÓÈ4€Ë/¿ü•Û¶m;±¨Fn{“RÁ+Ê[5^ˆëMöiÞïé¼_4ŠÃõ~ŸîÓ?\«L†¾Œkø/‰ÓO?=k> PdH³¼Ï´€#‹hÊâ}ØãþŠ¿È*3‹-Êþx P}•4/p~’ïꓸ4Í·%ÏOœâåª<¥ÉõñUÚ4Á*˜={vùáoí8à€ÎÍ7ßÜ-Û¾ö§3¿gDÙ0MoVÈ›ø¬"zrÊ);“SáÜ™PÓ“ ¤p¥ù8_¼Ò‰«ã‡6¥W8Móõ³_ýç>ŒcÛùÿH;ÙÏž¦If.\ØùÁ~}v¾¬O¦ üŽ¥÷®¸âŠ}×­[w¨þ™&¯QGqÄήñéL,¾y¯Gy>­Šß \‘ ûr #‰÷»Ì¯4Ü<¿Êòij¯?üÁ*`•?í´Ó:'žxân²Ábº`Á‚ÎÊ•+K‹²CÂc.½ôÒv-¸œ0)¥¶pä‘G¾î‰'žÈþÔ2)kgpÖ¬Y;ý©¡aß‚«?ÕLiª„É/á.òw+‡|2øÓp^šèD«°h'ƒ`6˜QäOaÑ”O8á„Ry:üðÃ;?þxi£8|·ÅõuFÔ_°‹Ç•©ÿ´DëfÐ8ÙáüŸ²|^Øü$­\ÕSöõA¯°ò¤a•np Œ,¨öóçÏÏæ-iÈS7™CŽL¦æv++M¯­jíÓ­1´²¼0Ú0à`±[Ù*ƒ:$øÄù°÷+Mùª†}ðû°ÊHã|ã쟬ýæ˜  GuTçä“OîvØaµš‚|T‘ ·z[+šÀöÿe“D×bëô5†¼¨ÇÁêT½~Åù°üä%݇Užò…•×ÓÉ/×Ó¨œpƒžÓ§OÏõtMÞ§Uõ#Ý0Sûjÿ®V¡E6ù_¤Sk‘™¸«\I½IË@¸è0Ô´ëÆöJø1¤#иò«Œ4¬xå#=5iaYO«8OŸçó„jr€ÅËÎÊ2æÌ™¹ PUÎ0Ƕoßž{¨®2Ð&¦6PÉ´iÓ2!)«póæÍ/z1 ÇJ+ üá!` @HWz˜——¶©H«Ä‹&-3ÂS‹,T=j~¯Bï9Ç?OóÔ¬LxúéæÿÕÓx^ ê”F4}䗖͆H+ 8@úIØS7- ¡-2E­øÔ-*gœãá_ƹom¶ýàƒîpiÁŸ1cÆn‹Mumܸ±Tø©ƒwpššFÀ Œðñjb™á Á^µ€¼òÙb`) -h%¸M^ «Ë&h”.z¥‰Þ§Ëïi<]?Îá<~ŒsÚj;ÛP{.sçέô´«—ºYD‹²ÕŸ—„ìZ~ãjµ!léÛIi+ìmÁV‚™¦·¶—!2­Í€¢.@H'!ö®ÚàãäWšw•–ºžfÜý“Ah£h¯œwñØŽ…ŒÓ{i—ýcd˾³‘m}ËêZ¾|ùίŒ®(­1 lhÝ´ThËn5®n4™pyåŒB\«ç(ô£¬ ô‘EGÐq ͇²²ÚLãl áï6ŸXxÛxã¶'€Y2&Юs(Èj<,Pé©‚Ú€ð”K˜• ÌäCý¸¥u›|ãÖY1÷°l±ÃXÝËxÇ~9©Âÿûî»/[|ËÊ«’ÖPÌE°®'Ÿ|²°N:ÅvõkØH«†‚¤€‚7h muˆ•6û¶†ÿe0V,Hhx¬æœa±ý|¹Í|¨óØ*ÂÿðÃwÖ¯_߬¢$WÏ@yì½a4@€º¯=xRWD瀃ƒ„l `ÆE§ô² €e¢ÉÀ0Ø„ßhh:Vg;9áq3,@,Œé\+êǪU«:@[¦ 1œ G}tÖ:U„hhöJq¶ïâ”u\VV€›wðI˜œü ¹Ü*¨že‘µ{ÐÍh”Ò¾äò4¡ÇMŸì ºmÕÇœ`¡ä~ÕùñÈ#´*üô¥5 0n$1P 17¢¸$ÐIÇ:M<ê7‡0ƒ> ômiÃO&îc—' €^‚æ]øDvX¦­ºé‹sB+7a„+?é;îT0ìõÙ.sH]Å0'|ðÁ«[c£z[ EÅ¥p•[R\œ Ã\l`õ÷&pêÉàs6€J7Ù ‚ífÐ1ð ãOÃišŸ(SV™¸¾-ÐI“Q¥¯¶ËG8õó28áGªªûäD>î¹çžÒóµ—k¨ïk˜4ÜÐcPÓ&a,jééÁtœ€¢=ðHf÷sõÙ_žC‚XN©£Îm·ÛŹ´äY¶lY-ÀHËèn¨@õGàdO«‰Á ðt­¿ ´$,ŽÂ³Yµ-Üà@ ê³àÕ|46öûüÛš]?M_@ F¸¹;Ð#Ø^ýG;àr´T#ÿVôXâõì–}c˜àÀ(sE»e+œwXÜ­íÈÌŠ+jƒF·r‹Òû.Q¬òÔzÎ@EXÆþ‘'X4žáÇ@ 3±z¶ÛƒŒ5ñ3"@»EÍgãi˜´Ý:Í#ߣ>šm›ä¯S—§í;P™Ð{:Ȥ‰V ³€|€4˜¤Ç€šA€Îð’ÌKÍI¿­Ó€ƒ/þ²íí·ºŸ×®#ðò!àºV|è55’3,¥R H 'Ë#šú0Á~r  ¡§}þêÕ«³}Ã|ñh`@…0OïèR.Ìà ¤Eu‡›GŠ@ÀV 0à Ë^ôA3Ðã+u6Üà@] Ž£²€•ÍѪåR—à´âRÝÏkã@€ °üÉë2˜X-m¬ðâå³=å²°GiµW½;T !&Ï>vm |PôUÀaÖÓòˆPº30”‡Å üy/Ÿ(øÑ/?Âȹ“,BŸø6 å1·˜Ç?+Ûu´Ù^_ÖЀÆÀ,”bKwáAÔþz€@Öw(õ£MèžiiÞ†&5ô-àÄyCXtÞO¾4¾*Η1J~Ú¨q”«y’òb”ÚÝf[Fèl[ƒÁÄç©+=atˆ[ ò³ziòTÕÈWÅÐoÚ‚Ã4ç"츺üÐ`ÅKùG­/£Üž±€Qe¤ሼIéÁ@~èð“`ÐB}Ôd×ʆ«ÉHŒëdW¿åŠr%Ü„¡Q?½+¿xns4ç]åœÒ4¡5Ó°Ÿô¤ù-•ù|R¥§.é*ܶŒÚ¬òÔ&Õ¡>ˆÉU¼\â•×—éýYæøé+úÊÞz…û-~¬„„’¼Í­… á¦~…I ¤AàÇúòäÇõ~꥜4.¥óéÞ¯v+Žp˜Ñá@@ c!a Ư°\ѧ‰Fì]è$¤Ê§tòáǨînþ4°LZñ>NtáN>´0¦º5&AoÛE1!”- V± v½&¶KÒh$£Õª—ZãU÷Ql_´)8PÄ€"ÎD|p` p  …A  &FCá@m°ým{Ï”jt9¶5˜¤S’¶•¿ªšÃ•Ú`•<•SNߣúÎâ¨`Ì9`2²µnj€ÝzÛT·’6èGÚè_”è•&#OÔ-£6Ø#¯{¬’Ý?…S·æ1 ÷ ƒ¿(gc0˜S ‰¶8ßY·›µà²Ë.{Æ*¹«nE½ÒëÙº/GBéÓ§—ùZŸOe)Òòâ‹Ò”wÝÉb“¡=Ì'.\¸¼nþÚ@Æè¥u+j‹^)!Ì+·ˆFñäñùS¿«ü4¯häŠ.ÜàÀ08`2yíW\Qû€¾X?kv /³{ƒ½ð)Ýlj®Ìõô©?¯LÑ䥕ÕiÁ>ràE»þÉ&å7€%K–¬7¸²I…Mó ž±N¹*ËçQœ/OqÐ)>u}ãì÷}ç~LѶ/ý¾pw“¾7*2Äù 9ÛšTÚ$¯J^?™å—«ü¾¼4 ʼnN®OKý„ÃÌgí VÖ´ÎÆð®w½ëq«ô¿6­¸I> a*œ”¥4•+¥åÅû4Ÿ_yå*o}§p Ÿ°½ÿ»úê«jZGc ÂÅ‹_eεM+¯›Ï []?uù8оð¹Ï}îã½”ÓP±}Êêw͹½—FTÍë…<ÒÔß­<å«ê¦åùv¨Œ”&ÂÁ>sà;öEëß鵎žà-oyËÛƒ\` á‚P_6ùåR±ürË#š*.4Þ¦u©Œ²ú"-8ÐLíÿ͹ >ýéOïèµÌž€œwÞyí¢Î[ÍÛ× BeBØ+#ÊòKÀó\Å•å‡4›TãÐÌhc§óÿlåÿÕk®¹fKÌhhÈù矿É>aõ&ˆÚhX^^ØäoêR~Y^ÒdËh}þ0Á>ràû"ô¹ŸúÔ§^úÿú*j hË\`¤úôo˜à|¤…¶íV„HŸH|žIã–KùS·( ºÔB+(\Ó'=/¾jœ/;¯Lçi}ùãæWŸÆ­ÝS ½Ëmqyƒ _ÕÖ@òö·¿ýzó¿ÊìW׫›'lš¸©[§.å%÷« ÅáùEnp %ðo°ÿËþxöÌÏ|æ3µßò«Ú†¾~ømo{ÛZkȯûÛß¾ØP ›]µaet!*wêú¹lÙ²ÿ`Œú/þ5³»l˜¤X/øi˜2•Ž¿ÈÏ•­8…=]QœòŒ«ëû8®}Ñvßg¼ý¸Ù«®¼òÊm£ÖÆ‘1Æ©üvùòå3Ì]bö2³o0&îÁD•µ¸]x/ø„Eãód‘?¢IãÒxå÷ñyq¾œðOY¬´žsféÇ>ö±ïŽ2F<³N>ùdnòé±+z衣̽оDt‘ Þ"„Ï3r ½\"I÷áŒp"^~¹E‚ìãñˤñ>M4ãæÂ«ÉÐ!ò}µñïËf—þÓ?ýÓ÷¬/O˜!6ª[Õ# ¾ñÇüj ÿ=vÕªU§Ú„E38×þ;PÙÓ ;ÀàþüLtlžQZ^ºO“?¯ŒqŒËëï8öc€mf±—¿ÉæÛuùÈG¾oþüI5ÀFÕ­jlÀwlþüù÷ZûkÖ¬™aß#x«Mà_µð¯›+áÔ¤NÃF“™¢ø¼ô"Ú¢x•1.nh•FŠÅú¦ñêÓD¿öÑ~tM¥\#L4–àù9oÞ<¶ üOÁRÆ=7oÞ|¦¹~»Ùט}…ÙÆ ¬ü$ÊïÝ™§‘?!» ý³žµ˜˜½ÙøsÓôéÓÔäÛû»•:Bcž—†Ìü1Â'ì_Ú ím/SðBÒ¯Xçg›–Ù] “¿W»Kc ´õö{§ñâ»¶­üž=–þ¡­ò?Ãá¬ÜäIi¯m ùCÞ¤Âþ½ ùvÝò$SßYøW̾Îì fwyÔháÌ”‚häB;ÎfÜÛ߀÷ÏYž{mŽ|ßú~ûÞ{ïýÝ~ðƒœ3M)3© Il¤”ˆØ&ÝßÇü;È9ÓügZ­á ³…ñ¶pLŒ7YƤ¹u›Éç³î3{§·ð–í·ß~÷˜:?Ð{÷u=ú)y µ‰Ï$X6a¯‚Æ&ÉžëÖ­;Á&Ê«,ýt‹:Ñ,šî~fÃŒ&Pá´1š÷r®IDAT{ÐÆn¹:§ôw™ å/íG“E»¶jÊÀ®ìx)dˆ³„&ì=ÍÊ•+ݱcÇ/HœbtÇš{¬¥c¹¾àà™Õÿãû#Æw^*ò²/³ðƒ&èOõ§ÊÉ[j| ¶Å±ýÉO~r¨}0˜k+гDæ(,<ßܽÍÍÔíª®åÉZ‰ëýD¦q>ÝûÛ¤ícYÜ—_g|yÄ„œÕ|§Ÿx ?ò|u>LKh‰‘UŠù⿸—=¶<ÂN—çýL{l†Mô™6ágØŸi‡“‡›;Cá w‹ËŠÇõ~"Ó8ŸîýÝh»¥×)k‚ÖœQ½7[?6ã7•?q-Lp7Y¿7Ú!Üš÷¿ÿýÌ… Èì&U]ýõÓL@ö7a9Èè`sñhvº•·¿ Ô"‡Lø÷§Kƒnç“ £!~?‹#³—ÅAívËÿ3 ¿”bûnqψÖ\2m%Ýèž·¶ûJï^|ñÅÌy…zú /ìiéÓƵðAF·Ùç̿åýÂÂO¹pÇòoÛk¯½Ìyág¿øÅ/¶ï»ï¾ÛöÞ{ïg—.]úœ§ ÿøq `ÈcvöÙgï}ÀÌ4¡›i<Ó„l– å¬=÷Üs¦5m¦ùq1{à„Å€>Øì0Í Vù6³ÛÍ>;á~Öú³Åú²Éü›¬/OÈO{à 7à†2ú8]tÑa?ýéOç™Ï·jæ›PÌ3÷(³ ÌÎ6;Ël¶j›;Õ à‘¹kGkŒ?«Ì¿ ¿i«M³Yi@°„éz`¬ ø¾&àÇØ„=É&ï‰VÔ æ.°0‚޳J‡éÆË'§«Í]ešÄcVÔæ_aà°âµ¯}íê+®¸ Ówá…ÎyþùçO± x‚M>}á„Àmþ½+$ýág+&샃ùï7p¸ïë_ÿú.çý©~üK HÆÐÕæšpŸi“éLK’“Epô9°Þšx'ÖÆóN…e_ýêWýf¶…SLØYÉß`Âþjcûéf_evÚ`‡`°µí·ß~¹Ú!]Ç´œÜ´I¹Áúr—÷M›»Óžl|ï_ÿõ_Š)k¦ \~ùåû¬_¿þLøEfÅ&Á"uáFÊXÛ:ûï¿Aµ§™_a›°{R¥ábí‘\ç¯xEǧ©CŠS¸®û³Ÿý¬cý²lƯŽwd A¼­¨;éÇŽçž{®ƒûì³Ïvžyæ™Q—‡­ƒß3û]ãý÷®¿þúåæ1ëôø™´`×ö;øàƒßh÷ͼåkÍî?¬1EX­=iÓ¦u:è Ì+!ÇEèv@`²4 @ (ÈO=õTfŸ~úéÎöíÛw‚Îx°ÙæÌm6ß5÷›gžyæ“ù qRÍ´w¼ãÇÚã£smà~Í&Ï[Íò¼| Æêízè¡;-‚.Ç`‡éλ Aî“O>ÙÙ²eKgÛ¶m\Lê^P{OXQ7 |Ýê½i²Ý_k`•Ÿ>}ú›mÒœkƒ„儾o†•¡FÐ;ì°ÌJ艟Œ+wߘٰ`„ëÖ­lÞ¼9sm¢Ïæ›kwØ3Î8ã‡ã®Œس÷½ì°ê-6ЗÙ`\`n_nÃÙ!Q&èGqDgöìÙ;-ª|˜Ñ䇘O<ñDgÆ ™Ý´iS«sŒ>´z³•ù%›‡Ÿ5Í€s„±;; @èí@ém†º¿eLþ ³­ÞžC}GÐçÌ™Ó9üðÃ3Ë „op@  €Ãºuë:7nä}‰V;fss¥•ùE³Ÿ70øQ«…÷±°‘€Å‹Ÿn ý}³Z;±çÀmîܹ#<2³?'æa¦Ð‚µk×vÖ¬YÓ±§Cžl´h´²®±…åŸí1ãšËm½¨‘®×Úý¦ ýZoßÐF<ðÀÎÑGÝ™7o^&ð3fÌh£Ø(c’p€s´aåÊ•U«Vµ?7}Åæò?šVðMó·«v´Àÿ‘®Û _fªÔ¶~q—¾±±225¡?öØc3¡'.Lp  4„Gy¤óØceà`B\%kÍ +ãSVö•v#qKá Ó†.öèîTS¿ÿÜ:ÍÞ¾±Îc¶ãŽ;®sÌ1Çtü¢oƒdnÔ598À£G€@€À¹BæiËûÌ~ø+_ùʆÊi%ëÐàüóÏ?ÆVå?µ^üžÙF‚Ï ¸ã?¾³páÂLðãЮ•9…”pág›°lÙ²ÎC=ÔˆçL#ø¤ÉÀ‡† |Þ‹ÿ3ãñïš­ý&'ö ,È„þÄO̮ÖŒW$úÆ®F<ð@çÑGmzA‰§|Ô쇯»îº­}klAÁ;Ü›nòþÒ:úÖ–} ÚSͳx»xÑ9餓Bè ¹ Ãâ—î¹çžÎ]wÝ•Ý`lÐŽm–çÏíæã?~ë[ßêiQ§îAÀöÖÝo›àÿoSyø Neã9Ô{ŸÇva‚£ÎÑ ž&Ô=<49Yn—~ïÆo¼}}í+œwÞyGð,Ô:òŽ:á9½½„Ñ9í´Ó²—eêä ÚàÀ¨p€«Ê?þñ3Í ÎÁ¡Æ‹vžõQ;|üÓü[[ïZßÀVýwZ'xìQù¡;'÷¯yÍk2á+·­u8$ð†ãí·ßžAkÉ&?«íÑøyöØðÞ~5½°‡ôý±5øš:S©|„ýÕ¯~uçu¯{]ön{¿:å†ÉÞlüþ÷¿Ÿ[…Šæ¶~ÿ—¿üå¨H_‹¬’€V-ÑÿkìÿµÎñf^W>°¿_´hQ<·ïÊ­ ˜,àÍÅû·ËžTí“ÉÕµ—V¥¯Jר…žCm%¿É„ÿ¬*•sªÎ9çdoÙU¡šàÀdãÀŠ+:·ÜrKåט îš5kÖk¯¼òÊÖ^\hÎ=÷܃mÿ~»íoNé6H\Öùå_þåÎë_ÿúxÛ®³"}Òs€/$Ý|óÍÙ]‚*µCõ‡í"ÒÉwÞyg+ Ð3ðòŽZ~Ó^àéúâ×um›]ä©ÒÙ  LÜ}÷Ý[o½µÒÍBûäCvïàTûôùO{åOÏ/¼›ð²Šðóžý{Þóžþ^G,òOJ¼êU¯ê\|ñÅ•>gòv¼}Oò6¾“Ñ+3z€%K–\b¹¬[#x ÷’K.É>ˆÙ6ÒƒS•\v»ôÒK³Ævã]C~µ \Ù®[zc±ÇüÓl?òmÛ÷—~#‹mReŸ¯îÖ˜HLu°Mæ·ûï¿¿ë7 ìÀý {|~—]A~ )ßk‡rÈ'lõ/ýê.â°÷üCø›ŽNä›’àC³\pA×Cr.٠ë.»ì²Ê—íR†6Òx±ÇT« „güöI¯Ž=¶HëŒpp 8Ð…úÊ4ÁWØ“µ}ï½÷Þo”Ñ¥ pQâ탙4ôÙ !/²¼µÇk»a‚Áf°?Î>=_$cÄÛ!<ömQ>¢I-µßǧ«ð7˾¸CøÝ&8hÎ;äËîËpk°‹±;xû¼Çhþ¦ Ýnɵ5€?ú£?:Ð^P˜Í×xŠ,§þìc‚½q€Þp–V$kÄó.-Ê7©©6Ìœ9ó|•§¬AóçÏoÒ–È$@Öø|}™¼Mhã§q6—d﬽0´9“Æ”{BP–iÁà@  Mó÷geÆnîi[ïS†(ªlj€!ÒŒn€J&8h‡Zý»•fgµ¹ÕÛ¼Ø ê|ý¤[§"=80Õ9`ú²-@&žðQÒÚÿ“Yì¦ÒÓeOh$ÿý&8h‡¼1X&sv!/«ÈîÔ~¹¯6Ø›HÏØ‹¥×ù_wn)ñ#Lp 8М|m˜¾L놦©© TÄ-%¾sVføêIÜ,ãP¤ºs€2.~JèEãnÓ¦M+Õh_Då/¶C €a‚õ9€êÏê^hÚÝž”ÕÜx6ɧ»©¼Ì€^¼ &8¨ÇþøÇbÛr—fä]nrXV@# @„*3¤ó%T¶ a‚Áj`Ï °Ø»‘[ëâyåÔ¾ ¨BPí«<ïç, ÛyÊ 78ètªỄ>Øu+ÞŸ€‚ùxù,3 [þb9Lp 8PÎd­¹›nõêÕÝȺ¦—Ko×ììE…nûŠÕ°a‚ÁÝ9À>~Æ •´e¶Öü)‹k¯¦xƒQ±d¶Üýg;À¡û’"ƒÀ_*óÐx:PÄ¥ˆŸj@&*7h¡½ãŽ;Jå¬ÿzÖ¨ ¡ø6,;°¿ï¬Y³¦ÒÕéHÐÆÈ ðÖ­[WIø¹ñ÷£ý¨ëá{>ô¬¨2‰½‹½.Ü™1cFgëÖ­ªŸN7ÙÃp8m`¤y#˜ `!ä¤_×x»õ µáïåÖ_^­…s#‰Ç\æF,jÿ¦M›rN§Ö®]›}.œmDl ò†(â&xVý:·÷XLÙóm›V€Æñ‡‚¼¼ÀÁÆôéÓ3‹°ƒxtÞ^àGs ´Ü h{˜£¼as€ý=s_wû«¶‡òÈîTÍS‡®u r:Ê5`4¡ ùT7õDÀ«?H‡Æ€6t{ÄX§£A|æ5 \ùÿ Àá _0ë”Q…¶/@Åtš½>Û@@×Ù"ð›§ÐY„ü@På1c•ÎMp`P@ÅGèë¨újçc¬ú~TZÛn߀†Â¾ÌÁ ˆ†À{4óZf :òcy‚Ê E°à¡â³¥m"¼È·ûØ*{9ég_û 4\×€Vr\B®Ž¡Ž%M€îð$K<  ¯¤*¸ÁarÁež³Úu óœ—zØïKS®[FSú¾ ƒ1ÜrBíç%"V~AŠtΙ3'³¬þhœ ÀX˜ƒ hBlšäkÊ$„ž¿©Ðr>€Ðs/* MÛV'ß@€¡|$•á‡T#PPû±|fKø¦°Ê\âN¸n›@8™Ã<–ù×Ô>–Õ‚¯¶ ¨ŽsÀÁ€Ç}8~Ô¨ôŒ@äi‡XÀ@š.` -ghÒ2˜83íËæ+s’E ·‰zïëdž®_¿¾óøã·v•×—ßÄ?P  ‚ òñ¸h0\ûÿ´S€î0 hº`Ae¬Â”v @ˆ­BÊÍ{07R-F¬øm¬ÎlcúAîù~•ùjŒÔ(´Vm ‹°¢À|€[d¼f e¢°5` <5М3`„ÐàÌÔ4Ò5G˜s½®òâ$ÚÏðÙö–ÍaÑËÐaVy¶Ü@]÷AÅ¢%H+À-3–ËFТ  `À xP‘† PÀ[ˆeï4´C/ðmöð`µçê;.á64ˆ6Û˜–5T 10f¾ìñSd•G¨9퇡 +=jZ™Ñ*Ï“òi« h{á5´ õ¡`\CS(ãöè¥1ŸdoŸ mÃbîðˆ_B?ê‚/> Ô›bðæÀ ÀúÕœ¼e O· h0ñy2”)ãA0(¤`%úpÇ挷:a?¦m·†¹ÇBÂÂ…àë‰@?ël»*od€!|Ú¿s X&`œl`¼Nkn&@™áœ‹v@^„͵  Ä£yÐÓ8/äøº~ ºo=cÏÜd[É/ ËãÉÆƒ²þLIH‚P XV{ Ç[V „=5¨îZbe ÓdcÂa ‡é—€œ0Fc*?€’I M_++«;“M.ÂîUHŠt1IUW   Š«I*ºp‹9 ^‹ÿðŽqÀÕ¥nqi‘Ps -èdŸ¬ZYpp&¨·Ä)útû@éB À¤¦¬©bÄCžàÒ\YñžxÿTáQÛý h‘£:dcõgrbü$xWéÜ:$^aå' H­V@C´-v¥µ¢ÔõÍ÷Ýûé‡hÔåMùØZ㢠ñØh°ú޳¡ý)HäMr €‚'>N¬¼r}ÏT&qâ3n¿òäÑú:Â?šha\PϽ" BŠWšâäJ½‹_a fžpçã©'óéÞm˜àhaè1B&¡•›§´"WÂÚBÓ¢ˆà@)v½*VJ:ÜÄQŠt=\NEíÁê¨Î«  L:Œ Œ2çCåщ¶•q  ôç’{Y+--¶]ÉSž&#ůžp§6Øj·¥ ¬¾F2ôµãQxp "LF6U$ÝIVìäzÝÎÜôŒ2Ä`€!ª*ä€]2[[˜XPìõ¿”Õ×èAuøzÊÂJóô}e@(çÀÖ… ./'Ù=µ6\rÉ%«­˜‡v/ª¿1EW_Ô/°Ê›Ò¦ñ>œç å`„‡Ào^qÅõ¾.c¬ »zÐDðd$„>NirE£0n}­è}ùE/××þàÀ8ð/Mêmö¶Û§¬²fßÁjÒJË#a“ªΣñé>O·xŸîËU¼\•np`ˆxØþsðëMêo‹/fðñ&6Í#!$¿üB…ë–íó©,•/W4JWا׭7èƒ-sà|ë[ßjôx¾ÐxûÌõ_›³¡åŽç°¨$AùóH|šür=½âp½õ4á ˜·^{íµK›ÖÙÎ?ÿ|ž9þ~ÓŠëæ“À‘¯Ì¯r¡‘Éóû¸”Ni¸ÞBçÓ|Xe„ ¶Øcùÿhõ½<ÙkVިǶ7Ø øßÖ¬³y*x¢8ï—Àú8üÑËÍ‹SšÜ,ãÄâR×Ó„?80 >3ñµè=ͽáÝï~÷œ^êl †>¿cÿ‚sš*¾ñot~øÃ*ªuWBIÁ©0Ö©,Í›†}YiáÔzúðúÁä‹ÿ§äƒ¯2Ú|­…-·)ìaÿ"Án¹å–]ªô^ÝÿV\4Ï3söÙg7ú¾g£LVáŸp"_fÎ:ë,. eÉ,£«“&&àrâ/×—‘—¦+ìËË‹+J'^Vù ´É#Ž8¢³hÑ¢ÎÝwßݹ뮻J‹¶¹xìœ9sÎ5¢J s€©'óO6E†ÿÄ;î¸ã²dþ#aÊ $t©ð_%NÕæµEeCãÓå÷é¢QœhT~¸Á¦à¯ãX<‘æôé§ŸÞY¾¼ü-߉yÈ… ÚP{ ð¡}èVÑ^@‘=öØcwSÿ% MãóIà$€¤).õ+ŸOWœhóÒÒ²–«2Ò°âà Ôáÿ7ùÊW¾²³dÉ’ÎñÇ¿S~¦OŸÞ9üðà eM2hu½Å^®-ϵ5Sýß\¶úÓi\d8ÈÐßcÑÅKØoˆW\‘zÒd¼_q¸Äû´¢°âEÛ&Àùö„rsÁ·ytN=õÔ—gfÏžÝõ¯å9“3Ma¡å/W’ j€ ïün°ÿþû'Õìä‘‚ƒ ´MØ•ª8$á“ÐIø‹sä§HxIU™¢¬öå(¸Á2 C'žxbç”SNÉV÷2Z¶ÔÝd09šgåôL¸÷-B*u¢Š@@ƒ6€å$“CE ËŒ„ROØûÉëÃÞ¯rUF¿Â*7Üà@f̘Ñ9á„:ÇsL¶øåѤqÌã*2gsû°4o·pm À²£ñ袎¸áÄ}zÊîÖYÊN…_ž¦UmåyS(R:_Føƒp wÞ¼yÙÞÞNëk3…›e2‡ü`LÊWМšk€©#[PñQß‹ Ï-›Ê@ë7zaCà%´e§U»|YiœÊ%>¥SX®ò†H9À r ,èp(^&Ài>ææŸFïýMå2j€ Ó |p&¨¾ÞO£iÔAä£+û.ýá&—!€¤€-«BɃ!^†¸4¬4¹E‚œÆ+,·[~¥‡;µ8€luÔQùóçwð÷j6oÞ¼Ë"˜WÞÆó¢+ÅÕJ6mZ©͆ ùePo,gÀ‚f€0JÀÓƒDŸ¦²pSVZ·ø4]a¹*'Ü©Çæä‘GÙ9úè£;¬úm; L{`þmݺµq•€™U¾l ûË€E[†:·mÛ–Y˜"0 =0£6 ŠË«¿Hp/7Í«øÔMé">öØcit­p# „ŒU^+n^­4Ð>WÜ™;wn‡½|¿ màm),õI3Ð@ÒÁÊdâ0eiyí}^ZÄ/˜;¨ó<¶CèYÈe8ß´©ûßü±ÍîEý§?€ÌœÒƒRexüñÇ‚šjmÂ>ñÄYÛË@í©$ÌÞU™>®È/ÚpÇ‹¨ôøÃ;¬3sæÌÒ•·Ÿ½CølæX™AûíöŽ@Y~¥õ¬¬€@·çþlX™u§Y•ÊÕvý†v£%h2‚Ó6 {Ÿæ‹ðhrag!@3d»hß³ÌÜôy­Gígåï&ü¤ÿä'?ÙùÊ^ÚÚP13i<4T*Ðv˜†¶<õÔS™U;À€' rÓ­ƒhÃè©‚ΜCðy¹f„=å ‹ÜU +¿³*ôe4=…#P<á”uŸ7ϰWçd Fi èÖ´&–¶rŽ!×Ó…x`ŒÐäd¥Ù!ðù¨´cVý"™IÛÿÐCuÖ¬Y“F7·ÔÎi<{'Þlbueÿ]t> m•GÕ j1@yO;L@ü¸ØnêÛ¨öu”Û%í FÐÑ:%ðøáû¸æ r‚ÜT™3ЬX±¢õ¯o· '’€*ApSÃÒ@l^XeÇÉ Í”= Чt€(^i¨´,Îbð#è²ÄA7™ #‚Ÿ·°äõ“ùsß}÷uÖ­[——ÜS\«€@°7á9)~Ô0,‡„Ü  Ó©ÐÀ ¶]Æ Š¸Ï ¥‚­€A“Ztrá, ©x\Å+®¨îAÆ{í‡-’úǪí?cK'þš´¨iœð30ðèŸ<Ær ÈÉìT9€“Àt¨¼tø Xâóâ|¾¼úSÁ\…Ó1ó¾ÛÓ²´$ä„•¿êù@š¿J¸u RÏ$Q˜8ܦ²-@#5QÉËeÒЃ¢göÐNu#„ð6Ìèp€9ÍJÏ>¿ÎŠOûPù= ÷£w}JÃy" ȨútLFÛn ¢Þp*„„yºÙúXqĽpG•Ì{0ætúT©J›Yõ9ì« UÊΣéP‚ÌAÛ„µŸŽùŸ•‹C@¬GÐ hX´Ád9'ȈO0GYíÙÆúù]µ7ä{øá‡³íqÕ.a°¢Ã¬ å Ëy¶ )¨ X@·¹¦ÊYü 3Z`ACp™«MV{zƒ,ðǺhËýV÷ó¸×wP¥.d¥×3\T~Vý<ÄL·Œ†– G”G€`c,n‡Û/ è=[TæaSƒà¯^½:»"? ÁW»T(¤ä®+7«=`€6€Íc„ß"  f!ø `ˆ`Ù;ù "qx¨!·0ÇV*l/BO;˜çk×®Í^øa¾ç-~½´·nÞCmbKÀ-@„”ƒ=­à¤ÁdÜ<°•À‚Ä€ Í@`Ày´‚@&´ƒ<ŽF\XhT }BÊ\åTŸÇ”×F™ym¯7p /§þ<ïGø1VpPæ3EŒBƒD° ) @`±¨jX e8r2¶Äq€ù¨ÅƒÕ¾hªË,ÊåÕ^½3J‚¯¾ ¨f °0›Ý?âã(ÂÊ¡¡¸lP¸¸¢ëÇ”  °MP> 0ub¨C`€‡‰[¦ÄsBó—Å¢-£yÍǶtÔü²¾ Ô(@Ú@ºoG°u!ˆA’J&¡VÞHx\ˆÅP¾î  0@ÊðåÝCPÈX5Ö?g\­îygM½t’9ÅCàQñYù5Ïz)wy‡táfßÎvÁõÚ€˜€0¢°m`‹ õ¾Û¡ «;–Û‡ ¼À-Áƒ†dd  íÈkŸò„;0¶Ì/èøû)ˆÌA]m§î~ÖÕ/®Ž¨s¨û0u>ÕDƒË=¶ ÀÁsª}?cÄÁeüð+Ü~m»–HÚ^òšzúq|õl¤€F¡ °OgÕFýïvX'áC¨„UÚ¤Ì ´º…Äc”¢½!ñЦá Ðnü€~¹iž¿ÌÆÞ"hXï—Rب‹yÀ¡[~´–øA¶ãeµï9P^PVñª¬¬Ð@ÏV?“ˆÔA"{À2£ Jl0Ò,@IXf˜´»xh“À@€@‹v’ºeuS‚Œ6å]ù%ì¸Ð S°¨[s…ñ–V8Ì6õ{œGè¸m ®aæÌKh¼lpu~€–€@˜Ún¤[ƒníShG7X¤ @œâIKý «ì4L<ùŠLº}BH½!]B*—>¥ñ„%à¢ó匊Ÿ¶i,q[ú#;*íìg;FÔq¤ ꫊4È‚0³r—i œK`L òË2ŠVÿºí§}Q*„uË ú—8ÀX1¶kž±"£ùðõÔùR++$j?+=&ª>… "PÐDñe°šê£âÉËäP°€C[  :Â-ç É8À <®’©*ìy\›ÒÇ@A‡w·&‹&KûVù}9äõOH#/@ @ÐÄÌ_VøË9ÿá­€š0~ÆÇ {y)S;5 âø³Ú£þóä@ @V„X€€Ë„T.´îéíF_´\¬&³§›ª~ÏKñ!ðúqðþ©Ê¯&ýhÂ5—A'ú„&".ÐD–KP!/š†7Ð ¼ËÄ÷ª¬Ï3N~x#È¥ÏX8ñJ|_é§âƩϣÚÖ€> ¡G}{:‘Æeâ+̹Fqj&é‰_ µ"*W‚}ÛFezW~Ú‹!Œ_Va[´¸Þ¯|ŠË ŠŸ¾r`,@a𬆾¡H(äÇ•‘`pÎ € N«%†_B†+P@“ð A¼ÊSÔ£8ïWºwóÒ§2D¯xÜ0£Å±€ÑbÝî­aÂk”*N®VDïBëÃN¹* 7ÏOÙÜ*þÝ[¾kŒ/#-wWÊ;ZAn,r€‡à Èyn^\mï2ÏßB¢ˆ)Ê—õËg€&þ(6s2oMF‘ßѦö8Ð/Z`b1 …íQip`48ÐÂ8„Уˆž9`gGµŸùÖÛ‹?ÝsKg ˜Y¦l!ÚZ·ÃµÀ*ÙT·’6èÚàb”1É9P[6k€]L¹{LP§¯·[x|‰:ƒø¹ÝYV—µÀ*^þrfÝÒKø¼@RTQ|•j”W´i¸(^trEnp`X0ÍüÇK—.Ý^·þÚð®w½ëy«ìúºõJ°ÉHð|œÒäŠFaܼ¸¼xOçëP¼\_vøƒÃä€ÍÉÏ7©¿6LTò/M*ë%„·ÈˆÆ§ÑçŧùEããGŠ7@ôU†?80hì°kãŸmRi#¸ð o¶É[“ ›æIOåH‹ÒEçÝn´¾Ì<Ú¢t_GøƒäÀ?˜ú¿±I}`¢¢˜[¼7iMI/t)\’e—$/ÈJPœ/Kq¢ÁUº\Åy˜à@›È›‹9åo4 ôÃ9ñ•¢À’%K¾m5|¬R--yf´åO›¥rq½:öþ´ŒÉŽ-ÍhŒb…qxÑžÊý§k®¹fKÓ7*´jþ±9µ=4ml*˜^½_å+./¬´Ô-nšæÃøe}žðÈ\}õÕ_饾žàœsÎyÆ þº@¼ô—»½´¤K^/lÄ¢,UÓEç]ü©¥O“.jKÄúÄí/ÿ½×²{*ÿô§?=ûk_ûÚ4¾8Óo#Á¤žT }œo‡è|\]¿ÊÈsW·ÌQ¦ŸŒ}e~×mŠ1áÿ©üíúÏ-u 2ú½äÙ™eñâŇØç©þÝþ7íÀ5kÖtŽ;î¸ì“Úì]úaù–>‘¥ýQž›W÷ÎFOx4É«¸ÐYŠ#uÊŸçæÅU©;+4~‚@øùļiÞ§œqÆ/Ü{|Å56=ivp•­ü3¨}Ó¦Më®».ûcÏÆ­é’QBY]áIé}UiZ®BëiÂèвùÓæ'Ö¿x÷»ß}v/u5»¸Èþ ë|_ù–-[:_úÒ—:k×®õÑ­ù%˜*Pa¹uãÓ|äWœwñ˦4>^õ‡h“Ì1Ÿ•ßÓö0PøÂE]ôÒÿÝûÄŠþÆ`ßÀÿT^|Mà¶ÛnÛùÌ<º&q6ÜÔ(-'œG/:¥ùü>®ˆÎÓ‹&Üà@›`Ž™gÿL]tÆfg‡Ûg繓ÓÈ4€Ë/¿ü•Û¶m;±¨Fn{“RÁ+Ê[5^ˆëMöiÞïé¼_4ŠÃõ~ŸîÓ?\«L†¾Œkø/‰ÓO?=k> PdH³¼Ï´€#‹hÊâ}ØãþŠ¿È*3‹-Êþx P}•4/p~’ïꓸ4Í·%ÏOœâåª<¥ÉõñUÚ4Á*˜={vùáoí8à€ÎÍ7ßÜ-Û¾ö§3¿gDÙ0MoVÈ›ø¬"zrÊ);“SáÜ™PÓ“ ¤p¥ù8_¼Ò‰«ã‡6¥W8Móõ³_ýç>ŒcÛùÿH;ÙÏž¦If.\ØùÁ~}v¾¬O¦ üŽ¥÷®¸âŠ}×­[w¨þ™&¯QGqÄήñéL,¾y¯Gy>­Šß \‘ ûr #‰÷»Ì¯4Ü<¿Êòij¯?üÁ*`•?í´Ó:'žxân²Ábº`Á‚ÎÊ•+K‹²CÂc.½ôÒv-¸œ0)¥¶pä‘G¾î‰'žÈþÔ2)kgpÖ¬Y;ý©¡aß‚«?ÕLiª„É/á.òw+‡|2øÓp^šèD«°h'ƒ`6˜QäOaÑ”O8á„Ry:üðÃ;?þxi£8|·ÅõuFÔ_°‹Ç•©ÿ´DëfÐ8ÙáüŸ²|^Øü$­\ÕSöõA¯°ò¤a•np Œ,¨öóçÏÏæ-iÈS7™CŽL¦æv++M¯­jíÓ­1´²¼0Ú0à`±[Ù*ƒ:$øÄù°÷+Mùª†}ðû°ÊHã|ã쟬ýæ˜  GuTçä“OîvØaµš‚|T‘ ·z[+šÀöÿe“D×bëô5†¼¨ÇÁêT½~Åù°üä%݇Užò…•×ÓÉ/×Ó¨œpƒžÓ§OÏõtMÞ§Uõ#Ý0Sûjÿ®V¡E6ù_¤Sk‘™¸«\I½IË@¸è0Ô´ëÆöJø1¤#иò«Œ4¬xå#=5iaYO«8OŸçó„jr€ÅËÎÊ2æÌ™¹ PUÎ0Ƕoßž{¨®2Ð&¦6PÉ´iÓ2!)«póæÍ/z1 ÇJ+ üá!` @HWz˜——¶©H«Ä‹&-3ÂS‹,T=j~¯Bï9Ç?OóÔ¬LxúéæÿÕÓx^ ê”F4}䗖͆H+ 8@úIØS7- ¡-2E­øÔ-*gœãá_ƹom¶ýàƒîpiÁŸ1cÆn‹Mumܸ±Tø©ƒwpššFÀ Œðñjb™á Á^µ€¼òÙb`) -h%¸M^ «Ë&h”.z¥‰Þ§Ëïi<]?Îá<~ŒsÚj;ÛP{.sçέô´«—ºYD‹²ÕŸ—„ìZ~ãjµ!léÛIi+ìmÁV‚™¦·¶—!2­Í€¢.@H'!ö®ÚàãäWšw•–ºžfÜý“Ah£h¯œwñØŽ…ŒÓ{i—ýcd˾³‘m}ËêZ¾|ùίŒ®(­1 lhÝ´ThËn5®n4™pyåŒB\«ç(ô£¬ ô‘EGÐq ͇²²ÚLãl áï6ŸXxÛxã¶'€Y2&Юs(Èj<,Pé©‚Ú€ð”K˜• ÌäCý¸¥u›|ãÖY1÷°l±ÃXÝËxÇ~9©Âÿûî»/[|ËÊ«’ÖPÌE°®'Ÿ|²°N:ÅvõkØH«†‚¤€‚7h muˆ•6û¶†ÿe0V,Hhx¬æœa±ý|¹Í|¨óØ*ÂÿðÃwÖ¯_߬¢$WÏ@yì½a4@€º¯=xRWD瀃ƒ„l `ÆE§ô² €e¢ÉÀ0Ø„ßhh:Vg;9áq3,@,Œé\+êǪU«:@[¦ 1œ G}tÖ:U„hhöJq¶ïâ”u\VV€›wðI˜œü ¹Ü*¨že‘µ{ÐÍh”Ò¾äò4¡ÇMŸì ºmÕÇœ`¡ä~ÕùñÈ#´*üô¥5 0n$1P 17¢¸$ÐIÇ:M<ê7‡0ƒ> ômiÃO&îc—' €^‚æ]øDvX¦­ºé‹sB+7a„+?é;îT0ìõÙ.sH]Å0'|ðÁ«[c£z[ EÅ¥p•[R\œ Ã\l`õ÷&pêÉàs6€J7Ù ‚ífÐ1ð ãOÃišŸ(SV™¸¾-ÐI“Q¥¯¶ËG8õó28áGªªûäD>î¹çžÒóµ—k¨ïk˜4ÜÐcPÓ&a,jééÁtœ€¢=ðHf÷sõÙ_žC‚XN©£Îm·ÛŹ´äY¶lY-ÀHËèn¨@õGàdO«‰Á ðt­¿ ´$,ŽÂ³Yµ-Üà@ ê³àÕ|46öûüÛš]?M_@ F¸¹;Ð#Ø^ýG;àr´T#ÿVôXâõì–}c˜àÀ(sE»e+œwXÜ­íÈÌŠ+jƒF·r‹Òû.Q¬òÔzÎ@EXÆþ‘'X4žáÇ@ 3±z¶ÛƒŒ5ñ3"@»EÍgãi˜´Ý:Í#ߣ>šm›ä¯S—§í;P™Ð{:Ȥ‰V ³€|€4˜¤Ç€šA€Îð’ÌKÍI¿­Ó€ƒ/þ²íí·ºŸ×®#ðò!àºV|è55’3,¥R H 'Ë#šú0Á~r  ¡§}þêÕ«³}Ã|ñh`@…0OïèR.Ìà ¤Eu‡›GŠ@ÀV 0à Ë^ôA3Ðã+u6Üà@] Ž£²€•ÍѪåR—à´âRÝÏkã@€ °üÉë2˜X-m¬ðâå³=å²°GiµW½;T !&Ï>vm |PôUÀaÖÓòˆPº30”‡Å üy/Ÿ(øÑ/?Âȹ“,BŸø6 å1·˜Ç?+Ûu´Ù^_ÖЀÆÀ,”bKwáAÔþz€@Öw(õ£MèžiiÞ†&5ô-àÄyCXtÞO¾4¾*Η1J~Ú¨q”«y’òb”ÚÝf[Fèl[ƒÁÄç©+=atˆ[ ò³ziòTÕÈWÅÐoÚ‚Ã4ç"츺üÐ`ÅKùG­/£Üž±€Qe¤ሼIéÁ@~èð“`ÐB}Ôd×ʆ«ÉHŒëdW¿åŠr%Ü„¡Q?½+¿xns4ç]åœÒ4¡5Ó°Ÿô¤ù-•ù|R¥§.é*ܶŒÚ¬òÔ&Õ¡>ˆÉU¼\â•×—éýYæøé+úÊÞz…û-~¬„„’¼Í­… á¦~…I ¤AàÇúòäÇõ~꥜4.¥óéÞ¯v+Žp˜Ñá@@ c!a Ư°\ѧ‰Fì]è$¤Ê§tòáǨînþ4°LZñ>NtáN>´0¦º5&AoÛE1!”- V± v½&¶KÒh$£Õª—ZãU÷Ql_´)8PÄ€"ÎD|p` p  …A  &FCá@m°ým{Ï”jt9¶5˜¤S’¶•¿ªšÃ•Ú`•<•SNߣúÎâ¨`Ì9`2²µnj€ÝzÛT·’6èGÚè_”è•&#OÔ-£6Ø#¯{¬’Ý?…S·æ1 ÷ ƒ¿(gc0˜S ‰¶8ßY·›µà²Ë.{Æ*¹«nE½ÒëÙº/GBéÓ§—ùZŸOe)Òòâ‹Ò”wÝÉb“¡=Ì'.\¸¼nþÚ@Æè¥u+j‹^)!Ì+·ˆFñäñùS¿«ü4¯häŠ.ÜàÀ08`2yíW\Qû€¾X?kv /³{ƒ½ð)Ýlj®Ìõô©?¯LÑ䥕ÕiÁ>ràE»þÉ&å7€%K–¬7¸²I…Mó ž±N¹*ËçQœ/OqÐ)>u}ãì÷}ç~LѶ/ý¾pw“¾7*2Äù 9ÛšTÚ$¯J^?™å—«ü¾¼4 ʼnN®OKý„ÃÌgí VÖ´ÎÆð®w½ëq«ô¿6­¸I> a*œ”¥4•+¥åÅû4Ÿ_yå*o}§p Ÿ°½ÿ»úê«jZGc ÂÅ‹_eεM+¯›Ï []?uù8оð¹Ï}îã½”ÓP±}Êêw͹½—FTÍë…<ÒÔß­<å«ê¦åùv¨Œ”&ÂÁ>sà;öEëß鵎žà-oyËÛƒ\` á‚P_6ùåR±ürË#š*.4Þ¦u©Œ²ú"-8ÐLíÿ͹ >ýéOïèµÌž€œwÞyí¢Î[ÍÛ× BeBØ+#ÊòKÀó\Å•å‡4›TãÐÌhc§óÿlåÿÕk®¹fKÌhhÈù矿É>aõ&ˆÚhX^^ØäoêR~Y^ÒdËh}þ0Á>ràû"ô¹ŸúÔ§^úÿú*j hË\`¤úôo˜à|¤…¶íV„HŸH|žIã–KùS·( ºÔB+(\Ó'=/¾jœ/;¯Lçi}ùãæWŸÆ­ÝS ½Ëmqyƒ _ÕÖ@òö·¿ýzó¿ÊìW׫›'lš¸©[§.å%÷« ÅáùEnp %ðo°ÿËþxöÌÏ|æ3µßò«Ú†¾~ømo{ÛZkȯûÛß¾ØP ›]µaet!*wêú¹lÙ²ÿ`Œú/þ5³»l˜¤X/øi˜2•Ž¿ÈÏ•­8…=]QœòŒ«ëû8®}Ñvßg¼ý¸Ù«®¼òÊm£ÖÆ‘1Æ©üvùòå3Ì]bö2³o0&îÁD•µ¸]x/ø„Eãód‘?¢IãÒxå÷ñyq¾œðOY¬´žsféÇ>ö±ïŽ2F<³N>ùdnòé±+z衣̽оDt‘ Þ"„Ï3r ½\"I÷áŒp"^~¹E‚ìãñˤñ>M4ãæÂ«ÉÐ!ò}µñïËf—þÓ?ýÓ÷¬/O˜!6ª[Õ# ¾ñÇüj ÿ=vÕªU§Ú„E38×þ;PÙÓ ;ÀàþüLtlžQZ^ºO“?¯ŒqŒËëï8öc€mf±—¿ÉæÛuùÈG¾oþüI5ÀFÕ­jlÀwlþüù÷ZûkÖ¬™aß#x«Mà_µð¯›+áÔ¤NÃF“™¢ø¼ô"Ú¢x•1.nh•FŠÅú¦ñêÓD¿öÑ~tM¥\#L4–àù9oÞ<¶ üOÁRÆ=7oÞ|¦¹~»Ùט}…ÙÆ ¬ü$ÊïÝ™§‘?!» ý³žµ˜˜½ÙøsÓôéÓÔäÛû»•:Bcž—†Ìü1Â'ì_Ú ím/SðBÒ¯Xçg›–Ù] “¿W»Kc ´õö{§ñâ»¶­üž=–þ¡­ò?Ãá¬ÜäIi¯m ùCÞ¤Âþ½ ùvÝò$SßYøW̾Îì fwyÔháÌ”‚häB;ÎfÜÛ߀÷ÏYž{mŽ|ßú~ûÞ{ïýÝ~ðƒœ3M)3© Il¤”ˆØ&ÝßÇü;È9ÓügZ­á ³…ñ¶pLŒ7YƤ¹u›Éç³î3{§·ð–í·ß~÷˜:?Ð{÷u=ú)y µ‰Ï$X6a¯‚Æ&ÉžëÖ­;Á&Ê«,ýt‹:Ñ,šî~fÃŒ&Pá´1š÷r®IDAT{ÐÆn¹:§ôw™ å/íG“E»¶jÊÀ®ìx)dˆ³„&ì=ÍÊ•+ݱcÇ/HœbtÇš{¬¥c¹¾àà™Õÿãû#Æw^*ò²/³ðƒ&èOõ§ÊÉ[j| ¶Å±ýÉO~r¨}0˜k+гDæ(,<ßܽÍÍÔíª®åÉZ‰ëýD¦q>ÝûÛ¤ícYÜ—_g|yÄ„œÕ|§Ÿx ?ò|u>LKh‰‘UŠù⿸—=¶<ÂN—çýL{l†Mô™6ágØŸi‡“‡›;Cá w‹ËŠÇõ~"Ó8ŸîýÝh»¥×)k‚ÖœQ½7[?6ã7•?q-Lp7Y¿7Ú!Üš÷¿ÿýÌ… Èì&U]ýõÓL@ö7a9Èè`sñhvº•·¿ Ô"‡Lø÷§Kƒnç“ £!~?‹#³—ÅAívËÿ3 ¿”bûnqψÖ\2m%Ýèž·¶Š$„„‘ÑH‘d‡93™äœdâ3™‰ãd2ög<>'çHŽ7‘pÈh·%!ÉR4R$[`Ä¾Ó tM M’¦~þš¢¸÷½ûî­»¼÷¾:§^Õ­½¾{oý¿úWÝz£‘0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#0—ì7—­v£Àœ#ðÎw¾ó¨C9ä 'Ÿ|råþûïðpÄOúÓ#öÛo¿ƒC×V{ðÏ~ö³#ƒ{@pWÐ]â‚=H{XðŠŸtÁþ½†÷š2šš=¡€'ãBB]»B]Ïì {4øCS~ú³p½“°pýlpé~üûT¸ÞMXH÷L°;C¿ŸÞ³gÏ›6mÚõ±}Le…$6FÀt‰€ @—h»®…@àâ‹/>ú©§žZ„Ûš èV¾*¸G‡Î­ .Âú¨¶b¯ŸëUÁâŽã‚{x°6Ï#ðd!àõXÂ>¾×…T<ŠŸø@ˆÛü;BÚ‡:è »wïÞñÅ/~¢bcŒÀŒ˜Ì˜“/o{ÛÛ9ì°ÃÖ=ûì³ëCÏŽ ‚e]Þëƒ{l¸^ìš pV‡kü²¿Ípx"4e‡ì^‚Àõ¶à0Ü»íÁÞîëƒÁnûô§?ýðpšî–þ0è{×Ü"\pÁáað?> üëqCUƒSðo~„û1{]fç6Ë…ËÛ±ƒ½$aK ÷‡ë{÷†m}Õ«^õÀå—_þÓ傯½]&L–én/H_ƒ þà°†¼9 Ü'µð ÁÅîò¡››‚ͱ¾ ˆ¹5`?ö`ï ¢°e/A¸;…»ƒÿ®Ï}îsÄÛ¹DÀ`.oÛb7ú oxÃ+W®<á'?ùÉÉ{…û‰a°=!ôúÄ`_,³x?»›ÞØ ÏéÝ¡%cwïõ$Üæå†Þï0¢ÀqT{ìÅ#ÌOIìÉáúÄ`ã]íáÒÆÌ%ld¼­ÈZ{0—÷s¡m°P·sx¹è¢‹Ö5ýaVtzhöŒ`O vs°ÞL@°YZøÚáÖðnÜ´7„÷ä¦<ð†uëÖÝæÏ#—ö™è´ã&½¸•þùë÷ì¯=DÀŸT¢û3ƒ]¬0Õ`“âÁÞìM¸$ܾTù±?y hØdCÀ ”ËQÐe—]vÐý÷ßj˜±œzÌÌ!Ÿuy#`ÚC€M‰÷ 1øA°?†|þóŸçšÃ˜lŒÀL˜Ì×r%~ûÛß¾*Ìê_fóç†æœÐ{fø/ ÖªûåzÜÛa#À>ƒë°á=ýA ç?xôÑGoüÆ7¾a°1¥˜”B³\á@œaýñû½ŸYýË‚õ3²\‚{»°Œpkx—)Àzè¡}ÕUW=½Ýs/r àÁ=ŠsVjüíÛ·Ÿ…×bCó_,»ïmæp$î(hjöµ<½Þy>øàQøÌrl£àyÃy ü×À¾ðôz_„=ó€À“¡‘×ûÝ@ ¾ž™ï~êSŸÚ2 wÛAÀ \Ujøã™¡Aú×íu™ÝÿH&¸6-!þôf„ E ãmжŒÃ‰ *ÛQ˜…8×àä%Ž|ü„aø¤ëÓ„ÿCWv¯ž~ú¹‰%þgžyfl!Âp¹&Ž´ Ó5ñ„ãÊOz›Ö€|Bðþn°?ôFÃÖ1L&ƒ¹ù>ŸÙýB°?ìß–Oîlj € ÿ0Ðiüé5ᲤG`smÓ °ë}L D ÂÿŒ XüXÈBQx¬µhÖŠ¥Ë½'†^°ÿV - KÒa€ù¿Ñû…sïùôn,ðÃË‹»~þ»Õ^˜Eyä‘£Ã?|Ÿ‹PWXìï{–Ý ‹[2ÂRþjylŸxâ‰}þ]»vãÃO´6¥ †ùQ°ß cË7)ûÖŸÿùŸ?RšÚs…€ À\Ý®çû®w½ëä0hýðB¾) vÌò×Ía7²79à1:âˆ#Æ‚a¾bÅŠñõQG5†k¡žú¹-² xüñÇÇ„@.ä@~\´6c`K|mðõà~%h`¾yõÕWóoŒ6sˆ€ ÀÜ´plî‘ab Ap™ñ/¥Aµ~ôÑGÂŒ­ü~üîKùX´Þi–# áóºÑÎ;÷¹ø G£°¤†O ¯ äû«ÁýjÀçÁøóÃ9yLx£Â_îÿýïÿ¼°éëüм¿쫃}~›÷Ûœ«IlŽ[µjÕX˜ã"èå2{g#œh ØGydŸ‹r€¦aIÌáŸ_ ý½:l(üó¿ø‹¿x`Iú=—Ý4Èm ÷Ž /Í›ƒ€{GpüÇ ¤iÙ›ªžÙúš5kÆvõêÕû>jzâmŒÀ¢ €ö &;vìa~øáñ†ÆEégA?`=ßïó’剅ì%X&T€Çà‚<ÒöxKÂæ½—„êß^Ôú¿ìsßxõئœUó©ÂAŸºñwë9ëtYF`ž`ÿD@VÄ€} h¶†ÉÍB¿¾–ò¾%Ú½€}œ«.™t|»úAà¿3T{q°|—¿÷€5øµk׎…ýúõëÇ~®-è;~À\ÝB Àç,'<ôÐC£x`LÂá]ã/¢ƒ£Âÿka,¼*,Ÿ|ÆŸösWBøô]õZ/¼ð³ó}OxØßÜ—WÏ9¼”ôcŽ9fŸEÈs­j†×b·È,aìo>|ðÁÇÄ`Û¶m#ìcÍýgú»ÃØøåпÿÎÐøBÐ <ºwlø½0hé…™>‰ûþP<3}æ™;ƒ°ÿM>:öØcGÌê5³÷F¼¹»•nð#À2‚ÈÚì/!ì ·ê+Á^|úŒ?1l÷Á5ȈoØÈwl(î}Á"øÿVÆ¢[/*•ñnû7Ž6lØ0¶ ûÖ¡wF ;ˆ@øëî±½ï¾ûƧ&f¯¨Ýw…qéÓaáŸîÝ3ೡ3ãmÐÐ7¼á ‡†gØÄ÷Á`ßl¿´WìßË£º?î¸ãF›6m |NƳ1F`1`OÁÖ­[ÇÄ—=,+̉áóÂÿ7´÷ÿ _|kNÚ<øfšÔ¼Eá4¾sÃw®/0ÔKCGÕ,¦³llÒ;þøãÇ—ùÌúmŒ€XN8»"°eË–Ñ=÷Ü3&sr,òuaìúX°W|æ3ŸÙ¹œw/O¯-fÀ‘oõCò_ö²`ùG½Á¾f÷¸Ìö-ð{»Ü0#Ð;ü3#{ wß}÷Øå ƒþŽòóÏ~ö³_ þ¹Qg S€ w"lèû[á!ûïBRÖ÷¨¥ó$‘»yóæÑ‰'ž8v9=ÏÆ#P„?{îºë®1!`OÁ€— ~ _#ý‰¿"¨~ÇMJ°â8ÞýèGoü? IÞT’¬·`fóÌêø'œpÂX½ï {½ÝWl– î½÷ÞÑí·ß>ºóÎ;‡úùá®p#>¾`úÝOúÓ7.üMiØA€ÀðÇ;G‡C8~5Ø„ÿ It¯—œ…ÒI'N>ùäñ,ß|ÓëípåF`©àxcˆ„böD þµS÷sŸûÜׇ԰!µÅ`ïÝ8ÿüóO¬ñÁÿá4ˆM}Ìòùö^BßëøCzuÜ#`„Ú– wÜqÇø/–7—+üðO…Ÿð?¾ðn,=ûN ü/Á~ ØÞ?áãðÔú§œrÊx¦Ïf>#`ŒÀ¼ À>ö@n¹å–ñ ¤íw†vüV8mðÃ>§Ò¦^›±´ Ï{F@þŸ†‡•]ýöyø \ÖñO;í´ÑK_úR«ÛçÍpÝFÀdE€ÿ3€ `ùÂ`f[÷ÿ¯ÐŽÎxríé­ KGÂŽþ3Ãf¹€‹ê½ý¹<ë÷¬å#ðq½žßÛ;àŠ€èþõðÖ[oÝ|óÍト:ª¶¬šBÄo‡ÿRø½°4À'…Kg–†¼ãïØÿo„;ü‘`{™ñ³¦ÏQ»gžyæèe/{™gúK÷º¹ÃFÀþúøÆoÝpà ã>Txî–Pç¿K–µ“±m,ž„]ýG†?•øûAøþ³f/›û8uõþYg5 Ç·}O]¾0F`n`ÏKh »wóOÁ½˜B­—‡¯®ê¥ö*]XÎè?ðè£þÂÃõÏ®k»Æ–ƒy˜é#ôùS#`Œ€˜Œ‡ÝvÛm£k¯½vüi!ä k&‹_ öŸ„c†¯éºî®ë[Hvö¿:ù‚ÅíÔð×¹gŸ}öèŒ3Îðº~§È»2#` Î`yàoþæoúø{cÎøáxä_ûâ¿øØ"á÷e¡@Øà·60·ÿ#tðÃÁvÖ7fûÌô±¨ûmŒ€0F üAZk®¹fü§Ekî ½øŸÂ²À•yz3¬R:’-w{¿0ëÿÕPÇoÛ™^½zõèÜsÏ«ú½‹¿å;ìâ€Xz|ðÁÑ~ðƒñ^Žÿ¨è«áŒ–¿Ž¾e‘nÂÜ€p‚ßúpcþ ÌüÏïêÆlÚ´i,øO=õTÿÃ^W »#`ŒÀ^ž|òÉñÒÀøÃÑ®]»ºÂå© }¸®·Íz\¶0FÀ´ŸrŽÀ·¿ýíÑO<Ñf…l|_Ð|¶ÍJr—=xðîw¿û¸ð¹ÇgBÇÏÍÝy•Çç|þ“N:IAv€0F`Axúé§Ç¿ÿýïØ8؆ àgAð¿…}üçÌ\˜A€·¿ýí'…µø¯$[‘Ìü ïk^óšÑk_ûÚkþ6FÀ#°¸ð¥ÀW¿úÕÑ]wÝÕZ'ƒ,ùÏá4ØKæáSÁÁ€°ÓÿÜ ¾ù‹p—ŽiãNñ¼ozÓ›üçtîÐŒËxéK_:þ‡~xl¿0FÀ,)h¾üå/·²I0h9ì°ÃNýä'?ùÐá3þ½ï/ƒ=*'X|ð(ü=ðø_úr–벌€0F`þàh᫯¾z|†@îÞ„½f;9äÓ Ø–»ì¦å †\tÑE§†Ý™ß Z×´Sqþµk׎Â~‚ѪU«â`û€0FÀ¼þ[àë_ÿúˆÏsšðû#á_c_qÅWlÉYnÓ²AÂÌŸSý¾ì‰M;ççìþ·¾õ­#ÿS_ŒŠýFÀ#P†ÀÖ­[GáœÿìKAýHÐ ŠôN.»ì²ƒ¶mÛö_ºÿSvCf ë.c•?ÕkcŒ€0F`ø‡AHÀ}÷Ý7K¶©iؽ⪫®Ú15q zÿøý¸ãŽû߃ð_®¾ò=ÿ\0:묳rérŒ€0F`‰`ߨ™gž9zøá‡Ç6W×Ã2÷Š@Þúº×½îã?øÁžÉUnÝrz%|î„ÿÇÂéIY4¨úÃ^‚ßøÛ#`Œ€¨‹šäÓN;m„6 h©ëó¢|¬rïì°DýŸn¸á†Ÿ½(A‡½€óÏ?}˜­=ôõˆý ŸZŒ.¹ä’QÐ(ä(Îe#`ŒÀ’#ÀÜ” %gäZÂTO š€ÂÿðÕ[o¦7ØÏGC¯ÏËÑsfþï}ï{G6lÈQœË0FÀ#0Fpâ‰'ŽO ܾ}{Tø?‚ðyàÏ…¥êo]ýõwf)´F!½€pØ‚ÿwƒm¬úGMÃg~›7o®Ñ}g1FÀ#0izè¡l{§†ûð¦W½êUríµ×îžÜ‚vb÷o§Ø‰¥Òé……?µ¼å-oñ¿øM„Û‘FÀ#ÐH@øƒºlšf´Ánzæ™g~¿iÛêæïœ„Ùÿ/‡¿¢nƒã|ìôùË_ÙoŒ€0F Âäu6¯Â¡>YÊgoA0]zé¥çg)pÆB:'À5c “s²ß/þâ/Æ9Ð#`Œ@¬X±b6±Ð45œ8øì³ÏŽÂÆÀû†7¼áÀ¦åÍš¿Sfÿ¯ ³ÿÆßè<ßúó­¦0FÀ.àËÎ Èa‚L¤˜—­_¿þÃ9Ê›¥ŒN ÀQGõ›³4®,-ªÿc=¶,ÚáFÀ#`ZEà~áFáS¾Æu À†‰í¿üЇ>”gm¡b«:S9\|ñÅ«Ÿz꩟㤾&Àîç~®IÎkŒ€0F ü­üyç7úö·ù›f† á‹¶ {öì¹(”ôÉf¥UÏÝX¹råvîܹ?›(š˜sÎ9gtÄYÎjÒ ç5FÀ%G€ÿ›¹æškFAp7BBû ‚û+¡ Î@gKaæþfÿM,äáŒ3Îh´3#`Œ€È2‰½Mäy9Ï6þbЖŸ’£mUÊh6¯RÃÞ4a£ÃYMgÿÇü(hf¨ÕI€0FÀ´‡ œéðnT ûBœ“óPпhTXÅÌ€Ë/¿üô»ï¾ûà¦à%/yIÅn9™0FÀöà“ôÕ«W}ôÑF•±`ï'o uB:Ygõ_‚Š£©šÄgý7z¾œÙ#`Z@`ãÆå[4A>÷ýïÿŠšù¢";ÑÁnÔ¹5¢J»ÿ>úè*IÆ#`Œ@g09½ãŽ;ÕÇBøRŽ2Ëç÷¿4*°BæN@ØÙx*³ÿ&&œ!åä¥&mp^#`Œ€0)|™ÖTÆQ&_@‚=;\.YÕTÀ7—6FÀ#`††ÿ ÐTÆÅ} 2³“¿·íJpXSprœ¸l¿0FÀp,}SG;Ð"ð5@Ø3·)G»¦•Ñ àÚT=ÂI#`Œ€0CC€óü›Ê8ú„ðßëvrÚ]ëà£ýèAáÓ†ƒš²#€ñsá#`Œ€ü­oSG—DÂ^€NÖ¼['áðžý·lÙÒ˜0›#Ø$acŒ€0F`(ppS @2ÉíDеN¸A¹ÖGžxâ‰Ñ‘G9”{îv#`Œ€ÔT€NPí„°C²); NZ2èä¹p%FÀ#PÇ{¬±ŒcAצ€ðç;ɦÿ˜ôÈ#Œ6mêdsd×÷Áõ#`ŒÀ"ðä“OŽÞM5»wïî¼÷zÅwüMU»vퟔ„FÁÆ#`Œ@ßlÛ¶­±ð§,qwm:#‡vئÔÔlß¾}´ys'g$4mªó#`ŒÀ#À¤ÍtÓ%n4M5äu`î”°PŸ9Ôi,y{ýúõã…uËp>#`Œ€0M`BÊ—iMÕÿ=ôPÓ¦ÔÊßàßÙC ðÀX Pëv;“0FÀä@€YûÃ?ÜxöO[ }˜Îcßó75ì`ÃË 6FÀ#`ºF€µ&¶Ø&†¯ÛúXÿ§ÍÔ$œéßt3 G p '4Ÿ²lŒ€0FÀTEàñÇk³›ªþ©YÖ—é”ÐI´9–ØKðàƒŽŽ=öؾ°s½FÀ#°d ÅFö4ÝølÌüÑ$ôe:'0&6†ÿhÜgˆ0¬X±¢qY.À#`ŒÀ$4ñdã_Žcéo½õÖñ÷“êl3®ÙâEÍ–åükß;vô¶~R³ûÎfŒ€0s†ÿEÃf½ûØè:ûÚü'è{!lš@ ÃpSPÇôqŠRŽö» #`Œ€6¹å åÝtÓM½wº@¯ÑäP¡P–˜ÙSO=Å¥0FÀl0[ϹSÿÎ;ﱑ°oÓ@ø³!0—am†Ý”9oR®¶¹#`Œ€˜?4¹Ì)¬ùìï¶Ûn½zÏ.ÊœûÚ¸Yƒ¸Kn„0FÀtŠ€äIÎI%‡]{íµ½nü‹Aìü+€¸rüü±çäø*@es¬"å­\¹2Û2ƒÊ¶kŒ€0‹òƒÏórmø-Åõ×_?¨ýj½€9òÈ#ÇÚ€;wf9$ˆ2)‹›·nÝ: 6FÀ#06”³±<Çuqe¨ýûÞõ·¯KicN9å”Ñ1Ç“mÖÎ9[·nÍÊâÒ6ûÚ#`&Žì%Ë-üï¾ûîÿ†fCØÄÇ?ýAN?ýôÑÚµk³T9÷Ýw߈¨`lŒ€0FÀÄ ðüȠ܆ro¾ùæÜÅf)o0€Þ ¬9Øç ƒmܸqtê©§Ž×ñ›öÁO¹Üê°1FÀ#ü¹Ü–-[ZY›g?ëþC5ƒ"€´gÏž±°ÆÏ›7oΦàœ–r~ÒA;mŒ€0F`¾`ÖÏš<ëýh sʾæškZ);W[± 0í ›0ÒœñÏìSѰ¡›Ål¾î #¬ Ö·fÍšl'¦}ðµ0FÀ d Ÿöq¸O]92­W,;ßxãƒ_v$\çqÄû@ÔÒÿÈZ «®Jm7騣Ž­ZµÊ_ L{¢oŒ€˜sø2Œ šæ¶ ›ýn¿ýö}r«­zr”;X@çØ¸ àÄÀxW&al\½zõX€V€f50AþM¯( ²acŒ€0‹…òƒþL,÷Û0hn¹å–ѽ÷ÞÛFñ­”9h@™é‹¤‡2ð§B,‚\ªýY‘B‹€6¥ˆÀa‡6kNoŒ€0C@“<„[ê~ºÌôºë®kå+‚6!< ó¬Õˆ”ýëû°¨ö!un8ƒ/ \ÿXØæ tÙFÀ#ðBüìóbk_˜*ÏZŽ÷Ç?£› ÀmBÍÏLŸSºŒÍq´ðqÇ7Ú°aÃøæCRÍÁ´ÛÉ`K'l"0 1Ç#`úGÁÏ?Ýýa³ô‚Ïo½õÖÖIÆ,mš%íÜ:…&sôÑG7qLìÚ'i`/ya„U$&œ\TµNgŒ€0“Ðxæ·Î~°É¥¿8ÙsÓM7'¦/ŽŸ¹"ÀŠ çf³sÿÀÞÀõ$ai€òá,ìM‚Xˆå e°1FÀ~@ÌÄÁß¶ª_=EðŸ4UÚ¡»sG!ŽðKUn3øõë×øŒuÊA;PÕˆ°$À~–#öÛo¿ªÙÎ#`2 ÀŽßÿ®?uòy‡É-Š™Kø0>fþÚµ_U@^„¶6 ¢.‚ Y¨ª:‚l°·€|h !|‘`cŒ€0í!ÀdÁÏÒl—†Y?kýó¸ÑoNsKè* Nä ,<Ìr“ÈÃaa“ʶ¬@ý0O– œ!©ð>±1FÀäA€1ϸ\EÓ›§ÖçJaC8‚¹°ˆf® 7„a `Îú<*zÔõ³¬óS*},š4 ö*d‚ú!XêV9lD´1FÀÙ`2ÇR-c|ÙW_³—Z-c:úÜu×]-1TkYÞTsO€–¶mÛ¶ñ,¡‹E-[$nÖ‡­„K~ˆ„  ¡ NiD¼i0ïCëÒŒ€XL«™H!ø»žíƒ(‚ŸåÝ;î¸c<ö/&ÊÏ÷j!Ý-rˆüàÔñÌÈyÐpsg5 „åψ`¢"ÓHuñcÙŸÀÚccŒ€0Ï!ÀXÉD‹ñ•qzÚØÚn,1 øÙ^GV´Õ®6Ë]HÌÐ!ÌÜ5ëfÃDËC†­kXçÇBìÜi íâáÂBN h¼DP÷N8Ÿ0óŽ“6fûþ®vòa†Là|Øè·lf¡7öÈä¯~ã?÷0 g6ˬ²¶_ö0°×@g h¿KUÈéY"ÀÒY“2´nŒÀ¢ €ÐGàc«,©¶ÙodÀ=÷Ü3^>îKëÐfÿª”½p€N3#g×&‚:6ofßÞ¦Ê÷ ðp£>‚ T!¬´Ò0˜ ÄwÌ~#`æ–`%ô«~jÝf÷ù–ÿþû½m³C({! €€Eå·6!›""0M•ç/ò³Ì O y詟e‚išê…0`!.,_H3 ý Eõ9Ì#044ž1¹é[½cC[ØÙ/UÓñ>.{^ý M¸)_¾à?Š„iÈ¡b³ubìÒ  %˜fDX& –- Ú×0-¿ã€0]"À>_ZÕch®ö3ãO{˜Œ ©]¹úפœ…'€ÃR€ö” QÔð`æ\kTÔ‰å Êf‰BP…  IÀ’ž6Š àz© É£ï¼FÀ4A€ñKBŸ1jH3j=Ÿó¡æg£¶M1KAèºvà§ûbhX*eùµB;—ðXÊ…ò€RÏ4CH§´|^H[e!6FÀ6`–Ï ¡ÏØÕçÎý²þ1iCã‹à¯2Á*+gY—†è†òÙ ‚]ÿ&¨ð"—%ÒI½ÅƒŸS…$ÍûhD@„  ›æa'âBy\ö#Ø#`ê"À¸‡ ÇæÔˆÖmϤ|Œ|Î*Æè*ãç¤ò–%né7uKw„å4ƒªÍVÉ <7»„lðÇFX^<ˆ d[…ióÀkýþˆ@D4ÒÓúíx#`–ÆÆ5 ý¡©õÓ;Áà‡ Xè§M¿^J,°D6ÙñI âSE8J¨2Ëæe‘:>§V€¶A8tÎeópCØ€¦ Š)#"l.ô’A$Æ,&P„=BŸÉCÕ±¥O4טíoß¾}ßl¿ÏöÌ{ÝKKtãâU—”WBòSFH·ÁBµ9¢¢ãˆ¥ö祭jRB@>´Òàú˜âªh:˜/xÿ§öšåCæÅÐffûhn5îÑ'›f,=>³î*K1äh$DYRàá„TÀ¬Û0:,ˆM„´[d€%ƒ*Kq›È%/R£¾ˆXK#f¿>F„»„=îÐÕùE¨26¡¥Eè3¦b,ô‹ªf°;Tí|ž`V0œÕ@$ ÆÒ ð¶aâ}”ùо±äYêÛ¬|ÔfB`R Tìa  {Íðqs/KvÕ[ˆ KLÈp韅~{è›$Ø2s‡yBfÕÄEA ( Ö¶4Ô­Ï9o€ í„ Žv@}‘–@ œp‘ˆ,Ÿ$Ú#ÐB„;–÷R3ûyöBJBŸÙ¾…¾PéÆõ¨]€3/"/;ÿ›ªÁŽ–xØ¥¨3K/hnau²$eà@€‹ 4%!E¤@K!‚˜ 4Å®°s4 Žã„„½>î¢ú‡Æ•Óù—<ÓïçΚLÀ=Ö Ør˜˜ @4 t[LáÌ&B,†—­€lŽ…¼RrˆIäkAާÉeÌ;¼‹"Ô± ok,è/4L¬üŒ=ú}Þçê6˜r¤ @ˆ¡ ¨³7 ¬ „c,˜c2À Ð–Aø®\¹rl©ƒA¢ …9ë¿iÄ &ø!,6F`Q` w*öúÁE5ô AÐÇB¹¿óxM*Þ5Ø9ê*ýK_n!Ey*{ݺucõŸ– pÛ|q :w8è+/.„—,·)#ÔÉ’–@Ú…yI!÷py9@¸KÀË•Ð_ÄÙ|fŒÚ{„jŸ¾·9v•µÃáÕ0¨†Ó82˜‡mBª-ƒàc×=køس– pÛ4Ô­S ÕgˆZên{@ƒp”‘ˆ’ÈÄED0®±6F '¼<óòðñõ² 9ÞS4—úÚ×´¬xä|îº(Ë£e ”yèQi! ™µ#|Ú6:ÁoÍš5û¾*@†´e¸ú´‘:x±QéS7¶- AY¨_oQÚ !ˆ]ü†.îWQÛ6<ì¼Ï]€ ÷ ‹Ði{Y ¬©®˜0›ÑËŠJ.Ý™_VNÝðxÉ€2 Ô/Û&!©Óf- †*dEA$B19_éD0¸¶©‡÷ASd¹w —_.áJõ0'8Æ“ Æ0µYLL2ÝW •6÷Tm* B!Áð‹àbyÑÛ2¬ö/ˆP/ƒ vžÚªöV! 1®†˜à×5éE&â0å% £küÊ/—°. ϹlìŸ8\×Â-¾V¾8 |­²ºèÓ2×Áä@c„‰ŒîÏ2ã²,}7Èx§‡:h!8ô…Ý¥2½üÌбmµ Eü•mPÝ| mÕO}}„¦MÂ¥¾U!< EFí,Šã¾,â½)êë"‡ñ ê}“?—¾Ç‹|÷‹ûfPŒK­Ðyz˜¡£­–€¶C ç¶I65JK€Ò $—vØTG€{8íœ$è«×ä”CG€û¿Ëli¯¦=#Cï›Û—€|XN|3VÕJQRÝëÄ@ Ù6„3Óøk:˜.@³1Fà9xGy'x7EÜõžÄ‚>ö;# L„Dw_2ý `Ü7ˆvÛËŸÂQ´t@Ý pXk ^—/ˆ7ïÂ^ÄWjüø]p(ܽL˜dr™ŠaÃ{ âGƒ“HÜÜ3vHA||2¸ÇêN‘Ü64ËtŸÝ×~л„ ×{„ ç]â‹ß»ØßOk]ë<#`ñî-óËÈ4-!Ä8à× Æ†WƒYøY>ÐÙÚS@½ 𱦀kê·1C@€™»Þ „=ï„\Ú—¾GCh³Û°X˜d¼Ÿñ ›±Ø¹/JÇõª#ÂI3B?¹9È„D ùã#‘ƒ.®Ú¥´v@Sx–S+!Ïó–>séuÓúßLBÀ`:3Æùå 0fîh 01vø!‚"K\œ~–ZcbÀ§‰2”ÇlLdB ’@lŒ@ñó™’ØXÛ?¯±¿¨L‡®0Ȉ´_ì|`B°¬ùcblñCDä΀¬¸YZ/aè+åg ‡ `!²„3èÛ,&ñóT&èéyúl.&îÕ""`ñ®ÆAÆb]T"lHÄÄØË/" —ðÔ¯´Uì b ›Õ+͈AL¬=Øã`<<ñ³“Fq S£ãç$ö+Þ®˜GL2Þ5 ÁÌP$™=$!¾7©ŸkY ]¹qÓbÍA.?‚DÄ@D!]¶AhÕsÓ{¦k°×ý“`×5®L™_ñvÀ¢"`ùÎ2˜ læÝ/\HC‘@( #\–+\Êd#ýl2Ea¥%\®Zø®4iÞy½FE.arŒâ%ع–pã«úIgcŒÀhdù)`p’@É\´‹ºÏrÕ< ,]ÇnYZŠ¢ ‘i^ ?ÈB°È"(eO>ò`SSÖ&¥KãÓkÒÅaòË¥-`Äul‹ÊWž´Ìô:N§rì#0&³á55µ¦©9AE$á­Y¯üE‚=Ž“Ÿça¯üò«êô9¯›ø)¿(?aq¸Úa×þ0ÈŒ½¹Ì€°8 3 c Y„/—4q|ê— V¸òÈU·ãç)ö_Wñ«L»FÀ0ÈüÄqæ¢]\„‚Þøqc«x XÒ*„l|-¿ÒëZi¥:×µêÖý–«p\Lž^Çq±œÑ?FÀ–0È °òz€òéœÎïC àI~j"^¶‹ëz½s.#`ŒÀð0È|OF6³#€Àçs9 sá˜^Ï^²s#`Œ@û:¬>\õKXΜé&¸åDÁ½6FÀt‡€ @f¬MêjP7ç2FÀÔEÀ .r%ùLJ€q°0FÀ €AÝŽåmŒ5Ë{ïÝs#`úAÀ 3îÖÔÔ nÎeŒ€¨‹€ @]äJò™”3%Ø` @Ž6FÀdFÀ 3 &™uqFÀ#Ð ­€]»v-Õ‡ñ&õžSkêáæ\FÀº´N~é—~ééиÝu8oùLêÝ1€z¸9—0 ‰@'2³u°÷ÖìXÈ[TÐ)€PdŒ€0³ ðÄ,‰ë¦íŠ<\·ó–Ï Þ³ nÎeŒÀâ!äÈ}]ôª+ðPqó‹€ ÀüÞ;·ÜìÜ›½Ä‚»"×Ô½°AÖ¼ðÖÆxÈû_˜ÃWFÀåE`ÿý÷ÿ›.zßøNJlCiOíˆû(?n‘¿jýÖTEÊ錀X`ørîG]ô¯ðì³Ï~»‹Î ¥þÚ á´­¨q;c¿ÒÆaò+®ÈÓÈû•/3*v€XV˜xý'?ùÉN–Í;!¿ü˿̆†{–å†J¨¥ý%\qEnQXZF“ë¢úû*/w[šôÃy€0CA ¨ÿ¿ÒU[:!t& øWuÕ©¾ëiC¸Q&Fî,}¬“Gu)¯\…ÕO¥KýJ¯x]Ë%Ü¡a×eE Œ…ÚUß;#apÿ£®:Õw=EB.“?ugi7y•¿(ߤ¸ié«äÓÄþ¢² #ÒÉMÃMÊÐs¸0K‚ÀuW^ye'ëÿàÙxï{ßûãPß—á&JÀ¥n•¾7Í£üU몒^ipåOËÃËüqžIeÅéì7FÀ,í²¯:fxØeçúª«L¸ÅᱜÔÎ8Ϥt³Ä•Õ×U–&®'N‡§þ¸¬ØO:]ãZ"çk#`–]‡rÈ'ºìo§àÑGýƒ0ÈßÓeû¨KBºcQ[+Qº*e•å›–wZ½iþ²ôqb¿ò+Ÿ\µ7½V¸]#`ŒÀ² ÆÁûÇüÇ;»ìo§àÃþðS¡sÿªË¥®XÈÅþ¢ö5W™”SVVY¸òâVÍŸ–_Ç~•)7³dlŒ€XB¶~øá¿Óu¿;%tî™gžùãà܈Q[ê¦ýU|®ëiñJ—Û-«—ðIqeí(ËCzÅÉ-+ÃáFÀFà7þðÿðñ®û×9ü“ðã?íº£]Ö‡0+h“ÂÕ¾¢|ÄÍ>)í¤8µ!uÓ<ºÆ•_mÔõ´¸¸å± FÅ~#`–0þ]{ÿý÷ÿA}íœÐÉ /¼ðsÁùxî¢N 4êŠýqÝeáqš\þ²ºŸ×_–Ž4uâÒº'•·Ã~#`ŒÀ!À²ø¿ño<ÛGŸz!tôé§Ÿþ‡Á¹§N·]g‘0‹ÃÊüq»â4MÂã¼ÓüÔYVošwRº4.¾Žý”™^§õøÚ#°¨­ç? Çþ^×Wÿz#a)àѰðáÐñ玸ë ë•p“;©*Ò¥+ ŸTÖ´¸¢zŠò¤u§×qž´Ì4m|-¿òÈõ@Œ¨ýFÀ,2a¼ûÒW\ñ{}ö±7@§ßùÎwþepþMŸ´Q·\Zv.ÁW”. K¯Ó²ŠâÓ°²ë´Ó®UNÚ†ôšt³”¥rí#`[߯} ô±× p¯€HÀo§Óè·M ½Ø×‡Çþ²4„—¥‹ó”ùÓ¼Ó®ËÊ!|ZÞYâÓ´“êuœ0F`x(Œ{oïêÿ&áÕ;jŸ…³?º}ûöŸNjè¼Å!Øbáû'õ¥jºIeäˆKÛQç:΃¿ìZá^Èqç\†0CE Œq{ÂÌÿŸøÄ'nB{'\pÁÚ]»v}òꫯÞÿñÇ;ÿ ²µ{ ¡F±?½Nãª4(Í£k\ùUÏ,×UêŽÓL«OmHóÄ×òÇíT˜]#`ŒÀ"!6¿8à€CéSß ¢ýþccãîÝ»GŸÿüçGá¸à¡`Óz;b¡W$LãÄiãðœþ¢6Äõ¦ñ9ên£ÌírFÀœ ãžzê©C øú‡>ô¡õ9Ë®[V¯ ¬ÿÿ£Ðð Õø  }îsŸ=òÈ# š[W‚S.™a·YíŽoDîxÕá%€eû€X/Ÿ|òINÁwgÏž=‚ýòG>ò‘£úî_o ¨þ_üßJ(4;v FK’6±Òu*ì' Íiqi|¥D‰ÒüÓ®£¬•½EeÆaø‹®ã°Ê•9¡0F`N@¦=ûìóçü0æðŠ  èåô¿¶¾À~á €€8(nŒüZ4wn[‚--7½¨¢°YLË(º&,O¯‹Ú§W›ŠÂg×#0„Í~#´Ú?ùÉO^Ô|A°_zé¥|Qd‡½€ ú¿4 ú¯ÔOHÀg?ûÙÑ-·Ü2)Ù`ãb¡ûip|ûÓ¸6;W§^ò¤ùŠÚ˜¦™vÝe¿‹Úë0#`Œ@NðO<ñD¡ðW=l æ÷.¹ä’SÖµ{@×Õÿáxà—ƒP8|ZÝ0¨;ï¼s¬>9þøãGZ#ÆM-e¥a}¦;=Ùí9î¢Ú¥þÆ×ò«­q?äO]å)*Oa©› á4žë4Mz­8sÞ>2ÄB-ö«-qXì/Š'¬(ÒVu)£¨œ¢°´ÌªiŠÒ•…Åá±?­Û×FÀ!# õþ½jýÊMeÜc¹ hþõ>ð#*gÌ”°S°sçÎKBg®Ûv>¼êª«F×\sMÝ"‘oš°›_Ô‰:yŠÊQXQy„Åáéuœ7K¯ã´òÛ5FÀÌaGÿˆCìŠ6ûUéËÞeÏ!ÿ?®’>gšN ÀAô/š6Yë&M‹j5¿¥\*+‚q|QƒêäQ9EyÕ¥‘[ÔŽ²üÊ#wRº´Ü¢´ ã¾Ú#`æÃ;l<{¯²Þ?©?hkaüµ‹/¾¸öyReqIÑ÷¼ç=/ ß=žÒTp}ôÑ£sÏ=w–ÆD@£¬ƒ}†Ó¶IB­(¾(¬Ï>Õ]†9áE¦(¼(¬(¯ÃŒ€0CB€1=lÚ½úÕ¯±4ýå/¹qó aÀQa’|i(ì?4.°b€uëÖý÷9÷ôtw}™@ªˆA+ÉRÇuLŠ®iȤ4ħùâ°´Nâ0EáUÃÊòÏ^TŸÊPœ\ÂmŒ€0CC`õêգ׿þõ£cŽ9fÜ´—½ìe£¿þë¿/ähk%”³x í %¸ëØÑ˜y¥ù𨡠Ú5M°§}ê⺠¯¢pŠÂigQxQ˜ÒÅ…uë0FÀLCÍõ+_ùÊÑYgõ‚±œqýÌ3Ï}ï{ß›VDÕøsß÷¾÷6¼ÿ¨j†&é:Ñ\~ùåûoÙ²åĦêÿSO=utðÁ—ö7²¥‰:Š@ I¨©]鵚B¸Ò̦ôÓ\Õ=-â'¥/Š+ £,‹â&WõÚ5FÀ ÆåSN9eôªW½jtÄÅ›ôÏ8ãŒñÆô¦cÙÞ}Œ—ïý_@|[Øý¿S ÀæÍ›+?ÜŒT¨VÎÜB²ö……•5©(-a³˜²ôeá”]W¦v(N®ÂÓ²¸gEiâôö#`ÚF`ãÆãuþ5kÖL¬ b°víÚÆÿ_ÃØ·÷‹€7O¬0cd'€°aï-MgÿôyýúÙþA‘"r3b7±¨Xˆá/ª¿,¼¨àYÒå',nSš¦N\YÂËâÊÚ1)}ÚV_#`ÚB`åÊ•cÁÜqÇU®²ðØcUN_”y²âåüà×|üã¸(]ΰN@þ¯l:û?òÈ#G|v1«‰…QÓ6ÌZ7é©៦—`LË( W¯ëØ-‹+ 'ï´¸²x‹â&7nŸýFÀ®à ³³Ï>{ô’—¼¤pÌžÔžc=vtë­·NJ25Ž/ÛöšýxUðEm¹€ ¼Nhª€41°«½ŸZtv†Â-Üô¡(\‚°(}“~«Ü´Œ²pµ/M?)\i딩r'åUùv€0¹`ÆÏF¾“O>¹p¼®Rßᇞ[®œê] €s6Z`iOÓ6MkB-èrqe¤éTî¬áÊ'WõézwR^âêÆOË›b3K›Ö#PU«VÿI'ô‚qºjþ8Ý!‡’Ež Ø»°ú†·¸!3ú;Ñ„NÚTýÎ'€9 ç/ÇD mÁƒà+ªcÖð:” ë²pÕ¡x¹ —[®xܲ4 Ç•?Îg¿0F  ØKÆŒŸuû¢1¹NL&›Ê8êÚslvÌš§uÀ'€‡zè!MgÛëÜÁæ ,­Ã4®.nÑ—+¡—†I\Qø´¸qÁ5~Ô–IY'¥!®I¼ú5©~Ç#`ê"À¸~â‰'Žød™nƒ i*ãhËÔ˜0žæQyK+ÿiÀÿà·_SvÄŒ½M#"ÀMä¬7³¬½Ë:~Z¾²úŸ$ «ÄO*[qªC®Âc—¸IñqZû€0M`ã8›ú8º7×2rQ{Me\26ξ㽨aSÂZ'amd¿uïÿ&— Î)ý¬ ÑÀŠL:xhZ¡³:¥-#Óꪯ:ÊÒV']Õ´ÓêªRVY7FÀ¤0†rT/øpvLSÁœ–_tÍ54B"º6­:0MÁ¡þrqÅŠx[7"áŒÆ¦$&˜©'. K;8)ââ:Òüñõ´tÄOKCyUÓTM·Ñ~#`ŒÀ,0F#ðO;í´;û»4œÐTÆ-,@õ’ƒ…rW@k2,{Â~†;>«˜X– xÒ”ÅQ‡„ç¤4UÚ’¦Q¹ix|­4rã¸ØO|•4äQÚiéãòí7FÀ!À¸È7ø¨ù»ší§í`,crÚTÆ¡åîÚt¢`Ç%îÙ³§Qÿzè¡Ñ,§35ª¬ ³ö <ñÄcÀúR]Ö'8I°“fRfá»ví5=¨)ÈhvïÞ=¶Üt´EZ ¶Tˆž†¥mš–†xLY9ŠOË-º&m•ôJ#·¨,…ÅiðÇ×Jc×#PÆØM›6gúáïå«fk=ÝöíÛÏþ™Xvm:%9Z€¾ @|“ 5,K<¤hÌÜT>_„0p&W6.G~ JÒ”ÒLŠW>•¥ëiî,éI§ý“êQ¾ªé'•å8#`ÆT¾×?á„ÆûªŒ{]"‚V›±?Çì¿é¹N¿;#Ì’Ù¤¡ïë4–<¨[ÐPÞÐ –6Š @ôÐJøq7%J[Ö7å+‹/ ŸUتEe…©üÔ-J›†©.åMã}mŒÀr!€œØ°aÃXÅÏ¡=Œ‘C5<ð@ãÙ?}{ä‘GzébgÁÆÌ=‡šã¾ûîq|ãP ÂL¹±ö@@Ò‡9|øÁIÄ îaŠÃ«úãzfÍÓ4oüUÛètFÀÌ?hMöÌöþŒwC7h´Ù˜Þtó“âpVN/ÝíŒÐ;nrÓ€”C}|@ݳ„Ÿö ðPƒDB0Im” M-#4y1T¦ÜYúBå‹ýUËHó¦×UËq:#`æÆ1NäCècñ7ÛºF„ñ‹µÿIcxÕ6mÛ¶mÔÇ´¯SSb6œã{GÂ4÷T½iuÒñÐÀ±ìe@Õv J™œUÒNJC9MËRþœeMj³ãŒ€˜_ÿÙ¼Ç Ëø=¯†ñ¡ÝtöOÿï¿ÿþÞ`è”ÐKnºGÓ^ÃÀrþ¡CÓöÌšŸË2L"À2 ‚:ÌR¸J ãVaÕqúYû§Oë'.WÙq=ö#0|{ø\OBÍš5•Æ£¡÷Œ \Žôóá‡ïë«Ï³ö;ž;vìñ`Í»G}tlyqØD!ù°@IDAT¨"È‹0ˆ°tQº8,·çð§e§×9êpFÀôƒ“>c2Çñq³vd§µ^_wLVýŒ}7ß|³.{q;'ô’‡‚Í€ÐÔhF×G?6m÷¤üà¢M„¨šØ8(2À¡M_ªTè꺬MŠÇÅÈ-Kß$¼Í²›´Ëy€x1ŒEk×® }?ÚËE5|Òº¾é—lÂgË–-ãuÝ‡Û €9±þcC  I…Ž\DÃÑÁbXàE£¿Xw#á‹+[ÆrO½òãÆ×©é#`æ>öV¯^=žå£â/#æ¶“ glã“¿škŠgÜ­·ÞZPS·A½ºLXUƒZ†›Ô÷±9ú2­ pK 4¸M5qý±p|œ¦Š?Ϋ2É'¿â«”å4FÀ´‚ñJ¡?Ï÷ê"Æ áÏ’s.sã7f-¯n»z#<\èóÃ853ikpëT—i¿0õЗ@úˆÙ=ê|ÞS›z0Ûg3yÎ%iZ¸zýõ×ï[Ž­×ºvr ‚Ð5ÀçPÔö§žzêXãŒdÊE•€Xí5ûƒ„êJÿg ÜÌ(Dp! J&BÈ®hŽï–öîÄÂ>ç—>Í[9ÿ%0¾!üër>÷ʦ¿´oƒ!4 ðÙ´Æ Rì@…ÑrT"7†Ù|Æ8´  ¿Ÿò$/$ Sci îfAÊ£ 4”ÏÚ™M7€}™&GD@d€kÙnZçZŒ@} ³Ú<«´øzTù6Ã@@“ÌǼ•1ÎÝtÓM#¾÷º$4<_°€šFFŸ± À!uwUò Q ?ÄÂ/¨îÇ契栬" qee;|~@. ™ù·iÿŸ¯·ÙδìÁŒ` `Æ^4ÃÔׯ_?þ‚€ý"Â_3ØC"Ð& u€\xˆZ¿î«Üi=! ‚\âb|†O«gãy·±3î‡üq¸âp±x¹J·ŒØ¹ÏŰ×9€à/’Źê…Þ{ï½£[n¹¥õzêµnr®¹ tA*~Öëìe³|mäæ³Ë“¼³<<<,+ÀÑx£àä‡hbL" È fcê  Ì:ùÇb˜´1a“Œ(N•/’qà 7d?50_ «•4W€.qƒa[„%iBå 6Œ—Ð@fùz€‡‹<ÜtˆxVT j§2FÀœ°æÎ˜Þ…ªŸv#{î¸ãŽÑÝwßݺ†!'NeeÍ #Ülfæ„1Á4mù˜!À±Ú4ˆV_ňGŸ#BBlŒ€0F ;þ*ã~®V1idÖ?Ëä1WÝm•3·Ò‹€SýŽ=öØñ7¹ìîåaH?,N›Ù8È e†_u¯,mé9ä2€kcŒ€0í À>ÆjÆÞª“¶-¡^fü÷ÜsÏTmsŽúº,cn !ð9 €Jž5föe_ ”‹ y`½Ÿ>åL3Î*ÀB(Ø#à}ÓPs¼0F :hxYúEø3æviÐ4óg>óöy_UŒæšÐIn š–Ð ˆ±ƒYÕCä§,d¶ï¶. †ükDÀZ2´nŒ€(G€1Wjþ*“±ò’êÅ0‰ä,Æô®IG½×Ë5÷€n3s‡ ÎGˆ³Öðå¸NfçU—b¥Ø´iÓXÕ¨²Ã”‡…+­š î£k¿0Fà…0vj¶Ï¸]eâõš_±´€ªŸsüû¨¿yf+a!]æKþs™O™cºÌĹ© ÿÐ…(ãBá†vèíñŠ) €ÀG]{do²Š!Tø¼$<„¸¹ ÂzíÚµc‹ºMûp«>èˆ cBû.¹<#0Ÿ060nÉæÚøÜ6´õ>»5®µ]ç"—¿Ô€ ÛEPeI }4c‡}jC åå6ìI }X^\ö$@Ð̲—ÚÉ2– X#` §fö¸Uö ÆWZcœæ³êª ¡´ÈíXzÀÍác‡½ÖãgU“³W@yÈh°ÜÜ&Ö@P6Ä2€¥ÎY –üʇè‹Ï!˜U§7ý €pd BÈKèãŸ7¡I{Ù×ÄlŸ±™13oýèç)¨^« @„”—Ý™03j–°”%|d€¦K Á_ó’ @3€@¯Ãòi§Œ ¡OàaR DìþXa#Éø%¡¯ñËB?F(¯ß Áök’è™.¥Zç8b‘¶44Œ™ºÎàšõ=È/õÖ}‘¤%  –% 19@{0«öDåÙ5F Þ]ÆÞEÍìqë¾Óå5uCû™¬ âgܵÐv¼`hvMLüÁš5kÆ/2å£Ðߤü²¼" h 6l]í@\åacC?ÑÄ‚1°1F`:DÞ+ƞئïÚô’†›"úêÛ¼“™á"^Þ²f’­¼Ü…ˆáÁ„•êHß\Ò§yêÐ2ëùm½-MÐf"¸9–(h;åbcƒf" mmѵ51Rö/ ¼+Ò¬!èñ3àok è[úÆÄƒu}fûo±¯}âúQF `*R ×Z¡gw^@¸!ø$èSÿ¼ö«j»™Ð ð±Z>´À¯Š^7éL*âŒpæAFpBÚØУlÖñyQʼD¼<øÛ4Z.`¿‚ê þ6^\ˆÔœiß´œ BQ¹Ö¤ˆùºì¸ñ,^am¼7}ô³JôYKŒŒ•àY& ªà4¤4&3Þ ߢêyÚD”ËÄXféK- õrÍØüJÉ©;þº€Á:eÛ\ªP4Š´Ї @Dt A ¬­û¢úí.ä¸XÞ; {Ü6µtCG˜w”1‰–ñIÆB_H Û5¨qôà# й—Šškˆg âå)`pjËPwüuƒž4ÔO; »4Ô‡å44Ú.rº¤1Q(BoñÃx†õ ¥BžpÂHcAöü³zïµh™ ÐóÈ̯Ï Á½c €ù2ëD#€ÀéÊh§=§"ÄÐLHã¶©!@pÆ#X¢†·MBRc&0™fDpEp.?×X†iˆöÏ3(.áŽ+A®8][°O¿Oø{M6ÀÔØMÇn^Rt'±æ‘ídPá{û66 VmŽ› yA¥!€±cËfÊUËŸ”¡¨%þ¿“‚6 ɤ¶M‹«JTŽˆBì¦~ð ‹¡0•c÷Å ¤yvåâçþÈJˆ+ ׊#̦à©ñ¡|m3\‡œÛ ãÝáeŠA+¡?-¢Mz¹µ±P/w[íÕ¦B}eÀlœ:™Ih^UqÀ©š>M'b r19_.ÄCZŒÂS¿â W¹ø‹L\ñ îÓxž™8}|ÿäW<®°ŠÃ^äª»Ý À¤€w!n¼Ñ˜ûc³ø˜d¼ÇC~i RÛÓN,B™—Ë`a% ¤D†úDD ·¨®„â¢öÏý&h)õ®Kèó,yÌ&’‹Õ*€ÅºŸ•{ÃLPBYŸ2 ª!€`Û$¤%`†I„RPe¿r§Ð,{Íîqy‡peÚzŸU¾ÝùAÀ 㽚÷K¤€åö3Ð,ˆùÖ¹M¬¥PÙ©(EàlŒÀ²#À»Éû yÈ;ïǼEË~o»ê¿ @F¤ñ¥ƒpøÚþòC?!" @ DØÜ¤{¨Ÿ5éxùbÀµXTâ÷÷NZº˜ˆç~÷K÷ëyLžÇ¢±o™^@fë:N8Ö œEp™0`åĆÍqÚÏ ›Fùi 䯤ÒÚ5CE€ç•÷Fä—w(&×9ߥ¡âàvuƒ€ @Fœ—ýÅD[ ÃwX߸" f±w˜7¹Ôî) <‘͘ps’&ívÞåC€÷AB=&Ëøã÷AïÅþåCÌ=n €ŒÈú%-á̬]ŸµÅ81ãaÐ)ˆý9fïÒRÄ-£~[È€ˆBŽ:ãºì_NxÆ$äõlKÀãÊÄï‚Âì®0Ȉ´_æÙÁŒµkŒpÄA€àg0ÝÙk|î{úø ˆ¸ ꉵ"h lŒ€àÙäYa•?ŸzŽÉûU†]#Ð7&ï€_òŒ`†¢ ì5ÀÆÇ,Ç8k†”ÙYZU´¿€üԣ͎ñú¬üq›f©Ïi‡‡€ž£øÙŠýòjy|ïc¿âí¡"`ñÎøåÏfÅ¢DbìS¿tÂc¿®åNªbÀ?•„ÈDA~„×q›ÊÊpx{€¿î³žØåþÏýÒ½’K«ÊüíµØ%ö0ȈqjÝÎY>€z7Ì nÎeŒÀâ!ÆÃþuK]l\pÁO†¶ïi©ýƒ+Ö`p·Ä 2FÀÌ»»hpë`o'vtÑ™!ÔaPï.XP7ç2F`!x¼‹^uB‚P|¸‹Î ¡€zwÁ nÎeŒÀâ!ÆÃ-]ôª:³­‹Î¸ŽùEÀ`~ï[nŒ@^ÂDòî¼%—Ö U¿¸úÅ µà…÷5ÆC~ÜØÿ¾2FÀ,/al¼¦‹ÞwE¾ÓEg†R‡ÛPÚ“³ê›\Ê–7öÏR/ù¬˜1§5F`Axú§?ýéõ]ô­pÀ,%H…¡®¹±òËíâf—Õ¡6àÆ~¥/ S\‘§/ó+Ÿâum׿˜L7ǰÇþëUW]µ8_¼ûÝïÞÀ¼¹G@;­ºŽP#ò¥n®ÆÕQµlµ‰ôò×)oR^ZUï†Ó#°À|©«¾u¢ØÛ™OtÕ©¾ë ê›IÚS$øfigœ–|qÝUóÅuÉ_%/i•^nQýEq„™TAÙiŒ€X`88¯3YÙƒûŸ„ŽurºQßG,à&µEéäNJ›Æ‘gR¾Iq*+.£JzåÃÓÇþ4âpåÓ¤e¥q¾6FÀ,_ºòÊ+ïíª¿€÷¼ç=|ÖðÿuÕ±>ë‘ KÝ*mjšGù'ÕU%Mœ_éqåãñÇ᱿,]QYÖ¤hùÚeB Œ‹Ðe;#t*tî£]v®ÏºŠ„`û'µ“tUÓN+gRöL—uwJ.¿üòŸ†ü.;ØG]E/ŸÂpcQû_GØ´xå‹ëR˜Ü*eÔͯ²‹ò—Å)\í³kŒ€X"®=ýôӯ躿:÷®w½ëóÁù¯]w´Ëú$ÌR·¬ J—Æ—…ÇéŠÒ…Åy¦ùËò>)®¬Ü4O|û­(CÐáFÀ,8¿Æ¹ë>vNövð÷Ù®;ÛU}µX°©Þ¢0ÅÉ-KS®|U\Ê(+§,œrÓ8]ãʯtº–«vÍ’Vyì#`–O}ò“ŸüJýì…\tÑEÂoõÑá.ꌅŸürUz­ðin|eyŸ·¥,iÊâŠÊŸ”Ö€qû€XtÂx¸õÀ¼¬¯~öBèìÊ•+ÿeèü÷úêx›õJÈÉë",ýiºøzš¿¬œ¢|ei /‹KË™”.›tÆ¥õøÚ#° °'îï~ü㸯þõFÞøÆ7>þ#àáãOõÕù®ê­"äHS”®,)M•9 šî7^rÉ%¿»üºåP7c®|áÏ~=”õÊ g!î¸ãŽÑ1Ç3 áãY2³ÂØ’.¾–hááÛÎQøÄƒfík¯ü©KdŠúS—–£tMÝT ·}M{©ƒûÿÌ3…Ý*ç7FÀLD€q á»×¼îÜsÏÝyÝu×ý•úr{%^xáßïBç÷i"éöÛo­]»–³ö Ï"Á¨0\L|-_áµ!m߸±Q{ÕÆÔU>…«<]ãbâp®› lÊHMÓ2ËòÇáøMRä}mŒÀ¼"ð“Ÿü$þc"Æì7¿ò•¯ü›`nê³oûo×xÛÛÞ¶"Ôyeô_DBíꫯÝrË-]7+[}©`SÁ„Çq ¯ê6É[µÒU©'íË´k•›–^ÏÒN§5FÀ °¬=zâ‰'â™ÿ¾f†¥€ýƒœûÓ°pê¾À<½€ƒ:è×ÃÀ¿±¬Ï€¯}ík£o}ë[eI.¡&·¬±i|z]–¯ixZOzMù„ÅáéuYâ½NÓOº®’—4UÓÅuå) #Ož^ÇåÚoŒ€˜'ÏvïÞ=¶ÓÚÍ$7h ^–‹/Ÿ–¶­ø^À¡‡ú{¨ÊŸ Þ}÷Ý£O}êS£Ç{¬-²—˃ ·Ø_TYÓôi™Óê#}Z§ÊHó¦×Ê«ôºNËK¯•>-/½V:»FÀyA€ýk»ví1û¯jH&Ãÿóûßÿþ×WÍ“3]çà‚ .ø¹°Ñë-³vâÁ…¿LÝ|óͳfí%},Ôb¿‡Å~ŧn•4ižôš2ŠÊ) +Ê[V”7 K¯)‡°8<ö§õøÚ#0dؼüøã˜ÕÏb A °p'ä{þs°Y i¶spØa‡ý³ºí…-±9;¯»Å«¾:°(OZ×,¸ÏR^YÚ¸¾²¶”…Çyí7FÀ Æ/6úa‹ÆÁ*mÞ«1xÍ¥—^zI•ô9ÓtJÂÎÿu¡³onÚ›nºi´cÇŽñçoMËj+¿¹Ôû«ÖKž4_z]µ,¥+Ê_V®²ä–¥KùNÃ(£(LeÛ5FÀ c=v,ø÷ ðÚÍC €æ Œ¿dä!µ ª‘±S°nݺ:¹¿¾[¯ëž|òÉ£ã?~¶S£ï­g‰…ZìWÅUÔ¾ ·j›ÊÒ•…Óö8¿lýrFÀrÈ!£×¿þõ£w¼ã£p Ï¾sXêÊ3òñÉ`0'†³o>”£U˨¼¯j“ÒµýÃg“’Lãt½7¾ñûÒé´=XÔL*ì¸É±!>Sú4,¾&š/Sq=Н¦|Ee…M«¯(OQ˜êµkŒ€ŒÅL>_ûÚ׎ ˜óÎ;otà 7ŒûiÚFÆÁPǯ†r>Ú´¬ªù;#úЇNÇ!ͬ½‰9餓F«V­zQ! ’½7u_{ÕÆT°ïKСGmI«ÌN³”S–6m›¯€0]#°zõêÑë^÷ºñ1õqÝ|ðèì³Ï}ï{ß‹ƒ›ø_ý¾÷½ïœ+¯¼òGM ©š·™4®ZKHÖKþÇ{ï½w†ÅIÏ:ë¬âˆ:¡ªÆIÆm",¾ŽÓ¦áEi‹ÂTÆ4—¼e¦(®(Lù‹â+ 'OQ¸Âäªl»FÀ¡ 6­Â‘½£ÓN;­pì¦/ùËG×\sMá87k?öއ ùþÁ¬yë¤ïl@Xãx+êÿ&–?bí¿ŠÈ! —²¶……•õ¹(mQù /‹+*RúIåÅ©¬²8ÕŸ!…Û5FÀt…šj&›ï~÷»G§Ÿ~z©ð§=Gyäè„Nh$Û‹ZÎE^ryø—Ü.úÚ™ œŽ´¹©úóæÍoD ˜„MBEuÓ&üEm( / ›TFÚg]Çõ+l’;)}Y\Y8õÌ7)ý¤v;Î# Æé—¾ô¥£sÎ9gÄ쿪abzÿý÷WM^šnï9ëÂÿà¼"$º¦4a¦ˆNÀïÿþïûWõW5ݸaÆ™»`TØUÓúg­\B­Šð/K;kx•6ªÌ4mY8éˆ+‹/‹Sz¹q} +˧µß#Ð&ŒÑlð{Å+^1þ+úYëZ¿~}ù‚œB^…Mí?Ú° €û榳n\×ð•€iK‘P®[vÕ|z¤ï¢þ¸¾´uã(§,oYxœ§,MYxÚn_#`r!€’C›K+ÊÑ ƒúʦ€¶ë-Ú#À7MÛß ·¢¶Kè•Å…Çeçö«=eåNŠW?Ëò>)•øIe;Î#0 £Ž:jü)Â?ç×ÉD²iÙX—Ý–¿˜Ö!QÇj÷v…nà@}£¥œÚ†¸½„ežøºqq=©_õ¦áéõ¤t“â(GñrÓ²•†øIiŠò9Ì#0 Œ£lÎãþM›6•Ž«³”9)-Çù6•sѸxàÅ_|ðUW]Uý¿…'5®$®XÑM™ío“- °O²¨{S£›9.žëIÂD“âËâÔöinÚž4½âå¦ñº&>GÊ«R–êµkŒ€˜†ªøOTüÌöëNÚÒr«^#›ÐG›øªf}Aº˜¼ ¢¥‹N4áæüº÷jweçÎ/:‹¹va3dDó€ ‡ø[å“à«"¼‹šCþIy‹òT «"p•FnYÙÄË–¥‰ÃgIç³ß##ÀF>>ã;å”S:›ÆõËÿè£V’ J_æ²­KÓ  C¨büñF}kš¿Qå!3ì,ü¡ÑØ¢¨#¤%TËò_÷£(ÊŽÓù«¦#ï¬iI_%ÒUI[Ô‡#°\0ö2ËçdØ7V'ÛFè±Çk¬þgÙ¹é$yÖ~vF`jÏ&†Mz].Lj«´»víï`Ý)=§¡iZ.A7I¸“fR<íšVŽâ'õAq¤­’^iª¦Ÿµ|¥·kŒ€ˆ` eCGî"ø«h`ãümú™µ?òÈ#Û„†¹kÓ@@6Ý 8>ø`¯ªžô! !&XJú ÙÑžiè1ˆIA\¦ÒÆa©¿JònS7=ùªæUZ¥×õ,ítZ#`ÆLÖõ;àgyˆ™Äx®1½n›NëÔÛ`7=7!ØÄ°5I2ѤEya‚h°1ˆ5|àÀÎ5®¹Eå¦ôeñE᪳(®(Œô²EñeaªGnYº¢ð:yŠÊq˜0ó‹ãߺuëFüï 3ýxìj¯~øáÆòˆñ¹ÑµéŒÐ1þ6~S³mÛ¶ñPÓrÚÌŸ’´|Á€† ÈHŠ@ bb <„Õ1*¿nÞYó“^yR680‹‰“¥cŽ9f<Ógmí鼘‡zh¼A¼é’[¾8ëÚtNrt’õþ|aØ!72ÀF¬4HÁ´GB4}0ê• ä´ÜI×Mó«ì¸þدx»FÀ,6Œ}¬é#øq‡¨Ñv˜¬Ar´e„>L§a‡Ðf]SƒQAØ´î&ùcÍmG#@;2 ó•0ŽÛBØ,x¨ ¹qYUüʇ+K>…W)CiêäQ^»FÀ Æ¥Õ«WUûýU«V »ÁZ·}ûöñX7m7­(vÿC$ú0:ˆÀË1ØÚŽ;Æš€>€ËQ'8è³B ä2 íÀ,Â\í¡ÌØ*|š«<ÓÒUË‹ýUó;0ó“„=kú¸³Lp†ÞsÖëÑèæ˜ýßsÏ=YdbÌ:'ldŒmj¸ËyY ˜Ö_}MÀ¦„?j2^"‚iùËâ%€q1r«¦/KW'¼¨- «Sžó#0 Øè½víÚ±°Gà3~-¢a:“ÏŸ‰, /Ó9 £€ß<"8PÃpDŽ›Ñ×M(ª—¾±aR›&aÏT‚4ý³¢XèÊ[¤uˆãikz]Ôþºa”mcŒÀð`LB­/¡ÏØT4~ ¿'Õ[Ⱥ?2'Ç–Zo½õÖÎÿ‰{Û @XóðäØ ÀxàÆkKM×bb`†æ+6?b1àà¥Ã–}]0k?bá^UÇy¨¯èZíHãn×a#À¤cåÊ•c¡Zÿè£^x߯.„Žì”Ë2ÂÖ­[ã*:÷÷Bè%Z€€²(G$`Úwô¤_CŸùt‹O4Z2hª!ˆ1J…¶®ã4Óüä)2*«,¾(ÃŒ€hfòL0˜áËr½ÌáŸCs †Œw7ÞxcãsqšÞÞ‚šYk.@YKprÔ"kÊn¸6E²6…¾¼´¬Åun\$´-ÄËîŠÃÀ| €V–=—]úL*lžÖlÒÎyRëþìõêÛôFè8jl6TäÒ š X´=³>(¬UÅ{ÈV@d?¶5»”èš6È[dÊ‹Ò:ÌÙ`"À²!‚•>vÙg÷e(2ñÉy®‰*õ°yý–[n)«²Óð^ =efÊ:>+‡a&|ÿý÷—€`Ø< «}X>_QˆtýEÅ4Bð|ëí3F`V˜iŸ_‰—e©tV¼âôÈ%„®5ÊfÂ{Í5×d“wq{ëø{'Zkb¶š‹ò}÷Ý7þþtQ?E©s³Ó<_‘ʼnˆ@¢ mh T§]#`š!Àû yGØ#äW¬X1ö{ü«‡+ã"kþÈ’\†ñöÇ?þqÖ¥„¦mëÐTR|J+e­%Ç' ؛ֵšµ,ù‹H}çÞ@ ¸ú’ÃÄ`Yž ÷s(ðþ¡²GÐ#à%ì—}Ù3×ýaw>'ó1æ4|òÇõÌ €°€‡úôÓO“ˆ@Žð裎Xೕܛà†t#Ûn „*ÕP§Èƒ¬qnûn¸üEGb ÙFÀ#èY*•ß›óÚ¹ûÈ6Q?öØcÙ+¸ë®»FØ¡™Á€a—%3Mþ‚?ûaÏzuS"À¾·¤LovÉûBÜŠ6qB°\î+~k òâïÒæ4Â]!/Ë;cÓ Ln˜õ3YÌmØ“6”MißEh꩸Ž;î¸ñÌ"ÀL¾ `Y5Ø4DÀ/Wú(ä½olÑ %BÀ=…nc ˆ/ëó±Eà3ñl¾ÿ»Í$Sç©än ²ëúë¯Ï]l¶òGèÂÀËŒýC°,€Š¦ €`pæ>{x mºG@ä ¨fdûIkíAbëžQÆ*mšÅEÐkìbŒñsÛç*¯›Y?ßâã¶aÐ:sØOyÕF»â2IŒú=ìà µiÓ¦ñA?Ä¡®AÔ1ììd3ª6´ª£NYΓ*_‚ˆ P3~½`hóÞ‹e/ áŽ@g|À• —K˜gðó÷”0Æ0ëoc­_hpÐjM š;HH‡ç_¥xex9ír€6­@Ñ´ÒOrÙsÀþN½b'­È$´†dzQõÅštO«–1œž»%Mày` Á"¼qYz¯kù½$ÕíáåGŒÜ¨;yœÖ#Æ”Ûn»mt×7üµ}°€Æ&$€MøãR€Ÿ£+Y¿!ªýY eò@p:DÀ›gEpøéôˈ€ž+=[ºf– ?.× ~—£…Œi¬y|-AÏŒ]~ õåx6Ò^¢ægœ¯##Ҳʮ!|çÏ^³y1ƒ&€È   6lûSæÆ  ?«à0!ˆª èUoZêA­Gy¬ãÙ,>“ÈAYïSb_‹,(L¤!¾¦Ü8]Y=‹ÎûŠK¸„¸üÄ&a®ô‹ˆ‘û”öŽ1AÔߪç+ù…%¡M¾öÚk[¯ç…µ6¿< ‹}Öì7nÜ8Šv–“ŽÙ;–xö ÔQõÀùlƒýþC PµIð"<ÇŒRä“®_ä'­ŒÒ©…Ë%•=Â}šA½ªMƒú$„¨*k`I@ÿ¼¥5Ïiu;Þ#`š#€ÀgÜn럢2ö³ÖO½‹bæ’¾Hç  `vÏN~nRUažjX" £†¬7A8GÀk·Us#`ŒÀì0æ£rgwÒÒïì%OÎA½¬ó3ó¯2Éœ\Ú°bç–#‚žO÷8aάœo~Y˜…ÆZ4 |=€`çÆO3<¤…òé dÀg LCÍñFÀj0–#ø»ØØ—¶ˆ±ýæ›oÿQ]·×sM¸Öó֬ͳñd ê²@|#É‹åk:>%Á¦U ^Ë ˆ–o–mŒ€0F :L¬Pó3Û¯{ÒkõÚ^œÒÁ‰~|A6mìqîù Yé„ †°SƒàE-ª"0ëMd]BEÝDùØ*¥€=B&t>¿ƒžŸÃ-5F {˜D1ÓGøÏ:fçh-cý–-[F÷Þ{ï©û‹ðY@ç`‹ßøï~õ‡0ºYöÄ`A&øï,u?dr1Í@>°ì/Àµ1FÀÑxEèc¿û0 6–s†?ãzä£~/@©ýÖÚ”ÇÌ›ÏöX£'¾Ê,¾ìfP–?$‚¥Bªì@;¡‡œvi¢*CÚáFÀ,*Ì´?Y^íCÅ/\ô,!ßyç•7€+ï"¸ G¸)0¸mÛ¶gì±€… Ž‡ @ªîø/»ÑRí³_íD Ê~X.Z,Úi 6FÀED¡Ï Áßd–?“7vö3f/«YHÀÍäaã –ÒC{˜#¼¼Ú¸×DåÃ~Ž Æ"Ü!÷*d€v’k2°¬¯¡ûm! }!ÌW^~4²MÆ}•7ÏîÂn jwÔ;lÔñÍBp‹ÀLëîˆË„\èøá¦dâIÁõÂeû€*Ìî5žVÙ'ÕE?ôLÙÜ×TóÛE{»ªc¡ €@d&EP$H!¬ÉCxxQQAšš¦d€vci3ËZ* \#`ŒÀ`¬”&Áß×F¾",h ËÁ÷Ýwßxl_öŠÑR:`ç›NŽæ° "ƒ EÈbùj€‡9ƒÉ€Ôþì€lL{(‰× Æ×ìk ÚXDjŠúç0#`Œ@ôUãRßëùEý¡]üq³~Æ[›b–†Ð}v›ò@ ¢G€N2®ä‘:kRúYâXë×ÿèëö °  {†”ˆ˜ üY"ÀÒæxÓã,mrZ#`Œ@QMBøUÆ©²²Ú g¢ÄºuëÖñ†ìi«¶Ú1Oå.àÆðPè~6íM›=#P±ì#à`Æžóágù²±´ ²¡/ª|£<äài€”i;ƉýcŒ€(@€1Aelò,šÉÚ]TýÒFXøÜÔ‚ ¥#€‡;iI@iqµO€½Ò PFÎ 2Zá€ÑBô`Çm*òóâê¼â!Òfp(ÖÆ## |ÔûØ¡ÆE„>»ú‡sŽÅCï{®ö--@X-_ ð…À´%ðX+ ™ˆÓäðKµÏ¡C¼Z& ¾ª†­!€P6ýÀ?M Rµ.§3F`>`Ö̘¢Yþgø1¢ší³”Kû-ôctf÷/5. +S•%b´úÓ­‘!hÛx™Ôüõ1–ò©í@Õ}j7„@¤Ea,HK r£8»FÀÌ7ì3’°G€"ôs|åÔ*Œwl˜FÍÏxg¡Ÿù¥'‚’—m$!8«AˆbYËçeCÈ"¤ÛxXÙD¨?*¢|êÒ'ƒ,ÌjXÒÀRFËi ;6FÀ ;B^3|Æ"Þíy3Œk}¾zbÏÖ<–yÂÚ º[ÌŽYOb9A^G5NͦùÚb¡wd Þ7°~ýúFÚA‘.逘%»F _RaÐGØ·1ÎtÑSÚÍ àgÂÌkºÀ¬i&2‹æEb–]G "™5C&ØØÇC @+Жf€zcí×ÚHÈ‹UG;@ÔpZzx.乑Z2€ áºqR™v€x1CÍæ5»ç}œwáHûÑ<² ‹–>aæ½_/¾ƒÃ 1(¹/¼p0QíÊo*ÔÈÏÆ;ÁÚµk÷‘´bº%Mio$dàиzÙêVÀ Rƒ•¡Ÿ‘¹#`&#ÀXÀäƒw5¶‹$é#BŸñÁ¯qh‘ú8ù.'Ö£ò”{€†y³$ÐDWƒ„`1¼èZ&ˆ…iœ'‡Ÿöë"Ê£®˜äXgã%/llè3$€6È9 ÎÆ,AÞ{ {„ ×mNúÄ—¾¡…Dàc%ìåöÙ¶e®Û ÂÝç¥dC ³i4l’Ëe~Z[G83@X&ÀmóÑ^4–`æ‚ÜËôƒÁ›ˆb ¢Î&)Z¾žxÞ7$Øqyöå¶ù^úÇø…°Gðã—Yô¾«ŸóàšÌp—˜1Ãd!6 B0ÞáPæåÁ¦³êÜõk¹€O ÑP'dRÐdÿÀ´v–òI[€›ÚœDlZoRxGxv%è%Ü%è—MÐ162V ðqU›‘>ó|m0ãÝã¥fv,"ÀŒµ-Ãì7ÞƒÀ#2@¸nËÄ'Æ_P/2ÔÅGËú >"ܮ巡­'d±ËåÙF€ÅÂ]Ï¢„~Ž%³yFl öØxù²‹±až±JÛMjÞ Ô[¨ïs/ ”5 á&íi !1!h“q§u3ø¡`hcÉ  ƒ8œAFÚƒ2 D2AÀ/‚€«k\…ÙÅöK°ÇÂ]a¼×ò/6 ³÷Žw^ï»Æe'A³£8¬& ïB!Äz:›úº$ñÞºÁ/&/)nÙ̹a—ÇÙšÒN°d€0f@Ý$Hû6 PXîÑ$“ƒ,á±_×ÿ{×|WU%"$R¡RË › ZÚêŒ( uA”W‹âØNã?´c[-¶Õ±Ö¦©dì@)Q ))-§€B’"4„Lšy‘wBè÷Ýü¾de÷œsϽ÷ÜsϽ÷Û3û®µ×^{í½¿sÎ^ëì{î¹uç¢q{Ï;_žk:Örà’ñ:NÎÉa9fÄJ×3©vý|w?,G°ý8´Ç¨”†¾ŸçŸ *) àÛ ™´CÀ»cf±ã£CÔ3ñ¡Â¸€ô3 éuNtÄ«lb À9+8å”±¬œ–Ëö5ÊzÄ…Y[Ž<Êc}ª7ÊøÔ97­ äã®ñw=TxL›v‘ðIzn}ókŽ «‚^ää)ëWJܙРë™pëeü DšòÒãqRx–S¾%À¼¤vEç,ëÒzÍ›vÅ“JOmRJé©NíóÆhyÿ öZtM¶Û%ëßhlyP8¨y-‚š¬Ô·íõþŽ—Q?fî0÷küÞïS`VÒ"Ä €é¸$;Âq9Òƒ§®s^[¼¾IyÝéüìèÜû pP!úýrœñS¼ ä.3ÿÕI‹…‚Ñ~ÍMï"àÿ&0ñ΄ ”2ƒ‚N¶æ[FüaÆxý*°'»-ýº–Çò¡ž¶€ ß(\XiPÀ9iQ¡#޹—íï<صKÁ %nMj›R;Þ®:¦ãН?^ ÒEugOLFa=×c[×¼Tˆô¨^p1( \š§ tÊ̪¯ Z=ÇÀg”Ø·‚R.‚ ªî[ý™A" kL;r,ë¡ÚxÎG~ãußÀ€ Ó¸]||^[øqî ¸@1 å‚·!{…}ëgˆ²Å1pÔw h¡”ž©h*¼NxÍÈá+¨Ž×N¼Öš:k8pPñqâÅ©'¬+6=4æ¸ÏÀ€).V Ð)+Sõº(qW@mp1Aî¢â¢õÍ~!Àó\×®žŸºâuù~ÇvÇ^´ãäAÊÀ€ï*àC‡JÄ‹™ÎX‹ Hf–«ô £ú¥}îp&ϲ“èžÏ:wéäS‡O»ÔQмd¦F TŒ²/æÎeÀÄ-}tÖCò ”°L^òÎ{ÝûGCY/n¢]Ú- e€àdxNòѹ¨óP,)Sz9#Ð4T|DâE_±é±5ÇÀ€™ØòÀˆ1yf- RÛ´’Áˆ^buiƒwt Hų¬õÍ:oäàYÖ¹EÇ®úx>åñÃ7{xÜpPñ‹AŦm.î ð%CÂ^”êâIãâ­r¤âsºi}µ“÷u‚úJƒî08 ó`Sý踊ʡ§e!ëcJ˱μFT|Ô¼HT hEæ$Ä™ÇKŠ:q«XeQÕÑžÓÄãCg-ì#O™Êrè±,JÆräUojÆe/&: stæÌñxŠåÐÊðtDLüj_a(¥mc Dˆê.–eòMLšiœ˪㸅䑪^2Í3¶Ïã©ëÔÖÔ½8¨øLð‚S1 CH)>6IDATdŽN.+Ññ+åQN>¶Q[ÒTOu ´ÃÀ !‹Wð®ÚGš×GžœmUG*>ÊËòEz¬s2F :T‡eËR\ü*6ms#„Ï:bR:kòÌâ%Uë£,¶cë•"ŸÖI'•Ç6eø´}´kÞæ"à âcÌŠMÛ\ ȉÊÑÊÁò¸Š'eY:¢’KOmX/™(§Ï•<¾¬^l_LîÂ@ÀÀÄQ™‚(™²dœ£xÕ‘F™xR&ÖË9³,^”z1G»j/YQYu¤Jl§”Ç«ÞÔ#0TŒz\ì+6=Òæè”×®]»Ïñs²r¾Â´ß周“3FÀ$LJÊ.öˆ€œUfÆ®yÞtc„'lŒ€¨ í ;@t‡›[#`ºEÀ@·Èå´sL±€6¹Ú#P1*Ô@Å€Úœ0FÀôÃê {@½ Ð=vniŒ€è"ÖFß@€ ª€ã*#`Œ@Å8¨PšsÐPmÒ#`*EÀ@¥pî5æ ;P½ÐnneŒ€èZ,ìcõGèº9÷þnw-ÝÊ#0ZÀôýo>ë ÖÖ¡)ž€b|òj½‡ŒåFÀŒ¯ÜyçÛú=çZ8Äû=‘&ÙwФ£á±#`†—0âý(Ò§á×`ìëú4þFšuÐÝañ@w¸¹•0#‡À³ų– ûsuL¦)}8èîH8è7·2F`äXYÇŒj &MšôP“iJ<ÄC˜ˆRC|¬?°¥KFÀñC7C߯cÖµ?þø˜ÌÆ:&Ô„>äØš0–nÇrœøNêÓ1äµõ@Š”ËFÀŒ)×1ïZ€™3gîÁ¢?6»ÑIò ªyÉHÅ×qÀ³úˆýG>K·Œ,ÚÈãËØ±Ž0F` Ø´ Žy×p"øà¿ê˜PúˆN¯“ñ¨(ÛŠíÄ^–®ìŠÏÒKeQ?¶ë»më€9—€7°>0oÞ¼ZvÌk poAîû‹ šp²Dg˜å %ëf¬ÑvÙööõ#_¦?铊OÛź<´ËFÀq@kâMuͳ¶à²Ë.û&u]†~¢ó/ZfüEº¬+ª—}é”Õíb[ÉSuÄgé°Î;)2.#0flܲeËu͹¶€Â?§®‰ ²9º”v2&¶Uûví¢^äóڕщm£~ä©£2iäcûÈK'¶õæ€0ãŠÖÇ[ñÀ­uÍ¿ÖàCù7LlU]“T?ѦcŒT|ª«r»zéQÚ(cG:EúÒ)Û_‘~¬ó@¢®3F`ÄxkàµuαÖࢋ.ÚŠ þ}D_Ñ©‰'Ÿ7¦^ëóì¶“õ«:Rñ©½(|Ô‹íÅKWå¨oÞ#0fÜôõ¯}Is®5àÄV¯^}=ÈŠ:'Yw_ѱeõ]¶>«­d²¡rÍÓ£¼¨.ÏžäeÛ§zy}Ê®©0F` ؆µñoëžwíÀW\± »S÷Dëì/uri9k,y:yrÙȪϒI?²M™vy:iû´ûuÑž¿ˆ(™7F`Œ¸ú¶Ûn«åýÿÓÚvþè£þ Èq £ÆGÇç–'—N^}ž\íÊÒnì¤mb9òCZÖ¸(OëTΪS;S#`ŒÀˆ#°/þ¹jsHÀ7Nž<ù÷0aþåáH¦èÜ8ÁÔÉ©>oò©¾ôòäªÏ¢E}åÕ¥ý¤åØOj#–#Ï6i9Úñ@Dü0c€Àî={öü^ü³ysHÀ‰^|ñÅ+á þl“®£O:º‡­ÿï j® 8áK/½ô+ ßÔäûÙotl‘}æÉ£ù²z±Û”mW¤—Öµ+k Ô‹ºi9Î+«NvL€0£ˆÖ½ûÞüæ7ÏäÜ úyïø-ð£A‚о£ó‹öËÈót¢òeõ¤[V?ÕkWŽãj§Û®>Ú2oŒ@1éõT¬íÚ¦ ß÷“ƒ>øÃü:|chÀ‰¿ÿýïßr1òj–G%éÂŒT<çù¢9G½Èµ)SG[Ñ^»r‘Íh‡zeÊQ'í»¨/×#°?7³‹!âÖâ{ÿ n¹å–û¼0ß_vhŸ  s‹.«O†T·¨®H—íb}7娷ø¬ñÇ~òê£N™±¨?S#`ŒÀ °zÒ¤IgÃù/jâ\¨ .¸à?Ø?)Ùëkç{µ_Eû<ÞÎv™¹eéDYìÛ¶CÜõFÀ XË~øòË/¿kîܹ?hêx°óÏ?1~+ù.°µþEbKN4Ïft~ÔIõÓržvò¬~ÊØNuÒrÙ1§ý—m×n^®7FÀ4ùpþgâ;ÿFÿóm£ÔsÏ=wÅöíÛÜÙÀƒœ;¤,GIå(|Z—e8ÕÏÒ‘ŒºèÇvâóh–Ý´¿´,[iÛ´,=S#`ŒÀ"ð Æ<뤓NºÛþ|ÇM£ÓÁÝÄàðÁ—n¿ýöߘ6mÚ?@ôçÈ øéÜ´¥-GËâ³æ’êçéÙÈj“ÊÔO”§²´LÝ,Y–ûì‹üŸ¢¸-TÊthYN-KÖn¼Ý´)²™e²O× ZŠ–ËFÀ4‡&Ožü«xÊÿ‹¿ûº4”Q†£xåœsÎù'|%ðVïi:òtx©ÓKËœC–¬sËO^ÿYcê´}–~–¬sµM#`Œ@…l„­Olݺõݸë_V¡ÝÚM ÅC€E¨ðW¨?ï¾ûîûè—‘__¤_gïhEcßÝÊØŽ)Þ)G[ªOûŠånø,»´“%§,•«,Ç%‹õæ€0M@kÕ|ü…ý~õ«_ýYÆÓë†v ø{Þóžy»víânÀmiÝ ËYέŒŒ:YzÝÎ%Ï^VY2õ›U—%k§ŸÕ&K&;¦FÀ"ðnºÎÇwýŠó'–#p2Ø XuÖYg}Šï x²A¦,‡–ÊXNeyc®ZOýdÙ-W‘~^úŠT}ˆ².îlD]óFÀ °ëÓ§‘߆íþƽ˿W<†þ+€,Î<óÌqÀÞ½pá¡|:Çgéõ[FǦ$>:8Êb9êfÉUiž¨y#ÊŠø<ý<9meÕI&šÕgQ]–¾eF`Üð5Ó·3`',ÿ3ž1ûë›o¾yCßz°á‘ ˆ)(½ï¼‡~ø[;vìøc”ÿå#XWwâEÚ«Cϲ‘%ÓÜ:]¤/*;¤Y2ÕçÕ¥rÎ_²”Ê–©0!¯«ÎZZ;=ßÿ¡ù¶úWæèŒŒxd¡w¼ã[ÁÏZ°`ÁS¦Lù$œÏŸ |˜êûIé蘳œ–wýõ×/¯©ÏÆu3v€Ž€|ðþ®ò?Bþ9ÕWIéèòœ»œ`Zß©¼h¼²•§STϺAÖçÙr#`Œ@lÄz6wüÿxÓM7=ÛEû‘j2¶€Žâé§Ÿ¾ üÌÇ{ì »wïþm8bî LW}/TÎ3uî´)§šW—%ïu,Eí5ž<ªê‹ìÕåËr#0Îøš)}ô ¬¾Œuõ+H|.Ì Œ} ³à´ÓNÛ~6þvø†éÓ§_ þ“È|Ÿ@å‰mžƒï¥®Š¶[PÊÔgép¾’§´ŠqÛ†Gâu5Žóo3g>Ñÿm`ôElóß ¾ó§ŸÛt0ìÕ’#È¿†èæ%K–¼¿½üG‘§"÷œèüªvþ Jη¨M;ÖKG4µ'yJ³ô¤“Ö¹lŒ€èÐf.~Ê7ûºë®ã«ârp ŧžzê òÉ'?‹ïŒ>žÏ ð¯ˆK%96Q6JQ:¡NÚNu¤±>Ú‹:‘¯JG6ÛÙc½tDÕ6Ò¢º¨gÞ# À»ýïbœµú³gÏæC~NmpÐ VϘ1ã%ÙÌK—.}7(w.C~ ra¢SËsÞEu2ZFGº¢eiÚ£ž²ìgQÙÍÒ‘L:¢’›#`:D`%Ö‘9¸Û¿wûcÿP_‡Øù€N;å”S£ÍâgŸ}ö¶lÙr!øßE~ré`JŽ//0€­}wÌE:Òk§C½¼¤±äÕ§ò2úÔ‘ž(Ç(>ÚÌÒõæ€0 ë±ṅl.œþw@ýÝ~PÙbi§UÖà¸èwÜqÛ0×yÌË–-{#è…þ>辯èܰõ*È[u­ÔÎa³];*Òc]ÙDÝ~ëk¼ôSvüÖ3F`äØŽÞ‹uqîêÕ«¿9oÞ<¾«ß©Gô ›ãWÏ|‘ù©§žz;þ‡ÁùMtxxpŸƒ¥cg@ œ=õ{uþ´©Ô©Ã¥~'m¤ß®M¬_¶­æbjŒÀX!À›¬ÿÄzxÇÖ­[¿‰7õñ«X§ pP!˜4uòÉ'?ÂüO?ýô©pþ øÅ¿ÚJr€ äìIPIò½-öªm^ý~ÍýœÚì—´çÔF´}‹½ÔW¦¤“öè–õŒ€*¶amã¶>wW¿ñ¥/}iÓP~Èë ìøã_óÌ3 pg€Á<ùÿ¥è0)0r'Ž_mHe[4ÖµãÙ¦›v²«¶eìHWmM€yÖẟ|ÇæÍ›ïÆßïr»ß©Ô2»@0 O#8¯¾b>Døëȇ ç¦<§ØK0g3wl§LQY;QO¼ì¨Ü®o×#02ð÷ùtúwâïÚï÷Ïös\ w<ù[Ï à×Gáß ÏÁ…p:‚וR–ãÌ’Ù£~§mR{ÑFäS½vå^ÇÑξë€|ýîb¬qó±úïW_}µ²7°C±¿cû±‡_¬CÇ­_À¼víÚ3p‘¼2æ·#OFî(E'ù"#r¾¢Eºeêd'ö/™Ú§eÉM€zøFÕ ó¼ßÁ¯¡À÷ù;†~V#6 : pü»1œû'ògñs—©ˆ–OG™»üÊàä®’œ­²ÊYƤÃ:ñEúY6òd²§úX޼êM€VàæOõîݹsçw¯½öÚ‡fäc:P >ðÇsÌf 4óÇ7nÜx2.°÷âãsÌo@î)Éé’2‰æíT_vÚÙ•ž©0CƒÀJ¬EàåûñLÓ½³fÍzfhFî¶p0D'‘Gù†Ë|‡½aÆñüÀ™`Ï@æW]ï í¾$'OAä÷)$LÔOÊ”WV]KÉFÀt…€®³®wÞˆwø‹Âáß}ÕUWý´snÑ$4éht8–iÓ¦ñaBæ¹lºmÛ¶Ÿ–™_Ì@ž„ÜsÒBCªÜ³Qˆ¶"_…mÛ0£ŽîÀ[×PæÉ‡ö¾kòAÞåïÞ½{á5×\Ã畜F#t0;ì°•˜óNkÍš5GL™2å4\Äg Ÿ‰ ™AÁëYWU’Ó&eR¹*û¶cŒ@-ð/t"/B~oÞû?´W îíÄÀ@áïoçG}4_É‹šyœóA/¾øâŒÉ“'¿;ïD@À_¼ ùÕÈ•¦4 HËìL2uÌr*S©0•!ÀŸàñ ýGp½}ëÀCØÎ__™u Í¡ê} ¸Ðy›¾t"ßL‹X^·nÝtlñ½}" `PÀ?4jûWÇl_6Áv¦s·Ó/‹ õŒ@WðÎþf\ƒtø}þóŸ_Õ•%79ŒÜ!ílBXv£…^YÜz–€AÁªU«f€þ2w~™ôXä®ìtÕÎŒ€(…À&\ËOà:û!´úÔ{tæÌ™~—~)øÆSÉÀx÷ÂYO?‚ó¾´råÊix/Á[!x ò©ÈÜ-8 y*ra‚ÍÌ€ÂF®4Fàpí‚sù ð¼³gðþ¾Ö[ g¿çeŒ@´ÈÕû8á„6 ´p"·*°Mzæ™gÞ:oû:‹ÒtTp÷àУ[Jø@Y¬©0íà÷Ë—âšú1y|M·/[á÷æ·ÏåpP'kå €Å‰w+&ò·£Ú’%KŽÂ¯f`áb0ÀÀ€‰|ÒD> ÔÉŒ3ü©¯Ÿ /G^†ëiÞíñäg>ó™5(;¾"pP_­Û¸ÈAàñǾ£<¿F8;'â«…õS!k=kÀ]eš¯Ý„¦”56R%‘å^ø^ÛǾ«´Õ/»Uޱ!¶øt=_ ÓÊ8ÏWàü^sžŽÿ§Þ¶çQr…¼ûÍE`ñâŇM:õX윈…³•qgô hp,ÈŽ?™NH™ÆÄ“ÖYV_­N'>4†´®Sy¯ícUÚê—Ý*ÇXƒ­]èc-°x´µ †óó8ùVsû8x~mæd‰€€FªåË—OÙ´iÓq»ví:z¿ˆøXdoÄÌ݃7"S6y߸xR¦ªÊ²Õ2:ñ¡>ÒºNå½¶ýUi«_v«c¶6bŽÏÁÆ >éПǹբ?àôiä|O”†Ãzä<î¶,X°àh,Öüä㰈ƒüð?ʇeuX>t_P€ò>žò¢²êZJj“Öu*ïµ}ì¯J[ý²[å3lñnœ¿ç];¿c'¿çÁZRÈèðÿoÁ{ŽßÏ;‘FÀÀH^O®,÷ÜsÏ‘¸£{~Nõz8¾.ù(8„×!…òQ XÞ—Y†üHÈZ]ˆª¿Xî…§½^ÚǶUÚê—Ý’cÜŽþù”<óúÈã˜´äØ†_c´»D«@×bÇh œúNÚw2F`/|&.¸ýöÛ'~øá¯…Ó™'tˆ#@LEùµ09 ™ïG8å#à„(;ü¡àY~5xþ‚:‡ =õù«œ×‚ÙŸb¹ž{iŸ×¶Ým¨ßŽüÚïÆ¼é°w#¿D9ÊÛð@ÜKpØ,ožóÁ9ñ›¡³ Øn^›‘7]yå•´édŒ@8è@77U#p×]wMY¿~ýáøs'S·oßþ*8ÁCñó°×àŽ¶Å#Ðx œâ«à8§À)Ç€6‡@¿õr&ÔŪ}<äAïÀHc_m‹á]öŽeÞAoa-ÚïD¹Å£¯Gk˲íxømè®}ìc›[–üaŒ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ@üÚxÍ3žÄIEND®B`‚ic09™ì‰PNG  IHDRôxÔúsRGB®ÎéDeXIfMM*‡i    øµ…@IDATxì½ eÅ}ÞùØ÷¦Wè!„"4’cK>Š$„„‘ÑH‘d‡93™äœdâ3™‰ãd2ög<>'çHŽ7‘pÈh·%!ÉR4R$[`Ä¾Ó tM M’¦~þš¢¸÷½ûî­»¼÷¾:§^Õ­½¾{oý¿úWÝz£‘0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#0—ì7—­v£Àœ#ðÎw¾ó¨C9ä 'Ÿ|råþûïðpÄOúÓ#öÛo¿ƒC×V{ðÏ~ö³#ƒ{@pWÐ]â‚=H{XðŠŸtÁþ½†÷š2šš=¡€'ãBB]»B]Ïì {4øCS~ú³p½“°pýlpé~üûT¸ÞMXH÷L°;C¿ŸÞ³gÏ›6mÚõ±}Le…$6FÀt‰€ @—h»®…@àâ‹/>ú©§žZ„Ûš èV¾*¸G‡Î­ .Âú¨¶b¯ŸëUÁâŽã‚{x°6Ï#ðd!àõXÂ>¾×…T<ŠŸø@ˆÛü;BÚ‡:è »wïÞñÅ/~¢bcŒÀŒ˜Ì˜“/o{ÛÛ9ì°ÃÖ=ûì³ëCÏŽ ‚e]Þëƒ{l¸^ìš pV‡kü²¿Ípx"4e‡ì^‚Àõ¶à0Ü»íÁÞîëƒÁnûô§?ýðpšî–þ0è{×Ü"\pÁáað?> üëqCUƒSðo~„û1{]fç6Ë…ËÛ±ƒ½$aK ÷‡ë{÷†m}Õ«^õÀå—_þÓ傯½]&L–én/H_ƒ þà°†¼9 Ü'µð ÁÅîò¡››‚ͱ¾ ˆ¹5`?ö`ï ¢°e/A¸;…»ƒÿ®Ï}îsÄÛ¹DÀ`.oÛb7ú oxÃ+W®<á'?ùÉÉ{…û‰a°=!ôúÄ`_,³x?»›ÞØ ÏéÝ¡%cwïõ$Üæå†Þï0¢ÀqT{ìÅ#ÌOIìÉáúÄ`ã]íáÒÆÌ%ld¼­ÈZ{0—÷s¡m°P·sx¹è¢‹Ö5ýaVtzhöŒ`O vs°ÞL@°YZøÚáÖðnÜ´7„÷ä¦<ð†uëÖÝæÏ#—ö™è´ã&½¸•þùë÷ì¯=DÀŸT¢û3ƒ]¬0Õ`“âÁÞìM¸$ܾTù±?y hØdCÀ ”ËQÐe—]vÐý÷ßj˜±œzÌÌ!Ÿuy#`ÚC€M‰÷ 1øA°?†|þóŸçšÃ˜lŒÀL˜Ì×r%~ûÛß¾*Ìê_fóç†æœÐ{fø/ ÖªûåzÜÛa#À>ƒë°á=ýA ç?xôÑGoüÆ7¾a°1¥˜”B³\á@œaýñû½ŸYýË‚õ3²\‚{»°Œpkx—)Àzè¡}ÕUW=½Ýs/r àÁ=ŠsVjüíÛ·Ÿ…×bCó_,»ïmæp$î(hjöµ<½Þy>øàQøÌrl£àyÃy ü×À¾ðôz_„=ó€À“¡‘×ûÝ@ ¾ž™ï~êSŸÚ2 wÛAÀ \Ujøã™¡Aú×íu™ÝÿH&¸6-!þôf„ E ãmжŒÃ‰ *ÛQ˜…8×àä%Ž|ü„aø¤ëÓ„ÿCWv¯ž~ú¹‰%þgžyfl!Âp¹&Ž´ Ó5ñ„ãÊOz›Ö€|Bðþn°?ôFÃÖ1L&ƒ¹ù>ŸÙýB°?ìß–Oîlj € ÿ0Ðiüé5ᲤG`smÓ °ë}L D ÂÿŒ XüXÈBQx¬µhÖŠ¥Ë½'†^°ÿV - KÒa€ù¿Ñû…sïùôn,ðÃË‹»~þ»Õ^˜Eyä‘£Ã?|Ÿ‹PWXìï{–Ý ‹[2ÂRþjylŸxâ‰}þ]»vãÃO´6¥ †ùQ°ß cË7)ûÖŸÿùŸ?RšÚs…€ À\Ý®çû®w½ëä0hýðB¾) vÌò×Ía7²79à1:âˆ#Æ‚a¾bÅŠñõQG5†k¡žú¹-² xüñÇÇ„@.ä@~\´6c`K|mðõà~%h`¾yõÕWóoŒ6sˆ€ ÀÜ´plî‘ab Ap™ñ/¥Aµ~ôÑGÂŒ­ü~üîKùX´Þi–# áóºÑÎ;÷¹ø G£°¤†O ¯ äû«ÁýjÀçÁøóÃ9yLx£Â_îÿýïÿ¼°éëüм¿쫃}~›÷Ûœ«IlŽ[µjÕX˜ã"èå2{g#œh ØGydŸ‹r€¦aIÌáŸ_ ý½:l(üó¿ø‹¿x`Iú=—Ý4Èm ÷Ž /Í›ƒ€{GpüÇ ¤iÙ›ªžÙúš5kÆvõêÕû>jzâmŒÀ¢ €ö &;vìa~øáñ†ÆEégA?`=ßïó’剅ì%X&T€Çà‚<ÒöxKÂæ½—„êß^Ôú¿ìsßxõئœUó©ÂAŸºñwë9ëtYF`ž`ÿD@VÄ€} h¶†ÉÍB¿¾–ò¾%Ú½€}œ«.™t|»úAà¿3T{q°|—¿÷€5øµk׎…ýúõëÇ~®-è;~À\ÝB Àç,'<ôÐC£x`LÂá]ã/¢ƒ£Âÿka,¼*,Ÿ|ÆŸösWBøô]õZ/¼ð³ó}OxØßÜ—WÏ9¼”ôcŽ9fŸEÈs­j†×b·È,aìo>|ðÁÇÄ`Û¶m#ìcÍýgú»ÃØøåпÿÎÐøBÐ <ºwlø½0hé…™>‰ûþP<3}æ™;ƒ°ÿM>:öØcGÌê5³÷F¼¹»•nð#À2‚ÈÚì/!ì ·ê+Á^|úŒ?1l÷Á5ȈoØÈwl(î}Á"øÿVÆ¢[/*•ñnû7Ž6lØ0¶ ûÖ¡wF ;ˆ@øëî±½ï¾ûƧ&f¯¨Ýw…qéÓaáŸîÝ3ೡ3ãmÐÐ7¼á ‡†gØÄ÷Á`ßl¿´WìßË£º?î¸ãF›6m |NƳ1F`1`OÁÖ­[ÇÄ—=,+̉áóÂÿ7´÷ÿ _|kNÚ<øfšÔ¼Eá4¾sÃw®/0ÔKCGÕ,¦³llÒ;þøãÇ—ùÌúmŒ€XN8»"°eË–Ñ=÷Ü3&sr,òuaìúX°W|æ3ŸÙ¹œw/O¯-fÀ‘oõCò_ö²`ùG½Á¾f÷¸Ìö-ð{»Ü0#Ð;ü3#{ wß}÷Øå ƒþŽòóÏ~ö³_ þ¹Qg S€ w"lèû[á!ûïBRÖ÷¨¥ó$‘»yóæÑ‰'ž8v9=ÏÆ#P„?{îºë®1!`OÁ€— ~ _#ý‰¿"¨~ÇMJ°â8ÞýèGoü? IÞT’¬·`fóÌêø'œpÂX½ï {½ÝWl– î½÷ÞÑí·ß>ºóÎ;‡úùá®p#>¾`úÝOúÓ7.üMiØA€ÀðÇ;G‡C8~5Ø„ÿ It¯—œ…ÒI'N>ùäñ,ß|ÓëípåF`©àxcˆ„böD þµS÷sŸûÜׇ԰!µÅ`ïÝ8ÿüóO¬ñÁÿá4ˆM}Ìòùö^BßëøCzuÜ#`„Ú– wÜqÇø/–7—+üðO…Ÿð?¾ðn,=ûN ü/Á~ ØÞ?áãðÔú§œrÊx¦Ïf>#`ŒÀ¼ À>ö@n¹å–ñ ¤íw†vüV8mðÃ>§Ò¦^›±´ Ï{F@þŸ†‡•]ýöyø \ÖñO;í´ÑK_úR«ÛçÍpÝFÀdE€ÿ3€ `ùÂ`f[÷ÿ¯ÐŽÎxríé­ KGÂŽþ3Ãf¹€‹ê½ý¹<ë÷¬å#ðq½žßÛ;àŠ€èþõðÖ[oÝ|óÍト:ª¶¬šBÄo‡ÿRø½°4À'…Kg–†¼ãïØÿo„;ü‘`{™ñ³¦ÏQ»gžyæèe/{™gúK÷º¹ÃFÀþúøÆoÝpà ã>Txî–Pç¿K–µ“±m,ž„]ýG†?•øûAøþ³f/›û8uõþYg5 Ç·}O]¾0F`n`ÏKh »wóOÁ½˜B­—‡¯®ê¥ö*]XÎè?ðè£þÂÃõÏ®k»Æ–ƒy˜é#ôùS#`Œ€˜Œ‡ÝvÛm£k¯½vüi!ä k&‹_ öŸ„c†¯éºî®ë[Hvö¿:ù‚ÅíÔð×¹gŸ}öèŒ3Îðº~§È»2#` Î`yàoþæoúø{cÎøáxä_ûâ¿øØ"á÷e¡@Øà·60·ÿ#tðÃÁvÖ7fûÌô±¨ûmŒ€0F üAZk®¹fü§Ekî ½øŸÂ²À•yz3¬R:’-w{¿0ëÿÕPÇoÛ™^½zõèÜsÏ«ú½‹¿å;ìâ€Xz|ðÁÑ~ðƒñ^Žÿ¨è«áŒ–¿Ž¾e‘nÂÜ€p‚ßúpcþ ÌüÏïêÆlÚ´i,øO=õTÿÃ^W »#`ŒÀ^ž|òÉñÒÀøÃÑ®]»ºÂå© }¸®·Íz\¶0FÀ´ŸrŽÀ·¿ýíÑO<Ñf…l|_Ð|¶ÍJr—=xðîw¿û¸ð¹ÇgBÇÏÍÝy•Çç|þ“N:IAv€0F`Axúé§Ç¿ÿýïØ8؆ àgAð¿…}üçÌ\˜A€·¿ýí'…µø¯$[‘Ìü ïk^óšÑk_ûÚkþ6FÀ#°¸ð¥ÀW¿úÕÑ]wÝÕZ'ƒ,ùÏá4ØKæáSÁÁ€°ÓÿÜ ¾ù‹p—ŽiãNñ¼ozÓ›üçtîÐŒËxéK_:þ‡~xl¿0FÀ,)h¾üå/·²I0h9ì°ÃNýä'?ùÐá3þ½ï/ƒ=*'X|ð(ü=ðø_úr–벌€0F`þàh᫯¾z|†@îÞ„½f;9äÓ Ø–»ì¦å †\tÑE§†Ý™ß Z×´Sqþµk׎Â~‚ѪU«â`û€0FÀ¼þ[àë_ÿúˆÏsšðû#á_c_qÅWlÉYnÓ²AÂÌŸSý¾ì‰M;ççìþ·¾õ­#ÿS_ŒŠýFÀ#P†ÀÖ­[GáœÿìKAýHÐ ŠôN.»ì²ƒ¶mÛö_ºÿSvCf ë.c•?ÕkcŒ€0F`ø‡AHÀ}÷Ý7K¶©iؽ⪫®Ú15q zÿøý¸ãŽû߃ð_®¾ò=ÿ\0:묳rérŒ€0F`‰`ߨ™gž9zøá‡Ç6W×Ã2÷Š@Þúº×½îã?øÁžÉUnÝrz%|î„ÿÇÂéIY4¨úÃ^‚ßøÛ#`Œ€¨‹šäÓN;m„6 h©ëó¢|¬rïì°DýŸn¸á†Ÿ½(A‡½€óÏ?}˜­=ôõˆý ŸZŒ.¹ä’QÐ(ä(Îe#`ŒÀ’#ÀÜ” %gäZÂTO š€ÂÿðÕ[o¦7ØÏGC¯ÏËÑsfþï}ï{G6lÈQœË0FÀ#0Fpâ‰'ŽO ܾ}{Tø?‚ðyàÏ…¥êo]ýõwf)´F!½€pØ‚ÿwƒm¬úGMÃg~›7o®Ñ}g1FÀ#0izè¡l{§†ûð¦W½êUríµ×îžÜ‚vb÷o§Ø‰¥Òé……?µ¼å-oñ¿øM„Û‘FÀ#ÐH@øƒºlšf´Ánzæ™g~¿iÛêæïœ„Ùÿ/‡¿¢nƒã|ìôùË_ÙoŒ€0F Âäu6¯Â¡>YÊgoA0]zé¥çg)pÆB:'À5c “s²ß/þâ/Æ9Ð#`Œ@¬X±b6±Ð45œ8øì³ÏŽÂÆÀû†7¼áÀ¦åÍš¿Sfÿ¯ ³ÿÆßè<ßúó­¦0FÀ.àËÎ Èa‚L¤˜—­_¿þÃ9Ê›¥ŒN ÀQGõ›³4®,-ªÿc=¶,ÚáFÀ#`ZEà~áFáS¾Æu À†‰í¿üЇ>”gm¡b«:S9\|ñÅ«Ÿz꩟㤾&Àîç~®IÎkŒ€0F ü­üyç7úö·ù›f† á‹¶ {öì¹(”ôÉf¥UÏÝX¹råvîܹ?›(š˜sÎ9gtÄYÎjÒ ç5FÀ%G€ÿ›¹æškFAp7BBû ‚û+¡ Î@gKaæþfÿM,äáŒ3Îh´3#`Œ€È2‰½Mäy9Ï6þbЖŸ’£mUÊh6¯RÃÞ4a£ÃYMgÿÇü(hf¨ÕI€0FÀ´‡ œéðnT ûBœ“óPпhTXÅÌ€Ë/¿üô»ï¾ûà¦à%/yIÅn9™0FÀöà“ôÕ«W}ôÑF•±`ï'o uB:Ygõ_‚Š£©šÄgý7z¾œÙ#`Z@`ãÆå[4A>÷ýïÿŠšù¢";ÑÁnÔ¹5¢J»ÿ>úè*IÆ#`Œ@g09½ãŽ;ÕÇBøRŽ2Ëç÷¿4*°BæN@ØÙx*³ÿ&&œ!åä¥&mp^#`Œ€0)|™ÖTÆQ&_@‚=;\.YÕTÀ7—6FÀ#`††ÿ ÐTÆÅ} 2³“¿·íJpXSprœ¸l¿0FÀp,}SG;Ð"ð5@Ø3·)G»¦•Ñ àÚT=ÂI#`Œ€0CC€óü›Ê8ú„ðßëvrÚ]ëà£ýèAáÓ†ƒš²#€ñsá#`Œ€ü­oSG—DÂ^€NÖ¼['áðžý·lÙÒ˜0›#Ø$acŒ€0F`(ppS @2ÉíDеN¸A¹ÖGžxâ‰Ñ‘G9”{îv#`Œ€ÔT€NPí„°C²); NZ2èä¹p%FÀ#PÇ{¬±ŒcAצ€ðç;ɦÿ˜ôÈ#Œ6mêdsd×÷Áõ#`ŒÀ"ðä“OŽÞM5»wïî¼÷zÅwüMU»vퟔ„FÁÆ#`Œ@ßlÛ¶­±ð§,qwm:#‡vئÔÔlß¾}´ys'g$4mªó#`ŒÀ#À¤ÍtÓ%n4M5äu`î”°PŸ9Ôi,y{ýúõã…uËp>#`Œ€0M`BÊ—iMÕÿ=ôPÓ¦ÔÊßàßÙC ðÀX Pëv;“0FÀä@€YûÃ?ÜxöO[ }˜Îcßó75ì`ÃË 6FÀ#`ºF€µ&¶Ø&†¯ÛúXÿ§ÍÔ$œéßt3 G p '4Ÿ²lŒ€0FÀTEàñÇk³›ªþ©YÖ—é”ÐI´9–ØKðàƒŽŽ=öؾ°s½FÀ#°d ÅFö4ÝølÌüÑ$ôe:'0&6†ÿhÜgˆ0¬X±¢qY.À#`ŒÀ$4ñdã_Žcéo½õÖñ÷“êl3®ÙâEÍ–åükß;vô¶~R³ûÎfŒ€0s†ÿEÃf½ûØè:ûÚü'è{!lš@ ÃpSPÇôqŠRŽö» #`Œ€6¹å åÝtÓM½wº@¯ÑäP¡P–˜ÙSO=Å¥0FÀl0[ϹSÿÎ;ﱑ°oÓ@ø³!0—am†Ý”9oR®¶¹#`Œ€˜?4¹Ì)¬ùìï¶Ûn½zÏ.ÊœûÚ¸Yƒ¸Kn„0FÀtŠ€äIÎI%‡]{íµ½nü‹Aìü+€¸rüü±çäø*@es¬"å­\¹2Û2ƒÊ¶kŒ€0‹òƒÏórmø-Åõ×_?¨ýj½€9òÈ#ÇÚ€;wf9$ˆ2)‹›·nÝ: 6FÀ#06”³±<Çuqe¨ýûÞõ·¯KicN9å”Ñ1Ç“mÖÎ9[·nÍÊâÒ6ûÚ#`&Žì%Ë-üï¾ûîÿ†fCØÄÇ?ýAN?ýôÑÚµk³T9÷Ýw߈¨`lŒ€0FÀÄ ðüȠ܆ro¾ùæÜÅf)o0€Þ ¬9Øç ƒmܸqtê©§Ž×ñ›öÁO¹Üê°1FÀ#ü¹Ü–-[ZY›g?ëþC5ƒ"€´gÏž±°ÆÏ›7oΦàœ–r~ÒA;mŒ€0F`¾`ÖÏš<ëýh sʾæškZ);W[± 0í ›0ÒœñÏìSѰ¡›Ål¾î #¬ Ö·fÍšl'¦}ðµ0FÀ d Ÿöq¸O]92­W,;ßxãƒ_v$\çqÄû@ÔÒÿÈZ «®Jm7騣Ž­ZµÊ_ L{¢oŒ€˜sø2Œ šæ¶ ›ýn¿ýö}r«­zr”;X@çØ¸ àÄÀxW&al\½zõX€V€f50AþM¯( ²acŒ€0‹…òƒþL,÷Û0hn¹å–ѽ÷ÞÛFñ­”9h@™é‹¤‡2ð§B,‚\ªýY‘B‹€6¥ˆÀa‡6kNoŒ€0C@“<„[ê~ºÌôºë®kå+‚6!< ó¬Õˆ”ýëû°¨ö!un8ƒ/ \ÿXØæ tÙFÀ#ðBüìóbk_˜*ÏZŽ÷Ç?£› ÀmBÍÏLŸSºŒÍq´ðqÇ7Ú°aÃøæCRÍÁ´ÛÉ`K'l"0 1Ç#`úGÁÏ?Ýýa³ô‚Ïo½õÖÖIÆ,mš%íÜ:…&sôÑG7qLìÚ'i`/ya„U$&œ\TµNgŒ€0“Ðxæ·Î~°É¥¿8ÙsÓM7'¦/ŽŸ¹"ÀŠ çf³sÿÀÞÀõ$ai€òá,ìM‚Xˆå e°1FÀ~@ÌÄÁß¶ª_=EðŸ4UÚ¡»sG!ŽðKUn3øõë×øŒuÊA;PÕˆ°$À~–#öÛo¿ªÙÎ#`2 ÀŽßÿ®?uòy‡É-Š™Kø0>fþÚµ_U@^„¶6 ¢.‚ Y¨ª:‚l°·€|h !|‘`cŒ€0í!ÀdÁÏÒl—†Y?kýó¸ÑoNsKè* Nä ,<Ìr“ÈÃaa“ʶ¬@ý0O– œ!©ð>±1FÀäA€1ϸ\EÓ›§ÖçJaC8‚¹°ˆf® 7„a `Îú<*zÔõ³¬óS*},š4 ö*d‚ú!XêV9lD´1FÀÙ`2ÇR-c|ÙW_³—Z-c:úÜu×]-1TkYÞTsO€–¶mÛ¶ñ,¡‹E-[$nÖ‡­„K~ˆ„  ¡ NiD¼i0ïCëÒŒ€XL«™H!ø»žíƒ(‚ŸåÝ;î¸c<ö/&ÊÏ÷j!Ý-rˆüàÔñÌÈyÐpsg5 „åψ`¢"ÓHuñcÙŸÀÚccŒ€0Ï!ÀXÉD‹ñ•qzÚØÚn,1 øÙ^GV´Õ®6Ë]HÌÐ!ÌÜ5ëfÃDËC†­kXçÇBìÜi íâáÂBN h¼DP÷N8Ÿ0óŽ“6fûþ®vòa†Là|Øè·lf¡7öÈä¯~ã?÷0 g6ˬ²¶_ö0°×@g h¿KUÈéY"ÀÒY“2´nŒÀ¢ €ÐGàc«,©¶ÙodÀ=÷Ü3^>îKëÐfÿª”½p€N3#g×&‚:6ofßÞ¦Ê÷ ðp£>‚ T!¬´Ò0˜ ÄwÌ~#`æ–`%ô«~jÝf÷ù–ÿþû½m³C({! €€Eå·6!›""0M•ç/ò³Ì O y詟e‚išê…0`!.,_H3 ý Eõ9Ì#044ž1¹é[½cC[ØÙ/UÓñ>.{^ý M¸)_¾à?Š„iÈ¡b³ubìÒ  %˜fDX& –- Ú×0-¿ã€0]"À>_ZÕch®ö3ãO{˜Œ ©]¹úפœ…'€ÃR€ö” QÔð`æ\kTÔ‰å Êf‰BP…  IÀ’ž6Š àz© É£ï¼FÀ4A€ñKBŸ1jH3j=Ÿó¡æg£¶M1KAèºvà§ûbhX*eùµB;—ðXÊ…ò€RÏ4CH§´|^H[e!6FÀ6`–Ï ¡ÏØÕçÎý²þ1iCã‹à¯2Á*+gY—†è†òÙ ‚]ÿ&¨ð"—%ÒI½ÅƒŸS…$ÍûhD@„  ›æa'âBy\ö#Ø#`ê"À¸‡ ÇæÔˆÖmϤ|Œ|Î*Æè*ãç¤ò–%né7uKw„å4ƒªÍVÉ <7»„lðÇFX^<ˆ d[…ióÀkýþˆ@D4ÒÓúíx#`–ÆÆ5 ý¡©õÓ;Áà‡ Xè§M¿^J,°D6ÙñI âSE8J¨2Ëæe‘:>§V€¶A8tÎeópCØ€¦ Š)#"l.ô’A$Æ,&P„=BŸÉCÕ±¥O4טíoß¾}ßl¿ÏöÌ{ÝKKtãâU—”WBòSFH·ÁBµ9¢¢ãˆ¥ö祭jRB@>´Òàú˜âªh:˜/xÿ§öšåCæÅÐffûhn5îÑ'›f,=>³î*K1äh$DYRàá„TÀ¬Û0:,ˆM„´[d€%ƒ*Kq›È%/R£¾ˆXK#f¿>F„»„=îÐÕùE¨26¡¥Eè3¦b,ô‹ªf°;Tí|ž`V0œÕ@$ ÆÒ ð¶aâ}”ùо±äYêÛ¬|ÔfB`R Tìa  {Íðqs/KvÕ[ˆ KLÈp韅~{è›$Ø2s‡yBfÕÄEA ( Ö¶4Ô­Ï9o€ í„ Žv@}‘–@ œp‘ˆ,Ÿ$Ú#ÐB„;–÷R3ûyöBJBŸÙ¾…¾PéÆõ¨]€3/"/;ÿ›ªÁŽ–xØ¥¨3K/hnau²$eà@€‹ 4%!E¤@K!‚˜ 4Å®°s4 Žã„„½>î¢ú‡Æ•Óù—<ÓïçΚLÀ=Ö Ør˜˜ @4 t[LáÌ&B,†—­€lŽ…¼RrˆIäkAާÉeÌ;¼‹"Ô± ok,è/4L¬üŒ=ú}Þçê6˜r¤ @ˆ¡ ¨³7 ¬ „c,˜c2À Ð–Aø®\¹rl©ƒA¢ …9ë¿iÄ &ø!,6F`Q` w*öúÁE5ô AÐÇB¹¿óxM*Þ5Ø9ê*ýK_n!Ey*{ݺucõŸ– pÛ|q :w8è+/.„—,·)#ÔÉ’–@Ú…yI!÷py9@¸KÀË•Ð_ÄÙ|fŒÚ{„jŸ¾·9v•µÃáÕ0¨†Ó82˜‡mBª-ƒàc×=køس– pÛ4Ô­S ÕgˆZên{@ƒp”‘ˆ’ÈÄED0®±6F '¼<óòðñõ² 9ÞS4—úÚ×´¬xä|îº(Ë£e ”yèQi! ™µ#|Ú6:ÁoÍš5û¾*@†´e¸ú´‘:x±QéS7¶- AY¨_oQÚ !ˆ]ü†.îWQÛ6<ì¼Ï]€ ÷ ‹Ði{Y ¬©®˜0›ÑËŠJ.Ý™_VNÝðxÉ€2 Ô/Û&!©Óf- †*dEA$B19_éD0¸¶©‡÷ASd¹w —_.áJõ0'8Æ“ Æ0µYLL2ÝW •6÷Tm* B!Áð‹àbyÑÛ2¬ö/ˆP/ƒ vžÚªöV! 1®†˜à×5éE&â0å% £küÊ/—°. ϹlìŸ8\×Â-¾V¾8 |­²ºèÓ2×Áä@c„‰ŒîÏ2ã²,}7Èx§‡:h!8ô…Ý¥2½üÌбmµ Eü•mPÝ| mÕO}}„¦MÂ¥¾U!< EFí,Šã¾,â½)êë"‡ñ ê}“?—¾Ç‹|÷‹ûfPŒK­Ðyz˜¡£­–€¶C ç¶I65JK€Ò $—vØTG€{8íœ$è«×ä”CG€û¿Ëli¯¦=#Cï›Û—€|XN|3VÕJQRÝëÄ@ Ù6„3Óøk:˜.@³1Fà9xGy'x7EÜõžÄ‚>ö;# L„Dw_2ý `Ü7ˆvÛËŸÂQ´t@Ý pXk ^—/ˆ7ïÂ^ÄWjüø]p(ܽL˜dr™ŠaÃ{ âGƒ“HÜÜ3vHA||2¸ÇêN‘Ü64ËtŸÝ×~л„ ×{„ ç]â‹ß»ØßOk]ë<#`ñî-óËÈ4-!Ä8à× Æ†WƒYøY>ÐÙÚS@½ 𱦀kê·1C@€™»Þ „=ï„\Ú—¾GCh³Û°X˜d¼Ÿñ ›±Ø¹/JÇõª#ÂI3B?¹9È„D ùã#‘ƒ.®Ú¥´v@Sx–S+!Ïó–>séuÓúßLBÀ`:3Æùå 0fîh 01vø!‚"K\œ~–ZcbÀ§‰2”ÇlLdB ’@lŒ@ñó™’ØXÛ?¯±¿¨L‡®0Ȉ´_ì|`B°¬ùcblñCDä΀¬¸YZ/aè+åg ‡ `!²„3èÛ,&ñóT&èéyúl.&îÕ""`ñ®ÆAÆb]T"lHÄÄØË/" —ðÔ¯´Uì b ›Õ+͈AL¬=Øã`<<ñ³“Fq S£ãç$ö+Þ®˜GL2Þ5 ÁÌP$™=$!¾7©ŸkY ]¹qÓbÍA.?‚DÄ@D!]¶AhÕsÓ{¦k°×ý“`×5®L™_ñvÀ¢"`ùÎ2˜ læÝ/\HC‘@( #\–+\Êd#ýl2Ea¥%\®Zø®4iÞy½FE.arŒâ%ع–pã«úIgcŒÀhdù)`p’@É\´‹ºÏrÕ< ,]ÇnYZŠ¢ ‘i^ ?ÈB°È"(eO>ò`SSÖ&¥KãÓkÒÅaòË¥-`Äul‹ÊWž´Ìô:N§rì#0&³á55µ¦©9AE$á­Y¯üE‚=Ž“Ÿça¯üò«êô9¯›ø)¿(?aq¸Úa×þ0ÈŒ½¹Ì€°8 3 c Y„/—4q|ê— V¸òÈU·ãç)ö_Wñ«L»FÀ0ÈüÄqæ¢]\„‚Þøqc«x XÒ*„l|-¿ÒëZi¥:×µêÖý–«p\Lž^Çq±œÑ?FÀ–0È °òz€òéœÎïC àI~j"^¶‹ëz½s.#`ŒÀð0È|OF6³#€Àçs9 sá˜^Ï^²s#`Œ@û:¬>\õKXΜé&¸åDÁ½6FÀt‡€ @f¬MêjP7ç2FÀÔEÀ .r%ùLJ€q°0FÀ €AÝŽåmŒ5Ë{ïÝs#`úAÀ 3îÖÔÔ nÎeŒ€¨‹€ @]äJò™”3%Ø` @Ž6FÀdFÀ 3 &™uqFÀ#Ð ­€]»v-Õ‡ñ&õžSkêáæ\FÀº´N~é—~ééиÝu8oùLêÝ1€z¸9—0 ‰@'2³u°÷ÖìXÈ[TÐ)€PdŒ€0³ ðÄ,‰ë¦íŠ<\·ó–Ï Þ³ nÎeŒÀâ!äÈ}]ôª+ðPqó‹€ ÀüÞ;·ÜìÜ›½Ä‚»"×Ô½°AÖ¼ðÖÆxÈû_˜ÃWFÀåE`ÿý÷ÿ›.zßøNJlCiOíˆû(?n‘¿jýÖTEÊ錀X`ørîG]ô¯ðì³Ï~»‹Î ¥þÚ á´­¨q;c¿ÒÆaò+®ÈÓÈû•/3*v€XV˜xý'?ùÉN–Í;!¿ü˿̆†{–å†J¨¥ý%\qEnQXZF“ë¢úû*/w[šôÃy€0CA ¨ÿ¿ÒU[:!t& øWuÕ©¾ëiC¸Q&Fî,}¬“Gu)¯\…ÕO¥KýJ¯x]Ë%Ü¡a×eE Œ…ÚUß;#apÿ£®:Õw=EB.“?ugi7y•¿(ߤ¸ié«äÓÄþ¢² #ÒÉMÃMÊÐs¸0K‚ÀuW^ye'ëÿàÙxï{ßûãPß—á&JÀ¥n•¾7Í£üU몒^ipåOËÃËüqžIeÅéì7FÀ,í²¯:fxØeçúª«L¸ÅᱜÔÎ8Ϥt³Ä•Õ×U–&®'N‡§þ¸¬ØO:]ãZ"çk#`–]‡rÈ'ºìo§àÑGýƒ0ÈßÓeû¨KBºcQ[+Qº*e•å›–wZ½iþ²ôqb¿ò+Ÿ\µ7½V¸]#`ŒÀ² ÆÁûÇüÇ;»ìo§àÃþðS¡sÿªË¥®XÈÅþ¢ö5W™”SVVY¸òâVÍŸ–_Ç~•)7³dlŒ€XB¶~øá¿Óu¿;%tî™gžùãà܈Q[ê¦ýU|®ëiñJ—Û-«—ðIqeí(ËCzÅÉ-+ÃáFÀFà7þðÿðñ®û×9ü“ðã?íº£]Ö‡0+h“ÂÕ¾¢|ÄÍ>)í¤8µ!uÓ<ºÆ•_mÔõ´¸¸å± FÅ~#`–0þ]{ÿý÷ÿA}íœÐÉ /¼ðsÁùxî¢N 4êŠýqÝeáqš\þ²ºŸ×_–Ž4uâÒº'•·Ã~#`ŒÀ!À²ø¿ño<ÛGŸz!tôé§Ÿþ‡Á¹§N·]g‘0‹ÃÊüq»â4MÂã¼ÓüÔYVošwRº4.¾Žý”™^§õøÚ#°¨­ç? Çþ^×Wÿz#a)àѰðáÐñ玸ë ë•p“;©*Ò¥+ ŸTÖ´¸¢zŠò¤u§×qž´Ì4m|-¿òÈõ@Œ¨ýFÀ,2a¼ûÒW\ñ{}ö±7@§ßùÎwþepþMŸ´Q·\Zv.ÁW”. K¯Ó²ŠâÓ°²ë´Ó®UNÚ†ôšt³”¥rí#`[߯} ô±× p¯€HÀo§Óè·M ½Ø×‡Çþ²4„—¥‹ó”ùÓ¼Ó®ËÊ!|ZÞYâÓ´“êuœ0F`x(Œ{oïêÿ&áÕ;jŸ…³?º}ûöŸNjè¼Å!Øbáû'õ¥jºIeäˆKÛQç:΃¿ìZá^Èqç\†0CE Œq{ÂÌÿŸøÄ'nB{'\pÁÚ]»v}òꫯÞÿñÇ;ÿ ²µ{ ¡F±?½Nãª4(Í£k\ùUÏ,×UêŽÓL«OmHóÄ×òÇíT˜]#`ŒÀ"!6¿8à€CéSß ¢ýþccãîÝ»GŸÿüçGá¸à¡`Óz;b¡W$LãÄiãðœþ¢6Äõ¦ñ9ên£ÌírFÀœ ãžzê©C øú‡>ô¡õ9Ë®[V¯ ¬ÿÿ£Ðð Õø  }îsŸ=òÈ# š[W‚S.™a·YíŽoDîxÕá%€eû€X/Ÿ|òINÁwgÏž=‚ýòG>ò‘£úî_o ¨þ_üßJ(4;v FK’6±Òu*ì' Íiqi|¥D‰ÒüÓ®£¬•½EeÆaø‹®ã°Ê•9¡0F`N@¦=ûìóçü0æðŠ  èåô¿¶¾À~á €€8(nŒüZ4wn[‚--7½¨¢°YLË(º&,O¯‹Ú§W›ŠÂg×#0„Í~#´Ú?ùÉO^Ô|A°_zé¥|Qd‡½€ ú¿4 ú¯ÔOHÀg?ûÙÑ-·Ü2)Ù`ãb¡ûip|ûÓ¸6;W§^ò¤ùŠÚ˜¦™vÝe¿‹Úë0#`Œ@NðO<ñD¡ðW=l æ÷.¹ä’SÖµ{@×Õÿáxà—ƒP8|ZÝ0¨;ï¼s¬>9þøãGZ#ÆM-e¥a}¦;=Ùí9î¢Ú¥þÆ×ò«­q?äO]å)*Oa©› á4žë4Mz­8sÞ>2ÄB-ö«-qXì/Š'¬(ÒVu)£¨œ¢°´ÌªiŠÒ•…Åá±?­Û×FÀ!# õþ½jýÊMeÜc¹ hþõ>ð#*gÌ”°S°sçÎKBg®Ûv>¼êª«F×\sMÝ"‘oš°›_Ô‰:yŠÊQXQy„Åáéuœ7K¯ã´òÛ5FÀÌaGÿˆCìŠ6ûUéËÞeÏ!ÿ?®’>gšN ÀAô/š6Yë&M‹j5¿¥\*+‚q|QƒêäQ9EyÕ¥‘[ÔŽ²üÊ#wRº´Ü¢´ ã¾Ú#`æÃ;l<{¯²Þ?©?hkaüµ‹/¾¸öyReqIÑ÷¼ç=/ ß=žÒTp}ôÑ£sÏ=w–ÆD@£¬ƒ}†Ó¶IB­(¾(¬Ï>Õ]†9áE¦(¼(¬(¯ÃŒ€0CB€1=lÚ½úÕ¯±4ýå/¹qó aÀQa’|i(ì?4.°b€uëÖý÷9÷ôtw}™@ªˆA+ÉRÇuLŠ®iȤ4ħùâ°´Nâ0EáUÃÊòÏ^TŸÊPœ\ÂmŒ€0CC`õêգ׿þõ£cŽ9fÜ´—½ìe£¿þë¿/ähk%”³x í %¸ëØÑ˜y¥ù𨡠Ú5M°§}ê⺠¯¢pŠÂigQxQ˜ÒÅ…uë0FÀLCÍõ+_ùÊÑYgõ‚±œqýÌ3Ï}ï{ß›VDÕøsß÷¾÷6¼ÿ¨j†&é:Ñ\~ùåûoÙ²åĦêÿSO=utðÁ—ö7²¥‰:Š@ I¨©]鵚B¸Ò̦ôÓ\Õ=-â'¥/Š+ £,‹â&WõÚ5FÀ ÆåSN9eôªW½jtÄÅ›ôÏ8ãŒñÆô¦cÙÞ}Œ—ïý_@|[Øý¿S ÀæÍ›+?ÜŒT¨VÎÜB²ö……•5©(-a³˜²ôeá”]W¦v(N®ÂÓ²¸gEiâôö#`ÚF`ãÆãuþ5kÖL¬ b°víÚÆÿ_ÃØ·÷‹€7O¬0cd'€°aï-MgÿôyýúÙþA‘"r3b7±¨Xˆá/ª¿,¼¨àYÒå',nSš¦N\YÂËâÊÚ1)}ÚV_#`ÚB`åÊ•cÁÜqÇU®²ðØcUN_”y²âåüà×|üã¸(]ΰN@þ¯l:û?òÈ#G|v1«‰…QÓ6ÌZ7é©៦—`LË( W¯ëØ-‹+ 'ï´¸²x‹â&7nŸýFÀ®à ³³Ï>{ô’—¼¤pÌžÔžc=vtë­·NJ25Ž/ÛöšýxUðEm¹€ ¼Nhª€41°«½ŸZtv†Â-Üô¡(\‚°(}“~«Ü´Œ²pµ/M?)\i딩r'åUùv€0¹`ÆÏF¾“O>¹p¼®Rßᇞ[®œê] €s6Z`iOÓ6MkB-èrqe¤éTî¬áÊ'WõézwR^âêÆOË›b3K›Ö#PU«VÿI'ô‚qºjþ8Ý!‡’Ež Ø»°ú†·¸!3ú;Ñ„NÚTýÎ'€9 ç/ÇD mÁƒà+ªcÖð:” ë²pÕ¡x¹ —[®xܲ4 Ç•?Îg¿0F  ØKÆŒŸuû¢1¹NL&›Ê8êÚslvÌš§uÀ'€‡zè!MgÛëÜÁæ ,­Ã4®.nÑ—+¡—†I\Qø´¸qÁ5~Ô–IY'¥!®I¼ú5©~Ç#`ê"À¸~â‰'Žød™nƒ i*ãhËÔ˜0žæQyK+ÿiÀÿà·_SvÄŒ½M#"ÀMä¬7³¬½Ë:~Z¾²úŸ$ «ÄO*[qªC®Âc—¸IñqZû€0M`ã8›ú8º7×2rQ{Me\26ξ㽨aSÂZ'amd¿uïÿ&— Î)ý¬ ÑÀŠL:xhZ¡³:¥-#Óꪯ:ÊÒV']Õ´ÓêªRVY7FÀ¤0†rT/øpvLSÁœ–_tÍ54B"º6­:0MÁ¡þrqÅŠx[7"áŒÆ¦$&˜©'. K;8)ââ:Òüñõ´tÄOKCyUÓTM·Ñ~#`ŒÀ,0F#ðO;í´;û»4œÐTÆ-,@õ’ƒ…rW@k2,{Â~†;>«˜X– xÒ”ÅQ‡„ç¤4UÚ’¦Q¹ix|­4rã¸ØO|•4äQÚiéãòí7FÀ!À¸È7ø¨ù»ší§í`,crÚTÆ¡åîÚt¢`Ç%îÙ³§Qÿzè¡Ñ,§35ª¬ ³ö <ñÄcÀúR]Ö'8I°“fRfá»ví5=¨)ÈhvïÞ=¶Üt´EZ ¶Tˆž†¥mš–†xLY9ŠOË-º&m•ôJ#·¨,…ÅiðÇ×Jc×#PÆØM›6gúáïå«fk=ÝöíÛÏþ™Xvm:%9Z€¾ @|“ 5,K<¤hÌÜT>_„0p&W6.G~ JÒ”ÒLŠW>•¥ëiî,éI§ý“êQ¾ªé'•å8#`ÆT¾×?á„ÆûªŒ{]"‚V›±?Çì¿é¹N¿;#Ì’Ù¤¡ïë4–<¨[ÐPÞÐ –6Š @ôÐJøq7%J[Ö7å+‹/ ŸUتEe…©üÔ-J›†©.åMã}mŒÀr!€œØ°aÃXÅÏ¡=Œ‘C5<ð@ãÙ?}{ä‘GzébgÁÆÌ=‡šã¾ûîq|ãP ÂL¹±ö@@Ò‡9|øÁIÄ îaŠÃ«úãzfÍÓ4oüUÛètFÀÌ?hMöÌöþŒwC7h´Ù˜Þtó“âpVN/ÝíŒÐ;nrÓ€”C}|@ݳ„Ÿö ðPƒDB0Im” M-#4y1T¦ÜYúBå‹ýUËHó¦×UËq:#`æÆ1NäCècñ7ÛºF„ñ‹µÿIcxÕ6mÛ¶mÔÇ´¯SSb6œã{GÂ4÷T½iuÒñÐÀ±ìe@Õv J™œUÒNJC9MËRþœeMj³ãŒ€˜_ÿÙ¼Ç Ëø=¯†ñ¡ÝtöOÿï¿ÿþÞ`è”ÐKnºGÓ^ÃÀrþ¡CÓöÌšŸË2L"À2 ‚:ÌR¸J ãVaÕqúYû§Oë'.WÙq=ö#0|{ø\OBÍš5•Æ£¡÷Œ \Žôóá‡ïë«Ï³ö;ž;vìñ`Í»G}tlyqØD!ù°@IDAT¨"È‹0ˆ°tQº8,·çð§e§×9êpFÀôƒ“>c2Çñq³vd§µ^_wLVýŒ}7ß|³.{q;'ô’‡‚Í€ÐÔhF×G?6m÷¤üà¢M„¨šØ8(2À¡M_ªTè꺬MŠÇÅÈ-Kß$¼Í²›´Ëy€x1ŒEk×® }?ÚËE5|Òº¾é—lÂgË–-ãuÝ‡Û €9±þcC  I…Ž\DÃÑÁbXàE£¿Xw#á‹+[ÆrO½òãÆ×©é#`æ>öV¯^=žå£â/#æ¶“ glã“¿škŠgÜ­·ÞZPS·A½ºLXUƒZ†›Ô÷±9ú2­ pK 4¸M5qý±p|œ¦Š?Ϋ2É'¿â«”å4FÀ´‚ñJ¡?Ï÷ê"Æ áÏ’s.sã7f-¯n»z#<\èóÃ853ikpëT—i¿0õЗ@úˆÙ=ê|ÞS›z0Ûg3yÎ%iZ¸zýõ×ï[Ž­×ºvr ‚Ð5ÀçPÔö§žzêXãŒdÊE•€Xí5ûƒ„êJÿg ÜÌ(Dp! J&BÈ®hŽï–öîÄÂ>ç—>Í[9ÿ%0¾!üër>÷ʦ¿´oƒ!4 ðÙ´Æ Rì@…ÑrT"7†Ù|Æ8´  ¿Ÿò$/$ Sci îfAÊ£ 4”ÏÚ™M7€}™&GD@d€kÙnZçZŒ@} ³Ú<«´øzTù6Ã@@“ÌǼ•1ÎÝtÓM#¾÷º$4<_°€šFFŸ± À!uwUò Q ?ÄÂ/¨îÇ契栬" qee;|~@. ™ù·iÿŸ¯·ÙδìÁŒ` `Æ^4ÃÔׯ_?þ‚€ý"Â_3ØC"Ð& u€\xˆZ¿î«Üi=! ‚\âb|†O«gãy·±3î‡üq¸âp±x¹J·ŒØ¹ÏŰ×9€à/’Źê…Þ{ï½£[n¹¥õzêµnr®¹ tA*~Öëìe³|mäæ³Ë“¼³<<<,+ÀÑx£àä‡hbL" È fcê  Ì:ùÇb˜´1a“Œ(N•/’qà 7d?50_ «•4W€.qƒa[„%iBå 6Œ—Ð@fùz€‡‹<ÜtˆxVT j§2FÀœ°æÎ˜Þ…ªŸv#{î¸ãŽÑÝwßݺ†!'NeeÍ #Ülfæ„1Á4mù˜!À±Ú4ˆV_ňGŸ#BBlŒ€0F ;þ*ã~®V1idÖ?Ëä1WÝm•3·Ò‹€SýŽ=öØñ7¹ìîåaH?,N›Ù8È e†_u¯,mé9ä2€kcŒ€0í À>ÆjÆÞª“¶-¡^fü÷ÜsÏTmsŽúº,cn !ð9 €Jž5föe_ ”‹ y`½Ÿ>åL3Î*ÀB(Ø#à}ÓPs¼0F :hxYúEø3æviÐ4óg>óöy_UŒæšÐIn š–Ð ˆ±ƒYÕCä§,d¶ï¶. †ükDÀZ2´nŒ€(G€1Wjþ*“±ò’êÅ0‰ä,Æô®IG½×Ë5÷€n3s‡ ÎGˆ³Öðå¸NfçU—b¥Ø´iÓXÕ¨²Ã”‡…+­š î£k¿0Fà…0vj¶Ï¸]eâõš_±´€ªŸsüû¨¿yf+a!]æKþs™O™cºÌĹ© ÿÐ…(ãBá†vèíñŠ) €ÀG]{do²Š!Tø¼$<„¸¹ ÂzíÚµc‹ºMûp«>èˆ cBû.¹<#0Ÿ060nÉæÚøÜ6´õ>»5®µ]ç"—¿Ô€ ÛEPeI }4c‡}jC åå6ìI }X^\ö$@Ð̲—ÚÉ2– X#` §fö¸Uö ÆWZcœæ³êª ¡´ÈíXzÀÍác‡½ÖãgU“³W@yÈh°ÜÜ&Ö@P6Ä2€¥ÎY –üʇè‹Ï!˜U§7ý €pd BÈKèãŸ7¡I{Ù×ÄlŸ±™13oýèç)¨^« @„”—Ý™03j–°”%|d€¦K Á_ó’ @3€@¯Ãòi§Œ ¡OàaR DìþXa#Éø%¡¯ñËB?F(¯ß Áök’è™.¥Zç8b‘¶44Œ™ºÎàšõ=È/õÖ}‘¤%  –% 19@{0«öDåÙ5F Þ]ÆÞEÍìqë¾Óå5uCû™¬ âgܵÐv¼`hvMLüÁš5kÆ/2å£Ðߤü²¼" h 6l]í@\åacC?ÑÄ‚1°1F`:DÞ+ƞئïÚô’†›"úêÛ¼“™á"^Þ²f’­¼Ü…ˆáÁ„•êHß\Ò§yêÐ2ëùm½-MÐf"¸9–(h;åbcƒf" mmѵ51Rö/ ¼+Ò¬!èñ3àok è[úÆÄƒu}fûo±¯}âúQF `*R ×Z¡gw^@¸!ø$èSÿ¼ö«j»™Ð ð±Z>´À¯Š^7éL*âŒpæAFpBÚØУlÖñyQʼD¼<øÛ4Z.`¿‚ê þ6^\ˆÔœiß´œ BQ¹Ö¤ˆùºì¸ñ,^am¼7}ô³JôYKŒŒ•àY& ªà4¤4&3Þ ߢêyÚD”ËÄXféK- õrÍØüJÉ©;þº€Á:eÛ\ªP4Š´Ї @Dt A ¬­û¢úí.ä¸XÞ; {Ü6µtCG˜w”1‰–ñIÆB_H Û5¨qôà# й—Šškˆg âå)`pjËPwüuƒž4ÔO; »4Ô‡å44Ú.rº¤1Q(BoñÃx†õ ¥BžpÂHcAöü³zïµh™ ÐóÈ̯Ï Á½c €ù2ëD#€ÀéÊh§=§"ÄÐLHã¶©!@pÆ#X¢†·MBRc&0™fDpEp.?×X†iˆöÏ3(.áŽ+A®8][°O¿Oø{M6ÀÔØMÇn^Rt'±æ‘ídPá{û66 VmŽ› yA¥!€±cËfÊUËŸ”¡¨%þ¿“‚6 ɤ¶M‹«JTŽˆBì¦~ð ‹¡0•c÷Å ¤yvåâçþÈJˆ+ ׊#̦à©ñ¡|m3\‡œÛ ãÝáeŠA+¡?-¢Mz¹µ±P/w[íÕ¦B}eÀlœ:™Ih^UqÀ©š>M'b r19_.ÄCZŒÂS¿â W¹ø‹L\ñ îÓxž™8}|ÿäW<®°ŠÃ^äª»Ý À¤€w!n¼Ñ˜ûc³ø˜d¼ÇC~i RÛÓN,B™—Ë`a% ¤D†úDD ·¨®„â¢öÏý&h)õ®Kèó,yÌ&’‹Õ*€ÅºŸ•{ÃLPBYŸ2 ª!€`Û$¤%`†I„RPe¿r§Ð,{Íîqy‡peÚzŸU¾ÝùAÀ 㽚÷K¤€åö3Ð,ˆùÖ¹M¬¥PÙ©(EàlŒÀ²#À»Éû yÈ;ïǼEË~o»ê¿ @F¤ñ¥ƒpøÚþòC?!" @ DØÜ¤{¨Ÿ5éxùbÀµXTâ÷÷NZº˜ˆç~÷K÷ëyLžÇ¢±o™^@fë:N8Ö œEp™0`åĆÍqÚÏ ›Fùi 䯤ÒÚ5CE€ç•÷Fä—w(&×9ߥ¡âàvuƒ€ @Fœ—ýÅD[ ÃwX߸" f±w˜7¹Ôî) <‘͘ps’&ívÞåC€÷AB=&Ëøã÷AïÅþåCÌ=n €ŒÈú%-á̬]ŸµÅ81ãaÐ)ˆý9fïÒRÄ-£~[È€ˆBŽ:ãºì_NxÆ$äõlKÀãÊÄï‚Âì®0Ȉ´_æÙÁŒµkŒpÄA€àg0ÝÙk|î{úø ˆ¸ ꉵ"h lŒ€àÙäYa•?ŸzŽÉûU†]#Ð7&ï€_òŒ`†¢ ì5ÀÆÇ,Ç8k†”ÙYZU´¿€üԣ͎ñú¬üq›f©Ïi‡‡€ž£øÙŠýòjy|ïc¿âí¡"`ñÎøåÏfÅ¢DbìS¿tÂc¿®åNªbÀ?•„ÈDA~„×q›ÊÊpx{€¿î³žØåþÏýÒ½’K«ÊüíµØ%ö0ȈqjÝÎY>€z7Ì nÎeŒÀâ!ÆÃþuK]l\pÁO†¶ïi©ýƒ+Ö`p·Ä 2FÀÌ»»hpë`o'vtÑ™!ÔaPï.XP7ç2F`!x¼‹^uB‚P|¸‹Î ¡€zwÁ nÎeŒÀâ!ÆÃ-]ôª:³­‹Î¸ŽùEÀ`~ï[nŒ@^ÂDòî¼%—Ö U¿¸úÅ µà…÷5ÆC~ÜØÿ¾2FÀ,/al¼¦‹ÞwE¾ÓEg†R‡ÛPÚ“³ê›\Ê–7öÏR/ù¬˜1§5F`Axú§?ýéõ]ô­pÀ,%H…¡®¹±òËíâf—Õ¡6àÆ~¥/ S\‘§/ó+Ÿâum׿˜L7ǰÇþëUW]µ8_¼ûÝïÞÀ¼¹G@;­ºŽP#ò¥n®ÆÕQµlµ‰ôò×)oR^ZUï†Ó#°À|©«¾u¢ØÛ™OtÕ©¾ë ê›IÚS$øfigœ–|qÝUóÅuÉ_%/i•^nQýEq„™TAÙiŒ€X`88¯3YÙƒûŸ„ŽurºQßG,à&µEéäNJ›Æ‘gR¾Iq*+.£JzåÃÓÇþ4âpåÓ¤e¥q¾6FÀ,_ºòÊ+ïíª¿€÷¼ç=|ÖðÿuÕ±>ë‘ KÝ*mjšGù'ÕU%Mœ_éqåãñÇ᱿,]QYÖ¤hùÚeB Œ‹Ðe;#t*tî£]v®ÏºŠ„`û'µ“tUÓN+gRöL—uwJ.¿üòŸ†ü.;ØG]E/ŸÂpcQû_GØ´xå‹ëR˜Ü*eÔͯ²‹ò—Å)\í³kŒ€X"®=ýôӯ躿:÷®w½ëóÁù¯]w´Ëú$ÌR·¬ J—Æ—…ÇéŠÒ…Åy¦ùËò>)®¬Ü4O|û­(CÐáFÀ,8¿Æ¹ë>vNövð÷Ù®;ÛU}µX°©Þ¢0ÅÉ-KS®|U\Ê(+§,œrÓ8]ãʯtº–«vÍ’Vyì#`–O}ò“ŸüJýì…\tÑEÂoõÑá.ꌅŸürUz­ðin|eyŸ·¥,iÊâŠÊŸ”Ö€qû€XtÂx¸õÀ¼¬¯~öBèìÊ•+ÿeèü÷úêx›õJÈÉë",ýiºøzš¿¬œ¢|ei /‹KË™”.›tÆ¥õøÚ#° °'îï~ü㸯þõFÞøÆ7>þ#àáãOõÕù®ê­"äHS”®,)M•9 šî7^rÉ%¿»üºåP7c®|áÏ~=”õÊ g!î¸ãŽÑ1Ç3 áãY2³ÂØ’.¾–hááÛÎQøÄƒfík¯ü©KdŠúS—–£tMÝT ·}M{©ƒûÿÌ3…Ý*ç7FÀLD€q á»×¼îÜsÏÝyÝu×ý•úr{%^xáßïBç÷i"éöÛo­]»–³ö Ï"Á¨0\L|-_áµ!m߸±Q{ÕÆÔU>…«<]ãbâp®› lÊHMÓ2ËòÇáøMRä}mŒÀ¼"ð“Ÿü$þc"Æì7¿ò•¯ü›`nê³oûo×xÛÛÞ¶"Ôyeô_DBíꫯÝrË-]7+[}©`SÁ„Çq ¯ê6É[µÒU©'íË´k•›–^ÏÒN§5FÀ °¬=zâ‰'â™ÿ¾f†¥€ýƒœûÓ°pê¾À<½€ƒ:è×ÃÀ¿±¬Ï€¯}ík£o}ë[eI.¡&·¬±i|z]–¯ixZOzMù„ÅáéuYâ½NÓOº®’—4UÓÅuå) #Ož^ÇåÚoŒ€˜'ÏvïÞ=¶ÓÚÍ$7h ^–‹/Ÿ–¶­ø^À¡‡ú{¨ÊŸ Þ}÷Ý£O}êS£Ç{¬-²—˃ ·Ø_TYÓôi™Óê#}Z§ÊHó¦×Ê«ôºNËK¯•>-/½V:»FÀyA€ýk»ví1û¯jH&Ãÿóûßÿþ×WÍ“3]çà‚ .ø¹°Ñë-³vâÁ…¿LÝ|óͳfí%},Ôb¿‡Å~ŧn•4ižôš2ŠÊ) +Ê[V”7 K¯)‡°8<ö§õøÚ#0dؼüøã˜ÕÏb A °p'ä{þs°Y i¶spØa‡ý³ºí…-±9;¯»Å«¾:°(OZ×,¸ÏR^YÚ¸¾²¶”…Çyí7FÀ Æ/6úa‹ÆÁ*mÞ«1xÍ¥—^zI•ô9ÓtJÂÎÿu¡³onÚ›nºi´cÇŽñçoMËj+¿¹Ôû«ÖKž4_z]µ,¥+Ê_V®²ä–¥KùNÃ(£(LeÛ5FÀ c=v,ø÷ ðÚÍC €æ Œ¿dä!µ ª‘±S°nݺ:¹¿¾[¯ëž|òÉ£ã?~¶S£ï­g‰…ZìWÅUÔ¾ ·j›ÊÒ•…Óö8¿lýrFÀrÈ!£×¿þõ£w¼ã£p Ï¾sXêÊ3òñÉ`0'†³o>”£U˨¼¯j“ÒµýÃg“’Lãt½7¾ñûÒé´=XÔL*ì¸É±!>Sú4,¾&š/Sq=Н¦|Ee…M«¯(OQ˜êµkŒ€ŒÅL>_ûÚ׎ ˜óÎ;otà 7ŒûiÚFÆÁPǯ†r>Ú´¬ªù;#úЇNÇ!ͬ½‰9餓F«V­zQ! ’½7u_{ÕÆT°ïKСGmI«ÌN³”S–6m›¯€0]#°zõêÑë^÷ºñ1õqÝ|ðèì³Ï}ï{ß‹ƒ›ø_ý¾÷½ïœ+¯¼òGM ©š·™4®ZKHÖKþÇ{ï½w†ÅIÏ:ë¬âˆ:¡ªÆIÆm",¾ŽÓ¦áEi‹ÂTÆ4—¼e¦(®(Lù‹â+ 'OQ¸Âäªl»FÀ¡ 6­Â‘½£ÓN;­pì¦/ùËG×\sMá87k?öއ ùþÁ¬yë¤ïl@Xãx+êÿ&–?bí¿ŠÈ! —²¶……•õ¹(mQù /‹+*RúIåÅ©¬²8ÕŸ!…Û5FÀt…šj&›ï~÷»G§Ÿ~z©ð§=Gyäè„Nh$Û‹ZÎE^ryø—Ü.úÚ™ œŽ´¹©úóæÍoD ˜„MBEuÓ&üEm( / ›TFÚg]Çõ+l’;)}Y\Y8õÌ7)ý¤v;Î# Æé—¾ô¥£sÎ9gÄ쿪abzÿý÷WM^šnï9ëÂÿà¼"$º¦4a¦ˆNÀïÿþïûWõW5ݸaÆ™»`TØUÓúg­\B­Šð/K;kx•6ªÌ4mY8éˆ+‹/‹Sz¹q} +˧µß#Ð&ŒÑlð{Å+^1þ+úYëZ¿~}ù‚œB^…Mí?Ú° €û榳n\×ð•€iK‘P®[vÕ|z¤ï¢þ¸¾´uã(§,oYxœ§,MYxÚn_#`r!€’C›K+ÊÑ ƒúʦ€¶ë-Ú#À7MÛß ·¢¶Kè•Å…Çeçö«=eåNŠW?Ëò>)•øIe;Î#0 £Ž:jü)Â?ç×ÉD²iÙX—Ý–¿˜Ö!QÇj÷v…nà@}£¥œÚ†¸½„ežøºqq=©_õ¦áéõ¤t“â(GñrÓ²•†øIiŠò9Ì#0 Œ£lÎãþM›6•Ž«³”9)-Çù6•sѸxàÅ_|ðUW]Uý¿…'5®$®XÑM™ío“- °O²¨{S£›9.žëIÂD“âËâÔöinÚž4½âå¦ñº&>GÊ«R–êµkŒ€˜†ªøOTüÌöëNÚÒr«^#›ÐG›øªf}Aº˜¼ ¢¥‹N4áæüº÷jweçÎ/:‹¹va3dDó€ ‡ø[å“à«"¼‹šCþIy‹òT «"p•FnYÙÄË–¥‰ÃgIç³ß##ÀF>>ã;å”S:›ÆõËÿè£V’ J_æ²­KÓ  C¨büñF}kš¿Qå!3ì,ü¡ÑØ¢¨#¤%TËò_÷£(ÊŽÓù«¦#ï¬iI_%ÒUI[Ô‡#°\0ö2ËçdØ7V'ÛFè±Çk¬þgÙ¹é$yÖ~vF`jÏ&†Mz].Lj«´»víï`Ý)=§¡iZ.A7I¸“fR<íšVŽâ'õAq¤­’^iª¦Ÿµ|¥·kŒ€ˆ` eCGî"ø«h`ãümú™µ?òÈ#Û„†¹kÓ@@6Ý 8>ø`¯ªžô! !&XJú ÙÑžiè1ˆIA\¦ÒÆa©¿JònS7=ùªæUZ¥×õ,ítZ#`ÆLÖõ;àgyˆ™Äx®1½n›NëÔÛ`7=7!ØÄ°5I2ѤEya‚h°1ˆ5|àÀÎ5®¹Eå¦ôeñE᪳(®(Œô²EñeaªGnYº¢ð:yŠÊq˜0ó‹ãߺuëFüï 3ýxìj¯~øáÆòˆñ¹ÑµéŒÐ1þ6~S³mÛ¶ñPÓrÚÌŸ’´|Á€† ÈHŠ@ bb <„Õ1*¿nÞYó“^yR680‹‰“¥cŽ9f<Ógmí鼘‡zh¼A¼é’[¾8ëÚtNrt’õþ|aØ!72ÀF¬4HÁ´GB4}0ê• ä´ÜI×Mó«ì¸þدx»FÀ,6Œ}¬é#øq‡¨Ñv˜¬Ar´e„>L§a‡Ðf]SƒQAØ´î&ùcÍmG#@;2 ó•0ŽÛBØ,x¨ ¹qYUüʇ+K>…W)CiêäQ^»FÀ Æ¥Õ«WUûýU«V »ÁZ·}ûöñX7m7­(vÿC$ú0:ˆÀË1ØÚŽ;Æš€>€ËQ'8è³B ä2 íÀ,Â\í¡ÌØ*|š«<ÓÒUË‹ýUó;0ó“„=kú¸³Lp†ÞsÖëÑèæ˜ýßsÏ=YdbÌ:'ldŒmj¸ËyY ˜Ö_}MÀ¦„?j2^"‚iùËâ%€q1r«¦/KW'¼¨- «Sžó#0 Øè½víÚ±°Gà3~-¢a:“ÏŸ‰, /Ó9 £€ß<"8PÃpDŽ›Ñ×M(ª—¾±aR›&aÏT‚4ý³¢XèÊ[¤uˆãikz]Ôþºa”mcŒÀð`LB­/¡ÏØT4~ ¿'Õ[Ⱥ?2'Ç–Zo½õÖÎÿ‰{Û @XóðäØ ÀxàÆkKM×bb`†æ+6?b1àà¥Ã–}]0k?bá^UÇy¨¯èZíHãn×a#À¤cåÊ•c¡Zÿè£^x߯.„Žì”Ë2ÂÖ­[ã*:÷÷Bè%Z€€²(G$`Úwô¤_CŸùt‹O4Z2hª!ˆ1J…¶®ã4Óüä)2*«,¾(ÃŒ€hfòL0˜áËr½ÌáŸCs †Œw7ÞxcãsqšÞÞ‚šYk.@YKprÔ"kÊn¸6E²6…¾¼´¬Åun\$´-ÄËîŠÃÀ| €V–=—]úL*lžÖlÒÎyRëþìõêÛôFè8jl6TäÒ š X´=³>(¬UÅ{ÈV@d?¶5»”èš6È[dÊ‹Ò:ÌÙ`"À²!‚•>vÙg÷e(2ñÉy®‰*õ°yý–[n)«²Óð^ =efÊ:>+‡a&|ÿý÷—€`Ø< «}X>_QˆtýEÅ4Bð|ëí3F`V˜iŸ_‰—e©tV¼âôÈ%„®5ÊfÂ{Í5×d“wq{ëø{'Zkb¶š‹ò}÷Ý7þþtQ?E©s³Ó<_‘ʼnˆ@¢ mh T§]#`š!Àû yGØ#äW¬X1ö{ü«‡+ã"kþÈ’\†ñöÇ?þqÖ¥„¦mëÐTR|J+e­%Ç' ؛ֵšµ,ù‹H}çÞ@ ¸ú’ÃÄ`Yž ÷s(ðþ¡²GÐ#à%ì—}Ù3×ýaw>'ó1æ4|òÇõÌ €°€‡úôÓO“ˆ@Žð裎Xೕܛà†t#Ûn „*ÕP§Èƒ¬qnûn¸üEGb ÙFÀ#èY*•ß›óÚ¹ûÈ6Q?öØcÙ+¸ë®»FØ¡™Á€a—%3Mþ‚?ûaÏzuS"À¾·¤LovÉûBÜŠ6qB°\î+~k òâïÒæ4Â]!/Ë;cÓ Ln˜õ3YÌmØ“6”MißEh꩸Ž;î¸ñÌ"ÀL¾ `Y5Ø4DÀ/Wú(ä½olÑ %BÀ=…nc ˆ/ëó±Eà3ñl¾ÿ»Í$Sç©än ²ëúë¯Ï]l¶òGèÂÀËŒýC°,€Š¦ €`pæ>{x mºG@ä ¨fdûIkíAbëžQÆ*mšÅEÐkìbŒñsÛç*¯›Y?ßâã¶aÐ:sØOyÕF»â2IŒú=ìà µiÓ¦ñA?Ä¡®AÔ1ììd3ª6´ª£NYΓ*_‚ˆ P3~½`hóÞ‹e/ áŽ@g|À• —K˜gðó÷”0Æ0ëoc­_hpÐjM š;HH‡ç_¥xex9ír€6­@Ñ´ÒOrÙsÀþN½b'­È$´†dzQõÅštO«–1œž»%Mày` Á"¼qYz¯kù½$ÕíáåGŒÜ¨;yœÖ#Æ”Ûn»mt×7üµ}°€Æ&$€MøãR€Ÿ£+Y¿!ªýY eò@p:DÀ›gEpøéôˈ€ž+=[ºf– ?.× ~—£…Œi¬y|-AÏŒ]~ õåx6Ò^¢ægœ¯##Ҳʮ!|çÏ^³y1ƒ&€È   6lûSæÆ  ?«à0!ˆª èUoZêA­Gy¬ãÙ,>“ÈAYïSb_‹,(L¤!¾¦Ü8]Y=‹ÎûŠK¸„¸üÄ&a®ô‹ˆ‘û”öŽ1AÔߪç+ù…%¡M¾öÚk[¯ç…µ6¿< ‹}Öì7nÜ8Šv–“ŽÙ;–xö ÔQõÀùlƒýþC PµIð"<ÇŒRä“®_ä'­ŒÒ©…Ë%•=Â}šA½ªMƒú$„¨*k`I@ÿ¼¥5Ïiu;Þ#`š#€ÀgÜn럢2ö³ÖO½‹bæ’¾Hç  `vÏN~nRUažjX" £†¬7A8GÀk·Us#`ŒÀì0æ£rgwÒÒïì%OÎA½¬ó3ó¯2Éœ\Ú°bç–#‚žO÷8aάœo~Y˜…ÆZ4 |=€`çÆO3<¤…òé dÀg LCÍñFÀj0–#ø»ØØ—¶ˆ±ýæ›oÿQ]·×sM¸Öó֬ͳñd ê²@|#É‹åk:>%Á¦U ^Ë ˆ–o–mŒ€0F :L¬Pó3Û¯{ÒkõÚ^œÒÁ‰~|A6mìqîù Yé„ †°SƒàE-ª"0ëMd]BEÝDùØ*¥€=B&t>¿ƒžŸÃ-5F {˜D1ÓGøÏ:fçh-cý–-[F÷Þ{ï©û‹ðY@ç`‹ßøï~õ‡0ºYöÄ`A&øï,u?dr1Í@>°ì/Àµ1FÀÑxEèc¿û0 6–s†?ãzä£~/@©ýÖÚ”ÇÌ›ÏöX£'¾Ê,¾ìfP–?$‚¥Bªì@;¡‡œvi¢*CÚáFÀ,*Ì´?Y^íCÅ/\ô,!ßyç•7€+ï"¸ G¸)0¸mÛ¶gì±€… Ž‡ @ªîø/»ÑRí³_íD Ê~X.Z,Úi 6FÀED¡Ï Áßd–?“7vö3f/«YHÀÍäaã –ÒC{˜#¼¼Ú¸×DåÃ~Ž Æ"Ü!÷*d€v’k2°¬¯¡ûm! }!ÌW^~4²MÆ}•7ÏîÂn jwÔ;lÔñÍBp‹ÀLëîˆË„\èøá¦dâIÁõÂeû€*Ìî5žVÙ'ÕE?ôLÙÜ×TóÛE{»ªc¡ €@d&EP$H!¬ÉCxxQQAšš¦d€vci3ËZ* \#`ŒÀ`¬”&Áß×F¾",h ËÁ÷Ýwßxl_öŠÑR:`ç›NŽæ° "ƒ EÈbùj€‡9ƒÉ€Ôþì€lL{(‰× Æ×ìk ÚXDjŠúç0#`Œ@ôUãRßëùEý¡]üq³~Æ[›b–†Ð}v›ò@ ¢G€N2®ä‘:kRúYâXë×ÿèëö °  {†”ˆ˜ üY"ÀÒæxÓã,mrZ#`Œ@QMBøUÆ©²²Ú g¢ÄºuëÖñ†ìi«¶Ú1Oå.àÆðPè~6íM›=#P±ì#à`Æžóágù²±´ ²¡/ª|£<äài€”i;ƉýcŒ€(@€1Aelò,šÉÚ]TýÒFXøÜÔ‚ ¥#€‡;iI@iqµO€½Ò PFÎ 2Zá€ÑBô`Çm*òóâê¼â!Òfp(ÖÆ## |ÔûØ¡ÆE„>»ú‡sŽÅCï{®ö--@X-_ ð…À´%ðX+ ™ˆÓäðKµÏ¡C¼Z& ¾ª†­!€P6ýÀ?M Rµ.§3F`>`Ö̘¢Yþgø1¢ší³”Kû-ôctf÷/5. +S•%b´úÓ­‘!hÛx™Ôüõ1–ò©í@Õ}j7„@¤Ea,HK r£8»FÀÌ7ì3’°G€"ôs|åÔ*Œwl˜FÍÏxg¡Ÿù¥'‚’—m$!8«AˆbYËçeCÈ"¤ÛxXÙD¨?*¢|êÒ'ƒ,ÌjXÒÀRFËi ;6FÀ ;B^3|Æ"Þíy3Œk}¾zbÏÖ<–yÂÚ º[ÌŽYOb9A^G5NͦùÚb¡wd Þ7°~ýúFÚA‘.逘%»F _RaÐGØ·1ÎtÑSÚÍ àgÂÌkºÀ¬i&2‹æEb–]G "™5C&ØØÇC @+Жf€zcí×ÚHÈ‹UG;@ÔpZzx.乑Z2€ áºqR™v€x1CÍæ5»ç}œwáHûÑ<² ‹–>aæ½_/¾ƒÃ 1(¹/¼p0QíÊo*ÔÈÏÆ;ÁÚµk÷‘´bº%Mio$dàиzÙêVÀ Rƒ•¡Ÿ‘¹#`&#ÀXÀäƒw5¶‹$é#BŸñÁ¯qh‘ú8ù.'Ö£ò”{€†y³$ÐDWƒ„`1¼èZ&ˆ…iœ'‡Ÿöë"Ê£®˜äXgã%/llè3$€6È9 ÎÆ,AÞ{ {„ ×mNúÄ—¾¡…Dàc%ìåöÙ¶e®Û ÂÝç¥dC ³i4l’Ëe~Z[G83@X&ÀmóÑ^4–`æ‚ÜËôƒÁ›ˆb ¢Î&)Z¾žxÞ7$Øqyöå¶ù^úÇø…°Gðã—Yô¾«ŸóàšÌp—˜1Ãd!6 B0ÞáPæåÁ¦³êÜõk¹€O ÑP'dRÐdÿÀ´v–òI[€›ÚœDlZoRxGxv%è%Ü%è—MÐ162V ðqU›‘>ó|m0ãÝã¥fv,"ÀŒµ-Ãì7ÞƒÀ#2@¸nËÄ'Æ_P/2ÔÅGËú >"ܮ巡­'d±ËåÙF€ÅÂ]Ï¢„~Ž%³yFl öØxù²‹±až±JÛMjÞ Ô[¨ïs/ ”5 á&íi !1!h“q§u3ø¡`hcÉ  ƒ8œAFÚƒ2 D2AÀ/‚€«k\…ÙÅöK°ÇÂ]a¼×ò/6 ³÷Žw^ï»Æe'A³£8¬& ïB!Äz:›úº$ñÞºÁ/&/)nÙ̹a—ÇÙšÒN°d€0f@Ý$Hû6 PXîÑ$“ƒ,á±_×ÿ{×|WU%"$R¡RË › ZÚêŒ( uA”W‹âØNã?´c[-¶Õ±Ö¦©dì@)Q ))-§€B’"4„Lšy‘wBè÷Ýü¾de÷œsϽ÷ÜsϽ÷Û3û®µ×^{í½¿sÎ^ëì{î¹uç¢q{Ï;_žk:Örà’ñ:NÎÉa9fÄJ×3©vý|w?,G°ý8´Ç¨”†¾ŸçŸ *) àÛ ™´CÀ»cf±ã£CÔ3ñ¡Â¸€ô3 éuNtÄ«lb À9+8å”±¬œ–Ëö5ÊzÄ…Y[Ž<Êc}ª7ÊøÔ97­ äã®ñw=TxL›v‘ðIzn}ókŽ «‚^ää)ëWJܙРë™pëeü DšòÒãqRx–S¾%À¼¤vEç,ëÒzÍ›vÅ“JOmRJé©NíóÆhyÿ öZtM¶Û%ëßhlyP8¨y-‚š¬Ô·íõþŽ—Q?fî0÷küÞïS`VÒ"Ä €é¸$;Âq9Òƒ§®s^[¼¾IyÝéüìèÜû pP!úýrœñS¼ ä.3ÿÕI‹…‚Ñ~ÍMï"àÿ&0ñ΄ ”2ƒ‚N¶æ[FüaÆxý*°'»-ýº–Çò¡ž¶€ ß(\XiPÀ9iQ¡#޹—íï<صKÁ %nMj›R;Þ®:¦ãН?^ ÒEugOLFa=×c[×¼Tˆô¨^p1( \š§ tÊ̪¯ Z=ÇÀg”Ø·‚R.‚ ªî[ý™A" kL;r,ë¡ÚxÎG~ãußÀ€ Ó¸]||^[øqî ¸@1 å‚·!{…}ëgˆ²Å1pÔw h¡”ž©h*¼NxÍÈá+¨Ž×N¼Öš:k8pPñqâÅ©'¬+6=4æ¸ÏÀ€).V Ð)+Sõº(qW@mp1Aî¢â¢õÍ~!Àó\×®žŸºâuù~ÇvÇ^´ãäAÊÀ€ï*àC‡JÄ‹™ÎX‹ Hf–«ô £ú¥}îp&ϲ“èžÏ:wéäS‡O»ÔQмd¦F TŒ²/æÎeÀÄ-}tÖCò ”°L^òÎ{ÝûGCY/n¢]Ú- e€àdxNòѹ¨óP,)Sz9#Ð4T|DâE_±é±5ÇÀ€™ØòÀˆ1yf- RÛ´’Áˆ^buiƒwt Hų¬õÍ:oäàYÖ¹EÇ®úx>åñÃ7{xÜpPñ‹AŦm.î ð%CÂ^”êâIãâ­r¤âsºi}µ“÷u‚úJƒî08 ó`Sý踊ʡ§e!ëcJ˱μFT|Ô¼HT hEæ$Ä™ÇKŠ:q«XeQÕÑžÓÄãCg-ì#O™Êrè±,JÆräUojÆe/&: stæÌñxŠåÐÊðtDLüj_a(¥mc Dˆê.–eòMLšiœ˪㸅䑪^2Í3¶Ïã©ëÔÖÔ½8¨øLð‚S1 CH)>6IDATdŽN.+Ññ+åQN>¶Q[ÒTOu ´ÃÀ !‹Wð®ÚGš×GžœmUG*>ÊËòEz¬s2F :T‡eËR\ü*6ms#„Ï:bR:kòÌâ%Uë£,¶cë•"ŸÖI'•Ç6eø´}´kÞæ"à âcÌŠMÛ\ ȉÊÑÊÁò¸Š'eY:¢’KOmX/™(§Ï•<¾¬^l_LîÂ@ÀÀÄQ™‚(™²dœ£xÕ‘F™xR&ÖË9³,^”z1G»j/YQYu¤Jl§”Ç«ÞÔ#0TŒz\ì+6=Òæè”×®]»Ïñs²r¾Â´ß周“3FÀ$LJÊ.öˆ€œUfÆ®yÞtc„'lŒ€¨ í ;@t‡›[#`ºEÀ@·Èå´sL±€6¹Ú#P1*Ô@Å€Úœ0FÀôÃê {@½ Ð=vniŒ€è"ÖFß@€ ª€ã*#`Œ@Å8¨PšsÐPmÒ#`*EÀ@¥pî5æ ;P½ÐnneŒ€èZ,ìcõGèº9÷þnw-ÝÊ#0ZÀôýo>ë ÖÖ¡)ž€b|òj½‡ŒåFÀŒ¯ÜyçÛú=çZ8Äû=‘&ÙwФ£á±#`†—0âý(Ò§á×`ìëú4þFšuÐÝañ@w¸¹•0#‡À³ų– ûsuL¦)}8èîH8è7·2F`äXYÇŒj &MšôP“iJ<ÄC˜ˆRC|¬?°¥KFÀñC7C߯cÖµ?þø˜ÌÆ:&Ô„>äØš0–nÇrœøNêÓ1äµõ@Š”ËFÀŒ)×1ïZ€™3gîÁ¢?6»ÑIò ªyÉHÅ×qÀ³úˆýG>K·Œ,ÚÈãËØ±Ž0F` Ø´ Žy×p"øà¿ê˜PúˆN¯“ñ¨(ÛŠíÄ^–®ìŠÏÒKeQ?¶ë»më€9—€7°>0oÞ¼ZvÌk poAîû‹ šp²Dg˜å %ëf¬ÑvÙööõ#_¦?铊OÛź<´ËFÀq@kâMuͳ¶à²Ë.û&u]†~¢ó/ZfüEº¬+ª—}é”Õíb[ÉSuÄgé°Î;)2.#0flܲeËu͹¶€Â?§®‰ ²9º”v2&¶Uûví¢^äóڕщm£~ä©£2iäcûÈK'¶õæ€0ãŠÖÇ[ñÀ­uÍ¿ÖàCù7LlU]“T?ѦcŒT|ª«r»zéQÚ(cG:EúÒ)Û_‘~¬ó@¢®3F`ÄxkàµuαÖࢋ.ÚŠ þ}D_Ñ©‰'Ÿ7¦^ëóì¶“õ«:Rñ©½(|Ô‹íÅKWå¨oÞ#0fÜôõ¯}Is®5àÄV¯^}=ÈŠ:'Yw_ѱeõ]¶>«­d²¡rÍÓ£¼¨.ÏžäeÛ§zy}Ê®©0F` ؆µñoëžwíÀW\± »S÷Dëì/uri9k,y:yrÙȪϒI?²M™vy:iû´ûuÑž¿ˆ(™7F`Œ¸ú¶Ûn«åýÿÓÚvþè£þ Èq £ÆGÇç–'—N^}ž\íÊÒnì¤mb9òCZÖ¸(OëTΪS;S#`ŒÀˆ#°/þ¹jsHÀ7Nž<ù÷0aþåáH¦èÜ8ÁÔÉ©>oò©¾ôòäªÏ¢E}åÕ¥ý¤åØOj#–#Ï6i9Úñ@Dü0c€Àî={öü^ü³ysHÀ‰^|ñÅ+á þl“®£O:º‡­ÿï j® 8áK/½ô+ ßÔäûÙotl‘}æÉ£ù²z±Û”mW¤—Öµ+k Ô‹ºi9Î+«NvL€0£ˆÖ½ûÞüæ7ÏäÜ úyïø-ð£A‚о£ó‹öËÈót¢òeõ¤[V?ÕkWŽãj§Û®>Ú2oŒ@1éõT¬íÚ¦ ß÷“ƒ>øÃü:|chÀ‰¿ÿýïßr1òj–G%éÂŒT<çù¢9G½Èµ)SG[Ñ^»r‘Íh‡zeÊQ'í»¨/×#°?7³‹!âÖâ{ÿ n¹å–û¼0ß_vhŸ  s‹.«O†T·¨®H—íb}7娷ø¬ñÇ~òê£N™±¨?S#`ŒÀ °zÒ¤IgÃù/jâ\¨ .¸à?Ø?)Ùëkç{µ_Eû<ÞÎv™¹eéDYìÛ¶CÜõFÀ XË~øòË/¿kîܹ?hêx°óÏ?1~+ù.°µþEbKN4Ïft~ÔIõÓržvò¬~ÊØNuÒrÙ1§ý—m×n^®7FÀ4ùpþgâ;ÿFÿóm£ÔsÏ=wÅöíÛÜÙÀƒœ;¤,GIå(|Z—e8ÕÏÒ‘ŒºèÇvâóh–Ý´¿´,[iÛ´,=S#`ŒÀ"ð Æ<뤓NºÛþ|ÇM£ÓÁÝÄàðÁ—n¿ýöߘ6mÚ?@ôçÈ øéÜ´¥-GËâ³æ’êçéÙÈj“ÊÔO”§²´LÝ,Y–ûì‹üŸ¢¸-TÊthYN-KÖn¼Ý´)²™e²O× ZŠ–ËFÀ4‡&Ožü«xÊÿ‹¿ûº4”Q†£xåœsÎù'|%ðVïi:òtx©ÓKËœC–¬sËO^ÿYcê´}–~–¬sµM#`Œ@…l„­Olݺõݸë_V¡ÝÚM ÅC€E¨ðW¨?ï¾ûîûè—‘__¤_gïhEcßÝÊØŽ)Þ)G[ªOûŠånø,»´“%§,•«,Ç%‹õæ€0M@kÕ|ü…ý~õ«_ýYÆÓë†v ø{Þóžy»víânÀmiÝ ËYέŒŒ:YzÝÎ%Ï^VY2õ›U—%k§ŸÕ&K&;¦FÀ"ðnºÎÇwýŠó'–#p2Ø XuÖYg}Šï x²A¦,‡–ÊXNeyc®ZOýdÙ-W‘~^úŠT}ˆ².îlD]óFÀ °ëÓ§‘߆íþƽ˿W<†þ+€,Î<óÌqÀÞ½pá¡|:Çgéõ[FǦ$>:8Êb9êfÉUiž¨y#ÊŠø<ý<9meÕI&šÕgQ]–¾eF`Üð5Ó·3`',ÿ3ž1ûë›o¾yCßz°á‘ ˆ)(½ï¼‡~ø[;vìøc”ÿå#XWwâEÚ«Cϲ‘%ÓÜ:]¤/*;¤Y2ÕçÕ¥rÎ_²”Ê–©0!¯«ÎZZ;=ßÿ¡ù¶úWæèŒŒxd¡w¼ã[ÁÏZ°`ÁS¦Lù$œÏŸ |˜êûIé蘳œ–wýõ×/¯©ÏÆu3v€Ž€|ðþ®ò?Bþ9ÕWIéèòœ»œ`Zß©¼h¼²•§STϺAÖçÙr#`Œ@lÄz6wüÿxÓM7=ÛEû‘j2¶€Žâé§Ÿ¾ üÌÇ{ì »wïþm8bî LW}/TÎ3uî´)§šW—%ïu,Eí5ž<ªê‹ìÕåËr#0Îøš)}ô ¬¾Œuõ+H|.Ì Œ} ³à´ÓNÛ~6þvø†éÓ§_ þ“È|Ÿ@å‰mžƒï¥®Š¶[PÊÔgép¾’§´ŠqÛ†Gâu5Žóo3g>Ñÿm`ôElóß ¾ó§ŸÛt0ìÕ’#È¿†èæ%K–¼¿½üG‘§"÷œèüªvþ Jη¨M;ÖKG4µ'yJ³ô¤“Ö¹lŒ€èÐf.~Ê7ûºë®ã«ârp ŧžzê òÉ'?‹ïŒ>žÏ ð¯ˆK%96Q6JQ:¡NÚNu¤±>Ú‹:‘¯JG6ÛÙc½tDÕ6Ò¢º¨gÞ# À»ýïbœµú³gÏæC~NmpÐ VϘ1ã%ÙÌK—.}7(w.C~ ra¢SËsÞEu2ZFGº¢eiÚ£ž²ìgQÙÍÒ‘L:¢’›#`:D`%Ö‘9¸Û¿wûcÿP_‡Øù€N;å”S£ÍâgŸ}ö¶lÙr!øßE~ré`JŽ//0€­}wÌE:Òk§C½¼¤±äÕ§ò2úÔ‘ž(Ç(>ÚÌÒõæ€0 ë±ṅl.œþw@ýÝ~PÙbi§UÖà¸èwÜqÛ0×yÌË–-{#è…þ>辯èܰõ*È[u­ÔÎa³];*Òc]ÙDÝ~ëk¼ôSvüÖ3F`äØŽÞ‹uqîêÕ«¿9oÞ<¾«ß©Gô ›ãWÏ|‘ù©§žz;þ‡ÁùMtxxpŸƒ¥cg@ œ=õ{uþ´©Ô©Ã¥~'m¤ß®M¬_¶­æbjŒÀX!À›¬ÿÄzxÇÖ­[¿‰7õñ«X§ pP!˜4uòÉ'?ÂüO?ýô©pþ øÅ¿ÚJr€ äìIPIò½-öªm^ý~ÍýœÚì—´çÔF´}‹½ÔW¦¤“öè–õŒ€*¶amã¶>wW¿ñ¥/}iÓP~Èë ìøã_óÌ3 pg€Á<ùÿ¥è0)0r'Ž_mHe[4ÖµãÙ¦›v²«¶eìHWmM€yÖẟ|ÇæÍ›ïÆßïr»ß©Ô2»@0 O#8¯¾b>Døëȇ ç¦<§ØK0g3wl§LQY;QO¼ì¨Ü®o×#02ð÷ùtúwâïÚï÷Ïös\ w<ù[Ï à×Gáß ÏÁ…p:‚וR–ãÌ’Ù£~§mR{ÑFäS½vå^ÇÑξë€|ýîb¬qó±úïW_}µ²7°C±¿cû±‡_¬CÇ­_À¼víÚ3p‘¼2æ·#OFî(E'ù"#r¾¢Eºeêd'ö/™Ú§eÉM€zøFÕ ó¼ßÁ¯¡À÷ù;†~V#6 : pü»1œû'ògñs—©ˆ–OG™»üÊàä®’œ­²ÊYƤÃ:ñEúY6òd²§úX޼êM€VàæOõîݹsçw¯½öÚ‡fäc:P >ðÇsÌf 4óÇ7nÜx2.°÷âãsÌo@î)Éé’2‰æíT_vÚÙ•ž©0CƒÀJ¬EàåûñLÓ½³fÍzfhFî¶p0D'‘Gù†Ë|‡½aÆñüÀ™`Ï@æW]ï í¾$'OAä÷)$LÔOÊ”WV]KÉFÀt…€®³®wÞˆwø‹Âáß}ÕUWý´snÑ$4éht8–iÓ¦ñaBæ¹lºmÛ¶Ÿ–™_Ì@ž„ÜsÒBCªÜ³Qˆ¶"_…mÛ0£ŽîÀ[×PæÉ‡ö¾kòAÞåïÞ½{á5×\Ã畜F#t0;ì°•˜óNkÍš5GL™2å4\Äg Ÿ‰ ™AÁëYWU’Ó&eR¹*û¶cŒ@-ð/t"/B~oÞû?´W îíÄÀ@áïoçG}4_É‹šyœóA/¾øâŒÉ“'¿;ïD@À_¼ ùÕÈ•¦4 HËìL2uÌr*S©0•!ÀŸàñ ýGp½}ëÀCØÎ__™u Í¡ê} ¸Ðy›¾t"ßL‹X^·nÝtlñ½}" `PÀ?4jûWÇl_6Áv¦s·Ó/‹ õŒ@WðÎþf\ƒtø}þóŸ_Õ•%79ŒÜ!ílBXv£…^YÜz–€AÁªU«f€þ2w~™ôXä®ìtÕÎŒ€(…À&\ËOà:û!´úÔ{tæÌ™~—~)øÆSÉÀx÷ÂYO?‚ó¾´råÊix/Á[!x ò©ÈÜ-8 y*ra‚ÍÌ€ÂF®4Fàpí‚sù ð¼³gðþ¾Ö[ g¿çeŒ@´ÈÕû8á„6 ´p"·*°Mzæ™gÞ:oû:‹ÒtTp÷àУ[Jø@Y¬©0íà÷Ë—âšú1y|M·/[á÷æ·ÏåpP'kå €Å‰w+&ò·£Ú’%KŽÂ¯f`áb0ÀÀ€‰|ÒD> ÔÉŒ3ü©¯Ÿ /G^†ëiÞíñäg>ó™5(;¾"pP_­Û¸ÈAàñǾ£<¿F8;'â«…õS!k=kÀ]eš¯Ý„¦”56R%‘å^ø^ÛǾ«´Õ/»Uޱ!¶øt=_ ÓÊ8ÏWàü^sžŽÿ§Þ¶çQr…¼ûÍE`ñâŇM:õX윈…³•qgô hp,ÈŽ?™NH™ÆÄ“ÖYV_­N'>4†´®Sy¯ícUÚê—Ý*ÇXƒ­]èc-°x´µ †óó8ùVsû8x~mæd‰€€FªåË—OÙ´iÓq»ví:z¿ˆøXdoÄÌ݃7"S6y߸xR¦ªÊ²Õ2:ñ¡>ÒºNå½¶ýUi«_v«c¶6bŽÏÁÆ >éПǹբ?àôiä|O”†Ãzä<î¶,X°àh,Öüä㰈ƒüð?ʇeuX>t_P€ò>žò¢²êZJj“Öu*ïµ}ì¯J[ý²[å3lñnœ¿ç];¿c'¿çÁZRÈèðÿoÁ{ŽßÏ;‘FÀÀH^O®,÷ÜsÏ‘¸£{~Nõz8¾.ù(8„×!…òQ XÞ—Y†üHÈZ]ˆª¿Xî…§½^ÚǶUÚê—Ý’cÜŽþù”<óúÈã˜´äØ†_c´»D«@×bÇh œúNÚw2F`/|&.¸ýöÛ'~øá¯…Ó™'tˆ#@LEùµ09 ™ïG8å#à„(;ü¡àY~5xþ‚:‡ =õù«œ×‚ÙŸb¹ž{iŸ×¶Ým¨ßŽüÚïÆ¼é°w#¿D9ÊÛð@ÜKpØ,ožóÁ9ñ›¡³ Øn^›‘7]yå•´édŒ@8è@77U#p×]wMY¿~ýáøs'S·oßþ*8ÁCñó°×àŽ¶Å#Ðx œâ«à8§À)Ç€6‡@¿õr&ÔŪ}<äAïÀHc_m‹á]öŽeÞAoa-ÚïD¹Å£¯Gk˲íxømè®}ìc›[–üaŒ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ@üÚxÍ3žÄIEND®B`‚ic05 5ARGB…,[†­ÃÌÕÕȦS$ŠB´ïùý‰ÿüùê¦/…uôþ‘ÿþîXЗÿ³€m™ÿQ•™ÿ|q™ÿlp™ÿlp™ÿlp™ÿlh™ÿg!û—ÿ÷!T™ÿ9š™ÿu™ÿlq™ÿlq™ÿlq™ÿln™ÿj1þ—ÿü1.þ—ÿþ!‘™ÿˆv™ÿsl™ÿql™ÿql™ÿql™ÿpB™ÿN˜—ÿ”OΓÿÆG…2~¿ñ‹ÿê³t(‹ B\rˆˆ—“ˆ„nW<†…UKZcgeecbcaaZSNUŠhsffz™¥¬²³³°¬¢—‡p^\^Q…tbvž¼Ã¸—fZW‚in´“ë^W€zcÀ•ûVU•–ÃÀe©³±À“à ¾¤‚W«¹Îļ¼ÂÃÁ¸¦œt]W«¸ÅÚæÝɾ¸¶¹¼¿ÀÁÁÀ¾¼¹³©£žwgb]W«¸ÅÒìöøðæÛË¿¶¯§¤£¡ž˜‡}vqlgb]W¬¸ÅÒëöøòìÒ¶®©¤ž™”Š…€{vqlgb]YªµÅÒèô÷ðéÒ¶®©¤ž™”Š…€{nvqlgb]UsqÄÒåòöíäѶ®©¤ž™”Š…€{vqlgoTU—ÃÉÜïôéßж®©¤ž™”Š…€{vrƒ¢À„d¬®²ÂÃÇÓÖÓ̶®©¤ž™”— ­¿Ã©W¬ºÌ¼¹À‚ÃÂÀÀ¾¾½¿Â‚ÿ¯ €^W¬¸ÆÝáÐÁ»¶»¿ÂƒÃ¾º³©¢šjb]W¬¸ÅÒìö÷ëáÒĺµ®¨¥¥¤¢ž˜ƒwqlgb]W¬¸ÅÒëöøòìÕĸ®©¤ž™”Š…€{vqlgb]Y¬¸ÅÒéõøñêÒ¶®©¤ž™”Š…€{vqlgb]Xz}ÄÒæòöíåѶ®©¤ž™”RŠ…€{vqlgeVUކÃËáðôêàж®©¤ž™”Š…€{vqv“ºzc©§¹ÃÄÍÚÛØÎ¶®©¤ž™”І‹“ ±Âô›[ªºÃ·¼Ã ÄÃÀ½»¹··¶º¾Â€Ã»¥•cXª·ÉÛÕý¹½Â‡Ã½¶¨¡”tb]Xª·ÅÒìõîáÑ·±­«ªª©§¥£¡šŽrlgb]Xª·ÅÒêöøòìÙÍÁ·°¦ š•Š…€{vqlgb]Yª·ÅÒéõøñëÓ÷®©¤Ÿ™”Š…€{vqlgb]Xÿ·ÅÒåóöîæÒ÷®©¤Ÿ™”Š…€{vqlgb]‚ÅÒãñõëáÐ÷®©¤Ÿ™”Š…€{vqlga…àíòçÜÏ÷®©¤Ÿ™”Š…€{vpl‹ ÛÍ·®©¤ š•Š„††…UKZcgeecbcaaZSNUŠhsffz™¥¬²³³°¬¢—‡p^\^Q…tbvž¼Ã¸—fZW‚in´“ë^W€zcÀ•ûVU•–ÃÀe©³±À“à ¾¤‚W«¹Îļ¼ÂÃÁ¸¦œt]W«¸ÅÚæÝɾ¸¶¹¼¿ÀÁÁÀ¾¼¹³©£žwgb]W«¸ÅÒìöøðæÛË¿¶¯§¤£¡ž˜‡}vqlgb]W¬¸ÅÒëöøòìÒ¶®©¤ž™”Š…€{vqlgb]YªµÅÒèô÷ðéÒ¶®©¤ž™”Š…€{nvqlgb]UsqÄÒåòöíäѶ®©¤ž™”Š…€{vqlgoTU—ÃÉÜïôéßж®©¤ž™”Š…€{vrƒ¢À„d¬®²ÂÃÇÓÖÓ̶®©¤ž™”— ­¿Ã©W¬ºÌ¼¹À‚ÃÂÀÀ¾¾½¿Â‚ÿ¯ €^W¬¸ÆÝáÐÁ»¶»¿ÂƒÃ¾º³©¢šjb]W¬¸ÅÒìö÷ëáÒĺµ®¨¥¥¤¢ž˜ƒwqlgb]W¬¸ÅÒëöøòìÕĸ®©¤ž™”Š…€{vqlgb]Y¬¸ÅÒéõøñêÒ¶®©¤ž™”Š…€{vqlgb]Xz}ÄÒæòöíåѶ®©¤ž™”RŠ…€{vqlgeVUކÃËáðôêàж®©¤ž™”Š…€{vqv“ºzc©§¹ÃÄÍÚÛØÎ¶®©¤ž™”І‹“ ±Âô›[ªºÃ·¼Ã ÄÃÀ½»¹··¶º¾Â€Ã»¥•cXª·ÉÛÕý¹½Â‡Ã½¶¨¡”tb]Xª·ÅÒìõîáÑ·±­«ªª©§¥£¡šŽrlgb]Xª·ÅÒêöøòìÙÍÁ·°¦ š•Š…€{vqlgb]Yª·ÅÒéõøñëÓ÷®©¤Ÿ™”Š…€{vqlgb]Xÿ·ÅÒåóöîæÒ÷®©¤Ÿ™”Š…€{vqlgb]‚ÅÒãñõëáÐ÷®©¤Ÿ™”Š…€{vqlga…àíòçÜÏ÷®©¤Ÿ™”Š…€{vpl‹ ÛÍ·®©¤ š•Š„††…UKZcgeecbcaaZSNUŠhsffz™¥¬²³³°¬¢—‡p^\^Q…tbvž¼Ã¸—fZW‚in´“ë^W€zcÀ•ûVU•–ÃÀe©³±À“à ¾¤‚W«¹Îļ¼ÂÃÁ¸¦œt]W«¸ÅÚæÝɾ¸¶¹¼¿ÀÁÁÀ¾¼¹³©£žwgb]W«¸ÅÒìöøðæÛË¿¶¯§¤£¡ž˜‡}vqlgb]W¬¸ÅÒëöøòìÒ¶®©¤ž™”Š…€{vqlgb]YªµÅÒèô÷ðéÒ¶®©¤ž™”Š…€{nvqlgb]UsqÄÒåòöíäѶ®©¤ž™”Š…€{vqlgoTU—ÃÉÜïôéßж®©¤ž™”Š…€{vrƒ¢À„d¬®²ÂÃÇÓÖÓ̶®©¤ž™”— ­¿Ã©W¬ºÌ¼¹À‚ÃÂÀÀ¾¾½¿Â‚ÿ¯ €^W¬¸ÆÝáÐÁ»¶»¿ÂƒÃ¾º³©¢šjb]W¬¸ÅÒìö÷ëáÒĺµ®¨¥¥¤¢ž˜ƒwqlgb]W¬¸ÅÒëöøòìÕĸ®©¤ž™”Š…€{vqlgb]Y¬¸ÅÒéõøñêÒ¶®©¤ž™”Š…€{vqlgb]Xz}ÄÒæòöíåѶ®©¤ž™”RŠ…€{vqlgeVUކÃËáðôêàж®©¤ž™”Š…€{vqv“ºzc©§¹ÃÄÍÚÛØÎ¶®©¤ž™”І‹“ ±Âô›[ªºÃ·¼Ã ÄÃÀ½»¹··¶º¾Â€Ã»¥•cXª·ÉÛÕý¹½Â‡Ã½¶¨¡”tb]Xª·ÅÒìõîáÑ·±­«ªª©§¥£¡šŽrlgb]Xª·ÅÒêöøòìÙÍÁ·°¦ š•Š…€{vqlgb]Yª·ÅÒéõøñëÓ÷®©¤Ÿ™”Š…€{vqlgb]Xÿ·ÅÒåóöîæÒ÷®©¤Ÿ™”Š…€{vqlgb]‚ÅÒãñõëáÐ÷®©¤Ÿ™”Š…€{vqlga…àíòçÜÏ÷®©¤Ÿ™”Š…€{vpl‹ ÛÍ·®©¤ š•Š„††ic10c‰PNG  IHDR+ƒsRGB®ÎéDeXIfMM*‡i   ÓÝê@IDATx콸%Wuç[s¸·s·Z…V"H 6j¢¬¬D° ÆolfülŸŸ'x‚=ý˜÷ÍûÙóñÙóÞx4öð3Ø4 $! ›$L0„r+¶Ô’:ªsέ·þ¥^W¥ÓçÜ{B…]»~ûûö­:v­ýÛuÏ©õßkïJ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @ &ãbª u „DàÆoœuâĉ‰²iÒ¤IsŽ;6þÔú–¶o¼¥9ZñÅuÜ,­ŸJZOÏõ -ËñvNznËö‘ãÆ›jyÚȆ–•“'O±M[6·~ÜgeoÝèŸmßI³c¶åAÛ¦r+ÿ„ Žiýøñã{í¸Z·´K¦OŸ~rÍš5Ùsµ™@€@A K±€ [n¹eŽ9¡=:gòäÉSÌnøLsÀ'™¥sÍYdŽ«œîi¶oª-gÙçtŸ-'Û¶¶mºå)–åxkßlËJr²uŽ’Ž›œ®ñ§ö:á¨-œZßoK‰ ü˜C¶~ØÚe¯µ›¶í¶vk9ïÔzêà[mçœÊê]W/; !а†½–wg–;m=Ívoï´û|§–vßï´!;M8Ø9uêÔ6üAÑ $@€@iJCÍ… ÔžÀ¸U«V-0G~91 ̉YxÊqÏ:óÃVKõƧν­ë³‡Æ×€@Î4ÔA" F„ ´´ýÚ·Ýò›CbÛÁƒ·ßsÏ=çdÈÙ>Šƒ È DÖ T€@/V®\9uöìÙÞ3¿ÄÎ]jN‡ø‘uÛ¦žy}^n™yƒ@‚@Å4ta“åÍ–5$adÝþwÓÏm°YëwÜq‡ŽyÑ2 € p@ˆŒÀÇ?þñI[·n]lÕZnÎübsÎ0g@½õ‹íóB ÁŸ¯í¶¡eMXG‚â% ±`›ýÏKئlŸ·ÚwÂû.ØlËöyã¾}û6[dŽ%A€@Ä"n\ªÄGàºë®Óú¥–Óz{xO—öPŸ.­ÆZžeyB|µ§F€@Á$x4Á&û^yZ¶iiß7›8ðC nЇ P €áR4 n ¨×~óæÍgØñgžÊKm)G™=xË©×>õÚóz9ƒ@‚*# ù¶Ú÷ÒF$R™…\€:@舆€ò#pÍ5×L‘3?qâij­Ô¥ê¹·‡e­{–ã?1¿+R J h.‚§-{ÁÓö÷´}>m“>}×]wi? €J&€P2p.ÄI šo=ag˹×Òj«ž|õà¿Ú2ß¹@Àøp‰j q  ìM#O_~ùåëW¯^}R€ /FóåIi€@¤¢¿eË–³Ì±?ÇzïÏÑÒªª|®åWYf2=ƒ@‚  ÏZ–@°Î‚u¶|Ê¢¨Ö>|øi†  > ôS 8 dÃô[zñ/¶¯°Lˆ~œMO­ úð!éÐ3­ ³Lš4é©5kÖì©_u°€@9ÊáÌU @œ Õ?W=ø§zñÏ5gß{ó®O‚ zЫ109`à ÖY~ê¶Ûn{¡ÞUÃz@ƒ@ŒgC¸ñÆ—šƒ‘zò-_¬u3Õ'Ü ÔjÌ‚ ‚ (:à)ËZ°Öò#š˜p÷îÝØë 5ì€@ jQ7/•ƒ@Ün¹å–É<ÃÆ„^lãò/²‡¸‹ÍÙ—£¾å™qמÚA€@ŽŽYYÏ[N‡Øo‰&&\k>hó ìÍñ:@ R•âçâ€@7¶oã:Óž|;>íÕ·¥ÆåËÑŸ`™@(Š€æH£$ ˜Ø,aà{•á3¶ýÅ¢.J¹€Š €PUÊ„ú" }›Ýù<{¸ºÌ £/'ÿ–÷U 'A€Š# È€'mˆÙZû½º×–=zô‹Ð$@A@²Y0 ñ85Fÿ²L辜þ ,¿öÔ€"&°Ùêöˆ†˜  Ì1qkS5ÔŒ@Í s!P7§fÝ×$|i¯¾Ù¯^ýK,Ϩ[]°€ Ð'ãvÞs–5”à^Ë©@pçwê3à  (‡@9œ¹ ¢'`áû,|_=øo0gÿ ¶|Ý©Y¿ª`1 P€"¨R&$pÍ5×Ìž0aÂåÊ/G_¿ò‚MÅ$4ŠÀ”)S{`Oëlã|Ó¥>Ožü½=|džì|û®»îzÄìbŒM ƒè–@·¤8%¸îºëζqÃï2åý§ì²o³ܳJ¼<—j89ër굜9sæ+ÖõYN¼öÍž=; ¹o8.ª H Ø¿*8p`d]Û³Ÿ÷íÛ—[(Ü .—ì³…Þ6ðu[~oÉ’%?¼õÖ[_šÔB€@°‚m k [n¹e‚=ĽÞêû6sø=¤~SêO=Ë! ‡^Y¼gõÚ{ï½BðÝé/Ç"®A@óHPA6k› ÊúlŽ[&Pfs ìµ{껊0¿hÑ¢!4÷f æá@·m°,^ã,¤ÿuöù.«âÛ-«—Ÿ ûâmïBk¦‰ìÜ¡Ÿ5kÖȺoÓR޽ÏD_¨1Ô†€œ Ð*øgE Ð'M,¨W~Ë:8¾f¿W?^³fÍèïíóBœtO {V ¾ ˜Ã¿Ì~üÞmYN¿ò¢¾ ãÄÆP¯¼Âì•åÜg|9õÚ®ñI€Š" ×3J ð-í•qé6_j ]ØmÇ|Óò×,ýŽ;îxª‹s8È™@Î@)"pà 7L·þ·Øê»¬—Eÿ,óÿfH/Ð8ú9sæ$sçÎ Ï׺òÐÐãë_FÅ 0½ÝÀ#$ìÞ½;Ù³gÏÈRBÍ$p 0­"zÍàw­sä+öÌt—½e`GEvpY4ŠI£š›ÊE@ãøm¦æ+N…õ¿Û®ófËtͼå*äÞ{ï})gß{óµ´û¥5ÁD@ƒÐp 3( 1 ›}›" H& …è'–ð5{cÆ÷ï¾ûî#&Bå!P€‚ÀRlü|¦~«©‡õÅ_kj˜%`ïENÇÜÏ›7/™?þHo¾}eëÕÈÎ: t  ¹@(ŒÀhâ€DE¢'°Íž»¾jm}§Õô«6€^AH‚ú €Ð4NiU«V-´°ÄkíGç:«õÕ–g5§öÍ©©^‡§^üááátü½Ã×R³ì“ @ L:°k×®‘è­+ïܹ3— L«±j@z5Å·,ßi‚À]wÞyçs–Çéh€F57•톀Màw±w½9ý í_iy¢eR4s¾Bõ=d_¾>k; €â" É %ìØ±#Ù¾}{ºÔp}fΨÚúi4‘àr%&”ˆªy©LÞò&Jyµ#°råÊ©ÎýSÖƒ9ý7[ά]%0x„€&ßsÇ^KwöÕ»Ï+óF0±@ ±ôFMD¨áYa@ë¼Ò°ö·…Þ$ðM{žûŠå;lî&¨}“R¼ äM”òjAàÆo\j†^oбzúßiëÓka8FŽ˜2eJ²`Á‚‘}9øÊš]Ÿ@臀 P”€–¶mÛ–”`Ë–-iä€u8„f*ö¼’@:o€mZc“~÷•»ø¸ à Åݾ¬ÍÜ¿Â&÷y¿)¼ï3oh$„À+­™õ.\˜:øƯ¥ÂúI€ :PT€†hè€gE (Š€$'ì™ñ 67ÄM øIbr$€#LŠªŽÀu×]w¶MþvƒY žþ·Vg Wn% g_νÂ÷Õ«¯%áû­”ø @±ðhE h(–L:V«›ð¬ ·›UŠ øž- 嫉°&9@¤ˆjèu}öE-‡_ù¢j¬àªYêÁ×kõpö³TX‡ ´'€(ОK [Ÿ·¡·™-k.»ì²ï¯^½úd va"€0>N.›À{ßûÞ3,¼_¡ý³|IÙ×çz/ gÿe¬A€ò" Q@C|ÒAE è3©RM ø¢u<}ÊÞ&p_¥–pq H`@€œ^<›o¾yî‰'Þg_ºµ«ý´eîÛⱿ⠓&MJÃ÷—.]š,Y²$íáçu{¯@Ä@€@a4T@Ã6oÞœæM›6%GŽ)ìz<*Ÿ˜ðö\ú9¶Žz$;! ©“,¦ÿ–[&=zôíÆâ£ö%«W÷Í€Ky4ÿgœ‘,[¶,uöåôÛ åÀ• @•ÀîÝ»“7¦s øœÖa2ê9ìÌ•€†üƒåÏØÈÏ®Y³f®¥S "€PXŠí€ÆõÛ{ß?bNÿ/Z û+…³z!à¡üîð«—Ú´i½Á±€ TL@o ,a`Æ L2X^›²K}Å¢þbÏž=wßsÏ=ÇË»4W‚@ozãÅѸ馛–ÛŒ«?k_šÿ‹¿¢€KPä)Æ8™_N¿^ǧí$@€â"à“ º qÀæRŠ«’áÕf“ud}ÁÌú4¯ ¯q°ˆ±ÔܰžþéÖÓÿAû‚”Ó¯×öáÐ ÛWøþòåËÓp~…ô«ÇŸ@€@óÈùפ‚Ï?ÿüH”€"H…xÀJþsšñ™»îºkWaW¡`ô@§«X:8o¼ñuVÊÇ-ÿ¼å9ƒ—H Yš¬O!üêÙ?óÌ3Óžþ‰'fa€ ¤,32 A@C”™\°›ã°E[®±Ž¯ÿn~¯+P(º$€Ð%(ëŸÀÊ•+§ÚŒñ7X rüßÕIœÙJÀ~õìËéWf²¾VJ|† @ [š\ðÙgŸM#´Ô0R®7!àÏ­Ä?³!Ûs-™Â Ѐ. qH,Ìÿ óÿ˜}Éý’•0¯¿R8+KÀf™M{õÏ:ë¬4¤_½ýÆ8{ë€ @ 7þ¶Í#ðÌ3Ï${÷îͭ솤÷8Þa‘·Þ~ûíß°õ΃ê—D $ÐM¹ŒÆö[]?`NéÇÍñ¿²)õ.ªžêá×øýW½êU‰œþyóæ1a_Q°)€ 1 x„Àúõë“çž{.9|øð˜çpÀèLx؆cÜjQœñå/y÷èG³ƒ@ŒgŸ"@o>·‚fã׬üîðÒŸWJ @ ÖÙ“¼ð ‰Ä6À[✠øú@%q2:@è†ÍcX½zõøûî»ïöåÿvôu–¹ŸÆÆvÚsçÎM{÷Õïfª¢&ö[“ÎìU‡‰fé—ï<44Ôù`ö@€ tE@Ñ.hþÞ,0&¶Mvĵár×]wíóhh4€F7ÿË•Ï{Þ3ÃfŸÿ%Û¢‰ý–¼¼‡µ,ŸÀÏCû§L™’ÝÍ: @€@ŽüÍO=õTòä“O&ûöí˱ôèŠÚosuýOþ¯¿ù›¿Ù]í¨P.rÁXßBlb¿YÖÛÿ«öeñ¿[-Ô·&ÅY>sæÌä¼óÎKÎ?ÿü´Çßxw1J† @èH`Ë–-ÉO<‘<þøãÉîÝ»;×ðûíyõÿ9zôèÞ}÷ÝÛ΂ê·À“iÒ”·ÜrËÌ#GŽü«ï¿±¼¨)õî¶žrúW¬X‘Nà·|ùòDáþ$@€ phÞ =öX²sçÎp Ç’ÖÉ÷g&üÞwÜ¡a$0 `ÓîõøÛÁÿjõþWöeÀ«ü27ÀìÙ³S‡_=ýË–-ãU}6¬B€ d'ܸqcȦVaÛ»è§í­^Ÿ°W§ŠèšDÔEšâŽ¿9ýãÏlu§`ãôy×Q6 @(ŸÀž={Í èÞ(ð þGíÓ§&Nœø¿ô¥/mxÅ>4†@äM½jÕªy6yÊošãÿëVÕÙ‘W·«ê §ãùâ¿pá®Îá @€ úصk×Èœ[·n­_бø°ûg&üg„€b‡\*@È­3€m6Ʋñÿ+bµå¹Å©ö†ƒÔé¿è¢‹ï¢E© @èÀŽ;ÒùÖ®]Ë‚/¡;jCƒÿd„ ÿáË_þ23*öv;Õöh€Ú6]GÃÇY¸ÿûmï¶|vÇ£°ÃTÍ䬳ÎJ.¾øât&òk@£SE@€ 0szÍ !>úhrèС1Έ{·ñÐ Š¿oQß´·h¾RÄ"jÜ믿þJsrÿÀªô–ˆªÕSUl¨C²téÒ‘ÞþiÓ¦õt>C€ 4‡À‰'’õë×'<òH:o€>78=iuÿwöÆ€/ØòÅsˆºê4¯õøŸoÕø–o‰ :}UAãú/¸à‚´·îÜÆxè‹!'A€ &8|øp 1 á“þÐ:Õþåí·ßþ&ß±Ö Æ-kŽÿ"3µå_²<Ñr£ÒôéÓéW^´H(H€ @œÀÎ;ÓáôV&E|Á¢‹ÿͰ®õ¶Ê5lÚn¸aº™ýë¦Ìý[[6nf9û¯ýëÓÞ~ó'A€ @ š/à¹çžKxàäÉ'ŸLNžŸ³Kž]âe ¿”&ó{ík_ËŒþ…“æ€ @18vìXòàƒ&?üá“ÄVÕ=ýOo¿ýö¿Ž­buª@9­¥‰þþ¹]êÿ¶ÍÔ÷îø¿ùÍoNf̘QI®@€ È Ä,˜ðÖ)úÏ,à`äÍdõ n–U«V-´ü³1Môgï÷L.½ôÒôu~Ó¦M+˜ ÅC€ @ ™$hhÀ~ô£äàÁ¨üåmøð-·ÝvÛÍlÙêjP û믿þJ›å]bY—)­hõøëU~—_~yby”v].@€ &p!@C"š#`u’~Ì"¾Üä¶-»î·ÿ[ÑlyrA—(­X ÓIV¬X‘¬\¹2™={vi×åB€ @€ÀËäük¢@½5àøñã/ï¨ïši/þñ¾}û~ëž{B¡7@Î-d¯÷›nó­VìÏå\t%ŽêU¯J®ºêªdáÂ…•\Ÿ‹B€ @¯$°{÷îä;ßùNòøã'æ@¿rg ?™ÿô {‡ï¾ûîm54¿V&#äØ\Öë¿ÔŠ»Ýòs,¶’¢†‡‡“Ÿú©ŸJÎ?ÿüJ®ÏE!@€ Ñ lÞ¼9ùö·¿<ÿüó£X½ÌÌï¸ãŽûêan=­DÈ©Ýì—ØdwXqËs*²’bfΜ™¼å-oI^÷º×% ý'A€ @axöÙg“o}ë[ɶmõî@·h†6‡Ú‡íUw†M¼¾ÖááåÐv7ÝtÓûífý´5=‡â*)Bü]qÅéZ'A€ @õ!`‘É<|ÿû߯ûNšoõ[69à'ëC¿>–" ØVæüÿ¶Ý ÿÉŠ©-Ë .¸ yûÛßž¨÷Ÿ@€ Ô—€& üîw¿›ÜÿýuŸàOìõã¿¶fÍšõmð,¯­ÓÊqæüÿ¾9ÿÿ"[ú2ahh(yç;ß™¼úÕ¯îë|N‚ @€Â$ð /$_ûÚ×’M›6…i`VÙä¯Nž<ù½&êâpé‚@Z¹å–[&9räÓ¶ýC­ûêðY!þW^yeòÆ7¾1™0aBLÆF@€ @ GÖY™<ôÐCéDŠ ¨c2à~Vš°§Žö‡f3@-b3ýϲS¾dù]=žÄáguVòž÷¼'™;wnö` @€ P,$ßüæ7“Ç{¬Ø Tº‰­ãòò/}éK› ºDcŠEè¡©­ç޽ŸònSÒ®ìá´ µñ3ÉUW]ÅìþA´F@€ @ |O?ýt:,`ïÞ½å_|À+š°Ï"Þ`‘O XT£OGè²ùí5sOœ8ñ·vã]Ñå)ÁvÞyç%ï~÷»“3fc†@€ @å°¡Ìé€|°v“š/vxâĉoùâ¿x_ùäâ¸"@íXWçß²dåÊ•Éë_ÿú.jÉ!€ @€@S<óÌ3ÉW¿úÕdÿþýµª²‰ÇÍϹÚ"¾Y+Ã1`Œ†¸îºë†l¼É7ì°KÇ84¨ÝšÙÿg~ægxµ_P­‚1€ @‡€&üÆ7¾‘¬]»6£º°düøñ'MøÀç?ÿù/vq8‡d0|FëªM–7ÃÆÎÕ¶_Þº/ÔÏšÕÿïxGš5îŸ@€ @  §OV¬X‘Ì›7/Y¿~}bCžÛÜ6›“mœå÷_zé¥O?üðÃg`À!th½êÏÂK4ÛÿÛ;ÜæáááÄìNÎ=÷ÜÄlÎ> ‚ @€Â#0þü䢋.J¶nÝšÔe‚@‰&X¬zÃÞ°Ã^uøáQ Ó"€6íbNô›ãs¶ë¦6»ƒÜôš×¼&YµjU2{öì íÃ(@€ @ \оøâ‹Ó‰7nÜ®¡ËN‰×Z$ÀA‹ø~f« ´c³æÿWÛü mv·Ia;W_}uòÖ·¾5Qø? € @€@?E|ÖYg%K–,I4IàñãÇû)¦ÔsLhñîË.»ì€½Ù` úxŒ-€n¼ñÆß°M¿Ó²9ÈêíßûÞ—œsÎ9AÚ‡Q€ @€@ý %^xa²aÆZ¼%àäÉ“Þc‘/Úp€o×xy#dXßtÓM×ÚÇOYŸÙäêÙgŸŽ÷×?' € @€@ž|H€^øÂ /äYt!eiC{;ÀÛ/¹ä’#&|·‹DP(À©F4çÿµ¦Ým§†Þ®o|ã“k®¹&™4iRè¦b @€ PSæP'6<:‘ðì³Ï_ Y°aÑï2`‰?Þà D0è7ß|ó\sþ¿e«‹+hƒ®/©Àw¾óÉ•W^É,ÿ]Sã@@€ @`K—.M”Ÿzê©à_¨H›'íê׿þõÏ›pß õŽñ\€$gï¾ü+kÜ+Cn`©nïÁ„l&¶A€ @˜;wnúºñuëÖ%G º†6'À8‹–¾ÎÞ”v¿½à‰ -Ù¸Æ 6éß¿4æ¿^2÷ž.7cÆŒäø@ªºõt"C€ @ȉÀôéÓÓÉׯ_Ÿ|8ù⿘lÚ´©jSF½þ´iÓ4`³ xÓ_ýÕ_=?êÁ ÙÙØ€[n¹e¦ÝgíÛÝ™ñÕ¸!6^eµ5ãò›rhh(yÿûߟLž<9Dó° € @€Ài&L˜X”urÆgœ¶/” GޤÃÿ'š=ŸûÈG>²0»Ê¶£QÀu×]÷S}‚|å߬Y³Ò1ÿzå € @€@hbÀ÷¾÷½‰"šCLŠФ€––ÚòÏB´± ›š$Œ³ð”?6¨R}‚Jêñßûޗ𪿠šc @€ L™2%hVçfˆI¯/Ôœ–®·a׿¢EÛÔà†nøõþ¯,h¯å›M‰Ù–,X° ×S9€ @€@PѬH¹-ÉùW$€’ùaŸüèG?zfh6mO#€ü㓬?Q4Ì~ÊÇ;Þ‘œ}öÙýœÊ9€ @€‚# a×_½œìàl;5€ìšmbÀŸg`Á5â-Ë–-û%ãø ³ì¹ø .¸ Y¹reÏçq @€ ''OžL6lؤ™š¸ÐÒ9_|ñcöjÀG‚4²£¢ìµS¬q¿`ì‚zíŸþ!sêÆ+ i)€ @€@u–/_žlÞ¼9Ù½{wuF´¹²„‰S¯ÔÞ7_xá…ÿcíÚµGÛݦè‡XÃþ²µZP¯ýÓ ™7ß|3¯û‹î߉ A€ @N@C¬C6 íMgš àèÑÿ óÏþ­Ûû2j`õêÕªßo„Öˆo{ÛÛ’yóæ…fö@€ @È•€œÿ«¯¾:×2ó(Ì'묳’çž{.È*Z4ù/™aQ axÉ96ûG>ò‘ m"‡9_B¾ôÒKéýϱ}) € @¨?K.¹$Í}Æ¢¯ýà?øš–mQ|Œ.`Μ9¿¼cÇŽ gòäÉÉù矄-@€ @ gžyf244”ìÙæP{>l¬þ](¼ò²#:àäÉ“7…þî¹ç2ó^w*å@€ @ÑPÏû\üèG? ¦NæKfm‘ðï-¿â5Ùê¸Ý€£Gž) „¼bÅŠ:ÞØ @€ @ pŠ–Öìû!ønm:‘_ýs?÷sÑ ˆ*àŸøÄeö:‰‰m¯ð›·õS§NM–,YÒº™Ï€ @€ `ìímÉ‚ ’íÛ·ÁCQ 6¡üˆ-ðûðÐȆV¢¬>ªF !-[¶ŒÉÿBhl€ @€‚%pÆg$¡Ìá¦h„ãǰ2ÿòÝöáG6D°›pU½ÿº/–/_ÁíA @€ G@~ÓC…ÑÉžíýW­sù§¯¹æš)wß}÷‘â”[rlÀ«C-ZTnKr5@€ @5#0þüdâĉIË|•Ô¢U0#¦Û› ^oˬĠ.ðùÏ~Ú½÷Þ;+`Ò¤Iéx–Ú‹"!@€ DC@a÷zà®]»‚¬“‰—ša¶Îkí ãBæÍ›ÇøÿoL‚ @€Â# ÿiÏž=•ÖΗ´È Ѥh"Ô0GŽ Âñž5kV47 @€ P$ùO¡Læ. ;ÁìB(²ñû-ûĉê¦ áÆ™1cF¿Õà<@€ @" ÿ©]ï{Z°¢ ;ŠºfLg†rÓLŸ>½¨ö¢\@€ @Q˜6mZ0@k‡²}ž{ã7κãŽ;öÅ=À"ÎEÐD$@€ @›€&QÅ—kdý”)SôŽ÷µc×$ü#¢lœÆ’PnÝÀ$@€ @›€^Š/×ÎóïÆnÆr°†šÓN­)׊—®Öæý‘U˜Á5!@€ O@þS(¾\;Xfßp»íuÜM€…ÝOi§ÖTÑ(UP皀 @€@ Øpî`"Úùr¶-šIÞ¢V¯^=Þ€I¡Ç¯ãÿ6C€ @(@è€E' ”~WŒrÁË.»lêÁƒÇ…"=ztkÙ@€ @NàÈ‘#ÁD¸MÙ%Y¬:t(íý×ìûíB6Ê6ñðáÃe_’ëA€ @¨%ùO¡tæÚäòíNn·±ŽÛ¢ààíõ ‰Ô£ª“ U›Àõ!@€ Ô‚€ü§&Tg²†#Äœ¢Ž;Vy{8p Dá&®@€ @…À¾}û‚ˆÐ\n!D”‚jà]Ñ 6ÀÀP-@7D€™3gZçC€ @ˆ–€zÜC{ï¿n¢è€PÆŽìÙ³ Ú¯)*@€ äA`÷îÝiøÑÓMx›[TÀôéÓƒÑ?®]»’eË–åñ?A€ @€¢$ ¿)”NÜæ“+º‘£4 `Ê‘MJ–†„bOÑ7åC€ @è•€Gôz^Ç7ámnQ 'NL&Ožœ„º!ç_jÖððp÷&eB€ @¨5Íߦ7„ ÿ  †·“†ìß¿?Ë·mÛ†DK` @€ ùK!8ÿâ"!âäÉ“¡!ÊÝž¨"DG@o-šP3IN˜0AI€ @€ `Ôã¾}ûö`€P:‘‹¾9¢BQ‘tS¿ð ɒ%KŠnGʇ @€ P.­¡Û¡ønûöí« »A NÐ<“&M b5ÌÖ­[“Å‹3à w)çB€ @QزeK0>’Bÿ8ßN•‰NPEg̘‘„¢àHÕÚ¹sg2oÞ¼NmÀv@€ @! p{ Û¥÷ïÞ½ÿ¯,Z $góæÍÉÐÐP07xc¾Y¨( @€ ùG¡8ÿ‚³cÇŽàeP”€†„ò:@5œGÌŸ?¿¨v¤\@€ @ÁP¤¶:kC4i»æ#hJŠRPã…4 @öèŠà¢A‚ @€šH@cÿCqþÅ_~Z^ÿç÷Z´ÀÔ©S“^å (M¸téRgÏ€ @€@c(ÔþðáÃÁLþ'ðzk[“R´€zÚ§M›–9r$˜öܽ{w2<<œHœ A€ @h uˆÊÙ©÷_CöìÙÓ”&Hë­ ÚI8vìXP ª /^õªW¥zc @€ è(ô_)$`Ó¦MÑq«BQ ¡M¨Æ8zôh:Ë$Žuk²€ @ˆ€zÙCšøOLå—iˆvÓRÔ€SáözÇdHIC4I¡"H€ @€b% ˆìíÛ·Õó/ÖêýoÒä~E/èu€š ´Æ•Ú´|ùrÞ àw"K@€ @ */¾øb¢Ð-ÇLÝ4ÁóÏ?Œ=e½ ˜êi?tèP™\Ǽ– M‚±dÉ’1å@€ @u# žE„4î_ Ÿ}öÙàæŠ+«m!Lœ81Q>qâDY\»ºŽ^±sçÎôÍ]ÀA€ @€j@@¯dW©ç_Ø. ©i|S*®¡!&Mˆ¡  @€ ¨£S½ÿ!¦uëÖ×1\&§ÆP&Ün¯¥ý“ @€ Ô™€Bþ5ß™Æý‡–öíÛר±ÿÞTá)S¦‚"»ôÏ¡…£ @€ Ô‘€†\kÒ¿Ð&`Kù\k×® R˜(³­%hò‰P‡èŸD"€3 @€ :ó¿yóæD3쇘dÛ®]»B4­T›%ˆ¬€ &” ¹Û‹¹bê?M·õà8@€ @ 9BïÌuÓ4RP@¨CÔ.ˆ!}¥a  @€ ÐŽ€œu^†<¡¹ìÓ¼¤—4RPÕêPÙç"sˆ € @‰€Âþå\‡<‘¹lSï?ée„`Ú´iA¾À›ÇEY!A€ @€ü”M›6íü‹ÓC=Ä$ë-7L£EH9ib@ýs’ @€ ”NàСCµ˜°\ŽÿºuëJçS‡ 6^P#…>€l”°mÛ6Þ])$@€ @ TûöíK¶nÝšhìÈI>øàƒ!›X©m†ܸqÉŒ3‚žÀï’Ý»w§Ñ¡ÿã¹½,!@€ zعsg²}ûö´S2äšhøôý÷ߟ0‡ZçVšØyW³öŒ?>™;wn:û¾Ô­ÓR;.\˜LœH†ÜVØ@€ ºC­(d…þ×!©çÏž=u0µ2‰È W˜ýìÙ³“³Ï>;øÉõJ MX—Æ fV!@€ À ÔÍßxâ‰'ÒHéÀ±Vn@Kh¶}ÍhyÞyç%guVÐJ‘Ó8 A€ @ȃ€&×LÿzÝ_ÒÆ“õë××ÁÔÊm$~¼Mè†×ÛæÌ™“Ìš5+}}„fá—ÃZRÔ®]»ÒH Ы I€ @€z% ßBãý÷îÝÛë©•/?íÑG­ìúu»0ZL½êŠÐÜ ,H.¼ðÂdñâÅÁ:ØšíRÊ—l&A€ @è…€BþåOÔÉù—X¡qÿLÞ}K#ŒÂJ=ëúGP’ ö .¸ Y´hQB€ Ð?‚Ô; @€ ÑÈoÐÄy ù×Pèº$Ù|ß}÷áü÷Ø`£ó˜ìØ…ØK8ÿüóSA@¯ -éŸAòú‹ÐZ{ @€ ù9[¶lIÃþëÔ¨!ÛrþC¢Në¶· =—‘­º©vìØ1òÙWôú= PDÀ¼yó’Є9ÿˆðc @€ 8½Z\!ÿJ\§$çÿÇ?þ1}6@ऌmß¾½­“¯É—-[–ÎÚЀº†ótÑ$@€ ôA@œêõ×äyu;¯ù ~ô£áü÷Ñî~ €“c©¹41 æh—  Ä9|BÙ_§ÐžvœÙ@€ ôN@~À¾}û’ 6¤o뽄jÏÐ0ç{ï½·6¯&¬–Vç«óÀÎlNÛ£0 CCCo<Ÿ#`þüùéÐEdç8­Ð’6è^“ª²mÊ”)%]™Ë@€ @UÐä~Ö|èС*ÍèûÚòcî¿ÿþ üª¾+ȉ=6„T3‰sçÎu–L zk€œmÃß¶mÛ¨Ç÷hF߇knÍð9kÖ¬TÈèÑÐ÷8€ @‚€:¬ÞóºFoݺ5yøá‡k7\!ˆ m ŒµIÿ@rœçÌ™3æøá»D@IDAT'@jÌŠÆÚT­¼éŸ_¶(@B†Ä€Ð&1« Ø@€ t& ÉýÔë_ç7ƒ=ÿüóÉc=Ö¹’ìé™@ÏÈ^:Áç˜={v¢1öc%9Ø ”åx+"@Nx•Éßp {$PLž<¹Js¸6 @€ 0  ?–ãðàÁKªîtuX®[·.yæ™gª3"Ò+# а íW¿D)l݆Õ̘1#QV$€æ¨zr>Ù®W€¨ŠÐð @€ PšÑ_‘Êu÷mÕC!ÿŠœ&åO`@¦R×Ô»/çY}·"€.;mÚ´dùòåéÛ É-ª|‡"4Ç Ì0àÍÁé€ @(˜€üýû÷§¾„"|ëœYýÀT)]g†cÙŽ0¡.ö«_βÆÒ«7½×<…Þ/[¶,Y¼xqú«òª«£/©†úÑÛT' @€ u@**¹*ß!O"ꈔó/ŠT€œØª_"ÀÌ™3ÓÀ~þ z¯ •Õ/!@ŽxI"†®/1@B€†, @€ ê ¨§\Ž,Îò–-[’µk×V ]}«–c@ŽœõŠ %‰ræõÙË€¬) Ã÷af áý–•-·×u½3Tão¦NÊD½Âãx@€ äH@üÉ/¨ª“0Ǫ¤EiøóÓO?¬_¿>ï¢)¯€`úÝ,gY‘Ó§OO³ÂrׯyÎ8ãŒtž Rúô_v’˜±iÓ¦4@Nš4©l¸ @€I@ѹš8\aòUt ]Q =ôPZ¯"ʧÌöÚsé{«þ! °páÂ4@B€nnõ¤’äpkŽ€E‹¥Ã$”­ü©nº¦²æ0q"·Ð íʹ€ @èD FÇ_uUƒfúïgØt'VlïŽÞ[wœz:ÊE¤á Ÿ—£¬h€A“Þ80gΜ4«< R‰2èÇ&©$pHÐD†$@€ @`prü5—æ‹¥Ç_Tä³(Ü_9¦z Þâå•€P k ЭÞr šHoÐ!Ys}xÀ’%KÒ/MD¨hƒ²’êvàÀäàÁƒé+ %L™2¥¬Ës@€ DE@C}åøÇêï ¤!ÅêõWýHÕ@(˜½œr%‰š@"€œô<Ã]4áàððpš¥**@_e% $n¨~ŠP " ,ú\€ @ îbvüÕ6"ýØcU2—YÝï¼íGÈ›h›òô:=9ÉšÕ_!ü>$@*XÞ¡ûþöÍ9 ±5 M•ÚnR5,@Q h‹ˆ€ @! Ç_Ãyõ ­g騒ê÷øã§@Œõ«c{!”ÔjrÄ•Ô;®¤!š@"@žÑiáöG“j"Be}¡èúe…ÛèŸ["€²ÄÕY‚ € @HÒˆ`Eîê9=Ö¤·—=ú裥QŽ•ežõBÈ“æeÉ —s¬±òž<@áóE©b”«ˆ À¡,ÁCB€ìÐP @€šD@ÏúzæW§œžcMŠp^·n]²aÆÂü›XÙ•Q/€2(g®¡°|ýó lUo½Æñç=7ÀÈN­d£¤8jhBYª£Â$€(ÄIÃ4'‚êL‚ @€@Ìôì¯goe=ÇœÔë¯ ¤0 TÐ.r‚•²"€zÅ5«¿œtM¨WT4€W×ç è QB¹Œ¹ôJ]K 4,@Q¼9À[…% @€@,äìËé×äÜyÏû#ùO?ýt²yóæèëû^íAè•XNÇ+ôGÎðüùó_Q¢Bååœ+,¨ŒWúÉù^¼xqš}®}Q-@¨üì<ª³Þ @‚ @€@ è^ÏÓeEÚVÍJ¯>òÉ' ™×¬êºÅx}€ [U_ R,XðŠqñzS€G(|FBAÉç Ðõ$Phˆ@ã“t eE?hh€ì`x@-Î5 @€ò  gzunÉñ/b‚ï$‚¨€"‰S6 @€@·ô¬ªN<íWgY“’|…ûí4‰iÙuE(›x‡ëI=” H9ü­I“ªW\ûô…S¶Ú¦ë{T€lÕ?¿rÑóhò Њ ЫI€ @(“€¢råôû0Þ2¯]õµÔùÔSO¥C„«¶…ëF`0~¹ž-gW"À¢E‹:ÎŒï=ârÂ%Tj”} TOŠ%¤´êËV™¹r½í( € @ &÷ö ‰ü“çž{.Ù°aC%~G‡faó€WÄ©rè5'€&mü»œ`½BÏ'ÐÓ—SI6*ëMÿ$1@Êh‘IâG6*@‘²A“'’ @€ 0=W+ÊUO u¯¢Ãmûó8WuÞ´iS²~ýúTÈ£Lʃ@íð +ô¥£×iÌ›7/ÿ;3üm ‰WO¼Ä€ª’†Ì;7Í>D`÷îÝ…Ú$N ëKÐ\ ¨ê.຀ @ ¾â/‡_Ï—êùnjRG›Âýå_TÕÉØTöeÔ  Ê}^C³ïË™µ š@ޝ†Týê‘ì‰z¥ "Š´K*¥"”u}´N‚ @€@;ªçg9ýUv¦µ³­ìmŠæ}úé§Óg÷²¯ÍõÊ#€Pë¾®$‡V_LŠP/÷hIû5IžK©—!(—%”5¯lr1 Èù$š(ú@yÊ”)iT€"Æâ7[öA€ ÄA@½ÚêÝ–Ó/ç¿é½ÜbñÌ3Ϥü5Ewøèµ@O{õÅ$‡Yó´{M`«‘š(PóxS(ã–Ô+¯¼dÉ’´§^QR‹ü¢Ñø-e…2iž Š–`¾€Ö»†Ï€ @ ^zÞlú¸þÖÖU§™&÷c‚¿V2qF¨IûÊ™×$´{M`»jè8e}ÙIDEó={öì4KØðɥ•ô¥/ÊQ$(3y`QÄ)€ TKÀ~E¡ê0„èØj‰¼tuwü5É_‘Q¹!ÔN'€p:“`·èT“Ο?¿§‰î‚¯Px‰úò é]θæ8P–} Û×0…"•TŸ/@òbÊ¢N¹€ @ xY§_ŽHϽÅ×~ô+Èñ—Ó¿qãFÄÑQE½ fÍ«^ümÛ¶¥³Æûw›Ôë.@Ù#BûBT´ÂÂ… Óìb€† ÈÞ¢’x*ò@YοĪÀ0¢¨S. @È—€&ð“ÃÓ:WÿÓ™4y @M[_ޱxõïÕQÍF„ú%™ô…î“úI(*I ðaÛ·oO‡H P„‘EQ§\@€ МþѹÉñWo¿²žsA‚@ï…±Ë!Ö€^ÔÖˆ€P…5‹Å‹§Y_ôþ&"Å€ìœb«¹|¨@¯¬k|‹a: @†€žÏ4LTÏ­ê´‘SK:€ž‘Ÿþùtþ0Χé[j~(<^óè5ý¾óÞ‡èËB_¦R CM”ýµ‚>g@‘“ºè‹S?4ÊJº¾O ¨H @€@1ñ*§_ϨZâÐvæ¬gyõökœ?œ:sjú€î9¿4‘žBÖûI ‡V_ú‚Õ2ääcõ—-[–:çŠ P.ZÀP‚²’D 0@‚ @Œ€:¸Üé/r.¨Á¬ çluRÉñ×V9þ„ú‡Ó6!Z‚b«ôa“þÑõ®{9ísçÎíy^¿¤ Š ° /_9»¡‘¸°téÒRʼn .<øP. 7 @€F' çL=oª—_ÎlhUn}5{ÅLÏ êí×Ü`¡?«WC‰«¶#€ÐŽJ·ù—æððpÏó´V[½ÛÊ3gÎL…•]‡/—V1@s%h¨@Ñ ­C$¢¸ u @€ÀK¼£ÉCûëðŒBÛ‰“zú7lØ02<5»°¡>êÓV][*U¯ Ô¼'ÞÄêÙ–S­Pw•í"C×Ux ‹šDPv{o}ÑÃTe…¬)K|P;ø¼*ÀD‚Þ\€ Ò ÈqÕs¤¢Kë0Ô´t@c\PY[¶lI6oÞœFéŽq8»!БÀàÞaÇ¢ÙQ%Ÿ@Ãäç‘4<ÀX9ÐRlõE^—äb€† ÈnʨƒÚcïÞ½i/EHP„€–bK‚ @1ð^~wú™˜®÷ÖU–Í÷¿ÞùqÆéNgÍ)­4è¼­@ä¬j²@e}±ë‹I_ìuJrº•õ6ñ‘s.A@u)#yt€®)ž<÷û6‡2ìæ€ @ ¬Ã¯Æòw"5övÍí¥Þ~E’’ '€ŒýSU@€@‰4æ\Ï rúÝá׳ ipÞÛ¯ )pœ)%tG ;NQ%‡\_:rn‹t W*ëÇC×­cT€_œ=¡¬/hÕÅ'õSÝÊL>€®¯¤2 e‘mZf=¹ @åÐ3ŽœQeïéÇ1Í· Ô¡£ñ‡m¾l)­;ÝqŠî(9­R%Èi,:y¯µ”d Ð8û²zÑó®›"'\Øð7 xd€„²“ÄeE&(iƒxûÊn®@¨=—¹ÃïN=,¯—•zNÓP\={×µ3¬^ıv4£Ñ‰|ŸTG £¨ží¢†d1f£¤,ËaÖNPÅ_¸paúV„ìP*^×"qGÙEHp;õ™@€@ó¨óE¨÷î—ÅØ$âz¶Uo¿=oWñLØ$ÞÔµ{ݳŠöHýhæ~‰e:‡îê R6x®3h½eÁç Ð}V ¨êí! ¨ % =bïQZ%Pç»Û!@§Ðó•|:¨—ªžEN·.Þ-zžÝ¾}{ÚÛ¯g0B#€Z‹Td~vìØ1Ú^¦rHý ršõũȀº«ÒŠvÐDˆÊJª—å*† x›fßæQ. hA!~}–€  F@½ûÞ³ïN¿~óIÅÐ3«Æô«·_C]á^úq÷¹$ ¨Î!$ÈÚ"À‰EˆY:¬C€z#Ðêì»ãʳ@oµ‰çhEkÊéWf…xÚµ©5AhjËwYoõ¸Ëñ“ ç®ê”u–¥ºJ  KòqøóçÏOgŒUÝôÃ#Å9„è€,g0ñ µOÑ ­ÂòÔX‡ $©À¯g,ïÙ÷%Î~w‡žÞ¯¬ub!€KKX9Ú!ExUåTΘ1#Í>y`lb@öµ‰‹/Nälûd‚ªwhIʸrV”Q[y„€–J º‘ @M à=ûrø%æãì‡ÙêzvÑ3¯zúCët “VÕ‘@[­"›¥~ʱS4@™¯ 즺r0=Œ^N± Y'´›rB?F=ëÃÃÃiV=5DÀÅ€¨$"y›8ãl¤€G „v_¹­,!@Ý£¯g%9øÞ»ïëÝœÏ1åÐs”œ~eµ ±@ˆ½…s®Ÿ~Ô å=ï!¾*Î{ÍgÍš•†ÐK¸óÒxú<šEõT••ô£åÑZ†>1î%å¬H£ûÉ…‰5 m$@€@H$Ä»s¯¥²ÄxBøCj¥ö¶è9©Õé§ÝÚ³bk|xªŽ¯MK©‘œ6ýÈ…27@§JËIv±Bcê5g€„}ñÇöEŸPÝTW©Úªk]ÄÙ­ålR;ª~òáØÈRÔì÷žj†~…߇ m9‹Ó§OO³Ä€ld@è½åÙzt³®¶ð7',\¸ð“ J¨Ûd6êe‘ ¡œMÙh$ d)±@ÝÈ:ú„ïwC,ìcôl§ ”=û³žÚ™&@hrëçTw9“RŠ.'¬I²ÄE,X° µ_ʰrÝœãnxË!ö9|2A¨ÃpNuôa­ûU_ 1àKͺPÕZ>C€@¾²¡ûu¦ç9ˆ8‡ù².»4E§ºÃ¯çÚ³ìàzu €P‡Vª®²J G«NIv+Ï;w¤·\aóô [R]çÍ›—fÕM¢‡ u.0Z›¨Íô œMrþ=jÀ—. dI±@ þ$g|}vG¿þµ£" _ÏjrúÞŸýÝÇùç@{í¹°µOúaÕ°zÖõª·::U/|r=ýxÈ9Ö‹ãXÇŒµP] SD„ÚÓ[oq´ôèÝ Z¯ã}ÜZ?>Cˆ€¾Ó=Ì¿ÛÝé×0¶©>jë½{÷¦Yjk Ð=€îYqd—ôƒ+ÇQãµåHË¡ªk’ã×:T@αrLŽq¶}>«7]ˆÚT?´±ÖÛ"³,´®{@B@V(àŸZ‰ñ€@~\¸Í:ö¾«(Ÿ½8JÒ= gwúõ F‚ú'P_Ϭÿ:sfIô­Iõ*7?ab6*044”:ÆúA’s¬¬è‡SëüjWAbB¼-õà¡:+·NB¨c@ Lú-Ñw;òí–îô‡Y¬ª3=Ïùo¹Dþ˜ŸeêÜNØîÊ èaEʰœ Ý´¤ºgÇÑ‹‰ÄqÑR9Vµ¼µîz`õ=Hh]èF!á$ÈÁhj’CåCüÐâØµ»O¦¨öWýUgÀÐC†îR±äd(U +4´À…Ý»ÊþÙ÷e·û:CŠmCJ‹€8ÿ¿ê´žuîýذj5M% ßbEèùo±–þ[ŒðÔÔ»‚zו@][.b»åpÈáÓ+öH/Ô}å  Ý)Ö°Öcý–“(AHyþüù)=tHð¬ú“ª# {OmâƒÝZâB€/;‰¾_KÝþ¹Ûëpò ๖ºç³K­»S¯¥öké9Öïç<¸RF˜tÏús†~kõ¬¡û™ÔŸ@ýÛ0Êð°4z³Êr§XGŠ—Bïô-…^9æ±w­Ãäxªîþ¢uî¡Ñï¡öºCÕ¯-­‚€ Y‘À·ùRû|ëz¿vp^˜ô œuÔ[?û=èKߟ=Ç÷…YK¬‚@>Ôù¢ßNwúõ¡ÿ €øÚ4Šñ£Ó[3Ê‘Ñ+³)J©×¸~Ì}©Ù“줊º$€¸(à b¬{“ëä÷s^½RYA@\‘ äBC'áÀÏócµÌnË®{Y££}uOúôïñìº;Öª_ëv¯³o÷¥ŸÓî³ß~Œ/u, hO@ÿ'z.p‡_¿‘ÁÅÿN{fl…@Lbj͈êÂÐà)çEó(RÀ“¢\ Ð2Ö(9\zŤòððpZ}9‰zÈQ”€/ór/ËzÈ:˜ª‰?—]«¬`à×–p0ZÊ ŽË–áŽs§cÅb¬cÚío·­Ó5Ø”C@¿ýúÝó¬ß~þWËaÏU "€[›FzŽ@‘/E(«·Üð%ds¬N±‘ì< "ëbˆÐgª&àBDÖÖ³4X‡:Ðo¸ÿ¦ËáW/¬¿ë°Àè|Ø[=“Š' ÁÖ¹ô  ÞPOÖcL%044”VÏœ¼—DKD[ž:A¨? ƒúÎ:üËŸ}†Ê®×¿ÆÔȃ@)£úÑR(,©\ê)Ÿ6mZšçÌ™“^ÜE=hxŽQða:áÉ'tQ@½)U…†»M,!@ YüwXξ~‡õ›äÎ>N~³îj A Jó #ÀZah{.X‘Þ[î'ûÈ„€˜EÖ UÿVQ@Că@”€~cô»*gßcµä¹hP²œˆ÷A°ø¡ ¶iRÃFôࢇõNÄøÐÒNЃšG ø’qÛaßÃX@ JzÎñßIwøµ$ʬÊVáÚˆŸ@üm\Û"Ô¯éÚ‰jG=Ìè!G6þ°£eLÉ#$|>Õ­5R€á1µ8u Ð=E‰éwOb±ÿjgîr$ €|8RJøQ,jEjõ˜+knOê×C?i©h˜zÍÛE ´Šâé\XB€@} èÙ%û»&á»]¯>Ï8õmc,‡@Ý Ô½±5% aÀ_Kè“îéÈçpqÀ—±<,& ø0-õÀH‚ p ´:ú±%òf¯²ëáÖË &@hRk׬®ühÖ¬Ár27û/R÷‚"üáJ]zÈŠ%b ( :KÐ|ZJ`ß,!”C@¿=ú½ÑïŽ~s”Û Ó<³”Ó\œÀà )¡ ü˜¶¦Åúün¾ßþpæhZúº[Ç¥"$|^¬ýŠðH‰ZWvÙcY‡ îè·Ä|ý†d}/ïY'Á¨3€:·^ä¶óCyçT= >” {Ïh=+øº–Ùãr2£´b!¡!>lBV}\ð¥¢ôK‚ — è{Q¿îìk©Ï<Õù7ÂëÀ€@'Ȱ½rüWÞµ6@=è“&MJ³zÒ³I½èzàk·Ì>fÏ y]uÕ‹ÙIe¯þ‡$ø‰¾r}° €@¿ô½ç~v©uålâ9#Kƒu@ )šÒÒ5¬'?Ì5l´š˜¬^tE´K>¤@â€g=4úz»sBÝ–F0gΜ3FP°Ô€¾§õì½÷Ùuœü6(&C¥@(7ë…@/´86/ÙÈ/ÓïE-õ ™\Щçç…ºì$ ¨1кÔ> ²øw­¾oý;×þvßGuùþ-‹× Љ@'2l¯œ?æ•7´ã¬û•ÛÝŸz(ÕC«–¾žÚ=´¶\¢ÒŠŠh7”@F©;ëòA;•V„‹CÁp§Þ¿#µômZvú^é´=ø c  @ Ò˜q:~äOg–° È–HК²÷²?ìº@ BÚ½žQõTÝ\ÐÒ…­«·Ž4€¯i™uêõýçÛD%ûݘ¥Ôi{öÖ!@ ?ýqã¬ðPd.Q:9ÒÊíîomóg=(g?ûv-CJ<¦L™’æV»d¿D‰ž%¸PZ]Zíç3 ðJúŸVÎ:òþÝ$G_ëþÝ•=Sç @ a´V´!ÀC(lŠš€œiE(k˜§Öÿ×RܾôqÿìçWµT}üíl8à‚@«@ '‚”GÀ¿7ü{Äzwê}»–í’Î'A€@ø^~ ßV,l&ÖàT·kr¬EÐ.eÿoô îõÙev½ÓÃ|»²óÞæ¯ilW®ì’â€Ăl4Ö³umWÛ ÐtÙÿuïµ÷múSÎnÏòâÿ+Kƒu@ñ@ˆ§-£« Ñ5)*™€" ”|Ùzyÿ󥜭·fmWòý­åñY6= ³¢€‹Ù¥Û]„}” ªèÞ÷ÿE-=Ëwæ}›ŽUòeú¡åÏhûZå# D@ ‚FŒ¹ z0Qo' (Ž€ÿ67Aöêú¿lÍÚ?Ú¶ìùy¬g‡̘1£m‘r‚E Q uéÛa ãH(›@öÿE÷ öûQËÖu£äËV›;mo=ŽÏ€ Ð\ÍmûZÔ\3îœÔÂ`Œ„@èR¹³1Ö6í÷c|=ûYøüsëz¯hÇŠ"ðò$øpƒ¬PàÛ}ɼNŒ¥ð{XŸ}Ýv}ήûý“ÝîçyyÙ¥Ž#A€ò&€7QÊË•@¹â¤0TNÀÅÒËÿwöX_×Ò×[ËËnoݧÏÙ¤ •§NšÝÜv]Nœ¢´t±@ë¾]Û²ŸÛÂÆJ ø½Ñi™uÚý˜ì6¯6n—üø^÷µ;žm€ " A•2s#0ÚÃTn¡ @ V<*È—íŒïö»Cǵ;Úg üš:6kGë¹r•³Â€ £-%24!µòR³L³û}]K_{ñÕÒ·¹³îü:moÝK?7»u@€@ Ô¹õ`;_ hdª ÈqtÞ¿oü³›åÛýs7K?Ç'`Ô„†­IÇøµüx?FŸ%È™õ¥Ö;e?Fçi^Rhu†U~öºÙëùzvÙj—ïë´]û;íóí¾ô²º9'{ìhǵ¯µ>C€šF i-^³ú¶{P¬Y0€@[Yçß#ôçN¿œzÿ¬ýZWÖº£ÏYçß÷µ½ mÔñJ¾L?´ù<Övío-c¬s:ï籄 @ xÅ3æ € ï}—#ëN·oË.³û²N¼ŽqG^ëÚçi4ç¸Ó¾NÛ½L–€ @ •@+>E€Ü šc <wÄÝñÖwˆ²;åÝ®«œì±YgÝ!h§Ôi_§íÊa; @È“@ž4)+w<,玔!P:9ÓJî”»s]f×õßzŽ;àÚîǶ:õÙŠöÝÑi_¯Û³×c€ Ô@Z©Á6vz o0ª\èËéìÒ×ÛíÏnË:ß~Ž–¾®c³Ç¸ÑÚî)»®m­Ÿý¸ÑövNö|Ö!@€’€» h<ÜÝ<×9ÈJ¾Ô=îë¾l·Í÷i©ý­Çè³R¶§Üi]¦Ú?Ç—ÚÞn½Ý¶ì±cí×±$@€ ê TßX0 ¬c1Êaì‚@n:4Ò‹­Buºó­Ï¾®í~fÉ:è¾ß·yyÙe§u?·ßýÙó²ei; € @ ™šÙ5ŽKmš*C%øLí^©ì}èë¾Ô1íÖÛmóòXB€ @  㫸(ׄ@·²NT·çp @€ œNàt&l ˆ@@ÑSÆךRM@€ ¦@hZ‹×¬¾5k°ÌEˆ © @€@[m±°1¡´v@€ @u'€P÷ŒÜ~€È8Àê`£` @€@.rÁH!E@(’.e·@h%Âg@€ X ÄÒ’× âÆ¥j€ @€@iJCÍ…ú%€Ð/9Îë‡ýPã@€ :@¨C+5ÜF€†ß%W dà\€ @ 4¥¡æB€@ Ô¡•°€ @ ýPãœR P*n.@€ DJ Ò†©Z1µføu! ü6ÂB@€ þ ôdzJ$€P"l.• p@€ ÄJ Ö–¨^5f ª‚PƒFÂD@€ ¾ ô…“Ê$€P&m®@€ ÄJ Ö–¨^5f ªB@  !@€ú"€Ð6N*“@™´¹÷ @€@¬bNÄÚ@Ô+I¸ @€ DãoF!,X°àp…7—.˜@Á€)þˆx>@€ ưçñ@ˆBxûÛß~ÜD™!€5à*!Ü8˜@€* `þ@ÜǺ䡱`= Ô³Ýêj5@][»!@€@1ˆ(†ë ¥î´Î“@˜í‚U€ @hóGöÆRÏ(†œjŒ±4 õ€ª#@@uì¹2 @”ÀóÚÕ³YѦÊlè¹öœP Š  M…‘Q4#•€ @¹˜u8¶ZE'ìß¿ÿo¬‘öÆÖPM¯œ²nR;§Ô·us>Ç´'PC¿¦–žÚmó}£-ý¼ì1¾-[¾ïGp,!@€@c |.ÆšG'üâ/þ¢Tš»bl¬&ש“6wþ)£ßs¹¶Ÿ›7¯KÑåûuZ—~ÝÖí½~örŠâÓ«=@€ PKÛgÍšõZZ>†ÑÑ §ê¥Z3F[F½» ‡ÎǨAf*WE}ýšy´g‘e¹QX… @Í#ð¹[o½õXŒÕŽRxøá‡°>Ækj²cžŽßh<Û]§Ý¶ÑÊèvŸ—›=¾Ý¶ìþÐ×Ý~-{I~^öœvÛ²û»]÷rzµ©Ûò9€ @ öôðúÿÖ¾*¥°zõê“ö€ÿ§êÌæËasÇ®†U+Üdg3ÃA ñk R†ÎÍÓF·©Ÿ2‰´%9€ Ô–Àß~îsŸ{¬¶Öax”€ê|òäÉ[mqdŒú³;bî]Ų®St=º)ßëÚSÝZ~eµ^£ŸÏyÔ­Ÿër @€@õ¬#è«·¢8 ¢>ðl3l]:J.“@Îb§2|{™õ)êZ^-My–%[B³i´ú0èÝÃù€ @ –Ö®X±â«µ´¼K££T{Àÿ?mq¢K8v¤;qýš^D™²eP»ú­O¨çµã<–­Î°Ÿs[Ëö²Z·ó€ @ÿ‡†“g>G·µðþ÷¿ÿIëÉûBt­ÖÐ åá6ݨÕvç8¾ý–åçjh;½œ^ëÒz]Àæ@€ GÎ?ÿüè}ǨÝö ÿ [D­âÄõ7XmZ9•æÛ)92¹~»s«¶É¯¯e·©Ÿs:•ÝOYýœÓéúl‡ @ˆ‡€ù¿{ï¿Z+zàæ›o^kõü\<·fskÒ‹£9%wÇ:.ÏýU\³Õ~·!O–­×(â³ÛÝKÙ~N¯uÕñDôBšc!@€@í |ÿ³Ÿýìmµ¯Eˆ^ƒãÇÿk[肇LÀ¹vŽo+Óü*®Yfý²×ê§®~Ž–Ý¦~ÎQÙ~^·×ÉžÓ‹}½”ϱ€ @µ `/;ù¿™¥Ý?´Ö¢Zíl„`oØhÕÿ/í°µ.ŠvÔúq"aç׫^Ý7ˆ-±Ÿë »­'Ý’â8@€ Poöœø§ý×ý£z×¢{ë!ÇôéÓÏWB©¦zuâz=¾¦X:šÝOýý-{I~^?çôr-¿N§sÆÚßɾ~ÏëTÛ!@€jA`׉'þ}-,ÍÉÈÆW_}õñãÇÿJNÜ(¦œ¾¢LéÕ)ìõø¢ì±\gÓ‹m~Ž–y¥"ÊÌË6Ê @(—€E}þæš5k¶•{Õj¯Ö@˜mBÀ;mñÅj‘sõ~ ´sÝ¡ë¦L?¶]9ÝœÛ1Σ—zù9!0,ʕÀڨ—{‹c!@€@ɾò—ù—Ÿ.ùš•_®Q€h;vì×l±«ròP¢œÂ~-Þ2®ÑmýûµÅÏët±ö·;ÏÏÑ’@€ ÝÖáÓÈèðÆ 6!àkøßÊ4>«5!P„#׫“Øëñ½¢-ºü^ì É–±ìv[Ç:.»ßÏѲ5ÅÐZ'>C€ ¼DÀžõ~Õzÿ74‘Gã5² øskôÏ5±Áë\gwÔFsÜÚÕÏo·¯ Û¼þίÊ:eËXûûµÝËí÷|΃ @ˆ†ÀŸ™óÿÙhjÓcE)ˆÑ‘#GòñL¼8¼Be9°½:‹½_!Â\/íõ.«]d|Q×l-—€\o ƒ @A°g¾‡gΜùσ0¦"#+ØP€ÿŸ½7¾ä¸ïû° ,ö¾ïÅI\$€¡ˆd(3!(ÛJ‚8,‚HÖaÓQ%)ÙQÅ.GŽ –”Ä.ljÙ¥Ž** ‚”J¢DH‰å’TU Q$ EÀâZ,öÀîbX, Ìw°¿Eïì¼7W÷LOϧ«æßófºýëOÏÿ½þýú˜—Þxãʸ¿6{ŠõHÀ 8"'#ÊØ)öªäVÝo£K•̪ûmÊ$ @€À(Íì¿|âŸ86 m)9Y€xÞ~ûí–E?ˆ-b=0ã͇ئ²š¦_¤cY–WqŸÁÊ¢Ìyu5æÝo««oymõ  @€€7Yï¯~âþûïÿº7‰#4i€ÚìÖ[oý—YÄ~#x€›fJß$OÓô1"³:4©·zX¹ódUÝŸ—¯Ëu+³o]t&/ @€@÷|êSŸútÉ#:y€Ú+Ûà'²è?ެíP7#`F^–¶ƒÐʪ£WŸiL¯>4©—é5/OÕýyù]7™óX°À"z܃ @£!ð™lÓ¿Ÿ¶ÅÎö8¾dÉ’g§ûóF|ó µ2‘MÒ–å¯sÍ È:iÇ’ÆêÔ?ŸLLïy2ëÞ[½çÕ—ë€ @9/ž8qâG²³~×ÏF À©Æùà?øäË/¿ü'Ož|#âöš¼jUZ•¡× Éª*³‰Ì±§­bÒõ~h>Uú¹å3À¥Á9 @¿Ì6ý»õ8>:Í*¼$ ì±‰>çµ×^û—¸ö²Ë.›{î[¾3,VÅì¼7½7öôVÿ²z”]ëšþ¼óÎ;;L¾®Y°²,¶ëŠ] q¯¬ÌEå(ýUuîz_\«‚•‘- šdTñá> @ˆ@ÖŸ{63þo¸ï¾ûž‰]×¾õ{ËÊí»äÈÊ»å–[þY¦ÒO=õÔìÿø#ÓuªÈh3í˜vѽbÚŸ}ëá[^Ⱥ!Ûø(nÊ4mä€ @ ?êûeý¸=\pÁóý•:ž’˜µUö&€›²è³ã5ÝþýûÍvìØ‘ÇfX¬‹v^Œ›Þ{z«Y=Ê®uM¿téÒÒÙ*K¡Lþ›wßsóº2ŠyÛÞ39uËqÓ·=¯2|S¿_Å­ªþÙz±¹N¥*Ù܇ @蟀úwÇ—M°++}÷Æ?óÄO°ÄÛiŠÉϸ馛.Φ‡üjÆä =ôÐìË_þ²ƒŠÓTm¡uTùv˲ëCëXÔ‹ÏÕÊÚ®ÌÙS-‰€ @Cñÿúë¯Ï^yå•YfãݲsçÎ¥K¬åNzÀÇ>ö±óŽ;ö¹¬£eY=ûì³³ìí³íÛ·ç·]ƒÀ΋±¯Ùç²{eׯ”¾o]‹3ÄOÁô°øÍ«oþµk—ÝÓµâ}÷³{nùíšÅvÝ•Õöž+‹óah@öÃ1Lá” @€ Ј@¶¡{nü[&9²ýî߽{÷«?ü0k¼O9cÔÛ`M%~î¹çþEV×ï]Tß/}éK³¯}ík‹’p¯GŒ®÷»AQ6‚>/Kì÷]½M×2盎s@€ á ¨ïvôèÑ3Œi¥m꜅ÿùî»ïþ¨N…iïS’mú÷ײþOUÕYÔ¾ð…Yæ5ªJÊý¨=ý0£¸ÿ’ý–hõà9òËi€ @`êÓe3ºçÎÚÌÞò&ÇÀ9Yº_ºóÎ;ß=„ޱ•9Éßÿýß¿2kˆ_ÎŽZõ׃%'À¿øÅØÚorúTnºoGŽ]Ÿ'Ãîóý³Õ«ªÞóî÷Yÿ®ºVåwGõ«ÒöYïe¹u !™€ @`Há/Nû/ÓGûdayv|öŽ;îØ\–fJ×jÀ©É^ ñ¿fuº¼i½´) ¯lJÍú! 7+³¬6‹î•¥·k–Oñ¢P•®êþ"Ù¾ïUéRuß§>]Ë€öÙÈ‚ @þ˜ñ_g¿&õ O9ve{Ü—9&½Þä·ÝvÛ Ù£÷÷Ú>~ÚàÿðçN3i+—|õèxL¡«[]cªO]|ÊŠ­ÍЀ ¤DàäÉ“ùÈ¿úouƒòèÈÂ÷eN€R7_Šé&åý¸á†–žþù¿‘5ä¶.ùâ‹/Î^xá…Ù%—\2Ó®ô îh¡c7Ý+»¶è^léûÖUås—…ÎÊôyóNù=7}1Ý¢{Å²ŠŸåmzÏôê#nòEÚUŸª²ªî»åW¥­ºïʲsí«ƒ@€ ­éךÿ6A³dGd}ñÿüÚk¯ýãl`÷;mäŒ=Ϥf¬Y³F›þíöÑh{öì™ýÆoüF¾ã¤yȆ€ C;†Ñ ÝRkã{H*¦÷:P6 @€À™^yå•ÖÆ¿$É BdÿJ¶)àz}˜Z˜ŒছnÒ¨ÿÿè³80ûìg?;ÓŒB?ŠÆdHcÍdË´šÚ}û<†ØtžW§&uð)«ª\+«nºyõ39óîWÉç> @€@ÿ´Ùß©Wúu*üĉ¹# ›°3ô¯: iæÉ8²éÿSÖFk}·“FÍøÎw&9ƒÄ7N¯òÌØó*´¦°¡Ê¶r}¸>eUa³²ê¦ë£~eK5ªôã> @€€?ZŽyäÈ[¿ïE°œ§Âe³þ–}˜J< Àí·ß~eÖ ?ªQ5•äÁœýéŸþi¨"{Š€ÃO¢êœ€÷C .oKç£}ÊòC)€ @u ÈÆ:zô¨÷Í×µ óö€_øñÿñÕuuJ!Ý$Y#ÿlÖXoîÖ¨ÕdlüùŸÿùì·û·gŽW)PiÓÚ°3ù¡(w‘oyw &««å÷)«®>V¦O>dÕÕŸt€ @å´Þ_3­Cg9Áެ¬ªœå&ïøà?xm6•÷޾à?ù䓳Ï|æ3³ƒöUä¤Ê©2Ð|…e`CË/+3†kV﮺˜ÅU¡IÚº²ªÒq€ @`8êÿiÔ_€Á}ÛSVæß¿ë®»® Y^L²“w,Y²äÈ€÷ZOmxÿý÷Ï}ôјÚzòºT”v?P©ÕgQ»ø¬«Éb€EĹ@€üДßëýièÌÚ^š- øß¥MéÞ’”*S¬ËÍ7ß¼3ëÄÿ»ìz¯é¡u%Úððáó‹.ºh–9"rǫ̃°Xí¼—Ý+»fùÊî•]ó™Þ§¬ººžz§’Ÿf—(|6Ý,¶4ŠíšÅU÷ê¦39–Þb·Ìb÷ž›ÞÒ…Žeðú Md…J»¨.MÊÔÿ°Öˆ @€ÂPÿL#þÇÏ—•†+éLÉ*×±+.»îºë¾øµ¯}í/ÏL•Þ§Þ ã>fÆÔ“•tíU}{ì±Ù§?ýi–T x_ÿÜM ¿2U|È(“[¼fåtÕ·(××ç&ú5I;ý|Õ9€ @ pÑ”gM~¯ÕÒ¬'ü|v~Žó9ÉÓdg|èCZ‘ºß—! Ýròfi9Àºuëf7nÌÕqGzí¼+ak–fˆôC”íxêNóÉ¡:¼\uî¹é­N[~7{¾({Ï=wóÏõ¹NˆÕIPG÷bšºu©›®(¿ês™\fTQã> @hO@F¿6úSŸk¨ ²Ï?ÿ|+~ û{â@IDATÇîÝ»¿üðÃ?nRŒSžðYƒ®¥Ñ´ÑÄúõëÝi&±¨6:=\cMçîg·2‹î¹éú:J+w§¶õ%·­>Å|®~v^LSöÙÒ6ei¹@€ ÐŒ€Œn­õ?vìØÜ~|3‰ÝR»K>³~àÏfÒ’ž¬`Ù²eWøXŽk¯½v¶sçÎÙ¹çž;;ï¼óιîöØN3· µ‚Œ1èÒU«‹o¶&·J?KW§ü&i«Êå> @€@x—_~ùìÒK/ip4;ÍudvßyçßžÄp% º>>Tµo¿ýö-™qð×dlÇ´à÷~ï÷ž¡Š¦±Ë€)svἆš•`¶cÖ_üo3…~op¥)¤ aÿ‘Ì«”µa€ïú®ïšé¡/ŸrèÃ0)Òi÷Ùå¸È¸o'}Z¹\–U5¯›¶n:•×&m› @€@;ê¿ãï˜}Ï÷|On÷HÊòåËg×_ýìK_úR;¡rú7Ý}÷ÝWÝ{ï½Iî¤à‚ .ø;ò,Å4úÿ®w½k®*ú§P=trª þA«3 ˜ÂÕu‘CÂÒ¹iìZ•úuÓIN“´Uår?n´uÜíƒv€ Ô hóó÷½ï}³M›6UU9¾úկΠ»ðŸ•n  çdƒÉÿUVö?¨ü ÅÆ1D·ÜrËêì=’WÊŠá¸êª«f+W®¬¬¡t•#À5+3‘à4;U¥©›î´ð9'&oÎíI^6&UŒ§mZËWØÒµÕ…ÿÅ*Â܇ @gЮúïyÏ{f·Þzk©ñ¯Ù~mùÌ€ìµ9}¾»n¸á†$Ë“«Ô–-[nÏÞ%ÍÎï|ç;Ïþ¯XpÅ–-0`>¤:ÝüÜÜ1M86IkòcŠ›èß$mLuD@€ 04 /¼0_ë_gTvÒ#e5i2+·Iž&ic•_W¯ºéš0!- @˜*Må×H¾6úkÓ‡–½ôÜsÏEƒO¯'tÂíwÜqÇÇxàεџ&5à§ú§7½øâ‹+cpèà²Ë.óò€´ùgòRpÄBÌ[ĦNšˆ«Ø›jÆ)dmÊh“§IBËo¢ i!@€À˜ÈÞºâŠ+fßýÝßïêßVwÙK_øÂfû­¸Îù z¬ÉÞØöÞLèv‘€¤ëÖ­»+s´ò>ùnMÿ_±b…o±¹<.‹ ß …F$Ô§áæÊZÄÔÒ-JÓ‘ÉT¾ErÝtMË™¾^mò4©C[ùmó5Ñ´€ @ šæÿîw¿{¶~ýúÎÕц۷of€…½ØþfVI[:€“'OÞÃ迪§õ,„þ ¸†\£zQšþµ÷[¢Ë¯äþ¥µ©K›OÆpÏ=÷œ{üøñM1<<úÇØ°aCðç MSQ™!þ!ƒW¢EVo7«]óÉÀdªŸr]½›ž»:5Í2}¬zYc×Ïô$† @±ÈÞ®6»æškò#¤¥¥Z P0¼cÁù–\Ÿ)ó±(ÔUdW_}õåög¶$äÃYv¶Á,Û0¢nòÎédÜ葪úÇb¬v®˜g®8$#Ó£/¬¼¦8Ûäk“GzµÉ×&[Vü}µQÓ¶©“^º×©cY¤ @`:´³ÿµ×^;{ûÛßÞ‹M£>‹–ìÛ·/VÈ8bl™ìÁyç+¯¼…ñëcCŒ6ŒÕÙ×Εú'êÓÑF×®yTW×Àѹ¯`FS]™MÓûÒ3v9Æ¥‰žmòH~Û|¦[×ü&‡€ Œ•€ ýz¥ŸFäû k×®i3÷¡ƒ–¸6Æ)}äH&ô7LÙ«¯¾úŸ¨ˆf¬\¹2pm‹—1óÚk¯å,ô§TÏ:FºwuҦʪk½ŒaW9¡óWéYu_úÕIºȇ @}ÐTÿ«®ºjÃßê¸zõê(ì8éSâØmz¦'ãÈÖÁ_ƒñ¯‡bh€=˜Ú@‡¸˜7Ëî=–‘VeЛ!W•®/¾õ1yMôo“§‰üyiÛ”Û&[þÐù]]8‡ @±X¾|ynôkÔèACÙO±Ør%¶Ã%±µ]}RrìŠå¡Ñô™˜‚9ôš#À'g3KþéK‹iš¾TÈÈ.ZûV»k¹]ó÷]_ʃ @¡hWMó×®þCþVG-9ˆÅ–“ZV턵wÝuךO~ò“‡k£=MƵÀöXšX×ßëAÖ¡ôóÎ;o´­—AWf¨»†^ÙýQWÚ³ò.+Ï¢çŠëZfßùy†æ6%7 @3ü5Ý?»ÉÊ6‰E§²þ_6 za¦ë#¦ï˜ãd™a°¹¬±†hœXdÔÕ·,]×ò»æ/Ó‰k€ @`H[¶l™]sÍ5³]»vÕê·©«í[6¤e¯ª¸?šÛIÌøüç?¿lÿþý™ýznà kF¢Ði‘6#@ü4ý&Ö% eu0íŽ1îæoš¯iz·,Ϋ _‹«s”§èš_R}È(׎«€ @ ,õç/¾øâ|Ä_#ÿc 19Êú‚×caY¥g€ì€ËeÆâШúƒþñ2–ù+åèûýŸ¡™¹ÿÌM¡uó%ß­c™Cço£ó¼<)Õe^¹@€D@;ú_qų«¯¾zÛ†äuZHöS,¶\™¾Y¿@˜¡®e_@ÓØcyh^yå•¡Px)WŽ€'NäŽÍˆñKDÆŽ†¼k@6-Çò¶Íç¥!G.Äú¨†OY>ôA @ðA`ãÆ¹ÑÉ%—Dc µ©—ì§Xl9ÙBÅõéq¡ ù9›Â~®:ʬoÝÆî0^2šÌ`3ÄxlÁŒ¿¦ÆøØêé[_ãÖVn×ün¹¾dù’ãêëù”êk  @ õiwìØ‘Oóß¼ysˆ"z—yüøñ {M*T¶œ;³1ãXkÞ¤"sÒ&±@uÓ?‚¦¬Ë`:¼üòËC«àµ|Ù,‹Ó34+@u ø6F}È«#§QÝ& @¡ \pÁ³Ë/¿|vå•WÎV¬Hf@:Ç&û)†ZŠP§º­CÊOÆ Hú§ˆaýý±cÇfòq´¼êa3G€þAåpÑò€!Œ¤:ÿ˜–¦©~]ó‰aÓ2«¸·¹oõh“·˜Ç—¬®rÜüîyQߦŸ}ÊjZ6é!@€À<êSnÛ¶-7ü/¼ðÂ(Œäyº¶½®~X,€f“·åX7_R¤1xŽ_ñš5kê¶ÃèÒéŸCK´i –Èì׋Á¯Û°¦·«³]«+cQ:_²|É‘®±Ëò©ß¢¶á @(Ц~—^zi¾±ßªUɼ®XÍü³OÕïŠÁŽ+›þ_ªôˆ/&åÐ?ÊáÇ£hŽƒ&í0ÈúgµYšñ 'Œfb¸†¬¥ ›±Ö¥Ü¶2Úæ ÉÕmú¹×R=wëêž§Z_ê@€@:Ôݺuknôk´¿K¿vLTd7Å`ü‹Y ËÉC·]r€XþQô ëœS ò˜iÍ °å¡f˜qgqÛv·üj§¶2ÆÔÆn}»êB–O™nýBÉuËà€ ´! õü²´¶åÊ•mDŒ:ì¦XúášÝœzHÊ ‘çX¼GGŽ9½i^êQ±~2¶ôÏã.bV@Q/ߟͨŒå ËwýšÈ3MòT¥ !Se†’[UŸ¾ï빜J]ûfKy€ ®ô;­Ñ~mê7¥Ñþ"7-+Ö îXl8 f¦’rèÁ‘¡ËÔýû÷ç›v¤þ-ªŸ6eÔ¡µ=Ú'@íãkV€Œ›¶Æ·Fmó/ªsÝ{¦ƒÒ/ÒÃMWWvt!䆩º„Bfî¤ @`ºôÚ¾‹.ºhvÉ%—ä}ãé’x³æ²—Ô'‹Á eÍ1l(ú™HÊ XÚ –†{ñÅ'ï°XÿØZ C{È ¶êóM ®Á·Èà6Ëb2Êä¦zÍå壎®<÷¼®ìyyÜëvnq]Ù¤ƒ @e4­_Sü/»ì²ÙêÕ«Ë’LöÚ¾}û¢0þÕSýW=“sèL;ðÇŽ=š?H2t oÐ^š CoŸË7Ìkkô¿¥ùðgVŸš„)ý\¹î¹OÝMVhùV1 @¨C@ƒ]šÚ¯‘þM›6-œíYG^Ši´\8¦éÿ±l&º­“sȘÔ’X ‚çŸ>…G膫|ÍÖÐ~ r–hã@sÔ© 6]HqÑÀ·g x½ŽìbšXeõìúÙêÙUμüc—?¯^\‡ @šÙºcÇŽÜèß¾}ûé~*dÊ ÈNòÑO/—Þìªú¨²I¦’sÈÔhr,;88p ÷þi¤›0Ÿ€þélã@kC9ä=”G‡(˜ai}™Ø1/Õu“©t±|9¹:»ú¹×ÇrZÿ2ùe×ÆÂ =!@ˆ€úˆ[¶lÉ~øÓç¯×FÈÓúë»×Ë.•¦ÿk€)„$­R½J#¦”wk×®]Sxž¼ÔQF½-ІrèÈPgó@3ð›ÑnŽ‹¥¤Ýó¢pM!¦Ûe×TñŒd¦ï}°²,ö]L™\÷š{î»läA€ õådô«/£Ñ€UZ5÷W›^x!šÍÿT«C‡ù«\ä’’uÄ4…CÞ-}IhŠ;¡9rt¨=Ýýš~ÑšWŒåut r[÷z3­ûMmú†,Õʰ8dY&»Ï²¬LÅC•ëêÀ9 @qPŸQ;økŠ¿vñסþÇ´ùŸj¡ÍÛ§’thýFŒcY ‡I^.ftû·²ýÌ /^Íöhê pµ±gŸüîT$»ææirn²•§«¬&åö‘Ö­[èòú,Ëê2D™V61 @ÃM±uëÖ¼¿sçÎZ³Q‡×:~ bý×^dzSÙTB’5ž'Nœˆ¦µÀÆs½¢QjÄŠÈ V63@ÎÞX×ð³sï®ïž—ató•ÝuÍÊ %žÜ¾ÊuË™w>OÇ©]wùL­îÔ€ Ж€ú•6½_ƒw¬éoK²<Ÿh5Ú^Õ—.ÏæªS É:dÊ8Œ©üÜsÏåïÿœÒÖG]‹3äüÑë }8\ýÝgIçöÅåsÆ€[ÞÏ]FCèï–ïžwÑEíìKV=È @€@Z¦»mÛ¶|=¿b·o¦ÄéJ•=¤¾•õ£‡&¡½Ç¦4ý_¼“uè¡Òˆ°vtŒ%hj‰6˜X·n],*%§‡ë Цzl™@¨/×8´ó~8L—¡yèòÝz›.»÷8‡ @`zV­Z•¯ç×ëú´¶?T?qzdç×øðáÃùFß1ô“MKmÖÓæñ¦WÈ8Y€ Å¶€tÚ»won²! h„ úg~饗òC_4zä Ðì­é æšCü¸¸º¸ç!ë_”måZ\¼?ÄgW÷|](€ °ÔÛ°aÃL¿6ò[³fMØ‘~ ÒÉŠÉøWÿïÙgŸ=CÏ)|HÚ LÄÅ´€*yšôÊ!ŒÁ)<ÔeuÔôž—_~9?4ÍGÏ…:útÆÌ34‡xæéRÆ/ĵbùú\¼¢Ü*™¦ƒÅUé¹@€@œÔßÓ”~ýŠYÏ?\;ÉþQ|ˆ>ï¼Zû#à²ö'I€ îÔ'×ÚýM›6åF¿ú¿¾ûݵDB‡Žvs=ÍHøö·¿Ý¦ZIå™”@_,z¨ µƒí¹zõêÕC§äd²Í•Íš! cÅŠ£ø¡3#ÒCü@»ò ³]³ÏÄ€ Œ“€úßÕ×´~þíW߈—_~9ßñ?ÖZ=öØcQîIÐ7¯I9WSŒl&@ß°ë”g›ÍiÔ˜y[. §ÀX~Í0·X­¤óŽ{¬,‹­Ì.÷-/1 @~ h棌|û2úá÷Ë7FiZÒ¬Y°n_-&=µ×óÏ?“Jƒé29€Hk'wíÀãRé§Tk dÒ$PæЬµ¹f€(iP‡ ª/|÷K_ç1ס¨«1±ëÛub@€Ê ¨cƾÖð«¯M˜ÿ²_bí;iÏ®Gyd: RQÓI:ÄDžI=¬±yÐpÄÚB~õ’CàèÑ£ù!碌d@³tŒe†€KÆ~ŠñPŽ•kº¸z¦x>¥º¦Ø~Ô €@¬Ôш¾ ~;´Ñ6aš4í?摵Ê׿þõ|ãîi¶ÐÙµž¬@Kôe%P¬AËdj#9´gȘÓú9yØÍ! Ïc 2Â]C\ç}8Ü2Çʽ!@}°õû6¥_Æÿ’%KúT²"% Á+´ŒTÅÙ³Ï>ËÔÿBãLÖ š ¥:b 2VôÍ“'OæÖuD§~èYÐÎ¥:´Y¤‚ÍS@SíÆ:KÀªŽ®nç}8Lb@€À” Ȱ×À“6ì³Ñý18L¹-C×]»ýËN‰9hv‚Fÿ g˜´@†…Œ'y¯ÌØ8OŸ^zé¥|&€^•B€€(ÎÐuÍj1‡€Å–~¬±ëpÿOuŽs`¬­ŠÞ€ 04ý†jð@#ú6¥_Æ?¿­C·LÜå«ÿ¥Á(9bê'å+_a×ÿ’Fš´@<4ŠªÑÓ˜÷žz¥œf*hc¾˜E„PF@KZt:t(¿-O¾žoshÖKJÓöÌ!PŒUy»æž»×r@5þ´ÉSC,I @½P@†¾F÷íH©OÐ+̉¦>‘¦ükd=öðè£æöSìz¡ßä‚®×jzÓ«¯¾:DÔ.SN ­cÙºukþ:ÃÚI8YrÙæ‚Aû_È) gÞb]›Zp û²s÷ÚÙŒ]ÿ12Gg@±Ðo¼Œ}èÛ?Sùciqê¡>¥6ªŽyÿ4#»gÏžÙ3Ï n à‹€ì£½{÷F»oš[O-O`Ý¿Käìs­ƒ’a­©-Úl-Ö ÜsÏ=—o΢/zºS 8S@Óµ§€œæ CÑ•4ù!@íhÙª–ôÙ¨¾bLãoÇ“\õ¨¨7“afáñãÇóuÿcеý0©p8\µY„œK/½4Õ4F±y¸ä‘Û¼y3ûÄÚH#ÖKŽ&ý?è° N†9Ë!0&§€FJ¦ò£0¥ºÚóI @ úÕˆþêÕ«OcÛO*m3•z¨¿¤]þÝ£1×ýµ×^›=ôÐC£X¢04G…Ñ#/—ÖÙkƒ¿ð ù.ü…¤Q|Ô&Z }ÇdˆE%Ðÿ‡ö¢p7Í”¡iŽÅê´hæ@Œ#S1þ7, @`Zn§Q}÷6_£úú-%@`(•ýûÒhã£þé_üÅ_œÑ?µ{ÄgÀp6“|Ô_/¬kI€ÖRéŸ@#î1òxi£ ½¯U?ôI@ÿrB7…ÑTE9ä pºN€ L‰€~ûdÔËÐW_MƾÎuÈ‘N€@,4È£åК=† ~èW¿úÕÙÁƒÇ n:â˜Ó òxÉà—Q-ãeçιC@Ž=`±9¤œš®-ÇFÖœ†åroôáÿ£¢÷X£r (6ÇöÖ,@ È˜×ÆÒ6¢o±Fùé›èÎdKÈö9|øpgY} Î<òHî°è«ÌÊÁ° åÓ4fÛhOFË®]»òY6#`AöAnIgÍ€· ÒZA@ÓÊÊöÖ@ÿor ¸çt˜*€Î¹›“rŽš\† 0Jú½’Q/cß ~Ñq Ü(!£to4X£QÍ*Sxì±Çò·£IçtÅPÑ ÚøB‰¾ä-˜#@F¶Í°{1Ä2®ô–m£ P1´ :T0Ç@qÆ€ž_u¦äpžë*¢Ü‡ ®ÔçÓt} ª˜oFWÙä‡@ ^zé¥(g7/b£AŽo|ã³={ö,Jƽ9pÌã^>tèPnxèGÀ ZËuá…æ£íz7¦þb r^èu†rT°™LL-ƒ.Mh)Ž¢WZÓ,m¦€Åæ,`=e¤… 0mú ±Q|ÕW,ƒŸß“i?)×^{7iÔ¿¸‡Sìu6ãÿÉ'ŸŒ]ÕhõÃP£iô émÛ¶m+M—Wøâ‹/ÎÿlF@,Óoe4i6€6œÑf†üÕhp’Œ‚€þÇô|R^Ϲf èSÀú<•ÿÕ3–ï¡Q¶Qµ›úv_ÿú×ó½Î¦ÞŽ]ë A½cRSý·oß>Óù¼ G€Þ°uëÖ|æ€fÄð* › ÀÞóZŽëS `βºªYtèš{”åã „' =™ÔDzÑ{רg©cxþ”0^²Cô3-V?hlAúëU`%t'€ !C*š@ç‹þ‰4ÝL34ê.o›‹ Ui\ÿüš   µ± x“€þŸõ?:ïÿÔr((¶k¿)iø¿‹¾›†× œI@ß§ê7ÉÀ—1oF¾Œ~ÙgÿLf|‚@êóË‘Ý2Æ ½eü«?p´àh#é;vìÈ×Wu´õƒ¦ÙZ õ6Ú' ¸Óy 5:e‘#/šœrPè–,& ÿu‹fô˜#À%Õ>/.»€Ò$`ƽà˨׹}–ÁO€üá¬ÁÇãÇûÚ³$-Ux衇fGí¹ä´‹Ãв}‹N€E!@ñé8|øpîWnÈ µ@ÚHÃ6 ´‘Í!u¢lŒ™€9 æÕAß »çîµßPÞí¦»jê³:$GÓtôO[×0è¨úYÙõe¡7È Y ìp".@ wö}`±)àv¸í¼˜ÆÒ*^tÏMÇ9 .}WȨ7Ã^Æ»}.ŽâëMó—Ѭɱ‡={ö̾ñoÐo Ø8<ÀÕ?œÚðONóMƒÖ¾íÚµ+—!#|ÈbÍd°ý´Q ¼ý@ ~êÜ›3 L[9\G€-]²ëî=÷¼L× 8¨ßa#ñÚ$O‡ó:w}]'@éОb²ÚرQP¿ã±Çã5=4 OåÐæ~ÚìOï›Õ?¢u®›¡jm¸yóæ|$^†øPû¨Ï>ûl^Ÿ7æˆ&u!- ¢ƒ`Ñš\×)P}oî¡/m,"g„m`¨ €€K`Ѭ7]Ù¹9Êbs ¸÷Š×ÜÏeò¹2úÍÖs«Ø5Ê›^Ó¨¼d ø& ß7ý Ôy A¿çO=õÔì[ßúV2uK»àÐR6GË´ÞN  ëAï$kûöíù>úЬä}}é˜çQŽÍPèÒáïSwÊ‚â& ãÉ—e$×a`ßÁºç^}.^/¦we*¥×9Á=îïŠ}.Æ*Q¿¯îu;W~3àí\éíÜb¥'@ˆ•€~gdô«ßo¿A±êÚD/mVøõ¯=ßs¬I>Òú!€Àdz¤È0×+åPE£ørø¹W‡Å–H¦fÈ(ïó‹Ae©L})­^½z¶nݺ¼žgà ÈÀë3˜CÁÊt¿›ž›Œ¢L»n±9-ì³Åæ¸p?Û5ý~”½î}—]7YŠ•_iŠ÷Üëvné­Lå³sÅvî^wËâ€À èwC3oûîß÷ÁZo<{ä‘Gf]gH÷¡kªeàزZ;oNur´9 <^>wêÔ2½=@3ô¥Y}®¡QP^I}Iáø0!ˆš€kÌJQ׈ŽZq”ƒ hh PýêÔFüX6Ãw¾óÙOšÏh°kÄÃÀÐ{=ôÏ?ÿ|¾v_£D2Öe$k&@ˆÑzÛ¤O³ 4+@Î÷äÔpgh©‚6F"@€ @oÐÛÂlÄ?EÃ_uÒ+Åÿò/ÿÒË2è·ÈqÖ…–Yz òÊØ7'€M ½à‚ fçw^¾7€ÏÙ¦–dëm:42/G€¼‹}› YZ¦ §„b @€¦L@€ê“kϰ µ­ê¨þdâ"€ Çöà¹çžËgh€BèÙV=Í8ÐÑ÷¬}©i„ŽeË–å›j/ÛøÉô#† @€@ÊdðËðO}< z~ãߘi†!>8znyÃôO¡Mûl&€Œaއœ `Õ´Y›7oΧÉ+§Ù}}Ù½ð ¹ÓCjV€9Bú(Ÿ2 @€ Ð'Íò5ÿ¯%¹}ÖÏ-K}}þûöís/s4ˆœZ³mÛ¶3ÖÇk­¼ cýóø|S@Yåt°W Ú¬€Ù“ X¾6:±WjV‚Ú‘@€ ¤¼£Yû°Ö¿ŒJœ×p Ô.š£å[·nͧƻjØÞš6¯/ÐÁfØ^Ú8PÓ“BìKàÖEË´G€f °O€K†s@€ 1Ð ž6öÓ¨ÿ‚úñ?þx^ç)Ô7…:â°eÜk9€œ2úÝ ©ñš  Ùrôl¯€;väN-Ð[ BwŸ9#To¶D"dÙȆ @€@4“!¬-õݧdÇ<ñij={ö$»‘aªíˆ`à–ÕÆÞ½{g›6mš­\¹ò,m45Þöèó Eˆ 6ä‡<™š²/g@è ZŽ ¥š… Íåàíg=\€ @˜€–íÚlÖTwó/C,›@kýC/Y.+›kÝ àèΰ³}a¼øâ‹¹œ2'€ÖëëºvÑïkY€[)ÍNÐ~Z" )M2Îõe2ˆ‰¦Né°YšÀ¦!©#€ @`ÛÔO}â>çéÔ×=Í þæ7¿™ÖMÉáÑß¾ÊÁÐéŠrÌ  ½Ö­[WšÚ6 Ô—þûþÇÓ”|é¦CzjV€œ¡—¸³äѬ€â’‰R`\„ @€€íÖ˜ãBï“åA]¯"Ôïê©§˜îï•êpÂp Ǿ´dÕúRY¿~ýL#ÿÅ kš  ¥ú"jêœZ¶ C:HoMÝ×D¨ ‡‡ÖWé°YìŠ6r!@€À´ ¨O®~§FûS…_YK«ïýÌ3ÏÌž|òÉIÖ¿ŒI ×pDØŠò.ê gãÆ¥N©,G€ÖÈk$\#ðZƒ4T°%ÚÌÐ]"r†‚Í ÓA{hy€f”9M†âB¹€ @ã" þ«úÖZ†:ÅÑ~k-õ±¿õ­oMæmVï)Ä8"me}éhý͛7/Ü _ÓòeøÊ×—ÔÞIßk×®Í[" ™Ò+dЗ´í£ rˆ΀ԑ @€Ò! Á4ö[<š5«‰"eøë•à„4 àˆ¸]5µ^¯ Ôæ{šò¾(ØkexÇðÅå.О¶_@È™ îñ0g€–L @€ à°~³f°†\Æê–ë¹úèOd¯õÓÛÉBÎâµþSÒ @ä­­/#94@£ÚUAŽmÒ§âX¦-i¿91tôµ_€fOèË\‡íÀ[ªžîC€ ´ h™­úÈí× Ò©Ù{öìaƒ¿ =8FÐØú¢Ú·oßlÆ ù¨v•Ýõå‹'Ïö Ðk5SAo°ëÔ«Mw¿í› G€b–´¡I@€ 0.êK«?lF,ýâ!)j°ìÙgŸÍ 9`2dkô[6€~y·.Mÿ”û÷ïϧ'i} WäéÐÈ»¼1ýskоŽ;vœÞÕO‡9äЗ{È Ï±œ!)#€ ´# ~«üÀ‰m@«]­üær Í&@Àà0#Œõý /äËdÐ7 6#À]£#@õrZ¯¤Ýýµ ¾ôC× ‡‰8ëÐk € @ý+£ßfmbô—s'ö?÷Üs“µa9!®bÅŒüЗßòòº›«ìÎЗª¾\cuHwÍx°™2еD@34+"d°Í æ…@€ à€ú¸öZkõÁذn1[ñ‘ѯýñ_Ìjêwq$òhà àè“và²dôjI€œš2ß%,[¶,7jeäê‹%´AÝEWË+#\ÇÖ­[s}µL@Ž‘Ð{èÇIeX9bgÎ @€Ê h´ÚŒ~ÅLí/çT¼ª>®^å§%±0+Òáó"8Ñá=}‰Ú¾2B»Mu×±jÕªÓë®Æð%c΀-[¶ä#õrh´ÞŒô®\å×ì Zš ½Ì X³,€ @`Ê4°¤~Åê3êP\¯¯ÖñCŸ¼^ÍHÕ'}Òî©,}h_€Õ«WÏÖ¬Yã¥TMk—<òÎÊË´,wÏýÈØ2Õ#tCFZZša³ä `v@húȇ @ 6ʯ¾—¦ª7k-ÉÕMõ}yn³š‘z8† ÞS™2:5…Æ ù:uźûÈk+GÀ˜¾ˆdtkV€;3@³TÐ^TýØÙŸÚÂÝ;@³x³€'€  M@ƒDê'Z¿GBså—á¯Ù½8Mšó#G9å\’¹ªo[à{ÄY£Ø2\åd­/ú1wf€~¨l™€'¡âTÜ;@û6ˆ§,ÓÓ„®€ éP¿Iƾú‚:˜ÖßþYK­ë×h¿–“öÑ'm¯-9ÇHÀ[­¡Îòj½–h ¿ï`ûØ÷˜– Ư_¿>?T£GæKäèk©ƒfRèP™ rؘ“E1k-b@€†& Q}PÛZ~ Õn-¢µ}ûöå†?”n,ɽ˜€Å|’º«‘m˜2tÛ¾*pÉ\¹re~ŒuV€ê§zÈY¢c(g€ôЗ¿{Õ š g€f à% @}PßÎFøYÇœ&åß»wo¾—©HÀb8óI¸å]”@#÷!‚ S«:d@Ë3<ÆYbã:ôY?x¡×—uŸÞYÍB0/»ôc9l–3D…@€€/2øÕ×±uüêÓü°Ñ~þ}ö'ýh”±À0öl¡¿ŒÉýû÷ç#ܱd@ë‚:lV€~HÆl}þÖ­[s/¸œ:dœ÷ä1¶d•ë:]l–3úlÊ‚ Œ›€ Q,Rƒß{jV§ö³dÂ?_$Ö#€ §äRéKG_Bú¢_·n··Ìå¨úAÑŒ€±Î °:jÔ]‡Þ(`¯û“3@K-úþÑT{Ú´<µ«ñ–3Àf à°–#† L›€ú)fì›áßwße*- 0mÈ­CçþSiùxë‰ Þ¶éE3}ékI€œ2fûš Íuè‹Ð¦¶ù Q¯ðs7Tä 1>Äk]‡€µ©9,ÖÆ‡@€Ò' ÙŸ(0c_ñ˜û]±·˜œ)È7áV_Ö±·Ø´ôÃ0­ö.­­¾¤ôº-ÐÆw}¥–A*„~ŒÌЗ!Êq—=ìØ±#Ÿé YrèÇw¨`?úV¾b¯½ l6³Œ1 @`¼4À¢ß}3ú‡Œ/½öšë-RXÓÛ·úz‹T{mÉ9U8¦Úò%õÖ”|ý@ô±$ X¼ O¡š²®‘t­=“>úñ{°7#lÛ¶mð¥.ËâÆ‚º§· ˜3À^ïèæá€ ¸è÷Ü5öuΈsm¤>«öÖ’ÑoýVø÷ÇŸ’šÀМYÒ9äИf¬X±bºjÝŒf{Ǭ<ª)xR‹Kää°}ä­:¨ýuhÆ‚‚9f4SÀ–¨}€ ôO@†¥ŒLw„_}%B¿Ä_³g5Ú¯¾c"€`L­Õ“®úq± år­¸F¤×®]›;$ôe«/Y)xVݽÔ´ªŸœ:b©£8»ožjsh–€ÎY: 2@€€?Z¢)§¼üfôû+IMh JF¿FûÕWS)…þh¤Mƒ€4Ú1H-ôƒ£/9à2ò† 20ÍèܰaÃé½dœ¦òå+czÓ¦Mù¡ÂÛ“wßf hV†…¢S@ua¦€Ñ!† ,& ¾ŒúËà' K@NûêËø×gÆNÀØ[0°þú¢;tèP¾.\³bé•¶D@?˜ÚàF›Æ2jî£I4ëB{1èPˆqv€[Ï2§€»É 9o†œMâêË9 @`(ê[éwÝFôeðëw”3úeð«¬A˜T›â ŒCÀ0t Œ¤|Ùú¡Ša6€‹LÎm¨ý 43@zÊ ™)yiÝÙª×ЯtÛ`Þ¹f1ßê ™ª‹9ã˜Gë€ 0vú-4c_±ú)1Íê;__ú«o%c_F¿–ÁªÝH•€T[6@½ìËQ÷êÕ«£˜ àVSSÎåÐa3ä Hif€ê«z®Zµ*?ôšAu&l©@ìuµ™ÒÓ‚ê#G€ëÐg–!b@ˆ€úú3c_çÙÇŒ·åÔ¯UÿéÀ§GúãÕÍ à,'#I£ëúa“`è½æA×ÌslÞ¼ùô2TÞ&àÖÛ^Û§zêÇLuÔšbu>bÒYN nÐÌs è93A ËP\=9‡ iQoÓöeðëœiâãx\£Ÿ5ýãh3´ôO€¦“¨?Û@Ž€ØGke$kæ‚– Èa{¤æ™W;h¯ êh´ÝfÈq3– ¶Q[é° ãß®s€eFˆ€|Ðïè+¶~Öƒû"Üõ…4­_¿6ô“€)À0åÖ÷Pwó€kJºŒì؃;3@;îëÇÜœÅèØëRG¿¥K—æû6hïu`43@?€r Œ­#}­3æÖ_í*‡€êkë3\RœC€@‘€ DõÌÀ×gýÖ¤6HP¬wÊŸ5x £_ýõ{ÆÖßI¹m¨Ûðp ߣ×@žT}ÁêÇRŽ€1ÆÊ@Ô¡ÝöõCo›Ö)NÑC¬ºj„ÕO³ôèÃiÛC©v9£tƒ9ŠŽ1=§Å:ñ€šÐï„käëÜ }ŒÃf,cLm}éWûÒ®1¶:Å@@ ­ˆ2¾Ì  Ùcy•A¨å š>¯ Ä2å ÐIjAËT_ ê™3@³R©³ê¥£èàP{Ë)`Ž;×õ±=»©=›Ô€@[ú¾×ï—ê—Øï@[™ä‹“€ÚX¿õ[R¸‰“§dðjï€âþrÈÉ“j½Õy´ÎdY»š#@Ï„9´´BNœeĸ@ }»¾{®ïgÂt¨½ÕïѯƒöŸNÛSÓpp„c‹äŒ€- @»ð§dèÙRÕGut÷HuôÁÝ?@õÖȹêºC@uuƒ9ŠK ”fÞÌs¸r8‡ 0eö]êÆfècäM÷ɰµü6ûÐ~kSí[M·¥©ùp I"eëK[#å2”e8ËHJ)èõ:´±žê:‡€öyÐaõ–3@í¬ÙS–§Y‹fFh†€;s@Žý?جf¤ôÍ@] 0]ú-Ôw¡ zû^4ãÞâéÒ¡æEê7ÙDšÚÏZþ"!>CÀ/~y"myômY€Ö×§¸ÑšêäÆú3ÃXƱ:>)Õ[³éŸGëðG€?–HªI@SÇeÉ 0Æ·Ô¬fžL›»Ó¾~ô\Ã8ÕN’ë0^S]2`õ¯[§zžƒ@\5KÀf˜SÀý¬Ì$¨C›4€@‘€Œ/9kͰw z÷‡n‘Ÿ°Áû2üÕàZDŒ{K@X¾HŸC@ ÂæÐúò)w3AÕ׌b±Ð‘ªC@uugF¸uWg@3ÜÝ'œMÀ¦ÕV='r¸Î×A ëæ$CLƒ€Ì›!_ö™Ñ×i< ¡k©gL}üú}OõíI¡9"¡àE¹µèGB?2P4}\ñ”‚Å7nÌ«­ú±Ô§b}N5Xݵ‡€‚œ!ª³)×=t›jdEGC9äÐÿœæ8°ÏæDP¬{8 B·ò!PŸ€;Z¯ßRû¿7Ã^ŸÍØWL€@(zædäë÷[}:6î E¹ðC`ZÖ–fH @@?ÚøE›éém28¦Š34CÂf(®2èÆÌÌEgˆ9ä ø% Bÿ{:ªBÙòs˜£À>+ÖA€êpgø˜ñ.ÃÝŒ{ýŸº×­¯Ï–”~ ¨/b¿Íê›ðûì—/Ò š€Ð„‘߈À‰'f:l€F™L,‡ˆ–G¬[·.¯:€ú±•w=õÝ¢3D`ÕÙ:b Î0¡®qR·DsrØ,s¸i˜iP—0éb$ ÿ3Ô»‡¾ÃÍ /¦Á ±5ÑI¬ïaSúçíS-@`pŒ£&§¥~lgÑ´fÍšüPgQœdÛ!/|ªHª§Í°i‡)Ï8ûiˆÿŠÚÈF0›´ë 0ëLÐ5÷³{ÆD@Ï«Œr{ní³ðîg÷Üî›ASÐM èÙV_Âl°ïoÝ#@ã'€`üm˜d ø‘©×¬r¸F±: 2ŠíÇ[±ýpד8žT2úlÙ€í#`u\l†ÏÒxÚÔ45ƒÊ>·‰Í) XÎ#ÅvÍöÙ-‹u0 ý?ëÐ3¢ “‚>Û=»oŸÝ{ölY»gq.Œ?˜Ý·ßLÅúÿ @éÀnÛŽºfüø´k>&f»Ë4C@Î:O•¯–LèX¿~}Pz›¡XÓSuˆ´{bÒÍ¥gÜŒÃ3Š\g€þïôÙ‚›A×Ýs»¯ë&ÇÎ+¸iÞ¼òæßy×-[Ž]këÿfQ˜wß½nçj;—L;×uûZt®ôvßò.Ò{€À|ú²¾€9Ê‹ßö9_ w ±À0öLT~€ü5¬F?W­Z•’*¶ÚgA£åfësŠAÆ’Þ.¡Ã‚;Ú¡¥Œvâ&0F›Ð"- 0ýÞ™ã_¿uîý¬!Z„2!q´ZðÃTâñ£FmsA-PÐH© È1 £8*àQ…AE¹û(Hræ‘C@ç©:DOဠŒ€ûö[®ß2ý¶Øq&†@IDATÓŸ †Á-£mº´ç«ßöÕ,’ëí Ôq°™æHÑ0vg lÚ´)¯¾9DÔ²·¤ê±ö&† qÐï‘ÍⳘߨq´ZB 8bht€@„äX¾|y¾§€©§Ñò)8Ì!"§ˆ9Ô¹²)”检@EÀŒýâȾ[ƒ&. Î!*8ªq0úAÓtuB<4Zn› Z‡£èƒ řťj¼˜SÀbãO«¡  Œ€kìÛȾëhæ÷e ­ˆŽˆŸ€øÛh²òC7ަ_äÐŽûæPœÚÆiÅ·虵N›bØh ÛG«¢% „" ßBýFèp#í·‚þO(òÈ…DÏA´øŒ¶i*sJlmi³Ôá‘s@‡:@v¿Rpä 4cÅfH¸ª—h¶€® @ ]úmÓw½~ëä6c_ŸSsˆ§ÛŠÔ éÀ^›&S£TŒÂdÄCE\Ç€Û¾ÖA’3ÀŠS eË\§€:†ª»b Œ€ýŽ™‘o±ê¯Fh ¤J@ª-›@½\1êP…d ëÐè¹ޏÎ;O¥35Ï) '€6Tlÿ öTC–€úúM2#_q*¿MÃÒ¥t@ 8ú L­`ô´Â–L&Ͱ5öî³ së€)¶suÆÜtc!§ÀªU«òÃôWT7s ˜s@N „!`Ng}×ÚïŒfj1u? o¤BýÀÐkJjH`ìÆ\Ãê’¼&­³?ï¼óòÅ,Q§ÍbëÀ¹Ã¦úžþùù±fÍšÓUVå°¥r ès]OWŽ@=Ð÷¥÷ö{¡XFY¤ìZjR ¯pxʼn0Ÿø¡õIs²lÖ@±¶2–m¶€Åvm¬ÏÙ’%Kf+W®Ì·¾æ(Æc­§[7Î!´! £Þ5ôí\qYàû²Œ × TàH¥%¬?À 6ê@U’cÀFÑM{¾lHAs Xli,Ïb[6QÔUõ³=læ3Š”ø Œ‘€û=®ï:fôëœ@oÀð Î"#0Fã+2„¨Sƒ€ë(>sêTÊ`‡:’v®xL¡l鯩®æpg ¨î@±°ïc3ìõlƾââ÷w,z£ Øàˆ­EÐç4~ÌO£àd rèñ\ Öuîµ±<¿63ÂÝ_@uU½Ì9 Ç€{Œ¥nÅ6ã3 /÷ûÓœ­n¬û |ÿÄÛ†hŒƒÀÙ½Úqè– ÀüyÄUÔæ|r öÜ*v;´:·CZëÌÆŠ@{ ,_¾C`Êì;GßC:wcûn²x'ýÿ @ 8âh´(!@‡¡ —&E@£ív+îþ¨S®ÏÖQwÏíž›¾(«Ïî̲òÌ)àÆæ0PL€üÐw‚ófØ›!¯Ï6U¿XêÐß%E}ø @ÍàhÆ‹Ô= “Ñ#lŠ5Í$PX´Ü@÷õ?¥Ž½{®kvÝÎ-ÎöôÇ6#,+NúÈ01‡€Í¢kúlõ*ËÏ5L€ýßêAçŠÝs׸·ëJ7/,º7/×!@ ~8âo£ÉjHçc²MOÅÐ(¼œÊþÇÜk®‘ ëv躂}vó˜lŸ±ô¶ µ1aY3@³ä0Gbsè<´žezq m ØÿWñÿ°ÌwÓ”•dz_F…k€¦IÀ4Û}4µV§E Ð?›Y0Ïxp¯Û¹ââyñšjâ^óQ3s,’%#Énl›šóÀô_$‹{hBÀ tåÑóeŸíÿ ìš ý²ÀóYF…k€ P—€º¤H7utp ‚žB!Ј€ûêžKÈ<ƒÅ½®óyŸ‹×M1÷º][Ë¡±h©å5ç€2ÂôyÞÑT+ƒx¬}ÝXçv¨vn±Œ{‹u]ÁâüƒógÞu' §€ opxC‰ è… ŠLÄG@Nƒ¢ãÀղ껠xߌ/Épï¹ç®|7Í&˜·ÜÀͧræ9ä<(J»HW6çÍW‹-·}¶gÂ>Ûýâu÷s1­åizÝòC€†&€`è ü…æu²fâ& 09Eç-_hbÞ÷{Ý=—l•#‡A1ÓÙ}]×Qt ¸Ÿå$Ðg¢ëÜýEF`^G225Q€@)}‡é°Ñ{3ÊuMçvÏFýí³¥³|î +Hi˼ëei¹@€À´à˜V{®¶tdG×d( Ñq­ï3ºí\±àv^Lk†¹›]+É) ó®+í¢{e²¸@€æÀ0 ×£ @Ç7Šf@  J@ß6Z®sרÖyñ¾k€Ûýb»®´æ}ß4½.yóòXYÄ€ @`8† N™µ Љ®Š„è•€Ðú5ãZçöÙÍ w¯ó螥+ÊÖ=eÁ×õ2Ù\ƒ @©ÀZ‹&VŸyûĪIu Љ€ fý¿˜ñl±{MçîgKc£àöÙÝsåµ´VžÏ;W> ó΋y-=1 @€€?8ü±DR®±@<"!Ј€žG{&ç›ìÞ—­ kvîÆ–vQ\–Þ®)Ÿ;·ØÊ-Þw¯W¥uï›b@€ ñÀ0¾6›”Æ“jî(*{ðàÁüÕjöì)¶s)hç»×Üó>ï«\ @€ªà¨"ÄýA ¸FÔ ŠPødhT]ÏÏÞdšœŠB€ É8w25¥¢£$€6ÊfµÒçœsΨõGy@€ Ì#€`®GA@Í€€ @€@p$ЈTðG€þX" € @ .8âj´)`@ƒÀ1@€  DÀ@à)¶õ8‘ÊþX" € @ .8âj´)ÀPÂG@€ @- àh ŽlýÀ ÐkJšÍ˜ÀS@€ *©¶lBõÂPcŽ *8FÐH¨@€ Њ€VØÈÔ'}Ò¦,@€ @ U8RmÙ„ê… ¡ÆAU˜0‚FBE@€ Vp´ÂF¦> àè“6eáà€ @H•€T[6¡záH¨1©  @€ 0ƒ¡§àºpÔ%E:˜àƒ"2 @€b$€ ÆVA§3à8À0â!@€#€`0ô\—€º¤H烑@€ #1¶ :AÀ8ø@€ @ ­°‘©O8ú¤MYÌà€ @p dýÿr?ù< @f žs# ûb8óá®_8üòD @H€@2öf€“'OOà¡¢ € @€ l@òXd*µV' À·¿ým­ø32 þ6JICf¤ÔšÔ€ t'õqtÇèOÂ=÷ÜóF&íU‘1µFúºàH¿©! @hB@Zý¥}±¿¢(©O8ú¤MY8x @€\™=ò‚ûyÌçI,8ÕO¹!Ð}>óÙp€ @K`éÒ¥O…-¡?é)9öô‡’ú$€ OڔŠž@€ ‡Àk—_~ù^çó¨OSr0`Ôâbåq,æÃ]pøc‰$@€ §Oí9—@Uf³d™ø$Z„J”ÀPŠ…‹€ @€@X‡߯ô¥ý®´lÔî+á¤#yh8†nñ•_öÌ”]SÍÜëÌ_[£1 @HàËe÷.:¥_Íèéu€„ ¸Z‚Õ£J èùðùŒàèØ d‡ @‰Èú˜8blË|ä#G3½¾£nèÔ€Oã®»6HhKÀ õb{ÚuW®]sÓ–]sóp@€ ŸÞxã >z–õ§žå!.®‰J“Tcžn×](v-†¶3]ªô³tÌpIq@€&Kà…xà[)Õ>™%j”¬óþRjêò׈4#í­»o®ávÓ¸÷8_LÀxùÙõŹû¹[¦‹]sõ.»ÖFCm¨‘€ $Gàßg5ú«”j•Ì&€j”¬óÿûtÜSz<ߪ‹kä½uuñ™å±gÂ>+×¢k‹¥Žû®Ë 暌EϘ¢ @€@gÿ_g ‘ Hj@¶ÀSߤ¦hDö¼ ¦NŸ¡Ê*–W÷Ú`€J .Ó¹$Ù`—L?—µ] ¥”ÉwËTYvÝÊ5‘}&† @˜$ßO­ÖI9Ô8YGþs©5õyÓ@‹ƒ‘Eã²/½‡*×­ß<vÝMëó¼L¾]SÜ4àhJŒô€ @ 9ÿñ¾ûîÛ“Z­’sd ô@jD}Þ¡u¹.^_LûÐÑÊè«NVŽ•«8D(“_vÍgÙ&ß§LdA€ Œ@Ö/üÔø´®Ö89À‡?üa½ @K aV'˜禷kÅünšâ½˜?Ï«O(­¼¼¬ŒÐupå[™eõb€KŠs@€ 09ÙÛÿÞ¸?ÅZ'çÈ:î²?›bcM¹NeFZeòÌ ì"·NÞ.å”é]§ÌºiL·PåŒ]~]ޤƒ @5?Ê^ÿ÷̨k0Gùäªgæ­ù¿³¨Þñ0\Ž‹@(ƒtQ-C«‹ÊÖ=+¿*]Ûû}ÉÕv¦¿ù&ËX2ÀHC€ IøDªµNÒ½ àѬÁþ$ÕF›z½ŠÆZŸ<¬lF§«·Éu¯éÜ—þ&§È×®webrŠò»Ê%? @€@2ž;yòd²3Ê“tœzô~1™GŠœõZ¾"3ìÜëe×ÜûS97>^²Bèå¶iù–‡.IÎ!@€ÀtdýÁgÓÿO¤ZãdË—/—׿…Tnjõ’aÖ5˜qçC–«‹Éu¯¥zk]Ûèey€">C€ I8±téÒd§ÿ«“uÜtÓM¯fõûדxL'PÉ2c­ìZS>d4-3dzŸõ1Y>ôõ%Ëä(n,_“<¤… @˜¬ÏøK÷Þ{ïs)×:Y€íøñãÿ6‹¤Ü€ÔÍ?Æ¢þk^¢Õ[q×ÐFV›<ÒÓò™ÎÌ0Ä€ @`24€ü¿¤^Û¤wß}÷á¬cÿ ©7âTê'#­*˜!W'm•¬©Üoˬm¾2®&«ìÞ¼k–GqÝÐ&O]Ù¤ƒ @5OÜwß}{F]ƒÊ'íPý—-[ödÑ¡,H9&†ž[3úÜkMÏc‘áêÝE§¶,ÝòÛœ›ÎmÊoš§KYÌhÓºä @ã$õýŽe}Ç>Ní›i¼àæ›o>˜5æÏ7ÃBê ˜h†]c‘Ñ¥mò¶©·åQRÆH ‰!ÙF3Ûäm“ÇÊ«ªWÝtE,_ñú¢Ï–§J§E2BÞk«Ÿå ©²!@€ÆGà7ÞøûŸûÜçŽOóvO 4·ÝvÛodÑ¿o‡‰\1hjÄ5M_¬£åW\'4M_GæXÒXÝ›èkyæñ­º_VV›<’cùL&3Œ1 @H—@ÖçûÝlê¿ìÄÉ„É8NµèßÍ⣓i]* H ì¡Ô2= @€&Mà¥%K–ü½©˜”àöÛo"kà{¦ÖȩԷh´55暦 ·¶õ²|Mêiyû &·‰LËãS“ÙDÒB€ Œ@Öïû¿ò+¿òÔø4ï¦ñ¤Bõ•¯|åÏ¢?í†ÜC¨cè™W'­ê[ú!¸ú,³)Ϻe›Üºé•Îò(nXДé!@€Àxd}½ßùÔ§>õÿŒGcšNÎpÏ=÷¼qî¹çj)Àq‘Ô6†œô2C°»–aº¶­k×òÝü¦‹{­ë¹Éô]?“ÛD?Ëã[—&:€ @ w{3€ìÁI†É9ÔÊ·ÜrË#Y£ÿw“lñWÚ 53ÜBU%´üPzÏ“kõ1~óÒ5½Bn™ª—ÉWÇâ}fÌ#Åu@€ 0jodý¼¹÷Þ{Ÿu-:(?I€xÝzë­ÿWÖø÷w`GÖˆ ¸>U²ì>ëÙ´,ã¢ØWè*³k~_õ@ @€À ~üäÿ;HÉ‘:Y€øgK~2‹žŠ¤-P£‚@C²¢È ·Ím#Üò†`1Ofˆ2U÷r»Ê´ümÚ†<€ @Qø¯½öÚÏE­aÊMÚpóÍ7Ìß–Çz`M 45Κ¦_¤žOY‹Êë½|L¦â²Ðõ~™L»Æ#A @€’ ðDöÊ¿>ðÀ¯'Q›•˜´@ܲ¥_΢ɽÿ±Ã3MÖ*°©¢&¯i¾²ô>e•ÉŸwÍÊUS0½bÔ)6V11B@€ #ÙÌïýê¯þê Ô¥s&ïÁÌ poéõ€„ˆ t5ÔÌí*'bD•ªU1¨º_Y@ËVî¼ì¡ïÏ+—ë€ @£& ÿ;3ãÿk£®…Gåqœ‚¹zõê˜NzCÏUQ2«‚ŠuÒVɪºoeU¥Ké¾Õ¹¾}r³z¹e² À¥Á9 @%ŸÊ6ýûíQjHi§À~à8™Î>þy Öˆõ@À µ> Ð>Ëò€& U̪îWU¢*×ûUå§t_¬€ @ UÙ`Î?ËŒÿ›jýÚÖ €C.[ p$Ûâ¿|å•W9—9M˜@•ÁØWÕM·¼²kîýϭΊ‡nùÌ¢(€ t'õã~ñÞ{ï½§»¤ô$à(´éÇ?þñ[ó7sÝñãÇ wøy†¡ne:.ºW–>Ô5ßzTÉëz?Wî"ížâ²Ðõ~™L®A€ ŒžÀþóÏ?ÿ¾*€À›Íø/2£â><ûÝßýÝÙ‰'œ»œÆ@`ž1Ø—n‹ŒÎE÷úÒÏg9VŸy2í¾â²Pç~Y¾¾®UéÇ €¾Z‚r @€€¯½öÚ,›Í½ñÕW_ýõo¼q™©iIÁpª=o¾ùæ+2ƒàþìãR]Ú·oßìÁœé!"ÄC`ž±éSC3 }ÊDVÜhó¸Ûí @€@SÆn¿e¹cýúõ÷Ýpà ¹mW•wJ÷qd­}Çw,ÏÞ ù@vºÖmü½{÷Î>ÿùÏŸåèÃuõ༜€móÚÃî—å^t¯,=×â&PÕžU÷Ëj—ú €ÔëWÖ¦\ƒ @ M'Ožœ¹K¸³³7Þxã¶;wþ»¬Æç¤YëvµÂq˦‰hwÈï*C('€–0 ŒNÿ×dÈú%`Æó"ö–fžf¡ïÏ+·Íõ*]ÛÈ$ @€@²ÓŽ;v–p9²~ÝÞu×]?wÖÍ _˜¼à–[nùñl$ìÇ=Ï>ûììsŸûÜLž$°dœšXdÔÚ½1°­Òµë}—,#ä. Î!@€@|´g›;òïj¨~a6ЫK?sçw~̽7åóI;´î?kü_¨óhO9ô€aÔ!.ye%Ø=ÅŰèžÒÚýb¾.÷Êdõ}­ŒEß:Ô-ÏÚ û,«nýI@€ P€gOøs3hi€œ™ýöo²™}n ݘ¬àž{îÉ–ýŸûKY[¯¨ÛÞ/¾øâ,{EàìÈ‘#u³Î3> CŸ*/22Ýsu¨JWuß•ú¼J—ªûMô«’Uu¿IY¤… @ˆ‡€ ÿº³³Oíp^Ö7üôÝwß}y<µF“É:zè¡ÿ>CþŸ5Å~èÐ¡Ü pàÀ¦YI:Âp|ÕU²ªîû¤PV3}|F @èN@}6­÷oúºöSË6dþúÇ>ö±ÚÀÝ5ŽOÂ$úЇ®É:÷÷´mÍøõ_ÿõÙSO=ÕVù<0®Lì¢{J_u¿Lfª×Œ…â1Ó{žÎU÷çåã: @€@ÔŸ{ùå—[mΞþæ4¸îèÑ£ÿg5F‹):2ÛÿíúAäÚmòÁœ=òÈ#]Ä·!߆é"yf4.JÓPýÁ“÷Y'Ÿe™¬>öYVõ¡ @€ 0v¯¿þú,3ÜgŠÛÍ# ?ñÑ~tá&ðmËC¾É9²]ÿ$k˜÷ûh=@ôG4ûÒ—¾”"û‰ŒÅdœY0Cͽf÷úˆ­ü>ʪ[†éÔŸe™¬ºõœ—ÎäÌ«Õ}W.K\œC€ ahàUÆÿ)㽓¶o@ÖÏû7Ù~Wu6ÒÌKFªw+µo»í¶u™ð›YæU­Ìɤ×ê-—\rÉlÉ’%§ß`„ÅÊnç—][t/tú!Ë®S7éwÞyç)éÁô¶Ø½i×,.»§kvßâ²tmïu‘ïêÑçù<#º¾dù’£:TÉ’‡¹‹—¹ 'ò@€ ¼E@›ýUíôÿVêê3õÿ²àuhSÀï¹úê«ùÑG}k„±ZÄèSLj@ÖÈ?›µØÖ­öÄOÌxàÙÁƒCˆGæ)UF›P*£rÚèjºÅ¦ŸéÕ¦Nn“ã£~Md•¥-sö¸ºr@€ †€FûµÞßFì}–"™§úšÿéùçŸÿ}ʃ¬ÉÌÈFÿ/Éú—³F Vgy§üñÙÆgëÖ­+Q6£Âb=$v^ŒËî•]³|e÷Ê®-J¿è^SY!ÒK¿¥K—JôinÅóü¦sßêd±Ý/æ+Þw?Û¹Åe2Ý+–Uüly-vå‡:?õÅJ|©\Ÿe6‘Õ$­)®Ñ½;–@€ Ðõ¿dü‡œ‰©Yš¹…÷íÞ½û7~øáú«á°%Mf@fhôÿüиµ¹ÄïüÎïäû„.kŠòÛrÆIyí°kMcËßE¦e~¨:]îÐÜ)€ L€Fç}­÷_ÄN6Û©þü²,þx–öœEéSºl4<&HÙÆÚàá³£7‡Ç3Ï<3ÓÞ_|ñ,›Zr‡ðZ¬v^ŒËî•]³|e÷Ê®-J¿è^SY¡ÒÛ®®*KÁ½fç¿™âÍ¿vÍâª{uÒ-J#ùÅûîg;·ØÕ§íù©/µ¶Ù[å¢L)Z·Üªtî}M=c@«Ç€L€ @ õÁŽ;dÊÿ"ENÍ,¾ðºë®{"›ð‹Ò¦r¯7ƒx``?Ÿ•ÿæ¼ñyúé§g¿ök¿6{òÉ'{,5ý¢\#-¦ÚJ/;Úêeùû¬c“2›¤­bÐD–¥ !S² € @ÃЀˑ#GfÚí¿Ï r­˜ÅÿâGôG×õYþPe%ïøÐ‡>ti÷o øøñã³ßú­ßš}ñ‹_ôòꊡê1ærë‹êèCÆ"ù)Þ3fŠ}…2çéæs6Ƽ2¸@€¦J@ý:ÙJ}Lù/c¬ò§Ã–lYÀ?-K—ÚµäY'þ§²F´žz¸äÐ[:”Ú3Ô{}ÄSA±m•°ü&³­œ:ù¬¬:ië¤ñ-¯N™¡Ò„¨‹ÉT\,mU:îC€ t'  þ4êïóm´r²+þëú¡º¤œ1åÔ0 êÆo\“9þNèrêÊß»wo¾A`Ýô¤+'PÇ SξŒº¾Ê)§Q}Õô«Ã-TÚj-ÏLJ×3K9ûS“úŸ›+€ @‹h†¥ŒþÇÝå‘î=õýœ=Ÿ´qÛ?vï§xž´ Û,îDzF]SýÿýïÏ7Ôk'˜bܾeêˆí¥Ÿ™³Ï²Î,9ObX‡cÝt}áÿ³Ê”@€ÀTèUéÙòìÓ¯ôŽ¥Þî,€¬ÿ÷c?øƒ?ø¶Xt ¡Gꀟ ­­ÌË/¿|vÙe—åÙõîIí:©˜ÐŒ@C²JbC³Nšªr¸ßž€ñ¯ÓÞ–¶ª4KWGf•,îC€ TÍsýõ×ϲ7³Í¶lÙ2ûÀ>P©ÇZŽ ·? çeöÙÏØ‡ãÞwÆï bæ]º&kÌ«b1°5âÿ}ß÷}gU_×õÀ9ÝYi¸PŸ€kØMe×­s©¡Ó6)¿ª.e÷›Èo’¶¬,®A€ ,&°mÛ¶ÙûÞ÷¾ÙÚµkO'¼êª«òW¥ïÙ³çôµ¡OäpìÆ;?úÑþãO}êS{‡Ö+DùÉ:–/_þÎzŽìÉÌÞ-yƃïfÖæCNŒ—LùyhF&¿ÊP'¥QMɳtn»VNaüW›Ô¯IÚñ“¡€ @`Ü–-[6{Ï{Þ3»âŠ+J+"§Àý÷ß_zoˆ‹…ÁØeYŸüc™?7„.¡ËLuþù9™Aý·eLÅpd{äÿU)'€fšXe$ZšªtÍK'‡͸‰ü¶i-ŸÕ‰€ @ Ù^Zöüáx®ñ/I;vìÈ—FÇ`«™® ëþäwÜ¡M“ IÎÈ6nØMãØ ƒ:†pÍ5×ÌV­ZU[é2—Ø4 –^ÿÜ„·—·®”ŸÕMWÌÝ$_“´Årê|-¿Ž¤ @)Ð&ï}ï{óuþuêùîw¿{öä“OÖI:DšíÙÀì-YÁŸ¢ðe&éX³fÍßÖ«%b2:ßùÎw6VÅò|0[°á8ÐGa}•‘Ü €þá^yüøñKbqèŸ‚àŸ€Œ2†½kÜùפ¦uËvÓ5‘_7m[ùmó…Ö«®|7]躸eÅr>Å:ÇÂ= @c' 5üÚä¯Ë@§¼ímo›ýÉŸüÉìĉQ q÷È:?[p{ÿRÊyR"9ÀÖ­[oþùç3[nøõÞçŸ~þŠ Om…˜\£Æç3`r}ʬQä’ÇPså»ç¡ÊC. @˜uëÖÍÞõ®wÍvíÚå¥ÚK—.Í7|üñǽÈë*DƒÈ'Àd2qt2¶ãþ­±Œþ_zé¥3=Ô¾ƒ6S5F­þ]¸šŒ”Z›pj“§‰ü¶iûÒ«¯rÚr  @‚€64¿þúëó{ßýg½5à›ßüæÕ:«Lõ €÷ßxãË|ðÁWÏJ<Ò þ­ÓAœÓ&}Ù ë Õ” #»iÏž=AË©+\}ôBŸñofyÿ nþØÓ%åȼS×þÞïýÞ’ a­i»f›‡F©¼Uª»Ú6Æe›r‡ÌãþcÖ©oÓôuëfrëèPW¦Ït¦ŸO™ódµ-«m>Ó£Mþ6y¬E½“qd÷.Ûô®Xɾ?Ëø/{púÖ£ª<ú_l+=rèîúçC\c­Ž¡Ö4½ËÉòÖ)ÇÍ7µsãÔ¶ÞCço«7ù @€ÀÐd]rÉ%ùTÿõë×­Nãò¥ ¶Üœþþ¶ÆŠ4C23²†Z!£5†‡&Ò¶®¥–í ŽÚsÌûÔªpd‰†6€»–ïgW]†Î @€À<Zßå•Wæëû‡|•ß<ýê^Wß-[NöPIX^rm”—’qdô—Ë0ÇcÓkãèáe9BÛŠKÿW^y%ÿ'ÔŒ€XÖäX}šw–¶é³aùTfÛ¼MóYýˆÏ$à¶Å™wê}êš¿^)¤‚ @ýظqcnôkÔ?ùkÍexGÜw^rã7.{ðÁ‡OaGÐÉ9byøOœ8‘¿Ë²cû ž]޽S‡f舅ñàpW «ÑÜ5¼1ꢞȄ @ M2wìØ‘þÛ·oOª’²Ÿb¶3²ezÍ€ˆžºó5]=–‡æøñãI8ÜöÕ?¥ÞÍ)Κ^4†}\ýëž›‘±²VU¬µNdºXܶ¸®ùÝr}Êrår@€|Ð+ò´“ÿÛÞö¶Y¬¯ïZçØ™yA×:Æ?™ÙHõ91Nkú|ŠAF“œ:äl‘#@Üû6–ëo–¦/ݬ<µ{_eöñŒ¹õòY^W¹]ó»u1Yëž{î¦å€ ôA@ýÉmÛ¶å†ÿE]”Tÿ²ÈOý.Í8Ža0W3 ËB¶aú9e×Çv-€ÀÇä8zôèØž…ÆúêŸC3äì°YÚ+`ÈàmMpËÛ4Ÿú–•m׺Ê÷%Gzø”Õµ^nþPz ñ,¸õ yŠYH‘ @˜ðk]ÿUW]•ìh±_~ùåüR €9›Uíçä±tØ92Ú‡¢©â2$lV€9úž`ÆLÓö·|ªsÓ¼ÆÉd´ÍorÆ[Ý»êBŽ/™]ëF~@€ PE@KkwîÜ9»âŠ+f[·nmÝ/­*'Öû‡ަÎz5zÊ!)€gt5Ò,ÇAW–_´H7Ý` Z³`Ÿºú”U¦~hùeer € hÆì…^˜þ[¶lHFàСCÑ8dä’š †Òˆ³Ö¥Ç<8Y€Ëß–ÈÈ•Àœnš>Î]ƒo‘Á݇.1”áòˆAŸE:„ÖÕ•ïž/Ò‰{€ @ .õ=5µÿ’lm¿Œ9oÐ~b:b˜ »…#{25@¤Âþýûg_|q ªD¡ƒ +› p½A g€t>Œ~“% >äEÑ0”pYù*•9ïú¯:&çz’Q‹a¦uð:R}W§ ¶ÁÞ  Ùò€ê QGo¨ ÀXÚº 3\Ûèny›”W•Ö•éžWåkr?”Ü¢}•S,—Ï€ @À¬\¹2Ôº~­ñ',& @›~ñb©íîÆ2“¼öõr%çÐzs94}#† Zïí$Ì' i6zm¢önPûi‡Žª/ÛìQéì°©CúlÆ`•œùš½uǧ¬·¤NïÌ8öQó6eµÉÓG](€ ¸ ÈþصkW>Ú¿iÓ¦Ê~lܵéO;0µ>|%——Ã^råšù»šœ@h4âË.üûöíË¿ by¨ý=:þ%Éø:qâD~¨ý4#@m©}3ÚÛ¹Ò‹¹ÿ/’S¼çÊj“ž<²$ÛÕ¯X–Ïc—ï2°ºXìÞ〠´! +ýìÛ¶mÛé~gYSͳwïÞh¦ÿkpQ‰ÔC²€X¼7z´ÀæÍ›S–¼ÖOKÌ#¨÷¢Öu¸JÈØÓa·b;7‡Œ}vóq~&>Œf+ÃbiàžŸ©‘ŸO®|÷Üt¤@€ " LíØ±ãô¡~*¡Í–dýòvRüåúÿÛ{¨=ŽòÎSÑÅWI–,[²1b°3ÄL.a„0°ÃÁÉÌ„lÎÙ™awÎfg†…3“ ÞÃda @¸£€™‹í&!™œ‰ÁŒX°±‰llcÙ’¬‹å‹,[²uµ÷ù·ôÈõ½î~ßî·oUÝ¿:§¾ê·ººê©_õ×]ÏS—Þ»woëýÏæ¤?§AüÛó±têwïÞ½ˆ©@óߤ2¢È #¯„VUàýžAλq Ì/<žWzÏ_×7‘_žay盌벬Pî®Êíªœ°nC€ 7Mï?÷Üs³Ýû5Ò‹Â7µÙÒi¦´\,›\½ƒ4HÑŠés€ú¬…¾L°zõêz­ÅÕ‹òf”Ý3`>Wüº¢®0<žv},ç¼]ÈÓeY^Ÿ°ÌðØÏ7¶“²’ @ÍPÿRJ¿FûzŸ°ÙRÆ››ø4H Wõûzè¡Q4È j9í¾ÓgvîܹhÕªUÑÜäC¸»Ã™¾L@í>ÏÌ€"®úŒÐ( kŠZ~]Ñù¢òR÷úö%ßå÷UoÊ… @ 9Ú{ê¼óÎËFú׬YSØÏk®Äñæ$å_ýëXFÿ¥ükIÂÜ` R¥Æ¢è«º±ô0Á5O`Ò ¸Œm|2¼§tìJ~øó¸ækZ>ÇPÎòW==¥êR6¯Ét“¿Ÿž{³1ayáqÙRªÔµlž¤ƒ Ð$žSMÒ$/,Z´råÊl#?)þ¬ÃµO@z‘¾”öÛ/uz Ú‹`,n°½ ¥Æô-Gír© ›…´ûï%c€ÖðÈëÁ¢)\nhóAS¤pê^ìÓÉUV¦y¯¯ócË–ÝT:/×ÃÉ|‹â•ŽÎö$-~C€Ò% ~¸öæZ»vm6Ú¿bÅŠt+“¨ä»víÊ$o³_^FþÇ2ý_\kPå¤ôÅ´ @J†ŒZK„놀¦ù‚²4jF€f}^°) ó”˾Œy²4UϪùô-KQùïaÕz‘€@›x6µI—¼‡J@3ƒ×­[—­åW¨Ï÷áú! ¯|=òÈ#Qþk3B_îÛ•nK´`éÒ¥Ù7ä5Í$§Í5Õhùò屈49ÔiÒ†Œò²òéá¯e2h–@—Jù´\WrL“¡ë›Âeñ°ëò)€ áP_J³nµyŸ<ûpÅѶR²wìØÑiŸ»LÍ·oß^&Ù`Ò Ú V’b§)á19M{¹à‚ ¢²|Åħ+Yd’AF^S|f€Œ3}.Óp%8 Û4 x9]q/[N(Wx\özÒA€ 0šåyöÙggSû¥ôkÔ´kº},SÿEG3„588&7x€Fy5 ¦i’Eÿš‚„‹ƒ€Údß¾}™×®¤ziÈà ö-¥+À¶%OÛùו;”/<žÌwڹɴü† @ =>ʯþô9眳èÌ3ÏŒnd9=ªíI¬©ÿ{÷îJùWm·mÛÖ^¥#Íyð=4 ¦Íu/hƒ:8³ñH|ÿRu¿ÈËP£Ù>;@í%ƒR Ε\%“Ž›š-àùzC‹dp=tžÞã=ôxB@€Ò! mÞ'¯ü4ꋟ€Fý5ÀÓÈ¿¨ùLàø 6+ašL³uzZnÚìMÓ½cš !}Sº®6£{"J¿* å¾w€Œš%ДÂ]J˜‰\É Ã¦dô<%Fx\B¬è’„òû±‡Ñ ‹@€ ‚/E_Sû5Ò¯\z|“½Ø wÝuWz0xqÒ$Æõ²†é«±ýC4po 6‹pï)ÖzÉ ¯Ù&1:Wl=lZFÏ׿óï#¿!Õ¥~” @¨J@³,5•ß×òŸqÆÑ ´T­ÓØÓkãmé`M F5ÅS±cúô_Èm4=P¤dÇ6 @ʤŒZ»„K€”DÿÌ >ñ¨ûLÓÓd Ð ˜gw¸‚ë¡è븩ôd¾éµ.C€ Ð&õ9¤ä»Â¿fÍÅÚÞqÞÚ_KëþctwÜqGŒbu"Óh ¢©Ý´ElNkÍe…Ò'\Ú´ÆI:Øéžsƒ€Œ±ì0²+îaصQ@e{ùÓdå @éÐ`œ>ɧQ~õ{¥ð§Ð7J‡p<’jÔ_úMŒNÿ=òÈ#1ŠÖ‰L£2h37=d¤¤Åæ´) Ö–Ë Š=üä|ðÁ¬Rš C€Œš!Âæ5Rþ]÷P•ÑqÓ†0ÿð.ðx½|OÆ{Ü?µÜdÝÈ«˜À¡C‡²ÎMõÏŠKª~F³¯ï¼óÎêèŠQÔn‘Õ”íoH­CÑCQ "n˜ô@T;ûš#ßPpåÊ•Ñî!0íÅÏ…aSFyî—C׿‡qóäÏ5€ P¿F#üRöW¯^yö¹*æ5Ä3hÕ²Xm¢£“ò¯þø˜Ýè RN4 {ðàÁ(Û]»dêAÉ.§Q6OãB… *s½8eòY)Þ®d{¨zé¸OÀd˜t“òùy÷Ðã !Ä@€gS ­€ N@35ªïžMûœÌ8C)ýúbVŒ³­Õ"šö¯éÿcw£3¨Áõ°Ò«eJ›êû¦)*cÿ‡ª[öìÙ“yå¥%+nÐý ¯ ĦH—­³:­aÇUǩ֥lI@  Più¢Fö]áõëGCažR=¤Wíܹ3ûôzŒrk#ø[n¹eA_4F9»i”•2¥u÷1:)F2hú”ÖŠãÆK@†ª‡~8ó¢ …Y/[Ý åSØG ¨Ý 0b("F< @ ê_h:¿Fõ¥ðKñgý~7ìS+ÅGþ5«ûñ¼H_%ÀÙãX!HÁÐ~Ú -F'…HËä0ÄØBýȤûB_²¿f¡en aK÷Kê ´êéF‘Û$ßU9mÖ¼!@U H±×~DRö}Ó>õ-p˜E@ÊÿŽ;¢ö/ù5˜vÏ=÷̪ÊhÎÖ Ö^auŠ”ÍÐΩz(ã G@ÖVyÿœ‰”ÝÛ2È CWʳÂ:‡ zx¦)s\åÚ*iË”M@€@ßÔ?Ј¾+üég³¾¾[%½òµ™ž6ü‹U—QÉöÃþ°³Á¤ZqÔ5€š¢u!±:}BN7¯¦_á 0‹€Vmr)ï_Ð^n A@Vý!½è]I÷PŒòŽóâ´Eçg1ç< @ FÐ;_о“|J¿ú8Ô! ~fÌ»ý{Ý6mÚ´`æ¬Ç9ý¿?õiÀ˜ÝÞ½{3…F³p¨J@$ÍðYº^/BÏÚ¾ªdI@ˆƒ€ú´šý'eß7–¯Y84I@KQ5K98i2ÿ¦òÚ²eKöU‚¦òJ>£7¨!]Šu?¿Ù¤¼I‘Óæ€C½õúvK@÷’f¿„¢È Ž‚/P¨=ÆâÔyŠýe6–¶ ž€@>žSù\Æ«~ föiTß×î+Ä?¶;¡ûújõx û‚+–¨ÁÓ;âUãHŽàx;KÑÑ&1ï^)QeqÓFçœsNf¸ÇmJ-»" ÿÇ<ó^¦´€{Fœ! n `¤ì–w ¥é=¬Ïïù¨¾+ü ÅÐ:ã‘AÏ-- g“ÆZ{-OøÁ~õï>ÙaèkÚ” ±/ŒÛ·o_´nݺl¤6¨‡hœ@žQ@4;@¡ :ÖÈ€ êôÕ¨¾+ú®ôk ?ï×ê<¹¢9Ú+MëýcŸ-­KÖ›nº) Y›k¡j9a˜à¥™šb¯©-áÔè‰d½ÿÔͽsçÎl3í⊃@—tÿMÎPù>[@ÆÜ0Ð¥l”@ˆ€ŒçRô5øä!SøcoµqÊ—ÂNÿÞ2š¥ Mÿ4ýWLÀvjÀsžóœÓíc¶vé»–úÇd_€‰†äg/òf HÜ»Q ÆuŠL­íå¶¡P@ƒ% }¦|Dß•}ì눃@ì´Þ__#K¥t×]we¤±sí[> 9- ÍÑî¿ÿþEk×®]tÑE-Ú³gOv3)>FçûÈ ‹2±в•Éý5´ŒÀê ÉË(£a 6žÈ@qÐûL ¾|8_ñ8¤F@ 쳡'™nÛ¶mÑæÍ›'£ùC@EiT]]è³{šb¯OªèA†rÆæ¤\iIÀ™gž™í›|ÈIZF Ù5“3ldÀnPˆƒ ôE@ëðµTÔ}­Í—×?Š~_­B¹M$}Ga*N:Ðm·Ý–Џ½ËIzJh³¦ØëªRJ4#ଳΊÖ k¦éHnÉÉHê”ÆåT´dŸœ1 }†€ÜPÐÔæHÊ'•inÑ6 ‚A­à9Õ*Þ,s½c¤Ø‡Š¾·_:%@ ?Úá_ )õ…¤ûhÝ?®< 3Xi#@½dÝ•KÁ %úJ€Œš††ƒÀPhöü¤UZÿ—ú?uÏ"PØ”q`( © 6”:æ1“Ö;C£ù>Нþ’{ÃA’{P@IDAT`LÔ·ÒLgé)9-ÓæsÕ[Œ'\ fÚIÒ_žÜ šr¯i2²>iÔ2§d}®Ck$/C% ÿ½I£€×UÜ(àÇœ! að¾›+ú“á0kM­ P€6?—#Ý!%'åÿÆoLNîc(Ù š£%“Vaý>÷Üs³]øõÏ#ëYLÿ@ú§>xð`&Ÿ^|8Œ€FËŠ6ð”q@†÷2x3Æv§P_@ 5zvkí½Fñµ ²Bõuä5š¯g:È' }Eº‹t…Ôœô²›nº)*+%†J¶–”ôŸsÎ9¹SŠeX·n]¦hǶY ”mŽ¡e š±À ±d£“lðô­`žÑNy7 ¸a@Pøü­A!HÁ—b//¥Þ]Ù—ò±6‚†B„äHé—¾Óìå²e´¸ù曓”½lÛN‡ aý“¸ èF/+ß,P7¨Ò>V(º‘¤ÚÏÀ7do€F’É€ È8 _ô¿îNýÏëxÒ Uƒz$ gžMCp<‘/ï#÷ =Nо?k‡P_ê¾ H'‘â/} E·{÷îE?üá ûf)Ö©™1T¤®­­×L€¼QCÏNJÁÙgŸ}FPÓTdÈÛÕÜÓwJfÉ/€>q8¹¤¡+9(©ðø´ç@hP}½#ëxÿ: 䇺#àÏžîJœ¯$½•ùp_ÇJƒƒº! =Íôu³¢n¤˜¿mp®Oý¥ò œ¿¦í_‰`ÆRäe’`–R¯—›6ᓲ­Ok躬nÚåSß__¹reö™C‘9n.À zI•yQùÿŸ‡ÊV×éw™ëgˆÁi@Ðs)¹—‚¿lÙ²lÔÞCWú+”Œ ¹ ¨¿¯QÿY:ËÜtpáÝw߽讻î¢OÔk s‚ÔŽãI×€:žÕI× óŒ3ÎȼÖÝhF€ }:Ye ”1@ M»ÃAÝð燇.Áäo'„ Ð4 XhWèCeÞ=lºlòƒš' Šš…¬%À©:õƒn¿ýöEÛ¶mKµ QÊ F³hwý]»v0”R£OóÉk&€,rRÂûìèË€¡M%“6 dY@›‚K!Ðp¶@x¬âýy2+ìHTŠz" ¥^J»Þë>j¯ßRôõÛzýÖñ䳤'±)¨A@ï~ 2ê3yÞ¨‘]o—Ê€¡õþ4Å5K@MžšVã{hjM• ÿô¹šóÏ??ûz€nný£–5"Ô;÷rÍLÐlÿZkór1 è x'ÞÃ"½c>wç¿ê·§+ʇx@ }ú–ÒîÊ»+ð®¼ûo…~ܾT”ÄD@}yé)O÷OéW·ÜrKï³¥cjÛ&eÁÐMäûr½ˆ53 ŠÓt»óÎ;/ÛS@ÿ´}n¨Žþ£>š´dA{ÌR"ªÔ•´€@<ü[Ï­2Î nÈ e±÷x7 ”É›4 P‘×ÿ^襸çýv¥ÞÿgÇŠzBåH÷Ðt)Ω;mV(忪>•z½»”@C´5r.#Àºuë2…yž@½ôµa ¼¦îhy@_ëv|ÝŒ«W¯Î–4„Šl D ¸òáaÙj¸A@a8» 4ø¹0mW¶,ÒA MzOkvœþ\Q×ïÐKY×o?ï¡+÷UÿÚ¬yCiÐ2^ J‚Û±cÇ¢ýèG'ú C¨SŒuÀÐ`«hÚvù—À×ø{g·j1y—ï{ŸM!Rô¹íÀFU[’ô€€Wz¤ Íã& þÛþÛCözÆû±BÜ0 ¸’î¡ßwþ[áä±Ò(ÎüãaÒ¢V€@j4P§‘r á]¦:Üyç‹¶nÝšZS$)/€†›M#öꮨOã;«i²s€@ªôìVÿ_ŠmqÓò)ÿ©oZØŸ¶òÅÐY­×?ëÚµk3%Y+MçŸÖù*#ŠF9¤xË+?Í Ð?OÝ|Ë”¦ÑLdàÐŒ !Ž!4G@Ï}ùiÅ|ÎAH“€ú÷Ò)4:>$Å_Fë{î¹'ó]ë0iÞ ÍJ Yž ró üd@£æÚ°)+—”ïg>ó™ÙÌíü)¯Ù]9ýÃjÓ"0tEr @€†L@}ì!Žø«Í¤ mÚ´‰)ÿ=ÞÀZ†¯QòðëR”µ°”榜ò“‘A^F}=@®œd о«V­Ê6 ìª|Ê @€@ê42®ÿ¡Mõ÷vѧÎo»í¶ÆC=_Âj0Tã5Wj)ÆÚI_ º¦qj=¿/ hz:fÈkÏ_ÐtÓ ¨®n`iÀ4Rœƒ @€À±e¥ôk¯ìž.)qÓ†èÚå_Š3å¿ÿ–ÃÐQH)ÖLmä'#€ÖkêSRÔën˜W}¶ïÏxÆ¢sÏ=7{˜ÈàKòÒ7ô9CÍ|ÀA€ @ÇH1–Ò¯Qÿ!*þª¥–(ÿèG?ʦþÓîqÀÐa;hÚÿ®]»²ü}Ã&)êš …¹||Ó@´a þë|š° 27¨Ž2¬X±bæfVUò'- @€R" >¹ÿ.çºæ£È÷ØF[¶léºhÊ›AÀ @MŸÖƾ'€|ƒÀ¶fxdl?%Øå¬m|¨ò´‹©To @€Æ@@{ƒIñ—>0d§å Zë¯@\|0ôÐ&ú§×L)ãnÐHý)§œ’}NOÿ,m®ÛgHÍÐÌ€6ËtÌ*CeÉ %šÀ'! @€Àh†¯Fú¥w5·/~ªŸFý·nÝÚ—”[‚€ÚH¢Ñ~m„±nݺl €—!ƒ€6ñÓçüšüR€ç?Êèà{hý‘”sY&ÛÞ Cùëa(/dÐp€ @HÀÖ÷‡m¤™¾·ß~{+{›…åp\Ÿ€ú çÎAÓâeÐL€ÉQðpo€.¬…š ©ùò’Ë÷ !¢m§Yòb ò53ÀgF´]6ùC€ @ )ÀÓ`ÚX¦¿KW¸ãŽ;é¸4`è¹4%^Ëô‰@„‡ÎgH!×äMÃòüXöIy­Uò)ûm—¯È<í ÙÚ0¯x«B€ ÄH@}dõ™5Í_ýö18ÍæÝ¾}û¢»ï¾{ðK†Öž"hQ=4´1àÙgŸ; ^ ¹¼”w)²Fãåõ9A­Û×~m/MÐEQyÕ[†yftÙò”@€ 0€–ôj ­–´¶½|vš]ŸÓ ‡;ï¼3›éÐuÙ”WŸ€ú ÉAÝ»w/:묳²=ò2Õh¸¦ÉKïÚº¨û׬Y“y"ÜÐöòÕÓ7)dV@Þ]A @€@W|´_JpKe»ªW™r|“¿{ï½·LrÒDJ@d £ 4ô`ѦxyÎ?(ÅXk‹”¶k§¥ Ú·@^O-Д§6eaV@×­Ly€ @N`¬£ýª¿úø;vìÈvøo{ðÏy¶G@{lçÎY µöX½zõ"mΗç45^F=Œ4# ¯iGúb¼¾$ K¨d—Q Mç³üS‚*rÿ„6Ë'o@€ áP\ýZMóïzöm,tµLyóæÍìîKƒ4 € ¶‘…4²¶iÚ}‘@åJñÕ4-¿íµùÓê©™ 2XÈË(!C€|›Kñ'ù¥K—f{h¯Gp€ @¨J@ƒjše+Å,;ùç1Ò@›õ³ûhÌ“‹¸ú0ÔgØZÚO–Gm8m<´?€d èÓIŽp‰€ Z" º´å4IeÈ«|Í Ðæ…2Là @€ 0€Ò¤ô«ÿ=f…W´³?Ÿõ›v·¤}@äí§Ñt}&PFm8ÍÉH ¥W °,–m޾O“#<çKÎ;ï¼Ì‚èJz›ûˆ™¼öSaD2hÁiF”PfŽ!@€†O@›øIé—os *’Ò¶nÝš}ÚoÌÚª®Œêìàznûgˬu×tø•+WfŸEИS‹Ð,É$ïûÈ }Út²bÊ«|Gd Q@€ 0>RôÕ?–Ò¯£±; Êmß¾=SþÙàow€DÚYÿœšŠsæ™gfŠl±µ~ÕªUÙí¯/äÉî k£ Ú/@Šz[N–L·ðÊ@âKfͪhKò… @膀+ýRü¥ô3Â}lgÿ;w.Ú¶m[ö9C˜ts/ÆP €Z¡¤ úÇÔ´vYçŠ>˜—•o¨iN2Ä4ÅIFгÎ:+óÚ»@†íÐæòñSò2hy€f”™]‘Ç—8@€ ¸hðLý^)ý qÇHŸÐòâ-[¶dŠ?\ÆG@‚m®ióRb5`Úª)ö—! –¥¡ŒRÀÏ=÷ÜÌË ½í/ ˆ£xʇÆq*Ë6¬Ç€ @ýð‘~)ümÎ,í§võJ-)Öˆ?Kê±Lýj ‰¶ äkô¼êN÷šö.«!@M"c@ø%ß

-Xñ†%9 @¨H@£Ö¾—•FûuŒË' Ý`ÇŽ‹î½÷ÞVËòK'6Rh¥2ê¡øÐCeëyV¯^=÷µÖ½ûÒ=\c¶j^!Ê»‚îÆ=øÚrÊÛ’AF^䵇€ @ >õï4¥_³?µž¿Íþ]}iûÏAýv)þÚÙ_3$˜êß›Ä*K¬-3‡\¾±Ÿ6¬º/€. ðéU±¯§Ò(üÊ•+3ߥ1@V½äõußDPÆX*àw! @˜M@}Oõ«4¥%v63õÿ¥ôkF°úÁ8Ì"€`¡ÄÎk_=Ö¬YSy_€ÉªJ¡ÕûŠ+N<Œc°ôe ;½´ü‹’CûÈË 0¯Af²Mø @€†D@}WWøÙ¾\ËÊ0¢™¯ñ׳0””ãFªc0 ðNЩûï¿‘–Hù¬ë¤Ìúnø>+…iX¡1@ÆG}ôÄžmË/C‰,²òráReË–Õm®‡ @IP,å}p)&Èb¥>þöíÛ™!SÃ$& €Ä¬¬¸RxeÔz â71]yÈ  Qm߈%K­d÷en ðÑzÜ·íd8‘×^ š ƒ€Ï`é“? @}P¿K} )ý ù]õ–³]»ve>æ=ºª×Œ+ú € ê–© ëô ¨³/À¤¸R¦µa ¼”grë¡žŠ ’Yòûì€. ²|‡³dpc€ ,’@€R% þ¡¦õËKé—W€ú‹RüYß_WÀPÌf0gd5ÔƒCK4òܤ“òºjÕªûèA•ÚT.ÿ´à9眓½¤´¦J^/¬.œ^’2@È»qÅ 2²à @€@ÌÔ—ñQ~)ý©õcb+cÉ<°è¾ûîËö–’lPbj¡ôeÁ~–ªÄÚ©^úi*|ÓNÓÚ—/_žy¢kF@J³œ‡ $òë֭˦¨i™€Œ2ltá|šœ^¢ZÂ!ƒ€/PˆA ‹V  @€¦ðþŠOëïbå4y†pN,5`'Å_Ú"€ -²‘æ. Ð&ym8)©RVehÐÃLÊsÛ›îµQ“N:iÑYg•yÍ¢ð=TŸ®,±*G åå|ÿ7`h£åÉ€ €’|€G¡|W}¡PŽ¡‹«||´Ÿ™Cká8ëƒ ÎviU*=´ý+RrÛr“³ü/m•×f¾¡1@Æ RÜ Ð¥qcrÿ1vƒ‹Œ’“=ڼȀ 0|êo¨¿¨‰òlÜ×l›‹©FûåÙÔ¯Y¶ä6›€ÙŒ™Bv­/Ò(½¦î·í\IõMaRÜ+ÀIéÖ—äeý]?ÄÕŽ¾ÉŽä›40CÀ[€ "á~)þ]÷gŠäRüäh?3(†ÔºiÕ@ZíÕ¸´ÚxNzmä×ÅçèT†ŽOÖO¦ê4Ú®}äÏ;L.š ®ª[×nÒ  e2hSA…òÌèºU(€ )øê¹gÍy{í£eœtóÑ~ÿöX“s9Êqt*MëÒƒIFM#ïÊùN÷RZ}¯€Ô-Îâ'¿víÚlºœ ¾‰`|Y›Ã=¤ü»!À— taøéꞢ@€PÿCƒ=>¥_¡ú^¸öÈ ¢Í·µäV3Eqˆ‰€˜Z£GY|Z’”rMmïr”8Ü+ \"úËIëñ׬Y“yñõ¥2 ôeèP'À­ý2LÈù²ÉëŒ.Û¿ÇÛž¢!@ƒ# þ“¿ë5È#…¿AˆÁQ!1VßJJ¿6öSß `ˆ±Uz”I£ÅR»Z0YÕeË–e-ÐKKëÛ»ÜuRž¦~k*¾/}Pžz1÷¹T ¬—: á>:§vpc€ ò8@€â" %Ó•|õ-Ýï¾}ÔOÕLZø÷5ÀÓ}­)1eRn½–d÷iKZ×~úé§·TÊôléê2FÈ0‘òW&këʵ– ˆ·4K †™zÉk¶‚œÏÐò_:ÐÖg$'Yñ€ cônö©üRøÕ‡`t¿û»Cì¥ôË«=pH‰€”Z«CYõ2‘Rªœp)€}9)š2DÈËÒí£Õ’mNkðÏ<óÌÌ«>²$Kñ–—á#—7KÀšàû ôyŸÄÀ  @MÐȾî{ˆ²ßÝêùÈØòÐCe#ý°¡-ª3äŠ8`ˆ£¢•B–fY75}]ûôíd Ðg 5;A²¹1@/Æ¡87vœsÎ9™UÙ÷a ¦õdyF-pƒ€/À(0”;“z@€@¤Hº²ïоBÌ6hWËSJÿÃ?œ)ý£Mªñ#uœ0ÄÙ.QI¥‡zšâ$C@, ï M õ€öeC™ ›ÀGÖµ™ ÚAØf„7«Œ2ò2V¸c¦€“ „ ±л\ïÉPÑWÿ Å2ž;CRú5Ú¯MýÔ6´O<íƒ$õ `¨Ïp49è¥ NdÐ:𘜦Ñû&{2H•²<¤uYÚ!œ zÊ ãL,{äÝy3B£€f øÌ¼ë‰ƒ ¤H@ï?Ù—Ò¯ …¸ø¨]´s¿¼úV(üñµ5G@s,G‘“ˆ²†J±Ö4ü7‚“1@³´w”ddÒÌÝlªçêÕ«3¯v‰}v@ø’gCurƒ€f?èXq8@€@¬ôöQ})ü:V?Iï:\¼ÔGTŸVJ?#ýñ¶’5O€žuóLG‘£[±µ?†½Š Ky gHI–es½"¹«ÆÍ[³ô’‹ÝyjrtDF&7 (”—q@uÆA€º$ ¥^ʽ+ü~Ü¥ ”5?µ›~MïWÿ1À0ÆVo¨ÎÚÎ÷Ðl€Xö(ªžŒš ¯¸/1@Êçœêê³T/HèEç”F%tŸÉàÎàg ¸q@Ëä1 éN¦.€ú! ù+ù>ª¯phý…~èv[ªúyá׺~ © iÇnÛ€Òâ"€ ®öHR½eI• ¶½Š€ÊXá3”Æ7Œy-}Q]ÊÄKIöO ê¥'eÚ2„¤ö"”¼ê˜ÉKþЩmU_ABã€~ã @N@ïÄ]Á÷÷ŠFõS{/zem§þœ©4Ú¯öÄAO Gü ŽjЋR ¥KRR¶4b|Úi§eþ¬³ÎÊ:C]* &V}µlC~íÚµYç'œ ŽPÊN¹¼%ZJ º7}ÓAS®/²C€ÀtšIæÊ½ÞqÝw¥ú•œM…€ÚT ¿FúåÕæqRi=ä욀®‰¼<½`5@»ÕK©Nq:¶FµÆ\SèÃ¥)Ž”—¹Ý4bîK#”^–räUçö(SOuT·É‘Ý£2Lz b_ÖR¦Þ¤ 0Rö\É÷éûú-E_ÏÜð¨âJÿ—s¯Å¨Q,0ÄÒ“C#èš  M¥L§ê|©€du.T'½päS)/jµ—üš5k²$ªg8C ¥ýŠêÆ«]UǼö”q@÷€Œ2°¤ $Ç1 n øH¾|Wò=Ô»‰ßnÛ£ëÒÔþêø(¿ pe_¡îwcé_x} !Ð m‘%ßôЖr쳤 ÉI™“b,#‡œêë#å¾bHõõºx½}CAuÜ|v€Â!ÏŒpE¡wl‹Î‡›††ôÿ¡ó8@)лOïþ)tÅ^ʽŒ¦(q)µhû²ê~Q_Á•~ ¦`jŸ;%Œ›€q·çµW@¶hZ¹6 L}Y@@)Æþe«ä ±Bq¢“Òª¯@ÈËù‹=4 Ðù;Öòb“·)á±³‹2€ÏCýϸÁ@÷€@Bå^ï0)÷ ]Á÷ß<ã»htËÐýNëó@Aº­ˆä©Àz &*¿FÔi8å”S’ýZ@ôÑ]µjUæu/p£ÀP;L2hÿy9ÕSu—¥_/ý!C² ×ø#þO|™A^Vn ðÐgÈ`àFµ†‚ ï¿õ?8y¬g!ÊTzí<4‰uNêu¯ro­¥©Ï `rë&Z7ur´F\ÉÙàÍ'e*4(Þ z }”\¡3Î8#óª»:Æ2¸1D!‘éÖ‰¹þWå¦íSJ¥{Ù n$˜ü=i4ðßa>C &ú_peÝCŹ1M¡ÿÏëØ è>Tøu?ã t `H·í/9/˜â&–A@K%´± œ¦Éë­uw•Ÿ•+Wf^uW=e ®˜ê<.j+WŠªJåÆŸIþöcÝ~¦óx?WµlÒ“€›I…\¿uŸzèÊ»§õÐïe…8 ‰€ º>¸ ÷ªü>÷pHõ¥.# clõDêÌ‹¦|Ci¦„¼cq“×KÛ ‡º–^J>))öÙggÐdðeÞ‘á~*?ŘRí7¯ñ`²>2辑—q@Nqú9Oç¡â§¥óëz:Æ•' [Οc =NaïçÂЕG˜^÷Îd\ÁŒ˜€þGôŽô÷¤B7z U‡Àà `|§[Auäpóò¡¯*ø—ÄR/u½Ü5KÀg •ñä²ÕSuö=–¶>_ pUÌ\¡”Œ]Ìq£Ê Ýø øÐ`¦ •nÒÍ:-&¯õßúÿ™x|Î:¯<üy¦ ] W¾EéÃ29†š%àa_Àÿo›-‰Ü ˜ `ˆ¹uF./¥fo)Ë—/ϼr_)Áa‡`¨J±” ß\ЩJñ›\:À=çt›$*ÁáqƇ&ëA^€@:ô¬ÑûÝ ß>ºÖ€w^HƒcŒ‡€ñ´ur5åÅÔ~“iym¸(§:u4Z®P~¨K4K`r/uÜ( cÕ@ˆ™€ÞÝþÞöw—ÞÝêGÑ—Š¹å ýÀÐwJ-A€—V H 'Ñ,É‘rEpƒ€Â!ÎÐ,ÓN;-óŽUuWg*ôêdá @}²¯wp¨ðKÙgõ!eBéÀN[NR q4¹Ö‡û H*u4|ù€†8Z®ºûƒÞ¾tÀš1ÀTn§C@M²/åÞGõ¥ôëÝKÿ¨)ÂäqÀ0ÎvO¢Ö¼àâm&7 ès„îB£€:(n ðóC '—¨^ª« nP¨Ž€ P†€}7¨KÑ—Ï3.Ó7*C“4€À4¦Ñá\¯xÉõŠ¿ráyFµ¡OWTÇF)Ë ‡ä|/…U«V¨3N à€Ž±Üß…z/ºÆô¸] 6 `h“.y×"À °¾(.Öºz˜ûÞ.”w€¼ä3?—7S@FÙñÙúƒ aPFÏ|½çôœ÷÷œ~{ÿÆÃaÕœÚ@±À{ X>^ŒÃm|ÍÐòœk½;Ÿ-à†…agÉÓ¥Ê(~ŠQõp£€/!PGQ#B8@Hƒ€¿»¤äëùí3ÝܨM&vDJŒ…€±´t‚õä…™`£ÕY3&7Ô} #€¤„ÇC¸GòŒª—:‘áÆOl6Xóæâr@5 ¸QZ¡+ù ¥èá}T—C‰ÀHC!&ÆJ@Ë–-[–y}¢0tuqÀByuÆÂµ”aúTŽUçICˆdWýÂ%~LÇ3•–EN@ ®Ü»Âï¿õ¬åy›B "# 0€it8×;½h¥ á G@K |>?ï47øŒtœrç-o¶€Fž|¶€ªþ8@È' g§äëyéʾB¹”ßù5&€À1¸¢&À 8êæ‰V¸ÉYá}䆟=þ޶BS“D3#òfGhÔJÆÜ8 8 1ðç¼”zÖû1ÓöÇpPG@ €<*ÄEC TÜ¢ A’& Qty¹ÉûËg ¨c¨Î¢wuœšó//`H­å¨BÀ{~ë·”|ýÖ³\nòY_%ÒB CkÑÕ‡—öÀ4òêHiÖˆzž êXºWG3¥ûtša œ-à;YkÆ@JõËk;â ´ Ld]ÉW>ŸÂã´kŒô€Ú#€ =¶äÜ^æ @$‹F„Ë s ïžU\h$ðc7èw¬N†ßhqùòå Ä”ünÐŒßk@aÌuZP ~@­ðçB)õêù¡có\Þ³4/q€ P€j¼HÝ1:§¸VH‰^Hx‡dOþÓúõ}‡EË $פqÀ ö-;åCõ ø³ÊŸWnÔ C=»b|~Õ¯=9@H“€4Ûm4RÓiMS¾¢n (ºç½ínýöã0,º¾kÀÓŒ’W#á— Ü0Úž ]s¥<tEÀŸ+>R†~¬4¡‹åùÊÄ1 ,$€`!~EF€ÎDd ‚8½ÐL)ÖòryÿŠS§ÜücË»¶«ÊÉØáË V®\¹ XÉtì{(Ä@°? P‰€þ¿¤¼û3@ÏŸ–¯ãÐO{FL;WI C€@ç0tŽœ« “Q…i!pŒ€ïGà†Åæý/)NÞ“Çþ»èúc¥5ûWFŽ“O>9óE9K R`¯è<c!àÿ§ }d^Ç*õ:žtJ‡ƒ ñÀ0ž¶N²¦tL’l6„Nˆ€Ï*EÎû¿S\‘w¥Â¯ótažMO[^ rÜ@ Ù2øÌð·âqˆ€þwÜ 'Ùܘåq Cïÿs^É߯pÚ¹0Ç€ 0l†Ý¾É׎KòMHD@ÆywEÿŸa¼ŽÝë:?'%&üíÇ~>;9çŸY/kšqÀ®€Í) —˜€+íBàJ»ÿ/„¡§ó¸YÑÿCQ|x-Ç€ <ò¨ :9Ñ4‚@`.n4˜ü_–’>7Y€Î‡iüx2ôë&Ó{|^(¹–-[–ù¼óaœŒ2(”wÃÇë·ŸS:\ÚÂûÈÃPµ û±×Z÷BžSº"7í\Ñ5ÄC€æ!€`j\Ó:E¡¦ DGÀLÏ‚pöAaýùá׆¿Ãë‹â=ÍÒ¥KÉ{:Ï 5š ÂߊŸüí†Åãfð6P¨û!ü­«'çÅM¦{›” (>Ìwò~C€b&€ æÖA¶ÂNh ”%à†ƒÉpòú&”=ÍlÐ̂ɼ&O–­ßáL‚Ð0à†7(/?Ï)Î}^þ³âÊÈæQ6½§óPy„Çy¿'Ë™L?íš¼´žß´sž†€ 0d†Üº¨µ4"U€JÍ^ð™ŽË•yWö'ëù ÂóúJ‚ ò¡›öL-:W5^åU½¦(ý´¼Âzq @€@9Êq"UO¦u {‰b!äÐójR!Gèý¼+êžVñŠ“²®cy?VAú]äŠÎÅåC< @ã €`íœt-Õ‘õ©»IWá!^ ¸âí¡ž-RÂÊ»ÒíçzšÉ¸ð·ò˜tº®È+Š/ʇx@€ P•€ªÄHß9uŠ1tŽ!Ð)PÙÖÿ¼¼Çy芶+ßJ£8?ï¡+õú{…t]ž+ŠWÚ¢sEñyù@€ú&€ ï |@‘mW®¥ðú±‡ç¿C¥{òœ~‡çu¼;ÏsUã•GÑ5yù@€Æ@ÀZ9ñ:J9X¼xqâµ@|T'àŠ±Y?CWp§ãI/E[ÎÏO ý\X–ç¯<òŽóâ´UÎë: @€@»0´Ë—Ü!ÄHi gßäðwxìÊ®ÒÉyzWÆé·{¥Ë ¯Ñ9¹iqMžÏ ã @€À `d³«R®ø «VÔ&VÚnÏž=™xá½çÇ*AÞq^\˜¶ÊùLþ@€ @ !Ì«n$Ù´G T˜Ú+…œ!pŒNr'@€  •€¡¶ì€ê…`@IU @€ Þ`è =—%€ ,)Ò5A€MP$@€  `ˆ±Ui pð£eZLö€ @½ÀÐz .K@YR¤ƒ @€ PL@1ÎDB@$ 11˜0’†¦š€ @`„0Œ°ÑS«2€ÔZ,my1¤Ý~H@€ PL@1ÎDB@$ € @€@Ò0$Ý|ãÀ8Ú9¦Z2 ¦Ö@@€ ¦`hŠ$ù@ƒ!€`0MIE @€ÆI€q¶Ë¥Â0äÖ¥n€ @`¼0Œ·í“©9€dš A!@€ ˆ `ˆ¸qí Ü ]`@×Ä)€ @  º Lµ `¨ *ÀPI!@€’!€ ™¦· ÆÝþÔ€ @¨O@}†äÐ @¦ˆ˜p€ @"€`@9äª`rëÆW7 ñµ A€ Ô'0ÀâÅ‹Ÿ¬ƒb%€ Ö–¦\†Ù®Ô € ÌK`éÒ¥ƒÐ7cxâ‰'ÌÛ˜\? ñ·B€ @`¨Ìðøê6€5Æ d7UuÀÐUò,"À €"2ÄC€ qØ¿ÿcC¨9€!´âê€`Q1DÔˆ@€ú'pdãÆ‡ú£¾ƒ1؃°ÈÔoÒaæ€`˜íJ­ @€ ý ÈXJÄÁ¬¶;KÕ˜DIÀd³%+43’m:‡ @mØÑF¦}ä9€mxo)³ºáL)Ç`àN€ @l Ž“>Œà-oyË}Ö“n „/$€  'Z € ¨d @€%`ºÈÖDEšØƒ1X‡]ßeÌÔŒ§µ€ @€ ÐfôA½D™›J¤!I‚˜`£%,23nC€ ŒšÀMC©ýÒ¡TDõ°ÎûÍŒÜ ©EŸª ŠÙS,Æt”×îyqM3á9Ò4Qòƒ @ÉØsÍ5×lIVú Á5àèѣ̘hà¡üìBé «Øë¡¶tï²úïXÚ€· ! @=þk¿¹A¸A~ý×ýNk•ƒh*±€@,Šá¡Fú#OYÏ‹ï•Ë¡0t?þæ€ @`Ô¾>¤ÚÊ`£vêÝ_7¤¢.O•·"Å-LóÔ•Óòòš~ÅðÎ:ƒ_^\_5/’ÅãC¹M(|ŽÀ¿&óô¼Ë†ó–í²—-§‰t^æ¼2Ï’!õügÕó€ @i°þé—6nܸ/-©gK;HÀ›ßüæÍVõïÏ®>)R"Жòé ÚVB½…m×%,«ê±s¨z]Ùôž[ æÉòf”mMÒA€ a°½å¾0Äš Òp¼¡þdˆ 6æ:… £+lmó躜¼:†qMÖ×ëÖVþ’ÕËhRî0¯yò÷kÚ¬w(#Ç€ @ÉØrèСÿ’œÔ%¬ओNúœÕO $I„À,…Í»¶«ÓU9m×£Éüɬ6*Sf^^yqUò*“v2 ³&‰ð€ Œƒ€õ=?jÓÿùi¹Á.¿üòÇìöüü8nÑqÔ²ªr9¯Ò8/ͪòÍ[Î<×5É¢¼æ©SxMŒ2…òq @€ Çm0ùÓÉH[QÐÁÄÁFð>nÁ™©\ïõm‚q¼ú*¿ŽÌ©´1rB€ L'`}ÂO^}õÕwOO•öÙÁÞøÆ7þÀšè¯Ón&¤²Ê¡+sMRó<ËÊÐdÙ1çå\êÊ8o>ó\ç×(œæ˜0ç @€Àà´ýáàj5Q¡ÁT_ëÈ_i{FÂn–Â6­j®ôMKÓö9—¡N=BçÍϯ óêòØË¯ÂažkT'¿nžúa˜‡×@€ 4 Xßïã×\sͶ4¥//õ( 6 àû†DŸÄ „@ÅNüz…óº&ò˜·ì®¯ë²®ó”5Ï5E =¯¢óÄC€  ŽÀnÛùÿÿ\­r*4 €ê}äÈ‘gÁþD%B@ŠÙ4WWqóëg•3M†¶ÎÅ,Û´:»ÜÓÒôy.vùúdCÙ€ ® ÄØëšåõCÀFÿÿÝg>ó™‡û)½ÛRGc¸âŠ+¶ÛCå}Ý⥴& QYk³Nž·Â*ί«r§í¢,—¯JY³®É;ÏoUB@€ 0h7^tÑEŸt ƒÊÆ :Û,€ÿdÁƒús˜ ²Š_žRWµºžGÙ몦/›oìéfÕÛÏ+¬âüºy®™UÖ¬óªP'- @H’À“ú_]yå•£Ù/nT›ð¸uúÿ…5r5-$É{y˜BÏRÚfÕZ××ÍcVc8Ÿ2ÇY²Ï:?†ö¥Ž€ @` lÀç?~á _Ð~q£q£2¨Ußô¦7}ÂO¦…VÑIåÝ•µ0ÞãVõ©Õñ:‡¦^`'ç¹FyÎ*cž|ç¹Æe™&ç«´U3ª#= @H‡€õo>tèÐ{Ò‘¸IGg6kìwX°£„äÒ%iÊÞ¼rTUcK?o½Ë\Wµ®eòœ'Ë¡°Içù6™'yA€ DOà° öüöÆE/iÃŽÒ`Ÿ|Ø:þÿÜXŽf­GÃ÷MoÙ¹XUq«š¾· FT°³nZ$o‹&óŸ•ç¬óMבü @€â%`}ÃwÙÔÿÄ+a{’Ò œføºY}ÞßZrN™€+Œ)×!”Ý룰Içù¶‘ç,Yg¯"“×#Ì“%U’€ $Cà+_üâ?˜Œ´ :Z€8®\¹òß[‡ÿÛ 3%» „ Úd1®ÄMÆwñ»Ï²›¨ŸË?ï<åx¾ó\[tͬ<ý|Q]f/*—x@€ ä l]ºtéo[-šK˨ —\rÉSÞjíõpBm6jQ]y« ÁóQ؇óòç)»Îµó”§k¼Ì¦yy¾ErÕ=_”ï´x/“Ó(q€ $Gà€Iü– 6<˜œä V>.WÊl‘€ @ 6ë>ù/mÝÿwkç”x£7¨ý.¿üòÿj£}¿Ÿx[ŽR|WðÖu±æUµ^^¢ëf/º®N¼—©0ÏÕ=Ÿ—g™8/7/-3ò¨@€’$ð[÷ÿ¹$%oXh Ç^vÙeïµÿ5 ó%»† )e‹™¦ð•ÍÃÓy^ueòüb ½^±ÈSF—¹¨-f/Si @€’$ðç^xồ”¼¡1‡jÊÿ“'tÒ¿°Ÿ£ŸÒÂ}ÖX–E ^X€+{aܼÇMæ5¯ ±]çLÊ´Ežìu¯Ï˳n\Œ2Õ­×C€ ,úöé§ŸþÖ+¯¼’Ï¿¿0ÿ¯yÍkö›!àõu{ÍaD\ét…­ њ̫ yRÏÃyz[U­Ï¬ëÛ>/yUKª¶é!@€@TþþСC—­_¿þ±¨¤êY  `û<`ÿbÑ»&Nñ3qRêbuyJm^\(ÿ¬óaZŽËˆù>)_ RB€ QØvôèÑ×mܸñ¡QSÈ©<€(¿ú«¿z·}àr;µ/ç4Q=˜¦œ¹Bœ'Þ´ëòÒ·çòu%ˬòfo‚—Q”Wìç‹ä&€ @ Z»l&ç+¯¹æšmÑJØ£` à¿þõ¯ÿž^k§10ê#z–ÂØ…LÓd˜v® Ùš,Ã뢰Èyš¢ó©Ä{=º² •ÖCN@€ p‚À}¦Ã½úsŸûÜOÄp°€€8þxÝë^÷-Sþ{‹}|á~ÅF TÜ\¶<¥®Ì9¥ñk==! @€ 5û–,Yòª«¯¾ú²gá0ÌhÛà«–ä æÌHÊéL*ú(ê@/(b²- ’•Šöv,ʳíó¥„$ @€@¬vYñ•Ÿýìg7Å*`,ra(Ѷàoí†ú5KŠ ¯¶“)‰m—;æüǤ€{]Y0æ;žºC€ ë»Ýc²¾üóŸÿü­©ÈܧœJÒ¿ì²ËþÚí ðHÉKH–WüÍͪ۬ó]ò˜%KÛ绬+eA€ ÌOÀú…ñ9kþË3ÄPžÕ"ÛàO<ñÄ+í’*\FÒ† ”UóŠõkóÎM‹óëæ9?Ÿw®‰8ÏVùE盡jE²ÌªKÕrê¤wYêäÁµ€ @½øo¶æÿ6òo/¥'Z(€Š g3¾oF€Kì²/%yCŠˆ²o<›iJæ´s ÒQ†]ÖiVY³Î;O§0t,ip @€â `}´¿:xðà+7lØð`¥#€9ÚÊŒäÈ‘d—Þ<Çå\ÒWðz(zpE6ÉrV^³Î.‚ @˜E`ýÖ­[ß¼qãF¾Ô6‹TÎy 9PÊDÙ×¶:tèå–öoʤ'Ms¤æ¹y•Åy¯Ë“aqMòh2¯il½…ynÖùðš*iÃë8† @h•Àë§ýŽ}æïm_ÿú×´ZÒ€3ÇP£qßð†7 ÛvM–U%/–´Ý²ä@€JØc˰_k›ý}´TjÀPˆ¦Ü‰+®¸âÐk^óšß¶Ô`¾}M¨œX¤Rc˜bê¾ ž·Â˜œËUW&ϧ‹ú5YV•¼ó×sçÀ…s`À\Øæ¿è•¯|å¦C‡ý¢å ]-Ÿ˜?'®œE@/÷³ÒÖ=ßU9uå,s}•º”MëéÎró¤m#Ï2²Î*—ó€ @O#°qéÒ¥/øìg?‹òÿ44íG0 }ÆO+áu¯{–¼ë«_ýê5Kç§ìø9OKDD!W•`Þ‘ôP¹›–‡§›–¦PPN$O€vO¾ © @ñØn}«ÿÙFý¿Hã“„=¶¹møµýû÷_l"¼×þ˜ Ðc[Pt=n”qƒÉ´ÜæI;-?›'Ï*×Ì*Ÿó€ Ô'P¦Q¿rè€Öú¯?|øðO£ü÷@¢HfLéúçå—_þ˜•©ÙeŸ ¼ÊŽªkR,O/ˆ¢ÑYy±¾.³ds¹Ã¸Y2·‘¶Jž³äëò|ªrwɈ² @€@Gî´ýÏÞf›ü]×Qy3ƒ3fêê´Í¸aß¾}/4ååVæ‘®ÊR9Rüf)eÒˆI™tž¦©2‡Òe¹”妛Åz^†Udž· ®ƒ @#"pÀêú6Ûù(ÿqµ:3"jã³~Ͼpõ’%K>a¢½$"ñ¢E ›”G%Ø@…iKñžWY<­‡eÊ Ór•!F@€ ðëK]k}¨ß±éþ?z*–£X`ˆ¥%9ìK7Û?ÎËþîïþî­ýGæ×§9 ”UÖ< ÝSðœÉS1Í•-£lºæ%$G@€ †l¶|þíîÿ•†ò#›° ¨MdiŠê“¯xÅ+6Ø'µIàçÍÏþ~Z'’G £òt? C•4mÈ9M6+#߬<¦÷üû¨Û¤\¡,~<™fò·§‹AþIÙø @€$ð¸õ«®4ñ§?ýi”ÿÈ‘7Ð¥—^zŸ‰ø›6à-ü°ù_Œ\äÎÄ“7mD?Tð¦¥ëLàˆ Yµ!f•ü«¤­+k—eÕ••ë!@€@d´»ÿÿc™¿ó“ŸüäݑɆ80€‰-ú—ù—¿kÊÊË®¿þúß4ÙÞg~]l2v)O“Š›çÕ‡‘ lÙž®KÆeÊj[®yòoòš>î‰2ÜI@€z&ð]ÛÝÿí6Ýÿ[=ËAñ `¨¬Ï䦌]?Ïuó\ÊÊ1 @CÖgúŒmð÷ŸúÔ§´)9n 0 ¤!U—¼ä%×~ï{ß{¡}:ð­¦Xþ¾Eý䀪· *®Äy¨“e”iO?+mÙt.TÕô~ÝCg1oÝæ¹~žk$ß¼×Í[7®ƒ @‘8`ò}Ò¦ú¿Ï>é§õþ¸À0°ý…_ø…ÃV¥«ÌpµíðOMÁù?ì÷óVMª“>ìyÊ ¯ ÁŒ˜€ @ .ýÖúÔ‘#GÞ·aÆíu3ãúx `ˆ·mjIvܰÁ _”!À2”!@Jšü¬‘|‡èJ]Ùô~]̡שªŒó\7Ï5¡\ó^?ïuaÙC€ Ðÿ«–,Yò¯_¿~ga*N †€Á4e~Er `)Ÿ›ŸzX±¡òXFñ-ý°Z£^m¶©’Ó¼×U)ƒ´€ @ AZ?éã&÷ûlÿC ÊÈsÀ0'¸Ô.›4˜Bün«Ã©Õ£Œ¼®ô•QúËäGš…œïÂØò¿ú¸>,3<./5)!@€À ü‰O|bÏ jD%*ÀP Wú‰Ý°iÓ¦k{ì±ß°%ihR‰ó¼Æf0ðzÏ{W×½^å6‘Ǽò—-_÷EßrÖ©#×B€ #p¿õi>nþƒ6Õ/DÆKÀHÛþâ‹/>dUßpçwþéÃ?üÏíaðvû}qÊ8\I“Â֦몜*up™ª\ÓdÚ¾ÊoªÜ¦òi’)yA€ Üjýœ¯X±âê~ðƒ7Y$N@â XWü /¼ð åq•¼møK¦<¿ÓŽ_o¾]-Ú ¨ë&•¶*Šxm•ëæ‘ÙËj»œydók\Fÿ]&T}æ¹./ïºù„ׇÇyeÍŠ«{ý¬ü9@€@>&ûù%Œ&öI«éWíS~lëû¿bÇúƒ@F7 ¶<àzûqý7Þø³öþצý–ý>åD‚¸rWU÷넠굩a ë:ì}_?ÌE×Ô­KQ¾ÄC€ h`ïϬÿòÞ?ù“?ÙÔBþd9ЈMWá…/|áÍ–çÛ¾ûÝï¾Û6ùŸìøwÌŸÙt9CÎ/T« ÂkçaT÷úyÊl뚺u©{}[õ"_@€ Ð }¾o½õÛ?ò±}L›üá PH@!N¼øÅ/Þe®´ ßøðáfÇÿ›ù‹b!#宬ríŠ`Ùô^Çy¯óëÇ:¿ºêæSçzÝ3u®¯[w®‡ Œ…ïÛj-m}”ïÛlܾhû®v5©ÇJÀX[¾B½mÃÀ}–|ýu×]wÕêÕ«ßlmøâ Y4AM¾„›Ì«.ÊP–ð¸n¾\@€: pÈú/nå|È”þïtPE Œ€5h›Õ¹ä’KŽXþ*Ë-·¼ÈÂe^3–›ïÜÍRÞÂócùëßTã4‘gÝ<ê^ŸÇ¢<óÊ!€ ÌIàN»îSGýÌ'?ùÉûæÌƒË °7Á\~æg~FSŽÞfŸ|Çã?þ¦`ÿkûý³seÖðE®ÌUUú›cÞ²ý:Éàr‡qMÈV'P–ð¸Nžº¶n^u¯Ï“?Ì3<ÎKK @h‘€6õû+Ûͽmê÷U;f7ÿa%k cié–êiŸ|IJ^/¯Y‹/Ö¬€ß4šùN+k®@W-ܯ×uóæQµÌ®Ò‡uëªÌ.Ë ëWtÜ¥<”@€j¸Ýú¢Ÿ^ºtéUùÈG—Bài0< óðY7ÝtÓ;O:é¤+,ŸÿÕüÅóæ7ë:)z¡²7¯ÒîyÌ{½äl"Yõñ¼×»®lMåS$GÛù•K< @(Ià€¥û²õG×âŸ`´¿$4’U'€ :3®˜Aàçþç¶$Ù¬€Ûn»íE¦|ýûýæ—͸”ÓhJó ëV¡É¼òd©šÃP^ùÄA€ €À­v¼ÁfÑ~’OøT8l€ÖÐ’±<ÿùÏ×^¿eŸüß-üL™ú- Ú|¯.TçUðšÌc– aYMk#OÉÖd¾ž—‡MÕÝói+_ÏŸ€ ä¸ßú~ÚX{ÃÇ?þñÿ/ç%¸Ë~¿WÞŒ/Y²ä­vüÛæ×™ŸËÍ£¼ù5³îi5‘Ç´ü97€óWªðxúUÓφù„ÇÓ¯â, @(Mà€õ1®µÔl'ÿ¿´Oø.}% !Ð  Â$«r̰ÉR¾Ë‚ÿÞ¾"p‰…šð&ó§—Ë¡z*Wêê(þÕKMç çÓ´Ämå;)g[å´•ï¤üü† @`ŽZ_â¿YÍ6aÝ»’³2»ªå@€ ÐLé·>Ý?üáßÞY© `è6EµKÀÖO›`#÷¿fño°’ŸÓFé¡â©cÜ·Q^•dËôcU·ð¸Éº’ @É8lý¶oZßà/Íÿ…ôß›\  `¨Œäi°‡ù c€Iüo·lÙr.·øËÌ¿Ââ–µU“"ÓÊm«È™ùÉ4ó†„å‡Ç e?w6.‹‡sgÄ…€ ¤Bà~ôëÖ/ûŠù¿úЇ>ôp*‚#'š €  Šä=g?ûÙ›MÈËß{ï½k–,YòJSú.·ß¿jþ ó­»"%³kÃ@‘U4‘OyT•{VúP¦ðxÖuœ‡ @ JºÉüµæ¿²zõjvî²™ª+º"M9Ñxæ3Ÿù  £M]6š‚·dçÎ/1%ü2û­¥ÿÀ|§®/%3,7<î´òÇ Ëû…2!@HžÀ~«ÁuÖ§ø²mý•~ô£;’¯€@C04’lÒ$`ŠÿQ“üúãþ]÷Ýwßö²ÐÌZ]*`ùOu¡"ìÇ]Ì𲦠×ÑI—ÅC[tÜ‘H@€@œ6[?é+&Ú—Ï8㌿»òÊ+Å)&RA _úåOé‘X·nÝ‚¥Ë–-û'¶wÀkLÌKÍŸÓ·¸R~]ö°-£€çßw˔ʗ¹–4€ $I`I}õƒþÖújÿåøÀ–$kÐ蘀ŽS\:Ž/øœI,¿H³ì#C€ükͯ0ß»“Â*½áqSµ‘gS²MËÇåöPiÃãi×r€ ¨1in6¯µü×îß¿ÿëׯ?•„,M@FD„@ŽÏXo¬7%ré<ð³fȾ,`q?o~q‚"Ttý¸‰Ùž—‡1Õ¹ª,^u}x\5?ÒC€ Ðß¼ï[–ãõ6+óoÞ÷¾÷=ÚXîd‘À0Ò†§Úõ˜"-+ô÷û+y䑳>|‰ý¾ÔÎiÉÀ³ÍGç¤Üº‚ëá¼F]çyx¨ ‡ÇѨ(ÐêR±ê$‡ ôA`³½{¯µ>ƵüÚÇ>ö1mÜŒƒ$€ A˜d5^+W®|ÀjŸ}Y@}ôÑçÛ®³¯6ÿ+öÓf‚Ë£“’*ºáq]y=/•_Ñqݲ¸€ äì6‰¿&…ßú×þÑýëø“kBN€ÔZ y“ °bÅŠÛLPù?¶Ú’½{÷þœÿ’½à^fá«ÌŸi>j—§¨›ü­ÈœW– ã[)˜L!@è’ÀN+ìzóÙ´~Û¸ïF;~²K( c'€`ìwõo€)ÍúÔ /ø°)µ‹÷íÛ÷|‹{™»Ô~ÿc;>Û|ôN y¨”‡Çm –“wƵ)yC€ Pž€õs4¥ÿ[毷ã¿}ÿûßwù«I ´A@TÉSØ P›Úl:à¢\pôèQíðKöó—ÍG¹‡€dÍs¡îÇV—¼¤­Çyù*È= ãÂãYç•@€ÀTð¸Ý¼Fø¯µe×Ù¿–Hâ ˆ`ˆ¨1e¼N9å”ÍVûì ¢ ƒÀ‘#G|ÉÀ¥uâcr¡Òœ'—Î{óÒ@€@’3©o2½½ç¿eý–o~èCz8Éš 4FDÀˆ›ª¦Cà¸A@F ’úñÇ–½X_j£ê¿(o/Z}vð$KÍ…Æ€ð8µz / @`dî²÷öw¬òÝÿŽ}éÆõëת ä `H¾ ©Àœzê©[­žòר¾ö^f þŒ½„5KàE%ÿÓ:—¢ áqŠuAf@€À/2«ü‹ì¼¾6 jv2Ñ?n ðPÕбÕ/Ñ!6 @ :¾vÿûöŽý¾½c¯·™ˆ7]yå•Ú³ Œ€5(Õ/ÓO?}‡Õ^þË¢`/ñ¥=ôÐO-Y²äev¬Í5K@_hD{–.e¼çåN†’ÅãÂ㼸>ä¦L@€@ô)¾lÁÞß·Y†ß4eŸµû4 "@  º Lè€)èG¬Ø_ؽ{÷9K—.}‘½ð_hçdPx¾ùQ:7 x(EÇ£D¥!@ u[­?p“½Ûn´éüÚ°ïÆ÷¼ç=ÛS¯òCóÀ0?;®„@rÖ®]»Ë„þëã>“Ïž=«>üû¡¥2(ll¦@V @h›ÀN{û4~…ßýÃ?üÃûÚ.”ü!´`H«½X½zµ¦ý]ÜgùÛÒ3lßx|?Íÿæg ø@€@_4ÃïóRò7™Ò«…7˜²ÿ`_Q.  é´’B 3gžyæ^+lQ@38 ÏfK¬Ãñsv|¡yž#@hÀ>ËóVó7Ù{÷Fó7ÙÞ>?´5ûZ(‹,! ã>‚F¦Šh‚Àñ™×Y^ò™³‡e»víºÈf ü´uJ.¶HÍÐç/Èð€ 24ª¯ÏýJÙÏFömÍþ­¦ì߯nüeð‘(K@YR¤ƒžFÀ”~}ŽÐ7Üè î¾ûîU'Ÿ|ò d0#~ÖÎ/÷4„€ ‘Ø©©ûV÷LÙ·pÓ¾}ûnýà?øøHyPm@ C:„MQ ŸüÉŸ|Ú¾ªûÖ­[ŸaÏpÃÀOYÜÇA€†BÀŒä{¬.Rò7™Â«èKéÿè?0”:R@ =Òk3$†@²žõ¬gí0áå¿ì•ضmÛ©G}¾uŽ~Ê:K µÙ Œò'{:B@€@„ž0™î1‡½Ãn³™o·ëXʾ)ú»í@ *¢j„Àøœþùšòxãq¿€f Ø' }OÍðcöX@Š€ Ð2ƒ–ÿ]æ5Š¿Ù|6¢ê©§þèïxÇ~ûƒ  I4BB`œ‚ lÙ²eµ.°‘–‹mÄE^`3d Ь–, Å@¨@`§¥Õ”ýÍönÉ};Þôîw¿ûnûýd…|H @ J?¥T@`wÞyçÉG޹È.½Ð:jϵNÛsíXáó,<ßü;¶à˜óc;ëxèçC]ÖõX‹,äïq¡LaÜ´øiçÂz…ùÅ“×Sÿ3ðzŠ@ÑýR5¾Éû«¨ì&Ë@^Úm›ù»Ìˆ|—”|ã¦ðÇš¾ÏçõÔÂ8@`Ș0äÖ¥n /¼PS4xÜ/¨ý÷¾÷½e+W®<ß š-puöÂPûœ¾à~@€@ªô.Øn^#ø™—¢o þæåË—ßúö·¿ÝöSmYä†j`@m„d À-·Ü²Ú꡽2oFßs@3VyíØsg ¤~^•ó:xÆ…ÇMžW¾ražÇbŽý­O^Oݧe8Âk¼ŠþOÚ¾Úa?›¦oõΔ|)øK—.Ý|ðàÁ{l$ÿ‰ðÞ瀎ÀÀ@`ï|ç;kN>ùägY'óY–ô9æŸm£IϲΦ~˯󎷇·@™õxc=ÊÕ¥¬*W.,óX̱¿UãÉk -íX­‹þOäxØêr¯ùmö¬Ýbòo±PÓö·ZÜÖeË–maã=µ*€@uª3ã @ lÚ´é¤Ç{ì™ÖA}†8×|¶¼@¡â¬Ãúó§é" d.ï8/N‰=ÞÃ0.<®{¾É¼ªÈ¢råÂkŽÅû[5ž¼žºÏÊp„×0xýŸDؾL&}Vëï7[¨÷²ßŠ{îsŸ»åŠ+®8jÇ8@h˜€†’ IÖÁ]|ÓM7cû*Ã^ÃàUôÒqû>`åí2¯|5’¿Íž[:´Õ¦çï“L8@èž›vÏœ!‘°ŽïVenÉßPTýo~ó›«5c`É’%çZÇÙgL†2ðì.‚H< Ðö\ÚaϨl´Þ޳P¿Íï8zô¨Â­ï|ç;mKò… ú˜PŸ!9@èŒÀu×]·Ôö#XgmÍ8Ç >ß:ÝëldMŸ9\{›Q`ûÕÖ¡õå-AÐ>g[˜Í,°ã,;õ#ï8/.L[å|VàD9æÆM‹Ÿv.”+̯(ž¼0„÷‰Ý/U㛼¿Ž—íë른k§ü=ö¿ï#ô:ÞcÃì÷ã?¾Û¦ãñ:B€Àð `~SC@3 üÙŸýÙ’³ÍÙúܳ,ñÚÅ‹ŸcÊ„fè·B Ö˜—áL Ï´p¥…™³c?›´ÛâØ»wïý(ôºkp€ PD@â!@`&3œºjÕªÕ¦˜È0ySFd,Ðñ¹¦”hƒ,^¡ýVZlxh¿3WUA,J¯ÌŠÎU'¯§Œ;Y#ÿSÄ^¹¼²Qyc¶Ó|6 oœöèØŒm{ì& õ[Çö™»='tÒýo{ÛÛ‡Ì9† Ô%€ .A®‡ ʾô¥/­0ÅG†vñŠãá*S~V˜‘Àã–Ë`œWüróYÜñøS,Ìu–g#ñÊ„¼žŽ²ˆÉ€x=juÔ†vÚ±^¡¦Óï³{2‹×9;~ØÓ(ÞîßG§t¶ôæQ)÷¦Ä?f¿q€ (`ˆ¢€æ! M÷ïß¿âàÁƒš]l†Áé¦x­4ÅLÆS-\n~™_e¿µÏÁ‰sv|✥ÉÎYÜÉæOÓ9óËÌc„ g¼&bžúYt®j¼rœrsKáV(…ü€)á[xâœ]Ä~?bçÚ½ñ˜ï·¸CvìÕ9ó{u^רµÚ2˜G÷wWyâ @ƒ#€`pMJ… @ Iñ±Ê6KÓ×V>|ødSeXdÊâ‰cS"3cÃñrOµÐg&È‘[xš)™2.Èn>ûJƒ)¥Ë-Ïef'Âsаë<þDhù¬²øŸÈ;w<Ñ;wb†vþýÜïQyiôú § C—×d‘"}Bxûýˆ;ª´:¶ ;¶¸½vìé4ržUÌê~âØÒh”=svmvlqOÚ”ø‡ý)è̱#½S"„ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ 9ÿP0p^*òÄ»IEND®B`‚ic11Ò‰PNG  IHDR szzôsRGB®ÎéDeXIfMM*‡i     ¬†bó4IDATX µ—ÉKäWÇ_·íÒí¾µ¢Áe"Œ t<%‡&ÂÁ£§¢aNÁ\¼äœ? Ï^28—!„(âÅf $ƒ :¸Æ}·ÛžúTº:¿îÌd¶öÁû½µ¾õ­zUïuûÜkJÁÅÅŃòòò®`0ø0|xww± ´Ád2é|>ß©ôodnóúúúO©¿ÝÞÞ>+,,\œœLüŸ ßË?)..þæôô´GÖC555êêjII‰£ °+((@±Š' ÇuçççîèèÈíìì$BìØï÷ÏÖ÷SSSϲõeþV„¾…¡ŽŽ_SS“*Ëz›1„VWW],Kž Ù¯'&&Æ Ãø†††bùùù]ÑhÔ‰»m=§íöö¶›žžvrDO…Äg€ûùŒŒŒ<¾¹¹éêëë»7å詯¯wNâæ‘ÄÖÌ)¶¶¶ŽH$âòòò˜»×"^vÝÝÝ®¢¢â!Š”€Ö_œ·œ¿# î«Hf¸ÍÍM Ô“““#ôøH”&‰êÚÚZä««+¦3"]'Þá#Yà.//Õ8²dii‰ I#)Fä3Ãá°¦ýýý}e+ñá∬’‚–†È²NŃìG-V‹µnkkKÓ“±·¤ Ø$ÖWUUqF®±±Ñ1öæ·¤’•HÖ5Sy“cJ³›>% –üãóÔ,€Växô(ðÀ )4Ù-yU\u…¡lüQÀâ¶`„½–ÙZŽÚ+¹9K ,,,|4330˽èc™­½/ÒÒR¼X$8õ`é´··G9+”˜›C¡Ù¡wüû Xëêê\ss³#ÝgggÝÚÚZTôÏ+I¿e”jð±{{{š D=^à±y“ÂECJó`Éëé°˜ –WT ›yyœþϲ Î+ÇF^2­K؇w(dx k©©Rpâããc,w+++ée# `ämkk«²ÅX.cVØ=}oÇ…BŽ”ôµtÅr. ÒÓOi±ÀóÙÐР·"Ö÷A† …>J†Þ2Y<‚ræÁa/òf„íUÔÇd<Æ…A%(7K œñ˪ay•Ò—#ÓKBÓPÆ¿JMß>v°ư§¥æ $w%°¸¸˜˜››KŸ ÊL!.ŲWYò¶dˆñ _ðõ5TòìKI J̽f-DrA€ÌéììtòCÄɽã+++û òòèls7ÖÛyHåhP@ °[›}Qç|eo~÷."`BÖ…T¼„ó‚íñb¼®/2ú hJjü,£&d.FA®ÒаSíãããÓô•îèíí”ñçRc(6ëŒã”y±üÓ±±±Ç‚•qŠÝÓÓóD:OäÉŒˆ ±¥ˆ»Ëpó;r}Ad‘öéèèèR6ƿɚ½â/// éô@^¸©a‰p*ÐÊ…`\âã\Æq©»Òß‘ú\›?ä/Ÿþèð@ý§ûÛÊSaé\$IEND®B`‚info>bplist00Ô X$versionY$archiverT$topX$objects† _NSKeyedArchiverÑ Troot€§ U$nullÓ WNS.keysZNS.objectsV$class¢€€¢€€€Tname_assetcatalog-referenceTiconÓ   €Ò !"Z$classnameX$classes\NSDictionary¢!#XNSObject$)27ILQS[ahp{‚…‡‰ŒŽ’—°µ¼½¾ÀÅÐÙæé$òsqlitebrowser-sqlitebrowser-5733cb7/installer/macos/nightly.json000066400000000000000000000012551463772530400253470ustar00rootroot00000000000000{ "title": "Install DB4S Nightly build", "icon": "macapp-nightly.icns", "icon-size": 128, "background": "background.png", "format": "ULFO", "window": { "size": { "width": 500, "height": 320 } }, "contents": [ { "x": 90, "y": 180, "type": "file", "path": "DB Browser for SQLite Nightly.app" }, { "x": 395, "y": 180, "type": "link", "path": "/Applications" }, { "x": 90, "y": 380, "type": "position", "path": ".background" }, { "x": 240, "y": 380, "type": "position", "path": ".DS_Store" }, { "x": 400, "y": 380, "type": "position", "path": ".VolumeIcon.icns" }, { "x": 90, "y": 530, "type": "position", "path": ".Trashes" } ] } sqlitebrowser-sqlitebrowser-5733cb7/installer/macos/notarize.sh000066400000000000000000000133001463772530400251570ustar00rootroot00000000000000#!/usr/bin/env bash # Create a new keychain CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db echo -n "$P12" | base64 --decode -o $CERTIFICATE_PATH security create-keychain -p "$KEYCHAIN_PW" $KEYCHAIN_PATH security set-keychain-settings -lut 21600 $KEYCHAIN_PATH security unlock-keychain -p "$KEYCHAIN_PW" $KEYCHAIN_PATH security import $CERTIFICATE_PATH -P "$P12_PW" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH # Run macdeployqt find build -name "DB Browser for SQL*.app" -exec $(brew --prefix sqlb-qt@5)/bin/macdeployqt {} -sign-for-notarization=$DEV_ID \; # Add the 'formats' and 'nalgeon/sqlean' extensions to the app bundle gh auth login --with-token <<< "$GH_TOKEN" gh release download --pattern "sqlean-macos-x86.zip" --repo "nalgeon/sqlean" unzip sqlean-macos-x86.zip -d sqlean-macos-x86 gh release download --pattern "sqlean-macos-arm64.zip" --repo "nalgeon/sqlean" unzip sqlean-macos-arm64.zip -d sqlean-macos-arm64 lipo -create sqlean-macos-x86/sqlean.dylib sqlean-macos-arm64/sqlean.dylib -output sqlean.dylib for TARGET in $(find build -name "DB Browser for SQL*.app" | sed -e 's/ /_/g'); do TARGET=$(echo $TARGET | sed -e 's/_/ /g') mkdir "$TARGET/Contents/Extensions" clang -I /opt/homebrew/opt/sqlb-sqlite/include -L /opt/homebrew/opt/sqlb-sqlite/lib -fno-common -dynamiclib src/extensions/extension-formats.c -o "$TARGET/Contents/Extensions/formats.dylib" if [ -f "$TARGET/Contents/Extensions/formats.dylib" ]; then install_name_tool -id "@executable_path/../Extensions/formats.dylib" "$TARGET/Contents/Extensions/formats.dylib" ln -s formats.dylib "$TARGET/Contents/Extensions/formats.dylib.dylib" fi cp sqlean.dylib "$TARGET/Contents/Extensions/" if [ -f "$TARGET/Contents/Extensions/sqlean.dylib" ]; then install_name_tool -id "@executable_path/../Extensions/sqlean.dylib" "$TARGET/Contents/Extensions/sqlean.dylib" ln -s sqlean.dylib "$TARGET/Contents/Extensions/sqlean.dylib.dylib" fi done # Copy the license file to the app bundle for TARGET in $(find build -name "DB Browser for SQL*.app" | sed -e 's/ /_/g'); do TARGET=$(echo $TARGET | sed -e 's/_/ /g') cp LICENSE* "$TARGET/Contents/Resources/" done # Copy the translation files to the app bundle for TARGET in $(find build -name "DB Browser for SQL*.app" | sed -e 's/ /_/g'); do TARGET=$(echo $TARGET | sed -e 's/_/ /g') mkdir "$TARGET/Contents/translations" for i in ar cs de en es fr it ko pl pt pt_BR ru uk zh_CN zh_TW; do find $(brew --prefix sqlb-qt@5)/translations -name "qt_${i}.qm" 2> /dev/null -exec cp {} "$TARGET/Contents/translations/" \; find $(brew --prefix sqlb-qt@5)/translations -name "qtbase_${i}.qm" 2> /dev/null -exec cp {} "$TARGET/Contents/translations/" \; find $(brew --prefix sqlb-qt@5)/translations -name "qtmultimedia_${i}.qm" 2> /dev/null -exec cp {} "$TARGET/Contents/translations/" \; find $(brew --prefix sqlb-qt@5)/translations -name "qtscript_${i}.qm" 2> /dev/null -exec cp {} "$TARGET/Contents/translations/" \; find $(brew --prefix sqlb-qt@5)/translations -name "qtxmlpatterns_${i}.qm" 2> /dev/null -exec cp {} "$TARGET/Contents/translations/" \; done done # Copy the icon file to the app bundle for TARGET in $(find build -name "DB Browser for SQL*.app" | sed -e 's/ /_/g'); do TARGET=$(echo $TARGET | sed -e 's/_/ /g') if [ "$NIGHTLY" = "false" ]; then cp installer/macos/macapp.icns "$TARGET/Contents/Resources/" /usr/libexec/PlistBuddy -c "Set :CFBundleIconFile macapp.icns" "$TARGET/Contents/Info.plist" else cp installer/macos/macapp-nightly.icns "$TARGET/Contents/Resources/" /usr/libexec/PlistBuddy -c "Set :CFBundleIconFile macapp-nightly.icns" "$TARGET/Contents/Info.plist" fi done # Sign the manually added extensions for TARGET in $(find build -name "DB Browser for SQL*.app" | sed -e 's/ /_/g'); do TARGET=$(echo $TARGET | sed -e 's/_/ /g') codesign --sign "$DEV_ID" --deep --force --options=runtime --strict --timestamp "$TARGET/Contents/Extensions/formats.dylib" codesign --sign "$DEV_ID" --deep --force --options=runtime --strict --timestamp "$TARGET/Contents/Extensions/sqlean.dylib" codesign --sign "$DEV_ID" --deep --force --options=runtime --strict --timestamp "$TARGET" done # Move app bundle to installer folder for DMG creation mv build/*.app installer/macos # Create the DMG export DATE=$(date +%Y%m%d) if [ "$SQLCIPHER" = "1" ]; then if [ "$NIGHTLY" = "false" ]; then # Continuous with SQLCipher sed -i "" 's/"DB Browser for SQLCipher Nightly.app"/"DB Browser for SQLCipher-dev-'$(git rev-parse --short --verify HEAD)'.app"/' installer/macos/sqlcipher-nightly.json TARGET="DB.Browser.for.SQLCipher-dev-$(git rev-parse --short --verify HEAD).dmg" else # Nightly with SQLCipher TARGET="DB.Browser.for.SQLCipher-universal_$DATE.dmg" fi appdmg --quiet installer/macos/sqlcipher-nightly.json "$TARGET" else if [ "$NIGHTLY" = "false" ]; then # Continuous without SQLCipher sed -i "" 's/"DB Browser for SQLite Nightly.app"/"DB Browser for SQLite-dev-'$(git rev-parse --short --verify HEAD)'.app"/' installer/macos/nightly.json TARGET="DB.Browser.for.SQLite-dev-$(git rev-parse --short --verify HEAD).dmg" else # Nightly without SQLCipher TARGET="DB.Browser.for.SQLite-universal_$DATE.dmg" fi appdmg --quiet installer/macos/nightly.json "$TARGET" fi codesign --sign "$DEV_ID" --verbose --options=runtime --timestamp "$TARGET" codesign -vvv --deep --strict --verbose=4 "$TARGET" # Notarize the dmg xcrun notarytool submit *.dmg --apple-id $APPLE_ID --password $APPLE_PW --team-id $TEAM_ID --wait # Staple the notarization ticket xcrun stapler staple *.dmg sqlitebrowser-sqlitebrowser-5733cb7/installer/macos/sqlcipher-nightly.json000066400000000000000000000012601463772530400273330ustar00rootroot00000000000000{ "title": "Install DB4S Nightly build", "icon": "macapp-nightly.icns", "icon-size": 128, "background": "background.png", "format": "ULFO", "window": { "size": { "width": 500, "height": 320 } }, "contents": [ { "x": 90, "y": 180, "type": "file", "path": "DB Browser for SQLCipher Nightly.app" }, { "x": 395, "y": 180, "type": "link", "path": "/Applications" }, { "x": 90, "y": 380, "type": "position", "path": ".background" }, { "x": 240, "y": 380, "type": "position", "path": ".DS_Store" }, { "x": 400, "y": 380, "type": "position", "path": ".VolumeIcon.icns" }, { "x": 90, "y": 530, "type": "position", "path": ".Trashes" } ] } sqlitebrowser-sqlitebrowser-5733cb7/installer/other/000077500000000000000000000000001463772530400230125ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/installer/other/get_nightlies_from_github_actions.sh000066400000000000000000000043711463772530400323050ustar00rootroot00000000000000# SPDX-FileCopyrightText: (C) 2024 SeongTae Jeong # This script downloads the daily build output from GitHub Release, built by GitHub Actions, and archives it on our nightly server. #!/usr/bin/env bash source /root/.gh_token_secure set -ex echo "$(TZ=UTC date +"%Y-%m-%d %H:%M:%S %Z"): [START]" echo "Clear the incoming directory" DOWNLOAD_DIR="/tmp/incoming/" rm -rfv $DOWNLOAD_DIR mkdir -v $DOWNLOAD_DIR if [ $(ls -l /nightlies/macos-universal | grep -c "$(date +%Y%m%d)") ] && [ $(ls -l /nightlies/win32 /nightlies/win64 | grep -c "$(date +%Y-%m-%d)") -ne 0 ]; then echo "Nightly build already exists" exit 1 fi if ! gh auth login --with-token <<< "$GH_TOKEN"; then echo "Unable to authenticate with GitHub" fi echo "Successfully authenticated with GitHub" IS_BUILD_SUCCESS=$(gh run list --created $(date '+%Y-%m-%d') --limit 1 --status "success" --workflow "cppcmake-nightly.yml" --repo "sqlitebrowser/sqlitebrowser" | wc -l) if [ $IS_BUILD_SUCCESS -eq 0 ]; then echo "No successful build found" exit 1 fi echo "Found a successful build" if ! gh release download --dir /tmp/incoming/ -R "sqlitebrowser/sqlitebrowser" nightly; then echo "Unable to download the nightly build" fi echo "Successfully downloaded the nightly build" mv -v $DOWNLOAD_DIR*win32* /nightlies/win32/ mv -v $DOWNLOAD_DIR*win64* /nightlies/win64/ mv -v $DOWNLOAD_DIR*dmg /nightlies/macos-universal/ rm -v /nightlies/latest/*.dmg rm -v /nightlies/latest/*.msi rm -v /nightlies/latest/*.zip DATE=$(date +%Y%m%d) ln -sv /nightlies/macos-universal/DB.Browser.for.SQLCipher-universal_$DATE.dmg /nightlies/latest/DB.Browser.for.SQLCipher-universal.dmg ln -sv /nightlies/macos-universal/DB.Browser.for.SQLite-universal_$DATE.dmg /nightlies/latest/DB.Browser.for.SQLite-universal.dmg DATE=$(date +%Y-%m-%d) ln -sv /nightlies/win32/DB.Browser.for.SQLite-$DATE-win32.msi /nightlies/latest/DB.Browser.for.SQLite-win32.msi ln -sv /nightlies/win32/DB.Browser.for.SQLite-$DATE-win32.zip /nightlies/latest/DB.Browser.for.SQLite-win32.zip ln -sv /nightlies/win64/DB.Browser.for.SQLite-$DATE-win64.msi /nightlies/latest/DB.Browser.for.SQLite-win64.msi ln -sv /nightlies/win64/DB.Browser.for.SQLite-$DATE-win64.zip /nightlies/latest/DB.Browser.for.SQLite-win64.zip echo "[STOP]" sqlitebrowser-sqlitebrowser-5733cb7/installer/other/move_nightlies_into_dirs.sh000066400000000000000000000017321463772530400304370ustar00rootroot00000000000000#!/bin/bash # Moving the nightly builds into appropriate subdirs. Designed to be # run automatically from cron, using something like this: # 10 0 14 * * /usr/local/bin/move_nightlies_into_dirs.sh # Retrieve the month number for last month YEARMONTH=`date -d "last month 13:00" '+%Y-%m'` YEARMONTHOSX=`date -d "last month 13:00" '+%Y%m'` # Create appropriate new subfolders mkdir /nightlies/macos-universal/${YEARMONTH} mkdir /nightlies/win32/${YEARMONTH} mkdir /nightlies/win64/${YEARMONTH} # Move builds mv /nightlies/macos-universal/DB*${YEARMONTHOSX}* /nightlies/macos-universal/night*${YEARMONTHOSX}* /nightlies/macos-universal/${YEARMONTH}/ mv /nightlies/win32/DB*${YEARMONTH}* /nightlies/win32/${YEARMONTH}/ mv /nightlies/win64/DB*${YEARMONTH}* /nightlies/win64/${YEARMONTH}/ # Fix ownership and SELinux context's chown -Rh nightlies: /nightlies/macos-universal/${YEARMONTH} /nightlies/win32/${YEARMONTH} /nightlies/win64/${YEARMONTH} echo Nightlies moved for $YEARMONTH sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/000077500000000000000000000000001463772530400233635ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/background.bmp000066400000000000000000022617521463772530400262210ustar00rootroot00000000000000BMêc Š|í8 `c   ÿÿÿÿBGRsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿñññÿìììÿçççÿáááÿÚÚÚÿÒÒÒÿÌÌÌÿÆÆÆÿÂÂÂÿ¿¿¿ÿºººÿµµµÿ±±±ÿ­­­ÿ¨¨¨ÿ¦¦¦ÿ¤¤¤ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¢¢¢ÿ¤¤¤ÿ¦¦¦ÿ©©©ÿ­­­ÿ°°°ÿ³³³ÿ···ÿ½½½ÿÃÃÃÿËËËÿÓÓÓÿÚÚÚÿáááÿèèèÿðððÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿôôôÿíííÿçççÿßßßÿÖÖÖÿÍÍÍÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ’’’ÿ   ÿ²²²ÿÄÄÄÿÑÑÑÿßßßÿïïïÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿùùùÿóóóÿíííÿæææÿÞÞÞÿÚÚÚÿ×××ÿÔÔÔÿÑÑÑÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿÿ–––ÿ²²²ÿÇÇÇÿÞÞÞÿðððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿúúúÿöööÿñññÿìììÿéééÿæææÿãããÿàààÿÞÞÞÿÛÛÛÿØØØÿÕÕÕÿÒÒÒÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿ„„„ÿ¨¨¨ÿÇÇÇÿáááÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ÷÷÷ÿôôôÿòòòÿôôôÿõõõÿòòòÿïïïÿíííÿêêêÿèèèÿåååÿâââÿßßßÿÜÜÜÿÚÚÚÿ×××ÿÓÓÓÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿvvvÿšššÿÄÄÄÿäääÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿñññÿêêêÿèèèÿëëëÿïïïÿòòòÿõõõÿõõõÿóóóÿðððÿîîîÿëëëÿèèèÿæææÿãããÿàààÿÞÞÞÿÛÛÛÿØØØÿÔÔÔÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿzzzÿ°°°ÿÚÚÚÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿâââÿÝÝÝÿäääÿèèèÿëëëÿíííÿðððÿóóóÿöööÿöööÿôôôÿñññÿîîîÿìììÿéééÿçççÿäääÿáááÿßßßÿÜÜÜÿÚÚÚÿÕÕÕÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿtttÿ¯¯¯ÿàààÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿåååÿÖÖÖÿ×××ÿÚÚÚÿÝÝÝÿæææÿéééÿëëëÿîîîÿñññÿóóóÿöööÿöööÿôôôÿñññÿïïïÿìììÿêêêÿçççÿåååÿãããÿàààÿÞÞÞÿÛÛÛÿÖÖÖÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿƒƒƒÿÉÉÉÿøøøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿÝÝÝÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿÞÞÞÿçççÿéééÿìììÿïïïÿñññÿôôôÿöööÿöööÿôôôÿòòòÿðððÿíííÿëëëÿèèèÿæææÿäääÿáááÿßßßÿÜÜÜÿ×××ÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿnnnÿ½½½ÿõõõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿÞÞÞÿÈÈÈÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿÞÞÞÿèèèÿêêêÿíííÿïïïÿòòòÿôôôÿ÷÷÷ÿ÷÷÷ÿõõõÿòòòÿðððÿîîîÿìììÿéééÿçççÿåååÿâââÿàààÿÞÞÞÿ×××ÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿpppÿÄÄÄÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìììÿÆÆÆÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿßßßÿéééÿëëëÿîîîÿðððÿòòòÿõõõÿ÷÷÷ÿ÷÷÷ÿõõõÿóóóÿñññÿïïïÿìììÿêêêÿèèèÿæææÿãããÿáááÿßßßÿØØØÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿƒƒƒÿãããÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÛÛÛÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿàààÿêêêÿìììÿîîîÿñññÿóóóÿõõõÿøøøÿøøøÿöööÿóóóÿòòòÿïïïÿíííÿëëëÿéééÿçççÿåååÿãããÿáááÿÙÙÙÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ```ÿÂÂÂÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿÏÏÏÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿáááÿëëëÿíííÿïïïÿñññÿóóóÿöööÿøøøÿøøøÿöööÿôôôÿòòòÿðððÿîîîÿìììÿêêêÿèèèÿæææÿäääÿâââÿÙÙÙÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÐÐÐÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿâââÿìììÿîîîÿðððÿòòòÿôôôÿöööÿøøøÿøøøÿöööÿôôôÿóóóÿñññÿïïïÿíííÿëëëÿéééÿçççÿåååÿãããÿÙÙÙÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿªªªÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿãããÿíííÿïïïÿñññÿóóóÿõõõÿ÷÷÷ÿùùùÿøøøÿ÷÷÷ÿõõõÿóóóÿñññÿðððÿîîîÿìììÿêêêÿèèèÿæææÿäääÿÙÙÙÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿÉÉÉÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿµµµÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿãããÿîîîÿðððÿñññÿóóóÿõõõÿ÷÷÷ÿùùùÿùùùÿ÷÷÷ÿöööÿôôôÿòòòÿðððÿïïïÿíííÿëëëÿéééÿèèèÿæææÿÙÙÙÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿeeeÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÞÞÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿåååÿïïïÿðððÿòòòÿôôôÿöööÿ÷÷÷ÿùùùÿùùùÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿìììÿëëëÿéééÿçççÿÙÙÙÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿ¿¿¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÅÅÅÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿæææÿïïïÿñññÿóóóÿôôôÿöööÿøøøÿúúúÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿíííÿìììÿêêêÿéééÿÙÙÙÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿmmmÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿ‹‹‹ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿºººÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿçççÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿØØØÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿdddÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿèèèÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿØØØÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿéééÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿ×××ÿÎÎÎÿÌÌÌÿÉÉÉÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿêêêÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿâââÿÞÞÞÿÛÛÛÿØØØÿÕÕÕÿÒÒÒÿÏÏÏÿËËËÿÈÈÈÿÅÅÅÿÁÁÁÿ½½½ÿºººÿ¸¸¸ÿµµµÿ²²²ÿ®®®ÿªªªÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿëëëÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿèèèÿçççÿåååÿäääÿâââÿáááÿßßßÿÞÞÞÿÜÜÜÿÙÙÙÿ×××ÿÕÕÕÿÔÔÔÿÓÓÓÿÏÏÏÿÊÊÊÿÅÅÅÿÀÀÀÿ¼¼¼ÿ¶¶¶ÿ°°°ÿªªªÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ   ÿ   ÿŸŸŸÿžžžÿÿœœœÿ›››ÿšššÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿìììÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿäääÿàààÿÜÜÜÿÙÙÙÿ×××ÿÔÔÔÿÒÒÒÿËËËÿÅÅÅÿ½½½ÿ¶¶¶ÿ±±±ÿ¨¨¨ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿŸŸŸÿœœœÿ™™™ÿ–––ÿ’’’ÿŒŒŒÿˆˆˆÿƒƒƒÿÿ€€€ÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿíííÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿêêêÿåååÿÞÞÞÿØØØÿÔÔÔÿÐÐÐÿÐÐÐÿÏÏÏÿÇÇÇÿ¿¿¿ÿ¶¶¶ÿ®®®ÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿœœœÿ———ÿ‘‘‘ÿŠŠŠÿ‚‚‚ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿ×××ÿÚÚÚÿîîîÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿòòòÿèèèÿàààÿ×××ÿÑÑÑÿÐÐÐÿÐÐÐÿÐÐÐÿËËËÿÀÀÀÿ···ÿ¬¬¬ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¤¤¤ÿ¦¦¦ÿ©©©ÿ«««ÿ­­­ÿ¯¯¯ÿ°°°ÿ±±±ÿ±±±ÿ²²²ÿ²²²ÿ³³³ÿ³³³ÿ³³³ÿ²²²ÿ²²²ÿ²²²ÿ±±±ÿ°°°ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŸŸŸÿ˜˜˜ÿÿ………ÿyyyÿuuuÿtttÿsssÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÐÐÐÿÔÔÔÿÜÜÜÿéééÿîîîÿðððÿñññÿóóóÿõõõÿñññÿèèèÿßßßÿÔÔÔÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿÉÉÉÿ¾¾¾ÿ´´´ÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¨¨¨ÿ¬¬¬ÿ°°°ÿµµµÿ···ÿºººÿ¾¾¾ÿÁÁÁÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ¯¯¯ÿªªªÿ¦¦¦ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ›››ÿÿ‚‚‚ÿtttÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÒÒÒÿáááÿëëëÿìììÿîîîÿïïïÿêêêÿàààÿÖÖÖÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿÌÌÌÿÁÁÁÿ´´´ÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¤¤¤ÿ«««ÿ°°°ÿ¶¶¶ÿ»»»ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ½½½ÿ¹¹¹ÿ´´´ÿ®®®ÿ¨¨¨ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ–––ÿ‡‡‡ÿtttÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÊÊÊÿÔÔÔÿåååÿéééÿëëëÿçççÿÞÞÞÿÓÓÓÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿÇÇÇÿºººÿ¬¬¬ÿ¢¢¢ÿ£££ÿ«««ÿ²²²ÿ¹¹¹ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ½½½ÿ¶¶¶ÿ¯¯¯ÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ———ÿ„„„ÿnnnÿiiiÿgggÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿ×××ÿæææÿæææÿßßßÿÕÕÕÿÐÐÐÿÐÐÐÿÐÐÐÿÏÏÏÿÄÄÄÿ¶¶¶ÿ¦¦¦ÿ£££ÿªªªÿ´´´ÿ¼¼¼ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ¸¸¸ÿ°°°ÿ¦¦¦ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿÿvvvÿfffÿeeeÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÅÅÅÿÛÛÛÿãããÿÛÛÛÿÒÒÒÿÐÐÐÿÐÐÐÿÏÏÏÿÄÄÄÿµµµÿ¥¥¥ÿ¤¤¤ÿ¯¯¯ÿ¹¹¹ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿµµµÿªªªÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ———ÿzzzÿdddÿcccÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÄÄÄÿÜÜÜÿÚÚÚÿÑÑÑÿÐÐÐÿÐÐÐÿÇÇÇÿ···ÿ¦¦¦ÿ£££ÿ®®®ÿºººÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ´´´ÿ¨¨¨ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ———ÿuuuÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿºººÿÃÃÃÿØØØÿÒÒÒÿÐÐÐÿÍÍÍÿ¼¼¼ÿªªªÿ¢¢¢ÿ¦¦¦ÿ´´´ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¼¼¼ÿ®®®ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿÿgggÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ¶¶¶ÿÀÀÀÿÓÓÓÿÐÐÐÿÆÆÆÿ³³³ÿ£££ÿ¢¢¢ÿ§§§ÿ···ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÁÁÁÿÀÀÀÿ¾¾¾ÿ¾¾¾ÿ½½½ÿ¼¼¼ÿ¼¼¼ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ¼¼¼ÿ¼¼¼ÿ¾¾¾ÿ¿¿¿ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ°°°ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿžžžÿvvvÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ³³³ÿ»»»ÿÏÏÏÿÂÂÂÿ¬¬¬ÿ¢¢¢ÿ¢¢¢ÿ¤¤¤ÿµµµÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÁÁÁÿ¿¿¿ÿ½½½ÿºººÿ···ÿ³³³ÿ°°°ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ———ÿ–––ÿ–––ÿ———ÿ™™™ÿ›››ÿžžžÿ¢¢¢ÿ¦¦¦ÿ«««ÿ¯¯¯ÿ³³³ÿ¹¹¹ÿ¿¿¿ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ¬¬¬ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ‚‚‚ÿ\\\ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ¶¶¶ÿ¾¾¾ÿ©©©ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ«««ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÆÆÆÿÊÊÊÿÍÍÍÿÏÏÏÿÏÏÏÿÏÏÏÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿ‡‡‡ÿ‰‰‰ÿÿ™™™ÿ¢¢¢ÿ©©©ÿ´´´ÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¸¸¸ÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ………ÿ[[[ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¯¯¯ÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ²²²ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÊÊÊÿÒÒÒÿÙÙÙÿÝÝÝÿáááÿàààÿÝÝÝÿÚÚÚÿ×××ÿÔÔÔÿÑÑÑÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿÿÿœœœÿ«««ÿ¶¶¶ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ|||ÿZZZÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿ¨¨¨ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ´´´ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÎÎÎÿÛÛÛÿçççÿîîîÿîîîÿëëëÿéééÿæææÿãããÿáááÿÞÞÞÿÛÛÛÿØØØÿÖÖÖÿÒÒÒÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿ{{{ÿŒŒŒÿ   ÿ¯¯¯ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ   ÿgggÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ´´´ÿœœœÿœœœÿœœœÿœœœÿ«««ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÇÇÇÿÒÒÒÿßßßÿìììÿòòòÿõõõÿõõõÿòòòÿïïïÿíííÿêêêÿèèèÿåååÿâââÿßßßÿÝÝÝÿÚÚÚÿ×××ÿÓÓÓÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿtttÿˆˆˆÿŸŸŸÿµµµÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿÿœœœÿœœœÿœœœÿˆˆˆÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ©©©ÿŽŽŽÿŽŽŽÿŽŽŽÿÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÆÆÆÿÏÏÏÿÛÛÛÿåååÿéééÿìììÿðððÿóóóÿöööÿõõõÿóóóÿðððÿíííÿëëëÿèèèÿæææÿãããÿàààÿÞÞÞÿÛÛÛÿØØØÿÔÔÔÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿyyyÿ———ÿ±±±ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ©©©ÿŽŽŽÿŽŽŽÿŽŽŽÿÿ[[[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ™™™ÿ€€€ÿ€€€ÿ€€€ÿ•••ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÉÉÉÿÒÒÒÿÚÚÚÿÞÞÞÿåååÿèèèÿëëëÿîîîÿðððÿóóóÿöööÿöööÿóóóÿðððÿîîîÿìììÿéééÿçççÿäääÿâââÿßßßÿÜÜÜÿÚÚÚÿÕÕÕÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿwwwÿœœœÿ¹¹¹ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ···ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿdddÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ“““ÿrrrÿrrrÿrrrÿ™™™ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÈÈÈÿÏÏÏÿÔÔÔÿ×××ÿÛÛÛÿÞÞÞÿæææÿéééÿìììÿîîîÿñññÿôôôÿ÷÷÷ÿöööÿôôôÿñññÿïïïÿìììÿêêêÿèèèÿåååÿãããÿàààÿÞÞÞÿÛÛÛÿÖÖÖÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿhhhÿ‰‰‰ÿ¯¯¯ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿqqqÿrrrÿrrrÿrrrÿlllÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿœœœÿdddÿdddÿdddÿ†††ÿÃÃÃÿÃÃÃÿÃÃÃÿÅÅÅÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿßßßÿçççÿêêêÿìììÿïïïÿòòòÿôôôÿ÷÷÷ÿöööÿôôôÿòòòÿïïïÿíííÿëëëÿèèèÿæææÿäääÿáááÿßßßÿÝÝÝÿÖÖÖÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿÿ¯¯¯ÿÃÃÃÿÃÃÃÿµµµÿdddÿdddÿdddÿdddÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÂÂÂÿVVVÿVVVÿVVVÿ[[[ÿ¼¼¼ÿÂÂÂÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿàààÿèèèÿëëëÿíííÿðððÿòòòÿõõõÿ÷÷÷ÿ÷÷÷ÿôôôÿòòòÿðððÿîîîÿìììÿéééÿçççÿåååÿâââÿàààÿÞÞÞÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿ………ÿ¸¸¸ÿ–––ÿVVVÿVVVÿVVVÿVVVÿ¿¿¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïïïÿRRRÿNNNÿNNNÿWWWÿ¬¬¬ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿàààÿéééÿìììÿîîîÿðððÿóóóÿõõõÿøøøÿ÷÷÷ÿõõõÿóóóÿñññÿïïïÿìììÿêêêÿèèèÿæææÿäääÿáááÿßßßÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿdddÿ^^^ÿNNNÿNNNÿNNNÿ```ÿôôôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ±±±ÿNNNÿdddÿ®®®ÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿáááÿêêêÿìììÿïïïÿñññÿóóóÿöööÿøøøÿ÷÷÷ÿõõõÿóóóÿñññÿïïïÿíííÿëëëÿéééÿçççÿåååÿãããÿáááÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿYYYÿOOOÿNNNÿÌÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿÿ°°°ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿâââÿëëëÿíííÿïïïÿòòòÿôôôÿöööÿøøøÿøøøÿöööÿôôôÿòòòÿðððÿîîîÿìììÿêêêÿèèèÿæææÿäääÿâââÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿZZZÿ®®®ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿ¾¾¾ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿãããÿìììÿîîîÿðððÿòòòÿôôôÿöööÿøøøÿøøøÿöööÿôôôÿòòòÿñññÿïïïÿíííÿëëëÿéééÿçççÿåååÿãããÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ”””ÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÍÍÍÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿäääÿíííÿïïïÿñññÿóóóÿõõõÿ÷÷÷ÿùùùÿøøøÿ÷÷÷ÿõõõÿóóóÿñññÿðððÿîîîÿìììÿêêêÿèèèÿçççÿåååÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿ»»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïïïÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿåååÿîîîÿðððÿòòòÿóóóÿõõõÿ÷÷÷ÿùùùÿùùùÿ÷÷÷ÿõõõÿôôôÿòòòÿðððÿïïïÿíííÿëëëÿêêêÿèèèÿæææÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿ^^^ÿðððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÏÏÏÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿçççÿïïïÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿùùùÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿìììÿëëëÿéééÿèèèÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿ¾¾¾ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿºººÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿèèèÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿêêêÿéééÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿ‘‘‘ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿêêêÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿÖÖÖÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿ{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿêêêÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿÖÖÖÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿëëëÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿÕÕÕÿÎÎÎÿËËËÿÈÈÈÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿìììÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿåååÿãããÿáááÿÞÞÞÿÜÜÜÿÚÚÚÿØØØÿÔÔÔÿÑÑÑÿÎÎÎÿÊÊÊÿÇÇÇÿÄÄÄÿÁÁÁÿ¿¿¿ÿ½½½ÿ»»»ÿ···ÿ´´´ÿ±±±ÿ­­­ÿ©©©ÿ¤¤¤ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿíííÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿèèèÿæææÿåååÿãããÿâââÿàààÿÝÝÝÿÛÛÛÿØØØÿÖÖÖÿÕÕÕÿÓÓÓÿÎÎÎÿÈÈÈÿÁÁÁÿ¼¼¼ÿ¸¸¸ÿ´´´ÿ®®®ÿªªªÿ§§§ÿ¥¥¥ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ   ÿ   ÿžžžÿÿœœœÿšššÿ™™™ÿ———ÿ”””ÿÿÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿîîîÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿçççÿâââÿÞÞÞÿÚÚÚÿ×××ÿÔÔÔÿÑÑÑÿÎÎÎÿÇÇÇÿÀÀÀÿ···ÿ±±±ÿ©©©ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŸŸŸÿœœœÿ˜˜˜ÿ”””ÿÿŠŠŠÿƒƒƒÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿîîîÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿñññÿéééÿâââÿÛÛÛÿÖÖÖÿÑÑÑÿÐÐÐÿÐÐÐÿÍÍÍÿÄÄÄÿ¼¼¼ÿ²²²ÿ©©©ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŸŸŸÿšššÿ“““ÿ‹‹‹ÿ‚‚‚ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÞÞÞÿîîîÿðððÿñññÿóóóÿõõõÿöööÿøøøÿùùùÿòòòÿçççÿÞÞÞÿÕÕÕÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿÉÉÉÿ¾¾¾ÿ´´´ÿ©©©ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¥¥¥ÿ¨¨¨ÿªªªÿ®®®ÿ°°°ÿ²²²ÿ´´´ÿµµµÿ¶¶¶ÿ···ÿ¹¹¹ÿºººÿºººÿ»»»ÿ»»»ÿ¼¼¼ÿ»»»ÿ»»»ÿ»»»ÿºººÿ¹¹¹ÿ¸¸¸ÿ···ÿ¶¶¶ÿ´´´ÿ³³³ÿ±±±ÿ¯¯¯ÿ¬¬¬ÿ©©©ÿ¦¦¦ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ   ÿ™™™ÿÿ………ÿxxxÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÕÕÕÿâââÿìììÿîîîÿðððÿñññÿóóóÿðððÿçççÿÝÝÝÿÒÒÒÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿÈÈÈÿ½½½ÿ²²²ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¨¨¨ÿ¬¬¬ÿ±±±ÿ¶¶¶ÿ¹¹¹ÿ¼¼¼ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ¾¾¾ÿºººÿ···ÿ³³³ÿ®®®ÿªªªÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ™™™ÿŽŽŽÿÿqqqÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿ×××ÿçççÿëëëÿíííÿîîîÿêêêÿáááÿÖÖÖÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿÌÌÌÿÀÀÀÿ³³³ÿ¦¦¦ÿ¢¢¢ÿ¢¢¢ÿ§§§ÿ®®®ÿ³³³ÿºººÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ¼¼¼ÿ¶¶¶ÿ°°°ÿªªªÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŸŸŸÿ“““ÿÿoooÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿËËËÿÜÜÜÿçççÿéééÿèèèÿßßßÿÕÕÕÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿÈÈÈÿºººÿ¬¬¬ÿ¢¢¢ÿ¤¤¤ÿ¬¬¬ÿ´´´ÿ»»»ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ¾¾¾ÿ¶¶¶ÿ°°°ÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ   ÿÿ{{{ÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÊÊÊÿßßßÿæææÿáááÿØØØÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿÆÆÆÿ···ÿ¨¨¨ÿ¢¢¢ÿ«««ÿ´´´ÿ½½½ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ¸¸¸ÿ¯¯¯ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ›››ÿ………ÿjjjÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿËËËÿáááÿÞÞÞÿÔÔÔÿÐÐÐÿÐÐÐÿÐÐÐÿÆÆÆÿ···ÿ§§§ÿ£££ÿ®®®ÿ¸¸¸ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¼¼¼ÿ²²²ÿ¦¦¦ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŸŸŸÿˆˆˆÿiiiÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÌÌÌÿÜÜÜÿÔÔÔÿÐÐÐÿÐÐÐÿÊÊÊÿºººÿ¨¨¨ÿ¢¢¢ÿªªªÿ···ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¼¼¼ÿ¯¯¯ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŸŸŸÿƒƒƒÿcccÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿËËËÿÖÖÖÿÐÐÐÿÏÏÏÿÁÁÁÿ¯¯¯ÿ¢¢¢ÿ£££ÿ°°°ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿµµµÿ¦¦¦ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ™™™ÿrrrÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿ¶¶¶ÿÇÇÇÿÒÒÒÿËËËÿ¹¹¹ÿ¦¦¦ÿ¢¢¢ÿ£££ÿ±±±ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÁÁÁÿÀÀÀÿ¾¾¾ÿ¼¼¼ÿºººÿ¸¸¸ÿ¶¶¶ÿµµµÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ©©©ÿ¨¨¨ÿ§§§ÿ§§§ÿ§§§ÿ§§§ÿ¨¨¨ÿ©©©ÿ«««ÿ­­­ÿ¯¯¯ÿ±±±ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ···ÿ¦¦¦ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿƒƒƒÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ³³³ÿÂÂÂÿÉÉÉÿ´´´ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ«««ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÅÅÅÿÇÇÇÿÉÉÉÿÉÉÉÿÈÈÈÿÇÇÇÿÅÅÅÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿÿŒŒŒÿÿ”””ÿšššÿ¢¢¢ÿ¨¨¨ÿ®®®ÿ¶¶¶ÿ½½½ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ³³³ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŽŽŽÿ^^^ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ°°°ÿ¶¶¶ÿ²²²ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¶¶¶ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÇÇÇÿÍÍÍÿÒÒÒÿÖÖÖÿ×××ÿÙÙÙÿ×××ÿÔÔÔÿÑÑÑÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿ„„„ÿÿ›››ÿ¥¥¥ÿ±±±ÿ»»»ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ½½½ÿ¨¨¨ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿÿ\\\ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ­­­ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¤¤¤ÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÐÐÐÿÙÙÙÿâââÿçççÿéééÿæææÿãããÿàààÿÝÝÝÿÛÛÛÿØØØÿÕÕÕÿÒÒÒÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿ€€€ÿ‘‘‘ÿ¡¡¡ÿ°°°ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ«««ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ„„„ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ½½½ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÌÌÌÿÙÙÙÿçççÿóóóÿôôôÿñññÿïïïÿìììÿêêêÿçççÿäääÿáááÿßßßÿÜÜÜÿÙÙÙÿÖÖÖÿÓÓÓÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿvvvÿ„„„ÿ›››ÿ®®®ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿªªªÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿkkkÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¦¦¦ÿ˜˜˜ÿ˜˜˜ÿ˜˜˜ÿ˜˜˜ÿ³³³ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÍÍÍÿØØØÿåååÿëëëÿïïïÿòòòÿõõõÿõõõÿòòòÿðððÿíííÿëëëÿèèèÿåååÿâââÿàààÿÝÝÝÿÚÚÚÿØØØÿÔÔÔÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿrrrÿ‹‹‹ÿ£££ÿ»»»ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ›››ÿ˜˜˜ÿ˜˜˜ÿ˜˜˜ÿ‡‡‡ÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ———ÿ‹‹‹ÿ‹‹‹ÿ‹‹‹ÿ“““ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÈÈÈÿÒÒÒÿÜÜÜÿäääÿçççÿëëëÿíííÿðððÿóóóÿöööÿõõõÿóóóÿðððÿîîîÿëëëÿéééÿæææÿäääÿáááÿÞÞÞÿÜÜÜÿÙÙÙÿÕÕÕÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿ„„„ÿ¤¤¤ÿ½½½ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ©©©ÿ‹‹‹ÿ‹‹‹ÿ‹‹‹ÿ‰‰‰ÿxxxÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ†††ÿ|||ÿ|||ÿ|||ÿžžžÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÉÉÉÿÑÑÑÿ×××ÿÚÚÚÿÞÞÞÿæææÿèèèÿëëëÿîîîÿñññÿóóóÿöööÿöööÿóóóÿñññÿîîîÿìììÿêêêÿçççÿåååÿâââÿàààÿÝÝÝÿÛÛÛÿÕÕÕÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿlllÿÿ²²²ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿµµµÿ|||ÿ|||ÿ|||ÿ|||ÿ~~~ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‚‚‚ÿoooÿoooÿoooÿÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÇÇÇÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿÞÞÞÿçççÿéééÿìììÿïïïÿñññÿôôôÿ÷÷÷ÿöööÿôôôÿñññÿïïïÿíííÿêêêÿèèèÿæææÿãããÿáááÿÞÞÞÿÜÜÜÿÖÖÖÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿÿ«««ÿÃÃÃÿÃÃÃÿÃÃÃÿ···ÿnnnÿoooÿoooÿoooÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ–––ÿ```ÿ```ÿ```ÿ‡‡‡ÿÃÃÃÿÃÃÃÿÃÃÃÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿßßßÿèèèÿêêêÿíííÿïïïÿòòòÿôôôÿ÷÷÷ÿöööÿôôôÿòòòÿðððÿîîîÿëëëÿéééÿçççÿäääÿâââÿàààÿÝÝÝÿÖÖÖÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿ|||ÿ°°°ÿÃÃÃÿ©©©ÿ```ÿ```ÿ```ÿ```ÿ¦¦¦ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÁÁÁÿSSSÿSSSÿSSSÿVVVÿ¸¸¸ÿÁÁÁÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿàààÿéééÿëëëÿîîîÿðððÿòòòÿõõõÿ÷÷÷ÿ÷÷÷ÿõõõÿòòòÿðððÿîîîÿìììÿêêêÿèèèÿåååÿãããÿáááÿßßßÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿŒŒŒÿzzzÿSSSÿSSSÿSSSÿTTTÿÙÙÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿWWWÿNNNÿNNNÿˆˆˆÿ»»»ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿáááÿêêêÿìììÿîîîÿñññÿóóóÿõõõÿøøøÿ÷÷÷ÿõõõÿóóóÿñññÿïïïÿíííÿëëëÿéééÿæææÿäääÿâââÿàààÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ]]]ÿSSSÿNNNÿNNNÿ‡‡‡ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿNNNÿ•••ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿâââÿëëëÿíííÿïïïÿñññÿôôôÿöööÿøøøÿøøøÿöööÿôôôÿòòòÿðððÿîîîÿìììÿêêêÿèèèÿåååÿäääÿáááÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ]]]ÿTTTÿ]]]ÿêêêÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ¨¨¨ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿâââÿìììÿîîîÿðððÿòòòÿôôôÿöööÿøøøÿøøøÿöööÿôôôÿòòòÿðððÿîîîÿíííÿëëëÿéééÿçççÿåååÿãããÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿçççÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿãããÿíííÿïïïÿñññÿóóóÿõõõÿ÷÷÷ÿùùùÿøøøÿ÷÷÷ÿõõõÿóóóÿñññÿïïïÿíííÿìììÿêêêÿèèèÿæææÿäääÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ^^^ÿäääÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿ···ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿåååÿîîîÿïïïÿñññÿóóóÿõõõÿ÷÷÷ÿùùùÿùùùÿ÷÷÷ÿõõõÿóóóÿòòòÿðððÿîîîÿíííÿëëëÿéééÿçççÿæææÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿ‚‚‚ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÞÞÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿæææÿïïïÿðððÿòòòÿôôôÿöööÿøøøÿùùùÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿïïïÿîîîÿìììÿêêêÿéééÿçççÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿÕÕÕÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÃÃÃÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿèèèÿðððÿñññÿóóóÿôôôÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿóóóÿòòòÿðððÿïïïÿíííÿìììÿêêêÿèèèÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿ¢¢¢ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³³³ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿéééÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿ×××ÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿ‚‚‚ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿêêêÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿÖÖÖÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿëëëÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿÖÖÖÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÃÃÃÿÀÀÀÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿëëëÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿÝÝÝÿØØØÿÕÕÕÿÒÒÒÿÏÏÏÿÌÌÌÿÈÈÈÿÅÅÅÿÁÁÁÿ½½½ÿ¸¸¸ÿ´´´ÿ°°°ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿìììÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿèèèÿæææÿåååÿãããÿâââÿáááÿßßßÿÞÞÞÿÜÜÜÿÛÛÛÿÙÙÙÿØØØÿÖÖÖÿÔÔÔÿÒÒÒÿÏÏÏÿÉÉÉÿÃÃÃÿ¼¼¼ÿ···ÿ±±±ÿ«««ÿ¥¥¥ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ   ÿŸŸŸÿžžžÿžžžÿœœœÿ›››ÿšššÿ˜˜˜ÿ———ÿ”””ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿŒŒŒÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿíííÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿëëëÿéééÿèèèÿäääÿàààÿÝÝÝÿÚÚÚÿ×××ÿÕÕÕÿÓÓÓÿÎÎÎÿÇÇÇÿÀÀÀÿ¹¹¹ÿ´´´ÿ­­­ÿ¦¦¦ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿžžžÿœœœÿšššÿ———ÿ”””ÿÿ‹‹‹ÿ†††ÿ„„„ÿƒƒƒÿÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÚÚÚÿîîîÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿòòòÿðððÿêêêÿäääÿÞÞÞÿÙÙÙÿÕÕÕÿÑÑÑÿÐÐÐÿÏÏÏÿÇÇÇÿÀÀÀÿ···ÿ¯¯¯ÿ¦¦¦ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŸŸŸÿšššÿ–––ÿÿ‰‰‰ÿÿ|||ÿ{{{ÿzzzÿyyyÿxxxÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿ×××ÿÛÛÛÿîîîÿðððÿñññÿóóóÿõõõÿöööÿøøøÿúúúÿùùùÿ÷÷÷ÿðððÿçççÿßßßÿ×××ÿÑÑÑÿÐÐÐÿÐÐÐÿÐÐÐÿÉÉÉÿ¿¿¿ÿ¶¶¶ÿ«««ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¥¥¥ÿ¦¦¦ÿ¨¨¨ÿ©©©ÿªªªÿ«««ÿ¬¬¬ÿ¬¬¬ÿ¬¬¬ÿ¬¬¬ÿ¬¬¬ÿ«««ÿ«««ÿªªªÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿžžžÿ˜˜˜ÿÿ†††ÿzzzÿvvvÿuuuÿtttÿrrrÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÔÔÔÿÙÙÙÿæææÿîîîÿðððÿñññÿóóóÿõõõÿöööÿðððÿæææÿÜÜÜÿÒÒÒÿÐÐÐÿÐÐÐÿÐÐÐÿÏÏÏÿÇÇÇÿ¼¼¼ÿ±±±ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¥¥¥ÿ©©©ÿ­­­ÿ±±±ÿµµµÿ···ÿ¹¹¹ÿ¼¼¼ÿ¿¿¿ÿÁÁÁÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÂÂÂÿÀÀÀÿ¾¾¾ÿ»»»ÿ¸¸¸ÿ¶¶¶ÿ³³³ÿ¯¯¯ÿ«««ÿ§§§ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ›››ÿ‘‘‘ÿ„„„ÿwwwÿqqqÿpppÿoooÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÍÍÍÿÑÑÑÿÞÞÞÿêêêÿìììÿîîîÿðððÿïïïÿçççÿÝÝÝÿÒÒÒÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿÈÈÈÿ½½½ÿ°°°ÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ£££ÿªªªÿ¯¯¯ÿµµµÿºººÿ½½½ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ»»»ÿ···ÿ±±±ÿ¬¬¬ÿ¦¦¦ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ™™™ÿ‹‹‹ÿzzzÿnnnÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÊÊÊÿÑÑÑÿãããÿéééÿëëëÿëëëÿãããÿÙÙÙÿÑÑÑÿÐÐÐÿÐÐÐÿÐÐÐÿÎÎÎÿÂÂÂÿµµµÿ§§§ÿ¢¢¢ÿ¤¤¤ÿ¬¬¬ÿ²²²ÿ¹¹¹ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ¼¼¼ÿµµµÿ¯¯¯ÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿœœœÿ‹‹‹ÿvvvÿjjjÿiiiÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿÇÇÇÿÔÔÔÿåååÿèèèÿäääÿÚÚÚÿÑÑÑÿÐÐÐÿÐÐÐÿÐÐÐÿÌÌÌÿ¾¾¾ÿ°°°ÿ£££ÿ¤¤¤ÿ­­­ÿ¶¶¶ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ¹¹¹ÿ±±±ÿ¨¨¨ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ˜˜˜ÿ‚‚‚ÿkkkÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÄÄÄÿ×××ÿäääÿßßßÿÕÕÕÿÐÐÐÿÐÐÐÿÐÐÐÿËËËÿ¾¾¾ÿ­­­ÿ¢¢¢ÿ¨¨¨ÿ³³³ÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ···ÿ­­­ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŸŸŸÿ‰‰‰ÿkkkÿdddÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÂÂÂÿÙÙÙÿÝÝÝÿÓÓÓÿÐÐÐÿÐÐÐÿÍÍÍÿ¿¿¿ÿ®®®ÿ¢¢¢ÿ§§§ÿ´´´ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ¸¸¸ÿ¬¬¬ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ   ÿ‰‰‰ÿgggÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿºººÿÀÀÀÿØØØÿÔÔÔÿÐÐÐÿÐÐÐÿÄÄÄÿ³³³ÿ£££ÿ£££ÿ¯¯¯ÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ´´´ÿ¦¦¦ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿžžžÿ~~~ÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿ¶¶¶ÿ¾¾¾ÿÓÓÓÿÐÐÐÿÌÌÌÿ»»»ÿ¨¨¨ÿ¢¢¢ÿ£££ÿ²²²ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¸¸¸ÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ”””ÿgggÿ^^^ÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ³³³ÿºººÿÏÏÏÿÉÉÉÿµµµÿ£££ÿ¢¢¢ÿ¢¢¢ÿ°°°ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ···ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿÿqqqÿ\\\ÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿµµµÿÄÄÄÿ±±±ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ§§§ÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ¯¯¯ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ   ÿsssÿ[[[ÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ°°°ÿ¬¬¬ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ®®®ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¸¸¸ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿŸŸŸÿlllÿZZZÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ©©©ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ°°°ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ»»»ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿšššÿ]]]ÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿŸŸŸÿžžžÿžžžÿžžžÿªªªÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ···ÿžžžÿžžžÿžžžÿžžžÿ~~~ÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ   ÿ‘‘‘ÿ‘‘‘ÿ‘‘‘ÿ’’’ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ   ÿ‘‘‘ÿ‘‘‘ÿ‘‘‘ÿ‹‹‹ÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŽŽŽÿƒƒƒÿƒƒƒÿƒƒƒÿ™™™ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ±±±ÿƒƒƒÿƒƒƒÿƒƒƒÿƒƒƒÿzzzÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿuuuÿuuuÿuuuÿŸŸŸÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¸¸¸ÿuuuÿuuuÿuuuÿuuuÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŒŒŒÿgggÿgggÿgggÿ•••ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ²²²ÿgggÿgggÿgggÿgggÿ”””ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿªªªÿYYYÿYYYÿYYYÿkkkÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ˜˜˜ÿYYYÿYYYÿYYYÿYYYÿÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜÜÜÿOOOÿOOOÿOOOÿNNNÿŸŸŸÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ»»»ÿ[[[ÿOOOÿOOOÿOOOÿ\\\ÿòòòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŒŒŒÿNNNÿNNNÿNNNÿWWWÿ²²²ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿxxxÿNNNÿNNNÿNNNÿNNNÿÂÂÂÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëëëÿ[[[ÿNNNÿNNNÿNNNÿ\\\ÿ±±±ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ|||ÿNNNÿNNNÿNNNÿNNNÿÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙÙÙÿSSSÿNNNÿNNNÿNNNÿTTTÿ   ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿµµµÿmmmÿNNNÿNNNÿNNNÿNNNÿ˜˜˜ÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ×××ÿXXXÿNNNÿNNNÿNNNÿNNNÿ{{{ÿ¸¸¸ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ˜˜˜ÿSSSÿNNNÿNNNÿNNNÿNNNÿ¥¥¥ÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿæææÿuuuÿNNNÿNNNÿNNNÿNNNÿRRRÿÿ»»»ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ£££ÿeeeÿNNNÿNNNÿNNNÿNNNÿRRRÿÂÂÂÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿ«««ÿNNNÿNNNÿNNNÿNNNÿNNNÿTTTÿŒŒŒÿ¶¶¶ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿžžžÿgggÿNNNÿNNNÿNNNÿNNNÿNNNÿÿäääÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿãããÿ‰‰‰ÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿxxxÿ¤¤¤ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ±±±ÿŒŒŒÿXXXÿNNNÿNNNÿNNNÿNNNÿNNNÿbbbÿÅÅÅÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ×××ÿ„„„ÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿWWWÿƒƒƒÿ§§§ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ±±±ÿ”””ÿhhhÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿaaaÿ½½½ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÞÞÿ›››ÿRRRÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿSSSÿ{{{ÿšššÿ´´´ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¼¼¼ÿ¥¥¥ÿŠŠŠÿ```ÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿyyyÿÇÇÇÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñññÿÀÀÀÿyyyÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿZZZÿÿ™™™ÿ¯¯¯ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿµµµÿ£££ÿ‹‹‹ÿkkkÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿ^^^ÿ¨¨¨ÿàààÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿçççÿºººÿ|||ÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿlllÿ………ÿ›››ÿªªªÿ¹¹¹ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ¯¯¯ÿ¢¢¢ÿÿvvvÿWWWÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿ```ÿ¦¦¦ÿ×××ÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿîîîÿÉÉÉÿÿ```ÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿMMMÿUUUÿlllÿ‚‚‚ÿ’’’ÿÿ©©©ÿ´´´ÿ¼¼¼ÿÂÂÂÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ®®®ÿ¢¢¢ÿ———ÿ‰‰‰ÿtttÿ^^^ÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿPPPÿ………ÿ»»»ÿàààÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿæææÿÈÈÈÿ¡¡¡ÿrrrÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿPPPÿ]]]ÿrrrÿ}}}ÿ†††ÿŒŒŒÿ’’’ÿ˜˜˜ÿ   ÿ£££ÿ§§§ÿ«««ÿ®®®ÿ¯¯¯ÿ¯¯¯ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ¨¨¨ÿ¤¤¤ÿ¢¢¢ÿ›››ÿ”””ÿŽŽŽÿˆˆˆÿÿvvvÿhhhÿTTTÿOOOÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿZZZÿ“““ÿ»»»ÿÛÛÛÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóóóÿÞÞÞÿÀÀÀÿ§§§ÿ~~~ÿRRRÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿiiiÿ™™™ÿµµµÿÓÓÓÿêêêÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿîîîÿÙÙÙÿÇÇÇÿµµµÿ›››ÿ~~~ÿaaaÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿWWWÿrrrÿŽŽŽÿ«««ÿÀÀÀÿÒÒÒÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿìììÿàààÿÖÖÖÿÍÍÍÿÁÁÁÿ³³³ÿ§§§ÿ›››ÿ’’’ÿŠŠŠÿƒƒƒÿyyyÿnnnÿfffÿ]]]ÿWWWÿSSSÿNNNÿRRRÿUUUÿZZZÿbbbÿlllÿtttÿÿ‡‡‡ÿŽŽŽÿ———ÿ¢¢¢ÿ¯¯¯ÿ¼¼¼ÿÈÈÈÿÒÒÒÿÛÛÛÿæææÿôôôÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿsqlitebrowser-sqlitebrowser-5733cb7/installer/windows/banner.bmp000066400000000000000000003375221463772530400253440ustar00rootroot00000000000000BMR¿Š|í: Ⱦ  ÿÿÿÿBGRsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿñññÿéééÿàààÿÓÓÓÿÉÉÉÿÁÁÁÿ²²²ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ£££ÿ®®®ÿ­­­ÿ¼¼¼ÿÃÃÃÿÕÕÕÿàààÿïïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿùùùÿùùùÿòòòÿèèèÿàààÿÙÙÙÿÐÐÐÿÈÈÈÿÀÀÀÿ¸¸¸ÿ±±±ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ–––ÿ’’’ÿÿŒŒŒÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿÿ¤¤¤ÿÅÅÅÿáááÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿçççÿçççÿïïïÿõõõÿñññÿêêêÿãããÿÜÜÜÿÑÑÑÿÈÈÈÿÀÀÀÿ¸¸¸ÿ±±±ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ–––ÿ’’’ÿÿŒŒŒÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿyyyÿ°°°ÿäääÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïïïÿÔÔÔÿÒÒÒÿÛÛÛÿêêêÿñññÿöööÿòòòÿìììÿæææÿàààÿÒÒÒÿÈÈÈÿÀÀÀÿ¸¸¸ÿ±±±ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ–––ÿ’’’ÿÿŒŒŒÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿnnnÿjjjÿgggÿ‘‘‘ÿäääÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛÛÛÿÁÁÁÿÉÉÉÿÒÒÒÿÝÝÝÿìììÿòòòÿ÷÷÷ÿôôôÿîîîÿéééÿãããÿÒÒÒÿÈÈÈÿÀÀÀÿ¸¸¸ÿ±±±ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ–––ÿ’’’ÿÿŒŒŒÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿnnnÿjjjÿgggÿdddÿ```ÿ½½½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááÿ¸¸¸ÿÁÁÁÿÉÉÉÿÒÒÒÿÞÞÞÿïïïÿôôôÿøøøÿõõõÿðððÿëëëÿçççÿÓÓÓÿÈÈÈÿÀÀÀÿ¸¸¸ÿ±±±ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ–––ÿ’’’ÿÿŒŒŒÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿnnnÿjjjÿgggÿdddÿ```ÿ]]]ÿÉÉÉÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿºººÿ¸¸¸ÿÁÁÁÿÉÉÉÿÒÒÒÿÞÞÞÿñññÿõõõÿùùùÿöööÿòòòÿîîîÿêêêÿÔÔÔÿÈÈÈÿÀÀÀÿ¸¸¸ÿ±±±ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ–––ÿ’’’ÿÿŒŒŒÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿnnnÿjjjÿgggÿdddÿ```ÿ]]]ÿtttÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÉÉÉÿÒÒÒÿàààÿñññÿöööÿùùùÿ÷÷÷ÿóóóÿïïïÿëëëÿÔÔÔÿÈÈÈÿÀÀÀÿ¸¸¸ÿ±±±ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ–––ÿ’’’ÿÿŒŒŒÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿnnnÿjjjÿgggÿdddÿ```ÿ]]]ÿZZZÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÉÉÉÿÒÒÒÿâââÿñññÿöööÿùùùÿ÷÷÷ÿóóóÿïïïÿëëëÿåååÿßßßÿÙÙÙÿÌÌÌÿÀÀÀÿ¹¹¹ÿ±±±ÿ¬¬¬ÿ¥¥¥ÿ¡¡¡ÿ   ÿžžžÿÿšššÿ———ÿ“““ÿŽŽŽÿ‡‡‡ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿnnnÿjjjÿgggÿdddÿ```ÿ]]]ÿZZZÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÉÉÉÿÒÒÒÿãããÿñññÿöööÿôôôÿéééÿßßßÿÑÑÑÿÁÁÁÿ¶¶¶ÿ¬¬¬ÿ§§§ÿ©©©ÿ«««ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿªªªÿ©©©ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ   ÿšššÿ“““ÿˆˆˆÿzzzÿqqqÿnnnÿjjjÿgggÿdddÿ```ÿ]]]ÿZZZÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿËËËÿàààÿæææÿßßßÿÒÒÒÿÂÂÂÿ¸¸¸ÿ³³³ÿµµµÿ»»»ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ¹¹¹ÿ´´´ÿ­­­ÿ¥¥¥ÿ¢¢¢ÿœœœÿ‹‹‹ÿvvvÿgggÿdddÿ```ÿ]]]ÿZZZÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÅÅÅÿÙÙÙÿÒÒÒÿÀÀÀÿ¹¹¹ÿ¶¶¶ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ´´´ÿ©©©ÿ¢¢¢ÿ–––ÿwwwÿ```ÿ]]]ÿZZZÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¾¾¾ÿÈÈÈÿµµµÿ²²²ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿÀÀÀÿ¾¾¾ÿ»»»ÿ¹¹¹ÿ···ÿ¶¶¶ÿ¶¶¶ÿ···ÿ»»»ÿºººÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ½½½ÿ­­­ÿ¢¢¢ÿ‘‘‘ÿaaaÿZZZÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ÿ¬¬¬ÿ¦¦¦ÿ½½½ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿËËËÿÑÑÑÿÓÓÓÿÒÒÒÿÍÍÍÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿŒŒŒÿ”””ÿœœœÿ¥¥¥ÿ°°°ÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿºººÿ¤¤¤ÿ———ÿ^^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸŸŸÿ›››ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÅÅÅÿÒÒÒÿâââÿòòòÿïïïÿèèèÿáááÿÚÚÚÿÐÐÐÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿÿ~~~ÿ{{{ÿwwwÿ€€€ÿ•••ÿ®®®ÿÀÀÀÿÃÃÃÿÃÃÃÿºººÿ™™™ÿ|||ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{{{ÿŠŠŠÿÃÃÃÿÅÅÅÿÎÎÎÿÛÛÛÿéééÿðððÿöööÿñññÿëëëÿäääÿÝÝÝÿÑÑÑÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿqqqÿ”””ÿ···ÿÃÃÃÿ|||ÿoooÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ›››ÿkkkÿÂÂÂÿÊÊÊÿÒÒÒÿÝÝÝÿëëëÿñññÿ÷÷÷ÿóóóÿíííÿçççÿáááÿÑÑÑÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿŽŽŽÿTTTÿœœœÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâââÿ°°°ÿÁÁÁÿÊÊÊÿÒÒÒÿÞÞÞÿíííÿóóóÿøøøÿôôôÿïïïÿêêêÿäääÿÒÒÒÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿZZZÿìììÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÐÐÐÿ¸¸¸ÿÁÁÁÿÊÊÊÿÒÒÒÿÞÞÞÿðððÿõõõÿùùùÿõõõÿñññÿìììÿèèèÿÓÓÓÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿ¯¯¯ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°ÿ¸¸¸ÿÁÁÁÿÊÊÊÿÒÒÒÿàààÿñññÿöööÿùùùÿöööÿòòòÿïïïÿêêêÿÓÓÓÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿeeeÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÊÊÊÿÒÒÒÿâââÿñññÿöööÿùùùÿ÷÷÷ÿóóóÿïïïÿëëëÿÚÚÚÿÐÐÐÿÇÇÇÿÀÀÀÿ¹¹¹ÿ¶¶¶ÿ±±±ÿ§§§ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÊÊÊÿÒÒÒÿâââÿñññÿöööÿùùùÿ÷÷÷ÿóóóÿêêêÿãããÿÝÝÝÿÒÒÒÿÇÇÇÿ½½½ÿ···ÿ­­­ÿªªªÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿŸŸŸÿžžžÿšššÿ˜˜˜ÿ’’’ÿ‹‹‹ÿ‚‚‚ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÊÊÊÿÔÔÔÿçççÿñññÿíííÿåååÿÚÚÚÿÇÇÇÿºººÿ²²²ÿ«««ÿ¯¯¯ÿ±±±ÿ···ÿ···ÿ¹¹¹ÿ½½½ÿ½½½ÿ½½½ÿ½½½ÿ½½½ÿ¼¼¼ÿ¸¸¸ÿ···ÿ¶¶¶ÿ°°°ÿ®®®ÿ©©©ÿ£££ÿ¢¢¢ÿŸŸŸÿ———ÿŒŒŒÿzzzÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÑÑÑÿâââÿÜÜÜÿÏÏÏÿ¿¿¿ÿ¹¹¹ÿµµµÿºººÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ¹¹¹ÿ±±±ÿ¨¨¨ÿ¢¢¢ÿÿŠŠŠÿoooÿcccÿ```ÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿËËËÿÔÔÔÿÀÀÀÿ···ÿ···ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ´´´ÿ§§§ÿ¡¡¡ÿÿgggÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¾¾¾ÿ¸¸¸ÿ¬¬¬ÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÇÇÇÿÇÇÇÿÅÅÅÿÁÁÁÿ¼¼¼ÿ¸¸¸ÿ²²²ÿ¯¯¯ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ£££ÿ¤¤¤ÿ¨¨¨ÿ¦¦¦ÿ¬¬¬ÿ¯¯¯ÿ···ÿ½½½ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¸¸¸ÿ¦¦¦ÿÿrrrÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿªªªÿ£££ÿ°°°ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÉÉÉÿØØØÿàààÿâââÿàààÿØØØÿÐÐÐÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿ‚‚‚ÿÿÿžžžÿ®®®ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ«««ÿ   ÿhhhÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ’’’ÿ–––ÿÃÃÃÿÃÃÃÿÅÅÅÿÐÐÐÿâââÿïïïÿõõõÿðððÿêêêÿãããÿÜÜÜÿÐÐÐÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿ†††ÿ¢¢¢ÿ¾¾¾ÿÃÃÃÿ¿¿¿ÿÿzzzÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿtttÿˆˆˆÿÃÃÃÿÈÈÈÿÒÒÒÿÜÜÜÿêêêÿñññÿöööÿòòòÿìììÿåååÿßßßÿÑÑÑÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿjjjÿ“““ÿ¼¼¼ÿhhhÿzzzÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿ†††ÿÁÁÁÿÊÊÊÿÒÒÒÿÝÝÝÿìììÿòòòÿ÷÷÷ÿóóóÿîîîÿèèèÿâââÿÒÒÒÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿaaaÿTTTÿÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿäääÿ¸¸¸ÿÁÁÁÿÊÊÊÿÒÒÒÿÞÞÞÿîîîÿôôôÿøøøÿõõõÿðððÿëëëÿæææÿÓÓÓÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿÝÝÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ½½½ÿ¸¸¸ÿÁÁÁÿÊÊÊÿÒÒÒÿßßßÿñññÿõõõÿùùùÿöööÿòòòÿîîîÿéééÿÔÔÔÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿŒŒŒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÊÊÊÿÒÒÒÿáááÿñññÿöööÿùùùÿ÷÷÷ÿóóóÿïïïÿëëëÿÓÓÓÿÇÇÇÿÀÀÀÿ¸¸¸ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿŸŸŸÿœœœÿ™™™ÿ•••ÿ’’’ÿÿ‹‹‹ÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÊÊÊÿÒÒÒÿâââÿñññÿöööÿùùùÿ÷÷÷ÿóóóÿïïïÿëëëÿãããÿÞÞÞÿÕÕÕÿÍÍÍÿÃÃÃÿ»»»ÿ³³³ÿ¬¬¬ÿ£££ÿ   ÿžžžÿœœœÿ›››ÿ–––ÿ“““ÿŽŽŽÿˆˆˆÿ………ÿ‚‚‚ÿ~~~ÿ{{{ÿwwwÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÊÊÊÿÒÒÒÿâââÿñññÿöööÿùùùÿðððÿåååÿÝÝÝÿÏÏÏÿÂÂÂÿ¶¶¶ÿ­­­ÿ£££ÿ¤¤¤ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿªªªÿ¨¨¨ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿžžžÿšššÿ“““ÿŠŠŠÿ~~~ÿtttÿqqqÿmmmÿjjjÿgggÿcccÿ```ÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÁÁÁÿÊÊÊÿÜÜÜÿêêêÿåååÿÜÜÜÿÍÍÍÿ½½½ÿ¶¶¶ÿ±±±ÿ´´´ÿ¸¸¸ÿ½½½ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ½½½ÿ···ÿ³³³ÿ­­­ÿ¦¦¦ÿ¢¢¢ÿžžžÿ’’’ÿ€€€ÿlllÿgggÿcccÿ```ÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¸¸¸ÿÂÂÂÿÙÙÙÿÙÙÙÿÉÉÉÿ¼¼¼ÿ¶¶¶ÿ¹¹¹ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ···ÿ­­­ÿ£££ÿŸŸŸÿ‹‹‹ÿjjjÿ```ÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿ¼¼¼ÿÏÏÏÿ¾¾¾ÿ²²²ÿ¹¹¹ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ¶¶¶ÿ¦¦¦ÿ   ÿƒƒƒÿ]]]ÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯¯¯ÿµµµÿ¦¦¦ÿ¸¸¸ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ³³³ÿ¢¢¢ÿŒŒŒÿYYYÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ£££ÿÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ´´´ÿÿxxxÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ~~~ÿ”””ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ}}}ÿrrrÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ†††ÿlllÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ»»»ÿXXXÿ”””ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙÙÙÿNNNÿÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿxxxÿ^^^ÿçççÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÐÐÐÿWWWÿqqqÿ±±±ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¥¥¥ÿcccÿlllÿäääÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìììÿ–––ÿNNNÿvvvÿ¢¢¢ÿ½½½ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿºººÿ™™™ÿhhhÿRRRÿ¯¯¯ÿöööÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿéééÿ±±±ÿiiiÿOOOÿyyyÿ–––ÿ«««ÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¸¸¸ÿ§§§ÿ‘‘‘ÿlllÿNNNÿwwwÿÀÀÀÿôôôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿâââÿ¿¿¿ÿ———ÿ[[[ÿNNNÿ\\\ÿtttÿ‹‹‹ÿ‘‘‘ÿ¡¡¡ÿ¡¡¡ÿªªªÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ²²²ÿ¦¦¦ÿ¡¡¡ÿ   ÿÿ†††ÿrrrÿTTTÿNNNÿlllÿ   ÿÆÆÆÿìììÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿîîîÿÛÛÛÿËËËÿ²²²ÿ¤¤¤ÿ‹‹‹ÿˆˆˆÿiiiÿNNNÿNNNÿNNNÿNNNÿNNNÿNNNÿrrrÿ‹‹‹ÿŒŒŒÿ«««ÿµµµÿÎÎÎÿàààÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿsqlitebrowser-sqlitebrowser-5733cb7/installer/windows/build.cmd000066400000000000000000000020501463772530400251440ustar00rootroot00000000000000@echo off :: Output file name set MSI=DB.Browser.for.SQLite-%1 :: Set the ARCH based on the first parameter if "%1"=="" ( echo ERROR: You must select a build type, either "win64" or "win32" goto :eof ) else if "%1"=="win32" ( set ARCH=x86 ) else if "%1"=="win64" ( set ARCH=x64 ) else ( echo ERROR: Unknown build type="%1" goto :eof ) :: Suppress some ICE checks :: - 61 (major upgrade) :: - 03 & 82 (merge module) :: - 38 & 43 & 57 (non-advertised shortcuts) set ICE=-sice:ICE03 -sice:ICE82 -sice:ICE61 -sice:ICE38 -sice:ICE43 -sice:ICE57 :: Suppress 'light.exe' warning :: - 1104 (vcredist merge module installer version) set LIGHT=-sw1104 :: Compile & Link "%WIX%\bin\candle.exe" -nologo -pedantic -arch %ARCH% product.wxs translations.wxs ui.wxs "%WIX%\bin\light.exe" -sval -nologo -pedantic %LIGHT% %ICE% -ext WixUIExtension -ext WixUtilExtension -cultures:en-us -loc strings.wxl product.wixobj translations.wixobj ui.wixobj -out %MSI%.msi :: Cleanup del product.wixobj del translations.wixobj del ui.wixobj del %MSI%.wixpdb sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/license.rtf000066400000000000000000001633771463772530400255430ustar00rootroot00000000000000{\rtf1\ansi\ansicpg1252\cocoartf2761 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Arial-BoldMT;\f1\fswiss\fcharset0 ArialMT;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \paperw11900\paperh16840\margl1440\margr1440\vieww16560\viewh8400\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \f0\b\fs28 \cf0 DB Browser for SQLite is bi-licensed under the Mozilla Public License\ Version 2, as well as the GNU General Public License Version 3 or later.\ \ Modification or redistribution is permitted under the conditions of these licenses.\ \ Check `LICENSE-GPL-3.0` for the full text of the GNU General Public License Version 3.\ Check `LICENSE-MPL-2.0` for the full text of the Mozilla Public License Version 2.\ Check `LICENSE-MIT` for the full text of the MIT License. and that is the license for the `nalgeon/sqlean` library.\ Check `LICENSE-PLUGINS` for other rights regarding included third-party resources. \f1\b0\fs24 \ \ \f0\b\fs26 LICENSE-GPL-3.0 \f1\b0\fs24 \ 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.\ \ \ Copyright (C) \ \ 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:\ \ Copyright (C) \ 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\ .\ \ \f0\b\fs26 LICENSE-MPL-2.0 \f1\b0\fs24 \ Mozilla Public License Version 2.0\ ==================================\ \ 1. Definitions\ --------------\ \ 1.1. "Contributor"\ means each individual or legal entity that creates, contributes to\ the creation of, or owns Covered Software.\ \ 1.2. "Contributor Version"\ means the combination of the Contributions of others (if any) used\ by a Contributor and that particular Contributor's Contribution.\ \ 1.3. "Contribution"\ means Covered Software of a particular Contributor.\ \ 1.4. "Covered Software"\ means Source Code Form to which the initial Contributor has attached\ the notice in Exhibit A, the Executable Form of such Source Code\ Form, and Modifications of such Source Code Form, in each case\ including portions thereof.\ \ 1.5. "Incompatible With Secondary Licenses"\ means\ \ (a) that the initial Contributor has attached the notice described\ in Exhibit B to the Covered Software; or\ \ (b) that the Covered Software was made available under the terms of\ version 1.1 or earlier of the License, but not also under the\ terms of a Secondary License.\ \ 1.6. "Executable Form"\ means any form of the work other than Source Code Form.\ \ 1.7. "Larger Work"\ means a work that combines Covered Software with other material, in\ a separate file or files, that is not Covered Software.\ \ 1.8. "License"\ means this document.\ \ 1.9. "Licensable"\ means having the right to grant, to the maximum extent possible,\ whether at the time of the initial grant or subsequently, any and\ all of the rights conveyed by this License.\ \ 1.10. "Modifications"\ means any of the following:\ \ (a) any file in Source Code Form that results from an addition to,\ deletion from, or modification of the contents of Covered\ Software; or\ \ (b) any new file in Source Code Form that contains any Covered\ Software.\ \ 1.11. "Patent Claims" of a Contributor\ means any patent claim(s), including without limitation, method,\ process, and apparatus claims, in any patent Licensable by such\ Contributor that would be infringed, but for the grant of the\ License, by the making, using, selling, offering for sale, having\ made, import, or transfer of either its Contributions or its\ Contributor Version.\ \ 1.12. "Secondary License"\ means either the GNU General Public License, Version 2.0, the GNU\ Lesser General Public License, Version 2.1, the GNU Affero General\ Public License, Version 3.0, or any later versions of those\ licenses.\ \ 1.13. "Source Code Form"\ means the form of the work preferred for making modifications.\ \ 1.14. "You" (or "Your")\ means an individual or a legal entity exercising rights under this\ License. For legal entities, "You" includes any entity that\ controls, is controlled by, or is under common control with You. For\ purposes of this definition, "control" means (a) the power, direct\ or indirect, to cause the direction or management of such entity,\ whether by contract or otherwise, or (b) ownership of more than\ fifty percent (50%) of the outstanding shares or beneficial\ ownership of such entity.\ \ 2. License Grants and Conditions\ --------------------------------\ \ 2.1. Grants\ \ Each Contributor hereby grants You a world-wide, royalty-free,\ non-exclusive license:\ \ (a) under intellectual property rights (other than patent or trademark)\ Licensable by such Contributor to use, reproduce, make available,\ modify, display, perform, distribute, and otherwise exploit its\ Contributions, either on an unmodified basis, with Modifications, or\ as part of a Larger Work; and\ \ (b) under Patent Claims of such Contributor to make, use, sell, offer\ for sale, have made, import, and otherwise transfer either its\ Contributions or its Contributor Version.\ \ 2.2. Effective Date\ \ The licenses granted in Section 2.1 with respect to any Contribution\ become effective for each Contribution on the date the Contributor first\ distributes such Contribution.\ \ 2.3. Limitations on Grant Scope\ \ The licenses granted in this Section 2 are the only rights granted under\ this License. No additional rights or licenses will be implied from the\ distribution or licensing of Covered Software under this License.\ Notwithstanding Section 2.1(b) above, no patent license is granted by a\ Contributor:\ \ (a) for any code that a Contributor has removed from Covered Software;\ or\ \ (b) for infringements caused by: (i) Your and any other third party's\ modifications of Covered Software, or (ii) the combination of its\ Contributions with other software (except as part of its Contributor\ Version); or\ \ (c) under Patent Claims infringed by Covered Software in the absence of\ its Contributions.\ \ This License does not grant any rights in the trademarks, service marks,\ or logos of any Contributor (except as may be necessary to comply with\ the notice requirements in Section 3.4).\ \ 2.4. Subsequent Licenses\ \ No Contributor makes additional grants as a result of Your choice to\ distribute the Covered Software under a subsequent version of this\ License (see Section 10.2) or under the terms of a Secondary License (if\ permitted under the terms of Section 3.3).\ \ 2.5. Representation\ \ Each Contributor represents that the Contributor believes its\ Contributions are its original creation(s) or it has sufficient rights\ to grant the rights to its Contributions conveyed by this License.\ \ 2.6. Fair Use\ \ This License is not intended to limit any rights You have under\ applicable copyright doctrines of fair use, fair dealing, or other\ equivalents.\ \ 2.7. Conditions\ \ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\ in Section 2.1.\ \ 3. Responsibilities\ -------------------\ \ 3.1. Distribution of Source Form\ \ All distribution of Covered Software in Source Code Form, including any\ Modifications that You create or to which You contribute, must be under\ the terms of this License. You must inform recipients that the Source\ Code Form of the Covered Software is governed by the terms of this\ License, and how they can obtain a copy of this License. You may not\ attempt to alter or restrict the recipients' rights in the Source Code\ Form.\ \ 3.2. Distribution of Executable Form\ \ If You distribute Covered Software in Executable Form then:\ \ (a) such Covered Software must also be made available in Source Code\ Form, as described in Section 3.1, and You must inform recipients of\ the Executable Form how they can obtain a copy of such Source Code\ Form by reasonable means in a timely manner, at a charge no more\ than the cost of distribution to the recipient; and\ \ (b) You may distribute such Executable Form under the terms of this\ License, or sublicense it under different terms, provided that the\ license for the Executable Form does not attempt to limit or alter\ the recipients' rights in the Source Code Form under this License.\ \ 3.3. Distribution of a Larger Work\ \ You may create and distribute a Larger Work under terms of Your choice,\ provided that You also comply with the requirements of this License for\ the Covered Software. If the Larger Work is a combination of Covered\ Software with a work governed by one or more Secondary Licenses, and the\ Covered Software is not Incompatible With Secondary Licenses, this\ License permits You to additionally distribute such Covered Software\ under the terms of such Secondary License(s), so that the recipient of\ the Larger Work may, at their option, further distribute the Covered\ Software under the terms of either this License or such Secondary\ License(s).\ \ 3.4. Notices\ \ You may not remove or alter the substance of any license notices\ (including copyright notices, patent notices, disclaimers of warranty,\ or limitations of liability) contained within the Source Code Form of\ the Covered Software, except that You may alter any license notices to\ the extent required to remedy known factual inaccuracies.\ \ 3.5. Application of Additional Terms\ \ You may choose to offer, and to charge a fee for, warranty, support,\ indemnity or liability obligations to one or more recipients of Covered\ Software. However, You may do so only on Your own behalf, and not on\ behalf of any Contributor. You must make it absolutely clear that any\ such warranty, support, indemnity, or liability obligation is offered by\ You alone, and You hereby agree to indemnify every Contributor for any\ liability incurred by such Contributor as a result of warranty, support,\ indemnity or liability terms You offer. You may include additional\ disclaimers of warranty and limitations of liability specific to any\ jurisdiction.\ \ 4. Inability to Comply Due to Statute or Regulation\ ---------------------------------------------------\ \ If it is impossible for You to comply with any of the terms of this\ License with respect to some or all of the Covered Software due to\ statute, judicial order, or regulation then You must: (a) comply with\ the terms of this License to the maximum extent possible; and (b)\ describe the limitations and the code they affect. Such description must\ be placed in a text file included with all distributions of the Covered\ Software under this License. Except to the extent prohibited by statute\ or regulation, such description must be sufficiently detailed for a\ recipient of ordinary skill to be able to understand it.\ \ 5. Termination\ --------------\ \ 5.1. The rights granted under this License will terminate automatically\ if You fail to comply with any of its terms. However, if You become\ compliant, then the rights granted under this License from a particular\ Contributor are reinstated (a) provisionally, unless and until such\ Contributor explicitly and finally terminates Your grants, and (b) on an\ ongoing basis, if such Contributor fails to notify You of the\ non-compliance by some reasonable means prior to 60 days after You have\ come back into compliance. Moreover, Your grants from a particular\ Contributor are reinstated on an ongoing basis if such Contributor\ notifies You of the non-compliance by some reasonable means, this is the\ first time You have received notice of non-compliance with this License\ from such Contributor, and You become compliant prior to 30 days after\ Your receipt of the notice.\ \ 5.2. If You initiate litigation against any entity by asserting a patent\ infringement claim (excluding declaratory judgment actions,\ counter-claims, and cross-claims) alleging that a Contributor Version\ directly or indirectly infringes any patent, then the rights granted to\ You by any and all Contributors for the Covered Software under Section\ 2.1 of this License shall terminate.\ \ 5.3. In the event of termination under Sections 5.1 or 5.2 above, all\ end user license agreements (excluding distributors and resellers) which\ have been validly granted by You or Your distributors under this License\ prior to termination shall survive termination.\ \ ************************************************************************\ * *\ * 6. Disclaimer of Warranty *\ * ------------------------- *\ * *\ * Covered Software is provided under this License on an "as is" *\ * basis, without warranty of any kind, either expressed, implied, or *\ * statutory, including, without limitation, warranties that the *\ * Covered Software is free of defects, merchantable, fit for a *\ * particular purpose or non-infringing. The entire risk as to the *\ * quality and performance of the Covered Software is with You. *\ * Should any Covered Software prove defective in any respect, You *\ * (not any Contributor) assume the cost of any necessary servicing, *\ * repair, or correction. This disclaimer of warranty constitutes an *\ * essential part of this License. No use of any Covered Software is *\ * authorized under this License except under this disclaimer. *\ * *\ ************************************************************************\ \ ************************************************************************\ * *\ * 7. Limitation of Liability *\ * -------------------------- *\ * *\ * Under no circumstances and under no legal theory, whether tort *\ * (including negligence), contract, or otherwise, shall any *\ * Contributor, or anyone who distributes Covered Software as *\ * permitted above, be liable to You for any direct, indirect, *\ * special, incidental, or consequential damages of any character *\ * including, without limitation, damages for lost profits, loss of *\ * goodwill, work stoppage, computer failure or malfunction, or any *\ * and all other commercial damages or losses, even if such party *\ * shall have been informed of the possibility of such damages. This *\ * limitation of liability shall not apply to liability for death or *\ * personal injury resulting from such party's negligence to the *\ * extent applicable law prohibits such limitation. Some *\ * jurisdictions do not allow the exclusion or limitation of *\ * incidental or consequential damages, so this exclusion and *\ * limitation may not apply to You. *\ * *\ ************************************************************************\ \ 8. Litigation\ -------------\ \ Any litigation relating to this License may be brought only in the\ courts of a jurisdiction where the defendant maintains its principal\ place of business and such litigation shall be governed by laws of that\ jurisdiction, without reference to its conflict-of-law provisions.\ Nothing in this Section shall prevent a party's ability to bring\ cross-claims or counter-claims.\ \ 9. Miscellaneous\ ----------------\ \ This License represents the complete agreement concerning the subject\ matter hereof. If any provision of this License is held to be\ unenforceable, such provision shall be reformed only to the extent\ necessary to make it enforceable. Any law or regulation which provides\ that the language of a contract shall be construed against the drafter\ shall not be used to construe this License against a Contributor.\ \ 10. Versions of the License\ ---------------------------\ \ 10.1. New Versions\ \ Mozilla Foundation is the license steward. Except as provided in Section\ 10.3, no one other than the license steward has the right to modify or\ publish new versions of this License. Each version will be given a\ distinguishing version number.\ \ 10.2. Effect of New Versions\ \ You may distribute the Covered Software under the terms of the version\ of the License under which You originally received the Covered Software,\ or under the terms of any subsequent version published by the license\ steward.\ \ 10.3. Modified Versions\ \ If you create software not governed by this License, and you want to\ create a new license for such software, you may create and use a\ modified version of this License if you rename the license and remove\ any references to the name of the license steward (except to note that\ such modified license differs from this License).\ \ 10.4. Distributing Source Code Form that is Incompatible With Secondary\ Licenses\ \ If You choose to distribute Source Code Form that is Incompatible With\ Secondary Licenses under the terms of this version of the License, the\ notice described in Exhibit B of this License must be attached.\ \ Exhibit A - Source Code Form License Notice\ -------------------------------------------\ \ This Source Code Form is subject to the terms of the Mozilla Public\ License, v. 2.0. If a copy of the MPL was not distributed with this\ file, You can obtain one at http://mozilla.org/MPL/2.0/.\ \ If it is not possible or desirable to put the notice in a particular\ file, then You may include the notice in a location (such as a LICENSE\ file in a relevant directory) where a recipient would be likely to look\ for such a notice.\ \ You may add additional accurate notices of copyright ownership.\ \ Exhibit B - "Incompatible With Secondary Licenses" Notice\ ---------------------------------------------------------\ \ This Source Code Form is "Incompatible With Secondary Licenses", as\ defined by the Mozilla Public License, v. 2.0.\ \ \f0\b\fs26 LICENSE-MIT \f1\b0\fs24 \ MIT License\ \ Copyright (c) 2021+ Anton Zhiyanov \ \ Permission is hereby granted, free of charge, to any person obtaining a copy\ of this software and associated documentation files (the "Software"), to deal\ in the Software without restriction, including without limitation the rights\ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ copies of the Software, and to permit persons to whom the Software is\ furnished to do so, subject to the following conditions:\ \ The above copyright notice and this permission notice shall be included in all\ copies or substantial portions of the Software.\ \ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\ SOFTWARE.\ \ \f0\b\fs26 LICENSE-PLUGINS \f1\b0\fs24 \ DB Browser for SQLite includes support for TIFF and WebP images. The\ support for these comes from the LibTIFF and WebP projects, which have\ their own (Open Source) licenses, different to ours.\ \ LibTIFF - http://www.simplesystems.org/libtiff/\ \ Copyright (c) 1988-1997 Sam Leffler\ Copyright (c) 1991-1997 Silicon Graphics, Inc.\ \ Permission to use, copy, modify, distribute, and sell this software and \ its documentation for any purpose is hereby granted without fee, provided\ that (i) the above copyright notices and this permission notice appear in\ all copies of the software and related documentation, and (ii) the names of\ Sam Leffler and Silicon Graphics may not be used in any advertising or\ publicity relating to the software without the specific, prior written\ permission of Sam Leffler and Silicon Graphics.\ \ THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, \ EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY \ WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. \ \ IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR\ ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,\ OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\ WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF \ LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE \ OF THIS SOFTWARE. \ \ WebP - https://developers.google.com/speed/webp/\ \ Copyright (c) 2010, Google Inc. All rights reserved.\ \ 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 Google 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\ HOLDER 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.\ \ Icons - https://codefisher.org/pastel-svg/\ \ Most of the icons come from the Pastel SVG icon set created by Michael\ Buckley. We have obtained a special license (Creative Commons\ Attribution Share Alike 4.0\ http://creativecommons.org/licenses/by-sa/4.0/) but you might be\ required to redistribute it under Creative Commons Attribution\ NonCommercial Share Alike 4.0\ http://creativecommons.org/licenses/by-nc-sa/4.0/\ Check https://codefisher.org/pastel-svg/ for clarification.\ \ The construction emoji for the icon used in the nightly version come\ from the OpenMoji under CC BY-SA 4.0 license.\ Check https://openmoji.org/library/emoji-1F6A7/ and\ https://openmoji.org/faq/ for clarification.\ \ Some icons might have other open licenses, check history of the files\ under `src/icons`.}sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/product.wxs000066400000000000000000000444601463772530400256160ustar00rootroot00000000000000 SHORTCUT_SQLITE_DESKTOP SHORTCUT_SQLCIPHER_DESKTOP SHORTCUT_SQLITE_PROGRAMMENU SHORTCUT_SQLCIPHER_PROGRAMMENU LicenseAccepted = "1" NOT Installed NSIS_INSTALLDIR NSIS_INSTALLDIR sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/resources/000077500000000000000000000000001463772530400253755ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/resources/background.xcf000066400000000000000000001017211463772530400302200ustar00rootroot00000000000000gimp xcf v011í8–BB 6 gimp-commentgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) µ~žv€ logo.pngÿ!?€ "     %$ÿÿÿÿ#ÿÿÿÿ ¶v€Ú~’v€ 3®\š&NN$NNñP]r}†Œ’˜ £§«®¯¯°ý¯®¬ NõMUl‚’©´¼ÂÄÃÿX Núl…›ª¹Âà NûZ™¯¿"à ÿPNûS{š´Â&ÃÿLNüWƒ§¿*ÃNýx¤¿-ÃNýTŒ¶0Ãÿ.NýR»2ÃNþ{¸4ÃþBNþT 6ÃÿNþ\±7ÃÿSNþW²8ÃOþNŸ9Ãÿ[YþkÂ9Ãÿlgÿ•:Ãÿ}uÿŸ:Ãÿƒÿ™:ÃÿŸ‘þ’¾9Ãþ«Ÿžÿª9Ãþ­©¢ÿ°8Ãý­°¬¢þ®Â6Ãû­°µÄ±¢þ§¼5Ãô­°³ºÏɵ£¢¢°À3Ãò­°³¶¾ÓÐÌ»¨¢£²À1Ãð­°³¶ºÀØÔÐÐij££¯¼/Ãí­°³¶º½ÂÙÝÓÐÐÍ¿®¢§´¾,Ãô­°³¶º½ÀÄ×äßÕÐù˾­¢¨³¼)Ãñ­°³¶º½ÀÄÇÔåèäÚÑÐøÌ¾°£¤­¶¾%Ãî­°³¶º½ÀÄÇÊÑãéëëãÙÑÐöε§¢¤¬²¹¿ Ãë­°³¶º½ÀÄÇÊÍÑÞêìîðïçÝÒÐóȽ°¤¢¢£ª¯µº½ÂÃç­°³¶º½ÀÄÇÊÍÑÔÙæîðñóõöðæÜÒÐûÏǼ±¥¢õ¥©­±µ·¹¼¿ÁÂÃâ­°³¶º½ÀÄÇÊÍÑÔ×Ûîðñóõöøúù÷ðçß×ÑÐûÉ¿¶«£ ¢ù£¥¦¨©ª«¬«Ôª­°³¶º½ÀÄÇÊÍÑÔ×ÚîðñóõöøúùøöõôòðêäÞÙÕÑÐÏÇÀ·¯¦¢Í­°³¶º½ÀÄÇÊÍÑÔ×ÚíðñóõöøúùøöõôòñïîìëéèäàÝÚ×ÕÓÎÇÀ¹´­¦£ ¢€À­°³¶º½ÀÄÇÊÍÑÔ×ÚìðñóõöøúùøöõôòñïîìëéèæåãâáßÞÜÛÙØÖÔÒÏÉü·±«¥¢¡¡ Ÿž­°³¶º½ÀÄÇÊÍÑÔ×ÚëðñóõöøúùøöõôòñïîìëéÝØÕÒÏÌÈÅÁ½¸´°®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÚëðñóõöøúùøöõôòñïîìëéÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÚêðñóõöøúùøöõôòñïîìëéÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Úéðñóõöøúùøöõôòñïîìëé×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Úèðñóôöøúùøöõóòðïíìêè×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Úæïðòôöøùù÷öôóñïîìêéç×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›®°³¶º½ÀÄÇÊÍÑÔ×Úåîïñóõ÷ùù÷õóòðîíëéçæ×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›&±³¶º½ÀÄÇÊÍÑÔ×Úãíïñóõ÷ùø÷õóñïíìêèæä×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›I˜¶º½ÀÄÇÊÍÑÔ×Úâìîðòôöøøöôòðîíëéçåã×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›NN•º½ÀÄÇÊÍÑÔ×Úâëíïñôöøøöôòðîìêèåäá×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›NÈ»ÀÄÇÊÍÑÔ×Úáêìîñóõø÷õóñïíëéæäâà×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›TSÃV¸ÁÄÇÊÍÑÔ×Úàéëîðòõ÷÷õòðîìêèåãáß×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›c`ÿ‡ÃÇÇÊÍÑÔ×Úßèêíïòô÷öôòðîëéçäâàÝÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›voÿÃÈÇÍÑÔ×ÚÞçéìïñô÷öôñïíêèæãáÞÜÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›†|ÿžÃÊÉÑ×ÚÞæèëîñóööóñîìêçåâàÝÛÕÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›—‹ÿ“ÃÌÈÒÜäçëíðóöõóðîëéæäáÞÜÙÕÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¦˜ÿ³ÃÍÄÍØåëïòõõòðíëèåâàÝÚØÔÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¥¢þ£½ ÃÐÌÙçóôñïìêçäáßÜÙÖÓÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­­£¢þ¤¼ ÃÒÄÐÙâçéæãàÝÛØÕÒÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°¶²¢þ£¶ÃÐÇÍÒÖ×Ù×ÔÑÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³ÂÉ´£¢¢«¾ÃÔÅÇÉÉÈÇÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶ÇÒ˹¦¢£±ÀÃíÂÁÀ¾¼º¸¶µ³±¯®­¬ª©©¨§ñ­°³¶ºËÖÐÏÁ¯¢£°¾0Ãî­°³¶º½ÌÜÔÐÐʺ¨¢ª·Á-Ãõ­°³¶º½ÀËáÞÔÐùÆ·§£®¸Á*Ã&NN$NNñP]r}†Œ’˜ £§«®¯¯°ý¯®¬ NõMUl‚’©´¼ÂÄÃÿX Núl…›ª¹Âà NûZ™¯¿"à ÿPNûS{š´Â&ÃÿLNüWƒ§¿*ÃNýx¤¿-ÃNýTŒ¶0Ãÿ.NýR»2ÃNþ{¸4ÃþBNþT 6ÃÿNþ\±7ÃÿSNþW²8ÃOþNŸ9Ãÿ[YþkÂ9Ãÿlgÿ•:Ãÿ}uÿŸ:Ãÿƒÿ™:ÃÿŸ‘þ’¾9Ãþ«Ÿžÿª9Ãþ­©¢ÿ°8Ãý­°¬¢þ®Â6Ãû­°µÄ±¢þ§¼5Ãô­°³ºÏɵ£¢¢°À3Ãò­°³¶¾ÓÐÌ»¨¢£²À1Ãð­°³¶ºÀØÔÐÐij££¯¼/Ãí­°³¶º½ÂÙÝÓÐÐÍ¿®¢§´¾,Ãô­°³¶º½ÀÄ×äßÕÐù˾­¢¨³¼)Ãñ­°³¶º½ÀÄÇÔåèäÚÑÐøÌ¾°£¤­¶¾%Ãî­°³¶º½ÀÄÇÊÑãéëëãÙÑÐöε§¢¤¬²¹¿ Ãë­°³¶º½ÀÄÇÊÍÑÞêìîðïçÝÒÐóȽ°¤¢¢£ª¯µº½ÂÃç­°³¶º½ÀÄÇÊÍÑÔÙæîðñóõöðæÜÒÐûÏǼ±¥¢õ¥©­±µ·¹¼¿ÁÂÃâ­°³¶º½ÀÄÇÊÍÑÔ×Ûîðñóõöøúù÷ðçß×ÑÐûÉ¿¶«£ ¢ù£¥¦¨©ª«¬«Ôª­°³¶º½ÀÄÇÊÍÑÔ×ÚîðñóõöøúùøöõôòðêäÞÙÕÑÐÏÇÀ·¯¦¢Í­°³¶º½ÀÄÇÊÍÑÔ×ÚíðñóõöøúùøöõôòñïîìëéèäàÝÚ×ÕÓÎÇÀ¹´­¦£ ¢€À­°³¶º½ÀÄÇÊÍÑÔ×ÚìðñóõöøúùøöõôòñïîìëéèæåãâáßÞÜÛÙØÖÔÒÏÉü·±«¥¢¡¡ Ÿž­°³¶º½ÀÄÇÊÍÑÔ×ÚëðñóõöøúùøöõôòñïîìëéÝØÕÒÏÌÈÅÁ½¸´°®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÚëðñóõöøúùøöõôòñïîìëéÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÚêðñóõöøúùøöõôòñïîìëéÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Úéðñóõöøúùøöõôòñïîìëé×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Úèðñóôöøúùøöõóòðïíìêè×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Úæïðòôöøùù÷öôóñïîìêéç×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›®°³¶º½ÀÄÇÊÍÑÔ×Úåîïñóõ÷ùù÷õóòðîíëéçæ×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›&±³¶º½ÀÄÇÊÍÑÔ×Úãíïñóõ÷ùø÷õóñïíìêèæä×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›I˜¶º½ÀÄÇÊÍÑÔ×Úâìîðòôöøøöôòðîíëéçåã×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›NN•º½ÀÄÇÊÍÑÔ×Úâëíïñôöøøöôòðîìêèåäá×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›NÈ»ÀÄÇÊÍÑÔ×Úáêìîñóõø÷õóñïíëéæäâà×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›TSÃV¸ÁÄÇÊÍÑÔ×Úàéëîðòõ÷÷õòðîìêèåãáß×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›c`ÿ‡ÃÇÇÊÍÑÔ×Úßèêíïòô÷öôòðîëéçäâàÝÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›voÿÃÈÇÍÑÔ×ÚÞçéìïñô÷öôñïíêèæãáÞÜÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›†|ÿžÃÊÉÑ×ÚÞæèëîñóööóñîìêçåâàÝÛÕÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›—‹ÿ“ÃÌÈÒÜäçëíðóöõóðîëéæäáÞÜÙÕÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¦˜ÿ³ÃÍÄÍØåëïòõõòðíëèåâàÝÚØÔÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¥¢þ£½ ÃÐÌÙçóôñïìêçäáßÜÙÖÓÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­­£¢þ¤¼ ÃÒÄÐÙâçéæãàÝÛØÕÒÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°¶²¢þ£¶ÃÐÇÍÒÖ×Ù×ÔÑÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³ÂÉ´£¢¢«¾ÃÔÅÇÉÉÈÇÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶ÇÒ˹¦¢£±ÀÃíÂÁÀ¾¼º¸¶µ³±¯®­¬ª©©¨§ñ­°³¶ºËÖÐÏÁ¯¢£°¾0Ãî­°³¶º½ÌÜÔÐÐʺ¨¢ª·Á-Ãõ­°³¶º½ÀËáÞÔÐùÆ·§£®¸Á*Ã&NN$NNñP]r}†Œ’˜ £§«®¯¯°ý¯®¬ NõMUl‚’©´¼ÂÄÃÿX Núl…›ª¹Âà NûZ™¯¿"à ÿPNûS{š´Â&ÃÿLNüWƒ§¿*ÃNýx¤¿-ÃNýTŒ¶0Ãÿ.NýR»2ÃNþ{¸4ÃþBNþT 6ÃÿNþ\±7ÃÿSNþW²8ÃOþNŸ9Ãÿ[YþkÂ9Ãÿlgÿ•:Ãÿ}uÿŸ:Ãÿƒÿ™:ÃÿŸ‘þ’¾9Ãþ«Ÿžÿª9Ãþ­©¢ÿ°8Ãý­°¬¢þ®Â6Ãû­°µÄ±¢þ§¼5Ãô­°³ºÏɵ£¢¢°À3Ãò­°³¶¾ÓÐÌ»¨¢£²À1Ãð­°³¶ºÀØÔÐÐij££¯¼/Ãí­°³¶º½ÂÙÝÓÐÐÍ¿®¢§´¾,Ãô­°³¶º½ÀÄ×äßÕÐù˾­¢¨³¼)Ãñ­°³¶º½ÀÄÇÔåèäÚÑÐøÌ¾°£¤­¶¾%Ãî­°³¶º½ÀÄÇÊÑãéëëãÙÑÐöε§¢¤¬²¹¿ Ãë­°³¶º½ÀÄÇÊÍÑÞêìîðïçÝÒÐóȽ°¤¢¢£ª¯µº½ÂÃç­°³¶º½ÀÄÇÊÍÑÔÙæîðñóõöðæÜÒÐûÏǼ±¥¢õ¥©­±µ·¹¼¿ÁÂÃâ­°³¶º½ÀÄÇÊÍÑÔ×Ûîðñóõöøúù÷ðçß×ÑÐûÉ¿¶«£ ¢ù£¥¦¨©ª«¬«Ôª­°³¶º½ÀÄÇÊÍÑÔ×ÚîðñóõöøúùøöõôòðêäÞÙÕÑÐÏÇÀ·¯¦¢Í­°³¶º½ÀÄÇÊÍÑÔ×ÚíðñóõöøúùøöõôòñïîìëéèäàÝÚ×ÕÓÎÇÀ¹´­¦£ ¢€À­°³¶º½ÀÄÇÊÍÑÔ×ÚìðñóõöøúùøöõôòñïîìëéèæåãâáßÞÜÛÙØÖÔÒÏÉü·±«¥¢¡¡ Ÿž­°³¶º½ÀÄÇÊÍÑÔ×ÚëðñóõöøúùøöõôòñïîìëéÝØÕÒÏÌÈÅÁ½¸´°®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÚëðñóõöøúùøöõôòñïîìëéÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÚêðñóõöøúùøöõôòñïîìëéÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Úéðñóõöøúùøöõôòñïîìëé×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Úèðñóôöøúùøöõóòðïíìêè×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Úæïðòôöøùù÷öôóñïîìêéç×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›®°³¶º½ÀÄÇÊÍÑÔ×Úåîïñóõ÷ùù÷õóòðîíëéçæ×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›&±³¶º½ÀÄÇÊÍÑÔ×Úãíïñóõ÷ùø÷õóñïíìêèæä×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›I˜¶º½ÀÄÇÊÍÑÔ×Úâìîðòôöøøöôòðîíëéçåã×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›NN•º½ÀÄÇÊÍÑÔ×Úâëíïñôöøøöôòðîìêèåäá×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›NÈ»ÀÄÇÊÍÑÔ×Úáêìîñóõø÷õóñïíëéæäâà×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›TSÃV¸ÁÄÇÊÍÑÔ×Úàéëîðòõ÷÷õòðîìêèåãáß×ÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›c`ÿ‡ÃÇÇÊÍÑÔ×Úßèêíïòô÷öôòðîëéçäâàÝÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›voÿÃÈÇÍÑÔ×ÚÞçéìïñô÷öôñïíêèæãáÞÜÖÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›†|ÿžÃÊÉÑ×ÚÞæèëîñóööóñîìêçåâàÝÛÕÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›—‹ÿ“ÃÌÈÒÜäçëíðóöõóðîëéæäáÞÜÙÕÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¦˜ÿ³ÃÍÄÍØåëïòõõòðíëèåâàÝÚØÔÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¥¢þ£½ ÃÐÌÙçóôñïìêçäáßÜÙÖÓÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­­£¢þ¤¼ ÃÒÄÐÙâçéæãàÝÛØÕÒÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°¶²¢þ£¶ÃÐÇÍÒÖ×Ù×ÔÑÎËÈÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³ÂÉ´£¢¢«¾ÃÔÅÇÉÉÈÇÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶ÇÒ˹¦¢£±ÀÃíÂÁÀ¾¼º¸¶µ³±¯®­¬ª©©¨§ñ­°³¶ºËÖÐÏÁ¯¢£°¾0Ãî­°³¶º½ÌÜÔÐÐʺ¨¢ª·Á-Ãõ­°³¶º½ÀËáÞÔÐùÆ·§£®¸Á*Ã&ç -G[l—ª¹ÅÎÕßéïöúüÿýûøòëø(Uw•¹ÚóÿúK‚ªÚýÿû:t²æ$ÿü's·ô(ÿý8ŒÜ,ÿ ý"‚ß/ÿ üJ¹ý1ÿýXÔ4ÿþ@Ï6ÿþ£8ÿþ:ã9ÿþXù:ÿþUü;ÿý/÷<ÿþÌ=ÿÿN>ÿÿª>ÿÿÝ>ÿÿú>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿý>ÿÿñ>ÿÿÈ>ÿÿw>ÿþî=ÿþ]=ÿýâ<ÿþ†=ÿþú=ÿÿƒ>ÿÿË>ÿÿòÿÿ NþOJ&N Nô¨¤¢›”ŽˆvhTONÿC Ãø¾¸®¢—‰t^NÃú¾¯¢vW Nÿ.Ãüµ£‹k NÿM Ãü¼¥Š` Nÿ; Ãý±”hN#Ãý±ŒXN%Ãý¿žgN'Ãý£eN)ÃýÀ˜SNÿQ+ÃþµmNüOX,Ãþ¿|NýRY-ÃþÁxNþU.Ãþ»[OþRY/Ãÿ˜Y/Ãÿ²gÿ]/Ãÿ¸uÿa/Ãÿ±ƒÿ_/Ãÿ ‘þ‹Y.Ãÿ·žþ~Y-Ãþ»£¢ýš]Y,Ãþ¸£¢üŸlZY*ÃþÁ¯¢û s[ZY)Ãþ·¥¢úq\[ZY'Ãþ¸§¢ù”g^\[ZY$ÃýÀ´¦¢÷ž~`_^\[ZY!ÃýÁ¸¬¢õ ‰ga`_^\[ZYÃüÀ·­£¢óŸ‰kdba`_^\[ZYÃüÀ¹±¨¢ñ˜‚kfedba`_^\[ZYÃûÁ¼µ¯§¢îœ‹vjigfedba`_^\[ZYÃú¿»·±¬¦ ¢ë™‹znlkjigfedba`_^\[ZYÃÂöÀ¾»¸¶³¯«§£ ¢â›‘„wqponlkjigfedba`_^\[ZY¨§¥¤£¢âž˜†zvutrqponlkjigfedba`_^\[ZY¢ÜŸš–‰|{zyxvutrqponlkjigfedba`_^\[ZY¢€桞œš—”‹†„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYžœ›š˜—”’‘ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[Zš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\Yš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_]TPXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`]SNNSYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedbaŒzSÍTYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfed|°Ã©`ÒZš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigf«Ãþ·noÔ`š™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjl²Ãÿµ|Öbš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponl„¤½Ãÿ©‹Ø‰Zš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqr‹£»ÃþÀ›˜Û‡Xš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvv„›®À Ãþª¢Þ¡kXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{€‘¡°¿ ÃþÁ«¢ã„ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ„›¥±»Ãþ½¨¢è\ZXš™˜–•”“’Œ”𢍮¶½Ãý³£¢ïŽ^[ZX§¨©«­¯±³¶¹½ÂÃý·¦¢ù¡ƒ^\[ZX%ÃýÁµ¦¢ø™r_^\[ZX#Ãý¼¯£¢öŸƒc`_^\[ZX Ãý¼²¦¢ôŸˆiba`_^\[ZX NþOJ&N Nô¨¤¢›”ŽˆvhTONÿC Ãø¾¸®¢—‰t^NÃú¾¯¢vW Nÿ.Ãüµ£‹k NÿM Ãü¼¥Š` Nÿ; Ãý±”hN#Ãý±ŒXN%Ãý¿žgN'Ãý£eN)ÃýÀ˜SNÿQ+ÃþµmNüOX,Ãþ¿|NýRY-ÃþÁxNþU.Ãþ»[OþRY/Ãÿ˜Y/Ãÿ²gÿ]/Ãÿ¸uÿa/Ãÿ±ƒÿ_/Ãÿ ‘þ‹Y.Ãÿ·žþ~Y-Ãþ»£¢ýš]Y,Ãþ¸£¢üŸlZY*ÃþÁ¯¢û s[ZY)Ãþ·¥¢úq\[ZY'Ãþ¸§¢ù”g^\[ZY$ÃýÀ´¦¢÷ž~`_^\[ZY!ÃýÁ¸¬¢õ ‰ga`_^\[ZYÃüÀ·­£¢óŸ‰kdba`_^\[ZYÃüÀ¹±¨¢ñ˜‚kfedba`_^\[ZYÃûÁ¼µ¯§¢îœ‹vjigfedba`_^\[ZYÃú¿»·±¬¦ ¢ë™‹znlkjigfedba`_^\[ZYÃÂöÀ¾»¸¶³¯«§£ ¢â›‘„wqponlkjigfedba`_^\[ZY¨§¥¤£¢âž˜†zvutrqponlkjigfedba`_^\[ZY¢ÜŸš–‰|{zyxvutrqponlkjigfedba`_^\[ZY¢€桞œš—”‹†„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYžœ›š˜—”’‘ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[Zš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\Yš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_]TPXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`]SNNSYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedbaŒzSÍTYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfed|°Ã©`ÒZš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigf«Ãþ·noÔ`š™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjl²Ãÿµ|Öbš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponl„¤½Ãÿ©‹Ø‰Zš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqr‹£»ÃþÀ›˜Û‡Xš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvv„›®À Ãþª¢Þ¡kXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{€‘¡°¿ ÃþÁ«¢ã„ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ„›¥±»Ãþ½¨¢è\ZXš™˜–•”“’Œ”𢍮¶½Ãý³£¢ïŽ^[ZX§¨©«­¯±³¶¹½ÂÃý·¦¢ù¡ƒ^\[ZX%ÃýÁµ¦¢ø™r_^\[ZX#Ãý¼¯£¢öŸƒc`_^\[ZX Ãý¼²¦¢ôŸˆiba`_^\[ZX NþOJ&N Nô¨¤¢›”ŽˆvhTONÿC Ãø¾¸®¢—‰t^NÃú¾¯¢vW Nÿ.Ãüµ£‹k NÿM Ãü¼¥Š` Nÿ; Ãý±”hN#Ãý±ŒXN%Ãý¿žgN'Ãý£eN)ÃýÀ˜SNÿQ+ÃþµmNüOX,Ãþ¿|NýRY-ÃþÁxNþU.Ãþ»[OþRY/Ãÿ˜Y/Ãÿ²gÿ]/Ãÿ¸uÿa/Ãÿ±ƒÿ_/Ãÿ ‘þ‹Y.Ãÿ·žþ~Y-Ãþ»£¢ýš]Y,Ãþ¸£¢üŸlZY*ÃþÁ¯¢û s[ZY)Ãþ·¥¢úq\[ZY'Ãþ¸§¢ù”g^\[ZY$ÃýÀ´¦¢÷ž~`_^\[ZY!ÃýÁ¸¬¢õ ‰ga`_^\[ZYÃüÀ·­£¢óŸ‰kdba`_^\[ZYÃüÀ¹±¨¢ñ˜‚kfedba`_^\[ZYÃûÁ¼µ¯§¢îœ‹vjigfedba`_^\[ZYÃú¿»·±¬¦ ¢ë™‹znlkjigfedba`_^\[ZYÃÂöÀ¾»¸¶³¯«§£ ¢â›‘„wqponlkjigfedba`_^\[ZY¨§¥¤£¢âž˜†zvutrqponlkjigfedba`_^\[ZY¢ÜŸš–‰|{zyxvutrqponlkjigfedba`_^\[ZY¢€桞œš—”‹†„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYžœ›š˜—”’‘ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[Zš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\Yš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_]TPXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`]SNNSYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedbaŒzSÍTYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfed|°Ã©`ÒZš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigf«Ãþ·noÔ`š™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjl²Ãÿµ|Öbš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponl„¤½Ãÿ©‹Ø‰Zš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqr‹£»ÃþÀ›˜Û‡Xš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvv„›®À Ãþª¢Þ¡kXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{€‘¡°¿ ÃþÁ«¢ã„ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ„›¥±»Ãþ½¨¢è\ZXš™˜–•”“’Œ”𢍮¶½Ãý³£¢ïŽ^[ZX§¨©«­¯±³¶¹½ÂÃý·¦¢ù¡ƒ^\[ZX%ÃýÁµ¦¢ø™r_^\[ZX#Ãý¼¯£¢öŸƒc`_^\[ZX Ãý¼²¦¢ôŸˆiba`_^\[ZXòäÙÑɾ°ž‰tbP9' ÿøúæÉ¤ƒc9 ÿúí¼”a2ÿûøÄ‹QÿûþÓ‹F!ÿüô«X $ÿüõ¨G 'ÿýßv )ÿýóˆ+ÿýòz-ÿþÙ=.ÿýý0ÿþ¬1ÿü¾ 2ÿý¸3ÿþ‚3ÿþù 4ÿÿ†4ÿÿÊ4ÿÿä4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿè4ÿÿÜ4ÿÿµ4ÿÿ_3ÿþÝ2ÿýý?2ÿý–2ÿý÷23ÿþÓ4ÿÿW4ÿÿ°4ÿÿÙ4ÿÿæ4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿçó­°³¶º½ÀÄÊßæáØÐùÆ·¨¢«´½'Ãð­°³¶º½ÀÄÇËÜçéèßÕÐ÷Ⱥ¬¢¤¬´»Á"Ãí­°³¶º½ÀÄÇÊÍ×çëíîêáÖÐõÌÀ³¦¢¢§®³º¾Ãé­°³¶º½ÀÄÇÊÍÑÕâìîðñóðçÝÒÐüȽ²¥¢ø£¨¬±¶¹¼ÀÃå­°³¶º½ÀÄÇÊÍÑÔ×ÞîðñóõöøùòçÞÕÐüɾ´©¢ï£¥¨ª®°²´µ¶·¹ºº»»¼»Öº¹­°³¶º½ÀÄÇÊÍÑÔ×ÛîðñóõöøúùøöõñéâÛÖÑÐÐÍﲩ¢Ò­°³¶º½ÀÄÇÊÍÑÔ×ÚîðñóõöøúùøöõôòñïîìçâÞÚ×ÔÑÎÇÀ·±©¢Æ­°³¶º½ÀÄÇÊÍÑÔ×ÛíðñóõöøúùøöõôòñïîìëéèæåãâàÝÛØÖÕÓÎÈÁ¼¸´®ª§¥£¢€¡­°³¶º½ÀÄÇÊÍÑÔ×ÛìðñóõöøúùøöõôòñïîìëéåãáÞÜÚØÔÑÎÊÇÄÁ¿½»·´±­©¤¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÛëðñóõöøúùøöõôòñïîìëéÕÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÛêðñóõöøúùøöõôòñïîìëéÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÛêðñóõöøúùøöõôòñïîìëéÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Ûèðñóõöøúùøöõôòñïîìêé×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Ûçïñòôöøùùøöôóñðîìëéè×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›®°³¶º½ÀÄÇÊÍÑÔ×Ûåîðòóõ÷ùù÷õôòðïíëêèæ×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›£°³¶º½ÀÄÇÊÍÑÔ×Ûäíïñóõ÷ùø÷õóñðîìêèçå×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›±³¶º½ÀÄÇÊÍÑÔ×Ûãìîðòôöøøöôòñïíëéçåã×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›Nj°º½ÀÄÇÊÍÑÔ×Ûâëíïòôöøøöôòðîìêèæäâ×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›NNd®½ÀÄÇÊÍÑÔ×Ûáêìïñóöø÷õóñïíëéçåãá×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ONÃW¬ÀÄÇÊÍÑÔ×Ûàéìîðóõø÷õóñïìêèæäáß×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›XVÃ[¼ÂÄÇÊÍÑÔ×Ûàèëíðòõ÷÷ôòðîìéçåâàÞ×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›hdÿ†ÃÇÅÊÍÑÔ×Ûßçêìïòô÷öôòïíëèæäáßÝÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›xrÿ™ÃÉÈÏÔ×ÛÞæéìîñô÷öôñïìêèåãàÞÛÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›‰€ÿ•ÃËÉÒÚÞåèëîðóööóðîìéçäâßÜÚÕÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›œŽþ¾ÃÍÆÏÛåéìðóöõóðíëèæãàÞÛØÔÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ªœÿ« ÃÏÇÒßìòõõòïíêèåâßÝÚ×ÓÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¨¢ÿ´ ÃÑÄÎÛçîîëéæãáÞÛØÖÒÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯§¢ÿ²ÃÔÊÒÙÝáàÝÚ×ÔÑÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯¶¾©¢þ«ÀÃýÆÊÍÏØÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯³»Ï¬¢¢¤µÂÃÄÛÃÁ¿½º·³°®¬«ª©¨§¥¤£¢ Ÿž›¬¯³¶ÀÓÐÆ³£¢§·#ÃøÂÁÀ¾¾½¼¼»ï¼¬¯³¶ºÃØÒÐͼª¢¦´Á/Ãí¬¯³¶º½ÄÜÚÑÐÐÇ·¦£®ºÂ,Ã꬯³¶º½ÀÅÛãÛÒÐÐÏĵ¥¤¯¹Á)Ãò¬¯³¶º½ÀÃÇ׿æßÕÐ÷Ïͦ£ª´¼Â%Ãאָ³¶º½ÀÃÇÊÔåéëçÞÓÐ÷Ǻ¬¢£«²¹¿!Ã쬯³¶º½ÀÃÇÊÍÒáëìîïêàÖÐôÌÁ´§¢¢¤«°¶»¿Ã謯³¶º½ÀÃÇÊÍÐÔÜéîðñóõñèßÔÐüɾ´§¢ö£¨¬°µ·º¾ÁÂÃ㬯³¶º½ÀÃÇÊÍÐÔ×Úîðñóõöøúùòèà×ÑÐûËÀ·¬£¢ô£¤¦©«­¯°±±²²³²Õ±¬¯³¶º½ÀÃÇÊÍÐÔ×Úíðñóõöøúùø÷õôòêåÞØÔÐÐÏÇ¿¶®¤¢Ï¬¯³¶º½ÀÃÇÊÍÐÔ×Úìðñóõöøúùø÷õôòñïîìëéäàÜÙ×ÔÒËŽ¶±¨£¢€À¬¯³¶º½ÀÃÇÊÍÐÔ×Úëðñóõöøúùø÷õôòñïîìëéèçåäâáßÞÜÙ×ÕÔÓÏÊÅÀ¼¶°ª¥¢¢¡¡  ¬¯³¶º½ÀÃÇÊÍÐÔ×Úêðñóõöøúùø÷õôòñïîìëéâÞÛØÕÒÏËÈÅÁ½º¸µ²®ª¨§¥¤£¢ Ÿž›¬¯³¶º½ÀÃÇÊÍÐÔ×Úéðñóõöøúùø÷õôòñïîìëé×ÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯³¶º½ÀÃÇÊÍÐÔ×Úèðñóõöøúùø÷õôòñïîìëéØÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¯³¶º½ÀÃÇÊÍÐÔ×Úçðñóõöøúùø÷õôòñïîìëéØÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¯³¶º½ÀÃÇÊÍÐÔ×Úæïñóôöøúùø÷õôòñïíìêéÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¯³¶º½ÀÃÇÊÍÐÔ×Úåïðòôö÷ùùøöôóñðîìëéçÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›®°³¶º½ÀÃÇÊÍÐÔ×Úãîðñóõ÷ùù÷öôòðïíëéèæÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›Q°³¶º½ÀÃÇÊÍÐÔ×Úãíïñóõ÷ùø÷õóñðîìêèæäÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›³³¶º½ÀÃÇÊÍÐÔ×ÚâìîðòôöøøöôóñïíëéçåãÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›´¶º½ÀÃÇÊÍÐÔ×ÚáëíïñóöøøöôòðîìêèæäâÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›øº½ÀÃÇÊÍÐÔ×ÚàêìîñóõøøöóòïíëéçåãáÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ŽÀÃÇÊÍÐÔ×Úßéëîðòõ÷÷õóñïìêèæãáߨÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÆÁÄÇÊÍÐÔ×ÚÞèêíïòô÷÷õòðîìéçåâàÞ×ÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÈÇÊÍÐÔ×ÚÞçéìïñôööôòðíëèæäáßÜ×ÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž› ÊÎÑÔ×ÚÝæéëîñóööôñïìêçåãàÞÛÖÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž› ÌÕ×ÚÝäèëíðóööôñîìéçäáßÜÚÕÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÏÞáäèëïòõõóðîëèæãàÞÛØÔÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÒèëîñôõòïíêèåâßÜÚ×ÓÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÕñõôòïìéæãàÞÛØÕÒÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÚëéæãàÝÚ×ÔÑÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ßÛÚ×ÔÑÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›#äÈÄÂÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ó­°³¶º½ÀÄÊßæáØÐùÆ·¨¢«´½'Ãð­°³¶º½ÀÄÇËÜçéèßÕÐ÷Ⱥ¬¢¤¬´»Á"Ãí­°³¶º½ÀÄÇÊÍ×çëíîêáÖÐõÌÀ³¦¢¢§®³º¾Ãé­°³¶º½ÀÄÇÊÍÑÕâìîðñóðçÝÒÐüȽ²¥¢ø£¨¬±¶¹¼ÀÃå­°³¶º½ÀÄÇÊÍÑÔ×ÞîðñóõöøùòçÞÕÐüɾ´©¢ï£¥¨ª®°²´µ¶·¹ºº»»¼»Öº¹­°³¶º½ÀÄÇÊÍÑÔ×ÛîðñóõöøúùøöõñéâÛÖÑÐÐÍﲩ¢Ò­°³¶º½ÀÄÇÊÍÑÔ×ÚîðñóõöøúùøöõôòñïîìçâÞÚ×ÔÑÎÇÀ·±©¢Æ­°³¶º½ÀÄÇÊÍÑÔ×ÛíðñóõöøúùøöõôòñïîìëéèæåãâàÝÛØÖÕÓÎÈÁ¼¸´®ª§¥£¢€¡­°³¶º½ÀÄÇÊÍÑÔ×ÛìðñóõöøúùøöõôòñïîìëéåãáÞÜÚØÔÑÎÊÇÄÁ¿½»·´±­©¤¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÛëðñóõöøúùøöõôòñïîìëéÕÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÛêðñóõöøúùøöõôòñïîìëéÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÛêðñóõöøúùøöõôòñïîìëéÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Ûèðñóõöøúùøöõôòñïîìêé×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Ûçïñòôöøùùøöôóñðîìëéè×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›®°³¶º½ÀÄÇÊÍÑÔ×Ûåîðòóõ÷ùù÷õôòðïíëêèæ×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›£°³¶º½ÀÄÇÊÍÑÔ×Ûäíïñóõ÷ùø÷õóñðîìêèçå×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›±³¶º½ÀÄÇÊÍÑÔ×Ûãìîðòôöøøöôòñïíëéçåã×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›Nj°º½ÀÄÇÊÍÑÔ×Ûâëíïòôöøøöôòðîìêèæäâ×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›NNd®½ÀÄÇÊÍÑÔ×Ûáêìïñóöø÷õóñïíëéçåãá×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ONÃW¬ÀÄÇÊÍÑÔ×Ûàéìîðóõø÷õóñïìêèæäáß×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›XVÃ[¼ÂÄÇÊÍÑÔ×Ûàèëíðòõ÷÷ôòðîìéçåâàÞ×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›hdÿ†ÃÇÅÊÍÑÔ×Ûßçêìïòô÷öôòïíëèæäáßÝÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›xrÿ™ÃÉÈÏÔ×ÛÞæéìîñô÷öôñïìêèåãàÞÛÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›‰€ÿ•ÃËÉÒÚÞåèëîðóööóðîìéçäâßÜÚÕÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›œŽþ¾ÃÍÆÏÛåéìðóöõóðíëèæãàÞÛØÔÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ªœÿ« ÃÏÇÒßìòõõòïíêèåâßÝÚ×ÓÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¨¢ÿ´ ÃÑÄÎÛçîîëéæãáÞÛØÖÒÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯§¢ÿ²ÃÔÊÒÙÝáàÝÚ×ÔÑÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯¶¾©¢þ«ÀÃýÆÊÍÏØÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯³»Ï¬¢¢¤µÂÃÄÛÃÁ¿½º·³°®¬«ª©¨§¥¤£¢ Ÿž›¬¯³¶ÀÓÐÆ³£¢§·#ÃøÂÁÀ¾¾½¼¼»ï¼¬¯³¶ºÃØÒÐͼª¢¦´Á/Ãí¬¯³¶º½ÄÜÚÑÐÐÇ·¦£®ºÂ,Ã꬯³¶º½ÀÅÛãÛÒÐÐÏĵ¥¤¯¹Á)Ãò¬¯³¶º½ÀÃÇ׿æßÕÐ÷Ïͦ£ª´¼Â%Ãאָ³¶º½ÀÃÇÊÔåéëçÞÓÐ÷Ǻ¬¢£«²¹¿!Ã쬯³¶º½ÀÃÇÊÍÒáëìîïêàÖÐôÌÁ´§¢¢¤«°¶»¿Ã謯³¶º½ÀÃÇÊÍÐÔÜéîðñóõñèßÔÐüɾ´§¢ö£¨¬°µ·º¾ÁÂÃ㬯³¶º½ÀÃÇÊÍÐÔ×Úîðñóõöøúùòèà×ÑÐûËÀ·¬£¢ô£¤¦©«­¯°±±²²³²Õ±¬¯³¶º½ÀÃÇÊÍÐÔ×Úíðñóõöøúùø÷õôòêåÞØÔÐÐÏÇ¿¶®¤¢Ï¬¯³¶º½ÀÃÇÊÍÐÔ×Úìðñóõöøúùø÷õôòñïîìëéäàÜÙ×ÔÒËŽ¶±¨£¢€À¬¯³¶º½ÀÃÇÊÍÐÔ×Úëðñóõöøúùø÷õôòñïîìëéèçåäâáßÞÜÙ×ÕÔÓÏÊÅÀ¼¶°ª¥¢¢¡¡  ¬¯³¶º½ÀÃÇÊÍÐÔ×Úêðñóõöøúùø÷õôòñïîìëéâÞÛØÕÒÏËÈÅÁ½º¸µ²®ª¨§¥¤£¢ Ÿž›¬¯³¶º½ÀÃÇÊÍÐÔ×Úéðñóõöøúùø÷õôòñïîìëé×ÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯³¶º½ÀÃÇÊÍÐÔ×Úèðñóõöøúùø÷õôòñïîìëéØÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¯³¶º½ÀÃÇÊÍÐÔ×Úçðñóõöøúùø÷õôòñïîìëéØÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¯³¶º½ÀÃÇÊÍÐÔ×Úæïñóôöøúùø÷õôòñïíìêéÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¯³¶º½ÀÃÇÊÍÐÔ×Úåïðòôö÷ùùøöôóñðîìëéçÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›®°³¶º½ÀÃÇÊÍÐÔ×Úãîðñóõ÷ùù÷öôòðïíëéèæÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›Q°³¶º½ÀÃÇÊÍÐÔ×Úãíïñóõ÷ùø÷õóñðîìêèæäÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›³³¶º½ÀÃÇÊÍÐÔ×ÚâìîðòôöøøöôóñïíëéçåãÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›´¶º½ÀÃÇÊÍÐÔ×ÚáëíïñóöøøöôòðîìêèæäâÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›øº½ÀÃÇÊÍÐÔ×ÚàêìîñóõøøöóòïíëéçåãáÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ŽÀÃÇÊÍÐÔ×Úßéëîðòõ÷÷õóñïìêèæãáߨÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÆÁÄÇÊÍÐÔ×ÚÞèêíïòô÷÷õòðîìéçåâàÞ×ÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÈÇÊÍÐÔ×ÚÞçéìïñôööôòðíëèæäáßÜ×ÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž› ÊÎÑÔ×ÚÝæéëîñóööôñïìêçåãàÞÛÖÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž› ÌÕ×ÚÝäèëíðóööôñîìéçäáßÜÚÕÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÏÞáäèëïòõõóðîëèæãàÞÛØÔÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÒèëîñôõòïíêèåâßÜÚ×ÓÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÕñõôòïìéæãàÞÛØÕÒÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÚëéæãàÝÚ×ÔÑÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ßÛÚ×ÔÑÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›#äÈÄÂÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ó­°³¶º½ÀÄÊßæáØÐùÆ·¨¢«´½'Ãð­°³¶º½ÀÄÇËÜçéèßÕÐ÷Ⱥ¬¢¤¬´»Á"Ãí­°³¶º½ÀÄÇÊÍ×çëíîêáÖÐõÌÀ³¦¢¢§®³º¾Ãé­°³¶º½ÀÄÇÊÍÑÕâìîðñóðçÝÒÐüȽ²¥¢ø£¨¬±¶¹¼ÀÃå­°³¶º½ÀÄÇÊÍÑÔ×ÞîðñóõöøùòçÞÕÐüɾ´©¢ï£¥¨ª®°²´µ¶·¹ºº»»¼»Öº¹­°³¶º½ÀÄÇÊÍÑÔ×ÛîðñóõöøúùøöõñéâÛÖÑÐÐÍﲩ¢Ò­°³¶º½ÀÄÇÊÍÑÔ×ÚîðñóõöøúùøöõôòñïîìçâÞÚ×ÔÑÎÇÀ·±©¢Æ­°³¶º½ÀÄÇÊÍÑÔ×ÛíðñóõöøúùøöõôòñïîìëéèæåãâàÝÛØÖÕÓÎÈÁ¼¸´®ª§¥£¢€¡­°³¶º½ÀÄÇÊÍÑÔ×ÛìðñóõöøúùøöõôòñïîìëéåãáÞÜÚØÔÑÎÊÇÄÁ¿½»·´±­©¤¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÛëðñóõöøúùøöõôòñïîìëéÕÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÛêðñóõöøúùøöõôòñïîìëéÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×ÛêðñóõöøúùøöõôòñïîìëéÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Ûèðñóõöøúùøöõôòñïîìêé×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­°³¶º½ÀÄÇÊÍÑÔ×Ûçïñòôöøùùøöôóñðîìëéè×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›®°³¶º½ÀÄÇÊÍÑÔ×Ûåîðòóõ÷ùù÷õôòðïíëêèæ×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›£°³¶º½ÀÄÇÊÍÑÔ×Ûäíïñóõ÷ùø÷õóñðîìêèçå×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›±³¶º½ÀÄÇÊÍÑÔ×Ûãìîðòôöøøöôòñïíëéçåã×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›Nj°º½ÀÄÇÊÍÑÔ×Ûâëíïòôöøøöôòðîìêèæäâ×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›NNd®½ÀÄÇÊÍÑÔ×Ûáêìïñóöø÷õóñïíëéçåãá×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ONÃW¬ÀÄÇÊÍÑÔ×Ûàéìîðóõø÷õóñïìêèæäáß×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›XVÃ[¼ÂÄÇÊÍÑÔ×Ûàèëíðòõ÷÷ôòðîìéçåâàÞ×ÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›hdÿ†ÃÇÅÊÍÑÔ×Ûßçêìïòô÷öôòïíëèæäáßÝÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›xrÿ™ÃÉÈÏÔ×ÛÞæéìîñô÷öôñïìêèåãàÞÛÖÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›‰€ÿ•ÃËÉÒÚÞåèëîðóööóðîìéçäâßÜÚÕÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›œŽþ¾ÃÍÆÏÛåéìðóöõóðíëèæãàÞÛØÔÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ªœÿ« ÃÏÇÒßìòõõòïíêèåâßÝÚ×ÓÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¨¢ÿ´ ÃÑÄÎÛçîîëéæãáÞÛØÖÒÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯§¢ÿ²ÃÔÊÒÙÝáàÝÚ×ÔÑÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯¶¾©¢þ«ÀÃýÆÊÍÏØÎËÈÅÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯³»Ï¬¢¢¤µÂÃÄÛÃÁ¿½º·³°®¬«ª©¨§¥¤£¢ Ÿž›¬¯³¶ÀÓÐÆ³£¢§·#ÃøÂÁÀ¾¾½¼¼»ï¼¬¯³¶ºÃØÒÐͼª¢¦´Á/Ãí¬¯³¶º½ÄÜÚÑÐÐÇ·¦£®ºÂ,Ã꬯³¶º½ÀÅÛãÛÒÐÐÏĵ¥¤¯¹Á)Ãò¬¯³¶º½ÀÃÇ׿æßÕÐ÷Ïͦ£ª´¼Â%Ãאָ³¶º½ÀÃÇÊÔåéëçÞÓÐ÷Ǻ¬¢£«²¹¿!Ã쬯³¶º½ÀÃÇÊÍÒáëìîïêàÖÐôÌÁ´§¢¢¤«°¶»¿Ã謯³¶º½ÀÃÇÊÍÐÔÜéîðñóõñèßÔÐüɾ´§¢ö£¨¬°µ·º¾ÁÂÃ㬯³¶º½ÀÃÇÊÍÐÔ×Úîðñóõöøúùòèà×ÑÐûËÀ·¬£¢ô£¤¦©«­¯°±±²²³²Õ±¬¯³¶º½ÀÃÇÊÍÐÔ×Úíðñóõöøúùø÷õôòêåÞØÔÐÐÏÇ¿¶®¤¢Ï¬¯³¶º½ÀÃÇÊÍÐÔ×Úìðñóõöøúùø÷õôòñïîìëéäàÜÙ×ÔÒËŽ¶±¨£¢€À¬¯³¶º½ÀÃÇÊÍÐÔ×Úëðñóõöøúùø÷õôòñïîìëéèçåäâáßÞÜÙ×ÕÔÓÏÊÅÀ¼¶°ª¥¢¢¡¡  ¬¯³¶º½ÀÃÇÊÍÐÔ×Úêðñóõöøúùø÷õôòñïîìëéâÞÛØÕÒÏËÈÅÁ½º¸µ²®ª¨§¥¤£¢ Ÿž›¬¯³¶º½ÀÃÇÊÍÐÔ×Úéðñóõöøúùø÷õôòñïîìëé×ÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›¬¯³¶º½ÀÃÇÊÍÐÔ×Úèðñóõöøúùø÷õôòñïîìëéØÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¯³¶º½ÀÃÇÊÍÐÔ×Úçðñóõöøúùø÷õôòñïîìëéØÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¯³¶º½ÀÃÇÊÍÐÔ×Úæïñóôöøúùø÷õôòñïíìêéÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›­¯³¶º½ÀÃÇÊÍÐÔ×Úåïðòôö÷ùùøöôóñðîìëéçÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›®°³¶º½ÀÃÇÊÍÐÔ×Úãîðñóõ÷ùù÷öôòðïíëéèæÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›Q°³¶º½ÀÃÇÊÍÐÔ×Úãíïñóõ÷ùø÷õóñðîìêèæäÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›³³¶º½ÀÃÇÊÍÐÔ×ÚâìîðòôöøøöôóñïíëéçåãÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›´¶º½ÀÃÇÊÍÐÔ×ÚáëíïñóöøøöôòðîìêèæäâÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›øº½ÀÃÇÊÍÐÔ×ÚàêìîñóõøøöóòïíëéçåãáÙÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ŽÀÃÇÊÍÐÔ×Úßéëîðòõ÷÷õóñïìêèæãáߨÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÆÁÄÇÊÍÐÔ×ÚÞèêíïòô÷÷õòðîìéçåâàÞ×ÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÈÇÊÍÐÔ×ÚÞçéìïñôööôòðíëèæäáßÜ×ÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž› ÊÎÑÔ×ÚÝæéëîñóööôñïìêçåãàÞÛÖÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž› ÌÕ×ÚÝäèëíðóööôñîìéçäáßÜÚÕÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÏÞáäèëïòõõóðîëèæãàÞÛØÔÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÒèëîñôõòïíêèåâßÜÚ×ÓÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÕñõôòïìéæãàÞÛØÕÒÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ÚëéæãàÝÚ×ÔÑÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›ßÛÚ×ÔÑÎÌÉÆÃÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›#äÈÄÂÀ½º·´±¯®­¬ª©¨§¥¤£¢ Ÿž›Àÿÿü>ÿÿß>ÿÿ¥>ÿÿ>>ÿþ±=ÿýá<ÿýÛ<ÿþ›=ÿþ&ý=ÿÿƒ>ÿÿÅ>ÿÿß>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿç>ÿÿà>ÿÿÁ>ÿÿw>ÿþó=ÿþo=ÿýª<ÿþ³;ÿþ“:ÿþSë8ÿýšý6ÿý+¬þ4ÿ ý(šõ2ÿ ýkÊ0ÿü&|Îþ,ÿühªî)ÿû0k©Þ%ÿúD{¥Òûÿø!Lp°Ôîÿ%æ#@Ufx¢²ÀÉÑÙäëòøúýÿýûøòëÃüÀ¸¯¥¢ò›…jedba`_^\[ZXÃû¾¶°§¢ï {igfedba`_^\[ZXÃúÀ¼¶°ª£¢ìŸ“okjigfedba`_^\[ZX ÃøÁ¾º·³®ª¤ ¢Þ™Žqonlkjigfedba`_^\[ZX¸·¶´³±¯¬©¦£¢ä ™…xtrqponlkjigfedba`_^\[ZX¢ßŸš“‹‚zyxvutrqponlkjigfedba`_^\[ZX ¢€ៜ˜”Šƒ€~|{zyxvutrqponlkjigfedba`_^\[ZX¡¡  žœš™—”Љˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[Zš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[Yš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^ZSYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_YONVš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedbad^NÍRYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedb…¸–VÎYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfe¯ÃõdÓ]š™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjih‰¯Ãþ¿qrÕbš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkwœ¹Ãÿ·€Ødš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqpoy—±Ãÿ©ŽÙ[š™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvuttˆŸµÂ Ãþ¾œÝˆYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zy{Œ ¯À ÃþÀ§¢à gYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€œ«¶ÂÃþ¿§¢æ|ZYš™˜–•”“’ŽŒ‹Š‰‡‰™¢©´¼Ãþ¸¤¢ë…[ZYš™—––—™›ž¢¦«¯³¹¿ÂÃþ¾¬¢÷‚\[ZY¼¾¿Â#Ãý¿°£¢ùžv^\[ZY%Ãþ¼®¢øg_^\[ZY"Ãý¿´¨¢ö—ua`_^\[ZYÃý¾µª¢ô—zdca`_^\[ZYÃüÀ¸°¦¢ñ¡vfedca`_^\[ZYÃû½¶¯§¢ï—„nigfedca`_^\[ZYÃú½¹´®¨ ¢ë¡–‡tlkjigfedca`_^\[ZYÃ÷¿¼¹¶³¯ª¦ ¢à›‚tponlkjigfedca`_^\[ZY°¯®¬ª§¥£¢ãŸ˜…yutsqponlkjigfedca`_^\[ZY¢Ý¡œ—‘Š‚{zyxvutsqponlkjigfedca`_^\[ZY ¢€°¡Ÿœ™–’Œˆƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYŸžœ›š˜–”‘‹Š‰ˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponmkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[Zš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[Zš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\\š™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\Ïš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_К™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedcb`Ñš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedc6Ôš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfe Öš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjij Øš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponmlB Ûš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqpo-àš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutãš™˜—•”“’ދЉˆ†…„ƒ€~}|zSèš™˜—•”“’ދЉˆ†…„ƒ‚ ñš™˜—•”“’Ž‹Šˆ&ÃüÀ¸¯¥¢ò›…jedba`_^\[ZXÃû¾¶°§¢ï {igfedba`_^\[ZXÃúÀ¼¶°ª£¢ìŸ“okjigfedba`_^\[ZX ÃøÁ¾º·³®ª¤ ¢Þ™Žqonlkjigfedba`_^\[ZX¸·¶´³±¯¬©¦£¢ä ™…xtrqponlkjigfedba`_^\[ZX¢ßŸš“‹‚zyxvutrqponlkjigfedba`_^\[ZX ¢€ៜ˜”Šƒ€~|{zyxvutrqponlkjigfedba`_^\[ZX¡¡  žœš™—”Љˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[Zš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[Yš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^ZSYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_YONVš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedbad^NÍRYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedb…¸–VÎYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfe¯ÃõdÓ]š™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjih‰¯Ãþ¿qrÕbš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkwœ¹Ãÿ·€Ødš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqpoy—±Ãÿ©ŽÙ[š™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvuttˆŸµÂ Ãþ¾œÝˆYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zy{Œ ¯À ÃþÀ§¢à gYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€œ«¶ÂÃþ¿§¢æ|ZYš™˜–•”“’ŽŒ‹Š‰‡‰™¢©´¼Ãþ¸¤¢ë…[ZYš™—––—™›ž¢¦«¯³¹¿ÂÃþ¾¬¢÷‚\[ZY¼¾¿Â#Ãý¿°£¢ùžv^\[ZY%Ãþ¼®¢øg_^\[ZY"Ãý¿´¨¢ö—ua`_^\[ZYÃý¾µª¢ô—zdca`_^\[ZYÃüÀ¸°¦¢ñ¡vfedca`_^\[ZYÃû½¶¯§¢ï—„nigfedca`_^\[ZYÃú½¹´®¨ ¢ë¡–‡tlkjigfedca`_^\[ZYÃ÷¿¼¹¶³¯ª¦ ¢à›‚tponlkjigfedca`_^\[ZY°¯®¬ª§¥£¢ãŸ˜…yutsqponlkjigfedca`_^\[ZY¢Ý¡œ—‘Š‚{zyxvutsqponlkjigfedca`_^\[ZY ¢€°¡Ÿœ™–’Œˆƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYŸžœ›š˜–”‘‹Š‰ˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponmkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[Zš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[Zš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\\š™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\Ïš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_К™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedcb`Ñš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedc6Ôš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfe Öš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjij Øš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponmlB Ûš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqpo-àš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutãš™˜—•”“’ދЉˆ†…„ƒ€~}|zSèš™˜—•”“’ދЉˆ†…„ƒ‚ ñš™˜—•”“’Ž‹Šˆ&ÃüÀ¸¯¥¢ò›…jedba`_^\[ZXÃû¾¶°§¢ï {igfedba`_^\[ZXÃúÀ¼¶°ª£¢ìŸ“okjigfedba`_^\[ZX ÃøÁ¾º·³®ª¤ ¢Þ™Žqonlkjigfedba`_^\[ZX¸·¶´³±¯¬©¦£¢ä ™…xtrqponlkjigfedba`_^\[ZX¢ßŸš“‹‚zyxvutrqponlkjigfedba`_^\[ZX ¢€ៜ˜”Šƒ€~|{zyxvutrqponlkjigfedba`_^\[ZX¡¡  žœš™—”Љˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZXš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[ZYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[Zš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^\[Yš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_^ZSYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedba`_YONVš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedbad^NÍRYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfedb…¸–VÎYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjigfe¯ÃõdÓ]š™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkjih‰¯Ãþ¿qrÕbš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqponlkwœ¹Ãÿ·€Ødš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvutrqpoy—±Ãÿ©ŽÙ[š™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zyxvuttˆŸµÂ Ãþ¾œÝˆYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€~|{zy{Œ ¯À ÃþÀ§¢à gYš™˜–•”“’ŽŒ‹Š‰ˆ†…„ƒ€œ«¶ÂÃþ¿§¢æ|ZYš™˜–•”“’ŽŒ‹Š‰‡‰™¢©´¼Ãþ¸¤¢ë…[ZYš™—––—™›ž¢¦«¯³¹¿ÂÃþ¾¬¢÷‚\[ZY¼¾¿Â#Ãý¿°£¢ùžv^\[ZY%Ãþ¼®¢øg_^\[ZY"Ãý¿´¨¢ö—ua`_^\[ZYÃý¾µª¢ô—zdca`_^\[ZYÃüÀ¸°¦¢ñ¡vfedca`_^\[ZYÃû½¶¯§¢ï—„nigfedca`_^\[ZYÃú½¹´®¨ ¢ë¡–‡tlkjigfedca`_^\[ZYÃ÷¿¼¹¶³¯ª¦ ¢à›‚tponlkjigfedca`_^\[ZY°¯®¬ª§¥£¢ãŸ˜…yutsqponlkjigfedca`_^\[ZY¢Ý¡œ—‘Š‚{zyxvutsqponlkjigfedca`_^\[ZY ¢€°¡Ÿœ™–’Œˆƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYŸžœ›š˜–”‘‹Š‰ˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponmkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[ZYš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[Zš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\[Zš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\\š™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_^\Ïš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedca`_К™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedcb`Ñš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfedc6Ôš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjigfe Öš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponlkjij Øš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqponmlB Ûš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutsqpo-àš™˜—•”“’ދЉˆ†…„ƒ€~}{zyxvutãš™˜—•”“’ދЉˆ†…„ƒ€~}|zSèš™˜—•”“’ދЉˆ†…„ƒ‚ ñš™˜—•”“’Ž‹Šˆ&4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿç4ÿÿã4ÿÿË4ÿÿŠ3ÿþü%3ÿþ2ÿýÈ2ÿý¡3ÿþo3ÿþö4ÿÿ‡4ÿÿÒ4ÿÿ÷Ùÿÿ÷4ÿÿÒ4ÿÿˆ3ÿþ÷3ÿþv2ÿý«1ÿü­/ÿýþ….ÿþßC,ÿýô‚ *ÿý÷(ÿýä{ %ÿü÷«K "ÿüô«YÿûýЈDÿûò¿†MÿùþᲊW* ÿøòÛº–yW- ñäÚÒÊÀ³¤‘|hWC+ &;@í8 Backgroundÿ!?€ "     %$ÿÿÿþ#ÿÿÿÿ ©í8݃­ƒ¹ƒÅí8-=M]m}­½ÍÝíý‚ ‚‚-‚=‚M‚]‚m‚}‚‚‚­‚½‚݂͂í‚ýƒ ƒƒ-ƒ=ƒMƒ]ƒmƒ}ƒƒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Øÿ Øÿ Øÿ Øÿöœ{N='sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/resources/banner.xcf000066400000000000000000000142361463772530400273520ustar00rootroot00000000000000gimp xcf v011í:–BB6 gimp-commentgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) µ‹,0 logo.pngÿ!?€ "     ¸%$ÿÿÿÿ#ÿÿÿÿ¶,0Ò,0ê ÿMNNù\t‹‘¡¡ª³ø²¦¡ †rTN ÿNûOy–«¼Ãü¸§‘lNNýv¢½Ãýº™hNNþq±!Ã÷¥cNNNNÂ#Ãú¾xNQZl&Ãû»XY~”'Ãû}r£¼%Ãù´x¯µ¦¸"Ãõ³¢ŒY¯¼Ï¾²¹ÃïÁ¶¦ ƒ]Y¯¸ÂÙÙɼ¶¹ÁÃæ¿·­£Ÿ‹j`]Y¯¸ÁÊÜêåÜͽ¶±´¸½Á ÃÞ¿½·³­¦¢ž’€lgc`]Y¯¸ÁÊÒâñöùðåÝ϶­£¤©ýª¨£¢€Ežš“Š~tqmjgc`]Y¯¸ÁÊÒâñöù÷óïëãÞÕÍû³¬£ žœ›–“Žˆ…‚~{wtqmjgc`]Y¯¸ÁÊÒáñöù÷óïëÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgc`]Y°¸ÁÊÒßñõùöòîéÔÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgc`]Zª¸ÁÊÒÞîôøõðëæÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgc`]ZO†ÁÊÒÝìò÷óîèâÒÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgcaTRiˆÃÈÒÜêñöòìåßÑÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjj“¼he’–ÃÃÅÐâïõðêãÜÐÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtq†¢¾Ã¿zª£°ÃâÉØàâàØÐÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚ž®¾Ã÷Á« h¯¾¸¬¼ÃÇîÅÁ¼¸²¯¬ª§¥£¤¨¦¬¯·½Ãó¸¦rY¯¸ËÔÀ··ÁÃì¿´§¡g]Y¯¸ÁÑâÜÏ¿¹µºÀÃΌ±¨¢Šoc`]Y¯¸ÁÊÔçñíåÚǺ²«¯±··¹½Ø¼¸·¶°®©£¢Ÿ—Œzmjgc`]Y¯¸ÁÊÒâñöù÷óêãÝÒǽ·­ª¢€K¡Ÿžš˜’‹‚{wtqmjgc`]Y¯¸ÁÊÒâñöù÷óïëÚÐÇÀ¹¶±§£Ÿœ™•’‹ˆ…~{wtqmjgc`]Y¯¸ÁÊÒàñöùöòïêÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgc`]Z±¸ÁÊÒÞðõùõñìèÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgc`]Z}°ÁÊÒÞíóøôïêäÒÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgc`ZTUkÂÊÒÝëñ÷óíçáÑÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgcŽTUzŠÃÅÎÛéðöñëäÝÑÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmq”·Ã|oŸ›¿ÃÃÅÒâòïèáÚÐÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{w€•®ÀÃú™|­¬¦½ÃæËÑÓÒÍÇÀ¸°­©¦£Ÿœ™•’‹Œ”œ¥°¼Ãöº¤—^¯¾Èµ²¿ ÃôÁÀ¾»¹·¶¶·»º¼ Ãñ½­¢‘aZ¯¸ÅÙÒÀ¹¶¿Ãé¾´©¢–w`]Z¯¸ÁËàæßÒ¸³µ»¿Ãྐྵ´­¥¢œ‹vgd`]Z¯¸ÁÉÒãñöôéßÑÁ¶¬§©«°€íª©¥¢¢ š“ˆzqnjgd`]Z¯¸ÁÉÒâñöù÷óïëåßÙÌÀ¹±¬¥¡ žš—“އ‚~{wtqnjgd`]Z¯¸ÁÉÒàñöù÷óïëÔÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]Z°¸ÁÉÒÞñõùöòîêÔÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]Z²¸ÁÉÒÞïôøõðëçÓÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]Z¹ÁÉÒÝìò÷ôîéãÒÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]ØÂÊÒÛêñöòìæàÒÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgdaÛËÓÛçïõñêãÜÑÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjg àçíôïèàÙÐÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{xtqoèäß×ÏÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚| ÿMNNù\t‹‘¡¡ª³ø²¦¡ †rTN ÿNûOy–«¼Ãü¸§‘lNNýv¢½Ãýº™hNNþq±!Ã÷¥cNNNNÂ#Ãú¾xNQZl&Ãû»XY~”'Ãû}r£¼%Ãù´x¯µ¦¸"Ãõ³¢ŒY¯¼Ï¾²¹ÃïÁ¶¦ ƒ]Y¯¸ÂÙÙɼ¶¹ÁÃæ¿·­£Ÿ‹j`]Y¯¸ÁÊÜêåÜͽ¶±´¸½Á ÃÞ¿½·³­¦¢ž’€lgc`]Y¯¸ÁÊÒâñöùðåÝ϶­£¤©ýª¨£¢€Ežš“Š~tqmjgc`]Y¯¸ÁÊÒâñöù÷óïëãÞÕÍû³¬£ žœ›–“Žˆ…‚~{wtqmjgc`]Y¯¸ÁÊÒáñöù÷óïëÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgc`]Y°¸ÁÊÒßñõùöòîéÔÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgc`]Zª¸ÁÊÒÞîôøõðëæÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgc`]ZO†ÁÊÒÝìò÷óîèâÒÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgcaTRiˆÃÈÒÜêñöòìåßÑÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjj“¼he’–ÃÃÅÐâïõðêãÜÐÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtq†¢¾Ã¿zª£°ÃâÉØàâàØÐÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚ž®¾Ã÷Á« h¯¾¸¬¼ÃÇîÅÁ¼¸²¯¬ª§¥£¤¨¦¬¯·½Ãó¸¦rY¯¸ËÔÀ··ÁÃì¿´§¡g]Y¯¸ÁÑâÜÏ¿¹µºÀÃΌ±¨¢Šoc`]Y¯¸ÁÊÔçñíåÚǺ²«¯±··¹½Ø¼¸·¶°®©£¢Ÿ—Œzmjgc`]Y¯¸ÁÊÒâñöù÷óêãÝÒǽ·­ª¢€K¡Ÿžš˜’‹‚{wtqmjgc`]Y¯¸ÁÊÒâñöù÷óïëÚÐÇÀ¹¶±§£Ÿœ™•’‹ˆ…~{wtqmjgc`]Y¯¸ÁÊÒàñöùöòïêÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgc`]Z±¸ÁÊÒÞðõùõñìèÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgc`]Z}°ÁÊÒÞíóøôïêäÒÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgc`ZTUkÂÊÒÝëñ÷óíçáÑÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgcŽTUzŠÃÅÎÛéðöñëäÝÑÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmq”·Ã|oŸ›¿ÃÃÅÒâòïèáÚÐÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{w€•®ÀÃú™|­¬¦½ÃæËÑÓÒÍÇÀ¸°­©¦£Ÿœ™•’‹Œ”œ¥°¼Ãöº¤—^¯¾Èµ²¿ ÃôÁÀ¾»¹·¶¶·»º¼ Ãñ½­¢‘aZ¯¸ÅÙÒÀ¹¶¿Ãé¾´©¢–w`]Z¯¸ÁËàæßÒ¸³µ»¿Ãྐྵ´­¥¢œ‹vgd`]Z¯¸ÁÉÒãñöôéßÑÁ¶¬§©«°€íª©¥¢¢ š“ˆzqnjgd`]Z¯¸ÁÉÒâñöù÷óïëåßÙÌÀ¹±¬¥¡ žš—“އ‚~{wtqnjgd`]Z¯¸ÁÉÒàñöù÷óïëÔÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]Z°¸ÁÉÒÞñõùöòîêÔÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]Z²¸ÁÉÒÞïôøõðëçÓÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]Z¹ÁÉÒÝìò÷ôîéãÒÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]ØÂÊÒÛêñöòìæàÒÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgdaÛËÓÛçïõñêãÜÑÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjg àçíôïèàÙÐÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{xtqoèäß×ÏÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚| ÿMNNù\t‹‘¡¡ª³ø²¦¡ †rTN ÿNûOy–«¼Ãü¸§‘lNNýv¢½Ãýº™hNNþq±!Ã÷¥cNNNNÂ#Ãú¾xNQZl&Ãû»XY~”'Ãû}r£¼%Ãù´x¯µ¦¸"Ãõ³¢ŒY¯¼Ï¾²¹ÃïÁ¶¦ ƒ]Y¯¸ÂÙÙɼ¶¹ÁÃæ¿·­£Ÿ‹j`]Y¯¸ÁÊÜêåÜͽ¶±´¸½Á ÃÞ¿½·³­¦¢ž’€lgc`]Y¯¸ÁÊÒâñöùðåÝ϶­£¤©ýª¨£¢€Ežš“Š~tqmjgc`]Y¯¸ÁÊÒâñöù÷óïëãÞÕÍû³¬£ žœ›–“Žˆ…‚~{wtqmjgc`]Y¯¸ÁÊÒáñöù÷óïëÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgc`]Y°¸ÁÊÒßñõùöòîéÔÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgc`]Zª¸ÁÊÒÞîôøõðëæÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgc`]ZO†ÁÊÒÝìò÷óîèâÒÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjgcaTRiˆÃÈÒÜêñöòìåßÑÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtqmjj“¼he’–ÃÃÅÐâïõðêãÜÐÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚~{wtq†¢¾Ã¿zª£°ÃâÉØàâàØÐÇÀ¸°­©¦£Ÿœ™•’‹ˆ…‚ž®¾Ã÷Á« h¯¾¸¬¼ÃÇîÅÁ¼¸²¯¬ª§¥£¤¨¦¬¯·½Ãó¸¦rY¯¸ËÔÀ··ÁÃì¿´§¡g]Y¯¸ÁÑâÜÏ¿¹µºÀÃΌ±¨¢Šoc`]Y¯¸ÁÊÔçñíåÚǺ²«¯±··¹½Ø¼¸·¶°®©£¢Ÿ—Œzmjgc`]Y¯¸ÁÊÒâñöù÷óêãÝÒǽ·­ª¢€K¡Ÿžš˜’‹‚{wtqmjgc`]Y¯¸ÁÊÒâñöù÷óïëÚÐÇÀ¹¶±§£Ÿœ™•’‹ˆ…~{wtqmjgc`]Y¯¸ÁÊÒàñöùöòïêÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgc`]Z±¸ÁÊÒÞðõùõñìèÓÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgc`]Z}°ÁÊÒÞíóøôïêäÒÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgc`ZTUkÂÊÒÝëñ÷óíçáÑÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmjgcŽTUzŠÃÅÎÛéðöñëäÝÑÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{wtqmq”·Ã|oŸ›¿ÃÃÅÒâòïèáÚÐÇÀ¸°­©¦£Ÿœ™•’‹ˆ…~{w€•®ÀÃú™|­¬¦½ÃæËÑÓÒÍÇÀ¸°­©¦£Ÿœ™•’‹Œ”œ¥°¼Ãöº¤—^¯¾Èµ²¿ ÃôÁÀ¾»¹·¶¶·»º¼ Ãñ½­¢‘aZ¯¸ÅÙÒÀ¹¶¿Ãé¾´©¢–w`]Z¯¸ÁËàæßÒ¸³µ»¿Ãྐྵ´­¥¢œ‹vgd`]Z¯¸ÁÉÒãñöôéßÑÁ¶¬§©«°€íª©¥¢¢ š“ˆzqnjgd`]Z¯¸ÁÉÒâñöù÷óïëåßÙÌÀ¹±¬¥¡ žš—“އ‚~{wtqnjgd`]Z¯¸ÁÉÒàñöù÷óïëÔÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]Z°¸ÁÉÒÞñõùöòîêÔÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]Z²¸ÁÉÒÞïôøõðëçÓÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]Z¹ÁÉÒÝìò÷ôîéãÒÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgd`]ØÂÊÒÛêñöòìæàÒÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjgdaÛËÓÛçïõñêãÜÑÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{wtqnjg àçíôïèàÙÐÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚~{xtqoèäß×ÏÈÀ¸±­©¦£Ÿœ™–’Œˆ…‚| ø'Qo™­ÍÐíÿøæÍÌ£•iFûC„¿÷ÿüë³x- ý3šíÿýáƒþ,À"ÿýýþfú%ÿüë=U(ÿýõ8Ø)ÿÿÇŒÿÿÜ)ÿþÑ_)ÿþNŸ)ÿþ„õ)ÿÿì`ÿÿü)ÿþ÷¨)ÿþ¢M)ÿþ.½)ÿþ»þ‹ÿÿå)ÿþês)ÿýv’'ÿÿþLÖ#ÿþÒBýQ³üÿýô©C üS˜ÒÿûúʼnK÷4`~™»ÌÕòÿøèÎÍ«™oT, í: Backgroundÿ!?€ "     %$ÿÿÿþ#ÿÿÿÿ–í:Êz†’í:&2>JVbn€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ 2ÿ 2ÿ 2ÿö{=sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/resources/icon.png000066400000000000000000000157021463772530400270400ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aË pHYs0w0w4„.tEXtSoftwarewww.inkscape.org›î<tEXtAuthorJakub Steineræû÷/!tEXtSourcehttp://jimmac.musichall.czifã^XtEXtCopyrightCC0 Public Domain Dedication http://creativecommons.org/publicdomain/zero/1.0/Æã½ùžIDATxœí]iŒÇy}Õsß×^¼)Q$uÇ$¨$¢ŒH D¢dR„¼6bñ~$2Ë@l°ƒ8É"rþ"À Ä-…¡M›R$GÊa6âP²)Ǥ$2äR"ÃÍjwgfç¾û¨Êe{z¦{Î=¸ì4zfúªéúê«ë{¯75Èj'`PLNNúdY!„$c㢌±€ ?!$xí»À lq»€êµÏ%UÆX…R „Tä4M[°èóùR'Nœ(,ß?[¬u Üêr¹v2ÆnaŒm&„l°ÀfV1} €4€ÿÇ›%„\%„Ìx¿P(\úÑ~T_ÅôuÄš1€ƒns8{!p'€]×6ßê¦l P3„iJéBÈYÆØ¯×ûÞ‰'äÕN°J099‘eùJé~BÈýöˆ rO‡ÃŸÏŸÏÇ§Ó Ç·Û —Ë—Ë%Îõx<-׫ª MÓ”RȲŒF£UU¡( êõ:ªÕ*dyà¼SœcŒ½Mù ¥ôÔ÷¿ÿýKƒÞ´¬ˆLNNúƃŒ±G!Ü…¥:¹+x<D£Q„Ãa±…B!ƒAøý~¸Ýîåûhš†Z­†Z­†R©„R©„b±ˆR©„B¡€|>r¹Üëmü„òo‡ã_Ož<9» IoÁ²À#<2êr¹žpÀÞN×x<Œa||‰D±X ñxÀjVóýAQär9d³Yd³Y¤Ói¤R)äóù®®'„¼ àuBȉW^yåç˕ΡÀ¡C‡B&%Iú-ÆØƘÃì\I’0117bÓ¦MG$frÖ$dYF2™ÄÂÂfggñᇢV«Y^C¹ÂûG/½ú꫇™ž¡À‘#Gî ”>-IÒ“š¦ùÛ>ˆŒŽŽâÖ[oÅöíÛ111ÑT/߬`Œ!›ÍbffW®\ÁÌÌ E1=]’¤7cãv»_=qâ„6èó2€C‡ís¹\¡(ʯ·»—$Iغu+vïÞ;vÜ®|¥¡ª*fggqéÒ%\¼xÑÔ;H’”¦”þÉÄÄÄß?ÿüó¦Ó }ÀÇ?þñÛ½^ïß6ßhw|bb÷ÜsvíÚ¿¿­C°Ñ(¥˜™™Á¹sçpñâEÑKÑC’¤ €¯¼òÊ+G°^ŸÑ“<õÔS®\.÷§Š¢|RÚT¿;Ü~ûíØ»w/&&&zM‡¨V«xçwpæÌ”J¥–ã‡ã$Izì{ßûÞå^îÛµ>|x‹Ûíþa£Ñ¸Mÿ»$I¸ë®»°ÿ~„ÃV£¬6†MÓpöìYüô§?méjB¨ÃáøúÉ“'ÿ¼ÛûueO<ñįB~(Ër“?ß´i~øaÄãñnŸgcHPU§NÂéÓ§A)m:æt:_;yòäatQ%t4€'Ÿ|ò¾b±xJUU'ÿM’$<ôÐCØ»w/Y3£É7%’É$^{í5är¹¦ßNç›÷Þ{ïG§¦¦¨É¥–fÇLqäÈ‘€3FC â¸Ýn<þøã¸óÎ;íÌ_ƒ¸ãŽ;077‡b±(~§”nÉf³w?þ„Õõ–ñ###/W«UÑw“$ ?þ8n¹å–ncxðù|˜œœÄøøxÓï²,â3Ÿù̧¬®55€§žzjÇâââGõ¿ÝÿýضmÛ@‰µ±;Í$‰?.—ËÂÇ»\.ìÛ·oh ¶1|D£QìÙ³.\Ðÿ/B C¡B¡=r8hš†J¥‚R©Ô–Â[ú—/_¶ &5EO,¥cccPÕj‘H‘H”R”J%är9ÌÍÍÁét" ®8qãF¥Õjårõz½m‰æ¿«W¯¢Z­öTêõèÙ€%W”N§122‚D"Y–Q­V¡(Š0UUQ(P(077‡Ã¿ß/è[v5qŒ1Q˜jµše×MUU$“IÌÏÏ£V«õñ}°Ä|I§Ó‚¹ã÷û¡ªªøN§‰D‰DBx†b±(Z­^¯^¯§is½ãÚ4-êõºàZ5Úc(‹X\\Äââ"TU8ã9ú6ž°|>/J¾Ûí†×ë!õzÕjU4X¸g ê4Î¥–¢ŠÝn· tºÝn8ÎÞSpr©,Ë‚pÚM]ÍC¥R mY–ÁZÆs dFÙlápX Eúý~ƒABDQ©TP¯×011!9•Jår¹‰;GÃáì^§Ó)6‡Ã§s(É”RhšEQÄ^UU‘ñÝvÇ€%¯Ê=e±X„¢(`Œõt^1´7ÈC¹\†¦i-áá^¯~¿£££–<@­VÕgüh2ÎÀå[;88H’$>sÖF3%I!¤Å›H’ÔRªøwþÒ)¥-›¦ib¤Drº9oð5–ç/7†^„Ú±Wô$Iкù •eYÔ…Fn·»Éˆôm‹Z­†J¥"žÃ3b-ƒ1&Ü?ÿŸµZMÐJf¸C7€^K!D¸w¿ß/^7 îRƒÁ 4M% ±üóÄú‚Þ+p÷¯ßx<Åjg¸«nfÐyú½ÞôF£÷(ÆLPUµÅ›¥[ŸYúLÓ§«ŠèÓ`<ضacYZQÃüÓÆm¬ƒy‰ãçð½þ<>YBiÊH~ÿv™f•¡7Rwš7Y–‘ËåZ2ÝlÓ—ÒõšiÃIJÌãóßèãk¦Àkå ¯l„Óè+зlÙ0<€í¦‡Bȳc¦@ùq¿Ô×»š>¿·ki¯µ®ÒJé?›35€÷Þ{ïUƒÊÚÀ˜©ÆcÆóÚ]cv½žñãoûÛo™45€©©)J)ýô¡;cly·ËÌv†`Ör·Ñ7j”Ò/Y`Ù xâ‰'þe~~¾çª S)î¦Ôëûê6ú¥ô+Çÿ…Õ9–ð¹Ï}î×ÞxãÏœ9ÓÓƒÍ2ݬ-Ði³Ñ;êõ:dYþêC=d9Öci„㚦‘·Þz §NêºDvãºzµ  w0¶GpmeëØØØ_Yoj_üâÍçóøtêÙ³g±°°ÐU¿¼ÛÌ4þnÖ°Ñ6oÞ,æ;x¾QJ¿099iªÁkê"‘Èïóhضm[_`Ÿ¯EŸÆ˜Ñztã lM‚VB°aÃÜvÛmغukË»!„4ÓPJ‘J¥¢f÷³Ò¨9gŠ¢´PÃc"ÃãñÀçóÁï÷‹zȬÔóÏfí» hF4Å–-[°}ûvKÑmÎÓà(—Ë %ÈʲƘ·l6Û"E¦Ì) "(”†¡—îàÍBb±ÆÇDZyóæ®ÖRàÇzL&-¯15I’”H$ÒbÅ9;)€ó®H¥RA*•‚ÏçC(B$A 0­ë̓n#ˆÇãëY”KÓ4¤Ó馼©×ëXXX°¼ÎrÀãñ4…N1¶DGA0ì*aŒ1ùšL&CÈï÷ÃëõŠ?©ÏpcPÇz„ÓéD(B8F<G,k»˜U7Ð4 M|ÆΟ?ß± í‰Dàp8ÍfEì[:†¢(ˆF£=7Ð4M¤‘§SAœN§ÐX I’0ö@ €`0ˆP($4ƒ¢^¯#•JµDF_¼xétºãõ €1&ÖàÔ$MÓ?=‘HÀëí¸”%xLŸúø~}<ßZ2 n´|y:Îlâ â~Ku'hš†\.ײv¥.\Àìlw‹Žu¨ª*J¥6lØ€ÑÑQäóyd2Ôj5ÌÏÏÃï÷#‹ Ì3Õ#â#]œd¬:ŒÕ‰þ³®'pÝÐôdþ™Oô줕î¢2¶DÇ+‹-î]Qœ;w®«’ÏÑuPh£Ñ@±XD<G"‘@<G­VC&“A>ŸÇÜÜœ)\Iö/Ïœõ Nãô|#’É$¦§§{æEôÌ¥IFGGEÉܼy36lØ D"R©”ж¤Üà½)+€R©„Ë—/#›ÍöU5ö.Ë2Òé4ÆÇÇá÷ûŸ=‹!‹AÓ4‹Eär9ÌÎÎÂãñú¸m ÁÅ9ά_©TpõêUd2™¨q}ñxŸ3 b'çìÆ Ë²`ºær¹¦õ}½^ïºvÙÝ‚±ëZÕjÕR~RŠl6‹ùùy …¡ô’ú&†ðƈ¢(ˆÅb¢{éàµZ n·###i‰Èf³PU.—KDpM€õ>îϵx¦sÞ¿x5ÀŸdYêðøÀÌ z½ŽL&ƒH$"J7ª×ëMžA/Q­VQ*•ÄŸã/‚Ëåc.—ë†3 #A”Ï—t“yŒ-Qí¹¢ ¯ÿ—£û;j¥T„B!1˜Ã½!Š¢4éðÑ@àúha¹\CÈú?Ë»`úî—Ëå-½.Àrƒw19 MÏKä"<(£4 ”Ëeá%¹ Ìry •(Ë2Êå2¢ÑæÙGB¼^/|>Rijè4 BÄ,—ñ8?§“F1ï³scàýw¾çç´3”N3’z&ò àôv>DζVclUèáÜ <¢Ñh[οÏçC8n‚0*†ëOÆØšŒ`ŒµèqÚúZ zY3ú’$‰Æ Q€»V½{å.X/ ¡‹àr+˽—ЧÍ(Ñnæs-aÍ€$I²Šƒ¦³ˆŠ¢ˆW¯×¡ªª0žYÆ@}Ým|?¿ ýF e[óú\ˆ—4îŒ /®b‰°Ê$žV³ã®]¸! €‹Bõ*a£3lˆ›VôpëX" ذæ`*ö±f"Œ±õV×®&!¦Ë‡˜€¦iÇÑ50òÕ3ž«ÿ|#¶¦×0Œ±2;hjŸüä'ßðƒ~žØ®¥­ßóÏV›ÝcG?>gvܲH)ý]™>Ú¶ä·;ÏìÛclÚëõ~ÕêœNW/\¸ð^'6¬Ü¸Y•`µÙè×ÞÝW^xá…¼Õy–ðéOú#o¾ùæç_ýõžÖ£±ÊÜ6‰´ `È ”¢R© Ñh|볟ý¬9  Àëõ~GUUivv/¿ürËâ„fè”V^Aïþm^`ïPår™–FEyÑê|Sxúé§÷år¹|®=›Í"•Jõ¤`üÞMÀöýÁívcÿþýbÊ盪ª‡'''·š]g:œH$¾ '¸ÝnìÞ½»‰µc†n2²]·°]7ÐöÖp:¸í¶Ûpï½÷Âçó1†S§N‰ãŒ1©Ñh< àÏÚ^oqã;õ,Óx<ÞÄÉgƬ‚+Ú•x³½Ý è .— ;vìÀÝwßÝ´¶óÈÈHËŠ-™LæWÍîc%ãÓG¨¶£8QJÅt+§Bq´+Ùü³qo•ù”R{8X‡X,†;wbûöím×LbŒµPÉM™¼VP2®_W¯×Ûò5Má[œÀWüj‚eåþí6@+6n܈-[¶ˆu—ÌP©Tš<€¡„ÃÔü~:‹5ÕÁ™L›6m2½cL¬…—Ïç›D"Œ 7u“ù7kO€¯Ø>66†‰‰ Äb±®®ãQzÍf-¯15Bˆ‡›ˆ œèa¬cÚAO'„ˆ¿P($+úLn×¼Y¼€$IˆD"ˆÅbH$íyI‚Á âäÃÇFe£K]Kó”Ò&÷Ïx] Dô Bˆ¨÷¼|#õÛ¨ÑÃE"øüod-§!'­ôZA𦠂µá´æéáĸ;¥´EAĘú—­oqó=7&Y–…K· P1ÞSOA·"L0Ì?¯išÐ0ŠCè_¼êK¡YÆX FwÊÔµXŠÁ e½DØè¶@ÄM+˜ï÷¦¶¬9˜Rº¬ `ºß§õÓÒ×ÉýÞÆ)Κ05—Ëõ]½­>p Æà cëÚ¸·jyÛF00¨$I/˜45€Ã‡Ï0U–°B»–¶~¯?Ïl[’l«BÈw;f*÷cÙt¹\_p¥×‡š•nýqcæZ¾1#ËòÓV'XÀc=–ð)X¨Lµƒ™oW¢­¼€íBžräĉ–+Huì:tè4cìÖ ú)í¶ „9Jé—^zé¿;ÛÕ8À£>ú®¦i¿àgÝœßkš¹» è ÿ!Ëò}ÇŽ;ÓÍÉ]Ìu:˜¢aI^össs~MÓ–$éaBÈÔÒ-|afÀ\ ¢ÝüûMÀBþòÆ3Ï<ÓU‹¾,[HØÆ«N^ÛÍfïfŒ} ÀGc0Æ&ŒÝ=+CXçhxÀ›Œ±ÿ¬×ë?üÆ7¾Q^‰¯XL`<À{ž€|>¿ƒ²À¿ÄÛËëÿuèÎxÀYÆØÏªÕêÏŸ}öÙÞXCª…F£Ñ|@(YÎÍÍm¥”ÞÍ»1¶“² ÀN[V+`À%BÈ4cì€K’$pajjÊZ¶cqCŒ°\¹rÅ›Íf7kš¶‰RºUUÕÍš¦mÔ4m”R:ªªjBÓ´MÓ”Ro·q}޵ù.SJ3)¥Ji†1–¤”Î0Æ>Ô4íCY–g¦¦¦VÄ…ŠÂzÁ믿ú«Õj€€1UUšÈš¦•(¥¼t4M«1ƪn·;_,k_þò—k+ù_lØXvü?5ýÀ¸IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/strings.wxl000066400000000000000000000027671463772530400256240ustar00rootroot00000000000000 This Setup Wizard will install [ProductName] on your computer. If you have a previous version already installed, this installation process will update it. [ProductName] Setup {\WixUI_Font_Title}Shortcuts Select the shortcuts for the application. [ProductName] uses the latest version of SQLite, so you can enjoy all of its new features and bug fixes, but it does not have encryption support. It is also built with SQLCipher as a separate application. SQLCipher is an open source extension to SQLite providing transparent 256-bit AES encryption of database files, but uses a slightly older version of SQLite. Both applications (with and without SQLCipher) are installed and can run concurrently. This page allows you to choose the shortcuts for each application and where to place them. DB Browser (SQLite) DB Browser (SQLCipher) Desktop Program Menu sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/translations.wxs000066400000000000000000000264121463772530400266540ustar00rootroot00000000000000 sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/ui.wxs000066400000000000000000000054541463772530400245530ustar00rootroot00000000000000

1 1 1 sqlitebrowser-sqlitebrowser-5733cb7/installer/windows/variables.wxi000066400000000000000000000074451463772530400260760ustar00rootroot00000000000000 sqlitebrowser-sqlitebrowser-5733cb7/libs/000077500000000000000000000000001463772530400206255ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/DB4S_PATCH_05000066400000000000000000000221271463772530400224730ustar00rootroot00000000000000--- QScintilla_gpl-2.10.8/Qt4Qt5/qscintilla.pro 2018-10-01 15:46:06.000000000 +0200 +++ qscintilla/Qt4Qt5/qscintilla.pro 2018-11-21 19:51:25.870248673 +0100 @@ -23,24 +23,12 @@ !win32:VERSION = 13.2.1 TEMPLATE = lib -CONFIG += qt warn_off thread exceptions hide_symbols - -CONFIG(debug, debug|release) { - mac: { - TARGET = qscintilla2_qt$${QT_MAJOR_VERSION}_debug - } else { - win32: { - TARGET = qscintilla2_qt$${QT_MAJOR_VERSION}d - } else { - TARGET = qscintilla2_qt$${QT_MAJOR_VERSION} - } - } -} else { - TARGET = qscintilla2_qt$${QT_MAJOR_VERSION} -} - +TARGET = qscintilla2 +CONFIG += qt warn_off thread exceptions hide_symbols staticlib debug_and_release INCLUDEPATH += . ../include ../lexlib ../src +QMAKE_CXXFLAGS += -std=c++11 + !CONFIG(staticlib) { DEFINES += QSCINTILLA_MAKE_DLL } @@ -59,11 +47,6 @@ DEFINES += QT_NO_ACCESSIBILITY } -# For old versions of GCC. -unix:!macx { - CONFIG += c++11 -} - # Comment this in if you want the internal Scintilla classes to be placed in a # Scintilla namespace rather than pollute the global namespace. #DEFINES += SCI_NAMESPACE @@ -97,69 +80,20 @@ HEADERS = \ ./Qsci/qsciglobal.h \ - ./Qsci/qsciscintilla.h \ - ./Qsci/qsciscintillabase.h \ - ./Qsci/qsciabstractapis.h \ - ./Qsci/qsciapis.h \ ./Qsci/qscicommand.h \ ./Qsci/qscicommandset.h \ ./Qsci/qscidocument.h \ - ./Qsci/qscilexer.h \ - ./Qsci/qscilexeravs.h \ - ./Qsci/qscilexerbash.h \ - ./Qsci/qscilexerbatch.h \ - ./Qsci/qscilexercmake.h \ - ./Qsci/qscilexercoffeescript.h \ - ./Qsci/qscilexercpp.h \ - ./Qsci/qscilexercsharp.h \ - ./Qsci/qscilexercss.h \ - ./Qsci/qscilexercustom.h \ - ./Qsci/qscilexerd.h \ - ./Qsci/qscilexerdiff.h \ - ./Qsci/qscilexeredifact.h \ - ./Qsci/qscilexerfortran.h \ - ./Qsci/qscilexerfortran77.h \ - ./Qsci/qscilexerhtml.h \ - ./Qsci/qscilexeridl.h \ - ./Qsci/qscilexerjava.h \ - ./Qsci/qscilexerjavascript.h \ - ./Qsci/qscilexerjson.h \ - ./Qsci/qscilexerlua.h \ - ./Qsci/qscilexermakefile.h \ - ./Qsci/qscilexermarkdown.h \ - ./Qsci/qscilexermatlab.h \ - ./Qsci/qscilexeroctave.h \ - ./Qsci/qscilexerpascal.h \ - ./Qsci/qscilexerperl.h \ - ./Qsci/qscilexerpostscript.h \ - ./Qsci/qscilexerpo.h \ - ./Qsci/qscilexerpov.h \ - ./Qsci/qscilexerproperties.h \ - ./Qsci/qscilexerpython.h \ - ./Qsci/qscilexerruby.h \ - ./Qsci/qscilexerspice.h \ - ./Qsci/qscilexersql.h \ - ./Qsci/qscilexertcl.h \ - ./Qsci/qscilexertex.h \ - ./Qsci/qscilexerverilog.h \ - ./Qsci/qscilexervhdl.h \ - ./Qsci/qscilexerxml.h \ - ./Qsci/qscilexeryaml.h \ - ./Qsci/qscimacro.h \ ./Qsci/qsciprinter.h \ ./Qsci/qscistyle.h \ ./Qsci/qscistyledtext.h \ ListBoxQt.h \ - SciAccessibility.h \ - SciClasses.h \ SciNamespace.h \ - ScintillaQt.h \ ../include/ILexer.h \ ../include/Platform.h \ - ../include/Sci_Position.h \ ../include/SciLexer.h \ ../include/Scintilla.h \ ../include/ScintillaWidget.h \ + ../include/Sci_Position.h \ ../lexlib/Accessor.h \ ../lexlib/CharacterCategory.h \ ../lexlib/CharacterSet.h \ @@ -170,7 +104,6 @@ ../lexlib/LexerSimple.h \ ../lexlib/OptionSet.h \ ../lexlib/PropSetSimple.h \ - ../lexlib/StringCopy.h \ ../lexlib/StyleContext.h \ ../lexlib/SubStyles.h \ ../lexlib/WordList.h \ @@ -184,15 +117,12 @@ ../src/ContractionState.h \ ../src/Decoration.h \ ../src/Document.h \ - ../src/EditModel.h \ ../src/Editor.h \ - ../src/EditView.h \ ../src/ExternalLexer.h \ ../src/FontQuality.h \ ../src/Indicator.h \ ../src/KeyMap.h \ ../src/LineMarker.h \ - ../src/MarginView.h \ ../src/Partitioning.h \ ../src/PerLine.h \ ../src/PositionCache.h \ @@ -205,7 +135,26 @@ ../src/UnicodeFromUTF8.h \ ../src/UniConversion.h \ ../src/ViewStyle.h \ - ../src/XPM.h + ../src/XPM.h \ + ../src/Position.h \ + ../src/SparseVector.h \ + ./Qsci/qsciscintilla.h \ + ./Qsci/qsciscintillabase.h \ + ./Qsci/qsciabstractapis.h \ + ./Qsci/qsciapis.h \ + ./Qsci/qscilexer.h \ + ./Qsci/qscilexercustom.h \ + ./Qsci/qscilexersql.h \ + ./Qsci/qscilexerjson.h \ + ./Qsci/qscilexerhtml.h \ + ./Qsci/qscilexerxml.h \ + ./Qsci/qscilexerjavascript.h \ + ./Qsci/qscilexercpp.h \ + ./Qsci/qscilexerpython.h \ + ./Qsci/qscimacro.h \ + SciClasses.h \ + ScintillaQt.h \ + SciAccessibility.h SOURCES = \ qsciscintilla.cpp \ @@ -216,161 +165,28 @@ qscicommandset.cpp \ qscidocument.cpp \ qscilexer.cpp \ - qscilexeravs.cpp \ - qscilexerbash.cpp \ - qscilexerbatch.cpp \ - qscilexercmake.cpp \ - qscilexercoffeescript.cpp \ - qscilexercpp.cpp \ - qscilexercsharp.cpp \ - qscilexercss.cpp \ qscilexercustom.cpp \ - qscilexerd.cpp \ - qscilexerdiff.cpp \ - qscilexeredifact.cpp \ - qscilexerfortran.cpp \ - qscilexerfortran77.cpp \ + qscilexersql.cpp \ + qscilexerjson.cpp \ qscilexerhtml.cpp \ - qscilexeridl.cpp \ - qscilexerjava.cpp \ + qscilexerxml.cpp \ qscilexerjavascript.cpp \ - qscilexerjson.cpp \ - qscilexerlua.cpp \ - qscilexermakefile.cpp \ - qscilexermarkdown.cpp \ - qscilexermatlab.cpp \ - qscilexeroctave.cpp \ - qscilexerpascal.cpp \ - qscilexerperl.cpp \ - qscilexerpostscript.cpp \ - qscilexerpo.cpp \ - qscilexerpov.cpp \ - qscilexerproperties.cpp \ + qscilexercpp.cpp \ qscilexerpython.cpp \ - qscilexerruby.cpp \ - qscilexerspice.cpp \ - qscilexersql.cpp \ - qscilexertcl.cpp \ - qscilexertex.cpp \ - qscilexerverilog.cpp \ - qscilexervhdl.cpp \ - qscilexerxml.cpp \ - qscilexeryaml.cpp \ qscimacro.cpp \ qsciprinter.cpp \ qscistyle.cpp \ qscistyledtext.cpp \ - MacPasteboardMime.cpp \ - InputMethod.cpp \ - SciAccessibility.cpp \ + MacPasteboardMime.cpp \ + InputMethod.cpp \ SciClasses.cpp \ ListBoxQt.cpp \ PlatQt.cpp \ ScintillaQt.cpp \ - ../lexers/LexA68k.cpp \ - ../lexers/LexAbaqus.cpp \ - ../lexers/LexAda.cpp \ - ../lexers/LexAPDL.cpp \ - ../lexers/LexAsm.cpp \ - ../lexers/LexAsn1.cpp \ - ../lexers/LexASY.cpp \ - ../lexers/LexAU3.cpp \ - ../lexers/LexAVE.cpp \ - ../lexers/LexAVS.cpp \ - ../lexers/LexBaan.cpp \ - ../lexers/LexBash.cpp \ - ../lexers/LexBasic.cpp \ - ../lexers/LexBatch.cpp \ - ../lexers/LexBibTeX.cpp \ - ../lexers/LexBullant.cpp \ - ../lexers/LexCaml.cpp \ - ../lexers/LexCLW.cpp \ - ../lexers/LexCmake.cpp \ - ../lexers/LexCOBOL.cpp \ - ../lexers/LexCoffeeScript.cpp \ - ../lexers/LexConf.cpp \ - ../lexers/LexCPP.cpp \ - ../lexers/LexCrontab.cpp \ - ../lexers/LexCsound.cpp \ - ../lexers/LexCSS.cpp \ - ../lexers/LexD.cpp \ - ../lexers/LexDiff.cpp \ - ../lexers/LexDMAP.cpp \ - ../lexers/LexDMIS.cpp \ - ../lexers/LexECL.cpp \ - ../lexers/LexEDIFACT.cpp \ - ../lexers/LexEiffel.cpp \ - ../lexers/LexErlang.cpp \ - ../lexers/LexErrorList.cpp \ - ../lexers/LexEScript.cpp \ - ../lexers/LexFlagship.cpp \ - ../lexers/LexForth.cpp \ - ../lexers/LexFortran.cpp \ - ../lexers/LexGAP.cpp \ - ../lexers/LexGui4Cli.cpp \ - ../lexers/LexHaskell.cpp \ - ../lexers/LexHex.cpp \ - ../lexers/LexHTML.cpp \ - ../lexers/LexInno.cpp \ - ../lexers/LexJSON.cpp \ - ../lexers/LexKix.cpp \ - ../lexers/LexKVIrc.cpp \ - ../lexers/LexLaTeX.cpp \ - ../lexers/LexLisp.cpp \ - ../lexers/LexLout.cpp \ - ../lexers/LexLua.cpp \ - ../lexers/LexMagik.cpp \ - ../lexers/LexMake.cpp \ - ../lexers/LexMarkdown.cpp \ - ../lexers/LexMatlab.cpp \ - ../lexers/LexMetapost.cpp \ - ../lexers/LexMMIXAL.cpp \ - ../lexers/LexModula.cpp \ - ../lexers/LexMPT.cpp \ - ../lexers/LexMSSQL.cpp \ - ../lexers/LexMySQL.cpp \ - ../lexers/LexNimrod.cpp \ - ../lexers/LexNsis.cpp \ - ../lexers/LexNull.cpp \ - ../lexers/LexOpal.cpp \ - ../lexers/LexOScript.cpp \ - ../lexers/LexPascal.cpp \ - ../lexers/LexPB.cpp \ - ../lexers/LexPerl.cpp \ - ../lexers/LexPLM.cpp \ - ../lexers/LexPO.cpp \ - ../lexers/LexPOV.cpp \ - ../lexers/LexPowerPro.cpp \ - ../lexers/LexPowerShell.cpp \ - ../lexers/LexProgress.cpp \ - ../lexers/LexProps.cpp \ - ../lexers/LexPS.cpp \ - ../lexers/LexPython.cpp \ - ../lexers/LexR.cpp \ - ../lexers/LexRebol.cpp \ - ../lexers/LexRegistry.cpp \ - ../lexers/LexRuby.cpp \ - ../lexers/LexRust.cpp \ - ../lexers/LexScriptol.cpp \ - ../lexers/LexSmalltalk.cpp \ - ../lexers/LexSML.cpp \ - ../lexers/LexSorcus.cpp \ - ../lexers/LexSpecman.cpp \ - ../lexers/LexSpice.cpp \ + SciAccessibility.cpp \ ../lexers/LexSQL.cpp \ - ../lexers/LexSTTXT.cpp \ - ../lexers/LexTACL.cpp \ - ../lexers/LexTADS3.cpp \ - ../lexers/LexTAL.cpp \ - ../lexers/LexTCL.cpp \ - ../lexers/LexTCMD.cpp \ - ../lexers/LexTeX.cpp \ - ../lexers/LexTxt2tags.cpp \ - ../lexers/LexVB.cpp \ - ../lexers/LexVerilog.cpp \ - ../lexers/LexVHDL.cpp \ - ../lexers/LexVisualProlog.cpp \ - ../lexers/LexYAML.cpp \ + ../lexers/LexJSON.cpp \ + ../lexers/LexHTML.cpp \ ../lexlib/Accessor.cpp \ ../lexlib/CharacterCategory.cpp \ ../lexlib/CharacterSet.cpp \ @@ -391,20 +207,20 @@ ../src/ContractionState.cpp \ ../src/Decoration.cpp \ ../src/Document.cpp \ - ../src/EditModel.cpp \ ../src/Editor.cpp \ + ../src/EditModel.cpp \ ../src/EditView.cpp \ ../src/ExternalLexer.cpp \ ../src/Indicator.cpp \ - ../src/KeyMap.cpp \ + ../src/KeyMap.cpp \ ../src/LineMarker.cpp \ ../src/MarginView.cpp \ ../src/PerLine.cpp \ ../src/PositionCache.cpp \ - ../src/RESearch.cpp \ + ../src/RESearch.cpp \ ../src/RunStyles.cpp \ - ../src/ScintillaBase.cpp \ - ../src/Selection.cpp \ + ../src/ScintillaBase.cpp \ + ../src/Selection.cpp \ ../src/Style.cpp \ ../src/UniConversion.cpp \ ../src/ViewStyle.cpp \ sqlitebrowser-sqlitebrowser-5733cb7/libs/DB4S_PATCH_06000066400000000000000000000061361463772530400224760ustar00rootroot00000000000000--- QScintilla_gpl-2.10.8/src/Catalogue.cpp 2018-10-01 15:41:57.000000000 +0200 +++ qscintilla/src/Catalogue.cpp 2018-11-18 16:09:52.796704316 +0100 @@ -77,124 +77,10 @@ //++Autogenerated -- run scripts/LexGen.py to regenerate //**\(\tLINK_LEXER(\*);\n\) - LINK_LEXER(lmA68k); - LINK_LEXER(lmAbaqus); - LINK_LEXER(lmAda); - LINK_LEXER(lmAPDL); - LINK_LEXER(lmAs); - LINK_LEXER(lmAsm); - LINK_LEXER(lmAsn1); - LINK_LEXER(lmASY); - LINK_LEXER(lmAU3); - LINK_LEXER(lmAVE); - LINK_LEXER(lmAVS); - LINK_LEXER(lmBaan); - LINK_LEXER(lmBash); - LINK_LEXER(lmBatch); - LINK_LEXER(lmBibTeX); - LINK_LEXER(lmBlitzBasic); - LINK_LEXER(lmBullant); - LINK_LEXER(lmCaml); - LINK_LEXER(lmClw); - LINK_LEXER(lmClwNoCase); - LINK_LEXER(lmCmake); - LINK_LEXER(lmCOBOL); - LINK_LEXER(lmCoffeeScript); - LINK_LEXER(lmConf); - LINK_LEXER(lmCPP); - LINK_LEXER(lmCPPNoCase); - LINK_LEXER(lmCsound); - LINK_LEXER(lmCss); - LINK_LEXER(lmD); - LINK_LEXER(lmDiff); - LINK_LEXER(lmDMAP); - LINK_LEXER(lmDMIS); - LINK_LEXER(lmECL); - LINK_LEXER(lmEDIFACT); - LINK_LEXER(lmEiffel); - LINK_LEXER(lmEiffelkw); - LINK_LEXER(lmErlang); - LINK_LEXER(lmErrorList); - LINK_LEXER(lmESCRIPT); - LINK_LEXER(lmF77); - LINK_LEXER(lmFlagShip); - LINK_LEXER(lmForth); - LINK_LEXER(lmFortran); - LINK_LEXER(lmFreeBasic); - LINK_LEXER(lmGAP); - LINK_LEXER(lmGui4Cli); - LINK_LEXER(lmHaskell); - LINK_LEXER(lmHTML); - LINK_LEXER(lmIHex); - LINK_LEXER(lmInno); - LINK_LEXER(lmJSON); - LINK_LEXER(lmKix); - LINK_LEXER(lmKVIrc); - LINK_LEXER(lmLatex); - LINK_LEXER(lmLISP); - LINK_LEXER(lmLiterateHaskell); - LINK_LEXER(lmLot); - LINK_LEXER(lmLout); - LINK_LEXER(lmLua); - LINK_LEXER(lmMagikSF); - LINK_LEXER(lmMake); - LINK_LEXER(lmMarkdown); - LINK_LEXER(lmMatlab); - LINK_LEXER(lmMETAPOST); - LINK_LEXER(lmMMIXAL); - LINK_LEXER(lmModula); - LINK_LEXER(lmMSSQL); - LINK_LEXER(lmMySQL); - LINK_LEXER(lmNimrod); - LINK_LEXER(lmNncrontab); - LINK_LEXER(lmNsis); - LINK_LEXER(lmNull); - LINK_LEXER(lmOctave); - LINK_LEXER(lmOpal); - LINK_LEXER(lmOScript); - LINK_LEXER(lmPascal); - LINK_LEXER(lmPB); - LINK_LEXER(lmPerl); - LINK_LEXER(lmPHPSCRIPT); - LINK_LEXER(lmPLM); - LINK_LEXER(lmPO); - LINK_LEXER(lmPOV); - LINK_LEXER(lmPowerPro); - LINK_LEXER(lmPowerShell); - LINK_LEXER(lmProgress); - LINK_LEXER(lmProps); - LINK_LEXER(lmPS); - LINK_LEXER(lmPureBasic); - LINK_LEXER(lmPython); - LINK_LEXER(lmR); - LINK_LEXER(lmREBOL); - LINK_LEXER(lmRegistry); - LINK_LEXER(lmRuby); - LINK_LEXER(lmRust); - LINK_LEXER(lmScriptol); - LINK_LEXER(lmSmalltalk); - LINK_LEXER(lmSML); - LINK_LEXER(lmSorc); - LINK_LEXER(lmSpecman); - LINK_LEXER(lmSpice); - LINK_LEXER(lmSQL); - LINK_LEXER(lmSrec); - LINK_LEXER(lmSTTXT); - LINK_LEXER(lmTACL); - LINK_LEXER(lmTADS3); - LINK_LEXER(lmTAL); - LINK_LEXER(lmTCL); - LINK_LEXER(lmTCMD); - LINK_LEXER(lmTEHex); - LINK_LEXER(lmTeX); - LINK_LEXER(lmTxt2tags); - LINK_LEXER(lmVB); - LINK_LEXER(lmVBScript); - LINK_LEXER(lmVerilog); - LINK_LEXER(lmVHDL); - LINK_LEXER(lmVisualProlog); - LINK_LEXER(lmXML); - LINK_LEXER(lmYAML); + LINK_LEXER(lmSQL); + LINK_LEXER(lmJSON); + LINK_LEXER(lmHTML); + LINK_LEXER(lmXML); //--Autogenerated -- end of automatically generated section sqlitebrowser-sqlitebrowser-5733cb7/libs/json/000077500000000000000000000000001463772530400215765ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/json/CMakeLists.txt000066400000000000000000000001531463772530400243350ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.12.2) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(JSON11_HDR json.hpp ) sqlitebrowser-sqlitebrowser-5733cb7/libs/json/ChangeLog.md000066400000000000000000010171361463772530400237600ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [3.10.4](https://github.com/nlohmann/json/releases/tag/3.10.4) (2021-10-16) [Full Changelog](https://github.com/nlohmann/json/compare/v3.10.3...3.10.4) - Compiler error in output serializer due to 'incompatible initializer' [\#3081](https://github.com/nlohmann/json/issues/3081) - Strange behaviour when using std::sort on std::vector\ [\#3080](https://github.com/nlohmann/json/issues/3080) - Unhandled exception: nlohmann::detail::parse\_error [\#3078](https://github.com/nlohmann/json/issues/3078) - explicit constructor with default does not compile [\#3077](https://github.com/nlohmann/json/issues/3077) - Parse an object but get an array using GCC [\#3076](https://github.com/nlohmann/json/issues/3076) - Version 3.10.3 breaks backward-compatibility with 3.10.2 [\#3070](https://github.com/nlohmann/json/issues/3070) - Feature request, Add to\_json/from\_json to align with other to/from binary api. [\#3067](https://github.com/nlohmann/json/issues/3067) - vcpkg is out of date [\#3066](https://github.com/nlohmann/json/issues/3066) - Revert invalid fix [\#3082](https://github.com/nlohmann/json/pull/3082) ([nlohmann](https://github.com/nlohmann)) - Allow to use get with explicit constructor [\#3079](https://github.com/nlohmann/json/pull/3079) ([nlohmann](https://github.com/nlohmann)) - fix std::filesystem::path regression [\#3073](https://github.com/nlohmann/json/pull/3073) ([theodelrieu](https://github.com/theodelrieu)) - Fix Clang version [\#3040](https://github.com/nlohmann/json/pull/3040) ([nlohmann](https://github.com/nlohmann)) - Fix assertion failure for JSON\_DIAGNOSTICS [\#3037](https://github.com/nlohmann/json/pull/3037) ([carlsmedstad](https://github.com/carlsmedstad)) - meta: fix is\_compatible/constructible traits [\#3020](https://github.com/nlohmann/json/pull/3020) ([theodelrieu](https://github.com/theodelrieu)) - Set parent pointers for values inserted via update\(\) \(fixes \#3007\). [\#3008](https://github.com/nlohmann/json/pull/3008) ([AnthonyVH](https://github.com/AnthonyVH)) - Allow allocators for output\_vector\_adapter [\#2989](https://github.com/nlohmann/json/pull/2989) ([nlohmann](https://github.com/nlohmann)) - Re-add Clang 12 [\#2986](https://github.com/nlohmann/json/pull/2986) ([nlohmann](https://github.com/nlohmann)) - Use new Docker image [\#2981](https://github.com/nlohmann/json/pull/2981) ([nlohmann](https://github.com/nlohmann)) - Fix -Wunused warnings on JSON\_DIAGNOSTICS [\#2976](https://github.com/nlohmann/json/pull/2976) ([gcerretani](https://github.com/gcerretani)) - Update docset generation script [\#2967](https://github.com/nlohmann/json/pull/2967) ([nlohmann](https://github.com/nlohmann)) ## [v3.10.3](https://github.com/nlohmann/json/releases/tag/v3.10.3) (2021-10-08) [Full Changelog](https://github.com/nlohmann/json/compare/v3.10.2...v3.10.3) - Parsing an emtpy string returns a string with size 1 instead of expected 0 [\#3057](https://github.com/nlohmann/json/issues/3057) - Linking error "duplicate symbol: std::type\_info::operator==" on static build with MinGW [\#3042](https://github.com/nlohmann/json/issues/3042) - Yet another assertion failure when inserting into arrays with JSON\_DIAGNOSTICS set [\#3032](https://github.com/nlohmann/json/issues/3032) - accept and parse function not work well with a pure number string [\#3029](https://github.com/nlohmann/json/issues/3029) - push\_back doesn't work for serializing containers [\#3027](https://github.com/nlohmann/json/issues/3027) - Strange behaviour when creating array with single element [\#3025](https://github.com/nlohmann/json/issues/3025) - Input ordered\_json doesn't work [\#3023](https://github.com/nlohmann/json/issues/3023) - Issue iterating through 'items' [\#3021](https://github.com/nlohmann/json/issues/3021) - Cannot spell the namespace right [\#3015](https://github.com/nlohmann/json/issues/3015) - JSON Parse error when reading json object from file [\#3011](https://github.com/nlohmann/json/issues/3011) - Parent pointer not properly set when using update\(\) [\#3007](https://github.com/nlohmann/json/issues/3007) - Overwriting terminated null character [\#3001](https://github.com/nlohmann/json/issues/3001) - 'operator =' is ambiguous on VS2017 [\#2997](https://github.com/nlohmann/json/issues/2997) - JSON Patch for Array Elements [\#2994](https://github.com/nlohmann/json/issues/2994) - JSON Parse throwing error [\#2983](https://github.com/nlohmann/json/issues/2983) - to\_{binary format} does not provide a mechanism for specifying a custom allocator for the returned type. [\#2982](https://github.com/nlohmann/json/issues/2982) - 3.10.1 zip json.hpp has version number 3.10.0 instead of 3.10.1 [\#2973](https://github.com/nlohmann/json/issues/2973) - Assertion failure when serializing array with JSON\_DIAGNOSTICS set [\#2926](https://github.com/nlohmann/json/issues/2926) ## [v3.10.2](https://github.com/nlohmann/json/releases/tag/v3.10.2) (2021-08-26) [Full Changelog](https://github.com/nlohmann/json/compare/v3.10.1...v3.10.2) - Annoying -Wundef on new JSON\_DIAGNOSTICS macro [\#2975](https://github.com/nlohmann/json/issues/2975) - += issue with multiple redirection. [\#2970](https://github.com/nlohmann/json/issues/2970) - "incomplete type ‘nlohmann::detail::wide\_string\_input\_helper" compilation error [\#2969](https://github.com/nlohmann/json/issues/2969) ## [v3.10.1](https://github.com/nlohmann/json/releases/tag/v3.10.1) (2021-08-24) [Full Changelog](https://github.com/nlohmann/json/compare/v3.10.0...v3.10.1) - JSON\_DIAGNOSTICS assertion for ordered\_json [\#2962](https://github.com/nlohmann/json/issues/2962) - Inserting in unordered json using a pointer retains the leading slash [\#2958](https://github.com/nlohmann/json/issues/2958) - Test \#9: test-cbor test case sample.json fails in debug mode - Stack overflow [\#2955](https://github.com/nlohmann/json/issues/2955) - 3.10.0 broke at least the Bear project [\#2953](https://github.com/nlohmann/json/issues/2953) - 2 tests fail in 3.10.0: cmake\_fetch\_content\_configure, cmake\_fetch\_content\_build [\#2951](https://github.com/nlohmann/json/issues/2951) - ctest \(58+60,/67 cmake\_import\_configure\) fails when build with -D JSON\_Install:BOOL=OFF because of missing nlohmann\_jsonTargets.cmake [\#2946](https://github.com/nlohmann/json/issues/2946) - Document vcpkg usage [\#2944](https://github.com/nlohmann/json/issues/2944) - Linker error LNK2005 when compiling \(x64\) json-3.10.0.zip with Visual Studio 2019 16.11.1 [\#2941](https://github.com/nlohmann/json/issues/2941) - Move Travis jobs to travis-ci.com [\#2938](https://github.com/nlohmann/json/issues/2938) - Fixed typo in docs/api/basic\_json/parse.md [\#2968](https://github.com/nlohmann/json/pull/2968) ([mb0202](https://github.com/mb0202)) - Add link to Homebrew package [\#2966](https://github.com/nlohmann/json/pull/2966) ([nlohmann](https://github.com/nlohmann)) - Fix parent update for diagnostics with ordered\_json [\#2963](https://github.com/nlohmann/json/pull/2963) ([nlohmann](https://github.com/nlohmann)) - Set stack size for some unit tests when using MSVC [\#2961](https://github.com/nlohmann/json/pull/2961) ([nlohmann](https://github.com/nlohmann)) - Add regression test [\#2960](https://github.com/nlohmann/json/pull/2960) ([nlohmann](https://github.com/nlohmann)) - Update Travis badge [\#2959](https://github.com/nlohmann/json/pull/2959) ([nlohmann](https://github.com/nlohmann)) - Fix some extra ";" clang warnings [\#2957](https://github.com/nlohmann/json/pull/2957) ([Hallot](https://github.com/Hallot)) - Add documentation for integration via vcpkg [\#2954](https://github.com/nlohmann/json/pull/2954) ([nlohmann](https://github.com/nlohmann)) - Avoid duplicate AppVeyor builds [\#2952](https://github.com/nlohmann/json/pull/2952) ([nlohmann](https://github.com/nlohmann)) - 🚨 fix gdb\_pretty\_printer failure on basic types [\#2950](https://github.com/nlohmann/json/pull/2950) ([senyai](https://github.com/senyai)) - Add header to use value\_t [\#2948](https://github.com/nlohmann/json/pull/2948) ([nlohmann](https://github.com/nlohmann)) - Skip some tests if JSON\_Install is not set [\#2947](https://github.com/nlohmann/json/pull/2947) ([nlohmann](https://github.com/nlohmann)) - Remove outdated json\_unit test binary [\#2945](https://github.com/nlohmann/json/pull/2945) ([nlohmann](https://github.com/nlohmann)) - Updating the Homebrew Command [\#2943](https://github.com/nlohmann/json/pull/2943) ([amirmasoudabdol](https://github.com/amirmasoudabdol)) ## [v3.10.0](https://github.com/nlohmann/json/releases/tag/v3.10.0) (2021-08-17) [Full Changelog](https://github.com/nlohmann/json/compare/v3.9.1...v3.10.0) - Latest version 3.9.1 uses throw instead of JSON\_THROW in the amalgamated json.hpp file [\#2934](https://github.com/nlohmann/json/issues/2934) - Copy to a variable inside a Structure [\#2933](https://github.com/nlohmann/json/issues/2933) - warning C4068: unknown pragma 'GCC' on MSVC/cl [\#2924](https://github.com/nlohmann/json/issues/2924) - Errors during ninja test [\#2918](https://github.com/nlohmann/json/issues/2918) - compiler warning: "not return a value" [\#2917](https://github.com/nlohmann/json/issues/2917) - Comparison floating points causes warning [\#2909](https://github.com/nlohmann/json/issues/2909) - Why can't I have std::vector\ testList? [\#2900](https://github.com/nlohmann/json/issues/2900) - \[json.hpp\] from releases doesnt work [\#2897](https://github.com/nlohmann/json/issues/2897) - g++ \(11\) -Wuseless-cast gives lots of warnings [\#2893](https://github.com/nlohmann/json/issues/2893) - Cannot serialize and immediatly deserialize json to/from bson [\#2892](https://github.com/nlohmann/json/issues/2892) - Floating-point precision conversion error [\#2876](https://github.com/nlohmann/json/issues/2876) - How to avoid escaping for an already escaped string in .dump\(\) [\#2870](https://github.com/nlohmann/json/issues/2870) - can't parse std::vector\ [\#2869](https://github.com/nlohmann/json/issues/2869) - ASAN detects memory leaks [\#2865](https://github.com/nlohmann/json/issues/2865) - Binary subtype field cannot represent all CBOR tags [\#2863](https://github.com/nlohmann/json/issues/2863) - string literals possibly being parsed as another type due to the presence of only digits and full-stops [\#2852](https://github.com/nlohmann/json/issues/2852) - json::parse\(\) works only with absolute paths [\#2851](https://github.com/nlohmann/json/issues/2851) - Compiler Warnings on Raspberry Pi OS [\#2850](https://github.com/nlohmann/json/issues/2850) - Braced initialization and aggregate initialization behavior is different for `json::array()` function call. [\#2848](https://github.com/nlohmann/json/issues/2848) - 3.9.1: test suite is failing [\#2845](https://github.com/nlohmann/json/issues/2845) - Documentation for macro JSON\_NO\_IO is missing [\#2842](https://github.com/nlohmann/json/issues/2842) - Assertion failure when inserting into arrays with JSON\_DIAGNOSTICS set [\#2838](https://github.com/nlohmann/json/issues/2838) - HELP! There is a memory leak in the code?! [\#2837](https://github.com/nlohmann/json/issues/2837) - Elegant conversion of a 2-D-json array to a standard C++ array [\#2805](https://github.com/nlohmann/json/issues/2805) - Swift Package Manager support [\#2802](https://github.com/nlohmann/json/issues/2802) - Referencing a subkey which doesn't exist gives crash [\#2797](https://github.com/nlohmann/json/issues/2797) - Failed benchmark due to renamed branch [\#2796](https://github.com/nlohmann/json/issues/2796) - Build Errors with VS 2019 and json Version 3.9.1 when attempting to replicate SAX Example [\#2782](https://github.com/nlohmann/json/issues/2782) - Value with spaces cannot be parsed [\#2781](https://github.com/nlohmann/json/issues/2781) - \[Question\] CBOR rfc support. [\#2779](https://github.com/nlohmann/json/issues/2779) - Using JSON.hpp header file in Visual Studio 2013 \(C++ Project\) [\#2775](https://github.com/nlohmann/json/issues/2775) - compilation error on clang-8 + C++17 [\#2759](https://github.com/nlohmann/json/issues/2759) - Undefined symbol EOF [\#2755](https://github.com/nlohmann/json/issues/2755) - Parsing a string into json object behaves differently under g++ and MinGW compilers. [\#2746](https://github.com/nlohmann/json/issues/2746) - big git history size [\#2742](https://github.com/nlohmann/json/issues/2742) - How to get reference of std::vector\ [\#2735](https://github.com/nlohmann/json/issues/2735) - CMake failure in VS2019 Community [\#2734](https://github.com/nlohmann/json/issues/2734) - Possibility to use with custom c++ version to use in intel sgx enclaves [\#2730](https://github.com/nlohmann/json/issues/2730) - Possibility to use without the dependency to file io and streams to use in intel sgx enclaves [\#2728](https://github.com/nlohmann/json/issues/2728) - error C2784& error C2839... in my visual studio 2015 compiler [\#2726](https://github.com/nlohmann/json/issues/2726) - `-fno-expection` not respected anymore in 3.9.1 [\#2725](https://github.com/nlohmann/json/issues/2725) - When exceptions disabled with JSON\_NOEXCEPTION, lib just aborts without any message [\#2724](https://github.com/nlohmann/json/issues/2724) - Critical error detected c0000374 on windows10 msvc 2019 16.8.5 [\#2710](https://github.com/nlohmann/json/issues/2710) - unused parameter error/warning [\#2706](https://github.com/nlohmann/json/issues/2706) - How to store data into a Map from json file [\#2691](https://github.com/nlohmann/json/issues/2691) - Tests do not compile with pre-release glibc [\#2686](https://github.com/nlohmann/json/issues/2686) - compile errors .... chromium-style [\#2680](https://github.com/nlohmann/json/issues/2680) - .dump\(\) not allowing compact form [\#2678](https://github.com/nlohmann/json/issues/2678) - error: no matching function for call to ‘nlohmann::basic\_json\<\>::value\(int, std::set\&\)’ [\#2671](https://github.com/nlohmann/json/issues/2671) - Compiler warning: unused parameter [\#2668](https://github.com/nlohmann/json/issues/2668) - Deserializing to a struct as shown on the project homepage throws compile time errors [\#2665](https://github.com/nlohmann/json/issues/2665) - Unable to compile on MSVC 2019 with SDL checking enabled: This function or variable may be unsafe [\#2664](https://github.com/nlohmann/json/issues/2664) - terminating with uncaught exception of type nlohmann::detail::type\_error: \[json.exception.type\_error.302\] type must be array, but is object [\#2661](https://github.com/nlohmann/json/issues/2661) - unused-parameter on OSX when Diagnostics is off [\#2658](https://github.com/nlohmann/json/issues/2658) - std::pair wrong serialization [\#2655](https://github.com/nlohmann/json/issues/2655) - The result of json is\_number\_integer\(\) function is wrong when read a json file [\#2653](https://github.com/nlohmann/json/issues/2653) - 2 backslash cause problem [\#2652](https://github.com/nlohmann/json/issues/2652) - No support for using an external/system copy of Hedley [\#2651](https://github.com/nlohmann/json/issues/2651) - error: incomplete type 'qfloat16' used in type trait expression [\#2650](https://github.com/nlohmann/json/issues/2650) - Unused variable in exception class when not using improved diagnostics [\#2646](https://github.com/nlohmann/json/issues/2646) - I am trying to do this - converting from wstring works incorrectly! [\#2642](https://github.com/nlohmann/json/issues/2642) - Exception 207 On ARM Processor During Literal String Parsing [\#2634](https://github.com/nlohmann/json/issues/2634) - double free or corruption \(!prev\) error on Json push\_back and write [\#2632](https://github.com/nlohmann/json/issues/2632) - nlohmann::detail::parse\_error: syntax error while parsing CBOR string: expected length specification \(0x60-0x7B\) or indefinite string type \(0x7F\) [\#2629](https://github.com/nlohmann/json/issues/2629) - please allow disabling implicit conversions in non-single-file use [\#2621](https://github.com/nlohmann/json/issues/2621) - Preserve decimal formatting [\#2618](https://github.com/nlohmann/json/issues/2618) - Visual Studio Visual Assist code issues reported by VA code inspection of file json.hpp [\#2615](https://github.com/nlohmann/json/issues/2615) - Missing get function and no viable overloaded '=' on mac [\#2610](https://github.com/nlohmann/json/issues/2610) - corruption when parse from string [\#2603](https://github.com/nlohmann/json/issues/2603) - Parse from byte-vector results in compile error [\#2602](https://github.com/nlohmann/json/issues/2602) - Memory leak when working on ARM Linux [\#2601](https://github.com/nlohmann/json/issues/2601) - Unhandled exception in test-cbor.exe Stack overflow when debugging project with Visual Studio 2019 16.7.7 compiled with c++17 or c++latest [\#2598](https://github.com/nlohmann/json/issues/2598) - Error in download\_test\_data.vcxproj when compiling with Visual Studio 2019 16.7.7 Professional msbuild on Windows 10 2004 Professional [\#2594](https://github.com/nlohmann/json/issues/2594) - Warnings C4715 and C4127 when building json-3.9.1 with Visual Studio 2019 16.7.7 [\#2592](https://github.com/nlohmann/json/issues/2592) - I tried some change to dump\(\) for \[1,2,3...\] [\#2584](https://github.com/nlohmann/json/issues/2584) - try/catch block does not catch parsing error [\#2579](https://github.com/nlohmann/json/issues/2579) - Serializing uint64\_t is broken for large values [\#2578](https://github.com/nlohmann/json/issues/2578) - deserializing arrays should be part of the library [\#2575](https://github.com/nlohmann/json/issues/2575) - Deserialization to std::array with non-default constructable types fails [\#2574](https://github.com/nlohmann/json/issues/2574) - Compilation error when trying to use same type for number\_integer\_t and number\_unsigned\_t in basic\_json template specification. [\#2573](https://github.com/nlohmann/json/issues/2573) - compiler error: directive output may be truncated writing between 2 and 8 bytes [\#2572](https://github.com/nlohmann/json/issues/2572) - Incorrect convert map to json when key cannot construct an string i.e. int [\#2564](https://github.com/nlohmann/json/issues/2564) - no matching function for call to ‘nlohmann::basic\_json\<\>::basic\_json\(\\)’ [\#2559](https://github.com/nlohmann/json/issues/2559) - type\_error factory creates a dangling pointer \(in VisualStudio 2019\) [\#2535](https://github.com/nlohmann/json/issues/2535) - Cannot assign from ordered\_json vector\ to value in not ordered json [\#2528](https://github.com/nlohmann/json/issues/2528) - Qt6: Break changes [\#2519](https://github.com/nlohmann/json/issues/2519) - valgrind memcheck Illegal instruction when use nlohmann::json::parse [\#2518](https://github.com/nlohmann/json/issues/2518) - Buffer overflow [\#2515](https://github.com/nlohmann/json/issues/2515) - Including CTest in the top-level CMakeLists.txt sets BUILD\_TESTING=ON for parent projects [\#2513](https://github.com/nlohmann/json/issues/2513) - Compilation error when using NLOHMANN\_JSON\_SERIALIZE\_ENUM ordered\_json on libc++ [\#2491](https://github.com/nlohmann/json/issues/2491) - Missing "void insert\( InputIt first, InputIt last \);" overload in nlohmann::ordered\_map [\#2490](https://github.com/nlohmann/json/issues/2490) - Could not find a package configuration file provided by "nlohmann\_json" [\#2482](https://github.com/nlohmann/json/issues/2482) - json becomes empty for unknown reason [\#2470](https://github.com/nlohmann/json/issues/2470) - Using std::wstring as StringType fails compiling [\#2459](https://github.com/nlohmann/json/issues/2459) - Sample code in GIF slide outdated \(cannot use emplace\(\) with array\) [\#2457](https://github.com/nlohmann/json/issues/2457) - from\_json\ is treated as an array on latest MSVC [\#2453](https://github.com/nlohmann/json/issues/2453) - MemorySanitizer: use-of-uninitialized-value [\#2449](https://github.com/nlohmann/json/issues/2449) - I need help [\#2441](https://github.com/nlohmann/json/issues/2441) - type conversion failing with clang ext\_vector\_type [\#2436](https://github.com/nlohmann/json/issues/2436) - json::parse\(\) can't be resolved under specific circumstances [\#2427](https://github.com/nlohmann/json/issues/2427) - from\_\*\(ptr, len\) deprecation [\#2426](https://github.com/nlohmann/json/issues/2426) - Error ONLY in release mode [\#2425](https://github.com/nlohmann/json/issues/2425) - "Custom data source" exemple make no sense [\#2423](https://github.com/nlohmann/json/issues/2423) - Compile errors [\#2421](https://github.com/nlohmann/json/issues/2421) - Refuses to compile in project [\#2419](https://github.com/nlohmann/json/issues/2419) - Compilation failure of tests with C++20 standard \(caused by change of u8 literals\) [\#2413](https://github.com/nlohmann/json/issues/2413) - No matching function for call to 'input\_adapter' under Xcode of with nlohmann version 3.9.1 [\#2412](https://github.com/nlohmann/json/issues/2412) - Git tags are not valid semvers [\#2409](https://github.com/nlohmann/json/issues/2409) - after dump, stderr output disappear [\#2403](https://github.com/nlohmann/json/issues/2403) - Using custom string. [\#2398](https://github.com/nlohmann/json/issues/2398) - value\(\) throws unhandled exception for partially specified json object [\#2393](https://github.com/nlohmann/json/issues/2393) - assertion on runtime causes program to stop when accessing const json with missing key [\#2392](https://github.com/nlohmann/json/issues/2392) - Usage with -fno-elide-constructors causes dump\(\) output to be array of `null`s [\#2387](https://github.com/nlohmann/json/issues/2387) - Build fails with clang-cl due to override of CMAKE\_CXX\_COMPILER\(?\) [\#2384](https://github.com/nlohmann/json/issues/2384) - std::optional not working with primitive types [\#2383](https://github.com/nlohmann/json/issues/2383) - Unexpected array when initializing a json const& on gcc 4.8.5 using uniform syntax [\#2370](https://github.com/nlohmann/json/issues/2370) - setprecision support [\#2362](https://github.com/nlohmann/json/issues/2362) - json::parse\(allow\_exceptions = false\) documentation is misleading. [\#2360](https://github.com/nlohmann/json/issues/2360) - std::begin and std::end usage without specifying std namespace [\#2359](https://github.com/nlohmann/json/issues/2359) - Custom object conversion to json hangs in background thread [\#2358](https://github.com/nlohmann/json/issues/2358) - Add support of nullable fields to NLOHMANN\_DEFINE\_TYPE\_NON\_INTRUSIVE and NLOHMANN\_DEFINE\_TYPE\_INTRUSIVE [\#2356](https://github.com/nlohmann/json/issues/2356) - the portfile for the vcpkg is not working. [\#2351](https://github.com/nlohmann/json/issues/2351) - Compiler warns of implicit fallthrough when defining preprocessor macro NDEBUG [\#2348](https://github.com/nlohmann/json/issues/2348) - Compile error on Intel compiler running in Windows [\#2346](https://github.com/nlohmann/json/issues/2346) - Build error caused by overwriting CMAKE\_CXX\_COMPILER [\#2343](https://github.com/nlohmann/json/issues/2343) - Error: an attribute list cannot appear here JSON\_HEDLEY\_DEPRECATED\_FOR [\#2342](https://github.com/nlohmann/json/issues/2342) - compiler warning [\#2341](https://github.com/nlohmann/json/issues/2341) - 3.9.0: tests make build non-reproducible [\#2324](https://github.com/nlohmann/json/issues/2324) - Initialization different between gcc/clang [\#2311](https://github.com/nlohmann/json/issues/2311) - Attempt to `get()` a numeric value as a type which cannot represent it should throw [\#2310](https://github.com/nlohmann/json/issues/2310) - Surprising behaviour with overloaded operators [\#2256](https://github.com/nlohmann/json/issues/2256) - ADL issue in input\_adapter [\#2248](https://github.com/nlohmann/json/issues/2248) - Output adapters should be templated. [\#2172](https://github.com/nlohmann/json/issues/2172) - error when using nlohmann::json, std::function and std::bind [\#2147](https://github.com/nlohmann/json/issues/2147) - Remove undefined behavior for const operator\[\] [\#2111](https://github.com/nlohmann/json/issues/2111) - json\({}\) gives null instead of empty object with GCC and -std=c++17 [\#2046](https://github.com/nlohmann/json/issues/2046) - GDB pretty printing support [\#1952](https://github.com/nlohmann/json/issues/1952) - Always compile tests with all warnings enabled and error out on warnings [\#1798](https://github.com/nlohmann/json/issues/1798) - Fixes Cppcheck warnings [\#1759](https://github.com/nlohmann/json/issues/1759) - How to get position info or parser context with custom from\_json\(\) that may throw exceptions? [\#1508](https://github.com/nlohmann/json/issues/1508) - Suggestion to improve value\(\) accessors with respect to move semantics [\#1275](https://github.com/nlohmann/json/issues/1275) - Add Key name to Exception [\#932](https://github.com/nlohmann/json/issues/932) - Overwork warning flags [\#2936](https://github.com/nlohmann/json/pull/2936) ([nlohmann](https://github.com/nlohmann)) - Treat MSVC warnings as errors [\#2930](https://github.com/nlohmann/json/pull/2930) ([nlohmann](https://github.com/nlohmann)) - All: fix warnings when compiling with -Wswitch-enum [\#2927](https://github.com/nlohmann/json/pull/2927) ([fhuberts](https://github.com/fhuberts)) - Guard GCC pragmas [\#2925](https://github.com/nlohmann/json/pull/2925) ([nlohmann](https://github.com/nlohmann)) - Supress -Wfloat-equal on intended float comparisions [\#2911](https://github.com/nlohmann/json/pull/2911) ([Finkman](https://github.com/Finkman)) - Fix binary subtypes [\#2908](https://github.com/nlohmann/json/pull/2908) ([nlohmann](https://github.com/nlohmann)) - Fix useless-cast warnings [\#2902](https://github.com/nlohmann/json/pull/2902) ([nlohmann](https://github.com/nlohmann)) - Add regression test [\#2898](https://github.com/nlohmann/json/pull/2898) ([nlohmann](https://github.com/nlohmann)) - Refactor Unicode tests [\#2889](https://github.com/nlohmann/json/pull/2889) ([nlohmann](https://github.com/nlohmann)) - CMake cleanup [\#2885](https://github.com/nlohmann/json/pull/2885) ([nlohmann](https://github.com/nlohmann)) - Avoid string in case of empty CBOR objects [\#2879](https://github.com/nlohmann/json/pull/2879) ([nlohmann](https://github.com/nlohmann)) - Suppress C4127 warning in unit-json\_pointer.cpp [\#2875](https://github.com/nlohmann/json/pull/2875) ([nlohmann](https://github.com/nlohmann)) - Fix truncation warning [\#2874](https://github.com/nlohmann/json/pull/2874) ([nlohmann](https://github.com/nlohmann)) - Fix memory leak in to\_json [\#2872](https://github.com/nlohmann/json/pull/2872) ([nlohmann](https://github.com/nlohmann)) - Fix assertion failure in diagnostics [\#2866](https://github.com/nlohmann/json/pull/2866) ([nlohmann](https://github.com/nlohmann)) - Update documentation [\#2861](https://github.com/nlohmann/json/pull/2861) ([nlohmann](https://github.com/nlohmann)) - Consistency with `using` in README.md [\#2826](https://github.com/nlohmann/json/pull/2826) ([justanotheranonymoususer](https://github.com/justanotheranonymoususer)) - Properly constrain the basic\_json conversion operator [\#2825](https://github.com/nlohmann/json/pull/2825) ([ldionne](https://github.com/ldionne)) - Fix CI [\#2817](https://github.com/nlohmann/json/pull/2817) ([nlohmann](https://github.com/nlohmann)) - Specified git branch for google benchmark fetch in benchmark test [\#2795](https://github.com/nlohmann/json/pull/2795) ([grafail](https://github.com/grafail)) - Add C++ standards to macOS matrix [\#2790](https://github.com/nlohmann/json/pull/2790) ([nlohmann](https://github.com/nlohmann)) - Update URLs to HTTPS [\#2789](https://github.com/nlohmann/json/pull/2789) ([TotalCaesar659](https://github.com/TotalCaesar659)) - Link to Conan Center package added [\#2771](https://github.com/nlohmann/json/pull/2771) ([offa](https://github.com/offa)) - Keep consistent formatting [\#2770](https://github.com/nlohmann/json/pull/2770) ([jasmcaus](https://github.com/jasmcaus)) - Add a cmake option to use SYSTEM in target\_include\_directories [\#2762](https://github.com/nlohmann/json/pull/2762) ([jpl-mac](https://github.com/jpl-mac)) - replace EOF with std::char\_traits\::eof\(\) [\#2756](https://github.com/nlohmann/json/pull/2756) ([nlohmann](https://github.com/nlohmann)) - Fix typo in README [\#2754](https://github.com/nlohmann/json/pull/2754) ([mortenfyhn](https://github.com/mortenfyhn)) - Update documentation [\#2749](https://github.com/nlohmann/json/pull/2749) ([nlohmann](https://github.com/nlohmann)) - Add documentation for numbers [\#2747](https://github.com/nlohmann/json/pull/2747) ([nlohmann](https://github.com/nlohmann)) - Use Clang 12 in CI [\#2737](https://github.com/nlohmann/json/pull/2737) ([nlohmann](https://github.com/nlohmann)) - Fixes \#2730 [\#2731](https://github.com/nlohmann/json/pull/2731) ([theShmoo](https://github.com/theShmoo)) - Possibility to use without the dependency to file io and streams to use in intel sgx enclaves [\#2729](https://github.com/nlohmann/json/pull/2729) ([theShmoo](https://github.com/theShmoo)) - Update json.hpp [\#2707](https://github.com/nlohmann/json/pull/2707) ([raduteo](https://github.com/raduteo)) - pkg-config.pc.in: Don't concatenate paths [\#2690](https://github.com/nlohmann/json/pull/2690) ([doronbehar](https://github.com/doronbehar)) - add more CI steps [\#2689](https://github.com/nlohmann/json/pull/2689) ([nlohmann](https://github.com/nlohmann)) - Update doctest from 2.4.4 to 2.4.6 \(fixes \#2686\) [\#2687](https://github.com/nlohmann/json/pull/2687) ([musicinmybrain](https://github.com/musicinmybrain)) - License fix [\#2683](https://github.com/nlohmann/json/pull/2683) ([nlohmann](https://github.com/nlohmann)) - Update parse\_exceptions.md - correct `json::exception::parse_error` [\#2679](https://github.com/nlohmann/json/pull/2679) ([frasermarlow](https://github.com/frasermarlow)) - Remove HEDLEY annotation from exception::what\(\) [\#2673](https://github.com/nlohmann/json/pull/2673) ([remyjette](https://github.com/remyjette)) - Fix amount of entries in the json object [\#2659](https://github.com/nlohmann/json/pull/2659) ([abbaswasim](https://github.com/abbaswasim)) - Fix missing 1.78 in example in README.md [\#2625](https://github.com/nlohmann/json/pull/2625) ([wawiesel](https://github.com/wawiesel)) - Add GDB pretty printer [\#2607](https://github.com/nlohmann/json/pull/2607) ([nlohmann](https://github.com/nlohmann)) - readme: fix tilde character display [\#2582](https://github.com/nlohmann/json/pull/2582) ([bl-ue](https://github.com/bl-ue)) - Add support for deserialization of STL containers of non-default constructable types \(fixes \#2574\). [\#2576](https://github.com/nlohmann/json/pull/2576) ([AnthonyVH](https://github.com/AnthonyVH)) - Better diagnostics [\#2562](https://github.com/nlohmann/json/pull/2562) ([nlohmann](https://github.com/nlohmann)) - CI targets [\#2561](https://github.com/nlohmann/json/pull/2561) ([nlohmann](https://github.com/nlohmann)) - Add switch to skip non-reproducible tests. [\#2560](https://github.com/nlohmann/json/pull/2560) ([nlohmann](https://github.com/nlohmann)) - Fix compilation of input\_adapter\(container\) in edge cases [\#2553](https://github.com/nlohmann/json/pull/2553) ([jasujm](https://github.com/jasujm)) - Allow parsing from std::byte containers [\#2550](https://github.com/nlohmann/json/pull/2550) ([nlohmann](https://github.com/nlohmann)) - Travis doesn't run any tests in C++17 mode [\#2540](https://github.com/nlohmann/json/pull/2540) ([karzhenkov](https://github.com/karzhenkov)) - Doctest is updated to v2.4.3 [\#2538](https://github.com/nlohmann/json/pull/2538) ([YarikTH](https://github.com/YarikTH)) - Fix warnings [\#2537](https://github.com/nlohmann/json/pull/2537) ([nlohmann](https://github.com/nlohmann)) - Fix a shadowing warning [\#2536](https://github.com/nlohmann/json/pull/2536) ([nlohmann](https://github.com/nlohmann)) - Clarify license of is\_complete\_type implementation [\#2534](https://github.com/nlohmann/json/pull/2534) ([nlohmann](https://github.com/nlohmann)) - Do not unconditionally redefine C++14 constructs [\#2533](https://github.com/nlohmann/json/pull/2533) ([nlohmann](https://github.com/nlohmann)) - Doctest is updated to v2.4.1 [\#2525](https://github.com/nlohmann/json/pull/2525) ([YarikTH](https://github.com/YarikTH)) - Add MAIN\_PROJECT check for test and install options [\#2514](https://github.com/nlohmann/json/pull/2514) ([globberwops](https://github.com/globberwops)) - Ranged insert test section is added in unit-ordered\_json.cpp [\#2512](https://github.com/nlohmann/json/pull/2512) ([YarikTH](https://github.com/YarikTH)) - Add asserts to suppress C28020 [\#2447](https://github.com/nlohmann/json/pull/2447) ([jbzdarkid](https://github.com/jbzdarkid)) - Change argument name "subtype" in byte\_container\_with\_subtype [\#2444](https://github.com/nlohmann/json/pull/2444) ([linev](https://github.com/linev)) - 📠add CPM.Cmake example [\#2406](https://github.com/nlohmann/json/pull/2406) ([leozz37](https://github.com/leozz37)) - Fix move constructor of json\_ref [\#2405](https://github.com/nlohmann/json/pull/2405) ([karzhenkov](https://github.com/karzhenkov)) - Properly select "Release" build for Travis [\#2375](https://github.com/nlohmann/json/pull/2375) ([karzhenkov](https://github.com/karzhenkov)) - Update Hedley [\#2367](https://github.com/nlohmann/json/pull/2367) ([nlohmann](https://github.com/nlohmann)) - Fix and extend documentation of discarded values [\#2363](https://github.com/nlohmann/json/pull/2363) ([nlohmann](https://github.com/nlohmann)) - Fix typos in documentation [\#2354](https://github.com/nlohmann/json/pull/2354) ([rbuch](https://github.com/rbuch)) - Remove "\#define private public" from tests [\#2352](https://github.com/nlohmann/json/pull/2352) ([nlohmann](https://github.com/nlohmann)) - Remove -Wimplicit-fallthrough warning [\#2349](https://github.com/nlohmann/json/pull/2349) ([nlohmann](https://github.com/nlohmann)) - Fix code to work without exceptions [\#2347](https://github.com/nlohmann/json/pull/2347) ([nlohmann](https://github.com/nlohmann)) - fix cmake script overwriting compiler path [\#2344](https://github.com/nlohmann/json/pull/2344) ([ongjunjie](https://github.com/ongjunjie)) ## [v3.9.1](https://github.com/nlohmann/json/releases/tag/v3.9.1) (2020-08-06) [Full Changelog](https://github.com/nlohmann/json/compare/v3.9.0...v3.9.1) - Can't parse not formatted JSON. [\#2340](https://github.com/nlohmann/json/issues/2340) - parse returns desired array contained in array when JSON text begins with square bracket on gcc 7.5.0 [\#2339](https://github.com/nlohmann/json/issues/2339) - Unexpected deserialization difference between Mac and Linux [\#2338](https://github.com/nlohmann/json/issues/2338) - Reading ordered\_json from file causes compile error [\#2331](https://github.com/nlohmann/json/issues/2331) - ignore\_comment=true fails on multiple consecutive lines starting with comments [\#2330](https://github.com/nlohmann/json/issues/2330) - Update documentation about Homebrew installation and CMake integration - Homebrew [\#2326](https://github.com/nlohmann/json/issues/2326) - Chinese character initialize error [\#2325](https://github.com/nlohmann/json/issues/2325) - json.update and vector\does not work with ordered\_json [\#2315](https://github.com/nlohmann/json/issues/2315) - Ambiguous call to overloaded function [\#2210](https://github.com/nlohmann/json/issues/2210) - Fix fallthrough warning [\#2333](https://github.com/nlohmann/json/pull/2333) ([nlohmann](https://github.com/nlohmann)) - Fix lexer to properly cope with repeated comments [\#2332](https://github.com/nlohmann/json/pull/2332) ([nlohmann](https://github.com/nlohmann)) - Fix name of Homebrew formula in documentation [\#2327](https://github.com/nlohmann/json/pull/2327) ([nlohmann](https://github.com/nlohmann)) - fix typo [\#2320](https://github.com/nlohmann/json/pull/2320) ([wx257osn2](https://github.com/wx257osn2)) - Fix a bug due to missing overloads in ordered\_map container [\#2319](https://github.com/nlohmann/json/pull/2319) ([nlohmann](https://github.com/nlohmann)) - cmake: install pkg-config file relative to current\_binary\_dir [\#2318](https://github.com/nlohmann/json/pull/2318) ([eli-schwartz](https://github.com/eli-schwartz)) - Fixed installation of pkg-config file on other than Ubuntu [\#2314](https://github.com/nlohmann/json/pull/2314) ([xvitaly](https://github.com/xvitaly)) ## [v3.9.0](https://github.com/nlohmann/json/releases/tag/v3.9.0) (2020-07-27) [Full Changelog](https://github.com/nlohmann/json/compare/v3.8.0...v3.9.0) - Unknown Type Name clang error when using NLOHMANN\_DEFINE\_TYPE\_NON\_INTRUSIVE [\#2313](https://github.com/nlohmann/json/issues/2313) - Clang 10.0 / GCC 10.1 warnings on disabled exceptions [\#2304](https://github.com/nlohmann/json/issues/2304) - Application stalls indefinitely with message byte size 10 [\#2293](https://github.com/nlohmann/json/issues/2293) - linker error [\#2292](https://github.com/nlohmann/json/issues/2292) - Add support for high-precision numbers in UBJSON encoding [\#2286](https://github.com/nlohmann/json/issues/2286) - NLOHMANN\_DEFINE\_TYPE\_NON\_INTRUSIVE fails if the length of the argument is 10 [\#2280](https://github.com/nlohmann/json/issues/2280) - Custom types : MACRO expansion bug [\#2267](https://github.com/nlohmann/json/issues/2267) - to/from\_json Failing To Convert String [\#2238](https://github.com/nlohmann/json/issues/2238) - clang 9.0 report warning: unused type alias 'size\_type' \[-Wunused-local-typedef\] [\#2221](https://github.com/nlohmann/json/issues/2221) - Enormous array created when working with map\ [\#2220](https://github.com/nlohmann/json/issues/2220) - Can I disable sorting of json values [\#2219](https://github.com/nlohmann/json/issues/2219) - Getting Qt types to work [\#2217](https://github.com/nlohmann/json/issues/2217) - Convert to Qt QVariant [\#2216](https://github.com/nlohmann/json/issues/2216) - How to custom serialize same data type of vector? [\#2215](https://github.com/nlohmann/json/issues/2215) - json constructor does not support std::optional [\#2214](https://github.com/nlohmann/json/issues/2214) - Failing to Parse Valid JSON [\#2209](https://github.com/nlohmann/json/issues/2209) - \(De-\)Serialization of std::variant with namespaces [\#2208](https://github.com/nlohmann/json/issues/2208) - Addint support for complex type [\#2207](https://github.com/nlohmann/json/issues/2207) - array\_index possible out of range [\#2205](https://github.com/nlohmann/json/issues/2205) - Object deserialized as array [\#2204](https://github.com/nlohmann/json/issues/2204) - Sending to a function a reference to a sub-branch [\#2200](https://github.com/nlohmann/json/issues/2200) - How to Serialize derived class to JSON object? [\#2199](https://github.com/nlohmann/json/issues/2199) - JSON incorrectly serialized [\#2198](https://github.com/nlohmann/json/issues/2198) - Exception Unhandled out\_of\_range error [\#2197](https://github.com/nlohmann/json/issues/2197) - msgpack serialisation : float is treated as 64bit float, not 32bit float. [\#2196](https://github.com/nlohmann/json/issues/2196) - Is it possible to use compile-time type guarantees for JSON structures? [\#2195](https://github.com/nlohmann/json/issues/2195) - Question : performance against python dict [\#2194](https://github.com/nlohmann/json/issues/2194) - vs2017 compile error [\#2192](https://github.com/nlohmann/json/issues/2192) - Check if a key exists [\#2191](https://github.com/nlohmann/json/issues/2191) - Failed to run tests due to missing test data on builders without Internet access [\#2190](https://github.com/nlohmann/json/issues/2190) - 3.8.0: unit-cbor.cpp test failures [\#2189](https://github.com/nlohmann/json/issues/2189) - 'nlohmann/json.hpp' file not found [\#2188](https://github.com/nlohmann/json/issues/2188) - How to send json data over the wire? [\#2185](https://github.com/nlohmann/json/issues/2185) - Ubuntu 16 not supporting nlohmann/json? [\#2184](https://github.com/nlohmann/json/issues/2184) - .get\ causing emdash errors [\#2180](https://github.com/nlohmann/json/issues/2180) - Object properties should not be re-sorted alphabetically [\#2179](https://github.com/nlohmann/json/issues/2179) - Custom type registration : instrusive API [\#2175](https://github.com/nlohmann/json/issues/2175) - Many version of the function "void to\_json\(json& j, const MyStruct& struct\)" [\#2171](https://github.com/nlohmann/json/issues/2171) - How should strings be escaped? [\#2155](https://github.com/nlohmann/json/issues/2155) - Adding a value to an existing json puts it at the beginning instead of the end [\#2149](https://github.com/nlohmann/json/issues/2149) - The header file is big, can we use what we need. [\#2134](https://github.com/nlohmann/json/issues/2134) - Changing the default format for unordered\_map \(or other set\) [\#2132](https://github.com/nlohmann/json/issues/2132) - Getting size of deserialized bson document [\#2131](https://github.com/nlohmann/json/issues/2131) - implicit conversion failure [\#2128](https://github.com/nlohmann/json/issues/2128) - Error thrown when parsing in a subclass [\#2124](https://github.com/nlohmann/json/issues/2124) - explicit conversion to string not considered for std::map keys in GCC8 [\#2096](https://github.com/nlohmann/json/issues/2096) - Add support for JSONC [\#2061](https://github.com/nlohmann/json/issues/2061) - Library provides template arg for string\_type but assumes std::string in some places [\#2059](https://github.com/nlohmann/json/issues/2059) - incremental parsing with sax\_parser [\#2030](https://github.com/nlohmann/json/issues/2030) - Question about flatten and unflatten [\#1989](https://github.com/nlohmann/json/issues/1989) - CBOR parser doesn't skip tags [\#1968](https://github.com/nlohmann/json/issues/1968) - Compilation failure using Clang on Windows [\#1898](https://github.com/nlohmann/json/issues/1898) - Fail to build when including json.hpp as a system include [\#1818](https://github.com/nlohmann/json/issues/1818) - Parsing string into json doesn't preserve the order correctly. [\#1817](https://github.com/nlohmann/json/issues/1817) - \[C++17\] Allow std::optional to convert to nlohmann::json [\#1749](https://github.com/nlohmann/json/issues/1749) - How can I save json object in file in order? [\#1717](https://github.com/nlohmann/json/issues/1717) - Support for Comments [\#1513](https://github.com/nlohmann/json/issues/1513) - clang compiler: error : unknown type name 'not' [\#1119](https://github.com/nlohmann/json/issues/1119) - dump\(\) without alphabetical order [\#1106](https://github.com/nlohmann/json/issues/1106) - operator T\(\) considered harmful [\#958](https://github.com/nlohmann/json/issues/958) - Order of the elements in JSON object [\#952](https://github.com/nlohmann/json/issues/952) - How to prevent alphabetical sorting of data? [\#727](https://github.com/nlohmann/json/issues/727) - Why is an object ordering values by Alphabetical Order? [\#660](https://github.com/nlohmann/json/issues/660) - Feature request: Comments [\#597](https://github.com/nlohmann/json/issues/597) - Head Elements Sorting [\#543](https://github.com/nlohmann/json/issues/543) - Automatic ordered JSON [\#424](https://github.com/nlohmann/json/issues/424) - Support for comments. [\#376](https://github.com/nlohmann/json/issues/376) - Optional comment support. [\#363](https://github.com/nlohmann/json/issues/363) - Strip comments / Minify [\#294](https://github.com/nlohmann/json/issues/294) - maintaining order of keys during iteration [\#106](https://github.com/nlohmann/json/issues/106) - Update documentation [\#2312](https://github.com/nlohmann/json/pull/2312) ([nlohmann](https://github.com/nlohmann)) - Fix bug in CBOR tag handling [\#2308](https://github.com/nlohmann/json/pull/2308) ([nlohmann](https://github.com/nlohmann)) - added inline to NLOHMANN\_DEFINE\_TYPE\_NON\_INTRUSIVE macro [\#2306](https://github.com/nlohmann/json/pull/2306) ([jwittbrodt](https://github.com/jwittbrodt)) - fixes unused variable 'ex' for \#2304 [\#2305](https://github.com/nlohmann/json/pull/2305) ([AODQ](https://github.com/AODQ)) - Cleanup [\#2303](https://github.com/nlohmann/json/pull/2303) ([nlohmann](https://github.com/nlohmann)) - Add test with multiple translation units [\#2301](https://github.com/nlohmann/json/pull/2301) ([nlohmann](https://github.com/nlohmann)) - Merge GitHub actions [\#2300](https://github.com/nlohmann/json/pull/2300) ([nlohmann](https://github.com/nlohmann)) - Fix unused parameter [\#2299](https://github.com/nlohmann/json/pull/2299) ([nlohmann](https://github.com/nlohmann)) - Add support for high-precision numbers in UBJSON encoding [\#2297](https://github.com/nlohmann/json/pull/2297) ([nlohmann](https://github.com/nlohmann)) - fix eof for get\_binary and get\_string [\#2294](https://github.com/nlohmann/json/pull/2294) ([jprochazk](https://github.com/jprochazk)) - Serialisation macros: increase upper bound on number of member variables [\#2287](https://github.com/nlohmann/json/pull/2287) ([pfeatherstone](https://github.com/pfeatherstone)) - add inline specifier for detail::combine [\#2285](https://github.com/nlohmann/json/pull/2285) ([T0b1-iOS](https://github.com/T0b1-iOS)) - Add static assertion for missing binary function in SAX interface [\#2282](https://github.com/nlohmann/json/pull/2282) ([nlohmann](https://github.com/nlohmann)) - Add test for target\_include\_directories [\#2279](https://github.com/nlohmann/json/pull/2279) ([nlohmann](https://github.com/nlohmann)) - Clean up maintainer Makefiles and fix some linter warnings [\#2274](https://github.com/nlohmann/json/pull/2274) ([nlohmann](https://github.com/nlohmann)) - Add option to ignore CBOR tags [\#2273](https://github.com/nlohmann/json/pull/2273) ([nlohmann](https://github.com/nlohmann)) - Hash function without allocation [\#2269](https://github.com/nlohmann/json/pull/2269) ([nlohmann](https://github.com/nlohmann)) - Add ClangCL for MSVC [\#2268](https://github.com/nlohmann/json/pull/2268) ([t-b](https://github.com/t-b)) - Makefile: Always use SED variable [\#2264](https://github.com/nlohmann/json/pull/2264) ([t-b](https://github.com/t-b)) - Add Xcode 12 CI [\#2262](https://github.com/nlohmann/json/pull/2262) ([nlohmann](https://github.com/nlohmann)) - Make library work with Clang on Windows [\#2259](https://github.com/nlohmann/json/pull/2259) ([nlohmann](https://github.com/nlohmann)) - Add ordered\_json specialization with ordered object keys [\#2258](https://github.com/nlohmann/json/pull/2258) ([nlohmann](https://github.com/nlohmann)) - Add pkg-config file [\#2253](https://github.com/nlohmann/json/pull/2253) ([ericonr](https://github.com/ericonr)) - Fix regression from \#2181 [\#2251](https://github.com/nlohmann/json/pull/2251) ([nlohmann](https://github.com/nlohmann)) - Tag binary values in cbor if set [\#2244](https://github.com/nlohmann/json/pull/2244) ([matthewbauer](https://github.com/matthewbauer)) - Make assert configurable via JSON\_ASSERT [\#2242](https://github.com/nlohmann/json/pull/2242) ([nlohmann](https://github.com/nlohmann)) - Add specialization of get\_to [\#2233](https://github.com/nlohmann/json/pull/2233) ([nlohmann](https://github.com/nlohmann)) - Refine documentation of error\_handler parameter [\#2232](https://github.com/nlohmann/json/pull/2232) ([nlohmann](https://github.com/nlohmann)) - Simplify conversion from/to custom types [\#2225](https://github.com/nlohmann/json/pull/2225) ([nlohmann](https://github.com/nlohmann)) - Remove unused typedefs [\#2224](https://github.com/nlohmann/json/pull/2224) ([nlohmann](https://github.com/nlohmann)) - Enable CMake policy CMP0077 [\#2222](https://github.com/nlohmann/json/pull/2222) ([alexreinking](https://github.com/alexreinking)) - Add option to ignore comments in parse/accept functions [\#2212](https://github.com/nlohmann/json/pull/2212) ([nlohmann](https://github.com/nlohmann)) - Fix Clang-Tidy warnings [\#2211](https://github.com/nlohmann/json/pull/2211) ([nlohmann](https://github.com/nlohmann)) - Simple ordered\_json that works on all supported compilers [\#2206](https://github.com/nlohmann/json/pull/2206) ([gatopeich](https://github.com/gatopeich)) - Use unsigned indizies for array index in json pointer [\#2203](https://github.com/nlohmann/json/pull/2203) ([t-b](https://github.com/t-b)) - Add option to not rely on Internet connectivity during test stage [\#2202](https://github.com/nlohmann/json/pull/2202) ([nlohmann](https://github.com/nlohmann)) - Serialize floating-point numbers with 32 bit when possible \(MessagePack\) [\#2201](https://github.com/nlohmann/json/pull/2201) ([nlohmann](https://github.com/nlohmann)) - Fix consistency in function `int_to_string()` [\#2193](https://github.com/nlohmann/json/pull/2193) ([dota17](https://github.com/dota17)) - Fix issue\#1275 [\#2181](https://github.com/nlohmann/json/pull/2181) ([dota17](https://github.com/dota17)) - C++20 support by removing swap specialization [\#2176](https://github.com/nlohmann/json/pull/2176) ([gracicot](https://github.com/gracicot)) - Feat/explicit conversion operator [\#1559](https://github.com/nlohmann/json/pull/1559) ([theodelrieu](https://github.com/theodelrieu)) ## [v3.8.0](https://github.com/nlohmann/json/releases/tag/v3.8.0) (2020-06-14) [Full Changelog](https://github.com/nlohmann/json/compare/v3.7.3...v3.8.0) - sorry delete this issue, i'm stupid [\#2187](https://github.com/nlohmann/json/issues/2187) - Append to a std::nlohmann::json type [\#2186](https://github.com/nlohmann/json/issues/2186) - Some troubles to compile the last revision [\#2177](https://github.com/nlohmann/json/issues/2177) - ​\#​ Top level CMakeLists.txt​ ​project​\(FOO\) ... ​option​\(FOO\_USE\_EXTERNAL\_JSON ​"Use an external JSON library"​ ​OFF​\) ... ​add\_subdirectory​\(thirdparty\) ... ​add\_library​\(foo ...\) ... ​\#​ Note that the namespaced target will always be available regardless of the​ ​\#​ import method​ ​target\_link\_libraries​\(foo ​PRIVATE​ nlohmann\_json::nlohmann\_json\) [\#2170](https://github.com/nlohmann/json/issues/2170) - https://www.github.com/nlohmann/json/tree/develop/include%2Fnlohmann%2Fjson\_fwd.hpp [\#2169](https://github.com/nlohmann/json/issues/2169) - templated from\_json of non primitive types causes gcc error [\#2168](https://github.com/nlohmann/json/issues/2168) - few warnings/errors in copy assignment [\#2167](https://github.com/nlohmann/json/issues/2167) - Different output when upgrading from clang 9 to clang 10 [\#2166](https://github.com/nlohmann/json/issues/2166) - Cannot build with VS 2019 / C++17 [\#2163](https://github.com/nlohmann/json/issues/2163) - Q: When I received an illegal string,How the program knows? [\#2162](https://github.com/nlohmann/json/issues/2162) - Problem while reading a json file [\#2161](https://github.com/nlohmann/json/issues/2161) - converting std::chrono::system\_clock::time\_point to json. [\#2159](https://github.com/nlohmann/json/issues/2159) - how to parse vector\ format [\#2157](https://github.com/nlohmann/json/issues/2157) - nlohmann::json and =nullptr [\#2156](https://github.com/nlohmann/json/issues/2156) - test-cbor fails [\#2154](https://github.com/nlohmann/json/issues/2154) - Accessing array inside array syntax? [\#2151](https://github.com/nlohmann/json/issues/2151) - Best way to catch errors when querying json [\#2150](https://github.com/nlohmann/json/issues/2150) - JSON Data Mapping Key-Value from other Key-Value [\#2148](https://github.com/nlohmann/json/issues/2148) - Conflicts with std \ compiling with GCC 10 [\#2146](https://github.com/nlohmann/json/issues/2146) - Incorrect CMake FetchContent example [\#2142](https://github.com/nlohmann/json/issues/2142) - Help for a Beginner? [\#2141](https://github.com/nlohmann/json/issues/2141) - Read Json from File [\#2139](https://github.com/nlohmann/json/issues/2139) - How to feed a predefined integer value into json string [\#2138](https://github.com/nlohmann/json/issues/2138) - getting json array inside json object [\#2135](https://github.com/nlohmann/json/issues/2135) - Add .contains example to doc [\#2133](https://github.com/nlohmann/json/issues/2133) - Is it safe to return string.c\_str\(\) received from get\(\)? [\#2130](https://github.com/nlohmann/json/issues/2130) - GCC 10: Compilation error when including any before including json header in C++17 mode [\#2129](https://github.com/nlohmann/json/issues/2129) - Intersection of two json files [\#2127](https://github.com/nlohmann/json/issues/2127) - App crashes when dump method called for non ascii chars. [\#2126](https://github.com/nlohmann/json/issues/2126) - iterator based erase method [\#2122](https://github.com/nlohmann/json/issues/2122) - quick and convenient api to get/set nested json values [\#2120](https://github.com/nlohmann/json/issues/2120) - assigning nullptr to std::string [\#2118](https://github.com/nlohmann/json/issues/2118) - usless\_cast warnings with gcc 9.3 and 10.1 \(C++17\) [\#2114](https://github.com/nlohmann/json/issues/2114) - clang 10 warning [\#2113](https://github.com/nlohmann/json/issues/2113) - Possible incorrect \_MSC\_VER reference [\#2112](https://github.com/nlohmann/json/issues/2112) - warning under gcc 10.1 [\#2110](https://github.com/nlohmann/json/issues/2110) - Wdeprecated-declarations from GCC v10.1.0 [\#2109](https://github.com/nlohmann/json/issues/2109) - Global std::vector from json [\#2108](https://github.com/nlohmann/json/issues/2108) - heap-buffer-overflow when using nlohmann/json, ASAN, and gtest [\#2107](https://github.com/nlohmann/json/issues/2107) - exception 0x770DC5AF when i read an special char in json file [\#2106](https://github.com/nlohmann/json/issues/2106) - json::parse\(\) fails to parse a dump\(2,' '\) output, yet does successfully parse dump\(\) [\#2105](https://github.com/nlohmann/json/issues/2105) - run test-udt error in MSVC 19.16.27034.0 [\#2103](https://github.com/nlohmann/json/issues/2103) - Unable to dump to stringstream [\#2102](https://github.com/nlohmann/json/issues/2102) - Can't ad an object in another objet [\#2101](https://github.com/nlohmann/json/issues/2101) - Implicit conversion causes "cannot use operator\[\] with a string argument with string" [\#2098](https://github.com/nlohmann/json/issues/2098) - C++20: char8\_t [\#2097](https://github.com/nlohmann/json/issues/2097) - Compilation issues when included in project [\#2094](https://github.com/nlohmann/json/issues/2094) - string value with null character causes infinite loop [\#2093](https://github.com/nlohmann/json/issues/2093) - corrupted size vs. prev\_size \(aborted\) [\#2092](https://github.com/nlohmann/json/issues/2092) - Get string field content without return std::string copy [\#2091](https://github.com/nlohmann/json/issues/2091) - JSON Comments \(JSON 5\) [\#2090](https://github.com/nlohmann/json/issues/2090) - Remove \#include \ [\#2089](https://github.com/nlohmann/json/issues/2089) - JSON library as a git submodule [\#2088](https://github.com/nlohmann/json/issues/2088) - Apple Clang 11.0.3 on MacOS Catalina 10.15.4 not compiling [\#2087](https://github.com/nlohmann/json/issues/2087) - Value function return empty object even if it exist [\#2086](https://github.com/nlohmann/json/issues/2086) - Cannot debug but Run works [\#2085](https://github.com/nlohmann/json/issues/2085) - Question about serialization. [\#2084](https://github.com/nlohmann/json/issues/2084) - How to include in an external project [\#2083](https://github.com/nlohmann/json/issues/2083) - Missing tests for binary values [\#2082](https://github.com/nlohmann/json/issues/2082) - How to override default string serialization? [\#2079](https://github.com/nlohmann/json/issues/2079) - Can't have a json type as a property in an arbitrary type [\#2078](https://github.com/nlohmann/json/issues/2078) - New release? [\#2075](https://github.com/nlohmann/json/issues/2075) - CMake FetchContent \> Updating the documentation? [\#2073](https://github.com/nlohmann/json/issues/2073) - How to convert STL Vector \(of user defined type\) to Json [\#2072](https://github.com/nlohmann/json/issues/2072) - how to make an array of objects [\#2070](https://github.com/nlohmann/json/issues/2070) - ‘\_\_int64’ was not declared [\#2068](https://github.com/nlohmann/json/issues/2068) - \[json.exception.type\_error.317\] cannot serialize binary data to text JSON [\#2067](https://github.com/nlohmann/json/issues/2067) - Unexpected end of input; expected '\[', '{', or a literal [\#2066](https://github.com/nlohmann/json/issues/2066) - Json structure can be nested? [\#2065](https://github.com/nlohmann/json/issues/2065) - Bug: returning reference to local temporary object [\#2064](https://github.com/nlohmann/json/issues/2064) - Allow to use non strict parsing [\#2063](https://github.com/nlohmann/json/issues/2063) - Crashing on json::at [\#2062](https://github.com/nlohmann/json/issues/2062) - How to convert a const std::vector\ message to a json, to be able to parse it and extract information from it? Can you point to any examples? [\#2058](https://github.com/nlohmann/json/issues/2058) - Nice library [\#2057](https://github.com/nlohmann/json/issues/2057) - json.hpp:15372:22: error: expected unqualified-id if \(not std::isfinite\(x\)\): Started getting this bug after updating my XCode [\#2056](https://github.com/nlohmann/json/issues/2056) - Confused as how I can extract the values from the JSON object. [\#2055](https://github.com/nlohmann/json/issues/2055) - Warnings with GCC 10 [\#2052](https://github.com/nlohmann/json/issues/2052) - Warnings with Clang 10 [\#2049](https://github.com/nlohmann/json/issues/2049) - Update doctest [\#2048](https://github.com/nlohmann/json/issues/2048) - Unclear error message: "cannot use operator\[\] with a string argument with array" [\#2047](https://github.com/nlohmann/json/issues/2047) - Serializing std::variant\\> [\#2045](https://github.com/nlohmann/json/issues/2045) - Crash when parse big jsonfile [\#2042](https://github.com/nlohmann/json/issues/2042) - How to check if a key exists without silently generating null objects on the path [\#2041](https://github.com/nlohmann/json/issues/2041) - Crash when traversing over items\(\) of temporary json objects [\#2040](https://github.com/nlohmann/json/issues/2040) - How to parse multiple line value ? [\#2039](https://github.com/nlohmann/json/issues/2039) - SAX API uses unsigned std::size\_t but -1 if element size is not known; [\#2037](https://github.com/nlohmann/json/issues/2037) - How to parse big decimal data [\#2036](https://github.com/nlohmann/json/issues/2036) - how use template \ struct adl\_serializer [\#2035](https://github.com/nlohmann/json/issues/2035) - auto iterator returned by find to handle value depending if is string or numeric. [\#2032](https://github.com/nlohmann/json/issues/2032) - pass find returned iterator to numeric variable. [\#2031](https://github.com/nlohmann/json/issues/2031) - Parse error on valid json file [\#2029](https://github.com/nlohmann/json/issues/2029) - Is here any elegant way to combine serialization and deserialization code? [\#2028](https://github.com/nlohmann/json/issues/2028) - Notes about dump function [\#2027](https://github.com/nlohmann/json/issues/2027) - Different JSON printouts for empty dictionary on Linux and Mac. [\#2026](https://github.com/nlohmann/json/issues/2026) - easier way to get exception reason out of json\_sax\_dom\_callback\_parser without exceptions [\#2024](https://github.com/nlohmann/json/issues/2024) - Using fifo\_map with base class and derived class [\#2023](https://github.com/nlohmann/json/issues/2023) - Error reading JSON File [\#2022](https://github.com/nlohmann/json/issues/2022) - Parse causing crash on android. Cannot catch. [\#2021](https://github.com/nlohmann/json/issues/2021) - Extra backslashes in nested json [\#2020](https://github.com/nlohmann/json/issues/2020) - How to create patch for merge\_patch input ? [\#2018](https://github.com/nlohmann/json/issues/2018) - CppUTest/include/CppUTestExt/MockSupport.h:40: error: default argument for ‘MockFailureReporter\* failureReporterForThisCall’ has type ‘void\*’ [\#2017](https://github.com/nlohmann/json/issues/2017) - including another file [\#2016](https://github.com/nlohmann/json/issues/2016) - GNU PREREQ Error with gcc 9.3.0 [\#2015](https://github.com/nlohmann/json/issues/2015) - Parse error: json.exception.parse\_error.101 - invalid string: ill-formed UTF-8 byte [\#2014](https://github.com/nlohmann/json/issues/2014) - Add more flexibility to basic\_json's ObjectType \(and ArrayType\) [\#2013](https://github.com/nlohmann/json/issues/2013) - afl persistent mode [\#2012](https://github.com/nlohmann/json/issues/2012) - Compiler Errors under VS2019 in Appveyor CI [\#2009](https://github.com/nlohmann/json/issues/2009) - Another compilation failure with Visual Studio [\#2007](https://github.com/nlohmann/json/issues/2007) - Implicit cast to std::string broken again with VS2019 16.5.0 [\#2006](https://github.com/nlohmann/json/issues/2006) - error: no matching member function for call to 'AddRaw' [\#2005](https://github.com/nlohmann/json/issues/2005) - When I re-create an object again after the network request, an error is reported [\#2003](https://github.com/nlohmann/json/issues/2003) - How to merge \(and not replace\) different Json::Value objects in jsoncpp [\#2001](https://github.com/nlohmann/json/issues/2001) - scalar transforms to list [\#2000](https://github.com/nlohmann/json/issues/2000) - Dump JSON containing multibyte characters [\#1999](https://github.com/nlohmann/json/issues/1999) - Build error when modify value [\#1998](https://github.com/nlohmann/json/issues/1998) - How do i include a vector of pointers in my json? [\#1997](https://github.com/nlohmann/json/issues/1997) - Compiler error wrt incomplete types changed in gcc8.3.0-26 [\#1996](https://github.com/nlohmann/json/issues/1996) - NaN-like comparison behavior of discarded is inconvenient [\#1988](https://github.com/nlohmann/json/issues/1988) - Maintaining JSON package in my CMake [\#1987](https://github.com/nlohmann/json/issues/1987) - reading int number and string number [\#1986](https://github.com/nlohmann/json/issues/1986) - Build error: keyword is hidden by macro definition! [\#1985](https://github.com/nlohmann/json/issues/1985) - JSON patch diff for op=add formation is not as per standard \(RFC 6902\) [\#1983](https://github.com/nlohmann/json/issues/1983) - json\_pointer.contains\(\) exception is incorrectly raised [\#1982](https://github.com/nlohmann/json/issues/1982) - Error with non existing key [\#1981](https://github.com/nlohmann/json/issues/1981) - Closed [\#1978](https://github.com/nlohmann/json/issues/1978) - Where is the library built and what is the name? [\#1977](https://github.com/nlohmann/json/issues/1977) - The cmake\_import example does not build [\#1976](https://github.com/nlohmann/json/issues/1976) - Dumping core when reading invalid file [\#1975](https://github.com/nlohmann/json/issues/1975) - Abort in dump\(\) method [\#1973](https://github.com/nlohmann/json/issues/1973) - Unclear docs regarding parser\_callback\_t callbacks [\#1972](https://github.com/nlohmann/json/issues/1972) - Possible memory leak on push\_back [\#1971](https://github.com/nlohmann/json/issues/1971) - Is it possible to get a safe mutable reference/pointer to internal variant used in nlohmann json? [\#1970](https://github.com/nlohmann/json/issues/1970) - Getting a flatten json to map\ [\#1957](https://github.com/nlohmann/json/issues/1957) - forced type conversion or lexical cast without exception. [\#1955](https://github.com/nlohmann/json/issues/1955) - Add json\_view type support to avoid excessive copying [\#1954](https://github.com/nlohmann/json/issues/1954) - Adding "examples" section for real-life usages [\#1953](https://github.com/nlohmann/json/issues/1953) - Add nlohmann::json::key\_type [\#1951](https://github.com/nlohmann/json/issues/1951) - cannot use operator\[\] with a string argument with string [\#1949](https://github.com/nlohmann/json/issues/1949) - std::ifstream \>\> json error [\#1948](https://github.com/nlohmann/json/issues/1948) - Cannot update json data in an iterator? [\#1947](https://github.com/nlohmann/json/issues/1947) - How can i build this library in VS 2017? [\#1943](https://github.com/nlohmann/json/issues/1943) - json\_pointer.contains\(\) exceptions when path not found [\#1942](https://github.com/nlohmann/json/issues/1942) - Nested objects serialize/deserialize [\#1941](https://github.com/nlohmann/json/issues/1941) - Compile warning on architectures that are not x86 [\#1939](https://github.com/nlohmann/json/issues/1939) - Version of nlohmann-json-dev in debian packages [\#1938](https://github.com/nlohmann/json/issues/1938) - Create a json object for every cycle [\#1937](https://github.com/nlohmann/json/issues/1937) - How to get the object name? [\#1936](https://github.com/nlohmann/json/issues/1936) - Reserve and resize function for basic json [\#1935](https://github.com/nlohmann/json/issues/1935) - How to use json parse in tsl::ordread\_map? [\#1934](https://github.com/nlohmann/json/issues/1934) - C++14 support is not enabled with msvc2015 [\#1932](https://github.com/nlohmann/json/issues/1932) - Need help with to\_json for derived class, keep getting "cannot use operator" [\#1931](https://github.com/nlohmann/json/issues/1931) - How to handle std::vector\ [\#1930](https://github.com/nlohmann/json/issues/1930) - Heap corruption issue [\#1929](https://github.com/nlohmann/json/issues/1929) - Add `std::wistream` support. [\#1928](https://github.com/nlohmann/json/issues/1928) - This i can write and read any file thanks [\#1927](https://github.com/nlohmann/json/issues/1927) - How can I get this simple example working? [\#1926](https://github.com/nlohmann/json/issues/1926) - emplace\_back does not seems to work with the int 0 [\#1925](https://github.com/nlohmann/json/issues/1925) - Why nlohmann does not release memory [\#1924](https://github.com/nlohmann/json/issues/1924) - Is it possible to have template `json::parse` with `noexcept` specifier? [\#1922](https://github.com/nlohmann/json/issues/1922) - JSON to wstring? [\#1921](https://github.com/nlohmann/json/issues/1921) - GCC 10 tests build failure [\#1920](https://github.com/nlohmann/json/issues/1920) - Size of binary json representations [\#1919](https://github.com/nlohmann/json/issues/1919) - Accessing strings \(for example in keys or values\) without having the lib create a copy of it. [\#1916](https://github.com/nlohmann/json/issues/1916) - operator== documentation should show how to apply custom comparison function [\#1915](https://github.com/nlohmann/json/issues/1915) - char8\_t and std::u8string support [\#1914](https://github.com/nlohmann/json/issues/1914) - std::is\_pod is deprecated in C++20 [\#1913](https://github.com/nlohmann/json/issues/1913) - Incomplete types reported by \(experimental\) GCC10 [\#1912](https://github.com/nlohmann/json/issues/1912) - Compile warnings on MSVC 14.2 [\#1911](https://github.com/nlohmann/json/issues/1911) - How to parse json file with type composition of std::optional and std::variant [\#1910](https://github.com/nlohmann/json/issues/1910) - why root\_schema be implemented as unique\_ptr in json-validator.cpp,could I use it as shared\_ptr? [\#1908](https://github.com/nlohmann/json/issues/1908) - compile error in gcc-6.3.0 [\#1906](https://github.com/nlohmann/json/issues/1906) - Scalar constexpr is odr-used when used as json initializer [\#1905](https://github.com/nlohmann/json/issues/1905) - install Slack app [\#1904](https://github.com/nlohmann/json/issues/1904) - typo in a comment [\#1903](https://github.com/nlohmann/json/issues/1903) - Watch JSON variables in Debug [\#1902](https://github.com/nlohmann/json/issues/1902) - does Json sdk cares about dfc dfd utf8 issue? [\#1901](https://github.com/nlohmann/json/issues/1901) - Allow multiple line string value in JSON [\#1897](https://github.com/nlohmann/json/issues/1897) - Writing map to json file [\#1896](https://github.com/nlohmann/json/issues/1896) - Small documentation mistake [\#1895](https://github.com/nlohmann/json/issues/1895) - why static function `parse` cann't find in visual studio 2019 [\#1894](https://github.com/nlohmann/json/issues/1894) - Best way to handle json files with missing key value pairs. [\#1893](https://github.com/nlohmann/json/issues/1893) - accessing json object as multimap [\#1892](https://github.com/nlohmann/json/issues/1892) - What is the best way to parse vec3s into glm::vec3 [\#1891](https://github.com/nlohmann/json/issues/1891) - Get array of items without using vector [\#1890](https://github.com/nlohmann/json/issues/1890) - Build errors \(clang 11.0.0\) on macOS 10.15.2 [\#1889](https://github.com/nlohmann/json/issues/1889) - Multiple arrays to vectors help [\#1888](https://github.com/nlohmann/json/issues/1888) - json::parse\(begin, end\) parse error on first character using uchar\* [\#1887](https://github.com/nlohmann/json/issues/1887) - issue in free\(\) [\#1886](https://github.com/nlohmann/json/issues/1886) - is\_number\_unsigned\(\) returns false for positive integers \(int or 0 or 1 literals\) [\#1885](https://github.com/nlohmann/json/issues/1885) - MSVC build failure with /Zc:\_\_cplusplus and C++17 [\#1883](https://github.com/nlohmann/json/issues/1883) - RFC 6901 op:replace & arrays [\#1882](https://github.com/nlohmann/json/issues/1882) - Problem with serialization of my custom template doubly-linked list [\#1881](https://github.com/nlohmann/json/issues/1881) - is\_array\(\) is True, but raise 'cannot use operator\[\] for object iterators' [\#1880](https://github.com/nlohmann/json/issues/1880) - Serialize dynamic array [\#1879](https://github.com/nlohmann/json/issues/1879) - Serialization of struct object. [\#1877](https://github.com/nlohmann/json/issues/1877) - warning:c4503 [\#1875](https://github.com/nlohmann/json/issues/1875) - Why are flattened empty objects/arrays not representable? [\#1874](https://github.com/nlohmann/json/issues/1874) - Container Overflow \(ASAN\) when using operator \>\> on an ifs [\#1873](https://github.com/nlohmann/json/issues/1873) - Sub-array to vector or map object? [\#1870](https://github.com/nlohmann/json/issues/1870) - WIP: QT \(cute\) type supports [\#1869](https://github.com/nlohmann/json/issues/1869) - Compiler flags to disable features and shrink code size [\#1868](https://github.com/nlohmann/json/issues/1868) - null strings [\#1867](https://github.com/nlohmann/json/issues/1867) - Struct with array of struct and \_\_attribute\_\_\(\(packed\)\) [\#1866](https://github.com/nlohmann/json/issues/1866) - Best way to extract numbers in the string? [\#1865](https://github.com/nlohmann/json/issues/1865) - Displaying \\?\Volume{guid} from string to json giving error [\#1864](https://github.com/nlohmann/json/issues/1864) - not working when compiling as x86 [\#1863](https://github.com/nlohmann/json/issues/1863) - Skipping evaluation of log line expressions with a macro, is it possible? [\#1862](https://github.com/nlohmann/json/issues/1862) - Suppress warnings [\#1861](https://github.com/nlohmann/json/issues/1861) - conflit with g++ compile option -mwindows [\#1860](https://github.com/nlohmann/json/issues/1860) - How to serialize nested classes to semi-flat JSON object? [\#1859](https://github.com/nlohmann/json/issues/1859) - Memory Requirement for large json file [\#1858](https://github.com/nlohmann/json/issues/1858) - Query a binary format \(BSON, CBOR, MessagePack, UBJSON\) [\#1856](https://github.com/nlohmann/json/issues/1856) - Documentation on operator\[\] behavior with missing keys [\#1855](https://github.com/nlohmann/json/issues/1855) - Problem in converting string into JSON; Can't parse successfully. [\#1854](https://github.com/nlohmann/json/issues/1854) - json.at\_or\_default\(key, defaultval\) [\#1852](https://github.com/nlohmann/json/issues/1852) - please improve the enum conversion documentation \(my example gist provided\) [\#1851](https://github.com/nlohmann/json/issues/1851) - Default value returned on ValueType nlohmann::basic\_json::value \(const typename object\_t::key\_type& key, const ValueType& default\_value\) [\#1850](https://github.com/nlohmann/json/issues/1850) - Accounting for arbitrary precision numerical literals [\#1849](https://github.com/nlohmann/json/issues/1849) - While trying to make a simple array, I get a nested array instead [\#1848](https://github.com/nlohmann/json/issues/1848) - How to reuse the parser and serializer intermediate storage? [\#1847](https://github.com/nlohmann/json/issues/1847) - Too much content in json.hpp leads to slow compilation [\#1845](https://github.com/nlohmann/json/issues/1845) - Cannot read some data in json file [\#1843](https://github.com/nlohmann/json/issues/1843) - Precompiled JSON library? [\#1842](https://github.com/nlohmann/json/issues/1842) - Please change assert into throw\(maybe\) in line 17946 [\#1841](https://github.com/nlohmann/json/issues/1841) - JSON for modern C++ ECCN information [\#1840](https://github.com/nlohmann/json/issues/1840) - CI: reduce build time for Travis valgrind [\#1836](https://github.com/nlohmann/json/issues/1836) - How do I traverse a json object and add new elements into the hierarchy [\#1834](https://github.com/nlohmann/json/issues/1834) - Invalid UTF-8 byte at index 1: 0x65 [\#1831](https://github.com/nlohmann/json/issues/1831) - Serialize big data in json [\#1828](https://github.com/nlohmann/json/issues/1828) - Backslash '\' in value causes exception [\#1827](https://github.com/nlohmann/json/issues/1827) - from\_json for non default constructible class with dependency injection [\#1819](https://github.com/nlohmann/json/issues/1819) - Semi-frequent timeouts in `test-unicode_all` with 3.6.1 \(aarch64\) [\#1816](https://github.com/nlohmann/json/issues/1816) - input\_adapter not user extensible [\#1813](https://github.com/nlohmann/json/issues/1813) - crash at json::destroy on android [\#1812](https://github.com/nlohmann/json/issues/1812) - Logs are repeating while cmake [\#1809](https://github.com/nlohmann/json/issues/1809) - Add a the possibility to add dynamic json objects [\#1795](https://github.com/nlohmann/json/issues/1795) - Unnecessary test data file in the release [\#1790](https://github.com/nlohmann/json/issues/1790) - Add support for parse stack limiting [\#1788](https://github.com/nlohmann/json/issues/1788) - GCC -Wuseless-cast warnings [\#1777](https://github.com/nlohmann/json/issues/1777) - compilation issue with NVCC 9.0 [\#1773](https://github.com/nlohmann/json/issues/1773) - Unexpected behavior with fifo\_map json when copy and append [\#1763](https://github.com/nlohmann/json/issues/1763) - Parse error [\#1761](https://github.com/nlohmann/json/issues/1761) - Assignment \(using value\(\)\) to nonexistent element behaves differently on Xcode 8 vs Xcode 10 [\#1758](https://github.com/nlohmann/json/issues/1758) - Readme out of date [\#1756](https://github.com/nlohmann/json/issues/1756) - cmake\_\* tests don't use the build system's compiler [\#1747](https://github.com/nlohmann/json/issues/1747) - Static assertions for template type properties required [\#1729](https://github.com/nlohmann/json/issues/1729) - Use float and possibly half in json::to\_cbor [\#1719](https://github.com/nlohmann/json/issues/1719) - json::from\_cbor does not respect allow\_exceptions = false when input is string literal [\#1715](https://github.com/nlohmann/json/issues/1715) - /Zc:\_\_cplusplus leads to C2416 [\#1695](https://github.com/nlohmann/json/issues/1695) - `unflatten` vs objects with number-ish keys [\#1575](https://github.com/nlohmann/json/issues/1575) - A "thinner" source code tar as part of release? [\#1572](https://github.com/nlohmann/json/issues/1572) - Repository is almost 450MB [\#1497](https://github.com/nlohmann/json/issues/1497) - Substantial performance penalty caused by polymorphic input adapter [\#1457](https://github.com/nlohmann/json/issues/1457) - Move tests to a separate repo [\#1235](https://github.com/nlohmann/json/issues/1235) - reduce repos size [\#1185](https://github.com/nlohmann/json/issues/1185) - CMakeLists.txt in release zips? [\#1184](https://github.com/nlohmann/json/issues/1184) - Minimal branch? [\#1066](https://github.com/nlohmann/json/issues/1066) - Move test blobs to a submodule? [\#732](https://github.com/nlohmann/json/issues/732) - \[Question\] When using this as git submodule, will it clone the whole thing include test data and benchmark? [\#620](https://github.com/nlohmann/json/issues/620) - Need to improve ignores.. [\#567](https://github.com/nlohmann/json/issues/567) - Minimal repository \(current size very large\) [\#556](https://github.com/nlohmann/json/issues/556) - For a header-only library you have to clone 214MB [\#482](https://github.com/nlohmann/json/issues/482) - 17 MB / 90 MB repo size!? [\#96](https://github.com/nlohmann/json/issues/96) - Improve parse\_ubjson\_fuzzer [\#2182](https://github.com/nlohmann/json/pull/2182) ([tanuj208](https://github.com/tanuj208)) - Add input adapter tests [\#2178](https://github.com/nlohmann/json/pull/2178) ([nlohmann](https://github.com/nlohmann)) - Fix warnings [\#2174](https://github.com/nlohmann/json/pull/2174) ([nlohmann](https://github.com/nlohmann)) - Fix PR\#1006 [\#2158](https://github.com/nlohmann/json/pull/2158) ([dota17](https://github.com/dota17)) - Fix issue\#1972 [\#2153](https://github.com/nlohmann/json/pull/2153) ([dota17](https://github.com/dota17)) - Update URLs to HTTPS [\#2152](https://github.com/nlohmann/json/pull/2152) ([TotalCaesar659](https://github.com/TotalCaesar659)) - Fix Issue\#1813: user defined input adapters [\#2145](https://github.com/nlohmann/json/pull/2145) ([FrancoisChabot](https://github.com/FrancoisChabot)) - Fix issue\#1939: Cast character to unsigned for comparison [\#2144](https://github.com/nlohmann/json/pull/2144) ([XyFreak](https://github.com/XyFreak)) - Fix issue\#2142: readme: fix typo in CMake FetchContent example [\#2143](https://github.com/nlohmann/json/pull/2143) ([quentin-dev](https://github.com/quentin-dev)) - Respect allow\_exceptions=false for binary formats [\#2140](https://github.com/nlohmann/json/pull/2140) ([nlohmann](https://github.com/nlohmann)) - Fix issue 2112 [\#2137](https://github.com/nlohmann/json/pull/2137) ([dota17](https://github.com/dota17)) - Add bleeding edge GCC to CI [\#2136](https://github.com/nlohmann/json/pull/2136) ([aokellermann](https://github.com/aokellermann)) - Clean up implementation of binary type [\#2125](https://github.com/nlohmann/json/pull/2125) ([nlohmann](https://github.com/nlohmann)) - Fixed a compilation error in MSVC [\#2121](https://github.com/nlohmann/json/pull/2121) ([gistrec](https://github.com/gistrec)) - Overwork CI [\#2119](https://github.com/nlohmann/json/pull/2119) ([nlohmann](https://github.com/nlohmann)) - Fix warnings from Clang 10 and GCC 9 [\#2116](https://github.com/nlohmann/json/pull/2116) ([nlohmann](https://github.com/nlohmann)) - Do not include \ when using C++17 [\#2115](https://github.com/nlohmann/json/pull/2115) ([nlohmann](https://github.com/nlohmann)) - Fix issue\#2086: disallow json::value\_t type parameter in value\(\) [\#2104](https://github.com/nlohmann/json/pull/2104) ([dota17](https://github.com/dota17)) - Fix Coveralls integration [\#2100](https://github.com/nlohmann/json/pull/2100) ([nlohmann](https://github.com/nlohmann)) - Add tests for binary values [\#2099](https://github.com/nlohmann/json/pull/2099) ([nlohmann](https://github.com/nlohmann)) - Use external test data [\#2081](https://github.com/nlohmann/json/pull/2081) ([nlohmann](https://github.com/nlohmann)) - Remove Doozer CI [\#2080](https://github.com/nlohmann/json/pull/2080) ([nlohmann](https://github.com/nlohmann)) - Fix README.md. Missing ``` [\#2077](https://github.com/nlohmann/json/pull/2077) ([ArthurSonzogni](https://github.com/ArthurSonzogni)) - Fix error message about invalid surrogate pairs [\#2076](https://github.com/nlohmann/json/pull/2076) ([rmisev](https://github.com/rmisev)) - Add CMake fetchcontent documentation and tests [\#2074](https://github.com/nlohmann/json/pull/2074) ([ArthurSonzogni](https://github.com/ArthurSonzogni)) - Properly pass serialize\_binary to dump function [\#2071](https://github.com/nlohmann/json/pull/2071) ([nlohmann](https://github.com/nlohmann)) - Fix returning reference to local temporary object [\#2069](https://github.com/nlohmann/json/pull/2069) ([nlohmann](https://github.com/nlohmann)) - updated wandbox link [\#2060](https://github.com/nlohmann/json/pull/2060) ([alexandermyasnikov](https://github.com/alexandermyasnikov)) - Fix bug in diff function [\#2054](https://github.com/nlohmann/json/pull/2054) ([nlohmann](https://github.com/nlohmann)) - Fix GCC compiler warnings [\#2053](https://github.com/nlohmann/json/pull/2053) ([nlohmann](https://github.com/nlohmann)) - Fix Clang compiler warnings [\#2051](https://github.com/nlohmann/json/pull/2051) ([nlohmann](https://github.com/nlohmann)) - Update doctest to 2.3.7 [\#2050](https://github.com/nlohmann/json/pull/2050) ([nlohmann](https://github.com/nlohmann)) - Fix issue\#1719 [\#2044](https://github.com/nlohmann/json/pull/2044) ([dota17](https://github.com/dota17)) - Add missing testcase about NaN in unit-constructor1.cpp [\#2043](https://github.com/nlohmann/json/pull/2043) ([dota17](https://github.com/dota17)) - Templatize basic\_json constructor from json\_ref [\#2034](https://github.com/nlohmann/json/pull/2034) ([ArtemSarmini](https://github.com/ArtemSarmini)) - Replace deprecated std::is\_pod [\#2033](https://github.com/nlohmann/json/pull/2033) ([nlohmann](https://github.com/nlohmann)) - Fixes \#1971 \(memory leak in basic\_json::push\_back\) [\#2025](https://github.com/nlohmann/json/pull/2025) ([ArtemSarmini](https://github.com/ArtemSarmini)) - fix \#1982:json\_pointer.contains\(\) exception is incorrectly raised [\#2019](https://github.com/nlohmann/json/pull/2019) ([dota17](https://github.com/dota17)) - Update LICENSE.MIT [\#2010](https://github.com/nlohmann/json/pull/2010) ([magamig](https://github.com/magamig)) - PR for \#2006 to test in AppVeyor. [\#2008](https://github.com/nlohmann/json/pull/2008) ([garethsb](https://github.com/garethsb)) - Added wsjcpp.yml [\#2004](https://github.com/nlohmann/json/pull/2004) ([sea-kg](https://github.com/sea-kg)) - fix error 'setw' is not a member of 'std' in Wandbox example [\#2002](https://github.com/nlohmann/json/pull/2002) ([alexandermyasnikov](https://github.com/alexandermyasnikov)) - catch exceptions for json\_pointer : ..../+99 [\#1990](https://github.com/nlohmann/json/pull/1990) ([dota17](https://github.com/dota17)) - Modify the document about operator== [\#1984](https://github.com/nlohmann/json/pull/1984) ([dota17](https://github.com/dota17)) - Rename argument array\_index to array\_indx in json\_pointer methods [\#1980](https://github.com/nlohmann/json/pull/1980) ([linev](https://github.com/linev)) - README: Fix string representation of `dump`ed `json` [\#1979](https://github.com/nlohmann/json/pull/1979) ([alex-weej](https://github.com/alex-weej)) - fix warnings in serializer.hpp for VS2019 [\#1969](https://github.com/nlohmann/json/pull/1969) ([dota17](https://github.com/dota17)) - Fix C26451 warnnings in to\_chars.hpp [\#1967](https://github.com/nlohmann/json/pull/1967) ([dota17](https://github.com/dota17)) - appveyor.yml: Compile and test with latest version for \_\_cplusplus ma… [\#1958](https://github.com/nlohmann/json/pull/1958) ([t-b](https://github.com/t-b)) - Fix typo in examples [\#1956](https://github.com/nlohmann/json/pull/1956) ([dota17](https://github.com/dota17)) - templated input adapters [\#1950](https://github.com/nlohmann/json/pull/1950) ([FrancoisChabot](https://github.com/FrancoisChabot)) - Update README.md : add a FAQ about memory release [\#1933](https://github.com/nlohmann/json/pull/1933) ([dota17](https://github.com/dota17)) - Some typos [\#1923](https://github.com/nlohmann/json/pull/1923) ([Coeur](https://github.com/Coeur)) - Fix link to parse function in README [\#1918](https://github.com/nlohmann/json/pull/1918) ([kastiglione](https://github.com/kastiglione)) - Readme: Updated links to hunter repo & docs [\#1917](https://github.com/nlohmann/json/pull/1917) ([jothepro](https://github.com/jothepro)) - Adds instruction for using Build2's package manager [\#1909](https://github.com/nlohmann/json/pull/1909) ([Klaim](https://github.com/Klaim)) - Update README.md [\#1907](https://github.com/nlohmann/json/pull/1907) ([pauljurczak](https://github.com/pauljurczak)) - Fix warning: ignoring return value [\#1871](https://github.com/nlohmann/json/pull/1871) ([sonulohani](https://github.com/sonulohani)) - docs: add central repository as conan source to readme [\#1857](https://github.com/nlohmann/json/pull/1857) ([gocarlos](https://github.com/gocarlos)) - README: Package in MSYS2 renamed to nlohmann-json [\#1853](https://github.com/nlohmann/json/pull/1853) ([podsvirov](https://github.com/podsvirov)) - Fix msvc warnings [\#1846](https://github.com/nlohmann/json/pull/1846) ([MBalszun](https://github.com/MBalszun)) - Update tests that generate CMake projects to use main project's C++ compiler [\#1844](https://github.com/nlohmann/json/pull/1844) ([Tridacnid](https://github.com/Tridacnid)) - make CMake's version config file architecture-independent [\#1746](https://github.com/nlohmann/json/pull/1746) ([uhoreg](https://github.com/uhoreg)) - Add binary type support to all binary file formats, as well as an internally represented binary type [\#1662](https://github.com/nlohmann/json/pull/1662) ([OmnipotentEntity](https://github.com/OmnipotentEntity)) ## [v3.7.3](https://github.com/nlohmann/json/releases/tag/v3.7.3) (2019-11-17) [Full Changelog](https://github.com/nlohmann/json/compare/v3.7.2...v3.7.3) - Project branches [\#1839](https://github.com/nlohmann/json/issues/1839) - Quadratic destruction complexity introduced in \#1436 [\#1837](https://github.com/nlohmann/json/issues/1837) - Trying to open a file [\#1814](https://github.com/nlohmann/json/issues/1814) - Comparing data type with value\_t::number\_integer fails [\#1783](https://github.com/nlohmann/json/issues/1783) - CMake version config file is architecture-dependent [\#1697](https://github.com/nlohmann/json/issues/1697) - Fix quadratic destruction complexity [\#1838](https://github.com/nlohmann/json/pull/1838) ([nickaein](https://github.com/nickaein)) ## [v3.7.2](https://github.com/nlohmann/json/releases/tag/v3.7.2) (2019-11-10) [Full Changelog](https://github.com/nlohmann/json/compare/v3.7.1...v3.7.2) - Segmentation fault in destructor in case of large inputs [\#1835](https://github.com/nlohmann/json/issues/1835) - type\_name\(\) is not consistent with type\(\) [\#1833](https://github.com/nlohmann/json/issues/1833) - json::parse is not a member [\#1832](https://github.com/nlohmann/json/issues/1832) - How do you deal with json\* ? [\#1829](https://github.com/nlohmann/json/issues/1829) - Combined find\_package/add\_subdirectory not linking libraries [\#1771](https://github.com/nlohmann/json/issues/1771) - example code for ifstream reading a json file results in no operator error [\#1766](https://github.com/nlohmann/json/issues/1766) - Warning: unsequenced modification and access to 'range' [\#1674](https://github.com/nlohmann/json/issues/1674) - Segmentation fault \(stack overflow\) due to unbounded recursion [\#1419](https://github.com/nlohmann/json/issues/1419) - Stack-overflow \(OSS-Fuzz 4234\) [\#832](https://github.com/nlohmann/json/issues/832) - Configure WhiteSource Bolt for GitHub [\#1830](https://github.com/nlohmann/json/pull/1830) ([whitesource-bolt-for-github[bot]](https://github.com/apps/whitesource-bolt-for-github)) - Prevent stackoverflow caused by recursive deconstruction [\#1436](https://github.com/nlohmann/json/pull/1436) ([nickaein](https://github.com/nickaein)) ## [v3.7.1](https://github.com/nlohmann/json/releases/tag/v3.7.1) (2019-11-06) [Full Changelog](https://github.com/nlohmann/json/compare/v3.7.0...v3.7.1) - std::is\_constructible is always true with tuple [\#1825](https://github.com/nlohmann/json/issues/1825) - Can't compile from\_json\(std::valarray\\). [\#1824](https://github.com/nlohmann/json/issues/1824) - json class should have a get\_or member function [\#1823](https://github.com/nlohmann/json/issues/1823) - NLOHMANN\_JSON\_SERIALIZE\_ENUM macro capture's json objects by value [\#1822](https://github.com/nlohmann/json/issues/1822) - Parse fails when number literals start with zero [\#1820](https://github.com/nlohmann/json/issues/1820) - Weird behaviour of `contains` with `json_pointer` [\#1815](https://github.com/nlohmann/json/issues/1815) - strange behaviour with json\_pointer and .contains\(\) [\#1811](https://github.com/nlohmann/json/issues/1811) - Can \#1695 be re-opened? [\#1808](https://github.com/nlohmann/json/issues/1808) - Merge two json objects [\#1807](https://github.com/nlohmann/json/issues/1807) - std::is\_constructible\\> when to\_json not defined [\#1805](https://github.com/nlohmann/json/issues/1805) - Private data on parsing [\#1802](https://github.com/nlohmann/json/issues/1802) - Capturing Line and Position when querying [\#1800](https://github.com/nlohmann/json/issues/1800) - json error on parsing DBL\_MAX from string [\#1796](https://github.com/nlohmann/json/issues/1796) - De/Serialisation of vector of tupple object with nested obect need Help please [\#1794](https://github.com/nlohmann/json/issues/1794) - Output json is corrupted [\#1793](https://github.com/nlohmann/json/issues/1793) - variable name byte sometimes used as a \#define [\#1792](https://github.com/nlohmann/json/issues/1792) - Can't read json file [\#1791](https://github.com/nlohmann/json/issues/1791) - Problems with special German letters [\#1789](https://github.com/nlohmann/json/issues/1789) - Support for trailing commas [\#1787](https://github.com/nlohmann/json/issues/1787) - json\_pointer construction bug [\#1786](https://github.com/nlohmann/json/issues/1786) - Visual Studio 2017 warning [\#1784](https://github.com/nlohmann/json/issues/1784) - ciso646 header become obsolete [\#1782](https://github.com/nlohmann/json/issues/1782) - Migrate LGTM.com installation from OAuth to GitHub App [\#1781](https://github.com/nlohmann/json/issues/1781) - JSON comparison, contains and operator& [\#1778](https://github.com/nlohmann/json/issues/1778) - pass a json object to a class contructor adds an array around the object [\#1776](https://github.com/nlohmann/json/issues/1776) - 'Float' number\_float\_function\_t template parameter name conflicts with C '\#define Float float' [\#1775](https://github.com/nlohmann/json/issues/1775) - A weird building problem :-\( [\#1774](https://github.com/nlohmann/json/issues/1774) - What is this json\_ref? [\#1772](https://github.com/nlohmann/json/issues/1772) - Interoperability with other languages [\#1770](https://github.com/nlohmann/json/issues/1770) - Json dump [\#1768](https://github.com/nlohmann/json/issues/1768) - json\_pointer\<\>::back\(\) should be const [\#1764](https://github.com/nlohmann/json/issues/1764) - How to get value from array [\#1762](https://github.com/nlohmann/json/issues/1762) - Merge two jsons [\#1757](https://github.com/nlohmann/json/issues/1757) - Unable to locate nlohmann\_jsonConfig.cmake [\#1755](https://github.com/nlohmann/json/issues/1755) - json.hpp won;t compile VS2019 CLR/CLI app but does in console app [\#1754](https://github.com/nlohmann/json/issues/1754) - \[Nested Json Objects\] Segmentation fault [\#1753](https://github.com/nlohmann/json/issues/1753) - remove/replace assert with exceptions [\#1752](https://github.com/nlohmann/json/issues/1752) - Add array support for update\(\) function [\#1751](https://github.com/nlohmann/json/issues/1751) - Is there a reason the `get_to` method is defined in `include/nlohmann/json.hpp` but not in `single_include/nlohmann/json.hpp`? [\#1750](https://github.com/nlohmann/json/issues/1750) - how to validate json object before calling dump\(\) [\#1748](https://github.com/nlohmann/json/issues/1748) - Unable to invoke accessors on json objects in lldb [\#1745](https://github.com/nlohmann/json/issues/1745) - Escaping string before parsing [\#1743](https://github.com/nlohmann/json/issues/1743) - Construction in a member initializer list using curly braces is set as 'array' [\#1742](https://github.com/nlohmann/json/issues/1742) - Read a subkey from json object [\#1740](https://github.com/nlohmann/json/issues/1740) - Serialize vector of glm:vec2 [\#1739](https://github.com/nlohmann/json/issues/1739) - Support nlohmann::basic\_json::value with JSON\_NOEXCEPTION [\#1738](https://github.com/nlohmann/json/issues/1738) - how to know the parse is error [\#1737](https://github.com/nlohmann/json/issues/1737) - How to check if a given key exists in a JSON object [\#1736](https://github.com/nlohmann/json/issues/1736) - Allow The Colon Key-Value Delimiter To Have A Space Before It \[@ READ ONLY\] [\#1735](https://github.com/nlohmann/json/issues/1735) - Allow Tail { "Key": "Value" } Comma \[@ READ ONLY\] [\#1734](https://github.com/nlohmann/json/issues/1734) - No-throw json::value\(\) [\#1733](https://github.com/nlohmann/json/issues/1733) - JsonObject.dump\(\) [\#1732](https://github.com/nlohmann/json/issues/1732) - basic\_json has no member "parse" [\#1731](https://github.com/nlohmann/json/issues/1731) - Exception "type must be string, but is array" [\#1730](https://github.com/nlohmann/json/issues/1730) - json::contains usage to find a path [\#1727](https://github.com/nlohmann/json/issues/1727) - How to create JSON Object from my Structures of Data and Json File from that Object [\#1726](https://github.com/nlohmann/json/issues/1726) - please provide an API to read JSON from file directly. [\#1725](https://github.com/nlohmann/json/issues/1725) - How to modify a value stored at a key? [\#1723](https://github.com/nlohmann/json/issues/1723) - CMake not correctly finding the configuration package for 3.7.0 [\#1721](https://github.com/nlohmann/json/issues/1721) - name typo in the "spack package management" section of README.md [\#1720](https://github.com/nlohmann/json/issues/1720) - How to add json to another json? [\#1718](https://github.com/nlohmann/json/issues/1718) - json::parse\(\) ubsan regression with v3.7.0 [\#1716](https://github.com/nlohmann/json/issues/1716) - What I am doing wrong?!? [\#1714](https://github.com/nlohmann/json/issues/1714) - Potential memory leak detected by Valgrind [\#1713](https://github.com/nlohmann/json/issues/1713) - json::parse is not thread safe? [\#1712](https://github.com/nlohmann/json/issues/1712) - static analysis alarm by cppcheck [\#1711](https://github.com/nlohmann/json/issues/1711) - The compilation time is slow [\#1710](https://github.com/nlohmann/json/issues/1710) - not linking properly with cmake [\#1709](https://github.com/nlohmann/json/issues/1709) - Error in dump\(\) with int64\_t minimum value [\#1708](https://github.com/nlohmann/json/issues/1708) - Crash on trying to deserialize json string on 3ds homebrew [\#1707](https://github.com/nlohmann/json/issues/1707) - Can't compile VS2019. 13 Errors [\#1706](https://github.com/nlohmann/json/issues/1706) - find an object that matches the search criteria [\#1705](https://github.com/nlohmann/json/issues/1705) - IntelliSense goes crazy on VS2019 [\#1704](https://github.com/nlohmann/json/issues/1704) - Installing on Ubuntu 16.04 [\#1703](https://github.com/nlohmann/json/issues/1703) - Where is json::parse now? [\#1702](https://github.com/nlohmann/json/issues/1702) - Forward header should't be amalgamated [\#1700](https://github.com/nlohmann/json/issues/1700) - Json support for Cmake version 2.8.12 [\#1699](https://github.com/nlohmann/json/issues/1699) - Intruisive scientific notation when using .dump\(\); [\#1698](https://github.com/nlohmann/json/issues/1698) - Is there support for automatic serialization/deserialization? [\#1696](https://github.com/nlohmann/json/issues/1696) - on MSVC dump\(\) will hard crash for larger json [\#1693](https://github.com/nlohmann/json/issues/1693) - puzzled implicit conversions [\#1692](https://github.com/nlohmann/json/issues/1692) - Information: My project uses this awesome library [\#1691](https://github.com/nlohmann/json/issues/1691) - Consider listing files explicitly instead of using GLOB [\#1686](https://github.com/nlohmann/json/issues/1686) - Failing tests on MSVC with VS2019 15.9.13 x64 [\#1685](https://github.com/nlohmann/json/issues/1685) - Consider putting the user-defined literals in a namespace [\#1682](https://github.com/nlohmann/json/issues/1682) - Change from v2 to v3. Encoding with cp1252 [\#1680](https://github.com/nlohmann/json/issues/1680) - How to add Fifo\_map into json using Cmake [\#1679](https://github.com/nlohmann/json/issues/1679) - include.zip should contain meson.build [\#1672](https://github.com/nlohmann/json/issues/1672) - \[Question\] How do I parse JSON into custom types? [\#1669](https://github.com/nlohmann/json/issues/1669) - Binary \(0x05\) data type for BSON to JSON conversion [\#1668](https://github.com/nlohmann/json/issues/1668) - Possible to call dump from lldb? [\#1666](https://github.com/nlohmann/json/issues/1666) - Segmentation fault when linked with libunwind [\#1665](https://github.com/nlohmann/json/issues/1665) - Should I include single-header after my to\_json and from\_json custom functions declaration? Why not? [\#1663](https://github.com/nlohmann/json/issues/1663) - Errors/Warnings in VS 2019 when Including Header File [\#1659](https://github.com/nlohmann/json/issues/1659) - Return null object from object's const operator\[\] as well. [\#1658](https://github.com/nlohmann/json/issues/1658) - Can't stream json object in to std::basic\_stringstream\ [\#1656](https://github.com/nlohmann/json/issues/1656) - C2440 in vs2015 cannot convert from 'initializer-list' to nlohmann::basic\_json [\#1655](https://github.com/nlohmann/json/issues/1655) - Issues around get and pointers [\#1653](https://github.com/nlohmann/json/issues/1653) - Non-member operator== breaks enum \(de\)serialization [\#1647](https://github.com/nlohmann/json/issues/1647) - Valgrind: bytes in 1 blocks are definitely lost [\#1646](https://github.com/nlohmann/json/issues/1646) - Convenient way to make 'basic\_json' accept 'QString' as an key type as well? [\#1640](https://github.com/nlohmann/json/issues/1640) - mongodb: nan, inf [\#1599](https://github.com/nlohmann/json/issues/1599) - Error in adl\_serializer [\#1590](https://github.com/nlohmann/json/issues/1590) - Injecting class during serialization [\#1584](https://github.com/nlohmann/json/issues/1584) - output\_adapter not user extensible [\#1534](https://github.com/nlohmann/json/issues/1534) - Inclusion of nlohmann/json.hpp causes OS/ABI to change on Linux [\#1410](https://github.com/nlohmann/json/issues/1410) - Add library versioning using inline namespaces [\#1394](https://github.com/nlohmann/json/issues/1394) - CBOR byte string support [\#1129](https://github.com/nlohmann/json/issues/1129) - How to deserialize array with derived objects [\#716](https://github.com/nlohmann/json/issues/716) - Add restriction for tuple specialization of to\_json [\#1826](https://github.com/nlohmann/json/pull/1826) ([cbegue](https://github.com/cbegue)) - Fix for \#1647 [\#1821](https://github.com/nlohmann/json/pull/1821) ([AnthonyVH](https://github.com/AnthonyVH)) - Fix issue \#1805 [\#1806](https://github.com/nlohmann/json/pull/1806) ([cbegue](https://github.com/cbegue)) - Fix some spelling errors - mostly in comments & documentation. [\#1803](https://github.com/nlohmann/json/pull/1803) ([flopp](https://github.com/flopp)) - Update Hedley to v11. [\#1799](https://github.com/nlohmann/json/pull/1799) ([nemequ](https://github.com/nemequ)) - iteration\_proxy: Fix integer truncation from std::size\_t to int [\#1797](https://github.com/nlohmann/json/pull/1797) ([t-b](https://github.com/t-b)) - appveyor.yml: Add MSVC 16 2019 support [\#1780](https://github.com/nlohmann/json/pull/1780) ([t-b](https://github.com/t-b)) - test/CMakeLists.txt: Use an explicit list instead of GLOB [\#1779](https://github.com/nlohmann/json/pull/1779) ([t-b](https://github.com/t-b)) - Make json\_pointer::back const \(resolves \#1764\) [\#1769](https://github.com/nlohmann/json/pull/1769) ([chris0x44](https://github.com/chris0x44)) - did you mean 'serialization'? [\#1767](https://github.com/nlohmann/json/pull/1767) ([0xflotus](https://github.com/0xflotus)) - Allow items\(\) to be used with custom string [\#1765](https://github.com/nlohmann/json/pull/1765) ([crazyjul](https://github.com/crazyjul)) - Cppcheck fixes [\#1760](https://github.com/nlohmann/json/pull/1760) ([Xav83](https://github.com/Xav83)) - Fix and add test's for SFINAE problem [\#1741](https://github.com/nlohmann/json/pull/1741) ([tete17](https://github.com/tete17)) - Fix clang sanitizer invocation [\#1728](https://github.com/nlohmann/json/pull/1728) ([t-b](https://github.com/t-b)) - Add gcc 9 and compile with experimental C++20 support [\#1724](https://github.com/nlohmann/json/pull/1724) ([t-b](https://github.com/t-b)) - Fix int64 min issue [\#1722](https://github.com/nlohmann/json/pull/1722) ([t-b](https://github.com/t-b)) - release: add singleinclude and meson.build to include.zip [\#1694](https://github.com/nlohmann/json/pull/1694) ([eli-schwartz](https://github.com/eli-schwartz)) ## [v3.7.0](https://github.com/nlohmann/json/releases/tag/v3.7.0) (2019-07-28) [Full Changelog](https://github.com/nlohmann/json/compare/v3.6.1...v3.7.0) - How can I retrieve uknown strings from json file in my C++ program. [\#1684](https://github.com/nlohmann/json/issues/1684) - contains\(\) is sometimes causing stack-based buffer overrun exceptions [\#1683](https://github.com/nlohmann/json/issues/1683) - How to deserialize arrays from json [\#1681](https://github.com/nlohmann/json/issues/1681) - Compilation failed in VS2015 [\#1678](https://github.com/nlohmann/json/issues/1678) - Why the compiled object file is so huge? [\#1677](https://github.com/nlohmann/json/issues/1677) - From Version 2.1.1 to 3.6.1 serialize std::set [\#1676](https://github.com/nlohmann/json/issues/1676) - Qt deprecation model halting compiltion [\#1675](https://github.com/nlohmann/json/issues/1675) - Build For Raspberry pi , Rapbery with new Compiler C++17 [\#1671](https://github.com/nlohmann/json/issues/1671) - Build from Raspberry pi [\#1667](https://github.com/nlohmann/json/issues/1667) - Can not translate map with integer key to dict string ? [\#1664](https://github.com/nlohmann/json/issues/1664) - Double type converts to scientific notation [\#1661](https://github.com/nlohmann/json/issues/1661) - Missing v3.6.1 tag on master branch [\#1657](https://github.com/nlohmann/json/issues/1657) - Support Fleese Binary Data Format [\#1654](https://github.com/nlohmann/json/issues/1654) - Suggestion: replace alternative tokens for !, && and || with their symbols [\#1652](https://github.com/nlohmann/json/issues/1652) - Build failure test-allocator.vcxproj [\#1651](https://github.com/nlohmann/json/issues/1651) - How to provide function json& to\_json\(\) which is similar as 'void to\_json\(json&j, const CObject& obj\)' ? [\#1650](https://github.com/nlohmann/json/issues/1650) - Can't throw exception when starting file is a number [\#1649](https://github.com/nlohmann/json/issues/1649) - to\_json / from\_json with nested type [\#1648](https://github.com/nlohmann/json/issues/1648) - How to create a json object from a std::string, created by j.dump? [\#1645](https://github.com/nlohmann/json/issues/1645) - Problem getting vector \(array\) of strings [\#1644](https://github.com/nlohmann/json/issues/1644) - json.hpp compilation issue with other typedefs with same name [\#1642](https://github.com/nlohmann/json/issues/1642) - nlohmann::adl\_serializer\::to\_json no matching overloaded function found [\#1641](https://github.com/nlohmann/json/issues/1641) - overwrite adl\_serializer\ to change behaviour [\#1638](https://github.com/nlohmann/json/issues/1638) - json.SelectToken\("Manufacturers.Products.Price"\); [\#1637](https://github.com/nlohmann/json/issues/1637) - Add json type as value [\#1636](https://github.com/nlohmann/json/issues/1636) - Unit conversion test error: conversion from 'nlohmann::json' to non-scalar type 'std::string\_view' requested [\#1634](https://github.com/nlohmann/json/issues/1634) - nlohmann VS JsonCpp by C++17 [\#1633](https://github.com/nlohmann/json/issues/1633) - To integrate an inline helper function that return type name as string [\#1632](https://github.com/nlohmann/json/issues/1632) - Return JSON as reference [\#1631](https://github.com/nlohmann/json/issues/1631) - Updating from an older version causes problems with assing a json object to a struct [\#1630](https://github.com/nlohmann/json/issues/1630) - Can without default constructor function for user defined classes when only to\_json is needed? [\#1629](https://github.com/nlohmann/json/issues/1629) - Compilation fails with clang 6.x-8.x in C++14 mode [\#1628](https://github.com/nlohmann/json/issues/1628) - Treating floating point as string [\#1627](https://github.com/nlohmann/json/issues/1627) - error parsing character Ã¥ [\#1626](https://github.com/nlohmann/json/issues/1626) - \[Help\] How to Improve Json Output Performance with Large Json Arrays [\#1624](https://github.com/nlohmann/json/issues/1624) - Suggested link changes for reporting new issues \[blob/develop/REAME.md and blob/develop/.github/CONTRIBUTING.md\] [\#1623](https://github.com/nlohmann/json/issues/1623) - Broken link to issue template in CONTRIBUTING.md [\#1622](https://github.com/nlohmann/json/issues/1622) - Missing word in README.md file [\#1621](https://github.com/nlohmann/json/issues/1621) - Package manager instructions in README for brew is incorrect [\#1620](https://github.com/nlohmann/json/issues/1620) - Building with Visual Studio 2019 [\#1619](https://github.com/nlohmann/json/issues/1619) - Precedence of to\_json and builtin harmful [\#1617](https://github.com/nlohmann/json/issues/1617) - The type json is missing from the html documentation [\#1616](https://github.com/nlohmann/json/issues/1616) - variant is not support in Release 3.6.1? [\#1615](https://github.com/nlohmann/json/issues/1615) - Replace assert with throw for const operator\[\] [\#1614](https://github.com/nlohmann/json/issues/1614) - Memory Overhead is Too High \(10x or more\) [\#1613](https://github.com/nlohmann/json/issues/1613) - program crash everytime, when other data type incomming in json stream as expected [\#1612](https://github.com/nlohmann/json/issues/1612) - Improved Enum Support [\#1611](https://github.com/nlohmann/json/issues/1611) - is it possible convert json object back to stl container ? [\#1610](https://github.com/nlohmann/json/issues/1610) - Add C++17-like emplace.back\(\) for arrays. [\#1609](https://github.com/nlohmann/json/issues/1609) - is\_nothrow\_copy\_constructible fails for json::const\_iterator on MSVC2015 x86 Debug build [\#1608](https://github.com/nlohmann/json/issues/1608) - Reading and writing array elements [\#1607](https://github.com/nlohmann/json/issues/1607) - Converting json::value to int [\#1605](https://github.com/nlohmann/json/issues/1605) - I have a vector of keys and and a string of value and i want to create nested json array [\#1604](https://github.com/nlohmann/json/issues/1604) - In compatible JSON object from nlohmann::json to nohman::json - unexpected end of input; expected '\[', '{', or a literal [\#1603](https://github.com/nlohmann/json/issues/1603) - json parser crash if having a large number integer in message [\#1602](https://github.com/nlohmann/json/issues/1602) - Value method with undocumented throwing 302 exception [\#1601](https://github.com/nlohmann/json/issues/1601) - Accessing value with json pointer adds key if not existing [\#1600](https://github.com/nlohmann/json/issues/1600) - README.md broken link to project documentation [\#1597](https://github.com/nlohmann/json/issues/1597) - Random Kudos: Thanks for your work on this! [\#1596](https://github.com/nlohmann/json/issues/1596) - json::parse return value and errors [\#1595](https://github.com/nlohmann/json/issues/1595) - initializer list constructor makes curly brace initialization fragile [\#1594](https://github.com/nlohmann/json/issues/1594) - trying to log message for missing keyword, difference between \["foo"\] and at\("foo"\) [\#1593](https://github.com/nlohmann/json/issues/1593) - std::string and std::wstring `to_json` [\#1592](https://github.com/nlohmann/json/issues/1592) - I have a C structure which I need to convert to a JSON. How do I do it? Haven't found proper examples so far. [\#1591](https://github.com/nlohmann/json/issues/1591) - dump\_escaped possible error ? [\#1589](https://github.com/nlohmann/json/issues/1589) - json::parse\(\) into a vector\ results in unhandled exception [\#1587](https://github.com/nlohmann/json/issues/1587) - push\_back\(\)/emplace\_back\(\) on array invalidates pointers to existing array items [\#1586](https://github.com/nlohmann/json/issues/1586) - Getting nlohmann::detail::parse\_error on JSON generated by nlohmann::json not sure why [\#1583](https://github.com/nlohmann/json/issues/1583) - getting error terminate called after throwing an instance of 'std::domain\_error' what\(\): cannot use at\(\) with string [\#1582](https://github.com/nlohmann/json/issues/1582) - how i create json file [\#1581](https://github.com/nlohmann/json/issues/1581) - prevent rounding of double datatype values [\#1580](https://github.com/nlohmann/json/issues/1580) - Documentation Container Overview Doesn't Reference Const Methods [\#1579](https://github.com/nlohmann/json/issues/1579) - Writing an array into a nlohmann::json object [\#1578](https://github.com/nlohmann/json/issues/1578) - compilation error when using with another library [\#1577](https://github.com/nlohmann/json/issues/1577) - Homebrew on OSX doesn't install cmake config file [\#1576](https://github.com/nlohmann/json/issues/1576) - JSON Parse Out of Range Error [\#1574](https://github.com/nlohmann/json/issues/1574) - Integrating into existing CMake Project [\#1573](https://github.com/nlohmann/json/issues/1573) - conversion to std::string failed [\#1571](https://github.com/nlohmann/json/issues/1571) - jPtr operation does not throw [\#1569](https://github.com/nlohmann/json/issues/1569) - How to generate dll file for this project [\#1568](https://github.com/nlohmann/json/issues/1568) - how to pass variable data to json in c [\#1567](https://github.com/nlohmann/json/issues/1567) - I want to achieve an upgraded function. [\#1566](https://github.com/nlohmann/json/issues/1566) - How to determine the type of elements read from a JSON array? [\#1564](https://github.com/nlohmann/json/issues/1564) - try\_get\_to [\#1563](https://github.com/nlohmann/json/issues/1563) - example code compile error [\#1562](https://github.com/nlohmann/json/issues/1562) - How to iterate over nested json object [\#1561](https://github.com/nlohmann/json/issues/1561) - Build Option/Separate Function to Allow to Throw on Duplicate Keys [\#1560](https://github.com/nlohmann/json/issues/1560) - Compiler Switches -Weffc++ & -Wshadow are throwing errors [\#1558](https://github.com/nlohmann/json/issues/1558) - warning: use of the 'nodiscard' attribute is a C++17 extension [\#1557](https://github.com/nlohmann/json/issues/1557) - Import/Export compressed JSON files [\#1556](https://github.com/nlohmann/json/issues/1556) - GDB renderers for json library [\#1554](https://github.com/nlohmann/json/issues/1554) - Is it possible to construct a json string object from a binary buffer? [\#1553](https://github.com/nlohmann/json/issues/1553) - json objects in list [\#1552](https://github.com/nlohmann/json/issues/1552) - Matrix output [\#1550](https://github.com/nlohmann/json/issues/1550) - Using json merge\_patch on ordered non-alphanumeric datasets [\#1549](https://github.com/nlohmann/json/issues/1549) - Invalid parsed value for big integer [\#1548](https://github.com/nlohmann/json/issues/1548) - Integrating with android ndk issues. [\#1547](https://github.com/nlohmann/json/issues/1547) - add noexcept json::value\("key", default\) method variant? [\#1546](https://github.com/nlohmann/json/issues/1546) - Thank you! 🙌 [\#1545](https://github.com/nlohmann/json/issues/1545) - Output and input matrix [\#1544](https://github.com/nlohmann/json/issues/1544) - Add regression tests for MSVC [\#1543](https://github.com/nlohmann/json/issues/1543) - \[Help Needed!\] Season of Docs [\#1542](https://github.com/nlohmann/json/issues/1542) - program still abort\(\) or exit\(\) with try catch [\#1541](https://github.com/nlohmann/json/issues/1541) - Have a json::type\_error exception because of JSON object [\#1540](https://github.com/nlohmann/json/issues/1540) - Using versioned namespaces [\#1539](https://github.com/nlohmann/json/issues/1539) - Quoted numbers [\#1538](https://github.com/nlohmann/json/issues/1538) - Reading a JSON file into an object [\#1537](https://github.com/nlohmann/json/issues/1537) - Releases 3.6.0 and 3.6.1 don't build on conda / windows [\#1536](https://github.com/nlohmann/json/issues/1536) - \[Clang\] warning: use of the 'nodiscard' attribute is a C++17 extension \[-Wc++17-extensions\] [\#1535](https://github.com/nlohmann/json/issues/1535) - wchar\_t/std::wstring json can be created but not accessed [\#1533](https://github.com/nlohmann/json/issues/1533) - json stringify [\#1532](https://github.com/nlohmann/json/issues/1532) - How can I use it from gcc on RPI [\#1528](https://github.com/nlohmann/json/issues/1528) - std::pair treated as an array instead of key-value in `std::vector>` [\#1520](https://github.com/nlohmann/json/issues/1520) - Excessive Memory Usage for Large Json File [\#1516](https://github.com/nlohmann/json/issues/1516) - SAX dumper [\#1512](https://github.com/nlohmann/json/issues/1512) - Conversion to user type containing a std::vector not working with documented approach [\#1511](https://github.com/nlohmann/json/issues/1511) - Inconsistent use of type alias. [\#1507](https://github.com/nlohmann/json/issues/1507) - Is there a current way to represent strings as json int? [\#1503](https://github.com/nlohmann/json/issues/1503) - Intermittent issues with loadJSON [\#1484](https://github.com/nlohmann/json/issues/1484) - use json construct std::string [\#1462](https://github.com/nlohmann/json/issues/1462) - JSON Creation [\#1461](https://github.com/nlohmann/json/issues/1461) - Null bytes in files are treated like EOF [\#1095](https://github.com/nlohmann/json/issues/1095) - Feature: to\_string\(const json& j\); [\#916](https://github.com/nlohmann/json/issues/916) - Use GNUInstallDirs instead of hard-coded path. [\#1673](https://github.com/nlohmann/json/pull/1673) ([ghost](https://github.com/ghost)) - Package Manager: MSYS2 \(pacman\) [\#1670](https://github.com/nlohmann/json/pull/1670) ([podsvirov](https://github.com/podsvirov)) - Fix json.hpp compilation issue with other typedefs with same name \(Issue \#1642\) [\#1643](https://github.com/nlohmann/json/pull/1643) ([kevinlul](https://github.com/kevinlul)) - Add explicit conversion from json to std::string\_view in conversion unit test [\#1639](https://github.com/nlohmann/json/pull/1639) ([taylorhoward92](https://github.com/taylorhoward92)) - Minor fixes in docs [\#1625](https://github.com/nlohmann/json/pull/1625) ([nickaein](https://github.com/nickaein)) - Fix broken links to documentation [\#1598](https://github.com/nlohmann/json/pull/1598) ([nickaein](https://github.com/nickaein)) - Added to\_string and added basic tests [\#1585](https://github.com/nlohmann/json/pull/1585) ([Macr0Nerd](https://github.com/Macr0Nerd)) - Regression tests for MSVC [\#1570](https://github.com/nlohmann/json/pull/1570) ([nickaein](https://github.com/nickaein)) - Fix/1511 [\#1555](https://github.com/nlohmann/json/pull/1555) ([theodelrieu](https://github.com/theodelrieu)) - Remove C++17 extension warning from clang; \#1535 [\#1551](https://github.com/nlohmann/json/pull/1551) ([heavywatal](https://github.com/heavywatal)) - moved from Catch to doctest for unit tests [\#1439](https://github.com/nlohmann/json/pull/1439) ([onqtam](https://github.com/onqtam)) ## [v3.6.1](https://github.com/nlohmann/json/releases/tag/v3.6.1) (2019-03-20) [Full Changelog](https://github.com/nlohmann/json/compare/3.6.1...v3.6.1) ## [3.6.1](https://github.com/nlohmann/json/releases/tag/3.6.1) (2019-03-20) [Full Changelog](https://github.com/nlohmann/json/compare/v3.6.0...3.6.1) - Failed to build with \ [\#1531](https://github.com/nlohmann/json/issues/1531) - Compiling 3.6.0 with GCC \> 7, array vs std::array \#590 is back [\#1530](https://github.com/nlohmann/json/issues/1530) - 3.6.0: warning: missing initializer for member 'std::array\::\_M\_elems' \[-Wmissing-field-initializers\] [\#1527](https://github.com/nlohmann/json/issues/1527) - unable to parse json [\#1525](https://github.com/nlohmann/json/issues/1525) ## [v3.6.0](https://github.com/nlohmann/json/releases/tag/v3.6.0) (2019-03-19) [Full Changelog](https://github.com/nlohmann/json/compare/v3.5.0...v3.6.0) - How can I turn a string of a json array into a json array? [\#1526](https://github.com/nlohmann/json/issues/1526) - Minor: missing a std:: namespace tag [\#1521](https://github.com/nlohmann/json/issues/1521) - how to precision to four decimal for double when use to\_json [\#1519](https://github.com/nlohmann/json/issues/1519) - error parse [\#1518](https://github.com/nlohmann/json/issues/1518) - Compile error: template argument deduction/substitution failed [\#1515](https://github.com/nlohmann/json/issues/1515) - std::complex type [\#1510](https://github.com/nlohmann/json/issues/1510) - CBOR byte string support [\#1509](https://github.com/nlohmann/json/issues/1509) - Compilation error getting a std::pair\<\> on latest VS 2017 compiler [\#1506](https://github.com/nlohmann/json/issues/1506) - "Integration" section of documentation needs update? [\#1505](https://github.com/nlohmann/json/issues/1505) - Json object from string from a TCP socket [\#1504](https://github.com/nlohmann/json/issues/1504) - MSVC warning C4946 \("reinterpret\_cast used between related classes"\) compiling json.hpp [\#1502](https://github.com/nlohmann/json/issues/1502) - How to programmatically fill an n-th dimensional JSON object? [\#1501](https://github.com/nlohmann/json/issues/1501) - Error compiling with clang and `JSON_NOEXCEPTION`: need to include `cstdlib` [\#1500](https://github.com/nlohmann/json/issues/1500) - The code compiles unsuccessfully with android-ndk-r10e [\#1499](https://github.com/nlohmann/json/issues/1499) - Cmake 3.1 in develop, when is it likely to make it into a stable release? [\#1498](https://github.com/nlohmann/json/issues/1498) - Some Help please object inside array [\#1494](https://github.com/nlohmann/json/issues/1494) - How to get data into vector of user-defined type from a Json object [\#1493](https://github.com/nlohmann/json/issues/1493) - how to find subelement without loop [\#1490](https://github.com/nlohmann/json/issues/1490) - json to std::map [\#1487](https://github.com/nlohmann/json/issues/1487) - Type in README.md [\#1486](https://github.com/nlohmann/json/issues/1486) - Error in parsing and reading msgpack-lite [\#1485](https://github.com/nlohmann/json/issues/1485) - Compiling issues with libc 2.12 [\#1483](https://github.com/nlohmann/json/issues/1483) - How do I use reference or pointer binding values? [\#1482](https://github.com/nlohmann/json/issues/1482) - Compilation fails in MSVC with the Microsoft Language Extensions disabled [\#1481](https://github.com/nlohmann/json/issues/1481) - Functional visit [\#1480](https://github.com/nlohmann/json/issues/1480) - \[Question\] Unescaped dump [\#1479](https://github.com/nlohmann/json/issues/1479) - Some Help please [\#1478](https://github.com/nlohmann/json/issues/1478) - Global variables are stored within the JSON file, how do I declare them as global variables when I read them out in my C++ program? [\#1476](https://github.com/nlohmann/json/issues/1476) - Unable to modify one of the values within the JSON file, and save it [\#1475](https://github.com/nlohmann/json/issues/1475) - Documentation of parse function has two identical @pre causes [\#1473](https://github.com/nlohmann/json/issues/1473) - GCC 9.0 build failure [\#1472](https://github.com/nlohmann/json/issues/1472) - Can we have an `exists()` method? [\#1471](https://github.com/nlohmann/json/issues/1471) - How to parse multi object json from file? [\#1470](https://github.com/nlohmann/json/issues/1470) - How to returns the name of the upper object? [\#1467](https://github.com/nlohmann/json/issues/1467) - Error: "tuple\_size" has already been declared in the current scope [\#1466](https://github.com/nlohmann/json/issues/1466) - Checking keys of two jsons against eachother [\#1465](https://github.com/nlohmann/json/issues/1465) - Disable installation when used as meson subproject [\#1463](https://github.com/nlohmann/json/issues/1463) - Unpack list of integers to a std::vector\ [\#1460](https://github.com/nlohmann/json/issues/1460) - Implement DRY definition of JSON representation of a c++ class [\#1459](https://github.com/nlohmann/json/issues/1459) - json.exception.type\_error.305 with GCC 4.9 when using C++ {} initializer [\#1458](https://github.com/nlohmann/json/issues/1458) - API to convert an "uninitialized" json into an empty object or empty array [\#1456](https://github.com/nlohmann/json/issues/1456) - How to parse a vector of objects with const attributes [\#1453](https://github.com/nlohmann/json/issues/1453) - NLOHMANN\_JSON\_SERIALIZE\_ENUM potentially requires duplicate definitions [\#1450](https://github.com/nlohmann/json/issues/1450) - Question about making json object from file directory [\#1449](https://github.com/nlohmann/json/issues/1449) - .get\(\) throws error if used with userdefined structs in unordered\_map [\#1448](https://github.com/nlohmann/json/issues/1448) - Integer Overflow \(OSS-Fuzz 12506\) [\#1447](https://github.com/nlohmann/json/issues/1447) - If a string has too many invalid UTF-8 characters, json::dump attempts to index an array out of bounds. [\#1445](https://github.com/nlohmann/json/issues/1445) - Setting values of .JSON file [\#1444](https://github.com/nlohmann/json/issues/1444) - alias object\_t::key\_type in basic\_json [\#1442](https://github.com/nlohmann/json/issues/1442) - Latest Ubuntu package is 2.1.1 [\#1438](https://github.com/nlohmann/json/issues/1438) - lexer.hpp\(1363\) '\_snprintf': is not a member | Visualstudio 2017 [\#1437](https://github.com/nlohmann/json/issues/1437) - Static method invites inadvertent logic error. [\#1433](https://github.com/nlohmann/json/issues/1433) - EOS compilation produces "fatal error: 'nlohmann/json.hpp' file not found" [\#1432](https://github.com/nlohmann/json/issues/1432) - Support for bad commas [\#1429](https://github.com/nlohmann/json/issues/1429) - Please have one base exception class for all json exceptions [\#1427](https://github.com/nlohmann/json/issues/1427) - Compilation warning: 'tuple\_size' defined as a class template here but previously declared as a struct template [\#1426](https://github.com/nlohmann/json/issues/1426) - Which version can be used with GCC 4.8.2 ? [\#1424](https://github.com/nlohmann/json/issues/1424) - Ignore nullptr values on constructing json object from a container [\#1422](https://github.com/nlohmann/json/issues/1422) - Support for custom float precision via unquoted strings [\#1421](https://github.com/nlohmann/json/issues/1421) - It is possible to call `json::find` with a json\_pointer as argument. This causes runtime UB/crash. [\#1418](https://github.com/nlohmann/json/issues/1418) - Dump throwing exception [\#1416](https://github.com/nlohmann/json/issues/1416) - Build error [\#1415](https://github.com/nlohmann/json/issues/1415) - Append version to include.zip [\#1412](https://github.com/nlohmann/json/issues/1412) - error C2039: '\_snprintf': is not a member of 'std' - Windows [\#1408](https://github.com/nlohmann/json/issues/1408) - Deserializing to vector [\#1407](https://github.com/nlohmann/json/issues/1407) - Efficient way to set a `json` object as value into another `json` key [\#1406](https://github.com/nlohmann/json/issues/1406) - Document return value of parse\(\) when allow\_exceptions == false and parsing fails [\#1405](https://github.com/nlohmann/json/issues/1405) - Unexpected behaviour with structured binding [\#1404](https://github.com/nlohmann/json/issues/1404) - Which native types does get\\(\) allow? [\#1403](https://github.com/nlohmann/json/issues/1403) - Add something like Json::StaticString [\#1402](https://github.com/nlohmann/json/issues/1402) - -Wmismatched-tags in 3.5.0? [\#1401](https://github.com/nlohmann/json/issues/1401) - Coverity Scan reports an UNCAUGHT\_EXCEPT issue [\#1400](https://github.com/nlohmann/json/issues/1400) - fff [\#1399](https://github.com/nlohmann/json/issues/1399) - sorry this is not an issue, just a Question, How to change a key value in a file and save it ? [\#1398](https://github.com/nlohmann/json/issues/1398) - appveyor x64 builds appear to be using Win32 toolset [\#1374](https://github.com/nlohmann/json/issues/1374) - Serializing/Deserializing a Class containing a vector of itself [\#1373](https://github.com/nlohmann/json/issues/1373) - Retrieving array elements. [\#1369](https://github.com/nlohmann/json/issues/1369) - Deserialize [\#1366](https://github.com/nlohmann/json/issues/1366) - call of overloaded for push\_back and operator+= is ambiguous [\#1352](https://github.com/nlohmann/json/issues/1352) - got an error and cann't figure it out [\#1351](https://github.com/nlohmann/json/issues/1351) - Improve number-to-string conversion [\#1334](https://github.com/nlohmann/json/issues/1334) - Implicit type conversion error on MSVC [\#1333](https://github.com/nlohmann/json/issues/1333) - NuGet Package [\#1132](https://github.com/nlohmann/json/issues/1132) - Change macros to numeric\_limits [\#1514](https://github.com/nlohmann/json/pull/1514) ([naszta](https://github.com/naszta)) - fix GCC 7.1.1 - 7.2.1 on CentOS [\#1496](https://github.com/nlohmann/json/pull/1496) ([lieff](https://github.com/lieff)) - Update Buckaroo instructions in README.md [\#1495](https://github.com/nlohmann/json/pull/1495) ([njlr](https://github.com/njlr)) - Fix gcc9 build error test/src/unit-allocator.cpp \(Issue \#1472\) [\#1492](https://github.com/nlohmann/json/pull/1492) ([stac47](https://github.com/stac47)) - Fix typo in README.md [\#1491](https://github.com/nlohmann/json/pull/1491) ([nickaein](https://github.com/nickaein)) - Do proper endian conversions [\#1489](https://github.com/nlohmann/json/pull/1489) ([andreas-schwab](https://github.com/andreas-schwab)) - Fix documentation [\#1477](https://github.com/nlohmann/json/pull/1477) ([nickaein](https://github.com/nickaein)) - Implement contains\(\) member function [\#1474](https://github.com/nlohmann/json/pull/1474) ([nickaein](https://github.com/nickaein)) - Add operator/= and operator/ to construct a JSON pointer by appending two JSON pointers [\#1469](https://github.com/nlohmann/json/pull/1469) ([garethsb](https://github.com/garethsb)) - Disable Clang -Wmismatched-tags warning on tuple\_size / tuple\_element [\#1468](https://github.com/nlohmann/json/pull/1468) ([past-due](https://github.com/past-due)) - Disable installation when used as meson subproject. \#1463 [\#1464](https://github.com/nlohmann/json/pull/1464) ([elvisoric](https://github.com/elvisoric)) - docs: README typo [\#1455](https://github.com/nlohmann/json/pull/1455) ([wythe](https://github.com/wythe)) - remove extra semicolon from readme [\#1451](https://github.com/nlohmann/json/pull/1451) ([Afforix](https://github.com/Afforix)) - attempt to fix \#1445, flush buffer in serializer::dump\_escaped in UTF8\_REJECT case. [\#1446](https://github.com/nlohmann/json/pull/1446) ([scinart](https://github.com/scinart)) - Use C++11 features supported by CMake 3.1. [\#1441](https://github.com/nlohmann/json/pull/1441) ([iwanders](https://github.com/iwanders)) - :rotating\_light: fixed unused variable warning [\#1435](https://github.com/nlohmann/json/pull/1435) ([pboettch](https://github.com/pboettch)) - allow push\_back\(\) and pop\_back\(\) calls on json\_pointer [\#1434](https://github.com/nlohmann/json/pull/1434) ([pboettch](https://github.com/pboettch)) - Add instructions about using nlohmann/json with the conda package manager [\#1430](https://github.com/nlohmann/json/pull/1430) ([nicoddemus](https://github.com/nicoddemus)) - Updated year in README.md [\#1425](https://github.com/nlohmann/json/pull/1425) ([jef](https://github.com/jef)) - Fixed broken links in the README file [\#1423](https://github.com/nlohmann/json/pull/1423) ([skypjack](https://github.com/skypjack)) - Fixed broken links in the README file [\#1420](https://github.com/nlohmann/json/pull/1420) ([skypjack](https://github.com/skypjack)) - docs: typo in README [\#1417](https://github.com/nlohmann/json/pull/1417) ([wythe](https://github.com/wythe)) - Fix x64 target platform for appveyor [\#1414](https://github.com/nlohmann/json/pull/1414) ([nickaein](https://github.com/nickaein)) - Improve dump\_integer performance [\#1411](https://github.com/nlohmann/json/pull/1411) ([nickaein](https://github.com/nickaein)) - buildsystem: relax requirement on cmake version [\#1409](https://github.com/nlohmann/json/pull/1409) ([yann-morin-1998](https://github.com/yann-morin-1998)) - CMake: Optional Install if Embedded [\#1330](https://github.com/nlohmann/json/pull/1330) ([ax3l](https://github.com/ax3l)) ## [v3.5.0](https://github.com/nlohmann/json/releases/tag/v3.5.0) (2018-12-21) [Full Changelog](https://github.com/nlohmann/json/compare/v3.4.0...v3.5.0) - Copyconstructor inserts original into array with single element [\#1397](https://github.com/nlohmann/json/issues/1397) - Get value without explicit typecasting [\#1395](https://github.com/nlohmann/json/issues/1395) - Big file parsing [\#1393](https://github.com/nlohmann/json/issues/1393) - some static analysis warning at line 11317 [\#1390](https://github.com/nlohmann/json/issues/1390) - Adding Structured Binding Support [\#1388](https://github.com/nlohmann/json/issues/1388) - map\ exhibits unexpected behavior [\#1387](https://github.com/nlohmann/json/issues/1387) - Error Code Return [\#1386](https://github.com/nlohmann/json/issues/1386) - using unordered\_map as object type [\#1385](https://github.com/nlohmann/json/issues/1385) - float precision [\#1384](https://github.com/nlohmann/json/issues/1384) - \[json.exception.type\_error.316\] invalid UTF-8 byte at index 1: 0xC3 [\#1383](https://github.com/nlohmann/json/issues/1383) - Inconsistent Constructor \(GCC vs. Clang\) [\#1381](https://github.com/nlohmann/json/issues/1381) - \#define or || [\#1379](https://github.com/nlohmann/json/issues/1379) - How to iterate inside the values ? [\#1377](https://github.com/nlohmann/json/issues/1377) - items\(\) unable to get the elements [\#1375](https://github.com/nlohmann/json/issues/1375) - conversion json to std::map doesn't work for types \ [\#1372](https://github.com/nlohmann/json/issues/1372) - A minor issue in the build instructions [\#1371](https://github.com/nlohmann/json/issues/1371) - Using this library without stream ? [\#1370](https://github.com/nlohmann/json/issues/1370) - Writing and reading BSON data [\#1368](https://github.com/nlohmann/json/issues/1368) - Retrieving array elements from object type iterator. [\#1367](https://github.com/nlohmann/json/issues/1367) - json::dump\(\) silently crashes if items contain accented letters [\#1365](https://github.com/nlohmann/json/issues/1365) - warnings in MSVC \(2015\) in 3.4.0 related to bool... [\#1364](https://github.com/nlohmann/json/issues/1364) - Cant compile with -C++17 and beyond compiler options [\#1362](https://github.com/nlohmann/json/issues/1362) - json to concrete type conversion through reference or pointer fails [\#1361](https://github.com/nlohmann/json/issues/1361) - the first attributes of JSON string is misplaced [\#1360](https://github.com/nlohmann/json/issues/1360) - Copy-construct using initializer-list converts objects to arrays [\#1359](https://github.com/nlohmann/json/issues/1359) - About value\(key, default\_value\) and operator\[\]\(key\) [\#1358](https://github.com/nlohmann/json/issues/1358) - Problem with printing json response object [\#1356](https://github.com/nlohmann/json/issues/1356) - Serializing pointer segfaults [\#1355](https://github.com/nlohmann/json/issues/1355) - Read `long long int` data as a number. [\#1354](https://github.com/nlohmann/json/issues/1354) - eclipse oxygen in ubuntu get\ is ambiguous [\#1353](https://github.com/nlohmann/json/issues/1353) - Can't build on Visual Studio 2017 v15.8.9 [\#1350](https://github.com/nlohmann/json/issues/1350) - cannot parse from string? [\#1349](https://github.com/nlohmann/json/issues/1349) - Error: out\_of\_range [\#1348](https://github.com/nlohmann/json/issues/1348) - expansion pattern 'CompatibleObjectType' contains no argument packs, with CUDA 10 [\#1347](https://github.com/nlohmann/json/issues/1347) - Unable to update a value for a nested\(multi-level\) json file [\#1344](https://github.com/nlohmann/json/issues/1344) - Fails to compile when std::iterator\_traits is not SFINAE friendly. [\#1341](https://github.com/nlohmann/json/issues/1341) - EOF flag not set on exhausted input streams. [\#1340](https://github.com/nlohmann/json/issues/1340) - Shadowed Member in merge\_patch [\#1339](https://github.com/nlohmann/json/issues/1339) - Periods/literal dots in keys? [\#1338](https://github.com/nlohmann/json/issues/1338) - Protect macro expansion of commonly defined macros [\#1337](https://github.com/nlohmann/json/issues/1337) - How to validate an input before parsing? [\#1336](https://github.com/nlohmann/json/issues/1336) - Non-verifying dump\(\) alternative for debugging/logging needed [\#1335](https://github.com/nlohmann/json/issues/1335) - Json Libarary is not responding for me in c++ [\#1332](https://github.com/nlohmann/json/issues/1332) - Question - how to find an object in an array [\#1331](https://github.com/nlohmann/json/issues/1331) - Nesting additional data in json object [\#1328](https://github.com/nlohmann/json/issues/1328) - can to\_json\(\) be defined inside a class? [\#1324](https://github.com/nlohmann/json/issues/1324) - CodeBlocks IDE can't find `json.hpp` header [\#1318](https://github.com/nlohmann/json/issues/1318) - Change json\_pointer to provide an iterator begin/end/etc, don't use vectors, and also enable string\_view [\#1312](https://github.com/nlohmann/json/issues/1312) - Xcode - adding it to library [\#1300](https://github.com/nlohmann/json/issues/1300) - unicode: accept char16\_t, char32\_t sequences [\#1298](https://github.com/nlohmann/json/issues/1298) - unicode: char16\_t\* is compiler error, but char16\_t\[\] is accepted [\#1297](https://github.com/nlohmann/json/issues/1297) - Dockerfile Project Help Needed [\#1296](https://github.com/nlohmann/json/issues/1296) - Comparisons between large unsigned and negative signed integers [\#1295](https://github.com/nlohmann/json/issues/1295) - CMake alias to `nlohmann::json` [\#1291](https://github.com/nlohmann/json/issues/1291) - Release zips without tests [\#1285](https://github.com/nlohmann/json/issues/1285) - separate object\_t::key\_type from basic\_json::key\_type, and use an allocator which returns object\_t::key\_type [\#1274](https://github.com/nlohmann/json/issues/1274) - Is there a nice way to associate external values with json elements? [\#1256](https://github.com/nlohmann/json/issues/1256) - Delete by json\_pointer [\#1248](https://github.com/nlohmann/json/issues/1248) - Expose lexer, as a StAX parser [\#1219](https://github.com/nlohmann/json/issues/1219) - Subclassing json\(\) & error on recursive load [\#1201](https://github.com/nlohmann/json/issues/1201) - Check value for existence by json\_pointer [\#1194](https://github.com/nlohmann/json/issues/1194) - Feature/add file input adapter [\#1392](https://github.com/nlohmann/json/pull/1392) ([dumarjo](https://github.com/dumarjo)) - Added Support for Structured Bindings [\#1391](https://github.com/nlohmann/json/pull/1391) ([pratikpc](https://github.com/pratikpc)) - Link to issue \#958 broken [\#1382](https://github.com/nlohmann/json/pull/1382) ([kjpus](https://github.com/kjpus)) - readme: fix typo [\#1380](https://github.com/nlohmann/json/pull/1380) ([manu-chroma](https://github.com/manu-chroma)) - recommend using explicit from JSON conversions [\#1363](https://github.com/nlohmann/json/pull/1363) ([theodelrieu](https://github.com/theodelrieu)) - Fix merge\_patch shadow warning [\#1346](https://github.com/nlohmann/json/pull/1346) ([ax3l](https://github.com/ax3l)) - Allow installation via Meson [\#1345](https://github.com/nlohmann/json/pull/1345) ([mpoquet](https://github.com/mpoquet)) - Set eofbit on exhausted input stream. [\#1343](https://github.com/nlohmann/json/pull/1343) ([mefyl](https://github.com/mefyl)) - Add a SFINAE friendly iterator\_traits and use that instead. [\#1342](https://github.com/nlohmann/json/pull/1342) ([dgavedissian](https://github.com/dgavedissian)) - Fix EOL Whitespaces & CMake Spelling [\#1329](https://github.com/nlohmann/json/pull/1329) ([ax3l](https://github.com/ax3l)) ## [v3.4.0](https://github.com/nlohmann/json/releases/tag/v3.4.0) (2018-10-30) [Full Changelog](https://github.com/nlohmann/json/compare/v3.3.0...v3.4.0) - Big uint64\_t values are serialized wrong [\#1327](https://github.com/nlohmann/json/issues/1327) - \[Question\] Efficient check for equivalency? [\#1325](https://github.com/nlohmann/json/issues/1325) - Can't use ifstream and .clear\(\) [\#1321](https://github.com/nlohmann/json/issues/1321) - \[Warning\] -Wparentheses on line 555 on single\_include [\#1319](https://github.com/nlohmann/json/issues/1319) - Compilation error using at and find with enum struct [\#1316](https://github.com/nlohmann/json/issues/1316) - Parsing JSON from a web address [\#1311](https://github.com/nlohmann/json/issues/1311) - How to convert JSON to Struct with embeded subject [\#1310](https://github.com/nlohmann/json/issues/1310) - Null safety/coalescing function? [\#1309](https://github.com/nlohmann/json/issues/1309) - Building fails using single include file: json.hpp [\#1308](https://github.com/nlohmann/json/issues/1308) - json::parse\(std::string\) Exception inside packaged Lib [\#1306](https://github.com/nlohmann/json/issues/1306) - Problem in Dockerfile with installation of library [\#1304](https://github.com/nlohmann/json/issues/1304) - compile error in from\_json converting to container with std::pair [\#1299](https://github.com/nlohmann/json/issues/1299) - Json that I am trying to parse, and I am lost Structure Array below top level [\#1293](https://github.com/nlohmann/json/issues/1293) - Serializing std::variant causes stack overflow [\#1292](https://github.com/nlohmann/json/issues/1292) - How do I go about customising from\_json to support \_\_int128\_t/\_\_uint128\_t? [\#1290](https://github.com/nlohmann/json/issues/1290) - merge\_patch: inconsistent behaviour merging empty sub-object [\#1289](https://github.com/nlohmann/json/issues/1289) - Buffer over/underrun using UBJson? [\#1288](https://github.com/nlohmann/json/issues/1288) - Enable the latest C++ standard with Visual Studio [\#1287](https://github.com/nlohmann/json/issues/1287) - truncation of constant value in to\_cbor\(\) [\#1286](https://github.com/nlohmann/json/issues/1286) - eosio.wasmsdk error [\#1284](https://github.com/nlohmann/json/issues/1284) - use the same interface for writing arrays and non-arrays [\#1283](https://github.com/nlohmann/json/issues/1283) - How to read json file with optional entries and entries with different types [\#1281](https://github.com/nlohmann/json/issues/1281) - merge result not as espected [\#1279](https://github.com/nlohmann/json/issues/1279) - how to get only "name" from below json [\#1278](https://github.com/nlohmann/json/issues/1278) - syntax error on right json string [\#1276](https://github.com/nlohmann/json/issues/1276) - Parsing JSON Array where members have no key, using custom types [\#1267](https://github.com/nlohmann/json/issues/1267) - I get a json exception periodically from json::parse for the same json [\#1263](https://github.com/nlohmann/json/issues/1263) - serialize std::variant\<...\> [\#1261](https://github.com/nlohmann/json/issues/1261) - GCC 8.2.1. Compilation error: invalid conversion from... [\#1246](https://github.com/nlohmann/json/issues/1246) - BSON support [\#1244](https://github.com/nlohmann/json/issues/1244) - enum to json mapping [\#1208](https://github.com/nlohmann/json/issues/1208) - Soften the landing when dumping non-UTF8 strings \(type\_error.316 exception\) [\#1198](https://github.com/nlohmann/json/issues/1198) - Add macro to define enum/JSON mapping [\#1323](https://github.com/nlohmann/json/pull/1323) ([nlohmann](https://github.com/nlohmann)) - Add BSON support [\#1320](https://github.com/nlohmann/json/pull/1320) ([nlohmann](https://github.com/nlohmann)) - Properly convert constants to CharType [\#1315](https://github.com/nlohmann/json/pull/1315) ([nlohmann](https://github.com/nlohmann)) - Allow to set error handler for decoding errors [\#1314](https://github.com/nlohmann/json/pull/1314) ([nlohmann](https://github.com/nlohmann)) - Add Meson related info to README [\#1305](https://github.com/nlohmann/json/pull/1305) ([koponomarenko](https://github.com/koponomarenko)) - Improve diagnostic messages for binary formats [\#1303](https://github.com/nlohmann/json/pull/1303) ([nlohmann](https://github.com/nlohmann)) - add new is\_constructible\_\* traits used in from\_json [\#1301](https://github.com/nlohmann/json/pull/1301) ([theodelrieu](https://github.com/theodelrieu)) - add constraints for variadic json\_ref constructors [\#1294](https://github.com/nlohmann/json/pull/1294) ([theodelrieu](https://github.com/theodelrieu)) - Improve diagnostic messages [\#1282](https://github.com/nlohmann/json/pull/1282) ([nlohmann](https://github.com/nlohmann)) - Removed linter warnings [\#1280](https://github.com/nlohmann/json/pull/1280) ([nlohmann](https://github.com/nlohmann)) - Thirdparty benchmark: Fix Clang detection. [\#1277](https://github.com/nlohmann/json/pull/1277) ([Lord-Kamina](https://github.com/Lord-Kamina)) ## [v3.3.0](https://github.com/nlohmann/json/releases/tag/v3.3.0) (2018-10-05) [Full Changelog](https://github.com/nlohmann/json/compare/3.3.0...v3.3.0) - Fix warning C4127: conditional expression is constant [\#1272](https://github.com/nlohmann/json/pull/1272) ([antonioborondo](https://github.com/antonioborondo)) - Turn off additional deprecation warnings for GCC. [\#1271](https://github.com/nlohmann/json/pull/1271) ([chuckatkins](https://github.com/chuckatkins)) - docs: Add additional CMake documentation [\#1270](https://github.com/nlohmann/json/pull/1270) ([chuckatkins](https://github.com/chuckatkins)) - unit-testsuites.cpp: fix hangup if file not found [\#1262](https://github.com/nlohmann/json/pull/1262) ([knilch0r](https://github.com/knilch0r)) - Fix broken cmake imported target alias [\#1260](https://github.com/nlohmann/json/pull/1260) ([chuckatkins](https://github.com/chuckatkins)) - GCC 48 [\#1257](https://github.com/nlohmann/json/pull/1257) ([henryiii](https://github.com/henryiii)) - Add version and license to meson.build [\#1252](https://github.com/nlohmann/json/pull/1252) ([koponomarenko](https://github.com/koponomarenko)) - \#1179 Reordered the code. It seems to stop clang 3.4.2 in RHEL 7 from crash… [\#1249](https://github.com/nlohmann/json/pull/1249) ([LEgregius](https://github.com/LEgregius)) - Use a version check to provide backwards comatible CMake imported target names [\#1245](https://github.com/nlohmann/json/pull/1245) ([chuckatkins](https://github.com/chuckatkins)) - Fix issue \#1237 [\#1238](https://github.com/nlohmann/json/pull/1238) ([theodelrieu](https://github.com/theodelrieu)) - Add a get overload taking a parameter. [\#1231](https://github.com/nlohmann/json/pull/1231) ([theodelrieu](https://github.com/theodelrieu)) - Move lambda out of unevaluated context [\#1230](https://github.com/nlohmann/json/pull/1230) ([mandreyel](https://github.com/mandreyel)) - Remove static asserts [\#1228](https://github.com/nlohmann/json/pull/1228) ([theodelrieu](https://github.com/theodelrieu)) - Better error 305 [\#1221](https://github.com/nlohmann/json/pull/1221) ([rivertam](https://github.com/rivertam)) - Fix \#1213 [\#1214](https://github.com/nlohmann/json/pull/1214) ([simnalamburt](https://github.com/simnalamburt)) - Export package to allow builds without installing [\#1202](https://github.com/nlohmann/json/pull/1202) ([dennisfischer](https://github.com/dennisfischer)) ## [3.3.0](https://github.com/nlohmann/json/releases/tag/3.3.0) (2018-10-05) [Full Changelog](https://github.com/nlohmann/json/compare/v3.2.0...3.3.0) - When key is not found print the key name into error too [\#1273](https://github.com/nlohmann/json/issues/1273) - Visual Studio 2017 15.8.5 "conditional expression is constant" warning on Line 1851 in json.hpp [\#1268](https://github.com/nlohmann/json/issues/1268) - how can we get this working on WSL? [\#1264](https://github.com/nlohmann/json/issues/1264) - Help needed [\#1259](https://github.com/nlohmann/json/issues/1259) - A way to get to a JSON values "key" [\#1258](https://github.com/nlohmann/json/issues/1258) - While compiling got 76 errors [\#1255](https://github.com/nlohmann/json/issues/1255) - Two blackslashes on json output file [\#1253](https://github.com/nlohmann/json/issues/1253) - Including nlohmann the badwrong way. [\#1250](https://github.com/nlohmann/json/issues/1250) - how to build with clang? [\#1247](https://github.com/nlohmann/json/issues/1247) - Cmake target\_link\_libraries unable to find nlohmann\_json since version 3.2.0 [\#1243](https://github.com/nlohmann/json/issues/1243) - \[Question\] Access to end\(\) iterator reference [\#1242](https://github.com/nlohmann/json/issues/1242) - Parsing different json format [\#1241](https://github.com/nlohmann/json/issues/1241) - Parsing Multiple JSON Files [\#1240](https://github.com/nlohmann/json/issues/1240) - Doesn't compile under C++17 [\#1239](https://github.com/nlohmann/json/issues/1239) - Conversion operator for nlohmann::json is not SFINAE friendly [\#1237](https://github.com/nlohmann/json/issues/1237) - Custom deserialization of number\_float\_t [\#1236](https://github.com/nlohmann/json/issues/1236) - deprecated-declarations warnings when compiling tests with GCC 8.2.1. [\#1233](https://github.com/nlohmann/json/issues/1233) - Incomplete type with json\_fwd.hpp [\#1232](https://github.com/nlohmann/json/issues/1232) - Parse Error [\#1229](https://github.com/nlohmann/json/issues/1229) - json::get function with argument [\#1227](https://github.com/nlohmann/json/issues/1227) - questions regarding from\_json [\#1226](https://github.com/nlohmann/json/issues/1226) - Lambda in unevaluated context [\#1225](https://github.com/nlohmann/json/issues/1225) - NLohmann doesn't compile when enabling strict warning policies [\#1224](https://github.com/nlohmann/json/issues/1224) - Creating array of objects [\#1223](https://github.com/nlohmann/json/issues/1223) - Somewhat unhelpful error message "cannot use operator\[\] with object" [\#1220](https://github.com/nlohmann/json/issues/1220) - single\_include json.hpp [\#1218](https://github.com/nlohmann/json/issues/1218) - Maps with enum class keys which are convertible to JSON strings should be converted to JSON dictionaries [\#1217](https://github.com/nlohmann/json/issues/1217) - Adding JSON Array to the Array [\#1216](https://github.com/nlohmann/json/issues/1216) - Best way to output a vector of a given type to json [\#1215](https://github.com/nlohmann/json/issues/1215) - compiler warning: double definition of macro JSON\_INTERNAL\_CATCH [\#1213](https://github.com/nlohmann/json/issues/1213) - Compilation error when using MOCK\_METHOD1 from GMock and nlohmann::json [\#1212](https://github.com/nlohmann/json/issues/1212) - Issues parsing a previously encoded binary \(non-UTF8\) string. [\#1211](https://github.com/nlohmann/json/issues/1211) - Yet another ordering question: char \* and parse\(\) [\#1209](https://github.com/nlohmann/json/issues/1209) - Error using gcc 8.1.0 on Ubuntu 14.04 [\#1207](https://github.com/nlohmann/json/issues/1207) - "type must be string, but is " std::string\(j.type\_name\(\) [\#1206](https://github.com/nlohmann/json/issues/1206) - Returning empty json object from a function of type const json& ? [\#1205](https://github.com/nlohmann/json/issues/1205) - VS2017 compiler suggests using constexpr if [\#1204](https://github.com/nlohmann/json/issues/1204) - Template instatiation error on compiling [\#1203](https://github.com/nlohmann/json/issues/1203) - BUG - json dump field with unicode -\> array of ints \(instead of string\) [\#1197](https://github.com/nlohmann/json/issues/1197) - Compile error using Code::Blocks // mingw-w64 GCC 8.1.0 - "Incomplete Type" [\#1193](https://github.com/nlohmann/json/issues/1193) - SEGFAULT on arm target [\#1190](https://github.com/nlohmann/json/issues/1190) - Compiler crash with old Clang [\#1179](https://github.com/nlohmann/json/issues/1179) - Custom Precision on floating point numbers [\#1170](https://github.com/nlohmann/json/issues/1170) - Can we have a json\_view class like std::string\_view? [\#1158](https://github.com/nlohmann/json/issues/1158) - improve error handling [\#1152](https://github.com/nlohmann/json/issues/1152) - We should remove static\_asserts [\#960](https://github.com/nlohmann/json/issues/960) ## [v3.2.0](https://github.com/nlohmann/json/releases/tag/v3.2.0) (2018-08-20) [Full Changelog](https://github.com/nlohmann/json/compare/3.2.0...v3.2.0) - Fix -Wno-sometimes-uninitialized by initializing "result" in parse\_sax [\#1200](https://github.com/nlohmann/json/pull/1200) ([thyu](https://github.com/thyu)) - \[RFC\] Introduce a new macro function: JSON\_INTERNAL\_CATCH [\#1187](https://github.com/nlohmann/json/pull/1187) ([simnalamburt](https://github.com/simnalamburt)) - Fix unit tests that were silently skipped or crashed \(depending on the compiler\) [\#1176](https://github.com/nlohmann/json/pull/1176) ([grembo](https://github.com/grembo)) - Refactor/no virtual sax [\#1153](https://github.com/nlohmann/json/pull/1153) ([theodelrieu](https://github.com/theodelrieu)) - Fixed compiler error in VS 2015 for debug mode [\#1151](https://github.com/nlohmann/json/pull/1151) ([sonulohani](https://github.com/sonulohani)) - Fix links to cppreference named requirements \(formerly concepts\) [\#1144](https://github.com/nlohmann/json/pull/1144) ([jrakow](https://github.com/jrakow)) - meson: fix include directory [\#1142](https://github.com/nlohmann/json/pull/1142) ([jrakow](https://github.com/jrakow)) - Feature/unordered map conversion [\#1138](https://github.com/nlohmann/json/pull/1138) ([theodelrieu](https://github.com/theodelrieu)) - fixed compile error for \#1045 [\#1134](https://github.com/nlohmann/json/pull/1134) ([Daniel599](https://github.com/Daniel599)) - test \(non\)equality for alt\_string implementation [\#1130](https://github.com/nlohmann/json/pull/1130) ([agrianius](https://github.com/agrianius)) - remove stringstream dependency [\#1117](https://github.com/nlohmann/json/pull/1117) ([TinyTinni](https://github.com/TinyTinni)) - Provide a from\_json overload for std::map [\#1089](https://github.com/nlohmann/json/pull/1089) ([theodelrieu](https://github.com/theodelrieu)) - fix typo in README [\#1078](https://github.com/nlohmann/json/pull/1078) ([martin-mfg](https://github.com/martin-mfg)) - Fix typo [\#1058](https://github.com/nlohmann/json/pull/1058) ([dns13](https://github.com/dns13)) - Misc cmake packaging enhancements [\#1048](https://github.com/nlohmann/json/pull/1048) ([chuckatkins](https://github.com/chuckatkins)) - Fixed incorrect LLVM version number in README [\#1047](https://github.com/nlohmann/json/pull/1047) ([jammehcow](https://github.com/jammehcow)) - Fix trivial typo in comment. [\#1043](https://github.com/nlohmann/json/pull/1043) ([coryan](https://github.com/coryan)) - Package Manager: Spack [\#1041](https://github.com/nlohmann/json/pull/1041) ([ax3l](https://github.com/ax3l)) - CMake: 3.8+ is Sufficient [\#1040](https://github.com/nlohmann/json/pull/1040) ([ax3l](https://github.com/ax3l)) - Added support for string\_view in C++17 [\#1028](https://github.com/nlohmann/json/pull/1028) ([gracicot](https://github.com/gracicot)) - Added public target\_compile\_features for auto and constexpr [\#1026](https://github.com/nlohmann/json/pull/1026) ([ktonon](https://github.com/ktonon)) ## [3.2.0](https://github.com/nlohmann/json/releases/tag/3.2.0) (2018-08-20) [Full Changelog](https://github.com/nlohmann/json/compare/v3.1.2...3.2.0) - Am I doing this wrong? Getting an empty string [\#1199](https://github.com/nlohmann/json/issues/1199) - Incompatible Pointer Type [\#1196](https://github.com/nlohmann/json/issues/1196) - json.exception.type\_error.316 [\#1195](https://github.com/nlohmann/json/issues/1195) - Strange warnings in Code::Blocks 17.12, GNU GCC [\#1192](https://github.com/nlohmann/json/issues/1192) - \[Question\] Current place in code to change floating point resolution [\#1191](https://github.com/nlohmann/json/issues/1191) - Add key name when throwing type error [\#1189](https://github.com/nlohmann/json/issues/1189) - Not able to include in visual studio code? [\#1188](https://github.com/nlohmann/json/issues/1188) - Get an Index or row number of an element [\#1186](https://github.com/nlohmann/json/issues/1186) - Difference between `merge_patch` and `update` [\#1183](https://github.com/nlohmann/json/issues/1183) - Is there a way to get an element from a JSON without throwing an exception on failure? [\#1182](https://github.com/nlohmann/json/issues/1182) - to\_string? [\#1181](https://github.com/nlohmann/json/issues/1181) - How to cache a json object's pointer into a map? [\#1180](https://github.com/nlohmann/json/issues/1180) - Can this library work within a Qt project for Android using Qt Creator? [\#1178](https://github.com/nlohmann/json/issues/1178) - How to get all keys of one object? [\#1177](https://github.com/nlohmann/json/issues/1177) - How can I only parse the first level and get the value as string? [\#1175](https://github.com/nlohmann/json/issues/1175) - I have a query regarding nlohmann::basic\_json::basic\_json [\#1174](https://github.com/nlohmann/json/issues/1174) - unordered\_map with vectors won't convert to json? [\#1173](https://github.com/nlohmann/json/issues/1173) - return json objects from functions [\#1172](https://github.com/nlohmann/json/issues/1172) - Problem when exporting to CBOR [\#1171](https://github.com/nlohmann/json/issues/1171) - Roundtripping null to nullptr does not work [\#1169](https://github.com/nlohmann/json/issues/1169) - MSVC fails to compile std::swap specialization for nlohmann::json [\#1168](https://github.com/nlohmann/json/issues/1168) - Unexpected behaviour of is\_null - Part II [\#1167](https://github.com/nlohmann/json/issues/1167) - Floating point imprecision [\#1166](https://github.com/nlohmann/json/issues/1166) - Combine json objects into one? [\#1165](https://github.com/nlohmann/json/issues/1165) - Is there any way to know if the object has changed? [\#1164](https://github.com/nlohmann/json/issues/1164) - Value throws on null string [\#1163](https://github.com/nlohmann/json/issues/1163) - Weird template issue in large project [\#1162](https://github.com/nlohmann/json/issues/1162) - \_json returns a different result vs ::parse [\#1161](https://github.com/nlohmann/json/issues/1161) - Showing difference between two json objects [\#1160](https://github.com/nlohmann/json/issues/1160) - no instance of overloaded function "std::swap" matches the specified type [\#1159](https://github.com/nlohmann/json/issues/1159) - resize\(...\)? [\#1157](https://github.com/nlohmann/json/issues/1157) - Issue with struct nested in class' to\_json [\#1155](https://github.com/nlohmann/json/issues/1155) - Deserialize std::map with std::nan [\#1154](https://github.com/nlohmann/json/issues/1154) - Parse throwing errors [\#1149](https://github.com/nlohmann/json/issues/1149) - cocoapod integration [\#1148](https://github.com/nlohmann/json/issues/1148) - wstring parsing [\#1147](https://github.com/nlohmann/json/issues/1147) - Is it possible to dump a two-dimensional array to "\[\[null\],\[1,2,3\]\]"? [\#1146](https://github.com/nlohmann/json/issues/1146) - Want to write a class member variable and a struct variable \( this structure is inside the class\) to the json file [\#1145](https://github.com/nlohmann/json/issues/1145) - Does json support converting an instance of a struct into json string? [\#1143](https://github.com/nlohmann/json/issues/1143) - \#Most efficient way to search for child parameters \(recursive find?\) [\#1141](https://github.com/nlohmann/json/issues/1141) - could not find to\_json\(\) method in T's namespace [\#1140](https://github.com/nlohmann/json/issues/1140) - chars get treated as JSON numbers not JSON strings [\#1139](https://github.com/nlohmann/json/issues/1139) - How do I count number of objects in array? [\#1137](https://github.com/nlohmann/json/issues/1137) - Serializing a vector of classes? [\#1136](https://github.com/nlohmann/json/issues/1136) - Compile error. Unable convert form nullptr to nullptr&& [\#1135](https://github.com/nlohmann/json/issues/1135) - std::unordered\_map in struct, serialization [\#1133](https://github.com/nlohmann/json/issues/1133) - dump\(\) can't handle umlauts [\#1131](https://github.com/nlohmann/json/issues/1131) - Add a way to get a key reference from the iterator [\#1127](https://github.com/nlohmann/json/issues/1127) - can't not parse "\\“ string [\#1123](https://github.com/nlohmann/json/issues/1123) - if json file contain Internationalization chars , get exception [\#1122](https://github.com/nlohmann/json/issues/1122) - How to use a json::iterator dereferenced value in code? [\#1120](https://github.com/nlohmann/json/issues/1120) - Disable implicit conversions from json to std::initializer\_list\ for any T [\#1118](https://github.com/nlohmann/json/issues/1118) - Implicit conversions to complex types can lead to surprising and confusing errors [\#1116](https://github.com/nlohmann/json/issues/1116) - How can I write from\_json for a complex datatype that is not default constructible? [\#1115](https://github.com/nlohmann/json/issues/1115) - Compile error in VS2015 when compiling unit-conversions.cpp [\#1114](https://github.com/nlohmann/json/issues/1114) - ADL Serializer for std::any / boost::any [\#1113](https://github.com/nlohmann/json/issues/1113) - Unexpected behaviour of is\_null [\#1112](https://github.com/nlohmann/json/issues/1112) - How to resolve " undefined reference to `std::\_\_throw\_bad\_cast\(\)'" [\#1111](https://github.com/nlohmann/json/issues/1111) - cannot compile on ubuntu 18.04 and 16.04 [\#1110](https://github.com/nlohmann/json/issues/1110) - JSON representation for floating point values has too many digits [\#1109](https://github.com/nlohmann/json/issues/1109) - Not working for classes containing "\_declspec\(dllimport\)" in their declaration [\#1108](https://github.com/nlohmann/json/issues/1108) - Get keys from json object [\#1107](https://github.com/nlohmann/json/issues/1107) - Cannot deserialize types using std::ratio [\#1105](https://github.com/nlohmann/json/issues/1105) - i want to learn json [\#1104](https://github.com/nlohmann/json/issues/1104) - Type checking during compile [\#1103](https://github.com/nlohmann/json/issues/1103) - Iterate through sub items [\#1102](https://github.com/nlohmann/json/issues/1102) - cppcheck failing for version 3.1.2 [\#1101](https://github.com/nlohmann/json/issues/1101) - Deserializing std::map [\#1100](https://github.com/nlohmann/json/issues/1100) - accessing key by reference [\#1098](https://github.com/nlohmann/json/issues/1098) - clang 3.8.0 croaks while trying to compile with debug symbols [\#1097](https://github.com/nlohmann/json/issues/1097) - Serialize a list of class objects with json [\#1096](https://github.com/nlohmann/json/issues/1096) - Small question [\#1094](https://github.com/nlohmann/json/issues/1094) - Upgrading to 3.x: to\_/from\_json with enum class [\#1093](https://github.com/nlohmann/json/issues/1093) - Q: few questions about json construction [\#1092](https://github.com/nlohmann/json/issues/1092) - general crayCC compilation failure [\#1091](https://github.com/nlohmann/json/issues/1091) - Merge Patch clears original data [\#1090](https://github.com/nlohmann/json/issues/1090) - \[Question\] how to use nlohmann/json in c++? [\#1088](https://github.com/nlohmann/json/issues/1088) - C++17 decomposition declaration support [\#1087](https://github.com/nlohmann/json/issues/1087) - \[Question\] Access multi-level json objects [\#1086](https://github.com/nlohmann/json/issues/1086) - Serializing vector [\#1085](https://github.com/nlohmann/json/issues/1085) - update nested value in multi hierarchy json object [\#1084](https://github.com/nlohmann/json/issues/1084) - Overriding default values? [\#1083](https://github.com/nlohmann/json/issues/1083) - detail namespace collision with Cereal? [\#1082](https://github.com/nlohmann/json/issues/1082) - Error using json.dump\(\); [\#1081](https://github.com/nlohmann/json/issues/1081) - Consuming TCP Stream [\#1080](https://github.com/nlohmann/json/issues/1080) - Compilation error with strong typed enums in map in combination with namespaces [\#1079](https://github.com/nlohmann/json/issues/1079) - cassert error [\#1076](https://github.com/nlohmann/json/issues/1076) - Valid json data not being parsed [\#1075](https://github.com/nlohmann/json/issues/1075) - Feature request :: Better testing for key existance without try/catch [\#1074](https://github.com/nlohmann/json/issues/1074) - Hi, I have input like a.b.c and want to convert it to \"a\"{\"b\": \"c\"} form. Any suggestions how do I do this? Thanks. [\#1073](https://github.com/nlohmann/json/issues/1073) - ADL deserializer not picked up for non default-constructible type [\#1072](https://github.com/nlohmann/json/issues/1072) - Deserializing std::array doesn't compiler \(no insert\(\)\) [\#1071](https://github.com/nlohmann/json/issues/1071) - Serializing OpenCV Mat problem [\#1070](https://github.com/nlohmann/json/issues/1070) - Compilation error with ICPC compiler [\#1068](https://github.com/nlohmann/json/issues/1068) - Not existing value, crash [\#1065](https://github.com/nlohmann/json/issues/1065) - cyryllic symbols [\#1064](https://github.com/nlohmann/json/issues/1064) - newbie usage question [\#1063](https://github.com/nlohmann/json/issues/1063) - Trying j\["strTest"\] = "%A" produces "strTest": "-0X1.CCCCCCCCCCCCCP+205" [\#1062](https://github.com/nlohmann/json/issues/1062) - convert json value to std::string??? [\#1061](https://github.com/nlohmann/json/issues/1061) - Commented out test cases, should they be removed? [\#1060](https://github.com/nlohmann/json/issues/1060) - different behaviour between clang and gcc with braced initialization [\#1059](https://github.com/nlohmann/json/issues/1059) - json array: initialize with prescribed size and `resize` method. [\#1057](https://github.com/nlohmann/json/issues/1057) - Is it possible to use exceptions istead of assertions? [\#1056](https://github.com/nlohmann/json/issues/1056) - when using assign operator in with json object a static assertion fails.. [\#1055](https://github.com/nlohmann/json/issues/1055) - Iterate over leafs of a JSON data structure: enrich the JSON pointer API [\#1054](https://github.com/nlohmann/json/issues/1054) - \[Feature request\] Access by path [\#1053](https://github.com/nlohmann/json/issues/1053) - document that implicit js -\> primitive conversion does not work for std::string::value\_type and why [\#1052](https://github.com/nlohmann/json/issues/1052) - error: ‘BasicJsonType’ in namespace ‘::’ does not name a type [\#1051](https://github.com/nlohmann/json/issues/1051) - Destructor is called when filling object through assignement [\#1050](https://github.com/nlohmann/json/issues/1050) - Is this thing thread safe for reads? [\#1049](https://github.com/nlohmann/json/issues/1049) - clang-tidy: Call to virtual function during construction [\#1046](https://github.com/nlohmann/json/issues/1046) - Using STL algorithms with JSON containers with expected results? [\#1045](https://github.com/nlohmann/json/issues/1045) - Usage with gtest/gmock not working as expected [\#1044](https://github.com/nlohmann/json/issues/1044) - Consequences of from\_json / to\_json being in namespace of data struct. [\#1042](https://github.com/nlohmann/json/issues/1042) - const\_reference operator\[\]\(const typename object\_t::key\_type& key\) const throw instead of assert [\#1039](https://github.com/nlohmann/json/issues/1039) - Trying to retrieve data from nested objects [\#1038](https://github.com/nlohmann/json/issues/1038) - Direct download link for json\_fwd.hpp? [\#1037](https://github.com/nlohmann/json/issues/1037) - I know the library supports UTF-8, but failed to dump the value [\#1036](https://github.com/nlohmann/json/issues/1036) - Putting a Vec3-like vector into a json object [\#1035](https://github.com/nlohmann/json/issues/1035) - Ternary operator crash [\#1034](https://github.com/nlohmann/json/issues/1034) - Issued with Clion Inspection Resolution since 2018.1 [\#1033](https://github.com/nlohmann/json/issues/1033) - Some testcases fail and one never finishes [\#1032](https://github.com/nlohmann/json/issues/1032) - Can this class work with wchar\_t / std::wstring? [\#1031](https://github.com/nlohmann/json/issues/1031) - Makefile: Valgrind flags have no effect [\#1030](https://github.com/nlohmann/json/issues/1030) - 「==〠Should be 「\>〠[\#1029](https://github.com/nlohmann/json/issues/1029) - HOCON reader? [\#1027](https://github.com/nlohmann/json/issues/1027) - add json string in previous string?? [\#1025](https://github.com/nlohmann/json/issues/1025) - RFC: fluent parsing interface [\#1023](https://github.com/nlohmann/json/issues/1023) - Does it support chinese character? [\#1022](https://github.com/nlohmann/json/issues/1022) - to/from\_msgpack only works with standard typization [\#1021](https://github.com/nlohmann/json/issues/1021) - Build failure using latest clang and GCC compilers [\#1020](https://github.com/nlohmann/json/issues/1020) - can two json objects be concatenated? [\#1019](https://github.com/nlohmann/json/issues/1019) - Erase by integer index [\#1018](https://github.com/nlohmann/json/issues/1018) - Function find overload taking a json\_pointer [\#1017](https://github.com/nlohmann/json/issues/1017) - I think should implement an parser function [\#1016](https://github.com/nlohmann/json/issues/1016) - Readme gif [\#1015](https://github.com/nlohmann/json/issues/1015) - Python bindings [\#1014](https://github.com/nlohmann/json/issues/1014) - how to add two json string in single object?? [\#1012](https://github.com/nlohmann/json/issues/1012) - how to serialize class Object \(convert data in object into json\)?? [\#1011](https://github.com/nlohmann/json/issues/1011) - Enable forward declaration of json by making json a class instead of a using declaration [\#997](https://github.com/nlohmann/json/issues/997) - compilation error while using intel c++ compiler 2018 [\#994](https://github.com/nlohmann/json/issues/994) - How to create a json variable? [\#990](https://github.com/nlohmann/json/issues/990) - istream \>\> json --- 1st character skipped in stream [\#976](https://github.com/nlohmann/json/issues/976) - Add a SAX parser [\#971](https://github.com/nlohmann/json/issues/971) - How to solve large json file? [\#927](https://github.com/nlohmann/json/issues/927) - json\_pointer public push\_back, pop\_back [\#837](https://github.com/nlohmann/json/issues/837) - Using input\_adapter in a slightly unexpected way [\#834](https://github.com/nlohmann/json/issues/834) ## [v3.1.2](https://github.com/nlohmann/json/releases/tag/v3.1.2) (2018-03-14) [Full Changelog](https://github.com/nlohmann/json/compare/3.1.2...v3.1.2) - Allowing for user-defined string type in lexer/parser [\#1009](https://github.com/nlohmann/json/pull/1009) ([nlohmann](https://github.com/nlohmann)) - dump to alternative string type, as defined in basic\_json template [\#1006](https://github.com/nlohmann/json/pull/1006) ([agrianius](https://github.com/agrianius)) - Fix memory leak during parser callback [\#1001](https://github.com/nlohmann/json/pull/1001) ([nlohmann](https://github.com/nlohmann)) - fixed misprinted condition detected by PVS Studio. [\#992](https://github.com/nlohmann/json/pull/992) ([bogemic](https://github.com/bogemic)) - Fix/basic json conversion [\#986](https://github.com/nlohmann/json/pull/986) ([theodelrieu](https://github.com/theodelrieu)) - Make integration section concise [\#981](https://github.com/nlohmann/json/pull/981) ([wla80](https://github.com/wla80)) ## [3.1.2](https://github.com/nlohmann/json/releases/tag/3.1.2) (2018-03-14) [Full Changelog](https://github.com/nlohmann/json/compare/v3.1.1...3.1.2) - STL containers are always serialized to a nested array like \[\[1,2,3\]\] [\#1013](https://github.com/nlohmann/json/issues/1013) - The library doesn't want to insert an unordered\_map [\#1010](https://github.com/nlohmann/json/issues/1010) - Convert Json to uint8\_t [\#1008](https://github.com/nlohmann/json/issues/1008) - How to compare two JSON objects? [\#1007](https://github.com/nlohmann/json/issues/1007) - Syntax checking [\#1003](https://github.com/nlohmann/json/issues/1003) - more than one operator '=' matches these operands [\#1002](https://github.com/nlohmann/json/issues/1002) - How to check if key existed [\#1000](https://github.com/nlohmann/json/issues/1000) - nlohmann::json::parse exhaust memory in go binding [\#999](https://github.com/nlohmann/json/issues/999) - Range-based iteration over a non-array object [\#998](https://github.com/nlohmann/json/issues/998) - get\ for types that are not default constructible [\#996](https://github.com/nlohmann/json/issues/996) - Prevent Null values to appear in .dump\(\) [\#995](https://github.com/nlohmann/json/issues/995) - number parsing [\#993](https://github.com/nlohmann/json/issues/993) - C2664 \(C++/CLR\) cannot convert 'nullptr' to 'nullptr &&' [\#987](https://github.com/nlohmann/json/issues/987) - Uniform initialization from another json object differs between gcc and clang. [\#985](https://github.com/nlohmann/json/issues/985) - Problem with adding the lib as a submodule [\#983](https://github.com/nlohmann/json/issues/983) - UTF-8/Unicode error [\#982](https://github.com/nlohmann/json/issues/982) - "forcing MSVC stacktrace to show which T we're talking about." error [\#980](https://github.com/nlohmann/json/issues/980) - reverse order of serialization [\#979](https://github.com/nlohmann/json/issues/979) - Assigning between different json types [\#977](https://github.com/nlohmann/json/issues/977) - Support serialisation of `unique_ptr<>` and `shared_ptr<>` [\#975](https://github.com/nlohmann/json/issues/975) - Unexpected end of input \(not same as one before\) [\#974](https://github.com/nlohmann/json/issues/974) - Segfault on direct initializing json object [\#973](https://github.com/nlohmann/json/issues/973) - Segmentation fault on G++ when trying to assign json string literal to custom json type. [\#972](https://github.com/nlohmann/json/issues/972) - os\_defines.h:44:19: error: missing binary operator before token "\(" [\#970](https://github.com/nlohmann/json/issues/970) - Passing an iteration object by reference to a function [\#967](https://github.com/nlohmann/json/issues/967) - Json and fmt::lib's format\_arg\(\) [\#964](https://github.com/nlohmann/json/issues/964) ## [v3.1.1](https://github.com/nlohmann/json/releases/tag/v3.1.1) (2018-02-13) [Full Changelog](https://github.com/nlohmann/json/compare/v3.1.0...v3.1.1) - Updation of child object isn't reflected in parent Object [\#968](https://github.com/nlohmann/json/issues/968) - How to add user defined C++ path to sublime text [\#966](https://github.com/nlohmann/json/issues/966) - fast number parsing [\#965](https://github.com/nlohmann/json/issues/965) - With non-unique keys, later stored entries are not taken into account anymore [\#963](https://github.com/nlohmann/json/issues/963) - Timeout \(OSS-Fuzz 6034\) [\#962](https://github.com/nlohmann/json/issues/962) - Incorrect parsing of indefinite length CBOR strings. [\#961](https://github.com/nlohmann/json/issues/961) - Reload a json file at runtime without emptying my std::ifstream [\#959](https://github.com/nlohmann/json/issues/959) - Split headers should be part of the release [\#956](https://github.com/nlohmann/json/issues/956) - Coveralls shows no coverage data [\#953](https://github.com/nlohmann/json/issues/953) - Feature request: Implicit conversion to bool [\#951](https://github.com/nlohmann/json/issues/951) - converting json to vector of type with templated constructor [\#924](https://github.com/nlohmann/json/issues/924) - No structured bindings support? [\#901](https://github.com/nlohmann/json/issues/901) - \[Request\] Macro generating from\_json\(\) and to\_json\(\) [\#895](https://github.com/nlohmann/json/issues/895) - basic\_json::value throws exception instead of returning default value [\#871](https://github.com/nlohmann/json/issues/871) - Fix constraints on from\_json\(CompatibleArrayType\) [\#969](https://github.com/nlohmann/json/pull/969) ([theodelrieu](https://github.com/theodelrieu)) - Make coveralls watch the include folder [\#957](https://github.com/nlohmann/json/pull/957) ([theodelrieu](https://github.com/theodelrieu)) - Fix links in README.md [\#955](https://github.com/nlohmann/json/pull/955) ([patrikhuber](https://github.com/patrikhuber)) - Add a note about installing the library with cget [\#954](https://github.com/nlohmann/json/pull/954) ([pfultz2](https://github.com/pfultz2)) ## [v3.1.0](https://github.com/nlohmann/json/releases/tag/v3.1.0) (2018-02-01) [Full Changelog](https://github.com/nlohmann/json/compare/3.1.0...v3.1.0) - Templatize std::string in binary\_reader \#941 [\#950](https://github.com/nlohmann/json/pull/950) ([kaidokert](https://github.com/kaidokert)) - fix cmake install directory \(for real this time\) [\#944](https://github.com/nlohmann/json/pull/944) ([theodelrieu](https://github.com/theodelrieu)) - Allow overriding THROW/CATCH/TRY macros with no-exceptions \#938 [\#940](https://github.com/nlohmann/json/pull/940) ([kaidokert](https://github.com/kaidokert)) - Removed compiler warning about unused variable 'kMinExp' [\#936](https://github.com/nlohmann/json/pull/936) ([zerodefect](https://github.com/zerodefect)) - Fix a typo in README.md [\#930](https://github.com/nlohmann/json/pull/930) ([Pipeliner](https://github.com/Pipeliner)) - Howto installation of json\_fwd.hpp \(fixes \#923\) [\#925](https://github.com/nlohmann/json/pull/925) ([zerodefect](https://github.com/zerodefect)) - fix sfinae on basic\_json UDT constructor [\#919](https://github.com/nlohmann/json/pull/919) ([theodelrieu](https://github.com/theodelrieu)) - Floating-point formatting [\#915](https://github.com/nlohmann/json/pull/915) ([abolz](https://github.com/abolz)) - Fix/cmake install [\#911](https://github.com/nlohmann/json/pull/911) ([theodelrieu](https://github.com/theodelrieu)) - fix link to the documentation of the emplace function [\#900](https://github.com/nlohmann/json/pull/900) ([Dobiasd](https://github.com/Dobiasd)) - JSON Merge Patch \(RFC 7396\) [\#876](https://github.com/nlohmann/json/pull/876) ([nlohmann](https://github.com/nlohmann)) - Refactor/split it [\#700](https://github.com/nlohmann/json/pull/700) ([theodelrieu](https://github.com/theodelrieu)) ## [3.1.0](https://github.com/nlohmann/json/releases/tag/3.1.0) (2018-02-01) [Full Changelog](https://github.com/nlohmann/json/compare/v3.0.1...3.1.0) - I have a proposal [\#949](https://github.com/nlohmann/json/issues/949) - VERSION define\(s\) [\#948](https://github.com/nlohmann/json/issues/948) - v3.0.1 compile error in icc 16.0.4 [\#947](https://github.com/nlohmann/json/issues/947) - Use in VS2017 15.5.5 [\#946](https://github.com/nlohmann/json/issues/946) - Process for reporting Security Bugs? [\#945](https://github.com/nlohmann/json/issues/945) - Please expose a NLOHMANN\_JSON\_VERSION macro [\#943](https://github.com/nlohmann/json/issues/943) - Change header include directory to nlohmann/json [\#942](https://github.com/nlohmann/json/issues/942) - string\_type in binary\_reader [\#941](https://github.com/nlohmann/json/issues/941) - compile error with clang 5.0 -std=c++1z and no string\_view [\#939](https://github.com/nlohmann/json/issues/939) - Allow overriding JSON\_THROW to something else than abort\(\) [\#938](https://github.com/nlohmann/json/issues/938) - Handle invalid string in Json file [\#937](https://github.com/nlohmann/json/issues/937) - Unused variable 'kMinExp' [\#935](https://github.com/nlohmann/json/issues/935) - yytext is already defined [\#933](https://github.com/nlohmann/json/issues/933) - Equality operator fails [\#931](https://github.com/nlohmann/json/issues/931) - use in visual studio 2015 [\#929](https://github.com/nlohmann/json/issues/929) - Relative includes of json\_fwd.hpp in detail/meta.hpp. \[Develop branch\] [\#928](https://github.com/nlohmann/json/issues/928) - GCC 7.x issue [\#926](https://github.com/nlohmann/json/issues/926) - json\_fwd.hpp not installed [\#923](https://github.com/nlohmann/json/issues/923) - Use Google Benchmarks [\#921](https://github.com/nlohmann/json/issues/921) - Move class json\_pointer to separate file [\#920](https://github.com/nlohmann/json/issues/920) - Unable to locate 'to\_json\(\)' and 'from\_json\(\)' methods in the same namespace [\#917](https://github.com/nlohmann/json/issues/917) - \[answered\]Read key1 from .value example [\#914](https://github.com/nlohmann/json/issues/914) - Don't use `define private public` in test files [\#913](https://github.com/nlohmann/json/issues/913) - value\(\) template argument type deduction [\#912](https://github.com/nlohmann/json/issues/912) - Installation path is incorrect [\#910](https://github.com/nlohmann/json/issues/910) - H [\#909](https://github.com/nlohmann/json/issues/909) - Build failure using clang 5 [\#908](https://github.com/nlohmann/json/issues/908) - Amalgate [\#907](https://github.com/nlohmann/json/issues/907) - Update documentation and tests wrt. split headers [\#906](https://github.com/nlohmann/json/issues/906) - Lib not working on ubuntu 16.04 [\#905](https://github.com/nlohmann/json/issues/905) - Problem when writing to file. [\#904](https://github.com/nlohmann/json/issues/904) - C2864 error when compiling with VS2015 and VS 2017 [\#903](https://github.com/nlohmann/json/issues/903) - \[json.exception.type\_error.304\] cannot use at\(\) with object [\#902](https://github.com/nlohmann/json/issues/902) - How do I forward nlohmann::json declaration? [\#899](https://github.com/nlohmann/json/issues/899) - How to effectively store binary data? [\#898](https://github.com/nlohmann/json/issues/898) - How to get the length of a JSON string without retrieving its std::string? [\#897](https://github.com/nlohmann/json/issues/897) - Regression Tests Failure using "ctest" [\#887](https://github.com/nlohmann/json/issues/887) - Discuss: add JSON Merge Patch \(RFC 7396\)? [\#877](https://github.com/nlohmann/json/issues/877) - Discuss: replace static "iterator\_wrapper" function with "items" member function [\#874](https://github.com/nlohmann/json/issues/874) - Make optional user-data available in from\_json [\#864](https://github.com/nlohmann/json/issues/864) - Casting to std::string not working in VS2015 [\#861](https://github.com/nlohmann/json/issues/861) - Sequential reading of JSON arrays [\#851](https://github.com/nlohmann/json/issues/851) - Idea: Handle Multimaps Better [\#816](https://github.com/nlohmann/json/issues/816) - Floating point rounding [\#777](https://github.com/nlohmann/json/issues/777) - Loss of precision when serializing \ [\#360](https://github.com/nlohmann/json/issues/360) ## [v3.0.1](https://github.com/nlohmann/json/releases/tag/v3.0.1) (2017-12-29) [Full Changelog](https://github.com/nlohmann/json/compare/3.0.1...v3.0.1) - Includes CTest module/adds BUILD\_TESTING option [\#885](https://github.com/nlohmann/json/pull/885) ([TinyTinni](https://github.com/TinyTinni)) - Fix MSVC warning C4819 [\#882](https://github.com/nlohmann/json/pull/882) ([erengy](https://github.com/erengy)) - Merge branch 'develop' into coverity\_scan [\#880](https://github.com/nlohmann/json/pull/880) ([nlohmann](https://github.com/nlohmann)) - :wrench: Fix up a few more effc++ items [\#858](https://github.com/nlohmann/json/pull/858) ([mattismyname](https://github.com/mattismyname)) ## [3.0.1](https://github.com/nlohmann/json/releases/tag/3.0.1) (2017-12-29) [Full Changelog](https://github.com/nlohmann/json/compare/v3.0.0...3.0.1) - Problem parsing array to global vector [\#896](https://github.com/nlohmann/json/issues/896) - Invalid RFC6902 copy operation succeeds [\#894](https://github.com/nlohmann/json/issues/894) - How to rename a key during looping? [\#893](https://github.com/nlohmann/json/issues/893) - clang++-6.0 \(6.0.0-svn321357-1\) warning [\#892](https://github.com/nlohmann/json/issues/892) - Make json.hpp aware of the modules TS? [\#891](https://github.com/nlohmann/json/issues/891) - All enum values not handled in switch cases. \( -Wswitch-enum \) [\#889](https://github.com/nlohmann/json/issues/889) - JSON Pointer resolve failure resulting in incorrect exception code [\#888](https://github.com/nlohmann/json/issues/888) - Unexpected nested arrays from std::vector [\#886](https://github.com/nlohmann/json/issues/886) - erase multiple elements from a json object [\#884](https://github.com/nlohmann/json/issues/884) - Container function overview in Doxygen is not updated [\#883](https://github.com/nlohmann/json/issues/883) - How to use this for binary file uploads [\#881](https://github.com/nlohmann/json/issues/881) - Allow setting JSON\_BuildTests=OFF from parent CMakeLists.txt [\#846](https://github.com/nlohmann/json/issues/846) - Unit test fails for local-independent str-to-num [\#845](https://github.com/nlohmann/json/issues/845) - Another idea about type support [\#774](https://github.com/nlohmann/json/issues/774) ## [v3.0.0](https://github.com/nlohmann/json/releases/tag/v3.0.0) (2017-12-17) [Full Changelog](https://github.com/nlohmann/json/compare/3.0.0...v3.0.0) - :white\_check\_mark: re-added tests for algorithms [\#879](https://github.com/nlohmann/json/pull/879) ([nlohmann](https://github.com/nlohmann)) - Overworked library toward 3.0.0 release [\#875](https://github.com/nlohmann/json/pull/875) ([nlohmann](https://github.com/nlohmann)) - :rotating\_light: remove C4996 warnings \#872 [\#873](https://github.com/nlohmann/json/pull/873) ([nlohmann](https://github.com/nlohmann)) - :boom: throwing an exception in case dump encounters a non-UTF-8 string \#838 [\#870](https://github.com/nlohmann/json/pull/870) ([nlohmann](https://github.com/nlohmann)) - :memo: fixing documentation \#867 [\#868](https://github.com/nlohmann/json/pull/868) ([nlohmann](https://github.com/nlohmann)) - iter\_impl template conformance with C++17 [\#860](https://github.com/nlohmann/json/pull/860) ([bogemic](https://github.com/bogemic)) - Std allocator conformance cpp17 [\#856](https://github.com/nlohmann/json/pull/856) ([bogemic](https://github.com/bogemic)) - cmake: use BUILD\_INTERFACE/INSTALL\_INTERFACE [\#855](https://github.com/nlohmann/json/pull/855) ([theodelrieu](https://github.com/theodelrieu)) - to/from\_json: add a MSVC-specific static\_assert to force a stacktrace [\#854](https://github.com/nlohmann/json/pull/854) ([theodelrieu](https://github.com/theodelrieu)) - Add .natvis for MSVC debug view [\#844](https://github.com/nlohmann/json/pull/844) ([TinyTinni](https://github.com/TinyTinni)) - Updated hunter package links [\#829](https://github.com/nlohmann/json/pull/829) ([jowr](https://github.com/jowr)) - Typos README [\#811](https://github.com/nlohmann/json/pull/811) ([Itja](https://github.com/Itja)) - add forwarding references to json\_ref constructor [\#807](https://github.com/nlohmann/json/pull/807) ([theodelrieu](https://github.com/theodelrieu)) - Add transparent comparator and perfect forwarding support to find\(\) and count\(\) [\#795](https://github.com/nlohmann/json/pull/795) ([jseward](https://github.com/jseward)) - Error : 'identifier "size\_t" is undefined' in linux [\#793](https://github.com/nlohmann/json/pull/793) ([sonulohani](https://github.com/sonulohani)) - Fix Visual Studio 2017 warnings [\#788](https://github.com/nlohmann/json/pull/788) ([jseward](https://github.com/jseward)) - Fix warning C4706 on Visual Studio 2017 [\#785](https://github.com/nlohmann/json/pull/785) ([jseward](https://github.com/jseward)) - Set GENERATE\_TAGFILE in Doxyfile [\#783](https://github.com/nlohmann/json/pull/783) ([eld00d](https://github.com/eld00d)) - using more CMake [\#765](https://github.com/nlohmann/json/pull/765) ([nlohmann](https://github.com/nlohmann)) - Simplified istream handing \#367 [\#764](https://github.com/nlohmann/json/pull/764) ([pjkundert](https://github.com/pjkundert)) - Add info for the vcpkg package. [\#753](https://github.com/nlohmann/json/pull/753) ([gregmarr](https://github.com/gregmarr)) - fix from\_json implementation for pair/tuple [\#708](https://github.com/nlohmann/json/pull/708) ([theodelrieu](https://github.com/theodelrieu)) - Update json.hpp [\#686](https://github.com/nlohmann/json/pull/686) ([GoWebProd](https://github.com/GoWebProd)) - Remove duplicate word [\#685](https://github.com/nlohmann/json/pull/685) ([daixtrose](https://github.com/daixtrose)) - To fix compilation issue for intel OSX compiler [\#682](https://github.com/nlohmann/json/pull/682) ([kbthomp1](https://github.com/kbthomp1)) - Digraph warning [\#679](https://github.com/nlohmann/json/pull/679) ([traits](https://github.com/traits)) - massage -\> message [\#678](https://github.com/nlohmann/json/pull/678) ([DmitryKuk](https://github.com/DmitryKuk)) - Fix "not constraint" grammar in docs [\#674](https://github.com/nlohmann/json/pull/674) ([wincent](https://github.com/wincent)) - Add documentation for integration with CMake and hunter [\#671](https://github.com/nlohmann/json/pull/671) ([dan-42](https://github.com/dan-42)) - REFACTOR: rewrite CMakeLists.txt for better inlcude and reuse [\#669](https://github.com/nlohmann/json/pull/669) ([dan-42](https://github.com/dan-42)) - enable\_testing only if the JSON\_BuildTests is ON [\#666](https://github.com/nlohmann/json/pull/666) ([effolkronium](https://github.com/effolkronium)) - Support moving from rvalues in std::initializer\_list [\#663](https://github.com/nlohmann/json/pull/663) ([himikof](https://github.com/himikof)) - add ensure\_ascii parameter to dump. \#330 [\#654](https://github.com/nlohmann/json/pull/654) ([ryanjmulder](https://github.com/ryanjmulder)) - Rename BuildTests to JSON\_BuildTests [\#652](https://github.com/nlohmann/json/pull/652) ([olegendo](https://github.com/olegendo)) - Don't include \, use std::make\_shared [\#650](https://github.com/nlohmann/json/pull/650) ([olegendo](https://github.com/olegendo)) - Refacto/split basic json [\#643](https://github.com/nlohmann/json/pull/643) ([theodelrieu](https://github.com/theodelrieu)) - fix typo in operator\_\_notequal example [\#630](https://github.com/nlohmann/json/pull/630) ([Chocobo1](https://github.com/Chocobo1)) - Fix MSVC warning C4819 [\#629](https://github.com/nlohmann/json/pull/629) ([Chocobo1](https://github.com/Chocobo1)) - \[BugFix\] Add parentheses around std::min [\#626](https://github.com/nlohmann/json/pull/626) ([koemeet](https://github.com/koemeet)) - add pair/tuple conversions [\#624](https://github.com/nlohmann/json/pull/624) ([theodelrieu](https://github.com/theodelrieu)) - remove std::pair support [\#615](https://github.com/nlohmann/json/pull/615) ([theodelrieu](https://github.com/theodelrieu)) - Add pair support, fix CompatibleObject conversions \(fixes \#600\) [\#609](https://github.com/nlohmann/json/pull/609) ([theodelrieu](https://github.com/theodelrieu)) - \#550 Fix iterator related compiling issues for Intel icc [\#598](https://github.com/nlohmann/json/pull/598) ([HenryRLee](https://github.com/HenryRLee)) - Issue \#593 Fix the arithmetic operators in the iterator and reverse iterator [\#595](https://github.com/nlohmann/json/pull/595) ([HenryRLee](https://github.com/HenryRLee)) - fix doxygen error of basic\_json::get\(\) [\#583](https://github.com/nlohmann/json/pull/583) ([zhaohuaxishi](https://github.com/zhaohuaxishi)) - Fixing assignement for iterator wrapper second, and adding unit test [\#579](https://github.com/nlohmann/json/pull/579) ([Type1J](https://github.com/Type1J)) - Adding first and second properties to iteration\_proxy\_internal [\#578](https://github.com/nlohmann/json/pull/578) ([Type1J](https://github.com/Type1J)) - Adding support for Meson. [\#576](https://github.com/nlohmann/json/pull/576) ([Type1J](https://github.com/Type1J)) - add enum class default conversions [\#545](https://github.com/nlohmann/json/pull/545) ([theodelrieu](https://github.com/theodelrieu)) - Properly pop diagnostics [\#540](https://github.com/nlohmann/json/pull/540) ([tinloaf](https://github.com/tinloaf)) - Add Visual Studio 17 image to appveyor build matrix [\#536](https://github.com/nlohmann/json/pull/536) ([vpetrigo](https://github.com/vpetrigo)) - UTF8 encoding enhancement [\#534](https://github.com/nlohmann/json/pull/534) ([TedLyngmo](https://github.com/TedLyngmo)) - Fix typo [\#530](https://github.com/nlohmann/json/pull/530) ([berkus](https://github.com/berkus)) - Make exception base class visible in basic\_json [\#526](https://github.com/nlohmann/json/pull/526) ([krzysztofwos](https://github.com/krzysztofwos)) - :art: Namespace `uint8_t` from the C++ stdlib [\#510](https://github.com/nlohmann/json/pull/510) ([alex-weej](https://github.com/alex-weej)) - add to\_json method for C arrays [\#508](https://github.com/nlohmann/json/pull/508) ([theodelrieu](https://github.com/theodelrieu)) - Fix -Weffc++ warnings \(GNU 6.3.1\) [\#496](https://github.com/nlohmann/json/pull/496) ([TedLyngmo](https://github.com/TedLyngmo)) ## [3.0.0](https://github.com/nlohmann/json/releases/tag/3.0.0) (2017-12-17) [Full Changelog](https://github.com/nlohmann/json/compare/v2.1.1...3.0.0) - unicode strings [\#878](https://github.com/nlohmann/json/issues/878) - Visual Studio 2017 15.5 C++17 std::allocator deprecations [\#872](https://github.com/nlohmann/json/issues/872) - Typo "excpetion" [\#869](https://github.com/nlohmann/json/issues/869) - Explicit array example in README.md incorrect [\#867](https://github.com/nlohmann/json/issues/867) - why don't you release this from Feb. ? [\#865](https://github.com/nlohmann/json/issues/865) - json::parse throws std::invalid\_argument when processing string generated by json::dump\(\) [\#863](https://github.com/nlohmann/json/issues/863) - code analysis: potential bug? [\#859](https://github.com/nlohmann/json/issues/859) - MSVC2017, 15.5 new issues. [\#857](https://github.com/nlohmann/json/issues/857) - very basic: fetching string value/content without quotes [\#853](https://github.com/nlohmann/json/issues/853) - Ambiguous function call to get with pointer type and constant json object in VS2015 \(15.4.4\) [\#852](https://github.com/nlohmann/json/issues/852) - How to put object in the array as a member? [\#850](https://github.com/nlohmann/json/issues/850) - misclick, please ignore [\#849](https://github.com/nlohmann/json/issues/849) - Make XML great again. [\#847](https://github.com/nlohmann/json/issues/847) - Converting to array not working [\#843](https://github.com/nlohmann/json/issues/843) - Iteration weirdness [\#842](https://github.com/nlohmann/json/issues/842) - Use reference or pointer as Object value [\#841](https://github.com/nlohmann/json/issues/841) - Ambiguity in parsing nested maps [\#840](https://github.com/nlohmann/json/issues/840) - could not find from\_json\(\) method in T's namespace [\#839](https://github.com/nlohmann/json/issues/839) - Incorrect parse error with binary data in keys? [\#838](https://github.com/nlohmann/json/issues/838) - using dump\(\) when std::wstring is StringType with VS2017 [\#836](https://github.com/nlohmann/json/issues/836) - Show the path of the currently parsed value when an error occurs [\#835](https://github.com/nlohmann/json/issues/835) - Repetitive data type while reading [\#833](https://github.com/nlohmann/json/issues/833) - Storing multiple types inside map [\#831](https://github.com/nlohmann/json/issues/831) - Application terminating [\#830](https://github.com/nlohmann/json/issues/830) - Missing CMake hunter package? [\#828](https://github.com/nlohmann/json/issues/828) - std::map\ from json object yields C2665: 'std::pair\::pair': none of the 2 overloads could convert all the argument types [\#827](https://github.com/nlohmann/json/issues/827) - object.dump gives quoted string, want to use .dump\(\) to generate javascripts. [\#826](https://github.com/nlohmann/json/issues/826) - Assertion failed on \["NoExistKey"\] of an not existing key of const json& [\#825](https://github.com/nlohmann/json/issues/825) - vs2015 error : static member will remain uninitialized at runtime but use in constant-expressions is supported [\#824](https://github.com/nlohmann/json/issues/824) - Code Checking Warnings from json.hpp on VS2017 Community [\#821](https://github.com/nlohmann/json/issues/821) - Missing iostream in try online [\#820](https://github.com/nlohmann/json/issues/820) - Floating point value loses decimal point during dump [\#818](https://github.com/nlohmann/json/issues/818) - Conan package for the library [\#817](https://github.com/nlohmann/json/issues/817) - stream error [\#815](https://github.com/nlohmann/json/issues/815) - Link error when using find\(\) on the latest commit [\#814](https://github.com/nlohmann/json/issues/814) - ABI issue with json object between 2 shared libraries [\#813](https://github.com/nlohmann/json/issues/813) - scan\_string\(\) return token\_type::parse\_error; when parse ansi file [\#812](https://github.com/nlohmann/json/issues/812) - segfault when using fifo\_map with json [\#810](https://github.com/nlohmann/json/issues/810) - This shit is shit [\#809](https://github.com/nlohmann/json/issues/809) - \_finite and \_isnan are no members of "std" [\#808](https://github.com/nlohmann/json/issues/808) - how to print out the line which causing exception? [\#806](https://github.com/nlohmann/json/issues/806) - {} uses copy constructor, while = does not [\#805](https://github.com/nlohmann/json/issues/805) - json.hpp:8955: multiple definition of function that is not defined twice or more. [\#804](https://github.com/nlohmann/json/issues/804) - \[question\] to\_json for base and derived class [\#803](https://github.com/nlohmann/json/issues/803) - Misleading error message - unexpected '"' - on incorrect utf-8 symbol [\#802](https://github.com/nlohmann/json/issues/802) - json data = std::string\_view\("hi"\); doesn't work? [\#801](https://github.com/nlohmann/json/issues/801) - Thread safety of parse\(\) [\#800](https://github.com/nlohmann/json/issues/800) - Numbers as strings [\#799](https://github.com/nlohmann/json/issues/799) - Tests failing on arm [\#797](https://github.com/nlohmann/json/issues/797) - Using your library \(without modification\) in another library [\#796](https://github.com/nlohmann/json/issues/796) - Iterating over sub-object [\#794](https://github.com/nlohmann/json/issues/794) - how to get the json object again from which printed by the method of dump\(\) [\#792](https://github.com/nlohmann/json/issues/792) - ppa to include source [\#791](https://github.com/nlohmann/json/issues/791) - Different include paths in macOS and Ubuntu [\#790](https://github.com/nlohmann/json/issues/790) - Missing break after line 12886 in switch/case [\#789](https://github.com/nlohmann/json/issues/789) - All unit tests fail? [\#787](https://github.com/nlohmann/json/issues/787) - More use of move semantics in deserialization [\#786](https://github.com/nlohmann/json/issues/786) - warning C4706 - Visual Studio 2017 \(/W4\) [\#784](https://github.com/nlohmann/json/issues/784) - Compile error in clang 5.0 [\#782](https://github.com/nlohmann/json/issues/782) - Error Installing appium\_lib with Ruby v2.4.2 Due to JSON [\#781](https://github.com/nlohmann/json/issues/781) - ::get\\(\) fails in new\(er\) release \[MSVC\] [\#780](https://github.com/nlohmann/json/issues/780) - Type Conversion [\#779](https://github.com/nlohmann/json/issues/779) - Segfault on nested parsing [\#778](https://github.com/nlohmann/json/issues/778) - Build warnings: shadowing exception id [\#776](https://github.com/nlohmann/json/issues/776) - multi-level JSON support. [\#775](https://github.com/nlohmann/json/issues/775) - SIGABRT on dump\(\) [\#773](https://github.com/nlohmann/json/issues/773) - \[Question\] Custom StringType template parameter \(possibility for a KeyType template parameter\) [\#772](https://github.com/nlohmann/json/issues/772) - constexpr ALL the Things! [\#771](https://github.com/nlohmann/json/issues/771) - error: ‘BasicJsonType’ in namespace ‘::’ does not name a type [\#770](https://github.com/nlohmann/json/issues/770) - Program calls abort function [\#769](https://github.com/nlohmann/json/issues/769) - \[Question\] Floating point resolution config during dump\(\) ? [\#768](https://github.com/nlohmann/json/issues/768) - make check - no test ran [\#767](https://github.com/nlohmann/json/issues/767) - The library cannot work properly with custom allocator based containers [\#766](https://github.com/nlohmann/json/issues/766) - Documentation or feature request. [\#763](https://github.com/nlohmann/json/issues/763) - warnings in msvc about mix/max macro while windows.h is used in the project [\#762](https://github.com/nlohmann/json/issues/762) - std::signbit ambiguous [\#761](https://github.com/nlohmann/json/issues/761) - How to use value for std::experimental::optional type? [\#760](https://github.com/nlohmann/json/issues/760) - Cannot load json file properly [\#759](https://github.com/nlohmann/json/issues/759) - Compilation error with unordered\_map\< int, int \> [\#758](https://github.com/nlohmann/json/issues/758) - CBOR string [\#757](https://github.com/nlohmann/json/issues/757) - Proposal: out\_of\_range should be a subclass of std::out\_of\_range [\#756](https://github.com/nlohmann/json/issues/756) - Compiling with icpc [\#755](https://github.com/nlohmann/json/issues/755) - Getter is setting the value to null if the key does not exist [\#754](https://github.com/nlohmann/json/issues/754) - parsing works sometimes and crashes others [\#752](https://github.com/nlohmann/json/issues/752) - Static\_assert failed "incompatible pointer type" with Xcode [\#751](https://github.com/nlohmann/json/issues/751) - user-defined literal operator not found [\#750](https://github.com/nlohmann/json/issues/750) - getting clean string from it.key\(\) [\#748](https://github.com/nlohmann/json/issues/748) - Best method for exploring and obtaining values of nested json objects when the names are not known beforehand? [\#747](https://github.com/nlohmann/json/issues/747) - null char at the end of string [\#746](https://github.com/nlohmann/json/issues/746) - Incorrect sample for operator \>\> in docs [\#745](https://github.com/nlohmann/json/issues/745) - User-friendly documentation [\#744](https://github.com/nlohmann/json/issues/744) - Retrieve all values that match a json path [\#743](https://github.com/nlohmann/json/issues/743) - Compilation issue with gcc 7.2 [\#742](https://github.com/nlohmann/json/issues/742) - CMake target nlohmann\_json does not have src into its interface includes [\#741](https://github.com/nlohmann/json/issues/741) - Error when serializing empty json: type must be string, but is object [\#740](https://github.com/nlohmann/json/issues/740) - Conversion error for std::map\ [\#739](https://github.com/nlohmann/json/issues/739) - Dumping Json to file as array [\#738](https://github.com/nlohmann/json/issues/738) - nesting json objects [\#737](https://github.com/nlohmann/json/issues/737) - where to find general help? [\#736](https://github.com/nlohmann/json/issues/736) - Compilation Error on Clang 5.0 Upgrade [\#735](https://github.com/nlohmann/json/issues/735) - Compilation error with std::map\ on vs 2015 [\#734](https://github.com/nlohmann/json/issues/734) - Benchmarks for Binary formats [\#733](https://github.com/nlohmann/json/issues/733) - Support \n symbols in json string. [\#731](https://github.com/nlohmann/json/issues/731) - Project's name is too generic and hard to search for [\#730](https://github.com/nlohmann/json/issues/730) - Visual Studio 2015 IntelliTrace problems [\#729](https://github.com/nlohmann/json/issues/729) - How to erase nested objects inside other objects? [\#728](https://github.com/nlohmann/json/issues/728) - Serialization for CBOR [\#726](https://github.com/nlohmann/json/issues/726) - Using json Object as value in a map [\#725](https://github.com/nlohmann/json/issues/725) - std::regex and nlohmann::json value [\#724](https://github.com/nlohmann/json/issues/724) - Warnings when compiling with VisualStudio 2015 [\#723](https://github.com/nlohmann/json/issues/723) - Has this lib the unicode \(wstring\) support? [\#722](https://github.com/nlohmann/json/issues/722) - When will be 3.0 in master? [\#721](https://github.com/nlohmann/json/issues/721) - Determine the type from error message. [\#720](https://github.com/nlohmann/json/issues/720) - Compile-Error C2100 \(MS VS2015\) in line 887 json.hpp [\#719](https://github.com/nlohmann/json/issues/719) - from\_json not working for boost::optional example [\#718](https://github.com/nlohmann/json/issues/718) - about from\_json and to\_json function [\#717](https://github.com/nlohmann/json/issues/717) - How to detect parse failure? [\#715](https://github.com/nlohmann/json/issues/715) - Parse throw std::ios\_base::failure exception when failbit set to true [\#714](https://github.com/nlohmann/json/issues/714) - Is there a way of format just making a pretty print without changing the key's orders ? [\#713](https://github.com/nlohmann/json/issues/713) - Serialization of array of not same model items [\#712](https://github.com/nlohmann/json/issues/712) - pointer to json parse vector [\#711](https://github.com/nlohmann/json/issues/711) - Gtest SEH Exception [\#709](https://github.com/nlohmann/json/issues/709) - broken from\_json implementation for pair and tuple [\#707](https://github.com/nlohmann/json/issues/707) - Unevaluated lambda in assert breaks gcc 7 build [\#705](https://github.com/nlohmann/json/issues/705) - Issues when adding values to firebase database [\#704](https://github.com/nlohmann/json/issues/704) - Floating point equality - revisited [\#703](https://github.com/nlohmann/json/issues/703) - Conversion from valarray\ to json fails to build [\#702](https://github.com/nlohmann/json/issues/702) - internal compiler error \(gcc7\) [\#701](https://github.com/nlohmann/json/issues/701) - One build system to rule them all [\#698](https://github.com/nlohmann/json/issues/698) - Generated nlohmann\_jsonConfig.cmake does not set JSON\_INCLUDE\_DIR [\#695](https://github.com/nlohmann/json/issues/695) - support the Chinese language in json string [\#694](https://github.com/nlohmann/json/issues/694) - NaN problem within develop branch [\#693](https://github.com/nlohmann/json/issues/693) - Please post example of specialization for boost::filesystem [\#692](https://github.com/nlohmann/json/issues/692) - Impossible to do an array of composite objects [\#691](https://github.com/nlohmann/json/issues/691) - How to save json to file? [\#690](https://github.com/nlohmann/json/issues/690) - my simple json parser [\#689](https://github.com/nlohmann/json/issues/689) - problem with new struct parsing syntax [\#688](https://github.com/nlohmann/json/issues/688) - Parse error while parse the json string contains UTF 8 encoded document bytes string [\#684](https://github.com/nlohmann/json/issues/684) - \[question\] how to get a string value by pointer [\#683](https://github.com/nlohmann/json/issues/683) - create json object from string variable [\#681](https://github.com/nlohmann/json/issues/681) - adl\_serializer and CRTP [\#680](https://github.com/nlohmann/json/issues/680) - Is there a way to control the precision of serialized floating point numbers? [\#677](https://github.com/nlohmann/json/issues/677) - Is there a way to get the path of a value? [\#676](https://github.com/nlohmann/json/issues/676) - Could the parser locate errors to line? [\#675](https://github.com/nlohmann/json/issues/675) - There is performance inefficiency found by coverity tool json2.1.1/include/nlohmann/json.hpp [\#673](https://github.com/nlohmann/json/issues/673) - include problem, when cmake on osx [\#672](https://github.com/nlohmann/json/issues/672) - Operator= ambiguous in C++1z and GCC 7.1.1 [\#670](https://github.com/nlohmann/json/issues/670) - should't the cmake install target be to nlohman/json.hpp [\#668](https://github.com/nlohmann/json/issues/668) - deserialise from `std::vector` [\#667](https://github.com/nlohmann/json/issues/667) - How to iterate? [\#665](https://github.com/nlohmann/json/issues/665) - could this json lib work on windows? [\#664](https://github.com/nlohmann/json/issues/664) - How does from\_json work? [\#662](https://github.com/nlohmann/json/issues/662) - insert\(or merge\) object should replace same key , not ignore [\#661](https://github.com/nlohmann/json/issues/661) - Parse method doesn't handle newlines. [\#659](https://github.com/nlohmann/json/issues/659) - Compilation "note" on GCC 6 ARM [\#658](https://github.com/nlohmann/json/issues/658) - Adding additional push\_back/operator+= rvalue overloads for JSON object [\#657](https://github.com/nlohmann/json/issues/657) - dump's parameter "ensure\_ascii" creates too long sequences [\#656](https://github.com/nlohmann/json/issues/656) - Question: parsing `void *` [\#655](https://github.com/nlohmann/json/issues/655) - how should I check a string is valid JSON string ? [\#653](https://github.com/nlohmann/json/issues/653) - Question: thread safety of read only accesses [\#651](https://github.com/nlohmann/json/issues/651) - Eclipse: Method 'size' could not be resolved [\#649](https://github.com/nlohmann/json/issues/649) - Update/Add object fields [\#648](https://github.com/nlohmann/json/issues/648) - No exception raised for Out Of Range input of numbers [\#647](https://github.com/nlohmann/json/issues/647) - Package Name [\#646](https://github.com/nlohmann/json/issues/646) - What is the meaning of operator\[\]\(T\* key\) [\#645](https://github.com/nlohmann/json/issues/645) - Which is the correct way to json objects as parameters to functions? [\#644](https://github.com/nlohmann/json/issues/644) - Method to get string representations of values [\#642](https://github.com/nlohmann/json/issues/642) - CBOR serialization of a given JSON value does not serialize [\#641](https://github.com/nlohmann/json/issues/641) - Are we forced to use "-fexceptions" flag in android ndk project [\#640](https://github.com/nlohmann/json/issues/640) - Comparison of objects containing floats [\#639](https://github.com/nlohmann/json/issues/639) - 'localeconv' is not supported by NDK for SDK \<=20 [\#638](https://github.com/nlohmann/json/issues/638) - \[Question\] cLion integration [\#637](https://github.com/nlohmann/json/issues/637) - How to construct an iteratable usage in nlohmann json? [\#636](https://github.com/nlohmann/json/issues/636) - \[Question\] copy assign json-container to vector [\#635](https://github.com/nlohmann/json/issues/635) - Get size without .dump\(\) [\#634](https://github.com/nlohmann/json/issues/634) - Segmentation fault when parsing invalid json file [\#633](https://github.com/nlohmann/json/issues/633) - How to serialize from json to vector\? [\#632](https://github.com/nlohmann/json/issues/632) - no member named 'thousands\_sep' in 'lconv' [\#631](https://github.com/nlohmann/json/issues/631) - \[Question\] Any fork for \(the unsupported\) Visual Studio 2012 version? [\#628](https://github.com/nlohmann/json/issues/628) - Dependency injection in serializer [\#627](https://github.com/nlohmann/json/issues/627) - from\_json for std::array [\#625](https://github.com/nlohmann/json/issues/625) - Discussion: How to structure the parsing function families [\#623](https://github.com/nlohmann/json/issues/623) - Question: How to erase subtree [\#622](https://github.com/nlohmann/json/issues/622) - Insertion into nested json field [\#621](https://github.com/nlohmann/json/issues/621) - Question: return static json object from function [\#618](https://github.com/nlohmann/json/issues/618) - icc16 error [\#617](https://github.com/nlohmann/json/issues/617) - \[-Wdeprecated-declarations\] in row `j >> ss;` in file `json.hpp:7405:26` and FAILED unit tests with MinGWx64! [\#616](https://github.com/nlohmann/json/issues/616) - to\_json for pairs, tuples [\#614](https://github.com/nlohmann/json/issues/614) - Using uninitialized memory 'buf' in line 11173 v2.1.1? [\#613](https://github.com/nlohmann/json/issues/613) - How to parse multiple same Keys of JSON and save them? [\#612](https://github.com/nlohmann/json/issues/612) - "Multiple declarations" error when using types defined with `typedef` [\#611](https://github.com/nlohmann/json/issues/611) - 2.1.1+ breaks compilation of shared\_ptr\ == 0 [\#610](https://github.com/nlohmann/json/issues/610) - a bug of inheritance ? [\#608](https://github.com/nlohmann/json/issues/608) - std::map key conversion with to\_json [\#607](https://github.com/nlohmann/json/issues/607) - json.hpp:6384:62: error: wrong number of template arguments \(1, should be 2\) [\#606](https://github.com/nlohmann/json/issues/606) - Incremental parsing: Where's the push version? [\#605](https://github.com/nlohmann/json/issues/605) - Is there a way to validate the structure of a json object ? [\#604](https://github.com/nlohmann/json/issues/604) - \[Question\] Issue when using Appveyor when compiling library [\#603](https://github.com/nlohmann/json/issues/603) - BOM not skipped when using json:parse\(iterator\) [\#602](https://github.com/nlohmann/json/issues/602) - Use of the binary type in CBOR and Message Pack [\#601](https://github.com/nlohmann/json/issues/601) - Newbie issue: how does one convert a map in Json back to std::map? [\#600](https://github.com/nlohmann/json/issues/600) - Plugin system [\#599](https://github.com/nlohmann/json/issues/599) - Using custom types for scalars? [\#596](https://github.com/nlohmann/json/issues/596) - Issues with the arithmetic in iterator and reverse iterator [\#593](https://github.com/nlohmann/json/issues/593) - not enough examples [\#592](https://github.com/nlohmann/json/issues/592) - in-class initialization for type 'const T' is not yet implemented [\#591](https://github.com/nlohmann/json/issues/591) - compiling with gcc 7 -\> error on bool operator \< [\#590](https://github.com/nlohmann/json/issues/590) - Parsing from stream leads to an array [\#589](https://github.com/nlohmann/json/issues/589) - Buggy support for binary string data [\#587](https://github.com/nlohmann/json/issues/587) - C++17's ambiguous conversion [\#586](https://github.com/nlohmann/json/issues/586) - How does the messagepack encoding/decoding compare to msgpack-cpp in terms of performance? [\#585](https://github.com/nlohmann/json/issues/585) - is it possible to check existence of a value deep in hierarchy? [\#584](https://github.com/nlohmann/json/issues/584) - loading from a stream and exceptions [\#582](https://github.com/nlohmann/json/issues/582) - Visual Studio seems not to have all min\(\) function versions [\#581](https://github.com/nlohmann/json/issues/581) - Supporting of the json schema [\#580](https://github.com/nlohmann/json/issues/580) - Stack-overflow \(OSS-Fuzz 1444\) [\#577](https://github.com/nlohmann/json/issues/577) - Heap-buffer-overflow \(OSS-Fuzz 1400\) [\#575](https://github.com/nlohmann/json/issues/575) - JSON escape quotes [\#574](https://github.com/nlohmann/json/issues/574) - error: static\_assert failed [\#573](https://github.com/nlohmann/json/issues/573) - Storing floats, and round trip serialisation/deserialisation diffs [\#572](https://github.com/nlohmann/json/issues/572) - JSON.getLong produces inconsistent results [\#571](https://github.com/nlohmann/json/issues/571) - Request: Object.at\(\) with default return value [\#570](https://github.com/nlohmann/json/issues/570) - Internal structure gets corrupted while parsing [\#569](https://github.com/nlohmann/json/issues/569) - create template \ basic\_json from\_cbor\(Iter begin, Iter end\) [\#568](https://github.com/nlohmann/json/issues/568) - Conan.io [\#566](https://github.com/nlohmann/json/issues/566) - contradictory documentation regarding json::find [\#565](https://github.com/nlohmann/json/issues/565) - Unexpected '\"' in middle of array [\#564](https://github.com/nlohmann/json/issues/564) - Support parse std::pair to Json object [\#563](https://github.com/nlohmann/json/issues/563) - json and Microsoft Visual c++ Compiler Nov 2012 CTP [\#562](https://github.com/nlohmann/json/issues/562) - from\_json declaration order and exceptions [\#561](https://github.com/nlohmann/json/issues/561) - Tip: Don't upgrade to VS2017 if using json initializer list constructs [\#559](https://github.com/nlohmann/json/issues/559) - parse error - unexpected end of input [\#558](https://github.com/nlohmann/json/issues/558) - Cant modify existing numbers inside a json object [\#557](https://github.com/nlohmann/json/issues/557) - Better support for SAX style serialize and deserialize in new version? [\#554](https://github.com/nlohmann/json/issues/554) - Cannot convert from json array to std::array [\#553](https://github.com/nlohmann/json/issues/553) - Do not define an unnamed namespace in a header file \(DCL59-CPP\) [\#552](https://github.com/nlohmann/json/issues/552) - Parse error on known good json file [\#551](https://github.com/nlohmann/json/issues/551) - Warning on Intel compiler \(icc 17\) [\#550](https://github.com/nlohmann/json/issues/550) - multiple versions of 'vsnprintf' [\#549](https://github.com/nlohmann/json/issues/549) - illegal indirection [\#548](https://github.com/nlohmann/json/issues/548) - Ambiguous compare operators with clang-5.0 [\#547](https://github.com/nlohmann/json/issues/547) - Using tsl::ordered\_map [\#546](https://github.com/nlohmann/json/issues/546) - Compiler support errors are inconvenient [\#544](https://github.com/nlohmann/json/issues/544) - Duplicate symbols error happens while to\_json/from\_json method implemented inside entity definition header file [\#542](https://github.com/nlohmann/json/issues/542) - consider adding a bool json::is\_valid\(std::string const&\) non-member function [\#541](https://github.com/nlohmann/json/issues/541) - Help request [\#539](https://github.com/nlohmann/json/issues/539) - How to deal with missing keys in `from_json`? [\#538](https://github.com/nlohmann/json/issues/538) - recursive from\_msgpack implementation will stack overflow [\#537](https://github.com/nlohmann/json/issues/537) - Exception objects must be nothrow copy constructible \(ERR60-CPP\) [\#531](https://github.com/nlohmann/json/issues/531) - Support for multiple root elements [\#529](https://github.com/nlohmann/json/issues/529) - Port has\_shape from dropbox/json11 [\#528](https://github.com/nlohmann/json/issues/528) - dump\_float: truncation from ptrdiff\_t to long [\#527](https://github.com/nlohmann/json/issues/527) - Make exception base class visible in basic\_json [\#525](https://github.com/nlohmann/json/issues/525) - msgpack unit test failures on ppc64 arch [\#524](https://github.com/nlohmann/json/issues/524) - How about split the implementation out, and only leave the interface? [\#523](https://github.com/nlohmann/json/issues/523) - VC++2017 not enough actual parameters for macro 'max' [\#522](https://github.com/nlohmann/json/issues/522) - crash on empty ifstream [\#521](https://github.com/nlohmann/json/issues/521) - Suggestion: Support tabs for indentation when serializing to stream. [\#520](https://github.com/nlohmann/json/issues/520) - Abrt in get\_number \(OSS-Fuzz 885\) [\#519](https://github.com/nlohmann/json/issues/519) - Abrt on unknown address \(OSS-Fuzz 884\) [\#518](https://github.com/nlohmann/json/issues/518) - Stack-overflow \(OSS-Fuzz 869\) [\#517](https://github.com/nlohmann/json/issues/517) - Assertion error \(OSS-Fuzz 868\) [\#516](https://github.com/nlohmann/json/issues/516) - NaN to json and back [\#515](https://github.com/nlohmann/json/issues/515) - Comparison of NaN [\#514](https://github.com/nlohmann/json/issues/514) - why it's not possible to serialize c++11 enums directly [\#513](https://github.com/nlohmann/json/issues/513) - clang compile error: use of overloaded operator '\<=' is ambiguous with \(nlohmann::json{{"a", 5}}\)\["a"\] \<= 10 [\#512](https://github.com/nlohmann/json/issues/512) - Why not also look inside the type for \(static\) to\_json and from\_json funtions? [\#511](https://github.com/nlohmann/json/issues/511) - Parser issues [\#509](https://github.com/nlohmann/json/issues/509) - I may not understand [\#507](https://github.com/nlohmann/json/issues/507) - VS2017 min / max problem for 2.1.1 [\#506](https://github.com/nlohmann/json/issues/506) - CBOR/MessagePack is not read until the end [\#505](https://github.com/nlohmann/json/issues/505) - Assertion error \(OSS-Fuzz 856\) [\#504](https://github.com/nlohmann/json/issues/504) - Return position in parse error exceptions [\#503](https://github.com/nlohmann/json/issues/503) - conversion from/to C array is not supported [\#502](https://github.com/nlohmann/json/issues/502) - error C2338: could not find to\_json\(\) method in T's namespace [\#501](https://github.com/nlohmann/json/issues/501) - Test suite fails in en\_GB.UTF-8 [\#500](https://github.com/nlohmann/json/issues/500) - cannot use operator\[\] with number [\#499](https://github.com/nlohmann/json/issues/499) - consider using \_\_cpp\_exceptions and/or \_\_EXCEPTIONS to disable/enable exception support [\#498](https://github.com/nlohmann/json/issues/498) - Stack-overflow \(OSS-Fuzz issue 814\) [\#497](https://github.com/nlohmann/json/issues/497) - Using in Unreal Engine - handling custom types conversion [\#495](https://github.com/nlohmann/json/issues/495) - Conversion from vector\ to json fails to build [\#494](https://github.com/nlohmann/json/issues/494) - fill\_line\_buffer incorrectly tests m\_stream for eof but not fail or bad bits [\#493](https://github.com/nlohmann/json/issues/493) - Compiling with \_GLIBCXX\_DEBUG yields iterator-comparison warnings during tests [\#492](https://github.com/nlohmann/json/issues/492) - crapy interface [\#491](https://github.com/nlohmann/json/issues/491) - Fix Visual Studo 2013 builds. [\#490](https://github.com/nlohmann/json/issues/490) - Failed to compile with -D\_GLIBCXX\_PARALLEL [\#489](https://github.com/nlohmann/json/issues/489) - Input several field with the same name [\#488](https://github.com/nlohmann/json/issues/488) - read in .json file yields strange sizes [\#487](https://github.com/nlohmann/json/issues/487) - json::value\_t can't be a map's key type in VC++ 2015 [\#486](https://github.com/nlohmann/json/issues/486) - Using fifo\_map [\#485](https://github.com/nlohmann/json/issues/485) - Cannot get float pointer for value stored as `0` [\#484](https://github.com/nlohmann/json/issues/484) - byte string support [\#483](https://github.com/nlohmann/json/issues/483) - https://github.com/nlohmann/json\#execute-unit-tests [\#481](https://github.com/nlohmann/json/issues/481) - Remove deprecated constructor basic\_json\(std::istream&\) [\#480](https://github.com/nlohmann/json/issues/480) - writing the binary json file? [\#479](https://github.com/nlohmann/json/issues/479) - CBOR/MessagePack from uint8\_t \* and size [\#478](https://github.com/nlohmann/json/issues/478) - Streaming binary representations [\#477](https://github.com/nlohmann/json/issues/477) - Reuse memory in to\_cbor and to\_msgpack functions [\#476](https://github.com/nlohmann/json/issues/476) - Error Using JSON Library with arrays C++ [\#475](https://github.com/nlohmann/json/issues/475) - Moving forward to version 3.0.0 [\#474](https://github.com/nlohmann/json/issues/474) - Inconsistent behavior in conversion to array type [\#473](https://github.com/nlohmann/json/issues/473) - Create a \[key:member\_pointer\] map to ease parsing custom types [\#471](https://github.com/nlohmann/json/issues/471) - MSVC 2015 update 2 [\#469](https://github.com/nlohmann/json/issues/469) - VS2017 implicit to std::string conversion fix. [\#464](https://github.com/nlohmann/json/issues/464) - How to make sure a string or string literal is a valid JSON? [\#458](https://github.com/nlohmann/json/issues/458) - basic\_json templated on a "policy" class [\#456](https://github.com/nlohmann/json/issues/456) - json::value\(const json\_pointer&, ValueType\) requires exceptions to return the default value. [\#440](https://github.com/nlohmann/json/issues/440) - is it possible merge two json object [\#428](https://github.com/nlohmann/json/issues/428) - Is it possible to turn this into a shared library? [\#420](https://github.com/nlohmann/json/issues/420) - Further thoughts on performance improvements [\#418](https://github.com/nlohmann/json/issues/418) - nan number stored as null [\#388](https://github.com/nlohmann/json/issues/388) - Behavior of operator\>\> should more closely resemble that of built-in overloads. [\#367](https://github.com/nlohmann/json/issues/367) - Request: range-based-for over a json-object to expose .first/.second [\#350](https://github.com/nlohmann/json/issues/350) - feature wish: JSONPath [\#343](https://github.com/nlohmann/json/issues/343) - UTF-8/Unicode escape and dump [\#330](https://github.com/nlohmann/json/issues/330) - Serialized value not always can be parsed. [\#329](https://github.com/nlohmann/json/issues/329) - Is there a way to forward declare nlohmann::json? [\#314](https://github.com/nlohmann/json/issues/314) - Exception line [\#301](https://github.com/nlohmann/json/issues/301) - Do not throw exception when default\_value's type does not match the actual type [\#278](https://github.com/nlohmann/json/issues/278) - dump\(\) method doesn't work with a custom allocator [\#268](https://github.com/nlohmann/json/issues/268) - Readme documentation enhancements [\#248](https://github.com/nlohmann/json/issues/248) - Use user-defined exceptions [\#244](https://github.com/nlohmann/json/issues/244) - Incorrect C++11 allocator model support [\#161](https://github.com/nlohmann/json/issues/161) ## [v2.1.1](https://github.com/nlohmann/json/releases/tag/v2.1.1) (2017-02-25) [Full Changelog](https://github.com/nlohmann/json/compare/2.1.1...v2.1.1) - Speedup CI builds using cotire [\#461](https://github.com/nlohmann/json/pull/461) ([tusharpm](https://github.com/tusharpm)) - TurpentineDistillery feature/locale independent str to num [\#450](https://github.com/nlohmann/json/pull/450) ([nlohmann](https://github.com/nlohmann)) - README: adjust boost::optional example [\#439](https://github.com/nlohmann/json/pull/439) ([jaredgrubb](https://github.com/jaredgrubb)) - fix \#414 - comparing to 0 literal [\#415](https://github.com/nlohmann/json/pull/415) ([stanmihai4](https://github.com/stanmihai4)) - locale-independent num-to-str [\#378](https://github.com/nlohmann/json/pull/378) ([TurpentineDistillery](https://github.com/TurpentineDistillery)) ## [2.1.1](https://github.com/nlohmann/json/releases/tag/2.1.1) (2017-02-25) [Full Changelog](https://github.com/nlohmann/json/compare/v2.1.0...2.1.1) - warning in the library [\#472](https://github.com/nlohmann/json/issues/472) - How to create an array of Objects? [\#470](https://github.com/nlohmann/json/issues/470) - \[Bug?\] Cannot get int pointer, but int64\_t works [\#468](https://github.com/nlohmann/json/issues/468) - Illegal indirection [\#467](https://github.com/nlohmann/json/issues/467) - in vs can't find linkageId [\#466](https://github.com/nlohmann/json/issues/466) - Roundtrip error while parsing "1000000000000000010E5" [\#465](https://github.com/nlohmann/json/issues/465) - C4996 error and warning with Visual Studio [\#463](https://github.com/nlohmann/json/issues/463) - Support startIndex for from\_cbor/from\_msgpack [\#462](https://github.com/nlohmann/json/issues/462) - question: monospace font used in feature slideshow? [\#460](https://github.com/nlohmann/json/issues/460) - Object.keys\(\) [\#459](https://github.com/nlohmann/json/issues/459) - Use “, “ as delimiter for json-objects. [\#457](https://github.com/nlohmann/json/issues/457) - Enum -\> string during serialization and vice versa [\#455](https://github.com/nlohmann/json/issues/455) - doubles are printed as integers [\#454](https://github.com/nlohmann/json/issues/454) - Warnings with Visual Studio c++ \(VS2015 Update 3\) [\#453](https://github.com/nlohmann/json/issues/453) - Heap-buffer-overflow \(OSS-Fuzz issue 585\) [\#452](https://github.com/nlohmann/json/issues/452) - use of undeclared identifier 'UINT8\_MAX' [\#451](https://github.com/nlohmann/json/issues/451) - Question on the lifetime managment of objects at the lower levels [\#449](https://github.com/nlohmann/json/issues/449) - Json should not be constructible with 'json\*' [\#448](https://github.com/nlohmann/json/issues/448) - Move value\_t to namespace scope [\#447](https://github.com/nlohmann/json/issues/447) - Typo in README.md [\#446](https://github.com/nlohmann/json/issues/446) - make check compilation is unneccesarily slow [\#445](https://github.com/nlohmann/json/issues/445) - Problem in dump\(\) in json.h caused by ss.imbue [\#444](https://github.com/nlohmann/json/issues/444) - I want to create Windows Application in Visual Studio 2015 c++, and i have a problem [\#443](https://github.com/nlohmann/json/issues/443) - Implicit conversion issues [\#442](https://github.com/nlohmann/json/issues/442) - Parsing of floats locale dependent [\#302](https://github.com/nlohmann/json/issues/302) ## [v2.1.0](https://github.com/nlohmann/json/releases/tag/v2.1.0) (2017-01-28) [Full Changelog](https://github.com/nlohmann/json/compare/2.1.0...v2.1.0) - conversion from/to user-defined types [\#435](https://github.com/nlohmann/json/pull/435) ([nlohmann](https://github.com/nlohmann)) - Fix documentation error [\#430](https://github.com/nlohmann/json/pull/430) ([vjon](https://github.com/vjon)) ## [2.1.0](https://github.com/nlohmann/json/releases/tag/2.1.0) (2017-01-28) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.10...2.1.0) - Parsing multiple JSON objects from a string or stream [\#438](https://github.com/nlohmann/json/issues/438) - Use-of-uninitialized-value \(OSS-Fuzz issue 477\) [\#437](https://github.com/nlohmann/json/issues/437) - add `reserve` function for array to reserve memory before adding json values into it [\#436](https://github.com/nlohmann/json/issues/436) - Typo in examples page [\#434](https://github.com/nlohmann/json/issues/434) - avoid malformed json [\#433](https://github.com/nlohmann/json/issues/433) - How to add json objects to a map? [\#432](https://github.com/nlohmann/json/issues/432) - create json instance from raw json \(unsigned char\*\) [\#431](https://github.com/nlohmann/json/issues/431) - Getting std::invalid\_argument: stream error when following example [\#429](https://github.com/nlohmann/json/issues/429) - Forward declare-only header? [\#427](https://github.com/nlohmann/json/issues/427) - Implicit conversion from array to object [\#425](https://github.com/nlohmann/json/issues/425) - error C4996: 'strerror' when reading file [\#422](https://github.com/nlohmann/json/issues/422) - Get an error - JSON pointer must be empty or begin with '/' [\#421](https://github.com/nlohmann/json/issues/421) - size parameter for parse\(\) [\#419](https://github.com/nlohmann/json/issues/419) - json.hpp forcibly defines GCC\_VERSION [\#417](https://github.com/nlohmann/json/issues/417) - Use-of-uninitialized-value \(OSS-Fuzz issue 377\) [\#416](https://github.com/nlohmann/json/issues/416) - comparing to 0 literal [\#414](https://github.com/nlohmann/json/issues/414) - Single char converted to ASCII code instead of string [\#413](https://github.com/nlohmann/json/issues/413) - How to know if a string was parsed as utf-8? [\#406](https://github.com/nlohmann/json/issues/406) - Overloaded += to add objects to an array makes no sense? [\#404](https://github.com/nlohmann/json/issues/404) - Finding a value in an array [\#399](https://github.com/nlohmann/json/issues/399) - add release information in static function [\#397](https://github.com/nlohmann/json/issues/397) - Optimize memory usage of json objects in combination with binary serialization [\#373](https://github.com/nlohmann/json/issues/373) - Conversion operators not considered [\#369](https://github.com/nlohmann/json/issues/369) - Append ".0" to serialized floating\_point values that are digits-only. [\#362](https://github.com/nlohmann/json/issues/362) - Add a customization point for user-defined types [\#328](https://github.com/nlohmann/json/issues/328) - Conformance report for reference [\#307](https://github.com/nlohmann/json/issues/307) - Document the best way to serialize/deserialize user defined types to json [\#298](https://github.com/nlohmann/json/issues/298) - Add StringView template typename to basic\_json [\#297](https://github.com/nlohmann/json/issues/297) - \[Improvement\] Add option to remove exceptions [\#296](https://github.com/nlohmann/json/issues/296) - Performance in miloyip/nativejson-benchmark [\#202](https://github.com/nlohmann/json/issues/202) ## [v2.0.10](https://github.com/nlohmann/json/releases/tag/v2.0.10) (2017-01-02) [Full Changelog](https://github.com/nlohmann/json/compare/2.0.10...v2.0.10) - Feature/clang sanitize [\#410](https://github.com/nlohmann/json/pull/410) ([Daniel599](https://github.com/Daniel599)) - Add Doozer build badge [\#400](https://github.com/nlohmann/json/pull/400) ([andoma](https://github.com/andoma)) ## [2.0.10](https://github.com/nlohmann/json/releases/tag/2.0.10) (2017-01-02) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.9...2.0.10) - Heap-buffer-overflow \(OSS-Fuzz issue 367\) [\#412](https://github.com/nlohmann/json/issues/412) - Heap-buffer-overflow \(OSS-Fuzz issue 366\) [\#411](https://github.com/nlohmann/json/issues/411) - Use-of-uninitialized-value \(OSS-Fuzz issue 347\) [\#409](https://github.com/nlohmann/json/issues/409) - Heap-buffer-overflow \(OSS-Fuzz issue 344\) [\#408](https://github.com/nlohmann/json/issues/408) - Heap-buffer-overflow \(OSS-Fuzz issue 343\) [\#407](https://github.com/nlohmann/json/issues/407) - Heap-buffer-overflow \(OSS-Fuzz issue 342\) [\#405](https://github.com/nlohmann/json/issues/405) - strerror throwing error in compiler VS2015 [\#403](https://github.com/nlohmann/json/issues/403) - json::parse of std::string being underlined by Visual Studio [\#402](https://github.com/nlohmann/json/issues/402) - Explicitly getting string without .dump\(\) [\#401](https://github.com/nlohmann/json/issues/401) - Possible to speed up json::parse? [\#398](https://github.com/nlohmann/json/issues/398) - the alphabetic order in the code influence console\_output. [\#396](https://github.com/nlohmann/json/issues/396) - Execute tests with clang sanitizers [\#394](https://github.com/nlohmann/json/issues/394) - Check if library can be used with ETL [\#361](https://github.com/nlohmann/json/issues/361) ## [v2.0.9](https://github.com/nlohmann/json/releases/tag/v2.0.9) (2016-12-16) [Full Changelog](https://github.com/nlohmann/json/compare/2.0.9...v2.0.9) - Replace class iterator and const\_iterator by using a single template class to reduce code. [\#395](https://github.com/nlohmann/json/pull/395) ([Bosswestfalen](https://github.com/Bosswestfalen)) - Clang: quiet a warning [\#391](https://github.com/nlohmann/json/pull/391) ([jaredgrubb](https://github.com/jaredgrubb)) - Fix issue \#380: Signed integer overflow check [\#390](https://github.com/nlohmann/json/pull/390) ([qwename](https://github.com/qwename)) ## [2.0.9](https://github.com/nlohmann/json/releases/tag/2.0.9) (2016-12-16) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.8...2.0.9) - \#pragma GCC diagnostic ignored "-Wdocumentation" [\#393](https://github.com/nlohmann/json/issues/393) - How to parse this json file and write separate sub object as json files? [\#392](https://github.com/nlohmann/json/issues/392) - Integer-overflow \(OSS-Fuzz issue 267\) [\#389](https://github.com/nlohmann/json/issues/389) - Implement indefinite-length types from RFC 7049 [\#387](https://github.com/nlohmann/json/issues/387) - template parameter "T" is not used in declaring the parameter types of function template [\#386](https://github.com/nlohmann/json/issues/386) - Serializing json instances containing already serialized string values without escaping [\#385](https://github.com/nlohmann/json/issues/385) - Add test cases from RFC 7049 [\#384](https://github.com/nlohmann/json/issues/384) - Add a table of contents to the README file [\#383](https://github.com/nlohmann/json/issues/383) - Update FAQ section in the guidelines for contributing [\#382](https://github.com/nlohmann/json/issues/382) - Allow for forward declaring nlohmann::json [\#381](https://github.com/nlohmann/json/issues/381) - Bug in overflow detection when parsing integers [\#380](https://github.com/nlohmann/json/issues/380) - A unique name to mention the library? [\#377](https://github.com/nlohmann/json/issues/377) - Non-unique keys in objects. [\#375](https://github.com/nlohmann/json/issues/375) - Request: binary serialization/deserialization [\#358](https://github.com/nlohmann/json/issues/358) ## [v2.0.8](https://github.com/nlohmann/json/releases/tag/v2.0.8) (2016-12-02) [Full Changelog](https://github.com/nlohmann/json/compare/2.0.8...v2.0.8) ## [2.0.8](https://github.com/nlohmann/json/releases/tag/2.0.8) (2016-12-02) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.7...2.0.8) - Reading from file [\#374](https://github.com/nlohmann/json/issues/374) - Compiler warnings? [\#372](https://github.com/nlohmann/json/issues/372) - docs: how to release a json object in memory? [\#371](https://github.com/nlohmann/json/issues/371) - crash in dump [\#370](https://github.com/nlohmann/json/issues/370) - Coverity issue \(FORWARD\_NULL\) in lexer\(std::istream& s\) [\#368](https://github.com/nlohmann/json/issues/368) - json::parse on failed stream gets stuck [\#366](https://github.com/nlohmann/json/issues/366) - Performance improvements [\#365](https://github.com/nlohmann/json/issues/365) - 'to\_string' is not a member of 'std' [\#364](https://github.com/nlohmann/json/issues/364) - Crash in dump\(\) from a static object [\#359](https://github.com/nlohmann/json/issues/359) - json::parse\(...\) vs json j; j.parse\(...\) [\#357](https://github.com/nlohmann/json/issues/357) - Hi, is there any method to dump json to string with the insert order rather than alphabets [\#356](https://github.com/nlohmann/json/issues/356) - Provide an example of reading from an json with only a key that has an array of strings. [\#354](https://github.com/nlohmann/json/issues/354) - Request: access with default value. [\#353](https://github.com/nlohmann/json/issues/353) - {} and \[\] causes parser error. [\#352](https://github.com/nlohmann/json/issues/352) - Reading a JSON file into a JSON object [\#351](https://github.com/nlohmann/json/issues/351) - Request: 'emplace\_back' [\#349](https://github.com/nlohmann/json/issues/349) - Is it possible to stream data through the json parser without storing everything in memory? [\#347](https://github.com/nlohmann/json/issues/347) - pure virtual conversion operator [\#346](https://github.com/nlohmann/json/issues/346) - Floating point precision lost [\#345](https://github.com/nlohmann/json/issues/345) - unit-conversions SIGSEGV on armv7hl [\#303](https://github.com/nlohmann/json/issues/303) - Coverity scan fails [\#299](https://github.com/nlohmann/json/issues/299) - Using QString as string type [\#274](https://github.com/nlohmann/json/issues/274) ## [v2.0.7](https://github.com/nlohmann/json/releases/tag/v2.0.7) (2016-11-02) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.6...v2.0.7) - JSON5 [\#348](https://github.com/nlohmann/json/issues/348) - Check "Parsing JSON is a Minefield" [\#344](https://github.com/nlohmann/json/issues/344) - Allow hex numbers [\#342](https://github.com/nlohmann/json/issues/342) - Convert strings to numbers [\#341](https://github.com/nlohmann/json/issues/341) - ""-operators ignore the length parameter [\#340](https://github.com/nlohmann/json/issues/340) - JSON into std::tuple [\#339](https://github.com/nlohmann/json/issues/339) - JSON into vector [\#335](https://github.com/nlohmann/json/issues/335) - Installing with Homebrew on Mac Errors \(El Capitan\) [\#331](https://github.com/nlohmann/json/issues/331) - g++ make check results in error [\#312](https://github.com/nlohmann/json/issues/312) - Cannot convert from 'json' to 'char' [\#276](https://github.com/nlohmann/json/issues/276) - Please add a Pretty-Print option for arrays to stay always in one line [\#229](https://github.com/nlohmann/json/issues/229) - Conversion to STL map\\> gives error [\#220](https://github.com/nlohmann/json/issues/220) - std::unorderd\_map cannot be used as ObjectType [\#164](https://github.com/nlohmann/json/issues/164) - fix minor grammar/style issue in README.md [\#336](https://github.com/nlohmann/json/pull/336) ([seeekr](https://github.com/seeekr)) ## [v2.0.6](https://github.com/nlohmann/json/releases/tag/v2.0.6) (2016-10-15) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.5...v2.0.6) - How to handle json files? [\#333](https://github.com/nlohmann/json/issues/333) - This file requires compiler and library support .... [\#332](https://github.com/nlohmann/json/issues/332) - Segmentation fault on saving json to file [\#326](https://github.com/nlohmann/json/issues/326) - parse error - unexpected \ with 2.0.5 [\#325](https://github.com/nlohmann/json/issues/325) - Add nested object capability to pointers [\#323](https://github.com/nlohmann/json/issues/323) - Fix usage examples' comments for std::multiset [\#322](https://github.com/nlohmann/json/issues/322) - json\_unit runs forever when executed in build directory [\#319](https://github.com/nlohmann/json/issues/319) - Visual studio 2015 update3 true != TRUE [\#317](https://github.com/nlohmann/json/issues/317) - releasing single header file in compressed format [\#316](https://github.com/nlohmann/json/issues/316) - json object from std::ifstream [\#315](https://github.com/nlohmann/json/issues/315) - make has\_mapped\_type struct friendly [\#324](https://github.com/nlohmann/json/pull/324) ([vpetrigo](https://github.com/vpetrigo)) - Fix usage examples' comments for std::multiset [\#321](https://github.com/nlohmann/json/pull/321) ([vasild](https://github.com/vasild)) - Include dir relocation [\#318](https://github.com/nlohmann/json/pull/318) ([ChristophJud](https://github.com/ChristophJud)) - trivial documentation fix [\#313](https://github.com/nlohmann/json/pull/313) ([5tefan](https://github.com/5tefan)) ## [v2.0.5](https://github.com/nlohmann/json/releases/tag/v2.0.5) (2016-09-14) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.4...v2.0.5) - \[feature request\]: schema validator and comments [\#311](https://github.com/nlohmann/json/issues/311) - make json\_benchmarks no longer working in 2.0.4 [\#310](https://github.com/nlohmann/json/issues/310) - Segmentation fault \(core dumped\) [\#309](https://github.com/nlohmann/json/issues/309) - No matching member function for call to 'get\_impl' [\#308](https://github.com/nlohmann/json/issues/308) ## [v2.0.4](https://github.com/nlohmann/json/releases/tag/v2.0.4) (2016-09-11) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.3...v2.0.4) - Parsing fails without space at end of file [\#306](https://github.com/nlohmann/json/issues/306) - json schema validator [\#305](https://github.com/nlohmann/json/issues/305) - Unused variable warning [\#304](https://github.com/nlohmann/json/issues/304) ## [v2.0.3](https://github.com/nlohmann/json/releases/tag/v2.0.3) (2016-08-31) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.2...v2.0.3) - warning C4706: assignment within conditional expression [\#295](https://github.com/nlohmann/json/issues/295) - Q: Is it possible to build json tree from already UTF8 encoded values? [\#293](https://github.com/nlohmann/json/issues/293) - Equality operator results in array when assigned object [\#292](https://github.com/nlohmann/json/issues/292) - Support for integers not from the range \[-\(2\*\*53\)+1, \(2\*\*53\)-1\] in parser [\#291](https://github.com/nlohmann/json/issues/291) - Support for iterator-range parsing [\#290](https://github.com/nlohmann/json/issues/290) - Horribly inconsistent behavior between const/non-const reference in operator \[\] \(\) [\#289](https://github.com/nlohmann/json/issues/289) - Silently get numbers into smaller types [\#288](https://github.com/nlohmann/json/issues/288) - Incorrect parsing of large int64\_t numbers [\#287](https://github.com/nlohmann/json/issues/287) - \[question\]: macro to disable floating point support [\#284](https://github.com/nlohmann/json/issues/284) - unit-constructor1.cpp: Fix floating point truncation warning [\#300](https://github.com/nlohmann/json/pull/300) ([t-b](https://github.com/t-b)) ## [v2.0.2](https://github.com/nlohmann/json/releases/tag/v2.0.2) (2016-07-31) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.1...v2.0.2) - can function dump\(\) return string in the order I push in the json object ? [\#286](https://github.com/nlohmann/json/issues/286) - Error on the Mac: Undefined symbols for architecture x86\_64 [\#285](https://github.com/nlohmann/json/issues/285) - value\(\) does not work with \_json\_pointer types [\#283](https://github.com/nlohmann/json/issues/283) - Build error for std::int64 [\#282](https://github.com/nlohmann/json/issues/282) - strings can't be accessed after dump\(\)-\>parse\(\) - type is lost [\#281](https://github.com/nlohmann/json/issues/281) - Easy serialization of classes [\#280](https://github.com/nlohmann/json/issues/280) - recursive data structures [\#277](https://github.com/nlohmann/json/issues/277) - hexify\(\) function emits conversion warning [\#270](https://github.com/nlohmann/json/issues/270) - let the makefile choose the correct sed [\#279](https://github.com/nlohmann/json/pull/279) ([murinicanor](https://github.com/murinicanor)) - Update hexify to use array lookup instead of ternary \(\#270\) [\#275](https://github.com/nlohmann/json/pull/275) ([dtoma](https://github.com/dtoma)) ## [v2.0.1](https://github.com/nlohmann/json/releases/tag/v2.0.1) (2016-06-28) [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.0...v2.0.1) - Compilation error. [\#273](https://github.com/nlohmann/json/issues/273) - dump\(\) performance degradation in v2 [\#272](https://github.com/nlohmann/json/issues/272) - fixed a tiny typo [\#271](https://github.com/nlohmann/json/pull/271) ([feroldi](https://github.com/feroldi)) ## [v2.0.0](https://github.com/nlohmann/json/releases/tag/v2.0.0) (2016-06-23) [Full Changelog](https://github.com/nlohmann/json/compare/v1.1.0...v2.0.0) - json::diff generates incorrect patch when removing multiple array elements. [\#269](https://github.com/nlohmann/json/issues/269) - Docs - What does Json\[key\] return? [\#267](https://github.com/nlohmann/json/issues/267) - Compiler Errors With JSON.hpp [\#265](https://github.com/nlohmann/json/issues/265) - Ambiguous push\_back and operator+= overloads [\#263](https://github.com/nlohmann/json/issues/263) - Preseving order of items in json [\#262](https://github.com/nlohmann/json/issues/262) - '\' char problem in strings [\#261](https://github.com/nlohmann/json/issues/261) - VS2015 compile fail [\#260](https://github.com/nlohmann/json/issues/260) - -Wconversion warning [\#259](https://github.com/nlohmann/json/issues/259) - Maybe a bug [\#258](https://github.com/nlohmann/json/issues/258) - Few tests failed on Visual C++ 2015 [\#257](https://github.com/nlohmann/json/issues/257) - Access keys when iteration with new for loop C++11 [\#256](https://github.com/nlohmann/json/issues/256) - multiline text values [\#255](https://github.com/nlohmann/json/issues/255) - Error when using json in g++ [\#254](https://github.com/nlohmann/json/issues/254) - is the release 2.0? [\#253](https://github.com/nlohmann/json/issues/253) - concatenate objects [\#252](https://github.com/nlohmann/json/issues/252) - Encoding [\#251](https://github.com/nlohmann/json/issues/251) - Unable to build example for constructing json object with stringstreams [\#250](https://github.com/nlohmann/json/issues/250) - Hexadecimal support [\#249](https://github.com/nlohmann/json/issues/249) - Update long-term goals [\#246](https://github.com/nlohmann/json/issues/246) - Contribution To This Json Project [\#245](https://github.com/nlohmann/json/issues/245) - Trouble using parser with initial dictionary [\#243](https://github.com/nlohmann/json/issues/243) - Unit test fails when doing a CMake out-of-tree build [\#241](https://github.com/nlohmann/json/issues/241) - -Wconversion warnings [\#239](https://github.com/nlohmann/json/issues/239) - Additional integration options [\#237](https://github.com/nlohmann/json/issues/237) - .get\\(\) works for non spaced string but returns as array for spaced/longer strings [\#236](https://github.com/nlohmann/json/issues/236) - ambiguous overload for 'push\_back' and 'operator+=' [\#235](https://github.com/nlohmann/json/issues/235) - Can't use basic\_json::iterator as a base iterator for std::move\_iterator [\#233](https://github.com/nlohmann/json/issues/233) - json object's creation can freezes execution [\#231](https://github.com/nlohmann/json/issues/231) - Incorrect dumping of parsed numbers with exponents, but without decimal places [\#230](https://github.com/nlohmann/json/issues/230) - double values are serialized with commas as decimal points [\#228](https://github.com/nlohmann/json/issues/228) - Move semantics with std::initializer\_list [\#225](https://github.com/nlohmann/json/issues/225) - replace emplace [\#224](https://github.com/nlohmann/json/issues/224) - abort during getline in yyfill [\#223](https://github.com/nlohmann/json/issues/223) - free\(\): invalid pointer error in GCC 5.2.1 [\#221](https://github.com/nlohmann/json/issues/221) - Error compile Android NDK error: 'strtof' is not a member of 'std' [\#219](https://github.com/nlohmann/json/issues/219) - Wrong link in the README.md [\#217](https://github.com/nlohmann/json/issues/217) - Wide character strings not supported [\#216](https://github.com/nlohmann/json/issues/216) - Memory allocations using range-based for loops [\#214](https://github.com/nlohmann/json/issues/214) - would you like to support gcc 4.8.1? [\#211](https://github.com/nlohmann/json/issues/211) - Reading concatenated json's from an istream [\#210](https://github.com/nlohmann/json/issues/210) - Conflicting typedef of ssize\_t on Windows 32 bit when using Boost.Python [\#204](https://github.com/nlohmann/json/issues/204) - Inconsistency between operator\[\] and push\_back [\#203](https://github.com/nlohmann/json/issues/203) - Small bugs in json.hpp \(get\_number\) and unit.cpp \(non-standard integer type test\) [\#199](https://github.com/nlohmann/json/issues/199) - GCC/clang floating point parsing bug in strtod\(\) [\#195](https://github.com/nlohmann/json/issues/195) - What is within scope? [\#192](https://github.com/nlohmann/json/issues/192) - Bugs in miloyip/nativejson-benchmark: roundtrips [\#187](https://github.com/nlohmann/json/issues/187) - Floating point exceptions [\#181](https://github.com/nlohmann/json/issues/181) - Integer conversion to unsigned [\#178](https://github.com/nlohmann/json/issues/178) - map string string fails to compile [\#176](https://github.com/nlohmann/json/issues/176) - In basic\_json::basic\_json\(const CompatibleArrayType& val\), the requirement of CompatibleArrayType is not strict enough. [\#174](https://github.com/nlohmann/json/issues/174) - Provide a FAQ [\#163](https://github.com/nlohmann/json/issues/163) - Implicit assignment to std::string fails [\#144](https://github.com/nlohmann/json/issues/144) - Fix Issue \#265 [\#266](https://github.com/nlohmann/json/pull/266) ([06needhamt](https://github.com/06needhamt)) - Define CMake/CTest tests [\#247](https://github.com/nlohmann/json/pull/247) ([robertmrk](https://github.com/robertmrk)) - Out of tree builds and a few other miscellaneous CMake cleanups. [\#242](https://github.com/nlohmann/json/pull/242) ([ChrisKitching](https://github.com/ChrisKitching)) - Implement additional integration options [\#238](https://github.com/nlohmann/json/pull/238) ([robertmrk](https://github.com/robertmrk)) - make serialization locale-independent [\#232](https://github.com/nlohmann/json/pull/232) ([nlohmann](https://github.com/nlohmann)) - fixes \#223 by updating README.md [\#227](https://github.com/nlohmann/json/pull/227) ([kevin--](https://github.com/kevin--)) - Use namespace std for int64\_t and uint64\_t [\#226](https://github.com/nlohmann/json/pull/226) ([lv-zheng](https://github.com/lv-zheng)) - Added missing cerrno header to fix ERANGE compile error on android [\#222](https://github.com/nlohmann/json/pull/222) ([Teemperor](https://github.com/Teemperor)) - Corrected readme [\#218](https://github.com/nlohmann/json/pull/218) ([Annihil](https://github.com/Annihil)) - Create PULL\_REQUEST\_TEMPLATE.md [\#213](https://github.com/nlohmann/json/pull/213) ([whackashoe](https://github.com/whackashoe)) - fixed noexcept; added constexpr [\#208](https://github.com/nlohmann/json/pull/208) ([nlohmann](https://github.com/nlohmann)) - Add support for afl-fuzz testing [\#207](https://github.com/nlohmann/json/pull/207) ([mykter](https://github.com/mykter)) - replaced ssize\_t occurrences with auto \(addresses \#204\) [\#205](https://github.com/nlohmann/json/pull/205) ([nlohmann](https://github.com/nlohmann)) - Fixed issue \#199 - Small bugs in json.hpp \(get\_number\) and unit.cpp \(non-standard integer type test\) [\#200](https://github.com/nlohmann/json/pull/200) ([twelsby](https://github.com/twelsby)) - Fix broken link [\#197](https://github.com/nlohmann/json/pull/197) ([vog](https://github.com/vog)) - Issue \#195 - update Travis to Trusty due to gcc/clang strtod\(\) bug [\#196](https://github.com/nlohmann/json/pull/196) ([twelsby](https://github.com/twelsby)) - Issue \#178 - Extending support to full uint64\_t/int64\_t range and unsigned type \(updated\) [\#193](https://github.com/nlohmann/json/pull/193) ([twelsby](https://github.com/twelsby)) ## [v1.1.0](https://github.com/nlohmann/json/releases/tag/v1.1.0) (2016-01-24) [Full Changelog](https://github.com/nlohmann/json/compare/v1.0.0...v1.1.0) - Small error in pull \#185 [\#194](https://github.com/nlohmann/json/issues/194) - Bugs in miloyip/nativejson-benchmark: floating-point parsing [\#186](https://github.com/nlohmann/json/issues/186) - Floating point equality [\#185](https://github.com/nlohmann/json/issues/185) - Unused variables in catch [\#180](https://github.com/nlohmann/json/issues/180) - Typo in documentation [\#179](https://github.com/nlohmann/json/issues/179) - JSON performance benchmark comparision [\#177](https://github.com/nlohmann/json/issues/177) - Since re2c is often ignored in pull requests, it may make sense to make a contributing.md file [\#175](https://github.com/nlohmann/json/issues/175) - Question about exceptions [\#173](https://github.com/nlohmann/json/issues/173) - Android? [\#172](https://github.com/nlohmann/json/issues/172) - Cannot index by key of type static constexpr const char\* [\#171](https://github.com/nlohmann/json/issues/171) - Add assertions [\#168](https://github.com/nlohmann/json/issues/168) - MSVC 2015 build fails when attempting to compare object\_t [\#167](https://github.com/nlohmann/json/issues/167) - Member detector is not portable [\#166](https://github.com/nlohmann/json/issues/166) - Unnecessary const\_cast [\#162](https://github.com/nlohmann/json/issues/162) - Question about get\_ref\(\) [\#128](https://github.com/nlohmann/json/issues/128) - range based for loop for objects [\#83](https://github.com/nlohmann/json/issues/83) - Consider submitting this to the Boost Library Incubator [\#66](https://github.com/nlohmann/json/issues/66) - Fixed Issue \#186 - add strto\(f|d|ld\) overload wrappers, "-0.0" special case and FP trailing zero [\#191](https://github.com/nlohmann/json/pull/191) ([twelsby](https://github.com/twelsby)) - Issue \#185 - remove approx\(\) and use \#pragma to kill warnings [\#190](https://github.com/nlohmann/json/pull/190) ([twelsby](https://github.com/twelsby)) - Fixed Issue \#171 - added two extra template overloads of operator\[\] for T\* arguments [\#189](https://github.com/nlohmann/json/pull/189) ([twelsby](https://github.com/twelsby)) - Fixed issue \#167 - removed operator ValueType\(\) condition for VS2015 [\#188](https://github.com/nlohmann/json/pull/188) ([twelsby](https://github.com/twelsby)) - Implementation of get\_ref\(\) [\#184](https://github.com/nlohmann/json/pull/184) ([dariomt](https://github.com/dariomt)) - Fixed some typos in CONTRIBUTING.md [\#182](https://github.com/nlohmann/json/pull/182) ([nibroc](https://github.com/nibroc)) ## [v1.0.0](https://github.com/nlohmann/json/releases/tag/v1.0.0) (2015-12-27) [Full Changelog](https://github.com/nlohmann/json/compare/v1.0.0-rc1...v1.0.0) - add key name to exception [\#160](https://github.com/nlohmann/json/issues/160) - Getting member discarding qualifyer [\#159](https://github.com/nlohmann/json/issues/159) - basic\_json::iterator::value\(\) output includes quotes while basic\_json::iterator::key\(\) doesn't [\#158](https://github.com/nlohmann/json/issues/158) - Indexing `const basic_json<>` with `const basic_string` [\#157](https://github.com/nlohmann/json/issues/157) - token\_type\_name\(token\_type t\): not all control paths return a value [\#156](https://github.com/nlohmann/json/issues/156) - prevent json.hpp from emitting compiler warnings [\#154](https://github.com/nlohmann/json/issues/154) - json::parse\(string\) does not check utf8 bom [\#152](https://github.com/nlohmann/json/issues/152) - unsigned 64bit values output as signed [\#151](https://github.com/nlohmann/json/issues/151) - Wish feature: json5 [\#150](https://github.com/nlohmann/json/issues/150) - Unable to compile on MSVC 2015 with SDL checking enabled: This function or variable may be unsafe. [\#149](https://github.com/nlohmann/json/issues/149) - "Json Object" type does not keep object order [\#148](https://github.com/nlohmann/json/issues/148) - dump\(\) convert strings encoded by utf-8 to shift-jis on windows 10. [\#147](https://github.com/nlohmann/json/issues/147) - Unable to get field names in a json object [\#145](https://github.com/nlohmann/json/issues/145) - Question: Is the use of incomplete type correct? [\#138](https://github.com/nlohmann/json/issues/138) - json.hpp:5746:32: error: 'to\_string' is not a member of 'std' [\#136](https://github.com/nlohmann/json/issues/136) - Bug in basic\_json::operator\[\] const overload [\#135](https://github.com/nlohmann/json/issues/135) - wrong enable\_if for const pointer \(instead of pointer-to-const\) [\#134](https://github.com/nlohmann/json/issues/134) - overload of at\(\) with default value [\#133](https://github.com/nlohmann/json/issues/133) - Splitting source [\#132](https://github.com/nlohmann/json/issues/132) - Question about get\_ptr\(\) [\#127](https://github.com/nlohmann/json/issues/127) - Visual Studio 14 Debug assertion failed [\#125](https://github.com/nlohmann/json/issues/125) - Memory leak in face of exceptions [\#118](https://github.com/nlohmann/json/issues/118) - Find and Count for arrays [\#117](https://github.com/nlohmann/json/issues/117) - dynamically constructing an arbitrarily nested object [\#114](https://github.com/nlohmann/json/issues/114) - Returning any data type [\#113](https://github.com/nlohmann/json/issues/113) - Compile error with g++ 4.9.3 cygwin 64-bit [\#112](https://github.com/nlohmann/json/issues/112) - insert json array issue with gcc4.8.2 [\#110](https://github.com/nlohmann/json/issues/110) - error: unterminated raw string [\#109](https://github.com/nlohmann/json/issues/109) - vector\ copy constructor really weird [\#108](https://github.com/nlohmann/json/issues/108) - \[clang-3.6.2\] string/sstream with number to json issue [\#107](https://github.com/nlohmann/json/issues/107) - object field accessors [\#103](https://github.com/nlohmann/json/issues/103) - v8pp and json [\#95](https://github.com/nlohmann/json/issues/95) - Wishlist [\#65](https://github.com/nlohmann/json/issues/65) - Windows/Visual Studio \(through 2013\) is unsupported [\#62](https://github.com/nlohmann/json/issues/62) - Replace sprintf with hex function, this fixes \#149 [\#153](https://github.com/nlohmann/json/pull/153) ([whackashoe](https://github.com/whackashoe)) - Fix character skipping after a surrogate pair [\#146](https://github.com/nlohmann/json/pull/146) ([robertmrk](https://github.com/robertmrk)) - Detect correctly pointer-to-const [\#137](https://github.com/nlohmann/json/pull/137) ([dariomt](https://github.com/dariomt)) - disabled "CopyAssignable" test for MSVC in Debug mode, see \#125 [\#131](https://github.com/nlohmann/json/pull/131) ([dariomt](https://github.com/dariomt)) - removed stream operator for iterator, resolution for \#125 [\#130](https://github.com/nlohmann/json/pull/130) ([dariomt](https://github.com/dariomt)) - fixed typos in comments for examples [\#129](https://github.com/nlohmann/json/pull/129) ([dariomt](https://github.com/dariomt)) - Remove superfluous inefficiency [\#126](https://github.com/nlohmann/json/pull/126) ([d-frey](https://github.com/d-frey)) - remove invalid parameter '-stdlib=libc++' in CMakeLists.txt [\#124](https://github.com/nlohmann/json/pull/124) ([emvivre](https://github.com/emvivre)) - exception-safe object creation, fixes \#118 [\#122](https://github.com/nlohmann/json/pull/122) ([d-frey](https://github.com/d-frey)) - Fix small oversight. [\#121](https://github.com/nlohmann/json/pull/121) ([ColinH](https://github.com/ColinH)) - Overload parse\(\) to accept an rvalue reference [\#120](https://github.com/nlohmann/json/pull/120) ([silverweed](https://github.com/silverweed)) - Use the right variable name in doc string [\#115](https://github.com/nlohmann/json/pull/115) ([whoshuu](https://github.com/whoshuu)) ## [v1.0.0-rc1](https://github.com/nlohmann/json/releases/tag/v1.0.0-rc1) (2015-07-26) [Full Changelog](https://github.com/nlohmann/json/compare/4502e7e51c0569419c26e75fbdd5748170603e54...v1.0.0-rc1) - Finish documenting the public interface in Doxygen [\#102](https://github.com/nlohmann/json/issues/102) - Binary string causes numbers to be dumped as hex [\#101](https://github.com/nlohmann/json/issues/101) - failed to iterator json object with reverse\_iterator [\#100](https://github.com/nlohmann/json/issues/100) - 'noexcept' : unknown override specifier [\#99](https://github.com/nlohmann/json/issues/99) - json float parsing problem [\#98](https://github.com/nlohmann/json/issues/98) - Adjust wording to JSON RFC [\#97](https://github.com/nlohmann/json/issues/97) - static analysis warnings [\#94](https://github.com/nlohmann/json/issues/94) - reverse\_iterator operator inheritance problem [\#93](https://github.com/nlohmann/json/issues/93) - init error [\#92](https://github.com/nlohmann/json/issues/92) - access by \(const\) reference [\#91](https://github.com/nlohmann/json/issues/91) - is\_integer and is\_float tests [\#90](https://github.com/nlohmann/json/issues/90) - Nonstandard integer type [\#89](https://github.com/nlohmann/json/issues/89) - static library build [\#84](https://github.com/nlohmann/json/issues/84) - lexer::get\_number return NAN [\#82](https://github.com/nlohmann/json/issues/82) - MinGW have no std::to\_string [\#80](https://github.com/nlohmann/json/issues/80) - Incorrect behaviour of basic\_json::count method [\#78](https://github.com/nlohmann/json/issues/78) - Invoking is\_array\(\) function creates "null" value [\#77](https://github.com/nlohmann/json/issues/77) - dump\(\) / parse\(\) not idempotent [\#76](https://github.com/nlohmann/json/issues/76) - Handle infinity and NaN cases [\#70](https://github.com/nlohmann/json/issues/70) - errors in g++-4.8.1 [\#68](https://github.com/nlohmann/json/issues/68) - Keys when iterating over objects [\#67](https://github.com/nlohmann/json/issues/67) - Compilation results in tons of warnings [\#64](https://github.com/nlohmann/json/issues/64) - Complete brief documentation [\#61](https://github.com/nlohmann/json/issues/61) - Double quotation mark is not parsed correctly [\#60](https://github.com/nlohmann/json/issues/60) - Get coverage back to 100% [\#58](https://github.com/nlohmann/json/issues/58) - erase elements using iterators [\#57](https://github.com/nlohmann/json/issues/57) - Removing item from array [\#56](https://github.com/nlohmann/json/issues/56) - Serialize/Deserialize like PHP? [\#55](https://github.com/nlohmann/json/issues/55) - Numbers as keys [\#54](https://github.com/nlohmann/json/issues/54) - Why are elements alphabetized on key while iterating? [\#53](https://github.com/nlohmann/json/issues/53) - Document erase, count, and iterators key and value [\#52](https://github.com/nlohmann/json/issues/52) - Do not use std::to\_string [\#51](https://github.com/nlohmann/json/issues/51) - Supported compilers [\#50](https://github.com/nlohmann/json/issues/50) - Confused about iterating through json objects [\#49](https://github.com/nlohmann/json/issues/49) - Use non-member begin/end [\#48](https://github.com/nlohmann/json/issues/48) - Erase key [\#47](https://github.com/nlohmann/json/issues/47) - Key iterator [\#46](https://github.com/nlohmann/json/issues/46) - Add count member function [\#45](https://github.com/nlohmann/json/issues/45) - Problem getting vector \(array\) of strings [\#44](https://github.com/nlohmann/json/issues/44) - Compilation error due to assuming that private=public [\#43](https://github.com/nlohmann/json/issues/43) - Use of deprecated implicit copy constructor [\#42](https://github.com/nlohmann/json/issues/42) - Printing attribute names [\#39](https://github.com/nlohmann/json/issues/39) - dumping a small number\_float just outputs 0.000000 [\#37](https://github.com/nlohmann/json/issues/37) - find is error [\#32](https://github.com/nlohmann/json/issues/32) - Avoid using spaces when encoding without pretty print [\#31](https://github.com/nlohmann/json/issues/31) - Cannot encode long numbers [\#30](https://github.com/nlohmann/json/issues/30) - segmentation fault when iterating over empty arrays/objects [\#28](https://github.com/nlohmann/json/issues/28) - Creating an empty array [\#27](https://github.com/nlohmann/json/issues/27) - Custom allocator support [\#25](https://github.com/nlohmann/json/issues/25) - make the type of the used string container customizable [\#20](https://github.com/nlohmann/json/issues/20) - Improper parsing of JSON string "\\" [\#17](https://github.com/nlohmann/json/issues/17) - create a header-only version [\#16](https://github.com/nlohmann/json/issues/16) - Don't return "const values" [\#15](https://github.com/nlohmann/json/issues/15) - Add to\_string overload for indentation [\#13](https://github.com/nlohmann/json/issues/13) - string parser does not recognize uncompliant strings [\#12](https://github.com/nlohmann/json/issues/12) - possible double-free in find function [\#11](https://github.com/nlohmann/json/issues/11) - UTF-8 encoding/deconding/testing [\#10](https://github.com/nlohmann/json/issues/10) - move code into namespace [\#9](https://github.com/nlohmann/json/issues/9) - free functions for explicit objects and arrays in initializer lists [\#8](https://github.com/nlohmann/json/issues/8) - unique\_ptr for ownership [\#7](https://github.com/nlohmann/json/issues/7) - Add unit tests [\#4](https://github.com/nlohmann/json/issues/4) - Drop C++98 support [\#3](https://github.com/nlohmann/json/issues/3) - Test case coverage [\#2](https://github.com/nlohmann/json/issues/2) - Runtime error in Travis job [\#1](https://github.com/nlohmann/json/issues/1) - Keyword 'inline' is useless when member functions are defined in headers [\#87](https://github.com/nlohmann/json/pull/87) ([ahamez](https://github.com/ahamez)) - Remove useless typename [\#86](https://github.com/nlohmann/json/pull/86) ([ahamez](https://github.com/ahamez)) - Avoid warning with Xcode's clang [\#85](https://github.com/nlohmann/json/pull/85) ([ahamez](https://github.com/ahamez)) - Fix typos [\#73](https://github.com/nlohmann/json/pull/73) ([aqnouch](https://github.com/aqnouch)) - Replace `default_callback` function with `nullptr` and check for null… [\#72](https://github.com/nlohmann/json/pull/72) ([aburgh](https://github.com/aburgh)) - support enum [\#71](https://github.com/nlohmann/json/pull/71) ([likebeta](https://github.com/likebeta)) - Fix performance regression introduced with the parsing callback feature. [\#69](https://github.com/nlohmann/json/pull/69) ([aburgh](https://github.com/aburgh)) - Improve the implementations of the comparission-operators [\#63](https://github.com/nlohmann/json/pull/63) ([Florianjw](https://github.com/Florianjw)) - Fix compilation of json\_unit with GCC 5 [\#59](https://github.com/nlohmann/json/pull/59) ([dkopecek](https://github.com/dkopecek)) - Parse streams incrementally. [\#40](https://github.com/nlohmann/json/pull/40) ([aburgh](https://github.com/aburgh)) - Feature/small float serialization [\#38](https://github.com/nlohmann/json/pull/38) ([jrandall](https://github.com/jrandall)) - template version with re2c scanner [\#36](https://github.com/nlohmann/json/pull/36) ([nlohmann](https://github.com/nlohmann)) - more descriptive documentation in example [\#33](https://github.com/nlohmann/json/pull/33) ([luxe](https://github.com/luxe)) - Fix string conversion under Clang [\#26](https://github.com/nlohmann/json/pull/26) ([wancw](https://github.com/wancw)) - Fixed dumping of strings [\#24](https://github.com/nlohmann/json/pull/24) ([Teemperor](https://github.com/Teemperor)) - Added a remark to the readme that coverage is GCC only for now [\#23](https://github.com/nlohmann/json/pull/23) ([Teemperor](https://github.com/Teemperor)) - Unicode escaping [\#22](https://github.com/nlohmann/json/pull/22) ([Teemperor](https://github.com/Teemperor)) - Implemented the JSON spec for string parsing for everything but the \uXXXX escaping [\#21](https://github.com/nlohmann/json/pull/21) ([Teemperor](https://github.com/Teemperor)) - add the std iterator typedefs to iterator and const\_iterator [\#19](https://github.com/nlohmann/json/pull/19) ([kirkshoop](https://github.com/kirkshoop)) - Fixed escaped quotes [\#18](https://github.com/nlohmann/json/pull/18) ([Teemperor](https://github.com/Teemperor)) - Fix double delete on std::bad\_alloc exception [\#14](https://github.com/nlohmann/json/pull/14) ([elliotgoodrich](https://github.com/elliotgoodrich)) - Added CMake and lcov [\#6](https://github.com/nlohmann/json/pull/6) ([Teemperor](https://github.com/Teemperor)) - Version 2.0 [\#5](https://github.com/nlohmann/json/pull/5) ([nlohmann](https://github.com/nlohmann)) \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* sqlitebrowser-sqlitebrowser-5733cb7/libs/json/LICENSE.MIT000066400000000000000000000020641463772530400232350ustar00rootroot00000000000000MIT License Copyright (c) 2013-2021 Niels Lohmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sqlitebrowser-sqlitebrowser-5733cb7/libs/json/README.md000066400000000000000000003026411463772530400230630ustar00rootroot00000000000000[![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif)](https://github.com/nlohmann/json/releases) [![Build Status](https://app.travis-ci.com/nlohmann/json.svg?branch=develop)](https://app.travis-ci.com/nlohmann/json) [![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) [![Ubuntu](https://github.com/nlohmann/json/workflows/Ubuntu/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AUbuntu) [![macOS](https://github.com/nlohmann/json/workflows/macOS/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AmacOS) [![Windows](https://github.com/nlohmann/json/workflows/Windows/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AWindows) [![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0d1a9d5d6fd46fcb655c4cb930bb3e8)](https://www.codacy.com/gh/nlohmann/json/dashboard?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/nlohmann/json.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nlohmann/json/context:cpp) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/1mp10JbaANo6FUc7) [![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](https://nlohmann.github.io/json/doxygen/index.html) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) [![GitHub Downloads](https://img.shields.io/github/downloads/nlohmann/json/total)](https://github.com/nlohmann/json/releases) [![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](https://github.com/nlohmann/json/issues) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/nlohmann/json.svg)](https://isitmaintained.com/project/nlohmann/json "Average time to resolve an issue") [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/289/badge)](https://bestpractices.coreinfrastructure.org/projects/289) [![GitHub Sponsors](https://img.shields.io/badge/GitHub-Sponsors-ff69b4)](https://github.com/sponsors/nlohmann) - [Design goals](#design-goals) - [Sponsors](#sponsors) - [Support](#support) ([documentation](https://json.nlohmann.me), [FAQ](http://127.0.0.1:8000/home/faq/), [discussions](https://github.com/nlohmann/json/discussions), [API](https://json.nlohmann.me/api/basic_json/), [bug issues](https://github.com/nlohmann/json/issues)) - [Examples](#examples) - [JSON as first-class data type](#json-as-first-class-data-type) - [Serialization / Deserialization](#serialization--deserialization) - [STL-like access](#stl-like-access) - [Conversion from STL containers](#conversion-from-stl-containers) - [JSON Pointer and JSON Patch](#json-pointer-and-json-patch) - [JSON Merge Patch](#json-merge-patch) - [Implicit conversions](#implicit-conversions) - [Conversions to/from arbitrary types](#arbitrary-types-conversions) - [Specializing enum conversion](#specializing-enum-conversion) - [Binary formats (BSON, CBOR, MessagePack, and UBJSON)](#binary-formats-bson-cbor-messagepack-and-ubjson) - [Supported compilers](#supported-compilers) - [Integration](#integration) - [CMake](#cmake) - [Package Managers](#package-managers) - [Pkg-config](#pkg-config) - [License](#license) - [Contact](#contact) - [Thanks](#thanks) - [Used third-party tools](#used-third-party-tools) - [Projects using JSON for Modern C++](#projects-using-json-for-modern-c) - [Notes](#notes) - [Execute unit tests](#execute-unit-tests) ## Design goals There are myriads of [JSON](https://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals: - **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you'll know what I mean. - **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. - **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/test/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](https://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). Other aspects were not so important to us: - **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs. - **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set. See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information. ## Sponsors You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nlohmann). ### :label: Named Sponsors - [Michael Hartmann](https://github.com/reFX-Mike) - [Stefan Hagen](https://github.com/sthagen) - [Steve Sperandeo](https://github.com/homer6) - [Robert Jefe Lindstädt](https://github.com/eljefedelrodeodeljefe) - [Steve Wagner](https://github.com/ciroque) Thanks everyone! ## Support :question: If you have a **question**, please check if it is already answered in the [**FAQ**](https://json.nlohmann.me/home/faq/) or the [**Q&A**](https://github.com/nlohmann/json/discussions/categories/q-a) section. If not, please [**ask a new question**](https://github.com/nlohmann/json/discussions/new) there. :books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/doc/examples), or browse through the [**help pages**](https://json.nlohmann.me). :construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/) or the [**Doxygen documentation**](https://json.nlohmann.me/doxygen/index.html). :bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as many information as possible to help us understand and reproduce your issue. There is also a [**docset**](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for the documentation browsers [Dash](https://kapeli.com/dash), [Velocity](https://velocity.silverlakesoftware.com), and [Zeal](https://zealdocs.org) that contains the full [documentation](https://json.nlohmann.me) as offline resource. ## Examples Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/api/basic_json/emplace/)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). ### JSON as first-class data type Here are some examples to give you an idea how to use the class. Assume you want to create the JSON object ```json { "pi": 3.141, "happy": true, "name": "Niels", "nothing": null, "answer": { "everything": 42 }, "list": [1, 0, 2], "object": { "currency": "USD", "value": 42.99 } } ``` With this library, you could write: ```cpp // create an empty structure (null) json j; // add a number that is stored as double (note the implicit conversion of j to an object) j["pi"] = 3.141; // add a Boolean that is stored as bool j["happy"] = true; // add a string that is stored as std::string j["name"] = "Niels"; // add another null object by passing nullptr j["nothing"] = nullptr; // add an object inside the object j["answer"]["everything"] = 42; // add an array that is stored as std::vector (using an initializer list) j["list"] = { 1, 0, 2 }; // add another object (using an initializer list of pairs) j["object"] = { {"currency", "USD"}, {"value", 42.99} }; // instead, you could also write (which looks very similar to the JSON above) json j2 = { {"pi", 3.141}, {"happy", true}, {"name", "Niels"}, {"nothing", nullptr}, {"answer", { {"everything", 42} }}, {"list", {1, 0, 2}}, {"object", { {"currency", "USD"}, {"value", 42.99} }} }; ``` Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array()`](https://nlohmann.github.io/json/api/basic_json/array/) and [`json::object()`](https://nlohmann.github.io/json/api/basic_json/object/) will help: ```cpp // a way to express the empty array [] json empty_array_explicit = json::array(); // ways to express the empty object {} json empty_object_implicit = json({}); json empty_object_explicit = json::object(); // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} }); ``` ### Serialization / Deserialization #### To/from strings You can create a JSON value (deserialization) by appending `_json` to a string literal: ```cpp // create object from string literal json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; // or even nicer with a raw string literal auto j2 = R"( { "happy": true, "pi": 3.141 } )"_json; ``` Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object. The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/api/basic_json/parse/): ```cpp // parse explicitly auto j3 = json::parse(R"({"happy": true, "pi": 3.141})"); ``` You can also get a string representation of a JSON value (serialize): ```cpp // explicit conversion to string std::string s = j.dump(); // {"happy":true,"pi":3.141} // serialization with pretty printing // pass in the amount of spaces to indent std::cout << j.dump(4) << std::endl; // { // "happy": true, // "pi": 3.141 // } ``` Note the difference between serialization and assignment: ```cpp // store a string in a JSON value json j_string = "this is a string"; // retrieve the string value auto cpp_string = j_string.get(); // retrieve the string value (alternative when an variable already exists) std::string cpp_string2; j_string.get_to(cpp_string2); // retrieve the serialized value (explicit JSON serialization) std::string serialized_string = j_string.dump(); // output of original string std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get() << '\n'; // output of serialized value std::cout << j_string << " == " << serialized_string << std::endl; ``` [`.dump()`](https://nlohmann.github.io/json/api/basic_json/dump/) returns the originally stored string value. Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. #### To/from streams (e.g. files, string streams) You can also use streams to serialize and deserialize: ```cpp // deserialize from standard input json j; std::cin >> j; // serialize to standard output std::cout << j; // the setw manipulator was overloaded to set the indentation for pretty printing std::cout << std::setw(4) << j << std::endl; ``` These operators work for any subclasses of `std::istream` or `std::ostream`. Here is the same example with files: ```cpp // read a JSON file std::ifstream i("file.json"); json j; i >> j; // write prettified JSON to another file std::ofstream o("pretty.json"); o << std::setw(4) << j << std::endl; ``` Please note that setting the exception bit for `failbit` is inappropriate for this use case. It will result in program termination due to the `noexcept` specifier in use. #### Read from iterator range You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose `value_type` is an integral type of 1, 2 or 4 bytes, which will be interpreted as UTF-8, UTF-16 and UTF-32 respectively. For instance, a `std::vector`, or a `std::list`: ```cpp std::vector v = {'t', 'r', 'u', 'e'}; json j = json::parse(v.begin(), v.end()); ``` You may leave the iterators for the range [begin, end): ```cpp std::vector v = {'t', 'r', 'u', 'e'}; json j = json::parse(v); ``` #### Custom data source Since the parse function accepts arbitrary iterator ranges, you can provide your own data sources by implementing the `LegacyInputIterator` concept. ```cpp struct MyContainer { void advance(); const char& get_current(); }; struct MyIterator { using difference_type = std::ptrdiff_t; using value_type = char; using pointer = const char*; using reference = const char&; using iterator_category = std::input_iterator_tag; MyIterator& operator++() { MyContainer.advance(); return *this; } bool operator!=(const MyIterator& rhs) const { return rhs.target != target; } reference operator*() const { return target.get_current(); } MyContainer* target = nullptr; }; MyIterator begin(MyContainer& tgt) { return MyIterator{&tgt}; } MyIterator end(const MyContainer&) { return {}; } void foo() { MyContainer c; json j = json::parse(c); } ``` #### SAX interface The library uses a SAX-like interface with the following functions: ```cpp // called when null is parsed bool null(); // called when a boolean is parsed; value is passed bool boolean(bool val); // called when a signed or unsigned integer number is parsed; value is passed bool number_integer(number_integer_t val); bool number_unsigned(number_unsigned_t val); // called when a floating-point number is parsed; value and original string is passed bool number_float(number_float_t val, const string_t& s); // called when a string is parsed; value is passed and can be safely moved away bool string(string_t& val); // called when a binary value is parsed; value is passed and can be safely moved away bool binary(binary_t& val); // called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known) bool start_object(std::size_t elements); bool end_object(); bool start_array(std::size_t elements); bool end_array(); // called when an object key is parsed; value is passed and can be safely moved away bool key(string_t& val); // called when a parse error occurs; byte position, the last token, and an exception is passed bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex); ``` The return value of each function determines whether parsing should proceed. To implement your own SAX handler, proceed as follows: 1. Implement the SAX interface in a class. You can use class `nlohmann::json_sax` as base class, but you can also use any class where the functions described above are implemented and public. 2. Create an object of your SAX interface class, e.g. `my_sax`. 3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface. Note the `sax_parse` function only returns a `bool` indicating the result of the last executed SAX event. It does not return a `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp). ### STL-like access We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirement. ```cpp // create an array using push_back json j; j.push_back("foo"); j.push_back(1); j.push_back(true); // also use emplace_back j.emplace_back(1.78); // iterate the array for (json::iterator it = j.begin(); it != j.end(); ++it) { std::cout << *it << '\n'; } // range-based for for (auto& element : j) { std::cout << element << '\n'; } // getter/setter const auto tmp = j[0].get(); j[1] = 42; bool foo = j.at(2); // comparison j == R"(["foo", 1, true, 1.78])"_json; // true // other stuff j.size(); // 4 entries j.empty(); // false j.type(); // json::value_t::array j.clear(); // the array is empty again // convenience type checkers j.is_null(); j.is_boolean(); j.is_number(); j.is_object(); j.is_array(); j.is_string(); // create an object json o; o["foo"] = 23; o["bar"] = false; o["baz"] = 3.141; // also use emplace o.emplace("weather", "sunny"); // special iterator member functions for objects for (json::iterator it = o.begin(); it != o.end(); ++it) { std::cout << it.key() << " : " << it.value() << "\n"; } // the same code as range for for (auto& el : o.items()) { std::cout << el.key() << " : " << el.value() << "\n"; } // even easier with structured bindings (C++17) for (auto& [key, value] : o.items()) { std::cout << key << " : " << value << "\n"; } // find an entry if (o.contains("foo")) { // there is an entry with key "foo" } // or via find and an iterator if (o.find("foo") != o.end()) { // there is an entry with key "foo" } // or simpler using count() int foo_present = o.count("foo"); // 1 int fob_present = o.count("fob"); // 0 // delete an entry o.erase("foo"); ``` ### Conversion from STL containers Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON values (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container. ```cpp std::vector c_vector {1, 2, 3, 4}; json j_vec(c_vector); // [1, 2, 3, 4] std::deque c_deque {1.2, 2.3, 3.4, 5.6}; json j_deque(c_deque); // [1.2, 2.3, 3.4, 5.6] std::list c_list {true, true, false, true}; json j_list(c_list); // [true, true, false, true] std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; json j_flist(c_flist); // [12345678909876, 23456789098765, 34567890987654, 45678909876543] std::array c_array {{1, 2, 3, 4}}; json j_array(c_array); // [1, 2, 3, 4] std::set c_set {"one", "two", "three", "four", "one"}; json j_set(c_set); // only one entry for "one" is used // ["four", "one", "three", "two"] std::unordered_set c_uset {"one", "two", "three", "four", "one"}; json j_uset(c_uset); // only one entry for "one" is used // maybe ["two", "three", "four", "one"] std::multiset c_mset {"one", "two", "one", "four"}; json j_mset(c_mset); // both entries for "one" are used // maybe ["one", "two", "one", "four"] std::unordered_multiset c_umset {"one", "two", "one", "four"}; json j_umset(c_umset); // both entries for "one" are used // maybe ["one", "two", "one", "four"] ``` Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON values (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. ```cpp std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; json j_map(c_map); // {"one": 1, "three": 3, "two": 2 } std::unordered_map c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} }; json j_umap(c_umap); // {"one": 1.2, "two": 2.3, "three": 3.4} std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; json j_mmap(c_mmap); // only one entry for key "three" is used // maybe {"one": true, "two": true, "three": true} std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; json j_ummap(c_ummap); // only one entry for key "three" is used // maybe {"one": true, "two": true, "three": true} ``` ### JSON Pointer and JSON Patch The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address structured values. On top of this, **JSON Patch** ([RFC 6902](https://tools.ietf.org/html/rfc6902)) allows to describe differences between two JSON values - effectively allowing patch and diff operations known from Unix. ```cpp // a JSON value json j_original = R"({ "baz": ["one", "two", "three"], "foo": "bar" })"_json; // access members with a JSON pointer (RFC 6901) j_original["/baz/1"_json_pointer]; // "two" // a JSON patch (RFC 6902) json j_patch = R"([ { "op": "replace", "path": "/baz", "value": "boo" }, { "op": "add", "path": "/hello", "value": ["world"] }, { "op": "remove", "path": "/foo"} ])"_json; // apply the patch json j_result = j_original.patch(j_patch); // { // "baz": "boo", // "hello": ["world"] // } // calculate a JSON patch from two JSON values json::diff(j_result, j_original); // [ // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, // { "op": "remove","path": "/hello" }, // { "op": "add", "path": "/foo", "value": "bar" } // ] ``` ### JSON Merge Patch The library supports **JSON Merge Patch** ([RFC 7386](https://tools.ietf.org/html/rfc7386)) as a patch format. Instead of using JSON Pointer (see above) to specify values to be manipulated, it describes the changes using a syntax that closely mimics the document being modified. ```cpp // a JSON value json j_document = R"({ "a": "b", "c": { "d": "e", "f": "g" } })"_json; // a patch json j_patch = R"({ "a":"z", "c": { "f": null } })"_json; // apply the patch j_document.merge_patch(j_patch); // { // "a": "z", // "c": { // "d": "e" // } // } ``` ### Implicit conversions Supported types can be implicitly converted to JSON values. It is recommended to **NOT USE** implicit conversions **FROM** a JSON value. You can find more details about this recommendation [here](https://www.github.com/nlohmann/json/issues/958). You can switch off implicit conversions by defining `JSON_USE_IMPLICIT_CONVERSIONS` to `0` before including the `json.hpp` header. When using CMake, you can also achieve this by setting the option `JSON_ImplicitConversions` to `OFF`. ```cpp // strings std::string s1 = "Hello, world!"; json js = s1; auto s2 = js.get(); // NOT RECOMMENDED std::string s3 = js; std::string s4; s4 = js; // Booleans bool b1 = true; json jb = b1; auto b2 = jb.get(); // NOT RECOMMENDED bool b3 = jb; bool b4; b4 = jb; // numbers int i = 42; json jn = i; auto f = jn.get(); // NOT RECOMMENDED double f2 = jb; double f3; f3 = jb; // etc. ``` Note that `char` types are not automatically converted to JSON strings, but to integer numbers. A conversion to a string must be specified explicitly: ```cpp char ch = 'A'; // ASCII value 65 json j_default = ch; // stores integer number 65 json j_string = std::string(1, ch); // stores string "A" ``` ### Arbitrary types conversions Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines: ```cpp namespace ns { // a simple struct to model a person struct person { std::string name; std::string address; int age; }; } ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; // convert to JSON: copy each value into the JSON object json j; j["name"] = p.name; j["address"] = p.address; j["age"] = p.age; // ... // convert from JSON: copy each value from the JSON object ns::person p { j["name"].get(), j["address"].get(), j["age"].get() }; ``` It works, but that's quite a lot of boilerplate... Fortunately, there's a better way: ```cpp // create a person ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60}; // conversion: person -> json json j = p; std::cout << j << std::endl; // {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} // conversion: json -> person auto p2 = j.get(); // that's it assert(p == p2); ``` #### Basic usage To make this work with one of your types, you only need to provide two functions: ```cpp using json = nlohmann::json; namespace ns { void to_json(json& j, const person& p) { j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}}; } void from_json(const json& j, person& p) { j.at("name").get_to(p.name); j.at("address").get_to(p.address); j.at("age").get_to(p.age); } } // namespace ns ``` That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called. Likewise, when calling `get()` or `get_to(your_type&)`, the `from_json` method will be called. Some important things: * Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined). * Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. * When using `get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) * In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/api/basic_json/at/) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. #### Simplify your life with macros If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: - `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for. - `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members. In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. ##### Examples The `to_json`/`from_json` functions for the `person` struct above can be created with: ```cpp namespace ns { NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) } ``` Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed: ```cpp namespace ns { class address { private: std::string street; int housenumber; int postcode; public: NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) }; } ``` #### How do I convert third-party types? This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: The library uses **JSON Serializers** to convert types to json. The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)). It is implemented like this (simplified): ```cpp template struct adl_serializer { static void to_json(json& j, const T& value) { // calls the "to_json" method in T's namespace } static void from_json(const json& j, T& value) { // same thing, but with the "from_json" method } }; ``` This serializer works fine when you have control over the type's namespace. However, what about `boost::optional` or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`... To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example: ```cpp // partial specialization (full specialization works too) namespace nlohmann { template struct adl_serializer> { static void to_json(json& j, const boost::optional& opt) { if (opt == boost::none) { j = nullptr; } else { j = *opt; // this will call adl_serializer::to_json which will // find the free function to_json in T's namespace! } } static void from_json(const json& j, boost::optional& opt) { if (j.is_null()) { opt = boost::none; } else { opt = j.get(); // same as above, but with // adl_serializer::from_json } } }; } ``` #### How can I use `get()` for non-default constructible/non-copyable types? There is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload: ```cpp struct move_only_type { move_only_type() = delete; move_only_type(int ii): i(ii) {} move_only_type(const move_only_type&) = delete; move_only_type(move_only_type&&) = default; int i; }; namespace nlohmann { template <> struct adl_serializer { // note: the return type is no longer 'void', and the method only takes // one argument static move_only_type from_json(const json& j) { return {j.get()}; } // Here's the catch! You must provide a to_json method! Otherwise you // will not be able to convert move_only_type to json, since you fully // specialized adl_serializer on that type static void to_json(json& j, move_only_type t) { j = t.i; } }; } ``` #### Can I write my own serializer? (Advanced use) Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/test/src/unit-udt.cpp) in the test suite, to see a few examples. If you write your own serializer, you'll need to do a few things: - use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`) - use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods - use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL Here is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL. ```cpp // You should use void as a second template argument // if you don't need compile-time checks on T template::type> struct less_than_32_serializer { template static void to_json(BasicJsonType& j, T value) { // we want to use ADL, and call the correct to_json overload using nlohmann::to_json; // this method is called by adl_serializer, // this is where the magic happens to_json(j, value); } template static void from_json(const BasicJsonType& j, T& value) { // same thing here using nlohmann::from_json; from_json(j, value); } }; ``` Be **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention: ```cpp template struct bad_serializer { template static void to_json(BasicJsonType& j, const T& value) { // this calls BasicJsonType::json_serializer::to_json(j, value); // if BasicJsonType::json_serializer == bad_serializer ... oops! j = value; } template static void to_json(const BasicJsonType& j, T& value) { // this calls BasicJsonType::json_serializer::from_json(j, value); // if BasicJsonType::json_serializer == bad_serializer ... oops! value = j.template get(); // oops! } }; ``` ### Specializing enum conversion By default, enum values are serialized to JSON as integers. In some cases this could result in undesired behavior. If an enum is modified or re-ordered after data has been serialized to JSON, the later de-serialized JSON data may be undefined or a different enum value than was originally intended. It is possible to more precisely specify how a given enum is mapped to and from JSON as shown below: ```cpp // example enum type declaration enum TaskState { TS_STOPPED, TS_RUNNING, TS_COMPLETED, TS_INVALID=-1, }; // map TaskState values to JSON as strings NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, { {TS_INVALID, nullptr}, {TS_STOPPED, "stopped"}, {TS_RUNNING, "running"}, {TS_COMPLETED, "completed"}, }) ``` The `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serialization code. **Usage:** ```cpp // enum to JSON as string json j = TS_STOPPED; assert(j == "stopped"); // json string to enum json j3 = "running"; assert(j3.get() == TS_RUNNING); // undefined json value to enum (where the first map entry above is the default) json jPi = 3.14; assert(jPi.get() == TS_INVALID ); ``` Just as in [Arbitrary Type Conversions](#arbitrary-types-conversions) above, - `NLOHMANN_JSON_SERIALIZE_ENUM()` MUST be declared in your enum type's namespace (which can be the global namespace), or the library will not be able to locate it and it will default to integer serialization. - It MUST be available (e.g., proper headers must be included) everywhere you use the conversions. Other Important points: - When using `get()`, undefined JSON values will default to the first pair specified in your map. Select this default pair carefully. - If an enum or JSON value is specified more than once in your map, the first matching occurrence from the top of the map will be returned when converting to or from JSON. ### Binary formats (BSON, CBOR, MessagePack, and UBJSON) Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [BSON](https://bsonspec.org) (Binary JSON), [CBOR](https://cbor.io) (Concise Binary Object Representation), [MessagePack](https://msgpack.org), and [UBJSON](https://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors. ```cpp // create a JSON value json j = R"({"compact": true, "schema": 0})"_json; // serialize to BSON std::vector v_bson = json::to_bson(j); // 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x00, 0x01, 0x10, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // roundtrip json j_from_bson = json::from_bson(v_bson); // serialize to CBOR std::vector v_cbor = json::to_cbor(j); // 0xA2, 0x67, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xF5, 0x66, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00 // roundtrip json j_from_cbor = json::from_cbor(v_cbor); // serialize to MessagePack std::vector v_msgpack = json::to_msgpack(j); // 0x82, 0xA7, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xC3, 0xA6, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00 // roundtrip json j_from_msgpack = json::from_msgpack(v_msgpack); // serialize to UBJSON std::vector v_ubjson = json::to_ubjson(j); // 0x7B, 0x69, 0x07, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x54, 0x69, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x69, 0x00, 0x7D // roundtrip json j_from_ubjson = json::from_ubjson(v_ubjson); ``` The library also supports binary types from BSON, CBOR (byte strings), and MessagePack (bin, ext, fixext). They are stored by default as `std::vector` to be processed outside of the library. ```cpp // CBOR byte string with payload 0xCAFE std::vector v = {0x42, 0xCA, 0xFE}; // read value json j = json::from_cbor(v); // the JSON value has type binary j.is_binary(); // true // get reference to stored binary value auto& binary = j.get_binary(); // the binary value has no subtype (CBOR has no binary subtypes) binary.has_subtype(); // false // access std::vector member functions binary.size(); // 2 binary[0]; // 0xCA binary[1]; // 0xFE // set subtype to 0x10 binary.set_subtype(0x10); // serialize to MessagePack auto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE ``` ## Supported compilers Though it's 2021 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: - GCC 4.8 - 11.0 (and possibly later) - Clang 3.4 - 13.0 (and possibly later) - Apple Clang 9.1 - 12.4 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) - Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) - Microsoft Visual C++ 2019 / Build Tools 16.3.1+1def00d3d (and possibly later) I would be happy to learn about other compilers/versions. Please note: - GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler. - Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. ``` APP_STL := c++_shared NDK_TOOLCHAIN_VERSION := clang3.6 APP_CPPFLAGS += -frtti -fexceptions ``` The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10. - For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](https://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219). - Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case. The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json), [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [Drone CI](https://cloud.drone.io/nlohmann/json), and [GitHub Actions](https://github.com/nlohmann/json/actions): | Compiler | Operating System | CI Provider | |-------------------------------------------------------------------|--------------------|----------------| | Apple Clang 10.0.1 (clang-1001.0.46.4); Xcode 10.2.1 | macOS 10.14.4 | Travis | | Apple Clang 10.0.1 (clang-1001.0.46.4); Xcode 10.3 | macOS 10.15.7 | GitHub Actions | | Apple Clang 11.0.0 (clang-1100.0.33.12); Xcode 11.2.1 | macOS 10.15.7 | GitHub Actions | | Apple Clang 11.0.0 (clang-1100.0.33.17); Xcode 11.3.1 | macOS 10.15.7 | GitHub Actions | | Apple Clang 11.0.3 (clang-1103.0.32.59); Xcode 11.4.1 | macOS 10.15.7 | GitHub Actions | | Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.5 | macOS 10.15.7 | GitHub Actions | | Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.6 | macOS 10.15.7 | GitHub Actions | | Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.7 | macOS 10.15.7 | GitHub Actions | | Apple Clang 12.0.0 (clang-1200.0.32.2); Xcode 12 | macOS 10.15.7 | GitHub Actions | | Apple Clang 12.0.0 (clang-1200.0.32.21); Xcode 12.1 | macOS 10.15.7 | GitHub Actions | | Apple Clang 12.0.0 (clang-1200.0.32.21); Xcode 12.1.1 | macOS 10.15.7 | GitHub Actions | | Apple Clang 12.0.0 (clang-1200.0.32.27); Xcode 12.2 | macOS 10.15.7 | GitHub Actions | | Apple Clang 12.0.0 (clang-1200.0.32.28); Xcode 12.3 | macOS 10.15.7 | GitHub Actions | | Apple Clang 12.0.0 (clang-1200.0.32.29); Xcode 12.4 | macOS 10.15.7 | GitHub Actions | | GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions | | GCC 4.9.3 (Ubuntu 4.9.3-13ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions | | GCC 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.12) | Ubuntu 20.04.2 LTS | GitHub Actions | | GCC 6.5.0 (Ubuntu 6.5.0-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis | | GCC 7.5.0 (Ubuntu 7.5.0-6ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions | | GCC 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions | | GCC 8.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions | | GCC 8.4.0 (Ubuntu 8.4.0-3ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions | | GCC 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) | Ubuntu 20.04.2 LTS | GitHub Actions | | GCC 10.2.0 (Ubuntu 10.2.0-5ubuntu1~20.04) | Ubuntu 20.04.2 LTS | GitHub Actions | | GCC 11.0.1 20210321 (experimental) | Ubuntu 20.04.2 LTS | GitHub Actions | | GCC 11.1.0 | Ubuntu (aarch64) | Drone CI | | Clang 3.5.2 (3.5.2-3ubuntu1) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 3.6.2 (3.6.2-3ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 3.7.1 (3.7.1-2ubuntu2) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 3.8.0 (3.8.0-2ubuntu4) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 3.9.1 (3.9.1-4ubuntu3\~16.04.2) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 4.0.0 (4.0.0-1ubuntu1\~16.04.2) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 5.0.0 (5.0.0-3\~16.04.1) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 6.0.1 (6.0.1-14) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 7.0.1 (7.0.1-12) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 8.0.1 (8.0.1-9) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 9.0.1 (9.0.1-12) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 10.0.0 (10.0.0-4ubuntu1) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 10.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | | Clang 11.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | | Clang 11.0.0 with MSVC-like command-line | Windows-10.0.17763 | GitHub Actions | | Clang 11.0.0 (11.0.0-2~ubuntu20.04.1) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 12.0.0 (12.0.0-3ubuntu1~20.04.3) | Ubuntu 20.04.2 LTS | GitHub Actions | | Clang 13.0.0 (13.0.0-++20210828094952+9c49fee5e7ac-1exp120210828075752.71 | Ubuntu 20.04.2 LTS | GitHub Actions | | Visual Studio 14 2015 MSVC 19.0.24241.7 (Build Engine version 14.0.25420.1) | Windows-6.3.9600 | AppVeyor | | Visual Studio 15 2017 MSVC 19.16.27035.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | AppVeyor | | Visual Studio 15 2017 MSVC 19.16.27045.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | GitHub Actions | | Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | GitHub Actions | | Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | AppVeyor | ## Integration [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add ```cpp #include // for convenience using json = nlohmann::json; ``` to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`. ### CMake You can also use the `nlohmann_json::nlohmann_json` interface target in CMake. This target populates the appropriate usage requirements for `INTERFACE_INCLUDE_DIRECTORIES` to point to the appropriate include directories and `INTERFACE_COMPILE_FEATURES` for the necessary C++11 flags. #### External To use this library from a CMake project, you can locate it directly with `find_package()` and use the namespaced imported target from the generated package configuration: ```cmake # CMakeLists.txt find_package(nlohmann_json 3.2.0 REQUIRED) ... add_library(foo ...) ... target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) ``` The package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of the build tree. #### Embedded To embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call `add_subdirectory()` in your `CMakeLists.txt` file: ```cmake # Typically you don't care so much for a third party library's tests to be # run from your own project's code. set(JSON_BuildTests OFF CACHE INTERNAL "") # If you only include this third party in PRIVATE source files, you do not # need to install it when your main project gets installed. # set(JSON_Install OFF CACHE INTERNAL "") # Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it # unintended consequences that will break the build. It's generally # discouraged (although not necessarily well documented as such) to use # include(...) for pulling in other CMake projects anyways. add_subdirectory(nlohmann_json) ... add_library(foo ...) ... target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) ``` ##### Embedded (FetchContent) Since CMake v3.11, [FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can be used to automatically download the repository as a dependency at configure time. Example: ```cmake include(FetchContent) FetchContent_Declare(json GIT_REPOSITORY https://github.com/nlohmann/json.git GIT_TAG v3.7.3) FetchContent_GetProperties(json) if(NOT json_POPULATED) FetchContent_Populate(json) add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) endif() target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) ``` **Note**: The repository https://github.com/nlohmann/json download size is huge. It contains all the dataset used for the benchmarks. You might want to depend on a smaller repository. For instance, you might want to replace the URL above by https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent #### Supporting Both To allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin to the following: ``` cmake # Top level CMakeLists.txt project(FOO) ... option(FOO_USE_EXTERNAL_JSON "Use an external JSON library" OFF) ... add_subdirectory(thirdparty) ... add_library(foo ...) ... # Note that the namespaced target will always be available regardless of the # import method target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) ``` ```cmake # thirdparty/CMakeLists.txt ... if(FOO_USE_EXTERNAL_JSON) find_package(nlohmann_json 3.2.0 REQUIRED) else() set(JSON_BuildTests OFF CACHE INTERNAL "") add_subdirectory(nlohmann_json) endif() ... ``` `thirdparty/nlohmann_json` is then a complete copy of this source tree. ### Package Managers :beer: If you are using OS X and [Homebrew](https://brew.sh), just type `brew install nlohmann-json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann-json --HEAD`. See [nlohmann-json](https://formulae.brew.sh/formula/nlohmann-json) for more information. If you are using the [Meson Build System](https://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the `include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. Please see the meson project for any issues regarding the packaging. The provided meson.build can also be used as an alternative to cmake for installing `nlohmann_json` system-wide in which case a pkg-config file is installed. To use it, simply have your build system require the `nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than using the subproject directly. If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add [`nlohmann_json/x.y.z`](https://conan.io/center/nlohmann_json) to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/conan-io/conan-center-index/issues) if you experience problems with the packages. If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging. If you are using [hunter](https://github.com/cpp-pm/hunter) on your project for external dependencies, then you can use the [nlohmann_json package](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging. If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. Please file issues [here](https://github.com/buckaroo-pm/nlohmann-json). There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example). If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can install the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json) with `vcpkg install nlohmann-json` and follow the then displayed descriptions. Please see the vcpkg project for any issues regarding the packaging. If you are using [cget](https://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open). If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please files issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues). If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues). If you are using [MSYS2](https://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, just type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages. If you are using [MacPorts](https://ports.macports.org), execute `sudo port install nlohmann-json` to install the [nlohmann-json](https://ports.macports.org/port/nlohmann-json/) package. If you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) package from the public repository https://cppget.org or directly from the [package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, just add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml). Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if you experience problems with the packages. If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch. If you are using [`CPM.cmake`](https://github.com/TheLartians/CPM.cmake), you can check this [`example`](https://github.com/TheLartians/CPM.cmake/tree/master/examples/json). After [adding CPM script](https://github.com/TheLartians/CPM.cmake#adding-cpm) to your project, implement the following snippet to your CMake: ```cmake CPMAddPackage( NAME nlohmann_json GITHUB_REPOSITORY nlohmann/json VERSION 3.9.1) ``` ### Pkg-config If you are using bare Makefiles, you can use `pkg-config` to generate the include flags that point to where the library is installed: ```sh pkg-config nlohmann_json --cflags ``` Users of the Meson build system will also be able to use a system wide library, which will be found by `pkg-config`: ```meson json = dependency('nlohmann_json', required: true) ``` ## License The class is licensed under the [MIT License](https://opensource.org/licenses/MIT): Copyright © 2013-2021 [Niels Lohmann](https://nlohmann.me) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Softwareâ€), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS ISâ€, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/) The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/). The class contains parts of [Google Abseil](https://github.com/abseil/abseil-cpp) which is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). ## Contact If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new/choose). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases. Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc). ## Security [Commits by Niels Lohmann](https://github.com/nlohmann/json/commits) and [releases](https://github.com/nlohmann/json/releases) are signed with this [PGP Key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69). ## Thanks I deeply appreciate the help of the following people. - [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization. - [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes. - [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries. - [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang. - Tomas Ã…blad found a bug in the iterator implementation. - [Joshua C. Randall](https://github.com/jrandall) fixed a bug in the floating-point serialization. - [Aaron Burghardt](https://github.com/aburgh) implemented code to parse streams incrementally. Furthermore, he greatly improved the parser class by allowing the definition of a filter function to discard undesired elements while parsing. - [Daniel KopeÄek](https://github.com/dkopecek) fixed a bug in the compilation with GCC 5.0. - [Florian Weber](https://github.com/Florianjw) fixed a bug in and improved the performance of the comparison operators. - [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping. - [易æ€é¾™](https://github.com/likebeta) implemented a conversion from anonymous enums. - [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio. - [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types. - [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling. - [dariomt](https://github.com/dariomt) fixed some typos in the examples. - [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation. - [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue. - [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation. - [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. - [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values. - [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. - [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. - [406345](https://github.com/406345) fixed two small warnings. - [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function. - [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. - [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers. - [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file. - [msm-](https://github.com/msm-) added support for American Fuzzy Lop. - [Annihil](https://github.com/Annihil) fixed an example in the README file. - [Themercee](https://github.com/Themercee) noted a wrong URL in the README file. - [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`. - [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212). - [zewt](https://github.com/zewt) added useful notes to the README file about Android. - [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake. - [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files. - [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal). - [Mário Feroldi](https://github.com/thelostt) fixed a small typo. - [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release. - [Damien](https://github.com/dtoma) fixed one of the last conversion warnings. - [Thomas Braun](https://github.com/t-b) fixed a warning in a test case and adjusted MSVC calls in the CI. - [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks. - [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation. - [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`. - [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion. - [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix. - [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file. - [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function. - [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing. - [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan. - [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning. - [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check. - [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one. - [Daniel599](https://github.com/Daniel599) helped to get Travis execute the tests with Clang's sanitizers. - [Jonathan Lee](https://github.com/vjon) fixed an example in the README file. - [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types. - [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio. - [Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types. - [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example. - [Martin HoÅ™eňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite. - [ukhegg](https://github.com/ukhegg) found proposed an improvement for the examples section. - [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README. - [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s. - [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation. - [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings. - [Krzysztof WoÅ›](https://github.com/krzysztofwos) made exceptions more visible. - [ftillier](https://github.com/ftillier) fixed a compiler warning. - [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped. - [Fytch](https://github.com/Fytch) found a bug in the documentation. - [Jay Sistar](https://github.com/Type1J) implemented a Meson build description. - [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation. - [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager. - [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`. - [Mike Tzou](https://github.com/Chocobo1) fixed some typos. - [amrcode](https://github.com/amrcode) noted a misleading documentation about comparison of floats. - [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `` with ``. - [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library. - [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists. - [Greg Hurrell](https://github.com/wincent) fixed a typo. - [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo. - [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler. - [Markus Werle](https://github.com/daixtrose) fixed a typo. - [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check. - [Alex](https://github.com/leha-bot) noted an error in a code sample. - [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped fixing them. - [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams. - [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error. - [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings. - [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file. - [pvleuven](https://github.com/pvleuven) helped fixing a warning in ICC. - [Pavel](https://github.com/crea7or) helped fixing some warnings in MSVC. - [Jamie Seward](https://github.com/jseward) avoided unnecessary string copies in `find()` and `count()`. - [Mitja](https://github.com/Itja) fixed some typos. - [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links. - [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view. - [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings. - [Eren Okka](https://github.com/erengy) fixed some MSVC warnings. - [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed. - [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README. - [zerodefect](https://github.com/zerodefect) fixed a compiler warning. - [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior. - [mark-99](https://github.com/mark-99) helped fixing an ICC error. - [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file. - [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings. - [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager. - [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise. - [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback. - [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type. - [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake. - [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io). - [Carlos O'Ryan](https://github.com/coryan) fixed a typo. - [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section. - [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration. - [Jan Schöppach](https://github.com/dns13) fixed a typo. - [martin-mfg](https://github.com/martin-mfg) fixed a typo. - [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`. - [agrianius](https://github.com/agrianius) added code to use alternative string implementations. - [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function. - [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](cppreference.com). - [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode. - [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases. - [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library. - [thyu](https://github.com/thyu) fixed a compiler warning. - [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2. - [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library. - [Hyeon Kim](https://github.com/simnalamburt) fixed an issue with a double macro definition. - [Ben Berman](https://github.com/rivertam) made some error messages more understandable. - [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler. - [mandreyel](https://github.com/mandreyel) fixed a compilation problem. - [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file. - [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8. - [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory. - [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning. - [Dan Gendreau](https://github.com/dgendreau) implemented the `NLOHMANN_JSON_SERIALIZE_ENUM` macro to quickly define a enum/JSON mapping. - [efp](https://github.com/efp) added line and column information to parse errors. - [julian-becker](https://github.com/julian-becker) added BSON support. - [Pratik Chowdhury](https://github.com/pratikpc) added support for structured bindings. - [David Avedissian](https://github.com/davedissian) added support for Clang 5.0.1 (PS4 version). - [Jonathan Dumaresq](https://github.com/dumarjo) implemented an input adapter to read from `FILE*`. - [kjpus](https://github.com/kjpus) fixed a link in the documentation. - [Manvendra Singh](https://github.com/manu-chroma) fixed a typo in the documentation. - [ziggurat29](https://github.com/ziggurat29) fixed an MSVC warning. - [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC. - [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream. - [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson. - [Michael Behrns-Miller](https://github.com/moodboom) found an issue with a missing namespace. - [Nasztanovics Ferenc](https://github.com/naszta) fixed a compilation issue with libc 2.12. - [Andreas Schwab](https://github.com/andreas-schwab) fixed the endian conversion. - [Mark-Dunning](https://github.com/Mark-Dunning) fixed a warning in MSVC. - [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) added `operator/` for JSON Pointers. - [John-Mark](https://github.com/johnmarkwayve) noted a missing header. - [Vitaly Zaitsev](https://github.com/xvitaly) fixed compilation with GCC 9.0. - [Laurent Stacul](https://github.com/stac47) fixed compilation with GCC 9.0. - [Ivor Wanders](https://github.com/iwanders) helped reducing the CMake requirement to version 3.1. - [njlr](https://github.com/njlr) updated the Buckaroo instructions. - [Lion](https://github.com/lieff) fixed a compilation issue with GCC 7 on CentOS. - [Isaac Nickaein](https://github.com/nickaein) improved the integer serialization performance and implemented the `contains()` function. - [past-due](https://github.com/past-due) suppressed an unfixable warning. - [Elvis Oric](https://github.com/elvisoric) improved Meson support. - [MatÄ›j Plch](https://github.com/Afforix) fixed an example in the README. - [Mark Beckwith](https://github.com/wythe) fixed a typo. - [scinart](https://github.com/scinart) fixed bug in the serializer. - [Patrick Boettcher](https://github.com/pboettch) implemented `push_back()` and `pop_back()` for JSON Pointers. - [Bruno Oliveira](https://github.com/nicoddemus) added support for Conda. - [Michele Caini](https://github.com/skypjack) fixed links in the README. - [Hani](https://github.com/hnkb) documented how to install the library with NuGet. - [Mark Beckwith](https://github.com/wythe) fixed a typo. - [yann-morin-1998](https://github.com/yann-morin-1998) helped reducing the CMake requirement to version 3.1. - [Konstantin Podsvirov](https://github.com/podsvirov) maintains a package for the MSYS2 software distro. - [remyabel](https://github.com/remyabel) added GNUInstallDirs to the CMake files. - [Taylor Howard](https://github.com/taylorhoward92) fixed a unit test. - [Gabe Ron](https://github.com/Macr0Nerd) implemented the `to_string` method. - [Watal M. Iwasaki](https://github.com/heavywatal) fixed a Clang warning. - [Viktor Kirilov](https://github.com/onqtam) switched the unit tests from [Catch](https://github.com/philsquared/Catch) to [doctest](https://github.com/onqtam/doctest) - [Juncheng E](https://github.com/ejcjason) fixed a typo. - [tete17](https://github.com/tete17) fixed a bug in the `contains` function. - [Xav83](https://github.com/Xav83) fixed some cppcheck warnings. - [0xflotus](https://github.com/0xflotus) fixed some typos. - [Christian Deneke](https://github.com/chris0x44) added a const version of `json_pointer::back`. - [Julien Hamaide](https://github.com/crazyjul) made the `items()` function work with custom string types. - [Evan Nemerson](https://github.com/nemequ) updated fixed a bug in Hedley and updated this library accordingly. - [Florian Pigorsch](https://github.com/flopp) fixed a lot of typos. - [Camille Bégué](https://github.com/cbegue) fixed an issue in the conversion from `std::pair` and `std::tuple` to `json`. - [Anthony VH](https://github.com/AnthonyVH) fixed a compile error in an enum deserialization. - [Yuriy Vountesmery](https://github.com/ua-code-dragon) noted a subtle bug in a preprocessor check. - [Chen](https://github.com/dota17) fixed numerous issues in the library. - [Antony Kellermann](https://github.com/aokellermann) added a CI step for GCC 10.1. - [Alex](https://github.com/gistrec) fixed an MSVC warning. - [Rainer](https://github.com/rvjr) proposed an improvement in the floating-point serialization in CBOR. - [Francois Chabot](https://github.com/FrancoisChabot) made performance improvements in the input adapters. - [Arthur Sonzogni](https://github.com/ArthurSonzogni) documented how the library can be included via `FetchContent`. - [Rimas MiseviÄius](https://github.com/rmisev) fixed an error message. - [Alexander Myasnikov](https://github.com/alexandermyasnikov) fixed some examples and a link in the README. - [Hubert Chathi](https://github.com/uhoreg) made CMake's version config file architecture-independent. - [OmnipotentEntity](https://github.com/OmnipotentEntity) implemented the binary values for CBOR, MessagePack, BSON, and UBJSON. - [ArtemSarmini](https://github.com/ArtemSarmini) fixed a compilation issue with GCC 10 and fixed a leak. - [Evgenii Sopov](https://github.com/sea-kg) integrated the library to the wsjcpp package manager. - [Sergey Linev](https://github.com/linev) fixed a compiler warning. - [Miguel Magalhães](https://github.com/magamig) fixed the year in the copyright. - [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) fixed a compilation issue with MSVC. - [Alexander “weej†Jones](https://github.com/alex-weej) fixed an example in the README. - [Antoine CÅ“ur](https://github.com/Coeur) fixed some typos in the documentation. - [jothepro](https://github.com/jothepro) updated links to the Hunter package. - [Dave Lee](https://github.com/kastiglione) fixed link in the README. - [Joël Lamotte](https://github.com/Klaim) added instruction for using Build2's package manager. - [Paul Jurczak](https://github.com/pauljurczak) fixed an example in the README. - [Sonu Lohani](https://github.com/sonulohani) fixed a warning. - [Carlos Gomes Martinho](https://github.com/gocarlos) updated the Conan package source. - [Konstantin Podsvirov](https://github.com/podsvirov) fixed the MSYS2 package documentation. - [Tridacnid](https://github.com/Tridacnid) improved the CMake tests. - [Michael](https://github.com/MBalszun) fixed MSVC warnings. - [Quentin Barbarat](https://github.com/quentin-dev) fixed an example in the documentation. - [XyFreak](https://github.com/XyFreak) fixed a compiler warning. - [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README. - [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input. - [AODQ](https://github.com/AODQ) fixed a compiler warning. - [jwittbrodt](https://github.com/jwittbrodt) made `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` inline. - [pfeatherstone](https://github.com/pfeatherstone) improved the upper bound of arguments of the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros. - [Jan Procházka](https://github.com/jprochazk) fixed a bug in the CBOR parser for binary and string values. - [T0b1-iOS](https://github.com/T0b1-iOS) fixed a bug in the new hash implementation. - [Matthew Bauer](https://github.com/matthewbauer) adjusted the CBOR writer to create tags for binary subtypes. - [gatopeich](https://github.com/gatopeich) implemented an ordered map container for `nlohmann::ordered_json`. - [Érico Nogueira Rolim](https://github.com/ericonr) added support for pkg-config. - [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros. - [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support. - [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`. - [Hannes Domani](https://github.com/ssbssa) provided a GDB pretty printer. - Lars Wirzenius reviewed the README file. - [Jun Jie](https://github.com/ongjunjie) fixed a compiler path in the CMake scripts. - [Ronak Buch](https://github.com/rbuch) fixed typos in the documentation. - [Alexander Karzhenkov](https://github.com/karzhenkov) fixed a move constructor and the Travis builds. - [Leonardo Lima](https://github.com/leozz37) added CPM.Cmake support. - [Joseph Blackman](https://github.com/jbzdarkid) fixed a warning. - [Yaroslav](https://github.com/YarikTH) updated doctest and implemented unit tests. - [Martin Stump](https://github.com/globberwops) fixed a bug in the CMake files. - [Jaakko Moisio](https://github.com/jasujm) fixed a bug in the input adapters. - [bl-ue](https://github.com/bl-ue) fixed some Markdown issues in the README file. - [William A. Wieselquist](https://github.com/wawiesel) fixed an example from the README. - [abbaswasim](https://github.com/abbaswasim) fixed an example from the README. - [Remy Jette](https://github.com/remyjette) fixed a warning. - [Fraser](https://github.com/frasermarlow) fixed the documentation. - [Ben Beasley](https://github.com/musicinmybrain) updated doctest. - [Doron Behar](https://github.com/doronbehar) fixed pkg-config.pc. - [raduteo](https://github.com/raduteo) fixed a warning. - [David Pfahler](https://github.com/theShmoo) added the possibility to compile the library without I/O support. - [Morten Fyhn Amundsen](https://github.com/mortenfyhn) fixed a typo. - [jpl-mac](https://github.com/jpl-mac) allowed to treat the library as a system header in CMake. - [Jason Dsouza](https://github.com/jasmcaus) fixed the indentation of the CMake file. - [offa](https://github.com/offa) added a link to Conan Center to the documentation. - [TotalCaesar659](https://github.com/TotalCaesar659) updated the links in the documentation to use HTTPS. - [Rafail Giavrimis](https://github.com/grafail) fixed the Google Benchmark default branch. - [Louis Dionne](https://github.com/ldionne) fixed a conversion operator. - [justanotheranonymoususer](https://github.com/justanotheranonymoususer) made the examples in the README more consistent. - [Finkman](https://github.com/Finkman) suppressed some `-Wfloat-equal` warnings. - [Ferry Huberts](https://github.com/fhuberts) fixed `-Wswitch-enum` warnings. - [Arseniy Terekhin](https://github.com/senyai) made the GDB pretty-printer robust against unset variable names. - [Amir Masoud Abdol](https://github.com/amirmasoudabdol) updated the Homebrew command as nlohmann/json is now in homebrew-core. - [Hallot](https://github.com/Hallot) fixed some `-Wextra-semi-stmt warnings`. - [Giovanni Cerretani](https://github.com/gcerretani) fixed `-Wunused` warnings on `JSON_DIAGNOSTICS`. - [Bogdan Popescu](https://github.com/Kapeli) hosts the [docset](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for offline documentation viewers. - [Carl Smedstad](https://github.com/carlsmedstad) fixed an assertion error when using `JSON_DIAGNOSTICS`. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. ## Used third-party tools The library itself consists of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot! - [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file - [**American fuzzy lop**](https://lcamtuf.coredump.cx/afl/) for fuzz testing - [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows - [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation - [**Clang**](https://clang.llvm.org) for compilation with code sanitizers - [**CMake**](https://cmake.org) for build automation - [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json) - [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json) - [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json) - [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis - [**doctest**](https://github.com/onqtam/doctest) for the unit tests - [**Doxygen**](https://www.doxygen.nl/index.html) to generate [documentation](https://nlohmann.github.io/json/doxygen/index.html) - [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages - [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md) - [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks - [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros - [**lcov**](http://ltp.sourceforge.net/coverage/lcov.php) to process coverage information and create a HTML view - [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz - [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json)) - [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments. - [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](https://wandbox.org) - [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS - [**Valgrind**](https://valgrind.org) to check for correct memory management - [**Wandbox**](https://wandbox.org) for [online examples](https://wandbox.org/permlink/1mp10JbaANo6FUc7) ## Projects using JSON for Modern C++ The library is currently used in Apple macOS Sierra and iOS 10. I am not sure what they are using the library for, but I am happy that it runs on so many devices. ## Notes ### Character encoding The library supports **Unicode input** as follows: - Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 8259](https://tools.ietf.org/html/rfc8259.html#section-8.1). - `std::u16string` and `std::u32string` can be parsed, assuming UTF-16 and UTF-32 encoding, respectively. These encodings are not supported when reading from files or other input containers. - Other encodings such as Latin-1 or ISO 8859-1 are **not** supported and will yield parse or serialization errors. - [Unicode noncharacters](https://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library. - Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. - The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs. - When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. - To store wide strings (e.g., `std::wstring`), you need to convert them to a a UTF-8 encoded `std::string` before, see [an example](https://json.nlohmann.me/home/faq/#wide-string-handling). ### Comments in JSON This library does not support comments by default. It does so for three reasons: 1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript. 2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012: > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. > Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser. 3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this. However, you can pass set parameter `ignore_comments` to true in the `parse` function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. ### Order of object keys By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". If you do want to preserve the insertion order, you can try the type [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179). Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). ### Memory Release We checked with Valgrind and the Address Sanitizer (ASAN) that there are no memory leaks. If you find that a parsing program with this library does not release memory, please consider the following case and it maybe unrelated to this library. **Your program is compiled with glibc.** There is a tunable threshold that glibc uses to decide whether to actually return memory to the system or whether to cache it for later reuse. If in your program you make lots of small allocations and those small allocations are not a contiguous block and are presumably below the threshold, then they will not get returned to the OS. Here is a related issue [#1924](https://github.com/nlohmann/json/issues/1924). ### Further notes - The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/api/basic_json/operator%5B%5D/) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/api/basic_json/at/). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`. - As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. - The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag. - **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. Note the explanatory [`what()`](https://en.cppreference.com/w/cpp/error/exception/what) string of exceptions is not available for MSVC if exceptions are disabled, see [#2824](https://github.com/nlohmann/json/discussions/2824). ## Execute unit tests To compile and run the tests, you need to execute ```sh $ mkdir build $ cd build $ cmake .. -DJSON_BuildTests=On $ cmake --build . $ ctest --output-on-failure ``` Note that during the `ctest` stage, several JSON test files are downloaded from an [external repository](https://github.com/nlohmann/json_test_data). If policies forbid downloading artifacts during testing, you can download the files yourself and pass the directory with the test files via `-DJSON_TestDataDirectory=path` to CMake. Then, no Internet connectivity is required. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information. In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure` will fail. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information. Some tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information. Note you need to call `cmake -LE "not_reproducible|git_required"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information. As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/compiler-options/compiler-option-details/floating-point-options/fp-model-fp.html) then. sqlitebrowser-sqlitebrowser-5733cb7/libs/json/json.hpp000066400000000000000000035775601463772530400233070ustar00rootroot00000000000000/* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ | | |__ | | | | | | version 3.10.4 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . SPDX-License-Identifier: MIT Copyright (c) 2013-2019 Niels Lohmann . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDE_NLOHMANN_JSON_HPP_ #define INCLUDE_NLOHMANN_JSON_HPP_ #define NLOHMANN_JSON_VERSION_MAJOR 3 #define NLOHMANN_JSON_VERSION_MINOR 10 #define NLOHMANN_JSON_VERSION_PATCH 4 #include // all_of, find, for_each #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list #ifndef JSON_NO_IO #include // istream, ostream #endif // JSON_NO_IO #include // random_access_iterator_tag #include // unique_ptr #include // accumulate #include // string, stoi, to_string #include // declval, forward, move, pair, swap #include // vector // #include #include #include // #include #include // transform #include // array #include // forward_list #include // inserter, front_inserter, end #include // map #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible #include // unordered_map #include // pair, declval #include // valarray // #include #include // exception #include // runtime_error #include // to_string #include // vector // #include #include // array #include // size_t #include // uint8_t #include // string namespace nlohmann { namespace detail { /////////////////////////// // JSON type enumeration // /////////////////////////// /*! @brief the JSON type enumeration This enumeration collects the different JSON types. It is internally used to distinguish the stored values, and the functions @ref basic_json::is_null(), @ref basic_json::is_object(), @ref basic_json::is_array(), @ref basic_json::is_string(), @ref basic_json::is_boolean(), @ref basic_json::is_number() (with @ref basic_json::is_number_integer(), @ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), @ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and @ref basic_json::is_structured() rely on it. @note There are three enumeration entries (number_integer, number_unsigned, and number_float), because the library distinguishes these three types for numbers: @ref basic_json::number_unsigned_t is used for unsigned integers, @ref basic_json::number_integer_t is used for signed integers, and @ref basic_json::number_float_t is used for floating-point numbers or to approximate integers which do not fit in the limits of their respective type. @sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON value with the default value for a given type @since version 1.0.0 */ enum class value_t : std::uint8_t { null, ///< null value object, ///< object (unordered set of name/value pairs) array, ///< array (ordered collection of values) string, ///< string value boolean, ///< boolean value number_integer, ///< number value (signed integer) number_unsigned, ///< number value (unsigned integer) number_float, ///< number value (floating-point) binary, ///< binary array (ordered collection of bytes) discarded ///< discarded by the parser callback function }; /*! @brief comparison operator for JSON types Returns an ordering that is similar to Python: - order: null < boolean < number < object < array < string < binary - furthermore, each type is not smaller than itself - discarded values are not comparable - binary is represented as a b"" string in python and directly comparable to a string; however, making a binary array directly comparable with a string would be surprising behavior in a JSON file. @since version 1.0.0 */ inline bool operator<(const value_t lhs, const value_t rhs) noexcept { static constexpr std::array order = {{ 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, 6 /* binary */ } }; const auto l_index = static_cast(lhs); const auto r_index = static_cast(rhs); return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; } } // namespace detail } // namespace nlohmann // #include #include // #include #include // declval, pair // #include /* Hedley - https://nemequ.github.io/hedley * Created by Evan Nemerson * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to * the public domain worldwide. This software is distributed without * any warranty. * * For details, see . * SPDX-License-Identifier: CC0-1.0 */ #if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) #if defined(JSON_HEDLEY_VERSION) #undef JSON_HEDLEY_VERSION #endif #define JSON_HEDLEY_VERSION 15 #if defined(JSON_HEDLEY_STRINGIFY_EX) #undef JSON_HEDLEY_STRINGIFY_EX #endif #define JSON_HEDLEY_STRINGIFY_EX(x) #x #if defined(JSON_HEDLEY_STRINGIFY) #undef JSON_HEDLEY_STRINGIFY #endif #define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) #if defined(JSON_HEDLEY_CONCAT_EX) #undef JSON_HEDLEY_CONCAT_EX #endif #define JSON_HEDLEY_CONCAT_EX(a,b) a##b #if defined(JSON_HEDLEY_CONCAT) #undef JSON_HEDLEY_CONCAT #endif #define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) #if defined(JSON_HEDLEY_CONCAT3_EX) #undef JSON_HEDLEY_CONCAT3_EX #endif #define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c #if defined(JSON_HEDLEY_CONCAT3) #undef JSON_HEDLEY_CONCAT3 #endif #define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) #if defined(JSON_HEDLEY_VERSION_ENCODE) #undef JSON_HEDLEY_VERSION_ENCODE #endif #define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) #if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) #undef JSON_HEDLEY_VERSION_DECODE_MAJOR #endif #define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) #if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) #undef JSON_HEDLEY_VERSION_DECODE_MINOR #endif #define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) #if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) #undef JSON_HEDLEY_VERSION_DECODE_REVISION #endif #define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) #if defined(JSON_HEDLEY_GNUC_VERSION) #undef JSON_HEDLEY_GNUC_VERSION #endif #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #elif defined(__GNUC__) #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) #endif #if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) #undef JSON_HEDLEY_GNUC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_GNUC_VERSION) #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_MSVC_VERSION) #undef JSON_HEDLEY_MSVC_VERSION #endif #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) #elif defined(_MSC_FULL_VER) && !defined(__ICL) #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) #elif defined(_MSC_VER) && !defined(__ICL) #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) #endif #if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) #undef JSON_HEDLEY_MSVC_VERSION_CHECK #endif #if !defined(JSON_HEDLEY_MSVC_VERSION) #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) #elif defined(_MSC_VER) && (_MSC_VER >= 1400) #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) #elif defined(_MSC_VER) && (_MSC_VER >= 1200) #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) #else #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) #endif #if defined(JSON_HEDLEY_INTEL_VERSION) #undef JSON_HEDLEY_INTEL_VERSION #endif #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) #elif defined(__INTEL_COMPILER) && !defined(__ICL) #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) #endif #if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) #undef JSON_HEDLEY_INTEL_VERSION_CHECK #endif #if defined(JSON_HEDLEY_INTEL_VERSION) #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_INTEL_CL_VERSION) #undef JSON_HEDLEY_INTEL_CL_VERSION #endif #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) #endif #if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK #endif #if defined(JSON_HEDLEY_INTEL_CL_VERSION) #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_PGI_VERSION) #undef JSON_HEDLEY_PGI_VERSION #endif #if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) #endif #if defined(JSON_HEDLEY_PGI_VERSION_CHECK) #undef JSON_HEDLEY_PGI_VERSION_CHECK #endif #if defined(JSON_HEDLEY_PGI_VERSION) #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_SUNPRO_VERSION) #undef JSON_HEDLEY_SUNPRO_VERSION #endif #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) #elif defined(__SUNPRO_C) #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) #elif defined(__SUNPRO_CC) #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) #endif #if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK #endif #if defined(JSON_HEDLEY_SUNPRO_VERSION) #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) #undef JSON_HEDLEY_EMSCRIPTEN_VERSION #endif #if defined(__EMSCRIPTEN__) #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) #endif #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK #endif #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_ARM_VERSION) #undef JSON_HEDLEY_ARM_VERSION #endif #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) #endif #if defined(JSON_HEDLEY_ARM_VERSION_CHECK) #undef JSON_HEDLEY_ARM_VERSION_CHECK #endif #if defined(JSON_HEDLEY_ARM_VERSION) #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_IBM_VERSION) #undef JSON_HEDLEY_IBM_VERSION #endif #if defined(__ibmxl__) #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) #elif defined(__xlC__) && defined(__xlC_ver__) #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) #elif defined(__xlC__) #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) #endif #if defined(JSON_HEDLEY_IBM_VERSION_CHECK) #undef JSON_HEDLEY_IBM_VERSION_CHECK #endif #if defined(JSON_HEDLEY_IBM_VERSION) #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TI_VERSION) #undef JSON_HEDLEY_TI_VERSION #endif #if \ defined(__TI_COMPILER_VERSION__) && \ ( \ defined(__TMS470__) || defined(__TI_ARM__) || \ defined(__MSP430__) || \ defined(__TMS320C2000__) \ ) #if (__TI_COMPILER_VERSION__ >= 16000000) #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #endif #if defined(JSON_HEDLEY_TI_VERSION_CHECK) #undef JSON_HEDLEY_TI_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TI_VERSION) #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TI_CL2000_VERSION) #undef JSON_HEDLEY_TI_CL2000_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TI_CL2000_VERSION) #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TI_CL430_VERSION) #undef JSON_HEDLEY_TI_CL430_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TI_CL430_VERSION) #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TI_ARMCL_VERSION) #undef JSON_HEDLEY_TI_ARMCL_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TI_ARMCL_VERSION) #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TI_CL6X_VERSION) #undef JSON_HEDLEY_TI_CL6X_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TI_CL6X_VERSION) #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TI_CL7X_VERSION) #undef JSON_HEDLEY_TI_CL7X_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TI_CL7X_VERSION) #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TI_CLPRU_VERSION) #undef JSON_HEDLEY_TI_CLPRU_VERSION #endif #if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TI_CLPRU_VERSION) #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_CRAY_VERSION) #undef JSON_HEDLEY_CRAY_VERSION #endif #if defined(_CRAYC) #if defined(_RELEASE_PATCHLEVEL) #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) #else #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) #endif #endif #if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) #undef JSON_HEDLEY_CRAY_VERSION_CHECK #endif #if defined(JSON_HEDLEY_CRAY_VERSION) #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_IAR_VERSION) #undef JSON_HEDLEY_IAR_VERSION #endif #if defined(__IAR_SYSTEMS_ICC__) #if __VER__ > 1000 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) #else #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) #endif #endif #if defined(JSON_HEDLEY_IAR_VERSION_CHECK) #undef JSON_HEDLEY_IAR_VERSION_CHECK #endif #if defined(JSON_HEDLEY_IAR_VERSION) #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TINYC_VERSION) #undef JSON_HEDLEY_TINYC_VERSION #endif #if defined(__TINYC__) #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) #endif #if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) #undef JSON_HEDLEY_TINYC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TINYC_VERSION) #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_DMC_VERSION) #undef JSON_HEDLEY_DMC_VERSION #endif #if defined(__DMC__) #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) #endif #if defined(JSON_HEDLEY_DMC_VERSION_CHECK) #undef JSON_HEDLEY_DMC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_DMC_VERSION) #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_COMPCERT_VERSION) #undef JSON_HEDLEY_COMPCERT_VERSION #endif #if defined(__COMPCERT_VERSION__) #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) #endif #if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK #endif #if defined(JSON_HEDLEY_COMPCERT_VERSION) #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_PELLES_VERSION) #undef JSON_HEDLEY_PELLES_VERSION #endif #if defined(__POCC__) #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) #endif #if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) #undef JSON_HEDLEY_PELLES_VERSION_CHECK #endif #if defined(JSON_HEDLEY_PELLES_VERSION) #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_MCST_LCC_VERSION) #undef JSON_HEDLEY_MCST_LCC_VERSION #endif #if defined(__LCC__) && defined(__LCC_MINOR__) #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) #endif #if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_MCST_LCC_VERSION) #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_GCC_VERSION) #undef JSON_HEDLEY_GCC_VERSION #endif #if \ defined(JSON_HEDLEY_GNUC_VERSION) && \ !defined(__clang__) && \ !defined(JSON_HEDLEY_INTEL_VERSION) && \ !defined(JSON_HEDLEY_PGI_VERSION) && \ !defined(JSON_HEDLEY_ARM_VERSION) && \ !defined(JSON_HEDLEY_CRAY_VERSION) && \ !defined(JSON_HEDLEY_TI_VERSION) && \ !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ !defined(__COMPCERT__) && \ !defined(JSON_HEDLEY_MCST_LCC_VERSION) #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION #endif #if defined(JSON_HEDLEY_GCC_VERSION_CHECK) #undef JSON_HEDLEY_GCC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_GCC_VERSION) #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_HAS_ATTRIBUTE) #undef JSON_HEDLEY_HAS_ATTRIBUTE #endif #if \ defined(__has_attribute) && \ ( \ (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ ) # define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) #else # define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) #else #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) #else #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE #endif #if \ defined(__has_cpp_attribute) && \ defined(__cplusplus) && \ (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) #else #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS #endif #if !defined(__cplusplus) || !defined(__has_cpp_attribute) #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) #elif \ !defined(JSON_HEDLEY_PGI_VERSION) && \ !defined(JSON_HEDLEY_IAR_VERSION) && \ (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) #else #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) #else #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) #else #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_BUILTIN) #undef JSON_HEDLEY_HAS_BUILTIN #endif #if defined(__has_builtin) #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) #else #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) #undef JSON_HEDLEY_GNUC_HAS_BUILTIN #endif #if defined(__has_builtin) #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) #else #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) #undef JSON_HEDLEY_GCC_HAS_BUILTIN #endif #if defined(__has_builtin) #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) #else #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_FEATURE) #undef JSON_HEDLEY_HAS_FEATURE #endif #if defined(__has_feature) #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) #else #define JSON_HEDLEY_HAS_FEATURE(feature) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) #undef JSON_HEDLEY_GNUC_HAS_FEATURE #endif #if defined(__has_feature) #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) #else #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_FEATURE) #undef JSON_HEDLEY_GCC_HAS_FEATURE #endif #if defined(__has_feature) #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) #else #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_EXTENSION) #undef JSON_HEDLEY_HAS_EXTENSION #endif #if defined(__has_extension) #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) #else #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) #undef JSON_HEDLEY_GNUC_HAS_EXTENSION #endif #if defined(__has_extension) #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) #else #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) #undef JSON_HEDLEY_GCC_HAS_EXTENSION #endif #if defined(__has_extension) #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) #else #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) #else #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) #else #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) #else #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_WARNING) #undef JSON_HEDLEY_HAS_WARNING #endif #if defined(__has_warning) #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) #else #define JSON_HEDLEY_HAS_WARNING(warning) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_WARNING) #undef JSON_HEDLEY_GNUC_HAS_WARNING #endif #if defined(__has_warning) #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) #else #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_WARNING) #undef JSON_HEDLEY_GCC_HAS_WARNING #endif #if defined(__has_warning) #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) #else #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ defined(__clang__) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_PRAGMA(value) __pragma(value) #else #define JSON_HEDLEY_PRAGMA(value) #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) #undef JSON_HEDLEY_DIAGNOSTIC_PUSH #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_POP) #undef JSON_HEDLEY_DIAGNOSTIC_POP #endif #if defined(__clang__) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) #elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") #elif \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") #else #define JSON_HEDLEY_DIAGNOSTIC_PUSH #define JSON_HEDLEY_DIAGNOSTIC_POP #endif /* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ #endif #if defined(__cplusplus) # if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") # if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") # if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") # define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ xpr \ JSON_HEDLEY_DIAGNOSTIC_POP # else # define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ xpr \ JSON_HEDLEY_DIAGNOSTIC_POP # endif # else # define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ xpr \ JSON_HEDLEY_DIAGNOSTIC_POP # endif # endif #endif #if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x #endif #if defined(JSON_HEDLEY_CONST_CAST) #undef JSON_HEDLEY_CONST_CAST #endif #if defined(__cplusplus) # define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) #elif \ JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) # define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ ((T) (expr)); \ JSON_HEDLEY_DIAGNOSTIC_POP \ })) #else # define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) #endif #if defined(JSON_HEDLEY_REINTERPRET_CAST) #undef JSON_HEDLEY_REINTERPRET_CAST #endif #if defined(__cplusplus) #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) #else #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) #endif #if defined(JSON_HEDLEY_STATIC_CAST) #undef JSON_HEDLEY_STATIC_CAST #endif #if defined(__cplusplus) #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) #else #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) #endif #if defined(JSON_HEDLEY_CPP_CAST) #undef JSON_HEDLEY_CPP_CAST #endif #if defined(__cplusplus) # if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") # define JSON_HEDLEY_CPP_CAST(T, expr) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ ((T) (expr)) \ JSON_HEDLEY_DIAGNOSTIC_POP # elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) # define JSON_HEDLEY_CPP_CAST(T, expr) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("diag_suppress=Pe137") \ JSON_HEDLEY_DIAGNOSTIC_POP # else # define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) # endif #else # define JSON_HEDLEY_CPP_CAST(T, expr) (expr) #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") #elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) #elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) #elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") #elif \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") #elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) #elif \ JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") #elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") #elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") #elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) #elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) #elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") #elif \ JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") #elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") #elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION #endif #if JSON_HEDLEY_HAS_WARNING("-Wunused-function") #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") #elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) #elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION #endif #if defined(JSON_HEDLEY_DEPRECATED) #undef JSON_HEDLEY_DEPRECATED #endif #if defined(JSON_HEDLEY_DEPRECATED_FOR) #undef JSON_HEDLEY_DEPRECATED_FOR #endif #if \ JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) #elif \ (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) #elif defined(__cplusplus) && (__cplusplus >= 201402L) #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") #else #define JSON_HEDLEY_DEPRECATED(since) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) #endif #if defined(JSON_HEDLEY_UNAVAILABLE) #undef JSON_HEDLEY_UNAVAILABLE #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) #else #define JSON_HEDLEY_UNAVAILABLE(available_since) #endif #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) #undef JSON_HEDLEY_WARN_UNUSED_RESULT #endif #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) #elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) #elif defined(_Check_return_) /* SAL */ #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ #else #define JSON_HEDLEY_WARN_UNUSED_RESULT #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) #endif #if defined(JSON_HEDLEY_SENTINEL) #undef JSON_HEDLEY_SENTINEL #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) #else #define JSON_HEDLEY_SENTINEL(position) #endif #if defined(JSON_HEDLEY_NO_RETURN) #undef JSON_HEDLEY_NO_RETURN #endif #if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_NO_RETURN __noreturn #elif \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define JSON_HEDLEY_NO_RETURN _Noreturn #elif defined(__cplusplus) && (__cplusplus >= 201103L) #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) #elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) #else #define JSON_HEDLEY_NO_RETURN #endif #if defined(JSON_HEDLEY_NO_ESCAPE) #undef JSON_HEDLEY_NO_ESCAPE #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) #else #define JSON_HEDLEY_NO_ESCAPE #endif #if defined(JSON_HEDLEY_UNREACHABLE) #undef JSON_HEDLEY_UNREACHABLE #endif #if defined(JSON_HEDLEY_UNREACHABLE_RETURN) #undef JSON_HEDLEY_UNREACHABLE_RETURN #endif #if defined(JSON_HEDLEY_ASSUME) #undef JSON_HEDLEY_ASSUME #endif #if \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_ASSUME(expr) __assume(expr) #elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) #elif \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) #if defined(__cplusplus) #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) #else #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) #endif #endif #if \ (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() #elif defined(JSON_HEDLEY_ASSUME) #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) #endif #if !defined(JSON_HEDLEY_ASSUME) #if defined(JSON_HEDLEY_UNREACHABLE) #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) #else #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) #endif #endif #if defined(JSON_HEDLEY_UNREACHABLE) #if \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) #else #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() #endif #else #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) #endif #if !defined(JSON_HEDLEY_UNREACHABLE) #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) #endif JSON_HEDLEY_DIAGNOSTIC_PUSH #if JSON_HEDLEY_HAS_WARNING("-Wpedantic") #pragma clang diagnostic ignored "-Wpedantic" #endif #if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" #endif #if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) #if defined(__clang__) #pragma clang diagnostic ignored "-Wvariadic-macros" #elif defined(JSON_HEDLEY_GCC_VERSION) #pragma GCC diagnostic ignored "-Wvariadic-macros" #endif #endif #if defined(JSON_HEDLEY_NON_NULL) #undef JSON_HEDLEY_NON_NULL #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) #else #define JSON_HEDLEY_NON_NULL(...) #endif JSON_HEDLEY_DIAGNOSTIC_POP #if defined(JSON_HEDLEY_PRINTF_FORMAT) #undef JSON_HEDLEY_PRINTF_FORMAT #endif #if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) #elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) #else #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) #endif #if defined(JSON_HEDLEY_CONSTEXPR) #undef JSON_HEDLEY_CONSTEXPR #endif #if defined(__cplusplus) #if __cplusplus >= 201103L #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) #endif #endif #if !defined(JSON_HEDLEY_CONSTEXPR) #define JSON_HEDLEY_CONSTEXPR #endif #if defined(JSON_HEDLEY_PREDICT) #undef JSON_HEDLEY_PREDICT #endif #if defined(JSON_HEDLEY_LIKELY) #undef JSON_HEDLEY_LIKELY #endif #if defined(JSON_HEDLEY_UNLIKELY) #undef JSON_HEDLEY_UNLIKELY #endif #if defined(JSON_HEDLEY_UNPREDICTABLE) #undef JSON_HEDLEY_UNPREDICTABLE #endif #if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) #endif #if \ (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) # define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) # define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) #elif \ (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) # define JSON_HEDLEY_PREDICT(expr, expected, probability) \ (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ (__extension__ ({ \ double hedley_probability_ = (probability); \ ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ })) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ (__extension__ ({ \ double hedley_probability_ = (probability); \ ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ })) # define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #else # define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) # define JSON_HEDLEY_LIKELY(expr) (!!(expr)) # define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) #endif #if !defined(JSON_HEDLEY_UNPREDICTABLE) #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) #endif #if defined(JSON_HEDLEY_MALLOC) #undef JSON_HEDLEY_MALLOC #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_MALLOC __declspec(restrict) #else #define JSON_HEDLEY_MALLOC #endif #if defined(JSON_HEDLEY_PURE) #undef JSON_HEDLEY_PURE #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) # define JSON_HEDLEY_PURE __attribute__((__pure__)) #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) # define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") #elif defined(__cplusplus) && \ ( \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ ) # define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") #else # define JSON_HEDLEY_PURE #endif #if defined(JSON_HEDLEY_CONST) #undef JSON_HEDLEY_CONST #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_CONST __attribute__((__const__)) #elif \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) #define JSON_HEDLEY_CONST _Pragma("no_side_effect") #else #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE #endif #if defined(JSON_HEDLEY_RESTRICT) #undef JSON_HEDLEY_RESTRICT #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) #define JSON_HEDLEY_RESTRICT restrict #elif \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ defined(__clang__) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_RESTRICT __restrict #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) #define JSON_HEDLEY_RESTRICT _Restrict #else #define JSON_HEDLEY_RESTRICT #endif #if defined(JSON_HEDLEY_INLINE) #undef JSON_HEDLEY_INLINE #endif #if \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ (defined(__cplusplus) && (__cplusplus >= 199711L)) #define JSON_HEDLEY_INLINE inline #elif \ defined(JSON_HEDLEY_GCC_VERSION) || \ JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) #define JSON_HEDLEY_INLINE __inline__ #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_INLINE __inline #else #define JSON_HEDLEY_INLINE #endif #if defined(JSON_HEDLEY_ALWAYS_INLINE) #undef JSON_HEDLEY_ALWAYS_INLINE #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) # define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) # define JSON_HEDLEY_ALWAYS_INLINE __forceinline #elif defined(__cplusplus) && \ ( \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ ) # define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) # define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") #else # define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE #endif #if defined(JSON_HEDLEY_NEVER_INLINE) #undef JSON_HEDLEY_NEVER_INLINE #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) #elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") #elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) #else #define JSON_HEDLEY_NEVER_INLINE #endif #if defined(JSON_HEDLEY_PRIVATE) #undef JSON_HEDLEY_PRIVATE #endif #if defined(JSON_HEDLEY_PUBLIC) #undef JSON_HEDLEY_PUBLIC #endif #if defined(JSON_HEDLEY_IMPORT) #undef JSON_HEDLEY_IMPORT #endif #if defined(_WIN32) || defined(__CYGWIN__) # define JSON_HEDLEY_PRIVATE # define JSON_HEDLEY_PUBLIC __declspec(dllexport) # define JSON_HEDLEY_IMPORT __declspec(dllimport) #else # if \ JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ ( \ defined(__TI_EABI__) && \ ( \ (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ ) \ ) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) # define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) # define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) # else # define JSON_HEDLEY_PRIVATE # define JSON_HEDLEY_PUBLIC # endif # define JSON_HEDLEY_IMPORT extern #endif #if defined(JSON_HEDLEY_NO_THROW) #undef JSON_HEDLEY_NO_THROW #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) #define JSON_HEDLEY_NO_THROW __declspec(nothrow) #else #define JSON_HEDLEY_NO_THROW #endif #if defined(JSON_HEDLEY_FALL_THROUGH) #undef JSON_HEDLEY_FALL_THROUGH #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) #elif defined(__fallthrough) /* SAL */ #define JSON_HEDLEY_FALL_THROUGH __fallthrough #else #define JSON_HEDLEY_FALL_THROUGH #endif #if defined(JSON_HEDLEY_RETURNS_NON_NULL) #undef JSON_HEDLEY_RETURNS_NON_NULL #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) #elif defined(_Ret_notnull_) /* SAL */ #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ #else #define JSON_HEDLEY_RETURNS_NON_NULL #endif #if defined(JSON_HEDLEY_ARRAY_PARAM) #undef JSON_HEDLEY_ARRAY_PARAM #endif #if \ defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ !defined(__STDC_NO_VLA__) && \ !defined(__cplusplus) && \ !defined(JSON_HEDLEY_PGI_VERSION) && \ !defined(JSON_HEDLEY_TINYC_VERSION) #define JSON_HEDLEY_ARRAY_PARAM(name) (name) #else #define JSON_HEDLEY_ARRAY_PARAM(name) #endif #if defined(JSON_HEDLEY_IS_CONSTANT) #undef JSON_HEDLEY_IS_CONSTANT #endif #if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) #undef JSON_HEDLEY_REQUIRE_CONSTEXPR #endif /* JSON_HEDLEY_IS_CONSTEXPR_ is for HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(JSON_HEDLEY_IS_CONSTEXPR_) #undef JSON_HEDLEY_IS_CONSTEXPR_ #endif #if \ JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) #endif #if !defined(__cplusplus) # if \ JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) #if defined(__INTPTR_TYPE__) #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) #else #include #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) #endif # elif \ ( \ defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ !defined(JSON_HEDLEY_PGI_VERSION) && \ !defined(JSON_HEDLEY_IAR_VERSION)) || \ (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) #if defined(__INTPTR_TYPE__) #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) #else #include #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) #endif # elif \ defined(JSON_HEDLEY_GCC_VERSION) || \ defined(JSON_HEDLEY_INTEL_VERSION) || \ defined(JSON_HEDLEY_TINYC_VERSION) || \ defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ defined(__clang__) # define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ sizeof(void) != \ sizeof(*( \ 1 ? \ ((void*) ((expr) * 0L) ) : \ ((struct { char v[sizeof(void) * 2]; } *) 1) \ ) \ ) \ ) # endif #endif #if defined(JSON_HEDLEY_IS_CONSTEXPR_) #if !defined(JSON_HEDLEY_IS_CONSTANT) #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) #endif #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) #else #if !defined(JSON_HEDLEY_IS_CONSTANT) #define JSON_HEDLEY_IS_CONSTANT(expr) (0) #endif #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) #endif #if defined(JSON_HEDLEY_BEGIN_C_DECLS) #undef JSON_HEDLEY_BEGIN_C_DECLS #endif #if defined(JSON_HEDLEY_END_C_DECLS) #undef JSON_HEDLEY_END_C_DECLS #endif #if defined(JSON_HEDLEY_C_DECL) #undef JSON_HEDLEY_C_DECL #endif #if defined(__cplusplus) #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { #define JSON_HEDLEY_END_C_DECLS } #define JSON_HEDLEY_C_DECL extern "C" #else #define JSON_HEDLEY_BEGIN_C_DECLS #define JSON_HEDLEY_END_C_DECLS #define JSON_HEDLEY_C_DECL #endif #if defined(JSON_HEDLEY_STATIC_ASSERT) #undef JSON_HEDLEY_STATIC_ASSERT #endif #if \ !defined(__cplusplus) && ( \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ defined(_Static_assert) \ ) # define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) #elif \ (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) # define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) #else # define JSON_HEDLEY_STATIC_ASSERT(expr, message) #endif #if defined(JSON_HEDLEY_NULL) #undef JSON_HEDLEY_NULL #endif #if defined(__cplusplus) #if __cplusplus >= 201103L #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) #elif defined(NULL) #define JSON_HEDLEY_NULL NULL #else #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) #endif #elif defined(NULL) #define JSON_HEDLEY_NULL NULL #else #define JSON_HEDLEY_NULL ((void*) 0) #endif #if defined(JSON_HEDLEY_MESSAGE) #undef JSON_HEDLEY_MESSAGE #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") # define JSON_HEDLEY_MESSAGE(msg) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ JSON_HEDLEY_PRAGMA(message msg) \ JSON_HEDLEY_DIAGNOSTIC_POP #elif \ JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) #elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) #else # define JSON_HEDLEY_MESSAGE(msg) #endif #if defined(JSON_HEDLEY_WARNING) #undef JSON_HEDLEY_WARNING #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") # define JSON_HEDLEY_WARNING(msg) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ JSON_HEDLEY_PRAGMA(clang warning msg) \ JSON_HEDLEY_DIAGNOSTIC_POP #elif \ JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) #else # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) #endif #if defined(JSON_HEDLEY_REQUIRE) #undef JSON_HEDLEY_REQUIRE #endif #if defined(JSON_HEDLEY_REQUIRE_MSG) #undef JSON_HEDLEY_REQUIRE_MSG #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) # if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") # define JSON_HEDLEY_REQUIRE(expr) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ __attribute__((diagnose_if(!(expr), #expr, "error"))) \ JSON_HEDLEY_DIAGNOSTIC_POP # define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ __attribute__((diagnose_if(!(expr), msg, "error"))) \ JSON_HEDLEY_DIAGNOSTIC_POP # else # define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) # define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) # endif #else # define JSON_HEDLEY_REQUIRE(expr) # define JSON_HEDLEY_REQUIRE_MSG(expr,msg) #endif #if defined(JSON_HEDLEY_FLAGS) #undef JSON_HEDLEY_FLAGS #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) #else #define JSON_HEDLEY_FLAGS #endif #if defined(JSON_HEDLEY_FLAGS_CAST) #undef JSON_HEDLEY_FLAGS_CAST #endif #if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) # define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("warning(disable:188)") \ ((T) (expr)); \ JSON_HEDLEY_DIAGNOSTIC_POP \ })) #else # define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) #endif #if defined(JSON_HEDLEY_EMPTY_BASES) #undef JSON_HEDLEY_EMPTY_BASES #endif #if \ (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) #else #define JSON_HEDLEY_EMPTY_BASES #endif /* Remaining macros are deprecated. */ #if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK #endif #if defined(__clang__) #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) #else #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE #endif #define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) #if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE #endif #define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) #if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) #undef JSON_HEDLEY_CLANG_HAS_BUILTIN #endif #define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) #if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) #undef JSON_HEDLEY_CLANG_HAS_FEATURE #endif #define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) #if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) #undef JSON_HEDLEY_CLANG_HAS_EXTENSION #endif #define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) #if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE #endif #define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) #if defined(JSON_HEDLEY_CLANG_HAS_WARNING) #undef JSON_HEDLEY_CLANG_HAS_WARNING #endif #define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) #endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ // #include #include // #include namespace nlohmann { namespace detail { template struct make_void { using type = void; }; template using void_t = typename make_void::type; } // namespace detail } // namespace nlohmann // https://en.cppreference.com/w/cpp/experimental/is_detected namespace nlohmann { namespace detail { struct nonesuch { nonesuch() = delete; ~nonesuch() = delete; nonesuch(nonesuch const&) = delete; nonesuch(nonesuch const&&) = delete; void operator=(nonesuch const&) = delete; void operator=(nonesuch&&) = delete; }; template class Op, class... Args> struct detector { using value_t = std::false_type; using type = Default; }; template class Op, class... Args> struct detector>, Op, Args...> { using value_t = std::true_type; using type = Op; }; template class Op, class... Args> using is_detected = typename detector::value_t; template class Op, class... Args> struct is_detected_lazy : is_detected { }; template class Op, class... Args> using detected_t = typename detector::type; template class Op, class... Args> using detected_or = detector; template class Op, class... Args> using detected_or_t = typename detected_or::type; template class Op, class... Args> using is_detected_exact = std::is_same>; template class Op, class... Args> using is_detected_convertible = std::is_convertible, To>; } // namespace detail } // namespace nlohmann // This file contains all internal macro definitions // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them // exclude unsupported compilers #if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) #if defined(__clang__) #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif #endif // C++ language standard detection // if the user manually specified the used c++ version this is skipped #if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) #define JSON_HAS_CPP_20 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) #define JSON_HAS_CPP_14 #endif // the cpp 11 flag is always specified because it is the minimal required version #define JSON_HAS_CPP_11 #endif // disable documentation warnings on clang #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdocumentation" #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" #endif // allow to disable exceptions #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) #define JSON_INTERNAL_CATCH(exception) catch(exception) #else #include #define JSON_THROW(exception) std::abort() #define JSON_TRY if(true) #define JSON_CATCH(exception) if(false) #define JSON_INTERNAL_CATCH(exception) if(false) #endif // override exception macros #if defined(JSON_THROW_USER) #undef JSON_THROW #define JSON_THROW JSON_THROW_USER #endif #if defined(JSON_TRY_USER) #undef JSON_TRY #define JSON_TRY JSON_TRY_USER #endif #if defined(JSON_CATCH_USER) #undef JSON_CATCH #define JSON_CATCH JSON_CATCH_USER #undef JSON_INTERNAL_CATCH #define JSON_INTERNAL_CATCH JSON_CATCH_USER #endif #if defined(JSON_INTERNAL_CATCH_USER) #undef JSON_INTERNAL_CATCH #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #endif // allow to override assert #if !defined(JSON_ASSERT) #include // assert #define JSON_ASSERT(x) assert(x) #endif // allow to access some private functions (needed by the test suite) #if defined(JSON_TESTS_PRIVATE) #define JSON_PRIVATE_UNLESS_TESTED public #else #define JSON_PRIVATE_UNLESS_TESTED private #endif /*! @brief macro to briefly define a mapping between an enum and JSON @def NLOHMANN_JSON_SERIALIZE_ENUM @since version 3.4.0 */ #define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ template \ inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ { \ static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ static const std::pair m[] = __VA_ARGS__; \ auto it = std::find_if(std::begin(m), std::end(m), \ [e](const std::pair& ej_pair) -> bool \ { \ return ej_pair.first == e; \ }); \ j = ((it != std::end(m)) ? it : std::begin(m))->second; \ } \ template \ inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ { \ static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ static const std::pair m[] = __VA_ARGS__; \ auto it = std::find_if(std::begin(m), std::end(m), \ [&j](const std::pair& ej_pair) -> bool \ { \ return ej_pair.second == j; \ }); \ e = ((it != std::end(m)) ? it : std::begin(m))->first; \ } // Ugly macros to avoid uglier copy-paste when specializing basic_json. They // may be removed in the future once the class is split. #define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ template class ObjectType, \ template class ArrayType, \ class StringType, class BooleanType, class NumberIntegerType, \ class NumberUnsignedType, class NumberFloatType, \ template class AllocatorType, \ template class JSONSerializer, \ class BinaryType> #define NLOHMANN_BASIC_JSON_TPL \ basic_json // Macros to simplify conversion from/to types #define NLOHMANN_JSON_EXPAND( x ) x #define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME #define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ NLOHMANN_JSON_PASTE64, \ NLOHMANN_JSON_PASTE63, \ NLOHMANN_JSON_PASTE62, \ NLOHMANN_JSON_PASTE61, \ NLOHMANN_JSON_PASTE60, \ NLOHMANN_JSON_PASTE59, \ NLOHMANN_JSON_PASTE58, \ NLOHMANN_JSON_PASTE57, \ NLOHMANN_JSON_PASTE56, \ NLOHMANN_JSON_PASTE55, \ NLOHMANN_JSON_PASTE54, \ NLOHMANN_JSON_PASTE53, \ NLOHMANN_JSON_PASTE52, \ NLOHMANN_JSON_PASTE51, \ NLOHMANN_JSON_PASTE50, \ NLOHMANN_JSON_PASTE49, \ NLOHMANN_JSON_PASTE48, \ NLOHMANN_JSON_PASTE47, \ NLOHMANN_JSON_PASTE46, \ NLOHMANN_JSON_PASTE45, \ NLOHMANN_JSON_PASTE44, \ NLOHMANN_JSON_PASTE43, \ NLOHMANN_JSON_PASTE42, \ NLOHMANN_JSON_PASTE41, \ NLOHMANN_JSON_PASTE40, \ NLOHMANN_JSON_PASTE39, \ NLOHMANN_JSON_PASTE38, \ NLOHMANN_JSON_PASTE37, \ NLOHMANN_JSON_PASTE36, \ NLOHMANN_JSON_PASTE35, \ NLOHMANN_JSON_PASTE34, \ NLOHMANN_JSON_PASTE33, \ NLOHMANN_JSON_PASTE32, \ NLOHMANN_JSON_PASTE31, \ NLOHMANN_JSON_PASTE30, \ NLOHMANN_JSON_PASTE29, \ NLOHMANN_JSON_PASTE28, \ NLOHMANN_JSON_PASTE27, \ NLOHMANN_JSON_PASTE26, \ NLOHMANN_JSON_PASTE25, \ NLOHMANN_JSON_PASTE24, \ NLOHMANN_JSON_PASTE23, \ NLOHMANN_JSON_PASTE22, \ NLOHMANN_JSON_PASTE21, \ NLOHMANN_JSON_PASTE20, \ NLOHMANN_JSON_PASTE19, \ NLOHMANN_JSON_PASTE18, \ NLOHMANN_JSON_PASTE17, \ NLOHMANN_JSON_PASTE16, \ NLOHMANN_JSON_PASTE15, \ NLOHMANN_JSON_PASTE14, \ NLOHMANN_JSON_PASTE13, \ NLOHMANN_JSON_PASTE12, \ NLOHMANN_JSON_PASTE11, \ NLOHMANN_JSON_PASTE10, \ NLOHMANN_JSON_PASTE9, \ NLOHMANN_JSON_PASTE8, \ NLOHMANN_JSON_PASTE7, \ NLOHMANN_JSON_PASTE6, \ NLOHMANN_JSON_PASTE5, \ NLOHMANN_JSON_PASTE4, \ NLOHMANN_JSON_PASTE3, \ NLOHMANN_JSON_PASTE2, \ NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) #define NLOHMANN_JSON_PASTE2(func, v1) func(v1) #define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) #define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) #define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) #define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) #define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) #define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) #define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) #define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) #define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) #define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) #define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) #define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) #define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) #define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) #define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) #define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) #define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) #define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) #define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) #define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) #define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) #define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) #define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) #define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) #define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) #define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) #define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) #define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) #define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) #define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) #define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) #define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) #define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) #define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) #define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) #define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) #define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) #define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) #define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) #define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) #define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) #define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) #define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) #define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) #define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) #define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) #define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) #define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) #define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) #define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) #define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) #define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) #define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) #define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) #define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) #define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) #define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) #define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) #define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) #define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) #define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) #define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) #define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; #define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); /*! @brief macro @def NLOHMANN_DEFINE_TYPE_INTRUSIVE @since version 3.9.0 */ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } /*! @brief macro @def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE @since version 3.9.0 */ #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } // inspired from https://stackoverflow.com/a/26745591 // allows to call any std function as if (e.g. with begin): // using std::begin; begin(x); // // it allows using the detected idiom to retrieve the return type // of such an expression #define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ namespace detail { \ using std::std_name; \ \ template \ using result_of_##std_name = decltype(std_name(std::declval()...)); \ } \ \ namespace detail2 { \ struct std_name##_tag \ { \ }; \ \ template \ std_name##_tag std_name(T&&...); \ \ template \ using result_of_##std_name = decltype(std_name(std::declval()...)); \ \ template \ struct would_call_std_##std_name \ { \ static constexpr auto const value = ::nlohmann::detail:: \ is_detected_exact::value; \ }; \ } /* namespace detail2 */ \ \ template \ struct would_call_std_##std_name : detail2::would_call_std_##std_name \ { \ } #ifndef JSON_USE_IMPLICIT_CONVERSIONS #define JSON_USE_IMPLICIT_CONVERSIONS 1 #endif #if JSON_USE_IMPLICIT_CONVERSIONS #define JSON_EXPLICIT #else #define JSON_EXPLICIT explicit #endif #ifndef JSON_DIAGNOSTICS #define JSON_DIAGNOSTICS 0 #endif namespace nlohmann { namespace detail { /*! @brief replace all occurrences of a substring by another string @param[in,out] s the string to manipulate; changed so that all occurrences of @a f are replaced with @a t @param[in] f the substring to replace with @a t @param[in] t the string to replace @a f @pre The search string @a f must not be empty. **This precondition is enforced with an assertion.** @since version 2.0.0 */ inline void replace_substring(std::string& s, const std::string& f, const std::string& t) { JSON_ASSERT(!f.empty()); for (auto pos = s.find(f); // find first occurrence of f pos != std::string::npos; // make sure f was found s.replace(pos, f.size(), t), // replace with t, and pos = s.find(f, pos + t.size())) // find next occurrence of f {} } /*! * @brief string escaping as described in RFC 6901 (Sect. 4) * @param[in] s string to escape * @return escaped string * * Note the order of escaping "~" to "~0" and "/" to "~1" is important. */ inline std::string escape(std::string s) { replace_substring(s, "~", "~0"); replace_substring(s, "/", "~1"); return s; } /*! * @brief string unescaping as described in RFC 6901 (Sect. 4) * @param[in] s string to unescape * @return unescaped string * * Note the order of escaping "~1" to "/" and "~0" to "~" is important. */ static void unescape(std::string& s) { replace_substring(s, "~1", "/"); replace_substring(s, "~0", "~"); } } // namespace detail } // namespace nlohmann // #include #include // size_t namespace nlohmann { namespace detail { /// struct to capture the start position of the current token struct position_t { /// the total number of characters read std::size_t chars_read_total = 0; /// the number of characters read in the current line std::size_t chars_read_current_line = 0; /// the number of lines read std::size_t lines_read = 0; /// conversion to size_t to preserve SAX interface constexpr operator size_t() const { return chars_read_total; } }; } // namespace detail } // namespace nlohmann // #include namespace nlohmann { namespace detail { //////////////// // exceptions // //////////////// /*! @brief general exception of the @ref basic_json class This class is an extension of `std::exception` objects with a member @a id for exception ids. It is used as the base class for all exceptions thrown by the @ref basic_json class. This class can hence be used as "wildcard" to catch exceptions. Subclasses: - @ref parse_error for exceptions indicating a parse error - @ref invalid_iterator for exceptions indicating errors with iterators - @ref type_error for exceptions indicating executing a member function with a wrong type - @ref out_of_range for exceptions indicating access out of the defined range - @ref other_error for exceptions indicating other library errors @internal @note To have nothrow-copy-constructible exceptions, we internally use `std::runtime_error` which can cope with arbitrary-length error messages. Intermediate strings are built with static functions and then passed to the actual constructor. @endinternal @liveexample{The following code shows how arbitrary library exceptions can be caught.,exception} @since version 3.0.0 */ class exception : public std::exception { public: /// returns the explanatory string const char* what() const noexcept override { return m.what(); } /// the id of the exception const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) protected: JSON_HEDLEY_NON_NULL(3) exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} static std::string name(const std::string& ename, int id_) { return "[json.exception." + ename + "." + std::to_string(id_) + "] "; } template static std::string diagnostics(const BasicJsonType& leaf_element) { #if JSON_DIAGNOSTICS std::vector tokens; for (const auto* current = &leaf_element; current->m_parent != nullptr; current = current->m_parent) { switch (current->m_parent->type()) { case value_t::array: { for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i) { if (¤t->m_parent->m_value.array->operator[](i) == current) { tokens.emplace_back(std::to_string(i)); break; } } break; } case value_t::object: { for (const auto& element : *current->m_parent->m_value.object) { if (&element.second == current) { tokens.emplace_back(element.first.c_str()); break; } } break; } case value_t::null: // LCOV_EXCL_LINE case value_t::string: // LCOV_EXCL_LINE case value_t::boolean: // LCOV_EXCL_LINE case value_t::number_integer: // LCOV_EXCL_LINE case value_t::number_unsigned: // LCOV_EXCL_LINE case value_t::number_float: // LCOV_EXCL_LINE case value_t::binary: // LCOV_EXCL_LINE case value_t::discarded: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE break; // LCOV_EXCL_LINE } } if (tokens.empty()) { return ""; } return "(" + std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, [](const std::string & a, const std::string & b) { return a + "/" + detail::escape(b); }) + ") "; #else static_cast(leaf_element); return ""; #endif } private: /// an exception object as storage for error messages std::runtime_error m; }; /*! @brief exception indicating a parse error This exception is thrown by the library when a parse error occurs. Parse errors can occur during the deserialization of JSON text, CBOR, MessagePack, as well as when using JSON Patch. Member @a byte holds the byte index of the last read character in the input file. Exceptions have ids 1xx. name / id | example message | description ------------------------------ | --------------- | ------------------------- json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). json.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed. @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of file. This also holds true when reading a byte vector (CBOR or MessagePack). @liveexample{The following code shows how a `parse_error` exception can be caught.,parse_error} @sa - @ref exception for the base class of the library exceptions @sa - @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref type_error for exceptions indicating executing a member function with a wrong type @sa - @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class parse_error : public exception { public: /*! @brief create a parse error exception @param[in] id_ the id of the exception @param[in] pos the position where the error occurred (or with chars_read_total=0 if the position cannot be determined) @param[in] what_arg the explanatory string @return parse_error object */ template static parse_error create(int id_, const position_t& pos, const std::string& what_arg, const BasicJsonType& context) { std::string w = exception::name("parse_error", id_) + "parse error" + position_string(pos) + ": " + exception::diagnostics(context) + what_arg; return parse_error(id_, pos.chars_read_total, w.c_str()); } template static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, const BasicJsonType& context) { std::string w = exception::name("parse_error", id_) + "parse error" + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + ": " + exception::diagnostics(context) + what_arg; return parse_error(id_, byte_, w.c_str()); } /*! @brief byte index of the parse error The byte index of the last read character in the input file. @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of file. This also holds true when reading a byte vector (CBOR or MessagePack). */ const std::size_t byte; private: parse_error(int id_, std::size_t byte_, const char* what_arg) : exception(id_, what_arg), byte(byte_) {} static std::string position_string(const position_t& pos) { return " at line " + std::to_string(pos.lines_read + 1) + ", column " + std::to_string(pos.chars_read_current_line); } }; /*! @brief exception indicating errors with iterators This exception is thrown if iterators passed to a library function do not match the expected semantics. Exceptions have ids 2xx. name / id | example message | description ----------------------------------- | --------------- | ------------------------- json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). @liveexample{The following code shows how an `invalid_iterator` exception can be caught.,invalid_iterator} @sa - @ref exception for the base class of the library exceptions @sa - @ref parse_error for exceptions indicating a parse error @sa - @ref type_error for exceptions indicating executing a member function with a wrong type @sa - @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class invalid_iterator : public exception { public: template static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context) { std::string w = exception::name("invalid_iterator", id_) + exception::diagnostics(context) + what_arg; return invalid_iterator(id_, w.c_str()); } private: JSON_HEDLEY_NON_NULL(3) invalid_iterator(int id_, const char* what_arg) : exception(id_, what_arg) {} }; /*! @brief exception indicating executing a member function with a wrong type This exception is thrown in case of a type error; that is, a library function is executed on a JSON value whose type does not match the expected semantics. Exceptions have ids 3xx. name / id | example message | description ----------------------------- | --------------- | ------------------------- json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | @liveexample{The following code shows how a `type_error` exception can be caught.,type_error} @sa - @ref exception for the base class of the library exceptions @sa - @ref parse_error for exceptions indicating a parse error @sa - @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class type_error : public exception { public: template static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context) { std::string w = exception::name("type_error", id_) + exception::diagnostics(context) + what_arg; return type_error(id_, w.c_str()); } private: JSON_HEDLEY_NON_NULL(3) type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} }; /*! @brief exception indicating access out of the defined range This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for instance in case of array indices or nonexisting object keys. Exceptions have ids 4xx. name / id | example message | description ------------------------------- | --------------- | ------------------------- json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) | json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | @liveexample{The following code shows how an `out_of_range` exception can be caught.,out_of_range} @sa - @ref exception for the base class of the library exceptions @sa - @ref parse_error for exceptions indicating a parse error @sa - @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref type_error for exceptions indicating executing a member function with a wrong type @sa - @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class out_of_range : public exception { public: template static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context) { std::string w = exception::name("out_of_range", id_) + exception::diagnostics(context) + what_arg; return out_of_range(id_, w.c_str()); } private: JSON_HEDLEY_NON_NULL(3) out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} }; /*! @brief exception indicating other library errors This exception is thrown in case of errors that cannot be classified with the other exception types. Exceptions have ids 5xx. name / id | example message | description ------------------------------ | --------------- | ------------------------- json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. @sa - @ref exception for the base class of the library exceptions @sa - @ref parse_error for exceptions indicating a parse error @sa - @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref type_error for exceptions indicating executing a member function with a wrong type @sa - @ref out_of_range for exceptions indicating access out of the defined range @liveexample{The following code shows how an `other_error` exception can be caught.,other_error} @since version 3.0.0 */ class other_error : public exception { public: template static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context) { std::string w = exception::name("other_error", id_) + exception::diagnostics(context) + what_arg; return other_error(id_, w.c_str()); } private: JSON_HEDLEY_NON_NULL(3) other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} }; } // namespace detail } // namespace nlohmann // #include // #include #include // size_t #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type #include // index_sequence, make_index_sequence, index_sequence_for // #include namespace nlohmann { namespace detail { template using uncvref_t = typename std::remove_cv::type>::type; #ifdef JSON_HAS_CPP_14 // the following utilities are natively available in C++14 using std::enable_if_t; using std::index_sequence; using std::make_index_sequence; using std::index_sequence_for; #else // alias templates to reduce boilerplate template using enable_if_t = typename std::enable_if::type; // The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h // which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. //// START OF CODE FROM GOOGLE ABSEIL // integer_sequence // // Class template representing a compile-time integer sequence. An instantiation // of `integer_sequence` has a sequence of integers encoded in its // type through its template arguments (which is a common need when // working with C++11 variadic templates). `absl::integer_sequence` is designed // to be a drop-in replacement for C++14's `std::integer_sequence`. // // Example: // // template< class T, T... Ints > // void user_function(integer_sequence); // // int main() // { // // user_function's `T` will be deduced to `int` and `Ints...` // // will be deduced to `0, 1, 2, 3, 4`. // user_function(make_integer_sequence()); // } template struct integer_sequence { using value_type = T; static constexpr std::size_t size() noexcept { return sizeof...(Ints); } }; // index_sequence // // A helper template for an `integer_sequence` of `size_t`, // `absl::index_sequence` is designed to be a drop-in replacement for C++14's // `std::index_sequence`. template using index_sequence = integer_sequence; namespace utility_internal { template struct Extend; // Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. template struct Extend, SeqSize, 0> { using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; }; template struct Extend, SeqSize, 1> { using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; }; // Recursion helper for 'make_integer_sequence'. // 'Gen::type' is an alias for 'integer_sequence'. template struct Gen { using type = typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; }; template struct Gen { using type = integer_sequence; }; } // namespace utility_internal // Compile-time sequences of integers // make_integer_sequence // // This template alias is equivalent to // `integer_sequence`, and is designed to be a drop-in // replacement for C++14's `std::make_integer_sequence`. template using make_integer_sequence = typename utility_internal::Gen::type; // make_index_sequence // // This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, // and is designed to be a drop-in replacement for C++14's // `std::make_index_sequence`. template using make_index_sequence = make_integer_sequence; // index_sequence_for // // Converts a typename pack into an index sequence of the same length, and // is designed to be a drop-in replacement for C++14's // `std::index_sequence_for()` template using index_sequence_for = make_index_sequence; //// END OF CODE FROM GOOGLE ABSEIL #endif // dispatch utility (taken from ranges-v3) template struct priority_tag : priority_tag < N - 1 > {}; template<> struct priority_tag<0> {}; // taken from ranges-v3 template struct static_const { static constexpr T value{}; }; template constexpr T static_const::value; } // namespace detail } // namespace nlohmann // #include namespace nlohmann { namespace detail { // dispatching helper struct template struct identity_tag {}; } // namespace detail } // namespace nlohmann // #include #include // numeric_limits #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval #include // tuple // #include // #include #include // random_access_iterator_tag // #include // #include namespace nlohmann { namespace detail { template struct iterator_types {}; template struct iterator_types < It, void_t> { using difference_type = typename It::difference_type; using value_type = typename It::value_type; using pointer = typename It::pointer; using reference = typename It::reference; using iterator_category = typename It::iterator_category; }; // This is required as some compilers implement std::iterator_traits in a way that // doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. template struct iterator_traits { }; template struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> : iterator_types { }; template struct iterator_traits::value>> { using iterator_category = std::random_access_iterator_tag; using value_type = T; using difference_type = ptrdiff_t; using pointer = T*; using reference = T&; }; } // namespace detail } // namespace nlohmann // #include // #include namespace nlohmann { NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); } // namespace nlohmann // #include // #include namespace nlohmann { NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); } // namespace nlohmann // #include // #include // #include #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ #include // int64_t, uint64_t #include // map #include // allocator #include // string #include // vector /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @since version 1.0.0 */ namespace nlohmann { /*! @brief default JSONSerializer template argument This serializer ignores the template arguments and uses ADL ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) for serialization. */ template struct adl_serializer; template class ObjectType = std::map, template class ArrayType = std::vector, class StringType = std::string, class BooleanType = bool, class NumberIntegerType = std::int64_t, class NumberUnsignedType = std::uint64_t, class NumberFloatType = double, template class AllocatorType = std::allocator, template class JSONSerializer = adl_serializer, class BinaryType = std::vector> class basic_json; /*! @brief JSON Pointer A JSON pointer defines a string syntax for identifying a specific value within a JSON document. It can be used with functions `at` and `operator[]`. Furthermore, JSON pointers are the base for JSON patches. @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) @since version 2.0.0 */ template class json_pointer; /*! @brief default JSON class This type is the default specialization of the @ref basic_json class which uses the standard template types. @since version 1.0.0 */ using json = basic_json<>; template struct ordered_map; /*! @brief ordered JSON class This type preserves the insertion order of object keys. @since version 3.9.0 */ using ordered_json = basic_json; } // namespace nlohmann #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ namespace nlohmann { /*! @brief detail namespace with internal helper functions This namespace collects functions that should not be exposed, implementations of some @ref basic_json methods, and meta-programming helpers. @since version 2.1.0 */ namespace detail { ///////////// // helpers // ///////////// // Note to maintainers: // // Every trait in this file expects a non CV-qualified type. // The only exceptions are in the 'aliases for detected' section // (i.e. those of the form: decltype(T::member_function(std::declval()))) // // In this case, T has to be properly CV-qualified to constraint the function arguments // (e.g. to_json(BasicJsonType&, const T&)) template struct is_basic_json : std::false_type {}; NLOHMANN_BASIC_JSON_TPL_DECLARATION struct is_basic_json : std::true_type {}; ////////////////////// // json_ref helpers // ////////////////////// template class json_ref; template struct is_json_ref : std::false_type {}; template struct is_json_ref> : std::true_type {}; ////////////////////////// // aliases for detected // ////////////////////////// template using mapped_type_t = typename T::mapped_type; template using key_type_t = typename T::key_type; template using value_type_t = typename T::value_type; template using difference_type_t = typename T::difference_type; template using pointer_t = typename T::pointer; template using reference_t = typename T::reference; template using iterator_category_t = typename T::iterator_category; template using to_json_function = decltype(T::to_json(std::declval()...)); template using from_json_function = decltype(T::from_json(std::declval()...)); template using get_template_function = decltype(std::declval().template get()); // trait checking if JSONSerializer::from_json(json const&, udt&) exists template struct has_from_json : std::false_type {}; // trait checking if j.get is valid // use this trait instead of std::is_constructible or std::is_convertible, // both rely on, or make use of implicit conversions, and thus fail when T // has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) template struct is_getable { static constexpr bool value = is_detected::value; }; template struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> { using serializer = typename BasicJsonType::template json_serializer; static constexpr bool value = is_detected_exact::value; }; // This trait checks if JSONSerializer::from_json(json const&) exists // this overload is used for non-default-constructible user-defined-types template struct has_non_default_from_json : std::false_type {}; template struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> { using serializer = typename BasicJsonType::template json_serializer; static constexpr bool value = is_detected_exact::value; }; // This trait checks if BasicJsonType::json_serializer::to_json exists // Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. template struct has_to_json : std::false_type {}; template struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> { using serializer = typename BasicJsonType::template json_serializer; static constexpr bool value = is_detected_exact::value; }; /////////////////// // is_ functions // /////////////////// // https://en.cppreference.com/w/cpp/types/conjunction template struct conjunction : std::true_type { }; template struct conjunction : B1 { }; template struct conjunction : std::conditional, B1>::type {}; // https://en.cppreference.com/w/cpp/types/negation template struct negation : std::integral_constant < bool, !B::value > { }; // Reimplementation of is_constructible and is_default_constructible, due to them being broken for // std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). // This causes compile errors in e.g. clang 3.5 or gcc 4.9. template struct is_default_constructible : std::is_default_constructible {}; template struct is_default_constructible> : conjunction, is_default_constructible> {}; template struct is_default_constructible> : conjunction, is_default_constructible> {}; template struct is_default_constructible> : conjunction...> {}; template struct is_default_constructible> : conjunction...> {}; template struct is_constructible : std::is_constructible {}; template struct is_constructible> : is_default_constructible> {}; template struct is_constructible> : is_default_constructible> {}; template struct is_constructible> : is_default_constructible> {}; template struct is_constructible> : is_default_constructible> {}; template struct is_iterator_traits : std::false_type {}; template struct is_iterator_traits> { private: using traits = iterator_traits; public: static constexpr auto value = is_detected::value && is_detected::value && is_detected::value && is_detected::value && is_detected::value; }; template struct is_range { private: using t_ref = typename std::add_lvalue_reference::type; using iterator = detected_t; using sentinel = detected_t; // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator // and https://en.cppreference.com/w/cpp/iterator/sentinel_for // but reimplementing these would be too much work, as a lot of other concepts are used underneath static constexpr auto is_iterator_begin = is_iterator_traits>::value; public: static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; }; template using iterator_t = enable_if_t::value, result_of_begin())>>; template using range_value_t = value_type_t>>; // The following implementation of is_complete_type is taken from // https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ // and is written by Xiang Fan who agreed to using it in this library. template struct is_complete_type : std::false_type {}; template struct is_complete_type : std::true_type {}; template struct is_compatible_object_type_impl : std::false_type {}; template struct is_compatible_object_type_impl < BasicJsonType, CompatibleObjectType, enable_if_t < is_detected::value&& is_detected::value >> { using object_t = typename BasicJsonType::object_t; // macOS's is_constructible does not play well with nonesuch... static constexpr bool value = is_constructible::value && is_constructible::value; }; template struct is_compatible_object_type : is_compatible_object_type_impl {}; template struct is_constructible_object_type_impl : std::false_type {}; template struct is_constructible_object_type_impl < BasicJsonType, ConstructibleObjectType, enable_if_t < is_detected::value&& is_detected::value >> { using object_t = typename BasicJsonType::object_t; static constexpr bool value = (is_default_constructible::value && (std::is_move_assignable::value || std::is_copy_assignable::value) && (is_constructible::value && std::is_same < typename object_t::mapped_type, typename ConstructibleObjectType::mapped_type >::value)) || (has_from_json::value || has_non_default_from_json < BasicJsonType, typename ConstructibleObjectType::mapped_type >::value); }; template struct is_constructible_object_type : is_constructible_object_type_impl {}; template struct is_compatible_string_type { static constexpr auto value = is_constructible::value; }; template struct is_constructible_string_type { static constexpr auto value = is_constructible::value; }; template struct is_compatible_array_type_impl : std::false_type {}; template struct is_compatible_array_type_impl < BasicJsonType, CompatibleArrayType, enable_if_t < is_detected::value&& is_iterator_traits>>::value&& // special case for types like std::filesystem::path whose iterator's value_type are themselves // c.f. https://github.com/nlohmann/json/pull/3073 !std::is_same>::value >> { static constexpr bool value = is_constructible>::value; }; template struct is_compatible_array_type : is_compatible_array_type_impl {}; template struct is_constructible_array_type_impl : std::false_type {}; template struct is_constructible_array_type_impl < BasicJsonType, ConstructibleArrayType, enable_if_t::value >> : std::true_type {}; template struct is_constructible_array_type_impl < BasicJsonType, ConstructibleArrayType, enable_if_t < !std::is_same::value&& !is_compatible_string_type::value&& is_default_constructible::value&& (std::is_move_assignable::value || std::is_copy_assignable::value)&& is_detected::value&& is_iterator_traits>>::value&& is_detected::value&& // special case for types like std::filesystem::path whose iterator's value_type are themselves // c.f. https://github.com/nlohmann/json/pull/3073 !std::is_same>::value&& is_complete_type < detected_t>::value >> { using value_type = range_value_t; static constexpr bool value = std::is_same::value || has_from_json::value || has_non_default_from_json < BasicJsonType, value_type >::value; }; template struct is_constructible_array_type : is_constructible_array_type_impl {}; template struct is_compatible_integer_type_impl : std::false_type {}; template struct is_compatible_integer_type_impl < RealIntegerType, CompatibleNumberIntegerType, enable_if_t < std::is_integral::value&& std::is_integral::value&& !std::is_same::value >> { // is there an assert somewhere on overflows? using RealLimits = std::numeric_limits; using CompatibleLimits = std::numeric_limits; static constexpr auto value = is_constructible::value && CompatibleLimits::is_integer && RealLimits::is_signed == CompatibleLimits::is_signed; }; template struct is_compatible_integer_type : is_compatible_integer_type_impl {}; template struct is_compatible_type_impl: std::false_type {}; template struct is_compatible_type_impl < BasicJsonType, CompatibleType, enable_if_t::value >> { static constexpr bool value = has_to_json::value; }; template struct is_compatible_type : is_compatible_type_impl {}; template struct is_constructible_tuple : std::false_type {}; template struct is_constructible_tuple> : conjunction...> {}; // a naive helper to check if a type is an ordered_map (exploits the fact that // ordered_map inherits capacity() from std::vector) template struct is_ordered_map { using one = char; struct two { char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) }; template static one test( decltype(&C::capacity) ) ; template static two test(...); enum { value = sizeof(test(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) }; // to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) template < typename T, typename U, enable_if_t < !std::is_same::value, int > = 0 > T conditional_static_cast(U value) { return static_cast(value); } template::value, int> = 0> T conditional_static_cast(U value) { return value; } } // namespace detail } // namespace nlohmann // #include #ifdef JSON_HAS_CPP_17 #include #endif namespace nlohmann { namespace detail { template void from_json(const BasicJsonType& j, typename std::nullptr_t& n) { if (JSON_HEDLEY_UNLIKELY(!j.is_null())) { JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()), j)); } n = nullptr; } // overloads for basic_json template parameters template < typename BasicJsonType, typename ArithmeticType, enable_if_t < std::is_arithmetic::value&& !std::is_same::value, int > = 0 > void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) { switch (static_cast(j)) { case value_t::number_unsigned: { val = static_cast(*j.template get_ptr()); break; } case value_t::number_integer: { val = static_cast(*j.template get_ptr()); break; } case value_t::number_float: { val = static_cast(*j.template get_ptr()); break; } case value_t::null: case value_t::object: case value_t::array: case value_t::string: case value_t::boolean: case value_t::binary: case value_t::discarded: default: JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); } } template void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) { if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) { JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()), j)); } b = *j.template get_ptr(); } template void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) { if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); } s = *j.template get_ptr(); } template < typename BasicJsonType, typename ConstructibleStringType, enable_if_t < is_constructible_string_type::value&& !std::is_same::value, int > = 0 > void from_json(const BasicJsonType& j, ConstructibleStringType& s) { if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); } s = *j.template get_ptr(); } template void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) { get_arithmetic_value(j, val); } template void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) { get_arithmetic_value(j, val); } template void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) { get_arithmetic_value(j, val); } template::value, int> = 0> void from_json(const BasicJsonType& j, EnumType& e) { typename std::underlying_type::type val; get_arithmetic_value(j, val); e = static_cast(val); } // forward_list doesn't have an insert method template::value, int> = 0> void from_json(const BasicJsonType& j, std::forward_list& l) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); } l.clear(); std::transform(j.rbegin(), j.rend(), std::front_inserter(l), [](const BasicJsonType & i) { return i.template get(); }); } // valarray doesn't have an insert method template::value, int> = 0> void from_json(const BasicJsonType& j, std::valarray& l) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); } l.resize(j.size()); std::transform(j.begin(), j.end(), std::begin(l), [](const BasicJsonType & elem) { return elem.template get(); }); } template auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) -> decltype(j.template get(), void()) { for (std::size_t i = 0; i < N; ++i) { arr[i] = j.at(i).template get(); } } template void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) { arr = *j.template get_ptr(); } template auto from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) -> decltype(j.template get(), void()) { for (std::size_t i = 0; i < N; ++i) { arr[i] = j.at(i).template get(); } } template::value, int> = 0> auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) -> decltype( arr.reserve(std::declval()), j.template get(), void()) { using std::end; ConstructibleArrayType ret; ret.reserve(j.size()); std::transform(j.begin(), j.end(), std::inserter(ret, end(ret)), [](const BasicJsonType & i) { // get() returns *this, this won't call a from_json // method when value_type is BasicJsonType return i.template get(); }); arr = std::move(ret); } template::value, int> = 0> void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<0> /*unused*/) { using std::end; ConstructibleArrayType ret; std::transform( j.begin(), j.end(), std::inserter(ret, end(ret)), [](const BasicJsonType & i) { // get() returns *this, this won't call a from_json // method when value_type is BasicJsonType return i.template get(); }); arr = std::move(ret); } template < typename BasicJsonType, typename ConstructibleArrayType, enable_if_t < is_constructible_array_type::value&& !is_constructible_object_type::value&& !is_constructible_string_type::value&& !std::is_same::value&& !is_basic_json::value, int > = 0 > auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), j.template get(), void()) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); } from_json_array_impl(j, arr, priority_tag<3> {}); } template < typename BasicJsonType, typename T, std::size_t... Idx > std::array from_json_inplace_array_impl(BasicJsonType&& j, identity_tag> /*unused*/, index_sequence /*unused*/) { return { { std::forward(j).at(Idx).template get()... } }; } template < typename BasicJsonType, typename T, std::size_t N > auto from_json(BasicJsonType&& j, identity_tag> tag) -> decltype(from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {})) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); } return from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {}); } template void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) { if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) { JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()), j)); } bin = *j.template get_ptr(); } template::value, int> = 0> void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) { if (JSON_HEDLEY_UNLIKELY(!j.is_object())) { JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()), j)); } ConstructibleObjectType ret; const auto* inner_object = j.template get_ptr(); using value_type = typename ConstructibleObjectType::value_type; std::transform( inner_object->begin(), inner_object->end(), std::inserter(ret, ret.begin()), [](typename BasicJsonType::object_t::value_type const & p) { return value_type(p.first, p.second.template get()); }); obj = std::move(ret); } // overload for arithmetic types, not chosen for basic_json template arguments // (BooleanType, etc..); note: Is it really necessary to provide explicit // overloads for boolean_t etc. in case of a custom BooleanType which is not // an arithmetic type? template < typename BasicJsonType, typename ArithmeticType, enable_if_t < std::is_arithmetic::value&& !std::is_same::value&& !std::is_same::value&& !std::is_same::value&& !std::is_same::value, int > = 0 > void from_json(const BasicJsonType& j, ArithmeticType& val) { switch (static_cast(j)) { case value_t::number_unsigned: { val = static_cast(*j.template get_ptr()); break; } case value_t::number_integer: { val = static_cast(*j.template get_ptr()); break; } case value_t::number_float: { val = static_cast(*j.template get_ptr()); break; } case value_t::boolean: { val = static_cast(*j.template get_ptr()); break; } case value_t::null: case value_t::object: case value_t::array: case value_t::string: case value_t::binary: case value_t::discarded: default: JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); } } template std::tuple from_json_tuple_impl_base(BasicJsonType&& j, index_sequence /*unused*/) { return std::make_tuple(std::forward(j).at(Idx).template get()...); } template < typename BasicJsonType, class A1, class A2 > std::pair from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<0> /*unused*/) { return {std::forward(j).at(0).template get(), std::forward(j).at(1).template get()}; } template void from_json_tuple_impl(BasicJsonType&& j, std::pair& p, priority_tag<1> /*unused*/) { p = from_json_tuple_impl(std::forward(j), identity_tag> {}, priority_tag<0> {}); } template std::tuple from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<2> /*unused*/) { return from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); } template void from_json_tuple_impl(BasicJsonType&& j, std::tuple& t, priority_tag<3> /*unused*/) { t = from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); } template auto from_json(BasicJsonType&& j, TupleRelated&& t) -> decltype(from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {})) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); } return from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {}); } template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, typename = enable_if_t < !std::is_constructible < typename BasicJsonType::string_t, Key >::value >> void from_json(const BasicJsonType& j, std::map& m) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); } m.clear(); for (const auto& p : j) { if (JSON_HEDLEY_UNLIKELY(!p.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()), j)); } m.emplace(p.at(0).template get(), p.at(1).template get()); } } template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, typename = enable_if_t < !std::is_constructible < typename BasicJsonType::string_t, Key >::value >> void from_json(const BasicJsonType& j, std::unordered_map& m) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); } m.clear(); for (const auto& p : j) { if (JSON_HEDLEY_UNLIKELY(!p.is_array())) { JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()), j)); } m.emplace(p.at(0).template get(), p.at(1).template get()); } } #ifdef JSON_HAS_CPP_17 template void from_json(const BasicJsonType& j, std::filesystem::path& p) { if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); } p = *j.template get_ptr(); } #endif struct from_json_fn { template auto operator()(const BasicJsonType& j, T&& val) const noexcept(noexcept(from_json(j, std::forward(val)))) -> decltype(from_json(j, std::forward(val))) { return from_json(j, std::forward(val)); } }; } // namespace detail /// namespace to hold default `from_json` function /// to see why this is required: /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) { constexpr const auto& from_json = detail::static_const::value; // NOLINT(misc-definitions-in-headers) } // namespace } // namespace nlohmann // #include #include // copy #include // begin, end #include // string #include // tuple, get #include // is_same, is_constructible, is_floating_point, is_enum, underlying_type #include // move, forward, declval, pair #include // valarray #include // vector // #include // #include #include // size_t #include // input_iterator_tag #include // string, to_string #include // tuple_size, get, tuple_element #include // move // #include // #include namespace nlohmann { namespace detail { template void int_to_string( string_type& target, std::size_t value ) { // For ADL using std::to_string; target = to_string(value); } template class iteration_proxy_value { public: using difference_type = std::ptrdiff_t; using value_type = iteration_proxy_value; using pointer = value_type * ; using reference = value_type & ; using iterator_category = std::input_iterator_tag; using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; private: /// the iterator IteratorType anchor; /// an index for arrays (used to create key names) std::size_t array_index = 0; /// last stringified array index mutable std::size_t array_index_last = 0; /// a string representation of the array index mutable string_type array_index_str = "0"; /// an empty string (to return a reference for primitive values) const string_type empty_str{}; public: explicit iteration_proxy_value(IteratorType it) noexcept : anchor(std::move(it)) {} /// dereference operator (needed for range-based for) iteration_proxy_value& operator*() { return *this; } /// increment operator (needed for range-based for) iteration_proxy_value& operator++() { ++anchor; ++array_index; return *this; } /// equality operator (needed for InputIterator) bool operator==(const iteration_proxy_value& o) const { return anchor == o.anchor; } /// inequality operator (needed for range-based for) bool operator!=(const iteration_proxy_value& o) const { return anchor != o.anchor; } /// return key of the iterator const string_type& key() const { JSON_ASSERT(anchor.m_object != nullptr); switch (anchor.m_object->type()) { // use integer array index as key case value_t::array: { if (array_index != array_index_last) { int_to_string( array_index_str, array_index ); array_index_last = array_index; } return array_index_str; } // use key from the object case value_t::object: return anchor.key(); // use an empty key for all primitive types case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: return empty_str; } } /// return value of the iterator typename IteratorType::reference value() const { return anchor.value(); } }; /// proxy class for the items() function template class iteration_proxy { private: /// the container to iterate typename IteratorType::reference container; public: /// construct iteration proxy from a container explicit iteration_proxy(typename IteratorType::reference cont) noexcept : container(cont) {} /// return iterator begin (needed for range-based for) iteration_proxy_value begin() noexcept { return iteration_proxy_value(container.begin()); } /// return iterator end (needed for range-based for) iteration_proxy_value end() noexcept { return iteration_proxy_value(container.end()); } }; // Structured Bindings Support // For further reference see https://blog.tartanllama.xyz/structured-bindings/ // And see https://github.com/nlohmann/json/pull/1391 template = 0> auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) { return i.key(); } // Structured Bindings Support // For further reference see https://blog.tartanllama.xyz/structured-bindings/ // And see https://github.com/nlohmann/json/pull/1391 template = 0> auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) { return i.value(); } } // namespace detail } // namespace nlohmann // The Addition to the STD Namespace is required to add // Structured Bindings Support to the iteration_proxy_value class // For further reference see https://blog.tartanllama.xyz/structured-bindings/ // And see https://github.com/nlohmann/json/pull/1391 namespace std { #if defined(__clang__) // Fix: https://github.com/nlohmann/json/issues/1401 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmismatched-tags" #endif template class tuple_size<::nlohmann::detail::iteration_proxy_value> : public std::integral_constant {}; template class tuple_element> { public: using type = decltype( get(std::declval < ::nlohmann::detail::iteration_proxy_value> ())); }; #if defined(__clang__) #pragma clang diagnostic pop #endif } // namespace std // #include // #include // #include #ifdef JSON_HAS_CPP_17 #include #endif namespace nlohmann { namespace detail { ////////////////// // constructors // ////////////////// /* * Note all external_constructor<>::construct functions need to call * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an * allocated value (e.g., a string). See bug issue * https://github.com/nlohmann/json/issues/2865 for more information. */ template struct external_constructor; template<> struct external_constructor { template static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept { j.m_value.destroy(j.m_type); j.m_type = value_t::boolean; j.m_value = b; j.assert_invariant(); } }; template<> struct external_constructor { template static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) { j.m_value.destroy(j.m_type); j.m_type = value_t::string; j.m_value = s; j.assert_invariant(); } template static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) { j.m_value.destroy(j.m_type); j.m_type = value_t::string; j.m_value = std::move(s); j.assert_invariant(); } template < typename BasicJsonType, typename CompatibleStringType, enable_if_t < !std::is_same::value, int > = 0 > static void construct(BasicJsonType& j, const CompatibleStringType& str) { j.m_value.destroy(j.m_type); j.m_type = value_t::string; j.m_value.string = j.template create(str); j.assert_invariant(); } }; template<> struct external_constructor { template static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) { j.m_value.destroy(j.m_type); j.m_type = value_t::binary; j.m_value = typename BasicJsonType::binary_t(b); j.assert_invariant(); } template static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) { j.m_value.destroy(j.m_type); j.m_type = value_t::binary; j.m_value = typename BasicJsonType::binary_t(std::move(b)); j.assert_invariant(); } }; template<> struct external_constructor { template static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept { j.m_value.destroy(j.m_type); j.m_type = value_t::number_float; j.m_value = val; j.assert_invariant(); } }; template<> struct external_constructor { template static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept { j.m_value.destroy(j.m_type); j.m_type = value_t::number_unsigned; j.m_value = val; j.assert_invariant(); } }; template<> struct external_constructor { template static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept { j.m_value.destroy(j.m_type); j.m_type = value_t::number_integer; j.m_value = val; j.assert_invariant(); } }; template<> struct external_constructor { template static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) { j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = arr; j.set_parents(); j.assert_invariant(); } template static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) { j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = std::move(arr); j.set_parents(); j.assert_invariant(); } template < typename BasicJsonType, typename CompatibleArrayType, enable_if_t < !std::is_same::value, int > = 0 > static void construct(BasicJsonType& j, const CompatibleArrayType& arr) { using std::begin; using std::end; j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value.array = j.template create(begin(arr), end(arr)); j.set_parents(); j.assert_invariant(); } template static void construct(BasicJsonType& j, const std::vector& arr) { j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = value_t::array; j.m_value.array->reserve(arr.size()); for (const bool x : arr) { j.m_value.array->push_back(x); j.set_parent(j.m_value.array->back()); } j.assert_invariant(); } template::value, int> = 0> static void construct(BasicJsonType& j, const std::valarray& arr) { j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = value_t::array; j.m_value.array->resize(arr.size()); if (arr.size() > 0) { std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); } j.set_parents(); j.assert_invariant(); } }; template<> struct external_constructor { template static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) { j.m_value.destroy(j.m_type); j.m_type = value_t::object; j.m_value = obj; j.set_parents(); j.assert_invariant(); } template static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) { j.m_value.destroy(j.m_type); j.m_type = value_t::object; j.m_value = std::move(obj); j.set_parents(); j.assert_invariant(); } template < typename BasicJsonType, typename CompatibleObjectType, enable_if_t < !std::is_same::value, int > = 0 > static void construct(BasicJsonType& j, const CompatibleObjectType& obj) { using std::begin; using std::end; j.m_value.destroy(j.m_type); j.m_type = value_t::object; j.m_value.object = j.template create(begin(obj), end(obj)); j.set_parents(); j.assert_invariant(); } }; ///////////// // to_json // ///////////// template::value, int> = 0> void to_json(BasicJsonType& j, T b) noexcept { external_constructor::construct(j, b); } template::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleString& s) { external_constructor::construct(j, s); } template void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) { external_constructor::construct(j, std::move(s)); } template::value, int> = 0> void to_json(BasicJsonType& j, FloatType val) noexcept { external_constructor::construct(j, static_cast(val)); } template::value, int> = 0> void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept { external_constructor::construct(j, static_cast(val)); } template::value, int> = 0> void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept { external_constructor::construct(j, static_cast(val)); } template::value, int> = 0> void to_json(BasicJsonType& j, EnumType e) noexcept { using underlying_type = typename std::underlying_type::type; external_constructor::construct(j, static_cast(e)); } template void to_json(BasicJsonType& j, const std::vector& e) { external_constructor::construct(j, e); } template < typename BasicJsonType, typename CompatibleArrayType, enable_if_t < is_compatible_array_type::value&& !is_compatible_object_type::value&& !is_compatible_string_type::value&& !std::is_same::value&& !is_basic_json::value, int > = 0 > void to_json(BasicJsonType& j, const CompatibleArrayType& arr) { external_constructor::construct(j, arr); } template void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) { external_constructor::construct(j, bin); } template::value, int> = 0> void to_json(BasicJsonType& j, const std::valarray& arr) { external_constructor::construct(j, std::move(arr)); } template void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) { external_constructor::construct(j, std::move(arr)); } template < typename BasicJsonType, typename CompatibleObjectType, enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > void to_json(BasicJsonType& j, const CompatibleObjectType& obj) { external_constructor::construct(j, obj); } template void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) { external_constructor::construct(j, std::move(obj)); } template < typename BasicJsonType, typename T, std::size_t N, enable_if_t < !std::is_constructible::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) int > = 0 > void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) { external_constructor::construct(j, arr); } template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > void to_json(BasicJsonType& j, const std::pair& p) { j = { p.first, p.second }; } // for https://github.com/nlohmann/json/pull/1134 template>::value, int> = 0> void to_json(BasicJsonType& j, const T& b) { j = { {b.key(), b.value()} }; } template void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) { j = { std::get(t)... }; } template::value, int > = 0> void to_json(BasicJsonType& j, const T& t) { to_json_tuple_impl(j, t, make_index_sequence::value> {}); } #ifdef JSON_HAS_CPP_17 template void to_json(BasicJsonType& j, const std::filesystem::path& p) { j = p.string(); } #endif struct to_json_fn { template auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) -> decltype(to_json(j, std::forward(val)), void()) { return to_json(j, std::forward(val)); } }; } // namespace detail /// namespace to hold default `to_json` function /// to see why this is required: /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) { constexpr const auto& to_json = detail::static_const::value; // NOLINT(misc-definitions-in-headers) } // namespace } // namespace nlohmann // #include // #include namespace nlohmann { template struct adl_serializer { /*! @brief convert a JSON value to any value type This function is usually called by the `get()` function of the @ref basic_json class (either explicit or via conversion operators). @note This function is chosen for default-constructible value types. @param[in] j JSON value to read from @param[in,out] val value to write to */ template static auto from_json(BasicJsonType && j, TargetType& val) noexcept( noexcept(::nlohmann::from_json(std::forward(j), val))) -> decltype(::nlohmann::from_json(std::forward(j), val), void()) { ::nlohmann::from_json(std::forward(j), val); } /*! @brief convert a JSON value to any value type This function is usually called by the `get()` function of the @ref basic_json class (either explicit or via conversion operators). @note This function is chosen for value types which are not default-constructible. @param[in] j JSON value to read from @return copy of the JSON value, converted to @a ValueType */ template static auto from_json(BasicJsonType && j) noexcept( noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) { return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); } /*! @brief convert any value type to a JSON value This function is usually called by the constructors of the @ref basic_json class. @param[in,out] j JSON value to write to @param[in] val value to read from */ template static auto to_json(BasicJsonType& j, TargetType && val) noexcept( noexcept(::nlohmann::to_json(j, std::forward(val)))) -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) { ::nlohmann::to_json(j, std::forward(val)); } }; } // namespace nlohmann // #include #include // uint8_t, uint64_t #include // tie #include // move namespace nlohmann { /*! @brief an internal type for a backed binary type This type extends the template parameter @a BinaryType provided to `basic_json` with a subtype used by BSON and MessagePack. This type exists so that the user does not have to specify a type themselves with a specific naming scheme in order to override the binary type. @tparam BinaryType container to store bytes (`std::vector` by default) @since version 3.8.0; changed type of subtypes to std::uint64_t in 3.10.0. */ template class byte_container_with_subtype : public BinaryType { public: /// the type of the underlying container using container_type = BinaryType; /// the type of the subtype using subtype_type = std::uint64_t; byte_container_with_subtype() noexcept(noexcept(container_type())) : container_type() {} byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) : container_type(b) {} byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) : container_type(std::move(b)) {} byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) : container_type(b) , m_subtype(subtype_) , m_has_subtype(true) {} byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) : container_type(std::move(b)) , m_subtype(subtype_) , m_has_subtype(true) {} bool operator==(const byte_container_with_subtype& rhs) const { return std::tie(static_cast(*this), m_subtype, m_has_subtype) == std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); } bool operator!=(const byte_container_with_subtype& rhs) const { return !(rhs == *this); } /*! @brief sets the binary subtype Sets the binary subtype of the value, also flags a binary JSON value as having a subtype, which has implications for serialization. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @sa see @ref subtype() -- return the binary subtype @sa see @ref clear_subtype() -- clears the binary subtype @sa see @ref has_subtype() -- returns whether or not the binary value has a subtype @since version 3.8.0 */ void set_subtype(subtype_type subtype_) noexcept { m_subtype = subtype_; m_has_subtype = true; } /*! @brief return the binary subtype Returns the numerical subtype of the value if it has a subtype. If it does not have a subtype, this function will return subtype_type(-1) as a sentinel value. @return the numerical subtype of the binary value @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @sa see @ref set_subtype() -- sets the binary subtype @sa see @ref clear_subtype() -- clears the binary subtype @sa see @ref has_subtype() -- returns whether or not the binary value has a subtype @since version 3.8.0; fixed return value to properly return subtype_type(-1) as documented in version 3.10.0 */ constexpr subtype_type subtype() const noexcept { return m_has_subtype ? m_subtype : subtype_type(-1); } /*! @brief return whether the value has a subtype @return whether the value has a subtype @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @sa see @ref subtype() -- return the binary subtype @sa see @ref set_subtype() -- sets the binary subtype @sa see @ref clear_subtype() -- clears the binary subtype @since version 3.8.0 */ constexpr bool has_subtype() const noexcept { return m_has_subtype; } /*! @brief clears the binary subtype Clears the binary subtype and flags the value as not having a subtype, which has implications for serialization; for instance MessagePack will prefer the bin family over the ext family. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @sa see @ref subtype() -- return the binary subtype @sa see @ref set_subtype() -- sets the binary subtype @sa see @ref has_subtype() -- returns whether or not the binary value has a subtype @since version 3.8.0 */ void clear_subtype() noexcept { m_subtype = 0; m_has_subtype = false; } private: subtype_type m_subtype = 0; bool m_has_subtype = false; }; } // namespace nlohmann // #include // #include // #include // #include #include // uint8_t #include // size_t #include // hash // #include // #include namespace nlohmann { namespace detail { // boost::hash_combine inline std::size_t combine(std::size_t seed, std::size_t h) noexcept { seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); return seed; } /*! @brief hash a JSON value The hash function tries to rely on std::hash where possible. Furthermore, the type of the JSON value is taken into account to have different hash values for null, 0, 0U, and false, etc. @tparam BasicJsonType basic_json specialization @param j JSON value to hash @return hash value of j */ template std::size_t hash(const BasicJsonType& j) { using string_t = typename BasicJsonType::string_t; using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; const auto type = static_cast(j.type()); switch (j.type()) { case BasicJsonType::value_t::null: case BasicJsonType::value_t::discarded: { return combine(type, 0); } case BasicJsonType::value_t::object: { auto seed = combine(type, j.size()); for (const auto& element : j.items()) { const auto h = std::hash {}(element.key()); seed = combine(seed, h); seed = combine(seed, hash(element.value())); } return seed; } case BasicJsonType::value_t::array: { auto seed = combine(type, j.size()); for (const auto& element : j) { seed = combine(seed, hash(element)); } return seed; } case BasicJsonType::value_t::string: { const auto h = std::hash {}(j.template get_ref()); return combine(type, h); } case BasicJsonType::value_t::boolean: { const auto h = std::hash {}(j.template get()); return combine(type, h); } case BasicJsonType::value_t::number_integer: { const auto h = std::hash {}(j.template get()); return combine(type, h); } case BasicJsonType::value_t::number_unsigned: { const auto h = std::hash {}(j.template get()); return combine(type, h); } case BasicJsonType::value_t::number_float: { const auto h = std::hash {}(j.template get()); return combine(type, h); } case BasicJsonType::value_t::binary: { auto seed = combine(type, j.get_binary().size()); const auto h = std::hash {}(j.get_binary().has_subtype()); seed = combine(seed, h); seed = combine(seed, static_cast(j.get_binary().subtype())); for (const auto byte : j.get_binary()) { seed = combine(seed, std::hash {}(byte)); } return seed; } default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE return 0; // LCOV_EXCL_LINE } } } // namespace detail } // namespace nlohmann // #include #include // generate_n #include // array #include // ldexp #include // size_t #include // uint8_t, uint16_t, uint32_t, uint64_t #include // snprintf #include // memcpy #include // back_inserter #include // numeric_limits #include // char_traits, string #include // make_pair, move #include // vector // #include // #include #include // array #include // size_t #include // strlen #include // begin, end, iterator_traits, random_access_iterator_tag, distance, next #include // shared_ptr, make_shared, addressof #include // accumulate #include // string, char_traits #include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer #include // pair, declval #ifndef JSON_NO_IO #include // FILE * #include // istream #endif // JSON_NO_IO // #include // #include namespace nlohmann { namespace detail { /// the supported input formats enum class input_format_t { json, cbor, msgpack, ubjson, bson }; //////////////////// // input adapters // //////////////////// #ifndef JSON_NO_IO /*! Input adapter for stdio file access. This adapter read only 1 byte and do not use any buffer. This adapter is a very low level adapter. */ class file_input_adapter { public: using char_type = char; JSON_HEDLEY_NON_NULL(2) explicit file_input_adapter(std::FILE* f) noexcept : m_file(f) {} // make class move-only file_input_adapter(const file_input_adapter&) = delete; file_input_adapter(file_input_adapter&&) noexcept = default; file_input_adapter& operator=(const file_input_adapter&) = delete; file_input_adapter& operator=(file_input_adapter&&) = delete; ~file_input_adapter() = default; std::char_traits::int_type get_character() noexcept { return std::fgetc(m_file); } private: /// the file pointer to read from std::FILE* m_file; }; /*! Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at beginning of input. Does not support changing the underlying std::streambuf in mid-input. Maintains underlying std::istream and std::streambuf to support subsequent use of standard std::istream operations to process any input characters following those used in parsing the JSON input. Clears the std::istream flags; any input errors (e.g., EOF) will be detected by the first subsequent call for input from the std::istream. */ class input_stream_adapter { public: using char_type = char; ~input_stream_adapter() { // clear stream flags; we use underlying streambuf I/O, do not // maintain ifstream flags, except eof if (is != nullptr) { is->clear(is->rdstate() & std::ios::eofbit); } } explicit input_stream_adapter(std::istream& i) : is(&i), sb(i.rdbuf()) {} // delete because of pointer members input_stream_adapter(const input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&&) = delete; input_stream_adapter(input_stream_adapter&& rhs) noexcept : is(rhs.is), sb(rhs.sb) { rhs.is = nullptr; rhs.sb = nullptr; } // std::istream/std::streambuf use std::char_traits::to_int_type, to // ensure that std::char_traits::eof() and the character 0xFF do not // end up as the same value, eg. 0xFFFFFFFF. std::char_traits::int_type get_character() { auto res = sb->sbumpc(); // set eof manually, as we don't use the istream interface. if (JSON_HEDLEY_UNLIKELY(res == std::char_traits::eof())) { is->clear(is->rdstate() | std::ios::eofbit); } return res; } private: /// the associated input stream std::istream* is = nullptr; std::streambuf* sb = nullptr; }; #endif // JSON_NO_IO // General-purpose iterator-based adapter. It might not be as fast as // theoretically possible for some containers, but it is extremely versatile. template class iterator_input_adapter { public: using char_type = typename std::iterator_traits::value_type; iterator_input_adapter(IteratorType first, IteratorType last) : current(std::move(first)), end(std::move(last)) {} typename std::char_traits::int_type get_character() { if (JSON_HEDLEY_LIKELY(current != end)) { auto result = std::char_traits::to_int_type(*current); std::advance(current, 1); return result; } return std::char_traits::eof(); } private: IteratorType current; IteratorType end; template friend struct wide_string_input_helper; bool empty() const { return current == end; } }; template struct wide_string_input_helper; template struct wide_string_input_helper { // UTF-32 static void fill_buffer(BaseInputAdapter& input, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; if (JSON_HEDLEY_UNLIKELY(input.empty())) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; } else { // get the current character const auto wc = input.get_character(); // UTF-32 to UTF-8 encoding if (wc < 0x80) { utf8_bytes[0] = static_cast::int_type>(wc); utf8_bytes_filled = 1; } else if (wc <= 0x7FF) { utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); utf8_bytes_filled = 2; } else if (wc <= 0xFFFF) { utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); utf8_bytes_filled = 3; } else if (wc <= 0x10FFFF) { utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); utf8_bytes_filled = 4; } else { // unknown character utf8_bytes[0] = static_cast::int_type>(wc); utf8_bytes_filled = 1; } } } }; template struct wide_string_input_helper { // UTF-16 static void fill_buffer(BaseInputAdapter& input, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; if (JSON_HEDLEY_UNLIKELY(input.empty())) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; } else { // get the current character const auto wc = input.get_character(); // UTF-16 to UTF-8 encoding if (wc < 0x80) { utf8_bytes[0] = static_cast::int_type>(wc); utf8_bytes_filled = 1; } else if (wc <= 0x7FF) { utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); utf8_bytes_filled = 2; } else if (0xD800 > wc || wc >= 0xE000) { utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); utf8_bytes_filled = 3; } else { if (JSON_HEDLEY_UNLIKELY(!input.empty())) { const auto wc2 = static_cast(input.get_character()); const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); utf8_bytes_filled = 4; } else { utf8_bytes[0] = static_cast::int_type>(wc); utf8_bytes_filled = 1; } } } } }; // Wraps another input apdater to convert wide character types into individual bytes. template class wide_string_input_adapter { public: using char_type = char; wide_string_input_adapter(BaseInputAdapter base) : base_adapter(base) {} typename std::char_traits::int_type get_character() noexcept { // check if buffer needs to be filled if (utf8_bytes_index == utf8_bytes_filled) { fill_buffer(); JSON_ASSERT(utf8_bytes_filled > 0); JSON_ASSERT(utf8_bytes_index == 0); } // use buffer JSON_ASSERT(utf8_bytes_filled > 0); JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); return utf8_bytes[utf8_bytes_index++]; } private: BaseInputAdapter base_adapter; template void fill_buffer() { wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); } /// a buffer for UTF-8 bytes std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; /// index to the utf8_codes array for the next valid byte std::size_t utf8_bytes_index = 0; /// number of valid bytes in the utf8_codes array std::size_t utf8_bytes_filled = 0; }; template struct iterator_input_adapter_factory { using iterator_type = IteratorType; using char_type = typename std::iterator_traits::value_type; using adapter_type = iterator_input_adapter; static adapter_type create(IteratorType first, IteratorType last) { return adapter_type(std::move(first), std::move(last)); } }; template struct is_iterator_of_multibyte { using value_type = typename std::iterator_traits::value_type; enum { value = sizeof(value_type) > 1 }; }; template struct iterator_input_adapter_factory::value>> { using iterator_type = IteratorType; using char_type = typename std::iterator_traits::value_type; using base_adapter_type = iterator_input_adapter; using adapter_type = wide_string_input_adapter; static adapter_type create(IteratorType first, IteratorType last) { return adapter_type(base_adapter_type(std::move(first), std::move(last))); } }; // General purpose iterator-based input template typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) { using factory_type = iterator_input_adapter_factory; return factory_type::create(first, last); } // Convenience shorthand from container to iterator // Enables ADL on begin(container) and end(container) // Encloses the using declarations in namespace for not to leak them to outside scope namespace container_input_adapter_factory_impl { using std::begin; using std::end; template struct container_input_adapter_factory {}; template struct container_input_adapter_factory< ContainerType, void_t()), end(std::declval()))>> { using adapter_type = decltype(input_adapter(begin(std::declval()), end(std::declval()))); static adapter_type create(const ContainerType& container) { return input_adapter(begin(container), end(container)); } }; } // namespace container_input_adapter_factory_impl template typename container_input_adapter_factory_impl::container_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) { return container_input_adapter_factory_impl::container_input_adapter_factory::create(container); } #ifndef JSON_NO_IO // Special cases with fast paths inline file_input_adapter input_adapter(std::FILE* file) { return file_input_adapter(file); } inline input_stream_adapter input_adapter(std::istream& stream) { return input_stream_adapter(stream); } inline input_stream_adapter input_adapter(std::istream&& stream) { return input_stream_adapter(stream); } #endif // JSON_NO_IO using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); // Null-delimited strings, and the like. template < typename CharT, typename std::enable_if < std::is_pointer::value&& !std::is_array::value&& std::is_integral::type>::value&& sizeof(typename std::remove_pointer::type) == 1, int >::type = 0 > contiguous_bytes_input_adapter input_adapter(CharT b) { auto length = std::strlen(reinterpret_cast(b)); const auto* ptr = reinterpret_cast(b); return input_adapter(ptr, ptr + length); } template auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) { return input_adapter(array, array + N); } // This class only handles inputs of input_buffer_adapter type. // It's required so that expressions like {ptr, len} can be implicitely casted // to the correct adapter. class span_input_adapter { public: template < typename CharT, typename std::enable_if < std::is_pointer::value&& std::is_integral::type>::value&& sizeof(typename std::remove_pointer::type) == 1, int >::type = 0 > span_input_adapter(CharT b, std::size_t l) : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} template::iterator_category, std::random_access_iterator_tag>::value, int>::type = 0> span_input_adapter(IteratorType first, IteratorType last) : ia(input_adapter(first, last)) {} contiguous_bytes_input_adapter&& get() { return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) } private: contiguous_bytes_input_adapter ia; }; } // namespace detail } // namespace nlohmann // #include #include #include // string #include // move #include // vector // #include // #include namespace nlohmann { /*! @brief SAX interface This class describes the SAX interface used by @ref nlohmann::json::sax_parse. Each function is called in different situations while the input is parsed. The boolean return value informs the parser whether to continue processing the input. */ template struct json_sax { using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; /*! @brief a null value was read @return whether parsing should proceed */ virtual bool null() = 0; /*! @brief a boolean value was read @param[in] val boolean value @return whether parsing should proceed */ virtual bool boolean(bool val) = 0; /*! @brief an integer number was read @param[in] val integer value @return whether parsing should proceed */ virtual bool number_integer(number_integer_t val) = 0; /*! @brief an unsigned integer number was read @param[in] val unsigned integer value @return whether parsing should proceed */ virtual bool number_unsigned(number_unsigned_t val) = 0; /*! @brief an floating-point number was read @param[in] val floating-point value @param[in] s raw token value @return whether parsing should proceed */ virtual bool number_float(number_float_t val, const string_t& s) = 0; /*! @brief a string was read @param[in] val string value @return whether parsing should proceed @note It is safe to move the passed string. */ virtual bool string(string_t& val) = 0; /*! @brief a binary string was read @param[in] val binary value @return whether parsing should proceed @note It is safe to move the passed binary. */ virtual bool binary(binary_t& val) = 0; /*! @brief the beginning of an object was read @param[in] elements number of object elements or -1 if unknown @return whether parsing should proceed @note binary formats may report the number of elements */ virtual bool start_object(std::size_t elements) = 0; /*! @brief an object key was read @param[in] val object key @return whether parsing should proceed @note It is safe to move the passed string. */ virtual bool key(string_t& val) = 0; /*! @brief the end of an object was read @return whether parsing should proceed */ virtual bool end_object() = 0; /*! @brief the beginning of an array was read @param[in] elements number of array elements or -1 if unknown @return whether parsing should proceed @note binary formats may report the number of elements */ virtual bool start_array(std::size_t elements) = 0; /*! @brief the end of an array was read @return whether parsing should proceed */ virtual bool end_array() = 0; /*! @brief a parse error occurred @param[in] position the position in the input where the error occurs @param[in] last_token the last read token @param[in] ex an exception object describing the error @return whether parsing should proceed (must return false) */ virtual bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex) = 0; json_sax() = default; json_sax(const json_sax&) = default; json_sax(json_sax&&) noexcept = default; json_sax& operator=(const json_sax&) = default; json_sax& operator=(json_sax&&) noexcept = default; virtual ~json_sax() = default; }; namespace detail { /*! @brief SAX implementation to create a JSON value from SAX events This class implements the @ref json_sax interface and processes the SAX events to create a JSON value which makes it basically a DOM parser. The structure or hierarchy of the JSON value is managed by the stack `ref_stack` which contains a pointer to the respective array or object for each recursion depth. After successful parsing, the value that is passed by reference to the constructor contains the parsed value. @tparam BasicJsonType the JSON type */ template class json_sax_dom_parser { public: using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; /*! @param[in,out] r reference to a JSON value that is manipulated while parsing @param[in] allow_exceptions_ whether parse errors yield exceptions */ explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) : root(r), allow_exceptions(allow_exceptions_) {} // make class move-only json_sax_dom_parser(const json_sax_dom_parser&) = delete; json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) ~json_sax_dom_parser() = default; bool null() { handle_value(nullptr); return true; } bool boolean(bool val) { handle_value(val); return true; } bool number_integer(number_integer_t val) { handle_value(val); return true; } bool number_unsigned(number_unsigned_t val) { handle_value(val); return true; } bool number_float(number_float_t val, const string_t& /*unused*/) { handle_value(val); return true; } bool string(string_t& val) { handle_value(val); return true; } bool binary(binary_t& val) { handle_value(std::move(val)); return true; } bool start_object(std::size_t len) { ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); } return true; } bool key(string_t& val) { // add null at given key and store the reference for later object_element = &(ref_stack.back()->m_value.object->operator[](val)); return true; } bool end_object() { ref_stack.back()->set_parents(); ref_stack.pop_back(); return true; } bool start_array(std::size_t len) { ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); } return true; } bool end_array() { ref_stack.back()->set_parents(); ref_stack.pop_back(); return true; } template bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const Exception& ex) { errored = true; static_cast(ex); if (allow_exceptions) { JSON_THROW(ex); } return false; } constexpr bool is_errored() const { return errored; } private: /*! @invariant If the ref stack is empty, then the passed value will be the new root. @invariant If the ref stack contains a value, then it is an array or an object to which we can add elements */ template JSON_HEDLEY_RETURNS_NON_NULL BasicJsonType* handle_value(Value&& v) { if (ref_stack.empty()) { root = BasicJsonType(std::forward(v)); return &root; } JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); if (ref_stack.back()->is_array()) { ref_stack.back()->m_value.array->emplace_back(std::forward(v)); return &(ref_stack.back()->m_value.array->back()); } JSON_ASSERT(ref_stack.back()->is_object()); JSON_ASSERT(object_element); *object_element = BasicJsonType(std::forward(v)); return object_element; } /// the parsed JSON value BasicJsonType& root; /// stack to model hierarchy of values std::vector ref_stack {}; /// helper to hold the reference for the next object element BasicJsonType* object_element = nullptr; /// whether a syntax error occurred bool errored = false; /// whether to throw exceptions in case of errors const bool allow_exceptions = true; }; template class json_sax_dom_callback_parser { public: using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; using parser_callback_t = typename BasicJsonType::parser_callback_t; using parse_event_t = typename BasicJsonType::parse_event_t; json_sax_dom_callback_parser(BasicJsonType& r, const parser_callback_t cb, const bool allow_exceptions_ = true) : root(r), callback(cb), allow_exceptions(allow_exceptions_) { keep_stack.push_back(true); } // make class move-only json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) ~json_sax_dom_callback_parser() = default; bool null() { handle_value(nullptr); return true; } bool boolean(bool val) { handle_value(val); return true; } bool number_integer(number_integer_t val) { handle_value(val); return true; } bool number_unsigned(number_unsigned_t val) { handle_value(val); return true; } bool number_float(number_float_t val, const string_t& /*unused*/) { handle_value(val); return true; } bool string(string_t& val) { handle_value(val); return true; } bool binary(binary_t& val) { handle_value(std::move(val)); return true; } bool start_object(std::size_t len) { // check callback for object start const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); keep_stack.push_back(keep); auto val = handle_value(BasicJsonType::value_t::object, true); ref_stack.push_back(val.second); // check object limit if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); } return true; } bool key(string_t& val) { BasicJsonType k = BasicJsonType(val); // check callback for key const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); key_keep_stack.push_back(keep); // add discarded value at given key and store the reference for later if (keep && ref_stack.back()) { object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); } return true; } bool end_object() { if (ref_stack.back()) { if (!callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) { // discard object *ref_stack.back() = discarded; } else { ref_stack.back()->set_parents(); } } JSON_ASSERT(!ref_stack.empty()); JSON_ASSERT(!keep_stack.empty()); ref_stack.pop_back(); keep_stack.pop_back(); if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) { // remove discarded value for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) { if (it->is_discarded()) { ref_stack.back()->erase(it); break; } } } return true; } bool start_array(std::size_t len) { const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); keep_stack.push_back(keep); auto val = handle_value(BasicJsonType::value_t::array, true); ref_stack.push_back(val.second); // check array limit if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); } return true; } bool end_array() { bool keep = true; if (ref_stack.back()) { keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); if (keep) { ref_stack.back()->set_parents(); } else { // discard array *ref_stack.back() = discarded; } } JSON_ASSERT(!ref_stack.empty()); JSON_ASSERT(!keep_stack.empty()); ref_stack.pop_back(); keep_stack.pop_back(); // remove discarded value if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) { ref_stack.back()->m_value.array->pop_back(); } return true; } template bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const Exception& ex) { errored = true; static_cast(ex); if (allow_exceptions) { JSON_THROW(ex); } return false; } constexpr bool is_errored() const { return errored; } private: /*! @param[in] v value to add to the JSON value we build during parsing @param[in] skip_callback whether we should skip calling the callback function; this is required after start_array() and start_object() SAX events, because otherwise we would call the callback function with an empty array or object, respectively. @invariant If the ref stack is empty, then the passed value will be the new root. @invariant If the ref stack contains a value, then it is an array or an object to which we can add elements @return pair of boolean (whether value should be kept) and pointer (to the passed value in the ref_stack hierarchy; nullptr if not kept) */ template std::pair handle_value(Value&& v, const bool skip_callback = false) { JSON_ASSERT(!keep_stack.empty()); // do not handle this value if we know it would be added to a discarded // container if (!keep_stack.back()) { return {false, nullptr}; } // create value auto value = BasicJsonType(std::forward(v)); // check callback const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); // do not handle this value if we just learnt it shall be discarded if (!keep) { return {false, nullptr}; } if (ref_stack.empty()) { root = std::move(value); return {true, &root}; } // skip this value if we already decided to skip the parent // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) if (!ref_stack.back()) { return {false, nullptr}; } // we now only expect arrays and objects JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); // array if (ref_stack.back()->is_array()) { ref_stack.back()->m_value.array->emplace_back(std::move(value)); return {true, &(ref_stack.back()->m_value.array->back())}; } // object JSON_ASSERT(ref_stack.back()->is_object()); // check if we should store an element for the current key JSON_ASSERT(!key_keep_stack.empty()); const bool store_element = key_keep_stack.back(); key_keep_stack.pop_back(); if (!store_element) { return {false, nullptr}; } JSON_ASSERT(object_element); *object_element = std::move(value); return {true, object_element}; } /// the parsed JSON value BasicJsonType& root; /// stack to model hierarchy of values std::vector ref_stack {}; /// stack to manage which values to keep std::vector keep_stack {}; /// stack to manage which object keys to keep std::vector key_keep_stack {}; /// helper to hold the reference for the next object element BasicJsonType* object_element = nullptr; /// whether a syntax error occurred bool errored = false; /// callback function const parser_callback_t callback = nullptr; /// whether to throw exceptions in case of errors const bool allow_exceptions = true; /// a discarded value for the callback BasicJsonType discarded = BasicJsonType::value_t::discarded; }; template class json_sax_acceptor { public: using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; bool null() { return true; } bool boolean(bool /*unused*/) { return true; } bool number_integer(number_integer_t /*unused*/) { return true; } bool number_unsigned(number_unsigned_t /*unused*/) { return true; } bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) { return true; } bool string(string_t& /*unused*/) { return true; } bool binary(binary_t& /*unused*/) { return true; } bool start_object(std::size_t /*unused*/ = std::size_t(-1)) { return true; } bool key(string_t& /*unused*/) { return true; } bool end_object() { return true; } bool start_array(std::size_t /*unused*/ = std::size_t(-1)) { return true; } bool end_array() { return true; } bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) { return false; } }; } // namespace detail } // namespace nlohmann // #include #include // array #include // localeconv #include // size_t #include // snprintf #include // strtof, strtod, strtold, strtoll, strtoull #include // initializer_list #include // char_traits, string #include // move #include // vector // #include // #include // #include namespace nlohmann { namespace detail { /////////// // lexer // /////////// template class lexer_base { public: /// token types for the parser enum class token_type { uninitialized, ///< indicating the scanner is uninitialized literal_true, ///< the `true` literal literal_false, ///< the `false` literal literal_null, ///< the `null` literal value_string, ///< a string -- use get_string() for actual value value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value value_integer, ///< a signed integer -- use get_number_integer() for actual value value_float, ///< an floating point number -- use get_number_float() for actual value begin_array, ///< the character for array begin `[` begin_object, ///< the character for object begin `{` end_array, ///< the character for array end `]` end_object, ///< the character for object end `}` name_separator, ///< the name separator `:` value_separator, ///< the value separator `,` parse_error, ///< indicating a parse error end_of_input, ///< indicating the end of the input buffer literal_or_value ///< a literal or the begin of a value (only for diagnostics) }; /// return name of values of type token_type (only used for errors) JSON_HEDLEY_RETURNS_NON_NULL JSON_HEDLEY_CONST static const char* token_type_name(const token_type t) noexcept { switch (t) { case token_type::uninitialized: return ""; case token_type::literal_true: return "true literal"; case token_type::literal_false: return "false literal"; case token_type::literal_null: return "null literal"; case token_type::value_string: return "string literal"; case token_type::value_unsigned: case token_type::value_integer: case token_type::value_float: return "number literal"; case token_type::begin_array: return "'['"; case token_type::begin_object: return "'{'"; case token_type::end_array: return "']'"; case token_type::end_object: return "'}'"; case token_type::name_separator: return "':'"; case token_type::value_separator: return "','"; case token_type::parse_error: return ""; case token_type::end_of_input: return "end of input"; case token_type::literal_or_value: return "'[', '{', or a literal"; // LCOV_EXCL_START default: // catch non-enum values return "unknown token"; // LCOV_EXCL_STOP } } }; /*! @brief lexical analysis This class organizes the lexical analysis during JSON deserialization. */ template class lexer : public lexer_base { using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using char_type = typename InputAdapterType::char_type; using char_int_type = typename std::char_traits::int_type; public: using token_type = typename lexer_base::token_type; explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept : ia(std::move(adapter)) , ignore_comments(ignore_comments_) , decimal_point_char(static_cast(get_decimal_point())) {} // delete because of pointer members lexer(const lexer&) = delete; lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) lexer& operator=(lexer&) = delete; lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) ~lexer() = default; private: ///////////////////// // locales ///////////////////// /// return the locale-dependent decimal point JSON_HEDLEY_PURE static char get_decimal_point() noexcept { const auto* loc = localeconv(); JSON_ASSERT(loc != nullptr); return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); } ///////////////////// // scan functions ///////////////////// /*! @brief get codepoint from 4 hex characters following `\u` For input "\u c1 c2 c3 c4" the codepoint is: (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The conversion is done by subtracting the offset (0x30, 0x37, and 0x57) between the ASCII value of the character and the desired integer value. @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or non-hex character) */ int get_codepoint() { // this function only makes sense after reading `\u` JSON_ASSERT(current == 'u'); int codepoint = 0; const auto factors = { 12u, 8u, 4u, 0u }; for (const auto factor : factors) { get(); if (current >= '0' && current <= '9') { codepoint += static_cast((static_cast(current) - 0x30u) << factor); } else if (current >= 'A' && current <= 'F') { codepoint += static_cast((static_cast(current) - 0x37u) << factor); } else if (current >= 'a' && current <= 'f') { codepoint += static_cast((static_cast(current) - 0x57u) << factor); } else { return -1; } } JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); return codepoint; } /*! @brief check if the next byte(s) are inside a given range Adds the current byte and, for each passed range, reads a new byte and checks if it is inside the range. If a violation was detected, set up an error message and return false. Otherwise, return true. @param[in] ranges list of integers; interpreted as list of pairs of inclusive lower and upper bound, respectively @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, 1, 2, or 3 pairs. This precondition is enforced by an assertion. @return true if and only if no range violation was detected */ bool next_byte_in_range(std::initializer_list ranges) { JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); add(current); for (auto range = ranges.begin(); range != ranges.end(); ++range) { get(); if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) { add(current); } else { error_message = "invalid string: ill-formed UTF-8 byte"; return false; } } return true; } /*! @brief scan a string literal This function scans a string according to Sect. 7 of RFC 8259. While scanning, bytes are escaped and copied into buffer token_buffer. Then the function returns successfully, token_buffer is *not* null-terminated (as it may contain \0 bytes), and token_buffer.size() is the number of bytes in the string. @return token_type::value_string if string could be successfully scanned, token_type::parse_error otherwise @note In case of errors, variable error_message contains a textual description. */ token_type scan_string() { // reset token_buffer (ignore opening quote) reset(); // we entered the function by reading an open quote JSON_ASSERT(current == '\"'); while (true) { // get next character switch (get()) { // end of file while parsing string case std::char_traits::eof(): { error_message = "invalid string: missing closing quote"; return token_type::parse_error; } // closing quote case '\"': { return token_type::value_string; } // escapes case '\\': { switch (get()) { // quotation mark case '\"': add('\"'); break; // reverse solidus case '\\': add('\\'); break; // solidus case '/': add('/'); break; // backspace case 'b': add('\b'); break; // form feed case 'f': add('\f'); break; // line feed case 'n': add('\n'); break; // carriage return case 'r': add('\r'); break; // tab case 't': add('\t'); break; // unicode escapes case 'u': { const int codepoint1 = get_codepoint(); int codepoint = codepoint1; // start with codepoint1 if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) { error_message = "invalid string: '\\u' must be followed by 4 hex digits"; return token_type::parse_error; } // check if code point is a high surrogate if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) { // expect next \uxxxx entry if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) { const int codepoint2 = get_codepoint(); if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) { error_message = "invalid string: '\\u' must be followed by 4 hex digits"; return token_type::parse_error; } // check if codepoint2 is a low surrogate if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) { // overwrite codepoint codepoint = static_cast( // high surrogate occupies the most significant 22 bits (static_cast(codepoint1) << 10u) // low surrogate occupies the least significant 15 bits + static_cast(codepoint2) // there is still the 0xD800, 0xDC00 and 0x10000 noise // in the result so we have to subtract with: // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - 0x35FDC00u); } else { error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; return token_type::parse_error; } } else { error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; return token_type::parse_error; } } else { if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) { error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; return token_type::parse_error; } } // result of the above calculation yields a proper codepoint JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); // translate codepoint into bytes if (codepoint < 0x80) { // 1-byte characters: 0xxxxxxx (ASCII) add(static_cast(codepoint)); } else if (codepoint <= 0x7FF) { // 2-byte characters: 110xxxxx 10xxxxxx add(static_cast(0xC0u | (static_cast(codepoint) >> 6u))); add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); } else if (codepoint <= 0xFFFF) { // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx add(static_cast(0xE0u | (static_cast(codepoint) >> 12u))); add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); } else { // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx add(static_cast(0xF0u | (static_cast(codepoint) >> 18u))); add(static_cast(0x80u | ((static_cast(codepoint) >> 12u) & 0x3Fu))); add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); } break; } // other characters after escape default: error_message = "invalid string: forbidden character after backslash"; return token_type::parse_error; } break; } // invalid control characters case 0x00: { error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; return token_type::parse_error; } case 0x01: { error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; return token_type::parse_error; } case 0x02: { error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; return token_type::parse_error; } case 0x03: { error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; return token_type::parse_error; } case 0x04: { error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; return token_type::parse_error; } case 0x05: { error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; return token_type::parse_error; } case 0x06: { error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; return token_type::parse_error; } case 0x07: { error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; return token_type::parse_error; } case 0x08: { error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; return token_type::parse_error; } case 0x09: { error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; return token_type::parse_error; } case 0x0A: { error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; return token_type::parse_error; } case 0x0B: { error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; return token_type::parse_error; } case 0x0C: { error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; return token_type::parse_error; } case 0x0D: { error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; return token_type::parse_error; } case 0x0E: { error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; return token_type::parse_error; } case 0x0F: { error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; return token_type::parse_error; } case 0x10: { error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; return token_type::parse_error; } case 0x11: { error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; return token_type::parse_error; } case 0x12: { error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; return token_type::parse_error; } case 0x13: { error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; return token_type::parse_error; } case 0x14: { error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; return token_type::parse_error; } case 0x15: { error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; return token_type::parse_error; } case 0x16: { error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; return token_type::parse_error; } case 0x17: { error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; return token_type::parse_error; } case 0x18: { error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; return token_type::parse_error; } case 0x19: { error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; return token_type::parse_error; } case 0x1A: { error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; return token_type::parse_error; } case 0x1B: { error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; return token_type::parse_error; } case 0x1C: { error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; return token_type::parse_error; } case 0x1D: { error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; return token_type::parse_error; } case 0x1E: { error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; return token_type::parse_error; } case 0x1F: { error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; return token_type::parse_error; } // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) case 0x20: case 0x21: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5D: case 0x5E: case 0x5F: case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: { add(current); break; } // U+0080..U+07FF: bytes C2..DF 80..BF case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: { if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) { return token_type::parse_error; } break; } // U+0800..U+0FFF: bytes E0 A0..BF 80..BF case 0xE0: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xEE: case 0xEF: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+D000..U+D7FF: bytes ED 80..9F 80..BF case 0xED: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF case 0xF0: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF case 0xF1: case 0xF2: case 0xF3: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF case 0xF4: { if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } break; } // remaining bytes (80..C1 and F5..FF) are ill-formed default: { error_message = "invalid string: ill-formed UTF-8 byte"; return token_type::parse_error; } } } } /*! * @brief scan a comment * @return whether comment could be scanned successfully */ bool scan_comment() { switch (get()) { // single-line comments skip input until a newline or EOF is read case '/': { while (true) { switch (get()) { case '\n': case '\r': case std::char_traits::eof(): case '\0': return true; default: break; } } } // multi-line comments skip input until */ is read case '*': { while (true) { switch (get()) { case std::char_traits::eof(): case '\0': { error_message = "invalid comment; missing closing '*/'"; return false; } case '*': { switch (get()) { case '/': return true; default: { unget(); continue; } } } default: continue; } } } // unexpected character after reading '/' default: { error_message = "invalid comment; expecting '/' or '*' after '/'"; return false; } } } JSON_HEDLEY_NON_NULL(2) static void strtof(float& f, const char* str, char** endptr) noexcept { f = std::strtof(str, endptr); } JSON_HEDLEY_NON_NULL(2) static void strtof(double& f, const char* str, char** endptr) noexcept { f = std::strtod(str, endptr); } JSON_HEDLEY_NON_NULL(2) static void strtof(long double& f, const char* str, char** endptr) noexcept { f = std::strtold(str, endptr); } /*! @brief scan a number literal This function scans a string according to Sect. 6 of RFC 8259. The function is realized with a deterministic finite state machine derived from the grammar described in RFC 8259. Starting in state "init", the input is read and used to determined the next state. Only state "done" accepts the number. State "error" is a trap state to model errors. In the table below, "anything" means any character but the ones listed before. state | 0 | 1-9 | e E | + | - | . | anything ---------|----------|----------|----------|---------|---------|----------|----------- init | zero | any1 | [error] | [error] | minus | [error] | [error] minus | zero | any1 | [error] | [error] | [error] | [error] | [error] zero | done | done | exponent | done | done | decimal1 | done any1 | any1 | any1 | exponent | done | done | decimal1 | done decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] decimal2 | decimal2 | decimal2 | exponent | done | done | done | done exponent | any2 | any2 | [error] | sign | sign | [error] | [error] sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] any2 | any2 | any2 | done | done | done | done | done The state machine is realized with one label per state (prefixed with "scan_number_") and `goto` statements between them. The state machine contains cycles, but any cycle can be left when EOF is read. Therefore, the function is guaranteed to terminate. During scanning, the read bytes are stored in token_buffer. This string is then converted to a signed integer, an unsigned integer, or a floating-point number. @return token_type::value_unsigned, token_type::value_integer, or token_type::value_float if number could be successfully scanned, token_type::parse_error otherwise @note The scanner is independent of the current locale. Internally, the locale's decimal point is used instead of `.` to work with the locale-dependent converters. */ token_type scan_number() // lgtm [cpp/use-of-goto] { // reset token_buffer to store the number's bytes reset(); // the type of the parsed number; initially set to unsigned; will be // changed if minus sign, decimal point or exponent is read token_type number_type = token_type::value_unsigned; // state (init): we just found out we need to scan a number switch (current) { case '-': { add(current); goto scan_number_minus; } case '0': { add(current); goto scan_number_zero; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any1; } // all other characters are rejected outside scan_number() default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } scan_number_minus: // state: we just parsed a leading minus sign number_type = token_type::value_integer; switch (get()) { case '0': { add(current); goto scan_number_zero; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any1; } default: { error_message = "invalid number; expected digit after '-'"; return token_type::parse_error; } } scan_number_zero: // state: we just parse a zero (maybe with a leading minus sign) switch (get()) { case '.': { add(decimal_point_char); goto scan_number_decimal1; } case 'e': case 'E': { add(current); goto scan_number_exponent; } default: goto scan_number_done; } scan_number_any1: // state: we just parsed a number 0-9 (maybe with a leading minus sign) switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any1; } case '.': { add(decimal_point_char); goto scan_number_decimal1; } case 'e': case 'E': { add(current); goto scan_number_exponent; } default: goto scan_number_done; } scan_number_decimal1: // state: we just parsed a decimal point number_type = token_type::value_float; switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_decimal2; } default: { error_message = "invalid number; expected digit after '.'"; return token_type::parse_error; } } scan_number_decimal2: // we just parsed at least one number after a decimal point switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_decimal2; } case 'e': case 'E': { add(current); goto scan_number_exponent; } default: goto scan_number_done; } scan_number_exponent: // we just parsed an exponent number_type = token_type::value_float; switch (get()) { case '+': case '-': { add(current); goto scan_number_sign; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any2; } default: { error_message = "invalid number; expected '+', '-', or digit after exponent"; return token_type::parse_error; } } scan_number_sign: // we just parsed an exponent sign switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any2; } default: { error_message = "invalid number; expected digit after exponent sign"; return token_type::parse_error; } } scan_number_any2: // we just parsed a number after the exponent or exponent sign switch (get()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { add(current); goto scan_number_any2; } default: goto scan_number_done; } scan_number_done: // unget the character after the number (we only read it to know that // we are done scanning a number) unget(); char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) errno = 0; // try to parse integers first and fall back to floats if (number_type == token_type::value_unsigned) { const auto x = std::strtoull(token_buffer.data(), &endptr, 10); // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { value_unsigned = static_cast(x); if (value_unsigned == x) { return token_type::value_unsigned; } } } else if (number_type == token_type::value_integer) { const auto x = std::strtoll(token_buffer.data(), &endptr, 10); // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { value_integer = static_cast(x); if (value_integer == x) { return token_type::value_integer; } } } // this code is reached if we parse a floating-point number or if an // integer conversion above failed strtof(value_float, token_buffer.data(), &endptr); // we checked the number format before JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); return token_type::value_float; } /*! @param[in] literal_text the literal text to expect @param[in] length the length of the passed literal text @param[in] return_type the token type to return on success */ JSON_HEDLEY_NON_NULL(2) token_type scan_literal(const char_type* literal_text, const std::size_t length, token_type return_type) { JSON_ASSERT(std::char_traits::to_char_type(current) == literal_text[0]); for (std::size_t i = 1; i < length; ++i) { if (JSON_HEDLEY_UNLIKELY(std::char_traits::to_char_type(get()) != literal_text[i])) { error_message = "invalid literal"; return token_type::parse_error; } } return return_type; } ///////////////////// // input management ///////////////////// /// reset token_buffer; current character is beginning of token void reset() noexcept { token_buffer.clear(); token_string.clear(); token_string.push_back(std::char_traits::to_char_type(current)); } /* @brief get next character from the input This function provides the interface to the used input adapter. It does not throw in case the input reached EOF, but returns a `std::char_traits::eof()` in that case. Stores the scanned characters for use in error messages. @return character read from the input */ char_int_type get() { ++position.chars_read_total; ++position.chars_read_current_line; if (next_unget) { // just reset the next_unget variable and work with current next_unget = false; } else { current = ia.get_character(); } if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) { token_string.push_back(std::char_traits::to_char_type(current)); } if (current == '\n') { ++position.lines_read; position.chars_read_current_line = 0; } return current; } /*! @brief unget current character (read it again on next get) We implement unget by setting variable next_unget to true. The input is not changed - we just simulate ungetting by modifying chars_read_total, chars_read_current_line, and token_string. The next call to get() will behave as if the unget character is read again. */ void unget() { next_unget = true; --position.chars_read_total; // in case we "unget" a newline, we have to also decrement the lines_read if (position.chars_read_current_line == 0) { if (position.lines_read > 0) { --position.lines_read; } } else { --position.chars_read_current_line; } if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) { JSON_ASSERT(!token_string.empty()); token_string.pop_back(); } } /// add a character to token_buffer void add(char_int_type c) { token_buffer.push_back(static_cast(c)); } public: ///////////////////// // value getters ///////////////////// /// return integer value constexpr number_integer_t get_number_integer() const noexcept { return value_integer; } /// return unsigned integer value constexpr number_unsigned_t get_number_unsigned() const noexcept { return value_unsigned; } /// return floating-point value constexpr number_float_t get_number_float() const noexcept { return value_float; } /// return current string value (implicitly resets the token; useful only once) string_t& get_string() { return token_buffer; } ///////////////////// // diagnostics ///////////////////// /// return position of last read token constexpr position_t get_position() const noexcept { return position; } /// return the last read token (for errors only). Will never contain EOF /// (an arbitrary value that is not a valid char value, often -1), because /// 255 may legitimately occur. May contain NUL, which should be escaped. std::string get_token_string() const { // escape control characters std::string result; for (const auto c : token_string) { if (static_cast(c) <= '\x1F') { // escape control characters std::array cs{{}}; (std::snprintf)(cs.data(), cs.size(), "", static_cast(c)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) result += cs.data(); } else { // add character as is result.push_back(static_cast(c)); } } return result; } /// return syntax error message JSON_HEDLEY_RETURNS_NON_NULL constexpr const char* get_error_message() const noexcept { return error_message; } ///////////////////// // actual scanner ///////////////////// /*! @brief skip the UTF-8 byte order mark @return true iff there is no BOM or the correct BOM has been skipped */ bool skip_bom() { if (get() == 0xEF) { // check if we completely parse the BOM return get() == 0xBB && get() == 0xBF; } // the first character is not the beginning of the BOM; unget it to // process is later unget(); return true; } void skip_whitespace() { do { get(); } while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); } token_type scan() { // initially, skip the BOM if (position.chars_read_total == 0 && !skip_bom()) { error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; return token_type::parse_error; } // read next character and ignore whitespace skip_whitespace(); // ignore comments while (ignore_comments && current == '/') { if (!scan_comment()) { return token_type::parse_error; } // skip following whitespace skip_whitespace(); } switch (current) { // structural characters case '[': return token_type::begin_array; case ']': return token_type::end_array; case '{': return token_type::begin_object; case '}': return token_type::end_object; case ':': return token_type::name_separator; case ',': return token_type::value_separator; // literals case 't': { std::array true_literal = {{char_type('t'), char_type('r'), char_type('u'), char_type('e')}}; return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); } case 'f': { std::array false_literal = {{char_type('f'), char_type('a'), char_type('l'), char_type('s'), char_type('e')}}; return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); } case 'n': { std::array null_literal = {{char_type('n'), char_type('u'), char_type('l'), char_type('l')}}; return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); } // string case '\"': return scan_string(); // number case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return scan_number(); // end of input (the null byte is needed when parsing from // string literals) case '\0': case std::char_traits::eof(): return token_type::end_of_input; // error default: error_message = "invalid literal"; return token_type::parse_error; } } private: /// input adapter InputAdapterType ia; /// whether comments should be ignored (true) or signaled as errors (false) const bool ignore_comments = false; /// the current character char_int_type current = std::char_traits::eof(); /// whether the next get() call should just return current bool next_unget = false; /// the start position of the current token position_t position {}; /// raw input token string (for error messages) std::vector token_string {}; /// buffer for variable-length tokens (numbers, strings) string_t token_buffer {}; /// a description of occurred lexer errors const char* error_message = ""; // number values number_integer_t value_integer = 0; number_unsigned_t value_unsigned = 0; number_float_t value_float = 0; /// the decimal point const char_int_type decimal_point_char = '.'; }; } // namespace detail } // namespace nlohmann // #include // #include #include // size_t #include // declval #include // string // #include // #include namespace nlohmann { namespace detail { template using null_function_t = decltype(std::declval().null()); template using boolean_function_t = decltype(std::declval().boolean(std::declval())); template using number_integer_function_t = decltype(std::declval().number_integer(std::declval())); template using number_unsigned_function_t = decltype(std::declval().number_unsigned(std::declval())); template using number_float_function_t = decltype(std::declval().number_float( std::declval(), std::declval())); template using string_function_t = decltype(std::declval().string(std::declval())); template using binary_function_t = decltype(std::declval().binary(std::declval())); template using start_object_function_t = decltype(std::declval().start_object(std::declval())); template using key_function_t = decltype(std::declval().key(std::declval())); template using end_object_function_t = decltype(std::declval().end_object()); template using start_array_function_t = decltype(std::declval().start_array(std::declval())); template using end_array_function_t = decltype(std::declval().end_array()); template using parse_error_function_t = decltype(std::declval().parse_error( std::declval(), std::declval(), std::declval())); template struct is_sax { private: static_assert(is_basic_json::value, "BasicJsonType must be of type basic_json<...>"); using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; using exception_t = typename BasicJsonType::exception; public: static constexpr bool value = is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value && is_detected_exact::value; }; template struct is_sax_static_asserts { private: static_assert(is_basic_json::value, "BasicJsonType must be of type basic_json<...>"); using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; using exception_t = typename BasicJsonType::exception; public: static_assert(is_detected_exact::value, "Missing/invalid function: bool null()"); static_assert(is_detected_exact::value, "Missing/invalid function: bool boolean(bool)"); static_assert(is_detected_exact::value, "Missing/invalid function: bool boolean(bool)"); static_assert( is_detected_exact::value, "Missing/invalid function: bool number_integer(number_integer_t)"); static_assert( is_detected_exact::value, "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); static_assert(is_detected_exact::value, "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); static_assert( is_detected_exact::value, "Missing/invalid function: bool string(string_t&)"); static_assert( is_detected_exact::value, "Missing/invalid function: bool binary(binary_t&)"); static_assert(is_detected_exact::value, "Missing/invalid function: bool start_object(std::size_t)"); static_assert(is_detected_exact::value, "Missing/invalid function: bool key(string_t&)"); static_assert(is_detected_exact::value, "Missing/invalid function: bool end_object()"); static_assert(is_detected_exact::value, "Missing/invalid function: bool start_array(std::size_t)"); static_assert(is_detected_exact::value, "Missing/invalid function: bool end_array()"); static_assert( is_detected_exact::value, "Missing/invalid function: bool parse_error(std::size_t, const " "std::string&, const exception&)"); }; } // namespace detail } // namespace nlohmann // #include // #include namespace nlohmann { namespace detail { /// how to treat CBOR tags enum class cbor_tag_handler_t { error, ///< throw a parse_error exception in case of a tag ignore, ///< ignore tags store ///< store tags as binary type }; /*! @brief determine system byte order @return true if and only if system's byte order is little endian @note from https://stackoverflow.com/a/1001328/266378 */ static inline bool little_endianess(int num = 1) noexcept { return *reinterpret_cast(&num) == 1; } /////////////////// // binary reader // /////////////////// /*! @brief deserialization of CBOR, MessagePack, and UBJSON values */ template> class binary_reader { using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; using json_sax_t = SAX; using char_type = typename InputAdapterType::char_type; using char_int_type = typename std::char_traits::int_type; public: /*! @brief create a binary reader @param[in] adapter input adapter to read from */ explicit binary_reader(InputAdapterType&& adapter) noexcept : ia(std::move(adapter)) { (void)detail::is_sax_static_asserts {}; } // make class move-only binary_reader(const binary_reader&) = delete; binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) binary_reader& operator=(const binary_reader&) = delete; binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) ~binary_reader() = default; /*! @param[in] format the binary format to parse @param[in] sax_ a SAX event processor @param[in] strict whether to expect the input to be consumed completed @param[in] tag_handler how to treat CBOR tags @return whether parsing was successful */ JSON_HEDLEY_NON_NULL(3) bool sax_parse(const input_format_t format, json_sax_t* sax_, const bool strict = true, const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { sax = sax_; bool result = false; switch (format) { case input_format_t::bson: result = parse_bson_internal(); break; case input_format_t::cbor: result = parse_cbor_internal(true, tag_handler); break; case input_format_t::msgpack: result = parse_msgpack_internal(); break; case input_format_t::ubjson: result = parse_ubjson_internal(); break; case input_format_t::json: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } // strict mode: next byte must be EOF if (result && strict) { if (format == input_format_t::ubjson) { get_ignore_noop(); } else { get(); } if (JSON_HEDLEY_UNLIKELY(current != std::char_traits::eof())) { return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"), BasicJsonType())); } } return result; } private: ////////// // BSON // ////////// /*! @brief Reads in a BSON-object and passes it to the SAX-parser. @return whether a valid BSON-value was passed to the SAX parser */ bool parse_bson_internal() { std::int32_t document_size{}; get_number(input_format_t::bson, document_size); if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) { return false; } if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) { return false; } return sax->end_object(); } /*! @brief Parses a C-style string from the BSON input. @param[in,out] result A reference to the string variable where the read string is to be stored. @return `true` if the \x00-byte indicating the end of the string was encountered before the EOF; false` indicates an unexpected EOF. */ bool get_bson_cstr(string_t& result) { auto out = std::back_inserter(result); while (true) { get(); if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) { return false; } if (current == 0x00) { return true; } *out++ = static_cast(current); } } /*! @brief Parses a zero-terminated string of length @a len from the BSON input. @param[in] len The length (including the zero-byte at the end) of the string to be read. @param[in,out] result A reference to the string variable where the read string is to be stored. @tparam NumberType The type of the length @a len @pre len >= 1 @return `true` if the string was successfully parsed */ template bool get_bson_string(const NumberType len, string_t& result) { if (JSON_HEDLEY_UNLIKELY(len < 1)) { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"), BasicJsonType())); } return get_string(input_format_t::bson, len - static_cast(1), result) && get() != std::char_traits::eof(); } /*! @brief Parses a byte array input of length @a len from the BSON input. @param[in] len The length of the byte array to be read. @param[in,out] result A reference to the binary variable where the read array is to be stored. @tparam NumberType The type of the length @a len @pre len >= 0 @return `true` if the byte array was successfully parsed */ template bool get_bson_binary(const NumberType len, binary_t& result) { if (JSON_HEDLEY_UNLIKELY(len < 0)) { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"), BasicJsonType())); } // All BSON binary values have a subtype std::uint8_t subtype{}; get_number(input_format_t::bson, subtype); result.set_subtype(subtype); return get_binary(input_format_t::bson, len, result); } /*! @brief Read a BSON document element of the given @a element_type. @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html @param[in] element_type_parse_position The position in the input stream, where the `element_type` was read. @warning Not all BSON element types are supported yet. An unsupported @a element_type will give rise to a parse_error.114: Unsupported BSON record type 0x... @return whether a valid BSON-object/array was passed to the SAX parser */ bool parse_bson_element_internal(const char_int_type element_type, const std::size_t element_type_parse_position) { switch (element_type) { case 0x01: // double { double number{}; return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); } case 0x02: // string { std::int32_t len{}; string_t value; return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); } case 0x03: // object { return parse_bson_internal(); } case 0x04: // array { return parse_bson_array(); } case 0x05: // binary { std::int32_t len{}; binary_t value; return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); } case 0x08: // boolean { return sax->boolean(get() != 0); } case 0x0A: // null { return sax->null(); } case 0x10: // int32 { std::int32_t value{}; return get_number(input_format_t::bson, value) && sax->number_integer(value); } case 0x12: // int64 { std::int64_t value{}; return get_number(input_format_t::bson, value) && sax->number_integer(value); } default: // anything else not supported (yet) { std::array cr{{}}; (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()), BasicJsonType())); } } } /*! @brief Read a BSON element list (as specified in the BSON-spec) The same binary layout is used for objects and arrays, hence it must be indicated with the argument @a is_array which one is expected (true --> array, false --> object). @param[in] is_array Determines if the element list being read is to be treated as an object (@a is_array == false), or as an array (@a is_array == true). @return whether a valid BSON-object/array was passed to the SAX parser */ bool parse_bson_element_list(const bool is_array) { string_t key; while (auto element_type = get()) { if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) { return false; } const std::size_t element_type_parse_position = chars_read; if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) { return false; } if (!is_array && !sax->key(key)) { return false; } if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) { return false; } // get_bson_cstr only appends key.clear(); } return true; } /*! @brief Reads an array from the BSON input and passes it to the SAX-parser. @return whether a valid BSON-array was passed to the SAX parser */ bool parse_bson_array() { std::int32_t document_size{}; get_number(input_format_t::bson, document_size); if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) { return false; } if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) { return false; } return sax->end_array(); } ////////// // CBOR // ////////// /*! @param[in] get_char whether a new character should be retrieved from the input (true) or whether the last read character should be considered instead (false) @param[in] tag_handler how CBOR tags should be treated @return whether a valid CBOR value was passed to the SAX parser */ bool parse_cbor_internal(const bool get_char, const cbor_tag_handler_t tag_handler) { switch (get_char ? get() : current) { // EOF case std::char_traits::eof(): return unexpect_eof(input_format_t::cbor, "value"); // Integer 0x00..0x17 (0..23) case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: return sax->number_unsigned(static_cast(current)); case 0x18: // Unsigned integer (one-byte uint8_t follows) { std::uint8_t number{}; return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); } case 0x19: // Unsigned integer (two-byte uint16_t follows) { std::uint16_t number{}; return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); } case 0x1A: // Unsigned integer (four-byte uint32_t follows) { std::uint32_t number{}; return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); } case 0x1B: // Unsigned integer (eight-byte uint64_t follows) { std::uint64_t number{}; return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); } // Negative integer -1-0x00..-1-0x17 (-1..-24) case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: return sax->number_integer(static_cast(0x20 - 1 - current)); case 0x38: // Negative integer (one-byte uint8_t follows) { std::uint8_t number{}; return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); } case 0x39: // Negative integer -1-n (two-byte uint16_t follows) { std::uint16_t number{}; return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); } case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) { std::uint32_t number{}; return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); } case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) { std::uint64_t number{}; return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - static_cast(number)); } // Binary data (0x00..0x17 bytes follow) case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: // Binary data (one-byte uint8_t for n follows) case 0x59: // Binary data (two-byte uint16_t for n follow) case 0x5A: // Binary data (four-byte uint32_t for n follow) case 0x5B: // Binary data (eight-byte uint64_t for n follow) case 0x5F: // Binary data (indefinite length) { binary_t b; return get_cbor_binary(b) && sax->binary(b); } // UTF-8 string (0x00..0x17 bytes follow) case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: // UTF-8 string (one-byte uint8_t for n follows) case 0x79: // UTF-8 string (two-byte uint16_t for n follow) case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) case 0x7F: // UTF-8 string (indefinite length) { string_t s; return get_cbor_string(s) && sax->string(s); } // array (0x00..0x17 data items follow) case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: return get_cbor_array(static_cast(static_cast(current) & 0x1Fu), tag_handler); case 0x98: // array (one-byte uint8_t for n follows) { std::uint8_t len{}; return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); } case 0x99: // array (two-byte uint16_t for n follow) { std::uint16_t len{}; return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); } case 0x9A: // array (four-byte uint32_t for n follow) { std::uint32_t len{}; return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); } case 0x9B: // array (eight-byte uint64_t for n follow) { std::uint64_t len{}; return get_number(input_format_t::cbor, len) && get_cbor_array(detail::conditional_static_cast(len), tag_handler); } case 0x9F: // array (indefinite length) return get_cbor_array(std::size_t(-1), tag_handler); // map (0x00..0x17 pairs of data items follow) case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: return get_cbor_object(static_cast(static_cast(current) & 0x1Fu), tag_handler); case 0xB8: // map (one-byte uint8_t for n follows) { std::uint8_t len{}; return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); } case 0xB9: // map (two-byte uint16_t for n follow) { std::uint16_t len{}; return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); } case 0xBA: // map (four-byte uint32_t for n follow) { std::uint32_t len{}; return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); } case 0xBB: // map (eight-byte uint64_t for n follow) { std::uint64_t len{}; return get_number(input_format_t::cbor, len) && get_cbor_object(detail::conditional_static_cast(len), tag_handler); } case 0xBF: // map (indefinite length) return get_cbor_object(std::size_t(-1), tag_handler); case 0xC6: // tagged item case 0xC7: case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD8: // tagged item (1 bytes follow) case 0xD9: // tagged item (2 bytes follow) case 0xDA: // tagged item (4 bytes follow) case 0xDB: // tagged item (8 bytes follow) { switch (tag_handler) { case cbor_tag_handler_t::error: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); } case cbor_tag_handler_t::ignore: { // ignore binary subtype switch (current) { case 0xD8: { std::uint8_t subtype_to_ignore{}; get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xD9: { std::uint16_t subtype_to_ignore{}; get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xDA: { std::uint32_t subtype_to_ignore{}; get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xDB: { std::uint64_t subtype_to_ignore{}; get_number(input_format_t::cbor, subtype_to_ignore); break; } default: break; } return parse_cbor_internal(true, tag_handler); } case cbor_tag_handler_t::store: { binary_t b; // use binary subtype and store in binary container switch (current) { case 0xD8: { std::uint8_t subtype{}; get_number(input_format_t::cbor, subtype); b.set_subtype(detail::conditional_static_cast(subtype)); break; } case 0xD9: { std::uint16_t subtype{}; get_number(input_format_t::cbor, subtype); b.set_subtype(detail::conditional_static_cast(subtype)); break; } case 0xDA: { std::uint32_t subtype{}; get_number(input_format_t::cbor, subtype); b.set_subtype(detail::conditional_static_cast(subtype)); break; } case 0xDB: { std::uint64_t subtype{}; get_number(input_format_t::cbor, subtype); b.set_subtype(detail::conditional_static_cast(subtype)); break; } default: return parse_cbor_internal(true, tag_handler); } get(); return get_cbor_binary(b) && sax->binary(b); } default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE return false; // LCOV_EXCL_LINE } } case 0xF4: // false return sax->boolean(false); case 0xF5: // true return sax->boolean(true); case 0xF6: // null return sax->null(); case 0xF9: // Half-Precision Float (two-byte IEEE 754) { const auto byte1_raw = get(); if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) { return false; } const auto byte2_raw = get(); if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) { return false; } const auto byte1 = static_cast(byte1_raw); const auto byte2 = static_cast(byte2_raw); // code from RFC 7049, Appendix D, Figure 3: // As half-precision floating-point numbers were only added // to IEEE 754 in 2008, today's programming platforms often // still only have limited support for them. It is very // easy to include at least decoding support for them even // without such support. An example of a small decoder for // half-precision floating-point numbers in the C language // is shown in Fig. 3. const auto half = static_cast((byte1 << 8u) + byte2); const double val = [&half] { const int exp = (half >> 10u) & 0x1Fu; const unsigned int mant = half & 0x3FFu; JSON_ASSERT(0 <= exp&& exp <= 32); JSON_ASSERT(mant <= 1024); switch (exp) { case 0: return std::ldexp(mant, -24); case 31: return (mant == 0) ? std::numeric_limits::infinity() : std::numeric_limits::quiet_NaN(); default: return std::ldexp(mant + 1024, exp - 25); } }(); return sax->number_float((half & 0x8000u) != 0 ? static_cast(-val) : static_cast(val), ""); } case 0xFA: // Single-Precision Float (four-byte IEEE 754) { float number{}; return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); } case 0xFB: // Double-Precision Float (eight-byte IEEE 754) { double number{}; return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); } default: // anything else (0xFF is handled inside the other types) { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); } } } /*! @brief reads a CBOR string This function first reads starting bytes to determine the expected string length and then copies this number of bytes into a string. Additionally, CBOR's strings with indefinite lengths are supported. @param[out] result created string @return whether string creation completed */ bool get_cbor_string(string_t& result) { if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) { return false; } switch (current) { // UTF-8 string (0x00..0x17 bytes follow) case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: { return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); } case 0x78: // UTF-8 string (one-byte uint8_t for n follows) { std::uint8_t len{}; return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); } case 0x79: // UTF-8 string (two-byte uint16_t for n follow) { std::uint16_t len{}; return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); } case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) { std::uint32_t len{}; return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); } case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) { std::uint64_t len{}; return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); } case 0x7F: // UTF-8 string (indefinite length) { while (get() != 0xFF) { string_t chunk; if (!get_cbor_string(chunk)) { return false; } result.append(chunk); } return true; } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"), BasicJsonType())); } } } /*! @brief reads a CBOR byte array This function first reads starting bytes to determine the expected byte array length and then copies this number of bytes into the byte array. Additionally, CBOR's byte arrays with indefinite lengths are supported. @param[out] result created byte array @return whether byte array creation completed */ bool get_cbor_binary(binary_t& result) { if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) { return false; } switch (current) { // Binary data (0x00..0x17 bytes follow) case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: { return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); } case 0x58: // Binary data (one-byte uint8_t for n follows) { std::uint8_t len{}; return get_number(input_format_t::cbor, len) && get_binary(input_format_t::cbor, len, result); } case 0x59: // Binary data (two-byte uint16_t for n follow) { std::uint16_t len{}; return get_number(input_format_t::cbor, len) && get_binary(input_format_t::cbor, len, result); } case 0x5A: // Binary data (four-byte uint32_t for n follow) { std::uint32_t len{}; return get_number(input_format_t::cbor, len) && get_binary(input_format_t::cbor, len, result); } case 0x5B: // Binary data (eight-byte uint64_t for n follow) { std::uint64_t len{}; return get_number(input_format_t::cbor, len) && get_binary(input_format_t::cbor, len, result); } case 0x5F: // Binary data (indefinite length) { while (get() != 0xFF) { binary_t chunk; if (!get_cbor_binary(chunk)) { return false; } result.insert(result.end(), chunk.begin(), chunk.end()); } return true; } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary"), BasicJsonType())); } } } /*! @param[in] len the length of the array or std::size_t(-1) for an array of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether array creation completed */ bool get_cbor_array(const std::size_t len, const cbor_tag_handler_t tag_handler) { if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) { return false; } if (len != std::size_t(-1)) { for (std::size_t i = 0; i < len; ++i) { if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) { return false; } } } else { while (get() != 0xFF) { if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) { return false; } } } return sax->end_array(); } /*! @param[in] len the length of the object or std::size_t(-1) for an object of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether object creation completed */ bool get_cbor_object(const std::size_t len, const cbor_tag_handler_t tag_handler) { if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) { return false; } if (len != 0) { string_t key; if (len != std::size_t(-1)) { for (std::size_t i = 0; i < len; ++i) { get(); if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) { return false; } if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) { return false; } key.clear(); } } else { while (get() != 0xFF) { if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) { return false; } if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) { return false; } key.clear(); } } } return sax->end_object(); } ///////////// // MsgPack // ///////////// /*! @return whether a valid MessagePack value was passed to the SAX parser */ bool parse_msgpack_internal() { switch (get()) { // EOF case std::char_traits::eof(): return unexpect_eof(input_format_t::msgpack, "value"); // positive fixint case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: return sax->number_unsigned(static_cast(current)); // fixmap case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: return get_msgpack_object(static_cast(static_cast(current) & 0x0Fu)); // fixarray case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: return get_msgpack_array(static_cast(static_cast(current) & 0x0Fu)); // fixstr case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: case 0xD9: // str 8 case 0xDA: // str 16 case 0xDB: // str 32 { string_t s; return get_msgpack_string(s) && sax->string(s); } case 0xC0: // nil return sax->null(); case 0xC2: // false return sax->boolean(false); case 0xC3: // true return sax->boolean(true); case 0xC4: // bin 8 case 0xC5: // bin 16 case 0xC6: // bin 32 case 0xC7: // ext 8 case 0xC8: // ext 16 case 0xC9: // ext 32 case 0xD4: // fixext 1 case 0xD5: // fixext 2 case 0xD6: // fixext 4 case 0xD7: // fixext 8 case 0xD8: // fixext 16 { binary_t b; return get_msgpack_binary(b) && sax->binary(b); } case 0xCA: // float 32 { float number{}; return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); } case 0xCB: // float 64 { double number{}; return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); } case 0xCC: // uint 8 { std::uint8_t number{}; return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); } case 0xCD: // uint 16 { std::uint16_t number{}; return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); } case 0xCE: // uint 32 { std::uint32_t number{}; return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); } case 0xCF: // uint 64 { std::uint64_t number{}; return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); } case 0xD0: // int 8 { std::int8_t number{}; return get_number(input_format_t::msgpack, number) && sax->number_integer(number); } case 0xD1: // int 16 { std::int16_t number{}; return get_number(input_format_t::msgpack, number) && sax->number_integer(number); } case 0xD2: // int 32 { std::int32_t number{}; return get_number(input_format_t::msgpack, number) && sax->number_integer(number); } case 0xD3: // int 64 { std::int64_t number{}; return get_number(input_format_t::msgpack, number) && sax->number_integer(number); } case 0xDC: // array 16 { std::uint16_t len{}; return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); } case 0xDD: // array 32 { std::uint32_t len{}; return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); } case 0xDE: // map 16 { std::uint16_t len{}; return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); } case 0xDF: // map 32 { std::uint32_t len{}; return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); } // negative fixint case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: case 0xEF: case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7: case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: return sax->number_integer(static_cast(current)); default: // anything else { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); } } } /*! @brief reads a MessagePack string This function first reads starting bytes to determine the expected string length and then copies this number of bytes into a string. @param[out] result created string @return whether string creation completed */ bool get_msgpack_string(string_t& result) { if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) { return false; } switch (current) { // fixstr case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: { return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result); } case 0xD9: // str 8 { std::uint8_t len{}; return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); } case 0xDA: // str 16 { std::uint16_t len{}; return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); } case 0xDB: // str 32 { std::uint32_t len{}; return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"), BasicJsonType())); } } } /*! @brief reads a MessagePack byte array This function first reads starting bytes to determine the expected byte array length and then copies this number of bytes into a byte array. @param[out] result created byte array @return whether byte array creation completed */ bool get_msgpack_binary(binary_t& result) { // helper function to set the subtype auto assign_and_return_true = [&result](std::int8_t subtype) { result.set_subtype(static_cast(subtype)); return true; }; switch (current) { case 0xC4: // bin 8 { std::uint8_t len{}; return get_number(input_format_t::msgpack, len) && get_binary(input_format_t::msgpack, len, result); } case 0xC5: // bin 16 { std::uint16_t len{}; return get_number(input_format_t::msgpack, len) && get_binary(input_format_t::msgpack, len, result); } case 0xC6: // bin 32 { std::uint32_t len{}; return get_number(input_format_t::msgpack, len) && get_binary(input_format_t::msgpack, len, result); } case 0xC7: // ext 8 { std::uint8_t len{}; std::int8_t subtype{}; return get_number(input_format_t::msgpack, len) && get_number(input_format_t::msgpack, subtype) && get_binary(input_format_t::msgpack, len, result) && assign_and_return_true(subtype); } case 0xC8: // ext 16 { std::uint16_t len{}; std::int8_t subtype{}; return get_number(input_format_t::msgpack, len) && get_number(input_format_t::msgpack, subtype) && get_binary(input_format_t::msgpack, len, result) && assign_and_return_true(subtype); } case 0xC9: // ext 32 { std::uint32_t len{}; std::int8_t subtype{}; return get_number(input_format_t::msgpack, len) && get_number(input_format_t::msgpack, subtype) && get_binary(input_format_t::msgpack, len, result) && assign_and_return_true(subtype); } case 0xD4: // fixext 1 { std::int8_t subtype{}; return get_number(input_format_t::msgpack, subtype) && get_binary(input_format_t::msgpack, 1, result) && assign_and_return_true(subtype); } case 0xD5: // fixext 2 { std::int8_t subtype{}; return get_number(input_format_t::msgpack, subtype) && get_binary(input_format_t::msgpack, 2, result) && assign_and_return_true(subtype); } case 0xD6: // fixext 4 { std::int8_t subtype{}; return get_number(input_format_t::msgpack, subtype) && get_binary(input_format_t::msgpack, 4, result) && assign_and_return_true(subtype); } case 0xD7: // fixext 8 { std::int8_t subtype{}; return get_number(input_format_t::msgpack, subtype) && get_binary(input_format_t::msgpack, 8, result) && assign_and_return_true(subtype); } case 0xD8: // fixext 16 { std::int8_t subtype{}; return get_number(input_format_t::msgpack, subtype) && get_binary(input_format_t::msgpack, 16, result) && assign_and_return_true(subtype); } default: // LCOV_EXCL_LINE return false; // LCOV_EXCL_LINE } } /*! @param[in] len the length of the array @return whether array creation completed */ bool get_msgpack_array(const std::size_t len) { if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) { return false; } for (std::size_t i = 0; i < len; ++i) { if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) { return false; } } return sax->end_array(); } /*! @param[in] len the length of the object @return whether object creation completed */ bool get_msgpack_object(const std::size_t len) { if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) { return false; } string_t key; for (std::size_t i = 0; i < len; ++i) { get(); if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) { return false; } if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) { return false; } key.clear(); } return sax->end_object(); } //////////// // UBJSON // //////////// /*! @param[in] get_char whether a new character should be retrieved from the input (true, default) or whether the last read character should be considered instead @return whether a valid UBJSON value was passed to the SAX parser */ bool parse_ubjson_internal(const bool get_char = true) { return get_ubjson_value(get_char ? get_ignore_noop() : current); } /*! @brief reads a UBJSON string This function is either called after reading the 'S' byte explicitly indicating a string, or in case of an object key where the 'S' byte can be left out. @param[out] result created string @param[in] get_char whether a new character should be retrieved from the input (true, default) or whether the last read character should be considered instead @return whether string creation completed */ bool get_ubjson_string(string_t& result, const bool get_char = true) { if (get_char) { get(); // TODO(niels): may we ignore N here? } if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) { return false; } switch (current) { case 'U': { std::uint8_t len{}; return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } case 'i': { std::int8_t len{}; return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } case 'I': { std::int16_t len{}; return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } case 'l': { std::int32_t len{}; return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } case 'L': { std::int64_t len{}; return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); } default: auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"), BasicJsonType())); } } /*! @param[out] result determined size @return whether size determination completed */ bool get_ubjson_size_value(std::size_t& result) { switch (get_ignore_noop()) { case 'U': { std::uint8_t number{}; if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } result = static_cast(number); return true; } case 'i': { std::int8_t number{}; if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char return true; } case 'I': { std::int16_t number{}; if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } result = static_cast(number); return true; } case 'l': { std::int32_t number{}; if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } result = static_cast(number); return true; } case 'L': { std::int64_t number{}; if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) { return false; } result = static_cast(number); return true; } default: { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"), BasicJsonType())); } } } /*! @brief determine the type and size for a container In the optimized UBJSON format, a type and a size can be provided to allow for a more compact representation. @param[out] result pair of the size and the type @return whether pair creation completed */ bool get_ubjson_size_type(std::pair& result) { result.first = string_t::npos; // size result.second = 0; // type get_ignore_noop(); if (current == '$') { result.second = get(); // must not ignore 'N', because 'N' maybe the type if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "type"))) { return false; } get_ignore_noop(); if (JSON_HEDLEY_UNLIKELY(current != '#')) { if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) { return false; } auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"), BasicJsonType())); } return get_ubjson_size_value(result.first); } if (current == '#') { return get_ubjson_size_value(result.first); } return true; } /*! @param prefix the previously read or set type prefix @return whether value creation completed */ bool get_ubjson_value(const char_int_type prefix) { switch (prefix) { case std::char_traits::eof(): // EOF return unexpect_eof(input_format_t::ubjson, "value"); case 'T': // true return sax->boolean(true); case 'F': // false return sax->boolean(false); case 'Z': // null return sax->null(); case 'U': { std::uint8_t number{}; return get_number(input_format_t::ubjson, number) && sax->number_unsigned(number); } case 'i': { std::int8_t number{}; return get_number(input_format_t::ubjson, number) && sax->number_integer(number); } case 'I': { std::int16_t number{}; return get_number(input_format_t::ubjson, number) && sax->number_integer(number); } case 'l': { std::int32_t number{}; return get_number(input_format_t::ubjson, number) && sax->number_integer(number); } case 'L': { std::int64_t number{}; return get_number(input_format_t::ubjson, number) && sax->number_integer(number); } case 'd': { float number{}; return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); } case 'D': { double number{}; return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); } case 'H': { return get_ubjson_high_precision_number(); } case 'C': // char { get(); if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "char"))) { return false; } if (JSON_HEDLEY_UNLIKELY(current > 127)) { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"), BasicJsonType())); } string_t s(1, static_cast(current)); return sax->string(s); } case 'S': // string { string_t s; return get_ubjson_string(s) && sax->string(s); } case '[': // array return get_ubjson_array(); case '{': // object return get_ubjson_object(); default: // anything else { auto last_token = get_token_string(); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); } } } /*! @return whether array creation completed */ bool get_ubjson_array() { std::pair size_and_type; if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) { return false; } if (size_and_type.first != string_t::npos) { if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) { return false; } if (size_and_type.second != 0) { if (size_and_type.second != 'N') { for (std::size_t i = 0; i < size_and_type.first; ++i) { if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) { return false; } } } } else { for (std::size_t i = 0; i < size_and_type.first; ++i) { if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) { return false; } } } } else { if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) { return false; } while (current != ']') { if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) { return false; } get_ignore_noop(); } } return sax->end_array(); } /*! @return whether object creation completed */ bool get_ubjson_object() { std::pair size_and_type; if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) { return false; } string_t key; if (size_and_type.first != string_t::npos) { if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) { return false; } if (size_and_type.second != 0) { for (std::size_t i = 0; i < size_and_type.first; ++i) { if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) { return false; } if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) { return false; } key.clear(); } } else { for (std::size_t i = 0; i < size_and_type.first; ++i) { if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) { return false; } if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) { return false; } key.clear(); } } } else { if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) { return false; } while (current != '}') { if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) { return false; } if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) { return false; } get_ignore_noop(); key.clear(); } } return sax->end_object(); } // Note, no reader for UBJSON binary types is implemented because they do // not exist bool get_ubjson_high_precision_number() { // get size of following number string std::size_t size{}; auto res = get_ubjson_size_value(size); if (JSON_HEDLEY_UNLIKELY(!res)) { return res; } // get number string std::vector number_vector; for (std::size_t i = 0; i < size; ++i) { get(); if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "number"))) { return false; } number_vector.push_back(static_cast(current)); } // parse number string using ia_type = decltype(detail::input_adapter(number_vector)); auto number_lexer = detail::lexer(detail::input_adapter(number_vector), false); const auto result_number = number_lexer.scan(); const auto number_string = number_lexer.get_token_string(); const auto result_remainder = number_lexer.scan(); using token_type = typename detail::lexer_base::token_type; if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) { return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType())); } switch (result_number) { case token_type::value_integer: return sax->number_integer(number_lexer.get_number_integer()); case token_type::value_unsigned: return sax->number_unsigned(number_lexer.get_number_unsigned()); case token_type::value_float: return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); case token_type::uninitialized: case token_type::literal_true: case token_type::literal_false: case token_type::literal_null: case token_type::value_string: case token_type::begin_array: case token_type::begin_object: case token_type::end_array: case token_type::end_object: case token_type::name_separator: case token_type::value_separator: case token_type::parse_error: case token_type::end_of_input: case token_type::literal_or_value: default: return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType())); } } /////////////////////// // Utility functions // /////////////////////// /*! @brief get next character from the input This function provides the interface to the used input adapter. It does not throw in case the input reached EOF, but returns a -'ve valued `std::char_traits::eof()` in that case. @return character read from the input */ char_int_type get() { ++chars_read; return current = ia.get_character(); } /*! @return character read from the input after ignoring all 'N' entries */ char_int_type get_ignore_noop() { do { get(); } while (current == 'N'); return current; } /* @brief read a number from the input @tparam NumberType the type of the number @param[in] format the current format (for diagnostics) @param[out] result number of type @a NumberType @return whether conversion completed @note This function needs to respect the system's endianess, because bytes in CBOR, MessagePack, and UBJSON are stored in network order (big endian) and therefore need reordering on little endian systems. */ template bool get_number(const input_format_t format, NumberType& result) { // step 1: read input into array with system's byte order std::array vec{}; for (std::size_t i = 0; i < sizeof(NumberType); ++i) { get(); if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) { return false; } // reverse byte order prior to conversion if necessary if (is_little_endian != InputIsLittleEndian) { vec[sizeof(NumberType) - i - 1] = static_cast(current); } else { vec[i] = static_cast(current); // LCOV_EXCL_LINE } } // step 2: convert array into number of type T and return std::memcpy(&result, vec.data(), sizeof(NumberType)); return true; } /*! @brief create a string by reading characters from the input @tparam NumberType the type of the number @param[in] format the current format (for diagnostics) @param[in] len number of characters to read @param[out] result string created by reading @a len bytes @return whether string creation completed @note We can not reserve @a len bytes for the result, because @a len may be too large. Usually, @ref unexpect_eof() detects the end of the input before we run out of string memory. */ template bool get_string(const input_format_t format, const NumberType len, string_t& result) { bool success = true; for (NumberType i = 0; i < len; i++) { get(); if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) { success = false; break; } result.push_back(static_cast(current)); } return success; } /*! @brief create a byte array by reading bytes from the input @tparam NumberType the type of the number @param[in] format the current format (for diagnostics) @param[in] len number of bytes to read @param[out] result byte array created by reading @a len bytes @return whether byte array creation completed @note We can not reserve @a len bytes for the result, because @a len may be too large. Usually, @ref unexpect_eof() detects the end of the input before we run out of memory. */ template bool get_binary(const input_format_t format, const NumberType len, binary_t& result) { bool success = true; for (NumberType i = 0; i < len; i++) { get(); if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) { success = false; break; } result.push_back(static_cast(current)); } return success; } /*! @param[in] format the current format (for diagnostics) @param[in] context further context information (for diagnostics) @return whether the last read character is not EOF */ JSON_HEDLEY_NON_NULL(3) bool unexpect_eof(const input_format_t format, const char* context) const { if (JSON_HEDLEY_UNLIKELY(current == std::char_traits::eof())) { return sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), BasicJsonType())); } return true; } /*! @return a string representation of the last read byte */ std::string get_token_string() const { std::array cr{{}}; (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) return std::string{cr.data()}; } /*! @param[in] format the current format @param[in] detail a detailed error message @param[in] context further context information @return a message string to use in the parse_error exceptions */ std::string exception_message(const input_format_t format, const std::string& detail, const std::string& context) const { std::string error_msg = "syntax error while parsing "; switch (format) { case input_format_t::cbor: error_msg += "CBOR"; break; case input_format_t::msgpack: error_msg += "MessagePack"; break; case input_format_t::ubjson: error_msg += "UBJSON"; break; case input_format_t::bson: error_msg += "BSON"; break; case input_format_t::json: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } return error_msg + " " + context + ": " + detail; } private: /// input adapter InputAdapterType ia; /// the current character char_int_type current = std::char_traits::eof(); /// the number of characters read std::size_t chars_read = 0; /// whether we can assume little endianess const bool is_little_endian = little_endianess(); /// the SAX parser json_sax_t* sax = nullptr; }; } // namespace detail } // namespace nlohmann // #include // #include // #include #include // isfinite #include // uint8_t #include // function #include // string #include // move #include // vector // #include // #include // #include // #include // #include // #include // #include namespace nlohmann { namespace detail { //////////// // parser // //////////// enum class parse_event_t : std::uint8_t { /// the parser read `{` and started to process a JSON object object_start, /// the parser read `}` and finished processing a JSON object object_end, /// the parser read `[` and started to process a JSON array array_start, /// the parser read `]` and finished processing a JSON array array_end, /// the parser read a key of a value in an object key, /// the parser finished reading a JSON value value }; template using parser_callback_t = std::function; /*! @brief syntax analysis This class implements a recursive descent parser. */ template class parser { using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using lexer_t = lexer; using token_type = typename lexer_t::token_type; public: /// a parser reading from an input adapter explicit parser(InputAdapterType&& adapter, const parser_callback_t cb = nullptr, const bool allow_exceptions_ = true, const bool skip_comments = false) : callback(cb) , m_lexer(std::move(adapter), skip_comments) , allow_exceptions(allow_exceptions_) { // read first token get_token(); } /*! @brief public parser interface @param[in] strict whether to expect the last token to be EOF @param[in,out] result parsed JSON value @throw parse_error.101 in case of an unexpected token @throw parse_error.102 if to_unicode fails or surrogate error @throw parse_error.103 if to_unicode fails */ void parse(const bool strict, BasicJsonType& result) { if (callback) { json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); sax_parse_internal(&sdp); // in strict mode, input must be completely read if (strict && (get_token() != token_type::end_of_input)) { sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType())); } // in case of an error, return discarded value if (sdp.is_errored()) { result = value_t::discarded; return; } // set top-level value to null if it was discarded by the callback // function if (result.is_discarded()) { result = nullptr; } } else { json_sax_dom_parser sdp(result, allow_exceptions); sax_parse_internal(&sdp); // in strict mode, input must be completely read if (strict && (get_token() != token_type::end_of_input)) { sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType())); } // in case of an error, return discarded value if (sdp.is_errored()) { result = value_t::discarded; return; } } result.assert_invariant(); } /*! @brief public accept interface @param[in] strict whether to expect the last token to be EOF @return whether the input is a proper JSON text */ bool accept(const bool strict = true) { json_sax_acceptor sax_acceptor; return sax_parse(&sax_acceptor, strict); } template JSON_HEDLEY_NON_NULL(2) bool sax_parse(SAX* sax, const bool strict = true) { (void)detail::is_sax_static_asserts {}; const bool result = sax_parse_internal(sax); // strict mode: next byte must be EOF if (result && strict && (get_token() != token_type::end_of_input)) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType())); } return result; } private: template JSON_HEDLEY_NON_NULL(2) bool sax_parse_internal(SAX* sax) { // stack to remember the hierarchy of structured values we are parsing // true = array; false = object std::vector states; // value to avoid a goto (see comment where set to true) bool skip_to_state_evaluation = false; while (true) { if (!skip_to_state_evaluation) { // invariant: get_token() was called before each iteration switch (last_token) { case token_type::begin_object: { if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) { return false; } // closing } -> we are done if (get_token() == token_type::end_object) { if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) { return false; } break; } // parse key if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType())); } if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) { return false; } // parse separator (:) if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType())); } // remember we are now inside an object states.push_back(false); // parse values get_token(); continue; } case token_type::begin_array: { if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) { return false; } // closing ] -> we are done if (get_token() == token_type::end_array) { if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) { return false; } break; } // remember we are now inside an array states.push_back(true); // parse values (no need to call get_token) continue; } case token_type::value_float: { const auto res = m_lexer.get_number_float(); if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'", BasicJsonType())); } if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) { return false; } break; } case token_type::literal_false: { if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) { return false; } break; } case token_type::literal_null: { if (JSON_HEDLEY_UNLIKELY(!sax->null())) { return false; } break; } case token_type::literal_true: { if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) { return false; } break; } case token_type::value_integer: { if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) { return false; } break; } case token_type::value_string: { if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) { return false; } break; } case token_type::value_unsigned: { if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) { return false; } break; } case token_type::parse_error: { // using "uninitialized" to avoid "expected" message return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), BasicJsonType())); } case token_type::uninitialized: case token_type::end_array: case token_type::end_object: case token_type::name_separator: case token_type::value_separator: case token_type::end_of_input: case token_type::literal_or_value: default: // the last token was unexpected { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), BasicJsonType())); } } } else { skip_to_state_evaluation = false; } // we reached this line after we successfully parsed a value if (states.empty()) { // empty stack: we reached the end of the hierarchy: done return true; } if (states.back()) // array { // comma -> next value if (get_token() == token_type::value_separator) { // parse a new value get_token(); continue; } // closing ] if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) { if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) { return false; } // We are done with this array. Before we can parse a // new value, we need to evaluate the new state first. // By setting skip_to_state_evaluation to false, we // are effectively jumping to the beginning of this if. JSON_ASSERT(!states.empty()); states.pop_back(); skip_to_state_evaluation = true; continue; } return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), BasicJsonType())); } // states.back() is false -> object // comma -> next value if (get_token() == token_type::value_separator) { // parse key if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType())); } if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) { return false; } // parse separator (:) if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType())); } // parse values get_token(); continue; } // closing } if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) { if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) { return false; } // We are done with this object. Before we can parse a // new value, we need to evaluate the new state first. // By setting skip_to_state_evaluation to false, we // are effectively jumping to the beginning of this if. JSON_ASSERT(!states.empty()); states.pop_back(); skip_to_state_evaluation = true; continue; } return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), BasicJsonType())); } } /// get next token from lexer token_type get_token() { return last_token = m_lexer.scan(); } std::string exception_message(const token_type expected, const std::string& context) { std::string error_msg = "syntax error "; if (!context.empty()) { error_msg += "while parsing " + context + " "; } error_msg += "- "; if (last_token == token_type::parse_error) { error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + m_lexer.get_token_string() + "'"; } else { error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); } if (expected != token_type::uninitialized) { error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); } return error_msg; } private: /// callback function const parser_callback_t callback = nullptr; /// the type of the last read token token_type last_token = token_type::uninitialized; /// the lexer lexer_t m_lexer; /// whether to throw exceptions in case of errors const bool allow_exceptions = true; }; } // namespace detail } // namespace nlohmann // #include // #include #include // ptrdiff_t #include // numeric_limits // #include namespace nlohmann { namespace detail { /* @brief an iterator for primitive JSON types This class models an iterator for primitive JSON types (boolean, number, string). It's only purpose is to allow the iterator/const_iterator classes to "iterate" over primitive values. Internally, the iterator is modeled by a `difference_type` variable. Value begin_value (`0`) models the begin, end_value (`1`) models past the end. */ class primitive_iterator_t { private: using difference_type = std::ptrdiff_t; static constexpr difference_type begin_value = 0; static constexpr difference_type end_value = begin_value + 1; JSON_PRIVATE_UNLESS_TESTED: /// iterator as signed integer type difference_type m_it = (std::numeric_limits::min)(); public: constexpr difference_type get_value() const noexcept { return m_it; } /// set iterator to a defined beginning void set_begin() noexcept { m_it = begin_value; } /// set iterator to a defined past the end void set_end() noexcept { m_it = end_value; } /// return whether the iterator can be dereferenced constexpr bool is_begin() const noexcept { return m_it == begin_value; } /// return whether the iterator is at end constexpr bool is_end() const noexcept { return m_it == end_value; } friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept { return lhs.m_it == rhs.m_it; } friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept { return lhs.m_it < rhs.m_it; } primitive_iterator_t operator+(difference_type n) noexcept { auto result = *this; result += n; return result; } friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept { return lhs.m_it - rhs.m_it; } primitive_iterator_t& operator++() noexcept { ++m_it; return *this; } primitive_iterator_t const operator++(int) noexcept // NOLINT(readability-const-return-type) { auto result = *this; ++m_it; return result; } primitive_iterator_t& operator--() noexcept { --m_it; return *this; } primitive_iterator_t const operator--(int) noexcept // NOLINT(readability-const-return-type) { auto result = *this; --m_it; return result; } primitive_iterator_t& operator+=(difference_type n) noexcept { m_it += n; return *this; } primitive_iterator_t& operator-=(difference_type n) noexcept { m_it -= n; return *this; } }; } // namespace detail } // namespace nlohmann namespace nlohmann { namespace detail { /*! @brief an iterator value @note This structure could easily be a union, but MSVC currently does not allow unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. */ template struct internal_iterator { /// iterator for JSON objects typename BasicJsonType::object_t::iterator object_iterator {}; /// iterator for JSON arrays typename BasicJsonType::array_t::iterator array_iterator {}; /// generic iterator for all other types primitive_iterator_t primitive_iterator {}; }; } // namespace detail } // namespace nlohmann // #include #include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next #include // conditional, is_const, remove_const // #include // #include // #include // #include // #include // #include // #include namespace nlohmann { namespace detail { // forward declare, to be able to friend it later on template class iteration_proxy; template class iteration_proxy_value; /*! @brief a template for a bidirectional iterator for the @ref basic_json class This class implements a both iterators (iterator and const_iterator) for the @ref basic_json class. @note An iterator is called *initialized* when a pointer to a JSON value has been set (e.g., by a constructor or a copy assignment). If the iterator is default-constructed, it is *uninitialized* and most methods are undefined. **The library uses assertions to detect calls on uninitialized iterators.** @requirement The class satisfies the following concept requirements: - [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): The iterator that can be moved can be moved in both directions (i.e. incremented and decremented). @since version 1.0.0, simplified in version 2.0.9, change to bidirectional iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) */ template class iter_impl { /// the iterator with BasicJsonType of different const-ness using other_iter_impl = iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; /// allow basic_json to access private members friend other_iter_impl; friend BasicJsonType; friend iteration_proxy; friend iteration_proxy_value; using object_t = typename BasicJsonType::object_t; using array_t = typename BasicJsonType::array_t; // make sure BasicJsonType is basic_json or const basic_json static_assert(is_basic_json::type>::value, "iter_impl only accepts (const) basic_json"); public: /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. /// The C++ Standard has never required user-defined iterators to derive from std::iterator. /// A user-defined iterator should provide publicly accessible typedefs named /// iterator_category, value_type, difference_type, pointer, and reference. /// Note that value_type is required to be non-const, even for constant iterators. using iterator_category = std::bidirectional_iterator_tag; /// the type of the values when the iterator is dereferenced using value_type = typename BasicJsonType::value_type; /// a type to represent differences between iterators using difference_type = typename BasicJsonType::difference_type; /// defines a pointer to the type iterated over (value_type) using pointer = typename std::conditional::value, typename BasicJsonType::const_pointer, typename BasicJsonType::pointer>::type; /// defines a reference to the type iterated over (value_type) using reference = typename std::conditional::value, typename BasicJsonType::const_reference, typename BasicJsonType::reference>::type; iter_impl() = default; ~iter_impl() = default; iter_impl(iter_impl&&) noexcept = default; iter_impl& operator=(iter_impl&&) noexcept = default; /*! @brief constructor for a given JSON instance @param[in] object pointer to a JSON object for this iterator @pre object != nullptr @post The iterator is initialized; i.e. `m_object != nullptr`. */ explicit iter_impl(pointer object) noexcept : m_object(object) { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { m_it.object_iterator = typename object_t::iterator(); break; } case value_t::array: { m_it.array_iterator = typename array_t::iterator(); break; } case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { m_it.primitive_iterator = primitive_iterator_t(); break; } } } /*! @note The conventional copy constructor and copy assignment are implicitly defined. Combined with the following converting constructor and assignment, they support: (1) copy from iterator to iterator, (2) copy from const iterator to const iterator, and (3) conversion from iterator to const iterator. However conversion from const iterator to iterator is not defined. */ /*! @brief const copy constructor @param[in] other const iterator to copy from @note This copy constructor had to be defined explicitly to circumvent a bug occurring on msvc v19.0 compiler (VS 2015) debug build. For more information refer to: https://github.com/nlohmann/json/issues/1608 */ iter_impl(const iter_impl& other) noexcept : m_object(other.m_object), m_it(other.m_it) {} /*! @brief converting assignment @param[in] other const iterator to copy from @return const/non-const iterator @note It is not checked whether @a other is initialized. */ iter_impl& operator=(const iter_impl& other) noexcept { if (&other != this) { m_object = other.m_object; m_it = other.m_it; } return *this; } /*! @brief converting constructor @param[in] other non-const iterator to copy from @note It is not checked whether @a other is initialized. */ iter_impl(const iter_impl::type>& other) noexcept : m_object(other.m_object), m_it(other.m_it) {} /*! @brief converting assignment @param[in] other non-const iterator to copy from @return const/non-const iterator @note It is not checked whether @a other is initialized. */ iter_impl& operator=(const iter_impl::type>& other) noexcept // NOLINT(cert-oop54-cpp) { m_object = other.m_object; m_it = other.m_it; return *this; } JSON_PRIVATE_UNLESS_TESTED: /*! @brief set the iterator to the first value @pre The iterator is initialized; i.e. `m_object != nullptr`. */ void set_begin() noexcept { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { m_it.object_iterator = m_object->m_value.object->begin(); break; } case value_t::array: { m_it.array_iterator = m_object->m_value.array->begin(); break; } case value_t::null: { // set to end so begin()==end() is true: null is empty m_it.primitive_iterator.set_end(); break; } case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { m_it.primitive_iterator.set_begin(); break; } } } /*! @brief set the iterator past the last value @pre The iterator is initialized; i.e. `m_object != nullptr`. */ void set_end() noexcept { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { m_it.object_iterator = m_object->m_value.object->end(); break; } case value_t::array: { m_it.array_iterator = m_object->m_value.array->end(); break; } case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { m_it.primitive_iterator.set_end(); break; } } } public: /*! @brief return a reference to the value pointed to by the iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ reference operator*() const { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); return m_it.object_iterator->second; } case value_t::array: { JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); return *m_it.array_iterator; } case value_t::null: JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) { return *m_object; } JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); } } } /*! @brief dereference the iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ pointer operator->() const { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); return &(m_it.object_iterator->second); } case value_t::array: { JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); return &*m_it.array_iterator; } case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) { return m_object; } JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); } } } /*! @brief post-increment (it++) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ iter_impl const operator++(int) // NOLINT(readability-const-return-type) { auto result = *this; ++(*this); return result; } /*! @brief pre-increment (++it) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ iter_impl& operator++() { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { std::advance(m_it.object_iterator, 1); break; } case value_t::array: { std::advance(m_it.array_iterator, 1); break; } case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { ++m_it.primitive_iterator; break; } } return *this; } /*! @brief post-decrement (it--) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ iter_impl const operator--(int) // NOLINT(readability-const-return-type) { auto result = *this; --(*this); return result; } /*! @brief pre-decrement (--it) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ iter_impl& operator--() { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { std::advance(m_it.object_iterator, -1); break; } case value_t::array: { std::advance(m_it.array_iterator, -1); break; } case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { --m_it.primitive_iterator; break; } } return *this; } /*! @brief comparison: equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator==(const IterImpl& other) const { // if objects are not the same, the comparison is undefined if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) { JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object)); } JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: return (m_it.object_iterator == other.m_it.object_iterator); case value_t::array: return (m_it.array_iterator == other.m_it.array_iterator); case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: return (m_it.primitive_iterator == other.m_it.primitive_iterator); } } /*! @brief comparison: not equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > bool operator!=(const IterImpl& other) const { return !operator==(other); } /*! @brief comparison: smaller @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator<(const iter_impl& other) const { // if objects are not the same, the comparison is undefined if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) { JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object)); } JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", *m_object)); case value_t::array: return (m_it.array_iterator < other.m_it.array_iterator); case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: return (m_it.primitive_iterator < other.m_it.primitive_iterator); } } /*! @brief comparison: less than or equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator<=(const iter_impl& other) const { return !other.operator < (*this); } /*! @brief comparison: greater than @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator>(const iter_impl& other) const { return !operator<=(other); } /*! @brief comparison: greater than or equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator>=(const iter_impl& other) const { return !operator<(other); } /*! @brief add to iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ iter_impl& operator+=(difference_type i) { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object)); case value_t::array: { std::advance(m_it.array_iterator, i); break; } case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { m_it.primitive_iterator += i; break; } } return *this; } /*! @brief subtract from iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ iter_impl& operator-=(difference_type i) { return operator+=(-i); } /*! @brief add to iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ iter_impl operator+(difference_type i) const { auto result = *this; result += i; return result; } /*! @brief addition of distance and iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ friend iter_impl operator+(difference_type i, const iter_impl& it) { auto result = it; result += i; return result; } /*! @brief subtract from iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ iter_impl operator-(difference_type i) const { auto result = *this; result -= i; return result; } /*! @brief return difference @pre The iterator is initialized; i.e. `m_object != nullptr`. */ difference_type operator-(const iter_impl& other) const { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object)); case value_t::array: return m_it.array_iterator - other.m_it.array_iterator; case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: return m_it.primitive_iterator - other.m_it.primitive_iterator; } } /*! @brief access to successor @pre The iterator is initialized; i.e. `m_object != nullptr`. */ reference operator[](difference_type n) const { JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", *m_object)); case value_t::array: return *std::next(m_it.array_iterator, n); case value_t::null: JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) { return *m_object; } JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); } } } /*! @brief return the key of an object iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ const typename object_t::key_type& key() const { JSON_ASSERT(m_object != nullptr); if (JSON_HEDLEY_LIKELY(m_object->is_object())) { return m_it.object_iterator->first; } JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", *m_object)); } /*! @brief return the value of an iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ reference value() const { return operator*(); } JSON_PRIVATE_UNLESS_TESTED: /// associated JSON instance pointer m_object = nullptr; /// the actual iterator of the associated instance internal_iterator::type> m_it {}; }; } // namespace detail } // namespace nlohmann // #include // #include #include // ptrdiff_t #include // reverse_iterator #include // declval namespace nlohmann { namespace detail { ////////////////////// // reverse_iterator // ////////////////////// /*! @brief a template for a reverse iterator class @tparam Base the base iterator type to reverse. Valid types are @ref iterator (to create @ref reverse_iterator) and @ref const_iterator (to create @ref const_reverse_iterator). @requirement The class satisfies the following concept requirements: - [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): The iterator that can be moved can be moved in both directions (i.e. incremented and decremented). - [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): It is possible to write to the pointed-to element (only if @a Base is @ref iterator). @since version 1.0.0 */ template class json_reverse_iterator : public std::reverse_iterator { public: using difference_type = std::ptrdiff_t; /// shortcut to the reverse iterator adapter using base_iterator = std::reverse_iterator; /// the reference type for the pointed-to element using reference = typename Base::reference; /// create reverse iterator from iterator explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept : base_iterator(it) {} /// create reverse iterator from base class explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} /// post-increment (it++) json_reverse_iterator const operator++(int) // NOLINT(readability-const-return-type) { return static_cast(base_iterator::operator++(1)); } /// pre-increment (++it) json_reverse_iterator& operator++() { return static_cast(base_iterator::operator++()); } /// post-decrement (it--) json_reverse_iterator const operator--(int) // NOLINT(readability-const-return-type) { return static_cast(base_iterator::operator--(1)); } /// pre-decrement (--it) json_reverse_iterator& operator--() { return static_cast(base_iterator::operator--()); } /// add to iterator json_reverse_iterator& operator+=(difference_type i) { return static_cast(base_iterator::operator+=(i)); } /// add to iterator json_reverse_iterator operator+(difference_type i) const { return static_cast(base_iterator::operator+(i)); } /// subtract from iterator json_reverse_iterator operator-(difference_type i) const { return static_cast(base_iterator::operator-(i)); } /// return difference difference_type operator-(const json_reverse_iterator& other) const { return base_iterator(*this) - base_iterator(other); } /// access to successor reference operator[](difference_type n) const { return *(this->operator+(n)); } /// return the key of an object iterator auto key() const -> decltype(std::declval().key()) { auto it = --this->base(); return it.key(); } /// return the value of an iterator reference value() const { auto it = --this->base(); return it.operator * (); } }; } // namespace detail } // namespace nlohmann // #include // #include #include // all_of #include // isdigit #include // max #include // accumulate #include // string #include // move #include // vector // #include // #include // #include // #include namespace nlohmann { template class json_pointer { // allow basic_json to access private members NLOHMANN_BASIC_JSON_TPL_DECLARATION friend class basic_json; public: /*! @brief create JSON pointer Create a JSON pointer according to the syntax described in [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). @param[in] s string representing the JSON pointer; if omitted, the empty string is assumed which references the whole JSON value @throw parse_error.107 if the given JSON pointer @a s is nonempty and does not begin with a slash (`/`); see example below @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is not followed by `0` (representing `~`) or `1` (representing `/`); see example below @liveexample{The example shows the construction several valid JSON pointers as well as the exceptional behavior.,json_pointer} @since version 2.0.0 */ explicit json_pointer(const std::string& s = "") : reference_tokens(split(s)) {} /*! @brief return a string representation of the JSON pointer @invariant For each JSON pointer `ptr`, it holds: @code {.cpp} ptr == json_pointer(ptr.to_string()); @endcode @return a string representation of the JSON pointer @liveexample{The example shows the result of `to_string`.,json_pointer__to_string} @since version 2.0.0 */ std::string to_string() const { return std::accumulate(reference_tokens.begin(), reference_tokens.end(), std::string{}, [](const std::string & a, const std::string & b) { return a + "/" + detail::escape(b); }); } /// @copydoc to_string() operator std::string() const { return to_string(); } /*! @brief append another JSON pointer at the end of this JSON pointer @param[in] ptr JSON pointer to append @return JSON pointer with @a ptr appended @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} @complexity Linear in the length of @a ptr. @sa see @ref operator/=(std::string) to append a reference token @sa see @ref operator/=(std::size_t) to append an array index @sa see @ref operator/(const json_pointer&, const json_pointer&) for a binary operator @since version 3.6.0 */ json_pointer& operator/=(const json_pointer& ptr) { reference_tokens.insert(reference_tokens.end(), ptr.reference_tokens.begin(), ptr.reference_tokens.end()); return *this; } /*! @brief append an unescaped reference token at the end of this JSON pointer @param[in] token reference token to append @return JSON pointer with @a token appended without escaping @a token @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} @complexity Amortized constant. @sa see @ref operator/=(const json_pointer&) to append a JSON pointer @sa see @ref operator/=(std::size_t) to append an array index @sa see @ref operator/(const json_pointer&, std::size_t) for a binary operator @since version 3.6.0 */ json_pointer& operator/=(std::string token) { push_back(std::move(token)); return *this; } /*! @brief append an array index at the end of this JSON pointer @param[in] array_idx array index to append @return JSON pointer with @a array_idx appended @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} @complexity Amortized constant. @sa see @ref operator/=(const json_pointer&) to append a JSON pointer @sa see @ref operator/=(std::string) to append a reference token @sa see @ref operator/(const json_pointer&, std::string) for a binary operator @since version 3.6.0 */ json_pointer& operator/=(std::size_t array_idx) { return *this /= std::to_string(array_idx); } /*! @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer @param[in] lhs JSON pointer @param[in] rhs JSON pointer @return a new JSON pointer with @a rhs appended to @a lhs @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} @complexity Linear in the length of @a lhs and @a rhs. @sa see @ref operator/=(const json_pointer&) to append a JSON pointer @since version 3.6.0 */ friend json_pointer operator/(const json_pointer& lhs, const json_pointer& rhs) { return json_pointer(lhs) /= rhs; } /*! @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer @param[in] ptr JSON pointer @param[in] token reference token @return a new JSON pointer with unescaped @a token appended to @a ptr @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} @complexity Linear in the length of @a ptr. @sa see @ref operator/=(std::string) to append a reference token @since version 3.6.0 */ friend json_pointer operator/(const json_pointer& ptr, std::string token) // NOLINT(performance-unnecessary-value-param) { return json_pointer(ptr) /= std::move(token); } /*! @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer @param[in] ptr JSON pointer @param[in] array_idx array index @return a new JSON pointer with @a array_idx appended to @a ptr @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} @complexity Linear in the length of @a ptr. @sa see @ref operator/=(std::size_t) to append an array index @since version 3.6.0 */ friend json_pointer operator/(const json_pointer& ptr, std::size_t array_idx) { return json_pointer(ptr) /= array_idx; } /*! @brief returns the parent of this JSON pointer @return parent of this JSON pointer; in case this JSON pointer is the root, the root itself is returned @complexity Linear in the length of the JSON pointer. @liveexample{The example shows the result of `parent_pointer` for different JSON Pointers.,json_pointer__parent_pointer} @since version 3.6.0 */ json_pointer parent_pointer() const { if (empty()) { return *this; } json_pointer res = *this; res.pop_back(); return res; } /*! @brief remove last reference token @pre not `empty()` @liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back} @complexity Constant. @throw out_of_range.405 if JSON pointer has no parent @since version 3.6.0 */ void pop_back() { if (JSON_HEDLEY_UNLIKELY(empty())) { JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); } reference_tokens.pop_back(); } /*! @brief return last reference token @pre not `empty()` @return last reference token @liveexample{The example shows the usage of `back`.,json_pointer__back} @complexity Constant. @throw out_of_range.405 if JSON pointer has no parent @since version 3.6.0 */ const std::string& back() const { if (JSON_HEDLEY_UNLIKELY(empty())) { JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); } return reference_tokens.back(); } /*! @brief append an unescaped token at the end of the reference pointer @param[in] token token to add @complexity Amortized constant. @liveexample{The example shows the result of `push_back` for different JSON Pointers.,json_pointer__push_back} @since version 3.6.0 */ void push_back(const std::string& token) { reference_tokens.push_back(token); } /// @copydoc push_back(const std::string&) void push_back(std::string&& token) { reference_tokens.push_back(std::move(token)); } /*! @brief return whether pointer points to the root document @return true iff the JSON pointer points to the root document @complexity Constant. @exceptionsafety No-throw guarantee: this function never throws exceptions. @liveexample{The example shows the result of `empty` for different JSON Pointers.,json_pointer__empty} @since version 3.6.0 */ bool empty() const noexcept { return reference_tokens.empty(); } private: /*! @param[in] s reference token to be converted into an array index @return integer representation of @a s @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index begins not with a digit @throw out_of_range.404 if string @a s could not be converted to an integer @throw out_of_range.410 if an array index exceeds size_type */ static typename BasicJsonType::size_type array_index(const std::string& s) { using size_type = typename BasicJsonType::size_type; // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) { JSON_THROW(detail::parse_error::create(106, 0, "array index '" + s + "' must not begin with '0'", BasicJsonType())); } // error condition (cf. RFC 6901, Sect. 4) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) { JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number", BasicJsonType())); } std::size_t processed_chars = 0; unsigned long long res = 0; // NOLINT(runtime/int) JSON_TRY { res = std::stoull(s, &processed_chars); } JSON_CATCH(std::out_of_range&) { JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType())); } // check if the string was completely read if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size())) { JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType())); } // only triggered on special platforms (like 32bit), see also // https://github.com/nlohmann/json/pull/2203 if (res >= static_cast((std::numeric_limits::max)())) // NOLINT(runtime/int) { JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type", BasicJsonType())); // LCOV_EXCL_LINE } return static_cast(res); } JSON_PRIVATE_UNLESS_TESTED: json_pointer top() const { if (JSON_HEDLEY_UNLIKELY(empty())) { JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); } json_pointer result = *this; result.reference_tokens = {reference_tokens[0]}; return result; } private: /*! @brief create and return a reference to the pointed to value @complexity Linear in the number of reference tokens. @throw parse_error.109 if array index is not a number @throw type_error.313 if value cannot be unflattened */ BasicJsonType& get_and_create(BasicJsonType& j) const { auto* result = &j; // in case no reference tokens exist, return a reference to the JSON value // j which will be overwritten by a primitive value for (const auto& reference_token : reference_tokens) { switch (result->type()) { case detail::value_t::null: { if (reference_token == "0") { // start a new array if reference token is 0 result = &result->operator[](0); } else { // start a new object otherwise result = &result->operator[](reference_token); } break; } case detail::value_t::object: { // create an entry in the object result = &result->operator[](reference_token); break; } case detail::value_t::array: { // create an entry in the array result = &result->operator[](array_index(reference_token)); break; } /* The following code is only reached if there exists a reference token _and_ the current value is primitive. In this case, we have an error situation, because primitive values may only occur as single value; that is, with an empty list of reference tokens. */ case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", j)); } } return *result; } /*! @brief return a reference to the pointed to value @note This version does not throw if a value is not present, but tries to create nested values instead. For instance, calling this function with pointer `"/this/that"` on a null value is equivalent to calling `operator[]("this").operator[]("that")` on that value, effectively changing the null value to an object. @param[in] ptr a JSON value @return reference to the JSON value pointed to by the JSON pointer @complexity Linear in the length of the JSON pointer. @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.404 if the JSON pointer can not be resolved */ BasicJsonType& get_unchecked(BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { // convert null values to arrays or objects before continuing if (ptr->is_null()) { // check if reference token is a number const bool nums = std::all_of(reference_token.begin(), reference_token.end(), [](const unsigned char x) { return std::isdigit(x); }); // change value to array for numbers or "-" or to object otherwise *ptr = (nums || reference_token == "-") ? detail::value_t::array : detail::value_t::object; } switch (ptr->type()) { case detail::value_t::object: { // use unchecked object access ptr = &ptr->operator[](reference_token); break; } case detail::value_t::array: { if (reference_token == "-") { // explicitly treat "-" as index beyond the end ptr = &ptr->operator[](ptr->m_value.array->size()); } else { // convert array index to number; unchecked access ptr = &ptr->operator[](array_index(reference_token)); } break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); } } return *ptr; } /*! @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.402 if the array index '-' is used @throw out_of_range.404 if the JSON pointer can not be resolved */ BasicJsonType& get_checked(BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { // note: at performs range check ptr = &ptr->at(reference_token); break; } case detail::value_t::array: { if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" always fails the range check JSON_THROW(detail::out_of_range::create(402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range", *ptr)); } // note: at performs range check ptr = &ptr->at(array_index(reference_token)); break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); } } return *ptr; } /*! @brief return a const reference to the pointed to value @param[in] ptr a JSON value @return const reference to the JSON value pointed to by the JSON pointer @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.402 if the array index '-' is used @throw out_of_range.404 if the JSON pointer can not be resolved */ const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { // use unchecked object access ptr = &ptr->operator[](reference_token); break; } case detail::value_t::array: { if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" cannot be used for const access JSON_THROW(detail::out_of_range::create(402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range", *ptr)); } // use unchecked array access ptr = &ptr->operator[](array_index(reference_token)); break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); } } return *ptr; } /*! @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.402 if the array index '-' is used @throw out_of_range.404 if the JSON pointer can not be resolved */ const BasicJsonType& get_checked(const BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { // note: at performs range check ptr = &ptr->at(reference_token); break; } case detail::value_t::array: { if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" always fails the range check JSON_THROW(detail::out_of_range::create(402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range", *ptr)); } // note: at performs range check ptr = &ptr->at(array_index(reference_token)); break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); } } return *ptr; } /*! @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number */ bool contains(const BasicJsonType* ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->type()) { case detail::value_t::object: { if (!ptr->contains(reference_token)) { // we did not find the key in the object return false; } ptr = &ptr->operator[](reference_token); break; } case detail::value_t::array: { if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" always fails the range check return false; } if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) { // invalid char return false; } if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) { if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) { // first char should be between '1' and '9' return false; } for (std::size_t i = 1; i < reference_token.size(); i++) { if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) { // other char should be between '0' and '9' return false; } } } const auto idx = array_index(reference_token); if (idx >= ptr->size()) { // index out of range return false; } ptr = &ptr->operator[](idx); break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: { // we do not expect primitive values if there is still a // reference token to process return false; } } } // no reference token left means we found a primitive value return true; } /*! @brief split the string input to reference tokens @note This function is only called by the json_pointer constructor. All exceptions below are documented there. @throw parse_error.107 if the pointer is not empty or begins with '/' @throw parse_error.108 if character '~' is not followed by '0' or '1' */ static std::vector split(const std::string& reference_string) { std::vector result; // special case: empty reference string -> no reference tokens if (reference_string.empty()) { return result; } // check if nonempty reference string begins with slash if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) { JSON_THROW(detail::parse_error::create(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'", BasicJsonType())); } // extract the reference tokens: // - slash: position of the last read slash (or end of string) // - start: position after the previous slash for ( // search for the first slash after the first character std::size_t slash = reference_string.find_first_of('/', 1), // set the beginning of the first reference token start = 1; // we can stop if start == 0 (if slash == std::string::npos) start != 0; // set the beginning of the next reference token // (will eventually be 0 if slash == std::string::npos) start = (slash == std::string::npos) ? 0 : slash + 1, // find next slash slash = reference_string.find_first_of('/', start)) { // use the text between the beginning of the reference token // (start) and the last slash (slash). auto reference_token = reference_string.substr(start, slash - start); // check reference tokens are properly escaped for (std::size_t pos = reference_token.find_first_of('~'); pos != std::string::npos; pos = reference_token.find_first_of('~', pos + 1)) { JSON_ASSERT(reference_token[pos] == '~'); // ~ must be followed by 0 or 1 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || (reference_token[pos + 1] != '0' && reference_token[pos + 1] != '1'))) { JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", BasicJsonType())); } } // finally, store the reference token detail::unescape(reference_token); result.push_back(reference_token); } return result; } private: /*! @param[in] reference_string the reference string to the current value @param[in] value the value to consider @param[in,out] result the result object to insert values to @note Empty objects or arrays are flattened to `null`. */ static void flatten(const std::string& reference_string, const BasicJsonType& value, BasicJsonType& result) { switch (value.type()) { case detail::value_t::array: { if (value.m_value.array->empty()) { // flatten empty array as null result[reference_string] = nullptr; } else { // iterate array and use index as reference string for (std::size_t i = 0; i < value.m_value.array->size(); ++i) { flatten(reference_string + "/" + std::to_string(i), value.m_value.array->operator[](i), result); } } break; } case detail::value_t::object: { if (value.m_value.object->empty()) { // flatten empty object as null result[reference_string] = nullptr; } else { // iterate object and use keys as reference string for (const auto& element : *value.m_value.object) { flatten(reference_string + "/" + detail::escape(element.first), element.second, result); } } break; } case detail::value_t::null: case detail::value_t::string: case detail::value_t::boolean: case detail::value_t::number_integer: case detail::value_t::number_unsigned: case detail::value_t::number_float: case detail::value_t::binary: case detail::value_t::discarded: default: { // add primitive value with its reference string result[reference_string] = value; break; } } } /*! @param[in] value flattened JSON @return unflattened JSON @throw parse_error.109 if array index is not a number @throw type_error.314 if value is not an object @throw type_error.315 if object values are not primitive @throw type_error.313 if value cannot be unflattened */ static BasicJsonType unflatten(const BasicJsonType& value) { if (JSON_HEDLEY_UNLIKELY(!value.is_object())) { JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", value)); } BasicJsonType result; // iterate the JSON object values for (const auto& element : *value.m_value.object) { if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) { JSON_THROW(detail::type_error::create(315, "values in object must be primitive", element.second)); } // assign value to reference pointed to by JSON pointer; Note that if // the JSON pointer is "" (i.e., points to the whole value), function // get_and_create returns a reference to result itself. An assignment // will then create a primitive value. json_pointer(element.first).get_and_create(result) = element.second; } return result; } /*! @brief compares two JSON pointers for equality @param[in] lhs JSON pointer to compare @param[in] rhs JSON pointer to compare @return whether @a lhs is equal to @a rhs @complexity Linear in the length of the JSON pointer @exceptionsafety No-throw guarantee: this function never throws exceptions. */ friend bool operator==(json_pointer const& lhs, json_pointer const& rhs) noexcept { return lhs.reference_tokens == rhs.reference_tokens; } /*! @brief compares two JSON pointers for inequality @param[in] lhs JSON pointer to compare @param[in] rhs JSON pointer to compare @return whether @a lhs is not equal @a rhs @complexity Linear in the length of the JSON pointer @exceptionsafety No-throw guarantee: this function never throws exceptions. */ friend bool operator!=(json_pointer const& lhs, json_pointer const& rhs) noexcept { return !(lhs == rhs); } /// the reference tokens std::vector reference_tokens; }; } // namespace nlohmann // #include #include #include // #include namespace nlohmann { namespace detail { template class json_ref { public: using value_type = BasicJsonType; json_ref(value_type&& value) : owned_value(std::move(value)) {} json_ref(const value_type& value) : value_ref(&value) {} json_ref(std::initializer_list init) : owned_value(init) {} template < class... Args, enable_if_t::value, int> = 0 > json_ref(Args && ... args) : owned_value(std::forward(args)...) {} // class should be movable only json_ref(json_ref&&) noexcept = default; json_ref(const json_ref&) = delete; json_ref& operator=(const json_ref&) = delete; json_ref& operator=(json_ref&&) = delete; ~json_ref() = default; value_type moved_or_copied() const { if (value_ref == nullptr) { return std::move(owned_value); } return *value_ref; } value_type const& operator*() const { return value_ref ? *value_ref : owned_value; } value_type const* operator->() const { return &** this; } private: mutable value_type owned_value = nullptr; value_type const* value_ref = nullptr; }; } // namespace detail } // namespace nlohmann // #include // #include // #include // #include // #include #include // reverse #include // array #include // isnan, isinf #include // uint8_t, uint16_t, uint32_t, uint64_t #include // memcpy #include // numeric_limits #include // string #include // move // #include // #include // #include #include // copy #include // size_t #include // back_inserter #include // shared_ptr, make_shared #include // basic_string #include // vector #ifndef JSON_NO_IO #include // streamsize #include // basic_ostream #endif // JSON_NO_IO // #include namespace nlohmann { namespace detail { /// abstract output adapter interface template struct output_adapter_protocol { virtual void write_character(CharType c) = 0; virtual void write_characters(const CharType* s, std::size_t length) = 0; virtual ~output_adapter_protocol() = default; output_adapter_protocol() = default; output_adapter_protocol(const output_adapter_protocol&) = default; output_adapter_protocol(output_adapter_protocol&&) noexcept = default; output_adapter_protocol& operator=(const output_adapter_protocol&) = default; output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default; }; /// a type to simplify interfaces template using output_adapter_t = std::shared_ptr>; /// output adapter for byte vectors template> class output_vector_adapter : public output_adapter_protocol { public: explicit output_vector_adapter(std::vector& vec) noexcept : v(vec) {} void write_character(CharType c) override { v.push_back(c); } JSON_HEDLEY_NON_NULL(2) void write_characters(const CharType* s, std::size_t length) override { std::copy(s, s + length, std::back_inserter(v)); } private: std::vector& v; }; #ifndef JSON_NO_IO /// output adapter for output streams template class output_stream_adapter : public output_adapter_protocol { public: explicit output_stream_adapter(std::basic_ostream& s) noexcept : stream(s) {} void write_character(CharType c) override { stream.put(c); } JSON_HEDLEY_NON_NULL(2) void write_characters(const CharType* s, std::size_t length) override { stream.write(s, static_cast(length)); } private: std::basic_ostream& stream; }; #endif // JSON_NO_IO /// output adapter for basic_string template> class output_string_adapter : public output_adapter_protocol { public: explicit output_string_adapter(StringType& s) noexcept : str(s) {} void write_character(CharType c) override { str.push_back(c); } JSON_HEDLEY_NON_NULL(2) void write_characters(const CharType* s, std::size_t length) override { str.append(s, length); } private: StringType& str; }; template> class output_adapter { public: template> output_adapter(std::vector& vec) : oa(std::make_shared>(vec)) {} #ifndef JSON_NO_IO output_adapter(std::basic_ostream& s) : oa(std::make_shared>(s)) {} #endif // JSON_NO_IO output_adapter(StringType& s) : oa(std::make_shared>(s)) {} operator output_adapter_t() { return oa; } private: output_adapter_t oa = nullptr; }; } // namespace detail } // namespace nlohmann namespace nlohmann { namespace detail { /////////////////// // binary writer // /////////////////// /*! @brief serialization to CBOR and MessagePack values */ template class binary_writer { using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; using number_float_t = typename BasicJsonType::number_float_t; public: /*! @brief create a binary writer @param[in] adapter output adapter to write to */ explicit binary_writer(output_adapter_t adapter) : oa(std::move(adapter)) { JSON_ASSERT(oa); } /*! @param[in] j JSON value to serialize @pre j.type() == value_t::object */ void write_bson(const BasicJsonType& j) { switch (j.type()) { case value_t::object: { write_bson_object(*j.m_value.object); break; } case value_t::null: case value_t::array: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()), j)); } } } /*! @param[in] j JSON value to serialize */ void write_cbor(const BasicJsonType& j) { switch (j.type()) { case value_t::null: { oa->write_character(to_char_type(0xF6)); break; } case value_t::boolean: { oa->write_character(j.m_value.boolean ? to_char_type(0xF5) : to_char_type(0xF4)); break; } case value_t::number_integer: { if (j.m_value.number_integer >= 0) { // CBOR does not differentiate between positive signed // integers and unsigned integers. Therefore, we used the // code from the value_t::number_unsigned case here. if (j.m_value.number_integer <= 0x17) { write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x18)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x19)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x1A)); write_number(static_cast(j.m_value.number_integer)); } else { oa->write_character(to_char_type(0x1B)); write_number(static_cast(j.m_value.number_integer)); } } else { // The conversions below encode the sign in the first // byte, and the value is converted to a positive number. const auto positive_number = -1 - j.m_value.number_integer; if (j.m_value.number_integer >= -24) { write_number(static_cast(0x20 + positive_number)); } else if (positive_number <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x38)); write_number(static_cast(positive_number)); } else if (positive_number <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x39)); write_number(static_cast(positive_number)); } else if (positive_number <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x3A)); write_number(static_cast(positive_number)); } else { oa->write_character(to_char_type(0x3B)); write_number(static_cast(positive_number)); } } break; } case value_t::number_unsigned: { if (j.m_value.number_unsigned <= 0x17) { write_number(static_cast(j.m_value.number_unsigned)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x18)); write_number(static_cast(j.m_value.number_unsigned)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x19)); write_number(static_cast(j.m_value.number_unsigned)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x1A)); write_number(static_cast(j.m_value.number_unsigned)); } else { oa->write_character(to_char_type(0x1B)); write_number(static_cast(j.m_value.number_unsigned)); } break; } case value_t::number_float: { if (std::isnan(j.m_value.number_float)) { // NaN is 0xf97e00 in CBOR oa->write_character(to_char_type(0xF9)); oa->write_character(to_char_type(0x7E)); oa->write_character(to_char_type(0x00)); } else if (std::isinf(j.m_value.number_float)) { // Infinity is 0xf97c00, -Infinity is 0xf9fc00 oa->write_character(to_char_type(0xf9)); oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); oa->write_character(to_char_type(0x00)); } else { write_compact_float(j.m_value.number_float, detail::input_format_t::cbor); } break; } case value_t::string: { // step 1: write control byte and the string length const auto N = j.m_value.string->size(); if (N <= 0x17) { write_number(static_cast(0x60 + N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x78)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x79)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x7A)); write_number(static_cast(N)); } // LCOV_EXCL_START else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x7B)); write_number(static_cast(N)); } // LCOV_EXCL_STOP // step 2: write the string oa->write_characters( reinterpret_cast(j.m_value.string->c_str()), j.m_value.string->size()); break; } case value_t::array: { // step 1: write control byte and the array size const auto N = j.m_value.array->size(); if (N <= 0x17) { write_number(static_cast(0x80 + N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x98)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x99)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x9A)); write_number(static_cast(N)); } // LCOV_EXCL_START else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x9B)); write_number(static_cast(N)); } // LCOV_EXCL_STOP // step 2: write each element for (const auto& el : *j.m_value.array) { write_cbor(el); } break; } case value_t::binary: { if (j.m_value.binary->has_subtype()) { if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) { write_number(static_cast(0xd8)); write_number(static_cast(j.m_value.binary->subtype())); } else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) { write_number(static_cast(0xd9)); write_number(static_cast(j.m_value.binary->subtype())); } else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) { write_number(static_cast(0xda)); write_number(static_cast(j.m_value.binary->subtype())); } else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) { write_number(static_cast(0xdb)); write_number(static_cast(j.m_value.binary->subtype())); } } // step 1: write control byte and the binary array size const auto N = j.m_value.binary->size(); if (N <= 0x17) { write_number(static_cast(0x40 + N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x58)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x59)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x5A)); write_number(static_cast(N)); } // LCOV_EXCL_START else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0x5B)); write_number(static_cast(N)); } // LCOV_EXCL_STOP // step 2: write each element oa->write_characters( reinterpret_cast(j.m_value.binary->data()), N); break; } case value_t::object: { // step 1: write control byte and the object size const auto N = j.m_value.object->size(); if (N <= 0x17) { write_number(static_cast(0xA0 + N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0xB8)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0xB9)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0xBA)); write_number(static_cast(N)); } // LCOV_EXCL_START else if (N <= (std::numeric_limits::max)()) { oa->write_character(to_char_type(0xBB)); write_number(static_cast(N)); } // LCOV_EXCL_STOP // step 2: write each element for (const auto& el : *j.m_value.object) { write_cbor(el.first); write_cbor(el.second); } break; } case value_t::discarded: default: break; } } /*! @param[in] j JSON value to serialize */ void write_msgpack(const BasicJsonType& j) { switch (j.type()) { case value_t::null: // nil { oa->write_character(to_char_type(0xC0)); break; } case value_t::boolean: // true and false { oa->write_character(j.m_value.boolean ? to_char_type(0xC3) : to_char_type(0xC2)); break; } case value_t::number_integer: { if (j.m_value.number_integer >= 0) { // MessagePack does not differentiate between positive // signed integers and unsigned integers. Therefore, we used // the code from the value_t::number_unsigned case here. if (j.m_value.number_unsigned < 128) { // positive fixnum write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 8 oa->write_character(to_char_type(0xCC)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 16 oa->write_character(to_char_type(0xCD)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 32 oa->write_character(to_char_type(0xCE)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 64 oa->write_character(to_char_type(0xCF)); write_number(static_cast(j.m_value.number_integer)); } } else { if (j.m_value.number_integer >= -32) { // negative fixnum write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer >= (std::numeric_limits::min)() && j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 8 oa->write_character(to_char_type(0xD0)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer >= (std::numeric_limits::min)() && j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 16 oa->write_character(to_char_type(0xD1)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer >= (std::numeric_limits::min)() && j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 32 oa->write_character(to_char_type(0xD2)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer >= (std::numeric_limits::min)() && j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 64 oa->write_character(to_char_type(0xD3)); write_number(static_cast(j.m_value.number_integer)); } } break; } case value_t::number_unsigned: { if (j.m_value.number_unsigned < 128) { // positive fixnum write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 8 oa->write_character(to_char_type(0xCC)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 16 oa->write_character(to_char_type(0xCD)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 32 oa->write_character(to_char_type(0xCE)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 64 oa->write_character(to_char_type(0xCF)); write_number(static_cast(j.m_value.number_integer)); } break; } case value_t::number_float: { write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack); break; } case value_t::string: { // step 1: write control byte and the string length const auto N = j.m_value.string->size(); if (N <= 31) { // fixstr write_number(static_cast(0xA0 | N)); } else if (N <= (std::numeric_limits::max)()) { // str 8 oa->write_character(to_char_type(0xD9)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { // str 16 oa->write_character(to_char_type(0xDA)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { // str 32 oa->write_character(to_char_type(0xDB)); write_number(static_cast(N)); } // step 2: write the string oa->write_characters( reinterpret_cast(j.m_value.string->c_str()), j.m_value.string->size()); break; } case value_t::array: { // step 1: write control byte and the array size const auto N = j.m_value.array->size(); if (N <= 15) { // fixarray write_number(static_cast(0x90 | N)); } else if (N <= (std::numeric_limits::max)()) { // array 16 oa->write_character(to_char_type(0xDC)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { // array 32 oa->write_character(to_char_type(0xDD)); write_number(static_cast(N)); } // step 2: write each element for (const auto& el : *j.m_value.array) { write_msgpack(el); } break; } case value_t::binary: { // step 0: determine if the binary type has a set subtype to // determine whether or not to use the ext or fixext types const bool use_ext = j.m_value.binary->has_subtype(); // step 1: write control byte and the byte string length const auto N = j.m_value.binary->size(); if (N <= (std::numeric_limits::max)()) { std::uint8_t output_type{}; bool fixed = true; if (use_ext) { switch (N) { case 1: output_type = 0xD4; // fixext 1 break; case 2: output_type = 0xD5; // fixext 2 break; case 4: output_type = 0xD6; // fixext 4 break; case 8: output_type = 0xD7; // fixext 8 break; case 16: output_type = 0xD8; // fixext 16 break; default: output_type = 0xC7; // ext 8 fixed = false; break; } } else { output_type = 0xC4; // bin 8 fixed = false; } oa->write_character(to_char_type(output_type)); if (!fixed) { write_number(static_cast(N)); } } else if (N <= (std::numeric_limits::max)()) { std::uint8_t output_type = use_ext ? 0xC8 // ext 16 : 0xC5; // bin 16 oa->write_character(to_char_type(output_type)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { std::uint8_t output_type = use_ext ? 0xC9 // ext 32 : 0xC6; // bin 32 oa->write_character(to_char_type(output_type)); write_number(static_cast(N)); } // step 1.5: if this is an ext type, write the subtype if (use_ext) { write_number(static_cast(j.m_value.binary->subtype())); } // step 2: write the byte string oa->write_characters( reinterpret_cast(j.m_value.binary->data()), N); break; } case value_t::object: { // step 1: write control byte and the object size const auto N = j.m_value.object->size(); if (N <= 15) { // fixmap write_number(static_cast(0x80 | (N & 0xF))); } else if (N <= (std::numeric_limits::max)()) { // map 16 oa->write_character(to_char_type(0xDE)); write_number(static_cast(N)); } else if (N <= (std::numeric_limits::max)()) { // map 32 oa->write_character(to_char_type(0xDF)); write_number(static_cast(N)); } // step 2: write each element for (const auto& el : *j.m_value.object) { write_msgpack(el.first); write_msgpack(el.second); } break; } case value_t::discarded: default: break; } } /*! @param[in] j JSON value to serialize @param[in] use_count whether to use '#' prefixes (optimized format) @param[in] use_type whether to use '$' prefixes (optimized format) @param[in] add_prefix whether prefixes need to be used for this value */ void write_ubjson(const BasicJsonType& j, const bool use_count, const bool use_type, const bool add_prefix = true) { switch (j.type()) { case value_t::null: { if (add_prefix) { oa->write_character(to_char_type('Z')); } break; } case value_t::boolean: { if (add_prefix) { oa->write_character(j.m_value.boolean ? to_char_type('T') : to_char_type('F')); } break; } case value_t::number_integer: { write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); break; } case value_t::number_unsigned: { write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); break; } case value_t::number_float: { write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); break; } case value_t::string: { if (add_prefix) { oa->write_character(to_char_type('S')); } write_number_with_ubjson_prefix(j.m_value.string->size(), true); oa->write_characters( reinterpret_cast(j.m_value.string->c_str()), j.m_value.string->size()); break; } case value_t::array: { if (add_prefix) { oa->write_character(to_char_type('[')); } bool prefix_required = true; if (use_type && !j.m_value.array->empty()) { JSON_ASSERT(use_count); const CharType first_prefix = ubjson_prefix(j.front()); const bool same_prefix = std::all_of(j.begin() + 1, j.end(), [this, first_prefix](const BasicJsonType & v) { return ubjson_prefix(v) == first_prefix; }); if (same_prefix) { prefix_required = false; oa->write_character(to_char_type('$')); oa->write_character(first_prefix); } } if (use_count) { oa->write_character(to_char_type('#')); write_number_with_ubjson_prefix(j.m_value.array->size(), true); } for (const auto& el : *j.m_value.array) { write_ubjson(el, use_count, use_type, prefix_required); } if (!use_count) { oa->write_character(to_char_type(']')); } break; } case value_t::binary: { if (add_prefix) { oa->write_character(to_char_type('[')); } if (use_type && !j.m_value.binary->empty()) { JSON_ASSERT(use_count); oa->write_character(to_char_type('$')); oa->write_character('U'); } if (use_count) { oa->write_character(to_char_type('#')); write_number_with_ubjson_prefix(j.m_value.binary->size(), true); } if (use_type) { oa->write_characters( reinterpret_cast(j.m_value.binary->data()), j.m_value.binary->size()); } else { for (size_t i = 0; i < j.m_value.binary->size(); ++i) { oa->write_character(to_char_type('U')); oa->write_character(j.m_value.binary->data()[i]); } } if (!use_count) { oa->write_character(to_char_type(']')); } break; } case value_t::object: { if (add_prefix) { oa->write_character(to_char_type('{')); } bool prefix_required = true; if (use_type && !j.m_value.object->empty()) { JSON_ASSERT(use_count); const CharType first_prefix = ubjson_prefix(j.front()); const bool same_prefix = std::all_of(j.begin(), j.end(), [this, first_prefix](const BasicJsonType & v) { return ubjson_prefix(v) == first_prefix; }); if (same_prefix) { prefix_required = false; oa->write_character(to_char_type('$')); oa->write_character(first_prefix); } } if (use_count) { oa->write_character(to_char_type('#')); write_number_with_ubjson_prefix(j.m_value.object->size(), true); } for (const auto& el : *j.m_value.object) { write_number_with_ubjson_prefix(el.first.size(), true); oa->write_characters( reinterpret_cast(el.first.c_str()), el.first.size()); write_ubjson(el.second, use_count, use_type, prefix_required); } if (!use_count) { oa->write_character(to_char_type('}')); } break; } case value_t::discarded: default: break; } } private: ////////// // BSON // ////////// /*! @return The size of a BSON document entry header, including the id marker and the entry name size (and its null-terminator). */ static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j) { const auto it = name.find(static_cast(0)); if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) { JSON_THROW(out_of_range::create(409, "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")", j)); static_cast(j); } return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; } /*! @brief Writes the given @a element_type and @a name to the output adapter */ void write_bson_entry_header(const string_t& name, const std::uint8_t element_type) { oa->write_character(to_char_type(element_type)); // boolean oa->write_characters( reinterpret_cast(name.c_str()), name.size() + 1u); } /*! @brief Writes a BSON element with key @a name and boolean value @a value */ void write_bson_boolean(const string_t& name, const bool value) { write_bson_entry_header(name, 0x08); oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00)); } /*! @brief Writes a BSON element with key @a name and double value @a value */ void write_bson_double(const string_t& name, const double value) { write_bson_entry_header(name, 0x01); write_number(value); } /*! @return The size of the BSON-encoded string in @a value */ static std::size_t calc_bson_string_size(const string_t& value) { return sizeof(std::int32_t) + value.size() + 1ul; } /*! @brief Writes a BSON element with key @a name and string value @a value */ void write_bson_string(const string_t& name, const string_t& value) { write_bson_entry_header(name, 0x02); write_number(static_cast(value.size() + 1ul)); oa->write_characters( reinterpret_cast(value.c_str()), value.size() + 1); } /*! @brief Writes a BSON element with key @a name and null value */ void write_bson_null(const string_t& name) { write_bson_entry_header(name, 0x0A); } /*! @return The size of the BSON-encoded integer @a value */ static std::size_t calc_bson_integer_size(const std::int64_t value) { return (std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)() ? sizeof(std::int32_t) : sizeof(std::int64_t); } /*! @brief Writes a BSON element with key @a name and integer @a value */ void write_bson_integer(const string_t& name, const std::int64_t value) { if ((std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)()) { write_bson_entry_header(name, 0x10); // int32 write_number(static_cast(value)); } else { write_bson_entry_header(name, 0x12); // int64 write_number(static_cast(value)); } } /*! @return The size of the BSON-encoded unsigned integer in @a j */ static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept { return (value <= static_cast((std::numeric_limits::max)())) ? sizeof(std::int32_t) : sizeof(std::int64_t); } /*! @brief Writes a BSON element with key @a name and unsigned @a value */ void write_bson_unsigned(const string_t& name, const BasicJsonType& j) { if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) { write_bson_entry_header(name, 0x10 /* int32 */); write_number(static_cast(j.m_value.number_unsigned)); } else if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) { write_bson_entry_header(name, 0x12 /* int64 */); write_number(static_cast(j.m_value.number_unsigned)); } else { JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(j.m_value.number_unsigned) + " cannot be represented by BSON as it does not fit int64", j)); } } /*! @brief Writes a BSON element with key @a name and object @a value */ void write_bson_object_entry(const string_t& name, const typename BasicJsonType::object_t& value) { write_bson_entry_header(name, 0x03); // object write_bson_object(value); } /*! @return The size of the BSON-encoded array @a value */ static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) { std::size_t array_index = 0ul; const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), std::size_t(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) { return result + calc_bson_element_size(std::to_string(array_index++), el); }); return sizeof(std::int32_t) + embedded_document_size + 1ul; } /*! @return The size of the BSON-encoded binary array @a value */ static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) { return sizeof(std::int32_t) + value.size() + 1ul; } /*! @brief Writes a BSON element with key @a name and array @a value */ void write_bson_array(const string_t& name, const typename BasicJsonType::array_t& value) { write_bson_entry_header(name, 0x04); // array write_number(static_cast(calc_bson_array_size(value))); std::size_t array_index = 0ul; for (const auto& el : value) { write_bson_element(std::to_string(array_index++), el); } oa->write_character(to_char_type(0x00)); } /*! @brief Writes a BSON element with key @a name and binary value @a value */ void write_bson_binary(const string_t& name, const binary_t& value) { write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); write_number(value.has_subtype() ? static_cast(value.subtype()) : std::uint8_t(0x00)); oa->write_characters(reinterpret_cast(value.data()), value.size()); } /*! @brief Calculates the size necessary to serialize the JSON value @a j with its @a name @return The calculated size for the BSON document entry for @a j with the given @a name. */ static std::size_t calc_bson_element_size(const string_t& name, const BasicJsonType& j) { const auto header_size = calc_bson_entry_header_size(name, j); switch (j.type()) { case value_t::object: return header_size + calc_bson_object_size(*j.m_value.object); case value_t::array: return header_size + calc_bson_array_size(*j.m_value.array); case value_t::binary: return header_size + calc_bson_binary_size(*j.m_value.binary); case value_t::boolean: return header_size + 1ul; case value_t::number_float: return header_size + 8ul; case value_t::number_integer: return header_size + calc_bson_integer_size(j.m_value.number_integer); case value_t::number_unsigned: return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned); case value_t::string: return header_size + calc_bson_string_size(*j.m_value.string); case value_t::null: return header_size + 0ul; // LCOV_EXCL_START case value_t::discarded: default: JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) return 0ul; // LCOV_EXCL_STOP } } /*! @brief Serializes the JSON value @a j to BSON and associates it with the key @a name. @param name The name to associate with the JSON entity @a j within the current BSON document */ void write_bson_element(const string_t& name, const BasicJsonType& j) { switch (j.type()) { case value_t::object: return write_bson_object_entry(name, *j.m_value.object); case value_t::array: return write_bson_array(name, *j.m_value.array); case value_t::binary: return write_bson_binary(name, *j.m_value.binary); case value_t::boolean: return write_bson_boolean(name, j.m_value.boolean); case value_t::number_float: return write_bson_double(name, j.m_value.number_float); case value_t::number_integer: return write_bson_integer(name, j.m_value.number_integer); case value_t::number_unsigned: return write_bson_unsigned(name, j); case value_t::string: return write_bson_string(name, *j.m_value.string); case value_t::null: return write_bson_null(name); // LCOV_EXCL_START case value_t::discarded: default: JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) return; // LCOV_EXCL_STOP } } /*! @brief Calculates the size of the BSON serialization of the given JSON-object @a j. @param[in] value JSON value to serialize @pre value.type() == value_t::object */ static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) { std::size_t document_size = std::accumulate(value.begin(), value.end(), std::size_t(0), [](size_t result, const typename BasicJsonType::object_t::value_type & el) { return result += calc_bson_element_size(el.first, el.second); }); return sizeof(std::int32_t) + document_size + 1ul; } /*! @param[in] value JSON value to serialize @pre value.type() == value_t::object */ void write_bson_object(const typename BasicJsonType::object_t& value) { write_number(static_cast(calc_bson_object_size(value))); for (const auto& el : value) { write_bson_element(el.first, el.second); } oa->write_character(to_char_type(0x00)); } ////////// // CBOR // ////////// static constexpr CharType get_cbor_float_prefix(float /*unused*/) { return to_char_type(0xFA); // Single-Precision Float } static constexpr CharType get_cbor_float_prefix(double /*unused*/) { return to_char_type(0xFB); // Double-Precision Float } ///////////// // MsgPack // ///////////// static constexpr CharType get_msgpack_float_prefix(float /*unused*/) { return to_char_type(0xCA); // float 32 } static constexpr CharType get_msgpack_float_prefix(double /*unused*/) { return to_char_type(0xCB); // float 64 } //////////// // UBJSON // //////////// // UBJSON: write number (floating point) template::value, int>::type = 0> void write_number_with_ubjson_prefix(const NumberType n, const bool add_prefix) { if (add_prefix) { oa->write_character(get_ubjson_float_prefix(n)); } write_number(n); } // UBJSON: write number (unsigned integer) template::value, int>::type = 0> void write_number_with_ubjson_prefix(const NumberType n, const bool add_prefix) { if (n <= static_cast((std::numeric_limits::max)())) { if (add_prefix) { oa->write_character(to_char_type('i')); // int8 } write_number(static_cast(n)); } else if (n <= (std::numeric_limits::max)()) { if (add_prefix) { oa->write_character(to_char_type('U')); // uint8 } write_number(static_cast(n)); } else if (n <= static_cast((std::numeric_limits::max)())) { if (add_prefix) { oa->write_character(to_char_type('I')); // int16 } write_number(static_cast(n)); } else if (n <= static_cast((std::numeric_limits::max)())) { if (add_prefix) { oa->write_character(to_char_type('l')); // int32 } write_number(static_cast(n)); } else if (n <= static_cast((std::numeric_limits::max)())) { if (add_prefix) { oa->write_character(to_char_type('L')); // int64 } write_number(static_cast(n)); } else { if (add_prefix) { oa->write_character(to_char_type('H')); // high-precision number } const auto number = BasicJsonType(n).dump(); write_number_with_ubjson_prefix(number.size(), true); for (std::size_t i = 0; i < number.size(); ++i) { oa->write_character(to_char_type(static_cast(number[i]))); } } } // UBJSON: write number (signed integer) template < typename NumberType, typename std::enable_if < std::is_signed::value&& !std::is_floating_point::value, int >::type = 0 > void write_number_with_ubjson_prefix(const NumberType n, const bool add_prefix) { if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) { if (add_prefix) { oa->write_character(to_char_type('i')); // int8 } write_number(static_cast(n)); } else if (static_cast((std::numeric_limits::min)()) <= n && n <= static_cast((std::numeric_limits::max)())) { if (add_prefix) { oa->write_character(to_char_type('U')); // uint8 } write_number(static_cast(n)); } else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) { if (add_prefix) { oa->write_character(to_char_type('I')); // int16 } write_number(static_cast(n)); } else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) { if (add_prefix) { oa->write_character(to_char_type('l')); // int32 } write_number(static_cast(n)); } else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) { if (add_prefix) { oa->write_character(to_char_type('L')); // int64 } write_number(static_cast(n)); } // LCOV_EXCL_START else { if (add_prefix) { oa->write_character(to_char_type('H')); // high-precision number } const auto number = BasicJsonType(n).dump(); write_number_with_ubjson_prefix(number.size(), true); for (std::size_t i = 0; i < number.size(); ++i) { oa->write_character(to_char_type(static_cast(number[i]))); } } // LCOV_EXCL_STOP } /*! @brief determine the type prefix of container values */ CharType ubjson_prefix(const BasicJsonType& j) const noexcept { switch (j.type()) { case value_t::null: return 'Z'; case value_t::boolean: return j.m_value.boolean ? 'T' : 'F'; case value_t::number_integer: { if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'i'; } if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'U'; } if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'I'; } if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'l'; } if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'L'; } // anything else is treated as high-precision number return 'H'; // LCOV_EXCL_LINE } case value_t::number_unsigned: { if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) { return 'i'; } if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) { return 'U'; } if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) { return 'I'; } if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) { return 'l'; } if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) { return 'L'; } // anything else is treated as high-precision number return 'H'; // LCOV_EXCL_LINE } case value_t::number_float: return get_ubjson_float_prefix(j.m_value.number_float); case value_t::string: return 'S'; case value_t::array: // fallthrough case value_t::binary: return '['; case value_t::object: return '{'; case value_t::discarded: default: // discarded values return 'N'; } } static constexpr CharType get_ubjson_float_prefix(float /*unused*/) { return 'd'; // float 32 } static constexpr CharType get_ubjson_float_prefix(double /*unused*/) { return 'D'; // float 64 } /////////////////////// // Utility functions // /////////////////////// /* @brief write a number to output input @param[in] n number of type @a NumberType @tparam NumberType the type of the number @tparam OutputIsLittleEndian Set to true if output data is required to be little endian @note This function needs to respect the system's endianess, because bytes in CBOR, MessagePack, and UBJSON are stored in network order (big endian) and therefore need reordering on little endian systems. */ template void write_number(const NumberType n) { // step 1: write number to array of length NumberType std::array vec{}; std::memcpy(vec.data(), &n, sizeof(NumberType)); // step 2: write array to output (with possible reordering) if (is_little_endian != OutputIsLittleEndian) { // reverse byte order prior to conversion if necessary std::reverse(vec.begin(), vec.end()); } oa->write_characters(vec.data(), sizeof(NumberType)); } void write_compact_float(const number_float_t n, detail::input_format_t format) { #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" #endif if (static_cast(n) >= static_cast(std::numeric_limits::lowest()) && static_cast(n) <= static_cast((std::numeric_limits::max)()) && static_cast(static_cast(n)) == static_cast(n)) { oa->write_character(format == detail::input_format_t::cbor ? get_cbor_float_prefix(static_cast(n)) : get_msgpack_float_prefix(static_cast(n))); write_number(static_cast(n)); } else { oa->write_character(format == detail::input_format_t::cbor ? get_cbor_float_prefix(n) : get_msgpack_float_prefix(n)); write_number(n); } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif } public: // The following to_char_type functions are implement the conversion // between uint8_t and CharType. In case CharType is not unsigned, // such a conversion is required to allow values greater than 128. // See for a discussion. template < typename C = CharType, enable_if_t < std::is_signed::value && std::is_signed::value > * = nullptr > static constexpr CharType to_char_type(std::uint8_t x) noexcept { return *reinterpret_cast(&x); } template < typename C = CharType, enable_if_t < std::is_signed::value && std::is_unsigned::value > * = nullptr > static CharType to_char_type(std::uint8_t x) noexcept { static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); static_assert(std::is_trivial::value, "CharType must be trivial"); CharType result; std::memcpy(&result, &x, sizeof(x)); return result; } template::value>* = nullptr> static constexpr CharType to_char_type(std::uint8_t x) noexcept { return x; } template < typename InputCharType, typename C = CharType, enable_if_t < std::is_signed::value && std::is_signed::value && std::is_same::type>::value > * = nullptr > static constexpr CharType to_char_type(InputCharType x) noexcept { return x; } private: /// whether we can assume little endianess const bool is_little_endian = little_endianess(); /// the output output_adapter_t oa = nullptr; }; } // namespace detail } // namespace nlohmann // #include // #include #include // reverse, remove, fill, find, none_of #include // array #include // localeconv, lconv #include // labs, isfinite, isnan, signbit #include // size_t, ptrdiff_t #include // uint8_t #include // snprintf #include // numeric_limits #include // string, char_traits #include // is_same #include // move // #include #include // array #include // signbit, isfinite #include // intN_t, uintN_t #include // memcpy, memmove #include // numeric_limits #include // conditional // #include namespace nlohmann { namespace detail { /*! @brief implements the Grisu2 algorithm for binary to decimal floating-point conversion. This implementation is a slightly modified version of the reference implementation which may be obtained from http://florian.loitsch.com/publications (bench.tar.gz). The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. For a detailed description of the algorithm see: [1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming Language Design and Implementation, PLDI 2010 [2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation, PLDI 1996 */ namespace dtoa_impl { template Target reinterpret_bits(const Source source) { static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); Target target; std::memcpy(&target, &source, sizeof(Source)); return target; } struct diyfp // f * 2^e { static constexpr int kPrecision = 64; // = q std::uint64_t f = 0; int e = 0; constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} /*! @brief returns x - y @pre x.e == y.e and x.f >= y.f */ static diyfp sub(const diyfp& x, const diyfp& y) noexcept { JSON_ASSERT(x.e == y.e); JSON_ASSERT(x.f >= y.f); return {x.f - y.f, x.e}; } /*! @brief returns x * y @note The result is rounded. (Only the upper q bits are returned.) */ static diyfp mul(const diyfp& x, const diyfp& y) noexcept { static_assert(kPrecision == 64, "internal error"); // Computes: // f = round((x.f * y.f) / 2^q) // e = x.e + y.e + q // Emulate the 64-bit * 64-bit multiplication: // // p = u * v // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) // // (Since Q might be larger than 2^32 - 1) // // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) // // (Q_hi + H does not overflow a 64-bit int) // // = p_lo + 2^64 p_hi const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; const std::uint64_t u_hi = x.f >> 32u; const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; const std::uint64_t v_hi = y.f >> 32u; const std::uint64_t p0 = u_lo * v_lo; const std::uint64_t p1 = u_lo * v_hi; const std::uint64_t p2 = u_hi * v_lo; const std::uint64_t p3 = u_hi * v_hi; const std::uint64_t p0_hi = p0 >> 32u; const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; const std::uint64_t p1_hi = p1 >> 32u; const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; const std::uint64_t p2_hi = p2 >> 32u; std::uint64_t Q = p0_hi + p1_lo + p2_lo; // The full product might now be computed as // // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) // p_lo = p0_lo + (Q << 32) // // But in this particular case here, the full p_lo is not required. // Effectively we only need to add the highest bit in p_lo to p_hi (and // Q_hi + 1 does not overflow). Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); return {h, x.e + y.e + 64}; } /*! @brief normalize x such that the significand is >= 2^(q-1) @pre x.f != 0 */ static diyfp normalize(diyfp x) noexcept { JSON_ASSERT(x.f != 0); while ((x.f >> 63u) == 0) { x.f <<= 1u; x.e--; } return x; } /*! @brief normalize x such that the result has the exponent E @pre e >= x.e and the upper e - x.e bits of x.f must be zero. */ static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept { const int delta = x.e - target_exponent; JSON_ASSERT(delta >= 0); JSON_ASSERT(((x.f << delta) >> delta) == x.f); return {x.f << delta, target_exponent}; } }; struct boundaries { diyfp w; diyfp minus; diyfp plus; }; /*! Compute the (normalized) diyfp representing the input number 'value' and its boundaries. @pre value must be finite and positive */ template boundaries compute_boundaries(FloatType value) { JSON_ASSERT(std::isfinite(value)); JSON_ASSERT(value > 0); // Convert the IEEE representation into a diyfp. // // If v is denormal: // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) // If v is normalized: // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) static_assert(std::numeric_limits::is_iec559, "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); constexpr int kMinExp = 1 - kBias; constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) using bits_type = typename std::conditional::type; const auto bits = static_cast(reinterpret_bits(value)); const std::uint64_t E = bits >> (kPrecision - 1); const std::uint64_t F = bits & (kHiddenBit - 1); const bool is_denormal = E == 0; const diyfp v = is_denormal ? diyfp(F, kMinExp) : diyfp(F + kHiddenBit, static_cast(E) - kBias); // Compute the boundaries m- and m+ of the floating-point value // v = f * 2^e. // // Determine v- and v+, the floating-point predecessor and successor if v, // respectively. // // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) // // v+ = v + 2^e // // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ // between m- and m+ round to v, regardless of how the input rounding // algorithm breaks ties. // // ---+-------------+-------------+-------------+-------------+--- (A) // v- m- v m+ v+ // // -----------------+------+------+-------------+-------------+--- (B) // v- m- v m+ v+ const bool lower_boundary_is_closer = F == 0 && E > 1; const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); const diyfp m_minus = lower_boundary_is_closer ? diyfp(4 * v.f - 1, v.e - 2) // (B) : diyfp(2 * v.f - 1, v.e - 1); // (A) // Determine the normalized w+ = m+. const diyfp w_plus = diyfp::normalize(m_plus); // Determine w- = m- such that e_(w-) = e_(w+). const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); return {diyfp::normalize(v), w_minus, w_plus}; } // Given normalized diyfp w, Grisu needs to find a (normalized) cached // power-of-ten c, such that the exponent of the product c * w = f * 2^e lies // within a certain range [alpha, gamma] (Definition 3.2 from [1]) // // alpha <= e = e_c + e_w + q <= gamma // // or // // f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q // <= f_c * f_w * 2^gamma // // Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies // // 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma // // or // // 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) // // The choice of (alpha,gamma) determines the size of the table and the form of // the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well // in practice: // // The idea is to cut the number c * w = f * 2^e into two parts, which can be // processed independently: An integral part p1, and a fractional part p2: // // f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e // = (f div 2^-e) + (f mod 2^-e) * 2^e // = p1 + p2 * 2^e // // The conversion of p1 into decimal form requires a series of divisions and // modulos by (a power of) 10. These operations are faster for 32-bit than for // 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be // achieved by choosing // // -e >= 32 or e <= -32 := gamma // // In order to convert the fractional part // // p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... // // into decimal form, the fraction is repeatedly multiplied by 10 and the digits // d[-i] are extracted in order: // // (10 * p2) div 2^-e = d[-1] // (10 * p2) mod 2^-e = d[-2] / 10^1 + ... // // The multiplication by 10 must not overflow. It is sufficient to choose // // 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. // // Since p2 = f mod 2^-e < 2^-e, // // -e <= 60 or e >= -60 := alpha constexpr int kAlpha = -60; constexpr int kGamma = -32; struct cached_power // c = f * 2^e ~= 10^k { std::uint64_t f; int e; int k; }; /*! For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c satisfies (Definition 3.2 from [1]) alpha <= e_c + e + q <= gamma. */ inline cached_power get_cached_power_for_binary_exponent(int e) { // Now // // alpha <= e_c + e + q <= gamma (1) // ==> f_c * 2^alpha <= c * 2^e * 2^q // // and since the c's are normalized, 2^(q-1) <= f_c, // // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) // ==> 2^(alpha - e - 1) <= c // // If c were an exact power of ten, i.e. c = 10^k, one may determine k as // // k = ceil( log_10( 2^(alpha - e - 1) ) ) // = ceil( (alpha - e - 1) * log_10(2) ) // // From the paper: // "In theory the result of the procedure could be wrong since c is rounded, // and the computation itself is approximated [...]. In practice, however, // this simple function is sufficient." // // For IEEE double precision floating-point numbers converted into // normalized diyfp's w = f * 2^e, with q = 64, // // e >= -1022 (min IEEE exponent) // -52 (p - 1) // -52 (p - 1, possibly normalize denormal IEEE numbers) // -11 (normalize the diyfp) // = -1137 // // and // // e <= +1023 (max IEEE exponent) // -52 (p - 1) // -11 (normalize the diyfp) // = 960 // // This binary exponent range [-1137,960] results in a decimal exponent // range [-307,324]. One does not need to store a cached power for each // k in this range. For each such k it suffices to find a cached power // such that the exponent of the product lies in [alpha,gamma]. // This implies that the difference of the decimal exponents of adjacent // table entries must be less than or equal to // // floor( (gamma - alpha) * log_10(2) ) = 8. // // (A smaller distance gamma-alpha would require a larger table.) // NB: // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. constexpr int kCachedPowersMinDecExp = -300; constexpr int kCachedPowersDecStep = 8; static constexpr std::array kCachedPowers = { { { 0xAB70FE17C79AC6CA, -1060, -300 }, { 0xFF77B1FCBEBCDC4F, -1034, -292 }, { 0xBE5691EF416BD60C, -1007, -284 }, { 0x8DD01FAD907FFC3C, -980, -276 }, { 0xD3515C2831559A83, -954, -268 }, { 0x9D71AC8FADA6C9B5, -927, -260 }, { 0xEA9C227723EE8BCB, -901, -252 }, { 0xAECC49914078536D, -874, -244 }, { 0x823C12795DB6CE57, -847, -236 }, { 0xC21094364DFB5637, -821, -228 }, { 0x9096EA6F3848984F, -794, -220 }, { 0xD77485CB25823AC7, -768, -212 }, { 0xA086CFCD97BF97F4, -741, -204 }, { 0xEF340A98172AACE5, -715, -196 }, { 0xB23867FB2A35B28E, -688, -188 }, { 0x84C8D4DFD2C63F3B, -661, -180 }, { 0xC5DD44271AD3CDBA, -635, -172 }, { 0x936B9FCEBB25C996, -608, -164 }, { 0xDBAC6C247D62A584, -582, -156 }, { 0xA3AB66580D5FDAF6, -555, -148 }, { 0xF3E2F893DEC3F126, -529, -140 }, { 0xB5B5ADA8AAFF80B8, -502, -132 }, { 0x87625F056C7C4A8B, -475, -124 }, { 0xC9BCFF6034C13053, -449, -116 }, { 0x964E858C91BA2655, -422, -108 }, { 0xDFF9772470297EBD, -396, -100 }, { 0xA6DFBD9FB8E5B88F, -369, -92 }, { 0xF8A95FCF88747D94, -343, -84 }, { 0xB94470938FA89BCF, -316, -76 }, { 0x8A08F0F8BF0F156B, -289, -68 }, { 0xCDB02555653131B6, -263, -60 }, { 0x993FE2C6D07B7FAC, -236, -52 }, { 0xE45C10C42A2B3B06, -210, -44 }, { 0xAA242499697392D3, -183, -36 }, { 0xFD87B5F28300CA0E, -157, -28 }, { 0xBCE5086492111AEB, -130, -20 }, { 0x8CBCCC096F5088CC, -103, -12 }, { 0xD1B71758E219652C, -77, -4 }, { 0x9C40000000000000, -50, 4 }, { 0xE8D4A51000000000, -24, 12 }, { 0xAD78EBC5AC620000, 3, 20 }, { 0x813F3978F8940984, 30, 28 }, { 0xC097CE7BC90715B3, 56, 36 }, { 0x8F7E32CE7BEA5C70, 83, 44 }, { 0xD5D238A4ABE98068, 109, 52 }, { 0x9F4F2726179A2245, 136, 60 }, { 0xED63A231D4C4FB27, 162, 68 }, { 0xB0DE65388CC8ADA8, 189, 76 }, { 0x83C7088E1AAB65DB, 216, 84 }, { 0xC45D1DF942711D9A, 242, 92 }, { 0x924D692CA61BE758, 269, 100 }, { 0xDA01EE641A708DEA, 295, 108 }, { 0xA26DA3999AEF774A, 322, 116 }, { 0xF209787BB47D6B85, 348, 124 }, { 0xB454E4A179DD1877, 375, 132 }, { 0x865B86925B9BC5C2, 402, 140 }, { 0xC83553C5C8965D3D, 428, 148 }, { 0x952AB45CFA97A0B3, 455, 156 }, { 0xDE469FBD99A05FE3, 481, 164 }, { 0xA59BC234DB398C25, 508, 172 }, { 0xF6C69A72A3989F5C, 534, 180 }, { 0xB7DCBF5354E9BECE, 561, 188 }, { 0x88FCF317F22241E2, 588, 196 }, { 0xCC20CE9BD35C78A5, 614, 204 }, { 0x98165AF37B2153DF, 641, 212 }, { 0xE2A0B5DC971F303A, 667, 220 }, { 0xA8D9D1535CE3B396, 694, 228 }, { 0xFB9B7CD9A4A7443C, 720, 236 }, { 0xBB764C4CA7A44410, 747, 244 }, { 0x8BAB8EEFB6409C1A, 774, 252 }, { 0xD01FEF10A657842C, 800, 260 }, { 0x9B10A4E5E9913129, 827, 268 }, { 0xE7109BFBA19C0C9D, 853, 276 }, { 0xAC2820D9623BF429, 880, 284 }, { 0x80444B5E7AA7CF85, 907, 292 }, { 0xBF21E44003ACDD2D, 933, 300 }, { 0x8E679C2F5E44FF8F, 960, 308 }, { 0xD433179D9C8CB841, 986, 316 }, { 0x9E19DB92B4E31BA9, 1013, 324 }, } }; // This computation gives exactly the same results for k as // k = ceil((kAlpha - e - 1) * 0.30102999566398114) // for |e| <= 1500, but doesn't require floating-point operations. // NB: log_10(2) ~= 78913 / 2^18 JSON_ASSERT(e >= -1500); JSON_ASSERT(e <= 1500); const int f = kAlpha - e - 1; const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; JSON_ASSERT(index >= 0); JSON_ASSERT(static_cast(index) < kCachedPowers.size()); const cached_power cached = kCachedPowers[static_cast(index)]; JSON_ASSERT(kAlpha <= cached.e + e + 64); JSON_ASSERT(kGamma >= cached.e + e + 64); return cached; } /*! For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. For n == 0, returns 1 and sets pow10 := 1. */ inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) { // LCOV_EXCL_START if (n >= 1000000000) { pow10 = 1000000000; return 10; } // LCOV_EXCL_STOP if (n >= 100000000) { pow10 = 100000000; return 9; } if (n >= 10000000) { pow10 = 10000000; return 8; } if (n >= 1000000) { pow10 = 1000000; return 7; } if (n >= 100000) { pow10 = 100000; return 6; } if (n >= 10000) { pow10 = 10000; return 5; } if (n >= 1000) { pow10 = 1000; return 4; } if (n >= 100) { pow10 = 100; return 3; } if (n >= 10) { pow10 = 10; return 2; } pow10 = 1; return 1; } inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, std::uint64_t rest, std::uint64_t ten_k) { JSON_ASSERT(len >= 1); JSON_ASSERT(dist <= delta); JSON_ASSERT(rest <= delta); JSON_ASSERT(ten_k > 0); // <--------------------------- delta ----> // <---- dist ---------> // --------------[------------------+-------------------]-------------- // M- w M+ // // ten_k // <------> // <---- rest ----> // --------------[------------------+----+--------------]-------------- // w V // = buf * 10^k // // ten_k represents a unit-in-the-last-place in the decimal representation // stored in buf. // Decrement buf by ten_k while this takes buf closer to w. // The tests are written in this order to avoid overflow in unsigned // integer arithmetic. while (rest < dist && delta - rest >= ten_k && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) { JSON_ASSERT(buf[len - 1] != '0'); buf[len - 1]--; rest += ten_k; } } /*! Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. M- and M+ must be normalized and share the same exponent -60 <= e <= -32. */ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, diyfp M_minus, diyfp w, diyfp M_plus) { static_assert(kAlpha >= -60, "internal error"); static_assert(kGamma <= -32, "internal error"); // Generates the digits (and the exponent) of a decimal floating-point // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. // // <--------------------------- delta ----> // <---- dist ---------> // --------------[------------------+-------------------]-------------- // M- w M+ // // Grisu2 generates the digits of M+ from left to right and stops as soon as // V is in [M-,M+]. JSON_ASSERT(M_plus.e >= kAlpha); JSON_ASSERT(M_plus.e <= kGamma); std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): // // M+ = f * 2^e // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e // = ((p1 ) * 2^-e + (p2 )) * 2^e // = p1 + p2 * 2^e const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e // 1) // // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] JSON_ASSERT(p1 > 0); std::uint32_t pow10{}; const int k = find_largest_pow10(p1, pow10); // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) // // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) // // M+ = p1 + p2 * 2^e // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e // = d[k-1] * 10^(k-1) + ( rest) * 2^e // // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) // // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] // // but stop as soon as // // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e int n = k; while (n > 0) { // Invariants: // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) // pow10 = 10^(n-1) <= p1 < 10^n // const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) // // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) // JSON_ASSERT(d <= 9); buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d // // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) // p1 = r; n--; // // M+ = buffer * 10^n + (p1 + p2 * 2^e) // pow10 = 10^n // // Now check if enough digits have been generated. // Compute // // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e // // Note: // Since rest and delta share the same exponent e, it suffices to // compare the significands. const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; if (rest <= delta) { // V = buffer * 10^n, with M- <= V <= M+. decimal_exponent += n; // We may now just stop. But instead look if the buffer could be // decremented to bring V closer to w. // // pow10 = 10^n is now 1 ulp in the decimal representation V. // The rounding procedure works with diyfp's with an implicit // exponent of e. // // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e // const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; grisu2_round(buffer, length, dist, delta, rest, ten_n); return; } pow10 /= 10; // // pow10 = 10^(n-1) <= p1 < 10^n // Invariants restored. } // 2) // // The digits of the integral part have been generated: // // M+ = d[k-1]...d[1]d[0] + p2 * 2^e // = buffer + p2 * 2^e // // Now generate the digits of the fractional part p2 * 2^e. // // Note: // No decimal point is generated: the exponent is adjusted instead. // // p2 actually represents the fraction // // p2 * 2^e // = p2 / 2^-e // = d[-1] / 10^1 + d[-2] / 10^2 + ... // // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) // // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) // // using // // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) // = ( d) * 2^-e + ( r) // // or // 10^m * p2 * 2^e = d + r * 2^e // // i.e. // // M+ = buffer + p2 * 2^e // = buffer + 10^-m * (d + r * 2^e) // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e // // and stop as soon as 10^-m * r * 2^e <= delta * 2^e JSON_ASSERT(p2 > delta); int m = 0; for (;;) { // Invariant: // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e // = buffer * 10^-m + 10^-m * (p2 ) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e // JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); p2 *= 10; const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e // // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e // JSON_ASSERT(d <= 9); buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d // // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e // p2 = r; m++; // // M+ = buffer * 10^-m + 10^-m * p2 * 2^e // Invariant restored. // Check if enough digits have been generated. // // 10^-m * p2 * 2^e <= delta * 2^e // p2 * 2^e <= 10^m * delta * 2^e // p2 <= 10^m * delta delta *= 10; dist *= 10; if (p2 <= delta) { break; } } // V = buffer * 10^-m, with M- <= V <= M+. decimal_exponent -= m; // 1 ulp in the decimal representation is now 10^-m. // Since delta and dist are now scaled by 10^m, we need to do the // same with ulp in order to keep the units in sync. // // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e // const std::uint64_t ten_m = one.f; grisu2_round(buffer, length, dist, delta, p2, ten_m); // By construction this algorithm generates the shortest possible decimal // number (Loitsch, Theorem 6.2) which rounds back to w. // For an input number of precision p, at least // // N = 1 + ceil(p * log_10(2)) // // decimal digits are sufficient to identify all binary floating-point // numbers (Matula, "In-and-Out conversions"). // This implies that the algorithm does not produce more than N decimal // digits. // // N = 17 for p = 53 (IEEE double precision) // N = 9 for p = 24 (IEEE single precision) } /*! v = buf * 10^decimal_exponent len is the length of the buffer (number of decimal digits) The buffer must be large enough, i.e. >= max_digits10. */ JSON_HEDLEY_NON_NULL(1) inline void grisu2(char* buf, int& len, int& decimal_exponent, diyfp m_minus, diyfp v, diyfp m_plus) { JSON_ASSERT(m_plus.e == m_minus.e); JSON_ASSERT(m_plus.e == v.e); // --------(-----------------------+-----------------------)-------- (A) // m- v m+ // // --------------------(-----------+-----------------------)-------- (B) // m- v m+ // // First scale v (and m- and m+) such that the exponent is in the range // [alpha, gamma]. const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] const diyfp w = diyfp::mul(v, c_minus_k); const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); // ----(---+---)---------------(---+---)---------------(---+---)---- // w- w w+ // = c*m- = c*v = c*m+ // // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and // w+ are now off by a small amount. // In fact: // // w - v * 10^k < 1 ulp // // To account for this inaccuracy, add resp. subtract 1 ulp. // // --------+---[---------------(---+---)---------------]---+-------- // w- M- w M+ w+ // // Now any number in [M-, M+] (bounds included) will round to w when input, // regardless of how the input rounding algorithm breaks ties. // // And digit_gen generates the shortest possible such number in [M-, M+]. // Note that this does not mean that Grisu2 always generates the shortest // possible number in the interval (m-, m+). const diyfp M_minus(w_minus.f + 1, w_minus.e); const diyfp M_plus (w_plus.f - 1, w_plus.e ); decimal_exponent = -cached.k; // = -(-k) = k grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); } /*! v = buf * 10^decimal_exponent len is the length of the buffer (number of decimal digits) The buffer must be large enough, i.e. >= max_digits10. */ template JSON_HEDLEY_NON_NULL(1) void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) { static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, "internal error: not enough precision"); JSON_ASSERT(std::isfinite(value)); JSON_ASSERT(value > 0); // If the neighbors (and boundaries) of 'value' are always computed for double-precision // numbers, all float's can be recovered using strtod (and strtof). However, the resulting // decimal representations are not exactly "short". // // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) // says "value is converted to a string as if by std::sprintf in the default ("C") locale" // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' // does. // On the other hand, the documentation for 'std::to_chars' requires that "parsing the // representation using the corresponding std::from_chars function recovers value exactly". That // indicates that single precision floating-point numbers should be recovered using // 'std::strtof'. // // NB: If the neighbors are computed for single-precision numbers, there is a single float // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision // value is off by 1 ulp. #if 0 const boundaries w = compute_boundaries(static_cast(value)); #else const boundaries w = compute_boundaries(value); #endif grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); } /*! @brief appends a decimal representation of e to buf @return a pointer to the element following the exponent. @pre -1000 < e < 1000 */ JSON_HEDLEY_NON_NULL(1) JSON_HEDLEY_RETURNS_NON_NULL inline char* append_exponent(char* buf, int e) { JSON_ASSERT(e > -1000); JSON_ASSERT(e < 1000); if (e < 0) { e = -e; *buf++ = '-'; } else { *buf++ = '+'; } auto k = static_cast(e); if (k < 10) { // Always print at least two digits in the exponent. // This is for compatibility with printf("%g"). *buf++ = '0'; *buf++ = static_cast('0' + k); } else if (k < 100) { *buf++ = static_cast('0' + k / 10); k %= 10; *buf++ = static_cast('0' + k); } else { *buf++ = static_cast('0' + k / 100); k %= 100; *buf++ = static_cast('0' + k / 10); k %= 10; *buf++ = static_cast('0' + k); } return buf; } /*! @brief prettify v = buf * 10^decimal_exponent If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point notation. Otherwise it will be printed in exponential notation. @pre min_exp < 0 @pre max_exp > 0 */ JSON_HEDLEY_NON_NULL(1) JSON_HEDLEY_RETURNS_NON_NULL inline char* format_buffer(char* buf, int len, int decimal_exponent, int min_exp, int max_exp) { JSON_ASSERT(min_exp < 0); JSON_ASSERT(max_exp > 0); const int k = len; const int n = len + decimal_exponent; // v = buf * 10^(n-k) // k is the length of the buffer (number of decimal digits) // n is the position of the decimal point relative to the start of the buffer. if (k <= n && n <= max_exp) { // digits[000] // len <= max_exp + 2 std::memset(buf + k, '0', static_cast(n) - static_cast(k)); // Make it look like a floating-point number (#362, #378) buf[n + 0] = '.'; buf[n + 1] = '0'; return buf + (static_cast(n) + 2); } if (0 < n && n <= max_exp) { // dig.its // len <= max_digits10 + 1 JSON_ASSERT(k > n); std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); buf[n] = '.'; return buf + (static_cast(k) + 1U); } if (min_exp < n && n <= 0) { // 0.[000]digits // len <= 2 + (-min_exp - 1) + max_digits10 std::memmove(buf + (2 + static_cast(-n)), buf, static_cast(k)); buf[0] = '0'; buf[1] = '.'; std::memset(buf + 2, '0', static_cast(-n)); return buf + (2U + static_cast(-n) + static_cast(k)); } if (k == 1) { // dE+123 // len <= 1 + 5 buf += 1; } else { // d.igitsE+123 // len <= max_digits10 + 1 + 5 std::memmove(buf + 2, buf + 1, static_cast(k) - 1); buf[1] = '.'; buf += 1 + static_cast(k); } *buf++ = 'e'; return append_exponent(buf, n - 1); } } // namespace dtoa_impl /*! @brief generates a decimal representation of the floating-point number value in [first, last). The format of the resulting decimal representation is similar to printf's %g format. Returns an iterator pointing past-the-end of the decimal representation. @note The input number must be finite, i.e. NaN's and Inf's are not supported. @note The buffer must be large enough. @note The result is NOT null-terminated. */ template JSON_HEDLEY_NON_NULL(1, 2) JSON_HEDLEY_RETURNS_NON_NULL char* to_chars(char* first, const char* last, FloatType value) { static_cast(last); // maybe unused - fix warning JSON_ASSERT(std::isfinite(value)); // Use signbit(value) instead of (value < 0) since signbit works for -0. if (std::signbit(value)) { value = -value; *first++ = '-'; } #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" #endif if (value == 0) // +-0 { *first++ = '0'; // Make it look like a floating-point number (#362, #378) *first++ = '.'; *first++ = '0'; return first; } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); // Compute v = buffer * 10^decimal_exponent. // The decimal digits are stored in the buffer, which needs to be interpreted // as an unsigned decimal integer. // len is the length of the buffer, i.e. the number of decimal digits. int len = 0; int decimal_exponent = 0; dtoa_impl::grisu2(first, len, decimal_exponent, value); JSON_ASSERT(len <= std::numeric_limits::max_digits10); // Format the buffer like printf("%.*g", prec, value) constexpr int kMinExp = -4; // Use digits10 here to increase compatibility with version 2. constexpr int kMaxExp = std::numeric_limits::digits10; JSON_ASSERT(last - first >= kMaxExp + 2); JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); } } // namespace detail } // namespace nlohmann // #include // #include // #include // #include // #include // #include namespace nlohmann { namespace detail { /////////////////// // serialization // /////////////////// /// how to treat decoding errors enum class error_handler_t { strict, ///< throw a type_error exception in case of invalid UTF-8 replace, ///< replace invalid UTF-8 sequences with U+FFFD ignore ///< ignore invalid UTF-8 sequences }; template class serializer { using string_t = typename BasicJsonType::string_t; using number_float_t = typename BasicJsonType::number_float_t; using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using binary_char_t = typename BasicJsonType::binary_t::value_type; static constexpr std::uint8_t UTF8_ACCEPT = 0; static constexpr std::uint8_t UTF8_REJECT = 1; public: /*! @param[in] s output stream to serialize to @param[in] ichar indentation character to use @param[in] error_handler_ how to react on decoding errors */ serializer(output_adapter_t s, const char ichar, error_handler_t error_handler_ = error_handler_t::strict) : o(std::move(s)) , loc(std::localeconv()) , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep))) , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point))) , indent_char(ichar) , indent_string(512, indent_char) , error_handler(error_handler_) {} // delete because of pointer members serializer(const serializer&) = delete; serializer& operator=(const serializer&) = delete; serializer(serializer&&) = delete; serializer& operator=(serializer&&) = delete; ~serializer() = default; /*! @brief internal implementation of the serialization function This function is called by the public member function dump and organizes the serialization internally. The indentation level is propagated as additional parameter. In case of arrays and objects, the function is called recursively. - strings and object keys are escaped using `escape_string()` - integer numbers are converted implicitly via `operator<<` - floating-point numbers are converted to a string using `"%g"` format - binary values are serialized as objects containing the subtype and the byte array @param[in] val value to serialize @param[in] pretty_print whether the output shall be pretty-printed @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters in the output are escaped with `\uXXXX` sequences, and the result consists of ASCII characters only. @param[in] indent_step the indent level @param[in] current_indent the current indent level (only used internally) */ void dump(const BasicJsonType& val, const bool pretty_print, const bool ensure_ascii, const unsigned int indent_step, const unsigned int current_indent = 0) { switch (val.m_type) { case value_t::object: { if (val.m_value.object->empty()) { o->write_characters("{}", 2); return; } if (pretty_print) { o->write_characters("{\n", 2); // variable to hold indentation for recursive calls const auto new_indent = current_indent + indent_step; if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) { indent_string.resize(indent_string.size() * 2, ' '); } // first n-1 elements auto i = val.m_value.object->cbegin(); for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) { o->write_characters(indent_string.c_str(), new_indent); o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\": ", 3); dump(i->second, true, ensure_ascii, indent_step, new_indent); o->write_characters(",\n", 2); } // last element JSON_ASSERT(i != val.m_value.object->cend()); JSON_ASSERT(std::next(i) == val.m_value.object->cend()); o->write_characters(indent_string.c_str(), new_indent); o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\": ", 3); dump(i->second, true, ensure_ascii, indent_step, new_indent); o->write_character('\n'); o->write_characters(indent_string.c_str(), current_indent); o->write_character('}'); } else { o->write_character('{'); // first n-1 elements auto i = val.m_value.object->cbegin(); for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) { o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\":", 2); dump(i->second, false, ensure_ascii, indent_step, current_indent); o->write_character(','); } // last element JSON_ASSERT(i != val.m_value.object->cend()); JSON_ASSERT(std::next(i) == val.m_value.object->cend()); o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\":", 2); dump(i->second, false, ensure_ascii, indent_step, current_indent); o->write_character('}'); } return; } case value_t::array: { if (val.m_value.array->empty()) { o->write_characters("[]", 2); return; } if (pretty_print) { o->write_characters("[\n", 2); // variable to hold indentation for recursive calls const auto new_indent = current_indent + indent_step; if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) { indent_string.resize(indent_string.size() * 2, ' '); } // first n-1 elements for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) { o->write_characters(indent_string.c_str(), new_indent); dump(*i, true, ensure_ascii, indent_step, new_indent); o->write_characters(",\n", 2); } // last element JSON_ASSERT(!val.m_value.array->empty()); o->write_characters(indent_string.c_str(), new_indent); dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); o->write_character('\n'); o->write_characters(indent_string.c_str(), current_indent); o->write_character(']'); } else { o->write_character('['); // first n-1 elements for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) { dump(*i, false, ensure_ascii, indent_step, current_indent); o->write_character(','); } // last element JSON_ASSERT(!val.m_value.array->empty()); dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); o->write_character(']'); } return; } case value_t::string: { o->write_character('\"'); dump_escaped(*val.m_value.string, ensure_ascii); o->write_character('\"'); return; } case value_t::binary: { if (pretty_print) { o->write_characters("{\n", 2); // variable to hold indentation for recursive calls const auto new_indent = current_indent + indent_step; if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) { indent_string.resize(indent_string.size() * 2, ' '); } o->write_characters(indent_string.c_str(), new_indent); o->write_characters("\"bytes\": [", 10); if (!val.m_value.binary->empty()) { for (auto i = val.m_value.binary->cbegin(); i != val.m_value.binary->cend() - 1; ++i) { dump_integer(*i); o->write_characters(", ", 2); } dump_integer(val.m_value.binary->back()); } o->write_characters("],\n", 3); o->write_characters(indent_string.c_str(), new_indent); o->write_characters("\"subtype\": ", 11); if (val.m_value.binary->has_subtype()) { dump_integer(val.m_value.binary->subtype()); } else { o->write_characters("null", 4); } o->write_character('\n'); o->write_characters(indent_string.c_str(), current_indent); o->write_character('}'); } else { o->write_characters("{\"bytes\":[", 10); if (!val.m_value.binary->empty()) { for (auto i = val.m_value.binary->cbegin(); i != val.m_value.binary->cend() - 1; ++i) { dump_integer(*i); o->write_character(','); } dump_integer(val.m_value.binary->back()); } o->write_characters("],\"subtype\":", 12); if (val.m_value.binary->has_subtype()) { dump_integer(val.m_value.binary->subtype()); o->write_character('}'); } else { o->write_characters("null}", 5); } } return; } case value_t::boolean: { if (val.m_value.boolean) { o->write_characters("true", 4); } else { o->write_characters("false", 5); } return; } case value_t::number_integer: { dump_integer(val.m_value.number_integer); return; } case value_t::number_unsigned: { dump_integer(val.m_value.number_unsigned); return; } case value_t::number_float: { dump_float(val.m_value.number_float); return; } case value_t::discarded: { o->write_characters("", 11); return; } case value_t::null: { o->write_characters("null", 4); return; } default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } } JSON_PRIVATE_UNLESS_TESTED: /*! @brief dump escaped string Escape a string by replacing certain special characters by a sequence of an escape character (backslash) and another character and other control characters by a sequence of "\u" followed by a four-digit hex representation. The escaped string is written to output stream @a o. @param[in] s the string to escape @param[in] ensure_ascii whether to escape non-ASCII characters with \uXXXX sequences @complexity Linear in the length of string @a s. */ void dump_escaped(const string_t& s, const bool ensure_ascii) { std::uint32_t codepoint{}; std::uint8_t state = UTF8_ACCEPT; std::size_t bytes = 0; // number of bytes written to string_buffer // number of bytes written at the point of the last valid byte std::size_t bytes_after_last_accept = 0; std::size_t undumped_chars = 0; for (std::size_t i = 0; i < s.size(); ++i) { const auto byte = static_cast(s[i]); switch (decode(state, codepoint, byte)) { case UTF8_ACCEPT: // decode found a new code point { switch (codepoint) { case 0x08: // backspace { string_buffer[bytes++] = '\\'; string_buffer[bytes++] = 'b'; break; } case 0x09: // horizontal tab { string_buffer[bytes++] = '\\'; string_buffer[bytes++] = 't'; break; } case 0x0A: // newline { string_buffer[bytes++] = '\\'; string_buffer[bytes++] = 'n'; break; } case 0x0C: // formfeed { string_buffer[bytes++] = '\\'; string_buffer[bytes++] = 'f'; break; } case 0x0D: // carriage return { string_buffer[bytes++] = '\\'; string_buffer[bytes++] = 'r'; break; } case 0x22: // quotation mark { string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\"'; break; } case 0x5C: // reverse solidus { string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\\'; break; } default: { // escape control characters (0x00..0x1F) or, if // ensure_ascii parameter is used, non-ASCII characters if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F))) { if (codepoint <= 0xFFFF) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", static_cast(codepoint)); bytes += 6; } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", static_cast(0xD7C0u + (codepoint >> 10u)), static_cast(0xDC00u + (codepoint & 0x3FFu))); bytes += 12; } } else { // copy byte to buffer (all previous bytes // been copied have in default case above) string_buffer[bytes++] = s[i]; } break; } } // write buffer and reset index; there must be 13 bytes // left, as this is the maximal number of bytes to be // written ("\uxxxx\uxxxx\0") for one code point if (string_buffer.size() - bytes < 13) { o->write_characters(string_buffer.data(), bytes); bytes = 0; } // remember the byte position of this accept bytes_after_last_accept = bytes; undumped_chars = 0; break; } case UTF8_REJECT: // decode found invalid UTF-8 byte { switch (error_handler) { case error_handler_t::strict: { std::string sn(9, '\0'); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) (std::snprintf)(&sn[0], sn.size(), "%.2X", byte); JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn, BasicJsonType())); } case error_handler_t::ignore: case error_handler_t::replace: { // in case we saw this character the first time, we // would like to read it again, because the byte // may be OK for itself, but just not OK for the // previous sequence if (undumped_chars > 0) { --i; } // reset length buffer to the last accepted index; // thus removing/ignoring the invalid characters bytes = bytes_after_last_accept; if (error_handler == error_handler_t::replace) { // add a replacement character if (ensure_ascii) { string_buffer[bytes++] = '\\'; string_buffer[bytes++] = 'u'; string_buffer[bytes++] = 'f'; string_buffer[bytes++] = 'f'; string_buffer[bytes++] = 'f'; string_buffer[bytes++] = 'd'; } else { string_buffer[bytes++] = detail::binary_writer::to_char_type('\xEF'); string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBF'); string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBD'); } // write buffer and reset index; there must be 13 bytes // left, as this is the maximal number of bytes to be // written ("\uxxxx\uxxxx\0") for one code point if (string_buffer.size() - bytes < 13) { o->write_characters(string_buffer.data(), bytes); bytes = 0; } bytes_after_last_accept = bytes; } undumped_chars = 0; // continue processing the string state = UTF8_ACCEPT; break; } default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } break; } default: // decode found yet incomplete multi-byte code point { if (!ensure_ascii) { // code point will not be escaped - copy byte to buffer string_buffer[bytes++] = s[i]; } ++undumped_chars; break; } } } // we finished processing the string if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT)) { // write buffer if (bytes > 0) { o->write_characters(string_buffer.data(), bytes); } } else { // we finish reading, but do not accept: string was incomplete switch (error_handler) { case error_handler_t::strict: { std::string sn(9, '\0'); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast(s.back())); JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn, BasicJsonType())); } case error_handler_t::ignore: { // write all accepted bytes o->write_characters(string_buffer.data(), bytes_after_last_accept); break; } case error_handler_t::replace: { // write all accepted bytes o->write_characters(string_buffer.data(), bytes_after_last_accept); // add a replacement character if (ensure_ascii) { o->write_characters("\\ufffd", 6); } else { o->write_characters("\xEF\xBF\xBD", 3); } break; } default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } } } private: /*! @brief count digits Count the number of decimal (base 10) digits for an input unsigned integer. @param[in] x unsigned integer number to count its digits @return number of decimal digits */ inline unsigned int count_digits(number_unsigned_t x) noexcept { unsigned int n_digits = 1; for (;;) { if (x < 10) { return n_digits; } if (x < 100) { return n_digits + 1; } if (x < 1000) { return n_digits + 2; } if (x < 10000) { return n_digits + 3; } x = x / 10000u; n_digits += 4; } } /*! @brief dump an integer Dump a given integer to output stream @a o. Works internally with @a number_buffer. @param[in] x integer number (signed or unsigned) to dump @tparam NumberType either @a number_integer_t or @a number_unsigned_t */ template < typename NumberType, detail::enable_if_t < std::is_integral::value || std::is_same::value || std::is_same::value || std::is_same::value, int > = 0 > void dump_integer(NumberType x) { static constexpr std::array, 100> digits_to_99 { { {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, } }; // special case for "0" if (x == 0) { o->write_character('0'); return; } // use a pointer to fill the buffer auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) const bool is_negative = std::is_signed::value && !(x >= 0); // see issue #755 number_unsigned_t abs_value; unsigned int n_chars{}; if (is_negative) { *buffer_ptr = '-'; abs_value = remove_sign(static_cast(x)); // account one more byte for the minus sign n_chars = 1 + count_digits(abs_value); } else { abs_value = static_cast(x); n_chars = count_digits(abs_value); } // spare 1 byte for '\0' JSON_ASSERT(n_chars < number_buffer.size() - 1); // jump to the end to generate the string from backward // so we later avoid reversing the result buffer_ptr += n_chars; // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu // See: https://www.youtube.com/watch?v=o4-CwDo2zpg while (abs_value >= 100) { const auto digits_index = static_cast((abs_value % 100)); abs_value /= 100; *(--buffer_ptr) = digits_to_99[digits_index][1]; *(--buffer_ptr) = digits_to_99[digits_index][0]; } if (abs_value >= 10) { const auto digits_index = static_cast(abs_value); *(--buffer_ptr) = digits_to_99[digits_index][1]; *(--buffer_ptr) = digits_to_99[digits_index][0]; } else { *(--buffer_ptr) = static_cast('0' + abs_value); } o->write_characters(number_buffer.data(), n_chars); } /*! @brief dump a floating-point number Dump a given floating-point number to output stream @a o. Works internally with @a number_buffer. @param[in] x floating-point number to dump */ void dump_float(number_float_t x) { // NaN / inf if (!std::isfinite(x)) { o->write_characters("null", 4); return; } // If number_float_t is an IEEE-754 single or double precision number, // use the Grisu2 algorithm to produce short numbers which are // guaranteed to round-trip, using strtof and strtod, resp. // // NB: The test below works if == . static constexpr bool is_ieee_single_or_double = (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 24 && std::numeric_limits::max_exponent == 128) || (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 53 && std::numeric_limits::max_exponent == 1024); dump_float(x, std::integral_constant()); } void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) { auto* begin = number_buffer.data(); auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); o->write_characters(begin, static_cast(end - begin)); } void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) { // get number of digits for a float -> text -> float round-trip static constexpr auto d = std::numeric_limits::max_digits10; // the actual conversion // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); // negative value indicates an error JSON_ASSERT(len > 0); // check if buffer was large enough JSON_ASSERT(static_cast(len) < number_buffer.size()); // erase thousands separator if (thousands_sep != '\0') { // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); std::fill(end, number_buffer.end(), '\0'); JSON_ASSERT((end - number_buffer.begin()) <= len); len = (end - number_buffer.begin()); } // convert decimal point to '.' if (decimal_point != '\0' && decimal_point != '.') { // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081 const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); if (dec_pos != number_buffer.end()) { *dec_pos = '.'; } } o->write_characters(number_buffer.data(), static_cast(len)); // determine if need to append ".0" const bool value_is_int_like = std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, [](char c) { return c == '.' || c == 'e'; }); if (value_is_int_like) { o->write_characters(".0", 2); } } /*! @brief check whether a string is UTF-8 encoded The function checks each byte of a string whether it is UTF-8 encoded. The result of the check is stored in the @a state parameter. The function must be called initially with state 0 (accept). State 1 means the string must be rejected, because the current byte is not allowed. If the string is completely processed, but the state is non-zero, the string ended prematurely; that is, the last byte indicated more bytes should have followed. @param[in,out] state the state of the decoding @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) @param[in] byte next byte to decode @return new state @note The function has been edited: a std::array is used. @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ */ static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept { static const std::array utf8d = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 } }; JSON_ASSERT(byte < utf8d.size()); const std::uint8_t type = utf8d[byte]; codep = (state != UTF8_ACCEPT) ? (byte & 0x3fu) | (codep << 6u) : (0xFFu >> type) & (byte); std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); JSON_ASSERT(index < 400); state = utf8d[index]; return state; } /* * Overload to make the compiler happy while it is instantiating * dump_integer for number_unsigned_t. * Must never be called. */ number_unsigned_t remove_sign(number_unsigned_t x) { JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE return x; // LCOV_EXCL_LINE } /* * Helper function for dump_integer * * This function takes a negative signed integer and returns its absolute * value as unsigned integer. The plus/minus shuffling is necessary as we can * not directly remove the sign of an arbitrary signed integer as the * absolute values of INT_MIN and INT_MAX are usually not the same. See * #1708 for details. */ inline number_unsigned_t remove_sign(number_integer_t x) noexcept { JSON_ASSERT(x < 0 && x < (std::numeric_limits::max)()); // NOLINT(misc-redundant-expression) return static_cast(-(x + 1)) + 1; } private: /// the output of the serializer output_adapter_t o = nullptr; /// a (hopefully) large enough character buffer std::array number_buffer{{}}; /// the locale const std::lconv* loc = nullptr; /// the locale's thousand separator character const char thousands_sep = '\0'; /// the locale's decimal point character const char decimal_point = '\0'; /// string buffer std::array string_buffer{{}}; /// the indentation character const char indent_char; /// the indentation string string_t indent_string; /// error_handler how to react on decoding errors const error_handler_t error_handler; }; } // namespace detail } // namespace nlohmann // #include // #include // #include #include // less #include // initializer_list #include // input_iterator_tag, iterator_traits #include // allocator #include // for out_of_range #include // enable_if, is_convertible #include // pair #include // vector // #include namespace nlohmann { /// ordered_map: a minimal map-like container that preserves insertion order /// for use within nlohmann::basic_json template , class Allocator = std::allocator>> struct ordered_map : std::vector, Allocator> { using key_type = Key; using mapped_type = T; using Container = std::vector, Allocator>; using typename Container::iterator; using typename Container::const_iterator; using typename Container::size_type; using typename Container::value_type; // Explicit constructors instead of `using Container::Container` // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} template ordered_map(It first, It last, const Allocator& alloc = Allocator()) : Container{first, last, alloc} {} ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) : Container{init, alloc} {} std::pair emplace(const key_type& key, T&& t) { for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == key) { return {it, false}; } } Container::emplace_back(key, t); return {--this->end(), true}; } T& operator[](const Key& key) { return emplace(key, T{}).first->second; } const T& operator[](const Key& key) const { return at(key); } T& at(const Key& key) { for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == key) { return it->second; } } JSON_THROW(std::out_of_range("key not found")); } const T& at(const Key& key) const { for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == key) { return it->second; } } JSON_THROW(std::out_of_range("key not found")); } size_type erase(const Key& key) { for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == key) { // Since we cannot move const Keys, re-construct them in place for (auto next = it; ++next != this->end(); ++it) { it->~value_type(); // Destroy but keep allocation new (&*it) value_type{std::move(*next)}; } Container::pop_back(); return 1; } } return 0; } iterator erase(iterator pos) { auto it = pos; // Since we cannot move const Keys, re-construct them in place for (auto next = it; ++next != this->end(); ++it) { it->~value_type(); // Destroy but keep allocation new (&*it) value_type{std::move(*next)}; } Container::pop_back(); return pos; } size_type count(const Key& key) const { for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == key) { return 1; } } return 0; } iterator find(const Key& key) { for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == key) { return it; } } return Container::end(); } const_iterator find(const Key& key) const { for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == key) { return it; } } return Container::end(); } std::pair insert( value_type&& value ) { return emplace(value.first, std::move(value.second)); } std::pair insert( const value_type& value ) { for (auto it = this->begin(); it != this->end(); ++it) { if (it->first == value.first) { return {it, false}; } } Container::push_back(value); return {--this->end(), true}; } template using require_input_iter = typename std::enable_if::iterator_category, std::input_iterator_tag>::value>::type; template> void insert(InputIt first, InputIt last) { for (auto it = first; it != last; ++it) { insert(*it); } } }; } // namespace nlohmann #if defined(JSON_HAS_CPP_17) #include #endif /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @since version 1.0.0 */ namespace nlohmann { /*! @brief a class to store JSON values @tparam ObjectType type for JSON objects (`std::map` by default; will be used in @ref object_t) @tparam ArrayType type for JSON arrays (`std::vector` by default; will be used in @ref array_t) @tparam StringType type for JSON strings and object keys (`std::string` by default; will be used in @ref string_t) @tparam BooleanType type for JSON booleans (`bool` by default; will be used in @ref boolean_t) @tparam NumberIntegerType type for JSON integer numbers (`int64_t` by default; will be used in @ref number_integer_t) @tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by default; will be used in @ref number_unsigned_t) @tparam NumberFloatType type for JSON floating-point numbers (`double` by default; will be used in @ref number_float_t) @tparam BinaryType type for packed binary data for compatibility with binary serialization formats (`std::vector` by default; will be used in @ref binary_t) @tparam AllocatorType type of the allocator to use (`std::allocator` by default) @tparam JSONSerializer the serializer to resolve internal calls to `to_json()` and `from_json()` (@ref adl_serializer by default) @requirement The class satisfies the following concept requirements: - Basic - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible): JSON values can be default constructed. The result will be a JSON null value. - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible): A JSON value can be constructed from an rvalue argument. - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible): A JSON value can be copy-constructed from an lvalue expression. - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable): A JSON value van be assigned from an rvalue argument. - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable): A JSON value can be copy-assigned from an lvalue expression. - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible): JSON values can be destructed. - Layout - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType): JSON values have [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout): All non-static data members are private and standard layout types, the class has no virtual functions or (virtual) base classes. - Library-wide - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable): JSON values can be compared with `==`, see @ref operator==(const_reference,const_reference). - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable): JSON values can be compared with `<`, see @ref operator<(const_reference,const_reference). - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable): Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of other compatible types, using unqualified function call @ref swap(). - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer): JSON values can be compared against `std::nullptr_t` objects which are used to model the `null` value. - Container - [Container](https://en.cppreference.com/w/cpp/named_req/Container): JSON values can be used like STL containers and provide iterator access. - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer); JSON values can be used like STL containers and provide reverse iterator access. @invariant The member variables @a m_value and @a m_type have the following relationship: - If `m_type == value_t::object`, then `m_value.object != nullptr`. - If `m_type == value_t::array`, then `m_value.array != nullptr`. - If `m_type == value_t::string`, then `m_value.string != nullptr`. The invariants are checked by member function assert_invariant(). @internal @note ObjectType trick from https://stackoverflow.com/a/9860911 @endinternal @see [RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc8259) @since version 1.0.0 @nosubgrouping */ NLOHMANN_BASIC_JSON_TPL_DECLARATION class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { private: template friend struct detail::external_constructor; friend ::nlohmann::json_pointer; template friend class ::nlohmann::detail::parser; friend ::nlohmann::detail::serializer; template friend class ::nlohmann::detail::iter_impl; template friend class ::nlohmann::detail::binary_writer; template friend class ::nlohmann::detail::binary_reader; template friend class ::nlohmann::detail::json_sax_dom_parser; template friend class ::nlohmann::detail::json_sax_dom_callback_parser; friend class ::nlohmann::detail::exception; /// workaround type for MSVC using basic_json_t = NLOHMANN_BASIC_JSON_TPL; JSON_PRIVATE_UNLESS_TESTED: // convenience aliases for types residing in namespace detail; using lexer = ::nlohmann::detail::lexer_base; template static ::nlohmann::detail::parser parser( InputAdapterType adapter, detail::parser_callback_tcb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false ) { return ::nlohmann::detail::parser(std::move(adapter), std::move(cb), allow_exceptions, ignore_comments); } private: using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; template using internal_iterator = ::nlohmann::detail::internal_iterator; template using iter_impl = ::nlohmann::detail::iter_impl; template using iteration_proxy = ::nlohmann::detail::iteration_proxy; template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; template using output_adapter_t = ::nlohmann::detail::output_adapter_t; template using binary_reader = ::nlohmann::detail::binary_reader; template using binary_writer = ::nlohmann::detail::binary_writer; JSON_PRIVATE_UNLESS_TESTED: using serializer = ::nlohmann::detail::serializer; public: using value_t = detail::value_t; /// JSON Pointer, see @ref nlohmann::json_pointer using json_pointer = ::nlohmann::json_pointer; template using json_serializer = JSONSerializer; /// how to treat decoding errors using error_handler_t = detail::error_handler_t; /// how to treat CBOR tags using cbor_tag_handler_t = detail::cbor_tag_handler_t; /// helper type for initializer lists of basic_json values using initializer_list_t = std::initializer_list>; using input_format_t = detail::input_format_t; /// SAX interface type, see @ref nlohmann::json_sax using json_sax_t = json_sax; //////////////// // exceptions // //////////////// /// @name exceptions /// Classes to implement user-defined exceptions. /// @{ /// @copydoc detail::exception using exception = detail::exception; /// @copydoc detail::parse_error using parse_error = detail::parse_error; /// @copydoc detail::invalid_iterator using invalid_iterator = detail::invalid_iterator; /// @copydoc detail::type_error using type_error = detail::type_error; /// @copydoc detail::out_of_range using out_of_range = detail::out_of_range; /// @copydoc detail::other_error using other_error = detail::other_error; /// @} ///////////////////// // container types // ///////////////////// /// @name container types /// The canonic container types to use @ref basic_json like any other STL /// container. /// @{ /// the type of elements in a basic_json container using value_type = basic_json; /// the type of an element reference using reference = value_type&; /// the type of an element const reference using const_reference = const value_type&; /// a type to represent differences between iterators using difference_type = std::ptrdiff_t; /// a type to represent container sizes using size_type = std::size_t; /// the allocator type using allocator_type = AllocatorType; /// the type of an element pointer using pointer = typename std::allocator_traits::pointer; /// the type of an element const pointer using const_pointer = typename std::allocator_traits::const_pointer; /// an iterator for a basic_json container using iterator = iter_impl; /// a const iterator for a basic_json container using const_iterator = iter_impl; /// a reverse iterator for a basic_json container using reverse_iterator = json_reverse_iterator; /// a const reverse iterator for a basic_json container using const_reverse_iterator = json_reverse_iterator; /// @} /*! @brief returns the allocator associated with the container */ static allocator_type get_allocator() { return allocator_type(); } /*! @brief returns version information on the library This function returns a JSON object with information about the library, including the version number and information on the platform and compiler. @return JSON object holding version information key | description ----------- | --------------- `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). `copyright` | The copyright line for the library as string. `name` | The name of the library as string. `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. `url` | The URL of the project as string. `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). @liveexample{The following code shows an example output of the `meta()` function.,meta} @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @complexity Constant. @since 2.1.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json meta() { basic_json result; result["copyright"] = "(C) 2013-2021 Niels Lohmann"; result["name"] = "JSON for Modern C++"; result["url"] = "https://github.com/nlohmann/json"; result["version"]["string"] = std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + std::to_string(NLOHMANN_JSON_VERSION_PATCH); result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; #ifdef _WIN32 result["platform"] = "win32"; #elif defined __linux__ result["platform"] = "linux"; #elif defined __APPLE__ result["platform"] = "apple"; #elif defined __unix__ result["platform"] = "unix"; #else result["platform"] = "unknown"; #endif #if defined(__ICC) || defined(__INTEL_COMPILER) result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; #elif defined(__clang__) result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; #elif defined(__GNUC__) || defined(__GNUG__) result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; #elif defined(__HP_cc) || defined(__HP_aCC) result["compiler"] = "hp" #elif defined(__IBMCPP__) result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; #elif defined(_MSC_VER) result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; #elif defined(__PGI) result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; #elif defined(__SUNPRO_CC) result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; #else result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; #endif #ifdef __cplusplus result["compiler"]["c++"] = std::to_string(__cplusplus); #else result["compiler"]["c++"] = "unknown"; #endif return result; } /////////////////////////// // JSON value data types // /////////////////////////// /// @name JSON value data types /// The data types to store a JSON value. These types are derived from /// the template arguments passed to class @ref basic_json. /// @{ #if defined(JSON_HAS_CPP_14) // Use transparent comparator if possible, combined with perfect forwarding // on find() and count() calls prevents unnecessary string construction. using object_comparator_t = std::less<>; #else using object_comparator_t = std::less; #endif /*! @brief a type for an object [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON objects as follows: > An object is an unordered collection of zero or more name/value pairs, > where a name is a string and a value is a string, number, boolean, null, > object, or array. To store objects in C++, a type is defined by the template parameters described below. @tparam ObjectType the container to store objects (e.g., `std::map` or `std::unordered_map`) @tparam StringType the type of the keys or names (e.g., `std::string`). The comparison function `std::less` is used to order elements inside the container. @tparam AllocatorType the allocator to use for objects (e.g., `std::allocator`) #### Default type With the default values for @a ObjectType (`std::map`), @a StringType (`std::string`), and @a AllocatorType (`std::allocator`), the default value for @a object_t is: @code {.cpp} std::map< std::string, // key_type basic_json, // value_type std::less, // key_compare std::allocator> // allocator_type > @endcode #### Behavior The choice of @a object_t influences the behavior of the JSON class. With the default type, objects have the following behavior: - When all names are unique, objects will be interoperable in the sense that all software implementations receiving that object will agree on the name-value mappings. - When the names within an object are not unique, it is unspecified which one of the values for a given key will be chosen. For instance, `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or `{"key": 2}`. - Internally, name/value pairs are stored in lexicographical order of the names. Objects will also be serialized (see @ref dump) in this order. For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored and serialized as `{"a": 2, "b": 1}`. - When comparing objects, the order of the name/value pairs is irrelevant. This makes objects interoperable in the sense that they will not be affected by these differences. For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be treated as equal. #### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the maximum depth of nesting. In this class, the object's limit of nesting is not explicitly constrained. However, a maximum depth of nesting may be introduced by the compiler or runtime environment. A theoretical limit can be queried by calling the @ref max_size function of a JSON object. #### Storage Objects are stored as pointers in a @ref basic_json type. That is, for any access to object values, a pointer of type `object_t*` must be dereferenced. @sa see @ref array_t -- type for an array value @since version 1.0.0 @note The order name/value pairs are added to the object is *not* preserved by the library. Therefore, iterating an object may return name/value pairs in a different order than they were originally stored. In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default. Please note this behavior conforms to [RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON objects. */ using object_t = ObjectType>>; /*! @brief a type for an array [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON arrays as follows: > An array is an ordered sequence of zero or more values. To store objects in C++, a type is defined by the template parameters explained below. @tparam ArrayType container type to store arrays (e.g., `std::vector` or `std::list`) @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) #### Default type With the default values for @a ArrayType (`std::vector`) and @a AllocatorType (`std::allocator`), the default value for @a array_t is: @code {.cpp} std::vector< basic_json, // value_type std::allocator // allocator_type > @endcode #### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the maximum depth of nesting. In this class, the array's limit of nesting is not explicitly constrained. However, a maximum depth of nesting may be introduced by the compiler or runtime environment. A theoretical limit can be queried by calling the @ref max_size function of a JSON array. #### Storage Arrays are stored as pointers in a @ref basic_json type. That is, for any access to array values, a pointer of type `array_t*` must be dereferenced. @sa see @ref object_t -- type for an object value @since version 1.0.0 */ using array_t = ArrayType>; /*! @brief a type for a string [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON strings as follows: > A string is a sequence of zero or more Unicode characters. To store objects in C++, a type is defined by the template parameter described below. Unicode values are split by the JSON class into byte-sized characters during deserialization. @tparam StringType the container to store strings (e.g., `std::string`). Note this container is used for keys/names in objects, see @ref object_t. #### Default type With the default values for @a StringType (`std::string`), the default value for @a string_t is: @code {.cpp} std::string @endcode #### Encoding Strings are stored in UTF-8 encoding. Therefore, functions like `std::string::size()` or `std::string::length()` return the number of bytes in the string rather than the number of characters or glyphs. #### String comparison [RFC 8259](https://tools.ietf.org/html/rfc8259) states: > Software implementations are typically required to test names of object > members for equality. Implementations that transform the textual > representation into sequences of Unicode code units and then perform the > comparison numerically, code unit by code unit, are interoperable in the > sense that implementations will agree in all cases on equality or > inequality of two strings. For example, implementations that compare > strings with escaped characters unconverted may incorrectly find that > `"a\\b"` and `"a\u005Cb"` are not equal. This implementation is interoperable as it does compare strings code unit by code unit. #### Storage String values are stored as pointers in a @ref basic_json type. That is, for any access to string values, a pointer of type `string_t*` must be dereferenced. @since version 1.0.0 */ using string_t = StringType; /*! @brief a type for a boolean [RFC 8259](https://tools.ietf.org/html/rfc8259) implicitly describes a boolean as a type which differentiates the two literals `true` and `false`. To store objects in C++, a type is defined by the template parameter @a BooleanType which chooses the type to use. #### Default type With the default values for @a BooleanType (`bool`), the default value for @a boolean_t is: @code {.cpp} bool @endcode #### Storage Boolean values are stored directly inside a @ref basic_json type. @since version 1.0.0 */ using boolean_t = BooleanType; /*! @brief a type for a number (integer) [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows: > The representation of numbers is similar to that used in most > programming languages. A number is represented in base 10 using decimal > digits. It contains an integer component that may be prefixed with an > optional minus sign, which may be followed by a fraction part and/or an > exponent part. Leading zeros are not allowed. (...) Numeric values that > cannot be represented in the grammar below (such as Infinity and NaN) > are not permitted. This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different types, @ref number_integer_t, @ref number_unsigned_t and @ref number_float_t are used. To store integer numbers in C++, a type is defined by the template parameter @a NumberIntegerType which chooses the type to use. #### Default type With the default values for @a NumberIntegerType (`int64_t`), the default value for @a number_integer_t is: @code {.cpp} int64_t @endcode #### Default behavior - The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in integer literals lead to an interpretation as octal number. Internally, the value will be stored as decimal number. For instance, the C++ integer literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. #### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the range and precision of numbers. When the default type is used, the maximal integer number that can be stored is `9223372036854775807` (INT64_MAX) and the minimal integer number that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will be automatically be stored as @ref number_unsigned_t or @ref number_float_t. [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: > Note that when such software is used, numbers that are integers and are > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense > that implementations will agree exactly on their numeric values. As this range is a subrange of the exactly supported range [INT64_MIN, INT64_MAX], this class's integer type is interoperable. #### Storage Integer number values are stored directly inside a @ref basic_json type. @sa see @ref number_float_t -- type for number values (floating-point) @sa see @ref number_unsigned_t -- type for number values (unsigned integer) @since version 1.0.0 */ using number_integer_t = NumberIntegerType; /*! @brief a type for a number (unsigned) [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows: > The representation of numbers is similar to that used in most > programming languages. A number is represented in base 10 using decimal > digits. It contains an integer component that may be prefixed with an > optional minus sign, which may be followed by a fraction part and/or an > exponent part. Leading zeros are not allowed. (...) Numeric values that > cannot be represented in the grammar below (such as Infinity and NaN) > are not permitted. This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different types, @ref number_integer_t, @ref number_unsigned_t and @ref number_float_t are used. To store unsigned integer numbers in C++, a type is defined by the template parameter @a NumberUnsignedType which chooses the type to use. #### Default type With the default values for @a NumberUnsignedType (`uint64_t`), the default value for @a number_unsigned_t is: @code {.cpp} uint64_t @endcode #### Default behavior - The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in integer literals lead to an interpretation as octal number. Internally, the value will be stored as decimal number. For instance, the C++ integer literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. #### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the range and precision of numbers. When the default type is used, the maximal integer number that can be stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number that can be stored is `0`. Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will be automatically be stored as @ref number_integer_t or @ref number_float_t. [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: > Note that when such software is used, numbers that are integers and are > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense > that implementations will agree exactly on their numeric values. As this range is a subrange (when considered in conjunction with the number_integer_t type) of the exactly supported range [0, UINT64_MAX], this class's integer type is interoperable. #### Storage Integer number values are stored directly inside a @ref basic_json type. @sa see @ref number_float_t -- type for number values (floating-point) @sa see @ref number_integer_t -- type for number values (integer) @since version 2.0.0 */ using number_unsigned_t = NumberUnsignedType; /*! @brief a type for a number (floating-point) [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows: > The representation of numbers is similar to that used in most > programming languages. A number is represented in base 10 using decimal > digits. It contains an integer component that may be prefixed with an > optional minus sign, which may be followed by a fraction part and/or an > exponent part. Leading zeros are not allowed. (...) Numeric values that > cannot be represented in the grammar below (such as Infinity and NaN) > are not permitted. This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different types, @ref number_integer_t, @ref number_unsigned_t and @ref number_float_t are used. To store floating-point numbers in C++, a type is defined by the template parameter @a NumberFloatType which chooses the type to use. #### Default type With the default values for @a NumberFloatType (`double`), the default value for @a number_float_t is: @code {.cpp} double @endcode #### Default behavior - The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in floating-point literals will be ignored. Internally, the value will be stored as decimal number. For instance, the C++ floating-point literal `01.2` will be serialized to `1.2`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. #### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) states: > This specification allows implementations to set limits on the range and > precision of numbers accepted. Since software that implements IEEE > 754-2008 binary64 (double precision) numbers is generally available and > widely used, good interoperability can be achieved by implementations > that expect no more precision or range than these provide, in the sense > that implementations will approximate JSON numbers within the expected > precision. This implementation does exactly follow this approach, as it uses double precision floating-point numbers. Note values smaller than `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` will be stored as NaN internally and be serialized to `null`. #### Storage Floating-point number values are stored directly inside a @ref basic_json type. @sa see @ref number_integer_t -- type for number values (integer) @sa see @ref number_unsigned_t -- type for number values (unsigned integer) @since version 1.0.0 */ using number_float_t = NumberFloatType; /*! @brief a type for a packed binary type This type is a type designed to carry binary data that appears in various serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and BSON's generic binary subtype. This type is NOT a part of standard JSON and exists solely for compatibility with these binary types. As such, it is simply defined as an ordered sequence of zero or more byte values. Additionally, as an implementation detail, the subtype of the binary data is carried around as a `std::uint8_t`, which is compatible with both of the binary data formats that use binary subtyping, (though the specific numbering is incompatible with each other, and it is up to the user to translate between them). [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type as: > Major type 2: a byte string. The string's length in bytes is represented > following the rules for positive integers (major type 0). [MessagePack's documentation on the bin type family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family) describes this type as: > Bin format family stores an byte array in 2, 3, or 5 bytes of extra bytes > in addition to the size of the byte array. [BSON's specifications](http://bsonspec.org/spec.html) describe several binary types; however, this type is intended to represent the generic binary type which has the description: > Generic binary subtype - This is the most commonly used binary subtype and > should be the 'default' for drivers and tools. None of these impose any limitations on the internal representation other than the basic unit of storage be some type of array whose parts are decomposable into bytes. The default representation of this binary format is a `std::vector`, which is a very common way to represent a byte array in modern C++. #### Default type The default values for @a BinaryType is `std::vector` #### Storage Binary Arrays are stored as pointers in a @ref basic_json type. That is, for any access to array values, a pointer of the type `binary_t*` must be dereferenced. #### Notes on subtypes - CBOR - Binary values are represented as byte strings. Subtypes are serialized as tagged values. - MessagePack - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The subtype is then added as singed 8-bit integer. - If no subtype is given, the bin family (bin8, bin16, bin32) is used. - BSON - If a subtype is given, it is used and added as unsigned 8-bit integer. - If no subtype is given, the generic binary subtype 0x00 is used. @sa see @ref binary -- create a binary array @since version 3.8.0 */ using binary_t = nlohmann::byte_container_with_subtype; /// @} private: /// helper for exception-safe object creation template JSON_HEDLEY_RETURNS_NON_NULL static T* create(Args&& ... args) { AllocatorType alloc; using AllocatorTraits = std::allocator_traits>; auto deleter = [&](T * obj) { AllocatorTraits::deallocate(alloc, obj, 1); }; std::unique_ptr obj(AllocatorTraits::allocate(alloc, 1), deleter); AllocatorTraits::construct(alloc, obj.get(), std::forward(args)...); JSON_ASSERT(obj != nullptr); return obj.release(); } //////////////////////// // JSON value storage // //////////////////////// JSON_PRIVATE_UNLESS_TESTED: /*! @brief a JSON value The actual storage for a JSON value of the @ref basic_json class. This union combines the different storage types for the JSON value types defined in @ref value_t. JSON type | value_t type | used type --------- | --------------- | ------------------------ object | object | pointer to @ref object_t array | array | pointer to @ref array_t string | string | pointer to @ref string_t boolean | boolean | @ref boolean_t number | number_integer | @ref number_integer_t number | number_unsigned | @ref number_unsigned_t number | number_float | @ref number_float_t binary | binary | pointer to @ref binary_t null | null | *no value is stored* @note Variable-length types (objects, arrays, and strings) are stored as pointers. The size of the union should not exceed 64 bits if the default value types are used. @since version 1.0.0 */ union json_value { /// object (stored with pointer to save storage) object_t* object; /// array (stored with pointer to save storage) array_t* array; /// string (stored with pointer to save storage) string_t* string; /// binary (stored with pointer to save storage) binary_t* binary; /// boolean boolean_t boolean; /// number (integer) number_integer_t number_integer; /// number (unsigned integer) number_unsigned_t number_unsigned; /// number (floating-point) number_float_t number_float; /// default constructor (for null values) json_value() = default; /// constructor for booleans json_value(boolean_t v) noexcept : boolean(v) {} /// constructor for numbers (integer) json_value(number_integer_t v) noexcept : number_integer(v) {} /// constructor for numbers (unsigned) json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} /// constructor for numbers (floating-point) json_value(number_float_t v) noexcept : number_float(v) {} /// constructor for empty values of a given type json_value(value_t t) { switch (t) { case value_t::object: { object = create(); break; } case value_t::array: { array = create(); break; } case value_t::string: { string = create(""); break; } case value_t::binary: { binary = create(); break; } case value_t::boolean: { boolean = boolean_t(false); break; } case value_t::number_integer: { number_integer = number_integer_t(0); break; } case value_t::number_unsigned: { number_unsigned = number_unsigned_t(0); break; } case value_t::number_float: { number_float = number_float_t(0.0); break; } case value_t::null: { object = nullptr; // silence warning, see #821 break; } case value_t::discarded: default: { object = nullptr; // silence warning, see #821 if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) { JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.10.4", basic_json())); // LCOV_EXCL_LINE } break; } } } /// constructor for strings json_value(const string_t& value) { string = create(value); } /// constructor for rvalue strings json_value(string_t&& value) { string = create(std::move(value)); } /// constructor for objects json_value(const object_t& value) { object = create(value); } /// constructor for rvalue objects json_value(object_t&& value) { object = create(std::move(value)); } /// constructor for arrays json_value(const array_t& value) { array = create(value); } /// constructor for rvalue arrays json_value(array_t&& value) { array = create(std::move(value)); } /// constructor for binary arrays json_value(const typename binary_t::container_type& value) { binary = create(value); } /// constructor for rvalue binary arrays json_value(typename binary_t::container_type&& value) { binary = create(std::move(value)); } /// constructor for binary arrays (internal type) json_value(const binary_t& value) { binary = create(value); } /// constructor for rvalue binary arrays (internal type) json_value(binary_t&& value) { binary = create(std::move(value)); } void destroy(value_t t) { if (t == value_t::array || t == value_t::object) { // flatten the current json_value to a heap-allocated stack std::vector stack; // move the top-level items to stack if (t == value_t::array) { stack.reserve(array->size()); std::move(array->begin(), array->end(), std::back_inserter(stack)); } else { stack.reserve(object->size()); for (auto&& it : *object) { stack.push_back(std::move(it.second)); } } while (!stack.empty()) { // move the last item to local variable to be processed basic_json current_item(std::move(stack.back())); stack.pop_back(); // if current_item is array/object, move // its children to the stack to be processed later if (current_item.is_array()) { std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack)); current_item.m_value.array->clear(); } else if (current_item.is_object()) { for (auto&& it : *current_item.m_value.object) { stack.push_back(std::move(it.second)); } current_item.m_value.object->clear(); } // it's now safe that current_item get destructed // since it doesn't have any children } } switch (t) { case value_t::object: { AllocatorType alloc; std::allocator_traits::destroy(alloc, object); std::allocator_traits::deallocate(alloc, object, 1); break; } case value_t::array: { AllocatorType alloc; std::allocator_traits::destroy(alloc, array); std::allocator_traits::deallocate(alloc, array, 1); break; } case value_t::string: { AllocatorType alloc; std::allocator_traits::destroy(alloc, string); std::allocator_traits::deallocate(alloc, string, 1); break; } case value_t::binary: { AllocatorType alloc; std::allocator_traits::destroy(alloc, binary); std::allocator_traits::deallocate(alloc, binary, 1); break; } case value_t::null: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::discarded: default: { break; } } } }; private: /*! @brief checks the class invariants This function asserts the class invariants. It needs to be called at the end of every constructor to make sure that created objects respect the invariant. Furthermore, it has to be called each time the type of a JSON value is changed, because the invariant expresses a relationship between @a m_type and @a m_value. Furthermore, the parent relation is checked for arrays and objects: If @a check_parents true and the value is an array or object, then the container's elements must have the current value as parent. @param[in] check_parents whether the parent relation should be checked. The value is true by default and should only be set to false during destruction of objects when the invariant does not need to hold. */ void assert_invariant(bool check_parents = true) const noexcept { JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr); JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr); JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr); JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr); #if JSON_DIAGNOSTICS JSON_TRY { // cppcheck-suppress assertWithSideEffect JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j) { return j.m_parent == this; })); } JSON_CATCH(...) {} // LCOV_EXCL_LINE #endif static_cast(check_parents); } void set_parents() { #if JSON_DIAGNOSTICS switch (m_type) { case value_t::array: { for (auto& element : *m_value.array) { element.m_parent = this; } break; } case value_t::object: { for (auto& element : *m_value.object) { element.second.m_parent = this; } break; } case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: break; } #endif } iterator set_parents(iterator it, typename iterator::difference_type count) { #if JSON_DIAGNOSTICS for (typename iterator::difference_type i = 0; i < count; ++i) { (it + i)->m_parent = this; } #else static_cast(count); #endif return it; } reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1)) { #if JSON_DIAGNOSTICS if (old_capacity != std::size_t(-1)) { // see https://github.com/nlohmann/json/issues/2838 JSON_ASSERT(type() == value_t::array); if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) { // capacity has changed: update all parents set_parents(); return j; } } // ordered_json uses a vector internally, so pointers could have // been invalidated; see https://github.com/nlohmann/json/issues/2962 #ifdef JSON_HEDLEY_MSVC_VERSION #pragma warning(push ) #pragma warning(disable : 4127) // ignore warning to replace if with if constexpr #endif if (detail::is_ordered_map::value) { set_parents(); return j; } #ifdef JSON_HEDLEY_MSVC_VERSION #pragma warning( pop ) #endif j.m_parent = this; #else static_cast(j); static_cast(old_capacity); #endif return j; } public: ////////////////////////// // JSON parser callback // ////////////////////////// /*! @brief parser event types The parser callback distinguishes the following events: - `object_start`: the parser read `{` and started to process a JSON object - `key`: the parser read a key of a value in an object - `object_end`: the parser read `}` and finished processing a JSON object - `array_start`: the parser read `[` and started to process a JSON array - `array_end`: the parser read `]` and finished processing a JSON array - `value`: the parser finished reading a JSON value @image html callback_events.png "Example when certain parse events are triggered" @sa see @ref parser_callback_t for more information and examples */ using parse_event_t = detail::parse_event_t; /*! @brief per-element parser callback type With a parser callback function, the result of parsing a JSON text can be influenced. When passed to @ref parse, it is called on certain events (passed as @ref parse_event_t via parameter @a event) with a set recursion depth @a depth and context JSON value @a parsed. The return value of the callback function is a boolean indicating whether the element that emitted the callback shall be kept or not. We distinguish six scenarios (determined by the event type) in which the callback function can be called. The following table describes the values of the parameters @a depth, @a event, and @a parsed. parameter @a event | description | parameter @a depth | parameter @a parsed ------------------ | ----------- | ------------------ | ------------------- parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value @image html callback_events.png "Example when certain parse events are triggered" Discarding a value (i.e., returning `false`) has different effects depending on the context in which function was called: - Discarded values in structured types are skipped. That is, the parser will behave as if the discarded value was never read. - In case a value outside a structured type is skipped, it is replaced with `null`. This case happens if the top-level element is skipped. @param[in] depth the depth of the recursion during parsing @param[in] event an event of type parse_event_t indicating the context in the callback function has been called @param[in,out] parsed the current intermediate parse result; note that writing to this value has no effect for parse_event_t::key events @return Whether the JSON value which called the function during parsing should be kept (`true`) or not (`false`). In the latter case, it is either skipped completely or replaced by an empty discarded object. @sa see @ref parse for examples @since version 1.0.0 */ using parser_callback_t = detail::parser_callback_t; ////////////////// // constructors // ////////////////// /// @name constructors and destructors /// Constructors of class @ref basic_json, copy/move constructor, copy /// assignment, static functions creating objects, and the destructor. /// @{ /*! @brief create an empty value with a given type Create an empty JSON value with a given type. The value will be default initialized with an empty value which depends on the type: Value type | initial value ----------- | ------------- null | `null` boolean | `false` string | `""` number | `0` object | `{}` array | `[]` binary | empty array @param[in] v the type of the value to create @complexity Constant. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @liveexample{The following code shows the constructor for different @ref value_t values,basic_json__value_t} @sa see @ref clear() -- restores the postcondition of this constructor @since version 1.0.0 */ basic_json(const value_t v) : m_type(v), m_value(v) { assert_invariant(); } /*! @brief create a null object Create a `null` JSON value. It either takes a null pointer as parameter (explicitly creating `null`) or no parameter (implicitly creating `null`). The passed null pointer itself is not read -- it is only used to choose the right constructor. @complexity Constant. @exceptionsafety No-throw guarantee: this constructor never throws exceptions. @liveexample{The following code shows the constructor with and without a null pointer parameter.,basic_json__nullptr_t} @since version 1.0.0 */ basic_json(std::nullptr_t = nullptr) noexcept : basic_json(value_t::null) { assert_invariant(); } /*! @brief create a JSON value This is a "catch all" constructor for all compatible JSON types; that is, types for which a `to_json()` method exists. The constructor forwards the parameter @a val to that method (to `json_serializer::to_json` method with `U = uncvref_t`, to be exact). Template type @a CompatibleType includes, but is not limited to, the following types: - **arrays**: @ref array_t and all kinds of compatible containers such as `std::vector`, `std::deque`, `std::list`, `std::forward_list`, `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, `std::multiset`, and `std::unordered_multiset` with a `value_type` from which a @ref basic_json value can be constructed. - **objects**: @ref object_t and all kinds of compatible associative containers such as `std::map`, `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with a `key_type` compatible to @ref string_t and a `value_type` from which a @ref basic_json value can be constructed. - **strings**: @ref string_t, string literals, and all compatible string containers can be used. - **numbers**: @ref number_integer_t, @ref number_unsigned_t, @ref number_float_t, and all convertible number types such as `int`, `size_t`, `int64_t`, `float` or `double` can be used. - **boolean**: @ref boolean_t / `bool` can be used. - **binary**: @ref binary_t / `std::vector` may be used, unfortunately because string literals cannot be distinguished from binary character arrays by the C++ type system, all types compatible with `const char*` will be directed to the string constructor instead. This is both for backwards compatibility, and due to the fact that a binary type is not a standard JSON type. See the examples below. @tparam CompatibleType a type such that: - @a CompatibleType is not derived from `std::istream`, - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move constructors), - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments) - @a CompatibleType is not a @ref basic_json nested type (e.g., @ref json_pointer, @ref iterator, etc ...) - `json_serializer` has a `to_json(basic_json_t&, CompatibleType&&)` method @tparam U = `uncvref_t` @param[in] val the value to be forwarded to the respective constructor @complexity Usually linear in the size of the passed @a val, also depending on the implementation of the called `to_json()` method. @exceptionsafety Depends on the called constructor. For types directly supported by the library (i.e., all types for which no `to_json()` function was provided), strong guarantee holds: if an exception is thrown, there are no changes to any JSON value. @liveexample{The following code shows the constructor with several compatible types.,basic_json__CompatibleType} @since version 2.1.0 */ template < typename CompatibleType, typename U = detail::uncvref_t, detail::enable_if_t < !detail::is_basic_json::value && detail::is_compatible_type::value, int > = 0 > basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape) JSONSerializer::to_json(std::declval(), std::forward(val)))) { JSONSerializer::to_json(*this, std::forward(val)); set_parents(); assert_invariant(); } /*! @brief create a JSON value from an existing one This is a constructor for existing @ref basic_json types. It does not hijack copy/move constructors, since the parameter has different template arguments than the current ones. The constructor tries to convert the internal @ref m_value of the parameter. @tparam BasicJsonType a type such that: - @a BasicJsonType is a @ref basic_json type. - @a BasicJsonType has different template arguments than @ref basic_json_t. @param[in] val the @ref basic_json value to be converted. @complexity Usually linear in the size of the passed @a val, also depending on the implementation of the called `to_json()` method. @exceptionsafety Depends on the called constructor. For types directly supported by the library (i.e., all types for which no `to_json()` function was provided), strong guarantee holds: if an exception is thrown, there are no changes to any JSON value. @since version 3.2.0 */ template < typename BasicJsonType, detail::enable_if_t < detail::is_basic_json::value&& !std::is_same::value, int > = 0 > basic_json(const BasicJsonType& val) { using other_boolean_t = typename BasicJsonType::boolean_t; using other_number_float_t = typename BasicJsonType::number_float_t; using other_number_integer_t = typename BasicJsonType::number_integer_t; using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; using other_string_t = typename BasicJsonType::string_t; using other_object_t = typename BasicJsonType::object_t; using other_array_t = typename BasicJsonType::array_t; using other_binary_t = typename BasicJsonType::binary_t; switch (val.type()) { case value_t::boolean: JSONSerializer::to_json(*this, val.template get()); break; case value_t::number_float: JSONSerializer::to_json(*this, val.template get()); break; case value_t::number_integer: JSONSerializer::to_json(*this, val.template get()); break; case value_t::number_unsigned: JSONSerializer::to_json(*this, val.template get()); break; case value_t::string: JSONSerializer::to_json(*this, val.template get_ref()); break; case value_t::object: JSONSerializer::to_json(*this, val.template get_ref()); break; case value_t::array: JSONSerializer::to_json(*this, val.template get_ref()); break; case value_t::binary: JSONSerializer::to_json(*this, val.template get_ref()); break; case value_t::null: *this = nullptr; break; case value_t::discarded: m_type = value_t::discarded; break; default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } set_parents(); assert_invariant(); } /*! @brief create a container (array or object) from an initializer list Creates a JSON value of type array or object from the passed initializer list @a init. In case @a type_deduction is `true` (default), the type of the JSON value to be created is deducted from the initializer list @a init according to the following rules: 1. If the list is empty, an empty JSON object value `{}` is created. 2. If the list consists of pairs whose first element is a string, a JSON object value is created where the first elements of the pairs are treated as keys and the second elements are as values. 3. In all other cases, an array is created. The rules aim to create the best fit between a C++ initializer list and JSON values. The rationale is as follows: 1. The empty initializer list is written as `{}` which is exactly an empty JSON object. 2. C++ has no way of describing mapped types other than to list a list of pairs. As JSON requires that keys must be of type string, rule 2 is the weakest constraint one can pose on initializer lists to interpret them as an object. 3. In all other cases, the initializer list could not be interpreted as JSON object type, so interpreting it as JSON array type is safe. With the rules described above, the following JSON values cannot be expressed by an initializer list: - the empty array (`[]`): use @ref array(initializer_list_t) with an empty initializer list in this case - arrays whose elements satisfy rule 2: use @ref array(initializer_list_t) with the same initializer list in this case @note When used without parentheses around an empty initializer list, @ref basic_json() is called instead of this function, yielding the JSON null value. @param[in] init initializer list with JSON values @param[in] type_deduction internal parameter; when set to `true`, the type of the JSON value is deducted from the initializer list @a init; when set to `false`, the type provided via @a manual_type is forced. This mode is used by the functions @ref array(initializer_list_t) and @ref object(initializer_list_t). @param[in] manual_type internal parameter; when @a type_deduction is set to `false`, the created JSON value will use the provided type (only @ref value_t::array and @ref value_t::object are valid); when @a type_deduction is set to `true`, this parameter has no effect @throw type_error.301 if @a type_deduction is `false`, @a manual_type is `value_t::object`, but @a init contains an element which is not a pair whose first element is a string. In this case, the constructor could not create an object. If @a type_deduction would have be `true`, an array would have been created. See @ref object(initializer_list_t) for an example. @complexity Linear in the size of the initializer list @a init. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @liveexample{The example below shows how JSON values are created from initializer lists.,basic_json__list_init_t} @sa see @ref array(initializer_list_t) -- create a JSON array value from an initializer list @sa see @ref object(initializer_list_t) -- create a JSON object value from an initializer list @since version 1.0.0 */ basic_json(initializer_list_t init, bool type_deduction = true, value_t manual_type = value_t::array) { // check if each element is an array with two elements whose first // element is a string bool is_an_object = std::all_of(init.begin(), init.end(), [](const detail::json_ref& element_ref) { return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string(); }); // adjust type if type deduction is not wanted if (!type_deduction) { // if array is wanted, do not create an object though possible if (manual_type == value_t::array) { is_an_object = false; } // if object is wanted but impossible, throw an exception if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) { JSON_THROW(type_error::create(301, "cannot create object from initializer list", basic_json())); } } if (is_an_object) { // the initializer list is a list of pairs -> create object m_type = value_t::object; m_value = value_t::object; for (auto& element_ref : init) { auto element = element_ref.moved_or_copied(); m_value.object->emplace( std::move(*((*element.m_value.array)[0].m_value.string)), std::move((*element.m_value.array)[1])); } } else { // the initializer list describes an array -> create array m_type = value_t::array; m_value.array = create(init.begin(), init.end()); } set_parents(); assert_invariant(); } /*! @brief explicitly create a binary array (without subtype) Creates a JSON binary array value from a given binary container. Binary values are part of various binary formats, such as CBOR, MessagePack, and BSON. This constructor is used to create a value for serialization to those formats. @note Note, this function exists because of the difficulty in correctly specifying the correct template overload in the standard value ctor, as both JSON arrays and JSON binary arrays are backed with some form of a `std::vector`. Because JSON binary arrays are a non-standard extension it was decided that it would be best to prevent automatic initialization of a binary array type, for backwards compatibility and so it does not happen on accident. @param[in] init container containing bytes to use as binary type @return JSON binary array value @complexity Linear in the size of @a init. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json binary(const typename binary_t::container_type& init) { auto res = basic_json(); res.m_type = value_t::binary; res.m_value = init; return res; } /*! @brief explicitly create a binary array (with subtype) Creates a JSON binary array value from a given binary container. Binary values are part of various binary formats, such as CBOR, MessagePack, and BSON. This constructor is used to create a value for serialization to those formats. @note Note, this function exists because of the difficulty in correctly specifying the correct template overload in the standard value ctor, as both JSON arrays and JSON binary arrays are backed with some form of a `std::vector`. Because JSON binary arrays are a non-standard extension it was decided that it would be best to prevent automatic initialization of a binary array type, for backwards compatibility and so it does not happen on accident. @param[in] init container containing bytes to use as binary type @param[in] subtype subtype to use in MessagePack and BSON @return JSON binary array value @complexity Linear in the size of @a init. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); res.m_type = value_t::binary; res.m_value = binary_t(init, subtype); return res; } /// @copydoc binary(const typename binary_t::container_type&) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json binary(typename binary_t::container_type&& init) { auto res = basic_json(); res.m_type = value_t::binary; res.m_value = std::move(init); return res; } /// @copydoc binary(const typename binary_t::container_type&, typename binary_t::subtype_type) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); res.m_type = value_t::binary; res.m_value = binary_t(std::move(init), subtype); return res; } /*! @brief explicitly create an array from an initializer list Creates a JSON array value from a given initializer list. That is, given a list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the initializer list is empty, the empty array `[]` is created. @note This function is only needed to express two edge cases that cannot be realized with the initializer list constructor (@ref basic_json(initializer_list_t, bool, value_t)). These cases are: 1. creating an array whose elements are all pairs whose first element is a string -- in this case, the initializer list constructor would create an object, taking the first elements as keys 2. creating an empty array -- passing the empty initializer list to the initializer list constructor yields an empty object @param[in] init initializer list with JSON values to create an array from (optional) @return JSON array value @complexity Linear in the size of @a init. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @liveexample{The following code shows an example for the `array` function.,array} @sa see @ref basic_json(initializer_list_t, bool, value_t) -- create a JSON value from an initializer list @sa see @ref object(initializer_list_t) -- create a JSON object value from an initializer list @since version 1.0.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json array(initializer_list_t init = {}) { return basic_json(init, false, value_t::array); } /*! @brief explicitly create an object from an initializer list Creates a JSON object value from a given initializer list. The initializer lists elements must be pairs, and their first elements must be strings. If the initializer list is empty, the empty object `{}` is created. @note This function is only added for symmetry reasons. In contrast to the related function @ref array(initializer_list_t), there are no cases which can only be expressed by this function. That is, any initializer list @a init can also be passed to the initializer list constructor @ref basic_json(initializer_list_t, bool, value_t). @param[in] init initializer list to create an object from (optional) @return JSON object value @throw type_error.301 if @a init is not a list of pairs whose first elements are strings. In this case, no object can be created. When such a value is passed to @ref basic_json(initializer_list_t, bool, value_t), an array would have been created from the passed initializer list @a init. See example below. @complexity Linear in the size of @a init. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @liveexample{The following code shows an example for the `object` function.,object} @sa see @ref basic_json(initializer_list_t, bool, value_t) -- create a JSON value from an initializer list @sa see @ref array(initializer_list_t) -- create a JSON array value from an initializer list @since version 1.0.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json object(initializer_list_t init = {}) { return basic_json(init, false, value_t::object); } /*! @brief construct an array with count copies of given value Constructs a JSON array value by creating @a cnt copies of a passed value. In case @a cnt is `0`, an empty array is created. @param[in] cnt the number of JSON copies of @a val to create @param[in] val the JSON value to copy @post `std::distance(begin(),end()) == cnt` holds. @complexity Linear in @a cnt. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @liveexample{The following code shows examples for the @ref basic_json(size_type\, const basic_json&) constructor.,basic_json__size_type_basic_json} @since version 1.0.0 */ basic_json(size_type cnt, const basic_json& val) : m_type(value_t::array) { m_value.array = create(cnt, val); set_parents(); assert_invariant(); } /*! @brief construct a JSON container given an iterator range Constructs the JSON value with the contents of the range `[first, last)`. The semantics depends on the different types a JSON value can have: - In case of a null type, invalid_iterator.206 is thrown. - In case of other primitive types (number, boolean, or string), @a first must be `begin()` and @a last must be `end()`. In this case, the value is copied. Otherwise, invalid_iterator.204 is thrown. - In case of structured types (array, object), the constructor behaves as similar versions for `std::vector` or `std::map`; that is, a JSON array or object is constructed from the values in the range. @tparam InputIT an input iterator type (@ref iterator or @ref const_iterator) @param[in] first begin of the range to copy from (included) @param[in] last end of the range to copy from (excluded) @pre Iterators @a first and @a last must be initialized. **This precondition is enforced with an assertion (see warning).** If assertions are switched off, a violation of this precondition yields undefined behavior. @pre Range `[first, last)` is valid. Usually, this precondition cannot be checked efficiently. Only certain edge cases are detected; see the description of the exceptions below. A violation of this precondition yields undefined behavior. @warning A precondition is enforced with a runtime assertion that will result in calling `std::abort` if this precondition is not met. Assertions can be disabled by defining `NDEBUG` at compile time. See https://en.cppreference.com/w/cpp/error/assert for more information. @throw invalid_iterator.201 if iterators @a first and @a last are not compatible (i.e., do not belong to the same JSON value). In this case, the range `[first, last)` is undefined. @throw invalid_iterator.204 if iterators @a first and @a last belong to a primitive type (number, boolean, or string), but @a first does not point to the first element any more. In this case, the range `[first, last)` is undefined. See example code below. @throw invalid_iterator.206 if iterators @a first and @a last belong to a null value. In this case, the range `[first, last)` is undefined. @complexity Linear in distance between @a first and @a last. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @liveexample{The example below shows several ways to create JSON values by specifying a subrange with iterators.,basic_json__InputIt_InputIt} @since version 1.0.0 */ template < class InputIT, typename std::enable_if < std::is_same::value || std::is_same::value, int >::type = 0 > basic_json(InputIT first, InputIT last) { JSON_ASSERT(first.m_object != nullptr); JSON_ASSERT(last.m_object != nullptr); // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", basic_json())); } // copy type from first iterator m_type = first.m_object->m_type; // check if iterator range is complete for primitive values switch (m_type) { case value_t::boolean: case value_t::number_float: case value_t::number_integer: case value_t::number_unsigned: case value_t::string: { if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) { JSON_THROW(invalid_iterator::create(204, "iterators out of range", *first.m_object)); } break; } case value_t::null: case value_t::object: case value_t::array: case value_t::binary: case value_t::discarded: default: break; } switch (m_type) { case value_t::number_integer: { m_value.number_integer = first.m_object->m_value.number_integer; break; } case value_t::number_unsigned: { m_value.number_unsigned = first.m_object->m_value.number_unsigned; break; } case value_t::number_float: { m_value.number_float = first.m_object->m_value.number_float; break; } case value_t::boolean: { m_value.boolean = first.m_object->m_value.boolean; break; } case value_t::string: { m_value = *first.m_object->m_value.string; break; } case value_t::object: { m_value.object = create(first.m_it.object_iterator, last.m_it.object_iterator); break; } case value_t::array: { m_value.array = create(first.m_it.array_iterator, last.m_it.array_iterator); break; } case value_t::binary: { m_value = *first.m_object->m_value.binary; break; } case value_t::null: case value_t::discarded: default: JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + std::string(first.m_object->type_name()), *first.m_object)); } set_parents(); assert_invariant(); } /////////////////////////////////////// // other constructors and destructor // /////////////////////////////////////// template, std::is_same>::value, int> = 0 > basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {} /*! @brief copy constructor Creates a copy of a given JSON value. @param[in] other the JSON value to copy @post `*this == other` @complexity Linear in the size of @a other. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes to any JSON value. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is linear. - As postcondition, it holds: `other == basic_json(other)`. @liveexample{The following code shows an example for the copy constructor.,basic_json__basic_json} @since version 1.0.0 */ basic_json(const basic_json& other) : m_type(other.m_type) { // check of passed value is valid other.assert_invariant(); switch (m_type) { case value_t::object: { m_value = *other.m_value.object; break; } case value_t::array: { m_value = *other.m_value.array; break; } case value_t::string: { m_value = *other.m_value.string; break; } case value_t::boolean: { m_value = other.m_value.boolean; break; } case value_t::number_integer: { m_value = other.m_value.number_integer; break; } case value_t::number_unsigned: { m_value = other.m_value.number_unsigned; break; } case value_t::number_float: { m_value = other.m_value.number_float; break; } case value_t::binary: { m_value = *other.m_value.binary; break; } case value_t::null: case value_t::discarded: default: break; } set_parents(); assert_invariant(); } /*! @brief move constructor Move constructor. Constructs a JSON value with the contents of the given value @a other using move semantics. It "steals" the resources from @a other and leaves it as JSON null value. @param[in,out] other value to move to this object @post `*this` has the same value as @a other before the call. @post @a other is a JSON null value. @complexity Constant. @exceptionsafety No-throw guarantee: this constructor never throws exceptions. @requirement This function helps `basic_json` satisfying the [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible) requirements. @liveexample{The code below shows the move constructor explicitly called via std::move.,basic_json__moveconstructor} @since version 1.0.0 */ basic_json(basic_json&& other) noexcept : m_type(std::move(other.m_type)), m_value(std::move(other.m_value)) { // check that passed value is valid other.assert_invariant(false); // invalidate payload other.m_type = value_t::null; other.m_value = {}; set_parents(); assert_invariant(); } /*! @brief copy assignment Copy assignment operator. Copies a JSON value via the "copy and swap" strategy: It is expressed in terms of the copy constructor, destructor, and the `swap()` member function. @param[in] other value to copy from @complexity Linear. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is linear. @liveexample{The code below shows and example for the copy assignment. It creates a copy of value `a` which is then swapped with `b`. Finally\, the copy of `a` (which is the null value after the swap) is destroyed.,basic_json__copyassignment} @since version 1.0.0 */ basic_json& operator=(basic_json other) noexcept ( std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value ) { // check that passed value is valid other.assert_invariant(); using std::swap; swap(m_type, other.m_type); swap(m_value, other.m_value); set_parents(); assert_invariant(); return *this; } /*! @brief destructor Destroys the JSON value and frees all allocated memory. @complexity Linear. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is linear. - All stored elements are destroyed and all memory is freed. @since version 1.0.0 */ ~basic_json() noexcept { assert_invariant(false); m_value.destroy(m_type); } /// @} public: /////////////////////// // object inspection // /////////////////////// /// @name object inspection /// Functions to inspect the type of a JSON value. /// @{ /*! @brief serialization Serialization function for JSON values. The function tries to mimic Python's `json.dumps()` function, and currently supports its @a indent and @a ensure_ascii parameters. @param[in] indent If indent is nonnegative, then array elements and object members will be pretty-printed with that indent level. An indent level of `0` will only insert newlines. `-1` (the default) selects the most compact representation. @param[in] indent_char The character to use for indentation if @a indent is greater than `0`. The default is ` ` (space). @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters in the output are escaped with `\uXXXX` sequences, and the result consists of ASCII characters only. @param[in] error_handler how to react on decoding errors; there are three possible values: `strict` (throws and exception in case a decoding error occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), and `ignore` (ignore invalid UTF-8 sequences during serialization; all bytes are copied to the output unchanged). @return string containing the serialization of the JSON value @throw type_error.316 if a string stored inside the JSON value is not UTF-8 encoded and @a error_handler is set to strict @note Binary values are serialized as object containing two keys: - "bytes": an array of bytes as integers - "subtype": the subtype as integer or "null" if the binary has no subtype @complexity Linear. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes in the JSON value. @liveexample{The following example shows the effect of different @a indent\, @a indent_char\, and @a ensure_ascii parameters to the result of the serialization.,dump} @see https://docs.python.org/2/library/json.html#json.dump @since version 1.0.0; indentation character @a indent_char, option @a ensure_ascii and exceptions added in version 3.0.0; error handlers added in version 3.4.0; serialization of binary values added in version 3.8.0. */ string_t dump(const int indent = -1, const char indent_char = ' ', const bool ensure_ascii = false, const error_handler_t error_handler = error_handler_t::strict) const { string_t result; serializer s(detail::output_adapter(result), indent_char, error_handler); if (indent >= 0) { s.dump(*this, true, ensure_ascii, static_cast(indent)); } else { s.dump(*this, false, ensure_ascii, 0); } return result; } /*! @brief return the type of the JSON value (explicit) Return the type of the JSON value as a value from the @ref value_t enumeration. @return the type of the JSON value Value type | return value ------------------------- | ------------------------- null | value_t::null boolean | value_t::boolean string | value_t::string number (integer) | value_t::number_integer number (unsigned integer) | value_t::number_unsigned number (floating-point) | value_t::number_float object | value_t::object array | value_t::array binary | value_t::binary discarded | value_t::discarded @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `type()` for all JSON types.,type} @sa see @ref operator value_t() -- return the type of the JSON value (implicit) @sa see @ref type_name() -- return the type as string @since version 1.0.0 */ constexpr value_t type() const noexcept { return m_type; } /*! @brief return whether type is primitive This function returns true if and only if the JSON type is primitive (string, number, boolean, or null). @return `true` if type is primitive (string, number, boolean, or null), `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_primitive()` for all JSON types.,is_primitive} @sa see @ref is_structured() -- returns whether JSON value is structured @sa see @ref is_null() -- returns whether JSON value is `null` @sa see @ref is_string() -- returns whether JSON value is a string @sa see @ref is_boolean() -- returns whether JSON value is a boolean @sa see @ref is_number() -- returns whether JSON value is a number @sa see @ref is_binary() -- returns whether JSON value is a binary array @since version 1.0.0 */ constexpr bool is_primitive() const noexcept { return is_null() || is_string() || is_boolean() || is_number() || is_binary(); } /*! @brief return whether type is structured This function returns true if and only if the JSON type is structured (array or object). @return `true` if type is structured (array or object), `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_structured()` for all JSON types.,is_structured} @sa see @ref is_primitive() -- returns whether value is primitive @sa see @ref is_array() -- returns whether value is an array @sa see @ref is_object() -- returns whether value is an object @since version 1.0.0 */ constexpr bool is_structured() const noexcept { return is_array() || is_object(); } /*! @brief return whether value is null This function returns true if and only if the JSON value is null. @return `true` if type is null, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_null()` for all JSON types.,is_null} @since version 1.0.0 */ constexpr bool is_null() const noexcept { return m_type == value_t::null; } /*! @brief return whether value is a boolean This function returns true if and only if the JSON value is a boolean. @return `true` if type is boolean, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_boolean()` for all JSON types.,is_boolean} @since version 1.0.0 */ constexpr bool is_boolean() const noexcept { return m_type == value_t::boolean; } /*! @brief return whether value is a number This function returns true if and only if the JSON value is a number. This includes both integer (signed and unsigned) and floating-point values. @return `true` if type is number (regardless whether integer, unsigned integer or floating-type), `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_number()` for all JSON types.,is_number} @sa see @ref is_number_integer() -- check if value is an integer or unsigned integer number @sa see @ref is_number_unsigned() -- check if value is an unsigned integer number @sa see @ref is_number_float() -- check if value is a floating-point number @since version 1.0.0 */ constexpr bool is_number() const noexcept { return is_number_integer() || is_number_float(); } /*! @brief return whether value is an integer number This function returns true if and only if the JSON value is a signed or unsigned integer number. This excludes floating-point values. @return `true` if type is an integer or unsigned integer number, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_number_integer()` for all JSON types.,is_number_integer} @sa see @ref is_number() -- check if value is a number @sa see @ref is_number_unsigned() -- check if value is an unsigned integer number @sa see @ref is_number_float() -- check if value is a floating-point number @since version 1.0.0 */ constexpr bool is_number_integer() const noexcept { return m_type == value_t::number_integer || m_type == value_t::number_unsigned; } /*! @brief return whether value is an unsigned integer number This function returns true if and only if the JSON value is an unsigned integer number. This excludes floating-point and signed integer values. @return `true` if type is an unsigned integer number, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_number_unsigned()` for all JSON types.,is_number_unsigned} @sa see @ref is_number() -- check if value is a number @sa see @ref is_number_integer() -- check if value is an integer or unsigned integer number @sa see @ref is_number_float() -- check if value is a floating-point number @since version 2.0.0 */ constexpr bool is_number_unsigned() const noexcept { return m_type == value_t::number_unsigned; } /*! @brief return whether value is a floating-point number This function returns true if and only if the JSON value is a floating-point number. This excludes signed and unsigned integer values. @return `true` if type is a floating-point number, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_number_float()` for all JSON types.,is_number_float} @sa see @ref is_number() -- check if value is number @sa see @ref is_number_integer() -- check if value is an integer number @sa see @ref is_number_unsigned() -- check if value is an unsigned integer number @since version 1.0.0 */ constexpr bool is_number_float() const noexcept { return m_type == value_t::number_float; } /*! @brief return whether value is an object This function returns true if and only if the JSON value is an object. @return `true` if type is object, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_object()` for all JSON types.,is_object} @since version 1.0.0 */ constexpr bool is_object() const noexcept { return m_type == value_t::object; } /*! @brief return whether value is an array This function returns true if and only if the JSON value is an array. @return `true` if type is array, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_array()` for all JSON types.,is_array} @since version 1.0.0 */ constexpr bool is_array() const noexcept { return m_type == value_t::array; } /*! @brief return whether value is a string This function returns true if and only if the JSON value is a string. @return `true` if type is string, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_string()` for all JSON types.,is_string} @since version 1.0.0 */ constexpr bool is_string() const noexcept { return m_type == value_t::string; } /*! @brief return whether value is a binary array This function returns true if and only if the JSON value is a binary array. @return `true` if type is binary array, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_binary()` for all JSON types.,is_binary} @since version 3.8.0 */ constexpr bool is_binary() const noexcept { return m_type == value_t::binary; } /*! @brief return whether value is discarded This function returns true if and only if the JSON value was discarded during parsing with a callback function (see @ref parser_callback_t). @note This function will always be `false` for JSON values after parsing. That is, discarded values can only occur during parsing, but will be removed when inside a structured value or replaced by null in other cases. @return `true` if type is discarded, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_discarded()` for all JSON types.,is_discarded} @since version 1.0.0 */ constexpr bool is_discarded() const noexcept { return m_type == value_t::discarded; } /*! @brief return the type of the JSON value (implicit) Implicitly return the type of the JSON value as a value from the @ref value_t enumeration. @return the type of the JSON value @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies the @ref value_t operator for all JSON types.,operator__value_t} @sa see @ref type() -- return the type of the JSON value (explicit) @sa see @ref type_name() -- return the type as string @since version 1.0.0 */ constexpr operator value_t() const noexcept { return m_type; } /// @} private: ////////////////// // value access // ////////////////// /// get a boolean (explicit) boolean_t get_impl(boolean_t* /*unused*/) const { if (JSON_HEDLEY_LIKELY(is_boolean())) { return m_value.boolean; } JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()), *this)); } /// get a pointer to the value (object) object_t* get_impl_ptr(object_t* /*unused*/) noexcept { return is_object() ? m_value.object : nullptr; } /// get a pointer to the value (object) constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept { return is_object() ? m_value.object : nullptr; } /// get a pointer to the value (array) array_t* get_impl_ptr(array_t* /*unused*/) noexcept { return is_array() ? m_value.array : nullptr; } /// get a pointer to the value (array) constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept { return is_array() ? m_value.array : nullptr; } /// get a pointer to the value (string) string_t* get_impl_ptr(string_t* /*unused*/) noexcept { return is_string() ? m_value.string : nullptr; } /// get a pointer to the value (string) constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept { return is_string() ? m_value.string : nullptr; } /// get a pointer to the value (boolean) boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept { return is_boolean() ? &m_value.boolean : nullptr; } /// get a pointer to the value (boolean) constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept { return is_boolean() ? &m_value.boolean : nullptr; } /// get a pointer to the value (integer number) number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept { return is_number_integer() ? &m_value.number_integer : nullptr; } /// get a pointer to the value (integer number) constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept { return is_number_integer() ? &m_value.number_integer : nullptr; } /// get a pointer to the value (unsigned number) number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept { return is_number_unsigned() ? &m_value.number_unsigned : nullptr; } /// get a pointer to the value (unsigned number) constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept { return is_number_unsigned() ? &m_value.number_unsigned : nullptr; } /// get a pointer to the value (floating-point number) number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept { return is_number_float() ? &m_value.number_float : nullptr; } /// get a pointer to the value (floating-point number) constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept { return is_number_float() ? &m_value.number_float : nullptr; } /// get a pointer to the value (binary) binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept { return is_binary() ? m_value.binary : nullptr; } /// get a pointer to the value (binary) constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept { return is_binary() ? m_value.binary : nullptr; } /*! @brief helper function to implement get_ref() This function helps to implement get_ref() without code duplication for const and non-const overloads @tparam ThisType will be deduced as `basic_json` or `const basic_json` @throw type_error.303 if ReferenceType does not match underlying value type of the current JSON */ template static ReferenceType get_ref_impl(ThisType& obj) { // delegate the call to get_ptr<>() auto* ptr = obj.template get_ptr::type>(); if (JSON_HEDLEY_LIKELY(ptr != nullptr)) { return *ptr; } JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()), obj)); } public: /// @name value access /// Direct access to the stored value of a JSON value. /// @{ /*! @brief get a pointer value (implicit) Implicit pointer access to the internally stored JSON value. No copies are made. @warning Writing data to the pointee of the result yields an undefined state. @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, @ref number_unsigned_t, or @ref number_float_t. Enforced by a static assertion. @return pointer to the internally stored JSON value if the requested pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @complexity Constant. @liveexample{The example below shows how pointers to internal values of a JSON value can be requested. Note that no type conversions are made and a `nullptr` is returned if the value and the requested pointer type does not match.,get_ptr} @since version 1.0.0 */ template::value, int>::type = 0> auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) { // delegate the call to get_impl_ptr<>() return get_impl_ptr(static_cast(nullptr)); } /*! @brief get a pointer value (implicit) @copydoc get_ptr() */ template < typename PointerType, typename std::enable_if < std::is_pointer::value&& std::is_const::type>::value, int >::type = 0 > constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) { // delegate the call to get_impl_ptr<>() const return get_impl_ptr(static_cast(nullptr)); } private: /*! @brief get a value (explicit) Explicit type conversion between the JSON value and a compatible value which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). The value is converted by calling the @ref json_serializer `from_json()` method. The function is equivalent to executing @code {.cpp} ValueType ret; JSONSerializer::from_json(*this, ret); return ret; @endcode This overloads is chosen if: - @a ValueType is not @ref basic_json, - @ref json_serializer has a `from_json()` method of the form `void from_json(const basic_json&, ValueType&)`, and - @ref json_serializer does not have a `from_json()` method of the form `ValueType from_json(const basic_json&)` @tparam ValueType the returned value type @return copy of the JSON value, converted to @a ValueType @throw what @ref json_serializer `from_json()` method throws @liveexample{The example below shows several conversions from JSON values to other types. There a few things to note: (1) Floating-point numbers can be converted to integers\, (2) A JSON array can be converted to a standard `std::vector`\, (3) A JSON object can be converted to C++ associative containers such as `std::unordered_map`.,get__ValueType_const} @since version 2.1.0 */ template < typename ValueType, detail::enable_if_t < detail::is_default_constructible::value&& detail::has_from_json::value, int > = 0 > ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept( JSONSerializer::from_json(std::declval(), std::declval()))) { auto ret = ValueType(); JSONSerializer::from_json(*this, ret); return ret; } /*! @brief get a value (explicit); special case Explicit type conversion between the JSON value and a compatible value which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). The value is converted by calling the @ref json_serializer `from_json()` method. The function is equivalent to executing @code {.cpp} return JSONSerializer::from_json(*this); @endcode This overloads is chosen if: - @a ValueType is not @ref basic_json and - @ref json_serializer has a `from_json()` method of the form `ValueType from_json(const basic_json&)` @note If @ref json_serializer has both overloads of `from_json()`, this one is chosen. @tparam ValueType the returned value type @return copy of the JSON value, converted to @a ValueType @throw what @ref json_serializer `from_json()` method throws @since version 2.1.0 */ template < typename ValueType, detail::enable_if_t < detail::has_non_default_from_json::value, int > = 0 > ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept( JSONSerializer::from_json(std::declval()))) { return JSONSerializer::from_json(*this); } /*! @brief get special-case overload This overloads converts the current @ref basic_json in a different @ref basic_json type @tparam BasicJsonType == @ref basic_json @return a copy of *this, converted into @a BasicJsonType @complexity Depending on the implementation of the called `from_json()` method. @since version 3.2.0 */ template < typename BasicJsonType, detail::enable_if_t < detail::is_basic_json::value, int > = 0 > BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const { return *this; } /*! @brief get special-case overload This overloads avoids a lot of template boilerplate, it can be seen as the identity method @tparam BasicJsonType == @ref basic_json @return a copy of *this @complexity Constant. @since version 2.1.0 */ template::value, int> = 0> basic_json get_impl(detail::priority_tag<3> /*unused*/) const { return *this; } /*! @brief get a pointer value (explicit) @copydoc get() */ template::value, int> = 0> constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept -> decltype(std::declval().template get_ptr()) { // delegate the call to get_ptr return get_ptr(); } public: /*! @brief get a (pointer) value (explicit) Performs explicit type conversion between the JSON value and a compatible value if required. - If the requested type is a pointer to the internally stored JSON value that pointer is returned. No copies are made. - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible from the current @ref basic_json. - Otherwise the value is converted by calling the @ref json_serializer `from_json()` method. @tparam ValueTypeCV the provided value type @tparam ValueType the returned value type @return copy of the JSON value, converted to @tparam ValueType if necessary @throw what @ref json_serializer `from_json()` method throws if conversion is required @since version 2.1.0 */ template < typename ValueTypeCV, typename ValueType = detail::uncvref_t> #if defined(JSON_HAS_CPP_14) constexpr #endif auto get() const noexcept( noexcept(std::declval().template get_impl(detail::priority_tag<4> {}))) -> decltype(std::declval().template get_impl(detail::priority_tag<4> {})) { // we cannot static_assert on ValueTypeCV being non-const, because // there is support for get(), which is why we // still need the uncvref static_assert(!std::is_reference::value, "get() cannot be used with reference types, you might want to use get_ref()"); return get_impl(detail::priority_tag<4> {}); } /*! @brief get a pointer value (explicit) Explicit pointer access to the internally stored JSON value. No copies are made. @warning The pointer becomes invalid if the underlying JSON object changes. @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, @ref number_unsigned_t, or @ref number_float_t. @return pointer to the internally stored JSON value if the requested pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @complexity Constant. @liveexample{The example below shows how pointers to internal values of a JSON value can be requested. Note that no type conversions are made and a `nullptr` is returned if the value and the requested pointer type does not match.,get__PointerType} @sa see @ref get_ptr() for explicit pointer-member access @since version 1.0.0 */ template::value, int>::type = 0> auto get() noexcept -> decltype(std::declval().template get_ptr()) { // delegate the call to get_ptr return get_ptr(); } /*! @brief get a value (explicit) Explicit type conversion between the JSON value and a compatible value. The value is filled into the input parameter by calling the @ref json_serializer `from_json()` method. The function is equivalent to executing @code {.cpp} ValueType v; JSONSerializer::from_json(*this, v); @endcode This overloads is chosen if: - @a ValueType is not @ref basic_json, - @ref json_serializer has a `from_json()` method of the form `void from_json(const basic_json&, ValueType&)`, and @tparam ValueType the input parameter type. @return the input parameter, allowing chaining calls. @throw what @ref json_serializer `from_json()` method throws @liveexample{The example below shows several conversions from JSON values to other types. There a few things to note: (1) Floating-point numbers can be converted to integers\, (2) A JSON array can be converted to a standard `std::vector`\, (3) A JSON object can be converted to C++ associative containers such as `std::unordered_map`.,get_to} @since version 3.3.0 */ template < typename ValueType, detail::enable_if_t < !detail::is_basic_json::value&& detail::has_from_json::value, int > = 0 > ValueType & get_to(ValueType& v) const noexcept(noexcept( JSONSerializer::from_json(std::declval(), v))) { JSONSerializer::from_json(*this, v); return v; } // specialization to allow to call get_to with a basic_json value // see https://github.com/nlohmann/json/issues/2175 template::value, int> = 0> ValueType & get_to(ValueType& v) const { v = *this; return v; } template < typename T, std::size_t N, typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) detail::enable_if_t < detail::has_from_json::value, int > = 0 > Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) noexcept(noexcept(JSONSerializer::from_json( std::declval(), v))) { JSONSerializer::from_json(*this, v); return v; } /*! @brief get a reference value (implicit) Implicit reference access to the internally stored JSON value. No copies are made. @warning Writing data to the referee of the result yields an undefined state. @tparam ReferenceType reference type; must be a reference to @ref array_t, @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref number_float_t. Enforced by static assertion. @return reference to the internally stored JSON value if the requested reference type @a ReferenceType fits to the JSON value; throws type_error.303 otherwise @throw type_error.303 in case passed type @a ReferenceType is incompatible with the stored JSON value; see example below @complexity Constant. @liveexample{The example shows several calls to `get_ref()`.,get_ref} @since version 1.1.0 */ template::value, int>::type = 0> ReferenceType get_ref() { // delegate call to get_ref_impl return get_ref_impl(*this); } /*! @brief get a reference value (implicit) @copydoc get_ref() */ template < typename ReferenceType, typename std::enable_if < std::is_reference::value&& std::is_const::type>::value, int >::type = 0 > ReferenceType get_ref() const { // delegate call to get_ref_impl return get_ref_impl(*this); } /*! @brief get a value (implicit) Implicit type conversion between the JSON value and a compatible value. The call is realized by calling @ref get() const. @tparam ValueType non-pointer type compatible to the JSON value, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for JSON arrays. The character type of @ref string_t as well as an initializer list of this type is excluded to avoid ambiguities as these types implicitly convert to `std::string`. @return copy of the JSON value, converted to type @a ValueType @throw type_error.302 in case passed type @a ValueType is incompatible to the JSON value type (e.g., the JSON value is of type boolean, but a string is requested); see example below @complexity Linear in the size of the JSON value. @liveexample{The example below shows several conversions from JSON values to other types. There a few things to note: (1) Floating-point numbers can be converted to integers\, (2) A JSON array can be converted to a standard `std::vector`\, (3) A JSON object can be converted to C++ associative containers such as `std::unordered_map`.,operator__ValueType} @since version 1.0.0 */ template < typename ValueType, typename std::enable_if < detail::conjunction < detail::negation>, detail::negation>>, detail::negation>, detail::negation>, detail::negation>>, #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) detail::negation>, #endif detail::is_detected_lazy >::value, int >::type = 0 > JSON_EXPLICIT operator ValueType() const { // delegate the call to get<>() const return get(); } /*! @return reference to the binary value @throw type_error.302 if the value is not binary @sa see @ref is_binary() to check if the value is binary @since version 3.8.0 */ binary_t& get_binary() { if (!is_binary()) { JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()), *this)); } return *get_ptr(); } /// @copydoc get_binary() const binary_t& get_binary() const { if (!is_binary()) { JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()), *this)); } return *get_ptr(); } /// @} //////////////////// // element access // //////////////////// /// @name element access /// Access to the JSON value. /// @{ /*! @brief access specified array element with bounds checking Returns a reference to the element at specified location @a idx, with bounds checking. @param[in] idx index of the element to access @return reference to the element at index @a idx @throw type_error.304 if the JSON value is not an array; in this case, calling `at` with an index makes no sense. See example below. @throw out_of_range.401 if the index @a idx is out of range of the array; that is, `idx >= size()`. See example below. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes in the JSON value. @complexity Constant. @since version 1.0.0 @liveexample{The example below shows how array elements can be read and written using `at()`. It also demonstrates the different exceptions that can be thrown.,at__size_type} */ reference at(size_type idx) { // at only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { JSON_TRY { return set_parent(m_value.array->at(idx)); } JSON_CATCH (std::out_of_range&) { // create better exception explanation JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); } } else { JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); } } /*! @brief access specified array element with bounds checking Returns a const reference to the element at specified location @a idx, with bounds checking. @param[in] idx index of the element to access @return const reference to the element at index @a idx @throw type_error.304 if the JSON value is not an array; in this case, calling `at` with an index makes no sense. See example below. @throw out_of_range.401 if the index @a idx is out of range of the array; that is, `idx >= size()`. See example below. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes in the JSON value. @complexity Constant. @since version 1.0.0 @liveexample{The example below shows how array elements can be read using `at()`. It also demonstrates the different exceptions that can be thrown., at__size_type_const} */ const_reference at(size_type idx) const { // at only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { JSON_TRY { return m_value.array->at(idx); } JSON_CATCH (std::out_of_range&) { // create better exception explanation JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); } } else { JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); } } /*! @brief access specified object element with bounds checking Returns a reference to the element at with specified key @a key, with bounds checking. @param[in] key key of the element to access @return reference to the element at key @a key @throw type_error.304 if the JSON value is not an object; in this case, calling `at` with a key makes no sense. See example below. @throw out_of_range.403 if the key @a key is is not stored in the object; that is, `find(key) == end()`. See example below. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes in the JSON value. @complexity Logarithmic in the size of the container. @sa see @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa see @ref value() for access by value with a default value @since version 1.0.0 @liveexample{The example below shows how object elements can be read and written using `at()`. It also demonstrates the different exceptions that can be thrown.,at__object_t_key_type} */ reference at(const typename object_t::key_type& key) { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { JSON_TRY { return set_parent(m_value.object->at(key)); } JSON_CATCH (std::out_of_range&) { // create better exception explanation JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); } } else { JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); } } /*! @brief access specified object element with bounds checking Returns a const reference to the element at with specified key @a key, with bounds checking. @param[in] key key of the element to access @return const reference to the element at key @a key @throw type_error.304 if the JSON value is not an object; in this case, calling `at` with a key makes no sense. See example below. @throw out_of_range.403 if the key @a key is is not stored in the object; that is, `find(key) == end()`. See example below. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes in the JSON value. @complexity Logarithmic in the size of the container. @sa see @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa see @ref value() for access by value with a default value @since version 1.0.0 @liveexample{The example below shows how object elements can be read using `at()`. It also demonstrates the different exceptions that can be thrown., at__object_t_key_type_const} */ const_reference at(const typename object_t::key_type& key) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { JSON_TRY { return m_value.object->at(key); } JSON_CATCH (std::out_of_range&) { // create better exception explanation JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); } } else { JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); } } /*! @brief access specified array element Returns a reference to the element at specified location @a idx. @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), then the array is silently filled up with `null` values to make `idx` a valid reference to the last stored element. @param[in] idx index of the element to access @return reference to the element at index @a idx @throw type_error.305 if the JSON value is not an array or null; in that cases, using the [] operator with an index makes no sense. @complexity Constant if @a idx is in the range of the array. Otherwise linear in `idx - size()`. @liveexample{The example below shows how array elements can be read and written using `[]` operator. Note the addition of `null` values.,operatorarray__size_type} @since version 1.0.0 */ reference operator[](size_type idx) { // implicitly convert null value to an empty array if (is_null()) { m_type = value_t::array; m_value.array = create(); assert_invariant(); } // operator[] only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { // fill up array with null values if given idx is outside range if (idx >= m_value.array->size()) { #if JSON_DIAGNOSTICS // remember array size & capacity before resizing const auto old_size = m_value.array->size(); const auto old_capacity = m_value.array->capacity(); #endif m_value.array->resize(idx + 1); #if JSON_DIAGNOSTICS if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) { // capacity has changed: update all parents set_parents(); } else { // set parent for values added above set_parents(begin() + static_cast(old_size), static_cast(idx + 1 - old_size)); } #endif assert_invariant(); } return m_value.array->operator[](idx); } JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()), *this)); } /*! @brief access specified array element Returns a const reference to the element at specified location @a idx. @param[in] idx index of the element to access @return const reference to the element at index @a idx @throw type_error.305 if the JSON value is not an array; in that case, using the [] operator with an index makes no sense. @complexity Constant. @liveexample{The example below shows how array elements can be read using the `[]` operator.,operatorarray__size_type_const} @since version 1.0.0 */ const_reference operator[](size_type idx) const { // const operator[] only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { return m_value.array->operator[](idx); } JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()), *this)); } /*! @brief access specified object element Returns a reference to the element at with specified key @a key. @note If @a key is not found in the object, then it is silently added to the object and filled with a `null` value to make `key` a valid reference. In case the value was `null` before, it is converted to an object. @param[in] key key of the element to access @return reference to the element at key @a key @throw type_error.305 if the JSON value is not an object or null; in that cases, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read and written using the `[]` operator.,operatorarray__key_type} @sa see @ref at(const typename object_t::key_type&) for access by reference with range checking @sa see @ref value() for access by value with a default value @since version 1.0.0 */ reference operator[](const typename object_t::key_type& key) { // implicitly convert null value to an empty object if (is_null()) { m_type = value_t::object; m_value.object = create(); assert_invariant(); } // operator[] only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { return set_parent(m_value.object->operator[](key)); } JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); } /*! @brief read-only access specified object element Returns a const reference to the element at with specified key @a key. No bounds checking is performed. @warning If the element with key @a key does not exist, the behavior is undefined. @param[in] key key of the element to access @return const reference to the element at key @a key @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** @throw type_error.305 if the JSON value is not an object; in that case, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read using the `[]` operator.,operatorarray__key_type_const} @sa see @ref at(const typename object_t::key_type&) for access by reference with range checking @sa see @ref value() for access by value with a default value @since version 1.0.0 */ const_reference operator[](const typename object_t::key_type& key) const { // const operator[] only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); } /*! @brief access specified object element Returns a reference to the element at with specified key @a key. @note If @a key is not found in the object, then it is silently added to the object and filled with a `null` value to make `key` a valid reference. In case the value was `null` before, it is converted to an object. @param[in] key key of the element to access @return reference to the element at key @a key @throw type_error.305 if the JSON value is not an object or null; in that cases, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read and written using the `[]` operator.,operatorarray__key_type} @sa see @ref at(const typename object_t::key_type&) for access by reference with range checking @sa see @ref value() for access by value with a default value @since version 1.1.0 */ template JSON_HEDLEY_NON_NULL(2) reference operator[](T* key) { // implicitly convert null to object if (is_null()) { m_type = value_t::object; m_value = value_t::object; assert_invariant(); } // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { return set_parent(m_value.object->operator[](key)); } JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); } /*! @brief read-only access specified object element Returns a const reference to the element at with specified key @a key. No bounds checking is performed. @warning If the element with key @a key does not exist, the behavior is undefined. @param[in] key key of the element to access @return const reference to the element at key @a key @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** @throw type_error.305 if the JSON value is not an object; in that case, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read using the `[]` operator.,operatorarray__key_type_const} @sa see @ref at(const typename object_t::key_type&) for access by reference with range checking @sa see @ref value() for access by value with a default value @since version 1.1.0 */ template JSON_HEDLEY_NON_NULL(2) const_reference operator[](T* key) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); } /*! @brief access specified object element with default value Returns either a copy of an object's element at the specified key @a key or a given default value if no element with key @a key exists. The function is basically equivalent to executing @code {.cpp} try { return at(key); } catch(out_of_range) { return default_value; } @endcode @note Unlike @ref at(const typename object_t::key_type&), this function does not throw if the given key @a key was not found. @note Unlike @ref operator[](const typename object_t::key_type& key), this function does not implicitly add an element to the position defined by @a key. This function is furthermore also applicable to const objects. @param[in] key key of the element to access @param[in] default_value the value to return if @a key is not found @tparam ValueType type compatible to JSON values, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for JSON arrays. Note the type of the expected value at @a key and the default value @a default_value must be compatible. @return copy of the element at key @a key or @a default_value if @a key is not found @throw type_error.302 if @a default_value does not match the type of the value at @a key @throw type_error.306 if the JSON value is not an object; in that case, using `value()` with a key makes no sense. @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be queried with a default value.,basic_json__value} @sa see @ref at(const typename object_t::key_type&) for access by reference with range checking @sa see @ref operator[](const typename object_t::key_type&) for unchecked access by reference @since version 1.0.0 */ // using std::is_convertible in a std::enable_if will fail when using explicit conversions template < class ValueType, typename std::enable_if < detail::is_getable::value && !std::is_same::value, int >::type = 0 > ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { // if key is found, return value and given default value otherwise const auto it = find(key); if (it != end()) { return it->template get(); } return default_value; } JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); } /*! @brief overload for a default value of type const char* @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const */ string_t value(const typename object_t::key_type& key, const char* default_value) const { return value(key, string_t(default_value)); } /*! @brief access specified object element via JSON Pointer with default value Returns either a copy of an object's element at the specified key @a key or a given default value if no element with key @a key exists. The function is basically equivalent to executing @code {.cpp} try { return at(ptr); } catch(out_of_range) { return default_value; } @endcode @note Unlike @ref at(const json_pointer&), this function does not throw if the given key @a key was not found. @param[in] ptr a JSON pointer to the element to access @param[in] default_value the value to return if @a ptr found no value @tparam ValueType type compatible to JSON values, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for JSON arrays. Note the type of the expected value at @a key and the default value @a default_value must be compatible. @return copy of the element at key @a key or @a default_value if @a key is not found @throw type_error.302 if @a default_value does not match the type of the value at @a ptr @throw type_error.306 if the JSON value is not an object; in that case, using `value()` with a key makes no sense. @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be queried with a default value.,basic_json__value_ptr} @sa see @ref operator[](const json_pointer&) for unchecked access by reference @since version 2.0.2 */ template::value, int>::type = 0> ValueType value(const json_pointer& ptr, const ValueType& default_value) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { // if pointer resolves a value, return it or use default value JSON_TRY { return ptr.get_checked(this).template get(); } JSON_INTERNAL_CATCH (out_of_range&) { return default_value; } } JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); } /*! @brief overload for a default value of type const char* @copydoc basic_json::value(const json_pointer&, ValueType) const */ JSON_HEDLEY_NON_NULL(3) string_t value(const json_pointer& ptr, const char* default_value) const { return value(ptr, string_t(default_value)); } /*! @brief access the first element Returns a reference to the first element in the container. For a JSON container `c`, the expression `c.front()` is equivalent to `*c.begin()`. @return In case of a structured type (array or object), a reference to the first element is returned. In case of number, string, boolean, or binary values, a reference to the value is returned. @complexity Constant. @pre The JSON value must not be `null` (would throw `std::out_of_range`) or an empty array or object (undefined behavior, **guarded by assertions**). @post The JSON value remains unchanged. @throw invalid_iterator.214 when called on `null` value @liveexample{The following code shows an example for `front()`.,front} @sa see @ref back() -- access the last element @since version 1.0.0 */ reference front() { return *begin(); } /*! @copydoc basic_json::front() */ const_reference front() const { return *cbegin(); } /*! @brief access the last element Returns a reference to the last element in the container. For a JSON container `c`, the expression `c.back()` is equivalent to @code {.cpp} auto tmp = c.end(); --tmp; return *tmp; @endcode @return In case of a structured type (array or object), a reference to the last element is returned. In case of number, string, boolean, or binary values, a reference to the value is returned. @complexity Constant. @pre The JSON value must not be `null` (would throw `std::out_of_range`) or an empty array or object (undefined behavior, **guarded by assertions**). @post The JSON value remains unchanged. @throw invalid_iterator.214 when called on a `null` value. See example below. @liveexample{The following code shows an example for `back()`.,back} @sa see @ref front() -- access the first element @since version 1.0.0 */ reference back() { auto tmp = end(); --tmp; return *tmp; } /*! @copydoc basic_json::back() */ const_reference back() const { auto tmp = cend(); --tmp; return *tmp; } /*! @brief remove element given an iterator Removes the element specified by iterator @a pos. The iterator @a pos must be valid and dereferenceable. Thus the `end()` iterator (which is valid, but is not dereferenceable) cannot be used as a value for @a pos. If called on a primitive type other than `null`, the resulting JSON value will be `null`. @param[in] pos iterator to the element to remove @return Iterator following the last removed element. If the iterator @a pos refers to the last element, the `end()` iterator is returned. @tparam IteratorType an @ref iterator or @ref const_iterator @post Invalidates iterators and references at or after the point of the erase, including the `end()` iterator. @throw type_error.307 if called on a `null` value; example: `"cannot use erase() with null"` @throw invalid_iterator.202 if called on an iterator which does not belong to the current JSON value; example: `"iterator does not fit current value"` @throw invalid_iterator.205 if called on a primitive type with invalid iterator (i.e., any iterator which is not `begin()`); example: `"iterator out of range"` @complexity The complexity depends on the type: - objects: amortized constant - arrays: linear in distance between @a pos and the end of the container - strings and binary: linear in the length of the member - other types: constant @liveexample{The example shows the result of `erase()` for different JSON types.,erase__IteratorType} @sa see @ref erase(IteratorType, IteratorType) -- removes the elements in the given range @sa see @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @sa see @ref erase(const size_type) -- removes the element from an array at the given index @since version 1.0.0 */ template < class IteratorType, typename std::enable_if < std::is_same::value || std::is_same::value, int >::type = 0 > IteratorType erase(IteratorType pos) { // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) { JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); } IteratorType result = end(); switch (m_type) { case value_t::boolean: case value_t::number_float: case value_t::number_integer: case value_t::number_unsigned: case value_t::string: case value_t::binary: { if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) { JSON_THROW(invalid_iterator::create(205, "iterator out of range", *this)); } if (is_string()) { AllocatorType alloc; std::allocator_traits::destroy(alloc, m_value.string); std::allocator_traits::deallocate(alloc, m_value.string, 1); m_value.string = nullptr; } else if (is_binary()) { AllocatorType alloc; std::allocator_traits::destroy(alloc, m_value.binary); std::allocator_traits::deallocate(alloc, m_value.binary, 1); m_value.binary = nullptr; } m_type = value_t::null; assert_invariant(); break; } case value_t::object: { result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); break; } case value_t::array: { result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); break; } case value_t::null: case value_t::discarded: default: JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); } return result; } /*! @brief remove elements given an iterator range Removes the element specified by the range `[first; last)`. The iterator @a first does not need to be dereferenceable if `first == last`: erasing an empty range is a no-op. If called on a primitive type other than `null`, the resulting JSON value will be `null`. @param[in] first iterator to the beginning of the range to remove @param[in] last iterator past the end of the range to remove @return Iterator following the last removed element. If the iterator @a second refers to the last element, the `end()` iterator is returned. @tparam IteratorType an @ref iterator or @ref const_iterator @post Invalidates iterators and references at or after the point of the erase, including the `end()` iterator. @throw type_error.307 if called on a `null` value; example: `"cannot use erase() with null"` @throw invalid_iterator.203 if called on iterators which does not belong to the current JSON value; example: `"iterators do not fit current value"` @throw invalid_iterator.204 if called on a primitive type with invalid iterators (i.e., if `first != begin()` and `last != end()`); example: `"iterators out of range"` @complexity The complexity depends on the type: - objects: `log(size()) + std::distance(first, last)` - arrays: linear in the distance between @a first and @a last, plus linear in the distance between @a last and end of the container - strings and binary: linear in the length of the member - other types: constant @liveexample{The example shows the result of `erase()` for different JSON types.,erase__IteratorType_IteratorType} @sa see @ref erase(IteratorType) -- removes the element at a given position @sa see @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @sa see @ref erase(const size_type) -- removes the element from an array at the given index @since version 1.0.0 */ template < class IteratorType, typename std::enable_if < std::is_same::value || std::is_same::value, int >::type = 0 > IteratorType erase(IteratorType first, IteratorType last) { // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) { JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", *this)); } IteratorType result = end(); switch (m_type) { case value_t::boolean: case value_t::number_float: case value_t::number_integer: case value_t::number_unsigned: case value_t::string: case value_t::binary: { if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) { JSON_THROW(invalid_iterator::create(204, "iterators out of range", *this)); } if (is_string()) { AllocatorType alloc; std::allocator_traits::destroy(alloc, m_value.string); std::allocator_traits::deallocate(alloc, m_value.string, 1); m_value.string = nullptr; } else if (is_binary()) { AllocatorType alloc; std::allocator_traits::destroy(alloc, m_value.binary); std::allocator_traits::deallocate(alloc, m_value.binary, 1); m_value.binary = nullptr; } m_type = value_t::null; assert_invariant(); break; } case value_t::object: { result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, last.m_it.object_iterator); break; } case value_t::array: { result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, last.m_it.array_iterator); break; } case value_t::null: case value_t::discarded: default: JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); } return result; } /*! @brief remove element from a JSON object given a key Removes elements from a JSON object with the key value @a key. @param[in] key value of the elements to remove @return Number of elements removed. If @a ObjectType is the default `std::map` type, the return value will always be `0` (@a key was not found) or `1` (@a key was found). @post References and iterators to the erased elements are invalidated. Other references and iterators are not affected. @throw type_error.307 when called on a type other than JSON object; example: `"cannot use erase() with null"` @complexity `log(size()) + count(key)` @liveexample{The example shows the effect of `erase()`.,erase__key_type} @sa see @ref erase(IteratorType) -- removes the element at a given position @sa see @ref erase(IteratorType, IteratorType) -- removes the elements in the given range @sa see @ref erase(const size_type) -- removes the element from an array at the given index @since version 1.0.0 */ size_type erase(const typename object_t::key_type& key) { // this erase only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { return m_value.object->erase(key); } JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); } /*! @brief remove element from a JSON array given an index Removes element from a JSON array at the index @a idx. @param[in] idx index of the element to remove @throw type_error.307 when called on a type other than JSON object; example: `"cannot use erase() with null"` @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 is out of range"` @complexity Linear in distance between @a idx and the end of the container. @liveexample{The example shows the effect of `erase()`.,erase__size_type} @sa see @ref erase(IteratorType) -- removes the element at a given position @sa see @ref erase(IteratorType, IteratorType) -- removes the elements in the given range @sa see @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @since version 1.0.0 */ void erase(const size_type idx) { // this erase only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { if (JSON_HEDLEY_UNLIKELY(idx >= size())) { JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); } m_value.array->erase(m_value.array->begin() + static_cast(idx)); } else { JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); } } /// @} //////////// // lookup // //////////// /// @name lookup /// @{ /*! @brief find an element in a JSON object Finds an element in a JSON object with key equivalent to @a key. If the element is not found or the JSON value is not an object, end() is returned. @note This method always returns @ref end() when executed on a JSON type that is not an object. @param[in] key key value of the element to search for. @return Iterator to an element with key equivalent to @a key. If no such element is found or the JSON value is not an object, past-the-end (see @ref end()) iterator is returned. @complexity Logarithmic in the size of the JSON object. @liveexample{The example shows how `find()` is used.,find__key_type} @sa see @ref contains(KeyT&&) const -- checks whether a key exists @since version 1.0.0 */ template iterator find(KeyT&& key) { auto result = end(); if (is_object()) { result.m_it.object_iterator = m_value.object->find(std::forward(key)); } return result; } /*! @brief find an element in a JSON object @copydoc find(KeyT&&) */ template const_iterator find(KeyT&& key) const { auto result = cend(); if (is_object()) { result.m_it.object_iterator = m_value.object->find(std::forward(key)); } return result; } /*! @brief returns the number of occurrences of a key in a JSON object Returns the number of elements with key @a key. If ObjectType is the default `std::map` type, the return value will always be `0` (@a key was not found) or `1` (@a key was found). @note This method always returns `0` when executed on a JSON type that is not an object. @param[in] key key value of the element to count @return Number of elements with key @a key. If the JSON value is not an object, the return value will be `0`. @complexity Logarithmic in the size of the JSON object. @liveexample{The example shows how `count()` is used.,count} @since version 1.0.0 */ template size_type count(KeyT&& key) const { // return 0 for all nonobject types return is_object() ? m_value.object->count(std::forward(key)) : 0; } /*! @brief check the existence of an element in a JSON object Check whether an element exists in a JSON object with key equivalent to @a key. If the element is not found or the JSON value is not an object, false is returned. @note This method always returns false when executed on a JSON type that is not an object. @param[in] key key value to check its existence. @return true if an element with specified @a key exists. If no such element with such key is found or the JSON value is not an object, false is returned. @complexity Logarithmic in the size of the JSON object. @liveexample{The following code shows an example for `contains()`.,contains} @sa see @ref find(KeyT&&) -- returns an iterator to an object element @sa see @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer @since version 3.6.0 */ template < typename KeyT, typename std::enable_if < !std::is_same::type, json_pointer>::value, int >::type = 0 > bool contains(KeyT && key) const { return is_object() && m_value.object->find(std::forward(key)) != m_value.object->end(); } /*! @brief check the existence of an element in a JSON object given a JSON pointer Check whether the given JSON pointer @a ptr can be resolved in the current JSON value. @note This method can be executed on any JSON value type. @param[in] ptr JSON pointer to check its existence. @return true if the JSON pointer can be resolved to a stored value, false otherwise. @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`. @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @complexity Logarithmic in the size of the JSON object. @liveexample{The following code shows an example for `contains()`.,contains_json_pointer} @sa see @ref contains(KeyT &&) const -- checks the existence of a key @since version 3.7.0 */ bool contains(const json_pointer& ptr) const { return ptr.contains(this); } /// @} /////////////// // iterators // /////////////// /// @name iterators /// @{ /*! @brief returns an iterator to the first element Returns an iterator to the first element. @image html range-begin-end.svg "Illustration from cppreference.com" @return iterator to the first element @complexity Constant. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is constant. @liveexample{The following code shows an example for `begin()`.,begin} @sa see @ref cbegin() -- returns a const iterator to the beginning @sa see @ref end() -- returns an iterator to the end @sa see @ref cend() -- returns a const iterator to the end @since version 1.0.0 */ iterator begin() noexcept { iterator result(this); result.set_begin(); return result; } /*! @copydoc basic_json::cbegin() */ const_iterator begin() const noexcept { return cbegin(); } /*! @brief returns a const iterator to the first element Returns a const iterator to the first element. @image html range-begin-end.svg "Illustration from cppreference.com" @return const iterator to the first element @complexity Constant. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is constant. - Has the semantics of `const_cast(*this).begin()`. @liveexample{The following code shows an example for `cbegin()`.,cbegin} @sa see @ref begin() -- returns an iterator to the beginning @sa see @ref end() -- returns an iterator to the end @sa see @ref cend() -- returns a const iterator to the end @since version 1.0.0 */ const_iterator cbegin() const noexcept { const_iterator result(this); result.set_begin(); return result; } /*! @brief returns an iterator to one past the last element Returns an iterator to one past the last element. @image html range-begin-end.svg "Illustration from cppreference.com" @return iterator one past the last element @complexity Constant. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is constant. @liveexample{The following code shows an example for `end()`.,end} @sa see @ref cend() -- returns a const iterator to the end @sa see @ref begin() -- returns an iterator to the beginning @sa see @ref cbegin() -- returns a const iterator to the beginning @since version 1.0.0 */ iterator end() noexcept { iterator result(this); result.set_end(); return result; } /*! @copydoc basic_json::cend() */ const_iterator end() const noexcept { return cend(); } /*! @brief returns a const iterator to one past the last element Returns a const iterator to one past the last element. @image html range-begin-end.svg "Illustration from cppreference.com" @return const iterator one past the last element @complexity Constant. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is constant. - Has the semantics of `const_cast(*this).end()`. @liveexample{The following code shows an example for `cend()`.,cend} @sa see @ref end() -- returns an iterator to the end @sa see @ref begin() -- returns an iterator to the beginning @sa see @ref cbegin() -- returns a const iterator to the beginning @since version 1.0.0 */ const_iterator cend() const noexcept { const_iterator result(this); result.set_end(); return result; } /*! @brief returns an iterator to the reverse-beginning Returns an iterator to the reverse-beginning; that is, the last element. @image html range-rbegin-rend.svg "Illustration from cppreference.com" @complexity Constant. @requirement This function helps `basic_json` satisfying the [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirements: - The complexity is constant. - Has the semantics of `reverse_iterator(end())`. @liveexample{The following code shows an example for `rbegin()`.,rbegin} @sa see @ref crbegin() -- returns a const reverse iterator to the beginning @sa see @ref rend() -- returns a reverse iterator to the end @sa see @ref crend() -- returns a const reverse iterator to the end @since version 1.0.0 */ reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } /*! @copydoc basic_json::crbegin() */ const_reverse_iterator rbegin() const noexcept { return crbegin(); } /*! @brief returns an iterator to the reverse-end Returns an iterator to the reverse-end; that is, one before the first element. @image html range-rbegin-rend.svg "Illustration from cppreference.com" @complexity Constant. @requirement This function helps `basic_json` satisfying the [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirements: - The complexity is constant. - Has the semantics of `reverse_iterator(begin())`. @liveexample{The following code shows an example for `rend()`.,rend} @sa see @ref crend() -- returns a const reverse iterator to the end @sa see @ref rbegin() -- returns a reverse iterator to the beginning @sa see @ref crbegin() -- returns a const reverse iterator to the beginning @since version 1.0.0 */ reverse_iterator rend() noexcept { return reverse_iterator(begin()); } /*! @copydoc basic_json::crend() */ const_reverse_iterator rend() const noexcept { return crend(); } /*! @brief returns a const reverse iterator to the last element Returns a const iterator to the reverse-beginning; that is, the last element. @image html range-rbegin-rend.svg "Illustration from cppreference.com" @complexity Constant. @requirement This function helps `basic_json` satisfying the [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirements: - The complexity is constant. - Has the semantics of `const_cast(*this).rbegin()`. @liveexample{The following code shows an example for `crbegin()`.,crbegin} @sa see @ref rbegin() -- returns a reverse iterator to the beginning @sa see @ref rend() -- returns a reverse iterator to the end @sa see @ref crend() -- returns a const reverse iterator to the end @since version 1.0.0 */ const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); } /*! @brief returns a const reverse iterator to one before the first Returns a const reverse iterator to the reverse-end; that is, one before the first element. @image html range-rbegin-rend.svg "Illustration from cppreference.com" @complexity Constant. @requirement This function helps `basic_json` satisfying the [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirements: - The complexity is constant. - Has the semantics of `const_cast(*this).rend()`. @liveexample{The following code shows an example for `crend()`.,crend} @sa see @ref rend() -- returns a reverse iterator to the end @sa see @ref rbegin() -- returns a reverse iterator to the beginning @sa see @ref crbegin() -- returns a const reverse iterator to the beginning @since version 1.0.0 */ const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); } public: /*! @brief wrapper to access iterator member functions in range-based for This function allows to access @ref iterator::key() and @ref iterator::value() during range-based for loops. In these loops, a reference to the JSON values is returned, so there is no access to the underlying iterator. For loop without iterator_wrapper: @code{cpp} for (auto it = j_object.begin(); it != j_object.end(); ++it) { std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; } @endcode Range-based for loop without iterator proxy: @code{cpp} for (auto it : j_object) { // "it" is of type json::reference and has no key() member std::cout << "value: " << it << '\n'; } @endcode Range-based for loop with iterator proxy: @code{cpp} for (auto it : json::iterator_wrapper(j_object)) { std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; } @endcode @note When iterating over an array, `key()` will return the index of the element as string (see example). @param[in] ref reference to a JSON value @return iteration proxy object wrapping @a ref with an interface to use in range-based for loops @liveexample{The following code shows how the wrapper is used,iterator_wrapper} @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes in the JSON value. @complexity Constant. @note The name of this function is not yet final and may change in the future. @deprecated This stream operator is deprecated and will be removed in future 4.0.0 of the library. Please use @ref items() instead; that is, replace `json::iterator_wrapper(j)` with `j.items()`. */ JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) static iteration_proxy iterator_wrapper(reference ref) noexcept { return ref.items(); } /*! @copydoc iterator_wrapper(reference) */ JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) static iteration_proxy iterator_wrapper(const_reference ref) noexcept { return ref.items(); } /*! @brief helper to access iterator member functions in range-based for This function allows to access @ref iterator::key() and @ref iterator::value() during range-based for loops. In these loops, a reference to the JSON values is returned, so there is no access to the underlying iterator. For loop without `items()` function: @code{cpp} for (auto it = j_object.begin(); it != j_object.end(); ++it) { std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; } @endcode Range-based for loop without `items()` function: @code{cpp} for (auto it : j_object) { // "it" is of type json::reference and has no key() member std::cout << "value: " << it << '\n'; } @endcode Range-based for loop with `items()` function: @code{cpp} for (auto& el : j_object.items()) { std::cout << "key: " << el.key() << ", value:" << el.value() << '\n'; } @endcode The `items()` function also allows to use [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding) (C++17): @code{cpp} for (auto& [key, val] : j_object.items()) { std::cout << "key: " << key << ", value:" << val << '\n'; } @endcode @note When iterating over an array, `key()` will return the index of the element as string (see example). For primitive types (e.g., numbers), `key()` returns an empty string. @warning Using `items()` on temporary objects is dangerous. Make sure the object's lifetime exeeds the iteration. See for more information. @return iteration proxy object wrapping @a ref with an interface to use in range-based for loops @liveexample{The following code shows how the function is used.,items} @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes in the JSON value. @complexity Constant. @since version 3.1.0, structured bindings support since 3.5.0. */ iteration_proxy items() noexcept { return iteration_proxy(*this); } /*! @copydoc items() */ iteration_proxy items() const noexcept { return iteration_proxy(*this); } /// @} ////////////// // capacity // ////////////// /// @name capacity /// @{ /*! @brief checks whether the container is empty. Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). @return The return value depends on the different types and is defined as follows: Value type | return value ----------- | ------------- null | `true` boolean | `false` string | `false` number | `false` binary | `false` object | result of function `object_t::empty()` array | result of function `array_t::empty()` @liveexample{The following code uses `empty()` to check if a JSON object contains any elements.,empty} @complexity Constant, as long as @ref array_t and @ref object_t satisfy the Container concept; that is, their `empty()` functions have constant complexity. @iterators No changes. @exceptionsafety No-throw guarantee: this function never throws exceptions. @note This function does not return whether a string stored as JSON value is empty - it returns whether the JSON container itself is empty which is false in the case of a string. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is constant. - Has the semantics of `begin() == end()`. @sa see @ref size() -- returns the number of elements @since version 1.0.0 */ bool empty() const noexcept { switch (m_type) { case value_t::null: { // null values are empty return true; } case value_t::array: { // delegate call to array_t::empty() return m_value.array->empty(); } case value_t::object: { // delegate call to object_t::empty() return m_value.object->empty(); } case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { // all other types are nonempty return false; } } } /*! @brief returns the number of elements Returns the number of elements in a JSON value. @return The return value depends on the different types and is defined as follows: Value type | return value ----------- | ------------- null | `0` boolean | `1` string | `1` number | `1` binary | `1` object | result of function object_t::size() array | result of function array_t::size() @liveexample{The following code calls `size()` on the different value types.,size} @complexity Constant, as long as @ref array_t and @ref object_t satisfy the Container concept; that is, their size() functions have constant complexity. @iterators No changes. @exceptionsafety No-throw guarantee: this function never throws exceptions. @note This function does not return the length of a string stored as JSON value - it returns the number of elements in the JSON value which is 1 in the case of a string. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is constant. - Has the semantics of `std::distance(begin(), end())`. @sa see @ref empty() -- checks whether the container is empty @sa see @ref max_size() -- returns the maximal number of elements @since version 1.0.0 */ size_type size() const noexcept { switch (m_type) { case value_t::null: { // null values are empty return 0; } case value_t::array: { // delegate call to array_t::size() return m_value.array->size(); } case value_t::object: { // delegate call to object_t::size() return m_value.object->size(); } case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { // all other types have size 1 return 1; } } } /*! @brief returns the maximum possible number of elements Returns the maximum number of elements a JSON value is able to hold due to system or library implementation limitations, i.e. `std::distance(begin(), end())` for the JSON value. @return The return value depends on the different types and is defined as follows: Value type | return value ----------- | ------------- null | `0` (same as `size()`) boolean | `1` (same as `size()`) string | `1` (same as `size()`) number | `1` (same as `size()`) binary | `1` (same as `size()`) object | result of function `object_t::max_size()` array | result of function `array_t::max_size()` @liveexample{The following code calls `max_size()` on the different value types. Note the output is implementation specific.,max_size} @complexity Constant, as long as @ref array_t and @ref object_t satisfy the Container concept; that is, their `max_size()` functions have constant complexity. @iterators No changes. @exceptionsafety No-throw guarantee: this function never throws exceptions. @requirement This function helps `basic_json` satisfying the [Container](https://en.cppreference.com/w/cpp/named_req/Container) requirements: - The complexity is constant. - Has the semantics of returning `b.size()` where `b` is the largest possible JSON value. @sa see @ref size() -- returns the number of elements @since version 1.0.0 */ size_type max_size() const noexcept { switch (m_type) { case value_t::array: { // delegate call to array_t::max_size() return m_value.array->max_size(); } case value_t::object: { // delegate call to object_t::max_size() return m_value.object->max_size(); } case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { // all other types have max_size() == size() return size(); } } } /// @} /////////////// // modifiers // /////////////// /// @name modifiers /// @{ /*! @brief clears the contents Clears the content of a JSON value and resets it to the default value as if @ref basic_json(value_t) would have been called with the current value type from @ref type(): Value type | initial value ----------- | ------------- null | `null` boolean | `false` string | `""` number | `0` binary | An empty byte vector object | `{}` array | `[]` @post Has the same effect as calling @code {.cpp} *this = basic_json(type()); @endcode @liveexample{The example below shows the effect of `clear()` to different JSON types.,clear} @complexity Linear in the size of the JSON value. @iterators All iterators, pointers and references related to this container are invalidated. @exceptionsafety No-throw guarantee: this function never throws exceptions. @sa see @ref basic_json(value_t) -- constructor that creates an object with the same value than calling `clear()` @since version 1.0.0 */ void clear() noexcept { switch (m_type) { case value_t::number_integer: { m_value.number_integer = 0; break; } case value_t::number_unsigned: { m_value.number_unsigned = 0; break; } case value_t::number_float: { m_value.number_float = 0.0; break; } case value_t::boolean: { m_value.boolean = false; break; } case value_t::string: { m_value.string->clear(); break; } case value_t::binary: { m_value.binary->clear(); break; } case value_t::array: { m_value.array->clear(); break; } case value_t::object: { m_value.object->clear(); break; } case value_t::null: case value_t::discarded: default: break; } } /*! @brief add an object to an array Appends the given element @a val to the end of the JSON value. If the function is called on a JSON null value, an empty array is created before appending @a val. @param[in] val the value to add to the JSON array @throw type_error.308 when called on a type other than JSON array or null; example: `"cannot use push_back() with number"` @complexity Amortized constant. @liveexample{The example shows how `push_back()` and `+=` can be used to add elements to a JSON array. Note how the `null` value was silently converted to a JSON array.,push_back} @since version 1.0.0 */ void push_back(basic_json&& val) { // push_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); } // transform null object into an array if (is_null()) { m_type = value_t::array; m_value = value_t::array; assert_invariant(); } // add element to array (move semantics) const auto old_capacity = m_value.array->capacity(); m_value.array->push_back(std::move(val)); set_parent(m_value.array->back(), old_capacity); // if val is moved from, basic_json move constructor marks it null so we do not call the destructor } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ reference operator+=(basic_json&& val) { push_back(std::move(val)); return *this; } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ void push_back(const basic_json& val) { // push_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); } // transform null object into an array if (is_null()) { m_type = value_t::array; m_value = value_t::array; assert_invariant(); } // add element to array const auto old_capacity = m_value.array->capacity(); m_value.array->push_back(val); set_parent(m_value.array->back(), old_capacity); } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ reference operator+=(const basic_json& val) { push_back(val); return *this; } /*! @brief add an object to an object Inserts the given element @a val to the JSON object. If the function is called on a JSON null value, an empty object is created before inserting @a val. @param[in] val the value to add to the JSON object @throw type_error.308 when called on a type other than JSON object or null; example: `"cannot use push_back() with number"` @complexity Logarithmic in the size of the container, O(log(`size()`)). @liveexample{The example shows how `push_back()` and `+=` can be used to add elements to a JSON object. Note how the `null` value was silently converted to a JSON object.,push_back__object_t__value} @since version 1.0.0 */ void push_back(const typename object_t::value_type& val) { // push_back only works for null objects or objects if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) { JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); } // transform null object into an object if (is_null()) { m_type = value_t::object; m_value = value_t::object; assert_invariant(); } // add element to object auto res = m_value.object->insert(val); set_parent(res.first->second); } /*! @brief add an object to an object @copydoc push_back(const typename object_t::value_type&) */ reference operator+=(const typename object_t::value_type& val) { push_back(val); return *this; } /*! @brief add an object to an object This function allows to use `push_back` with an initializer list. In case 1. the current value is an object, 2. the initializer list @a init contains only two elements, and 3. the first element of @a init is a string, @a init is converted into an object element and added using @ref push_back(const typename object_t::value_type&). Otherwise, @a init is converted to a JSON value and added using @ref push_back(basic_json&&). @param[in] init an initializer list @complexity Linear in the size of the initializer list @a init. @note This function is required to resolve an ambiguous overload error, because pairs like `{"key", "value"}` can be both interpreted as `object_t::value_type` or `std::initializer_list`, see https://github.com/nlohmann/json/issues/235 for more information. @liveexample{The example shows how initializer lists are treated as objects when possible.,push_back__initializer_list} */ void push_back(initializer_list_t init) { if (is_object() && init.size() == 2 && (*init.begin())->is_string()) { basic_json&& key = init.begin()->moved_or_copied(); push_back(typename object_t::value_type( std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); } else { push_back(basic_json(init)); } } /*! @brief add an object to an object @copydoc push_back(initializer_list_t) */ reference operator+=(initializer_list_t init) { push_back(init); return *this; } /*! @brief add an object to an array Creates a JSON value from the passed parameters @a args to the end of the JSON value. If the function is called on a JSON null value, an empty array is created before appending the value created from @a args. @param[in] args arguments to forward to a constructor of @ref basic_json @tparam Args compatible types to create a @ref basic_json object @return reference to the inserted element @throw type_error.311 when called on a type other than JSON array or null; example: `"cannot use emplace_back() with number"` @complexity Amortized constant. @liveexample{The example shows how `push_back()` can be used to add elements to a JSON array. Note how the `null` value was silently converted to a JSON array.,emplace_back} @since version 2.0.8, returns reference since 3.7.0 */ template reference emplace_back(Args&& ... args) { // emplace_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()), *this)); } // transform null object into an array if (is_null()) { m_type = value_t::array; m_value = value_t::array; assert_invariant(); } // add element to array (perfect forwarding) const auto old_capacity = m_value.array->capacity(); m_value.array->emplace_back(std::forward(args)...); return set_parent(m_value.array->back(), old_capacity); } /*! @brief add an object to an object if key does not exist Inserts a new element into a JSON object constructed in-place with the given @a args if there is no element with the key in the container. If the function is called on a JSON null value, an empty object is created before appending the value created from @a args. @param[in] args arguments to forward to a constructor of @ref basic_json @tparam Args compatible types to create a @ref basic_json object @return a pair consisting of an iterator to the inserted element, or the already-existing element if no insertion happened, and a bool denoting whether the insertion took place. @throw type_error.311 when called on a type other than JSON object or null; example: `"cannot use emplace() with number"` @complexity Logarithmic in the size of the container, O(log(`size()`)). @liveexample{The example shows how `emplace()` can be used to add elements to a JSON object. Note how the `null` value was silently converted to a JSON object. Further note how no value is added if there was already one value stored with the same key.,emplace} @since version 2.0.8 */ template std::pair emplace(Args&& ... args) { // emplace only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) { JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()), *this)); } // transform null object into an object if (is_null()) { m_type = value_t::object; m_value = value_t::object; assert_invariant(); } // add element to array (perfect forwarding) auto res = m_value.object->emplace(std::forward(args)...); set_parent(res.first->second); // create result iterator and set iterator to the result of emplace auto it = begin(); it.m_it.object_iterator = res.first; // return pair of iterator and boolean return {it, res.second}; } /// Helper for insertion of an iterator /// @note: This uses std::distance to support GCC 4.8, /// see https://github.com/nlohmann/json/pull/1257 template iterator insert_iterator(const_iterator pos, Args&& ... args) { iterator result(this); JSON_ASSERT(m_value.array != nullptr); auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); result.m_it.array_iterator = m_value.array->begin() + insert_pos; // This could have been written as: // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); // but the return value of insert is missing in GCC 4.8, so it is written this way instead. set_parents(); return result; } /*! @brief inserts element Inserts element @a val before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator @param[in] val element to insert @return iterator pointing to the inserted @a val. @throw type_error.309 if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @complexity Constant plus linear in the distance between @a pos and end of the container. @liveexample{The example shows how `insert()` is used.,insert} @since version 1.0.0 */ iterator insert(const_iterator pos, const basic_json& val) { // insert only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); } // insert to array and return iterator return insert_iterator(pos, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); } /*! @brief inserts element @copydoc insert(const_iterator, const basic_json&) */ iterator insert(const_iterator pos, basic_json&& val) { return insert(pos, val); } /*! @brief inserts elements Inserts @a cnt copies of @a val before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator @param[in] cnt number of copies of @a val to insert @param[in] val element to insert @return iterator pointing to the first element inserted, or @a pos if `cnt==0` @throw type_error.309 if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @complexity Linear in @a cnt plus linear in the distance between @a pos and end of the container. @liveexample{The example shows how `insert()` is used.,insert__count} @since version 1.0.0 */ iterator insert(const_iterator pos, size_type cnt, const basic_json& val) { // insert only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); } // insert to array and return iterator return insert_iterator(pos, cnt, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); } /*! @brief inserts elements Inserts elements from range `[first, last)` before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert @throw type_error.309 if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @throw invalid_iterator.210 if @a first and @a last do not belong to the same JSON value; example: `"iterators do not fit"` @throw invalid_iterator.211 if @a first or @a last are iterators into container for which insert is called; example: `"passed iterators may not belong to container"` @return iterator pointing to the first element inserted, or @a pos if `first==last` @complexity Linear in `std::distance(first, last)` plus linear in the distance between @a pos and end of the container. @liveexample{The example shows how `insert()` is used.,insert__range} @since version 1.0.0 */ iterator insert(const_iterator pos, const_iterator first, const_iterator last) { // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) { JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); } // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); } if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) { JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", *this)); } // insert to array and return iterator return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); } /*! @brief inserts elements Inserts elements from initializer list @a ilist before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator @param[in] ilist initializer list to insert the values from @throw type_error.309 if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw invalid_iterator.202 if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @return iterator pointing to the first element inserted, or @a pos if `ilist` is empty @complexity Linear in `ilist.size()` plus linear in the distance between @a pos and end of the container. @liveexample{The example shows how `insert()` is used.,insert__ilist} @since version 1.0.0 */ iterator insert(const_iterator pos, initializer_list_t ilist) { // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) { JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); } // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); } // insert to array and return iterator return insert_iterator(pos, ilist.begin(), ilist.end()); } /*! @brief inserts elements Inserts elements from range `[first, last)`. @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert @throw type_error.309 if called on JSON values other than objects; example: `"cannot use insert() with string"` @throw invalid_iterator.202 if iterator @a first or @a last does does not point to an object; example: `"iterators first and last must point to objects"` @throw invalid_iterator.210 if @a first and @a last do not belong to the same JSON value; example: `"iterators do not fit"` @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number of elements to insert. @liveexample{The example shows how `insert()` is used.,insert__range_object} @since version 3.0.0 */ void insert(const_iterator first, const_iterator last) { // insert only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); } // passed iterators must belong to objects if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) { JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", *this)); } m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); } /*! @brief updates a JSON object from another object, overwriting existing keys Inserts all values from JSON object @a j and overwrites existing keys. @param[in] j JSON object to read values from @throw type_error.312 if called on JSON values other than objects; example: `"cannot use update() with string"` @complexity O(N*log(size() + N)), where N is the number of elements to insert. @liveexample{The example shows how `update()` is used.,update} @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update @since version 3.0.0 */ void update(const_reference j) { // implicitly convert null value to an empty object if (is_null()) { m_type = value_t::object; m_value.object = create(); assert_invariant(); } if (JSON_HEDLEY_UNLIKELY(!is_object())) { JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this)); } if (JSON_HEDLEY_UNLIKELY(!j.is_object())) { JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()), *this)); } for (auto it = j.cbegin(); it != j.cend(); ++it) { m_value.object->operator[](it.key()) = it.value(); #if JSON_DIAGNOSTICS m_value.object->operator[](it.key()).m_parent = this; #endif } } /*! @brief updates a JSON object from another object, overwriting existing keys Inserts all values from from range `[first, last)` and overwrites existing keys. @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert @throw type_error.312 if called on JSON values other than objects; example: `"cannot use update() with string"` @throw invalid_iterator.202 if iterator @a first or @a last does does not point to an object; example: `"iterators first and last must point to objects"` @throw invalid_iterator.210 if @a first and @a last do not belong to the same JSON value; example: `"iterators do not fit"` @complexity O(N*log(size() + N)), where N is the number of elements to insert. @liveexample{The example shows how `update()` is used__range.,update} @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update @since version 3.0.0 */ void update(const_iterator first, const_iterator last) { // implicitly convert null value to an empty object if (is_null()) { m_type = value_t::object; m_value.object = create(); assert_invariant(); } if (JSON_HEDLEY_UNLIKELY(!is_object())) { JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this)); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); } // passed iterators must belong to objects if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object() || !last.m_object->is_object())) { JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", *this)); } for (auto it = first; it != last; ++it) { m_value.object->operator[](it.key()) = it.value(); #if JSON_DIAGNOSTICS m_value.object->operator[](it.key()).m_parent = this; #endif } } /*! @brief exchanges the values Exchanges the contents of the JSON value with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. @param[in,out] other JSON value to exchange the contents with @complexity Constant. @liveexample{The example below shows how JSON values can be swapped with `swap()`.,swap__reference} @since version 1.0.0 */ void swap(reference other) noexcept ( std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value ) { std::swap(m_type, other.m_type); std::swap(m_value, other.m_value); set_parents(); other.set_parents(); assert_invariant(); } /*! @brief exchanges the values Exchanges the contents of the JSON value from @a left with those of @a right. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. implemented as a friend function callable via ADL. @param[in,out] left JSON value to exchange the contents with @param[in,out] right JSON value to exchange the contents with @complexity Constant. @liveexample{The example below shows how JSON values can be swapped with `swap()`.,swap__reference} @since version 1.0.0 */ friend void swap(reference left, reference right) noexcept ( std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value ) { left.swap(right); } /*! @brief exchanges the values Exchanges the contents of a JSON array with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. @param[in,out] other array to exchange the contents with @throw type_error.310 when JSON value is not an array; example: `"cannot use swap() with string"` @complexity Constant. @liveexample{The example below shows how arrays can be swapped with `swap()`.,swap__array_t} @since version 1.0.0 */ void swap(array_t& other) // NOLINT(bugprone-exception-escape) { // swap only works for arrays if (JSON_HEDLEY_LIKELY(is_array())) { std::swap(*(m_value.array), other); } else { JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); } } /*! @brief exchanges the values Exchanges the contents of a JSON object with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. @param[in,out] other object to exchange the contents with @throw type_error.310 when JSON value is not an object; example: `"cannot use swap() with string"` @complexity Constant. @liveexample{The example below shows how objects can be swapped with `swap()`.,swap__object_t} @since version 1.0.0 */ void swap(object_t& other) // NOLINT(bugprone-exception-escape) { // swap only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { std::swap(*(m_value.object), other); } else { JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); } } /*! @brief exchanges the values Exchanges the contents of a JSON string with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. @param[in,out] other string to exchange the contents with @throw type_error.310 when JSON value is not a string; example: `"cannot use swap() with boolean"` @complexity Constant. @liveexample{The example below shows how strings can be swapped with `swap()`.,swap__string_t} @since version 1.0.0 */ void swap(string_t& other) // NOLINT(bugprone-exception-escape) { // swap only works for strings if (JSON_HEDLEY_LIKELY(is_string())) { std::swap(*(m_value.string), other); } else { JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); } } /*! @brief exchanges the values Exchanges the contents of a JSON string with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. @param[in,out] other binary to exchange the contents with @throw type_error.310 when JSON value is not a string; example: `"cannot use swap() with boolean"` @complexity Constant. @liveexample{The example below shows how strings can be swapped with `swap()`.,swap__binary_t} @since version 3.8.0 */ void swap(binary_t& other) // NOLINT(bugprone-exception-escape) { // swap only works for strings if (JSON_HEDLEY_LIKELY(is_binary())) { std::swap(*(m_value.binary), other); } else { JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); } } /// @copydoc swap(binary_t&) void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape) { // swap only works for strings if (JSON_HEDLEY_LIKELY(is_binary())) { std::swap(*(m_value.binary), other); } else { JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); } } /// @} public: ////////////////////////////////////////// // lexicographical comparison operators // ////////////////////////////////////////// /// @name lexicographical comparison operators /// @{ /*! @brief comparison: equal Compares two JSON values for equality according to the following rules: - Two JSON values are equal if (1) they are from the same type and (2) their stored values are the same according to their respective `operator==`. - Integer and floating-point numbers are automatically converted before comparison. Note that two NaN values are always treated as unequal. - Two JSON null values are equal. @note Floating-point inside JSON values numbers are compared with `json::number_float_t::operator==` which is `double::operator==` by default. To compare floating-point while respecting an epsilon, an alternative [comparison function](https://github.com/mariokonrad/marnav/blob/master/include/marnav/math/floatingpoint.hpp#L34-#L39) could be used, for instance @code {.cpp} template::value, T>::type> inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept { return std::abs(a - b) <= epsilon; } @endcode Or you can self-defined operator equal function like this: @code {.cpp} bool my_equal(const_reference lhs, const_reference rhs) { const auto lhs_type lhs.type(); const auto rhs_type rhs.type(); if (lhs_type == rhs_type) { switch(lhs_type) // self_defined case case value_t::number_float: return std::abs(lhs - rhs) <= std::numeric_limits::epsilon(); // other cases remain the same with the original ... } ... } @endcode @note NaN values never compare equal to themselves or to other NaN values. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether the values @a lhs and @a rhs are equal @exceptionsafety No-throw guarantee: this function never throws exceptions. @complexity Linear. @liveexample{The example demonstrates comparing several JSON types.,operator__equal} @since version 1.0.0 */ friend bool operator==(const_reference lhs, const_reference rhs) noexcept { #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" #endif const auto lhs_type = lhs.type(); const auto rhs_type = rhs.type(); if (lhs_type == rhs_type) { switch (lhs_type) { case value_t::array: return *lhs.m_value.array == *rhs.m_value.array; case value_t::object: return *lhs.m_value.object == *rhs.m_value.object; case value_t::null: return true; case value_t::string: return *lhs.m_value.string == *rhs.m_value.string; case value_t::boolean: return lhs.m_value.boolean == rhs.m_value.boolean; case value_t::number_integer: return lhs.m_value.number_integer == rhs.m_value.number_integer; case value_t::number_unsigned: return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; case value_t::number_float: return lhs.m_value.number_float == rhs.m_value.number_float; case value_t::binary: return *lhs.m_value.binary == *rhs.m_value.binary; case value_t::discarded: default: return false; } } else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) { return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; } else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) { return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); } else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) { return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; } else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) { return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); } else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) { return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; } else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) { return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); } return false; #ifdef __GNUC__ #pragma GCC diagnostic pop #endif } /*! @brief comparison: equal @copydoc operator==(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator==(const_reference lhs, ScalarType rhs) noexcept { return lhs == basic_json(rhs); } /*! @brief comparison: equal @copydoc operator==(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator==(ScalarType lhs, const_reference rhs) noexcept { return basic_json(lhs) == rhs; } /*! @brief comparison: not equal Compares two JSON values for inequality by calculating `not (lhs == rhs)`. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether the values @a lhs and @a rhs are not equal @complexity Linear. @exceptionsafety No-throw guarantee: this function never throws exceptions. @liveexample{The example demonstrates comparing several JSON types.,operator__notequal} @since version 1.0.0 */ friend bool operator!=(const_reference lhs, const_reference rhs) noexcept { return !(lhs == rhs); } /*! @brief comparison: not equal @copydoc operator!=(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept { return lhs != basic_json(rhs); } /*! @brief comparison: not equal @copydoc operator!=(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept { return basic_json(lhs) != rhs; } /*! @brief comparison: less than Compares whether one JSON value @a lhs is less than another JSON value @a rhs according to the following rules: - If @a lhs and @a rhs have the same type, the values are compared using the default `<` operator. - Integer and floating-point numbers are automatically converted before comparison - In case @a lhs and @a rhs have different types, the values are ignored and the order of the types is considered, see @ref operator<(const value_t, const value_t). @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether @a lhs is less than @a rhs @complexity Linear. @exceptionsafety No-throw guarantee: this function never throws exceptions. @liveexample{The example demonstrates comparing several JSON types.,operator__less} @since version 1.0.0 */ friend bool operator<(const_reference lhs, const_reference rhs) noexcept { const auto lhs_type = lhs.type(); const auto rhs_type = rhs.type(); if (lhs_type == rhs_type) { switch (lhs_type) { case value_t::array: // note parentheses are necessary, see // https://github.com/nlohmann/json/issues/1530 return (*lhs.m_value.array) < (*rhs.m_value.array); case value_t::object: return (*lhs.m_value.object) < (*rhs.m_value.object); case value_t::null: return false; case value_t::string: return (*lhs.m_value.string) < (*rhs.m_value.string); case value_t::boolean: return (lhs.m_value.boolean) < (rhs.m_value.boolean); case value_t::number_integer: return (lhs.m_value.number_integer) < (rhs.m_value.number_integer); case value_t::number_unsigned: return (lhs.m_value.number_unsigned) < (rhs.m_value.number_unsigned); case value_t::number_float: return (lhs.m_value.number_float) < (rhs.m_value.number_float); case value_t::binary: return (*lhs.m_value.binary) < (*rhs.m_value.binary); case value_t::discarded: default: return false; } } else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) { return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; } else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) { return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); } else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) { return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; } else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) { return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); } else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) { return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); } else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) { return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; } // We only reach this line if we cannot compare values. In that case, // we compare types. Note we have to call the operator explicitly, // because MSVC has problems otherwise. return operator<(lhs_type, rhs_type); } /*! @brief comparison: less than @copydoc operator<(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator<(const_reference lhs, ScalarType rhs) noexcept { return lhs < basic_json(rhs); } /*! @brief comparison: less than @copydoc operator<(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator<(ScalarType lhs, const_reference rhs) noexcept { return basic_json(lhs) < rhs; } /*! @brief comparison: less than or equal Compares whether one JSON value @a lhs is less than or equal to another JSON value by calculating `not (rhs < lhs)`. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether @a lhs is less than or equal to @a rhs @complexity Linear. @exceptionsafety No-throw guarantee: this function never throws exceptions. @liveexample{The example demonstrates comparing several JSON types.,operator__greater} @since version 1.0.0 */ friend bool operator<=(const_reference lhs, const_reference rhs) noexcept { return !(rhs < lhs); } /*! @brief comparison: less than or equal @copydoc operator<=(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept { return lhs <= basic_json(rhs); } /*! @brief comparison: less than or equal @copydoc operator<=(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept { return basic_json(lhs) <= rhs; } /*! @brief comparison: greater than Compares whether one JSON value @a lhs is greater than another JSON value by calculating `not (lhs <= rhs)`. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether @a lhs is greater than to @a rhs @complexity Linear. @exceptionsafety No-throw guarantee: this function never throws exceptions. @liveexample{The example demonstrates comparing several JSON types.,operator__lessequal} @since version 1.0.0 */ friend bool operator>(const_reference lhs, const_reference rhs) noexcept { return !(lhs <= rhs); } /*! @brief comparison: greater than @copydoc operator>(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator>(const_reference lhs, ScalarType rhs) noexcept { return lhs > basic_json(rhs); } /*! @brief comparison: greater than @copydoc operator>(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator>(ScalarType lhs, const_reference rhs) noexcept { return basic_json(lhs) > rhs; } /*! @brief comparison: greater than or equal Compares whether one JSON value @a lhs is greater than or equal to another JSON value by calculating `not (lhs < rhs)`. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether @a lhs is greater than or equal to @a rhs @complexity Linear. @exceptionsafety No-throw guarantee: this function never throws exceptions. @liveexample{The example demonstrates comparing several JSON types.,operator__greaterequal} @since version 1.0.0 */ friend bool operator>=(const_reference lhs, const_reference rhs) noexcept { return !(lhs < rhs); } /*! @brief comparison: greater than or equal @copydoc operator>=(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept { return lhs >= basic_json(rhs); } /*! @brief comparison: greater than or equal @copydoc operator>=(const_reference, const_reference) */ template::value, int>::type = 0> friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept { return basic_json(lhs) >= rhs; } /// @} /////////////////// // serialization // /////////////////// /// @name serialization /// @{ #ifndef JSON_NO_IO /*! @brief serialize to stream Serialize the given JSON value @a j to the output stream @a o. The JSON value will be serialized using the @ref dump member function. - The indentation of the output can be controlled with the member variable `width` of the output stream @a o. For instance, using the manipulator `std::setw(4)` on @a o sets the indentation level to `4` and the serialization result is the same as calling `dump(4)`. - The indentation character can be controlled with the member variable `fill` of the output stream @a o. For instance, the manipulator `std::setfill('\\t')` sets indentation to use a tab character rather than the default space character. @param[in,out] o stream to serialize to @param[in] j JSON value to serialize @return the stream @a o @throw type_error.316 if a string stored inside the JSON value is not UTF-8 encoded @complexity Linear. @liveexample{The example below shows the serialization with different parameters to `width` to adjust the indentation level.,operator_serialize} @since version 1.0.0; indentation character added in version 3.0.0 */ friend std::ostream& operator<<(std::ostream& o, const basic_json& j) { // read width member and use it as indentation parameter if nonzero const bool pretty_print = o.width() > 0; const auto indentation = pretty_print ? o.width() : 0; // reset width to 0 for subsequent calls to this stream o.width(0); // do the actual serialization serializer s(detail::output_adapter(o), o.fill()); s.dump(j, pretty_print, false, static_cast(indentation)); return o; } /*! @brief serialize to stream @deprecated This stream operator is deprecated and will be removed in future 4.0.0 of the library. Please use @ref operator<<(std::ostream&, const basic_json&) instead; that is, replace calls like `j >> o;` with `o << j;`. @since version 1.0.0; deprecated since version 3.0.0 */ JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) friend std::ostream& operator>>(const basic_json& j, std::ostream& o) { return o << j; } #endif // JSON_NO_IO /// @} ///////////////////// // deserialization // ///////////////////// /// @name deserialization /// @{ /*! @brief deserialize from a compatible input @tparam InputType A compatible input, for instance - an std::istream object - a FILE pointer - a C-style array of characters - a pointer to a null-terminated string of single byte characters - an object obj for which begin(obj) and end(obj) produces a valid pair of iterators. @param[in] i input to read from @param[in] cb a parser callback function of type @ref parser_callback_t which is used to control the deserialization by filtering unwanted values (optional) @param[in] allow_exceptions whether to throw exceptions in case of a parse error (optional, true by default) @param[in] ignore_comments whether comments should be ignored and treated like whitespace (true) or yield a parse error (true); (optional, false by default) @return deserialized JSON value; in case of a parse error and @a allow_exceptions set to `false`, the return value will be value_t::discarded. @throw parse_error.101 if a parse error occurs; example: `""unexpected end of input; expected string literal""` @throw parse_error.102 if to_unicode fails or surrogate error @throw parse_error.103 if to_unicode fails @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb or reading from the input @a i has a super-linear complexity. @note A UTF-8 byte order mark is silently ignored. @liveexample{The example below demonstrates the `parse()` function reading from an array.,parse__array__parser_callback_t} @liveexample{The example below demonstrates the `parse()` function with and without callback function.,parse__string__parser_callback_t} @liveexample{The example below demonstrates the `parse()` function with and without callback function.,parse__istream__parser_callback_t} @liveexample{The example below demonstrates the `parse()` function reading from a contiguous container.,parse__contiguouscontainer__parser_callback_t} @since version 2.0.3 (contiguous containers); version 3.9.0 allowed to ignore comments. */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(InputType&& i, const parser_callback_t cb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false) { basic_json result; parser(detail::input_adapter(std::forward(i)), cb, allow_exceptions, ignore_comments).parse(true, result); return result; } /*! @brief deserialize from a pair of character iterators The value_type of the iterator must be a integral type with size of 1, 2 or 4 bytes, which will be interpreted respectively as UTF-8, UTF-16 and UTF-32. @param[in] first iterator to start of character range @param[in] last iterator to end of character range @param[in] cb a parser callback function of type @ref parser_callback_t which is used to control the deserialization by filtering unwanted values (optional) @param[in] allow_exceptions whether to throw exceptions in case of a parse error (optional, true by default) @param[in] ignore_comments whether comments should be ignored and treated like whitespace (true) or yield a parse error (true); (optional, false by default) @return deserialized JSON value; in case of a parse error and @a allow_exceptions set to `false`, the return value will be value_t::discarded. @throw parse_error.101 if a parse error occurs; example: `""unexpected end of input; expected string literal""` @throw parse_error.102 if to_unicode fails or surrogate error @throw parse_error.103 if to_unicode fails */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false) { basic_json result; parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result); return result; } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) static basic_json parse(detail::span_input_adapter&& i, const parser_callback_t cb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false) { basic_json result; parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result); return result; } /*! @brief check if the input is valid JSON Unlike the @ref parse(InputType&&, const parser_callback_t,const bool) function, this function neither throws an exception in case of invalid JSON input (i.e., a parse error) nor creates diagnostic information. @tparam InputType A compatible input, for instance - an std::istream object - a FILE pointer - a C-style array of characters - a pointer to a null-terminated string of single byte characters - an object obj for which begin(obj) and end(obj) produces a valid pair of iterators. @param[in] i input to read from @param[in] ignore_comments whether comments should be ignored and treated like whitespace (true) or yield a parse error (true); (optional, false by default) @return Whether the input read from @a i is valid JSON. @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. @note A UTF-8 byte order mark is silently ignored. @liveexample{The example below demonstrates the `accept()` function reading from a string.,accept__string} */ template static bool accept(InputType&& i, const bool ignore_comments = false) { return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments).accept(true); } template static bool accept(IteratorType first, IteratorType last, const bool ignore_comments = false) { return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) static bool accept(detail::span_input_adapter&& i, const bool ignore_comments = false) { return parser(i.get(), nullptr, false, ignore_comments).accept(true); } /*! @brief generate SAX events The SAX event lister must follow the interface of @ref json_sax. This function reads from a compatible input. Examples are: - an std::istream object - a FILE pointer - a C-style array of characters - a pointer to a null-terminated string of single byte characters - an object obj for which begin(obj) and end(obj) produces a valid pair of iterators. @param[in] i input to read from @param[in,out] sax SAX event listener @param[in] format the format to parse (JSON, CBOR, MessagePack, or UBJSON) @param[in] strict whether the input has to be consumed completely @param[in] ignore_comments whether comments should be ignored and treated like whitespace (true) or yield a parse error (true); (optional, false by default); only applies to the JSON file format. @return return value of the last processed SAX event @throw parse_error.101 if a parse error occurs; example: `""unexpected end of input; expected string literal""` @throw parse_error.102 if to_unicode fails or surrogate error @throw parse_error.103 if to_unicode fails @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the SAX consumer @a sax has a super-linear complexity. @note A UTF-8 byte order mark is silently ignored. @liveexample{The example below demonstrates the `sax_parse()` function reading from string and processing the events with a user-defined SAX event consumer.,sax_parse} @since version 3.2.0 */ template JSON_HEDLEY_NON_NULL(2) static bool sax_parse(InputType&& i, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false) { auto ia = detail::input_adapter(std::forward(i)); return format == input_format_t::json ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); } template JSON_HEDLEY_NON_NULL(3) static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false) { auto ia = detail::input_adapter(std::move(first), std::move(last)); return format == input_format_t::json ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); } template JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) JSON_HEDLEY_NON_NULL(2) static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true, const bool ignore_comments = false) { auto ia = i.get(); return format == input_format_t::json // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); } #ifndef JSON_NO_IO /*! @brief deserialize from stream @deprecated This stream operator is deprecated and will be removed in version 4.0.0 of the library. Please use @ref operator>>(std::istream&, basic_json&) instead; that is, replace calls like `j << i;` with `i >> j;`. @since version 1.0.0; deprecated since version 3.0.0 */ JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) friend std::istream& operator<<(basic_json& j, std::istream& i) { return operator>>(i, j); } /*! @brief deserialize from stream Deserializes an input stream to a JSON value. @param[in,out] i input stream to read a serialized JSON value from @param[in,out] j JSON value to write the deserialized input to @throw parse_error.101 in case of an unexpected token @throw parse_error.102 if to_unicode fails or surrogate error @throw parse_error.103 if to_unicode fails @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. @note A UTF-8 byte order mark is silently ignored. @liveexample{The example below shows how a JSON value is constructed by reading a serialization from a stream.,operator_deserialize} @sa parse(std::istream&, const parser_callback_t) for a variant with a parser callback function to filter values while parsing @since version 1.0.0 */ friend std::istream& operator>>(std::istream& i, basic_json& j) { parser(detail::input_adapter(i)).parse(false, j); return i; } #endif // JSON_NO_IO /// @} /////////////////////////// // convenience functions // /////////////////////////// /*! @brief return the type as string Returns the type name as string to be used in error messages - usually to indicate that a function was called on a wrong JSON type. @return a string representation of a the @a m_type member: Value type | return value ----------- | ------------- null | `"null"` boolean | `"boolean"` string | `"string"` number | `"number"` (for all number types) object | `"object"` array | `"array"` binary | `"binary"` discarded | `"discarded"` @exceptionsafety No-throw guarantee: this function never throws exceptions. @complexity Constant. @liveexample{The following code exemplifies `type_name()` for all JSON types.,type_name} @sa see @ref type() -- return the type of the JSON value @sa see @ref operator value_t() -- return the type of the JSON value (implicit) @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` since 3.0.0 */ JSON_HEDLEY_RETURNS_NON_NULL const char* type_name() const noexcept { { switch (m_type) { case value_t::null: return "null"; case value_t::object: return "object"; case value_t::array: return "array"; case value_t::string: return "string"; case value_t::boolean: return "boolean"; case value_t::binary: return "binary"; case value_t::discarded: return "discarded"; case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: default: return "number"; } } } JSON_PRIVATE_UNLESS_TESTED: ////////////////////// // member variables // ////////////////////// /// the type of the current element value_t m_type = value_t::null; /// the value of the current element json_value m_value = {}; #if JSON_DIAGNOSTICS /// a pointer to a parent value (for debugging purposes) basic_json* m_parent = nullptr; #endif ////////////////////////////////////////// // binary serialization/deserialization // ////////////////////////////////////////// /// @name binary serialization/deserialization support /// @{ public: /*! @brief create a CBOR serialization of a given JSON value Serializes a given JSON value @a j to a byte vector using the CBOR (Concise Binary Object Representation) serialization format. CBOR is a binary serialization format which aims to be more compact than JSON itself, yet more efficient to parse. The library uses the following mapping from JSON values types to CBOR types according to the CBOR specification (RFC 7049): JSON value type | value/range | CBOR type | first byte --------------- | ------------------------------------------ | ---------------------------------- | --------------- null | `null` | Null | 0xF6 boolean | `true` | True | 0xF5 boolean | `false` | False | 0xF4 number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 number_integer | -24..-1 | Negative integer | 0x20..0x37 number_integer | 0..23 | Integer | 0x00..0x17 number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B number_unsigned | 0..23 | Integer | 0x00..0x17 number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B number_float | *any value representable by a float* | Single-Precision Float | 0xFA number_float | *any value NOT representable by a float* | Double-Precision Float | 0xFB string | *length*: 0..23 | UTF-8 string | 0x60..0x77 string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B array | *size*: 0..23 | array | 0x80..0x97 array | *size*: 23..255 | array (1 byte follow) | 0x98 array | *size*: 256..65535 | array (2 bytes follow) | 0x99 array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B object | *size*: 0..23 | map | 0xA0..0xB7 object | *size*: 23..255 | map (1 byte follow) | 0xB8 object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB binary | *size*: 0..23 | byte string | 0x40..0x57 binary | *size*: 23..255 | byte string (1 byte follow) | 0x58 binary | *size*: 256..65535 | byte string (2 bytes follow) | 0x59 binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B Binary values with subtype are mapped to tagged values (0xD8..0xDB) depending on the subtype, followed by a byte string, see "binary" cells in the table above. @note The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value. @note If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the @ref dump() function which serializes NaN or Infinity to `null`. @note The following CBOR types are not used in the conversion: - UTF-8 strings terminated by "break" (0x7F) - arrays terminated by "break" (0x9F) - maps terminated by "break" (0xBF) - byte strings terminated by "break" (0x5F) - date/time (0xC0..0xC1) - bignum (0xC2..0xC3) - decimal fraction (0xC4) - bigfloat (0xC5) - expected conversions (0xD5..0xD7) - simple values (0xE0..0xF3, 0xF8) - undefined (0xF7) - half-precision floats (0xF9) - break (0xFF) @param[in] j JSON value to serialize @return CBOR serialization as byte vector @complexity Linear in the size of the JSON value @a j. @liveexample{The example shows the serialization of a JSON value to a byte vector in CBOR format.,to_cbor} @sa http://cbor.io @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the analogous deserialization @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the related UBJSON format @since version 2.0.9; compact representation of floating-point numbers since version 3.8.0 */ static std::vector to_cbor(const basic_json& j) { std::vector result; to_cbor(j, result); return result; } static void to_cbor(const basic_json& j, detail::output_adapter o) { binary_writer(o).write_cbor(j); } static void to_cbor(const basic_json& j, detail::output_adapter o) { binary_writer(o).write_cbor(j); } /*! @brief create a MessagePack serialization of a given JSON value Serializes a given JSON value @a j to a byte vector using the MessagePack serialization format. MessagePack is a binary serialization format which aims to be more compact than JSON itself, yet more efficient to parse. The library uses the following mapping from JSON values types to MessagePack types according to the MessagePack specification: JSON value type | value/range | MessagePack type | first byte --------------- | --------------------------------- | ---------------- | ---------- null | `null` | nil | 0xC0 boolean | `true` | true | 0xC3 boolean | `false` | false | 0xC2 number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 number_integer | -2147483648..-32769 | int32 | 0xD2 number_integer | -32768..-129 | int16 | 0xD1 number_integer | -128..-33 | int8 | 0xD0 number_integer | -32..-1 | negative fixint | 0xE0..0xFF number_integer | 0..127 | positive fixint | 0x00..0x7F number_integer | 128..255 | uint 8 | 0xCC number_integer | 256..65535 | uint 16 | 0xCD number_integer | 65536..4294967295 | uint 32 | 0xCE number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF number_unsigned | 0..127 | positive fixint | 0x00..0x7F number_unsigned | 128..255 | uint 8 | 0xCC number_unsigned | 256..65535 | uint 16 | 0xCD number_unsigned | 65536..4294967295 | uint 32 | 0xCE number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF number_float | *any value representable by a float* | float 32 | 0xCA number_float | *any value NOT representable by a float* | float 64 | 0xCB string | *length*: 0..31 | fixstr | 0xA0..0xBF string | *length*: 32..255 | str 8 | 0xD9 string | *length*: 256..65535 | str 16 | 0xDA string | *length*: 65536..4294967295 | str 32 | 0xDB array | *size*: 0..15 | fixarray | 0x90..0x9F array | *size*: 16..65535 | array 16 | 0xDC array | *size*: 65536..4294967295 | array 32 | 0xDD object | *size*: 0..15 | fix map | 0x80..0x8F object | *size*: 16..65535 | map 16 | 0xDE object | *size*: 65536..4294967295 | map 32 | 0xDF binary | *size*: 0..255 | bin 8 | 0xC4 binary | *size*: 256..65535 | bin 16 | 0xC5 binary | *size*: 65536..4294967295 | bin 32 | 0xC6 @note The mapping is **complete** in the sense that any JSON value type can be converted to a MessagePack value. @note The following values can **not** be converted to a MessagePack value: - strings with more than 4294967295 bytes - byte strings with more than 4294967295 bytes - arrays with more than 4294967295 elements - objects with more than 4294967295 elements @note Any MessagePack output created @ref to_msgpack can be successfully parsed by @ref from_msgpack. @note If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the @ref dump() function which serializes NaN or Infinity to `null`. @param[in] j JSON value to serialize @return MessagePack serialization as byte vector @complexity Linear in the size of the JSON value @a j. @liveexample{The example shows the serialization of a JSON value to a byte vector in MessagePack format.,to_msgpack} @sa http://msgpack.org @sa see @ref from_msgpack for the analogous deserialization @sa see @ref to_cbor(const basic_json& for the related CBOR format @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the related UBJSON format @since version 2.0.9 */ static std::vector to_msgpack(const basic_json& j) { std::vector result; to_msgpack(j, result); return result; } static void to_msgpack(const basic_json& j, detail::output_adapter o) { binary_writer(o).write_msgpack(j); } static void to_msgpack(const basic_json& j, detail::output_adapter o) { binary_writer(o).write_msgpack(j); } /*! @brief create a UBJSON serialization of a given JSON value Serializes a given JSON value @a j to a byte vector using the UBJSON (Universal Binary JSON) serialization format. UBJSON aims to be more compact than JSON itself, yet more efficient to parse. The library uses the following mapping from JSON values types to UBJSON types according to the UBJSON specification: JSON value type | value/range | UBJSON type | marker --------------- | --------------------------------- | ----------- | ------ null | `null` | null | `Z` boolean | `true` | true | `T` boolean | `false` | false | `F` number_integer | -9223372036854775808..-2147483649 | int64 | `L` number_integer | -2147483648..-32769 | int32 | `l` number_integer | -32768..-129 | int16 | `I` number_integer | -128..127 | int8 | `i` number_integer | 128..255 | uint8 | `U` number_integer | 256..32767 | int16 | `I` number_integer | 32768..2147483647 | int32 | `l` number_integer | 2147483648..9223372036854775807 | int64 | `L` number_unsigned | 0..127 | int8 | `i` number_unsigned | 128..255 | uint8 | `U` number_unsigned | 256..32767 | int16 | `I` number_unsigned | 32768..2147483647 | int32 | `l` number_unsigned | 2147483648..9223372036854775807 | int64 | `L` number_unsigned | 2147483649..18446744073709551615 | high-precision | `H` number_float | *any value* | float64 | `D` string | *with shortest length indicator* | string | `S` array | *see notes on optimized format* | array | `[` object | *see notes on optimized format* | map | `{` @note The mapping is **complete** in the sense that any JSON value type can be converted to a UBJSON value. @note The following values can **not** be converted to a UBJSON value: - strings with more than 9223372036854775807 bytes (theoretical) @note The following markers are not used in the conversion: - `Z`: no-op values are not created. - `C`: single-byte strings are serialized with `S` markers. @note Any UBJSON output created @ref to_ubjson can be successfully parsed by @ref from_ubjson. @note If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the @ref dump() function which serializes NaN or Infinity to `null`. @note The optimized formats for containers are supported: Parameter @a use_size adds size information to the beginning of a container and removes the closing marker. Parameter @a use_type further checks whether all elements of a container have the same type and adds the type marker to the beginning of the container. The @a use_type parameter must only be used together with @a use_size = true. Note that @a use_size = true alone may result in larger representations - the benefit of this parameter is that the receiving side is immediately informed on the number of elements of the container. @note If the JSON data contains the binary type, the value stored is a list of integers, as suggested by the UBJSON documentation. In particular, this means that serialization and the deserialization of a JSON containing binary values into UBJSON and back will result in a different JSON object. @param[in] j JSON value to serialize @param[in] use_size whether to add size annotations to container types @param[in] use_type whether to add type annotations to container types (must be combined with @a use_size = true) @return UBJSON serialization as byte vector @complexity Linear in the size of the JSON value @a j. @liveexample{The example shows the serialization of a JSON value to a byte vector in UBJSON format.,to_ubjson} @sa http://ubjson.org @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the analogous deserialization @sa see @ref to_cbor(const basic_json& for the related CBOR format @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format @since version 3.1.0 */ static std::vector to_ubjson(const basic_json& j, const bool use_size = false, const bool use_type = false) { std::vector result; to_ubjson(j, result, use_size, use_type); return result; } static void to_ubjson(const basic_json& j, detail::output_adapter o, const bool use_size = false, const bool use_type = false) { binary_writer(o).write_ubjson(j, use_size, use_type); } static void to_ubjson(const basic_json& j, detail::output_adapter o, const bool use_size = false, const bool use_type = false) { binary_writer(o).write_ubjson(j, use_size, use_type); } /*! @brief Serializes the given JSON object `j` to BSON and returns a vector containing the corresponding BSON-representation. BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are stored as a single entity (a so-called document). The library uses the following mapping from JSON values types to BSON types: JSON value type | value/range | BSON type | marker --------------- | --------------------------------- | ----------- | ------ null | `null` | null | 0x0A boolean | `true`, `false` | boolean | 0x08 number_integer | -9223372036854775808..-2147483649 | int64 | 0x12 number_integer | -2147483648..2147483647 | int32 | 0x10 number_integer | 2147483648..9223372036854775807 | int64 | 0x12 number_unsigned | 0..2147483647 | int32 | 0x10 number_unsigned | 2147483648..9223372036854775807 | int64 | 0x12 number_unsigned | 9223372036854775808..18446744073709551615| -- | -- number_float | *any value* | double | 0x01 string | *any value* | string | 0x02 array | *any value* | document | 0x04 object | *any value* | document | 0x03 binary | *any value* | binary | 0x05 @warning The mapping is **incomplete**, since only JSON-objects (and things contained therein) can be serialized to BSON. Also, integers larger than 9223372036854775807 cannot be serialized to BSON, and the keys may not contain U+0000, since they are serialized a zero-terminated c-strings. @throw out_of_range.407 if `j.is_number_unsigned() && j.get() > 9223372036854775807` @throw out_of_range.409 if a key in `j` contains a NULL (U+0000) @throw type_error.317 if `!j.is_object()` @pre The input `j` is required to be an object: `j.is_object() == true`. @note Any BSON output created via @ref to_bson can be successfully parsed by @ref from_bson. @param[in] j JSON value to serialize @return BSON serialization as byte vector @complexity Linear in the size of the JSON value @a j. @liveexample{The example shows the serialization of a JSON value to a byte vector in BSON format.,to_bson} @sa http://bsonspec.org/spec.html @sa see @ref from_bson(detail::input_adapter&&, const bool strict) for the analogous deserialization @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the related UBJSON format @sa see @ref to_cbor(const basic_json&) for the related CBOR format @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format */ static std::vector to_bson(const basic_json& j) { std::vector result; to_bson(j, result); return result; } /*! @brief Serializes the given JSON object `j` to BSON and forwards the corresponding BSON-representation to the given output_adapter `o`. @param j The JSON object to convert to BSON. @param o The output adapter that receives the binary BSON representation. @pre The input `j` shall be an object: `j.is_object() == true` @sa see @ref to_bson(const basic_json&) */ static void to_bson(const basic_json& j, detail::output_adapter o) { binary_writer(o).write_bson(j); } /*! @copydoc to_bson(const basic_json&, detail::output_adapter) */ static void to_bson(const basic_json& j, detail::output_adapter o) { binary_writer(o).write_bson(j); } /*! @brief create a JSON value from an input in CBOR format Deserializes a given input @a i to a JSON value using the CBOR (Concise Binary Object Representation) serialization format. The library maps CBOR types to JSON value types as follows: CBOR type | JSON value type | first byte ---------------------- | --------------- | ---------- Integer | number_unsigned | 0x00..0x17 Unsigned integer | number_unsigned | 0x18 Unsigned integer | number_unsigned | 0x19 Unsigned integer | number_unsigned | 0x1A Unsigned integer | number_unsigned | 0x1B Negative integer | number_integer | 0x20..0x37 Negative integer | number_integer | 0x38 Negative integer | number_integer | 0x39 Negative integer | number_integer | 0x3A Negative integer | number_integer | 0x3B Byte string | binary | 0x40..0x57 Byte string | binary | 0x58 Byte string | binary | 0x59 Byte string | binary | 0x5A Byte string | binary | 0x5B UTF-8 string | string | 0x60..0x77 UTF-8 string | string | 0x78 UTF-8 string | string | 0x79 UTF-8 string | string | 0x7A UTF-8 string | string | 0x7B UTF-8 string | string | 0x7F array | array | 0x80..0x97 array | array | 0x98 array | array | 0x99 array | array | 0x9A array | array | 0x9B array | array | 0x9F map | object | 0xA0..0xB7 map | object | 0xB8 map | object | 0xB9 map | object | 0xBA map | object | 0xBB map | object | 0xBF False | `false` | 0xF4 True | `true` | 0xF5 Null | `null` | 0xF6 Half-Precision Float | number_float | 0xF9 Single-Precision Float | number_float | 0xFA Double-Precision Float | number_float | 0xFB @warning The mapping is **incomplete** in the sense that not all CBOR types can be converted to a JSON value. The following CBOR types are not supported and will yield parse errors (parse_error.112): - date/time (0xC0..0xC1) - bignum (0xC2..0xC3) - decimal fraction (0xC4) - bigfloat (0xC5) - expected conversions (0xD5..0xD7) - simple values (0xE0..0xF3, 0xF8) - undefined (0xF7) @warning CBOR allows map keys of any type, whereas JSON only allows strings as keys in object values. Therefore, CBOR maps with keys other than UTF-8 strings are rejected (parse_error.113). @note Any CBOR output created @ref to_cbor can be successfully parsed by @ref from_cbor. @param[in] i an input in CBOR format convertible to an input adapter @param[in] strict whether to expect the input to be consumed until EOF (true by default) @param[in] allow_exceptions whether to throw exceptions in case of a parse error (optional, true by default) @param[in] tag_handler how to treat CBOR tags (optional, error by default) @return deserialized JSON value; in case of a parse error and @a allow_exceptions set to `false`, the return value will be value_t::discarded. @throw parse_error.110 if the given input ends prematurely or the end of file was not reached when @a strict was set to true @throw parse_error.112 if unsupported features from CBOR were used in the given input @a v or if the input is not valid CBOR @throw parse_error.113 if a string was expected as map key, but not found @complexity Linear in the size of the input @a i. @liveexample{The example shows the deserialization of a byte vector in CBOR format to a JSON value.,from_cbor} @sa http://cbor.io @sa see @ref to_cbor(const basic_json&) for the analogous serialization @sa see @ref from_msgpack(InputType&&, const bool, const bool) for the related MessagePack format @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the related UBJSON format @since version 2.0.9; parameter @a start_index since 2.1.1; changed to consume input adapters, removed start_index parameter, and added @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0; added @a tag_handler parameter since 3.9.0. */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_cbor(InputType&& i, const bool strict = true, const bool allow_exceptions = true, const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); return res ? result : basic_json(value_t::discarded); } /*! @copydoc from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_cbor(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true, const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); return res ? result : basic_json(value_t::discarded); } template JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) static basic_json from_cbor(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true, const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) static basic_json from_cbor(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true, const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); return res ? result : basic_json(value_t::discarded); } /*! @brief create a JSON value from an input in MessagePack format Deserializes a given input @a i to a JSON value using the MessagePack serialization format. The library maps MessagePack types to JSON value types as follows: MessagePack type | JSON value type | first byte ---------------- | --------------- | ---------- positive fixint | number_unsigned | 0x00..0x7F fixmap | object | 0x80..0x8F fixarray | array | 0x90..0x9F fixstr | string | 0xA0..0xBF nil | `null` | 0xC0 false | `false` | 0xC2 true | `true` | 0xC3 float 32 | number_float | 0xCA float 64 | number_float | 0xCB uint 8 | number_unsigned | 0xCC uint 16 | number_unsigned | 0xCD uint 32 | number_unsigned | 0xCE uint 64 | number_unsigned | 0xCF int 8 | number_integer | 0xD0 int 16 | number_integer | 0xD1 int 32 | number_integer | 0xD2 int 64 | number_integer | 0xD3 str 8 | string | 0xD9 str 16 | string | 0xDA str 32 | string | 0xDB array 16 | array | 0xDC array 32 | array | 0xDD map 16 | object | 0xDE map 32 | object | 0xDF bin 8 | binary | 0xC4 bin 16 | binary | 0xC5 bin 32 | binary | 0xC6 ext 8 | binary | 0xC7 ext 16 | binary | 0xC8 ext 32 | binary | 0xC9 fixext 1 | binary | 0xD4 fixext 2 | binary | 0xD5 fixext 4 | binary | 0xD6 fixext 8 | binary | 0xD7 fixext 16 | binary | 0xD8 negative fixint | number_integer | 0xE0-0xFF @note Any MessagePack output created @ref to_msgpack can be successfully parsed by @ref from_msgpack. @param[in] i an input in MessagePack format convertible to an input adapter @param[in] strict whether to expect the input to be consumed until EOF (true by default) @param[in] allow_exceptions whether to throw exceptions in case of a parse error (optional, true by default) @return deserialized JSON value; in case of a parse error and @a allow_exceptions set to `false`, the return value will be value_t::discarded. @throw parse_error.110 if the given input ends prematurely or the end of file was not reached when @a strict was set to true @throw parse_error.112 if unsupported features from MessagePack were used in the given input @a i or if the input is not valid MessagePack @throw parse_error.113 if a string was expected as map key, but not found @complexity Linear in the size of the input @a i. @liveexample{The example shows the deserialization of a byte vector in MessagePack format to a JSON value.,from_msgpack} @sa http://msgpack.org @sa see @ref to_msgpack(const basic_json&) for the analogous serialization @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the related CBOR format @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the related UBJSON format @sa see @ref from_bson(InputType&&, const bool, const bool) for the related BSON format @since version 2.0.9; parameter @a start_index since 2.1.1; changed to consume input adapters, removed start_index parameter, and added @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0 */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_msgpack(InputType&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } /*! @copydoc from_msgpack(InputType&&, const bool, const bool) */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_msgpack(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } template JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) static basic_json from_msgpack(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) { return from_msgpack(ptr, ptr + len, strict, allow_exceptions); } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) static basic_json from_msgpack(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } /*! @brief create a JSON value from an input in UBJSON format Deserializes a given input @a i to a JSON value using the UBJSON (Universal Binary JSON) serialization format. The library maps UBJSON types to JSON value types as follows: UBJSON type | JSON value type | marker ----------- | --------------------------------------- | ------ no-op | *no value, next value is read* | `N` null | `null` | `Z` false | `false` | `F` true | `true` | `T` float32 | number_float | `d` float64 | number_float | `D` uint8 | number_unsigned | `U` int8 | number_integer | `i` int16 | number_integer | `I` int32 | number_integer | `l` int64 | number_integer | `L` high-precision number | number_integer, number_unsigned, or number_float - depends on number string | 'H' string | string | `S` char | string | `C` array | array (optimized values are supported) | `[` object | object (optimized values are supported) | `{` @note The mapping is **complete** in the sense that any UBJSON value can be converted to a JSON value. @param[in] i an input in UBJSON format convertible to an input adapter @param[in] strict whether to expect the input to be consumed until EOF (true by default) @param[in] allow_exceptions whether to throw exceptions in case of a parse error (optional, true by default) @return deserialized JSON value; in case of a parse error and @a allow_exceptions set to `false`, the return value will be value_t::discarded. @throw parse_error.110 if the given input ends prematurely or the end of file was not reached when @a strict was set to true @throw parse_error.112 if a parse error occurs @throw parse_error.113 if a string could not be parsed successfully @complexity Linear in the size of the input @a i. @liveexample{The example shows the deserialization of a byte vector in UBJSON format to a JSON value.,from_ubjson} @sa http://ubjson.org @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the analogous serialization @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the related CBOR format @sa see @ref from_msgpack(InputType&&, const bool, const bool) for the related MessagePack format @sa see @ref from_bson(InputType&&, const bool, const bool) for the related BSON format @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0 */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_ubjson(InputType&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } /*! @copydoc from_ubjson(InputType&&, const bool, const bool) */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_ubjson(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } template JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) static basic_json from_ubjson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) { return from_ubjson(ptr, ptr + len, strict, allow_exceptions); } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) static basic_json from_ubjson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } /*! @brief Create a JSON value from an input in BSON format Deserializes a given input @a i to a JSON value using the BSON (Binary JSON) serialization format. The library maps BSON record types to JSON value types as follows: BSON type | BSON marker byte | JSON value type --------------- | ---------------- | --------------------------- double | 0x01 | number_float string | 0x02 | string document | 0x03 | object array | 0x04 | array binary | 0x05 | binary undefined | 0x06 | still unsupported ObjectId | 0x07 | still unsupported boolean | 0x08 | boolean UTC Date-Time | 0x09 | still unsupported null | 0x0A | null Regular Expr. | 0x0B | still unsupported DB Pointer | 0x0C | still unsupported JavaScript Code | 0x0D | still unsupported Symbol | 0x0E | still unsupported JavaScript Code | 0x0F | still unsupported int32 | 0x10 | number_integer Timestamp | 0x11 | still unsupported 128-bit decimal float | 0x13 | still unsupported Max Key | 0x7F | still unsupported Min Key | 0xFF | still unsupported @warning The mapping is **incomplete**. The unsupported mappings are indicated in the table above. @param[in] i an input in BSON format convertible to an input adapter @param[in] strict whether to expect the input to be consumed until EOF (true by default) @param[in] allow_exceptions whether to throw exceptions in case of a parse error (optional, true by default) @return deserialized JSON value; in case of a parse error and @a allow_exceptions set to `false`, the return value will be value_t::discarded. @throw parse_error.114 if an unsupported BSON record type is encountered @complexity Linear in the size of the input @a i. @liveexample{The example shows the deserialization of a byte vector in BSON format to a JSON value.,from_bson} @sa http://bsonspec.org/spec.html @sa see @ref to_bson(const basic_json&) for the analogous serialization @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the related CBOR format @sa see @ref from_msgpack(InputType&&, const bool, const bool) for the related MessagePack format @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the related UBJSON format */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_bson(InputType&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::forward(i)); const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } /*! @copydoc from_bson(InputType&&, const bool, const bool) */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_bson(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = detail::input_adapter(std::move(first), std::move(last)); const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } template JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) static basic_json from_bson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) { return from_bson(ptr, ptr + len, strict, allow_exceptions); } JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) static basic_json from_bson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); auto ia = i.get(); // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } /// @} ////////////////////////// // JSON Pointer support // ////////////////////////// /// @name JSON Pointer functions /// @{ /*! @brief access specified element via JSON Pointer Uses a JSON pointer to retrieve a reference to the respective JSON value. No bound checking is performed. Similar to @ref operator[](const typename object_t::key_type&), `null` values are created in arrays and objects if necessary. In particular: - If the JSON pointer points to an object key that does not exist, it is created an filled with a `null` value before a reference to it is returned. - If the JSON pointer points to an array index that does not exist, it is created an filled with a `null` value before a reference to it is returned. All indices between the current maximum and the given index are also filled with `null`. - The special value `-` is treated as a synonym for the index past the end. @param[in] ptr a JSON pointer @return reference to the element pointed to by @a ptr @complexity Constant. @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,operatorjson_pointer} @since version 2.0.0 */ reference operator[](const json_pointer& ptr) { return ptr.get_unchecked(this); } /*! @brief access specified element via JSON Pointer Uses a JSON pointer to retrieve a reference to the respective JSON value. No bound checking is performed. The function does not change the JSON value; no `null` values are created. In particular, the special value `-` yields an exception. @param[in] ptr JSON pointer to the desired element @return const reference to the element pointed to by @a ptr @complexity Constant. @throw parse_error.106 if an array index begins with '0' @throw parse_error.109 if an array index was not a number @throw out_of_range.402 if the array index '-' is used @throw out_of_range.404 if the JSON pointer can not be resolved @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} @since version 2.0.0 */ const_reference operator[](const json_pointer& ptr) const { return ptr.get_unchecked(this); } /*! @brief access specified element via JSON Pointer Returns a reference to the element at with specified JSON pointer @a ptr, with bounds checking. @param[in] ptr JSON pointer to the desired element @return reference to the element pointed to by @a ptr @throw parse_error.106 if an array index in the passed JSON pointer @a ptr begins with '0'. See example below. @throw parse_error.109 if an array index in the passed JSON pointer @a ptr is not a number. See example below. @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr is out of range. See example below. @throw out_of_range.402 if the array index '-' is used in the passed JSON pointer @a ptr. As `at` provides checked access (and no elements are implicitly inserted), the index '-' is always invalid. See example below. @throw out_of_range.403 if the JSON pointer describes a key of an object which cannot be found. See example below. @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. See example below. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes in the JSON value. @complexity Constant. @since version 2.0.0 @liveexample{The behavior is shown in the example.,at_json_pointer} */ reference at(const json_pointer& ptr) { return ptr.get_checked(this); } /*! @brief access specified element via JSON Pointer Returns a const reference to the element at with specified JSON pointer @a ptr, with bounds checking. @param[in] ptr JSON pointer to the desired element @return reference to the element pointed to by @a ptr @throw parse_error.106 if an array index in the passed JSON pointer @a ptr begins with '0'. See example below. @throw parse_error.109 if an array index in the passed JSON pointer @a ptr is not a number. See example below. @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr is out of range. See example below. @throw out_of_range.402 if the array index '-' is used in the passed JSON pointer @a ptr. As `at` provides checked access (and no elements are implicitly inserted), the index '-' is always invalid. See example below. @throw out_of_range.403 if the JSON pointer describes a key of an object which cannot be found. See example below. @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. See example below. @exceptionsafety Strong guarantee: if an exception is thrown, there are no changes in the JSON value. @complexity Constant. @since version 2.0.0 @liveexample{The behavior is shown in the example.,at_json_pointer_const} */ const_reference at(const json_pointer& ptr) const { return ptr.get_checked(this); } /*! @brief return flattened JSON value The function creates a JSON object whose keys are JSON pointers (see [RFC 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all primitive. The original JSON value can be restored using the @ref unflatten() function. @return an object that maps JSON pointers to primitive values @note Empty objects and arrays are flattened to `null` and will not be reconstructed correctly by the @ref unflatten() function. @complexity Linear in the size the JSON value. @liveexample{The following code shows how a JSON object is flattened to an object whose keys consist of JSON pointers.,flatten} @sa see @ref unflatten() for the reverse function @since version 2.0.0 */ basic_json flatten() const { basic_json result(value_t::object); json_pointer::flatten("", *this, result); return result; } /*! @brief unflatten a previously flattened JSON value The function restores the arbitrary nesting of a JSON value that has been flattened before using the @ref flatten() function. The JSON value must meet certain constraints: 1. The value must be an object. 2. The keys must be JSON pointers (see [RFC 6901](https://tools.ietf.org/html/rfc6901)) 3. The mapped values must be primitive JSON types. @return the original JSON from a flattened version @note Empty objects and arrays are flattened by @ref flatten() to `null` values and can not unflattened to their original type. Apart from this example, for a JSON value `j`, the following is always true: `j == j.flatten().unflatten()`. @complexity Linear in the size the JSON value. @throw type_error.314 if value is not an object @throw type_error.315 if object values are not primitive @liveexample{The following code shows how a flattened JSON object is unflattened into the original nested JSON object.,unflatten} @sa see @ref flatten() for the reverse function @since version 2.0.0 */ basic_json unflatten() const { return json_pointer::unflatten(*this); } /// @} ////////////////////////// // JSON Patch functions // ////////////////////////// /// @name JSON Patch functions /// @{ /*! @brief applies a JSON patch [JSON Patch](http://jsonpatch.com) defines a JSON document structure for expressing a sequence of operations to apply to a JSON) document. With this function, a JSON Patch is applied to the current JSON value by executing all operations from the patch. @param[in] json_patch JSON patch document @return patched document @note The application of a patch is atomic: Either all operations succeed and the patched document is returned or an exception is thrown. In any case, the original value is not changed: the patch is applied to a copy of the value. @throw parse_error.104 if the JSON patch does not consist of an array of objects @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory attributes are missing); example: `"operation add must have member path"` @throw out_of_range.401 if an array index is out of range. @throw out_of_range.403 if a JSON pointer inside the patch could not be resolved successfully in the current JSON value; example: `"key baz not found"` @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", "move") @throw other_error.501 if "test" operation was unsuccessful @complexity Linear in the size of the JSON value and the length of the JSON patch. As usually only a fraction of the JSON value is affected by the patch, the complexity can usually be neglected. @liveexample{The following code shows how a JSON patch is applied to a value.,patch} @sa see @ref diff -- create a JSON patch by comparing two JSON values @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) @since version 2.0.0 */ basic_json patch(const basic_json& json_patch) const { // make a working copy to apply the patch to basic_json result = *this; // the valid JSON Patch operations enum class patch_operations {add, remove, replace, move, copy, test, invalid}; const auto get_op = [](const std::string & op) { if (op == "add") { return patch_operations::add; } if (op == "remove") { return patch_operations::remove; } if (op == "replace") { return patch_operations::replace; } if (op == "move") { return patch_operations::move; } if (op == "copy") { return patch_operations::copy; } if (op == "test") { return patch_operations::test; } return patch_operations::invalid; }; // wrapper for "add" operation; add value at ptr const auto operation_add = [&result](json_pointer & ptr, basic_json val) { // adding to the root of the target document means replacing it if (ptr.empty()) { result = val; return; } // make sure the top element of the pointer exists json_pointer top_pointer = ptr.top(); if (top_pointer != ptr) { result.at(top_pointer); } // get reference to parent of JSON pointer ptr const auto last_path = ptr.back(); ptr.pop_back(); basic_json& parent = result[ptr]; switch (parent.m_type) { case value_t::null: case value_t::object: { // use operator[] to add value parent[last_path] = val; break; } case value_t::array: { if (last_path == "-") { // special case: append to back parent.push_back(val); } else { const auto idx = json_pointer::array_index(last_path); if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) { // avoid undefined behavior JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", parent)); } // default case: insert add offset parent.insert(parent.begin() + static_cast(idx), val); } break; } // if there exists a parent it cannot be primitive case value_t::string: // LCOV_EXCL_LINE case value_t::boolean: // LCOV_EXCL_LINE case value_t::number_integer: // LCOV_EXCL_LINE case value_t::number_unsigned: // LCOV_EXCL_LINE case value_t::number_float: // LCOV_EXCL_LINE case value_t::binary: // LCOV_EXCL_LINE case value_t::discarded: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE } }; // wrapper for "remove" operation; remove value at ptr const auto operation_remove = [this, &result](json_pointer & ptr) { // get reference to parent of JSON pointer ptr const auto last_path = ptr.back(); ptr.pop_back(); basic_json& parent = result.at(ptr); // remove child if (parent.is_object()) { // perform range check auto it = parent.find(last_path); if (JSON_HEDLEY_LIKELY(it != parent.end())) { parent.erase(it); } else { JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found", *this)); } } else if (parent.is_array()) { // note erase performs range check parent.erase(json_pointer::array_index(last_path)); } }; // type check: top level value must be an array if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) { JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", json_patch)); } // iterate and apply the operations for (const auto& val : json_patch) { // wrapper to get a value for an operation const auto get_value = [&val](const std::string & op, const std::string & member, bool string_type) -> basic_json & { // find value auto it = val.m_value.object->find(member); // context-sensitive error message const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; // check if desired value is present if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'", val)); } // check if result is of type string if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'", val)); } // no error: return value return it->second; }; // type check: every element of the array must be an object if (JSON_HEDLEY_UNLIKELY(!val.is_object())) { JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", val)); } // collect mandatory members const auto op = get_value("op", "op", true).template get(); const auto path = get_value(op, "path", true).template get(); json_pointer ptr(path); switch (get_op(op)) { case patch_operations::add: { operation_add(ptr, get_value("add", "value", false)); break; } case patch_operations::remove: { operation_remove(ptr); break; } case patch_operations::replace: { // the "path" location must exist - use at() result.at(ptr) = get_value("replace", "value", false); break; } case patch_operations::move: { const auto from_path = get_value("move", "from", true).template get(); json_pointer from_ptr(from_path); // the "from" location must exist - use at() basic_json v = result.at(from_ptr); // The move operation is functionally identical to a // "remove" operation on the "from" location, followed // immediately by an "add" operation at the target // location with the value that was just removed. operation_remove(from_ptr); operation_add(ptr, v); break; } case patch_operations::copy: { const auto from_path = get_value("copy", "from", true).template get(); const json_pointer from_ptr(from_path); // the "from" location must exist - use at() basic_json v = result.at(from_ptr); // The copy is functionally identical to an "add" // operation at the target location using the value // specified in the "from" member. operation_add(ptr, v); break; } case patch_operations::test: { bool success = false; JSON_TRY { // check if "value" matches the one at "path" // the "path" location must exist - use at() success = (result.at(ptr) == get_value("test", "value", false)); } JSON_INTERNAL_CATCH (out_of_range&) { // ignore out of range errors: success remains false } // throw an exception if test fails if (JSON_HEDLEY_UNLIKELY(!success)) { JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump(), val)); } break; } case patch_operations::invalid: default: { // op must be "add", "remove", "replace", "move", "copy", or // "test" JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid", val)); } } } return result; } /*! @brief creates a diff as a JSON patch Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can be changed into the value @a target by calling @ref patch function. @invariant For two JSON values @a source and @a target, the following code yields always `true`: @code {.cpp} source.patch(diff(source, target)) == target; @endcode @note Currently, only `remove`, `add`, and `replace` operations are generated. @param[in] source JSON value to compare from @param[in] target JSON value to compare against @param[in] path helper value to create JSON pointers @return a JSON patch to convert the @a source to @a target @complexity Linear in the lengths of @a source and @a target. @liveexample{The following code shows how a JSON patch is created as a diff for two JSON values.,diff} @sa see @ref patch -- apply a JSON patch @sa see @ref merge_patch -- apply a JSON Merge Patch @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) @since version 2.0.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json diff(const basic_json& source, const basic_json& target, const std::string& path = "") { // the patch basic_json result(value_t::array); // if the values are the same, return empty patch if (source == target) { return result; } if (source.type() != target.type()) { // different types: replace value result.push_back( { {"op", "replace"}, {"path", path}, {"value", target} }); return result; } switch (source.type()) { case value_t::array: { // first pass: traverse common elements std::size_t i = 0; while (i < source.size() && i < target.size()) { // recursive call to compare array values at index i auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); result.insert(result.end(), temp_diff.begin(), temp_diff.end()); ++i; } // i now reached the end of at least one array // in a second pass, traverse the remaining elements // remove my remaining elements const auto end_index = static_cast(result.size()); while (i < source.size()) { // add operations in reverse order to avoid invalid // indices result.insert(result.begin() + end_index, object( { {"op", "remove"}, {"path", path + "/" + std::to_string(i)} })); ++i; } // add other remaining elements while (i < target.size()) { result.push_back( { {"op", "add"}, {"path", path + "/-"}, {"value", target[i]} }); ++i; } break; } case value_t::object: { // first pass: traverse this object's elements for (auto it = source.cbegin(); it != source.cend(); ++it) { // escape the key name to be used in a JSON patch const auto path_key = path + "/" + detail::escape(it.key()); if (target.find(it.key()) != target.end()) { // recursive call to compare object values at key it auto temp_diff = diff(it.value(), target[it.key()], path_key); result.insert(result.end(), temp_diff.begin(), temp_diff.end()); } else { // found a key that is not in o -> remove it result.push_back(object( { {"op", "remove"}, {"path", path_key} })); } } // second pass: traverse other object's elements for (auto it = target.cbegin(); it != target.cend(); ++it) { if (source.find(it.key()) == source.end()) { // found a key that is not in this -> add it const auto path_key = path + "/" + detail::escape(it.key()); result.push_back( { {"op", "add"}, {"path", path_key}, {"value", it.value()} }); } } break; } case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: { // both primitive type: replace value result.push_back( { {"op", "replace"}, {"path", path}, {"value", target} }); break; } } return result; } /// @} //////////////////////////////// // JSON Merge Patch functions // //////////////////////////////// /// @name JSON Merge Patch functions /// @{ /*! @brief applies a JSON Merge Patch The merge patch format is primarily intended for use with the HTTP PATCH method as a means of describing a set of modifications to a target resource's content. This function applies a merge patch to the current JSON value. The function implements the following algorithm from Section 2 of [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396): ``` define MergePatch(Target, Patch): if Patch is an Object: if Target is not an Object: Target = {} // Ignore the contents and set it to an empty Object for each Name/Value pair in Patch: if Value is null: if Name exists in Target: remove the Name/Value pair from Target else: Target[Name] = MergePatch(Target[Name], Value) return Target else: return Patch ``` Thereby, `Target` is the current object; that is, the patch is applied to the current value. @param[in] apply_patch the patch to apply @complexity Linear in the lengths of @a patch. @liveexample{The following code shows how a JSON Merge Patch is applied to a JSON document.,merge_patch} @sa see @ref patch -- apply a JSON patch @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396) @since version 3.0.0 */ void merge_patch(const basic_json& apply_patch) { if (apply_patch.is_object()) { if (!is_object()) { *this = object(); } for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it) { if (it.value().is_null()) { erase(it.key()); } else { operator[](it.key()).merge_patch(it.value()); } } } else { *this = apply_patch; } } /// @} }; /*! @brief user-defined to_string function for JSON values This function implements a user-defined to_string for JSON objects. @param[in] j a JSON object @return a std::string object */ NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j) { return j.dump(); } } // namespace nlohmann /////////////////////// // nonmember support // /////////////////////// // specialization of std::swap, and std::hash namespace std { /// hash value for JSON objects template<> struct hash { /*! @brief return a hash value for a JSON object @since version 1.0.0 */ std::size_t operator()(const nlohmann::json& j) const { return nlohmann::detail::hash(j); } }; /// specialization for std::less /// @note: do not remove the space after '<', /// see https://github.com/nlohmann/json/pull/679 template<> struct less<::nlohmann::detail::value_t> { /*! @brief compare two value_t enum values @since version 3.0.0 */ bool operator()(nlohmann::detail::value_t lhs, nlohmann::detail::value_t rhs) const noexcept { return nlohmann::detail::operator<(lhs, rhs); } }; // C++20 prohibit function specialization in the std namespace. #ifndef JSON_HAS_CPP_20 /*! @brief exchanges the values of two JSON objects @since version 1.0.0 */ template<> inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible::value&& // NOLINT(misc-redundant-expression) is_nothrow_move_assignable::value ) { j1.swap(j2); } #endif } // namespace std /*! @brief user-defined string literal for JSON values This operator implements a user-defined string literal for JSON objects. It can be used by adding `"_json"` to a string literal and returns a JSON object if no parse error occurred. @param[in] s a string representation of a JSON object @param[in] n the length of string @a s @return a JSON object @since version 1.0.0 */ JSON_HEDLEY_NON_NULL(1) inline nlohmann::json operator "" _json(const char* s, std::size_t n) { return nlohmann::json::parse(s, s + n); } /*! @brief user-defined string literal for JSON pointer This operator implements a user-defined string literal for JSON Pointers. It can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer object if no parse error occurred. @param[in] s a string representation of a JSON Pointer @param[in] n the length of string @a s @return a JSON pointer object @since version 2.0.0 */ JSON_HEDLEY_NON_NULL(1) inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) { return nlohmann::json::json_pointer(std::string(s, n)); } // #include // restore clang diagnostic settings #if defined(__clang__) #pragma clang diagnostic pop #endif // clean up #undef JSON_ASSERT #undef JSON_INTERNAL_CATCH #undef JSON_CATCH #undef JSON_THROW #undef JSON_TRY #undef JSON_PRIVATE_UNLESS_TESTED #undef JSON_HAS_CPP_11 #undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_20 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL #undef JSON_EXPLICIT #undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL // #include #undef JSON_HEDLEY_ALWAYS_INLINE #undef JSON_HEDLEY_ARM_VERSION #undef JSON_HEDLEY_ARM_VERSION_CHECK #undef JSON_HEDLEY_ARRAY_PARAM #undef JSON_HEDLEY_ASSUME #undef JSON_HEDLEY_BEGIN_C_DECLS #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE #undef JSON_HEDLEY_CLANG_HAS_BUILTIN #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE #undef JSON_HEDLEY_CLANG_HAS_EXTENSION #undef JSON_HEDLEY_CLANG_HAS_FEATURE #undef JSON_HEDLEY_CLANG_HAS_WARNING #undef JSON_HEDLEY_COMPCERT_VERSION #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK #undef JSON_HEDLEY_CONCAT #undef JSON_HEDLEY_CONCAT3 #undef JSON_HEDLEY_CONCAT3_EX #undef JSON_HEDLEY_CONCAT_EX #undef JSON_HEDLEY_CONST #undef JSON_HEDLEY_CONSTEXPR #undef JSON_HEDLEY_CONST_CAST #undef JSON_HEDLEY_CPP_CAST #undef JSON_HEDLEY_CRAY_VERSION #undef JSON_HEDLEY_CRAY_VERSION_CHECK #undef JSON_HEDLEY_C_DECL #undef JSON_HEDLEY_DEPRECATED #undef JSON_HEDLEY_DEPRECATED_FOR #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION #undef JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_DIAGNOSTIC_PUSH #undef JSON_HEDLEY_DMC_VERSION #undef JSON_HEDLEY_DMC_VERSION_CHECK #undef JSON_HEDLEY_EMPTY_BASES #undef JSON_HEDLEY_EMSCRIPTEN_VERSION #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK #undef JSON_HEDLEY_END_C_DECLS #undef JSON_HEDLEY_FLAGS #undef JSON_HEDLEY_FLAGS_CAST #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE #undef JSON_HEDLEY_GCC_HAS_BUILTIN #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE #undef JSON_HEDLEY_GCC_HAS_EXTENSION #undef JSON_HEDLEY_GCC_HAS_FEATURE #undef JSON_HEDLEY_GCC_HAS_WARNING #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK #undef JSON_HEDLEY_GCC_VERSION #undef JSON_HEDLEY_GCC_VERSION_CHECK #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE #undef JSON_HEDLEY_GNUC_HAS_BUILTIN #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE #undef JSON_HEDLEY_GNUC_HAS_EXTENSION #undef JSON_HEDLEY_GNUC_HAS_FEATURE #undef JSON_HEDLEY_GNUC_HAS_WARNING #undef JSON_HEDLEY_GNUC_VERSION #undef JSON_HEDLEY_GNUC_VERSION_CHECK #undef JSON_HEDLEY_HAS_ATTRIBUTE #undef JSON_HEDLEY_HAS_BUILTIN #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE #undef JSON_HEDLEY_HAS_EXTENSION #undef JSON_HEDLEY_HAS_FEATURE #undef JSON_HEDLEY_HAS_WARNING #undef JSON_HEDLEY_IAR_VERSION #undef JSON_HEDLEY_IAR_VERSION_CHECK #undef JSON_HEDLEY_IBM_VERSION #undef JSON_HEDLEY_IBM_VERSION_CHECK #undef JSON_HEDLEY_IMPORT #undef JSON_HEDLEY_INLINE #undef JSON_HEDLEY_INTEL_CL_VERSION #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK #undef JSON_HEDLEY_INTEL_VERSION #undef JSON_HEDLEY_INTEL_VERSION_CHECK #undef JSON_HEDLEY_IS_CONSTANT #undef JSON_HEDLEY_IS_CONSTEXPR_ #undef JSON_HEDLEY_LIKELY #undef JSON_HEDLEY_MALLOC #undef JSON_HEDLEY_MCST_LCC_VERSION #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK #undef JSON_HEDLEY_MESSAGE #undef JSON_HEDLEY_MSVC_VERSION #undef JSON_HEDLEY_MSVC_VERSION_CHECK #undef JSON_HEDLEY_NEVER_INLINE #undef JSON_HEDLEY_NON_NULL #undef JSON_HEDLEY_NO_ESCAPE #undef JSON_HEDLEY_NO_RETURN #undef JSON_HEDLEY_NO_THROW #undef JSON_HEDLEY_NULL #undef JSON_HEDLEY_PELLES_VERSION #undef JSON_HEDLEY_PELLES_VERSION_CHECK #undef JSON_HEDLEY_PGI_VERSION #undef JSON_HEDLEY_PGI_VERSION_CHECK #undef JSON_HEDLEY_PREDICT #undef JSON_HEDLEY_PRINTF_FORMAT #undef JSON_HEDLEY_PRIVATE #undef JSON_HEDLEY_PUBLIC #undef JSON_HEDLEY_PURE #undef JSON_HEDLEY_REINTERPRET_CAST #undef JSON_HEDLEY_REQUIRE #undef JSON_HEDLEY_REQUIRE_CONSTEXPR #undef JSON_HEDLEY_REQUIRE_MSG #undef JSON_HEDLEY_RESTRICT #undef JSON_HEDLEY_RETURNS_NON_NULL #undef JSON_HEDLEY_SENTINEL #undef JSON_HEDLEY_STATIC_ASSERT #undef JSON_HEDLEY_STATIC_CAST #undef JSON_HEDLEY_STRINGIFY #undef JSON_HEDLEY_STRINGIFY_EX #undef JSON_HEDLEY_SUNPRO_VERSION #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK #undef JSON_HEDLEY_TINYC_VERSION #undef JSON_HEDLEY_TINYC_VERSION_CHECK #undef JSON_HEDLEY_TI_ARMCL_VERSION #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK #undef JSON_HEDLEY_TI_CL2000_VERSION #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK #undef JSON_HEDLEY_TI_CL430_VERSION #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK #undef JSON_HEDLEY_TI_CL6X_VERSION #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK #undef JSON_HEDLEY_TI_CL7X_VERSION #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK #undef JSON_HEDLEY_TI_CLPRU_VERSION #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK #undef JSON_HEDLEY_TI_VERSION #undef JSON_HEDLEY_TI_VERSION_CHECK #undef JSON_HEDLEY_UNAVAILABLE #undef JSON_HEDLEY_UNLIKELY #undef JSON_HEDLEY_UNPREDICTABLE #undef JSON_HEDLEY_UNREACHABLE #undef JSON_HEDLEY_UNREACHABLE_RETURN #undef JSON_HEDLEY_VERSION #undef JSON_HEDLEY_VERSION_DECODE_MAJOR #undef JSON_HEDLEY_VERSION_DECODE_MINOR #undef JSON_HEDLEY_VERSION_DECODE_REVISION #undef JSON_HEDLEY_VERSION_ENCODE #undef JSON_HEDLEY_WARNING #undef JSON_HEDLEY_WARN_UNUSED_RESULT #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG #undef JSON_HEDLEY_FALL_THROUGH #endif // INCLUDE_NLOHMANN_JSON_HPP_ sqlitebrowser-sqlitebrowser-5733cb7/libs/qcustomplot-source/000077500000000000000000000000001463772530400245155ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qcustomplot-source/CMakeLists.txt000066400000000000000000000010251463772530400272530ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.12.2) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(Qt5 REQUIRED COMPONENTS Widgets PrintSupport) set(QCUSTOMPLOT_SRC qcustomplot.cpp ) set(QCUSTOMPLOT_MOC_HDR qcustomplot.h ) add_library(qcustomplot ${QCUSTOMPLOT_SRC} ${QCUSTOMPLOT_MOC_HDR} ${QCUSTOMPLOT_MOC}) target_include_directories(qcustomplot INTERFACE ${CMAKE_CURRENT_LIST_DIR}) target_link_libraries(qcustomplot Qt5::Widgets Qt5::PrintSupport) add_library(QCustomPlot::QCustomPlot ALIAS qcustomplot) sqlitebrowser-sqlitebrowser-5733cb7/libs/qcustomplot-source/GPL.txt000077500000000000000000001057551463772530400257200ustar00rootroot00000000000000 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. Copyright (C) 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: Copyright (C) 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 . sqlitebrowser-sqlitebrowser-5733cb7/libs/qcustomplot-source/changelog.txt000066400000000000000000001510201463772530400272040ustar00rootroot00000000000000#### Version 2.1.0 released on 29.03.21 #### Added features: - Compatibility up to Qt 6.0 - Tech Preview: Radial Plots (see setupPolarPlotDemo in examples project) - QCPAxisTickerDateTime can now be configured with a QTimeZone for adjusting the label display to arbitrary time zones - QCPColorGradient (and thus also QCPColorMap) now has explicit configurable NaN handling (see QCPColorGradient::setNanHandling) - added timing/benchmarking method QCustomPlot::replotTime(bool average) which returns the milliseconds per replot - QCustomPlot::plottableAt has an optional output parameter dataIndex, providing the index of the data point at the probed position - QCustomPlot::plottableAt template method allows limiting the search to the specified QCPAbstractPlottable subclass T - QCustomPlot::itemAt template method allows limiting the search to the specified QCPAbstractItem subclass T - Added Interaction flag QCP::iSelectPlottablesBeyondAxisRect, allows selection of data points very close to (and beyond of) the axes - QCPAxisTickerDateTime::dateTimeToKey(QDate &) now also takes a TimeSpec to specify the interpretation of the start-of-day - QCPAxisTickerLog now switches to linear ticks if zoomed in beyond where logarithmic ticks are reasonable - Added QCustomPlot::afterLayout signal, for user code that crucially depends on layout sizes/positions, right before the draw step during a replot Bugfixes: - Fixed bug where QCPLayer::replot wouldn't issue full replot even though invalidated buffers existed - Fixed QCPCurve bug causing rendering artifacts when using keys/values smaller than about 1e-12 in some constellations - Fixed getValueRange when used with explicit keyRange, now doesn't use key range expanded by one point to each side anymore - Fixed bug of QCPAxis tick label font size change only propagating to the layout after second call to replot - Fixed bug of QCPTextElement not respecting the configured text alignment flag (setTextFlags) - Various documentation typos and improvements Other: - QCP Now requires C++11. However, Qt4.6 compatibility is maintained in the QCP 2.x release series - QCPColorScale is now initialized with gpCold gradient preset, which prevents color maps turning black when linking them to a default-created color scale without explicitly setting a gradient - QCPLegend::clearItems is now faster in case of many legend items (>1000) - Modernized expressions and thereby avoided some warnings (e.g. nullptr and casts) - Switched to foreach (Qt macro) where possible (in preparation for switch to range-based for (C++11), soonest at next major release) - Work around Qt bug, drawing lines with pen width 1 as slow as with pen widths > 1 (polyfill instead of line algorithm, also on Normal-DPI), by using pen width 0 in such cases. - Added QCP::Interaction flag iNone=0x000 to allow explicitly specifying no interaction (Avoids QFlags::zero, which was deprecated in Qt5.14) - QCP is now compatible with defines QT_USE_QSTRINGBUILDER, QT_USE_FAST_CONCATENATION (Qt<4.8), QT_USE_FAST_OPERATOR_PLUS (Qt<4.8) #### Version 2.0.1 released on 25.06.18 #### Bugfixes: - Default filling order of QCPLayoutGrid is now foColumnsFirst instead of foRowsFirst, as intended and consistent with QCP1. Note that this also changes the indexing order of e.g. QCustomPlot::axisRect(int index), compared with 2.0.0. You can change the filling and thus indexing order yourself by calling QCPLayoutGrid::setFillOrder. - fixed bug in QCPColorMap, when using alpha in the gradient color stops. Used to draw falsely black data points when the associated data value is exactly on the first or last color stop. - QCPDataSelection::enforceType(stDataRange) would erroneously add an empty data range to the selection, if the selection was already empty. This in turn would cause isEmpty() to erroneously return false. - fixed hypothetical crash when selectTest is called on a QCPItemCurve which has all of its points at the same position Other: - Various documentation improvements and clarifications - Prevent conflict with windows.h min/max macros if user forgets to define NOMINMAX - compiling QCP shared libraries with static Qt is now easier - added defines QCUSTOMPLOT_VERSION and QCUSTOMPLOT_VERSION_STR (the same way Qt does) to provide the used QCP version number - added missing Q_DECL_OVERRIDE declarations, thus preventing warnings some compiler settings - QCPAxisTicker and subclasses are no longer copyable by value, as intended - QCPBarsGroup constructor is now explicit, as intended - Qt 5.11 compatibility #### Version 2.0.0 released on 04.09.17 #### Added major features: - Axis tick and tick label generation was completely refactored and is now handled in the QCPAxisTicker class (also see QCPAxis::setTicker). Available ticker subclasses for special uses cases: QCPAxisTicker, QCPAxisTickerFixed, QCPAxisTickerLog, QCPAxisTickerPi, QCPAxisTickerTime, QCPAxisTickerDateTime, QCPAxisTickerText - Data container is now based on QCPDataContainer template for unified data interface and significantly improved memory footprint and better performance for common use-cases, especially data adding/removing. - New data selection mechanism allows selection of single data points and data ranges for plottables. See special documentation page "data selection mechanism". - Rubber band/selection rect for data point selection and axis zooming is now available, see documentation of QCustomPlot::setSelectionRectMode and QCPSelectionRect. For this purpose, the new default layer "overlay" was introduced, which is now the top layer, and holds the QCustomPlot's QCPSelectionRect instance. - Data sharing between plottables of the same type (see setData methods taking a QSharedPointer) - OpenGL hardware acceleration is now available across all Qt versions (including Qt4) in a unified, simple interface, with QCustomPlot::setOpenGl (experimental) - QCPStatisticalBox can now display a series of statistical boxes instead of only a single one - New QCPErrorBars plottable allows attaching error bars to any one-dimensional plottable (QCPGraph has thus lost its own error-bar capability) - QCPColorMap now supports transparency via alpha in its color gradient stops, and via a dedicated cell-wise alpha map (see QCPColorMapData::setAlpha) - Layers may now be individually replotted (QCPLayer::replot), if the mode (QCPLayer::setMode) is set to lmBuffered. Mutually adjacent lmLogical layers share a single paint buffer to save resources. By default, the new topmost "overlay" layer which contains the selection rect is an lmBuffered layer. Updating the selection rect is thus very fast, independent of the plot contents. - QCPLayerable (and thus practically all objects in QCP) now have virtual methods to receive mouse press/move/release/doubleclick/wheel events. Before, only QCPLayoutElement provided them. this makes it much easier to subclass e.g. items and plottables to provide custom mouse interactions that were cumbersome and awkward with the simpler signal-based interface Added minor features: - High-DPI support for Qt versions 5.0 and up, using device pixel ratio detected by Qt (can be changed manually via QCustomPlot::setBufferDevicePixelRatio). - QCPGraph and QCPCurve can now be configured to only display every n'th scatter symbol, see ::setScatterSkip() method - QCPFinancial allows to define bar width in absolute pixels and axis rect ratio, instead of only in plot key coordinates (see QCPFinancial::setWidthType) - Range dragging/zooming can now be configured to affect more than one axis per orientation (see new overloads of QCPAxisRect::setRangeDragAxes/setRangeZoomAxes) - Added QCPTextElement (replaces QCPPlotTitle) for general texts in layouts. Provides clicked and doubleClicked signals, as replacement for the removed QCustomPlot::titleClicked/titleDoubleClicked - Export functions (QCustomPlot::savePng etc.) now support specifying the resolution that will be written to the image file header. This improves operability with other tools which respect metadata. - Replots can now be queued to the next event loop iteration with replot(QCP::rpQueuedReplot). This way you can successively ask for a replot at multiple code locations without causing redundant replots - QCPAxisRect::zoom(...) allows to zoom to a specific rectangular region given in pixel coordinates, either affecting all axes or a specified subset of axes. - QCPRange::bounded returns a bounded range, trying to preserve its size. Works with rangeChanged signal to limit the allowed range (see rangeChanged doc) - Plottable rescaleValueAxis method (and getValueRange) now take parameter inKeyRange, which allows rescaling of the value axis only with respect to data in the currently visible key range - plottableClick and plottableDoubleClick signals now carry the clicked data point index as second parameter - Added QCPAxis::scaleRange overload without "center" argument, which scales around the current axis range center - Added QCPRange::expand/expanded overloads which take only one double parameter - Plottables addToLegend/removeFromLegend methods now have overloads that take any QCPLegend, to make working with non-default legends easier (legends that are not QCustomPlot::legend) - Added QCPStatisticalBox::setWhiskerAntialiased to allow controlling antialiasing state of whiskers independently of quartile box/median line - The virtual method QCPLayoutElement::layoutChanged() now allows subclasses to react on a move of the layout element between logical positions in the parent layout, or between layouts - QCPMarginGroup::commonMargin is now virtual, to facilitate subclassing of QCPMarginGroup - QCPGraph::getPreparedData is now virtual, and thus allows subclasses to easily generate own plotted data, e.g. on-the-fly. - Added QCPRange qDebug stream operator - QCPLayoutGrid (and thus QCPLegend) can now wrap rows or columns at specified row/column counts, see setFillOrder, setWrap and the new addElement overload which doesn't have row/column index Added minor features after beta: - QCPGraph fill now renders separate fill segments when there are gaps in the graph data (created by inserting NaN values) - fractional device pixel ratios are now used, if Qt version >= 5.6 - Axes may now be dragged/zoomed individually by starting the drag/zoom on top of the axis (previously, this required additional code) - Manual minimum and maximum layout element sizes (setMinimumSize/setMaximumSize) can now affect the inner or the outer rect, see QCPLayoutElement::setSizeConstraintRect Bugfixes [Also backported to 1.3.2]: - Fixed possible crash when having a QCPGraph with scatters only and a non-transparent main/fill brush of the graph - Fixed QCPItemPixmap not updating internally cached scaled pixmap if new pixmap set with same scaled dimensions - When using log axis scale and zooming out as far as possible (~1e-280..1e280), axis doesn't end up in (via mouse) unrecoverable range with strange axis ticks anymore - Axis tick label algorithm for beautifully typeset powers now checks whether "e" in tick label is actually part of a number before converting the exponent to superscript - Fixed QCustomPlot::moveLayer performing incorrect move and possible crash in certain situations - Fixed possible crash on QCustomPlot destruction due to wrong QObject-hierarchy. Only occurs if a QCPAxisRect is removed from the normal QCustomPlot destruction hierarchy by taking it out of its layout - Fixed possible freeze when data values become infinity after coord-to-pixel transformation (e.g. maximally zoomed out log axis), and line style is not solid (e.g. dashed) or phFastPolylines is disabled - Fixed a few missing enums in meta type system, by unifying usage of Q_ENUMS, Q_FLAGS and Q_DECLARE_METATYPE Bugfixes [Not in 1.3.2]: - Fixed QCPItemLine/QCPItemStraightLine not being selectable when defining coords are many orders of magnitude (>1e8) larger than currently viewed range - Fixed/worked around crash due to bug in QPainter::drawPixmap with very large negative x/y pixel coordinates, when drawing sparse pixmap scatters - Fixed possible (but unlikely) int overflow in adaptive sampling algorithm, that could cause plot artifacts when using extremely sparse data (with respect to current key axis range). - Fixed QCPBarsGroup bug which caused stPlotCoords spacing to be wrong with vertical key axes - A QCPBars axis rescale in the main window constructor (i.e. without well-defined plot size) now falls back to a datapoint-tight rescaling instead of doing nothing (because bar width can't be determined) - Improved QCPBars stacking when using bars with very large keys and key separation at limit of double precision Bugfixes after beta: - fixed QCPCurve vertex optimization algorithm not handling log axes correctly - upon removing the inner most axis, the offset of the new inner most axis (previously second axis) is now set to the value of the removed axis, instead of leaving a gap - QCPColorMap now has a default gradient (gpCold) again, instead of an empty and thus black gradient - doc: black QCPColorMap/QCPColorGradient documentation images fixed - scatter styles ssDiamond, ssTriangle and ssTriangleInverted now get proper filling with the specified brush - fixed click signals of plottable/axes/etc. not being emitted properly - fixed uninitialized scatterSkip on QCPCurve, leading to irregular default appearance of scatter skips - fixed device pixel ratio not being implemented correctly in cached tick labels - QCPLayoutElement::setMaximum/setMinimum now is with respect to the inner rect as intended (and documented), instead of the outer rect (and this can now be changed via setSizeConstraintRect) - fixed dllimport issue on template classes when compiling as shared library with MSVC Summary of backward incompatible changes: Plottable related: - Removed QCustomPlot::addPlottable, not needed anymore as plottables now automatically register in their constructor - Removed QCustomPlot::addItem, not needed anymore as items now automatically register in their constructor - QCPAbstractPlottable::addToLegend/removeFromLegend are not virtual anymore. If your plottable requires a custom legend item, add it to the legend manually. - setData/addData method overloads of plottables have changed to facilitate data sharing and new data container (see documentation) - plottableClick and plottableDoubleClick signals now carry the clicked data point index as second parameter, and the QMouseEvent parameter has moved to third. Check all your usages of those signals, because Qt's connect method only reports problems during runtime! - setSelectable now not only limits what can be selected by the user, but limits also any programmatic selection changes via setSelected. - enum QCPAbstractPlottable::SignDomain has changed namespace to QCP::SignDomain Axis related: - Removed QCPAxis::setAutoTicks, setAutoTickCount, setAutoTickLabels, setAutoTickStep, setAutoSubTicks, setTickLabelType, setDateTimeFormat, setDateTimeSpec, setTickStep, setTickVector, setTickVectorLabels, setSubTickCount in favor of new QCPAxisTicker-based interface - Added QCPAxis::setSubTicks to enable/disable subticks (manually controlling the subtick count needs subclassing of QCPAxisTicker, e.g. QCPAxisTickerText and QCPAxisTickerLog provide setSubTickCount) Item related: - Renamed QCPAbstractItem::rectSelectTest to rectDistance, to prevent confusion with new QCPAbstractPlottable1D::selectTestRect - Renamed QCPItemAnchor::pixelPoint to QCPItemAnchor::pixelPosition (also affects subclass QCPItemPosition) General: - Renamed QCustomPlot::RefreshPriority enums (parameter of the replot() method): rpImmediate to rpImmediateRefresh, rpQueued to rpQueuedRefresh, rpHint to rpRefreshHint - Renamed QCustomPlot::PlottingHint enum phForceRepaint to phImmediateRefresh - Removed QCPPlotTitle layout element (See new QCPTextElement for almost drop-in replacement) - Removed signals QCustomPlot::titleClicked/titleDoubleClicked, replaced by QCPTextElement signals clicked/doubleClicked. - QCustomPlot::savePdf has changed parameters from (fileName, bool noCosmeticPen, width, height,...) to (fileName, width, height, QCP::ExportPen exportPen,...) - Virtual methods QCPLayoutElement::mouseMoveEvent/mouseReleaseEvent (which are now introduced already in the superclass QCPLayerable) have gained an additional parameter const QPointF &startPos. If you have reimplemented these methods, make sure to update your function signatures, otherwise your reimplementations will likely be ignored by the compiler without warning - Creating a new QCPColorGradient without supplying a preset parameter in the constructor now creates an empty gradient, instead of loading the gpCold preset Other: - Replaced usage of Qt's QVector2D with own QCPVector2D which uses double precision and offers some convenience functions - Extended relative range to which QCPItemLine/QCPItemStraightLine can be zoomed before vanishing from ~1e9 to ~1e16 - Removed QCPItemStraightLine::distToStraightLine (replaced by QCPVector2D::distanceToStraightLine) - Removed QCPAbstractPlottable::distSqrToLine and QCPAbstractItem::distSqrToLine (replaced by QCPVector2D::distanceSquaredToLine) - Qt5.5 compatibility (If you use PDF export, test your outputs, as output dimensions might change when switching Qt versions -- QCP does not try to emulate previous Qt version behaviour here) - QCP now includes instead of just because some users had problems with the latter. Please report if you now experience issues due to the new include. - QCPGraph can now use a brush (filled polygon under the graph data) without having a graph line (line style lsNone) - QCPFinancial is now two-colored (setTwoColored(true)) by default, and has green/red as default two-colored brushes and pens - Plottable pixelsToCoords/coordsToPixels methods are now public, and offer transformations from pixel to plot coordinates and vice versa, using the plottable's axes - Plottable getKeyRange/getValueRange methods are now public - QCPBarsGroup now always places the QCPBars that was added to the group first towards lower keys, independent of axis orientation or direction (the ordering used to flip with axis orientation) - Default focus policy for QCustomPlot is now Qt::ClickFocus, instead of Qt::NoFocus. - tweaked QCPLegend and QCPAbstractLegendItem margins: The items have by default zero own margins, and QCPLegend row- and column spacing was increased to compensate. Legend was made slightly denser by default. - Used doxygen version is now 1.8.12, and documentation/postprocessing-scripts were adapted accordingly. Expect minor issues and some warnings when using older doxygen. Other after beta: - Integrated OpenGL support (QCustomPlot::setOpenGl) is experimental for now, due the strong dependency on the system/graphics driver of the current implementation - fixed some plot title font sizes in the example projects that were too small due to switch to QCPTextElement - added missing override specifiers on reimplemented virtual methods - changed to more intuitive defaults for QCPSelectionDecorator scatter style (now doesn't define an own scatter pen by default) #### Version 1.3.2 released on 22.12.15 #### Bugfixes [Backported from 2.0.0 branch]: - Fixed possible crash when having a QCPGraph with scatters only and a non-transparent main/fill brush of the graph - Fixed QCPItemPixmap not updating internally cached scaled pixmap if new pixmap set with same scaled dimensions - When using log axis scale and zooming out as far as possible (~1e-280..1e280), axis doesn't end up in (via mouse) unrecoverable range with strange axis ticks anymore - Axis tick label algorithm for beautifully typeset powers now checks whether "e" in tick label is actually part of a number before converting the exponent to superscript - Fixed QCustomPlot::moveLayer performing incorrect move and possible crash in certain situations - Fixed possible crash on QCustomPlot destruction due to wrong QObject-hierarchy. Only occurs if a QCPAxisRect is removed from the normal QCustomPlot destruction hierarchy by taking it out of its layout - Fixed possible freeze when data values become infinity after coord-to-pixel transformation (e.g. maximally zoomed out log axis), and line style is not solid (e.g. dashed) or phFastPolylines is disabled Other [Backported from 2.0.0 branch]: - A few documentation fixes/improvements - Qt5.5 compatibility (If you use PDF export, test your outputs, as output dimensions might change when switching Qt versions -- QCP does not try to emulate previous Qt version behaviour here) - QCP now includes instead of just because some users had problems with the latter. Please report if you now experience issues due to the new include. #### Version 1.3.1 released on 25.04.15 #### Bugfixes: - Fixed bug that prevented automatic axis rescaling when some graphs/curves had only NaN data points - Improved QCPItemBracket selection boundaries, especially bsCurly and bsCalligraphic - Fixed bug of axis rect and colorscale background shifted downward by one logical pixel (visible in scaled png and pdf export) - Replot upon mouse release is now only performed if a selection change has actually happened (improves responsivity on particularly complex plots) - Fixed bug that allowed scatter-only graphs to be selected by clicking the non-existent line between scatters - Fixed crash when trying to select a scatter-only QCPGraph whose only points in the visible key range are at identical key coordinates and vertically off-screen, with adaptive sampling enabled - Fixed pdf export of QCPColorMap with enabled interpolation (didn't appear interpolated in pdf) - Reduced QCPColorMap jitter of internal cell boundaries for small sized maps when viewed with high zoom, by applying oversampling factors dependant on map size - Fixed bug of QCPColorMap::fill() not causing the buffered internal image map to be updated, and thus the change didn't become visible immediately - Axis labels with size set in pixels (setPixelSize) instead of points now correctly calculate the exponent's font size if beautifully typeset powers are enabled - Fixed QCPColorMap appearing at the wrong position for logarithmic axes and color map spanning larger ranges Other: - Pdf export used to embed entire QCPColorMaps, potentially leading to large files. Now only the visible portion of the map is embedded in the pdf - Many documentation fixes and extensions, style modernization - Reduced documentation file size (and thus full package size) by automatically reducing image palettes during package build - Fixed MSVC warning message (at warning level 4) due to temporary QLists in some foreach statements #### Version 1.3.0 released on 27.12.14 #### Added features: - New plottable class QCPFinancial allows display of candlestick/ohlc data - New class QCPBarsGroup allows horizontal grouping of multiple QCPBars plottables - Added QCPBars feature allowing non-zero base values (see property QCPBars::setBaseValue) - Added QCPBars width type, for more flexible bar widths (see property QCPBars::setWidthType) - New QCPCurve optimization algorithm, fixes bug which caused line flicker at deep zoom into curve segment - Item positions can now have different position types and anchors for their x and y coordinates (QCPItemPosition::setTypeX/Y, setParentAnchorX/Y) - QCPGraph and QCPCurve can now display gaps in their lines, when inserting quiet NaNs as values (std::numeric_limits::quiet_NaN()) - QCPAxis now supports placing the tick labels inside the axis rect, for particularly space saving plots (QCPAxis::setTickLabelSide) Added features after beta: - Made code compatible with QT_NO_CAST_FROM_ASCII, QT_NO_CAST_TO_ASCII - Added compatibility with QT_NO_KEYWORDS after sending code files through a simple reg-ex script - Added possibility to inject own QCPAxis(-subclasses) via second, optional QCPAxisRect::addAxis parameter - Added parameter to QCPItemPixmap::setScaled to specify transformation mode Bugfixes: - Fixed bug in QCPCurve rendering of very zoomed-in curves (via new optimization algorithm) - Fixed conflict with MSVC-specific keyword "interface" in text-document-integration example - Fixed QCPScatterStyle bug ignoring the specified pen in the custom scatter shape constructor - Fixed bug (possible crash) during QCustomPlot teardown, when a QCPLegend that has no parent layout (i.e. was removed from layout manually) gets deleted Bugfixes after beta: - Fixed bug of QCPColorMap/QCPColorGradient colors being off by one color sampling step (only noticeable in special cases) - Fixed bug of QCPGraph adaptive sampling on vertical key axis, causing staggered look - Fixed low (float) precision in QCPCurve optimization algorithm, by not using QVector2D anymore Other: - Qt 5.3 and Qt 5.4 compatibility #### Version 1.2.1 released on 07.04.14 #### Bugfixes: - Fixed regression which garbled date-time tick labels on axes, if setTickLabelType is ltDateTime and setNumberFormat contains the "b" option #### Version 1.2.0 released on 14.03.14 #### Added features: - Adaptive Sampling for QCPGraph greatly improves performance for high data densities (see QCPGraph::setAdaptiveSampling) - QCPColorMap plottable with QCPColorScale layout element allows plotting of 2D color maps - QCustomPlot::savePdf now has additional optional parameters pdfCreator and pdfTitle to set according PDF metadata fields - QCustomPlot::replot now allows specifying whether the widget update is immediate (repaint) or queued (update) - QCPRange operators +, -, *, / with double operand for range shifting and scaling, and ==, != for range comparison - Layers now have a visibility property (QCPLayer::setVisible) - static functions QCPAxis::opposite and QCPAxis::orientation now offer more convenience when handling axis types - added notification signals for selectability change (selectableChanged) on all objects that have a selected/selectable property - added notification signal for QCPAxis scaleType property - added notification signal QCPLayerable::layerChanged Bugfixes: - Fixed assert halt, when QCPAxis auto tick labels not disabled but nevertheless a custom non-number tick label ending in "e" given - Fixed painting glitches when QCustomPlot resized inside a QMdiArea or under certain conditions inside a QLayout - If changing QCPAxis::scaleType and thus causing range sanitizing and a range modification, rangeChanged wouldn't be emitted - Fixed documentation bug that caused indentation to be lost in code examples Bugfixes after beta: - Fixed bug that caused crash if clicked-on legend item is removed in mousePressEvent. - On some systems, font size defaults to -1, which used to cause a debug output in QCPAxisPainterPrivate::TickLabelDataQCP. Now it's checked before setting values based on the default font size. - When using multiple axes on one side, setting one to invisible didn't properly compress the freed space. - Fixed bug that allowed selection of plottables when clicking in the bottom or top margin of a QCPAxisRect (outside the inner rect) Other: - In method QCPAbstractPlottable::getKeyRange/getValueRange, renamed parameter "validRange" to "foundRange", to better reflect its meaning (and contrast it from QCPRange::validRange) - QCPAxis low-level axis painting methods exported to QCPAxisPainterPrivate #### Version 1.1.1 released on 09.12.13 #### Bugfixes: - Fixed bug causing legends blocking input events from reaching underlying axis rect even if legend is invisible - Added missing Q_PROPERTY for QCPAxis::setDateTimeSpec - Fixed behaviour of QCPAxisRect::setupFullAxesBox (now transfers more properties from bottom/left to top/right axes and sets visibility of bottom/left axes to true) - Made sure PDF export doesn't default to grayscale output on some systems Other: - Plotting hint QCP::phForceRepaint is now enabled on all systems (and not only on windows) by default - Documentation improvements #### Version 1.1.0 released on 04.11.13 #### Added features: - Added QCPRange::expand and QCPRange::expanded - Added QCPAxis::rescale to rescale axis to all associated plottables - Added QCPAxis::setDateTimeSpec/dateTimeSpec to allow axis labels either in UTC or local time - QCPAxis now additionally emits a rangeChanged signal overload that provides the old range as second parameter Bugfixes: - Fixed QCustomPlot::rescaleAxes not rescaling properly if first plottable has an empty range - QCPGraph::rescaleAxes/rescaleKeyAxis/rescaleValueAxis are no longer virtual (never were in base class, was a mistake) - Fixed bugs in QCPAxis::items and QCPAxisRect::items not properly returning associated items and potentially stalling Other: - Internal change from QWeakPointer to QPointer, thus got rid of deprecated Qt functionality - Qt5.1 and Qt5.2 (beta1) compatibility - Release packages now extract to single subdirectory and don't place multiple files in current working directory #### Version 1.0.1 released on 05.09.13 #### Bugfixes: - using define flag QCUSTOMPLOT_CHECK_DATA caused debug output when data was correct, instead of invalid (fixed QCP::isInvalidData) - documentation images are now properly shown when viewed with Qt Assistant - fixed various documentation mistakes Other: - Adapted documentation style sheet to better match Qt5 documentation #### Version 1.0.0 released on 01.08.13 #### Quick Summary: - Layout system for multiple axis rects in one plot - Multiple axes per side - Qt5 compatibility - More flexible and consistent scatter configuration with QCPScatterStyle - Various interface cleanups/refactoring - Pixmap-cached axis labels for improved replot performance Changes that break backward compatibility: - QCustomPlot::axisRect() changed meaning due to the extensive changes to how axes and axis rects are handled it now returns a pointer to a QCPAxisRect and takes an integer index as parameter. - QCPAxis constructor changed to now take QCPAxisRect* as parent - setAutoMargin, setMarginLeft/Right/Top/Bottom removed due to the axis rect changes (see QCPAxisRect::setMargins/setAutoMargins) - setAxisRect removed due to the axis rect changes - setAxisBackground(-Scaled/-ScaledMode) now moved to QCPAxisRect as setBackground(-Scaled/ScaledMode) (access via QCustomPlot::axisRects()) - QCPLegend now is a QCPLayoutElement - QCPAbstractPlottable::drawLegendIcon parameter "rect" changed from QRect to QRectF - QCPAbstractLegendItem::draw second parameter removed (position/size now handled via QCPLayoutElement base class) - removed QCPLegend::setMargin/setMarginLeft/Right/Top/Bottom (now inherits the capability from QCPLayoutElement::setMargins) - removed QCPLegend::setMinimumSize (now inherits the capability from QCPLayoutElement::setMinimumSize) - removed enum QCPLegend::PositionStyle, QCPLegend::positionStyle/setPositionStyle/position/setPosition (replaced by capabilities of QCPLayoutInset) - QCPLegend transformed to work with new layout system (almost everything changed) - removed entire title interface: QCustomPlot::setTitle/setTitleFont/setTitleColor/setTitleSelected/setTitleSelectedFont/setTitleSelectedColor and the QCustomPlot::iSelectTitle interaction flag (all functionality is now given by the layout element "QCPPlotTitle" which can be added to the plot layout) - selectTest functions now take two additional parameters: bool onlySelectable and QVariant *details=0 - selectTest functions now ignores visibility of objects and (if parameter onlySelectable is true) does not anymore ignore selectability of the object - moved QCustomPlot::Interaction/Interactions to QCP namespace as QCP::Interaction/Interactions - moved QCustomPlot::setupFullAxesBox() to QCPAxisRect::setupFullAxesBox. Now also accepts parameter to decide whether to connect opposite axis ranges - moved range dragging/zooming interface from QCustomPlot to QCPAxisRect (setRangeDrag, setRangeZoom, setRangeDragAxes, setRangeZoomAxes,...) - rangeDrag/Zoom is now set to Qt::Horizontal|Qt::Vertical instead of 0 by default, on the other hand, iRangeDrag/Zoom is unset in interactions by default (this makes enabling dragging/zooming easier by just adding the interaction flags) - QCPScatterStyle takes over everything related to handling scatters in all plottables - removed setScatterPen/Size on QCPGraph and QCPCurve, removed setOutlierPen/Size on QCPStatisticalBox (now handled via QCPScatterStyle) - modified setScatterStyle on QCPGraph and QCPCurve, and setOutlierStyle on QCPStatisticalBox, to take QCPScatterStyle - axis grid and subgrid are now reachable via the QCPGrid *QCPAxis::grid() method. (e.g. instead of xAxis->setGrid(true), write xAxis->grid()->setVisible(true)) Added features: - Axis tick labels are now pixmap-cached, thus increasing replot performance (in usual setups by about 24%). See plotting hint phCacheLabels which is set by default - Advanced layout system, including the classes QCPLayoutElement, QCPLayout, QCPLayoutGrid, QCPLayoutInset, QCPAxisRect - QCustomPlot::axisRects() returns all the axis rects in the QCustomPlot. - QCustomPlot::plotLayout() returns the top level layout (initially a QCPLayoutGrid with one QCPAxisRect inside) - QCPAxis now may have an offset to the axis rect (setOffset) - Multiple axes per QCPAxisRect side are now supported (see QCPAxisRect::addAxis) - QCustomPlot::toPixmap renders the plot into a pixmap and returns it - When setting tick label rotation to +90 or -90 degrees on a vertical axis, the labels are now centered vertically on the tick height (This allows space saving vertical tick labels by having the text direction parallel to the axis) - Substantially increased replot performance when using very large manual tick vectors (> 10000 ticks) via QCPAxis::setTickVector - QCPAxis and QCPAxisRect now allow easy access to all plottables(), graphs() and items() that are associated with them - Added QCustomPlot::hasItem method for consistency with plottable interface, hasPlottable - Added QCPAxisRect::setMinimumMargins as replacement for hardcoded minimum axis margin (15 px) when auto margin is enabled - Added Flags type QCPAxis::AxisTypes (from QCPAxis::AxisType), used in QCPAxisRect interface - Automatic margin calculation can now be enabled/disabled on a per-side basis, see QCPAxisRect::setAutoMargins - QCPAxisRect margins of multiple axis rects can be coupled via QCPMarginGroup - Added new default layers "background" and "legend" (QCPAxisRect draws its background on the "background" layer, QCPLegend is on the "legend" layer by default) - Custom scatter style via QCP::ssCustom and respective setCustomScatter functions that take a QPainterPath - Filled scatters via QCPScatterStyle::setBrush Added features after beta: - Added QCustomPlot::toPainter method, to allow rendering with existing painter - QCPItemEllipse now provides a center anchor Bugfixes: - Fixed compile error on ARM - Wrong legend icons were displayed if using pixmaps for scatters that are smaller than the legend icon rect - Fixed clipping inaccuracy for rotated tick labels (were hidden too early, because the non-rotated bounding box was used) - Fixed bug that caused wrong clipping of axis ticks and subticks when the ticks were given manually by QCPAxis::setTickVector - Fixed Qt5 crash when dragging graph out of view (iterator out of bounds in QCPGraph::getVisibleDataBounds) - Fixed QCPItemText not scaling properly when using scaled raster export Bugfixes after beta: - Fixed bug that clipped the rightmost pixel column of tick labels when caching activated (only visible on windows for superscript exponents) - Restored compatibility to Qt4.6 - Restored support for -no-RTTI compilation - Empty manual tick labels are handled more gracefully (no QPainter qDebug messages anymore) - Fixed type ambiguity in QCPLineEnding::draw causing compile error on ARM - Fixed bug of grid layouts not propagating the minimum size from their child elements to the parent layout correctly - Fixed bug of child elements (e.g. axis rects) of inset layouts not properly receiving mouse events Other: - Opened up non-amalgamated project structure to public via git repository #### Version released on 09.06.12 #### Quick Summary: - Items (arrows, text,...) - Layers (easier control over rendering order) - New antialiasing system (Each objects controls own antialiasing with setAntialiased) - Performance Improvements - improved pixel-precise drawing - easier shared library creation/usage Changes that (might) break backward compatibility: - enum QCPGraph::ScatterSymbol was moved to QCP namespace (now QCP::ScatterSymbol). This replace should fix your code: "QCPGraph::ss" -> "QCP::ss" - enum QCustomPlot::AntialiasedElement and flag QCustomPlot::AntialiasedElements was moved to QCP namespace This replace should fix your code: "QCustomPlot::ae" -> "QCP::ae" - the meaning of QCustomPlot::setAntialiasedElements has changed slightly: It is now an override to force elements to be antialiased. If you want to force elements to not be drawn antialiased, use the new setNotAntialiasedElements. If an element is mentioned in neither of those functions, it now controls its antialiasing itself via its "setAntialiased" function(s). (e.g. QCPAxis::setAntialiased(bool), QCPAbstractPlottable::setAntialiased(bool), QCPAbstractPlottable::setAntialiasedScatters(bool), etc.) - QCPAxis::setTickVector and QCPAxis::setTickVectorLabels no longer take a pointer but a const reference of the respective QVector as parameter. (handing over a pointer didn't give any noticeable performance benefits but was inconsistent with the rest of the interface) - Equally QCPAxis::tickVector and QCPAxis::tickVectorLabels don't return by pointer but by value now - QCustomPlot::savePngScaled was removed, its purpose is now included as optional parameter "scale" of savePng. - If you have derived from QCPAbstractPlottable: all selectTest functions now consistently take the argument "const QPointF &pos" which is the test point in pixel coordinates. (the argument there was "double key, double value" in plot coordinates, before). - QCPAbstractPlottable, QCPAxis and QCPLegend now inherit from QCPLayerable - If you have derived from QCPAbstractPlottable: the draw method signature has changed from "draw (..) const" to "draw (..)", i.e. the method is not const anymore. This allows the draw function of your plottable to perform buffering/caching operations, if necessary. Added features: - Item system: QCPAbstractItem, QCPItemAnchor, QCPItemPosition, QCPLineEnding. Allows placing of lines, arrows, text, pixmaps etc. - New Items: QCPItemStraightLine, QCPItemLine, QCPItemCurve, QCPItemEllipse, QCPItemRect, QCPItemPixmap, QCPItemText, QCPItemBracket, QCPItemTracer - QCustomPlot::addItem/itemCount/item/removeItem/selectedItems - signals QCustomPlot::itemClicked/itemDoubleClicked - the QCustomPlot interactions property now includes iSelectItems (for selection of QCPAbstractItem) - QCPLineEnding. Represents the different styles a line/curve can end (e.g. different arrows, circle, square, bar, etc.), see e.g. QCPItemCurve::setHead - Layer system: QCPLayerable, QCPLayer. Allows more sophisticated control over drawing order and a kind of grouping. - QCPAbstractPlottable, QCPAbstractItem, QCPAxis, QCPGrid, QCPLegend are layerables and derive from QCPLayerable - QCustomPlot::addLayer/moveLayer/removeLayer/setCurrentLayer/layer/currentLayer/layerCount - Initially there are three layers: "grid", "main", and "axes". The "main" layer is initially empty and set as current layer, so new plottables/items are put there. - QCustomPlot::viewport now makes the previously inaccessible viewport rect read-only-accessible (needed that for item-interface) - PNG export now allows transparent background by calling QCustomPlot::setColor(Qt::transparent) before savePng - QCPStatisticalBox outlier symbols may now be all scatter symbols, not only hardcoded circles. - perfect precision of scatter symbol/error bar drawing and clipping in both antialiased and non-antialiased mode, by introducing QCPPainter that works around some QPainter bugs/inconveniences. Further, more complex symbols like ssCrossSquare used to look crooked, now they look good. - new antialiasing control system: Each drawing element now has its own "setAntialiased" function to control whether it is drawn antialiased. - QCustomPlot::setAntialiasedElements and QCustomPlot::setNotAntialiasedElements can be used to override the individual settings. - Subclasses of QCPAbstractPlottable can now use the convenience functions like applyFillAntialiasingHint or applyScattersAntialiasingHint to easily make their drawing code comply with the overall antialiasing system. - QCustomPlot::setNoAntialiasingOnDrag allows greatly improved performance and responsiveness by temporarily disabling all antialiasing while the user is dragging axis ranges - QCPGraph can now show scatter symbols at data points and hide its line (see QCPGraph::setScatterStyle, setScatterSize, setScatterPixmap, setLineStyle) - Grid drawing code was sourced out from QCPAxis to QCPGrid. QCPGrid is mainly an internal class and every QCPAxis owns one. The grid interface still works through QCPAxis and hasn't changed. The separation allows the grid to be drawn on a different layer as the axes, such that e.g. a graph can be above the grid but below the axes. - QCustomPlot::hasPlottable(plottable), returns whether the QCustomPlot contains the plottable - QCustomPlot::setPlottingHint/setPlottingHints, plotting hints control details about the plotting quality/speed - export to jpg and bmp added (QCustomPlot::saveJpg/saveBmp), as well as control over compression quality for png and jpg - multi-select-modifier may now be specified with QCustomPlot::setMultiSelectModifier and is not fixed to Ctrl anymore Bugfixes: - fixed QCustomPlot ignores replot after it had size (0,0) even if size becomes valid again - on Windows, a repaint used to be delayed during dragging/zooming of a complex plot, until the drag operation was done. This was fixed, i.e. repaints are forced after a replot() call. See QCP::phForceRepaint and setPlottingHints. - when using the raster paintengine and exporting to scaled PNG, pen widths are now scaled correctly (QPainter bug workaround via QCPPainter) - PDF export now respects QCustomPlot background color (QCustomPlot::setColor), also Qt::transparent - fixed a bug on QCPBars and QCPStatisticalBox where auto-rescaling of axis would fail when all data is very small (< 1e-11) - fixed mouse event propagation bug that prevented range dragging from working on KDE (GNU/Linux) - fixed a compiler warning on 64-bit systems due to pointer cast to int instead of quintptr in a qDebug output Other: - Added support for easier shared library creation (including examples for compiling and using QCustomPlot as shared library) - QCustomPlot now has the Qt::WA_OpaquePaintEvent widget attribute (gives slightly improved performance). - QCP::aeGraphs (enum QCP::AntialiasedElement, previously QCustomPlot::aeGraphs) has been marked deprecated since version 02.02.12 and was now removed. Use QCP::aePlottables instead. - optional performance-quality-tradeoff for solid graph lines (see QCustomPlot::setPlottingHints). - marked data classes and QCPRange as Q_MOVABLE_TYPE - replaced usage of own macro FUNCNAME with Qt macro Q_FUNC_INFO - QCustomPlot now returns a minimum size hint of 50*50 #### Version released on 31.03.12 #### Changes that (might) break backward compatibility: - QCPAbstractLegendItem now inherits from QObject - mousePress, mouseMove and mouseRelease signals are now emitted before and not after any QCustomPlot processing (range dragging, selecting, etc.) Added features: - Interaction system: now allows selecting of objects like plottables, axes, legend and plot title, see QCustomPlot::setInteractions documentation - Interaction system for plottables: - setSelectable, setSelected, setSelectedPen, setSelectedBrush, selectTest on QCPAbstractPlottable and all derived plottables - setSelectionTolerance on QCustomPlot - selectedPlottables and selectedGraphs on QCustomPlot (returns the list of currently selected plottables/graphs) - Interaction system for axes: - setSelectable, setSelected, setSelectedBasePen, setSelectedTickPen, setSelectedSubTickPen, setSelectedLabelFont, setSelectedTickLabelFont, setSelectedLabelColor, setSelectedTickLabelColor, selectTest on QCPAxis - selectedAxes on QCustomPlot (returns a list of the axes that currently have selected parts) - Interaction system for legend: - setSelectable, setSelected, setSelectedBorderPen, setSelectedIconBorderPen, setSelectedBrush, setSelectedFont, setSelectedTextColor, selectedItems on QCPLegend - setSelectedFont, setSelectedTextColor, setSelectable, setSelected on QCPAbstractLegendItem - selectedLegends on QCustomPlot - Interaction system for title: - setSelectedTitleFont, setSelectedTitleColor, setTitleSelected on QCustomPlot - new signals in accordance with the interaction system: - selectionChangedByUser on QCustomPlot - selectionChanged on QCPAbstractPlottable - selectionChanged on QCPAxis - selectionChanged on QCPLegend and QCPAbstractLegendItem - plottableClick, legendClick, axisClick, titleClick, plottableDoubleClick, legendDoubleClick, axisDoubleClick, titleDoubleClick on QCustomPlot - QCustomPlot::deselectAll (deselects everything, i.e. axes and plottables) - QCPAbstractPlottable::pixelsToCoords (inverse function to the already existing coordsToPixels function) - QCPRange::contains(double value) - QCPAxis::setLabelColor and setTickLabelColor - QCustomPlot::setTitleColor - QCustomPlot now emits beforeReplot and afterReplot signals. Note that it is safe to make two customPlots mutually call eachothers replot functions in one of these slots, it will not cause an infinite loop. (usefull for synchronizing axes ranges between two customPlots, because setRange alone doesn't replot) - If the Qt version is 4.7 or greater, the tick label strings in date-time-mode now support sub-second accuracy (e.g. with format like "hh:mm:ss.zzz"). Bugfixes: - tick labels/margins should no longer oscillate by one pixel when dragging range or replotting repeatedly while changing e.g. data. This was caused by a bug in Qt's QFontMetrics::boundingRect function when the font has an integer point size (probably some rounding problem). The fix hence consists of creating a temporary font (only for bounding-box calculation) which is 0.05pt larger and thus avoiding the jittering rounding outcome. - tick label, axis label and plot title colors used to be undefined. This was fixed by providing explicit color properties. Other: - fixed some glitches in the documentation - QCustomPlot::replot and QCustomPlot::rescaleAxes are now slots #### Version released on 02.02.12 #### Changes that break backward compatibility: - renamed all secondary classes from QCustomPlot[...] to QCP[...]: QCustomPlotAxis -> QCPAxis QCustomPlotGraph -> QCPGraph QCustomPlotRange -> QCPRange QCustomPlotData -> QCPData QCustomPlotDataMap -> QCPDataMap QCustomPlotLegend -> QCPLegend QCustomPlotDataMapIterator -> QCPDataMapIterator QCustomPlotDataMutableMapIterator -> QCPDataMutableMapIterator A simple search and replace on all code files should make your code run again, e.g. consider the regex "QCustomPlot(?=[AGRDL])" -> "QCP". Make sure not to just replace "QCustomPlot" with "QCP" because the main class QCustomPlot hasn't changed to QCP. This change was necessary because class names became unhandy, pardon my bad naming decision in the beginning. - QCPAxis::tickLength() and QCPAxis::subTickLength() now each split into two functions for inward and outward ticks (tickLengthIn/tickLengthOut). - QCPLegend now uses QCPAbstractLegendItem to carry item data (before, the legend was passed QCPGraphs directly) - QCustomPlot::addGraph() now doesn't return the index of the created graph anymore, but a pointer to the created QCPGraph. - QCustomPlot::setAutoAddGraphToLegend is replaced by setAutoAddPlottableToLegend Added features: - Reversed axis range with QCPAxis::setRangeReversed(bool) - Tick labels are now only drawn if not clipped by the viewport (widget border) on the sides (e.g. left and right on a horizontal axis). - Zerolines. Like grid lines only with a separate pen (QCPAxis::setZeroLinePen), at tick position zero. - Outward ticks. QCPAxis::setTickLength/setSubTickLength now accepts two arguments for inward and outward tick length. This doesn't break backward compatibility because the second argument (outward) has default value zero and thereby a call with one argument hasn't changed its meaning. - QCPGraph now inherits from QCPAbstractPlottable - QCustomPlot::addPlottable/plottable/removePlottable/clearPlottables added to interface with the new QCPAbstractPlottable-based system. The simpler interface which only acts on QCPGraphs (addGraph, graph, removeGraph, etc.) was adapted internally and is kept for backward compatibility and ease of use. - QCPLegend items for plottables (e.g. graphs) can automatically wrap their texts to fit the widths, see QCPLegend::setMinimumSize and QCPPlottableLegendItem::setTextWrap. - QCustomPlot::rescaleAxes. Adapts axis ranges to show all plottables/graphs, by calling QCPAbstractPlottable::rescaleAxes on all plottables in the plot. - QCPCurve. For plotting of parametric curves. - QCPBars. For plotting of bar charts. - QCPStatisticalBox. For statistical box plots. Bugfixes: - Fixed QCustomPlot::removeGraph(int) not being able to remove graph index 0 - made QCustomPlot::replot() abort painting when painter initialization fails (e.g. because width/height of QCustomPlot is zero) - The distance of the axis label from the axis ignored the tick label padding, this could have caused overlapping axis labels and tick labels - fixed memory leak in QCustomPlot (dtor didn't delete legend) - fixed bug that prevented QCPAxis::setRangeLower/Upper from setting the value to exactly 0. Other: - Changed default error bar handle size (QCustomPlotGraph::setErrorBarSize) from 4 to 6. - Removed QCustomPlotDataFetcher. Was deprecated and not used class. - Extended documentation, especially class descriptions. #### Version released on 15.01.12 #### Changes that (might) break backward compatibility: - QCustomPlotGraph now inherits from QObject Added features: - Added axis background pixmap (QCustomPlot::setAxisBackground, setAxisBackgroundScaled, setAxisBackgroundScaledMode) - Added width and height parameter on PDF export function QCustomPlot::savePdf(). This now allows PDF export to have arbitrary dimensions, independent of the current geometry of the QCustomPlot. - Added overload of QCustomPlot::removeGraph that takes QCustomPlotGraph* as parameter, instead the index of the graph - Added all enums to the Qt meta system via Q_ENUMS(). The enums can now be transformed to QString values easily with the Qt meta system, which makes saving state e.g. as XML significantly nicer. - added typedef QMapIterator QCustomPlotDataMapIterator and typedef QMutableMapIterator QCustomPlotDataMutableMapIterator for improved information hiding, when using iterators outside QCustomPlot code Bugfixes: - Fixed savePngScaled. Axis/label drawing functions used to reset the painter transform and thereby break savePngScaled. Now they buffer the current transform and restore it afterwards. - Fixed some glitches in the doxygen comments (affects documentation only) Other: - Changed the default tickLabelPadding of top axis from 3 to 6 pixels. Looks better. - Changed the default QCustomPlot::setAntialiasedElements setting: Graph fills are now antialiased by default. That's a bit slower, but makes fill borders look better. #### Version released on 19.11.11 #### Changes that break backward compatibility: - QCustomPlotAxis: tickFont and setTickFont renamed to tickLabelFont and setTickLabelFont (for naming consistency) Other: - QCustomPlotAxis: Added rotated tick labels, see setTickLabelRotation sqlitebrowser-sqlitebrowser-5733cb7/libs/qcustomplot-source/qcustomplot.cpp000066400000000000000000047671751463772530400276460ustar00rootroot00000000000000/*************************************************************************** ** ** ** QCustomPlot, an easy to use, modern plotting widget for Qt ** ** Copyright (C) 2011-2021 Emanuel Eichhammer ** ** ** ** 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 http://www.gnu.org/licenses/. ** ** ** **************************************************************************** ** Author: Emanuel Eichhammer ** ** Website/Contact: http://www.qcustomplot.com/ ** ** Date: 29.03.21 ** ** Version: 2.1.0 ** ****************************************************************************/ #include "qcustomplot.h" /* including file 'src/vector2d.cpp' */ /* modified 2021-03-29T02:30:44, size 7973 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPVector2D //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPVector2D \brief Represents two doubles as a mathematical 2D vector This class acts as a replacement for QVector2D with the advantage of double precision instead of single, and some convenience methods tailored for the QCustomPlot library. */ /* start documentation of inline functions */ /*! \fn void QCPVector2D::setX(double x) Sets the x coordinate of this vector to \a x. \see setY */ /*! \fn void QCPVector2D::setY(double y) Sets the y coordinate of this vector to \a y. \see setX */ /*! \fn double QCPVector2D::length() const Returns the length of this vector. \see lengthSquared */ /*! \fn double QCPVector2D::lengthSquared() const Returns the squared length of this vector. In some situations, e.g. when just trying to find the shortest vector of a group, this is faster than calculating \ref length, because it avoids calculation of a square root. \see length */ /*! \fn double QCPVector2D::angle() const Returns the angle of the vector in radians. The angle is measured between the positive x line and the vector, counter-clockwise in a mathematical coordinate system (y axis upwards positive). In screen/widget coordinates where the y axis is inverted, the angle appears clockwise. */ /*! \fn QPoint QCPVector2D::toPoint() const Returns a QPoint which has the x and y coordinates of this vector, truncating any floating point information. \see toPointF */ /*! \fn QPointF QCPVector2D::toPointF() const Returns a QPointF which has the x and y coordinates of this vector. \see toPoint */ /*! \fn bool QCPVector2D::isNull() const Returns whether this vector is null. A vector is null if \c qIsNull returns true for both x and y coordinates, i.e. if both are binary equal to 0. */ /*! \fn QCPVector2D QCPVector2D::perpendicular() const Returns a vector perpendicular to this vector, with the same length. */ /*! \fn double QCPVector2D::dot() const Returns the dot/scalar product of this vector with the specified vector \a vec. */ /* end documentation of inline functions */ /*! Creates a QCPVector2D object and initializes the x and y coordinates to 0. */ QCPVector2D::QCPVector2D() : mX(0), mY(0) { } /*! Creates a QCPVector2D object and initializes the \a x and \a y coordinates with the specified values. */ QCPVector2D::QCPVector2D(double x, double y) : mX(x), mY(y) { } /*! Creates a QCPVector2D object and initializes the x and y coordinates respective coordinates of the specified \a point. */ QCPVector2D::QCPVector2D(const QPoint &point) : mX(point.x()), mY(point.y()) { } /*! Creates a QCPVector2D object and initializes the x and y coordinates respective coordinates of the specified \a point. */ QCPVector2D::QCPVector2D(const QPointF &point) : mX(point.x()), mY(point.y()) { } /*! Normalizes this vector. After this operation, the length of the vector is equal to 1. If the vector has both entries set to zero, this method does nothing. \see normalized, length, lengthSquared */ void QCPVector2D::normalize() { if (mX == 0.0 && mY == 0.0) return; const double lenInv = 1.0/length(); mX *= lenInv; mY *= lenInv; } /*! Returns a normalized version of this vector. The length of the returned vector is equal to 1. If the vector has both entries set to zero, this method returns the vector unmodified. \see normalize, length, lengthSquared */ QCPVector2D QCPVector2D::normalized() const { if (mX == 0.0 && mY == 0.0) return *this; const double lenInv = 1.0/length(); return QCPVector2D(mX*lenInv, mY*lenInv); } /*! \overload Returns the squared shortest distance of this vector (interpreted as a point) to the finite line segment given by \a start and \a end. \see distanceToStraightLine */ double QCPVector2D::distanceSquaredToLine(const QCPVector2D &start, const QCPVector2D &end) const { const QCPVector2D v(end-start); const double vLengthSqr = v.lengthSquared(); if (!qFuzzyIsNull(vLengthSqr)) { const double mu = v.dot(*this-start)/vLengthSqr; if (mu < 0) return (*this-start).lengthSquared(); else if (mu > 1) return (*this-end).lengthSquared(); else return ((start + mu*v)-*this).lengthSquared(); } else return (*this-start).lengthSquared(); } /*! \overload Returns the squared shortest distance of this vector (interpreted as a point) to the finite line segment given by \a line. \see distanceToStraightLine */ double QCPVector2D::distanceSquaredToLine(const QLineF &line) const { return distanceSquaredToLine(QCPVector2D(line.p1()), QCPVector2D(line.p2())); } /*! Returns the shortest distance of this vector (interpreted as a point) to the infinite straight line given by a \a base point and a \a direction vector. \see distanceSquaredToLine */ double QCPVector2D::distanceToStraightLine(const QCPVector2D &base, const QCPVector2D &direction) const { return qAbs((*this-base).dot(direction.perpendicular()))/direction.length(); } /*! Scales this vector by the given \a factor, i.e. the x and y components are multiplied by \a factor. */ QCPVector2D &QCPVector2D::operator*=(double factor) { mX *= factor; mY *= factor; return *this; } /*! Scales this vector by the given \a divisor, i.e. the x and y components are divided by \a divisor. */ QCPVector2D &QCPVector2D::operator/=(double divisor) { mX /= divisor; mY /= divisor; return *this; } /*! Adds the given \a vector to this vector component-wise. */ QCPVector2D &QCPVector2D::operator+=(const QCPVector2D &vector) { mX += vector.mX; mY += vector.mY; return *this; } /*! subtracts the given \a vector from this vector component-wise. */ QCPVector2D &QCPVector2D::operator-=(const QCPVector2D &vector) { mX -= vector.mX; mY -= vector.mY; return *this; } /* end of 'src/vector2d.cpp' */ /* including file 'src/painter.cpp' */ /* modified 2021-03-29T02:30:44, size 8656 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPainter //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPainter \brief QPainter subclass used internally This QPainter subclass is used to provide some extended functionality e.g. for tweaking position consistency between antialiased and non-antialiased painting. Further it provides workarounds for QPainter quirks. \warning This class intentionally hides non-virtual functions of QPainter, e.g. setPen, save and restore. So while it is possible to pass a QCPPainter instance to a function that expects a QPainter pointer, some of the workarounds and tweaks will be unavailable to the function (because it will call the base class implementations of the functions actually hidden by QCPPainter). */ /*! Creates a new QCPPainter instance and sets default values */ QCPPainter::QCPPainter() : mModes(pmDefault), mIsAntialiasing(false) { // don't setRenderHint(QPainter::NonCosmeticDefautPen) here, because painter isn't active yet and // a call to begin() will follow } /*! Creates a new QCPPainter instance on the specified paint \a device and sets default values. Just like the analogous QPainter constructor, begins painting on \a device immediately. Like \ref begin, this method sets QPainter::NonCosmeticDefaultPen in Qt versions before Qt5. */ QCPPainter::QCPPainter(QPaintDevice *device) : QPainter(device), mModes(pmDefault), mIsAntialiasing(false) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) // before Qt5, default pens used to be cosmetic if NonCosmeticDefaultPen flag isn't set. So we set it to get consistency across Qt versions. if (isActive()) setRenderHint(QPainter::NonCosmeticDefaultPen); #endif } /*! Sets the pen of the painter and applies certain fixes to it, depending on the mode of this QCPPainter. \note this function hides the non-virtual base class implementation. */ void QCPPainter::setPen(const QPen &pen) { QPainter::setPen(pen); if (mModes.testFlag(pmNonCosmetic)) makeNonCosmetic(); } /*! \overload Sets the pen (by color) of the painter and applies certain fixes to it, depending on the mode of this QCPPainter. \note this function hides the non-virtual base class implementation. */ void QCPPainter::setPen(const QColor &color) { QPainter::setPen(color); if (mModes.testFlag(pmNonCosmetic)) makeNonCosmetic(); } /*! \overload Sets the pen (by style) of the painter and applies certain fixes to it, depending on the mode of this QCPPainter. \note this function hides the non-virtual base class implementation. */ void QCPPainter::setPen(Qt::PenStyle penStyle) { QPainter::setPen(penStyle); if (mModes.testFlag(pmNonCosmetic)) makeNonCosmetic(); } /*! \overload Works around a Qt bug introduced with Qt 4.8 which makes drawing QLineF unpredictable when antialiasing is disabled. Thus when antialiasing is disabled, it rounds the \a line to integer coordinates and then passes it to the original drawLine. \note this function hides the non-virtual base class implementation. */ void QCPPainter::drawLine(const QLineF &line) { if (mIsAntialiasing || mModes.testFlag(pmVectorized)) QPainter::drawLine(line); else QPainter::drawLine(line.toLine()); } /*! Sets whether painting uses antialiasing or not. Use this method instead of using setRenderHint with QPainter::Antialiasing directly, as it allows QCPPainter to regain pixel exactness between antialiased and non-antialiased painting (Since Qt < 5.0 uses slightly different coordinate systems for AA/Non-AA painting). */ void QCPPainter::setAntialiasing(bool enabled) { setRenderHint(QPainter::Antialiasing, enabled); if (mIsAntialiasing != enabled) { mIsAntialiasing = enabled; if (!mModes.testFlag(pmVectorized)) // antialiasing half-pixel shift only needed for rasterized outputs { if (mIsAntialiasing) translate(0.5, 0.5); else translate(-0.5, -0.5); } } } /*! Sets the mode of the painter. This controls whether the painter shall adjust its fixes/workarounds optimized for certain output devices. */ void QCPPainter::setModes(QCPPainter::PainterModes modes) { mModes = modes; } /*! Sets the QPainter::NonCosmeticDefaultPen in Qt versions before Qt5 after beginning painting on \a device. This is necessary to get cosmetic pen consistency across Qt versions, because since Qt5, all pens are non-cosmetic by default, and in Qt4 this render hint must be set to get that behaviour. The Constructor \ref QCPPainter(QPaintDevice *device) which directly starts painting also sets the render hint as appropriate. \note this function hides the non-virtual base class implementation. */ bool QCPPainter::begin(QPaintDevice *device) { bool result = QPainter::begin(device); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) // before Qt5, default pens used to be cosmetic if NonCosmeticDefaultPen flag isn't set. So we set it to get consistency across Qt versions. if (result) setRenderHint(QPainter::NonCosmeticDefaultPen); #endif return result; } /*! \overload Sets the mode of the painter. This controls whether the painter shall adjust its fixes/workarounds optimized for certain output devices. */ void QCPPainter::setMode(QCPPainter::PainterMode mode, bool enabled) { if (!enabled && mModes.testFlag(mode)) mModes &= ~mode; else if (enabled && !mModes.testFlag(mode)) mModes |= mode; } /*! Saves the painter (see QPainter::save). Since QCPPainter adds some new internal state to QPainter, the save/restore functions are reimplemented to also save/restore those members. \note this function hides the non-virtual base class implementation. \see restore */ void QCPPainter::save() { mAntialiasingStack.push(mIsAntialiasing); QPainter::save(); } /*! Restores the painter (see QPainter::restore). Since QCPPainter adds some new internal state to QPainter, the save/restore functions are reimplemented to also save/restore those members. \note this function hides the non-virtual base class implementation. \see save */ void QCPPainter::restore() { if (!mAntialiasingStack.isEmpty()) mIsAntialiasing = mAntialiasingStack.pop(); else qDebug() << Q_FUNC_INFO << "Unbalanced save/restore"; QPainter::restore(); } /*! Changes the pen width to 1 if it currently is 0. This function is called in the \ref setPen overrides when the \ref pmNonCosmetic mode is set. */ void QCPPainter::makeNonCosmetic() { if (qFuzzyIsNull(pen().widthF())) { QPen p = pen(); p.setWidth(1); QPainter::setPen(p); } } /* end of 'src/painter.cpp' */ /* including file 'src/paintbuffer.cpp' */ /* modified 2021-03-29T02:30:44, size 18915 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAbstractPaintBuffer //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAbstractPaintBuffer \brief The abstract base class for paint buffers, which define the rendering backend This abstract base class defines the basic interface that a paint buffer needs to provide in order to be usable by QCustomPlot. A paint buffer manages both a surface to draw onto, and the matching paint device. The size of the surface can be changed via \ref setSize. External classes (\ref QCustomPlot and \ref QCPLayer) request a painter via \ref startPainting and then perform the draw calls. Once the painting is complete, \ref donePainting is called, so the paint buffer implementation can do clean up if necessary. Before rendering a frame, each paint buffer is usually filled with a color using \ref clear (usually the color is \c Qt::transparent), to remove the contents of the previous frame. The simplest paint buffer implementation is \ref QCPPaintBufferPixmap which allows regular software rendering via the raster engine. Hardware accelerated rendering via pixel buffers and frame buffer objects is provided by \ref QCPPaintBufferGlPbuffer and \ref QCPPaintBufferGlFbo. They are used automatically if \ref QCustomPlot::setOpenGl is enabled. */ /* start documentation of pure virtual functions */ /*! \fn virtual QCPPainter *QCPAbstractPaintBuffer::startPainting() = 0 Returns a \ref QCPPainter which is ready to draw to this buffer. The ownership and thus the responsibility to delete the painter after the painting operations are complete is given to the caller of this method. Once you are done using the painter, delete the painter and call \ref donePainting. While a painter generated with this method is active, you must not call \ref setSize, \ref setDevicePixelRatio or \ref clear. This method may return 0, if a painter couldn't be activated on the buffer. This usually indicates a problem with the respective painting backend. */ /*! \fn virtual void QCPAbstractPaintBuffer::draw(QCPPainter *painter) const = 0 Draws the contents of this buffer with the provided \a painter. This is the method that is used to finally join all paint buffers and draw them onto the screen. */ /*! \fn virtual void QCPAbstractPaintBuffer::clear(const QColor &color) = 0 Fills the entire buffer with the provided \a color. To have an empty transparent buffer, use the named color \c Qt::transparent. This method must not be called if there is currently a painter (acquired with \ref startPainting) active. */ /*! \fn virtual void QCPAbstractPaintBuffer::reallocateBuffer() = 0 Reallocates the internal buffer with the currently configured size (\ref setSize) and device pixel ratio, if applicable (\ref setDevicePixelRatio). It is called as soon as any of those properties are changed on this paint buffer. \note Subclasses of \ref QCPAbstractPaintBuffer must call their reimplementation of this method in their constructor, to perform the first allocation (this can not be done by the base class because calling pure virtual methods in base class constructors is not possible). */ /* end documentation of pure virtual functions */ /* start documentation of inline functions */ /*! \fn virtual void QCPAbstractPaintBuffer::donePainting() If you have acquired a \ref QCPPainter to paint onto this paint buffer via \ref startPainting, call this method as soon as you are done with the painting operations and have deleted the painter. paint buffer subclasses may use this method to perform any type of cleanup that is necessary. The default implementation does nothing. */ /* end documentation of inline functions */ /*! Creates a paint buffer and initializes it with the provided \a size and \a devicePixelRatio. Subclasses must call their \ref reallocateBuffer implementation in their respective constructors. */ QCPAbstractPaintBuffer::QCPAbstractPaintBuffer(const QSize &size, double devicePixelRatio) : mSize(size), mDevicePixelRatio(devicePixelRatio), mInvalidated(true) { } QCPAbstractPaintBuffer::~QCPAbstractPaintBuffer() { } /*! Sets the paint buffer size. The buffer is reallocated (by calling \ref reallocateBuffer), so any painters that were obtained by \ref startPainting are invalidated and must not be used after calling this method. If \a size is already the current buffer size, this method does nothing. */ void QCPAbstractPaintBuffer::setSize(const QSize &size) { if (mSize != size) { mSize = size; reallocateBuffer(); } } /*! Sets the invalidated flag to \a invalidated. This mechanism is used internally in conjunction with isolated replotting of \ref QCPLayer instances (in \ref QCPLayer::lmBuffered mode). If \ref QCPLayer::replot is called on a buffered layer, i.e. an isolated repaint of only that layer (and its dedicated paint buffer) is requested, QCustomPlot will decide depending on the invalidated flags of other paint buffers whether it also replots them, instead of only the layer on which the replot was called. The invalidated flag is set to true when \ref QCPLayer association has changed, i.e. if layers were added or removed from this buffer, or if they were reordered. It is set to false as soon as all associated \ref QCPLayer instances are drawn onto the buffer. Under normal circumstances, it is not necessary to manually call this method. */ void QCPAbstractPaintBuffer::setInvalidated(bool invalidated) { mInvalidated = invalidated; } /*! Sets the device pixel ratio to \a ratio. This is useful to render on high-DPI output devices. The ratio is automatically set to the device pixel ratio used by the parent QCustomPlot instance. The buffer is reallocated (by calling \ref reallocateBuffer), so any painters that were obtained by \ref startPainting are invalidated and must not be used after calling this method. \note This method is only available for Qt versions 5.4 and higher. */ void QCPAbstractPaintBuffer::setDevicePixelRatio(double ratio) { if (!qFuzzyCompare(ratio, mDevicePixelRatio)) { #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED mDevicePixelRatio = ratio; reallocateBuffer(); #else qDebug() << Q_FUNC_INFO << "Device pixel ratios not supported for Qt versions before 5.4"; mDevicePixelRatio = 1.0; #endif } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPaintBufferPixmap //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPaintBufferPixmap \brief A paint buffer based on QPixmap, using software raster rendering This paint buffer is the default and fall-back paint buffer which uses software rendering and QPixmap as internal buffer. It is used if \ref QCustomPlot::setOpenGl is false. */ /*! Creates a pixmap paint buffer instancen with the specified \a size and \a devicePixelRatio, if applicable. */ QCPPaintBufferPixmap::QCPPaintBufferPixmap(const QSize &size, double devicePixelRatio) : QCPAbstractPaintBuffer(size, devicePixelRatio) { QCPPaintBufferPixmap::reallocateBuffer(); } QCPPaintBufferPixmap::~QCPPaintBufferPixmap() { } /* inherits documentation from base class */ QCPPainter *QCPPaintBufferPixmap::startPainting() { QCPPainter *result = new QCPPainter(&mBuffer); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) result->setRenderHint(QPainter::HighQualityAntialiasing); #endif return result; } /* inherits documentation from base class */ void QCPPaintBufferPixmap::draw(QCPPainter *painter) const { if (painter && painter->isActive()) painter->drawPixmap(0, 0, mBuffer); else qDebug() << Q_FUNC_INFO << "invalid or inactive painter passed"; } /* inherits documentation from base class */ void QCPPaintBufferPixmap::clear(const QColor &color) { mBuffer.fill(color); } /* inherits documentation from base class */ void QCPPaintBufferPixmap::reallocateBuffer() { setInvalidated(); if (!qFuzzyCompare(1.0, mDevicePixelRatio)) { #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED mBuffer = QPixmap(mSize*mDevicePixelRatio); mBuffer.setDevicePixelRatio(mDevicePixelRatio); #else qDebug() << Q_FUNC_INFO << "Device pixel ratios not supported for Qt versions before 5.4"; mDevicePixelRatio = 1.0; mBuffer = QPixmap(mSize); #endif } else { mBuffer = QPixmap(mSize); } } #ifdef QCP_OPENGL_PBUFFER //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPaintBufferGlPbuffer //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPaintBufferGlPbuffer \brief A paint buffer based on OpenGL pixel buffers, using hardware accelerated rendering This paint buffer is one of the OpenGL paint buffers which facilitate hardware accelerated plot rendering. It is based on OpenGL pixel buffers (pbuffer) and is used in Qt versions before 5.0. (See \ref QCPPaintBufferGlFbo used in newer Qt versions.) The OpenGL paint buffers are used if \ref QCustomPlot::setOpenGl is set to true, and if they are supported by the system. */ /*! Creates a \ref QCPPaintBufferGlPbuffer instance with the specified \a size and \a devicePixelRatio, if applicable. The parameter \a multisamples defines how many samples are used per pixel. Higher values thus result in higher quality antialiasing. If the specified \a multisamples value exceeds the capability of the graphics hardware, the highest supported multisampling is used. */ QCPPaintBufferGlPbuffer::QCPPaintBufferGlPbuffer(const QSize &size, double devicePixelRatio, int multisamples) : QCPAbstractPaintBuffer(size, devicePixelRatio), mGlPBuffer(0), mMultisamples(qMax(0, multisamples)) { QCPPaintBufferGlPbuffer::reallocateBuffer(); } QCPPaintBufferGlPbuffer::~QCPPaintBufferGlPbuffer() { if (mGlPBuffer) delete mGlPBuffer; } /* inherits documentation from base class */ QCPPainter *QCPPaintBufferGlPbuffer::startPainting() { if (!mGlPBuffer->isValid()) { qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?"; return 0; } QCPPainter *result = new QCPPainter(mGlPBuffer); result->setRenderHint(QPainter::HighQualityAntialiasing); return result; } /* inherits documentation from base class */ void QCPPaintBufferGlPbuffer::draw(QCPPainter *painter) const { if (!painter || !painter->isActive()) { qDebug() << Q_FUNC_INFO << "invalid or inactive painter passed"; return; } if (!mGlPBuffer->isValid()) { qDebug() << Q_FUNC_INFO << "OpenGL pbuffer isn't valid, reallocateBuffer was not called?"; return; } painter->drawImage(0, 0, mGlPBuffer->toImage()); } /* inherits documentation from base class */ void QCPPaintBufferGlPbuffer::clear(const QColor &color) { if (mGlPBuffer->isValid()) { mGlPBuffer->makeCurrent(); glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF()); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); mGlPBuffer->doneCurrent(); } else qDebug() << Q_FUNC_INFO << "OpenGL pbuffer invalid or context not current"; } /* inherits documentation from base class */ void QCPPaintBufferGlPbuffer::reallocateBuffer() { if (mGlPBuffer) delete mGlPBuffer; QGLFormat format; format.setAlpha(true); format.setSamples(mMultisamples); mGlPBuffer = new QGLPixelBuffer(mSize, format); } #endif // QCP_OPENGL_PBUFFER #ifdef QCP_OPENGL_FBO //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPaintBufferGlFbo //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPaintBufferGlFbo \brief A paint buffer based on OpenGL frame buffers objects, using hardware accelerated rendering This paint buffer is one of the OpenGL paint buffers which facilitate hardware accelerated plot rendering. It is based on OpenGL frame buffer objects (fbo) and is used in Qt versions 5.0 and higher. (See \ref QCPPaintBufferGlPbuffer used in older Qt versions.) The OpenGL paint buffers are used if \ref QCustomPlot::setOpenGl is set to true, and if they are supported by the system. */ /*! Creates a \ref QCPPaintBufferGlFbo instance with the specified \a size and \a devicePixelRatio, if applicable. All frame buffer objects shall share one OpenGL context and paint device, which need to be set up externally and passed via \a glContext and \a glPaintDevice. The set-up is done in \ref QCustomPlot::setupOpenGl and the context and paint device are managed by the parent QCustomPlot instance. */ QCPPaintBufferGlFbo::QCPPaintBufferGlFbo(const QSize &size, double devicePixelRatio, QWeakPointer glContext, QWeakPointer glPaintDevice) : QCPAbstractPaintBuffer(size, devicePixelRatio), mGlContext(glContext), mGlPaintDevice(glPaintDevice), mGlFrameBuffer(0) { QCPPaintBufferGlFbo::reallocateBuffer(); } QCPPaintBufferGlFbo::~QCPPaintBufferGlFbo() { if (mGlFrameBuffer) delete mGlFrameBuffer; } /* inherits documentation from base class */ QCPPainter *QCPPaintBufferGlFbo::startPainting() { QSharedPointer paintDevice = mGlPaintDevice.toStrongRef(); QSharedPointer context = mGlContext.toStrongRef(); if (!paintDevice) { qDebug() << Q_FUNC_INFO << "OpenGL paint device doesn't exist"; return 0; } if (!context) { qDebug() << Q_FUNC_INFO << "OpenGL context doesn't exist"; return 0; } if (!mGlFrameBuffer) { qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?"; return 0; } if (QOpenGLContext::currentContext() != context.data()) context->makeCurrent(context->surface()); mGlFrameBuffer->bind(); QCPPainter *result = new QCPPainter(paintDevice.data()); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) result->setRenderHint(QPainter::HighQualityAntialiasing); #endif return result; } /* inherits documentation from base class */ void QCPPaintBufferGlFbo::donePainting() { if (mGlFrameBuffer && mGlFrameBuffer->isBound()) mGlFrameBuffer->release(); else qDebug() << Q_FUNC_INFO << "Either OpenGL frame buffer not valid or was not bound"; } /* inherits documentation from base class */ void QCPPaintBufferGlFbo::draw(QCPPainter *painter) const { if (!painter || !painter->isActive()) { qDebug() << Q_FUNC_INFO << "invalid or inactive painter passed"; return; } if (!mGlFrameBuffer) { qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?"; return; } painter->drawImage(0, 0, mGlFrameBuffer->toImage()); } /* inherits documentation from base class */ void QCPPaintBufferGlFbo::clear(const QColor &color) { QSharedPointer context = mGlContext.toStrongRef(); if (!context) { qDebug() << Q_FUNC_INFO << "OpenGL context doesn't exist"; return; } if (!mGlFrameBuffer) { qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?"; return; } if (QOpenGLContext::currentContext() != context.data()) context->makeCurrent(context->surface()); mGlFrameBuffer->bind(); glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF()); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); mGlFrameBuffer->release(); } /* inherits documentation from base class */ void QCPPaintBufferGlFbo::reallocateBuffer() { // release and delete possibly existing framebuffer: if (mGlFrameBuffer) { if (mGlFrameBuffer->isBound()) mGlFrameBuffer->release(); delete mGlFrameBuffer; mGlFrameBuffer = 0; } QSharedPointer paintDevice = mGlPaintDevice.toStrongRef(); QSharedPointer context = mGlContext.toStrongRef(); if (!paintDevice) { qDebug() << Q_FUNC_INFO << "OpenGL paint device doesn't exist"; return; } if (!context) { qDebug() << Q_FUNC_INFO << "OpenGL context doesn't exist"; return; } // create new fbo with appropriate size: context->makeCurrent(context->surface()); QOpenGLFramebufferObjectFormat frameBufferFormat; frameBufferFormat.setSamples(context->format().samples()); frameBufferFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); mGlFrameBuffer = new QOpenGLFramebufferObject(mSize*mDevicePixelRatio, frameBufferFormat); if (paintDevice->size() != mSize*mDevicePixelRatio) paintDevice->setSize(mSize*mDevicePixelRatio); #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED paintDevice->setDevicePixelRatio(mDevicePixelRatio); #endif } #endif // QCP_OPENGL_FBO /* end of 'src/paintbuffer.cpp' */ /* including file 'src/layer.cpp' */ /* modified 2021-03-29T02:30:44, size 37615 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPLayer //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPLayer \brief A layer that may contain objects, to control the rendering order The Layering system of QCustomPlot is the mechanism to control the rendering order of the elements inside the plot. It is based on the two classes QCPLayer and QCPLayerable. QCustomPlot holds an ordered list of one or more instances of QCPLayer (see QCustomPlot::addLayer, QCustomPlot::layer, QCustomPlot::moveLayer, etc.). When replotting, QCustomPlot goes through the list of layers bottom to top and successively draws the layerables of the layers into the paint buffer(s). A QCPLayer contains an ordered list of QCPLayerable instances. QCPLayerable is an abstract base class from which almost all visible objects derive, like axes, grids, graphs, items, etc. \section qcplayer-defaultlayers Default layers Initially, QCustomPlot has six layers: "background", "grid", "main", "axes", "legend" and "overlay" (in that order). On top is the "overlay" layer, which only contains the QCustomPlot's selection rect (\ref QCustomPlot::selectionRect). The next two layers "axes" and "legend" contain the default axes and legend, so they will be drawn above plottables. In the middle, there is the "main" layer. It is initially empty and set as the current layer (see QCustomPlot::setCurrentLayer). This means, all new plottables, items etc. are created on this layer by default. Then comes the "grid" layer which contains the QCPGrid instances (which belong tightly to QCPAxis, see \ref QCPAxis::grid). The Axis rect background shall be drawn behind everything else, thus the default QCPAxisRect instance is placed on the "background" layer. Of course, the layer affiliation of the individual objects can be changed as required (\ref QCPLayerable::setLayer). \section qcplayer-ordering Controlling the rendering order via layers Controlling the ordering of layerables in the plot is easy: Create a new layer in the position you want the layerable to be in, e.g. above "main", with \ref QCustomPlot::addLayer. Then set the current layer with \ref QCustomPlot::setCurrentLayer to that new layer and finally create the objects normally. They will be placed on the new layer automatically, due to the current layer setting. Alternatively you could have also ignored the current layer setting and just moved the objects with \ref QCPLayerable::setLayer to the desired layer after creating them. It is also possible to move whole layers. For example, If you want the grid to be shown in front of all plottables/items on the "main" layer, just move it above "main" with QCustomPlot::moveLayer. The rendering order within one layer is simply by order of creation or insertion. The item created last (or added last to the layer), is drawn on top of all other objects on that layer. When a layer is deleted, the objects on it are not deleted with it, but fall on the layer below the deleted layer, see QCustomPlot::removeLayer. \section qcplayer-buffering Replotting only a specific layer If the layer mode (\ref setMode) is set to \ref lmBuffered, you can replot only this specific layer by calling \ref replot. In certain situations this can provide better replot performance, compared with a full replot of all layers. Upon creation of a new layer, the layer mode is initialized to \ref lmLogical. The only layer that is set to \ref lmBuffered in a new \ref QCustomPlot instance is the "overlay" layer, containing the selection rect. */ /* start documentation of inline functions */ /*! \fn QList QCPLayer::children() const Returns a list of all layerables on this layer. The order corresponds to the rendering order: layerables with higher indices are drawn above layerables with lower indices. */ /*! \fn int QCPLayer::index() const Returns the index this layer has in the QCustomPlot. The index is the integer number by which this layer can be accessed via \ref QCustomPlot::layer. Layers with higher indices will be drawn above layers with lower indices. */ /* end documentation of inline functions */ /*! Creates a new QCPLayer instance. Normally you shouldn't directly instantiate layers, use \ref QCustomPlot::addLayer instead. \warning It is not checked that \a layerName is actually a unique layer name in \a parentPlot. This check is only performed by \ref QCustomPlot::addLayer. */ QCPLayer::QCPLayer(QCustomPlot *parentPlot, const QString &layerName) : QObject(parentPlot), mParentPlot(parentPlot), mName(layerName), mIndex(-1), // will be set to a proper value by the QCustomPlot layer creation function mVisible(true), mMode(lmLogical) { // Note: no need to make sure layerName is unique, because layer // management is done with QCustomPlot functions. } QCPLayer::~QCPLayer() { // If child layerables are still on this layer, detach them, so they don't try to reach back to this // then invalid layer once they get deleted/moved themselves. This only happens when layers are deleted // directly, like in the QCustomPlot destructor. (The regular layer removal procedure for the user is to // call QCustomPlot::removeLayer, which moves all layerables off this layer before deleting it.) while (!mChildren.isEmpty()) mChildren.last()->setLayer(nullptr); // removes itself from mChildren via removeChild() if (mParentPlot->currentLayer() == this) qDebug() << Q_FUNC_INFO << "The parent plot's mCurrentLayer will be a dangling pointer. Should have been set to a valid layer or nullptr beforehand."; } /*! Sets whether this layer is visible or not. If \a visible is set to false, all layerables on this layer will be invisible. This function doesn't change the visibility property of the layerables (\ref QCPLayerable::setVisible), but the \ref QCPLayerable::realVisibility of each layerable takes the visibility of the parent layer into account. */ void QCPLayer::setVisible(bool visible) { mVisible = visible; } /*! Sets the rendering mode of this layer. If \a mode is set to \ref lmBuffered for a layer, it will be given a dedicated paint buffer by the parent QCustomPlot instance. This means it may be replotted individually by calling \ref QCPLayer::replot, without needing to replot all other layers. Layers which are set to \ref lmLogical (the default) are used only to define the rendering order and can't be replotted individually. Note that each layer which is set to \ref lmBuffered requires additional paint buffers for the layers below, above and for the layer itself. This increases the memory consumption and (slightly) decreases the repainting speed because multiple paint buffers need to be joined. So you should carefully choose which layers benefit from having their own paint buffer. A typical example would be a layer which contains certain layerables (e.g. items) that need to be changed and thus replotted regularly, while all other layerables on other layers stay static. By default, only the topmost layer called "overlay" is in mode \ref lmBuffered, and contains the selection rect. \see replot */ void QCPLayer::setMode(QCPLayer::LayerMode mode) { if (mMode != mode) { mMode = mode; if (QSharedPointer pb = mPaintBuffer.toStrongRef()) pb->setInvalidated(); } } /*! \internal Draws the contents of this layer with the provided \a painter. \see replot, drawToPaintBuffer */ void QCPLayer::draw(QCPPainter *painter) { foreach (QCPLayerable *child, mChildren) { if (child->realVisibility()) { painter->save(); painter->setClipRect(child->clipRect().translated(0, -1)); child->applyDefaultAntialiasingHint(painter); child->draw(painter); painter->restore(); } } } /*! \internal Draws the contents of this layer into the paint buffer which is associated with this layer. The association is established by the parent QCustomPlot, which manages all paint buffers (see \ref QCustomPlot::setupPaintBuffers). \see draw */ void QCPLayer::drawToPaintBuffer() { if (QSharedPointer pb = mPaintBuffer.toStrongRef()) { if (QCPPainter *painter = pb->startPainting()) { if (painter->isActive()) draw(painter); else qDebug() << Q_FUNC_INFO << "paint buffer returned inactive painter"; delete painter; pb->donePainting(); } else qDebug() << Q_FUNC_INFO << "paint buffer returned nullptr painter"; } else qDebug() << Q_FUNC_INFO << "no valid paint buffer associated with this layer"; } /*! If the layer mode (\ref setMode) is set to \ref lmBuffered, this method allows replotting only the layerables on this specific layer, without the need to replot all other layers (as a call to \ref QCustomPlot::replot would do). QCustomPlot also makes sure to replot all layers instead of only this one, if the layer ordering or any layerable-layer-association has changed since the last full replot and any other paint buffers were thus invalidated. If the layer mode is \ref lmLogical however, this method simply calls \ref QCustomPlot::replot on the parent QCustomPlot instance. \see draw */ void QCPLayer::replot() { if (mMode == lmBuffered && !mParentPlot->hasInvalidatedPaintBuffers()) { if (QSharedPointer pb = mPaintBuffer.toStrongRef()) { pb->clear(Qt::transparent); drawToPaintBuffer(); pb->setInvalidated(false); // since layer is lmBuffered, we know only this layer is on buffer and we can reset invalidated flag mParentPlot->update(); } else qDebug() << Q_FUNC_INFO << "no valid paint buffer associated with this layer"; } else mParentPlot->replot(); } /*! \internal Adds the \a layerable to the list of this layer. If \a prepend is set to true, the layerable will be prepended to the list, i.e. be drawn beneath the other layerables already in the list. This function does not change the \a mLayer member of \a layerable to this layer. (Use QCPLayerable::setLayer to change the layer of an object, not this function.) \see removeChild */ void QCPLayer::addChild(QCPLayerable *layerable, bool prepend) { if (!mChildren.contains(layerable)) { if (prepend) mChildren.prepend(layerable); else mChildren.append(layerable); if (QSharedPointer pb = mPaintBuffer.toStrongRef()) pb->setInvalidated(); } else qDebug() << Q_FUNC_INFO << "layerable is already child of this layer" << reinterpret_cast(layerable); } /*! \internal Removes the \a layerable from the list of this layer. This function does not change the \a mLayer member of \a layerable. (Use QCPLayerable::setLayer to change the layer of an object, not this function.) \see addChild */ void QCPLayer::removeChild(QCPLayerable *layerable) { if (mChildren.removeOne(layerable)) { if (QSharedPointer pb = mPaintBuffer.toStrongRef()) pb->setInvalidated(); } else qDebug() << Q_FUNC_INFO << "layerable is not child of this layer" << reinterpret_cast(layerable); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPLayerable //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPLayerable \brief Base class for all drawable objects This is the abstract base class most visible objects derive from, e.g. plottables, axes, grid etc. Every layerable is on a layer (QCPLayer) which allows controlling the rendering order by stacking the layers accordingly. For details about the layering mechanism, see the QCPLayer documentation. */ /* start documentation of inline functions */ /*! \fn QCPLayerable *QCPLayerable::parentLayerable() const Returns the parent layerable of this layerable. The parent layerable is used to provide visibility hierarchies in conjunction with the method \ref realVisibility. This way, layerables only get drawn if their parent layerables are visible, too. Note that a parent layerable is not necessarily also the QObject parent for memory management. Further, a layerable doesn't always have a parent layerable, so this function may return \c nullptr. A parent layerable is set implicitly when placed inside layout elements and doesn't need to be set manually by the user. */ /* end documentation of inline functions */ /* start documentation of pure virtual functions */ /*! \fn virtual void QCPLayerable::applyDefaultAntialiasingHint(QCPPainter *painter) const = 0 \internal This function applies the default antialiasing setting to the specified \a painter, using the function \ref applyAntialiasingHint. It is the antialiasing state the painter is put in, when \ref draw is called on the layerable. If the layerable has multiple entities whose antialiasing setting may be specified individually, this function should set the antialiasing state of the most prominent entity. In this case however, the \ref draw function usually calls the specialized versions of this function before drawing each entity, effectively overriding the setting of the default antialiasing hint. First example: QCPGraph has multiple entities that have an antialiasing setting: The graph line, fills and scatters. Those can be configured via QCPGraph::setAntialiased, QCPGraph::setAntialiasedFill and QCPGraph::setAntialiasedScatters. Consequently, there isn't only the QCPGraph::applyDefaultAntialiasingHint function (which corresponds to the graph line's antialiasing), but specialized ones like QCPGraph::applyFillAntialiasingHint and QCPGraph::applyScattersAntialiasingHint. So before drawing one of those entities, QCPGraph::draw calls the respective specialized applyAntialiasingHint function. Second example: QCPItemLine consists only of a line so there is only one antialiasing setting which can be controlled with QCPItemLine::setAntialiased. (This function is inherited by all layerables. The specialized functions, as seen on QCPGraph, must be added explicitly to the respective layerable subclass.) Consequently it only has the normal QCPItemLine::applyDefaultAntialiasingHint. The \ref QCPItemLine::draw function doesn't need to care about setting any antialiasing states, because the default antialiasing hint is already set on the painter when the \ref draw function is called, and that's the state it wants to draw the line with. */ /*! \fn virtual void QCPLayerable::draw(QCPPainter *painter) const = 0 \internal This function draws the layerable with the specified \a painter. It is only called by QCustomPlot, if the layerable is visible (\ref setVisible). Before this function is called, the painter's antialiasing state is set via \ref applyDefaultAntialiasingHint, see the documentation there. Further, the clipping rectangle was set to \ref clipRect. */ /* end documentation of pure virtual functions */ /* start documentation of signals */ /*! \fn void QCPLayerable::layerChanged(QCPLayer *newLayer); This signal is emitted when the layer of this layerable changes, i.e. this layerable is moved to a different layer. \see setLayer */ /* end documentation of signals */ /*! Creates a new QCPLayerable instance. Since QCPLayerable is an abstract base class, it can't be instantiated directly. Use one of the derived classes. If \a plot is provided, it automatically places itself on the layer named \a targetLayer. If \a targetLayer is an empty string, it places itself on the current layer of the plot (see \ref QCustomPlot::setCurrentLayer). It is possible to provide \c nullptr as \a plot. In that case, you should assign a parent plot at a later time with \ref initializeParentPlot. The layerable's parent layerable is set to \a parentLayerable, if provided. Direct layerable parents are mainly used to control visibility in a hierarchy of layerables. This means a layerable is only drawn, if all its ancestor layerables are also visible. Note that \a parentLayerable does not become the QObject-parent (for memory management) of this layerable, \a plot does. It is not uncommon to set the QObject-parent to something else in the constructors of QCPLayerable subclasses, to guarantee a working destruction hierarchy. */ QCPLayerable::QCPLayerable(QCustomPlot *plot, QString targetLayer, QCPLayerable *parentLayerable) : QObject(plot), mVisible(true), mParentPlot(plot), mParentLayerable(parentLayerable), mLayer(nullptr), mAntialiased(true) { if (mParentPlot) { if (targetLayer.isEmpty()) setLayer(mParentPlot->currentLayer()); else if (!setLayer(targetLayer)) qDebug() << Q_FUNC_INFO << "setting QCPlayerable initial layer to" << targetLayer << "failed."; } } QCPLayerable::~QCPLayerable() { if (mLayer) { mLayer->removeChild(this); mLayer = nullptr; } } /*! Sets the visibility of this layerable object. If an object is not visible, it will not be drawn on the QCustomPlot surface, and user interaction with it (e.g. click and selection) is not possible. */ void QCPLayerable::setVisible(bool on) { mVisible = on; } /*! Sets the \a layer of this layerable object. The object will be placed on top of the other objects already on \a layer. If \a layer is 0, this layerable will not be on any layer and thus not appear in the plot (or interact/receive events). Returns true if the layer of this layerable was successfully changed to \a layer. */ bool QCPLayerable::setLayer(QCPLayer *layer) { return moveToLayer(layer, false); } /*! \overload Sets the layer of this layerable object by name Returns true on success, i.e. if \a layerName is a valid layer name. */ bool QCPLayerable::setLayer(const QString &layerName) { if (!mParentPlot) { qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set"; return false; } if (QCPLayer *layer = mParentPlot->layer(layerName)) { return setLayer(layer); } else { qDebug() << Q_FUNC_INFO << "there is no layer with name" << layerName; return false; } } /*! Sets whether this object will be drawn antialiased or not. Note that antialiasing settings may be overridden by QCustomPlot::setAntialiasedElements and QCustomPlot::setNotAntialiasedElements. */ void QCPLayerable::setAntialiased(bool enabled) { mAntialiased = enabled; } /*! Returns whether this layerable is visible, taking the visibility of the layerable parent and the visibility of this layerable's layer into account. This is the method that is consulted to decide whether a layerable shall be drawn or not. If this layerable has a direct layerable parent (usually set via hierarchies implemented in subclasses, like in the case of \ref QCPLayoutElement), this function returns true only if this layerable has its visibility set to true and the parent layerable's \ref realVisibility returns true. */ bool QCPLayerable::realVisibility() const { return mVisible && (!mLayer || mLayer->visible()) && (!mParentLayerable || mParentLayerable.data()->realVisibility()); } /*! This function is used to decide whether a click hits a layerable object or not. \a pos is a point in pixel coordinates on the QCustomPlot surface. This function returns the shortest pixel distance of this point to the object. If the object is either invisible or the distance couldn't be determined, -1.0 is returned. Further, if \a onlySelectable is true and the object is not selectable, -1.0 is returned, too. If the object is represented not by single lines but by an area like a \ref QCPItemText or the bars of a \ref QCPBars plottable, a click inside the area should also be considered a hit. In these cases this function thus returns a constant value greater zero but still below the parent plot's selection tolerance. (typically the selectionTolerance multiplied by 0.99). Providing a constant value for area objects allows selecting line objects even when they are obscured by such area objects, by clicking close to the lines (i.e. closer than 0.99*selectionTolerance). The actual setting of the selection state is not done by this function. This is handled by the parent QCustomPlot when the mouseReleaseEvent occurs, and the finally selected object is notified via the \ref selectEvent/\ref deselectEvent methods. \a details is an optional output parameter. Every layerable subclass may place any information in \a details. This information will be passed to \ref selectEvent when the parent QCustomPlot decides on the basis of this selectTest call, that the object was successfully selected. The subsequent call to \ref selectEvent will carry the \a details. This is useful for multi-part objects (like QCPAxis). This way, a possibly complex calculation to decide which part was clicked is only done once in \ref selectTest. The result (i.e. the actually clicked part) can then be placed in \a details. So in the subsequent \ref selectEvent, the decision which part was selected doesn't have to be done a second time for a single selection operation. In the case of 1D Plottables (\ref QCPAbstractPlottable1D, like \ref QCPGraph or \ref QCPBars) \a details will be set to a \ref QCPDataSelection, describing the closest data point to \a pos. You may pass \c nullptr as \a details to indicate that you are not interested in those selection details. \see selectEvent, deselectEvent, mousePressEvent, wheelEvent, QCustomPlot::setInteractions, QCPAbstractPlottable1D::selectTestRect */ double QCPLayerable::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(pos) Q_UNUSED(onlySelectable) Q_UNUSED(details) return -1.0; } /*! \internal Sets the parent plot of this layerable. Use this function once to set the parent plot if you have passed \c nullptr in the constructor. It can not be used to move a layerable from one QCustomPlot to another one. Note that, unlike when passing a non \c nullptr parent plot in the constructor, this function does not make \a parentPlot the QObject-parent of this layerable. If you want this, call QObject::setParent(\a parentPlot) in addition to this function. Further, you will probably want to set a layer (\ref setLayer) after calling this function, to make the layerable appear on the QCustomPlot. The parent plot change will be propagated to subclasses via a call to \ref parentPlotInitialized so they can react accordingly (e.g. also initialize the parent plot of child layerables, like QCPLayout does). */ void QCPLayerable::initializeParentPlot(QCustomPlot *parentPlot) { if (mParentPlot) { qDebug() << Q_FUNC_INFO << "called with mParentPlot already initialized"; return; } if (!parentPlot) qDebug() << Q_FUNC_INFO << "called with parentPlot zero"; mParentPlot = parentPlot; parentPlotInitialized(mParentPlot); } /*! \internal Sets the parent layerable of this layerable to \a parentLayerable. Note that \a parentLayerable does not become the QObject-parent (for memory management) of this layerable. The parent layerable has influence on the return value of the \ref realVisibility method. Only layerables with a fully visible parent tree will return true for \ref realVisibility, and thus be drawn. \see realVisibility */ void QCPLayerable::setParentLayerable(QCPLayerable *parentLayerable) { mParentLayerable = parentLayerable; } /*! \internal Moves this layerable object to \a layer. If \a prepend is true, this object will be prepended to the new layer's list, i.e. it will be drawn below the objects already on the layer. If it is false, the object will be appended. Returns true on success, i.e. if \a layer is a valid layer. */ bool QCPLayerable::moveToLayer(QCPLayer *layer, bool prepend) { if (layer && !mParentPlot) { qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set"; return false; } if (layer && layer->parentPlot() != mParentPlot) { qDebug() << Q_FUNC_INFO << "layer" << layer->name() << "is not in same QCustomPlot as this layerable"; return false; } QCPLayer *oldLayer = mLayer; if (mLayer) mLayer->removeChild(this); mLayer = layer; if (mLayer) mLayer->addChild(this, prepend); if (mLayer != oldLayer) emit layerChanged(mLayer); return true; } /*! \internal Sets the QCPainter::setAntialiasing state on the provided \a painter, depending on the \a localAntialiased value as well as the overrides \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. Which override enum this function takes into account is controlled via \a overrideElement. */ void QCPLayerable::applyAntialiasingHint(QCPPainter *painter, bool localAntialiased, QCP::AntialiasedElement overrideElement) const { if (mParentPlot && mParentPlot->notAntialiasedElements().testFlag(overrideElement)) painter->setAntialiasing(false); else if (mParentPlot && mParentPlot->antialiasedElements().testFlag(overrideElement)) painter->setAntialiasing(true); else painter->setAntialiasing(localAntialiased); } /*! \internal This function is called by \ref initializeParentPlot, to allow subclasses to react on the setting of a parent plot. This is the case when \c nullptr was passed as parent plot in the constructor, and the parent plot is set at a later time. For example, QCPLayoutElement/QCPLayout hierarchies may be created independently of any QCustomPlot at first. When they are then added to a layout inside the QCustomPlot, the top level element of the hierarchy gets its parent plot initialized with \ref initializeParentPlot. To propagate the parent plot to all the children of the hierarchy, the top level element then uses this function to pass the parent plot on to its child elements. The default implementation does nothing. \see initializeParentPlot */ void QCPLayerable::parentPlotInitialized(QCustomPlot *parentPlot) { Q_UNUSED(parentPlot) } /*! \internal Returns the selection category this layerable shall belong to. The selection category is used in conjunction with \ref QCustomPlot::setInteractions to control which objects are selectable and which aren't. Subclasses that don't fit any of the normal \ref QCP::Interaction values can use \ref QCP::iSelectOther. This is what the default implementation returns. \see QCustomPlot::setInteractions */ QCP::Interaction QCPLayerable::selectionCategory() const { return QCP::iSelectOther; } /*! \internal Returns the clipping rectangle of this layerable object. By default, this is the viewport of the parent QCustomPlot. Specific subclasses may reimplement this function to provide different clipping rects. The returned clipping rect is set on the painter before the draw function of the respective object is called. */ QRect QCPLayerable::clipRect() const { if (mParentPlot) return mParentPlot->viewport(); else return {}; } /*! \internal This event is called when the layerable shall be selected, as a consequence of a click by the user. Subclasses should react to it by setting their selection state appropriately. The default implementation does nothing. \a event is the mouse event that caused the selection. \a additive indicates, whether the user was holding the multi-select-modifier while performing the selection (see \ref QCustomPlot::setMultiSelectModifier). if \a additive is true, the selection state must be toggled (i.e. become selected when unselected and unselected when selected). Every selectEvent is preceded by a call to \ref selectTest, which has returned positively (i.e. returned a value greater than 0 and less than the selection tolerance of the parent QCustomPlot). The \a details data you output from \ref selectTest is fed back via \a details here. You may use it to transport any kind of information from the selectTest to the possibly subsequent selectEvent. Usually \a details is used to transfer which part was clicked, if it is a layerable that has multiple individually selectable parts (like QCPAxis). This way selectEvent doesn't need to do the calculation again to find out which part was actually clicked. \a selectionStateChanged is an output parameter. If the pointer is non-null, this function must set the value either to true or false, depending on whether the selection state of this layerable was actually changed. For layerables that only are selectable as a whole and not in parts, this is simple: if \a additive is true, \a selectionStateChanged must also be set to true, because the selection toggles. If \a additive is false, \a selectionStateChanged is only set to true, if the layerable was previously unselected and now is switched to the selected state. \see selectTest, deselectEvent */ void QCPLayerable::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) { Q_UNUSED(event) Q_UNUSED(additive) Q_UNUSED(details) Q_UNUSED(selectionStateChanged) } /*! \internal This event is called when the layerable shall be deselected, either as consequence of a user interaction or a call to \ref QCustomPlot::deselectAll. Subclasses should react to it by unsetting their selection appropriately. just as in \ref selectEvent, the output parameter \a selectionStateChanged (if non-null), must return true or false when the selection state of this layerable has changed or not changed, respectively. \see selectTest, selectEvent */ void QCPLayerable::deselectEvent(bool *selectionStateChanged) { Q_UNUSED(selectionStateChanged) } /*! This event gets called when the user presses a mouse button while the cursor is over the layerable. Whether a cursor is over the layerable is decided by a preceding call to \ref selectTest. The current pixel position of the cursor on the QCustomPlot widget is accessible via \c event->pos(). The parameter \a details contains layerable-specific details about the hit, which were generated in the previous call to \ref selectTest. For example, One-dimensional plottables like \ref QCPGraph or \ref QCPBars convey the clicked data point in the \a details parameter, as \ref QCPDataSelection packed as QVariant. Multi-part objects convey the specific \c SelectablePart that was hit (e.g. \ref QCPAxis::SelectablePart in the case of axes). QCustomPlot uses an event propagation system that works the same as Qt's system. If your layerable doesn't reimplement the \ref mousePressEvent or explicitly calls \c event->ignore() in its reimplementation, the event will be propagated to the next layerable in the stacking order. Once a layerable has accepted the \ref mousePressEvent, it is considered the mouse grabber and will receive all following calls to \ref mouseMoveEvent or \ref mouseReleaseEvent for this mouse interaction (a "mouse interaction" in this context ends with the release). The default implementation does nothing except explicitly ignoring the event with \c event->ignore(). \see mouseMoveEvent, mouseReleaseEvent, mouseDoubleClickEvent, wheelEvent */ void QCPLayerable::mousePressEvent(QMouseEvent *event, const QVariant &details) { Q_UNUSED(details) event->ignore(); } /*! This event gets called when the user moves the mouse while holding a mouse button, after this layerable has become the mouse grabber by accepting the preceding \ref mousePressEvent. The current pixel position of the cursor on the QCustomPlot widget is accessible via \c event->pos(). The parameter \a startPos indicates the position where the initial \ref mousePressEvent occurred, that started the mouse interaction. The default implementation does nothing. \see mousePressEvent, mouseReleaseEvent, mouseDoubleClickEvent, wheelEvent */ void QCPLayerable::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) { Q_UNUSED(startPos) event->ignore(); } /*! This event gets called when the user releases the mouse button, after this layerable has become the mouse grabber by accepting the preceding \ref mousePressEvent. The current pixel position of the cursor on the QCustomPlot widget is accessible via \c event->pos(). The parameter \a startPos indicates the position where the initial \ref mousePressEvent occurred, that started the mouse interaction. The default implementation does nothing. \see mousePressEvent, mouseMoveEvent, mouseDoubleClickEvent, wheelEvent */ void QCPLayerable::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) { Q_UNUSED(startPos) event->ignore(); } /*! This event gets called when the user presses the mouse button a second time in a double-click, while the cursor is over the layerable. Whether a cursor is over the layerable is decided by a preceding call to \ref selectTest. The \ref mouseDoubleClickEvent is called instead of the second \ref mousePressEvent. So in the case of a double-click, the event succession is pressEvent – releaseEvent – doubleClickEvent – releaseEvent. The current pixel position of the cursor on the QCustomPlot widget is accessible via \c event->pos(). The parameter \a details contains layerable-specific details about the hit, which were generated in the previous call to \ref selectTest. For example, One-dimensional plottables like \ref QCPGraph or \ref QCPBars convey the clicked data point in the \a details parameter, as \ref QCPDataSelection packed as QVariant. Multi-part objects convey the specific \c SelectablePart that was hit (e.g. \ref QCPAxis::SelectablePart in the case of axes). Similarly to \ref mousePressEvent, once a layerable has accepted the \ref mouseDoubleClickEvent, it is considered the mouse grabber and will receive all following calls to \ref mouseMoveEvent and \ref mouseReleaseEvent for this mouse interaction (a "mouse interaction" in this context ends with the release). The default implementation does nothing except explicitly ignoring the event with \c event->ignore(). \see mousePressEvent, mouseMoveEvent, mouseReleaseEvent, wheelEvent */ void QCPLayerable::mouseDoubleClickEvent(QMouseEvent *event, const QVariant &details) { Q_UNUSED(details) event->ignore(); } /*! This event gets called when the user turns the mouse scroll wheel while the cursor is over the layerable. Whether a cursor is over the layerable is decided by a preceding call to \ref selectTest. The current pixel position of the cursor on the QCustomPlot widget is accessible via \c event->pos(). The \c event->angleDelta() indicates how far the mouse wheel was turned, which is usually +/- 120 for single rotation steps. However, if the mouse wheel is turned rapidly, multiple steps may accumulate to one event, making the delta larger. On the other hand, if the wheel has very smooth steps or none at all, the delta may be smaller. The default implementation does nothing. \see mousePressEvent, mouseMoveEvent, mouseReleaseEvent, mouseDoubleClickEvent */ void QCPLayerable::wheelEvent(QWheelEvent *event) { event->ignore(); } /* end of 'src/layer.cpp' */ /* including file 'src/axis/range.cpp' */ /* modified 2021-03-29T02:30:44, size 12221 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPRange //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPRange \brief Represents the range an axis is encompassing. contains a \a lower and \a upper double value and provides convenience input, output and modification functions. \see QCPAxis::setRange */ /* start of documentation of inline functions */ /*! \fn double QCPRange::size() const Returns the size of the range, i.e. \a upper-\a lower */ /*! \fn double QCPRange::center() const Returns the center of the range, i.e. (\a upper+\a lower)*0.5 */ /*! \fn void QCPRange::normalize() Makes sure \a lower is numerically smaller than \a upper. If this is not the case, the values are swapped. */ /*! \fn bool QCPRange::contains(double value) const Returns true when \a value lies within or exactly on the borders of the range. */ /*! \fn QCPRange &QCPRange::operator+=(const double& value) Adds \a value to both boundaries of the range. */ /*! \fn QCPRange &QCPRange::operator-=(const double& value) Subtracts \a value from both boundaries of the range. */ /*! \fn QCPRange &QCPRange::operator*=(const double& value) Multiplies both boundaries of the range by \a value. */ /*! \fn QCPRange &QCPRange::operator/=(const double& value) Divides both boundaries of the range by \a value. */ /* end of documentation of inline functions */ /*! Minimum range size (\a upper - \a lower) the range changing functions will accept. Smaller intervals would cause errors due to the 11-bit exponent of double precision numbers, corresponding to a minimum magnitude of roughly 1e-308. \warning Do not use this constant to indicate "arbitrarily small" values in plotting logic (as values that will appear in the plot)! It is intended only as a bound to compare against, e.g. to prevent axis ranges from obtaining underflowing ranges. \see validRange, maxRange */ const double QCPRange::minRange = 1e-280; /*! Maximum values (negative and positive) the range will accept in range-changing functions. Larger absolute values would cause errors due to the 11-bit exponent of double precision numbers, corresponding to a maximum magnitude of roughly 1e308. \warning Do not use this constant to indicate "arbitrarily large" values in plotting logic (as values that will appear in the plot)! It is intended only as a bound to compare against, e.g. to prevent axis ranges from obtaining overflowing ranges. \see validRange, minRange */ const double QCPRange::maxRange = 1e250; /*! Constructs a range with \a lower and \a upper set to zero. */ QCPRange::QCPRange() : lower(0), upper(0) { } /*! \overload Constructs a range with the specified \a lower and \a upper values. The resulting range will be normalized (see \ref normalize), so if \a lower is not numerically smaller than \a upper, they will be swapped. */ QCPRange::QCPRange(double lower, double upper) : lower(lower), upper(upper) { normalize(); } /*! \overload Expands this range such that \a otherRange is contained in the new range. It is assumed that both this range and \a otherRange are normalized (see \ref normalize). If this range contains NaN as lower or upper bound, it will be replaced by the respective bound of \a otherRange. If \a otherRange is already inside the current range, this function does nothing. \see expanded */ void QCPRange::expand(const QCPRange &otherRange) { if (lower > otherRange.lower || qIsNaN(lower)) lower = otherRange.lower; if (upper < otherRange.upper || qIsNaN(upper)) upper = otherRange.upper; } /*! \overload Expands this range such that \a includeCoord is contained in the new range. It is assumed that this range is normalized (see \ref normalize). If this range contains NaN as lower or upper bound, the respective bound will be set to \a includeCoord. If \a includeCoord is already inside the current range, this function does nothing. \see expand */ void QCPRange::expand(double includeCoord) { if (lower > includeCoord || qIsNaN(lower)) lower = includeCoord; if (upper < includeCoord || qIsNaN(upper)) upper = includeCoord; } /*! \overload Returns an expanded range that contains this and \a otherRange. It is assumed that both this range and \a otherRange are normalized (see \ref normalize). If this range contains NaN as lower or upper bound, the returned range's bound will be taken from \a otherRange. \see expand */ QCPRange QCPRange::expanded(const QCPRange &otherRange) const { QCPRange result = *this; result.expand(otherRange); return result; } /*! \overload Returns an expanded range that includes the specified \a includeCoord. It is assumed that this range is normalized (see \ref normalize). If this range contains NaN as lower or upper bound, the returned range's bound will be set to \a includeCoord. \see expand */ QCPRange QCPRange::expanded(double includeCoord) const { QCPRange result = *this; result.expand(includeCoord); return result; } /*! Returns this range, possibly modified to not exceed the bounds provided as \a lowerBound and \a upperBound. If possible, the size of the current range is preserved in the process. If the range shall only be bounded at the lower side, you can set \a upperBound to \ref QCPRange::maxRange. If it shall only be bounded at the upper side, set \a lowerBound to -\ref QCPRange::maxRange. */ QCPRange QCPRange::bounded(double lowerBound, double upperBound) const { if (lowerBound > upperBound) qSwap(lowerBound, upperBound); QCPRange result(lower, upper); if (result.lower < lowerBound) { result.lower = lowerBound; result.upper = lowerBound + size(); if (result.upper > upperBound || qFuzzyCompare(size(), upperBound-lowerBound)) result.upper = upperBound; } else if (result.upper > upperBound) { result.upper = upperBound; result.lower = upperBound - size(); if (result.lower < lowerBound || qFuzzyCompare(size(), upperBound-lowerBound)) result.lower = lowerBound; } return result; } /*! Returns a sanitized version of the range. Sanitized means for logarithmic scales, that the range won't span the positive and negative sign domain, i.e. contain zero. Further \a lower will always be numerically smaller (or equal) to \a upper. If the original range does span positive and negative sign domains or contains zero, the returned range will try to approximate the original range as good as possible. If the positive interval of the original range is wider than the negative interval, the returned range will only contain the positive interval, with lower bound set to \a rangeFac or \a rangeFac *\a upper, whichever is closer to zero. Same procedure is used if the negative interval is wider than the positive interval, this time by changing the \a upper bound. */ QCPRange QCPRange::sanitizedForLogScale() const { double rangeFac = 1e-3; QCPRange sanitizedRange(lower, upper); sanitizedRange.normalize(); // can't have range spanning negative and positive values in log plot, so change range to fix it //if (qFuzzyCompare(sanitizedRange.lower+1, 1) && !qFuzzyCompare(sanitizedRange.upper+1, 1)) if (sanitizedRange.lower == 0.0 && sanitizedRange.upper != 0.0) { // case lower is 0 if (rangeFac < sanitizedRange.upper*rangeFac) sanitizedRange.lower = rangeFac; else sanitizedRange.lower = sanitizedRange.upper*rangeFac; } //else if (!qFuzzyCompare(lower+1, 1) && qFuzzyCompare(upper+1, 1)) else if (sanitizedRange.lower != 0.0 && sanitizedRange.upper == 0.0) { // case upper is 0 if (-rangeFac > sanitizedRange.lower*rangeFac) sanitizedRange.upper = -rangeFac; else sanitizedRange.upper = sanitizedRange.lower*rangeFac; } else if (sanitizedRange.lower < 0 && sanitizedRange.upper > 0) { // find out whether negative or positive interval is wider to decide which sign domain will be chosen if (-sanitizedRange.lower > sanitizedRange.upper) { // negative is wider, do same as in case upper is 0 if (-rangeFac > sanitizedRange.lower*rangeFac) sanitizedRange.upper = -rangeFac; else sanitizedRange.upper = sanitizedRange.lower*rangeFac; } else { // positive is wider, do same as in case lower is 0 if (rangeFac < sanitizedRange.upper*rangeFac) sanitizedRange.lower = rangeFac; else sanitizedRange.lower = sanitizedRange.upper*rangeFac; } } // due to normalization, case lower>0 && upper<0 should never occur, because that implies upper -maxRange && upper < maxRange && qAbs(lower-upper) > minRange && qAbs(lower-upper) < maxRange && !(lower > 0 && qIsInf(upper/lower)) && !(upper < 0 && qIsInf(lower/upper))); } /*! \overload Checks, whether the specified range is within valid bounds, which are defined as QCPRange::maxRange and QCPRange::minRange. A valid range means: \li range bounds within -maxRange and maxRange \li range size above minRange \li range size below maxRange */ bool QCPRange::validRange(const QCPRange &range) { return (range.lower > -maxRange && range.upper < maxRange && qAbs(range.lower-range.upper) > minRange && qAbs(range.lower-range.upper) < maxRange && !(range.lower > 0 && qIsInf(range.upper/range.lower)) && !(range.upper < 0 && qIsInf(range.lower/range.upper))); } /* end of 'src/axis/range.cpp' */ /* including file 'src/selection.cpp' */ /* modified 2021-03-29T02:30:44, size 21837 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPDataRange //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPDataRange \brief Describes a data range given by begin and end index QCPDataRange holds two integers describing the begin (\ref setBegin) and end (\ref setEnd) index of a contiguous set of data points. The \a end index corresponds to the data point just after the last data point of the data range, like in standard iterators. Data Ranges are not bound to a certain plottable, thus they can be freely exchanged, created and modified. If a non-contiguous data set shall be described, the class \ref QCPDataSelection is used, which holds and manages multiple instances of \ref QCPDataRange. In most situations, \ref QCPDataSelection is thus used. Both \ref QCPDataRange and \ref QCPDataSelection offer convenience methods to work with them, e.g. \ref bounded, \ref expanded, \ref intersects, \ref intersection, \ref adjusted, \ref contains. Further, addition and subtraction operators (defined in \ref QCPDataSelection) can be used to join/subtract data ranges and data selections (or mixtures), to retrieve a corresponding \ref QCPDataSelection. %QCustomPlot's \ref dataselection "data selection mechanism" is based on \ref QCPDataSelection and QCPDataRange. \note Do not confuse \ref QCPDataRange with \ref QCPRange. A \ref QCPRange describes an interval in floating point plot coordinates, e.g. the current axis range. */ /* start documentation of inline functions */ /*! \fn int QCPDataRange::size() const Returns the number of data points described by this data range. This is equal to the end index minus the begin index. \see length */ /*! \fn int QCPDataRange::length() const Returns the number of data points described by this data range. Equivalent to \ref size. */ /*! \fn void QCPDataRange::setBegin(int begin) Sets the begin of this data range. The \a begin index points to the first data point that is part of the data range. No checks or corrections are made to ensure the resulting range is valid (\ref isValid). \see setEnd */ /*! \fn void QCPDataRange::setEnd(int end) Sets the end of this data range. The \a end index points to the data point just after the last data point that is part of the data range. No checks or corrections are made to ensure the resulting range is valid (\ref isValid). \see setBegin */ /*! \fn bool QCPDataRange::isValid() const Returns whether this range is valid. A valid range has a begin index greater or equal to 0, and an end index greater or equal to the begin index. \note Invalid ranges should be avoided and are never the result of any of QCustomPlot's methods (unless they are themselves fed with invalid ranges). Do not pass invalid ranges to QCustomPlot's methods. The invalid range is not inherently prevented in QCPDataRange, to allow temporary invalid begin/end values while manipulating the range. An invalid range is not necessarily empty (\ref isEmpty), since its \ref length can be negative and thus non-zero. */ /*! \fn bool QCPDataRange::isEmpty() const Returns whether this range is empty, i.e. whether its begin index equals its end index. \see size, length */ /*! \fn QCPDataRange QCPDataRange::adjusted(int changeBegin, int changeEnd) const Returns a data range where \a changeBegin and \a changeEnd were added to the begin and end indices, respectively. */ /* end documentation of inline functions */ /*! Creates an empty QCPDataRange, with begin and end set to 0. */ QCPDataRange::QCPDataRange() : mBegin(0), mEnd(0) { } /*! Creates a QCPDataRange, initialized with the specified \a begin and \a end. No checks or corrections are made to ensure the resulting range is valid (\ref isValid). */ QCPDataRange::QCPDataRange(int begin, int end) : mBegin(begin), mEnd(end) { } /*! Returns a data range that matches this data range, except that parts exceeding \a other are excluded. This method is very similar to \ref intersection, with one distinction: If this range and the \a other range share no intersection, the returned data range will be empty with begin and end set to the respective boundary side of \a other, at which this range is residing. (\ref intersection would just return a range with begin and end set to 0.) */ QCPDataRange QCPDataRange::bounded(const QCPDataRange &other) const { QCPDataRange result(intersection(other)); if (result.isEmpty()) // no intersection, preserve respective bounding side of otherRange as both begin and end of return value { if (mEnd <= other.mBegin) result = QCPDataRange(other.mBegin, other.mBegin); else result = QCPDataRange(other.mEnd, other.mEnd); } return result; } /*! Returns a data range that contains both this data range as well as \a other. */ QCPDataRange QCPDataRange::expanded(const QCPDataRange &other) const { return {qMin(mBegin, other.mBegin), qMax(mEnd, other.mEnd)}; } /*! Returns the data range which is contained in both this data range and \a other. This method is very similar to \ref bounded, with one distinction: If this range and the \a other range share no intersection, the returned data range will be empty with begin and end set to 0. (\ref bounded would return a range with begin and end set to one of the boundaries of \a other, depending on which side this range is on.) \see QCPDataSelection::intersection */ QCPDataRange QCPDataRange::intersection(const QCPDataRange &other) const { QCPDataRange result(qMax(mBegin, other.mBegin), qMin(mEnd, other.mEnd)); if (result.isValid()) return result; else return {}; } /*! Returns whether this data range and \a other share common data points. \see intersection, contains */ bool QCPDataRange::intersects(const QCPDataRange &other) const { return !( (mBegin > other.mBegin && mBegin >= other.mEnd) || (mEnd <= other.mBegin && mEnd < other.mEnd) ); } /*! Returns whether all data points of \a other are also contained inside this data range. \see intersects */ bool QCPDataRange::contains(const QCPDataRange &other) const { return mBegin <= other.mBegin && mEnd >= other.mEnd; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPDataSelection //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPDataSelection \brief Describes a data set by holding multiple QCPDataRange instances QCPDataSelection manages multiple instances of QCPDataRange in order to represent any (possibly disjoint) set of data selection. The data selection can be modified with addition and subtraction operators which take QCPDataSelection and QCPDataRange instances, as well as methods such as \ref addDataRange and \ref clear. Read access is provided by \ref dataRange, \ref dataRanges, \ref dataRangeCount, etc. The method \ref simplify is used to join directly adjacent or even overlapping QCPDataRange instances. QCPDataSelection automatically simplifies when using the addition/subtraction operators. The only case when \ref simplify is left to the user, is when calling \ref addDataRange, with the parameter \a simplify explicitly set to false. This is useful if many data ranges will be added to the selection successively and the overhead for simplifying after each iteration shall be avoided. In this case, you should make sure to call \ref simplify after completing the operation. Use \ref enforceType to bring the data selection into a state complying with the constraints for selections defined in \ref QCP::SelectionType. %QCustomPlot's \ref dataselection "data selection mechanism" is based on QCPDataSelection and QCPDataRange. \section qcpdataselection-iterating Iterating over a data selection As an example, the following code snippet calculates the average value of a graph's data \ref QCPAbstractPlottable::selection "selection": \snippet documentation/doc-code-snippets/mainwindow.cpp qcpdataselection-iterating-1 */ /* start documentation of inline functions */ /*! \fn int QCPDataSelection::dataRangeCount() const Returns the number of ranges that make up the data selection. The ranges can be accessed by \ref dataRange via their index. \see dataRange, dataPointCount */ /*! \fn QList QCPDataSelection::dataRanges() const Returns all data ranges that make up the data selection. If the data selection is simplified (the usual state of the selection, see \ref simplify), the ranges are sorted by ascending data point index. \see dataRange */ /*! \fn bool QCPDataSelection::isEmpty() const Returns true if there are no data ranges, and thus no data points, in this QCPDataSelection instance. \see dataRangeCount */ /* end documentation of inline functions */ /*! Creates an empty QCPDataSelection. */ QCPDataSelection::QCPDataSelection() { } /*! Creates a QCPDataSelection containing the provided \a range. */ QCPDataSelection::QCPDataSelection(const QCPDataRange &range) { mDataRanges.append(range); } /*! Returns true if this selection is identical (contains the same data ranges with the same begin and end indices) to \a other. Note that both data selections must be in simplified state (the usual state of the selection, see \ref simplify) for this operator to return correct results. */ bool QCPDataSelection::operator==(const QCPDataSelection &other) const { if (mDataRanges.size() != other.mDataRanges.size()) return false; for (int i=0; i= other.end()) break; // since data ranges are sorted after the simplify() call, no ranges which contain other will come after this if (thisEnd > other.begin()) // ranges which don't fulfill this are entirely before other and can be ignored { if (thisBegin >= other.begin()) // range leading segment is encompassed { if (thisEnd <= other.end()) // range fully encompassed, remove completely { mDataRanges.removeAt(i); continue; } else // only leading segment is encompassed, trim accordingly mDataRanges[i].setBegin(other.end()); } else // leading segment is not encompassed { if (thisEnd <= other.end()) // only trailing segment is encompassed, trim accordingly { mDataRanges[i].setEnd(other.begin()); } else // other lies inside this range, so split range { mDataRanges[i].setEnd(other.begin()); mDataRanges.insert(i+1, QCPDataRange(other.end(), thisEnd)); break; // since data ranges are sorted (and don't overlap) after simplify() call, we're done here } } } ++i; } return *this; } /*! Returns the total number of data points contained in all data ranges that make up this data selection. */ int QCPDataSelection::dataPointCount() const { int result = 0; foreach (QCPDataRange dataRange, mDataRanges) result += dataRange.length(); return result; } /*! Returns the data range with the specified \a index. If the data selection is simplified (the usual state of the selection, see \ref simplify), the ranges are sorted by ascending data point index. \see dataRangeCount */ QCPDataRange QCPDataSelection::dataRange(int index) const { if (index >= 0 && index < mDataRanges.size()) { return mDataRanges.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of range:" << index; return {}; } } /*! Returns a \ref QCPDataRange which spans the entire data selection, including possible intermediate segments which are not part of the original data selection. */ QCPDataRange QCPDataSelection::span() const { if (isEmpty()) return {}; else return {mDataRanges.first().begin(), mDataRanges.last().end()}; } /*! Adds the given \a dataRange to this data selection. This is equivalent to the += operator but allows disabling immediate simplification by setting \a simplify to false. This can improve performance if adding a very large amount of data ranges successively. In this case, make sure to call \ref simplify manually, after the operation. */ void QCPDataSelection::addDataRange(const QCPDataRange &dataRange, bool simplify) { mDataRanges.append(dataRange); if (simplify) this->simplify(); } /*! Removes all data ranges. The data selection then contains no data points. \ref isEmpty */ void QCPDataSelection::clear() { mDataRanges.clear(); } /*! Sorts all data ranges by range begin index in ascending order, and then joins directly adjacent or overlapping ranges. This can reduce the number of individual data ranges in the selection, and prevents possible double-counting when iterating over the data points held by the data ranges. This method is automatically called when using the addition/subtraction operators. The only case when \ref simplify is left to the user, is when calling \ref addDataRange, with the parameter \a simplify explicitly set to false. */ void QCPDataSelection::simplify() { // remove any empty ranges: for (int i=mDataRanges.size()-1; i>=0; --i) { if (mDataRanges.at(i).isEmpty()) mDataRanges.removeAt(i); } if (mDataRanges.isEmpty()) return; // sort ranges by starting value, ascending: std::sort(mDataRanges.begin(), mDataRanges.end(), lessThanDataRangeBegin); // join overlapping/contiguous ranges: int i = 1; while (i < mDataRanges.size()) { if (mDataRanges.at(i-1).end() >= mDataRanges.at(i).begin()) // range i overlaps/joins with i-1, so expand range i-1 appropriately and remove range i from list { mDataRanges[i-1].setEnd(qMax(mDataRanges.at(i-1).end(), mDataRanges.at(i).end())); mDataRanges.removeAt(i); } else ++i; } } /*! Makes sure this data selection conforms to the specified \a type selection type. Before the type is enforced, \ref simplify is called. Depending on \a type, enforcing means adding new data points that were previously not part of the selection, or removing data points from the selection. If the current selection already conforms to \a type, the data selection is not changed. \see QCP::SelectionType */ void QCPDataSelection::enforceType(QCP::SelectionType type) { simplify(); switch (type) { case QCP::stNone: { mDataRanges.clear(); break; } case QCP::stWhole: { // whole selection isn't defined by data range, so don't change anything (is handled in plottable methods) break; } case QCP::stSingleData: { // reduce all data ranges to the single first data point: if (!mDataRanges.isEmpty()) { if (mDataRanges.size() > 1) mDataRanges = QList() << mDataRanges.first(); if (mDataRanges.first().length() > 1) mDataRanges.first().setEnd(mDataRanges.first().begin()+1); } break; } case QCP::stDataRange: { if (!isEmpty()) mDataRanges = QList() << span(); break; } case QCP::stMultipleDataRanges: { // this is the selection type that allows all concievable combinations of ranges, so do nothing break; } } } /*! Returns true if the data selection \a other is contained entirely in this data selection, i.e. all data point indices that are in \a other are also in this data selection. \see QCPDataRange::contains */ bool QCPDataSelection::contains(const QCPDataSelection &other) const { if (other.isEmpty()) return false; int otherIndex = 0; int thisIndex = 0; while (thisIndex < mDataRanges.size() && otherIndex < other.mDataRanges.size()) { if (mDataRanges.at(thisIndex).contains(other.mDataRanges.at(otherIndex))) ++otherIndex; else ++thisIndex; } return thisIndex < mDataRanges.size(); // if thisIndex ran all the way to the end to find a containing range for the current otherIndex, other is not contained in this } /*! Returns a data selection containing the points which are both in this data selection and in the data range \a other. A common use case is to limit an unknown data selection to the valid range of a data container, using \ref QCPDataContainer::dataRange as \a other. One can then safely iterate over the returned data selection without exceeding the data container's bounds. */ QCPDataSelection QCPDataSelection::intersection(const QCPDataRange &other) const { QCPDataSelection result; foreach (QCPDataRange dataRange, mDataRanges) result.addDataRange(dataRange.intersection(other), false); result.simplify(); return result; } /*! Returns a data selection containing the points which are both in this data selection and in the data selection \a other. */ QCPDataSelection QCPDataSelection::intersection(const QCPDataSelection &other) const { QCPDataSelection result; for (int i=0; iorientation() == Qt::Horizontal) return {axis->pixelToCoord(mRect.left()), axis->pixelToCoord(mRect.left()+mRect.width())}; else return {axis->pixelToCoord(mRect.top()+mRect.height()), axis->pixelToCoord(mRect.top())}; } else { qDebug() << Q_FUNC_INFO << "called with axis zero"; return {}; } } /*! Sets the pen that will be used to draw the selection rect outline. \see setBrush */ void QCPSelectionRect::setPen(const QPen &pen) { mPen = pen; } /*! Sets the brush that will be used to fill the selection rect. By default the selection rect is not filled, i.e. \a brush is Qt::NoBrush. \see setPen */ void QCPSelectionRect::setBrush(const QBrush &brush) { mBrush = brush; } /*! If there is currently a selection interaction going on (\ref isActive), the interaction is canceled. The selection rect will emit the \ref canceled signal. */ void QCPSelectionRect::cancel() { if (mActive) { mActive = false; emit canceled(mRect, nullptr); } } /*! \internal This method is called by QCustomPlot to indicate that a selection rect interaction was initiated. The default implementation sets the selection rect to active, initializes the selection rect geometry and emits the \ref started signal. */ void QCPSelectionRect::startSelection(QMouseEvent *event) { mActive = true; mRect = QRect(event->pos(), event->pos()); emit started(event); } /*! \internal This method is called by QCustomPlot to indicate that an ongoing selection rect interaction needs to update its geometry. The default implementation updates the rect and emits the \ref changed signal. */ void QCPSelectionRect::moveSelection(QMouseEvent *event) { mRect.setBottomRight(event->pos()); emit changed(mRect, event); layer()->replot(); } /*! \internal This method is called by QCustomPlot to indicate that an ongoing selection rect interaction has finished by the user releasing the mouse button. The default implementation deactivates the selection rect and emits the \ref accepted signal. */ void QCPSelectionRect::endSelection(QMouseEvent *event) { mRect.setBottomRight(event->pos()); mActive = false; emit accepted(mRect, event); } /*! \internal This method is called by QCustomPlot when a key has been pressed by the user while the selection rect interaction is active. The default implementation allows to \ref cancel the interaction by hitting the escape key. */ void QCPSelectionRect::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape && mActive) { mActive = false; emit canceled(mRect, event); } } /* inherits documentation from base class */ void QCPSelectionRect::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeOther); } /*! \internal If the selection rect is active (\ref isActive), draws the selection rect defined by \a mRect. \seebaseclassmethod */ void QCPSelectionRect::draw(QCPPainter *painter) { if (mActive) { painter->setPen(mPen); painter->setBrush(mBrush); painter->drawRect(mRect); } } /* end of 'src/selectionrect.cpp' */ /* including file 'src/layout.cpp' */ /* modified 2021-03-29T02:30:44, size 78863 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPMarginGroup //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPMarginGroup \brief A margin group allows synchronization of margin sides if working with multiple layout elements. QCPMarginGroup allows you to tie a margin side of two or more layout elements together, such that they will all have the same size, based on the largest required margin in the group. \n \image html QCPMarginGroup.png "Demonstration of QCPMarginGroup" \n In certain situations it is desirable that margins at specific sides are synchronized across layout elements. For example, if one QCPAxisRect is below another one in a grid layout, it will provide a cleaner look to the user if the left and right margins of the two axis rects are of the same size. The left axis of the top axis rect will then be at the same horizontal position as the left axis of the lower axis rect, making them appear aligned. The same applies for the right axes. This is what QCPMarginGroup makes possible. To add/remove a specific side of a layout element to/from a margin group, use the \ref QCPLayoutElement::setMarginGroup method. To completely break apart the margin group, either call \ref clear, or just delete the margin group. \section QCPMarginGroup-example Example First create a margin group: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpmargingroup-creation-1 Then set this group on the layout element sides: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpmargingroup-creation-2 Here, we've used the first two axis rects of the plot and synchronized their left margins with each other and their right margins with each other. */ /* start documentation of inline functions */ /*! \fn QList QCPMarginGroup::elements(QCP::MarginSide side) const Returns a list of all layout elements that have their margin \a side associated with this margin group. */ /* end documentation of inline functions */ /*! Creates a new QCPMarginGroup instance in \a parentPlot. */ QCPMarginGroup::QCPMarginGroup(QCustomPlot *parentPlot) : QObject(parentPlot), mParentPlot(parentPlot) { mChildren.insert(QCP::msLeft, QList()); mChildren.insert(QCP::msRight, QList()); mChildren.insert(QCP::msTop, QList()); mChildren.insert(QCP::msBottom, QList()); } QCPMarginGroup::~QCPMarginGroup() { clear(); } /*! Returns whether this margin group is empty. If this function returns true, no layout elements use this margin group to synchronize margin sides. */ bool QCPMarginGroup::isEmpty() const { QHashIterator > it(mChildren); while (it.hasNext()) { it.next(); if (!it.value().isEmpty()) return false; } return true; } /*! Clears this margin group. The synchronization of the margin sides that use this margin group is lifted and they will use their individual margin sizes again. */ void QCPMarginGroup::clear() { // make all children remove themselves from this margin group: QHashIterator > it(mChildren); while (it.hasNext()) { it.next(); const QList elements = it.value(); for (int i=elements.size()-1; i>=0; --i) elements.at(i)->setMarginGroup(it.key(), nullptr); // removes itself from mChildren via removeChild } } /*! \internal Returns the synchronized common margin for \a side. This is the margin value that will be used by the layout element on the respective side, if it is part of this margin group. The common margin is calculated by requesting the automatic margin (\ref QCPLayoutElement::calculateAutoMargin) of each element associated with \a side in this margin group, and choosing the largest returned value. (QCPLayoutElement::minimumMargins is taken into account, too.) */ int QCPMarginGroup::commonMargin(QCP::MarginSide side) const { // query all automatic margins of the layout elements in this margin group side and find maximum: int result = 0; foreach (QCPLayoutElement *el, mChildren.value(side)) { if (!el->autoMargins().testFlag(side)) continue; int m = qMax(el->calculateAutoMargin(side), QCP::getMarginValue(el->minimumMargins(), side)); if (m > result) result = m; } return result; } /*! \internal Adds \a element to the internal list of child elements, for the margin \a side. This function does not modify the margin group property of \a element. */ void QCPMarginGroup::addChild(QCP::MarginSide side, QCPLayoutElement *element) { if (!mChildren[side].contains(element)) mChildren[side].append(element); else qDebug() << Q_FUNC_INFO << "element is already child of this margin group side" << reinterpret_cast(element); } /*! \internal Removes \a element from the internal list of child elements, for the margin \a side. This function does not modify the margin group property of \a element. */ void QCPMarginGroup::removeChild(QCP::MarginSide side, QCPLayoutElement *element) { if (!mChildren[side].removeOne(element)) qDebug() << Q_FUNC_INFO << "element is not child of this margin group side" << reinterpret_cast(element); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPLayoutElement //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPLayoutElement \brief The abstract base class for all objects that form \ref thelayoutsystem "the layout system". This is an abstract base class. As such, it can't be instantiated directly, rather use one of its subclasses. A Layout element is a rectangular object which can be placed in layouts. It has an outer rect (QCPLayoutElement::outerRect) and an inner rect (\ref QCPLayoutElement::rect). The difference between outer and inner rect is called its margin. The margin can either be set to automatic or manual (\ref setAutoMargins) on a per-side basis. If a side is set to manual, that margin can be set explicitly with \ref setMargins and will stay fixed at that value. If it's set to automatic, the layout element subclass will control the value itself (via \ref calculateAutoMargin). Layout elements can be placed in layouts (base class QCPLayout) like QCPLayoutGrid. The top level layout is reachable via \ref QCustomPlot::plotLayout, and is a \ref QCPLayoutGrid. Since \ref QCPLayout itself derives from \ref QCPLayoutElement, layouts can be nested. Thus in QCustomPlot one can divide layout elements into two categories: The ones that are invisible by themselves, because they don't draw anything. Their only purpose is to manage the position and size of other layout elements. This category of layout elements usually use QCPLayout as base class. Then there is the category of layout elements which actually draw something. For example, QCPAxisRect, QCPLegend and QCPTextElement are of this category. This does not necessarily mean that the latter category can't have child layout elements. QCPLegend for instance, actually derives from QCPLayoutGrid and the individual legend items are child layout elements in the grid layout. */ /* start documentation of inline functions */ /*! \fn QCPLayout *QCPLayoutElement::layout() const Returns the parent layout of this layout element. */ /*! \fn QRect QCPLayoutElement::rect() const Returns the inner rect of this layout element. The inner rect is the outer rect (\ref outerRect, \ref setOuterRect) shrinked by the margins (\ref setMargins, \ref setAutoMargins). In some cases, the area between outer and inner rect is left blank. In other cases the margin area is used to display peripheral graphics while the main content is in the inner rect. This is where automatic margin calculation becomes interesting because it allows the layout element to adapt the margins to the peripheral graphics it wants to draw. For example, \ref QCPAxisRect draws the axis labels and tick labels in the margin area, thus needs to adjust the margins (if \ref setAutoMargins is enabled) according to the space required by the labels of the axes. \see outerRect */ /*! \fn QRect QCPLayoutElement::outerRect() const Returns the outer rect of this layout element. The outer rect is the inner rect expanded by the margins (\ref setMargins, \ref setAutoMargins). The outer rect is used (and set via \ref setOuterRect) by the parent \ref QCPLayout to control the size of this layout element. \see rect */ /* end documentation of inline functions */ /*! Creates an instance of QCPLayoutElement and sets default values. */ QCPLayoutElement::QCPLayoutElement(QCustomPlot *parentPlot) : QCPLayerable(parentPlot), // parenthood is changed as soon as layout element gets inserted into a layout (except for top level layout) mParentLayout(nullptr), mMinimumSize(), mMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX), mSizeConstraintRect(scrInnerRect), mRect(0, 0, 0, 0), mOuterRect(0, 0, 0, 0), mMargins(0, 0, 0, 0), mMinimumMargins(0, 0, 0, 0), mAutoMargins(QCP::msAll) { } QCPLayoutElement::~QCPLayoutElement() { setMarginGroup(QCP::msAll, nullptr); // unregister at margin groups, if there are any // unregister at layout: if (qobject_cast(mParentLayout)) // the qobject_cast is just a safeguard in case the layout forgets to call clear() in its dtor and this dtor is called by QObject dtor mParentLayout->take(this); } /*! Sets the outer rect of this layout element. If the layout element is inside a layout, the layout sets the position and size of this layout element using this function. Calling this function externally has no effect, since the layout will overwrite any changes to the outer rect upon the next replot. The layout element will adapt its inner \ref rect by applying the margins inward to the outer rect. \see rect */ void QCPLayoutElement::setOuterRect(const QRect &rect) { if (mOuterRect != rect) { mOuterRect = rect; mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom()); } } /*! Sets the margins of this layout element. If \ref setAutoMargins is disabled for some or all sides, this function is used to manually set the margin on those sides. Sides that are still set to be handled automatically are ignored and may have any value in \a margins. The margin is the distance between the outer rect (controlled by the parent layout via \ref setOuterRect) and the inner \ref rect (which usually contains the main content of this layout element). \see setAutoMargins */ void QCPLayoutElement::setMargins(const QMargins &margins) { if (mMargins != margins) { mMargins = margins; mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom()); } } /*! If \ref setAutoMargins is enabled on some or all margins, this function is used to provide minimum values for those margins. The minimum values are not enforced on margin sides that were set to be under manual control via \ref setAutoMargins. \see setAutoMargins */ void QCPLayoutElement::setMinimumMargins(const QMargins &margins) { if (mMinimumMargins != margins) { mMinimumMargins = margins; } } /*! Sets on which sides the margin shall be calculated automatically. If a side is calculated automatically, a minimum margin value may be provided with \ref setMinimumMargins. If a side is set to be controlled manually, the value may be specified with \ref setMargins. Margin sides that are under automatic control may participate in a \ref QCPMarginGroup (see \ref setMarginGroup), to synchronize (align) it with other layout elements in the plot. \see setMinimumMargins, setMargins, QCP::MarginSide */ void QCPLayoutElement::setAutoMargins(QCP::MarginSides sides) { mAutoMargins = sides; } /*! Sets the minimum size of this layout element. A parent layout tries to respect the \a size here by changing row/column sizes in the layout accordingly. If the parent layout size is not sufficient to satisfy all minimum size constraints of its child layout elements, the layout may set a size that is actually smaller than \a size. QCustomPlot propagates the layout's size constraints to the outside by setting its own minimum QWidget size accordingly, so violations of \a size should be exceptions. Whether this constraint applies to the inner or the outer rect can be specified with \ref setSizeConstraintRect (see \ref rect and \ref outerRect). */ void QCPLayoutElement::setMinimumSize(const QSize &size) { if (mMinimumSize != size) { mMinimumSize = size; if (mParentLayout) mParentLayout->sizeConstraintsChanged(); } } /*! \overload Sets the minimum size of this layout element. Whether this constraint applies to the inner or the outer rect can be specified with \ref setSizeConstraintRect (see \ref rect and \ref outerRect). */ void QCPLayoutElement::setMinimumSize(int width, int height) { setMinimumSize(QSize(width, height)); } /*! Sets the maximum size of this layout element. A parent layout tries to respect the \a size here by changing row/column sizes in the layout accordingly. Whether this constraint applies to the inner or the outer rect can be specified with \ref setSizeConstraintRect (see \ref rect and \ref outerRect). */ void QCPLayoutElement::setMaximumSize(const QSize &size) { if (mMaximumSize != size) { mMaximumSize = size; if (mParentLayout) mParentLayout->sizeConstraintsChanged(); } } /*! \overload Sets the maximum size of this layout element. Whether this constraint applies to the inner or the outer rect can be specified with \ref setSizeConstraintRect (see \ref rect and \ref outerRect). */ void QCPLayoutElement::setMaximumSize(int width, int height) { setMaximumSize(QSize(width, height)); } /*! Sets to which rect of a layout element the size constraints apply. Size constraints can be set via \ref setMinimumSize and \ref setMaximumSize. The outer rect (\ref outerRect) includes the margins (e.g. in the case of a QCPAxisRect the axis labels), whereas the inner rect (\ref rect) does not. \see setMinimumSize, setMaximumSize */ void QCPLayoutElement::setSizeConstraintRect(SizeConstraintRect constraintRect) { if (mSizeConstraintRect != constraintRect) { mSizeConstraintRect = constraintRect; if (mParentLayout) mParentLayout->sizeConstraintsChanged(); } } /*! Sets the margin \a group of the specified margin \a sides. Margin groups allow synchronizing specified margins across layout elements, see the documentation of \ref QCPMarginGroup. To unset the margin group of \a sides, set \a group to \c nullptr. Note that margin groups only work for margin sides that are set to automatic (\ref setAutoMargins). \see QCP::MarginSide */ void QCPLayoutElement::setMarginGroup(QCP::MarginSides sides, QCPMarginGroup *group) { QVector sideVector; if (sides.testFlag(QCP::msLeft)) sideVector.append(QCP::msLeft); if (sides.testFlag(QCP::msRight)) sideVector.append(QCP::msRight); if (sides.testFlag(QCP::msTop)) sideVector.append(QCP::msTop); if (sides.testFlag(QCP::msBottom)) sideVector.append(QCP::msBottom); foreach (QCP::MarginSide side, sideVector) { if (marginGroup(side) != group) { QCPMarginGroup *oldGroup = marginGroup(side); if (oldGroup) // unregister at old group oldGroup->removeChild(side, this); if (!group) // if setting to 0, remove hash entry. Else set hash entry to new group and register there { mMarginGroups.remove(side); } else // setting to a new group { mMarginGroups[side] = group; group->addChild(side, this); } } } } /*! Updates the layout element and sub-elements. This function is automatically called before every replot by the parent layout element. It is called multiple times, once for every \ref UpdatePhase. The phases are run through in the order of the enum values. For details about what happens at the different phases, see the documentation of \ref UpdatePhase. Layout elements that have child elements should call the \ref update method of their child elements, and pass the current \a phase unchanged. The default implementation executes the automatic margin mechanism in the \ref upMargins phase. Subclasses should make sure to call the base class implementation. */ void QCPLayoutElement::update(UpdatePhase phase) { if (phase == upMargins) { if (mAutoMargins != QCP::msNone) { // set the margins of this layout element according to automatic margin calculation, either directly or via a margin group: QMargins newMargins = mMargins; const QList allMarginSides = QList() << QCP::msLeft << QCP::msRight << QCP::msTop << QCP::msBottom; foreach (QCP::MarginSide side, allMarginSides) { if (mAutoMargins.testFlag(side)) // this side's margin shall be calculated automatically { if (mMarginGroups.contains(side)) QCP::setMarginValue(newMargins, side, mMarginGroups[side]->commonMargin(side)); // this side is part of a margin group, so get the margin value from that group else QCP::setMarginValue(newMargins, side, calculateAutoMargin(side)); // this side is not part of a group, so calculate the value directly // apply minimum margin restrictions: if (QCP::getMarginValue(newMargins, side) < QCP::getMarginValue(mMinimumMargins, side)) QCP::setMarginValue(newMargins, side, QCP::getMarginValue(mMinimumMargins, side)); } } setMargins(newMargins); } } } /*! Returns the suggested minimum size this layout element (the \ref outerRect) may be compressed to, if no manual minimum size is set. if a minimum size (\ref setMinimumSize) was not set manually, parent layouts use the returned size (usually indirectly through \ref QCPLayout::getFinalMinimumOuterSize) to determine the minimum allowed size of this layout element. A manual minimum size is considered set if it is non-zero. The default implementation simply returns the sum of the horizontal margins for the width and the sum of the vertical margins for the height. Reimplementations may use their detailed knowledge about the layout element's content to provide size hints. */ QSize QCPLayoutElement::minimumOuterSizeHint() const { return {mMargins.left()+mMargins.right(), mMargins.top()+mMargins.bottom()}; } /*! Returns the suggested maximum size this layout element (the \ref outerRect) may be expanded to, if no manual maximum size is set. if a maximum size (\ref setMaximumSize) was not set manually, parent layouts use the returned size (usually indirectly through \ref QCPLayout::getFinalMaximumOuterSize) to determine the maximum allowed size of this layout element. A manual maximum size is considered set if it is smaller than Qt's \c QWIDGETSIZE_MAX. The default implementation simply returns \c QWIDGETSIZE_MAX for both width and height, implying no suggested maximum size. Reimplementations may use their detailed knowledge about the layout element's content to provide size hints. */ QSize QCPLayoutElement::maximumOuterSizeHint() const { return {QWIDGETSIZE_MAX, QWIDGETSIZE_MAX}; } /*! Returns a list of all child elements in this layout element. If \a recursive is true, all sub-child elements are included in the list, too. \warning There may be \c nullptr entries in the returned list. For example, QCPLayoutGrid may have empty cells which yield \c nullptr at the respective index. */ QList QCPLayoutElement::elements(bool recursive) const { Q_UNUSED(recursive) return QList(); } /*! Layout elements are sensitive to events inside their outer rect. If \a pos is within the outer rect, this method returns a value corresponding to 0.99 times the parent plot's selection tolerance. However, layout elements are not selectable by default. So if \a onlySelectable is true, -1.0 is returned. See \ref QCPLayerable::selectTest for a general explanation of this virtual method. QCPLayoutElement subclasses may reimplement this method to provide more specific selection test behaviour. */ double QCPLayoutElement::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable) return -1; if (QRectF(mOuterRect).contains(pos)) { if (mParentPlot) return mParentPlot->selectionTolerance()*0.99; else { qDebug() << Q_FUNC_INFO << "parent plot not defined"; return -1; } } else return -1; } /*! \internal propagates the parent plot initialization to all child elements, by calling \ref QCPLayerable::initializeParentPlot on them. */ void QCPLayoutElement::parentPlotInitialized(QCustomPlot *parentPlot) { foreach (QCPLayoutElement *el, elements(false)) { if (!el->parentPlot()) el->initializeParentPlot(parentPlot); } } /*! \internal Returns the margin size for this \a side. It is used if automatic margins is enabled for this \a side (see \ref setAutoMargins). If a minimum margin was set with \ref setMinimumMargins, the returned value will not be smaller than the specified minimum margin. The default implementation just returns the respective manual margin (\ref setMargins) or the minimum margin, whichever is larger. */ int QCPLayoutElement::calculateAutoMargin(QCP::MarginSide side) { return qMax(QCP::getMarginValue(mMargins, side), QCP::getMarginValue(mMinimumMargins, side)); } /*! \internal This virtual method is called when this layout element was moved to a different QCPLayout, or when this layout element has changed its logical position (e.g. row and/or column) within the same QCPLayout. Subclasses may use this to react accordingly. Since this method is called after the completion of the move, you can access the new parent layout via \ref layout(). The default implementation does nothing. */ void QCPLayoutElement::layoutChanged() { } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPLayout //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPLayout \brief The abstract base class for layouts This is an abstract base class for layout elements whose main purpose is to define the position and size of other child layout elements. In most cases, layouts don't draw anything themselves (but there are exceptions to this, e.g. QCPLegend). QCPLayout derives from QCPLayoutElement, and thus can itself be nested in other layouts. QCPLayout introduces a common interface for accessing and manipulating the child elements. Those functions are most notably \ref elementCount, \ref elementAt, \ref takeAt, \ref take, \ref simplify, \ref removeAt, \ref remove and \ref clear. Individual subclasses may add more functions to this interface which are more specialized to the form of the layout. For example, \ref QCPLayoutGrid adds functions that take row and column indices to access cells of the layout grid more conveniently. Since this is an abstract base class, you can't instantiate it directly. Rather use one of its subclasses like QCPLayoutGrid or QCPLayoutInset. For a general introduction to the layout system, see the dedicated documentation page \ref thelayoutsystem "The Layout System". */ /* start documentation of pure virtual functions */ /*! \fn virtual int QCPLayout::elementCount() const = 0 Returns the number of elements/cells in the layout. \see elements, elementAt */ /*! \fn virtual QCPLayoutElement* QCPLayout::elementAt(int index) const = 0 Returns the element in the cell with the given \a index. If \a index is invalid, returns \c nullptr. Note that even if \a index is valid, the respective cell may be empty in some layouts (e.g. QCPLayoutGrid), so this function may return \c nullptr in those cases. You may use this function to check whether a cell is empty or not. \see elements, elementCount, takeAt */ /*! \fn virtual QCPLayoutElement* QCPLayout::takeAt(int index) = 0 Removes the element with the given \a index from the layout and returns it. If the \a index is invalid or the cell with that index is empty, returns \c nullptr. Note that some layouts don't remove the respective cell right away but leave an empty cell after successful removal of the layout element. To collapse empty cells, use \ref simplify. \see elementAt, take */ /*! \fn virtual bool QCPLayout::take(QCPLayoutElement* element) = 0 Removes the specified \a element from the layout and returns true on success. If the \a element isn't in this layout, returns false. Note that some layouts don't remove the respective cell right away but leave an empty cell after successful removal of the layout element. To collapse empty cells, use \ref simplify. \see takeAt */ /* end documentation of pure virtual functions */ /*! Creates an instance of QCPLayout and sets default values. Note that since QCPLayout is an abstract base class, it can't be instantiated directly. */ QCPLayout::QCPLayout() { } /*! If \a phase is \ref upLayout, calls \ref updateLayout, which subclasses may reimplement to reposition and resize their cells. Finally, the call is propagated down to all child \ref QCPLayoutElement "QCPLayoutElements". For details about this method and the update phases, see the documentation of \ref QCPLayoutElement::update. */ void QCPLayout::update(UpdatePhase phase) { QCPLayoutElement::update(phase); // set child element rects according to layout: if (phase == upLayout) updateLayout(); // propagate update call to child elements: const int elCount = elementCount(); for (int i=0; iupdate(phase); } } /* inherits documentation from base class */ QList QCPLayout::elements(bool recursive) const { const int c = elementCount(); QList result; #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) result.reserve(c); #endif for (int i=0; ielements(recursive); } } return result; } /*! Simplifies the layout by collapsing empty cells. The exact behavior depends on subclasses, the default implementation does nothing. Not all layouts need simplification. For example, QCPLayoutInset doesn't use explicit simplification while QCPLayoutGrid does. */ void QCPLayout::simplify() { } /*! Removes and deletes the element at the provided \a index. Returns true on success. If \a index is invalid or points to an empty cell, returns false. This function internally uses \ref takeAt to remove the element from the layout and then deletes the returned element. Note that some layouts don't remove the respective cell right away but leave an empty cell after successful removal of the layout element. To collapse empty cells, use \ref simplify. \see remove, takeAt */ bool QCPLayout::removeAt(int index) { if (QCPLayoutElement *el = takeAt(index)) { delete el; return true; } else return false; } /*! Removes and deletes the provided \a element. Returns true on success. If \a element is not in the layout, returns false. This function internally uses \ref takeAt to remove the element from the layout and then deletes the element. Note that some layouts don't remove the respective cell right away but leave an empty cell after successful removal of the layout element. To collapse empty cells, use \ref simplify. \see removeAt, take */ bool QCPLayout::remove(QCPLayoutElement *element) { if (take(element)) { delete element; return true; } else return false; } /*! Removes and deletes all layout elements in this layout. Finally calls \ref simplify to make sure all empty cells are collapsed. \see remove, removeAt */ void QCPLayout::clear() { for (int i=elementCount()-1; i>=0; --i) { if (elementAt(i)) removeAt(i); } simplify(); } /*! Subclasses call this method to report changed (minimum/maximum) size constraints. If the parent of this layout is again a QCPLayout, forwards the call to the parent's \ref sizeConstraintsChanged. If the parent is a QWidget (i.e. is the \ref QCustomPlot::plotLayout of QCustomPlot), calls QWidget::updateGeometry, so if the QCustomPlot widget is inside a Qt QLayout, it may update itself and resize cells accordingly. */ void QCPLayout::sizeConstraintsChanged() const { if (QWidget *w = qobject_cast(parent())) w->updateGeometry(); else if (QCPLayout *l = qobject_cast(parent())) l->sizeConstraintsChanged(); } /*! \internal Subclasses reimplement this method to update the position and sizes of the child elements/cells via calling their \ref QCPLayoutElement::setOuterRect. The default implementation does nothing. The geometry used as a reference is the inner \ref rect of this layout. Child elements should stay within that rect. \ref getSectionSizes may help with the reimplementation of this function. \see update */ void QCPLayout::updateLayout() { } /*! \internal Associates \a el with this layout. This is done by setting the \ref QCPLayoutElement::layout, the \ref QCPLayerable::parentLayerable and the QObject parent to this layout. Further, if \a el didn't previously have a parent plot, calls \ref QCPLayerable::initializeParentPlot on \a el to set the paret plot. This method is used by subclass specific methods that add elements to the layout. Note that this method only changes properties in \a el. The removal from the old layout and the insertion into the new layout must be done additionally. */ void QCPLayout::adoptElement(QCPLayoutElement *el) { if (el) { el->mParentLayout = this; el->setParentLayerable(this); el->setParent(this); if (!el->parentPlot()) el->initializeParentPlot(mParentPlot); el->layoutChanged(); } else qDebug() << Q_FUNC_INFO << "Null element passed"; } /*! \internal Disassociates \a el from this layout. This is done by setting the \ref QCPLayoutElement::layout and the \ref QCPLayerable::parentLayerable to zero. The QObject parent is set to the parent QCustomPlot. This method is used by subclass specific methods that remove elements from the layout (e.g. \ref take or \ref takeAt). Note that this method only changes properties in \a el. The removal from the old layout must be done additionally. */ void QCPLayout::releaseElement(QCPLayoutElement *el) { if (el) { el->mParentLayout = nullptr; el->setParentLayerable(nullptr); el->setParent(mParentPlot); // Note: Don't initializeParentPlot(0) here, because layout element will stay in same parent plot } else qDebug() << Q_FUNC_INFO << "Null element passed"; } /*! \internal This is a helper function for the implementation of \ref updateLayout in subclasses. It calculates the sizes of one-dimensional sections with provided constraints on maximum section sizes, minimum section sizes, relative stretch factors and the final total size of all sections. The QVector entries refer to the sections. Thus all QVectors must have the same size. \a maxSizes gives the maximum allowed size of each section. If there shall be no maximum size imposed, set all vector values to Qt's QWIDGETSIZE_MAX. \a minSizes gives the minimum allowed size of each section. If there shall be no minimum size imposed, set all vector values to zero. If the \a minSizes entries add up to a value greater than \a totalSize, sections will be scaled smaller than the proposed minimum sizes. (In other words, not exceeding the allowed total size is taken to be more important than not going below minimum section sizes.) \a stretchFactors give the relative proportions of the sections to each other. If all sections shall be scaled equally, set all values equal. If the first section shall be double the size of each individual other section, set the first number of \a stretchFactors to double the value of the other individual values (e.g. {2, 1, 1, 1}). \a totalSize is the value that the final section sizes will add up to. Due to rounding, the actual sum may differ slightly. If you want the section sizes to sum up to exactly that value, you could distribute the remaining difference on the sections. The return value is a QVector containing the section sizes. */ QVector QCPLayout::getSectionSizes(QVector maxSizes, QVector minSizes, QVector stretchFactors, int totalSize) const { if (maxSizes.size() != minSizes.size() || minSizes.size() != stretchFactors.size()) { qDebug() << Q_FUNC_INFO << "Passed vector sizes aren't equal:" << maxSizes << minSizes << stretchFactors; return QVector(); } if (stretchFactors.isEmpty()) return QVector(); int sectionCount = stretchFactors.size(); QVector sectionSizes(sectionCount); // if provided total size is forced smaller than total minimum size, ignore minimum sizes (squeeze sections): int minSizeSum = 0; for (int i=0; i minimumLockedSections; QList unfinishedSections; for (int i=0; i result(sectionCount); for (int i=0; iminimumOuterSizeHint(); QSize minOuter = el->minimumSize(); // depending on sizeConstraitRect this might be with respect to inner rect, so possibly add margins in next four lines (preserving unset minimum of 0) if (minOuter.width() > 0 && el->sizeConstraintRect() == QCPLayoutElement::scrInnerRect) minOuter.rwidth() += el->margins().left() + el->margins().right(); if (minOuter.height() > 0 && el->sizeConstraintRect() == QCPLayoutElement::scrInnerRect) minOuter.rheight() += el->margins().top() + el->margins().bottom(); return {minOuter.width() > 0 ? minOuter.width() : minOuterHint.width(), minOuter.height() > 0 ? minOuter.height() : minOuterHint.height()}; } /*! \internal This is a helper function for the implementation of subclasses. It returns the maximum size that should finally be used for the outer rect of the passed layout element \a el. It takes into account whether a manual maximum size is set (\ref QCPLayoutElement::setMaximumSize), which size constraint is set (\ref QCPLayoutElement::setSizeConstraintRect), as well as the maximum size hint, if no manual maximum size was set (\ref QCPLayoutElement::maximumOuterSizeHint). */ QSize QCPLayout::getFinalMaximumOuterSize(const QCPLayoutElement *el) { QSize maxOuterHint = el->maximumOuterSizeHint(); QSize maxOuter = el->maximumSize(); // depending on sizeConstraitRect this might be with respect to inner rect, so possibly add margins in next four lines (preserving unset maximum of QWIDGETSIZE_MAX) if (maxOuter.width() < QWIDGETSIZE_MAX && el->sizeConstraintRect() == QCPLayoutElement::scrInnerRect) maxOuter.rwidth() += el->margins().left() + el->margins().right(); if (maxOuter.height() < QWIDGETSIZE_MAX && el->sizeConstraintRect() == QCPLayoutElement::scrInnerRect) maxOuter.rheight() += el->margins().top() + el->margins().bottom(); return {maxOuter.width() < QWIDGETSIZE_MAX ? maxOuter.width() : maxOuterHint.width(), maxOuter.height() < QWIDGETSIZE_MAX ? maxOuter.height() : maxOuterHint.height()}; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPLayoutGrid //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPLayoutGrid \brief A layout that arranges child elements in a grid Elements are laid out in a grid with configurable stretch factors (\ref setColumnStretchFactor, \ref setRowStretchFactor) and spacing (\ref setColumnSpacing, \ref setRowSpacing). Elements can be added to cells via \ref addElement. The grid is expanded if the specified row or column doesn't exist yet. Whether a cell contains a valid layout element can be checked with \ref hasElement, that element can be retrieved with \ref element. If rows and columns that only have empty cells shall be removed, call \ref simplify. Removal of elements is either done by just adding the element to a different layout or by using the QCPLayout interface \ref take or \ref remove. If you use \ref addElement(QCPLayoutElement*) without explicit parameters for \a row and \a column, the grid layout will choose the position according to the current \ref setFillOrder and the wrapping (\ref setWrap). Row and column insertion can be performed with \ref insertRow and \ref insertColumn. */ /* start documentation of inline functions */ /*! \fn int QCPLayoutGrid::rowCount() const Returns the number of rows in the layout. \see columnCount */ /*! \fn int QCPLayoutGrid::columnCount() const Returns the number of columns in the layout. \see rowCount */ /* end documentation of inline functions */ /*! Creates an instance of QCPLayoutGrid and sets default values. */ QCPLayoutGrid::QCPLayoutGrid() : mColumnSpacing(5), mRowSpacing(5), mWrap(0), mFillOrder(foColumnsFirst) { } QCPLayoutGrid::~QCPLayoutGrid() { // clear all child layout elements. This is important because only the specific layouts know how // to handle removing elements (clear calls virtual removeAt method to do that). clear(); } /*! Returns the element in the cell in \a row and \a column. Returns \c nullptr if either the row/column is invalid or if the cell is empty. In those cases, a qDebug message is printed. To check whether a cell exists and isn't empty, use \ref hasElement. \see addElement, hasElement */ QCPLayoutElement *QCPLayoutGrid::element(int row, int column) const { if (row >= 0 && row < mElements.size()) { if (column >= 0 && column < mElements.first().size()) { if (QCPLayoutElement *result = mElements.at(row).at(column)) return result; else qDebug() << Q_FUNC_INFO << "Requested cell is empty. Row:" << row << "Column:" << column; } else qDebug() << Q_FUNC_INFO << "Invalid column. Row:" << row << "Column:" << column; } else qDebug() << Q_FUNC_INFO << "Invalid row. Row:" << row << "Column:" << column; return nullptr; } /*! \overload Adds the \a element to cell with \a row and \a column. If \a element is already in a layout, it is first removed from there. If \a row or \a column don't exist yet, the layout is expanded accordingly. Returns true if the element was added successfully, i.e. if the cell at \a row and \a column didn't already have an element. Use the overload of this method without explicit row/column index to place the element according to the configured fill order and wrapping settings. \see element, hasElement, take, remove */ bool QCPLayoutGrid::addElement(int row, int column, QCPLayoutElement *element) { if (!hasElement(row, column)) { if (element && element->layout()) // remove from old layout first element->layout()->take(element); expandTo(row+1, column+1); mElements[row][column] = element; if (element) adoptElement(element); return true; } else qDebug() << Q_FUNC_INFO << "There is already an element in the specified row/column:" << row << column; return false; } /*! \overload Adds the \a element to the next empty cell according to the current fill order (\ref setFillOrder) and wrapping (\ref setWrap). If \a element is already in a layout, it is first removed from there. If necessary, the layout is expanded to hold the new element. Returns true if the element was added successfully. \see setFillOrder, setWrap, element, hasElement, take, remove */ bool QCPLayoutGrid::addElement(QCPLayoutElement *element) { int rowIndex = 0; int colIndex = 0; if (mFillOrder == foColumnsFirst) { while (hasElement(rowIndex, colIndex)) { ++colIndex; if (colIndex >= mWrap && mWrap > 0) { colIndex = 0; ++rowIndex; } } } else { while (hasElement(rowIndex, colIndex)) { ++rowIndex; if (rowIndex >= mWrap && mWrap > 0) { rowIndex = 0; ++colIndex; } } } return addElement(rowIndex, colIndex, element); } /*! Returns whether the cell at \a row and \a column exists and contains a valid element, i.e. isn't empty. \see element */ bool QCPLayoutGrid::hasElement(int row, int column) { if (row >= 0 && row < rowCount() && column >= 0 && column < columnCount()) return mElements.at(row).at(column); else return false; } /*! Sets the stretch \a factor of \a column. Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond their minimum and maximum widths/heights, regardless of the stretch factor. (see \ref QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize, \ref QCPLayoutElement::setSizeConstraintRect.) The default stretch factor of newly created rows/columns is 1. \see setColumnStretchFactors, setRowStretchFactor */ void QCPLayoutGrid::setColumnStretchFactor(int column, double factor) { if (column >= 0 && column < columnCount()) { if (factor > 0) mColumnStretchFactors[column] = factor; else qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor; } else qDebug() << Q_FUNC_INFO << "Invalid column:" << column; } /*! Sets the stretch \a factors of all columns. \a factors must have the size \ref columnCount. Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond their minimum and maximum widths/heights, regardless of the stretch factor. (see \ref QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize, \ref QCPLayoutElement::setSizeConstraintRect.) The default stretch factor of newly created rows/columns is 1. \see setColumnStretchFactor, setRowStretchFactors */ void QCPLayoutGrid::setColumnStretchFactors(const QList &factors) { if (factors.size() == mColumnStretchFactors.size()) { mColumnStretchFactors = factors; for (int i=0; i= 0 && row < rowCount()) { if (factor > 0) mRowStretchFactors[row] = factor; else qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor; } else qDebug() << Q_FUNC_INFO << "Invalid row:" << row; } /*! Sets the stretch \a factors of all rows. \a factors must have the size \ref rowCount. Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond their minimum and maximum widths/heights, regardless of the stretch factor. (see \ref QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize, \ref QCPLayoutElement::setSizeConstraintRect.) The default stretch factor of newly created rows/columns is 1. \see setRowStretchFactor, setColumnStretchFactors */ void QCPLayoutGrid::setRowStretchFactors(const QList &factors) { if (factors.size() == mRowStretchFactors.size()) { mRowStretchFactors = factors; for (int i=0; i tempElements; if (rearrange) { tempElements.reserve(elCount); for (int i=0; i()); mRowStretchFactors.append(1); } // go through rows and expand columns as necessary: int newColCount = qMax(columnCount(), newColumnCount); for (int i=0; i rowCount()) newIndex = rowCount(); mRowStretchFactors.insert(newIndex, 1); QList newRow; for (int col=0; col columnCount()) newIndex = columnCount(); mColumnStretchFactors.insert(newIndex, 1); for (int row=0; row= 0 && row < rowCount()) { if (column >= 0 && column < columnCount()) { switch (mFillOrder) { case foRowsFirst: return column*rowCount() + row; case foColumnsFirst: return row*columnCount() + column; } } else qDebug() << Q_FUNC_INFO << "row index out of bounds:" << row; } else qDebug() << Q_FUNC_INFO << "column index out of bounds:" << column; return 0; } /*! Converts the linear index to row and column indices and writes the result to \a row and \a column. The way the cells are indexed depends on \ref setFillOrder. If it is \ref foRowsFirst, the indices increase left to right and then top to bottom. If it is \ref foColumnsFirst, the indices increase top to bottom and then left to right. If there are no cells (i.e. column or row count is zero), sets \a row and \a column to -1. For the retrieved \a row and \a column to be valid, the passed \a index must be valid itself, i.e. greater or equal to zero and smaller than the current \ref elementCount. \see rowColToIndex */ void QCPLayoutGrid::indexToRowCol(int index, int &row, int &column) const { row = -1; column = -1; const int nCols = columnCount(); const int nRows = rowCount(); if (nCols == 0 || nRows == 0) return; if (index < 0 || index >= elementCount()) { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return; } switch (mFillOrder) { case foRowsFirst: { column = index / nRows; row = index % nRows; break; } case foColumnsFirst: { row = index / nCols; column = index % nCols; break; } } } /* inherits documentation from base class */ void QCPLayoutGrid::updateLayout() { QVector minColWidths, minRowHeights, maxColWidths, maxRowHeights; getMinimumRowColSizes(&minColWidths, &minRowHeights); getMaximumRowColSizes(&maxColWidths, &maxRowHeights); int totalRowSpacing = (rowCount()-1) * mRowSpacing; int totalColSpacing = (columnCount()-1) * mColumnSpacing; QVector colWidths = getSectionSizes(maxColWidths, minColWidths, mColumnStretchFactors.toVector(), mRect.width()-totalColSpacing); QVector rowHeights = getSectionSizes(maxRowHeights, minRowHeights, mRowStretchFactors.toVector(), mRect.height()-totalRowSpacing); // go through cells and set rects accordingly: int yOffset = mRect.top(); for (int row=0; row 0) yOffset += rowHeights.at(row-1)+mRowSpacing; int xOffset = mRect.left(); for (int col=0; col 0) xOffset += colWidths.at(col-1)+mColumnSpacing; if (mElements.at(row).at(col)) mElements.at(row).at(col)->setOuterRect(QRect(xOffset, yOffset, colWidths.at(col), rowHeights.at(row))); } } } /*! \seebaseclassmethod Note that the association of the linear \a index to the row/column based cells depends on the current setting of \ref setFillOrder. \see rowColToIndex */ QCPLayoutElement *QCPLayoutGrid::elementAt(int index) const { if (index >= 0 && index < elementCount()) { int row, col; indexToRowCol(index, row, col); return mElements.at(row).at(col); } else return nullptr; } /*! \seebaseclassmethod Note that the association of the linear \a index to the row/column based cells depends on the current setting of \ref setFillOrder. \see rowColToIndex */ QCPLayoutElement *QCPLayoutGrid::takeAt(int index) { if (QCPLayoutElement *el = elementAt(index)) { releaseElement(el); int row, col; indexToRowCol(index, row, col); mElements[row][col] = nullptr; return el; } else { qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index; return nullptr; } } /* inherits documentation from base class */ bool QCPLayoutGrid::take(QCPLayoutElement *element) { if (element) { for (int i=0; i QCPLayoutGrid::elements(bool recursive) const { QList result; const int elCount = elementCount(); #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) result.reserve(elCount); #endif for (int i=0; ielements(recursive); } } return result; } /*! Simplifies the layout by collapsing rows and columns which only contain empty cells. */ void QCPLayoutGrid::simplify() { // remove rows with only empty cells: for (int row=rowCount()-1; row>=0; --row) { bool hasElements = false; for (int col=0; col=0; --col) { bool hasElements = false; for (int row=0; row minColWidths, minRowHeights; getMinimumRowColSizes(&minColWidths, &minRowHeights); QSize result(0, 0); foreach (int w, minColWidths) result.rwidth() += w; foreach (int h, minRowHeights) result.rheight() += h; result.rwidth() += qMax(0, columnCount()-1) * mColumnSpacing; result.rheight() += qMax(0, rowCount()-1) * mRowSpacing; result.rwidth() += mMargins.left()+mMargins.right(); result.rheight() += mMargins.top()+mMargins.bottom(); return result; } /* inherits documentation from base class */ QSize QCPLayoutGrid::maximumOuterSizeHint() const { QVector maxColWidths, maxRowHeights; getMaximumRowColSizes(&maxColWidths, &maxRowHeights); QSize result(0, 0); foreach (int w, maxColWidths) result.setWidth(qMin(result.width()+w, QWIDGETSIZE_MAX)); foreach (int h, maxRowHeights) result.setHeight(qMin(result.height()+h, QWIDGETSIZE_MAX)); result.rwidth() += qMax(0, columnCount()-1) * mColumnSpacing; result.rheight() += qMax(0, rowCount()-1) * mRowSpacing; result.rwidth() += mMargins.left()+mMargins.right(); result.rheight() += mMargins.top()+mMargins.bottom(); if (result.height() > QWIDGETSIZE_MAX) result.setHeight(QWIDGETSIZE_MAX); if (result.width() > QWIDGETSIZE_MAX) result.setWidth(QWIDGETSIZE_MAX); return result; } /*! \internal Places the minimum column widths and row heights into \a minColWidths and \a minRowHeights respectively. The minimum height of a row is the largest minimum height of any element's outer rect in that row. The minimum width of a column is the largest minimum width of any element's outer rect in that column. This is a helper function for \ref updateLayout. \see getMaximumRowColSizes */ void QCPLayoutGrid::getMinimumRowColSizes(QVector *minColWidths, QVector *minRowHeights) const { *minColWidths = QVector(columnCount(), 0); *minRowHeights = QVector(rowCount(), 0); for (int row=0; rowat(col) < minSize.width()) (*minColWidths)[col] = minSize.width(); if (minRowHeights->at(row) < minSize.height()) (*minRowHeights)[row] = minSize.height(); } } } } /*! \internal Places the maximum column widths and row heights into \a maxColWidths and \a maxRowHeights respectively. The maximum height of a row is the smallest maximum height of any element's outer rect in that row. The maximum width of a column is the smallest maximum width of any element's outer rect in that column. This is a helper function for \ref updateLayout. \see getMinimumRowColSizes */ void QCPLayoutGrid::getMaximumRowColSizes(QVector *maxColWidths, QVector *maxRowHeights) const { *maxColWidths = QVector(columnCount(), QWIDGETSIZE_MAX); *maxRowHeights = QVector(rowCount(), QWIDGETSIZE_MAX); for (int row=0; rowat(col) > maxSize.width()) (*maxColWidths)[col] = maxSize.width(); if (maxRowHeights->at(row) > maxSize.height()) (*maxRowHeights)[row] = maxSize.height(); } } } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPLayoutInset //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPLayoutInset \brief A layout that places child elements aligned to the border or arbitrarily positioned Elements are placed either aligned to the border or at arbitrary position in the area of the layout. Which placement applies is controlled with the \ref InsetPlacement (\ref setInsetPlacement). Elements are added via \ref addElement(QCPLayoutElement *element, Qt::Alignment alignment) or addElement(QCPLayoutElement *element, const QRectF &rect). If the first method is used, the inset placement will default to \ref ipBorderAligned and the element will be aligned according to the \a alignment parameter. The second method defaults to \ref ipFree and allows placing elements at arbitrary position and size, defined by \a rect. The alignment or rect can be set via \ref setInsetAlignment or \ref setInsetRect, respectively. This is the layout that every QCPAxisRect has as \ref QCPAxisRect::insetLayout. */ /* start documentation of inline functions */ /*! \fn virtual void QCPLayoutInset::simplify() The QCPInsetLayout does not need simplification since it can never have empty cells due to its linear index structure. This method does nothing. */ /* end documentation of inline functions */ /*! Creates an instance of QCPLayoutInset and sets default values. */ QCPLayoutInset::QCPLayoutInset() { } QCPLayoutInset::~QCPLayoutInset() { // clear all child layout elements. This is important because only the specific layouts know how // to handle removing elements (clear calls virtual removeAt method to do that). clear(); } /*! Returns the placement type of the element with the specified \a index. */ QCPLayoutInset::InsetPlacement QCPLayoutInset::insetPlacement(int index) const { if (elementAt(index)) return mInsetPlacement.at(index); else { qDebug() << Q_FUNC_INFO << "Invalid element index:" << index; return ipFree; } } /*! Returns the alignment of the element with the specified \a index. The alignment only has a meaning, if the inset placement (\ref setInsetPlacement) is \ref ipBorderAligned. */ Qt::Alignment QCPLayoutInset::insetAlignment(int index) const { if (elementAt(index)) return mInsetAlignment.at(index); else { qDebug() << Q_FUNC_INFO << "Invalid element index:" << index; #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) return nullptr; #else return {}; #endif } } /*! Returns the rect of the element with the specified \a index. The rect only has a meaning, if the inset placement (\ref setInsetPlacement) is \ref ipFree. */ QRectF QCPLayoutInset::insetRect(int index) const { if (elementAt(index)) return mInsetRect.at(index); else { qDebug() << Q_FUNC_INFO << "Invalid element index:" << index; return {}; } } /*! Sets the inset placement type of the element with the specified \a index to \a placement. \see InsetPlacement */ void QCPLayoutInset::setInsetPlacement(int index, QCPLayoutInset::InsetPlacement placement) { if (elementAt(index)) mInsetPlacement[index] = placement; else qDebug() << Q_FUNC_INFO << "Invalid element index:" << index; } /*! If the inset placement (\ref setInsetPlacement) is \ref ipBorderAligned, this function is used to set the alignment of the element with the specified \a index to \a alignment. \a alignment is an or combination of the following alignment flags: Qt::AlignLeft, Qt::AlignHCenter, Qt::AlighRight, Qt::AlignTop, Qt::AlignVCenter, Qt::AlignBottom. Any other alignment flags will be ignored. */ void QCPLayoutInset::setInsetAlignment(int index, Qt::Alignment alignment) { if (elementAt(index)) mInsetAlignment[index] = alignment; else qDebug() << Q_FUNC_INFO << "Invalid element index:" << index; } /*! If the inset placement (\ref setInsetPlacement) is \ref ipFree, this function is used to set the position and size of the element with the specified \a index to \a rect. \a rect is given in fractions of the whole inset layout rect. So an inset with rect (0, 0, 1, 1) will span the entire layout. An inset with rect (0.6, 0.1, 0.35, 0.35) will be in the top right corner of the layout, with 35% width and height of the parent layout. Note that the minimum and maximum sizes of the embedded element (\ref QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize) are enforced. */ void QCPLayoutInset::setInsetRect(int index, const QRectF &rect) { if (elementAt(index)) mInsetRect[index] = rect; else qDebug() << Q_FUNC_INFO << "Invalid element index:" << index; } /* inherits documentation from base class */ void QCPLayoutInset::updateLayout() { for (int i=0; i finalMaxSize.width()) insetRect.setWidth(finalMaxSize.width()); if (insetRect.size().height() > finalMaxSize.height()) insetRect.setHeight(finalMaxSize.height()); } else if (mInsetPlacement.at(i) == ipBorderAligned) { insetRect.setSize(finalMinSize); Qt::Alignment al = mInsetAlignment.at(i); if (al.testFlag(Qt::AlignLeft)) insetRect.moveLeft(rect().x()); else if (al.testFlag(Qt::AlignRight)) insetRect.moveRight(rect().x()+rect().width()); else insetRect.moveLeft(int( rect().x()+rect().width()*0.5-finalMinSize.width()*0.5 )); // default to Qt::AlignHCenter if (al.testFlag(Qt::AlignTop)) insetRect.moveTop(rect().y()); else if (al.testFlag(Qt::AlignBottom)) insetRect.moveBottom(rect().y()+rect().height()); else insetRect.moveTop(int( rect().y()+rect().height()*0.5-finalMinSize.height()*0.5 )); // default to Qt::AlignVCenter } mElements.at(i)->setOuterRect(insetRect); } } /* inherits documentation from base class */ int QCPLayoutInset::elementCount() const { return mElements.size(); } /* inherits documentation from base class */ QCPLayoutElement *QCPLayoutInset::elementAt(int index) const { if (index >= 0 && index < mElements.size()) return mElements.at(index); else return nullptr; } /* inherits documentation from base class */ QCPLayoutElement *QCPLayoutInset::takeAt(int index) { if (QCPLayoutElement *el = elementAt(index)) { releaseElement(el); mElements.removeAt(index); mInsetPlacement.removeAt(index); mInsetAlignment.removeAt(index); mInsetRect.removeAt(index); return el; } else { qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index; return nullptr; } } /* inherits documentation from base class */ bool QCPLayoutInset::take(QCPLayoutElement *element) { if (element) { for (int i=0; irealVisibility() && el->selectTest(pos, onlySelectable) >= 0) return mParentPlot->selectionTolerance()*0.99; } return -1; } /*! Adds the specified \a element to the layout as an inset aligned at the border (\ref setInsetAlignment is initialized with \ref ipBorderAligned). The alignment is set to \a alignment. \a alignment is an or combination of the following alignment flags: Qt::AlignLeft, Qt::AlignHCenter, Qt::AlighRight, Qt::AlignTop, Qt::AlignVCenter, Qt::AlignBottom. Any other alignment flags will be ignored. \see addElement(QCPLayoutElement *element, const QRectF &rect) */ void QCPLayoutInset::addElement(QCPLayoutElement *element, Qt::Alignment alignment) { if (element) { if (element->layout()) // remove from old layout first element->layout()->take(element); mElements.append(element); mInsetPlacement.append(ipBorderAligned); mInsetAlignment.append(alignment); mInsetRect.append(QRectF(0.6, 0.6, 0.4, 0.4)); adoptElement(element); } else qDebug() << Q_FUNC_INFO << "Can't add nullptr element"; } /*! Adds the specified \a element to the layout as an inset with free positioning/sizing (\ref setInsetAlignment is initialized with \ref ipFree). The position and size is set to \a rect. \a rect is given in fractions of the whole inset layout rect. So an inset with rect (0, 0, 1, 1) will span the entire layout. An inset with rect (0.6, 0.1, 0.35, 0.35) will be in the top right corner of the layout, with 35% width and height of the parent layout. \see addElement(QCPLayoutElement *element, Qt::Alignment alignment) */ void QCPLayoutInset::addElement(QCPLayoutElement *element, const QRectF &rect) { if (element) { if (element->layout()) // remove from old layout first element->layout()->take(element); mElements.append(element); mInsetPlacement.append(ipFree); mInsetAlignment.append(Qt::AlignRight|Qt::AlignTop); mInsetRect.append(rect); adoptElement(element); } else qDebug() << Q_FUNC_INFO << "Can't add nullptr element"; } /* end of 'src/layout.cpp' */ /* including file 'src/lineending.cpp' */ /* modified 2021-03-29T02:30:44, size 11189 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPLineEnding //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPLineEnding \brief Handles the different ending decorations for line-like items \image html QCPLineEnding.png "The various ending styles currently supported" For every ending a line-like item has, an instance of this class exists. For example, QCPItemLine has two endings which can be set with QCPItemLine::setHead and QCPItemLine::setTail. The styles themselves are defined via the enum QCPLineEnding::EndingStyle. Most decorations can be modified regarding width and length, see \ref setWidth and \ref setLength. The direction of the ending decoration (e.g. direction an arrow is pointing) is controlled by the line-like item. For example, when both endings of a QCPItemLine are set to be arrows, they will point to opposite directions, e.g. "outward". This can be changed by \ref setInverted, which would make the respective arrow point inward. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle where actually a QCPLineEnding is expected, e.g. \snippet documentation/doc-code-snippets/mainwindow.cpp qcplineending-sethead */ /*! Creates a QCPLineEnding instance with default values (style \ref esNone). */ QCPLineEnding::QCPLineEnding() : mStyle(esNone), mWidth(8), mLength(10), mInverted(false) { } /*! Creates a QCPLineEnding instance with the specified values. */ QCPLineEnding::QCPLineEnding(QCPLineEnding::EndingStyle style, double width, double length, bool inverted) : mStyle(style), mWidth(width), mLength(length), mInverted(inverted) { } /*! Sets the style of the ending decoration. */ void QCPLineEnding::setStyle(QCPLineEnding::EndingStyle style) { mStyle = style; } /*! Sets the width of the ending decoration, if the style supports it. On arrows, for example, the width defines the size perpendicular to the arrow's pointing direction. \see setLength */ void QCPLineEnding::setWidth(double width) { mWidth = width; } /*! Sets the length of the ending decoration, if the style supports it. On arrows, for example, the length defines the size in pointing direction. \see setWidth */ void QCPLineEnding::setLength(double length) { mLength = length; } /*! Sets whether the ending decoration shall be inverted. For example, an arrow decoration will point inward when \a inverted is set to true. Note that also the \a width direction is inverted. For symmetrical ending styles like arrows or discs, this doesn't make a difference. However, asymmetric styles like \ref esHalfBar are affected by it, which can be used to control to which side the half bar points to. */ void QCPLineEnding::setInverted(bool inverted) { mInverted = inverted; } /*! \internal Returns the maximum pixel radius the ending decoration might cover, starting from the position the decoration is drawn at (typically a line ending/\ref QCPItemPosition of an item). This is relevant for clipping. Only omit painting of the decoration when the position where the decoration is supposed to be drawn is farther away from the clipping rect than the returned distance. */ double QCPLineEnding::boundingDistance() const { switch (mStyle) { case esNone: return 0; case esFlatArrow: case esSpikeArrow: case esLineArrow: case esSkewedBar: return qSqrt(mWidth*mWidth+mLength*mLength); // items that have width and length case esDisc: case esSquare: case esDiamond: case esBar: case esHalfBar: return mWidth*1.42; // items that only have a width -> width*sqrt(2) } return 0; } /*! Starting from the origin of this line ending (which is style specific), returns the length covered by the line ending symbol, in backward direction. For example, the \ref esSpikeArrow has a shorter real length than a \ref esFlatArrow, even if both have the same \ref setLength value, because the spike arrow has an inward curved back, which reduces the length along its center axis (the drawing origin for arrows is at the tip). This function is used for precise, style specific placement of line endings, for example in QCPAxes. */ double QCPLineEnding::realLength() const { switch (mStyle) { case esNone: case esLineArrow: case esSkewedBar: case esBar: case esHalfBar: return 0; case esFlatArrow: return mLength; case esDisc: case esSquare: case esDiamond: return mWidth*0.5; case esSpikeArrow: return mLength*0.8; } return 0; } /*! \internal Draws the line ending with the specified \a painter at the position \a pos. The direction of the line ending is controlled with \a dir. */ void QCPLineEnding::draw(QCPPainter *painter, const QCPVector2D &pos, const QCPVector2D &dir) const { if (mStyle == esNone) return; QCPVector2D lengthVec = dir.normalized() * mLength*(mInverted ? -1 : 1); if (lengthVec.isNull()) lengthVec = QCPVector2D(1, 0); QCPVector2D widthVec = dir.normalized().perpendicular() * mWidth*0.5*(mInverted ? -1 : 1); QPen penBackup = painter->pen(); QBrush brushBackup = painter->brush(); QPen miterPen = penBackup; miterPen.setJoinStyle(Qt::MiterJoin); // to make arrow heads spikey QBrush brush(painter->pen().color(), Qt::SolidPattern); switch (mStyle) { case esNone: break; case esFlatArrow: { QPointF points[3] = {pos.toPointF(), (pos-lengthVec+widthVec).toPointF(), (pos-lengthVec-widthVec).toPointF() }; painter->setPen(miterPen); painter->setBrush(brush); painter->drawConvexPolygon(points, 3); painter->setBrush(brushBackup); painter->setPen(penBackup); break; } case esSpikeArrow: { QPointF points[4] = {pos.toPointF(), (pos-lengthVec+widthVec).toPointF(), (pos-lengthVec*0.8).toPointF(), (pos-lengthVec-widthVec).toPointF() }; painter->setPen(miterPen); painter->setBrush(brush); painter->drawConvexPolygon(points, 4); painter->setBrush(brushBackup); painter->setPen(penBackup); break; } case esLineArrow: { QPointF points[3] = {(pos-lengthVec+widthVec).toPointF(), pos.toPointF(), (pos-lengthVec-widthVec).toPointF() }; painter->setPen(miterPen); painter->drawPolyline(points, 3); painter->setPen(penBackup); break; } case esDisc: { painter->setBrush(brush); painter->drawEllipse(pos.toPointF(), mWidth*0.5, mWidth*0.5); painter->setBrush(brushBackup); break; } case esSquare: { QCPVector2D widthVecPerp = widthVec.perpendicular(); QPointF points[4] = {(pos-widthVecPerp+widthVec).toPointF(), (pos-widthVecPerp-widthVec).toPointF(), (pos+widthVecPerp-widthVec).toPointF(), (pos+widthVecPerp+widthVec).toPointF() }; painter->setPen(miterPen); painter->setBrush(brush); painter->drawConvexPolygon(points, 4); painter->setBrush(brushBackup); painter->setPen(penBackup); break; } case esDiamond: { QCPVector2D widthVecPerp = widthVec.perpendicular(); QPointF points[4] = {(pos-widthVecPerp).toPointF(), (pos-widthVec).toPointF(), (pos+widthVecPerp).toPointF(), (pos+widthVec).toPointF() }; painter->setPen(miterPen); painter->setBrush(brush); painter->drawConvexPolygon(points, 4); painter->setBrush(brushBackup); painter->setPen(penBackup); break; } case esBar: { painter->drawLine((pos+widthVec).toPointF(), (pos-widthVec).toPointF()); break; } case esHalfBar: { painter->drawLine((pos+widthVec).toPointF(), pos.toPointF()); break; } case esSkewedBar: { QCPVector2D shift; if (!qFuzzyIsNull(painter->pen().widthF()) || painter->modes().testFlag(QCPPainter::pmNonCosmetic)) shift = dir.normalized()*qMax(qreal(1.0), painter->pen().widthF())*qreal(0.5); // if drawing with thick (non-cosmetic) pen, shift bar a little in line direction to prevent line from sticking through bar slightly painter->drawLine((pos+widthVec+lengthVec*0.2*(mInverted?-1:1)+shift).toPointF(), (pos-widthVec-lengthVec*0.2*(mInverted?-1:1)+shift).toPointF()); break; } } } /*! \internal \overload Draws the line ending. The direction is controlled with the \a angle parameter in radians. */ void QCPLineEnding::draw(QCPPainter *painter, const QCPVector2D &pos, double angle) const { draw(painter, pos, QCPVector2D(qCos(angle), qSin(angle))); } /* end of 'src/lineending.cpp' */ /* including file 'src/axis/labelpainter.cpp' */ /* modified 2021-03-29T02:30:44, size 27296 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPLabelPainterPrivate //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPLabelPainterPrivate \internal \brief (Private) This is a private class and not part of the public QCustomPlot interface. */ const QChar QCPLabelPainterPrivate::SymbolDot(183); const QChar QCPLabelPainterPrivate::SymbolCross(215); /*! Constructs a QCPLabelPainterPrivate instance. Make sure to not create a new instance on every redraw, to utilize the caching mechanisms. the \a parentPlot does not take ownership of the label painter. Make sure to delete it appropriately. */ QCPLabelPainterPrivate::QCPLabelPainterPrivate(QCustomPlot *parentPlot) : mAnchorMode(amRectangular), mAnchorSide(asLeft), mAnchorReferenceType(artNormal), mColor(Qt::black), mPadding(0), mRotation(0), mSubstituteExponent(true), mMultiplicationSymbol(QChar(215)), mAbbreviateDecimalPowers(false), mParentPlot(parentPlot), mLabelCache(16) { analyzeFontMetrics(); } QCPLabelPainterPrivate::~QCPLabelPainterPrivate() { } void QCPLabelPainterPrivate::setAnchorSide(AnchorSide side) { mAnchorSide = side; } void QCPLabelPainterPrivate::setAnchorMode(AnchorMode mode) { mAnchorMode = mode; } void QCPLabelPainterPrivate::setAnchorReference(const QPointF &pixelPoint) { mAnchorReference = pixelPoint; } void QCPLabelPainterPrivate::setAnchorReferenceType(AnchorReferenceType type) { mAnchorReferenceType = type; } void QCPLabelPainterPrivate::setFont(const QFont &font) { if (mFont != font) { mFont = font; analyzeFontMetrics(); } } void QCPLabelPainterPrivate::setColor(const QColor &color) { mColor = color; } void QCPLabelPainterPrivate::setPadding(int padding) { mPadding = padding; } void QCPLabelPainterPrivate::setRotation(double rotation) { mRotation = qBound(-90.0, rotation, 90.0); } void QCPLabelPainterPrivate::setSubstituteExponent(bool enabled) { mSubstituteExponent = enabled; } void QCPLabelPainterPrivate::setMultiplicationSymbol(QChar symbol) { mMultiplicationSymbol = symbol; } void QCPLabelPainterPrivate::setAbbreviateDecimalPowers(bool enabled) { mAbbreviateDecimalPowers = enabled; } void QCPLabelPainterPrivate::setCacheSize(int labelCount) { mLabelCache.setMaxCost(labelCount); } int QCPLabelPainterPrivate::cacheSize() const { return mLabelCache.maxCost(); } void QCPLabelPainterPrivate::drawTickLabel(QCPPainter *painter, const QPointF &tickPos, const QString &text) { double realRotation = mRotation; AnchorSide realSide = mAnchorSide; // for circular axes, the anchor side is determined depending on the quadrant of tickPos with respect to mCircularReference if (mAnchorMode == amSkewedUpright) { realSide = skewedAnchorSide(tickPos, 0.2, 0.3); } else if (mAnchorMode == amSkewedRotated) // in this mode every label is individually rotated to match circle tangent { realSide = skewedAnchorSide(tickPos, 0, 0); realRotation += QCPVector2D(tickPos-mAnchorReference).angle()/M_PI*180.0; if (realRotation > 90) realRotation -= 180; else if (realRotation < -90) realRotation += 180; } realSide = rotationCorrectedSide(realSide, realRotation); // rotation angles may change the true anchor side of the label drawLabelMaybeCached(painter, mFont, mColor, getAnchorPos(tickPos), realSide, realRotation, text); } /*! \internal Returns the size ("margin" in QCPAxisRect context, so measured perpendicular to the axis backbone direction) needed to fit the axis. */ /* TODO: needed? int QCPLabelPainterPrivate::size() const { int result = 0; // get length of tick marks pointing outwards: if (!tickPositions.isEmpty()) result += qMax(0, qMax(tickLengthOut, subTickLengthOut)); // calculate size of tick labels: if (tickLabelSide == QCPAxis::lsOutside) { QSize tickLabelsSize(0, 0); if (!tickLabels.isEmpty()) { for (int i=0; ibufferDevicePixelRatio())); result.append(QByteArray::number(mRotation)); //result.append(QByteArray::number((int)tickLabelSide)); TODO: check whether this is really a cache-invalidating property result.append(QByteArray::number((int)mSubstituteExponent)); result.append(QString(mMultiplicationSymbol).toUtf8()); result.append(mColor.name().toLatin1()+QByteArray::number(mColor.alpha(), 16)); result.append(mFont.toString().toLatin1()); return result; } /*! \internal Draws a single tick label with the provided \a painter, utilizing the internal label cache to significantly speed up drawing of labels that were drawn in previous calls. The tick label is always bound to an axis, the distance to the axis is controllable via \a distanceToAxis in pixels. The pixel position in the axis direction is passed in the \a position parameter. Hence for the bottom axis, \a position would indicate the horizontal pixel position (not coordinate), at which the label should be drawn. In order to later draw the axis label in a place that doesn't overlap with the tick labels, the largest tick label size is needed. This is acquired by passing a \a tickLabelsSize to the \ref drawTickLabel calls during the process of drawing all tick labels of one axis. In every call, \a tickLabelsSize is expanded, if the drawn label exceeds the value \a tickLabelsSize currently holds. The label is drawn with the font and pen that are currently set on the \a painter. To draw superscripted powers, the font is temporarily made smaller by a fixed factor (see \ref getTickLabelData). */ void QCPLabelPainterPrivate::drawLabelMaybeCached(QCPPainter *painter, const QFont &font, const QColor &color, const QPointF &pos, AnchorSide side, double rotation, const QString &text) { // warning: if you change anything here, also adapt getMaxTickLabelSize() accordingly! if (text.isEmpty()) return; QSize finalSize; if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && !painter->modes().testFlag(QCPPainter::pmNoCaching)) // label caching enabled { QByteArray key = cacheKey(text, color, rotation, side); CachedLabel *cachedLabel = mLabelCache.take(QString::fromUtf8(key)); // attempt to take label from cache (don't use object() because we want ownership/prevent deletion during our operations, we re-insert it afterwards) if (!cachedLabel) // no cached label existed, create it { LabelData labelData = getTickLabelData(font, color, rotation, side, text); cachedLabel = createCachedLabel(labelData); } // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels): bool labelClippedByBorder = false; /* if (tickLabelSide == QCPAxis::lsOutside) { if (QCPAxis::orientation(type) == Qt::Horizontal) labelClippedByBorder = labelAnchor.x()+cachedLabel->offset.x()+cachedLabel->pixmap.width()/mParentPlot->bufferDevicePixelRatio() > viewportRect.right() || labelAnchor.x()+cachedLabel->offset.x() < viewportRect.left(); else labelClippedByBorder = labelAnchor.y()+cachedLabel->offset.y()+cachedLabel->pixmap.height()/mParentPlot->bufferDevicePixelRatio() > viewportRect.bottom() || labelAnchor.y()+cachedLabel->offset.y() < viewportRect.top(); } */ if (!labelClippedByBorder) { painter->drawPixmap(pos+cachedLabel->offset, cachedLabel->pixmap); finalSize = cachedLabel->pixmap.size()/mParentPlot->bufferDevicePixelRatio(); // TODO: collect this in a member rect list? } mLabelCache.insert(QString::fromUtf8(key), cachedLabel); } else // label caching disabled, draw text directly on surface: { LabelData labelData = getTickLabelData(font, color, rotation, side, text); // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels): bool labelClippedByBorder = false; /* if (tickLabelSide == QCPAxis::lsOutside) { if (QCPAxis::orientation(type) == Qt::Horizontal) labelClippedByBorder = finalPosition.x()+(labelData.rotatedTotalBounds.width()+labelData.rotatedTotalBounds.left()) > viewportRect.right() || finalPosition.x()+labelData.rotatedTotalBounds.left() < viewportRect.left(); else labelClippedByBorder = finalPosition.y()+(labelData.rotatedTotalBounds.height()+labelData.rotatedTotalBounds.top()) > viewportRect.bottom() || finalPosition.y()+labelData.rotatedTotalBounds.top() < viewportRect.top(); } */ if (!labelClippedByBorder) { drawText(painter, pos, labelData); finalSize = labelData.rotatedTotalBounds.size(); } } /* // expand passed tickLabelsSize if current tick label is larger: if (finalSize.width() > tickLabelsSize->width()) tickLabelsSize->setWidth(finalSize.width()); if (finalSize.height() > tickLabelsSize->height()) tickLabelsSize->setHeight(finalSize.height()); */ } QPointF QCPLabelPainterPrivate::getAnchorPos(const QPointF &tickPos) { switch (mAnchorMode) { case amRectangular: { switch (mAnchorSide) { case asLeft: return tickPos+QPointF(mPadding, 0); case asRight: return tickPos+QPointF(-mPadding, 0); case asTop: return tickPos+QPointF(0, mPadding); case asBottom: return tickPos+QPointF(0, -mPadding); case asTopLeft: return tickPos+QPointF(mPadding*M_SQRT1_2, mPadding*M_SQRT1_2); case asTopRight: return tickPos+QPointF(-mPadding*M_SQRT1_2, mPadding*M_SQRT1_2); case asBottomRight: return tickPos+QPointF(-mPadding*M_SQRT1_2, -mPadding*M_SQRT1_2); case asBottomLeft: return tickPos+QPointF(mPadding*M_SQRT1_2, -mPadding*M_SQRT1_2); } } case amSkewedUpright: case amSkewedRotated: { QCPVector2D anchorNormal(tickPos-mAnchorReference); if (mAnchorReferenceType == artTangent) anchorNormal = anchorNormal.perpendicular(); anchorNormal.normalize(); return tickPos+(anchorNormal*mPadding).toPointF(); } } return tickPos; } /*! \internal This is a \ref placeTickLabel helper function. Draws the tick label specified in \a labelData with \a painter at the pixel positions \a x and \a y. This function is used by \ref placeTickLabel to create new tick labels for the cache, or to directly draw the labels on the QCustomPlot surface when label caching is disabled, i.e. when QCP::phCacheLabels plotting hint is not set. */ void QCPLabelPainterPrivate::drawText(QCPPainter *painter, const QPointF &pos, const LabelData &labelData) const { // backup painter settings that we're about to change: QTransform oldTransform = painter->transform(); QFont oldFont = painter->font(); QPen oldPen = painter->pen(); // transform painter to position/rotation: painter->translate(pos); painter->setTransform(labelData.transform, true); // draw text: painter->setFont(labelData.baseFont); painter->setPen(QPen(labelData.color)); if (!labelData.expPart.isEmpty()) // use superscripted exponent typesetting { painter->drawText(0, 0, 0, 0, Qt::TextDontClip, labelData.basePart); if (!labelData.suffixPart.isEmpty()) painter->drawText(labelData.baseBounds.width()+1+labelData.expBounds.width(), 0, 0, 0, Qt::TextDontClip, labelData.suffixPart); painter->setFont(labelData.expFont); painter->drawText(labelData.baseBounds.width()+1, 0, labelData.expBounds.width(), labelData.expBounds.height(), Qt::TextDontClip, labelData.expPart); } else { painter->drawText(0, 0, labelData.totalBounds.width(), labelData.totalBounds.height(), Qt::TextDontClip | Qt::AlignHCenter, labelData.basePart); } /* Debug code to draw label bounding boxes, baseline, and capheight painter->save(); painter->setPen(QPen(QColor(0, 0, 0, 150))); painter->drawRect(labelData.totalBounds); const int baseline = labelData.totalBounds.height()-mLetterDescent; painter->setPen(QPen(QColor(255, 0, 0, 150))); painter->drawLine(QLineF(0, baseline, labelData.totalBounds.width(), baseline)); painter->setPen(QPen(QColor(0, 0, 255, 150))); painter->drawLine(QLineF(0, baseline-mLetterCapHeight, labelData.totalBounds.width(), baseline-mLetterCapHeight)); painter->restore(); */ // reset painter settings to what it was before: painter->setTransform(oldTransform); painter->setFont(oldFont); painter->setPen(oldPen); } /*! \internal This is a \ref placeTickLabel helper function. Transforms the passed \a text and \a font to a tickLabelData structure that can then be further processed by \ref getTickLabelDrawOffset and \ref drawTickLabel. It splits the text into base and exponent if necessary (member substituteExponent) and calculates appropriate bounding boxes. */ QCPLabelPainterPrivate::LabelData QCPLabelPainterPrivate::getTickLabelData(const QFont &font, const QColor &color, double rotation, AnchorSide side, const QString &text) const { LabelData result; result.rotation = rotation; result.side = side; result.color = color; // determine whether beautiful decimal powers should be used bool useBeautifulPowers = false; int ePos = -1; // first index of exponent part, text before that will be basePart, text until eLast will be expPart int eLast = -1; // last index of exponent part, rest of text after this will be suffixPart if (mSubstituteExponent) { ePos = text.indexOf(QLatin1Char('e')); if (ePos > 0 && text.at(ePos-1).isDigit()) { eLast = ePos; while (eLast+1 < text.size() && (text.at(eLast+1) == QLatin1Char('+') || text.at(eLast+1) == QLatin1Char('-') || text.at(eLast+1).isDigit())) ++eLast; if (eLast > ePos) // only if also to right of 'e' is a digit/+/- interpret it as beautifiable power useBeautifulPowers = true; } } // calculate text bounding rects and do string preparation for beautiful decimal powers: result.baseFont = font; if (result.baseFont.pointSizeF() > 0) // might return -1 if specified with setPixelSize, in that case we can't do correction in next line result.baseFont.setPointSizeF(result.baseFont.pointSizeF()+0.05); // QFontMetrics.boundingRect has a bug for exact point sizes that make the results oscillate due to internal rounding QFontMetrics baseFontMetrics(result.baseFont); if (useBeautifulPowers) { // split text into parts of number/symbol that will be drawn normally and part that will be drawn as exponent: result.basePart = text.left(ePos); result.suffixPart = text.mid(eLast+1); // also drawn normally but after exponent // in log scaling, we want to turn "1*10^n" into "10^n", else add multiplication sign and decimal base: if (mAbbreviateDecimalPowers && result.basePart == QLatin1String("1")) result.basePart = QLatin1String("10"); else result.basePart += QString(mMultiplicationSymbol) + QLatin1String("10"); result.expPart = text.mid(ePos+1, eLast-ePos); // clip "+" and leading zeros off expPart: while (result.expPart.length() > 2 && result.expPart.at(1) == QLatin1Char('0')) // length > 2 so we leave one zero when numberFormatChar is 'e' result.expPart.remove(1, 1); if (!result.expPart.isEmpty() && result.expPart.at(0) == QLatin1Char('+')) result.expPart.remove(0, 1); // prepare smaller font for exponent: result.expFont = font; if (result.expFont.pointSize() > 0) result.expFont.setPointSize(result.expFont.pointSize()*0.75); else result.expFont.setPixelSize(result.expFont.pixelSize()*0.75); // calculate bounding rects of base part(s), exponent part and total one: result.baseBounds = baseFontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.basePart); result.expBounds = QFontMetrics(result.expFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.expPart); if (!result.suffixPart.isEmpty()) result.suffixBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.suffixPart); result.totalBounds = result.baseBounds.adjusted(0, 0, result.expBounds.width()+result.suffixBounds.width()+2, 0); // +2 consists of the 1 pixel spacing between base and exponent (see drawTickLabel) and an extra pixel to include AA } else // useBeautifulPowers == false { result.basePart = text; result.totalBounds = baseFontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter, result.basePart); } result.totalBounds.moveTopLeft(QPoint(0, 0)); applyAnchorTransform(result); result.rotatedTotalBounds = result.transform.mapRect(result.totalBounds); return result; } void QCPLabelPainterPrivate::applyAnchorTransform(LabelData &labelData) const { if (!qFuzzyIsNull(labelData.rotation)) labelData.transform.rotate(labelData.rotation); // rotates effectively clockwise (due to flipped y axis of painter vs widget coordinate system) // from now on we translate in rotated label-local coordinate system. // shift origin of coordinate system to appropriate point on label: labelData.transform.translate(0, -labelData.totalBounds.height()+mLetterDescent+mLetterCapHeight); // shifts origin to true top of capital (or number) characters if (labelData.side == asLeft || labelData.side == asRight) // anchor is centered vertically labelData.transform.translate(0, -mLetterCapHeight/2.0); else if (labelData.side == asTop || labelData.side == asBottom) // anchor is centered horizontally labelData.transform.translate(-labelData.totalBounds.width()/2.0, 0); if (labelData.side == asTopRight || labelData.side == asRight || labelData.side == asBottomRight) // anchor is at right labelData.transform.translate(-labelData.totalBounds.width(), 0); if (labelData.side == asBottomLeft || labelData.side == asBottom || labelData.side == asBottomRight) // anchor is at bottom (no elseif!) labelData.transform.translate(0, -mLetterCapHeight); } /*! \internal Simulates the steps done by \ref placeTickLabel by calculating bounding boxes of the text label to be drawn, depending on number format etc. Since only the largest tick label is wanted for the margin calculation, the passed \a tickLabelsSize is only expanded, if it's currently set to a smaller width/height. */ /* void QCPLabelPainterPrivate::getMaxTickLabelSize(const QFont &font, const QString &text, QSize *tickLabelsSize) const { // note: this function must return the same tick label sizes as the placeTickLabel function. QSize finalSize; if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && mLabelCache.contains(text)) // label caching enabled and have cached label { const CachedLabel *cachedLabel = mLabelCache.object(text); finalSize = cachedLabel->pixmap.size()/mParentPlot->bufferDevicePixelRatio(); } else // label caching disabled or no label with this text cached: { // TODO: LabelData labelData = getTickLabelData(font, text); // TODO: finalSize = labelData.rotatedTotalBounds.size(); } // expand passed tickLabelsSize if current tick label is larger: if (finalSize.width() > tickLabelsSize->width()) tickLabelsSize->setWidth(finalSize.width()); if (finalSize.height() > tickLabelsSize->height()) tickLabelsSize->setHeight(finalSize.height()); } */ QCPLabelPainterPrivate::CachedLabel *QCPLabelPainterPrivate::createCachedLabel(const LabelData &labelData) const { CachedLabel *result = new CachedLabel; // allocate pixmap with the correct size and pixel ratio: if (!qFuzzyCompare(1.0, mParentPlot->bufferDevicePixelRatio())) { result->pixmap = QPixmap(labelData.rotatedTotalBounds.size()*mParentPlot->bufferDevicePixelRatio()); #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED # ifdef QCP_DEVICEPIXELRATIO_FLOAT result->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatioF()); # else result->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatio()); # endif #endif } else result->pixmap = QPixmap(labelData.rotatedTotalBounds.size()); result->pixmap.fill(Qt::transparent); // draw the label into the pixmap // offset is between label anchor and topleft of cache pixmap, so pixmap can be drawn at pos+offset to make the label anchor appear at pos. // We use rotatedTotalBounds.topLeft() because rotatedTotalBounds is in a coordinate system where the label anchor is at (0, 0) result->offset = labelData.rotatedTotalBounds.topLeft(); QCPPainter cachePainter(&result->pixmap); drawText(&cachePainter, -result->offset, labelData); return result; } QByteArray QCPLabelPainterPrivate::cacheKey(const QString &text, const QColor &color, double rotation, AnchorSide side) const { return text.toUtf8()+ QByteArray::number(color.red()+256*color.green()+65536*color.blue(), 36)+ QByteArray::number(color.alpha()+256*(int)side, 36)+ QByteArray::number((int)(rotation*100)%36000, 36); } QCPLabelPainterPrivate::AnchorSide QCPLabelPainterPrivate::skewedAnchorSide(const QPointF &tickPos, double sideExpandHorz, double sideExpandVert) const { QCPVector2D anchorNormal = QCPVector2D(tickPos-mAnchorReference); if (mAnchorReferenceType == artTangent) anchorNormal = anchorNormal.perpendicular(); const double radius = anchorNormal.length(); const double sideHorz = sideExpandHorz*radius; const double sideVert = sideExpandVert*radius; if (anchorNormal.x() > sideHorz) { if (anchorNormal.y() > sideVert) return asTopLeft; else if (anchorNormal.y() < -sideVert) return asBottomLeft; else return asLeft; } else if (anchorNormal.x() < -sideHorz) { if (anchorNormal.y() > sideVert) return asTopRight; else if (anchorNormal.y() < -sideVert) return asBottomRight; else return asRight; } else { if (anchorNormal.y() > 0) return asTop; else return asBottom; } return asBottom; // should never be reached } QCPLabelPainterPrivate::AnchorSide QCPLabelPainterPrivate::rotationCorrectedSide(AnchorSide side, double rotation) const { AnchorSide result = side; const bool rotateClockwise = rotation > 0; if (!qFuzzyIsNull(rotation)) { if (!qFuzzyCompare(qAbs(rotation), 90)) // avoid graphical collision with anchor tangent (e.g. axis line) when rotating, so change anchor side appropriately: { if (side == asTop) result = rotateClockwise ? asLeft : asRight; else if (side == asBottom) result = rotateClockwise ? asRight : asLeft; else if (side == asTopLeft) result = rotateClockwise ? asLeft : asTop; else if (side == asTopRight) result = rotateClockwise ? asTop : asRight; else if (side == asBottomLeft) result = rotateClockwise ? asBottom : asLeft; else if (side == asBottomRight) result = rotateClockwise ? asRight : asBottom; } else // for full rotation by +/-90 degrees, other sides are more appropriate for centering on anchor: { if (side == asLeft) result = rotateClockwise ? asBottom : asTop; else if (side == asRight) result = rotateClockwise ? asTop : asBottom; else if (side == asTop) result = rotateClockwise ? asLeft : asRight; else if (side == asBottom) result = rotateClockwise ? asRight : asLeft; else if (side == asTopLeft) result = rotateClockwise ? asBottomLeft : asTopRight; else if (side == asTopRight) result = rotateClockwise ? asTopLeft : asBottomRight; else if (side == asBottomLeft) result = rotateClockwise ? asBottomRight : asTopLeft; else if (side == asBottomRight) result = rotateClockwise ? asTopRight : asBottomLeft; } } return result; } void QCPLabelPainterPrivate::analyzeFontMetrics() { const QFontMetrics fm(mFont); mLetterCapHeight = fm.tightBoundingRect(QLatin1String("8")).height(); // this method is slow, that's why we query it only upon font change mLetterDescent = fm.descent(); } /* end of 'src/axis/labelpainter.cpp' */ /* including file 'src/axis/axisticker.cpp' */ /* modified 2021-03-29T02:30:44, size 18688 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxisTicker //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxisTicker \brief The base class tick generator used by QCPAxis to create tick positions and tick labels Each QCPAxis has an internal QCPAxisTicker (or a subclass) in order to generate tick positions and tick labels for the current axis range. The ticker of an axis can be set via \ref QCPAxis::setTicker. Since that method takes a QSharedPointer, multiple axes can share the same ticker instance. This base class generates normal tick coordinates and numeric labels for linear axes. It picks a reasonable tick step (the separation between ticks) which results in readable tick labels. The number of ticks that should be approximately generated can be set via \ref setTickCount. Depending on the current tick step strategy (\ref setTickStepStrategy), the algorithm either sacrifices readability to better match the specified tick count (\ref QCPAxisTicker::tssMeetTickCount) or relaxes the tick count in favor of better tick steps (\ref QCPAxisTicker::tssReadability), which is the default. The following more specialized axis ticker subclasses are available, see details in the respective class documentation:
QCPAxisTickerFixed\image html axisticker-fixed.png
QCPAxisTickerLog\image html axisticker-log.png
QCPAxisTickerPi\image html axisticker-pi.png
QCPAxisTickerText\image html axisticker-text.png
QCPAxisTickerDateTime\image html axisticker-datetime.png
QCPAxisTickerTime\image html axisticker-time.png \image html axisticker-time2.png
\section axisticker-subclassing Creating own axis tickers Creating own axis tickers can be achieved very easily by sublassing QCPAxisTicker and reimplementing some or all of the available virtual methods. In the simplest case you might wish to just generate different tick steps than the other tickers, so you only reimplement the method \ref getTickStep. If you additionally want control over the string that will be shown as tick label, reimplement \ref getTickLabel. If you wish to have complete control, you can generate the tick vectors and tick label vectors yourself by reimplementing \ref createTickVector and \ref createLabelVector. The default implementations use the previously mentioned virtual methods \ref getTickStep and \ref getTickLabel, but your reimplementations don't necessarily need to do so. For example in the case of unequal tick steps, the method \ref getTickStep loses its usefulness and can be ignored. The sub tick count between major ticks can be controlled with \ref getSubTickCount. Full sub tick placement control is obtained by reimplementing \ref createSubTickVector. See the documentation of all these virtual methods in QCPAxisTicker for detailed information about the parameters and expected return values. */ /*! Constructs the ticker and sets reasonable default values. Axis tickers are commonly created managed by a QSharedPointer, which then can be passed to QCPAxis::setTicker. */ QCPAxisTicker::QCPAxisTicker() : mTickStepStrategy(tssReadability), mTickCount(5), mTickOrigin(0) { } QCPAxisTicker::~QCPAxisTicker() { } /*! Sets which strategy the axis ticker follows when choosing the size of the tick step. For the available strategies, see \ref TickStepStrategy. */ void QCPAxisTicker::setTickStepStrategy(QCPAxisTicker::TickStepStrategy strategy) { mTickStepStrategy = strategy; } /*! Sets how many ticks this ticker shall aim to generate across the axis range. Note that \a count is not guaranteed to be matched exactly, as generating readable tick intervals may conflict with the requested number of ticks. Whether the readability has priority over meeting the requested \a count can be specified with \ref setTickStepStrategy. */ void QCPAxisTicker::setTickCount(int count) { if (count > 0) mTickCount = count; else qDebug() << Q_FUNC_INFO << "tick count must be greater than zero:" << count; } /*! Sets the mathematical coordinate (or "offset") of the zeroth tick. This tick coordinate is just a concept and doesn't need to be inside the currently visible axis range. By default \a origin is zero, which for example yields ticks {-5, 0, 5, 10, 15,...} when the tick step is five. If \a origin is now set to 1 instead, the correspondingly generated ticks would be {-4, 1, 6, 11, 16,...}. */ void QCPAxisTicker::setTickOrigin(double origin) { mTickOrigin = origin; } /*! This is the method called by QCPAxis in order to actually generate tick coordinates (\a ticks), tick label strings (\a tickLabels) and sub tick coordinates (\a subTicks). The ticks are generated for the specified \a range. The generated labels typically follow the specified \a locale, \a formatChar and number \a precision, however this might be different (or even irrelevant) for certain QCPAxisTicker subclasses. The output parameter \a ticks is filled with the generated tick positions in axis coordinates. The output parameters \a subTicks and \a tickLabels are optional (set them to \c nullptr if not needed) and are respectively filled with sub tick coordinates, and tick label strings belonging to \a ticks by index. */ void QCPAxisTicker::generate(const QCPRange &range, const QLocale &locale, QChar formatChar, int precision, QVector &ticks, QVector *subTicks, QVector *tickLabels) { // generate (major) ticks: double tickStep = getTickStep(range); ticks = createTickVector(tickStep, range); trimTicks(range, ticks, true); // trim ticks to visible range plus one outer tick on each side (incase a subclass createTickVector creates more) // generate sub ticks between major ticks: if (subTicks) { if (!ticks.isEmpty()) { *subTicks = createSubTickVector(getSubTickCount(tickStep), ticks); trimTicks(range, *subTicks, false); } else *subTicks = QVector(); } // finally trim also outliers (no further clipping happens in axis drawing): trimTicks(range, ticks, false); // generate labels for visible ticks if requested: if (tickLabels) *tickLabels = createLabelVector(ticks, locale, formatChar, precision); } /*! \internal Takes the entire currently visible axis range and returns a sensible tick step in order to provide readable tick labels as well as a reasonable number of tick counts (see \ref setTickCount, \ref setTickStepStrategy). If a QCPAxisTicker subclass only wants a different tick step behaviour than the default implementation, it should reimplement this method. See \ref cleanMantissa for a possible helper function. */ double QCPAxisTicker::getTickStep(const QCPRange &range) { double exactStep = range.size()/double(mTickCount+1e-10); // mTickCount ticks on average, the small addition is to prevent jitter on exact integers return cleanMantissa(exactStep); } /*! \internal Takes the \a tickStep, i.e. the distance between two consecutive ticks, and returns an appropriate number of sub ticks for that specific tick step. Note that a returned sub tick count of e.g. 4 will split each tick interval into 5 sections. */ int QCPAxisTicker::getSubTickCount(double tickStep) { int result = 1; // default to 1, if no proper value can be found // separate integer and fractional part of mantissa: double epsilon = 0.01; double intPartf; int intPart; double fracPart = modf(getMantissa(tickStep), &intPartf); intPart = int(intPartf); // handle cases with (almost) integer mantissa: if (fracPart < epsilon || 1.0-fracPart < epsilon) { if (1.0-fracPart < epsilon) ++intPart; switch (intPart) { case 1: result = 4; break; // 1.0 -> 0.2 substep case 2: result = 3; break; // 2.0 -> 0.5 substep case 3: result = 2; break; // 3.0 -> 1.0 substep case 4: result = 3; break; // 4.0 -> 1.0 substep case 5: result = 4; break; // 5.0 -> 1.0 substep case 6: result = 2; break; // 6.0 -> 2.0 substep case 7: result = 6; break; // 7.0 -> 1.0 substep case 8: result = 3; break; // 8.0 -> 2.0 substep case 9: result = 2; break; // 9.0 -> 3.0 substep } } else { // handle cases with significantly fractional mantissa: if (qAbs(fracPart-0.5) < epsilon) // *.5 mantissa { switch (intPart) { case 1: result = 2; break; // 1.5 -> 0.5 substep case 2: result = 4; break; // 2.5 -> 0.5 substep case 3: result = 4; break; // 3.5 -> 0.7 substep case 4: result = 2; break; // 4.5 -> 1.5 substep case 5: result = 4; break; // 5.5 -> 1.1 substep (won't occur with default getTickStep from here on) case 6: result = 4; break; // 6.5 -> 1.3 substep case 7: result = 2; break; // 7.5 -> 2.5 substep case 8: result = 4; break; // 8.5 -> 1.7 substep case 9: result = 4; break; // 9.5 -> 1.9 substep } } // if mantissa fraction isn't 0.0 or 0.5, don't bother finding good sub tick marks, leave default } return result; } /*! \internal This method returns the tick label string as it should be printed under the \a tick coordinate. If a textual number is returned, it should respect the provided \a locale, \a formatChar and \a precision. If the returned value contains exponentials of the form "2e5" and beautifully typeset powers is enabled in the QCPAxis number format (\ref QCPAxis::setNumberFormat), the exponential part will be formatted accordingly using multiplication symbol and superscript during rendering of the label automatically. */ QString QCPAxisTicker::getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) { return locale.toString(tick, formatChar.toLatin1(), precision); } /*! \internal Returns a vector containing all coordinates of sub ticks that should be drawn. It generates \a subTickCount sub ticks between each tick pair given in \a ticks. If a QCPAxisTicker subclass needs maximal control over the generated sub ticks, it should reimplement this method. Depending on the purpose of the subclass it doesn't necessarily need to base its result on \a subTickCount or \a ticks. */ QVector QCPAxisTicker::createSubTickVector(int subTickCount, const QVector &ticks) { QVector result; if (subTickCount <= 0 || ticks.size() < 2) return result; result.reserve((ticks.size()-1)*subTickCount); for (int i=1; i QCPAxisTicker::createTickVector(double tickStep, const QCPRange &range) { QVector result; // Generate tick positions according to tickStep: qint64 firstStep = qint64(floor((range.lower-mTickOrigin)/tickStep)); // do not use qFloor here, or we'll lose 64 bit precision qint64 lastStep = qint64(ceil((range.upper-mTickOrigin)/tickStep)); // do not use qCeil here, or we'll lose 64 bit precision int tickcount = int(lastStep-firstStep+1); if (tickcount < 0) tickcount = 0; result.resize(tickcount); for (int i=0; i QCPAxisTicker::createLabelVector(const QVector &ticks, const QLocale &locale, QChar formatChar, int precision) { QVector result; result.reserve(ticks.size()); foreach (double tickCoord, ticks) result.append(getTickLabel(tickCoord, locale, formatChar, precision)); return result; } /*! \internal Removes tick coordinates from \a ticks which lie outside the specified \a range. If \a keepOneOutlier is true, it preserves one tick just outside the range on both sides, if present. The passed \a ticks must be sorted in ascending order. */ void QCPAxisTicker::trimTicks(const QCPRange &range, QVector &ticks, bool keepOneOutlier) const { bool lowFound = false; bool highFound = false; int lowIndex = 0; int highIndex = -1; for (int i=0; i < ticks.size(); ++i) { if (ticks.at(i) >= range.lower) { lowFound = true; lowIndex = i; break; } } for (int i=ticks.size()-1; i >= 0; --i) { if (ticks.at(i) <= range.upper) { highFound = true; highIndex = i; break; } } if (highFound && lowFound) { int trimFront = qMax(0, lowIndex-(keepOneOutlier ? 1 : 0)); int trimBack = qMax(0, ticks.size()-(keepOneOutlier ? 2 : 1)-highIndex); if (trimFront > 0 || trimBack > 0) ticks = ticks.mid(trimFront, ticks.size()-trimFront-trimBack); } else // all ticks are either all below or all above the range ticks.clear(); } /*! \internal Returns the coordinate contained in \a candidates which is closest to the provided \a target. This method assumes \a candidates is not empty and sorted in ascending order. */ double QCPAxisTicker::pickClosest(double target, const QVector &candidates) const { if (candidates.size() == 1) return candidates.first(); QVector::const_iterator it = std::lower_bound(candidates.constBegin(), candidates.constEnd(), target); if (it == candidates.constEnd()) return *(it-1); else if (it == candidates.constBegin()) return *it; else return target-*(it-1) < *it-target ? *(it-1) : *it; } /*! \internal Returns the decimal mantissa of \a input. Optionally, if \a magnitude is not set to zero, it also returns the magnitude of \a input as a power of 10. For example, an input of 142.6 will return a mantissa of 1.426 and a magnitude of 100. */ double QCPAxisTicker::getMantissa(double input, double *magnitude) const { const double mag = qPow(10.0, qFloor(qLn(input)/qLn(10.0))); if (magnitude) *magnitude = mag; return input/mag; } /*! \internal Returns a number that is close to \a input but has a clean, easier human readable mantissa. How strongly the mantissa is altered, and thus how strong the result deviates from the original \a input, depends on the current tick step strategy (see \ref setTickStepStrategy). */ double QCPAxisTicker::cleanMantissa(double input) const { double magnitude; const double mantissa = getMantissa(input, &magnitude); switch (mTickStepStrategy) { case tssReadability: { return pickClosest(mantissa, QVector() << 1.0 << 2.0 << 2.5 << 5.0 << 10.0)*magnitude; } case tssMeetTickCount: { // this gives effectively a mantissa of 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 8.0, 10.0 if (mantissa <= 5.0) return int(mantissa*2)/2.0*magnitude; // round digit after decimal point to 0.5 else return int(mantissa/2.0)*2.0*magnitude; // round to first digit in multiples of 2 } } return input; } /* end of 'src/axis/axisticker.cpp' */ /* including file 'src/axis/axistickerdatetime.cpp' */ /* modified 2021-03-29T02:30:44, size 18829 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxisTickerDateTime //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxisTickerDateTime \brief Specialized axis ticker for calendar dates and times as axis ticks \image html axisticker-datetime.png This QCPAxisTicker subclass generates ticks that correspond to real calendar dates and times. The plot axis coordinate is interpreted as Unix Time, so seconds since Epoch (January 1, 1970, 00:00 UTC). This is also used for example by QDateTime in the toTime_t()/setTime_t() methods with a precision of one second. Since Qt 4.7, millisecond accuracy can be obtained from QDateTime by using QDateTime::fromMSecsSinceEpoch()/1000.0. The static methods \ref dateTimeToKey and \ref keyToDateTime conveniently perform this conversion achieving a precision of one millisecond on all Qt versions. The format of the date/time display in the tick labels is controlled with \ref setDateTimeFormat. If a different time spec or time zone shall be used for the tick label appearance, see \ref setDateTimeSpec or \ref setTimeZone, respectively. This ticker produces unequal tick spacing in order to provide intuitive date and time-of-day ticks. For example, if the axis range spans a few years such that there is one tick per year, ticks will be positioned on 1. January of every year. This is intuitive but, due to leap years, will result in slightly unequal tick intervals (visually unnoticeable). The same can be seen in the image above: even though the number of days varies month by month, this ticker generates ticks on the same day of each month. If you would like to change the date/time that is used as a (mathematical) starting date for the ticks, use the \ref setTickOrigin(const QDateTime &origin) method overload, which takes a QDateTime. If you pass 15. July, 9:45 to this method, the yearly ticks will end up on 15. July at 9:45 of every year. The ticker can be created and assigned to an axis like this: \snippet documentation/doc-image-generator/mainwindow.cpp axistickerdatetime-creation \note If you rather wish to display relative times in terms of days, hours, minutes, seconds and milliseconds, and are not interested in the intricacies of real calendar dates with months and (leap) years, have a look at QCPAxisTickerTime instead. */ /*! Constructs the ticker and sets reasonable default values. Axis tickers are commonly created managed by a QSharedPointer, which then can be passed to QCPAxis::setTicker. */ QCPAxisTickerDateTime::QCPAxisTickerDateTime() : mDateTimeFormat(QLatin1String("hh:mm:ss\ndd.MM.yy")), mDateTimeSpec(Qt::LocalTime), mDateStrategy(dsNone) { setTickCount(4); } /*! Sets the format in which dates and times are displayed as tick labels. For details about the \a format string, see the documentation of QDateTime::toString(). Typical expressions are
\c dThe day as a number without a leading zero (1 to 31)
\c ddThe day as a number with a leading zero (01 to 31)
\c dddThe abbreviated localized day name (e.g. 'Mon' to 'Sun'). Uses the system locale to localize the name, i.e. QLocale::system().
\c ddddThe long localized day name (e.g. 'Monday' to 'Sunday'). Uses the system locale to localize the name, i.e. QLocale::system().
\c MThe month as a number without a leading zero (1 to 12)
\c MMThe month as a number with a leading zero (01 to 12)
\c MMMThe abbreviated localized month name (e.g. 'Jan' to 'Dec'). Uses the system locale to localize the name, i.e. QLocale::system().
\c MMMMThe long localized month name (e.g. 'January' to 'December'). Uses the system locale to localize the name, i.e. QLocale::system().
\c yyThe year as a two digit number (00 to 99)
\c yyyyThe year as a four digit number. If the year is negative, a minus sign is prepended, making five characters.
\c hThe hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
\c hhThe hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
\c HThe hour without a leading zero (0 to 23, even with AM/PM display)
\c HHThe hour with a leading zero (00 to 23, even with AM/PM display)
\c mThe minute without a leading zero (0 to 59)
\c mmThe minute with a leading zero (00 to 59)
\c sThe whole second, without any leading zero (0 to 59)
\c ssThe whole second, with a leading zero where applicable (00 to 59)
\c zThe fractional part of the second, to go after a decimal point, without trailing zeroes (0 to 999). Thus "s.z" reports the seconds to full available (millisecond) precision without trailing zeroes.
\c zzzThe fractional part of the second, to millisecond precision, including trailing zeroes where applicable (000 to 999).
\c AP or \c AUse AM/PM display. A/AP will be replaced by an upper-case version of either QLocale::amText() or QLocale::pmText().
\c ap or \c aUse am/pm display. a/ap will be replaced by a lower-case version of either QLocale::amText() or QLocale::pmText().
\c tThe timezone (for example "CEST")
Newlines can be inserted with \c "\n", literal strings (even when containing above expressions) by encapsulating them using single-quotes. A literal single quote can be generated by using two consecutive single quotes in the format. \see setDateTimeSpec, setTimeZone */ void QCPAxisTickerDateTime::setDateTimeFormat(const QString &format) { mDateTimeFormat = format; } /*! Sets the time spec that is used for creating the tick labels from corresponding dates/times. The default value of QDateTime objects (and also QCPAxisTickerDateTime) is Qt::LocalTime. However, if the displayed tick labels shall be given in UTC, set \a spec to Qt::UTC. Tick labels corresponding to other time zones can be achieved with \ref setTimeZone (which sets \a spec to \c Qt::TimeZone internally). Note that if \a spec is afterwards set to not be \c Qt::TimeZone again, the \ref setTimeZone setting will be ignored accordingly. \see setDateTimeFormat, setTimeZone */ void QCPAxisTickerDateTime::setDateTimeSpec(Qt::TimeSpec spec) { mDateTimeSpec = spec; } # if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) /*! Sets the time zone that is used for creating the tick labels from corresponding dates/times. The time spec (\ref setDateTimeSpec) is set to \c Qt::TimeZone. \see setDateTimeFormat, setTimeZone */ void QCPAxisTickerDateTime::setTimeZone(const QTimeZone &zone) { mTimeZone = zone; mDateTimeSpec = Qt::TimeZone; } #endif /*! Sets the tick origin (see \ref QCPAxisTicker::setTickOrigin) in seconds since Epoch (1. Jan 1970, 00:00 UTC). For the date time ticker it might be more intuitive to use the overload which directly takes a QDateTime, see \ref setTickOrigin(const QDateTime &origin). This is useful to define the month/day/time recurring at greater tick interval steps. For example, If you pass 15. July, 9:45 to this method and the tick interval happens to be one tick per year, the ticks will end up on 15. July at 9:45 of every year. */ void QCPAxisTickerDateTime::setTickOrigin(double origin) { QCPAxisTicker::setTickOrigin(origin); } /*! Sets the tick origin (see \ref QCPAxisTicker::setTickOrigin) as a QDateTime \a origin. This is useful to define the month/day/time recurring at greater tick interval steps. For example, If you pass 15. July, 9:45 to this method and the tick interval happens to be one tick per year, the ticks will end up on 15. July at 9:45 of every year. */ void QCPAxisTickerDateTime::setTickOrigin(const QDateTime &origin) { setTickOrigin(dateTimeToKey(origin)); } /*! \internal Returns a sensible tick step with intervals appropriate for a date-time-display, such as weekly, monthly, bi-monthly, etc. Note that this tick step isn't used exactly when generating the tick vector in \ref createTickVector, but only as a guiding value requiring some correction for each individual tick interval. Otherwise this would lead to unintuitive date displays, e.g. jumping between first day in the month to the last day in the previous month from tick to tick, due to the non-uniform length of months. The same problem arises with leap years. \seebaseclassmethod */ double QCPAxisTickerDateTime::getTickStep(const QCPRange &range) { double result = range.size()/double(mTickCount+1e-10); // mTickCount ticks on average, the small addition is to prevent jitter on exact integers mDateStrategy = dsNone; // leaving it at dsNone means tick coordinates will not be tuned in any special way in createTickVector if (result < 1) // ideal tick step is below 1 second -> use normal clean mantissa algorithm in units of seconds { result = cleanMantissa(result); } else if (result < 86400*30.4375*12) // below a year { result = pickClosest(result, QVector() << 1 << 2.5 << 5 << 10 << 15 << 30 << 60 << 2.5*60 << 5*60 << 10*60 << 15*60 << 30*60 << 60*60 // second, minute, hour range << 3600*2 << 3600*3 << 3600*6 << 3600*12 << 3600*24 // hour to day range << 86400*2 << 86400*5 << 86400*7 << 86400*14 << 86400*30.4375 << 86400*30.4375*2 << 86400*30.4375*3 << 86400*30.4375*6 << 86400*30.4375*12); // day, week, month range (avg. days per month includes leap years) if (result > 86400*30.4375-1) // month tick intervals or larger mDateStrategy = dsUniformDayInMonth; else if (result > 3600*24-1) // day tick intervals or larger mDateStrategy = dsUniformTimeInDay; } else // more than a year, go back to normal clean mantissa algorithm but in units of years { const double secondsPerYear = 86400*30.4375*12; // average including leap years result = cleanMantissa(result/secondsPerYear)*secondsPerYear; mDateStrategy = dsUniformDayInMonth; } return result; } /*! \internal Returns a sensible sub tick count with intervals appropriate for a date-time-display, such as weekly, monthly, bi-monthly, etc. \seebaseclassmethod */ int QCPAxisTickerDateTime::getSubTickCount(double tickStep) { int result = QCPAxisTicker::getSubTickCount(tickStep); switch (qRound(tickStep)) // hand chosen subticks for specific minute/hour/day/week/month range (as specified in getTickStep) { case 5*60: result = 4; break; case 10*60: result = 1; break; case 15*60: result = 2; break; case 30*60: result = 1; break; case 60*60: result = 3; break; case 3600*2: result = 3; break; case 3600*3: result = 2; break; case 3600*6: result = 1; break; case 3600*12: result = 3; break; case 3600*24: result = 3; break; case 86400*2: result = 1; break; case 86400*5: result = 4; break; case 86400*7: result = 6; break; case 86400*14: result = 1; break; case int(86400*30.4375+0.5): result = 3; break; case int(86400*30.4375*2+0.5): result = 1; break; case int(86400*30.4375*3+0.5): result = 2; break; case int(86400*30.4375*6+0.5): result = 5; break; case int(86400*30.4375*12+0.5): result = 3; break; } return result; } /*! \internal Generates a date/time tick label for tick coordinate \a tick, based on the currently set format (\ref setDateTimeFormat), time spec (\ref setDateTimeSpec), and possibly time zone (\ref setTimeZone). \seebaseclassmethod */ QString QCPAxisTickerDateTime::getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) { Q_UNUSED(precision) Q_UNUSED(formatChar) # if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) if (mDateTimeSpec == Qt::TimeZone) return locale.toString(keyToDateTime(tick).toTimeZone(mTimeZone), mDateTimeFormat); else return locale.toString(keyToDateTime(tick).toTimeSpec(mDateTimeSpec), mDateTimeFormat); # else return locale.toString(keyToDateTime(tick).toTimeSpec(mDateTimeSpec), mDateTimeFormat); # endif } /*! \internal Uses the passed \a tickStep as a guiding value and applies corrections in order to obtain non-uniform tick intervals but intuitive tick labels, e.g. falling on the same day of each month. \seebaseclassmethod */ QVector QCPAxisTickerDateTime::createTickVector(double tickStep, const QCPRange &range) { QVector result = QCPAxisTicker::createTickVector(tickStep, range); if (!result.isEmpty()) { if (mDateStrategy == dsUniformTimeInDay) { QDateTime uniformDateTime = keyToDateTime(mTickOrigin); // the time of this datetime will be set for all other ticks, if possible QDateTime tickDateTime; for (int i=0; i 15) // with leap years involved, date month may jump backwards or forwards, and needs to be corrected before setting day tickDateTime = tickDateTime.addMonths(-1); tickDateTime.setDate(QDate(tickDateTime.date().year(), tickDateTime.date().month(), thisUniformDay)); result[i] = dateTimeToKey(tickDateTime); } } } return result; } /*! A convenience method which turns \a key (in seconds since Epoch 1. Jan 1970, 00:00 UTC) into a QDateTime object. This can be used to turn axis coordinates to actual QDateTimes. The accuracy achieved by this method is one millisecond, irrespective of the used Qt version (it works around the lack of a QDateTime::fromMSecsSinceEpoch in Qt 4.6) \see dateTimeToKey */ QDateTime QCPAxisTickerDateTime::keyToDateTime(double key) { # if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) return QDateTime::fromTime_t(key).addMSecs((key-(qint64)key)*1000); # else return QDateTime::fromMSecsSinceEpoch(qint64(key*1000.0)); # endif } /*! \overload A convenience method which turns a QDateTime object into a double value that corresponds to seconds since Epoch (1. Jan 1970, 00:00 UTC). This is the format used as axis coordinates by QCPAxisTickerDateTime. The accuracy achieved by this method is one millisecond, irrespective of the used Qt version (it works around the lack of a QDateTime::toMSecsSinceEpoch in Qt 4.6) \see keyToDateTime */ double QCPAxisTickerDateTime::dateTimeToKey(const QDateTime &dateTime) { # if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) return dateTime.toTime_t()+dateTime.time().msec()/1000.0; # else return dateTime.toMSecsSinceEpoch()/1000.0; # endif } /*! \overload A convenience method which turns a QDate object into a double value that corresponds to seconds since Epoch (1. Jan 1970, 00:00 UTC). This is the format used as axis coordinates by QCPAxisTickerDateTime. The returned value will be the start of the passed day of \a date, interpreted in the given \a timeSpec. \see keyToDateTime */ double QCPAxisTickerDateTime::dateTimeToKey(const QDate &date, Qt::TimeSpec timeSpec) { # if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) return QDateTime(date, QTime(0, 0), timeSpec).toTime_t(); # elif QT_VERSION < QT_VERSION_CHECK(5, 14, 0) return QDateTime(date, QTime(0, 0), timeSpec).toMSecsSinceEpoch()/1000.0; # else return date.startOfDay(timeSpec).toMSecsSinceEpoch()/1000.0; # endif } /* end of 'src/axis/axistickerdatetime.cpp' */ /* including file 'src/axis/axistickertime.cpp' */ /* modified 2021-03-29T02:30:44, size 11745 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxisTickerTime //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxisTickerTime \brief Specialized axis ticker for time spans in units of milliseconds to days \image html axisticker-time.png This QCPAxisTicker subclass generates ticks that corresponds to time intervals. The format of the time display in the tick labels is controlled with \ref setTimeFormat and \ref setFieldWidth. The time coordinate is in the unit of seconds with respect to the time coordinate zero. Unlike with QCPAxisTickerDateTime, the ticks don't correspond to a specific calendar date and time. The time can be displayed in milliseconds, seconds, minutes, hours and days. Depending on the largest available unit in the format specified with \ref setTimeFormat, any time spans above will be carried in that largest unit. So for example if the format string is "%m:%s" and a tick at coordinate value 7815 (being 2 hours, 10 minutes and 15 seconds) is created, the resulting tick label will show "130:15" (130 minutes, 15 seconds). If the format string is "%h:%m:%s", the hour unit will be used and the label will thus be "02:10:15". Negative times with respect to the axis zero will carry a leading minus sign. The ticker can be created and assigned to an axis like this: \snippet documentation/doc-image-generator/mainwindow.cpp axistickertime-creation Here is an example of a time axis providing time information in days, hours and minutes. Due to the axis range spanning a few days and the wanted tick count (\ref setTickCount), the ticker decided to use tick steps of 12 hours: \image html axisticker-time2.png The format string for this example is \snippet documentation/doc-image-generator/mainwindow.cpp axistickertime-creation-2 \note If you rather wish to display calendar dates and times, have a look at QCPAxisTickerDateTime instead. */ /*! Constructs the ticker and sets reasonable default values. Axis tickers are commonly created managed by a QSharedPointer, which then can be passed to QCPAxis::setTicker. */ QCPAxisTickerTime::QCPAxisTickerTime() : mTimeFormat(QLatin1String("%h:%m:%s")), mSmallestUnit(tuSeconds), mBiggestUnit(tuHours) { setTickCount(4); mFieldWidth[tuMilliseconds] = 3; mFieldWidth[tuSeconds] = 2; mFieldWidth[tuMinutes] = 2; mFieldWidth[tuHours] = 2; mFieldWidth[tuDays] = 1; mFormatPattern[tuMilliseconds] = QLatin1String("%z"); mFormatPattern[tuSeconds] = QLatin1String("%s"); mFormatPattern[tuMinutes] = QLatin1String("%m"); mFormatPattern[tuHours] = QLatin1String("%h"); mFormatPattern[tuDays] = QLatin1String("%d"); } /*! Sets the format that will be used to display time in the tick labels. The available patterns are: - %%z for milliseconds - %%s for seconds - %%m for minutes - %%h for hours - %%d for days The field width (zero padding) can be controlled for each unit with \ref setFieldWidth. The largest unit that appears in \a format will carry all the remaining time of a certain tick coordinate, even if it overflows the natural limit of the unit. For example, if %%m is the largest unit it might become larger than 59 in order to consume larger time values. If on the other hand %%h is available, the minutes will wrap around to zero after 59 and the time will carry to the hour digit. */ void QCPAxisTickerTime::setTimeFormat(const QString &format) { mTimeFormat = format; // determine smallest and biggest unit in format, to optimize unit replacement and allow biggest // unit to consume remaining time of a tick value and grow beyond its modulo (e.g. min > 59) mSmallestUnit = tuMilliseconds; mBiggestUnit = tuMilliseconds; bool hasSmallest = false; for (int i = tuMilliseconds; i <= tuDays; ++i) { TimeUnit unit = static_cast(i); if (mTimeFormat.contains(mFormatPattern.value(unit))) { if (!hasSmallest) { mSmallestUnit = unit; hasSmallest = true; } mBiggestUnit = unit; } } } /*! Sets the field widh of the specified \a unit to be \a width digits, when displayed in the tick label. If the number for the specific unit is shorter than \a width, it will be padded with an according number of zeros to the left in order to reach the field width. \see setTimeFormat */ void QCPAxisTickerTime::setFieldWidth(QCPAxisTickerTime::TimeUnit unit, int width) { mFieldWidth[unit] = qMax(width, 1); } /*! \internal Returns the tick step appropriate for time displays, depending on the provided \a range and the smallest available time unit in the current format (\ref setTimeFormat). For example if the unit of seconds isn't available in the format, this method will not generate steps (like 2.5 minutes) that require sub-minute precision to be displayed correctly. \seebaseclassmethod */ double QCPAxisTickerTime::getTickStep(const QCPRange &range) { double result = range.size()/double(mTickCount+1e-10); // mTickCount ticks on average, the small addition is to prevent jitter on exact integers if (result < 1) // ideal tick step is below 1 second -> use normal clean mantissa algorithm in units of seconds { if (mSmallestUnit == tuMilliseconds) result = qMax(cleanMantissa(result), 0.001); // smallest tick step is 1 millisecond else // have no milliseconds available in format, so stick with 1 second tickstep result = 1.0; } else if (result < 3600*24) // below a day { // the filling of availableSteps seems a bit contorted but it fills in a sorted fashion and thus saves a post-fill sorting run QVector availableSteps; // seconds range: if (mSmallestUnit <= tuSeconds) availableSteps << 1; if (mSmallestUnit == tuMilliseconds) availableSteps << 2.5; // only allow half second steps if milliseconds are there to display it else if (mSmallestUnit == tuSeconds) availableSteps << 2; if (mSmallestUnit <= tuSeconds) availableSteps << 5 << 10 << 15 << 30; // minutes range: if (mSmallestUnit <= tuMinutes) availableSteps << 1*60; if (mSmallestUnit <= tuSeconds) availableSteps << 2.5*60; // only allow half minute steps if seconds are there to display it else if (mSmallestUnit == tuMinutes) availableSteps << 2*60; if (mSmallestUnit <= tuMinutes) availableSteps << 5*60 << 10*60 << 15*60 << 30*60; // hours range: if (mSmallestUnit <= tuHours) availableSteps << 1*3600 << 2*3600 << 3*3600 << 6*3600 << 12*3600 << 24*3600; // pick available step that is most appropriate to approximate ideal step: result = pickClosest(result, availableSteps); } else // more than a day, go back to normal clean mantissa algorithm but in units of days { const double secondsPerDay = 3600*24; result = cleanMantissa(result/secondsPerDay)*secondsPerDay; } return result; } /*! \internal Returns the sub tick count appropriate for the provided \a tickStep and time displays. \seebaseclassmethod */ int QCPAxisTickerTime::getSubTickCount(double tickStep) { int result = QCPAxisTicker::getSubTickCount(tickStep); switch (qRound(tickStep)) // hand chosen subticks for specific minute/hour/day range (as specified in getTickStep) { case 5*60: result = 4; break; case 10*60: result = 1; break; case 15*60: result = 2; break; case 30*60: result = 1; break; case 60*60: result = 3; break; case 3600*2: result = 3; break; case 3600*3: result = 2; break; case 3600*6: result = 1; break; case 3600*12: result = 3; break; case 3600*24: result = 3; break; } return result; } /*! \internal Returns the tick label corresponding to the provided \a tick and the configured format and field widths (\ref setTimeFormat, \ref setFieldWidth). \seebaseclassmethod */ QString QCPAxisTickerTime::getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) { Q_UNUSED(precision) Q_UNUSED(formatChar) Q_UNUSED(locale) bool negative = tick < 0; if (negative) tick *= -1; double values[tuDays+1]; // contains the msec/sec/min/... value with its respective modulo (e.g. minute 0..59) double restValues[tuDays+1]; // contains the msec/sec/min/... value as if it's the largest available unit and thus consumes the remaining time restValues[tuMilliseconds] = tick*1000; values[tuMilliseconds] = modf(restValues[tuMilliseconds]/1000, &restValues[tuSeconds])*1000; values[tuSeconds] = modf(restValues[tuSeconds]/60, &restValues[tuMinutes])*60; values[tuMinutes] = modf(restValues[tuMinutes]/60, &restValues[tuHours])*60; values[tuHours] = modf(restValues[tuHours]/24, &restValues[tuDays])*24; // no need to set values[tuDays] because days are always a rest value (there is no higher unit so it consumes all remaining time) QString result = mTimeFormat; for (int i = mSmallestUnit; i <= mBiggestUnit; ++i) { TimeUnit iUnit = static_cast(i); replaceUnit(result, iUnit, qRound(iUnit == mBiggestUnit ? restValues[iUnit] : values[iUnit])); } if (negative) result.prepend(QLatin1Char('-')); return result; } /*! \internal Replaces all occurrences of the format pattern belonging to \a unit in \a text with the specified \a value, using the field width as specified with \ref setFieldWidth for the \a unit. */ void QCPAxisTickerTime::replaceUnit(QString &text, QCPAxisTickerTime::TimeUnit unit, int value) const { QString valueStr = QString::number(value); while (valueStr.size() < mFieldWidth.value(unit)) valueStr.prepend(QLatin1Char('0')); text.replace(mFormatPattern.value(unit), valueStr); } /* end of 'src/axis/axistickertime.cpp' */ /* including file 'src/axis/axistickerfixed.cpp' */ /* modified 2021-03-29T02:30:44, size 5575 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxisTickerFixed //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxisTickerFixed \brief Specialized axis ticker with a fixed tick step \image html axisticker-fixed.png This QCPAxisTicker subclass generates ticks with a fixed tick step set with \ref setTickStep. It is also possible to allow integer multiples and integer powers of the specified tick step with \ref setScaleStrategy. A typical application of this ticker is to make an axis only display integers, by setting the tick step of the ticker to 1.0 and the scale strategy to \ref ssMultiples. Another case is when a certain number has a special meaning and axis ticks should only appear at multiples of that value. In this case you might also want to consider \ref QCPAxisTickerPi because despite the name it is not limited to only pi symbols/values. The ticker can be created and assigned to an axis like this: \snippet documentation/doc-image-generator/mainwindow.cpp axistickerfixed-creation */ /*! Constructs the ticker and sets reasonable default values. Axis tickers are commonly created managed by a QSharedPointer, which then can be passed to QCPAxis::setTicker. */ QCPAxisTickerFixed::QCPAxisTickerFixed() : mTickStep(1.0), mScaleStrategy(ssNone) { } /*! Sets the fixed tick interval to \a step. The axis ticker will only use this tick step when generating axis ticks. This might cause a very high tick density and overlapping labels if the axis range is zoomed out. Using \ref setScaleStrategy it is possible to relax the fixed step and also allow multiples or powers of \a step. This will enable the ticker to reduce the number of ticks to a reasonable amount (see \ref setTickCount). */ void QCPAxisTickerFixed::setTickStep(double step) { if (step > 0) mTickStep = step; else qDebug() << Q_FUNC_INFO << "tick step must be greater than zero:" << step; } /*! Sets whether the specified tick step (\ref setTickStep) is absolutely fixed or whether modifications may be applied to it before calculating the finally used tick step, such as permitting multiples or powers. See \ref ScaleStrategy for details. The default strategy is \ref ssNone, which means the tick step is absolutely fixed. */ void QCPAxisTickerFixed::setScaleStrategy(QCPAxisTickerFixed::ScaleStrategy strategy) { mScaleStrategy = strategy; } /*! \internal Determines the actually used tick step from the specified tick step and scale strategy (\ref setTickStep, \ref setScaleStrategy). This method either returns the specified tick step exactly, or, if the scale strategy is not \ref ssNone, a modification of it to allow varying the number of ticks in the current axis range. \seebaseclassmethod */ double QCPAxisTickerFixed::getTickStep(const QCPRange &range) { switch (mScaleStrategy) { case ssNone: { return mTickStep; } case ssMultiples: { double exactStep = range.size()/double(mTickCount+1e-10); // mTickCount ticks on average, the small addition is to prevent jitter on exact integers if (exactStep < mTickStep) return mTickStep; else return qint64(cleanMantissa(exactStep/mTickStep)+0.5)*mTickStep; } case ssPowers: { double exactStep = range.size()/double(mTickCount+1e-10); // mTickCount ticks on average, the small addition is to prevent jitter on exact integers return qPow(mTickStep, int(qLn(exactStep)/qLn(mTickStep)+0.5)); } } return mTickStep; } /* end of 'src/axis/axistickerfixed.cpp' */ /* including file 'src/axis/axistickertext.cpp' */ /* modified 2021-03-29T02:30:44, size 8742 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxisTickerText //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxisTickerText \brief Specialized axis ticker which allows arbitrary labels at specified coordinates \image html axisticker-text.png This QCPAxisTicker subclass generates ticks which can be directly specified by the user as coordinates and associated strings. They can be passed as a whole with \ref setTicks or one at a time with \ref addTick. Alternatively you can directly access the internal storage via \ref ticks and modify the tick/label data there. This is useful for cases where the axis represents categories rather than numerical values. If you are updating the ticks of this ticker regularly and in a dynamic fasion (e.g. dependent on the axis range), it is a sign that you should probably create an own ticker by subclassing QCPAxisTicker, instead of using this one. The ticker can be created and assigned to an axis like this: \snippet documentation/doc-image-generator/mainwindow.cpp axistickertext-creation */ /* start of documentation of inline functions */ /*! \fn QMap &QCPAxisTickerText::ticks() Returns a non-const reference to the internal map which stores the tick coordinates and their labels. You can access the map directly in order to add, remove or manipulate ticks, as an alternative to using the methods provided by QCPAxisTickerText, such as \ref setTicks and \ref addTick. */ /* end of documentation of inline functions */ /*! Constructs the ticker and sets reasonable default values. Axis tickers are commonly created managed by a QSharedPointer, which then can be passed to QCPAxis::setTicker. */ QCPAxisTickerText::QCPAxisTickerText() : mSubTickCount(0) { } /*! \overload Sets the ticks that shall appear on the axis. The map key of \a ticks corresponds to the axis coordinate, and the map value is the string that will appear as tick label. An alternative to manipulate ticks is to directly access the internal storage with the \ref ticks getter. \see addTicks, addTick, clear */ void QCPAxisTickerText::setTicks(const QMap &ticks) { mTicks = ticks; } /*! \overload Sets the ticks that shall appear on the axis. The entries of \a positions correspond to the axis coordinates, and the entries of \a labels are the respective strings that will appear as tick labels. \see addTicks, addTick, clear */ void QCPAxisTickerText::setTicks(const QVector &positions, const QVector &labels) { clear(); addTicks(positions, labels); } /*! Sets the number of sub ticks that shall appear between ticks. For QCPAxisTickerText, there is no automatic sub tick count calculation. So if sub ticks are needed, they must be configured with this method. */ void QCPAxisTickerText::setSubTickCount(int subTicks) { if (subTicks >= 0) mSubTickCount = subTicks; else qDebug() << Q_FUNC_INFO << "sub tick count can't be negative:" << subTicks; } /*! Clears all ticks. An alternative to manipulate ticks is to directly access the internal storage with the \ref ticks getter. \see setTicks, addTicks, addTick */ void QCPAxisTickerText::clear() { mTicks.clear(); } /*! Adds a single tick to the axis at the given axis coordinate \a position, with the provided tick \a label. \see addTicks, setTicks, clear */ void QCPAxisTickerText::addTick(double position, const QString &label) { mTicks.insert(position, label); } /*! \overload Adds the provided \a ticks to the ones already existing. The map key of \a ticks corresponds to the axis coordinate, and the map value is the string that will appear as tick label. An alternative to manipulate ticks is to directly access the internal storage with the \ref ticks getter. \see addTick, setTicks, clear */ void QCPAxisTickerText::addTicks(const QMap &ticks) { #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) mTicks.unite(ticks); #else mTicks.insert(ticks); #endif } /*! \overload Adds the provided ticks to the ones already existing. The entries of \a positions correspond to the axis coordinates, and the entries of \a labels are the respective strings that will appear as tick labels. An alternative to manipulate ticks is to directly access the internal storage with the \ref ticks getter. \see addTick, setTicks, clear */ void QCPAxisTickerText::addTicks(const QVector &positions, const QVector &labels) { if (positions.size() != labels.size()) qDebug() << Q_FUNC_INFO << "passed unequal length vectors for positions and labels:" << positions.size() << labels.size(); int n = qMin(positions.size(), labels.size()); for (int i=0; i QCPAxisTickerText::createTickVector(double tickStep, const QCPRange &range) { Q_UNUSED(tickStep) QVector result; if (mTicks.isEmpty()) return result; QMap::const_iterator start = mTicks.lowerBound(range.lower); QMap::const_iterator end = mTicks.upperBound(range.upper); // this method should try to give one tick outside of range so proper subticks can be generated: if (start != mTicks.constBegin()) --start; if (end != mTicks.constEnd()) ++end; for (QMap::const_iterator it = start; it != end; ++it) result.append(it.key()); return result; } /* end of 'src/axis/axistickertext.cpp' */ /* including file 'src/axis/axistickerpi.cpp' */ /* modified 2021-03-29T02:30:44, size 11177 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxisTickerPi //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxisTickerPi \brief Specialized axis ticker to display ticks in units of an arbitrary constant, for example pi \image html axisticker-pi.png This QCPAxisTicker subclass generates ticks that are expressed with respect to a given symbolic constant with a numerical value specified with \ref setPiValue and an appearance in the tick labels specified with \ref setPiSymbol. Ticks may be generated at fractions of the symbolic constant. How these fractions appear in the tick label can be configured with \ref setFractionStyle. The ticker can be created and assigned to an axis like this: \snippet documentation/doc-image-generator/mainwindow.cpp axistickerpi-creation */ /*! Constructs the ticker and sets reasonable default values. Axis tickers are commonly created managed by a QSharedPointer, which then can be passed to QCPAxis::setTicker. */ QCPAxisTickerPi::QCPAxisTickerPi() : mPiSymbol(QLatin1String(" ")+QChar(0x03C0)), mPiValue(M_PI), mPeriodicity(0), mFractionStyle(fsUnicodeFractions), mPiTickStep(0) { setTickCount(4); } /*! Sets how the symbol part (which is always a suffix to the number) shall appear in the axis tick label. If a space shall appear between the number and the symbol, make sure the space is contained in \a symbol. */ void QCPAxisTickerPi::setPiSymbol(QString symbol) { mPiSymbol = symbol; } /*! Sets the numerical value that the symbolic constant has. This will be used to place the appropriate fractions of the symbol at the respective axis coordinates. */ void QCPAxisTickerPi::setPiValue(double pi) { mPiValue = pi; } /*! Sets whether the axis labels shall appear periodicly and if so, at which multiplicity of the symbolic constant. To disable periodicity, set \a multiplesOfPi to zero. For example, an axis that identifies 0 with 2pi would set \a multiplesOfPi to two. */ void QCPAxisTickerPi::setPeriodicity(int multiplesOfPi) { mPeriodicity = qAbs(multiplesOfPi); } /*! Sets how the numerical/fractional part preceding the symbolic constant is displayed in tick labels. See \ref FractionStyle for the various options. */ void QCPAxisTickerPi::setFractionStyle(QCPAxisTickerPi::FractionStyle style) { mFractionStyle = style; } /*! \internal Returns the tick step, using the constant's value (\ref setPiValue) as base unit. In consequence the numerical/fractional part preceding the symbolic constant is made to have a readable mantissa. \seebaseclassmethod */ double QCPAxisTickerPi::getTickStep(const QCPRange &range) { mPiTickStep = range.size()/mPiValue/double(mTickCount+1e-10); // mTickCount ticks on average, the small addition is to prevent jitter on exact integers mPiTickStep = cleanMantissa(mPiTickStep); return mPiTickStep*mPiValue; } /*! \internal Returns the sub tick count, using the constant's value (\ref setPiValue) as base unit. In consequence the sub ticks divide the numerical/fractional part preceding the symbolic constant reasonably, and not the total tick coordinate. \seebaseclassmethod */ int QCPAxisTickerPi::getSubTickCount(double tickStep) { return QCPAxisTicker::getSubTickCount(tickStep/mPiValue); } /*! \internal Returns the tick label as a fractional/numerical part and a symbolic string as suffix. The formatting of the fraction is done according to the specified \ref setFractionStyle. The appended symbol is specified with \ref setPiSymbol. \seebaseclassmethod */ QString QCPAxisTickerPi::getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) { double tickInPis = tick/mPiValue; if (mPeriodicity > 0) tickInPis = fmod(tickInPis, mPeriodicity); if (mFractionStyle != fsFloatingPoint && mPiTickStep > 0.09 && mPiTickStep < 50) { // simply construct fraction from decimal like 1.234 -> 1234/1000 and then simplify fraction, smaller digits are irrelevant due to mPiTickStep conditional above int denominator = 1000; int numerator = qRound(tickInPis*denominator); simplifyFraction(numerator, denominator); if (qAbs(numerator) == 1 && denominator == 1) return (numerator < 0 ? QLatin1String("-") : QLatin1String("")) + mPiSymbol.trimmed(); else if (numerator == 0) return QLatin1String("0"); else return fractionToString(numerator, denominator) + mPiSymbol; } else { if (qFuzzyIsNull(tickInPis)) return QLatin1String("0"); else if (qFuzzyCompare(qAbs(tickInPis), 1.0)) return (tickInPis < 0 ? QLatin1String("-") : QLatin1String("")) + mPiSymbol.trimmed(); else return QCPAxisTicker::getTickLabel(tickInPis, locale, formatChar, precision) + mPiSymbol; } } /*! \internal Takes the fraction given by \a numerator and \a denominator and modifies the values to make sure the fraction is in irreducible form, i.e. numerator and denominator don't share any common factors which could be cancelled. */ void QCPAxisTickerPi::simplifyFraction(int &numerator, int &denominator) const { if (numerator == 0 || denominator == 0) return; int num = numerator; int denom = denominator; while (denom != 0) // euclidean gcd algorithm { int oldDenom = denom; denom = num % denom; num = oldDenom; } // num is now gcd of numerator and denominator numerator /= num; denominator /= num; } /*! \internal Takes the fraction given by \a numerator and \a denominator and returns a string representation. The result depends on the configured fraction style (\ref setFractionStyle). This method is used to format the numerical/fractional part when generating tick labels. It simplifies the passed fraction to an irreducible form using \ref simplifyFraction and factors out any integer parts of the fraction (e.g. "10/4" becomes "2 1/2"). */ QString QCPAxisTickerPi::fractionToString(int numerator, int denominator) const { if (denominator == 0) { qDebug() << Q_FUNC_INFO << "called with zero denominator"; return QString(); } if (mFractionStyle == fsFloatingPoint) // should never be the case when calling this function { qDebug() << Q_FUNC_INFO << "shouldn't be called with fraction style fsDecimal"; return QString::number(numerator/double(denominator)); // failsafe } int sign = numerator*denominator < 0 ? -1 : 1; numerator = qAbs(numerator); denominator = qAbs(denominator); if (denominator == 1) { return QString::number(sign*numerator); } else { int integerPart = numerator/denominator; int remainder = numerator%denominator; if (remainder == 0) { return QString::number(sign*integerPart); } else { if (mFractionStyle == fsAsciiFractions) { return QString(QLatin1String("%1%2%3/%4")) .arg(sign == -1 ? QLatin1String("-") : QLatin1String("")) .arg(integerPart > 0 ? QString::number(integerPart)+QLatin1String(" ") : QString(QLatin1String(""))) .arg(remainder) .arg(denominator); } else if (mFractionStyle == fsUnicodeFractions) { return QString(QLatin1String("%1%2%3")) .arg(sign == -1 ? QLatin1String("-") : QLatin1String("")) .arg(integerPart > 0 ? QString::number(integerPart) : QLatin1String("")) .arg(unicodeFraction(remainder, denominator)); } } } return QString(); } /*! \internal Returns the unicode string representation of the fraction given by \a numerator and \a denominator. This is the representation used in \ref fractionToString when the fraction style (\ref setFractionStyle) is \ref fsUnicodeFractions. This method doesn't use the single-character common fractions but builds each fraction from a superscript unicode number, the unicode fraction character, and a subscript unicode number. */ QString QCPAxisTickerPi::unicodeFraction(int numerator, int denominator) const { return unicodeSuperscript(numerator)+QChar(0x2044)+unicodeSubscript(denominator); } /*! \internal Returns the unicode string representing \a number as superscript. This is used to build unicode fractions in \ref unicodeFraction. */ QString QCPAxisTickerPi::unicodeSuperscript(int number) const { if (number == 0) return QString(QChar(0x2070)); QString result; while (number > 0) { const int digit = number%10; switch (digit) { case 1: { result.prepend(QChar(0x00B9)); break; } case 2: { result.prepend(QChar(0x00B2)); break; } case 3: { result.prepend(QChar(0x00B3)); break; } default: { result.prepend(QChar(0x2070+digit)); break; } } number /= 10; } return result; } /*! \internal Returns the unicode string representing \a number as subscript. This is used to build unicode fractions in \ref unicodeFraction. */ QString QCPAxisTickerPi::unicodeSubscript(int number) const { if (number == 0) return QString(QChar(0x2080)); QString result; while (number > 0) { result.prepend(QChar(0x2080+number%10)); number /= 10; } return result; } /* end of 'src/axis/axistickerpi.cpp' */ /* including file 'src/axis/axistickerlog.cpp' */ /* modified 2021-03-29T02:30:44, size 7890 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxisTickerLog //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxisTickerLog \brief Specialized axis ticker suited for logarithmic axes \image html axisticker-log.png This QCPAxisTicker subclass generates ticks with unequal tick intervals suited for logarithmic axis scales. The ticks are placed at powers of the specified log base (\ref setLogBase). Especially in the case of a log base equal to 10 (the default), it might be desirable to have tick labels in the form of powers of ten without mantissa display. To achieve this, set the number precision (\ref QCPAxis::setNumberPrecision) to zero and the number format (\ref QCPAxis::setNumberFormat) to scientific (exponential) display with beautifully typeset decimal powers, so a format string of "eb". This will result in the following axis tick labels: \image html axisticker-log-powers.png The ticker can be created and assigned to an axis like this: \snippet documentation/doc-image-generator/mainwindow.cpp axistickerlog-creation Note that the nature of logarithmic ticks imply that there exists a smallest possible tick step, corresponding to one multiplication by the log base. If the user zooms in further than that, no new ticks would appear, leading to very sparse or even no axis ticks on the axis. To prevent this situation, this ticker falls back to regular tick generation if the axis range would be covered by too few logarithmically placed ticks. */ /*! Constructs the ticker and sets reasonable default values. Axis tickers are commonly created managed by a QSharedPointer, which then can be passed to QCPAxis::setTicker. */ QCPAxisTickerLog::QCPAxisTickerLog() : mLogBase(10.0), mSubTickCount(8), // generates 10 intervals mLogBaseLnInv(1.0/qLn(mLogBase)) { } /*! Sets the logarithm base used for tick coordinate generation. The ticks will be placed at integer powers of \a base. */ void QCPAxisTickerLog::setLogBase(double base) { if (base > 0) { mLogBase = base; mLogBaseLnInv = 1.0/qLn(mLogBase); } else qDebug() << Q_FUNC_INFO << "log base has to be greater than zero:" << base; } /*! Sets the number of sub ticks in a tick interval. Within each interval, the sub ticks are spaced linearly to provide a better visual guide, so the sub tick density increases toward the higher tick. Note that \a subTicks is the number of sub ticks (not sub intervals) in one tick interval. So in the case of logarithm base 10 an intuitive sub tick spacing would be achieved with eight sub ticks (the default). This means e.g. between the ticks 10 and 100 there will be eight ticks, namely at 20, 30, 40, 50, 60, 70, 80 and 90. */ void QCPAxisTickerLog::setSubTickCount(int subTicks) { if (subTicks >= 0) mSubTickCount = subTicks; else qDebug() << Q_FUNC_INFO << "sub tick count can't be negative:" << subTicks; } /*! \internal Returns the sub tick count specified in \ref setSubTickCount. For QCPAxisTickerLog, there is no automatic sub tick count calculation necessary. \seebaseclassmethod */ int QCPAxisTickerLog::getSubTickCount(double tickStep) { Q_UNUSED(tickStep) return mSubTickCount; } /*! \internal Creates ticks with a spacing given by the logarithm base and an increasing integer power in the provided \a range. The step in which the power increases tick by tick is chosen in order to keep the total number of ticks as close as possible to the tick count (\ref setTickCount). The parameter \a tickStep is ignored for the normal logarithmic ticker generation. Only when zoomed in very far such that not enough logarithmically placed ticks would be visible, this function falls back to the regular QCPAxisTicker::createTickVector, which then uses \a tickStep. \seebaseclassmethod */ QVector QCPAxisTickerLog::createTickVector(double tickStep, const QCPRange &range) { QVector result; if (range.lower > 0 && range.upper > 0) // positive range { const double baseTickCount = qLn(range.upper/range.lower)*mLogBaseLnInv; if (baseTickCount < 1.6) // if too few log ticks would be visible in axis range, fall back to regular tick vector generation return QCPAxisTicker::createTickVector(tickStep, range); const double exactPowerStep = baseTickCount/double(mTickCount+1e-10); const double newLogBase = qPow(mLogBase, qMax(int(cleanMantissa(exactPowerStep)), 1)); double currentTick = qPow(newLogBase, qFloor(qLn(range.lower)/qLn(newLogBase))); result.append(currentTick); while (currentTick < range.upper && currentTick > 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case { currentTick *= newLogBase; result.append(currentTick); } } else if (range.lower < 0 && range.upper < 0) // negative range { const double baseTickCount = qLn(range.lower/range.upper)*mLogBaseLnInv; if (baseTickCount < 1.6) // if too few log ticks would be visible in axis range, fall back to regular tick vector generation return QCPAxisTicker::createTickVector(tickStep, range); const double exactPowerStep = baseTickCount/double(mTickCount+1e-10); const double newLogBase = qPow(mLogBase, qMax(int(cleanMantissa(exactPowerStep)), 1)); double currentTick = -qPow(newLogBase, qCeil(qLn(-range.lower)/qLn(newLogBase))); result.append(currentTick); while (currentTick < range.upper && currentTick < 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case { currentTick /= newLogBase; result.append(currentTick); } } else // invalid range for logarithmic scale, because lower and upper have different sign { qDebug() << Q_FUNC_INFO << "Invalid range for logarithmic plot: " << range.lower << ".." << range.upper; } return result; } /* end of 'src/axis/axistickerlog.cpp' */ /* including file 'src/axis/axis.cpp' */ /* modified 2021-03-29T02:30:44, size 99883 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPGrid //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPGrid \brief Responsible for drawing the grid of a QCPAxis. This class is tightly bound to QCPAxis. Every axis owns a grid instance and uses it to draw the grid lines, sub grid lines and zero-line. You can interact with the grid of an axis via \ref QCPAxis::grid. Normally, you don't need to create an instance of QCPGrid yourself. The axis and grid drawing was split into two classes to allow them to be placed on different layers (both QCPAxis and QCPGrid inherit from QCPLayerable). Thus it is possible to have the grid in the background and the axes in the foreground, and any plottables/items in between. This described situation is the default setup, see the QCPLayer documentation. */ /*! Creates a QCPGrid instance and sets default values. You shouldn't instantiate grids on their own, since every QCPAxis brings its own QCPGrid. */ QCPGrid::QCPGrid(QCPAxis *parentAxis) : QCPLayerable(parentAxis->parentPlot(), QString(), parentAxis), mSubGridVisible{}, mAntialiasedSubGrid{}, mAntialiasedZeroLine{}, mParentAxis(parentAxis) { // warning: this is called in QCPAxis constructor, so parentAxis members should not be accessed/called setParent(parentAxis); setPen(QPen(QColor(200,200,200), 0, Qt::DotLine)); setSubGridPen(QPen(QColor(220,220,220), 0, Qt::DotLine)); setZeroLinePen(QPen(QColor(200,200,200), 0, Qt::SolidLine)); setSubGridVisible(false); setAntialiased(false); setAntialiasedSubGrid(false); setAntialiasedZeroLine(false); } /*! Sets whether grid lines at sub tick marks are drawn. \see setSubGridPen */ void QCPGrid::setSubGridVisible(bool visible) { mSubGridVisible = visible; } /*! Sets whether sub grid lines are drawn antialiased. */ void QCPGrid::setAntialiasedSubGrid(bool enabled) { mAntialiasedSubGrid = enabled; } /*! Sets whether zero lines are drawn antialiased. */ void QCPGrid::setAntialiasedZeroLine(bool enabled) { mAntialiasedZeroLine = enabled; } /*! Sets the pen with which (major) grid lines are drawn. */ void QCPGrid::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen with which sub grid lines are drawn. */ void QCPGrid::setSubGridPen(const QPen &pen) { mSubGridPen = pen; } /*! Sets the pen with which zero lines are drawn. Zero lines are lines at value coordinate 0 which may be drawn with a different pen than other grid lines. To disable zero lines and just draw normal grid lines at zero, set \a pen to Qt::NoPen. */ void QCPGrid::setZeroLinePen(const QPen &pen) { mZeroLinePen = pen; } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing the major grid lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set with \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased */ void QCPGrid::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeGrid); } /*! \internal Draws grid lines and sub grid lines at the positions of (sub) ticks of the parent axis, spanning over the complete axis rect. Also draws the zero line, if appropriate (\ref setZeroLinePen). */ void QCPGrid::draw(QCPPainter *painter) { if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; } if (mParentAxis->subTicks() && mSubGridVisible) drawSubGridLines(painter); drawGridLines(painter); } /*! \internal Draws the main grid lines and possibly a zero line with the specified painter. This is a helper function called by \ref draw. */ void QCPGrid::drawGridLines(QCPPainter *painter) const { if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; } const int tickCount = mParentAxis->mTickVector.size(); double t; // helper variable, result of coordinate-to-pixel transforms if (mParentAxis->orientation() == Qt::Horizontal) { // draw zeroline: int zeroLineIndex = -1; if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0) { applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine); painter->setPen(mZeroLinePen); double epsilon = mParentAxis->range().size()*1E-6; // for comparing double to zero for (int i=0; imTickVector.at(i)) < epsilon) { zeroLineIndex = i; t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // x painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top())); break; } } } // draw grid lines: applyDefaultAntialiasingHint(painter); painter->setPen(mPen); for (int i=0; icoordToPixel(mParentAxis->mTickVector.at(i)); // x painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top())); } } else { // draw zeroline: int zeroLineIndex = -1; if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0) { applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine); painter->setPen(mZeroLinePen); double epsilon = mParentAxis->mRange.size()*1E-6; // for comparing double to zero for (int i=0; imTickVector.at(i)) < epsilon) { zeroLineIndex = i; t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // y painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t)); break; } } } // draw grid lines: applyDefaultAntialiasingHint(painter); painter->setPen(mPen); for (int i=0; icoordToPixel(mParentAxis->mTickVector.at(i)); // y painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t)); } } } /*! \internal Draws the sub grid lines with the specified painter. This is a helper function called by \ref draw. */ void QCPGrid::drawSubGridLines(QCPPainter *painter) const { if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; } applyAntialiasingHint(painter, mAntialiasedSubGrid, QCP::aeSubGrid); double t; // helper variable, result of coordinate-to-pixel transforms painter->setPen(mSubGridPen); if (mParentAxis->orientation() == Qt::Horizontal) { foreach (double tickCoord, mParentAxis->mSubTickVector) { t = mParentAxis->coordToPixel(tickCoord); // x painter->drawLine(QLineF(t, mParentAxis->mAxisRect->bottom(), t, mParentAxis->mAxisRect->top())); } } else { foreach (double tickCoord, mParentAxis->mSubTickVector) { t = mParentAxis->coordToPixel(tickCoord); // y painter->drawLine(QLineF(mParentAxis->mAxisRect->left(), t, mParentAxis->mAxisRect->right(), t)); } } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxis //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxis \brief Manages a single axis inside a QCustomPlot. Usually doesn't need to be instantiated externally. Access %QCustomPlot's default four axes via QCustomPlot::xAxis (bottom), QCustomPlot::yAxis (left), QCustomPlot::xAxis2 (top) and QCustomPlot::yAxis2 (right). Axes are always part of an axis rect, see QCPAxisRect. \image html AxisNamesOverview.png
Naming convention of axis parts
\n \image html AxisRectSpacingOverview.png
Overview of the spacings and paddings that define the geometry of an axis. The dashed gray line on the left represents the QCustomPlot widget border.
Each axis holds an instance of QCPAxisTicker which is used to generate the tick coordinates and tick labels. You can access the currently installed \ref ticker or set a new one (possibly one of the specialized subclasses, or your own subclass) via \ref setTicker. For details, see the documentation of QCPAxisTicker. */ /* start of documentation of inline functions */ /*! \fn Qt::Orientation QCPAxis::orientation() const Returns the orientation of this axis. The axis orientation (horizontal or vertical) is deduced from the axis type (left, top, right or bottom). \see orientation(AxisType type), pixelOrientation */ /*! \fn QCPGrid *QCPAxis::grid() const Returns the \ref QCPGrid instance belonging to this axis. Access it to set details about the way the grid is displayed. */ /*! \fn static Qt::Orientation QCPAxis::orientation(AxisType type) Returns the orientation of the specified axis type \see orientation(), pixelOrientation */ /*! \fn int QCPAxis::pixelOrientation() const Returns which direction points towards higher coordinate values/keys, in pixel space. This method returns either 1 or -1. If it returns 1, then going in the positive direction along the orientation of the axis in pixels corresponds to going from lower to higher axis coordinates. On the other hand, if this method returns -1, going to smaller pixel values corresponds to going from lower to higher axis coordinates. For example, this is useful to easily shift axis coordinates by a certain amount given in pixels, without having to care about reversed or vertically aligned axes: \code double newKey = keyAxis->pixelToCoord(keyAxis->coordToPixel(oldKey)+10*keyAxis->pixelOrientation()); \endcode \a newKey will then contain a key that is ten pixels towards higher keys, starting from \a oldKey. */ /*! \fn QSharedPointer QCPAxis::ticker() const Returns a modifiable shared pointer to the currently installed axis ticker. The axis ticker is responsible for generating the tick positions and tick labels of this axis. You can access the \ref QCPAxisTicker with this method and modify basic properties such as the approximate tick count (\ref QCPAxisTicker::setTickCount). You can gain more control over the axis ticks by setting a different \ref QCPAxisTicker subclass, see the documentation there. A new axis ticker can be set with \ref setTicker. Since the ticker is stored in the axis as a shared pointer, multiple axes may share the same axis ticker simply by passing the same shared pointer to multiple axes. \see setTicker */ /* end of documentation of inline functions */ /* start of documentation of signals */ /*! \fn void QCPAxis::rangeChanged(const QCPRange &newRange) This signal is emitted when the range of this axis has changed. You can connect it to the \ref setRange slot of another axis to communicate the new range to the other axis, in order for it to be synchronized. You may also manipulate/correct the range with \ref setRange in a slot connected to this signal. This is useful if for example a maximum range span shall not be exceeded, or if the lower/upper range shouldn't go beyond certain values (see \ref QCPRange::bounded). For example, the following slot would limit the x axis to ranges between 0 and 10: \code customPlot->xAxis->setRange(newRange.bounded(0, 10)) \endcode */ /*! \fn void QCPAxis::rangeChanged(const QCPRange &newRange, const QCPRange &oldRange) \overload Additionally to the new range, this signal also provides the previous range held by the axis as \a oldRange. */ /*! \fn void QCPAxis::scaleTypeChanged(QCPAxis::ScaleType scaleType); This signal is emitted when the scale type changes, by calls to \ref setScaleType */ /*! \fn void QCPAxis::selectionChanged(QCPAxis::SelectableParts selection) This signal is emitted when the selection state of this axis has changed, either by user interaction or by a direct call to \ref setSelectedParts. */ /*! \fn void QCPAxis::selectableChanged(const QCPAxis::SelectableParts &parts); This signal is emitted when the selectability changes, by calls to \ref setSelectableParts */ /* end of documentation of signals */ /*! Constructs an Axis instance of Type \a type for the axis rect \a parent. Usually it isn't necessary to instantiate axes directly, because you can let QCustomPlot create them for you with \ref QCPAxisRect::addAxis. If you want to use own QCPAxis-subclasses however, create them manually and then inject them also via \ref QCPAxisRect::addAxis. */ QCPAxis::QCPAxis(QCPAxisRect *parent, AxisType type) : QCPLayerable(parent->parentPlot(), QString(), parent), // axis base: mAxisType(type), mAxisRect(parent), mPadding(5), mOrientation(orientation(type)), mSelectableParts(spAxis | spTickLabels | spAxisLabel), mSelectedParts(spNone), mBasePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), mSelectedBasePen(QPen(Qt::blue, 2)), // axis label: mLabel(), mLabelFont(mParentPlot->font()), mSelectedLabelFont(QFont(mLabelFont.family(), mLabelFont.pointSize(), QFont::Bold)), mLabelColor(Qt::black), mSelectedLabelColor(Qt::blue), // tick labels: mTickLabels(true), mTickLabelFont(mParentPlot->font()), mSelectedTickLabelFont(QFont(mTickLabelFont.family(), mTickLabelFont.pointSize(), QFont::Bold)), mTickLabelColor(Qt::black), mSelectedTickLabelColor(Qt::blue), mNumberPrecision(6), mNumberFormatChar('g'), mNumberBeautifulPowers(true), // ticks and subticks: mTicks(true), mSubTicks(true), mTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), mSelectedTickPen(QPen(Qt::blue, 2)), mSubTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), mSelectedSubTickPen(QPen(Qt::blue, 2)), // scale and range: mRange(0, 5), mRangeReversed(false), mScaleType(stLinear), // internal members: mGrid(new QCPGrid(this)), mAxisPainter(new QCPAxisPainterPrivate(parent->parentPlot())), mTicker(new QCPAxisTicker), mCachedMarginValid(false), mCachedMargin(0), mDragging(false) { setParent(parent); mGrid->setVisible(false); setAntialiased(false); setLayer(mParentPlot->currentLayer()); // it's actually on that layer already, but we want it in front of the grid, so we place it on there again if (type == atTop) { setTickLabelPadding(3); setLabelPadding(6); } else if (type == atRight) { setTickLabelPadding(7); setLabelPadding(12); } else if (type == atBottom) { setTickLabelPadding(3); setLabelPadding(3); } else if (type == atLeft) { setTickLabelPadding(5); setLabelPadding(10); } } QCPAxis::~QCPAxis() { delete mAxisPainter; delete mGrid; // delete grid here instead of via parent ~QObject for better defined deletion order } /* No documentation as it is a property getter */ int QCPAxis::tickLabelPadding() const { return mAxisPainter->tickLabelPadding; } /* No documentation as it is a property getter */ double QCPAxis::tickLabelRotation() const { return mAxisPainter->tickLabelRotation; } /* No documentation as it is a property getter */ QCPAxis::LabelSide QCPAxis::tickLabelSide() const { return mAxisPainter->tickLabelSide; } /* No documentation as it is a property getter */ QString QCPAxis::numberFormat() const { QString result; result.append(mNumberFormatChar); if (mNumberBeautifulPowers) { result.append(QLatin1Char('b')); if (mAxisPainter->numberMultiplyCross) result.append(QLatin1Char('c')); } return result; } /* No documentation as it is a property getter */ int QCPAxis::tickLengthIn() const { return mAxisPainter->tickLengthIn; } /* No documentation as it is a property getter */ int QCPAxis::tickLengthOut() const { return mAxisPainter->tickLengthOut; } /* No documentation as it is a property getter */ int QCPAxis::subTickLengthIn() const { return mAxisPainter->subTickLengthIn; } /* No documentation as it is a property getter */ int QCPAxis::subTickLengthOut() const { return mAxisPainter->subTickLengthOut; } /* No documentation as it is a property getter */ int QCPAxis::labelPadding() const { return mAxisPainter->labelPadding; } /* No documentation as it is a property getter */ int QCPAxis::offset() const { return mAxisPainter->offset; } /* No documentation as it is a property getter */ QCPLineEnding QCPAxis::lowerEnding() const { return mAxisPainter->lowerEnding; } /* No documentation as it is a property getter */ QCPLineEnding QCPAxis::upperEnding() const { return mAxisPainter->upperEnding; } /*! Sets whether the axis uses a linear scale or a logarithmic scale. Note that this method controls the coordinate transformation. For logarithmic scales, you will likely also want to use a logarithmic tick spacing and labeling, which can be achieved by setting the axis ticker to an instance of \ref QCPAxisTickerLog : \snippet documentation/doc-code-snippets/mainwindow.cpp qcpaxisticker-log-creation See the documentation of \ref QCPAxisTickerLog about the details of logarithmic axis tick creation. \ref setNumberPrecision */ void QCPAxis::setScaleType(QCPAxis::ScaleType type) { if (mScaleType != type) { mScaleType = type; if (mScaleType == stLogarithmic) setRange(mRange.sanitizedForLogScale()); mCachedMarginValid = false; emit scaleTypeChanged(mScaleType); } } /*! Sets the range of the axis. This slot may be connected with the \ref rangeChanged signal of another axis so this axis is always synchronized with the other axis range, when it changes. To invert the direction of an axis, use \ref setRangeReversed. */ void QCPAxis::setRange(const QCPRange &range) { if (range.lower == mRange.lower && range.upper == mRange.upper) return; if (!QCPRange::validRange(range)) return; QCPRange oldRange = mRange; if (mScaleType == stLogarithmic) { mRange = range.sanitizedForLogScale(); } else { mRange = range.sanitizedForLinScale(); } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Sets whether the user can (de-)select the parts in \a selectable by clicking on the QCustomPlot surface. (When \ref QCustomPlot::setInteractions contains iSelectAxes.) However, even when \a selectable is set to a value not allowing the selection of a specific part, it is still possible to set the selection of this part manually, by calling \ref setSelectedParts directly. \see SelectablePart, setSelectedParts */ void QCPAxis::setSelectableParts(const SelectableParts &selectable) { if (mSelectableParts != selectable) { mSelectableParts = selectable; emit selectableChanged(mSelectableParts); } } /*! Sets the selected state of the respective axis parts described by \ref SelectablePart. When a part is selected, it uses a different pen/font. The entire selection mechanism for axes is handled automatically when \ref QCustomPlot::setInteractions contains iSelectAxes. You only need to call this function when you wish to change the selection state manually. This function can change the selection state of a part, independent of the \ref setSelectableParts setting. emits the \ref selectionChanged signal when \a selected is different from the previous selection state. \see SelectablePart, setSelectableParts, selectTest, setSelectedBasePen, setSelectedTickPen, setSelectedSubTickPen, setSelectedTickLabelFont, setSelectedLabelFont, setSelectedTickLabelColor, setSelectedLabelColor */ void QCPAxis::setSelectedParts(const SelectableParts &selected) { if (mSelectedParts != selected) { mSelectedParts = selected; emit selectionChanged(mSelectedParts); } } /*! \overload Sets the lower and upper bound of the axis range. To invert the direction of an axis, use \ref setRangeReversed. There is also a slot to set a range, see \ref setRange(const QCPRange &range). */ void QCPAxis::setRange(double lower, double upper) { if (lower == mRange.lower && upper == mRange.upper) return; if (!QCPRange::validRange(lower, upper)) return; QCPRange oldRange = mRange; mRange.lower = lower; mRange.upper = upper; if (mScaleType == stLogarithmic) { mRange = mRange.sanitizedForLogScale(); } else { mRange = mRange.sanitizedForLinScale(); } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! \overload Sets the range of the axis. The \a position coordinate indicates together with the \a alignment parameter, where the new range will be positioned. \a size defines the size of the new axis range. \a alignment may be Qt::AlignLeft, Qt::AlignRight or Qt::AlignCenter. This will cause the left border, right border, or center of the range to be aligned with \a position. Any other values of \a alignment will default to Qt::AlignCenter. */ void QCPAxis::setRange(double position, double size, Qt::AlignmentFlag alignment) { if (alignment == Qt::AlignLeft) setRange(position, position+size); else if (alignment == Qt::AlignRight) setRange(position-size, position); else // alignment == Qt::AlignCenter setRange(position-size/2.0, position+size/2.0); } /*! Sets the lower bound of the axis range. The upper bound is not changed. \see setRange */ void QCPAxis::setRangeLower(double lower) { if (mRange.lower == lower) return; QCPRange oldRange = mRange; mRange.lower = lower; if (mScaleType == stLogarithmic) { mRange = mRange.sanitizedForLogScale(); } else { mRange = mRange.sanitizedForLinScale(); } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Sets the upper bound of the axis range. The lower bound is not changed. \see setRange */ void QCPAxis::setRangeUpper(double upper) { if (mRange.upper == upper) return; QCPRange oldRange = mRange; mRange.upper = upper; if (mScaleType == stLogarithmic) { mRange = mRange.sanitizedForLogScale(); } else { mRange = mRange.sanitizedForLinScale(); } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Sets whether the axis range (direction) is displayed reversed. Normally, the values on horizontal axes increase left to right, on vertical axes bottom to top. When \a reversed is set to true, the direction of increasing values is inverted. Note that the range and data interface stays the same for reversed axes, e.g. the \a lower part of the \ref setRange interface will still reference the mathematically smaller number than the \a upper part. */ void QCPAxis::setRangeReversed(bool reversed) { mRangeReversed = reversed; } /*! The axis ticker is responsible for generating the tick positions and tick labels. See the documentation of QCPAxisTicker for details on how to work with axis tickers. You can change the tick positioning/labeling behaviour of this axis by setting a different QCPAxisTicker subclass using this method. If you only wish to modify the currently installed axis ticker, access it via \ref ticker. Since the ticker is stored in the axis as a shared pointer, multiple axes may share the same axis ticker simply by passing the same shared pointer to multiple axes. \see ticker */ void QCPAxis::setTicker(QSharedPointer ticker) { if (ticker) mTicker = ticker; else qDebug() << Q_FUNC_INFO << "can not set nullptr as axis ticker"; // no need to invalidate margin cache here because produced tick labels are checked for changes in setupTickVector } /*! Sets whether tick marks are displayed. Note that setting \a show to false does not imply that tick labels are invisible, too. To achieve that, see \ref setTickLabels. \see setSubTicks */ void QCPAxis::setTicks(bool show) { if (mTicks != show) { mTicks = show; mCachedMarginValid = false; } } /*! Sets whether tick labels are displayed. Tick labels are the numbers drawn next to tick marks. */ void QCPAxis::setTickLabels(bool show) { if (mTickLabels != show) { mTickLabels = show; mCachedMarginValid = false; if (!mTickLabels) mTickVectorLabels.clear(); } } /*! Sets the distance between the axis base line (including any outward ticks) and the tick labels. \see setLabelPadding, setPadding */ void QCPAxis::setTickLabelPadding(int padding) { if (mAxisPainter->tickLabelPadding != padding) { mAxisPainter->tickLabelPadding = padding; mCachedMarginValid = false; } } /*! Sets the font of the tick labels. \see setTickLabels, setTickLabelColor */ void QCPAxis::setTickLabelFont(const QFont &font) { if (font != mTickLabelFont) { mTickLabelFont = font; mCachedMarginValid = false; } } /*! Sets the color of the tick labels. \see setTickLabels, setTickLabelFont */ void QCPAxis::setTickLabelColor(const QColor &color) { mTickLabelColor = color; } /*! Sets the rotation of the tick labels. If \a degrees is zero, the labels are drawn normally. Else, the tick labels are drawn rotated by \a degrees clockwise. The specified angle is bound to values from -90 to 90 degrees. If \a degrees is exactly -90, 0 or 90, the tick labels are centered on the tick coordinate. For other angles, the label is drawn with an offset such that it seems to point toward or away from the tick mark. */ void QCPAxis::setTickLabelRotation(double degrees) { if (!qFuzzyIsNull(degrees-mAxisPainter->tickLabelRotation)) { mAxisPainter->tickLabelRotation = qBound(-90.0, degrees, 90.0); mCachedMarginValid = false; } } /*! Sets whether the tick labels (numbers) shall appear inside or outside the axis rect. The usual and default setting is \ref lsOutside. Very compact plots sometimes require tick labels to be inside the axis rect, to save space. If \a side is set to \ref lsInside, the tick labels appear on the inside are additionally clipped to the axis rect. */ void QCPAxis::setTickLabelSide(LabelSide side) { mAxisPainter->tickLabelSide = side; mCachedMarginValid = false; } /*! Sets the number format for the numbers in tick labels. This \a formatCode is an extended version of the format code used e.g. by QString::number() and QLocale::toString(). For reference about that, see the "Argument Formats" section in the detailed description of the QString class. \a formatCode is a string of one, two or three characters. The first character is identical to the normal format code used by Qt. In short, this means: 'e'/'E' scientific format, 'f' fixed format, 'g'/'G' scientific or fixed, whichever is shorter. For the 'e', 'E', and 'f' formats, the precision set by \ref setNumberPrecision represents the number of digits after the decimal point. For the 'g' and 'G' formats, the precision represents the maximum number of significant digits, trailing zeroes are omitted. The second and third characters are optional and specific to QCustomPlot:\n If the first char was 'e' or 'g', numbers are/might be displayed in the scientific format, e.g. "5.5e9", which is ugly in a plot. So when the second char of \a formatCode is set to 'b' (for "beautiful"), those exponential numbers are formatted in a more natural way, i.e. "5.5 [multiplication sign] 10 [superscript] 9". By default, the multiplication sign is a centered dot. If instead a cross should be shown (as is usual in the USA), the third char of \a formatCode can be set to 'c'. The inserted multiplication signs are the UTF-8 characters 215 (0xD7) for the cross and 183 (0xB7) for the dot. Examples for \a formatCode: \li \c g normal format code behaviour. If number is small, fixed format is used, if number is large, normal scientific format is used \li \c gb If number is small, fixed format is used, if number is large, scientific format is used with beautifully typeset decimal powers and a dot as multiplication sign \li \c ebc All numbers are in scientific format with beautifully typeset decimal power and a cross as multiplication sign \li \c fb illegal format code, since fixed format doesn't support (or need) beautifully typeset decimal powers. Format code will be reduced to 'f'. \li \c hello illegal format code, since first char is not 'e', 'E', 'f', 'g' or 'G'. Current format code will not be changed. */ void QCPAxis::setNumberFormat(const QString &formatCode) { if (formatCode.isEmpty()) { qDebug() << Q_FUNC_INFO << "Passed formatCode is empty"; return; } mCachedMarginValid = false; // interpret first char as number format char: QString allowedFormatChars(QLatin1String("eEfgG")); if (allowedFormatChars.contains(formatCode.at(0))) { mNumberFormatChar = QLatin1Char(formatCode.at(0).toLatin1()); } else { qDebug() << Q_FUNC_INFO << "Invalid number format code (first char not in 'eEfgG'):" << formatCode; return; } if (formatCode.length() < 2) { mNumberBeautifulPowers = false; mAxisPainter->numberMultiplyCross = false; return; } // interpret second char as indicator for beautiful decimal powers: if (formatCode.at(1) == QLatin1Char('b') && (mNumberFormatChar == QLatin1Char('e') || mNumberFormatChar == QLatin1Char('g'))) { mNumberBeautifulPowers = true; } else { qDebug() << Q_FUNC_INFO << "Invalid number format code (second char not 'b' or first char neither 'e' nor 'g'):" << formatCode; return; } if (formatCode.length() < 3) { mAxisPainter->numberMultiplyCross = false; return; } // interpret third char as indicator for dot or cross multiplication symbol: if (formatCode.at(2) == QLatin1Char('c')) { mAxisPainter->numberMultiplyCross = true; } else if (formatCode.at(2) == QLatin1Char('d')) { mAxisPainter->numberMultiplyCross = false; } else { qDebug() << Q_FUNC_INFO << "Invalid number format code (third char neither 'c' nor 'd'):" << formatCode; return; } } /*! Sets the precision of the tick label numbers. See QLocale::toString(double i, char f, int prec) for details. The effect of precisions are most notably for number Formats starting with 'e', see \ref setNumberFormat */ void QCPAxis::setNumberPrecision(int precision) { if (mNumberPrecision != precision) { mNumberPrecision = precision; mCachedMarginValid = false; } } /*! Sets the length of the ticks in pixels. \a inside is the length the ticks will reach inside the plot and \a outside is the length they will reach outside the plot. If \a outside is greater than zero, the tick labels and axis label will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setSubTickLength, setTickLengthIn, setTickLengthOut */ void QCPAxis::setTickLength(int inside, int outside) { setTickLengthIn(inside); setTickLengthOut(outside); } /*! Sets the length of the inward ticks in pixels. \a inside is the length the ticks will reach inside the plot. \see setTickLengthOut, setTickLength, setSubTickLength */ void QCPAxis::setTickLengthIn(int inside) { if (mAxisPainter->tickLengthIn != inside) { mAxisPainter->tickLengthIn = inside; } } /*! Sets the length of the outward ticks in pixels. \a outside is the length the ticks will reach outside the plot. If \a outside is greater than zero, the tick labels and axis label will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setTickLengthIn, setTickLength, setSubTickLength */ void QCPAxis::setTickLengthOut(int outside) { if (mAxisPainter->tickLengthOut != outside) { mAxisPainter->tickLengthOut = outside; mCachedMarginValid = false; // only outside tick length can change margin } } /*! Sets whether sub tick marks are displayed. Sub ticks are only potentially visible if (major) ticks are also visible (see \ref setTicks) \see setTicks */ void QCPAxis::setSubTicks(bool show) { if (mSubTicks != show) { mSubTicks = show; mCachedMarginValid = false; } } /*! Sets the length of the subticks in pixels. \a inside is the length the subticks will reach inside the plot and \a outside is the length they will reach outside the plot. If \a outside is greater than zero, the tick labels and axis label will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setTickLength, setSubTickLengthIn, setSubTickLengthOut */ void QCPAxis::setSubTickLength(int inside, int outside) { setSubTickLengthIn(inside); setSubTickLengthOut(outside); } /*! Sets the length of the inward subticks in pixels. \a inside is the length the subticks will reach inside the plot. \see setSubTickLengthOut, setSubTickLength, setTickLength */ void QCPAxis::setSubTickLengthIn(int inside) { if (mAxisPainter->subTickLengthIn != inside) { mAxisPainter->subTickLengthIn = inside; } } /*! Sets the length of the outward subticks in pixels. \a outside is the length the subticks will reach outside the plot. If \a outside is greater than zero, the tick labels will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setSubTickLengthIn, setSubTickLength, setTickLength */ void QCPAxis::setSubTickLengthOut(int outside) { if (mAxisPainter->subTickLengthOut != outside) { mAxisPainter->subTickLengthOut = outside; mCachedMarginValid = false; // only outside tick length can change margin } } /*! Sets the pen, the axis base line is drawn with. \see setTickPen, setSubTickPen */ void QCPAxis::setBasePen(const QPen &pen) { mBasePen = pen; } /*! Sets the pen, tick marks will be drawn with. \see setTickLength, setBasePen */ void QCPAxis::setTickPen(const QPen &pen) { mTickPen = pen; } /*! Sets the pen, subtick marks will be drawn with. \see setSubTickCount, setSubTickLength, setBasePen */ void QCPAxis::setSubTickPen(const QPen &pen) { mSubTickPen = pen; } /*! Sets the font of the axis label. \see setLabelColor */ void QCPAxis::setLabelFont(const QFont &font) { if (mLabelFont != font) { mLabelFont = font; mCachedMarginValid = false; } } /*! Sets the color of the axis label. \see setLabelFont */ void QCPAxis::setLabelColor(const QColor &color) { mLabelColor = color; } /*! Sets the text of the axis label that will be shown below/above or next to the axis, depending on its orientation. To disable axis labels, pass an empty string as \a str. */ void QCPAxis::setLabel(const QString &str) { if (mLabel != str) { mLabel = str; mCachedMarginValid = false; } } /*! Sets the distance between the tick labels and the axis label. \see setTickLabelPadding, setPadding */ void QCPAxis::setLabelPadding(int padding) { if (mAxisPainter->labelPadding != padding) { mAxisPainter->labelPadding = padding; mCachedMarginValid = false; } } /*! Sets the padding of the axis. When \ref QCPAxisRect::setAutoMargins is enabled, the padding is the additional outer most space, that is left blank. The axis padding has no meaning if \ref QCPAxisRect::setAutoMargins is disabled. \see setLabelPadding, setTickLabelPadding */ void QCPAxis::setPadding(int padding) { if (mPadding != padding) { mPadding = padding; mCachedMarginValid = false; } } /*! Sets the offset the axis has to its axis rect side. If an axis rect side has multiple axes and automatic margin calculation is enabled for that side, only the offset of the inner most axis has meaning (even if it is set to be invisible). The offset of the other, outer axes is controlled automatically, to place them at appropriate positions. */ void QCPAxis::setOffset(int offset) { mAxisPainter->offset = offset; } /*! Sets the font that is used for tick labels when they are selected. \see setTickLabelFont, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPAxis::setSelectedTickLabelFont(const QFont &font) { if (font != mSelectedTickLabelFont) { mSelectedTickLabelFont = font; // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts } } /*! Sets the font that is used for the axis label when it is selected. \see setLabelFont, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPAxis::setSelectedLabelFont(const QFont &font) { mSelectedLabelFont = font; // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts } /*! Sets the color that is used for tick labels when they are selected. \see setTickLabelColor, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPAxis::setSelectedTickLabelColor(const QColor &color) { if (color != mSelectedTickLabelColor) { mSelectedTickLabelColor = color; } } /*! Sets the color that is used for the axis label when it is selected. \see setLabelColor, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPAxis::setSelectedLabelColor(const QColor &color) { mSelectedLabelColor = color; } /*! Sets the pen that is used to draw the axis base line when selected. \see setBasePen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPAxis::setSelectedBasePen(const QPen &pen) { mSelectedBasePen = pen; } /*! Sets the pen that is used to draw the (major) ticks when selected. \see setTickPen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPAxis::setSelectedTickPen(const QPen &pen) { mSelectedTickPen = pen; } /*! Sets the pen that is used to draw the subticks when selected. \see setSubTickPen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPAxis::setSelectedSubTickPen(const QPen &pen) { mSelectedSubTickPen = pen; } /*! Sets the style for the lower axis ending. See the documentation of QCPLineEnding for available styles. For horizontal axes, this method refers to the left ending, for vertical axes the bottom ending. Note that this meaning does not change when the axis range is reversed with \ref setRangeReversed. \see setUpperEnding */ void QCPAxis::setLowerEnding(const QCPLineEnding &ending) { mAxisPainter->lowerEnding = ending; } /*! Sets the style for the upper axis ending. See the documentation of QCPLineEnding for available styles. For horizontal axes, this method refers to the right ending, for vertical axes the top ending. Note that this meaning does not change when the axis range is reversed with \ref setRangeReversed. \see setLowerEnding */ void QCPAxis::setUpperEnding(const QCPLineEnding &ending) { mAxisPainter->upperEnding = ending; } /*! If the scale type (\ref setScaleType) is \ref stLinear, \a diff is added to the lower and upper bounds of the range. The range is simply moved by \a diff. If the scale type is \ref stLogarithmic, the range bounds are multiplied by \a diff. This corresponds to an apparent "linear" move in logarithmic scaling by a distance of log(diff). */ void QCPAxis::moveRange(double diff) { QCPRange oldRange = mRange; if (mScaleType == stLinear) { mRange.lower += diff; mRange.upper += diff; } else // mScaleType == stLogarithmic { mRange.lower *= diff; mRange.upper *= diff; } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Scales the range of this axis by \a factor around the center of the current axis range. For example, if \a factor is 2.0, then the axis range will double its size, and the point at the axis range center won't have changed its position in the QCustomPlot widget (i.e. coordinates around the center will have moved symmetrically closer). If you wish to scale around a different coordinate than the current axis range center, use the overload \ref scaleRange(double factor, double center). */ void QCPAxis::scaleRange(double factor) { scaleRange(factor, range().center()); } /*! \overload Scales the range of this axis by \a factor around the coordinate \a center. For example, if \a factor is 2.0, \a center is 1.0, then the axis range will double its size, and the point at coordinate 1.0 won't have changed its position in the QCustomPlot widget (i.e. coordinates around 1.0 will have moved symmetrically closer to 1.0). \see scaleRange(double factor) */ void QCPAxis::scaleRange(double factor, double center) { QCPRange oldRange = mRange; if (mScaleType == stLinear) { QCPRange newRange; newRange.lower = (mRange.lower-center)*factor + center; newRange.upper = (mRange.upper-center)*factor + center; if (QCPRange::validRange(newRange)) mRange = newRange.sanitizedForLinScale(); } else // mScaleType == stLogarithmic { if ((mRange.upper < 0 && center < 0) || (mRange.upper > 0 && center > 0)) // make sure center has same sign as range { QCPRange newRange; newRange.lower = qPow(mRange.lower/center, factor)*center; newRange.upper = qPow(mRange.upper/center, factor)*center; if (QCPRange::validRange(newRange)) mRange = newRange.sanitizedForLogScale(); } else qDebug() << Q_FUNC_INFO << "Center of scaling operation doesn't lie in same logarithmic sign domain as range:" << center; } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Scales the range of this axis to have a certain scale \a ratio to \a otherAxis. The scaling will be done around the center of the current axis range. For example, if \a ratio is 1, this axis is the \a yAxis and \a otherAxis is \a xAxis, graphs plotted with those axes will appear in a 1:1 aspect ratio, independent of the aspect ratio the axis rect has. This is an operation that changes the range of this axis once, it doesn't fix the scale ratio indefinitely. Note that calling this function in the constructor of the QCustomPlot's parent won't have the desired effect, since the widget dimensions aren't defined yet, and a resizeEvent will follow. */ void QCPAxis::setScaleRatio(const QCPAxis *otherAxis, double ratio) { int otherPixelSize, ownPixelSize; if (otherAxis->orientation() == Qt::Horizontal) otherPixelSize = otherAxis->axisRect()->width(); else otherPixelSize = otherAxis->axisRect()->height(); if (orientation() == Qt::Horizontal) ownPixelSize = axisRect()->width(); else ownPixelSize = axisRect()->height(); double newRangeSize = ratio*otherAxis->range().size()*ownPixelSize/double(otherPixelSize); setRange(range().center(), newRangeSize, Qt::AlignCenter); } /*! Changes the axis range such that all plottables associated with this axis are fully visible in that dimension. \see QCPAbstractPlottable::rescaleAxes, QCustomPlot::rescaleAxes */ void QCPAxis::rescale(bool onlyVisiblePlottables) { QCPRange newRange; bool haveRange = false; foreach (QCPAbstractPlottable *plottable, plottables()) { if (!plottable->realVisibility() && onlyVisiblePlottables) continue; QCPRange plottableRange; bool currentFoundRange; QCP::SignDomain signDomain = QCP::sdBoth; if (mScaleType == stLogarithmic) signDomain = (mRange.upper < 0 ? QCP::sdNegative : QCP::sdPositive); if (plottable->keyAxis() == this) plottableRange = plottable->getKeyRange(currentFoundRange, signDomain); else plottableRange = plottable->getValueRange(currentFoundRange, signDomain); if (currentFoundRange) { if (!haveRange) newRange = plottableRange; else newRange.expand(plottableRange); haveRange = true; } } if (haveRange) { if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable { double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason if (mScaleType == stLinear) { newRange.lower = center-mRange.size()/2.0; newRange.upper = center+mRange.size()/2.0; } else // mScaleType == stLogarithmic { newRange.lower = center/qSqrt(mRange.upper/mRange.lower); newRange.upper = center*qSqrt(mRange.upper/mRange.lower); } } setRange(newRange); } } /*! Transforms \a value, in pixel coordinates of the QCustomPlot widget, to axis coordinates. */ double QCPAxis::pixelToCoord(double value) const { if (orientation() == Qt::Horizontal) { if (mScaleType == stLinear) { if (!mRangeReversed) return (value-mAxisRect->left())/double(mAxisRect->width())*mRange.size()+mRange.lower; else return -(value-mAxisRect->left())/double(mAxisRect->width())*mRange.size()+mRange.upper; } else // mScaleType == stLogarithmic { if (!mRangeReversed) return qPow(mRange.upper/mRange.lower, (value-mAxisRect->left())/double(mAxisRect->width()))*mRange.lower; else return qPow(mRange.upper/mRange.lower, (mAxisRect->left()-value)/double(mAxisRect->width()))*mRange.upper; } } else // orientation() == Qt::Vertical { if (mScaleType == stLinear) { if (!mRangeReversed) return (mAxisRect->bottom()-value)/double(mAxisRect->height())*mRange.size()+mRange.lower; else return -(mAxisRect->bottom()-value)/double(mAxisRect->height())*mRange.size()+mRange.upper; } else // mScaleType == stLogarithmic { if (!mRangeReversed) return qPow(mRange.upper/mRange.lower, (mAxisRect->bottom()-value)/double(mAxisRect->height()))*mRange.lower; else return qPow(mRange.upper/mRange.lower, (value-mAxisRect->bottom())/double(mAxisRect->height()))*mRange.upper; } } } /*! Transforms \a value, in coordinates of the axis, to pixel coordinates of the QCustomPlot widget. */ double QCPAxis::coordToPixel(double value) const { if (orientation() == Qt::Horizontal) { if (mScaleType == stLinear) { if (!mRangeReversed) return (value-mRange.lower)/mRange.size()*mAxisRect->width()+mAxisRect->left(); else return (mRange.upper-value)/mRange.size()*mAxisRect->width()+mAxisRect->left(); } else // mScaleType == stLogarithmic { if (value >= 0.0 && mRange.upper < 0.0) // invalid value for logarithmic scale, just draw it outside visible range return !mRangeReversed ? mAxisRect->right()+200 : mAxisRect->left()-200; else if (value <= 0.0 && mRange.upper >= 0.0) // invalid value for logarithmic scale, just draw it outside visible range return !mRangeReversed ? mAxisRect->left()-200 : mAxisRect->right()+200; else { if (!mRangeReversed) return qLn(value/mRange.lower)/qLn(mRange.upper/mRange.lower)*mAxisRect->width()+mAxisRect->left(); else return qLn(mRange.upper/value)/qLn(mRange.upper/mRange.lower)*mAxisRect->width()+mAxisRect->left(); } } } else // orientation() == Qt::Vertical { if (mScaleType == stLinear) { if (!mRangeReversed) return mAxisRect->bottom()-(value-mRange.lower)/mRange.size()*mAxisRect->height(); else return mAxisRect->bottom()-(mRange.upper-value)/mRange.size()*mAxisRect->height(); } else // mScaleType == stLogarithmic { if (value >= 0.0 && mRange.upper < 0.0) // invalid value for logarithmic scale, just draw it outside visible range return !mRangeReversed ? mAxisRect->top()-200 : mAxisRect->bottom()+200; else if (value <= 0.0 && mRange.upper >= 0.0) // invalid value for logarithmic scale, just draw it outside visible range return !mRangeReversed ? mAxisRect->bottom()+200 : mAxisRect->top()-200; else { if (!mRangeReversed) return mAxisRect->bottom()-qLn(value/mRange.lower)/qLn(mRange.upper/mRange.lower)*mAxisRect->height(); else return mAxisRect->bottom()-qLn(mRange.upper/value)/qLn(mRange.upper/mRange.lower)*mAxisRect->height(); } } } } /*! Returns the part of the axis that is hit by \a pos (in pixels). The return value of this function is independent of the user-selectable parts defined with \ref setSelectableParts. Further, this function does not change the current selection state of the axis. If the axis is not visible (\ref setVisible), this function always returns \ref spNone. \see setSelectedParts, setSelectableParts, QCustomPlot::setInteractions */ QCPAxis::SelectablePart QCPAxis::getPartAt(const QPointF &pos) const { if (!mVisible) return spNone; if (mAxisPainter->axisSelectionBox().contains(pos.toPoint())) return spAxis; else if (mAxisPainter->tickLabelsSelectionBox().contains(pos.toPoint())) return spTickLabels; else if (mAxisPainter->labelSelectionBox().contains(pos.toPoint())) return spAxisLabel; else return spNone; } /* inherits documentation from base class */ double QCPAxis::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { if (!mParentPlot) return -1; SelectablePart part = getPartAt(pos); if ((onlySelectable && !mSelectableParts.testFlag(part)) || part == spNone) return -1; if (details) details->setValue(part); return mParentPlot->selectionTolerance()*0.99; } /*! Returns a list of all the plottables that have this axis as key or value axis. If you are only interested in plottables of type QCPGraph, see \ref graphs. \see graphs, items */ QList QCPAxis::plottables() const { QList result; if (!mParentPlot) return result; foreach (QCPAbstractPlottable *plottable, mParentPlot->mPlottables) { if (plottable->keyAxis() == this || plottable->valueAxis() == this) result.append(plottable); } return result; } /*! Returns a list of all the graphs that have this axis as key or value axis. \see plottables, items */ QList QCPAxis::graphs() const { QList result; if (!mParentPlot) return result; foreach (QCPGraph *graph, mParentPlot->mGraphs) { if (graph->keyAxis() == this || graph->valueAxis() == this) result.append(graph); } return result; } /*! Returns a list of all the items that are associated with this axis. An item is considered associated with an axis if at least one of its positions uses the axis as key or value axis. \see plottables, graphs */ QList QCPAxis::items() const { QList result; if (!mParentPlot) return result; foreach (QCPAbstractItem *item, mParentPlot->mItems) { foreach (QCPItemPosition *position, item->positions()) { if (position->keyAxis() == this || position->valueAxis() == this) { result.append(item); break; } } } return result; } /*! Transforms a margin side to the logically corresponding axis type. (QCP::msLeft to QCPAxis::atLeft, QCP::msRight to QCPAxis::atRight, etc.) */ QCPAxis::AxisType QCPAxis::marginSideToAxisType(QCP::MarginSide side) { switch (side) { case QCP::msLeft: return atLeft; case QCP::msRight: return atRight; case QCP::msTop: return atTop; case QCP::msBottom: return atBottom; default: break; } qDebug() << Q_FUNC_INFO << "Invalid margin side passed:" << static_cast(side); return atLeft; } /*! Returns the axis type that describes the opposite axis of an axis with the specified \a type. */ QCPAxis::AxisType QCPAxis::opposite(QCPAxis::AxisType type) { switch (type) { case atLeft: return atRight; case atRight: return atLeft; case atBottom: return atTop; case atTop: return atBottom; } qDebug() << Q_FUNC_INFO << "invalid axis type"; return atLeft; } /* inherits documentation from base class */ void QCPAxis::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) { Q_UNUSED(event) SelectablePart part = details.value(); if (mSelectableParts.testFlag(part)) { SelectableParts selBefore = mSelectedParts; setSelectedParts(additive ? mSelectedParts^part : part); if (selectionStateChanged) *selectionStateChanged = mSelectedParts != selBefore; } } /* inherits documentation from base class */ void QCPAxis::deselectEvent(bool *selectionStateChanged) { SelectableParts selBefore = mSelectedParts; setSelectedParts(mSelectedParts & ~mSelectableParts); if (selectionStateChanged) *selectionStateChanged = mSelectedParts != selBefore; } /*! \internal This mouse event reimplementation provides the functionality to let the user drag individual axes exclusively, by startig the drag on top of the axis. For the axis to accept this event and perform the single axis drag, the parent \ref QCPAxisRect must be configured accordingly, i.e. it must allow range dragging in the orientation of this axis (\ref QCPAxisRect::setRangeDrag) and this axis must be a draggable axis (\ref QCPAxisRect::setRangeDragAxes) \seebaseclassmethod \note The dragging of possibly multiple axes at once by starting the drag anywhere in the axis rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::mousePressEvent. */ void QCPAxis::mousePressEvent(QMouseEvent *event, const QVariant &details) { Q_UNUSED(details) if (!mParentPlot->interactions().testFlag(QCP::iRangeDrag) || !mAxisRect->rangeDrag().testFlag(orientation()) || !mAxisRect->rangeDragAxes(orientation()).contains(this)) { event->ignore(); return; } if (event->buttons() & Qt::LeftButton) { mDragging = true; // initialize antialiasing backup in case we start dragging: if (mParentPlot->noAntialiasingOnDrag()) { mAADragBackup = mParentPlot->antialiasedElements(); mNotAADragBackup = mParentPlot->notAntialiasedElements(); } // Mouse range dragging interaction: if (mParentPlot->interactions().testFlag(QCP::iRangeDrag)) mDragStartRange = mRange; } } /*! \internal This mouse event reimplementation provides the functionality to let the user drag individual axes exclusively, by startig the drag on top of the axis. \seebaseclassmethod \note The dragging of possibly multiple axes at once by starting the drag anywhere in the axis rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::mousePressEvent. \see QCPAxis::mousePressEvent */ void QCPAxis::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) { if (mDragging) { const double startPixel = orientation() == Qt::Horizontal ? startPos.x() : startPos.y(); const double currentPixel = orientation() == Qt::Horizontal ? event->pos().x() : event->pos().y(); if (mScaleType == QCPAxis::stLinear) { const double diff = pixelToCoord(startPixel) - pixelToCoord(currentPixel); setRange(mDragStartRange.lower+diff, mDragStartRange.upper+diff); } else if (mScaleType == QCPAxis::stLogarithmic) { const double diff = pixelToCoord(startPixel) / pixelToCoord(currentPixel); setRange(mDragStartRange.lower*diff, mDragStartRange.upper*diff); } if (mParentPlot->noAntialiasingOnDrag()) mParentPlot->setNotAntialiasedElements(QCP::aeAll); mParentPlot->replot(QCustomPlot::rpQueuedReplot); } } /*! \internal This mouse event reimplementation provides the functionality to let the user drag individual axes exclusively, by startig the drag on top of the axis. \seebaseclassmethod \note The dragging of possibly multiple axes at once by starting the drag anywhere in the axis rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::mousePressEvent. \see QCPAxis::mousePressEvent */ void QCPAxis::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) { Q_UNUSED(event) Q_UNUSED(startPos) mDragging = false; if (mParentPlot->noAntialiasingOnDrag()) { mParentPlot->setAntialiasedElements(mAADragBackup); mParentPlot->setNotAntialiasedElements(mNotAADragBackup); } } /*! \internal This mouse event reimplementation provides the functionality to let the user zoom individual axes exclusively, by performing the wheel event on top of the axis. For the axis to accept this event and perform the single axis zoom, the parent \ref QCPAxisRect must be configured accordingly, i.e. it must allow range zooming in the orientation of this axis (\ref QCPAxisRect::setRangeZoom) and this axis must be a zoomable axis (\ref QCPAxisRect::setRangeZoomAxes) \seebaseclassmethod \note The zooming of possibly multiple axes at once by performing the wheel event anywhere in the axis rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::wheelEvent. */ void QCPAxis::wheelEvent(QWheelEvent *event) { // Mouse range zooming interaction: if (!mParentPlot->interactions().testFlag(QCP::iRangeZoom) || !mAxisRect->rangeZoom().testFlag(orientation()) || !mAxisRect->rangeZoomAxes(orientation()).contains(this)) { event->ignore(); return; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) const double delta = event->delta(); #else const double delta = event->angleDelta().y(); #endif #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) const QPointF pos = event->pos(); #else const QPointF pos = event->position(); #endif const double wheelSteps = delta/120.0; // a single step delta is +/-120 usually const double factor = qPow(mAxisRect->rangeZoomFactor(orientation()), wheelSteps); scaleRange(factor, pixelToCoord(orientation() == Qt::Horizontal ? pos.x() : pos.y())); mParentPlot->replot(); } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing axis lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set with \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. \seebaseclassmethod \see setAntialiased */ void QCPAxis::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeAxes); } /*! \internal Draws the axis with the specified \a painter, using the internal QCPAxisPainterPrivate instance. \seebaseclassmethod */ void QCPAxis::draw(QCPPainter *painter) { QVector subTickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter QVector tickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter QVector tickLabels; // the final vector passed to QCPAxisPainter tickPositions.reserve(mTickVector.size()); tickLabels.reserve(mTickVector.size()); subTickPositions.reserve(mSubTickVector.size()); if (mTicks) { for (int i=0; itype = mAxisType; mAxisPainter->basePen = getBasePen(); mAxisPainter->labelFont = getLabelFont(); mAxisPainter->labelColor = getLabelColor(); mAxisPainter->label = mLabel; mAxisPainter->substituteExponent = mNumberBeautifulPowers; mAxisPainter->tickPen = getTickPen(); mAxisPainter->subTickPen = getSubTickPen(); mAxisPainter->tickLabelFont = getTickLabelFont(); mAxisPainter->tickLabelColor = getTickLabelColor(); mAxisPainter->axisRect = mAxisRect->rect(); mAxisPainter->viewportRect = mParentPlot->viewport(); mAxisPainter->abbreviateDecimalPowers = mScaleType == stLogarithmic; mAxisPainter->reversedEndings = mRangeReversed; mAxisPainter->tickPositions = tickPositions; mAxisPainter->tickLabels = tickLabels; mAxisPainter->subTickPositions = subTickPositions; mAxisPainter->draw(painter); } /*! \internal Prepares the internal tick vector, sub tick vector and tick label vector. This is done by calling QCPAxisTicker::generate on the currently installed ticker. If a change in the label text/count is detected, the cached axis margin is invalidated to make sure the next margin calculation recalculates the label sizes and returns an up-to-date value. */ void QCPAxis::setupTickVectors() { if (!mParentPlot) return; if ((!mTicks && !mTickLabels && !mGrid->visible()) || mRange.size() <= 0) return; QVector oldLabels = mTickVectorLabels; mTicker->generate(mRange, mParentPlot->locale(), mNumberFormatChar, mNumberPrecision, mTickVector, mSubTicks ? &mSubTickVector : nullptr, mTickLabels ? &mTickVectorLabels : nullptr); mCachedMarginValid &= mTickVectorLabels == oldLabels; // if labels have changed, margin might have changed, too } /*! \internal Returns the pen that is used to draw the axis base line. Depending on the selection state, this is either mSelectedBasePen or mBasePen. */ QPen QCPAxis::getBasePen() const { return mSelectedParts.testFlag(spAxis) ? mSelectedBasePen : mBasePen; } /*! \internal Returns the pen that is used to draw the (major) ticks. Depending on the selection state, this is either mSelectedTickPen or mTickPen. */ QPen QCPAxis::getTickPen() const { return mSelectedParts.testFlag(spAxis) ? mSelectedTickPen : mTickPen; } /*! \internal Returns the pen that is used to draw the subticks. Depending on the selection state, this is either mSelectedSubTickPen or mSubTickPen. */ QPen QCPAxis::getSubTickPen() const { return mSelectedParts.testFlag(spAxis) ? mSelectedSubTickPen : mSubTickPen; } /*! \internal Returns the font that is used to draw the tick labels. Depending on the selection state, this is either mSelectedTickLabelFont or mTickLabelFont. */ QFont QCPAxis::getTickLabelFont() const { return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelFont : mTickLabelFont; } /*! \internal Returns the font that is used to draw the axis label. Depending on the selection state, this is either mSelectedLabelFont or mLabelFont. */ QFont QCPAxis::getLabelFont() const { return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelFont : mLabelFont; } /*! \internal Returns the color that is used to draw the tick labels. Depending on the selection state, this is either mSelectedTickLabelColor or mTickLabelColor. */ QColor QCPAxis::getTickLabelColor() const { return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelColor : mTickLabelColor; } /*! \internal Returns the color that is used to draw the axis label. Depending on the selection state, this is either mSelectedLabelColor or mLabelColor. */ QColor QCPAxis::getLabelColor() const { return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelColor : mLabelColor; } /*! \internal Returns the appropriate outward margin for this axis. It is needed if \ref QCPAxisRect::setAutoMargins is set to true on the parent axis rect. An axis with axis type \ref atLeft will return an appropriate left margin, \ref atBottom will return an appropriate bottom margin and so forth. For the calculation, this function goes through similar steps as \ref draw, so changing one function likely requires the modification of the other one as well. The margin consists of the outward tick length, tick label padding, tick label size, label padding, label size, and padding. The margin is cached internally, so repeated calls while leaving the axis range, fonts, etc. unchanged are very fast. */ int QCPAxis::calculateMargin() { if (!mVisible) // if not visible, directly return 0, don't cache 0 because we can't react to setVisible in QCPAxis return 0; if (mCachedMarginValid) return mCachedMargin; // run through similar steps as QCPAxis::draw, and calculate margin needed to fit axis and its labels int margin = 0; QVector tickPositions; // the final coordToPixel transformed vector passed to QCPAxisPainter QVector tickLabels; // the final vector passed to QCPAxisPainter tickPositions.reserve(mTickVector.size()); tickLabels.reserve(mTickVector.size()); if (mTicks) { for (int i=0; itype = mAxisType; mAxisPainter->labelFont = getLabelFont(); mAxisPainter->label = mLabel; mAxisPainter->tickLabelFont = mTickLabelFont; mAxisPainter->axisRect = mAxisRect->rect(); mAxisPainter->viewportRect = mParentPlot->viewport(); mAxisPainter->tickPositions = tickPositions; mAxisPainter->tickLabels = tickLabels; margin += mAxisPainter->size(); margin += mPadding; mCachedMargin = margin; mCachedMarginValid = true; return margin; } /* inherits documentation from base class */ QCP::Interaction QCPAxis::selectionCategory() const { return QCP::iSelectAxes; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxisPainterPrivate //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxisPainterPrivate \internal \brief (Private) This is a private class and not part of the public QCustomPlot interface. It is used by QCPAxis to do the low-level drawing of axis backbone, tick marks, tick labels and axis label. It also buffers the labels to reduce replot times. The parameters are configured by directly accessing the public member variables. */ /*! Constructs a QCPAxisPainterPrivate instance. Make sure to not create a new instance on every redraw, to utilize the caching mechanisms. */ QCPAxisPainterPrivate::QCPAxisPainterPrivate(QCustomPlot *parentPlot) : type(QCPAxis::atLeft), basePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), lowerEnding(QCPLineEnding::esNone), upperEnding(QCPLineEnding::esNone), labelPadding(0), tickLabelPadding(0), tickLabelRotation(0), tickLabelSide(QCPAxis::lsOutside), substituteExponent(true), numberMultiplyCross(false), tickLengthIn(5), tickLengthOut(0), subTickLengthIn(2), subTickLengthOut(0), tickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), subTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), offset(0), abbreviateDecimalPowers(false), reversedEndings(false), mParentPlot(parentPlot), mLabelCache(16) // cache at most 16 (tick) labels { } QCPAxisPainterPrivate::~QCPAxisPainterPrivate() { } /*! \internal Draws the axis with the specified \a painter. The selection boxes (mAxisSelectionBox, mTickLabelsSelectionBox, mLabelSelectionBox) are set here, too. */ void QCPAxisPainterPrivate::draw(QCPPainter *painter) { QByteArray newHash = generateLabelParameterHash(); if (newHash != mLabelParameterHash) { mLabelCache.clear(); mLabelParameterHash = newHash; } QPoint origin; switch (type) { case QCPAxis::atLeft: origin = axisRect.bottomLeft() +QPoint(-offset, 0); break; case QCPAxis::atRight: origin = axisRect.bottomRight()+QPoint(+offset, 0); break; case QCPAxis::atTop: origin = axisRect.topLeft() +QPoint(0, -offset); break; case QCPAxis::atBottom: origin = axisRect.bottomLeft() +QPoint(0, +offset); break; } double xCor = 0, yCor = 0; // paint system correction, for pixel exact matches (affects baselines and ticks of top/right axes) switch (type) { case QCPAxis::atTop: yCor = -1; break; case QCPAxis::atRight: xCor = 1; break; default: break; } int margin = 0; // draw baseline: QLineF baseLine; painter->setPen(basePen); if (QCPAxis::orientation(type) == Qt::Horizontal) baseLine.setPoints(origin+QPointF(xCor, yCor), origin+QPointF(axisRect.width()+xCor, yCor)); else baseLine.setPoints(origin+QPointF(xCor, yCor), origin+QPointF(xCor, -axisRect.height()+yCor)); if (reversedEndings) baseLine = QLineF(baseLine.p2(), baseLine.p1()); // won't make a difference for line itself, but for line endings later painter->drawLine(baseLine); // draw ticks: if (!tickPositions.isEmpty()) { painter->setPen(tickPen); int tickDir = (type == QCPAxis::atBottom || type == QCPAxis::atRight) ? -1 : 1; // direction of ticks ("inward" is right for left axis and left for right axis) if (QCPAxis::orientation(type) == Qt::Horizontal) { foreach (double tickPos, tickPositions) painter->drawLine(QLineF(tickPos+xCor, origin.y()-tickLengthOut*tickDir+yCor, tickPos+xCor, origin.y()+tickLengthIn*tickDir+yCor)); } else { foreach (double tickPos, tickPositions) painter->drawLine(QLineF(origin.x()-tickLengthOut*tickDir+xCor, tickPos+yCor, origin.x()+tickLengthIn*tickDir+xCor, tickPos+yCor)); } } // draw subticks: if (!subTickPositions.isEmpty()) { painter->setPen(subTickPen); // direction of ticks ("inward" is right for left axis and left for right axis) int tickDir = (type == QCPAxis::atBottom || type == QCPAxis::atRight) ? -1 : 1; if (QCPAxis::orientation(type) == Qt::Horizontal) { foreach (double subTickPos, subTickPositions) painter->drawLine(QLineF(subTickPos+xCor, origin.y()-subTickLengthOut*tickDir+yCor, subTickPos+xCor, origin.y()+subTickLengthIn*tickDir+yCor)); } else { foreach (double subTickPos, subTickPositions) painter->drawLine(QLineF(origin.x()-subTickLengthOut*tickDir+xCor, subTickPos+yCor, origin.x()+subTickLengthIn*tickDir+xCor, subTickPos+yCor)); } } margin += qMax(0, qMax(tickLengthOut, subTickLengthOut)); // draw axis base endings: bool antialiasingBackup = painter->antialiasing(); painter->setAntialiasing(true); // always want endings to be antialiased, even if base and ticks themselves aren't painter->setBrush(QBrush(basePen.color())); QCPVector2D baseLineVector(baseLine.dx(), baseLine.dy()); if (lowerEnding.style() != QCPLineEnding::esNone) lowerEnding.draw(painter, QCPVector2D(baseLine.p1())-baseLineVector.normalized()*lowerEnding.realLength()*(lowerEnding.inverted()?-1:1), -baseLineVector); if (upperEnding.style() != QCPLineEnding::esNone) upperEnding.draw(painter, QCPVector2D(baseLine.p2())+baseLineVector.normalized()*upperEnding.realLength()*(upperEnding.inverted()?-1:1), baseLineVector); painter->setAntialiasing(antialiasingBackup); // tick labels: QRect oldClipRect; if (tickLabelSide == QCPAxis::lsInside) // if using inside labels, clip them to the axis rect { oldClipRect = painter->clipRegion().boundingRect(); painter->setClipRect(axisRect); } QSize tickLabelsSize(0, 0); // size of largest tick label, for offset calculation of axis label if (!tickLabels.isEmpty()) { if (tickLabelSide == QCPAxis::lsOutside) margin += tickLabelPadding; painter->setFont(tickLabelFont); painter->setPen(QPen(tickLabelColor)); const int maxLabelIndex = qMin(tickPositions.size(), tickLabels.size()); int distanceToAxis = margin; if (tickLabelSide == QCPAxis::lsInside) distanceToAxis = -(qMax(tickLengthIn, subTickLengthIn)+tickLabelPadding); for (int i=0; isetClipRect(oldClipRect); // axis label: QRect labelBounds; if (!label.isEmpty()) { margin += labelPadding; painter->setFont(labelFont); painter->setPen(QPen(labelColor)); labelBounds = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip, label); if (type == QCPAxis::atLeft) { QTransform oldTransform = painter->transform(); painter->translate((origin.x()-margin-labelBounds.height()), origin.y()); painter->rotate(-90); painter->drawText(0, 0, axisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label); painter->setTransform(oldTransform); } else if (type == QCPAxis::atRight) { QTransform oldTransform = painter->transform(); painter->translate((origin.x()+margin+labelBounds.height()), origin.y()-axisRect.height()); painter->rotate(90); painter->drawText(0, 0, axisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label); painter->setTransform(oldTransform); } else if (type == QCPAxis::atTop) painter->drawText(origin.x(), origin.y()-margin-labelBounds.height(), axisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label); else if (type == QCPAxis::atBottom) painter->drawText(origin.x(), origin.y()+margin, axisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, label); } // set selection boxes: int selectionTolerance = 0; if (mParentPlot) selectionTolerance = mParentPlot->selectionTolerance(); else qDebug() << Q_FUNC_INFO << "mParentPlot is null"; int selAxisOutSize = qMax(qMax(tickLengthOut, subTickLengthOut), selectionTolerance); int selAxisInSize = selectionTolerance; int selTickLabelSize; int selTickLabelOffset; if (tickLabelSide == QCPAxis::lsOutside) { selTickLabelSize = (QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width()); selTickLabelOffset = qMax(tickLengthOut, subTickLengthOut)+tickLabelPadding; } else { selTickLabelSize = -(QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width()); selTickLabelOffset = -(qMax(tickLengthIn, subTickLengthIn)+tickLabelPadding); } int selLabelSize = labelBounds.height(); int selLabelOffset = qMax(tickLengthOut, subTickLengthOut)+(!tickLabels.isEmpty() && tickLabelSide == QCPAxis::lsOutside ? tickLabelPadding+selTickLabelSize : 0)+labelPadding; if (type == QCPAxis::atLeft) { mAxisSelectionBox.setCoords(origin.x()-selAxisOutSize, axisRect.top(), origin.x()+selAxisInSize, axisRect.bottom()); mTickLabelsSelectionBox.setCoords(origin.x()-selTickLabelOffset-selTickLabelSize, axisRect.top(), origin.x()-selTickLabelOffset, axisRect.bottom()); mLabelSelectionBox.setCoords(origin.x()-selLabelOffset-selLabelSize, axisRect.top(), origin.x()-selLabelOffset, axisRect.bottom()); } else if (type == QCPAxis::atRight) { mAxisSelectionBox.setCoords(origin.x()-selAxisInSize, axisRect.top(), origin.x()+selAxisOutSize, axisRect.bottom()); mTickLabelsSelectionBox.setCoords(origin.x()+selTickLabelOffset+selTickLabelSize, axisRect.top(), origin.x()+selTickLabelOffset, axisRect.bottom()); mLabelSelectionBox.setCoords(origin.x()+selLabelOffset+selLabelSize, axisRect.top(), origin.x()+selLabelOffset, axisRect.bottom()); } else if (type == QCPAxis::atTop) { mAxisSelectionBox.setCoords(axisRect.left(), origin.y()-selAxisOutSize, axisRect.right(), origin.y()+selAxisInSize); mTickLabelsSelectionBox.setCoords(axisRect.left(), origin.y()-selTickLabelOffset-selTickLabelSize, axisRect.right(), origin.y()-selTickLabelOffset); mLabelSelectionBox.setCoords(axisRect.left(), origin.y()-selLabelOffset-selLabelSize, axisRect.right(), origin.y()-selLabelOffset); } else if (type == QCPAxis::atBottom) { mAxisSelectionBox.setCoords(axisRect.left(), origin.y()-selAxisInSize, axisRect.right(), origin.y()+selAxisOutSize); mTickLabelsSelectionBox.setCoords(axisRect.left(), origin.y()+selTickLabelOffset+selTickLabelSize, axisRect.right(), origin.y()+selTickLabelOffset); mLabelSelectionBox.setCoords(axisRect.left(), origin.y()+selLabelOffset+selLabelSize, axisRect.right(), origin.y()+selLabelOffset); } mAxisSelectionBox = mAxisSelectionBox.normalized(); mTickLabelsSelectionBox = mTickLabelsSelectionBox.normalized(); mLabelSelectionBox = mLabelSelectionBox.normalized(); // draw hitboxes for debug purposes: //painter->setBrush(Qt::NoBrush); //painter->drawRects(QVector() << mAxisSelectionBox << mTickLabelsSelectionBox << mLabelSelectionBox); } /*! \internal Returns the size ("margin" in QCPAxisRect context, so measured perpendicular to the axis backbone direction) needed to fit the axis. */ int QCPAxisPainterPrivate::size() { int result = 0; QByteArray newHash = generateLabelParameterHash(); if (newHash != mLabelParameterHash) { mLabelCache.clear(); mLabelParameterHash = newHash; } // get length of tick marks pointing outwards: if (!tickPositions.isEmpty()) result += qMax(0, qMax(tickLengthOut, subTickLengthOut)); // calculate size of tick labels: if (tickLabelSide == QCPAxis::lsOutside) { QSize tickLabelsSize(0, 0); if (!tickLabels.isEmpty()) { foreach (const QString &tickLabel, tickLabels) getMaxTickLabelSize(tickLabelFont, tickLabel, &tickLabelsSize); result += QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width(); result += tickLabelPadding; } } // calculate size of axis label (only height needed, because left/right labels are rotated by 90 degrees): if (!label.isEmpty()) { QFontMetrics fontMetrics(labelFont); QRect bounds; bounds = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter | Qt::AlignVCenter, label); result += bounds.height() + labelPadding; } return result; } /*! \internal Clears the internal label cache. Upon the next \ref draw, all labels will be created new. This method is called automatically in \ref draw, if any parameters have changed that invalidate the cached labels, such as font, color, etc. */ void QCPAxisPainterPrivate::clearCache() { mLabelCache.clear(); } /*! \internal Returns a hash that allows uniquely identifying whether the label parameters have changed such that the cached labels must be refreshed (\ref clearCache). It is used in \ref draw. If the return value of this method hasn't changed since the last redraw, the respective label parameters haven't changed and cached labels may be used. */ QByteArray QCPAxisPainterPrivate::generateLabelParameterHash() const { QByteArray result; result.append(QByteArray::number(mParentPlot->bufferDevicePixelRatio())); result.append(QByteArray::number(tickLabelRotation)); result.append(QByteArray::number(int(tickLabelSide))); result.append(QByteArray::number(int(substituteExponent))); result.append(QByteArray::number(int(numberMultiplyCross))); result.append(tickLabelColor.name().toLatin1()+QByteArray::number(tickLabelColor.alpha(), 16)); result.append(tickLabelFont.toString().toLatin1()); return result; } /*! \internal Draws a single tick label with the provided \a painter, utilizing the internal label cache to significantly speed up drawing of labels that were drawn in previous calls. The tick label is always bound to an axis, the distance to the axis is controllable via \a distanceToAxis in pixels. The pixel position in the axis direction is passed in the \a position parameter. Hence for the bottom axis, \a position would indicate the horizontal pixel position (not coordinate), at which the label should be drawn. In order to later draw the axis label in a place that doesn't overlap with the tick labels, the largest tick label size is needed. This is acquired by passing a \a tickLabelsSize to the \ref drawTickLabel calls during the process of drawing all tick labels of one axis. In every call, \a tickLabelsSize is expanded, if the drawn label exceeds the value \a tickLabelsSize currently holds. The label is drawn with the font and pen that are currently set on the \a painter. To draw superscripted powers, the font is temporarily made smaller by a fixed factor (see \ref getTickLabelData). */ void QCPAxisPainterPrivate::placeTickLabel(QCPPainter *painter, double position, int distanceToAxis, const QString &text, QSize *tickLabelsSize) { // warning: if you change anything here, also adapt getMaxTickLabelSize() accordingly! if (text.isEmpty()) return; QSize finalSize; QPointF labelAnchor; switch (type) { case QCPAxis::atLeft: labelAnchor = QPointF(axisRect.left()-distanceToAxis-offset, position); break; case QCPAxis::atRight: labelAnchor = QPointF(axisRect.right()+distanceToAxis+offset, position); break; case QCPAxis::atTop: labelAnchor = QPointF(position, axisRect.top()-distanceToAxis-offset); break; case QCPAxis::atBottom: labelAnchor = QPointF(position, axisRect.bottom()+distanceToAxis+offset); break; } if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && !painter->modes().testFlag(QCPPainter::pmNoCaching)) // label caching enabled { CachedLabel *cachedLabel = mLabelCache.take(text); // attempt to get label from cache if (!cachedLabel) // no cached label existed, create it { cachedLabel = new CachedLabel; TickLabelData labelData = getTickLabelData(painter->font(), text); cachedLabel->offset = getTickLabelDrawOffset(labelData)+labelData.rotatedTotalBounds.topLeft(); if (!qFuzzyCompare(1.0, mParentPlot->bufferDevicePixelRatio())) { cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size()*mParentPlot->bufferDevicePixelRatio()); #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED # ifdef QCP_DEVICEPIXELRATIO_FLOAT cachedLabel->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatioF()); # else cachedLabel->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatio()); # endif #endif } else cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size()); cachedLabel->pixmap.fill(Qt::transparent); QCPPainter cachePainter(&cachedLabel->pixmap); cachePainter.setPen(painter->pen()); drawTickLabel(&cachePainter, -labelData.rotatedTotalBounds.topLeft().x(), -labelData.rotatedTotalBounds.topLeft().y(), labelData); } // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels): bool labelClippedByBorder = false; if (tickLabelSide == QCPAxis::lsOutside) { if (QCPAxis::orientation(type) == Qt::Horizontal) labelClippedByBorder = labelAnchor.x()+cachedLabel->offset.x()+cachedLabel->pixmap.width()/mParentPlot->bufferDevicePixelRatio() > viewportRect.right() || labelAnchor.x()+cachedLabel->offset.x() < viewportRect.left(); else labelClippedByBorder = labelAnchor.y()+cachedLabel->offset.y()+cachedLabel->pixmap.height()/mParentPlot->bufferDevicePixelRatio() > viewportRect.bottom() || labelAnchor.y()+cachedLabel->offset.y() < viewportRect.top(); } if (!labelClippedByBorder) { painter->drawPixmap(labelAnchor+cachedLabel->offset, cachedLabel->pixmap); finalSize = cachedLabel->pixmap.size()/mParentPlot->bufferDevicePixelRatio(); } mLabelCache.insert(text, cachedLabel); // return label to cache or insert for the first time if newly created } else // label caching disabled, draw text directly on surface: { TickLabelData labelData = getTickLabelData(painter->font(), text); QPointF finalPosition = labelAnchor + getTickLabelDrawOffset(labelData); // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels): bool labelClippedByBorder = false; if (tickLabelSide == QCPAxis::lsOutside) { if (QCPAxis::orientation(type) == Qt::Horizontal) labelClippedByBorder = finalPosition.x()+(labelData.rotatedTotalBounds.width()+labelData.rotatedTotalBounds.left()) > viewportRect.right() || finalPosition.x()+labelData.rotatedTotalBounds.left() < viewportRect.left(); else labelClippedByBorder = finalPosition.y()+(labelData.rotatedTotalBounds.height()+labelData.rotatedTotalBounds.top()) > viewportRect.bottom() || finalPosition.y()+labelData.rotatedTotalBounds.top() < viewportRect.top(); } if (!labelClippedByBorder) { drawTickLabel(painter, finalPosition.x(), finalPosition.y(), labelData); finalSize = labelData.rotatedTotalBounds.size(); } } // expand passed tickLabelsSize if current tick label is larger: if (finalSize.width() > tickLabelsSize->width()) tickLabelsSize->setWidth(finalSize.width()); if (finalSize.height() > tickLabelsSize->height()) tickLabelsSize->setHeight(finalSize.height()); } /*! \internal This is a \ref placeTickLabel helper function. Draws the tick label specified in \a labelData with \a painter at the pixel positions \a x and \a y. This function is used by \ref placeTickLabel to create new tick labels for the cache, or to directly draw the labels on the QCustomPlot surface when label caching is disabled, i.e. when QCP::phCacheLabels plotting hint is not set. */ void QCPAxisPainterPrivate::drawTickLabel(QCPPainter *painter, double x, double y, const TickLabelData &labelData) const { // backup painter settings that we're about to change: QTransform oldTransform = painter->transform(); QFont oldFont = painter->font(); // transform painter to position/rotation: painter->translate(x, y); if (!qFuzzyIsNull(tickLabelRotation)) painter->rotate(tickLabelRotation); // draw text: if (!labelData.expPart.isEmpty()) // indicator that beautiful powers must be used { painter->setFont(labelData.baseFont); painter->drawText(0, 0, 0, 0, Qt::TextDontClip, labelData.basePart); if (!labelData.suffixPart.isEmpty()) painter->drawText(labelData.baseBounds.width()+1+labelData.expBounds.width(), 0, 0, 0, Qt::TextDontClip, labelData.suffixPart); painter->setFont(labelData.expFont); painter->drawText(labelData.baseBounds.width()+1, 0, labelData.expBounds.width(), labelData.expBounds.height(), Qt::TextDontClip, labelData.expPart); } else { painter->setFont(labelData.baseFont); painter->drawText(0, 0, labelData.totalBounds.width(), labelData.totalBounds.height(), Qt::TextDontClip | Qt::AlignHCenter, labelData.basePart); } // reset painter settings to what it was before: painter->setTransform(oldTransform); painter->setFont(oldFont); } /*! \internal This is a \ref placeTickLabel helper function. Transforms the passed \a text and \a font to a tickLabelData structure that can then be further processed by \ref getTickLabelDrawOffset and \ref drawTickLabel. It splits the text into base and exponent if necessary (member substituteExponent) and calculates appropriate bounding boxes. */ QCPAxisPainterPrivate::TickLabelData QCPAxisPainterPrivate::getTickLabelData(const QFont &font, const QString &text) const { TickLabelData result; // determine whether beautiful decimal powers should be used bool useBeautifulPowers = false; int ePos = -1; // first index of exponent part, text before that will be basePart, text until eLast will be expPart int eLast = -1; // last index of exponent part, rest of text after this will be suffixPart if (substituteExponent) { ePos = text.indexOf(QLatin1Char('e')); if (ePos > 0 && text.at(ePos-1).isDigit()) { eLast = ePos; while (eLast+1 < text.size() && (text.at(eLast+1) == QLatin1Char('+') || text.at(eLast+1) == QLatin1Char('-') || text.at(eLast+1).isDigit())) ++eLast; if (eLast > ePos) // only if also to right of 'e' is a digit/+/- interpret it as beautifiable power useBeautifulPowers = true; } } // calculate text bounding rects and do string preparation for beautiful decimal powers: result.baseFont = font; if (result.baseFont.pointSizeF() > 0) // might return -1 if specified with setPixelSize, in that case we can't do correction in next line result.baseFont.setPointSizeF(result.baseFont.pointSizeF()+0.05); // QFontMetrics.boundingRect has a bug for exact point sizes that make the results oscillate due to internal rounding if (useBeautifulPowers) { // split text into parts of number/symbol that will be drawn normally and part that will be drawn as exponent: result.basePart = text.left(ePos); result.suffixPart = text.mid(eLast+1); // also drawn normally but after exponent // in log scaling, we want to turn "1*10^n" into "10^n", else add multiplication sign and decimal base: if (abbreviateDecimalPowers && result.basePart == QLatin1String("1")) result.basePart = QLatin1String("10"); else result.basePart += (numberMultiplyCross ? QString(QChar(215)) : QString(QChar(183))) + QLatin1String("10"); result.expPart = text.mid(ePos+1, eLast-ePos); // clip "+" and leading zeros off expPart: while (result.expPart.length() > 2 && result.expPart.at(1) == QLatin1Char('0')) // length > 2 so we leave one zero when numberFormatChar is 'e' result.expPart.remove(1, 1); if (!result.expPart.isEmpty() && result.expPart.at(0) == QLatin1Char('+')) result.expPart.remove(0, 1); // prepare smaller font for exponent: result.expFont = font; if (result.expFont.pointSize() > 0) result.expFont.setPointSize(int(result.expFont.pointSize()*0.75)); else result.expFont.setPixelSize(int(result.expFont.pixelSize()*0.75)); // calculate bounding rects of base part(s), exponent part and total one: result.baseBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.basePart); result.expBounds = QFontMetrics(result.expFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.expPart); if (!result.suffixPart.isEmpty()) result.suffixBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.suffixPart); result.totalBounds = result.baseBounds.adjusted(0, 0, result.expBounds.width()+result.suffixBounds.width()+2, 0); // +2 consists of the 1 pixel spacing between base and exponent (see drawTickLabel) and an extra pixel to include AA } else // useBeautifulPowers == false { result.basePart = text; result.totalBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter, result.basePart); } result.totalBounds.moveTopLeft(QPoint(0, 0)); // want bounding box aligned top left at origin, independent of how it was created, to make further processing simpler // calculate possibly different bounding rect after rotation: result.rotatedTotalBounds = result.totalBounds; if (!qFuzzyIsNull(tickLabelRotation)) { QTransform transform; transform.rotate(tickLabelRotation); result.rotatedTotalBounds = transform.mapRect(result.rotatedTotalBounds); } return result; } /*! \internal This is a \ref placeTickLabel helper function. Calculates the offset at which the top left corner of the specified tick label shall be drawn. The offset is relative to a point right next to the tick the label belongs to. This function is thus responsible for e.g. centering tick labels under ticks and positioning them appropriately when they are rotated. */ QPointF QCPAxisPainterPrivate::getTickLabelDrawOffset(const TickLabelData &labelData) const { /* calculate label offset from base point at tick (non-trivial, for best visual appearance): short explanation for bottom axis: The anchor, i.e. the point in the label that is placed horizontally under the corresponding tick is always on the label side that is closer to the axis (e.g. the left side of the text when we're rotating clockwise). On that side, the height is halved and the resulting point is defined the anchor. This way, a 90 degree rotated text will be centered under the tick (i.e. displaced horizontally by half its height). At the same time, a 45 degree rotated text will "point toward" its tick, as is typical for rotated tick labels. */ bool doRotation = !qFuzzyIsNull(tickLabelRotation); bool flip = qFuzzyCompare(qAbs(tickLabelRotation), 90.0); // perfect +/-90 degree flip. Indicates vertical label centering on vertical axes. double radians = tickLabelRotation/180.0*M_PI; double x = 0; double y = 0; if ((type == QCPAxis::atLeft && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atRight && tickLabelSide == QCPAxis::lsInside)) // Anchor at right side of tick label { if (doRotation) { if (tickLabelRotation > 0) { x = -qCos(radians)*labelData.totalBounds.width(); y = flip ? -labelData.totalBounds.width()/2.0 : -qSin(radians)*labelData.totalBounds.width()-qCos(radians)*labelData.totalBounds.height()/2.0; } else { x = -qCos(-radians)*labelData.totalBounds.width()-qSin(-radians)*labelData.totalBounds.height(); y = flip ? +labelData.totalBounds.width()/2.0 : +qSin(-radians)*labelData.totalBounds.width()-qCos(-radians)*labelData.totalBounds.height()/2.0; } } else { x = -labelData.totalBounds.width(); y = -labelData.totalBounds.height()/2.0; } } else if ((type == QCPAxis::atRight && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atLeft && tickLabelSide == QCPAxis::lsInside)) // Anchor at left side of tick label { if (doRotation) { if (tickLabelRotation > 0) { x = +qSin(radians)*labelData.totalBounds.height(); y = flip ? -labelData.totalBounds.width()/2.0 : -qCos(radians)*labelData.totalBounds.height()/2.0; } else { x = 0; y = flip ? +labelData.totalBounds.width()/2.0 : -qCos(-radians)*labelData.totalBounds.height()/2.0; } } else { x = 0; y = -labelData.totalBounds.height()/2.0; } } else if ((type == QCPAxis::atTop && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atBottom && tickLabelSide == QCPAxis::lsInside)) // Anchor at bottom side of tick label { if (doRotation) { if (tickLabelRotation > 0) { x = -qCos(radians)*labelData.totalBounds.width()+qSin(radians)*labelData.totalBounds.height()/2.0; y = -qSin(radians)*labelData.totalBounds.width()-qCos(radians)*labelData.totalBounds.height(); } else { x = -qSin(-radians)*labelData.totalBounds.height()/2.0; y = -qCos(-radians)*labelData.totalBounds.height(); } } else { x = -labelData.totalBounds.width()/2.0; y = -labelData.totalBounds.height(); } } else if ((type == QCPAxis::atBottom && tickLabelSide == QCPAxis::lsOutside) || (type == QCPAxis::atTop && tickLabelSide == QCPAxis::lsInside)) // Anchor at top side of tick label { if (doRotation) { if (tickLabelRotation > 0) { x = +qSin(radians)*labelData.totalBounds.height()/2.0; y = 0; } else { x = -qCos(-radians)*labelData.totalBounds.width()-qSin(-radians)*labelData.totalBounds.height()/2.0; y = +qSin(-radians)*labelData.totalBounds.width(); } } else { x = -labelData.totalBounds.width()/2.0; y = 0; } } return {x, y}; } /*! \internal Simulates the steps done by \ref placeTickLabel by calculating bounding boxes of the text label to be drawn, depending on number format etc. Since only the largest tick label is wanted for the margin calculation, the passed \a tickLabelsSize is only expanded, if it's currently set to a smaller width/height. */ void QCPAxisPainterPrivate::getMaxTickLabelSize(const QFont &font, const QString &text, QSize *tickLabelsSize) const { // note: this function must return the same tick label sizes as the placeTickLabel function. QSize finalSize; if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && mLabelCache.contains(text)) // label caching enabled and have cached label { const CachedLabel *cachedLabel = mLabelCache.object(text); finalSize = cachedLabel->pixmap.size()/mParentPlot->bufferDevicePixelRatio(); } else // label caching disabled or no label with this text cached: { TickLabelData labelData = getTickLabelData(font, text); finalSize = labelData.rotatedTotalBounds.size(); } // expand passed tickLabelsSize if current tick label is larger: if (finalSize.width() > tickLabelsSize->width()) tickLabelsSize->setWidth(finalSize.width()); if (finalSize.height() > tickLabelsSize->height()) tickLabelsSize->setHeight(finalSize.height()); } /* end of 'src/axis/axis.cpp' */ /* including file 'src/scatterstyle.cpp' */ /* modified 2021-03-29T02:30:44, size 17466 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPScatterStyle //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPScatterStyle \brief Represents the visual appearance of scatter points This class holds information about shape, color and size of scatter points. In plottables like QCPGraph it is used to store how scatter points shall be drawn. For example, \ref QCPGraph::setScatterStyle takes a QCPScatterStyle instance. A scatter style consists of a shape (\ref setShape), a line color (\ref setPen) and possibly a fill (\ref setBrush), if the shape provides a fillable area. Further, the size of the shape can be controlled with \ref setSize. \section QCPScatterStyle-defining Specifying a scatter style You can set all these configurations either by calling the respective functions on an instance: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpscatterstyle-creation-1 Or you can use one of the various constructors that take different parameter combinations, making it easy to specify a scatter style in a single call, like so: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpscatterstyle-creation-2 \section QCPScatterStyle-undefinedpen Leaving the color/pen up to the plottable There are two constructors which leave the pen undefined: \ref QCPScatterStyle() and \ref QCPScatterStyle(ScatterShape shape, double size). If those constructors are used, a call to \ref isPenDefined will return false. It leads to scatter points that inherit the pen from the plottable that uses the scatter style. Thus, if such a scatter style is passed to QCPGraph, the line color of the graph (\ref QCPGraph::setPen) will be used by the scatter points. This makes it very convenient to set up typical scatter settings: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpscatterstyle-shortcreation Notice that it wasn't even necessary to explicitly call a QCPScatterStyle constructor. This works because QCPScatterStyle provides a constructor that can transform a \ref ScatterShape directly into a QCPScatterStyle instance (that's the \ref QCPScatterStyle(ScatterShape shape, double size) constructor with a default for \a size). In those cases, C++ allows directly supplying a \ref ScatterShape, where actually a QCPScatterStyle is expected. \section QCPScatterStyle-custompath-and-pixmap Custom shapes and pixmaps QCPScatterStyle supports drawing custom shapes and arbitrary pixmaps as scatter points. For custom shapes, you can provide a QPainterPath with the desired shape to the \ref setCustomPath function or call the constructor that takes a painter path. The scatter shape will automatically be set to \ref ssCustom. For pixmaps, you call \ref setPixmap with the desired QPixmap. Alternatively you can use the constructor that takes a QPixmap. The scatter shape will automatically be set to \ref ssPixmap. Note that \ref setSize does not influence the appearance of the pixmap. */ /* start documentation of inline functions */ /*! \fn bool QCPScatterStyle::isNone() const Returns whether the scatter shape is \ref ssNone. \see setShape */ /*! \fn bool QCPScatterStyle::isPenDefined() const Returns whether a pen has been defined for this scatter style. The pen is undefined if a constructor is called that does not carry \a pen as parameter. Those are \ref QCPScatterStyle() and \ref QCPScatterStyle(ScatterShape shape, double size). If the pen is undefined, the pen of the respective plottable will be used for drawing scatters. If a pen was defined for this scatter style instance, and you now wish to undefine the pen, call \ref undefinePen. \see setPen */ /* end documentation of inline functions */ /*! Creates a new QCPScatterStyle instance with size set to 6. No shape, pen or brush is defined. Since the pen is undefined (\ref isPenDefined returns false), the scatter color will be inherited from the plottable that uses this scatter style. */ QCPScatterStyle::QCPScatterStyle() : mSize(6), mShape(ssNone), mPen(Qt::NoPen), mBrush(Qt::NoBrush), mPenDefined(false) { } /*! Creates a new QCPScatterStyle instance with shape set to \a shape and size to \a size. No pen or brush is defined. Since the pen is undefined (\ref isPenDefined returns false), the scatter color will be inherited from the plottable that uses this scatter style. */ QCPScatterStyle::QCPScatterStyle(ScatterShape shape, double size) : mSize(size), mShape(shape), mPen(Qt::NoPen), mBrush(Qt::NoBrush), mPenDefined(false) { } /*! Creates a new QCPScatterStyle instance with shape set to \a shape, the pen color set to \a color, and size to \a size. No brush is defined, i.e. the scatter point will not be filled. */ QCPScatterStyle::QCPScatterStyle(ScatterShape shape, const QColor &color, double size) : mSize(size), mShape(shape), mPen(QPen(color)), mBrush(Qt::NoBrush), mPenDefined(true) { } /*! Creates a new QCPScatterStyle instance with shape set to \a shape, the pen color set to \a color, the brush color to \a fill (with a solid pattern), and size to \a size. */ QCPScatterStyle::QCPScatterStyle(ScatterShape shape, const QColor &color, const QColor &fill, double size) : mSize(size), mShape(shape), mPen(QPen(color)), mBrush(QBrush(fill)), mPenDefined(true) { } /*! Creates a new QCPScatterStyle instance with shape set to \a shape, the pen set to \a pen, the brush to \a brush, and size to \a size. \warning In some cases it might be tempting to directly use a pen style like Qt::NoPen as \a pen and a color like Qt::blue as \a brush. Notice however, that the corresponding call\n QCPScatterStyle(QCPScatterShape::ssCircle, Qt::NoPen, Qt::blue, 5)\n doesn't necessarily lead C++ to use this constructor in some cases, but might mistake Qt::NoPen for a QColor and use the \ref QCPScatterStyle(ScatterShape shape, const QColor &color, const QColor &fill, double size) constructor instead (which will lead to an unexpected look of the scatter points). To prevent this, be more explicit with the parameter types. For example, use QBrush(Qt::blue) instead of just Qt::blue, to clearly point out to the compiler that this constructor is wanted. */ QCPScatterStyle::QCPScatterStyle(ScatterShape shape, const QPen &pen, const QBrush &brush, double size) : mSize(size), mShape(shape), mPen(pen), mBrush(brush), mPenDefined(pen.style() != Qt::NoPen) { } /*! Creates a new QCPScatterStyle instance which will show the specified \a pixmap. The scatter shape is set to \ref ssPixmap. */ QCPScatterStyle::QCPScatterStyle(const QPixmap &pixmap) : mSize(5), mShape(ssPixmap), mPen(Qt::NoPen), mBrush(Qt::NoBrush), mPixmap(pixmap), mPenDefined(false) { } /*! Creates a new QCPScatterStyle instance with a custom shape that is defined via \a customPath. The scatter shape is set to \ref ssCustom. The custom shape line will be drawn with \a pen and filled with \a brush. The size has a slightly different meaning than for built-in scatter points: The custom path will be drawn scaled by a factor of \a size/6.0. Since the default \a size is 6, the custom path will appear in its original size by default. To for example double the size of the path, set \a size to 12. */ QCPScatterStyle::QCPScatterStyle(const QPainterPath &customPath, const QPen &pen, const QBrush &brush, double size) : mSize(size), mShape(ssCustom), mPen(pen), mBrush(brush), mCustomPath(customPath), mPenDefined(pen.style() != Qt::NoPen) { } /*! Copies the specified \a properties from the \a other scatter style to this scatter style. */ void QCPScatterStyle::setFromOther(const QCPScatterStyle &other, ScatterProperties properties) { if (properties.testFlag(spPen)) { setPen(other.pen()); if (!other.isPenDefined()) undefinePen(); } if (properties.testFlag(spBrush)) setBrush(other.brush()); if (properties.testFlag(spSize)) setSize(other.size()); if (properties.testFlag(spShape)) { setShape(other.shape()); if (other.shape() == ssPixmap) setPixmap(other.pixmap()); else if (other.shape() == ssCustom) setCustomPath(other.customPath()); } } /*! Sets the size (pixel diameter) of the drawn scatter points to \a size. \see setShape */ void QCPScatterStyle::setSize(double size) { mSize = size; } /*! Sets the shape to \a shape. Note that the calls \ref setPixmap and \ref setCustomPath automatically set the shape to \ref ssPixmap and \ref ssCustom, respectively. \see setSize */ void QCPScatterStyle::setShape(QCPScatterStyle::ScatterShape shape) { mShape = shape; } /*! Sets the pen that will be used to draw scatter points to \a pen. If the pen was previously undefined (see \ref isPenDefined), the pen is considered defined after a call to this function, even if \a pen is Qt::NoPen. If you have defined a pen previously by calling this function and now wish to undefine the pen, call \ref undefinePen. \see setBrush */ void QCPScatterStyle::setPen(const QPen &pen) { mPenDefined = true; mPen = pen; } /*! Sets the brush that will be used to fill scatter points to \a brush. Note that not all scatter shapes have fillable areas. For example, \ref ssPlus does not while \ref ssCircle does. \see setPen */ void QCPScatterStyle::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the pixmap that will be drawn as scatter point to \a pixmap. Note that \ref setSize does not influence the appearance of the pixmap. The scatter shape is automatically set to \ref ssPixmap. */ void QCPScatterStyle::setPixmap(const QPixmap &pixmap) { setShape(ssPixmap); mPixmap = pixmap; } /*! Sets the custom shape that will be drawn as scatter point to \a customPath. The scatter shape is automatically set to \ref ssCustom. */ void QCPScatterStyle::setCustomPath(const QPainterPath &customPath) { setShape(ssCustom); mCustomPath = customPath; } /*! Sets this scatter style to have an undefined pen (see \ref isPenDefined for what an undefined pen implies). A call to \ref setPen will define a pen. */ void QCPScatterStyle::undefinePen() { mPenDefined = false; } /*! Applies the pen and the brush of this scatter style to \a painter. If this scatter style has an undefined pen (\ref isPenDefined), sets the pen of \a painter to \a defaultPen instead. This function is used by plottables (or any class that wants to draw scatters) just before a number of scatters with this style shall be drawn with the \a painter. \see drawShape */ void QCPScatterStyle::applyTo(QCPPainter *painter, const QPen &defaultPen) const { painter->setPen(mPenDefined ? mPen : defaultPen); painter->setBrush(mBrush); } /*! Draws the scatter shape with \a painter at position \a pos. This function does not modify the pen or the brush on the painter, as \ref applyTo is meant to be called before scatter points are drawn with \ref drawShape. \see applyTo */ void QCPScatterStyle::drawShape(QCPPainter *painter, const QPointF &pos) const { drawShape(painter, pos.x(), pos.y()); } /*! \overload Draws the scatter shape with \a painter at position \a x and \a y. */ void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const { double w = mSize/2.0; switch (mShape) { case ssNone: break; case ssDot: { painter->drawLine(QPointF(x, y), QPointF(x+0.0001, y)); break; } case ssCross: { painter->drawLine(QLineF(x-w, y-w, x+w, y+w)); painter->drawLine(QLineF(x-w, y+w, x+w, y-w)); break; } case ssPlus: { painter->drawLine(QLineF(x-w, y, x+w, y)); painter->drawLine(QLineF( x, y+w, x, y-w)); break; } case ssCircle: { painter->drawEllipse(QPointF(x , y), w, w); break; } case ssDisc: { QBrush b = painter->brush(); painter->setBrush(painter->pen().color()); painter->drawEllipse(QPointF(x , y), w, w); painter->setBrush(b); break; } case ssSquare: { painter->drawRect(QRectF(x-w, y-w, mSize, mSize)); break; } case ssDiamond: { QPointF lineArray[4] = {QPointF(x-w, y), QPointF( x, y-w), QPointF(x+w, y), QPointF( x, y+w)}; painter->drawPolygon(lineArray, 4); break; } case ssStar: { painter->drawLine(QLineF(x-w, y, x+w, y)); painter->drawLine(QLineF( x, y+w, x, y-w)); painter->drawLine(QLineF(x-w*0.707, y-w*0.707, x+w*0.707, y+w*0.707)); painter->drawLine(QLineF(x-w*0.707, y+w*0.707, x+w*0.707, y-w*0.707)); break; } case ssTriangle: { QPointF lineArray[3] = {QPointF(x-w, y+0.755*w), QPointF(x+w, y+0.755*w), QPointF( x, y-0.977*w)}; painter->drawPolygon(lineArray, 3); break; } case ssTriangleInverted: { QPointF lineArray[3] = {QPointF(x-w, y-0.755*w), QPointF(x+w, y-0.755*w), QPointF( x, y+0.977*w)}; painter->drawPolygon(lineArray, 3); break; } case ssCrossSquare: { painter->drawRect(QRectF(x-w, y-w, mSize, mSize)); painter->drawLine(QLineF(x-w, y-w, x+w*0.95, y+w*0.95)); painter->drawLine(QLineF(x-w, y+w*0.95, x+w*0.95, y-w)); break; } case ssPlusSquare: { painter->drawRect(QRectF(x-w, y-w, mSize, mSize)); painter->drawLine(QLineF(x-w, y, x+w*0.95, y)); painter->drawLine(QLineF( x, y+w, x, y-w)); break; } case ssCrossCircle: { painter->drawEllipse(QPointF(x, y), w, w); painter->drawLine(QLineF(x-w*0.707, y-w*0.707, x+w*0.670, y+w*0.670)); painter->drawLine(QLineF(x-w*0.707, y+w*0.670, x+w*0.670, y-w*0.707)); break; } case ssPlusCircle: { painter->drawEllipse(QPointF(x, y), w, w); painter->drawLine(QLineF(x-w, y, x+w, y)); painter->drawLine(QLineF( x, y+w, x, y-w)); break; } case ssPeace: { painter->drawEllipse(QPointF(x, y), w, w); painter->drawLine(QLineF(x, y-w, x, y+w)); painter->drawLine(QLineF(x, y, x-w*0.707, y+w*0.707)); painter->drawLine(QLineF(x, y, x+w*0.707, y+w*0.707)); break; } case ssPixmap: { const double widthHalf = mPixmap.width()*0.5; const double heightHalf = mPixmap.height()*0.5; #if QT_VERSION < QT_VERSION_CHECK(4, 8, 0) const QRectF clipRect = painter->clipRegion().boundingRect().adjusted(-widthHalf, -heightHalf, widthHalf, heightHalf); #else const QRectF clipRect = painter->clipBoundingRect().adjusted(-widthHalf, -heightHalf, widthHalf, heightHalf); #endif if (clipRect.contains(x, y)) painter->drawPixmap(qRound(x-widthHalf), qRound(y-heightHalf), mPixmap); break; } case ssCustom: { QTransform oldTransform = painter->transform(); painter->translate(x, y); painter->scale(mSize/6.0, mSize/6.0); painter->drawPath(mCustomPath); painter->setTransform(oldTransform); break; } } } /* end of 'src/scatterstyle.cpp' */ /* including file 'src/plottable.cpp' */ /* modified 2021-03-29T02:30:44, size 38818 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPSelectionDecorator //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPSelectionDecorator \brief Controls how a plottable's data selection is drawn Each \ref QCPAbstractPlottable instance has one \ref QCPSelectionDecorator (accessible via \ref QCPAbstractPlottable::selectionDecorator) and uses it when drawing selected segments of its data. The selection decorator controls both pen (\ref setPen) and brush (\ref setBrush), as well as the scatter style (\ref setScatterStyle) if the plottable draws scatters. Since a \ref QCPScatterStyle is itself composed of different properties such as color shape and size, the decorator allows specifying exactly which of those properties shall be used for the selected data point, via \ref setUsedScatterProperties. A \ref QCPSelectionDecorator subclass instance can be passed to a plottable via \ref QCPAbstractPlottable::setSelectionDecorator, allowing greater customizability of the appearance of selected segments. Use \ref copyFrom to easily transfer the settings of one decorator to another one. This is especially useful since plottables take ownership of the passed selection decorator, and thus the same decorator instance can not be passed to multiple plottables. Selection decorators can also themselves perform drawing operations by reimplementing \ref drawDecoration, which is called by the plottable's draw method. The base class \ref QCPSelectionDecorator does not make use of this however. For example, \ref QCPSelectionDecoratorBracket draws brackets around selected data segments. */ /*! Creates a new QCPSelectionDecorator instance with default values */ QCPSelectionDecorator::QCPSelectionDecorator() : mPen(QColor(80, 80, 255), 2.5), mBrush(Qt::NoBrush), mUsedScatterProperties(QCPScatterStyle::spNone), mPlottable(nullptr) { } QCPSelectionDecorator::~QCPSelectionDecorator() { } /*! Sets the pen that will be used by the parent plottable to draw selected data segments. */ void QCPSelectionDecorator::setPen(const QPen &pen) { mPen = pen; } /*! Sets the brush that will be used by the parent plottable to draw selected data segments. */ void QCPSelectionDecorator::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the scatter style that will be used by the parent plottable to draw scatters in selected data segments. \a usedProperties specifies which parts of the passed \a scatterStyle will be used by the plottable. The used properties can also be changed via \ref setUsedScatterProperties. */ void QCPSelectionDecorator::setScatterStyle(const QCPScatterStyle &scatterStyle, QCPScatterStyle::ScatterProperties usedProperties) { mScatterStyle = scatterStyle; setUsedScatterProperties(usedProperties); } /*! Use this method to define which properties of the scatter style (set via \ref setScatterStyle) will be used for selected data segments. All properties of the scatter style that are not specified in \a properties will remain as specified in the plottable's original scatter style. \see QCPScatterStyle::ScatterProperty */ void QCPSelectionDecorator::setUsedScatterProperties(const QCPScatterStyle::ScatterProperties &properties) { mUsedScatterProperties = properties; } /*! Sets the pen of \a painter to the pen of this selection decorator. \see applyBrush, getFinalScatterStyle */ void QCPSelectionDecorator::applyPen(QCPPainter *painter) const { painter->setPen(mPen); } /*! Sets the brush of \a painter to the brush of this selection decorator. \see applyPen, getFinalScatterStyle */ void QCPSelectionDecorator::applyBrush(QCPPainter *painter) const { painter->setBrush(mBrush); } /*! Returns the scatter style that the parent plottable shall use for selected scatter points. The plottable's original (unselected) scatter style must be passed as \a unselectedStyle. Depending on the setting of \ref setUsedScatterProperties, the returned scatter style is a mixture of this selecion decorator's scatter style (\ref setScatterStyle), and \a unselectedStyle. \see applyPen, applyBrush, setScatterStyle */ QCPScatterStyle QCPSelectionDecorator::getFinalScatterStyle(const QCPScatterStyle &unselectedStyle) const { QCPScatterStyle result(unselectedStyle); result.setFromOther(mScatterStyle, mUsedScatterProperties); // if style shall inherit pen from plottable (has no own pen defined), give it the selected // plottable pen explicitly, so it doesn't use the unselected plottable pen when used in the // plottable: if (!result.isPenDefined()) result.setPen(mPen); return result; } /*! Copies all properties (e.g. color, fill, scatter style) of the \a other selection decorator to this selection decorator. */ void QCPSelectionDecorator::copyFrom(const QCPSelectionDecorator *other) { setPen(other->pen()); setBrush(other->brush()); setScatterStyle(other->scatterStyle(), other->usedScatterProperties()); } /*! This method is called by all plottables' draw methods to allow custom selection decorations to be drawn. Use the passed \a painter to perform the drawing operations. \a selection carries the data selection for which the decoration shall be drawn. The default base class implementation of \ref QCPSelectionDecorator has no special decoration, so this method does nothing. */ void QCPSelectionDecorator::drawDecoration(QCPPainter *painter, QCPDataSelection selection) { Q_UNUSED(painter) Q_UNUSED(selection) } /*! \internal This method is called as soon as a selection decorator is associated with a plottable, by a call to \ref QCPAbstractPlottable::setSelectionDecorator. This way the selection decorator can obtain a pointer to the plottable that uses it (e.g. to access data points via the \ref QCPAbstractPlottable::interface1D interface). If the selection decorator was already added to a different plottable before, this method aborts the registration and returns false. */ bool QCPSelectionDecorator::registerWithPlottable(QCPAbstractPlottable *plottable) { if (!mPlottable) { mPlottable = plottable; return true; } else { qDebug() << Q_FUNC_INFO << "This selection decorator is already registered with plottable:" << reinterpret_cast(mPlottable); return false; } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAbstractPlottable //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAbstractPlottable \brief The abstract base class for all data representing objects in a plot. It defines a very basic interface like name, pen, brush, visibility etc. Since this class is abstract, it can't be instantiated. Use one of the subclasses or create a subclass yourself to create new ways of displaying data (see "Creating own plottables" below). Plottables that display one-dimensional data (i.e. data points have a single key dimension and one or multiple values at each key) are based off of the template subclass \ref QCPAbstractPlottable1D, see details there. All further specifics are in the subclasses, for example: \li A normal graph with possibly a line and/or scatter points \ref QCPGraph (typically created with \ref QCustomPlot::addGraph) \li A parametric curve: \ref QCPCurve \li A bar chart: \ref QCPBars \li A statistical box plot: \ref QCPStatisticalBox \li A color encoded two-dimensional map: \ref QCPColorMap \li An OHLC/Candlestick chart: \ref QCPFinancial \section plottables-subclassing Creating own plottables Subclassing directly from QCPAbstractPlottable is only recommended if you wish to display two-dimensional data like \ref QCPColorMap, i.e. two logical key dimensions and one (or more) data dimensions. If you want to display data with only one logical key dimension, you should rather derive from \ref QCPAbstractPlottable1D. If subclassing QCPAbstractPlottable directly, these are the pure virtual functions you must implement: \li \ref selectTest \li \ref draw \li \ref drawLegendIcon \li \ref getKeyRange \li \ref getValueRange See the documentation of those functions for what they need to do. For drawing your plot, you can use the \ref coordsToPixels functions to translate a point in plot coordinates to pixel coordinates. This function is quite convenient, because it takes the orientation of the key and value axes into account for you (x and y are swapped when the key axis is vertical and the value axis horizontal). If you are worried about performance (i.e. you need to translate many points in a loop like QCPGraph), you can directly use \ref QCPAxis::coordToPixel. However, you must then take care about the orientation of the axis yourself. Here are some important members you inherit from QCPAbstractPlottable:
QCustomPlot *\b mParentPlot A pointer to the parent QCustomPlot instance. The parent plot is inferred from the axes that are passed in the constructor.
QString \b mName The name of the plottable.
QPen \b mPen The generic pen of the plottable. You should use this pen for the most prominent data representing lines in the plottable (e.g QCPGraph uses this pen for its graph lines and scatters)
QBrush \b mBrush The generic brush of the plottable. You should use this brush for the most prominent fillable structures in the plottable (e.g. QCPGraph uses this brush to control filling under the graph)
QPointer<\ref QCPAxis> \b mKeyAxis, \b mValueAxis The key and value axes this plottable is attached to. Call their QCPAxis::coordToPixel functions to translate coordinates to pixels in either the key or value dimension. Make sure to check whether the pointer is \c nullptr before using it. If one of the axes is null, don't draw the plottable.
\ref QCPSelectionDecorator \b mSelectionDecorator The currently set selection decorator which specifies how selected data of the plottable shall be drawn and decorated. When drawing your data, you must consult this decorator for the appropriate pen/brush before drawing unselected/selected data segments. Finally, you should call its \ref QCPSelectionDecorator::drawDecoration method at the end of your \ref draw implementation.
\ref QCP::SelectionType \b mSelectable In which composition, if at all, this plottable's data may be selected. Enforcing this setting on the data selection is done by QCPAbstractPlottable automatically.
\ref QCPDataSelection \b mSelection Holds the current selection state of the plottable's data, i.e. the selected data ranges (\ref QCPDataRange).
*/ /* start of documentation of inline functions */ /*! \fn QCPSelectionDecorator *QCPAbstractPlottable::selectionDecorator() const Provides access to the selection decorator of this plottable. The selection decorator controls how selected data ranges are drawn (e.g. their pen color and fill), see \ref QCPSelectionDecorator for details. If you wish to use an own \ref QCPSelectionDecorator subclass, pass an instance of it to \ref setSelectionDecorator. */ /*! \fn bool QCPAbstractPlottable::selected() const Returns true if there are any data points of the plottable currently selected. Use \ref selection to retrieve the current \ref QCPDataSelection. */ /*! \fn QCPDataSelection QCPAbstractPlottable::selection() const Returns a \ref QCPDataSelection encompassing all the data points that are currently selected on this plottable. \see selected, setSelection, setSelectable */ /*! \fn virtual QCPPlottableInterface1D *QCPAbstractPlottable::interface1D() If this plottable is a one-dimensional plottable, i.e. it implements the \ref QCPPlottableInterface1D, returns the \a this pointer with that type. Otherwise (e.g. in the case of a \ref QCPColorMap) returns zero. You can use this method to gain read access to data coordinates while holding a pointer to the abstract base class only. */ /* end of documentation of inline functions */ /* start of documentation of pure virtual functions */ /*! \fn void QCPAbstractPlottable::drawLegendIcon(QCPPainter *painter, const QRect &rect) const = 0 \internal called by QCPLegend::draw (via QCPPlottableLegendItem::draw) to create a graphical representation of this plottable inside \a rect, next to the plottable name. The passed \a painter has its cliprect set to \a rect, so painting outside of \a rect won't appear outside the legend icon border. */ /*! \fn QCPRange QCPAbstractPlottable::getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain) const = 0 Returns the coordinate range that all data in this plottable span in the key axis dimension. For logarithmic plots, one can set \a inSignDomain to either \ref QCP::sdNegative or \ref QCP::sdPositive in order to restrict the returned range to that sign domain. E.g. when only negative range is wanted, set \a inSignDomain to \ref QCP::sdNegative and all positive points will be ignored for range calculation. For no restriction, just set \a inSignDomain to \ref QCP::sdBoth (default). \a foundRange is an output parameter that indicates whether a range could be found or not. If this is false, you shouldn't use the returned range (e.g. no points in data). Note that \a foundRange is not the same as \ref QCPRange::validRange, since the range returned by this function may have size zero (e.g. when there is only one data point). In this case \a foundRange would return true, but the returned range is not a valid range in terms of \ref QCPRange::validRange. \see rescaleAxes, getValueRange */ /*! \fn QCPRange QCPAbstractPlottable::getValueRange(bool &foundRange, QCP::SignDomain inSignDomain, const QCPRange &inKeyRange) const = 0 Returns the coordinate range that the data points in the specified key range (\a inKeyRange) span in the value axis dimension. For logarithmic plots, one can set \a inSignDomain to either \ref QCP::sdNegative or \ref QCP::sdPositive in order to restrict the returned range to that sign domain. E.g. when only negative range is wanted, set \a inSignDomain to \ref QCP::sdNegative and all positive points will be ignored for range calculation. For no restriction, just set \a inSignDomain to \ref QCP::sdBoth (default). \a foundRange is an output parameter that indicates whether a range could be found or not. If this is false, you shouldn't use the returned range (e.g. no points in data). If \a inKeyRange has both lower and upper bound set to zero (is equal to QCPRange()), all data points are considered, without any restriction on the keys. Note that \a foundRange is not the same as \ref QCPRange::validRange, since the range returned by this function may have size zero (e.g. when there is only one data point). In this case \a foundRange would return true, but the returned range is not a valid range in terms of \ref QCPRange::validRange. \see rescaleAxes, getKeyRange */ /* end of documentation of pure virtual functions */ /* start of documentation of signals */ /*! \fn void QCPAbstractPlottable::selectionChanged(bool selected) This signal is emitted when the selection state of this plottable has changed, either by user interaction or by a direct call to \ref setSelection. The parameter \a selected indicates whether there are any points selected or not. \see selectionChanged(const QCPDataSelection &selection) */ /*! \fn void QCPAbstractPlottable::selectionChanged(const QCPDataSelection &selection) This signal is emitted when the selection state of this plottable has changed, either by user interaction or by a direct call to \ref setSelection. The parameter \a selection holds the currently selected data ranges. \see selectionChanged(bool selected) */ /*! \fn void QCPAbstractPlottable::selectableChanged(QCP::SelectionType selectable); This signal is emitted when the selectability of this plottable has changed. \see setSelectable */ /* end of documentation of signals */ /*! Constructs an abstract plottable which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and have perpendicular orientations. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. Since QCPAbstractPlottable is an abstract class that defines the basic interface to plottables, it can't be directly instantiated. You probably want one of the subclasses like \ref QCPGraph or \ref QCPCurve instead. */ QCPAbstractPlottable::QCPAbstractPlottable(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPLayerable(keyAxis->parentPlot(), QString(), keyAxis->axisRect()), mName(), mAntialiasedFill(true), mAntialiasedScatters(true), mPen(Qt::black), mBrush(Qt::NoBrush), mKeyAxis(keyAxis), mValueAxis(valueAxis), mSelectable(QCP::stWhole), mSelectionDecorator(nullptr) { if (keyAxis->parentPlot() != valueAxis->parentPlot()) qDebug() << Q_FUNC_INFO << "Parent plot of keyAxis is not the same as that of valueAxis."; if (keyAxis->orientation() == valueAxis->orientation()) qDebug() << Q_FUNC_INFO << "keyAxis and valueAxis must be orthogonal to each other."; mParentPlot->registerPlottable(this); setSelectionDecorator(new QCPSelectionDecorator); } QCPAbstractPlottable::~QCPAbstractPlottable() { if (mSelectionDecorator) { delete mSelectionDecorator; mSelectionDecorator = nullptr; } } /*! The name is the textual representation of this plottable as it is displayed in the legend (\ref QCPLegend). It may contain any UTF-8 characters, including newlines. */ void QCPAbstractPlottable::setName(const QString &name) { mName = name; } /*! Sets whether fills of this plottable are drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAbstractPlottable::setAntialiasedFill(bool enabled) { mAntialiasedFill = enabled; } /*! Sets whether the scatter symbols of this plottable are drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAbstractPlottable::setAntialiasedScatters(bool enabled) { mAntialiasedScatters = enabled; } /*! The pen is used to draw basic lines that make up the plottable representation in the plot. For example, the \ref QCPGraph subclass draws its graph lines with this pen. \see setBrush */ void QCPAbstractPlottable::setPen(const QPen &pen) { mPen = pen; } /*! The brush is used to draw basic fills of the plottable representation in the plot. The Fill can be a color, gradient or texture, see the usage of QBrush. For example, the \ref QCPGraph subclass draws the fill under the graph with this brush, when it's not set to Qt::NoBrush. \see setPen */ void QCPAbstractPlottable::setBrush(const QBrush &brush) { mBrush = brush; } /*! The key axis of a plottable can be set to any axis of a QCustomPlot, as long as it is orthogonal to the plottable's value axis. This function performs no checks to make sure this is the case. The typical mathematical choice is to use the x-axis (QCustomPlot::xAxis) as key axis and the y-axis (QCustomPlot::yAxis) as value axis. Normally, the key and value axes are set in the constructor of the plottable (or \ref QCustomPlot::addGraph when working with QCPGraphs through the dedicated graph interface). \see setValueAxis */ void QCPAbstractPlottable::setKeyAxis(QCPAxis *axis) { mKeyAxis = axis; } /*! The value axis of a plottable can be set to any axis of a QCustomPlot, as long as it is orthogonal to the plottable's key axis. This function performs no checks to make sure this is the case. The typical mathematical choice is to use the x-axis (QCustomPlot::xAxis) as key axis and the y-axis (QCustomPlot::yAxis) as value axis. Normally, the key and value axes are set in the constructor of the plottable (or \ref QCustomPlot::addGraph when working with QCPGraphs through the dedicated graph interface). \see setKeyAxis */ void QCPAbstractPlottable::setValueAxis(QCPAxis *axis) { mValueAxis = axis; } /*! Sets which data ranges of this plottable are selected. Selected data ranges are drawn differently (e.g. color) in the plot. This can be controlled via the selection decorator (see \ref selectionDecorator). The entire selection mechanism for plottables is handled automatically when \ref QCustomPlot::setInteractions contains iSelectPlottables. You only need to call this function when you wish to change the selection state programmatically. Using \ref setSelectable you can further specify for each plottable whether and to which granularity it is selectable. If \a selection is not compatible with the current \ref QCP::SelectionType set via \ref setSelectable, the resulting selection will be adjusted accordingly (see \ref QCPDataSelection::enforceType). emits the \ref selectionChanged signal when \a selected is different from the previous selection state. \see setSelectable, selectTest */ void QCPAbstractPlottable::setSelection(QCPDataSelection selection) { selection.enforceType(mSelectable); if (mSelection != selection) { mSelection = selection; emit selectionChanged(selected()); emit selectionChanged(mSelection); } } /*! Use this method to set an own QCPSelectionDecorator (subclass) instance. This allows you to customize the visual representation of selected data ranges further than by using the default QCPSelectionDecorator. The plottable takes ownership of the \a decorator. The currently set decorator can be accessed via \ref selectionDecorator. */ void QCPAbstractPlottable::setSelectionDecorator(QCPSelectionDecorator *decorator) { if (decorator) { if (decorator->registerWithPlottable(this)) { delete mSelectionDecorator; // delete old decorator if necessary mSelectionDecorator = decorator; } } else if (mSelectionDecorator) // just clear decorator { delete mSelectionDecorator; mSelectionDecorator = nullptr; } } /*! Sets whether and to which granularity this plottable can be selected. A selection can happen by clicking on the QCustomPlot surface (When \ref QCustomPlot::setInteractions contains \ref QCP::iSelectPlottables), by dragging a selection rect (When \ref QCustomPlot::setSelectionRectMode is \ref QCP::srmSelect), or programmatically by calling \ref setSelection. \see setSelection, QCP::SelectionType */ void QCPAbstractPlottable::setSelectable(QCP::SelectionType selectable) { if (mSelectable != selectable) { mSelectable = selectable; QCPDataSelection oldSelection = mSelection; mSelection.enforceType(mSelectable); emit selectableChanged(mSelectable); if (mSelection != oldSelection) { emit selectionChanged(selected()); emit selectionChanged(mSelection); } } } /*! Convenience function for transforming a key/value pair to pixels on the QCustomPlot surface, taking the orientations of the axes associated with this plottable into account (e.g. whether key represents x or y). \a key and \a value are transformed to the coodinates in pixels and are written to \a x and \a y. \see pixelsToCoords, QCPAxis::coordToPixel */ void QCPAbstractPlottable::coordsToPixels(double key, double value, double &x, double &y) const { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (keyAxis->orientation() == Qt::Horizontal) { x = keyAxis->coordToPixel(key); y = valueAxis->coordToPixel(value); } else { y = keyAxis->coordToPixel(key); x = valueAxis->coordToPixel(value); } } /*! \overload Transforms the given \a key and \a value to pixel coordinates and returns them in a QPointF. */ const QPointF QCPAbstractPlottable::coordsToPixels(double key, double value) const { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); } if (keyAxis->orientation() == Qt::Horizontal) return QPointF(keyAxis->coordToPixel(key), valueAxis->coordToPixel(value)); else return QPointF(valueAxis->coordToPixel(value), keyAxis->coordToPixel(key)); } /*! Convenience function for transforming a x/y pixel pair on the QCustomPlot surface to plot coordinates, taking the orientations of the axes associated with this plottable into account (e.g. whether key represents x or y). \a x and \a y are transformed to the plot coodinates and are written to \a key and \a value. \see coordsToPixels, QCPAxis::coordToPixel */ void QCPAbstractPlottable::pixelsToCoords(double x, double y, double &key, double &value) const { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (keyAxis->orientation() == Qt::Horizontal) { key = keyAxis->pixelToCoord(x); value = valueAxis->pixelToCoord(y); } else { key = keyAxis->pixelToCoord(y); value = valueAxis->pixelToCoord(x); } } /*! \overload Returns the pixel input \a pixelPos as plot coordinates \a key and \a value. */ void QCPAbstractPlottable::pixelsToCoords(const QPointF &pixelPos, double &key, double &value) const { pixelsToCoords(pixelPos.x(), pixelPos.y(), key, value); } /*! Rescales the key and value axes associated with this plottable to contain all displayed data, so the whole plottable is visible. If the scaling of an axis is logarithmic, rescaleAxes will make sure not to rescale to an illegal range i.e. a range containing different signs and/or zero. Instead it will stay in the current sign domain and ignore all parts of the plottable that lie outside of that domain. \a onlyEnlarge makes sure the ranges are only expanded, never reduced. So it's possible to show multiple plottables in their entirety by multiple calls to rescaleAxes where the first call has \a onlyEnlarge set to false (the default), and all subsequent set to true. \see rescaleKeyAxis, rescaleValueAxis, QCustomPlot::rescaleAxes, QCPAxis::rescale */ void QCPAbstractPlottable::rescaleAxes(bool onlyEnlarge) const { rescaleKeyAxis(onlyEnlarge); rescaleValueAxis(onlyEnlarge); } /*! Rescales the key axis of the plottable so the whole plottable is visible. See \ref rescaleAxes for detailed behaviour. */ void QCPAbstractPlottable::rescaleKeyAxis(bool onlyEnlarge) const { QCPAxis *keyAxis = mKeyAxis.data(); if (!keyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; } QCP::SignDomain signDomain = QCP::sdBoth; if (keyAxis->scaleType() == QCPAxis::stLogarithmic) signDomain = (keyAxis->range().upper < 0 ? QCP::sdNegative : QCP::sdPositive); bool foundRange; QCPRange newRange = getKeyRange(foundRange, signDomain); if (foundRange) { if (onlyEnlarge) newRange.expand(keyAxis->range()); if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable { double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason if (keyAxis->scaleType() == QCPAxis::stLinear) { newRange.lower = center-keyAxis->range().size()/2.0; newRange.upper = center+keyAxis->range().size()/2.0; } else // scaleType() == stLogarithmic { newRange.lower = center/qSqrt(keyAxis->range().upper/keyAxis->range().lower); newRange.upper = center*qSqrt(keyAxis->range().upper/keyAxis->range().lower); } } keyAxis->setRange(newRange); } } /*! Rescales the value axis of the plottable so the whole plottable is visible. If \a inKeyRange is set to true, only the data points which are in the currently visible key axis range are considered. Returns true if the axis was actually scaled. This might not be the case if this plottable has an invalid range, e.g. because it has no data points. See \ref rescaleAxes for detailed behaviour. */ void QCPAbstractPlottable::rescaleValueAxis(bool onlyEnlarge, bool inKeyRange) const { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } QCP::SignDomain signDomain = QCP::sdBoth; if (valueAxis->scaleType() == QCPAxis::stLogarithmic) signDomain = (valueAxis->range().upper < 0 ? QCP::sdNegative : QCP::sdPositive); bool foundRange; QCPRange newRange = getValueRange(foundRange, signDomain, inKeyRange ? keyAxis->range() : QCPRange()); if (foundRange) { if (onlyEnlarge) newRange.expand(valueAxis->range()); if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable { double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason if (valueAxis->scaleType() == QCPAxis::stLinear) { newRange.lower = center-valueAxis->range().size()/2.0; newRange.upper = center+valueAxis->range().size()/2.0; } else // scaleType() == stLogarithmic { newRange.lower = center/qSqrt(valueAxis->range().upper/valueAxis->range().lower); newRange.upper = center*qSqrt(valueAxis->range().upper/valueAxis->range().lower); } } valueAxis->setRange(newRange); } } /*! \overload Adds this plottable to the specified \a legend. Creates a QCPPlottableLegendItem which is inserted into the legend. Returns true on success, i.e. when the legend exists and a legend item associated with this plottable isn't already in the legend. If the plottable needs a more specialized representation in the legend, you can create a corresponding subclass of \ref QCPPlottableLegendItem and add it to the legend manually instead of calling this method. \see removeFromLegend, QCPLegend::addItem */ bool QCPAbstractPlottable::addToLegend(QCPLegend *legend) { if (!legend) { qDebug() << Q_FUNC_INFO << "passed legend is null"; return false; } if (legend->parentPlot() != mParentPlot) { qDebug() << Q_FUNC_INFO << "passed legend isn't in the same QCustomPlot as this plottable"; return false; } if (!legend->hasItemWithPlottable(this)) { legend->addItem(new QCPPlottableLegendItem(legend, this)); return true; } else return false; } /*! \overload Adds this plottable to the legend of the parent QCustomPlot (\ref QCustomPlot::legend). \see removeFromLegend */ bool QCPAbstractPlottable::addToLegend() { if (!mParentPlot || !mParentPlot->legend) return false; else return addToLegend(mParentPlot->legend); } /*! \overload Removes the plottable from the specifed \a legend. This means the \ref QCPPlottableLegendItem that is associated with this plottable is removed. Returns true on success, i.e. if the legend exists and a legend item associated with this plottable was found and removed. \see addToLegend, QCPLegend::removeItem */ bool QCPAbstractPlottable::removeFromLegend(QCPLegend *legend) const { if (!legend) { qDebug() << Q_FUNC_INFO << "passed legend is null"; return false; } if (QCPPlottableLegendItem *lip = legend->itemWithPlottable(this)) return legend->removeItem(lip); else return false; } /*! \overload Removes the plottable from the legend of the parent QCustomPlot. \see addToLegend */ bool QCPAbstractPlottable::removeFromLegend() const { if (!mParentPlot || !mParentPlot->legend) return false; else return removeFromLegend(mParentPlot->legend); } /* inherits documentation from base class */ QRect QCPAbstractPlottable::clipRect() const { if (mKeyAxis && mValueAxis) return mKeyAxis.data()->axisRect()->rect() & mValueAxis.data()->axisRect()->rect(); else return {}; } /* inherits documentation from base class */ QCP::Interaction QCPAbstractPlottable::selectionCategory() const { return QCP::iSelectPlottables; } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing plottable lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set with \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. \seebaseclassmethod \see setAntialiased, applyFillAntialiasingHint, applyScattersAntialiasingHint */ void QCPAbstractPlottable::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aePlottables); } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing plottable fills. This function takes into account the local setting of the antialiasing flag as well as the overrides set with \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased, applyDefaultAntialiasingHint, applyScattersAntialiasingHint */ void QCPAbstractPlottable::applyFillAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiasedFill, QCP::aeFills); } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing plottable scatter points. This function takes into account the local setting of the antialiasing flag as well as the overrides set with \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased, applyFillAntialiasingHint, applyDefaultAntialiasingHint */ void QCPAbstractPlottable::applyScattersAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiasedScatters, QCP::aeScatters); } /* inherits documentation from base class */ void QCPAbstractPlottable::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) { Q_UNUSED(event) if (mSelectable != QCP::stNone) { QCPDataSelection newSelection = details.value(); QCPDataSelection selectionBefore = mSelection; if (additive) { if (mSelectable == QCP::stWhole) // in whole selection mode, we toggle to no selection even if currently unselected point was hit { if (selected()) setSelection(QCPDataSelection()); else setSelection(newSelection); } else // in all other selection modes we toggle selections of homogeneously selected/unselected segments { if (mSelection.contains(newSelection)) // if entire newSelection is already selected, toggle selection setSelection(mSelection-newSelection); else setSelection(mSelection+newSelection); } } else setSelection(newSelection); if (selectionStateChanged) *selectionStateChanged = mSelection != selectionBefore; } } /* inherits documentation from base class */ void QCPAbstractPlottable::deselectEvent(bool *selectionStateChanged) { if (mSelectable != QCP::stNone) { QCPDataSelection selectionBefore = mSelection; setSelection(QCPDataSelection()); if (selectionStateChanged) *selectionStateChanged = mSelection != selectionBefore; } } /* end of 'src/plottable.cpp' */ /* including file 'src/item.cpp' */ /* modified 2021-03-29T02:30:44, size 49486 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemAnchor //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemAnchor \brief An anchor of an item to which positions can be attached to. An item (QCPAbstractItem) may have one or more anchors. Unlike QCPItemPosition, an anchor doesn't control anything on its item, but provides a way to tie other items via their positions to the anchor. For example, a QCPItemRect is defined by its positions \a topLeft and \a bottomRight. Additionally it has various anchors like \a top, \a topRight or \a bottomLeft etc. So you can attach the \a start (which is a QCPItemPosition) of a QCPItemLine to one of the anchors by calling QCPItemPosition::setParentAnchor on \a start, passing the wanted anchor of the QCPItemRect. This way the start of the line will now always follow the respective anchor location on the rect item. Note that QCPItemPosition derives from QCPItemAnchor, so every position can also serve as an anchor to other positions. To learn how to provide anchors in your own item subclasses, see the subclassing section of the QCPAbstractItem documentation. */ /* start documentation of inline functions */ /*! \fn virtual QCPItemPosition *QCPItemAnchor::toQCPItemPosition() Returns \c nullptr if this instance is merely a QCPItemAnchor, and a valid pointer of type QCPItemPosition* if it actually is a QCPItemPosition (which is a subclass of QCPItemAnchor). This safe downcast functionality could also be achieved with a dynamic_cast. However, QCustomPlot avoids dynamic_cast to work with projects that don't have RTTI support enabled (e.g. -fno-rtti flag with gcc compiler). */ /* end documentation of inline functions */ /*! Creates a new QCPItemAnchor. You shouldn't create QCPItemAnchor instances directly, even if you want to make a new item subclass. Use \ref QCPAbstractItem::createAnchor instead, as explained in the subclassing section of the QCPAbstractItem documentation. */ QCPItemAnchor::QCPItemAnchor(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString &name, int anchorId) : mName(name), mParentPlot(parentPlot), mParentItem(parentItem), mAnchorId(anchorId) { } QCPItemAnchor::~QCPItemAnchor() { // unregister as parent at children: foreach (QCPItemPosition *child, mChildrenX.values()) { if (child->parentAnchorX() == this) child->setParentAnchorX(nullptr); // this acts back on this anchor and child removes itself from mChildrenX } foreach (QCPItemPosition *child, mChildrenY.values()) { if (child->parentAnchorY() == this) child->setParentAnchorY(nullptr); // this acts back on this anchor and child removes itself from mChildrenY } } /*! Returns the final absolute pixel position of the QCPItemAnchor on the QCustomPlot surface. The pixel information is internally retrieved via QCPAbstractItem::anchorPixelPosition of the parent item, QCPItemAnchor is just an intermediary. */ QPointF QCPItemAnchor::pixelPosition() const { if (mParentItem) { if (mAnchorId > -1) { return mParentItem->anchorPixelPosition(mAnchorId); } else { qDebug() << Q_FUNC_INFO << "no valid anchor id set:" << mAnchorId; return {}; } } else { qDebug() << Q_FUNC_INFO << "no parent item set"; return {}; } } /*! \internal Adds \a pos to the childX list of this anchor, which keeps track of which children use this anchor as parent anchor for the respective coordinate. This is necessary to notify the children prior to destruction of the anchor. Note that this function does not change the parent setting in \a pos. */ void QCPItemAnchor::addChildX(QCPItemPosition *pos) { if (!mChildrenX.contains(pos)) mChildrenX.insert(pos); else qDebug() << Q_FUNC_INFO << "provided pos is child already" << reinterpret_cast(pos); } /*! \internal Removes \a pos from the childX list of this anchor. Note that this function does not change the parent setting in \a pos. */ void QCPItemAnchor::removeChildX(QCPItemPosition *pos) { if (!mChildrenX.remove(pos)) qDebug() << Q_FUNC_INFO << "provided pos isn't child" << reinterpret_cast(pos); } /*! \internal Adds \a pos to the childY list of this anchor, which keeps track of which children use this anchor as parent anchor for the respective coordinate. This is necessary to notify the children prior to destruction of the anchor. Note that this function does not change the parent setting in \a pos. */ void QCPItemAnchor::addChildY(QCPItemPosition *pos) { if (!mChildrenY.contains(pos)) mChildrenY.insert(pos); else qDebug() << Q_FUNC_INFO << "provided pos is child already" << reinterpret_cast(pos); } /*! \internal Removes \a pos from the childY list of this anchor. Note that this function does not change the parent setting in \a pos. */ void QCPItemAnchor::removeChildY(QCPItemPosition *pos) { if (!mChildrenY.remove(pos)) qDebug() << Q_FUNC_INFO << "provided pos isn't child" << reinterpret_cast(pos); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemPosition //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemPosition \brief Manages the position of an item. Every item has at least one public QCPItemPosition member pointer which provides ways to position the item on the QCustomPlot surface. Some items have multiple positions, for example QCPItemRect has two: \a topLeft and \a bottomRight. QCPItemPosition has a type (\ref PositionType) that can be set with \ref setType. This type defines how coordinates passed to \ref setCoords are to be interpreted, e.g. as absolute pixel coordinates, as plot coordinates of certain axes (\ref QCPItemPosition::setAxes), as fractions of the axis rect (\ref QCPItemPosition::setAxisRect), etc. For more advanced plots it is also possible to assign different types per X/Y coordinate of the position (see \ref setTypeX, \ref setTypeY). This way an item could be positioned for example at a fixed pixel distance from the top in the Y direction, while following a plot coordinate in the X direction. A QCPItemPosition may have a parent QCPItemAnchor, see \ref setParentAnchor. This way you can tie multiple items together. If the QCPItemPosition has a parent, its coordinates (\ref setCoords) are considered to be absolute pixels in the reference frame of the parent anchor, where (0, 0) means directly ontop of the parent anchor. For example, You could attach the \a start position of a QCPItemLine to the \a bottom anchor of a QCPItemText to make the starting point of the line always be centered under the text label, no matter where the text is moved to. For more advanced plots, it is possible to assign different parent anchors per X/Y coordinate of the position, see \ref setParentAnchorX, \ref setParentAnchorY. This way an item could follow another item in the X direction but stay at a fixed position in the Y direction. Or even follow item A in X, and item B in Y. Note that every QCPItemPosition inherits from QCPItemAnchor and thus can itself be used as parent anchor for other positions. To set the apparent pixel position on the QCustomPlot surface directly, use \ref setPixelPosition. This works no matter what type this QCPItemPosition is or what parent-child situation it is in, as \ref setPixelPosition transforms the coordinates appropriately, to make the position appear at the specified pixel values. */ /* start documentation of inline functions */ /*! \fn QCPItemPosition::PositionType *QCPItemPosition::type() const Returns the current position type. If different types were set for X and Y (\ref setTypeX, \ref setTypeY), this method returns the type of the X coordinate. In that case rather use \a typeX() and \a typeY(). \see setType */ /*! \fn QCPItemAnchor *QCPItemPosition::parentAnchor() const Returns the current parent anchor. If different parent anchors were set for X and Y (\ref setParentAnchorX, \ref setParentAnchorY), this method returns the parent anchor of the Y coordinate. In that case rather use \a parentAnchorX() and \a parentAnchorY(). \see setParentAnchor */ /* end documentation of inline functions */ /*! Creates a new QCPItemPosition. You shouldn't create QCPItemPosition instances directly, even if you want to make a new item subclass. Use \ref QCPAbstractItem::createPosition instead, as explained in the subclassing section of the QCPAbstractItem documentation. */ QCPItemPosition::QCPItemPosition(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString &name) : QCPItemAnchor(parentPlot, parentItem, name), mPositionTypeX(ptAbsolute), mPositionTypeY(ptAbsolute), mKey(0), mValue(0), mParentAnchorX(nullptr), mParentAnchorY(nullptr) { } QCPItemPosition::~QCPItemPosition() { // unregister as parent at children: // Note: this is done in ~QCPItemAnchor again, but it's important QCPItemPosition does it itself, because only then // the setParentAnchor(0) call the correct QCPItemPosition::pixelPosition function instead of QCPItemAnchor::pixelPosition foreach (QCPItemPosition *child, mChildrenX.values()) { if (child->parentAnchorX() == this) child->setParentAnchorX(nullptr); // this acts back on this anchor and child removes itself from mChildrenX } foreach (QCPItemPosition *child, mChildrenY.values()) { if (child->parentAnchorY() == this) child->setParentAnchorY(nullptr); // this acts back on this anchor and child removes itself from mChildrenY } // unregister as child in parent: if (mParentAnchorX) mParentAnchorX->removeChildX(this); if (mParentAnchorY) mParentAnchorY->removeChildY(this); } /* can't make this a header inline function, because QPointer breaks with forward declared types, see QTBUG-29588 */ QCPAxisRect *QCPItemPosition::axisRect() const { return mAxisRect.data(); } /*! Sets the type of the position. The type defines how the coordinates passed to \ref setCoords should be handled and how the QCPItemPosition should behave in the plot. The possible values for \a type can be separated in two main categories: \li The position is regarded as a point in plot coordinates. This corresponds to \ref ptPlotCoords and requires two axes that define the plot coordinate system. They can be specified with \ref setAxes. By default, the QCustomPlot's x- and yAxis are used. \li The position is fixed on the QCustomPlot surface, i.e. independent of axis ranges. This corresponds to all other types, i.e. \ref ptAbsolute, \ref ptViewportRatio and \ref ptAxisRectRatio. They differ only in the way the absolute position is described, see the documentation of \ref PositionType for details. For \ref ptAxisRectRatio, note that you can specify the axis rect with \ref setAxisRect. By default this is set to the main axis rect. Note that the position type \ref ptPlotCoords is only available (and sensible) when the position has no parent anchor (\ref setParentAnchor). If the type is changed, the apparent pixel position on the plot is preserved. This means the coordinates as retrieved with coords() and set with \ref setCoords may change in the process. This method sets the type for both X and Y directions. It is also possible to set different types for X and Y, see \ref setTypeX, \ref setTypeY. */ void QCPItemPosition::setType(QCPItemPosition::PositionType type) { setTypeX(type); setTypeY(type); } /*! This method sets the position type of the X coordinate to \a type. For a detailed description of what a position type is, see the documentation of \ref setType. \see setType, setTypeY */ void QCPItemPosition::setTypeX(QCPItemPosition::PositionType type) { if (mPositionTypeX != type) { // if switching from or to coordinate type that isn't valid (e.g. because axes or axis rect // were deleted), don't try to recover the pixelPosition() because it would output a qDebug warning. bool retainPixelPosition = true; if ((mPositionTypeX == ptPlotCoords || type == ptPlotCoords) && (!mKeyAxis || !mValueAxis)) retainPixelPosition = false; if ((mPositionTypeX == ptAxisRectRatio || type == ptAxisRectRatio) && (!mAxisRect)) retainPixelPosition = false; QPointF pixel; if (retainPixelPosition) pixel = pixelPosition(); mPositionTypeX = type; if (retainPixelPosition) setPixelPosition(pixel); } } /*! This method sets the position type of the Y coordinate to \a type. For a detailed description of what a position type is, see the documentation of \ref setType. \see setType, setTypeX */ void QCPItemPosition::setTypeY(QCPItemPosition::PositionType type) { if (mPositionTypeY != type) { // if switching from or to coordinate type that isn't valid (e.g. because axes or axis rect // were deleted), don't try to recover the pixelPosition() because it would output a qDebug warning. bool retainPixelPosition = true; if ((mPositionTypeY == ptPlotCoords || type == ptPlotCoords) && (!mKeyAxis || !mValueAxis)) retainPixelPosition = false; if ((mPositionTypeY == ptAxisRectRatio || type == ptAxisRectRatio) && (!mAxisRect)) retainPixelPosition = false; QPointF pixel; if (retainPixelPosition) pixel = pixelPosition(); mPositionTypeY = type; if (retainPixelPosition) setPixelPosition(pixel); } } /*! Sets the parent of this QCPItemPosition to \a parentAnchor. This means the position will now follow any position changes of the anchor. The local coordinate system of positions with a parent anchor always is absolute pixels, with (0, 0) being exactly on top of the parent anchor. (Hence the type shouldn't be set to \ref ptPlotCoords for positions with parent anchors.) if \a keepPixelPosition is true, the current pixel position of the QCPItemPosition is preserved during reparenting. If it's set to false, the coordinates are set to (0, 0), i.e. the position will be exactly on top of the parent anchor. To remove this QCPItemPosition from any parent anchor, set \a parentAnchor to \c nullptr. If the QCPItemPosition previously had no parent and the type is \ref ptPlotCoords, the type is set to \ref ptAbsolute, to keep the position in a valid state. This method sets the parent anchor for both X and Y directions. It is also possible to set different parents for X and Y, see \ref setParentAnchorX, \ref setParentAnchorY. */ bool QCPItemPosition::setParentAnchor(QCPItemAnchor *parentAnchor, bool keepPixelPosition) { bool successX = setParentAnchorX(parentAnchor, keepPixelPosition); bool successY = setParentAnchorY(parentAnchor, keepPixelPosition); return successX && successY; } /*! This method sets the parent anchor of the X coordinate to \a parentAnchor. For a detailed description of what a parent anchor is, see the documentation of \ref setParentAnchor. \see setParentAnchor, setParentAnchorY */ bool QCPItemPosition::setParentAnchorX(QCPItemAnchor *parentAnchor, bool keepPixelPosition) { // make sure self is not assigned as parent: if (parentAnchor == this) { qDebug() << Q_FUNC_INFO << "can't set self as parent anchor" << reinterpret_cast(parentAnchor); return false; } // make sure no recursive parent-child-relationships are created: QCPItemAnchor *currentParent = parentAnchor; while (currentParent) { if (QCPItemPosition *currentParentPos = currentParent->toQCPItemPosition()) { // is a QCPItemPosition, might have further parent, so keep iterating if (currentParentPos == this) { qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast(parentAnchor); return false; } currentParent = currentParentPos->parentAnchorX(); } else { // is a QCPItemAnchor, can't have further parent. Now make sure the parent items aren't the // same, to prevent a position being child of an anchor which itself depends on the position, // because they're both on the same item: if (currentParent->mParentItem == mParentItem) { qDebug() << Q_FUNC_INFO << "can't set parent to be an anchor which itself depends on this position" << reinterpret_cast(parentAnchor); return false; } break; } } // if previously no parent set and PosType is still ptPlotCoords, set to ptAbsolute: if (!mParentAnchorX && mPositionTypeX == ptPlotCoords) setTypeX(ptAbsolute); // save pixel position: QPointF pixelP; if (keepPixelPosition) pixelP = pixelPosition(); // unregister at current parent anchor: if (mParentAnchorX) mParentAnchorX->removeChildX(this); // register at new parent anchor: if (parentAnchor) parentAnchor->addChildX(this); mParentAnchorX = parentAnchor; // restore pixel position under new parent: if (keepPixelPosition) setPixelPosition(pixelP); else setCoords(0, coords().y()); return true; } /*! This method sets the parent anchor of the Y coordinate to \a parentAnchor. For a detailed description of what a parent anchor is, see the documentation of \ref setParentAnchor. \see setParentAnchor, setParentAnchorX */ bool QCPItemPosition::setParentAnchorY(QCPItemAnchor *parentAnchor, bool keepPixelPosition) { // make sure self is not assigned as parent: if (parentAnchor == this) { qDebug() << Q_FUNC_INFO << "can't set self as parent anchor" << reinterpret_cast(parentAnchor); return false; } // make sure no recursive parent-child-relationships are created: QCPItemAnchor *currentParent = parentAnchor; while (currentParent) { if (QCPItemPosition *currentParentPos = currentParent->toQCPItemPosition()) { // is a QCPItemPosition, might have further parent, so keep iterating if (currentParentPos == this) { qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast(parentAnchor); return false; } currentParent = currentParentPos->parentAnchorY(); } else { // is a QCPItemAnchor, can't have further parent. Now make sure the parent items aren't the // same, to prevent a position being child of an anchor which itself depends on the position, // because they're both on the same item: if (currentParent->mParentItem == mParentItem) { qDebug() << Q_FUNC_INFO << "can't set parent to be an anchor which itself depends on this position" << reinterpret_cast(parentAnchor); return false; } break; } } // if previously no parent set and PosType is still ptPlotCoords, set to ptAbsolute: if (!mParentAnchorY && mPositionTypeY == ptPlotCoords) setTypeY(ptAbsolute); // save pixel position: QPointF pixelP; if (keepPixelPosition) pixelP = pixelPosition(); // unregister at current parent anchor: if (mParentAnchorY) mParentAnchorY->removeChildY(this); // register at new parent anchor: if (parentAnchor) parentAnchor->addChildY(this); mParentAnchorY = parentAnchor; // restore pixel position under new parent: if (keepPixelPosition) setPixelPosition(pixelP); else setCoords(coords().x(), 0); return true; } /*! Sets the coordinates of this QCPItemPosition. What the coordinates mean, is defined by the type (\ref setType, \ref setTypeX, \ref setTypeY). For example, if the type is \ref ptAbsolute, \a key and \a value mean the x and y pixel position on the QCustomPlot surface. In that case the origin (0, 0) is in the top left corner of the QCustomPlot viewport. If the type is \ref ptPlotCoords, \a key and \a value mean a point in the plot coordinate system defined by the axes set by \ref setAxes. By default those are the QCustomPlot's xAxis and yAxis. See the documentation of \ref setType for other available coordinate types and their meaning. If different types were configured for X and Y (\ref setTypeX, \ref setTypeY), \a key and \a value must also be provided in the different coordinate systems. Here, the X type refers to \a key, and the Y type refers to \a value. \see setPixelPosition */ void QCPItemPosition::setCoords(double key, double value) { mKey = key; mValue = value; } /*! \overload Sets the coordinates as a QPointF \a pos where pos.x has the meaning of \a key and pos.y the meaning of \a value of the \ref setCoords(double key, double value) method. */ void QCPItemPosition::setCoords(const QPointF &pos) { setCoords(pos.x(), pos.y()); } /*! Returns the final absolute pixel position of the QCPItemPosition on the QCustomPlot surface. It includes all effects of type (\ref setType) and possible parent anchors (\ref setParentAnchor). \see setPixelPosition */ QPointF QCPItemPosition::pixelPosition() const { QPointF result; // determine X: switch (mPositionTypeX) { case ptAbsolute: { result.rx() = mKey; if (mParentAnchorX) result.rx() += mParentAnchorX->pixelPosition().x(); break; } case ptViewportRatio: { result.rx() = mKey*mParentPlot->viewport().width(); if (mParentAnchorX) result.rx() += mParentAnchorX->pixelPosition().x(); else result.rx() += mParentPlot->viewport().left(); break; } case ptAxisRectRatio: { if (mAxisRect) { result.rx() = mKey*mAxisRect.data()->width(); if (mParentAnchorX) result.rx() += mParentAnchorX->pixelPosition().x(); else result.rx() += mAxisRect.data()->left(); } else qDebug() << Q_FUNC_INFO << "Item position type x is ptAxisRectRatio, but no axis rect was defined"; break; } case ptPlotCoords: { if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Horizontal) result.rx() = mKeyAxis.data()->coordToPixel(mKey); else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Horizontal) result.rx() = mValueAxis.data()->coordToPixel(mValue); else qDebug() << Q_FUNC_INFO << "Item position type x is ptPlotCoords, but no axes were defined"; break; } } // determine Y: switch (mPositionTypeY) { case ptAbsolute: { result.ry() = mValue; if (mParentAnchorY) result.ry() += mParentAnchorY->pixelPosition().y(); break; } case ptViewportRatio: { result.ry() = mValue*mParentPlot->viewport().height(); if (mParentAnchorY) result.ry() += mParentAnchorY->pixelPosition().y(); else result.ry() += mParentPlot->viewport().top(); break; } case ptAxisRectRatio: { if (mAxisRect) { result.ry() = mValue*mAxisRect.data()->height(); if (mParentAnchorY) result.ry() += mParentAnchorY->pixelPosition().y(); else result.ry() += mAxisRect.data()->top(); } else qDebug() << Q_FUNC_INFO << "Item position type y is ptAxisRectRatio, but no axis rect was defined"; break; } case ptPlotCoords: { if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Vertical) result.ry() = mKeyAxis.data()->coordToPixel(mKey); else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Vertical) result.ry() = mValueAxis.data()->coordToPixel(mValue); else qDebug() << Q_FUNC_INFO << "Item position type y is ptPlotCoords, but no axes were defined"; break; } } return result; } /*! When \ref setType is \ref ptPlotCoords, this function may be used to specify the axes the coordinates set with \ref setCoords relate to. By default they are set to the initial xAxis and yAxis of the QCustomPlot. */ void QCPItemPosition::setAxes(QCPAxis *keyAxis, QCPAxis *valueAxis) { mKeyAxis = keyAxis; mValueAxis = valueAxis; } /*! When \ref setType is \ref ptAxisRectRatio, this function may be used to specify the axis rect the coordinates set with \ref setCoords relate to. By default this is set to the main axis rect of the QCustomPlot. */ void QCPItemPosition::setAxisRect(QCPAxisRect *axisRect) { mAxisRect = axisRect; } /*! Sets the apparent pixel position. This works no matter what type (\ref setType) this QCPItemPosition is or what parent-child situation it is in, as coordinates are transformed appropriately, to make the position finally appear at the specified pixel values. Only if the type is \ref ptAbsolute and no parent anchor is set, this function's effect is identical to that of \ref setCoords. \see pixelPosition, setCoords */ void QCPItemPosition::setPixelPosition(const QPointF &pixelPosition) { double x = pixelPosition.x(); double y = pixelPosition.y(); switch (mPositionTypeX) { case ptAbsolute: { if (mParentAnchorX) x -= mParentAnchorX->pixelPosition().x(); break; } case ptViewportRatio: { if (mParentAnchorX) x -= mParentAnchorX->pixelPosition().x(); else x -= mParentPlot->viewport().left(); x /= double(mParentPlot->viewport().width()); break; } case ptAxisRectRatio: { if (mAxisRect) { if (mParentAnchorX) x -= mParentAnchorX->pixelPosition().x(); else x -= mAxisRect.data()->left(); x /= double(mAxisRect.data()->width()); } else qDebug() << Q_FUNC_INFO << "Item position type x is ptAxisRectRatio, but no axis rect was defined"; break; } case ptPlotCoords: { if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Horizontal) x = mKeyAxis.data()->pixelToCoord(x); else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Horizontal) y = mValueAxis.data()->pixelToCoord(x); else qDebug() << Q_FUNC_INFO << "Item position type x is ptPlotCoords, but no axes were defined"; break; } } switch (mPositionTypeY) { case ptAbsolute: { if (mParentAnchorY) y -= mParentAnchorY->pixelPosition().y(); break; } case ptViewportRatio: { if (mParentAnchorY) y -= mParentAnchorY->pixelPosition().y(); else y -= mParentPlot->viewport().top(); y /= double(mParentPlot->viewport().height()); break; } case ptAxisRectRatio: { if (mAxisRect) { if (mParentAnchorY) y -= mParentAnchorY->pixelPosition().y(); else y -= mAxisRect.data()->top(); y /= double(mAxisRect.data()->height()); } else qDebug() << Q_FUNC_INFO << "Item position type y is ptAxisRectRatio, but no axis rect was defined"; break; } case ptPlotCoords: { if (mKeyAxis && mKeyAxis.data()->orientation() == Qt::Vertical) x = mKeyAxis.data()->pixelToCoord(y); else if (mValueAxis && mValueAxis.data()->orientation() == Qt::Vertical) y = mValueAxis.data()->pixelToCoord(y); else qDebug() << Q_FUNC_INFO << "Item position type y is ptPlotCoords, but no axes were defined"; break; } } setCoords(x, y); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAbstractItem //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAbstractItem \brief The abstract base class for all items in a plot. In QCustomPlot, items are supplemental graphical elements that are neither plottables (QCPAbstractPlottable) nor axes (QCPAxis). While plottables are always tied to two axes and thus plot coordinates, items can also be placed in absolute coordinates independent of any axes. Each specific item has at least one QCPItemPosition member which controls the positioning. Some items are defined by more than one coordinate and thus have two or more QCPItemPosition members (For example, QCPItemRect has \a topLeft and \a bottomRight). This abstract base class defines a very basic interface like visibility and clipping. Since this class is abstract, it can't be instantiated. Use one of the subclasses or create a subclass yourself to create new items. The built-in items are:
QCPItemLineA line defined by a start and an end point. May have different ending styles on each side (e.g. arrows).
QCPItemStraightLineA straight line defined by a start and a direction point. Unlike QCPItemLine, the straight line is infinitely long and has no endings.
QCPItemCurveA curve defined by start, end and two intermediate control points. May have different ending styles on each side (e.g. arrows).
QCPItemRectA rectangle
QCPItemEllipseAn ellipse
QCPItemPixmapAn arbitrary pixmap
QCPItemTextA text label
QCPItemBracketA bracket which may be used to reference/highlight certain parts in the plot.
QCPItemTracerAn item that can be attached to a QCPGraph and sticks to its data points, given a key coordinate.
\section items-clipping Clipping Items are by default clipped to the main axis rect (they are only visible inside the axis rect). To make an item visible outside that axis rect, disable clipping via \ref setClipToAxisRect "setClipToAxisRect(false)". On the other hand if you want the item to be clipped to a different axis rect, specify it via \ref setClipAxisRect. This clipAxisRect property of an item is only used for clipping behaviour, and in principle is independent of the coordinate axes the item might be tied to via its position members (\ref QCPItemPosition::setAxes). However, it is common that the axis rect for clipping also contains the axes used for the item positions. \section items-using Using items First you instantiate the item you want to use and add it to the plot: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-1 by default, the positions of the item are bound to the x- and y-Axis of the plot. So we can just set the plot coordinates where the line should start/end: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-2 If we don't want the line to be positioned in plot coordinates but a different coordinate system, e.g. absolute pixel positions on the QCustomPlot surface, we need to change the position type like this: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-3 Then we can set the coordinates, this time in pixels: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-4 and make the line visible on the entire QCustomPlot, by disabling clipping to the axis rect: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpitemline-creation-5 For more advanced plots, it is even possible to set different types and parent anchors per X/Y coordinate of an item position, using for example \ref QCPItemPosition::setTypeX or \ref QCPItemPosition::setParentAnchorX. For details, see the documentation of \ref QCPItemPosition. \section items-subclassing Creating own items To create an own item, you implement a subclass of QCPAbstractItem. These are the pure virtual functions, you must implement: \li \ref selectTest \li \ref draw See the documentation of those functions for what they need to do. \subsection items-positioning Allowing the item to be positioned As mentioned, item positions are represented by QCPItemPosition members. Let's assume the new item shall have only one point as its position (as opposed to two like a rect or multiple like a polygon). You then add a public member of type QCPItemPosition like so: \code QCPItemPosition * const myPosition;\endcode the const makes sure the pointer itself can't be modified from the user of your new item (the QCPItemPosition instance it points to, can be modified, of course). The initialization of this pointer is made easy with the \ref createPosition function. Just assign the return value of this function to each QCPItemPosition in the constructor of your item. \ref createPosition takes a string which is the name of the position, typically this is identical to the variable name. For example, the constructor of QCPItemExample could look like this: \code QCPItemExample::QCPItemExample(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), myPosition(createPosition("myPosition")) { // other constructor code } \endcode \subsection items-drawing The draw function To give your item a visual representation, reimplement the \ref draw function and use the passed QCPPainter to draw the item. You can retrieve the item position in pixel coordinates from the position member(s) via \ref QCPItemPosition::pixelPosition. To optimize performance you should calculate a bounding rect first (don't forget to take the pen width into account), check whether it intersects the \ref clipRect, and only draw the item at all if this is the case. \subsection items-selection The selectTest function Your implementation of the \ref selectTest function may use the helpers \ref QCPVector2D::distanceSquaredToLine and \ref rectDistance. With these, the implementation of the selection test becomes significantly simpler for most items. See the documentation of \ref selectTest for what the function parameters mean and what the function should return. \subsection anchors Providing anchors Providing anchors (QCPItemAnchor) starts off like adding a position. First you create a public member, e.g. \code QCPItemAnchor * const bottom;\endcode and create it in the constructor with the \ref createAnchor function, assigning it a name and an anchor id (an integer enumerating all anchors on the item, you may create an own enum for this). Since anchors can be placed anywhere, relative to the item's position(s), your item needs to provide the position of every anchor with the reimplementation of the \ref anchorPixelPosition(int anchorId) function. In essence the QCPItemAnchor is merely an intermediary that itself asks your item for the pixel position when anything attached to the anchor needs to know the coordinates. */ /* start of documentation of inline functions */ /*! \fn QList QCPAbstractItem::positions() const Returns all positions of the item in a list. \see anchors, position */ /*! \fn QList QCPAbstractItem::anchors() const Returns all anchors of the item in a list. Note that since a position (QCPItemPosition) is always also an anchor, the list will also contain the positions of this item. \see positions, anchor */ /* end of documentation of inline functions */ /* start documentation of pure virtual functions */ /*! \fn void QCPAbstractItem::draw(QCPPainter *painter) = 0 \internal Draws this item with the provided \a painter. The cliprect of the provided painter is set to the rect returned by \ref clipRect before this function is called. The clipRect depends on the clipping settings defined by \ref setClipToAxisRect and \ref setClipAxisRect. */ /* end documentation of pure virtual functions */ /* start documentation of signals */ /*! \fn void QCPAbstractItem::selectionChanged(bool selected) This signal is emitted when the selection state of this item has changed, either by user interaction or by a direct call to \ref setSelected. */ /* end documentation of signals */ /*! Base class constructor which initializes base class members. */ QCPAbstractItem::QCPAbstractItem(QCustomPlot *parentPlot) : QCPLayerable(parentPlot), mClipToAxisRect(false), mSelectable(true), mSelected(false) { parentPlot->registerItem(this); QList rects = parentPlot->axisRects(); if (!rects.isEmpty()) { setClipToAxisRect(true); setClipAxisRect(rects.first()); } } QCPAbstractItem::~QCPAbstractItem() { // don't delete mPositions because every position is also an anchor and thus in mAnchors qDeleteAll(mAnchors); } /* can't make this a header inline function, because QPointer breaks with forward declared types, see QTBUG-29588 */ QCPAxisRect *QCPAbstractItem::clipAxisRect() const { return mClipAxisRect.data(); } /*! Sets whether the item shall be clipped to an axis rect or whether it shall be visible on the entire QCustomPlot. The axis rect can be set with \ref setClipAxisRect. \see setClipAxisRect */ void QCPAbstractItem::setClipToAxisRect(bool clip) { mClipToAxisRect = clip; if (mClipToAxisRect) setParentLayerable(mClipAxisRect.data()); } /*! Sets the clip axis rect. It defines the rect that will be used to clip the item when \ref setClipToAxisRect is set to true. \see setClipToAxisRect */ void QCPAbstractItem::setClipAxisRect(QCPAxisRect *rect) { mClipAxisRect = rect; if (mClipToAxisRect) setParentLayerable(mClipAxisRect.data()); } /*! Sets whether the user can (de-)select this item by clicking on the QCustomPlot surface. (When \ref QCustomPlot::setInteractions contains QCustomPlot::iSelectItems.) However, even when \a selectable was set to false, it is possible to set the selection manually, by calling \ref setSelected. \see QCustomPlot::setInteractions, setSelected */ void QCPAbstractItem::setSelectable(bool selectable) { if (mSelectable != selectable) { mSelectable = selectable; emit selectableChanged(mSelectable); } } /*! Sets whether this item is selected or not. When selected, it might use a different visual appearance (e.g. pen and brush), this depends on the specific item though. The entire selection mechanism for items is handled automatically when \ref QCustomPlot::setInteractions contains QCustomPlot::iSelectItems. You only need to call this function when you wish to change the selection state manually. This function can change the selection state even when \ref setSelectable was set to false. emits the \ref selectionChanged signal when \a selected is different from the previous selection state. \see setSelectable, selectTest */ void QCPAbstractItem::setSelected(bool selected) { if (mSelected != selected) { mSelected = selected; emit selectionChanged(mSelected); } } /*! Returns the QCPItemPosition with the specified \a name. If this item doesn't have a position by that name, returns \c nullptr. This function provides an alternative way to access item positions. Normally, you access positions direcly by their member pointers (which typically have the same variable name as \a name). \see positions, anchor */ QCPItemPosition *QCPAbstractItem::position(const QString &name) const { foreach (QCPItemPosition *position, mPositions) { if (position->name() == name) return position; } qDebug() << Q_FUNC_INFO << "position with name not found:" << name; return nullptr; } /*! Returns the QCPItemAnchor with the specified \a name. If this item doesn't have an anchor by that name, returns \c nullptr. This function provides an alternative way to access item anchors. Normally, you access anchors direcly by their member pointers (which typically have the same variable name as \a name). \see anchors, position */ QCPItemAnchor *QCPAbstractItem::anchor(const QString &name) const { foreach (QCPItemAnchor *anchor, mAnchors) { if (anchor->name() == name) return anchor; } qDebug() << Q_FUNC_INFO << "anchor with name not found:" << name; return nullptr; } /*! Returns whether this item has an anchor with the specified \a name. Note that you can check for positions with this function, too. This is because every position is also an anchor (QCPItemPosition inherits from QCPItemAnchor). \see anchor, position */ bool QCPAbstractItem::hasAnchor(const QString &name) const { foreach (QCPItemAnchor *anchor, mAnchors) { if (anchor->name() == name) return true; } return false; } /*! \internal Returns the rect the visual representation of this item is clipped to. This depends on the current setting of \ref setClipToAxisRect as well as the axis rect set with \ref setClipAxisRect. If the item is not clipped to an axis rect, QCustomPlot's viewport rect is returned. \see draw */ QRect QCPAbstractItem::clipRect() const { if (mClipToAxisRect && mClipAxisRect) return mClipAxisRect.data()->rect(); else return mParentPlot->viewport(); } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing item lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set with \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased */ void QCPAbstractItem::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeItems); } /*! \internal A convenience function which returns the selectTest value for a specified \a rect and a specified click position \a pos. \a filledRect defines whether a click inside the rect should also be considered a hit or whether only the rect border is sensitive to hits. This function may be used to help with the implementation of the \ref selectTest function for specific items. For example, if your item consists of four rects, call this function four times, once for each rect, in your \ref selectTest reimplementation. Finally, return the minimum (non -1) of all four returned values. */ double QCPAbstractItem::rectDistance(const QRectF &rect, const QPointF &pos, bool filledRect) const { double result = -1; // distance to border: const QList lines = QList() << QLineF(rect.topLeft(), rect.topRight()) << QLineF(rect.bottomLeft(), rect.bottomRight()) << QLineF(rect.topLeft(), rect.bottomLeft()) << QLineF(rect.topRight(), rect.bottomRight()); const QCPVector2D posVec(pos); double minDistSqr = (std::numeric_limits::max)(); foreach (const QLineF &line, lines) { double distSqr = posVec.distanceSquaredToLine(line.p1(), line.p2()); if (distSqr < minDistSqr) minDistSqr = distSqr; } result = qSqrt(minDistSqr); // filled rect, allow click inside to count as hit: if (filledRect && result > mParentPlot->selectionTolerance()*0.99) { if (rect.contains(pos)) result = mParentPlot->selectionTolerance()*0.99; } return result; } /*! \internal Returns the pixel position of the anchor with Id \a anchorId. This function must be reimplemented in item subclasses if they want to provide anchors (QCPItemAnchor). For example, if the item has two anchors with id 0 and 1, this function takes one of these anchor ids and returns the respective pixel points of the specified anchor. \see createAnchor */ QPointF QCPAbstractItem::anchorPixelPosition(int anchorId) const { qDebug() << Q_FUNC_INFO << "called on item which shouldn't have any anchors (this method not reimplemented). anchorId" << anchorId; return {}; } /*! \internal Creates a QCPItemPosition, registers it with this item and returns a pointer to it. The specified \a name must be a unique string that is usually identical to the variable name of the position member (This is needed to provide the name-based \ref position access to positions). Don't delete positions created by this function manually, as the item will take care of it. Use this function in the constructor (initialization list) of the specific item subclass to create each position member. Don't create QCPItemPositions with \b new yourself, because they won't be registered with the item properly. \see createAnchor */ QCPItemPosition *QCPAbstractItem::createPosition(const QString &name) { if (hasAnchor(name)) qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name; QCPItemPosition *newPosition = new QCPItemPosition(mParentPlot, this, name); mPositions.append(newPosition); mAnchors.append(newPosition); // every position is also an anchor newPosition->setAxes(mParentPlot->xAxis, mParentPlot->yAxis); newPosition->setType(QCPItemPosition::ptPlotCoords); if (mParentPlot->axisRect()) newPosition->setAxisRect(mParentPlot->axisRect()); newPosition->setCoords(0, 0); return newPosition; } /*! \internal Creates a QCPItemAnchor, registers it with this item and returns a pointer to it. The specified \a name must be a unique string that is usually identical to the variable name of the anchor member (This is needed to provide the name based \ref anchor access to anchors). The \a anchorId must be a number identifying the created anchor. It is recommended to create an enum (e.g. "AnchorIndex") for this on each item that uses anchors. This id is used by the anchor to identify itself when it calls QCPAbstractItem::anchorPixelPosition. That function then returns the correct pixel coordinates for the passed anchor id. Don't delete anchors created by this function manually, as the item will take care of it. Use this function in the constructor (initialization list) of the specific item subclass to create each anchor member. Don't create QCPItemAnchors with \b new yourself, because then they won't be registered with the item properly. \see createPosition */ QCPItemAnchor *QCPAbstractItem::createAnchor(const QString &name, int anchorId) { if (hasAnchor(name)) qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name; QCPItemAnchor *newAnchor = new QCPItemAnchor(mParentPlot, this, name, anchorId); mAnchors.append(newAnchor); return newAnchor; } /* inherits documentation from base class */ void QCPAbstractItem::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) { Q_UNUSED(event) Q_UNUSED(details) if (mSelectable) { bool selBefore = mSelected; setSelected(additive ? !mSelected : true); if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore; } } /* inherits documentation from base class */ void QCPAbstractItem::deselectEvent(bool *selectionStateChanged) { if (mSelectable) { bool selBefore = mSelected; setSelected(false); if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore; } } /* inherits documentation from base class */ QCP::Interaction QCPAbstractItem::selectionCategory() const { return QCP::iSelectItems; } /* end of 'src/item.cpp' */ /* including file 'src/core.cpp' */ /* modified 2021-03-29T02:30:44, size 127198 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCustomPlot //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCustomPlot \brief The central class of the library. This is the QWidget which displays the plot and interacts with the user. For tutorials on how to use QCustomPlot, see the website\n http://www.qcustomplot.com/ */ /* start of documentation of inline functions */ /*! \fn QCPSelectionRect *QCustomPlot::selectionRect() const Allows access to the currently used QCPSelectionRect instance (or subclass thereof), that is used to handle and draw selection rect interactions (see \ref setSelectionRectMode). \see setSelectionRect */ /*! \fn QCPLayoutGrid *QCustomPlot::plotLayout() const Returns the top level layout of this QCustomPlot instance. It is a \ref QCPLayoutGrid, initially containing just one cell with the main QCPAxisRect inside. */ /* end of documentation of inline functions */ /* start of documentation of signals */ /*! \fn void QCustomPlot::mouseDoubleClick(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse double click event. */ /*! \fn void QCustomPlot::mousePress(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse press event. It is emitted before QCustomPlot handles any other mechanism like range dragging. So a slot connected to this signal can still influence the behaviour e.g. with \ref QCPAxisRect::setRangeDrag or \ref QCPAxisRect::setRangeDragAxes. */ /*! \fn void QCustomPlot::mouseMove(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse move event. It is emitted before QCustomPlot handles any other mechanism like range dragging. So a slot connected to this signal can still influence the behaviour e.g. with \ref QCPAxisRect::setRangeDrag or \ref QCPAxisRect::setRangeDragAxes. \warning It is discouraged to change the drag-axes with \ref QCPAxisRect::setRangeDragAxes here, because the dragging starting point was saved the moment the mouse was pressed. Thus it only has a meaning for the range drag axes that were set at that moment. If you want to change the drag axes, consider doing this in the \ref mousePress signal instead. */ /*! \fn void QCustomPlot::mouseRelease(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse release event. It is emitted before QCustomPlot handles any other mechanisms like object selection. So a slot connected to this signal can still influence the behaviour e.g. with \ref setInteractions or \ref QCPAbstractPlottable::setSelectable. */ /*! \fn void QCustomPlot::mouseWheel(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse wheel event. It is emitted before QCustomPlot handles any other mechanisms like range zooming. So a slot connected to this signal can still influence the behaviour e.g. with \ref QCPAxisRect::setRangeZoom, \ref QCPAxisRect::setRangeZoomAxes or \ref QCPAxisRect::setRangeZoomFactor. */ /*! \fn void QCustomPlot::plottableClick(QCPAbstractPlottable *plottable, int dataIndex, QMouseEvent *event) This signal is emitted when a plottable is clicked. \a event is the mouse event that caused the click and \a plottable is the plottable that received the click. The parameter \a dataIndex indicates the data point that was closest to the click position. \see plottableDoubleClick */ /*! \fn void QCustomPlot::plottableDoubleClick(QCPAbstractPlottable *plottable, int dataIndex, QMouseEvent *event) This signal is emitted when a plottable is double clicked. \a event is the mouse event that caused the click and \a plottable is the plottable that received the click. The parameter \a dataIndex indicates the data point that was closest to the click position. \see plottableClick */ /*! \fn void QCustomPlot::itemClick(QCPAbstractItem *item, QMouseEvent *event) This signal is emitted when an item is clicked. \a event is the mouse event that caused the click and \a item is the item that received the click. \see itemDoubleClick */ /*! \fn void QCustomPlot::itemDoubleClick(QCPAbstractItem *item, QMouseEvent *event) This signal is emitted when an item is double clicked. \a event is the mouse event that caused the click and \a item is the item that received the click. \see itemClick */ /*! \fn void QCustomPlot::axisClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event) This signal is emitted when an axis is clicked. \a event is the mouse event that caused the click, \a axis is the axis that received the click and \a part indicates the part of the axis that was clicked. \see axisDoubleClick */ /*! \fn void QCustomPlot::axisDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event) This signal is emitted when an axis is double clicked. \a event is the mouse event that caused the click, \a axis is the axis that received the click and \a part indicates the part of the axis that was clicked. \see axisClick */ /*! \fn void QCustomPlot::legendClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event) This signal is emitted when a legend (item) is clicked. \a event is the mouse event that caused the click, \a legend is the legend that received the click and \a item is the legend item that received the click. If only the legend and no item is clicked, \a item is \c nullptr. This happens for a click inside the legend padding or the space between two items. \see legendDoubleClick */ /*! \fn void QCustomPlot::legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event) This signal is emitted when a legend (item) is double clicked. \a event is the mouse event that caused the click, \a legend is the legend that received the click and \a item is the legend item that received the click. If only the legend and no item is clicked, \a item is \c nullptr. This happens for a click inside the legend padding or the space between two items. \see legendClick */ /*! \fn void QCustomPlot::selectionChangedByUser() This signal is emitted after the user has changed the selection in the QCustomPlot, e.g. by clicking. It is not emitted when the selection state of an object has changed programmatically by a direct call to setSelected()/setSelection() on an object or by calling \ref deselectAll. In addition to this signal, selectable objects also provide individual signals, for example \ref QCPAxis::selectionChanged or \ref QCPAbstractPlottable::selectionChanged. Note that those signals are emitted even if the selection state is changed programmatically. See the documentation of \ref setInteractions for details about the selection mechanism. \see selectedPlottables, selectedGraphs, selectedItems, selectedAxes, selectedLegends */ /*! \fn void QCustomPlot::beforeReplot() This signal is emitted immediately before a replot takes place (caused by a call to the slot \ref replot). It is safe to mutually connect the replot slot with this signal on two QCustomPlots to make them replot synchronously, it won't cause an infinite recursion. \see replot, afterReplot, afterLayout */ /*! \fn void QCustomPlot::afterLayout() This signal is emitted immediately after the layout step has been completed, which occurs right before drawing the plot. This is typically during a call to \ref replot, and in such cases this signal is emitted in between the signals \ref beforeReplot and \ref afterReplot. Unlike those signals however, this signal is also emitted during off-screen painting, such as when calling \ref toPixmap or \ref savePdf. The layout step queries all layouts and layout elements in the plot for their proposed size and arranges the objects accordingly as preparation for the subsequent drawing step. Through this signal, you have the opportunity to update certain things in your plot that depend crucially on the exact dimensions/positioning of layout elements such as axes and axis rects. \warning However, changing any parameters of this QCustomPlot instance which would normally affect the layouting (e.g. axis range order of magnitudes, tick label sizes, etc.) will not issue a second run of the layout step. It will propagate directly to the draw step and may cause graphical inconsistencies such as overlapping objects, if sizes or positions have changed. \see updateLayout, beforeReplot, afterReplot */ /*! \fn void QCustomPlot::afterReplot() This signal is emitted immediately after a replot has taken place (caused by a call to the slot \ref replot). It is safe to mutually connect the replot slot with this signal on two QCustomPlots to make them replot synchronously, it won't cause an infinite recursion. \see replot, beforeReplot, afterLayout */ /* end of documentation of signals */ /* start of documentation of public members */ /*! \var QCPAxis *QCustomPlot::xAxis A pointer to the primary x Axis (bottom) of the main axis rect of the plot. QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref yAxis2) and the \ref legend. They make it very easy working with plots that only have a single axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the layout system\endlink to add multiple axis rects or multiple axes to one side, use the \ref QCPAxisRect::axis interface to access the new axes. If one of the four default axes or the default legend is removed due to manipulation of the layout system (e.g. by removing the main axis rect), the corresponding pointers become \c nullptr. If an axis convenience pointer is currently \c nullptr and a new axis rect or a corresponding axis is added in the place of the main axis rect, QCustomPlot resets the convenience pointers to the according new axes. Similarly the \ref legend convenience pointer will be reset if a legend is added after the main legend was removed before. */ /*! \var QCPAxis *QCustomPlot::yAxis A pointer to the primary y Axis (left) of the main axis rect of the plot. QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref yAxis2) and the \ref legend. They make it very easy working with plots that only have a single axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the layout system\endlink to add multiple axis rects or multiple axes to one side, use the \ref QCPAxisRect::axis interface to access the new axes. If one of the four default axes or the default legend is removed due to manipulation of the layout system (e.g. by removing the main axis rect), the corresponding pointers become \c nullptr. If an axis convenience pointer is currently \c nullptr and a new axis rect or a corresponding axis is added in the place of the main axis rect, QCustomPlot resets the convenience pointers to the according new axes. Similarly the \ref legend convenience pointer will be reset if a legend is added after the main legend was removed before. */ /*! \var QCPAxis *QCustomPlot::xAxis2 A pointer to the secondary x Axis (top) of the main axis rect of the plot. Secondary axes are invisible by default. Use QCPAxis::setVisible to change this (or use \ref QCPAxisRect::setupFullAxesBox). QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref yAxis2) and the \ref legend. They make it very easy working with plots that only have a single axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the layout system\endlink to add multiple axis rects or multiple axes to one side, use the \ref QCPAxisRect::axis interface to access the new axes. If one of the four default axes or the default legend is removed due to manipulation of the layout system (e.g. by removing the main axis rect), the corresponding pointers become \c nullptr. If an axis convenience pointer is currently \c nullptr and a new axis rect or a corresponding axis is added in the place of the main axis rect, QCustomPlot resets the convenience pointers to the according new axes. Similarly the \ref legend convenience pointer will be reset if a legend is added after the main legend was removed before. */ /*! \var QCPAxis *QCustomPlot::yAxis2 A pointer to the secondary y Axis (right) of the main axis rect of the plot. Secondary axes are invisible by default. Use QCPAxis::setVisible to change this (or use \ref QCPAxisRect::setupFullAxesBox). QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref yAxis2) and the \ref legend. They make it very easy working with plots that only have a single axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the layout system\endlink to add multiple axis rects or multiple axes to one side, use the \ref QCPAxisRect::axis interface to access the new axes. If one of the four default axes or the default legend is removed due to manipulation of the layout system (e.g. by removing the main axis rect), the corresponding pointers become \c nullptr. If an axis convenience pointer is currently \c nullptr and a new axis rect or a corresponding axis is added in the place of the main axis rect, QCustomPlot resets the convenience pointers to the according new axes. Similarly the \ref legend convenience pointer will be reset if a legend is added after the main legend was removed before. */ /*! \var QCPLegend *QCustomPlot::legend A pointer to the default legend of the main axis rect. The legend is invisible by default. Use QCPLegend::setVisible to change this. QCustomPlot offers convenient pointers to the axes (\ref xAxis, \ref yAxis, \ref xAxis2, \ref yAxis2) and the \ref legend. They make it very easy working with plots that only have a single axis rect and at most one axis at each axis rect side. If you use \link thelayoutsystem the layout system\endlink to add multiple legends to the plot, use the layout system interface to access the new legend. For example, legends can be placed inside an axis rect's \ref QCPAxisRect::insetLayout "inset layout", and must then also be accessed via the inset layout. If the default legend is removed due to manipulation of the layout system (e.g. by removing the main axis rect), the corresponding pointer becomes \c nullptr. If an axis convenience pointer is currently \c nullptr and a new axis rect or a corresponding axis is added in the place of the main axis rect, QCustomPlot resets the convenience pointers to the according new axes. Similarly the \ref legend convenience pointer will be reset if a legend is added after the main legend was removed before. */ /* end of documentation of public members */ /*! Constructs a QCustomPlot and sets reasonable default values. */ QCustomPlot::QCustomPlot(QWidget *parent) : QWidget(parent), xAxis(nullptr), yAxis(nullptr), xAxis2(nullptr), yAxis2(nullptr), legend(nullptr), mBufferDevicePixelRatio(1.0), // will be adapted to primary screen below mPlotLayout(nullptr), mAutoAddPlottableToLegend(true), mAntialiasedElements(QCP::aeNone), mNotAntialiasedElements(QCP::aeNone), mInteractions(QCP::iNone), mSelectionTolerance(8), mNoAntialiasingOnDrag(false), mBackgroundBrush(Qt::white, Qt::SolidPattern), mBackgroundScaled(true), mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding), mCurrentLayer(nullptr), mPlottingHints(QCP::phCacheLabels|QCP::phImmediateRefresh), mMultiSelectModifier(Qt::ControlModifier), mSelectionRectMode(QCP::srmNone), mSelectionRect(nullptr), mOpenGl(false), mMouseHasMoved(false), mMouseEventLayerable(nullptr), mMouseSignalLayerable(nullptr), mReplotting(false), mReplotQueued(false), mReplotTime(0), mReplotTimeAverage(0), mOpenGlMultisamples(16), mOpenGlAntialiasedElementsBackup(QCP::aeNone), mOpenGlCacheLabelsBackup(true) { setAttribute(Qt::WA_NoMousePropagation); setAttribute(Qt::WA_OpaquePaintEvent); setFocusPolicy(Qt::ClickFocus); setMouseTracking(true); QLocale currentLocale = locale(); currentLocale.setNumberOptions(QLocale::OmitGroupSeparator); setLocale(currentLocale); #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED # ifdef QCP_DEVICEPIXELRATIO_FLOAT setBufferDevicePixelRatio(QWidget::devicePixelRatioF()); # else setBufferDevicePixelRatio(QWidget::devicePixelRatio()); # endif #endif mOpenGlAntialiasedElementsBackup = mAntialiasedElements; mOpenGlCacheLabelsBackup = mPlottingHints.testFlag(QCP::phCacheLabels); // create initial layers: mLayers.append(new QCPLayer(this, QLatin1String("background"))); mLayers.append(new QCPLayer(this, QLatin1String("grid"))); mLayers.append(new QCPLayer(this, QLatin1String("main"))); mLayers.append(new QCPLayer(this, QLatin1String("axes"))); mLayers.append(new QCPLayer(this, QLatin1String("legend"))); mLayers.append(new QCPLayer(this, QLatin1String("overlay"))); updateLayerIndices(); setCurrentLayer(QLatin1String("main")); layer(QLatin1String("overlay"))->setMode(QCPLayer::lmBuffered); // create initial layout, axis rect and legend: mPlotLayout = new QCPLayoutGrid; mPlotLayout->initializeParentPlot(this); mPlotLayout->setParent(this); // important because if parent is QWidget, QCPLayout::sizeConstraintsChanged will call QWidget::updateGeometry mPlotLayout->setLayer(QLatin1String("main")); QCPAxisRect *defaultAxisRect = new QCPAxisRect(this, true); mPlotLayout->addElement(0, 0, defaultAxisRect); xAxis = defaultAxisRect->axis(QCPAxis::atBottom); yAxis = defaultAxisRect->axis(QCPAxis::atLeft); xAxis2 = defaultAxisRect->axis(QCPAxis::atTop); yAxis2 = defaultAxisRect->axis(QCPAxis::atRight); legend = new QCPLegend; legend->setVisible(false); defaultAxisRect->insetLayout()->addElement(legend, Qt::AlignRight|Qt::AlignTop); defaultAxisRect->insetLayout()->setMargins(QMargins(12, 12, 12, 12)); defaultAxisRect->setLayer(QLatin1String("background")); xAxis->setLayer(QLatin1String("axes")); yAxis->setLayer(QLatin1String("axes")); xAxis2->setLayer(QLatin1String("axes")); yAxis2->setLayer(QLatin1String("axes")); xAxis->grid()->setLayer(QLatin1String("grid")); yAxis->grid()->setLayer(QLatin1String("grid")); xAxis2->grid()->setLayer(QLatin1String("grid")); yAxis2->grid()->setLayer(QLatin1String("grid")); legend->setLayer(QLatin1String("legend")); // create selection rect instance: mSelectionRect = new QCPSelectionRect(this); mSelectionRect->setLayer(QLatin1String("overlay")); setViewport(rect()); // needs to be called after mPlotLayout has been created replot(rpQueuedReplot); } QCustomPlot::~QCustomPlot() { clearPlottables(); clearItems(); if (mPlotLayout) { delete mPlotLayout; mPlotLayout = nullptr; } mCurrentLayer = nullptr; qDeleteAll(mLayers); // don't use removeLayer, because it would prevent the last layer to be removed mLayers.clear(); } /*! Sets which elements are forcibly drawn antialiased as an \a or combination of QCP::AntialiasedElement. This overrides the antialiasing settings for whole element groups, normally controlled with the \a setAntialiasing function on the individual elements. If an element is neither specified in \ref setAntialiasedElements nor in \ref setNotAntialiasedElements, the antialiasing setting on each individual element instance is used. For example, if \a antialiasedElements contains \ref QCP::aePlottables, all plottables will be drawn antialiased, no matter what the specific QCPAbstractPlottable::setAntialiased value was set to. if an element in \a antialiasedElements is already set in \ref setNotAntialiasedElements, it is removed from there. \see setNotAntialiasedElements */ void QCustomPlot::setAntialiasedElements(const QCP::AntialiasedElements &antialiasedElements) { mAntialiasedElements = antialiasedElements; // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously: if ((mNotAntialiasedElements & mAntialiasedElements) != 0) mNotAntialiasedElements |= ~mAntialiasedElements; } /*! Sets whether the specified \a antialiasedElement is forcibly drawn antialiased. See \ref setAntialiasedElements for details. \see setNotAntialiasedElement */ void QCustomPlot::setAntialiasedElement(QCP::AntialiasedElement antialiasedElement, bool enabled) { if (!enabled && mAntialiasedElements.testFlag(antialiasedElement)) mAntialiasedElements &= ~antialiasedElement; else if (enabled && !mAntialiasedElements.testFlag(antialiasedElement)) mAntialiasedElements |= antialiasedElement; // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously: if ((mNotAntialiasedElements & mAntialiasedElements) != 0) mNotAntialiasedElements |= ~mAntialiasedElements; } /*! Sets which elements are forcibly drawn not antialiased as an \a or combination of QCP::AntialiasedElement. This overrides the antialiasing settings for whole element groups, normally controlled with the \a setAntialiasing function on the individual elements. If an element is neither specified in \ref setAntialiasedElements nor in \ref setNotAntialiasedElements, the antialiasing setting on each individual element instance is used. For example, if \a notAntialiasedElements contains \ref QCP::aePlottables, no plottables will be drawn antialiased, no matter what the specific QCPAbstractPlottable::setAntialiased value was set to. if an element in \a notAntialiasedElements is already set in \ref setAntialiasedElements, it is removed from there. \see setAntialiasedElements */ void QCustomPlot::setNotAntialiasedElements(const QCP::AntialiasedElements ¬AntialiasedElements) { mNotAntialiasedElements = notAntialiasedElements; // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously: if ((mNotAntialiasedElements & mAntialiasedElements) != 0) mAntialiasedElements |= ~mNotAntialiasedElements; } /*! Sets whether the specified \a notAntialiasedElement is forcibly drawn not antialiased. See \ref setNotAntialiasedElements for details. \see setAntialiasedElement */ void QCustomPlot::setNotAntialiasedElement(QCP::AntialiasedElement notAntialiasedElement, bool enabled) { if (!enabled && mNotAntialiasedElements.testFlag(notAntialiasedElement)) mNotAntialiasedElements &= ~notAntialiasedElement; else if (enabled && !mNotAntialiasedElements.testFlag(notAntialiasedElement)) mNotAntialiasedElements |= notAntialiasedElement; // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously: if ((mNotAntialiasedElements & mAntialiasedElements) != 0) mAntialiasedElements |= ~mNotAntialiasedElements; } /*! If set to true, adding a plottable (e.g. a graph) to the QCustomPlot automatically also adds the plottable to the legend (QCustomPlot::legend). \see addGraph, QCPLegend::addItem */ void QCustomPlot::setAutoAddPlottableToLegend(bool on) { mAutoAddPlottableToLegend = on; } /*! Sets the possible interactions of this QCustomPlot as an or-combination of \ref QCP::Interaction enums. There are the following types of interactions: Axis range manipulation is controlled via \ref QCP::iRangeDrag and \ref QCP::iRangeZoom. When the respective interaction is enabled, the user may drag axes ranges and zoom with the mouse wheel. For details how to control which axes the user may drag/zoom and in what orientations, see \ref QCPAxisRect::setRangeDrag, \ref QCPAxisRect::setRangeZoom, \ref QCPAxisRect::setRangeDragAxes, \ref QCPAxisRect::setRangeZoomAxes. Plottable data selection is controlled by \ref QCP::iSelectPlottables. If \ref QCP::iSelectPlottables is set, the user may select plottables (graphs, curves, bars,...) and their data by clicking on them or in their vicinity (\ref setSelectionTolerance). Whether the user can actually select a plottable and its data can further be restricted with the \ref QCPAbstractPlottable::setSelectable method on the specific plottable. For details, see the special page about the \ref dataselection "data selection mechanism". To retrieve a list of all currently selected plottables, call \ref selectedPlottables. If you're only interested in QCPGraphs, you may use the convenience function \ref selectedGraphs. Item selection is controlled by \ref QCP::iSelectItems. If \ref QCP::iSelectItems is set, the user may select items (QCPItemLine, QCPItemText,...) by clicking on them or in their vicinity. To find out whether a specific item is selected, call QCPAbstractItem::selected(). To retrieve a list of all currently selected items, call \ref selectedItems. Axis selection is controlled with \ref QCP::iSelectAxes. If \ref QCP::iSelectAxes is set, the user may select parts of the axes by clicking on them. What parts exactly (e.g. Axis base line, tick labels, axis label) are selectable can be controlled via \ref QCPAxis::setSelectableParts for each axis. To retrieve a list of all axes that currently contain selected parts, call \ref selectedAxes. Which parts of an axis are selected, can be retrieved with QCPAxis::selectedParts(). Legend selection is controlled with \ref QCP::iSelectLegend. If this is set, the user may select the legend itself or individual items by clicking on them. What parts exactly are selectable can be controlled via \ref QCPLegend::setSelectableParts. To find out whether the legend or any of its child items are selected, check the value of QCPLegend::selectedParts. To find out which child items are selected, call \ref QCPLegend::selectedItems. All other selectable elements The selection of all other selectable objects (e.g. QCPTextElement, or your own layerable subclasses) is controlled with \ref QCP::iSelectOther. If set, the user may select those objects by clicking on them. To find out which are currently selected, you need to check their selected state explicitly. If the selection state has changed by user interaction, the \ref selectionChangedByUser signal is emitted. Each selectable object additionally emits an individual selectionChanged signal whenever their selection state has changed, i.e. not only by user interaction. To allow multiple objects to be selected by holding the selection modifier (\ref setMultiSelectModifier), set the flag \ref QCP::iMultiSelect. \note In addition to the selection mechanism presented here, QCustomPlot always emits corresponding signals, when an object is clicked or double clicked. see \ref plottableClick and \ref plottableDoubleClick for example. \see setInteraction, setSelectionTolerance */ void QCustomPlot::setInteractions(const QCP::Interactions &interactions) { mInteractions = interactions; } /*! Sets the single \a interaction of this QCustomPlot to \a enabled. For details about the interaction system, see \ref setInteractions. \see setInteractions */ void QCustomPlot::setInteraction(const QCP::Interaction &interaction, bool enabled) { if (!enabled && mInteractions.testFlag(interaction)) mInteractions &= ~interaction; else if (enabled && !mInteractions.testFlag(interaction)) mInteractions |= interaction; } /*! Sets the tolerance that is used to decide whether a click selects an object (e.g. a plottable) or not. If the user clicks in the vicinity of the line of e.g. a QCPGraph, it's only regarded as a potential selection when the minimum distance between the click position and the graph line is smaller than \a pixels. Objects that are defined by an area (e.g. QCPBars) only react to clicks directly inside the area and ignore this selection tolerance. In other words, it only has meaning for parts of objects that are too thin to exactly hit with a click and thus need such a tolerance. \see setInteractions, QCPLayerable::selectTest */ void QCustomPlot::setSelectionTolerance(int pixels) { mSelectionTolerance = pixels; } /*! Sets whether antialiasing is disabled for this QCustomPlot while the user is dragging axes ranges. If many objects, especially plottables, are drawn antialiased, this greatly improves performance during dragging. Thus it creates a more responsive user experience. As soon as the user stops dragging, the last replot is done with normal antialiasing, to restore high image quality. \see setAntialiasedElements, setNotAntialiasedElements */ void QCustomPlot::setNoAntialiasingOnDrag(bool enabled) { mNoAntialiasingOnDrag = enabled; } /*! Sets the plotting hints for this QCustomPlot instance as an \a or combination of QCP::PlottingHint. \see setPlottingHint */ void QCustomPlot::setPlottingHints(const QCP::PlottingHints &hints) { mPlottingHints = hints; } /*! Sets the specified plotting \a hint to \a enabled. \see setPlottingHints */ void QCustomPlot::setPlottingHint(QCP::PlottingHint hint, bool enabled) { QCP::PlottingHints newHints = mPlottingHints; if (!enabled) newHints &= ~hint; else newHints |= hint; if (newHints != mPlottingHints) setPlottingHints(newHints); } /*! Sets the keyboard modifier that will be recognized as multi-select-modifier. If \ref QCP::iMultiSelect is specified in \ref setInteractions, the user may select multiple objects (or data points) by clicking on them one after the other while holding down \a modifier. By default the multi-select-modifier is set to Qt::ControlModifier. \see setInteractions */ void QCustomPlot::setMultiSelectModifier(Qt::KeyboardModifier modifier) { mMultiSelectModifier = modifier; } /*! Sets how QCustomPlot processes mouse click-and-drag interactions by the user. If \a mode is \ref QCP::srmNone, the mouse drag is forwarded to the underlying objects. For example, QCPAxisRect may process a mouse drag by dragging axis ranges, see \ref QCPAxisRect::setRangeDrag. If \a mode is not \ref QCP::srmNone, the current selection rect (\ref selectionRect) becomes activated and allows e.g. rect zooming and data point selection. If you wish to provide your user both with axis range dragging and data selection/range zooming, use this method to switch between the modes just before the interaction is processed, e.g. in reaction to the \ref mousePress or \ref mouseMove signals. For example you could check whether the user is holding a certain keyboard modifier, and then decide which \a mode shall be set. If a selection rect interaction is currently active, and \a mode is set to \ref QCP::srmNone, the interaction is canceled (\ref QCPSelectionRect::cancel). Switching between any of the other modes will keep the selection rect active. Upon completion of the interaction, the behaviour is as defined by the currently set \a mode, not the mode that was set when the interaction started. \see setInteractions, setSelectionRect, QCPSelectionRect */ void QCustomPlot::setSelectionRectMode(QCP::SelectionRectMode mode) { if (mSelectionRect) { if (mode == QCP::srmNone) mSelectionRect->cancel(); // when switching to none, we immediately want to abort a potentially active selection rect // disconnect old connections: if (mSelectionRectMode == QCP::srmSelect) disconnect(mSelectionRect, SIGNAL(accepted(QRect,QMouseEvent*)), this, SLOT(processRectSelection(QRect,QMouseEvent*))); else if (mSelectionRectMode == QCP::srmZoom) disconnect(mSelectionRect, SIGNAL(accepted(QRect,QMouseEvent*)), this, SLOT(processRectZoom(QRect,QMouseEvent*))); // establish new ones: if (mode == QCP::srmSelect) connect(mSelectionRect, SIGNAL(accepted(QRect,QMouseEvent*)), this, SLOT(processRectSelection(QRect,QMouseEvent*))); else if (mode == QCP::srmZoom) connect(mSelectionRect, SIGNAL(accepted(QRect,QMouseEvent*)), this, SLOT(processRectZoom(QRect,QMouseEvent*))); } mSelectionRectMode = mode; } /*! Sets the \ref QCPSelectionRect instance that QCustomPlot will use if \a mode is not \ref QCP::srmNone and the user performs a click-and-drag interaction. QCustomPlot takes ownership of the passed \a selectionRect. It can be accessed later via \ref selectionRect. This method is useful if you wish to replace the default QCPSelectionRect instance with an instance of a QCPSelectionRect subclass, to introduce custom behaviour of the selection rect. \see setSelectionRectMode */ void QCustomPlot::setSelectionRect(QCPSelectionRect *selectionRect) { delete mSelectionRect; mSelectionRect = selectionRect; if (mSelectionRect) { // establish connections with new selection rect: if (mSelectionRectMode == QCP::srmSelect) connect(mSelectionRect, SIGNAL(accepted(QRect,QMouseEvent*)), this, SLOT(processRectSelection(QRect,QMouseEvent*))); else if (mSelectionRectMode == QCP::srmZoom) connect(mSelectionRect, SIGNAL(accepted(QRect,QMouseEvent*)), this, SLOT(processRectZoom(QRect,QMouseEvent*))); } } /*! \warning This is still an experimental feature and its performance depends on the system that it runs on. Having multiple QCustomPlot widgets in one application with enabled OpenGL rendering might cause context conflicts on some systems. This method allows to enable OpenGL plot rendering, for increased plotting performance of graphically demanding plots (thick lines, translucent fills, etc.). If \a enabled is set to true, QCustomPlot will try to initialize OpenGL and, if successful, continue plotting with hardware acceleration. The parameter \a multisampling controls how many samples will be used per pixel, it essentially controls the antialiasing quality. If \a multisampling is set too high for the current graphics hardware, the maximum allowed value will be used. You can test whether switching to OpenGL rendering was successful by checking whether the according getter \a QCustomPlot::openGl() returns true. If the OpenGL initialization fails, rendering continues with the regular software rasterizer, and an according qDebug output is generated. If switching to OpenGL was successful, this method disables label caching (\ref setPlottingHint "setPlottingHint(QCP::phCacheLabels, false)") and turns on QCustomPlot's antialiasing override for all elements (\ref setAntialiasedElements "setAntialiasedElements(QCP::aeAll)"), leading to a higher quality output. The antialiasing override allows for pixel-grid aligned drawing in the OpenGL paint device. As stated before, in OpenGL rendering the actual antialiasing of the plot is controlled with \a multisampling. If \a enabled is set to false, the antialiasing/label caching settings are restored to what they were before OpenGL was enabled, if they weren't altered in the meantime. \note OpenGL support is only enabled if QCustomPlot is compiled with the macro \c QCUSTOMPLOT_USE_OPENGL defined. This define must be set before including the QCustomPlot header both during compilation of the QCustomPlot library as well as when compiling your application. It is best to just include the line DEFINES += QCUSTOMPLOT_USE_OPENGL in the respective qmake project files. \note If you are using a Qt version before 5.0, you must also add the module "opengl" to your \c QT variable in the qmake project files. For Qt versions 5.0 and higher, QCustomPlot switches to a newer OpenGL interface which is already in the "gui" module. */ void QCustomPlot::setOpenGl(bool enabled, int multisampling) { mOpenGlMultisamples = qMax(0, multisampling); #ifdef QCUSTOMPLOT_USE_OPENGL mOpenGl = enabled; if (mOpenGl) { if (setupOpenGl()) { // backup antialiasing override and labelcaching setting so we can restore upon disabling OpenGL mOpenGlAntialiasedElementsBackup = mAntialiasedElements; mOpenGlCacheLabelsBackup = mPlottingHints.testFlag(QCP::phCacheLabels); // set antialiasing override to antialias all (aligns gl pixel grid properly), and disable label caching (would use software rasterizer for pixmap caches): setAntialiasedElements(QCP::aeAll); setPlottingHint(QCP::phCacheLabels, false); } else { qDebug() << Q_FUNC_INFO << "Failed to enable OpenGL, continuing plotting without hardware acceleration."; mOpenGl = false; } } else { // restore antialiasing override and labelcaching to what it was before enabling OpenGL, if nobody changed it in the meantime: if (mAntialiasedElements == QCP::aeAll) setAntialiasedElements(mOpenGlAntialiasedElementsBackup); if (!mPlottingHints.testFlag(QCP::phCacheLabels)) setPlottingHint(QCP::phCacheLabels, mOpenGlCacheLabelsBackup); freeOpenGl(); } // recreate all paint buffers: mPaintBuffers.clear(); setupPaintBuffers(); #else Q_UNUSED(enabled) qDebug() << Q_FUNC_INFO << "QCustomPlot can't use OpenGL because QCUSTOMPLOT_USE_OPENGL was not defined during compilation (add 'DEFINES += QCUSTOMPLOT_USE_OPENGL' to your qmake .pro file)"; #endif } /*! Sets the viewport of this QCustomPlot. Usually users of QCustomPlot don't need to change the viewport manually. The viewport is the area in which the plot is drawn. All mechanisms, e.g. margin calculation take the viewport to be the outer border of the plot. The viewport normally is the rect() of the QCustomPlot widget, i.e. a rect with top left (0, 0) and size of the QCustomPlot widget. Don't confuse the viewport with the axis rect (QCustomPlot::axisRect). An axis rect is typically an area enclosed by four axes, where the graphs/plottables are drawn in. The viewport is larger and contains also the axes themselves, their tick numbers, their labels, or even additional axis rects, color scales and other layout elements. This function is used to allow arbitrary size exports with \ref toPixmap, \ref savePng, \ref savePdf, etc. by temporarily changing the viewport size. */ void QCustomPlot::setViewport(const QRect &rect) { mViewport = rect; if (mPlotLayout) mPlotLayout->setOuterRect(mViewport); } /*! Sets the device pixel ratio used by the paint buffers of this QCustomPlot instance. Normally, this doesn't need to be set manually, because it is initialized with the regular \a QWidget::devicePixelRatio which is configured by Qt to fit the display device (e.g. 1 for normal displays, 2 for High-DPI displays). Device pixel ratios are supported by Qt only for Qt versions since 5.4. If this method is called when QCustomPlot is being used with older Qt versions, outputs an according qDebug message and leaves the internal buffer device pixel ratio at 1.0. */ void QCustomPlot::setBufferDevicePixelRatio(double ratio) { if (!qFuzzyCompare(ratio, mBufferDevicePixelRatio)) { #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED mBufferDevicePixelRatio = ratio; foreach (QSharedPointer buffer, mPaintBuffers) buffer->setDevicePixelRatio(mBufferDevicePixelRatio); // Note: axis label cache has devicePixelRatio as part of cache hash, so no need to manually clear cache here #else qDebug() << Q_FUNC_INFO << "Device pixel ratios not supported for Qt versions before 5.4"; mBufferDevicePixelRatio = 1.0; #endif } } /*! Sets \a pm as the viewport background pixmap (see \ref setViewport). The pixmap is always drawn below all other objects in the plot. For cases where the provided pixmap doesn't have the same size as the viewport, scaling can be enabled with \ref setBackgroundScaled and the scaling mode (whether and how the aspect ratio is preserved) can be set with \ref setBackgroundScaledMode. To set all these options in one call, consider using the overloaded version of this function. If a background brush was set with \ref setBackground(const QBrush &brush), the viewport will first be filled with that brush, before drawing the background pixmap. This can be useful for background pixmaps with translucent areas. \see setBackgroundScaled, setBackgroundScaledMode */ void QCustomPlot::setBackground(const QPixmap &pm) { mBackgroundPixmap = pm; mScaledBackgroundPixmap = QPixmap(); } /*! Sets the background brush of the viewport (see \ref setViewport). Before drawing everything else, the background is filled with \a brush. If a background pixmap was set with \ref setBackground(const QPixmap &pm), this brush will be used to fill the viewport before the background pixmap is drawn. This can be useful for background pixmaps with translucent areas. Set \a brush to Qt::NoBrush or Qt::Transparent to leave background transparent. This can be useful for exporting to image formats which support transparency, e.g. \ref savePng. \see setBackgroundScaled, setBackgroundScaledMode */ void QCustomPlot::setBackground(const QBrush &brush) { mBackgroundBrush = brush; } /*! \overload Allows setting the background pixmap of the viewport, whether it shall be scaled and how it shall be scaled in one call. \see setBackground(const QPixmap &pm), setBackgroundScaled, setBackgroundScaledMode */ void QCustomPlot::setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode) { mBackgroundPixmap = pm; mScaledBackgroundPixmap = QPixmap(); mBackgroundScaled = scaled; mBackgroundScaledMode = mode; } /*! Sets whether the viewport background pixmap shall be scaled to fit the viewport. If \a scaled is set to true, control whether and how the aspect ratio of the original pixmap is preserved with \ref setBackgroundScaledMode. Note that the scaled version of the original pixmap is buffered, so there is no performance penalty on replots. (Except when the viewport dimensions are changed continuously.) \see setBackground, setBackgroundScaledMode */ void QCustomPlot::setBackgroundScaled(bool scaled) { mBackgroundScaled = scaled; } /*! If scaling of the viewport background pixmap is enabled (\ref setBackgroundScaled), use this function to define whether and how the aspect ratio of the original pixmap is preserved. \see setBackground, setBackgroundScaled */ void QCustomPlot::setBackgroundScaledMode(Qt::AspectRatioMode mode) { mBackgroundScaledMode = mode; } /*! Returns the plottable with \a index. If the index is invalid, returns \c nullptr. There is an overloaded version of this function with no parameter which returns the last added plottable, see QCustomPlot::plottable() \see plottableCount */ QCPAbstractPlottable *QCustomPlot::plottable(int index) { if (index >= 0 && index < mPlottables.size()) { return mPlottables.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return nullptr; } } /*! \overload Returns the last plottable that was added to the plot. If there are no plottables in the plot, returns \c nullptr. \see plottableCount */ QCPAbstractPlottable *QCustomPlot::plottable() { if (!mPlottables.isEmpty()) { return mPlottables.last(); } else return nullptr; } /*! Removes the specified plottable from the plot and deletes it. If necessary, the corresponding legend item is also removed from the default legend (QCustomPlot::legend). Returns true on success. \see clearPlottables */ bool QCustomPlot::removePlottable(QCPAbstractPlottable *plottable) { if (!mPlottables.contains(plottable)) { qDebug() << Q_FUNC_INFO << "plottable not in list:" << reinterpret_cast(plottable); return false; } // remove plottable from legend: plottable->removeFromLegend(); // special handling for QCPGraphs to maintain the simple graph interface: if (QCPGraph *graph = qobject_cast(plottable)) mGraphs.removeOne(graph); // remove plottable: delete plottable; mPlottables.removeOne(plottable); return true; } /*! \overload Removes and deletes the plottable by its \a index. */ bool QCustomPlot::removePlottable(int index) { if (index >= 0 && index < mPlottables.size()) return removePlottable(mPlottables[index]); else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return false; } } /*! Removes all plottables from the plot and deletes them. Corresponding legend items are also removed from the default legend (QCustomPlot::legend). Returns the number of plottables removed. \see removePlottable */ int QCustomPlot::clearPlottables() { int c = mPlottables.size(); for (int i=c-1; i >= 0; --i) removePlottable(mPlottables[i]); return c; } /*! Returns the number of currently existing plottables in the plot \see plottable */ int QCustomPlot::plottableCount() const { return mPlottables.size(); } /*! Returns a list of the selected plottables. If no plottables are currently selected, the list is empty. There is a convenience function if you're only interested in selected graphs, see \ref selectedGraphs. \see setInteractions, QCPAbstractPlottable::setSelectable, QCPAbstractPlottable::setSelection */ QList QCustomPlot::selectedPlottables() const { QList result; foreach (QCPAbstractPlottable *plottable, mPlottables) { if (plottable->selected()) result.append(plottable); } return result; } /*! Returns any plottable at the pixel position \a pos. Since it can capture all plottables, the return type is the abstract base class of all plottables, QCPAbstractPlottable. For details, and if you wish to specify a certain plottable type (e.g. QCPGraph), see the template method plottableAt() \see plottableAt(), itemAt, layoutElementAt */ QCPAbstractPlottable *QCustomPlot::plottableAt(const QPointF &pos, bool onlySelectable, int *dataIndex) const { return plottableAt(pos, onlySelectable, dataIndex); } /*! Returns whether this QCustomPlot instance contains the \a plottable. */ bool QCustomPlot::hasPlottable(QCPAbstractPlottable *plottable) const { return mPlottables.contains(plottable); } /*! Returns the graph with \a index. If the index is invalid, returns \c nullptr. There is an overloaded version of this function with no parameter which returns the last created graph, see QCustomPlot::graph() \see graphCount, addGraph */ QCPGraph *QCustomPlot::graph(int index) const { if (index >= 0 && index < mGraphs.size()) { return mGraphs.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return nullptr; } } /*! \overload Returns the last graph, that was created with \ref addGraph. If there are no graphs in the plot, returns \c nullptr. \see graphCount, addGraph */ QCPGraph *QCustomPlot::graph() const { if (!mGraphs.isEmpty()) { return mGraphs.last(); } else return nullptr; } /*! Creates a new graph inside the plot. If \a keyAxis and \a valueAxis are left unspecified (0), the bottom (xAxis) is used as key and the left (yAxis) is used as value axis. If specified, \a keyAxis and \a valueAxis must reside in this QCustomPlot. \a keyAxis will be used as key axis (typically "x") and \a valueAxis as value axis (typically "y") for the graph. Returns a pointer to the newly created graph, or \c nullptr if adding the graph failed. \see graph, graphCount, removeGraph, clearGraphs */ QCPGraph *QCustomPlot::addGraph(QCPAxis *keyAxis, QCPAxis *valueAxis) { if (!keyAxis) keyAxis = xAxis; if (!valueAxis) valueAxis = yAxis; if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "can't use default QCustomPlot xAxis or yAxis, because at least one is invalid (has been deleted)"; return nullptr; } if (keyAxis->parentPlot() != this || valueAxis->parentPlot() != this) { qDebug() << Q_FUNC_INFO << "passed keyAxis or valueAxis doesn't have this QCustomPlot as parent"; return nullptr; } QCPGraph *newGraph = new QCPGraph(keyAxis, valueAxis); newGraph->setName(QLatin1String("Graph ")+QString::number(mGraphs.size())); return newGraph; } /*! Removes the specified \a graph from the plot and deletes it. If necessary, the corresponding legend item is also removed from the default legend (QCustomPlot::legend). If any other graphs in the plot have a channel fill set towards the removed graph, the channel fill property of those graphs is reset to \c nullptr (no channel fill). Returns true on success. \see clearGraphs */ bool QCustomPlot::removeGraph(QCPGraph *graph) { return removePlottable(graph); } /*! \overload Removes and deletes the graph by its \a index. */ bool QCustomPlot::removeGraph(int index) { if (index >= 0 && index < mGraphs.size()) return removeGraph(mGraphs[index]); else return false; } /*! Removes all graphs from the plot and deletes them. Corresponding legend items are also removed from the default legend (QCustomPlot::legend). Returns the number of graphs removed. \see removeGraph */ int QCustomPlot::clearGraphs() { int c = mGraphs.size(); for (int i=c-1; i >= 0; --i) removeGraph(mGraphs[i]); return c; } /*! Returns the number of currently existing graphs in the plot \see graph, addGraph */ int QCustomPlot::graphCount() const { return mGraphs.size(); } /*! Returns a list of the selected graphs. If no graphs are currently selected, the list is empty. If you are not only interested in selected graphs but other plottables like QCPCurve, QCPBars, etc., use \ref selectedPlottables. \see setInteractions, selectedPlottables, QCPAbstractPlottable::setSelectable, QCPAbstractPlottable::setSelection */ QList QCustomPlot::selectedGraphs() const { QList result; foreach (QCPGraph *graph, mGraphs) { if (graph->selected()) result.append(graph); } return result; } /*! Returns the item with \a index. If the index is invalid, returns \c nullptr. There is an overloaded version of this function with no parameter which returns the last added item, see QCustomPlot::item() \see itemCount */ QCPAbstractItem *QCustomPlot::item(int index) const { if (index >= 0 && index < mItems.size()) { return mItems.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return nullptr; } } /*! \overload Returns the last item that was added to this plot. If there are no items in the plot, returns \c nullptr. \see itemCount */ QCPAbstractItem *QCustomPlot::item() const { if (!mItems.isEmpty()) { return mItems.last(); } else return nullptr; } /*! Removes the specified item from the plot and deletes it. Returns true on success. \see clearItems */ bool QCustomPlot::removeItem(QCPAbstractItem *item) { if (mItems.contains(item)) { delete item; mItems.removeOne(item); return true; } else { qDebug() << Q_FUNC_INFO << "item not in list:" << reinterpret_cast(item); return false; } } /*! \overload Removes and deletes the item by its \a index. */ bool QCustomPlot::removeItem(int index) { if (index >= 0 && index < mItems.size()) return removeItem(mItems[index]); else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return false; } } /*! Removes all items from the plot and deletes them. Returns the number of items removed. \see removeItem */ int QCustomPlot::clearItems() { int c = mItems.size(); for (int i=c-1; i >= 0; --i) removeItem(mItems[i]); return c; } /*! Returns the number of currently existing items in the plot \see item */ int QCustomPlot::itemCount() const { return mItems.size(); } /*! Returns a list of the selected items. If no items are currently selected, the list is empty. \see setInteractions, QCPAbstractItem::setSelectable, QCPAbstractItem::setSelected */ QList QCustomPlot::selectedItems() const { QList result; foreach (QCPAbstractItem *item, mItems) { if (item->selected()) result.append(item); } return result; } /*! Returns the item at the pixel position \a pos. Since it can capture all items, the return type is the abstract base class of all items, QCPAbstractItem. For details, and if you wish to specify a certain item type (e.g. QCPItemLine), see the template method itemAt() \see itemAt(), plottableAt, layoutElementAt */ QCPAbstractItem *QCustomPlot::itemAt(const QPointF &pos, bool onlySelectable) const { return itemAt(pos, onlySelectable); } /*! Returns whether this QCustomPlot contains the \a item. \see item */ bool QCustomPlot::hasItem(QCPAbstractItem *item) const { return mItems.contains(item); } /*! Returns the layer with the specified \a name. If there is no layer with the specified name, \c nullptr is returned. Layer names are case-sensitive. \see addLayer, moveLayer, removeLayer */ QCPLayer *QCustomPlot::layer(const QString &name) const { foreach (QCPLayer *layer, mLayers) { if (layer->name() == name) return layer; } return nullptr; } /*! \overload Returns the layer by \a index. If the index is invalid, \c nullptr is returned. \see addLayer, moveLayer, removeLayer */ QCPLayer *QCustomPlot::layer(int index) const { if (index >= 0 && index < mLayers.size()) { return mLayers.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return nullptr; } } /*! Returns the layer that is set as current layer (see \ref setCurrentLayer). */ QCPLayer *QCustomPlot::currentLayer() const { return mCurrentLayer; } /*! Sets the layer with the specified \a name to be the current layer. All layerables (\ref QCPLayerable), e.g. plottables and items, are created on the current layer. Returns true on success, i.e. if there is a layer with the specified \a name in the QCustomPlot. Layer names are case-sensitive. \see addLayer, moveLayer, removeLayer, QCPLayerable::setLayer */ bool QCustomPlot::setCurrentLayer(const QString &name) { if (QCPLayer *newCurrentLayer = layer(name)) { return setCurrentLayer(newCurrentLayer); } else { qDebug() << Q_FUNC_INFO << "layer with name doesn't exist:" << name; return false; } } /*! \overload Sets the provided \a layer to be the current layer. Returns true on success, i.e. when \a layer is a valid layer in the QCustomPlot. \see addLayer, moveLayer, removeLayer */ bool QCustomPlot::setCurrentLayer(QCPLayer *layer) { if (!mLayers.contains(layer)) { qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast(layer); return false; } mCurrentLayer = layer; return true; } /*! Returns the number of currently existing layers in the plot \see layer, addLayer */ int QCustomPlot::layerCount() const { return mLayers.size(); } /*! Adds a new layer to this QCustomPlot instance. The new layer will have the name \a name, which must be unique. Depending on \a insertMode, it is positioned either below or above \a otherLayer. Returns true on success, i.e. if there is no other layer named \a name and \a otherLayer is a valid layer inside this QCustomPlot. If \a otherLayer is 0, the highest layer in the QCustomPlot will be used. For an explanation of what layers are in QCustomPlot, see the documentation of \ref QCPLayer. \see layer, moveLayer, removeLayer */ bool QCustomPlot::addLayer(const QString &name, QCPLayer *otherLayer, QCustomPlot::LayerInsertMode insertMode) { if (!otherLayer) otherLayer = mLayers.last(); if (!mLayers.contains(otherLayer)) { qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast(otherLayer); return false; } if (layer(name)) { qDebug() << Q_FUNC_INFO << "A layer exists already with the name" << name; return false; } QCPLayer *newLayer = new QCPLayer(this, name); mLayers.insert(otherLayer->index() + (insertMode==limAbove ? 1:0), newLayer); updateLayerIndices(); setupPaintBuffers(); // associates new layer with the appropriate paint buffer return true; } /*! Removes the specified \a layer and returns true on success. All layerables (e.g. plottables and items) on the removed layer will be moved to the layer below \a layer. If \a layer is the bottom layer, the layerables are moved to the layer above. In both cases, the total rendering order of all layerables in the QCustomPlot is preserved. If \a layer is the current layer (\ref setCurrentLayer), the layer below (or above, if bottom layer) becomes the new current layer. It is not possible to remove the last layer of the plot. \see layer, addLayer, moveLayer */ bool QCustomPlot::removeLayer(QCPLayer *layer) { if (!mLayers.contains(layer)) { qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast(layer); return false; } if (mLayers.size() < 2) { qDebug() << Q_FUNC_INFO << "can't remove last layer"; return false; } // append all children of this layer to layer below (if this is lowest layer, prepend to layer above) int removedIndex = layer->index(); bool isFirstLayer = removedIndex==0; QCPLayer *targetLayer = isFirstLayer ? mLayers.at(removedIndex+1) : mLayers.at(removedIndex-1); QList children = layer->children(); if (isFirstLayer) // prepend in reverse order (such that relative order stays the same) std::reverse(children.begin(), children.end()); foreach (QCPLayerable *child, children) child->moveToLayer(targetLayer, isFirstLayer); // prepend if isFirstLayer, otherwise append // if removed layer is current layer, change current layer to layer below/above: if (layer == mCurrentLayer) setCurrentLayer(targetLayer); // invalidate the paint buffer that was responsible for this layer: if (QSharedPointer pb = layer->mPaintBuffer.toStrongRef()) pb->setInvalidated(); // remove layer: delete layer; mLayers.removeOne(layer); updateLayerIndices(); return true; } /*! Moves the specified \a layer either above or below \a otherLayer. Whether it's placed above or below is controlled with \a insertMode. Returns true on success, i.e. when both \a layer and \a otherLayer are valid layers in the QCustomPlot. \see layer, addLayer, moveLayer */ bool QCustomPlot::moveLayer(QCPLayer *layer, QCPLayer *otherLayer, QCustomPlot::LayerInsertMode insertMode) { if (!mLayers.contains(layer)) { qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast(layer); return false; } if (!mLayers.contains(otherLayer)) { qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast(otherLayer); return false; } if (layer->index() > otherLayer->index()) mLayers.move(layer->index(), otherLayer->index() + (insertMode==limAbove ? 1:0)); else if (layer->index() < otherLayer->index()) mLayers.move(layer->index(), otherLayer->index() + (insertMode==limAbove ? 0:-1)); // invalidate the paint buffers that are responsible for the layers: if (QSharedPointer pb = layer->mPaintBuffer.toStrongRef()) pb->setInvalidated(); if (QSharedPointer pb = otherLayer->mPaintBuffer.toStrongRef()) pb->setInvalidated(); updateLayerIndices(); return true; } /*! Returns the number of axis rects in the plot. All axis rects can be accessed via QCustomPlot::axisRect(). Initially, only one axis rect exists in the plot. \see axisRect, axisRects */ int QCustomPlot::axisRectCount() const { return axisRects().size(); } /*! Returns the axis rect with \a index. Initially, only one axis rect (with index 0) exists in the plot. If multiple axis rects were added, all of them may be accessed with this function in a linear fashion (even when they are nested in a layout hierarchy or inside other axis rects via QCPAxisRect::insetLayout). The order of the axis rects is given by the fill order of the \ref QCPLayout that is holding them. For example, if the axis rects are in the top level grid layout (accessible via \ref QCustomPlot::plotLayout), they are ordered from left to right, top to bottom, if the layout's default \ref QCPLayoutGrid::setFillOrder "setFillOrder" of \ref QCPLayoutGrid::foColumnsFirst "foColumnsFirst" wasn't changed. If you want to access axis rects by their row and column index, use the layout interface. For example, use \ref QCPLayoutGrid::element of the top level grid layout, and \c qobject_cast the returned layout element to \ref QCPAxisRect. (See also \ref thelayoutsystem.) \see axisRectCount, axisRects, QCPLayoutGrid::setFillOrder */ QCPAxisRect *QCustomPlot::axisRect(int index) const { const QList rectList = axisRects(); if (index >= 0 && index < rectList.size()) { return rectList.at(index); } else { qDebug() << Q_FUNC_INFO << "invalid axis rect index" << index; return nullptr; } } /*! Returns all axis rects in the plot. The order of the axis rects is given by the fill order of the \ref QCPLayout that is holding them. For example, if the axis rects are in the top level grid layout (accessible via \ref QCustomPlot::plotLayout), they are ordered from left to right, top to bottom, if the layout's default \ref QCPLayoutGrid::setFillOrder "setFillOrder" of \ref QCPLayoutGrid::foColumnsFirst "foColumnsFirst" wasn't changed. \see axisRectCount, axisRect, QCPLayoutGrid::setFillOrder */ QList QCustomPlot::axisRects() const { QList result; QStack elementStack; if (mPlotLayout) elementStack.push(mPlotLayout); while (!elementStack.isEmpty()) { foreach (QCPLayoutElement *element, elementStack.pop()->elements(false)) { if (element) { elementStack.push(element); if (QCPAxisRect *ar = qobject_cast(element)) result.append(ar); } } } return result; } /*! Returns the layout element at pixel position \a pos. If there is no element at that position, returns \c nullptr. Only visible elements are used. If \ref QCPLayoutElement::setVisible on the element itself or on any of its parent elements is set to false, it will not be considered. \see itemAt, plottableAt */ QCPLayoutElement *QCustomPlot::layoutElementAt(const QPointF &pos) const { QCPLayoutElement *currentElement = mPlotLayout; bool searchSubElements = true; while (searchSubElements && currentElement) { searchSubElements = false; foreach (QCPLayoutElement *subElement, currentElement->elements(false)) { if (subElement && subElement->realVisibility() && subElement->selectTest(pos, false) >= 0) { currentElement = subElement; searchSubElements = true; break; } } } return currentElement; } /*! Returns the layout element of type \ref QCPAxisRect at pixel position \a pos. This method ignores other layout elements even if they are visually in front of the axis rect (e.g. a \ref QCPLegend). If there is no axis rect at that position, returns \c nullptr. Only visible axis rects are used. If \ref QCPLayoutElement::setVisible on the axis rect itself or on any of its parent elements is set to false, it will not be considered. \see layoutElementAt */ QCPAxisRect *QCustomPlot::axisRectAt(const QPointF &pos) const { QCPAxisRect *result = nullptr; QCPLayoutElement *currentElement = mPlotLayout; bool searchSubElements = true; while (searchSubElements && currentElement) { searchSubElements = false; foreach (QCPLayoutElement *subElement, currentElement->elements(false)) { if (subElement && subElement->realVisibility() && subElement->selectTest(pos, false) >= 0) { currentElement = subElement; searchSubElements = true; if (QCPAxisRect *ar = qobject_cast(currentElement)) result = ar; break; } } } return result; } /*! Returns the axes that currently have selected parts, i.e. whose selection state is not \ref QCPAxis::spNone. \see selectedPlottables, selectedLegends, setInteractions, QCPAxis::setSelectedParts, QCPAxis::setSelectableParts */ QList QCustomPlot::selectedAxes() const { QList result, allAxes; foreach (QCPAxisRect *rect, axisRects()) allAxes << rect->axes(); foreach (QCPAxis *axis, allAxes) { if (axis->selectedParts() != QCPAxis::spNone) result.append(axis); } return result; } /*! Returns the legends that currently have selected parts, i.e. whose selection state is not \ref QCPLegend::spNone. \see selectedPlottables, selectedAxes, setInteractions, QCPLegend::setSelectedParts, QCPLegend::setSelectableParts, QCPLegend::selectedItems */ QList QCustomPlot::selectedLegends() const { QList result; QStack elementStack; if (mPlotLayout) elementStack.push(mPlotLayout); while (!elementStack.isEmpty()) { foreach (QCPLayoutElement *subElement, elementStack.pop()->elements(false)) { if (subElement) { elementStack.push(subElement); if (QCPLegend *leg = qobject_cast(subElement)) { if (leg->selectedParts() != QCPLegend::spNone) result.append(leg); } } } } return result; } /*! Deselects all layerables (plottables, items, axes, legends,...) of the QCustomPlot. Since calling this function is not a user interaction, this does not emit the \ref selectionChangedByUser signal. The individual selectionChanged signals are emitted though, if the objects were previously selected. \see setInteractions, selectedPlottables, selectedItems, selectedAxes, selectedLegends */ void QCustomPlot::deselectAll() { foreach (QCPLayer *layer, mLayers) { foreach (QCPLayerable *layerable, layer->children()) layerable->deselectEvent(nullptr); } } /*! Causes a complete replot into the internal paint buffer(s). Finally, the widget surface is refreshed with the new buffer contents. This is the method that must be called to make changes to the plot, e.g. on the axis ranges or data points of graphs, visible. The parameter \a refreshPriority can be used to fine-tune the timing of the replot. For example if your application calls \ref replot very quickly in succession (e.g. multiple independent functions change some aspects of the plot and each wants to make sure the change gets replotted), it is advisable to set \a refreshPriority to \ref QCustomPlot::rpQueuedReplot. This way, the actual replotting is deferred to the next event loop iteration. Multiple successive calls of \ref replot with this priority will only cause a single replot, avoiding redundant replots and improving performance. Under a few circumstances, QCustomPlot causes a replot by itself. Those are resize events of the QCustomPlot widget and user interactions (object selection and range dragging/zooming). Before the replot happens, the signal \ref beforeReplot is emitted. After the replot, \ref afterReplot is emitted. It is safe to mutually connect the replot slot with any of those two signals on two QCustomPlots to make them replot synchronously, it won't cause an infinite recursion. If a layer is in mode \ref QCPLayer::lmBuffered (\ref QCPLayer::setMode), it is also possible to replot only that specific layer via \ref QCPLayer::replot. See the documentation there for details. \see replotTime */ void QCustomPlot::replot(QCustomPlot::RefreshPriority refreshPriority) { if (refreshPriority == QCustomPlot::rpQueuedReplot) { if (!mReplotQueued) { mReplotQueued = true; QTimer::singleShot(0, this, SLOT(replot())); } return; } if (mReplotting) // incase signals loop back to replot slot return; mReplotting = true; mReplotQueued = false; emit beforeReplot(); # if QT_VERSION < QT_VERSION_CHECK(4, 8, 0) QTime replotTimer; replotTimer.start(); # else QElapsedTimer replotTimer; replotTimer.start(); # endif updateLayout(); // draw all layered objects (grid, axes, plottables, items, legend,...) into their buffers: setupPaintBuffers(); foreach (QCPLayer *layer, mLayers) layer->drawToPaintBuffer(); foreach (QSharedPointer buffer, mPaintBuffers) buffer->setInvalidated(false); if ((refreshPriority == rpRefreshHint && mPlottingHints.testFlag(QCP::phImmediateRefresh)) || refreshPriority==rpImmediateRefresh) repaint(); else update(); # if QT_VERSION < QT_VERSION_CHECK(4, 8, 0) mReplotTime = replotTimer.elapsed(); # else mReplotTime = replotTimer.nsecsElapsed()*1e-6; # endif if (!qFuzzyIsNull(mReplotTimeAverage)) mReplotTimeAverage = mReplotTimeAverage*0.9 + mReplotTime*0.1; // exponential moving average with a time constant of 10 last replots else mReplotTimeAverage = mReplotTime; // no previous replots to average with, so initialize with replot time emit afterReplot(); mReplotting = false; } /*! Returns the time in milliseconds that the last replot took. If \a average is set to true, an exponential moving average over the last couple of replots is returned. \see replot */ double QCustomPlot::replotTime(bool average) const { return average ? mReplotTimeAverage : mReplotTime; } /*! Rescales the axes such that all plottables (like graphs) in the plot are fully visible. if \a onlyVisiblePlottables is set to true, only the plottables that have their visibility set to true (QCPLayerable::setVisible), will be used to rescale the axes. \see QCPAbstractPlottable::rescaleAxes, QCPAxis::rescale */ void QCustomPlot::rescaleAxes(bool onlyVisiblePlottables) { QList allAxes; foreach (QCPAxisRect *rect, axisRects()) allAxes << rect->axes(); foreach (QCPAxis *axis, allAxes) axis->rescale(onlyVisiblePlottables); } /*! Saves a PDF with the vectorized plot to the file \a fileName. The axis ratio as well as the scale of texts and lines will be derived from the specified \a width and \a height. This means, the output will look like the normal on-screen output of a QCustomPlot widget with the corresponding pixel width and height. If either \a width or \a height is zero, the exported image will have the same dimensions as the QCustomPlot widget currently has. Setting \a exportPen to \ref QCP::epNoCosmetic allows to disable the use of cosmetic pens when drawing to the PDF file. Cosmetic pens are pens with numerical width 0, which are always drawn as a one pixel wide line, no matter what zoom factor is set in the PDF-Viewer. For more information about cosmetic pens, see the QPainter and QPen documentation. The objects of the plot will appear in the current selection state. If you don't want any selected objects to be painted in their selected look, deselect everything with \ref deselectAll before calling this function. Returns true on success. \warning \li If you plan on editing the exported PDF file with a vector graphics editor like Inkscape, it is advised to set \a exportPen to \ref QCP::epNoCosmetic to avoid losing those cosmetic lines (which might be quite many, because cosmetic pens are the default for e.g. axes and tick marks). \li If calling this function inside the constructor of the parent of the QCustomPlot widget (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this function uses the current width and height of the QCustomPlot widget. However, in Qt, these aren't defined yet inside the constructor, so you would get an image that has strange widths/heights. \a pdfCreator and \a pdfTitle may be used to set the according metadata fields in the resulting PDF file. \note On Android systems, this method does nothing and issues an according qDebug warning message. This is also the case if for other reasons the define flag \c QT_NO_PRINTER is set. \see savePng, saveBmp, saveJpg, saveRastered */ bool QCustomPlot::savePdf(const QString &fileName, int width, int height, QCP::ExportPen exportPen, const QString &pdfCreator, const QString &pdfTitle) { bool success = false; #ifdef QT_NO_PRINTER Q_UNUSED(fileName) Q_UNUSED(exportPen) Q_UNUSED(width) Q_UNUSED(height) Q_UNUSED(pdfCreator) Q_UNUSED(pdfTitle) qDebug() << Q_FUNC_INFO << "Qt was built without printer support (QT_NO_PRINTER). PDF not created."; #else int newWidth, newHeight; if (width == 0 || height == 0) { newWidth = this->width(); newHeight = this->height(); } else { newWidth = width; newHeight = height; } QPrinter printer(QPrinter::ScreenResolution); printer.setOutputFileName(fileName); printer.setOutputFormat(QPrinter::PdfFormat); printer.setColorMode(QPrinter::Color); printer.printEngine()->setProperty(QPrintEngine::PPK_Creator, pdfCreator); printer.printEngine()->setProperty(QPrintEngine::PPK_DocumentName, pdfTitle); QRect oldViewport = viewport(); setViewport(QRect(0, 0, newWidth, newHeight)); #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0) printer.setFullPage(true); printer.setPaperSize(viewport().size(), QPrinter::DevicePixel); #else QPageLayout pageLayout; pageLayout.setMode(QPageLayout::FullPageMode); pageLayout.setOrientation(QPageLayout::Portrait); pageLayout.setMargins(QMarginsF(0, 0, 0, 0)); pageLayout.setPageSize(QPageSize(viewport().size(), QPageSize::Point, QString(), QPageSize::ExactMatch)); printer.setPageLayout(pageLayout); #endif QCPPainter printpainter; if (printpainter.begin(&printer)) { printpainter.setMode(QCPPainter::pmVectorized); printpainter.setMode(QCPPainter::pmNoCaching); printpainter.setMode(QCPPainter::pmNonCosmetic, exportPen==QCP::epNoCosmetic); printpainter.setWindow(mViewport); if (mBackgroundBrush.style() != Qt::NoBrush && mBackgroundBrush.color() != Qt::white && mBackgroundBrush.color() != Qt::transparent && mBackgroundBrush.color().alpha() > 0) // draw pdf background color if not white/transparent printpainter.fillRect(viewport(), mBackgroundBrush); draw(&printpainter); printpainter.end(); success = true; } setViewport(oldViewport); #endif // QT_NO_PRINTER return success; } /*! Saves a PNG image file to \a fileName on disc. The output plot will have the dimensions \a width and \a height in pixels, multiplied by \a scale. If either \a width or \a height is zero, the current width and height of the QCustomPlot widget is used instead. Line widths and texts etc. are not scaled up when larger widths/heights are used. If you want that effect, use the \a scale parameter. For example, if you set both \a width and \a height to 100 and \a scale to 2, you will end up with an image file of size 200*200 in which all graphical elements are scaled up by factor 2 (line widths, texts, etc.). This scaling is not done by stretching a 100*100 image, the result will have full 200*200 pixel resolution. If you use a high scaling factor, it is recommended to enable antialiasing for all elements by temporarily setting \ref QCustomPlot::setAntialiasedElements to \ref QCP::aeAll as this allows QCustomPlot to place objects with sub-pixel accuracy. image compression can be controlled with the \a quality parameter which must be between 0 and 100 or -1 to use the default setting. The \a resolution will be written to the image file header and has no direct consequence for the quality or the pixel size. However, if opening the image with a tool which respects the metadata, it will be able to scale the image to match either a given size in real units of length (inch, centimeters, etc.), or the target display DPI. You can specify in which units \a resolution is given, by setting \a resolutionUnit. The \a resolution is converted to the format's expected resolution unit internally. Returns true on success. If this function fails, most likely the PNG format isn't supported by the system, see Qt docs about QImageWriter::supportedImageFormats(). The objects of the plot will appear in the current selection state. If you don't want any selected objects to be painted in their selected look, deselect everything with \ref deselectAll before calling this function. If you want the PNG to have a transparent background, call \ref setBackground(const QBrush &brush) with no brush (Qt::NoBrush) or a transparent color (Qt::transparent), before saving. \warning If calling this function inside the constructor of the parent of the QCustomPlot widget (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this function uses the current width and height of the QCustomPlot widget. However, in Qt, these aren't defined yet inside the constructor, so you would get an image that has strange widths/heights. \see savePdf, saveBmp, saveJpg, saveRastered */ bool QCustomPlot::savePng(const QString &fileName, int width, int height, double scale, int quality, int resolution, QCP::ResolutionUnit resolutionUnit) { return saveRastered(fileName, width, height, scale, "PNG", quality, resolution, resolutionUnit); } /*! Saves a JPEG image file to \a fileName on disc. The output plot will have the dimensions \a width and \a height in pixels, multiplied by \a scale. If either \a width or \a height is zero, the current width and height of the QCustomPlot widget is used instead. Line widths and texts etc. are not scaled up when larger widths/heights are used. If you want that effect, use the \a scale parameter. For example, if you set both \a width and \a height to 100 and \a scale to 2, you will end up with an image file of size 200*200 in which all graphical elements are scaled up by factor 2 (line widths, texts, etc.). This scaling is not done by stretching a 100*100 image, the result will have full 200*200 pixel resolution. If you use a high scaling factor, it is recommended to enable antialiasing for all elements by temporarily setting \ref QCustomPlot::setAntialiasedElements to \ref QCP::aeAll as this allows QCustomPlot to place objects with sub-pixel accuracy. image compression can be controlled with the \a quality parameter which must be between 0 and 100 or -1 to use the default setting. The \a resolution will be written to the image file header and has no direct consequence for the quality or the pixel size. However, if opening the image with a tool which respects the metadata, it will be able to scale the image to match either a given size in real units of length (inch, centimeters, etc.), or the target display DPI. You can specify in which units \a resolution is given, by setting \a resolutionUnit. The \a resolution is converted to the format's expected resolution unit internally. Returns true on success. If this function fails, most likely the JPEG format isn't supported by the system, see Qt docs about QImageWriter::supportedImageFormats(). The objects of the plot will appear in the current selection state. If you don't want any selected objects to be painted in their selected look, deselect everything with \ref deselectAll before calling this function. \warning If calling this function inside the constructor of the parent of the QCustomPlot widget (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this function uses the current width and height of the QCustomPlot widget. However, in Qt, these aren't defined yet inside the constructor, so you would get an image that has strange widths/heights. \see savePdf, savePng, saveBmp, saveRastered */ bool QCustomPlot::saveJpg(const QString &fileName, int width, int height, double scale, int quality, int resolution, QCP::ResolutionUnit resolutionUnit) { return saveRastered(fileName, width, height, scale, "JPG", quality, resolution, resolutionUnit); } /*! Saves a BMP image file to \a fileName on disc. The output plot will have the dimensions \a width and \a height in pixels, multiplied by \a scale. If either \a width or \a height is zero, the current width and height of the QCustomPlot widget is used instead. Line widths and texts etc. are not scaled up when larger widths/heights are used. If you want that effect, use the \a scale parameter. For example, if you set both \a width and \a height to 100 and \a scale to 2, you will end up with an image file of size 200*200 in which all graphical elements are scaled up by factor 2 (line widths, texts, etc.). This scaling is not done by stretching a 100*100 image, the result will have full 200*200 pixel resolution. If you use a high scaling factor, it is recommended to enable antialiasing for all elements by temporarily setting \ref QCustomPlot::setAntialiasedElements to \ref QCP::aeAll as this allows QCustomPlot to place objects with sub-pixel accuracy. The \a resolution will be written to the image file header and has no direct consequence for the quality or the pixel size. However, if opening the image with a tool which respects the metadata, it will be able to scale the image to match either a given size in real units of length (inch, centimeters, etc.), or the target display DPI. You can specify in which units \a resolution is given, by setting \a resolutionUnit. The \a resolution is converted to the format's expected resolution unit internally. Returns true on success. If this function fails, most likely the BMP format isn't supported by the system, see Qt docs about QImageWriter::supportedImageFormats(). The objects of the plot will appear in the current selection state. If you don't want any selected objects to be painted in their selected look, deselect everything with \ref deselectAll before calling this function. \warning If calling this function inside the constructor of the parent of the QCustomPlot widget (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this function uses the current width and height of the QCustomPlot widget. However, in Qt, these aren't defined yet inside the constructor, so you would get an image that has strange widths/heights. \see savePdf, savePng, saveJpg, saveRastered */ bool QCustomPlot::saveBmp(const QString &fileName, int width, int height, double scale, int resolution, QCP::ResolutionUnit resolutionUnit) { return saveRastered(fileName, width, height, scale, "BMP", -1, resolution, resolutionUnit); } /*! \internal Returns a minimum size hint that corresponds to the minimum size of the top level layout (\ref plotLayout). To prevent QCustomPlot from being collapsed to size/width zero, set a minimum size (setMinimumSize) either on the whole QCustomPlot or on any layout elements inside the plot. This is especially important, when placed in a QLayout where other components try to take in as much space as possible (e.g. QMdiArea). */ QSize QCustomPlot::minimumSizeHint() const { return mPlotLayout->minimumOuterSizeHint(); } /*! \internal Returns a size hint that is the same as \ref minimumSizeHint. */ QSize QCustomPlot::sizeHint() const { return mPlotLayout->minimumOuterSizeHint(); } /*! \internal Event handler for when the QCustomPlot widget needs repainting. This does not cause a \ref replot, but draws the internal buffer on the widget surface. */ void QCustomPlot::paintEvent(QPaintEvent *event) { Q_UNUSED(event) QCPPainter painter(this); if (painter.isActive()) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) painter.setRenderHint(QPainter::HighQualityAntialiasing); // to make Antialiasing look good if using the OpenGL graphicssystem #endif if (mBackgroundBrush.style() != Qt::NoBrush) painter.fillRect(mViewport, mBackgroundBrush); drawBackground(&painter); foreach (QSharedPointer buffer, mPaintBuffers) buffer->draw(&painter); } } /*! \internal Event handler for a resize of the QCustomPlot widget. The viewport (which becomes the outer rect of mPlotLayout) is resized appropriately. Finally a \ref replot is performed. */ void QCustomPlot::resizeEvent(QResizeEvent *event) { Q_UNUSED(event) // resize and repaint the buffer: setViewport(rect()); replot(rpQueuedRefresh); // queued refresh is important here, to prevent painting issues in some contexts (e.g. MDI subwindow) } /*! \internal Event handler for when a double click occurs. Emits the \ref mouseDoubleClick signal, then determines the layerable under the cursor and forwards the event to it. Finally, emits the specialized signals when certain objecs are clicked (e.g. \ref plottableDoubleClick, \ref axisDoubleClick, etc.). \see mousePressEvent, mouseReleaseEvent */ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) { emit mouseDoubleClick(event); mMouseHasMoved = false; mMousePressPos = event->pos(); // determine layerable under the cursor (this event is called instead of the second press event in a double-click): QList details; QList candidates = layerableListAt(mMousePressPos, false, &details); for (int i=0; iaccept(); // default impl of QCPLayerable's mouse events ignore the event, in that case propagate to next candidate in list candidates.at(i)->mouseDoubleClickEvent(event, details.at(i)); if (event->isAccepted()) { mMouseEventLayerable = candidates.at(i); mMouseEventLayerableDetails = details.at(i); break; } } // emit specialized object double click signals: if (!candidates.isEmpty()) { if (QCPAbstractPlottable *ap = qobject_cast(candidates.first())) { int dataIndex = 0; if (!details.first().value().isEmpty()) dataIndex = details.first().value().dataRange().begin(); emit plottableDoubleClick(ap, dataIndex, event); } else if (QCPAxis *ax = qobject_cast(candidates.first())) emit axisDoubleClick(ax, details.first().value(), event); else if (QCPAbstractItem *ai = qobject_cast(candidates.first())) emit itemDoubleClick(ai, event); else if (QCPLegend *lg = qobject_cast(candidates.first())) emit legendDoubleClick(lg, nullptr, event); else if (QCPAbstractLegendItem *li = qobject_cast(candidates.first())) emit legendDoubleClick(li->parentLegend(), li, event); } event->accept(); // in case QCPLayerable reimplementation manipulates event accepted state. In QWidget event system, QCustomPlot wants to accept the event. } /*! \internal Event handler for when a mouse button is pressed. Emits the mousePress signal. If the current \ref setSelectionRectMode is not \ref QCP::srmNone, passes the event to the selection rect. Otherwise determines the layerable under the cursor and forwards the event to it. \see mouseMoveEvent, mouseReleaseEvent */ void QCustomPlot::mousePressEvent(QMouseEvent *event) { emit mousePress(event); // save some state to tell in releaseEvent whether it was a click: mMouseHasMoved = false; mMousePressPos = event->pos(); if (mSelectionRect && mSelectionRectMode != QCP::srmNone) { if (mSelectionRectMode != QCP::srmZoom || qobject_cast(axisRectAt(mMousePressPos))) // in zoom mode only activate selection rect if on an axis rect mSelectionRect->startSelection(event); } else { // no selection rect interaction, prepare for click signal emission and forward event to layerable under the cursor: QList details; QList candidates = layerableListAt(mMousePressPos, false, &details); if (!candidates.isEmpty()) { mMouseSignalLayerable = candidates.first(); // candidate for signal emission is always topmost hit layerable (signal emitted in release event) mMouseSignalLayerableDetails = details.first(); } // forward event to topmost candidate which accepts the event: for (int i=0; iaccept(); // default impl of QCPLayerable's mouse events call ignore() on the event, in that case propagate to next candidate in list candidates.at(i)->mousePressEvent(event, details.at(i)); if (event->isAccepted()) { mMouseEventLayerable = candidates.at(i); mMouseEventLayerableDetails = details.at(i); break; } } } event->accept(); // in case QCPLayerable reimplementation manipulates event accepted state. In QWidget event system, QCustomPlot wants to accept the event. } /*! \internal Event handler for when the cursor is moved. Emits the \ref mouseMove signal. If the selection rect (\ref setSelectionRect) is currently active, the event is forwarded to it in order to update the rect geometry. Otherwise, if a layout element has mouse capture focus (a mousePressEvent happened on top of the layout element before), the mouseMoveEvent is forwarded to that element. \see mousePressEvent, mouseReleaseEvent */ void QCustomPlot::mouseMoveEvent(QMouseEvent *event) { emit mouseMove(event); if (!mMouseHasMoved && (mMousePressPos-event->pos()).manhattanLength() > 3) mMouseHasMoved = true; // moved too far from mouse press position, don't handle as click on mouse release if (mSelectionRect && mSelectionRect->isActive()) mSelectionRect->moveSelection(event); else if (mMouseEventLayerable) // call event of affected layerable: mMouseEventLayerable->mouseMoveEvent(event, mMousePressPos); event->accept(); // in case QCPLayerable reimplementation manipulates event accepted state. In QWidget event system, QCustomPlot wants to accept the event. } /*! \internal Event handler for when a mouse button is released. Emits the \ref mouseRelease signal. If the mouse was moved less than a certain threshold in any direction since the \ref mousePressEvent, it is considered a click which causes the selection mechanism (if activated via \ref setInteractions) to possibly change selection states accordingly. Further, specialized mouse click signals are emitted (e.g. \ref plottableClick, \ref axisClick, etc.) If a layerable is the mouse capturer (a \ref mousePressEvent happened on top of the layerable before), the \ref mouseReleaseEvent is forwarded to that element. \see mousePressEvent, mouseMoveEvent */ void QCustomPlot::mouseReleaseEvent(QMouseEvent *event) { emit mouseRelease(event); if (!mMouseHasMoved) // mouse hasn't moved (much) between press and release, so handle as click { if (mSelectionRect && mSelectionRect->isActive()) // a simple click shouldn't successfully finish a selection rect, so cancel it here mSelectionRect->cancel(); if (event->button() == Qt::LeftButton) processPointSelection(event); // emit specialized click signals of QCustomPlot instance: if (QCPAbstractPlottable *ap = qobject_cast(mMouseSignalLayerable)) { int dataIndex = 0; if (!mMouseSignalLayerableDetails.value().isEmpty()) dataIndex = mMouseSignalLayerableDetails.value().dataRange().begin(); emit plottableClick(ap, dataIndex, event); } else if (QCPAxis *ax = qobject_cast(mMouseSignalLayerable)) emit axisClick(ax, mMouseSignalLayerableDetails.value(), event); else if (QCPAbstractItem *ai = qobject_cast(mMouseSignalLayerable)) emit itemClick(ai, event); else if (QCPLegend *lg = qobject_cast(mMouseSignalLayerable)) emit legendClick(lg, nullptr, event); else if (QCPAbstractLegendItem *li = qobject_cast(mMouseSignalLayerable)) emit legendClick(li->parentLegend(), li, event); mMouseSignalLayerable = nullptr; } if (mSelectionRect && mSelectionRect->isActive()) // Note: if a click was detected above, the selection rect is canceled there { // finish selection rect, the appropriate action will be taken via signal-slot connection: mSelectionRect->endSelection(event); } else { // call event of affected layerable: if (mMouseEventLayerable) { mMouseEventLayerable->mouseReleaseEvent(event, mMousePressPos); mMouseEventLayerable = nullptr; } } if (noAntialiasingOnDrag()) replot(rpQueuedReplot); event->accept(); // in case QCPLayerable reimplementation manipulates event accepted state. In QWidget event system, QCustomPlot wants to accept the event. } /*! \internal Event handler for mouse wheel events. First, the \ref mouseWheel signal is emitted. Then determines the affected layerable and forwards the event to it. */ void QCustomPlot::wheelEvent(QWheelEvent *event) { emit mouseWheel(event); #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) const QPointF pos = event->pos(); #else const QPointF pos = event->position(); #endif // forward event to layerable under cursor: foreach (QCPLayerable *candidate, layerableListAt(pos, false)) { event->accept(); // default impl of QCPLayerable's mouse events ignore the event, in that case propagate to next candidate in list candidate->wheelEvent(event); if (event->isAccepted()) break; } event->accept(); // in case QCPLayerable reimplementation manipulates event accepted state. In QWidget event system, QCustomPlot wants to accept the event. } /*! \internal This function draws the entire plot, including background pixmap, with the specified \a painter. It does not make use of the paint buffers like \ref replot, so this is the function typically used by saving/exporting methods such as \ref savePdf or \ref toPainter. Note that it does not fill the background with the background brush (as the user may specify with \ref setBackground(const QBrush &brush)), this is up to the respective functions calling this method. */ void QCustomPlot::draw(QCPPainter *painter) { updateLayout(); // draw viewport background pixmap: drawBackground(painter); // draw all layered objects (grid, axes, plottables, items, legend,...): foreach (QCPLayer *layer, mLayers) layer->draw(painter); /* Debug code to draw all layout element rects foreach (QCPLayoutElement *el, findChildren()) { painter->setBrush(Qt::NoBrush); painter->setPen(QPen(QColor(0, 0, 0, 100), 0, Qt::DashLine)); painter->drawRect(el->rect()); painter->setPen(QPen(QColor(255, 0, 0, 100), 0, Qt::DashLine)); painter->drawRect(el->outerRect()); } */ } /*! \internal Performs the layout update steps defined by \ref QCPLayoutElement::UpdatePhase, by calling \ref QCPLayoutElement::update on the main plot layout. Here, the layout elements calculate their positions and margins, and prepare for the following draw call. */ void QCustomPlot::updateLayout() { // run through layout phases: mPlotLayout->update(QCPLayoutElement::upPreparation); mPlotLayout->update(QCPLayoutElement::upMargins); mPlotLayout->update(QCPLayoutElement::upLayout); emit afterLayout(); } /*! \internal Draws the viewport background pixmap of the plot. If a pixmap was provided via \ref setBackground, this function buffers the scaled version depending on \ref setBackgroundScaled and \ref setBackgroundScaledMode and then draws it inside the viewport with the provided \a painter. The scaled version is buffered in mScaledBackgroundPixmap to prevent expensive rescaling at every redraw. It is only updated, when the axis rect has changed in a way that requires a rescale of the background pixmap (this is dependent on the \ref setBackgroundScaledMode), or when a differend axis background pixmap was set. Note that this function does not draw a fill with the background brush (\ref setBackground(const QBrush &brush)) beneath the pixmap. \see setBackground, setBackgroundScaled, setBackgroundScaledMode */ void QCustomPlot::drawBackground(QCPPainter *painter) { // Note: background color is handled in individual replot/save functions // draw background pixmap (on top of fill, if brush specified): if (!mBackgroundPixmap.isNull()) { if (mBackgroundScaled) { // check whether mScaledBackground needs to be updated: QSize scaledSize(mBackgroundPixmap.size()); scaledSize.scale(mViewport.size(), mBackgroundScaledMode); if (mScaledBackgroundPixmap.size() != scaledSize) mScaledBackgroundPixmap = mBackgroundPixmap.scaled(mViewport.size(), mBackgroundScaledMode, Qt::SmoothTransformation); painter->drawPixmap(mViewport.topLeft(), mScaledBackgroundPixmap, QRect(0, 0, mViewport.width(), mViewport.height()) & mScaledBackgroundPixmap.rect()); } else { painter->drawPixmap(mViewport.topLeft(), mBackgroundPixmap, QRect(0, 0, mViewport.width(), mViewport.height())); } } } /*! \internal Goes through the layers and makes sure this QCustomPlot instance holds the correct number of paint buffers and that they have the correct configuration (size, pixel ratio, etc.). Allocations, reallocations and deletions of paint buffers are performed as necessary. It also associates the paint buffers with the layers, so they draw themselves into the right buffer when \ref QCPLayer::drawToPaintBuffer is called. This means it associates adjacent \ref QCPLayer::lmLogical layers to a mutual paint buffer and creates dedicated paint buffers for layers in \ref QCPLayer::lmBuffered mode. This method uses \ref createPaintBuffer to create new paint buffers. After this method, the paint buffers are empty (filled with \c Qt::transparent) and invalidated (so an attempt to replot only a single buffered layer causes a full replot). This method is called in every \ref replot call, prior to actually drawing the layers (into their associated paint buffer). If the paint buffers don't need changing/reallocating, this method basically leaves them alone and thus finishes very fast. */ void QCustomPlot::setupPaintBuffers() { int bufferIndex = 0; if (mPaintBuffers.isEmpty()) mPaintBuffers.append(QSharedPointer(createPaintBuffer())); for (int layerIndex = 0; layerIndex < mLayers.size(); ++layerIndex) { QCPLayer *layer = mLayers.at(layerIndex); if (layer->mode() == QCPLayer::lmLogical) { layer->mPaintBuffer = mPaintBuffers.at(bufferIndex).toWeakRef(); } else if (layer->mode() == QCPLayer::lmBuffered) { ++bufferIndex; if (bufferIndex >= mPaintBuffers.size()) mPaintBuffers.append(QSharedPointer(createPaintBuffer())); layer->mPaintBuffer = mPaintBuffers.at(bufferIndex).toWeakRef(); if (layerIndex < mLayers.size()-1 && mLayers.at(layerIndex+1)->mode() == QCPLayer::lmLogical) // not last layer, and next one is logical, so prepare another buffer for next layerables { ++bufferIndex; if (bufferIndex >= mPaintBuffers.size()) mPaintBuffers.append(QSharedPointer(createPaintBuffer())); } } } // remove unneeded buffers: while (mPaintBuffers.size()-1 > bufferIndex) mPaintBuffers.removeLast(); // resize buffers to viewport size and clear contents: foreach (QSharedPointer buffer, mPaintBuffers) { buffer->setSize(viewport().size()); // won't do anything if already correct size buffer->clear(Qt::transparent); buffer->setInvalidated(); } } /*! \internal This method is used by \ref setupPaintBuffers when it needs to create new paint buffers. Depending on the current setting of \ref setOpenGl, and the current Qt version, different backends (subclasses of \ref QCPAbstractPaintBuffer) are created, initialized with the proper size and device pixel ratio, and returned. */ QCPAbstractPaintBuffer *QCustomPlot::createPaintBuffer() { if (mOpenGl) { #if defined(QCP_OPENGL_FBO) return new QCPPaintBufferGlFbo(viewport().size(), mBufferDevicePixelRatio, mGlContext, mGlPaintDevice); #elif defined(QCP_OPENGL_PBUFFER) return new QCPPaintBufferGlPbuffer(viewport().size(), mBufferDevicePixelRatio, mOpenGlMultisamples); #else qDebug() << Q_FUNC_INFO << "OpenGL enabled even though no support for it compiled in, this shouldn't have happened. Falling back to pixmap paint buffer."; return new QCPPaintBufferPixmap(viewport().size(), mBufferDevicePixelRatio); #endif } else return new QCPPaintBufferPixmap(viewport().size(), mBufferDevicePixelRatio); } /*! This method returns whether any of the paint buffers held by this QCustomPlot instance are invalidated. If any buffer is invalidated, a partial replot (\ref QCPLayer::replot) is not allowed and always causes a full replot (\ref QCustomPlot::replot) of all layers. This is the case when for example the layer order has changed, new layers were added or removed, layer modes were changed (\ref QCPLayer::setMode), or layerables were added or removed. \see QCPAbstractPaintBuffer::setInvalidated */ bool QCustomPlot::hasInvalidatedPaintBuffers() { foreach (QSharedPointer buffer, mPaintBuffers) { if (buffer->invalidated()) return true; } return false; } /*! \internal When \ref setOpenGl is set to true, this method is used to initialize OpenGL (create a context, surface, paint device). Returns true on success. If this method is successful, all paint buffers should be deleted and then reallocated by calling \ref setupPaintBuffers, so the OpenGL-based paint buffer subclasses (\ref QCPPaintBufferGlPbuffer, \ref QCPPaintBufferGlFbo) are used for subsequent replots. \see freeOpenGl */ bool QCustomPlot::setupOpenGl() { #ifdef QCP_OPENGL_FBO freeOpenGl(); QSurfaceFormat proposedSurfaceFormat; proposedSurfaceFormat.setSamples(mOpenGlMultisamples); #ifdef QCP_OPENGL_OFFSCREENSURFACE QOffscreenSurface *surface = new QOffscreenSurface; #else QWindow *surface = new QWindow; surface->setSurfaceType(QSurface::OpenGLSurface); #endif surface->setFormat(proposedSurfaceFormat); surface->create(); mGlSurface = QSharedPointer(surface); mGlContext = QSharedPointer(new QOpenGLContext); mGlContext->setFormat(mGlSurface->format()); if (!mGlContext->create()) { qDebug() << Q_FUNC_INFO << "Failed to create OpenGL context"; mGlContext.clear(); mGlSurface.clear(); return false; } if (!mGlContext->makeCurrent(mGlSurface.data())) // context needs to be current to create paint device { qDebug() << Q_FUNC_INFO << "Failed to make opengl context current"; mGlContext.clear(); mGlSurface.clear(); return false; } if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()) { qDebug() << Q_FUNC_INFO << "OpenGL of this system doesn't support frame buffer objects"; mGlContext.clear(); mGlSurface.clear(); return false; } mGlPaintDevice = QSharedPointer(new QOpenGLPaintDevice); return true; #elif defined(QCP_OPENGL_PBUFFER) return QGLFormat::hasOpenGL(); #else return false; #endif } /*! \internal When \ref setOpenGl is set to false, this method is used to deinitialize OpenGL (releases the context and frees resources). After OpenGL is disabled, all paint buffers should be deleted and then reallocated by calling \ref setupPaintBuffers, so the standard software rendering paint buffer subclass (\ref QCPPaintBufferPixmap) is used for subsequent replots. \see setupOpenGl */ void QCustomPlot::freeOpenGl() { #ifdef QCP_OPENGL_FBO mGlPaintDevice.clear(); mGlContext.clear(); mGlSurface.clear(); #endif } /*! \internal This method is used by \ref QCPAxisRect::removeAxis to report removed axes to the QCustomPlot so it may clear its QCustomPlot::xAxis, yAxis, xAxis2 and yAxis2 members accordingly. */ void QCustomPlot::axisRemoved(QCPAxis *axis) { if (xAxis == axis) xAxis = nullptr; if (xAxis2 == axis) xAxis2 = nullptr; if (yAxis == axis) yAxis = nullptr; if (yAxis2 == axis) yAxis2 = nullptr; // Note: No need to take care of range drag axes and range zoom axes, because they are stored in smart pointers } /*! \internal This method is used by the QCPLegend destructor to report legend removal to the QCustomPlot so it may clear its QCustomPlot::legend member accordingly. */ void QCustomPlot::legendRemoved(QCPLegend *legend) { if (this->legend == legend) this->legend = nullptr; } /*! \internal This slot is connected to the selection rect's \ref QCPSelectionRect::accepted signal when \ref setSelectionRectMode is set to \ref QCP::srmSelect. First, it determines which axis rect was the origin of the selection rect judging by the starting point of the selection. Then it goes through the plottables (\ref QCPAbstractPlottable1D to be precise) associated with that axis rect and finds the data points that are in \a rect. It does this by querying their \ref QCPAbstractPlottable1D::selectTestRect method. Then, the actual selection is done by calling the plottables' \ref QCPAbstractPlottable::selectEvent, placing the found selected data points in the \a details parameter as QVariant(\ref QCPDataSelection). All plottables that weren't touched by \a rect receive a \ref QCPAbstractPlottable::deselectEvent. \see processRectZoom */ void QCustomPlot::processRectSelection(QRect rect, QMouseEvent *event) { typedef QPair SelectionCandidate; typedef QMultiMap SelectionCandidates; // map key is number of selected data points, so we have selections sorted by size bool selectionStateChanged = false; if (mInteractions.testFlag(QCP::iSelectPlottables)) { SelectionCandidates potentialSelections; QRectF rectF(rect.normalized()); if (QCPAxisRect *affectedAxisRect = axisRectAt(rectF.topLeft())) { // determine plottables that were hit by the rect and thus are candidates for selection: foreach (QCPAbstractPlottable *plottable, affectedAxisRect->plottables()) { if (QCPPlottableInterface1D *plottableInterface = plottable->interface1D()) { QCPDataSelection dataSel = plottableInterface->selectTestRect(rectF, true); if (!dataSel.isEmpty()) potentialSelections.insert(dataSel.dataPointCount(), SelectionCandidate(plottable, dataSel)); } } if (!mInteractions.testFlag(QCP::iMultiSelect)) { // only leave plottable with most selected points in map, since we will only select a single plottable: if (!potentialSelections.isEmpty()) { SelectionCandidates::iterator it = potentialSelections.begin(); while (it != std::prev(potentialSelections.end())) // erase all except last element it = potentialSelections.erase(it); } } bool additive = event->modifiers().testFlag(mMultiSelectModifier); // deselect all other layerables if not additive selection: if (!additive) { // emit deselection except to those plottables who will be selected afterwards: foreach (QCPLayer *layer, mLayers) { foreach (QCPLayerable *layerable, layer->children()) { if ((potentialSelections.isEmpty() || potentialSelections.constBegin()->first != layerable) && mInteractions.testFlag(layerable->selectionCategory())) { bool selChanged = false; layerable->deselectEvent(&selChanged); selectionStateChanged |= selChanged; } } } } // go through selections in reverse (largest selection first) and emit select events: SelectionCandidates::const_iterator it = potentialSelections.constEnd(); while (it != potentialSelections.constBegin()) { --it; if (mInteractions.testFlag(it.value().first->selectionCategory())) { bool selChanged = false; it.value().first->selectEvent(event, additive, QVariant::fromValue(it.value().second), &selChanged); selectionStateChanged |= selChanged; } } } } if (selectionStateChanged) { emit selectionChangedByUser(); replot(rpQueuedReplot); } else if (mSelectionRect) mSelectionRect->layer()->replot(); } /*! \internal This slot is connected to the selection rect's \ref QCPSelectionRect::accepted signal when \ref setSelectionRectMode is set to \ref QCP::srmZoom. It determines which axis rect was the origin of the selection rect judging by the starting point of the selection, and then zooms the axes defined via \ref QCPAxisRect::setRangeZoomAxes to the provided \a rect (see \ref QCPAxisRect::zoom). \see processRectSelection */ void QCustomPlot::processRectZoom(QRect rect, QMouseEvent *event) { Q_UNUSED(event) if (QCPAxisRect *axisRect = axisRectAt(rect.topLeft())) { QList affectedAxes = QList() << axisRect->rangeZoomAxes(Qt::Horizontal) << axisRect->rangeZoomAxes(Qt::Vertical); affectedAxes.removeAll(static_cast(nullptr)); axisRect->zoom(QRectF(rect), affectedAxes); } replot(rpQueuedReplot); // always replot to make selection rect disappear } /*! \internal This method is called when a simple left mouse click was detected on the QCustomPlot surface. It first determines the layerable that was hit by the click, and then calls its \ref QCPLayerable::selectEvent. All other layerables receive a QCPLayerable::deselectEvent (unless the multi-select modifier was pressed, see \ref setMultiSelectModifier). In this method the hit layerable is determined a second time using \ref layerableAt (after the one in \ref mousePressEvent), because we want \a onlySelectable set to true this time. This implies that the mouse event grabber (mMouseEventLayerable) may be a different one from the clicked layerable determined here. For example, if a non-selectable layerable is in front of a selectable layerable at the click position, the front layerable will receive mouse events but the selectable one in the back will receive the \ref QCPLayerable::selectEvent. \see processRectSelection, QCPLayerable::selectTest */ void QCustomPlot::processPointSelection(QMouseEvent *event) { QVariant details; QCPLayerable *clickedLayerable = layerableAt(event->pos(), true, &details); bool selectionStateChanged = false; bool additive = mInteractions.testFlag(QCP::iMultiSelect) && event->modifiers().testFlag(mMultiSelectModifier); // deselect all other layerables if not additive selection: if (!additive) { foreach (QCPLayer *layer, mLayers) { foreach (QCPLayerable *layerable, layer->children()) { if (layerable != clickedLayerable && mInteractions.testFlag(layerable->selectionCategory())) { bool selChanged = false; layerable->deselectEvent(&selChanged); selectionStateChanged |= selChanged; } } } } if (clickedLayerable && mInteractions.testFlag(clickedLayerable->selectionCategory())) { // a layerable was actually clicked, call its selectEvent: bool selChanged = false; clickedLayerable->selectEvent(event, additive, details, &selChanged); selectionStateChanged |= selChanged; } if (selectionStateChanged) { emit selectionChangedByUser(); replot(rpQueuedReplot); } } /*! \internal Registers the specified plottable with this QCustomPlot and, if \ref setAutoAddPlottableToLegend is enabled, adds it to the legend (QCustomPlot::legend). QCustomPlot takes ownership of the plottable. Returns true on success, i.e. when \a plottable isn't already in this plot and the parent plot of \a plottable is this QCustomPlot. This method is called automatically in the QCPAbstractPlottable base class constructor. */ bool QCustomPlot::registerPlottable(QCPAbstractPlottable *plottable) { if (mPlottables.contains(plottable)) { qDebug() << Q_FUNC_INFO << "plottable already added to this QCustomPlot:" << reinterpret_cast(plottable); return false; } if (plottable->parentPlot() != this) { qDebug() << Q_FUNC_INFO << "plottable not created with this QCustomPlot as parent:" << reinterpret_cast(plottable); return false; } mPlottables.append(plottable); // possibly add plottable to legend: if (mAutoAddPlottableToLegend) plottable->addToLegend(); if (!plottable->layer()) // usually the layer is already set in the constructor of the plottable (via QCPLayerable constructor) plottable->setLayer(currentLayer()); return true; } /*! \internal In order to maintain the simplified graph interface of QCustomPlot, this method is called by the QCPGraph constructor to register itself with this QCustomPlot's internal graph list. Returns true on success, i.e. if \a graph is valid and wasn't already registered with this QCustomPlot. This graph specific registration happens in addition to the call to \ref registerPlottable by the QCPAbstractPlottable base class. */ bool QCustomPlot::registerGraph(QCPGraph *graph) { if (!graph) { qDebug() << Q_FUNC_INFO << "passed graph is zero"; return false; } if (mGraphs.contains(graph)) { qDebug() << Q_FUNC_INFO << "graph already registered with this QCustomPlot"; return false; } mGraphs.append(graph); return true; } /*! \internal Registers the specified item with this QCustomPlot. QCustomPlot takes ownership of the item. Returns true on success, i.e. when \a item wasn't already in the plot and the parent plot of \a item is this QCustomPlot. This method is called automatically in the QCPAbstractItem base class constructor. */ bool QCustomPlot::registerItem(QCPAbstractItem *item) { if (mItems.contains(item)) { qDebug() << Q_FUNC_INFO << "item already added to this QCustomPlot:" << reinterpret_cast(item); return false; } if (item->parentPlot() != this) { qDebug() << Q_FUNC_INFO << "item not created with this QCustomPlot as parent:" << reinterpret_cast(item); return false; } mItems.append(item); if (!item->layer()) // usually the layer is already set in the constructor of the item (via QCPLayerable constructor) item->setLayer(currentLayer()); return true; } /*! \internal Assigns all layers their index (QCPLayer::mIndex) in the mLayers list. This method is thus called after every operation that changes the layer indices, like layer removal, layer creation, layer moving. */ void QCustomPlot::updateLayerIndices() const { for (int i=0; imIndex = i; } /*! \internal Returns the top-most layerable at pixel position \a pos. If \a onlySelectable is set to true, only those layerables that are selectable will be considered. (Layerable subclasses communicate their selectability via the QCPLayerable::selectTest method, by returning -1.) \a selectionDetails is an output parameter that contains selection specifics of the affected layerable. This is useful if the respective layerable shall be given a subsequent QCPLayerable::selectEvent (like in \ref mouseReleaseEvent). \a selectionDetails usually contains information about which part of the layerable was hit, in multi-part layerables (e.g. QCPAxis::SelectablePart). If the layerable is a plottable, \a selectionDetails contains a \ref QCPDataSelection instance with the single data point which is closest to \a pos. \see layerableListAt, layoutElementAt, axisRectAt */ QCPLayerable *QCustomPlot::layerableAt(const QPointF &pos, bool onlySelectable, QVariant *selectionDetails) const { QList details; QList candidates = layerableListAt(pos, onlySelectable, selectionDetails ? &details : nullptr); if (selectionDetails && !details.isEmpty()) *selectionDetails = details.first(); if (!candidates.isEmpty()) return candidates.first(); else return nullptr; } /*! \internal Returns the layerables at pixel position \a pos. If \a onlySelectable is set to true, only those layerables that are selectable will be considered. (Layerable subclasses communicate their selectability via the QCPLayerable::selectTest method, by returning -1.) The returned list is sorted by the layerable/drawing order such that the layerable that appears on top in the plot is at index 0 of the returned list. If you only need to know the top layerable, rather use \ref layerableAt. \a selectionDetails is an output parameter that contains selection specifics of the affected layerable. This is useful if the respective layerable shall be given a subsequent QCPLayerable::selectEvent (like in \ref mouseReleaseEvent). \a selectionDetails usually contains information about which part of the layerable was hit, in multi-part layerables (e.g. QCPAxis::SelectablePart). If the layerable is a plottable, \a selectionDetails contains a \ref QCPDataSelection instance with the single data point which is closest to \a pos. \see layerableAt, layoutElementAt, axisRectAt */ QList QCustomPlot::layerableListAt(const QPointF &pos, bool onlySelectable, QList *selectionDetails) const { QList result; for (int layerIndex=mLayers.size()-1; layerIndex>=0; --layerIndex) { const QList layerables = mLayers.at(layerIndex)->children(); for (int i=layerables.size()-1; i>=0; --i) { if (!layerables.at(i)->realVisibility()) continue; QVariant details; double dist = layerables.at(i)->selectTest(pos, onlySelectable, selectionDetails ? &details : nullptr); if (dist >= 0 && dist < selectionTolerance()) { result.append(layerables.at(i)); if (selectionDetails) selectionDetails->append(details); } } } return result; } /*! Saves the plot to a rastered image file \a fileName in the image format \a format. The plot is sized to \a width and \a height in pixels and scaled with \a scale. (width 100 and scale 2.0 lead to a full resolution file with width 200.) If the \a format supports compression, \a quality may be between 0 and 100 to control it. Returns true on success. If this function fails, most likely the given \a format isn't supported by the system, see Qt docs about QImageWriter::supportedImageFormats(). The \a resolution will be written to the image file header (if the file format supports this) and has no direct consequence for the quality or the pixel size. However, if opening the image with a tool which respects the metadata, it will be able to scale the image to match either a given size in real units of length (inch, centimeters, etc.), or the target display DPI. You can specify in which units \a resolution is given, by setting \a resolutionUnit. The \a resolution is converted to the format's expected resolution unit internally. \see saveBmp, saveJpg, savePng, savePdf */ bool QCustomPlot::saveRastered(const QString &fileName, int width, int height, double scale, const char *format, int quality, int resolution, QCP::ResolutionUnit resolutionUnit) { QImage buffer = toPixmap(width, height, scale).toImage(); int dotsPerMeter = 0; switch (resolutionUnit) { case QCP::ruDotsPerMeter: dotsPerMeter = resolution; break; case QCP::ruDotsPerCentimeter: dotsPerMeter = resolution*100; break; case QCP::ruDotsPerInch: dotsPerMeter = int(resolution/0.0254); break; } buffer.setDotsPerMeterX(dotsPerMeter); // this is saved together with some image formats, e.g. PNG, and is relevant when opening image in other tools buffer.setDotsPerMeterY(dotsPerMeter); // this is saved together with some image formats, e.g. PNG, and is relevant when opening image in other tools if (!buffer.isNull()) return buffer.save(fileName, format, quality); else return false; } /*! Renders the plot to a pixmap and returns it. The plot is sized to \a width and \a height in pixels and scaled with \a scale. (width 100 and scale 2.0 lead to a full resolution pixmap with width 200.) \see toPainter, saveRastered, saveBmp, savePng, saveJpg, savePdf */ QPixmap QCustomPlot::toPixmap(int width, int height, double scale) { // this method is somewhat similar to toPainter. Change something here, and a change in toPainter might be necessary, too. int newWidth, newHeight; if (width == 0 || height == 0) { newWidth = this->width(); newHeight = this->height(); } else { newWidth = width; newHeight = height; } int scaledWidth = qRound(scale*newWidth); int scaledHeight = qRound(scale*newHeight); QPixmap result(scaledWidth, scaledHeight); result.fill(mBackgroundBrush.style() == Qt::SolidPattern ? mBackgroundBrush.color() : Qt::transparent); // if using non-solid pattern, make transparent now and draw brush pattern later QCPPainter painter; painter.begin(&result); if (painter.isActive()) { QRect oldViewport = viewport(); setViewport(QRect(0, 0, newWidth, newHeight)); painter.setMode(QCPPainter::pmNoCaching); if (!qFuzzyCompare(scale, 1.0)) { if (scale > 1.0) // for scale < 1 we always want cosmetic pens where possible, because else lines might disappear for very small scales painter.setMode(QCPPainter::pmNonCosmetic); painter.scale(scale, scale); } if (mBackgroundBrush.style() != Qt::SolidPattern && mBackgroundBrush.style() != Qt::NoBrush) // solid fills were done a few lines above with QPixmap::fill painter.fillRect(mViewport, mBackgroundBrush); draw(&painter); setViewport(oldViewport); painter.end(); } else // might happen if pixmap has width or height zero { qDebug() << Q_FUNC_INFO << "Couldn't activate painter on pixmap"; return QPixmap(); } return result; } /*! Renders the plot using the passed \a painter. The plot is sized to \a width and \a height in pixels. If the \a painter's scale is not 1.0, the resulting plot will appear scaled accordingly. \note If you are restricted to using a QPainter (instead of QCPPainter), create a temporary QPicture and open a QCPPainter on it. Then call \ref toPainter with this QCPPainter. After ending the paint operation on the picture, draw it with the QPainter. This will reproduce the painter actions the QCPPainter took, with a QPainter. \see toPixmap */ void QCustomPlot::toPainter(QCPPainter *painter, int width, int height) { // this method is somewhat similar to toPixmap. Change something here, and a change in toPixmap might be necessary, too. int newWidth, newHeight; if (width == 0 || height == 0) { newWidth = this->width(); newHeight = this->height(); } else { newWidth = width; newHeight = height; } if (painter->isActive()) { QRect oldViewport = viewport(); setViewport(QRect(0, 0, newWidth, newHeight)); painter->setMode(QCPPainter::pmNoCaching); if (mBackgroundBrush.style() != Qt::NoBrush) // unlike in toPixmap, we can't do QPixmap::fill for Qt::SolidPattern brush style, so we also draw solid fills with fillRect here painter->fillRect(mViewport, mBackgroundBrush); draw(painter); setViewport(oldViewport); } else qDebug() << Q_FUNC_INFO << "Passed painter is not active"; } /* end of 'src/core.cpp' */ /* including file 'src/colorgradient.cpp' */ /* modified 2021-03-29T02:30:44, size 25278 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPColorGradient //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPColorGradient \brief Defines a color gradient for use with e.g. \ref QCPColorMap This class describes a color gradient which can be used to encode data with color. For example, QCPColorMap and QCPColorScale have \ref QCPColorMap::setGradient "setGradient" methods which take an instance of this class. Colors are set with \ref setColorStopAt(double position, const QColor &color) with a \a position from 0 to 1. In between these defined color positions, the color will be interpolated linearly either in RGB or HSV space, see \ref setColorInterpolation. Alternatively, load one of the preset color gradients shown in the image below, with \ref loadPreset, or by directly specifying the preset in the constructor. Apart from red, green and blue components, the gradient also interpolates the alpha values of the configured color stops. This allows to display some portions of the data range as transparent in the plot. How NaN values are interpreted can be configured with \ref setNanHandling. \image html QCPColorGradient.png The constructor \ref QCPColorGradient(GradientPreset preset) allows directly converting a \ref GradientPreset to a QCPColorGradient. This means that you can directly pass \ref GradientPreset to all the \a setGradient methods, e.g.: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolorgradient-setgradient The total number of levels used in the gradient can be set with \ref setLevelCount. Whether the color gradient shall be applied periodically (wrapping around) to data values that lie outside the data range specified on the plottable instance can be controlled with \ref setPeriodic. */ /*! Constructs a new, empty QCPColorGradient with no predefined color stops. You can add own color stops with \ref setColorStopAt. The color level count is initialized to 350. */ QCPColorGradient::QCPColorGradient() : mLevelCount(350), mColorInterpolation(ciRGB), mNanHandling(nhNone), mNanColor(Qt::black), mPeriodic(false), mColorBufferInvalidated(true) { mColorBuffer.fill(qRgb(0, 0, 0), mLevelCount); } /*! Constructs a new QCPColorGradient initialized with the colors and color interpolation according to \a preset. The color level count is initialized to 350. */ QCPColorGradient::QCPColorGradient(GradientPreset preset) : mLevelCount(350), mColorInterpolation(ciRGB), mNanHandling(nhNone), mNanColor(Qt::black), mPeriodic(false), mColorBufferInvalidated(true) { mColorBuffer.fill(qRgb(0, 0, 0), mLevelCount); loadPreset(preset); } /* undocumented operator */ bool QCPColorGradient::operator==(const QCPColorGradient &other) const { return ((other.mLevelCount == this->mLevelCount) && (other.mColorInterpolation == this->mColorInterpolation) && (other.mNanHandling == this ->mNanHandling) && (other.mNanColor == this->mNanColor) && (other.mPeriodic == this->mPeriodic) && (other.mColorStops == this->mColorStops)); } /*! Sets the number of discretization levels of the color gradient to \a n. The default is 350 which is typically enough to create a smooth appearance. The minimum number of levels is 2. \image html QCPColorGradient-levelcount.png */ void QCPColorGradient::setLevelCount(int n) { if (n < 2) { qDebug() << Q_FUNC_INFO << "n must be greater or equal 2 but was" << n; n = 2; } if (n != mLevelCount) { mLevelCount = n; mColorBufferInvalidated = true; } } /*! Sets at which positions from 0 to 1 which color shall occur. The positions are the keys, the colors are the values of the passed QMap \a colorStops. In between these color stops, the color is interpolated according to \ref setColorInterpolation. A more convenient way to create a custom gradient may be to clear all color stops with \ref clearColorStops (or creating a new, empty QCPColorGradient) and then adding them one by one with \ref setColorStopAt. \see clearColorStops */ void QCPColorGradient::setColorStops(const QMap &colorStops) { mColorStops = colorStops; mColorBufferInvalidated = true; } /*! Sets the \a color the gradient will have at the specified \a position (from 0 to 1). In between these color stops, the color is interpolated according to \ref setColorInterpolation. \see setColorStops, clearColorStops */ void QCPColorGradient::setColorStopAt(double position, const QColor &color) { mColorStops.insert(position, color); mColorBufferInvalidated = true; } /*! Sets whether the colors in between the configured color stops (see \ref setColorStopAt) shall be interpolated linearly in RGB or in HSV color space. For example, a sweep in RGB space from red to green will have a muddy brown intermediate color, whereas in HSV space the intermediate color is yellow. */ void QCPColorGradient::setColorInterpolation(QCPColorGradient::ColorInterpolation interpolation) { if (interpolation != mColorInterpolation) { mColorInterpolation = interpolation; mColorBufferInvalidated = true; } } /*! Sets how NaNs in the data are displayed in the plot. \see setNanColor */ void QCPColorGradient::setNanHandling(QCPColorGradient::NanHandling handling) { mNanHandling = handling; } /*! Sets the color that NaN data is represented by, if \ref setNanHandling is set to ref nhNanColor. \see setNanHandling */ void QCPColorGradient::setNanColor(const QColor &color) { mNanColor = color; } /*! Sets whether data points that are outside the configured data range (e.g. \ref QCPColorMap::setDataRange) are colored by periodically repeating the color gradient or whether they all have the same color, corresponding to the respective gradient boundary color. \image html QCPColorGradient-periodic.png As shown in the image above, gradients that have the same start and end color are especially suitable for a periodic gradient mapping, since they produce smooth color transitions throughout the color map. A preset that has this property is \ref gpHues. In practice, using periodic color gradients makes sense when the data corresponds to a periodic dimension, such as an angle or a phase. If this is not the case, the color encoding might become ambiguous, because multiple different data values are shown as the same color. */ void QCPColorGradient::setPeriodic(bool enabled) { mPeriodic = enabled; } /*! \overload This method is used to quickly convert a \a data array to colors. The colors will be output in the array \a scanLine. Both \a data and \a scanLine must have the length \a n when passed to this function. The data range that shall be used for mapping the data value to the gradient is passed in \a range. \a logarithmic indicates whether the data values shall be mapped to colors logarithmically. if \a data actually contains 2D-data linearized via [row*columnCount + column], you can set \a dataIndexFactor to columnCount to convert a column instead of a row of the data array, in \a scanLine. \a scanLine will remain a regular (1D) array. This works because \a data is addressed data[i*dataIndexFactor]. Use the overloaded method to additionally provide alpha map data. The QRgb values that are placed in \a scanLine have their r, g, and b components premultiplied with alpha (see QImage::Format_ARGB32_Premultiplied). */ void QCPColorGradient::colorize(const double *data, const QCPRange &range, QRgb *scanLine, int n, int dataIndexFactor, bool logarithmic) { // If you change something here, make sure to also adapt color() and the other colorize() overload if (!data) { qDebug() << Q_FUNC_INFO << "null pointer given as data"; return; } if (!scanLine) { qDebug() << Q_FUNC_INFO << "null pointer given as scanLine"; return; } if (mColorBufferInvalidated) updateColorBuffer(); const bool skipNanCheck = mNanHandling == nhNone; const double posToIndexFactor = !logarithmic ? (mLevelCount-1)/range.size() : (mLevelCount-1)/qLn(range.upper/range.lower); for (int i=0; i::const_iterator it=mColorStops.constBegin(); it!=mColorStops.constEnd(); ++it) result.setColorStopAt(1.0-it.key(), it.value()); return result; } /*! \internal Returns true if the color gradient uses transparency, i.e. if any of the configured color stops has an alpha value below 255. */ bool QCPColorGradient::stopsUseAlpha() const { for (QMap::const_iterator it=mColorStops.constBegin(); it!=mColorStops.constEnd(); ++it) { if (it.value().alpha() < 255) return true; } return false; } /*! \internal Updates the internal color buffer which will be used by \ref colorize and \ref color, to quickly convert positions to colors. This is where the interpolation between color stops is calculated. */ void QCPColorGradient::updateColorBuffer() { if (mColorBuffer.size() != mLevelCount) mColorBuffer.resize(mLevelCount); if (mColorStops.size() > 1) { double indexToPosFactor = 1.0/double(mLevelCount-1); const bool useAlpha = stopsUseAlpha(); for (int i=0; i::const_iterator it = mColorStops.lowerBound(position); if (it == mColorStops.constEnd()) // position is on or after last stop, use color of last stop { if (useAlpha) { const QColor col = std::prev(it).value(); const double alphaPremultiplier = col.alpha()/255.0; // since we use QImage::Format_ARGB32_Premultiplied mColorBuffer[i] = qRgba(int(col.red()*alphaPremultiplier), int(col.green()*alphaPremultiplier), int(col.blue()*alphaPremultiplier), col.alpha()); } else mColorBuffer[i] = std::prev(it).value().rgba(); } else if (it == mColorStops.constBegin()) // position is on or before first stop, use color of first stop { if (useAlpha) { const QColor &col = it.value(); const double alphaPremultiplier = col.alpha()/255.0; // since we use QImage::Format_ARGB32_Premultiplied mColorBuffer[i] = qRgba(int(col.red()*alphaPremultiplier), int(col.green()*alphaPremultiplier), int(col.blue()*alphaPremultiplier), col.alpha()); } else mColorBuffer[i] = it.value().rgba(); } else // position is in between stops (or on an intermediate stop), interpolate color { QMap::const_iterator high = it; QMap::const_iterator low = std::prev(it); double t = (position-low.key())/(high.key()-low.key()); // interpolation factor 0..1 switch (mColorInterpolation) { case ciRGB: { if (useAlpha) { const int alpha = int((1-t)*low.value().alpha() + t*high.value().alpha()); const double alphaPremultiplier = alpha/255.0; // since we use QImage::Format_ARGB32_Premultiplied mColorBuffer[i] = qRgba(int( ((1-t)*low.value().red() + t*high.value().red())*alphaPremultiplier ), int( ((1-t)*low.value().green() + t*high.value().green())*alphaPremultiplier ), int( ((1-t)*low.value().blue() + t*high.value().blue())*alphaPremultiplier ), alpha); } else { mColorBuffer[i] = qRgb(int( ((1-t)*low.value().red() + t*high.value().red()) ), int( ((1-t)*low.value().green() + t*high.value().green()) ), int( ((1-t)*low.value().blue() + t*high.value().blue())) ); } break; } case ciHSV: { QColor lowHsv = low.value().toHsv(); QColor highHsv = high.value().toHsv(); double hue = 0; double hueDiff = highHsv.hueF()-lowHsv.hueF(); if (hueDiff > 0.5) hue = lowHsv.hueF() - t*(1.0-hueDiff); else if (hueDiff < -0.5) hue = lowHsv.hueF() + t*(1.0+hueDiff); else hue = lowHsv.hueF() + t*hueDiff; if (hue < 0) hue += 1.0; else if (hue >= 1.0) hue -= 1.0; if (useAlpha) { const QRgb rgb = QColor::fromHsvF(hue, (1-t)*lowHsv.saturationF() + t*highHsv.saturationF(), (1-t)*lowHsv.valueF() + t*highHsv.valueF()).rgb(); const double alpha = (1-t)*lowHsv.alphaF() + t*highHsv.alphaF(); mColorBuffer[i] = qRgba(int(qRed(rgb)*alpha), int(qGreen(rgb)*alpha), int(qBlue(rgb)*alpha), int(255*alpha)); } else { mColorBuffer[i] = QColor::fromHsvF(hue, (1-t)*lowHsv.saturationF() + t*highHsv.saturationF(), (1-t)*lowHsv.valueF() + t*highHsv.valueF()).rgb(); } break; } } } } } else if (mColorStops.size() == 1) { const QRgb rgb = mColorStops.constBegin().value().rgb(); const double alpha = mColorStops.constBegin().value().alphaF(); mColorBuffer.fill(qRgba(int(qRed(rgb)*alpha), int(qGreen(rgb)*alpha), int(qBlue(rgb)*alpha), int(255*alpha))); } else // mColorStops is empty, fill color buffer with black { mColorBuffer.fill(qRgb(0, 0, 0)); } mColorBufferInvalidated = false; } /* end of 'src/colorgradient.cpp' */ /* including file 'src/selectiondecorator-bracket.cpp' */ /* modified 2021-03-29T02:30:44, size 12308 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPSelectionDecoratorBracket //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPSelectionDecoratorBracket \brief A selection decorator which draws brackets around each selected data segment Additionally to the regular highlighting of selected segments via color, fill and scatter style, this \ref QCPSelectionDecorator subclass draws markers at the begin and end of each selected data segment of the plottable. The shape of the markers can be controlled with \ref setBracketStyle, \ref setBracketWidth and \ref setBracketHeight. The color/fill can be controlled with \ref setBracketPen and \ref setBracketBrush. To introduce custom bracket styles, it is only necessary to sublcass \ref QCPSelectionDecoratorBracket and reimplement \ref drawBracket. The rest will be managed by the base class. */ /*! Creates a new QCPSelectionDecoratorBracket instance with default values. */ QCPSelectionDecoratorBracket::QCPSelectionDecoratorBracket() : mBracketPen(QPen(Qt::black)), mBracketBrush(Qt::NoBrush), mBracketWidth(5), mBracketHeight(50), mBracketStyle(bsSquareBracket), mTangentToData(false), mTangentAverage(2) { } QCPSelectionDecoratorBracket::~QCPSelectionDecoratorBracket() { } /*! Sets the pen that will be used to draw the brackets at the beginning and end of each selected data segment. */ void QCPSelectionDecoratorBracket::setBracketPen(const QPen &pen) { mBracketPen = pen; } /*! Sets the brush that will be used to draw the brackets at the beginning and end of each selected data segment. */ void QCPSelectionDecoratorBracket::setBracketBrush(const QBrush &brush) { mBracketBrush = brush; } /*! Sets the width of the drawn bracket. The width dimension is always parallel to the key axis of the data, or the tangent direction of the current data slope, if \ref setTangentToData is enabled. */ void QCPSelectionDecoratorBracket::setBracketWidth(int width) { mBracketWidth = width; } /*! Sets the height of the drawn bracket. The height dimension is always perpendicular to the key axis of the data, or the tangent direction of the current data slope, if \ref setTangentToData is enabled. */ void QCPSelectionDecoratorBracket::setBracketHeight(int height) { mBracketHeight = height; } /*! Sets the shape that the bracket/marker will have. \see setBracketWidth, setBracketHeight */ void QCPSelectionDecoratorBracket::setBracketStyle(QCPSelectionDecoratorBracket::BracketStyle style) { mBracketStyle = style; } /*! Sets whether the brackets will be rotated such that they align with the slope of the data at the position that they appear in. For noisy data, it might be more visually appealing to average the slope over multiple data points. This can be configured via \ref setTangentAverage. */ void QCPSelectionDecoratorBracket::setTangentToData(bool enabled) { mTangentToData = enabled; } /*! Controls over how many data points the slope shall be averaged, when brackets shall be aligned with the data (if \ref setTangentToData is true). From the position of the bracket, \a pointCount points towards the selected data range will be taken into account. The smallest value of \a pointCount is 1, which is effectively equivalent to disabling \ref setTangentToData. */ void QCPSelectionDecoratorBracket::setTangentAverage(int pointCount) { mTangentAverage = pointCount; if (mTangentAverage < 1) mTangentAverage = 1; } /*! Draws the bracket shape with \a painter. The parameter \a direction is either -1 or 1 and indicates whether the bracket shall point to the left or the right (i.e. is a closing or opening bracket, respectively). The passed \a painter already contains all transformations that are necessary to position and rotate the bracket appropriately. Painting operations can be performed as if drawing upright brackets on flat data with horizontal key axis, with (0, 0) being the center of the bracket. If you wish to sublcass \ref QCPSelectionDecoratorBracket in order to provide custom bracket shapes (see \ref QCPSelectionDecoratorBracket::bsUserStyle), this is the method you should reimplement. */ void QCPSelectionDecoratorBracket::drawBracket(QCPPainter *painter, int direction) const { switch (mBracketStyle) { case bsSquareBracket: { painter->drawLine(QLineF(mBracketWidth*direction, -mBracketHeight*0.5, 0, -mBracketHeight*0.5)); painter->drawLine(QLineF(mBracketWidth*direction, mBracketHeight*0.5, 0, mBracketHeight*0.5)); painter->drawLine(QLineF(0, -mBracketHeight*0.5, 0, mBracketHeight*0.5)); break; } case bsHalfEllipse: { painter->drawArc(QRectF(-mBracketWidth*0.5, -mBracketHeight*0.5, mBracketWidth, mBracketHeight), -90*16, -180*16*direction); break; } case bsEllipse: { painter->drawEllipse(QRectF(-mBracketWidth*0.5, -mBracketHeight*0.5, mBracketWidth, mBracketHeight)); break; } case bsPlus: { painter->drawLine(QLineF(0, -mBracketHeight*0.5, 0, mBracketHeight*0.5)); painter->drawLine(QLineF(-mBracketWidth*0.5, 0, mBracketWidth*0.5, 0)); break; } default: { qDebug() << Q_FUNC_INFO << "unknown/custom bracket style can't be handeld by default implementation:" << static_cast(mBracketStyle); break; } } } /*! Draws the bracket decoration on the data points at the begin and end of each selected data segment given in \a seletion. It uses the method \ref drawBracket to actually draw the shapes. \seebaseclassmethod */ void QCPSelectionDecoratorBracket::drawDecoration(QCPPainter *painter, QCPDataSelection selection) { if (!mPlottable || selection.isEmpty()) return; if (QCPPlottableInterface1D *interface1d = mPlottable->interface1D()) { foreach (const QCPDataRange &dataRange, selection.dataRanges()) { // determine position and (if tangent mode is enabled) angle of brackets: int openBracketDir = (mPlottable->keyAxis() && !mPlottable->keyAxis()->rangeReversed()) ? 1 : -1; int closeBracketDir = -openBracketDir; QPointF openBracketPos = getPixelCoordinates(interface1d, dataRange.begin()); QPointF closeBracketPos = getPixelCoordinates(interface1d, dataRange.end()-1); double openBracketAngle = 0; double closeBracketAngle = 0; if (mTangentToData) { openBracketAngle = getTangentAngle(interface1d, dataRange.begin(), openBracketDir); closeBracketAngle = getTangentAngle(interface1d, dataRange.end()-1, closeBracketDir); } // draw opening bracket: QTransform oldTransform = painter->transform(); painter->setPen(mBracketPen); painter->setBrush(mBracketBrush); painter->translate(openBracketPos); painter->rotate(openBracketAngle/M_PI*180.0); drawBracket(painter, openBracketDir); painter->setTransform(oldTransform); // draw closing bracket: painter->setPen(mBracketPen); painter->setBrush(mBracketBrush); painter->translate(closeBracketPos); painter->rotate(closeBracketAngle/M_PI*180.0); drawBracket(painter, closeBracketDir); painter->setTransform(oldTransform); } } } /*! \internal If \ref setTangentToData is enabled, brackets need to be rotated according to the data slope. This method returns the angle in radians by which a bracket at the given \a dataIndex must be rotated. The parameter \a direction must be set to either -1 or 1, representing whether it is an opening or closing bracket. Since for slope calculation multiple data points are required, this defines the direction in which the algorithm walks, starting at \a dataIndex, to average those data points. (see \ref setTangentToData and \ref setTangentAverage) \a interface1d is the interface to the plottable's data which is used to query data coordinates. */ double QCPSelectionDecoratorBracket::getTangentAngle(const QCPPlottableInterface1D *interface1d, int dataIndex, int direction) const { if (!interface1d || dataIndex < 0 || dataIndex >= interface1d->dataCount()) return 0; direction = direction < 0 ? -1 : 1; // enforce direction is either -1 or 1 // how many steps we can actually go from index in the given direction without exceeding data bounds: int averageCount; if (direction < 0) averageCount = qMin(mTangentAverage, dataIndex); else averageCount = qMin(mTangentAverage, interface1d->dataCount()-1-dataIndex); qDebug() << averageCount; // calculate point average of averageCount points: QVector points(averageCount); QPointF pointsAverage; int currentIndex = dataIndex; for (int i=0; ikeyAxis(); QCPAxis *valueAxis = mPlottable->valueAxis(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return {0, 0}; } if (keyAxis->orientation() == Qt::Horizontal) return {keyAxis->coordToPixel(interface1d->dataMainKey(dataIndex)), valueAxis->coordToPixel(interface1d->dataMainValue(dataIndex))}; else return {valueAxis->coordToPixel(interface1d->dataMainValue(dataIndex)), keyAxis->coordToPixel(interface1d->dataMainKey(dataIndex))}; } /* end of 'src/selectiondecorator-bracket.cpp' */ /* including file 'src/layoutelements/layoutelement-axisrect.cpp' */ /* modified 2021-03-29T02:30:44, size 47193 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAxisRect //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAxisRect \brief Holds multiple axes and arranges them in a rectangular shape. This class represents an axis rect, a rectangular area that is bounded on all sides with an arbitrary number of axes. Initially QCustomPlot has one axis rect, accessible via QCustomPlot::axisRect(). However, the layout system allows to have multiple axis rects, e.g. arranged in a grid layout (QCustomPlot::plotLayout). By default, QCPAxisRect comes with four axes, at bottom, top, left and right. They can be accessed via \ref axis by providing the respective axis type (\ref QCPAxis::AxisType) and index. If you need all axes in the axis rect, use \ref axes. The top and right axes are set to be invisible initially (QCPAxis::setVisible). To add more axes to a side, use \ref addAxis or \ref addAxes. To remove an axis, use \ref removeAxis. The axis rect layerable itself only draws a background pixmap or color, if specified (\ref setBackground). It is placed on the "background" layer initially (see \ref QCPLayer for an explanation of the QCustomPlot layer system). The axes that are held by the axis rect can be placed on other layers, independently of the axis rect. Every axis rect has a child layout of type \ref QCPLayoutInset. It is accessible via \ref insetLayout and can be used to have other layout elements (or even other layouts with multiple elements) hovering inside the axis rect. If an axis rect is clicked and dragged, it processes this by moving certain axis ranges. The behaviour can be controlled with \ref setRangeDrag and \ref setRangeDragAxes. If the mouse wheel is scrolled while the cursor is on the axis rect, certain axes are scaled. This is controllable via \ref setRangeZoom, \ref setRangeZoomAxes and \ref setRangeZoomFactor. These interactions are only enabled if \ref QCustomPlot::setInteractions contains \ref QCP::iRangeDrag and \ref QCP::iRangeZoom. \image html AxisRectSpacingOverview.png
Overview of the spacings and paddings that define the geometry of an axis. The dashed line on the far left indicates the viewport/widget border.
*/ /* start documentation of inline functions */ /*! \fn QCPLayoutInset *QCPAxisRect::insetLayout() const Returns the inset layout of this axis rect. It can be used to place other layout elements (or even layouts with multiple other elements) inside/on top of an axis rect. \see QCPLayoutInset */ /*! \fn int QCPAxisRect::left() const Returns the pixel position of the left border of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPAxisRect::right() const Returns the pixel position of the right border of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPAxisRect::top() const Returns the pixel position of the top border of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPAxisRect::bottom() const Returns the pixel position of the bottom border of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPAxisRect::width() const Returns the pixel width of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPAxisRect::height() const Returns the pixel height of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QSize QCPAxisRect::size() const Returns the pixel size of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPAxisRect::topLeft() const Returns the top left corner of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPAxisRect::topRight() const Returns the top right corner of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPAxisRect::bottomLeft() const Returns the bottom left corner of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPAxisRect::bottomRight() const Returns the bottom right corner of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPAxisRect::center() const Returns the center of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /* end documentation of inline functions */ /*! Creates a QCPAxisRect instance and sets default values. An axis is added for each of the four sides, the top and right axes are set invisible initially. */ QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes) : QCPLayoutElement(parentPlot), mBackgroundBrush(Qt::NoBrush), mBackgroundScaled(true), mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding), mInsetLayout(new QCPLayoutInset), mRangeDrag(Qt::Horizontal|Qt::Vertical), mRangeZoom(Qt::Horizontal|Qt::Vertical), mRangeZoomFactorHorz(0.85), mRangeZoomFactorVert(0.85), mDragging(false) { mInsetLayout->initializeParentPlot(mParentPlot); mInsetLayout->setParentLayerable(this); mInsetLayout->setParent(this); setMinimumSize(50, 50); setMinimumMargins(QMargins(15, 15, 15, 15)); mAxes.insert(QCPAxis::atLeft, QList()); mAxes.insert(QCPAxis::atRight, QList()); mAxes.insert(QCPAxis::atTop, QList()); mAxes.insert(QCPAxis::atBottom, QList()); if (setupDefaultAxes) { QCPAxis *xAxis = addAxis(QCPAxis::atBottom); QCPAxis *yAxis = addAxis(QCPAxis::atLeft); QCPAxis *xAxis2 = addAxis(QCPAxis::atTop); QCPAxis *yAxis2 = addAxis(QCPAxis::atRight); setRangeDragAxes(xAxis, yAxis); setRangeZoomAxes(xAxis, yAxis); xAxis2->setVisible(false); yAxis2->setVisible(false); xAxis->grid()->setVisible(true); yAxis->grid()->setVisible(true); xAxis2->grid()->setVisible(false); yAxis2->grid()->setVisible(false); xAxis2->grid()->setZeroLinePen(Qt::NoPen); yAxis2->grid()->setZeroLinePen(Qt::NoPen); xAxis2->grid()->setVisible(false); yAxis2->grid()->setVisible(false); } } QCPAxisRect::~QCPAxisRect() { delete mInsetLayout; mInsetLayout = nullptr; foreach (QCPAxis *axis, axes()) removeAxis(axis); } /*! Returns the number of axes on the axis rect side specified with \a type. \see axis */ int QCPAxisRect::axisCount(QCPAxis::AxisType type) const { return mAxes.value(type).size(); } /*! Returns the axis with the given \a index on the axis rect side specified with \a type. \see axisCount, axes */ QCPAxis *QCPAxisRect::axis(QCPAxis::AxisType type, int index) const { QList ax(mAxes.value(type)); if (index >= 0 && index < ax.size()) { return ax.at(index); } else { qDebug() << Q_FUNC_INFO << "Axis index out of bounds:" << index; return nullptr; } } /*! Returns all axes on the axis rect sides specified with \a types. \a types may be a single \ref QCPAxis::AxisType or an or-combination, to get the axes of multiple sides. \see axis */ QList QCPAxisRect::axes(QCPAxis::AxisTypes types) const { QList result; if (types.testFlag(QCPAxis::atLeft)) result << mAxes.value(QCPAxis::atLeft); if (types.testFlag(QCPAxis::atRight)) result << mAxes.value(QCPAxis::atRight); if (types.testFlag(QCPAxis::atTop)) result << mAxes.value(QCPAxis::atTop); if (types.testFlag(QCPAxis::atBottom)) result << mAxes.value(QCPAxis::atBottom); return result; } /*! \overload Returns all axes of this axis rect. */ QList QCPAxisRect::axes() const { QList result; QHashIterator > it(mAxes); while (it.hasNext()) { it.next(); result << it.value(); } return result; } /*! Adds a new axis to the axis rect side specified with \a type, and returns it. If \a axis is 0, a new QCPAxis instance is created internally. QCustomPlot owns the returned axis, so if you want to remove an axis, use \ref removeAxis instead of deleting it manually. You may inject QCPAxis instances (or subclasses of QCPAxis) by setting \a axis to an axis that was previously created outside QCustomPlot. It is important to note that QCustomPlot takes ownership of the axis, so you may not delete it afterwards. Further, the \a axis must have been created with this axis rect as parent and with the same axis type as specified in \a type. If this is not the case, a debug output is generated, the axis is not added, and the method returns \c nullptr. This method can not be used to move \a axis between axis rects. The same \a axis instance must not be added multiple times to the same or different axis rects. If an axis rect side already contains one or more axes, the lower and upper endings of the new axis (\ref QCPAxis::setLowerEnding, \ref QCPAxis::setUpperEnding) are set to \ref QCPLineEnding::esHalfBar. \see addAxes, setupFullAxesBox */ QCPAxis *QCPAxisRect::addAxis(QCPAxis::AxisType type, QCPAxis *axis) { QCPAxis *newAxis = axis; if (!newAxis) { newAxis = new QCPAxis(this, type); } else // user provided existing axis instance, do some sanity checks { if (newAxis->axisType() != type) { qDebug() << Q_FUNC_INFO << "passed axis has different axis type than specified in type parameter"; return nullptr; } if (newAxis->axisRect() != this) { qDebug() << Q_FUNC_INFO << "passed axis doesn't have this axis rect as parent axis rect"; return nullptr; } if (axes().contains(newAxis)) { qDebug() << Q_FUNC_INFO << "passed axis is already owned by this axis rect"; return nullptr; } } if (!mAxes[type].isEmpty()) // multiple axes on one side, add half-bar axis ending to additional axes with offset { bool invert = (type == QCPAxis::atRight) || (type == QCPAxis::atBottom); newAxis->setLowerEnding(QCPLineEnding(QCPLineEnding::esHalfBar, 6, 10, !invert)); newAxis->setUpperEnding(QCPLineEnding(QCPLineEnding::esHalfBar, 6, 10, invert)); } mAxes[type].append(newAxis); // reset convenience axis pointers on parent QCustomPlot if they are unset: if (mParentPlot && mParentPlot->axisRectCount() > 0 && mParentPlot->axisRect(0) == this) { switch (type) { case QCPAxis::atBottom: { if (!mParentPlot->xAxis) mParentPlot->xAxis = newAxis; break; } case QCPAxis::atLeft: { if (!mParentPlot->yAxis) mParentPlot->yAxis = newAxis; break; } case QCPAxis::atTop: { if (!mParentPlot->xAxis2) mParentPlot->xAxis2 = newAxis; break; } case QCPAxis::atRight: { if (!mParentPlot->yAxis2) mParentPlot->yAxis2 = newAxis; break; } } } return newAxis; } /*! Adds a new axis with \ref addAxis to each axis rect side specified in \a types. This may be an or-combination of QCPAxis::AxisType, so axes can be added to multiple sides at once. Returns a list of the added axes. \see addAxis, setupFullAxesBox */ QList QCPAxisRect::addAxes(QCPAxis::AxisTypes types) { QList result; if (types.testFlag(QCPAxis::atLeft)) result << addAxis(QCPAxis::atLeft); if (types.testFlag(QCPAxis::atRight)) result << addAxis(QCPAxis::atRight); if (types.testFlag(QCPAxis::atTop)) result << addAxis(QCPAxis::atTop); if (types.testFlag(QCPAxis::atBottom)) result << addAxis(QCPAxis::atBottom); return result; } /*! Removes the specified \a axis from the axis rect and deletes it. Returns true on success, i.e. if \a axis was a valid axis in this axis rect. \see addAxis */ bool QCPAxisRect::removeAxis(QCPAxis *axis) { // don't access axis->axisType() to provide safety when axis is an invalid pointer, rather go through all axis containers: QHashIterator > it(mAxes); while (it.hasNext()) { it.next(); if (it.value().contains(axis)) { if (it.value().first() == axis && it.value().size() > 1) // if removing first axis, transfer axis offset to the new first axis (which at this point is the second axis, if it exists) it.value()[1]->setOffset(axis->offset()); mAxes[it.key()].removeOne(axis); if (qobject_cast(parentPlot())) // make sure this isn't called from QObject dtor when QCustomPlot is already destructed (happens when the axis rect is not in any layout and thus QObject-child of QCustomPlot) parentPlot()->axisRemoved(axis); delete axis; return true; } } qDebug() << Q_FUNC_INFO << "Axis isn't in axis rect:" << reinterpret_cast(axis); return false; } /*! Zooms in (or out) to the passed rectangular region \a pixelRect, given in pixel coordinates. All axes of this axis rect will have their range zoomed accordingly. If you only wish to zoom specific axes, use the overloaded version of this method. \see QCustomPlot::setSelectionRectMode */ void QCPAxisRect::zoom(const QRectF &pixelRect) { zoom(pixelRect, axes()); } /*! \overload Zooms in (or out) to the passed rectangular region \a pixelRect, given in pixel coordinates. Only the axes passed in \a affectedAxes will have their ranges zoomed accordingly. \see QCustomPlot::setSelectionRectMode */ void QCPAxisRect::zoom(const QRectF &pixelRect, const QList &affectedAxes) { foreach (QCPAxis *axis, affectedAxes) { if (!axis) { qDebug() << Q_FUNC_INFO << "a passed axis was zero"; continue; } QCPRange pixelRange; if (axis->orientation() == Qt::Horizontal) pixelRange = QCPRange(pixelRect.left(), pixelRect.right()); else pixelRange = QCPRange(pixelRect.top(), pixelRect.bottom()); axis->setRange(axis->pixelToCoord(pixelRange.lower), axis->pixelToCoord(pixelRange.upper)); } } /*! Convenience function to create an axis on each side that doesn't have any axes yet and set their visibility to true. Further, the top/right axes are assigned the following properties of the bottom/left axes: \li range (\ref QCPAxis::setRange) \li range reversed (\ref QCPAxis::setRangeReversed) \li scale type (\ref QCPAxis::setScaleType) \li tick visibility (\ref QCPAxis::setTicks) \li number format (\ref QCPAxis::setNumberFormat) \li number precision (\ref QCPAxis::setNumberPrecision) \li tick count of ticker (\ref QCPAxisTicker::setTickCount) \li tick origin of ticker (\ref QCPAxisTicker::setTickOrigin) Tick label visibility (\ref QCPAxis::setTickLabels) of the right and top axes are set to false. If \a connectRanges is true, the \ref QCPAxis::rangeChanged "rangeChanged" signals of the bottom and left axes are connected to the \ref QCPAxis::setRange slots of the top and right axes. */ void QCPAxisRect::setupFullAxesBox(bool connectRanges) { QCPAxis *xAxis, *yAxis, *xAxis2, *yAxis2; if (axisCount(QCPAxis::atBottom) == 0) xAxis = addAxis(QCPAxis::atBottom); else xAxis = axis(QCPAxis::atBottom); if (axisCount(QCPAxis::atLeft) == 0) yAxis = addAxis(QCPAxis::atLeft); else yAxis = axis(QCPAxis::atLeft); if (axisCount(QCPAxis::atTop) == 0) xAxis2 = addAxis(QCPAxis::atTop); else xAxis2 = axis(QCPAxis::atTop); if (axisCount(QCPAxis::atRight) == 0) yAxis2 = addAxis(QCPAxis::atRight); else yAxis2 = axis(QCPAxis::atRight); xAxis->setVisible(true); yAxis->setVisible(true); xAxis2->setVisible(true); yAxis2->setVisible(true); xAxis2->setTickLabels(false); yAxis2->setTickLabels(false); xAxis2->setRange(xAxis->range()); xAxis2->setRangeReversed(xAxis->rangeReversed()); xAxis2->setScaleType(xAxis->scaleType()); xAxis2->setTicks(xAxis->ticks()); xAxis2->setNumberFormat(xAxis->numberFormat()); xAxis2->setNumberPrecision(xAxis->numberPrecision()); xAxis2->ticker()->setTickCount(xAxis->ticker()->tickCount()); xAxis2->ticker()->setTickOrigin(xAxis->ticker()->tickOrigin()); yAxis2->setRange(yAxis->range()); yAxis2->setRangeReversed(yAxis->rangeReversed()); yAxis2->setScaleType(yAxis->scaleType()); yAxis2->setTicks(yAxis->ticks()); yAxis2->setNumberFormat(yAxis->numberFormat()); yAxis2->setNumberPrecision(yAxis->numberPrecision()); yAxis2->ticker()->setTickCount(yAxis->ticker()->tickCount()); yAxis2->ticker()->setTickOrigin(yAxis->ticker()->tickOrigin()); if (connectRanges) { connect(xAxis, SIGNAL(rangeChanged(QCPRange)), xAxis2, SLOT(setRange(QCPRange))); connect(yAxis, SIGNAL(rangeChanged(QCPRange)), yAxis2, SLOT(setRange(QCPRange))); } } /*! Returns a list of all the plottables that are associated with this axis rect. A plottable is considered associated with an axis rect if its key or value axis (or both) is in this axis rect. \see graphs, items */ QList QCPAxisRect::plottables() const { // Note: don't append all QCPAxis::plottables() into a list, because we might get duplicate entries QList result; foreach (QCPAbstractPlottable *plottable, mParentPlot->mPlottables) { if (plottable->keyAxis()->axisRect() == this || plottable->valueAxis()->axisRect() == this) result.append(plottable); } return result; } /*! Returns a list of all the graphs that are associated with this axis rect. A graph is considered associated with an axis rect if its key or value axis (or both) is in this axis rect. \see plottables, items */ QList QCPAxisRect::graphs() const { // Note: don't append all QCPAxis::graphs() into a list, because we might get duplicate entries QList result; foreach (QCPGraph *graph, mParentPlot->mGraphs) { if (graph->keyAxis()->axisRect() == this || graph->valueAxis()->axisRect() == this) result.append(graph); } return result; } /*! Returns a list of all the items that are associated with this axis rect. An item is considered associated with an axis rect if any of its positions has key or value axis set to an axis that is in this axis rect, or if any of its positions has \ref QCPItemPosition::setAxisRect set to the axis rect, or if the clip axis rect (\ref QCPAbstractItem::setClipAxisRect) is set to this axis rect. \see plottables, graphs */ QList QCPAxisRect::items() const { // Note: don't just append all QCPAxis::items() into a list, because we might get duplicate entries // and miss those items that have this axis rect as clipAxisRect. QList result; foreach (QCPAbstractItem *item, mParentPlot->mItems) { if (item->clipAxisRect() == this) { result.append(item); continue; } foreach (QCPItemPosition *position, item->positions()) { if (position->axisRect() == this || position->keyAxis()->axisRect() == this || position->valueAxis()->axisRect() == this) { result.append(item); break; } } } return result; } /*! This method is called automatically upon replot and doesn't need to be called by users of QCPAxisRect. Calls the base class implementation to update the margins (see \ref QCPLayoutElement::update), and finally passes the \ref rect to the inset layout (\ref insetLayout) and calls its QCPInsetLayout::update function. \seebaseclassmethod */ void QCPAxisRect::update(UpdatePhase phase) { QCPLayoutElement::update(phase); switch (phase) { case upPreparation: { foreach (QCPAxis *axis, axes()) axis->setupTickVectors(); break; } case upLayout: { mInsetLayout->setOuterRect(rect()); break; } default: break; } // pass update call on to inset layout (doesn't happen automatically, because QCPAxisRect doesn't derive from QCPLayout): mInsetLayout->update(phase); } /* inherits documentation from base class */ QList QCPAxisRect::elements(bool recursive) const { QList result; if (mInsetLayout) { result << mInsetLayout; if (recursive) result << mInsetLayout->elements(recursive); } return result; } /* inherits documentation from base class */ void QCPAxisRect::applyDefaultAntialiasingHint(QCPPainter *painter) const { painter->setAntialiasing(false); } /* inherits documentation from base class */ void QCPAxisRect::draw(QCPPainter *painter) { drawBackground(painter); } /*! Sets \a pm as the axis background pixmap. The axis background pixmap will be drawn inside the axis rect. Since axis rects place themselves on the "background" layer by default, the axis rect backgrounds are usually drawn below everything else. For cases where the provided pixmap doesn't have the same size as the axis rect, scaling can be enabled with \ref setBackgroundScaled and the scaling mode (i.e. whether and how the aspect ratio is preserved) can be set with \ref setBackgroundScaledMode. To set all these options in one call, consider using the overloaded version of this function. Below the pixmap, the axis rect may be optionally filled with a brush, if specified with \ref setBackground(const QBrush &brush). \see setBackgroundScaled, setBackgroundScaledMode, setBackground(const QBrush &brush) */ void QCPAxisRect::setBackground(const QPixmap &pm) { mBackgroundPixmap = pm; mScaledBackgroundPixmap = QPixmap(); } /*! \overload Sets \a brush as the background brush. The axis rect background will be filled with this brush. Since axis rects place themselves on the "background" layer by default, the axis rect backgrounds are usually drawn below everything else. The brush will be drawn before (under) any background pixmap, which may be specified with \ref setBackground(const QPixmap &pm). To disable drawing of a background brush, set \a brush to Qt::NoBrush. \see setBackground(const QPixmap &pm) */ void QCPAxisRect::setBackground(const QBrush &brush) { mBackgroundBrush = brush; } /*! \overload Allows setting the background pixmap of the axis rect, whether it shall be scaled and how it shall be scaled in one call. \see setBackground(const QPixmap &pm), setBackgroundScaled, setBackgroundScaledMode */ void QCPAxisRect::setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode) { mBackgroundPixmap = pm; mScaledBackgroundPixmap = QPixmap(); mBackgroundScaled = scaled; mBackgroundScaledMode = mode; } /*! Sets whether the axis background pixmap shall be scaled to fit the axis rect or not. If \a scaled is set to true, you may control whether and how the aspect ratio of the original pixmap is preserved with \ref setBackgroundScaledMode. Note that the scaled version of the original pixmap is buffered, so there is no performance penalty on replots. (Except when the axis rect dimensions are changed continuously.) \see setBackground, setBackgroundScaledMode */ void QCPAxisRect::setBackgroundScaled(bool scaled) { mBackgroundScaled = scaled; } /*! If scaling of the axis background pixmap is enabled (\ref setBackgroundScaled), use this function to define whether and how the aspect ratio of the original pixmap passed to \ref setBackground is preserved. \see setBackground, setBackgroundScaled */ void QCPAxisRect::setBackgroundScaledMode(Qt::AspectRatioMode mode) { mBackgroundScaledMode = mode; } /*! Returns the range drag axis of the \a orientation provided. If multiple axes were set, returns the first one (use \ref rangeDragAxes to retrieve a list with all set axes). \see setRangeDragAxes */ QCPAxis *QCPAxisRect::rangeDragAxis(Qt::Orientation orientation) { if (orientation == Qt::Horizontal) return mRangeDragHorzAxis.isEmpty() ? nullptr : mRangeDragHorzAxis.first().data(); else return mRangeDragVertAxis.isEmpty() ? nullptr : mRangeDragVertAxis.first().data(); } /*! Returns the range zoom axis of the \a orientation provided. If multiple axes were set, returns the first one (use \ref rangeZoomAxes to retrieve a list with all set axes). \see setRangeZoomAxes */ QCPAxis *QCPAxisRect::rangeZoomAxis(Qt::Orientation orientation) { if (orientation == Qt::Horizontal) return mRangeZoomHorzAxis.isEmpty() ? nullptr : mRangeZoomHorzAxis.first().data(); else return mRangeZoomVertAxis.isEmpty() ? nullptr : mRangeZoomVertAxis.first().data(); } /*! Returns all range drag axes of the \a orientation provided. \see rangeZoomAxis, setRangeZoomAxes */ QList QCPAxisRect::rangeDragAxes(Qt::Orientation orientation) { QList result; if (orientation == Qt::Horizontal) { foreach (QPointer axis, mRangeDragHorzAxis) { if (!axis.isNull()) result.append(axis.data()); } } else { foreach (QPointer axis, mRangeDragVertAxis) { if (!axis.isNull()) result.append(axis.data()); } } return result; } /*! Returns all range zoom axes of the \a orientation provided. \see rangeDragAxis, setRangeDragAxes */ QList QCPAxisRect::rangeZoomAxes(Qt::Orientation orientation) { QList result; if (orientation == Qt::Horizontal) { foreach (QPointer axis, mRangeZoomHorzAxis) { if (!axis.isNull()) result.append(axis.data()); } } else { foreach (QPointer axis, mRangeZoomVertAxis) { if (!axis.isNull()) result.append(axis.data()); } } return result; } /*! Returns the range zoom factor of the \a orientation provided. \see setRangeZoomFactor */ double QCPAxisRect::rangeZoomFactor(Qt::Orientation orientation) { return (orientation == Qt::Horizontal ? mRangeZoomFactorHorz : mRangeZoomFactorVert); } /*! Sets which axis orientation may be range dragged by the user with mouse interaction. What orientation corresponds to which specific axis can be set with \ref setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical). By default, the horizontal axis is the bottom axis (xAxis) and the vertical axis is the left axis (yAxis). To disable range dragging entirely, pass \c nullptr as \a orientations or remove \ref QCP::iRangeDrag from \ref QCustomPlot::setInteractions. To enable range dragging for both directions, pass Qt::Horizontal | Qt::Vertical as \a orientations. In addition to setting \a orientations to a non-zero value, make sure \ref QCustomPlot::setInteractions contains \ref QCP::iRangeDrag to enable the range dragging interaction. \see setRangeZoom, setRangeDragAxes, QCustomPlot::setNoAntialiasingOnDrag */ void QCPAxisRect::setRangeDrag(Qt::Orientations orientations) { mRangeDrag = orientations; } /*! Sets which axis orientation may be zoomed by the user with the mouse wheel. What orientation corresponds to which specific axis can be set with \ref setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical). By default, the horizontal axis is the bottom axis (xAxis) and the vertical axis is the left axis (yAxis). To disable range zooming entirely, pass \c nullptr as \a orientations or remove \ref QCP::iRangeZoom from \ref QCustomPlot::setInteractions. To enable range zooming for both directions, pass Qt::Horizontal | Qt::Vertical as \a orientations. In addition to setting \a orientations to a non-zero value, make sure \ref QCustomPlot::setInteractions contains \ref QCP::iRangeZoom to enable the range zooming interaction. \see setRangeZoomFactor, setRangeZoomAxes, setRangeDrag */ void QCPAxisRect::setRangeZoom(Qt::Orientations orientations) { mRangeZoom = orientations; } /*! \overload Sets the axes whose range will be dragged when \ref setRangeDrag enables mouse range dragging on the QCustomPlot widget. Pass \c nullptr if no axis shall be dragged in the respective orientation. Use the overload taking a list of axes, if multiple axes (more than one per orientation) shall react to dragging interactions. \see setRangeZoomAxes */ void QCPAxisRect::setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical) { QList horz, vert; if (horizontal) horz.append(horizontal); if (vertical) vert.append(vertical); setRangeDragAxes(horz, vert); } /*! \overload This method allows to set up multiple axes to react to horizontal and vertical dragging. The drag orientation that the respective axis will react to is deduced from its orientation (\ref QCPAxis::orientation). In the unusual case that you wish to e.g. drag a vertically oriented axis with a horizontal drag motion, use the overload taking two separate lists for horizontal and vertical dragging. */ void QCPAxisRect::setRangeDragAxes(QList axes) { QList horz, vert; foreach (QCPAxis *ax, axes) { if (ax->orientation() == Qt::Horizontal) horz.append(ax); else vert.append(ax); } setRangeDragAxes(horz, vert); } /*! \overload This method allows to set multiple axes up to react to horizontal and vertical dragging, and define specifically which axis reacts to which drag orientation (irrespective of the axis orientation). */ void QCPAxisRect::setRangeDragAxes(QList horizontal, QList vertical) { mRangeDragHorzAxis.clear(); foreach (QCPAxis *ax, horizontal) { QPointer axPointer(ax); if (!axPointer.isNull()) mRangeDragHorzAxis.append(axPointer); else qDebug() << Q_FUNC_INFO << "invalid axis passed in horizontal list:" << reinterpret_cast(ax); } mRangeDragVertAxis.clear(); foreach (QCPAxis *ax, vertical) { QPointer axPointer(ax); if (!axPointer.isNull()) mRangeDragVertAxis.append(axPointer); else qDebug() << Q_FUNC_INFO << "invalid axis passed in vertical list:" << reinterpret_cast(ax); } } /*! Sets the axes whose range will be zoomed when \ref setRangeZoom enables mouse wheel zooming on the QCustomPlot widget. Pass \c nullptr if no axis shall be zoomed in the respective orientation. The two axes can be zoomed with different strengths, when different factors are passed to \ref setRangeZoomFactor(double horizontalFactor, double verticalFactor). Use the overload taking a list of axes, if multiple axes (more than one per orientation) shall react to zooming interactions. \see setRangeDragAxes */ void QCPAxisRect::setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical) { QList horz, vert; if (horizontal) horz.append(horizontal); if (vertical) vert.append(vertical); setRangeZoomAxes(horz, vert); } /*! \overload This method allows to set up multiple axes to react to horizontal and vertical range zooming. The zoom orientation that the respective axis will react to is deduced from its orientation (\ref QCPAxis::orientation). In the unusual case that you wish to e.g. zoom a vertically oriented axis with a horizontal zoom interaction, use the overload taking two separate lists for horizontal and vertical zooming. */ void QCPAxisRect::setRangeZoomAxes(QList axes) { QList horz, vert; foreach (QCPAxis *ax, axes) { if (ax->orientation() == Qt::Horizontal) horz.append(ax); else vert.append(ax); } setRangeZoomAxes(horz, vert); } /*! \overload This method allows to set multiple axes up to react to horizontal and vertical zooming, and define specifically which axis reacts to which zoom orientation (irrespective of the axis orientation). */ void QCPAxisRect::setRangeZoomAxes(QList horizontal, QList vertical) { mRangeZoomHorzAxis.clear(); foreach (QCPAxis *ax, horizontal) { QPointer axPointer(ax); if (!axPointer.isNull()) mRangeZoomHorzAxis.append(axPointer); else qDebug() << Q_FUNC_INFO << "invalid axis passed in horizontal list:" << reinterpret_cast(ax); } mRangeZoomVertAxis.clear(); foreach (QCPAxis *ax, vertical) { QPointer axPointer(ax); if (!axPointer.isNull()) mRangeZoomVertAxis.append(axPointer); else qDebug() << Q_FUNC_INFO << "invalid axis passed in vertical list:" << reinterpret_cast(ax); } } /*! Sets how strong one rotation step of the mouse wheel zooms, when range zoom was activated with \ref setRangeZoom. The two parameters \a horizontalFactor and \a verticalFactor provide a way to let the horizontal axis zoom at different rates than the vertical axis. Which axis is horizontal and which is vertical, can be set with \ref setRangeZoomAxes. When the zoom factor is greater than one, scrolling the mouse wheel backwards (towards the user) will zoom in (make the currently visible range smaller). For zoom factors smaller than one, the same scrolling direction will zoom out. */ void QCPAxisRect::setRangeZoomFactor(double horizontalFactor, double verticalFactor) { mRangeZoomFactorHorz = horizontalFactor; mRangeZoomFactorVert = verticalFactor; } /*! \overload Sets both the horizontal and vertical zoom \a factor. */ void QCPAxisRect::setRangeZoomFactor(double factor) { mRangeZoomFactorHorz = factor; mRangeZoomFactorVert = factor; } /*! \internal Draws the background of this axis rect. It may consist of a background fill (a QBrush) and a pixmap. If a brush was given via \ref setBackground(const QBrush &brush), this function first draws an according filling inside the axis rect with the provided \a painter. Then, if a pixmap was provided via \ref setBackground, this function buffers the scaled version depending on \ref setBackgroundScaled and \ref setBackgroundScaledMode and then draws it inside the axis rect with the provided \a painter. The scaled version is buffered in mScaledBackgroundPixmap to prevent expensive rescaling at every redraw. It is only updated, when the axis rect has changed in a way that requires a rescale of the background pixmap (this is dependent on the \ref setBackgroundScaledMode), or when a differend axis background pixmap was set. \see setBackground, setBackgroundScaled, setBackgroundScaledMode */ void QCPAxisRect::drawBackground(QCPPainter *painter) { // draw background fill: if (mBackgroundBrush != Qt::NoBrush) painter->fillRect(mRect, mBackgroundBrush); // draw background pixmap (on top of fill, if brush specified): if (!mBackgroundPixmap.isNull()) { if (mBackgroundScaled) { // check whether mScaledBackground needs to be updated: QSize scaledSize(mBackgroundPixmap.size()); scaledSize.scale(mRect.size(), mBackgroundScaledMode); if (mScaledBackgroundPixmap.size() != scaledSize) mScaledBackgroundPixmap = mBackgroundPixmap.scaled(mRect.size(), mBackgroundScaledMode, Qt::SmoothTransformation); painter->drawPixmap(mRect.topLeft()+QPoint(0, -1), mScaledBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height()) & mScaledBackgroundPixmap.rect()); } else { painter->drawPixmap(mRect.topLeft()+QPoint(0, -1), mBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height())); } } } /*! \internal This function makes sure multiple axes on the side specified with \a type don't collide, but are distributed according to their respective space requirement (QCPAxis::calculateMargin). It does this by setting an appropriate offset (\ref QCPAxis::setOffset) on all axes except the one with index zero. This function is called by \ref calculateAutoMargin. */ void QCPAxisRect::updateAxesOffset(QCPAxis::AxisType type) { const QList axesList = mAxes.value(type); if (axesList.isEmpty()) return; bool isFirstVisible = !axesList.first()->visible(); // if the first axis is visible, the second axis (which is where the loop starts) isn't the first visible axis, so initialize with false for (int i=1; ioffset() + axesList.at(i-1)->calculateMargin(); if (axesList.at(i)->visible()) // only add inner tick length to offset if this axis is visible and it's not the first visible one (might happen if true first axis is invisible) { if (!isFirstVisible) offset += axesList.at(i)->tickLengthIn(); isFirstVisible = false; } axesList.at(i)->setOffset(offset); } } /* inherits documentation from base class */ int QCPAxisRect::calculateAutoMargin(QCP::MarginSide side) { if (!mAutoMargins.testFlag(side)) qDebug() << Q_FUNC_INFO << "Called with side that isn't specified as auto margin"; updateAxesOffset(QCPAxis::marginSideToAxisType(side)); // note: only need to look at the last (outer most) axis to determine the total margin, due to updateAxisOffset call const QList axesList = mAxes.value(QCPAxis::marginSideToAxisType(side)); if (!axesList.isEmpty()) return axesList.last()->offset() + axesList.last()->calculateMargin(); else return 0; } /*! \internal Reacts to a change in layout to potentially set the convenience axis pointers \ref QCustomPlot::xAxis, \ref QCustomPlot::yAxis, etc. of the parent QCustomPlot to the respective axes of this axis rect. This is only done if the respective convenience pointer is currently zero and if there is no QCPAxisRect at position (0, 0) of the plot layout. This automation makes it simpler to replace the main axis rect with a newly created one, without the need to manually reset the convenience pointers. */ void QCPAxisRect::layoutChanged() { if (mParentPlot && mParentPlot->axisRectCount() > 0 && mParentPlot->axisRect(0) == this) { if (axisCount(QCPAxis::atBottom) > 0 && !mParentPlot->xAxis) mParentPlot->xAxis = axis(QCPAxis::atBottom); if (axisCount(QCPAxis::atLeft) > 0 && !mParentPlot->yAxis) mParentPlot->yAxis = axis(QCPAxis::atLeft); if (axisCount(QCPAxis::atTop) > 0 && !mParentPlot->xAxis2) mParentPlot->xAxis2 = axis(QCPAxis::atTop); if (axisCount(QCPAxis::atRight) > 0 && !mParentPlot->yAxis2) mParentPlot->yAxis2 = axis(QCPAxis::atRight); } } /*! \internal Event handler for when a mouse button is pressed on the axis rect. If the left mouse button is pressed, the range dragging interaction is initialized (the actual range manipulation happens in the \ref mouseMoveEvent). The mDragging flag is set to true and some anchor points are set that are needed to determine the distance the mouse was dragged in the mouse move/release events later. \see mouseMoveEvent, mouseReleaseEvent */ void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details) { Q_UNUSED(details) if (event->buttons() & Qt::LeftButton) { mDragging = true; // initialize antialiasing backup in case we start dragging: if (mParentPlot->noAntialiasingOnDrag()) { mAADragBackup = mParentPlot->antialiasedElements(); mNotAADragBackup = mParentPlot->notAntialiasedElements(); } // Mouse range dragging interaction: if (mParentPlot->interactions().testFlag(QCP::iRangeDrag)) { mDragStartHorzRange.clear(); foreach (QPointer axis, mRangeDragHorzAxis) mDragStartHorzRange.append(axis.isNull() ? QCPRange() : axis->range()); mDragStartVertRange.clear(); foreach (QPointer axis, mRangeDragVertAxis) mDragStartVertRange.append(axis.isNull() ? QCPRange() : axis->range()); } } } /*! \internal Event handler for when the mouse is moved on the axis rect. If range dragging was activated in a preceding \ref mousePressEvent, the range is moved accordingly. \see mousePressEvent, mouseReleaseEvent */ void QCPAxisRect::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) { Q_UNUSED(startPos) // Mouse range dragging interaction: if (mDragging && mParentPlot->interactions().testFlag(QCP::iRangeDrag)) { if (mRangeDrag.testFlag(Qt::Horizontal)) { for (int i=0; i= mDragStartHorzRange.size()) break; if (ax->mScaleType == QCPAxis::stLinear) { double diff = ax->pixelToCoord(startPos.x()) - ax->pixelToCoord(event->pos().x()); ax->setRange(mDragStartHorzRange.at(i).lower+diff, mDragStartHorzRange.at(i).upper+diff); } else if (ax->mScaleType == QCPAxis::stLogarithmic) { double diff = ax->pixelToCoord(startPos.x()) / ax->pixelToCoord(event->pos().x()); ax->setRange(mDragStartHorzRange.at(i).lower*diff, mDragStartHorzRange.at(i).upper*diff); } } } if (mRangeDrag.testFlag(Qt::Vertical)) { for (int i=0; i= mDragStartVertRange.size()) break; if (ax->mScaleType == QCPAxis::stLinear) { double diff = ax->pixelToCoord(startPos.y()) - ax->pixelToCoord(event->pos().y()); ax->setRange(mDragStartVertRange.at(i).lower+diff, mDragStartVertRange.at(i).upper+diff); } else if (ax->mScaleType == QCPAxis::stLogarithmic) { double diff = ax->pixelToCoord(startPos.y()) / ax->pixelToCoord(event->pos().y()); ax->setRange(mDragStartVertRange.at(i).lower*diff, mDragStartVertRange.at(i).upper*diff); } } } if (mRangeDrag != 0) // if either vertical or horizontal drag was enabled, do a replot { if (mParentPlot->noAntialiasingOnDrag()) mParentPlot->setNotAntialiasedElements(QCP::aeAll); mParentPlot->replot(QCustomPlot::rpQueuedReplot); } } } /* inherits documentation from base class */ void QCPAxisRect::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) { Q_UNUSED(event) Q_UNUSED(startPos) mDragging = false; if (mParentPlot->noAntialiasingOnDrag()) { mParentPlot->setAntialiasedElements(mAADragBackup); mParentPlot->setNotAntialiasedElements(mNotAADragBackup); } } /*! \internal Event handler for mouse wheel events. If rangeZoom is Qt::Horizontal, Qt::Vertical or both, the ranges of the axes defined as rangeZoomHorzAxis and rangeZoomVertAxis are scaled. The center of the scaling operation is the current cursor position inside the axis rect. The scaling factor is dependent on the mouse wheel delta (which direction the wheel was rotated) to provide a natural zooming feel. The Strength of the zoom can be controlled via \ref setRangeZoomFactor. Note, that event->angleDelta() is usually +/-120 for single rotation steps. However, if the mouse wheel is turned rapidly, many steps may bunch up to one event, so the delta may then be multiples of 120. This is taken into account here, by calculating \a wheelSteps and using it as exponent of the range zoom factor. This takes care of the wheel direction automatically, by inverting the factor, when the wheel step is negative (f^-1 = 1/f). */ void QCPAxisRect::wheelEvent(QWheelEvent *event) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) const double delta = event->delta(); #else const double delta = event->angleDelta().y(); #endif #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) const QPointF pos = event->pos(); #else const QPointF pos = event->position(); #endif // Mouse range zooming interaction: if (mParentPlot->interactions().testFlag(QCP::iRangeZoom)) { if (mRangeZoom != 0) { double factor; double wheelSteps = delta/120.0; // a single step delta is +/-120 usually if (mRangeZoom.testFlag(Qt::Horizontal)) { factor = qPow(mRangeZoomFactorHorz, wheelSteps); foreach (QPointer axis, mRangeZoomHorzAxis) { if (!axis.isNull()) axis->scaleRange(factor, axis->pixelToCoord(pos.x())); } } if (mRangeZoom.testFlag(Qt::Vertical)) { factor = qPow(mRangeZoomFactorVert, wheelSteps); foreach (QPointer axis, mRangeZoomVertAxis) { if (!axis.isNull()) axis->scaleRange(factor, axis->pixelToCoord(pos.y())); } } mParentPlot->replot(); } } } /* end of 'src/layoutelements/layoutelement-axisrect.cpp' */ /* including file 'src/layoutelements/layoutelement-legend.cpp' */ /* modified 2021-03-29T02:30:44, size 31762 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAbstractLegendItem //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAbstractLegendItem \brief The abstract base class for all entries in a QCPLegend. It defines a very basic interface for entries in a QCPLegend. For representing plottables in the legend, the subclass \ref QCPPlottableLegendItem is more suitable. Only derive directly from this class when you need absolute freedom (e.g. a custom legend entry that's not even associated with a plottable). You must implement the following pure virtual functions: \li \ref draw (from QCPLayerable) You inherit the following members you may use:
QCPLegend *\b mParentLegend A pointer to the parent QCPLegend.
QFont \b mFont The generic font of the item. You should use this font for all or at least the most prominent text of the item.
*/ /* start of documentation of signals */ /*! \fn void QCPAbstractLegendItem::selectionChanged(bool selected) This signal is emitted when the selection state of this legend item has changed, either by user interaction or by a direct call to \ref setSelected. */ /* end of documentation of signals */ /*! Constructs a QCPAbstractLegendItem and associates it with the QCPLegend \a parent. This does not cause the item to be added to \a parent, so \ref QCPLegend::addItem must be called separately. */ QCPAbstractLegendItem::QCPAbstractLegendItem(QCPLegend *parent) : QCPLayoutElement(parent->parentPlot()), mParentLegend(parent), mFont(parent->font()), mTextColor(parent->textColor()), mSelectedFont(parent->selectedFont()), mSelectedTextColor(parent->selectedTextColor()), mSelectable(true), mSelected(false) { setLayer(QLatin1String("legend")); setMargins(QMargins(0, 0, 0, 0)); } /*! Sets the default font of this specific legend item to \a font. \see setTextColor, QCPLegend::setFont */ void QCPAbstractLegendItem::setFont(const QFont &font) { mFont = font; } /*! Sets the default text color of this specific legend item to \a color. \see setFont, QCPLegend::setTextColor */ void QCPAbstractLegendItem::setTextColor(const QColor &color) { mTextColor = color; } /*! When this legend item is selected, \a font is used to draw generic text, instead of the normal font set with \ref setFont. \see setFont, QCPLegend::setSelectedFont */ void QCPAbstractLegendItem::setSelectedFont(const QFont &font) { mSelectedFont = font; } /*! When this legend item is selected, \a color is used to draw generic text, instead of the normal color set with \ref setTextColor. \see setTextColor, QCPLegend::setSelectedTextColor */ void QCPAbstractLegendItem::setSelectedTextColor(const QColor &color) { mSelectedTextColor = color; } /*! Sets whether this specific legend item is selectable. \see setSelectedParts, QCustomPlot::setInteractions */ void QCPAbstractLegendItem::setSelectable(bool selectable) { if (mSelectable != selectable) { mSelectable = selectable; emit selectableChanged(mSelectable); } } /*! Sets whether this specific legend item is selected. It is possible to set the selection state of this item by calling this function directly, even if setSelectable is set to false. \see setSelectableParts, QCustomPlot::setInteractions */ void QCPAbstractLegendItem::setSelected(bool selected) { if (mSelected != selected) { mSelected = selected; emit selectionChanged(mSelected); } } /* inherits documentation from base class */ double QCPAbstractLegendItem::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (!mParentPlot) return -1; if (onlySelectable && (!mSelectable || !mParentLegend->selectableParts().testFlag(QCPLegend::spItems))) return -1; if (mRect.contains(pos.toPoint())) return mParentPlot->selectionTolerance()*0.99; else return -1; } /* inherits documentation from base class */ void QCPAbstractLegendItem::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeLegendItems); } /* inherits documentation from base class */ QRect QCPAbstractLegendItem::clipRect() const { return mOuterRect; } /* inherits documentation from base class */ void QCPAbstractLegendItem::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) { Q_UNUSED(event) Q_UNUSED(details) if (mSelectable && mParentLegend->selectableParts().testFlag(QCPLegend::spItems)) { bool selBefore = mSelected; setSelected(additive ? !mSelected : true); if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore; } } /* inherits documentation from base class */ void QCPAbstractLegendItem::deselectEvent(bool *selectionStateChanged) { if (mSelectable && mParentLegend->selectableParts().testFlag(QCPLegend::spItems)) { bool selBefore = mSelected; setSelected(false); if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore; } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPlottableLegendItem //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPlottableLegendItem \brief A legend item representing a plottable with an icon and the plottable name. This is the standard legend item for plottables. It displays an icon of the plottable next to the plottable name. The icon is drawn by the respective plottable itself (\ref QCPAbstractPlottable::drawLegendIcon), and tries to give an intuitive symbol for the plottable. For example, the QCPGraph draws a centered horizontal line and/or a single scatter point in the middle. Legend items of this type are always associated with one plottable (retrievable via the plottable() function and settable with the constructor). You may change the font of the plottable name with \ref setFont. Icon padding and border pen is taken from the parent QCPLegend, see \ref QCPLegend::setIconBorderPen and \ref QCPLegend::setIconTextPadding. The function \ref QCPAbstractPlottable::addToLegend/\ref QCPAbstractPlottable::removeFromLegend creates/removes legend items of this type. Since QCPLegend is based on QCPLayoutGrid, a legend item itself is just a subclass of QCPLayoutElement. While it could be added to a legend (or any other layout) via the normal layout interface, QCPLegend has specialized functions for handling legend items conveniently, see the documentation of \ref QCPLegend. */ /*! Creates a new legend item associated with \a plottable. Once it's created, it can be added to the legend via \ref QCPLegend::addItem. A more convenient way of adding/removing a plottable to/from the legend is via the functions \ref QCPAbstractPlottable::addToLegend and \ref QCPAbstractPlottable::removeFromLegend. */ QCPPlottableLegendItem::QCPPlottableLegendItem(QCPLegend *parent, QCPAbstractPlottable *plottable) : QCPAbstractLegendItem(parent), mPlottable(plottable) { setAntialiased(false); } /*! \internal Returns the pen that shall be used to draw the icon border, taking into account the selection state of this item. */ QPen QCPPlottableLegendItem::getIconBorderPen() const { return mSelected ? mParentLegend->selectedIconBorderPen() : mParentLegend->iconBorderPen(); } /*! \internal Returns the text color that shall be used to draw text, taking into account the selection state of this item. */ QColor QCPPlottableLegendItem::getTextColor() const { return mSelected ? mSelectedTextColor : mTextColor; } /*! \internal Returns the font that shall be used to draw text, taking into account the selection state of this item. */ QFont QCPPlottableLegendItem::getFont() const { return mSelected ? mSelectedFont : mFont; } /*! \internal Draws the item with \a painter. The size and position of the drawn legend item is defined by the parent layout (typically a \ref QCPLegend) and the \ref minimumOuterSizeHint and \ref maximumOuterSizeHint of this legend item. */ void QCPPlottableLegendItem::draw(QCPPainter *painter) { if (!mPlottable) return; painter->setFont(getFont()); painter->setPen(QPen(getTextColor())); QSize iconSize = mParentLegend->iconSize(); QRect textRect = painter->fontMetrics().boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name()); QRect iconRect(mRect.topLeft(), iconSize); int textHeight = qMax(textRect.height(), iconSize.height()); // if text has smaller height than icon, center text vertically in icon height, else align tops painter->drawText(mRect.x()+iconSize.width()+mParentLegend->iconTextPadding(), mRect.y(), textRect.width(), textHeight, Qt::TextDontClip, mPlottable->name()); // draw icon: painter->save(); painter->setClipRect(iconRect, Qt::IntersectClip); mPlottable->drawLegendIcon(painter, iconRect); painter->restore(); // draw icon border: if (getIconBorderPen().style() != Qt::NoPen) { painter->setPen(getIconBorderPen()); painter->setBrush(Qt::NoBrush); int halfPen = qCeil(painter->pen().widthF()*0.5)+1; painter->setClipRect(mOuterRect.adjusted(-halfPen, -halfPen, halfPen, halfPen)); // extend default clip rect so thicker pens (especially during selection) are not clipped painter->drawRect(iconRect); } } /*! \internal Calculates and returns the size of this item. This includes the icon, the text and the padding in between. \seebaseclassmethod */ QSize QCPPlottableLegendItem::minimumOuterSizeHint() const { if (!mPlottable) return {}; QSize result(0, 0); QRect textRect; QFontMetrics fontMetrics(getFont()); QSize iconSize = mParentLegend->iconSize(); textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name()); result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width()); result.setHeight(qMax(textRect.height(), iconSize.height())); result.rwidth() += mMargins.left()+mMargins.right(); result.rheight() += mMargins.top()+mMargins.bottom(); return result; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPLegend //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPLegend \brief Manages a legend inside a QCustomPlot. A legend is a small box somewhere in the plot which lists plottables with their name and icon. A legend is populated with legend items by calling \ref QCPAbstractPlottable::addToLegend on the plottable, for which a legend item shall be created. In the case of the main legend (\ref QCustomPlot::legend), simply adding plottables to the plot while \ref QCustomPlot::setAutoAddPlottableToLegend is set to true (the default) creates corresponding legend items. The legend item associated with a certain plottable can be removed with \ref QCPAbstractPlottable::removeFromLegend. However, QCPLegend also offers an interface to add and manipulate legend items directly: \ref item, \ref itemWithPlottable, \ref itemCount, \ref addItem, \ref removeItem, etc. Since \ref QCPLegend derives from \ref QCPLayoutGrid, it can be placed in any position a \ref QCPLayoutElement may be positioned. The legend items are themselves \ref QCPLayoutElement "QCPLayoutElements" which are placed in the grid layout of the legend. \ref QCPLegend only adds an interface specialized for handling child elements of type \ref QCPAbstractLegendItem, as mentioned above. In principle, any other layout elements may also be added to a legend via the normal \ref QCPLayoutGrid interface. See the special page about \link thelayoutsystem The Layout System\endlink for examples on how to add other elements to the legend and move it outside the axis rect. Use the methods \ref setFillOrder and \ref setWrap inherited from \ref QCPLayoutGrid to control in which order (column first or row first) the legend is filled up when calling \ref addItem, and at which column or row wrapping occurs. The default fill order for legends is \ref foRowsFirst. By default, every QCustomPlot has one legend (\ref QCustomPlot::legend) which is placed in the inset layout of the main axis rect (\ref QCPAxisRect::insetLayout). To move the legend to another position inside the axis rect, use the methods of the \ref QCPLayoutInset. To move the legend outside of the axis rect, place it anywhere else with the \ref QCPLayout/\ref QCPLayoutElement interface. */ /* start of documentation of signals */ /*! \fn void QCPLegend::selectionChanged(QCPLegend::SelectableParts selection); This signal is emitted when the selection state of this legend has changed. \see setSelectedParts, setSelectableParts */ /* end of documentation of signals */ /*! Constructs a new QCPLegend instance with default values. Note that by default, QCustomPlot already contains a legend ready to be used as \ref QCustomPlot::legend */ QCPLegend::QCPLegend() : mIconTextPadding{} { setFillOrder(QCPLayoutGrid::foRowsFirst); setWrap(0); setRowSpacing(3); setColumnSpacing(8); setMargins(QMargins(7, 5, 7, 4)); setAntialiased(false); setIconSize(32, 18); setIconTextPadding(7); setSelectableParts(spLegendBox | spItems); setSelectedParts(spNone); setBorderPen(QPen(Qt::black, 0)); setSelectedBorderPen(QPen(Qt::blue, 2)); setIconBorderPen(Qt::NoPen); setSelectedIconBorderPen(QPen(Qt::blue, 2)); setBrush(Qt::white); setSelectedBrush(Qt::white); setTextColor(Qt::black); setSelectedTextColor(Qt::blue); } QCPLegend::~QCPLegend() { clearItems(); if (qobject_cast(mParentPlot)) // make sure this isn't called from QObject dtor when QCustomPlot is already destructed (happens when the legend is not in any layout and thus QObject-child of QCustomPlot) mParentPlot->legendRemoved(this); } /* no doc for getter, see setSelectedParts */ QCPLegend::SelectableParts QCPLegend::selectedParts() const { // check whether any legend elements selected, if yes, add spItems to return value bool hasSelectedItems = false; for (int i=0; iselected()) { hasSelectedItems = true; break; } } if (hasSelectedItems) return mSelectedParts | spItems; else return mSelectedParts & ~spItems; } /*! Sets the pen, the border of the entire legend is drawn with. */ void QCPLegend::setBorderPen(const QPen &pen) { mBorderPen = pen; } /*! Sets the brush of the legend background. */ void QCPLegend::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the default font of legend text. Legend items that draw text (e.g. the name of a graph) will use this font by default. However, a different font can be specified on a per-item-basis by accessing the specific legend item. This function will also set \a font on all already existing legend items. \see QCPAbstractLegendItem::setFont */ void QCPLegend::setFont(const QFont &font) { mFont = font; for (int i=0; isetFont(mFont); } } /*! Sets the default color of legend text. Legend items that draw text (e.g. the name of a graph) will use this color by default. However, a different colors can be specified on a per-item-basis by accessing the specific legend item. This function will also set \a color on all already existing legend items. \see QCPAbstractLegendItem::setTextColor */ void QCPLegend::setTextColor(const QColor &color) { mTextColor = color; for (int i=0; isetTextColor(color); } } /*! Sets the size of legend icons. Legend items that draw an icon (e.g. a visual representation of the graph) will use this size by default. */ void QCPLegend::setIconSize(const QSize &size) { mIconSize = size; } /*! \overload */ void QCPLegend::setIconSize(int width, int height) { mIconSize.setWidth(width); mIconSize.setHeight(height); } /*! Sets the horizontal space in pixels between the legend icon and the text next to it. Legend items that draw an icon (e.g. a visual representation of the graph) and text (e.g. the name of the graph) will use this space by default. */ void QCPLegend::setIconTextPadding(int padding) { mIconTextPadding = padding; } /*! Sets the pen used to draw a border around each legend icon. Legend items that draw an icon (e.g. a visual representation of the graph) will use this pen by default. If no border is wanted, set this to \a Qt::NoPen. */ void QCPLegend::setIconBorderPen(const QPen &pen) { mIconBorderPen = pen; } /*! Sets whether the user can (de-)select the parts in \a selectable by clicking on the QCustomPlot surface. (When \ref QCustomPlot::setInteractions contains \ref QCP::iSelectLegend.) However, even when \a selectable is set to a value not allowing the selection of a specific part, it is still possible to set the selection of this part manually, by calling \ref setSelectedParts directly. \see SelectablePart, setSelectedParts */ void QCPLegend::setSelectableParts(const SelectableParts &selectable) { if (mSelectableParts != selectable) { mSelectableParts = selectable; emit selectableChanged(mSelectableParts); } } /*! Sets the selected state of the respective legend parts described by \ref SelectablePart. When a part is selected, it uses a different pen/font and brush. If some legend items are selected and \a selected doesn't contain \ref spItems, those items become deselected. The entire selection mechanism is handled automatically when \ref QCustomPlot::setInteractions contains iSelectLegend. You only need to call this function when you wish to change the selection state manually. This function can change the selection state of a part even when \ref setSelectableParts was set to a value that actually excludes the part. emits the \ref selectionChanged signal when \a selected is different from the previous selection state. Note that it doesn't make sense to set the selected state \ref spItems here when it wasn't set before, because there's no way to specify which exact items to newly select. Do this by calling \ref QCPAbstractLegendItem::setSelected directly on the legend item you wish to select. \see SelectablePart, setSelectableParts, selectTest, setSelectedBorderPen, setSelectedIconBorderPen, setSelectedBrush, setSelectedFont */ void QCPLegend::setSelectedParts(const SelectableParts &selected) { SelectableParts newSelected = selected; mSelectedParts = this->selectedParts(); // update mSelectedParts in case item selection changed if (mSelectedParts != newSelected) { if (!mSelectedParts.testFlag(spItems) && newSelected.testFlag(spItems)) // attempt to set spItems flag (can't do that) { qDebug() << Q_FUNC_INFO << "spItems flag can not be set, it can only be unset with this function"; newSelected &= ~spItems; } if (mSelectedParts.testFlag(spItems) && !newSelected.testFlag(spItems)) // spItems flag was unset, so clear item selection { for (int i=0; isetSelected(false); } } mSelectedParts = newSelected; emit selectionChanged(mSelectedParts); } } /*! When the legend box is selected, this pen is used to draw the border instead of the normal pen set via \ref setBorderPen. \see setSelectedParts, setSelectableParts, setSelectedBrush */ void QCPLegend::setSelectedBorderPen(const QPen &pen) { mSelectedBorderPen = pen; } /*! Sets the pen legend items will use to draw their icon borders, when they are selected. \see setSelectedParts, setSelectableParts, setSelectedFont */ void QCPLegend::setSelectedIconBorderPen(const QPen &pen) { mSelectedIconBorderPen = pen; } /*! When the legend box is selected, this brush is used to draw the legend background instead of the normal brush set via \ref setBrush. \see setSelectedParts, setSelectableParts, setSelectedBorderPen */ void QCPLegend::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /*! Sets the default font that is used by legend items when they are selected. This function will also set \a font on all already existing legend items. \see setFont, QCPAbstractLegendItem::setSelectedFont */ void QCPLegend::setSelectedFont(const QFont &font) { mSelectedFont = font; for (int i=0; isetSelectedFont(font); } } /*! Sets the default text color that is used by legend items when they are selected. This function will also set \a color on all already existing legend items. \see setTextColor, QCPAbstractLegendItem::setSelectedTextColor */ void QCPLegend::setSelectedTextColor(const QColor &color) { mSelectedTextColor = color; for (int i=0; isetSelectedTextColor(color); } } /*! Returns the item with index \a i. If non-legend items were added to the legend, and the element at the specified cell index is not a QCPAbstractLegendItem, returns \c nullptr. Note that the linear index depends on the current fill order (\ref setFillOrder). \see itemCount, addItem, itemWithPlottable */ QCPAbstractLegendItem *QCPLegend::item(int index) const { return qobject_cast(elementAt(index)); } /*! Returns the QCPPlottableLegendItem which is associated with \a plottable (e.g. a \ref QCPGraph*). If such an item isn't in the legend, returns \c nullptr. \see hasItemWithPlottable */ QCPPlottableLegendItem *QCPLegend::itemWithPlottable(const QCPAbstractPlottable *plottable) const { for (int i=0; i(item(i))) { if (pli->plottable() == plottable) return pli; } } return nullptr; } /*! Returns the number of items currently in the legend. It is identical to the base class QCPLayoutGrid::elementCount(), and unlike the other "item" interface methods of QCPLegend, doesn't only address elements which can be cast to QCPAbstractLegendItem. Note that if empty cells are in the legend (e.g. by calling methods of the \ref QCPLayoutGrid base class which allows creating empty cells), they are included in the returned count. \see item */ int QCPLegend::itemCount() const { return elementCount(); } /*! Returns whether the legend contains \a item. \see hasItemWithPlottable */ bool QCPLegend::hasItem(QCPAbstractLegendItem *item) const { for (int i=0; iitem(i)) return true; } return false; } /*! Returns whether the legend contains a QCPPlottableLegendItem which is associated with \a plottable (e.g. a \ref QCPGraph*). If such an item isn't in the legend, returns false. \see itemWithPlottable */ bool QCPLegend::hasItemWithPlottable(const QCPAbstractPlottable *plottable) const { return itemWithPlottable(plottable); } /*! Adds \a item to the legend, if it's not present already. The element is arranged according to the current fill order (\ref setFillOrder) and wrapping (\ref setWrap). Returns true on sucess, i.e. if the item wasn't in the list already and has been successfuly added. The legend takes ownership of the item. \see removeItem, item, hasItem */ bool QCPLegend::addItem(QCPAbstractLegendItem *item) { return addElement(item); } /*! \overload Removes the item with the specified \a index from the legend and deletes it. After successful removal, the legend is reordered according to the current fill order (\ref setFillOrder) and wrapping (\ref setWrap), so no empty cell remains where the removed \a item was. If you don't want this, rather use the raw element interface of \ref QCPLayoutGrid. Returns true, if successful. Unlike \ref QCPLayoutGrid::removeAt, this method only removes elements derived from \ref QCPAbstractLegendItem. \see itemCount, clearItems */ bool QCPLegend::removeItem(int index) { if (QCPAbstractLegendItem *ali = item(index)) { bool success = remove(ali); if (success) setFillOrder(fillOrder(), true); // gets rid of empty cell by reordering return success; } else return false; } /*! \overload Removes \a item from the legend and deletes it. After successful removal, the legend is reordered according to the current fill order (\ref setFillOrder) and wrapping (\ref setWrap), so no empty cell remains where the removed \a item was. If you don't want this, rather use the raw element interface of \ref QCPLayoutGrid. Returns true, if successful. \see clearItems */ bool QCPLegend::removeItem(QCPAbstractLegendItem *item) { bool success = remove(item); if (success) setFillOrder(fillOrder(), true); // gets rid of empty cell by reordering return success; } /*! Removes all items from the legend. */ void QCPLegend::clearItems() { for (int i=elementCount()-1; i>=0; --i) { if (item(i)) removeAt(i); // don't use removeItem() because it would unnecessarily reorder the whole legend for each item } setFillOrder(fillOrder(), true); // get rid of empty cells by reordering once after all items are removed } /*! Returns the legend items that are currently selected. If no items are selected, the list is empty. \see QCPAbstractLegendItem::setSelected, setSelectable */ QList QCPLegend::selectedItems() const { QList result; for (int i=0; iselected()) result.append(ali); } } return result; } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing main legend elements. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set with \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. \seebaseclassmethod \see setAntialiased */ void QCPLegend::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeLegend); } /*! \internal Returns the pen used to paint the border of the legend, taking into account the selection state of the legend box. */ QPen QCPLegend::getBorderPen() const { return mSelectedParts.testFlag(spLegendBox) ? mSelectedBorderPen : mBorderPen; } /*! \internal Returns the brush used to paint the background of the legend, taking into account the selection state of the legend box. */ QBrush QCPLegend::getBrush() const { return mSelectedParts.testFlag(spLegendBox) ? mSelectedBrush : mBrush; } /*! \internal Draws the legend box with the provided \a painter. The individual legend items are layerables themselves, thus are drawn independently. */ void QCPLegend::draw(QCPPainter *painter) { // draw background rect: painter->setBrush(getBrush()); painter->setPen(getBorderPen()); painter->drawRect(mOuterRect); } /* inherits documentation from base class */ double QCPLegend::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { if (!mParentPlot) return -1; if (onlySelectable && !mSelectableParts.testFlag(spLegendBox)) return -1; if (mOuterRect.contains(pos.toPoint())) { if (details) details->setValue(spLegendBox); return mParentPlot->selectionTolerance()*0.99; } return -1; } /* inherits documentation from base class */ void QCPLegend::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) { Q_UNUSED(event) mSelectedParts = selectedParts(); // in case item selection has changed if (details.value() == spLegendBox && mSelectableParts.testFlag(spLegendBox)) { SelectableParts selBefore = mSelectedParts; setSelectedParts(additive ? mSelectedParts^spLegendBox : mSelectedParts|spLegendBox); // no need to unset spItems in !additive case, because they will be deselected by QCustomPlot (they're normal QCPLayerables with own deselectEvent) if (selectionStateChanged) *selectionStateChanged = mSelectedParts != selBefore; } } /* inherits documentation from base class */ void QCPLegend::deselectEvent(bool *selectionStateChanged) { mSelectedParts = selectedParts(); // in case item selection has changed if (mSelectableParts.testFlag(spLegendBox)) { SelectableParts selBefore = mSelectedParts; setSelectedParts(selectedParts() & ~spLegendBox); if (selectionStateChanged) *selectionStateChanged = mSelectedParts != selBefore; } } /* inherits documentation from base class */ QCP::Interaction QCPLegend::selectionCategory() const { return QCP::iSelectLegend; } /* inherits documentation from base class */ QCP::Interaction QCPAbstractLegendItem::selectionCategory() const { return QCP::iSelectLegend; } /* inherits documentation from base class */ void QCPLegend::parentPlotInitialized(QCustomPlot *parentPlot) { if (parentPlot && !parentPlot->legend) parentPlot->legend = this; } /* end of 'src/layoutelements/layoutelement-legend.cpp' */ /* including file 'src/layoutelements/layoutelement-textelement.cpp' */ /* modified 2021-03-29T02:30:44, size 12925 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPTextElement //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPTextElement \brief A layout element displaying a text The text may be specified with \ref setText, the formatting can be controlled with \ref setFont, \ref setTextColor, and \ref setTextFlags. A text element can be added as follows: \snippet documentation/doc-code-snippets/mainwindow.cpp qcptextelement-creation */ /* start documentation of signals */ /*! \fn void QCPTextElement::selectionChanged(bool selected) This signal is emitted when the selection state has changed to \a selected, either by user interaction or by a direct call to \ref setSelected. \see setSelected, setSelectable */ /*! \fn void QCPTextElement::clicked(QMouseEvent *event) This signal is emitted when the text element is clicked. \see doubleClicked, selectTest */ /*! \fn void QCPTextElement::doubleClicked(QMouseEvent *event) This signal is emitted when the text element is double clicked. \see clicked, selectTest */ /* end documentation of signals */ /*! \overload Creates a new QCPTextElement instance and sets default values. The initial text is empty (\ref setText). */ QCPTextElement::QCPTextElement(QCustomPlot *parentPlot) : QCPLayoutElement(parentPlot), mText(), mTextFlags(Qt::AlignCenter), mFont(QFont(QLatin1String("sans serif"), 12)), // will be taken from parentPlot if available, see below mTextColor(Qt::black), mSelectedFont(QFont(QLatin1String("sans serif"), 12)), // will be taken from parentPlot if available, see below mSelectedTextColor(Qt::blue), mSelectable(false), mSelected(false) { if (parentPlot) { mFont = parentPlot->font(); mSelectedFont = parentPlot->font(); } setMargins(QMargins(2, 2, 2, 2)); } /*! \overload Creates a new QCPTextElement instance and sets default values. The initial text is set to \a text. */ QCPTextElement::QCPTextElement(QCustomPlot *parentPlot, const QString &text) : QCPLayoutElement(parentPlot), mText(text), mTextFlags(Qt::AlignCenter), mFont(QFont(QLatin1String("sans serif"), 12)), // will be taken from parentPlot if available, see below mTextColor(Qt::black), mSelectedFont(QFont(QLatin1String("sans serif"), 12)), // will be taken from parentPlot if available, see below mSelectedTextColor(Qt::blue), mSelectable(false), mSelected(false) { if (parentPlot) { mFont = parentPlot->font(); mSelectedFont = parentPlot->font(); } setMargins(QMargins(2, 2, 2, 2)); } /*! \overload Creates a new QCPTextElement instance and sets default values. The initial text is set to \a text with \a pointSize. */ QCPTextElement::QCPTextElement(QCustomPlot *parentPlot, const QString &text, double pointSize) : QCPLayoutElement(parentPlot), mText(text), mTextFlags(Qt::AlignCenter), mFont(QFont(QLatin1String("sans serif"), int(pointSize))), // will be taken from parentPlot if available, see below mTextColor(Qt::black), mSelectedFont(QFont(QLatin1String("sans serif"), int(pointSize))), // will be taken from parentPlot if available, see below mSelectedTextColor(Qt::blue), mSelectable(false), mSelected(false) { mFont.setPointSizeF(pointSize); // set here again as floating point, because constructor above only takes integer if (parentPlot) { mFont = parentPlot->font(); mFont.setPointSizeF(pointSize); mSelectedFont = parentPlot->font(); mSelectedFont.setPointSizeF(pointSize); } setMargins(QMargins(2, 2, 2, 2)); } /*! \overload Creates a new QCPTextElement instance and sets default values. The initial text is set to \a text with \a pointSize and the specified \a fontFamily. */ QCPTextElement::QCPTextElement(QCustomPlot *parentPlot, const QString &text, const QString &fontFamily, double pointSize) : QCPLayoutElement(parentPlot), mText(text), mTextFlags(Qt::AlignCenter), mFont(QFont(fontFamily, int(pointSize))), mTextColor(Qt::black), mSelectedFont(QFont(fontFamily, int(pointSize))), mSelectedTextColor(Qt::blue), mSelectable(false), mSelected(false) { mFont.setPointSizeF(pointSize); // set here again as floating point, because constructor above only takes integer setMargins(QMargins(2, 2, 2, 2)); } /*! \overload Creates a new QCPTextElement instance and sets default values. The initial text is set to \a text with the specified \a font. */ QCPTextElement::QCPTextElement(QCustomPlot *parentPlot, const QString &text, const QFont &font) : QCPLayoutElement(parentPlot), mText(text), mTextFlags(Qt::AlignCenter), mFont(font), mTextColor(Qt::black), mSelectedFont(font), mSelectedTextColor(Qt::blue), mSelectable(false), mSelected(false) { setMargins(QMargins(2, 2, 2, 2)); } /*! Sets the text that will be displayed to \a text. Multiple lines can be created by insertion of "\n". \see setFont, setTextColor, setTextFlags */ void QCPTextElement::setText(const QString &text) { mText = text; } /*! Sets options for text alignment and wrapping behaviour. \a flags is a bitwise OR-combination of \c Qt::AlignmentFlag and \c Qt::TextFlag enums. Possible enums are: - Qt::AlignLeft - Qt::AlignRight - Qt::AlignHCenter - Qt::AlignJustify - Qt::AlignTop - Qt::AlignBottom - Qt::AlignVCenter - Qt::AlignCenter - Qt::TextDontClip - Qt::TextSingleLine - Qt::TextExpandTabs - Qt::TextShowMnemonic - Qt::TextWordWrap - Qt::TextIncludeTrailingSpaces */ void QCPTextElement::setTextFlags(int flags) { mTextFlags = flags; } /*! Sets the \a font of the text. \see setTextColor, setSelectedFont */ void QCPTextElement::setFont(const QFont &font) { mFont = font; } /*! Sets the \a color of the text. \see setFont, setSelectedTextColor */ void QCPTextElement::setTextColor(const QColor &color) { mTextColor = color; } /*! Sets the \a font of the text that will be used if the text element is selected (\ref setSelected). \see setFont */ void QCPTextElement::setSelectedFont(const QFont &font) { mSelectedFont = font; } /*! Sets the \a color of the text that will be used if the text element is selected (\ref setSelected). \see setTextColor */ void QCPTextElement::setSelectedTextColor(const QColor &color) { mSelectedTextColor = color; } /*! Sets whether the user may select this text element. Note that even when \a selectable is set to false, the selection state may be changed programmatically via \ref setSelected. */ void QCPTextElement::setSelectable(bool selectable) { if (mSelectable != selectable) { mSelectable = selectable; emit selectableChanged(mSelectable); } } /*! Sets the selection state of this text element to \a selected. If the selection has changed, \ref selectionChanged is emitted. Note that this function can change the selection state independently of the current \ref setSelectable state. */ void QCPTextElement::setSelected(bool selected) { if (mSelected != selected) { mSelected = selected; emit selectionChanged(mSelected); } } /* inherits documentation from base class */ void QCPTextElement::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeOther); } /* inherits documentation from base class */ void QCPTextElement::draw(QCPPainter *painter) { painter->setFont(mainFont()); painter->setPen(QPen(mainTextColor())); painter->drawText(mRect, mTextFlags, mText, &mTextBoundingRect); } /* inherits documentation from base class */ QSize QCPTextElement::minimumOuterSizeHint() const { QFontMetrics metrics(mFont); QSize result(metrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, mText).size()); result.rwidth() += mMargins.left()+mMargins.right(); result.rheight() += mMargins.top()+mMargins.bottom(); return result; } /* inherits documentation from base class */ QSize QCPTextElement::maximumOuterSizeHint() const { QFontMetrics metrics(mFont); QSize result(metrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, mText).size()); result.setWidth(QWIDGETSIZE_MAX); result.rheight() += mMargins.top()+mMargins.bottom(); return result; } /* inherits documentation from base class */ void QCPTextElement::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) { Q_UNUSED(event) Q_UNUSED(details) if (mSelectable) { bool selBefore = mSelected; setSelected(additive ? !mSelected : true); if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore; } } /* inherits documentation from base class */ void QCPTextElement::deselectEvent(bool *selectionStateChanged) { if (mSelectable) { bool selBefore = mSelected; setSelected(false); if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore; } } /*! Returns 0.99*selectionTolerance (see \ref QCustomPlot::setSelectionTolerance) when \a pos is within the bounding box of the text element's text. Note that this bounding box is updated in the draw call. If \a pos is outside the text's bounding box or if \a onlySelectable is true and this text element is not selectable (\ref setSelectable), returns -1. \seebaseclassmethod */ double QCPTextElement::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; if (mTextBoundingRect.contains(pos.toPoint())) return mParentPlot->selectionTolerance()*0.99; else return -1; } /*! Accepts the mouse event in order to emit the according click signal in the \ref mouseReleaseEvent. \seebaseclassmethod */ void QCPTextElement::mousePressEvent(QMouseEvent *event, const QVariant &details) { Q_UNUSED(details) event->accept(); } /*! Emits the \ref clicked signal if the cursor hasn't moved by more than a few pixels since the \ref mousePressEvent. \seebaseclassmethod */ void QCPTextElement::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) { if ((QPointF(event->pos())-startPos).manhattanLength() <= 3) emit clicked(event); } /*! Emits the \ref doubleClicked signal. \seebaseclassmethod */ void QCPTextElement::mouseDoubleClickEvent(QMouseEvent *event, const QVariant &details) { Q_UNUSED(details) emit doubleClicked(event); } /*! \internal Returns the main font to be used. This is mSelectedFont if \ref setSelected is set to true, else mFont is returned. */ QFont QCPTextElement::mainFont() const { return mSelected ? mSelectedFont : mFont; } /*! \internal Returns the main color to be used. This is mSelectedTextColor if \ref setSelected is set to true, else mTextColor is returned. */ QColor QCPTextElement::mainTextColor() const { return mSelected ? mSelectedTextColor : mTextColor; } /* end of 'src/layoutelements/layoutelement-textelement.cpp' */ /* including file 'src/layoutelements/layoutelement-colorscale.cpp' */ /* modified 2021-03-29T02:30:44, size 26531 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPColorScale //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPColorScale \brief A color scale for use with color coding data such as QCPColorMap This layout element can be placed on the plot to correlate a color gradient with data values. It is usually used in combination with one or multiple \ref QCPColorMap "QCPColorMaps". \image html QCPColorScale.png The color scale can be either horizontal or vertical, as shown in the image above. The orientation and the side where the numbers appear is controlled with \ref setType. Use \ref QCPColorMap::setColorScale to connect a color map with a color scale. Once they are connected, they share their gradient, data range and data scale type (\ref setGradient, \ref setDataRange, \ref setDataScaleType). Multiple color maps may be associated with a single color scale, to make them all synchronize these properties. To have finer control over the number display and axis behaviour, you can directly access the \ref axis. See the documentation of QCPAxis for details about configuring axes. For example, if you want to change the number of automatically generated ticks, call \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolorscale-tickcount Placing a color scale next to the main axis rect works like with any other layout element: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolorscale-creation In this case we have placed it to the right of the default axis rect, so it wasn't necessary to call \ref setType, since \ref QCPAxis::atRight is already the default. The text next to the color scale can be set with \ref setLabel. For optimum appearance (like in the image above), it may be desirable to line up the axis rect and the borders of the color scale. Use a \ref QCPMarginGroup to achieve this: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcolorscale-margingroup Color scales are initialized with a non-zero minimum top and bottom margin (\ref setMinimumMargins), because vertical color scales are most common and the minimum top/bottom margin makes sure it keeps some distance to the top/bottom widget border. So if you change to a horizontal color scale by setting \ref setType to \ref QCPAxis::atBottom or \ref QCPAxis::atTop, you might want to also change the minimum margins accordingly, e.g. setMinimumMargins(QMargins(6, 0, 6, 0)). */ /* start documentation of inline functions */ /*! \fn QCPAxis *QCPColorScale::axis() const Returns the internal \ref QCPAxis instance of this color scale. You can access it to alter the appearance and behaviour of the axis. \ref QCPColorScale duplicates some properties in its interface for convenience. Those are \ref setDataRange (\ref QCPAxis::setRange), \ref setDataScaleType (\ref QCPAxis::setScaleType), and the method \ref setLabel (\ref QCPAxis::setLabel). As they each are connected, it does not matter whether you use the method on the QCPColorScale or on its QCPAxis. If the type of the color scale is changed with \ref setType, the axis returned by this method will change, too, to either the left, right, bottom or top axis, depending on which type was set. */ /* end documentation of signals */ /* start documentation of signals */ /*! \fn void QCPColorScale::dataRangeChanged(const QCPRange &newRange); This signal is emitted when the data range changes. \see setDataRange */ /*! \fn void QCPColorScale::dataScaleTypeChanged(QCPAxis::ScaleType scaleType); This signal is emitted when the data scale type changes. \see setDataScaleType */ /*! \fn void QCPColorScale::gradientChanged(const QCPColorGradient &newGradient); This signal is emitted when the gradient changes. \see setGradient */ /* end documentation of signals */ /*! Constructs a new QCPColorScale. */ QCPColorScale::QCPColorScale(QCustomPlot *parentPlot) : QCPLayoutElement(parentPlot), mType(QCPAxis::atTop), // set to atTop such that setType(QCPAxis::atRight) below doesn't skip work because it thinks it's already atRight mDataScaleType(QCPAxis::stLinear), mGradient(QCPColorGradient::gpCold), mBarWidth(20), mAxisRect(new QCPColorScaleAxisRectPrivate(this)) { setMinimumMargins(QMargins(0, 6, 0, 6)); // for default right color scale types, keep some room at bottom and top (important if no margin group is used) setType(QCPAxis::atRight); setDataRange(QCPRange(0, 6)); } QCPColorScale::~QCPColorScale() { delete mAxisRect; } /* undocumented getter */ QString QCPColorScale::label() const { if (!mColorAxis) { qDebug() << Q_FUNC_INFO << "internal color axis undefined"; return QString(); } return mColorAxis.data()->label(); } /* undocumented getter */ bool QCPColorScale::rangeDrag() const { if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return false; } return mAxisRect.data()->rangeDrag().testFlag(QCPAxis::orientation(mType)) && mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType)) && mAxisRect.data()->rangeDragAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType); } /* undocumented getter */ bool QCPColorScale::rangeZoom() const { if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return false; } return mAxisRect.data()->rangeZoom().testFlag(QCPAxis::orientation(mType)) && mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType)) && mAxisRect.data()->rangeZoomAxis(QCPAxis::orientation(mType))->orientation() == QCPAxis::orientation(mType); } /*! Sets at which side of the color scale the axis is placed, and thus also its orientation. Note that after setting \a type to a different value, the axis returned by \ref axis() will be a different one. The new axis will adopt the following properties from the previous axis: The range, scale type, label and ticker (the latter will be shared and not copied). */ void QCPColorScale::setType(QCPAxis::AxisType type) { if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return; } if (mType != type) { mType = type; QCPRange rangeTransfer(0, 6); QString labelTransfer; QSharedPointer tickerTransfer; // transfer/revert some settings on old axis if it exists: bool doTransfer = !mColorAxis.isNull(); if (doTransfer) { rangeTransfer = mColorAxis.data()->range(); labelTransfer = mColorAxis.data()->label(); tickerTransfer = mColorAxis.data()->ticker(); mColorAxis.data()->setLabel(QString()); disconnect(mColorAxis.data(), SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange))); disconnect(mColorAxis.data(), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType))); } const QList allAxisTypes = QList() << QCPAxis::atLeft << QCPAxis::atRight << QCPAxis::atBottom << QCPAxis::atTop; foreach (QCPAxis::AxisType atype, allAxisTypes) { mAxisRect.data()->axis(atype)->setTicks(atype == mType); mAxisRect.data()->axis(atype)->setTickLabels(atype== mType); } // set new mColorAxis pointer: mColorAxis = mAxisRect.data()->axis(mType); // transfer settings to new axis: if (doTransfer) { mColorAxis.data()->setRange(rangeTransfer); // range transfer necessary if axis changes from vertical to horizontal or vice versa (axes with same orientation are synchronized via signals) mColorAxis.data()->setLabel(labelTransfer); mColorAxis.data()->setTicker(tickerTransfer); } connect(mColorAxis.data(), SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange))); connect(mColorAxis.data(), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType))); mAxisRect.data()->setRangeDragAxes(QList() << mColorAxis.data()); } } /*! Sets the range spanned by the color gradient and that is shown by the axis in the color scale. It is equivalent to calling QCPColorMap::setDataRange on any of the connected color maps. It is also equivalent to directly accessing the \ref axis and setting its range with \ref QCPAxis::setRange. \see setDataScaleType, setGradient, rescaleDataRange */ void QCPColorScale::setDataRange(const QCPRange &dataRange) { if (mDataRange.lower != dataRange.lower || mDataRange.upper != dataRange.upper) { mDataRange = dataRange; if (mColorAxis) mColorAxis.data()->setRange(mDataRange); emit dataRangeChanged(mDataRange); } } /*! Sets the scale type of the color scale, i.e. whether values are associated with colors linearly or logarithmically. It is equivalent to calling QCPColorMap::setDataScaleType on any of the connected color maps. It is also equivalent to directly accessing the \ref axis and setting its scale type with \ref QCPAxis::setScaleType. Note that this method controls the coordinate transformation. For logarithmic scales, you will likely also want to use a logarithmic tick spacing and labeling, which can be achieved by setting the color scale's \ref axis ticker to an instance of \ref QCPAxisTickerLog : \snippet documentation/doc-code-snippets/mainwindow.cpp qcpaxisticker-log-colorscale See the documentation of \ref QCPAxisTickerLog about the details of logarithmic axis tick creation. \see setDataRange, setGradient */ void QCPColorScale::setDataScaleType(QCPAxis::ScaleType scaleType) { if (mDataScaleType != scaleType) { mDataScaleType = scaleType; if (mColorAxis) mColorAxis.data()->setScaleType(mDataScaleType); if (mDataScaleType == QCPAxis::stLogarithmic) setDataRange(mDataRange.sanitizedForLogScale()); emit dataScaleTypeChanged(mDataScaleType); } } /*! Sets the color gradient that will be used to represent data values. It is equivalent to calling QCPColorMap::setGradient on any of the connected color maps. \see setDataRange, setDataScaleType */ void QCPColorScale::setGradient(const QCPColorGradient &gradient) { if (mGradient != gradient) { mGradient = gradient; if (mAxisRect) mAxisRect.data()->mGradientImageInvalidated = true; emit gradientChanged(mGradient); } } /*! Sets the axis label of the color scale. This is equivalent to calling \ref QCPAxis::setLabel on the internal \ref axis. */ void QCPColorScale::setLabel(const QString &str) { if (!mColorAxis) { qDebug() << Q_FUNC_INFO << "internal color axis undefined"; return; } mColorAxis.data()->setLabel(str); } /*! Sets the width (or height, for horizontal color scales) the bar where the gradient is displayed will have. */ void QCPColorScale::setBarWidth(int width) { mBarWidth = width; } /*! Sets whether the user can drag the data range (\ref setDataRange). Note that \ref QCP::iRangeDrag must be in the QCustomPlot's interactions (\ref QCustomPlot::setInteractions) to allow range dragging. */ void QCPColorScale::setRangeDrag(bool enabled) { if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return; } if (enabled) { mAxisRect.data()->setRangeDrag(QCPAxis::orientation(mType)); } else { #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) mAxisRect.data()->setRangeDrag(nullptr); #else mAxisRect.data()->setRangeDrag({}); #endif } } /*! Sets whether the user can zoom the data range (\ref setDataRange) by scrolling the mouse wheel. Note that \ref QCP::iRangeZoom must be in the QCustomPlot's interactions (\ref QCustomPlot::setInteractions) to allow range dragging. */ void QCPColorScale::setRangeZoom(bool enabled) { if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return; } if (enabled) { mAxisRect.data()->setRangeZoom(QCPAxis::orientation(mType)); } else { #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) mAxisRect.data()->setRangeDrag(nullptr); #else mAxisRect.data()->setRangeZoom({}); #endif } } /*! Returns a list of all the color maps associated with this color scale. */ QList QCPColorScale::colorMaps() const { QList result; for (int i=0; iplottableCount(); ++i) { if (QCPColorMap *cm = qobject_cast(mParentPlot->plottable(i))) if (cm->colorScale() == this) result.append(cm); } return result; } /*! Changes the data range such that all color maps associated with this color scale are fully mapped to the gradient in the data dimension. \see setDataRange */ void QCPColorScale::rescaleDataRange(bool onlyVisibleMaps) { QList maps = colorMaps(); QCPRange newRange; bool haveRange = false; QCP::SignDomain sign = QCP::sdBoth; if (mDataScaleType == QCPAxis::stLogarithmic) sign = (mDataRange.upper < 0 ? QCP::sdNegative : QCP::sdPositive); foreach (QCPColorMap *map, maps) { if (!map->realVisibility() && onlyVisibleMaps) continue; QCPRange mapRange; if (map->colorScale() == this) { bool currentFoundRange = true; mapRange = map->data()->dataBounds(); if (sign == QCP::sdPositive) { if (mapRange.lower <= 0 && mapRange.upper > 0) mapRange.lower = mapRange.upper*1e-3; else if (mapRange.lower <= 0 && mapRange.upper <= 0) currentFoundRange = false; } else if (sign == QCP::sdNegative) { if (mapRange.upper >= 0 && mapRange.lower < 0) mapRange.upper = mapRange.lower*1e-3; else if (mapRange.upper >= 0 && mapRange.lower >= 0) currentFoundRange = false; } if (currentFoundRange) { if (!haveRange) newRange = mapRange; else newRange.expand(mapRange); haveRange = true; } } } if (haveRange) { if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this dimension), shift current range to at least center the data { double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason if (mDataScaleType == QCPAxis::stLinear) { newRange.lower = center-mDataRange.size()/2.0; newRange.upper = center+mDataRange.size()/2.0; } else // mScaleType == stLogarithmic { newRange.lower = center/qSqrt(mDataRange.upper/mDataRange.lower); newRange.upper = center*qSqrt(mDataRange.upper/mDataRange.lower); } } setDataRange(newRange); } } /* inherits documentation from base class */ void QCPColorScale::update(UpdatePhase phase) { QCPLayoutElement::update(phase); if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return; } mAxisRect.data()->update(phase); switch (phase) { case upMargins: { if (mType == QCPAxis::atBottom || mType == QCPAxis::atTop) { setMaximumSize(QWIDGETSIZE_MAX, mBarWidth+mAxisRect.data()->margins().top()+mAxisRect.data()->margins().bottom()); setMinimumSize(0, mBarWidth+mAxisRect.data()->margins().top()+mAxisRect.data()->margins().bottom()); } else { setMaximumSize(mBarWidth+mAxisRect.data()->margins().left()+mAxisRect.data()->margins().right(), QWIDGETSIZE_MAX); setMinimumSize(mBarWidth+mAxisRect.data()->margins().left()+mAxisRect.data()->margins().right(), 0); } break; } case upLayout: { mAxisRect.data()->setOuterRect(rect()); break; } default: break; } } /* inherits documentation from base class */ void QCPColorScale::applyDefaultAntialiasingHint(QCPPainter *painter) const { painter->setAntialiasing(false); } /* inherits documentation from base class */ void QCPColorScale::mousePressEvent(QMouseEvent *event, const QVariant &details) { if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return; } mAxisRect.data()->mousePressEvent(event, details); } /* inherits documentation from base class */ void QCPColorScale::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) { if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return; } mAxisRect.data()->mouseMoveEvent(event, startPos); } /* inherits documentation from base class */ void QCPColorScale::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) { if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return; } mAxisRect.data()->mouseReleaseEvent(event, startPos); } /* inherits documentation from base class */ void QCPColorScale::wheelEvent(QWheelEvent *event) { if (!mAxisRect) { qDebug() << Q_FUNC_INFO << "internal axis rect was deleted"; return; } mAxisRect.data()->wheelEvent(event); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPColorScaleAxisRectPrivate //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPColorScaleAxisRectPrivate \internal \brief An axis rect subclass for use in a QCPColorScale This is a private class and not part of the public QCustomPlot interface. It provides the axis rect functionality for the QCPColorScale class. */ /*! Creates a new instance, as a child of \a parentColorScale. */ QCPColorScaleAxisRectPrivate::QCPColorScaleAxisRectPrivate(QCPColorScale *parentColorScale) : QCPAxisRect(parentColorScale->parentPlot(), true), mParentColorScale(parentColorScale), mGradientImageInvalidated(true) { setParentLayerable(parentColorScale); setMinimumMargins(QMargins(0, 0, 0, 0)); const QList allAxisTypes = QList() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight; foreach (QCPAxis::AxisType type, allAxisTypes) { axis(type)->setVisible(true); axis(type)->grid()->setVisible(false); axis(type)->setPadding(0); connect(axis(type), SIGNAL(selectionChanged(QCPAxis::SelectableParts)), this, SLOT(axisSelectionChanged(QCPAxis::SelectableParts))); connect(axis(type), SIGNAL(selectableChanged(QCPAxis::SelectableParts)), this, SLOT(axisSelectableChanged(QCPAxis::SelectableParts))); } connect(axis(QCPAxis::atLeft), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atRight), SLOT(setRange(QCPRange))); connect(axis(QCPAxis::atRight), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atLeft), SLOT(setRange(QCPRange))); connect(axis(QCPAxis::atBottom), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atTop), SLOT(setRange(QCPRange))); connect(axis(QCPAxis::atTop), SIGNAL(rangeChanged(QCPRange)), axis(QCPAxis::atBottom), SLOT(setRange(QCPRange))); connect(axis(QCPAxis::atLeft), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atRight), SLOT(setScaleType(QCPAxis::ScaleType))); connect(axis(QCPAxis::atRight), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atLeft), SLOT(setScaleType(QCPAxis::ScaleType))); connect(axis(QCPAxis::atBottom), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atTop), SLOT(setScaleType(QCPAxis::ScaleType))); connect(axis(QCPAxis::atTop), SIGNAL(scaleTypeChanged(QCPAxis::ScaleType)), axis(QCPAxis::atBottom), SLOT(setScaleType(QCPAxis::ScaleType))); // make layer transfers of color scale transfer to axis rect and axes // the axes must be set after axis rect, such that they appear above color gradient drawn by axis rect: connect(parentColorScale, SIGNAL(layerChanged(QCPLayer*)), this, SLOT(setLayer(QCPLayer*))); foreach (QCPAxis::AxisType type, allAxisTypes) connect(parentColorScale, SIGNAL(layerChanged(QCPLayer*)), axis(type), SLOT(setLayer(QCPLayer*))); } /*! \internal Updates the color gradient image if necessary, by calling \ref updateGradientImage, then draws it. Then the axes are drawn by calling the \ref QCPAxisRect::draw base class implementation. \seebaseclassmethod */ void QCPColorScaleAxisRectPrivate::draw(QCPPainter *painter) { if (mGradientImageInvalidated) updateGradientImage(); bool mirrorHorz = false; bool mirrorVert = false; if (mParentColorScale->mColorAxis) { mirrorHorz = mParentColorScale->mColorAxis.data()->rangeReversed() && (mParentColorScale->type() == QCPAxis::atBottom || mParentColorScale->type() == QCPAxis::atTop); mirrorVert = mParentColorScale->mColorAxis.data()->rangeReversed() && (mParentColorScale->type() == QCPAxis::atLeft || mParentColorScale->type() == QCPAxis::atRight); } painter->drawImage(rect().adjusted(0, -1, 0, -1), mGradientImage.mirrored(mirrorHorz, mirrorVert)); QCPAxisRect::draw(painter); } /*! \internal Uses the current gradient of the parent \ref QCPColorScale (specified in the constructor) to generate a gradient image. This gradient image will be used in the \ref draw method. */ void QCPColorScaleAxisRectPrivate::updateGradientImage() { if (rect().isEmpty()) return; const QImage::Format format = QImage::Format_ARGB32_Premultiplied; int n = mParentColorScale->mGradient.levelCount(); int w, h; QVector data(n); for (int i=0; imType == QCPAxis::atBottom || mParentColorScale->mType == QCPAxis::atTop) { w = n; h = rect().height(); mGradientImage = QImage(w, h, format); QVector pixels; for (int y=0; y(mGradientImage.scanLine(y))); mParentColorScale->mGradient.colorize(data.constData(), QCPRange(0, n-1), pixels.first(), n); for (int y=1; y(mGradientImage.scanLine(y)); const QRgb lineColor = mParentColorScale->mGradient.color(data[h-1-y], QCPRange(0, n-1)); for (int x=0; x allAxisTypes = QList() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight; foreach (QCPAxis::AxisType type, allAxisTypes) { if (QCPAxis *senderAxis = qobject_cast(sender())) if (senderAxis->axisType() == type) continue; if (axis(type)->selectableParts().testFlag(QCPAxis::spAxis)) { if (selectedParts.testFlag(QCPAxis::spAxis)) axis(type)->setSelectedParts(axis(type)->selectedParts() | QCPAxis::spAxis); else axis(type)->setSelectedParts(axis(type)->selectedParts() & ~QCPAxis::spAxis); } } } /*! \internal This slot is connected to the selectableChanged signals of the four axes in the constructor. It synchronizes the selectability of the axes. */ void QCPColorScaleAxisRectPrivate::axisSelectableChanged(QCPAxis::SelectableParts selectableParts) { // synchronize axis base selectability: const QList allAxisTypes = QList() << QCPAxis::atBottom << QCPAxis::atTop << QCPAxis::atLeft << QCPAxis::atRight; foreach (QCPAxis::AxisType type, allAxisTypes) { if (QCPAxis *senderAxis = qobject_cast(sender())) if (senderAxis->axisType() == type) continue; if (axis(type)->selectableParts().testFlag(QCPAxis::spAxis)) { if (selectableParts.testFlag(QCPAxis::spAxis)) axis(type)->setSelectableParts(axis(type)->selectableParts() | QCPAxis::spAxis); else axis(type)->setSelectableParts(axis(type)->selectableParts() & ~QCPAxis::spAxis); } } } /* end of 'src/layoutelements/layoutelement-colorscale.cpp' */ /* including file 'src/plottables/plottable-graph.cpp' */ /* modified 2021-03-29T02:30:44, size 74518 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPGraphData //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPGraphData \brief Holds the data of one single data point for QCPGraph. The stored data is: \li \a key: coordinate on the key axis of this data point (this is the \a mainKey and the \a sortKey) \li \a value: coordinate on the value axis of this data point (this is the \a mainValue) The container for storing multiple data points is \ref QCPGraphDataContainer. It is a typedef for \ref QCPDataContainer with \ref QCPGraphData as the DataType template parameter. See the documentation there for an explanation regarding the data type's generic methods. \see QCPGraphDataContainer */ /* start documentation of inline functions */ /*! \fn double QCPGraphData::sortKey() const Returns the \a key member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static QCPGraphData QCPGraphData::fromSortKey(double sortKey) Returns a data point with the specified \a sortKey. All other members are set to zero. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static static bool QCPGraphData::sortKeyIsMainKey() Since the member \a key is both the data point key coordinate and the data ordering parameter, this method returns true. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPGraphData::mainKey() const Returns the \a key member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPGraphData::mainValue() const Returns the \a value member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn QCPRange QCPGraphData::valueRange() const Returns a QCPRange with both lower and upper boundary set to \a value of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /* end documentation of inline functions */ /*! Constructs a data point with key and value set to zero. */ QCPGraphData::QCPGraphData() : key(0), value(0) { } /*! Constructs a data point with the specified \a key and \a value. */ QCPGraphData::QCPGraphData(double key, double value) : key(key), value(value) { } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPGraph //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPGraph \brief A plottable representing a graph in a plot. \image html QCPGraph.png Usually you create new graphs by calling QCustomPlot::addGraph. The resulting instance can be accessed via QCustomPlot::graph. To plot data, assign it with the \ref setData or \ref addData functions. Alternatively, you can also access and modify the data via the \ref data method, which returns a pointer to the internal \ref QCPGraphDataContainer. Graphs are used to display single-valued data. Single-valued means that there should only be one data point per unique key coordinate. In other words, the graph can't have \a loops. If you do want to plot non-single-valued curves, rather use the QCPCurve plottable. Gaps in the graph line can be created by adding data points with NaN as value (qQNaN() or std::numeric_limits::quiet_NaN()) in between the two data points that shall be separated. \section qcpgraph-appearance Changing the appearance The appearance of the graph is mainly determined by the line style, scatter style, brush and pen of the graph (\ref setLineStyle, \ref setScatterStyle, \ref setBrush, \ref setPen). \subsection filling Filling under or between graphs QCPGraph knows two types of fills: Normal graph fills towards the zero-value-line parallel to the key axis of the graph, and fills between two graphs, called channel fills. To enable a fill, just set a brush with \ref setBrush which is neither Qt::NoBrush nor fully transparent. By default, a normal fill towards the zero-value-line will be drawn. To set up a channel fill between this graph and another one, call \ref setChannelFillGraph with the other graph as parameter. \see QCustomPlot::addGraph, QCustomPlot::graph */ /* start of documentation of inline functions */ /*! \fn QSharedPointer QCPGraph::data() const Returns a shared pointer to the internal data storage of type \ref QCPGraphDataContainer. You may use it to directly manipulate the data, which may be more convenient and faster than using the regular \ref setData or \ref addData methods. */ /* end of documentation of inline functions */ /*! Constructs a graph which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The created QCPGraph is automatically registered with the QCustomPlot instance inferred from \a keyAxis. This QCustomPlot instance takes ownership of the QCPGraph, so do not delete it manually but use QCustomPlot::removePlottable() instead. To directly create a graph inside a plot, you can also use the simpler QCustomPlot::addGraph function. */ QCPGraph::QCPGraph(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable1D(keyAxis, valueAxis), mLineStyle{}, mScatterSkip{}, mAdaptiveSampling{} { // special handling for QCPGraphs to maintain the simple graph interface: mParentPlot->registerGraph(this); setPen(QPen(Qt::blue, 0)); setBrush(Qt::NoBrush); setLineStyle(lsLine); setScatterSkip(0); setChannelFillGraph(nullptr); setAdaptiveSampling(true); } QCPGraph::~QCPGraph() { } /*! \overload Replaces the current data container with the provided \a data container. Since a QSharedPointer is used, multiple QCPGraphs may share the same data container safely. Modifying the data in the container will then affect all graphs that share the container. Sharing can be achieved by simply exchanging the data containers wrapped in shared pointers: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpgraph-datasharing-1 If you do not wish to share containers, but create a copy from an existing container, rather use the \ref QCPDataContainer::set method on the graph's data container directly: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpgraph-datasharing-2 \see addData */ void QCPGraph::setData(QSharedPointer data) { mDataContainer = data; } /*! \overload Replaces the current data with the provided points in \a keys and \a values. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. \see addData */ void QCPGraph::setData(const QVector &keys, const QVector &values, bool alreadySorted) { mDataContainer->clear(); addData(keys, values, alreadySorted); } /*! Sets how the single data points are connected in the plot. For scatter-only plots, set \a ls to \ref lsNone and \ref setScatterStyle to the desired scatter style. \see setScatterStyle */ void QCPGraph::setLineStyle(LineStyle ls) { mLineStyle = ls; } /*! Sets the visual appearance of single data points in the plot. If set to \ref QCPScatterStyle::ssNone, no scatter points are drawn (e.g. for line-only-plots with appropriate line style). \see QCPScatterStyle, setLineStyle */ void QCPGraph::setScatterStyle(const QCPScatterStyle &style) { mScatterStyle = style; } /*! If scatters are displayed (scatter style not \ref QCPScatterStyle::ssNone), \a skip number of scatter points are skipped/not drawn after every drawn scatter point. This can be used to make the data appear sparser while for example still having a smooth line, and to improve performance for very high density plots. If \a skip is set to 0 (default), all scatter points are drawn. \see setScatterStyle */ void QCPGraph::setScatterSkip(int skip) { mScatterSkip = qMax(0, skip); } /*! Sets the target graph for filling the area between this graph and \a targetGraph with the current brush (\ref setBrush). When \a targetGraph is set to 0, a normal graph fill to the zero-value-line will be shown. To disable any filling, set the brush to Qt::NoBrush. \see setBrush */ void QCPGraph::setChannelFillGraph(QCPGraph *targetGraph) { // prevent setting channel target to this graph itself: if (targetGraph == this) { qDebug() << Q_FUNC_INFO << "targetGraph is this graph itself"; mChannelFillGraph = nullptr; return; } // prevent setting channel target to a graph not in the plot: if (targetGraph && targetGraph->mParentPlot != mParentPlot) { qDebug() << Q_FUNC_INFO << "targetGraph not in same plot"; mChannelFillGraph = nullptr; return; } mChannelFillGraph = targetGraph; } /*! Sets whether adaptive sampling shall be used when plotting this graph. QCustomPlot's adaptive sampling technique can drastically improve the replot performance for graphs with a larger number of points (e.g. above 10,000), without notably changing the appearance of the graph. By default, adaptive sampling is enabled. Even if enabled, QCustomPlot decides whether adaptive sampling shall actually be used on a per-graph basis. So leaving adaptive sampling enabled has no disadvantage in almost all cases. \image html adaptive-sampling-line.png "A line plot of 500,000 points without and with adaptive sampling" As can be seen, line plots experience no visual degradation from adaptive sampling. Outliers are reproduced reliably, as well as the overall shape of the data set. The replot time reduces dramatically though. This allows QCustomPlot to display large amounts of data in realtime. \image html adaptive-sampling-scatter.png "A scatter plot of 100,000 points without and with adaptive sampling" Care must be taken when using high-density scatter plots in combination with adaptive sampling. The adaptive sampling algorithm treats scatter plots more carefully than line plots which still gives a significant reduction of replot times, but not quite as much as for line plots. This is because scatter plots inherently need more data points to be preserved in order to still resemble the original, non-adaptive-sampling plot. As shown above, the results still aren't quite identical, as banding occurs for the outer data points. This is in fact intentional, such that the boundaries of the data cloud stay visible to the viewer. How strong the banding appears, depends on the point density, i.e. the number of points in the plot. For some situations with scatter plots it might thus be desirable to manually turn adaptive sampling off. For example, when saving the plot to disk. This can be achieved by setting \a enabled to false before issuing a command like \ref QCustomPlot::savePng, and setting \a enabled back to true afterwards. */ void QCPGraph::setAdaptiveSampling(bool enabled) { mAdaptiveSampling = enabled; } /*! \overload Adds the provided points in \a keys and \a values to the current data. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPGraph::addData(const QVector &keys, const QVector &values, bool alreadySorted) { if (keys.size() != values.size()) qDebug() << Q_FUNC_INFO << "keys and values have different sizes:" << keys.size() << values.size(); const int n = qMin(keys.size(), values.size()); QVector tempData(n); QVector::iterator it = tempData.begin(); const QVector::iterator itEnd = tempData.end(); int i = 0; while (it != itEnd) { it->key = keys[i]; it->value = values[i]; ++it; ++i; } mDataContainer->add(tempData, alreadySorted); // don't modify tempData beyond this to prevent copy on write } /*! \overload Adds the provided data point as \a key and \a value to the current data. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPGraph::addData(double key, double value) { mDataContainer->add(QCPGraphData(key, value)); } /*! Implements a selectTest specific to this plottable's point geometry. If \a details is not 0, it will be set to a \ref QCPDataSelection, describing the closest data point to \a pos. \seebaseclassmethod \ref QCPAbstractPlottable::selectTest */ double QCPGraph::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return -1; if (!mKeyAxis || !mValueAxis) return -1; if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()) || mParentPlot->interactions().testFlag(QCP::iSelectPlottablesBeyondAxisRect)) { QCPGraphDataContainer::const_iterator closestDataPoint = mDataContainer->constEnd(); double result = pointDistance(pos, closestDataPoint); if (details) { int pointIndex = int(closestDataPoint-mDataContainer->constBegin()); details->setValue(QCPDataSelection(QCPDataRange(pointIndex, pointIndex+1))); } return result; } else return -1; } /* inherits documentation from base class */ QCPRange QCPGraph::getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain) const { return mDataContainer->keyRange(foundRange, inSignDomain); } /* inherits documentation from base class */ QCPRange QCPGraph::getValueRange(bool &foundRange, QCP::SignDomain inSignDomain, const QCPRange &inKeyRange) const { return mDataContainer->valueRange(foundRange, inSignDomain, inKeyRange); } /* inherits documentation from base class */ void QCPGraph::draw(QCPPainter *painter) { if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (mKeyAxis.data()->range().size() <= 0 || mDataContainer->isEmpty()) return; if (mLineStyle == lsNone && mScatterStyle.isNone()) return; QVector lines, scatters; // line and (if necessary) scatter pixel coordinates will be stored here while iterating over segments // loop over and draw segments of unselected/selected data: QList selectedSegments, unselectedSegments, allSegments; getDataSegments(selectedSegments, unselectedSegments); allSegments << unselectedSegments << selectedSegments; for (int i=0; i= unselectedSegments.size(); // get line pixel points appropriate to line style: QCPDataRange lineDataRange = isSelectedSegment ? allSegments.at(i) : allSegments.at(i).adjusted(-1, 1); // unselected segments extend lines to bordering selected data point (safe to exceed total data bounds in first/last segment, getLines takes care) getLines(&lines, lineDataRange); // check data validity if flag set: #ifdef QCUSTOMPLOT_CHECK_DATA QCPGraphDataContainer::const_iterator it; for (it = mDataContainer->constBegin(); it != mDataContainer->constEnd(); ++it) { if (QCP::isInvalidData(it->key, it->value)) qDebug() << Q_FUNC_INFO << "Data point at" << it->key << "invalid." << "Plottable name:" << name(); } #endif // draw fill of graph: if (isSelectedSegment && mSelectionDecorator) mSelectionDecorator->applyBrush(painter); else painter->setBrush(mBrush); painter->setPen(Qt::NoPen); drawFill(painter, &lines); // draw line: if (mLineStyle != lsNone) { if (isSelectedSegment && mSelectionDecorator) mSelectionDecorator->applyPen(painter); else painter->setPen(mPen); painter->setBrush(Qt::NoBrush); if (mLineStyle == lsImpulse) drawImpulsePlot(painter, lines); else drawLinePlot(painter, lines); // also step plots can be drawn as a line plot } // draw scatters: QCPScatterStyle finalScatterStyle = mScatterStyle; if (isSelectedSegment && mSelectionDecorator) finalScatterStyle = mSelectionDecorator->getFinalScatterStyle(mScatterStyle); if (!finalScatterStyle.isNone()) { getScatters(&scatters, allSegments.at(i)); drawScatterPlot(painter, scatters, finalScatterStyle); } } // draw other selection decoration that isn't just line/scatter pens and brushes: if (mSelectionDecorator) mSelectionDecorator->drawDecoration(painter, selection()); } /* inherits documentation from base class */ void QCPGraph::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const { // draw fill: if (mBrush.style() != Qt::NoBrush) { applyFillAntialiasingHint(painter); painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush); } // draw line vertically centered: if (mLineStyle != lsNone) { applyDefaultAntialiasingHint(painter); painter->setPen(mPen); painter->drawLine(QLineF(rect.left(), rect.top()+rect.height()/2.0, rect.right()+5, rect.top()+rect.height()/2.0)); // +5 on x2 else last segment is missing from dashed/dotted pens } // draw scatter symbol: if (!mScatterStyle.isNone()) { applyScattersAntialiasingHint(painter); // scale scatter pixmap if it's too large to fit in legend icon rect: if (mScatterStyle.shape() == QCPScatterStyle::ssPixmap && (mScatterStyle.pixmap().size().width() > rect.width() || mScatterStyle.pixmap().size().height() > rect.height())) { QCPScatterStyle scaledStyle(mScatterStyle); scaledStyle.setPixmap(scaledStyle.pixmap().scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); scaledStyle.applyTo(painter, mPen); scaledStyle.drawShape(painter, QRectF(rect).center()); } else { mScatterStyle.applyTo(painter, mPen); mScatterStyle.drawShape(painter, QRectF(rect).center()); } } } /*! \internal This method retrieves an optimized set of data points via \ref getOptimizedLineData, and branches out to the line style specific functions such as \ref dataToLines, \ref dataToStepLeftLines, etc. according to the line style of the graph. \a lines will be filled with points in pixel coordinates, that can be drawn with the according draw functions like \ref drawLinePlot and \ref drawImpulsePlot. The points returned in \a lines aren't necessarily the original data points. For example, step line styles require additional points to form the steps when drawn. If the line style of the graph is \ref lsNone, the \a lines vector will be empty. \a dataRange specifies the beginning and ending data indices that will be taken into account for conversion. In this function, the specified range may exceed the total data bounds without harm: a correspondingly trimmed data range will be used. This takes the burden off the user of this function to check for valid indices in \a dataRange, e.g. when extending ranges coming from \ref getDataSegments. \see getScatters */ void QCPGraph::getLines(QVector *lines, const QCPDataRange &dataRange) const { if (!lines) return; QCPGraphDataContainer::const_iterator begin, end; getVisibleDataBounds(begin, end, dataRange); if (begin == end) { lines->clear(); return; } QVector lineData; if (mLineStyle != lsNone) getOptimizedLineData(&lineData, begin, end); if (mKeyAxis->rangeReversed() != (mKeyAxis->orientation() == Qt::Vertical)) // make sure key pixels are sorted ascending in lineData (significantly simplifies following processing) std::reverse(lineData.begin(), lineData.end()); switch (mLineStyle) { case lsNone: lines->clear(); break; case lsLine: *lines = dataToLines(lineData); break; case lsStepLeft: *lines = dataToStepLeftLines(lineData); break; case lsStepRight: *lines = dataToStepRightLines(lineData); break; case lsStepCenter: *lines = dataToStepCenterLines(lineData); break; case lsImpulse: *lines = dataToImpulseLines(lineData); break; } } /*! \internal This method retrieves an optimized set of data points via \ref getOptimizedScatterData and then converts them to pixel coordinates. The resulting points are returned in \a scatters, and can be passed to \ref drawScatterPlot. \a dataRange specifies the beginning and ending data indices that will be taken into account for conversion. In this function, the specified range may exceed the total data bounds without harm: a correspondingly trimmed data range will be used. This takes the burden off the user of this function to check for valid indices in \a dataRange, e.g. when extending ranges coming from \ref getDataSegments. */ void QCPGraph::getScatters(QVector *scatters, const QCPDataRange &dataRange) const { if (!scatters) return; QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; scatters->clear(); return; } QCPGraphDataContainer::const_iterator begin, end; getVisibleDataBounds(begin, end, dataRange); if (begin == end) { scatters->clear(); return; } QVector data; getOptimizedScatterData(&data, begin, end); if (mKeyAxis->rangeReversed() != (mKeyAxis->orientation() == Qt::Vertical)) // make sure key pixels are sorted ascending in data (significantly simplifies following processing) std::reverse(data.begin(), data.end()); scatters->resize(data.size()); if (keyAxis->orientation() == Qt::Vertical) { for (int i=0; icoordToPixel(data.at(i).value)); (*scatters)[i].setY(keyAxis->coordToPixel(data.at(i).key)); } } } else { for (int i=0; icoordToPixel(data.at(i).key)); (*scatters)[i].setY(valueAxis->coordToPixel(data.at(i).value)); } } } } /*! \internal Takes raw data points in plot coordinates as \a data, and returns a vector containing pixel coordinate points which are suitable for drawing the line style \ref lsLine. The source of \a data is usually \ref getOptimizedLineData, and this method is called in \a getLines if the line style is set accordingly. \see dataToStepLeftLines, dataToStepRightLines, dataToStepCenterLines, dataToImpulseLines, getLines, drawLinePlot */ QVector QCPGraph::dataToLines(const QVector &data) const { QVector result; QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return result; } result.resize(data.size()); // transform data points to pixels: if (keyAxis->orientation() == Qt::Vertical) { for (int i=0; icoordToPixel(data.at(i).value)); result[i].setY(keyAxis->coordToPixel(data.at(i).key)); } } else // key axis is horizontal { for (int i=0; icoordToPixel(data.at(i).key)); result[i].setY(valueAxis->coordToPixel(data.at(i).value)); } } return result; } /*! \internal Takes raw data points in plot coordinates as \a data, and returns a vector containing pixel coordinate points which are suitable for drawing the line style \ref lsStepLeft. The source of \a data is usually \ref getOptimizedLineData, and this method is called in \a getLines if the line style is set accordingly. \see dataToLines, dataToStepRightLines, dataToStepCenterLines, dataToImpulseLines, getLines, drawLinePlot */ QVector QCPGraph::dataToStepLeftLines(const QVector &data) const { QVector result; QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return result; } result.resize(data.size()*2); // calculate steps from data and transform to pixel coordinates: if (keyAxis->orientation() == Qt::Vertical) { double lastValue = valueAxis->coordToPixel(data.first().value); for (int i=0; icoordToPixel(data.at(i).key); result[i*2+0].setX(lastValue); result[i*2+0].setY(key); lastValue = valueAxis->coordToPixel(data.at(i).value); result[i*2+1].setX(lastValue); result[i*2+1].setY(key); } } else // key axis is horizontal { double lastValue = valueAxis->coordToPixel(data.first().value); for (int i=0; icoordToPixel(data.at(i).key); result[i*2+0].setX(key); result[i*2+0].setY(lastValue); lastValue = valueAxis->coordToPixel(data.at(i).value); result[i*2+1].setX(key); result[i*2+1].setY(lastValue); } } return result; } /*! \internal Takes raw data points in plot coordinates as \a data, and returns a vector containing pixel coordinate points which are suitable for drawing the line style \ref lsStepRight. The source of \a data is usually \ref getOptimizedLineData, and this method is called in \a getLines if the line style is set accordingly. \see dataToLines, dataToStepLeftLines, dataToStepCenterLines, dataToImpulseLines, getLines, drawLinePlot */ QVector QCPGraph::dataToStepRightLines(const QVector &data) const { QVector result; QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return result; } result.resize(data.size()*2); // calculate steps from data and transform to pixel coordinates: if (keyAxis->orientation() == Qt::Vertical) { double lastKey = keyAxis->coordToPixel(data.first().key); for (int i=0; icoordToPixel(data.at(i).value); result[i*2+0].setX(value); result[i*2+0].setY(lastKey); lastKey = keyAxis->coordToPixel(data.at(i).key); result[i*2+1].setX(value); result[i*2+1].setY(lastKey); } } else // key axis is horizontal { double lastKey = keyAxis->coordToPixel(data.first().key); for (int i=0; icoordToPixel(data.at(i).value); result[i*2+0].setX(lastKey); result[i*2+0].setY(value); lastKey = keyAxis->coordToPixel(data.at(i).key); result[i*2+1].setX(lastKey); result[i*2+1].setY(value); } } return result; } /*! \internal Takes raw data points in plot coordinates as \a data, and returns a vector containing pixel coordinate points which are suitable for drawing the line style \ref lsStepCenter. The source of \a data is usually \ref getOptimizedLineData, and this method is called in \a getLines if the line style is set accordingly. \see dataToLines, dataToStepLeftLines, dataToStepRightLines, dataToImpulseLines, getLines, drawLinePlot */ QVector QCPGraph::dataToStepCenterLines(const QVector &data) const { QVector result; QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return result; } result.resize(data.size()*2); // calculate steps from data and transform to pixel coordinates: if (keyAxis->orientation() == Qt::Vertical) { double lastKey = keyAxis->coordToPixel(data.first().key); double lastValue = valueAxis->coordToPixel(data.first().value); result[0].setX(lastValue); result[0].setY(lastKey); for (int i=1; icoordToPixel(data.at(i).key)+lastKey)*0.5; result[i*2-1].setX(lastValue); result[i*2-1].setY(key); lastValue = valueAxis->coordToPixel(data.at(i).value); lastKey = keyAxis->coordToPixel(data.at(i).key); result[i*2+0].setX(lastValue); result[i*2+0].setY(key); } result[data.size()*2-1].setX(lastValue); result[data.size()*2-1].setY(lastKey); } else // key axis is horizontal { double lastKey = keyAxis->coordToPixel(data.first().key); double lastValue = valueAxis->coordToPixel(data.first().value); result[0].setX(lastKey); result[0].setY(lastValue); for (int i=1; icoordToPixel(data.at(i).key)+lastKey)*0.5; result[i*2-1].setX(key); result[i*2-1].setY(lastValue); lastValue = valueAxis->coordToPixel(data.at(i).value); lastKey = keyAxis->coordToPixel(data.at(i).key); result[i*2+0].setX(key); result[i*2+0].setY(lastValue); } result[data.size()*2-1].setX(lastKey); result[data.size()*2-1].setY(lastValue); } return result; } /*! \internal Takes raw data points in plot coordinates as \a data, and returns a vector containing pixel coordinate points which are suitable for drawing the line style \ref lsImpulse. The source of \a data is usually \ref getOptimizedLineData, and this method is called in \a getLines if the line style is set accordingly. \see dataToLines, dataToStepLeftLines, dataToStepRightLines, dataToStepCenterLines, getLines, drawImpulsePlot */ QVector QCPGraph::dataToImpulseLines(const QVector &data) const { QVector result; QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return result; } result.resize(data.size()*2); // transform data points to pixels: if (keyAxis->orientation() == Qt::Vertical) { for (int i=0; icoordToPixel(data.at(i).key); result[i*2+0].setX(valueAxis->coordToPixel(0)); result[i*2+0].setY(key); result[i*2+1].setX(valueAxis->coordToPixel(data.at(i).value)); result[i*2+1].setY(key); } } else // key axis is horizontal { for (int i=0; icoordToPixel(data.at(i).key); result[i*2+0].setX(key); result[i*2+0].setY(valueAxis->coordToPixel(0)); result[i*2+1].setX(key); result[i*2+1].setY(valueAxis->coordToPixel(data.at(i).value)); } } return result; } /*! \internal Draws the fill of the graph using the specified \a painter, with the currently set brush. Depending on whether a normal fill or a channel fill (\ref setChannelFillGraph) is needed, \ref getFillPolygon or \ref getChannelFillPolygon are used to find the according fill polygons. In order to handle NaN Data points correctly (the fill needs to be split into disjoint areas), this method first determines a list of non-NaN segments with \ref getNonNanSegments, on which to operate. In the channel fill case, \ref getOverlappingSegments is used to consolidate the non-NaN segments of the two involved graphs, before passing the overlapping pairs to \ref getChannelFillPolygon. Pass the points of this graph's line as \a lines, in pixel coordinates. \see drawLinePlot, drawImpulsePlot, drawScatterPlot */ void QCPGraph::drawFill(QCPPainter *painter, QVector *lines) const { if (mLineStyle == lsImpulse) return; // fill doesn't make sense for impulse plot if (painter->brush().style() == Qt::NoBrush || painter->brush().color().alpha() == 0) return; applyFillAntialiasingHint(painter); const QVector segments = getNonNanSegments(lines, keyAxis()->orientation()); if (!mChannelFillGraph) { // draw base fill under graph, fill goes all the way to the zero-value-line: foreach (QCPDataRange segment, segments) painter->drawPolygon(getFillPolygon(lines, segment)); } else { // draw fill between this graph and mChannelFillGraph: QVector otherLines; mChannelFillGraph->getLines(&otherLines, QCPDataRange(0, mChannelFillGraph->dataCount())); if (!otherLines.isEmpty()) { QVector otherSegments = getNonNanSegments(&otherLines, mChannelFillGraph->keyAxis()->orientation()); QVector > segmentPairs = getOverlappingSegments(segments, lines, otherSegments, &otherLines); for (int i=0; idrawPolygon(getChannelFillPolygon(lines, segmentPairs.at(i).first, &otherLines, segmentPairs.at(i).second)); } } } /*! \internal Draws scatter symbols at every point passed in \a scatters, given in pixel coordinates. The scatters will be drawn with \a painter and have the appearance as specified in \a style. \see drawLinePlot, drawImpulsePlot */ void QCPGraph::drawScatterPlot(QCPPainter *painter, const QVector &scatters, const QCPScatterStyle &style) const { applyScattersAntialiasingHint(painter); style.applyTo(painter, mPen); foreach (const QPointF &scatter, scatters) style.drawShape(painter, scatter.x(), scatter.y()); } /*! \internal Draws lines between the points in \a lines, given in pixel coordinates. \see drawScatterPlot, drawImpulsePlot, QCPAbstractPlottable1D::drawPolyline */ void QCPGraph::drawLinePlot(QCPPainter *painter, const QVector &lines) const { if (painter->pen().style() != Qt::NoPen && painter->pen().color().alpha() != 0) { applyDefaultAntialiasingHint(painter); drawPolyline(painter, lines); } } /*! \internal Draws impulses from the provided data, i.e. it connects all line pairs in \a lines, given in pixel coordinates. The \a lines necessary for impulses are generated by \ref dataToImpulseLines from the regular graph data points. \see drawLinePlot, drawScatterPlot */ void QCPGraph::drawImpulsePlot(QCPPainter *painter, const QVector &lines) const { if (painter->pen().style() != Qt::NoPen && painter->pen().color().alpha() != 0) { applyDefaultAntialiasingHint(painter); QPen oldPen = painter->pen(); QPen newPen = painter->pen(); newPen.setCapStyle(Qt::FlatCap); // so impulse line doesn't reach beyond zero-line painter->setPen(newPen); painter->drawLines(lines); painter->setPen(oldPen); } } /*! \internal Returns via \a lineData the data points that need to be visualized for this graph when plotting graph lines, taking into consideration the currently visible axis ranges and, if \ref setAdaptiveSampling is enabled, local point densities. The considered data can be restricted further by \a begin and \a end, e.g. to only plot a certain segment of the data (see \ref getDataSegments). This method is used by \ref getLines to retrieve the basic working set of data. \see getOptimizedScatterData */ void QCPGraph::getOptimizedLineData(QVector *lineData, const QCPGraphDataContainer::const_iterator &begin, const QCPGraphDataContainer::const_iterator &end) const { if (!lineData) return; QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (begin == end) return; int dataCount = int(end-begin); int maxCount = (std::numeric_limits::max)(); if (mAdaptiveSampling) { double keyPixelSpan = qAbs(keyAxis->coordToPixel(begin->key)-keyAxis->coordToPixel((end-1)->key)); if (2*keyPixelSpan+2 < static_cast((std::numeric_limits::max)())) maxCount = int(2*keyPixelSpan+2); } if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average { QCPGraphDataContainer::const_iterator it = begin; double minValue = it->value; double maxValue = it->value; QCPGraphDataContainer::const_iterator currentIntervalFirstPoint = it; int reversedFactor = keyAxis->pixelOrientation(); // is used to calculate keyEpsilon pixel into the correct direction int reversedRound = reversedFactor==-1 ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey double currentIntervalStartKey = keyAxis->pixelToCoord(int(keyAxis->coordToPixel(begin->key)+reversedRound)); double lastIntervalEndKey = currentIntervalStartKey; double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes) int intervalDataCount = 1; ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect while (it != end) { if (it->key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary { if (it->value < minValue) minValue = it->value; else if (it->value > maxValue) maxValue = it->value; ++intervalDataCount; } else // new pixel interval started { if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster { if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.2, currentIntervalFirstPoint->value)); lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.25, minValue)); lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.75, maxValue)); if (it->key > currentIntervalStartKey+keyEpsilon*2) // new pixel started further away from previous cluster, so make sure the last point of the cluster is at a real data point lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.8, (it-1)->value)); } else lineData->append(QCPGraphData(currentIntervalFirstPoint->key, currentIntervalFirstPoint->value)); lastIntervalEndKey = (it-1)->key; minValue = it->value; maxValue = it->value; currentIntervalFirstPoint = it; currentIntervalStartKey = keyAxis->pixelToCoord(int(keyAxis->coordToPixel(it->key)+reversedRound)); if (keyEpsilonVariable) keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); intervalDataCount = 1; } ++it; } // handle last interval: if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster { if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.2, currentIntervalFirstPoint->value)); lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.25, minValue)); lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.75, maxValue)); } else lineData->append(QCPGraphData(currentIntervalFirstPoint->key, currentIntervalFirstPoint->value)); } else // don't use adaptive sampling algorithm, transfer points one-to-one from the data container into the output { lineData->resize(dataCount); std::copy(begin, end, lineData->begin()); } } /*! \internal Returns via \a scatterData the data points that need to be visualized for this graph when plotting scatter points, taking into consideration the currently visible axis ranges and, if \ref setAdaptiveSampling is enabled, local point densities. The considered data can be restricted further by \a begin and \a end, e.g. to only plot a certain segment of the data (see \ref getDataSegments). This method is used by \ref getScatters to retrieve the basic working set of data. \see getOptimizedLineData */ void QCPGraph::getOptimizedScatterData(QVector *scatterData, QCPGraphDataContainer::const_iterator begin, QCPGraphDataContainer::const_iterator end) const { if (!scatterData) return; QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } const int scatterModulo = mScatterSkip+1; const bool doScatterSkip = mScatterSkip > 0; int beginIndex = int(begin-mDataContainer->constBegin()); int endIndex = int(end-mDataContainer->constBegin()); while (doScatterSkip && begin != end && beginIndex % scatterModulo != 0) // advance begin iterator to first non-skipped scatter { ++beginIndex; ++begin; } if (begin == end) return; int dataCount = int(end-begin); int maxCount = (std::numeric_limits::max)(); if (mAdaptiveSampling) { int keyPixelSpan = int(qAbs(keyAxis->coordToPixel(begin->key)-keyAxis->coordToPixel((end-1)->key))); maxCount = 2*keyPixelSpan+2; } if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average { double valueMaxRange = valueAxis->range().upper; double valueMinRange = valueAxis->range().lower; QCPGraphDataContainer::const_iterator it = begin; int itIndex = int(beginIndex); double minValue = it->value; double maxValue = it->value; QCPGraphDataContainer::const_iterator minValueIt = it; QCPGraphDataContainer::const_iterator maxValueIt = it; QCPGraphDataContainer::const_iterator currentIntervalStart = it; int reversedFactor = keyAxis->pixelOrientation(); // is used to calculate keyEpsilon pixel into the correct direction int reversedRound = reversedFactor==-1 ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey double currentIntervalStartKey = keyAxis->pixelToCoord(int(keyAxis->coordToPixel(begin->key)+reversedRound)); double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes) int intervalDataCount = 1; // advance iterator to second (non-skipped) data point because adaptive sampling works in 1 point retrospect: if (!doScatterSkip) ++it; else { itIndex += scatterModulo; if (itIndex < endIndex) // make sure we didn't jump over end it += scatterModulo; else { it = end; itIndex = endIndex; } } // main loop over data points: while (it != end) { if (it->key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this pixel if necessary { if (it->value < minValue && it->value > valueMinRange && it->value < valueMaxRange) { minValue = it->value; minValueIt = it; } else if (it->value > maxValue && it->value > valueMinRange && it->value < valueMaxRange) { maxValue = it->value; maxValueIt = it; } ++intervalDataCount; } else // new pixel started { if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them { // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot): double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue)); int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average QCPGraphDataContainer::const_iterator intervalIt = currentIntervalStart; int c = 0; while (intervalIt != it) { if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && intervalIt->value > valueMinRange && intervalIt->value < valueMaxRange) scatterData->append(*intervalIt); ++c; if (!doScatterSkip) ++intervalIt; else intervalIt += scatterModulo; // since we know indices of "currentIntervalStart", "intervalIt" and "it" are multiples of scatterModulo, we can't accidentally jump over "it" here } } else if (currentIntervalStart->value > valueMinRange && currentIntervalStart->value < valueMaxRange) scatterData->append(*currentIntervalStart); minValue = it->value; maxValue = it->value; currentIntervalStart = it; currentIntervalStartKey = keyAxis->pixelToCoord(int(keyAxis->coordToPixel(it->key)+reversedRound)); if (keyEpsilonVariable) keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); intervalDataCount = 1; } // advance to next data point: if (!doScatterSkip) ++it; else { itIndex += scatterModulo; if (itIndex < endIndex) // make sure we didn't jump over end it += scatterModulo; else { it = end; itIndex = endIndex; } } } // handle last interval: if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them { // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot): double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue)); int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average QCPGraphDataContainer::const_iterator intervalIt = currentIntervalStart; int intervalItIndex = int(intervalIt-mDataContainer->constBegin()); int c = 0; while (intervalIt != it) { if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && intervalIt->value > valueMinRange && intervalIt->value < valueMaxRange) scatterData->append(*intervalIt); ++c; if (!doScatterSkip) ++intervalIt; else // here we can't guarantee that adding scatterModulo doesn't exceed "it" (because "it" is equal to "end" here, and "end" isn't scatterModulo-aligned), so check via index comparison: { intervalItIndex += scatterModulo; if (intervalItIndex < itIndex) intervalIt += scatterModulo; else { intervalIt = it; intervalItIndex = itIndex; } } } } else if (currentIntervalStart->value > valueMinRange && currentIntervalStart->value < valueMaxRange) scatterData->append(*currentIntervalStart); } else // don't use adaptive sampling algorithm, transfer points one-to-one from the data container into the output { QCPGraphDataContainer::const_iterator it = begin; int itIndex = beginIndex; scatterData->reserve(dataCount); while (it != end) { scatterData->append(*it); // advance to next data point: if (!doScatterSkip) ++it; else { itIndex += scatterModulo; if (itIndex < endIndex) it += scatterModulo; else { it = end; itIndex = endIndex; } } } } } /*! This method outputs the currently visible data range via \a begin and \a end. The returned range will also never exceed \a rangeRestriction. This method takes into account that the drawing of data lines at the axis rect border always requires the points just outside the visible axis range. So \a begin and \a end may actually indicate a range that contains one additional data point to the left and right of the visible axis range. */ void QCPGraph::getVisibleDataBounds(QCPGraphDataContainer::const_iterator &begin, QCPGraphDataContainer::const_iterator &end, const QCPDataRange &rangeRestriction) const { if (rangeRestriction.isEmpty()) { end = mDataContainer->constEnd(); begin = end; } else { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } // get visible data range: begin = mDataContainer->findBegin(keyAxis->range().lower); end = mDataContainer->findEnd(keyAxis->range().upper); // limit lower/upperEnd to rangeRestriction: mDataContainer->limitIteratorsToDataRange(begin, end, rangeRestriction); // this also ensures rangeRestriction outside data bounds doesn't break anything } } /*! \internal This method goes through the passed points in \a lineData and returns a list of the segments which don't contain NaN data points. \a keyOrientation defines whether the \a x or \a y member of the passed QPointF is used to check for NaN. If \a keyOrientation is \c Qt::Horizontal, the \a y member is checked, if it is \c Qt::Vertical, the \a x member is checked. \see getOverlappingSegments, drawFill */ QVector QCPGraph::getNonNanSegments(const QVector *lineData, Qt::Orientation keyOrientation) const { QVector result; const int n = lineData->size(); QCPDataRange currentSegment(-1, -1); int i = 0; if (keyOrientation == Qt::Horizontal) { while (i < n) { while (i < n && qIsNaN(lineData->at(i).y())) // seek next non-NaN data point ++i; if (i == n) break; currentSegment.setBegin(i++); while (i < n && !qIsNaN(lineData->at(i).y())) // seek next NaN data point or end of data ++i; currentSegment.setEnd(i++); result.append(currentSegment); } } else // keyOrientation == Qt::Vertical { while (i < n) { while (i < n && qIsNaN(lineData->at(i).x())) // seek next non-NaN data point ++i; if (i == n) break; currentSegment.setBegin(i++); while (i < n && !qIsNaN(lineData->at(i).x())) // seek next NaN data point or end of data ++i; currentSegment.setEnd(i++); result.append(currentSegment); } } return result; } /*! \internal This method takes two segment lists (e.g. created by \ref getNonNanSegments) \a thisSegments and \a otherSegments, and their associated point data \a thisData and \a otherData. It returns all pairs of segments (the first from \a thisSegments, the second from \a otherSegments), which overlap in plot coordinates. This method is useful in the case of a channel fill between two graphs, when only those non-NaN segments which actually overlap in their key coordinate shall be considered for drawing a channel fill polygon. It is assumed that the passed segments in \a thisSegments are ordered ascending by index, and that the segments don't overlap themselves. The same is assumed for the segments in \a otherSegments. This is fulfilled when the segments are obtained via \ref getNonNanSegments. \see getNonNanSegments, segmentsIntersect, drawFill, getChannelFillPolygon */ QVector > QCPGraph::getOverlappingSegments(QVector thisSegments, const QVector *thisData, QVector otherSegments, const QVector *otherData) const { QVector > result; if (thisData->isEmpty() || otherData->isEmpty() || thisSegments.isEmpty() || otherSegments.isEmpty()) return result; int thisIndex = 0; int otherIndex = 0; const bool verticalKey = mKeyAxis->orientation() == Qt::Vertical; while (thisIndex < thisSegments.size() && otherIndex < otherSegments.size()) { if (thisSegments.at(thisIndex).size() < 2) // segments with fewer than two points won't have a fill anyhow { ++thisIndex; continue; } if (otherSegments.at(otherIndex).size() < 2) // segments with fewer than two points won't have a fill anyhow { ++otherIndex; continue; } double thisLower, thisUpper, otherLower, otherUpper; if (!verticalKey) { thisLower = thisData->at(thisSegments.at(thisIndex).begin()).x(); thisUpper = thisData->at(thisSegments.at(thisIndex).end()-1).x(); otherLower = otherData->at(otherSegments.at(otherIndex).begin()).x(); otherUpper = otherData->at(otherSegments.at(otherIndex).end()-1).x(); } else { thisLower = thisData->at(thisSegments.at(thisIndex).begin()).y(); thisUpper = thisData->at(thisSegments.at(thisIndex).end()-1).y(); otherLower = otherData->at(otherSegments.at(otherIndex).begin()).y(); otherUpper = otherData->at(otherSegments.at(otherIndex).end()-1).y(); } int bPrecedence; if (segmentsIntersect(thisLower, thisUpper, otherLower, otherUpper, bPrecedence)) result.append(QPair(thisSegments.at(thisIndex), otherSegments.at(otherIndex))); if (bPrecedence <= 0) // otherSegment doesn't reach as far as thisSegment, so continue with next otherSegment, keeping current thisSegment ++otherIndex; else // otherSegment reaches further than thisSegment, so continue with next thisSegment, keeping current otherSegment ++thisIndex; } return result; } /*! \internal Returns whether the segments defined by the coordinates (aLower, aUpper) and (bLower, bUpper) have overlap. The output parameter \a bPrecedence indicates whether the \a b segment reaches farther than the \a a segment or not. If \a bPrecedence returns 1, segment \a b reaches the farthest to higher coordinates (i.e. bUpper > aUpper). If it returns -1, segment \a a reaches the farthest. Only if both segment's upper bounds are identical, 0 is returned as \a bPrecedence. It is assumed that the lower bounds always have smaller or equal values than the upper bounds. \see getOverlappingSegments */ bool QCPGraph::segmentsIntersect(double aLower, double aUpper, double bLower, double bUpper, int &bPrecedence) const { bPrecedence = 0; if (aLower > bUpper) { bPrecedence = -1; return false; } else if (bLower > aUpper) { bPrecedence = 1; return false; } else { if (aUpper > bUpper) bPrecedence = -1; else if (aUpper < bUpper) bPrecedence = 1; return true; } } /*! \internal Returns the point which closes the fill polygon on the zero-value-line parallel to the key axis. The logarithmic axis scale case is a bit special, since the zero-value-line in pixel coordinates is in positive or negative infinity. So this case is handled separately by just closing the fill polygon on the axis which lies in the direction towards the zero value. \a matchingDataPoint will provide the key (in pixels) of the returned point. Depending on whether the key axis of this graph is horizontal or vertical, \a matchingDataPoint will provide the x or y value of the returned point, respectively. */ QPointF QCPGraph::getFillBasePoint(QPointF matchingDataPoint) const { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return {}; } QPointF result; if (valueAxis->scaleType() == QCPAxis::stLinear) { if (keyAxis->orientation() == Qt::Horizontal) { result.setX(matchingDataPoint.x()); result.setY(valueAxis->coordToPixel(0)); } else // keyAxis->orientation() == Qt::Vertical { result.setX(valueAxis->coordToPixel(0)); result.setY(matchingDataPoint.y()); } } else // valueAxis->mScaleType == QCPAxis::stLogarithmic { // In logarithmic scaling we can't just draw to value 0 so we just fill all the way // to the axis which is in the direction towards 0 if (keyAxis->orientation() == Qt::Vertical) { if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) || (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis result.setX(keyAxis->axisRect()->right()); else result.setX(keyAxis->axisRect()->left()); result.setY(matchingDataPoint.y()); } else if (keyAxis->axisType() == QCPAxis::atTop || keyAxis->axisType() == QCPAxis::atBottom) { result.setX(matchingDataPoint.x()); if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed()) || (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis result.setY(keyAxis->axisRect()->top()); else result.setY(keyAxis->axisRect()->bottom()); } } return result; } /*! \internal Returns the polygon needed for drawing normal fills between this graph and the key axis. Pass the graph's data points (in pixel coordinates) as \a lineData, and specify the \a segment which shall be used for the fill. The collection of \a lineData points described by \a segment must not contain NaN data points (see \ref getNonNanSegments). The returned fill polygon will be closed at the key axis (the zero-value line) for linear value axes. For logarithmic value axes the polygon will reach just beyond the corresponding axis rect side (see \ref getFillBasePoint). For increased performance (due to implicit sharing), keep the returned QPolygonF const. \see drawFill, getNonNanSegments */ const QPolygonF QCPGraph::getFillPolygon(const QVector *lineData, QCPDataRange segment) const { if (segment.size() < 2) return QPolygonF(); QPolygonF result(segment.size()+2); result[0] = getFillBasePoint(lineData->at(segment.begin())); std::copy(lineData->constBegin()+segment.begin(), lineData->constBegin()+segment.end(), result.begin()+1); result[result.size()-1] = getFillBasePoint(lineData->at(segment.end()-1)); return result; } /*! \internal Returns the polygon needed for drawing (partial) channel fills between this graph and the graph specified by \ref setChannelFillGraph. The data points of this graph are passed as pixel coordinates via \a thisData, the data of the other graph as \a otherData. The returned polygon will be calculated for the specified data segments \a thisSegment and \a otherSegment, pertaining to the respective \a thisData and \a otherData, respectively. The passed \a thisSegment and \a otherSegment should correspond to the segment pairs returned by \ref getOverlappingSegments, to make sure only segments that actually have key coordinate overlap need to be processed here. For increased performance due to implicit sharing, keep the returned QPolygonF const. \see drawFill, getOverlappingSegments, getNonNanSegments */ const QPolygonF QCPGraph::getChannelFillPolygon(const QVector *thisData, QCPDataRange thisSegment, const QVector *otherData, QCPDataRange otherSegment) const { if (!mChannelFillGraph) return QPolygonF(); QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPolygonF(); } if (!mChannelFillGraph.data()->mKeyAxis) { qDebug() << Q_FUNC_INFO << "channel fill target key axis invalid"; return QPolygonF(); } if (mChannelFillGraph.data()->mKeyAxis.data()->orientation() != keyAxis->orientation()) return QPolygonF(); // don't have same axis orientation, can't fill that (Note: if keyAxis fits, valueAxis will fit too, because it's always orthogonal to keyAxis) if (thisData->isEmpty()) return QPolygonF(); QVector thisSegmentData(thisSegment.size()); QVector otherSegmentData(otherSegment.size()); std::copy(thisData->constBegin()+thisSegment.begin(), thisData->constBegin()+thisSegment.end(), thisSegmentData.begin()); std::copy(otherData->constBegin()+otherSegment.begin(), otherData->constBegin()+otherSegment.end(), otherSegmentData.begin()); // pointers to be able to swap them, depending which data range needs cropping: QVector *staticData = &thisSegmentData; QVector *croppedData = &otherSegmentData; // crop both vectors to ranges in which the keys overlap (which coord is key, depends on axisType): if (keyAxis->orientation() == Qt::Horizontal) { // x is key // crop lower bound: if (staticData->first().x() < croppedData->first().x()) // other one must be cropped qSwap(staticData, croppedData); const int lowBound = findIndexBelowX(croppedData, staticData->first().x()); if (lowBound == -1) return QPolygonF(); // key ranges have no overlap croppedData->remove(0, lowBound); // set lowest point of cropped data to fit exactly key position of first static data point via linear interpolation: if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation double slope; if (!qFuzzyCompare(croppedData->at(1).x(), croppedData->at(0).x())) slope = (croppedData->at(1).y()-croppedData->at(0).y())/(croppedData->at(1).x()-croppedData->at(0).x()); else slope = 0; (*croppedData)[0].setY(croppedData->at(0).y()+slope*(staticData->first().x()-croppedData->at(0).x())); (*croppedData)[0].setX(staticData->first().x()); // crop upper bound: if (staticData->last().x() > croppedData->last().x()) // other one must be cropped qSwap(staticData, croppedData); int highBound = findIndexAboveX(croppedData, staticData->last().x()); if (highBound == -1) return QPolygonF(); // key ranges have no overlap croppedData->remove(highBound+1, croppedData->size()-(highBound+1)); // set highest point of cropped data to fit exactly key position of last static data point via linear interpolation: if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation const int li = croppedData->size()-1; // last index if (!qFuzzyCompare(croppedData->at(li).x(), croppedData->at(li-1).x())) slope = (croppedData->at(li).y()-croppedData->at(li-1).y())/(croppedData->at(li).x()-croppedData->at(li-1).x()); else slope = 0; (*croppedData)[li].setY(croppedData->at(li-1).y()+slope*(staticData->last().x()-croppedData->at(li-1).x())); (*croppedData)[li].setX(staticData->last().x()); } else // mKeyAxis->orientation() == Qt::Vertical { // y is key // crop lower bound: if (staticData->first().y() < croppedData->first().y()) // other one must be cropped qSwap(staticData, croppedData); int lowBound = findIndexBelowY(croppedData, staticData->first().y()); if (lowBound == -1) return QPolygonF(); // key ranges have no overlap croppedData->remove(0, lowBound); // set lowest point of cropped data to fit exactly key position of first static data point via linear interpolation: if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation double slope; if (!qFuzzyCompare(croppedData->at(1).y(), croppedData->at(0).y())) // avoid division by zero in step plots slope = (croppedData->at(1).x()-croppedData->at(0).x())/(croppedData->at(1).y()-croppedData->at(0).y()); else slope = 0; (*croppedData)[0].setX(croppedData->at(0).x()+slope*(staticData->first().y()-croppedData->at(0).y())); (*croppedData)[0].setY(staticData->first().y()); // crop upper bound: if (staticData->last().y() > croppedData->last().y()) // other one must be cropped qSwap(staticData, croppedData); int highBound = findIndexAboveY(croppedData, staticData->last().y()); if (highBound == -1) return QPolygonF(); // key ranges have no overlap croppedData->remove(highBound+1, croppedData->size()-(highBound+1)); // set highest point of cropped data to fit exactly key position of last static data point via linear interpolation: if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation int li = croppedData->size()-1; // last index if (!qFuzzyCompare(croppedData->at(li).y(), croppedData->at(li-1).y())) // avoid division by zero in step plots slope = (croppedData->at(li).x()-croppedData->at(li-1).x())/(croppedData->at(li).y()-croppedData->at(li-1).y()); else slope = 0; (*croppedData)[li].setX(croppedData->at(li-1).x()+slope*(staticData->last().y()-croppedData->at(li-1).y())); (*croppedData)[li].setY(staticData->last().y()); } // return joined: for (int i=otherSegmentData.size()-1; i>=0; --i) // insert reversed, otherwise the polygon will be twisted thisSegmentData << otherSegmentData.at(i); return QPolygonF(thisSegmentData); } /*! \internal Finds the smallest index of \a data, whose points x value is just above \a x. Assumes x values in \a data points are ordered ascending, as is ensured by \ref getLines/\ref getScatters if the key axis is horizontal. Used to calculate the channel fill polygon, see \ref getChannelFillPolygon. */ int QCPGraph::findIndexAboveX(const QVector *data, double x) const { for (int i=data->size()-1; i>=0; --i) { if (data->at(i).x() < x) { if (isize()-1) return i+1; else return data->size()-1; } } return -1; } /*! \internal Finds the highest index of \a data, whose points x value is just below \a x. Assumes x values in \a data points are ordered ascending, as is ensured by \ref getLines/\ref getScatters if the key axis is horizontal. Used to calculate the channel fill polygon, see \ref getChannelFillPolygon. */ int QCPGraph::findIndexBelowX(const QVector *data, double x) const { for (int i=0; isize(); ++i) { if (data->at(i).x() > x) { if (i>0) return i-1; else return 0; } } return -1; } /*! \internal Finds the smallest index of \a data, whose points y value is just above \a y. Assumes y values in \a data points are ordered ascending, as is ensured by \ref getLines/\ref getScatters if the key axis is vertical. Used to calculate the channel fill polygon, see \ref getChannelFillPolygon. */ int QCPGraph::findIndexAboveY(const QVector *data, double y) const { for (int i=data->size()-1; i>=0; --i) { if (data->at(i).y() < y) { if (isize()-1) return i+1; else return data->size()-1; } } return -1; } /*! \internal Calculates the minimum distance in pixels the graph's representation has from the given \a pixelPoint. This is used to determine whether the graph was clicked or not, e.g. in \ref selectTest. The closest data point to \a pixelPoint is returned in \a closestData. Note that if the graph has a line representation, the returned distance may be smaller than the distance to the \a closestData point, since the distance to the graph line is also taken into account. If either the graph has no data or if the line style is \ref lsNone and the scatter style's shape is \ref QCPScatterStyle::ssNone (i.e. there is no visual representation of the graph), returns -1.0. */ double QCPGraph::pointDistance(const QPointF &pixelPoint, QCPGraphDataContainer::const_iterator &closestData) const { closestData = mDataContainer->constEnd(); if (mDataContainer->isEmpty()) return -1.0; if (mLineStyle == lsNone && mScatterStyle.isNone()) return -1.0; // calculate minimum distances to graph data points and find closestData iterator: double minDistSqr = (std::numeric_limits::max)(); // determine which key range comes into question, taking selection tolerance around pos into account: double posKeyMin, posKeyMax, dummy; pixelsToCoords(pixelPoint-QPointF(mParentPlot->selectionTolerance(), mParentPlot->selectionTolerance()), posKeyMin, dummy); pixelsToCoords(pixelPoint+QPointF(mParentPlot->selectionTolerance(), mParentPlot->selectionTolerance()), posKeyMax, dummy); if (posKeyMin > posKeyMax) qSwap(posKeyMin, posKeyMax); // iterate over found data points and then choose the one with the shortest distance to pos: QCPGraphDataContainer::const_iterator begin = mDataContainer->findBegin(posKeyMin, true); QCPGraphDataContainer::const_iterator end = mDataContainer->findEnd(posKeyMax, true); for (QCPGraphDataContainer::const_iterator it=begin; it!=end; ++it) { const double currentDistSqr = QCPVector2D(coordsToPixels(it->key, it->value)-pixelPoint).lengthSquared(); if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestData = it; } } // calculate distance to graph line if there is one (if so, will probably be smaller than distance to closest data point): if (mLineStyle != lsNone) { // line displayed, calculate distance to line segments: QVector lineData; getLines(&lineData, QCPDataRange(0, dataCount())); // don't limit data range further since with sharp data spikes, line segments may be closer to test point than segments with closer key coordinate QCPVector2D p(pixelPoint); const int step = mLineStyle==lsImpulse ? 2 : 1; // impulse plot differs from other line styles in that the lineData points are only pairwise connected for (int i=0; i *data, double y) const { for (int i=0; isize(); ++i) { if (data->at(i).y() > y) { if (i>0) return i-1; else return 0; } } return -1; } /* end of 'src/plottables/plottable-graph.cpp' */ /* including file 'src/plottables/plottable-curve.cpp' */ /* modified 2021-03-29T02:30:44, size 63851 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPCurveData //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPCurveData \brief Holds the data of one single data point for QCPCurve. The stored data is: \li \a t: the free ordering parameter of this curve point, like in the mathematical vector (x(t), y(t)). (This is the \a sortKey) \li \a key: coordinate on the key axis of this curve point (this is the \a mainKey) \li \a value: coordinate on the value axis of this curve point (this is the \a mainValue) The container for storing multiple data points is \ref QCPCurveDataContainer. It is a typedef for \ref QCPDataContainer with \ref QCPCurveData as the DataType template parameter. See the documentation there for an explanation regarding the data type's generic methods. \see QCPCurveDataContainer */ /* start documentation of inline functions */ /*! \fn double QCPCurveData::sortKey() const Returns the \a t member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static QCPCurveData QCPCurveData::fromSortKey(double sortKey) Returns a data point with the specified \a sortKey (assigned to the data point's \a t member). All other members are set to zero. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static static bool QCPCurveData::sortKeyIsMainKey() Since the member \a key is the data point key coordinate and the member \a t is the data ordering parameter, this method returns false. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPCurveData::mainKey() const Returns the \a key member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPCurveData::mainValue() const Returns the \a value member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn QCPRange QCPCurveData::valueRange() const Returns a QCPRange with both lower and upper boundary set to \a value of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /* end documentation of inline functions */ /*! Constructs a curve data point with t, key and value set to zero. */ QCPCurveData::QCPCurveData() : t(0), key(0), value(0) { } /*! Constructs a curve data point with the specified \a t, \a key and \a value. */ QCPCurveData::QCPCurveData(double t, double key, double value) : t(t), key(key), value(value) { } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPCurve //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPCurve \brief A plottable representing a parametric curve in a plot. \image html QCPCurve.png Unlike QCPGraph, plottables of this type may have multiple points with the same key coordinate, so their visual representation can have \a loops. This is realized by introducing a third coordinate \a t, which defines the order of the points described by the other two coordinates \a x and \a y. To plot data, assign it with the \ref setData or \ref addData functions. Alternatively, you can also access and modify the curve's data via the \ref data method, which returns a pointer to the internal \ref QCPCurveDataContainer. Gaps in the curve can be created by adding data points with NaN as key and value (qQNaN() or std::numeric_limits::quiet_NaN()) in between the two data points that shall be separated. \section qcpcurve-appearance Changing the appearance The appearance of the curve is determined by the pen and the brush (\ref setPen, \ref setBrush). \section qcpcurve-usage Usage Like all data representing objects in QCustomPlot, the QCPCurve is a plottable (QCPAbstractPlottable). So the plottable-interface of QCustomPlot applies (QCustomPlot::plottable, QCustomPlot::removePlottable, etc.) Usually, you first create an instance: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcurve-creation-1 which registers it with the QCustomPlot instance of the passed axes. Note that this QCustomPlot instance takes ownership of the plottable, so do not delete it manually but use QCustomPlot::removePlottable() instead. The newly created plottable can be modified, e.g.: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcurve-creation-2 */ /* start of documentation of inline functions */ /*! \fn QSharedPointer QCPCurve::data() const Returns a shared pointer to the internal data storage of type \ref QCPCurveDataContainer. You may use it to directly manipulate the data, which may be more convenient and faster than using the regular \ref setData or \ref addData methods. */ /* end of documentation of inline functions */ /*! Constructs a curve which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The created QCPCurve is automatically registered with the QCustomPlot instance inferred from \a keyAxis. This QCustomPlot instance takes ownership of the QCPCurve, so do not delete it manually but use QCustomPlot::removePlottable() instead. */ QCPCurve::QCPCurve(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable1D(keyAxis, valueAxis), mScatterSkip{}, mLineStyle{} { // modify inherited properties from abstract plottable: setPen(QPen(Qt::blue, 0)); setBrush(Qt::NoBrush); setScatterStyle(QCPScatterStyle()); setLineStyle(lsLine); setScatterSkip(0); } QCPCurve::~QCPCurve() { } /*! \overload Replaces the current data container with the provided \a data container. Since a QSharedPointer is used, multiple QCPCurves may share the same data container safely. Modifying the data in the container will then affect all curves that share the container. Sharing can be achieved by simply exchanging the data containers wrapped in shared pointers: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcurve-datasharing-1 If you do not wish to share containers, but create a copy from an existing container, rather use the \ref QCPDataContainer::set method on the curve's data container directly: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpcurve-datasharing-2 \see addData */ void QCPCurve::setData(QSharedPointer data) { mDataContainer = data; } /*! \overload Replaces the current data with the provided points in \a t, \a keys and \a values. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a t in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. \see addData */ void QCPCurve::setData(const QVector &t, const QVector &keys, const QVector &values, bool alreadySorted) { mDataContainer->clear(); addData(t, keys, values, alreadySorted); } /*! \overload Replaces the current data with the provided points in \a keys and \a values. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. The t parameter of each data point will be set to the integer index of the respective key/value pair. \see addData */ void QCPCurve::setData(const QVector &keys, const QVector &values) { mDataContainer->clear(); addData(keys, values); } /*! Sets the visual appearance of single data points in the plot. If set to \ref QCPScatterStyle::ssNone, no scatter points are drawn (e.g. for line-only plots with appropriate line style). \see QCPScatterStyle, setLineStyle */ void QCPCurve::setScatterStyle(const QCPScatterStyle &style) { mScatterStyle = style; } /*! If scatters are displayed (scatter style not \ref QCPScatterStyle::ssNone), \a skip number of scatter points are skipped/not drawn after every drawn scatter point. This can be used to make the data appear sparser while for example still having a smooth line, and to improve performance for very high density plots. If \a skip is set to 0 (default), all scatter points are drawn. \see setScatterStyle */ void QCPCurve::setScatterSkip(int skip) { mScatterSkip = qMax(0, skip); } /*! Sets how the single data points are connected in the plot or how they are represented visually apart from the scatter symbol. For scatter-only plots, set \a style to \ref lsNone and \ref setScatterStyle to the desired scatter style. \see setScatterStyle */ void QCPCurve::setLineStyle(QCPCurve::LineStyle style) { mLineStyle = style; } /*! \overload Adds the provided points in \a t, \a keys and \a values to the current data. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPCurve::addData(const QVector &t, const QVector &keys, const QVector &values, bool alreadySorted) { if (t.size() != keys.size() || t.size() != values.size()) qDebug() << Q_FUNC_INFO << "ts, keys and values have different sizes:" << t.size() << keys.size() << values.size(); const int n = qMin(qMin(t.size(), keys.size()), values.size()); QVector tempData(n); QVector::iterator it = tempData.begin(); const QVector::iterator itEnd = tempData.end(); int i = 0; while (it != itEnd) { it->t = t[i]; it->key = keys[i]; it->value = values[i]; ++it; ++i; } mDataContainer->add(tempData, alreadySorted); // don't modify tempData beyond this to prevent copy on write } /*! \overload Adds the provided points in \a keys and \a values to the current data. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. The t parameter of each data point will be set to the integer index of the respective key/value pair. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPCurve::addData(const QVector &keys, const QVector &values) { if (keys.size() != values.size()) qDebug() << Q_FUNC_INFO << "keys and values have different sizes:" << keys.size() << values.size(); const int n = qMin(keys.size(), values.size()); double tStart; if (!mDataContainer->isEmpty()) tStart = (mDataContainer->constEnd()-1)->t + 1.0; else tStart = 0; QVector tempData(n); QVector::iterator it = tempData.begin(); const QVector::iterator itEnd = tempData.end(); int i = 0; while (it != itEnd) { it->t = tStart + i; it->key = keys[i]; it->value = values[i]; ++it; ++i; } mDataContainer->add(tempData, true); // don't modify tempData beyond this to prevent copy on write } /*! \overload Adds the provided data point as \a t, \a key and \a value to the current data. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPCurve::addData(double t, double key, double value) { mDataContainer->add(QCPCurveData(t, key, value)); } /*! \overload Adds the provided data point as \a key and \a value to the current data. The t parameter is generated automatically by increments of 1 for each point, starting at the highest t of previously existing data or 0, if the curve data is empty. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPCurve::addData(double key, double value) { if (!mDataContainer->isEmpty()) mDataContainer->add(QCPCurveData((mDataContainer->constEnd()-1)->t + 1.0, key, value)); else mDataContainer->add(QCPCurveData(0.0, key, value)); } /*! Implements a selectTest specific to this plottable's point geometry. If \a details is not 0, it will be set to a \ref QCPDataSelection, describing the closest data point to \a pos. \seebaseclassmethod \ref QCPAbstractPlottable::selectTest */ double QCPCurve::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return -1; if (!mKeyAxis || !mValueAxis) return -1; if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()) || mParentPlot->interactions().testFlag(QCP::iSelectPlottablesBeyondAxisRect)) { QCPCurveDataContainer::const_iterator closestDataPoint = mDataContainer->constEnd(); double result = pointDistance(pos, closestDataPoint); if (details) { int pointIndex = int( closestDataPoint-mDataContainer->constBegin() ); details->setValue(QCPDataSelection(QCPDataRange(pointIndex, pointIndex+1))); } return result; } else return -1; } /* inherits documentation from base class */ QCPRange QCPCurve::getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain) const { return mDataContainer->keyRange(foundRange, inSignDomain); } /* inherits documentation from base class */ QCPRange QCPCurve::getValueRange(bool &foundRange, QCP::SignDomain inSignDomain, const QCPRange &inKeyRange) const { return mDataContainer->valueRange(foundRange, inSignDomain, inKeyRange); } /* inherits documentation from base class */ void QCPCurve::draw(QCPPainter *painter) { if (mDataContainer->isEmpty()) return; // allocate line vector: QVector lines, scatters; // loop over and draw segments of unselected/selected data: QList selectedSegments, unselectedSegments, allSegments; getDataSegments(selectedSegments, unselectedSegments); allSegments << unselectedSegments << selectedSegments; for (int i=0; i= unselectedSegments.size(); // fill with curve data: QPen finalCurvePen = mPen; // determine the final pen already here, because the line optimization depends on its stroke width if (isSelectedSegment && mSelectionDecorator) finalCurvePen = mSelectionDecorator->pen(); QCPDataRange lineDataRange = isSelectedSegment ? allSegments.at(i) : allSegments.at(i).adjusted(-1, 1); // unselected segments extend lines to bordering selected data point (safe to exceed total data bounds in first/last segment, getCurveLines takes care) getCurveLines(&lines, lineDataRange, finalCurvePen.widthF()); // check data validity if flag set: #ifdef QCUSTOMPLOT_CHECK_DATA for (QCPCurveDataContainer::const_iterator it = mDataContainer->constBegin(); it != mDataContainer->constEnd(); ++it) { if (QCP::isInvalidData(it->t) || QCP::isInvalidData(it->key, it->value)) qDebug() << Q_FUNC_INFO << "Data point at" << it->key << "invalid." << "Plottable name:" << name(); } #endif // draw curve fill: applyFillAntialiasingHint(painter); if (isSelectedSegment && mSelectionDecorator) mSelectionDecorator->applyBrush(painter); else painter->setBrush(mBrush); painter->setPen(Qt::NoPen); if (painter->brush().style() != Qt::NoBrush && painter->brush().color().alpha() != 0) painter->drawPolygon(QPolygonF(lines)); // draw curve line: if (mLineStyle != lsNone) { painter->setPen(finalCurvePen); painter->setBrush(Qt::NoBrush); drawCurveLine(painter, lines); } // draw scatters: QCPScatterStyle finalScatterStyle = mScatterStyle; if (isSelectedSegment && mSelectionDecorator) finalScatterStyle = mSelectionDecorator->getFinalScatterStyle(mScatterStyle); if (!finalScatterStyle.isNone()) { getScatters(&scatters, allSegments.at(i), finalScatterStyle.size()); drawScatterPlot(painter, scatters, finalScatterStyle); } } // draw other selection decoration that isn't just line/scatter pens and brushes: if (mSelectionDecorator) mSelectionDecorator->drawDecoration(painter, selection()); } /* inherits documentation from base class */ void QCPCurve::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const { // draw fill: if (mBrush.style() != Qt::NoBrush) { applyFillAntialiasingHint(painter); painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush); } // draw line vertically centered: if (mLineStyle != lsNone) { applyDefaultAntialiasingHint(painter); painter->setPen(mPen); painter->drawLine(QLineF(rect.left(), rect.top()+rect.height()/2.0, rect.right()+5, rect.top()+rect.height()/2.0)); // +5 on x2 else last segment is missing from dashed/dotted pens } // draw scatter symbol: if (!mScatterStyle.isNone()) { applyScattersAntialiasingHint(painter); // scale scatter pixmap if it's too large to fit in legend icon rect: if (mScatterStyle.shape() == QCPScatterStyle::ssPixmap && (mScatterStyle.pixmap().size().width() > rect.width() || mScatterStyle.pixmap().size().height() > rect.height())) { QCPScatterStyle scaledStyle(mScatterStyle); scaledStyle.setPixmap(scaledStyle.pixmap().scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); scaledStyle.applyTo(painter, mPen); scaledStyle.drawShape(painter, QRectF(rect).center()); } else { mScatterStyle.applyTo(painter, mPen); mScatterStyle.drawShape(painter, QRectF(rect).center()); } } } /*! \internal Draws lines between the points in \a lines, given in pixel coordinates. \see drawScatterPlot, getCurveLines */ void QCPCurve::drawCurveLine(QCPPainter *painter, const QVector &lines) const { if (painter->pen().style() != Qt::NoPen && painter->pen().color().alpha() != 0) { applyDefaultAntialiasingHint(painter); drawPolyline(painter, lines); } } /*! \internal Draws scatter symbols at every point passed in \a points, given in pixel coordinates. The scatters will be drawn with \a painter and have the appearance as specified in \a style. \see drawCurveLine, getCurveLines */ void QCPCurve::drawScatterPlot(QCPPainter *painter, const QVector &points, const QCPScatterStyle &style) const { // draw scatter point symbols: applyScattersAntialiasingHint(painter); style.applyTo(painter, mPen); foreach (const QPointF &point, points) if (!qIsNaN(point.x()) && !qIsNaN(point.y())) style.drawShape(painter, point); } /*! \internal Called by \ref draw to generate points in pixel coordinates which represent the line of the curve. Line segments that aren't visible in the current axis rect are handled in an optimized way. They are projected onto a rectangle slightly larger than the visible axis rect and simplified regarding point count. The algorithm makes sure to preserve appearance of lines and fills inside the visible axis rect by generating new temporary points on the outer rect if necessary. \a lines will be filled with points in pixel coordinates, that can be drawn with \ref drawCurveLine. \a dataRange specifies the beginning and ending data indices that will be taken into account for conversion. In this function, the specified range may exceed the total data bounds without harm: a correspondingly trimmed data range will be used. This takes the burden off the user of this function to check for valid indices in \a dataRange, e.g. when extending ranges coming from \ref getDataSegments. \a penWidth specifies the pen width that will be used to later draw the lines generated by this function. This is needed here to calculate an accordingly wider margin around the axis rect when performing the line optimization. Methods that are also involved in the algorithm are: \ref getRegion, \ref getOptimizedPoint, \ref getOptimizedCornerPoints \ref mayTraverse, \ref getTraverse, \ref getTraverseCornerPoints. \see drawCurveLine, drawScatterPlot */ void QCPCurve::getCurveLines(QVector *lines, const QCPDataRange &dataRange, double penWidth) const { if (!lines) return; lines->clear(); QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } // add margins to rect to compensate for stroke width const double strokeMargin = qMax(qreal(1.0), qreal(penWidth*0.75)); // stroke radius + 50% safety const double keyMin = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyAxis->range().lower)-strokeMargin*keyAxis->pixelOrientation()); const double keyMax = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyAxis->range().upper)+strokeMargin*keyAxis->pixelOrientation()); const double valueMin = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueAxis->range().lower)-strokeMargin*valueAxis->pixelOrientation()); const double valueMax = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueAxis->range().upper)+strokeMargin*valueAxis->pixelOrientation()); QCPCurveDataContainer::const_iterator itBegin = mDataContainer->constBegin(); QCPCurveDataContainer::const_iterator itEnd = mDataContainer->constEnd(); mDataContainer->limitIteratorsToDataRange(itBegin, itEnd, dataRange); if (itBegin == itEnd) return; QCPCurveDataContainer::const_iterator it = itBegin; QCPCurveDataContainer::const_iterator prevIt = itEnd-1; int prevRegion = getRegion(prevIt->key, prevIt->value, keyMin, valueMax, keyMax, valueMin); QVector trailingPoints; // points that must be applied after all other points (are generated only when handling first point to get virtual segment between last and first point right) while (it != itEnd) { const int currentRegion = getRegion(it->key, it->value, keyMin, valueMax, keyMax, valueMin); if (currentRegion != prevRegion) // changed region, possibly need to add some optimized edge points or original points if entering R { if (currentRegion != 5) // segment doesn't end in R, so it's a candidate for removal { QPointF crossA, crossB; if (prevRegion == 5) // we're coming from R, so add this point optimized { lines->append(getOptimizedPoint(currentRegion, it->key, it->value, prevIt->key, prevIt->value, keyMin, valueMax, keyMax, valueMin)); // in the situations 5->1/7/9/3 the segment may leave R and directly cross through two outer regions. In these cases we need to add an additional corner point *lines << getOptimizedCornerPoints(prevRegion, currentRegion, prevIt->key, prevIt->value, it->key, it->value, keyMin, valueMax, keyMax, valueMin); } else if (mayTraverse(prevRegion, currentRegion) && getTraverse(prevIt->key, prevIt->value, it->key, it->value, keyMin, valueMax, keyMax, valueMin, crossA, crossB)) { // add the two cross points optimized if segment crosses R and if segment isn't virtual zeroth segment between last and first curve point: QVector beforeTraverseCornerPoints, afterTraverseCornerPoints; getTraverseCornerPoints(prevRegion, currentRegion, keyMin, valueMax, keyMax, valueMin, beforeTraverseCornerPoints, afterTraverseCornerPoints); if (it != itBegin) { *lines << beforeTraverseCornerPoints; lines->append(crossA); lines->append(crossB); *lines << afterTraverseCornerPoints; } else { lines->append(crossB); *lines << afterTraverseCornerPoints; trailingPoints << beforeTraverseCornerPoints << crossA ; } } else // doesn't cross R, line is just moving around in outside regions, so only need to add optimized point(s) at the boundary corner(s) { *lines << getOptimizedCornerPoints(prevRegion, currentRegion, prevIt->key, prevIt->value, it->key, it->value, keyMin, valueMax, keyMax, valueMin); } } else // segment does end in R, so we add previous point optimized and this point at original position { if (it == itBegin) // it is first point in curve and prevIt is last one. So save optimized point for adding it to the lineData in the end trailingPoints << getOptimizedPoint(prevRegion, prevIt->key, prevIt->value, it->key, it->value, keyMin, valueMax, keyMax, valueMin); else lines->append(getOptimizedPoint(prevRegion, prevIt->key, prevIt->value, it->key, it->value, keyMin, valueMax, keyMax, valueMin)); lines->append(coordsToPixels(it->key, it->value)); } } else // region didn't change { if (currentRegion == 5) // still in R, keep adding original points { lines->append(coordsToPixels(it->key, it->value)); } else // still outside R, no need to add anything { // see how this is not doing anything? That's the main optimization... } } prevIt = it; prevRegion = currentRegion; ++it; } *lines << trailingPoints; } /*! \internal Called by \ref draw to generate points in pixel coordinates which represent the scatters of the curve. If a scatter skip is configured (\ref setScatterSkip), the returned points are accordingly sparser. Scatters that aren't visible in the current axis rect are optimized away. \a scatters will be filled with points in pixel coordinates, that can be drawn with \ref drawScatterPlot. \a dataRange specifies the beginning and ending data indices that will be taken into account for conversion. \a scatterWidth specifies the scatter width that will be used to later draw the scatters at pixel coordinates generated by this function. This is needed here to calculate an accordingly wider margin around the axis rect when performing the data point reduction. \see draw, drawScatterPlot */ void QCPCurve::getScatters(QVector *scatters, const QCPDataRange &dataRange, double scatterWidth) const { if (!scatters) return; scatters->clear(); QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } QCPCurveDataContainer::const_iterator begin = mDataContainer->constBegin(); QCPCurveDataContainer::const_iterator end = mDataContainer->constEnd(); mDataContainer->limitIteratorsToDataRange(begin, end, dataRange); if (begin == end) return; const int scatterModulo = mScatterSkip+1; const bool doScatterSkip = mScatterSkip > 0; int endIndex = int( end-mDataContainer->constBegin() ); QCPRange keyRange = keyAxis->range(); QCPRange valueRange = valueAxis->range(); // extend range to include width of scatter symbols: keyRange.lower = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyRange.lower)-scatterWidth*keyAxis->pixelOrientation()); keyRange.upper = keyAxis->pixelToCoord(keyAxis->coordToPixel(keyRange.upper)+scatterWidth*keyAxis->pixelOrientation()); valueRange.lower = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueRange.lower)-scatterWidth*valueAxis->pixelOrientation()); valueRange.upper = valueAxis->pixelToCoord(valueAxis->coordToPixel(valueRange.upper)+scatterWidth*valueAxis->pixelOrientation()); QCPCurveDataContainer::const_iterator it = begin; int itIndex = int( begin-mDataContainer->constBegin() ); while (doScatterSkip && it != end && itIndex % scatterModulo != 0) // advance begin iterator to first non-skipped scatter { ++itIndex; ++it; } if (keyAxis->orientation() == Qt::Vertical) { while (it != end) { if (!qIsNaN(it->value) && keyRange.contains(it->key) && valueRange.contains(it->value)) scatters->append(QPointF(valueAxis->coordToPixel(it->value), keyAxis->coordToPixel(it->key))); // advance iterator to next (non-skipped) data point: if (!doScatterSkip) ++it; else { itIndex += scatterModulo; if (itIndex < endIndex) // make sure we didn't jump over end it += scatterModulo; else { it = end; itIndex = endIndex; } } } } else { while (it != end) { if (!qIsNaN(it->value) && keyRange.contains(it->key) && valueRange.contains(it->value)) scatters->append(QPointF(keyAxis->coordToPixel(it->key), valueAxis->coordToPixel(it->value))); // advance iterator to next (non-skipped) data point: if (!doScatterSkip) ++it; else { itIndex += scatterModulo; if (itIndex < endIndex) // make sure we didn't jump over end it += scatterModulo; else { it = end; itIndex = endIndex; } } } } } /*! \internal This function is part of the curve optimization algorithm of \ref getCurveLines. It returns the region of the given point (\a key, \a value) with respect to a rectangle defined by \a keyMin, \a keyMax, \a valueMin, and \a valueMax. The regions are enumerated from top to bottom (\a valueMin to \a valueMax) and left to right (\a keyMin to \a keyMax):
147
258
369
With the rectangle being region 5, and the outer regions extending infinitely outwards. In the curve optimization algorithm, region 5 is considered to be the visible portion of the plot. */ int QCPCurve::getRegion(double key, double value, double keyMin, double valueMax, double keyMax, double valueMin) const { if (key < keyMin) // region 123 { if (value > valueMax) return 1; else if (value < valueMin) return 3; else return 2; } else if (key > keyMax) // region 789 { if (value > valueMax) return 7; else if (value < valueMin) return 9; else return 8; } else // region 456 { if (value > valueMax) return 4; else if (value < valueMin) return 6; else return 5; } } /*! \internal This function is part of the curve optimization algorithm of \ref getCurveLines. This method is used in case the current segment passes from inside the visible rect (region 5, see \ref getRegion) to any of the outer regions (\a otherRegion). The current segment is given by the line connecting (\a key, \a value) with (\a otherKey, \a otherValue). It returns the intersection point of the segment with the border of region 5. For this function it doesn't matter whether (\a key, \a value) is the point inside region 5 or whether it's (\a otherKey, \a otherValue), i.e. whether the segment is coming from region 5 or leaving it. It is important though that \a otherRegion correctly identifies the other region not equal to 5. */ QPointF QCPCurve::getOptimizedPoint(int otherRegion, double otherKey, double otherValue, double key, double value, double keyMin, double valueMax, double keyMax, double valueMin) const { // The intersection point interpolation here is done in pixel coordinates, so we don't need to // differentiate between different axis scale types. Note that the nomenclature // top/left/bottom/right/min/max is with respect to the rect in plot coordinates, wich may be // different in pixel coordinates (horz/vert key axes, reversed ranges) const double keyMinPx = mKeyAxis->coordToPixel(keyMin); const double keyMaxPx = mKeyAxis->coordToPixel(keyMax); const double valueMinPx = mValueAxis->coordToPixel(valueMin); const double valueMaxPx = mValueAxis->coordToPixel(valueMax); const double otherValuePx = mValueAxis->coordToPixel(otherValue); const double valuePx = mValueAxis->coordToPixel(value); const double otherKeyPx = mKeyAxis->coordToPixel(otherKey); const double keyPx = mKeyAxis->coordToPixel(key); double intersectKeyPx = keyMinPx; // initial key just a fail-safe double intersectValuePx = valueMinPx; // initial value just a fail-safe switch (otherRegion) { case 1: // top and left edge { intersectValuePx = valueMaxPx; intersectKeyPx = otherKeyPx + (keyPx-otherKeyPx)/(valuePx-otherValuePx)*(intersectValuePx-otherValuePx); if (intersectKeyPx < qMin(keyMinPx, keyMaxPx) || intersectKeyPx > qMax(keyMinPx, keyMaxPx)) // check whether top edge is not intersected, then it must be left edge (qMin/qMax necessary since axes may be reversed) { intersectKeyPx = keyMinPx; intersectValuePx = otherValuePx + (valuePx-otherValuePx)/(keyPx-otherKeyPx)*(intersectKeyPx-otherKeyPx); } break; } case 2: // left edge { intersectKeyPx = keyMinPx; intersectValuePx = otherValuePx + (valuePx-otherValuePx)/(keyPx-otherKeyPx)*(intersectKeyPx-otherKeyPx); break; } case 3: // bottom and left edge { intersectValuePx = valueMinPx; intersectKeyPx = otherKeyPx + (keyPx-otherKeyPx)/(valuePx-otherValuePx)*(intersectValuePx-otherValuePx); if (intersectKeyPx < qMin(keyMinPx, keyMaxPx) || intersectKeyPx > qMax(keyMinPx, keyMaxPx)) // check whether bottom edge is not intersected, then it must be left edge (qMin/qMax necessary since axes may be reversed) { intersectKeyPx = keyMinPx; intersectValuePx = otherValuePx + (valuePx-otherValuePx)/(keyPx-otherKeyPx)*(intersectKeyPx-otherKeyPx); } break; } case 4: // top edge { intersectValuePx = valueMaxPx; intersectKeyPx = otherKeyPx + (keyPx-otherKeyPx)/(valuePx-otherValuePx)*(intersectValuePx-otherValuePx); break; } case 5: { break; // case 5 shouldn't happen for this function but we add it anyway to prevent potential discontinuity in branch table } case 6: // bottom edge { intersectValuePx = valueMinPx; intersectKeyPx = otherKeyPx + (keyPx-otherKeyPx)/(valuePx-otherValuePx)*(intersectValuePx-otherValuePx); break; } case 7: // top and right edge { intersectValuePx = valueMaxPx; intersectKeyPx = otherKeyPx + (keyPx-otherKeyPx)/(valuePx-otherValuePx)*(intersectValuePx-otherValuePx); if (intersectKeyPx < qMin(keyMinPx, keyMaxPx) || intersectKeyPx > qMax(keyMinPx, keyMaxPx)) // check whether top edge is not intersected, then it must be right edge (qMin/qMax necessary since axes may be reversed) { intersectKeyPx = keyMaxPx; intersectValuePx = otherValuePx + (valuePx-otherValuePx)/(keyPx-otherKeyPx)*(intersectKeyPx-otherKeyPx); } break; } case 8: // right edge { intersectKeyPx = keyMaxPx; intersectValuePx = otherValuePx + (valuePx-otherValuePx)/(keyPx-otherKeyPx)*(intersectKeyPx-otherKeyPx); break; } case 9: // bottom and right edge { intersectValuePx = valueMinPx; intersectKeyPx = otherKeyPx + (keyPx-otherKeyPx)/(valuePx-otherValuePx)*(intersectValuePx-otherValuePx); if (intersectKeyPx < qMin(keyMinPx, keyMaxPx) || intersectKeyPx > qMax(keyMinPx, keyMaxPx)) // check whether bottom edge is not intersected, then it must be right edge (qMin/qMax necessary since axes may be reversed) { intersectKeyPx = keyMaxPx; intersectValuePx = otherValuePx + (valuePx-otherValuePx)/(keyPx-otherKeyPx)*(intersectKeyPx-otherKeyPx); } break; } } if (mKeyAxis->orientation() == Qt::Horizontal) return {intersectKeyPx, intersectValuePx}; else return {intersectValuePx, intersectKeyPx}; } /*! \internal This function is part of the curve optimization algorithm of \ref getCurveLines. In situations where a single segment skips over multiple regions it might become necessary to add extra points at the corners of region 5 (see \ref getRegion) such that the optimized segment doesn't unintentionally cut through the visible area of the axis rect and create plot artifacts. This method provides these points that must be added, assuming the original segment doesn't start, end, or traverse region 5. (Corner points where region 5 is traversed are calculated by \ref getTraverseCornerPoints.) For example, consider a segment which directly goes from region 4 to 2 but originally is far out to the top left such that it doesn't cross region 5. Naively optimizing these points by projecting them on the top and left borders of region 5 will create a segment that surely crosses 5, creating a visual artifact in the plot. This method prevents this by providing extra points at the top left corner, making the optimized curve correctly pass from region 4 to 1 to 2 without traversing 5. */ QVector QCPCurve::getOptimizedCornerPoints(int prevRegion, int currentRegion, double prevKey, double prevValue, double key, double value, double keyMin, double valueMax, double keyMax, double valueMin) const { QVector result; switch (prevRegion) { case 1: { switch (currentRegion) { case 2: { result << coordsToPixels(keyMin, valueMax); break; } case 4: { result << coordsToPixels(keyMin, valueMax); break; } case 3: { result << coordsToPixels(keyMin, valueMax) << coordsToPixels(keyMin, valueMin); break; } case 7: { result << coordsToPixels(keyMin, valueMax) << coordsToPixels(keyMax, valueMax); break; } case 6: { result << coordsToPixels(keyMin, valueMax) << coordsToPixels(keyMin, valueMin); result.append(result.last()); break; } case 8: { result << coordsToPixels(keyMin, valueMax) << coordsToPixels(keyMax, valueMax); result.append(result.last()); break; } case 9: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points if ((value-prevValue)/(key-prevKey)*(keyMin-key)+value < valueMin) // segment passes below R { result << coordsToPixels(keyMin, valueMax) << coordsToPixels(keyMin, valueMin); result.append(result.last()); result << coordsToPixels(keyMax, valueMin); } else { result << coordsToPixels(keyMin, valueMax) << coordsToPixels(keyMax, valueMax); result.append(result.last()); result << coordsToPixels(keyMax, valueMin); } break; } } break; } case 2: { switch (currentRegion) { case 1: { result << coordsToPixels(keyMin, valueMax); break; } case 3: { result << coordsToPixels(keyMin, valueMin); break; } case 4: { result << coordsToPixels(keyMin, valueMax); result.append(result.last()); break; } case 6: { result << coordsToPixels(keyMin, valueMin); result.append(result.last()); break; } case 7: { result << coordsToPixels(keyMin, valueMax); result.append(result.last()); result << coordsToPixels(keyMax, valueMax); break; } case 9: { result << coordsToPixels(keyMin, valueMin); result.append(result.last()); result << coordsToPixels(keyMax, valueMin); break; } } break; } case 3: { switch (currentRegion) { case 2: { result << coordsToPixels(keyMin, valueMin); break; } case 6: { result << coordsToPixels(keyMin, valueMin); break; } case 1: { result << coordsToPixels(keyMin, valueMin) << coordsToPixels(keyMin, valueMax); break; } case 9: { result << coordsToPixels(keyMin, valueMin) << coordsToPixels(keyMax, valueMin); break; } case 4: { result << coordsToPixels(keyMin, valueMin) << coordsToPixels(keyMin, valueMax); result.append(result.last()); break; } case 8: { result << coordsToPixels(keyMin, valueMin) << coordsToPixels(keyMax, valueMin); result.append(result.last()); break; } case 7: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points if ((value-prevValue)/(key-prevKey)*(keyMax-key)+value < valueMin) // segment passes below R { result << coordsToPixels(keyMin, valueMin) << coordsToPixels(keyMax, valueMin); result.append(result.last()); result << coordsToPixels(keyMax, valueMax); } else { result << coordsToPixels(keyMin, valueMin) << coordsToPixels(keyMin, valueMax); result.append(result.last()); result << coordsToPixels(keyMax, valueMax); } break; } } break; } case 4: { switch (currentRegion) { case 1: { result << coordsToPixels(keyMin, valueMax); break; } case 7: { result << coordsToPixels(keyMax, valueMax); break; } case 2: { result << coordsToPixels(keyMin, valueMax); result.append(result.last()); break; } case 8: { result << coordsToPixels(keyMax, valueMax); result.append(result.last()); break; } case 3: { result << coordsToPixels(keyMin, valueMax); result.append(result.last()); result << coordsToPixels(keyMin, valueMin); break; } case 9: { result << coordsToPixels(keyMax, valueMax); result.append(result.last()); result << coordsToPixels(keyMax, valueMin); break; } } break; } case 5: { switch (currentRegion) { case 1: { result << coordsToPixels(keyMin, valueMax); break; } case 7: { result << coordsToPixels(keyMax, valueMax); break; } case 9: { result << coordsToPixels(keyMax, valueMin); break; } case 3: { result << coordsToPixels(keyMin, valueMin); break; } } break; } case 6: { switch (currentRegion) { case 3: { result << coordsToPixels(keyMin, valueMin); break; } case 9: { result << coordsToPixels(keyMax, valueMin); break; } case 2: { result << coordsToPixels(keyMin, valueMin); result.append(result.last()); break; } case 8: { result << coordsToPixels(keyMax, valueMin); result.append(result.last()); break; } case 1: { result << coordsToPixels(keyMin, valueMin); result.append(result.last()); result << coordsToPixels(keyMin, valueMax); break; } case 7: { result << coordsToPixels(keyMax, valueMin); result.append(result.last()); result << coordsToPixels(keyMax, valueMax); break; } } break; } case 7: { switch (currentRegion) { case 4: { result << coordsToPixels(keyMax, valueMax); break; } case 8: { result << coordsToPixels(keyMax, valueMax); break; } case 1: { result << coordsToPixels(keyMax, valueMax) << coordsToPixels(keyMin, valueMax); break; } case 9: { result << coordsToPixels(keyMax, valueMax) << coordsToPixels(keyMax, valueMin); break; } case 2: { result << coordsToPixels(keyMax, valueMax) << coordsToPixels(keyMin, valueMax); result.append(result.last()); break; } case 6: { result << coordsToPixels(keyMax, valueMax) << coordsToPixels(keyMax, valueMin); result.append(result.last()); break; } case 3: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points if ((value-prevValue)/(key-prevKey)*(keyMax-key)+value < valueMin) // segment passes below R { result << coordsToPixels(keyMax, valueMax) << coordsToPixels(keyMax, valueMin); result.append(result.last()); result << coordsToPixels(keyMin, valueMin); } else { result << coordsToPixels(keyMax, valueMax) << coordsToPixels(keyMin, valueMax); result.append(result.last()); result << coordsToPixels(keyMin, valueMin); } break; } } break; } case 8: { switch (currentRegion) { case 7: { result << coordsToPixels(keyMax, valueMax); break; } case 9: { result << coordsToPixels(keyMax, valueMin); break; } case 4: { result << coordsToPixels(keyMax, valueMax); result.append(result.last()); break; } case 6: { result << coordsToPixels(keyMax, valueMin); result.append(result.last()); break; } case 1: { result << coordsToPixels(keyMax, valueMax); result.append(result.last()); result << coordsToPixels(keyMin, valueMax); break; } case 3: { result << coordsToPixels(keyMax, valueMin); result.append(result.last()); result << coordsToPixels(keyMin, valueMin); break; } } break; } case 9: { switch (currentRegion) { case 6: { result << coordsToPixels(keyMax, valueMin); break; } case 8: { result << coordsToPixels(keyMax, valueMin); break; } case 3: { result << coordsToPixels(keyMax, valueMin) << coordsToPixels(keyMin, valueMin); break; } case 7: { result << coordsToPixels(keyMax, valueMin) << coordsToPixels(keyMax, valueMax); break; } case 2: { result << coordsToPixels(keyMax, valueMin) << coordsToPixels(keyMin, valueMin); result.append(result.last()); break; } case 4: { result << coordsToPixels(keyMax, valueMin) << coordsToPixels(keyMax, valueMax); result.append(result.last()); break; } case 1: { // in this case we need another distinction of cases: segment may pass below or above rect, requiring either bottom right or top left corner points if ((value-prevValue)/(key-prevKey)*(keyMin-key)+value < valueMin) // segment passes below R { result << coordsToPixels(keyMax, valueMin) << coordsToPixels(keyMin, valueMin); result.append(result.last()); result << coordsToPixels(keyMin, valueMax); } else { result << coordsToPixels(keyMax, valueMin) << coordsToPixels(keyMax, valueMax); result.append(result.last()); result << coordsToPixels(keyMin, valueMax); } break; } } break; } } return result; } /*! \internal This function is part of the curve optimization algorithm of \ref getCurveLines. This method returns whether a segment going from \a prevRegion to \a currentRegion (see \ref getRegion) may traverse the visible region 5. This function assumes that neither \a prevRegion nor \a currentRegion is 5 itself. If this method returns false, the segment for sure doesn't pass region 5. If it returns true, the segment may or may not pass region 5 and a more fine-grained calculation must be used (\ref getTraverse). */ bool QCPCurve::mayTraverse(int prevRegion, int currentRegion) const { switch (prevRegion) { case 1: { switch (currentRegion) { case 4: case 7: case 2: case 3: return false; default: return true; } } case 2: { switch (currentRegion) { case 1: case 3: return false; default: return true; } } case 3: { switch (currentRegion) { case 1: case 2: case 6: case 9: return false; default: return true; } } case 4: { switch (currentRegion) { case 1: case 7: return false; default: return true; } } case 5: return false; // should never occur case 6: { switch (currentRegion) { case 3: case 9: return false; default: return true; } } case 7: { switch (currentRegion) { case 1: case 4: case 8: case 9: return false; default: return true; } } case 8: { switch (currentRegion) { case 7: case 9: return false; default: return true; } } case 9: { switch (currentRegion) { case 3: case 6: case 8: case 7: return false; default: return true; } } default: return true; } } /*! \internal This function is part of the curve optimization algorithm of \ref getCurveLines. This method assumes that the \ref mayTraverse test has returned true, so there is a chance the segment defined by (\a prevKey, \a prevValue) and (\a key, \a value) goes through the visible region 5. The return value of this method indicates whether the segment actually traverses region 5 or not. If the segment traverses 5, the output parameters \a crossA and \a crossB indicate the entry and exit points of region 5. They will become the optimized points for that segment. */ bool QCPCurve::getTraverse(double prevKey, double prevValue, double key, double value, double keyMin, double valueMax, double keyMax, double valueMin, QPointF &crossA, QPointF &crossB) const { // The intersection point interpolation here is done in pixel coordinates, so we don't need to // differentiate between different axis scale types. Note that the nomenclature // top/left/bottom/right/min/max is with respect to the rect in plot coordinates, wich may be // different in pixel coordinates (horz/vert key axes, reversed ranges) QList intersections; const double valueMinPx = mValueAxis->coordToPixel(valueMin); const double valueMaxPx = mValueAxis->coordToPixel(valueMax); const double keyMinPx = mKeyAxis->coordToPixel(keyMin); const double keyMaxPx = mKeyAxis->coordToPixel(keyMax); const double keyPx = mKeyAxis->coordToPixel(key); const double valuePx = mValueAxis->coordToPixel(value); const double prevKeyPx = mKeyAxis->coordToPixel(prevKey); const double prevValuePx = mValueAxis->coordToPixel(prevValue); if (qFuzzyIsNull(keyPx-prevKeyPx)) // line is parallel to value axis { // due to region filter in mayTraverse(), if line is parallel to value or key axis, region 5 is traversed here intersections.append(mKeyAxis->orientation() == Qt::Horizontal ? QPointF(keyPx, valueMinPx) : QPointF(valueMinPx, keyPx)); // direction will be taken care of at end of method intersections.append(mKeyAxis->orientation() == Qt::Horizontal ? QPointF(keyPx, valueMaxPx) : QPointF(valueMaxPx, keyPx)); } else if (qFuzzyIsNull(valuePx-prevValuePx)) // line is parallel to key axis { // due to region filter in mayTraverse(), if line is parallel to value or key axis, region 5 is traversed here intersections.append(mKeyAxis->orientation() == Qt::Horizontal ? QPointF(keyMinPx, valuePx) : QPointF(valuePx, keyMinPx)); // direction will be taken care of at end of method intersections.append(mKeyAxis->orientation() == Qt::Horizontal ? QPointF(keyMaxPx, valuePx) : QPointF(valuePx, keyMaxPx)); } else // line is skewed { double gamma; double keyPerValuePx = (keyPx-prevKeyPx)/(valuePx-prevValuePx); // check top of rect: gamma = prevKeyPx + (valueMaxPx-prevValuePx)*keyPerValuePx; if (gamma >= qMin(keyMinPx, keyMaxPx) && gamma <= qMax(keyMinPx, keyMaxPx)) // qMin/qMax necessary since axes may be reversed intersections.append(mKeyAxis->orientation() == Qt::Horizontal ? QPointF(gamma, valueMaxPx) : QPointF(valueMaxPx, gamma)); // check bottom of rect: gamma = prevKeyPx + (valueMinPx-prevValuePx)*keyPerValuePx; if (gamma >= qMin(keyMinPx, keyMaxPx) && gamma <= qMax(keyMinPx, keyMaxPx)) // qMin/qMax necessary since axes may be reversed intersections.append(mKeyAxis->orientation() == Qt::Horizontal ? QPointF(gamma, valueMinPx) : QPointF(valueMinPx, gamma)); const double valuePerKeyPx = 1.0/keyPerValuePx; // check left of rect: gamma = prevValuePx + (keyMinPx-prevKeyPx)*valuePerKeyPx; if (gamma >= qMin(valueMinPx, valueMaxPx) && gamma <= qMax(valueMinPx, valueMaxPx)) // qMin/qMax necessary since axes may be reversed intersections.append(mKeyAxis->orientation() == Qt::Horizontal ? QPointF(keyMinPx, gamma) : QPointF(gamma, keyMinPx)); // check right of rect: gamma = prevValuePx + (keyMaxPx-prevKeyPx)*valuePerKeyPx; if (gamma >= qMin(valueMinPx, valueMaxPx) && gamma <= qMax(valueMinPx, valueMaxPx)) // qMin/qMax necessary since axes may be reversed intersections.append(mKeyAxis->orientation() == Qt::Horizontal ? QPointF(keyMaxPx, gamma) : QPointF(gamma, keyMaxPx)); } // handle cases where found points isn't exactly 2: if (intersections.size() > 2) { // line probably goes through corner of rect, and we got duplicate points there. single out the point pair with greatest distance in between: double distSqrMax = 0; QPointF pv1, pv2; for (int i=0; i distSqrMax) { pv1 = intersections.at(i); pv2 = intersections.at(k); distSqrMax = distSqr; } } } intersections = QList() << pv1 << pv2; } else if (intersections.size() != 2) { // one or even zero points found (shouldn't happen unless line perfectly tangent to corner), no need to draw segment return false; } // possibly re-sort points so optimized point segment has same direction as original segment: double xDelta = keyPx-prevKeyPx; double yDelta = valuePx-prevValuePx; if (mKeyAxis->orientation() != Qt::Horizontal) qSwap(xDelta, yDelta); if (xDelta*(intersections.at(1).x()-intersections.at(0).x()) + yDelta*(intersections.at(1).y()-intersections.at(0).y()) < 0) // scalar product of both segments < 0 -> opposite direction intersections.move(0, 1); crossA = intersections.at(0); crossB = intersections.at(1); return true; } /*! \internal This function is part of the curve optimization algorithm of \ref getCurveLines. This method assumes that the \ref getTraverse test has returned true, so the segment definitely traverses the visible region 5 when going from \a prevRegion to \a currentRegion. In certain situations it is not sufficient to merely generate the entry and exit points of the segment into/out of region 5, as \ref getTraverse provides. It may happen that a single segment, in addition to traversing region 5, skips another region outside of region 5, which makes it necessary to add an optimized corner point there (very similar to the job \ref getOptimizedCornerPoints does for segments that are completely in outside regions and don't traverse 5). As an example, consider a segment going from region 1 to region 6, traversing the lower left corner of region 5. In this configuration, the segment additionally crosses the border between region 1 and 2 before entering region 5. This makes it necessary to add an additional point in the top left corner, before adding the optimized traverse points. So in this case, the output parameter \a beforeTraverse will contain the top left corner point, and \a afterTraverse will be empty. In some cases, such as when going from region 1 to 9, it may even be necessary to add additional corner points before and after the traverse. Then both \a beforeTraverse and \a afterTraverse return the respective corner points. */ void QCPCurve::getTraverseCornerPoints(int prevRegion, int currentRegion, double keyMin, double valueMax, double keyMax, double valueMin, QVector &beforeTraverse, QVector &afterTraverse) const { switch (prevRegion) { case 1: { switch (currentRegion) { case 6: { beforeTraverse << coordsToPixels(keyMin, valueMax); break; } case 9: { beforeTraverse << coordsToPixels(keyMin, valueMax); afterTraverse << coordsToPixels(keyMax, valueMin); break; } case 8: { beforeTraverse << coordsToPixels(keyMin, valueMax); break; } } break; } case 2: { switch (currentRegion) { case 7: { afterTraverse << coordsToPixels(keyMax, valueMax); break; } case 9: { afterTraverse << coordsToPixels(keyMax, valueMin); break; } } break; } case 3: { switch (currentRegion) { case 4: { beforeTraverse << coordsToPixels(keyMin, valueMin); break; } case 7: { beforeTraverse << coordsToPixels(keyMin, valueMin); afterTraverse << coordsToPixels(keyMax, valueMax); break; } case 8: { beforeTraverse << coordsToPixels(keyMin, valueMin); break; } } break; } case 4: { switch (currentRegion) { case 3: { afterTraverse << coordsToPixels(keyMin, valueMin); break; } case 9: { afterTraverse << coordsToPixels(keyMax, valueMin); break; } } break; } case 5: { break; } // shouldn't happen because this method only handles full traverses case 6: { switch (currentRegion) { case 1: { afterTraverse << coordsToPixels(keyMin, valueMax); break; } case 7: { afterTraverse << coordsToPixels(keyMax, valueMax); break; } } break; } case 7: { switch (currentRegion) { case 2: { beforeTraverse << coordsToPixels(keyMax, valueMax); break; } case 3: { beforeTraverse << coordsToPixels(keyMax, valueMax); afterTraverse << coordsToPixels(keyMin, valueMin); break; } case 6: { beforeTraverse << coordsToPixels(keyMax, valueMax); break; } } break; } case 8: { switch (currentRegion) { case 1: { afterTraverse << coordsToPixels(keyMin, valueMax); break; } case 3: { afterTraverse << coordsToPixels(keyMin, valueMin); break; } } break; } case 9: { switch (currentRegion) { case 2: { beforeTraverse << coordsToPixels(keyMax, valueMin); break; } case 1: { beforeTraverse << coordsToPixels(keyMax, valueMin); afterTraverse << coordsToPixels(keyMin, valueMax); break; } case 4: { beforeTraverse << coordsToPixels(keyMax, valueMin); break; } } break; } } } /*! \internal Calculates the (minimum) distance (in pixels) the curve's representation has from the given \a pixelPoint in pixels. This is used to determine whether the curve was clicked or not, e.g. in \ref selectTest. The closest data point to \a pixelPoint is returned in \a closestData. Note that if the curve has a line representation, the returned distance may be smaller than the distance to the \a closestData point, since the distance to the curve line is also taken into account. If either the curve has no data or if the line style is \ref lsNone and the scatter style's shape is \ref QCPScatterStyle::ssNone (i.e. there is no visual representation of the curve), returns -1.0. */ double QCPCurve::pointDistance(const QPointF &pixelPoint, QCPCurveDataContainer::const_iterator &closestData) const { closestData = mDataContainer->constEnd(); if (mDataContainer->isEmpty()) return -1.0; if (mLineStyle == lsNone && mScatterStyle.isNone()) return -1.0; if (mDataContainer->size() == 1) { QPointF dataPoint = coordsToPixels(mDataContainer->constBegin()->key, mDataContainer->constBegin()->value); closestData = mDataContainer->constBegin(); return QCPVector2D(dataPoint-pixelPoint).length(); } // calculate minimum distances to curve data points and find closestData iterator: double minDistSqr = (std::numeric_limits::max)(); // iterate over found data points and then choose the one with the shortest distance to pos: QCPCurveDataContainer::const_iterator begin = mDataContainer->constBegin(); QCPCurveDataContainer::const_iterator end = mDataContainer->constEnd(); for (QCPCurveDataContainer::const_iterator it=begin; it!=end; ++it) { const double currentDistSqr = QCPVector2D(coordsToPixels(it->key, it->value)-pixelPoint).lengthSquared(); if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestData = it; } } // calculate distance to line if there is one (if so, will probably be smaller than distance to closest data point): if (mLineStyle != lsNone) { QVector lines; getCurveLines(&lines, QCPDataRange(0, dataCount()), mParentPlot->selectionTolerance()*1.2); // optimized lines outside axis rect shouldn't respond to clicks at the edge, so use 1.2*tolerance as pen width for (int i=0; i QCPBarsGroup::bars() const Returns all bars currently in this group. \see bars(int index) */ /*! \fn int QCPBarsGroup::size() const Returns the number of QCPBars plottables that are part of this group. */ /*! \fn bool QCPBarsGroup::isEmpty() const Returns whether this bars group is empty. \see size */ /*! \fn bool QCPBarsGroup::contains(QCPBars *bars) Returns whether the specified \a bars plottable is part of this group. */ /* end of documentation of inline functions */ /*! Constructs a new bars group for the specified QCustomPlot instance. */ QCPBarsGroup::QCPBarsGroup(QCustomPlot *parentPlot) : QObject(parentPlot), mParentPlot(parentPlot), mSpacingType(stAbsolute), mSpacing(4) { } QCPBarsGroup::~QCPBarsGroup() { clear(); } /*! Sets how the spacing between adjacent bars is interpreted. See \ref SpacingType. The actual spacing can then be specified with \ref setSpacing. \see setSpacing */ void QCPBarsGroup::setSpacingType(SpacingType spacingType) { mSpacingType = spacingType; } /*! Sets the spacing between adjacent bars. What the number passed as \a spacing actually means, is defined by the current \ref SpacingType, which can be set with \ref setSpacingType. \see setSpacingType */ void QCPBarsGroup::setSpacing(double spacing) { mSpacing = spacing; } /*! Returns the QCPBars instance with the specified \a index in this group. If no such QCPBars exists, returns \c nullptr. \see bars(), size */ QCPBars *QCPBarsGroup::bars(int index) const { if (index >= 0 && index < mBars.size()) { return mBars.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return nullptr; } } /*! Removes all QCPBars plottables from this group. \see isEmpty */ void QCPBarsGroup::clear() { const QList oldBars = mBars; foreach (QCPBars *bars, oldBars) bars->setBarsGroup(nullptr); // removes itself from mBars via removeBars } /*! Adds the specified \a bars plottable to this group. Alternatively, you can also use \ref QCPBars::setBarsGroup on the \a bars instance. \see insert, remove */ void QCPBarsGroup::append(QCPBars *bars) { if (!bars) { qDebug() << Q_FUNC_INFO << "bars is 0"; return; } if (!mBars.contains(bars)) bars->setBarsGroup(this); else qDebug() << Q_FUNC_INFO << "bars plottable is already in this bars group:" << reinterpret_cast(bars); } /*! Inserts the specified \a bars plottable into this group at the specified index position \a i. This gives you full control over the ordering of the bars. \a bars may already be part of this group. In that case, \a bars is just moved to the new index position. \see append, remove */ void QCPBarsGroup::insert(int i, QCPBars *bars) { if (!bars) { qDebug() << Q_FUNC_INFO << "bars is 0"; return; } // first append to bars list normally: if (!mBars.contains(bars)) bars->setBarsGroup(this); // then move to according position: mBars.move(mBars.indexOf(bars), qBound(0, i, mBars.size()-1)); } /*! Removes the specified \a bars plottable from this group. \see contains, clear */ void QCPBarsGroup::remove(QCPBars *bars) { if (!bars) { qDebug() << Q_FUNC_INFO << "bars is 0"; return; } if (mBars.contains(bars)) bars->setBarsGroup(nullptr); else qDebug() << Q_FUNC_INFO << "bars plottable is not in this bars group:" << reinterpret_cast(bars); } /*! \internal Adds the specified \a bars to the internal mBars list of bars. This method does not change the barsGroup property on \a bars. \see unregisterBars */ void QCPBarsGroup::registerBars(QCPBars *bars) { if (!mBars.contains(bars)) mBars.append(bars); } /*! \internal Removes the specified \a bars from the internal mBars list of bars. This method does not change the barsGroup property on \a bars. \see registerBars */ void QCPBarsGroup::unregisterBars(QCPBars *bars) { mBars.removeOne(bars); } /*! \internal Returns the pixel offset in the key dimension the specified \a bars plottable should have at the given key coordinate \a keyCoord. The offset is relative to the pixel position of the key coordinate \a keyCoord. */ double QCPBarsGroup::keyPixelOffset(const QCPBars *bars, double keyCoord) { // find list of all base bars in case some mBars are stacked: QList baseBars; foreach (const QCPBars *b, mBars) { while (b->barBelow()) b = b->barBelow(); if (!baseBars.contains(b)) baseBars.append(b); } // find base bar this "bars" is stacked on: const QCPBars *thisBase = bars; while (thisBase->barBelow()) thisBase = thisBase->barBelow(); // determine key pixel offset of this base bars considering all other base bars in this barsgroup: double result = 0; int index = baseBars.indexOf(thisBase); if (index >= 0) { if (baseBars.size() % 2 == 1 && index == (baseBars.size()-1)/2) // is center bar (int division on purpose) { return result; } else { double lowerPixelWidth, upperPixelWidth; int startIndex; int dir = (index <= (baseBars.size()-1)/2) ? -1 : 1; // if bar is to lower keys of center, dir is negative if (baseBars.size() % 2 == 0) // even number of bars { startIndex = baseBars.size()/2 + (dir < 0 ? -1 : 0); result += getPixelSpacing(baseBars.at(startIndex), keyCoord)*0.5; // half of middle spacing } else // uneven number of bars { startIndex = (baseBars.size()-1)/2+dir; baseBars.at((baseBars.size()-1)/2)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth); result += qAbs(upperPixelWidth-lowerPixelWidth)*0.5; // half of center bar result += getPixelSpacing(baseBars.at((baseBars.size()-1)/2), keyCoord); // center bar spacing } for (int i = startIndex; i != index; i += dir) // add widths and spacings of bars in between center and our bars { baseBars.at(i)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth); result += qAbs(upperPixelWidth-lowerPixelWidth); result += getPixelSpacing(baseBars.at(i), keyCoord); } // finally half of our bars width: baseBars.at(index)->getPixelWidth(keyCoord, lowerPixelWidth, upperPixelWidth); result += qAbs(upperPixelWidth-lowerPixelWidth)*0.5; // correct sign of result depending on orientation and direction of key axis: result *= dir*thisBase->keyAxis()->pixelOrientation(); } } return result; } /*! \internal Returns the spacing in pixels which is between this \a bars and the following one, both at the key coordinate \a keyCoord. \note Typically the returned value doesn't depend on \a bars or \a keyCoord. \a bars is only needed to get access to the key axis transformation and axis rect for the modes \ref stAxisRectRatio and \ref stPlotCoords. The \a keyCoord is only relevant for spacings given in \ref stPlotCoords on a logarithmic axis. */ double QCPBarsGroup::getPixelSpacing(const QCPBars *bars, double keyCoord) { switch (mSpacingType) { case stAbsolute: { return mSpacing; } case stAxisRectRatio: { if (bars->keyAxis()->orientation() == Qt::Horizontal) return bars->keyAxis()->axisRect()->width()*mSpacing; else return bars->keyAxis()->axisRect()->height()*mSpacing; } case stPlotCoords: { double keyPixel = bars->keyAxis()->coordToPixel(keyCoord); return qAbs(bars->keyAxis()->coordToPixel(keyCoord+mSpacing)-keyPixel); } } return 0; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPBarsData //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPBarsData \brief Holds the data of one single data point (one bar) for QCPBars. The stored data is: \li \a key: coordinate on the key axis of this bar (this is the \a mainKey and the \a sortKey) \li \a value: height coordinate on the value axis of this bar (this is the \a mainValue) The container for storing multiple data points is \ref QCPBarsDataContainer. It is a typedef for \ref QCPDataContainer with \ref QCPBarsData as the DataType template parameter. See the documentation there for an explanation regarding the data type's generic methods. \see QCPBarsDataContainer */ /* start documentation of inline functions */ /*! \fn double QCPBarsData::sortKey() const Returns the \a key member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static QCPBarsData QCPBarsData::fromSortKey(double sortKey) Returns a data point with the specified \a sortKey. All other members are set to zero. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static static bool QCPBarsData::sortKeyIsMainKey() Since the member \a key is both the data point key coordinate and the data ordering parameter, this method returns true. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPBarsData::mainKey() const Returns the \a key member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPBarsData::mainValue() const Returns the \a value member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn QCPRange QCPBarsData::valueRange() const Returns a QCPRange with both lower and upper boundary set to \a value of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /* end documentation of inline functions */ /*! Constructs a bar data point with key and value set to zero. */ QCPBarsData::QCPBarsData() : key(0), value(0) { } /*! Constructs a bar data point with the specified \a key and \a value. */ QCPBarsData::QCPBarsData(double key, double value) : key(key), value(value) { } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPBars //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPBars \brief A plottable representing a bar chart in a plot. \image html QCPBars.png To plot data, assign it with the \ref setData or \ref addData functions. \section qcpbars-appearance Changing the appearance The appearance of the bars is determined by the pen and the brush (\ref setPen, \ref setBrush). The width of the individual bars can be controlled with \ref setWidthType and \ref setWidth. Bar charts are stackable. This means, two QCPBars plottables can be placed on top of each other (see \ref QCPBars::moveAbove). So when two bars are at the same key position, they will appear stacked. If you would like to group multiple QCPBars plottables together so they appear side by side as shown below, use QCPBarsGroup. \image html QCPBarsGroup.png \section qcpbars-usage Usage Like all data representing objects in QCustomPlot, the QCPBars is a plottable (QCPAbstractPlottable). So the plottable-interface of QCustomPlot applies (QCustomPlot::plottable, QCustomPlot::removePlottable, etc.) Usually, you first create an instance: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpbars-creation-1 which registers it with the QCustomPlot instance of the passed axes. Note that this QCustomPlot instance takes ownership of the plottable, so do not delete it manually but use QCustomPlot::removePlottable() instead. The newly created plottable can be modified, e.g.: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpbars-creation-2 */ /* start of documentation of inline functions */ /*! \fn QSharedPointer QCPBars::data() const Returns a shared pointer to the internal data storage of type \ref QCPBarsDataContainer. You may use it to directly manipulate the data, which may be more convenient and faster than using the regular \ref setData or \ref addData methods. */ /*! \fn QCPBars *QCPBars::barBelow() const Returns the bars plottable that is directly below this bars plottable. If there is no such plottable, returns \c nullptr. \see barAbove, moveBelow, moveAbove */ /*! \fn QCPBars *QCPBars::barAbove() const Returns the bars plottable that is directly above this bars plottable. If there is no such plottable, returns \c nullptr. \see barBelow, moveBelow, moveAbove */ /* end of documentation of inline functions */ /*! Constructs a bar chart which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The created QCPBars is automatically registered with the QCustomPlot instance inferred from \a keyAxis. This QCustomPlot instance takes ownership of the QCPBars, so do not delete it manually but use QCustomPlot::removePlottable() instead. */ QCPBars::QCPBars(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable1D(keyAxis, valueAxis), mWidth(0.75), mWidthType(wtPlotCoords), mBarsGroup(nullptr), mBaseValue(0), mStackingGap(1) { // modify inherited properties from abstract plottable: mPen.setColor(Qt::blue); mPen.setStyle(Qt::SolidLine); mBrush.setColor(QColor(40, 50, 255, 30)); mBrush.setStyle(Qt::SolidPattern); mSelectionDecorator->setBrush(QBrush(QColor(160, 160, 255))); } QCPBars::~QCPBars() { setBarsGroup(nullptr); if (mBarBelow || mBarAbove) connectBars(mBarBelow.data(), mBarAbove.data()); // take this bar out of any stacking } /*! \overload Replaces the current data container with the provided \a data container. Since a QSharedPointer is used, multiple QCPBars may share the same data container safely. Modifying the data in the container will then affect all bars that share the container. Sharing can be achieved by simply exchanging the data containers wrapped in shared pointers: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpbars-datasharing-1 If you do not wish to share containers, but create a copy from an existing container, rather use the \ref QCPDataContainer::set method on the bar's data container directly: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpbars-datasharing-2 \see addData */ void QCPBars::setData(QSharedPointer data) { mDataContainer = data; } /*! \overload Replaces the current data with the provided points in \a keys and \a values. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. \see addData */ void QCPBars::setData(const QVector &keys, const QVector &values, bool alreadySorted) { mDataContainer->clear(); addData(keys, values, alreadySorted); } /*! Sets the width of the bars. How the number passed as \a width is interpreted (e.g. screen pixels, plot coordinates,...), depends on the currently set width type, see \ref setWidthType and \ref WidthType. */ void QCPBars::setWidth(double width) { mWidth = width; } /*! Sets how the width of the bars is defined. See the documentation of \ref WidthType for an explanation of the possible values for \a widthType. The default value is \ref wtPlotCoords. \see setWidth */ void QCPBars::setWidthType(QCPBars::WidthType widthType) { mWidthType = widthType; } /*! Sets to which QCPBarsGroup this QCPBars instance belongs to. Alternatively, you can also use \ref QCPBarsGroup::append. To remove this QCPBars from any group, set \a barsGroup to \c nullptr. */ void QCPBars::setBarsGroup(QCPBarsGroup *barsGroup) { // deregister at old group: if (mBarsGroup) mBarsGroup->unregisterBars(this); mBarsGroup = barsGroup; // register at new group: if (mBarsGroup) mBarsGroup->registerBars(this); } /*! Sets the base value of this bars plottable. The base value defines where on the value coordinate the bars start. How far the bars extend from the base value is given by their individual value data. For example, if the base value is set to 1, a bar with data value 2 will have its lowest point at value coordinate 1 and highest point at 3. For stacked bars, only the base value of the bottom-most QCPBars has meaning. The default base value is 0. */ void QCPBars::setBaseValue(double baseValue) { mBaseValue = baseValue; } /*! If this bars plottable is stacked on top of another bars plottable (\ref moveAbove), this method allows specifying a distance in \a pixels, by which the drawn bar rectangles will be separated by the bars below it. */ void QCPBars::setStackingGap(double pixels) { mStackingGap = pixels; } /*! \overload Adds the provided points in \a keys and \a values to the current data. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPBars::addData(const QVector &keys, const QVector &values, bool alreadySorted) { if (keys.size() != values.size()) qDebug() << Q_FUNC_INFO << "keys and values have different sizes:" << keys.size() << values.size(); const int n = qMin(keys.size(), values.size()); QVector tempData(n); QVector::iterator it = tempData.begin(); const QVector::iterator itEnd = tempData.end(); int i = 0; while (it != itEnd) { it->key = keys[i]; it->value = values[i]; ++it; ++i; } mDataContainer->add(tempData, alreadySorted); // don't modify tempData beyond this to prevent copy on write } /*! \overload Adds the provided data point as \a key and \a value to the current data. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPBars::addData(double key, double value) { mDataContainer->add(QCPBarsData(key, value)); } /*! Moves this bars plottable below \a bars. In other words, the bars of this plottable will appear below the bars of \a bars. The move target \a bars must use the same key and value axis as this plottable. Inserting into and removing from existing bar stacking is handled gracefully. If \a bars already has a bars object below itself, this bars object is inserted between the two. If this bars object is already between two other bars, the two other bars will be stacked on top of each other after the operation. To remove this bars plottable from any stacking, set \a bars to \c nullptr. \see moveBelow, barAbove, barBelow */ void QCPBars::moveBelow(QCPBars *bars) { if (bars == this) return; if (bars && (bars->keyAxis() != mKeyAxis.data() || bars->valueAxis() != mValueAxis.data())) { qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars"; return; } // remove from stacking: connectBars(mBarBelow.data(), mBarAbove.data()); // Note: also works if one (or both) of them is 0 // if new bar given, insert this bar below it: if (bars) { if (bars->mBarBelow) connectBars(bars->mBarBelow.data(), this); connectBars(this, bars); } } /*! Moves this bars plottable above \a bars. In other words, the bars of this plottable will appear above the bars of \a bars. The move target \a bars must use the same key and value axis as this plottable. Inserting into and removing from existing bar stacking is handled gracefully. If \a bars already has a bars object above itself, this bars object is inserted between the two. If this bars object is already between two other bars, the two other bars will be stacked on top of each other after the operation. To remove this bars plottable from any stacking, set \a bars to \c nullptr. \see moveBelow, barBelow, barAbove */ void QCPBars::moveAbove(QCPBars *bars) { if (bars == this) return; if (bars && (bars->keyAxis() != mKeyAxis.data() || bars->valueAxis() != mValueAxis.data())) { qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars"; return; } // remove from stacking: connectBars(mBarBelow.data(), mBarAbove.data()); // Note: also works if one (or both) of them is 0 // if new bar given, insert this bar above it: if (bars) { if (bars->mBarAbove) connectBars(this, bars->mBarAbove.data()); connectBars(bars, this); } } /*! \copydoc QCPPlottableInterface1D::selectTestRect */ QCPDataSelection QCPBars::selectTestRect(const QRectF &rect, bool onlySelectable) const { QCPDataSelection result; if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return result; if (!mKeyAxis || !mValueAxis) return result; QCPBarsDataContainer::const_iterator visibleBegin, visibleEnd; getVisibleDataBounds(visibleBegin, visibleEnd); for (QCPBarsDataContainer::const_iterator it=visibleBegin; it!=visibleEnd; ++it) { if (rect.intersects(getBarRect(it->key, it->value))) result.addDataRange(QCPDataRange(int(it-mDataContainer->constBegin()), int(it-mDataContainer->constBegin()+1)), false); } result.simplify(); return result; } /*! Implements a selectTest specific to this plottable's point geometry. If \a details is not 0, it will be set to a \ref QCPDataSelection, describing the closest data point to \a pos. \seebaseclassmethod \ref QCPAbstractPlottable::selectTest */ double QCPBars::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return -1; if (!mKeyAxis || !mValueAxis) return -1; if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()) || mParentPlot->interactions().testFlag(QCP::iSelectPlottablesBeyondAxisRect)) { // get visible data range: QCPBarsDataContainer::const_iterator visibleBegin, visibleEnd; getVisibleDataBounds(visibleBegin, visibleEnd); for (QCPBarsDataContainer::const_iterator it=visibleBegin; it!=visibleEnd; ++it) { if (getBarRect(it->key, it->value).contains(pos)) { if (details) { int pointIndex = int(it-mDataContainer->constBegin()); details->setValue(QCPDataSelection(QCPDataRange(pointIndex, pointIndex+1))); } return mParentPlot->selectionTolerance()*0.99; } } } return -1; } /* inherits documentation from base class */ QCPRange QCPBars::getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain) const { /* Note: If this QCPBars uses absolute pixels as width (or is in a QCPBarsGroup with spacing in absolute pixels), using this method to adapt the key axis range to fit the bars into the currently visible axis range will not work perfectly. Because in the moment the axis range is changed to the new range, the fixed pixel widths/spacings will represent different coordinate spans than before, which in turn would require a different key range to perfectly fit, and so on. The only solution would be to iteratively approach the perfect fitting axis range, but the mismatch isn't large enough in most applications, to warrant this here. If a user does need a better fit, he should call the corresponding axis rescale multiple times in a row. */ QCPRange range; range = mDataContainer->keyRange(foundRange, inSignDomain); // determine exact range of bars by including bar width and barsgroup offset: if (foundRange && mKeyAxis) { double lowerPixelWidth, upperPixelWidth, keyPixel; // lower range bound: getPixelWidth(range.lower, lowerPixelWidth, upperPixelWidth); keyPixel = mKeyAxis.data()->coordToPixel(range.lower) + lowerPixelWidth; if (mBarsGroup) keyPixel += mBarsGroup->keyPixelOffset(this, range.lower); const double lowerCorrected = mKeyAxis.data()->pixelToCoord(keyPixel); if (!qIsNaN(lowerCorrected) && qIsFinite(lowerCorrected) && range.lower > lowerCorrected) range.lower = lowerCorrected; // upper range bound: getPixelWidth(range.upper, lowerPixelWidth, upperPixelWidth); keyPixel = mKeyAxis.data()->coordToPixel(range.upper) + upperPixelWidth; if (mBarsGroup) keyPixel += mBarsGroup->keyPixelOffset(this, range.upper); const double upperCorrected = mKeyAxis.data()->pixelToCoord(keyPixel); if (!qIsNaN(upperCorrected) && qIsFinite(upperCorrected) && range.upper < upperCorrected) range.upper = upperCorrected; } return range; } /* inherits documentation from base class */ QCPRange QCPBars::getValueRange(bool &foundRange, QCP::SignDomain inSignDomain, const QCPRange &inKeyRange) const { // Note: can't simply use mDataContainer->valueRange here because we need to // take into account bar base value and possible stacking of multiple bars QCPRange range; range.lower = mBaseValue; range.upper = mBaseValue; bool haveLower = true; // set to true, because baseValue should always be visible in bar charts bool haveUpper = true; // set to true, because baseValue should always be visible in bar charts QCPBarsDataContainer::const_iterator itBegin = mDataContainer->constBegin(); QCPBarsDataContainer::const_iterator itEnd = mDataContainer->constEnd(); if (inKeyRange != QCPRange()) { itBegin = mDataContainer->findBegin(inKeyRange.lower, false); itEnd = mDataContainer->findEnd(inKeyRange.upper, false); } for (QCPBarsDataContainer::const_iterator it = itBegin; it != itEnd; ++it) { const double current = it->value + getStackedBaseValue(it->key, it->value >= 0); if (qIsNaN(current)) continue; if (inSignDomain == QCP::sdBoth || (inSignDomain == QCP::sdNegative && current < 0) || (inSignDomain == QCP::sdPositive && current > 0)) { if (current < range.lower || !haveLower) { range.lower = current; haveLower = true; } if (current > range.upper || !haveUpper) { range.upper = current; haveUpper = true; } } } foundRange = true; // return true because bar charts always have the 0-line visible return range; } /* inherits documentation from base class */ QPointF QCPBars::dataPixelPosition(int index) const { if (index >= 0 && index < mDataContainer->size()) { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return {}; } const QCPDataContainer::const_iterator it = mDataContainer->constBegin()+index; const double valuePixel = valueAxis->coordToPixel(getStackedBaseValue(it->key, it->value >= 0) + it->value); const double keyPixel = keyAxis->coordToPixel(it->key) + (mBarsGroup ? mBarsGroup->keyPixelOffset(this, it->key) : 0); if (keyAxis->orientation() == Qt::Horizontal) return {keyPixel, valuePixel}; else return {valuePixel, keyPixel}; } else { qDebug() << Q_FUNC_INFO << "Index out of bounds" << index; return {}; } } /* inherits documentation from base class */ void QCPBars::draw(QCPPainter *painter) { if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (mDataContainer->isEmpty()) return; QCPBarsDataContainer::const_iterator visibleBegin, visibleEnd; getVisibleDataBounds(visibleBegin, visibleEnd); // loop over and draw segments of unselected/selected data: QList selectedSegments, unselectedSegments, allSegments; getDataSegments(selectedSegments, unselectedSegments); allSegments << unselectedSegments << selectedSegments; for (int i=0; i= unselectedSegments.size(); QCPBarsDataContainer::const_iterator begin = visibleBegin; QCPBarsDataContainer::const_iterator end = visibleEnd; mDataContainer->limitIteratorsToDataRange(begin, end, allSegments.at(i)); if (begin == end) continue; for (QCPBarsDataContainer::const_iterator it=begin; it!=end; ++it) { // check data validity if flag set: #ifdef QCUSTOMPLOT_CHECK_DATA if (QCP::isInvalidData(it->key, it->value)) qDebug() << Q_FUNC_INFO << "Data point at" << it->key << "of drawn range invalid." << "Plottable name:" << name(); #endif // draw bar: if (isSelectedSegment && mSelectionDecorator) { mSelectionDecorator->applyBrush(painter); mSelectionDecorator->applyPen(painter); } else { painter->setBrush(mBrush); painter->setPen(mPen); } applyDefaultAntialiasingHint(painter); painter->drawPolygon(getBarRect(it->key, it->value)); } } // draw other selection decoration that isn't just line/scatter pens and brushes: if (mSelectionDecorator) mSelectionDecorator->drawDecoration(painter, selection()); } /* inherits documentation from base class */ void QCPBars::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const { // draw filled rect: applyDefaultAntialiasingHint(painter); painter->setBrush(mBrush); painter->setPen(mPen); QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67); r.moveCenter(rect.center()); painter->drawRect(r); } /*! \internal called by \ref draw to determine which data (key) range is visible at the current key axis range setting, so only that needs to be processed. It also takes into account the bar width. \a begin returns an iterator to the lowest data point that needs to be taken into account when plotting. Note that in order to get a clean plot all the way to the edge of the axis rect, \a lower may still be just outside the visible range. \a end returns an iterator one higher than the highest visible data point. Same as before, \a end may also lie just outside of the visible range. if the plottable contains no data, both \a begin and \a end point to constEnd. */ void QCPBars::getVisibleDataBounds(QCPBarsDataContainer::const_iterator &begin, QCPBarsDataContainer::const_iterator &end) const { if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; begin = mDataContainer->constEnd(); end = mDataContainer->constEnd(); return; } if (mDataContainer->isEmpty()) { begin = mDataContainer->constEnd(); end = mDataContainer->constEnd(); return; } // get visible data range as QMap iterators begin = mDataContainer->findBegin(mKeyAxis.data()->range().lower); end = mDataContainer->findEnd(mKeyAxis.data()->range().upper); double lowerPixelBound = mKeyAxis.data()->coordToPixel(mKeyAxis.data()->range().lower); double upperPixelBound = mKeyAxis.data()->coordToPixel(mKeyAxis.data()->range().upper); bool isVisible = false; // walk left from begin to find lower bar that actually is completely outside visible pixel range: QCPBarsDataContainer::const_iterator it = begin; while (it != mDataContainer->constBegin()) { --it; const QRectF barRect = getBarRect(it->key, it->value); if (mKeyAxis.data()->orientation() == Qt::Horizontal) isVisible = ((!mKeyAxis.data()->rangeReversed() && barRect.right() >= lowerPixelBound) || (mKeyAxis.data()->rangeReversed() && barRect.left() <= lowerPixelBound)); else // keyaxis is vertical isVisible = ((!mKeyAxis.data()->rangeReversed() && barRect.top() <= lowerPixelBound) || (mKeyAxis.data()->rangeReversed() && barRect.bottom() >= lowerPixelBound)); if (isVisible) begin = it; else break; } // walk right from ubound to find upper bar that actually is completely outside visible pixel range: it = end; while (it != mDataContainer->constEnd()) { const QRectF barRect = getBarRect(it->key, it->value); if (mKeyAxis.data()->orientation() == Qt::Horizontal) isVisible = ((!mKeyAxis.data()->rangeReversed() && barRect.left() <= upperPixelBound) || (mKeyAxis.data()->rangeReversed() && barRect.right() >= upperPixelBound)); else // keyaxis is vertical isVisible = ((!mKeyAxis.data()->rangeReversed() && barRect.bottom() >= upperPixelBound) || (mKeyAxis.data()->rangeReversed() && barRect.top() <= upperPixelBound)); if (isVisible) end = it+1; else break; ++it; } } /*! \internal Returns the rect in pixel coordinates of a single bar with the specified \a key and \a value. The rect is shifted according to the bar stacking (see \ref moveAbove) and base value (see \ref setBaseValue), and to have non-overlapping border lines with the bars stacked below. */ QRectF QCPBars::getBarRect(double key, double value) const { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return {}; } double lowerPixelWidth, upperPixelWidth; getPixelWidth(key, lowerPixelWidth, upperPixelWidth); double base = getStackedBaseValue(key, value >= 0); double basePixel = valueAxis->coordToPixel(base); double valuePixel = valueAxis->coordToPixel(base+value); double keyPixel = keyAxis->coordToPixel(key); if (mBarsGroup) keyPixel += mBarsGroup->keyPixelOffset(this, key); double bottomOffset = (mBarBelow && mPen != Qt::NoPen ? 1 : 0)*(mPen.isCosmetic() ? 1 : mPen.widthF()); bottomOffset += mBarBelow ? mStackingGap : 0; bottomOffset *= (value<0 ? -1 : 1)*valueAxis->pixelOrientation(); if (qAbs(valuePixel-basePixel) <= qAbs(bottomOffset)) bottomOffset = valuePixel-basePixel; if (keyAxis->orientation() == Qt::Horizontal) { return QRectF(QPointF(keyPixel+lowerPixelWidth, valuePixel), QPointF(keyPixel+upperPixelWidth, basePixel+bottomOffset)).normalized(); } else { return QRectF(QPointF(basePixel+bottomOffset, keyPixel+lowerPixelWidth), QPointF(valuePixel, keyPixel+upperPixelWidth)).normalized(); } } /*! \internal This function is used to determine the width of the bar at coordinate \a key, according to the specified width (\ref setWidth) and width type (\ref setWidthType). The output parameters \a lower and \a upper return the number of pixels the bar extends to lower and higher keys, relative to the \a key coordinate (so with a non-reversed horizontal axis, \a lower is negative and \a upper positive). */ void QCPBars::getPixelWidth(double key, double &lower, double &upper) const { lower = 0; upper = 0; switch (mWidthType) { case wtAbsolute: { upper = mWidth*0.5*mKeyAxis.data()->pixelOrientation(); lower = -upper; break; } case wtAxisRectRatio: { if (mKeyAxis && mKeyAxis.data()->axisRect()) { if (mKeyAxis.data()->orientation() == Qt::Horizontal) upper = mKeyAxis.data()->axisRect()->width()*mWidth*0.5*mKeyAxis.data()->pixelOrientation(); else upper = mKeyAxis.data()->axisRect()->height()*mWidth*0.5*mKeyAxis.data()->pixelOrientation(); lower = -upper; } else qDebug() << Q_FUNC_INFO << "No key axis or axis rect defined"; break; } case wtPlotCoords: { if (mKeyAxis) { double keyPixel = mKeyAxis.data()->coordToPixel(key); upper = mKeyAxis.data()->coordToPixel(key+mWidth*0.5)-keyPixel; lower = mKeyAxis.data()->coordToPixel(key-mWidth*0.5)-keyPixel; // no need to qSwap(lower, higher) when range reversed, because higher/lower are gained by // coordinate transform which includes range direction } else qDebug() << Q_FUNC_INFO << "No key axis defined"; break; } } } /*! \internal This function is called to find at which value to start drawing the base of a bar at \a key, when it is stacked on top of another QCPBars (e.g. with \ref moveAbove). positive and negative bars are separated per stack (positive are stacked above baseValue upwards, negative are stacked below baseValue downwards). This can be indicated with \a positive. So if the bar for which we need the base value is negative, set \a positive to false. */ double QCPBars::getStackedBaseValue(double key, bool positive) const { if (mBarBelow) { double max = 0; // don't initialize with mBaseValue here because only base value of bottom-most bar has meaning in a bar stack // find bars of mBarBelow that are approximately at key and find largest one: double epsilon = qAbs(key)*(sizeof(key)==4 ? 1e-6 : 1e-14); // should be safe even when changed to use float at some point if (key == 0) epsilon = (sizeof(key)==4 ? 1e-6 : 1e-14); QCPBarsDataContainer::const_iterator it = mBarBelow.data()->mDataContainer->findBegin(key-epsilon); QCPBarsDataContainer::const_iterator itEnd = mBarBelow.data()->mDataContainer->findEnd(key+epsilon); while (it != itEnd) { if (it->key > key-epsilon && it->key < key+epsilon) { if ((positive && it->value > max) || (!positive && it->value < max)) max = it->value; } ++it; } // recurse down the bar-stack to find the total height: return max + mBarBelow.data()->getStackedBaseValue(key, positive); } else return mBaseValue; } /*! \internal Connects \a below and \a above to each other via their mBarAbove/mBarBelow properties. The bar(s) currently above lower and below upper will become disconnected to lower/upper. If lower is zero, upper will be disconnected at the bottom. If upper is zero, lower will be disconnected at the top. */ void QCPBars::connectBars(QCPBars *lower, QCPBars *upper) { if (!lower && !upper) return; if (!lower) // disconnect upper at bottom { // disconnect old bar below upper: if (upper->mBarBelow && upper->mBarBelow.data()->mBarAbove.data() == upper) upper->mBarBelow.data()->mBarAbove = nullptr; upper->mBarBelow = nullptr; } else if (!upper) // disconnect lower at top { // disconnect old bar above lower: if (lower->mBarAbove && lower->mBarAbove.data()->mBarBelow.data() == lower) lower->mBarAbove.data()->mBarBelow = nullptr; lower->mBarAbove = nullptr; } else // connect lower and upper { // disconnect old bar above lower: if (lower->mBarAbove && lower->mBarAbove.data()->mBarBelow.data() == lower) lower->mBarAbove.data()->mBarBelow = nullptr; // disconnect old bar below upper: if (upper->mBarBelow && upper->mBarBelow.data()->mBarAbove.data() == upper) upper->mBarBelow.data()->mBarAbove = nullptr; lower->mBarAbove = upper; upper->mBarBelow = lower; } } /* end of 'src/plottables/plottable-bars.cpp' */ /* including file 'src/plottables/plottable-statisticalbox.cpp' */ /* modified 2021-03-29T02:30:44, size 28951 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPStatisticalBoxData //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPStatisticalBoxData \brief Holds the data of one single data point for QCPStatisticalBox. The stored data is: \li \a key: coordinate on the key axis of this data point (this is the \a mainKey and the \a sortKey) \li \a minimum: the position of the lower whisker, typically the minimum measurement of the sample that's not considered an outlier. \li \a lowerQuartile: the lower end of the box. The lower and the upper quartiles are the two statistical quartiles around the median of the sample, they should contain 50% of the sample data. \li \a median: the value of the median mark inside the quartile box. The median separates the sample data in half (50% of the sample data is below/above the median). (This is the \a mainValue) \li \a upperQuartile: the upper end of the box. The lower and the upper quartiles are the two statistical quartiles around the median of the sample, they should contain 50% of the sample data. \li \a maximum: the position of the upper whisker, typically the maximum measurement of the sample that's not considered an outlier. \li \a outliers: a QVector of outlier values that will be drawn as scatter points at the \a key coordinate of this data point (see \ref QCPStatisticalBox::setOutlierStyle) The container for storing multiple data points is \ref QCPStatisticalBoxDataContainer. It is a typedef for \ref QCPDataContainer with \ref QCPStatisticalBoxData as the DataType template parameter. See the documentation there for an explanation regarding the data type's generic methods. \see QCPStatisticalBoxDataContainer */ /* start documentation of inline functions */ /*! \fn double QCPStatisticalBoxData::sortKey() const Returns the \a key member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static QCPStatisticalBoxData QCPStatisticalBoxData::fromSortKey(double sortKey) Returns a data point with the specified \a sortKey. All other members are set to zero. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static static bool QCPStatisticalBoxData::sortKeyIsMainKey() Since the member \a key is both the data point key coordinate and the data ordering parameter, this method returns true. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPStatisticalBoxData::mainKey() const Returns the \a key member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPStatisticalBoxData::mainValue() const Returns the \a median member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn QCPRange QCPStatisticalBoxData::valueRange() const Returns a QCPRange spanning from the \a minimum to the \a maximum member of this statistical box data point, possibly further expanded by outliers. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /* end documentation of inline functions */ /*! Constructs a data point with key and all values set to zero. */ QCPStatisticalBoxData::QCPStatisticalBoxData() : key(0), minimum(0), lowerQuartile(0), median(0), upperQuartile(0), maximum(0) { } /*! Constructs a data point with the specified \a key, \a minimum, \a lowerQuartile, \a median, \a upperQuartile, \a maximum and optionally a number of \a outliers. */ QCPStatisticalBoxData::QCPStatisticalBoxData(double key, double minimum, double lowerQuartile, double median, double upperQuartile, double maximum, const QVector &outliers) : key(key), minimum(minimum), lowerQuartile(lowerQuartile), median(median), upperQuartile(upperQuartile), maximum(maximum), outliers(outliers) { } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPStatisticalBox //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPStatisticalBox \brief A plottable representing a single statistical box in a plot. \image html QCPStatisticalBox.png To plot data, assign it with the \ref setData or \ref addData functions. Alternatively, you can also access and modify the data via the \ref data method, which returns a pointer to the internal \ref QCPStatisticalBoxDataContainer. Additionally each data point can itself have a list of outliers, drawn as scatter points at the key coordinate of the respective statistical box data point. They can either be set by using the respective \ref addData(double,double,double,double,double,double,const QVector&) "addData" method or accessing the individual data points through \ref data, and setting the QVector outliers of the data points directly. \section qcpstatisticalbox-appearance Changing the appearance The appearance of each data point box, ranging from the lower to the upper quartile, is controlled via \ref setPen and \ref setBrush. You may change the width of the boxes with \ref setWidth in plot coordinates. Each data point's visual representation also consists of two whiskers. Whiskers are the lines which reach from the upper quartile to the maximum, and from the lower quartile to the minimum. The appearance of the whiskers can be modified with: \ref setWhiskerPen, \ref setWhiskerBarPen, \ref setWhiskerWidth. The whisker width is the width of the bar perpendicular to the whisker at the top (for maximum) and bottom (for minimum). If the whisker pen is changed, make sure to set the \c capStyle to \c Qt::FlatCap. Otherwise the backbone line might exceed the whisker bars by a few pixels due to the pen cap being not perfectly flat. The median indicator line inside the box has its own pen, \ref setMedianPen. The outlier data points are drawn as normal scatter points. Their look can be controlled with \ref setOutlierStyle \section qcpstatisticalbox-usage Usage Like all data representing objects in QCustomPlot, the QCPStatisticalBox is a plottable (QCPAbstractPlottable). So the plottable-interface of QCustomPlot applies (QCustomPlot::plottable, QCustomPlot::removePlottable, etc.) Usually, you first create an instance: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpstatisticalbox-creation-1 which registers it with the QCustomPlot instance of the passed axes. Note that this QCustomPlot instance takes ownership of the plottable, so do not delete it manually but use QCustomPlot::removePlottable() instead. The newly created plottable can be modified, e.g.: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpstatisticalbox-creation-2 */ /* start documentation of inline functions */ /*! \fn QSharedPointer QCPStatisticalBox::data() const Returns a shared pointer to the internal data storage of type \ref QCPStatisticalBoxDataContainer. You may use it to directly manipulate the data, which may be more convenient and faster than using the regular \ref setData or \ref addData methods. */ /* end documentation of inline functions */ /*! Constructs a statistical box which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The created QCPStatisticalBox is automatically registered with the QCustomPlot instance inferred from \a keyAxis. This QCustomPlot instance takes ownership of the QCPStatisticalBox, so do not delete it manually but use QCustomPlot::removePlottable() instead. */ QCPStatisticalBox::QCPStatisticalBox(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable1D(keyAxis, valueAxis), mWidth(0.5), mWhiskerWidth(0.2), mWhiskerPen(Qt::black, 0, Qt::DashLine, Qt::FlatCap), mWhiskerBarPen(Qt::black), mWhiskerAntialiased(false), mMedianPen(Qt::black, 3, Qt::SolidLine, Qt::FlatCap), mOutlierStyle(QCPScatterStyle::ssCircle, Qt::blue, 6) { setPen(QPen(Qt::black)); setBrush(Qt::NoBrush); } /*! \overload Replaces the current data container with the provided \a data container. Since a QSharedPointer is used, multiple QCPStatisticalBoxes may share the same data container safely. Modifying the data in the container will then affect all statistical boxes that share the container. Sharing can be achieved by simply exchanging the data containers wrapped in shared pointers: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpstatisticalbox-datasharing-1 If you do not wish to share containers, but create a copy from an existing container, rather use the \ref QCPDataContainer::set method on the statistical box data container directly: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpstatisticalbox-datasharing-2 \see addData */ void QCPStatisticalBox::setData(QSharedPointer data) { mDataContainer = data; } /*! \overload Replaces the current data with the provided points in \a keys, \a minimum, \a lowerQuartile, \a median, \a upperQuartile and \a maximum. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. \see addData */ void QCPStatisticalBox::setData(const QVector &keys, const QVector &minimum, const QVector &lowerQuartile, const QVector &median, const QVector &upperQuartile, const QVector &maximum, bool alreadySorted) { mDataContainer->clear(); addData(keys, minimum, lowerQuartile, median, upperQuartile, maximum, alreadySorted); } /*! Sets the width of the boxes in key coordinates. \see setWhiskerWidth */ void QCPStatisticalBox::setWidth(double width) { mWidth = width; } /*! Sets the width of the whiskers in key coordinates. Whiskers are the lines which reach from the upper quartile to the maximum, and from the lower quartile to the minimum. \see setWidth */ void QCPStatisticalBox::setWhiskerWidth(double width) { mWhiskerWidth = width; } /*! Sets the pen used for drawing the whisker backbone. Whiskers are the lines which reach from the upper quartile to the maximum, and from the lower quartile to the minimum. Make sure to set the \c capStyle of the passed \a pen to \c Qt::FlatCap. Otherwise the backbone line might exceed the whisker bars by a few pixels due to the pen cap being not perfectly flat. \see setWhiskerBarPen */ void QCPStatisticalBox::setWhiskerPen(const QPen &pen) { mWhiskerPen = pen; } /*! Sets the pen used for drawing the whisker bars. Those are the lines parallel to the key axis at each end of the whisker backbone. Whiskers are the lines which reach from the upper quartile to the maximum, and from the lower quartile to the minimum. \see setWhiskerPen */ void QCPStatisticalBox::setWhiskerBarPen(const QPen &pen) { mWhiskerBarPen = pen; } /*! Sets whether the statistical boxes whiskers are drawn with antialiasing or not. Note that antialiasing settings may be overridden by QCustomPlot::setAntialiasedElements and QCustomPlot::setNotAntialiasedElements. */ void QCPStatisticalBox::setWhiskerAntialiased(bool enabled) { mWhiskerAntialiased = enabled; } /*! Sets the pen used for drawing the median indicator line inside the statistical boxes. */ void QCPStatisticalBox::setMedianPen(const QPen &pen) { mMedianPen = pen; } /*! Sets the appearance of the outlier data points. Outliers can be specified with the method \ref addData(double key, double minimum, double lowerQuartile, double median, double upperQuartile, double maximum, const QVector &outliers) */ void QCPStatisticalBox::setOutlierStyle(const QCPScatterStyle &style) { mOutlierStyle = style; } /*! \overload Adds the provided points in \a keys, \a minimum, \a lowerQuartile, \a median, \a upperQuartile and \a maximum to the current data. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPStatisticalBox::addData(const QVector &keys, const QVector &minimum, const QVector &lowerQuartile, const QVector &median, const QVector &upperQuartile, const QVector &maximum, bool alreadySorted) { if (keys.size() != minimum.size() || minimum.size() != lowerQuartile.size() || lowerQuartile.size() != median.size() || median.size() != upperQuartile.size() || upperQuartile.size() != maximum.size() || maximum.size() != keys.size()) qDebug() << Q_FUNC_INFO << "keys, minimum, lowerQuartile, median, upperQuartile, maximum have different sizes:" << keys.size() << minimum.size() << lowerQuartile.size() << median.size() << upperQuartile.size() << maximum.size(); const int n = qMin(keys.size(), qMin(minimum.size(), qMin(lowerQuartile.size(), qMin(median.size(), qMin(upperQuartile.size(), maximum.size()))))); QVector tempData(n); QVector::iterator it = tempData.begin(); const QVector::iterator itEnd = tempData.end(); int i = 0; while (it != itEnd) { it->key = keys[i]; it->minimum = minimum[i]; it->lowerQuartile = lowerQuartile[i]; it->median = median[i]; it->upperQuartile = upperQuartile[i]; it->maximum = maximum[i]; ++it; ++i; } mDataContainer->add(tempData, alreadySorted); // don't modify tempData beyond this to prevent copy on write } /*! \overload Adds the provided data point as \a key, \a minimum, \a lowerQuartile, \a median, \a upperQuartile and \a maximum to the current data. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. */ void QCPStatisticalBox::addData(double key, double minimum, double lowerQuartile, double median, double upperQuartile, double maximum, const QVector &outliers) { mDataContainer->add(QCPStatisticalBoxData(key, minimum, lowerQuartile, median, upperQuartile, maximum, outliers)); } /*! \copydoc QCPPlottableInterface1D::selectTestRect */ QCPDataSelection QCPStatisticalBox::selectTestRect(const QRectF &rect, bool onlySelectable) const { QCPDataSelection result; if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return result; if (!mKeyAxis || !mValueAxis) return result; QCPStatisticalBoxDataContainer::const_iterator visibleBegin, visibleEnd; getVisibleDataBounds(visibleBegin, visibleEnd); for (QCPStatisticalBoxDataContainer::const_iterator it=visibleBegin; it!=visibleEnd; ++it) { if (rect.intersects(getQuartileBox(it))) result.addDataRange(QCPDataRange(int(it-mDataContainer->constBegin()), int(it-mDataContainer->constBegin()+1)), false); } result.simplify(); return result; } /*! Implements a selectTest specific to this plottable's point geometry. If \a details is not 0, it will be set to a \ref QCPDataSelection, describing the closest data point to \a pos. \seebaseclassmethod \ref QCPAbstractPlottable::selectTest */ double QCPStatisticalBox::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return -1; if (!mKeyAxis || !mValueAxis) return -1; if (mKeyAxis->axisRect()->rect().contains(pos.toPoint()) || mParentPlot->interactions().testFlag(QCP::iSelectPlottablesBeyondAxisRect)) { // get visible data range: QCPStatisticalBoxDataContainer::const_iterator visibleBegin, visibleEnd; QCPStatisticalBoxDataContainer::const_iterator closestDataPoint = mDataContainer->constEnd(); getVisibleDataBounds(visibleBegin, visibleEnd); double minDistSqr = (std::numeric_limits::max)(); for (QCPStatisticalBoxDataContainer::const_iterator it=visibleBegin; it!=visibleEnd; ++it) { if (getQuartileBox(it).contains(pos)) // quartile box { double currentDistSqr = mParentPlot->selectionTolerance()*0.99 * mParentPlot->selectionTolerance()*0.99; if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestDataPoint = it; } } else // whiskers { const QVector whiskerBackbones = getWhiskerBackboneLines(it); const QCPVector2D posVec(pos); foreach (const QLineF &backbone, whiskerBackbones) { double currentDistSqr = posVec.distanceSquaredToLine(backbone); if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestDataPoint = it; } } } } if (details) { int pointIndex = int(closestDataPoint-mDataContainer->constBegin()); details->setValue(QCPDataSelection(QCPDataRange(pointIndex, pointIndex+1))); } return qSqrt(minDistSqr); } return -1; } /* inherits documentation from base class */ QCPRange QCPStatisticalBox::getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain) const { QCPRange range = mDataContainer->keyRange(foundRange, inSignDomain); // determine exact range by including width of bars/flags: if (foundRange) { if (inSignDomain != QCP::sdPositive || range.lower-mWidth*0.5 > 0) range.lower -= mWidth*0.5; if (inSignDomain != QCP::sdNegative || range.upper+mWidth*0.5 < 0) range.upper += mWidth*0.5; } return range; } /* inherits documentation from base class */ QCPRange QCPStatisticalBox::getValueRange(bool &foundRange, QCP::SignDomain inSignDomain, const QCPRange &inKeyRange) const { return mDataContainer->valueRange(foundRange, inSignDomain, inKeyRange); } /* inherits documentation from base class */ void QCPStatisticalBox::draw(QCPPainter *painter) { if (mDataContainer->isEmpty()) return; QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } QCPStatisticalBoxDataContainer::const_iterator visibleBegin, visibleEnd; getVisibleDataBounds(visibleBegin, visibleEnd); // loop over and draw segments of unselected/selected data: QList selectedSegments, unselectedSegments, allSegments; getDataSegments(selectedSegments, unselectedSegments); allSegments << unselectedSegments << selectedSegments; for (int i=0; i= unselectedSegments.size(); QCPStatisticalBoxDataContainer::const_iterator begin = visibleBegin; QCPStatisticalBoxDataContainer::const_iterator end = visibleEnd; mDataContainer->limitIteratorsToDataRange(begin, end, allSegments.at(i)); if (begin == end) continue; for (QCPStatisticalBoxDataContainer::const_iterator it=begin; it!=end; ++it) { // check data validity if flag set: # ifdef QCUSTOMPLOT_CHECK_DATA if (QCP::isInvalidData(it->key, it->minimum) || QCP::isInvalidData(it->lowerQuartile, it->median) || QCP::isInvalidData(it->upperQuartile, it->maximum)) qDebug() << Q_FUNC_INFO << "Data point at" << it->key << "of drawn range has invalid data." << "Plottable name:" << name(); for (int i=0; ioutliers.size(); ++i) if (QCP::isInvalidData(it->outliers.at(i))) qDebug() << Q_FUNC_INFO << "Data point outlier at" << it->key << "of drawn range invalid." << "Plottable name:" << name(); # endif if (isSelectedSegment && mSelectionDecorator) { mSelectionDecorator->applyPen(painter); mSelectionDecorator->applyBrush(painter); } else { painter->setPen(mPen); painter->setBrush(mBrush); } QCPScatterStyle finalOutlierStyle = mOutlierStyle; if (isSelectedSegment && mSelectionDecorator) finalOutlierStyle = mSelectionDecorator->getFinalScatterStyle(mOutlierStyle); drawStatisticalBox(painter, it, finalOutlierStyle); } } // draw other selection decoration that isn't just line/scatter pens and brushes: if (mSelectionDecorator) mSelectionDecorator->drawDecoration(painter, selection()); } /* inherits documentation from base class */ void QCPStatisticalBox::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const { // draw filled rect: applyDefaultAntialiasingHint(painter); painter->setPen(mPen); painter->setBrush(mBrush); QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67); r.moveCenter(rect.center()); painter->drawRect(r); } /*! Draws the graphical representation of a single statistical box with the data given by the iterator \a it with the provided \a painter. If the statistical box has a set of outlier data points, they are drawn with \a outlierStyle. \see getQuartileBox, getWhiskerBackboneLines, getWhiskerBarLines */ void QCPStatisticalBox::drawStatisticalBox(QCPPainter *painter, QCPStatisticalBoxDataContainer::const_iterator it, const QCPScatterStyle &outlierStyle) const { // draw quartile box: applyDefaultAntialiasingHint(painter); const QRectF quartileBox = getQuartileBox(it); painter->drawRect(quartileBox); // draw median line with cliprect set to quartile box: painter->save(); painter->setClipRect(quartileBox, Qt::IntersectClip); painter->setPen(mMedianPen); painter->drawLine(QLineF(coordsToPixels(it->key-mWidth*0.5, it->median), coordsToPixels(it->key+mWidth*0.5, it->median))); painter->restore(); // draw whisker lines: applyAntialiasingHint(painter, mWhiskerAntialiased, QCP::aePlottables); painter->setPen(mWhiskerPen); painter->drawLines(getWhiskerBackboneLines(it)); painter->setPen(mWhiskerBarPen); painter->drawLines(getWhiskerBarLines(it)); // draw outliers: applyScattersAntialiasingHint(painter); outlierStyle.applyTo(painter, mPen); for (int i=0; ioutliers.size(); ++i) outlierStyle.drawShape(painter, coordsToPixels(it->key, it->outliers.at(i))); } /*! \internal called by \ref draw to determine which data (key) range is visible at the current key axis range setting, so only that needs to be processed. It also takes into account the bar width. \a begin returns an iterator to the lowest data point that needs to be taken into account when plotting. Note that in order to get a clean plot all the way to the edge of the axis rect, \a lower may still be just outside the visible range. \a end returns an iterator one higher than the highest visible data point. Same as before, \a end may also lie just outside of the visible range. if the plottable contains no data, both \a begin and \a end point to constEnd. */ void QCPStatisticalBox::getVisibleDataBounds(QCPStatisticalBoxDataContainer::const_iterator &begin, QCPStatisticalBoxDataContainer::const_iterator &end) const { if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; begin = mDataContainer->constEnd(); end = mDataContainer->constEnd(); return; } begin = mDataContainer->findBegin(mKeyAxis.data()->range().lower-mWidth*0.5); // subtract half width of box to include partially visible data points end = mDataContainer->findEnd(mKeyAxis.data()->range().upper+mWidth*0.5); // add half width of box to include partially visible data points } /*! \internal Returns the box in plot coordinates (keys in x, values in y of the returned rect) that covers the value range from the lower to the upper quartile, of the data given by \a it. \see drawStatisticalBox, getWhiskerBackboneLines, getWhiskerBarLines */ QRectF QCPStatisticalBox::getQuartileBox(QCPStatisticalBoxDataContainer::const_iterator it) const { QRectF result; result.setTopLeft(coordsToPixels(it->key-mWidth*0.5, it->upperQuartile)); result.setBottomRight(coordsToPixels(it->key+mWidth*0.5, it->lowerQuartile)); return result; } /*! \internal Returns the whisker backbones (keys in x, values in y of the returned lines) that cover the value range from the minimum to the lower quartile, and from the upper quartile to the maximum of the data given by \a it. \see drawStatisticalBox, getQuartileBox, getWhiskerBarLines */ QVector QCPStatisticalBox::getWhiskerBackboneLines(QCPStatisticalBoxDataContainer::const_iterator it) const { QVector result(2); result[0].setPoints(coordsToPixels(it->key, it->lowerQuartile), coordsToPixels(it->key, it->minimum)); // min backbone result[1].setPoints(coordsToPixels(it->key, it->upperQuartile), coordsToPixels(it->key, it->maximum)); // max backbone return result; } /*! \internal Returns the whisker bars (keys in x, values in y of the returned lines) that are placed at the end of the whisker backbones, at the minimum and maximum of the data given by \a it. \see drawStatisticalBox, getQuartileBox, getWhiskerBackboneLines */ QVector QCPStatisticalBox::getWhiskerBarLines(QCPStatisticalBoxDataContainer::const_iterator it) const { QVector result(2); result[0].setPoints(coordsToPixels(it->key-mWhiskerWidth*0.5, it->minimum), coordsToPixels(it->key+mWhiskerWidth*0.5, it->minimum)); // min bar result[1].setPoints(coordsToPixels(it->key-mWhiskerWidth*0.5, it->maximum), coordsToPixels(it->key+mWhiskerWidth*0.5, it->maximum)); // max bar return result; } /* end of 'src/plottables/plottable-statisticalbox.cpp' */ /* including file 'src/plottables/plottable-colormap.cpp' */ /* modified 2021-03-29T02:30:44, size 48149 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPColorMapData //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPColorMapData \brief Holds the two-dimensional data of a QCPColorMap plottable. This class is a data storage for \ref QCPColorMap. It holds a two-dimensional array, which \ref QCPColorMap then displays as a 2D image in the plot, where the array values are represented by a color, depending on the value. The size of the array can be controlled via \ref setSize (or \ref setKeySize, \ref setValueSize). Which plot coordinates these cells correspond to can be configured with \ref setRange (or \ref setKeyRange, \ref setValueRange). The data cells can be accessed in two ways: They can be directly addressed by an integer index with \ref setCell. This is the fastest method. Alternatively, they can be addressed by their plot coordinate with \ref setData. plot coordinate to cell index transformations and vice versa are provided by the functions \ref coordToCell and \ref cellToCoord. A \ref QCPColorMapData also holds an on-demand two-dimensional array of alpha values which (if allocated) has the same size as the data map. It can be accessed via \ref setAlpha, \ref fillAlpha and \ref clearAlpha. The memory for the alpha map is only allocated if needed, i.e. on the first call of \ref setAlpha. \ref clearAlpha restores full opacity and frees the alpha map. This class also buffers the minimum and maximum values that are in the data set, to provide QCPColorMap::rescaleDataRange with the necessary information quickly. Setting a cell to a value that is greater than the current maximum increases this maximum to the new value. However, setting the cell that currently holds the maximum value to a smaller value doesn't decrease the maximum again, because finding the true new maximum would require going through the entire data array, which might be time consuming. The same holds for the data minimum. This functionality is given by \ref recalculateDataBounds, such that you can decide when it is sensible to find the true current minimum and maximum. The method QCPColorMap::rescaleDataRange offers a convenience parameter \a recalculateDataBounds which may be set to true to automatically call \ref recalculateDataBounds internally. */ /* start of documentation of inline functions */ /*! \fn bool QCPColorMapData::isEmpty() const Returns whether this instance carries no data. This is equivalent to having a size where at least one of the dimensions is 0 (see \ref setSize). */ /* end of documentation of inline functions */ /*! Constructs a new QCPColorMapData instance. The instance has \a keySize cells in the key direction and \a valueSize cells in the value direction. These cells will be displayed by the \ref QCPColorMap at the coordinates \a keyRange and \a valueRange. \see setSize, setKeySize, setValueSize, setRange, setKeyRange, setValueRange */ QCPColorMapData::QCPColorMapData(int keySize, int valueSize, const QCPRange &keyRange, const QCPRange &valueRange) : mKeySize(0), mValueSize(0), mKeyRange(keyRange), mValueRange(valueRange), mIsEmpty(true), mData(nullptr), mAlpha(nullptr), mDataModified(true) { setSize(keySize, valueSize); fill(0); } QCPColorMapData::~QCPColorMapData() { delete[] mData; delete[] mAlpha; } /*! Constructs a new QCPColorMapData instance copying the data and range of \a other. */ QCPColorMapData::QCPColorMapData(const QCPColorMapData &other) : mKeySize(0), mValueSize(0), mIsEmpty(true), mData(nullptr), mAlpha(nullptr), mDataModified(true) { *this = other; } /*! Overwrites this color map data instance with the data stored in \a other. The alpha map state is transferred, too. */ QCPColorMapData &QCPColorMapData::operator=(const QCPColorMapData &other) { if (&other != this) { const int keySize = other.keySize(); const int valueSize = other.valueSize(); if (!other.mAlpha && mAlpha) clearAlpha(); setSize(keySize, valueSize); if (other.mAlpha && !mAlpha) createAlpha(false); setRange(other.keyRange(), other.valueRange()); if (!isEmpty()) { memcpy(mData, other.mData, sizeof(mData[0])*size_t(keySize*valueSize)); if (mAlpha) memcpy(mAlpha, other.mAlpha, sizeof(mAlpha[0])*size_t(keySize*valueSize)); } mDataBounds = other.mDataBounds; mDataModified = true; } return *this; } /* undocumented getter */ double QCPColorMapData::data(double key, double value) { int keyCell = int( (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5 ); int valueCell = int( (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5 ); if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize) return mData[valueCell*mKeySize + keyCell]; else return 0; } /* undocumented getter */ double QCPColorMapData::cell(int keyIndex, int valueIndex) { if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize) return mData[valueIndex*mKeySize + keyIndex]; else return 0; } /*! Returns the alpha map value of the cell with the indices \a keyIndex and \a valueIndex. If this color map data doesn't have an alpha map (because \ref setAlpha was never called after creation or after a call to \ref clearAlpha), returns 255, which corresponds to full opacity. \see setAlpha */ unsigned char QCPColorMapData::alpha(int keyIndex, int valueIndex) { if (mAlpha && keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize) return mAlpha[valueIndex*mKeySize + keyIndex]; else return 255; } /*! Resizes the data array to have \a keySize cells in the key dimension and \a valueSize cells in the value dimension. The current data is discarded and the map cells are set to 0, unless the map had already the requested size. Setting at least one of \a keySize or \a valueSize to zero frees the internal data array and \ref isEmpty returns true. \see setRange, setKeySize, setValueSize */ void QCPColorMapData::setSize(int keySize, int valueSize) { if (keySize != mKeySize || valueSize != mValueSize) { mKeySize = keySize; mValueSize = valueSize; delete[] mData; mIsEmpty = mKeySize == 0 || mValueSize == 0; if (!mIsEmpty) { #ifdef __EXCEPTIONS try { // 2D arrays get memory intensive fast. So if the allocation fails, at least output debug message #endif mData = new double[size_t(mKeySize*mValueSize)]; #ifdef __EXCEPTIONS } catch (...) { mData = nullptr; } #endif if (mData) fill(0); else qDebug() << Q_FUNC_INFO << "out of memory for data dimensions "<< mKeySize << "*" << mValueSize; } else mData = nullptr; if (mAlpha) // if we had an alpha map, recreate it with new size createAlpha(); mDataModified = true; } } /*! Resizes the data array to have \a keySize cells in the key dimension. The current data is discarded and the map cells are set to 0, unless the map had already the requested size. Setting \a keySize to zero frees the internal data array and \ref isEmpty returns true. \see setKeyRange, setSize, setValueSize */ void QCPColorMapData::setKeySize(int keySize) { setSize(keySize, mValueSize); } /*! Resizes the data array to have \a valueSize cells in the value dimension. The current data is discarded and the map cells are set to 0, unless the map had already the requested size. Setting \a valueSize to zero frees the internal data array and \ref isEmpty returns true. \see setValueRange, setSize, setKeySize */ void QCPColorMapData::setValueSize(int valueSize) { setSize(mKeySize, valueSize); } /*! Sets the coordinate ranges the data shall be distributed over. This defines the rectangular area covered by the color map in plot coordinates. The outer cells will be centered on the range boundaries given to this function. For example, if the key size (\ref setKeySize) is 3 and \a keyRange is set to QCPRange(2, 3) there will be cells centered on the key coordinates 2, 2.5 and 3. \see setSize */ void QCPColorMapData::setRange(const QCPRange &keyRange, const QCPRange &valueRange) { setKeyRange(keyRange); setValueRange(valueRange); } /*! Sets the coordinate range the data shall be distributed over in the key dimension. Together with the value range, This defines the rectangular area covered by the color map in plot coordinates. The outer cells will be centered on the range boundaries given to this function. For example, if the key size (\ref setKeySize) is 3 and \a keyRange is set to QCPRange(2, 3) there will be cells centered on the key coordinates 2, 2.5 and 3. \see setRange, setValueRange, setSize */ void QCPColorMapData::setKeyRange(const QCPRange &keyRange) { mKeyRange = keyRange; } /*! Sets the coordinate range the data shall be distributed over in the value dimension. Together with the key range, This defines the rectangular area covered by the color map in plot coordinates. The outer cells will be centered on the range boundaries given to this function. For example, if the value size (\ref setValueSize) is 3 and \a valueRange is set to QCPRange(2, 3) there will be cells centered on the value coordinates 2, 2.5 and 3. \see setRange, setKeyRange, setSize */ void QCPColorMapData::setValueRange(const QCPRange &valueRange) { mValueRange = valueRange; } /*! Sets the data of the cell, which lies at the plot coordinates given by \a key and \a value, to \a z. \note The QCPColorMap always displays the data at equal key/value intervals, even if the key or value axis is set to a logarithmic scaling. If you want to use QCPColorMap with logarithmic axes, you shouldn't use the \ref QCPColorMapData::setData method as it uses a linear transformation to determine the cell index. Rather directly access the cell index with \ref QCPColorMapData::setCell. \see setCell, setRange */ void QCPColorMapData::setData(double key, double value, double z) { int keyCell = int( (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5 ); int valueCell = int( (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5 ); if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize) { mData[valueCell*mKeySize + keyCell] = z; if (z < mDataBounds.lower) mDataBounds.lower = z; if (z > mDataBounds.upper) mDataBounds.upper = z; mDataModified = true; } } /*! Sets the data of the cell with indices \a keyIndex and \a valueIndex to \a z. The indices enumerate the cells starting from zero, up to the map's size-1 in the respective dimension (see \ref setSize). In the standard plot configuration (horizontal key axis and vertical value axis, both not range-reversed), the cell with indices (0, 0) is in the bottom left corner and the cell with indices (keySize-1, valueSize-1) is in the top right corner of the color map. \see setData, setSize */ void QCPColorMapData::setCell(int keyIndex, int valueIndex, double z) { if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize) { mData[valueIndex*mKeySize + keyIndex] = z; if (z < mDataBounds.lower) mDataBounds.lower = z; if (z > mDataBounds.upper) mDataBounds.upper = z; mDataModified = true; } else qDebug() << Q_FUNC_INFO << "index out of bounds:" << keyIndex << valueIndex; } /*! Sets the alpha of the color map cell given by \a keyIndex and \a valueIndex to \a alpha. A value of 0 for \a alpha results in a fully transparent cell, and a value of 255 results in a fully opaque cell. If an alpha map doesn't exist yet for this color map data, it will be created here. If you wish to restore full opacity and free any allocated memory of the alpha map, call \ref clearAlpha. Note that the cell-wise alpha which can be configured here is independent of any alpha configured in the color map's gradient (\ref QCPColorGradient). If a cell is affected both by the cell-wise and gradient alpha, the alpha values will be blended accordingly during rendering of the color map. \see fillAlpha, clearAlpha */ void QCPColorMapData::setAlpha(int keyIndex, int valueIndex, unsigned char alpha) { if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize) { if (mAlpha || createAlpha()) { mAlpha[valueIndex*mKeySize + keyIndex] = alpha; mDataModified = true; } } else qDebug() << Q_FUNC_INFO << "index out of bounds:" << keyIndex << valueIndex; } /*! Goes through the data and updates the buffered minimum and maximum data values. Calling this method is only advised if you are about to call \ref QCPColorMap::rescaleDataRange and can not guarantee that the cells holding the maximum or minimum data haven't been overwritten with a smaller or larger value respectively, since the buffered maximum/minimum values have been updated the last time. Why this is the case is explained in the class description (\ref QCPColorMapData). Note that the method \ref QCPColorMap::rescaleDataRange provides a parameter \a recalculateDataBounds for convenience. Setting this to true will call this method for you, before doing the rescale. */ void QCPColorMapData::recalculateDataBounds() { if (mKeySize > 0 && mValueSize > 0) { double minHeight = mData[0]; double maxHeight = mData[0]; const int dataCount = mValueSize*mKeySize; for (int i=0; i maxHeight) maxHeight = mData[i]; if (mData[i] < minHeight) minHeight = mData[i]; } mDataBounds.lower = minHeight; mDataBounds.upper = maxHeight; } } /*! Frees the internal data memory. This is equivalent to calling \ref setSize "setSize(0, 0)". */ void QCPColorMapData::clear() { setSize(0, 0); } /*! Frees the internal alpha map. The color map will have full opacity again. */ void QCPColorMapData::clearAlpha() { if (mAlpha) { delete[] mAlpha; mAlpha = nullptr; mDataModified = true; } } /*! Sets all cells to the value \a z. */ void QCPColorMapData::fill(double z) { const int dataCount = mValueSize*mKeySize; for (int i=0; i(data); return; } if (copy) { *mMapData = *data; } else { delete mMapData; mMapData = data; } mMapImageInvalidated = true; } /*! Sets the data range of this color map to \a dataRange. The data range defines which data values are mapped to the color gradient. To make the data range span the full range of the data set, use \ref rescaleDataRange. \see QCPColorScale::setDataRange */ void QCPColorMap::setDataRange(const QCPRange &dataRange) { if (!QCPRange::validRange(dataRange)) return; if (mDataRange.lower != dataRange.lower || mDataRange.upper != dataRange.upper) { if (mDataScaleType == QCPAxis::stLogarithmic) mDataRange = dataRange.sanitizedForLogScale(); else mDataRange = dataRange.sanitizedForLinScale(); mMapImageInvalidated = true; emit dataRangeChanged(mDataRange); } } /*! Sets whether the data is correlated with the color gradient linearly or logarithmically. \see QCPColorScale::setDataScaleType */ void QCPColorMap::setDataScaleType(QCPAxis::ScaleType scaleType) { if (mDataScaleType != scaleType) { mDataScaleType = scaleType; mMapImageInvalidated = true; emit dataScaleTypeChanged(mDataScaleType); if (mDataScaleType == QCPAxis::stLogarithmic) setDataRange(mDataRange.sanitizedForLogScale()); } } /*! Sets the color gradient that is used to represent the data. For more details on how to create an own gradient or use one of the preset gradients, see \ref QCPColorGradient. The colors defined by the gradient will be used to represent data values in the currently set data range, see \ref setDataRange. Data points that are outside this data range will either be colored uniformly with the respective gradient boundary color, or the gradient will repeat, depending on \ref QCPColorGradient::setPeriodic. \see QCPColorScale::setGradient */ void QCPColorMap::setGradient(const QCPColorGradient &gradient) { if (mGradient != gradient) { mGradient = gradient; mMapImageInvalidated = true; emit gradientChanged(mGradient); } } /*! Sets whether the color map image shall use bicubic interpolation when displaying the color map shrinked or expanded, and not at a 1:1 pixel-to-data scale. \image html QCPColorMap-interpolate.png "A 10*10 color map, with interpolation and without interpolation enabled" */ void QCPColorMap::setInterpolate(bool enabled) { mInterpolate = enabled; mMapImageInvalidated = true; // because oversampling factors might need to change } /*! Sets whether the outer most data rows and columns are clipped to the specified key and value range (see \ref QCPColorMapData::setKeyRange, \ref QCPColorMapData::setValueRange). if \a enabled is set to false, the data points at the border of the color map are drawn with the same width and height as all other data points. Since the data points are represented by rectangles of one color centered on the data coordinate, this means that the shown color map extends by half a data point over the specified key/value range in each direction. \image html QCPColorMap-tightboundary.png "A color map, with tight boundary enabled and disabled" */ void QCPColorMap::setTightBoundary(bool enabled) { mTightBoundary = enabled; } /*! Associates the color scale \a colorScale with this color map. This means that both the color scale and the color map synchronize their gradient, data range and data scale type (\ref setGradient, \ref setDataRange, \ref setDataScaleType). Multiple color maps can be associated with one single color scale. This causes the color maps to also synchronize those properties, via the mutual color scale. This function causes the color map to adopt the current color gradient, data range and data scale type of \a colorScale. After this call, you may change these properties at either the color map or the color scale, and the setting will be applied to both. Pass \c nullptr as \a colorScale to disconnect the color scale from this color map again. */ void QCPColorMap::setColorScale(QCPColorScale *colorScale) { if (mColorScale) // unconnect signals from old color scale { disconnect(this, SIGNAL(dataRangeChanged(QCPRange)), mColorScale.data(), SLOT(setDataRange(QCPRange))); disconnect(this, SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), mColorScale.data(), SLOT(setDataScaleType(QCPAxis::ScaleType))); disconnect(this, SIGNAL(gradientChanged(QCPColorGradient)), mColorScale.data(), SLOT(setGradient(QCPColorGradient))); disconnect(mColorScale.data(), SIGNAL(dataRangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange))); disconnect(mColorScale.data(), SIGNAL(gradientChanged(QCPColorGradient)), this, SLOT(setGradient(QCPColorGradient))); disconnect(mColorScale.data(), SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType))); } mColorScale = colorScale; if (mColorScale) // connect signals to new color scale { setGradient(mColorScale.data()->gradient()); setDataRange(mColorScale.data()->dataRange()); setDataScaleType(mColorScale.data()->dataScaleType()); connect(this, SIGNAL(dataRangeChanged(QCPRange)), mColorScale.data(), SLOT(setDataRange(QCPRange))); connect(this, SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), mColorScale.data(), SLOT(setDataScaleType(QCPAxis::ScaleType))); connect(this, SIGNAL(gradientChanged(QCPColorGradient)), mColorScale.data(), SLOT(setGradient(QCPColorGradient))); connect(mColorScale.data(), SIGNAL(dataRangeChanged(QCPRange)), this, SLOT(setDataRange(QCPRange))); connect(mColorScale.data(), SIGNAL(gradientChanged(QCPColorGradient)), this, SLOT(setGradient(QCPColorGradient))); connect(mColorScale.data(), SIGNAL(dataScaleTypeChanged(QCPAxis::ScaleType)), this, SLOT(setDataScaleType(QCPAxis::ScaleType))); } } /*! Sets the data range (\ref setDataRange) to span the minimum and maximum values that occur in the current data set. This corresponds to the \ref rescaleKeyAxis or \ref rescaleValueAxis methods, only for the third data dimension of the color map. The minimum and maximum values of the data set are buffered in the internal QCPColorMapData instance (\ref data). As data is updated via its \ref QCPColorMapData::setCell or \ref QCPColorMapData::setData, the buffered minimum and maximum values are updated, too. For performance reasons, however, they are only updated in an expanding fashion. So the buffered maximum can only increase and the buffered minimum can only decrease. In consequence, changes to the data that actually lower the maximum of the data set (by overwriting the cell holding the current maximum with a smaller value), aren't recognized and the buffered maximum overestimates the true maximum of the data set. The same happens for the buffered minimum. To recalculate the true minimum and maximum by explicitly looking at each cell, the method QCPColorMapData::recalculateDataBounds can be used. For convenience, setting the parameter \a recalculateDataBounds calls this method before setting the data range to the buffered minimum and maximum. \see setDataRange */ void QCPColorMap::rescaleDataRange(bool recalculateDataBounds) { if (recalculateDataBounds) mMapData->recalculateDataBounds(); setDataRange(mMapData->dataBounds()); } /*! Takes the current appearance of the color map and updates the legend icon, which is used to represent this color map in the legend (see \ref QCPLegend). The \a transformMode specifies whether the rescaling is done by a faster, low quality image scaling algorithm (Qt::FastTransformation) or by a slower, higher quality algorithm (Qt::SmoothTransformation). The current color map appearance is scaled down to \a thumbSize. Ideally, this should be equal to the size of the legend icon (see \ref QCPLegend::setIconSize). If it isn't exactly the configured legend icon size, the thumb will be rescaled during drawing of the legend item. \see setDataRange */ void QCPColorMap::updateLegendIcon(Qt::TransformationMode transformMode, const QSize &thumbSize) { if (mMapImage.isNull() && !data()->isEmpty()) updateMapImage(); // try to update map image if it's null (happens if no draw has happened yet) if (!mMapImage.isNull()) // might still be null, e.g. if data is empty, so check here again { bool mirrorX = (keyAxis()->orientation() == Qt::Horizontal ? keyAxis() : valueAxis())->rangeReversed(); bool mirrorY = (valueAxis()->orientation() == Qt::Vertical ? valueAxis() : keyAxis())->rangeReversed(); mLegendIcon = QPixmap::fromImage(mMapImage.mirrored(mirrorX, mirrorY)).scaled(thumbSize, Qt::KeepAspectRatio, transformMode); } } /* inherits documentation from base class */ double QCPColorMap::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if ((onlySelectable && mSelectable == QCP::stNone) || mMapData->isEmpty()) return -1; if (!mKeyAxis || !mValueAxis) return -1; if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()) || mParentPlot->interactions().testFlag(QCP::iSelectPlottablesBeyondAxisRect)) { double posKey, posValue; pixelsToCoords(pos, posKey, posValue); if (mMapData->keyRange().contains(posKey) && mMapData->valueRange().contains(posValue)) { if (details) details->setValue(QCPDataSelection(QCPDataRange(0, 1))); // temporary solution, to facilitate whole-plottable selection. Replace in future version with segmented 2D selection. return mParentPlot->selectionTolerance()*0.99; } } return -1; } /* inherits documentation from base class */ QCPRange QCPColorMap::getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain) const { foundRange = true; QCPRange result = mMapData->keyRange(); result.normalize(); if (inSignDomain == QCP::sdPositive) { if (result.lower <= 0 && result.upper > 0) result.lower = result.upper*1e-3; else if (result.lower <= 0 && result.upper <= 0) foundRange = false; } else if (inSignDomain == QCP::sdNegative) { if (result.upper >= 0 && result.lower < 0) result.upper = result.lower*1e-3; else if (result.upper >= 0 && result.lower >= 0) foundRange = false; } return result; } /* inherits documentation from base class */ QCPRange QCPColorMap::getValueRange(bool &foundRange, QCP::SignDomain inSignDomain, const QCPRange &inKeyRange) const { if (inKeyRange != QCPRange()) { if (mMapData->keyRange().upper < inKeyRange.lower || mMapData->keyRange().lower > inKeyRange.upper) { foundRange = false; return {}; } } foundRange = true; QCPRange result = mMapData->valueRange(); result.normalize(); if (inSignDomain == QCP::sdPositive) { if (result.lower <= 0 && result.upper > 0) result.lower = result.upper*1e-3; else if (result.lower <= 0 && result.upper <= 0) foundRange = false; } else if (inSignDomain == QCP::sdNegative) { if (result.upper >= 0 && result.lower < 0) result.upper = result.lower*1e-3; else if (result.upper >= 0 && result.lower >= 0) foundRange = false; } return result; } /*! \internal Updates the internal map image buffer by going through the internal \ref QCPColorMapData and turning the data values into color pixels with \ref QCPColorGradient::colorize. This method is called by \ref QCPColorMap::draw if either the data has been modified or the map image has been invalidated for a different reason (e.g. a change of the data range with \ref setDataRange). If the map cell count is low, the image created will be oversampled in order to avoid a QPainter::drawImage bug which makes inner pixel boundaries jitter when stretch-drawing images without smooth transform enabled. Accordingly, oversampling isn't performed if \ref setInterpolate is true. */ void QCPColorMap::updateMapImage() { QCPAxis *keyAxis = mKeyAxis.data(); if (!keyAxis) return; if (mMapData->isEmpty()) return; const QImage::Format format = QImage::Format_ARGB32_Premultiplied; const int keySize = mMapData->keySize(); const int valueSize = mMapData->valueSize(); int keyOversamplingFactor = mInterpolate ? 1 : int(1.0+100.0/double(keySize)); // make mMapImage have at least size 100, factor becomes 1 if size > 200 or interpolation is on int valueOversamplingFactor = mInterpolate ? 1 : int(1.0+100.0/double(valueSize)); // make mMapImage have at least size 100, factor becomes 1 if size > 200 or interpolation is on // resize mMapImage to correct dimensions including possible oversampling factors, according to key/value axes orientation: if (keyAxis->orientation() == Qt::Horizontal && (mMapImage.width() != keySize*keyOversamplingFactor || mMapImage.height() != valueSize*valueOversamplingFactor)) mMapImage = QImage(QSize(keySize*keyOversamplingFactor, valueSize*valueOversamplingFactor), format); else if (keyAxis->orientation() == Qt::Vertical && (mMapImage.width() != valueSize*valueOversamplingFactor || mMapImage.height() != keySize*keyOversamplingFactor)) mMapImage = QImage(QSize(valueSize*valueOversamplingFactor, keySize*keyOversamplingFactor), format); if (mMapImage.isNull()) { qDebug() << Q_FUNC_INFO << "Couldn't create map image (possibly too large for memory)"; mMapImage = QImage(QSize(10, 10), format); mMapImage.fill(Qt::black); } else { QImage *localMapImage = &mMapImage; // this is the image on which the colorization operates. Either the final mMapImage, or if we need oversampling, mUndersampledMapImage if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) { // resize undersampled map image to actual key/value cell sizes: if (keyAxis->orientation() == Qt::Horizontal && (mUndersampledMapImage.width() != keySize || mUndersampledMapImage.height() != valueSize)) mUndersampledMapImage = QImage(QSize(keySize, valueSize), format); else if (keyAxis->orientation() == Qt::Vertical && (mUndersampledMapImage.width() != valueSize || mUndersampledMapImage.height() != keySize)) mUndersampledMapImage = QImage(QSize(valueSize, keySize), format); localMapImage = &mUndersampledMapImage; // make the colorization run on the undersampled image } else if (!mUndersampledMapImage.isNull()) mUndersampledMapImage = QImage(); // don't need oversampling mechanism anymore (map size has changed) but mUndersampledMapImage still has nonzero size, free it const double *rawData = mMapData->mData; const unsigned char *rawAlpha = mMapData->mAlpha; if (keyAxis->orientation() == Qt::Horizontal) { const int lineCount = valueSize; const int rowCount = keySize; for (int line=0; line(localMapImage->scanLine(lineCount-1-line)); // invert scanline index because QImage counts scanlines from top, but our vertical index counts from bottom (mathematical coordinate system) if (rawAlpha) mGradient.colorize(rawData+line*rowCount, rawAlpha+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic); else mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic); } } else // keyAxis->orientation() == Qt::Vertical { const int lineCount = keySize; const int rowCount = valueSize; for (int line=0; line(localMapImage->scanLine(lineCount-1-line)); // invert scanline index because QImage counts scanlines from top, but our vertical index counts from bottom (mathematical coordinate system) if (rawAlpha) mGradient.colorize(rawData+line, rawAlpha+line, mDataRange, pixels, rowCount, lineCount, mDataScaleType==QCPAxis::stLogarithmic); else mGradient.colorize(rawData+line, mDataRange, pixels, rowCount, lineCount, mDataScaleType==QCPAxis::stLogarithmic); } } if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) { if (keyAxis->orientation() == Qt::Horizontal) mMapImage = mUndersampledMapImage.scaled(keySize*keyOversamplingFactor, valueSize*valueOversamplingFactor, Qt::IgnoreAspectRatio, Qt::FastTransformation); else mMapImage = mUndersampledMapImage.scaled(valueSize*valueOversamplingFactor, keySize*keyOversamplingFactor, Qt::IgnoreAspectRatio, Qt::FastTransformation); } } mMapData->mDataModified = false; mMapImageInvalidated = false; } /* inherits documentation from base class */ void QCPColorMap::draw(QCPPainter *painter) { if (mMapData->isEmpty()) return; if (!mKeyAxis || !mValueAxis) return; applyDefaultAntialiasingHint(painter); if (mMapData->mDataModified || mMapImageInvalidated) updateMapImage(); // use buffer if painting vectorized (PDF): const bool useBuffer = painter->modes().testFlag(QCPPainter::pmVectorized); QCPPainter *localPainter = painter; // will be redirected to paint on mapBuffer if painting vectorized QRectF mapBufferTarget; // the rect in absolute widget coordinates where the visible map portion/buffer will end up in QPixmap mapBuffer; if (useBuffer) { const double mapBufferPixelRatio = 3; // factor by which DPI is increased in embedded bitmaps mapBufferTarget = painter->clipRegion().boundingRect(); mapBuffer = QPixmap((mapBufferTarget.size()*mapBufferPixelRatio).toSize()); mapBuffer.fill(Qt::transparent); localPainter = new QCPPainter(&mapBuffer); localPainter->scale(mapBufferPixelRatio, mapBufferPixelRatio); localPainter->translate(-mapBufferTarget.topLeft()); } QRectF imageRect = QRectF(coordsToPixels(mMapData->keyRange().lower, mMapData->valueRange().lower), coordsToPixels(mMapData->keyRange().upper, mMapData->valueRange().upper)).normalized(); // extend imageRect to contain outer halves/quarters of bordering/cornering pixels (cells are centered on map range boundary): double halfCellWidth = 0; // in pixels double halfCellHeight = 0; // in pixels if (keyAxis()->orientation() == Qt::Horizontal) { if (mMapData->keySize() > 1) halfCellWidth = 0.5*imageRect.width()/double(mMapData->keySize()-1); if (mMapData->valueSize() > 1) halfCellHeight = 0.5*imageRect.height()/double(mMapData->valueSize()-1); } else // keyAxis orientation is Qt::Vertical { if (mMapData->keySize() > 1) halfCellHeight = 0.5*imageRect.height()/double(mMapData->keySize()-1); if (mMapData->valueSize() > 1) halfCellWidth = 0.5*imageRect.width()/double(mMapData->valueSize()-1); } imageRect.adjust(-halfCellWidth, -halfCellHeight, halfCellWidth, halfCellHeight); const bool mirrorX = (keyAxis()->orientation() == Qt::Horizontal ? keyAxis() : valueAxis())->rangeReversed(); const bool mirrorY = (valueAxis()->orientation() == Qt::Vertical ? valueAxis() : keyAxis())->rangeReversed(); const bool smoothBackup = localPainter->renderHints().testFlag(QPainter::SmoothPixmapTransform); localPainter->setRenderHint(QPainter::SmoothPixmapTransform, mInterpolate); QRegion clipBackup; if (mTightBoundary) { clipBackup = localPainter->clipRegion(); QRectF tightClipRect = QRectF(coordsToPixels(mMapData->keyRange().lower, mMapData->valueRange().lower), coordsToPixels(mMapData->keyRange().upper, mMapData->valueRange().upper)).normalized(); localPainter->setClipRect(tightClipRect, Qt::IntersectClip); } localPainter->drawImage(imageRect, mMapImage.mirrored(mirrorX, mirrorY)); if (mTightBoundary) localPainter->setClipRegion(clipBackup); localPainter->setRenderHint(QPainter::SmoothPixmapTransform, smoothBackup); if (useBuffer) // localPainter painted to mapBuffer, so now draw buffer with original painter { delete localPainter; painter->drawPixmap(mapBufferTarget.toRect(), mapBuffer); } } /* inherits documentation from base class */ void QCPColorMap::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const { applyDefaultAntialiasingHint(painter); // draw map thumbnail: if (!mLegendIcon.isNull()) { QPixmap scaledIcon = mLegendIcon.scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::FastTransformation); QRectF iconRect = QRectF(0, 0, scaledIcon.width(), scaledIcon.height()); iconRect.moveCenter(rect.center()); painter->drawPixmap(iconRect.topLeft(), scaledIcon); } /* // draw frame: painter->setBrush(Qt::NoBrush); painter->setPen(Qt::black); painter->drawRect(rect.adjusted(1, 1, 0, 0)); */ } /* end of 'src/plottables/plottable-colormap.cpp' */ /* including file 'src/plottables/plottable-financial.cpp' */ /* modified 2021-03-29T02:30:44, size 42914 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPFinancialData //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPFinancialData \brief Holds the data of one single data point for QCPFinancial. The stored data is: \li \a key: coordinate on the key axis of this data point (this is the \a mainKey and the \a sortKey) \li \a open: The opening value at the data point (this is the \a mainValue) \li \a high: The high/maximum value at the data point \li \a low: The low/minimum value at the data point \li \a close: The closing value at the data point The container for storing multiple data points is \ref QCPFinancialDataContainer. It is a typedef for \ref QCPDataContainer with \ref QCPFinancialData as the DataType template parameter. See the documentation there for an explanation regarding the data type's generic methods. \see QCPFinancialDataContainer */ /* start documentation of inline functions */ /*! \fn double QCPFinancialData::sortKey() const Returns the \a key member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static QCPFinancialData QCPFinancialData::fromSortKey(double sortKey) Returns a data point with the specified \a sortKey. All other members are set to zero. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn static static bool QCPFinancialData::sortKeyIsMainKey() Since the member \a key is both the data point key coordinate and the data ordering parameter, this method returns true. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPFinancialData::mainKey() const Returns the \a key member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn double QCPFinancialData::mainValue() const Returns the \a open member of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /*! \fn QCPRange QCPFinancialData::valueRange() const Returns a QCPRange spanning from the \a low to the \a high value of this data point. For a general explanation of what this method is good for in the context of the data container, see the documentation of \ref QCPDataContainer. */ /* end documentation of inline functions */ /*! Constructs a data point with key and all values set to zero. */ QCPFinancialData::QCPFinancialData() : key(0), open(0), high(0), low(0), close(0) { } /*! Constructs a data point with the specified \a key and OHLC values. */ QCPFinancialData::QCPFinancialData(double key, double open, double high, double low, double close) : key(key), open(open), high(high), low(low), close(close) { } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPFinancial //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPFinancial \brief A plottable representing a financial stock chart \image html QCPFinancial.png This plottable represents time series data binned to certain intervals, mainly used for stock charts. The two common representations OHLC (Open-High-Low-Close) bars and Candlesticks can be set via \ref setChartStyle. The data is passed via \ref setData as a set of open/high/low/close values at certain keys (typically times). This means the data must be already binned appropriately. If data is only available as a series of values (e.g. \a price against \a time), you can use the static convenience function \ref timeSeriesToOhlc to generate binned OHLC-data which can then be passed to \ref setData. The width of the OHLC bars/candlesticks can be controlled with \ref setWidth and \ref setWidthType. A typical choice is to set the width type to \ref wtPlotCoords (the default) and the width to (or slightly less than) one time bin interval width. \section qcpfinancial-appearance Changing the appearance Charts can be either single- or two-colored (\ref setTwoColored). If set to be single-colored, lines are drawn with the plottable's pen (\ref setPen) and fills with the brush (\ref setBrush). If set to two-colored, positive changes of the value during an interval (\a close >= \a open) are represented with a different pen and brush than negative changes (\a close < \a open). These can be configured with \ref setPenPositive, \ref setPenNegative, \ref setBrushPositive, and \ref setBrushNegative. In two-colored mode, the normal plottable pen/brush is ignored. Upon selection however, the normal selected pen/brush (provided by the \ref selectionDecorator) is used, irrespective of whether the chart is single- or two-colored. \section qcpfinancial-usage Usage Like all data representing objects in QCustomPlot, the QCPFinancial is a plottable (QCPAbstractPlottable). So the plottable-interface of QCustomPlot applies (QCustomPlot::plottable, QCustomPlot::removePlottable, etc.) Usually, you first create an instance: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpfinancial-creation-1 which registers it with the QCustomPlot instance of the passed axes. Note that this QCustomPlot instance takes ownership of the plottable, so do not delete it manually but use QCustomPlot::removePlottable() instead. The newly created plottable can be modified, e.g.: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpfinancial-creation-2 Here we have used the static helper method \ref timeSeriesToOhlc, to turn a time-price data series into a 24-hour binned open-high-low-close data series as QCPFinancial uses. */ /* start of documentation of inline functions */ /*! \fn QCPFinancialDataContainer *QCPFinancial::data() const Returns a pointer to the internal data storage of type \ref QCPFinancialDataContainer. You may use it to directly manipulate the data, which may be more convenient and faster than using the regular \ref setData or \ref addData methods, in certain situations. */ /* end of documentation of inline functions */ /*! Constructs a financial chart which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The created QCPFinancial is automatically registered with the QCustomPlot instance inferred from \a keyAxis. This QCustomPlot instance takes ownership of the QCPFinancial, so do not delete it manually but use QCustomPlot::removePlottable() instead. */ QCPFinancial::QCPFinancial(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable1D(keyAxis, valueAxis), mChartStyle(csCandlestick), mWidth(0.5), mWidthType(wtPlotCoords), mTwoColored(true), mBrushPositive(QBrush(QColor(50, 160, 0))), mBrushNegative(QBrush(QColor(180, 0, 15))), mPenPositive(QPen(QColor(40, 150, 0))), mPenNegative(QPen(QColor(170, 5, 5))) { mSelectionDecorator->setBrush(QBrush(QColor(160, 160, 255))); } QCPFinancial::~QCPFinancial() { } /*! \overload Replaces the current data container with the provided \a data container. Since a QSharedPointer is used, multiple QCPFinancials may share the same data container safely. Modifying the data in the container will then affect all financials that share the container. Sharing can be achieved by simply exchanging the data containers wrapped in shared pointers: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpfinancial-datasharing-1 If you do not wish to share containers, but create a copy from an existing container, rather use the \ref QCPDataContainer::set method on the financial's data container directly: \snippet documentation/doc-code-snippets/mainwindow.cpp qcpfinancial-datasharing-2 \see addData, timeSeriesToOhlc */ void QCPFinancial::setData(QSharedPointer data) { mDataContainer = data; } /*! \overload Replaces the current data with the provided points in \a keys, \a open, \a high, \a low and \a close. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. \see addData, timeSeriesToOhlc */ void QCPFinancial::setData(const QVector &keys, const QVector &open, const QVector &high, const QVector &low, const QVector &close, bool alreadySorted) { mDataContainer->clear(); addData(keys, open, high, low, close, alreadySorted); } /*! Sets which representation style shall be used to display the OHLC data. */ void QCPFinancial::setChartStyle(QCPFinancial::ChartStyle style) { mChartStyle = style; } /*! Sets the width of the individual bars/candlesticks to \a width in plot key coordinates. A typical choice is to set it to (or slightly less than) one bin interval width. */ void QCPFinancial::setWidth(double width) { mWidth = width; } /*! Sets how the width of the financial bars is defined. See the documentation of \ref WidthType for an explanation of the possible values for \a widthType. The default value is \ref wtPlotCoords. \see setWidth */ void QCPFinancial::setWidthType(QCPFinancial::WidthType widthType) { mWidthType = widthType; } /*! Sets whether this chart shall contrast positive from negative trends per data point by using two separate colors to draw the respective bars/candlesticks. If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref setBrush). \see setPenPositive, setPenNegative, setBrushPositive, setBrushNegative */ void QCPFinancial::setTwoColored(bool twoColored) { mTwoColored = twoColored; } /*! If \ref setTwoColored is set to true, this function controls the brush that is used to draw fills of data points with a positive trend (i.e. bars/candlesticks with close >= open). If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref setBrush). \see setBrushNegative, setPenPositive, setPenNegative */ void QCPFinancial::setBrushPositive(const QBrush &brush) { mBrushPositive = brush; } /*! If \ref setTwoColored is set to true, this function controls the brush that is used to draw fills of data points with a negative trend (i.e. bars/candlesticks with close < open). If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref setBrush). \see setBrushPositive, setPenNegative, setPenPositive */ void QCPFinancial::setBrushNegative(const QBrush &brush) { mBrushNegative = brush; } /*! If \ref setTwoColored is set to true, this function controls the pen that is used to draw outlines of data points with a positive trend (i.e. bars/candlesticks with close >= open). If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref setBrush). \see setPenNegative, setBrushPositive, setBrushNegative */ void QCPFinancial::setPenPositive(const QPen &pen) { mPenPositive = pen; } /*! If \ref setTwoColored is set to true, this function controls the pen that is used to draw outlines of data points with a negative trend (i.e. bars/candlesticks with close < open). If \a twoColored is false, the normal plottable's pen and brush are used (\ref setPen, \ref setBrush). \see setPenPositive, setBrushNegative, setBrushPositive */ void QCPFinancial::setPenNegative(const QPen &pen) { mPenNegative = pen; } /*! \overload Adds the provided points in \a keys, \a open, \a high, \a low and \a close to the current data. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. \see timeSeriesToOhlc */ void QCPFinancial::addData(const QVector &keys, const QVector &open, const QVector &high, const QVector &low, const QVector &close, bool alreadySorted) { if (keys.size() != open.size() || open.size() != high.size() || high.size() != low.size() || low.size() != close.size() || close.size() != keys.size()) qDebug() << Q_FUNC_INFO << "keys, open, high, low, close have different sizes:" << keys.size() << open.size() << high.size() << low.size() << close.size(); const int n = qMin(keys.size(), qMin(open.size(), qMin(high.size(), qMin(low.size(), close.size())))); QVector tempData(n); QVector::iterator it = tempData.begin(); const QVector::iterator itEnd = tempData.end(); int i = 0; while (it != itEnd) { it->key = keys[i]; it->open = open[i]; it->high = high[i]; it->low = low[i]; it->close = close[i]; ++it; ++i; } mDataContainer->add(tempData, alreadySorted); // don't modify tempData beyond this to prevent copy on write } /*! \overload Adds the provided data point as \a key, \a open, \a high, \a low and \a close to the current data. Alternatively, you can also access and modify the data directly via the \ref data method, which returns a pointer to the internal data container. \see timeSeriesToOhlc */ void QCPFinancial::addData(double key, double open, double high, double low, double close) { mDataContainer->add(QCPFinancialData(key, open, high, low, close)); } /*! \copydoc QCPPlottableInterface1D::selectTestRect */ QCPDataSelection QCPFinancial::selectTestRect(const QRectF &rect, bool onlySelectable) const { QCPDataSelection result; if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return result; if (!mKeyAxis || !mValueAxis) return result; QCPFinancialDataContainer::const_iterator visibleBegin, visibleEnd; getVisibleDataBounds(visibleBegin, visibleEnd); for (QCPFinancialDataContainer::const_iterator it=visibleBegin; it!=visibleEnd; ++it) { if (rect.intersects(selectionHitBox(it))) result.addDataRange(QCPDataRange(int(it-mDataContainer->constBegin()), int(it-mDataContainer->constBegin()+1)), false); } result.simplify(); return result; } /*! Implements a selectTest specific to this plottable's point geometry. If \a details is not 0, it will be set to a \ref QCPDataSelection, describing the closest data point to \a pos. \seebaseclassmethod \ref QCPAbstractPlottable::selectTest */ double QCPFinancial::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return -1; if (!mKeyAxis || !mValueAxis) return -1; if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()) || mParentPlot->interactions().testFlag(QCP::iSelectPlottablesBeyondAxisRect)) { // get visible data range: QCPFinancialDataContainer::const_iterator visibleBegin, visibleEnd; QCPFinancialDataContainer::const_iterator closestDataPoint = mDataContainer->constEnd(); getVisibleDataBounds(visibleBegin, visibleEnd); // perform select test according to configured style: double result = -1; switch (mChartStyle) { case QCPFinancial::csOhlc: result = ohlcSelectTest(pos, visibleBegin, visibleEnd, closestDataPoint); break; case QCPFinancial::csCandlestick: result = candlestickSelectTest(pos, visibleBegin, visibleEnd, closestDataPoint); break; } if (details) { int pointIndex = int(closestDataPoint-mDataContainer->constBegin()); details->setValue(QCPDataSelection(QCPDataRange(pointIndex, pointIndex+1))); } return result; } return -1; } /* inherits documentation from base class */ QCPRange QCPFinancial::getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain) const { QCPRange range = mDataContainer->keyRange(foundRange, inSignDomain); // determine exact range by including width of bars/flags: if (foundRange) { if (inSignDomain != QCP::sdPositive || range.lower-mWidth*0.5 > 0) range.lower -= mWidth*0.5; if (inSignDomain != QCP::sdNegative || range.upper+mWidth*0.5 < 0) range.upper += mWidth*0.5; } return range; } /* inherits documentation from base class */ QCPRange QCPFinancial::getValueRange(bool &foundRange, QCP::SignDomain inSignDomain, const QCPRange &inKeyRange) const { return mDataContainer->valueRange(foundRange, inSignDomain, inKeyRange); } /*! A convenience function that converts time series data (\a value against \a time) to OHLC binned data points. The return value can then be passed on to \ref QCPFinancialDataContainer::set(const QCPFinancialDataContainer&). The size of the bins can be controlled with \a timeBinSize in the same units as \a time is given. For example, if the unit of \a time is seconds and single OHLC/Candlesticks should span an hour each, set \a timeBinSize to 3600. \a timeBinOffset allows to control precisely at what \a time coordinate a bin should start. The value passed as \a timeBinOffset doesn't need to be in the range encompassed by the \a time keys. It merely defines the mathematical offset/phase of the bins that will be used to process the data. */ QCPFinancialDataContainer QCPFinancial::timeSeriesToOhlc(const QVector &time, const QVector &value, double timeBinSize, double timeBinOffset) { QCPFinancialDataContainer data; int count = qMin(time.size(), value.size()); if (count == 0) return QCPFinancialDataContainer(); QCPFinancialData currentBinData(0, value.first(), value.first(), value.first(), value.first()); int currentBinIndex = qFloor((time.first()-timeBinOffset)/timeBinSize+0.5); for (int i=0; i currentBinData.high) currentBinData.high = value.at(i); if (i == count-1) // last data point is in current bin, finalize bin: { currentBinData.close = value.at(i); currentBinData.key = timeBinOffset+(index)*timeBinSize; data.add(currentBinData); } } else // data point not anymore in current bin, set close of old and open of new bin, and add old to map: { // finalize current bin: currentBinData.close = value.at(i-1); currentBinData.key = timeBinOffset+(index-1)*timeBinSize; data.add(currentBinData); // start next bin: currentBinIndex = index; currentBinData.open = value.at(i); currentBinData.high = value.at(i); currentBinData.low = value.at(i); } } return data; } /* inherits documentation from base class */ void QCPFinancial::draw(QCPPainter *painter) { // get visible data range: QCPFinancialDataContainer::const_iterator visibleBegin, visibleEnd; getVisibleDataBounds(visibleBegin, visibleEnd); // loop over and draw segments of unselected/selected data: QList selectedSegments, unselectedSegments, allSegments; getDataSegments(selectedSegments, unselectedSegments); allSegments << unselectedSegments << selectedSegments; for (int i=0; i= unselectedSegments.size(); QCPFinancialDataContainer::const_iterator begin = visibleBegin; QCPFinancialDataContainer::const_iterator end = visibleEnd; mDataContainer->limitIteratorsToDataRange(begin, end, allSegments.at(i)); if (begin == end) continue; // draw data segment according to configured style: switch (mChartStyle) { case QCPFinancial::csOhlc: drawOhlcPlot(painter, begin, end, isSelectedSegment); break; case QCPFinancial::csCandlestick: drawCandlestickPlot(painter, begin, end, isSelectedSegment); break; } } // draw other selection decoration that isn't just line/scatter pens and brushes: if (mSelectionDecorator) mSelectionDecorator->drawDecoration(painter, selection()); } /* inherits documentation from base class */ void QCPFinancial::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const { painter->setAntialiasing(false); // legend icon especially of csCandlestick looks better without antialiasing if (mChartStyle == csOhlc) { if (mTwoColored) { // draw upper left half icon with positive color: painter->setBrush(mBrushPositive); painter->setPen(mPenPositive); painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.topLeft().toPoint())); painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft())); painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft())); painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft())); // draw bottom right half icon with negative color: painter->setBrush(mBrushNegative); painter->setPen(mPenNegative); painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.bottomRight().toPoint())); painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft())); painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft())); painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft())); } else { painter->setBrush(mBrush); painter->setPen(mPen); painter->drawLine(QLineF(0, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft())); painter->drawLine(QLineF(rect.width()*0.2, rect.height()*0.3, rect.width()*0.2, rect.height()*0.5).translated(rect.topLeft())); painter->drawLine(QLineF(rect.width()*0.8, rect.height()*0.5, rect.width()*0.8, rect.height()*0.7).translated(rect.topLeft())); } } else if (mChartStyle == csCandlestick) { if (mTwoColored) { // draw upper left half icon with positive color: painter->setBrush(mBrushPositive); painter->setPen(mPenPositive); painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.topLeft().toPoint())); painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft())); painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft())); painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft())); // draw bottom right half icon with negative color: painter->setBrush(mBrushNegative); painter->setPen(mPenNegative); painter->setClipRegion(QRegion(QPolygon() << rect.bottomLeft().toPoint() << rect.topRight().toPoint() << rect.bottomRight().toPoint())); painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft())); painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft())); painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft())); } else { painter->setBrush(mBrush); painter->setPen(mPen); painter->drawLine(QLineF(0, rect.height()*0.5, rect.width()*0.25, rect.height()*0.5).translated(rect.topLeft())); painter->drawLine(QLineF(rect.width()*0.75, rect.height()*0.5, rect.width(), rect.height()*0.5).translated(rect.topLeft())); painter->drawRect(QRectF(rect.width()*0.25, rect.height()*0.25, rect.width()*0.5, rect.height()*0.5).translated(rect.topLeft())); } } } /*! \internal Draws the data from \a begin to \a end-1 as OHLC bars with the provided \a painter. This method is a helper function for \ref draw. It is used when the chart style is \ref csOhlc. */ void QCPFinancial::drawOhlcPlot(QCPPainter *painter, const QCPFinancialDataContainer::const_iterator &begin, const QCPFinancialDataContainer::const_iterator &end, bool isSelected) { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (keyAxis->orientation() == Qt::Horizontal) { for (QCPFinancialDataContainer::const_iterator it = begin; it != end; ++it) { if (isSelected && mSelectionDecorator) mSelectionDecorator->applyPen(painter); else if (mTwoColored) painter->setPen(it->close >= it->open ? mPenPositive : mPenNegative); else painter->setPen(mPen); double keyPixel = keyAxis->coordToPixel(it->key); double openPixel = valueAxis->coordToPixel(it->open); double closePixel = valueAxis->coordToPixel(it->close); // draw backbone: painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it->high)), QPointF(keyPixel, valueAxis->coordToPixel(it->low))); // draw open: double pixelWidth = getPixelWidth(it->key, keyPixel); // sign of this makes sure open/close are on correct sides painter->drawLine(QPointF(keyPixel-pixelWidth, openPixel), QPointF(keyPixel, openPixel)); // draw close: painter->drawLine(QPointF(keyPixel, closePixel), QPointF(keyPixel+pixelWidth, closePixel)); } } else { for (QCPFinancialDataContainer::const_iterator it = begin; it != end; ++it) { if (isSelected && mSelectionDecorator) mSelectionDecorator->applyPen(painter); else if (mTwoColored) painter->setPen(it->close >= it->open ? mPenPositive : mPenNegative); else painter->setPen(mPen); double keyPixel = keyAxis->coordToPixel(it->key); double openPixel = valueAxis->coordToPixel(it->open); double closePixel = valueAxis->coordToPixel(it->close); // draw backbone: painter->drawLine(QPointF(valueAxis->coordToPixel(it->high), keyPixel), QPointF(valueAxis->coordToPixel(it->low), keyPixel)); // draw open: double pixelWidth = getPixelWidth(it->key, keyPixel); // sign of this makes sure open/close are on correct sides painter->drawLine(QPointF(openPixel, keyPixel-pixelWidth), QPointF(openPixel, keyPixel)); // draw close: painter->drawLine(QPointF(closePixel, keyPixel), QPointF(closePixel, keyPixel+pixelWidth)); } } } /*! \internal Draws the data from \a begin to \a end-1 as Candlesticks with the provided \a painter. This method is a helper function for \ref draw. It is used when the chart style is \ref csCandlestick. */ void QCPFinancial::drawCandlestickPlot(QCPPainter *painter, const QCPFinancialDataContainer::const_iterator &begin, const QCPFinancialDataContainer::const_iterator &end, bool isSelected) { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (keyAxis->orientation() == Qt::Horizontal) { for (QCPFinancialDataContainer::const_iterator it = begin; it != end; ++it) { if (isSelected && mSelectionDecorator) { mSelectionDecorator->applyPen(painter); mSelectionDecorator->applyBrush(painter); } else if (mTwoColored) { painter->setPen(it->close >= it->open ? mPenPositive : mPenNegative); painter->setBrush(it->close >= it->open ? mBrushPositive : mBrushNegative); } else { painter->setPen(mPen); painter->setBrush(mBrush); } double keyPixel = keyAxis->coordToPixel(it->key); double openPixel = valueAxis->coordToPixel(it->open); double closePixel = valueAxis->coordToPixel(it->close); // draw high: painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it->high)), QPointF(keyPixel, valueAxis->coordToPixel(qMax(it->open, it->close)))); // draw low: painter->drawLine(QPointF(keyPixel, valueAxis->coordToPixel(it->low)), QPointF(keyPixel, valueAxis->coordToPixel(qMin(it->open, it->close)))); // draw open-close box: double pixelWidth = getPixelWidth(it->key, keyPixel); painter->drawRect(QRectF(QPointF(keyPixel-pixelWidth, closePixel), QPointF(keyPixel+pixelWidth, openPixel))); } } else // keyAxis->orientation() == Qt::Vertical { for (QCPFinancialDataContainer::const_iterator it = begin; it != end; ++it) { if (isSelected && mSelectionDecorator) { mSelectionDecorator->applyPen(painter); mSelectionDecorator->applyBrush(painter); } else if (mTwoColored) { painter->setPen(it->close >= it->open ? mPenPositive : mPenNegative); painter->setBrush(it->close >= it->open ? mBrushPositive : mBrushNegative); } else { painter->setPen(mPen); painter->setBrush(mBrush); } double keyPixel = keyAxis->coordToPixel(it->key); double openPixel = valueAxis->coordToPixel(it->open); double closePixel = valueAxis->coordToPixel(it->close); // draw high: painter->drawLine(QPointF(valueAxis->coordToPixel(it->high), keyPixel), QPointF(valueAxis->coordToPixel(qMax(it->open, it->close)), keyPixel)); // draw low: painter->drawLine(QPointF(valueAxis->coordToPixel(it->low), keyPixel), QPointF(valueAxis->coordToPixel(qMin(it->open, it->close)), keyPixel)); // draw open-close box: double pixelWidth = getPixelWidth(it->key, keyPixel); painter->drawRect(QRectF(QPointF(closePixel, keyPixel-pixelWidth), QPointF(openPixel, keyPixel+pixelWidth))); } } } /*! \internal This function is used to determine the width of the bar at coordinate \a key, according to the specified width (\ref setWidth) and width type (\ref setWidthType). Provide the pixel position of \a key in \a keyPixel (because usually this was already calculated via \ref QCPAxis::coordToPixel when this function is called). It returns the number of pixels the bar extends to higher keys, relative to the \a key coordinate. So with a non-reversed horizontal axis, the return value is positive. With a reversed horizontal axis, the return value is negative. This is important so the open/close flags on the \ref csOhlc bar are drawn to the correct side. */ double QCPFinancial::getPixelWidth(double key, double keyPixel) const { double result = 0; switch (mWidthType) { case wtAbsolute: { if (mKeyAxis) result = mWidth*0.5*mKeyAxis.data()->pixelOrientation(); break; } case wtAxisRectRatio: { if (mKeyAxis && mKeyAxis.data()->axisRect()) { if (mKeyAxis.data()->orientation() == Qt::Horizontal) result = mKeyAxis.data()->axisRect()->width()*mWidth*0.5*mKeyAxis.data()->pixelOrientation(); else result = mKeyAxis.data()->axisRect()->height()*mWidth*0.5*mKeyAxis.data()->pixelOrientation(); } else qDebug() << Q_FUNC_INFO << "No key axis or axis rect defined"; break; } case wtPlotCoords: { if (mKeyAxis) result = mKeyAxis.data()->coordToPixel(key+mWidth*0.5)-keyPixel; else qDebug() << Q_FUNC_INFO << "No key axis defined"; break; } } return result; } /*! \internal This method is a helper function for \ref selectTest. It is used to test for selection when the chart style is \ref csOhlc. It only tests against the data points between \a begin and \a end. Like \ref selectTest, this method returns the shortest distance of \a pos to the graphical representation of the plottable, and \a closestDataPoint will point to the respective data point. */ double QCPFinancial::ohlcSelectTest(const QPointF &pos, const QCPFinancialDataContainer::const_iterator &begin, const QCPFinancialDataContainer::const_iterator &end, QCPFinancialDataContainer::const_iterator &closestDataPoint) const { closestDataPoint = mDataContainer->constEnd(); QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; } double minDistSqr = (std::numeric_limits::max)(); if (keyAxis->orientation() == Qt::Horizontal) { for (QCPFinancialDataContainer::const_iterator it=begin; it!=end; ++it) { double keyPixel = keyAxis->coordToPixel(it->key); // calculate distance to backbone: double currentDistSqr = QCPVector2D(pos).distanceSquaredToLine(QCPVector2D(keyPixel, valueAxis->coordToPixel(it->high)), QCPVector2D(keyPixel, valueAxis->coordToPixel(it->low))); if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestDataPoint = it; } } } else // keyAxis->orientation() == Qt::Vertical { for (QCPFinancialDataContainer::const_iterator it=begin; it!=end; ++it) { double keyPixel = keyAxis->coordToPixel(it->key); // calculate distance to backbone: double currentDistSqr = QCPVector2D(pos).distanceSquaredToLine(QCPVector2D(valueAxis->coordToPixel(it->high), keyPixel), QCPVector2D(valueAxis->coordToPixel(it->low), keyPixel)); if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestDataPoint = it; } } } return qSqrt(minDistSqr); } /*! \internal This method is a helper function for \ref selectTest. It is used to test for selection when the chart style is \ref csCandlestick. It only tests against the data points between \a begin and \a end. Like \ref selectTest, this method returns the shortest distance of \a pos to the graphical representation of the plottable, and \a closestDataPoint will point to the respective data point. */ double QCPFinancial::candlestickSelectTest(const QPointF &pos, const QCPFinancialDataContainer::const_iterator &begin, const QCPFinancialDataContainer::const_iterator &end, QCPFinancialDataContainer::const_iterator &closestDataPoint) const { closestDataPoint = mDataContainer->constEnd(); QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1; } double minDistSqr = (std::numeric_limits::max)(); if (keyAxis->orientation() == Qt::Horizontal) { for (QCPFinancialDataContainer::const_iterator it=begin; it!=end; ++it) { double currentDistSqr; // determine whether pos is in open-close-box: QCPRange boxKeyRange(it->key-mWidth*0.5, it->key+mWidth*0.5); QCPRange boxValueRange(it->close, it->open); double posKey, posValue; pixelsToCoords(pos, posKey, posValue); if (boxKeyRange.contains(posKey) && boxValueRange.contains(posValue)) // is in open-close-box { currentDistSqr = mParentPlot->selectionTolerance()*0.99 * mParentPlot->selectionTolerance()*0.99; } else { // calculate distance to high/low lines: double keyPixel = keyAxis->coordToPixel(it->key); double highLineDistSqr = QCPVector2D(pos).distanceSquaredToLine(QCPVector2D(keyPixel, valueAxis->coordToPixel(it->high)), QCPVector2D(keyPixel, valueAxis->coordToPixel(qMax(it->open, it->close)))); double lowLineDistSqr = QCPVector2D(pos).distanceSquaredToLine(QCPVector2D(keyPixel, valueAxis->coordToPixel(it->low)), QCPVector2D(keyPixel, valueAxis->coordToPixel(qMin(it->open, it->close)))); currentDistSqr = qMin(highLineDistSqr, lowLineDistSqr); } if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestDataPoint = it; } } } else // keyAxis->orientation() == Qt::Vertical { for (QCPFinancialDataContainer::const_iterator it=begin; it!=end; ++it) { double currentDistSqr; // determine whether pos is in open-close-box: QCPRange boxKeyRange(it->key-mWidth*0.5, it->key+mWidth*0.5); QCPRange boxValueRange(it->close, it->open); double posKey, posValue; pixelsToCoords(pos, posKey, posValue); if (boxKeyRange.contains(posKey) && boxValueRange.contains(posValue)) // is in open-close-box { currentDistSqr = mParentPlot->selectionTolerance()*0.99 * mParentPlot->selectionTolerance()*0.99; } else { // calculate distance to high/low lines: double keyPixel = keyAxis->coordToPixel(it->key); double highLineDistSqr = QCPVector2D(pos).distanceSquaredToLine(QCPVector2D(valueAxis->coordToPixel(it->high), keyPixel), QCPVector2D(valueAxis->coordToPixel(qMax(it->open, it->close)), keyPixel)); double lowLineDistSqr = QCPVector2D(pos).distanceSquaredToLine(QCPVector2D(valueAxis->coordToPixel(it->low), keyPixel), QCPVector2D(valueAxis->coordToPixel(qMin(it->open, it->close)), keyPixel)); currentDistSqr = qMin(highLineDistSqr, lowLineDistSqr); } if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestDataPoint = it; } } } return qSqrt(minDistSqr); } /*! \internal called by the drawing methods to determine which data (key) range is visible at the current key axis range setting, so only that needs to be processed. \a begin returns an iterator to the lowest data point that needs to be taken into account when plotting. Note that in order to get a clean plot all the way to the edge of the axis rect, \a begin may still be just outside the visible range. \a end returns the iterator just above the highest data point that needs to be taken into account. Same as before, \a end may also lie just outside of the visible range if the plottable contains no data, both \a begin and \a end point to \c constEnd. */ void QCPFinancial::getVisibleDataBounds(QCPFinancialDataContainer::const_iterator &begin, QCPFinancialDataContainer::const_iterator &end) const { if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; begin = mDataContainer->constEnd(); end = mDataContainer->constEnd(); return; } begin = mDataContainer->findBegin(mKeyAxis.data()->range().lower-mWidth*0.5); // subtract half width of ohlc/candlestick to include partially visible data points end = mDataContainer->findEnd(mKeyAxis.data()->range().upper+mWidth*0.5); // add half width of ohlc/candlestick to include partially visible data points } /*! \internal Returns the hit box in pixel coordinates that will be used for data selection with the selection rect (\ref selectTestRect), of the data point given by \a it. */ QRectF QCPFinancial::selectionHitBox(QCPFinancialDataContainer::const_iterator it) const { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return {}; } double keyPixel = keyAxis->coordToPixel(it->key); double highPixel = valueAxis->coordToPixel(it->high); double lowPixel = valueAxis->coordToPixel(it->low); double keyWidthPixels = keyPixel-keyAxis->coordToPixel(it->key-mWidth*0.5); if (keyAxis->orientation() == Qt::Horizontal) return QRectF(keyPixel-keyWidthPixels, highPixel, keyWidthPixels*2, lowPixel-highPixel).normalized(); else return QRectF(highPixel, keyPixel-keyWidthPixels, lowPixel-highPixel, keyWidthPixels*2).normalized(); } /* end of 'src/plottables/plottable-financial.cpp' */ /* including file 'src/plottables/plottable-errorbar.cpp' */ /* modified 2021-03-29T02:30:44, size 37679 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPErrorBarsData //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPErrorBarsData \brief Holds the data of one single error bar for QCPErrorBars. The stored data is: \li \a errorMinus: how much the error bar extends towards negative coordinates from the data point position \li \a errorPlus: how much the error bar extends towards positive coordinates from the data point position The container for storing the error bar information is \ref QCPErrorBarsDataContainer. It is a typedef for QVector<\ref QCPErrorBarsData>. \see QCPErrorBarsDataContainer */ /*! Constructs an error bar with errors set to zero. */ QCPErrorBarsData::QCPErrorBarsData() : errorMinus(0), errorPlus(0) { } /*! Constructs an error bar with equal \a error in both negative and positive direction. */ QCPErrorBarsData::QCPErrorBarsData(double error) : errorMinus(error), errorPlus(error) { } /*! Constructs an error bar with negative and positive errors set to \a errorMinus and \a errorPlus, respectively. */ QCPErrorBarsData::QCPErrorBarsData(double errorMinus, double errorPlus) : errorMinus(errorMinus), errorPlus(errorPlus) { } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPErrorBars //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPErrorBars \brief A plottable that adds a set of error bars to other plottables. \image html QCPErrorBars.png The \ref QCPErrorBars plottable can be attached to other one-dimensional plottables (e.g. \ref QCPGraph, \ref QCPCurve, \ref QCPBars, etc.) and equips them with error bars. Use \ref setDataPlottable to define for which plottable the \ref QCPErrorBars shall display the error bars. The orientation of the error bars can be controlled with \ref setErrorType. By using \ref setData, you can supply the actual error data, either as symmetric error or plus/minus asymmetric errors. \ref QCPErrorBars only stores the error data. The absolute key/value position of each error bar will be adopted from the configured data plottable. The error data of the \ref QCPErrorBars are associated one-to-one via their index to the data points of the data plottable. You can directly access and manipulate the error bar data via \ref data. Set either of the plus/minus errors to NaN (qQNaN() or std::numeric_limits::quiet_NaN()) to not show the respective error bar on the data point at that index. \section qcperrorbars-appearance Changing the appearance The appearance of the error bars is defined by the pen (\ref setPen), and the width of the whiskers (\ref setWhiskerWidth). Further, the error bar backbones may leave a gap around the data point center to prevent that error bars are drawn too close to or even through scatter points. This gap size can be controlled via \ref setSymbolGap. */ /* start of documentation of inline functions */ /*! \fn QSharedPointer QCPErrorBars::data() const Returns a shared pointer to the internal data storage of type \ref QCPErrorBarsDataContainer. You may use it to directly manipulate the error values, which may be more convenient and faster than using the regular \ref setData methods. */ /* end of documentation of inline functions */ /*! Constructs an error bars plottable which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. It is also important that the \a keyAxis and \a valueAxis are the same for the error bars plottable and the data plottable that the error bars shall be drawn on (\ref setDataPlottable). The created \ref QCPErrorBars is automatically registered with the QCustomPlot instance inferred from \a keyAxis. This QCustomPlot instance takes ownership of the \ref QCPErrorBars, so do not delete it manually but use \ref QCustomPlot::removePlottable() instead. */ QCPErrorBars::QCPErrorBars(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable(keyAxis, valueAxis), mDataContainer(new QVector), mErrorType(etValueError), mWhiskerWidth(9), mSymbolGap(10) { setPen(QPen(Qt::black, 0)); setBrush(Qt::NoBrush); } QCPErrorBars::~QCPErrorBars() { } /*! \overload Replaces the current data container with the provided \a data container. Since a QSharedPointer is used, multiple \ref QCPErrorBars instances may share the same data container safely. Modifying the data in the container will then affect all \ref QCPErrorBars instances that share the container. Sharing can be achieved by simply exchanging the data containers wrapped in shared pointers: \snippet documentation/doc-code-snippets/mainwindow.cpp qcperrorbars-datasharing-1 If you do not wish to share containers, but create a copy from an existing container, assign the data containers directly: \snippet documentation/doc-code-snippets/mainwindow.cpp qcperrorbars-datasharing-2 (This uses different notation compared with other plottables, because the \ref QCPErrorBars uses a \c QVector as its data container, instead of a \ref QCPDataContainer.) \see addData */ void QCPErrorBars::setData(QSharedPointer data) { mDataContainer = data; } /*! \overload Sets symmetrical error values as specified in \a error. The errors will be associated one-to-one by the data point index to the associated data plottable (\ref setDataPlottable). You can directly access and manipulate the error bar data via \ref data. \see addData */ void QCPErrorBars::setData(const QVector &error) { mDataContainer->clear(); addData(error); } /*! \overload Sets asymmetrical errors as specified in \a errorMinus and \a errorPlus. The errors will be associated one-to-one by the data point index to the associated data plottable (\ref setDataPlottable). You can directly access and manipulate the error bar data via \ref data. \see addData */ void QCPErrorBars::setData(const QVector &errorMinus, const QVector &errorPlus) { mDataContainer->clear(); addData(errorMinus, errorPlus); } /*! Sets the data plottable to which the error bars will be applied. The error values specified e.g. via \ref setData will be associated one-to-one by the data point index to the data points of \a plottable. This means that the error bars will adopt the key/value coordinates of the data point with the same index. The passed \a plottable must be a one-dimensional plottable, i.e. it must implement the \ref QCPPlottableInterface1D. Further, it must not be a \ref QCPErrorBars instance itself. If either of these restrictions is violated, a corresponding qDebug output is generated, and the data plottable of this \ref QCPErrorBars instance is set to zero. For proper display, care must also be taken that the key and value axes of the \a plottable match those configured for this \ref QCPErrorBars instance. */ void QCPErrorBars::setDataPlottable(QCPAbstractPlottable *plottable) { if (plottable && qobject_cast(plottable)) { mDataPlottable = nullptr; qDebug() << Q_FUNC_INFO << "can't set another QCPErrorBars instance as data plottable"; return; } if (plottable && !plottable->interface1D()) { mDataPlottable = nullptr; qDebug() << Q_FUNC_INFO << "passed plottable doesn't implement 1d interface, can't associate with QCPErrorBars"; return; } mDataPlottable = plottable; } /*! Sets in which orientation the error bars shall appear on the data points. If your data needs both error dimensions, create two \ref QCPErrorBars with different \a type. */ void QCPErrorBars::setErrorType(ErrorType type) { mErrorType = type; } /*! Sets the width of the whiskers (the short bars at the end of the actual error bar backbones) to \a pixels. */ void QCPErrorBars::setWhiskerWidth(double pixels) { mWhiskerWidth = pixels; } /*! Sets the gap diameter around the data points that will be left out when drawing the error bar backbones. This gap prevents that error bars are drawn too close to or even through scatter points. */ void QCPErrorBars::setSymbolGap(double pixels) { mSymbolGap = pixels; } /*! \overload Adds symmetrical error values as specified in \a error. The errors will be associated one-to-one by the data point index to the associated data plottable (\ref setDataPlottable). You can directly access and manipulate the error bar data via \ref data. \see setData */ void QCPErrorBars::addData(const QVector &error) { addData(error, error); } /*! \overload Adds asymmetrical errors as specified in \a errorMinus and \a errorPlus. The errors will be associated one-to-one by the data point index to the associated data plottable (\ref setDataPlottable). You can directly access and manipulate the error bar data via \ref data. \see setData */ void QCPErrorBars::addData(const QVector &errorMinus, const QVector &errorPlus) { if (errorMinus.size() != errorPlus.size()) qDebug() << Q_FUNC_INFO << "minus and plus error vectors have different sizes:" << errorMinus.size() << errorPlus.size(); const int n = qMin(errorMinus.size(), errorPlus.size()); mDataContainer->reserve(n); for (int i=0; iappend(QCPErrorBarsData(errorMinus.at(i), errorPlus.at(i))); } /*! \overload Adds a single symmetrical error bar as specified in \a error. The errors will be associated one-to-one by the data point index to the associated data plottable (\ref setDataPlottable). You can directly access and manipulate the error bar data via \ref data. \see setData */ void QCPErrorBars::addData(double error) { mDataContainer->append(QCPErrorBarsData(error)); } /*! \overload Adds a single asymmetrical error bar as specified in \a errorMinus and \a errorPlus. The errors will be associated one-to-one by the data point index to the associated data plottable (\ref setDataPlottable). You can directly access and manipulate the error bar data via \ref data. \see setData */ void QCPErrorBars::addData(double errorMinus, double errorPlus) { mDataContainer->append(QCPErrorBarsData(errorMinus, errorPlus)); } /* inherits documentation from base class */ int QCPErrorBars::dataCount() const { return mDataContainer->size(); } /* inherits documentation from base class */ double QCPErrorBars::dataMainKey(int index) const { if (mDataPlottable) return mDataPlottable->interface1D()->dataMainKey(index); else qDebug() << Q_FUNC_INFO << "no data plottable set"; return 0; } /* inherits documentation from base class */ double QCPErrorBars::dataSortKey(int index) const { if (mDataPlottable) return mDataPlottable->interface1D()->dataSortKey(index); else qDebug() << Q_FUNC_INFO << "no data plottable set"; return 0; } /* inherits documentation from base class */ double QCPErrorBars::dataMainValue(int index) const { if (mDataPlottable) return mDataPlottable->interface1D()->dataMainValue(index); else qDebug() << Q_FUNC_INFO << "no data plottable set"; return 0; } /* inherits documentation from base class */ QCPRange QCPErrorBars::dataValueRange(int index) const { if (mDataPlottable) { const double value = mDataPlottable->interface1D()->dataMainValue(index); if (index >= 0 && index < mDataContainer->size() && mErrorType == etValueError) return {value-mDataContainer->at(index).errorMinus, value+mDataContainer->at(index).errorPlus}; else return {value, value}; } else { qDebug() << Q_FUNC_INFO << "no data plottable set"; return {}; } } /* inherits documentation from base class */ QPointF QCPErrorBars::dataPixelPosition(int index) const { if (mDataPlottable) return mDataPlottable->interface1D()->dataPixelPosition(index); else qDebug() << Q_FUNC_INFO << "no data plottable set"; return {}; } /* inherits documentation from base class */ bool QCPErrorBars::sortKeyIsMainKey() const { if (mDataPlottable) { return mDataPlottable->interface1D()->sortKeyIsMainKey(); } else { qDebug() << Q_FUNC_INFO << "no data plottable set"; return true; } } /*! \copydoc QCPPlottableInterface1D::selectTestRect */ QCPDataSelection QCPErrorBars::selectTestRect(const QRectF &rect, bool onlySelectable) const { QCPDataSelection result; if (!mDataPlottable) return result; if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return result; if (!mKeyAxis || !mValueAxis) return result; QCPErrorBarsDataContainer::const_iterator visibleBegin, visibleEnd; getVisibleDataBounds(visibleBegin, visibleEnd, QCPDataRange(0, dataCount())); QVector backbones, whiskers; for (QCPErrorBarsDataContainer::const_iterator it=visibleBegin; it!=visibleEnd; ++it) { backbones.clear(); whiskers.clear(); getErrorBarLines(it, backbones, whiskers); foreach (const QLineF &backbone, backbones) { if (rectIntersectsLine(rect, backbone)) { result.addDataRange(QCPDataRange(int(it-mDataContainer->constBegin()), int(it-mDataContainer->constBegin()+1)), false); break; } } } result.simplify(); return result; } /* inherits documentation from base class */ int QCPErrorBars::findBegin(double sortKey, bool expandedRange) const { if (mDataPlottable) { if (mDataContainer->isEmpty()) return 0; int beginIndex = mDataPlottable->interface1D()->findBegin(sortKey, expandedRange); if (beginIndex >= mDataContainer->size()) beginIndex = mDataContainer->size()-1; return beginIndex; } else qDebug() << Q_FUNC_INFO << "no data plottable set"; return 0; } /* inherits documentation from base class */ int QCPErrorBars::findEnd(double sortKey, bool expandedRange) const { if (mDataPlottable) { if (mDataContainer->isEmpty()) return 0; int endIndex = mDataPlottable->interface1D()->findEnd(sortKey, expandedRange); if (endIndex > mDataContainer->size()) endIndex = mDataContainer->size(); return endIndex; } else qDebug() << Q_FUNC_INFO << "no data plottable set"; return 0; } /*! Implements a selectTest specific to this plottable's point geometry. If \a details is not 0, it will be set to a \ref QCPDataSelection, describing the closest data point to \a pos. \seebaseclassmethod \ref QCPAbstractPlottable::selectTest */ double QCPErrorBars::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { if (!mDataPlottable) return -1; if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return -1; if (!mKeyAxis || !mValueAxis) return -1; if (mKeyAxis.data()->axisRect()->rect().contains(pos.toPoint()) || mParentPlot->interactions().testFlag(QCP::iSelectPlottablesBeyondAxisRect)) { QCPErrorBarsDataContainer::const_iterator closestDataPoint = mDataContainer->constEnd(); double result = pointDistance(pos, closestDataPoint); if (details) { int pointIndex = int(closestDataPoint-mDataContainer->constBegin()); details->setValue(QCPDataSelection(QCPDataRange(pointIndex, pointIndex+1))); } return result; } else return -1; } /* inherits documentation from base class */ void QCPErrorBars::draw(QCPPainter *painter) { if (!mDataPlottable) return; if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (mKeyAxis.data()->range().size() <= 0 || mDataContainer->isEmpty()) return; // if the sort key isn't the main key, we must check the visibility for each data point/error bar individually // (getVisibleDataBounds applies range restriction, but otherwise can only return full data range): bool checkPointVisibility = !mDataPlottable->interface1D()->sortKeyIsMainKey(); // check data validity if flag set: #ifdef QCUSTOMPLOT_CHECK_DATA QCPErrorBarsDataContainer::const_iterator it; for (it = mDataContainer->constBegin(); it != mDataContainer->constEnd(); ++it) { if (QCP::isInvalidData(it->errorMinus, it->errorPlus)) qDebug() << Q_FUNC_INFO << "Data point at index" << it-mDataContainer->constBegin() << "invalid." << "Plottable name:" << name(); } #endif applyDefaultAntialiasingHint(painter); painter->setBrush(Qt::NoBrush); // loop over and draw segments of unselected/selected data: QList selectedSegments, unselectedSegments, allSegments; getDataSegments(selectedSegments, unselectedSegments); allSegments << unselectedSegments << selectedSegments; QVector backbones, whiskers; for (int i=0; i= unselectedSegments.size(); if (isSelectedSegment && mSelectionDecorator) mSelectionDecorator->applyPen(painter); else painter->setPen(mPen); if (painter->pen().capStyle() == Qt::SquareCap) { QPen capFixPen(painter->pen()); capFixPen.setCapStyle(Qt::FlatCap); painter->setPen(capFixPen); } backbones.clear(); whiskers.clear(); for (QCPErrorBarsDataContainer::const_iterator it=begin; it!=end; ++it) { if (!checkPointVisibility || errorBarVisible(int(it-mDataContainer->constBegin()))) getErrorBarLines(it, backbones, whiskers); } painter->drawLines(backbones); painter->drawLines(whiskers); } // draw other selection decoration that isn't just line/scatter pens and brushes: if (mSelectionDecorator) mSelectionDecorator->drawDecoration(painter, selection()); } /* inherits documentation from base class */ void QCPErrorBars::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const { applyDefaultAntialiasingHint(painter); painter->setPen(mPen); if (mErrorType == etValueError && mValueAxis && mValueAxis->orientation() == Qt::Vertical) { painter->drawLine(QLineF(rect.center().x(), rect.top()+2, rect.center().x(), rect.bottom()-1)); painter->drawLine(QLineF(rect.center().x()-4, rect.top()+2, rect.center().x()+4, rect.top()+2)); painter->drawLine(QLineF(rect.center().x()-4, rect.bottom()-1, rect.center().x()+4, rect.bottom()-1)); } else { painter->drawLine(QLineF(rect.left()+2, rect.center().y(), rect.right()-2, rect.center().y())); painter->drawLine(QLineF(rect.left()+2, rect.center().y()-4, rect.left()+2, rect.center().y()+4)); painter->drawLine(QLineF(rect.right()-2, rect.center().y()-4, rect.right()-2, rect.center().y()+4)); } } /* inherits documentation from base class */ QCPRange QCPErrorBars::getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain) const { if (!mDataPlottable) { foundRange = false; return {}; } QCPRange range; bool haveLower = false; bool haveUpper = false; QCPErrorBarsDataContainer::const_iterator it; for (it = mDataContainer->constBegin(); it != mDataContainer->constEnd(); ++it) { if (mErrorType == etValueError) { // error bar doesn't extend in key dimension (except whisker but we ignore that here), so only use data point center const double current = mDataPlottable->interface1D()->dataMainKey(int(it-mDataContainer->constBegin())); if (qIsNaN(current)) continue; if (inSignDomain == QCP::sdBoth || (inSignDomain == QCP::sdNegative && current < 0) || (inSignDomain == QCP::sdPositive && current > 0)) { if (current < range.lower || !haveLower) { range.lower = current; haveLower = true; } if (current > range.upper || !haveUpper) { range.upper = current; haveUpper = true; } } } else // mErrorType == etKeyError { const double dataKey = mDataPlottable->interface1D()->dataMainKey(int(it-mDataContainer->constBegin())); if (qIsNaN(dataKey)) continue; // plus error: double current = dataKey + (qIsNaN(it->errorPlus) ? 0 : it->errorPlus); if (inSignDomain == QCP::sdBoth || (inSignDomain == QCP::sdNegative && current < 0) || (inSignDomain == QCP::sdPositive && current > 0)) { if (current > range.upper || !haveUpper) { range.upper = current; haveUpper = true; } } // minus error: current = dataKey - (qIsNaN(it->errorMinus) ? 0 : it->errorMinus); if (inSignDomain == QCP::sdBoth || (inSignDomain == QCP::sdNegative && current < 0) || (inSignDomain == QCP::sdPositive && current > 0)) { if (current < range.lower || !haveLower) { range.lower = current; haveLower = true; } } } } if (haveUpper && !haveLower) { range.lower = range.upper; haveLower = true; } else if (haveLower && !haveUpper) { range.upper = range.lower; haveUpper = true; } foundRange = haveLower && haveUpper; return range; } /* inherits documentation from base class */ QCPRange QCPErrorBars::getValueRange(bool &foundRange, QCP::SignDomain inSignDomain, const QCPRange &inKeyRange) const { if (!mDataPlottable) { foundRange = false; return {}; } QCPRange range; const bool restrictKeyRange = inKeyRange != QCPRange(); bool haveLower = false; bool haveUpper = false; QCPErrorBarsDataContainer::const_iterator itBegin = mDataContainer->constBegin(); QCPErrorBarsDataContainer::const_iterator itEnd = mDataContainer->constEnd(); if (mDataPlottable->interface1D()->sortKeyIsMainKey() && restrictKeyRange) { itBegin = mDataContainer->constBegin()+findBegin(inKeyRange.lower, false); itEnd = mDataContainer->constBegin()+findEnd(inKeyRange.upper, false); } for (QCPErrorBarsDataContainer::const_iterator it = itBegin; it != itEnd; ++it) { if (restrictKeyRange) { const double dataKey = mDataPlottable->interface1D()->dataMainKey(int(it-mDataContainer->constBegin())); if (dataKey < inKeyRange.lower || dataKey > inKeyRange.upper) continue; } if (mErrorType == etValueError) { const double dataValue = mDataPlottable->interface1D()->dataMainValue(int(it-mDataContainer->constBegin())); if (qIsNaN(dataValue)) continue; // plus error: double current = dataValue + (qIsNaN(it->errorPlus) ? 0 : it->errorPlus); if (inSignDomain == QCP::sdBoth || (inSignDomain == QCP::sdNegative && current < 0) || (inSignDomain == QCP::sdPositive && current > 0)) { if (current > range.upper || !haveUpper) { range.upper = current; haveUpper = true; } } // minus error: current = dataValue - (qIsNaN(it->errorMinus) ? 0 : it->errorMinus); if (inSignDomain == QCP::sdBoth || (inSignDomain == QCP::sdNegative && current < 0) || (inSignDomain == QCP::sdPositive && current > 0)) { if (current < range.lower || !haveLower) { range.lower = current; haveLower = true; } } } else // mErrorType == etKeyError { // error bar doesn't extend in value dimension (except whisker but we ignore that here), so only use data point center const double current = mDataPlottable->interface1D()->dataMainValue(int(it-mDataContainer->constBegin())); if (qIsNaN(current)) continue; if (inSignDomain == QCP::sdBoth || (inSignDomain == QCP::sdNegative && current < 0) || (inSignDomain == QCP::sdPositive && current > 0)) { if (current < range.lower || !haveLower) { range.lower = current; haveLower = true; } if (current > range.upper || !haveUpper) { range.upper = current; haveUpper = true; } } } } if (haveUpper && !haveLower) { range.lower = range.upper; haveLower = true; } else if (haveLower && !haveUpper) { range.upper = range.lower; haveUpper = true; } foundRange = haveLower && haveUpper; return range; } /*! \internal Calculates the lines that make up the error bar belonging to the data point \a it. The resulting lines are added to \a backbones and \a whiskers. The vectors are not cleared, so calling this method with different \a it but the same \a backbones and \a whiskers allows to accumulate lines for multiple data points. This method assumes that \a it is a valid iterator within the bounds of this \ref QCPErrorBars instance and within the bounds of the associated data plottable. */ void QCPErrorBars::getErrorBarLines(QCPErrorBarsDataContainer::const_iterator it, QVector &backbones, QVector &whiskers) const { if (!mDataPlottable) return; int index = int(it-mDataContainer->constBegin()); QPointF centerPixel = mDataPlottable->interface1D()->dataPixelPosition(index); if (qIsNaN(centerPixel.x()) || qIsNaN(centerPixel.y())) return; QCPAxis *errorAxis = mErrorType == etValueError ? mValueAxis.data() : mKeyAxis.data(); QCPAxis *orthoAxis = mErrorType == etValueError ? mKeyAxis.data() : mValueAxis.data(); const double centerErrorAxisPixel = errorAxis->orientation() == Qt::Horizontal ? centerPixel.x() : centerPixel.y(); const double centerOrthoAxisPixel = orthoAxis->orientation() == Qt::Horizontal ? centerPixel.x() : centerPixel.y(); const double centerErrorAxisCoord = errorAxis->pixelToCoord(centerErrorAxisPixel); // depending on plottable, this might be different from just mDataPlottable->interface1D()->dataMainKey/Value const double symbolGap = mSymbolGap*0.5*errorAxis->pixelOrientation(); // plus error: double errorStart, errorEnd; if (!qIsNaN(it->errorPlus)) { errorStart = centerErrorAxisPixel+symbolGap; errorEnd = errorAxis->coordToPixel(centerErrorAxisCoord+it->errorPlus); if (errorAxis->orientation() == Qt::Vertical) { if ((errorStart > errorEnd) != errorAxis->rangeReversed()) backbones.append(QLineF(centerOrthoAxisPixel, errorStart, centerOrthoAxisPixel, errorEnd)); whiskers.append(QLineF(centerOrthoAxisPixel-mWhiskerWidth*0.5, errorEnd, centerOrthoAxisPixel+mWhiskerWidth*0.5, errorEnd)); } else { if ((errorStart < errorEnd) != errorAxis->rangeReversed()) backbones.append(QLineF(errorStart, centerOrthoAxisPixel, errorEnd, centerOrthoAxisPixel)); whiskers.append(QLineF(errorEnd, centerOrthoAxisPixel-mWhiskerWidth*0.5, errorEnd, centerOrthoAxisPixel+mWhiskerWidth*0.5)); } } // minus error: if (!qIsNaN(it->errorMinus)) { errorStart = centerErrorAxisPixel-symbolGap; errorEnd = errorAxis->coordToPixel(centerErrorAxisCoord-it->errorMinus); if (errorAxis->orientation() == Qt::Vertical) { if ((errorStart < errorEnd) != errorAxis->rangeReversed()) backbones.append(QLineF(centerOrthoAxisPixel, errorStart, centerOrthoAxisPixel, errorEnd)); whiskers.append(QLineF(centerOrthoAxisPixel-mWhiskerWidth*0.5, errorEnd, centerOrthoAxisPixel+mWhiskerWidth*0.5, errorEnd)); } else { if ((errorStart > errorEnd) != errorAxis->rangeReversed()) backbones.append(QLineF(errorStart, centerOrthoAxisPixel, errorEnd, centerOrthoAxisPixel)); whiskers.append(QLineF(errorEnd, centerOrthoAxisPixel-mWhiskerWidth*0.5, errorEnd, centerOrthoAxisPixel+mWhiskerWidth*0.5)); } } } /*! \internal This method outputs the currently visible data range via \a begin and \a end. The returned range will also never exceed \a rangeRestriction. Since error bars with type \ref etKeyError may extend to arbitrarily positive and negative key coordinates relative to their data point key, this method checks all outer error bars whether they truly don't reach into the visible portion of the axis rect, by calling \ref errorBarVisible. On the other hand error bars with type \ref etValueError that are associated with data plottables whose sort key is equal to the main key (see \ref qcpdatacontainer-datatype "QCPDataContainer DataType") can be handled very efficiently by finding the visible range of error bars through binary search (\ref QCPPlottableInterface1D::findBegin and \ref QCPPlottableInterface1D::findEnd). If the plottable's sort key is not equal to the main key, this method returns the full data range, only restricted by \a rangeRestriction. Drawing optimization then has to be done on a point-by-point basis in the \ref draw method. */ void QCPErrorBars::getVisibleDataBounds(QCPErrorBarsDataContainer::const_iterator &begin, QCPErrorBarsDataContainer::const_iterator &end, const QCPDataRange &rangeRestriction) const { QCPAxis *keyAxis = mKeyAxis.data(); QCPAxis *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; end = mDataContainer->constEnd(); begin = end; return; } if (!mDataPlottable || rangeRestriction.isEmpty()) { end = mDataContainer->constEnd(); begin = end; return; } if (!mDataPlottable->interface1D()->sortKeyIsMainKey()) { // if the sort key isn't the main key, it's not possible to find a contiguous range of visible // data points, so this method then only applies the range restriction and otherwise returns // the full data range. Visibility checks must be done on a per-datapoin-basis during drawing QCPDataRange dataRange(0, mDataContainer->size()); dataRange = dataRange.bounded(rangeRestriction); begin = mDataContainer->constBegin()+dataRange.begin(); end = mDataContainer->constBegin()+dataRange.end(); return; } // get visible data range via interface from data plottable, and then restrict to available error data points: const int n = qMin(mDataContainer->size(), mDataPlottable->interface1D()->dataCount()); int beginIndex = mDataPlottable->interface1D()->findBegin(keyAxis->range().lower); int endIndex = mDataPlottable->interface1D()->findEnd(keyAxis->range().upper); int i = beginIndex; while (i > 0 && i < n && i > rangeRestriction.begin()) { if (errorBarVisible(i)) beginIndex = i; --i; } i = endIndex; while (i >= 0 && i < n && i < rangeRestriction.end()) { if (errorBarVisible(i)) endIndex = i+1; ++i; } QCPDataRange dataRange(beginIndex, endIndex); dataRange = dataRange.bounded(rangeRestriction.bounded(QCPDataRange(0, mDataContainer->size()))); begin = mDataContainer->constBegin()+dataRange.begin(); end = mDataContainer->constBegin()+dataRange.end(); } /*! \internal Calculates the minimum distance in pixels the error bars' representation has from the given \a pixelPoint. This is used to determine whether the error bar was clicked or not, e.g. in \ref selectTest. The closest data point to \a pixelPoint is returned in \a closestData. */ double QCPErrorBars::pointDistance(const QPointF &pixelPoint, QCPErrorBarsDataContainer::const_iterator &closestData) const { closestData = mDataContainer->constEnd(); if (!mDataPlottable || mDataContainer->isEmpty()) return -1.0; if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return -1.0; } QCPErrorBarsDataContainer::const_iterator begin, end; getVisibleDataBounds(begin, end, QCPDataRange(0, dataCount())); // calculate minimum distances to error backbones (whiskers are ignored for speed) and find closestData iterator: double minDistSqr = (std::numeric_limits::max)(); QVector backbones, whiskers; for (QCPErrorBarsDataContainer::const_iterator it=begin; it!=end; ++it) { getErrorBarLines(it, backbones, whiskers); foreach (const QLineF &backbone, backbones) { const double currentDistSqr = QCPVector2D(pixelPoint).distanceSquaredToLine(backbone); if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestData = it; } } } return qSqrt(minDistSqr); } /*! \internal \note This method is identical to \ref QCPAbstractPlottable1D::getDataSegments but needs to be reproduced here since the \ref QCPErrorBars plottable, as a special case that doesn't have its own key/value data coordinates, doesn't derive from \ref QCPAbstractPlottable1D. See the documentation there for details. */ void QCPErrorBars::getDataSegments(QList &selectedSegments, QList &unselectedSegments) const { selectedSegments.clear(); unselectedSegments.clear(); if (mSelectable == QCP::stWhole) // stWhole selection type draws the entire plottable with selected style if mSelection isn't empty { if (selected()) selectedSegments << QCPDataRange(0, dataCount()); else unselectedSegments << QCPDataRange(0, dataCount()); } else { QCPDataSelection sel(selection()); sel.simplify(); selectedSegments = sel.dataRanges(); unselectedSegments = sel.inverse(QCPDataRange(0, dataCount())).dataRanges(); } } /*! \internal Returns whether the error bar at the specified \a index is visible within the current key axis range. This method assumes for performance reasons without checking that the key axis, the value axis, and the data plottable (\ref setDataPlottable) are not \c nullptr and that \a index is within valid bounds of this \ref QCPErrorBars instance and the bounds of the data plottable. */ bool QCPErrorBars::errorBarVisible(int index) const { QPointF centerPixel = mDataPlottable->interface1D()->dataPixelPosition(index); const double centerKeyPixel = mKeyAxis->orientation() == Qt::Horizontal ? centerPixel.x() : centerPixel.y(); if (qIsNaN(centerKeyPixel)) return false; double keyMin, keyMax; if (mErrorType == etKeyError) { const double centerKey = mKeyAxis->pixelToCoord(centerKeyPixel); const double errorPlus = mDataContainer->at(index).errorPlus; const double errorMinus = mDataContainer->at(index).errorMinus; keyMax = centerKey+(qIsNaN(errorPlus) ? 0 : errorPlus); keyMin = centerKey-(qIsNaN(errorMinus) ? 0 : errorMinus); } else // mErrorType == etValueError { keyMax = mKeyAxis->pixelToCoord(centerKeyPixel+mWhiskerWidth*0.5*mKeyAxis->pixelOrientation()); keyMin = mKeyAxis->pixelToCoord(centerKeyPixel-mWhiskerWidth*0.5*mKeyAxis->pixelOrientation()); } return ((keyMax > mKeyAxis->range().lower) && (keyMin < mKeyAxis->range().upper)); } /*! \internal Returns whether \a line intersects (or is contained in) \a pixelRect. \a line is assumed to be either perfectly horizontal or perfectly vertical, as is the case for error bar lines. */ bool QCPErrorBars::rectIntersectsLine(const QRectF &pixelRect, const QLineF &line) const { if (pixelRect.left() > line.x1() && pixelRect.left() > line.x2()) return false; else if (pixelRect.right() < line.x1() && pixelRect.right() < line.x2()) return false; else if (pixelRect.top() > line.y1() && pixelRect.top() > line.y2()) return false; else if (pixelRect.bottom() < line.y1() && pixelRect.bottom() < line.y2()) return false; else return true; } /* end of 'src/plottables/plottable-errorbar.cpp' */ /* including file 'src/items/item-straightline.cpp' */ /* modified 2021-03-29T02:30:44, size 7596 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemStraightLine //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemStraightLine \brief A straight line that spans infinitely in both directions \image html QCPItemStraightLine.png "Straight line example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a point1 and \a point2, which define the straight line. */ /*! Creates a straight line item and sets default values. The created item is automatically registered with \a parentPlot. This QCustomPlot instance takes ownership of the item, so do not delete it manually but use QCustomPlot::removeItem() instead. */ QCPItemStraightLine::QCPItemStraightLine(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), point1(createPosition(QLatin1String("point1"))), point2(createPosition(QLatin1String("point2"))) { point1->setCoords(0, 0); point2->setCoords(1, 1); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue,2)); } QCPItemStraightLine::~QCPItemStraightLine() { } /*! Sets the pen that will be used to draw the line \see setSelectedPen */ void QCPItemStraightLine::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line when selected \see setPen, setSelected */ void QCPItemStraightLine::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /* inherits documentation from base class */ double QCPItemStraightLine::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; return QCPVector2D(pos).distanceToStraightLine(point1->pixelPosition(), point2->pixelPosition()-point1->pixelPosition()); } /* inherits documentation from base class */ void QCPItemStraightLine::draw(QCPPainter *painter) { QCPVector2D start(point1->pixelPosition()); QCPVector2D end(point2->pixelPosition()); // get visible segment of straight line inside clipRect: int clipPad = qCeil(mainPen().widthF()); QLineF line = getRectClippedStraightLine(start, end-start, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad)); // paint visible segment, if existent: if (!line.isNull()) { painter->setPen(mainPen()); painter->drawLine(line); } } /*! \internal Returns the section of the straight line defined by \a base and direction vector \a vec, that is visible in the specified \a rect. This is a helper function for \ref draw. */ QLineF QCPItemStraightLine::getRectClippedStraightLine(const QCPVector2D &base, const QCPVector2D &vec, const QRect &rect) const { double bx, by; double gamma; QLineF result; if (vec.x() == 0 && vec.y() == 0) return result; if (qFuzzyIsNull(vec.x())) // line is vertical { // check top of rect: bx = rect.left(); by = rect.top(); gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y(); if (gamma >= 0 && gamma <= rect.width()) result.setLine(bx+gamma, rect.top(), bx+gamma, rect.bottom()); // no need to check bottom because we know line is vertical } else if (qFuzzyIsNull(vec.y())) // line is horizontal { // check left of rect: bx = rect.left(); by = rect.top(); gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x(); if (gamma >= 0 && gamma <= rect.height()) result.setLine(rect.left(), by+gamma, rect.right(), by+gamma); // no need to check right because we know line is horizontal } else // line is skewed { QList pointVectors; // check top of rect: bx = rect.left(); by = rect.top(); gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y(); if (gamma >= 0 && gamma <= rect.width()) pointVectors.append(QCPVector2D(bx+gamma, by)); // check bottom of rect: bx = rect.left(); by = rect.bottom(); gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y(); if (gamma >= 0 && gamma <= rect.width()) pointVectors.append(QCPVector2D(bx+gamma, by)); // check left of rect: bx = rect.left(); by = rect.top(); gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x(); if (gamma >= 0 && gamma <= rect.height()) pointVectors.append(QCPVector2D(bx, by+gamma)); // check right of rect: bx = rect.right(); by = rect.top(); gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x(); if (gamma >= 0 && gamma <= rect.height()) pointVectors.append(QCPVector2D(bx, by+gamma)); // evaluate points: if (pointVectors.size() == 2) { result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF()); } else if (pointVectors.size() > 2) { // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance: double distSqrMax = 0; QCPVector2D pv1, pv2; for (int i=0; i distSqrMax) { pv1 = pointVectors.at(i); pv2 = pointVectors.at(k); distSqrMax = distSqr; } } } result.setPoints(pv1.toPointF(), pv2.toPointF()); } } return result; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemStraightLine::mainPen() const { return mSelected ? mSelectedPen : mPen; } /* end of 'src/items/item-straightline.cpp' */ /* including file 'src/items/item-line.cpp' */ /* modified 2021-03-29T02:30:44, size 8525 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemLine //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemLine \brief A line from one point to another \image html QCPItemLine.png "Line example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a start and \a end, which define the end points of the line. With \ref setHead and \ref setTail you may set different line ending styles, e.g. to create an arrow. */ /*! Creates a line item and sets default values. The created item is automatically registered with \a parentPlot. This QCustomPlot instance takes ownership of the item, so do not delete it manually but use QCustomPlot::removeItem() instead. */ QCPItemLine::QCPItemLine(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), start(createPosition(QLatin1String("start"))), end(createPosition(QLatin1String("end"))) { start->setCoords(0, 0); end->setCoords(1, 1); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue,2)); } QCPItemLine::~QCPItemLine() { } /*! Sets the pen that will be used to draw the line \see setSelectedPen */ void QCPItemLine::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line when selected \see setPen, setSelected */ void QCPItemLine::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the line ending style of the head. The head corresponds to the \a end position. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle here, e.g. \code setHead(QCPLineEnding::esSpikeArrow) \endcode \see setTail */ void QCPItemLine::setHead(const QCPLineEnding &head) { mHead = head; } /*! Sets the line ending style of the tail. The tail corresponds to the \a start position. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle here, e.g. \code setTail(QCPLineEnding::esSpikeArrow) \endcode \see setHead */ void QCPItemLine::setTail(const QCPLineEnding &tail) { mTail = tail; } /* inherits documentation from base class */ double QCPItemLine::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; return qSqrt(QCPVector2D(pos).distanceSquaredToLine(start->pixelPosition(), end->pixelPosition())); } /* inherits documentation from base class */ void QCPItemLine::draw(QCPPainter *painter) { QCPVector2D startVec(start->pixelPosition()); QCPVector2D endVec(end->pixelPosition()); if (qFuzzyIsNull((startVec-endVec).lengthSquared())) return; // get visible segment of straight line inside clipRect: int clipPad = int(qMax(mHead.boundingDistance(), mTail.boundingDistance())); clipPad = qMax(clipPad, qCeil(mainPen().widthF())); QLineF line = getRectClippedLine(startVec, endVec, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad)); // paint visible segment, if existent: if (!line.isNull()) { painter->setPen(mainPen()); painter->drawLine(line); painter->setBrush(Qt::SolidPattern); if (mTail.style() != QCPLineEnding::esNone) mTail.draw(painter, startVec, startVec-endVec); if (mHead.style() != QCPLineEnding::esNone) mHead.draw(painter, endVec, endVec-startVec); } } /*! \internal Returns the section of the line defined by \a start and \a end, that is visible in the specified \a rect. This is a helper function for \ref draw. */ QLineF QCPItemLine::getRectClippedLine(const QCPVector2D &start, const QCPVector2D &end, const QRect &rect) const { bool containsStart = rect.contains(qRound(start.x()), qRound(start.y())); bool containsEnd = rect.contains(qRound(end.x()), qRound(end.y())); if (containsStart && containsEnd) return {start.toPointF(), end.toPointF()}; QCPVector2D base = start; QCPVector2D vec = end-start; double bx, by; double gamma, mu; QLineF result; QList pointVectors; if (!qFuzzyIsNull(vec.y())) // line is not horizontal { // check top of rect: bx = rect.left(); by = rect.top(); mu = (by-base.y())/vec.y(); if (mu >= 0 && mu <= 1) { gamma = base.x()-bx + mu*vec.x(); if (gamma >= 0 && gamma <= rect.width()) pointVectors.append(QCPVector2D(bx+gamma, by)); } // check bottom of rect: bx = rect.left(); by = rect.bottom(); mu = (by-base.y())/vec.y(); if (mu >= 0 && mu <= 1) { gamma = base.x()-bx + mu*vec.x(); if (gamma >= 0 && gamma <= rect.width()) pointVectors.append(QCPVector2D(bx+gamma, by)); } } if (!qFuzzyIsNull(vec.x())) // line is not vertical { // check left of rect: bx = rect.left(); by = rect.top(); mu = (bx-base.x())/vec.x(); if (mu >= 0 && mu <= 1) { gamma = base.y()-by + mu*vec.y(); if (gamma >= 0 && gamma <= rect.height()) pointVectors.append(QCPVector2D(bx, by+gamma)); } // check right of rect: bx = rect.right(); by = rect.top(); mu = (bx-base.x())/vec.x(); if (mu >= 0 && mu <= 1) { gamma = base.y()-by + mu*vec.y(); if (gamma >= 0 && gamma <= rect.height()) pointVectors.append(QCPVector2D(bx, by+gamma)); } } if (containsStart) pointVectors.append(start); if (containsEnd) pointVectors.append(end); // evaluate points: if (pointVectors.size() == 2) { result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF()); } else if (pointVectors.size() > 2) { // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance: double distSqrMax = 0; QCPVector2D pv1, pv2; for (int i=0; i distSqrMax) { pv1 = pointVectors.at(i); pv2 = pointVectors.at(k); distSqrMax = distSqr; } } } result.setPoints(pv1.toPointF(), pv2.toPointF()); } return result; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemLine::mainPen() const { return mSelected ? mSelectedPen : mPen; } /* end of 'src/items/item-line.cpp' */ /* including file 'src/items/item-curve.cpp' */ /* modified 2021-03-29T02:30:44, size 7273 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemCurve //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemCurve \brief A curved line from one point to another \image html QCPItemCurve.png "Curve example. Blue dotted circles are anchors, solid blue discs are positions." It has four positions, \a start and \a end, which define the end points of the line, and two control points which define the direction the line exits from the start and the direction from which it approaches the end: \a startDir and \a endDir. With \ref setHead and \ref setTail you may set different line ending styles, e.g. to create an arrow. Often it is desirable for the control points to stay at fixed relative positions to the start/end point. This can be achieved by setting the parent anchor e.g. of \a startDir simply to \a start, and then specify the desired pixel offset with QCPItemPosition::setCoords on \a startDir. */ /*! Creates a curve item and sets default values. The created item is automatically registered with \a parentPlot. This QCustomPlot instance takes ownership of the item, so do not delete it manually but use QCustomPlot::removeItem() instead. */ QCPItemCurve::QCPItemCurve(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), start(createPosition(QLatin1String("start"))), startDir(createPosition(QLatin1String("startDir"))), endDir(createPosition(QLatin1String("endDir"))), end(createPosition(QLatin1String("end"))) { start->setCoords(0, 0); startDir->setCoords(0.5, 0); endDir->setCoords(0, 0.5); end->setCoords(1, 1); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue,2)); } QCPItemCurve::~QCPItemCurve() { } /*! Sets the pen that will be used to draw the line \see setSelectedPen */ void QCPItemCurve::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line when selected \see setPen, setSelected */ void QCPItemCurve::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the line ending style of the head. The head corresponds to the \a end position. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle here, e.g. \code setHead(QCPLineEnding::esSpikeArrow) \endcode \see setTail */ void QCPItemCurve::setHead(const QCPLineEnding &head) { mHead = head; } /*! Sets the line ending style of the tail. The tail corresponds to the \a start position. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle here, e.g. \code setTail(QCPLineEnding::esSpikeArrow) \endcode \see setHead */ void QCPItemCurve::setTail(const QCPLineEnding &tail) { mTail = tail; } /* inherits documentation from base class */ double QCPItemCurve::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; QPointF startVec(start->pixelPosition()); QPointF startDirVec(startDir->pixelPosition()); QPointF endDirVec(endDir->pixelPosition()); QPointF endVec(end->pixelPosition()); QPainterPath cubicPath(startVec); cubicPath.cubicTo(startDirVec, endDirVec, endVec); QList polygons = cubicPath.toSubpathPolygons(); if (polygons.isEmpty()) return -1; const QPolygonF polygon = polygons.first(); QCPVector2D p(pos); double minDistSqr = (std::numeric_limits::max)(); for (int i=1; ipixelPosition()); QCPVector2D startDirVec(startDir->pixelPosition()); QCPVector2D endDirVec(endDir->pixelPosition()); QCPVector2D endVec(end->pixelPosition()); if ((endVec-startVec).length() > 1e10) // too large curves cause crash return; QPainterPath cubicPath(startVec.toPointF()); cubicPath.cubicTo(startDirVec.toPointF(), endDirVec.toPointF(), endVec.toPointF()); // paint visible segment, if existent: const int clipEnlarge = qCeil(mainPen().widthF()); QRect clip = clipRect().adjusted(-clipEnlarge, -clipEnlarge, clipEnlarge, clipEnlarge); QRect cubicRect = cubicPath.controlPointRect().toRect(); if (cubicRect.isEmpty()) // may happen when start and end exactly on same x or y position cubicRect.adjust(0, 0, 1, 1); if (clip.intersects(cubicRect)) { painter->setPen(mainPen()); painter->drawPath(cubicPath); painter->setBrush(Qt::SolidPattern); if (mTail.style() != QCPLineEnding::esNone) mTail.draw(painter, startVec, M_PI-cubicPath.angleAtPercent(0)/180.0*M_PI); if (mHead.style() != QCPLineEnding::esNone) mHead.draw(painter, endVec, -cubicPath.angleAtPercent(1)/180.0*M_PI); } } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemCurve::mainPen() const { return mSelected ? mSelectedPen : mPen; } /* end of 'src/items/item-curve.cpp' */ /* including file 'src/items/item-rect.cpp' */ /* modified 2021-03-29T02:30:44, size 6472 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemRect //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemRect \brief A rectangle \image html QCPItemRect.png "Rectangle example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a topLeft and \a bottomRight, which define the rectangle. */ /*! Creates a rectangle item and sets default values. The created item is automatically registered with \a parentPlot. This QCustomPlot instance takes ownership of the item, so do not delete it manually but use QCustomPlot::removeItem() instead. */ QCPItemRect::QCPItemRect(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), topLeft(createPosition(QLatin1String("topLeft"))), bottomRight(createPosition(QLatin1String("bottomRight"))), top(createAnchor(QLatin1String("top"), aiTop)), topRight(createAnchor(QLatin1String("topRight"), aiTopRight)), right(createAnchor(QLatin1String("right"), aiRight)), bottom(createAnchor(QLatin1String("bottom"), aiBottom)), bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)), left(createAnchor(QLatin1String("left"), aiLeft)) { topLeft->setCoords(0, 1); bottomRight->setCoords(1, 0); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue,2)); setBrush(Qt::NoBrush); setSelectedBrush(Qt::NoBrush); } QCPItemRect::~QCPItemRect() { } /*! Sets the pen that will be used to draw the line of the rectangle \see setSelectedPen, setBrush */ void QCPItemRect::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line of the rectangle when selected \see setPen, setSelected */ void QCPItemRect::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the brush that will be used to fill the rectangle. To disable filling, set \a brush to Qt::NoBrush. \see setSelectedBrush, setPen */ void QCPItemRect::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the brush that will be used to fill the rectangle when selected. To disable filling, set \a brush to Qt::NoBrush. \see setBrush */ void QCPItemRect::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /* inherits documentation from base class */ double QCPItemRect::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; QRectF rect = QRectF(topLeft->pixelPosition(), bottomRight->pixelPosition()).normalized(); bool filledRect = mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0; return rectDistance(rect, pos, filledRect); } /* inherits documentation from base class */ void QCPItemRect::draw(QCPPainter *painter) { QPointF p1 = topLeft->pixelPosition(); QPointF p2 = bottomRight->pixelPosition(); if (p1.toPoint() == p2.toPoint()) return; QRectF rect = QRectF(p1, p2).normalized(); double clipPad = mainPen().widthF(); QRectF boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad); if (boundingRect.intersects(clipRect())) // only draw if bounding rect of rect item is visible in cliprect { painter->setPen(mainPen()); painter->setBrush(mainBrush()); painter->drawRect(rect); } } /* inherits documentation from base class */ QPointF QCPItemRect::anchorPixelPosition(int anchorId) const { QRectF rect = QRectF(topLeft->pixelPosition(), bottomRight->pixelPosition()); switch (anchorId) { case aiTop: return (rect.topLeft()+rect.topRight())*0.5; case aiTopRight: return rect.topRight(); case aiRight: return (rect.topRight()+rect.bottomRight())*0.5; case aiBottom: return (rect.bottomLeft()+rect.bottomRight())*0.5; case aiBottomLeft: return rect.bottomLeft(); case aiLeft: return (rect.topLeft()+rect.bottomLeft())*0.5; } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return {}; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemRect::mainPen() const { return mSelected ? mSelectedPen : mPen; } /*! \internal Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item is not selected and mSelectedBrush when it is. */ QBrush QCPItemRect::mainBrush() const { return mSelected ? mSelectedBrush : mBrush; } /* end of 'src/items/item-rect.cpp' */ /* including file 'src/items/item-text.cpp' */ /* modified 2021-03-29T02:30:44, size 13335 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemText //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemText \brief A text label \image html QCPItemText.png "Text example. Blue dotted circles are anchors, solid blue discs are positions." Its position is defined by the member \a position and the setting of \ref setPositionAlignment. The latter controls which part of the text rect shall be aligned with \a position. The text alignment itself (i.e. left, center, right) can be controlled with \ref setTextAlignment. The text may be rotated around the \a position point with \ref setRotation. */ /*! Creates a text item and sets default values. The created item is automatically registered with \a parentPlot. This QCustomPlot instance takes ownership of the item, so do not delete it manually but use QCustomPlot::removeItem() instead. */ QCPItemText::QCPItemText(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), position(createPosition(QLatin1String("position"))), topLeft(createAnchor(QLatin1String("topLeft"), aiTopLeft)), top(createAnchor(QLatin1String("top"), aiTop)), topRight(createAnchor(QLatin1String("topRight"), aiTopRight)), right(createAnchor(QLatin1String("right"), aiRight)), bottomRight(createAnchor(QLatin1String("bottomRight"), aiBottomRight)), bottom(createAnchor(QLatin1String("bottom"), aiBottom)), bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)), left(createAnchor(QLatin1String("left"), aiLeft)), mText(QLatin1String("text")), mPositionAlignment(Qt::AlignCenter), mTextAlignment(Qt::AlignTop|Qt::AlignHCenter), mRotation(0) { position->setCoords(0, 0); setPen(Qt::NoPen); setSelectedPen(Qt::NoPen); setBrush(Qt::NoBrush); setSelectedBrush(Qt::NoBrush); setColor(Qt::black); setSelectedColor(Qt::blue); } QCPItemText::~QCPItemText() { } /*! Sets the color of the text. */ void QCPItemText::setColor(const QColor &color) { mColor = color; } /*! Sets the color of the text that will be used when the item is selected. */ void QCPItemText::setSelectedColor(const QColor &color) { mSelectedColor = color; } /*! Sets the pen that will be used do draw a rectangular border around the text. To disable the border, set \a pen to Qt::NoPen. \see setSelectedPen, setBrush, setPadding */ void QCPItemText::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used do draw a rectangular border around the text, when the item is selected. To disable the border, set \a pen to Qt::NoPen. \see setPen */ void QCPItemText::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the brush that will be used do fill the background of the text. To disable the background, set \a brush to Qt::NoBrush. \see setSelectedBrush, setPen, setPadding */ void QCPItemText::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the brush that will be used do fill the background of the text, when the item is selected. To disable the background, set \a brush to Qt::NoBrush. \see setBrush */ void QCPItemText::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /*! Sets the font of the text. \see setSelectedFont, setColor */ void QCPItemText::setFont(const QFont &font) { mFont = font; } /*! Sets the font of the text that will be used when the item is selected. \see setFont */ void QCPItemText::setSelectedFont(const QFont &font) { mSelectedFont = font; } /*! Sets the text that will be displayed. Multi-line texts are supported by inserting a line break character, e.g. '\n'. \see setFont, setColor, setTextAlignment */ void QCPItemText::setText(const QString &text) { mText = text; } /*! Sets which point of the text rect shall be aligned with \a position. Examples: \li If \a alignment is Qt::AlignHCenter | Qt::AlignTop, the text will be positioned such that the top of the text rect will be horizontally centered on \a position. \li If \a alignment is Qt::AlignLeft | Qt::AlignBottom, \a position will indicate the bottom left corner of the text rect. If you want to control the alignment of (multi-lined) text within the text rect, use \ref setTextAlignment. */ void QCPItemText::setPositionAlignment(Qt::Alignment alignment) { mPositionAlignment = alignment; } /*! Controls how (multi-lined) text is aligned inside the text rect (typically Qt::AlignLeft, Qt::AlignCenter or Qt::AlignRight). */ void QCPItemText::setTextAlignment(Qt::Alignment alignment) { mTextAlignment = alignment; } /*! Sets the angle in degrees by which the text (and the text rectangle, if visible) will be rotated around \a position. */ void QCPItemText::setRotation(double degrees) { mRotation = degrees; } /*! Sets the distance between the border of the text rectangle and the text. The appearance (and visibility) of the text rectangle can be controlled with \ref setPen and \ref setBrush. */ void QCPItemText::setPadding(const QMargins &padding) { mPadding = padding; } /* inherits documentation from base class */ double QCPItemText::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; // The rect may be rotated, so we transform the actual clicked pos to the rotated // coordinate system, so we can use the normal rectDistance function for non-rotated rects: QPointF positionPixels(position->pixelPosition()); QTransform inputTransform; inputTransform.translate(positionPixels.x(), positionPixels.y()); inputTransform.rotate(-mRotation); inputTransform.translate(-positionPixels.x(), -positionPixels.y()); QPointF rotatedPos = inputTransform.map(pos); QFontMetrics fontMetrics(mFont); QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText); QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom()); QPointF textPos = getTextDrawPoint(positionPixels, textBoxRect, mPositionAlignment); textBoxRect.moveTopLeft(textPos.toPoint()); return rectDistance(textBoxRect, rotatedPos, true); } /* inherits documentation from base class */ void QCPItemText::draw(QCPPainter *painter) { QPointF pos(position->pixelPosition()); QTransform transform = painter->transform(); transform.translate(pos.x(), pos.y()); if (!qFuzzyIsNull(mRotation)) transform.rotate(mRotation); painter->setFont(mainFont()); QRect textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText); QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom()); QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation textRect.moveTopLeft(textPos.toPoint()+QPoint(mPadding.left(), mPadding.top())); textBoxRect.moveTopLeft(textPos.toPoint()); int clipPad = qCeil(mainPen().widthF()); QRect boundingRect = textBoxRect.adjusted(-clipPad, -clipPad, clipPad, clipPad); if (transform.mapRect(boundingRect).intersects(painter->transform().mapRect(clipRect()))) { painter->setTransform(transform); if ((mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0) || (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)) { painter->setPen(mainPen()); painter->setBrush(mainBrush()); painter->drawRect(textBoxRect); } painter->setBrush(Qt::NoBrush); painter->setPen(QPen(mainColor())); painter->drawText(textRect, Qt::TextDontClip|mTextAlignment, mText); } } /* inherits documentation from base class */ QPointF QCPItemText::anchorPixelPosition(int anchorId) const { // get actual rect points (pretty much copied from draw function): QPointF pos(position->pixelPosition()); QTransform transform; transform.translate(pos.x(), pos.y()); if (!qFuzzyIsNull(mRotation)) transform.rotate(mRotation); QFontMetrics fontMetrics(mainFont()); QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText); QRectF textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom()); QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation textBoxRect.moveTopLeft(textPos.toPoint()); QPolygonF rectPoly = transform.map(QPolygonF(textBoxRect)); switch (anchorId) { case aiTopLeft: return rectPoly.at(0); case aiTop: return (rectPoly.at(0)+rectPoly.at(1))*0.5; case aiTopRight: return rectPoly.at(1); case aiRight: return (rectPoly.at(1)+rectPoly.at(2))*0.5; case aiBottomRight: return rectPoly.at(2); case aiBottom: return (rectPoly.at(2)+rectPoly.at(3))*0.5; case aiBottomLeft: return rectPoly.at(3); case aiLeft: return (rectPoly.at(3)+rectPoly.at(0))*0.5; } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return {}; } /*! \internal Returns the point that must be given to the QPainter::drawText function (which expects the top left point of the text rect), according to the position \a pos, the text bounding box \a rect and the requested \a positionAlignment. For example, if \a positionAlignment is Qt::AlignLeft | Qt::AlignBottom the returned point will be shifted upward by the height of \a rect, starting from \a pos. So if the text is finally drawn at that point, the lower left corner of the resulting text rect is at \a pos. */ QPointF QCPItemText::getTextDrawPoint(const QPointF &pos, const QRectF &rect, Qt::Alignment positionAlignment) const { if (positionAlignment == 0 || positionAlignment == (Qt::AlignLeft|Qt::AlignTop)) return pos; QPointF result = pos; // start at top left if (positionAlignment.testFlag(Qt::AlignHCenter)) result.rx() -= rect.width()/2.0; else if (positionAlignment.testFlag(Qt::AlignRight)) result.rx() -= rect.width(); if (positionAlignment.testFlag(Qt::AlignVCenter)) result.ry() -= rect.height()/2.0; else if (positionAlignment.testFlag(Qt::AlignBottom)) result.ry() -= rect.height(); return result; } /*! \internal Returns the font that should be used for drawing text. Returns mFont when the item is not selected and mSelectedFont when it is. */ QFont QCPItemText::mainFont() const { return mSelected ? mSelectedFont : mFont; } /*! \internal Returns the color that should be used for drawing text. Returns mColor when the item is not selected and mSelectedColor when it is. */ QColor QCPItemText::mainColor() const { return mSelected ? mSelectedColor : mColor; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemText::mainPen() const { return mSelected ? mSelectedPen : mPen; } /*! \internal Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item is not selected and mSelectedBrush when it is. */ QBrush QCPItemText::mainBrush() const { return mSelected ? mSelectedBrush : mBrush; } /* end of 'src/items/item-text.cpp' */ /* including file 'src/items/item-ellipse.cpp' */ /* modified 2021-03-29T02:30:44, size 7881 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemEllipse //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemEllipse \brief An ellipse \image html QCPItemEllipse.png "Ellipse example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a topLeft and \a bottomRight, which define the rect the ellipse will be drawn in. */ /*! Creates an ellipse item and sets default values. The created item is automatically registered with \a parentPlot. This QCustomPlot instance takes ownership of the item, so do not delete it manually but use QCustomPlot::removeItem() instead. */ QCPItemEllipse::QCPItemEllipse(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), topLeft(createPosition(QLatin1String("topLeft"))), bottomRight(createPosition(QLatin1String("bottomRight"))), topLeftRim(createAnchor(QLatin1String("topLeftRim"), aiTopLeftRim)), top(createAnchor(QLatin1String("top"), aiTop)), topRightRim(createAnchor(QLatin1String("topRightRim"), aiTopRightRim)), right(createAnchor(QLatin1String("right"), aiRight)), bottomRightRim(createAnchor(QLatin1String("bottomRightRim"), aiBottomRightRim)), bottom(createAnchor(QLatin1String("bottom"), aiBottom)), bottomLeftRim(createAnchor(QLatin1String("bottomLeftRim"), aiBottomLeftRim)), left(createAnchor(QLatin1String("left"), aiLeft)), center(createAnchor(QLatin1String("center"), aiCenter)) { topLeft->setCoords(0, 1); bottomRight->setCoords(1, 0); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue, 2)); setBrush(Qt::NoBrush); setSelectedBrush(Qt::NoBrush); } QCPItemEllipse::~QCPItemEllipse() { } /*! Sets the pen that will be used to draw the line of the ellipse \see setSelectedPen, setBrush */ void QCPItemEllipse::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line of the ellipse when selected \see setPen, setSelected */ void QCPItemEllipse::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the brush that will be used to fill the ellipse. To disable filling, set \a brush to Qt::NoBrush. \see setSelectedBrush, setPen */ void QCPItemEllipse::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the brush that will be used to fill the ellipse when selected. To disable filling, set \a brush to Qt::NoBrush. \see setBrush */ void QCPItemEllipse::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /* inherits documentation from base class */ double QCPItemEllipse::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; QPointF p1 = topLeft->pixelPosition(); QPointF p2 = bottomRight->pixelPosition(); QPointF center((p1+p2)/2.0); double a = qAbs(p1.x()-p2.x())/2.0; double b = qAbs(p1.y()-p2.y())/2.0; double x = pos.x()-center.x(); double y = pos.y()-center.y(); // distance to border: double c = 1.0/qSqrt(x*x/(a*a)+y*y/(b*b)); double result = qAbs(c-1)*qSqrt(x*x+y*y); // filled ellipse, allow click inside to count as hit: if (result > mParentPlot->selectionTolerance()*0.99 && mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0) { if (x*x/(a*a) + y*y/(b*b) <= 1) result = mParentPlot->selectionTolerance()*0.99; } return result; } /* inherits documentation from base class */ void QCPItemEllipse::draw(QCPPainter *painter) { QPointF p1 = topLeft->pixelPosition(); QPointF p2 = bottomRight->pixelPosition(); if (p1.toPoint() == p2.toPoint()) return; QRectF ellipseRect = QRectF(p1, p2).normalized(); const int clipEnlarge = qCeil(mainPen().widthF()); QRect clip = clipRect().adjusted(-clipEnlarge, -clipEnlarge, clipEnlarge, clipEnlarge); if (ellipseRect.intersects(clip)) // only draw if bounding rect of ellipse is visible in cliprect { painter->setPen(mainPen()); painter->setBrush(mainBrush()); #ifdef __EXCEPTIONS try // drawEllipse sometimes throws exceptions if ellipse is too big { #endif painter->drawEllipse(ellipseRect); #ifdef __EXCEPTIONS } catch (...) { qDebug() << Q_FUNC_INFO << "Item too large for memory, setting invisible"; setVisible(false); } #endif } } /* inherits documentation from base class */ QPointF QCPItemEllipse::anchorPixelPosition(int anchorId) const { QRectF rect = QRectF(topLeft->pixelPosition(), bottomRight->pixelPosition()); switch (anchorId) { case aiTopLeftRim: return rect.center()+(rect.topLeft()-rect.center())*1/qSqrt(2); case aiTop: return (rect.topLeft()+rect.topRight())*0.5; case aiTopRightRim: return rect.center()+(rect.topRight()-rect.center())*1/qSqrt(2); case aiRight: return (rect.topRight()+rect.bottomRight())*0.5; case aiBottomRightRim: return rect.center()+(rect.bottomRight()-rect.center())*1/qSqrt(2); case aiBottom: return (rect.bottomLeft()+rect.bottomRight())*0.5; case aiBottomLeftRim: return rect.center()+(rect.bottomLeft()-rect.center())*1/qSqrt(2); case aiLeft: return (rect.topLeft()+rect.bottomLeft())*0.5; case aiCenter: return (rect.topLeft()+rect.bottomRight())*0.5; } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return {}; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemEllipse::mainPen() const { return mSelected ? mSelectedPen : mPen; } /*! \internal Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item is not selected and mSelectedBrush when it is. */ QBrush QCPItemEllipse::mainBrush() const { return mSelected ? mSelectedBrush : mBrush; } /* end of 'src/items/item-ellipse.cpp' */ /* including file 'src/items/item-pixmap.cpp' */ /* modified 2021-03-29T02:30:44, size 10622 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemPixmap //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemPixmap \brief An arbitrary pixmap \image html QCPItemPixmap.png "Pixmap example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a topLeft and \a bottomRight, which define the rectangle the pixmap will be drawn in. Depending on the scale setting (\ref setScaled), the pixmap will be either scaled to fit the rectangle or be drawn aligned to the topLeft position. If scaling is enabled and \a topLeft is further to the bottom/right than \a bottomRight (as shown on the right side of the example image), the pixmap will be flipped in the respective orientations. */ /*! Creates a rectangle item and sets default values. The created item is automatically registered with \a parentPlot. This QCustomPlot instance takes ownership of the item, so do not delete it manually but use QCustomPlot::removeItem() instead. */ QCPItemPixmap::QCPItemPixmap(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), topLeft(createPosition(QLatin1String("topLeft"))), bottomRight(createPosition(QLatin1String("bottomRight"))), top(createAnchor(QLatin1String("top"), aiTop)), topRight(createAnchor(QLatin1String("topRight"), aiTopRight)), right(createAnchor(QLatin1String("right"), aiRight)), bottom(createAnchor(QLatin1String("bottom"), aiBottom)), bottomLeft(createAnchor(QLatin1String("bottomLeft"), aiBottomLeft)), left(createAnchor(QLatin1String("left"), aiLeft)), mScaled(false), mScaledPixmapInvalidated(true), mAspectRatioMode(Qt::KeepAspectRatio), mTransformationMode(Qt::SmoothTransformation) { topLeft->setCoords(0, 1); bottomRight->setCoords(1, 0); setPen(Qt::NoPen); setSelectedPen(QPen(Qt::blue)); } QCPItemPixmap::~QCPItemPixmap() { } /*! Sets the pixmap that will be displayed. */ void QCPItemPixmap::setPixmap(const QPixmap &pixmap) { mPixmap = pixmap; mScaledPixmapInvalidated = true; if (mPixmap.isNull()) qDebug() << Q_FUNC_INFO << "pixmap is null"; } /*! Sets whether the pixmap will be scaled to fit the rectangle defined by the \a topLeft and \a bottomRight positions. */ void QCPItemPixmap::setScaled(bool scaled, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformationMode) { mScaled = scaled; mAspectRatioMode = aspectRatioMode; mTransformationMode = transformationMode; mScaledPixmapInvalidated = true; } /*! Sets the pen that will be used to draw a border around the pixmap. \see setSelectedPen, setBrush */ void QCPItemPixmap::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw a border around the pixmap when selected \see setPen, setSelected */ void QCPItemPixmap::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /* inherits documentation from base class */ double QCPItemPixmap::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; return rectDistance(getFinalRect(), pos, true); } /* inherits documentation from base class */ void QCPItemPixmap::draw(QCPPainter *painter) { bool flipHorz = false; bool flipVert = false; QRect rect = getFinalRect(&flipHorz, &flipVert); int clipPad = mainPen().style() == Qt::NoPen ? 0 : qCeil(mainPen().widthF()); QRect boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad); if (boundingRect.intersects(clipRect())) { updateScaledPixmap(rect, flipHorz, flipVert); painter->drawPixmap(rect.topLeft(), mScaled ? mScaledPixmap : mPixmap); QPen pen = mainPen(); if (pen.style() != Qt::NoPen) { painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->drawRect(rect); } } } /* inherits documentation from base class */ QPointF QCPItemPixmap::anchorPixelPosition(int anchorId) const { bool flipHorz = false; bool flipVert = false; QRect rect = getFinalRect(&flipHorz, &flipVert); // we actually want denormal rects (negative width/height) here, so restore // the flipped state: if (flipHorz) rect.adjust(rect.width(), 0, -rect.width(), 0); if (flipVert) rect.adjust(0, rect.height(), 0, -rect.height()); switch (anchorId) { case aiTop: return (rect.topLeft()+rect.topRight())*0.5; case aiTopRight: return rect.topRight(); case aiRight: return (rect.topRight()+rect.bottomRight())*0.5; case aiBottom: return (rect.bottomLeft()+rect.bottomRight())*0.5; case aiBottomLeft: return rect.bottomLeft(); case aiLeft: return (rect.topLeft()+rect.bottomLeft())*0.5; } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return {}; } /*! \internal Creates the buffered scaled image (\a mScaledPixmap) to fit the specified \a finalRect. The parameters \a flipHorz and \a flipVert control whether the resulting image shall be flipped horizontally or vertically. (This is used when \a topLeft is further to the bottom/right than \a bottomRight.) This function only creates the scaled pixmap when the buffered pixmap has a different size than the expected result, so calling this function repeatedly, e.g. in the \ref draw function, does not cause expensive rescaling every time. If scaling is disabled, sets mScaledPixmap to a null QPixmap. */ void QCPItemPixmap::updateScaledPixmap(QRect finalRect, bool flipHorz, bool flipVert) { if (mPixmap.isNull()) return; if (mScaled) { #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED double devicePixelRatio = mPixmap.devicePixelRatio(); #else double devicePixelRatio = 1.0; #endif if (finalRect.isNull()) finalRect = getFinalRect(&flipHorz, &flipVert); if (mScaledPixmapInvalidated || finalRect.size() != mScaledPixmap.size()/devicePixelRatio) { mScaledPixmap = mPixmap.scaled(finalRect.size()*devicePixelRatio, mAspectRatioMode, mTransformationMode); if (flipHorz || flipVert) mScaledPixmap = QPixmap::fromImage(mScaledPixmap.toImage().mirrored(flipHorz, flipVert)); #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED mScaledPixmap.setDevicePixelRatio(devicePixelRatio); #endif } } else if (!mScaledPixmap.isNull()) mScaledPixmap = QPixmap(); mScaledPixmapInvalidated = false; } /*! \internal Returns the final (tight) rect the pixmap is drawn in, depending on the current item positions and scaling settings. The output parameters \a flippedHorz and \a flippedVert return whether the pixmap should be drawn flipped horizontally or vertically in the returned rect. (The returned rect itself is always normalized, i.e. the top left corner of the rect is actually further to the top/left than the bottom right corner). This is the case when the item position \a topLeft is further to the bottom/right than \a bottomRight. If scaling is disabled, returns a rect with size of the original pixmap and the top left corner aligned with the item position \a topLeft. The position \a bottomRight is ignored. */ QRect QCPItemPixmap::getFinalRect(bool *flippedHorz, bool *flippedVert) const { QRect result; bool flipHorz = false; bool flipVert = false; QPoint p1 = topLeft->pixelPosition().toPoint(); QPoint p2 = bottomRight->pixelPosition().toPoint(); if (p1 == p2) return {p1, QSize(0, 0)}; if (mScaled) { QSize newSize = QSize(p2.x()-p1.x(), p2.y()-p1.y()); QPoint topLeft = p1; if (newSize.width() < 0) { flipHorz = true; newSize.rwidth() *= -1; topLeft.setX(p2.x()); } if (newSize.height() < 0) { flipVert = true; newSize.rheight() *= -1; topLeft.setY(p2.y()); } QSize scaledSize = mPixmap.size(); #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED scaledSize /= mPixmap.devicePixelRatio(); scaledSize.scale(newSize*mPixmap.devicePixelRatio(), mAspectRatioMode); #else scaledSize.scale(newSize, mAspectRatioMode); #endif result = QRect(topLeft, scaledSize); } else { #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED result = QRect(p1, mPixmap.size()/mPixmap.devicePixelRatio()); #else result = QRect(p1, mPixmap.size()); #endif } if (flippedHorz) *flippedHorz = flipHorz; if (flippedVert) *flippedVert = flipVert; return result; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemPixmap::mainPen() const { return mSelected ? mSelectedPen : mPen; } /* end of 'src/items/item-pixmap.cpp' */ /* including file 'src/items/item-tracer.cpp' */ /* modified 2021-03-29T02:30:44, size 14645 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemTracer //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemTracer \brief Item that sticks to QCPGraph data points \image html QCPItemTracer.png "Tracer example. Blue dotted circles are anchors, solid blue discs are positions." The tracer can be connected with a QCPGraph via \ref setGraph. Then it will automatically adopt the coordinate axes of the graph and update its \a position to be on the graph's data. This means the key stays controllable via \ref setGraphKey, but the value will follow the graph data. If a QCPGraph is connected, note that setting the coordinates of the tracer item directly via \a position will have no effect because they will be overriden in the next redraw (this is when the coordinate update happens). If the specified key in \ref setGraphKey is outside the key bounds of the graph, the tracer will stay at the corresponding end of the graph. With \ref setInterpolating you may specify whether the tracer may only stay exactly on data points or whether it interpolates data points linearly, if given a key that lies between two data points of the graph. The tracer has different visual styles, see \ref setStyle. It is also possible to make the tracer have no own visual appearance (set the style to \ref tsNone), and just connect other item positions to the tracer \a position (used as an anchor) via \ref QCPItemPosition::setParentAnchor. \note The tracer position is only automatically updated upon redraws. So when the data of the graph changes and immediately afterwards (without a redraw) the position coordinates of the tracer are retrieved, they will not reflect the updated data of the graph. In this case \ref updatePosition must be called manually, prior to reading the tracer coordinates. */ /*! Creates a tracer item and sets default values. The created item is automatically registered with \a parentPlot. This QCustomPlot instance takes ownership of the item, so do not delete it manually but use QCustomPlot::removeItem() instead. */ QCPItemTracer::QCPItemTracer(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), position(createPosition(QLatin1String("position"))), mSize(6), mStyle(tsCrosshair), mGraph(nullptr), mGraphKey(0), mInterpolating(false) { position->setCoords(0, 0); setBrush(Qt::NoBrush); setSelectedBrush(Qt::NoBrush); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue, 2)); } QCPItemTracer::~QCPItemTracer() { } /*! Sets the pen that will be used to draw the line of the tracer \see setSelectedPen, setBrush */ void QCPItemTracer::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line of the tracer when selected \see setPen, setSelected */ void QCPItemTracer::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the brush that will be used to draw any fills of the tracer \see setSelectedBrush, setPen */ void QCPItemTracer::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the brush that will be used to draw any fills of the tracer, when selected. \see setBrush, setSelected */ void QCPItemTracer::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /*! Sets the size of the tracer in pixels, if the style supports setting a size (e.g. \ref tsSquare does, \ref tsCrosshair does not). */ void QCPItemTracer::setSize(double size) { mSize = size; } /*! Sets the style/visual appearance of the tracer. If you only want to use the tracer \a position as an anchor for other items, set \a style to \ref tsNone. */ void QCPItemTracer::setStyle(QCPItemTracer::TracerStyle style) { mStyle = style; } /*! Sets the QCPGraph this tracer sticks to. The tracer \a position will be set to type QCPItemPosition::ptPlotCoords and the axes will be set to the axes of \a graph. To free the tracer from any graph, set \a graph to \c nullptr. The tracer \a position can then be placed freely like any other item position. This is the state the tracer will assume when its graph gets deleted while still attached to it. \see setGraphKey */ void QCPItemTracer::setGraph(QCPGraph *graph) { if (graph) { if (graph->parentPlot() == mParentPlot) { position->setType(QCPItemPosition::ptPlotCoords); position->setAxes(graph->keyAxis(), graph->valueAxis()); mGraph = graph; updatePosition(); } else qDebug() << Q_FUNC_INFO << "graph isn't in same QCustomPlot instance as this item"; } else { mGraph = nullptr; } } /*! Sets the key of the graph's data point the tracer will be positioned at. This is the only free coordinate of a tracer when attached to a graph. Depending on \ref setInterpolating, the tracer will be either positioned on the data point closest to \a key, or will stay exactly at \a key and interpolate the value linearly. \see setGraph, setInterpolating */ void QCPItemTracer::setGraphKey(double key) { mGraphKey = key; } /*! Sets whether the value of the graph's data points shall be interpolated, when positioning the tracer. If \a enabled is set to false and a key is given with \ref setGraphKey, the tracer is placed on the data point of the graph which is closest to the key, but which is not necessarily exactly there. If \a enabled is true, the tracer will be positioned exactly at the specified key, and the appropriate value will be interpolated from the graph's data points linearly. \see setGraph, setGraphKey */ void QCPItemTracer::setInterpolating(bool enabled) { mInterpolating = enabled; } /* inherits documentation from base class */ double QCPItemTracer::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; QPointF center(position->pixelPosition()); double w = mSize/2.0; QRect clip = clipRect(); switch (mStyle) { case tsNone: return -1; case tsPlus: { if (clipRect().intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) return qSqrt(qMin(QCPVector2D(pos).distanceSquaredToLine(center+QPointF(-w, 0), center+QPointF(w, 0)), QCPVector2D(pos).distanceSquaredToLine(center+QPointF(0, -w), center+QPointF(0, w)))); break; } case tsCrosshair: { return qSqrt(qMin(QCPVector2D(pos).distanceSquaredToLine(QCPVector2D(clip.left(), center.y()), QCPVector2D(clip.right(), center.y())), QCPVector2D(pos).distanceSquaredToLine(QCPVector2D(center.x(), clip.top()), QCPVector2D(center.x(), clip.bottom())))); } case tsCircle: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) { // distance to border: double centerDist = QCPVector2D(center-pos).length(); double circleLine = w; double result = qAbs(centerDist-circleLine); // filled ellipse, allow click inside to count as hit: if (result > mParentPlot->selectionTolerance()*0.99 && mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0) { if (centerDist <= circleLine) result = mParentPlot->selectionTolerance()*0.99; } return result; } break; } case tsSquare: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) { QRectF rect = QRectF(center-QPointF(w, w), center+QPointF(w, w)); bool filledRect = mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0; return rectDistance(rect, pos, filledRect); } break; } } return -1; } /* inherits documentation from base class */ void QCPItemTracer::draw(QCPPainter *painter) { updatePosition(); if (mStyle == tsNone) return; painter->setPen(mainPen()); painter->setBrush(mainBrush()); QPointF center(position->pixelPosition()); double w = mSize/2.0; QRect clip = clipRect(); switch (mStyle) { case tsNone: return; case tsPlus: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) { painter->drawLine(QLineF(center+QPointF(-w, 0), center+QPointF(w, 0))); painter->drawLine(QLineF(center+QPointF(0, -w), center+QPointF(0, w))); } break; } case tsCrosshair: { if (center.y() > clip.top() && center.y() < clip.bottom()) painter->drawLine(QLineF(clip.left(), center.y(), clip.right(), center.y())); if (center.x() > clip.left() && center.x() < clip.right()) painter->drawLine(QLineF(center.x(), clip.top(), center.x(), clip.bottom())); break; } case tsCircle: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) painter->drawEllipse(center, w, w); break; } case tsSquare: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) painter->drawRect(QRectF(center-QPointF(w, w), center+QPointF(w, w))); break; } } } /*! If the tracer is connected with a graph (\ref setGraph), this function updates the tracer's \a position to reside on the graph data, depending on the configured key (\ref setGraphKey). It is called automatically on every redraw and normally doesn't need to be called manually. One exception is when you want to read the tracer coordinates via \a position and are not sure that the graph's data (or the tracer key with \ref setGraphKey) hasn't changed since the last redraw. In that situation, call this function before accessing \a position, to make sure you don't get out-of-date coordinates. If there is no graph set on this tracer, this function does nothing. */ void QCPItemTracer::updatePosition() { if (mGraph) { if (mParentPlot->hasPlottable(mGraph)) { if (mGraph->data()->size() > 1) { QCPGraphDataContainer::const_iterator first = mGraph->data()->constBegin(); QCPGraphDataContainer::const_iterator last = mGraph->data()->constEnd()-1; if (mGraphKey <= first->key) position->setCoords(first->key, first->value); else if (mGraphKey >= last->key) position->setCoords(last->key, last->value); else { QCPGraphDataContainer::const_iterator it = mGraph->data()->findBegin(mGraphKey); if (it != mGraph->data()->constEnd()) // mGraphKey is not exactly on last iterator, but somewhere between iterators { QCPGraphDataContainer::const_iterator prevIt = it; ++it; // won't advance to constEnd because we handled that case (mGraphKey >= last->key) before if (mInterpolating) { // interpolate between iterators around mGraphKey: double slope = 0; if (!qFuzzyCompare(double(it->key), double(prevIt->key))) slope = (it->value-prevIt->value)/(it->key-prevIt->key); position->setCoords(mGraphKey, (mGraphKey-prevIt->key)*slope+prevIt->value); } else { // find iterator with key closest to mGraphKey: if (mGraphKey < (prevIt->key+it->key)*0.5) position->setCoords(prevIt->key, prevIt->value); else position->setCoords(it->key, it->value); } } else // mGraphKey is exactly on last iterator (should actually be caught when comparing first/last keys, but this is a failsafe for fp uncertainty) position->setCoords(it->key, it->value); } } else if (mGraph->data()->size() == 1) { QCPGraphDataContainer::const_iterator it = mGraph->data()->constBegin(); position->setCoords(it->key, it->value); } else qDebug() << Q_FUNC_INFO << "graph has no data"; } else qDebug() << Q_FUNC_INFO << "graph not contained in QCustomPlot instance (anymore)"; } } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemTracer::mainPen() const { return mSelected ? mSelectedPen : mPen; } /*! \internal Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item is not selected and mSelectedBrush when it is. */ QBrush QCPItemTracer::mainBrush() const { return mSelected ? mSelectedBrush : mBrush; } /* end of 'src/items/item-tracer.cpp' */ /* including file 'src/items/item-bracket.cpp' */ /* modified 2021-03-29T02:30:44, size 10705 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPItemBracket //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPItemBracket \brief A bracket for referencing/highlighting certain parts in the plot. \image html QCPItemBracket.png "Bracket example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a left and \a right, which define the span of the bracket. If \a left is actually farther to the left than \a right, the bracket is opened to the bottom, as shown in the example image. The bracket supports multiple styles via \ref setStyle. The length, i.e. how far the bracket stretches away from the embraced span, can be controlled with \ref setLength. \image html QCPItemBracket-length.png
Demonstrating the effect of different values for \ref setLength, for styles \ref bsCalligraphic and \ref bsSquare. Anchors and positions are displayed for reference.
It provides an anchor \a center, to allow connection of other items, e.g. an arrow (QCPItemLine or QCPItemCurve) or a text label (QCPItemText), to the bracket. */ /*! Creates a bracket item and sets default values. The created item is automatically registered with \a parentPlot. This QCustomPlot instance takes ownership of the item, so do not delete it manually but use QCustomPlot::removeItem() instead. */ QCPItemBracket::QCPItemBracket(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), left(createPosition(QLatin1String("left"))), right(createPosition(QLatin1String("right"))), center(createAnchor(QLatin1String("center"), aiCenter)), mLength(8), mStyle(bsCalligraphic) { left->setCoords(0, 0); right->setCoords(1, 1); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue, 2)); } QCPItemBracket::~QCPItemBracket() { } /*! Sets the pen that will be used to draw the bracket. Note that when the style is \ref bsCalligraphic, only the color will be taken from the pen, the stroke and width are ignored. To change the apparent stroke width of a calligraphic bracket, use \ref setLength, which has a similar effect. \see setSelectedPen */ void QCPItemBracket::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the bracket when selected \see setPen, setSelected */ void QCPItemBracket::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the \a length in pixels how far the bracket extends in the direction towards the embraced span of the bracket (i.e. perpendicular to the left-right-direction) \image html QCPItemBracket-length.png
Demonstrating the effect of different values for \ref setLength, for styles \ref bsCalligraphic and \ref bsSquare. Anchors and positions are displayed for reference.
*/ void QCPItemBracket::setLength(double length) { mLength = length; } /*! Sets the style of the bracket, i.e. the shape/visual appearance. \see setPen */ void QCPItemBracket::setStyle(QCPItemBracket::BracketStyle style) { mStyle = style; } /* inherits documentation from base class */ double QCPItemBracket::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { Q_UNUSED(details) if (onlySelectable && !mSelectable) return -1; QCPVector2D p(pos); QCPVector2D leftVec(left->pixelPosition()); QCPVector2D rightVec(right->pixelPosition()); if (leftVec.toPoint() == rightVec.toPoint()) return -1; QCPVector2D widthVec = (rightVec-leftVec)*0.5; QCPVector2D lengthVec = widthVec.perpendicular().normalized()*mLength; QCPVector2D centerVec = (rightVec+leftVec)*0.5-lengthVec; switch (mStyle) { case QCPItemBracket::bsSquare: case QCPItemBracket::bsRound: { double a = p.distanceSquaredToLine(centerVec-widthVec, centerVec+widthVec); double b = p.distanceSquaredToLine(centerVec-widthVec+lengthVec, centerVec-widthVec); double c = p.distanceSquaredToLine(centerVec+widthVec+lengthVec, centerVec+widthVec); return qSqrt(qMin(qMin(a, b), c)); } case QCPItemBracket::bsCurly: case QCPItemBracket::bsCalligraphic: { double a = p.distanceSquaredToLine(centerVec-widthVec*0.75+lengthVec*0.15, centerVec+lengthVec*0.3); double b = p.distanceSquaredToLine(centerVec-widthVec+lengthVec*0.7, centerVec-widthVec*0.75+lengthVec*0.15); double c = p.distanceSquaredToLine(centerVec+widthVec*0.75+lengthVec*0.15, centerVec+lengthVec*0.3); double d = p.distanceSquaredToLine(centerVec+widthVec+lengthVec*0.7, centerVec+widthVec*0.75+lengthVec*0.15); return qSqrt(qMin(qMin(a, b), qMin(c, d))); } } return -1; } /* inherits documentation from base class */ void QCPItemBracket::draw(QCPPainter *painter) { QCPVector2D leftVec(left->pixelPosition()); QCPVector2D rightVec(right->pixelPosition()); if (leftVec.toPoint() == rightVec.toPoint()) return; QCPVector2D widthVec = (rightVec-leftVec)*0.5; QCPVector2D lengthVec = widthVec.perpendicular().normalized()*mLength; QCPVector2D centerVec = (rightVec+leftVec)*0.5-lengthVec; QPolygon boundingPoly; boundingPoly << leftVec.toPoint() << rightVec.toPoint() << (rightVec-lengthVec).toPoint() << (leftVec-lengthVec).toPoint(); const int clipEnlarge = qCeil(mainPen().widthF()); QRect clip = clipRect().adjusted(-clipEnlarge, -clipEnlarge, clipEnlarge, clipEnlarge); if (clip.intersects(boundingPoly.boundingRect())) { painter->setPen(mainPen()); switch (mStyle) { case bsSquare: { painter->drawLine((centerVec+widthVec).toPointF(), (centerVec-widthVec).toPointF()); painter->drawLine((centerVec+widthVec).toPointF(), (centerVec+widthVec+lengthVec).toPointF()); painter->drawLine((centerVec-widthVec).toPointF(), (centerVec-widthVec+lengthVec).toPointF()); break; } case bsRound: { painter->setBrush(Qt::NoBrush); QPainterPath path; path.moveTo((centerVec+widthVec+lengthVec).toPointF()); path.cubicTo((centerVec+widthVec).toPointF(), (centerVec+widthVec).toPointF(), centerVec.toPointF()); path.cubicTo((centerVec-widthVec).toPointF(), (centerVec-widthVec).toPointF(), (centerVec-widthVec+lengthVec).toPointF()); painter->drawPath(path); break; } case bsCurly: { painter->setBrush(Qt::NoBrush); QPainterPath path; path.moveTo((centerVec+widthVec+lengthVec).toPointF()); path.cubicTo((centerVec+widthVec-lengthVec*0.8).toPointF(), (centerVec+0.4*widthVec+lengthVec).toPointF(), centerVec.toPointF()); path.cubicTo((centerVec-0.4*widthVec+lengthVec).toPointF(), (centerVec-widthVec-lengthVec*0.8).toPointF(), (centerVec-widthVec+lengthVec).toPointF()); painter->drawPath(path); break; } case bsCalligraphic: { painter->setPen(Qt::NoPen); painter->setBrush(QBrush(mainPen().color())); QPainterPath path; path.moveTo((centerVec+widthVec+lengthVec).toPointF()); path.cubicTo((centerVec+widthVec-lengthVec*0.8).toPointF(), (centerVec+0.4*widthVec+0.8*lengthVec).toPointF(), centerVec.toPointF()); path.cubicTo((centerVec-0.4*widthVec+0.8*lengthVec).toPointF(), (centerVec-widthVec-lengthVec*0.8).toPointF(), (centerVec-widthVec+lengthVec).toPointF()); path.cubicTo((centerVec-widthVec-lengthVec*0.5).toPointF(), (centerVec-0.2*widthVec+1.2*lengthVec).toPointF(), (centerVec+lengthVec*0.2).toPointF()); path.cubicTo((centerVec+0.2*widthVec+1.2*lengthVec).toPointF(), (centerVec+widthVec-lengthVec*0.5).toPointF(), (centerVec+widthVec+lengthVec).toPointF()); painter->drawPath(path); break; } } } } /* inherits documentation from base class */ QPointF QCPItemBracket::anchorPixelPosition(int anchorId) const { QCPVector2D leftVec(left->pixelPosition()); QCPVector2D rightVec(right->pixelPosition()); if (leftVec.toPoint() == rightVec.toPoint()) return leftVec.toPointF(); QCPVector2D widthVec = (rightVec-leftVec)*0.5; QCPVector2D lengthVec = widthVec.perpendicular().normalized()*mLength; QCPVector2D centerVec = (rightVec+leftVec)*0.5-lengthVec; switch (anchorId) { case aiCenter: return centerVec.toPointF(); } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return {}; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemBracket::mainPen() const { return mSelected ? mSelectedPen : mPen; } /* end of 'src/items/item-bracket.cpp' */ /* including file 'src/polar/radialaxis.cpp' */ /* modified 2021-03-29T02:30:44, size 49415 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPolarAxisRadial //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPolarAxisRadial \brief The radial axis inside a radial plot \warning In this QCustomPlot version, polar plots are a tech preview. Expect documentation and functionality to be incomplete, as well as changing public interfaces in the future. Each axis holds an instance of QCPAxisTicker which is used to generate the tick coordinates and tick labels. You can access the currently installed \ref ticker or set a new one (possibly one of the specialized subclasses, or your own subclass) via \ref setTicker. For details, see the documentation of QCPAxisTicker. */ /* start of documentation of inline functions */ /*! \fn QSharedPointer QCPPolarAxisRadial::ticker() const Returns a modifiable shared pointer to the currently installed axis ticker. The axis ticker is responsible for generating the tick positions and tick labels of this axis. You can access the \ref QCPAxisTicker with this method and modify basic properties such as the approximate tick count (\ref QCPAxisTicker::setTickCount). You can gain more control over the axis ticks by setting a different \ref QCPAxisTicker subclass, see the documentation there. A new axis ticker can be set with \ref setTicker. Since the ticker is stored in the axis as a shared pointer, multiple axes may share the same axis ticker simply by passing the same shared pointer to multiple axes. \see setTicker */ /* end of documentation of inline functions */ /* start of documentation of signals */ /*! \fn void QCPPolarAxisRadial::rangeChanged(const QCPRange &newRange) This signal is emitted when the range of this axis has changed. You can connect it to the \ref setRange slot of another axis to communicate the new range to the other axis, in order for it to be synchronized. You may also manipulate/correct the range with \ref setRange in a slot connected to this signal. This is useful if for example a maximum range span shall not be exceeded, or if the lower/upper range shouldn't go beyond certain values (see \ref QCPRange::bounded). For example, the following slot would limit the x axis to ranges between 0 and 10: \code customPlot->xAxis->setRange(newRange.bounded(0, 10)) \endcode */ /*! \fn void QCPPolarAxisRadial::rangeChanged(const QCPRange &newRange, const QCPRange &oldRange) \overload Additionally to the new range, this signal also provides the previous range held by the axis as \a oldRange. */ /*! \fn void QCPPolarAxisRadial::scaleTypeChanged(QCPPolarAxisRadial::ScaleType scaleType); This signal is emitted when the scale type changes, by calls to \ref setScaleType */ /*! \fn void QCPPolarAxisRadial::selectionChanged(QCPPolarAxisRadial::SelectableParts selection) This signal is emitted when the selection state of this axis has changed, either by user interaction or by a direct call to \ref setSelectedParts. */ /*! \fn void QCPPolarAxisRadial::selectableChanged(const QCPPolarAxisRadial::SelectableParts &parts); This signal is emitted when the selectability changes, by calls to \ref setSelectableParts */ /* end of documentation of signals */ /*! Constructs an Axis instance of Type \a type for the axis rect \a parent. Usually it isn't necessary to instantiate axes directly, because you can let QCustomPlot create them for you with \ref QCPAxisRect::addAxis. If you want to use own QCPAxis-subclasses however, create them manually and then inject them also via \ref QCPAxisRect::addAxis. */ QCPPolarAxisRadial::QCPPolarAxisRadial(QCPPolarAxisAngular *parent) : QCPLayerable(parent->parentPlot(), QString(), parent), mRangeDrag(true), mRangeZoom(true), mRangeZoomFactor(0.85), // axis base: mAngularAxis(parent), mAngle(45), mAngleReference(arAngularAxis), mSelectableParts(spAxis | spTickLabels | spAxisLabel), mSelectedParts(spNone), mBasePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), mSelectedBasePen(QPen(Qt::blue, 2)), // axis label: mLabelPadding(0), mLabel(), mLabelFont(mParentPlot->font()), mSelectedLabelFont(QFont(mLabelFont.family(), mLabelFont.pointSize(), QFont::Bold)), mLabelColor(Qt::black), mSelectedLabelColor(Qt::blue), // tick labels: // mTickLabelPadding(0), in label painter mTickLabels(true), // mTickLabelRotation(0), in label painter mTickLabelFont(mParentPlot->font()), mSelectedTickLabelFont(QFont(mTickLabelFont.family(), mTickLabelFont.pointSize(), QFont::Bold)), mTickLabelColor(Qt::black), mSelectedTickLabelColor(Qt::blue), mNumberPrecision(6), mNumberFormatChar('g'), mNumberBeautifulPowers(true), mNumberMultiplyCross(false), // ticks and subticks: mTicks(true), mSubTicks(true), mTickLengthIn(5), mTickLengthOut(0), mSubTickLengthIn(2), mSubTickLengthOut(0), mTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), mSelectedTickPen(QPen(Qt::blue, 2)), mSubTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), mSelectedSubTickPen(QPen(Qt::blue, 2)), // scale and range: mRange(0, 5), mRangeReversed(false), mScaleType(stLinear), // internal members: mRadius(1), // non-zero initial value, will be overwritten in ::update() according to inner rect mTicker(new QCPAxisTicker), mLabelPainter(mParentPlot) { setParent(parent); setAntialiased(true); setTickLabelPadding(5); setTickLabelRotation(0); setTickLabelMode(lmUpright); mLabelPainter.setAnchorReferenceType(QCPLabelPainterPrivate::artTangent); mLabelPainter.setAbbreviateDecimalPowers(false); } QCPPolarAxisRadial::~QCPPolarAxisRadial() { } QCPPolarAxisRadial::LabelMode QCPPolarAxisRadial::tickLabelMode() const { switch (mLabelPainter.anchorMode()) { case QCPLabelPainterPrivate::amSkewedUpright: return lmUpright; case QCPLabelPainterPrivate::amSkewedRotated: return lmRotated; default: qDebug() << Q_FUNC_INFO << "invalid mode for polar axis"; break; } return lmUpright; } /* No documentation as it is a property getter */ QString QCPPolarAxisRadial::numberFormat() const { QString result; result.append(mNumberFormatChar); if (mNumberBeautifulPowers) { result.append(QLatin1Char('b')); if (mNumberMultiplyCross) result.append(QLatin1Char('c')); } return result; } /* No documentation as it is a property getter */ int QCPPolarAxisRadial::tickLengthIn() const { return mTickLengthIn; } /* No documentation as it is a property getter */ int QCPPolarAxisRadial::tickLengthOut() const { return mTickLengthOut; } /* No documentation as it is a property getter */ int QCPPolarAxisRadial::subTickLengthIn() const { return mSubTickLengthIn; } /* No documentation as it is a property getter */ int QCPPolarAxisRadial::subTickLengthOut() const { return mSubTickLengthOut; } /* No documentation as it is a property getter */ int QCPPolarAxisRadial::labelPadding() const { return mLabelPadding; } void QCPPolarAxisRadial::setRangeDrag(bool enabled) { mRangeDrag = enabled; } void QCPPolarAxisRadial::setRangeZoom(bool enabled) { mRangeZoom = enabled; } void QCPPolarAxisRadial::setRangeZoomFactor(double factor) { mRangeZoomFactor = factor; } /*! Sets whether the axis uses a linear scale or a logarithmic scale. Note that this method controls the coordinate transformation. For logarithmic scales, you will likely also want to use a logarithmic tick spacing and labeling, which can be achieved by setting the axis ticker to an instance of \ref QCPAxisTickerLog : \snippet documentation/doc-code-snippets/mainwindow.cpp qcpaxisticker-log-creation See the documentation of \ref QCPAxisTickerLog about the details of logarithmic axis tick creation. \ref setNumberPrecision */ void QCPPolarAxisRadial::setScaleType(QCPPolarAxisRadial::ScaleType type) { if (mScaleType != type) { mScaleType = type; if (mScaleType == stLogarithmic) setRange(mRange.sanitizedForLogScale()); //mCachedMarginValid = false; emit scaleTypeChanged(mScaleType); } } /*! Sets the range of the axis. This slot may be connected with the \ref rangeChanged signal of another axis so this axis is always synchronized with the other axis range, when it changes. To invert the direction of an axis, use \ref setRangeReversed. */ void QCPPolarAxisRadial::setRange(const QCPRange &range) { if (range.lower == mRange.lower && range.upper == mRange.upper) return; if (!QCPRange::validRange(range)) return; QCPRange oldRange = mRange; if (mScaleType == stLogarithmic) { mRange = range.sanitizedForLogScale(); } else { mRange = range.sanitizedForLinScale(); } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Sets whether the user can (de-)select the parts in \a selectable by clicking on the QCustomPlot surface. (When \ref QCustomPlot::setInteractions contains iSelectAxes.) However, even when \a selectable is set to a value not allowing the selection of a specific part, it is still possible to set the selection of this part manually, by calling \ref setSelectedParts directly. \see SelectablePart, setSelectedParts */ void QCPPolarAxisRadial::setSelectableParts(const SelectableParts &selectable) { if (mSelectableParts != selectable) { mSelectableParts = selectable; emit selectableChanged(mSelectableParts); } } /*! Sets the selected state of the respective axis parts described by \ref SelectablePart. When a part is selected, it uses a different pen/font. The entire selection mechanism for axes is handled automatically when \ref QCustomPlot::setInteractions contains iSelectAxes. You only need to call this function when you wish to change the selection state manually. This function can change the selection state of a part, independent of the \ref setSelectableParts setting. emits the \ref selectionChanged signal when \a selected is different from the previous selection state. \see SelectablePart, setSelectableParts, selectTest, setSelectedBasePen, setSelectedTickPen, setSelectedSubTickPen, setSelectedTickLabelFont, setSelectedLabelFont, setSelectedTickLabelColor, setSelectedLabelColor */ void QCPPolarAxisRadial::setSelectedParts(const SelectableParts &selected) { if (mSelectedParts != selected) { mSelectedParts = selected; emit selectionChanged(mSelectedParts); } } /*! \overload Sets the lower and upper bound of the axis range. To invert the direction of an axis, use \ref setRangeReversed. There is also a slot to set a range, see \ref setRange(const QCPRange &range). */ void QCPPolarAxisRadial::setRange(double lower, double upper) { if (lower == mRange.lower && upper == mRange.upper) return; if (!QCPRange::validRange(lower, upper)) return; QCPRange oldRange = mRange; mRange.lower = lower; mRange.upper = upper; if (mScaleType == stLogarithmic) { mRange = mRange.sanitizedForLogScale(); } else { mRange = mRange.sanitizedForLinScale(); } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! \overload Sets the range of the axis. The \a position coordinate indicates together with the \a alignment parameter, where the new range will be positioned. \a size defines the size of the new axis range. \a alignment may be Qt::AlignLeft, Qt::AlignRight or Qt::AlignCenter. This will cause the left border, right border, or center of the range to be aligned with \a position. Any other values of \a alignment will default to Qt::AlignCenter. */ void QCPPolarAxisRadial::setRange(double position, double size, Qt::AlignmentFlag alignment) { if (alignment == Qt::AlignLeft) setRange(position, position+size); else if (alignment == Qt::AlignRight) setRange(position-size, position); else // alignment == Qt::AlignCenter setRange(position-size/2.0, position+size/2.0); } /*! Sets the lower bound of the axis range. The upper bound is not changed. \see setRange */ void QCPPolarAxisRadial::setRangeLower(double lower) { if (mRange.lower == lower) return; QCPRange oldRange = mRange; mRange.lower = lower; if (mScaleType == stLogarithmic) { mRange = mRange.sanitizedForLogScale(); } else { mRange = mRange.sanitizedForLinScale(); } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Sets the upper bound of the axis range. The lower bound is not changed. \see setRange */ void QCPPolarAxisRadial::setRangeUpper(double upper) { if (mRange.upper == upper) return; QCPRange oldRange = mRange; mRange.upper = upper; if (mScaleType == stLogarithmic) { mRange = mRange.sanitizedForLogScale(); } else { mRange = mRange.sanitizedForLinScale(); } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Sets whether the axis range (direction) is displayed reversed. Normally, the values on horizontal axes increase left to right, on vertical axes bottom to top. When \a reversed is set to true, the direction of increasing values is inverted. Note that the range and data interface stays the same for reversed axes, e.g. the \a lower part of the \ref setRange interface will still reference the mathematically smaller number than the \a upper part. */ void QCPPolarAxisRadial::setRangeReversed(bool reversed) { mRangeReversed = reversed; } void QCPPolarAxisRadial::setAngle(double degrees) { mAngle = degrees; } void QCPPolarAxisRadial::setAngleReference(AngleReference reference) { mAngleReference = reference; } /*! The axis ticker is responsible for generating the tick positions and tick labels. See the documentation of QCPAxisTicker for details on how to work with axis tickers. You can change the tick positioning/labeling behaviour of this axis by setting a different QCPAxisTicker subclass using this method. If you only wish to modify the currently installed axis ticker, access it via \ref ticker. Since the ticker is stored in the axis as a shared pointer, multiple axes may share the same axis ticker simply by passing the same shared pointer to multiple axes. \see ticker */ void QCPPolarAxisRadial::setTicker(QSharedPointer ticker) { if (ticker) mTicker = ticker; else qDebug() << Q_FUNC_INFO << "can not set 0 as axis ticker"; // no need to invalidate margin cache here because produced tick labels are checked for changes in setupTickVector } /*! Sets whether tick marks are displayed. Note that setting \a show to false does not imply that tick labels are invisible, too. To achieve that, see \ref setTickLabels. \see setSubTicks */ void QCPPolarAxisRadial::setTicks(bool show) { if (mTicks != show) { mTicks = show; //mCachedMarginValid = false; } } /*! Sets whether tick labels are displayed. Tick labels are the numbers drawn next to tick marks. */ void QCPPolarAxisRadial::setTickLabels(bool show) { if (mTickLabels != show) { mTickLabels = show; //mCachedMarginValid = false; if (!mTickLabels) mTickVectorLabels.clear(); } } /*! Sets the distance between the axis base line (including any outward ticks) and the tick labels. \see setLabelPadding, setPadding */ void QCPPolarAxisRadial::setTickLabelPadding(int padding) { mLabelPainter.setPadding(padding); } /*! Sets the font of the tick labels. \see setTickLabels, setTickLabelColor */ void QCPPolarAxisRadial::setTickLabelFont(const QFont &font) { if (font != mTickLabelFont) { mTickLabelFont = font; //mCachedMarginValid = false; } } /*! Sets the color of the tick labels. \see setTickLabels, setTickLabelFont */ void QCPPolarAxisRadial::setTickLabelColor(const QColor &color) { mTickLabelColor = color; } /*! Sets the rotation of the tick labels. If \a degrees is zero, the labels are drawn normally. Else, the tick labels are drawn rotated by \a degrees clockwise. The specified angle is bound to values from -90 to 90 degrees. If \a degrees is exactly -90, 0 or 90, the tick labels are centered on the tick coordinate. For other angles, the label is drawn with an offset such that it seems to point toward or away from the tick mark. */ void QCPPolarAxisRadial::setTickLabelRotation(double degrees) { mLabelPainter.setRotation(degrees); } void QCPPolarAxisRadial::setTickLabelMode(LabelMode mode) { switch (mode) { case lmUpright: mLabelPainter.setAnchorMode(QCPLabelPainterPrivate::amSkewedUpright); break; case lmRotated: mLabelPainter.setAnchorMode(QCPLabelPainterPrivate::amSkewedRotated); break; } } /*! Sets the number format for the numbers in tick labels. This \a formatCode is an extended version of the format code used e.g. by QString::number() and QLocale::toString(). For reference about that, see the "Argument Formats" section in the detailed description of the QString class. \a formatCode is a string of one, two or three characters. The first character is identical to the normal format code used by Qt. In short, this means: 'e'/'E' scientific format, 'f' fixed format, 'g'/'G' scientific or fixed, whichever is shorter. The second and third characters are optional and specific to QCustomPlot:\n If the first char was 'e' or 'g', numbers are/might be displayed in the scientific format, e.g. "5.5e9", which is ugly in a plot. So when the second char of \a formatCode is set to 'b' (for "beautiful"), those exponential numbers are formatted in a more natural way, i.e. "5.5 [multiplication sign] 10 [superscript] 9". By default, the multiplication sign is a centered dot. If instead a cross should be shown (as is usual in the USA), the third char of \a formatCode can be set to 'c'. The inserted multiplication signs are the UTF-8 characters 215 (0xD7) for the cross and 183 (0xB7) for the dot. Examples for \a formatCode: \li \c g normal format code behaviour. If number is small, fixed format is used, if number is large, normal scientific format is used \li \c gb If number is small, fixed format is used, if number is large, scientific format is used with beautifully typeset decimal powers and a dot as multiplication sign \li \c ebc All numbers are in scientific format with beautifully typeset decimal power and a cross as multiplication sign \li \c fb illegal format code, since fixed format doesn't support (or need) beautifully typeset decimal powers. Format code will be reduced to 'f'. \li \c hello illegal format code, since first char is not 'e', 'E', 'f', 'g' or 'G'. Current format code will not be changed. */ void QCPPolarAxisRadial::setNumberFormat(const QString &formatCode) { if (formatCode.isEmpty()) { qDebug() << Q_FUNC_INFO << "Passed formatCode is empty"; return; } //mCachedMarginValid = false; // interpret first char as number format char: QString allowedFormatChars(QLatin1String("eEfgG")); if (allowedFormatChars.contains(formatCode.at(0))) { mNumberFormatChar = QLatin1Char(formatCode.at(0).toLatin1()); } else { qDebug() << Q_FUNC_INFO << "Invalid number format code (first char not in 'eEfgG'):" << formatCode; return; } if (formatCode.length() < 2) { mNumberBeautifulPowers = false; mNumberMultiplyCross = false; } else { // interpret second char as indicator for beautiful decimal powers: if (formatCode.at(1) == QLatin1Char('b') && (mNumberFormatChar == QLatin1Char('e') || mNumberFormatChar == QLatin1Char('g'))) mNumberBeautifulPowers = true; else qDebug() << Q_FUNC_INFO << "Invalid number format code (second char not 'b' or first char neither 'e' nor 'g'):" << formatCode; if (formatCode.length() < 3) { mNumberMultiplyCross = false; } else { // interpret third char as indicator for dot or cross multiplication symbol: if (formatCode.at(2) == QLatin1Char('c')) mNumberMultiplyCross = true; else if (formatCode.at(2) == QLatin1Char('d')) mNumberMultiplyCross = false; else qDebug() << Q_FUNC_INFO << "Invalid number format code (third char neither 'c' nor 'd'):" << formatCode; } } mLabelPainter.setSubstituteExponent(mNumberBeautifulPowers); mLabelPainter.setMultiplicationSymbol(mNumberMultiplyCross ? QCPLabelPainterPrivate::SymbolCross : QCPLabelPainterPrivate::SymbolDot); } /*! Sets the precision of the tick label numbers. See QLocale::toString(double i, char f, int prec) for details. The effect of precisions are most notably for number Formats starting with 'e', see \ref setNumberFormat */ void QCPPolarAxisRadial::setNumberPrecision(int precision) { if (mNumberPrecision != precision) { mNumberPrecision = precision; //mCachedMarginValid = false; } } /*! Sets the length of the ticks in pixels. \a inside is the length the ticks will reach inside the plot and \a outside is the length they will reach outside the plot. If \a outside is greater than zero, the tick labels and axis label will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setSubTickLength, setTickLengthIn, setTickLengthOut */ void QCPPolarAxisRadial::setTickLength(int inside, int outside) { setTickLengthIn(inside); setTickLengthOut(outside); } /*! Sets the length of the inward ticks in pixels. \a inside is the length the ticks will reach inside the plot. \see setTickLengthOut, setTickLength, setSubTickLength */ void QCPPolarAxisRadial::setTickLengthIn(int inside) { if (mTickLengthIn != inside) { mTickLengthIn = inside; } } /*! Sets the length of the outward ticks in pixels. \a outside is the length the ticks will reach outside the plot. If \a outside is greater than zero, the tick labels and axis label will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setTickLengthIn, setTickLength, setSubTickLength */ void QCPPolarAxisRadial::setTickLengthOut(int outside) { if (mTickLengthOut != outside) { mTickLengthOut = outside; //mCachedMarginValid = false; // only outside tick length can change margin } } /*! Sets whether sub tick marks are displayed. Sub ticks are only potentially visible if (major) ticks are also visible (see \ref setTicks) \see setTicks */ void QCPPolarAxisRadial::setSubTicks(bool show) { if (mSubTicks != show) { mSubTicks = show; //mCachedMarginValid = false; } } /*! Sets the length of the subticks in pixels. \a inside is the length the subticks will reach inside the plot and \a outside is the length they will reach outside the plot. If \a outside is greater than zero, the tick labels and axis label will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setTickLength, setSubTickLengthIn, setSubTickLengthOut */ void QCPPolarAxisRadial::setSubTickLength(int inside, int outside) { setSubTickLengthIn(inside); setSubTickLengthOut(outside); } /*! Sets the length of the inward subticks in pixels. \a inside is the length the subticks will reach inside the plot. \see setSubTickLengthOut, setSubTickLength, setTickLength */ void QCPPolarAxisRadial::setSubTickLengthIn(int inside) { if (mSubTickLengthIn != inside) { mSubTickLengthIn = inside; } } /*! Sets the length of the outward subticks in pixels. \a outside is the length the subticks will reach outside the plot. If \a outside is greater than zero, the tick labels will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setSubTickLengthIn, setSubTickLength, setTickLength */ void QCPPolarAxisRadial::setSubTickLengthOut(int outside) { if (mSubTickLengthOut != outside) { mSubTickLengthOut = outside; //mCachedMarginValid = false; // only outside tick length can change margin } } /*! Sets the pen, the axis base line is drawn with. \see setTickPen, setSubTickPen */ void QCPPolarAxisRadial::setBasePen(const QPen &pen) { mBasePen = pen; } /*! Sets the pen, tick marks will be drawn with. \see setTickLength, setBasePen */ void QCPPolarAxisRadial::setTickPen(const QPen &pen) { mTickPen = pen; } /*! Sets the pen, subtick marks will be drawn with. \see setSubTickCount, setSubTickLength, setBasePen */ void QCPPolarAxisRadial::setSubTickPen(const QPen &pen) { mSubTickPen = pen; } /*! Sets the font of the axis label. \see setLabelColor */ void QCPPolarAxisRadial::setLabelFont(const QFont &font) { if (mLabelFont != font) { mLabelFont = font; //mCachedMarginValid = false; } } /*! Sets the color of the axis label. \see setLabelFont */ void QCPPolarAxisRadial::setLabelColor(const QColor &color) { mLabelColor = color; } /*! Sets the text of the axis label that will be shown below/above or next to the axis, depending on its orientation. To disable axis labels, pass an empty string as \a str. */ void QCPPolarAxisRadial::setLabel(const QString &str) { if (mLabel != str) { mLabel = str; //mCachedMarginValid = false; } } /*! Sets the distance between the tick labels and the axis label. \see setTickLabelPadding, setPadding */ void QCPPolarAxisRadial::setLabelPadding(int padding) { if (mLabelPadding != padding) { mLabelPadding = padding; //mCachedMarginValid = false; } } /*! Sets the font that is used for tick labels when they are selected. \see setTickLabelFont, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisRadial::setSelectedTickLabelFont(const QFont &font) { if (font != mSelectedTickLabelFont) { mSelectedTickLabelFont = font; // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts } } /*! Sets the font that is used for the axis label when it is selected. \see setLabelFont, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisRadial::setSelectedLabelFont(const QFont &font) { mSelectedLabelFont = font; // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts } /*! Sets the color that is used for tick labels when they are selected. \see setTickLabelColor, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisRadial::setSelectedTickLabelColor(const QColor &color) { if (color != mSelectedTickLabelColor) { mSelectedTickLabelColor = color; } } /*! Sets the color that is used for the axis label when it is selected. \see setLabelColor, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisRadial::setSelectedLabelColor(const QColor &color) { mSelectedLabelColor = color; } /*! Sets the pen that is used to draw the axis base line when selected. \see setBasePen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisRadial::setSelectedBasePen(const QPen &pen) { mSelectedBasePen = pen; } /*! Sets the pen that is used to draw the (major) ticks when selected. \see setTickPen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisRadial::setSelectedTickPen(const QPen &pen) { mSelectedTickPen = pen; } /*! Sets the pen that is used to draw the subticks when selected. \see setSubTickPen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisRadial::setSelectedSubTickPen(const QPen &pen) { mSelectedSubTickPen = pen; } /*! If the scale type (\ref setScaleType) is \ref stLinear, \a diff is added to the lower and upper bounds of the range. The range is simply moved by \a diff. If the scale type is \ref stLogarithmic, the range bounds are multiplied by \a diff. This corresponds to an apparent "linear" move in logarithmic scaling by a distance of log(diff). */ void QCPPolarAxisRadial::moveRange(double diff) { QCPRange oldRange = mRange; if (mScaleType == stLinear) { mRange.lower += diff; mRange.upper += diff; } else // mScaleType == stLogarithmic { mRange.lower *= diff; mRange.upper *= diff; } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Scales the range of this axis by \a factor around the center of the current axis range. For example, if \a factor is 2.0, then the axis range will double its size, and the point at the axis range center won't have changed its position in the QCustomPlot widget (i.e. coordinates around the center will have moved symmetrically closer). If you wish to scale around a different coordinate than the current axis range center, use the overload \ref scaleRange(double factor, double center). */ void QCPPolarAxisRadial::scaleRange(double factor) { scaleRange(factor, range().center()); } /*! \overload Scales the range of this axis by \a factor around the coordinate \a center. For example, if \a factor is 2.0, \a center is 1.0, then the axis range will double its size, and the point at coordinate 1.0 won't have changed its position in the QCustomPlot widget (i.e. coordinates around 1.0 will have moved symmetrically closer to 1.0). \see scaleRange(double factor) */ void QCPPolarAxisRadial::scaleRange(double factor, double center) { QCPRange oldRange = mRange; if (mScaleType == stLinear) { QCPRange newRange; newRange.lower = (mRange.lower-center)*factor + center; newRange.upper = (mRange.upper-center)*factor + center; if (QCPRange::validRange(newRange)) mRange = newRange.sanitizedForLinScale(); } else // mScaleType == stLogarithmic { if ((mRange.upper < 0 && center < 0) || (mRange.upper > 0 && center > 0)) // make sure center has same sign as range { QCPRange newRange; newRange.lower = qPow(mRange.lower/center, factor)*center; newRange.upper = qPow(mRange.upper/center, factor)*center; if (QCPRange::validRange(newRange)) mRange = newRange.sanitizedForLogScale(); } else qDebug() << Q_FUNC_INFO << "Center of scaling operation doesn't lie in same logarithmic sign domain as range:" << center; } emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Changes the axis range such that all plottables associated with this axis are fully visible in that dimension. \see QCPAbstractPlottable::rescaleAxes, QCustomPlot::rescaleAxes */ void QCPPolarAxisRadial::rescale(bool onlyVisiblePlottables) { Q_UNUSED(onlyVisiblePlottables) /* TODO QList p = plottables(); QCPRange newRange; bool haveRange = false; for (int i=0; irealVisibility() && onlyVisiblePlottables) continue; QCPRange plottableRange; bool currentFoundRange; QCP::SignDomain signDomain = QCP::sdBoth; if (mScaleType == stLogarithmic) signDomain = (mRange.upper < 0 ? QCP::sdNegative : QCP::sdPositive); if (p.at(i)->keyAxis() == this) plottableRange = p.at(i)->getKeyRange(currentFoundRange, signDomain); else plottableRange = p.at(i)->getValueRange(currentFoundRange, signDomain); if (currentFoundRange) { if (!haveRange) newRange = plottableRange; else newRange.expand(plottableRange); haveRange = true; } } if (haveRange) { if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable { double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason if (mScaleType == stLinear) { newRange.lower = center-mRange.size()/2.0; newRange.upper = center+mRange.size()/2.0; } else // mScaleType == stLogarithmic { newRange.lower = center/qSqrt(mRange.upper/mRange.lower); newRange.upper = center*qSqrt(mRange.upper/mRange.lower); } } setRange(newRange); } */ } /*! Transforms \a value, in pixel coordinates of the QCustomPlot widget, to axis coordinates. */ void QCPPolarAxisRadial::pixelToCoord(QPointF pixelPos, double &angleCoord, double &radiusCoord) const { QCPVector2D posVector(pixelPos-mCenter); radiusCoord = radiusToCoord(posVector.length()); angleCoord = mAngularAxis->angleRadToCoord(posVector.angle()); } /*! Transforms \a value, in coordinates of the axis, to pixel coordinates of the QCustomPlot widget. */ QPointF QCPPolarAxisRadial::coordToPixel(double angleCoord, double radiusCoord) const { const double radiusPixel = coordToRadius(radiusCoord); const double angleRad = mAngularAxis->coordToAngleRad(angleCoord); return QPointF(mCenter.x()+qCos(angleRad)*radiusPixel, mCenter.y()+qSin(angleRad)*radiusPixel); } double QCPPolarAxisRadial::coordToRadius(double coord) const { if (mScaleType == stLinear) { if (!mRangeReversed) return (coord-mRange.lower)/mRange.size()*mRadius; else return (mRange.upper-coord)/mRange.size()*mRadius; } else // mScaleType == stLogarithmic { if (coord >= 0.0 && mRange.upper < 0.0) // invalid value for logarithmic scale, just return outside visible range return !mRangeReversed ? mRadius+200 : mRadius-200; else if (coord <= 0.0 && mRange.upper >= 0.0) // invalid value for logarithmic scale, just return outside visible range return !mRangeReversed ? mRadius-200 :mRadius+200; else { if (!mRangeReversed) return qLn(coord/mRange.lower)/qLn(mRange.upper/mRange.lower)*mRadius; else return qLn(mRange.upper/coord)/qLn(mRange.upper/mRange.lower)*mRadius; } } } double QCPPolarAxisRadial::radiusToCoord(double radius) const { if (mScaleType == stLinear) { if (!mRangeReversed) return (radius)/mRadius*mRange.size()+mRange.lower; else return -(radius)/mRadius*mRange.size()+mRange.upper; } else // mScaleType == stLogarithmic { if (!mRangeReversed) return qPow(mRange.upper/mRange.lower, (radius)/mRadius)*mRange.lower; else return qPow(mRange.upper/mRange.lower, (-radius)/mRadius)*mRange.upper; } } /*! Returns the part of the axis that is hit by \a pos (in pixels). The return value of this function is independent of the user-selectable parts defined with \ref setSelectableParts. Further, this function does not change the current selection state of the axis. If the axis is not visible (\ref setVisible), this function always returns \ref spNone. \see setSelectedParts, setSelectableParts, QCustomPlot::setInteractions */ QCPPolarAxisRadial::SelectablePart QCPPolarAxisRadial::getPartAt(const QPointF &pos) const { Q_UNUSED(pos) // TODO remove later if (!mVisible) return spNone; /* TODO: if (mAxisPainter->axisSelectionBox().contains(pos.toPoint())) return spAxis; else if (mAxisPainter->tickLabelsSelectionBox().contains(pos.toPoint())) return spTickLabels; else if (mAxisPainter->labelSelectionBox().contains(pos.toPoint())) return spAxisLabel; else */ return spNone; } /* inherits documentation from base class */ double QCPPolarAxisRadial::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { if (!mParentPlot) return -1; SelectablePart part = getPartAt(pos); if ((onlySelectable && !mSelectableParts.testFlag(part)) || part == spNone) return -1; if (details) details->setValue(part); return mParentPlot->selectionTolerance()*0.99; } /* inherits documentation from base class */ void QCPPolarAxisRadial::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) { Q_UNUSED(event) SelectablePart part = details.value(); if (mSelectableParts.testFlag(part)) { SelectableParts selBefore = mSelectedParts; setSelectedParts(additive ? mSelectedParts^part : part); if (selectionStateChanged) *selectionStateChanged = mSelectedParts != selBefore; } } /* inherits documentation from base class */ void QCPPolarAxisRadial::deselectEvent(bool *selectionStateChanged) { SelectableParts selBefore = mSelectedParts; setSelectedParts(mSelectedParts & ~mSelectableParts); if (selectionStateChanged) *selectionStateChanged = mSelectedParts != selBefore; } /*! \internal This mouse event reimplementation provides the functionality to let the user drag individual axes exclusively, by startig the drag on top of the axis. For the axis to accept this event and perform the single axis drag, the parent \ref QCPAxisRect must be configured accordingly, i.e. it must allow range dragging in the orientation of this axis (\ref QCPAxisRect::setRangeDrag) and this axis must be a draggable axis (\ref QCPAxisRect::setRangeDragAxes) \seebaseclassmethod \note The dragging of possibly multiple axes at once by starting the drag anywhere in the axis rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::mousePressEvent. */ void QCPPolarAxisRadial::mousePressEvent(QMouseEvent *event, const QVariant &details) { Q_UNUSED(details) if (!mParentPlot->interactions().testFlag(QCP::iRangeDrag)) { event->ignore(); return; } if (event->buttons() & Qt::LeftButton) { mDragging = true; // initialize antialiasing backup in case we start dragging: if (mParentPlot->noAntialiasingOnDrag()) { mAADragBackup = mParentPlot->antialiasedElements(); mNotAADragBackup = mParentPlot->notAntialiasedElements(); } // Mouse range dragging interaction: if (mParentPlot->interactions().testFlag(QCP::iRangeDrag)) mDragStartRange = mRange; } } /*! \internal This mouse event reimplementation provides the functionality to let the user drag individual axes exclusively, by startig the drag on top of the axis. \seebaseclassmethod \note The dragging of possibly multiple axes at once by starting the drag anywhere in the axis rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::mousePressEvent. \see QCPAxis::mousePressEvent */ void QCPPolarAxisRadial::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) { Q_UNUSED(event) // TODO remove later Q_UNUSED(startPos) // TODO remove later if (mDragging) { /* TODO const double startPixel = orientation() == Qt::Horizontal ? startPos.x() : startPos.y(); const double currentPixel = orientation() == Qt::Horizontal ? event->pos().x() : event->pos().y(); if (mScaleType == QCPPolarAxisRadial::stLinear) { const double diff = pixelToCoord(startPixel) - pixelToCoord(currentPixel); setRange(mDragStartRange.lower+diff, mDragStartRange.upper+diff); } else if (mScaleType == QCPPolarAxisRadial::stLogarithmic) { const double diff = pixelToCoord(startPixel) / pixelToCoord(currentPixel); setRange(mDragStartRange.lower*diff, mDragStartRange.upper*diff); } */ if (mParentPlot->noAntialiasingOnDrag()) mParentPlot->setNotAntialiasedElements(QCP::aeAll); mParentPlot->replot(QCustomPlot::rpQueuedReplot); } } /*! \internal This mouse event reimplementation provides the functionality to let the user drag individual axes exclusively, by startig the drag on top of the axis. \seebaseclassmethod \note The dragging of possibly multiple axes at once by starting the drag anywhere in the axis rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::mousePressEvent. \see QCPAxis::mousePressEvent */ void QCPPolarAxisRadial::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) { Q_UNUSED(event) Q_UNUSED(startPos) mDragging = false; if (mParentPlot->noAntialiasingOnDrag()) { mParentPlot->setAntialiasedElements(mAADragBackup); mParentPlot->setNotAntialiasedElements(mNotAADragBackup); } } /*! \internal This mouse event reimplementation provides the functionality to let the user zoom individual axes exclusively, by performing the wheel event on top of the axis. For the axis to accept this event and perform the single axis zoom, the parent \ref QCPAxisRect must be configured accordingly, i.e. it must allow range zooming in the orientation of this axis (\ref QCPAxisRect::setRangeZoom) and this axis must be a zoomable axis (\ref QCPAxisRect::setRangeZoomAxes) \seebaseclassmethod \note The zooming of possibly multiple axes at once by performing the wheel event anywhere in the axis rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::wheelEvent. */ void QCPPolarAxisRadial::wheelEvent(QWheelEvent *event) { // Mouse range zooming interaction: if (!mParentPlot->interactions().testFlag(QCP::iRangeZoom)) { event->ignore(); return; } // TODO: //const double wheelSteps = event->delta()/120.0; // a single step delta is +/-120 usually //const double factor = qPow(mRangeZoomFactor, wheelSteps); //scaleRange(factor, pixelToCoord(orientation() == Qt::Horizontal ? event->pos().x() : event->pos().y())); mParentPlot->replot(); } void QCPPolarAxisRadial::updateGeometry(const QPointF ¢er, double radius) { mCenter = center; mRadius = radius; if (mRadius < 1) mRadius = 1; } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing axis lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set with \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. \seebaseclassmethod \see setAntialiased */ void QCPPolarAxisRadial::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeAxes); } /*! \internal Draws the axis with the specified \a painter, using the internal QCPAxisPainterPrivate instance. \seebaseclassmethod */ void QCPPolarAxisRadial::draw(QCPPainter *painter) { const double axisAngleRad = (mAngle+(mAngleReference==arAngularAxis ? mAngularAxis->angle() : 0))/180.0*M_PI; const QPointF axisVector(qCos(axisAngleRad), qSin(axisAngleRad)); // semantically should be QCPVector2D, but we save time in loops when we keep it as QPointF const QPointF tickNormal = QCPVector2D(axisVector).perpendicular().toPointF(); // semantically should be QCPVector2D, but we save time in loops when we keep it as QPointF // draw baseline: painter->setPen(getBasePen()); painter->drawLine(QLineF(mCenter, mCenter+axisVector*(mRadius-0.5))); // draw subticks: if (!mSubTickVector.isEmpty()) { painter->setPen(getSubTickPen()); for (int i=0; idrawLine(QLineF(tickPosition-tickNormal*mSubTickLengthIn, tickPosition+tickNormal*mSubTickLengthOut)); } } // draw ticks and labels: if (!mTickVector.isEmpty()) { mLabelPainter.setAnchorReference(mCenter-axisVector); // subtract (normalized) axisVector, just to prevent degenerate tangents for tick label at exact lower axis range mLabelPainter.setFont(getTickLabelFont()); mLabelPainter.setColor(getTickLabelColor()); const QPen ticksPen = getTickPen(); painter->setPen(ticksPen); for (int i=0; idrawLine(QLineF(tickPosition-tickNormal*mTickLengthIn, tickPosition+tickNormal*mTickLengthOut)); // possibly draw tick labels: if (!mTickVectorLabels.isEmpty()) { if ((!mRangeReversed && (i < mTickVectorLabels.count()-1 || mRadius-r > 10)) || (mRangeReversed && (i > 0 || mRadius-r > 10))) // skip last label if it's closer than 10 pixels to angular axis mLabelPainter.drawTickLabel(painter, tickPosition+tickNormal*mSubTickLengthOut, mTickVectorLabels.at(i)); } } } } /*! \internal Prepares the internal tick vector, sub tick vector and tick label vector. This is done by calling QCPAxisTicker::generate on the currently installed ticker. If a change in the label text/count is detected, the cached axis margin is invalidated to make sure the next margin calculation recalculates the label sizes and returns an up-to-date value. */ void QCPPolarAxisRadial::setupTickVectors() { if (!mParentPlot) return; if ((!mTicks && !mTickLabels) || mRange.size() <= 0) return; mTicker->generate(mRange, mParentPlot->locale(), mNumberFormatChar, mNumberPrecision, mTickVector, mSubTicks ? &mSubTickVector : 0, mTickLabels ? &mTickVectorLabels : 0); } /*! \internal Returns the pen that is used to draw the axis base line. Depending on the selection state, this is either mSelectedBasePen or mBasePen. */ QPen QCPPolarAxisRadial::getBasePen() const { return mSelectedParts.testFlag(spAxis) ? mSelectedBasePen : mBasePen; } /*! \internal Returns the pen that is used to draw the (major) ticks. Depending on the selection state, this is either mSelectedTickPen or mTickPen. */ QPen QCPPolarAxisRadial::getTickPen() const { return mSelectedParts.testFlag(spAxis) ? mSelectedTickPen : mTickPen; } /*! \internal Returns the pen that is used to draw the subticks. Depending on the selection state, this is either mSelectedSubTickPen or mSubTickPen. */ QPen QCPPolarAxisRadial::getSubTickPen() const { return mSelectedParts.testFlag(spAxis) ? mSelectedSubTickPen : mSubTickPen; } /*! \internal Returns the font that is used to draw the tick labels. Depending on the selection state, this is either mSelectedTickLabelFont or mTickLabelFont. */ QFont QCPPolarAxisRadial::getTickLabelFont() const { return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelFont : mTickLabelFont; } /*! \internal Returns the font that is used to draw the axis label. Depending on the selection state, this is either mSelectedLabelFont or mLabelFont. */ QFont QCPPolarAxisRadial::getLabelFont() const { return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelFont : mLabelFont; } /*! \internal Returns the color that is used to draw the tick labels. Depending on the selection state, this is either mSelectedTickLabelColor or mTickLabelColor. */ QColor QCPPolarAxisRadial::getTickLabelColor() const { return mSelectedParts.testFlag(spTickLabels) ? mSelectedTickLabelColor : mTickLabelColor; } /*! \internal Returns the color that is used to draw the axis label. Depending on the selection state, this is either mSelectedLabelColor or mLabelColor. */ QColor QCPPolarAxisRadial::getLabelColor() const { return mSelectedParts.testFlag(spAxisLabel) ? mSelectedLabelColor : mLabelColor; } /* inherits documentation from base class */ QCP::Interaction QCPPolarAxisRadial::selectionCategory() const { return QCP::iSelectAxes; } /* end of 'src/polar/radialaxis.cpp' */ /* including file 'src/polar/layoutelement-angularaxis.cpp' */ /* modified 2021-03-29T02:30:44, size 57266 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPolarAxisAngular //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPolarAxisAngular \brief The main container for polar plots, representing the angular axis as a circle \warning In this QCustomPlot version, polar plots are a tech preview. Expect documentation and functionality to be incomplete, as well as changing public interfaces in the future. */ /* start documentation of inline functions */ /*! \fn QCPLayoutInset *QCPPolarAxisAngular::insetLayout() const Returns the inset layout of this axis rect. It can be used to place other layout elements (or even layouts with multiple other elements) inside/on top of an axis rect. \see QCPLayoutInset */ /*! \fn int QCPPolarAxisAngular::left() const Returns the pixel position of the left border of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPPolarAxisAngular::right() const Returns the pixel position of the right border of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPPolarAxisAngular::top() const Returns the pixel position of the top border of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPPolarAxisAngular::bottom() const Returns the pixel position of the bottom border of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPPolarAxisAngular::width() const Returns the pixel width of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn int QCPPolarAxisAngular::height() const Returns the pixel height of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QSize QCPPolarAxisAngular::size() const Returns the pixel size of this axis rect. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPPolarAxisAngular::topLeft() const Returns the top left corner of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPPolarAxisAngular::topRight() const Returns the top right corner of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPPolarAxisAngular::bottomLeft() const Returns the bottom left corner of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPPolarAxisAngular::bottomRight() const Returns the bottom right corner of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /*! \fn QPoint QCPPolarAxisAngular::center() const Returns the center of this axis rect in pixels. Margins are not taken into account here, so the returned value is with respect to the inner \ref rect. */ /* end documentation of inline functions */ /*! Creates a QCPPolarAxis instance and sets default values. An axis is added for each of the four sides, the top and right axes are set invisible initially. */ QCPPolarAxisAngular::QCPPolarAxisAngular(QCustomPlot *parentPlot) : QCPLayoutElement(parentPlot), mBackgroundBrush(Qt::NoBrush), mBackgroundScaled(true), mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding), mInsetLayout(new QCPLayoutInset), mRangeDrag(false), mRangeZoom(false), mRangeZoomFactor(0.85), // axis base: mAngle(-90), mAngleRad(mAngle/180.0*M_PI), mSelectableParts(spAxis | spTickLabels | spAxisLabel), mSelectedParts(spNone), mBasePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), mSelectedBasePen(QPen(Qt::blue, 2)), // axis label: mLabelPadding(0), mLabel(), mLabelFont(mParentPlot->font()), mSelectedLabelFont(QFont(mLabelFont.family(), mLabelFont.pointSize(), QFont::Bold)), mLabelColor(Qt::black), mSelectedLabelColor(Qt::blue), // tick labels: //mTickLabelPadding(0), in label painter mTickLabels(true), //mTickLabelRotation(0), in label painter mTickLabelFont(mParentPlot->font()), mSelectedTickLabelFont(QFont(mTickLabelFont.family(), mTickLabelFont.pointSize(), QFont::Bold)), mTickLabelColor(Qt::black), mSelectedTickLabelColor(Qt::blue), mNumberPrecision(6), mNumberFormatChar('g'), mNumberBeautifulPowers(true), mNumberMultiplyCross(false), // ticks and subticks: mTicks(true), mSubTicks(true), mTickLengthIn(5), mTickLengthOut(0), mSubTickLengthIn(2), mSubTickLengthOut(0), mTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), mSelectedTickPen(QPen(Qt::blue, 2)), mSubTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)), mSelectedSubTickPen(QPen(Qt::blue, 2)), // scale and range: mRange(0, 360), mRangeReversed(false), // internal members: mRadius(1), // non-zero initial value, will be overwritten in ::update() according to inner rect mGrid(new QCPPolarGrid(this)), mTicker(new QCPAxisTickerFixed), mDragging(false), mLabelPainter(parentPlot) { // TODO: //mInsetLayout->initializeParentPlot(mParentPlot); //mInsetLayout->setParentLayerable(this); //mInsetLayout->setParent(this); if (QCPAxisTickerFixed *fixedTicker = mTicker.dynamicCast().data()) { fixedTicker->setTickStep(30); } setAntialiased(true); setLayer(mParentPlot->currentLayer()); // it's actually on that layer already, but we want it in front of the grid, so we place it on there again setTickLabelPadding(5); setTickLabelRotation(0); setTickLabelMode(lmUpright); mLabelPainter.setAnchorReferenceType(QCPLabelPainterPrivate::artNormal); mLabelPainter.setAbbreviateDecimalPowers(false); mLabelPainter.setCacheSize(24); // so we can cache up to 15-degree intervals, polar angular axis uses a bit larger cache than normal axes setMinimumSize(50, 50); setMinimumMargins(QMargins(30, 30, 30, 30)); addRadialAxis(); mGrid->setRadialAxis(radialAxis()); } QCPPolarAxisAngular::~QCPPolarAxisAngular() { delete mGrid; // delete grid here instead of via parent ~QObject for better defined deletion order mGrid = 0; delete mInsetLayout; mInsetLayout = 0; QList radialAxesList = radialAxes(); for (int i=0; i= 0 && index < mRadialAxes.size()) { return mRadialAxes.at(index); } else { qDebug() << Q_FUNC_INFO << "Axis index out of bounds:" << index; return 0; } } /*! Returns all axes on the axis rect sides specified with \a types. \a types may be a single \ref QCPAxis::AxisType or an or-combination, to get the axes of multiple sides. \see axis */ QList QCPPolarAxisAngular::radialAxes() const { return mRadialAxes; } /*! Adds a new axis to the axis rect side specified with \a type, and returns it. If \a axis is 0, a new QCPAxis instance is created internally. QCustomPlot owns the returned axis, so if you want to remove an axis, use \ref removeAxis instead of deleting it manually. You may inject QCPAxis instances (or subclasses of QCPAxis) by setting \a axis to an axis that was previously created outside QCustomPlot. It is important to note that QCustomPlot takes ownership of the axis, so you may not delete it afterwards. Further, the \a axis must have been created with this axis rect as parent and with the same axis type as specified in \a type. If this is not the case, a debug output is generated, the axis is not added, and the method returns 0. This method can not be used to move \a axis between axis rects. The same \a axis instance must not be added multiple times to the same or different axis rects. If an axis rect side already contains one or more axes, the lower and upper endings of the new axis (\ref QCPAxis::setLowerEnding, \ref QCPAxis::setUpperEnding) are set to \ref QCPLineEnding::esHalfBar. \see addAxes, setupFullAxesBox */ QCPPolarAxisRadial *QCPPolarAxisAngular::addRadialAxis(QCPPolarAxisRadial *axis) { QCPPolarAxisRadial *newAxis = axis; if (!newAxis) { newAxis = new QCPPolarAxisRadial(this); } else // user provided existing axis instance, do some sanity checks { if (newAxis->angularAxis() != this) { qDebug() << Q_FUNC_INFO << "passed radial axis doesn't have this angular axis as parent angular axis"; return 0; } if (radialAxes().contains(newAxis)) { qDebug() << Q_FUNC_INFO << "passed axis is already owned by this angular axis"; return 0; } } mRadialAxes.append(newAxis); return newAxis; } /*! Removes the specified \a axis from the axis rect and deletes it. Returns true on success, i.e. if \a axis was a valid axis in this axis rect. \see addAxis */ bool QCPPolarAxisAngular::removeRadialAxis(QCPPolarAxisRadial *radialAxis) { if (mRadialAxes.contains(radialAxis)) { mRadialAxes.removeOne(radialAxis); delete radialAxis; return true; } else { qDebug() << Q_FUNC_INFO << "Radial axis isn't associated with this angular axis:" << reinterpret_cast(radialAxis); return false; } } QRegion QCPPolarAxisAngular::exactClipRegion() const { return QRegion(mCenter.x()-mRadius, mCenter.y()-mRadius, qRound(2*mRadius), qRound(2*mRadius), QRegion::Ellipse); } /*! If the scale type (\ref setScaleType) is \ref stLinear, \a diff is added to the lower and upper bounds of the range. The range is simply moved by \a diff. If the scale type is \ref stLogarithmic, the range bounds are multiplied by \a diff. This corresponds to an apparent "linear" move in logarithmic scaling by a distance of log(diff). */ void QCPPolarAxisAngular::moveRange(double diff) { QCPRange oldRange = mRange; mRange.lower += diff; mRange.upper += diff; emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Scales the range of this axis by \a factor around the center of the current axis range. For example, if \a factor is 2.0, then the axis range will double its size, and the point at the axis range center won't have changed its position in the QCustomPlot widget (i.e. coordinates around the center will have moved symmetrically closer). If you wish to scale around a different coordinate than the current axis range center, use the overload \ref scaleRange(double factor, double center). */ void QCPPolarAxisAngular::scaleRange(double factor) { scaleRange(factor, range().center()); } /*! \overload Scales the range of this axis by \a factor around the coordinate \a center. For example, if \a factor is 2.0, \a center is 1.0, then the axis range will double its size, and the point at coordinate 1.0 won't have changed its position in the QCustomPlot widget (i.e. coordinates around 1.0 will have moved symmetrically closer to 1.0). \see scaleRange(double factor) */ void QCPPolarAxisAngular::scaleRange(double factor, double center) { QCPRange oldRange = mRange; QCPRange newRange; newRange.lower = (mRange.lower-center)*factor + center; newRange.upper = (mRange.upper-center)*factor + center; if (QCPRange::validRange(newRange)) mRange = newRange.sanitizedForLinScale(); emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Changes the axis range such that all plottables associated with this axis are fully visible in that dimension. \see QCPAbstractPlottable::rescaleAxes, QCustomPlot::rescaleAxes */ void QCPPolarAxisAngular::rescale(bool onlyVisiblePlottables) { QCPRange newRange; bool haveRange = false; for (int i=0; irealVisibility() && onlyVisiblePlottables) continue; QCPRange range; bool currentFoundRange; if (mGraphs.at(i)->keyAxis() == this) range = mGraphs.at(i)->getKeyRange(currentFoundRange, QCP::sdBoth); else range = mGraphs.at(i)->getValueRange(currentFoundRange, QCP::sdBoth); if (currentFoundRange) { if (!haveRange) newRange = range; else newRange.expand(range); haveRange = true; } } if (haveRange) { if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable { double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason newRange.lower = center-mRange.size()/2.0; newRange.upper = center+mRange.size()/2.0; } setRange(newRange); } } /*! Transforms \a value, in pixel coordinates of the QCustomPlot widget, to axis coordinates. */ void QCPPolarAxisAngular::pixelToCoord(QPointF pixelPos, double &angleCoord, double &radiusCoord) const { if (!mRadialAxes.isEmpty()) mRadialAxes.first()->pixelToCoord(pixelPos, angleCoord, radiusCoord); else qDebug() << Q_FUNC_INFO << "no radial axis configured"; } /*! Transforms \a value, in coordinates of the axis, to pixel coordinates of the QCustomPlot widget. */ QPointF QCPPolarAxisAngular::coordToPixel(double angleCoord, double radiusCoord) const { if (!mRadialAxes.isEmpty()) { return mRadialAxes.first()->coordToPixel(angleCoord, radiusCoord); } else { qDebug() << Q_FUNC_INFO << "no radial axis configured"; return QPointF(); } } /*! Returns the part of the axis that is hit by \a pos (in pixels). The return value of this function is independent of the user-selectable parts defined with \ref setSelectableParts. Further, this function does not change the current selection state of the axis. If the axis is not visible (\ref setVisible), this function always returns \ref spNone. \see setSelectedParts, setSelectableParts, QCustomPlot::setInteractions */ QCPPolarAxisAngular::SelectablePart QCPPolarAxisAngular::getPartAt(const QPointF &pos) const { Q_UNUSED(pos) // TODO remove later if (!mVisible) return spNone; /* TODO: if (mAxisPainter->axisSelectionBox().contains(pos.toPoint())) return spAxis; else if (mAxisPainter->tickLabelsSelectionBox().contains(pos.toPoint())) return spTickLabels; else if (mAxisPainter->labelSelectionBox().contains(pos.toPoint())) return spAxisLabel; else */ return spNone; } /* inherits documentation from base class */ double QCPPolarAxisAngular::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { /* if (!mParentPlot) return -1; SelectablePart part = getPartAt(pos); if ((onlySelectable && !mSelectableParts.testFlag(part)) || part == spNone) return -1; if (details) details->setValue(part); return mParentPlot->selectionTolerance()*0.99; */ Q_UNUSED(details) if (onlySelectable) return -1; if (QRectF(mOuterRect).contains(pos)) { if (mParentPlot) return mParentPlot->selectionTolerance()*0.99; else { qDebug() << Q_FUNC_INFO << "parent plot not defined"; return -1; } } else return -1; } /*! This method is called automatically upon replot and doesn't need to be called by users of QCPPolarAxisAngular. Calls the base class implementation to update the margins (see \ref QCPLayoutElement::update), and finally passes the \ref rect to the inset layout (\ref insetLayout) and calls its QCPInsetLayout::update function. \seebaseclassmethod */ void QCPPolarAxisAngular::update(UpdatePhase phase) { QCPLayoutElement::update(phase); switch (phase) { case upPreparation: { setupTickVectors(); for (int i=0; isetupTickVectors(); break; } case upLayout: { mCenter = mRect.center(); mRadius = 0.5*qMin(qAbs(mRect.width()), qAbs(mRect.height())); if (mRadius < 1) mRadius = 1; // prevent cases where radius might become 0 which causes trouble for (int i=0; iupdateGeometry(mCenter, mRadius); mInsetLayout->setOuterRect(rect()); break; } default: break; } // pass update call on to inset layout (doesn't happen automatically, because QCPPolarAxis doesn't derive from QCPLayout): mInsetLayout->update(phase); } /* inherits documentation from base class */ QList QCPPolarAxisAngular::elements(bool recursive) const { QList result; if (mInsetLayout) { result << mInsetLayout; if (recursive) result << mInsetLayout->elements(recursive); } return result; } bool QCPPolarAxisAngular::removeGraph(QCPPolarGraph *graph) { if (!mGraphs.contains(graph)) { qDebug() << Q_FUNC_INFO << "graph not in list:" << reinterpret_cast(graph); return false; } // remove plottable from legend: graph->removeFromLegend(); // remove plottable: delete graph; mGraphs.removeOne(graph); return true; } /* inherits documentation from base class */ void QCPPolarAxisAngular::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeAxes); } /* inherits documentation from base class */ void QCPPolarAxisAngular::draw(QCPPainter *painter) { drawBackground(painter, mCenter, mRadius); // draw baseline circle: painter->setPen(getBasePen()); painter->drawEllipse(mCenter, mRadius, mRadius); // draw subticks: if (!mSubTickVector.isEmpty()) { painter->setPen(getSubTickPen()); for (int i=0; idrawLine(mCenter+mSubTickVectorCosSin.at(i)*(mRadius-mSubTickLengthIn), mCenter+mSubTickVectorCosSin.at(i)*(mRadius+mSubTickLengthOut)); } } // draw ticks and labels: if (!mTickVector.isEmpty()) { mLabelPainter.setAnchorReference(mCenter); mLabelPainter.setFont(getTickLabelFont()); mLabelPainter.setColor(getTickLabelColor()); const QPen ticksPen = getTickPen(); painter->setPen(ticksPen); for (int i=0; idrawLine(mCenter+mTickVectorCosSin.at(i)*(mRadius-mTickLengthIn), outerTick); // draw tick labels: if (!mTickVectorLabels.isEmpty()) { if (i < mTickVectorLabels.count()-1 || (mTickVectorCosSin.at(i)-mTickVectorCosSin.first()).manhattanLength() > 5/180.0*M_PI) // skip last label if it's closer than approx 5 degrees to first mLabelPainter.drawTickLabel(painter, outerTick, mTickVectorLabels.at(i)); } } } } /* inherits documentation from base class */ QCP::Interaction QCPPolarAxisAngular::selectionCategory() const { return QCP::iSelectAxes; } /*! Sets \a pm as the axis background pixmap. The axis background pixmap will be drawn inside the axis rect. Since axis rects place themselves on the "background" layer by default, the axis rect backgrounds are usually drawn below everything else. For cases where the provided pixmap doesn't have the same size as the axis rect, scaling can be enabled with \ref setBackgroundScaled and the scaling mode (i.e. whether and how the aspect ratio is preserved) can be set with \ref setBackgroundScaledMode. To set all these options in one call, consider using the overloaded version of this function. Below the pixmap, the axis rect may be optionally filled with a brush, if specified with \ref setBackground(const QBrush &brush). \see setBackgroundScaled, setBackgroundScaledMode, setBackground(const QBrush &brush) */ void QCPPolarAxisAngular::setBackground(const QPixmap &pm) { mBackgroundPixmap = pm; mScaledBackgroundPixmap = QPixmap(); } /*! \overload Sets \a brush as the background brush. The axis rect background will be filled with this brush. Since axis rects place themselves on the "background" layer by default, the axis rect backgrounds are usually drawn below everything else. The brush will be drawn before (under) any background pixmap, which may be specified with \ref setBackground(const QPixmap &pm). To disable drawing of a background brush, set \a brush to Qt::NoBrush. \see setBackground(const QPixmap &pm) */ void QCPPolarAxisAngular::setBackground(const QBrush &brush) { mBackgroundBrush = brush; } /*! \overload Allows setting the background pixmap of the axis rect, whether it shall be scaled and how it shall be scaled in one call. \see setBackground(const QPixmap &pm), setBackgroundScaled, setBackgroundScaledMode */ void QCPPolarAxisAngular::setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode) { mBackgroundPixmap = pm; mScaledBackgroundPixmap = QPixmap(); mBackgroundScaled = scaled; mBackgroundScaledMode = mode; } /*! Sets whether the axis background pixmap shall be scaled to fit the axis rect or not. If \a scaled is set to true, you may control whether and how the aspect ratio of the original pixmap is preserved with \ref setBackgroundScaledMode. Note that the scaled version of the original pixmap is buffered, so there is no performance penalty on replots. (Except when the axis rect dimensions are changed continuously.) \see setBackground, setBackgroundScaledMode */ void QCPPolarAxisAngular::setBackgroundScaled(bool scaled) { mBackgroundScaled = scaled; } /*! If scaling of the axis background pixmap is enabled (\ref setBackgroundScaled), use this function to define whether and how the aspect ratio of the original pixmap passed to \ref setBackground is preserved. \see setBackground, setBackgroundScaled */ void QCPPolarAxisAngular::setBackgroundScaledMode(Qt::AspectRatioMode mode) { mBackgroundScaledMode = mode; } void QCPPolarAxisAngular::setRangeDrag(bool enabled) { mRangeDrag = enabled; } void QCPPolarAxisAngular::setRangeZoom(bool enabled) { mRangeZoom = enabled; } void QCPPolarAxisAngular::setRangeZoomFactor(double factor) { mRangeZoomFactor = factor; } /*! Sets the range of the axis. This slot may be connected with the \ref rangeChanged signal of another axis so this axis is always synchronized with the other axis range, when it changes. To invert the direction of an axis, use \ref setRangeReversed. */ void QCPPolarAxisAngular::setRange(const QCPRange &range) { if (range.lower == mRange.lower && range.upper == mRange.upper) return; if (!QCPRange::validRange(range)) return; QCPRange oldRange = mRange; mRange = range.sanitizedForLinScale(); emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Sets whether the user can (de-)select the parts in \a selectable by clicking on the QCustomPlot surface. (When \ref QCustomPlot::setInteractions contains iSelectAxes.) However, even when \a selectable is set to a value not allowing the selection of a specific part, it is still possible to set the selection of this part manually, by calling \ref setSelectedParts directly. \see SelectablePart, setSelectedParts */ void QCPPolarAxisAngular::setSelectableParts(const SelectableParts &selectable) { if (mSelectableParts != selectable) { mSelectableParts = selectable; emit selectableChanged(mSelectableParts); } } /*! Sets the selected state of the respective axis parts described by \ref SelectablePart. When a part is selected, it uses a different pen/font. The entire selection mechanism for axes is handled automatically when \ref QCustomPlot::setInteractions contains iSelectAxes. You only need to call this function when you wish to change the selection state manually. This function can change the selection state of a part, independent of the \ref setSelectableParts setting. emits the \ref selectionChanged signal when \a selected is different from the previous selection state. \see SelectablePart, setSelectableParts, selectTest, setSelectedBasePen, setSelectedTickPen, setSelectedSubTickPen, setSelectedTickLabelFont, setSelectedLabelFont, setSelectedTickLabelColor, setSelectedLabelColor */ void QCPPolarAxisAngular::setSelectedParts(const SelectableParts &selected) { if (mSelectedParts != selected) { mSelectedParts = selected; emit selectionChanged(mSelectedParts); } } /*! \overload Sets the lower and upper bound of the axis range. To invert the direction of an axis, use \ref setRangeReversed. There is also a slot to set a range, see \ref setRange(const QCPRange &range). */ void QCPPolarAxisAngular::setRange(double lower, double upper) { if (lower == mRange.lower && upper == mRange.upper) return; if (!QCPRange::validRange(lower, upper)) return; QCPRange oldRange = mRange; mRange.lower = lower; mRange.upper = upper; mRange = mRange.sanitizedForLinScale(); emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! \overload Sets the range of the axis. The \a position coordinate indicates together with the \a alignment parameter, where the new range will be positioned. \a size defines the size of the new axis range. \a alignment may be Qt::AlignLeft, Qt::AlignRight or Qt::AlignCenter. This will cause the left border, right border, or center of the range to be aligned with \a position. Any other values of \a alignment will default to Qt::AlignCenter. */ void QCPPolarAxisAngular::setRange(double position, double size, Qt::AlignmentFlag alignment) { if (alignment == Qt::AlignLeft) setRange(position, position+size); else if (alignment == Qt::AlignRight) setRange(position-size, position); else // alignment == Qt::AlignCenter setRange(position-size/2.0, position+size/2.0); } /*! Sets the lower bound of the axis range. The upper bound is not changed. \see setRange */ void QCPPolarAxisAngular::setRangeLower(double lower) { if (mRange.lower == lower) return; QCPRange oldRange = mRange; mRange.lower = lower; mRange = mRange.sanitizedForLinScale(); emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Sets the upper bound of the axis range. The lower bound is not changed. \see setRange */ void QCPPolarAxisAngular::setRangeUpper(double upper) { if (mRange.upper == upper) return; QCPRange oldRange = mRange; mRange.upper = upper; mRange = mRange.sanitizedForLinScale(); emit rangeChanged(mRange); emit rangeChanged(mRange, oldRange); } /*! Sets whether the axis range (direction) is displayed reversed. Normally, the values on horizontal axes increase left to right, on vertical axes bottom to top. When \a reversed is set to true, the direction of increasing values is inverted. Note that the range and data interface stays the same for reversed axes, e.g. the \a lower part of the \ref setRange interface will still reference the mathematically smaller number than the \a upper part. */ void QCPPolarAxisAngular::setRangeReversed(bool reversed) { mRangeReversed = reversed; } void QCPPolarAxisAngular::setAngle(double degrees) { mAngle = degrees; mAngleRad = mAngle/180.0*M_PI; } /*! The axis ticker is responsible for generating the tick positions and tick labels. See the documentation of QCPAxisTicker for details on how to work with axis tickers. You can change the tick positioning/labeling behaviour of this axis by setting a different QCPAxisTicker subclass using this method. If you only wish to modify the currently installed axis ticker, access it via \ref ticker. Since the ticker is stored in the axis as a shared pointer, multiple axes may share the same axis ticker simply by passing the same shared pointer to multiple axes. \see ticker */ void QCPPolarAxisAngular::setTicker(QSharedPointer ticker) { if (ticker) mTicker = ticker; else qDebug() << Q_FUNC_INFO << "can not set 0 as axis ticker"; // no need to invalidate margin cache here because produced tick labels are checked for changes in setupTickVector } /*! Sets whether tick marks are displayed. Note that setting \a show to false does not imply that tick labels are invisible, too. To achieve that, see \ref setTickLabels. \see setSubTicks */ void QCPPolarAxisAngular::setTicks(bool show) { if (mTicks != show) { mTicks = show; //mCachedMarginValid = false; } } /*! Sets whether tick labels are displayed. Tick labels are the numbers drawn next to tick marks. */ void QCPPolarAxisAngular::setTickLabels(bool show) { if (mTickLabels != show) { mTickLabels = show; //mCachedMarginValid = false; if (!mTickLabels) mTickVectorLabels.clear(); } } /*! Sets the distance between the axis base line (including any outward ticks) and the tick labels. \see setLabelPadding, setPadding */ void QCPPolarAxisAngular::setTickLabelPadding(int padding) { mLabelPainter.setPadding(padding); } /*! Sets the font of the tick labels. \see setTickLabels, setTickLabelColor */ void QCPPolarAxisAngular::setTickLabelFont(const QFont &font) { mTickLabelFont = font; } /*! Sets the color of the tick labels. \see setTickLabels, setTickLabelFont */ void QCPPolarAxisAngular::setTickLabelColor(const QColor &color) { mTickLabelColor = color; } /*! Sets the rotation of the tick labels. If \a degrees is zero, the labels are drawn normally. Else, the tick labels are drawn rotated by \a degrees clockwise. The specified angle is bound to values from -90 to 90 degrees. If \a degrees is exactly -90, 0 or 90, the tick labels are centered on the tick coordinate. For other angles, the label is drawn with an offset such that it seems to point toward or away from the tick mark. */ void QCPPolarAxisAngular::setTickLabelRotation(double degrees) { mLabelPainter.setRotation(degrees); } void QCPPolarAxisAngular::setTickLabelMode(LabelMode mode) { switch (mode) { case lmUpright: mLabelPainter.setAnchorMode(QCPLabelPainterPrivate::amSkewedUpright); break; case lmRotated: mLabelPainter.setAnchorMode(QCPLabelPainterPrivate::amSkewedRotated); break; } } /*! Sets the number format for the numbers in tick labels. This \a formatCode is an extended version of the format code used e.g. by QString::number() and QLocale::toString(). For reference about that, see the "Argument Formats" section in the detailed description of the QString class. \a formatCode is a string of one, two or three characters. The first character is identical to the normal format code used by Qt. In short, this means: 'e'/'E' scientific format, 'f' fixed format, 'g'/'G' scientific or fixed, whichever is shorter. The second and third characters are optional and specific to QCustomPlot:\n If the first char was 'e' or 'g', numbers are/might be displayed in the scientific format, e.g. "5.5e9", which might be visually unappealing in a plot. So when the second char of \a formatCode is set to 'b' (for "beautiful"), those exponential numbers are formatted in a more natural way, i.e. "5.5 [multiplication sign] 10 [superscript] 9". By default, the multiplication sign is a centered dot. If instead a cross should be shown (as is usual in the USA), the third char of \a formatCode can be set to 'c'. The inserted multiplication signs are the UTF-8 characters 215 (0xD7) for the cross and 183 (0xB7) for the dot. Examples for \a formatCode: \li \c g normal format code behaviour. If number is small, fixed format is used, if number is large, normal scientific format is used \li \c gb If number is small, fixed format is used, if number is large, scientific format is used with beautifully typeset decimal powers and a dot as multiplication sign \li \c ebc All numbers are in scientific format with beautifully typeset decimal power and a cross as multiplication sign \li \c fb illegal format code, since fixed format doesn't support (or need) beautifully typeset decimal powers. Format code will be reduced to 'f'. \li \c hello illegal format code, since first char is not 'e', 'E', 'f', 'g' or 'G'. Current format code will not be changed. */ void QCPPolarAxisAngular::setNumberFormat(const QString &formatCode) { if (formatCode.isEmpty()) { qDebug() << Q_FUNC_INFO << "Passed formatCode is empty"; return; } //mCachedMarginValid = false; // interpret first char as number format char: QString allowedFormatChars(QLatin1String("eEfgG")); if (allowedFormatChars.contains(formatCode.at(0))) { mNumberFormatChar = QLatin1Char(formatCode.at(0).toLatin1()); } else { qDebug() << Q_FUNC_INFO << "Invalid number format code (first char not in 'eEfgG'):" << formatCode; return; } if (formatCode.length() < 2) { mNumberBeautifulPowers = false; mNumberMultiplyCross = false; } else { // interpret second char as indicator for beautiful decimal powers: if (formatCode.at(1) == QLatin1Char('b') && (mNumberFormatChar == QLatin1Char('e') || mNumberFormatChar == QLatin1Char('g'))) mNumberBeautifulPowers = true; else qDebug() << Q_FUNC_INFO << "Invalid number format code (second char not 'b' or first char neither 'e' nor 'g'):" << formatCode; if (formatCode.length() < 3) { mNumberMultiplyCross = false; } else { // interpret third char as indicator for dot or cross multiplication symbol: if (formatCode.at(2) == QLatin1Char('c')) mNumberMultiplyCross = true; else if (formatCode.at(2) == QLatin1Char('d')) mNumberMultiplyCross = false; else qDebug() << Q_FUNC_INFO << "Invalid number format code (third char neither 'c' nor 'd'):" << formatCode; } } mLabelPainter.setSubstituteExponent(mNumberBeautifulPowers); mLabelPainter.setMultiplicationSymbol(mNumberMultiplyCross ? QCPLabelPainterPrivate::SymbolCross : QCPLabelPainterPrivate::SymbolDot); } /*! Sets the precision of the tick label numbers. See QLocale::toString(double i, char f, int prec) for details. The effect of precisions are most notably for number Formats starting with 'e', see \ref setNumberFormat */ void QCPPolarAxisAngular::setNumberPrecision(int precision) { if (mNumberPrecision != precision) { mNumberPrecision = precision; //mCachedMarginValid = false; } } /*! Sets the length of the ticks in pixels. \a inside is the length the ticks will reach inside the plot and \a outside is the length they will reach outside the plot. If \a outside is greater than zero, the tick labels and axis label will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setSubTickLength, setTickLengthIn, setTickLengthOut */ void QCPPolarAxisAngular::setTickLength(int inside, int outside) { setTickLengthIn(inside); setTickLengthOut(outside); } /*! Sets the length of the inward ticks in pixels. \a inside is the length the ticks will reach inside the plot. \see setTickLengthOut, setTickLength, setSubTickLength */ void QCPPolarAxisAngular::setTickLengthIn(int inside) { if (mTickLengthIn != inside) { mTickLengthIn = inside; } } /*! Sets the length of the outward ticks in pixels. \a outside is the length the ticks will reach outside the plot. If \a outside is greater than zero, the tick labels and axis label will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setTickLengthIn, setTickLength, setSubTickLength */ void QCPPolarAxisAngular::setTickLengthOut(int outside) { if (mTickLengthOut != outside) { mTickLengthOut = outside; //mCachedMarginValid = false; // only outside tick length can change margin } } /*! Sets whether sub tick marks are displayed. Sub ticks are only potentially visible if (major) ticks are also visible (see \ref setTicks) \see setTicks */ void QCPPolarAxisAngular::setSubTicks(bool show) { if (mSubTicks != show) { mSubTicks = show; //mCachedMarginValid = false; } } /*! Sets the length of the subticks in pixels. \a inside is the length the subticks will reach inside the plot and \a outside is the length they will reach outside the plot. If \a outside is greater than zero, the tick labels and axis label will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setTickLength, setSubTickLengthIn, setSubTickLengthOut */ void QCPPolarAxisAngular::setSubTickLength(int inside, int outside) { setSubTickLengthIn(inside); setSubTickLengthOut(outside); } /*! Sets the length of the inward subticks in pixels. \a inside is the length the subticks will reach inside the plot. \see setSubTickLengthOut, setSubTickLength, setTickLength */ void QCPPolarAxisAngular::setSubTickLengthIn(int inside) { if (mSubTickLengthIn != inside) { mSubTickLengthIn = inside; } } /*! Sets the length of the outward subticks in pixels. \a outside is the length the subticks will reach outside the plot. If \a outside is greater than zero, the tick labels will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setSubTickLengthIn, setSubTickLength, setTickLength */ void QCPPolarAxisAngular::setSubTickLengthOut(int outside) { if (mSubTickLengthOut != outside) { mSubTickLengthOut = outside; //mCachedMarginValid = false; // only outside tick length can change margin } } /*! Sets the pen, the axis base line is drawn with. \see setTickPen, setSubTickPen */ void QCPPolarAxisAngular::setBasePen(const QPen &pen) { mBasePen = pen; } /*! Sets the pen, tick marks will be drawn with. \see setTickLength, setBasePen */ void QCPPolarAxisAngular::setTickPen(const QPen &pen) { mTickPen = pen; } /*! Sets the pen, subtick marks will be drawn with. \see setSubTickCount, setSubTickLength, setBasePen */ void QCPPolarAxisAngular::setSubTickPen(const QPen &pen) { mSubTickPen = pen; } /*! Sets the font of the axis label. \see setLabelColor */ void QCPPolarAxisAngular::setLabelFont(const QFont &font) { if (mLabelFont != font) { mLabelFont = font; //mCachedMarginValid = false; } } /*! Sets the color of the axis label. \see setLabelFont */ void QCPPolarAxisAngular::setLabelColor(const QColor &color) { mLabelColor = color; } /*! Sets the text of the axis label that will be shown below/above or next to the axis, depending on its orientation. To disable axis labels, pass an empty string as \a str. */ void QCPPolarAxisAngular::setLabel(const QString &str) { if (mLabel != str) { mLabel = str; //mCachedMarginValid = false; } } /*! Sets the distance between the tick labels and the axis label. \see setTickLabelPadding, setPadding */ void QCPPolarAxisAngular::setLabelPadding(int padding) { if (mLabelPadding != padding) { mLabelPadding = padding; //mCachedMarginValid = false; } } /*! Sets the font that is used for tick labels when they are selected. \see setTickLabelFont, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisAngular::setSelectedTickLabelFont(const QFont &font) { if (font != mSelectedTickLabelFont) { mSelectedTickLabelFont = font; // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts } } /*! Sets the font that is used for the axis label when it is selected. \see setLabelFont, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisAngular::setSelectedLabelFont(const QFont &font) { mSelectedLabelFont = font; // don't set mCachedMarginValid to false here because margin calculation is always done with non-selected fonts } /*! Sets the color that is used for tick labels when they are selected. \see setTickLabelColor, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisAngular::setSelectedTickLabelColor(const QColor &color) { if (color != mSelectedTickLabelColor) { mSelectedTickLabelColor = color; } } /*! Sets the color that is used for the axis label when it is selected. \see setLabelColor, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisAngular::setSelectedLabelColor(const QColor &color) { mSelectedLabelColor = color; } /*! Sets the pen that is used to draw the axis base line when selected. \see setBasePen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisAngular::setSelectedBasePen(const QPen &pen) { mSelectedBasePen = pen; } /*! Sets the pen that is used to draw the (major) ticks when selected. \see setTickPen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisAngular::setSelectedTickPen(const QPen &pen) { mSelectedTickPen = pen; } /*! Sets the pen that is used to draw the subticks when selected. \see setSubTickPen, setSelectableParts, setSelectedParts, QCustomPlot::setInteractions */ void QCPPolarAxisAngular::setSelectedSubTickPen(const QPen &pen) { mSelectedSubTickPen = pen; } /*! \internal Draws the background of this axis rect. It may consist of a background fill (a QBrush) and a pixmap. If a brush was given via \ref setBackground(const QBrush &brush), this function first draws an according filling inside the axis rect with the provided \a painter. Then, if a pixmap was provided via \ref setBackground, this function buffers the scaled version depending on \ref setBackgroundScaled and \ref setBackgroundScaledMode and then draws it inside the axis rect with the provided \a painter. The scaled version is buffered in mScaledBackgroundPixmap to prevent expensive rescaling at every redraw. It is only updated, when the axis rect has changed in a way that requires a rescale of the background pixmap (this is dependent on the \ref setBackgroundScaledMode), or when a differend axis background pixmap was set. \see setBackground, setBackgroundScaled, setBackgroundScaledMode */ void QCPPolarAxisAngular::drawBackground(QCPPainter *painter, const QPointF ¢er, double radius) { // draw background fill (don't use circular clip, looks bad): if (mBackgroundBrush != Qt::NoBrush) { QPainterPath ellipsePath; ellipsePath.addEllipse(center, radius, radius); painter->fillPath(ellipsePath, mBackgroundBrush); } // draw background pixmap (on top of fill, if brush specified): if (!mBackgroundPixmap.isNull()) { QRegion clipCircle(center.x()-radius, center.y()-radius, qRound(2*radius), qRound(2*radius), QRegion::Ellipse); QRegion originalClip = painter->clipRegion(); painter->setClipRegion(clipCircle); if (mBackgroundScaled) { // check whether mScaledBackground needs to be updated: QSize scaledSize(mBackgroundPixmap.size()); scaledSize.scale(mRect.size(), mBackgroundScaledMode); if (mScaledBackgroundPixmap.size() != scaledSize) mScaledBackgroundPixmap = mBackgroundPixmap.scaled(mRect.size(), mBackgroundScaledMode, Qt::SmoothTransformation); painter->drawPixmap(mRect.topLeft()+QPoint(0, -1), mScaledBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height()) & mScaledBackgroundPixmap.rect()); } else { painter->drawPixmap(mRect.topLeft()+QPoint(0, -1), mBackgroundPixmap, QRect(0, 0, mRect.width(), mRect.height())); } painter->setClipRegion(originalClip); } } /*! \internal Prepares the internal tick vector, sub tick vector and tick label vector. This is done by calling QCPAxisTicker::generate on the currently installed ticker. If a change in the label text/count is detected, the cached axis margin is invalidated to make sure the next margin calculation recalculates the label sizes and returns an up-to-date value. */ void QCPPolarAxisAngular::setupTickVectors() { if (!mParentPlot) return; if ((!mTicks && !mTickLabels && !mGrid->visible()) || mRange.size() <= 0) return; mSubTickVector.clear(); // since we might not pass it to mTicker->generate(), and we don't want old data in there mTicker->generate(mRange, mParentPlot->locale(), mNumberFormatChar, mNumberPrecision, mTickVector, mSubTicks ? &mSubTickVector : 0, mTickLabels ? &mTickVectorLabels : 0); // fill cos/sin buffers which will be used by draw() and QCPPolarGrid::draw(), so we don't have to calculate it twice: mTickVectorCosSin.resize(mTickVector.size()); for (int i=0; ibuttons() & Qt::LeftButton) { mDragging = true; // initialize antialiasing backup in case we start dragging: if (mParentPlot->noAntialiasingOnDrag()) { mAADragBackup = mParentPlot->antialiasedElements(); mNotAADragBackup = mParentPlot->notAntialiasedElements(); } // Mouse range dragging interaction: if (mParentPlot->interactions().testFlag(QCP::iRangeDrag)) { mDragAngularStart = range(); mDragRadialStart.clear(); for (int i=0; irange()); } } } /*! \internal Event handler for when the mouse is moved on the axis rect. If range dragging was activated in a preceding \ref mousePressEvent, the range is moved accordingly. \see mousePressEvent, mouseReleaseEvent */ void QCPPolarAxisAngular::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) { Q_UNUSED(startPos) bool doReplot = false; // Mouse range dragging interaction: if (mDragging && mParentPlot->interactions().testFlag(QCP::iRangeDrag)) { if (mRangeDrag) { doReplot = true; double angleCoordStart, radiusCoordStart; double angleCoord, radiusCoord; pixelToCoord(startPos, angleCoordStart, radiusCoordStart); pixelToCoord(event->pos(), angleCoord, radiusCoord); double diff = angleCoordStart - angleCoord; setRange(mDragAngularStart.lower+diff, mDragAngularStart.upper+diff); } for (int i=0; irangeDrag()) continue; doReplot = true; double angleCoordStart, radiusCoordStart; double angleCoord, radiusCoord; ax->pixelToCoord(startPos, angleCoordStart, radiusCoordStart); ax->pixelToCoord(event->pos(), angleCoord, radiusCoord); if (ax->scaleType() == QCPPolarAxisRadial::stLinear) { double diff = radiusCoordStart - radiusCoord; ax->setRange(mDragRadialStart.at(i).lower+diff, mDragRadialStart.at(i).upper+diff); } else if (ax->scaleType() == QCPPolarAxisRadial::stLogarithmic) { if (radiusCoord != 0) { double diff = radiusCoordStart/radiusCoord; ax->setRange(mDragRadialStart.at(i).lower*diff, mDragRadialStart.at(i).upper*diff); } } } if (doReplot) // if either vertical or horizontal drag was enabled, do a replot { if (mParentPlot->noAntialiasingOnDrag()) mParentPlot->setNotAntialiasedElements(QCP::aeAll); mParentPlot->replot(QCustomPlot::rpQueuedReplot); } } } /* inherits documentation from base class */ void QCPPolarAxisAngular::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) { Q_UNUSED(event) Q_UNUSED(startPos) mDragging = false; if (mParentPlot->noAntialiasingOnDrag()) { mParentPlot->setAntialiasedElements(mAADragBackup); mParentPlot->setNotAntialiasedElements(mNotAADragBackup); } } /*! \internal Event handler for mouse wheel events. If rangeZoom is Qt::Horizontal, Qt::Vertical or both, the ranges of the axes defined as rangeZoomHorzAxis and rangeZoomVertAxis are scaled. The center of the scaling operation is the current cursor position inside the axis rect. The scaling factor is dependent on the mouse wheel delta (which direction the wheel was rotated) to provide a natural zooming feel. The Strength of the zoom can be controlled via \ref setRangeZoomFactor. Note, that event->delta() is usually +/-120 for single rotation steps. However, if the mouse wheel is turned rapidly, many steps may bunch up to one event, so the event->delta() may then be multiples of 120. This is taken into account here, by calculating \a wheelSteps and using it as exponent of the range zoom factor. This takes care of the wheel direction automatically, by inverting the factor, when the wheel step is negative (f^-1 = 1/f). */ void QCPPolarAxisAngular::wheelEvent(QWheelEvent *event) { bool doReplot = false; // Mouse range zooming interaction: if (mParentPlot->interactions().testFlag(QCP::iRangeZoom)) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) const double delta = event->delta(); #else const double delta = event->angleDelta().y(); #endif #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) const QPointF pos = event->pos(); #else const QPointF pos = event->position(); #endif const double wheelSteps = delta/120.0; // a single step delta is +/-120 usually if (mRangeZoom) { double angleCoord, radiusCoord; pixelToCoord(pos, angleCoord, radiusCoord); scaleRange(qPow(mRangeZoomFactor, wheelSteps), angleCoord); } for (int i=0; irangeZoom()) continue; doReplot = true; double angleCoord, radiusCoord; ax->pixelToCoord(pos, angleCoord, radiusCoord); ax->scaleRange(qPow(ax->rangeZoomFactor(), wheelSteps), radiusCoord); } } if (doReplot) mParentPlot->replot(); } bool QCPPolarAxisAngular::registerPolarGraph(QCPPolarGraph *graph) { if (mGraphs.contains(graph)) { qDebug() << Q_FUNC_INFO << "plottable already added:" << reinterpret_cast(graph); return false; } if (graph->keyAxis() != this) { qDebug() << Q_FUNC_INFO << "plottable not created with this as axis:" << reinterpret_cast(graph); return false; } mGraphs.append(graph); // possibly add plottable to legend: if (mParentPlot->autoAddPlottableToLegend()) graph->addToLegend(); if (!graph->layer()) // usually the layer is already set in the constructor of the plottable (via QCPLayerable constructor) graph->setLayer(mParentPlot->currentLayer()); return true; } /* end of 'src/polar/layoutelement-angularaxis.cpp' */ /* including file 'src/polar/polargrid.cpp' */ /* modified 2021-03-29T02:30:44, size 7493 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPolarGrid //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPolarGrid \brief The grid in both angular and radial dimensions for polar plots \warning In this QCustomPlot version, polar plots are a tech preview. Expect documentation and functionality to be incomplete, as well as changing public interfaces in the future. */ /*! Creates a QCPPolarGrid instance and sets default values. You shouldn't instantiate grids on their own, since every axis brings its own grid. */ QCPPolarGrid::QCPPolarGrid(QCPPolarAxisAngular *parentAxis) : QCPLayerable(parentAxis->parentPlot(), QString(), parentAxis), mType(gtNone), mSubGridType(gtNone), mAntialiasedSubGrid(true), mAntialiasedZeroLine(true), mParentAxis(parentAxis) { // warning: this is called in QCPPolarAxisAngular constructor, so parentAxis members should not be accessed/called setParent(parentAxis); setType(gtAll); setSubGridType(gtNone); setAngularPen(QPen(QColor(200,200,200), 0, Qt::DotLine)); setAngularSubGridPen(QPen(QColor(220,220,220), 0, Qt::DotLine)); setRadialPen(QPen(QColor(200,200,200), 0, Qt::DotLine)); setRadialSubGridPen(QPen(QColor(220,220,220), 0, Qt::DotLine)); setRadialZeroLinePen(QPen(QColor(200,200,200), 0, Qt::SolidLine)); setAntialiased(true); } void QCPPolarGrid::setRadialAxis(QCPPolarAxisRadial *axis) { mRadialAxis = axis; } void QCPPolarGrid::setType(GridTypes type) { mType = type; } void QCPPolarGrid::setSubGridType(GridTypes type) { mSubGridType = type; } /*! Sets whether sub grid lines are drawn antialiased. */ void QCPPolarGrid::setAntialiasedSubGrid(bool enabled) { mAntialiasedSubGrid = enabled; } /*! Sets whether zero lines are drawn antialiased. */ void QCPPolarGrid::setAntialiasedZeroLine(bool enabled) { mAntialiasedZeroLine = enabled; } /*! Sets the pen with which (major) grid lines are drawn. */ void QCPPolarGrid::setAngularPen(const QPen &pen) { mAngularPen = pen; } /*! Sets the pen with which sub grid lines are drawn. */ void QCPPolarGrid::setAngularSubGridPen(const QPen &pen) { mAngularSubGridPen = pen; } void QCPPolarGrid::setRadialPen(const QPen &pen) { mRadialPen = pen; } void QCPPolarGrid::setRadialSubGridPen(const QPen &pen) { mRadialSubGridPen = pen; } void QCPPolarGrid::setRadialZeroLinePen(const QPen &pen) { mRadialZeroLinePen = pen; } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing the major grid lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set with \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased */ void QCPPolarGrid::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeGrid); } /*! \internal Draws grid lines and sub grid lines at the positions of (sub) ticks of the parent axis, spanning over the complete axis rect. Also draws the zero line, if appropriate (\ref setZeroLinePen). */ void QCPPolarGrid::draw(QCPPainter *painter) { if (!mParentAxis) { qDebug() << Q_FUNC_INFO << "invalid parent axis"; return; } const QPointF center = mParentAxis->mCenter; const double radius = mParentAxis->mRadius; painter->setBrush(Qt::NoBrush); // draw main angular grid: if (mType.testFlag(gtAngular)) drawAngularGrid(painter, center, radius, mParentAxis->mTickVectorCosSin, mAngularPen); // draw main radial grid: if (mType.testFlag(gtRadial) && mRadialAxis) drawRadialGrid(painter, center, mRadialAxis->tickVector(), mRadialPen, mRadialZeroLinePen); applyAntialiasingHint(painter, mAntialiasedSubGrid, QCP::aeGrid); // draw sub angular grid: if (mSubGridType.testFlag(gtAngular)) drawAngularGrid(painter, center, radius, mParentAxis->mSubTickVectorCosSin, mAngularSubGridPen); // draw sub radial grid: if (mSubGridType.testFlag(gtRadial) && mRadialAxis) drawRadialGrid(painter, center, mRadialAxis->subTickVector(), mRadialSubGridPen); } void QCPPolarGrid::drawRadialGrid(QCPPainter *painter, const QPointF ¢er, const QVector &coords, const QPen &pen, const QPen &zeroPen) { if (!mRadialAxis) return; if (coords.isEmpty()) return; const bool drawZeroLine = zeroPen != Qt::NoPen; const double zeroLineEpsilon = qAbs(coords.last()-coords.first())*1e-6; painter->setPen(pen); for (int i=0; icoordToRadius(coords.at(i)); if (drawZeroLine && qAbs(coords.at(i)) < zeroLineEpsilon) { applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine); painter->setPen(zeroPen); painter->drawEllipse(center, r, r); painter->setPen(pen); applyDefaultAntialiasingHint(painter); } else { painter->drawEllipse(center, r, r); } } } void QCPPolarGrid::drawAngularGrid(QCPPainter *painter, const QPointF ¢er, double radius, const QVector &ticksCosSin, const QPen &pen) { if (ticksCosSin.isEmpty()) return; painter->setPen(pen); for (int i=0; idrawLine(center, center+ticksCosSin.at(i)*radius); } /* end of 'src/polar/polargrid.cpp' */ /* including file 'src/polar/polargraph.cpp' */ /* modified 2021-03-29T02:30:44, size 44035 */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPolarLegendItem //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPolarLegendItem \brief A legend item for polar plots \warning In this QCustomPlot version, polar plots are a tech preview. Expect documentation and functionality to be incomplete, as well as changing public interfaces in the future. */ QCPPolarLegendItem::QCPPolarLegendItem(QCPLegend *parent, QCPPolarGraph *graph) : QCPAbstractLegendItem(parent), mPolarGraph(graph) { setAntialiased(false); } void QCPPolarLegendItem::draw(QCPPainter *painter) { if (!mPolarGraph) return; painter->setFont(getFont()); painter->setPen(QPen(getTextColor())); QSizeF iconSize = mParentLegend->iconSize(); QRectF textRect = painter->fontMetrics().boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPolarGraph->name()); QRectF iconRect(mRect.topLeft(), iconSize); int textHeight = qMax(textRect.height(), iconSize.height()); // if text has smaller height than icon, center text vertically in icon height, else align tops painter->drawText(mRect.x()+iconSize.width()+mParentLegend->iconTextPadding(), mRect.y(), textRect.width(), textHeight, Qt::TextDontClip, mPolarGraph->name()); // draw icon: painter->save(); painter->setClipRect(iconRect, Qt::IntersectClip); mPolarGraph->drawLegendIcon(painter, iconRect); painter->restore(); // draw icon border: if (getIconBorderPen().style() != Qt::NoPen) { painter->setPen(getIconBorderPen()); painter->setBrush(Qt::NoBrush); int halfPen = qCeil(painter->pen().widthF()*0.5)+1; painter->setClipRect(mOuterRect.adjusted(-halfPen, -halfPen, halfPen, halfPen)); // extend default clip rect so thicker pens (especially during selection) are not clipped painter->drawRect(iconRect); } } QSize QCPPolarLegendItem::minimumOuterSizeHint() const { if (!mPolarGraph) return QSize(); QSize result(0, 0); QRect textRect; QFontMetrics fontMetrics(getFont()); QSize iconSize = mParentLegend->iconSize(); textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPolarGraph->name()); result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width()); result.setHeight(qMax(textRect.height(), iconSize.height())); result.rwidth() += mMargins.left()+mMargins.right(); result.rheight() += mMargins.top()+mMargins.bottom(); return result; } QPen QCPPolarLegendItem::getIconBorderPen() const { return mSelected ? mParentLegend->selectedIconBorderPen() : mParentLegend->iconBorderPen(); } QColor QCPPolarLegendItem::getTextColor() const { return mSelected ? mSelectedTextColor : mTextColor; } QFont QCPPolarLegendItem::getFont() const { return mSelected ? mSelectedFont : mFont; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPolarGraph //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPolarGraph \brief A radial graph used to display data in polar plots \warning In this QCustomPlot version, polar plots are a tech preview. Expect documentation and functionality to be incomplete, as well as changing public interfaces in the future. */ /* start of documentation of inline functions */ // TODO /* end of documentation of inline functions */ /*! Constructs a graph which uses \a keyAxis as its angular and \a valueAxis as its radial axis. \a keyAxis and \a valueAxis must reside in the same QCustomPlot, and the radial axis must be associated with the angular axis. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The created QCPPolarGraph is automatically registered with the QCustomPlot instance inferred from \a keyAxis. This QCustomPlot instance takes ownership of the QCPPolarGraph, so do not delete it manually but use QCPPolarAxisAngular::removeGraph() instead. To directly create a QCPPolarGraph inside a plot, you shoud use the QCPPolarAxisAngular::addGraph method. */ QCPPolarGraph::QCPPolarGraph(QCPPolarAxisAngular *keyAxis, QCPPolarAxisRadial *valueAxis) : QCPLayerable(keyAxis->parentPlot(), QString(), keyAxis), mDataContainer(new QCPGraphDataContainer), mName(), mAntialiasedFill(true), mAntialiasedScatters(true), mPen(Qt::black), mBrush(Qt::NoBrush), mPeriodic(true), mKeyAxis(keyAxis), mValueAxis(valueAxis), mSelectable(QCP::stWhole) //mSelectionDecorator(0) // TODO { if (keyAxis->parentPlot() != valueAxis->parentPlot()) qDebug() << Q_FUNC_INFO << "Parent plot of keyAxis is not the same as that of valueAxis."; mKeyAxis->registerPolarGraph(this); //setSelectionDecorator(new QCPSelectionDecorator); // TODO setPen(QPen(Qt::blue, 0)); setBrush(Qt::NoBrush); setLineStyle(lsLine); } QCPPolarGraph::~QCPPolarGraph() { /* TODO if (mSelectionDecorator) { delete mSelectionDecorator; mSelectionDecorator = 0; } */ } /*! The name is the textual representation of this plottable as it is displayed in the legend (\ref QCPLegend). It may contain any UTF-8 characters, including newlines. */ void QCPPolarGraph::setName(const QString &name) { mName = name; } /*! Sets whether fills of this plottable are drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPPolarGraph::setAntialiasedFill(bool enabled) { mAntialiasedFill = enabled; } /*! Sets whether the scatter symbols of this plottable are drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPPolarGraph::setAntialiasedScatters(bool enabled) { mAntialiasedScatters = enabled; } /*! The pen is used to draw basic lines that make up the plottable representation in the plot. For example, the \ref QCPGraph subclass draws its graph lines with this pen. \see setBrush */ void QCPPolarGraph::setPen(const QPen &pen) { mPen = pen; } /*! The brush is used to draw basic fills of the plottable representation in the plot. The Fill can be a color, gradient or texture, see the usage of QBrush. For example, the \ref QCPGraph subclass draws the fill under the graph with this brush, when it's not set to Qt::NoBrush. \see setPen */ void QCPPolarGraph::setBrush(const QBrush &brush) { mBrush = brush; } void QCPPolarGraph::setPeriodic(bool enabled) { mPeriodic = enabled; } /*! The key axis of a plottable can be set to any axis of a QCustomPlot, as long as it is orthogonal to the plottable's value axis. This function performs no checks to make sure this is the case. The typical mathematical choice is to use the x-axis (QCustomPlot::xAxis) as key axis and the y-axis (QCustomPlot::yAxis) as value axis. Normally, the key and value axes are set in the constructor of the plottable (or \ref QCustomPlot::addGraph when working with QCPGraphs through the dedicated graph interface). \see setValueAxis */ void QCPPolarGraph::setKeyAxis(QCPPolarAxisAngular *axis) { mKeyAxis = axis; } /*! The value axis of a plottable can be set to any axis of a QCustomPlot, as long as it is orthogonal to the plottable's key axis. This function performs no checks to make sure this is the case. The typical mathematical choice is to use the x-axis (QCustomPlot::xAxis) as key axis and the y-axis (QCustomPlot::yAxis) as value axis. Normally, the key and value axes are set in the constructor of the plottable (or \ref QCustomPlot::addGraph when working with QCPGraphs through the dedicated graph interface). \see setKeyAxis */ void QCPPolarGraph::setValueAxis(QCPPolarAxisRadial *axis) { mValueAxis = axis; } /*! Sets whether and to which granularity this plottable can be selected. A selection can happen by clicking on the QCustomPlot surface (When \ref QCustomPlot::setInteractions contains \ref QCP::iSelectPlottables), by dragging a selection rect (When \ref QCustomPlot::setSelectionRectMode is \ref QCP::srmSelect), or programmatically by calling \ref setSelection. \see setSelection, QCP::SelectionType */ void QCPPolarGraph::setSelectable(QCP::SelectionType selectable) { if (mSelectable != selectable) { mSelectable = selectable; QCPDataSelection oldSelection = mSelection; mSelection.enforceType(mSelectable); emit selectableChanged(mSelectable); if (mSelection != oldSelection) { emit selectionChanged(selected()); emit selectionChanged(mSelection); } } } /*! Sets which data ranges of this plottable are selected. Selected data ranges are drawn differently (e.g. color) in the plot. This can be controlled via the selection decorator (see \ref selectionDecorator). The entire selection mechanism for plottables is handled automatically when \ref QCustomPlot::setInteractions contains iSelectPlottables. You only need to call this function when you wish to change the selection state programmatically. Using \ref setSelectable you can further specify for each plottable whether and to which granularity it is selectable. If \a selection is not compatible with the current \ref QCP::SelectionType set via \ref setSelectable, the resulting selection will be adjusted accordingly (see \ref QCPDataSelection::enforceType). emits the \ref selectionChanged signal when \a selected is different from the previous selection state. \see setSelectable, selectTest */ void QCPPolarGraph::setSelection(QCPDataSelection selection) { selection.enforceType(mSelectable); if (mSelection != selection) { mSelection = selection; emit selectionChanged(selected()); emit selectionChanged(mSelection); } } /*! \overload Replaces the current data container with the provided \a data container. Since a QSharedPointer is used, multiple QCPPolarGraphs may share the same data container safely. Modifying the data in the container will then affect all graphs that share the container. Sharing can be achieved by simply exchanging the data containers wrapped in shared pointers: \snippet documentation/doc-code-snippets/mainwindow.cpp QCPPolarGraph-datasharing-1 If you do not wish to share containers, but create a copy from an existing container, rather use the \ref QCPDataContainer::set method on the graph's data container directly: \snippet documentation/doc-code-snippets/mainwindow.cpp QCPPolarGraph-datasharing-2 \see addData */ void QCPPolarGraph::setData(QSharedPointer data) { mDataContainer = data; } /*! \overload Replaces the current data with the provided points in \a keys and \a values. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. If you can guarantee that the passed data points are sorted by \a keys in ascending order, you can set \a alreadySorted to true, to improve performance by saving a sorting run. \see addData */ void QCPPolarGraph::setData(const QVector &keys, const QVector &values, bool alreadySorted) { mDataContainer->clear(); addData(keys, values, alreadySorted); } /*! Sets how the single data points are connected in the plot. For scatter-only plots, set \a ls to \ref lsNone and \ref setScatterStyle to the desired scatter style. \see setScatterStyle */ void QCPPolarGraph::setLineStyle(LineStyle ls) { mLineStyle = ls; } /*! Sets the visual appearance of single data points in the plot. If set to \ref QCPScatterStyle::ssNone, no scatter points are drawn (e.g. for line-only-plots with appropriate line style). \see QCPScatterStyle, setLineStyle */ void QCPPolarGraph::setScatterStyle(const QCPScatterStyle &style) { mScatterStyle = style; } void QCPPolarGraph::addData(const QVector &keys, const QVector &values, bool alreadySorted) { if (keys.size() != values.size()) qDebug() << Q_FUNC_INFO << "keys and values have different sizes:" << keys.size() << values.size(); const int n = qMin(keys.size(), values.size()); QVector tempData(n); QVector::iterator it = tempData.begin(); const QVector::iterator itEnd = tempData.end(); int i = 0; while (it != itEnd) { it->key = keys[i]; it->value = values[i]; ++it; ++i; } mDataContainer->add(tempData, alreadySorted); // don't modify tempData beyond this to prevent copy on write } void QCPPolarGraph::addData(double key, double value) { mDataContainer->add(QCPGraphData(key, value)); } /*! Use this method to set an own QCPSelectionDecorator (subclass) instance. This allows you to customize the visual representation of selected data ranges further than by using the default QCPSelectionDecorator. The plottable takes ownership of the \a decorator. The currently set decorator can be accessed via \ref selectionDecorator. */ /* void QCPPolarGraph::setSelectionDecorator(QCPSelectionDecorator *decorator) { if (decorator) { if (decorator->registerWithPlottable(this)) { if (mSelectionDecorator) // delete old decorator if necessary delete mSelectionDecorator; mSelectionDecorator = decorator; } } else if (mSelectionDecorator) // just clear decorator { delete mSelectionDecorator; mSelectionDecorator = 0; } } */ void QCPPolarGraph::coordsToPixels(double key, double value, double &x, double &y) const { if (mValueAxis) { const QPointF point = mValueAxis->coordToPixel(key, value); x = point.x(); y = point.y(); } else { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; } } const QPointF QCPPolarGraph::coordsToPixels(double key, double value) const { if (mValueAxis) { return mValueAxis->coordToPixel(key, value); } else { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return QPointF(); } } void QCPPolarGraph::pixelsToCoords(double x, double y, double &key, double &value) const { if (mValueAxis) { mValueAxis->pixelToCoord(QPointF(x, y), key, value); } else { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; } } void QCPPolarGraph::pixelsToCoords(const QPointF &pixelPos, double &key, double &value) const { if (mValueAxis) { mValueAxis->pixelToCoord(pixelPos, key, value); } else { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; } } void QCPPolarGraph::rescaleAxes(bool onlyEnlarge) const { rescaleKeyAxis(onlyEnlarge); rescaleValueAxis(onlyEnlarge); } void QCPPolarGraph::rescaleKeyAxis(bool onlyEnlarge) const { QCPPolarAxisAngular *keyAxis = mKeyAxis.data(); if (!keyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; } bool foundRange; QCPRange newRange = getKeyRange(foundRange, QCP::sdBoth); if (foundRange) { if (onlyEnlarge) newRange.expand(keyAxis->range()); if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable { double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason newRange.lower = center-keyAxis->range().size()/2.0; newRange.upper = center+keyAxis->range().size()/2.0; } keyAxis->setRange(newRange); } } void QCPPolarGraph::rescaleValueAxis(bool onlyEnlarge, bool inKeyRange) const { QCPPolarAxisAngular *keyAxis = mKeyAxis.data(); QCPPolarAxisRadial *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } QCP::SignDomain signDomain = QCP::sdBoth; if (valueAxis->scaleType() == QCPPolarAxisRadial::stLogarithmic) signDomain = (valueAxis->range().upper < 0 ? QCP::sdNegative : QCP::sdPositive); bool foundRange; QCPRange newRange = getValueRange(foundRange, signDomain, inKeyRange ? keyAxis->range() : QCPRange()); if (foundRange) { if (onlyEnlarge) newRange.expand(valueAxis->range()); if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable { double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason if (valueAxis->scaleType() == QCPPolarAxisRadial::stLinear) { newRange.lower = center-valueAxis->range().size()/2.0; newRange.upper = center+valueAxis->range().size()/2.0; } else // scaleType() == stLogarithmic { newRange.lower = center/qSqrt(valueAxis->range().upper/valueAxis->range().lower); newRange.upper = center*qSqrt(valueAxis->range().upper/valueAxis->range().lower); } } valueAxis->setRange(newRange); } } bool QCPPolarGraph::addToLegend(QCPLegend *legend) { if (!legend) { qDebug() << Q_FUNC_INFO << "passed legend is null"; return false; } if (legend->parentPlot() != mParentPlot) { qDebug() << Q_FUNC_INFO << "passed legend isn't in the same QCustomPlot as this plottable"; return false; } //if (!legend->hasItemWithPlottable(this)) // TODO //{ legend->addItem(new QCPPolarLegendItem(legend, this)); return true; //} else // return false; } bool QCPPolarGraph::addToLegend() { if (!mParentPlot || !mParentPlot->legend) return false; else return addToLegend(mParentPlot->legend); } bool QCPPolarGraph::removeFromLegend(QCPLegend *legend) const { if (!legend) { qDebug() << Q_FUNC_INFO << "passed legend is null"; return false; } QCPPolarLegendItem *removableItem = 0; for (int i=0; iitemCount(); ++i) // TODO: reduce this to code in QCPAbstractPlottable::removeFromLegend once unified { if (QCPPolarLegendItem *pli = qobject_cast(legend->item(i))) { if (pli->polarGraph() == this) { removableItem = pli; break; } } } if (removableItem) return legend->removeItem(removableItem); else return false; } bool QCPPolarGraph::removeFromLegend() const { if (!mParentPlot || !mParentPlot->legend) return false; else return removeFromLegend(mParentPlot->legend); } double QCPPolarGraph::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return -1; if (!mKeyAxis || !mValueAxis) return -1; if (mKeyAxis->rect().contains(pos.toPoint())) { QCPGraphDataContainer::const_iterator closestDataPoint = mDataContainer->constEnd(); double result = pointDistance(pos, closestDataPoint); if (details) { int pointIndex = closestDataPoint-mDataContainer->constBegin(); details->setValue(QCPDataSelection(QCPDataRange(pointIndex, pointIndex+1))); } return result; } else return -1; } /* inherits documentation from base class */ QCPRange QCPPolarGraph::getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain) const { return mDataContainer->keyRange(foundRange, inSignDomain); } /* inherits documentation from base class */ QCPRange QCPPolarGraph::getValueRange(bool &foundRange, QCP::SignDomain inSignDomain, const QCPRange &inKeyRange) const { return mDataContainer->valueRange(foundRange, inSignDomain, inKeyRange); } /* inherits documentation from base class */ QRect QCPPolarGraph::clipRect() const { if (mKeyAxis) return mKeyAxis.data()->rect(); else return QRect(); } void QCPPolarGraph::draw(QCPPainter *painter) { if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (mKeyAxis.data()->range().size() <= 0 || mDataContainer->isEmpty()) return; if (mLineStyle == lsNone && mScatterStyle.isNone()) return; painter->setClipRegion(mKeyAxis->exactClipRegion()); QVector lines, scatters; // line and (if necessary) scatter pixel coordinates will be stored here while iterating over segments // loop over and draw segments of unselected/selected data: QList selectedSegments, unselectedSegments, allSegments; getDataSegments(selectedSegments, unselectedSegments); allSegments << unselectedSegments << selectedSegments; for (int i=0; i= unselectedSegments.size(); // get line pixel points appropriate to line style: QCPDataRange lineDataRange = isSelectedSegment ? allSegments.at(i) : allSegments.at(i).adjusted(-1, 1); // unselected segments extend lines to bordering selected data point (safe to exceed total data bounds in first/last segment, getLines takes care) getLines(&lines, lineDataRange); // check data validity if flag set: #ifdef QCUSTOMPLOT_CHECK_DATA QCPGraphDataContainer::const_iterator it; for (it = mDataContainer->constBegin(); it != mDataContainer->constEnd(); ++it) { if (QCP::isInvalidData(it->key, it->value)) qDebug() << Q_FUNC_INFO << "Data point at" << it->key << "invalid." << "Plottable name:" << name(); } #endif // draw fill of graph: //if (isSelectedSegment && mSelectionDecorator) // mSelectionDecorator->applyBrush(painter); //else painter->setBrush(mBrush); painter->setPen(Qt::NoPen); drawFill(painter, &lines); // draw line: if (mLineStyle != lsNone) { //if (isSelectedSegment && mSelectionDecorator) // mSelectionDecorator->applyPen(painter); //else painter->setPen(mPen); painter->setBrush(Qt::NoBrush); drawLinePlot(painter, lines); } // draw scatters: QCPScatterStyle finalScatterStyle = mScatterStyle; //if (isSelectedSegment && mSelectionDecorator) // finalScatterStyle = mSelectionDecorator->getFinalScatterStyle(mScatterStyle); if (!finalScatterStyle.isNone()) { getScatters(&scatters, allSegments.at(i)); drawScatterPlot(painter, scatters, finalScatterStyle); } } // draw other selection decoration that isn't just line/scatter pens and brushes: //if (mSelectionDecorator) // mSelectionDecorator->drawDecoration(painter, selection()); } QCP::Interaction QCPPolarGraph::selectionCategory() const { return QCP::iSelectPlottables; } void QCPPolarGraph::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aePlottables); } /* inherits documentation from base class */ void QCPPolarGraph::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) { Q_UNUSED(event) if (mSelectable != QCP::stNone) { QCPDataSelection newSelection = details.value(); QCPDataSelection selectionBefore = mSelection; if (additive) { if (mSelectable == QCP::stWhole) // in whole selection mode, we toggle to no selection even if currently unselected point was hit { if (selected()) setSelection(QCPDataSelection()); else setSelection(newSelection); } else // in all other selection modes we toggle selections of homogeneously selected/unselected segments { if (mSelection.contains(newSelection)) // if entire newSelection is already selected, toggle selection setSelection(mSelection-newSelection); else setSelection(mSelection+newSelection); } } else setSelection(newSelection); if (selectionStateChanged) *selectionStateChanged = mSelection != selectionBefore; } } /* inherits documentation from base class */ void QCPPolarGraph::deselectEvent(bool *selectionStateChanged) { if (mSelectable != QCP::stNone) { QCPDataSelection selectionBefore = mSelection; setSelection(QCPDataSelection()); if (selectionStateChanged) *selectionStateChanged = mSelection != selectionBefore; } } /*! \internal Draws lines between the points in \a lines, given in pixel coordinates. \see drawScatterPlot, drawImpulsePlot, QCPAbstractPlottable1D::drawPolyline */ void QCPPolarGraph::drawLinePlot(QCPPainter *painter, const QVector &lines) const { if (painter->pen().style() != Qt::NoPen && painter->pen().color().alpha() != 0) { applyDefaultAntialiasingHint(painter); drawPolyline(painter, lines); } } /*! \internal Draws the fill of the graph using the specified \a painter, with the currently set brush. Depending on whether a normal fill or a channel fill (\ref setChannelFillGraph) is needed, \ref getFillPolygon or \ref getChannelFillPolygon are used to find the according fill polygons. In order to handle NaN Data points correctly (the fill needs to be split into disjoint areas), this method first determines a list of non-NaN segments with \ref getNonNanSegments, on which to operate. In the channel fill case, \ref getOverlappingSegments is used to consolidate the non-NaN segments of the two involved graphs, before passing the overlapping pairs to \ref getChannelFillPolygon. Pass the points of this graph's line as \a lines, in pixel coordinates. \see drawLinePlot, drawImpulsePlot, drawScatterPlot */ void QCPPolarGraph::drawFill(QCPPainter *painter, QVector *lines) const { applyFillAntialiasingHint(painter); if (painter->brush().style() != Qt::NoBrush && painter->brush().color().alpha() != 0) painter->drawPolygon(QPolygonF(*lines)); } /*! \internal Draws scatter symbols at every point passed in \a scatters, given in pixel coordinates. The scatters will be drawn with \a painter and have the appearance as specified in \a style. \see drawLinePlot, drawImpulsePlot */ void QCPPolarGraph::drawScatterPlot(QCPPainter *painter, const QVector &scatters, const QCPScatterStyle &style) const { applyScattersAntialiasingHint(painter); style.applyTo(painter, mPen); for (int i=0; ifillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush); } // draw line vertically centered: if (mLineStyle != lsNone) { applyDefaultAntialiasingHint(painter); painter->setPen(mPen); painter->drawLine(QLineF(rect.left(), rect.top()+rect.height()/2.0, rect.right()+5, rect.top()+rect.height()/2.0)); // +5 on x2 else last segment is missing from dashed/dotted pens } // draw scatter symbol: if (!mScatterStyle.isNone()) { applyScattersAntialiasingHint(painter); // scale scatter pixmap if it's too large to fit in legend icon rect: if (mScatterStyle.shape() == QCPScatterStyle::ssPixmap && (mScatterStyle.pixmap().size().width() > rect.width() || mScatterStyle.pixmap().size().height() > rect.height())) { QCPScatterStyle scaledStyle(mScatterStyle); scaledStyle.setPixmap(scaledStyle.pixmap().scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); scaledStyle.applyTo(painter, mPen); scaledStyle.drawShape(painter, QRectF(rect).center()); } else { mScatterStyle.applyTo(painter, mPen); mScatterStyle.drawShape(painter, QRectF(rect).center()); } } } void QCPPolarGraph::applyFillAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiasedFill, QCP::aeFills); } void QCPPolarGraph::applyScattersAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiasedScatters, QCP::aeScatters); } double QCPPolarGraph::pointDistance(const QPointF &pixelPoint, QCPGraphDataContainer::const_iterator &closestData) const { closestData = mDataContainer->constEnd(); if (mDataContainer->isEmpty()) return -1.0; if (mLineStyle == lsNone && mScatterStyle.isNone()) return -1.0; // calculate minimum distances to graph data points and find closestData iterator: double minDistSqr = (std::numeric_limits::max)(); // determine which key range comes into question, taking selection tolerance around pos into account: double posKeyMin, posKeyMax, dummy; pixelsToCoords(pixelPoint-QPointF(mParentPlot->selectionTolerance(), mParentPlot->selectionTolerance()), posKeyMin, dummy); pixelsToCoords(pixelPoint+QPointF(mParentPlot->selectionTolerance(), mParentPlot->selectionTolerance()), posKeyMax, dummy); if (posKeyMin > posKeyMax) qSwap(posKeyMin, posKeyMax); // iterate over found data points and then choose the one with the shortest distance to pos: QCPGraphDataContainer::const_iterator begin = mDataContainer->findBegin(posKeyMin, true); QCPGraphDataContainer::const_iterator end = mDataContainer->findEnd(posKeyMax, true); for (QCPGraphDataContainer::const_iterator it=begin; it!=end; ++it) { const double currentDistSqr = QCPVector2D(coordsToPixels(it->key, it->value)-pixelPoint).lengthSquared(); if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; closestData = it; } } // calculate distance to graph line if there is one (if so, will probably be smaller than distance to closest data point): if (mLineStyle != lsNone) { // line displayed, calculate distance to line segments: QVector lineData; getLines(&lineData, QCPDataRange(0, dataCount())); QCPVector2D p(pixelPoint); for (int i=0; isize(); } void QCPPolarGraph::getDataSegments(QList &selectedSegments, QList &unselectedSegments) const { selectedSegments.clear(); unselectedSegments.clear(); if (mSelectable == QCP::stWhole) // stWhole selection type draws the entire plottable with selected style if mSelection isn't empty { if (selected()) selectedSegments << QCPDataRange(0, dataCount()); else unselectedSegments << QCPDataRange(0, dataCount()); } else { QCPDataSelection sel(selection()); sel.simplify(); selectedSegments = sel.dataRanges(); unselectedSegments = sel.inverse(QCPDataRange(0, dataCount())).dataRanges(); } } void QCPPolarGraph::drawPolyline(QCPPainter *painter, const QVector &lineData) const { // if drawing solid line and not in PDF, use much faster line drawing instead of polyline: if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) && painter->pen().style() == Qt::SolidLine && !painter->modes().testFlag(QCPPainter::pmVectorized) && !painter->modes().testFlag(QCPPainter::pmNoCaching)) { int i = 0; bool lastIsNan = false; const int lineDataSize = lineData.size(); while (i < lineDataSize && (qIsNaN(lineData.at(i).y()) || qIsNaN(lineData.at(i).x()))) // make sure first point is not NaN ++i; ++i; // because drawing works in 1 point retrospect while (i < lineDataSize) { if (!qIsNaN(lineData.at(i).y()) && !qIsNaN(lineData.at(i).x())) // NaNs create a gap in the line { if (!lastIsNan) painter->drawLine(lineData.at(i-1), lineData.at(i)); else lastIsNan = false; } else lastIsNan = true; ++i; } } else { int segmentStart = 0; int i = 0; const int lineDataSize = lineData.size(); while (i < lineDataSize) { if (qIsNaN(lineData.at(i).y()) || qIsNaN(lineData.at(i).x()) || qIsInf(lineData.at(i).y())) // NaNs create a gap in the line. Also filter Infs which make drawPolyline block { painter->drawPolyline(lineData.constData()+segmentStart, i-segmentStart); // i, because we don't want to include the current NaN point segmentStart = i+1; } ++i; } // draw last segment: painter->drawPolyline(lineData.constData()+segmentStart, lineDataSize-segmentStart); } } void QCPPolarGraph::getVisibleDataBounds(QCPGraphDataContainer::const_iterator &begin, QCPGraphDataContainer::const_iterator &end, const QCPDataRange &rangeRestriction) const { if (rangeRestriction.isEmpty()) { end = mDataContainer->constEnd(); begin = end; } else { QCPPolarAxisAngular *keyAxis = mKeyAxis.data(); QCPPolarAxisRadial *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } // get visible data range: if (mPeriodic) { begin = mDataContainer->constBegin(); end = mDataContainer->constEnd(); } else { begin = mDataContainer->findBegin(keyAxis->range().lower); end = mDataContainer->findEnd(keyAxis->range().upper); } // limit lower/upperEnd to rangeRestriction: mDataContainer->limitIteratorsToDataRange(begin, end, rangeRestriction); // this also ensures rangeRestriction outside data bounds doesn't break anything } } /*! \internal This method retrieves an optimized set of data points via \ref getOptimizedLineData, an branches out to the line style specific functions such as \ref dataToLines, \ref dataToStepLeftLines, etc. according to the line style of the graph. \a lines will be filled with points in pixel coordinates, that can be drawn with the according draw functions like \ref drawLinePlot and \ref drawImpulsePlot. The points returned in \a lines aren't necessarily the original data points. For example, step line styles require additional points to form the steps when drawn. If the line style of the graph is \ref lsNone, the \a lines vector will be empty. \a dataRange specifies the beginning and ending data indices that will be taken into account for conversion. In this function, the specified range may exceed the total data bounds without harm: a correspondingly trimmed data range will be used. This takes the burden off the user of this function to check for valid indices in \a dataRange, e.g. when extending ranges coming from \ref getDataSegments. \see getScatters */ void QCPPolarGraph::getLines(QVector *lines, const QCPDataRange &dataRange) const { if (!lines) return; QCPGraphDataContainer::const_iterator begin, end; getVisibleDataBounds(begin, end, dataRange); if (begin == end) { lines->clear(); return; } QVector lineData; if (mLineStyle != lsNone) getOptimizedLineData(&lineData, begin, end); switch (mLineStyle) { case lsNone: lines->clear(); break; case lsLine: *lines = dataToLines(lineData); break; } } void QCPPolarGraph::getScatters(QVector *scatters, const QCPDataRange &dataRange) const { QCPPolarAxisAngular *keyAxis = mKeyAxis.data(); QCPPolarAxisRadial *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (!scatters) return; QCPGraphDataContainer::const_iterator begin, end; getVisibleDataBounds(begin, end, dataRange); if (begin == end) { scatters->clear(); return; } QVector data; getOptimizedScatterData(&data, begin, end); scatters->resize(data.size()); for (int i=0; icoordToPixel(data.at(i).key, data.at(i).value); } } void QCPPolarGraph::getOptimizedLineData(QVector *lineData, const QCPGraphDataContainer::const_iterator &begin, const QCPGraphDataContainer::const_iterator &end) const { lineData->clear(); // TODO: fix for log axes and thick line style const QCPRange range = mValueAxis->range(); bool reversed = mValueAxis->rangeReversed(); const double clipMargin = range.size()*0.05; // extra distance from visible circle, so optimized outside lines can cover more angle before having to place a dummy point to prevent tangents const double upperClipValue = range.upper + (reversed ? 0 : range.size()*0.05+clipMargin); // clip slightly outside of actual range to avoid line thicknesses to peek into visible circle const double lowerClipValue = range.lower - (reversed ? range.size()*0.05+clipMargin : 0); // clip slightly outside of actual range to avoid line thicknesses to peek into visible circle const double maxKeySkip = qAsin(qSqrt(clipMargin*(clipMargin+2*range.size()))/(range.size()+clipMargin))/M_PI*mKeyAxis->range().size(); // the maximum angle between two points on outer circle (r=clipValue+clipMargin) before connecting line becomes tangent to inner circle (r=clipValue) double skipBegin = 0; bool belowRange = false; bool aboveRange = false; QCPGraphDataContainer::const_iterator it = begin; while (it != end) { if (it->value < lowerClipValue) { if (aboveRange) // jumped directly from above to below visible range, draw previous point so entry angle is correct { aboveRange = false; if (!reversed) // TODO: with inner radius, we'll need else case here with projected border point lineData->append(*(it-1)); } if (!belowRange) { skipBegin = it->key; lineData->append(QCPGraphData(it->key, lowerClipValue)); belowRange = true; } if (it->key-skipBegin > maxKeySkip) // add dummy point if we're exceeding the maximum skippable angle (to prevent unintentional intersections with visible circle) { skipBegin += maxKeySkip; lineData->append(QCPGraphData(skipBegin, lowerClipValue)); } } else if (it->value > upperClipValue) { if (belowRange) // jumped directly from below to above visible range, draw previous point so entry angle is correct (if lower means outer, so if reversed axis) { belowRange = false; if (reversed) lineData->append(*(it-1)); } if (!aboveRange) { skipBegin = it->key; lineData->append(QCPGraphData(it->key, upperClipValue)); aboveRange = true; } if (it->key-skipBegin > maxKeySkip) // add dummy point if we're exceeding the maximum skippable angle (to prevent unintentional intersections with visible circle) { skipBegin += maxKeySkip; lineData->append(QCPGraphData(skipBegin, upperClipValue)); } } else // value within bounds where we don't optimize away points { if (aboveRange) { aboveRange = false; if (!reversed) lineData->append(*(it-1)); // just entered from above, draw previous point so entry angle is correct (if above means outer, so if not reversed axis) } if (belowRange) { belowRange = false; if (reversed) lineData->append(*(it-1)); // just entered from below, draw previous point so entry angle is correct (if below means outer, so if reversed axis) } lineData->append(*it); // inside visible circle, add point normally } ++it; } // to make fill not erratic, add last point normally if it was outside visible circle: if (aboveRange) { aboveRange = false; if (!reversed) lineData->append(*(it-1)); // just entered from above, draw previous point so entry angle is correct (if above means outer, so if not reversed axis) } if (belowRange) { belowRange = false; if (reversed) lineData->append(*(it-1)); // just entered from below, draw previous point so entry angle is correct (if below means outer, so if reversed axis) } } void QCPPolarGraph::getOptimizedScatterData(QVector *scatterData, QCPGraphDataContainer::const_iterator begin, QCPGraphDataContainer::const_iterator end) const { scatterData->clear(); const QCPRange range = mValueAxis->range(); bool reversed = mValueAxis->rangeReversed(); const double clipMargin = range.size()*0.05; const double upperClipValue = range.upper + (reversed ? 0 : clipMargin); // clip slightly outside of actual range to avoid scatter size to peek into visible circle const double lowerClipValue = range.lower - (reversed ? clipMargin : 0); // clip slightly outside of actual range to avoid scatter size to peek into visible circle QCPGraphDataContainer::const_iterator it = begin; while (it != end) { if (it->value > lowerClipValue && it->value < upperClipValue) scatterData->append(*it); ++it; } } /*! \internal Takes raw data points in plot coordinates as \a data, and returns a vector containing pixel coordinate points which are suitable for drawing the line style \ref lsLine. The source of \a data is usually \ref getOptimizedLineData, and this method is called in \a getLines if the line style is set accordingly. \see dataToStepLeftLines, dataToStepRightLines, dataToStepCenterLines, dataToImpulseLines, getLines, drawLinePlot */ QVector QCPPolarGraph::dataToLines(const QVector &data) const { QVector result; QCPPolarAxisAngular *keyAxis = mKeyAxis.data(); QCPPolarAxisRadial *valueAxis = mValueAxis.data(); if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return result; } // transform data points to pixels: result.resize(data.size()); for (int i=0; icoordToPixel(data.at(i).key, data.at(i).value); return result; } /* end of 'src/polar/polargraph.cpp' */ sqlitebrowser-sqlitebrowser-5733cb7/libs/qcustomplot-source/qcustomplot.h000066400000000000000000011333451463772530400272720ustar00rootroot00000000000000/*************************************************************************** ** ** ** QCustomPlot, an easy to use, modern plotting widget for Qt ** ** Copyright (C) 2011-2021 Emanuel Eichhammer ** ** ** ** 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 http://www.gnu.org/licenses/. ** ** ** **************************************************************************** ** Author: Emanuel Eichhammer ** ** Website/Contact: http://www.qcustomplot.com/ ** ** Date: 29.03.21 ** ** Version: 2.1.0 ** ****************************************************************************/ #ifndef QCUSTOMPLOT_H #define QCUSTOMPLOT_H #include // some Qt version/configuration dependent macros to include or exclude certain code paths: #ifdef QCUSTOMPLOT_USE_OPENGL # if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) # define QCP_OPENGL_PBUFFER # else # define QCP_OPENGL_FBO # endif # if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) # define QCP_OPENGL_OFFSCREENSURFACE # endif #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) # define QCP_DEVICEPIXELRATIO_SUPPORTED # if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) # define QCP_DEVICEPIXELRATIO_FLOAT # endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef QCP_OPENGL_FBO # include # if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) # include # else # include # include # endif # ifdef QCP_OPENGL_OFFSCREENSURFACE # include # else # include # endif #endif #ifdef QCP_OPENGL_PBUFFER # include #endif #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) # include # include # include # include #else # include # include # include #endif #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) # include #endif # if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) # include #endif class QCPPainter; class QCustomPlot; class QCPLayerable; class QCPLayoutElement; class QCPLayout; class QCPAxis; class QCPAxisRect; class QCPAxisPainterPrivate; class QCPAbstractPlottable; class QCPGraph; class QCPAbstractItem; class QCPPlottableInterface1D; class QCPLegend; class QCPItemPosition; class QCPLayer; class QCPAbstractLegendItem; class QCPSelectionRect; class QCPColorMap; class QCPColorScale; class QCPBars; class QCPPolarAxisRadial; class QCPPolarAxisAngular; class QCPPolarGrid; class QCPPolarGraph; /* including file 'src/global.h' */ /* modified 2021-03-29T02:30:44, size 16981 */ #define QCUSTOMPLOT_VERSION_STR "2.1.0" #define QCUSTOMPLOT_VERSION 0x020100 // decl definitions for shared library compilation/usage: #if defined(QT_STATIC_BUILD) # define QCP_LIB_DECL #elif defined(QCUSTOMPLOT_COMPILE_LIBRARY) # define QCP_LIB_DECL Q_DECL_EXPORT #elif defined(QCUSTOMPLOT_USE_LIBRARY) # define QCP_LIB_DECL Q_DECL_IMPORT #else # define QCP_LIB_DECL #endif // define empty macro for Q_DECL_OVERRIDE if it doesn't exist (Qt < 5) #ifndef Q_DECL_OVERRIDE # define Q_DECL_OVERRIDE #endif /*! The QCP Namespace contains general enums, QFlags and functions used throughout the QCustomPlot library. It provides QMetaObject-based reflection of its enums and flags via \a QCP::staticMetaObject. */ #ifndef Q_MOC_RUN namespace QCP { #else class QCP { // when in moc-run, make it look like a class, so we get Q_GADGET, Q_ENUMS/Q_FLAGS features in namespace Q_GADGET Q_ENUMS(ExportPen) Q_ENUMS(ResolutionUnit) Q_ENUMS(SignDomain) Q_ENUMS(MarginSide) Q_FLAGS(MarginSides) Q_ENUMS(AntialiasedElement) Q_FLAGS(AntialiasedElements) Q_ENUMS(PlottingHint) Q_FLAGS(PlottingHints) Q_ENUMS(Interaction) Q_FLAGS(Interactions) Q_ENUMS(SelectionRectMode) Q_ENUMS(SelectionType) public: #endif /*! Defines the different units in which the image resolution can be specified in the export functions. \see QCustomPlot::savePng, QCustomPlot::saveJpg, QCustomPlot::saveBmp, QCustomPlot::saveRastered */ enum ResolutionUnit { ruDotsPerMeter ///< Resolution is given in dots per meter (dpm) ,ruDotsPerCentimeter ///< Resolution is given in dots per centimeter (dpcm) ,ruDotsPerInch ///< Resolution is given in dots per inch (DPI/PPI) }; /*! Defines how cosmetic pens (pens with numerical width 0) are handled during export. \see QCustomPlot::savePdf */ enum ExportPen { epNoCosmetic ///< Cosmetic pens are converted to pens with pixel width 1 when exporting ,epAllowCosmetic ///< Cosmetic pens are exported normally (e.g. in PDF exports, cosmetic pens always appear as 1 pixel on screen, independent of viewer zoom level) }; /*! Represents negative and positive sign domain, e.g. for passing to \ref QCPAbstractPlottable::getKeyRange and \ref QCPAbstractPlottable::getValueRange. This is primarily needed when working with logarithmic axis scales, since only one of the sign domains can be visible at a time. */ enum SignDomain { sdNegative ///< The negative sign domain, i.e. numbers smaller than zero ,sdBoth ///< Both sign domains, including zero, i.e. all numbers ,sdPositive ///< The positive sign domain, i.e. numbers greater than zero }; /*! Defines the sides of a rectangular entity to which margins can be applied. \see QCPLayoutElement::setAutoMargins, QCPAxisRect::setAutoMargins */ enum MarginSide { msLeft = 0x01 ///< 0x01 left margin ,msRight = 0x02 ///< 0x02 right margin ,msTop = 0x04 ///< 0x04 top margin ,msBottom = 0x08 ///< 0x08 bottom margin ,msAll = 0xFF ///< 0xFF all margins ,msNone = 0x00 ///< 0x00 no margin }; Q_DECLARE_FLAGS(MarginSides, MarginSide) /*! Defines what objects of a plot can be forcibly drawn antialiased/not antialiased. If an object is neither forcibly drawn antialiased nor forcibly drawn not antialiased, it is up to the respective element how it is drawn. Typically it provides a \a setAntialiased function for this. \c AntialiasedElements is a flag of or-combined elements of this enum type. \see QCustomPlot::setAntialiasedElements, QCustomPlot::setNotAntialiasedElements */ enum AntialiasedElement { aeAxes = 0x0001 ///< 0x0001 Axis base line and tick marks ,aeGrid = 0x0002 ///< 0x0002 Grid lines ,aeSubGrid = 0x0004 ///< 0x0004 Sub grid lines ,aeLegend = 0x0008 ///< 0x0008 Legend box ,aeLegendItems = 0x0010 ///< 0x0010 Legend items ,aePlottables = 0x0020 ///< 0x0020 Main lines of plottables ,aeItems = 0x0040 ///< 0x0040 Main lines of items ,aeScatters = 0x0080 ///< 0x0080 Scatter symbols of plottables (excluding scatter symbols of type ssPixmap) ,aeFills = 0x0100 ///< 0x0100 Borders of fills (e.g. under or between graphs) ,aeZeroLine = 0x0200 ///< 0x0200 Zero-lines, see \ref QCPGrid::setZeroLinePen ,aeOther = 0x8000 ///< 0x8000 Other elements that don't fit into any of the existing categories ,aeAll = 0xFFFF ///< 0xFFFF All elements ,aeNone = 0x0000 ///< 0x0000 No elements }; Q_DECLARE_FLAGS(AntialiasedElements, AntialiasedElement) /*! Defines plotting hints that control various aspects of the quality and speed of plotting. \see QCustomPlot::setPlottingHints */ enum PlottingHint { phNone = 0x000 ///< 0x000 No hints are set ,phFastPolylines = 0x001 ///< 0x001 Graph/Curve lines are drawn with a faster method. This reduces the quality especially of the line segment ///< joins, thus is most effective for pen sizes larger than 1. It is only used for solid line pens. ,phImmediateRefresh = 0x002 ///< 0x002 causes an immediate repaint() instead of a soft update() when QCustomPlot::replot() is called with parameter \ref QCustomPlot::rpRefreshHint. ///< This is set by default to prevent the plot from freezing on fast consecutive replots (e.g. user drags ranges with mouse). ,phCacheLabels = 0x004 ///< 0x004 axis (tick) labels will be cached as pixmaps, increasing replot performance. }; Q_DECLARE_FLAGS(PlottingHints, PlottingHint) /*! Defines the mouse interactions possible with QCustomPlot. \c Interactions is a flag of or-combined elements of this enum type. \see QCustomPlot::setInteractions */ enum Interaction { iNone = 0x000 ///< 0x000 None of the interactions are possible ,iRangeDrag = 0x001 ///< 0x001 Axis ranges are draggable (see \ref QCPAxisRect::setRangeDrag, \ref QCPAxisRect::setRangeDragAxes) ,iRangeZoom = 0x002 ///< 0x002 Axis ranges are zoomable with the mouse wheel (see \ref QCPAxisRect::setRangeZoom, \ref QCPAxisRect::setRangeZoomAxes) ,iMultiSelect = 0x004 ///< 0x004 The user can select multiple objects by holding the modifier set by \ref QCustomPlot::setMultiSelectModifier while clicking ,iSelectPlottables = 0x008 ///< 0x008 Plottables are selectable (e.g. graphs, curves, bars,... see QCPAbstractPlottable) ,iSelectAxes = 0x010 ///< 0x010 Axes are selectable (or parts of them, see QCPAxis::setSelectableParts) ,iSelectLegend = 0x020 ///< 0x020 Legends are selectable (or their child items, see QCPLegend::setSelectableParts) ,iSelectItems = 0x040 ///< 0x040 Items are selectable (Rectangles, Arrows, Textitems, etc. see \ref QCPAbstractItem) ,iSelectOther = 0x080 ///< 0x080 All other objects are selectable (e.g. your own derived layerables, other layout elements,...) ,iSelectPlottablesBeyondAxisRect = 0x100 ///< 0x100 When performing plottable selection/hit tests, this flag extends the sensitive area beyond the axis rect }; Q_DECLARE_FLAGS(Interactions, Interaction) /*! Defines the behaviour of the selection rect. \see QCustomPlot::setSelectionRectMode, QCustomPlot::selectionRect, QCPSelectionRect */ enum SelectionRectMode { srmNone ///< The selection rect is disabled, and all mouse events are forwarded to the underlying objects, e.g. for axis range dragging ,srmZoom ///< When dragging the mouse, a selection rect becomes active. Upon releasing, the axes that are currently set as range zoom axes (\ref QCPAxisRect::setRangeZoomAxes) will have their ranges zoomed accordingly. ,srmSelect ///< When dragging the mouse, a selection rect becomes active. Upon releasing, plottable data points that were within the selection rect are selected, if the plottable's selectability setting permits. (See \ref dataselection "data selection mechanism" for details.) ,srmCustom ///< When dragging the mouse, a selection rect becomes active. It is the programmer's responsibility to connect according slots to the selection rect's signals (e.g. \ref QCPSelectionRect::accepted) in order to process the user interaction. }; /*! Defines the different ways a plottable can be selected. These images show the effect of the different selection types, when the indicated selection rect was dragged:
\image html selectiontype-none.png stNone \image html selectiontype-whole.png stWhole \image html selectiontype-singledata.png stSingleData \image html selectiontype-datarange.png stDataRange \image html selectiontype-multipledataranges.png stMultipleDataRanges
\see QCPAbstractPlottable::setSelectable, QCPDataSelection::enforceType */ enum SelectionType { stNone ///< The plottable is not selectable ,stWhole ///< Selection behaves like \ref stMultipleDataRanges, but if there are any data points selected, the entire plottable is drawn as selected. ,stSingleData ///< One individual data point can be selected at a time ,stDataRange ///< Multiple contiguous data points (a data range) can be selected ,stMultipleDataRanges ///< Any combination of data points/ranges can be selected }; /*! \internal Returns whether the specified \a value is considered an invalid data value for plottables (i.e. is \e nan or \e +/-inf). This function is used to check data validity upon replots, when the compiler flag \c QCUSTOMPLOT_CHECK_DATA is set. */ inline bool isInvalidData(double value) { return qIsNaN(value) || qIsInf(value); } /*! \internal \overload Checks two arguments instead of one. */ inline bool isInvalidData(double value1, double value2) { return isInvalidData(value1) || isInvalidData(value2); } /*! \internal Sets the specified \a side of \a margins to \a value \see getMarginValue */ inline void setMarginValue(QMargins &margins, QCP::MarginSide side, int value) { switch (side) { case QCP::msLeft: margins.setLeft(value); break; case QCP::msRight: margins.setRight(value); break; case QCP::msTop: margins.setTop(value); break; case QCP::msBottom: margins.setBottom(value); break; case QCP::msAll: margins = QMargins(value, value, value, value); break; default: break; } } /*! \internal Returns the value of the specified \a side of \a margins. If \a side is \ref QCP::msNone or \ref QCP::msAll, returns 0. \see setMarginValue */ inline int getMarginValue(const QMargins &margins, QCP::MarginSide side) { switch (side) { case QCP::msLeft: return margins.left(); case QCP::msRight: return margins.right(); case QCP::msTop: return margins.top(); case QCP::msBottom: return margins.bottom(); default: break; } return 0; } extern const QMetaObject staticMetaObject; // in moc-run we create a static meta object for QCP "fake" object. This line is the link to it via QCP::staticMetaObject in normal operation as namespace } // end of namespace QCP Q_DECLARE_OPERATORS_FOR_FLAGS(QCP::AntialiasedElements) Q_DECLARE_OPERATORS_FOR_FLAGS(QCP::PlottingHints) Q_DECLARE_OPERATORS_FOR_FLAGS(QCP::MarginSides) Q_DECLARE_OPERATORS_FOR_FLAGS(QCP::Interactions) Q_DECLARE_METATYPE(QCP::ExportPen) Q_DECLARE_METATYPE(QCP::ResolutionUnit) Q_DECLARE_METATYPE(QCP::SignDomain) Q_DECLARE_METATYPE(QCP::MarginSide) Q_DECLARE_METATYPE(QCP::AntialiasedElement) Q_DECLARE_METATYPE(QCP::PlottingHint) Q_DECLARE_METATYPE(QCP::Interaction) Q_DECLARE_METATYPE(QCP::SelectionRectMode) Q_DECLARE_METATYPE(QCP::SelectionType) /* end of 'src/global.h' */ /* including file 'src/vector2d.h' */ /* modified 2021-03-29T02:30:44, size 4988 */ class QCP_LIB_DECL QCPVector2D { public: QCPVector2D(); QCPVector2D(double x, double y); QCPVector2D(const QPoint &point); QCPVector2D(const QPointF &point); // getters: double x() const { return mX; } double y() const { return mY; } double &rx() { return mX; } double &ry() { return mY; } // setters: void setX(double x) { mX = x; } void setY(double y) { mY = y; } // non-virtual methods: double length() const { return qSqrt(mX*mX+mY*mY); } double lengthSquared() const { return mX*mX+mY*mY; } double angle() const { return qAtan2(mY, mX); } QPoint toPoint() const { return QPoint(int(mX), int(mY)); } QPointF toPointF() const { return QPointF(mX, mY); } bool isNull() const { return qIsNull(mX) && qIsNull(mY); } void normalize(); QCPVector2D normalized() const; QCPVector2D perpendicular() const { return QCPVector2D(-mY, mX); } double dot(const QCPVector2D &vec) const { return mX*vec.mX+mY*vec.mY; } double distanceSquaredToLine(const QCPVector2D &start, const QCPVector2D &end) const; double distanceSquaredToLine(const QLineF &line) const; double distanceToStraightLine(const QCPVector2D &base, const QCPVector2D &direction) const; QCPVector2D &operator*=(double factor); QCPVector2D &operator/=(double divisor); QCPVector2D &operator+=(const QCPVector2D &vector); QCPVector2D &operator-=(const QCPVector2D &vector); private: // property members: double mX, mY; friend inline const QCPVector2D operator*(double factor, const QCPVector2D &vec); friend inline const QCPVector2D operator*(const QCPVector2D &vec, double factor); friend inline const QCPVector2D operator/(const QCPVector2D &vec, double divisor); friend inline const QCPVector2D operator+(const QCPVector2D &vec1, const QCPVector2D &vec2); friend inline const QCPVector2D operator-(const QCPVector2D &vec1, const QCPVector2D &vec2); friend inline const QCPVector2D operator-(const QCPVector2D &vec); }; Q_DECLARE_TYPEINFO(QCPVector2D, Q_MOVABLE_TYPE); inline const QCPVector2D operator*(double factor, const QCPVector2D &vec) { return QCPVector2D(vec.mX*factor, vec.mY*factor); } inline const QCPVector2D operator*(const QCPVector2D &vec, double factor) { return QCPVector2D(vec.mX*factor, vec.mY*factor); } inline const QCPVector2D operator/(const QCPVector2D &vec, double divisor) { return QCPVector2D(vec.mX/divisor, vec.mY/divisor); } inline const QCPVector2D operator+(const QCPVector2D &vec1, const QCPVector2D &vec2) { return QCPVector2D(vec1.mX+vec2.mX, vec1.mY+vec2.mY); } inline const QCPVector2D operator-(const QCPVector2D &vec1, const QCPVector2D &vec2) { return QCPVector2D(vec1.mX-vec2.mX, vec1.mY-vec2.mY); } inline const QCPVector2D operator-(const QCPVector2D &vec) { return QCPVector2D(-vec.mX, -vec.mY); } /*! \relates QCPVector2D Prints \a vec in a human readable format to the qDebug output. */ inline QDebug operator<< (QDebug d, const QCPVector2D &vec) { d.nospace() << "QCPVector2D(" << vec.x() << ", " << vec.y() << ")"; return d.space(); } /* end of 'src/vector2d.h' */ /* including file 'src/painter.h' */ /* modified 2021-03-29T02:30:44, size 4035 */ class QCP_LIB_DECL QCPPainter : public QPainter { Q_GADGET public: /*! Defines special modes the painter can operate in. They disable or enable certain subsets of features/fixes/workarounds, depending on whether they are wanted on the respective output device. */ enum PainterMode { pmDefault = 0x00 ///< 0x00 Default mode for painting on screen devices ,pmVectorized = 0x01 ///< 0x01 Mode for vectorized painting (e.g. PDF export). For example, this prevents some antialiasing fixes. ,pmNoCaching = 0x02 ///< 0x02 Mode for all sorts of exports (e.g. PNG, PDF,...). For example, this prevents using cached pixmap labels ,pmNonCosmetic = 0x04 ///< 0x04 Turns pen widths 0 to 1, i.e. disables cosmetic pens. (A cosmetic pen is always drawn with width 1 pixel in the vector image/pdf viewer, independent of zoom.) }; Q_ENUMS(PainterMode) Q_FLAGS(PainterModes) Q_DECLARE_FLAGS(PainterModes, PainterMode) QCPPainter(); explicit QCPPainter(QPaintDevice *device); // getters: bool antialiasing() const { return testRenderHint(QPainter::Antialiasing); } PainterModes modes() const { return mModes; } // setters: void setAntialiasing(bool enabled); void setMode(PainterMode mode, bool enabled=true); void setModes(PainterModes modes); // methods hiding non-virtual base class functions (QPainter bug workarounds): bool begin(QPaintDevice *device); void setPen(const QPen &pen); void setPen(const QColor &color); void setPen(Qt::PenStyle penStyle); void drawLine(const QLineF &line); void drawLine(const QPointF &p1, const QPointF &p2) {drawLine(QLineF(p1, p2));} void save(); void restore(); // non-virtual methods: void makeNonCosmetic(); protected: // property members: PainterModes mModes; bool mIsAntialiasing; // non-property members: QStack mAntialiasingStack; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCPPainter::PainterModes) Q_DECLARE_METATYPE(QCPPainter::PainterMode) /* end of 'src/painter.h' */ /* including file 'src/paintbuffer.h' */ /* modified 2021-03-29T02:30:44, size 5006 */ class QCP_LIB_DECL QCPAbstractPaintBuffer { public: explicit QCPAbstractPaintBuffer(const QSize &size, double devicePixelRatio); virtual ~QCPAbstractPaintBuffer(); // getters: QSize size() const { return mSize; } bool invalidated() const { return mInvalidated; } double devicePixelRatio() const { return mDevicePixelRatio; } // setters: void setSize(const QSize &size); void setInvalidated(bool invalidated=true); void setDevicePixelRatio(double ratio); // introduced virtual methods: virtual QCPPainter *startPainting() = 0; virtual void donePainting() {} virtual void draw(QCPPainter *painter) const = 0; virtual void clear(const QColor &color) = 0; protected: // property members: QSize mSize; double mDevicePixelRatio; // non-property members: bool mInvalidated; // introduced virtual methods: virtual void reallocateBuffer() = 0; }; class QCP_LIB_DECL QCPPaintBufferPixmap : public QCPAbstractPaintBuffer { public: explicit QCPPaintBufferPixmap(const QSize &size, double devicePixelRatio); virtual ~QCPPaintBufferPixmap() Q_DECL_OVERRIDE; // reimplemented virtual methods: virtual QCPPainter *startPainting() Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) const Q_DECL_OVERRIDE; void clear(const QColor &color) Q_DECL_OVERRIDE; protected: // non-property members: QPixmap mBuffer; // reimplemented virtual methods: virtual void reallocateBuffer() Q_DECL_OVERRIDE; }; #ifdef QCP_OPENGL_PBUFFER class QCP_LIB_DECL QCPPaintBufferGlPbuffer : public QCPAbstractPaintBuffer { public: explicit QCPPaintBufferGlPbuffer(const QSize &size, double devicePixelRatio, int multisamples); virtual ~QCPPaintBufferGlPbuffer() Q_DECL_OVERRIDE; // reimplemented virtual methods: virtual QCPPainter *startPainting() Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) const Q_DECL_OVERRIDE; void clear(const QColor &color) Q_DECL_OVERRIDE; protected: // non-property members: QGLPixelBuffer *mGlPBuffer; int mMultisamples; // reimplemented virtual methods: virtual void reallocateBuffer() Q_DECL_OVERRIDE; }; #endif // QCP_OPENGL_PBUFFER #ifdef QCP_OPENGL_FBO class QCP_LIB_DECL QCPPaintBufferGlFbo : public QCPAbstractPaintBuffer { public: explicit QCPPaintBufferGlFbo(const QSize &size, double devicePixelRatio, QWeakPointer glContext, QWeakPointer glPaintDevice); virtual ~QCPPaintBufferGlFbo() Q_DECL_OVERRIDE; // reimplemented virtual methods: virtual QCPPainter *startPainting() Q_DECL_OVERRIDE; virtual void donePainting() Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) const Q_DECL_OVERRIDE; void clear(const QColor &color) Q_DECL_OVERRIDE; protected: // non-property members: QWeakPointer mGlContext; QWeakPointer mGlPaintDevice; QOpenGLFramebufferObject *mGlFrameBuffer; // reimplemented virtual methods: virtual void reallocateBuffer() Q_DECL_OVERRIDE; }; #endif // QCP_OPENGL_FBO /* end of 'src/paintbuffer.h' */ /* including file 'src/layer.h' */ /* modified 2021-03-29T02:30:44, size 7038 */ class QCP_LIB_DECL QCPLayer : public QObject { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QCustomPlot* parentPlot READ parentPlot) Q_PROPERTY(QString name READ name) Q_PROPERTY(int index READ index) Q_PROPERTY(QList children READ children) Q_PROPERTY(bool visible READ visible WRITE setVisible) Q_PROPERTY(LayerMode mode READ mode WRITE setMode) /// \endcond public: /*! Defines the different rendering modes of a layer. Depending on the mode, certain layers can be replotted individually, without the need to replot (possibly complex) layerables on other layers. \see setMode */ enum LayerMode { lmLogical ///< Layer is used only for rendering order, and shares paint buffer with all other adjacent logical layers. ,lmBuffered ///< Layer has its own paint buffer and may be replotted individually (see \ref replot). }; Q_ENUMS(LayerMode) QCPLayer(QCustomPlot* parentPlot, const QString &layerName); virtual ~QCPLayer(); // getters: QCustomPlot *parentPlot() const { return mParentPlot; } QString name() const { return mName; } int index() const { return mIndex; } QList children() const { return mChildren; } bool visible() const { return mVisible; } LayerMode mode() const { return mMode; } // setters: void setVisible(bool visible); void setMode(LayerMode mode); // non-virtual methods: void replot(); protected: // property members: QCustomPlot *mParentPlot; QString mName; int mIndex; QList mChildren; bool mVisible; LayerMode mMode; // non-property members: QWeakPointer mPaintBuffer; // non-virtual methods: void draw(QCPPainter *painter); void drawToPaintBuffer(); void addChild(QCPLayerable *layerable, bool prepend); void removeChild(QCPLayerable *layerable); private: Q_DISABLE_COPY(QCPLayer) friend class QCustomPlot; friend class QCPLayerable; }; Q_DECLARE_METATYPE(QCPLayer::LayerMode) class QCP_LIB_DECL QCPLayerable : public QObject { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(bool visible READ visible WRITE setVisible) Q_PROPERTY(QCustomPlot* parentPlot READ parentPlot) Q_PROPERTY(QCPLayerable* parentLayerable READ parentLayerable) Q_PROPERTY(QCPLayer* layer READ layer WRITE setLayer NOTIFY layerChanged) Q_PROPERTY(bool antialiased READ antialiased WRITE setAntialiased) /// \endcond public: QCPLayerable(QCustomPlot *plot, QString targetLayer=QString(), QCPLayerable *parentLayerable=nullptr); virtual ~QCPLayerable(); // getters: bool visible() const { return mVisible; } QCustomPlot *parentPlot() const { return mParentPlot; } QCPLayerable *parentLayerable() const { return mParentLayerable.data(); } QCPLayer *layer() const { return mLayer; } bool antialiased() const { return mAntialiased; } // setters: void setVisible(bool on); Q_SLOT bool setLayer(QCPLayer *layer); bool setLayer(const QString &layerName); void setAntialiased(bool enabled); // introduced virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const; // non-property methods: bool realVisibility() const; signals: void layerChanged(QCPLayer *newLayer); protected: // property members: bool mVisible; QCustomPlot *mParentPlot; QPointer mParentLayerable; QCPLayer *mLayer; bool mAntialiased; // introduced virtual methods: virtual void parentPlotInitialized(QCustomPlot *parentPlot); virtual QCP::Interaction selectionCategory() const; virtual QRect clipRect() const; virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const = 0; virtual void draw(QCPPainter *painter) = 0; // selection events: virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged); virtual void deselectEvent(bool *selectionStateChanged); // low-level mouse events: virtual void mousePressEvent(QMouseEvent *event, const QVariant &details); virtual void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos); virtual void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos); virtual void mouseDoubleClickEvent(QMouseEvent *event, const QVariant &details); virtual void wheelEvent(QWheelEvent *event); // non-property methods: void initializeParentPlot(QCustomPlot *parentPlot); void setParentLayerable(QCPLayerable* parentLayerable); bool moveToLayer(QCPLayer *layer, bool prepend); void applyAntialiasingHint(QCPPainter *painter, bool localAntialiased, QCP::AntialiasedElement overrideElement) const; private: Q_DISABLE_COPY(QCPLayerable) friend class QCustomPlot; friend class QCPLayer; friend class QCPAxisRect; }; /* end of 'src/layer.h' */ /* including file 'src/axis/range.h' */ /* modified 2021-03-29T02:30:44, size 5280 */ class QCP_LIB_DECL QCPRange { public: double lower, upper; QCPRange(); QCPRange(double lower, double upper); bool operator==(const QCPRange& other) const { return lower == other.lower && upper == other.upper; } bool operator!=(const QCPRange& other) const { return !(*this == other); } QCPRange &operator+=(const double& value) { lower+=value; upper+=value; return *this; } QCPRange &operator-=(const double& value) { lower-=value; upper-=value; return *this; } QCPRange &operator*=(const double& value) { lower*=value; upper*=value; return *this; } QCPRange &operator/=(const double& value) { lower/=value; upper/=value; return *this; } friend inline const QCPRange operator+(const QCPRange&, double); friend inline const QCPRange operator+(double, const QCPRange&); friend inline const QCPRange operator-(const QCPRange& range, double value); friend inline const QCPRange operator*(const QCPRange& range, double value); friend inline const QCPRange operator*(double value, const QCPRange& range); friend inline const QCPRange operator/(const QCPRange& range, double value); double size() const { return upper-lower; } double center() const { return (upper+lower)*0.5; } void normalize() { if (lower > upper) qSwap(lower, upper); } void expand(const QCPRange &otherRange); void expand(double includeCoord); QCPRange expanded(const QCPRange &otherRange) const; QCPRange expanded(double includeCoord) const; QCPRange bounded(double lowerBound, double upperBound) const; QCPRange sanitizedForLogScale() const; QCPRange sanitizedForLinScale() const; bool contains(double value) const { return value >= lower && value <= upper; } static bool validRange(double lower, double upper); static bool validRange(const QCPRange &range); static const double minRange; static const double maxRange; }; Q_DECLARE_TYPEINFO(QCPRange, Q_MOVABLE_TYPE); /*! \relates QCPRange Prints \a range in a human readable format to the qDebug output. */ inline QDebug operator<< (QDebug d, const QCPRange &range) { d.nospace() << "QCPRange(" << range.lower << ", " << range.upper << ")"; return d.space(); } /*! Adds \a value to both boundaries of the range. */ inline const QCPRange operator+(const QCPRange& range, double value) { QCPRange result(range); result += value; return result; } /*! Adds \a value to both boundaries of the range. */ inline const QCPRange operator+(double value, const QCPRange& range) { QCPRange result(range); result += value; return result; } /*! Subtracts \a value from both boundaries of the range. */ inline const QCPRange operator-(const QCPRange& range, double value) { QCPRange result(range); result -= value; return result; } /*! Multiplies both boundaries of the range by \a value. */ inline const QCPRange operator*(const QCPRange& range, double value) { QCPRange result(range); result *= value; return result; } /*! Multiplies both boundaries of the range by \a value. */ inline const QCPRange operator*(double value, const QCPRange& range) { QCPRange result(range); result *= value; return result; } /*! Divides both boundaries of the range by \a value. */ inline const QCPRange operator/(const QCPRange& range, double value) { QCPRange result(range); result /= value; return result; } /* end of 'src/axis/range.h' */ /* including file 'src/selection.h' */ /* modified 2021-03-29T02:30:44, size 8569 */ class QCP_LIB_DECL QCPDataRange { public: QCPDataRange(); QCPDataRange(int begin, int end); bool operator==(const QCPDataRange& other) const { return mBegin == other.mBegin && mEnd == other.mEnd; } bool operator!=(const QCPDataRange& other) const { return !(*this == other); } // getters: int begin() const { return mBegin; } int end() const { return mEnd; } int size() const { return mEnd-mBegin; } int length() const { return size(); } // setters: void setBegin(int begin) { mBegin = begin; } void setEnd(int end) { mEnd = end; } // non-property methods: bool isValid() const { return (mEnd >= mBegin) && (mBegin >= 0); } bool isEmpty() const { return length() == 0; } QCPDataRange bounded(const QCPDataRange &other) const; QCPDataRange expanded(const QCPDataRange &other) const; QCPDataRange intersection(const QCPDataRange &other) const; QCPDataRange adjusted(int changeBegin, int changeEnd) const { return QCPDataRange(mBegin+changeBegin, mEnd+changeEnd); } bool intersects(const QCPDataRange &other) const; bool contains(const QCPDataRange &other) const; private: // property members: int mBegin, mEnd; }; Q_DECLARE_TYPEINFO(QCPDataRange, Q_MOVABLE_TYPE); class QCP_LIB_DECL QCPDataSelection { public: explicit QCPDataSelection(); explicit QCPDataSelection(const QCPDataRange &range); bool operator==(const QCPDataSelection& other) const; bool operator!=(const QCPDataSelection& other) const { return !(*this == other); } QCPDataSelection &operator+=(const QCPDataSelection& other); QCPDataSelection &operator+=(const QCPDataRange& other); QCPDataSelection &operator-=(const QCPDataSelection& other); QCPDataSelection &operator-=(const QCPDataRange& other); friend inline const QCPDataSelection operator+(const QCPDataSelection& a, const QCPDataSelection& b); friend inline const QCPDataSelection operator+(const QCPDataRange& a, const QCPDataSelection& b); friend inline const QCPDataSelection operator+(const QCPDataSelection& a, const QCPDataRange& b); friend inline const QCPDataSelection operator+(const QCPDataRange& a, const QCPDataRange& b); friend inline const QCPDataSelection operator-(const QCPDataSelection& a, const QCPDataSelection& b); friend inline const QCPDataSelection operator-(const QCPDataRange& a, const QCPDataSelection& b); friend inline const QCPDataSelection operator-(const QCPDataSelection& a, const QCPDataRange& b); friend inline const QCPDataSelection operator-(const QCPDataRange& a, const QCPDataRange& b); // getters: int dataRangeCount() const { return mDataRanges.size(); } int dataPointCount() const; QCPDataRange dataRange(int index=0) const; QList dataRanges() const { return mDataRanges; } QCPDataRange span() const; // non-property methods: void addDataRange(const QCPDataRange &dataRange, bool simplify=true); void clear(); bool isEmpty() const { return mDataRanges.isEmpty(); } void simplify(); void enforceType(QCP::SelectionType type); bool contains(const QCPDataSelection &other) const; QCPDataSelection intersection(const QCPDataRange &other) const; QCPDataSelection intersection(const QCPDataSelection &other) const; QCPDataSelection inverse(const QCPDataRange &outerRange) const; private: // property members: QList mDataRanges; inline static bool lessThanDataRangeBegin(const QCPDataRange &a, const QCPDataRange &b) { return a.begin() < b.begin(); } }; Q_DECLARE_METATYPE(QCPDataSelection) /*! Return a \ref QCPDataSelection with the data points in \a a joined with the data points in \a b. The resulting data selection is already simplified (see \ref QCPDataSelection::simplify). */ inline const QCPDataSelection operator+(const QCPDataSelection& a, const QCPDataSelection& b) { QCPDataSelection result(a); result += b; return result; } /*! Return a \ref QCPDataSelection with the data points in \a a joined with the data points in \a b. The resulting data selection is already simplified (see \ref QCPDataSelection::simplify). */ inline const QCPDataSelection operator+(const QCPDataRange& a, const QCPDataSelection& b) { QCPDataSelection result(a); result += b; return result; } /*! Return a \ref QCPDataSelection with the data points in \a a joined with the data points in \a b. The resulting data selection is already simplified (see \ref QCPDataSelection::simplify). */ inline const QCPDataSelection operator+(const QCPDataSelection& a, const QCPDataRange& b) { QCPDataSelection result(a); result += b; return result; } /*! Return a \ref QCPDataSelection with the data points in \a a joined with the data points in \a b. The resulting data selection is already simplified (see \ref QCPDataSelection::simplify). */ inline const QCPDataSelection operator+(const QCPDataRange& a, const QCPDataRange& b) { QCPDataSelection result(a); result += b; return result; } /*! Return a \ref QCPDataSelection with the data points which are in \a a but not in \a b. */ inline const QCPDataSelection operator-(const QCPDataSelection& a, const QCPDataSelection& b) { QCPDataSelection result(a); result -= b; return result; } /*! Return a \ref QCPDataSelection with the data points which are in \a a but not in \a b. */ inline const QCPDataSelection operator-(const QCPDataRange& a, const QCPDataSelection& b) { QCPDataSelection result(a); result -= b; return result; } /*! Return a \ref QCPDataSelection with the data points which are in \a a but not in \a b. */ inline const QCPDataSelection operator-(const QCPDataSelection& a, const QCPDataRange& b) { QCPDataSelection result(a); result -= b; return result; } /*! Return a \ref QCPDataSelection with the data points which are in \a a but not in \a b. */ inline const QCPDataSelection operator-(const QCPDataRange& a, const QCPDataRange& b) { QCPDataSelection result(a); result -= b; return result; } /*! \relates QCPDataRange Prints \a dataRange in a human readable format to the qDebug output. */ inline QDebug operator<< (QDebug d, const QCPDataRange &dataRange) { d.nospace() << "QCPDataRange(" << dataRange.begin() << ", " << dataRange.end() << ")"; return d; } /*! \relates QCPDataSelection Prints \a selection in a human readable format to the qDebug output. */ inline QDebug operator<< (QDebug d, const QCPDataSelection &selection) { d.nospace() << "QCPDataSelection("; for (int i=0; i elements(QCP::MarginSide side) const { return mChildren.value(side); } bool isEmpty() const; void clear(); protected: // non-property members: QCustomPlot *mParentPlot; QHash > mChildren; // introduced virtual methods: virtual int commonMargin(QCP::MarginSide side) const; // non-virtual methods: void addChild(QCP::MarginSide side, QCPLayoutElement *element); void removeChild(QCP::MarginSide side, QCPLayoutElement *element); private: Q_DISABLE_COPY(QCPMarginGroup) friend class QCPLayoutElement; }; class QCP_LIB_DECL QCPLayoutElement : public QCPLayerable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QCPLayout* layout READ layout) Q_PROPERTY(QRect rect READ rect) Q_PROPERTY(QRect outerRect READ outerRect WRITE setOuterRect) Q_PROPERTY(QMargins margins READ margins WRITE setMargins) Q_PROPERTY(QMargins minimumMargins READ minimumMargins WRITE setMinimumMargins) Q_PROPERTY(QSize minimumSize READ minimumSize WRITE setMinimumSize) Q_PROPERTY(QSize maximumSize READ maximumSize WRITE setMaximumSize) Q_PROPERTY(SizeConstraintRect sizeConstraintRect READ sizeConstraintRect WRITE setSizeConstraintRect) /// \endcond public: /*! Defines the phases of the update process, that happens just before a replot. At each phase, \ref update is called with the according UpdatePhase value. */ enum UpdatePhase { upPreparation ///< Phase used for any type of preparation that needs to be done before margin calculation and layout ,upMargins ///< Phase in which the margins are calculated and set ,upLayout ///< Final phase in which the layout system places the rects of the elements }; Q_ENUMS(UpdatePhase) /*! Defines to which rect of a layout element the size constraints that can be set via \ref setMinimumSize and \ref setMaximumSize apply. The outer rect (\ref outerRect) includes the margins (e.g. in the case of a QCPAxisRect the axis labels), whereas the inner rect (\ref rect) does not. \see setSizeConstraintRect */ enum SizeConstraintRect { scrInnerRect ///< Minimum/Maximum size constraints apply to inner rect , scrOuterRect ///< Minimum/Maximum size constraints apply to outer rect, thus include layout element margins }; Q_ENUMS(SizeConstraintRect) explicit QCPLayoutElement(QCustomPlot *parentPlot=nullptr); virtual ~QCPLayoutElement() Q_DECL_OVERRIDE; // getters: QCPLayout *layout() const { return mParentLayout; } QRect rect() const { return mRect; } QRect outerRect() const { return mOuterRect; } QMargins margins() const { return mMargins; } QMargins minimumMargins() const { return mMinimumMargins; } QCP::MarginSides autoMargins() const { return mAutoMargins; } QSize minimumSize() const { return mMinimumSize; } QSize maximumSize() const { return mMaximumSize; } SizeConstraintRect sizeConstraintRect() const { return mSizeConstraintRect; } QCPMarginGroup *marginGroup(QCP::MarginSide side) const { return mMarginGroups.value(side, nullptr); } QHash marginGroups() const { return mMarginGroups; } // setters: void setOuterRect(const QRect &rect); void setMargins(const QMargins &margins); void setMinimumMargins(const QMargins &margins); void setAutoMargins(QCP::MarginSides sides); void setMinimumSize(const QSize &size); void setMinimumSize(int width, int height); void setMaximumSize(const QSize &size); void setMaximumSize(int width, int height); void setSizeConstraintRect(SizeConstraintRect constraintRect); void setMarginGroup(QCP::MarginSides sides, QCPMarginGroup *group); // introduced virtual methods: virtual void update(UpdatePhase phase); virtual QSize minimumOuterSizeHint() const; virtual QSize maximumOuterSizeHint() const; virtual QList elements(bool recursive) const; // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; protected: // property members: QCPLayout *mParentLayout; QSize mMinimumSize, mMaximumSize; SizeConstraintRect mSizeConstraintRect; QRect mRect, mOuterRect; QMargins mMargins, mMinimumMargins; QCP::MarginSides mAutoMargins; QHash mMarginGroups; // introduced virtual methods: virtual int calculateAutoMargin(QCP::MarginSide side); virtual void layoutChanged(); // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE { Q_UNUSED(painter) } virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE { Q_UNUSED(painter) } virtual void parentPlotInitialized(QCustomPlot *parentPlot) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QCPLayoutElement) friend class QCustomPlot; friend class QCPLayout; friend class QCPMarginGroup; }; Q_DECLARE_METATYPE(QCPLayoutElement::UpdatePhase) class QCP_LIB_DECL QCPLayout : public QCPLayoutElement { Q_OBJECT public: explicit QCPLayout(); // reimplemented virtual methods: virtual void update(UpdatePhase phase) Q_DECL_OVERRIDE; virtual QList elements(bool recursive) const Q_DECL_OVERRIDE; // introduced virtual methods: virtual int elementCount() const = 0; virtual QCPLayoutElement* elementAt(int index) const = 0; virtual QCPLayoutElement* takeAt(int index) = 0; virtual bool take(QCPLayoutElement* element) = 0; virtual void simplify(); // non-virtual methods: bool removeAt(int index); bool remove(QCPLayoutElement* element); void clear(); protected: // introduced virtual methods: virtual void updateLayout(); // non-virtual methods: void sizeConstraintsChanged() const; void adoptElement(QCPLayoutElement *el); void releaseElement(QCPLayoutElement *el); QVector getSectionSizes(QVector maxSizes, QVector minSizes, QVector stretchFactors, int totalSize) const; static QSize getFinalMinimumOuterSize(const QCPLayoutElement *el); static QSize getFinalMaximumOuterSize(const QCPLayoutElement *el); private: Q_DISABLE_COPY(QCPLayout) friend class QCPLayoutElement; }; class QCP_LIB_DECL QCPLayoutGrid : public QCPLayout { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(int rowCount READ rowCount) Q_PROPERTY(int columnCount READ columnCount) Q_PROPERTY(QList columnStretchFactors READ columnStretchFactors WRITE setColumnStretchFactors) Q_PROPERTY(QList rowStretchFactors READ rowStretchFactors WRITE setRowStretchFactors) Q_PROPERTY(int columnSpacing READ columnSpacing WRITE setColumnSpacing) Q_PROPERTY(int rowSpacing READ rowSpacing WRITE setRowSpacing) Q_PROPERTY(FillOrder fillOrder READ fillOrder WRITE setFillOrder) Q_PROPERTY(int wrap READ wrap WRITE setWrap) /// \endcond public: /*! Defines in which direction the grid is filled when using \ref addElement(QCPLayoutElement*). The column/row at which wrapping into the next row/column occurs can be specified with \ref setWrap. \see setFillOrder */ enum FillOrder { foRowsFirst ///< Rows are filled first, and a new element is wrapped to the next column if the row count would exceed \ref setWrap. ,foColumnsFirst ///< Columns are filled first, and a new element is wrapped to the next row if the column count would exceed \ref setWrap. }; Q_ENUMS(FillOrder) explicit QCPLayoutGrid(); virtual ~QCPLayoutGrid() Q_DECL_OVERRIDE; // getters: int rowCount() const { return mElements.size(); } int columnCount() const { return mElements.size() > 0 ? mElements.first().size() : 0; } QList columnStretchFactors() const { return mColumnStretchFactors; } QList rowStretchFactors() const { return mRowStretchFactors; } int columnSpacing() const { return mColumnSpacing; } int rowSpacing() const { return mRowSpacing; } int wrap() const { return mWrap; } FillOrder fillOrder() const { return mFillOrder; } // setters: void setColumnStretchFactor(int column, double factor); void setColumnStretchFactors(const QList &factors); void setRowStretchFactor(int row, double factor); void setRowStretchFactors(const QList &factors); void setColumnSpacing(int pixels); void setRowSpacing(int pixels); void setWrap(int count); void setFillOrder(FillOrder order, bool rearrange=true); // reimplemented virtual methods: virtual void updateLayout() Q_DECL_OVERRIDE; virtual int elementCount() const Q_DECL_OVERRIDE { return rowCount()*columnCount(); } virtual QCPLayoutElement* elementAt(int index) const Q_DECL_OVERRIDE; virtual QCPLayoutElement* takeAt(int index) Q_DECL_OVERRIDE; virtual bool take(QCPLayoutElement* element) Q_DECL_OVERRIDE; virtual QList elements(bool recursive) const Q_DECL_OVERRIDE; virtual void simplify() Q_DECL_OVERRIDE; virtual QSize minimumOuterSizeHint() const Q_DECL_OVERRIDE; virtual QSize maximumOuterSizeHint() const Q_DECL_OVERRIDE; // non-virtual methods: QCPLayoutElement *element(int row, int column) const; bool addElement(int row, int column, QCPLayoutElement *element); bool addElement(QCPLayoutElement *element); bool hasElement(int row, int column); void expandTo(int newRowCount, int newColumnCount); void insertRow(int newIndex); void insertColumn(int newIndex); int rowColToIndex(int row, int column) const; void indexToRowCol(int index, int &row, int &column) const; protected: // property members: QList > mElements; QList mColumnStretchFactors; QList mRowStretchFactors; int mColumnSpacing, mRowSpacing; int mWrap; FillOrder mFillOrder; // non-virtual methods: void getMinimumRowColSizes(QVector *minColWidths, QVector *minRowHeights) const; void getMaximumRowColSizes(QVector *maxColWidths, QVector *maxRowHeights) const; private: Q_DISABLE_COPY(QCPLayoutGrid) }; Q_DECLARE_METATYPE(QCPLayoutGrid::FillOrder) class QCP_LIB_DECL QCPLayoutInset : public QCPLayout { Q_OBJECT public: /*! Defines how the placement and sizing is handled for a certain element in a QCPLayoutInset. */ enum InsetPlacement { ipFree ///< The element may be positioned/sized arbitrarily, see \ref setInsetRect ,ipBorderAligned ///< The element is aligned to one of the layout sides, see \ref setInsetAlignment }; Q_ENUMS(InsetPlacement) explicit QCPLayoutInset(); virtual ~QCPLayoutInset() Q_DECL_OVERRIDE; // getters: InsetPlacement insetPlacement(int index) const; Qt::Alignment insetAlignment(int index) const; QRectF insetRect(int index) const; // setters: void setInsetPlacement(int index, InsetPlacement placement); void setInsetAlignment(int index, Qt::Alignment alignment); void setInsetRect(int index, const QRectF &rect); // reimplemented virtual methods: virtual void updateLayout() Q_DECL_OVERRIDE; virtual int elementCount() const Q_DECL_OVERRIDE; virtual QCPLayoutElement* elementAt(int index) const Q_DECL_OVERRIDE; virtual QCPLayoutElement* takeAt(int index) Q_DECL_OVERRIDE; virtual bool take(QCPLayoutElement* element) Q_DECL_OVERRIDE; virtual void simplify() Q_DECL_OVERRIDE {} virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; // non-virtual methods: void addElement(QCPLayoutElement *element, Qt::Alignment alignment); void addElement(QCPLayoutElement *element, const QRectF &rect); protected: // property members: QList mElements; QList mInsetPlacement; QList mInsetAlignment; QList mInsetRect; private: Q_DISABLE_COPY(QCPLayoutInset) }; Q_DECLARE_METATYPE(QCPLayoutInset::InsetPlacement) /* end of 'src/layout.h' */ /* including file 'src/lineending.h' */ /* modified 2021-03-29T02:30:44, size 4426 */ class QCP_LIB_DECL QCPLineEnding { Q_GADGET public: /*! Defines the type of ending decoration for line-like items, e.g. an arrow. \image html QCPLineEnding.png The width and length of these decorations can be controlled with the functions \ref setWidth and \ref setLength. Some decorations like \ref esDisc, \ref esSquare, \ref esDiamond and \ref esBar only support a width, the length property is ignored. \see QCPItemLine::setHead, QCPItemLine::setTail, QCPItemCurve::setHead, QCPItemCurve::setTail, QCPAxis::setLowerEnding, QCPAxis::setUpperEnding */ enum EndingStyle { esNone ///< No ending decoration ,esFlatArrow ///< A filled arrow head with a straight/flat back (a triangle) ,esSpikeArrow ///< A filled arrow head with an indented back ,esLineArrow ///< A non-filled arrow head with open back ,esDisc ///< A filled circle ,esSquare ///< A filled square ,esDiamond ///< A filled diamond (45 degrees rotated square) ,esBar ///< A bar perpendicular to the line ,esHalfBar ///< A bar perpendicular to the line, pointing out to only one side (to which side can be changed with \ref setInverted) ,esSkewedBar ///< A bar that is skewed (skew controllable via \ref setLength) }; Q_ENUMS(EndingStyle) QCPLineEnding(); QCPLineEnding(EndingStyle style, double width=8, double length=10, bool inverted=false); // getters: EndingStyle style() const { return mStyle; } double width() const { return mWidth; } double length() const { return mLength; } bool inverted() const { return mInverted; } // setters: void setStyle(EndingStyle style); void setWidth(double width); void setLength(double length); void setInverted(bool inverted); // non-property methods: double boundingDistance() const; double realLength() const; void draw(QCPPainter *painter, const QCPVector2D &pos, const QCPVector2D &dir) const; void draw(QCPPainter *painter, const QCPVector2D &pos, double angle) const; protected: // property members: EndingStyle mStyle; double mWidth, mLength; bool mInverted; }; Q_DECLARE_TYPEINFO(QCPLineEnding, Q_MOVABLE_TYPE); Q_DECLARE_METATYPE(QCPLineEnding::EndingStyle) /* end of 'src/lineending.h' */ /* including file 'src/axis/labelpainter.h' */ /* modified 2021-03-29T02:30:44, size 7086 */ class QCPLabelPainterPrivate { Q_GADGET public: /*! TODO */ enum AnchorMode { amRectangular ///< ,amSkewedUpright ///< ,amSkewedRotated ///< }; Q_ENUMS(AnchorMode) /*! TODO */ enum AnchorReferenceType { artNormal ///< ,artTangent ///< }; Q_ENUMS(AnchorReferenceType) /*! TODO */ enum AnchorSide { asLeft ///< ,asRight ///< ,asTop ///< ,asBottom ///< ,asTopLeft ,asTopRight ,asBottomRight ,asBottomLeft }; Q_ENUMS(AnchorSide) explicit QCPLabelPainterPrivate(QCustomPlot *parentPlot); virtual ~QCPLabelPainterPrivate(); // setters: void setAnchorSide(AnchorSide side); void setAnchorMode(AnchorMode mode); void setAnchorReference(const QPointF &pixelPoint); void setAnchorReferenceType(AnchorReferenceType type); void setFont(const QFont &font); void setColor(const QColor &color); void setPadding(int padding); void setRotation(double rotation); void setSubstituteExponent(bool enabled); void setMultiplicationSymbol(QChar symbol); void setAbbreviateDecimalPowers(bool enabled); void setCacheSize(int labelCount); // getters: AnchorMode anchorMode() const { return mAnchorMode; } AnchorSide anchorSide() const { return mAnchorSide; } QPointF anchorReference() const { return mAnchorReference; } AnchorReferenceType anchorReferenceType() const { return mAnchorReferenceType; } QFont font() const { return mFont; } QColor color() const { return mColor; } int padding() const { return mPadding; } double rotation() const { return mRotation; } bool substituteExponent() const { return mSubstituteExponent; } QChar multiplicationSymbol() const { return mMultiplicationSymbol; } bool abbreviateDecimalPowers() const { return mAbbreviateDecimalPowers; } int cacheSize() const; //virtual int size() const; // non-property methods: void drawTickLabel(QCPPainter *painter, const QPointF &tickPos, const QString &text); void clearCache(); // constants that may be used with setMultiplicationSymbol: static const QChar SymbolDot; static const QChar SymbolCross; protected: struct CachedLabel { QPoint offset; QPixmap pixmap; }; struct LabelData { AnchorSide side; double rotation; // angle in degrees QTransform transform; // the transform about the label anchor which is at (0, 0). Does not contain final absolute x/y positioning on the plot/axis QString basePart, expPart, suffixPart; QRect baseBounds, expBounds, suffixBounds; QRect totalBounds; // is in a coordinate system where label top left is at (0, 0) QRect rotatedTotalBounds; // is in a coordinate system where the label anchor is at (0, 0) QFont baseFont, expFont; QColor color; }; // property members: AnchorMode mAnchorMode; AnchorSide mAnchorSide; QPointF mAnchorReference; AnchorReferenceType mAnchorReferenceType; QFont mFont; QColor mColor; int mPadding; double mRotation; // this is the rotation applied uniformly to all labels, not the heterogeneous rotation in amCircularRotated mode bool mSubstituteExponent; QChar mMultiplicationSymbol; bool mAbbreviateDecimalPowers; // non-property members: QCustomPlot *mParentPlot; QByteArray mLabelParameterHash; // to determine whether mLabelCache needs to be cleared due to changed parameters QCache mLabelCache; QRect mAxisSelectionBox, mTickLabelsSelectionBox, mLabelSelectionBox; int mLetterCapHeight, mLetterDescent; // introduced virtual methods: virtual void drawLabelMaybeCached(QCPPainter *painter, const QFont &font, const QColor &color, const QPointF &pos, AnchorSide side, double rotation, const QString &text); virtual QByteArray generateLabelParameterHash() const; // TODO: get rid of this in favor of invalidation flag upon setters? // non-virtual methods: QPointF getAnchorPos(const QPointF &tickPos); void drawText(QCPPainter *painter, const QPointF &pos, const LabelData &labelData) const; LabelData getTickLabelData(const QFont &font, const QColor &color, double rotation, AnchorSide side, const QString &text) const; void applyAnchorTransform(LabelData &labelData) const; //void getMaxTickLabelSize(const QFont &font, const QString &text, QSize *tickLabelsSize) const; CachedLabel *createCachedLabel(const LabelData &labelData) const; QByteArray cacheKey(const QString &text, const QColor &color, double rotation, AnchorSide side) const; AnchorSide skewedAnchorSide(const QPointF &tickPos, double sideExpandHorz, double sideExpandVert) const; AnchorSide rotationCorrectedSide(AnchorSide side, double rotation) const; void analyzeFontMetrics(); }; Q_DECLARE_METATYPE(QCPLabelPainterPrivate::AnchorMode) Q_DECLARE_METATYPE(QCPLabelPainterPrivate::AnchorSide) /* end of 'src/axis/labelpainter.h' */ /* including file 'src/axis/axisticker.h' */ /* modified 2021-03-29T02:30:44, size 4230 */ class QCP_LIB_DECL QCPAxisTicker { Q_GADGET public: /*! Defines the strategies that the axis ticker may follow when choosing the size of the tick step. \see setTickStepStrategy */ enum TickStepStrategy { tssReadability ///< A nicely readable tick step is prioritized over matching the requested number of ticks (see \ref setTickCount) ,tssMeetTickCount ///< Less readable tick steps are allowed which in turn facilitates getting closer to the requested tick count }; Q_ENUMS(TickStepStrategy) QCPAxisTicker(); virtual ~QCPAxisTicker(); // getters: TickStepStrategy tickStepStrategy() const { return mTickStepStrategy; } int tickCount() const { return mTickCount; } double tickOrigin() const { return mTickOrigin; } // setters: void setTickStepStrategy(TickStepStrategy strategy); void setTickCount(int count); void setTickOrigin(double origin); // introduced virtual methods: virtual void generate(const QCPRange &range, const QLocale &locale, QChar formatChar, int precision, QVector &ticks, QVector *subTicks, QVector *tickLabels); protected: // property members: TickStepStrategy mTickStepStrategy; int mTickCount; double mTickOrigin; // introduced virtual methods: virtual double getTickStep(const QCPRange &range); virtual int getSubTickCount(double tickStep); virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision); virtual QVector createTickVector(double tickStep, const QCPRange &range); virtual QVector createSubTickVector(int subTickCount, const QVector &ticks); virtual QVector createLabelVector(const QVector &ticks, const QLocale &locale, QChar formatChar, int precision); // non-virtual methods: void trimTicks(const QCPRange &range, QVector &ticks, bool keepOneOutlier) const; double pickClosest(double target, const QVector &candidates) const; double getMantissa(double input, double *magnitude=nullptr) const; double cleanMantissa(double input) const; private: Q_DISABLE_COPY(QCPAxisTicker) }; Q_DECLARE_METATYPE(QCPAxisTicker::TickStepStrategy) Q_DECLARE_METATYPE(QSharedPointer) /* end of 'src/axis/axisticker.h' */ /* including file 'src/axis/axistickerdatetime.h' */ /* modified 2021-03-29T02:30:44, size 3600 */ class QCP_LIB_DECL QCPAxisTickerDateTime : public QCPAxisTicker { public: QCPAxisTickerDateTime(); // getters: QString dateTimeFormat() const { return mDateTimeFormat; } Qt::TimeSpec dateTimeSpec() const { return mDateTimeSpec; } # if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) QTimeZone timeZone() const { return mTimeZone; } #endif // setters: void setDateTimeFormat(const QString &format); void setDateTimeSpec(Qt::TimeSpec spec); # if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) void setTimeZone(const QTimeZone &zone); # endif void setTickOrigin(double origin); // hides base class method but calls baseclass implementation ("using" throws off IDEs and doxygen) void setTickOrigin(const QDateTime &origin); // static methods: static QDateTime keyToDateTime(double key); static double dateTimeToKey(const QDateTime &dateTime); static double dateTimeToKey(const QDate &date, Qt::TimeSpec timeSpec=Qt::LocalTime); protected: // property members: QString mDateTimeFormat; Qt::TimeSpec mDateTimeSpec; # if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) QTimeZone mTimeZone; # endif // non-property members: enum DateStrategy {dsNone, dsUniformTimeInDay, dsUniformDayInMonth} mDateStrategy; // reimplemented virtual methods: virtual double getTickStep(const QCPRange &range) Q_DECL_OVERRIDE; virtual int getSubTickCount(double tickStep) Q_DECL_OVERRIDE; virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) Q_DECL_OVERRIDE; virtual QVector createTickVector(double tickStep, const QCPRange &range) Q_DECL_OVERRIDE; }; /* end of 'src/axis/axistickerdatetime.h' */ /* including file 'src/axis/axistickertime.h' */ /* modified 2021-03-29T02:30:44, size 3542 */ class QCP_LIB_DECL QCPAxisTickerTime : public QCPAxisTicker { Q_GADGET public: /*! Defines the logical units in which fractions of time spans can be expressed. \see setFieldWidth, setTimeFormat */ enum TimeUnit { tuMilliseconds ///< Milliseconds, one thousandth of a second (%%z in \ref setTimeFormat) ,tuSeconds ///< Seconds (%%s in \ref setTimeFormat) ,tuMinutes ///< Minutes (%%m in \ref setTimeFormat) ,tuHours ///< Hours (%%h in \ref setTimeFormat) ,tuDays ///< Days (%%d in \ref setTimeFormat) }; Q_ENUMS(TimeUnit) QCPAxisTickerTime(); // getters: QString timeFormat() const { return mTimeFormat; } int fieldWidth(TimeUnit unit) const { return mFieldWidth.value(unit); } // setters: void setTimeFormat(const QString &format); void setFieldWidth(TimeUnit unit, int width); protected: // property members: QString mTimeFormat; QHash mFieldWidth; // non-property members: TimeUnit mSmallestUnit, mBiggestUnit; QHash mFormatPattern; // reimplemented virtual methods: virtual double getTickStep(const QCPRange &range) Q_DECL_OVERRIDE; virtual int getSubTickCount(double tickStep) Q_DECL_OVERRIDE; virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) Q_DECL_OVERRIDE; // non-virtual methods: void replaceUnit(QString &text, TimeUnit unit, int value) const; }; Q_DECLARE_METATYPE(QCPAxisTickerTime::TimeUnit) /* end of 'src/axis/axistickertime.h' */ /* including file 'src/axis/axistickerfixed.h' */ /* modified 2021-03-29T02:30:44, size 3308 */ class QCP_LIB_DECL QCPAxisTickerFixed : public QCPAxisTicker { Q_GADGET public: /*! Defines how the axis ticker may modify the specified tick step (\ref setTickStep) in order to control the number of ticks in the axis range. \see setScaleStrategy */ enum ScaleStrategy { ssNone ///< Modifications are not allowed, the specified tick step is absolutely fixed. This might cause a high tick density and overlapping labels if the axis range is zoomed out. ,ssMultiples ///< An integer multiple of the specified tick step is allowed. The used factor follows the base class properties of \ref setTickStepStrategy and \ref setTickCount. ,ssPowers ///< An integer power of the specified tick step is allowed. }; Q_ENUMS(ScaleStrategy) QCPAxisTickerFixed(); // getters: double tickStep() const { return mTickStep; } ScaleStrategy scaleStrategy() const { return mScaleStrategy; } // setters: void setTickStep(double step); void setScaleStrategy(ScaleStrategy strategy); protected: // property members: double mTickStep; ScaleStrategy mScaleStrategy; // reimplemented virtual methods: virtual double getTickStep(const QCPRange &range) Q_DECL_OVERRIDE; }; Q_DECLARE_METATYPE(QCPAxisTickerFixed::ScaleStrategy) /* end of 'src/axis/axistickerfixed.h' */ /* including file 'src/axis/axistickertext.h' */ /* modified 2021-03-29T02:30:44, size 3090 */ class QCP_LIB_DECL QCPAxisTickerText : public QCPAxisTicker { public: QCPAxisTickerText(); // getters: QMap &ticks() { return mTicks; } int subTickCount() const { return mSubTickCount; } // setters: void setTicks(const QMap &ticks); void setTicks(const QVector &positions, const QVector &labels); void setSubTickCount(int subTicks); // non-virtual methods: void clear(); void addTick(double position, const QString &label); void addTicks(const QMap &ticks); void addTicks(const QVector &positions, const QVector &labels); protected: // property members: QMap mTicks; int mSubTickCount; // reimplemented virtual methods: virtual double getTickStep(const QCPRange &range) Q_DECL_OVERRIDE; virtual int getSubTickCount(double tickStep) Q_DECL_OVERRIDE; virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) Q_DECL_OVERRIDE; virtual QVector createTickVector(double tickStep, const QCPRange &range) Q_DECL_OVERRIDE; }; /* end of 'src/axis/axistickertext.h' */ /* including file 'src/axis/axistickerpi.h' */ /* modified 2021-03-29T02:30:44, size 3911 */ class QCP_LIB_DECL QCPAxisTickerPi : public QCPAxisTicker { Q_GADGET public: /*! Defines how fractions should be displayed in tick labels. \see setFractionStyle */ enum FractionStyle { fsFloatingPoint ///< Fractions are displayed as regular decimal floating point numbers, e.g. "0.25" or "0.125". ,fsAsciiFractions ///< Fractions are written as rationals using ASCII characters only, e.g. "1/4" or "1/8" ,fsUnicodeFractions ///< Fractions are written using sub- and superscript UTF-8 digits and the fraction symbol. }; Q_ENUMS(FractionStyle) QCPAxisTickerPi(); // getters: QString piSymbol() const { return mPiSymbol; } double piValue() const { return mPiValue; } bool periodicity() const { return mPeriodicity; } FractionStyle fractionStyle() const { return mFractionStyle; } // setters: void setPiSymbol(QString symbol); void setPiValue(double pi); void setPeriodicity(int multiplesOfPi); void setFractionStyle(FractionStyle style); protected: // property members: QString mPiSymbol; double mPiValue; int mPeriodicity; FractionStyle mFractionStyle; // non-property members: double mPiTickStep; // size of one tick step in units of mPiValue // reimplemented virtual methods: virtual double getTickStep(const QCPRange &range) Q_DECL_OVERRIDE; virtual int getSubTickCount(double tickStep) Q_DECL_OVERRIDE; virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) Q_DECL_OVERRIDE; // non-virtual methods: void simplifyFraction(int &numerator, int &denominator) const; QString fractionToString(int numerator, int denominator) const; QString unicodeFraction(int numerator, int denominator) const; QString unicodeSuperscript(int number) const; QString unicodeSubscript(int number) const; }; Q_DECLARE_METATYPE(QCPAxisTickerPi::FractionStyle) /* end of 'src/axis/axistickerpi.h' */ /* including file 'src/axis/axistickerlog.h' */ /* modified 2021-03-29T02:30:44, size 2594 */ class QCP_LIB_DECL QCPAxisTickerLog : public QCPAxisTicker { public: QCPAxisTickerLog(); // getters: double logBase() const { return mLogBase; } int subTickCount() const { return mSubTickCount; } // setters: void setLogBase(double base); void setSubTickCount(int subTicks); protected: // property members: double mLogBase; int mSubTickCount; // non-property members: double mLogBaseLnInv; // reimplemented virtual methods: virtual int getSubTickCount(double tickStep) Q_DECL_OVERRIDE; virtual QVector createTickVector(double tickStep, const QCPRange &range) Q_DECL_OVERRIDE; }; /* end of 'src/axis/axistickerlog.h' */ /* including file 'src/axis/axis.h' */ /* modified 2021-03-29T02:30:44, size 20913 */ class QCP_LIB_DECL QCPGrid :public QCPLayerable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(bool subGridVisible READ subGridVisible WRITE setSubGridVisible) Q_PROPERTY(bool antialiasedSubGrid READ antialiasedSubGrid WRITE setAntialiasedSubGrid) Q_PROPERTY(bool antialiasedZeroLine READ antialiasedZeroLine WRITE setAntialiasedZeroLine) Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen subGridPen READ subGridPen WRITE setSubGridPen) Q_PROPERTY(QPen zeroLinePen READ zeroLinePen WRITE setZeroLinePen) /// \endcond public: explicit QCPGrid(QCPAxis *parentAxis); // getters: bool subGridVisible() const { return mSubGridVisible; } bool antialiasedSubGrid() const { return mAntialiasedSubGrid; } bool antialiasedZeroLine() const { return mAntialiasedZeroLine; } QPen pen() const { return mPen; } QPen subGridPen() const { return mSubGridPen; } QPen zeroLinePen() const { return mZeroLinePen; } // setters: void setSubGridVisible(bool visible); void setAntialiasedSubGrid(bool enabled); void setAntialiasedZeroLine(bool enabled); void setPen(const QPen &pen); void setSubGridPen(const QPen &pen); void setZeroLinePen(const QPen &pen); protected: // property members: bool mSubGridVisible; bool mAntialiasedSubGrid, mAntialiasedZeroLine; QPen mPen, mSubGridPen, mZeroLinePen; // non-property members: QCPAxis *mParentAxis; // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; // non-virtual methods: void drawGridLines(QCPPainter *painter) const; void drawSubGridLines(QCPPainter *painter) const; friend class QCPAxis; }; class QCP_LIB_DECL QCPAxis : public QCPLayerable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(AxisType axisType READ axisType) Q_PROPERTY(QCPAxisRect* axisRect READ axisRect) Q_PROPERTY(ScaleType scaleType READ scaleType WRITE setScaleType NOTIFY scaleTypeChanged) Q_PROPERTY(QCPRange range READ range WRITE setRange NOTIFY rangeChanged) Q_PROPERTY(bool rangeReversed READ rangeReversed WRITE setRangeReversed) Q_PROPERTY(QSharedPointer ticker READ ticker WRITE setTicker) Q_PROPERTY(bool ticks READ ticks WRITE setTicks) Q_PROPERTY(bool tickLabels READ tickLabels WRITE setTickLabels) Q_PROPERTY(int tickLabelPadding READ tickLabelPadding WRITE setTickLabelPadding) Q_PROPERTY(QFont tickLabelFont READ tickLabelFont WRITE setTickLabelFont) Q_PROPERTY(QColor tickLabelColor READ tickLabelColor WRITE setTickLabelColor) Q_PROPERTY(double tickLabelRotation READ tickLabelRotation WRITE setTickLabelRotation) Q_PROPERTY(LabelSide tickLabelSide READ tickLabelSide WRITE setTickLabelSide) Q_PROPERTY(QString numberFormat READ numberFormat WRITE setNumberFormat) Q_PROPERTY(int numberPrecision READ numberPrecision WRITE setNumberPrecision) Q_PROPERTY(QVector tickVector READ tickVector) Q_PROPERTY(QVector tickVectorLabels READ tickVectorLabels) Q_PROPERTY(int tickLengthIn READ tickLengthIn WRITE setTickLengthIn) Q_PROPERTY(int tickLengthOut READ tickLengthOut WRITE setTickLengthOut) Q_PROPERTY(bool subTicks READ subTicks WRITE setSubTicks) Q_PROPERTY(int subTickLengthIn READ subTickLengthIn WRITE setSubTickLengthIn) Q_PROPERTY(int subTickLengthOut READ subTickLengthOut WRITE setSubTickLengthOut) Q_PROPERTY(QPen basePen READ basePen WRITE setBasePen) Q_PROPERTY(QPen tickPen READ tickPen WRITE setTickPen) Q_PROPERTY(QPen subTickPen READ subTickPen WRITE setSubTickPen) Q_PROPERTY(QFont labelFont READ labelFont WRITE setLabelFont) Q_PROPERTY(QColor labelColor READ labelColor WRITE setLabelColor) Q_PROPERTY(QString label READ label WRITE setLabel) Q_PROPERTY(int labelPadding READ labelPadding WRITE setLabelPadding) Q_PROPERTY(int padding READ padding WRITE setPadding) Q_PROPERTY(int offset READ offset WRITE setOffset) Q_PROPERTY(SelectableParts selectedParts READ selectedParts WRITE setSelectedParts NOTIFY selectionChanged) Q_PROPERTY(SelectableParts selectableParts READ selectableParts WRITE setSelectableParts NOTIFY selectableChanged) Q_PROPERTY(QFont selectedTickLabelFont READ selectedTickLabelFont WRITE setSelectedTickLabelFont) Q_PROPERTY(QFont selectedLabelFont READ selectedLabelFont WRITE setSelectedLabelFont) Q_PROPERTY(QColor selectedTickLabelColor READ selectedTickLabelColor WRITE setSelectedTickLabelColor) Q_PROPERTY(QColor selectedLabelColor READ selectedLabelColor WRITE setSelectedLabelColor) Q_PROPERTY(QPen selectedBasePen READ selectedBasePen WRITE setSelectedBasePen) Q_PROPERTY(QPen selectedTickPen READ selectedTickPen WRITE setSelectedTickPen) Q_PROPERTY(QPen selectedSubTickPen READ selectedSubTickPen WRITE setSelectedSubTickPen) Q_PROPERTY(QCPLineEnding lowerEnding READ lowerEnding WRITE setLowerEnding) Q_PROPERTY(QCPLineEnding upperEnding READ upperEnding WRITE setUpperEnding) Q_PROPERTY(QCPGrid* grid READ grid) /// \endcond public: /*! Defines at which side of the axis rect the axis will appear. This also affects how the tick marks are drawn, on which side the labels are placed etc. */ enum AxisType { atLeft = 0x01 ///< 0x01 Axis is vertical and on the left side of the axis rect ,atRight = 0x02 ///< 0x02 Axis is vertical and on the right side of the axis rect ,atTop = 0x04 ///< 0x04 Axis is horizontal and on the top side of the axis rect ,atBottom = 0x08 ///< 0x08 Axis is horizontal and on the bottom side of the axis rect }; Q_ENUMS(AxisType) Q_FLAGS(AxisTypes) Q_DECLARE_FLAGS(AxisTypes, AxisType) /*! Defines on which side of the axis the tick labels (numbers) shall appear. \see setTickLabelSide */ enum LabelSide { lsInside ///< Tick labels will be displayed inside the axis rect and clipped to the inner axis rect ,lsOutside ///< Tick labels will be displayed outside the axis rect }; Q_ENUMS(LabelSide) /*! Defines the scale of an axis. \see setScaleType */ enum ScaleType { stLinear ///< Linear scaling ,stLogarithmic ///< Logarithmic scaling with correspondingly transformed axis coordinates (possibly also \ref setTicker to a \ref QCPAxisTickerLog instance). }; Q_ENUMS(ScaleType) /*! Defines the selectable parts of an axis. \see setSelectableParts, setSelectedParts */ enum SelectablePart { spNone = 0 ///< None of the selectable parts ,spAxis = 0x001 ///< The axis backbone and tick marks ,spTickLabels = 0x002 ///< Tick labels (numbers) of this axis (as a whole, not individually) ,spAxisLabel = 0x004 ///< The axis label }; Q_ENUMS(SelectablePart) Q_FLAGS(SelectableParts) Q_DECLARE_FLAGS(SelectableParts, SelectablePart) explicit QCPAxis(QCPAxisRect *parent, AxisType type); virtual ~QCPAxis() Q_DECL_OVERRIDE; // getters: AxisType axisType() const { return mAxisType; } QCPAxisRect *axisRect() const { return mAxisRect; } ScaleType scaleType() const { return mScaleType; } const QCPRange range() const { return mRange; } bool rangeReversed() const { return mRangeReversed; } QSharedPointer ticker() const { return mTicker; } bool ticks() const { return mTicks; } bool tickLabels() const { return mTickLabels; } int tickLabelPadding() const; QFont tickLabelFont() const { return mTickLabelFont; } QColor tickLabelColor() const { return mTickLabelColor; } double tickLabelRotation() const; LabelSide tickLabelSide() const; QString numberFormat() const; int numberPrecision() const { return mNumberPrecision; } QVector tickVector() const { return mTickVector; } QVector tickVectorLabels() const { return mTickVectorLabels; } int tickLengthIn() const; int tickLengthOut() const; bool subTicks() const { return mSubTicks; } int subTickLengthIn() const; int subTickLengthOut() const; QPen basePen() const { return mBasePen; } QPen tickPen() const { return mTickPen; } QPen subTickPen() const { return mSubTickPen; } QFont labelFont() const { return mLabelFont; } QColor labelColor() const { return mLabelColor; } QString label() const { return mLabel; } int labelPadding() const; int padding() const { return mPadding; } int offset() const; SelectableParts selectedParts() const { return mSelectedParts; } SelectableParts selectableParts() const { return mSelectableParts; } QFont selectedTickLabelFont() const { return mSelectedTickLabelFont; } QFont selectedLabelFont() const { return mSelectedLabelFont; } QColor selectedTickLabelColor() const { return mSelectedTickLabelColor; } QColor selectedLabelColor() const { return mSelectedLabelColor; } QPen selectedBasePen() const { return mSelectedBasePen; } QPen selectedTickPen() const { return mSelectedTickPen; } QPen selectedSubTickPen() const { return mSelectedSubTickPen; } QCPLineEnding lowerEnding() const; QCPLineEnding upperEnding() const; QCPGrid *grid() const { return mGrid; } // setters: Q_SLOT void setScaleType(QCPAxis::ScaleType type); Q_SLOT void setRange(const QCPRange &range); void setRange(double lower, double upper); void setRange(double position, double size, Qt::AlignmentFlag alignment); void setRangeLower(double lower); void setRangeUpper(double upper); void setRangeReversed(bool reversed); void setTicker(QSharedPointer ticker); void setTicks(bool show); void setTickLabels(bool show); void setTickLabelPadding(int padding); void setTickLabelFont(const QFont &font); void setTickLabelColor(const QColor &color); void setTickLabelRotation(double degrees); void setTickLabelSide(LabelSide side); void setNumberFormat(const QString &formatCode); void setNumberPrecision(int precision); void setTickLength(int inside, int outside=0); void setTickLengthIn(int inside); void setTickLengthOut(int outside); void setSubTicks(bool show); void setSubTickLength(int inside, int outside=0); void setSubTickLengthIn(int inside); void setSubTickLengthOut(int outside); void setBasePen(const QPen &pen); void setTickPen(const QPen &pen); void setSubTickPen(const QPen &pen); void setLabelFont(const QFont &font); void setLabelColor(const QColor &color); void setLabel(const QString &str); void setLabelPadding(int padding); void setPadding(int padding); void setOffset(int offset); void setSelectedTickLabelFont(const QFont &font); void setSelectedLabelFont(const QFont &font); void setSelectedTickLabelColor(const QColor &color); void setSelectedLabelColor(const QColor &color); void setSelectedBasePen(const QPen &pen); void setSelectedTickPen(const QPen &pen); void setSelectedSubTickPen(const QPen &pen); Q_SLOT void setSelectableParts(const QCPAxis::SelectableParts &selectableParts); Q_SLOT void setSelectedParts(const QCPAxis::SelectableParts &selectedParts); void setLowerEnding(const QCPLineEnding &ending); void setUpperEnding(const QCPLineEnding &ending); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; // non-property methods: Qt::Orientation orientation() const { return mOrientation; } int pixelOrientation() const { return rangeReversed() != (orientation()==Qt::Vertical) ? -1 : 1; } void moveRange(double diff); void scaleRange(double factor); void scaleRange(double factor, double center); void setScaleRatio(const QCPAxis *otherAxis, double ratio=1.0); void rescale(bool onlyVisiblePlottables=false); double pixelToCoord(double value) const; double coordToPixel(double value) const; SelectablePart getPartAt(const QPointF &pos) const; QList plottables() const; QList graphs() const; QList items() const; static AxisType marginSideToAxisType(QCP::MarginSide side); static Qt::Orientation orientation(AxisType type) { return type==atBottom || type==atTop ? Qt::Horizontal : Qt::Vertical; } static AxisType opposite(AxisType type); signals: void rangeChanged(const QCPRange &newRange); void rangeChanged(const QCPRange &newRange, const QCPRange &oldRange); void scaleTypeChanged(QCPAxis::ScaleType scaleType); void selectionChanged(const QCPAxis::SelectableParts &parts); void selectableChanged(const QCPAxis::SelectableParts &parts); protected: // property members: // axis base: AxisType mAxisType; QCPAxisRect *mAxisRect; //int mOffset; // in QCPAxisPainter int mPadding; Qt::Orientation mOrientation; SelectableParts mSelectableParts, mSelectedParts; QPen mBasePen, mSelectedBasePen; //QCPLineEnding mLowerEnding, mUpperEnding; // in QCPAxisPainter // axis label: //int mLabelPadding; // in QCPAxisPainter QString mLabel; QFont mLabelFont, mSelectedLabelFont; QColor mLabelColor, mSelectedLabelColor; // tick labels: //int mTickLabelPadding; // in QCPAxisPainter bool mTickLabels; //double mTickLabelRotation; // in QCPAxisPainter QFont mTickLabelFont, mSelectedTickLabelFont; QColor mTickLabelColor, mSelectedTickLabelColor; int mNumberPrecision; QLatin1Char mNumberFormatChar; bool mNumberBeautifulPowers; //bool mNumberMultiplyCross; // QCPAxisPainter // ticks and subticks: bool mTicks; bool mSubTicks; //int mTickLengthIn, mTickLengthOut, mSubTickLengthIn, mSubTickLengthOut; // QCPAxisPainter QPen mTickPen, mSelectedTickPen; QPen mSubTickPen, mSelectedSubTickPen; // scale and range: QCPRange mRange; bool mRangeReversed; ScaleType mScaleType; // non-property members: QCPGrid *mGrid; QCPAxisPainterPrivate *mAxisPainter; QSharedPointer mTicker; QVector mTickVector; QVector mTickVectorLabels; QVector mSubTickVector; bool mCachedMarginValid; int mCachedMargin; bool mDragging; QCPRange mDragStartRange; QCP::AntialiasedElements mAADragBackup, mNotAADragBackup; // introduced virtual methods: virtual int calculateMargin(); // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QCP::Interaction selectionCategory() const Q_DECL_OVERRIDE; // events: virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) Q_DECL_OVERRIDE; virtual void deselectEvent(bool *selectionStateChanged) Q_DECL_OVERRIDE; // mouse events: virtual void mousePressEvent(QMouseEvent *event, const QVariant &details) Q_DECL_OVERRIDE; virtual void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; // non-virtual methods: void setupTickVectors(); QPen getBasePen() const; QPen getTickPen() const; QPen getSubTickPen() const; QFont getTickLabelFont() const; QFont getLabelFont() const; QColor getTickLabelColor() const; QColor getLabelColor() const; private: Q_DISABLE_COPY(QCPAxis) friend class QCustomPlot; friend class QCPGrid; friend class QCPAxisRect; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCPAxis::SelectableParts) Q_DECLARE_OPERATORS_FOR_FLAGS(QCPAxis::AxisTypes) Q_DECLARE_METATYPE(QCPAxis::AxisType) Q_DECLARE_METATYPE(QCPAxis::LabelSide) Q_DECLARE_METATYPE(QCPAxis::ScaleType) Q_DECLARE_METATYPE(QCPAxis::SelectablePart) class QCPAxisPainterPrivate { public: explicit QCPAxisPainterPrivate(QCustomPlot *parentPlot); virtual ~QCPAxisPainterPrivate(); virtual void draw(QCPPainter *painter); virtual int size(); void clearCache(); QRect axisSelectionBox() const { return mAxisSelectionBox; } QRect tickLabelsSelectionBox() const { return mTickLabelsSelectionBox; } QRect labelSelectionBox() const { return mLabelSelectionBox; } // public property members: QCPAxis::AxisType type; QPen basePen; QCPLineEnding lowerEnding, upperEnding; // directly accessed by QCPAxis setters/getters int labelPadding; // directly accessed by QCPAxis setters/getters QFont labelFont; QColor labelColor; QString label; int tickLabelPadding; // directly accessed by QCPAxis setters/getters double tickLabelRotation; // directly accessed by QCPAxis setters/getters QCPAxis::LabelSide tickLabelSide; // directly accessed by QCPAxis setters/getters bool substituteExponent; bool numberMultiplyCross; // directly accessed by QCPAxis setters/getters int tickLengthIn, tickLengthOut, subTickLengthIn, subTickLengthOut; // directly accessed by QCPAxis setters/getters QPen tickPen, subTickPen; QFont tickLabelFont; QColor tickLabelColor; QRect axisRect, viewportRect; int offset; // directly accessed by QCPAxis setters/getters bool abbreviateDecimalPowers; bool reversedEndings; QVector subTickPositions; QVector tickPositions; QVector tickLabels; protected: struct CachedLabel { QPointF offset; QPixmap pixmap; }; struct TickLabelData { QString basePart, expPart, suffixPart; QRect baseBounds, expBounds, suffixBounds, totalBounds, rotatedTotalBounds; QFont baseFont, expFont; }; QCustomPlot *mParentPlot; QByteArray mLabelParameterHash; // to determine whether mLabelCache needs to be cleared due to changed parameters QCache mLabelCache; QRect mAxisSelectionBox, mTickLabelsSelectionBox, mLabelSelectionBox; virtual QByteArray generateLabelParameterHash() const; virtual void placeTickLabel(QCPPainter *painter, double position, int distanceToAxis, const QString &text, QSize *tickLabelsSize); virtual void drawTickLabel(QCPPainter *painter, double x, double y, const TickLabelData &labelData) const; virtual TickLabelData getTickLabelData(const QFont &font, const QString &text) const; virtual QPointF getTickLabelDrawOffset(const TickLabelData &labelData) const; virtual void getMaxTickLabelSize(const QFont &font, const QString &text, QSize *tickLabelsSize) const; }; /* end of 'src/axis/axis.h' */ /* including file 'src/scatterstyle.h' */ /* modified 2021-03-29T02:30:44, size 7275 */ class QCP_LIB_DECL QCPScatterStyle { Q_GADGET public: /*! Represents the various properties of a scatter style instance. For example, this enum is used to specify which properties of \ref QCPSelectionDecorator::setScatterStyle will be used when highlighting selected data points. Specific scatter properties can be transferred between \ref QCPScatterStyle instances via \ref setFromOther. */ enum ScatterProperty { spNone = 0x00 ///< 0x00 None ,spPen = 0x01 ///< 0x01 The pen property, see \ref setPen ,spBrush = 0x02 ///< 0x02 The brush property, see \ref setBrush ,spSize = 0x04 ///< 0x04 The size property, see \ref setSize ,spShape = 0x08 ///< 0x08 The shape property, see \ref setShape ,spAll = 0xFF ///< 0xFF All properties }; Q_ENUMS(ScatterProperty) Q_FLAGS(ScatterProperties) Q_DECLARE_FLAGS(ScatterProperties, ScatterProperty) /*! Defines the shape used for scatter points. On plottables/items that draw scatters, the sizes of these visualizations (with exception of \ref ssDot and \ref ssPixmap) can be controlled with the \ref setSize function. Scatters are drawn with the pen and brush specified with \ref setPen and \ref setBrush. */ enum ScatterShape { ssNone ///< no scatter symbols are drawn (e.g. in QCPGraph, data only represented with lines) ,ssDot ///< \enumimage{ssDot.png} a single pixel (use \ref ssDisc or \ref ssCircle if you want a round shape with a certain radius) ,ssCross ///< \enumimage{ssCross.png} a cross ,ssPlus ///< \enumimage{ssPlus.png} a plus ,ssCircle ///< \enumimage{ssCircle.png} a circle ,ssDisc ///< \enumimage{ssDisc.png} a circle which is filled with the pen's color (not the brush as with ssCircle) ,ssSquare ///< \enumimage{ssSquare.png} a square ,ssDiamond ///< \enumimage{ssDiamond.png} a diamond ,ssStar ///< \enumimage{ssStar.png} a star with eight arms, i.e. a combination of cross and plus ,ssTriangle ///< \enumimage{ssTriangle.png} an equilateral triangle, standing on baseline ,ssTriangleInverted ///< \enumimage{ssTriangleInverted.png} an equilateral triangle, standing on corner ,ssCrossSquare ///< \enumimage{ssCrossSquare.png} a square with a cross inside ,ssPlusSquare ///< \enumimage{ssPlusSquare.png} a square with a plus inside ,ssCrossCircle ///< \enumimage{ssCrossCircle.png} a circle with a cross inside ,ssPlusCircle ///< \enumimage{ssPlusCircle.png} a circle with a plus inside ,ssPeace ///< \enumimage{ssPeace.png} a circle, with one vertical and two downward diagonal lines ,ssPixmap ///< a custom pixmap specified by \ref setPixmap, centered on the data point coordinates ,ssCustom ///< custom painter operations are performed per scatter (As QPainterPath, see \ref setCustomPath) }; Q_ENUMS(ScatterShape) QCPScatterStyle(); QCPScatterStyle(ScatterShape shape, double size=6); QCPScatterStyle(ScatterShape shape, const QColor &color, double size); QCPScatterStyle(ScatterShape shape, const QColor &color, const QColor &fill, double size); QCPScatterStyle(ScatterShape shape, const QPen &pen, const QBrush &brush, double size); QCPScatterStyle(const QPixmap &pixmap); QCPScatterStyle(const QPainterPath &customPath, const QPen &pen, const QBrush &brush=Qt::NoBrush, double size=6); // getters: double size() const { return mSize; } ScatterShape shape() const { return mShape; } QPen pen() const { return mPen; } QBrush brush() const { return mBrush; } QPixmap pixmap() const { return mPixmap; } QPainterPath customPath() const { return mCustomPath; } // setters: void setFromOther(const QCPScatterStyle &other, ScatterProperties properties); void setSize(double size); void setShape(ScatterShape shape); void setPen(const QPen &pen); void setBrush(const QBrush &brush); void setPixmap(const QPixmap &pixmap); void setCustomPath(const QPainterPath &customPath); // non-property methods: bool isNone() const { return mShape == ssNone; } bool isPenDefined() const { return mPenDefined; } void undefinePen(); void applyTo(QCPPainter *painter, const QPen &defaultPen) const; void drawShape(QCPPainter *painter, const QPointF &pos) const; void drawShape(QCPPainter *painter, double x, double y) const; protected: // property members: double mSize; ScatterShape mShape; QPen mPen; QBrush mBrush; QPixmap mPixmap; QPainterPath mCustomPath; // non-property members: bool mPenDefined; }; Q_DECLARE_TYPEINFO(QCPScatterStyle, Q_MOVABLE_TYPE); Q_DECLARE_OPERATORS_FOR_FLAGS(QCPScatterStyle::ScatterProperties) Q_DECLARE_METATYPE(QCPScatterStyle::ScatterProperty) Q_DECLARE_METATYPE(QCPScatterStyle::ScatterShape) /* end of 'src/scatterstyle.h' */ /* including file 'src/datacontainer.h' */ /* modified 2021-03-29T02:30:44, size 34070 */ /*! \relates QCPDataContainer Returns whether the sort key of \a a is less than the sort key of \a b. \see QCPDataContainer::sort */ template inline bool qcpLessThanSortKey(const DataType &a, const DataType &b) { return a.sortKey() < b.sortKey(); } template class QCPDataContainer // no QCP_LIB_DECL, template class ends up in header (cpp included below) { public: typedef typename QVector::const_iterator const_iterator; typedef typename QVector::iterator iterator; QCPDataContainer(); // getters: int size() const { return mData.size()-mPreallocSize; } bool isEmpty() const { return size() == 0; } bool autoSqueeze() const { return mAutoSqueeze; } // setters: void setAutoSqueeze(bool enabled); // non-virtual methods: void set(const QCPDataContainer &data); void set(const QVector &data, bool alreadySorted=false); void add(const QCPDataContainer &data); void add(const QVector &data, bool alreadySorted=false); void add(const DataType &data); void removeBefore(double sortKey); void removeAfter(double sortKey); void remove(double sortKeyFrom, double sortKeyTo); void remove(double sortKey); void clear(); void sort(); void squeeze(bool preAllocation=true, bool postAllocation=true); const_iterator constBegin() const { return mData.constBegin()+mPreallocSize; } const_iterator constEnd() const { return mData.constEnd(); } iterator begin() { return mData.begin()+mPreallocSize; } iterator end() { return mData.end(); } const_iterator findBegin(double sortKey, bool expandedRange=true) const; const_iterator findEnd(double sortKey, bool expandedRange=true) const; const_iterator at(int index) const { return constBegin()+qBound(0, index, size()); } QCPRange keyRange(bool &foundRange, QCP::SignDomain signDomain=QCP::sdBoth); QCPRange valueRange(bool &foundRange, QCP::SignDomain signDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()); QCPDataRange dataRange() const { return QCPDataRange(0, size()); } void limitIteratorsToDataRange(const_iterator &begin, const_iterator &end, const QCPDataRange &dataRange) const; protected: // property members: bool mAutoSqueeze; // non-property memebers: QVector mData; int mPreallocSize; int mPreallocIteration; // non-virtual methods: void preallocateGrow(int minimumPreallocSize); void performAutoSqueeze(); }; // include implementation in header since it is a class template: //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPDataContainer //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPDataContainer \brief The generic data container for one-dimensional plottables This class template provides a fast container for data storage of one-dimensional data. The data type is specified as template parameter (called \a DataType in the following) and must provide some methods as described in the \ref qcpdatacontainer-datatype "next section". The data is stored in a sorted fashion, which allows very quick lookups by the sorted key as well as retrieval of ranges (see \ref findBegin, \ref findEnd, \ref keyRange) using binary search. The container uses a preallocation and a postallocation scheme, such that appending and prepending data (with respect to the sort key) is very fast and minimizes reallocations. If data is added which needs to be inserted between existing keys, the merge usually can be done quickly too, using the fact that existing data is always sorted. The user can further improve performance by specifying that added data is already itself sorted by key, if he can guarantee that this is the case (see for example \ref add(const QVector &data, bool alreadySorted)). The data can be accessed with the provided const iterators (\ref constBegin, \ref constEnd). If it is necessary to alter existing data in-place, the non-const iterators can be used (\ref begin, \ref end). Changing data members that are not the sort key (for most data types called \a key) is safe from the container's perspective. Great care must be taken however if the sort key is modified through the non-const iterators. For performance reasons, the iterators don't automatically cause a re-sorting upon their manipulation. It is thus the responsibility of the user to leave the container in a sorted state when finished with the data manipulation, before calling any other methods on the container. A complete re-sort (e.g. after finishing all sort key manipulation) can be done by calling \ref sort. Failing to do so can not be detected by the container efficiently and will cause both rendering artifacts and potential data loss. Implementing one-dimensional plottables that make use of a \ref QCPDataContainer is usually done by subclassing from \ref QCPAbstractPlottable1D "QCPAbstractPlottable1D", which introduces an according \a mDataContainer member and some convenience methods. \section qcpdatacontainer-datatype Requirements for the DataType template parameter The template parameter DataType is the type of the stored data points. It must be trivially copyable and have the following public methods, preferably inline: \li double sortKey() const\n Returns the member variable of this data point that is the sort key, defining the ordering in the container. Often this variable is simply called \a key. \li static DataType fromSortKey(double sortKey)\n Returns a new instance of the data type initialized with its sort key set to \a sortKey. \li static bool sortKeyIsMainKey()\n Returns true if the sort key is equal to the main key (see method \c mainKey below). For most plottables this is the case. It is not the case for example for \ref QCPCurve, which uses \a t as sort key and \a key as main key. This is the reason why QCPCurve unlike QCPGraph can display parametric curves with loops. \li double mainKey() const\n Returns the variable of this data point considered the main key. This is commonly the variable that is used as the coordinate of this data point on the key axis of the plottable. This method is used for example when determining the automatic axis rescaling of key axes (\ref QCPAxis::rescale). \li double mainValue() const\n Returns the variable of this data point considered the main value. This is commonly the variable that is used as the coordinate of this data point on the value axis of the plottable. \li QCPRange valueRange() const\n Returns the range this data point spans in the value axis coordinate. If the data is single-valued (e.g. QCPGraphData), this is simply a range with both lower and upper set to the main data point value. However if the data points can represent multiple values at once (e.g QCPFinancialData with its \a high, \a low, \a open and \a close values at each \a key) this method should return the range those values span. This method is used for example when determining the automatic axis rescaling of value axes (\ref QCPAxis::rescale). */ /* start documentation of inline functions */ /*! \fn int QCPDataContainer::size() const Returns the number of data points in the container. */ /*! \fn bool QCPDataContainer::isEmpty() const Returns whether this container holds no data points. */ /*! \fn QCPDataContainer::const_iterator QCPDataContainer::constBegin() const Returns a const iterator to the first data point in this container. */ /*! \fn QCPDataContainer::const_iterator QCPDataContainer::constEnd() const Returns a const iterator to the element past the last data point in this container. */ /*! \fn QCPDataContainer::iterator QCPDataContainer::begin() const Returns a non-const iterator to the first data point in this container. You can manipulate the data points in-place through the non-const iterators, but great care must be taken when manipulating the sort key of a data point, see \ref sort, or the detailed description of this class. */ /*! \fn QCPDataContainer::iterator QCPDataContainer::end() const Returns a non-const iterator to the element past the last data point in this container. You can manipulate the data points in-place through the non-const iterators, but great care must be taken when manipulating the sort key of a data point, see \ref sort, or the detailed description of this class. */ /*! \fn QCPDataContainer::const_iterator QCPDataContainer::at(int index) const Returns a const iterator to the element with the specified \a index. If \a index points beyond the available elements in this container, returns \ref constEnd, i.e. an iterator past the last valid element. You can use this method to easily obtain iterators from a \ref QCPDataRange, see the \ref dataselection-accessing "data selection page" for an example. */ /*! \fn QCPDataRange QCPDataContainer::dataRange() const Returns a \ref QCPDataRange encompassing the entire data set of this container. This means the begin index of the returned range is 0, and the end index is \ref size. */ /* end documentation of inline functions */ /*! Constructs a QCPDataContainer used for plottable classes that represent a series of key-sorted data */ template QCPDataContainer::QCPDataContainer() : mAutoSqueeze(true), mPreallocSize(0), mPreallocIteration(0) { } /*! Sets whether the container automatically decides when to release memory from its post- and preallocation pools when data points are removed. By default this is enabled and for typical applications shouldn't be changed. If auto squeeze is disabled, you can manually decide when to release pre-/postallocation with \ref squeeze. */ template void QCPDataContainer::setAutoSqueeze(bool enabled) { if (mAutoSqueeze != enabled) { mAutoSqueeze = enabled; if (mAutoSqueeze) performAutoSqueeze(); } } /*! \overload Replaces the current data in this container with the provided \a data. \see add, remove */ template void QCPDataContainer::set(const QCPDataContainer &data) { clear(); add(data); } /*! \overload Replaces the current data in this container with the provided \a data If you can guarantee that the data points in \a data have ascending order with respect to the DataType's sort key, set \a alreadySorted to true to avoid an unnecessary sorting run. \see add, remove */ template void QCPDataContainer::set(const QVector &data, bool alreadySorted) { mData = data; mPreallocSize = 0; mPreallocIteration = 0; if (!alreadySorted) sort(); } /*! \overload Adds the provided \a data to the current data in this container. \see set, remove */ template void QCPDataContainer::add(const QCPDataContainer &data) { if (data.isEmpty()) return; const int n = data.size(); const int oldSize = size(); if (oldSize > 0 && !qcpLessThanSortKey(*constBegin(), *(data.constEnd()-1))) // prepend if new data keys are all smaller than or equal to existing ones { if (mPreallocSize < n) preallocateGrow(n); mPreallocSize -= n; std::copy(data.constBegin(), data.constEnd(), begin()); } else // don't need to prepend, so append and merge if necessary { mData.resize(mData.size()+n); std::copy(data.constBegin(), data.constEnd(), end()-n); if (oldSize > 0 && !qcpLessThanSortKey(*(constEnd()-n-1), *(constEnd()-n))) // if appended range keys aren't all greater than existing ones, merge the two partitions std::inplace_merge(begin(), end()-n, end(), qcpLessThanSortKey); } } /*! Adds the provided data points in \a data to the current data. If you can guarantee that the data points in \a data have ascending order with respect to the DataType's sort key, set \a alreadySorted to true to avoid an unnecessary sorting run. \see set, remove */ template void QCPDataContainer::add(const QVector &data, bool alreadySorted) { if (data.isEmpty()) return; if (isEmpty()) { set(data, alreadySorted); return; } const int n = data.size(); const int oldSize = size(); if (alreadySorted && oldSize > 0 && !qcpLessThanSortKey(*constBegin(), *(data.constEnd()-1))) // prepend if new data is sorted and keys are all smaller than or equal to existing ones { if (mPreallocSize < n) preallocateGrow(n); mPreallocSize -= n; std::copy(data.constBegin(), data.constEnd(), begin()); } else // don't need to prepend, so append and then sort and merge if necessary { mData.resize(mData.size()+n); std::copy(data.constBegin(), data.constEnd(), end()-n); if (!alreadySorted) // sort appended subrange if it wasn't already sorted std::sort(end()-n, end(), qcpLessThanSortKey); if (oldSize > 0 && !qcpLessThanSortKey(*(constEnd()-n-1), *(constEnd()-n))) // if appended range keys aren't all greater than existing ones, merge the two partitions std::inplace_merge(begin(), end()-n, end(), qcpLessThanSortKey); } } /*! \overload Adds the provided single data point to the current data. \see remove */ template void QCPDataContainer::add(const DataType &data) { if (isEmpty() || !qcpLessThanSortKey(data, *(constEnd()-1))) // quickly handle appends if new data key is greater or equal to existing ones { mData.append(data); } else if (qcpLessThanSortKey(data, *constBegin())) // quickly handle prepends using preallocated space { if (mPreallocSize < 1) preallocateGrow(1); --mPreallocSize; *begin() = data; } else // handle inserts, maintaining sorted keys { QCPDataContainer::iterator insertionPoint = std::lower_bound(begin(), end(), data, qcpLessThanSortKey); mData.insert(insertionPoint, data); } } /*! Removes all data points with (sort-)keys smaller than or equal to \a sortKey. \see removeAfter, remove, clear */ template void QCPDataContainer::removeBefore(double sortKey) { QCPDataContainer::iterator it = begin(); QCPDataContainer::iterator itEnd = std::lower_bound(begin(), end(), DataType::fromSortKey(sortKey), qcpLessThanSortKey); mPreallocSize += int(itEnd-it); // don't actually delete, just add it to the preallocated block (if it gets too large, squeeze will take care of it) if (mAutoSqueeze) performAutoSqueeze(); } /*! Removes all data points with (sort-)keys greater than or equal to \a sortKey. \see removeBefore, remove, clear */ template void QCPDataContainer::removeAfter(double sortKey) { QCPDataContainer::iterator it = std::upper_bound(begin(), end(), DataType::fromSortKey(sortKey), qcpLessThanSortKey); QCPDataContainer::iterator itEnd = end(); mData.erase(it, itEnd); // typically adds it to the postallocated block if (mAutoSqueeze) performAutoSqueeze(); } /*! Removes all data points with (sort-)keys between \a sortKeyFrom and \a sortKeyTo. if \a sortKeyFrom is greater or equal to \a sortKeyTo, the function does nothing. To remove a single data point with known (sort-)key, use \ref remove(double sortKey). \see removeBefore, removeAfter, clear */ template void QCPDataContainer::remove(double sortKeyFrom, double sortKeyTo) { if (sortKeyFrom >= sortKeyTo || isEmpty()) return; QCPDataContainer::iterator it = std::lower_bound(begin(), end(), DataType::fromSortKey(sortKeyFrom), qcpLessThanSortKey); QCPDataContainer::iterator itEnd = std::upper_bound(it, end(), DataType::fromSortKey(sortKeyTo), qcpLessThanSortKey); mData.erase(it, itEnd); if (mAutoSqueeze) performAutoSqueeze(); } /*! \overload Removes a single data point at \a sortKey. If the position is not known with absolute (binary) precision, consider using \ref remove(double sortKeyFrom, double sortKeyTo) with a small fuzziness interval around the suspected position, depeding on the precision with which the (sort-)key is known. \see removeBefore, removeAfter, clear */ template void QCPDataContainer::remove(double sortKey) { QCPDataContainer::iterator it = std::lower_bound(begin(), end(), DataType::fromSortKey(sortKey), qcpLessThanSortKey); if (it != end() && it->sortKey() == sortKey) { if (it == begin()) ++mPreallocSize; // don't actually delete, just add it to the preallocated block (if it gets too large, squeeze will take care of it) else mData.erase(it); } if (mAutoSqueeze) performAutoSqueeze(); } /*! Removes all data points. \see remove, removeAfter, removeBefore */ template void QCPDataContainer::clear() { mData.clear(); mPreallocIteration = 0; mPreallocSize = 0; } /*! Re-sorts all data points in the container by their sort key. When setting, adding or removing points using the QCPDataContainer interface (\ref set, \ref add, \ref remove, etc.), the container makes sure to always stay in a sorted state such that a full resort is never necessary. However, if you choose to directly manipulate the sort key on data points by accessing and modifying it through the non-const iterators (\ref begin, \ref end), it is your responsibility to bring the container back into a sorted state before any other methods are called on it. This can be achieved by calling this method immediately after finishing the sort key manipulation. */ template void QCPDataContainer::sort() { std::sort(begin(), end(), qcpLessThanSortKey); } /*! Frees all unused memory that is currently in the preallocation and postallocation pools. Note that QCPDataContainer automatically decides whether squeezing is necessary, if \ref setAutoSqueeze is left enabled. It should thus not be necessary to use this method for typical applications. The parameters \a preAllocation and \a postAllocation control whether pre- and/or post allocation should be freed, respectively. */ template void QCPDataContainer::squeeze(bool preAllocation, bool postAllocation) { if (preAllocation) { if (mPreallocSize > 0) { std::copy(begin(), end(), mData.begin()); mData.resize(size()); mPreallocSize = 0; } mPreallocIteration = 0; } if (postAllocation) mData.squeeze(); } /*! Returns an iterator to the data point with a (sort-)key that is equal to, just below, or just above \a sortKey. If \a expandedRange is true, the data point just below \a sortKey will be considered, otherwise the one just above. This can be used in conjunction with \ref findEnd to iterate over data points within a given key range, including or excluding the bounding data points that are just beyond the specified range. If \a expandedRange is true but there are no data points below \a sortKey, \ref constBegin is returned. If the container is empty, returns \ref constEnd. \see findEnd, QCPPlottableInterface1D::findBegin */ template typename QCPDataContainer::const_iterator QCPDataContainer::findBegin(double sortKey, bool expandedRange) const { if (isEmpty()) return constEnd(); QCPDataContainer::const_iterator it = std::lower_bound(constBegin(), constEnd(), DataType::fromSortKey(sortKey), qcpLessThanSortKey); if (expandedRange && it != constBegin()) // also covers it == constEnd case, and we know --constEnd is valid because mData isn't empty --it; return it; } /*! Returns an iterator to the element after the data point with a (sort-)key that is equal to, just above or just below \a sortKey. If \a expandedRange is true, the data point just above \a sortKey will be considered, otherwise the one just below. This can be used in conjunction with \ref findBegin to iterate over data points within a given key range, including the bounding data points that are just below and above the specified range. If \a expandedRange is true but there are no data points above \a sortKey, \ref constEnd is returned. If the container is empty, \ref constEnd is returned. \see findBegin, QCPPlottableInterface1D::findEnd */ template typename QCPDataContainer::const_iterator QCPDataContainer::findEnd(double sortKey, bool expandedRange) const { if (isEmpty()) return constEnd(); QCPDataContainer::const_iterator it = std::upper_bound(constBegin(), constEnd(), DataType::fromSortKey(sortKey), qcpLessThanSortKey); if (expandedRange && it != constEnd()) ++it; return it; } /*! Returns the range encompassed by the (main-)key coordinate of all data points. The output parameter \a foundRange indicates whether a sensible range was found. If this is false, you should not use the returned QCPRange (e.g. the data container is empty or all points have the same key). Use \a signDomain to control which sign of the key coordinates should be considered. This is relevant e.g. for logarithmic plots which can mathematically only display one sign domain at a time. If the DataType reports that its main key is equal to the sort key (\a sortKeyIsMainKey), as is the case for most plottables, this method uses this fact and finds the range very quickly. \see valueRange */ template QCPRange QCPDataContainer::keyRange(bool &foundRange, QCP::SignDomain signDomain) { if (isEmpty()) { foundRange = false; return QCPRange(); } QCPRange range; bool haveLower = false; bool haveUpper = false; double current; QCPDataContainer::const_iterator it = constBegin(); QCPDataContainer::const_iterator itEnd = constEnd(); if (signDomain == QCP::sdBoth) // range may be anywhere { if (DataType::sortKeyIsMainKey()) // if DataType is sorted by main key (e.g. QCPGraph, but not QCPCurve), use faster algorithm by finding just first and last key with non-NaN value { while (it != itEnd) // find first non-nan going up from left { if (!qIsNaN(it->mainValue())) { range.lower = it->mainKey(); haveLower = true; break; } ++it; } it = itEnd; while (it != constBegin()) // find first non-nan going down from right { --it; if (!qIsNaN(it->mainValue())) { range.upper = it->mainKey(); haveUpper = true; break; } } } else // DataType is not sorted by main key, go through all data points and accordingly expand range { while (it != itEnd) { if (!qIsNaN(it->mainValue())) { current = it->mainKey(); if (current < range.lower || !haveLower) { range.lower = current; haveLower = true; } if (current > range.upper || !haveUpper) { range.upper = current; haveUpper = true; } } ++it; } } } else if (signDomain == QCP::sdNegative) // range may only be in the negative sign domain { while (it != itEnd) { if (!qIsNaN(it->mainValue())) { current = it->mainKey(); if ((current < range.lower || !haveLower) && current < 0) { range.lower = current; haveLower = true; } if ((current > range.upper || !haveUpper) && current < 0) { range.upper = current; haveUpper = true; } } ++it; } } else if (signDomain == QCP::sdPositive) // range may only be in the positive sign domain { while (it != itEnd) { if (!qIsNaN(it->mainValue())) { current = it->mainKey(); if ((current < range.lower || !haveLower) && current > 0) { range.lower = current; haveLower = true; } if ((current > range.upper || !haveUpper) && current > 0) { range.upper = current; haveUpper = true; } } ++it; } } foundRange = haveLower && haveUpper; return range; } /*! Returns the range encompassed by the value coordinates of the data points in the specified key range (\a inKeyRange), using the full \a DataType::valueRange reported by the data points. The output parameter \a foundRange indicates whether a sensible range was found. If this is false, you should not use the returned QCPRange (e.g. the data container is empty or all points have the same value). If \a inKeyRange has both lower and upper bound set to zero (is equal to QCPRange()), all data points are considered, without any restriction on the keys. Use \a signDomain to control which sign of the value coordinates should be considered. This is relevant e.g. for logarithmic plots which can mathematically only display one sign domain at a time. \see keyRange */ template QCPRange QCPDataContainer::valueRange(bool &foundRange, QCP::SignDomain signDomain, const QCPRange &inKeyRange) { if (isEmpty()) { foundRange = false; return QCPRange(); } QCPRange range; const bool restrictKeyRange = inKeyRange != QCPRange(); bool haveLower = false; bool haveUpper = false; QCPRange current; QCPDataContainer::const_iterator itBegin = constBegin(); QCPDataContainer::const_iterator itEnd = constEnd(); if (DataType::sortKeyIsMainKey() && restrictKeyRange) { itBegin = findBegin(inKeyRange.lower, false); itEnd = findEnd(inKeyRange.upper, false); } if (signDomain == QCP::sdBoth) // range may be anywhere { for (QCPDataContainer::const_iterator it = itBegin; it != itEnd; ++it) { if (restrictKeyRange && (it->mainKey() < inKeyRange.lower || it->mainKey() > inKeyRange.upper)) continue; current = it->valueRange(); if ((current.lower < range.lower || !haveLower) && !qIsNaN(current.lower)) { range.lower = current.lower; haveLower = true; } if ((current.upper > range.upper || !haveUpper) && !qIsNaN(current.upper)) { range.upper = current.upper; haveUpper = true; } } } else if (signDomain == QCP::sdNegative) // range may only be in the negative sign domain { for (QCPDataContainer::const_iterator it = itBegin; it != itEnd; ++it) { if (restrictKeyRange && (it->mainKey() < inKeyRange.lower || it->mainKey() > inKeyRange.upper)) continue; current = it->valueRange(); if ((current.lower < range.lower || !haveLower) && current.lower < 0 && !qIsNaN(current.lower)) { range.lower = current.lower; haveLower = true; } if ((current.upper > range.upper || !haveUpper) && current.upper < 0 && !qIsNaN(current.upper)) { range.upper = current.upper; haveUpper = true; } } } else if (signDomain == QCP::sdPositive) // range may only be in the positive sign domain { for (QCPDataContainer::const_iterator it = itBegin; it != itEnd; ++it) { if (restrictKeyRange && (it->mainKey() < inKeyRange.lower || it->mainKey() > inKeyRange.upper)) continue; current = it->valueRange(); if ((current.lower < range.lower || !haveLower) && current.lower > 0 && !qIsNaN(current.lower)) { range.lower = current.lower; haveLower = true; } if ((current.upper > range.upper || !haveUpper) && current.upper > 0 && !qIsNaN(current.upper)) { range.upper = current.upper; haveUpper = true; } } } foundRange = haveLower && haveUpper; return range; } /*! Makes sure \a begin and \a end mark a data range that is both within the bounds of this data container's data, as well as within the specified \a dataRange. The initial range described by the passed iterators \a begin and \a end is never expanded, only contracted if necessary. This function doesn't require for \a dataRange to be within the bounds of this data container's valid range. */ template void QCPDataContainer::limitIteratorsToDataRange(const_iterator &begin, const_iterator &end, const QCPDataRange &dataRange) const { QCPDataRange iteratorRange(int(begin-constBegin()), int(end-constBegin())); iteratorRange = iteratorRange.bounded(dataRange.bounded(this->dataRange())); begin = constBegin()+iteratorRange.begin(); end = constBegin()+iteratorRange.end(); } /*! \internal Increases the preallocation pool to have a size of at least \a minimumPreallocSize. Depending on the preallocation history, the container will grow by more than requested, to speed up future consecutive size increases. if \a minimumPreallocSize is smaller than or equal to the current preallocation pool size, this method does nothing. */ template void QCPDataContainer::preallocateGrow(int minimumPreallocSize) { if (minimumPreallocSize <= mPreallocSize) return; int newPreallocSize = minimumPreallocSize; newPreallocSize += (1u< void QCPDataContainer::performAutoSqueeze() { const int totalAlloc = mData.capacity(); const int postAllocSize = totalAlloc-mData.size(); const int usedSize = size(); bool shrinkPostAllocation = false; bool shrinkPreAllocation = false; if (totalAlloc > 650000) // if allocation is larger, shrink earlier with respect to total used size { shrinkPostAllocation = postAllocSize > usedSize*1.5; // QVector grow strategy is 2^n for static data. Watch out not to oscillate! shrinkPreAllocation = mPreallocSize*10 > usedSize; } else if (totalAlloc > 1000) // below 10 MiB raw data be generous with preallocated memory, below 1k points don't even bother { shrinkPostAllocation = postAllocSize > usedSize*5; shrinkPreAllocation = mPreallocSize > usedSize*1.5; // preallocation can grow into postallocation, so can be smaller } if (shrinkPreAllocation || shrinkPostAllocation) squeeze(shrinkPreAllocation, shrinkPostAllocation); } /* end of 'src/datacontainer.h' */ /* including file 'src/plottable.h' */ /* modified 2021-03-29T02:30:44, size 8461 */ class QCP_LIB_DECL QCPSelectionDecorator { Q_GADGET public: QCPSelectionDecorator(); virtual ~QCPSelectionDecorator(); // getters: QPen pen() const { return mPen; } QBrush brush() const { return mBrush; } QCPScatterStyle scatterStyle() const { return mScatterStyle; } QCPScatterStyle::ScatterProperties usedScatterProperties() const { return mUsedScatterProperties; } // setters: void setPen(const QPen &pen); void setBrush(const QBrush &brush); void setScatterStyle(const QCPScatterStyle &scatterStyle, QCPScatterStyle::ScatterProperties usedProperties=QCPScatterStyle::spPen); void setUsedScatterProperties(const QCPScatterStyle::ScatterProperties &properties); // non-virtual methods: void applyPen(QCPPainter *painter) const; void applyBrush(QCPPainter *painter) const; QCPScatterStyle getFinalScatterStyle(const QCPScatterStyle &unselectedStyle) const; // introduced virtual methods: virtual void copyFrom(const QCPSelectionDecorator *other); virtual void drawDecoration(QCPPainter *painter, QCPDataSelection selection); protected: // property members: QPen mPen; QBrush mBrush; QCPScatterStyle mScatterStyle; QCPScatterStyle::ScatterProperties mUsedScatterProperties; // non-property members: QCPAbstractPlottable *mPlottable; // introduced virtual methods: virtual bool registerWithPlottable(QCPAbstractPlottable *plottable); private: Q_DISABLE_COPY(QCPSelectionDecorator) friend class QCPAbstractPlottable; }; Q_DECLARE_METATYPE(QCPSelectionDecorator*) class QCP_LIB_DECL QCPAbstractPlottable : public QCPLayerable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(bool antialiasedFill READ antialiasedFill WRITE setAntialiasedFill) Q_PROPERTY(bool antialiasedScatters READ antialiasedScatters WRITE setAntialiasedScatters) Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QBrush brush READ brush WRITE setBrush) Q_PROPERTY(QCPAxis* keyAxis READ keyAxis WRITE setKeyAxis) Q_PROPERTY(QCPAxis* valueAxis READ valueAxis WRITE setValueAxis) Q_PROPERTY(QCP::SelectionType selectable READ selectable WRITE setSelectable NOTIFY selectableChanged) Q_PROPERTY(QCPDataSelection selection READ selection WRITE setSelection NOTIFY selectionChanged) Q_PROPERTY(QCPSelectionDecorator* selectionDecorator READ selectionDecorator WRITE setSelectionDecorator) /// \endcond public: QCPAbstractPlottable(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPAbstractPlottable() Q_DECL_OVERRIDE; // getters: QString name() const { return mName; } bool antialiasedFill() const { return mAntialiasedFill; } bool antialiasedScatters() const { return mAntialiasedScatters; } QPen pen() const { return mPen; } QBrush brush() const { return mBrush; } QCPAxis *keyAxis() const { return mKeyAxis.data(); } QCPAxis *valueAxis() const { return mValueAxis.data(); } QCP::SelectionType selectable() const { return mSelectable; } bool selected() const { return !mSelection.isEmpty(); } QCPDataSelection selection() const { return mSelection; } QCPSelectionDecorator *selectionDecorator() const { return mSelectionDecorator; } // setters: void setName(const QString &name); void setAntialiasedFill(bool enabled); void setAntialiasedScatters(bool enabled); void setPen(const QPen &pen); void setBrush(const QBrush &brush); void setKeyAxis(QCPAxis *axis); void setValueAxis(QCPAxis *axis); Q_SLOT void setSelectable(QCP::SelectionType selectable); Q_SLOT void setSelection(QCPDataSelection selection); void setSelectionDecorator(QCPSelectionDecorator *decorator); // introduced virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE = 0; // actually introduced in QCPLayerable as non-pure, but we want to force reimplementation for plottables virtual QCPPlottableInterface1D *interface1D() { return nullptr; } virtual QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const = 0; virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const = 0; // non-property methods: void coordsToPixels(double key, double value, double &x, double &y) const; const QPointF coordsToPixels(double key, double value) const; void pixelsToCoords(double x, double y, double &key, double &value) const; void pixelsToCoords(const QPointF &pixelPos, double &key, double &value) const; void rescaleAxes(bool onlyEnlarge=false) const; void rescaleKeyAxis(bool onlyEnlarge=false) const; void rescaleValueAxis(bool onlyEnlarge=false, bool inKeyRange=false) const; bool addToLegend(QCPLegend *legend); bool addToLegend(); bool removeFromLegend(QCPLegend *legend) const; bool removeFromLegend() const; signals: void selectionChanged(bool selected); void selectionChanged(const QCPDataSelection &selection); void selectableChanged(QCP::SelectionType selectable); protected: // property members: QString mName; bool mAntialiasedFill, mAntialiasedScatters; QPen mPen; QBrush mBrush; QPointer mKeyAxis, mValueAxis; QCP::SelectionType mSelectable; QCPDataSelection mSelection; QCPSelectionDecorator *mSelectionDecorator; // reimplemented virtual methods: virtual QRect clipRect() const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE = 0; virtual QCP::Interaction selectionCategory() const Q_DECL_OVERRIDE; void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; // events: virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) Q_DECL_OVERRIDE; virtual void deselectEvent(bool *selectionStateChanged) Q_DECL_OVERRIDE; // introduced virtual methods: virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const = 0; // non-virtual methods: void applyFillAntialiasingHint(QCPPainter *painter) const; void applyScattersAntialiasingHint(QCPPainter *painter) const; private: Q_DISABLE_COPY(QCPAbstractPlottable) friend class QCustomPlot; friend class QCPAxis; friend class QCPPlottableLegendItem; }; /* end of 'src/plottable.h' */ /* including file 'src/item.h' */ /* modified 2021-03-29T02:30:44, size 9425 */ class QCP_LIB_DECL QCPItemAnchor { Q_GADGET public: QCPItemAnchor(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString &name, int anchorId=-1); virtual ~QCPItemAnchor(); // getters: QString name() const { return mName; } virtual QPointF pixelPosition() const; protected: // property members: QString mName; // non-property members: QCustomPlot *mParentPlot; QCPAbstractItem *mParentItem; int mAnchorId; QSet mChildrenX, mChildrenY; // introduced virtual methods: virtual QCPItemPosition *toQCPItemPosition() { return nullptr; } // non-virtual methods: void addChildX(QCPItemPosition* pos); // called from pos when this anchor is set as parent void removeChildX(QCPItemPosition *pos); // called from pos when its parent anchor is reset or pos deleted void addChildY(QCPItemPosition* pos); // called from pos when this anchor is set as parent void removeChildY(QCPItemPosition *pos); // called from pos when its parent anchor is reset or pos deleted private: Q_DISABLE_COPY(QCPItemAnchor) friend class QCPItemPosition; }; class QCP_LIB_DECL QCPItemPosition : public QCPItemAnchor { Q_GADGET public: /*! Defines the ways an item position can be specified. Thus it defines what the numbers passed to \ref setCoords actually mean. \see setType */ enum PositionType { ptAbsolute ///< Static positioning in pixels, starting from the top left corner of the viewport/widget. ,ptViewportRatio ///< Static positioning given by a fraction of the viewport size. For example, if you call setCoords(0, 0), the position will be at the top ///< left corner of the viewport/widget. setCoords(1, 1) will be at the bottom right corner, setCoords(0.5, 0) will be horizontally centered and ///< vertically at the top of the viewport/widget, etc. ,ptAxisRectRatio ///< Static positioning given by a fraction of the axis rect size (see \ref setAxisRect). For example, if you call setCoords(0, 0), the position will be at the top ///< left corner of the axis rect. setCoords(1, 1) will be at the bottom right corner, setCoords(0.5, 0) will be horizontally centered and ///< vertically at the top of the axis rect, etc. You can also go beyond the axis rect by providing negative coordinates or coordinates larger than 1. ,ptPlotCoords ///< Dynamic positioning at a plot coordinate defined by two axes (see \ref setAxes). }; Q_ENUMS(PositionType) QCPItemPosition(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString &name); virtual ~QCPItemPosition() Q_DECL_OVERRIDE; // getters: PositionType type() const { return typeX(); } PositionType typeX() const { return mPositionTypeX; } PositionType typeY() const { return mPositionTypeY; } QCPItemAnchor *parentAnchor() const { return parentAnchorX(); } QCPItemAnchor *parentAnchorX() const { return mParentAnchorX; } QCPItemAnchor *parentAnchorY() const { return mParentAnchorY; } double key() const { return mKey; } double value() const { return mValue; } QPointF coords() const { return QPointF(mKey, mValue); } QCPAxis *keyAxis() const { return mKeyAxis.data(); } QCPAxis *valueAxis() const { return mValueAxis.data(); } QCPAxisRect *axisRect() const; virtual QPointF pixelPosition() const Q_DECL_OVERRIDE; // setters: void setType(PositionType type); void setTypeX(PositionType type); void setTypeY(PositionType type); bool setParentAnchor(QCPItemAnchor *parentAnchor, bool keepPixelPosition=false); bool setParentAnchorX(QCPItemAnchor *parentAnchor, bool keepPixelPosition=false); bool setParentAnchorY(QCPItemAnchor *parentAnchor, bool keepPixelPosition=false); void setCoords(double key, double value); void setCoords(const QPointF &pos); void setAxes(QCPAxis* keyAxis, QCPAxis* valueAxis); void setAxisRect(QCPAxisRect *axisRect); void setPixelPosition(const QPointF &pixelPosition); protected: // property members: PositionType mPositionTypeX, mPositionTypeY; QPointer mKeyAxis, mValueAxis; QPointer mAxisRect; double mKey, mValue; QCPItemAnchor *mParentAnchorX, *mParentAnchorY; // reimplemented virtual methods: virtual QCPItemPosition *toQCPItemPosition() Q_DECL_OVERRIDE { return this; } private: Q_DISABLE_COPY(QCPItemPosition) }; Q_DECLARE_METATYPE(QCPItemPosition::PositionType) class QCP_LIB_DECL QCPAbstractItem : public QCPLayerable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(bool clipToAxisRect READ clipToAxisRect WRITE setClipToAxisRect) Q_PROPERTY(QCPAxisRect* clipAxisRect READ clipAxisRect WRITE setClipAxisRect) Q_PROPERTY(bool selectable READ selectable WRITE setSelectable NOTIFY selectableChanged) Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectionChanged) /// \endcond public: explicit QCPAbstractItem(QCustomPlot *parentPlot); virtual ~QCPAbstractItem() Q_DECL_OVERRIDE; // getters: bool clipToAxisRect() const { return mClipToAxisRect; } QCPAxisRect *clipAxisRect() const; bool selectable() const { return mSelectable; } bool selected() const { return mSelected; } // setters: void setClipToAxisRect(bool clip); void setClipAxisRect(QCPAxisRect *rect); Q_SLOT void setSelectable(bool selectable); Q_SLOT void setSelected(bool selected); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE = 0; // non-virtual methods: QList positions() const { return mPositions; } QList anchors() const { return mAnchors; } QCPItemPosition *position(const QString &name) const; QCPItemAnchor *anchor(const QString &name) const; bool hasAnchor(const QString &name) const; signals: void selectionChanged(bool selected); void selectableChanged(bool selectable); protected: // property members: bool mClipToAxisRect; QPointer mClipAxisRect; QList mPositions; QList mAnchors; bool mSelectable, mSelected; // reimplemented virtual methods: virtual QCP::Interaction selectionCategory() const Q_DECL_OVERRIDE; virtual QRect clipRect() const Q_DECL_OVERRIDE; virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE = 0; // events: virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) Q_DECL_OVERRIDE; virtual void deselectEvent(bool *selectionStateChanged) Q_DECL_OVERRIDE; // introduced virtual methods: virtual QPointF anchorPixelPosition(int anchorId) const; // non-virtual methods: double rectDistance(const QRectF &rect, const QPointF &pos, bool filledRect) const; QCPItemPosition *createPosition(const QString &name); QCPItemAnchor *createAnchor(const QString &name, int anchorId); private: Q_DISABLE_COPY(QCPAbstractItem) friend class QCustomPlot; friend class QCPItemAnchor; }; /* end of 'src/item.h' */ /* including file 'src/core.h' */ /* modified 2021-03-29T02:30:44, size 19304 */ class QCP_LIB_DECL QCustomPlot : public QWidget { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QRect viewport READ viewport WRITE setViewport) Q_PROPERTY(QPixmap background READ background WRITE setBackground) Q_PROPERTY(bool backgroundScaled READ backgroundScaled WRITE setBackgroundScaled) Q_PROPERTY(Qt::AspectRatioMode backgroundScaledMode READ backgroundScaledMode WRITE setBackgroundScaledMode) Q_PROPERTY(QCPLayoutGrid* plotLayout READ plotLayout) Q_PROPERTY(bool autoAddPlottableToLegend READ autoAddPlottableToLegend WRITE setAutoAddPlottableToLegend) Q_PROPERTY(int selectionTolerance READ selectionTolerance WRITE setSelectionTolerance) Q_PROPERTY(bool noAntialiasingOnDrag READ noAntialiasingOnDrag WRITE setNoAntialiasingOnDrag) Q_PROPERTY(Qt::KeyboardModifier multiSelectModifier READ multiSelectModifier WRITE setMultiSelectModifier) Q_PROPERTY(bool openGl READ openGl WRITE setOpenGl) /// \endcond public: /*! Defines how a layer should be inserted relative to an other layer. \see addLayer, moveLayer */ enum LayerInsertMode { limBelow ///< Layer is inserted below other layer ,limAbove ///< Layer is inserted above other layer }; Q_ENUMS(LayerInsertMode) /*! Defines with what timing the QCustomPlot surface is refreshed after a replot. \see replot */ enum RefreshPriority { rpImmediateRefresh ///< Replots immediately and repaints the widget immediately by calling QWidget::repaint() after the replot ,rpQueuedRefresh ///< Replots immediately, but queues the widget repaint, by calling QWidget::update() after the replot. This way multiple redundant widget repaints can be avoided. ,rpRefreshHint ///< Whether to use immediate or queued refresh depends on whether the plotting hint \ref QCP::phImmediateRefresh is set, see \ref setPlottingHints. ,rpQueuedReplot ///< Queues the entire replot for the next event loop iteration. This way multiple redundant replots can be avoided. The actual replot is then done with \ref rpRefreshHint priority. }; Q_ENUMS(RefreshPriority) explicit QCustomPlot(QWidget *parent = nullptr); virtual ~QCustomPlot() Q_DECL_OVERRIDE; // getters: QRect viewport() const { return mViewport; } double bufferDevicePixelRatio() const { return mBufferDevicePixelRatio; } QPixmap background() const { return mBackgroundPixmap; } bool backgroundScaled() const { return mBackgroundScaled; } Qt::AspectRatioMode backgroundScaledMode() const { return mBackgroundScaledMode; } QCPLayoutGrid *plotLayout() const { return mPlotLayout; } QCP::AntialiasedElements antialiasedElements() const { return mAntialiasedElements; } QCP::AntialiasedElements notAntialiasedElements() const { return mNotAntialiasedElements; } bool autoAddPlottableToLegend() const { return mAutoAddPlottableToLegend; } const QCP::Interactions interactions() const { return mInteractions; } int selectionTolerance() const { return mSelectionTolerance; } bool noAntialiasingOnDrag() const { return mNoAntialiasingOnDrag; } QCP::PlottingHints plottingHints() const { return mPlottingHints; } Qt::KeyboardModifier multiSelectModifier() const { return mMultiSelectModifier; } QCP::SelectionRectMode selectionRectMode() const { return mSelectionRectMode; } QCPSelectionRect *selectionRect() const { return mSelectionRect; } bool openGl() const { return mOpenGl; } // setters: void setViewport(const QRect &rect); void setBufferDevicePixelRatio(double ratio); void setBackground(const QPixmap &pm); void setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode=Qt::KeepAspectRatioByExpanding); void setBackground(const QBrush &brush); void setBackgroundScaled(bool scaled); void setBackgroundScaledMode(Qt::AspectRatioMode mode); void setAntialiasedElements(const QCP::AntialiasedElements &antialiasedElements); void setAntialiasedElement(QCP::AntialiasedElement antialiasedElement, bool enabled=true); void setNotAntialiasedElements(const QCP::AntialiasedElements ¬AntialiasedElements); void setNotAntialiasedElement(QCP::AntialiasedElement notAntialiasedElement, bool enabled=true); void setAutoAddPlottableToLegend(bool on); void setInteractions(const QCP::Interactions &interactions); void setInteraction(const QCP::Interaction &interaction, bool enabled=true); void setSelectionTolerance(int pixels); void setNoAntialiasingOnDrag(bool enabled); void setPlottingHints(const QCP::PlottingHints &hints); void setPlottingHint(QCP::PlottingHint hint, bool enabled=true); void setMultiSelectModifier(Qt::KeyboardModifier modifier); void setSelectionRectMode(QCP::SelectionRectMode mode); void setSelectionRect(QCPSelectionRect *selectionRect); void setOpenGl(bool enabled, int multisampling=16); // non-property methods: // plottable interface: QCPAbstractPlottable *plottable(int index); QCPAbstractPlottable *plottable(); bool removePlottable(QCPAbstractPlottable *plottable); bool removePlottable(int index); int clearPlottables(); int plottableCount() const; QList selectedPlottables() const; template PlottableType *plottableAt(const QPointF &pos, bool onlySelectable=false, int *dataIndex=nullptr) const; QCPAbstractPlottable *plottableAt(const QPointF &pos, bool onlySelectable=false, int *dataIndex=nullptr) const; bool hasPlottable(QCPAbstractPlottable *plottable) const; // specialized interface for QCPGraph: QCPGraph *graph(int index) const; QCPGraph *graph() const; QCPGraph *addGraph(QCPAxis *keyAxis=nullptr, QCPAxis *valueAxis=nullptr); bool removeGraph(QCPGraph *graph); bool removeGraph(int index); int clearGraphs(); int graphCount() const; QList selectedGraphs() const; // item interface: QCPAbstractItem *item(int index) const; QCPAbstractItem *item() const; bool removeItem(QCPAbstractItem *item); bool removeItem(int index); int clearItems(); int itemCount() const; QList selectedItems() const; template ItemType *itemAt(const QPointF &pos, bool onlySelectable=false) const; QCPAbstractItem *itemAt(const QPointF &pos, bool onlySelectable=false) const; bool hasItem(QCPAbstractItem *item) const; // layer interface: QCPLayer *layer(const QString &name) const; QCPLayer *layer(int index) const; QCPLayer *currentLayer() const; bool setCurrentLayer(const QString &name); bool setCurrentLayer(QCPLayer *layer); int layerCount() const; bool addLayer(const QString &name, QCPLayer *otherLayer=nullptr, LayerInsertMode insertMode=limAbove); bool removeLayer(QCPLayer *layer); bool moveLayer(QCPLayer *layer, QCPLayer *otherLayer, LayerInsertMode insertMode=limAbove); // axis rect/layout interface: int axisRectCount() const; QCPAxisRect* axisRect(int index=0) const; QList axisRects() const; QCPLayoutElement* layoutElementAt(const QPointF &pos) const; QCPAxisRect* axisRectAt(const QPointF &pos) const; Q_SLOT void rescaleAxes(bool onlyVisiblePlottables=false); QList selectedAxes() const; QList selectedLegends() const; Q_SLOT void deselectAll(); bool savePdf(const QString &fileName, int width=0, int height=0, QCP::ExportPen exportPen=QCP::epAllowCosmetic, const QString &pdfCreator=QString(), const QString &pdfTitle=QString()); bool savePng(const QString &fileName, int width=0, int height=0, double scale=1.0, int quality=-1, int resolution=96, QCP::ResolutionUnit resolutionUnit=QCP::ruDotsPerInch); bool saveJpg(const QString &fileName, int width=0, int height=0, double scale=1.0, int quality=-1, int resolution=96, QCP::ResolutionUnit resolutionUnit=QCP::ruDotsPerInch); bool saveBmp(const QString &fileName, int width=0, int height=0, double scale=1.0, int resolution=96, QCP::ResolutionUnit resolutionUnit=QCP::ruDotsPerInch); bool saveRastered(const QString &fileName, int width, int height, double scale, const char *format, int quality=-1, int resolution=96, QCP::ResolutionUnit resolutionUnit=QCP::ruDotsPerInch); QPixmap toPixmap(int width=0, int height=0, double scale=1.0); void toPainter(QCPPainter *painter, int width=0, int height=0); Q_SLOT void replot(QCustomPlot::RefreshPriority refreshPriority=QCustomPlot::rpRefreshHint); double replotTime(bool average=false) const; QCPAxis *xAxis, *yAxis, *xAxis2, *yAxis2; QCPLegend *legend; signals: void mouseDoubleClick(QMouseEvent *event); void mousePress(QMouseEvent *event); void mouseMove(QMouseEvent *event); void mouseRelease(QMouseEvent *event); void mouseWheel(QWheelEvent *event); void plottableClick(QCPAbstractPlottable *plottable, int dataIndex, QMouseEvent *event); void plottableDoubleClick(QCPAbstractPlottable *plottable, int dataIndex, QMouseEvent *event); void itemClick(QCPAbstractItem *item, QMouseEvent *event); void itemDoubleClick(QCPAbstractItem *item, QMouseEvent *event); void axisClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event); void axisDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event); void legendClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event); void legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event); void selectionChangedByUser(); void beforeReplot(); void afterLayout(); void afterReplot(); protected: // property members: QRect mViewport; double mBufferDevicePixelRatio; QCPLayoutGrid *mPlotLayout; bool mAutoAddPlottableToLegend; QList mPlottables; QList mGraphs; // extra list of plottables also in mPlottables that are of type QCPGraph QList mItems; QList mLayers; QCP::AntialiasedElements mAntialiasedElements, mNotAntialiasedElements; QCP::Interactions mInteractions; int mSelectionTolerance; bool mNoAntialiasingOnDrag; QBrush mBackgroundBrush; QPixmap mBackgroundPixmap; QPixmap mScaledBackgroundPixmap; bool mBackgroundScaled; Qt::AspectRatioMode mBackgroundScaledMode; QCPLayer *mCurrentLayer; QCP::PlottingHints mPlottingHints; Qt::KeyboardModifier mMultiSelectModifier; QCP::SelectionRectMode mSelectionRectMode; QCPSelectionRect *mSelectionRect; bool mOpenGl; // non-property members: QList > mPaintBuffers; QPoint mMousePressPos; bool mMouseHasMoved; QPointer mMouseEventLayerable; QPointer mMouseSignalLayerable; QVariant mMouseEventLayerableDetails; QVariant mMouseSignalLayerableDetails; bool mReplotting; bool mReplotQueued; double mReplotTime, mReplotTimeAverage; int mOpenGlMultisamples; QCP::AntialiasedElements mOpenGlAntialiasedElementsBackup; bool mOpenGlCacheLabelsBackup; #ifdef QCP_OPENGL_FBO QSharedPointer mGlContext; QSharedPointer mGlSurface; QSharedPointer mGlPaintDevice; #endif // reimplemented virtual methods: virtual QSize minimumSizeHint() const Q_DECL_OVERRIDE; virtual QSize sizeHint() const Q_DECL_OVERRIDE; virtual void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; virtual void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; virtual void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE; virtual void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; virtual void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; virtual void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; // introduced virtual methods: virtual void draw(QCPPainter *painter); virtual void updateLayout(); virtual void axisRemoved(QCPAxis *axis); virtual void legendRemoved(QCPLegend *legend); Q_SLOT virtual void processRectSelection(QRect rect, QMouseEvent *event); Q_SLOT virtual void processRectZoom(QRect rect, QMouseEvent *event); Q_SLOT virtual void processPointSelection(QMouseEvent *event); // non-virtual methods: bool registerPlottable(QCPAbstractPlottable *plottable); bool registerGraph(QCPGraph *graph); bool registerItem(QCPAbstractItem* item); void updateLayerIndices() const; QCPLayerable *layerableAt(const QPointF &pos, bool onlySelectable, QVariant *selectionDetails=nullptr) const; QList layerableListAt(const QPointF &pos, bool onlySelectable, QList *selectionDetails=nullptr) const; void drawBackground(QCPPainter *painter); void setupPaintBuffers(); QCPAbstractPaintBuffer *createPaintBuffer(); bool hasInvalidatedPaintBuffers(); bool setupOpenGl(); void freeOpenGl(); friend class QCPLegend; friend class QCPAxis; friend class QCPLayer; friend class QCPAxisRect; friend class QCPAbstractPlottable; friend class QCPGraph; friend class QCPAbstractItem; }; Q_DECLARE_METATYPE(QCustomPlot::LayerInsertMode) Q_DECLARE_METATYPE(QCustomPlot::RefreshPriority) // implementation of template functions: /*! Returns the plottable at the pixel position \a pos. The plottable type (a QCPAbstractPlottable subclass) that shall be taken into consideration can be specified via the template parameter. Plottables that only consist of single lines (like graphs) have a tolerance band around them, see \ref setSelectionTolerance. If multiple plottables come into consideration, the one closest to \a pos is returned. If \a onlySelectable is true, only plottables that are selectable (QCPAbstractPlottable::setSelectable) are considered. if \a dataIndex is non-null, it is set to the index of the plottable's data point that is closest to \a pos. If there is no plottable of the specified type at \a pos, returns \c nullptr. \see itemAt, layoutElementAt */ template PlottableType *QCustomPlot::plottableAt(const QPointF &pos, bool onlySelectable, int *dataIndex) const { PlottableType *resultPlottable = 0; QVariant resultDetails; double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value foreach (QCPAbstractPlottable *plottable, mPlottables) { PlottableType *currentPlottable = qobject_cast(plottable); if (!currentPlottable || (onlySelectable && !currentPlottable->selectable())) // we could have also passed onlySelectable to the selectTest function, but checking here is faster, because we have access to QCPAbstractPlottable::selectable continue; if (currentPlottable->clipRect().contains(pos.toPoint())) // only consider clicks where the plottable is actually visible { QVariant details; double currentDistance = currentPlottable->selectTest(pos, false, dataIndex ? &details : nullptr); if (currentDistance >= 0 && currentDistance < resultDistance) { resultPlottable = currentPlottable; resultDetails = details; resultDistance = currentDistance; } } } if (resultPlottable && dataIndex) { QCPDataSelection sel = resultDetails.value(); if (!sel.isEmpty()) *dataIndex = sel.dataRange(0).begin(); } return resultPlottable; } /*! Returns the item at the pixel position \a pos. The item type (a QCPAbstractItem subclass) that shall be taken into consideration can be specified via the template parameter. Items that only consist of single lines (e.g. \ref QCPItemLine or \ref QCPItemCurve) have a tolerance band around them, see \ref setSelectionTolerance. If multiple items come into consideration, the one closest to \a pos is returned. If \a onlySelectable is true, only items that are selectable (QCPAbstractItem::setSelectable) are considered. If there is no item at \a pos, returns \c nullptr. \see plottableAt, layoutElementAt */ template ItemType *QCustomPlot::itemAt(const QPointF &pos, bool onlySelectable) const { ItemType *resultItem = 0; double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value foreach (QCPAbstractItem *item, mItems) { ItemType *currentItem = qobject_cast(item); if (!currentItem || (onlySelectable && !currentItem->selectable())) // we could have also passed onlySelectable to the selectTest function, but checking here is faster, because we have access to QCPAbstractItem::selectable continue; if (!currentItem->clipToAxisRect() || currentItem->clipRect().contains(pos.toPoint())) // only consider clicks inside axis cliprect of the item if actually clipped to it { double currentDistance = currentItem->selectTest(pos, false); if (currentDistance >= 0 && currentDistance < resultDistance) { resultItem = currentItem; resultDistance = currentDistance; } } } return resultItem; } /* end of 'src/core.h' */ /* including file 'src/plottable1d.h' */ /* modified 2021-03-29T02:30:44, size 25638 */ class QCPPlottableInterface1D { public: virtual ~QCPPlottableInterface1D() = default; // introduced pure virtual methods: virtual int dataCount() const = 0; virtual double dataMainKey(int index) const = 0; virtual double dataSortKey(int index) const = 0; virtual double dataMainValue(int index) const = 0; virtual QCPRange dataValueRange(int index) const = 0; virtual QPointF dataPixelPosition(int index) const = 0; virtual bool sortKeyIsMainKey() const = 0; virtual QCPDataSelection selectTestRect(const QRectF &rect, bool onlySelectable) const = 0; virtual int findBegin(double sortKey, bool expandedRange=true) const = 0; virtual int findEnd(double sortKey, bool expandedRange=true) const = 0; }; template class QCPAbstractPlottable1D : public QCPAbstractPlottable, public QCPPlottableInterface1D // no QCP_LIB_DECL, template class ends up in header (cpp included below) { // No Q_OBJECT macro due to template class public: QCPAbstractPlottable1D(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPAbstractPlottable1D() Q_DECL_OVERRIDE; // virtual methods of 1d plottable interface: virtual int dataCount() const Q_DECL_OVERRIDE; virtual double dataMainKey(int index) const Q_DECL_OVERRIDE; virtual double dataSortKey(int index) const Q_DECL_OVERRIDE; virtual double dataMainValue(int index) const Q_DECL_OVERRIDE; virtual QCPRange dataValueRange(int index) const Q_DECL_OVERRIDE; virtual QPointF dataPixelPosition(int index) const Q_DECL_OVERRIDE; virtual bool sortKeyIsMainKey() const Q_DECL_OVERRIDE; virtual QCPDataSelection selectTestRect(const QRectF &rect, bool onlySelectable) const Q_DECL_OVERRIDE; virtual int findBegin(double sortKey, bool expandedRange=true) const Q_DECL_OVERRIDE; virtual int findEnd(double sortKey, bool expandedRange=true) const Q_DECL_OVERRIDE; // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; virtual QCPPlottableInterface1D *interface1D() Q_DECL_OVERRIDE { return this; } protected: // property members: QSharedPointer > mDataContainer; // helpers for subclasses: void getDataSegments(QList &selectedSegments, QList &unselectedSegments) const; void drawPolyline(QCPPainter *painter, const QVector &lineData) const; private: Q_DISABLE_COPY(QCPAbstractPlottable1D) }; // include implementation in header since it is a class template: //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPPlottableInterface1D //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPPlottableInterface1D \brief Defines an abstract interface for one-dimensional plottables This class contains only pure virtual methods which define a common interface to the data of one-dimensional plottables. For example, it is implemented by the template class \ref QCPAbstractPlottable1D (the preferred base class for one-dimensional plottables). So if you use that template class as base class of your one-dimensional plottable, you won't have to care about implementing the 1d interface yourself. If your plottable doesn't derive from \ref QCPAbstractPlottable1D but still wants to provide a 1d interface (e.g. like \ref QCPErrorBars does), you should inherit from both \ref QCPAbstractPlottable and \ref QCPPlottableInterface1D and accordingly reimplement the pure virtual methods of the 1d interface, matching your data container. Also, reimplement \ref QCPAbstractPlottable::interface1D to return the \c this pointer. If you have a \ref QCPAbstractPlottable pointer, you can check whether it implements this interface by calling \ref QCPAbstractPlottable::interface1D and testing it for a non-zero return value. If it indeed implements this interface, you may use it to access the plottable's data without needing to know the exact type of the plottable or its data point type. */ /* start documentation of pure virtual functions */ /*! \fn virtual int QCPPlottableInterface1D::dataCount() const = 0; Returns the number of data points of the plottable. */ /*! \fn virtual QCPDataSelection QCPPlottableInterface1D::selectTestRect(const QRectF &rect, bool onlySelectable) const = 0; Returns a data selection containing all the data points of this plottable which are contained (or hit by) \a rect. This is used mainly in the selection rect interaction for data selection (\ref dataselection "data selection mechanism"). If \a onlySelectable is true, an empty QCPDataSelection is returned if this plottable is not selectable (i.e. if \ref QCPAbstractPlottable::setSelectable is \ref QCP::stNone). \note \a rect must be a normalized rect (positive or zero width and height). This is especially important when using the rect of \ref QCPSelectionRect::accepted, which is not necessarily normalized. Use QRect::normalized() when passing a rect which might not be normalized. */ /*! \fn virtual double QCPPlottableInterface1D::dataMainKey(int index) const = 0 Returns the main key of the data point at the given \a index. What the main key is, is defined by the plottable's data type. See the \ref qcpdatacontainer-datatype "QCPDataContainer DataType" documentation for details about this naming convention. */ /*! \fn virtual double QCPPlottableInterface1D::dataSortKey(int index) const = 0 Returns the sort key of the data point at the given \a index. What the sort key is, is defined by the plottable's data type. See the \ref qcpdatacontainer-datatype "QCPDataContainer DataType" documentation for details about this naming convention. */ /*! \fn virtual double QCPPlottableInterface1D::dataMainValue(int index) const = 0 Returns the main value of the data point at the given \a index. What the main value is, is defined by the plottable's data type. See the \ref qcpdatacontainer-datatype "QCPDataContainer DataType" documentation for details about this naming convention. */ /*! \fn virtual QCPRange QCPPlottableInterface1D::dataValueRange(int index) const = 0 Returns the value range of the data point at the given \a index. What the value range is, is defined by the plottable's data type. See the \ref qcpdatacontainer-datatype "QCPDataContainer DataType" documentation for details about this naming convention. */ /*! \fn virtual QPointF QCPPlottableInterface1D::dataPixelPosition(int index) const = 0 Returns the pixel position on the widget surface at which the data point at the given \a index appears. Usually this corresponds to the point of \ref dataMainKey/\ref dataMainValue, in pixel coordinates. However, depending on the plottable, this might be a different apparent position than just a coord-to-pixel transform of those values. For example, \ref QCPBars apparent data values can be shifted depending on their stacking, bar grouping or configured base value. */ /*! \fn virtual bool QCPPlottableInterface1D::sortKeyIsMainKey() const = 0 Returns whether the sort key (\ref dataSortKey) is identical to the main key (\ref dataMainKey). What the sort and main keys are, is defined by the plottable's data type. See the \ref qcpdatacontainer-datatype "QCPDataContainer DataType" documentation for details about this naming convention. */ /*! \fn virtual int QCPPlottableInterface1D::findBegin(double sortKey, bool expandedRange) const = 0 Returns the index of the data point with a (sort-)key that is equal to, just below, or just above \a sortKey. If \a expandedRange is true, the data point just below \a sortKey will be considered, otherwise the one just above. This can be used in conjunction with \ref findEnd to iterate over data points within a given key range, including or excluding the bounding data points that are just beyond the specified range. If \a expandedRange is true but there are no data points below \a sortKey, 0 is returned. If the container is empty, returns 0 (in that case, \ref findEnd will also return 0, so a loop using these methods will not iterate over the index 0). \see findEnd, QCPDataContainer::findBegin */ /*! \fn virtual int QCPPlottableInterface1D::findEnd(double sortKey, bool expandedRange) const = 0 Returns the index one after the data point with a (sort-)key that is equal to, just above, or just below \a sortKey. If \a expandedRange is true, the data point just above \a sortKey will be considered, otherwise the one just below. This can be used in conjunction with \ref findBegin to iterate over data points within a given key range, including the bounding data points that are just below and above the specified range. If \a expandedRange is true but there are no data points above \a sortKey, the index just above the highest data point is returned. If the container is empty, returns 0. \see findBegin, QCPDataContainer::findEnd */ /* end documentation of pure virtual functions */ //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// QCPAbstractPlottable1D //////////////////////////////////////////////////////////////////////////////////////////////////// /*! \class QCPAbstractPlottable1D \brief A template base class for plottables with one-dimensional data This template class derives from \ref QCPAbstractPlottable and from the abstract interface \ref QCPPlottableInterface1D. It serves as a base class for all one-dimensional data (i.e. data with one key dimension), such as \ref QCPGraph and QCPCurve. The template parameter \a DataType is the type of the data points of this plottable (e.g. \ref QCPGraphData or \ref QCPCurveData). The main purpose of this base class is to provide the member \a mDataContainer (a shared pointer to a \ref QCPDataContainer "QCPDataContainer") and implement the according virtual methods of the \ref QCPPlottableInterface1D, such that most subclassed plottables don't need to worry about this anymore. Further, it provides a convenience method for retrieving selected/unselected data segments via \ref getDataSegments. This is useful when subclasses implement their \ref draw method and need to draw selected segments with a different pen/brush than unselected segments (also see \ref QCPSelectionDecorator). This class implements basic functionality of \ref QCPAbstractPlottable::selectTest and \ref QCPPlottableInterface1D::selectTestRect, assuming point-like data points, based on the 1D data interface. In spite of that, most plottable subclasses will want to reimplement those methods again, to provide a more accurate hit test based on their specific data visualization geometry. */ /* start documentation of inline functions */ /*! \fn QCPPlottableInterface1D *QCPAbstractPlottable1D::interface1D() Returns a \ref QCPPlottableInterface1D pointer to this plottable, providing access to its 1D interface. \seebaseclassmethod */ /* end documentation of inline functions */ /*! Forwards \a keyAxis and \a valueAxis to the \ref QCPAbstractPlottable::QCPAbstractPlottable "QCPAbstractPlottable" constructor and allocates the \a mDataContainer. */ template QCPAbstractPlottable1D::QCPAbstractPlottable1D(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable(keyAxis, valueAxis), mDataContainer(new QCPDataContainer) { } template QCPAbstractPlottable1D::~QCPAbstractPlottable1D() { } /*! \copydoc QCPPlottableInterface1D::dataCount */ template int QCPAbstractPlottable1D::dataCount() const { return mDataContainer->size(); } /*! \copydoc QCPPlottableInterface1D::dataMainKey */ template double QCPAbstractPlottable1D::dataMainKey(int index) const { if (index >= 0 && index < mDataContainer->size()) { return (mDataContainer->constBegin()+index)->mainKey(); } else { qDebug() << Q_FUNC_INFO << "Index out of bounds" << index; return 0; } } /*! \copydoc QCPPlottableInterface1D::dataSortKey */ template double QCPAbstractPlottable1D::dataSortKey(int index) const { if (index >= 0 && index < mDataContainer->size()) { return (mDataContainer->constBegin()+index)->sortKey(); } else { qDebug() << Q_FUNC_INFO << "Index out of bounds" << index; return 0; } } /*! \copydoc QCPPlottableInterface1D::dataMainValue */ template double QCPAbstractPlottable1D::dataMainValue(int index) const { if (index >= 0 && index < mDataContainer->size()) { return (mDataContainer->constBegin()+index)->mainValue(); } else { qDebug() << Q_FUNC_INFO << "Index out of bounds" << index; return 0; } } /*! \copydoc QCPPlottableInterface1D::dataValueRange */ template QCPRange QCPAbstractPlottable1D::dataValueRange(int index) const { if (index >= 0 && index < mDataContainer->size()) { return (mDataContainer->constBegin()+index)->valueRange(); } else { qDebug() << Q_FUNC_INFO << "Index out of bounds" << index; return QCPRange(0, 0); } } /*! \copydoc QCPPlottableInterface1D::dataPixelPosition */ template QPointF QCPAbstractPlottable1D::dataPixelPosition(int index) const { if (index >= 0 && index < mDataContainer->size()) { const typename QCPDataContainer::const_iterator it = mDataContainer->constBegin()+index; return coordsToPixels(it->mainKey(), it->mainValue()); } else { qDebug() << Q_FUNC_INFO << "Index out of bounds" << index; return QPointF(); } } /*! \copydoc QCPPlottableInterface1D::sortKeyIsMainKey */ template bool QCPAbstractPlottable1D::sortKeyIsMainKey() const { return DataType::sortKeyIsMainKey(); } /*! Implements a rect-selection algorithm assuming the data (accessed via the 1D data interface) is point-like. Most subclasses will want to reimplement this method again, to provide a more accurate hit test based on the true data visualization geometry. \seebaseclassmethod */ template QCPDataSelection QCPAbstractPlottable1D::selectTestRect(const QRectF &rect, bool onlySelectable) const { QCPDataSelection result; if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return result; if (!mKeyAxis || !mValueAxis) return result; // convert rect given in pixels to ranges given in plot coordinates: double key1, value1, key2, value2; pixelsToCoords(rect.topLeft(), key1, value1); pixelsToCoords(rect.bottomRight(), key2, value2); QCPRange keyRange(key1, key2); // QCPRange normalizes internally so we don't have to care about whether key1 < key2 QCPRange valueRange(value1, value2); typename QCPDataContainer::const_iterator begin = mDataContainer->constBegin(); typename QCPDataContainer::const_iterator end = mDataContainer->constEnd(); if (DataType::sortKeyIsMainKey()) // we can assume that data is sorted by main key, so can reduce the searched key interval: { begin = mDataContainer->findBegin(keyRange.lower, false); end = mDataContainer->findEnd(keyRange.upper, false); } if (begin == end) return result; int currentSegmentBegin = -1; // -1 means we're currently not in a segment that's contained in rect for (typename QCPDataContainer::const_iterator it=begin; it!=end; ++it) { if (currentSegmentBegin == -1) { if (valueRange.contains(it->mainValue()) && keyRange.contains(it->mainKey())) // start segment currentSegmentBegin = int(it-mDataContainer->constBegin()); } else if (!valueRange.contains(it->mainValue()) || !keyRange.contains(it->mainKey())) // segment just ended { result.addDataRange(QCPDataRange(currentSegmentBegin, int(it-mDataContainer->constBegin())), false); currentSegmentBegin = -1; } } // process potential last segment: if (currentSegmentBegin != -1) result.addDataRange(QCPDataRange(currentSegmentBegin, int(end-mDataContainer->constBegin())), false); result.simplify(); return result; } /*! \copydoc QCPPlottableInterface1D::findBegin */ template int QCPAbstractPlottable1D::findBegin(double sortKey, bool expandedRange) const { return int(mDataContainer->findBegin(sortKey, expandedRange)-mDataContainer->constBegin()); } /*! \copydoc QCPPlottableInterface1D::findEnd */ template int QCPAbstractPlottable1D::findEnd(double sortKey, bool expandedRange) const { return int(mDataContainer->findEnd(sortKey, expandedRange)-mDataContainer->constBegin()); } /*! Implements a point-selection algorithm assuming the data (accessed via the 1D data interface) is point-like. Most subclasses will want to reimplement this method again, to provide a more accurate hit test based on the true data visualization geometry. If \a details is not 0, it will be set to a \ref QCPDataSelection, describing the closest data point to \a pos. \seebaseclassmethod */ template double QCPAbstractPlottable1D::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const { if ((onlySelectable && mSelectable == QCP::stNone) || mDataContainer->isEmpty()) return -1; if (!mKeyAxis || !mValueAxis) return -1; QCPDataSelection selectionResult; double minDistSqr = (std::numeric_limits::max)(); int minDistIndex = mDataContainer->size(); typename QCPDataContainer::const_iterator begin = mDataContainer->constBegin(); typename QCPDataContainer::const_iterator end = mDataContainer->constEnd(); if (DataType::sortKeyIsMainKey()) // we can assume that data is sorted by main key, so can reduce the searched key interval: { // determine which key range comes into question, taking selection tolerance around pos into account: double posKeyMin, posKeyMax, dummy; pixelsToCoords(pos-QPointF(mParentPlot->selectionTolerance(), mParentPlot->selectionTolerance()), posKeyMin, dummy); pixelsToCoords(pos+QPointF(mParentPlot->selectionTolerance(), mParentPlot->selectionTolerance()), posKeyMax, dummy); if (posKeyMin > posKeyMax) qSwap(posKeyMin, posKeyMax); begin = mDataContainer->findBegin(posKeyMin, true); end = mDataContainer->findEnd(posKeyMax, true); } if (begin == end) return -1; QCPRange keyRange(mKeyAxis->range()); QCPRange valueRange(mValueAxis->range()); for (typename QCPDataContainer::const_iterator it=begin; it!=end; ++it) { const double mainKey = it->mainKey(); const double mainValue = it->mainValue(); if (keyRange.contains(mainKey) && valueRange.contains(mainValue)) // make sure data point is inside visible range, for speedup in cases where sort key isn't main key and we iterate over all points { const double currentDistSqr = QCPVector2D(coordsToPixels(mainKey, mainValue)-pos).lengthSquared(); if (currentDistSqr < minDistSqr) { minDistSqr = currentDistSqr; minDistIndex = int(it-mDataContainer->constBegin()); } } } if (minDistIndex != mDataContainer->size()) selectionResult.addDataRange(QCPDataRange(minDistIndex, minDistIndex+1), false); selectionResult.simplify(); if (details) details->setValue(selectionResult); return qSqrt(minDistSqr); } /*! Splits all data into selected and unselected segments and outputs them via \a selectedSegments and \a unselectedSegments, respectively. This is useful when subclasses implement their \ref draw method and need to draw selected segments with a different pen/brush than unselected segments (also see \ref QCPSelectionDecorator). \see setSelection */ template void QCPAbstractPlottable1D::getDataSegments(QList &selectedSegments, QList &unselectedSegments) const { selectedSegments.clear(); unselectedSegments.clear(); if (mSelectable == QCP::stWhole) // stWhole selection type draws the entire plottable with selected style if mSelection isn't empty { if (selected()) selectedSegments << QCPDataRange(0, dataCount()); else unselectedSegments << QCPDataRange(0, dataCount()); } else { QCPDataSelection sel(selection()); sel.simplify(); selectedSegments = sel.dataRanges(); unselectedSegments = sel.inverse(QCPDataRange(0, dataCount())).dataRanges(); } } /*! A helper method which draws a line with the passed \a painter, according to the pixel data in \a lineData. NaN points create gaps in the line, as expected from QCustomPlot's plottables (this is the main difference to QPainter's regular drawPolyline, which handles NaNs by lagging or crashing). Further it uses a faster line drawing technique based on \ref QCPPainter::drawLine rather than \c QPainter::drawPolyline if the configured \ref QCustomPlot::setPlottingHints() and \a painter style allows. */ template void QCPAbstractPlottable1D::drawPolyline(QCPPainter *painter, const QVector &lineData) const { // if drawing lines in plot (instead of PDF), reduce 1px lines to cosmetic, because at least in // Qt6 drawing of "1px" width lines is much slower even though it has same appearance apart from // High-DPI. In High-DPI cases people must set a pen width slightly larger than 1.0 to get // correct DPI scaling of width, but of course with performance penalty. if (!painter->modes().testFlag(QCPPainter::pmVectorized) && qFuzzyCompare(painter->pen().widthF(), 1.0)) { QPen newPen = painter->pen(); newPen.setWidth(0); painter->setPen(newPen); } // if drawing solid line and not in PDF, use much faster line drawing instead of polyline: if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) && painter->pen().style() == Qt::SolidLine && !painter->modes().testFlag(QCPPainter::pmVectorized) && !painter->modes().testFlag(QCPPainter::pmNoCaching)) { int i = 0; bool lastIsNan = false; const int lineDataSize = lineData.size(); while (i < lineDataSize && (qIsNaN(lineData.at(i).y()) || qIsNaN(lineData.at(i).x()))) // make sure first point is not NaN ++i; ++i; // because drawing works in 1 point retrospect while (i < lineDataSize) { if (!qIsNaN(lineData.at(i).y()) && !qIsNaN(lineData.at(i).x())) // NaNs create a gap in the line { if (!lastIsNan) painter->drawLine(lineData.at(i-1), lineData.at(i)); else lastIsNan = false; } else lastIsNan = true; ++i; } } else { int segmentStart = 0; int i = 0; const int lineDataSize = lineData.size(); while (i < lineDataSize) { if (qIsNaN(lineData.at(i).y()) || qIsNaN(lineData.at(i).x()) || qIsInf(lineData.at(i).y())) // NaNs create a gap in the line. Also filter Infs which make drawPolyline block { painter->drawPolyline(lineData.constData()+segmentStart, i-segmentStart); // i, because we don't want to include the current NaN point segmentStart = i+1; } ++i; } // draw last segment: painter->drawPolyline(lineData.constData()+segmentStart, lineDataSize-segmentStart); } } /* end of 'src/plottable1d.h' */ /* including file 'src/colorgradient.h' */ /* modified 2021-03-29T02:30:44, size 7262 */ class QCP_LIB_DECL QCPColorGradient { Q_GADGET public: /*! Defines the color spaces in which color interpolation between gradient stops can be performed. \see setColorInterpolation */ enum ColorInterpolation { ciRGB ///< Color channels red, green and blue are linearly interpolated ,ciHSV ///< Color channels hue, saturation and value are linearly interpolated (The hue is interpolated over the shortest angle distance) }; Q_ENUMS(ColorInterpolation) /*! Defines how NaN data points shall appear in the plot. \see setNanHandling, setNanColor */ enum NanHandling { nhNone ///< NaN data points are not explicitly handled and shouldn't occur in the data (this gives slight performance improvement) ,nhLowestColor ///< NaN data points appear as the lowest color defined in this QCPColorGradient ,nhHighestColor ///< NaN data points appear as the highest color defined in this QCPColorGradient ,nhTransparent ///< NaN data points appear transparent ,nhNanColor ///< NaN data points appear as the color defined with \ref setNanColor }; Q_ENUMS(NanHandling) /*! Defines the available presets that can be loaded with \ref loadPreset. See the documentation there for an image of the presets. */ enum GradientPreset { gpGrayscale ///< Continuous lightness from black to white (suited for non-biased data representation) ,gpHot ///< Continuous lightness from black over firey colors to white (suited for non-biased data representation) ,gpCold ///< Continuous lightness from black over icey colors to white (suited for non-biased data representation) ,gpNight ///< Continuous lightness from black over weak blueish colors to white (suited for non-biased data representation) ,gpCandy ///< Blue over pink to white ,gpGeography ///< Colors suitable to represent different elevations on geographical maps ,gpIon ///< Half hue spectrum from black over purple to blue and finally green (creates banding illusion but allows more precise magnitude estimates) ,gpThermal ///< Colors suitable for thermal imaging, ranging from dark blue over purple to orange, yellow and white ,gpPolar ///< Colors suitable to emphasize polarity around the center, with blue for negative, black in the middle and red for positive values ,gpSpectrum ///< An approximation of the visible light spectrum (creates banding illusion but allows more precise magnitude estimates) ,gpJet ///< Hue variation similar to a spectrum, often used in numerical visualization (creates banding illusion but allows more precise magnitude estimates) ,gpHues ///< Full hue cycle, with highest and lowest color red (suitable for periodic data, such as angles and phases, see \ref setPeriodic) }; Q_ENUMS(GradientPreset) QCPColorGradient(); QCPColorGradient(GradientPreset preset); bool operator==(const QCPColorGradient &other) const; bool operator!=(const QCPColorGradient &other) const { return !(*this == other); } // getters: int levelCount() const { return mLevelCount; } QMap colorStops() const { return mColorStops; } ColorInterpolation colorInterpolation() const { return mColorInterpolation; } NanHandling nanHandling() const { return mNanHandling; } QColor nanColor() const { return mNanColor; } bool periodic() const { return mPeriodic; } // setters: void setLevelCount(int n); void setColorStops(const QMap &colorStops); void setColorStopAt(double position, const QColor &color); void setColorInterpolation(ColorInterpolation interpolation); void setNanHandling(NanHandling handling); void setNanColor(const QColor &color); void setPeriodic(bool enabled); // non-property methods: void colorize(const double *data, const QCPRange &range, QRgb *scanLine, int n, int dataIndexFactor=1, bool logarithmic=false); void colorize(const double *data, const unsigned char *alpha, const QCPRange &range, QRgb *scanLine, int n, int dataIndexFactor=1, bool logarithmic=false); QRgb color(double position, const QCPRange &range, bool logarithmic=false); void loadPreset(GradientPreset preset); void clearColorStops(); QCPColorGradient inverted() const; protected: // property members: int mLevelCount; QMap mColorStops; ColorInterpolation mColorInterpolation; NanHandling mNanHandling; QColor mNanColor; bool mPeriodic; // non-property members: QVector mColorBuffer; // have colors premultiplied with alpha (for usage with QImage::Format_ARGB32_Premultiplied) bool mColorBufferInvalidated; // non-virtual methods: bool stopsUseAlpha() const; void updateColorBuffer(); }; Q_DECLARE_METATYPE(QCPColorGradient::ColorInterpolation) Q_DECLARE_METATYPE(QCPColorGradient::NanHandling) Q_DECLARE_METATYPE(QCPColorGradient::GradientPreset) /* end of 'src/colorgradient.h' */ /* including file 'src/selectiondecorator-bracket.h' */ /* modified 2021-03-29T02:30:44, size 4458 */ class QCP_LIB_DECL QCPSelectionDecoratorBracket : public QCPSelectionDecorator { Q_GADGET public: /*! Defines which shape is drawn at the boundaries of selected data ranges. Some of the bracket styles further allow specifying a height and/or width, see \ref setBracketHeight and \ref setBracketWidth. */ enum BracketStyle { bsSquareBracket ///< A square bracket is drawn. ,bsHalfEllipse ///< A half ellipse is drawn. The size of the ellipse is given by the bracket width/height properties. ,bsEllipse ///< An ellipse is drawn. The size of the ellipse is given by the bracket width/height properties. ,bsPlus ///< A plus is drawn. ,bsUserStyle ///< Start custom bracket styles at this index when subclassing and reimplementing \ref drawBracket. }; Q_ENUMS(BracketStyle) QCPSelectionDecoratorBracket(); virtual ~QCPSelectionDecoratorBracket() Q_DECL_OVERRIDE; // getters: QPen bracketPen() const { return mBracketPen; } QBrush bracketBrush() const { return mBracketBrush; } int bracketWidth() const { return mBracketWidth; } int bracketHeight() const { return mBracketHeight; } BracketStyle bracketStyle() const { return mBracketStyle; } bool tangentToData() const { return mTangentToData; } int tangentAverage() const { return mTangentAverage; } // setters: void setBracketPen(const QPen &pen); void setBracketBrush(const QBrush &brush); void setBracketWidth(int width); void setBracketHeight(int height); void setBracketStyle(BracketStyle style); void setTangentToData(bool enabled); void setTangentAverage(int pointCount); // introduced virtual methods: virtual void drawBracket(QCPPainter *painter, int direction) const; // virtual methods: virtual void drawDecoration(QCPPainter *painter, QCPDataSelection selection) Q_DECL_OVERRIDE; protected: // property members: QPen mBracketPen; QBrush mBracketBrush; int mBracketWidth; int mBracketHeight; BracketStyle mBracketStyle; bool mTangentToData; int mTangentAverage; // non-virtual methods: double getTangentAngle(const QCPPlottableInterface1D *interface1d, int dataIndex, int direction) const; QPointF getPixelCoordinates(const QCPPlottableInterface1D *interface1d, int dataIndex) const; }; Q_DECLARE_METATYPE(QCPSelectionDecoratorBracket::BracketStyle) /* end of 'src/selectiondecorator-bracket.h' */ /* including file 'src/layoutelements/layoutelement-axisrect.h' */ /* modified 2021-03-29T02:30:44, size 7529 */ class QCP_LIB_DECL QCPAxisRect : public QCPLayoutElement { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPixmap background READ background WRITE setBackground) Q_PROPERTY(bool backgroundScaled READ backgroundScaled WRITE setBackgroundScaled) Q_PROPERTY(Qt::AspectRatioMode backgroundScaledMode READ backgroundScaledMode WRITE setBackgroundScaledMode) Q_PROPERTY(Qt::Orientations rangeDrag READ rangeDrag WRITE setRangeDrag) Q_PROPERTY(Qt::Orientations rangeZoom READ rangeZoom WRITE setRangeZoom) /// \endcond public: explicit QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes=true); virtual ~QCPAxisRect() Q_DECL_OVERRIDE; // getters: QPixmap background() const { return mBackgroundPixmap; } QBrush backgroundBrush() const { return mBackgroundBrush; } bool backgroundScaled() const { return mBackgroundScaled; } Qt::AspectRatioMode backgroundScaledMode() const { return mBackgroundScaledMode; } Qt::Orientations rangeDrag() const { return mRangeDrag; } Qt::Orientations rangeZoom() const { return mRangeZoom; } QCPAxis *rangeDragAxis(Qt::Orientation orientation); QCPAxis *rangeZoomAxis(Qt::Orientation orientation); QList rangeDragAxes(Qt::Orientation orientation); QList rangeZoomAxes(Qt::Orientation orientation); double rangeZoomFactor(Qt::Orientation orientation); // setters: void setBackground(const QPixmap &pm); void setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode=Qt::KeepAspectRatioByExpanding); void setBackground(const QBrush &brush); void setBackgroundScaled(bool scaled); void setBackgroundScaledMode(Qt::AspectRatioMode mode); void setRangeDrag(Qt::Orientations orientations); void setRangeZoom(Qt::Orientations orientations); void setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical); void setRangeDragAxes(QList axes); void setRangeDragAxes(QList horizontal, QList vertical); void setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical); void setRangeZoomAxes(QList axes); void setRangeZoomAxes(QList horizontal, QList vertical); void setRangeZoomFactor(double horizontalFactor, double verticalFactor); void setRangeZoomFactor(double factor); // non-property methods: int axisCount(QCPAxis::AxisType type) const; QCPAxis *axis(QCPAxis::AxisType type, int index=0) const; QList axes(QCPAxis::AxisTypes types) const; QList axes() const; QCPAxis *addAxis(QCPAxis::AxisType type, QCPAxis *axis=nullptr); QList addAxes(QCPAxis::AxisTypes types); bool removeAxis(QCPAxis *axis); QCPLayoutInset *insetLayout() const { return mInsetLayout; } void zoom(const QRectF &pixelRect); void zoom(const QRectF &pixelRect, const QList &affectedAxes); void setupFullAxesBox(bool connectRanges=false); QList plottables() const; QList graphs() const; QList items() const; // read-only interface imitating a QRect: int left() const { return mRect.left(); } int right() const { return mRect.right(); } int top() const { return mRect.top(); } int bottom() const { return mRect.bottom(); } int width() const { return mRect.width(); } int height() const { return mRect.height(); } QSize size() const { return mRect.size(); } QPoint topLeft() const { return mRect.topLeft(); } QPoint topRight() const { return mRect.topRight(); } QPoint bottomLeft() const { return mRect.bottomLeft(); } QPoint bottomRight() const { return mRect.bottomRight(); } QPoint center() const { return mRect.center(); } // reimplemented virtual methods: virtual void update(UpdatePhase phase) Q_DECL_OVERRIDE; virtual QList elements(bool recursive) const Q_DECL_OVERRIDE; protected: // property members: QBrush mBackgroundBrush; QPixmap mBackgroundPixmap; QPixmap mScaledBackgroundPixmap; bool mBackgroundScaled; Qt::AspectRatioMode mBackgroundScaledMode; QCPLayoutInset *mInsetLayout; Qt::Orientations mRangeDrag, mRangeZoom; QList > mRangeDragHorzAxis, mRangeDragVertAxis; QList > mRangeZoomHorzAxis, mRangeZoomVertAxis; double mRangeZoomFactorHorz, mRangeZoomFactorVert; // non-property members: QList mDragStartHorzRange, mDragStartVertRange; QCP::AntialiasedElements mAADragBackup, mNotAADragBackup; bool mDragging; QHash > mAxes; // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual int calculateAutoMargin(QCP::MarginSide side) Q_DECL_OVERRIDE; virtual void layoutChanged() Q_DECL_OVERRIDE; // events: virtual void mousePressEvent(QMouseEvent *event, const QVariant &details) Q_DECL_OVERRIDE; virtual void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; // non-property methods: void drawBackground(QCPPainter *painter); void updateAxesOffset(QCPAxis::AxisType type); private: Q_DISABLE_COPY(QCPAxisRect) friend class QCustomPlot; }; /* end of 'src/layoutelements/layoutelement-axisrect.h' */ /* including file 'src/layoutelements/layoutelement-legend.h' */ /* modified 2021-03-29T02:30:44, size 10425 */ class QCP_LIB_DECL QCPAbstractLegendItem : public QCPLayoutElement { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QCPLegend* parentLegend READ parentLegend) Q_PROPERTY(QFont font READ font WRITE setFont) Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor) Q_PROPERTY(QFont selectedFont READ selectedFont WRITE setSelectedFont) Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor) Q_PROPERTY(bool selectable READ selectable WRITE setSelectable NOTIFY selectionChanged) Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectableChanged) /// \endcond public: explicit QCPAbstractLegendItem(QCPLegend *parent); // getters: QCPLegend *parentLegend() const { return mParentLegend; } QFont font() const { return mFont; } QColor textColor() const { return mTextColor; } QFont selectedFont() const { return mSelectedFont; } QColor selectedTextColor() const { return mSelectedTextColor; } bool selectable() const { return mSelectable; } bool selected() const { return mSelected; } // setters: void setFont(const QFont &font); void setTextColor(const QColor &color); void setSelectedFont(const QFont &font); void setSelectedTextColor(const QColor &color); Q_SLOT void setSelectable(bool selectable); Q_SLOT void setSelected(bool selected); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; signals: void selectionChanged(bool selected); void selectableChanged(bool selectable); protected: // property members: QCPLegend *mParentLegend; QFont mFont; QColor mTextColor; QFont mSelectedFont; QColor mSelectedTextColor; bool mSelectable, mSelected; // reimplemented virtual methods: virtual QCP::Interaction selectionCategory() const Q_DECL_OVERRIDE; virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual QRect clipRect() const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE = 0; // events: virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) Q_DECL_OVERRIDE; virtual void deselectEvent(bool *selectionStateChanged) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QCPAbstractLegendItem) friend class QCPLegend; }; class QCP_LIB_DECL QCPPlottableLegendItem : public QCPAbstractLegendItem { Q_OBJECT public: QCPPlottableLegendItem(QCPLegend *parent, QCPAbstractPlottable *plottable); // getters: QCPAbstractPlottable *plottable() { return mPlottable; } protected: // property members: QCPAbstractPlottable *mPlottable; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QSize minimumOuterSizeHint() const Q_DECL_OVERRIDE; // non-virtual methods: QPen getIconBorderPen() const; QColor getTextColor() const; QFont getFont() const; }; class QCP_LIB_DECL QCPLegend : public QCPLayoutGrid { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPen borderPen READ borderPen WRITE setBorderPen) Q_PROPERTY(QBrush brush READ brush WRITE setBrush) Q_PROPERTY(QFont font READ font WRITE setFont) Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor) Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize) Q_PROPERTY(int iconTextPadding READ iconTextPadding WRITE setIconTextPadding) Q_PROPERTY(QPen iconBorderPen READ iconBorderPen WRITE setIconBorderPen) Q_PROPERTY(SelectableParts selectableParts READ selectableParts WRITE setSelectableParts NOTIFY selectionChanged) Q_PROPERTY(SelectableParts selectedParts READ selectedParts WRITE setSelectedParts NOTIFY selectableChanged) Q_PROPERTY(QPen selectedBorderPen READ selectedBorderPen WRITE setSelectedBorderPen) Q_PROPERTY(QPen selectedIconBorderPen READ selectedIconBorderPen WRITE setSelectedIconBorderPen) Q_PROPERTY(QBrush selectedBrush READ selectedBrush WRITE setSelectedBrush) Q_PROPERTY(QFont selectedFont READ selectedFont WRITE setSelectedFont) Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor) /// \endcond public: /*! Defines the selectable parts of a legend \see setSelectedParts, setSelectableParts */ enum SelectablePart { spNone = 0x000 ///< 0x000 None ,spLegendBox = 0x001 ///< 0x001 The legend box (frame) ,spItems = 0x002 ///< 0x002 Legend items individually (see \ref selectedItems) }; Q_ENUMS(SelectablePart) Q_FLAGS(SelectableParts) Q_DECLARE_FLAGS(SelectableParts, SelectablePart) explicit QCPLegend(); virtual ~QCPLegend() Q_DECL_OVERRIDE; // getters: QPen borderPen() const { return mBorderPen; } QBrush brush() const { return mBrush; } QFont font() const { return mFont; } QColor textColor() const { return mTextColor; } QSize iconSize() const { return mIconSize; } int iconTextPadding() const { return mIconTextPadding; } QPen iconBorderPen() const { return mIconBorderPen; } SelectableParts selectableParts() const { return mSelectableParts; } SelectableParts selectedParts() const; QPen selectedBorderPen() const { return mSelectedBorderPen; } QPen selectedIconBorderPen() const { return mSelectedIconBorderPen; } QBrush selectedBrush() const { return mSelectedBrush; } QFont selectedFont() const { return mSelectedFont; } QColor selectedTextColor() const { return mSelectedTextColor; } // setters: void setBorderPen(const QPen &pen); void setBrush(const QBrush &brush); void setFont(const QFont &font); void setTextColor(const QColor &color); void setIconSize(const QSize &size); void setIconSize(int width, int height); void setIconTextPadding(int padding); void setIconBorderPen(const QPen &pen); Q_SLOT void setSelectableParts(const SelectableParts &selectableParts); Q_SLOT void setSelectedParts(const SelectableParts &selectedParts); void setSelectedBorderPen(const QPen &pen); void setSelectedIconBorderPen(const QPen &pen); void setSelectedBrush(const QBrush &brush); void setSelectedFont(const QFont &font); void setSelectedTextColor(const QColor &color); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; // non-virtual methods: QCPAbstractLegendItem *item(int index) const; QCPPlottableLegendItem *itemWithPlottable(const QCPAbstractPlottable *plottable) const; int itemCount() const; bool hasItem(QCPAbstractLegendItem *item) const; bool hasItemWithPlottable(const QCPAbstractPlottable *plottable) const; bool addItem(QCPAbstractLegendItem *item); bool removeItem(int index); bool removeItem(QCPAbstractLegendItem *item); void clearItems(); QList selectedItems() const; signals: void selectionChanged(QCPLegend::SelectableParts parts); void selectableChanged(QCPLegend::SelectableParts parts); protected: // property members: QPen mBorderPen, mIconBorderPen; QBrush mBrush; QFont mFont; QColor mTextColor; QSize mIconSize; int mIconTextPadding; SelectableParts mSelectedParts, mSelectableParts; QPen mSelectedBorderPen, mSelectedIconBorderPen; QBrush mSelectedBrush; QFont mSelectedFont; QColor mSelectedTextColor; // reimplemented virtual methods: virtual void parentPlotInitialized(QCustomPlot *parentPlot) Q_DECL_OVERRIDE; virtual QCP::Interaction selectionCategory() const Q_DECL_OVERRIDE; virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; // events: virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) Q_DECL_OVERRIDE; virtual void deselectEvent(bool *selectionStateChanged) Q_DECL_OVERRIDE; // non-virtual methods: QPen getBorderPen() const; QBrush getBrush() const; private: Q_DISABLE_COPY(QCPLegend) friend class QCustomPlot; friend class QCPAbstractLegendItem; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCPLegend::SelectableParts) Q_DECLARE_METATYPE(QCPLegend::SelectablePart) /* end of 'src/layoutelements/layoutelement-legend.h' */ /* including file 'src/layoutelements/layoutelement-textelement.h' */ /* modified 2021-03-29T02:30:44, size 5359 */ class QCP_LIB_DECL QCPTextElement : public QCPLayoutElement { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QString text READ text WRITE setText) Q_PROPERTY(QFont font READ font WRITE setFont) Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor) Q_PROPERTY(QFont selectedFont READ selectedFont WRITE setSelectedFont) Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor) Q_PROPERTY(bool selectable READ selectable WRITE setSelectable NOTIFY selectableChanged) Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectionChanged) /// \endcond public: explicit QCPTextElement(QCustomPlot *parentPlot); QCPTextElement(QCustomPlot *parentPlot, const QString &text); QCPTextElement(QCustomPlot *parentPlot, const QString &text, double pointSize); QCPTextElement(QCustomPlot *parentPlot, const QString &text, const QString &fontFamily, double pointSize); QCPTextElement(QCustomPlot *parentPlot, const QString &text, const QFont &font); // getters: QString text() const { return mText; } int textFlags() const { return mTextFlags; } QFont font() const { return mFont; } QColor textColor() const { return mTextColor; } QFont selectedFont() const { return mSelectedFont; } QColor selectedTextColor() const { return mSelectedTextColor; } bool selectable() const { return mSelectable; } bool selected() const { return mSelected; } // setters: void setText(const QString &text); void setTextFlags(int flags); void setFont(const QFont &font); void setTextColor(const QColor &color); void setSelectedFont(const QFont &font); void setSelectedTextColor(const QColor &color); Q_SLOT void setSelectable(bool selectable); Q_SLOT void setSelected(bool selected); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; virtual void mousePressEvent(QMouseEvent *event, const QVariant &details) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void mouseDoubleClickEvent(QMouseEvent *event, const QVariant &details) Q_DECL_OVERRIDE; signals: void selectionChanged(bool selected); void selectableChanged(bool selectable); void clicked(QMouseEvent *event); void doubleClicked(QMouseEvent *event); protected: // property members: QString mText; int mTextFlags; QFont mFont; QColor mTextColor; QFont mSelectedFont; QColor mSelectedTextColor; QRect mTextBoundingRect; bool mSelectable, mSelected; // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QSize minimumOuterSizeHint() const Q_DECL_OVERRIDE; virtual QSize maximumOuterSizeHint() const Q_DECL_OVERRIDE; // events: virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) Q_DECL_OVERRIDE; virtual void deselectEvent(bool *selectionStateChanged) Q_DECL_OVERRIDE; // non-virtual methods: QFont mainFont() const; QColor mainTextColor() const; private: Q_DISABLE_COPY(QCPTextElement) }; /* end of 'src/layoutelements/layoutelement-textelement.h' */ /* including file 'src/layoutelements/layoutelement-colorscale.h' */ /* modified 2021-03-29T02:30:44, size 5939 */ class QCPColorScaleAxisRectPrivate : public QCPAxisRect { Q_OBJECT public: explicit QCPColorScaleAxisRectPrivate(QCPColorScale *parentColorScale); protected: QCPColorScale *mParentColorScale; QImage mGradientImage; bool mGradientImageInvalidated; // re-using some methods of QCPAxisRect to make them available to friend class QCPColorScale using QCPAxisRect::calculateAutoMargin; using QCPAxisRect::mousePressEvent; using QCPAxisRect::mouseMoveEvent; using QCPAxisRect::mouseReleaseEvent; using QCPAxisRect::wheelEvent; using QCPAxisRect::update; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; void updateGradientImage(); Q_SLOT void axisSelectionChanged(QCPAxis::SelectableParts selectedParts); Q_SLOT void axisSelectableChanged(QCPAxis::SelectableParts selectableParts); friend class QCPColorScale; }; class QCP_LIB_DECL QCPColorScale : public QCPLayoutElement { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QCPAxis::AxisType type READ type WRITE setType) Q_PROPERTY(QCPRange dataRange READ dataRange WRITE setDataRange NOTIFY dataRangeChanged) Q_PROPERTY(QCPAxis::ScaleType dataScaleType READ dataScaleType WRITE setDataScaleType NOTIFY dataScaleTypeChanged) Q_PROPERTY(QCPColorGradient gradient READ gradient WRITE setGradient NOTIFY gradientChanged) Q_PROPERTY(QString label READ label WRITE setLabel) Q_PROPERTY(int barWidth READ barWidth WRITE setBarWidth) Q_PROPERTY(bool rangeDrag READ rangeDrag WRITE setRangeDrag) Q_PROPERTY(bool rangeZoom READ rangeZoom WRITE setRangeZoom) /// \endcond public: explicit QCPColorScale(QCustomPlot *parentPlot); virtual ~QCPColorScale() Q_DECL_OVERRIDE; // getters: QCPAxis *axis() const { return mColorAxis.data(); } QCPAxis::AxisType type() const { return mType; } QCPRange dataRange() const { return mDataRange; } QCPAxis::ScaleType dataScaleType() const { return mDataScaleType; } QCPColorGradient gradient() const { return mGradient; } QString label() const; int barWidth () const { return mBarWidth; } bool rangeDrag() const; bool rangeZoom() const; // setters: void setType(QCPAxis::AxisType type); Q_SLOT void setDataRange(const QCPRange &dataRange); Q_SLOT void setDataScaleType(QCPAxis::ScaleType scaleType); Q_SLOT void setGradient(const QCPColorGradient &gradient); void setLabel(const QString &str); void setBarWidth(int width); void setRangeDrag(bool enabled); void setRangeZoom(bool enabled); // non-property methods: QList colorMaps() const; void rescaleDataRange(bool onlyVisibleMaps); // reimplemented virtual methods: virtual void update(UpdatePhase phase) Q_DECL_OVERRIDE; signals: void dataRangeChanged(const QCPRange &newRange); void dataScaleTypeChanged(QCPAxis::ScaleType scaleType); void gradientChanged(const QCPColorGradient &newGradient); protected: // property members: QCPAxis::AxisType mType; QCPRange mDataRange; QCPAxis::ScaleType mDataScaleType; QCPColorGradient mGradient; int mBarWidth; // non-property members: QPointer mAxisRect; QPointer mColorAxis; // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; // events: virtual void mousePressEvent(QMouseEvent *event, const QVariant &details) Q_DECL_OVERRIDE; virtual void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QCPColorScale) friend class QCPColorScaleAxisRectPrivate; }; /* end of 'src/layoutelements/layoutelement-colorscale.h' */ /* including file 'src/plottables/plottable-graph.h' */ /* modified 2021-03-29T02:30:44, size 9316 */ class QCP_LIB_DECL QCPGraphData { public: QCPGraphData(); QCPGraphData(double key, double value); inline double sortKey() const { return key; } inline static QCPGraphData fromSortKey(double sortKey) { return QCPGraphData(sortKey, 0); } inline static bool sortKeyIsMainKey() { return true; } inline double mainKey() const { return key; } inline double mainValue() const { return value; } inline QCPRange valueRange() const { return QCPRange(value, value); } double key, value; }; Q_DECLARE_TYPEINFO(QCPGraphData, Q_PRIMITIVE_TYPE); /*! \typedef QCPGraphDataContainer Container for storing \ref QCPGraphData points. The data is stored sorted by \a key. This template instantiation is the container in which QCPGraph holds its data. For details about the generic container, see the documentation of the class template \ref QCPDataContainer. \see QCPGraphData, QCPGraph::setData */ typedef QCPDataContainer QCPGraphDataContainer; class QCP_LIB_DECL QCPGraph : public QCPAbstractPlottable1D { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(LineStyle lineStyle READ lineStyle WRITE setLineStyle) Q_PROPERTY(QCPScatterStyle scatterStyle READ scatterStyle WRITE setScatterStyle) Q_PROPERTY(int scatterSkip READ scatterSkip WRITE setScatterSkip) Q_PROPERTY(QCPGraph* channelFillGraph READ channelFillGraph WRITE setChannelFillGraph) Q_PROPERTY(bool adaptiveSampling READ adaptiveSampling WRITE setAdaptiveSampling) /// \endcond public: /*! Defines how the graph's line is represented visually in the plot. The line is drawn with the current pen of the graph (\ref setPen). \see setLineStyle */ enum LineStyle { lsNone ///< data points are not connected with any lines (e.g. data only represented ///< with symbols according to the scatter style, see \ref setScatterStyle) ,lsLine ///< data points are connected by a straight line ,lsStepLeft ///< line is drawn as steps where the step height is the value of the left data point ,lsStepRight ///< line is drawn as steps where the step height is the value of the right data point ,lsStepCenter ///< line is drawn as steps where the step is in between two data points ,lsImpulse ///< each data point is represented by a line parallel to the value axis, which reaches from the data point to the zero-value-line }; Q_ENUMS(LineStyle) explicit QCPGraph(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPGraph() Q_DECL_OVERRIDE; // getters: QSharedPointer data() const { return mDataContainer; } LineStyle lineStyle() const { return mLineStyle; } QCPScatterStyle scatterStyle() const { return mScatterStyle; } int scatterSkip() const { return mScatterSkip; } QCPGraph *channelFillGraph() const { return mChannelFillGraph.data(); } bool adaptiveSampling() const { return mAdaptiveSampling; } // setters: void setData(QSharedPointer data); void setData(const QVector &keys, const QVector &values, bool alreadySorted=false); void setLineStyle(LineStyle ls); void setScatterStyle(const QCPScatterStyle &style); void setScatterSkip(int skip); void setChannelFillGraph(QCPGraph *targetGraph); void setAdaptiveSampling(bool enabled); // non-property methods: void addData(const QVector &keys, const QVector &values, bool alreadySorted=false); void addData(double key, double value); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; virtual QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const Q_DECL_OVERRIDE; virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const Q_DECL_OVERRIDE; protected: // property members: LineStyle mLineStyle; QCPScatterStyle mScatterStyle; int mScatterSkip; QPointer mChannelFillGraph; bool mAdaptiveSampling; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const Q_DECL_OVERRIDE; // introduced virtual methods: virtual void drawFill(QCPPainter *painter, QVector *lines) const; virtual void drawScatterPlot(QCPPainter *painter, const QVector &scatters, const QCPScatterStyle &style) const; virtual void drawLinePlot(QCPPainter *painter, const QVector &lines) const; virtual void drawImpulsePlot(QCPPainter *painter, const QVector &lines) const; virtual void getOptimizedLineData(QVector *lineData, const QCPGraphDataContainer::const_iterator &begin, const QCPGraphDataContainer::const_iterator &end) const; virtual void getOptimizedScatterData(QVector *scatterData, QCPGraphDataContainer::const_iterator begin, QCPGraphDataContainer::const_iterator end) const; // non-virtual methods: void getVisibleDataBounds(QCPGraphDataContainer::const_iterator &begin, QCPGraphDataContainer::const_iterator &end, const QCPDataRange &rangeRestriction) const; void getLines(QVector *lines, const QCPDataRange &dataRange) const; void getScatters(QVector *scatters, const QCPDataRange &dataRange) const; QVector dataToLines(const QVector &data) const; QVector dataToStepLeftLines(const QVector &data) const; QVector dataToStepRightLines(const QVector &data) const; QVector dataToStepCenterLines(const QVector &data) const; QVector dataToImpulseLines(const QVector &data) const; QVector getNonNanSegments(const QVector *lineData, Qt::Orientation keyOrientation) const; QVector > getOverlappingSegments(QVector thisSegments, const QVector *thisData, QVector otherSegments, const QVector *otherData) const; bool segmentsIntersect(double aLower, double aUpper, double bLower, double bUpper, int &bPrecedence) const; QPointF getFillBasePoint(QPointF matchingDataPoint) const; const QPolygonF getFillPolygon(const QVector *lineData, QCPDataRange segment) const; const QPolygonF getChannelFillPolygon(const QVector *thisData, QCPDataRange thisSegment, const QVector *otherData, QCPDataRange otherSegment) const; int findIndexBelowX(const QVector *data, double x) const; int findIndexAboveX(const QVector *data, double x) const; int findIndexBelowY(const QVector *data, double y) const; int findIndexAboveY(const QVector *data, double y) const; double pointDistance(const QPointF &pixelPoint, QCPGraphDataContainer::const_iterator &closestData) const; friend class QCustomPlot; friend class QCPLegend; }; Q_DECLARE_METATYPE(QCPGraph::LineStyle) /* end of 'src/plottables/plottable-graph.h' */ /* including file 'src/plottables/plottable-curve.h' */ /* modified 2021-03-29T02:30:44, size 7434 */ class QCP_LIB_DECL QCPCurveData { public: QCPCurveData(); QCPCurveData(double t, double key, double value); inline double sortKey() const { return t; } inline static QCPCurveData fromSortKey(double sortKey) { return QCPCurveData(sortKey, 0, 0); } inline static bool sortKeyIsMainKey() { return false; } inline double mainKey() const { return key; } inline double mainValue() const { return value; } inline QCPRange valueRange() const { return QCPRange(value, value); } double t, key, value; }; Q_DECLARE_TYPEINFO(QCPCurveData, Q_PRIMITIVE_TYPE); /*! \typedef QCPCurveDataContainer Container for storing \ref QCPCurveData points. The data is stored sorted by \a t, so the \a sortKey() (returning \a t) is different from \a mainKey() (returning \a key). This template instantiation is the container in which QCPCurve holds its data. For details about the generic container, see the documentation of the class template \ref QCPDataContainer. \see QCPCurveData, QCPCurve::setData */ typedef QCPDataContainer QCPCurveDataContainer; class QCP_LIB_DECL QCPCurve : public QCPAbstractPlottable1D { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QCPScatterStyle scatterStyle READ scatterStyle WRITE setScatterStyle) Q_PROPERTY(int scatterSkip READ scatterSkip WRITE setScatterSkip) Q_PROPERTY(LineStyle lineStyle READ lineStyle WRITE setLineStyle) /// \endcond public: /*! Defines how the curve's line is represented visually in the plot. The line is drawn with the current pen of the curve (\ref setPen). \see setLineStyle */ enum LineStyle { lsNone ///< No line is drawn between data points (e.g. only scatters) ,lsLine ///< Data points are connected with a straight line }; Q_ENUMS(LineStyle) explicit QCPCurve(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPCurve() Q_DECL_OVERRIDE; // getters: QSharedPointer data() const { return mDataContainer; } QCPScatterStyle scatterStyle() const { return mScatterStyle; } int scatterSkip() const { return mScatterSkip; } LineStyle lineStyle() const { return mLineStyle; } // setters: void setData(QSharedPointer data); void setData(const QVector &t, const QVector &keys, const QVector &values, bool alreadySorted=false); void setData(const QVector &keys, const QVector &values); void setScatterStyle(const QCPScatterStyle &style); void setScatterSkip(int skip); void setLineStyle(LineStyle style); // non-property methods: void addData(const QVector &t, const QVector &keys, const QVector &values, bool alreadySorted=false); void addData(const QVector &keys, const QVector &values); void addData(double t, double key, double value); void addData(double key, double value); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; virtual QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const Q_DECL_OVERRIDE; virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const Q_DECL_OVERRIDE; protected: // property members: QCPScatterStyle mScatterStyle; int mScatterSkip; LineStyle mLineStyle; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const Q_DECL_OVERRIDE; // introduced virtual methods: virtual void drawCurveLine(QCPPainter *painter, const QVector &lines) const; virtual void drawScatterPlot(QCPPainter *painter, const QVector &points, const QCPScatterStyle &style) const; // non-virtual methods: void getCurveLines(QVector *lines, const QCPDataRange &dataRange, double penWidth) const; void getScatters(QVector *scatters, const QCPDataRange &dataRange, double scatterWidth) const; int getRegion(double key, double value, double keyMin, double valueMax, double keyMax, double valueMin) const; QPointF getOptimizedPoint(int otherRegion, double otherKey, double otherValue, double key, double value, double keyMin, double valueMax, double keyMax, double valueMin) const; QVector getOptimizedCornerPoints(int prevRegion, int currentRegion, double prevKey, double prevValue, double key, double value, double keyMin, double valueMax, double keyMax, double valueMin) const; bool mayTraverse(int prevRegion, int currentRegion) const; bool getTraverse(double prevKey, double prevValue, double key, double value, double keyMin, double valueMax, double keyMax, double valueMin, QPointF &crossA, QPointF &crossB) const; void getTraverseCornerPoints(int prevRegion, int currentRegion, double keyMin, double valueMax, double keyMax, double valueMin, QVector &beforeTraverse, QVector &afterTraverse) const; double pointDistance(const QPointF &pixelPoint, QCPCurveDataContainer::const_iterator &closestData) const; friend class QCustomPlot; friend class QCPLegend; }; Q_DECLARE_METATYPE(QCPCurve::LineStyle) /* end of 'src/plottables/plottable-curve.h' */ /* including file 'src/plottables/plottable-bars.h' */ /* modified 2021-03-29T02:30:44, size 8955 */ class QCP_LIB_DECL QCPBarsGroup : public QObject { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(SpacingType spacingType READ spacingType WRITE setSpacingType) Q_PROPERTY(double spacing READ spacing WRITE setSpacing) /// \endcond public: /*! Defines the ways the spacing between bars in the group can be specified. Thus it defines what the number passed to \ref setSpacing actually means. \see setSpacingType, setSpacing */ enum SpacingType { stAbsolute ///< Bar spacing is in absolute pixels ,stAxisRectRatio ///< Bar spacing is given by a fraction of the axis rect size ,stPlotCoords ///< Bar spacing is in key coordinates and thus scales with the key axis range }; Q_ENUMS(SpacingType) explicit QCPBarsGroup(QCustomPlot *parentPlot); virtual ~QCPBarsGroup(); // getters: SpacingType spacingType() const { return mSpacingType; } double spacing() const { return mSpacing; } // setters: void setSpacingType(SpacingType spacingType); void setSpacing(double spacing); // non-virtual methods: QList bars() const { return mBars; } QCPBars* bars(int index) const; int size() const { return mBars.size(); } bool isEmpty() const { return mBars.isEmpty(); } void clear(); bool contains(QCPBars *bars) const { return mBars.contains(bars); } void append(QCPBars *bars); void insert(int i, QCPBars *bars); void remove(QCPBars *bars); protected: // non-property members: QCustomPlot *mParentPlot; SpacingType mSpacingType; double mSpacing; QList mBars; // non-virtual methods: void registerBars(QCPBars *bars); void unregisterBars(QCPBars *bars); // virtual methods: double keyPixelOffset(const QCPBars *bars, double keyCoord); double getPixelSpacing(const QCPBars *bars, double keyCoord); private: Q_DISABLE_COPY(QCPBarsGroup) friend class QCPBars; }; Q_DECLARE_METATYPE(QCPBarsGroup::SpacingType) class QCP_LIB_DECL QCPBarsData { public: QCPBarsData(); QCPBarsData(double key, double value); inline double sortKey() const { return key; } inline static QCPBarsData fromSortKey(double sortKey) { return QCPBarsData(sortKey, 0); } inline static bool sortKeyIsMainKey() { return true; } inline double mainKey() const { return key; } inline double mainValue() const { return value; } inline QCPRange valueRange() const { return QCPRange(value, value); } // note that bar base value isn't held in each QCPBarsData and thus can't/shouldn't be returned here double key, value; }; Q_DECLARE_TYPEINFO(QCPBarsData, Q_PRIMITIVE_TYPE); /*! \typedef QCPBarsDataContainer Container for storing \ref QCPBarsData points. The data is stored sorted by \a key. This template instantiation is the container in which QCPBars holds its data. For details about the generic container, see the documentation of the class template \ref QCPDataContainer. \see QCPBarsData, QCPBars::setData */ typedef QCPDataContainer QCPBarsDataContainer; class QCP_LIB_DECL QCPBars : public QCPAbstractPlottable1D { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(double width READ width WRITE setWidth) Q_PROPERTY(WidthType widthType READ widthType WRITE setWidthType) Q_PROPERTY(QCPBarsGroup* barsGroup READ barsGroup WRITE setBarsGroup) Q_PROPERTY(double baseValue READ baseValue WRITE setBaseValue) Q_PROPERTY(double stackingGap READ stackingGap WRITE setStackingGap) Q_PROPERTY(QCPBars* barBelow READ barBelow) Q_PROPERTY(QCPBars* barAbove READ barAbove) /// \endcond public: /*! Defines the ways the width of the bar can be specified. Thus it defines what the number passed to \ref setWidth actually means. \see setWidthType, setWidth */ enum WidthType { wtAbsolute ///< Bar width is in absolute pixels ,wtAxisRectRatio ///< Bar width is given by a fraction of the axis rect size ,wtPlotCoords ///< Bar width is in key coordinates and thus scales with the key axis range }; Q_ENUMS(WidthType) explicit QCPBars(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPBars() Q_DECL_OVERRIDE; // getters: double width() const { return mWidth; } WidthType widthType() const { return mWidthType; } QCPBarsGroup *barsGroup() const { return mBarsGroup; } double baseValue() const { return mBaseValue; } double stackingGap() const { return mStackingGap; } QCPBars *barBelow() const { return mBarBelow.data(); } QCPBars *barAbove() const { return mBarAbove.data(); } QSharedPointer data() const { return mDataContainer; } // setters: void setData(QSharedPointer data); void setData(const QVector &keys, const QVector &values, bool alreadySorted=false); void setWidth(double width); void setWidthType(WidthType widthType); void setBarsGroup(QCPBarsGroup *barsGroup); void setBaseValue(double baseValue); void setStackingGap(double pixels); // non-property methods: void addData(const QVector &keys, const QVector &values, bool alreadySorted=false); void addData(double key, double value); void moveBelow(QCPBars *bars); void moveAbove(QCPBars *bars); // reimplemented virtual methods: virtual QCPDataSelection selectTestRect(const QRectF &rect, bool onlySelectable) const Q_DECL_OVERRIDE; virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; virtual QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const Q_DECL_OVERRIDE; virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const Q_DECL_OVERRIDE; virtual QPointF dataPixelPosition(int index) const Q_DECL_OVERRIDE; protected: // property members: double mWidth; WidthType mWidthType; QCPBarsGroup *mBarsGroup; double mBaseValue; double mStackingGap; QPointer mBarBelow, mBarAbove; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const Q_DECL_OVERRIDE; // non-virtual methods: void getVisibleDataBounds(QCPBarsDataContainer::const_iterator &begin, QCPBarsDataContainer::const_iterator &end) const; QRectF getBarRect(double key, double value) const; void getPixelWidth(double key, double &lower, double &upper) const; double getStackedBaseValue(double key, bool positive) const; static void connectBars(QCPBars* lower, QCPBars* upper); friend class QCustomPlot; friend class QCPLegend; friend class QCPBarsGroup; }; Q_DECLARE_METATYPE(QCPBars::WidthType) /* end of 'src/plottables/plottable-bars.h' */ /* including file 'src/plottables/plottable-statisticalbox.h' */ /* modified 2021-03-29T02:30:44, size 7522 */ class QCP_LIB_DECL QCPStatisticalBoxData { public: QCPStatisticalBoxData(); QCPStatisticalBoxData(double key, double minimum, double lowerQuartile, double median, double upperQuartile, double maximum, const QVector& outliers=QVector()); inline double sortKey() const { return key; } inline static QCPStatisticalBoxData fromSortKey(double sortKey) { return QCPStatisticalBoxData(sortKey, 0, 0, 0, 0, 0); } inline static bool sortKeyIsMainKey() { return true; } inline double mainKey() const { return key; } inline double mainValue() const { return median; } inline QCPRange valueRange() const { QCPRange result(minimum, maximum); for (QVector::const_iterator it = outliers.constBegin(); it != outliers.constEnd(); ++it) result.expand(*it); return result; } double key, minimum, lowerQuartile, median, upperQuartile, maximum; QVector outliers; }; Q_DECLARE_TYPEINFO(QCPStatisticalBoxData, Q_MOVABLE_TYPE); /*! \typedef QCPStatisticalBoxDataContainer Container for storing \ref QCPStatisticalBoxData points. The data is stored sorted by \a key. This template instantiation is the container in which QCPStatisticalBox holds its data. For details about the generic container, see the documentation of the class template \ref QCPDataContainer. \see QCPStatisticalBoxData, QCPStatisticalBox::setData */ typedef QCPDataContainer QCPStatisticalBoxDataContainer; class QCP_LIB_DECL QCPStatisticalBox : public QCPAbstractPlottable1D { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(double width READ width WRITE setWidth) Q_PROPERTY(double whiskerWidth READ whiskerWidth WRITE setWhiskerWidth) Q_PROPERTY(QPen whiskerPen READ whiskerPen WRITE setWhiskerPen) Q_PROPERTY(QPen whiskerBarPen READ whiskerBarPen WRITE setWhiskerBarPen) Q_PROPERTY(bool whiskerAntialiased READ whiskerAntialiased WRITE setWhiskerAntialiased) Q_PROPERTY(QPen medianPen READ medianPen WRITE setMedianPen) Q_PROPERTY(QCPScatterStyle outlierStyle READ outlierStyle WRITE setOutlierStyle) /// \endcond public: explicit QCPStatisticalBox(QCPAxis *keyAxis, QCPAxis *valueAxis); // getters: QSharedPointer data() const { return mDataContainer; } double width() const { return mWidth; } double whiskerWidth() const { return mWhiskerWidth; } QPen whiskerPen() const { return mWhiskerPen; } QPen whiskerBarPen() const { return mWhiskerBarPen; } bool whiskerAntialiased() const { return mWhiskerAntialiased; } QPen medianPen() const { return mMedianPen; } QCPScatterStyle outlierStyle() const { return mOutlierStyle; } // setters: void setData(QSharedPointer data); void setData(const QVector &keys, const QVector &minimum, const QVector &lowerQuartile, const QVector &median, const QVector &upperQuartile, const QVector &maximum, bool alreadySorted=false); void setWidth(double width); void setWhiskerWidth(double width); void setWhiskerPen(const QPen &pen); void setWhiskerBarPen(const QPen &pen); void setWhiskerAntialiased(bool enabled); void setMedianPen(const QPen &pen); void setOutlierStyle(const QCPScatterStyle &style); // non-property methods: void addData(const QVector &keys, const QVector &minimum, const QVector &lowerQuartile, const QVector &median, const QVector &upperQuartile, const QVector &maximum, bool alreadySorted=false); void addData(double key, double minimum, double lowerQuartile, double median, double upperQuartile, double maximum, const QVector &outliers=QVector()); // reimplemented virtual methods: virtual QCPDataSelection selectTestRect(const QRectF &rect, bool onlySelectable) const Q_DECL_OVERRIDE; virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; virtual QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const Q_DECL_OVERRIDE; virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const Q_DECL_OVERRIDE; protected: // property members: double mWidth; double mWhiskerWidth; QPen mWhiskerPen, mWhiskerBarPen; bool mWhiskerAntialiased; QPen mMedianPen; QCPScatterStyle mOutlierStyle; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const Q_DECL_OVERRIDE; // introduced virtual methods: virtual void drawStatisticalBox(QCPPainter *painter, QCPStatisticalBoxDataContainer::const_iterator it, const QCPScatterStyle &outlierStyle) const; // non-virtual methods: void getVisibleDataBounds(QCPStatisticalBoxDataContainer::const_iterator &begin, QCPStatisticalBoxDataContainer::const_iterator &end) const; QRectF getQuartileBox(QCPStatisticalBoxDataContainer::const_iterator it) const; QVector getWhiskerBackboneLines(QCPStatisticalBoxDataContainer::const_iterator it) const; QVector getWhiskerBarLines(QCPStatisticalBoxDataContainer::const_iterator it) const; friend class QCustomPlot; friend class QCPLegend; }; /* end of 'src/plottables/plottable-statisticalbox.h' */ /* including file 'src/plottables/plottable-colormap.h' */ /* modified 2021-03-29T02:30:44, size 7092 */ class QCP_LIB_DECL QCPColorMapData { public: QCPColorMapData(int keySize, int valueSize, const QCPRange &keyRange, const QCPRange &valueRange); ~QCPColorMapData(); QCPColorMapData(const QCPColorMapData &other); QCPColorMapData &operator=(const QCPColorMapData &other); // getters: int keySize() const { return mKeySize; } int valueSize() const { return mValueSize; } QCPRange keyRange() const { return mKeyRange; } QCPRange valueRange() const { return mValueRange; } QCPRange dataBounds() const { return mDataBounds; } double data(double key, double value); double cell(int keyIndex, int valueIndex); unsigned char alpha(int keyIndex, int valueIndex); // setters: void setSize(int keySize, int valueSize); void setKeySize(int keySize); void setValueSize(int valueSize); void setRange(const QCPRange &keyRange, const QCPRange &valueRange); void setKeyRange(const QCPRange &keyRange); void setValueRange(const QCPRange &valueRange); void setData(double key, double value, double z); void setCell(int keyIndex, int valueIndex, double z); void setAlpha(int keyIndex, int valueIndex, unsigned char alpha); // non-property methods: void recalculateDataBounds(); void clear(); void clearAlpha(); void fill(double z); void fillAlpha(unsigned char alpha); bool isEmpty() const { return mIsEmpty; } void coordToCell(double key, double value, int *keyIndex, int *valueIndex) const; void cellToCoord(int keyIndex, int valueIndex, double *key, double *value) const; protected: // property members: int mKeySize, mValueSize; QCPRange mKeyRange, mValueRange; bool mIsEmpty; // non-property members: double *mData; unsigned char *mAlpha; QCPRange mDataBounds; bool mDataModified; bool createAlpha(bool initializeOpaque=true); friend class QCPColorMap; }; class QCP_LIB_DECL QCPColorMap : public QCPAbstractPlottable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QCPRange dataRange READ dataRange WRITE setDataRange NOTIFY dataRangeChanged) Q_PROPERTY(QCPAxis::ScaleType dataScaleType READ dataScaleType WRITE setDataScaleType NOTIFY dataScaleTypeChanged) Q_PROPERTY(QCPColorGradient gradient READ gradient WRITE setGradient NOTIFY gradientChanged) Q_PROPERTY(bool interpolate READ interpolate WRITE setInterpolate) Q_PROPERTY(bool tightBoundary READ tightBoundary WRITE setTightBoundary) Q_PROPERTY(QCPColorScale* colorScale READ colorScale WRITE setColorScale) /// \endcond public: explicit QCPColorMap(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPColorMap() Q_DECL_OVERRIDE; // getters: QCPColorMapData *data() const { return mMapData; } QCPRange dataRange() const { return mDataRange; } QCPAxis::ScaleType dataScaleType() const { return mDataScaleType; } bool interpolate() const { return mInterpolate; } bool tightBoundary() const { return mTightBoundary; } QCPColorGradient gradient() const { return mGradient; } QCPColorScale *colorScale() const { return mColorScale.data(); } // setters: void setData(QCPColorMapData *data, bool copy=false); Q_SLOT void setDataRange(const QCPRange &dataRange); Q_SLOT void setDataScaleType(QCPAxis::ScaleType scaleType); Q_SLOT void setGradient(const QCPColorGradient &gradient); void setInterpolate(bool enabled); void setTightBoundary(bool enabled); void setColorScale(QCPColorScale *colorScale); // non-property methods: void rescaleDataRange(bool recalculateDataBounds=false); Q_SLOT void updateLegendIcon(Qt::TransformationMode transformMode=Qt::SmoothTransformation, const QSize &thumbSize=QSize(32, 18)); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; virtual QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const Q_DECL_OVERRIDE; virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const Q_DECL_OVERRIDE; signals: void dataRangeChanged(const QCPRange &newRange); void dataScaleTypeChanged(QCPAxis::ScaleType scaleType); void gradientChanged(const QCPColorGradient &newGradient); protected: // property members: QCPRange mDataRange; QCPAxis::ScaleType mDataScaleType; QCPColorMapData *mMapData; QCPColorGradient mGradient; bool mInterpolate; bool mTightBoundary; QPointer mColorScale; // non-property members: QImage mMapImage, mUndersampledMapImage; QPixmap mLegendIcon; bool mMapImageInvalidated; // introduced virtual methods: virtual void updateMapImage(); // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const Q_DECL_OVERRIDE; friend class QCustomPlot; friend class QCPLegend; }; /* end of 'src/plottables/plottable-colormap.h' */ /* including file 'src/plottables/plottable-financial.h' */ /* modified 2021-03-29T02:30:44, size 8644 */ class QCP_LIB_DECL QCPFinancialData { public: QCPFinancialData(); QCPFinancialData(double key, double open, double high, double low, double close); inline double sortKey() const { return key; } inline static QCPFinancialData fromSortKey(double sortKey) { return QCPFinancialData(sortKey, 0, 0, 0, 0); } inline static bool sortKeyIsMainKey() { return true; } inline double mainKey() const { return key; } inline double mainValue() const { return open; } inline QCPRange valueRange() const { return QCPRange(low, high); } // open and close must lie between low and high, so we don't need to check them double key, open, high, low, close; }; Q_DECLARE_TYPEINFO(QCPFinancialData, Q_PRIMITIVE_TYPE); /*! \typedef QCPFinancialDataContainer Container for storing \ref QCPFinancialData points. The data is stored sorted by \a key. This template instantiation is the container in which QCPFinancial holds its data. For details about the generic container, see the documentation of the class template \ref QCPDataContainer. \see QCPFinancialData, QCPFinancial::setData */ typedef QCPDataContainer QCPFinancialDataContainer; class QCP_LIB_DECL QCPFinancial : public QCPAbstractPlottable1D { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(ChartStyle chartStyle READ chartStyle WRITE setChartStyle) Q_PROPERTY(double width READ width WRITE setWidth) Q_PROPERTY(WidthType widthType READ widthType WRITE setWidthType) Q_PROPERTY(bool twoColored READ twoColored WRITE setTwoColored) Q_PROPERTY(QBrush brushPositive READ brushPositive WRITE setBrushPositive) Q_PROPERTY(QBrush brushNegative READ brushNegative WRITE setBrushNegative) Q_PROPERTY(QPen penPositive READ penPositive WRITE setPenPositive) Q_PROPERTY(QPen penNegative READ penNegative WRITE setPenNegative) /// \endcond public: /*! Defines the ways the width of the financial bar can be specified. Thus it defines what the number passed to \ref setWidth actually means. \see setWidthType, setWidth */ enum WidthType { wtAbsolute ///< width is in absolute pixels ,wtAxisRectRatio ///< width is given by a fraction of the axis rect size ,wtPlotCoords ///< width is in key coordinates and thus scales with the key axis range }; Q_ENUMS(WidthType) /*! Defines the possible representations of OHLC data in the plot. \see setChartStyle */ enum ChartStyle { csOhlc ///< Open-High-Low-Close bar representation ,csCandlestick ///< Candlestick representation }; Q_ENUMS(ChartStyle) explicit QCPFinancial(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPFinancial() Q_DECL_OVERRIDE; // getters: QSharedPointer data() const { return mDataContainer; } ChartStyle chartStyle() const { return mChartStyle; } double width() const { return mWidth; } WidthType widthType() const { return mWidthType; } bool twoColored() const { return mTwoColored; } QBrush brushPositive() const { return mBrushPositive; } QBrush brushNegative() const { return mBrushNegative; } QPen penPositive() const { return mPenPositive; } QPen penNegative() const { return mPenNegative; } // setters: void setData(QSharedPointer data); void setData(const QVector &keys, const QVector &open, const QVector &high, const QVector &low, const QVector &close, bool alreadySorted=false); void setChartStyle(ChartStyle style); void setWidth(double width); void setWidthType(WidthType widthType); void setTwoColored(bool twoColored); void setBrushPositive(const QBrush &brush); void setBrushNegative(const QBrush &brush); void setPenPositive(const QPen &pen); void setPenNegative(const QPen &pen); // non-property methods: void addData(const QVector &keys, const QVector &open, const QVector &high, const QVector &low, const QVector &close, bool alreadySorted=false); void addData(double key, double open, double high, double low, double close); // reimplemented virtual methods: virtual QCPDataSelection selectTestRect(const QRectF &rect, bool onlySelectable) const Q_DECL_OVERRIDE; virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; virtual QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const Q_DECL_OVERRIDE; virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const Q_DECL_OVERRIDE; // static methods: static QCPFinancialDataContainer timeSeriesToOhlc(const QVector &time, const QVector &value, double timeBinSize, double timeBinOffset = 0); protected: // property members: ChartStyle mChartStyle; double mWidth; WidthType mWidthType; bool mTwoColored; QBrush mBrushPositive, mBrushNegative; QPen mPenPositive, mPenNegative; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const Q_DECL_OVERRIDE; // non-virtual methods: void drawOhlcPlot(QCPPainter *painter, const QCPFinancialDataContainer::const_iterator &begin, const QCPFinancialDataContainer::const_iterator &end, bool isSelected); void drawCandlestickPlot(QCPPainter *painter, const QCPFinancialDataContainer::const_iterator &begin, const QCPFinancialDataContainer::const_iterator &end, bool isSelected); double getPixelWidth(double key, double keyPixel) const; double ohlcSelectTest(const QPointF &pos, const QCPFinancialDataContainer::const_iterator &begin, const QCPFinancialDataContainer::const_iterator &end, QCPFinancialDataContainer::const_iterator &closestDataPoint) const; double candlestickSelectTest(const QPointF &pos, const QCPFinancialDataContainer::const_iterator &begin, const QCPFinancialDataContainer::const_iterator &end, QCPFinancialDataContainer::const_iterator &closestDataPoint) const; void getVisibleDataBounds(QCPFinancialDataContainer::const_iterator &begin, QCPFinancialDataContainer::const_iterator &end) const; QRectF selectionHitBox(QCPFinancialDataContainer::const_iterator it) const; friend class QCustomPlot; friend class QCPLegend; }; Q_DECLARE_METATYPE(QCPFinancial::ChartStyle) /* end of 'src/plottables/plottable-financial.h' */ /* including file 'src/plottables/plottable-errorbar.h' */ /* modified 2021-03-29T02:30:44, size 7749 */ class QCP_LIB_DECL QCPErrorBarsData { public: QCPErrorBarsData(); explicit QCPErrorBarsData(double error); QCPErrorBarsData(double errorMinus, double errorPlus); double errorMinus, errorPlus; }; Q_DECLARE_TYPEINFO(QCPErrorBarsData, Q_PRIMITIVE_TYPE); /*! \typedef QCPErrorBarsDataContainer Container for storing \ref QCPErrorBarsData points. It is a typedef for QVector<\ref QCPErrorBarsData>. This is the container in which \ref QCPErrorBars holds its data. Unlike most other data containers for plottables, it is not based on \ref QCPDataContainer. This is because the error bars plottable is special in that it doesn't store its own key and value coordinate per error bar. It adopts the key and value from the plottable to which the error bars shall be applied (\ref QCPErrorBars::setDataPlottable). So the stored \ref QCPErrorBarsData doesn't need a sortable key, but merely an index (as \c QVector provides), which maps one-to-one to the indices of the other plottable's data. \see QCPErrorBarsData, QCPErrorBars::setData */ typedef QVector QCPErrorBarsDataContainer; class QCP_LIB_DECL QCPErrorBars : public QCPAbstractPlottable, public QCPPlottableInterface1D { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QSharedPointer data READ data WRITE setData) Q_PROPERTY(QCPAbstractPlottable* dataPlottable READ dataPlottable WRITE setDataPlottable) Q_PROPERTY(ErrorType errorType READ errorType WRITE setErrorType) Q_PROPERTY(double whiskerWidth READ whiskerWidth WRITE setWhiskerWidth) Q_PROPERTY(double symbolGap READ symbolGap WRITE setSymbolGap) /// \endcond public: /*! Defines in which orientation the error bars shall appear. If your data needs both error dimensions, create two \ref QCPErrorBars with different \ref ErrorType. \see setErrorType */ enum ErrorType { etKeyError ///< The errors are for the key dimension (bars appear parallel to the key axis) ,etValueError ///< The errors are for the value dimension (bars appear parallel to the value axis) }; Q_ENUMS(ErrorType) explicit QCPErrorBars(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPErrorBars() Q_DECL_OVERRIDE; // getters: QSharedPointer data() const { return mDataContainer; } QCPAbstractPlottable *dataPlottable() const { return mDataPlottable.data(); } ErrorType errorType() const { return mErrorType; } double whiskerWidth() const { return mWhiskerWidth; } double symbolGap() const { return mSymbolGap; } // setters: void setData(QSharedPointer data); void setData(const QVector &error); void setData(const QVector &errorMinus, const QVector &errorPlus); void setDataPlottable(QCPAbstractPlottable* plottable); void setErrorType(ErrorType type); void setWhiskerWidth(double pixels); void setSymbolGap(double pixels); // non-property methods: void addData(const QVector &error); void addData(const QVector &errorMinus, const QVector &errorPlus); void addData(double error); void addData(double errorMinus, double errorPlus); // virtual methods of 1d plottable interface: virtual int dataCount() const Q_DECL_OVERRIDE; virtual double dataMainKey(int index) const Q_DECL_OVERRIDE; virtual double dataSortKey(int index) const Q_DECL_OVERRIDE; virtual double dataMainValue(int index) const Q_DECL_OVERRIDE; virtual QCPRange dataValueRange(int index) const Q_DECL_OVERRIDE; virtual QPointF dataPixelPosition(int index) const Q_DECL_OVERRIDE; virtual bool sortKeyIsMainKey() const Q_DECL_OVERRIDE; virtual QCPDataSelection selectTestRect(const QRectF &rect, bool onlySelectable) const Q_DECL_OVERRIDE; virtual int findBegin(double sortKey, bool expandedRange=true) const Q_DECL_OVERRIDE; virtual int findEnd(double sortKey, bool expandedRange=true) const Q_DECL_OVERRIDE; // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; virtual QCPPlottableInterface1D *interface1D() Q_DECL_OVERRIDE { return this; } protected: // property members: QSharedPointer mDataContainer; QPointer mDataPlottable; ErrorType mErrorType; double mWhiskerWidth; double mSymbolGap; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const Q_DECL_OVERRIDE; virtual QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const Q_DECL_OVERRIDE; virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const Q_DECL_OVERRIDE; // non-virtual methods: void getErrorBarLines(QCPErrorBarsDataContainer::const_iterator it, QVector &backbones, QVector &whiskers) const; void getVisibleDataBounds(QCPErrorBarsDataContainer::const_iterator &begin, QCPErrorBarsDataContainer::const_iterator &end, const QCPDataRange &rangeRestriction) const; double pointDistance(const QPointF &pixelPoint, QCPErrorBarsDataContainer::const_iterator &closestData) const; // helpers: void getDataSegments(QList &selectedSegments, QList &unselectedSegments) const; bool errorBarVisible(int index) const; bool rectIntersectsLine(const QRectF &pixelRect, const QLineF &line) const; friend class QCustomPlot; friend class QCPLegend; }; /* end of 'src/plottables/plottable-errorbar.h' */ /* including file 'src/items/item-straightline.h' */ /* modified 2021-03-29T02:30:44, size 3137 */ class QCP_LIB_DECL QCPItemStraightLine : public QCPAbstractItem { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen selectedPen READ selectedPen WRITE setSelectedPen) /// \endcond public: explicit QCPItemStraightLine(QCustomPlot *parentPlot); virtual ~QCPItemStraightLine() Q_DECL_OVERRIDE; // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; QCPItemPosition * const point1; QCPItemPosition * const point2; protected: // property members: QPen mPen, mSelectedPen; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; // non-virtual methods: QLineF getRectClippedStraightLine(const QCPVector2D &base, const QCPVector2D &vec, const QRect &rect) const; QPen mainPen() const; }; /* end of 'src/items/item-straightline.h' */ /* including file 'src/items/item-line.h' */ /* modified 2021-03-29T02:30:44, size 3429 */ class QCP_LIB_DECL QCPItemLine : public QCPAbstractItem { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen selectedPen READ selectedPen WRITE setSelectedPen) Q_PROPERTY(QCPLineEnding head READ head WRITE setHead) Q_PROPERTY(QCPLineEnding tail READ tail WRITE setTail) /// \endcond public: explicit QCPItemLine(QCustomPlot *parentPlot); virtual ~QCPItemLine() Q_DECL_OVERRIDE; // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QCPLineEnding head() const { return mHead; } QCPLineEnding tail() const { return mTail; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setHead(const QCPLineEnding &head); void setTail(const QCPLineEnding &tail); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; QCPItemPosition * const start; QCPItemPosition * const end; protected: // property members: QPen mPen, mSelectedPen; QCPLineEnding mHead, mTail; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; // non-virtual methods: QLineF getRectClippedLine(const QCPVector2D &start, const QCPVector2D &end, const QRect &rect) const; QPen mainPen() const; }; /* end of 'src/items/item-line.h' */ /* including file 'src/items/item-curve.h' */ /* modified 2021-03-29T02:30:44, size 3401 */ class QCP_LIB_DECL QCPItemCurve : public QCPAbstractItem { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen selectedPen READ selectedPen WRITE setSelectedPen) Q_PROPERTY(QCPLineEnding head READ head WRITE setHead) Q_PROPERTY(QCPLineEnding tail READ tail WRITE setTail) /// \endcond public: explicit QCPItemCurve(QCustomPlot *parentPlot); virtual ~QCPItemCurve() Q_DECL_OVERRIDE; // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QCPLineEnding head() const { return mHead; } QCPLineEnding tail() const { return mTail; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setHead(const QCPLineEnding &head); void setTail(const QCPLineEnding &tail); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; QCPItemPosition * const start; QCPItemPosition * const startDir; QCPItemPosition * const endDir; QCPItemPosition * const end; protected: // property members: QPen mPen, mSelectedPen; QCPLineEnding mHead, mTail; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; // non-virtual methods: QPen mainPen() const; }; /* end of 'src/items/item-curve.h' */ /* including file 'src/items/item-rect.h' */ /* modified 2021-03-29T02:30:44, size 3710 */ class QCP_LIB_DECL QCPItemRect : public QCPAbstractItem { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen selectedPen READ selectedPen WRITE setSelectedPen) Q_PROPERTY(QBrush brush READ brush WRITE setBrush) Q_PROPERTY(QBrush selectedBrush READ selectedBrush WRITE setSelectedBrush) /// \endcond public: explicit QCPItemRect(QCustomPlot *parentPlot); virtual ~QCPItemRect() Q_DECL_OVERRIDE; // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QBrush brush() const { return mBrush; } QBrush selectedBrush() const { return mSelectedBrush; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setBrush(const QBrush &brush); void setSelectedBrush(const QBrush &brush); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; QCPItemPosition * const topLeft; QCPItemPosition * const bottomRight; QCPItemAnchor * const top; QCPItemAnchor * const topRight; QCPItemAnchor * const right; QCPItemAnchor * const bottom; QCPItemAnchor * const bottomLeft; QCPItemAnchor * const left; protected: enum AnchorIndex {aiTop, aiTopRight, aiRight, aiBottom, aiBottomLeft, aiLeft}; // property members: QPen mPen, mSelectedPen; QBrush mBrush, mSelectedBrush; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QPointF anchorPixelPosition(int anchorId) const Q_DECL_OVERRIDE; // non-virtual methods: QPen mainPen() const; QBrush mainBrush() const; }; /* end of 'src/items/item-rect.h' */ /* including file 'src/items/item-text.h' */ /* modified 2021-03-29T02:30:44, size 5576 */ class QCP_LIB_DECL QCPItemText : public QCPAbstractItem { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QColor color READ color WRITE setColor) Q_PROPERTY(QColor selectedColor READ selectedColor WRITE setSelectedColor) Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen selectedPen READ selectedPen WRITE setSelectedPen) Q_PROPERTY(QBrush brush READ brush WRITE setBrush) Q_PROPERTY(QBrush selectedBrush READ selectedBrush WRITE setSelectedBrush) Q_PROPERTY(QFont font READ font WRITE setFont) Q_PROPERTY(QFont selectedFont READ selectedFont WRITE setSelectedFont) Q_PROPERTY(QString text READ text WRITE setText) Q_PROPERTY(Qt::Alignment positionAlignment READ positionAlignment WRITE setPositionAlignment) Q_PROPERTY(Qt::Alignment textAlignment READ textAlignment WRITE setTextAlignment) Q_PROPERTY(double rotation READ rotation WRITE setRotation) Q_PROPERTY(QMargins padding READ padding WRITE setPadding) /// \endcond public: explicit QCPItemText(QCustomPlot *parentPlot); virtual ~QCPItemText() Q_DECL_OVERRIDE; // getters: QColor color() const { return mColor; } QColor selectedColor() const { return mSelectedColor; } QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QBrush brush() const { return mBrush; } QBrush selectedBrush() const { return mSelectedBrush; } QFont font() const { return mFont; } QFont selectedFont() const { return mSelectedFont; } QString text() const { return mText; } Qt::Alignment positionAlignment() const { return mPositionAlignment; } Qt::Alignment textAlignment() const { return mTextAlignment; } double rotation() const { return mRotation; } QMargins padding() const { return mPadding; } // setters; void setColor(const QColor &color); void setSelectedColor(const QColor &color); void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setBrush(const QBrush &brush); void setSelectedBrush(const QBrush &brush); void setFont(const QFont &font); void setSelectedFont(const QFont &font); void setText(const QString &text); void setPositionAlignment(Qt::Alignment alignment); void setTextAlignment(Qt::Alignment alignment); void setRotation(double degrees); void setPadding(const QMargins &padding); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; QCPItemPosition * const position; QCPItemAnchor * const topLeft; QCPItemAnchor * const top; QCPItemAnchor * const topRight; QCPItemAnchor * const right; QCPItemAnchor * const bottomRight; QCPItemAnchor * const bottom; QCPItemAnchor * const bottomLeft; QCPItemAnchor * const left; protected: enum AnchorIndex {aiTopLeft, aiTop, aiTopRight, aiRight, aiBottomRight, aiBottom, aiBottomLeft, aiLeft}; // property members: QColor mColor, mSelectedColor; QPen mPen, mSelectedPen; QBrush mBrush, mSelectedBrush; QFont mFont, mSelectedFont; QString mText; Qt::Alignment mPositionAlignment; Qt::Alignment mTextAlignment; double mRotation; QMargins mPadding; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QPointF anchorPixelPosition(int anchorId) const Q_DECL_OVERRIDE; // non-virtual methods: QPointF getTextDrawPoint(const QPointF &pos, const QRectF &rect, Qt::Alignment positionAlignment) const; QFont mainFont() const; QColor mainColor() const; QPen mainPen() const; QBrush mainBrush() const; }; /* end of 'src/items/item-text.h' */ /* including file 'src/items/item-ellipse.h' */ /* modified 2021-03-29T02:30:44, size 3890 */ class QCP_LIB_DECL QCPItemEllipse : public QCPAbstractItem { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen selectedPen READ selectedPen WRITE setSelectedPen) Q_PROPERTY(QBrush brush READ brush WRITE setBrush) Q_PROPERTY(QBrush selectedBrush READ selectedBrush WRITE setSelectedBrush) /// \endcond public: explicit QCPItemEllipse(QCustomPlot *parentPlot); virtual ~QCPItemEllipse() Q_DECL_OVERRIDE; // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QBrush brush() const { return mBrush; } QBrush selectedBrush() const { return mSelectedBrush; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setBrush(const QBrush &brush); void setSelectedBrush(const QBrush &brush); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; QCPItemPosition * const topLeft; QCPItemPosition * const bottomRight; QCPItemAnchor * const topLeftRim; QCPItemAnchor * const top; QCPItemAnchor * const topRightRim; QCPItemAnchor * const right; QCPItemAnchor * const bottomRightRim; QCPItemAnchor * const bottom; QCPItemAnchor * const bottomLeftRim; QCPItemAnchor * const left; QCPItemAnchor * const center; protected: enum AnchorIndex {aiTopLeftRim, aiTop, aiTopRightRim, aiRight, aiBottomRightRim, aiBottom, aiBottomLeftRim, aiLeft, aiCenter}; // property members: QPen mPen, mSelectedPen; QBrush mBrush, mSelectedBrush; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QPointF anchorPixelPosition(int anchorId) const Q_DECL_OVERRIDE; // non-virtual methods: QPen mainPen() const; QBrush mainBrush() const; }; /* end of 'src/items/item-ellipse.h' */ /* including file 'src/items/item-pixmap.h' */ /* modified 2021-03-29T02:30:44, size 4407 */ class QCP_LIB_DECL QCPItemPixmap : public QCPAbstractItem { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap) Q_PROPERTY(bool scaled READ scaled WRITE setScaled) Q_PROPERTY(Qt::AspectRatioMode aspectRatioMode READ aspectRatioMode) Q_PROPERTY(Qt::TransformationMode transformationMode READ transformationMode) Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen selectedPen READ selectedPen WRITE setSelectedPen) /// \endcond public: explicit QCPItemPixmap(QCustomPlot *parentPlot); virtual ~QCPItemPixmap() Q_DECL_OVERRIDE; // getters: QPixmap pixmap() const { return mPixmap; } bool scaled() const { return mScaled; } Qt::AspectRatioMode aspectRatioMode() const { return mAspectRatioMode; } Qt::TransformationMode transformationMode() const { return mTransformationMode; } QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } // setters; void setPixmap(const QPixmap &pixmap); void setScaled(bool scaled, Qt::AspectRatioMode aspectRatioMode=Qt::KeepAspectRatio, Qt::TransformationMode transformationMode=Qt::SmoothTransformation); void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; QCPItemPosition * const topLeft; QCPItemPosition * const bottomRight; QCPItemAnchor * const top; QCPItemAnchor * const topRight; QCPItemAnchor * const right; QCPItemAnchor * const bottom; QCPItemAnchor * const bottomLeft; QCPItemAnchor * const left; protected: enum AnchorIndex {aiTop, aiTopRight, aiRight, aiBottom, aiBottomLeft, aiLeft}; // property members: QPixmap mPixmap; QPixmap mScaledPixmap; bool mScaled; bool mScaledPixmapInvalidated; Qt::AspectRatioMode mAspectRatioMode; Qt::TransformationMode mTransformationMode; QPen mPen, mSelectedPen; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QPointF anchorPixelPosition(int anchorId) const Q_DECL_OVERRIDE; // non-virtual methods: void updateScaledPixmap(QRect finalRect=QRect(), bool flipHorz=false, bool flipVert=false); QRect getFinalRect(bool *flippedHorz=nullptr, bool *flippedVert=nullptr) const; QPen mainPen() const; }; /* end of 'src/items/item-pixmap.h' */ /* including file 'src/items/item-tracer.h' */ /* modified 2021-03-29T02:30:44, size 4811 */ class QCP_LIB_DECL QCPItemTracer : public QCPAbstractItem { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen selectedPen READ selectedPen WRITE setSelectedPen) Q_PROPERTY(QBrush brush READ brush WRITE setBrush) Q_PROPERTY(QBrush selectedBrush READ selectedBrush WRITE setSelectedBrush) Q_PROPERTY(double size READ size WRITE setSize) Q_PROPERTY(TracerStyle style READ style WRITE setStyle) Q_PROPERTY(QCPGraph* graph READ graph WRITE setGraph) Q_PROPERTY(double graphKey READ graphKey WRITE setGraphKey) Q_PROPERTY(bool interpolating READ interpolating WRITE setInterpolating) /// \endcond public: /*! The different visual appearances a tracer item can have. Some styles size may be controlled with \ref setSize. \see setStyle */ enum TracerStyle { tsNone ///< The tracer is not visible ,tsPlus ///< A plus shaped crosshair with limited size ,tsCrosshair ///< A plus shaped crosshair which spans the complete axis rect ,tsCircle ///< A circle ,tsSquare ///< A square }; Q_ENUMS(TracerStyle) explicit QCPItemTracer(QCustomPlot *parentPlot); virtual ~QCPItemTracer() Q_DECL_OVERRIDE; // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QBrush brush() const { return mBrush; } QBrush selectedBrush() const { return mSelectedBrush; } double size() const { return mSize; } TracerStyle style() const { return mStyle; } QCPGraph *graph() const { return mGraph; } double graphKey() const { return mGraphKey; } bool interpolating() const { return mInterpolating; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setBrush(const QBrush &brush); void setSelectedBrush(const QBrush &brush); void setSize(double size); void setStyle(TracerStyle style); void setGraph(QCPGraph *graph); void setGraphKey(double key); void setInterpolating(bool enabled); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; // non-virtual methods: void updatePosition(); QCPItemPosition * const position; protected: // property members: QPen mPen, mSelectedPen; QBrush mBrush, mSelectedBrush; double mSize; TracerStyle mStyle; QCPGraph *mGraph; double mGraphKey; bool mInterpolating; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; // non-virtual methods: QPen mainPen() const; QBrush mainBrush() const; }; Q_DECLARE_METATYPE(QCPItemTracer::TracerStyle) /* end of 'src/items/item-tracer.h' */ /* including file 'src/items/item-bracket.h' */ /* modified 2021-03-29T02:30:44, size 3991 */ class QCP_LIB_DECL QCPItemBracket : public QCPAbstractItem { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QPen pen READ pen WRITE setPen) Q_PROPERTY(QPen selectedPen READ selectedPen WRITE setSelectedPen) Q_PROPERTY(double length READ length WRITE setLength) Q_PROPERTY(BracketStyle style READ style WRITE setStyle) /// \endcond public: /*! Defines the various visual shapes of the bracket item. The appearance can be further modified by \ref setLength and \ref setPen. \see setStyle */ enum BracketStyle { bsSquare ///< A brace with angled edges ,bsRound ///< A brace with round edges ,bsCurly ///< A curly brace ,bsCalligraphic ///< A curly brace with varying stroke width giving a calligraphic impression }; Q_ENUMS(BracketStyle) explicit QCPItemBracket(QCustomPlot *parentPlot); virtual ~QCPItemBracket() Q_DECL_OVERRIDE; // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } double length() const { return mLength; } BracketStyle style() const { return mStyle; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setLength(double length); void setStyle(BracketStyle style); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=nullptr) const Q_DECL_OVERRIDE; QCPItemPosition * const left; QCPItemPosition * const right; QCPItemAnchor * const center; protected: // property members: enum AnchorIndex {aiCenter}; QPen mPen, mSelectedPen; double mLength; BracketStyle mStyle; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QPointF anchorPixelPosition(int anchorId) const Q_DECL_OVERRIDE; // non-virtual methods: QPen mainPen() const; }; Q_DECLARE_METATYPE(QCPItemBracket::BracketStyle) /* end of 'src/items/item-bracket.h' */ /* including file 'src/polar/radialaxis.h' */ /* modified 2021-03-29T02:30:44, size 12227 */ class QCP_LIB_DECL QCPPolarAxisRadial : public QCPLayerable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES /// \endcond public: /*! Defines the reference of the angle at which a radial axis is tilted (\ref setAngle). */ enum AngleReference { arAbsolute ///< The axis tilt is given in absolute degrees. The zero is to the right and positive angles are measured counter-clockwise. ,arAngularAxis ///< The axis tilt is measured in the angular coordinate system given by the parent angular axis. }; Q_ENUMS(AngleReference) /*! Defines the scale of an axis. \see setScaleType */ enum ScaleType { stLinear ///< Linear scaling ,stLogarithmic ///< Logarithmic scaling with correspondingly transformed axis coordinates (possibly also \ref setTicker to a \ref QCPAxisTickerLog instance). }; Q_ENUMS(ScaleType) /*! Defines the selectable parts of an axis. \see setSelectableParts, setSelectedParts */ enum SelectablePart { spNone = 0 ///< None of the selectable parts ,spAxis = 0x001 ///< The axis backbone and tick marks ,spTickLabels = 0x002 ///< Tick labels (numbers) of this axis (as a whole, not individually) ,spAxisLabel = 0x004 ///< The axis label }; Q_ENUMS(SelectablePart) Q_FLAGS(SelectableParts) Q_DECLARE_FLAGS(SelectableParts, SelectablePart) enum LabelMode { lmUpright ///< ,lmRotated ///< }; Q_ENUMS(LabelMode) explicit QCPPolarAxisRadial(QCPPolarAxisAngular *parent); virtual ~QCPPolarAxisRadial(); // getters: bool rangeDrag() const { return mRangeDrag; } bool rangeZoom() const { return mRangeZoom; } double rangeZoomFactor() const { return mRangeZoomFactor; } QCPPolarAxisAngular *angularAxis() const { return mAngularAxis; } ScaleType scaleType() const { return mScaleType; } const QCPRange range() const { return mRange; } bool rangeReversed() const { return mRangeReversed; } double angle() const { return mAngle; } AngleReference angleReference() const { return mAngleReference; } QSharedPointer ticker() const { return mTicker; } bool ticks() const { return mTicks; } bool tickLabels() const { return mTickLabels; } int tickLabelPadding() const { return mLabelPainter.padding(); } QFont tickLabelFont() const { return mTickLabelFont; } QColor tickLabelColor() const { return mTickLabelColor; } double tickLabelRotation() const { return mLabelPainter.rotation(); } LabelMode tickLabelMode() const; QString numberFormat() const; int numberPrecision() const { return mNumberPrecision; } QVector tickVector() const { return mTickVector; } QVector subTickVector() const { return mSubTickVector; } QVector tickVectorLabels() const { return mTickVectorLabels; } int tickLengthIn() const; int tickLengthOut() const; bool subTicks() const { return mSubTicks; } int subTickLengthIn() const; int subTickLengthOut() const; QPen basePen() const { return mBasePen; } QPen tickPen() const { return mTickPen; } QPen subTickPen() const { return mSubTickPen; } QFont labelFont() const { return mLabelFont; } QColor labelColor() const { return mLabelColor; } QString label() const { return mLabel; } int labelPadding() const; SelectableParts selectedParts() const { return mSelectedParts; } SelectableParts selectableParts() const { return mSelectableParts; } QFont selectedTickLabelFont() const { return mSelectedTickLabelFont; } QFont selectedLabelFont() const { return mSelectedLabelFont; } QColor selectedTickLabelColor() const { return mSelectedTickLabelColor; } QColor selectedLabelColor() const { return mSelectedLabelColor; } QPen selectedBasePen() const { return mSelectedBasePen; } QPen selectedTickPen() const { return mSelectedTickPen; } QPen selectedSubTickPen() const { return mSelectedSubTickPen; } // setters: void setRangeDrag(bool enabled); void setRangeZoom(bool enabled); void setRangeZoomFactor(double factor); Q_SLOT void setScaleType(QCPPolarAxisRadial::ScaleType type); Q_SLOT void setRange(const QCPRange &range); void setRange(double lower, double upper); void setRange(double position, double size, Qt::AlignmentFlag alignment); void setRangeLower(double lower); void setRangeUpper(double upper); void setRangeReversed(bool reversed); void setAngle(double degrees); void setAngleReference(AngleReference reference); void setTicker(QSharedPointer ticker); void setTicks(bool show); void setTickLabels(bool show); void setTickLabelPadding(int padding); void setTickLabelFont(const QFont &font); void setTickLabelColor(const QColor &color); void setTickLabelRotation(double degrees); void setTickLabelMode(LabelMode mode); void setNumberFormat(const QString &formatCode); void setNumberPrecision(int precision); void setTickLength(int inside, int outside=0); void setTickLengthIn(int inside); void setTickLengthOut(int outside); void setSubTicks(bool show); void setSubTickLength(int inside, int outside=0); void setSubTickLengthIn(int inside); void setSubTickLengthOut(int outside); void setBasePen(const QPen &pen); void setTickPen(const QPen &pen); void setSubTickPen(const QPen &pen); void setLabelFont(const QFont &font); void setLabelColor(const QColor &color); void setLabel(const QString &str); void setLabelPadding(int padding); void setSelectedTickLabelFont(const QFont &font); void setSelectedLabelFont(const QFont &font); void setSelectedTickLabelColor(const QColor &color); void setSelectedLabelColor(const QColor &color); void setSelectedBasePen(const QPen &pen); void setSelectedTickPen(const QPen &pen); void setSelectedSubTickPen(const QPen &pen); Q_SLOT void setSelectableParts(const QCPPolarAxisRadial::SelectableParts &selectableParts); Q_SLOT void setSelectedParts(const QCPPolarAxisRadial::SelectableParts &selectedParts); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const Q_DECL_OVERRIDE; // non-property methods: void moveRange(double diff); void scaleRange(double factor); void scaleRange(double factor, double center); void rescale(bool onlyVisiblePlottables=false); void pixelToCoord(QPointF pixelPos, double &angleCoord, double &radiusCoord) const; QPointF coordToPixel(double angleCoord, double radiusCoord) const; double coordToRadius(double coord) const; double radiusToCoord(double radius) const; SelectablePart getPartAt(const QPointF &pos) const; signals: void rangeChanged(const QCPRange &newRange); void rangeChanged(const QCPRange &newRange, const QCPRange &oldRange); void scaleTypeChanged(QCPPolarAxisRadial::ScaleType scaleType); void selectionChanged(const QCPPolarAxisRadial::SelectableParts &parts); void selectableChanged(const QCPPolarAxisRadial::SelectableParts &parts); protected: // property members: bool mRangeDrag; bool mRangeZoom; double mRangeZoomFactor; // axis base: QCPPolarAxisAngular *mAngularAxis; double mAngle; AngleReference mAngleReference; SelectableParts mSelectableParts, mSelectedParts; QPen mBasePen, mSelectedBasePen; // axis label: int mLabelPadding; QString mLabel; QFont mLabelFont, mSelectedLabelFont; QColor mLabelColor, mSelectedLabelColor; // tick labels: //int mTickLabelPadding; in label painter bool mTickLabels; //double mTickLabelRotation; in label painter QFont mTickLabelFont, mSelectedTickLabelFont; QColor mTickLabelColor, mSelectedTickLabelColor; int mNumberPrecision; QLatin1Char mNumberFormatChar; bool mNumberBeautifulPowers; bool mNumberMultiplyCross; // ticks and subticks: bool mTicks; bool mSubTicks; int mTickLengthIn, mTickLengthOut, mSubTickLengthIn, mSubTickLengthOut; QPen mTickPen, mSelectedTickPen; QPen mSubTickPen, mSelectedSubTickPen; // scale and range: QCPRange mRange; bool mRangeReversed; ScaleType mScaleType; // non-property members: QPointF mCenter; double mRadius; QSharedPointer mTicker; QVector mTickVector; QVector mTickVectorLabels; QVector mSubTickVector; bool mDragging; QCPRange mDragStartRange; QCP::AntialiasedElements mAADragBackup, mNotAADragBackup; QCPLabelPainterPrivate mLabelPainter; // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QCP::Interaction selectionCategory() const Q_DECL_OVERRIDE; // events: virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged) Q_DECL_OVERRIDE; virtual void deselectEvent(bool *selectionStateChanged) Q_DECL_OVERRIDE; // mouse events: virtual void mousePressEvent(QMouseEvent *event, const QVariant &details) Q_DECL_OVERRIDE; virtual void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; // non-virtual methods: void updateGeometry(const QPointF ¢er, double radius); void setupTickVectors(); QPen getBasePen() const; QPen getTickPen() const; QPen getSubTickPen() const; QFont getTickLabelFont() const; QFont getLabelFont() const; QColor getTickLabelColor() const; QColor getLabelColor() const; private: Q_DISABLE_COPY(QCPPolarAxisRadial) friend class QCustomPlot; friend class QCPPolarAxisAngular; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCPPolarAxisRadial::SelectableParts) Q_DECLARE_METATYPE(QCPPolarAxisRadial::AngleReference) Q_DECLARE_METATYPE(QCPPolarAxisRadial::ScaleType) Q_DECLARE_METATYPE(QCPPolarAxisRadial::SelectablePart) /* end of 'src/polar/radialaxis.h' */ /* including file 'src/polar/layoutelement-angularaxis.h' */ /* modified 2021-03-29T02:30:44, size 13461 */ class QCP_LIB_DECL QCPPolarAxisAngular : public QCPLayoutElement { Q_OBJECT /// \cond INCLUDE_QPROPERTIES /// \endcond public: /*! Defines the selectable parts of an axis. \see setSelectableParts, setSelectedParts */ enum SelectablePart { spNone = 0 ///< None of the selectable parts ,spAxis = 0x001 ///< The axis backbone and tick marks ,spTickLabels = 0x002 ///< Tick labels (numbers) of this axis (as a whole, not individually) ,spAxisLabel = 0x004 ///< The axis label }; Q_ENUMS(SelectablePart) Q_FLAGS(SelectableParts) Q_DECLARE_FLAGS(SelectableParts, SelectablePart) /*! TODO */ enum LabelMode { lmUpright ///< ,lmRotated ///< }; Q_ENUMS(LabelMode) explicit QCPPolarAxisAngular(QCustomPlot *parentPlot); virtual ~QCPPolarAxisAngular(); // getters: QPixmap background() const { return mBackgroundPixmap; } QBrush backgroundBrush() const { return mBackgroundBrush; } bool backgroundScaled() const { return mBackgroundScaled; } Qt::AspectRatioMode backgroundScaledMode() const { return mBackgroundScaledMode; } bool rangeDrag() const { return mRangeDrag; } bool rangeZoom() const { return mRangeZoom; } double rangeZoomFactor() const { return mRangeZoomFactor; } const QCPRange range() const { return mRange; } bool rangeReversed() const { return mRangeReversed; } double angle() const { return mAngle; } QSharedPointer ticker() const { return mTicker; } bool ticks() const { return mTicks; } bool tickLabels() const { return mTickLabels; } int tickLabelPadding() const { return mLabelPainter.padding(); } QFont tickLabelFont() const { return mTickLabelFont; } QColor tickLabelColor() const { return mTickLabelColor; } double tickLabelRotation() const { return mLabelPainter.rotation(); } LabelMode tickLabelMode() const; QString numberFormat() const; int numberPrecision() const { return mNumberPrecision; } QVector tickVector() const { return mTickVector; } QVector tickVectorLabels() const { return mTickVectorLabels; } int tickLengthIn() const { return mTickLengthIn; } int tickLengthOut() const { return mTickLengthOut; } bool subTicks() const { return mSubTicks; } int subTickLengthIn() const { return mSubTickLengthIn; } int subTickLengthOut() const { return mSubTickLengthOut; } QPen basePen() const { return mBasePen; } QPen tickPen() const { return mTickPen; } QPen subTickPen() const { return mSubTickPen; } QFont labelFont() const { return mLabelFont; } QColor labelColor() const { return mLabelColor; } QString label() const { return mLabel; } int labelPadding() const { return mLabelPadding; } SelectableParts selectedParts() const { return mSelectedParts; } SelectableParts selectableParts() const { return mSelectableParts; } QFont selectedTickLabelFont() const { return mSelectedTickLabelFont; } QFont selectedLabelFont() const { return mSelectedLabelFont; } QColor selectedTickLabelColor() const { return mSelectedTickLabelColor; } QColor selectedLabelColor() const { return mSelectedLabelColor; } QPen selectedBasePen() const { return mSelectedBasePen; } QPen selectedTickPen() const { return mSelectedTickPen; } QPen selectedSubTickPen() const { return mSelectedSubTickPen; } QCPPolarGrid *grid() const { return mGrid; } // setters: void setBackground(const QPixmap &pm); void setBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode=Qt::KeepAspectRatioByExpanding); void setBackground(const QBrush &brush); void setBackgroundScaled(bool scaled); void setBackgroundScaledMode(Qt::AspectRatioMode mode); void setRangeDrag(bool enabled); void setRangeZoom(bool enabled); void setRangeZoomFactor(double factor); Q_SLOT void setRange(const QCPRange &range); void setRange(double lower, double upper); void setRange(double position, double size, Qt::AlignmentFlag alignment); void setRangeLower(double lower); void setRangeUpper(double upper); void setRangeReversed(bool reversed); void setAngle(double degrees); void setTicker(QSharedPointer ticker); void setTicks(bool show); void setTickLabels(bool show); void setTickLabelPadding(int padding); void setTickLabelFont(const QFont &font); void setTickLabelColor(const QColor &color); void setTickLabelRotation(double degrees); void setTickLabelMode(LabelMode mode); void setNumberFormat(const QString &formatCode); void setNumberPrecision(int precision); void setTickLength(int inside, int outside=0); void setTickLengthIn(int inside); void setTickLengthOut(int outside); void setSubTicks(bool show); void setSubTickLength(int inside, int outside=0); void setSubTickLengthIn(int inside); void setSubTickLengthOut(int outside); void setBasePen(const QPen &pen); void setTickPen(const QPen &pen); void setSubTickPen(const QPen &pen); void setLabelFont(const QFont &font); void setLabelColor(const QColor &color); void setLabel(const QString &str); void setLabelPadding(int padding); void setLabelPosition(Qt::AlignmentFlag position); void setSelectedTickLabelFont(const QFont &font); void setSelectedLabelFont(const QFont &font); void setSelectedTickLabelColor(const QColor &color); void setSelectedLabelColor(const QColor &color); void setSelectedBasePen(const QPen &pen); void setSelectedTickPen(const QPen &pen); void setSelectedSubTickPen(const QPen &pen); Q_SLOT void setSelectableParts(const QCPPolarAxisAngular::SelectableParts &selectableParts); Q_SLOT void setSelectedParts(const QCPPolarAxisAngular::SelectableParts &selectedParts); // reimplemented virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const Q_DECL_OVERRIDE; virtual void update(UpdatePhase phase) Q_DECL_OVERRIDE; virtual QList elements(bool recursive) const Q_DECL_OVERRIDE; // non-property methods: bool removeGraph(QCPPolarGraph *graph); int radialAxisCount() const; QCPPolarAxisRadial *radialAxis(int index=0) const; QList radialAxes() const; QCPPolarAxisRadial *addRadialAxis(QCPPolarAxisRadial *axis=0); bool removeRadialAxis(QCPPolarAxisRadial *axis); QCPLayoutInset *insetLayout() const { return mInsetLayout; } QRegion exactClipRegion() const; void moveRange(double diff); void scaleRange(double factor); void scaleRange(double factor, double center); void rescale(bool onlyVisiblePlottables=false); double coordToAngleRad(double coord) const { return mAngleRad+(coord-mRange.lower)/mRange.size()*(mRangeReversed ? -2.0*M_PI : 2.0*M_PI); } // mention in doc that return doesn't wrap double angleRadToCoord(double angleRad) const { return mRange.lower+(angleRad-mAngleRad)/(mRangeReversed ? -2.0*M_PI : 2.0*M_PI)*mRange.size(); } void pixelToCoord(QPointF pixelPos, double &angleCoord, double &radiusCoord) const; QPointF coordToPixel(double angleCoord, double radiusCoord) const; SelectablePart getPartAt(const QPointF &pos) const; // read-only interface imitating a QRect: int left() const { return mRect.left(); } int right() const { return mRect.right(); } int top() const { return mRect.top(); } int bottom() const { return mRect.bottom(); } int width() const { return mRect.width(); } int height() const { return mRect.height(); } QSize size() const { return mRect.size(); } QPoint topLeft() const { return mRect.topLeft(); } QPoint topRight() const { return mRect.topRight(); } QPoint bottomLeft() const { return mRect.bottomLeft(); } QPoint bottomRight() const { return mRect.bottomRight(); } QPointF center() const { return mCenter; } double radius() const { return mRadius; } signals: void rangeChanged(const QCPRange &newRange); void rangeChanged(const QCPRange &newRange, const QCPRange &oldRange); void selectionChanged(const QCPPolarAxisAngular::SelectableParts &parts); void selectableChanged(const QCPPolarAxisAngular::SelectableParts &parts); protected: // property members: QBrush mBackgroundBrush; QPixmap mBackgroundPixmap; QPixmap mScaledBackgroundPixmap; bool mBackgroundScaled; Qt::AspectRatioMode mBackgroundScaledMode; QCPLayoutInset *mInsetLayout; bool mRangeDrag; bool mRangeZoom; double mRangeZoomFactor; // axis base: double mAngle, mAngleRad; SelectableParts mSelectableParts, mSelectedParts; QPen mBasePen, mSelectedBasePen; // axis label: int mLabelPadding; QString mLabel; QFont mLabelFont, mSelectedLabelFont; QColor mLabelColor, mSelectedLabelColor; // tick labels: //int mTickLabelPadding; in label painter bool mTickLabels; //double mTickLabelRotation; in label painter QFont mTickLabelFont, mSelectedTickLabelFont; QColor mTickLabelColor, mSelectedTickLabelColor; int mNumberPrecision; QLatin1Char mNumberFormatChar; bool mNumberBeautifulPowers; bool mNumberMultiplyCross; // ticks and subticks: bool mTicks; bool mSubTicks; int mTickLengthIn, mTickLengthOut, mSubTickLengthIn, mSubTickLengthOut; QPen mTickPen, mSelectedTickPen; QPen mSubTickPen, mSelectedSubTickPen; // scale and range: QCPRange mRange; bool mRangeReversed; // non-property members: QPointF mCenter; double mRadius; QList mRadialAxes; QCPPolarGrid *mGrid; QList mGraphs; QSharedPointer mTicker; QVector mTickVector; QVector mTickVectorLabels; QVector mTickVectorCosSin; QVector mSubTickVector; QVector mSubTickVectorCosSin; bool mDragging; QCPRange mDragAngularStart; QList mDragRadialStart; QCP::AntialiasedElements mAADragBackup, mNotAADragBackup; QCPLabelPainterPrivate mLabelPainter; // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QCP::Interaction selectionCategory() const Q_DECL_OVERRIDE; // events: virtual void mousePressEvent(QMouseEvent *event, const QVariant &details) Q_DECL_OVERRIDE; virtual void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) Q_DECL_OVERRIDE; virtual void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; // non-virtual methods: bool registerPolarGraph(QCPPolarGraph *graph); void drawBackground(QCPPainter *painter, const QPointF ¢er, double radius); void setupTickVectors(); QPen getBasePen() const; QPen getTickPen() const; QPen getSubTickPen() const; QFont getTickLabelFont() const; QFont getLabelFont() const; QColor getTickLabelColor() const; QColor getLabelColor() const; private: Q_DISABLE_COPY(QCPPolarAxisAngular) friend class QCustomPlot; friend class QCPPolarGrid; friend class QCPPolarGraph; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCPPolarAxisAngular::SelectableParts) Q_DECLARE_METATYPE(QCPPolarAxisAngular::SelectablePart) /* end of 'src/polar/layoutelement-angularaxis.h' */ /* including file 'src/polar/polargrid.h' */ /* modified 2021-03-29T02:30:44, size 4506 */ class QCP_LIB_DECL QCPPolarGrid :public QCPLayerable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES /// \endcond public: /*! TODO */ enum GridType { gtAngular = 0x01 ///< ,gtRadial = 0x02 ///< ,gtAll = 0xFF ///< ,gtNone = 0x00 ///< }; Q_ENUMS(GridType) Q_FLAGS(GridTypes) Q_DECLARE_FLAGS(GridTypes, GridType) explicit QCPPolarGrid(QCPPolarAxisAngular *parentAxis); // getters: QCPPolarAxisRadial *radialAxis() const { return mRadialAxis.data(); } GridTypes type() const { return mType; } GridTypes subGridType() const { return mSubGridType; } bool antialiasedSubGrid() const { return mAntialiasedSubGrid; } bool antialiasedZeroLine() const { return mAntialiasedZeroLine; } QPen angularPen() const { return mAngularPen; } QPen angularSubGridPen() const { return mAngularSubGridPen; } QPen radialPen() const { return mRadialPen; } QPen radialSubGridPen() const { return mRadialSubGridPen; } QPen radialZeroLinePen() const { return mRadialZeroLinePen; } // setters: void setRadialAxis(QCPPolarAxisRadial *axis); void setType(GridTypes type); void setSubGridType(GridTypes type); void setAntialiasedSubGrid(bool enabled); void setAntialiasedZeroLine(bool enabled); void setAngularPen(const QPen &pen); void setAngularSubGridPen(const QPen &pen); void setRadialPen(const QPen &pen); void setRadialSubGridPen(const QPen &pen); void setRadialZeroLinePen(const QPen &pen); protected: // property members: GridTypes mType; GridTypes mSubGridType; bool mAntialiasedSubGrid, mAntialiasedZeroLine; QPen mAngularPen, mAngularSubGridPen; QPen mRadialPen, mRadialSubGridPen, mRadialZeroLinePen; // non-property members: QCPPolarAxisAngular *mParentAxis; QPointer mRadialAxis; // reimplemented virtual methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const Q_DECL_OVERRIDE; virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; // non-virtual methods: void drawRadialGrid(QCPPainter *painter, const QPointF ¢er, const QVector &coords, const QPen &pen, const QPen &zeroPen=Qt::NoPen); void drawAngularGrid(QCPPainter *painter, const QPointF ¢er, double radius, const QVector &ticksCosSin, const QPen &pen); private: Q_DISABLE_COPY(QCPPolarGrid) }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCPPolarGrid::GridTypes) Q_DECLARE_METATYPE(QCPPolarGrid::GridType) /* end of 'src/polar/polargrid.h' */ /* including file 'src/polar/polargraph.h' */ /* modified 2021-03-29T02:30:44, size 9606 */ class QCP_LIB_DECL QCPPolarLegendItem : public QCPAbstractLegendItem { Q_OBJECT public: QCPPolarLegendItem(QCPLegend *parent, QCPPolarGraph *graph); // getters: QCPPolarGraph *polarGraph() { return mPolarGraph; } protected: // property members: QCPPolarGraph *mPolarGraph; // reimplemented virtual methods: virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE; virtual QSize minimumOuterSizeHint() const Q_DECL_OVERRIDE; // non-virtual methods: QPen getIconBorderPen() const; QColor getTextColor() const; QFont getFont() const; }; class QCP_LIB_DECL QCPPolarGraph : public QCPLayerable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES /// \endcond public: /*! Defines how the graph's line is represented visually in the plot. The line is drawn with the current pen of the graph (\ref setPen). \see setLineStyle */ enum LineStyle { lsNone ///< data points are not connected with any lines (e.g. data only represented ///< with symbols according to the scatter style, see \ref setScatterStyle) ,lsLine ///< data points are connected by a straight line }; Q_ENUMS(LineStyle) QCPPolarGraph(QCPPolarAxisAngular *keyAxis, QCPPolarAxisRadial *valueAxis); virtual ~QCPPolarGraph(); // getters: QString name() const { return mName; } bool antialiasedFill() const { return mAntialiasedFill; } bool antialiasedScatters() const { return mAntialiasedScatters; } QPen pen() const { return mPen; } QBrush brush() const { return mBrush; } bool periodic() const { return mPeriodic; } QCPPolarAxisAngular *keyAxis() const { return mKeyAxis.data(); } QCPPolarAxisRadial *valueAxis() const { return mValueAxis.data(); } QCP::SelectionType selectable() const { return mSelectable; } bool selected() const { return !mSelection.isEmpty(); } QCPDataSelection selection() const { return mSelection; } //QCPSelectionDecorator *selectionDecorator() const { return mSelectionDecorator; } QSharedPointer data() const { return mDataContainer; } LineStyle lineStyle() const { return mLineStyle; } QCPScatterStyle scatterStyle() const { return mScatterStyle; } // setters: void setName(const QString &name); void setAntialiasedFill(bool enabled); void setAntialiasedScatters(bool enabled); void setPen(const QPen &pen); void setBrush(const QBrush &brush); void setPeriodic(bool enabled); void setKeyAxis(QCPPolarAxisAngular *axis); void setValueAxis(QCPPolarAxisRadial *axis); Q_SLOT void setSelectable(QCP::SelectionType selectable); Q_SLOT void setSelection(QCPDataSelection selection); //void setSelectionDecorator(QCPSelectionDecorator *decorator); void setData(QSharedPointer data); void setData(const QVector &keys, const QVector &values, bool alreadySorted=false); void setLineStyle(LineStyle ls); void setScatterStyle(const QCPScatterStyle &style); // non-property methods: void addData(const QVector &keys, const QVector &values, bool alreadySorted=false); void addData(double key, double value); void coordsToPixels(double key, double value, double &x, double &y) const; const QPointF coordsToPixels(double key, double value) const; void pixelsToCoords(double x, double y, double &key, double &value) const; void pixelsToCoords(const QPointF &pixelPos, double &key, double &value) const; void rescaleAxes(bool onlyEnlarge=false) const; void rescaleKeyAxis(bool onlyEnlarge=false) const; void rescaleValueAxis(bool onlyEnlarge=false, bool inKeyRange=false) const; bool addToLegend(QCPLegend *legend); bool addToLegend(); bool removeFromLegend(QCPLegend *legend) const; bool removeFromLegend() const; // introduced virtual methods: virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const; // actually introduced in QCPLayerable as non-pure, but we want to force reimplementation for plottables virtual QCPPlottableInterface1D *interface1D() { return 0; } // TODO: return this later, when QCPAbstractPolarPlottable is created virtual QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const; virtual QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const; signals: void selectionChanged(bool selected); void selectionChanged(const QCPDataSelection &selection); void selectableChanged(QCP::SelectionType selectable); protected: // property members: QSharedPointer mDataContainer; LineStyle mLineStyle; QCPScatterStyle mScatterStyle; QString mName; bool mAntialiasedFill, mAntialiasedScatters; QPen mPen; QBrush mBrush; bool mPeriodic; QPointer mKeyAxis; QPointer mValueAxis; QCP::SelectionType mSelectable; QCPDataSelection mSelection; //QCPSelectionDecorator *mSelectionDecorator; // introduced virtual methods (later reimplemented TODO from QCPAbstractPolarPlottable): virtual QRect clipRect() const; virtual void draw(QCPPainter *painter); virtual QCP::Interaction selectionCategory() const; void applyDefaultAntialiasingHint(QCPPainter *painter) const; // events: virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged); virtual void deselectEvent(bool *selectionStateChanged); // virtual drawing helpers: virtual void drawLinePlot(QCPPainter *painter, const QVector &lines) const; virtual void drawFill(QCPPainter *painter, QVector *lines) const; virtual void drawScatterPlot(QCPPainter *painter, const QVector &scatters, const QCPScatterStyle &style) const; // introduced virtual methods: virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const; // non-virtual methods: void applyFillAntialiasingHint(QCPPainter *painter) const; void applyScattersAntialiasingHint(QCPPainter *painter) const; double pointDistance(const QPointF &pixelPoint, QCPGraphDataContainer::const_iterator &closestData) const; // drawing helpers: virtual int dataCount() const; void getDataSegments(QList &selectedSegments, QList &unselectedSegments) const; void drawPolyline(QCPPainter *painter, const QVector &lineData) const; void getVisibleDataBounds(QCPGraphDataContainer::const_iterator &begin, QCPGraphDataContainer::const_iterator &end, const QCPDataRange &rangeRestriction) const; void getLines(QVector *lines, const QCPDataRange &dataRange) const; void getScatters(QVector *scatters, const QCPDataRange &dataRange) const; void getOptimizedLineData(QVector *lineData, const QCPGraphDataContainer::const_iterator &begin, const QCPGraphDataContainer::const_iterator &end) const; void getOptimizedScatterData(QVector *scatterData, QCPGraphDataContainer::const_iterator begin, QCPGraphDataContainer::const_iterator end) const; QVector dataToLines(const QVector &data) const; private: Q_DISABLE_COPY(QCPPolarGraph) friend class QCPPolarLegendItem; }; /* end of 'src/polar/polargraph.h' */ #endif // QCUSTOMPLOT_H sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/000077500000000000000000000000001463772530400224405ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/CMakeLists.txt000066400000000000000000000011031463772530400251730ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.12.2) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(Qt5 REQUIRED COMPONENTS Widgets) set(QHEXEDIT_SRC src/qhexedit.cpp src/chunks.cpp src/commands.cpp ) set(QHEXEDIT_HDR src/chunks.h src/commands.h ) set(QHEXEDIT_MOC_HDR src/qhexedit.h src/commands.h ) add_library(qhexedit ${QHEXEDIT_SRC} ${QHEXEDIT_HDR} ${QHEXEDIT_MOC_HDR} ${QHEXEDIT_MOC}) target_include_directories(qhexedit INTERFACE src) target_link_libraries(qhexedit Qt5::Widgets) add_library(QHexEdit::QHexEdit ALIAS qhexedit) sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/src/000077500000000000000000000000001463772530400232275ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/src/chunks.cpp000066400000000000000000000204441463772530400252320ustar00rootroot00000000000000#include "chunks.h" #include #define NORMAL 0 #define HIGHLIGHTED 1 #define BUFFER_SIZE 0x10000 #define CHUNK_SIZE 0x1000 #define READ_CHUNK_MASK Q_INT64_C(0xfffffffffffff000) // ***************************************** Constructors and file settings Chunks::Chunks(QObject *parent): QObject(parent) { QBuffer *buf = new QBuffer(this); setIODevice(*buf); } Chunks::Chunks(QIODevice &ioDevice, QObject *parent): QObject(parent) { setIODevice(ioDevice); } bool Chunks::setIODevice(QIODevice &ioDevice) { _ioDevice = &ioDevice; bool ok = _ioDevice->open(QIODevice::ReadOnly); if (ok) // Try to open IODevice { _size = _ioDevice->size(); _ioDevice->close(); } else // Fallback is an empty buffer { QBuffer *buf = new QBuffer(this); _ioDevice = buf; _size = 0; } _chunks.clear(); _pos = 0; return ok; } // ***************************************** Getting data out of Chunks QByteArray Chunks::data(qint64 pos, qint64 maxSize, QByteArray *highlighted) { qint64 ioDelta = 0; int chunkIdx = 0; Chunk chunk; QByteArray buffer; // Do some checks and some arrangements if (highlighted) highlighted->clear(); if (pos >= _size) return buffer; if (maxSize < 0) maxSize = _size; else if ((pos + maxSize) > _size) maxSize = _size - pos; _ioDevice->open(QIODevice::ReadOnly); while (maxSize > 0) { chunk.absPos = LLONG_MAX; bool chunksLoopOngoing = true; while ((chunkIdx < _chunks.count()) && chunksLoopOngoing) { // In this section, we track changes before our required data and // we take the editdet data, if availible. ioDelta is a difference // counter to justify the read pointer to the original data, if // data in between was deleted or inserted. chunk = _chunks[chunkIdx]; if (chunk.absPos > pos) chunksLoopOngoing = false; else { chunkIdx += 1; qint64 count; qint64 chunkOfs = pos - chunk.absPos; if (maxSize > ((qint64)chunk.data.size() - chunkOfs)) { count = (qint64)chunk.data.size() - chunkOfs; ioDelta += CHUNK_SIZE - chunk.data.size(); } else count = maxSize; if (count > 0) { buffer += chunk.data.mid(chunkOfs, (int)count); maxSize -= count; pos += count; if (highlighted) *highlighted += chunk.dataChanged.mid(chunkOfs, (int)count); } } } if ((maxSize > 0) && (pos < chunk.absPos)) { // In this section, we read data from the original source. This only will // happen, whe no copied data is available qint64 byteCount; QByteArray readBuffer; if ((chunk.absPos - pos) > maxSize) byteCount = maxSize; else byteCount = chunk.absPos - pos; maxSize -= byteCount; _ioDevice->seek(pos + ioDelta); readBuffer = _ioDevice->read(byteCount); buffer += readBuffer; if (highlighted) *highlighted += QByteArray(readBuffer.size(), NORMAL); pos += readBuffer.size(); } } _ioDevice->close(); return buffer; } bool Chunks::write(QIODevice &iODevice, qint64 pos, qint64 count) { if (count == -1) count = _size; bool ok = iODevice.open(QIODevice::WriteOnly); if (ok) { for (qint64 idx=pos; idx < count; idx += BUFFER_SIZE) { QByteArray ba = data(idx, BUFFER_SIZE); iODevice.write(ba); } iODevice.close(); } return ok; } // ***************************************** Set and get highlighting infos void Chunks::setDataChanged(qint64 pos, bool dataChanged) { if ((pos < 0) || (pos >= _size)) return; int chunkIdx = getChunkIndex(pos); qint64 posInBa = pos - _chunks[chunkIdx].absPos; _chunks[chunkIdx].dataChanged[(int)posInBa] = char(dataChanged); } bool Chunks::dataChanged(qint64 pos) { QByteArray highlighted; data(pos, 1, &highlighted); return bool(highlighted.at(0)); } // ***************************************** Search API qint64 Chunks::indexOf(const QByteArray &ba, qint64 from) { qint64 result = -1; QByteArray buffer; for (qint64 pos=from; (pos < _size) && (result < 0); pos += BUFFER_SIZE) { buffer = data(pos, BUFFER_SIZE + ba.size() - 1); int findPos = buffer.indexOf(ba); if (findPos >= 0) result = pos + (qint64)findPos; } return result; } qint64 Chunks::lastIndexOf(const QByteArray &ba, qint64 from) { qint64 result = -1; QByteArray buffer; for (qint64 pos=from; (pos > 0) && (result < 0); pos -= BUFFER_SIZE) { qint64 sPos = pos - BUFFER_SIZE - (qint64)ba.size() + 1; if (sPos < 0) sPos = 0; buffer = data(sPos, pos - sPos); int findPos = buffer.lastIndexOf(ba); if (findPos >= 0) result = sPos + (qint64)findPos; } return result; } // ***************************************** Char manipulations bool Chunks::insert(qint64 pos, char b) { if ((pos < 0) || (pos > _size)) return false; int chunkIdx; if (pos == _size) chunkIdx = getChunkIndex(pos-1); else chunkIdx = getChunkIndex(pos); qint64 posInBa = pos - _chunks[chunkIdx].absPos; _chunks[chunkIdx].data.insert(posInBa, b); _chunks[chunkIdx].dataChanged.insert(posInBa, char(1)); for (int idx=chunkIdx+1; idx < _chunks.size(); idx++) _chunks[idx].absPos += 1; _size += 1; _pos = pos; return true; } bool Chunks::overwrite(qint64 pos, char b) { if ((pos < 0) || (pos >= _size)) return false; int chunkIdx = getChunkIndex(pos); qint64 posInBa = pos - _chunks[chunkIdx].absPos; _chunks[chunkIdx].data[(int)posInBa] = b; _chunks[chunkIdx].dataChanged[(int)posInBa] = char(1); _pos = pos; return true; } bool Chunks::removeAt(qint64 pos) { if ((pos < 0) || (pos >= _size)) return false; int chunkIdx = getChunkIndex(pos); qint64 posInBa = pos - _chunks[chunkIdx].absPos; _chunks[chunkIdx].data.remove(posInBa, 1); _chunks[chunkIdx].dataChanged.remove(posInBa, 1); for (int idx=chunkIdx+1; idx < _chunks.size(); idx++) _chunks[idx].absPos -= 1; _size -= 1; _pos = pos; return true; } // ***************************************** Utility functions char Chunks::operator[](qint64 pos) { return data(pos, 1)[0]; } qint64 Chunks::pos() { return _pos; } qint64 Chunks::size() { return _size; } int Chunks::getChunkIndex(qint64 absPos) { // This routine checks, if there is already a copied chunk available. If os, it // returns a reference to it. If there is no copied chunk available, original // data will be copied into a new chunk. int foundIdx = -1; int insertIdx = 0; qint64 ioDelta = 0; for (int idx=0; idx < _chunks.size(); idx++) { Chunk chunk = _chunks[idx]; if ((absPos >= chunk.absPos) && (absPos < (chunk.absPos + chunk.data.size()))) { foundIdx = idx; break; } if (absPos < chunk.absPos) { insertIdx = idx; break; } ioDelta += chunk.data.size() - CHUNK_SIZE; insertIdx = idx + 1; } if (foundIdx == -1) { Chunk newChunk; qint64 readAbsPos = absPos - ioDelta; qint64 readPos = (readAbsPos & READ_CHUNK_MASK); _ioDevice->open(QIODevice::ReadOnly); _ioDevice->seek(readPos); newChunk.data = _ioDevice->read(CHUNK_SIZE); _ioDevice->close(); newChunk.absPos = absPos - (readAbsPos - readPos); newChunk.dataChanged = QByteArray(newChunk.data.size(), char(0)); _chunks.insert(insertIdx, newChunk); foundIdx = insertIdx; } return foundIdx; } #ifdef MODUL_TEST int Chunks::chunkSize() { return _chunks.size(); } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/src/chunks.h000066400000000000000000000037451463772530400247040ustar00rootroot00000000000000#ifndef CHUNKS_H #define CHUNKS_H /** \cond docNever */ /*! The Chunks class is the storage backend for QHexEdit. * * When QHexEdit loads data, Chunks access them using a QIODevice interface. When the app uses * a QByteArray interface, QBuffer is used to provide again a QIODevice like interface. No data * will be changed, therefore Chunks opens the QIODevice in QIODevice::ReadOnly mode. After every * access Chunks closes the QIODevice, that's why external applications can overwrite files while * QHexEdit shows them. * * When the the user starts to edit the data, Chunks creates a local copy of a chunk of data (4 * kilobytes) and notes all changes there. Parallel to that chunk, there is a second chunk, * which keep track of which bytes are changed and which not. * */ #include struct Chunk { QByteArray data; QByteArray dataChanged; qint64 absPos; }; class Chunks: public QObject { Q_OBJECT public: // Constructors and file settings Chunks(QObject *parent); Chunks(QIODevice &ioDevice, QObject *parent); bool setIODevice(QIODevice &ioDevice); // Getting data out of Chunks QByteArray data(qint64 pos=0, qint64 count=-1, QByteArray *highlighted=0); bool write(QIODevice &iODevice, qint64 pos=0, qint64 count=-1); // Set and get highlighting infos void setDataChanged(qint64 pos, bool dataChanged); bool dataChanged(qint64 pos); // Search API qint64 indexOf(const QByteArray &ba, qint64 from); qint64 lastIndexOf(const QByteArray &ba, qint64 from); // Char manipulations bool insert(qint64 pos, char b); bool overwrite(qint64 pos, char b); bool removeAt(qint64 pos); // Utility functions char operator[](qint64 pos); qint64 pos(); qint64 size(); private: int getChunkIndex(qint64 absPos); QIODevice * _ioDevice; qint64 _pos; qint64 _size; QList _chunks; #ifdef MODUL_TEST public: int chunkSize(); #endif }; /** \endcond docNever */ #endif // CHUNKS_H sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/src/commands.cpp000066400000000000000000000100411463772530400255300ustar00rootroot00000000000000#include "commands.h" #include // Helper class to store single byte commands class CharCommand : public QUndoCommand { public: enum CCmd {insert, removeAt, overwrite}; CharCommand(Chunks * chunks, CCmd cmd, qint64 charPos, char newChar, QUndoCommand *parent=0); void undo(); void redo(); bool mergeWith(const QUndoCommand *command); int id() const { return 1234; } private: Chunks * _chunks; qint64 _charPos; bool _wasChanged; char _newChar; char _oldChar; CCmd _cmd; }; CharCommand::CharCommand(Chunks * chunks, CCmd cmd, qint64 charPos, char newChar, QUndoCommand *parent) : QUndoCommand(parent) { _chunks = chunks; _charPos = charPos; _newChar = newChar; _cmd = cmd; } bool CharCommand::mergeWith(const QUndoCommand *command) { const CharCommand *nextCommand = static_cast(command); bool result = false; if (_cmd != CharCommand::removeAt) { if (nextCommand->_cmd == overwrite) if (nextCommand->_charPos == _charPos) { _newChar = nextCommand->_newChar; result = true; } } return result; } void CharCommand::undo() { switch (_cmd) { case insert: _chunks->removeAt(_charPos); break; case overwrite: _chunks->overwrite(_charPos, _oldChar); _chunks->setDataChanged(_charPos, _wasChanged); break; case removeAt: _chunks->insert(_charPos, _oldChar); _chunks->setDataChanged(_charPos, _wasChanged); break; } } void CharCommand::redo() { switch (_cmd) { case insert: _chunks->insert(_charPos, _newChar); break; case overwrite: _oldChar = (*_chunks)[_charPos]; _wasChanged = _chunks->dataChanged(_charPos); _chunks->overwrite(_charPos, _newChar); break; case removeAt: _oldChar = (*_chunks)[_charPos]; _wasChanged = _chunks->dataChanged(_charPos); _chunks->removeAt(_charPos); break; } } UndoStack::UndoStack(Chunks * chunks, QObject * parent) : QUndoStack(parent) { _chunks = chunks; _parent = parent; } void UndoStack::insert(qint64 pos, char c) { if ((pos >= 0) && (pos <= _chunks->size())) { QUndoCommand *cc = new CharCommand(_chunks, CharCommand::insert, pos, c); this->push(cc); } } void UndoStack::insert(qint64 pos, const QByteArray &ba) { if ((pos >= 0) && (pos <= _chunks->size())) { QString txt = QString(tr("Inserting %1 bytes")).arg(ba.size()); beginMacro(txt); for (int idx=0; idx < ba.size(); idx++) { QUndoCommand *cc = new CharCommand(_chunks, CharCommand::insert, pos + idx, ba.at(idx)); this->push(cc); } endMacro(); } } void UndoStack::removeAt(qint64 pos, qint64 len) { if ((pos >= 0) && (pos < _chunks->size())) { if (len==1) { QUndoCommand *cc = new CharCommand(_chunks, CharCommand::removeAt, pos, char(0)); this->push(cc); } else { QString txt = QString(tr("Delete %1 chars")).arg(len); beginMacro(txt); for (qint64 cnt=0; cnt= 0) && (pos < _chunks->size())) { QUndoCommand *cc = new CharCommand(_chunks, CharCommand::overwrite, pos, c); this->push(cc); } } void UndoStack::overwrite(qint64 pos, int len, const QByteArray &ba) { if ((pos >= 0) && (pos < _chunks->size())) { QString txt = QString(tr("Overwrite %1 chars")).arg(len); beginMacro(txt); removeAt(pos, len); insert(pos, ba); endMacro(); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/src/commands.h000066400000000000000000000026331463772530400252050ustar00rootroot00000000000000#ifndef COMMANDS_H #define COMMANDS_H /** \cond docNever */ #include #include "chunks.h" /*! CharCommand is a class to provid undo/redo functionality in QHexEdit. A QUndoCommand represents a single editing action on a document. CharCommand is responsable for manipulations on single chars. It can insert. overwrite and remove characters. A manipulation stores allways two actions 1. redo (or do) action 2. undo action. CharCommand also supports command compression via mergeWidht(). This enables the user to perform an undo command e.g. 3 steps in a single command. If you for example insert a new byt "34" this means for the editor doing 3 steps: insert a "00", overwrite it with "03" and the overwrite it with "34". These 3 steps are combined into a single step, insert a "34". The byte array oriented commands are just put into a set of single byte commands, which are pooled together with the macroBegin() and macroEnd() functionality of Qt's QUndoStack. */ class UndoStack : public QUndoStack { Q_OBJECT public: UndoStack(Chunks *chunks, QObject * parent=0); void insert(qint64 pos, char c); void insert(qint64 pos, const QByteArray &ba); void removeAt(qint64 pos, qint64 len=1); void overwrite(qint64 pos, char c); void overwrite(qint64 pos, int len, const QByteArray &ba); private: Chunks * _chunks; QObject * _parent; }; /** \endcond docNever */ #endif // COMMANDS_H sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/src/license.txt000066400000000000000000000636411463772530400254240ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it!sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/src/qhexedit.cpp000066400000000000000000001015621463772530400255530ustar00rootroot00000000000000#include #include #include #include #include #include "qhexedit.h" #include // ********************************************************************** Constructor, destructor QHexEdit::QHexEdit(QWidget *parent) : QAbstractScrollArea(parent) { _addressArea = true; _addressWidth = 4; _asciiArea = true; _overwriteMode = true; _highlighting = true; _readOnly = false; _cursorPosition = 0; _lastEventSize = 0; _hexCharsInLine = 47; _bytesPerLine = 16; _editAreaIsAscii = false; _hexCaps = false; _dynamicBytesPerLine = false; _chunks = new Chunks(this); _undoStack = new UndoStack(_chunks, this); #ifdef Q_OS_WIN32 setFont(QFont("Courier", 10)); #else setFont(QFont("Monospace", 10)); #endif setAddressAreaColor(this->palette().alternateBase().color()); setHighlightingColor(QColor(0xff, 0xff, 0x99, 0xff)); setSelectionColor(this->palette().highlight().color()); connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor())); connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjust())); connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjust())); connect(_undoStack, SIGNAL(indexChanged(int)), this, SLOT(dataChangedPrivate(int))); _cursorTimer.setInterval(500); _cursorTimer.start(); setAddressWidth(4); setAddressArea(true); setAsciiArea(true); setOverwriteMode(true); setHighlighting(true); setReadOnly(false); init(); } QHexEdit::~QHexEdit() { } // ********************************************************************** Properties void QHexEdit::setAddressArea(bool addressArea) { _addressArea = addressArea; adjust(); setCursorPosition(_cursorPosition); viewport()->update(); } bool QHexEdit::addressArea() { return _addressArea; } void QHexEdit::setAddressAreaColor(const QColor &color) { _addressAreaColor = color; viewport()->update(); } QColor QHexEdit::addressAreaColor() { return _addressAreaColor; } void QHexEdit::setAddressOffset(qint64 addressOffset) { _addressOffset = addressOffset; adjust(); setCursorPosition(_cursorPosition); viewport()->update(); } qint64 QHexEdit::addressOffset() { return _addressOffset; } void QHexEdit::setAddressWidth(int addressWidth) { _addressWidth = addressWidth; adjust(); setCursorPosition(_cursorPosition); viewport()->update(); } int QHexEdit::addressWidth() { qint64 size = _chunks->size(); int n = 1; if (size > Q_INT64_C(0x100000000)){ n += 8; size /= Q_INT64_C(0x100000000);} if (size > 0x10000){ n += 4; size /= 0x10000;} if (size > 0x100){ n += 2; size /= 0x100;} if (size > 0x10){ n += 1;} if (n > _addressWidth) return n; else return _addressWidth; } void QHexEdit::setAsciiArea(bool asciiArea) { if (!asciiArea) _editAreaIsAscii = false; _asciiArea = asciiArea; adjust(); setCursorPosition(_cursorPosition); viewport()->update(); } bool QHexEdit::asciiArea() { return _asciiArea; } void QHexEdit::setBytesPerLine(int count) { _bytesPerLine = count; _hexCharsInLine = count * 3 - 1; adjust(); setCursorPosition(_cursorPosition); viewport()->update(); } int QHexEdit::bytesPerLine() { return _bytesPerLine; } void QHexEdit::setCursorPosition(qint64 position) { // 1. delete old cursor _blink = false; viewport()->update(_cursorRect); // 2. Check, if cursor in range? if (position > (_chunks->size() * 2 - 1)) position = _chunks->size() * 2 - (_overwriteMode ? 1 : 0); if (position < 0) position = 0; // 3. Calc new position of cursor _bPosCurrent = position / 2; _pxCursorY = ((position / 2 - _bPosFirst) / _bytesPerLine + 1) * _pxCharHeight; int x = (position % (2 * _bytesPerLine)); if (_editAreaIsAscii) { _pxCursorX = x / 2 * _pxCharWidth + _pxPosAsciiX; _cursorPosition = position & 0xFFFFFFFFFFFFFFFE; } else { _pxCursorX = (((x / 2) * 3) + (x % 2)) * _pxCharWidth + _pxPosHexX; _cursorPosition = position; } if (_overwriteMode) _cursorRect = QRect(_pxCursorX - horizontalScrollBar()->value(), _pxCursorY + _pxCursorWidth, _pxCharWidth, _pxCursorWidth); else _cursorRect = QRect(_pxCursorX - horizontalScrollBar()->value(), _pxCursorY - _pxCharHeight + 4, _pxCursorWidth, _pxCharHeight); // 4. Immediately draw new cursor _blink = true; viewport()->update(_cursorRect); emit currentAddressChanged(_bPosCurrent); } qint64 QHexEdit::cursorPosition(QPoint pos) { // Calc cursor position depending on a graphical position qint64 result = -1; int posX = pos.x() + horizontalScrollBar()->value(); int posY = pos.y() - 3; if ((posX >= _pxPosHexX) && (posX < (_pxPosHexX + (1 + _hexCharsInLine) * _pxCharWidth))) { _editAreaIsAscii = false; int x = (posX - _pxPosHexX) / _pxCharWidth; x = (x / 3) * 2 + x % 3; int y = (posY / _pxCharHeight) * 2 * _bytesPerLine; result = _bPosFirst * 2 + x + y; } else if (_asciiArea && (posX >= _pxPosAsciiX) && (posX < (_pxPosAsciiX + (1 + _bytesPerLine) * _pxCharWidth))) { _editAreaIsAscii = true; int x = 2 * (posX - _pxPosAsciiX) / _pxCharWidth; int y = (posY / _pxCharHeight) * 2 * _bytesPerLine; result = _bPosFirst * 2 + x + y; } return result; } qint64 QHexEdit::cursorPosition() { return _cursorPosition; } void QHexEdit::setData(const QByteArray &ba) { _data = ba; _bData.setData(_data); setData(_bData); } QByteArray QHexEdit::data() { return _chunks->data(0, -1); } void QHexEdit::setHighlighting(bool highlighting) { _highlighting = highlighting; viewport()->update(); } bool QHexEdit::highlighting() { return _highlighting; } void QHexEdit::setHighlightingColor(const QColor &color) { _brushHighlighted = QBrush(color); _penHighlighted = QPen(viewport()->palette().color(QPalette::WindowText)); viewport()->update(); } QColor QHexEdit::highlightingColor() { return _brushHighlighted.color(); } void QHexEdit::setOverwriteMode(bool overwriteMode) { _overwriteMode = overwriteMode; emit overwriteModeChanged(overwriteMode); } bool QHexEdit::overwriteMode() { return _overwriteMode; } void QHexEdit::setSelectionColor(const QColor &color) { _brushSelection = QBrush(color); _penSelection = QPen(Qt::white); viewport()->update(); } QColor QHexEdit::selectionColor() { return _brushSelection.color(); } bool QHexEdit::isReadOnly() { return _readOnly; } void QHexEdit::setReadOnly(bool readOnly) { _readOnly = readOnly; } void QHexEdit::setHexCaps(const bool isCaps) { if (_hexCaps != isCaps) { _hexCaps = isCaps; viewport()->update(); } } bool QHexEdit::hexCaps() { return _hexCaps; } void QHexEdit::setDynamicBytesPerLine(const bool isDynamic) { _dynamicBytesPerLine = isDynamic; resizeEvent(NULL); } bool QHexEdit::dynamicBytesPerLine() { return _dynamicBytesPerLine; } // ********************************************************************** Access to data of qhexedit bool QHexEdit::setData(QIODevice &iODevice) { bool ok = _chunks->setIODevice(iODevice); init(); dataChangedPrivate(); return ok; } QByteArray QHexEdit::dataAt(qint64 pos, qint64 count) { return _chunks->data(pos, count); } bool QHexEdit::write(QIODevice &iODevice, qint64 pos, qint64 count) { return _chunks->write(iODevice, pos, count); } // ********************************************************************** Char handling void QHexEdit::insert(qint64 index, char ch) { _undoStack->insert(index, ch); refresh(); } void QHexEdit::remove(qint64 index, qint64 len) { _undoStack->removeAt(index, len); refresh(); } void QHexEdit::replace(qint64 index, char ch) { _undoStack->overwrite(index, ch); refresh(); } // ********************************************************************** ByteArray handling void QHexEdit::insert(qint64 pos, const QByteArray &ba) { _undoStack->insert(pos, ba); refresh(); } void QHexEdit::replace(qint64 pos, qint64 len, const QByteArray &ba) { _undoStack->overwrite(pos, len, ba); refresh(); } // ********************************************************************** Utility functions void QHexEdit::ensureVisible() { if (_cursorPosition < (_bPosFirst * 2)) verticalScrollBar()->setValue((int)(_cursorPosition / 2 / _bytesPerLine)); if (_cursorPosition > ((_bPosFirst + (_rowsShown - 1)*_bytesPerLine) * 2)) verticalScrollBar()->setValue((int)(_cursorPosition / 2 / _bytesPerLine) - _rowsShown + 1); if (_pxCursorX < horizontalScrollBar()->value()) horizontalScrollBar()->setValue(_pxCursorX); if ((_pxCursorX + _pxCharWidth) > (horizontalScrollBar()->value() + viewport()->width())) horizontalScrollBar()->setValue(_pxCursorX + _pxCharWidth - viewport()->width()); viewport()->update(); } qint64 QHexEdit::indexOf(const QByteArray &ba, qint64 from) { qint64 pos = _chunks->indexOf(ba, from); if (pos > -1) { qint64 curPos = pos*2; setCursorPosition(curPos + ba.length()*2); resetSelection(curPos); setSelection(curPos + ba.length()*2); ensureVisible(); } return pos; } bool QHexEdit::isModified() { return _modified; } qint64 QHexEdit::lastIndexOf(const QByteArray &ba, qint64 from) { qint64 pos = _chunks->lastIndexOf(ba, from); if (pos > -1) { qint64 curPos = pos*2; setCursorPosition(curPos - 1); resetSelection(curPos); setSelection(curPos + ba.length()*2); ensureVisible(); } return pos; } void QHexEdit::redo() { _undoStack->redo(); setCursorPosition(_chunks->pos()*(_editAreaIsAscii ? 1 : 2)); refresh(); } QString QHexEdit::selectionToReadableString() { QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); return toReadable(ba); } QString QHexEdit::selectedData() { QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); return ba; } void QHexEdit::setFont(const QFont &font) { QWidget::setFont(font); _pxCharWidth = fontMetrics().width(QLatin1Char('2')); _pxCharHeight = fontMetrics().height(); _pxGapAdr = _pxCharWidth / 2; _pxGapAdrHex = _pxCharWidth; _pxGapHexAscii = 2 * _pxCharWidth; _pxCursorWidth = _pxCharHeight / 7; _pxSelectionSub = _pxCharHeight / 5; viewport()->update(); } QString QHexEdit::toReadableString() { QByteArray ba = _chunks->data(); return toReadable(ba); } void QHexEdit::undo() { _undoStack->undo(); setCursorPosition(_chunks->pos()*(_editAreaIsAscii ? 1 : 2)); refresh(); } // ********************************************************************** Handle events void QHexEdit::keyPressEvent(QKeyEvent *event) { // Cursor movements if (event->matches(QKeySequence::MoveToNextChar)) { qint64 pos = _cursorPosition + 1; if (_editAreaIsAscii) pos += 1; setCursorPosition(pos); resetSelection(pos); } if (event->matches(QKeySequence::MoveToPreviousChar)) { qint64 pos = _cursorPosition - 1; if (_editAreaIsAscii) pos -= 1; setCursorPosition(pos); resetSelection(pos); } if (event->matches(QKeySequence::MoveToEndOfLine)) { qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)) + (2 * _bytesPerLine) - 1; setCursorPosition(pos); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToStartOfLine)) { qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)); setCursorPosition(pos); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToPreviousLine)) { setCursorPosition(_cursorPosition - (2 * _bytesPerLine)); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToNextLine)) { setCursorPosition(_cursorPosition + (2 * _bytesPerLine)); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToNextPage)) { setCursorPosition(_cursorPosition + (((_rowsShown - 1) * 2 * _bytesPerLine))); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToPreviousPage)) { setCursorPosition(_cursorPosition - (((_rowsShown - 1) * 2 * _bytesPerLine))); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToEndOfDocument)) { setCursorPosition(_chunks->size() * 2 ); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToStartOfDocument)) { setCursorPosition(0); resetSelection(_cursorPosition); } // Select commands if (event->matches(QKeySequence::SelectAll)) { resetSelection(0); setSelection(2 * _chunks->size() + 1); } if (event->matches(QKeySequence::SelectNextChar)) { qint64 pos = _cursorPosition + 1; if (_editAreaIsAscii) pos += 1; setCursorPosition(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectPreviousChar)) { qint64 pos = _cursorPosition - 1; if (_editAreaIsAscii) pos -= 1; setSelection(pos); setCursorPosition(pos); } if (event->matches(QKeySequence::SelectEndOfLine)) { qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)) + (2 * _bytesPerLine) - 1; setCursorPosition(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectStartOfLine)) { qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)); setCursorPosition(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectPreviousLine)) { qint64 pos = _cursorPosition - (2 * _bytesPerLine); setCursorPosition(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectNextLine)) { qint64 pos = _cursorPosition + (2 * _bytesPerLine); setCursorPosition(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectNextPage)) { qint64 pos = _cursorPosition + (((viewport()->height() / _pxCharHeight) - 1) * 2 * _bytesPerLine); setCursorPosition(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectPreviousPage)) { qint64 pos = _cursorPosition - (((viewport()->height() / _pxCharHeight) - 1) * 2 * _bytesPerLine); setCursorPosition(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectEndOfDocument)) { qint64 pos = _chunks->size() * 2; setCursorPosition(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectStartOfDocument)) { qint64 pos = 0; setCursorPosition(pos); setSelection(pos); } // Edit Commands if (!_readOnly) { /* Cut */ if (event->matches(QKeySequence::Cut)) { QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); for (qint64 idx = 32; idx < ba.size(); idx +=33) ba.insert(idx, "\n"); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(ba); if (_overwriteMode) { qint64 len = getSelectionEnd() - getSelectionBegin(); replace(getSelectionBegin(), (int)len, QByteArray((int)len, char(0))); } else { remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); } setCursorPosition(2 * getSelectionBegin()); resetSelection(2 * getSelectionBegin()); } else /* Paste */ if (event->matches(QKeySequence::Paste)) { QClipboard *clipboard = QApplication::clipboard(); QByteArray ba = QByteArray().fromHex(clipboard->text().toLatin1()); if (_overwriteMode) { ba = ba.left(std::min(ba.size(), (_chunks->size() - _bPosCurrent))); replace(_bPosCurrent, ba.size(), ba); } else insert(_bPosCurrent, ba); setCursorPosition(_cursorPosition + 2 * ba.size()); resetSelection(getSelectionBegin()); } else /* Delete char */ if (event->matches(QKeySequence::Delete)) { if (getSelectionBegin() != getSelectionEnd()) { _bPosCurrent = getSelectionBegin(); if (_overwriteMode) { QByteArray ba = QByteArray(getSelectionEnd() - getSelectionBegin(), char(0)); replace(_bPosCurrent, ba.size(), ba); } else { remove(_bPosCurrent, getSelectionEnd() - getSelectionBegin()); } } else { if (_overwriteMode) replace(_bPosCurrent, char(0)); else remove(_bPosCurrent, 1); } setCursorPosition(2 * _bPosCurrent); resetSelection(2 * _bPosCurrent); } else /* Backspace */ if ((event->key() == Qt::Key_Backspace) && (event->modifiers() == Qt::NoModifier)) { if (getSelectionBegin() != getSelectionEnd()) { _bPosCurrent = getSelectionBegin(); setCursorPosition(2 * _bPosCurrent); if (_overwriteMode) { QByteArray ba = QByteArray(getSelectionEnd() - getSelectionBegin(), char(0)); replace(_bPosCurrent, ba.size(), ba); } else { remove(_bPosCurrent, getSelectionEnd() - getSelectionBegin()); } resetSelection(2 * _bPosCurrent); } else { bool behindLastByte = false; if ((_cursorPosition / 2) == _chunks->size()) behindLastByte = true; _bPosCurrent -= 1; if (_overwriteMode) replace(_bPosCurrent, char(0)); else remove(_bPosCurrent, 1); if (!behindLastByte) _bPosCurrent -= 1; setCursorPosition(2 * _bPosCurrent); resetSelection(2 * _bPosCurrent); } } else /* undo */ if (event->matches(QKeySequence::Undo)) { undo(); } else /* redo */ if (event->matches(QKeySequence::Redo)) { redo(); } else if ((QApplication::keyboardModifiers() == Qt::NoModifier) || (QApplication::keyboardModifiers() == Qt::KeypadModifier) || (QApplication::keyboardModifiers() == Qt::ShiftModifier) || (QApplication::keyboardModifiers() == (Qt::AltModifier | Qt::ControlModifier)) || (QApplication::keyboardModifiers() == Qt::GroupSwitchModifier)) { /* Hex and ascii input */ int key; if (_editAreaIsAscii) key = (uchar)event->text()[0].toLatin1(); else key = int(event->text()[0].toLower().toLatin1()); if ((((key >= '0' && key <= '9') || (key >= 'a' && key <= 'f')) && _editAreaIsAscii == false) || (key >= ' ' && _editAreaIsAscii)) { if (getSelectionBegin() != getSelectionEnd()) { if (_overwriteMode) { qint64 len = getSelectionEnd() - getSelectionBegin(); replace(getSelectionBegin(), (int)len, QByteArray((int)len, char(0))); } else { remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); _bPosCurrent = getSelectionBegin(); } setCursorPosition(2 * _bPosCurrent); resetSelection(2 * _bPosCurrent); } // If insert mode, then insert a byte if (_overwriteMode == false) if ((_cursorPosition % 2) == 0) insert(_bPosCurrent, char(0)); // Change content if (_chunks->size() > 0) { char ch = key; if (!_editAreaIsAscii){ QByteArray hexValue = _chunks->data(_bPosCurrent, 1).toHex(); if ((_cursorPosition % 2) == 0) hexValue[0] = key; else hexValue[1] = key; ch = QByteArray().fromHex(hexValue)[0]; } replace(_bPosCurrent, ch); if (_editAreaIsAscii) setCursorPosition(_cursorPosition + 2); else setCursorPosition(_cursorPosition + 1); resetSelection(_cursorPosition); } } } } /* Copy */ if (event->matches(QKeySequence::Copy)) { QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); for (qint64 idx = 32; idx < ba.size(); idx +=33) ba.insert(idx, "\n"); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(ba); } // Switch between insert/overwrite mode if ((event->key() == Qt::Key_Insert) && (event->modifiers() == Qt::NoModifier)) { setOverwriteMode(!overwriteMode()); setCursorPosition(_cursorPosition); } // switch from hex to ascii edit if (event->key() == Qt::Key_Tab && !_editAreaIsAscii){ _editAreaIsAscii = true; setCursorPosition(_cursorPosition); } // switch from ascii to hex edit if (event->key() == Qt::Key_Backtab && _editAreaIsAscii){ _editAreaIsAscii = false; setCursorPosition(_cursorPosition); } refresh(); } void QHexEdit::mouseMoveEvent(QMouseEvent * event) { _blink = false; viewport()->update(); qint64 actPos = cursorPosition(event->pos()); if (actPos >= 0) { setCursorPosition(actPos); setSelection(actPos); } } void QHexEdit::mousePressEvent(QMouseEvent * event) { _blink = false; viewport()->update(); qint64 cPos = cursorPosition(event->pos()); if (cPos >= 0) { if (event->button() != Qt::RightButton) resetSelection(cPos); setCursorPosition(cPos); } } void QHexEdit::paintEvent(QPaintEvent *event) { QPainter painter(viewport()); int pxOfsX = horizontalScrollBar()->value(); if (event->rect() != _cursorRect) { int pxPosStartY = _pxCharHeight; // draw some patterns if needed painter.fillRect(event->rect(), viewport()->palette().color(QPalette::Base)); if (_addressArea) painter.fillRect(QRect(-pxOfsX, event->rect().top(), _pxPosHexX - _pxGapAdrHex/2, height()), _addressAreaColor); if (_asciiArea) { int linePos = _pxPosAsciiX - (_pxGapHexAscii / 2); painter.setPen(Qt::gray); painter.drawLine(linePos - pxOfsX, event->rect().top(), linePos - pxOfsX, height()); } painter.setPen(viewport()->palette().color(QPalette::WindowText)); // paint address area if (_addressArea) { QString address; for (int row=0, pxPosY = _pxCharHeight; row <= (_dataShown.size()/_bytesPerLine); row++, pxPosY +=_pxCharHeight) { address = QString("%1").arg(_bPosFirst + row*_bytesPerLine + _addressOffset, _addrDigits, 16, QChar('0')); painter.drawText(_pxPosAdrX - pxOfsX, pxPosY, address); } } // paint hex and ascii area QPen colStandard = QPen(viewport()->palette().color(QPalette::WindowText)); painter.setBackgroundMode(Qt::TransparentMode); for (int row = 0, pxPosY = pxPosStartY; row <= _rowsShown; row++, pxPosY +=_pxCharHeight) { QByteArray hex; int pxPosX = _pxPosHexX - pxOfsX; int pxPosAsciiX2 = _pxPosAsciiX - pxOfsX; qint64 bPosLine = row * _bytesPerLine; for (int colIdx = 0; ((bPosLine + colIdx) < _dataShown.size() && (colIdx < _bytesPerLine)); colIdx++) { QColor c = viewport()->palette().color(QPalette::Base); painter.setPen(colStandard); qint64 posBa = _bPosFirst + bPosLine + colIdx; if ((getSelectionBegin() <= posBa) && (getSelectionEnd() > posBa)) { c = _brushSelection.color(); painter.setPen(_penSelection); } else { if (_highlighting) if (_markedShown.at((int)(posBa - _bPosFirst))) { c = _brushHighlighted.color(); painter.setPen(_penHighlighted); } } // render hex value QRect r; if (colIdx == 0) r.setRect(pxPosX, pxPosY - _pxCharHeight + _pxSelectionSub, 2*_pxCharWidth, _pxCharHeight); else r.setRect(pxPosX - _pxCharWidth, pxPosY - _pxCharHeight + _pxSelectionSub, 3*_pxCharWidth, _pxCharHeight); painter.fillRect(r, c); hex = _hexDataShown.mid((bPosLine + colIdx) * 2, 2); painter.drawText(pxPosX, pxPosY, hexCaps()?hex.toUpper():hex); pxPosX += 3*_pxCharWidth; // render ascii value if (_asciiArea) { int ch = (uchar)_dataShown.at(bPosLine + colIdx); if ( ch < ' ' || ch > '~' ) ch = '.'; r.setRect(pxPosAsciiX2, pxPosY - _pxCharHeight + _pxSelectionSub, _pxCharWidth, _pxCharHeight); painter.fillRect(r, c); painter.drawText(pxPosAsciiX2, pxPosY, QChar(ch)); pxPosAsciiX2 += _pxCharWidth; } } } painter.setBackgroundMode(Qt::TransparentMode); painter.setPen(viewport()->palette().color(QPalette::WindowText)); } // _cursorPosition counts in 2, _bPosFirst counts in 1 int hexPositionInShowData = _cursorPosition - 2 * _bPosFirst; // due to scrolling the cursor can go out of the currently displayed data if ((hexPositionInShowData >= 0) && (hexPositionInShowData < _hexDataShown.size())) { // paint cursor if (_readOnly) { // make the background stick out QColor color = viewport()->palette().dark().color(); painter.fillRect(QRect(_pxCursorX - pxOfsX, _pxCursorY - _pxCharHeight + _pxSelectionSub, _pxCharWidth, _pxCharHeight), color); } else { if (_blink && hasFocus()) painter.fillRect(_cursorRect, this->palette().color(QPalette::WindowText)); } if (_editAreaIsAscii) { // every 2 hex there is 1 ascii int asciiPositionInShowData = hexPositionInShowData / 2; int ch = (uchar)_dataShown.at(asciiPositionInShowData); if (ch < ' ' || ch > '~') ch = '.'; painter.drawText(_pxCursorX - pxOfsX, _pxCursorY, QChar(ch)); } else { painter.drawText(_pxCursorX - pxOfsX, _pxCursorY, _hexDataShown.mid(hexPositionInShowData, 1)); } } // emit event, if size has changed if (_lastEventSize != _chunks->size()) { _lastEventSize = _chunks->size(); emit currentSizeChanged(_lastEventSize); } } void QHexEdit::resizeEvent(QResizeEvent *) { if (_dynamicBytesPerLine) { int pxFixGaps = 0; if (_addressArea) pxFixGaps = addressWidth() * _pxCharWidth + _pxGapAdr; pxFixGaps += _pxGapAdrHex; if (_asciiArea) pxFixGaps += _pxGapHexAscii; // +1 because the last hex value do not have space. so it is effective one char more int charWidth = (viewport()->width() - pxFixGaps ) / _pxCharWidth + 1; // 2 hex alfa-digits 1 space 1 ascii per byte = 4; if ascii is disabled then 3 // to prevent devision by zero use the min value 1 setBytesPerLine(std::max(charWidth / (_asciiArea ? 4 : 3),1)); } adjust(); } bool QHexEdit::focusNextPrevChild(bool next) { if (_addressArea) { if ( (next && _editAreaIsAscii) || (!next && !_editAreaIsAscii )) return QWidget::focusNextPrevChild(next); else return false; } else { return QWidget::focusNextPrevChild(next); } } // ********************************************************************** Handle selections void QHexEdit::resetSelection() { _bSelectionBegin = _bSelectionInit; _bSelectionEnd = _bSelectionInit; } void QHexEdit::resetSelection(qint64 pos) { pos = pos / 2 ; if (pos < 0) pos = 0; if (pos > _chunks->size()) pos = _chunks->size(); _bSelectionInit = pos; _bSelectionBegin = pos; _bSelectionEnd = pos; } void QHexEdit::setSelection(qint64 pos) { pos = pos / 2; if (pos < 0) pos = 0; if (pos > _chunks->size()) pos = _chunks->size(); if (pos >= _bSelectionInit) { _bSelectionEnd = pos; _bSelectionBegin = _bSelectionInit; } else { _bSelectionBegin = pos; _bSelectionEnd = _bSelectionInit; } } qint64 QHexEdit::getSelectionBegin() { return _bSelectionBegin; } qint64 QHexEdit::getSelectionEnd() { return _bSelectionEnd; } // ********************************************************************** Private utility functions void QHexEdit::init() { _undoStack->clear(); setAddressOffset(0); resetSelection(0); setCursorPosition(0); verticalScrollBar()->setValue(0); _modified = false; } void QHexEdit::adjust() { // recalc Graphics if (_addressArea) { _addrDigits = addressWidth(); _pxPosHexX = _pxGapAdr + _addrDigits*_pxCharWidth + _pxGapAdrHex; } else _pxPosHexX = _pxGapAdrHex; _pxPosAdrX = _pxGapAdr; _pxPosAsciiX = _pxPosHexX + _hexCharsInLine * _pxCharWidth + _pxGapHexAscii; // set horizontalScrollBar() int pxWidth = _pxPosAsciiX; if (_asciiArea) pxWidth += _bytesPerLine*_pxCharWidth; horizontalScrollBar()->setRange(0, pxWidth - viewport()->width()); horizontalScrollBar()->setPageStep(viewport()->width()); // set verticalScrollbar() _rowsShown = ((viewport()->height()-4)/_pxCharHeight); int lineCount = (int)(_chunks->size() / (qint64)_bytesPerLine) + 1; verticalScrollBar()->setRange(0, lineCount - _rowsShown); verticalScrollBar()->setPageStep(_rowsShown); int value = verticalScrollBar()->value(); _bPosFirst = (qint64)value * _bytesPerLine; _bPosLast = _bPosFirst + (qint64)(_rowsShown * _bytesPerLine) - 1; if (_bPosLast >= _chunks->size()) _bPosLast = _chunks->size() - 1; readBuffers(); setCursorPosition(_cursorPosition); } void QHexEdit::dataChangedPrivate(int) { _modified = _undoStack->index() != 0; adjust(); emit dataChanged(); } void QHexEdit::refresh() { ensureVisible(); readBuffers(); } void QHexEdit::readBuffers() { _dataShown = _chunks->data(_bPosFirst, _bPosLast - _bPosFirst + _bytesPerLine + 1, &_markedShown); _hexDataShown = QByteArray(_dataShown.toHex()); } QString QHexEdit::toReadable(const QByteArray &ba) { QString result; for (int i=0; i < ba.size(); i += 16) { QString addrStr = QString("%1").arg(_addressOffset + i, addressWidth(), 16, QChar('0')); QString hexStr; QString ascStr; for (int j=0; j<16; j++) { if ((i + j) < ba.size()) { hexStr.append(" ").append(ba.mid(i+j, 1).toHex()); char ch = ba[i + j]; if ((ch < 0x20) || (ch > 0x7e)) ch = '.'; ascStr.append(QChar(ch)); } } result += addrStr + " " + QString("%1").arg(hexStr, -48) + " " + QString("%1").arg(ascStr, -17) + "\n"; } return result; } void QHexEdit::updateCursor() { if (_blink) _blink = false; else _blink = true; viewport()->update(_cursorRect); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qhexedit/src/qhexedit.h000066400000000000000000000372431463772530400252240ustar00rootroot00000000000000#ifndef QHEXEDIT_H #define QHEXEDIT_H #include #include #include #include "chunks.h" #include "commands.h" #ifdef QHEXEDIT_EXPORTS #define QHEXEDIT_API Q_DECL_EXPORT #elif QHEXEDIT_IMPORTS #define QHEXEDIT_API Q_DECL_IMPORT #else #define QHEXEDIT_API #endif /** \mainpage QHexEdit is a binary editor widget for Qt. \version Version 0.8.6 \image html qhexedit.png */ /** QHexEdit is a hex editor widget written in C++ for the Qt (Qt4, Qt5) framework. It is a simple editor for binary data, just like QPlainTextEdit is for text data. There are sip configuration files included, so it is easy to create bindings for PyQt and you can use this widget also in python 2 and 3. QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use the mouse or the keyboard to navigate inside the widget. If you hit the keys (0..9, a..f) you will change the data. Changed data is highlighted and can be accessed via data(). Normally QHexEdit works in the overwrite mode. You can set overwrite mode(false) and insert data. In this case the size of data() increases. It is also possible to delete bytes (del or backspace), here the size of data decreases. You can select data with keyboard hits or mouse movements. The copy-key will copy the selected data into the clipboard. The cut-key copies also but deletes it afterwards. In overwrite mode, the paste function overwrites the content of the (does not change the length) data. In insert mode, clipboard data will be inserted. The clipboard content is expected in ASCII Hex notation. Unknown characters will be ignored. QHexEdit comes with undo/redo functionality. All changes can be undone, by pressing the undo-key (usually ctr-z). They can also be redone afterwards. The undo/redo framework is cleared, when setData() sets up a new content for the editor. You can search data inside the content with indexOf() and lastIndexOf(). The replace() function is to change located subdata. This 'replaced' data can also be undone by the undo/redo framework. QHexEdit is based on QIODevice, that's why QHexEdit can handle big amounts of data. The size of edited data can be more then two gigabytes without any restrictions. */ class QHEXEDIT_API QHexEdit : public QAbstractScrollArea { Q_OBJECT /*! Property address area switch the address area on or off. Set addressArea true (show it), false (hide it). */ Q_PROPERTY(bool addressArea READ addressArea WRITE setAddressArea) /*! Property address area color sets (setAddressAreaColor()) the background color of address areas. You can also read the color (addressAreaColor()). */ Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor) /*! Property addressOffset is added to the Numbers of the Address Area. A offset in the address area (left side) is sometimes useful, whe you show only a segment of a complete memory picture. With setAddressOffset() you set this property - with addressOffset() you get the current value. */ Q_PROPERTY(qint64 addressOffset READ addressOffset WRITE setAddressOffset) /*! Set and get the minimum width of the address area, width in characters. */ Q_PROPERTY(int addressWidth READ addressWidth WRITE setAddressWidth) /*! Switch the ascii area on (true, show it) or off (false, hide it). */ Q_PROPERTY(bool asciiArea READ asciiArea WRITE setAsciiArea) /*! Set and get bytes number per line.*/ Q_PROPERTY(int bytesPerLine READ bytesPerLine WRITE setBytesPerLine) /*! Property cursorPosition sets or gets the position of the editor cursor in QHexEdit. Every byte in data has two cursor positions: the lower and upper Nibble. Maximum cursor position is factor two of data.size(). */ Q_PROPERTY(qint64 cursorPosition READ cursorPosition WRITE setCursorPosition) /*! Property data holds the content of QHexEdit. Call setData() to set the content of QHexEdit, data() returns the actual content. When calling setData() with a QByteArray as argument, QHexEdit creates a internal copy of the data If you want to edit big files please use setData(), based on QIODevice. */ Q_PROPERTY(QByteArray data READ data WRITE setData NOTIFY dataChanged) /*! That property defines if the hex values looks as a-f if the value is false(default) or A-F if value is true. */ Q_PROPERTY(bool hexCaps READ hexCaps WRITE setHexCaps) /*! Property defines the dynamic calculation of bytesPerLine parameter depends of width of widget. set this property true to avoid horizontal scrollbars and show the maximal possible data. defalut value is false*/ Q_PROPERTY(bool dynamicBytesPerLine READ dynamicBytesPerLine WRITE setDynamicBytesPerLine) /*! Switch the highlighting feature on or of: true (show it), false (hide it). */ Q_PROPERTY(bool highlighting READ highlighting WRITE setHighlighting) /*! Property highlighting color sets (setHighlightingColor()) the background color of highlighted text areas. You can also read the color (highlightingColor()). */ Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor) /*! Property overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode in which the editor works. In overwrite mode the user will overwrite existing data. The size of data will be constant. In insert mode the size will grow, when inserting new data. */ Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode) /*! Property selection color sets (setSelectionColor()) the background color of selected text areas. You can also read the color (selectionColor()). */ Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor) /*! Property readOnly sets (setReadOnly()) or gets (isReadOnly) the mode in which the editor works. In readonly mode the the user can only navigate through the data and select data; modifying is not possible. This property's default is false. */ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) /*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/ Q_PROPERTY(QFont font READ font WRITE setFont) public: /*! Creates an instance of QHexEdit. \param parent Parent widget of QHexEdit. */ QHexEdit(QWidget *parent=0); // Access to data of qhexedit /*! Sets the data of QHexEdit. The QIODevice will be opened just before reading and closed immediately afterwards. This is to allow other programs to rewrite the file while editing it. */ bool setData(QIODevice &iODevice); /*! Gives back the data as a QByteArray starting at position \param pos and delivering \param count bytes. */ QByteArray dataAt(qint64 pos, qint64 count=-1); /*! Gives back the data into a \param iODevice starting at position \param pos and delivering \param count bytes. */ bool write(QIODevice &iODevice, qint64 pos=0, qint64 count=-1); // Char handling /*! Inserts a char. \param pos Index position, where to insert \param ch Char, which is to insert The char will be inserted and size of data grows. */ void insert(qint64 pos, char ch); /*! Removes len bytes from the content. \param pos Index position, where to remove \param len Amount of bytes to remove */ void remove(qint64 pos, qint64 len=1); /*! Replaces a char. \param pos Index position, where to overwrite \param ch Char, which is to insert The char will be overwritten and size remains constant. */ void replace(qint64 pos, char ch); // ByteArray handling /*! Inserts a byte array. \param pos Index position, where to insert \param ba QByteArray, which is to insert The QByteArray will be inserted and size of data grows. */ void insert(qint64 pos, const QByteArray &ba); /*! Replaces \param len bytes with a byte array \param ba \param pos Index position, where to overwrite \param ba QByteArray, which is inserted \param len count of bytes to overwrite The data is overwritten and size of data may change. */ void replace(qint64 pos, qint64 len, const QByteArray &ba); // Utility functions /*! Calc cursor position from graphics position * \param point from where the cursor position should be calculated * \return Cursor position */ qint64 cursorPosition(QPoint point); /*! Ensure the cursor to be visbile */ void ensureVisible(); /*! Find first occurrence of ba in QHexEdit data * \param ba Data to find * \param from Point where the search starts * \return pos if fond, else -1 */ qint64 indexOf(const QByteArray &ba, qint64 from); /*! Returns if any changes where done on document * \return true when document is modified else false */ bool isModified(); /*! Find last occurrence of ba in QHexEdit data * \param ba Data to find * \param from Point where the search starts * \return pos if fond, else -1 */ qint64 lastIndexOf(const QByteArray &ba, qint64 from); /*! Gives back a formatted image of the selected content of QHexEdit */ QString selectionToReadableString(); /*! Return the selected content of QHexEdit as QByteArray */ QString selectedData(); /*! Set Font of QHexEdit * \param font */ void setFont(const QFont &font); /*! Gives back a formatted image of the content of QHexEdit */ QString toReadableString(); public slots: /*! Redoes the last operation. If there is no operation to redo, i.e. there is no redo step in the undo/redo history, nothing happens. */ void redo(); /*! Undoes the last operation. If there is no operation to undo, i.e. there is no undo step in the undo/redo history, nothing happens. */ void undo(); signals: /*! Contains the address, where the cursor is located. */ void currentAddressChanged(qint64 address); /*! Contains the size of the data to edit. */ void currentSizeChanged(qint64 size); /*! The signal is emitted every time, the data is changed. */ void dataChanged(); /*! The signal is emitted every time, the overwrite mode is changed. */ void overwriteModeChanged(bool state); /*! \cond docNever */ public: ~QHexEdit(); // Properties bool addressArea(); void setAddressArea(bool addressArea); QColor addressAreaColor(); void setAddressAreaColor(const QColor &color); qint64 addressOffset(); void setAddressOffset(qint64 addressArea); int addressWidth(); void setAddressWidth(int addressWidth); bool asciiArea(); void setAsciiArea(bool asciiArea); int bytesPerLine(); void setBytesPerLine(int count); qint64 cursorPosition(); void setCursorPosition(qint64 position); QByteArray data(); void setData(const QByteArray &ba); void setHexCaps(const bool isCaps); bool hexCaps(); void setDynamicBytesPerLine(const bool isDynamic); bool dynamicBytesPerLine(); bool highlighting(); void setHighlighting(bool mode); QColor highlightingColor(); void setHighlightingColor(const QColor &color); bool overwriteMode(); void setOverwriteMode(bool overwriteMode); bool isReadOnly(); void setReadOnly(bool readOnly); QColor selectionColor(); void setSelectionColor(const QColor &color); protected: // Handle events void keyPressEvent(QKeyEvent *event); void mouseMoveEvent(QMouseEvent * event); void mousePressEvent(QMouseEvent * event); void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *); virtual bool focusNextPrevChild(bool next); private: // Handle selections void resetSelection(qint64 pos); // set selectionStart and selectionEnd to pos void resetSelection(); // set selectionEnd to selectionStart void setSelection(qint64 pos); // set min (if below init) or max (if greater init) qint64 getSelectionBegin(); qint64 getSelectionEnd(); // Private utility functions void init(); void readBuffers(); QString toReadable(const QByteArray &ba); private slots: void adjust(); // recalc pixel positions void dataChangedPrivate(int idx=0); // emit dataChanged() signal void refresh(); // ensureVisible() and readBuffers() void updateCursor(); // update blinking cursor private: // Name convention: pixel positions start with _px int _pxCharWidth, _pxCharHeight; // char dimensions (dependend on font) int _pxPosHexX; // X-Pos of HeaxArea int _pxPosAdrX; // X-Pos of Address Area int _pxPosAsciiX; // X-Pos of Ascii Area int _pxGapAdr; // gap left from AddressArea int _pxGapAdrHex; // gap between AddressArea and HexAerea int _pxGapHexAscii; // gap between HexArea and AsciiArea int _pxCursorWidth; // cursor width int _pxSelectionSub; // offset selection rect int _pxCursorX; // current cursor pos int _pxCursorY; // current cursor pos // Name convention: absolute byte positions in chunks start with _b qint64 _bSelectionBegin; // first position of Selection qint64 _bSelectionEnd; // end of Selection qint64 _bSelectionInit; // memory position of Selection qint64 _bPosFirst; // position of first byte shown qint64 _bPosLast; // position of last byte shown qint64 _bPosCurrent; // current position // variables to store the property values bool _addressArea; // left area of QHexEdit QColor _addressAreaColor; int _addressWidth; bool _asciiArea; qint64 _addressOffset; int _bytesPerLine; int _hexCharsInLine; bool _highlighting; bool _overwriteMode; QBrush _brushSelection; QPen _penSelection; QBrush _brushHighlighted; QPen _penHighlighted; bool _readOnly; bool _hexCaps; bool _dynamicBytesPerLine; // other variables bool _editAreaIsAscii; // flag about the ascii mode edited int _addrDigits; // real no of addressdigits, may be > addressWidth bool _blink; // help get cursor blinking QBuffer _bData; // buffer, when setup with QByteArray Chunks *_chunks; // IODevice based access to data QTimer _cursorTimer; // for blinking cursor qint64 _cursorPosition; // absolute position of cursor, 1 Byte == 2 tics QRect _cursorRect; // physical dimensions of cursor QByteArray _data; // QHexEdit's data, when setup with QByteArray QByteArray _dataShown; // data in the current View QByteArray _hexDataShown; // data in view, transformed to hex qint64 _lastEventSize; // size, which was emitted last time QByteArray _markedShown; // marked data in view bool _modified; // Is any data in editor modified? int _rowsShown; // lines of text shown UndoStack * _undoStack; // Stack to store edit actions for undo/redo /*! \endcond docNever */ }; #endif // QHEXEDIT_H sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/000077500000000000000000000000001463772530400227705ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/ChangeLog000066400000000000000000006706351463772530400245630ustar00rootroot000000000000002019-02-12 Phil Thompson * NEWS: Released as v2.11.1. [bebf741baff8] [2.11.1] <2.11-maint> * NEWS: Updated the NEWS file. [9f2dd3438ac3] <2.11-maint> * Python/configure-old.py, Python/configure.py, designer- Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro, qt/qscintilla.pro: Bumped the major version number of the library because of the SendScintilla() signature change. [c2fe34e11899] <2.11-maint> * Python/sip/qsciscintillabase.sip, qt/qscimacro.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Fixed a regression in QsciScintilla::insert(). The signature of QsciScintillaBase::SendScintilla(unigned int, unsigned long, const char *) has changed so that the second argument is now uintptr_t. This may require code changes. [b62eb7f29de4] <2.11-maint> 2019-02-11 Phil Thompson * NEWS: Updated the NEWS file. [9768dbe05f64] <2.11-maint> * qt/qsciscintillabase.cpp: Fixed the marginRightClicked() signal. [6a6efafbefd6] <2.11-maint> * qt/qscintilla.pro: Bumped the library version number. [a4ee797a9df9] <2.11-maint> 2019-02-04 Phil Thompson * .hgtags: Added tag 2.11 for changeset 2610e30b0914 [f83b4fbdd928] * NEWS: Released as v2.11. [2610e30b0914] [2.11] 2018-12-21 Phil Thompson * METADATA.in: Corrected the wheel meta-data version. [593a629d46f5] 2018-12-15 Phil Thompson * NEWS: Updated the NEWS file. [992f3cb597c4] 2018-11-24 Phil Thompson * qt/qscintilla_de.qm, qt/qscintilla_de.ts: Updated German translations from Detlev. [f293bafecde8] 2018-11-17 Phil Thompson * qt/ScintillaQt.h: Fixed the Linux build. [3ec0608d1744] * qt/SciClasses.cpp, qt/SciClasses.h: Removed the redundant explicit handling of the Esc key in popup lists. [a3d596e37561] * NEWS, Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added QsciScintilla::cancelFind(). [520cda104a4b] 2018-11-13 Phil Thompson * NEWS, Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added support for Cxx11 regular expressions to findFirst() and findFirstInSelection(). [9c022f775241] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added the remaining new API calls. [03f9682f7d6c] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added the new wrap indent mode. [4a786cbfd975] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added the style metadata messages. [e3e38b577a1f] * NEWS, Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qsciscintillabase.h: Added the SCN_AUTOCSELECTIONCHANGE() signal. [156c8e0c6fb7] * NEWS, Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qsciscintillabase.h: Added the new SCN_USERLISTSELECTION() signal overload. [031270944f93] * NEWS, Python/sip/qsciscintillabase.sip, qt/qscilexer.cpp, qt/qsciscintillabase.h: Added the character/code unit functions. [ff2e92ed2890] * qt/qscilexer.cpp, qt/qscilexer.h, qt/qscintilla.pro, qt/qsciscintilla.cpp: Don't use the deprecated style bits API calls. [2d1cf2b1019f] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added support for the new gradient indicators. [02e7b6ba2fdb] 2018-11-12 Phil Thompson * NEWS, Python/sip/qscilexerdiff.sip, qt/qscilexerdiff.cpp, qt/qscilexerdiff.h, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts: Updates to the diff lexer. [fb8a0cb48593] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added the symbolic names for the new lexers. [b8d4fab81221] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Implemented the SCN_URIDROPPED signal. [242bb09d23ea] * qt/qsciscintillabase.h: Documented SCN_DWELLSTART and SCN_DWELLEND. [8750296d855d] * qt/PlatQt.cpp: Removed some unused platform methods. [70c01135aa8d] * qt/InputMethod.cpp, qt/ListBoxQt.cpp, qt/ListBoxQt.h, qt/PlatQt.cpp, qt/SciClasses.cpp, qt/SciNamespace.h, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qscintilla.pro, qt/qsciscintillabase.cpp: Removed the support for the optional Scintilla namespace. [33998bb1d26a] 2018-11-11 Phil Thompson * BACKPORTING, License.txt, LongTermDownload.html, NEWS, README, check.mak, checkdeps.mak, cocoa/InfoBar.mm, cocoa/PlatCocoa.h, cocoa/PlatCocoa.mm, cocoa/QuartzTextLayout.h, cocoa/ScintillaCocoa.h, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/Info.plist, cocoa/ScintillaFramework/Scinti llaFramework.xcodeproj/project.pbxproj, cocoa/ScintillaTest/AppController.mm, cocoa/ScintillaTest/ScintillaTest.xcodeproj/project.pbxproj, cocoa/ScintillaView.mm, cppcheck.suppress, curses/Makefile, curses/README.md, curses/ScintillaCurses.cxx, curses/ScintillaCurses.h, curses/THANKS.md, curses/jinx/Makefile, curses/jinx/jinx.c, delbin.bat, doc/Design.html, doc/LPegLexer.html, doc/SciCoding.html, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/ScintillaToDo.html, doc/StyleMetadata.html, doc/index.html, gtk/Converter.h, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/ScintillaGTK.h, gtk/ScintillaGTKAccessible.cxx, gtk/ScintillaGTKAccessible.h, gtk/deps.mak, gtk/makefile, gtk/scintilla-marshal.c, gtk/scintilla- marshal.h, gtk/scintilla-marshal.list, include/ILexer.h, include/ILoader.h, include/Platform.h, include/SciLexer.h, include/Sci_Position.h, include/Scintilla.h, include/Scintilla.iface, lexers/LexA68k.cxx, lexers/LexAPDL.cxx, lexers/LexASY.cxx, lexers/LexAU3.cxx, lexers/LexAVE.cxx, lexers/LexAVS.cxx, lexers/LexAbaqus.cxx, lexers/LexAda.cxx, lexers/LexAsm.cxx, lexers/LexAsn1.cxx, lexers/LexBaan.cxx, lexers/LexBash.cxx, lexers/LexBasic.cxx, lexers/LexBatch.cxx, lexers/LexBibTeX.cxx, lexers/LexBullant.cxx, lexers/LexCLW.cxx, lexers/LexCOBOL.cxx, lexers/LexCPP.cxx, lexers/LexCSS.cxx, lexers/LexCaml.cxx, lexers/LexCmake.cxx, lexers/LexCoffeeScript.cxx, lexers/LexConf.cxx, lexers/LexCrontab.cxx, lexers/LexCsound.cxx, lexers/LexD.cxx, lexers/LexDMAP.cxx, lexers/LexDMIS.cxx, lexers/LexDiff.cxx, lexers/LexECL.cxx, lexers/LexEDIFACT.cxx, lexers/LexEScript.cxx, lexers/LexEiffel.cxx, lexers/LexErlang.cxx, lexers/LexErrorList.cxx, lexers/LexFlagship.cxx, lexers/LexForth.cxx, lexers/LexFortran.cxx, lexers/LexGAP.cxx, lexers/LexGui4Cli.cxx, lexers/LexHTML.cxx, lexers/LexHaskell.cxx, lexers/LexHex.cxx, lexers/LexIndent.cxx, lexers/LexInno.cxx, lexers/LexJSON.cxx, lexers/LexKVIrc.cxx, lexers/LexKix.cxx, lexers/LexLPeg.cxx, lexers/LexLaTeX.cxx, lexers/LexLisp.cxx, lexers/LexLout.cxx, lexers/LexLua.cxx, lexers/LexMMIXAL.cxx, lexers/LexMPT.cxx, lexers/LexMSSQL.cxx, lexers/LexMagik.cxx, lexers/LexMake.cxx, lexers/LexMarkdown.cxx, lexers/LexMatlab.cxx, lexers/LexMaxima.cxx, lexers/LexMetapost.cxx, lexers/LexModula.cxx, lexers/LexMySQL.cxx, lexers/LexNimrod.cxx, lexers/LexNsis.cxx, lexers/LexNull.cxx, lexers/LexOScript.cxx, lexers/LexOpal.cxx, lexers/LexPB.cxx, lexers/LexPLM.cxx, lexers/LexPO.cxx, lexers/LexPOV.cxx, lexers/LexPS.cxx, lexers/LexPascal.cxx, lexers/LexPerl.cxx, lexers/LexPowerPro.cxx, lexers/LexPowerShell.cxx, lexers/LexProgress.cxx, lexers/LexProps.cxx, lexers/LexPython.cxx, lexers/LexR.cxx, lexers/LexRebol.cxx, lexers/LexRegistry.cxx, lexers/LexRuby.cxx, lexers/LexRust.cxx, lexers/LexSAS.cxx, lexers/LexSML.cxx, lexers/LexSQL.cxx, lexers/LexSTTXT.cxx, lexers/LexScriptol.cxx, lexers/LexSmalltalk.cxx, lexers/LexSorcus.cxx, lexers/LexSpecman.cxx, lexers/LexSpice.cxx, lexers/LexStata.cxx, lexers/LexTACL.cxx, lexers/LexTADS3.cxx, lexers/LexTAL.cxx, lexers/LexTCL.cxx, lexers/LexTCMD.cxx, lexers/LexTeX.cxx, lexers/LexTxt2tags.cxx, lexers/LexVB.cxx, lexers/LexVHDL.cxx, lexers/LexVerilog.cxx, lexers/LexVisualProlog.cxx, lexers/LexYAML.cxx, lexlib/Accessor.cxx, lexlib/Accessor.h, lexlib/CharacterCategory.cxx, lexlib/CharacterCategory.h, lexlib/CharacterSet.cxx, lexlib/CharacterSet.h, lexlib/DefaultLexer.cxx, lexlib/DefaultLexer.h, lexlib/LexAccessor.h, lexlib/LexerBase.cxx, lexlib/LexerBase.h, lexlib/LexerModule.cxx, lexlib/LexerModule.h, lexlib/LexerNoExceptions.cxx, lexlib/LexerNoExceptions.h, lexlib/LexerSimple.cxx, lexlib/LexerSimple.h, lexlib/OptionSet.h, lexlib/PropSetSimple.cxx, lexlib/PropSetSimple.h, lexlib/SparseState.h, lexlib/StringCopy.h, lexlib/StyleContext.cxx, lexlib/StyleContext.h, lexlib/SubStyles.h, lexlib/WordList.cxx, lexlib/WordList.h, lib/README.doc, qt/InputMethod.cpp, qt/ListBoxQt.cpp, qt/ListBoxQt.h, qt/PlatQt.cpp, qt/SciClasses.cpp, qt/SciClasses.h, qt/SciNamespace.h, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qscintilla.pro, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h, scripts/Face.py, scripts/FileGenerator.py, scripts/GenerateCaseConvert.py, scripts/HFacer.py, scripts/HeaderCheck.py, scripts/HeaderOrder.txt, scripts/LexGen.py, scripts/ScintillaData.py, src/AutoComplete.cxx, src/AutoComplete.h, src/CallTip.cxx, src/CallTip.h, src/CaseConvert.cxx, src/CaseConvert.h, src/CaseFolder.cxx, src/CaseFolder.h, src/Catalogue.cxx, src/Catalogue.h, src/CellBuffer.cxx, src/CellBuffer.h, src/CharClassify.cxx, src/CharClassify.h, src/ContractionState.cxx, src/ContractionState.h, src/DBCS.cxx, src/DBCS.h, src/Decoration.cxx, src/Decoration.h, src/Document.cxx, src/Document.h, src/EditModel.cxx, src/EditModel.h, src/EditView.cxx, src/EditView.h, src/Editor.cxx, src/Editor.h, src/ElapsedPeriod.h, src/ExternalLexer.cxx, src/ExternalLexer.h, src/FontQuality.h, src/Indicator.cxx, src/Indicator.h, src/IntegerRectangle.h, src/KeyMap.cxx, src/KeyMap.h, src/LineMarker.cxx, src/LineMarker.h, src/MarginView.cxx, src/MarginView.h, src/Partitioning.h, src/PerLine.cxx, src/PerLine.h, src/Position.h, src/PositionCache.cxx, src/PositionCache.h, src/RESearch.cxx, src/RESearch.h, src/RunStyles.cxx, src/RunStyles.h, src/ScintillaBase.cxx, src/ScintillaBase.h, src/Selection.cxx, src/Selection.h, src/SparseVector.h, src/SplitVector.h, src/Style.cxx, src/Style.h, src/UniConversion.cxx, src/UniConversion.h, src/UnicodeFromUTF8.h, src/UniqueString.h, src/ViewStyle.cxx, src/ViewStyle.h, src/XPM.cxx, src/XPM.h, test/README, test/ScintillaCallable.py, test/XiteWin.py, test/lexTests.py, test/performanceTests.py, test/simpleTests.py, test/test_lexlua.lua, test/unit/Sci.natvis, test/unit/UnitTester.cxx, test/unit/UnitTester.vcxproj, test/unit/catch.hpp, test/unit/makefile, test/unit/test.mak, test/unit/testCellBuffer.cxx, test/unit/testCharClassify.cxx, test/unit/testContractionState.cxx, test/unit/testDecoration.cxx, test/unit/testPartitioning.cxx, test/unit/testRunStyles.cxx, test/unit/testSparseState.cxx, test/unit/testSparseVector.cxx, test/unit/testSplitVector.cxx, test/unit/testUniConversion.cxx, test/unit/testUnicodeFromUTF8.cxx, test/unit/testWordList.cxx, test/unit/unitTest.cxx, version.txt, win32/CheckD2D.cxx, win32/HanjaDic.cxx, win32/HanjaDic.h, win32/PlatWin.cxx, win32/PlatWin.h, win32/SciLexer.vcxproj, win32/ScintRes.rc, win32/ScintillaDLL.cxx, win32/ScintillaWin.cxx, win32/ScintillaWin.h, win32/deps.mak, win32/makefile, win32/scintilla.mak: The v3.10.1 based code will now build - otherwise untested. [cb6d486795ec] 2018-11-05 Phil Thompson * NEWS: Updated the NEWS file. [a99dfcd91f84] * qt/qscintilla_cs.ts, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_es.qm, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts: Updated the translation files. [1529479f8a31] * Python/configure.py, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qscilexerpython.cpp, qt/qscintilla.pro, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Merged the 2.10-maint branch with the trunk. [5fcc66abfca0] 2018-10-01 Phil Thompson * .hgtags: Added tag 2.10.8 for changeset 57c8b6076899 [b565980f962b] <2.10-maint> * NEWS: Released as v2.10.8. [57c8b6076899] [2.10.8] <2.10-maint> 2018-09-30 Phil Thompson * NEWS: Updated the NEWS file. [345f597a4a90] <2.10-maint> 2018-08-02 Phil Thompson * qt/SciAccessibility.cpp: More accessibility fixes. [2cc2d6865762] <2.10-maint> * qt/SciAccessibility.cpp, qt/SciAccessibility.h, qt/qscintilla.pro: Refactored the accessibility support to use less of the Qt stuff which doesn't handle CR-LF end-of-lines. [8b2d6e3e73d8] <2.10-maint> 2018-07-15 Phil Thompson * NEWS: Updated the NEWS file. [fc1deaccc716] <2.10-maint> 2018-06-29 Phil Thompson * .hgtags: Added tag 2.10.7 for changeset 60598a703fd4 [8828f9ad7dc6] <2.10-maint> * NEWS: Released as v2.10.7. [60598a703fd4] [2.10.7] <2.10-maint> * NEWS: Updated the NEWS file. [92edf18019ec] <2.10-maint> 2018-06-25 Phil Thompson * NEWS, Python/sip/qsciscintillabase.sip: Tweaked the signature of the QscoScintillaBase::SCN_MACRORECORD() signal so that it matches what Qt uses so that the signal test passes. [bfcd9319329a] <2.10-maint> 2018-06-23 Phil Thompson * .hgtags: Added tag 2.10.6 for changeset dc0993c72a05 [9c774d0a9694] <2.10-maint> * NEWS: Released as v2.10.6. [dc0993c72a05] [2.10.6] <2.10-maint> 2018-06-22 Phil Thompson * .hgtags: Added tag 2.10.5 for changeset f35b3a43a241 [8cf5694ca328] <2.10-maint> * NEWS: Released as v2.10.5. [f35b3a43a241] [2.10.5] <2.10-maint> 2018-06-21 Phil Thompson * NEWS: Updated the NEWS file. [12cb1a2f5ec6] <2.10-maint> 2018-06-19 Phil Thompson * NEWS, Python/sip/qscistyle.sip, qt/qscistyle.cpp, qt/qscistyle.h: Added setStyle() to QsciStyle. [cf5281041224] <2.10-maint> 2018-06-16 Phil Thompson * qt/qscintilla_es.qm, qt/qscintilla_es.ts: Updated Spanish translations from Jaime Seuma. [a479b9f5436f] <2.10-maint> 2018-06-09 Phil Thompson * qt/qscintilla_cs.qm, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_es.qm, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm: Updated German translations from Detlev. [f69379899fb3] <2.10-maint> 2018-06-04 Phil Thompson * NEWS, Python/configure.py: Implemented support for the .dist-info directory. [387aa9bf6ad8] <2.10-maint> 2018-06-03 Phil Thompson * NEWS, Python/sip/qsciscintillabase.sip, qt/PlatQt.cpp, qt/ScintillaQt.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Fixes for font changes caused by dragging to a different display. [27b1f435e27a] <2.10-maint> 2018-05-29 Phil Thompson * qt/PlatQt.cpp: Disable to macOS use of integer font metrics for Qt5 as it is (probably) specific to Qt4. [c32fe0c4e55d] <2.10-maint> * qt/PlatQt.cpp: Fixed cursor positioning when using a secondary display with different scaling to the primary. [20420b7c4a4d] <2.10-maint> 2018-05-22 Phil Thompson * qt/qscilexerverilog.cpp: Fix the handling of the 'fold.verilog.flags' property in the Verilog lexer. [9b698ba38c2b] <2.10-maint> 2018-05-16 Phil Thompson * qt/qscilexerverilog.cpp, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts: Added the missing descriptions of inactive styles in the Verilog lexer. [4be691232e03] <2.10-maint> 2018-05-15 Phil Thompson * qt/qscilexer.h: Updated the QsciLexer::keywords() documentation to point out that sets are numbered from 1. [5954b91e7ec1] <2.10-maint> 2018-04-26 Phil Thompson * Python/sip/qscilexeredifact.sip, qt/qscilexeredifact.cpp, qt/qscilexeredifact.h: Added some default colours to the EDIFACT lexer. [175598286833] <2.10-maint> 2018-04-20 Phil Thompson * NEWS, Python/sip/qscilexeredifact.sip, qt/qscilexeredifact.cpp, qt/qscilexeredifact.h, qt/qscintilla.pro, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts: Added the QsciLexerEDIFACT class. [c1e31857f3e7] <2.10-maint> * qt/qsciscintilla.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: If the context menu is invoked when the cursor is outside the selection then the selection is cleared and the cursor moved to where the mouse was clicked. [7d230dad9379] <2.10-maint> 2018-04-19 Phil Thompson * Python/sip/qsciscintilla.sip, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Control-wheel up/down will now zoom in and out. [ba0049fe03b6] <2.10-maint> 2018-04-11 Phil Thompson * qt/PlatQt.cpp, qt/qsciabstractapis.cpp, qt/qscilexerpython.cpp, qt/qscilexerxml.cpp, qt/qsciscintilla.cpp: Removed warning messages about unused variables. [c2008ef93ee0] <2.10-maint> * qt/qscicommandset.cpp: Fixed the saving of alternative keys in the settings. [687470e937c1] <2.10-maint> * qt/ScintillaQt.cpp, qt/qsciapis.cpp, qt/qsciscintilla.cpp: Various stylistic changes to eliminate some warning messages. [dc753169870e] <2.10-maint> 2018-04-10 Phil Thompson * .hgtags: Added tag 2.10.4 for changeset 24cb0edc89a9 [05ada666e2cf] <2.10-maint> * NEWS: Released as v2.10.4. [24cb0edc89a9] [2.10.4] <2.10-maint> * qt/SciAccessibility.cpp: Fixed the retrieval of accessibility attributes. [e430a7dd7818] <2.10-maint> 2018-04-07 Phil Thompson * qt/qscilexer.cpp: Use STYLE_MAX to define the maximum number of styles. [23ca0cad0227] <2.10-maint> 2018-03-11 Phil Thompson * qt/qscintilla.pro: Force QT_NO_ACCESSIBILITY when building against Qt4. [b65f48ec1852] <2.10-maint> 2018-02-27 Phil Thompson * .hgtags: Added tag 2.10.3 for changeset bc769d6fcf53 [279625f1d8c9] <2.10-maint> * NEWS: Released as v2.10.3. [bc769d6fcf53] [2.10.3] <2.10-maint> * rb-product: Updated the PyQt5 wheel dependency. [7cef6e297ddf] <2.10-maint> * NEWS: Updated the NEWS file. [1e073e29eca4] <2.10-maint> 2018-02-10 Phil Thompson * qsci/api/python/Python-3.7.api: Added the API file for Python v3.70b1. [6d0032674462] <2.10-maint> 2018-02-07 Phil Thompson * qt/qsciscintilla.cpp: Fix the hotspot active background colour. [45cfd8c68394] <2.10-maint> * qt/SciAccessibility.cpp, qt/SciAccessibility.h: Completed the accessibility support. [2af3a5b045fa] <2.10-maint> 2018-02-06 Phil Thompson * qt/SciAccessibility.cpp, qt/SciAccessibility.h: Implemented all of the accessible interface except for attributes(). [434539a243dc] <2.10-maint> * qt/SciAccessibility.cpp: Implemented more of the accessible interface. [e8f3df5442cc] <2.10-maint> * qt/SciAccessibility.cpp, qt/SciAccessibility.h, qt/ScintillaQt.cpp: Implemented more of the accessible interface. [fb26d9fdba27] <2.10-maint> 2018-02-05 Phil Thompson * qt/SciAccessibility.cpp, qt/SciAccessibility.h, qt/ScintillaQt.cpp, qt/qsciscintillabase.cpp: More accessibility progress. [ea2432348b49] <2.10-maint> * qt/SciAccessibility.cpp, qt/SciAccessibility.h, qt/ScintillaQt.cpp: Some progress on accessibility. [055345b62d7b] <2.10-maint> * qt/qscintilla.pro: Updated the version of the shared library. [fb50133f8770] <2.10-maint> 2018-02-04 Phil Thompson * qt/SciAccessibility.cpp, qt/SciAccessibility.h, qt/qscintilla.pro, qt/qsciscintillabase.cpp: Added the stubs for accessibility support. [61e00a4f944f] <2.10-maint> * qt/SciAccessibility.cpp, qt/SciAccessibility.h, qt/qscintilla.pro, qt/qsciscintillabase.cpp: Added the stubs for accessibility support. [8f2f20b663f1] * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts: Updated the .ts files. [7630e7c16a42] * Python/sip/qscilexerpython.sip, qt/qscilexerpython.cpp, qt/qscilexerpython.h: Added the DoubleQuotedFString, SingleQuotedFString, TripleSingleQuotedFString and TripleDoubleQuotedFString styles to QsciLexerPython. [69a152791250] * Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added QsciScintilla::setCaretLineFrameWidth(). [61ed51375157] * Python/sip/qscicommand.sip: Added ReverseLines to the Python bindings. [132758b054dc] * qt/qscicommand.h: Added ReverseLines to QsciCommand::Command. [1cecbd08c177] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added SCLEX_INDENT, SCI_GETCARETLINEFRAME, SCI_SETCARETLINEFRAME, SCI_SETACCESSIBILITY, SCI_GETACCESSIBILITY and SCI_LINEREVERSE. [4a5c2bea7d34] 2018-02-03 Phil Thompson * Python/configure-old.py, Python/configure.py, designer- Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro, qt/ScintillaQt.h, qt/qscintilla.pro: Fixes to build with the latest code. [262ad022e5b6] * README, cocoa/InfoBar.mm, cocoa/PlatCocoa.h, cocoa/PlatCocoa.mm, cocoa/ScintillaCocoa.h, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/Info.plist, cocoa/ScintillaFramework/Scinti llaFramework.xcodeproj/project.pbxproj, cocoa/ScintillaTest/AppController.h, cocoa/ScintillaTest/AppController.mm, cocoa/ScintillaTest/English.lproj/MainMenu.xib, cocoa/ScintillaTest/ScintillaTest.xcodeproj/project.pbxproj, cocoa/ScintillaView.mm, cppcheck.suppress, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/index.html, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/ScintillaGTK.h, gtk/ScintillaGTKAccessible.cxx, gtk/ScintillaGTKAccessible.h, gtk/deps.mak, gtk/makefile, include/Platform.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, lexers/LexAsm.cxx, lexers/LexBaan.cxx, lexers/LexBash.cxx, lexers/LexBasic.cxx, lexers/LexCPP.cxx, lexers/LexD.cxx, lexers/LexDMIS.cxx, lexers/LexDiff.cxx, lexers/LexEDIFACT.cxx, lexers/LexErrorList.cxx, lexers/LexFortran.cxx, lexers/LexHTML.cxx, lexers/LexHaskell.cxx, lexers/LexIndent.cxx, lexers/LexJSON.cxx, lexers/LexLaTeX.cxx, lexers/LexLua.cxx, lexers/LexMatlab.cxx, lexers/LexPerl.cxx, lexers/LexPowerShell.cxx, lexers/LexProgress.cxx, lexers/LexProps.cxx, lexers/LexPython.cxx, lexers/LexRegistry.cxx, lexers/LexRust.cxx, lexers/LexSQL.cxx, lexers/LexVHDL.cxx, lexers/LexVerilog.cxx, lexers/LexVisualProlog.cxx, lexers/LexYAML.cxx, lexlib/Accessor.cxx, lexlib/CharacterCategory.cxx, lexlib/CharacterCategory.h, lexlib/CharacterSet.cxx, lexlib/CharacterSet.h, lexlib/LexAccessor.h, lexlib/LexerBase.cxx, lexlib/LexerModule.cxx, lexlib/LexerModule.h, lexlib/LexerNoExceptions.cxx, lexlib/LexerSimple.cxx, lexlib/PropSetSimple.cxx, lexlib/StyleContext.cxx, lexlib/StyleContext.h, lexlib/WordList.cxx, scripts/FileGenerator.py, scripts/HeaderOrder.txt, scripts/LexGen.py, scripts/ScintillaData.py, src/AutoComplete.cxx, src/AutoComplete.h, src/CallTip.cxx, src/CallTip.h, src/CaseConvert.cxx, src/CaseFolder.h, src/Catalogue.cxx, src/CellBuffer.cxx, src/CellBuffer.h, src/CharClassify.cxx, src/CharClassify.h, src/ContractionState.cxx, src/ContractionState.h, src/Decoration.cxx, src/Decoration.h, src/Document.cxx, src/Document.h, src/EditModel.cxx, src/EditModel.h, src/EditView.cxx, src/EditView.h, src/Editor.cxx, src/Editor.h, src/ExternalLexer.cxx, src/ExternalLexer.h, src/Indicator.cxx, src/KeyMap.cxx, src/LineMarker.cxx, src/LineMarker.h, src/MarginView.cxx, src/MarginView.h, src/Partitioning.h, src/PerLine.cxx, src/PerLine.h, src/Position.h, src/PositionCache.cxx, src/PositionCache.h, src/RESearch.cxx, src/RESearch.h, src/RunStyles.cxx, src/RunStyles.h, src/ScintillaBase.cxx, src/ScintillaBase.h, src/Selection.cxx, src/Selection.h, src/SparseVector.h, src/SplitVector.h, src/Style.cxx, src/Style.h, src/UniConversion.cxx, src/UniConversion.h, src/UniqueString.h, src/ViewStyle.cxx, src/ViewStyle.h, src/XPM.cxx, src/XPM.h, test/gi/Scintilla- filtered.h, test/unit/testCellBuffer.cxx, test/unit/testCharClassify.cxx, test/unit/testContractionState.cxx, test/unit/testDecoration.cxx, test/unit/testPartitioning.cxx, test/unit/testRunStyles.cxx, test/unit/testSparseState.cxx, test/unit/testSparseVector.cxx, test/unit/testSplitVector.cxx, test/unit/testUnicodeFromUTF8.cxx, version.txt, win32/HanjaDic.cxx, win32/PlatWin.cxx, win32/SciLexer.vcxproj, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/deps.mak, win32/makefile, win32/scintilla.mak: Rebased on Scintilla v3.7.6. [4822c10e2b59] * Merged the 2.10-maint branch into the trunk. [64e6e4c3471d] 2017-11-23 Phil Thompson * .hgtags: Added tag 2.10.2 for changeset bdfb9584af36 [d127fc44d4c4] <2.10-maint> * NEWS: Released as v2.10.2. [bdfb9584af36] [2.10.2] <2.10-maint> * qt/qscintilla.pro: Bumed the .so minor version. [4bb28057d3c2] <2.10-maint> 2017-11-13 Phil Thompson * NEWS, Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added setScrollWidth() , scrollWidth, setScrollWidthTracking() and scrollWidthTracking() to QsciScintilla. [c6e64e99cb12] <2.10-maint> 2017-11-01 Phil Thompson * qt/qsciscintilla.cpp: Fixed the handling of UTF8 call tips. [7aa9b863f330] <2.10-maint> 2017-07-04 Phil Thompson * qt/qscintilla.pro: Fixed case sensitivity of a couple of file names. [e9d9b80fd61b] <2.10-maint> * .hgignore: Ignore the new-style build directory. [6c20c6b41705] <2.10-maint> 2017-07-03 Phil Thompson * .hgtags: Added tag 2.10.1 for changeset 20e0e2d419ba [d6eba6c9e5ce] <2.10-maint> * NEWS: Released as v2.10.1. [20e0e2d419ba] [2.10.1] <2.10-maint> * rb-product: Updated the PyQt5 dependency to v5.9. [83200ee6b295] <2.10-maint> 2017-05-24 Phil Thompson * lib/README.doc: Updated the docs regarding use of build options supported by Scintilla. [fe6e73057d9e] <2.10-maint> 2017-05-15 Phil Thompson * Python/sip/qscilexer.sip, Python/sip/qscilexeravs.sip, Python/sip/qscilexerbash.sip, Python/sip/qscilexerbatch.sip, Python/sip/qscilexercoffeescript.sip, Python/sip/qscilexercpp.sip, Python/sip/qscilexercss.sip, Python/sip/qscilexerd.sip, Python/sip/qscilexerfortran77.sip, Python/sip/qscilexerhtml.sip, Python/sip/qscilexerlua.sip, Python/sip/qscilexerpascal.sip, Python/sip/qscilexerperl.sip, Python/sip/qscilexerpostscript.sip, Python/sip/qscilexerpov.sip, Python/sip/qscilexerpython.sip, Python/sip/qscilexerruby.sip, Python/sip/qscilexerspice.sip, Python/sip/qscilexersql.sip, Python/sip/qscilexertcl.sip, Python/sip/qscilexerverilog.sip, Python/sip/qscilexervhdl.sip: Added the lexer-specific re-implementations of previously internal methods to the Python bindings. [e8402392cedc] <2.10-maint> 2017-03-22 Phil Thompson * qt/qscintilla.pro: Enabled explicit C++11 support for Linux for old versions of GCC. [e0e0b344ccf1] <2.10-maint> 2017-03-16 Phil Thompson * qt/qscilexer.cpp: Changed the default macOS font to Menlo 12pt as it has bold etc. [39d69e37d352] <2.10-maint> * qt/qscilexer.cpp: Changed the default font on macOS to Monaco 12pt. [9030535e2457] <2.10-maint> * Python/configure.py: Fixed the rpath change of the Python bindings on macOS. [dd45e695812a] <2.10-maint> 2017-02-22 Phil Thompson * qt/qscintilla.pro: Fixed the .pro file so that debug builds match the features file. [1aedd0c6eeda] <2.10-maint> 2017-02-20 Phil Thompson * .hgtags: Added tag 2.10 for changeset 6c07847b2835 [2442f8d2df34] * NEWS: Released as v2.10. [6c07847b2835] [2.10] * qt/qscintilla_cs.qm, qt/qscintilla_de.qm, qt/qscintilla_es.qm, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm: Updated the .qm files. [3b3c5924e746] * qt/qscintilla_fr.ts: Partial updated French translations from Alan Garny. [ca2d6917015e] 2017-02-17 Phil Thompson * Python/sip/qsciscintillabase.sip: Added /Transfer/ to the scroll bar replacement functions. [49cf7181402a] 2017-02-15 Phil Thompson * qt/qscintilla_de.ts: Updated German translations from Detlev. [51cca6073075] 2017-02-14 Phil Thompson * qt/qscintilla_es.ts: Updated Spanish translations from Jaime Seuma. [0e30abdd0907] 2017-02-13 Phil Thompson * designer-Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro, qt/qscintilla.pro: Removed the 'release' option from all CONFIG lines. [0901267a8e49] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added replaceHorizontalScrollBar() and replaceVerticalScrollBar() to QsciScintillaBase. [bb7efd26b8b3] * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts: Updated the translation files. [76c23d751930] 2017-01-21 Phil Thompson * Python/sip/qscilexermarkdown.sip, qt/qscilexerjson.cpp, qt/qscilexermarkdown.cpp, qt/qscilexermarkdown.h: Updated the Markdown lexer with the latest settings from Detlev. [9e9992a4e9f7] 2017-01-17 Phil Thompson * qt/qsciapis.cpp: Fixed problems with auto-completion lists where contexts and image identifiers were getting lost. [039599ba1b85] 2017-01-16 Phil Thompson * designer-Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro: Fixed the example and designer plugin .pro files for the change library name. [d6c564089958] * lib/README.doc: Updated website links to https. [18a7013d4f8b] * qt/qsciabstractapis.h, qt/qsciapis.h, qt/qscicommand.h, qt/qscicommandset.h, qt/qscidocument.h, qt/qsciglobal.h, qt/qscilexer.h, qt/qscilexeravs.h, qt/qscilexerbash.h, qt/qscilexerbatch.h, qt/qscilexercmake.h, qt/qscilexercoffeescript.h, qt/qscilexercpp.h, qt/qscilexercsharp.h, qt/qscilexercss.h, qt/qscilexercustom.h, qt/qscilexerd.h, qt/qscilexerdiff.h, qt/qscilexerfortran.h, qt/qscilexerfortran77.h, qt/qscilexerhtml.h, qt/qscilexeridl.h, qt/qscilexerjava.h, qt/qscilexerjavascript.h, qt/qscilexerjson.h, qt/qscilexerlua.h, qt/qscilexermakefile.h, qt/qscilexermarkdown.h, qt/qscilexermatlab.h, qt/qscilexeroctave.h, qt/qscilexerpascal.h, qt/qscilexerperl.h, qt/qscilexerpo.h, qt/qscilexerpostscript.h, qt/qscilexerpov.h, qt/qscilexerproperties.h, qt/qscilexerpython.h, qt/qscilexerruby.h, qt/qscilexerspice.h, qt/qscilexersql.h, qt/qscilexertcl.h, qt/qscilexertex.h, qt/qscilexerverilog.h, qt/qscilexervhdl.h, qt/qscilexerxml.h, qt/qscilexeryaml.h, qt/qscimacro.h, qt/qsciprinter.h, qt/qsciscintilla.h, qt/qsciscintillabase.h, qt/qscistyle.h, qt/qscistyledtext.h: Removed all the __APPLE__ C++ linkages. [ecd39912cb9b] * NEWS, Python/sip/qscilexer.sip, qt/qscilexer.h: The previously internal methods of QsciLexer are now part of the public API and are exposed to Python. [4791eae227c6] * NEWS, Python/configure.py, qt/features/qscintilla2.prf, qt/features_staticlib/qscintilla2.prf, qt/qscintilla.pro: The name of the library now embeds the major version of Qt so that Qt4 and Qt5 libraries can be installed in the same directory. [b501dcc67049] * NEWS, Python/sip/qsciscintilla.sip, qt/qscilexercustom.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Implemented QscScintilla::bytes() and a corresponding text() overload mainly for the use of QsciLexerCustom::styleText() implementations. [ed7a5a072695] 2017-01-15 Phil Thompson * Python/sip/qsciscintillabase.sip: Updated the sub-class convertor code. [ee4e6efa0576] * NEWS, Python/sip/qscilexermarkdown.sip, Python/sip/qscimodcommon.sip, qt/qscilexermarkdown.cpp, qt/qscilexermarkdown.h, qt/qscintilla.pro: Added the QsciLexerMarkdown class. [0b5e03e0b64f] 2017-01-11 Phil Thompson * NEWS, Python/sip/qscilexerjson.sip, Python/sip/qscimodcommon.sip, qt/qscilexerjson.cpp, qt/qscilexerjson.h, qt/qscintilla.pro: Implemented QsciLexerJSON. [bb5118a2b0cb] 2017-01-05 Phil Thompson * NEWS, Python/sip/qscilexercoffeescript.sip, qt/qscilexercoffeescript.cpp, qt/qscilexercoffeescript.h: Added InstanceProperty to QsciLexerCoffeeScript. [2a6987f4c3c3] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Implemented the new notifications. [12ba81979751] 2017-01-04 Phil Thompson * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added the low-level popup options. [6a6fccaf8adf] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added support for multiple edge columns. [761b940d39c6] 2017-01-03 Phil Thompson * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added the low-level idle styling support. [fe8c747abb81] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added the low-level support for fold text. [3afaaf7830c6] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Updates to the low-level target support. [709bfb578a28] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added support for the additional indicators. [fb7bcbfc6c96] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added some more low-level constants. [d19d12e79c31] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added support for setting the margin background colour. Added support for setting the number of margins. [407db46c80a6] * qt/qscilexercustom.cpp, qt/qscilexercustom.h: Fixed QsciLexerCustom::startStyling() now that the 2nd argument isn't used. [2d4cc3cdb123] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added support for visible whitespace in indentations only. Added support for tab drawing modes. [1ef385e510b8] * qt/InputMethod.cpp: Updated the inputMethodEvent() implementation. [f0060458bd73] 2017-01-02 Phil Thompson * qt/InputMethod.cpp, qt/ScintillaQt.cpp, qt/ScintillaQt.h: Fixed compilation bugs with SCI_NAMESPACE defined. [ef072ff5da5e] * lib/README.doc: Minor documentation updates. [f89ceb95b9c5] * qt/qsciscintillabase.cpp: Fixed compilation bugs. [8fdfb9bca00d] * CONTRIBUTING, Python/configure-old.py, Python/configure.py, README, cocoa/PlatCocoa.h, cocoa/PlatCocoa.mm, cocoa/ScintillaCocoa.h, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/Info.plist, cocoa/ ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj, coc oa/ScintillaFramework/ScintillaFramework.xcodeproj/project.xcworkspa ce/contents.xcworkspacedata, cocoa/ScintillaFramework/ScintillaFrame work.xcodeproj/xcshareddata/xcschemes/Scintilla.xcscheme, cocoa/ScintillaFramework/module.modulemap, cocoa/ScintillaTest/AppController.h, cocoa/ScintillaTest/AppController.mm, cocoa/ScintillaTest/English.lproj/MainMenu.xib, cocoa/ScintillaTest/Info.plist, cocoa/ScintillaTest/ScintillaTest.xcodeproj/project.pbxproj, cocoa/S cintillaTest/ScintillaTest.xcodeproj/project.xcworkspace/contents.xc workspacedata, cocoa/ScintillaView.h, cocoa/ScintillaView.mm, cocoa/checkbuildosx.sh, cppcheck.suppress, delcvs.bat, designer- Qt4Qt5/designer.pro, doc/Design.html, doc/Icons.html, doc/Lexer.txt, doc/Privacy.html, doc/SciCoding.html, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/ScintillaToDo.html, doc/ScintillaUsage.html, doc/index.html, example- Qt4Qt5/application.pro, gtk/Converter.h, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/ScintillaGTK.h, gtk/ScintillaGTKAccessible.cxx, gtk/ScintillaGTKAccessible.h, gtk/deps.mak, gtk/makefile, gtk/scintilla-marshal.c, gtk/scintilla- marshal.h, gtk/scintilla-marshal.list, include/ILexer.h, include/Platform.h, include/SciLexer.h, include/Sci_Position.h, include/Scintilla.h, include/Scintilla.iface, include/ScintillaWidget.h, lexers/LexA68k.cxx, lexers/LexAPDL.cxx, lexers/LexASY.cxx, lexers/LexAU3.cxx, lexers/LexAVE.cxx, lexers/LexAVS.cxx, lexers/LexAbaqus.cxx, lexers/LexAda.cxx, lexers/LexAsm.cxx, lexers/LexAsn1.cxx, lexers/LexBaan.cxx, lexers/LexBash.cxx, lexers/LexBasic.cxx, lexers/LexBatch.cxx, lexers/LexBibTeX.cxx, lexers/LexBullant.cxx, lexers/LexCLW.cxx, lexers/LexCOBOL.cxx, lexers/LexCPP.cxx, lexers/LexCSS.cxx, lexers/LexCaml.cxx, lexers/LexCmake.cxx, lexers/LexCoffeeScript.cxx, lexers/LexConf.cxx, lexers/LexCrontab.cxx, lexers/LexCsound.cxx, lexers/LexD.cxx, lexers/LexDMAP.cxx, lexers/LexDMIS.cxx, lexers/LexDiff.cxx, lexers/LexECL.cxx, lexers/LexEDIFACT.cxx, lexers/LexEScript.cxx, lexers/LexEiffel.cxx, lexers/LexErlang.cxx, lexers/LexErrorList.cxx, lexers/LexFlagship.cxx, lexers/LexForth.cxx, lexers/LexFortran.cxx, lexers/LexGAP.cxx, lexers/LexGui4Cli.cxx, lexers/LexHTML.cxx, lexers/LexHaskell.cxx, lexers/LexHex.cxx, lexers/LexInno.cxx, lexers/LexJSON.cxx, lexers/LexKVIrc.cxx, lexers/LexKix.cxx, lexers/LexLaTeX.cxx, lexers/LexLisp.cxx, lexers/LexLout.cxx, lexers/LexLua.cxx, lexers/LexMMIXAL.cxx, lexers/LexMPT.cxx, lexers/LexMSSQL.cxx, lexers/LexMagik.cxx, lexers/LexMake.cxx, lexers/LexMarkdown.cxx, lexers/LexMatlab.cxx, lexers/LexMetapost.cxx, lexers/LexModula.cxx, lexers/LexMySQL.cxx, lexers/LexNimrod.cxx, lexers/LexNsis.cxx, lexers/LexNull.cxx, lexers/LexOScript.cxx, lexers/LexOpal.cxx, lexers/LexOthers.cxx, lexers/LexPB.cxx, lexers/LexPLM.cxx, lexers/LexPO.cxx, lexers/LexPOV.cxx, lexers/LexPS.cxx, lexers/LexPascal.cxx, lexers/LexPerl.cxx, lexers/LexPowerPro.cxx, lexers/LexPowerShell.cxx, lexers/LexProgress.cxx, lexers/LexProps.cxx, lexers/LexPython.cxx, lexers/LexR.cxx, lexers/LexRebol.cxx, lexers/LexRegistry.cxx, lexers/LexRuby.cxx, lexers/LexRust.cxx, lexers/LexSML.cxx, lexers/LexSQL.cxx, lexers/LexSTTXT.cxx, lexers/LexScriptol.cxx, lexers/LexSmalltalk.cxx, lexers/LexSorcus.cxx, lexers/LexSpecman.cxx, lexers/LexSpice.cxx, lexers/LexTACL.cxx, lexers/LexTADS3.cxx, lexers/LexTAL.cxx, lexers/LexTCL.cxx, lexers/LexTCMD.cxx, lexers/LexTeX.cxx, lexers/LexTxt2tags.cxx, lexers/LexVB.cxx, lexers/LexVHDL.cxx, lexers/LexVerilog.cxx, lexers/LexVisualProlog.cxx, lexers/LexYAML.cxx, lexlib/Accessor.cxx, lexlib/Accessor.h, lexlib/CharacterSet.cxx, lexlib/CharacterSet.h, lexlib/LexAccessor.h, lexlib/LexerBase.cxx, lexlib/LexerBase.h, lexlib/LexerModule.cxx, lexlib/LexerModule.h, lexlib/LexerNoExceptions.cxx, lexlib/LexerNoExceptions.h, lexlib/LexerSimple.cxx, lexlib/LexerSimple.h, lexlib/StyleContext.cxx, lexlib/StyleContext.h, lexlib/SubStyles.h, lexlib/WordList.cxx, lexlib/WordList.h, qt/qscintilla.pro, scripts/Face.py, scripts/FileGenerator.py, scripts/GenerateCaseConvert.py, scripts/HeaderCheck.py, scripts/HeaderOrder.txt, scripts/LexGen.py, scripts/ScintillaData.py, src/AutoComplete.cxx, src/CallTip.cxx, src/CaseConvert.cxx, src/CaseConvert.h, src/CaseFolder.cxx, src/Catalogue.cxx, src/CellBuffer.cxx, src/CellBuffer.h, src/CharClassify.cxx, src/CharClassify.h, src/ContractionState.cxx, src/ContractionState.h, src/Decoration.cxx, src/Document.cxx, src/Document.h, src/EditModel.cxx, src/EditModel.h, src/EditView.cxx, src/EditView.h, src/Editor.cxx, src/Editor.h, src/ExternalLexer.cxx, src/Indicator.cxx, src/Indicator.h, src/KeyMap.cxx, src/KeyMap.h, src/LineMarker.cxx, src/MarginView.cxx, src/PerLine.cxx, src/Position.h, src/PositionCache.cxx, src/PositionCache.h, src/RESearch.cxx, src/RESearch.h, src/RunStyles.cxx, src/ScintillaBase.cxx, src/ScintillaBase.h, src/Selection.cxx, src/Selection.h, src/SparseVector.h, src/SplitVector.h, src/Style.cxx, src/Style.h, src/UniConversion.cxx, src/UniConversion.h, src/ViewStyle.cxx, src/ViewStyle.h, src/XPM.cxx, test/ScintillaCallable.py, test/XiteQt.py, test/XiteWin.py, test/examples/perl-test- 5220delta.pl, test/examples/perl-test-5220delta.pl.styled, test/examples/perl-test-sub-prototypes.pl, test/examples/perl-test- sub-prototypes.pl.styled, test/gi/Scintilla-0.1.gir.good, test/gi /Scintilla-filtered.h, test/gi/filter-scintilla-h.py, test/gi/gi- test.py, test/gi/makefile, test/lexTests.py, test/simpleTests.py, test/unit/Sci.natvis, test/unit/UnitTester.cxx, test/unit/UnitTester.vcxproj, test/unit/makefile, test/unit/test.mak, test/unit/testCellBuffer.cxx, test/unit/testContractionState.cxx, test/unit/testDecoration.cxx, test/unit/testPartitioning.cxx, test/unit/testRunStyles.cxx, test/unit/testSparseState.cxx, test/unit/testSparseVector.cxx, test/unit/testSplitVector.cxx, test/unit/testWordList.cxx, version.txt, win32/HanjaDic.cxx, win32/HanjaDic.h, win32/PlatWin.cxx, win32/SciLexer.vcxproj, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/deps.mak, win32/makefile, win32/scintilla.mak: Initial merge of Scintilla v3.7.2. [abbfc844caaa] * lib/LICENSE.commercial.short, lib/LICENSE.gpl, lib/LICENSE.gpl.short: Updated the copyright notices. [10d2ba70b9d0] * Makefile, build.py: Merged the v2.9 maintenance branch. [8c0c0a19a3c8] 2016-12-25 Phil Thompson * .hgtags: Added tag 2.9.4 for changeset 06e486532f86 [a0e7ce41b57a] <2.9-maint> * NEWS: Released as v2.9.4. [06e486532f86] [2.9.4] <2.9-maint> 2016-12-24 Phil Thompson * qsci/api/python/Python-3.6.api: Added the .api file for Python v3.6. [4af5841ab5d2] <2.9-maint> 2016-11-07 Phil Thompson * qt/qsciscintillabase.cpp: Updated a comment to explain why setting custom scrollbars doesn't work. [757ca3bbc419] <2.9-maint> 2016-10-25 Phil Thompson * Python/configure.py: Fixed configure.py for Python v2. [6d784269a812] <2.9-maint> 2016-10-23 Phil Thompson * Python/sip/qscimod4.sip, Python/sip/qscimod5.sip: Explicitly %Import the QtCore module so that it is imported in the .pyi file. [fec61f546e2b] <2.9-maint> 2016-09-26 Phil Thompson * lib/README.doc: Removed some (possibly out of date) information about installation on macOS. [c793591a8192] <2.9-maint> * qt/InputMethod.cpp: Disable the hack for handling null input method method events on Windows as there are reports that this breaks character composition. [42977285ae81] <2.9-maint> 2016-09-25 Phil Thompson * qt/qsciscintilla.cpp: Fixed a Qt warning about a too large red value in a QColor. [f9af82c24301] <2.9-maint> 2016-09-23 Phil Thompson * rb-product: Added the minimum PyQt5 wheel version to the product file. [11d2fb4dc51a] <2.9-maint> 2016-09-10 Phil Thompson * Python/configure.py, rb-product: Updated the handling of the minimum SIP version. [1e50ffa9dac1] <2.9-maint> 2016-09-09 Phil Thompson * Python/sip/qscimod5.sip: The limited API is now used for the Python bindings. [a2b8118a4483] <2.9-maint> 2016-08-08 Phil Thompson * Makefile, build.py: Removed the old internal build system. [522e8b386eef] <2.9-maint> 2016-07-25 Phil Thompson * METADATA.in: Removed the Obsoletes tag from METADATA. [fbf9aa05d0b4] <2.9-maint> * .hgtags: Added tag 2.9.3 for changeset 19c9752958b7 [fb5cd006685f] <2.9-maint> * NEWS: Released as v2.9.3. [19c9752958b7] [2.9.3] <2.9-maint> 2016-07-19 Phil Thompson * METADATA.in: Updated METADATA. [aa51b27d9baf] <2.9-maint> 2016-06-21 Phil Thompson * build.py, lib/qscintilla.dxy: Simplify the generation of the doxygen documentation. [12575460cd55] <2.9-maint> * rb-product, rbproduct.py: Replaced the product plugin with a product file. [846ad54d791e] <2.9-maint> 2016-06-10 Phil Thompson * qt/ScintillaQt.cpp, qt/qscintilla.pro: Fixed a flicker problem on OS X. [c1482a759dc0] <2.9-maint> 2016-05-12 Phil Thompson * METADATA.in, rbproduct.py: Try to prevent the GPL and commercial versions being installed at the same time. (Although it doesn't seem to work.) [826424d291a2] <2.9-maint> * METADATA.in, rbproduct.py: Configure the PKG-INFO meta-data according to the license. [e3243207aa15] <2.9-maint> 2016-05-10 Phil Thompson * rbproduct.py: More changes to the product plugin required by rbtools. [437e6032e4df] <2.9-maint> 2016-05-09 Phil Thompson * rbproduct.py: Updated the product plugin for the latest rbtools changes. [393cae59af91] <2.9-maint> 2016-04-22 Phil Thompson * METADATA.in: Updated the meta-data now that Linux wheels are available from PyPI. [40f18e066c6f] <2.9-maint> 2016-04-18 Phil Thompson * .hgtags: Added tag 2.9.2 for changeset 15888f3e91ce [5cd132938309] <2.9-maint> * NEWS: Released as v2.9.2. [15888f3e91ce] [2.9.2] <2.9-maint> * Python/sip/qsciscintillabase.sip: Remove all deprecated /DocType/ annotations. [b9d570ab642a] <2.9-maint> 2016-04-17 Phil Thompson * rbproduct.py: Locate the static library on Windows. [dd8c14dace83] <2.9-maint> * rbproduct.py: Fixed a typo. [baf5c942f528] <2.9-maint> * rbproduct.py: Add any pre-installed .api files to the wheel. [cf7b6302ae83] <2.9-maint> * rbproduct.py: Exploit verbose mode in the product plugin. [da743c037880] <2.9-maint> * rbproduct.py: Fixed permissions of the product plugin. [6fac075e0b88] <2.9-maint> 2016-04-16 Phil Thompson * Makefile: Updated the clean target. [692b14f48ade] <2.9-maint> * rbproduct.py: The wheel now includes translations and API files. [bf911094e537] <2.9-maint> * METADATA.in, Makefile, Python/configure.py, build.py, rbproduct.py: Added the initial support for creating wheels. [da0a5d22e864] <2.9-maint> * Makefile, build.py: Added the --omit-license-tag option to build.py. Added the dist- wheel-gpl target to the master Makefile. [a63c245de735] <2.9-maint> 2016-04-15 Phil Thompson * Python/configure-old.py, Python/configure.py, build.py, qt/features/qscintilla2.prf, qt/features_staticlib/qscintilla2.prf, qt/qsciglobal.h, qt/qscintilla.pro: Symbols are now hidden if possible on all platforms. Improved the handling of QSCINTILLA_DLL so it should be completely automatic. Removed the --no-dll option to configure.py. [e35caca29dd6] <2.9-maint> 2016-03-25 Phil Thompson * Python/configure-old.py, build.py: Use the new naming standards for development versions. [21d2f882320a] <2.9-maint> 2016-03-14 Phil Thompson * Python/configure.py, build.py: The configure.py boilerplate code is applied automatically. [848f3fca41c0] <2.9-maint> 2016-03-13 Phil Thompson * Python/configure.py: Updated the configure.py boilerplate. [b3fd404a1134] <2.9-maint> 2016-03-07 Phil Thompson * Python/configure.py: Added support for PEP 484 stub files to configure.py. [9316fed27503] <2.9-maint> 2015-12-15 Phil Thompson * Makefile: Switched the internal build system to Python v3.5. [5215e7f3116e] <2.9-maint> 2015-10-28 Phil Thompson * Python/configure.py: Handle PATH components that are enclosed in quotes. [d0f19b69ce26] <2.9-maint> 2015-10-24 Phil Thompson * .hgtags: Added tag 2.9.1 for changeset 9bd39be91ef8 [c71bd22d6ccf] <2.9-maint> * NEWS: Released as v2.9.1. [9bd39be91ef8] [2.9.1] <2.9-maint> 2015-10-17 Phil Thompson * qt/qsciscintilla.cpp: Fixed the handling of the keypad modifier. [e363cc2c347f] <2.9-maint> 2015-09-18 Phil Thompson * qsci/api/python/Python-3.5.api: Added the .api file for Python v3.5. [5b4e58de4663] <2.9-maint> 2015-09-10 Phil Thompson * Python/sip/qsciabstractapis.sip, Python/sip/qsciapis.sip: Fixed the Python binding for QsciAbstractAPIs::updateAutoCompletionList(). [53f2939a3b29] <2.9-maint> 2015-09-08 Phil Thompson * Python/configure.py: Use win32-msvc2015 for Python v3.5 and later. [2f264662e2c7] <2.9-maint> 2015-09-01 Phil Thompson * qt/qsciscintilla.cpp: Fixed the restyling of a document displayed in multiple editors. [9309f264ab57] <2.9-maint> 2015-08-24 Phil Thompson * qt/qscintilla.pro, qt/qsciscintilla.cpp: Fixed a problem starting a call tip when the auto-completion list is displayed. Bumped the library version. [2ec2115ea4d2] <2.9-maint> 2015-07-12 Phil Thompson * designer-Qt4Qt5/qscintillaplugin.h: Fixed a warning message when compiling against Qt v5.5.0. [3ff05a0ef88d] <2.9-maint> 2015-07-09 Phil Thompson * Python/configure.py: Update QMAKE_RPATHDIR rather than set it. [045c64a7e65c] <2.9-maint> 2015-06-24 Phil Thompson * Python/configure.py: Set QMAKE_RPATHDIR for Qt v5.5 on OS X. [b83394e4a676] <2.9-maint> 2015-05-26 Phil Thompson * Python/configure.py: Fixed the backstop handling in the Python bindings configuration script and bumped the version number. [1ab1dd7ea495] <2.9-maint> 2015-05-02 Phil Thompson * qt/qscintilla.pro: Use QT_HOST_DATA for the .prf destination with Qt v5. Removed all Qt v3 support from the .pro file. [63c0391624a8] <2.9-maint> 2015-04-20 Phil Thompson * .hgtags: Added tag 2.9 for changeset 41ee8162fa81 [9817b0a7a4f7] * NEWS: Released as v2.9. [41ee8162fa81] [2.9] 2015-04-14 Phil Thompson * qt/qsciscintillabase.cpp: Fixed a problem notifying when focus is lost to another application widget. [41734678234e] 2015-04-06 Phil Thompson * qt/qsciscintillabase.cpp: Fixed a crash when deleting an instance. [eb936ad1f826] 2015-04-05 Phil Thompson * qt/qsciscintilla.cpp: Fixed a problem applying a lexer's styles that manifested itself by the wrong style being applied to line numbers when using a custom lexer. [c91009909b8e] 2015-04-04 Phil Thompson * qt/qscintilla_es.qm, qt/qscintilla_es.ts: Updated Spanish translations from Jaime. [d94218e7d47d] * qt/ScintillaQt.h: Fixed some header file dependencies. [f246e863957f] * qt/qscintilla_cs.qm, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_es.qm, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm: Updated German translations from Detlev. [01f3be277e14] 2015-04-03 Phil Thompson * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts: Updated the .ts translation files. [659fb035d1c4] 2015-04-02 Phil Thompson * qt/qsciapis.cpp: Fixed a problem displaying call-tips when auto-completion is enabled. [82ec45421a3d] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.h, qt/qsciscintillabase.h: Exposed the remaining new features. [6e84b61268c5] 2015-04-01 Phil Thompson * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Exposing new Scintilla functionality. [e0965dc46693] 2015-03-31 Phil Thompson * qt/qscilexerverilog.cpp, qt/qscilexerverilog.h: Enabled the new styling features of QsciLexerVerilog. [5be65189b15f] * NEWS, Python/sip/qscilexercpp.sip, qt/qscilexercpp.cpp, qt/qscilexercpp.h: Completed the updates to QsciLexerCPP. [a8e24b727d82] * NEWS, Python/sip/qscilexercpp.sip, Python/sip/qscilexersql.sip, Python/sip/qscilexerverilog.sip, Python/sip/qscilexervhdl.sip, Python/sip/qsciscintillabase.sip, qt/qscilexercpp.cpp, qt/qscilexercpp.h, qt/qscilexersql.cpp, qt/qscilexersql.h, qt/qscilexerverilog.cpp, qt/qscilexerverilog.h, qt/qscilexervhdl.cpp, qt/qscilexervhdl.h, qt/qsciscintillabase.h: Updated existing lexers with new styles. [768f8ff280e1] 2015-03-30 Phil Thompson * qt/qsciapis.cpp: Make sure call tips don't include image types. [d0830816cda4] * qt/ScintillaQt.cpp, qt/ScintillaQt.h: Fixed the horizontal scrollbar issues, particularly with long lines. [db8501c0803f] 2015-03-29 Phil Thompson * qt/ScintillaQt.cpp: Updated the paste support. [42ad3657d52e] * qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qsciscintillabase.cpp: Added support for idle processing. [ff277e910df7] 2015-03-27 Phil Thompson * NEWS: Updated the NEWS file. [64766fb4c800] * qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Add support for fine tickers. [3e9b89430dc0] 2015-03-26 Phil Thompson * Makefile, Python/sip/qsciabstractapis.sip, Python/sip/qsciapis.sip, Python/sip/qscicommandset.sip, Python/sip/qscilexer.sip, Python/sip/qscilexeravs.sip, Python/sip/qscilexerbash.sip, Python/sip/qscilexerbatch.sip, Python/sip/qscilexercmake.sip, Python/sip/qscilexercoffeescript.sip, Python/sip/qscilexercpp.sip, Python/sip/qscilexercsharp.sip, Python/sip/qscilexercss.sip, Python/sip/qscilexercustom.sip, Python/sip/qscilexerd.sip, Python/sip/qscilexerdiff.sip, Python/sip/qscilexerfortran.sip, Python/sip/qscilexerfortran77.sip, Python/sip/qscilexerhtml.sip, Python/sip/qscilexeridl.sip, Python/sip/qscilexerjava.sip, Python/sip/qscilexerjavascript.sip, Python/sip/qscilexerlua.sip, Python/sip/qscilexermakefile.sip, Python/sip/qscilexermatlab.sip, Python/sip/qscilexeroctave.sip, Python/sip/qscilexerpascal.sip, Python/sip/qscilexerperl.sip, Python/sip/qscilexerpo.sip, Python/sip/qscilexerpostscript.sip, Python/sip/qscilexerpov.sip, Python/sip/qscilexerproperties.sip, Python/sip/qscilexerpython.sip, Python/sip/qscilexerruby.sip, Python/sip/qscilexerspice.sip, Python/sip/qscilexersql.sip, Python/sip/qscilexertcl.sip, Python/sip/qscilexertex.sip, Python/sip/qscilexerverilog.sip, Python/sip/qscilexervhdl.sip, Python/sip/qscilexerxml.sip, Python/sip/qscilexeryaml.sip, Python/sip/qscimacro.sip, Python/sip/qscimod3.sip, Python/sip/qscimod4.sip, Python/sip/qscimod5.sip, Python/sip/qscimodcommon.sip, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, build.py, designer-Qt3/designer.pro, designer- Qt3/qscintillaplugin.cpp, example-Qt3/application.cpp, example- Qt3/application.h, example-Qt3/application.pro, example- Qt3/fileopen.xpm, example-Qt3/fileprint.xpm, example- Qt3/filesave.xpm, example-Qt3/main.cpp, lib/README, lib/README.doc, lib/qscintilla.dxy, qt/InputMethod.cpp, qt/ListBoxQt.cpp, qt/PlatQt.cpp, qt/SciClasses.cpp, qt/SciClasses.h, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qsciabstractapis.cpp, qt/qsciabstractapis.h, qt/qsciapis.cpp, qt/qsciapis.h, qt/qscicommandset.cpp, qt/qscicommandset.h, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscilexeravs.cpp, qt/qscilexeravs.h, qt/qscilexerbash.cpp, qt/qscilexerbash.h, qt/qscilexerbatch.cpp, qt/qscilexerbatch.h, qt/qscilexercmake.cpp, qt/qscilexercmake.h, qt/qscilexercoffeescript.cpp, qt/qscilexercoffeescript.h, qt/qscilexercpp.cpp, qt/qscilexercpp.h, qt/qscilexercsharp.cpp, qt/qscilexercsharp.h, qt/qscilexercss.cpp, qt/qscilexercss.h, qt/qscilexercustom.cpp, qt/qscilexercustom.h, qt/qscilexerd.cpp, qt/qscilexerd.h, qt/qscilexerdiff.cpp, qt/qscilexerdiff.h, qt/qscilexerfortran.cpp, qt/qscilexerfortran.h, qt/qscilexerfortran77.cpp, qt/qscilexerfortran77.h, qt/qscilexerhtml.cpp, qt/qscilexerhtml.h, qt/qscilexeridl.cpp, qt/qscilexeridl.h, qt/qscilexerjava.cpp, qt/qscilexerjava.h, qt/qscilexerjavascript.cpp, qt/qscilexerjavascript.h, qt/qscilexerlua.cpp, qt/qscilexerlua.h, qt/qscilexermakefile.cpp, qt/qscilexermakefile.h, qt/qscilexermatlab.cpp, qt/qscilexermatlab.h, qt/qscilexeroctave.cpp, qt/qscilexeroctave.h, qt/qscilexerpascal.cpp, qt/qscilexerpascal.h, qt/qscilexerperl.cpp, qt/qscilexerperl.h, qt/qscilexerpo.cpp, qt/qscilexerpo.h, qt/qscilexerpostscript.cpp, qt/qscilexerpostscript.h, qt/qscilexerpov.cpp, qt/qscilexerpov.h, qt/qscilexerproperties.cpp, qt/qscilexerproperties.h, qt/qscilexerpython.cpp, qt/qscilexerpython.h, qt/qscilexerruby.cpp, qt/qscilexerruby.h, qt/qscilexerspice.cpp, qt/qscilexerspice.h, qt/qscilexersql.cpp, qt/qscilexersql.h, qt/qscilexertcl.cpp, qt/qscilexertcl.h, qt/qscilexertex.cpp, qt/qscilexertex.h, qt/qscilexerverilog.cpp, qt/qscilexerverilog.h, qt/qscilexervhdl.cpp, qt/qscilexervhdl.h, qt/qscilexerxml.cpp, qt/qscilexerxml.h, qt/qscilexeryaml.cpp, qt/qscilexeryaml.h, qt/qscimacro.cpp, qt/qscimacro.h, qt/qsciprinter.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h, qt/qscistyle.cpp, qt/qscistyledtext.h: Removed all support for Qt3 and PyQt3. [b33b2f06716e] * Python/configure-old.py, Python/configure.py, designer- Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qscintilla.pro: The updated code now compiles. [35d05076c62f] * cocoa/InfoBar.h, cocoa/InfoBar.mm, cocoa/InfoBarCommunicator.h, cocoa/PlatCocoa.h, cocoa/PlatCocoa.mm, cocoa/QuartzTextLayout.h, cocoa/QuartzTextStyle.h, cocoa/ScintillaCocoa.h, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/ScintillaFramework .xcodeproj/project.pbxproj, cocoa/ScintillaTest/AppController.h, cocoa/ScintillaTest/ScintillaTest.xcodeproj/project.pbxproj, cocoa/ScintillaView.h, cocoa/ScintillaView.mm, cocoa/checkbuildosx.sh, cppcheck.suppress, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/index.html, gtk/Converter.h, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/deps.mak, gtk/makefile, include/Platform.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, lexers/LexAbaqus.cxx, lexers/LexAsm.cxx, lexers/LexBash.cxx, lexers/LexBasic.cxx, lexers/LexBibTeX.cxx, lexers/LexCPP.cxx, lexers/LexCmake.cxx, lexers/LexCoffeeScript.cxx, lexers/LexDMAP.cxx, lexers/LexDMIS.cxx, lexers/LexECL.cxx, lexers/LexEScript.cxx, lexers/LexForth.cxx, lexers/LexFortran.cxx, lexers/LexGui4Cli.cxx, lexers/LexHTML.cxx, lexers/LexHaskell.cxx, lexers/LexHex.cxx, lexers/LexKix.cxx, lexers/LexLua.cxx, lexers/LexMarkdown.cxx, lexers/LexMatlab.cxx, lexers/LexModula.cxx, lexers/LexMySQL.cxx, lexers/LexOthers.cxx, lexers/LexPS.cxx, lexers/LexPerl.cxx, lexers/LexRegistry.cxx, lexers/LexRuby.cxx, lexers/LexRust.cxx, lexers/LexSQL.cxx, lexers/LexScriptol.cxx, lexers/LexSpecman.cxx, lexers/LexTCL.cxx, lexers/LexTCMD.cxx, lexers/LexTxt2tags.cxx, lexers/LexVHDL.cxx, lexers/LexVerilog.cxx, lexers/LexVisualProlog.cxx, lexlib/Accessor.cxx, lexlib/Accessor.h, lexlib/CharacterCategory.cxx, lexlib/CharacterSet.cxx, lexlib/LexAccessor.h, lexlib/LexerBase.cxx, lexlib/LexerModule.cxx, lexlib/LexerModule.h, lexlib/LexerNoExceptions.cxx, lexlib/LexerSimple.cxx, lexlib/LexerSimple.h, lexlib/PropSetSimple.cxx, lexlib/SparseState.h, lexlib/StringCopy.h, lexlib/StyleContext.cxx, lexlib/StyleContext.h, lexlib/SubStyles.h, lexlib/WordList.cxx, lexlib/WordList.h, lib/README.doc, qt/qscintilla.pro, scripts/GenerateCaseConvert.py, scripts/GenerateCharacterCategory.py, scripts/HFacer.py, scripts/HeaderOrder.txt, scripts/LexGen.py, scripts/ScintillaData.py, src/AutoComplete.cxx, src/AutoComplete.h, src/CallTip.cxx, src/CaseConvert.cxx, src/CaseFolder.cxx, src/Catalogue.cxx, src/CellBuffer.cxx, src/CellBuffer.h, src/CharClassify.cxx, src/ContractionState.cxx, src/ContractionState.h, src/Decoration.cxx, src/Decoration.h, src/Document.cxx, src/Document.h, src/EditModel.cxx, src/EditModel.h, src/EditView.cxx, src/EditView.h, src/Editor.cxx, src/Editor.h, src/ExternalLexer.cxx, src/ExternalLexer.h, src/FontQuality.h, src/Indicator.cxx, src/Indicator.h, src/KeyMap.cxx, src/KeyMap.h, src/LineMarker.cxx, src/LineMarker.h, src/MarginView.cxx, src/MarginView.h, src/Partitioning.h, src/PerLine.cxx, src/PerLine.h, src/PositionCache.cxx, src/PositionCache.h, src/RESearch.cxx, src/RESearch.h, src/ScintillaBase.cxx, src/ScintillaBase.h, src/Selection.cxx, src/Selection.h, src/SplitVector.h, src/Style.cxx, src/Style.h, src/UniConversion.cxx, src/UniConversion.h, src/ViewStyle.cxx, src/ViewStyle.h, src/XPM.cxx, src/XPM.h, test/XiteQt.py, test/XiteWin.py, test/lexTests.py, test/simpleTests.py, test/unit/LICENSE_1_0.txt, test/unit/README, test/unit/SciTE.properties, test/unit/catch.hpp, test/unit/makefile, test/unit/test.mak, test/unit/testCellBuffer.cxx, test/unit/testCharClassify.cxx, test/unit/testContractionState.cxx, test/unit/testDecoration.cxx, test/unit/testPartitioning.cxx, test/unit/testRunStyles.cxx, test/unit/testSparseState.cxx, test/unit/testSplitVector.cxx, test/unit/testUnicodeFromUTF8.cxx, test/unit/unitTest.cxx, version.txt, win32/HanjaDic.cxx, win32/HanjaDic.h, win32/PlatWin.cxx, win32/PlatWin.h, win32/SciLexer.vcxproj, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/deps.mak, win32/makefile, win32/scintilla.mak: Added the initial import of Scintilla v3.5.4. [025db9484942] * lib/GPL_EXCEPTION.TXT, lib/GPL_EXCEPTION_ADDENDUM.TXT, lib/LICENSE.GPL2, lib/LICENSE.GPL3, lib/OPENSOURCE-NOTICE.TXT, qt/qscintilla_ru.qm, qt/qscintilla_ru.ts: Merged the 2.8-maint branch into the default. [efe1067a091a] 2015-03-19 Phil Thompson * qt/qsciscintilla.cpp: Fixed QsciScintilla::clearMarginText(). [885b972e38df] <2.8-maint> 2015-02-14 Phil Thompson * Makefile, Python/configure.py: Installing into a virtual env should now work. The internal build system supports sip5. [62d128cc92de] <2.8-maint> 2015-02-08 Phil Thompson * Python/configure.py: Use sip5 if available. [6f5e4b0dae8f] <2.8-maint> 2015-01-02 Phil Thompson * Python/configure.py, lib/LICENSE.commercial.short, lib/LICENSE.gpl, lib/LICENSE.gpl.short, qt/InputMethod.cpp: Updated the copyright notices. [50b9b459dc48] <2.8-maint> * Python/configure-old.py: Fixed configure-old.py for previews. [7ff9140391e4] <2.8-maint> 2014-12-22 Phil Thompson * build.py, lib/LICENSE.GPL3, lib/LICENSE.commercial.short, lib/LICENSE.gpl, lib/LICENSE.gpl.short: More license tweaks. [f3e84d697877] <2.8-maint> * build.py, lib/GPL_EXCEPTION.TXT, lib/GPL_EXCEPTION_ADDENDUM.TXT, lib/LICENSE.GPL2, lib/LICENSE.gpl.short, lib/OPENSOURCE-NOTICE.TXT, lib/README.doc: Aligned the GPL licensing with Qt. [aa58ba575cac] <2.8-maint> 2014-12-21 Phil Thompson * lib/LICENSE.commercial: Updated the commercial license to v4.0. [fd91beaa78dd] <2.8-maint> 2014-11-16 Phil Thompson * build.py: A source package now includes a full ChangeLog. [ba92c1d5c839] <2.8-maint> 2014-09-11 Phil Thompson * .hgtags: Added tag 2.8.4 for changeset e18756e8cf86 [e7f7a594518d] <2.8-maint> * .hgignore, NEWS: Released as v2.8.4. [e18756e8cf86] [2.8.4] <2.8-maint> 2014-09-04 Phil Thompson * NEWS: Updated the NEWS file. [e4e3562b54cb] <2.8-maint> 2014-09-03 Phil Thompson * Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added the missing SCI_SETHOTSPOTSINGLELINE to QsciScintillaBase. Added resetHotspotForegroundColor(), resetHotspotBackgroundColor(), setHotspotForegroundColor(), setHotspotBackgroundColor(), setHotspotUnderline() and setHotspotWrap() to QsciScintilla. [2da018f7e48c] <2.8-maint> 2014-07-31 Phil Thompson * qt/qsciscintilla.cpp: Attempted to improve the auto-indentation behaviour so that the indentation of a line is maintained if a new line has been inserted above by pressing enter at the start of the line. [aafc4a7247fb] <2.8-maint> 2014-07-11 Phil Thompson * Python/configure.py: Fixed the installation of the .api file. [aae8494847ff] <2.8-maint> 2014-07-10 Phil Thompson * Python/configure.py, designer-Qt4Qt5/designer.pro, qt/qscintilla.pro: Fixes to work around QTBUG-39300. Fix when building with a configuration file. [1051e8c260fd] <2.8-maint> 2014-07-03 Phil Thompson * .hgtags: Added tag 2.8.3 for changeset e9cb8530f97f [bb531051c8f3] <2.8-maint> * NEWS: Released as v2.8.3. [e9cb8530f97f] [2.8.3] <2.8-maint> 2014-07-01 Phil Thompson * Python/configure.py: Fixed a cut-and-paste bug in configure.py. [5f7c4c6c9a29] <2.8-maint> * Python/configure.py: Updated to the latest build system boilerplate. [ee0b9a647e7a] <2.8-maint> 2014-06-30 Phil Thompson * Makefile, Python/configure.py: Updates to the build system and the latest boilerplate configure.py. [8485111172c7] <2.8-maint> 2014-06-19 Phil Thompson * qt/qscilexercoffeescript.cpp, qt/qscintilla.pro, qt/qscintilla_cs.qm, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_es.qm, qt/qscintilla_es.ts, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm, qt/qscintilla_ru.qm, qt/qscintilla_ru.ts: Updated CoffeeScript keywords and German translations from Detlev. Updated Spanish translations from Jaime. Removed the Russian translations as none were current. [978fe16935c4] <2.8-maint> 2014-06-15 Phil Thompson * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the translation source files. [440ab56f1863] <2.8-maint> 2014-06-09 Phil Thompson * Python/sip/qscilexercoffeescript.sip, Python/sip/qscimodcommon.sip, Python/sip/qsciscintillabase.sip: Added QsciLexerCoffeeScript to the Python bindings. [36a6e2123a69] <2.8-maint> * qt/qscilexercoffeescript.h: QsciLexerCoffeeScript property setters are no longer virtual slots. [eef97550eb16] <2.8-maint> * qt/qscilexercoffeescript.cpp, qt/qscilexercoffeescript.h, qt/qscintilla.pro: Added the QsciLexerCoffeeScript class. [0cf56e9cd32a] <2.8-maint> 2014-06-03 Phil Thompson * Python/configure.py: Fixes for Python v2.6. [9b7b5393f228] <2.8-maint> 2014-06-01 Phil Thompson * Python/configure.py: Fixed a regression in configure.py when using the -n or -o options. [f7b1c9821894] <2.8-maint> 2014-05-29 Phil Thompson * qt/PlatQt.cpp, qt/qsciscintillabase.cpp: Fixes for Qt3. [4d0a54024b52] <2.8-maint> * qt/PlatQt.cpp, qt/qscilexer.cpp, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qscistyle.cpp: Font sizes are now handled as floating point values rather than integers. [ea017cc2b198] <2.8-maint> 2014-05-26 Phil Thompson * .hgtags: Added tag 2.8.2 for changeset 5aab3ae01e0e [6cc6eec7c440] <2.8-maint> * NEWS: Released as v2.8.2. [5aab3ae01e0e] [2.8.2] <2.8-maint> * Python/sip/qsciscintillabase.sip: Updated the sub-class converter code. [9b276dae576d] <2.8-maint> * Makefile: Internal build system fixes. [b29b24829b0b] <2.8-maint> 2014-05-24 Phil Thompson * Makefile, Python/configure.py: Fixed some build regressions with PyQt4. [175b657ad031] <2.8-maint> 2014-05-18 Phil Thompson * Makefile: Updates to the top-level Makefile for the latest Android tools. [405fb3eb5473] <2.8-maint> 2014-05-17 Phil Thompson * Makefile: Added the PyQt4 against Qt5 on the iPhone simulator build target. [c31ae5795eec] <2.8-maint> 2014-05-16 Phil Thompson * Makefile, Python/configure.py: Use the PyQt .sip files in sysroot when cross-compiling. [5d8e8b8ddfe5] <2.8-maint> * Makefile, Python/configure.py: Replaced pyqt_sip_flags with pyqt_disabled_features in the configuration file. [f209403c183b] <2.8-maint> 2014-05-15 Phil Thompson * Makefile, Python/sip/qscimod5.sip: The PyQt5 bindings now run on the iOS simulator. [056871b18335] <2.8-maint> * Makefile, Python/configure.py: Building the Python bindings for the iOS simulator now works. [9dfcea4447b8] <2.8-maint> * Makefile: Updated the main Makefile for the Qt v5.2 iOS support. [a619fd411878] <2.8-maint> 2014-05-14 Phil Thompson * Python/configure.py: Don't create the .api file if it isn't going to be installed. [79db1145e882] <2.8-maint> 2014-05-12 Phil Thompson * Python/configure.py: Added the --sysroot, --no-sip-files and --no-qsci-api options to configure.py. [10642d7deba9] <2.8-maint> 2014-05-05 Phil Thompson * Makefile: Updated the internal build system for the combined iOS/Android Qt installation. [9097d3096b70] <2.8-maint> 2014-05-04 Phil Thompson * qt/qscintilla_de.qm, qt/qscintilla_de.ts: Updated German translations from Detlev. [d4f631ee3aaf] <2.8-maint> * qt/qscintilla_es.qm, qt/qscintilla_es.ts: Updated Spanish translations from Jaime Seuma. [51350008c8a4] <2.8-maint> 2014-04-30 Phil Thompson * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the .ts files. [4c5f88b22952] <2.8-maint> 2014-04-29 Phil Thompson * Python/sip/qscilexerpo.sip, Python/sip/qscimodcommon.sip, qt/qscilexerpo.cpp, qt/qscilexerpo.h, qt/qscintilla.pro: Added the QsciLexerPO class. [d42e44550d80] <2.8-maint> * Python/sip/qscilexeravs.sip, Python/sip/qscimodcommon.sip, qt/qscilexeravs.cpp, qt/qscilexeravs.h, qt/qscintilla.pro: Added the QsciLexerAVS class. [ed6edb6ec205] <2.8-maint> 2014-04-27 Phil Thompson * Python/configure.py: Fixes for the refactored configure.py. [21b9fa66338e] <2.8-maint> * Python/configure.py: Initial refactoring of configure.py so that it is implemented as configurable (and reusable) boilerplate. [615d75a88db9] <2.8-maint> 2014-04-24 Phil Thompson * Python/sip/qsciscintilla.sip, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h: setEnabled() now implements the expected visual effects. [3e4254394b08] <2.8-maint> 2014-03-22 Phil Thompson * Python/configure.py: Fixed the handling of the --pyqt-sip-flags option. Restored the specification of the Python library directory for Windows. [3ea496d62b9f] <2.8-maint> * Python/configure.py, qt/features/qscintilla2.prf, qt/qscintilla.pro: Added the --pyqt-sip-flags to configure.py to avoid having to introspect PyQt. Fixed the .prf file for OS/X. Tweaks to configure.py so that a configuration file will use the same names as PyQt5. [77ff3a21d00a] <2.8-maint> 2014-03-21 Phil Thompson * Makefile, lib/README.doc, qt/qscintilla.pro: Changes to the .pro file to build a static library without having to edit it. [f82637449276] <2.8-maint> 2014-03-17 Phil Thompson * qt/PlatQt.cpp, qt/qsciscintillabase.cpp: Fixed building against Qt v5.0.x. [d68e28068b67] <2.8-maint> 2014-03-14 Phil Thompson * .hgtags: Added tag 2.8.1 for changeset 6bb7ab27c958 [dfd473e8336b] <2.8-maint> * NEWS: Released as v2.8.1. [6bb7ab27c958] [2.8.1] <2.8-maint> * qt/SciClasses.cpp: Fixed the display of UTF-8 call tips. [3f0ca7ba60a0] <2.8-maint> 2014-03-12 Phil Thompson * qsci/api/python/Python-3.4.api: Added the .api file for Python v3.4. [3db067b6dcec] <2.8-maint> 2014-03-05 Phil Thompson * qt/PlatQt.cpp: Revised attempt at the outline of alpha rectangles in case Qt ignore the alpha of the pen. [86ab8898503e] <2.8-maint> * qt/PlatQt.cpp: Fixed the setting of the pen when drawing alpha rectangles. [3f4ff2e8aca3] <2.8-maint> 2014-02-09 Phil Thompson * Python/configure.py: The Python module now has the correct install name on OS/X. [eec8c704418a] <2.8-maint> 2014-02-04 Phil Thompson * qt/qscicommand.cpp, qt/qscicommand.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Fixed a problem entering non-ASCII characters that clashed with Scintilla's SCK_* values. Key_Enter, Key_Backtab, Key_Super_L, Key_Super_R and Key_Menu are now valid QsciCommand keys. [94aec4f075df] <2.8-maint> 2014-01-31 Phil Thompson * qt/qsciscintilla.cpp: Make sure the editor is active after a selection of a user list entry. [e0f2106777d0] <2.8-maint> 2014-01-23 Phil Thompson * qt/SciClasses.cpp: On Linux, single clicking on an item in an auto-completion list now just selects the itemm (rather than inserting the item) to be consistent with other platforms. [d916bbbf6517] <2.8-maint> * qt/qsciscintillabase.cpp: Fix the handling of the auto-completion list when losing focus. [a67b51ac8611] <2.8-maint> 2014-01-22 Phil Thompson * qt/InputMethod.cpp, qt/qsciscintillabase.cpp: Fixed building against Qt4. [bf0a5f984fc1] <2.8-maint> 2014-01-19 Phil Thompson * NEWS: Updated the NEWS file. [da2a76da712e] <2.8-maint> 2014-01-18 Phil Thompson * qt/InputMethod.cpp: Another attempt to fix input events on losing focus. [6de3ab62fade] <2.8-maint> * lib/README.doc: Added the qmake integration section to the docs. [2918e4760c36] <2.8-maint> 2014-01-07 Phil Thompson * Makefile: Added Android to the internal build system. [3be74b3e89e9] <2.8-maint> 2014-01-06 Phil Thompson * qt/InputMethod.cpp, qt/qsciscintillabase.cpp: Newlines can now be entered on iOS. [8d23447dbd4d] <2.8-maint> 2014-01-05 Phil Thompson * qt/InputMethod.cpp: See if we can detect a input methdo event generated when losing focus and not to clear the selection. [8e4216289efe] <2.8-maint> 2014-01-04 Phil Thompson * Python/sip/qsciprinter.sip: The Python bindings now respect the PyQt_Printer feature. [c3106f715803] <2.8-maint> 2014-01-03 Phil Thompson * qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added support for software input panels with Qt v5. [d4499b61ff04] <2.8-maint> * qt/qsciscintilla.cpp: Disable input methods when read-only (rather than non-UTF8) to be consistent with Qt. [f8817d4a47e3] <2.8-maint> * qt/qscintilla.pro, qt/qsciprinter.h: Fixed the .pro file so that QT_NO_PRINTER is set properly and removed the workaround. [b5a6709d814a] <2.8-maint> 2014-01-02 Phil Thompson * qt/PlatQt.cpp: Finally fixed buffered drawing on retina displays. [f8d23103df70] <2.8-maint> * qt/PlatQt.cpp, qt/qsciscintillabase.cpp: Fixes for buffered drawing on retina displays. (Not yet correct, but close.) [a3b36be44112] <2.8-maint> * Makefile: Changed the build system for the example on the iOS simulator so that qmake is only used to generate the .xcodeproj file. [179dbf5ba385] <2.8-maint> * Makefile: Added the building of the example to the main Makefile. [aec2ac3ac591] <2.8-maint> * Makefile: Added iOS simulator targets to the build system. [72af8241b261] <2.8-maint> * Makefile, build.py, lib/LICENSE.GPL2, lib/LICENSE.GPL3, lib/LICENSE.commercial.short, lib/LICENSE.gpl.short, qt/InputMethod.cpp: Updated copyright notices. [f21e016499fe] <2.8-maint> * qt/MacPasteboardMime.cpp, qt/qsciprinter.cpp, qt/qsciprinter.h, qt/qsciscintillabase.cpp: Fixes for building for iOS. [46d25e648b4a] <2.8-maint> 2013-12-31 Phil Thompson * Python/configure.py, build.py, designer-Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro, lib/README.doc, qt/features/qscintilla2.prf, qt/qscintilla.pro: Implemented the qscintilla2.prf feature file and updated everything to use it. [c3bfef1a55ad] <2.8-maint> 2013-12-29 Phil Thompson * qt/ScintillaQt.h: Added some additional header file dependencies. [7ec67eced9de] <2.8-maint> 2013-12-21 Phil Thompson * qt/MacPasteboardMime.cpp, qt/ScintillaQt.cpp: Fixes for building against Qt3. [f25cbda736fd] <2.8-maint> 2013-12-16 Phil Thompson * designer-Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro: Updated the plugin and example .pro files to work around the qmake incompatibilities introduced in Qt v5.2.0. [a14729b2702d] <2.8-maint> 2013-12-15 Phil Thompson * qt/qsciscintillabase.cpp: Fixed the previous fix. [6c322fa1b20f] <2.8-maint> 2013-12-14 Phil Thompson * qt/PlatQt.cpp, qt/qsciscintillabase.cpp: Backed out the attempted fix for retina displays at it needs more work. As a workaround buffered writes are disabled if a retina display is detected. [a1f648d1025e] <2.8-maint> 2013-12-13 Phil Thompson * qt/qscintilla.pro: Enabled exceptions in the .pro file. [6e07131f6741] <2.8-maint> 2013-12-12 Phil Thompson * qt/PlatQt.cpp: Create pixmaps for buffered drawing using the same pixel ratio as the actual device. [f4f706006071] <2.8-maint> 2013-12-09 Phil Thompson * qt/qscilexeroctave.cpp: Updated the keywords defined for the Octave lexer. [9ccf1c74f266] <2.8-maint> 2013-12-06 Phil Thompson * qt/ScintillaQt.cpp: More scrollbar fixes. [194a2142c9b6] <2.8-maint> 2013-12-05 Phil Thompson * qt/ScintillaQt.cpp, qt/qscintilla.pro: Fixes to the scrollbar visibility handling. [5e8a96258ab0] <2.8-maint> 2013-12-04 Phil Thompson * qt/PlatQt.cpp: Fixed the implementation of SurfaceImpl::LogPixelsY() (even though it is never called). [9ef0387cfc08] <2.8-maint> 2013-11-08 Phil Thompson * .hgtags: Added tag 2.8 for changeset 562785a5f685 [fc52bfaa75c4] * NEWS: Released as v2.8. [562785a5f685] [2.8] 2013-11-05 Phil Thompson * qt/qscintilla_es.qm, qt/qscintilla_es.ts: Updated Spanish translations from Jaime Seuma. [e7a128a28157] 2013-11-04 Phil Thompson * NEWS, Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qscilexerpascal.cpp, qt/qsciscintillabase.h: Added support for the new v3.3.6 features to the low-level API. [e553c1263387] * Makefile, NEWS, cocoa/Framework.mk, cocoa/InfoBar.mm, cocoa/PlatCocoa.mm, cocoa/SciTest.mk, cocoa/ScintillaCocoa.h, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/ScintillaFramework .xcodeproj/project.pbxproj, cocoa/ScintillaView.h, cocoa/ScintillaView.mm, cocoa/checkbuildosx.sh, cocoa/common.mk, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/index.html, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/makefile, include/ILexer.h, include/Platform.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, lexers/LexCPP.cxx, lexers/LexCoffeeScript.cxx, lexers/LexOthers.cxx, lexers/LexPascal.cxx, lexers/LexPerl.cxx, lexers/LexRust.cxx, lexers/LexSQL.cxx, lexers/LexVisualProlog.cxx, lexlib/StyleContext.h, lexlib/SubStyles.h, lexlib/WordList.cxx, lib/README.doc, qt/qscintilla.pro, src/Catalogue.cxx, src/Document.cxx, src/Editor.cxx, src/ScintillaBase.cxx, src/ScintillaBase.h, src/ViewStyle.cxx, src/ViewStyle.h, test/XiteQt.py, test/simpleTests.py, version.txt, win32/PlatWin.cxx, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/makefile, win32/scintilla.mak: Merged Scintilla v3.3.6. [ada0941dec52] 2013-10-07 Phil Thompson * qt/qscintilla_de.qm, qt/qscintilla_de.ts: Updated German translations from Detlev. [6c0af6af651c] * Makefile, build.py, qt/MacPasteboardMime.cpp, qt/qscintilla.pro, qt/qsciscintillabase.cpp: Reinstated support for rectangular selections on OS/X for Qt v5.2 and later. [dbfdf7be4793] 2013-10-04 Phil Thompson * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the translation source files. [7ed4bf7ed4e7] * qt/qscilexercpp.cpp: Added missing descriptions to the C++ lexer settings. [55d7627bb129] 2013-10-01 Phil Thompson * designer-Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro: Fixed the building of the Designer plugin and the example for OS/X. [a67f71b06d3c] * NEWS, Python/sip/qsciscintillabase.sip, qt/InputMethod.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added the remaining non-provisional Scintilla v3.3.5 features to the low-level API. [4e8d0b46ebc0] * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the translation source files. [4beefc0d95ec] * NEWS, Python/sip/qscilexercpp.sip, Python/sip/qsciscintillabase.sip, qt/qscilexercpp.cpp, qt/qscilexercpp.h, qt/qsciscintillabase.h: Updated the lexers for Scintilla v3.3.5. [fc901a2a491f] 2013-09-30 Phil Thompson * Python/configure-old.py, Python/configure.py, README, cocoa/InfoBar.mm, cocoa/PlatCocoa.mm, cocoa/ScintillaCocoa.h, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/ScintillaFramework .xcodeproj/project.pbxproj, cocoa/ScintillaTest/AppController.mm, cocoa/ScintillaTest/English.lproj/MainMenu.xib, cocoa/ScintillaView.h, cocoa/ScintillaView.mm, cppcheck.suppress, delbin.bat, designer-Qt4Qt5/designer.pro, doc/Lexer.txt, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/ScintillaToDo.html, doc/index.html, example- Qt4Qt5/application.pro, gtk/Converter.h, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/deps.mak, gtk/makefile, include/Face.py, include/HFacer.py, include/ILexer.h, include/Platform.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, lexers/LexA68k.cxx, lexers/LexAU3.cxx, lexers/LexAVE.cxx, lexers/LexAda.cxx, lexers/LexAsm.cxx, lexers/LexAsn1.cxx, lexers/LexBash.cxx, lexers/LexBullant.cxx, lexers/LexCOBOL.cxx, lexers/LexCPP.cxx, lexers/LexCoffeeScript.cxx, lexers/LexConf.cxx, lexers/LexCrontab.cxx, lexers/LexCsound.cxx, lexers/LexD.cxx, lexers/LexECL.cxx, lexers/LexForth.cxx, lexers/LexGAP.cxx, lexers/LexGui4Cli.cxx, lexers/LexHTML.cxx, lexers/LexHaskell.cxx, lexers/LexInno.cxx, lexers/LexKVIrc.cxx, lexers/LexLaTeX.cxx, lexers/LexLisp.cxx, lexers/LexLout.cxx, lexers/LexLua.cxx, lexers/LexMMIXAL.cxx, lexers/LexMPT.cxx, lexers/LexMSSQL.cxx, lexers/LexMatlab.cxx, lexers/LexModula.cxx, lexers/LexMySQL.cxx, lexers/LexNsis.cxx, lexers/LexOpal.cxx, lexers/LexOthers.cxx, lexers/LexPO.cxx, lexers/LexPerl.cxx, lexers/LexPowerShell.cxx, lexers/LexPython.cxx, lexers/LexR.cxx, lexers/LexRuby.cxx, lexers/LexSTTXT.cxx, lexers/LexScriptol.cxx, lexers/LexSpice.cxx, lexers/LexTCMD.cxx, lexers/LexYAML.cxx, lexlib/Accessor.cxx, lexlib/Accessor.h, lexlib/CharacterCategory.cxx, lexlib/CharacterCategory.h, lexlib/CharacterSet.cxx, lexlib/LexAccessor.h, lexlib/LexerBase.cxx, lexlib/LexerModule.cxx, lexlib/LexerNoExceptions.cxx, lexlib/LexerNoExceptions.h, lexlib/LexerSimple.cxx, lexlib/OptionSet.h, lexlib/PropSetSimple.cxx, lexlib/PropSetSimple.h, lexlib/StyleContext.cxx, lexlib/StyleContext.h, lexlib/SubStyles.h, lexlib/WordList.cxx, lexlib/WordList.h, lib/README.doc, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qscintilla.pro, qt/qsciscintillabase.cpp, scripts/Face.py, scripts/FileGenerator.py, scripts/GenerateCaseConvert.py, scripts/GenerateCharacterCategory.py, scripts/HFacer.py, scripts/LexGen.py, scripts/ScintillaData.py, src/AutoComplete.cxx, src/AutoComplete.h, src/CallTip.cxx, src/CallTip.h, src/CaseConvert.cxx, src/CaseConvert.h, src/CaseFolder.cxx, src/CaseFolder.h, src/Catalogue.cxx, src/CellBuffer.cxx, src/CellBuffer.h, src/ContractionState.cxx, src/Decoration.cxx, src/Decoration.h, src/Document.cxx, src/Document.h, src/Editor.cxx, src/Editor.h, src/ExternalLexer.cxx, src/FontQuality.h, src/Indicator.cxx, src/KeyMap.cxx, src/KeyMap.h, src/LexGen.py, src/LineMarker.cxx, src/LineMarker.h, src/Partitioning.h, src/PerLine.cxx, src/PerLine.h, src/PositionCache.cxx, src/PositionCache.h, src/RESearch.cxx, src/RESearch.h, src/RunStyles.cxx, src/RunStyles.h, src/SVector.h, src/ScintillaBase.cxx, src/ScintillaBase.h, src/Selection.cxx, src/SplitVector.h, src/Style.cxx, src/Style.h, src/UniConversion.cxx, src/UniConversion.h, src/UnicodeFromUTF8.h, src/ViewStyle.cxx, src/ViewStyle.h, src/XPM.cxx, src/XPM.h, test/README, test/ScintillaCallable.py, test/XiteQt.py, test/XiteWin.py, test/examples/x.lua, test/examples/x.lua.styled, test/examples/x.pl, test/examples/x.pl.styled, test/examples/x.rb, test/examples/x.rb.styled, test/lexTests.py, test/performanceTests.py, test/simpleTests.py, test/unit/testCharClassify.cxx, test/unit/testContractionState.cxx, test/unit/testPartitioning.cxx, test/unit/testRunStyles.cxx, test/unit/testSplitVector.cxx, version.txt, win32/PlatWin.cxx, win32/PlatWin.h, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/deps.mak, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak: Initial merge of Scintilla v3.3.5. [40933b62f5ed] 2013-09-14 Phil Thompson * Python/configure-ng.py, Python/configure.py, designer- Qt4/designer.pro, designer-Qt4/qscintillaplugin.cpp, designer- Qt4/qscintillaplugin.h: Merged the 2.7-maint branch with the trunk. [7288d97c54b0] 2013-08-17 Phil Thompson * Python/sip/qsciscintillabase.sip: Fixed a missing const in the .sip files. [8b0425b87953] <2.7-maint> 2013-06-27 Phil Thompson * NEWS, Python/configure-old.py, Python/configure.py, Python/sip/qsciscintillabase.sip, designer-Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro, qt/InputMethod.cpp, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added support for input methods. [b97af619044b] <2.7-maint> 2013-06-16 Phil Thompson * .hgtags: Added tag 2.7.2 for changeset 9ecd14550589 [2b1f187f29c6] <2.7-maint> * NEWS: Released as v2.7.2. [9ecd14550589] [2.7.2] <2.7-maint> 2013-06-12 Phil Thompson * Python/configure.py: Fixed a configure.py bug. [cb062c6f9189] <2.7-maint> 2013-05-07 Phil Thompson * Makefile, Python/configure.py: Fixes for the PyQt5 support. [0714ef531ead] <2.7-maint> * Makefile, NEWS, Python/configure.py, Python/sip/qscimod5.sip, lib/README.doc: Added support for building against PyQt5. [c982ff1b86f7] <2.7-maint> 2013-05-05 Phil Thompson * build.py: Changed the format of the name of a snapshot to match other packages. [d1f87bbc8377] <2.7-maint> 2013-05-04 Phil Thompson * qt/PlatQt.cpp: Significantly improved the performance of measuring the width of text so that very long lines (100,000 characters) can be handled. [5c88dc344f69] <2.7-maint> 2013-04-08 Phil Thompson * Python/configure.py: configure.py now issues a more explicit error message if QtCore cannot be imported. [4d0097b1ff05] <2.7-maint> * Python/configure.py: Fixed a qmake warning message from configure.py. [2363c96edeb0] <2.7-maint> 2013-04-02 Phil Thompson * qt/qsciscintilla.cpp, qt/qsciscintilla.h: The default EOL mode on OS/X is now EolUnix. Clarified the documentation for EolMode. [a436460d0300] <2.7-maint> 2013-03-15 Phil Thompson * Python/configure.py: Further fixes for configure.py. [78fa6fef2c76] <2.7-maint> 2013-03-13 Phil Thompson * qt/qscilexer.h: Clarified the description of QSciLexer::description(). [688b482379e3] <2.7-maint> * Python/configure.py: Fixed the last (trivial) change. [0a3494ba669a] <2.7-maint> 2013-03-12 Phil Thompson * Python/configure.py: configure.py now gives the user more information about the copy of sip being used. [5c3be581d62b] <2.7-maint> 2013-03-07 Phil Thompson * Python/configure.py: On OS/X configure.py will explicitly set the qmake spec to macx-g++ (Qt4) or macx-clang (Qt5) if the default might be macx-xcode. Added the --spec option to configure.py. [36a9bf2fbebd] <2.7-maint> 2013-03-05 Phil Thompson * Python/configure.py: Minor cosmetic tweaks to configure.py. [296cd10747b7] <2.7-maint> * qt/PlatQt.cpp, qt/SciClasses.cpp, qt/qscicommandset.cpp, qt/qscintilla.pro, qt/qsciscintillabase.cpp: Removed the remaining uses of Q_WS_* for Qt v5. [7fafd5c09eea] <2.7-maint> 2013-03-01 Phil Thompson * .hgtags: Added tag 2.7.1 for changeset 2583dc3dbc8d [0674c291eab4] <2.7-maint> * NEWS: Released as v2.7.1. [2583dc3dbc8d] [2.7.1] <2.7-maint> 2013-02-28 Phil Thompson * lexlib/CharacterSet.h: Re-applied a fix to the underlying code thay got lost when Scintilla v3.23 was merged. [ee9eeec7d796] <2.7-maint> 2013-02-26 Phil Thompson * qt/qsciapis.cpp: A fix for the regression introduced with the previous fix. [154428cebb5e] <2.7-maint> 2013-02-19 Phil Thompson * NEWS, qt/qsciapis.cpp, qt/qscintilla.pro: Fixed an autocompletion bug where there are entries Foo.* and FooBar. [620d72d86980] <2.7-maint> 2013-02-06 Phil Thompson * Python/configure.py: configure.py fixes for Linux. [031b5b767926] <2.7-maint> * Python/configure.py: Added the --sip-incdir and --pyqt-sipdir options to configure.py and other fixes for building on Windows. [517a3d0243fd] <2.7-maint> * Makefile, NEWS: Updated the NEWS file. [eb00e08e1950] <2.7-maint> * Makefile, Python/configure.py: Fixed configure.py for Qt5. [7ddb5bf2030c] <2.7-maint> * Python/configure-ng.py, Python/configure-old.py, Python/configure.py, build.py, lib/README.doc: Completed configure-ng.py and renamed it configure.py. The old configure.py is now called configure-old.py. [8d58b2899080] <2.7-maint> 2013-02-05 Phil Thompson * Python/configure-ng.py: configure-ng.py now uses -fno-exceptions on Linux and OS/X. configure-ng.py now hides unneeded symbols on Linux. [391e4f56b009] <2.7-maint> * Python/configure-ng.py: configure-ng.py will now install the .sip and .api files. [e228d58a670c] <2.7-maint> * Python/configure-ng.py: configure-ng.py will now create a Makefile that will build the Python module. [cb47ace62a70] <2.7-maint> 2013-02-02 Phil Thompson * qt/qsciglobal.h: Use Q_OS_WIN for compatibility for Qt5. [da752cf4510a] <2.7-maint> 2013-01-29 Phil Thompson * designer-Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro: Use macx rather than mac in the .pro files. [ee818a367df7] <2.7-maint> 2012-12-21 Phil Thompson * Python/configure-ng.py, Python/configure.py, designer- Qt4Qt5/designer.pro, example-Qt4Qt5/application.pro, lib/README.doc, qt/qscintilla.pro: Various OS/X fixes so that setting DYLD_LIBRARY_PATH isn't necessary. [e7854b8b01e3] <2.7-maint> 2012-12-19 Phil Thompson * build.py, designer-Qt4/designer.pro, designer- Qt4/qscintillaplugin.cpp, designer-Qt4/qscintillaplugin.h, designer- Qt4Qt5/designer.pro, designer-Qt4Qt5/qscintillaplugin.cpp, designer- Qt4Qt5/qscintillaplugin.h, lib/README.doc: Updated the Designer plugin for Qt5. [77f575c87ebb] <2.7-maint> 2012-12-08 Phil Thompson * .hgtags: Added tag 2.7 for changeset 9bab1e7b02e3 [5600138109ce] * NEWS: Released as v2.7. [9bab1e7b02e3] [2.7] 2012-12-07 Phil Thompson * qt/qscintilla_es.qm, qt/qscintilla_es.ts: Updated Spanish translations from Jaime. [b188c942422c] * NEWS: Updated the NEWS file regarding Qt v5-rc1. [be9e6b928921] 2012-12-02 Phil Thompson * qt/qsciscintilla.cpp: A final(?) fix for scroll bars and annotations. [378f28e5b4b2] * Python/configure-ng.py: More build system changes. [f53fc8743ff1] 2012-11-29 Phil Thompson * Python/configure-ng.py: More configure script changes. [434c9b3185a5] * Python/configure-ng.py: More work on the new configure script. [3a044732b799] * qt/qscintilla_cs.qm, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_es.qm, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm, qt/qscintilla_ru.qm: Updated German translations from Detlev. [9dab221845ca] 2012-11-28 Phil Thompson * Python/configure-ng.py, build.py: Added the start of the SIP v5 compatible build script. [781d2af60cfc] 2012-11-27 Phil Thompson * Python/configure.py: Fixed the handling of the 'linux' platform in the Python bindings. [835d5e3be69e] 2012-11-26 Phil Thompson * qt/qsciscintilla.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Worked around Scintilla bugs related to scroll bars and annotations. [edc190ecc6fc] * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the translation files. [ec754f87a735] * NEWS, Python/sip/qscilexercss.sip, qt/qscilexercss.cpp, qt/qscilexercss.h: Updated the CSS lexer for Scintilla v3.23. [011fba6d668d] * qt/qscilexercpp.h: Fixed a couple of documentation typos. [7c2d04c76bd6] * NEWS, Python/sip/qscilexercpp.sip, qt/qscilexercpp.cpp, qt/qscilexercpp.h: Updated the C++ lexer for Scintilla v3.23. [ad93ee355639] 2012-11-24 Phil Thompson * Python/sip/qscilexercpp.sip, qt/qscilexercpp.cpp, qt/qscilexercpp.h: Updated the styles for the C++ lexer. [153429503998] 2012-11-23 Phil Thompson * NEWS, Python/sip/qsciscintilla.sip, qt/PlatQt.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added CallTipsPosition, callTipsPosition() and setCallTipsPosition(). [7e5602869fee] * NEWS, Python/sip/qsciscintilla.sip, qt/qsciscintilla.h: Added SquigglePixmapIndicator to QsciScintilla::IndicatorStyle. [ad98a5396151] * NEWS, Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added WrapFlagInMargin to QsciScintilla::WrapVisualFlag. [a38c75c45fb3] * NEWS, qt/PlatQt.cpp, qt/qsciscintilla.cpp, qt/qscistyle.cpp: Created a back door to pass the Qt weight of a font avoiding lossy conversions between Qt weights and Scintilla weights. The default behaviour is now SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE which is a change but reflects what people really expect. [78ce86e97ad3] 2012-11-21 Phil Thompson * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Updated the constants from Scintilla v3.23. [a3a0768af999] * NEWS, Python/configure.py, include/Platform.h, lib/README.doc, qt/ListBoxQt.cpp, qt/ListBoxQt.h, qt/PlatQt.cpp, qt/SciClasses.cpp, qt/ScintillaQt.cpp, qt/qscintilla.pro, src/ExternalLexer.h, src/XPM.cxx, src/XPM.h: Updated the platform support so that it compiles (but untested). [abae8e56a6ea] 2012-11-20 Phil Thompson * cocoa/InfoBar.h, cocoa/InfoBar.mm, cocoa/PlatCocoa.h, cocoa/PlatCocoa.mm, cocoa/QuartzTextStyle.h, cocoa/QuartzTextStyleAttribute.h, cocoa/ScintillaCocoa.h, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/English.lproj/InfoPlist.strings, cocoa/Scin tillaFramework/ScintillaFramework.xcodeproj/project.pbxproj, cocoa/ScintillaTest/AppController.mm, cocoa/ScintillaTest/English.lproj/InfoPlist.strings, cocoa/ScintillaTest/ScintillaTest.xcodeproj/project.pbxproj, cocoa/ScintillaView.h, cocoa/ScintillaView.mm, cocoa/checkbuildosx.sh, delbin.bat, delcvs.bat, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/ScintillaToDo.html, doc/annotations.png, doc/index.html, doc/styledmargin.png, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/makefile, include/Face.py, include/ILexer.h, include/Platform.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, include/ScintillaWidget.h, lexers/LexAVS.cxx, lexers/LexAda.cxx, lexers/LexAsm.cxx, lexers/LexBash.cxx, lexers/LexBasic.cxx, lexers/LexCPP.cxx, lexers/LexCSS.cxx, lexers/LexCoffeeScript.cxx, lexers/LexD.cxx, lexers/LexECL.cxx, lexers/LexFortran.cxx, lexers/LexHTML.cxx, lexers/LexLua.cxx, lexers/LexMMIXAL.cxx, lexers/LexMPT.cxx, lexers/LexNsis.cxx, lexers/LexOScript.cxx, lexers/LexOthers.cxx, lexers/LexPO.cxx, lexers/LexPascal.cxx, lexers/LexPerl.cxx, lexers/LexRuby.cxx, lexers/LexSQL.cxx, lexers/LexScriptol.cxx, lexers/LexSpice.cxx, lexers/LexTADS3.cxx, lexers/LexTCL.cxx, lexers/LexTCMD.cxx, lexers/LexVHDL.cxx, lexers/LexVisualProlog.cxx, lexers/LexYAML.cxx, lexlib/CharacterSet.h, lexlib/LexAccessor.h, lexlib/PropSetSimple.cxx, macosx/ExtInput.cxx, macosx/ExtInput.h, macosx/PlatMacOSX.cxx, macosx/PlatMacOSX.h, macosx/QuartzTextLayout.h, macosx/QuartzTextStyle.h, macosx/QuartzTextStyleAttribute.h, macosx/SciTest/English.lproj/InfoPlist.strings, macosx/SciTest/English.lproj/main.xib, macosx/SciTest/Info.plist, macosx/SciTest/SciTest.xcode/project.pbxproj, macosx/SciTest/SciTest_Prefix.pch, macosx/SciTest/main.cpp, macosx/SciTest/version.plist, macosx/ScintillaCallTip.cxx, macosx/ScintillaCallTip.h, macosx/ScintillaListBox.cxx, macosx/ScintillaListBox.h, macosx/ScintillaMacOSX.cxx, macosx/ScintillaMacOSX.h, macosx/TCarbonEvent.cxx, macosx/TCarbonEvent.h, macosx/TRect.h, macosx/TView.cxx, macosx/TView.h, macosx/deps.mak, macosx/makefile, src/AutoComplete.cxx, src/AutoComplete.h, src/CallTip.cxx, src/CallTip.h, src/Catalogue.cxx, src/CellBuffer.cxx, src/CellBuffer.h, src/CharClassify.cxx, src/CharClassify.h, src/Decoration.cxx, src/Document.cxx, src/Document.h, src/Editor.cxx, src/Editor.h, src/ExternalLexer.h, src/FontQuality.h, src/Indicator.cxx, src/Indicator.h, src/LexGen.py, src/LineMarker.cxx, src/LineMarker.h, src/PerLine.cxx, src/PerLine.h, src/PositionCache.cxx, src/PositionCache.h, src/RESearch.cxx, src/RunStyles.cxx, src/SciTE.properties, src/ScintillaBase.cxx, src/ScintillaBase.h, src/SplitVector.h, src/Style.cxx, src/Style.h, src/UniConversion.cxx, src/UniConversion.h, src/ViewStyle.cxx, src/ViewStyle.h, src/XPM.cxx, src/XPM.h, test/README, test/examples/x.cxx, test/examples/x.cxx.styled, test/lexTests.py, test/simpleTests.py, test/unit/makefile, test/unit/testCharClassify.cxx, test/unit/testRunStyles.cxx, tgzsrc, version.txt, win32/CheckD2D.cxx, win32/PlatWin.cxx, win32/PlatWin.h, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak, zipsrc.bat: Initial merge of Scintilla v3.23. [b116f361ac01] * example-Qt4/application.pro, example-Qt4/application.qrc, example- Qt4/images/copy.png, example-Qt4/images/cut.png, example- Qt4/images/new.png, example-Qt4/images/open.png, example- Qt4/images/paste.png, example-Qt4/images/save.png, example- Qt4/main.cpp, example-Qt4/mainwindow.cpp, example-Qt4/mainwindow.h: Merged the 2.6 maintenance branch with the trunk. [0bf4f7453c68] 2012-11-14 Phil Thompson * Makefile, example-Qt4Qt5/application.pro, qt/qsciscintillabase.cpp: Fixed the linking of the example on OS/X. [e1d1f43fae71] <2.6-maint> 2012-11-12 Phil Thompson * Makefile, qt/PlatQt.cpp, qt/qscimacro.cpp, qt/qsciscintilla.cpp, qt/qscistyle.cpp: Removed all calls that are deprecated in Qt5. The build system now supports cross-compilation to the Raspberry Pi. [afef9d2b3ab1] <2.6-maint> 2012-11-02 Phil Thompson * qt/qscilexersql.h: Added comments to the QsciLexerSQL documentation stating that additional keywords must be defined using lower case. [79a9274b77c3] <2.6-maint> 2012-10-09 Phil Thompson * NEWS, lib/ed.py, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added a replace option to the test editor's find commands. Finished implementing findFirstInSelection(). [80df6cc89bae] <2.6-maint> * lib/ed.py: Added the Find, Find in Selection and Find Next actions to the test editor. [4aad56aedbea] <2.6-maint> 2012-10-03 Phil Thompson * lib/ed.py: Added an internal copy of the hackable Python test editor. [a67a6fe99937] <2.6-maint> 2012-09-27 Phil Thompson * lib/gen_python3_api.py, qsci/api/python/Python-3.3.api: Fixed the gen_python3_api.py script to be able to exclude module hierachies. Added the API file for Python v3.3. [06bbb2d1c227] <2.6-maint> 2012-09-22 Phil Thompson * qt/ListBoxQt.cpp: Fixed a problem building against versions of Qt4 prior to v4.7. [7bf93d60a50b] <2.6-maint> 2012-09-18 Phil Thompson * NEWS, Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added setOverwriteMode() and overwriteMode() to QsciScintilla. [1affc53d2d88] <2.6-maint> 2012-09-14 Phil Thompson * qt/qsciscintillabase.cpp: Disable the use of QMacPasteboardMime for Qt v5-beta1. [a6625d5928c6] <2.6-maint> 2012-08-24 Phil Thompson * qt/qscilexerperl.cpp, qt/qscilexerperl.h: Fixed auto-indentation for Perl. [5eb1d97f95d6] <2.6-maint> 2012-08-13 Phil Thompson * lexlib/CharacterSet.h: Removed an incorrect assert() in the main Scintilla code. [1aaf5e09d4b2] <2.6-maint> 2012-08-09 Phil Thompson * NEWS, Python/sip/qsciscintilla.sip, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added QsciScintilla::wordAtLineIndex(). [0c5d77aef4f7] <2.6-maint> 2012-07-19 Phil Thompson * qt/qscintilla.pro, qt/qsciscintillabase.cpp: Fixed key handling on Linux with US international layout which generates non-ASCII sequences for quote characters. [061ab2c5bea3] <2.6-maint> 2012-06-20 Phil Thompson * .hgtags: Added tag 2.6.2 for changeset f9d3d982c20f [a5bb033cd9e0] <2.6-maint> * NEWS: Released as v2.6.2. [f9d3d982c20f] [2.6.2] <2.6-maint> 2012-06-19 Phil Thompson * qt/qsciscintillabase.cpp: Fixed pasting of text in UTF8 mode (and hopefully Latin1 mode as well). [6df653daef18] <2.6-maint> * qt/qsciscintillabase.cpp: Rectangular selections are now always encoded as plain/text with an explicit, and separate, marker to indicate that it is rectangular. [012a0b2ca89f] <2.6-maint> 2012-06-09 Phil Thompson * qt/qsciscintillabase.cpp: Used the Mac method of marking rectangular selections as the '\0' Scintilla hack just doesn't work with Qt. [75020a35b5eb] <2.6-maint> * qt/qscintilla.pro: Bumped the library version number. [12f21729e254] <2.6-maint> 2012-06-07 Phil Thompson * qt/qsciscintillabase.cpp: Improved the support for rectangular selections and the interoperability with other Scintilla based editors. [a42942b57fb7] <2.6-maint> * qt/qsciscintillabase.cpp: Fixed the middle button pasting of rectangular selections. [db58aa6c6d7d] <2.6-maint> * qt/qscidocument.cpp: Fixed a bug that seemed to mean the initial EOL mode was always UNIX. [88561cd29a60] <2.6-maint> * qt/qsciscintillabase.cpp: Line endings are properly translated when dropping text. [d21994584e87] <2.6-maint> 2012-06-04 Phil Thompson * Makefile, qt/qsciprinter.h: The Python bindings now build against Qt5. [ff2a74e5aec2] <2.6-maint> 2012-04-04 Phil Thompson * Makefile, NEWS, build.py, example-Qt4/application.pro, example- Qt4/application.qrc, example-Qt4/images/copy.png, example- Qt4/images/cut.png, example-Qt4/images/new.png, example- Qt4/images/open.png, example-Qt4/images/paste.png, example- Qt4/images/save.png, example-Qt4/main.cpp, example- Qt4/mainwindow.cpp, example-Qt4/mainwindow.h, example- Qt4Qt5/application.pro, example-Qt4Qt5/application.qrc, example- Qt4Qt5/images/copy.png, example-Qt4Qt5/images/cut.png, example- Qt4Qt5/images/new.png, example-Qt4Qt5/images/open.png, example- Qt4Qt5/images/paste.png, example-Qt4Qt5/images/save.png, example- Qt4Qt5/main.cpp, example-Qt4Qt5/mainwindow.cpp, example- Qt4Qt5/mainwindow.h, lib/LICENSE.GPL2, lib/LICENSE.GPL3, lib/LICENSE.commercial.short, lib/LICENSE.gpl.short, lib/README, lib/README.doc, lib/qscintilla.dxy, qt/PlatQt.cpp, qt/qscintilla.pro: Ported to Qt v5. [ff3710487c3e] <2.6-maint> 2012-04-02 Phil Thompson * qt/qsciapis.cpp: Worked around an obscure Qt (or compiler) bug when handling call tips. [e6c7edcfdfb9] <2.6-maint> 2012-03-04 Phil Thompson * Python/sip/qscilexer.sip, Python/sip/qscilexerbash.sip, Python/sip/qscilexerbatch.sip, Python/sip/qscilexercpp.sip, Python/sip/qscilexercss.sip, Python/sip/qscilexerd.sip, Python/sip/qscilexerdiff.sip, Python/sip/qscilexerhtml.sip, Python/sip/qscilexermakefile.sip, Python/sip/qscilexerperl.sip, Python/sip/qscilexerpov.sip, Python/sip/qscilexerproperties.sip, Python/sip/qscilexertex.sip, Python/sip/qscilexerverilog.sip, qt/qscilexer.h, qt/qscilexerbash.h, qt/qscilexerbatch.h, qt/qscilexercpp.h, qt/qscilexercss.h, qt/qscilexerd.h, qt/qscilexerdiff.h, qt/qscilexerhtml.h, qt/qscilexermakefile.h, qt/qscilexerperl.h, qt/qscilexerpov.h, qt/qscilexerproperties.h, qt/qscilexertex.h, qt/qscilexerverilog.h: QSciLexer::wordCharacters() is now part of the public API. [933ef6a11ee6] <2.6-maint> 2012-02-23 Phil Thompson * qt/qscilexercpp.h: Updated the documentation for QsciLexerCpp::keywords() so that it describes which sets are supported. [4e0cb0250dad] <2.6-maint> 2012-02-21 Phil Thompson * qt/qscintilla.pro, src/Document.cxx: Some Scintilla fixes for the SCI_NAMESPACE support. [611ffd016585] <2.6-maint> 2012-02-10 Phil Thompson * .hgtags: Added tag 2.6.1 for changeset 47d8fdf44946 [aa843f471972] <2.6-maint> * NEWS: Updated the NEWS file. Released as v2.6.1. [47d8fdf44946] [2.6.1] <2.6-maint> 2012-01-26 Phil Thompson * qt/qsciscintilla.cpp: Don't implement shortcut overrides for the standard context menu shortcuts. Instead leave it to the check against bound keys. [e8ccaf398640] <2.6-maint> 2012-01-19 Phil Thompson * qt/qsciapis.cpp: APIs now allow for whitespace between the end of a word and the opening parenthesis of the argument list. [b09b25f38411] <2.6-maint> 2012-01-11 Phil Thompson * qt/SciClasses.cpp: Fixed the handling of auto-completion lists on Windows. [131138b43c85] <2.6-maint> 2011-12-07 Phil Thompson * Python/sip/qscicommandset.sip, qt/qscicommandset.cpp, qt/qscicommandset.h, qt/qscintilla.pro: Improved the Qt v3 port so that the signatures don't need to be changed. Bumped the .so version number. [3171bb05b1d8] <2.6-maint> 2011-12-06 Phil Thompson * Makefile, NEWS, Python/sip/qscicommandset.sip, include/Platform.h, qt/ListBoxQt.cpp, qt/qscicommandset.cpp, qt/qscicommandset.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h, src/XPM.cxx: Fixed building against Qt v3. [74df75a62f5c] <2.6-maint> 2011-11-21 Phil Thompson * NEWS, include/Platform.h, qt/ListBoxQt.cpp, qt/ListBoxQt.h, qt/PlatQt.cpp, qt/SciClasses.cpp, qt/SciClasses.h, qt/SciNamespace.h, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qscintilla.pro, qt/qsciscintilla.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added support for SCI_NAMESPACE to allow all internal Scintilla classes to be placed in the Scintilla namespace. [ab7857131e35] <2.6-maint> 2011-11-11 Phil Thompson * .hgtags: Added tag 2.6 for changeset 8b119c4f69d0 [1a5dd31e773e] * NEWS, lib/README.doc: Updated the NEWS file. Updated the introductory documentation. Released as v2.6. [8b119c4f69d0] [2.6] 2011-11-07 Phil Thompson * NEWS, Python/sip/qscicommandset.sip, Python/sip/qsciscintilla.sip, qt/qscicommandset.cpp, qt/qscicommandset.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added QsciCommandSet::boundTo(). Ordinary keys and those bound to commands now override any shortcuts. [ba98bc555aca] 2011-10-28 Phil Thompson * qt/qscintilla_de.qm, qt/qscintilla_de.ts: More updated German translations from Detlev. [9ff20df1997b] 2011-10-27 Phil Thompson * qt/qscintilla_cs.qm, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_es.qm, qt/qscintilla_es.ts, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm, qt/qscintilla_ru.qm: Updated Spanish translations from Jaime. Updated German translations from Detlev. [4903315d96b1] 2011-10-23 Phil Thompson * Python/sip/qscicommand.sip: Fixed SelectAll in the Python bindings. [b6f0a46e0eac] * qt/ScintillaQt.cpp, qt/qsciscintillabase.cpp: Fixed drag and drop (specifically so that copying works on OS/X again). [6ab90cb63b2b] 2011-10-22 Phil Thompson * qt/PlatQt.cpp: Fixed a display bug with kerned fonts. [a746e319d9cd] * qt/qsciscintilla.cpp: The foreground and background colours of selected text are now taken from the application palette. [7f6c34ad8d27] * NEWS: Updated the NEWS file. [1717c6d59b12] * Python/sip/qsciscintilla.sip, qt/qscicommand.h, qt/qscicommandset.cpp, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Renamed QsciCommand::SelectDocument to SelectAll. Added QsciScintilla::createStandardContextMenu(). [c42fa7e83b07] 2011-10-21 Phil Thompson * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the .ts files. [92d0b6ddf371] * qt/qscicommandset.cpp: Completed the OS/X specific key bindings. [964fa889b807] 2011-10-20 Phil Thompson * qt/qscicommandset.cpp, qt/qsciscintillabase.cpp: Fixed the support for SCMOD_META. Started to add the correct OS/X key bindings as the default. [0073fa86a5a0] * Python/sip/qscicommand.sip, qt/qscicommand.h, qt/qscicommandset.cpp: All available commands are now defined in the standard command set. [7c7b81b55f0e] * Python/sip/qscicommand.sip, qt/qscicommand.h: Completed the QsciCommand::Command documentation. Added the members to QsciCommand.Command in the Python bindings. [0ca6ff576c21] 2011-10-18 Phil Thompson * NEWS, Python/sip/qscicommandset.sip, qt/qscicommand.h, qt/qscicommandset.cpp, qt/qscicommandset.h: Added QsciCommandSet::find(). [e75565018b90] * NEWS, Python/sip/qscicommand.sip, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qscicommand.cpp, qt/qscicommand.h, qt/qscicommandset.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added Command, command() and execute() to QsciCommand. Backed out the high level support for moving the selection up and down. [4852ee57353e] 2011-10-17 Phil Thompson * qt/qscilexersql.cpp: Fix for the changed fold at else property in the SQL lexer. [e65a458cd9d8] * NEWS, Python/sip/qscilexerpython.sip, qt/qscilexerpython.cpp, qt/qscilexerpython.h: Added highlightSubidentifiers() and setHighlightSubidentifiers() to the Python lexer. [b397695bc2ab] * NEWS, Python/sip/qscilexercpp.sip, qt/qscilexercpp.cpp, qt/qscilexercpp.h: Added support for triple quoted strings to the C++ lexer. [687d04948c5d] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added low level support for identifiers, scrolling to the start and end. Added low and hight level support for moving the selection up and down. [3ac1ccfad039] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added low and high level support for margin options. [f3cd3244cecd] 2011-10-14 Phil Thompson * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Updated the brace matching support to handle indicators. [7e4a4d3529a8] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added SCI_SETEMPTYSELECTION. [879b97c676a4] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Updated the support for indicators. [b3643569a827] * NEWS, Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added SCI_MARKERSETBACKSELECTED and SCI_MARKERENABLEHIGHLIGHT. [7127ee82d128] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added low and high-level support for RGBA images (ie. QImage). [7707052913ef] 2011-10-13 Phil Thompson * NEWS, Python/sip/qscilexerlua.sip, qt/qscilexerlua.cpp, qt/qscilexerlua.h: Updated the Lua lexer. [710e50d5692c] * NEWS, Python/sip/qscilexerperl.sip, qt/qscilexerperl.cpp, qt/qscilexerperl.h: Updated the Perl lexer. [6d16e2e9354b] 2011-10-11 Phil Thompson * Python/configure.py, cocoa/ScintillaCallTip.h, cocoa/ScintillaCallTip.mm, cocoa/ScintillaListBox.h, cocoa/ScintillaListBox.mm, cocoa/res/info_bar_bg.png, cocoa/res/mac_cursor_busy.png, cocoa/res/mac_cursor_flipped.png, macosx/SciTest/English.lproj/InfoPlist.strings, macosx/SciTest/English.lproj/main.nib/classes.nib, macosx/SciTest/English.lproj/main.nib/info.nib, macosx/SciTest/English.lproj/main.nib/objects.xib, macosx/SciTest/English.lproj/main.xib, qt/ListBoxQt.cpp, qt/ListBoxQt.h, qt/PlatQt.cpp, qt/qscintilla.pro, src/XPM.cxx, src/XPM.h: Some fixes left over from the merge of v2.29. Added support for RGBA images so that the merged version compiles. [16c6831c337f] * cocoa/InfoBar.mm, cocoa/PlatCocoa.h, cocoa/PlatCocoa.mm, cocoa/QuartzTextLayout.h, cocoa/QuartzTextStyle.h, cocoa/QuartzTextStyleAttribute.h, cocoa/ScintillaCocoa.h, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/ScintillaFramework .xcodeproj/project.pbxproj, cocoa/ScintillaTest/AppController.mm, cocoa/ScintillaTest/ScintillaTest.xcodeproj/project.pbxproj, cocoa/ScintillaView.h, cocoa/ScintillaView.mm, doc/SciCoding.html, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/ScintillaToDo.html, doc/index.html, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/makefile, include/Platform.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, lexers/LexAU3.cxx, lexers/LexCOBOL.cxx, lexers/LexCPP.cxx, lexers/LexConf.cxx, lexers/LexHTML.cxx, lexers/LexInno.cxx, lexers/LexLua.cxx, lexers/LexMagik.cxx, lexers/LexMarkdown.cxx, lexers/LexMatlab.cxx, lexers/LexModula.cxx, lexers/LexOthers.cxx, lexers/LexPerl.cxx, lexers/LexPowerPro.cxx, lexers/LexPython.cxx, lexers/LexSQL.cxx, lexers/LexTeX.cxx, lexers/LexVHDL.cxx, lexers/LexVerilog.cxx, lexlib/Accessor.cxx, lexlib/CharacterSet.h, lexlib/PropSetSimple.cxx, lexlib/SparseState.h, lexlib/StyleContext.h, lexlib/WordList.cxx, macosx/PlatMacOSX.cxx, macosx/PlatMacOSX.h, macosx/SciTest/SciTest.xcode/project.pbxproj, macosx/ScintillaMacOSX.h, macosx/makefile, src/CallTip.cxx, src/ContractionState.cxx, src/ContractionState.h, src/Decoration.cxx, src/Document.cxx, src/Document.h, src/Editor.cxx, src/Editor.h, src/Indicator.cxx, src/Indicator.h, src/KeyMap.cxx, src/KeyMap.h, src/LexGen.py, src/LineMarker.cxx, src/LineMarker.h, src/PerLine.cxx, src/PositionCache.cxx, src/PositionCache.h, src/RESearch.cxx, src/RunStyles.cxx, src/RunStyles.h, src/ScintillaBase.cxx, src/Style.cxx, src/Style.h, src/ViewStyle.cxx, src/ViewStyle.h, src/XPM.cxx, src/XPM.h, test/XiteMenu.py, test/XiteWin.py, test/examples/x.html, test/examples/x.html.styled, test/performanceTests.py, test/simpleTests.py, test/unit/testContractionState.cxx, test/unit/testRunStyles.cxx, version.txt, win32/PlatWin.cxx, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/scintilla.mak: Merged Scintilla v2.29. [750c2c3cef72] * Merged the v2.5 maintenance branch back into the trunk. [eab39863675f] 2011-06-24 Phil Thompson * qt/qscilexer.cpp, qt/qscilexerbash.cpp, qt/qscilexerbatch.cpp, qt/qscilexercmake.cpp, qt/qscilexercpp.cpp, qt/qscilexercsharp.cpp, qt/qscilexercss.cpp, qt/qscilexerd.cpp, qt/qscilexerfortran77.cpp, qt/qscilexerhtml.cpp, qt/qscilexerjavascript.cpp, qt/qscilexerlua.cpp, qt/qscilexermakefile.cpp, qt/qscilexermatlab.cpp, qt/qscilexerpascal.cpp, qt/qscilexerperl.cpp, qt/qscilexerpostscript.cpp, qt/qscilexerpov.cpp, qt/qscilexerproperties.cpp, qt/qscilexerpython.cpp, qt/qscilexerruby.cpp, qt/qscilexerspice.cpp, qt/qscilexersql.cpp, qt/qscilexertcl.cpp, qt/qscilexerverilog.cpp, qt/qscilexervhdl.cpp, qt/qscilexerxml.cpp, qt/qscilexeryaml.cpp: Changed the default fonts for MacOS so that they are larger and similar to the Windows defaults. [9c37c180ba8d] <2.5-maint> * build.py: Fixed the build system for MacOS as the development platform. [3352479980c5] <2.5-maint> 2011-05-13 Phil Thompson * lib/README.doc: Updated the licensing information in the main documentation. [d31c561e0b7c] <2.5-maint> * lib/LICENSE.GPL2, lib/LICENSE.GPL3, lib/LICENSE.gpl.short: Removed some out of date links from the license information. Updated the dates of some copyright notices. [a84451464396] <2.5-maint> 2011-05-10 Phil Thompson * Makefile, Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added the optional posix flag to QsciScintilla::findFirst(). [ad6064227d06] <2.5-maint> 2011-04-29 Phil Thompson * Python/configure.py, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qscistyle.cpp, qt/qscistyle.h, qt/qscistyledtext.cpp, qt/qscistyledtext.h: Fixed problems with QsciStyle and QsciStyledText when used with more than one QsciScintilla instance. [8bac389fb7ae] <2.5-maint> 2011-04-22 Phil Thompson * qt/qsciglobal.h: Changed the handling of QT_BEGIN_NAMESPACE etc. as it isn't defined in early versions of Qt v4. [595c8c6cdfd2] <2.5-maint> 2011-04-17 Phil Thompson * .hgtags: Added tag 2.5.1 for changeset c8648c2c0c7f [298153b3d40e] <2.5-maint> * NEWS: Released as v2.5.1. [c8648c2c0c7f] [2.5.1] <2.5-maint> 2011-04-16 Phil Thompson * qt/qscintilla_de.ts, qt/qscintilla_es.ts: Updated translations from Detlev and Jaime. [9436bea546c9] <2.5-maint> 2011-04-14 Phil Thompson * qt/qscintilla_cs.qm, qt/qscintilla_de.qm, qt/qscintilla_es.qm, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm, qt/qscintilla_ru.qm: Updated the compiled translation files. [c5d39aca8f51] <2.5-maint> 2011-04-13 Phil Thompson * Python/sip/qscilexermatlab.sip, Python/sip/qscilexeroctave.sip, Python/sip/qscimodcommon.sip: Added Python bindings for QsciLexerMatlab abd QsciLexerOctave. [22d0ed0fab2a] <2.5-maint> * NEWS, qt/qscilexermatlab.cpp, qt/qscilexermatlab.h, qt/qscilexeroctave.cpp, qt/qscilexeroctave.h, qt/qscintilla.pro, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Added QsciLexerMatlab and QsciLexerOctave. [40d3053334de] <2.5-maint> 2011-04-09 Phil Thompson * Merged the font strategy fix from the trunk. [d270e1b107d2] <2.5-maint> * NEWS: Updated the NEWS file. [8f32ff4cdd1f] <2.5-maint> 2011-04-07 Phil Thompson * qt/PlatQt.cpp, qt/qscintilla.pro: Fixed the handling of the font quality setting so that the default behavior (particularly on Windows) is the same as earlier versions. [87ae98d2674b] 2011-03-29 Phil Thompson * .hgtags: Added tag 2.5 for changeset 9d94a76f783e [e4807fd91f6c] * NEWS: Released as v2.5. [9d94a76f783e] [2.5] 2011-03-28 Phil Thompson * NEWS, Python/configure.py: Added support for the protected-is-public hack to configure.py. [beee52b8e10a] 2011-03-27 Phil Thompson * qt/PlatQt.cpp: Fixed an OS/X build problem. [ac7f1d3c9abe] 2011-03-26 Phil Thompson * NEWS, Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added replaceSelectedText() to QsciScintilla. [3c00a19d6571] 2011-03-25 Phil Thompson * Python/configure.py, Python/sip/qsciapis.sip, Python/sip/qscilexer.sip, Python/sip/qscilexercustom.sip, Python/sip/qscimod4.sip, Python/sip/qsciprinter.sip, Python/sip/qsciscintilla.sip, Python/sip/qscistyle.sip, qt/qsciapis.cpp, qt/qsciapis.h, qt/qscilexercustom.cpp, qt/qscilexercustom.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qscistyle.cpp, qt/qscistyle.h: Went through the API making sure all optional arguments had consistent and meaningful names. Enabled keyword support in the Python bindings. [d60fa45e40b7] 2011-03-23 Phil Thompson * qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_es.qm, qt/qscintilla_es.ts: Updated German translations from Detlev. Updated Spanish translations from Jaime. [f64c97749375] 2011-03-21 Phil Thompson * lexers/LexModula.cxx, lexlib/SparseState.h, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts, test/unit/testSparseState.cxx, vcbuild/SciLexer.dsp: Updated the translation files. Updated the repository for the new and removed Scintilla v2.25 files. [6eb77ba7c57c] * NEWS, Python/sip/qscilexercpp.sip, Python/sip/qsciscintillabase.sip, qt/qscilexercpp.cpp, qt/qscilexercpp.h, qt/qscintilla.pro, qt/qsciscintillabase.h: Added support for raw string to the C++ lexer. [f83112ced877] * NEWS, cocoa/Framework.mk, cocoa/PlatCocoa.mm, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/ScintillaFramework .xcodeproj/project.pbxproj, cocoa/ScintillaTest/AppController.mm, cocoa/ScintillaView.h, cocoa/ScintillaView.mm, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/index.html, gtk/PlatGTK.cxx, gtk/makefile, include/Platform.h, include/SciLexer.h, include/Scintilla.iface, lexers/LexAsm.cxx, lexers/LexBasic.cxx, lexers/LexCPP.cxx, lexers/LexD.cxx, lexers/LexFortran.cxx, lexers/LexOthers.cxx, lexlib/CharacterSet.h, lib/README.doc, macosx/SciTest/main.cpp, src/AutoComplete.cxx, src/Catalogue.cxx, src/Document.cxx, src/Editor.cxx, src/LexGen.py, test/unit/makefile, version.txt, win32/PlatWin.cxx, win32/ScintRes.rc, win32/scintilla.mak, win32/scintilla_vc6.mak: Merged Scintilla v2.25. [e01dec109182] 2011-03-14 Phil Thompson * qt/qscintilla_es.qm, qt/qscintilla_es.ts: Updated Spanish translations from Jaime Seuma. [b83a3ca4f3e6] 2011-03-12 Phil Thompson * qt/qscintilla_de.qm, qt/qscintilla_de.ts: Updated German translations from Detlev. [e5729134a47b] 2011-03-11 Phil Thompson * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the translation source files. [51e8ee8b1ba9] * NEWS, Python/sip/qscilexercpp.sip, qt/qscilexercpp.cpp, qt/qscilexercpp.h: Added support for the inactive styles of QsciLexerCPP. [59b566d322af] * qt/qscilexercpp.cpp, qt/qscilexercpp.h: Inlined all existing property getters in QsciLexerCPP. [1117e5105e5e] 2011-03-10 Phil Thompson * qt/qsciscintilla.cpp: Fixed QsciScintilla::setContractedFolds() so that it actually updates the display to show the new state. [5079f59a0103] * NEWS, Python/sip/qscilexerhtml.sip, qt/qscilexerhtml.cpp, qt/qscilexerhtml.h: Updated QsciLexerHTML. [0707f4bc7855] * NEWS, Python/sip/qscilexerproperties.sip, qt/qscilexerproperties.cpp, qt/qscilexerproperties.h: Updated QsciLexerProperties. [1dfe5e2d4913] * NEWS, Python/sip/qscilexerpython.sip, Python/sip/qscilexerruby.sip, Python/sip/qscilexersql.sip, Python/sip/qscilexertcl.sip, Python/sip/qscilexertex.sip, qt/qscilexerpython.cpp, qt/qscilexerpython.h, qt/qscilexerruby.h, qt/qscilexersql.h, qt/qscilexertcl.h, qt/qscilexertex.cpp, qt/qscilexertex.h: Updated QsciLexerPython. [bc96868a1a6f] * NEWS, Python/sip/qscilexerruby.sip, Python/sip/qscilexersql.sip, Python/sip/qscilexertcl.sip, Python/sip/qscilexertex.sip, qt/qscilexerruby.cpp, qt/qscilexerruby.h, qt/qscilexersql.h, qt/qscilexertcl.h, qt/qscilexertex.h: The new lexer property setters are no longer virtual slots. [c3e88383e8d3] * qt/qscilexersql.cpp, qt/qscilexersql.h: Restored the default behaviour of setFoldCompact() for QsciLexerSQL. [c74aef0f7eb4] * NEWS, Python/sip/qscilexertcl.sip, qt/qscilexersql.h, qt/qscilexertcl.cpp, qt/qscilexertcl.h: Updated QsciLexerTCL. [43a150bb40d5] * NEWS, Python/sip/qscilexertex.sip, qt/qscilexertex.cpp, qt/qscilexertex.h: Updated QsciLexerTeX. [1457935cee44] * qt/qscintilla_cs.qm, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_es.qm, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm, qt/qscintilla_ru.qm: Updated German translations from Detlev. [ad4a4bd4855b] 2011-03-08 Phil Thompson * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the .ts translation files. [8d70033d07e2] * NEWS, Python/sip/qscilexersql.sip, qt/qscilexersql.cpp, qt/qscilexersql.h: Updated QsciLexerSQL. [8bc79d109c88] * NEWS, Python/sip/qscilexercss.sip, qt/qscilexercss.cpp, qt/qscilexercss.h: Updated QsciLexerCSS. [f3adcb31b1a9] * NEWS, Python/sip/qscilexerd.sip, qt/qscilexerd.cpp, qt/qscilexerd.h: Updated QsciLexerD. [82d8a6561943] * Python/sip/qscilexerlua.sip, qt/qscilexerlua.cpp, qt/qscilexerlua.h: Updated QsciLexerLua. [103f5881c642] * NEWS, Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qsciscintillabase.h: Added support for the QsciScintillaBase::SCN_HOTSPOTRELEASECLICK() signal. [1edd56e105cd] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added low-level support for SCLEX_MARKDOWN, SCLEX_TXT2TAGS and SCLEX_A68K. [de92a613cea7] * Python/sip/qsciscintillabase.sip, qt/qscicommand.cpp, qt/qsciscintilla.cpp, qt/qsciscintillabase.h: Added support for SCMOD_SUPER as the Qt Meta key modifier. [24e745cddeea] * NEWS, Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Updated the QsciScintillaBase::SCN_UPDATEUI() signal. Added low- level support for SC_MOD_LEXERSTATE. [0a341fcb0545] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added low-level support for the updated property functions. [f33d9c271992] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added low-level support for SCI_GETLEXERLANGUAGE and SCI_PRIVATELEXERCALL. [ac69f8c2ef3b] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added low-level support for the new stick caret options. [693ac6c68e6f] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added low-level support for SCI_AUTOCGETCURRENTTEXT. [2634827cdb4e] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added low-level support for SC_SEL_THIN. [4225a944dc14] * qt/qsciscintilla.cpp: Folding now works again. [3972053c646e] 2011-03-07 Phil Thompson * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added low-level support for SCI_VERTICALCENTRECARET. [92d5ecb154d1] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added setContractedFolds() and contractedFolds() to QsciScintilla. [46eb254c6200] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added low-level support for SCI_CHANGELEXERSTATE. [edd899d77aa7] * Python/sip/qsciscintillabase.sip, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added low-level support for SCI_CHARPOSITIONFROMPOINT and SCI_CHARPOSITIONFROMPOINTCLOSE. [5a000cf4bfba] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added low-level support for multiple selections. [dedda8cbf413] * Python/sip/qsciscintillabase.sip, qt/qsciscintillabase.h: Added SCI_GETTAG. [775d0058f00e] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added QsciScintilla::setFirstVisibleLine(). [8b662ffe3fb6] * Python/sip/qsciscintillabase.sip, qt/PlatQt.cpp, qt/qsciscintillabase.h: Added low-level support for setting the font quality. [933e8b01eda6] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added high-level support for line wrap indentation modes. [1faa3b2fa31e] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added high-level support for extra ascent and descent space. Added high-level support for whitespace size, foreground and background. [537c551a79ef] * Python/sip/qsciscintillabase.sip, qt/PlatQt.cpp, qt/qsciscintillabase.h: Updated the low level support for cursors. [2ce685a89697] * NEWS, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.h, qt/qsciscintillabase.h: Updated the support for markers and added FullRectangle, LeftRectangle and Underline to the MarkerSymbol enum. [4c626f8189bf] 2011-03-06 Phil Thompson * NEWS, Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Rectangular selections are now fully supported. The signatures of toMimeData() and fromMimeData() have changed. [397948f42b2e] * NEWS: Updated the NEWS file. [bc75b98210f2] * .hgignore: Added the .hgignore file. [77312a36220e] * qt/qsciscintilla.cpp: Removed the workaround for the broken annotations in Scintilla v1.78. [70ab4c4b7c66] * qt/ListBoxQt.cpp: Fixed a regression when displaying an auto-completion list. [c38d4b97a1ca] 2011-03-04 Phil Thompson * qt/ListBoxQt.cpp, qt/PlatQt.cpp, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qsciscintillabase.cpp: Completed the merge of Scintilla v2.24. [6890939e2da6] * build.py, qt/qscintilla.pro: More build system changes. [3e9deec76c02] * qt/qscintilla.pro, qt/qsciscintilla.cpp: Updated the .pro file for the changed files and directory structure in v2.24. [274cb7017857] * License.txt, README, bin/empty.txt, cocoa/Framework.mk, cocoa/InfoBar.h, cocoa/InfoBar.mm, cocoa/InfoBarCommunicator.h, cocoa/PlatCocoa.h, cocoa/PlatCocoa.mm, cocoa/QuartzTextLayout.h, cocoa/QuartzTextStyle.h, cocoa/QuartzTextStyleAttribute.h, cocoa/SciTest.mk, cocoa/ScintillaCallTip.h, cocoa/ScintillaCallTip.mm, cocoa/ScintillaCocoa.h, cocoa/ScintillaCocoa.mm, cocoa/ScintillaFramework/Info.plist, cocoa/ ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj, cocoa/ScintillaFramework/Scintilla_Prefix.pch, cocoa/ScintillaListBox.h, cocoa/ScintillaListBox.mm, cocoa/ScintillaTest/AppController.h, cocoa/ScintillaTest/AppController.mm, cocoa/ScintillaTest/English.lproj/MainMenu.xib, cocoa/ScintillaTest/Info.plist, cocoa/ScintillaTest/Scintilla- Info.plist, cocoa/ScintillaTest/ScintillaTest.xcodeproj/project.pbxproj, cocoa/ScintillaTest/ScintillaTest_Prefix.pch, cocoa/ScintillaTest/TestData.sql, cocoa/ScintillaTest/main.m, cocoa/ScintillaView.h, cocoa/ScintillaView.mm, cocoa/common.mk, delbin.bat, delcvs.bat, doc/Design.html, doc/Lexer.txt, doc/SciBreak.jpg, doc/SciCoding.html, doc/SciRest.jpg, doc/SciTEIco.png, doc/SciWord.jpg, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/ScintillaToDo.html, doc/ScintillaUsage.html, doc/Steps.html, doc/index.html, gtk/Converter.h, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/deps.mak, gtk/makefile, gtk/scintilla-marshal.c, gtk/scintilla- marshal.h, gtk/scintilla-marshal.list, gtk/scintilla.mak, include/Accessor.h, include/Face.py, include/HFacer.py, include/ILexer.h, include/KeyWords.h, include/Platform.h, include/PropSet.h, include/SString.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, include/ScintillaWidget.h, include/WindowAccessor.h, lexers/LexA68k.cxx, lexers/LexAPDL.cxx, lexers/LexASY.cxx, lexers/LexAU3.cxx, lexers/LexAVE.cxx, lexers/LexAbaqus.cxx, lexers/LexAda.cxx, lexers/LexAsm.cxx, lexers/LexAsn1.cxx, lexers/LexBaan.cxx, lexers/LexBash.cxx, lexers/LexBasic.cxx, lexers/LexBullant.cxx, lexers/LexCLW.cxx, lexers/LexCOBOL.cxx, lexers/LexCPP.cxx, lexers/LexCSS.cxx, lexers/LexCaml.cxx, lexers/LexCmake.cxx, lexers/LexConf.cxx, lexers/LexCrontab.cxx, lexers/LexCsound.cxx, lexers/LexD.cxx, lexers/LexEScript.cxx, lexers/LexEiffel.cxx, lexers/LexErlang.cxx, lexers/LexFlagship.cxx, lexers/LexForth.cxx, lexers/LexFortran.cxx, lexers/LexGAP.cxx, lexers/LexGui4Cli.cxx, lexers/LexHTML.cxx, lexers/LexHaskell.cxx, lexers/LexInno.cxx, lexers/LexKix.cxx, lexers/LexLisp.cxx, lexers/LexLout.cxx, lexers/LexLua.cxx, lexers/LexMMIXAL.cxx, lexers/LexMPT.cxx, lexers/LexMSSQL.cxx, lexers/LexMagik.cxx, lexers/LexMarkdown.cxx, lexers/LexMatlab.cxx, lexers/LexMetapost.cxx, lexers/LexMySQL.cxx, lexers/LexNimrod.cxx, lexers/LexNsis.cxx, lexers/LexOpal.cxx, lexers/LexOthers.cxx, lexers/LexPB.cxx, lexers/LexPLM.cxx, lexers/LexPOV.cxx, lexers/LexPS.cxx, lexers/LexPascal.cxx, lexers/LexPerl.cxx, lexers/LexPowerPro.cxx, lexers/LexPowerShell.cxx, lexers/LexProgress.cxx, lexers/LexPython.cxx, lexers/LexR.cxx, lexers/LexRebol.cxx, lexers/LexRuby.cxx, lexers/LexSML.cxx, lexers/LexSQL.cxx, lexers/LexScriptol.cxx, lexers/LexSmalltalk.cxx, lexers/LexSorcus.cxx, lexers/LexSpecman.cxx, lexers/LexSpice.cxx, lexers/LexTACL.cxx, lexers/LexTADS3.cxx, lexers/LexTAL.cxx, lexers/LexTCL.cxx, lexers/LexTeX.cxx, lexers/LexTxt2tags.cxx, lexers/LexVB.cxx, lexers/LexVHDL.cxx, lexers/LexVerilog.cxx, lexers/LexYAML.cxx, lexlib/Accessor.cxx, lexlib/Accessor.h, lexlib/CharacterSet.cxx, lexlib/CharacterSet.h, lexlib/LexAccessor.h, lexlib/LexerBase.cxx, lexlib/LexerBase.h, lexlib/LexerModule.cxx, lexlib/LexerModule.h, lexlib/LexerNoExceptions.cxx, lexlib/LexerNoExceptions.h, lexlib/LexerSimple.cxx, lexlib/LexerSimple.h, lexlib/OptionSet.h, lexlib/PropSetSimple.cxx, lexlib/PropSetSimple.h, lexlib/StyleContext.cxx, lexlib/StyleContext.h, lexlib/WordList.cxx, lexlib/WordList.h, lib/README.doc, macosx/PlatMacOSX.cxx, macosx/SciTest/SciTest.xcode/project.pbxproj, macosx/ScintillaMacOSX.cxx, macosx/ScintillaMacOSX.h, macosx/deps.mak, macosx/makefile, src/AutoComplete.cxx, src/AutoComplete.h, src/CallTip.cxx, src/CallTip.h, src/Catalogue.cxx, src/Catalogue.h, src/CellBuffer.cxx, src/CellBuffer.h, src/CharClassify.cxx, src/CharClassify.h, src/CharacterSet.h, src/ContractionState.cxx, src/ContractionState.h, src/Decoration.h, src/Document.cxx, src/Document.h, src/DocumentAccessor.cxx, src/DocumentAccessor.h, src/Editor.cxx, src/Editor.h, src/ExternalLexer.cxx, src/ExternalLexer.h, src/FontQuality.h, src/Indicator.cxx, src/Indicator.h, src/KeyMap.cxx, src/KeyMap.h, src/KeyWords.cxx, src/LexAPDL.cxx, src/LexASY.cxx, src/LexAU3.cxx, src/LexAVE.cxx, src/LexAbaqus.cxx, src/LexAda.cxx, src/LexAsm.cxx, src/LexAsn1.cxx, src/LexBaan.cxx, src/LexBash.cxx, src/LexBasic.cxx, src/LexBullant.cxx, src/LexCLW.cxx, src/LexCOBOL.cxx, src/LexCPP.cxx, src/LexCSS.cxx, src/LexCaml.cxx, src/LexCmake.cxx, src/LexConf.cxx, src/LexCrontab.cxx, src/LexCsound.cxx, src/LexD.cxx, src/LexEScript.cxx, src/LexEiffel.cxx, src/LexErlang.cxx, src/LexFlagship.cxx, src/LexForth.cxx, src/LexFortran.cxx, src/LexGAP.cxx, src/LexGen.py, src/LexGui4Cli.cxx, src/LexHTML.cxx, src/LexHaskell.cxx, src/LexInno.cxx, src/LexKix.cxx, src/LexLisp.cxx, src/LexLout.cxx, src/LexLua.cxx, src/LexMMIXAL.cxx, src/LexMPT.cxx, src/LexMSSQL.cxx, src/LexMagik.cxx, src/LexMatlab.cxx, src/LexMetapost.cxx, src/LexMySQL.cxx, src/LexNimrod.cxx, src/LexNsis.cxx, src/LexOpal.cxx, src/LexOthers.cxx, src/LexPB.cxx, src/LexPLM.cxx, src/LexPOV.cxx, src/LexPS.cxx, src/LexPascal.cxx, src/LexPerl.cxx, src/LexPowerPro.cxx, src/LexPowerShell.cxx, src/LexProgress.cxx, src/LexPython.cxx, src/LexR.cxx, src/LexRebol.cxx, src/LexRuby.cxx, src/LexSML.cxx, src/LexSQL.cxx, src/LexScriptol.cxx, src/LexSmalltalk.cxx, src/LexSorcus.cxx, src/LexSpecman.cxx, src/LexSpice.cxx, src/LexTACL.cxx, src/LexTADS3.cxx, src/LexTAL.cxx, src/LexTCL.cxx, src/LexTeX.cxx, src/LexVB.cxx, src/LexVHDL.cxx, src/LexVerilog.cxx, src/LexYAML.cxx, src/LineMarker.cxx, src/LineMarker.h, src/Partitioning.h, src/PerLine.cxx, src/PerLine.h, src/PositionCache.cxx, src/PositionCache.h, src/PropSet.cxx, src/RESearch.cxx, src/RESearch.h, src/RunStyles.cxx, src/SVector.h, src/SciTE.properties, src/ScintillaBase.cxx, src/ScintillaBase.h, src/Selection.cxx, src/Selection.h, src/SplitVector.h, src/Style.cxx, src/Style.h, src/StyleContext.cxx, src/StyleContext.h, src/UniConversion.cxx, src/UniConversion.h, src/ViewStyle.cxx, src/ViewStyle.h, src/WindowAccessor.cxx, src/XPM.cxx, src/XPM.h, test/MessageNumbers.py, test/README, test/XiteMenu.py, test/XiteWin.py, test/examples/x.asp, test/examples/x.asp.styled, test/examples/x.cxx, test/examples/x.cxx.styled, test/examples/x.d, test/examples/x.d.styled, test/examples/x.html, test/examples/x.html.styled, test/examples/x.php, test/examples/x.php.styled, test/examples/x.py, test/examples/x.py.styled, test/examples/x.vb, test/examples/x.vb.styled, test/lexTests.py, test/performanceTests.py, test/simpleTests.py, test/unit/README, test/unit/SciTE.properties, test/unit/makefile, test/unit/testContractionState.cxx, test/unit/testPartitioning.cxx, test/unit/testRunStyles.cxx, test/unit/testSplitVector.cxx, test/unit/unitTest.cxx, test/xite.py, vcbuild/SciLexer.dsp, version.txt, win32/Margin.cur, win32/PlatWin.cxx, win32/PlatformRes.h, win32/SciTE.properties, win32/ScintRes.rc, win32/Scintilla.def, win32/ScintillaWin.cxx, win32/deps.mak, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak, zipsrc.bat: Merged Scintilla v2.24. [59ca27407fd9] 2011-03-03 Phil Thompson * Python/configure.py, qt/qscintilla.pro: Updated the .so version number to 6.0.0. [8ebe3f1fccd4] * Makefile: Switched the build system to Qt v4.7.2. [47f653394ef0] * .hgtags, lib/README.svn: Merged the v2.4 maintenance branch. [d00b7d9115d1] * qsci/api/python/Python-3.2.api: Added an API file for Python v3.2. [8cc94408b710] <2.4-maint> 2011-02-23 Phil Thompson * qt/qsciscintillabase.cpp: On X11 the control modifier is now used (instead of alt) to trigger a rectangular selection. [4bea3b8b8271] <2.4-maint> 2011-02-22 Phil Thompson * qt/qscimacro.cpp: Fixed a bug with Qt4 when loading a macro that meant that a macro may not have a terminating '\0'. [bbec6ef96cd2] <2.4-maint> 2011-02-06 Phil Thompson * lib/LICENSE.commercial.short, lib/LICENSE.gpl.short: Updated the copyright notices. [f386964f3853] <2.4-maint> * Python/sip/qsciscintilla.sip, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Deprecated setAutoCompletionShowSingle(), added setAutoCompletionUseSingle(). Deprecated autoCompletionShowSingle(), added autoCompletionUseSingle(). [7dae1a33b74b] <2.4-maint> * qt/qsciscintilla.cpp, qt/qsciscintilla.h: QsciScintilla::setAutoCompletionCaseSensitivity() is no longer ignored if a lexer has been set. [92d3c5f7b825] <2.4-maint> * qt/qscintilla.pro, qt/qsciscintillabase.cpp: Translate Key_Backtab to Shift-Key_Tab before passing to Scintilla. [fc2d75b26ef8] <2.4-maint> 2011-01-06 Phil Thompson * qt/qscintilla_es.ts: Updated Spanish translations from Jaime Seuma. [8921e85723a1] <2.4-maint> 2010-12-24 Phil Thompson * qt/qsciscintilla.h: Fixed a documentation typo. [1b951cf8838a] <2.4-maint> 2010-12-23 Phil Thompson * .hgtags: Added tag 2.4.6 for changeset 1884d76f35b0 [696037b84e26] <2.4-maint> * NEWS: Released as v2.4.6. [1884d76f35b0] [2.4.6] <2.4-maint> 2010-12-21 Phil Thompson * qt/qsciscintilla.cpp: Auto-completion words from documents are now ignored if they are already included from APIs. [db48fbf19e7c] <2.4-maint> * qt/SciClasses.cpp: Make sure call tips are redrawn afer being clicked on. [497ad4605ae3] <2.4-maint> 2010-11-23 Phil Thompson * NEWS, Python/sip/qsciscintilla.sip, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added support for indicators to the high-level API. See the NEWS file for the details. [8673b7890874] <2.4-maint> 2010-11-15 Phil Thompson * Python/configure.py: Added the --no-timestamp option to configure.py. [61d1b5d28e21] <2.4-maint> * qsci/api/python/Python-2.7.api: Added the API file for Python v2.7. [5b2c77e7150a] <2.4-maint> 2010-11-09 Phil Thompson * Makefile, qt/PlatQt.cpp: Applied a fix for calculating character widths under OS/X. Switched the build system to Qt v4.7.1. [47a4eff86efa] <2.4-maint> 2010-11-08 Phil Thompson * qt/qscilexercpp.h: Fixed a bug in the documentation of QsciLexerCPP.GlobalClass. [3cada289b329] <2.4-maint> 2010-10-24 Phil Thompson * qt/SciClasses.h, qt/ScintillaQt.h, qt/qscicommandset.h, qt/qsciglobal.h, qt/qscilexer.h, qt/qsciprinter.h, qt/qsciscintilla.h, qt/qsciscintillabase.h: Added support for QT_BEGIN_NAMESPACE and QT_END_NAMESPACE. [a80f0df49f6c] <2.4-maint> 2010-10-23 Phil Thompson * qt/qscintilla_de.qm, qt/qscintilla_de.ts: Updated German translations from Detlev. [693d3adf3c3f] <2.4-maint> 2010-10-21 Phil Thompson * Makefile, Python/sip/qscilexerproperties.sip, qt/qscilexerproperties.cpp, qt/qscilexerproperties.h, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Added support for the Key style to QsciLexerProperties. [0b2e86015862] <2.4-maint> 2010-08-31 Phil Thompson * .hgtags: Added tag 2.4.5 for changeset f3f3936e5b86 [84bb1b0d0674] <2.4-maint> * NEWS: Released as v2.4.5. [f3f3936e5b86] [2.4.5] <2.4-maint> 2010-08-21 Phil Thompson * NEWS: Updated the NEWS file. [80afe6b1504a] <2.4-maint> 2010-08-20 Phil Thompson * Python/sip/qsciscintillabase.sip: With Python v3, the QsciScintillaBase.SendScintilla() overloads that take char * arguments now require them to be bytes objects and no longer allow them to be str objects. [afa9ac3c487d] <2.4-maint> 2010-08-14 Phil Thompson * Python/sip/qsciscintillabase.sip: Reverted the addition of the /Encoding/ annotations to SendScintilla() as it is (probably) not the right solution. [4cb625284e4f] <2.4-maint> * qt/qsciscintilla.cpp: The entries in user and auto-completion lists should now support UTF-8. [112d71cec57a] <2.4-maint> * Python/sip/qsciscintillabase.sip: The QsciScintillaBase.SendScintilla() Python overloads will now accept unicode strings that can be encoded to UTF-8. [2f21b97985f2] <2.4-maint> 2010-07-22 Phil Thompson * qt/qscilexerhtml.cpp, qt/qscilexerhtml.h: Implemented QsciLexerHTML::autoCompletionFillups() to change the fillups to "/>". [8d9c1aad1349] <2.4-maint> * qt/qsciscintilla.cpp: Fixed a regression, and the original bug, in QsciScintilla::clearAnnotations(). [fd8746ae2198] <2.4-maint> * qt/qscistyle.cpp: QsciStyle now auto-allocates style numbers from 63 rather than STYLE_MAX because Scintilla only initially creates enough storage for that number of styles. [7c69b0a4ee5b] <2.4-maint> 2010-07-15 Phil Thompson * qt/qscilexerverilog.cpp, qt/qscintilla.pro: Fixed a bug in QsciLexerVerilog that meant that the Keyword style was being completely ignored. [09e28404476a] <2.4-maint> 2010-07-12 Phil Thompson * .hgtags: Added tag 2.4.4 for changeset c61a49005995 [4c98368d9bea] <2.4-maint> * NEWS: Released as v2.4.4. [c61a49005995] [2.4.4] <2.4-maint> 2010-06-08 Phil Thompson * Makefile, qt/qsciscintillabase.cpp: Pop-lists now get removed when the main widget loses focus. [169fa07f52ab] <2.4-maint> 2010-06-05 Phil Thompson * qt/ScintillaQt.cpp: Changed SCN_MODIFIED to deal with text being NULL. [68148fa857ab] <2.4-maint> 2010-06-03 Phil Thompson * qt/ScintillaQt.cpp: The SCN_MODIFIED signal now tries to make sure that the text passed is valid. [90e3461f410f] <2.4-maint> 2010-04-22 Phil Thompson * qt/qsciscintilla.cpp, qt/qsciscintilla.h: QsciScintilla::markerDefine() now allows existing markers to be redefined if an explicit marker number is given. [63f1a7a1d8e2] <2.4-maint> * qt/ScintillaQt.cpp, qt/qsciscintilla.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Fixed the drag and drop behaviour so that a move automatically turns into a copy when the mouse leaves the widget. [4dab09799716] <2.4-maint> 2010-04-21 Phil Thompson * qt/PlatQt.cpp, qt/ScintillaQt.cpp: Fixed build problems against Qt v3. [71168072ac9b] <2.4-maint> * Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added QsciScintillaBase::fromMimeData(). [b86a15672079] <2.4-maint> * Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Renamed QsciScintillaBase::createMimeData() to toMimeData(). [6f5837334dde] <2.4-maint> 2010-04-20 Phil Thompson * Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added QsciScintillaBase::canInsertFromMimeData(). [bbba2c1799ef] <2.4-maint> * Python/sip/qsciscintillabase.sip, qt/ScintillaQt.cpp, qt/qscintilla.pro, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added QsciScintillaBase::createMimeData(). [b2c3e3a9b43d] <2.4-maint> 2010-03-17 Phil Thompson * .hgtags: Added tag 2.4.3 for changeset 786429e0227d [1931843aec48] <2.4-maint> * NEWS, build.py: Fixed the generation of the change log after tagging a release. Updated the NEWS file. Released as v2.4.3. [786429e0227d] [2.4.3] <2.4-maint> 2010-02-23 Phil Thompson * qt/qsciscintilla.cpp, qt/qsciscintilla.h: Reverted the setting of the alpha component in setMarkerForegroundColor() (at least until SC_MARK_UNDERLINE is supported). [111da2e01c5e] <2.4-maint> * qt/PlatQt.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Fixed the very broken support for the alpha component with Qt4. [b1d73c7f447b] <2.4-maint> * Python/sip/qsciscintilla.sip, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added QsciScintilla::clearFolds() to clear all current folds (typically prior to disabling folding). [4f4266da1962] <2.4-maint> 2010-02-15 Phil Thompson * Makefile: Switched the build system to Qt v4.6.2. [f023013b79e4] <2.4-maint> 2010-02-07 Phil Thompson * qt/qscidocument.cpp: Fixed a bug in the handling of multiple views of a document. [8b4aa000df1c] <2.4-maint> 2010-01-31 Phil Thompson * Makefile, build.py: Minor tidy ups for the internal build system. [c3a41d195b8a] <2.4-maint> 2010-01-30 Phil Thompson * Makefile, Python/configure.py, build.py, lib/README.doc, lib/README.svn, lib/qscintilla.dxy, qt/qsciglobal.h: Changes to the internal build system required by the migration to Mercurial. [607e474dfd28] <2.4-maint> 2010-01-29 phil * .hgtags: Import from SVN. [49d5a0d80211] 2010-01-20 phil * Makefile, NEWS: Updated the build system to Qt v4.6.1. Released as v2.4.2. [73732e5bae08] [2.4.2] <2.4-maint> 2010-01-18 phil * qt/qscintilla_es.qm, qt/qscintilla_es.ts: Updated Spanish translations from Jaime Seuma. [3b911e69696d] <2.4-maint> 2010-01-15 phil * Python/configure.py: The Python bindings now check for SIP v4.10. [8d5f4957a07c] <2.4-maint> * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_es.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the .ts files. [15c647ac0c42] <2.4-maint> * NEWS, build.py: Fixed the build system for Qt v3 and v4 prior to v4.5. [1b5bea85a3bf] <2.4-maint> 2010-01-14 phil * NEWS, lib/LICENSE.commercial.short, lib/LICENSE.gpl.short: Released as v2.4.1. [a04b69746aa6] [2.4.1] <2.4-maint> 2009-12-22 phil * lib/gen_python3_api.py, qsci/api/python/Python-3.1.api: Added the API file for Python v3.1. [116c24ab58b2] <2.4-maint> * NEWS, Python/configure.py: Added support for automatically generated docstrings. [3d316b4f222b] <2.4-maint> 2009-12-11 phil * Makefile, qt/PlatQt.cpp: Fixed a performance problem when displaying very long lines. [d3fe67ad2eb5] <2.4-maint> 2009-11-01 phil * qt/qsciapis.cpp: Fixed a possible crash in the handling of call tips. [6248caa24fec] <2.4-maint> * qt/SciClasses.cpp: Applied the workaround for the autocomplete focus bug under Gnome's window manager which (appears) to work with current versions of Qt across all platforms. [f709f1518e70] <2.4-maint> * Makefile, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Make sure a lexer is fully detached when a QScintilla instance is destroyed. [db47764231d2] <2.4-maint> 2009-08-19 phil * lib/LICENSE.gpl.short, qt/qscintilla_de.qm, qt/qscintilla_de.ts: Updated German translations from Detlev. [458b60ec031e] <2.4-maint> 2009-08-09 phil * Python/sip/qscilexerverilog.sip, Python/sip/qscimodcommon.sip, qt/qscilexerverilog.cpp, qt/qscilexerverilog.h, qt/qscintilla.pro: Added the QsciLexerVerilog class. [86b2aceac88c] <2.4-maint> * Makefile, Python/sip/qscilexerspice.sip, Python/sip/qscimodcommon.sip, lib/LICENSE.commercial, lib /OPENSOURCE-NOTICE.TXT, lib/README.doc, qt/qscilexerspice.cpp, qt/qscilexerspice.h, qt/qscintilla.pro: Added the QsciLexerSpice class. [56532ec00839] <2.4-maint> 2009-06-05 phil * NEWS, lib/LICENSE.commercial: Released as v2.4. [612b1bcb8223] [2.4] 2009-06-03 phil * NEWS, qt/qscistyledtext.h: Fixed a bug building on Qt v3. [88ebc67fdff4] 2009-05-30 phil * qt/ScintillaQt.cpp: Applied a fix for copying UTF-8 text to the X clipboard from Lars Reichelt. [e59fa72c2e2d] 2009-05-27 phil * qt/qscilexercustom.h: Fixed a missing forward declaration in qscilexercustom.h. [0018449ee6aa] 2009-05-25 phil * qt/qscilexercustom.cpp: Don't ask the custom lexer to style zero characters. [6ae021232f4f] 2009-05-19 phil * NEWS, qt/qscintilla.pro, qt/qscintilla_cs.qm, qt/qscintilla_es.qm, qt/qscintilla_es.ts, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm, qt/qscintilla_ru.qm: Added Spanish translations from Jaime Seuma. [0cdbee8db9af] * qt/qsciscintilla.cpp: A minor fix for ancient C++ compilers. [0523c3a0e0aa] 2009-05-18 phil * NEWS, Python/sip/qscilexer.sip, Python/sip/qscilexercustom.sip, Python/sip/qscimodcommon.sip, Python/sip/qsciscintilla.sip, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscilexercustom.cpp, qt/qscilexercustom.h, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added QsciScintilla::annotation(). Added QsciLexerCustom (completely untested) and supporting changes to QsciLexer. [382d5b86f600] 2009-05-17 phil * qt/qscintilla_cs.ts, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated translations from Detlev. [0b8c8438e464] 2009-05-09 phil * NEWS, Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added support for text margins. [be9db7d41b50] * qt/PlatQt.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qscistyledtext.cpp, qt/qscistyledtext.h: Debugged the support for annotations. Tidied up the QString to Scintilla string conversions. [573199665222] 2009-05-08 phil * NEWS, Python/sip/qscimodcommon.sip, Python/sip/qsciscintilla.sip, Python/sip/qscistyle.sip, Python/sip/qscistyledtext.sip, qt/qscicommand.h, qt/qscimacro.h, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qscistyle.cpp, qt/qscistyle.h, qt/qscistyledtext.cpp, qt/qscistyledtext.h: Implemented the rest of the annotation API - still needs debugging. [7f23400d2416] 2009-05-07 phil * NEWS, qt/qscintilla.pro, qt/qscistyle.cpp, qt/qscistyle.h: Added the QsciStyle class. [bf8e3e02071e] 2009-05-06 phil * qt/qsciscintillabase.cpp: Fixed the key event handling when the text() is empty and the key() should be used - only seems to happen with OS/X. [868a146b019f] 2009-05-03 phil * Makefile, NEWS, Python/configure.py, Python/sip/qscicommand.sip, Python/sip/qscicommandset.sip, Python/sip/qscilexer.sip, Python/sip/qscilexercpp.sip, Python/sip/qscilexercss.sip, Python/sip/qscilexerdiff.sip, Python/sip/qscilexerhtml.sip, Python/sip/qscilexerpascal.sip, Python/sip/qscilexerperl.sip, Python/sip/qscilexerpython.sip, Python/sip/qscilexerxml.sip, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, README, UTF-8-demo.txt, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/ScintillaToDo.html, doc/annotations.png, doc/index.html, doc/styledmargin.png, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/deps.mak, gtk/makefile, gtk/scintilla.mak, include/Face.py, include/HFacer.py, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, include/ScintillaWidget.h, lib/LICENSE.commercial, macosx/PlatMacOSX.cxx, macosx/makefile, qt/PlatQt.cpp, qt/ScintillaQt.cpp, qt/qsciapis.cpp, qt/qscidocument.cpp, qt/qscidocument.h, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscilexercpp.cpp, qt/qscilexercpp.h, qt/qscilexercss.cpp, qt/qscilexercss.h, qt/qscilexerdiff.cpp, qt/qscilexerdiff.h, qt/qscilexerhtml.cpp, qt/qscilexerhtml.h, qt/qscilexerpascal.cpp, qt/qscilexerpascal.h, qt/qscilexerperl.cpp, qt/qscilexerperl.h, qt/qscilexerpython.cpp, qt/qscilexerpython.h, qt/qscilexerxml.cpp, qt/qscilexerxml.h, qt/qscintilla.pro, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h, src/CellBuffer.cxx, src/CellBuffer.h, src/Document.cxx, src/Document.h, src/Editor.cxx, src/Editor.h, src/ExternalLexer.cxx, src/Indicator.cxx, src/Indicator.h, src/KeyWords.cxx, src/LexAU3.cxx, src/LexAbaqus.cxx, src/LexAsm.cxx, src/LexBash.cxx, src/LexCOBOL.cxx, src/LexCPP.cxx, src/LexCSS.cxx, src/LexD.cxx, src/LexFortran.cxx, src/LexGen.py, src/LexHTML.cxx, src/LexHaskell.cxx, src/LexInno.cxx, src/LexLua.cxx, src/LexMySQL.cxx, src/LexNimrod.cxx, src/LexNsis.cxx, src/LexOthers.cxx, src/LexPascal.cxx, src/LexPerl.cxx, src/LexPowerPro.cxx, src/LexProgress.cxx, src/LexPython.cxx, src/LexRuby.cxx, src/LexSML.cxx, src/LexSQL.cxx, src/LexSorcus.cxx, src/LexTACL.cxx, src/LexTADS3.cxx, src/LexTAL.cxx, src/LexTeX.cxx, src/LexVerilog.cxx, src/LexYAML.cxx, src/PerLine.cxx, src/PerLine.h, src/PositionCache.cxx, src/RESearch.cxx, src/RESearch.h, src/RunStyles.h, src/SciTE.properties, src/ScintillaBase.cxx, src/SplitVector.h, src/UniConversion.cxx, src/ViewStyle.cxx, src/ViewStyle.h, vcbuild/SciLexer.dsp, version.txt, win32/PlatWin.cxx, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak: Merged the v2.3 branch onto the trunk. [1bb3d2b01123] 2008-09-20 phil * Makefile, NEWS, lib/README.doc: Released as v2.3. [8fd73a9a9d66] [2.3] 2008-09-17 phil * NEWS, Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added QsciScintilla::apiContext() for further open up the auto- completion and call tips support. [a6291ea6dd37] 2008-09-16 phil * Python/configure.py, lib/gen_python_api.py, qsci/api/python/Python-2.6.api, qt/qsciapis.h: Added the API file for Python v2.6rc1. Fixed a typo in the help for the Python bindings configure.py. [ac10be3cc7fb] 2008-09-03 phil * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the i18n .ts files. [b73beac06e0f] 2008-09-01 phil * lib/README.doc: Updated the Windows installation notes to cover the need to manually install the DLL when using Qt3. [17019ebfab36] * lib/README.doc, qt/qsciscintilla.cpp: Fixed a regression in the highlighting of call tip arguments. Updated the Windows installation notes to say that any header files installed from a previous build should first be removed. [cb3f27b93323] 2008-08-31 phil * NEWS, Python/configure.py, Python/sip/qsciabstractapis.sip, Python/sip/qsciapis.sip, Python/sip/qscilexer.sip, Python/sip/qscimodcommon.sip, Python/sip/qsciscintillabase.sip, qt/qsciabstractapis.cpp, qt/qsciabstractapis.h, qt/qsciapis.cpp, qt/qsciapis.h, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added the QsciAbstractAPIs class to allow applications to provide their own implementation of APIs. [eb5a8a602e5d] * Makefile, Python/configure.py, Python/sip/qscilexerfortran.sip, Python/sip/qscilexerfortran77.sip, Python/sip/qscilexerpascal.sip, Python/sip/qscilexerpostscript.sip, Python/sip/qscilexertcl.sip, Python/sip/qscilexerxml.sip, Python/sip/qscilexeryaml.sip, Python/sip/qscimodcommon.sip, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, build.py, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/index.html, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/makefile, gtk/scintilla.mak, include/Platform.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, lib/LICENSE.commercial, lib/README.doc, lib/qscintilla.dxy, macosx/ExtInput.cxx, macosx/ExtInput.h, macosx/PlatMacOSX.cxx, macosx/PlatMacOSX.h, macosx/QuartzTextLayout.h, macosx/QuartzTextStyle.h, macosx/QuartzTextStyleAttribute.h, macosx/ScintillaMacOSX.cxx, macosx/ScintillaMacOSX.h, macosx/TView.cxx, macosx/makefile, qt/ListBoxQt.cpp, qt/ListBoxQt.h, qt/qscilexerfortran.cpp, qt/qscilexerfortran.h, qt/qscilexerfortran77.cpp, qt/qscilexerfortran77.h, qt/qscilexerhtml.cpp, qt/qscilexerlua.cpp, qt/qscilexerlua.h, qt/qscilexerpascal.cpp, qt/qscilexerpascal.h, qt/qscilexerperl.cpp, qt/qscilexerperl.h, qt/qscilexerpostscript.cpp, qt/qscilexerpostscript.h, qt/qscilexertcl.cpp, qt/qscilexertcl.h, qt/qscilexerxml.cpp, qt/qscilexerxml.h, qt/qscilexeryaml.cpp, qt/qscilexeryaml.h, qt/qscimacro.cpp, qt/qscimacro.h, qt/qscintilla.pro, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.h, src/CellBuffer.cxx, src/Editor.cxx, src/Editor.h, src/KeyWords.cxx, src/LexCPP.cxx, src/LexGen.py, src/LexMagik.cxx, src/LexMatlab.cxx, src/LexPerl.cxx, src/LexPowerShell.cxx, src/LineMarker.cxx, src/RunStyles.cxx, src/RunStyles.h, vcbuild/SciLexer.dsp, version.txt, win32/PlatWin.cxx, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak: Merged the v2.2 maintenance branch. [cd784c60bcc7] 2008-02-27 phil * NEWS, build.py, lib/GPL_EXCEPTION.TXT, lib/LICENSE.GPL2, lib/LICENSE.GPL3, lib/LICENSE.commercial, lib/LICENSE.commercial.short, lib/LICENSE.gpl, lib/LICENSE.gpl.short, lib/OPENSOURCE-NOTICE.TXT: Updated the licenses to be in line with the the current Qt licenses, including GPL v3. Released as v2.2. [a039ca791129] [2.2] 2008-02-23 phil * Makefile, qt/PlatQt.cpp: Switched to Qt v4.3.4. Further tweaks for Windows64 support. [3ae9686f38e6] 2008-02-22 phil * Makefile, NEWS, Python/sip/qsciscintillabase.sip, qt/PlatQt.cpp, qt/ScintillaQt.cpp, qt/qscidocument.cpp, qt/qscimacro.cpp, qt/qscintilla.pro, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Several fixes for Windows64 support based on a patch from Randall Frank. [2c753ee01c42] 2008-02-09 phil * Python/configure.py, lib/README.doc, qt/qscintilla.pro: It's no longer necessary to set DYLD_LIBRARY_PATH when using the Python bindings. [d1098424aed1] 2008-02-03 phil * Python/sip/qscilexerruby.sip: Added the missing QsciLexerRuby.Error to the Python bindings. [0b4f06a30251] 2008-01-20 phil * designer-Qt4/qscintillaplugin.cpp, designer-Qt4/qscintillaplugin.h: Fixed a problem with the Qt4 Designer plugin on Leopard. [5450a1bc62df] 2008-01-11 phil * qt/SciClasses.cpp, qt/qsciscintillabase.cpp: Hopefully fixed shortcuts and accelerators when the autocompletion list is displayed. [8304a1f4e36b] 2008-01-06 phil * qt/SciClasses.cpp: Hopefully fixed a bug stopping normal typing when the autocompletion list is being displayed. [2db0cc8fa158] 2008-01-03 phil * lib/LICENSE.commercial.short, lib/LICENSE.gpl, lib/LICENSE.gpl.short, lib/README.doc, qt/qsciscintillabase.cpp: Fixed a Qt3 compilation bug. Updated the copyright notices. [cf238f41fb54] 2007-12-30 phil * qt/SciClasses.cpp, qt/SciClasses.h, qt/qsciscintillabase.cpp: Hopefully fixed the problems with the auto-completion popup on all platforms (not tested on Mac). [585aa7e4e59f] 2007-12-29 phil * qt/SciClasses.cpp: Remove the use of the internal Tooltip widget flag so that the X11 auto-completion list now has the same problems as the Windows version. (Prior to fixing the problem properly.) [93d584d099db] 2007-12-23 phil * qt/ScintillaQt.cpp: Fixed DND problems with Qt4. [23f8c1a7c4c7] * qt/qsciscintilla.cpp: Fix from Detlev for an infinite loop caused by calling getCursorPosition() when Scintilla reports a position past the end of the text. [dd99ade93fa6] 2007-12-05 phil * qt/qscilexerperl.cpp, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Fixed a silly typo in the updated Perl lexer. [0e290eb71572] * qt/qscintilla_de.qm: Updated German translations from Detlev. [e820d3c167f5] * Makefile: Switched the internal build system to Qt v4.3.3. [df2d877e2422] 2007-12-04 phil * qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the translation source files. [1fb11f16d750] * Python/sip/qscilexerperl.sip, Python/sip/qsciscintillabase.sip, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/index.html, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/makefile, gtk/scintilla.mak, include/Platform.h, include/PropSet.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, lib/README.svn, macosx/PlatMacOSX.cxx, macosx/ScintillaMacOSX.h, macosx/makefile, qt/PlatQt.cpp, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscilexerperl.cpp, qt/qscilexerperl.h, qt/qscilexerpython.cpp, qt/qscilexerpython.h, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintillabase.h, src/CellBuffer.cxx, src/CellBuffer.h, src/ContractionState.cxx, src/ContractionState.h, src/Document.cxx, src/Document.h, src/DocumentAccessor.cxx, src/Editor.cxx, src/Editor.h, src/KeyWords.cxx, src/LexAPDL.cxx, src/LexASY.cxx, src/LexAU3.cxx, src/LexAbaqus.cxx, src/LexBash.cxx, src/LexCPP.cxx, src/LexGen.py, src/LexHTML.cxx, src/LexHaskell.cxx, src/LexMetapost.cxx, src/LexOthers.cxx, src/LexPerl.cxx, src/LexPython.cxx, src/LexR.cxx, src/LexSQL.cxx, src/LexTeX.cxx, src/LexYAML.cxx, src/Partitioning.h, src/PositionCache.cxx, src/PositionCache.h, src/PropSet.cxx, src/RunStyles.cxx, src/RunStyles.h, src/ScintillaBase.cxx, src/SplitVector.h, src/ViewStyle.cxx, src/ViewStyle.h, vcbuild/SciLexer.dsp, version.txt, win32/PlatWin.cxx, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak: Merged Scintilla v1.75. [8009a4d7275a] 2007-11-17 phil * qt/SciClasses.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Bug fixes for selectAll() and getCursorPosition() from Baz Walter. [80eecca239b4] 2007-10-24 phil * qt/qsciscintilla.cpp: Fixed folding for HTML. [bb6fb6065e30] 2007-10-14 phil * build.py, lib/GPL_EXCEPTION.TXT, lib/GPL_EXCEPTION_ADDENDUM.TXT, lib/LICENSE.gpl, lib/OPENSOURCE-NOTICE.TXT, qt/qscicommandset.cpp: Control characters that are not bound to commands (or shortcuts) now default to doing nothing (rather than inserting the character into the text). Aligned the GPL license with Trolltech's exceptions. [148432c68762] 2007-10-12 phil * src/LexHTML.cxx: Fixed the Scintilla HTML lexer's handling of characters >= 0x80. [c4e271ce8e96] 2007-10-05 phil * qt/qsciscintillabase.cpp: Used NoSystemBackground rather than OpaquePaintEvent to eliminate flicker. [01a22c66304d] 2007-10-04 phil * Makefile, qt/qsciscintillabase.cpp: Fixed a flashing effect visible with a non-standard background. Switched to Qt v4.3.2. [781c58fcba96] 2007-09-23 phil * qt/qsciapis.h, qt/qscicommand.h, qt/qscicommandset.h, qt/qscidocument.h, qt/qsciglobal.h, qt/qscilexer.h, qt/qscilexerbash.h, qt/qscilexerbatch.h, qt/qscilexercmake.h, qt/qscilexercpp.h, qt/qscilexercsharp.h, qt/qscilexercss.h, qt/qscilexerd.h, qt/qscilexerdiff.h, qt/qscilexerhtml.h, qt/qscilexeridl.h, qt/qscilexerjava.h, qt/qscilexerjavascript.h, qt/qscilexerlua.h, qt/qscilexermakefile.h, qt/qscilexerperl.h, qt/qscilexerpov.h, qt/qscilexerproperties.h, qt/qscilexerpython.h, qt/qscilexerruby.h, qt/qscilexersql.h, qt/qscilexertex.h, qt/qscilexervhdl.h, qt/qscimacro.h, qt/qsciprinter.h, qt/qsciscintilla.h, qt/qsciscintillabase.h: Made the recent portabilty changes Mac specific as AIX has a problem with them. [0de605d4079f] 2007-09-16 phil * qt/qscilexer.cpp: A lexer's default colour, paper and font are now written to and read from the settings. [45277fc76ace] 2007-09-15 phil * lib/README.doc, qt/qsciapis.h, qt/qscicommand.h, qt/qscicommandset.h, qt/qscidocument.h, qt/qsciglobal.h, qt/qscilexer.h, qt/qscilexerbash.h, qt/qscilexerbatch.h, qt/qscilexercmake.h, qt/qscilexercpp.h, qt/qscilexercsharp.h, qt/qscilexercss.h, qt/qscilexerd.h, qt/qscilexerdiff.h, qt/qscilexerhtml.h, qt/qscilexeridl.h, qt/qscilexerjava.h, qt/qscilexerjavascript.h, qt/qscilexerlua.h, qt/qscilexermakefile.h, qt/qscilexerperl.h, qt/qscilexerpov.h, qt/qscilexerproperties.h, qt/qscilexerpython.h, qt/qscilexerruby.h, qt/qscilexersql.h, qt/qscilexertex.h, qt/qscilexervhdl.h, qt/qscimacro.h, qt/qsciprinter.h, qt/qsciscintilla.h, qt/qsciscintillabase.h: Fixed the MacOS build problems when using the binary installer version of Qt. [e059a923a447] * lib/LICENSE.commercial.short, qt/PlatQt.cpp: Added the missing WaitMouseMoved() implementation on MacOS. [78d1c8fc37c0] 2007-09-10 phil * qt/qsciscintilla.cpp, qt/qsciscintilla.h: QsciScintilla::setFont() now calls QWidget::setFont() so that font() returns the expected value. [fd4f577c60ea] 2007-09-02 phil * qt/qsciscintilla.cpp: Fixed problems which the font size of STYLE_DEFAULT not being updated when the font of style 0 was changed. Hopefully this fixes the problems with edge columns and indentation guides. [ddeccb6f64a0] 2007-08-12 phil * Makefile, lib/LICENSE.commercial.short, lib/LICENSE.gpl.short, qt/qscintilla.pro: Applied .pro file fix from Dirk Mueller to add a proper install rule. [a3a2e49f1042] 2007-07-22 phil * qt/qscilexer.cpp: Made sure that the backgound colour of areas of the widget with no text is updated when QsciLexer.setDefaultPaper() is called. [065558d2430b] 2007-07-09 phil * qt/qsciscintilla.cpp, qt/qsciscintilla.h: Explicitly set the style for STYLE_DEFAULT when setting a lexer. [a95fc3357771] 2007-06-30 phil * Python/sip/qsciscintillabase.sip, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/index.html, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/deps.mak, gtk/makefile, gtk/scintilla.mak, include/Accessor.h, include/HFacer.py, include/KeyWords.h, include/Platform.h, include/PropSet.h, include/SString.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, include/WindowAccessor.h, macosx/PlatMacOSX.cxx, macosx/PlatMacOSX.h, macosx/QuartzTextLayout.h, macosx/QuartzTextStyle.h, macosx/QuartzTextStyleAttribute.h, macosx/SciTest/English.lproj/InfoPlist.strings, macosx/SciTest/English.lproj/main.nib/classes.nib, macosx/SciTest/English.lproj/main.nib/info.nib, macosx/SciTest/English.lproj/main.nib/objects.xib, macosx/SciTest/Info.plist, macosx/SciTest/SciTest.xcode/project.pbxproj, macosx/SciTest/SciTest_Prefix.pch, macosx/SciTest/main.cpp, macosx/SciTest/version.plist, macosx/ScintillaCallTip.cxx, macosx/ScintillaCallTip.h, macosx/ScintillaListBox.cxx, macosx/ScintillaListBox.h, macosx/ScintillaMacOSX.cxx, macosx/ScintillaMacOSX.h, macosx/TCarbonEvent.cxx, macosx/TCarbonEvent.h, macosx/TRect.h, macosx/TView.cxx, macosx/TView.h, macosx/deps.mak, macosx/makefile, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qscintilla.pro, qt/qsciscintillabase.h, src/AutoComplete.cxx, src/AutoComplete.h, src/CallTip.cxx, src/CallTip.h, src/CellBuffer.cxx, src/CellBuffer.h, src/CharacterSet.h, src/ContractionState.cxx, src/ContractionState.h, src/Decoration.cxx, src/Decoration.h, src/Document.cxx, src/Document.h, src/DocumentAccessor.cxx, src/DocumentAccessor.h, src/Editor.cxx, src/Editor.h, src/ExternalLexer.cxx, src/ExternalLexer.h, src/Indicator.cxx, src/Indicator.h, src/KeyMap.cxx, src/KeyMap.h, src/KeyWords.cxx, src/LexAPDL.cxx, src/LexAU3.cxx, src/LexAVE.cxx, src/LexAda.cxx, src/LexAsm.cxx, src/LexAsn1.cxx, src/LexBaan.cxx, src/LexBash.cxx, src/LexBasic.cxx, src/LexBullant.cxx, src/LexCLW.cxx, src/LexCPP.cxx, src/LexCSS.cxx, src/LexCaml.cxx, src/LexCmake.cxx, src/LexConf.cxx, src/LexCrontab.cxx, src/LexCsound.cxx, src/LexD.cxx, src/LexEScript.cxx, src/LexEiffel.cxx, src/LexErlang.cxx, src/LexFlagship.cxx, src/LexForth.cxx, src/LexFortran.cxx, src/LexGAP.cxx, src/LexGen.py, src/LexGui4Cli.cxx, src/LexHTML.cxx, src/LexHaskell.cxx, src/LexInno.cxx, src/LexKix.cxx, src/LexLisp.cxx, src/LexLout.cxx, src/LexLua.cxx, src/LexMMIXAL.cxx, src/LexMPT.cxx, src/LexMSSQL.cxx, src/LexMatlab.cxx, src/LexMetapost.cxx, src/LexNsis.cxx, src/LexOpal.cxx, src/LexOthers.cxx, src/LexPB.cxx, src/LexPLM.cxx, src/LexPOV.cxx, src/LexPS.cxx, src/LexPascal.cxx, src/LexPerl.cxx, src/LexProgress.cxx, src/LexPython.cxx, src/LexRebol.cxx, src/LexRuby.cxx, src/LexSQL.cxx, src/LexScriptol.cxx, src/LexSmalltalk.cxx, src/LexSpecman.cxx, src/LexSpice.cxx, src/LexTADS3.cxx, src/LexTCL.cxx, src/LexTeX.cxx, src/LexVB.cxx, src/LexVHDL.cxx, src/LexVerilog.cxx, src/LexYAML.cxx, src/LineMarker.cxx, src/LineMarker.h, src/Partitioning.h, src/PositionCache.cxx, src/PositionCache.h, src/PropSet.cxx, src/RESearch.cxx, src/RESearch.h, src/RunStyles.cxx, src/RunStyles.h, src/SVector.h, src/ScintillaBase.cxx, src/ScintillaBase.h, src/SplitVector.h, src/Style.cxx, src/Style.h, src/StyleContext.cxx, src/StyleContext.h, src/UniConversion.cxx, src/UniConversion.h, src/ViewStyle.cxx, src/ViewStyle.h, src/WindowAccessor.cxx, src/XPM.cxx, src/XPM.h, vcbuild/SciLexer.dsp, version.txt, win32/PlatWin.cxx, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/deps.mak, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak, zipsrc.bat: Merged Scintilla v1.74. [04dee9c2424f] * Python/sip/qscilexerpython.sip, build.py, qt/qscilexer.cpp, qt/qscilexerbash.cpp, qt/qscilexerpython.cpp, qt/qscilexerpython.h, qt/qscintilla.pro: Fixed comment folding in the Bash lexer. A style is properly restored when read from QSettings. Removed ./Qsci from the qmake INCLUDEPATH. Removed the Scintilla version number from generated filenames. Used fully qualified enum names in the Python lexer so that the QMetaObject is correct. [6b27a5b211e0] 2007-06-01 phil * NEWS: Released as v2.1. [9976edafc5c1] [2.1] 2007-05-30 phil * Makefile: Switched the internal build system to Qt v4.3.0. [49284aa376ef] * NEWS, Python/configure.py, Python/sip/qscilexer.sip, Python/sip/qscilexerbash.sip, Python/sip/qscilexerbatch.sip, Python/sip/qscilexercmake.sip, Python/sip/qscilexercpp.sip, Python/sip/qscilexercsharp.sip, Python/sip/qscilexercss.sip, Python/sip/qscilexerd.sip, Python/sip/qscilexerdiff.sip, Python/sip/qscilexerhtml.sip, Python/sip/qscilexeridl.sip, Python/sip/qscilexerjavascript.sip, Python/sip/qscilexerlua.sip, Python/sip/qscilexermakefile.sip, Python/sip/qscilexerperl.sip, Python/sip/qscilexerpov.sip, Python/sip/qscilexerproperties.sip, Python/sip/qscilexerpython.sip, Python/sip/qscilexerruby.sip, Python/sip/qscilexersql.sip, Python/sip/qscilexertex.sip, Python/sip/qscilexervhdl.sip, Python/sip/qscimodcommon.sip, build.py, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscilexerbash.cpp, qt/qscilexerbash.h, qt/qscilexerbatch.cpp, qt/qscilexerbatch.h, qt/qscilexercmake.cpp, qt/qscilexercmake.h, qt/qscilexercpp.cpp, qt/qscilexercpp.h, qt/qscilexercsharp.cpp, qt/qscilexercsharp.h, qt/qscilexercss.cpp, qt/qscilexercss.h, qt/qscilexerd.cpp, qt/qscilexerd.h, qt/qscilexerdiff.cpp, qt/qscilexerdiff.h, qt/qscilexerhtml.cpp, qt/qscilexerhtml.h, qt/qscilexeridl.cpp, qt/qscilexeridl.h, qt/qscilexerjavascript.cpp, qt/qscilexerjavascript.h, qt/qscilexerlua.cpp, qt/qscilexerlua.h, qt/qscilexermakefile.cpp, qt/qscilexermakefile.h, qt/qscilexerperl.cpp, qt/qscilexerperl.h, qt/qscilexerpov.cpp, qt/qscilexerpov.h, qt/qscilexerproperties.cpp, qt/qscilexerproperties.h, qt/qscilexerpython.cpp, qt/qscilexerpython.h, qt/qscilexerruby.cpp, qt/qscilexerruby.h, qt/qscilexersql.cpp, qt/qscilexersql.h, qt/qscilexertex.cpp, qt/qscilexertex.h, qt/qscilexervhdl.cpp, qt/qscilexervhdl.h, qt/qscintilla.pro: Lexers now remember their style settings. A lexer no longer has to be the current lexer when changing a style's color, end-of-line fill, font or paper. The color(), eolFill(), font() and paper() methods of QsciLexer now return the current values for a style rather than the default values. The setDefaultColor(), setDefaultFont() and setDefaultPaper() methods of QsciLexer are no longer slots and no longer virtual. The defaultColor(), defaultFont() and defaultPaper() methods of QsciLexer are no longer virtual. The color(), eolFill(), font() and paper() methods of all QsciLexer derived classes (except for QsciLexer itself) have been renamed defaultColor(), defaultEolFill(), defaultFont() and defaultPaper() respectively. [38aeee2a5a36] 2007-05-28 phil * qt/qsciscintilla.cpp: Set the number of style bits after we've set the lexer. [84cda9af5b00] * Python/configure.py: Fixed the handling of the %Timeline in the Python bindings. [4b3146d1a236] 2007-05-27 phil * Python/sip/qsciscintillabase.sip: Updated the sub-class convertor code in the Python bindings for the Cmake and VHDL lexers. [6ab6570728a2] 2007-05-26 phil * NEWS: Updated the NEWS file. Released as v2.0. [eec9914d8211] [2.0] 2007-05-19 phil * Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added basic input method support for Qt4 so that accented characters now work. (Although there is still a font problem - at least a text colour problem.) [6b41f3694999] * qt/qsciapis.cpp, qt/qsciapis.h, qt/qsciscintillabase.cpp: Fixed building against Qt v3. [9e9ba05de0fb] 2007-05-17 phil * qt/qsciscintilla.cpp: Fixed an autocompletion problem where an empty list was being displayed. [c7214274017c] 2007-05-16 phil * qt/qsciscintilla.cpp: Fixed a bug where autocompleting from the document was looking for preceeding non-word characters as well. [3ee6fd746d49] * qt/qsciscintilla.cpp: Fixed silly typo that broke call tips. [05213a8933c2] 2007-05-09 phil * qt/qsciscintilla.cpp: Fiex an autocompletion bug for words that only had preceding whitespace. [a8f3339e02c6] * Python/configure.py, lib/gen_python_api.py, qsci/api/python/Python-2.4.api, qsci/api/python/Python-2.5.api, qt/qsciapis.cpp, qt/qsciapis.h: Call tips shouldn't now get confused with commas in the text after the argument list. The included API files for Python should now be complete and properly exclude anything beginning with an underscore. The Python bindings configure.py can now install the API file in a user supplied directory. [c7e93dc918de] * qt/qscintilla_cs.qm, qt/qscintilla_fr.qm, qt/qscintilla_pt_br.qm, qt/qscintilla_ru.qm: Ran lrelease on the project. [c3ce60078221] * Makefile, qt/qscintilla_cs.ts, qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Updated the internal build system to Qt v4.3.0rc1. Ran lupdate on the project. [6a86e71a4e26] 2007-05-08 phil * Python/sip/qsciscintilla.sip, qt/qsciapis.cpp, qt/qsciapis.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Call tips will now show all the tips for a function (in all scopes) if the current context/scope isn't known. [cbebccc205c7] * Python/sip/qsciscintilla.sip, qt/qsciapis.cpp, qt/qsciapis.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added callTipsStyle() and setCallTipsStyle() to QsciScintilla. [59d453b5da8c] 2007-05-07 phil * qt/qsciscintilla.cpp, qt/qsciscintilla.h: Autocompletion from documents should now work the same as QScintilla v1. The only difference is that the list does not contain the preceding context so it is consistent with autocompletion from APIs. [46de719d325e] * qt/qscintilla.pro, qt/qscintilla_cs.qm, qt/qscintilla_cs.ts: Added the Czech translations from Zdenek Bohm. [139fd9aee405] 2007-04-30 phil * Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added QsciScintilla::wordCharacters(). [d6e56986a031] 2007-04-29 phil * Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Added lots of consts to QsciScintilla getter methods. [4aaffa8611ba] * Python/configure.py, Python/sip/qsciscintilla.sip, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added caseSensitive() and isWordCharacter() to QsciScintilla. Updated translations from Detlev. [64223bf97266] 2007-04-10 phil * Python/sip/qscilexercmake.sip, Python/sip/qscilexervhdl.sip, Python/sip/qscimodcommon.sip, qt/qscilexercmake.cpp, qt/qscilexercmake.h, qt/qscilexervhdl.cpp, qt/qscilexervhdl.h, qt/qscintilla.pro: Added the QsciLexerVHDL class. [10029339786f] * Python/sip/qscilexercmake.sip, Python/sip/qscimodcommon.sip, qt/qscilexercmake.cpp, qt/qscilexercmake.h, qt/qscintilla.pro: Added the QsciLexerCmake class. [c1c911246f75] 2007-04-09 phil * qt/qsciapis.cpp, qt/qsciapis.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Finished call tip support. [b8c717297392] 2007-04-07 phil * qt/qsciapis.cpp, qt/qsciapis.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Some refactoring in preparation for getting call tips working. [6cb925653a80] 2007-04-06 phil * qt/qsciscintilla.cpp: Fixed autoindenting. [8d7b93ee4d9e] 2007-04-05 phil * qt/qsciapis.cpp, qt/qsciapis.h, qt/qsciscintilla.cpp: Fixed autocompletion so that it works with lexers that don't define word separators, and lexers that are case insensitive. [66634cf13685] 2007-04-04 phil * qt/ScintillaQt.cpp, qt/qsciscintilla.cpp: Fixed the horizontal scrollbar when word wrapping. [021ea1fe8468] 2007-04-03 phil * Python/configure.py, Python/sip/qsciscintillabase.sip, delcvs.bat, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/index.html, gtk/makefile, gtk/scintilla.mak, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, qt/ScintillaQt.cpp, qt/qscintilla.pro, qt/qsciscintillabase.h, src/Document.cxx, src/Document.h, src/DocumentAccessor.cxx, src/Editor.cxx, src/Editor.h, src/ExternalLexer.h, src/KeyWords.cxx, src/LexAU3.cxx, src/LexBash.cxx, src/LexCmake.cxx, src/LexHTML.cxx, src/LexLua.cxx, src/LexMSSQL.cxx, src/LexOthers.cxx, src/LexTADS3.cxx, src/PropSet.cxx, src/RESearch.cxx, src/RESearch.h, src/SplitVector.h, vcbuild/SciLexer.dsp, version.txt, win32/PlatWin.cxx, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak: Merged Scintilla v1.73. [2936af6fc62d] 2007-03-18 phil * Makefile, Python/sip/qscilexerd.sip, Python/sip/qscimodcommon.sip, Python/sip/qsciscintillabase.sip, qt/qscilexerd.cpp, qt/qscilexerd.h, qt/qscintilla.pro, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_pt_br.ts, qt/qscintilla_ru.ts: Switched the internal build system to Qt v4.2.3. Added the D lexer support from Detlev. [667e9b81ab4f] 2007-03-04 phil * Makefile, example-Qt4/mainwindow.cpp, qt/PlatQt.cpp, qt/qsciscintilla.cpp: Fixed a bug in default font handling. Removed use of QIODevice::Text in the example as it is unnecessary and a performance hog. Moved the internal Qt3 build system to Qt v3.3.8. Auto-indentation should now work (as badly) as it did with QScintilla v1. [4d3ad4d1f295] 2007-01-17 phil * Python/sip/qsciapis.sip, qt/qsciapis.cpp, qt/qsciapis.h: Added defaultPreparedName() to QsciAPIs. [2a3c872122dd] * designer-Qt4/qscintillaplugin.cpp: Fixed the Qt4 Designer plugin include file value. [ea7cb8634ad2] 2007-01-16 phil * Python/sip/qsciapis.sip, qt/qsciapis.cpp, qt/qsciapis.h: Added cancelPreparation() and apiPreparationCancelled() to QsciAPIs. [2d7dd00e3bc0] * Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, build.py, lib/LICENSE.commercial.short, lib/LICENSE.gpl.short, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Updated the copyright notices. Added selectionToEol() and setSelectionToEol() to QsciScintilla. Added the other 1.72 changes to the low level API. [ddcf2d43cf31] * doc/SciBreak.jpg, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/index.html, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/makefile, gtk/scintilla.mak, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, qt/ScintillaQt.h, src/CellBuffer.cxx, src/CellBuffer.h, src/ContractionState.cxx, src/Document.cxx, src/Document.h, src/DocumentAccessor.cxx, src/Editor.cxx, src/Editor.h, src/KeyWords.cxx, src/LexCPP.cxx, src/LexD.cxx, src/LexGen.py, src/LexHTML.cxx, src/LexInno.cxx, src/LexLua.cxx, src/LexMatlab.cxx, src/LexNsis.cxx, src/LexOthers.cxx, src/LexRuby.cxx, src/LexTADS3.cxx, src/Partitioning.h, src/ScintillaBase.cxx, src/SplitVector.h, src/StyleContext.h, src/ViewStyle.cxx, src/ViewStyle.h, vcbuild/SciLexer.dsp, version.txt, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak: Merged Scintilla v1.72, but any new features are not yet exploited. [dcdfde9050a2] 2007-01-09 phil * Python/configure.py: Fixed bug in configure.py when the -p flag wasn't specified. [50dc69f2b20d] 2007-01-04 phil * Python/configure.py, Python/sip/qscilexer.sip, qt/qsciapis.cpp, qt/qsciapis.h, qt/qsciscintilla.cpp: Backported to Qt v3. Note that this will probably break again in the future when call tips are redone. [3bcc4826fc73] 2007-01-02 phil * Python/configure.py, lib/gen_python_api.py, qsci/api/python/Python-2.4.api, qsci/api/python/Python-2.5.api, qt/qsciapis.cpp: Added the Python v2.4 and v2.5 API files. Added the generation of the QScintilla2.api file. [49beb92ca721] 2007-01-01 phil * Python/sip/qsciscintilla.sip, qt/qscilexer.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added autoCompletionFillupsEnabled() and setAutoCompletionFillupsEnabled() to QsciScintilla. Updated the Python bindings. [7aa946010e9d] * Python/sip/qsciapis.sip, qt/qsciapis.cpp, qt/qsciapis.h: Implemented loadPrepared() and savePrepared() in QsciAPIs. Added isPrepared() to QsciAPIs. Updated the Python bindings. [4c5e3d80fec7] * Python/sip/qsciapis.sip, qt/qsciapis.cpp, qt/qsciapis.h: Added installAPIFiles() and stubs for loadPrepared() and savePrepared() to QsciAPIs. [93f4dd7222a1] * Python/sip/qsciapis.sip: Added the missing qsciapis.sip file. [064b524acc93] * Python/sip/qscilexer.sip, Python/sip/qscimodcommon.sip, lib/qscintilla.dxy, qt/qsciapis.cpp, qt/qsciapis.h, qt/qscilexer.cpp, qt/qscilexer.h: Fixed the generation of the API documentation. Added apis() and setAPIs() to QsciLexer. Removed apiAdd(), apiClear(), apiLoad(), apiRemove(), apiProcessingStarted() and apiProcessingFinished() from QsciLexer. Added apiPreparationStarted() and apiPreparationFinished() to QsciAPIs. Made QsciAPIs part of the API again. Updated the Python bindings. [851d133b12ff] 2006-12-20 phil * Makefile, qt/qsciapis.cpp, qt/qsciapis.h: Updated the internal build system to Qt v4.2.2. More work on auto- completion. [d4542220e7a2] 2006-11-26 phil * qt/ListBoxQt.cpp, qt/ListBoxQt.h, qt/qsciapis.cpp, qt/qsciapis.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: More work on the auto-completion code. [37b2d0d2b154] 2006-11-22 phil * qt/qsciapis.cpp, qt/qsciapis.h, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscilexerbatch.cpp, qt/qscilexerbatch.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Changed the handling of case sensitivity in auto-completion lists. Lexers now say if they are case sensitive. [b1932fba61ec] 2006-11-17 phil * Makefile, Python/configure.py, Python/sip/qscicommand.sip, Python/sip/qscicommandset.sip, Python/sip/qscidocument.sip, Python/sip/qscilexer.sip, Python/sip/qscilexerbash.sip, Python/sip/qscilexerbatch.sip, Python/sip/qscilexercpp.sip, Python/sip/qscilexercsharp.sip, Python/sip/qscilexercss.sip, Python/sip/qscilexerdiff.sip, Python/sip/qscilexerhtml.sip, Python/sip/qscilexeridl.sip, Python/sip/qscilexerjava.sip, Python/sip/qscilexerjavascript.sip, Python/sip/qscilexerlua.sip, Python/sip/qscilexermakefile.sip, Python/sip/qscilexerperl.sip, Python/sip/qscilexerpov.sip, Python/sip/qscilexerproperties.sip, Python/sip/qscilexerpython.sip, Python/sip/qscilexerruby.sip, Python/sip/qscilexersql.sip, Python/sip/qscilexertex.sip, Python/sip/qscimacro.sip, Python/sip/qsciprinter.sip, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase.sip, TODO, build.py, designer-Qt3/qscintillaplugin.cpp, designer- Qt4/qscintillaplugin.cpp, example-Qt3/application.cpp, example- Qt4/mainwindow.cpp, qt/PlatQt.cpp, qt/ScintillaQt.cpp, qt/qsciapis.cpp, qt/qsciapis.h, qt/qscicommand.cpp, qt/qscicommand.h, qt/qscicommandset.cpp, qt/qscicommandset.h, qt/qscidocument.cpp, qt/qscidocument.h, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscilexerbash.cpp, qt/qscilexerbash.h, qt/qscilexerbatch.cpp, qt/qscilexerbatch.h, qt/qscilexercpp.cpp, qt/qscilexercpp.h, qt/qscilexercsharp.cpp, qt/qscilexercsharp.h, qt/qscilexercss.cpp, qt/qscilexercss.h, qt/qscilexerdiff.cpp, qt/qscilexerdiff.h, qt/qscilexerhtml.cpp, qt/qscilexerhtml.h, qt/qscilexeridl.cpp, qt/qscilexeridl.h, qt/qscilexerjava.cpp, qt/qscilexerjava.h, qt/qscilexerjavascript.cpp, qt/qscilexerjavascript.h, qt/qscilexerlua.cpp, qt/qscilexerlua.h, qt/qscilexermakefile.cpp, qt/qscilexermakefile.h, qt/qscilexerperl.cpp, qt/qscilexerperl.h, qt/qscilexerpov.cpp, qt/qscilexerpov.h, qt/qscilexerproperties.cpp, qt/qscilexerproperties.h, qt/qscilexerpython.cpp, qt/qscilexerpython.h, qt/qscilexerruby.cpp, qt/qscilexerruby.h, qt/qscilexersql.cpp, qt/qscilexersql.h, qt/qscilexertex.cpp, qt/qscilexertex.h, qt/qscimacro.cpp, qt/qscimacro.h, qt/qscintilla.pro, qt/qsciprinter.cpp, qt/qsciprinter.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Fixed the name of the generated source packages. Reorganised so that the header files are in a separate sub-directory. Updated the designer plugins and examples for the changing in header file structure. More work on autocompletion. Basic functionality is there, but no support for the "current context" yet. [312e74140bb8] 2006-11-04 phil * designer-Qt4/qscintillaplugin.cpp: Designer plugin fixes for Qt4 from DavidB. [920f7af8bec6] 2006-11-03 phil * qt/qscilexer.cpp: Fixed QsciLexer::setPaper() so that it also sets the background colour of the default style. [fcab00732d97] 2006-10-21 phil * Makefile, qt/qsciapis.cpp, qt/qsciapis.h, qt/qsciscintilla.cpp: Switched the internal build system to Qt v3.3.7 and v4.2.1. Portability fixes for Qt3. [512b57958ea4] 2006-10-20 phil * Makefile, build.py, include/Platform.h, lib/README.doc, qt/PlatQt.cpp, qt/qscimacro.cpp, qt/qscintilla.pro, qt/qsciscintilla.cpp: Renamed the base package QScintilla2. Platform portability fixes from Ulli. The qsci data directory is now installed (where API files will be kept). [2a61d65842fb] 2006-10-13 phil * Python/sip/qsciscintilla.sip, qt/qscintilla.pro, qt/qscintilla_pt_br.qm, qt/qscintilla_pt_br.ts, qt/qscintilla_ptbr.qm, qt/qscintilla_ptbr.ts, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added QsciScintilla::linesChanged() from Detlev. Removed QsciScintilla::markerChanged(). Renamed the Brazilian Portugese translation files. [5b23de72e063] * Makefile, Python/sip/qscilexer.sip, qt/ListBoxQt.cpp, qt/ListBoxQt.h, qt/ScintillaQt.cpp, qt/qsciapis.cpp, qt/qsciapis.h, qt/qscilexer.cpp, qt/qscilexer.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added apiRemove(), apiProcessingStarted() and apiProcessingFinished() to QsciLexer. [ef2cb95b868a] 2006-10-08 phil * qt/qsciscintilla.cpp, qt/qsciscintilla.h: Reset the text and paper colours and font when removing a lexer. [08ac85b34d80] * qt/qsciscintilla.cpp: Fixed Qt3 specific problem with most recent changes. [e4ba06e01a1e] 2006-10-06 phil * Python/sip/qsciapis.sip, Python/sip/qscilexer.sip, Python/sip/qscimodcommon.sip, Python/sip/qsciscintilla.sip, qt/ListBoxQt.cpp, qt/SciClasses.cpp, qt/qsciapis.cpp, qt/qsciapis.h, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscilexerbash.cpp, qt/qscilexerbash.h, qt/qscilexerbatch.cpp, qt/qscilexerbatch.h, qt/qscilexercpp.cpp, qt/qscilexercpp.h, qt/qscilexercsharp.h, qt/qscilexercss.cpp, qt/qscilexercss.h, qt/qscilexerdiff.cpp, qt/qscilexerdiff.h, qt/qscilexerhtml.cpp, qt/qscilexerhtml.h, qt/qscilexeridl.h, qt/qscilexerjavascript.h, qt/qscilexerlua.cpp, qt/qscilexerlua.h, qt/qscilexermakefile.cpp, qt/qscilexermakefile.h, qt/qscilexerperl.cpp, qt/qscilexerperl.h, qt/qscilexerpov.cpp, qt/qscilexerpov.h, qt/qscilexerproperties.cpp, qt/qscilexerproperties.h, qt/qscilexerpython.cpp, qt/qscilexerpython.h, qt/qscilexerruby.cpp, qt/qscilexerruby.h, qt/qscilexersql.cpp, qt/qscilexersql.h, qt/qscilexertex.cpp, qt/qscilexertex.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Made QsciAPIs an internal class and instead added apiAdd(), apiClear() and apiLoad() to QsciLexer. Replaced setAutoCompletionStartCharacters() with setAutoCompletionWordSeparators() in QsciScintilla. Removed autoCompletionFillupsEnabled(), setAutoCompletionFillupsEnabled(), setAutoCompletionAPIs() and setCallTipsAPIs() from QsciScintilla. Added AcsNone to QsciScintilla::AutoCompletionSource. Horizontal scrollbars are displayed as needed in autocompletion lists. Added QsciScintilla::lexer(). Fixed setFont(), setColor(), setEolFill() and setPaper() in QsciLexer so that they handle all styles as documented. Removed all occurences of QString::null. Fixed the problem with indentation guides not changing when the size of a space changed. Added the QsciScintilla::markerChanged() signal. Updated the Python bindings. [9ae22e152365] 2006-10-01 phil * qt/PlatQt.cpp: Fixed a silly line drawing bug. [0f9f5c22421a] 2006-09-30 phil * qt/qscintilla.pro: Fixes for building on Windows and MacOS/X. [c16bc6aeba20] 2006-09-29 phil * example-Qt4/application.pro, qt/PlatQt.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.cpp: Fixed the documentation bug in QsciScintilla::insert(). Fixed the mouse shape changing properly. Fixed the drawing of fold markers. [08af64d93094] 2006-09-23 phil * lib/README: Improved the README for the pedants amongst us. [683bdb9a84fc] * designer-Qt4/designer.pro, designer-Qt4/qscintillaplugin.cpp, designer-Qt4/qscintillaplugin.h: The Qt4 Designer plugin now loads - thanks to DavidB. [feb5a3618df6] 2006-09-16 phil * build.py, designer-Qt3/designer.pro, designer- Qt3/qscintillaplugin.cpp, designer-Qt4/designer.pro, designer- Qt4/qscintillaplugin.cpp, designer/designer.pro, designer/qscintillaplugin.cpp, lib/README.doc, qt/qsciscintilla.h: Fixed the Qt3 designer plugin. Added the Qt4 designer plugin based on Andrius Ozelis's work. (But it doesn't load for me - does anybody else have a problem?) [3a0873ed5ff0] 2006-09-09 phil * Python/sip/qsciscintilla.sip, qt/qsciscintilla.cpp, qt/qsciscintilla.h: QsciScintilla's setFont(), setColor() and setPaper() now work as expected when there is no lexer (and have no effect if there is a lexer). [65cc713d9ecb] 2006-08-28 phil * qt/ListBoxQt.cpp, qt/PlatQt.cpp: Fixed a crash when double-clicking on an auto-completion list entry. [d8eecfc59ca2] 2006-08-27 phil * Python/sip/qsciscintillabase.sip, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/index.html, gtk/Converter.h, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, qt/ScintillaQt.cpp, qt/qsciscintillabase.h, src/Editor.cxx, src/LexCPP.cxx, src/LexPerl.cxx, src/LexVB.cxx, src/StyleContext.h, version.txt, win32/ScintRes.rc, win32/ScintillaWin.cxx: Merged Scintilla v1.71. The SCN_DOUBLECLICK() signal now passes the line and position of the click. [81c852fed943] 2006-08-17 phil * Python/sip/qsciscintilla.sip, qt/ScintillaQt.cpp: Fixed pasting when Unicode mode is set. [9d4a7ccef6f4] * build.py: Fixed the internal build system leaving SVN remnants around. [96c36a0e94ac] 2006-07-30 phil * NEWS, Python/sip/qsciscintilla.sip, qt/qscicommand.h, qt/qscicommandset.h, qt/qsciscintilla.cpp, qt/qsciscintilla.h: Added autoCompletionFillupsEnabled() and setAutoCompletionFillupsEnabled() to QsciScintilla. Don't auto- complete numbers. Removed QsciCommandList. [e9886e5da7c3] 2006-07-29 phil * lib/README.doc, qt/PlatQt.cpp: Debugged the Qt3 backport - all seems to work. [1e743e050599] * Python/configure.py, Python/sip/qscimod3.sip, Python/sip/qsciscintillabase.sip, Python/sip/qsciscintillabase4.sip, build.py, lib/README, lib/README.doc, lib/qscintilla.dxy, qt/qsciscintillabase.h: The PyQt3 bindings now work. Updated the documentation and build system for both Qt3 and Qt4. [f4fa8a9a35c0] 2006-07-28 phil * Python/sip/qscimodcommon.sip, Python/sip/qsciscintillabase4.sip, Python/sip/qscitypes.sip, example-Qt3/application.cpp, example- Qt3/application.h, example-Qt3/application.pro, qt/qscicommand.cpp, qt/qscicommandset.cpp, qt/qscidocument.cpp, qt/qscimacro.cpp, qt/qscintilla.pro, qt/qsciprinter.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h, qt/qscitypes.h: Backed out the QscoTypes namespace now that the Qt3/4 source code has been consolidated. [372c37fa8b9c] * qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_ptbr.ts, qt/qscintilla_ru.ts, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h, qt/qsciscintillabase3.cpp, qt/qsciscintillabase3.h, qt/qsciscintillabase4.cpp, qt/qsciscintillabase4.h: Integated the Qt3 and Qt4 source files. [4ee1fcf04cd9] * Makefile, build.py, lib/README.doc, lib/qscintilla.dxy, qt/qscintilla.pro, qt/qsciscintillabase.h, qt/qsciscintillabase3.cpp, qt/qsciscintillabase3.h, qt/qsciscintillabase4.cpp, qt/qsciscintillabase4.h: The Qt3 port now compiles, but otherwise untested. [da227e07e729] * Python/sip/qscimacro.sip, lib/README.doc, lib/qscintilla.dxy, qt/PlatQt.cpp, qt/qscilexermakefile.cpp, qt/qscimacro.cpp, qt/qscimacro.h, qt/qscintilla.pro, qt/qsciscintillabase.h, qt/qsciscintillabase3.cpp, qt/qsciscintillabase3.h, qt/qsciscintillabase4.cpp, qt/qsciscintillabase4.h: Changes to QsciMacro so that it has a more consistent API across Qt3 and Qt4. Backported to Qt3 - doesn't yet build because Qt3 qmake doesn't understand the preprocessor. [910b415ec4a8] 2006-07-27 phil * build.py, designer/qscintillaplugin.cpp, example-Qt3/README, example-Qt4/README, lib/README, lib/README.doc, lib/qscintilla.dxy, qt/qscintilla.pro: Updated the documentation. [7774f3e87003] 2006-07-26 phil * Makefile, Python/configure.py, Python/qsciapis.sip, Python/qscicommand.sip, Python/qscicommandset.sip, Python/qscidocument.sip, Python/qscilexer.sip, Python/qscilexerbash.sip, Python/qscilexerbatch.sip, Python/qscilexercpp.sip, Python/qscilexercsharp.sip, Python/qscilexercss.sip, Python/qscilexerdiff.sip, Python/qscilexerhtml.sip, Python/qscilexeridl.sip, Python/qscilexerjava.sip, Python/qscilexerjavascript.sip, Python/qscilexerlua.sip, Python/qscilexermakefile.sip, Python/qscilexerperl.sip, Python/qscilexerpov.sip, Python/qscilexerproperties.sip, Python/qscilexerpython.sip, Python/qscilexerruby.sip, Python/qscilexersql.sip, Python/qscilexertex.sip, Python/qscimacro.sip, Python/qscimod4.sip, Python/qscimodcommon.sip, Python/qsciprinter.sip, Python/qsciscintilla.sip, Python/qsciscintillabase4.sip, Python/qscitypes.sip, Python/sip/qsciapis.sip, Python/sip/qscicommand.sip, Python/sip/qscicommandset.sip, Python/sip/qscidocument.sip, Python/sip/qscilexer.sip, Python/sip/qscilexerbash.sip, Python/sip/qscilexerbatch.sip, Python/sip/qscilexercpp.sip, Python/sip/qscilexercsharp.sip, Python/sip/qscilexercss.sip, Python/sip/qscilexerdiff.sip, Python/sip/qscilexerhtml.sip, Python/sip/qscilexeridl.sip, Python/sip/qscilexerjava.sip, Python/sip/qscilexerjavascript.sip, Python/sip/qscilexerlua.sip, Python/sip/qscilexermakefile.sip, Python/sip/qscilexerperl.sip, Python/sip/qscilexerpov.sip, Python/sip/qscilexerproperties.sip, Python/sip/qscilexerpython.sip, Python/sip/qscilexerruby.sip, Python/sip/qscilexersql.sip, Python/sip/qscilexertex.sip, Python/sip/qscimacro.sip, Python/sip/qscimod4.sip, Python/sip/qscimodcommon.sip, Python/sip/qsciprinter.sip, Python/sip/qsciscintilla.sip, Python/sip/qsciscintillabase4.sip, Python/sip/qscitypes.sip, build.py, lib/LICENSE.edu, lib/LICENSE.edu.short, lib/README.MacOS: Changed the build system to add the Python bindings. [8a56c38c418b] * Python/configure.py, Python/qscicommandset.sip, Python/qscilexerruby.sip, Python/qscilexertex.sip, Python/qscimod4.sip, Python/qsciscintilla.sip, Python/qsciscintillabase4.sip, Python/qscitypes.sip: Debugged the Python bindings - not yet part of the snapshots. [8e348d9c7d38] 2006-07-25 phil * Python/qsciapis.sip, Python/qscicommand.sip, Python/qscicommandset.sip, Python/qscidocument.sip, Python/qscilexer.sip, Python/qscilexerbash.sip, Python/qscilexerbatch.sip, Python/qscilexercpp.sip, Python/qscilexercsharp.sip, Python/qscilexercss.sip, Python/qscilexerdiff.sip, Python/qscilexerhtml.sip, Python/qscilexeridl.sip, Python/qscilexerjava.sip, Python/qscilexerjavascript.sip, Python/qscilexerlua.sip, Python/qscilexermakefile.sip, Python/qscilexerperl.sip, Python/qscilexerpov.sip, Python/qscilexerproperties.sip, Python/qscilexerpython.sip, Python/qscilexerruby.sip, Python/qscilexersql.sip, Python/qscilexertex.sip, Python/qscimacro.sip, Python/qscimod4.sip, Python/qscimodcommon.sip, Python/qsciprinter.sip, Python/qsciscintilla.sip, Python/qsciscintillabase4.sip, Python/qscitypes.sip, qt/qsciapis.h, qt/qsciglobal.h, qt/qscilexer.h, qt/qscilexerbash.h, qt/qscilexercpp.h, qt/qscilexerperl.h, qt/qscilexerpython.h, qt/qscilexersql.h, qt/qsciprinter.h, qt/qsciscintilla.h: Ported the .sip files from v1. (Not yet part of the snapshot.) [c03807f9fbab] * Makefile, qt/qscintilla-Qt4.pro, qt/qscintilla.pro: The .pro file should now work with both Qt v3 and v4. [c99aec4ce73d] * Makefile, qt/qscintilla-Qt4.pro, qt/qscintilla.pro, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h, qt/qsciscintillabase4.cpp, qt/qsciscintillabase4.h: Some file reorganisation for when the backport to Qt3 is done. [c97fb1bdc0e5] * qt/qscicommand.cpp, qt/qscicommandset.cpp, qt/qscidocument.cpp, qt/qscimacro.cpp, qt/qscintilla.pro, qt/qsciprinter.cpp, qt/qsciscintilla.cpp, qt/qsciscintilla.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h, qt/qscitypes.h: Moved the Scintilla API enums out of QsciScintillaBase and into the new QsciTypes namespace. [6de0ac19e4df] * qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Triple clicking now works. [8ef632d89147] 2006-07-23 phil * qt/qsciscintillabase.cpp: Fixed incorrect selection after dropping text. [4c62275c39f4] * qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qsciscintillabase.cpp: Dropping text seems (mostly) to work. [7acc97948229] 2006-07-22 phil * qt/PlatQt.cpp, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Scrollbars now work. The context menu now works. The clipboard and mouse selection now works. Dragging to external windows now works (but not dropping). [73995ec258cd] 2006-07-18 phil * example-Qt4/mainwindow.cpp, example-Qt4/mainwindow.h, qt/PlatQt.cpp, qt/qextscintillalexerbash.cxx, qt/qextscintillalexerbash.h, qt/qextscintillalexerbatch.cxx, qt/qextscintillalexerbatch.h, qt/qextscintillalexercpp.cxx, qt/qextscintillalexercpp.h, qt/qextscintillalexercsharp.cxx, qt/qextscintillalexercsharp.h, qt/qextscintillalexercss.cxx, qt/qextscintillalexercss.h, qt/qextscintillalexerdiff.cxx, qt/qextscintillalexerdiff.h, qt/qextscintillalexerhtml.cxx, qt/qextscintillalexerhtml.h, qt/qextscintillalexeridl.cxx, qt/qextscintillalexeridl.h, qt/qextscintillalexerjava.cxx, qt/qextscintillalexerjava.h, qt/qextscintillalexerjavascript.cxx, qt/qextscintillalexerjavascript.h, qt/qextscintillalexerlua.cxx, qt/qextscintillalexerlua.h, qt/qextscintillalexermakefile.cxx, qt/qextscintillalexermakefile.h, qt/qextscintillalexerperl.cxx, qt/qextscintillalexerperl.h, qt/qextscintillalexerpov.cxx, qt/qextscintillalexerpov.h, qt/qextscintillalexerproperties.cxx, qt/qextscintillalexerproperties.h, qt/qextscintillalexerpython.cxx, qt/qextscintillalexerpython.h, qt/qextscintillalexerruby.cxx, qt/qextscintillalexerruby.h, qt/qextscintillalexersql.cxx, qt/qextscintillalexersql.h, qt/qextscintillalexertex.cxx, qt/qextscintillalexertex.h, qt/qextscintillamacro.cxx, qt/qextscintillamacro.h, qt/qextscintillaprinter.cxx, qt/qextscintillaprinter.h, qt/qsciapis.h, qt/qscicommand.h, qt/qscilexer.h, qt/qscilexerbash.cpp, qt/qscilexerbash.h, qt/qscilexerbatch.cpp, qt/qscilexerbatch.h, qt/qscilexercpp.cpp, qt/qscilexercpp.h, qt/qscilexercsharp.cpp, qt/qscilexercsharp.h, qt/qscilexercss.cpp, qt/qscilexercss.h, qt/qscilexerdiff.cpp, qt/qscilexerdiff.h, qt/qscilexerhtml.cpp, qt/qscilexerhtml.h, qt/qscilexeridl.cpp, qt/qscilexeridl.h, qt/qscilexerjava.cpp, qt/qscilexerjava.h, qt/qscilexerjavascript.cpp, qt/qscilexerjavascript.h, qt/qscilexerlua.cpp, qt/qscilexerlua.h, qt/qscilexermakefile.cpp, qt/qscilexermakefile.h, qt/qscilexerperl.cpp, qt/qscilexerperl.h, qt/qscilexerpov.cpp, qt/qscilexerpov.h, qt/qscilexerproperties.cpp, qt/qscilexerproperties.h, qt/qscilexerpython.cpp, qt/qscilexerpython.h, qt/qscilexerruby.cpp, qt/qscilexerruby.h, qt/qscilexersql.cpp, qt/qscilexersql.h, qt/qscilexertex.cpp, qt/qscilexertex.h, qt/qscimacro.cpp, qt/qscimacro.h, qt/qscintilla.pro, qt/qsciprinter.cpp, qt/qsciprinter.h, qt/qsciscintilla.h: Ported the rest of the API to Qt4. Finished porting the example to Qt4. [de0ede6bbcf5] 2006-07-17 phil * qt/qextscintilla.cxx, qt/qextscintilla.h, qt/qextscintillaapis.cxx, qt/qextscintillaapis.h, qt/qextscintillacommand.cxx, qt/qextscintillacommand.h, qt/qextscintillacommandset.cxx, qt/qextscintillacommandset.h, qt/qextscintilladocument.cxx, qt/qextscintilladocument.h, qt/qextscintillalexer.cxx, qt/qextscintillalexer.h, qt/qsciapis.cpp, qt/qsciapis.h, qt/qscicommand.cpp, qt/qscicommand.h, qt/qscicommandset.cpp, qt/qscicommandset.h, qt/qscidocument.cpp, qt/qscidocument.h, qt/qscilexer.cpp, qt/qscilexer.h, qt/qscintilla.pro, qt/qsciscintilla.cpp, qt/qsciscintilla.h: More porting to Qt4 - just the lexers remaining. [07158797bcf2] * qt/ListBoxQt.cpp, qt/PlatQt.cpp, qt/SciClasses.cpp, qt/ScintillaQt.cpp, qt/qscintilla.pro, qt/qsciscintillabase.cpp: Further Qt4 changes so that Q3Support is no longer needed. [cb3ca2aee49e] * qt/ListBoxQt.cpp, qt/ListBoxQt.h, qt/PlatQt.cpp, qt/SciClasses.cpp, qt/SciClasses.h, qt/SciListBox.cxx, qt/SciListBox.h, qt/ScintillaQt.cpp, qt/ScintillaQt.h, qt/qscintilla.pro, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Ported the auto-completion list implementation to Qt4. [1d0d07f7ba3b] 2006-07-16 phil * qt/PlatQt.cpp, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Drawing now seems Ok. Keyboard support now seems Ok. Start of the mouse support. [20a223c3f57e] 2006-07-12 phil * include/Platform.h, qt/PlatQt.cpp, qt/ScintillaQt.cpp: Painting now seems to happen only within paint events - but incorrectly. [a60a10298391] * qt/PlatQt.cpp, qt/PlatQt.cxx, qt/ScintillaQt.cpp, qt/ScintillaQt.cxx, qt/ScintillaQt.h, qt/qscintilla.pro: Recoded the implementation of surfaces so that painters are only active during paint events. Not yet debugged. [d0d91ae8e514] * build.py, qt/PlatQt.cxx, qt/ScintillaQt.cxx, qt/ScintillaQt.h, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Recoded the handling of key presses so that it doesn't use any Qt3 specific features and should be backported to QScintilla v1. It also should work better in Unicode mode. [c2b96d686ee6] 2006-07-11 phil * Makefile, build.py, example-Qt3/README, example-Qt3/application.cpp, example-Qt3/application.h, example-Qt3/application.pro, example- Qt3/fileopen.xpm, example-Qt3/fileprint.xpm, example- Qt3/filesave.xpm, example-Qt3/main.cpp, example-Qt4/README, example- Qt4/application.pro, example-Qt4/application.qrc, example- Qt4/images/copy.png, example-Qt4/images/cut.png, example- Qt4/images/new.png, example-Qt4/images/open.png, example- Qt4/images/paste.png, example-Qt4/images/save.png, example- Qt4/main.cpp, example-Qt4/mainwindow.cpp, example-Qt4/mainwindow.h, example/README, example/application.cpp, example/application.h, example/application.pro, example/fileopen.xpm, example/fileprint.xpm, example/filesave.xpm, example/main.cpp, qt/PlatQt.cxx, qt/SciListBox.cxx, qt/SciListBox.h, qt/ScintillaQt.cxx, qt/ScintillaQt.h, qt/qextscintilla.cxx, qt/qextscintillabase.cxx, qt/qextscintillabase.h, qt/qextscintillaglobal.h, qt/qsciglobal.h, qt/qscintilla.pro, qt/qsciscintillabase.cpp, qt/qsciscintillabase.h: Whole raft of changes starting QScintilla2. [7f0bd20f2f83] 2006-07-09 phil * qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_fr.ts, qt/qscintilla_ptbr.ts, qt/qscintilla_ru.ts: Updated translations from Detlev. [c04c167d802e] 2006-07-08 phil * NEWS, qt/qextscintilla.cxx, qt/qextscintilla.h: Added QextScintilla::isCallTipActive(). [1f7dcb40db25] * lib/LICENSE.commercial.short, lib/LICENSE.edu.short, lib/LICENSE.gpl.short, qt/qextscintilla.cxx: Changed the autoindentation to be slightly cleverer when handling Python. If a lexer does not define block end words then a block start word is ignored unless it is the last significant word in a line. [d5813c13f5da] 2006-07-02 phil * qt/PlatQt.cxx: Possibly fixed a possible problem with double clicking under Windows. [271141bb2b43] * NEWS, qt/ScintillaQt.cxx, qt/qextscintilla.cxx, qt/qextscintilla.h: Added setWrapVisualFlags(), WrapMode::WrapCharacter, WrapVisualFlag to QextScintilla. The layout cache is now set according to the wrap mode. Setting a wrap mode now disables the horizontal scrollbar. [a498b86e7999] 2006-07-01 phil * NEWS, qt/qextscintilla.cxx, qt/qextscintilla.h: Added cancelList(), firstVisibleLine(), isListActive(), showUserList(), textHeight() and userListActivated() to QextScintilla. [058c7be4bdfe] * qt/qextscintilla.cxx: Auto-completion changed so that subsequent start characters cause the list to be re-created (containing a subset of the previous one). [5b534658e638] 2006-06-28 phil * NEWS, qt/SciListBox.cxx, qt/qextscintilla.cxx, qt/qextscintilla.h, qt/qextscintillaapis.cxx, qt/qextscintillaapis.h, qt/qextscintillalexer.cxx, qt/qextscintillalexer.h, qt/qextscintillalexerpython.cxx, qt/qextscintillalexerpython.h: Handle Key_Enter the same as Key_Return. QextScintilla::foldAll() can now optionally fold all child fold points. Added autoCompleteFromAll() and setAutoCompletionStartCharacters() to QextScintilla. Vastly improved the way auto-completion and call tips work. [8b0472aaed61] 2006-06-25 phil * qt/qextscintilla.cxx, qt/qextscintillabase.cxx, qt/qextscintillalexer.cxx: The default fore and background colours now default to the application palette rather than being hardcoded to black and white. [6cb6b5bef5fc] * NEWS, qt/qextscintilla.cxx, qt/qextscintilla.h, qt/qextscintillalexer.cxx, qt/qextscintillalexer.h: Added defaultColor() and setDefaultColor() to QextScintillaLexer. Added color() and setColor() to QextScintilla. Renamed eraseColor() and setEraseColor() to paper() and setPaper() in QextScintilla. [c1fbfc192235] * NEWS, qt/SciListBox.cxx, qt/qextscintilla.cxx, qt/qextscintilla.h, qt/qextscintillaapis.cxx, qt/qextscintillaapis.h, qt/qextscintillabase.h, qt/qextscintillalexer.cxx, qt/qextscintillalexer.h: Added a couple of extra SendScintilla overloads. One is needed for PyQt because of the change in SIP's handling of unsigned values. The other is needed to solve C++ problems caused by the first. Autocompletion list entries from APIs may now contain spaces. Added defaultPaper() and setDefaultPaper() to QextScintillaLexer. Added eraseColor() and setEraseColor() to QextScintilla. [34f527ca0f99] 2006-06-21 phil * qt/qextscintilla.cxx, qt/qextscintillalexer.cxx, qt/qextscintillalexer.h, qt/qextscintillalexerhtml.cxx, qt/qextscintillalexerhtml.h: Removed QextScintillaLexer::styleBits() now that SCI_GETSTYLEBITSNEEDED is available. [1c6837500560] * NEWS, qt/PlatQt.cxx, qt/qextscintilla.cxx, qt/qextscintilla.h: QextScintilla::setSelectionBackgroundColor(), QextScintilla::setMarkerBackgroundColor() and QextScintilla::setCaretLineBackgroundColor() now respect the alpha component. [48bae1fffe85] 2006-06-20 phil * NEWS, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/index.html, gtk/Converter.h, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, include/Scintilla.h, include/Scintilla.iface, qt/qextscintillabase.h, qt/qextscintillalexerpython.h, src/Editor.cxx, src/Editor.h, src/ViewStyle.cxx, src/ViewStyle.h, version.txt, win32/ScintRes.rc, win32/ScintillaWin.cxx: Merged Scintilla v1.70. [03ac3edd5dd2] 2006-06-19 phil * qt/qextscintillabase.h, qt/qextscintillalexerlua.h, qt/qextscintillalexerruby.cxx, qt/qextscintillalexerruby.h, qt/qextscintillalexersql.h: Significant, and incompatible, updates to the QextScintillaLexerRuby class. [0484fe132d0c] * src/PropSet.cxx: Fix for qsort helpers linkage from Ulli. (Patch sent upstream.) [2307adf67045] 2006-06-18 phil * qt/qextscintillalexerpython.cxx, qt/qextscintillalexerpython.h: Ctrl-D is now duplicate selection rather than duplicate line. Updated the Python lexer to add support for hightlighted identifiers and decorators. [52ca24a722ac] * qt/qextscintillabase.h, qt/qextscintillacommandset.cxx, qt/qextscintillalexer.h, qt/qextscintillalexerbash.h, qt/qextscintillalexerbatch.h, qt/qextscintillalexercpp.h, qt/qextscintillalexercsharp.h, qt/qextscintillalexercss.h, qt/qextscintillalexerhtml.h, qt/qextscintillalexeridl.h, qt/qextscintillalexerjava.h, qt/qextscintillalexerjavascript.h, qt/qextscintillalexerlua.h, qt/qextscintillalexerperl.h, qt/qextscintillalexerpov.h, qt/qextscintillalexerpython.h, qt/qextscintillalexerruby.h, qt/qextscintillalexersql.h, qt/qextscintillalexertex.h, qt/qscintilla.pro: Added the Scintilla 1.69 extensions to the low level API. [e89b98aaaa33] * .repoman, build.py, doc/Icons.html, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/ScintillaToDo.html, doc/index.html, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/deps.mak, gtk/makefile, gtk/scintilla.mak, include/HFacer.py, include/KeyWords.h, include/Platform.h, include/PropSet.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, include/ScintillaWidget.h, qt/PlatQt.cxx, qt/ScintillaQt.h, qt/qscintilla.pro, src/CallTip.cxx, src/CallTip.h, src/CellBuffer.cxx, src/CellBuffer.h, src/CharClassify.cxx, src/CharClassify.h, src/ContractionState.cxx, src/Document.cxx, src/Document.h, src/DocumentAccessor.cxx, src/Editor.cxx, src/Editor.h, src/ExternalLexer.cxx, src/Indicator.cxx, src/KeyMap.cxx, src/KeyWords.cxx, src/LexAU3.cxx, src/LexBash.cxx, src/LexBasic.cxx, src/LexCPP.cxx, src/LexCaml.cxx, src/LexCsound.cxx, src/LexEiffel.cxx, src/LexGen.py, src/LexGui4Cli.cxx, src/LexHTML.cxx, src/LexInno.cxx, src/LexLua.cxx, src/LexMSSQL.cxx, src/LexOpal.cxx, src/LexOthers.cxx, src/LexPOV.cxx, src/LexPython.cxx, src/LexRuby.cxx, src/LexSQL.cxx, src/LexSpice.cxx, src/LexTCL.cxx, src/LexVB.cxx, src/LineMarker.h, src/PropSet.cxx, src/RESearch.cxx, src/RESearch.h, src/ScintillaBase.cxx, src/StyleContext.h, src/ViewStyle.cxx, src/ViewStyle.h, src/XPM.cxx, vcbuild/SciLexer.dsp, version.txt, win32/PlatWin.cxx, win32/ScintRes.rc, win32/ScintillaWin.cxx, win32/deps.mak, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak: Removed the redundant .repoman file. Synced with Scintilla v1.69 with only the minimal changes needed to compile it. [6774f137c5a1] 2006-06-17 phil * .repoman, License.txt, Makefile, NEWS, README, TODO, bin/empty.txt, build.py, delbin.bat, delcvs.bat, designer/designer.pro, designer/qscintillaplugin.cpp, doc/Design.html, doc/Lexer.txt, doc/SciBreak.jpg, doc/SciCoding.html, doc/SciRest.jpg, doc/SciTEIco.png, doc/SciWord.jpg, doc/ScintillaDoc.html, doc/ScintillaDownload.html, doc/ScintillaHistory.html, doc/ScintillaRelated.html, doc/ScintillaToDo.html, doc/ScintillaUsage.html, doc/Steps.html, doc/index.html, example/README, example/application.cpp, example/application.h, example/application.pro, example/fileopen.xpm, example/fileprint.xpm, example/filesave.xpm, example/main.cpp, gtk/Converter.h, gtk/PlatGTK.cxx, gtk/ScintillaGTK.cxx, gtk/deps.mak, gtk/makefile, gtk/scintilla-marshal.c, gtk/scintilla- marshal.h, gtk/scintilla-marshal.list, gtk/scintilla.mak, include/Accessor.h, include/Face.py, include/HFacer.py, include/KeyWords.h, include/Platform.h, include/PropSet.h, include/SString.h, include/SciLexer.h, include/Scintilla.h, include/Scintilla.iface, include/ScintillaWidget.h, include/WindowAccessor.h, lib/LICENSE.commercial, lib/LICENSE.commercial.short, lib/LICENSE.edu, lib/LICENSE.edu.short, lib/LICENSE.gpl, lib/LICENSE.gpl.short, lib/README, lib/README.MacOS, lib/qscintilla.dxy, qt/PlatQt.cxx, qt/SciListBox.cxx, qt/SciListBox.h, qt/ScintillaQt.cxx, qt/ScintillaQt.h, qt/qextscintilla.cxx, qt/qextscintilla.h, qt/qextscintillaapis.cxx, qt/qextscintillaapis.h, qt/qextscintillabase.cxx, qt/qextscintillabase.h, qt/qextscintillacommand.cxx, qt/qextscintillacommand.h, qt/qextscintillacommandset.cxx, qt/qextscintillacommandset.h, qt/qextscintilladocument.cxx, qt/qextscintilladocument.h, qt/qextscintillaglobal.h, qt/qextscintillalexer.cxx, qt/qextscintillalexer.h, qt/qextscintillalexerbash.cxx, qt/qextscintillalexerbash.h, qt/qextscintillalexerbatch.cxx, qt/qextscintillalexerbatch.h, qt/qextscintillalexercpp.cxx, qt/qextscintillalexercpp.h, qt/qextscintillalexercsharp.cxx, qt/qextscintillalexercsharp.h, qt/qextscintillalexercss.cxx, qt/qextscintillalexercss.h, qt/qextscintillalexerdiff.cxx, qt/qextscintillalexerdiff.h, qt/qextscintillalexerhtml.cxx, qt/qextscintillalexerhtml.h, qt/qextscintillalexeridl.cxx, qt/qextscintillalexeridl.h, qt/qextscintillalexerjava.cxx, qt/qextscintillalexerjava.h, qt/qextscintillalexerjavascript.cxx, qt/qextscintillalexerjavascript.h, qt/qextscintillalexerlua.cxx, qt/qextscintillalexerlua.h, qt/qextscintillalexermakefile.cxx, qt/qextscintillalexermakefile.h, qt/qextscintillalexerperl.cxx, qt/qextscintillalexerperl.h, qt/qextscintillalexerpov.cxx, qt/qextscintillalexerpov.h, qt/qextscintillalexerproperties.cxx, qt/qextscintillalexerproperties.h, qt/qextscintillalexerpython.cxx, qt/qextscintillalexerpython.h, qt/qextscintillalexerruby.cxx, qt/qextscintillalexerruby.h, qt/qextscintillalexersql.cxx, qt/qextscintillalexersql.h, qt/qextscintillalexertex.cxx, qt/qextscintillalexertex.h, qt/qextscintillamacro.cxx, qt/qextscintillamacro.h, qt/qextscintillaprinter.cxx, qt/qextscintillaprinter.h, qt/qscintilla.pro, qt/qscintilla_de.qm, qt/qscintilla_de.ts, qt/qscintilla_fr.qm, qt/qscintilla_fr.ts, qt/qscintilla_ptbr.qm, qt/qscintilla_ptbr.ts, qt/qscintilla_ru.qm, qt/qscintilla_ru.ts, src/AutoComplete.cxx, src/AutoComplete.h, src/CallTip.cxx, src/CallTip.h, src/CellBuffer.cxx, src/CellBuffer.h, src/ContractionState.cxx, src/ContractionState.h, src/Document.cxx, src/Document.h, src/DocumentAccessor.cxx, src/DocumentAccessor.h, src/Editor.cxx, src/Editor.h, src/ExternalLexer.cxx, src/ExternalLexer.h, src/Indicator.cxx, src/Indicator.h, src/KeyMap.cxx, src/KeyMap.h, src/KeyWords.cxx, src/LexAPDL.cxx, src/LexAU3.cxx, src/LexAVE.cxx, src/LexAda.cxx, src/LexAsm.cxx, src/LexAsn1.cxx, src/LexBaan.cxx, src/LexBash.cxx, src/LexBasic.cxx, src/LexBullant.cxx, src/LexCLW.cxx, src/LexCPP.cxx, src/LexCSS.cxx, src/LexCaml.cxx, src/LexConf.cxx, src/LexCrontab.cxx, src/LexCsound.cxx, src/LexEScript.cxx, src/LexEiffel.cxx, src/LexErlang.cxx, src/LexFlagship.cxx, src/LexForth.cxx, src/LexFortran.cxx, src/LexGen.py, src/LexGui4Cli.cxx, src/LexHTML.cxx, src/LexHaskell.cxx, src/LexKix.cxx, src/LexLisp.cxx, src/LexLout.cxx, src/LexLua.cxx, src/LexMMIXAL.cxx, src/LexMPT.cxx, src/LexMSSQL.cxx, src/LexMatlab.cxx, src/LexMetapost.cxx, src/LexNsis.cxx, src/LexOthers.cxx, src/LexPB.cxx, src/LexPOV.cxx, src/LexPS.cxx, src/LexPascal.cxx, src/LexPerl.cxx, src/LexPython.cxx, src/LexRebol.cxx, src/LexRuby.cxx, src/LexSQL.cxx, src/LexScriptol.cxx, src/LexSmalltalk.cxx, src/LexSpecman.cxx, src/LexTADS3.cxx, src/LexTeX.cxx, src/LexVB.cxx, src/LexVHDL.cxx, src/LexVerilog.cxx, src/LexYAML.cxx, src/LineMarker.cxx, src/LineMarker.h, src/PropSet.cxx, src/RESearch.cxx, src/RESearch.h, src/SVector.h, src/SciTE.properties, src/ScintillaBase.cxx, src/ScintillaBase.h, src/Style.cxx, src/Style.h, src/StyleContext.cxx, src/StyleContext.h, src/UniConversion.cxx, src/UniConversion.h, src/ViewStyle.cxx, src/ViewStyle.h, src/WindowAccessor.cxx, src/XPM.cxx, src/XPM.h, tgzsrc, vcbuild/SciLexer.dsp, version.txt, win32/Margin.cur, win32/PlatWin.cxx, win32/PlatformRes.h, win32/SciTE.properties, win32/ScintRes.rc, win32/Scintilla.def, win32/ScintillaWin.cxx, win32/deps.mak, win32/makefile, win32/scintilla.mak, win32/scintilla_vc6.mak, zipsrc.bat: First import of QScintilla [0521804cd44a] sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/LICENSE000066400000000000000000001045131463772530400240010ustar00rootroot00000000000000 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. Copyright (C) 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: Copyright (C) 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 . sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/NEWS000066400000000000000000000634001463772530400234720ustar00rootroot00000000000000v2.11.1 14th February 2019 - There is a small (but potentially incompatible) change to the signature of a QsciScintillaBase::SendScintilla() overload which may require an explicit cast to be added. - Bug fixes. v2.11 10th February 2019 - Based on Scintilla v3.10.1. - Added setCaretLineFrameWidth() to QsciScintilla. - The findFirst() and findFirstInSelection() methods of QsciScintilla now support Cxx11 regular expressions. - Added cancelFind() to QsciScintilla. - Added GradientIndicator and CentreGradientIndicator to QsciScintilla::IndicatorStyle. - Added WrapIndentDeeplyIndented to QsciScintilla::WrapIndentMode. - Added ReverseLines to QsciCommand::Command. - Deprecated QsciLexer::styleBitsNeeded(). - Added the AddingPatchAdded, RemovingPatchAdded, AddingPatchRemoved and RemovingPatchRemoved styles to QsciLexerDiff. - Added the DoubleQuotedFString, SingleQuotedFString, TripleSingleQuotedFString and TripleDoubleQuotedFString styles to QsciLexerPython. - Added SCLEX_INDENT, SCLEX_MAXIMA and SCLEX_STATA to QsciScintillaBase. - Added SCI_SETACCESSIBILITY, SCI_GETACCESSIBILITY, SCI_GETCARETLINEFRAME, SCI_SETCARETLINEFRAME, SCI_SETCOMMANDEVENTS, SCI_GETCOMMANDEVENTS, SCI_LINEREVERSE and SCI_GETMOVEEXTENDSSELECTION to QsciScintillaBase. - Added SCI_GETLINECHARACTERINDEX, SCI_ALLOCATELINECHARACTERINDEX, SCI_RELEASELINECHARACTERINDEX, SCI_LINEFROMINDEXPOSITION, SCI_INDEXPOSITIONFROMLINE, SCI_COUNTCODEUNITS and SCI_POSITIONRELATIVECODEUNITS to QsciScintillaBase. - Added SC_LINECHARACTERINDEX_NONE, SC_LINECHARACTERINDEX_UTF32 and SC_LINECHARACTERINDEX_UTF16 to QsciScintillaBase. - Added SCI_GETNAMEDSTYLES, SCI_NAMEOFSTYLE, SCI_TAGSOFSTYLE and SCI_DESCRIPTIONOFSTYLE to QsciScintillaBase. - Added the SCN_AUTOCSELECTIONCHANGE and SCN_URIDROPPED() signals to QsciScintillaBase. - Added the overloaded SCN_USERLISTSELECTION() signal to QsciScintillaBase. - Added INDIC_GRADIENT and INDIC_GRADIENTCENTRE to QsciScintillaBase. - Added SC_PRINT_SCREENCOLOURS to QsciScintillaBase. - Added SC_WRAPINDENT_DEEPINDENT to QsciScintillaBase. - Added SCI_GETDOCUMENTOPTIONS, SC_DOCUMENTOPTION_DEFAULT, SC_DOCUMENTOPTION_STYLES_NONE and SC_DOCUMENTOPTION_TEXT_LARGE to QsciScintillaBase. v2.10.8 1st October 2018 - Bug fixes. v2.10.7 2nd July 2018 - Bug fixes. v2.10.6 24th June 2018 - A pseudo-release to create a version number for updated Python wheels. v2.10.5 23rd June 2018 - Added the QsciLexerEDIFACT class. - Added setStyle() to QsciStyle. - Control-wheel scroll will now zoom in and out of the document. - Buffered drawing is now disabled by default. - The Python bindings create a PEP 376 .dist-info directory on installation that provides version information for dependent packages and allows pip to uninstall. - Added the --no-dist-info option to the Python bindings' configure.py. - Bug fixes. v2.10.4 10th April 2018 - Bug fixes. v2.10.3 26th February 2018 - Added accessibility support. - Added the API file for Python v3.7. v2.10.2 23rd November 2017 - Added setScrollWidth() , scrollWidth, setScrollWidthTracking() and scrollWidthTracking() to QsciScintilla. - Bug fixes. v2.10.1 3rd July 2017 - Changed the default font on macOS to Menlo 12pt. - Added previously internal lexer methods to the Python bindings. v2.10 20th February 2017 - Based on Scintilla v3.7.2. - Added the QsciLexerJSON class. - Added the QsciLexerMarkdown class. - Added replaceHorizontalScrollBar() and replaceVerticalScrollBar() to QsciScintillaBase. - Added bytes() and a corresponding text() overload to QsciScintilla. - Added EdgeMultipleLines to QsciScintilla::EdgeMode. - Added addEdgeColumn() and clearEdgeColumns() to QsciScintilla. - Added the marginRightClicked() signal to QsciScintilla. - Added SymbolMarginColor to QsciScintilla::MarginType. - Added setMarginBackgroundColor() and marginBackgroundColor() to QsciScintilla. - Added setMargins() and margins() to QsciScintilla. - Added TriangleIndicator and TriangleCharacterIndicator to QsciScintilla::IndicatorStyle. - Added WsVisibleOnlyInIndent to QsciScintilla::WhitespaceVisibility. - Added TabDrawMode, setTabDrawMode() and tabDrawMode() to QsciScintilla. - Added InstanceProperty to QsciLexerCoffeeScript. - Added EDGE_MULTILINE to QsciScintillaBase. - Added INDIC_POINT and INDIC_POINTCHARACTER to QsciScintillaBase. - Added SC_AC_FILLUP, SC_AC_DOUBLECLICK, SC_AC_TAB, SC_AC_NEWLINE and SC_AC_COMMAND to QsciScintillaBase. - Added SC_CASE_CAMEL to QsciScintillaBase. - Added SC_CHARSET_CYRILLIC and SC_CHARSET_OEM866 to QsciScintillaBase. - Added SC_FOLDDISPLAYTEXT_HIDDEN, SC_FOLDDISPLAYTEXT_STANDARD and SC_FOLDDISPLAYTEXT_BOXED to QsciScintillaBase. - Added SC_IDLESTYLING_NONE, SC_IDLESTYLING_TOVISIBLE, SC_IDLESTYLING_AFTERVISIBLE and SC_IDLESTYLING_ALL to QsciScintillaBase. - Added SC_MARGIN_COLOUR to QsciScintillaBase. - Added SC_POPUP_NEVER, SC_POPUP_ALL and SC_POPUP_TEXT to QsciScintillaBase. - Added SCI_FOLDDISPLAYTEXTSETSTYLE and SCI_TOGGLEFOLDSHOWTEXT to QsciScintillaBase. - Added SCI_GETIDLESTYLING and SCI_SETIDLESTYLING to QsciScintillaBase. - Added SCI_GETMARGINBACKN and SCI_SETMARGINBACKN to QsciScintillaBase. - Added SCI_GETMARGINS and SCI_SETMARGINS to QsciScintillaBase. - Added SCI_GETMOUSEWHEELCAPTURES and SCI_SETMOUSEWHEELCAPTURES to QsciScintillaBase. - Added SCI_GETTABDRAWMODE and SCI_SETTABDRAWMODE to QsciScintillaBase. - Added SCI_ISRANGEWORD to QsciScintillaBase. - Added SCI_MULTIEDGEADDLINE and SCI_MULTIEDGECLEARALL to QsciScintillaBase. - Added SCI_MULTIPLESELECTADDNEXT and SCI_MULTIPLESELECTADDEACH to QsciScintillaBase. - Added SCI_TARGETWHOLEDOCUMENT to QsciScintillaBase. - Added SCLEX_JSON and SCLEX_EDIFACT to QsciScintillaBase. - Added SCTD_LONGARROW and SCTD_STRIKEOUT to QsciScintillaBase. - Added SCVS_NOWRAPLINESTART to QsciScintillaBase. - Added SCWS_VISIBLEONLYININDENT to QsciScintillaBase. - Added STYLE_FOLDDISPLAYTEXT to QsciScintillaBase. - Added the SCN_AUTOCCOMPLETED() signal to QsciScintillaBase. - Added the overloaded SCN_AUTOCSELECTION() and SCN_USERLISTSELECTION() signals to QsciScintillaBase. - Added the SCN_MARGINRIGHTCLICK() signal to QsciScintillaBase. - Renamed SCI_GETTARGETRANGE to SCI_GETTARGETTEXT in QsciScintillaBase. - Removed SCI_GETKEYSUNICODE and SCI_SETKEYSUNICODE to QsciScintillaBase. - The autoCompletionFillups(), autoCompletionWordSeparators(), blockEnd(), blockLookback(), blockStart(), blockStartKeyword(), braceStyle(), caseSensitive(), indentationGuideView() and defaultStyle() methods of QsciLexer are no longer marked as internal and are exposed to Python so that they may be used by QsciLexerCustom sub-classes. - The name of the library has been changed to include the major version number of the version of Qt it is built against (ie. 4 or 5). v2.9.4 25th December 2016 - Added the .api file for Python v3.6. - Bug fixes. v2.9.3 25th July 2016 - Bug fixes. v2.9.2 18th April 2016 - Added support for a PEP 484 stub file for the Python extension module. v2.9.1 24th October 2015 - Added the .api file for Python v3.5. - Bug fixes. v2.9 20th April 2015 - Based on Scintilla v3.5.4. - Added UserLiteral, InactiveUserLiteral, TaskMarker, InactiveTaskMarker, EscapeSequence, InactiveEscapeSequence, setHighlightBackQuotedStrings(), highlightBackQuotedStrings(), setHighlightEscapeSequences(), highlightEscapeSequences(), setVerbatimStringEscapeSequencesAllowed() and verbatimStringEscapeSequencesAllowed() to QsciLexerCPP. - Added CommentKeyword, DeclareInputPort, DeclareOutputPort, DeclareInputOutputPort, PortConnection and the inactive versions of all styles to QsciLexerVerilog. - Added CommentBlock to QsciLexerVHDL. - Added AnnotationIndented to QsciScintilla::AnnotationDisplay. - Added FullBoxIndicator, ThickCompositionIndicator, ThinCompositionIndicator and TextColorIndicator to QsciScintilla::IndicatorStyle. - Added setIndicatorHoverForegroundColor() and setIndicatorHoverStyle() to QsciScintilla. - Added Bookmark to QsciScintilla::MarkerSymbol. - Added WrapWhitespace to QsciScintilla::WrapMode. - Added SCLEX_AS, SCLEX_BIBTEX, SCLEX_DMAP, SCLEX_DMIS, SCLEX_IHEX, SCLEX_REGISTRY, SCLEX_SREC and SCLEX_TEHEX to QsciScintillaBase. - Added SCI_CHANGEINSERTION to QsciScintillaBase. - Added SCI_CLEARTABSTOPS, SCI_ADDTABSTOP and SCI_GETNEXTTABSTOP to QsciScintillaBase. - Added SCI_GETIMEINTERACTION, SCI_SETIMEINTERACTION, SC_IME_WINDOWED and SC_IME_INLINE to QsciScintillaBase. - Added SC_MARK_BOOKMARK to QsciScintillaBase. - Added INDIC_COMPOSITIONTHIN, INDIC_FULLBOX, INDIC_TEXTFORE, INDIC_IME, INDIC_IME_MAX, SC_INDICVALUEBIT, SC_INDICVALUEMASK, SC_INDICFLAG_VALUEBEFORE, SCI_INDICSETHOVERSTYLE, SCI_INDICGETHOVERSTYLE, SCI_INDICSETHOVERFORE, SCI_INDICGETHOVERFORE, SCI_INDICSETFLAGS and SCI_INDICGETFLAGS to QsciScintillaBase. - Added SCI_SETTARGETRANGE and SCI_GETTARGETRANGE to QsciScintillaBase. - Added SCFIND_CXX11REGEX to QsciScintillaBase. - Added SCI_CALLTIPSETPOSSTART to QsciScintillaBase. - Added SC_FOLDFLAG_LINESTATE to QsciScintillaBase. - Added SC_WRAP_WHITESPACE to QsciScintillaBase. - Added SC_PHASES_ONE, SC_PHASES_TWO, SC_PHASES_MULTIPLE, SCI_GETPHASESDRAW and SCI_SETPHASESDRAW to QsciScintillaBase. - Added SC_STATUS_OK, SC_STATUS_FAILURE, SC_STATUS_BADALLOC, SC_STATUS_WARN_START and SC_STATUS_WARNREGEX to QsciScintillaBase. - Added SC_MULTIAUTOC_ONCE, SC_MULTIAUTOC_EACH, SCI_AUTOCSETMULTI and SCI_AUTOCGETMULTI to QsciScintillaBase. - Added ANNOTATION_INDENTED to QsciScintillaBase. - Added SCI_DROPSELECTIONN to QsciScintillaBase. - Added SC_TECHNOLOGY_DIRECTWRITERETAIN and SC_TECHNOLOGY_DIRECTWRITEDC to QsciScintillaBase. - Added SC_LINE_END_TYPE_DEFAULT, SC_LINE_END_TYPE_UNICODE, SCI_GETLINEENDTYPESSUPPORTED, SCI_SETLINEENDTYPESALLOWED, SCI_GETLINEENDTYPESALLOWED and SCI_GETLINEENDTYPESACTIVE to QsciScintillaBase. - Added SCI_ALLOCATESUBSTYLES, SCI_GETSUBSTYLESSTART, SCI_GETSUBSTYLESLENGTH, SCI_GETSTYLEFROMSUBSTYLE, SCI_GETPRIMARYSTYLEFROMSTYLE, SCI_FREESUBSTYLES, SCI_SETIDENTIFIERS, SCI_DISTANCETOSECONDARYSTYLES and SCI_GETSUBSTYLEBASES to QsciScintillaBase. - Added SC_MOD_INSERTCHECK and SC_MOD_CHANGETABSTOPS to QsciScintillaBase. - Qt v3 and PyQt v3 are no longer supported. v2.8.4 11th September 2014 - Added setHotspotForegroundColor(), resetHotspotForegroundColor(), setHotspotBackgroundColor(), resetHotspotBackgroundColor(), setHotspotUnderline() and setHotspotWrap() to QsciScintilla. - Added SCI_SETHOTSPOTSINGLELINE to QsciScintillaBase. - Bug fixes. v2.8.3 3rd July 2014 - Added the QsciLexerCoffeeScript class. - Font sizes are now handled as floating point values rather than integers. - Bug fixes. v2.8.2 26th May 2014 - Added the QsciLexerAVS class. - Added the QsciLexerPO class. - Added the --sysroot, --no-sip-files and --no-qsci-api options to the Python bindings' configure.py. - Cross-compilation (specifically to iOS and Android) is now supported. - configure.py has been refactored and relicensed so that it can be used as a template for wrapping other bindings. - Bug fixes. v2.8.1 14th March 2014 - Added support for iOS and Android. - Added support for retina displays. - A qscintilla2.prf file is installed so that application .pro files only need to add CONFIG += qscintilla2. - Updated the keywords recognised by the Octave lexer. - Bug fixes. v2.8 9th November 2013 - Based on Scintilla v3.3.6. - Added the SCN_FOCUSIN() and SCN_FOCUSOUT() signals to QsciScintillaBase. - Added PreProcessorCommentLineDoc and InactivePreProcessorCommentLineDoc to QsciLexerCPP. - Added SCLEX_LITERATEHASKELL, SCLEX_KVIRC, SCLEX_RUST and SCLEX_STTXT to QsciScintillaBase. - Added ThickCompositionIndicator to QsciScintilla::IndicatorStyle. - Added INDIC_COMPOSITIONTHICK to QsciScintillaBase. - Added SC_FOLDACTION_CONTRACT, SC_FOLDACTION_EXPAND and SC_FOLDACTION_TOGGLE to QsciScintillaBase. - Added SCI_FOLDLINE, SCI_FOLDCHILDREN, SCI_EXPANDCHILDREN and SCI_FOLDALL to QsciScintillaBase. - Added SC_AUTOMATICFOLD_SHOW, SC_AUTOMATICFOLD_CLICK and SC_AUTOMATICFOLD_CHANGE to QsciScintillaBase. - Added SCI_SETAUTOMATICFOLD and SCI_GETAUTOMATICFOLD to QsciScintillaBase. - Added SC_ORDER_PRESORTED, SC_ORDER_PERFORMSORT and SC_ORDER_CUSTOM to QsciScintillaBase. - Added SCI_AUTOCSETORDER and SCI_AUTOCGETORDER to QsciScintillaBase. - Added SCI_POSITIONRELATIVE to QsciScintillaBase. - Added SCI_RELEASEALLEXTENDEDSTYLES and SCI_ALLOCATEEXTENDEDSTYLES to QsciScintillaBase. - Added SCI_SCROLLRANGE to QsciScintillaBase. - Added SCI_SETCARETLINEVISIBLEALWAYS and SCI_GETCARETLINEVISIBLEALWAYS to QsciScintillaBase. - Added SCI_SETMOUSESELECTIONRECTANGULARSWITCH and SCI_GETMOUSESELECTIONRECTANGULARSWITCH to QsciScintillaBase. - Added SCI_SETREPRESENTATION, SCI_GETREPRESENTATION and SCI_CLEARREPRESENTATION to QsciScintillaBase. - Input methods are now properly supported. v2.7.2 16th June 2013 - The build script for the Python bindings now has a --pyqt argument for specifying PyQt4 or PyQt5. - The default EOL mode on OS/X is now EolUnix. - Bug fixes. v2.7.1 1st March 2013 - Added support for the final release of Qt v5. - The build script for the Python bindings should now work with SIP v5. - Bug fixes. v2.7 8th December 2012 - Based on Scintilla v3.2.3. - Added support for Qt v5-rc1. - Added HashQuotedString, InactiveHashQuotedString, PreProcessorComment, InactivePreProcessorComment, setHighlightHashQuotedStrings() and highlightHashQuotedStrings() to QsciLexerCpp. - Added Variable, setHSSLanguage(), HSSLanguage(), setLessLanguage(), LessLanguage(), setSCCSLanguage() and SCCSLanguage() to QsciLexerCSS. - Added setOverwriteMode() and overwriteMode() to QsciScintilla. - Added wordAtLineIndex() to QsciScintilla. - Added findFirstInSelection() to QsciScintilla. - Added CallTipsPosition, callTipsPosition() and setCallTipsPosition() to QsciScintilla. - Added WrapFlagInMargin to QsciScintilla::WrapVisualFlag. - Added SquigglePixmapIndicator to QsciScintilla::IndicatorStyle. - The weight of a font (rather than whether it is just bold or not) is now respected. - Added SCLEX_AVS, SCLEX_COFFEESCRIPT, SCLEX_ECL, SCLEX_OSCRIPT, SCLEX_TCMD and SCLEX_VISUALPROLOG to QsciScintillaBase. - Added SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE and SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE to QsciScintillaBase. - Added SC_FONT_SIZE_MULTIPLIER to QsciScintillaBase. - Added SC_WEIGHT_NORMAL, SC_WEIGHT_SEMIBOLD and SC_WEIGHT_BOLD to QsciScintillaBase. - Added SC_WRAPVISUALFLAG_MARGIN to QsciScintillaBase. - Added INDIC_SQUIGGLEPIXMAP to QsciScintillaBase. - Added SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR, SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR, SCI_CALLTIPSETPOSITION, SCI_COUNTCHARACTERS, SCI_CREATELOADER, SCI_DELETERANGE, SCI_FINDINDICATORFLASH, SCI_FINDINDICATORHIDE, SCI_FINDINDICATORSHOW, SCI_GETALLLINESVISIBLE, SCI_GETGAPPOSITION, SCI_GETPUNCTUATIONCHARS, SCI_GETRANGEPOINTER, SCI_GETSELECTIONEMPTY, SCI_GETTECHNOLOGY, SCI_GETWHITESPACECHARS, SCI_GETWORDCHARS, SCI_RGBAIMAGESETSCALE, SCI_SETPUNCTUATIONCHARS, SCI_SETTECHNOLOGY, SCI_STYLESETSIZEFRACTIONAL, SCI_STYLEGETSIZEFRACTIONAL, SCI_STYLESETWEIGHT and SCI_STYLEGETWEIGHT to QsciScintillaBase. - Removed SCI_GETUSEPALETTE and SCI_SETUSEPALETTE from QsciScintillaBase. - Bug fixes. v2.6.2 20th June 2012 - Added support for Qt v5-alpha. - QsciLexer::wordCharacters() is now part of the public API. - Bug fixes. v2.6.1 10th February 2012 - Support SCI_NAMESPACE to enable all internal Scintilla classes to be put into the Scintilla namespace. - APIs now allow for spaces between the end of a word and the opening parenthesis. - Building against Qt v3 is fixed. v2.6 11th November 2011 - Based on Scintilla v2.29. - Added Command, command() and execute() to QsciCommand. - Added boundTo() and find() to QsciCommandSet. - Added createStandardContextMenu() to QsciScintilla. - Added StraightBoxIndicator, DashesIndicator, DotsIndicator, SquiggleLowIndicator and DotBoxIndicator to QsciScintilla::IndicatorStyle. - Added markerDefine() to QsciScintilla. - Added MoNone, MoSublineSelect, marginOptions() and setMarginOptions() to QsciScintilla. - Added registerImage() to QsciScintilla. - Added setIndicatorOutlineColor() to QsciScintilla. - Added setMatchedBraceIndicator(), resetMatchedBraceIndicator(), setUnmatchedBraceIndicator() and resetUnmatchedBraceIndicator() to QsciScintilla. - Added highlightTripleQuotedStrings() and setHighlightTripleQuotedStrings() to QsciLexerCpp. - Added Label to QsciLexerLua. - Added DoubleQuotedStringVar, Translation, RegexVar, SubstitutionVar, BackticksVar, DoubleQuotedHereDocumentVar, BacktickHereDocumentVar, QuotedStringQQVar, QuotedStringQXVar, QuotedStringQRVar, setFoldAtElse() and foldAtElse() to QsciLexerPerl. - Added highlightSubidentifiers() and setHighlightSubidentifiers() to QsciLexerPython. - Added INDIC_STRAIGHTBOX, INDIC_DASH, INDIC_DOTS, INDIC_SQUIGGLELOW and INDIC_DOTBOX to QsciScintillaBase. - Added SC_MARGINOPTION_NONE and SC_MARGINOPTION_SUBLINESELECT to QsciScintillaBase. - Added SC_MARK_RGBAIMAGE to QsciScintillaBase. - Added SCI_BRACEBADLIGHTINDICATOR, SCI_BRACEHIGHLIGHTINDICATOR, SCI_GETIDENTIFIER, SCI_GETMARGINOPTIONS, SCI_INDICGETOUTLINEALPHA, SCI_INDICSETOUTLINEALPHA, SCI_MARKERDEFINERGBAIMAGE, SCI_MARKERENABLEHIGHLIGHT, SCI_MARKERSETBACKSELECTED, SCI_MOVESELECTEDLINESDOWN, SCI_MOVESELECTEDLINESUP, SCI_REGISTERRGBAIMAGE, SCI_RGBAIMAGESETHEIGHT, SCI_RGBAIMAGESETWIDTH, SCI_SCROLLTOEND, SCI_SCROLLTOSTART, SCI_SETEMPTYSELECTION, SCI_SETIDENTIFIER and SCI_SETMARGINOPTIONS to QsciScintillaBase. v2.5.1 17th April 2011 - Added QsciLexerMatlab and QsciLexerOctave. v2.5 29th March 2011 - Based on Scintilla v2.25. - Rectangular selections are now fully supported and compatible with SciTE. - The signature of the fromMimeData() and toMimeData() methods of QsciScintillaBase have changed incompatibly in order to support rectangular selections. - Added QsciScintilla::setAutoCompletionUseSingle() to replace the now deprecated setAutoCompletionShowSingle(). - Added QsciScintilla::autoCompletionUseSingle() to replace the now deprecated autoCompletionShowSingle(). - QsciScintilla::setAutoCompletionCaseSensitivity() is no longer ignored if a lexer has been set. - Added FullRectangle, LeftRectangle and Underline to the QsciScintilla::MarkerSymbol enum. - Added setExtraAscent(), extraAscent(), setExtraDescent() and extraDescent() to QsciScintilla. - Added setWhitespaceSize() and whitespaceSize() to QsciScintilla. - Added replaceSelectedText() to QsciScintilla. - Added setWhitespaceBackgroundColor() and setWhitespaceForegroundColor() to QsciScintilla. - Added setWrapIndentMode() and wrapIndentMode() to QsciScintilla. - Added setFirstVisibleLine() to QsciScintilla. - Added setContractedFolds() and contractedFolds() to QsciScintilla. - Added the SCN_HOTSPOTRELEASECLICK() signal to QsciScintillaBase. - The signature of the QsciScintillaBase::SCN_UPDATEUI() signal has changed. - Added the RawString and inactive styles to QsciLexerCPP. - Added MediaRule to QsciLexerCSS. - Added BackquoteString, RawString, KeywordSet5, KeywordSet6 and KeywordSet7 to QsciLexerD. - Added setDjangoTemplates(), djangoTemplates(), setMakoTemplates() and makoTemplates() to QsciLexerHTML. - Added KeywordSet5, KeywordSet6, KeywordSet7 and KeywordSet8 to QsciLexerLua. - Added setInitialSpaces() and initialSpaces() to QsciLexerProperties. - Added setFoldCompact(), foldCompact(), setStringsOverNewlineAllowed() and stringsOverNewlineAllowed() to QsciLexerPython. - Added setFoldComments(), foldComments(), setFoldCompact() and foldCompact() to QsciLexerRuby. - Added setFoldComments() and foldComments(), and removed setFoldCompact() and foldCompact() from QsciLexerTCL. - Added setFoldComments(), foldComments(), setFoldCompact(), foldCompact(), setProcessComments(), processComments(), setProcessIf(), and processIf() to QsciLexerTeX. - Added QuotedIdentifier, setDottedWords(), dottedWords(), setFoldAtElse(), foldAtElse(), setFoldOnlyBegin(), foldOnlyBegin(), setHashComments(), hashComments(), setQuotedIdentifiers() and quotedIdentifiers() to QsciLexerSQL. - The Python bindings now allow optional arguments to be specified as keyword arguments. - The Python bindings will now build using the protected-is-public hack if possible. v2.4.6 23rd December 2010 - Added support for indicators to the high-level API, i.e. added the IndicatorStyle enum, the clearIndicatorRange(), fillIndicatorRange(), indicatorDefine(), indicatorDrawUnder(), setIndicatorDrawUnder() and setIndicatorForegroundColor methods, and the indicatorClicked() and indicatorReleased() signals to QsciScintilla. - Added support for the Key style in QsciLexerProperties. - Added an API file for Python v2.7. - Added the --no-timestamp command line option to the Python bindings' configure.py. v2.4.5 31st August 2010 - A bug fix release. v2.4.4 12th July 2010 - Added the canInsertFromMimeData(), fromMimeData() and toMimeData() methods to QsciScintillaBase. - QsciScintilla::markerDefine() now allows existing markers to be redefined. v2.4.3 17th March 2010 - Added clearFolds() to QsciScintilla. v2.4.2 20th January 2010 - Updated Spanish translations from Jaime Seuma. - Fixed compilation problems with Qt v3 and Qt v4 prior to v4.5. v2.4.1 14th January 2010 - Added the QsciLexerSpice and QsciLexerVerilog classes. - Significant performance improvements when handling long lines. - The Python bindings include automatically generated docstrings by default. - Added an API file for Python v3. v2.4 5th June 2009 - Based on Scintilla v1.78. - Added the QsciLexerCustom, QsciStyle and QsciStyledText classes. - Added annotate(), annotation(), clearAnnotations(), setAnnotationDisplay() and annotationDisplay() to QsciScintilla. - Added setMarginText(), clearMarginText(), setMarginType() and marginType() to QsciScintilla. - Added QsciLexer::lexerId() so that container lexers can be implemented. - Added editor() and styleBitsNeeded() to QsciLexer. - Added setDollarsAllowed() and dollarsAllowed() to QsciLexerCPP. - Added setFoldScriptComments(), foldScriptComments(), setFoldScriptHeredocs() and foldScriptHeredocs() to QsciLexerHTML. - Added setSmartHighlighting() and smartHighlighting() to QsciLexerPascal. (Note that the Scintilla Pascal lexer has changed so that any saved colour and font settings will not be properly restored.) - Added setFoldPackages(), foldPackages(), setFoldPODBlocks() and foldPODBlocks() to QsciLexerPerl. - Added setV2UnicodeAllowed(), v2UnicodeAllowed(), setV3BinaryOctalAllowed(), v3BinaryOctalAllowed(), setV3BytesAllowed and v3BytesAllowed() to QsciLexerPython. - Added setScriptsStyled() and scriptsStyled() to QsciLexerXML. - Added Spanish translations from Jaime Seuma. v2.3.2 17th November 2008 - A bug fix release. v2.3.1 6th November 2008 - Based on Scintilla v1.77. - Added the read() and write() methods to QsciScintilla to allow a file to be read and written while minimising the conversions. - Added the positionFromLineIndex() and lineIndexFromPosition() methods to QsciScintilla to convert between a Scintilla character address and a QScintilla character address. - Added QsciScintilla::wordAtPoint() to return the word at the given screen coordinates. - QSciScintilla::setSelection() now allows the carat to be left at either the start or the end of the selection. - 'with' is now treated as a keyword by the Python lexer. v2.3 20th September 2008 - Based on Scintilla v1.76. - The new QsciAbstractAPIs class allows applications to replace the default implementation of the language APIs used for auto-completion lists and call tips. - Added QsciScintilla::apiContext() to allow applications to determine the context used for auto-completion and call tips. - Added the QsciLexerFortran, QsciLexerFortran77, QsciLexerPascal, QsciLexerPostScript, QsciLexerTCL, QsciLexerXML and QsciLexerYAML classes. - QsciScintilla::setFolding() will now accept an optional margin number. v2.2 27th February 2008 - Based on Scintilla v1.75. - A lexer's default colour, paper and font are now written to and read from the settings. - Windows64 is now supported. - The signature of the QsciScintillaBase::SCN_MACRORECORD() signal has changed slightly. - Changed the licensing to match the current Qt licenses, including GPL v3. v2.1 1st June 2007 - A slightly revised API, incompatible with QScintilla v2.0. - Lexers now remember their style settings. A lexer no longer has to be the current lexer when changing a style's color, end-of-line fill, font or paper. - The color(), eolFill(), font() and paper() methods of QsciLexer now return the current values for a style rather than the default values. - The setDefaultColor(), setDefaultFont() and setDefaultPaper() methods of QsciLexer are no longer slots and no longer virtual. - The defaultColor(), defaultFont() and defaultPaper() methods of QsciLexer are no longer virtual. - The color(), eolFill(), font() and paper() methods of all QsciLexer derived classes (except for QsciLexer itself) have been renamed defaultColor(), defaultEolFill(), defaultFont() and defaultPaper() respectively. v2.0 26th May 2007 - A revised API, incompatible with QScintilla v1. - Hugely improved autocompletion and call tips support. - Supports both Qt v3 and Qt v4. - Includes Python bindings. sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/000077500000000000000000000000001463772530400240325ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/CMakeLists.txt000066400000000000000000000107751463772530400266040ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.12.2) # Disable AUTOMOC because it cannot be made to work with QScintilla set(CMAKE_AUTOMOC OFF) set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(Qt5 REQUIRED COMPONENTS PrintSupport Widgets) if(APPLE) find_package(Qt5 REQUIRED COMPONENTS MacExtras) endif() add_definitions(-DSCINTILLA_QT) add_definitions(-DSCI_LEXER) set(QSCINTILLA_SRC qsciscintilla.cpp qsciscintillabase.cpp qsciabstractapis.cpp qsciapis.cpp qscicommand.cpp qscicommandset.cpp qscidocument.cpp qscilexer.cpp qscilexercustom.cpp qscilexersql.cpp qscilexerjson.cpp qscilexerhtml.cpp qscilexerxml.cpp qscilexerjavascript.cpp qscilexercpp.cpp qscilexerpython.cpp qscimacro.cpp qsciprinter.cpp qscistyle.cpp qscistyledtext.cpp MacPasteboardMime.cpp InputMethod.cpp SciClasses.cpp ListBoxQt.cpp PlatQt.cpp ScintillaQt.cpp SciAccessibility.cpp ../lexers/LexSQL.cpp ../lexers/LexJSON.cpp ../lexers/LexHTML.cpp ../lexlib/Accessor.cpp ../lexlib/CharacterCategory.cpp ../lexlib/CharacterSet.cpp ../lexlib/DefaultLexer.cpp ../lexlib/LexerBase.cpp ../lexlib/LexerModule.cpp ../lexlib/LexerNoExceptions.cpp ../lexlib/LexerSimple.cpp ../lexlib/PropSetSimple.cpp ../lexlib/StyleContext.cpp ../lexlib/WordList.cpp ../src/AutoComplete.cpp ../src/CallTip.cpp ../src/CaseConvert.cpp ../src/CaseFolder.cpp ../src/Catalogue.cpp ../src/CellBuffer.cpp ../src/CharClassify.cpp ../src/ContractionState.cpp ../src/Decoration.cpp ../src/Document.cpp ../src/Editor.cpp ../src/EditModel.cpp ../src/EditView.cpp ../src/ExternalLexer.cpp ../src/Indicator.cpp ../src/KeyMap.cpp ../src/LineMarker.cpp ../src/MarginView.cpp ../src/PerLine.cpp ../src/PositionCache.cpp ../src/RESearch.cpp ../src/RunStyles.cpp ../src/ScintillaBase.cpp ../src/Selection.cpp ../src/Style.cpp ../src/UniConversion.cpp ../src/ViewStyle.cpp ../src/XPM.cpp ) set(QSCINTILLA_HDR ./Qsci/qsciglobal.h ./Qsci/qscicommand.h ./Qsci/qscicommandset.h ./Qsci/qscidocument.h ./Qsci/qsciprinter.h ./Qsci/qscistyle.h ./Qsci/qscistyledtext.h ListBoxQt.h SciNamespace.h ../include/ILexer.h ../include/Platform.h ../include/SciLexer.h ../include/Scintilla.h ../include/ScintillaWidget.h ../include/Sci_Position.h ../lexlib/Accessor.h ../lexlib/CharacterCategory.h ../lexlib/CharacterSet.h ../lexlib/DefaultLexer.h ../lexlib/LexAccessor.h ../lexlib/LexerBase.h ../lexlib/LexerModule.h ../lexlib/LexerNoExceptions.h ../lexlib/LexerSimple.h ../lexlib/OptionSet.h ../lexlib/PropSetSimple.h ../lexlib/StyleContext.h ../lexlib/SubStyles.h ../lexlib/WordList.h ../src/AutoComplete.h ../src/CallTip.h ../src/CaseConvert.h ../src/CaseFolder.h ../src/Catalogue.h ../src/CellBuffer.h ../src/CharClassify.h ../src/ContractionState.h ../src/Decoration.h ../src/Document.h ../src/Editor.h ../src/ExternalLexer.h ../src/FontQuality.h ../src/Indicator.h ../src/KeyMap.h ../src/LineMarker.h ../src/Partitioning.h ../src/PerLine.h ../src/PositionCache.h ../src/RESearch.h ../src/RunStyles.h ../src/ScintillaBase.h ../src/Selection.h ../src/SplitVector.h ../src/Style.h ../src/UnicodeFromUTF8.h ../src/UniConversion.h ../src/ViewStyle.h ../src/XPM.h ../src/Position.h ../src/SparseVector.h ) set(QSCINTILLA_MOC_HDR ./Qsci/qsciscintilla.h ./Qsci/qsciscintillabase.h ./Qsci/qsciabstractapis.h ./Qsci/qsciapis.h ./Qsci/qscilexer.h ./Qsci/qscilexercustom.h ./Qsci/qscilexersql.h ./Qsci/qscilexerjson.h ./Qsci/qscilexerhtml.h ./Qsci/qscilexerxml.h ./Qsci/qscilexerjavascript.h ./Qsci/qscilexercpp.h ./Qsci/qscilexerpython.h ./Qsci/qscimacro.h SciClasses.h ScintillaQt.h SciAccessibility.h ) QT5_WRAP_CPP(QSCINTILLA_WRAP_MOC_HDR ${QSCINTILLA_MOC_HDR}) add_library(qscintilla2 ${QSCINTILLA_SRC} ${QSCINTILLA_HDR} ${QSCINTILLA_MOC_HDR} ${QSCINTILLA_MOC} ${QSCINTILLA_WRAP_MOC_HDR}) target_include_directories(qscintilla2 PRIVATE ../include ../lexlib ../src) target_include_directories(qscintilla2 INTERFACE .) target_link_libraries(qscintilla2 Qt5::Widgets Qt5::PrintSupport) if (APPLE) target_link_libraries(qscintilla2 Qt5::MacExtras) endif() add_library(QScintilla::QScintilla ALIAS qscintilla2) sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/InputMethod.cpp000066400000000000000000000235031463772530400270010ustar00rootroot00000000000000// Copyright (c) 2017 Riverbank Computing Limited // Copyright (c) 2011 Archaeopteryx Software, Inc. // Copyright (c) 1990-2011, Scientific Toolworks, Inc. // // The License.txt file describes the conditions under which this software may // be distributed. #include #include #include #include #include #include #include #include #include #include "Qsci/qsciscintillabase.h" #include "ScintillaQt.h" #define INDIC_INPUTMETHOD 24 #define MAXLENINPUTIME 200 #define SC_INDICATOR_INPUT INDIC_IME #define SC_INDICATOR_TARGET INDIC_IME+1 #define SC_INDICATOR_CONVERTED INDIC_IME+2 #define SC_INDICATOR_UNKNOWN INDIC_IME_MAX static bool IsHangul(const QChar qchar) { int unicode = (int)qchar.unicode(); // Korean character ranges used for preedit chars. // http://www.programminginkorean.com/programming/hangul-in-unicode/ const bool HangulJamo = (0x1100 <= unicode && unicode <= 0x11FF); const bool HangulCompatibleJamo = (0x3130 <= unicode && unicode <= 0x318F); const bool HangulJamoExtendedA = (0xA960 <= unicode && unicode <= 0xA97F); const bool HangulJamoExtendedB = (0xD7B0 <= unicode && unicode <= 0xD7FF); const bool HangulSyllable = (0xAC00 <= unicode && unicode <= 0xD7A3); return HangulJamo || HangulCompatibleJamo || HangulSyllable || HangulJamoExtendedA || HangulJamoExtendedB; } static void MoveImeCarets(QsciScintillaQt *sqt, int offset) { // Move carets relatively by bytes for (size_t r=0; r < sqt->sel.Count(); r++) { int positionInsert = sqt->sel.Range(r).Start().Position(); sqt->sel.Range(r).caret.SetPosition(positionInsert + offset); sqt->sel.Range(r).anchor.SetPosition(positionInsert + offset); } } static void DrawImeIndicator(QsciScintillaQt *sqt, int indicator, int len) { // Emulate the visual style of IME characters with indicators. // Draw an indicator on the character before caret by the character bytes of len // so it should be called after AddCharUTF(). // It does not affect caret positions. if (indicator < 8 || indicator > INDIC_MAX) { return; } sqt->pdoc->DecorationSetCurrentIndicator(indicator); for (size_t r=0; r< sqt-> sel.Count(); r++) { int positionInsert = sqt->sel.Range(r).Start().Position(); sqt->pdoc->DecorationFillRange(positionInsert - len, 1, len); } } static int GetImeCaretPos(QInputMethodEvent *event) { foreach (QInputMethodEvent::Attribute attr, event->attributes()) { if (attr.type == QInputMethodEvent::Cursor) return attr.start; } return 0; } static std::vector MapImeIndicators(QInputMethodEvent *event) { std::vector imeIndicator(event->preeditString().size(), SC_INDICATOR_UNKNOWN); foreach (QInputMethodEvent::Attribute attr, event->attributes()) { if (attr.type == QInputMethodEvent::TextFormat) { QTextFormat format = attr.value.value(); QTextCharFormat charFormat = format.toCharFormat(); int indicator = SC_INDICATOR_UNKNOWN; switch (charFormat.underlineStyle()) { case QTextCharFormat::NoUnderline: // win32, linux indicator = SC_INDICATOR_TARGET; break; case QTextCharFormat::SingleUnderline: // osx case QTextCharFormat::DashUnderline: // win32, linux indicator = SC_INDICATOR_INPUT; break; case QTextCharFormat::DotLine: case QTextCharFormat::DashDotLine: case QTextCharFormat::WaveUnderline: case QTextCharFormat::SpellCheckUnderline: indicator = SC_INDICATOR_CONVERTED; break; default: indicator = SC_INDICATOR_UNKNOWN; } if (format.hasProperty(QTextFormat::BackgroundBrush)) // win32, linux indicator = SC_INDICATOR_TARGET; #ifdef Q_OS_OSX if (charFormat.underlineStyle() == QTextCharFormat::SingleUnderline) { QColor uc = charFormat.underlineColor(); if (uc.lightness() < 2) { // osx indicator = SC_INDICATOR_TARGET; } } #endif for (int i = attr.start; i < attr.start+attr.length; i++) { imeIndicator[i] = indicator; } } } return imeIndicator; } void QsciScintillaBase::inputMethodEvent(QInputMethodEvent *event) { // Copy & paste by johnsonj with a lot of helps of Neil // Great thanks for my forerunners, jiniya and BLUEnLIVE if (sci->pdoc->IsReadOnly() || sci->SelectionContainsProtected()) { // Here, a canceling and/or completing composition function is needed. return; } if (sci->pdoc->TentativeActive()) { sci->pdoc->TentativeUndo(); } else { // No tentative undo means start of this composition so // Fill in any virtual spaces. sci->ClearBeforeTentativeStart(); } sci->view.imeCaretBlockOverride = false; if (!event->commitString().isEmpty()) { const QString commitStr = event->commitString(); const unsigned int commitStrLen = commitStr.length(); for (unsigned int i = 0; i < commitStrLen;) { const unsigned int ucWidth = commitStr.at(i).isHighSurrogate() ? 2 : 1; const QString oneCharUTF16 = commitStr.mid(i, ucWidth); const QByteArray oneChar = textAsBytes(oneCharUTF16); const int oneCharLen = oneChar.length(); sci->AddCharUTF(oneChar.data(), oneCharLen); i += ucWidth; } } else if (!event->preeditString().isEmpty()) { const QString preeditStr = event->preeditString(); const unsigned int preeditStrLen = preeditStr.length(); if ((preeditStrLen == 0) || (preeditStrLen > MAXLENINPUTIME)) { sci->ShowCaretAtCurrentPosition(); return; } sci->pdoc->TentativeStart(); // TentativeActive() from now on. std::vector imeIndicator = MapImeIndicators(event); const bool recording = sci->recordingMacro; sci->recordingMacro = false; for (unsigned int i = 0; i < preeditStrLen;) { const unsigned int ucWidth = preeditStr.at(i).isHighSurrogate() ? 2 : 1; const QString oneCharUTF16 = preeditStr.mid(i, ucWidth); const QByteArray oneChar = textAsBytes(oneCharUTF16); const int oneCharLen = oneChar.length(); sci->AddCharUTF(oneChar.data(), oneCharLen); DrawImeIndicator(sci, imeIndicator[i], oneCharLen); i += ucWidth; } sci->recordingMacro = recording; // Move IME carets. int imeCaretPos = GetImeCaretPos(event); int imeEndToImeCaretU16 = imeCaretPos - preeditStrLen; int imeCaretPosDoc = sci->pdoc->GetRelativePositionUTF16(sci->CurrentPosition(), imeEndToImeCaretU16); MoveImeCarets(sci, - sci->CurrentPosition() + imeCaretPosDoc); if (IsHangul(preeditStr.at(0))) { #ifndef Q_OS_WIN if (imeCaretPos > 0) { int oneCharBefore = sci->pdoc->GetRelativePosition(sci->CurrentPosition(), -1); MoveImeCarets(sci, - sci->CurrentPosition() + oneCharBefore); } #endif sci->view.imeCaretBlockOverride = true; } // Set candidate box position for Qt::ImMicroFocus. preeditPos = sci->CurrentPosition(); sci->EnsureCaretVisible(); updateMicroFocus(); } sci->ShowCaretAtCurrentPosition(); } QVariant QsciScintillaBase::inputMethodQuery(Qt::InputMethodQuery query) const { int pos = SendScintilla(SCI_GETCURRENTPOS); int line = SendScintilla(SCI_LINEFROMPOSITION, pos); switch (query) { #if QT_VERSION >= 0x050000 case Qt::ImHints: return QWidget::inputMethodQuery(query); #endif case Qt::ImMicroFocus: { int startPos = (preeditPos >= 0) ? preeditPos : pos; Scintilla::Point pt = sci->LocationFromPosition(startPos); int width = SendScintilla(SCI_GETCARETWIDTH); int height = SendScintilla(SCI_TEXTHEIGHT, line); return QRect(pt.x, pt.y, width, height); } case Qt::ImFont: { char fontName[64]; int style = SendScintilla(SCI_GETSTYLEAT, pos); int len = SendScintilla(SCI_STYLEGETFONT, style, (sptr_t)fontName); int size = SendScintilla(SCI_STYLEGETSIZE, style); bool italic = SendScintilla(SCI_STYLEGETITALIC, style); int weight = SendScintilla(SCI_STYLEGETBOLD, style) ? QFont::Bold : -1; return QFont(QString::fromUtf8(fontName, len), size, weight, italic); } case Qt::ImCursorPosition: { int paraStart = sci->pdoc->ParaUp(pos); return pos - paraStart; } case Qt::ImSurroundingText: { int paraStart = sci->pdoc->ParaUp(pos); int paraEnd = sci->pdoc->ParaDown(pos); QVarLengthArray buffer(paraEnd - paraStart + 1); Sci_CharacterRange charRange; charRange.cpMin = paraStart; charRange.cpMax = paraEnd; Sci_TextRange textRange; textRange.chrg = charRange; textRange.lpstrText = buffer.data(); SendScintilla(SCI_GETTEXTRANGE, 0, (sptr_t)&textRange); return bytesAsText(buffer.constData()); } case Qt::ImCurrentSelection: { QVarLengthArray buffer(SendScintilla(SCI_GETSELTEXT)); SendScintilla(SCI_GETSELTEXT, 0, (sptr_t)buffer.data()); return bytesAsText(buffer.constData()); } default: return QVariant(); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/ListBoxQt.cpp000066400000000000000000000153741463772530400264410ustar00rootroot00000000000000// This module implements the specialisation of QListBox that handles the // Scintilla double-click callback. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "ListBoxQt.h" #include #include "SciClasses.h" #include "Qsci/qsciscintilla.h" QsciListBoxQt::QsciListBoxQt() : slb(0), visible_rows(5), utf8(false), delegate(0) { } void QsciListBoxQt::SetFont(Scintilla::Font &font) { QFont *f = reinterpret_cast(font.GetID()); if (f) slb->setFont(*f); } void QsciListBoxQt::Create(Scintilla::Window &parent, int, Scintilla::Point, int, bool unicodeMode, int) { utf8 = unicodeMode; // The parent we want is the QsciScintillaBase, not the text area. wid = slb = new QsciSciListBox(reinterpret_cast(parent.GetID())->parentWidget(), this); } void QsciListBoxQt::SetAverageCharWidth(int) { // We rely on sizeHint() for the size of the list box rather than make // calculations based on the average character width and the number of // visible rows. } void QsciListBoxQt::SetVisibleRows(int vrows) { // We only pretend to implement this. visible_rows = vrows; } int QsciListBoxQt::GetVisibleRows() const { return visible_rows; } Scintilla::PRectangle QsciListBoxQt::GetDesiredRect() { Scintilla::PRectangle rc(0, 0, 100, 100); if (slb) { QSize sh = slb->sizeHint(); rc.right = sh.width(); rc.bottom = sh.height(); } return rc; } int QsciListBoxQt::CaretFromEdge() { int dist = 0; // Find the width of the biggest image. for (xpmMap::const_iterator it = xset.begin(); it != xset.end(); ++it) { int w = it.value().width(); if (dist < w) dist = w; } if (slb) dist += slb->frameWidth(); // Fudge factor - adjust if required. dist += 3; return dist; } void QsciListBoxQt::Clear() { Q_ASSERT(slb); slb->clear(); } void QsciListBoxQt::Append(char *s, int type) { Q_ASSERT(slb); QString qs; if (utf8) qs = QString::fromUtf8(s); else qs = QString::fromLatin1(s); xpmMap::const_iterator it; if (type < 0 || (it = xset.find(type)) == xset.end()) slb->addItem(qs); else slb->addItemPixmap(it.value(), qs); } int QsciListBoxQt::Length() { Q_ASSERT(slb); return slb->count(); } void QsciListBoxQt::Select(int n) { Q_ASSERT(slb); slb->setCurrentRow(n); selectionChanged(); } int QsciListBoxQt::GetSelection() { Q_ASSERT(slb); return slb->currentRow(); } int QsciListBoxQt::Find(const char *prefix) { Q_ASSERT(slb); return slb->find(prefix); } void QsciListBoxQt::GetValue(int n, char *value, int len) { Q_ASSERT(slb); QString selection = slb->text(n); bool trim_selection = false; QObject *sci_obj = slb->parent(); if (sci_obj->inherits("QsciScintilla")) { QsciScintilla *sci = static_cast(sci_obj); if (sci->isAutoCompletionList()) { // Save the full selection and trim the value we return. sci->acSelection = selection; trim_selection = true; } } if (selection.isEmpty() || len <= 0) value[0] = '\0'; else { const char *s; int slen; QByteArray bytes; if (utf8) bytes = selection.toUtf8(); else bytes = selection.toLatin1(); s = bytes.data(); slen = bytes.length(); while (slen-- && len--) { if (trim_selection && *s == ' ') break; *value++ = *s++; } *value = '\0'; } } void QsciListBoxQt::Sort() { Q_ASSERT(slb); slb->sortItems(); } void QsciListBoxQt::RegisterImage(int type, const char *xpm_data) { xset.insert(type, *reinterpret_cast(xpm_data)); } void QsciListBoxQt::RegisterRGBAImage(int type, int, int, const unsigned char *pixelsImage) { QPixmap pm; #if QT_VERSION >= 0x040700 pm.convertFromImage(*reinterpret_cast(pixelsImage)); #else pm = QPixmap::fromImage(*reinterpret_cast(pixelsImage)); #endif xset.insert(type, pm); } void QsciListBoxQt::ClearRegisteredImages() { xset.clear(); } void QsciListBoxQt::SetDelegate(Scintilla::IListBoxDelegate *lbDelegate) { delegate = lbDelegate; } void QsciListBoxQt::handleDoubleClick() { if (delegate) { Scintilla::ListBoxEvent event( Scintilla::ListBoxEvent::EventType::doubleClick); delegate->ListNotify(&event); } } void QsciListBoxQt::handleRelease() { selectionChanged(); } void QsciListBoxQt::selectionChanged() { if (delegate) { Scintilla::ListBoxEvent event( Scintilla::ListBoxEvent::EventType::selectionChange); delegate->ListNotify(&event); } } void QsciListBoxQt::SetList(const char *list, char separator, char typesep) { char *words; Clear(); if ((words = qstrdup(list)) != NULL) { char *startword = words; char *numword = NULL; for (int i = 0; words[i] != '\0'; i++) { if (words[i] == separator) { words[i] = '\0'; if (numword) *numword = '\0'; Append(startword, numword ? atoi(numword + 1) : -1); startword = words + i + 1; numword = NULL; } else if (words[i] == typesep) { numword = words + i; } } if (startword) { if (numword) *numword = '\0'; Append(startword, numword ? atoi(numword + 1) : -1); } delete[] words; } } // The ListBox methods that need to be implemented explicitly. Scintilla::ListBox::ListBox() noexcept { } Scintilla::ListBox::~ListBox() { } Scintilla::ListBox *Scintilla::ListBox::Allocate() { return new QsciListBoxQt(); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/ListBoxQt.h000066400000000000000000000051171463772530400261000ustar00rootroot00000000000000// This defines the specialisation of QListBox that handles the Scintilla // double-click callback. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include #include #include #include "Platform.h" class QsciSciListBox; // This is an internal class but it is referenced by a public class so it has // to have a Qsci prefix rather than being put in the Scintilla namespace. // However the reason for avoiding this no longer applies. class QsciListBoxQt : public Scintilla::ListBox { public: QsciListBoxQt(); virtual void SetFont(Scintilla::Font &font); virtual void Create(Scintilla::Window &parent, int, Scintilla::Point, int, bool unicodeMode, int); virtual void SetAverageCharWidth(int); virtual void SetVisibleRows(int); virtual int GetVisibleRows() const; virtual Scintilla::PRectangle GetDesiredRect(); virtual int CaretFromEdge(); virtual void Clear(); virtual void Append(char *s, int type = -1); virtual int Length(); virtual void Select(int n); virtual int GetSelection(); virtual int Find(const char *prefix); virtual void GetValue(int n, char *value, int len); virtual void Sort(); virtual void RegisterImage(int type, const char *xpm_data); virtual void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage); virtual void ClearRegisteredImages(); virtual void SetDelegate(Scintilla::IListBoxDelegate *lbDelegate); virtual void SetList(const char *list, char separator, char typesep); void handleDoubleClick(); void handleRelease(); private: QsciSciListBox *slb; int visible_rows; bool utf8; Scintilla::IListBoxDelegate *delegate; typedef QMap xpmMap; xpmMap xset; void selectionChanged(); }; sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/MacPasteboardMime.cpp000066400000000000000000000055721463772530400300640ustar00rootroot00000000000000// This module implements part of the support for rectangular selections on // OS/X. It is a separate file to avoid clashes between OS/X and Scintilla // data types. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include #if (QT_VERSION >= 0x040200 && QT_VERSION < 0x050000 && defined(Q_OS_MAC)) || (QT_VERSION >= 0x050200 && defined(Q_OS_OSX)) #include #include #include #include #include #include #include static const QLatin1String mimeRectangular("text/x-qscintilla-rectangular"); static const QLatin1String utiRectangularMac("com.scintilla.utf16-plain-text.rectangular"); class RectangularPasteboardMime : public QMacPasteboardMime { public: RectangularPasteboardMime() : QMacPasteboardMime(MIME_ALL) { } bool canConvert(const QString &mime, QString flav) { return mime == mimeRectangular && flav == utiRectangularMac; } QList convertFromMime(const QString &, QVariant data, QString) { QList converted; converted.append(data.toByteArray()); return converted; } QVariant convertToMime(const QString &, QList data, QString) { QByteArray converted; foreach (QByteArray i, data) { converted += i; } return QVariant(converted); } QString convertorName() { return QString("QScintillaRectangular"); } QString flavorFor(const QString &mime) { if (mime == mimeRectangular) return QString(utiRectangularMac); return QString(); } QString mimeFor(QString flav) { if (flav == utiRectangularMac) return QString(mimeRectangular); return QString(); } }; // Initialise the singleton instance. void initialiseRectangularPasteboardMime() { static RectangularPasteboardMime *instance = 0; if (!instance) { instance = new RectangularPasteboardMime(); qRegisterDraggedTypes(QStringList(utiRectangularMac)); } } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/PlatQt.cpp000066400000000000000000000557541463772530400257630ustar00rootroot00000000000000// This module implements the portability layer for the Qt port of Scintilla. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "XPM.h" #include "Qsci/qsciscintillabase.h" #include "SciClasses.h" #include "FontQuality.h" namespace Scintilla { // Type convertors. static QFont *PFont(FontID fid) { return reinterpret_cast(fid); } static QWidget *PWindow(WindowID wid) { return reinterpret_cast(wid); } static QsciSciPopup *PMenu(MenuID mid) { return reinterpret_cast(mid); } // Font management. Font::Font() noexcept : fid(0) { } Font::~Font() { } void Font::Create(const FontParameters &fp) { Release(); QFont *f = new QFont(); QFont::StyleStrategy strategy; switch (fp.extraFontFlag & SC_EFF_QUALITY_MASK) { case SC_EFF_QUALITY_NON_ANTIALIASED: strategy = QFont::NoAntialias; break; case SC_EFF_QUALITY_ANTIALIASED: strategy = QFont::PreferAntialias; break; default: strategy = QFont::PreferDefault; } #if defined(Q_OS_MAC) && QT_VERSION < 0x050000 #if QT_VERSION >= 0x040700 strategy = static_cast(strategy | QFont::ForceIntegerMetrics); #else #warning "Correct handling of QFont metrics requires Qt v4.7.0 or later" #endif #endif f->setStyleStrategy(strategy); // If name of the font begins with a '-', assume, that it is an XLFD. if (fp.faceName[0] == '-') { f->setRawName(fp.faceName); } else { f->setFamily(fp.faceName); f->setPointSizeF(fp.size); // See if the Qt weight has been passed via the back door. Otherwise // map Scintilla weights to Qt weights ensuring that the SC_WEIGHT_* // values get mapped to the correct QFont::Weight values. int qt_weight; if (fp.weight < 0) qt_weight = -fp.weight; else if (fp.weight <= 200) qt_weight = QFont::Light; else if (fp.weight <= QsciScintillaBase::SC_WEIGHT_NORMAL) qt_weight = QFont::Normal; else if (fp.weight <= 600) qt_weight = QFont::DemiBold; else if (fp.weight <= 850) qt_weight = QFont::Bold; else qt_weight = QFont::Black; f->setWeight(qt_weight); f->setItalic(fp.italic); } fid = f; } void Font::Release() { if (fid) { delete PFont(fid); fid = 0; } } // A surface abstracts a place to draw. class SurfaceImpl : public Surface { public: SurfaceImpl(); virtual ~SurfaceImpl(); void Init(WindowID wid); void Init(SurfaceID sid, WindowID); void Init(QPainter *p); void InitPixMap(int width, int height, Surface *sid, WindowID wid); void Release(); bool Initialised() {return painter;} void PenColour(ColourDesired fore); int LogPixelsY() {return pd->logicalDpiY();} int DeviceHeightFont(int points) {return points;} void MoveTo(int x_,int y_); void LineTo(int x_,int y_); void Polygon(Point *pts, size_t npts, ColourDesired fore, ColourDesired back); void RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back); void FillRectangle(PRectangle rc, ColourDesired back); void FillRectangle(PRectangle rc, Surface &surfacePattern); void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back); void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, ColourDesired outline, int alphaOutline, int flags); void GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options); void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage); void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back); void Copy(PRectangle rc, Point from, Surface &surfaceSource); void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back); void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back); void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore); void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions); XYPOSITION WidthText(Font &font_, const char *s, int len); XYPOSITION Ascent(Font &font_); XYPOSITION Descent(Font &font_); XYPOSITION InternalLeading(Font &font_) {Q_UNUSED(font_); return 0;} XYPOSITION Height(Font &font_); XYPOSITION AverageCharWidth(Font &font_); void SetClip(PRectangle rc); void FlushCachedState(); void SetUnicodeMode(bool unicodeMode_) {unicodeMode = unicodeMode_;} void SetDBCSMode(int codePage) {Q_UNUSED(codePage);} void DrawXPM(PRectangle rc, const XPM *xpm); private: void drawRect(const PRectangle &rc); void drawText(const PRectangle &rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore); static QFont convertQFont(Font &font); QFontMetricsF metrics(Font &font_); QString convertText(const char *s, int len); static QColor convertQColor(const ColourDesired &col, unsigned alpha = 255); bool unicodeMode; QPaintDevice *pd; QPainter *painter; bool my_resources; int pen_x, pen_y; }; Surface *Surface::Allocate(int) { return new SurfaceImpl; } SurfaceImpl::SurfaceImpl() : unicodeMode(false), pd(0), painter(0), my_resources(false), pen_x(0), pen_y(0) { } SurfaceImpl::~SurfaceImpl() { Release(); } void SurfaceImpl::Init(WindowID wid) { Release(); pd = reinterpret_cast(wid); } void SurfaceImpl::Init(SurfaceID sid, WindowID) { Release(); // This method, and the SurfaceID type, is only used when printing. As it // is actually a void * we pass (when using SCI_FORMATRANGE) a pointer to a // QPainter rather than a pointer to a SurfaceImpl as might be expected. QPainter *p = reinterpret_cast(sid); pd = p->device(); painter = p; } void SurfaceImpl::Init(QPainter *p) { Release(); pd = p->device(); painter = p; } void SurfaceImpl::InitPixMap(int width, int height, Surface *sid, WindowID wid) { Release(); #if QT_VERSION >= 0x050100 int dpr = PWindow(wid)->devicePixelRatio(); QPixmap *pixmap = new QPixmap(width * dpr, height * dpr); pixmap->setDevicePixelRatio(dpr); #else QPixmap *pixmap = new QPixmap(width, height); Q_UNUSED(wid); #endif pd = pixmap; painter = new QPainter(pd); my_resources = true; SetUnicodeMode(static_cast(sid)->unicodeMode); } void SurfaceImpl::Release() { if (my_resources) { if (painter) delete painter; if (pd) delete pd; my_resources = false; } painter = 0; pd = 0; } void SurfaceImpl::MoveTo(int x_, int y_) { Q_ASSERT(painter); pen_x = x_; pen_y = y_; } void SurfaceImpl::LineTo(int x_, int y_) { Q_ASSERT(painter); painter->drawLine(pen_x, pen_y, x_, y_); pen_x = x_; pen_y = y_; } void SurfaceImpl::PenColour(ColourDesired fore) { Q_ASSERT(painter); painter->setPen(convertQColor(fore)); } void SurfaceImpl::Polygon(Point *pts, size_t npts, ColourDesired fore, ColourDesired back) { Q_ASSERT(painter); QPolygonF qpts(npts); for (size_t i = 0; i < npts; ++i) qpts[i] = QPointF(pts[i].x, pts[i].y); painter->setPen(convertQColor(fore)); painter->setBrush(convertQColor(back)); painter->drawPolygon(qpts); } void SurfaceImpl::RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back) { Q_ASSERT(painter); painter->setPen(convertQColor(fore)); painter->setBrush(convertQColor(back)); drawRect(rc); } void SurfaceImpl::FillRectangle(PRectangle rc, ColourDesired back) { Q_ASSERT(painter); painter->setPen(Qt::NoPen); painter->setBrush(convertQColor(back)); drawRect(rc); } void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { Q_ASSERT(painter); SurfaceImpl &si = static_cast(surfacePattern); QPixmap *pm = static_cast(si.pd); if (pm) { QBrush brsh(Qt::black, *pm); painter->setPen(Qt::NoPen); painter->setBrush(brsh); drawRect(rc); } else { FillRectangle(rc, ColourDesired(0)); } } void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) { Q_ASSERT(painter); painter->setPen(convertQColor(fore)); painter->setBrush(convertQColor(back)); painter->drawRoundRect( QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top)); } void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, ColourDesired outline, int alphaOutline, int) { Q_ASSERT(painter); QColor outline_colour = convertQColor(outline, alphaOutline); QColor fill_colour = convertQColor(fill, alphaFill); // There was a report of Qt seeming to ignore the alpha value of the pen so // so we disable the pen if the outline and fill colours are the same. if (outline_colour == fill_colour) painter->setPen(Qt::NoPen); else painter->setPen(outline_colour); painter->setBrush(fill_colour); const int radius = (cornerSize ? 25 : 0); painter->drawRoundRect( QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top), radius, radius); } void SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options) { Q_ASSERT(painter); QLinearGradient gradient; switch (options) { case GradientOptions::leftToRight: gradient = QLinearGradient(rc.left, rc.top, rc.right, rc.top); break; case GradientOptions::topToBottom: default: gradient = QLinearGradient(rc.left, rc.top, rc.left, rc.bottom); } gradient.setSpread(QGradient::RepeatSpread); for (const ColourStop &stop : stops) gradient.setColorAt(stop.position, convertQColor(stop.colour, stop.colour.GetAlpha())); painter->fillRect( QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top), QBrush(gradient)); } void SurfaceImpl::drawRect(const PRectangle &rc) { painter->drawRect( QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top)); } void SurfaceImpl::Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) { Q_ASSERT(painter); painter->setPen(convertQColor(fore)); painter->setBrush(convertQColor(back)); painter->drawEllipse( QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top)); } void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { Q_ASSERT(painter); SurfaceImpl &si = static_cast(surfaceSource); if (si.pd) { QPixmap *pm = static_cast(si.pd); qreal x = from.x; qreal y = from.y; qreal width = rc.right - rc.left; qreal height = rc.bottom - rc.top; #if QT_VERSION >= 0x050100 qreal dpr = pm->devicePixelRatio(); x *= dpr; y *= dpr; width *= dpr; height *= dpr; #endif painter->drawPixmap(QPointF(rc.left, rc.top), *pm, QRectF(x, y, width, height)); } } void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) { Q_ASSERT(painter); FillRectangle(rc, back); drawText(rc, font_, ybase, s, len, fore); } void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) { Q_ASSERT(painter); SetClip(rc); DrawTextNoClip(rc, font_, ybase, s, len, fore, back); painter->setClipping(false); } void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore) { // Only draw if there is a non-space. for (int i = 0; i < len; ++i) if (s[i] != ' ') { drawText(rc, font_, ybase, s, len, fore); return; } } void SurfaceImpl::drawText(const PRectangle &rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore) { QString qs = convertText(s, len); QFont *f = PFont(font_.GetID()); if (f) painter->setFont(*f); painter->setPen(convertQColor(fore)); painter->drawText(QPointF(rc.left, ybase), qs); } void SurfaceImpl::DrawXPM(PRectangle rc, const XPM *xpm) { Q_ASSERT(painter); XYPOSITION x, y; const QPixmap &qpm = xpm->Pixmap(); x = rc.left + (rc.Width() - qpm.width()) / 2.0; y = rc.top + (rc.Height() - qpm.height()) / 2.0; painter->drawPixmap(QPointF(x, y), qpm); } void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { Q_UNUSED(width); Q_UNUSED(height); Q_ASSERT(painter); const QImage *qim = reinterpret_cast(pixelsImage); painter->drawImage(QPointF(rc.left, rc.top), *qim); } void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) { QString qs = convertText(s, len); QTextLayout text_layout(qs, convertQFont(font_), pd); text_layout.beginLayout(); QTextLine text_line = text_layout.createLine(); text_layout.endLayout(); if (unicodeMode) { int i_char = 0, i_byte = 0;; while (i_char < qs.size()) { unsigned char byte = s[i_byte]; int nbytes, code_units; // Work out character sizes by looking at the byte stream. if (byte >= 0xf0) { nbytes = 4; code_units = 2; } else { if (byte >= 0xe0) nbytes = 3; else if (byte >= 0x80) nbytes = 2; else nbytes = 1; code_units = 1; } XYPOSITION position = text_line.cursorToX(i_char + code_units); // Set the same position for each byte of the character. for (int i = 0; i < nbytes && i_byte < len; ++i) positions[i_byte++] = position; i_char += code_units; } // This shouldn't be necessary... XYPOSITION last_position = ((i_byte > 0) ? positions[i_byte - 1] : 0); while (i_byte < len) positions[i_byte++] = last_position; } else { for (int i = 0; i < len; ++i) positions[i] = text_line.cursorToX(i + 1); } } XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) { return metrics(font_).width(convertText(s, len)); } XYPOSITION SurfaceImpl::Ascent(Font &font_) { return metrics(font_).ascent(); } XYPOSITION SurfaceImpl::Descent(Font &font_) { // Qt doesn't include the baseline in the descent, so add it. Note that // a descent from Qt4 always seems to be 2 pixels larger (irrespective of // font or size) than the same descent from Qt3. This means that text is a // little more spaced out with Qt4 - and will be more noticeable with // smaller fonts. return metrics(font_).descent() + 1; } XYPOSITION SurfaceImpl::Height(Font &font_) { return metrics(font_).height(); } XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { #if QT_VERSION >= 0x040200 return metrics(font_).averageCharWidth(); #else return metrics(font_).width('n'); #endif } void SurfaceImpl::SetClip(PRectangle rc) { Q_ASSERT(painter); painter->setClipRect( QRectF(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top)); } void SurfaceImpl::FlushCachedState() { } // Return the QFont for a Font. QFont SurfaceImpl::convertQFont(Font &font) { QFont *f = PFont(font.GetID()); if (f) return *f; return QApplication::font(); } // Get the metrics for a font. QFontMetricsF SurfaceImpl::metrics(Font &font_) { QFont fnt = convertQFont(font_); return QFontMetricsF(fnt, pd); } // Convert a Scintilla string to a Qt Unicode string. QString SurfaceImpl::convertText(const char *s, int len) { if (unicodeMode) return QString::fromUtf8(s, len); return QString::fromLatin1(s, len); } // Convert a Scintilla colour, and alpha component, to a Qt QColor. QColor SurfaceImpl::convertQColor(const ColourDesired &col, unsigned alpha) { int c = col.AsInteger(); unsigned r = c & 0xff; unsigned g = (c >> 8) & 0xff; unsigned b = (c >> 16) & 0xff; return QColor(r, g, b, alpha); } // Window (widget) management. Window::~Window() { } void Window::Destroy() { QWidget *w = PWindow(wid); if (w) { // Delete the widget next time round the event loop rather than // straight away. This gets round a problem when auto-completion lists // are cancelled after an entry has been double-clicked, ie. the list's // dtor is called from one of the list's slots. There are other ways // around the problem but this is the simplest and doesn't seem to // cause problems of its own. w->deleteLater(); wid = 0; } } PRectangle Window::GetPosition() const { QWidget *w = PWindow(wid); // Before any size allocated pretend its big enough not to be scrolled. PRectangle rc(0,0,5000,5000); if (w) { const QRect &r = w->geometry(); rc.right = r.right() - r.left() + 1; rc.bottom = r.bottom() - r.top() + 1; } return rc; } void Window::SetPosition(PRectangle rc) { PWindow(wid)->setGeometry(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); } void Window::SetPositionRelative(PRectangle rc, const Window *relativeTo) { QWidget *rel = PWindow(relativeTo->wid); QPoint pos = rel->mapToGlobal(rel->pos()); int x = pos.x() + rc.left; int y = pos.y() + rc.top; PWindow(wid)->setGeometry(x, y, rc.right - rc.left, rc.bottom - rc.top); } PRectangle Window::GetClientPosition() const { return GetPosition(); } void Window::Show(bool show) { QWidget *w = PWindow(wid); if (show) w->show(); else w->hide(); } void Window::InvalidateAll() { QWidget *w = PWindow(wid); if (w) w->update(); } void Window::InvalidateRectangle(PRectangle rc) { QWidget *w = PWindow(wid); if (w) w->update(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); } void Window::SetFont(Font &font) { PWindow(wid)->setFont(*PFont(font.GetID())); } void Window::SetCursor(Cursor curs) { Qt::CursorShape qc; switch (curs) { case cursorText: qc = Qt::IBeamCursor; break; case cursorUp: qc = Qt::UpArrowCursor; break; case cursorWait: qc = Qt::WaitCursor; break; case cursorHoriz: qc = Qt::SizeHorCursor; break; case cursorVert: qc = Qt::SizeVerCursor; break; case cursorHand: qc = Qt::PointingHandCursor; break; default: // Note that Qt doesn't have a standard cursor that could be used to // implement cursorReverseArrow. qc = Qt::ArrowCursor; } PWindow(wid)->setCursor(qc); } PRectangle Window::GetMonitorRect(Point pt) { QPoint qpt = PWindow(wid)->mapToGlobal(QPoint(pt.x, pt.y)); QRect qr = QApplication::desktop()->availableGeometry(qpt); qpt = PWindow(wid)->mapFromGlobal(qr.topLeft()); return PRectangle(qpt.x(), qpt.y(), qpt.x() + qr.width(), qpt.y() + qr.height()); } // Menu management. Menu::Menu() noexcept : mid(0) { } void Menu::CreatePopUp() { Destroy(); mid = new QsciSciPopup(); } void Menu::Destroy() { QsciSciPopup *m = PMenu(mid); if (m) { delete m; mid = 0; } } void Menu::Show(Point pt, Window &) { PMenu(mid)->popup(QPoint(pt.x, pt.y)); } class DynamicLibraryImpl : public DynamicLibrary { public: DynamicLibraryImpl(const char *modulePath) { m = new QLibrary(modulePath); m->load(); } virtual ~DynamicLibraryImpl() { if (m) delete m; } virtual Function FindFunction(const char *name) { if (m) return (Function)m->resolve(name); return 0; } virtual bool IsValid() { return m && m->isLoaded(); } private: QLibrary* m; }; DynamicLibrary *DynamicLibrary::Load(const char *modulePath) { return new DynamicLibraryImpl(modulePath); } // Manage system wide parameters. ColourDesired Platform::Chrome() { return ColourDesired(0xe0,0xe0,0xe0); } ColourDesired Platform::ChromeHighlight() { return ColourDesired(0xff,0xff,0xff); } const char *Platform::DefaultFont() { static QByteArray def_font; def_font = QApplication::font().family().toLatin1(); return def_font.constData(); } int Platform::DefaultFontSize() { return QApplication::font().pointSize(); } unsigned int Platform::DoubleClickTime() { return QApplication::doubleClickInterval(); } void Platform::DebugDisplay(const char *s) { qDebug("%s", s); } //#define TRACE #ifdef TRACE void Platform::DebugPrintf(const char *format, ...) { char buffer[2000]; va_list pArguments; va_start(pArguments, format); vsprintf(buffer, format, pArguments); va_end(pArguments); DebugDisplay(buffer); } #else void Platform::DebugPrintf(const char *, ...) { } #endif static bool assertionPopUps = true; bool Platform::ShowAssertionPopUps(bool assertionPopUps_) { bool ret = assertionPopUps; assertionPopUps = assertionPopUps_; return ret; } void Platform::Assert(const char *c, const char *file, int line) { qFatal("Assertion [%s] failed at %s %d\n", c, file, line); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/000077500000000000000000000000001463772530400247315ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qsciabstractapis.h000066400000000000000000000070531463772530400304470ustar00rootroot00000000000000// This module defines interface to the QsciAbstractAPIs class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCIABSTRACTAPIS_H #define QSCIABSTRACTAPIS_H #include #include #include #include #include class QsciLexer; //! \brief The QsciAbstractAPIs class represents the interface to the textual //! API information used in call tips and for auto-completion. A sub-class //! will provide the actual implementation of the interface. //! //! API information is specific to a particular language lexer but can be //! shared by multiple instances of the lexer. class QSCINTILLA_EXPORT QsciAbstractAPIs : public QObject { Q_OBJECT public: //! Constructs a QsciAbstractAPIs instance attached to lexer \a lexer. \a //! lexer becomes the instance's parent object although the instance can //! also be subsequently attached to other lexers. QsciAbstractAPIs(QsciLexer *lexer); //! Destroy the QsciAbstractAPIs instance. virtual ~QsciAbstractAPIs(); //! Return the lexer that the instance is attached to. QsciLexer *lexer() const; //! Update the list \a list with API entries derived from \a context. \a //! context is the list of words in the text preceding the cursor position. //! The characters that make up a word and the characters that separate //! words are defined by the lexer. The last word is a partial word and //! may be empty if the user has just entered a word separator. virtual void updateAutoCompletionList(const QStringList &context, QStringList &list) = 0; //! This is called when the user selects the entry \a selection from the //! auto-completion list. A sub-class can use this as a hint to provide //! more specific API entries in future calls to //! updateAutoCompletionList(). The default implementation does nothing. virtual void autoCompletionSelected(const QString &selection); //! Return the call tips valid for the context \a context. (Note that the //! last word of the context will always be empty.) \a commas is the number //! of commas the user has typed after the context and before the cursor //! position. The exact position of the list of call tips can be adjusted //! by specifying a corresponding left character shift in \a shifts. This //! is normally done to correct for any displayed context according to \a //! style. //! //! \sa updateAutoCompletionList() virtual QStringList callTips(const QStringList &context, int commas, QsciScintilla::CallTipsStyle style, QList &shifts) = 0; private: QsciLexer *lex; QsciAbstractAPIs(const QsciAbstractAPIs &); QsciAbstractAPIs &operator=(const QsciAbstractAPIs &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qsciapis.h000066400000000000000000000201561463772530400267220ustar00rootroot00000000000000// This module defines interface to the QsciAPIs class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCIAPIS_H #define QSCIAPIS_H #include #include #include #include #include #include #include class QsciAPIsPrepared; class QsciAPIsWorker; class QsciLexer; //! \brief The QsciAPIs class provies an implementation of the textual API //! information used in call tips and for auto-completion. //! //! Raw API information is read from one or more files. Each API function is //! described by a single line of text comprising the function's name, followed //! by the function's optional comma separated parameters enclosed in //! parenthesis, and finally followed by optional explanatory text. //! //! A function name may be followed by a `?' and a number. The number is used //! by auto-completion to display a registered QPixmap with the function name. //! //! All function names are used by auto-completion, but only those that include //! function parameters are used in call tips. //! //! QScintilla only deals with prepared API information and not the raw //! information described above. This is done so that large APIs can be //! handled while still being responsive to user input. The conversion of raw //! information to prepared information is time consuming (think tens of //! seconds) and implemented in a separate thread. Prepared information can //! be quickly saved to and loaded from files. Such files are portable between //! different architectures. //! //! QScintilla based applications that want to support large APIs would //! normally provide the user with the ability to specify a set of, possibly //! project specific, raw API files and convert them to prepared files that are //! loaded quickly when the application is invoked. class QSCINTILLA_EXPORT QsciAPIs : public QsciAbstractAPIs { Q_OBJECT public: //! Constructs a QsciAPIs instance attached to lexer \a lexer. \a lexer //! becomes the instance's parent object although the instance can also be //! subsequently attached to other lexers. QsciAPIs(QsciLexer *lexer); //! Destroy the QsciAPIs instance. virtual ~QsciAPIs(); //! Add the single raw API entry \a entry to the current set. //! //! \sa clear(), load(), remove() void add(const QString &entry); //! Deletes all raw API information. //! //! \sa add(), load(), remove() void clear(); //! Load the API information from the file named \a filename, adding it to //! the current set. Returns true if successful, otherwise false. bool load(const QString &filename); //! Remove the single raw API entry \a entry from the current set. //! //! \sa add(), clear(), load() void remove(const QString &entry); //! Convert the current raw API information to prepared API information. //! This is implemented by a separate thread. //! //! \sa cancelPreparation() void prepare(); //! Cancel the conversion of the current raw API information to prepared //! API information. //! //! \sa prepare() void cancelPreparation(); //! Return the default name of the prepared API information file. It is //! based on the name of the associated lexer and in the directory defined //! by the QSCIDIR environment variable. If the environment variable isn't //! set then $HOME/.qsci is used. QString defaultPreparedName() const; //! Check to see is a prepared API information file named \a filename //! exists. If \a filename is empty then the value returned by //! defaultPreparedName() is used. Returns true if successful, otherwise //! false. //! //! \sa defaultPreparedName() bool isPrepared(const QString &filename = QString()) const; //! Load the prepared API information from the file named \a filename. If //! \a filename is empty then a name is constructed based on the name of //! the associated lexer and saved in the directory defined by the QSCIDIR //! environment variable. If the environment variable isn't set then //! $HOME/.qsci is used. Returns true if successful, otherwise false. bool loadPrepared(const QString &filename = QString()); //! Save the prepared API information to the file named \a filename. If //! \a filename is empty then a name is constructed based on the name of //! the associated lexer and saved in the directory defined by the QSCIDIR //! environment variable. If the environment variable isn't set then //! $HOME/.qsci is used. Returns true if successful, otherwise false. bool savePrepared(const QString &filename = QString()) const; //! \reimp virtual void updateAutoCompletionList(const QStringList &context, QStringList &list); //! \reimp virtual void autoCompletionSelected(const QString &sel); //! \reimp virtual QStringList callTips(const QStringList &context, int commas, QsciScintilla::CallTipsStyle style, QList &shifts); //! \internal Reimplemented to receive termination events from the worker //! thread. virtual bool event(QEvent *e); //! Return a list of the installed raw API file names for the associated //! lexer. QStringList installedAPIFiles() const; signals: //! This signal is emitted when the conversion of raw API information to //! prepared API information has been cancelled. //! //! \sa apiPreparationFinished(), apiPreparationStarted() void apiPreparationCancelled(); //! This signal is emitted when the conversion of raw API information to //! prepared API information starts and can be used to give some visual //! feedback to the user. //! //! \sa apiPreparationCancelled(), apiPreparationFinished() void apiPreparationStarted(); //! This signal is emitted when the conversion of raw API information to //! prepared API information has finished. //! //! \sa apiPreparationCancelled(), apiPreparationStarted() void apiPreparationFinished(); private: friend class QsciAPIsPrepared; friend class QsciAPIsWorker; // This indexes a word in a set of raw APIs. The first part indexes the // entry in the set, the second part indexes the word within the entry. typedef QPair WordIndex; // This is a list of word indexes. typedef QList WordIndexList; QsciAPIsWorker *worker; QStringList old_context; QStringList::const_iterator origin; int origin_len; QString unambiguous_context; QStringList apis; QsciAPIsPrepared *prep; static bool enoughCommas(const QString &s, int commas); QStringList positionOrigin(const QStringList &context, QString &path); bool originStartsWith(const QString &path, const QString &wsep); const WordIndexList *wordIndexOf(const QString &word) const; void lastCompleteWord(const QString &word, QStringList &with_context, bool &unambig); void lastPartialWord(const QString &word, QStringList &with_context, bool &unambig); void addAPIEntries(const WordIndexList &wl, bool complete, QStringList &with_context, bool &unambig); QString prepName(const QString &filename, bool mkpath = false) const; void deleteWorker(); QsciAPIs(const QsciAPIs &); QsciAPIs &operator=(const QsciAPIs &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscicommand.h000066400000000000000000000350431463772530400274050ustar00rootroot00000000000000// This defines the interface to the QsciCommand class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCICOMMAND_H #define QSCICOMMAND_H #include #include #include class QsciScintilla; //! \brief The QsciCommand class represents an internal editor command that may //! have one or two keys bound to it. //! //! Methods are provided to change the keys bound to the command and to remove //! a key binding. Each command has a user friendly description of the command //! for use in key mapping dialogs. class QSCINTILLA_EXPORT QsciCommand { public: //! This enum defines the different commands that can be assigned to a key. enum Command { //! Move down one line. LineDown = QsciScintillaBase::SCI_LINEDOWN, //! Extend the selection down one line. LineDownExtend = QsciScintillaBase::SCI_LINEDOWNEXTEND, //! Extend the rectangular selection down one line. LineDownRectExtend = QsciScintillaBase::SCI_LINEDOWNRECTEXTEND, //! Scroll the view down one line. LineScrollDown = QsciScintillaBase::SCI_LINESCROLLDOWN, //! Move up one line. LineUp = QsciScintillaBase::SCI_LINEUP, //! Extend the selection up one line. LineUpExtend = QsciScintillaBase::SCI_LINEUPEXTEND, //! Extend the rectangular selection up one line. LineUpRectExtend = QsciScintillaBase::SCI_LINEUPRECTEXTEND, //! Scroll the view up one line. LineScrollUp = QsciScintillaBase::SCI_LINESCROLLUP, //! Scroll to the start of the document. ScrollToStart = QsciScintillaBase::SCI_SCROLLTOSTART, //! Scroll to the end of the document. ScrollToEnd = QsciScintillaBase::SCI_SCROLLTOEND, //! Scroll vertically to centre the current line. VerticalCentreCaret = QsciScintillaBase::SCI_VERTICALCENTRECARET, //! Move down one paragraph. ParaDown = QsciScintillaBase::SCI_PARADOWN, //! Extend the selection down one paragraph. ParaDownExtend = QsciScintillaBase::SCI_PARADOWNEXTEND, //! Move up one paragraph. ParaUp = QsciScintillaBase::SCI_PARAUP, //! Extend the selection up one paragraph. ParaUpExtend = QsciScintillaBase::SCI_PARAUPEXTEND, //! Move left one character. CharLeft = QsciScintillaBase::SCI_CHARLEFT, //! Extend the selection left one character. CharLeftExtend = QsciScintillaBase::SCI_CHARLEFTEXTEND, //! Extend the rectangular selection left one character. CharLeftRectExtend = QsciScintillaBase::SCI_CHARLEFTRECTEXTEND, //! Move right one character. CharRight = QsciScintillaBase::SCI_CHARRIGHT, //! Extend the selection right one character. CharRightExtend = QsciScintillaBase::SCI_CHARRIGHTEXTEND, //! Extend the rectangular selection right one character. CharRightRectExtend = QsciScintillaBase::SCI_CHARRIGHTRECTEXTEND, //! Move left one word. WordLeft = QsciScintillaBase::SCI_WORDLEFT, //! Extend the selection left one word. WordLeftExtend = QsciScintillaBase::SCI_WORDLEFTEXTEND, //! Move right one word. WordRight = QsciScintillaBase::SCI_WORDRIGHT, //! Extend the selection right one word. WordRightExtend = QsciScintillaBase::SCI_WORDRIGHTEXTEND, //! Move to the end of the previous word. WordLeftEnd = QsciScintillaBase::SCI_WORDLEFTEND, //! Extend the selection to the end of the previous word. WordLeftEndExtend = QsciScintillaBase::SCI_WORDLEFTENDEXTEND, //! Move to the end of the next word. WordRightEnd = QsciScintillaBase::SCI_WORDRIGHTEND, //! Extend the selection to the end of the next word. WordRightEndExtend = QsciScintillaBase::SCI_WORDRIGHTENDEXTEND, //! Move left one word part. WordPartLeft = QsciScintillaBase::SCI_WORDPARTLEFT, //! Extend the selection left one word part. WordPartLeftExtend = QsciScintillaBase::SCI_WORDPARTLEFTEXTEND, //! Move right one word part. WordPartRight = QsciScintillaBase::SCI_WORDPARTRIGHT, //! Extend the selection right one word part. WordPartRightExtend = QsciScintillaBase::SCI_WORDPARTRIGHTEXTEND, //! Move to the start of the document line. Home = QsciScintillaBase::SCI_HOME, //! Extend the selection to the start of the document line. HomeExtend = QsciScintillaBase::SCI_HOMEEXTEND, //! Extend the rectangular selection to the start of the document line. HomeRectExtend = QsciScintillaBase::SCI_HOMERECTEXTEND, //! Move to the start of the displayed line. HomeDisplay = QsciScintillaBase::SCI_HOMEDISPLAY, //! Extend the selection to the start of the displayed line. HomeDisplayExtend = QsciScintillaBase::SCI_HOMEDISPLAYEXTEND, //! Move to the start of the displayed or document line. HomeWrap = QsciScintillaBase::SCI_HOMEWRAP, //! Extend the selection to the start of the displayed or document //! line. HomeWrapExtend = QsciScintillaBase::SCI_HOMEWRAPEXTEND, //! Move to the first visible character in the document line. VCHome = QsciScintillaBase::SCI_VCHOME, //! Extend the selection to the first visible character in the document //! line. VCHomeExtend = QsciScintillaBase::SCI_VCHOMEEXTEND, //! Extend the rectangular selection to the first visible character in //! the document line. VCHomeRectExtend = QsciScintillaBase::SCI_VCHOMERECTEXTEND, //! Move to the first visible character of the displayed or document //! line. VCHomeWrap = QsciScintillaBase::SCI_VCHOMEWRAP, //! Extend the selection to the first visible character of the //! displayed or document line. VCHomeWrapExtend = QsciScintillaBase::SCI_VCHOMEWRAPEXTEND, //! Move to the end of the document line. LineEnd = QsciScintillaBase::SCI_LINEEND, //! Extend the selection to the end of the document line. LineEndExtend = QsciScintillaBase::SCI_LINEENDEXTEND, //! Extend the rectangular selection to the end of the document line. LineEndRectExtend = QsciScintillaBase::SCI_LINEENDRECTEXTEND, //! Move to the end of the displayed line. LineEndDisplay = QsciScintillaBase::SCI_LINEENDDISPLAY, //! Extend the selection to the end of the displayed line. LineEndDisplayExtend = QsciScintillaBase::SCI_LINEENDDISPLAYEXTEND, //! Move to the end of the displayed or document line. LineEndWrap = QsciScintillaBase::SCI_LINEENDWRAP, //! Extend the selection to the end of the displayed or document line. LineEndWrapExtend = QsciScintillaBase::SCI_LINEENDWRAPEXTEND, //! Move to the start of the document. DocumentStart = QsciScintillaBase::SCI_DOCUMENTSTART, //! Extend the selection to the start of the document. DocumentStartExtend = QsciScintillaBase::SCI_DOCUMENTSTARTEXTEND, //! Move to the end of the document. DocumentEnd = QsciScintillaBase::SCI_DOCUMENTEND, //! Extend the selection to the end of the document. DocumentEndExtend = QsciScintillaBase::SCI_DOCUMENTENDEXTEND, //! Move up one page. PageUp = QsciScintillaBase::SCI_PAGEUP, //! Extend the selection up one page. PageUpExtend = QsciScintillaBase::SCI_PAGEUPEXTEND, //! Extend the rectangular selection up one page. PageUpRectExtend = QsciScintillaBase::SCI_PAGEUPRECTEXTEND, //! Move down one page. PageDown = QsciScintillaBase::SCI_PAGEDOWN, //! Extend the selection down one page. PageDownExtend = QsciScintillaBase::SCI_PAGEDOWNEXTEND, //! Extend the rectangular selection down one page. PageDownRectExtend = QsciScintillaBase::SCI_PAGEDOWNRECTEXTEND, //! Stuttered move up one page. StutteredPageUp = QsciScintillaBase::SCI_STUTTEREDPAGEUP, //! Stuttered extend the selection up one page. StutteredPageUpExtend = QsciScintillaBase::SCI_STUTTEREDPAGEUPEXTEND, //! Stuttered move down one page. StutteredPageDown = QsciScintillaBase::SCI_STUTTEREDPAGEDOWN, //! Stuttered extend the selection down one page. StutteredPageDownExtend = QsciScintillaBase::SCI_STUTTEREDPAGEDOWNEXTEND, //! Delete the current character. Delete = QsciScintillaBase::SCI_CLEAR, //! Delete the previous character. DeleteBack = QsciScintillaBase::SCI_DELETEBACK, //! Delete the previous character if not at start of line. DeleteBackNotLine = QsciScintillaBase::SCI_DELETEBACKNOTLINE, //! Delete the word to the left. DeleteWordLeft = QsciScintillaBase::SCI_DELWORDLEFT, //! Delete the word to the right. DeleteWordRight = QsciScintillaBase::SCI_DELWORDRIGHT, //! Delete right to the end of the next word. DeleteWordRightEnd = QsciScintillaBase::SCI_DELWORDRIGHTEND, //! Delete the line to the left. DeleteLineLeft = QsciScintillaBase::SCI_DELLINELEFT, //! Delete the line to the right. DeleteLineRight = QsciScintillaBase::SCI_DELLINERIGHT, //! Delete the current line. LineDelete = QsciScintillaBase::SCI_LINEDELETE, //! Cut the current line to the clipboard. LineCut = QsciScintillaBase::SCI_LINECUT, //! Copy the current line to the clipboard. LineCopy = QsciScintillaBase::SCI_LINECOPY, //! Transpose the current and previous lines. LineTranspose = QsciScintillaBase::SCI_LINETRANSPOSE, //! Duplicate the current line. LineDuplicate = QsciScintillaBase::SCI_LINEDUPLICATE, //! Select the whole document. SelectAll = QsciScintillaBase::SCI_SELECTALL, //! Move the selected lines up one line. MoveSelectedLinesUp = QsciScintillaBase::SCI_MOVESELECTEDLINESUP, //! Move the selected lines down one line. MoveSelectedLinesDown = QsciScintillaBase::SCI_MOVESELECTEDLINESDOWN, //! Duplicate the selection. SelectionDuplicate = QsciScintillaBase::SCI_SELECTIONDUPLICATE, //! Convert the selection to lower case. SelectionLowerCase = QsciScintillaBase::SCI_LOWERCASE, //! Convert the selection to upper case. SelectionUpperCase = QsciScintillaBase::SCI_UPPERCASE, //! Cut the selection to the clipboard. SelectionCut = QsciScintillaBase::SCI_CUT, //! Copy the selection to the clipboard. SelectionCopy = QsciScintillaBase::SCI_COPY, //! Paste from the clipboard. Paste = QsciScintillaBase::SCI_PASTE, //! Toggle insert/overtype. EditToggleOvertype = QsciScintillaBase::SCI_EDITTOGGLEOVERTYPE, //! Insert a platform dependent newline. Newline = QsciScintillaBase::SCI_NEWLINE, //! Insert a formfeed. Formfeed = QsciScintillaBase::SCI_FORMFEED, //! Indent one level. Tab = QsciScintillaBase::SCI_TAB, //! De-indent one level. Backtab = QsciScintillaBase::SCI_BACKTAB, //! Cancel any current operation. Cancel = QsciScintillaBase::SCI_CANCEL, //! Undo the last command. Undo = QsciScintillaBase::SCI_UNDO, //! Redo the last command. Redo = QsciScintillaBase::SCI_REDO, //! Zoom in. ZoomIn = QsciScintillaBase::SCI_ZOOMIN, //! Zoom out. ZoomOut = QsciScintillaBase::SCI_ZOOMOUT, //! Reverse the selected lines. ReverseLines = QsciScintillaBase::SCI_LINEREVERSE, }; //! Return the command that will be executed by this instance. Command command() const {return scicmd;} //! Execute the command. void execute(); //! Binds the key \a key to the command. If \a key is 0 then the key //! binding is removed. If \a key is invalid then the key binding is //! unchanged. Valid keys are any visible or control character or any //! of \c Qt::Key_Down, \c Qt::Key_Up, \c Qt::Key_Left, \c Qt::Key_Right, //! \c Qt::Key_Home, \c Qt::Key_End, \c Qt::Key_PageUp, //! \c Qt::Key_PageDown, \c Qt::Key_Delete, \c Qt::Key_Insert, //! \c Qt::Key_Escape, \c Qt::Key_Backspace, \c Qt::Key_Tab, //! \c Qt::Key_Backtab, \c Qt::Key_Return, \c Qt::Key_Enter, //! \c Qt::Key_Super_L, \c Qt::Key_Super_R or \c Qt::Key_Menu. Keys may be //! modified with any combination of \c Qt::ShiftModifier, //! \c Qt::ControlModifier, \c Qt::AltModifier and \c Qt::MetaModifier. //! //! \sa key(), setAlternateKey(), validKey() void setKey(int key); //! Binds the alternate key \a altkey to the command. If \a key is 0 //! then the alternate key binding is removed. //! //! \sa alternateKey(), setKey(), validKey() void setAlternateKey(int altkey); //! The key that is currently bound to the command is returned. //! //! \sa setKey(), alternateKey() int key() const {return qkey;} //! The alternate key that is currently bound to the command is //! returned. //! //! \sa setAlternateKey(), key() int alternateKey() const {return qaltkey;} //! If the key \a key is valid then true is returned. static bool validKey(int key); //! The user friendly description of the command is returned. QString description() const; private: friend class QsciCommandSet; QsciCommand(QsciScintilla *qs, Command cmd, int key, int altkey, const char *desc); void bindKey(int key,int &qk,int &scik); QsciScintilla *qsCmd; Command scicmd; int qkey, scikey, qaltkey, scialtkey; const char *descCmd; QsciCommand(const QsciCommand &); QsciCommand &operator=(const QsciCommand &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscicommandset.h000066400000000000000000000053731463772530400301240ustar00rootroot00000000000000// This defines the interface to the QsciCommandSet class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCICOMMANDSET_H #define QSCICOMMANDSET_H #include #include #include #include QT_BEGIN_NAMESPACE class QSettings; QT_END_NAMESPACE class QsciScintilla; //! \brief The QsciCommandSet class represents the set of all internal editor //! commands that may have keys bound. //! //! Methods are provided to access the individual commands and to read and //! write the current bindings from and to settings files. class QSCINTILLA_EXPORT QsciCommandSet { public: //! The key bindings for each command in the set are read from the //! settings \a qs. \a prefix is prepended to the key of each entry. //! true is returned if there was no error. //! //! \sa writeSettings() bool readSettings(QSettings &qs, const char *prefix = "/Scintilla"); //! The key bindings for each command in the set are written to the //! settings \a qs. \a prefix is prepended to the key of each entry. //! true is returned if there was no error. //! //! \sa readSettings() bool writeSettings(QSettings &qs, const char *prefix = "/Scintilla"); //! The commands in the set are returned as a list. QList &commands() {return cmds;} //! The primary keys bindings for all commands are removed. void clearKeys(); //! The alternate keys bindings for all commands are removed. void clearAlternateKeys(); // Find the command that is bound to \a key. QsciCommand *boundTo(int key) const; // Find a specific command \a command. QsciCommand *find(QsciCommand::Command command) const; private: friend class QsciScintilla; QsciCommandSet(QsciScintilla *qs); ~QsciCommandSet(); QsciScintilla *qsci; QList cmds; QsciCommandSet(const QsciCommandSet &); QsciCommandSet &operator=(const QsciCommandSet &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscidocument.h000066400000000000000000000035551463772530400276100ustar00rootroot00000000000000// This defines the interface to the QsciDocument class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCIDOCUMENT_H #define QSCIDOCUMENT_H #include class QsciScintillaBase; class QsciDocumentP; //! \brief The QsciDocument class represents a document to be edited. //! //! It is an opaque class that can be attached to multiple instances of //! QsciScintilla to create different simultaneous views of the same document. //! QsciDocument uses implicit sharing so that copying class instances is a //! cheap operation. class QSCINTILLA_EXPORT QsciDocument { public: //! Create a new unattached document. QsciDocument(); virtual ~QsciDocument(); QsciDocument(const QsciDocument &); QsciDocument &operator=(const QsciDocument &); private: friend class QsciScintilla; void attach(const QsciDocument &that); void detach(); void display(QsciScintillaBase *qsb, const QsciDocument *from); void undisplay(QsciScintillaBase *qsb); bool isModified() const; void setModified(bool m); QsciDocumentP *pdoc; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qsciglobal.h000066400000000000000000000031001463772530400272140ustar00rootroot00000000000000// This module defines various things common to all of the Scintilla Qt port. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCIGLOBAL_H #define QSCIGLOBAL_H #include #define QSCINTILLA_VERSION 0x020b01 #define QSCINTILLA_VERSION_STR "2.11.1" // Define QSCINTILLA_MAKE_DLL to create a QScintilla shared library, or // define QSCINTILLA_DLL to link against a QScintilla shared library, or define // neither to either build or link against a static QScintilla library. #if defined(QSCINTILLA_DLL) #define QSCINTILLA_EXPORT Q_DECL_IMPORT #elif defined(QSCINTILLA_MAKE_DLL) #define QSCINTILLA_EXPORT Q_DECL_EXPORT #else #define QSCINTILLA_EXPORT #endif #if !defined(QT_BEGIN_NAMESPACE) #define QT_BEGIN_NAMESPACE #define QT_END_NAMESPACE #endif #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscilexer.h000066400000000000000000000314111463772530400271010ustar00rootroot00000000000000// This defines the interface to the QsciLexer class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCILEXER_H #define QSCILEXER_H #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QSettings; QT_END_NAMESPACE class QsciAbstractAPIs; class QsciScintilla; //! \brief The QsciLexer class is an abstract class used as a base for language //! lexers. //! //! A lexer scans the text breaking it up into separate language objects, e.g. //! keywords, strings, operators. The lexer then uses a different style to //! draw each object. A style is identified by a style number and has a number //! of attributes, including colour and font. A specific language lexer will //! implement appropriate default styles which can be overriden by an //! application by further sub-classing the specific language lexer. //! //! A lexer may provide one or more sets of words to be recognised as keywords. //! Most lexers only provide one set, but some may support languages embedded //! in other languages and provide several sets. //! //! QsciLexer provides convenience methods for saving and restoring user //! preferences for fonts and colours. //! //! If you want to write a lexer for a new language then you can add it to the //! underlying Scintilla code and implement a corresponding QsciLexer sub-class //! to manage the different styles used. Alternatively you can implement a //! sub-class of QsciLexerCustom. class QSCINTILLA_EXPORT QsciLexer : public QObject { Q_OBJECT public: //! Construct a QsciLexer with parent \a parent. \a parent is typically //! the QsciScintilla instance. QsciLexer(QObject *parent = 0); //! Destroy the QSciLexer. virtual ~QsciLexer(); //! Returns the name of the language. It must be re-implemented by a //! sub-class. virtual const char *language() const = 0; //! Returns the name of the lexer. If 0 is returned then the lexer's //! numeric identifier is used. The default implementation returns 0. //! //! \sa lexerId() virtual const char *lexer() const; //! Returns the identifier (i.e. a QsciScintillaBase::SCLEX_* value) of the //! lexer. This is only used if lexer() returns 0. The default //! implementation returns QsciScintillaBase::SCLEX_CONTAINER. //! //! \sa lexer() virtual int lexerId() const; //! Returns the current API set or 0 if there isn't one. //! //! \sa setAPIs() QsciAbstractAPIs *apis() const; //! Returns the characters that can fill up auto-completion. virtual const char *autoCompletionFillups() const; //! Returns the list of character sequences that can separate //! auto-completion words. The first in the list is assumed to be the //! sequence used to separate words in the lexer's API files. virtual QStringList autoCompletionWordSeparators() const; //! Returns the auto-indentation style. The default is 0 if the //! language is block structured, or QsciScintilla::AiMaintain if not. //! //! \sa setAutoIndentStyle(), QsciScintilla::AiMaintain, //! QsciScintilla::AiOpening, QsciScintilla::AiClosing int autoIndentStyle(); //! Returns a space separated list of words or characters in a particular //! style that define the end of a block for auto-indentation. The style //! is returned via \a style. virtual const char *blockEnd(int *style = 0) const; //! Returns the number of lines prior to the current one when determining //! the scope of a block when auto-indenting. virtual int blockLookback() const; //! Returns a space separated list of words or characters in a particular //! style that define the start of a block for auto-indentation. The style //! is returned via \a style. virtual const char *blockStart(int *style = 0) const; //! Returns a space separated list of keywords in a particular style that //! define the start of a block for auto-indentation. The style is //! returned via \a style. virtual const char *blockStartKeyword(int *style = 0) const; //! Returns the style used for braces for brace matching. virtual int braceStyle() const; //! Returns true if the language is case sensitive. The default is true. virtual bool caseSensitive() const; //! Returns the foreground colour of the text for style number \a style. //! The default colour is that returned by defaultColor(). //! //! \sa defaultColor(), paper() virtual QColor color(int style) const; //! Returns the end-of-line for style number \a style. The default is //! false. virtual bool eolFill(int style) const; //! Returns the font for style number \a style. The default font is //! that returned by defaultFont(). //! //! \sa defaultFont() virtual QFont font(int style) const; //! Returns the view used for indentation guides. virtual int indentationGuideView() const; //! Returns the set of keywords for the keyword set \a set recognised //! by the lexer as a space separated string. Keyword sets are numbered //! from 1. 0 is returned if there is no such set. virtual const char *keywords(int set) const; //! Returns the number of the style used for whitespace. The default //! implementation returns 0 which is the convention adopted by most //! lexers. virtual int defaultStyle() const; //! Returns the descriptive name for style number \a style. For a valid //! style number for this language a non-empty QString must be returned. //! If the style number is invalid then an empty QString must be returned. //! This is intended to be used in user preference dialogs. virtual QString description(int style) const = 0; //! Returns the background colour of the text for style number //! \a style. //! //! \sa defaultPaper(), color() virtual QColor paper(int style) const; //! Returns the default text colour. //! //! \sa setDefaultColor() QColor defaultColor() const; //! Returns the default text colour for style number \a style. virtual QColor defaultColor(int style) const; //! Returns the default end-of-line for style number \a style. The default //! is false. virtual bool defaultEolFill(int style) const; //! Returns the default font. //! //! \sa setDefaultFont() QFont defaultFont() const; //! Returns the default font for style number \a style. virtual QFont defaultFont(int style) const; //! Returns the default paper colour. //! //! \sa setDefaultPaper() QColor defaultPaper() const; //! Returns the default paper colour for style number \a style. virtual QColor defaultPaper(int style) const; //! Returns the QsciScintilla instance that the lexer is currently attached //! to or 0 if it is unattached. QsciScintilla *editor() const {return attached_editor;} //! The current set of APIs is set to \a apis. If \a apis is 0 then any //! existing APIs for this lexer are removed. //! //! \sa apis() void setAPIs(QsciAbstractAPIs *apis); //! The default text colour is set to \a c. //! //! \sa defaultColor(), color() void setDefaultColor(const QColor &c); //! The default font is set to \a f. //! //! \sa defaultFont(), font() void setDefaultFont(const QFont &f); //! The default paper colour is set to \a c. //! //! \sa defaultPaper(), paper() void setDefaultPaper(const QColor &c); //! \internal Set the QsciScintilla instance that the lexer is attached to. virtual void setEditor(QsciScintilla *editor); //! The colour, paper, font and end-of-line for each style number, and //! all lexer specific properties are read from the settings \a qs. //! \a prefix is prepended to the key of each entry. true is returned //! if there was no error. //! //! \sa writeSettings(), QsciScintilla::setLexer() bool readSettings(QSettings &qs,const char *prefix = "/Scintilla"); //! Causes all properties to be refreshed by emitting the //! propertyChanged() signal as required. virtual void refreshProperties(); //! Returns the number of style bits needed by the lexer. Normally this //! should only be re-implemented by custom lexers. This is deprecated and //! no longer has any effect. virtual int styleBitsNeeded() const; //! Returns the string of characters that comprise a word. The default is //! 0 which implies the upper and lower case alphabetic characters and //! underscore. virtual const char *wordCharacters() const; //! The colour, paper, font and end-of-line for each style number, and //! all lexer specific properties are written to the settings \a qs. //! \a prefix is prepended to the key of each entry. true is returned //! if there was no error. //! //! \sa readSettings() bool writeSettings(QSettings &qs, const char *prefix = "/Scintilla") const; public slots: //! The auto-indentation style is set to \a autoindentstyle. //! //! \sa autoIndentStyle(), QsciScintilla::AiMaintain, //! QsciScintilla::AiOpening, QsciScintilla::AiClosing virtual void setAutoIndentStyle(int autoindentstyle); //! The foreground colour for style number \a style is set to \a c. If //! \a style is -1 then the colour is set for all styles. virtual void setColor(const QColor &c,int style = -1); //! The end-of-line fill for style number \a style is set to //! \a eoffill. If \a style is -1 then the fill is set for all styles. virtual void setEolFill(bool eoffill,int style = -1); //! The font for style number \a style is set to \a f. If \a style is //! -1 then the font is set for all styles. virtual void setFont(const QFont &f,int style = -1); //! The background colour for style number \a style is set to \a c. If //! \a style is -1 then the colour is set for all styles. virtual void setPaper(const QColor &c,int style = -1); signals: //! This signal is emitted when the foreground colour of style number //! \a style has changed. The new colour is \a c. void colorChanged(const QColor &c,int style); //! This signal is emitted when the end-of-file fill of style number //! \a style has changed. The new fill is \a eolfilled. void eolFillChanged(bool eolfilled,int style); //! This signal is emitted when the font of style number \a style has //! changed. The new font is \a f. void fontChanged(const QFont &f,int style); //! This signal is emitted when the background colour of style number //! \a style has changed. The new colour is \a c. void paperChanged(const QColor &c,int style); //! This signal is emitted when the value of the lexer property \a prop //! needs to be changed. The new value is \a val. void propertyChanged(const char *prop, const char *val); protected: //! The lexer's properties are read from the settings \a qs. \a prefix //! (which has a trailing '/') should be used as a prefix to the key of //! each setting. true is returned if there is no error. //! virtual bool readProperties(QSettings &qs,const QString &prefix); //! The lexer's properties are written to the settings \a qs. //! \a prefix (which has a trailing '/') should be used as a prefix to //! the key of each setting. true is returned if there is no error. //! virtual bool writeProperties(QSettings &qs,const QString &prefix) const; private: struct StyleData { QFont font; QColor color; QColor paper; bool eol_fill; }; struct StyleDataMap { bool style_data_set; QMap style_data; }; StyleDataMap *style_map; int autoIndStyle; QFont defFont; QColor defColor; QColor defPaper; QsciAbstractAPIs *apiSet; QsciScintilla *attached_editor; void setStyleDefaults() const; StyleData &styleData(int style) const; QsciLexer(const QsciLexer &); QsciLexer &operator=(const QsciLexer &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscilexercpp.h000066400000000000000000000321631463772530400276110ustar00rootroot00000000000000// This defines the interface to the QsciLexerCPP class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCILEXERCPP_H #define QSCILEXERCPP_H #include #include #include //! \brief The QsciLexerCPP class encapsulates the Scintilla C++ //! lexer. class QSCINTILLA_EXPORT QsciLexerCPP : public QsciLexer { Q_OBJECT public: //! This enum defines the meanings of the different styles used by the //! C++ lexer. enum { //! The default. Default = 0, InactiveDefault = Default + 64, //! A C comment. Comment = 1, InactiveComment = Comment + 64, //! A C++ comment line. CommentLine = 2, InactiveCommentLine = CommentLine + 64, //! A JavaDoc/Doxygen style C comment. CommentDoc = 3, InactiveCommentDoc = CommentDoc + 64, //! A number. Number = 4, InactiveNumber = Number + 64, //! A keyword. Keyword = 5, InactiveKeyword = Keyword + 64, //! A double-quoted string. DoubleQuotedString = 6, InactiveDoubleQuotedString = DoubleQuotedString + 64, //! A single-quoted string. SingleQuotedString = 7, InactiveSingleQuotedString = SingleQuotedString + 64, //! An IDL UUID. UUID = 8, InactiveUUID = UUID + 64, //! A pre-processor block. PreProcessor = 9, InactivePreProcessor = PreProcessor + 64, //! An operator. Operator = 10, InactiveOperator = Operator + 64, //! An identifier Identifier = 11, InactiveIdentifier = Identifier + 64, //! The end of a line where a string is not closed. UnclosedString = 12, InactiveUnclosedString = UnclosedString + 64, //! A C# verbatim string. VerbatimString = 13, InactiveVerbatimString = VerbatimString + 64, //! A JavaScript regular expression. Regex = 14, InactiveRegex = Regex + 64, //! A JavaDoc/Doxygen style C++ comment line. CommentLineDoc = 15, InactiveCommentLineDoc = CommentLineDoc + 64, //! A keyword defined in keyword set number 2. The class must be //! sub-classed and re-implement keywords() to make use of this style. KeywordSet2 = 16, InactiveKeywordSet2 = KeywordSet2 + 64, //! A JavaDoc/Doxygen keyword. CommentDocKeyword = 17, InactiveCommentDocKeyword = CommentDocKeyword + 64, //! A JavaDoc/Doxygen keyword error. CommentDocKeywordError = 18, InactiveCommentDocKeywordError = CommentDocKeywordError + 64, //! A global class or typedef defined in keyword set number 5. The //! class must be sub-classed and re-implement keywords() to make use //! of this style. GlobalClass = 19, InactiveGlobalClass = GlobalClass + 64, //! A C++ raw string. RawString = 20, InactiveRawString = RawString + 64, //! A Vala triple-quoted verbatim string. TripleQuotedVerbatimString = 21, InactiveTripleQuotedVerbatimString = TripleQuotedVerbatimString + 64, //! A Pike hash-quoted string. HashQuotedString = 22, InactiveHashQuotedString = HashQuotedString + 64, //! A pre-processor stream comment. PreProcessorComment = 23, InactivePreProcessorComment = PreProcessorComment + 64, //! A JavaDoc/Doxygen style pre-processor comment. PreProcessorCommentLineDoc = 24, InactivePreProcessorCommentLineDoc = PreProcessorCommentLineDoc + 64, //! A user-defined literal. UserLiteral = 25, InactiveUserLiteral = UserLiteral + 64, //! A task marker. TaskMarker = 26, InactiveTaskMarker = TaskMarker + 64, //! An escape sequence. EscapeSequence = 27, InactiveEscapeSequence = EscapeSequence + 64, }; //! Construct a QsciLexerCPP with parent \a parent. \a parent is typically //! the QsciScintilla instance. \a caseInsensitiveKeywords is true if the //! lexer ignores the case of keywords. QsciLexerCPP(QObject *parent = 0, bool caseInsensitiveKeywords = false); //! Destroys the QsciLexerCPP instance. virtual ~QsciLexerCPP(); //! Returns the name of the language. const char *language() const; //! Returns the name of the lexer. Some lexers support a number of //! languages. const char *lexer() const; //! \internal Returns the character sequences that can separate //! auto-completion words. QStringList autoCompletionWordSeparators() const; //! \internal Returns a space separated list of words or characters in //! a particular style that define the end of a block for //! auto-indentation. The styles is returned via \a style. const char *blockEnd(int *style = 0) const; //! \internal Returns a space separated list of words or characters in //! a particular style that define the start of a block for //! auto-indentation. The styles is returned via \a style. const char *blockStart(int *style = 0) const; //! \internal Returns a space separated list of keywords in a //! particular style that define the start of a block for //! auto-indentation. The styles is returned via \a style. const char *blockStartKeyword(int *style = 0) const; //! \internal Returns the style used for braces for brace matching. int braceStyle() const; //! Returns the string of characters that comprise a word. const char *wordCharacters() const; //! Returns the foreground colour of the text for style number \a style. //! //! \sa defaultPaper() QColor defaultColor(int style) const; //! Returns the end-of-line fill for style number \a style. bool defaultEolFill(int style) const; //! Returns the font for style number \a style. QFont defaultFont(int style) const; //! Returns the background colour of the text for style number \a style. //! //! \sa defaultColor() QColor defaultPaper(int style) const; //! Returns the set of keywords for the keyword set \a set recognised //! by the lexer as a space separated string. Set 1 is normally used for //! primary keywords and identifiers. Set 2 is normally used for secondary //! keywords and identifiers. Set 3 is normally used for documentation //! comment keywords. Set 4 is normally used for global classes and //! typedefs. const char *keywords(int set) const; //! Returns the descriptive name for style number \a style. If the //! style is invalid for this language then an empty QString is returned. //! This is intended to be used in user preference dialogs. QString description(int style) const; //! Causes all properties to be refreshed by emitting the //! propertyChanged() signal as required. void refreshProperties(); //! Returns true if "} else {" lines can be folded. //! //! \sa setFoldAtElse() bool foldAtElse() const {return fold_atelse;} //! Returns true if multi-line comment blocks can be folded. //! //! \sa setFoldComments() bool foldComments() const {return fold_comments;} //! Returns true if trailing blank lines are included in a fold block. //! //! \sa setFoldCompact() bool foldCompact() const {return fold_compact;} //! Returns true if preprocessor blocks can be folded. //! //! \sa setFoldPreprocessor() bool foldPreprocessor() const {return fold_preproc;} //! Returns true if preprocessor lines (after the preprocessor //! directive) are styled. //! //! \sa setStylePreprocessor() bool stylePreprocessor() const {return style_preproc;} //! If \a allowed is true then '$' characters are allowed in identifier //! names. The default is true. //! //! \sa dollarsAllowed() void setDollarsAllowed(bool allowed); //! Returns true if '$' characters are allowed in identifier names. //! //! \sa setDollarsAllowed() bool dollarsAllowed() const {return dollars;} //! If \a enabled is true then triple quoted strings are highlighted. The //! default is false. //! //! \sa highlightTripleQuotedStrings() void setHighlightTripleQuotedStrings(bool enabled); //! Returns true if triple quoted strings should be highlighted. //! //! \sa setHighlightTripleQuotedStrings() bool highlightTripleQuotedStrings() const {return highlight_triple;} //! If \a enabled is true then hash quoted strings are highlighted. The //! default is false. //! //! \sa highlightHashQuotedStrings() void setHighlightHashQuotedStrings(bool enabled); //! Returns true if hash quoted strings should be highlighted. //! //! \sa setHighlightHashQuotedStrings() bool highlightHashQuotedStrings() const {return highlight_hash;} //! If \a enabled is true then back-quoted raw strings are highlighted. //! The default is false. //! //! \sa highlightBackQuotedStrings() void setHighlightBackQuotedStrings(bool enabled); //! Returns true if back-quoted raw strings should be highlighted. //! //! \sa setHighlightBackQuotedStrings() bool highlightBackQuotedStrings() const {return highlight_back;} //! If \a enabled is true then escape sequences in strings are highlighted. //! The default is false. //! //! \sa highlightEscapeSequences() void setHighlightEscapeSequences(bool enabled); //! Returns true if escape sequences in strings should be highlighted. //! //! \sa setHighlightEscapeSequences() bool highlightEscapeSequences() const {return highlight_escape;} //! If \a allowed is true then escape sequences are allowed in verbatim //! strings. The default is false. //! //! \sa verbatimStringEscapeSequencesAllowed() void setVerbatimStringEscapeSequencesAllowed(bool allowed); //! Returns true if hash quoted strings should be highlighted. //! //! \sa setVerbatimStringEscapeSequencesAllowed() bool verbatimStringEscapeSequencesAllowed() const {return vs_escape;} public slots: //! If \a fold is true then "} else {" lines can be folded. The //! default is false. //! //! \sa foldAtElse() virtual void setFoldAtElse(bool fold); //! If \a fold is true then multi-line comment blocks can be folded. //! The default is false. //! //! \sa foldComments() virtual void setFoldComments(bool fold); //! If \a fold is true then trailing blank lines are included in a fold //! block. The default is true. //! //! \sa foldCompact() virtual void setFoldCompact(bool fold); //! If \a fold is true then preprocessor blocks can be folded. The //! default is true. //! //! \sa foldPreprocessor() virtual void setFoldPreprocessor(bool fold); //! If \a style is true then preprocessor lines (after the preprocessor //! directive) are styled. The default is false. //! //! \sa stylePreprocessor() virtual void setStylePreprocessor(bool style); protected: //! The lexer's properties are read from the settings \a qs. \a prefix //! (which has a trailing '/') should be used as a prefix to the key of //! each setting. true is returned if there is no error. //! //! \sa writeProperties() bool readProperties(QSettings &qs,const QString &prefix); //! The lexer's properties are written to the settings \a qs. //! \a prefix (which has a trailing '/') should be used as a prefix to //! the key of each setting. true is returned if there is no error. //! //! \sa readProperties() bool writeProperties(QSettings &qs,const QString &prefix) const; private: void setAtElseProp(); void setCommentProp(); void setCompactProp(); void setPreprocProp(); void setStylePreprocProp(); void setDollarsProp(); void setHighlightTripleProp(); void setHighlightHashProp(); void setHighlightBackProp(); void setHighlightEscapeProp(); void setVerbatimStringEscapeProp(); bool fold_atelse; bool fold_comments; bool fold_compact; bool fold_preproc; bool style_preproc; bool dollars; bool highlight_triple; bool highlight_hash; bool highlight_back; bool highlight_escape; bool vs_escape; bool nocase; QsciLexerCPP(const QsciLexerCPP &); QsciLexerCPP &operator=(const QsciLexerCPP &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscilexercustom.h000066400000000000000000000071071463772530400303410ustar00rootroot00000000000000// This defines the interface to the QsciLexerCustom class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCILEXERCUSTOM_H #define QSCILEXERCUSTOM_H #include #include class QsciScintilla; class QsciStyle; //! \brief The QsciLexerCustom class is an abstract class used as a base for //! new language lexers. //! //! The advantage of implementing a new lexer this way (as opposed to adding //! the lexer to the underlying Scintilla code) is that it does not require the //! QScintilla library to be re-compiled. It also makes it possible to //! integrate external lexers. //! //! All that is necessary to implement a new lexer is to define appropriate //! styles and to re-implement the styleText() method. class QSCINTILLA_EXPORT QsciLexerCustom : public QsciLexer { Q_OBJECT public: //! Construct a QsciLexerCustom with parent \a parent. \a parent is //! typically the QsciScintilla instance. QsciLexerCustom(QObject *parent = 0); //! Destroy the QSciLexerCustom. virtual ~QsciLexerCustom(); //! The next \a length characters starting from the current styling //! position have their style set to style number \a style. The current //! styling position is moved. The styling position is initially set by //! calling startStyling(). //! //! \sa startStyling(), styleText() void setStyling(int length, int style); //! The next \a length characters starting from the current styling //! position have their style set to style \a style. The current styling //! position is moved. The styling position is initially set by calling //! startStyling(). //! //! \sa startStyling(), styleText() void setStyling(int length, const QsciStyle &style); //! The styling position is set to \a start. \a styleBits is unused. //! //! \sa setStyling(), styleBitsNeeded(), styleText() void startStyling(int pos, int styleBits = 0); //! This is called when the section of text beginning at position \a start //! and up to position \a end needs to be styled. \a start will always be //! at the start of a line. The text is styled by calling startStyling() //! followed by one or more calls to setStyling(). It must be //! re-implemented by a sub-class. //! //! \sa setStyling(), startStyling(), QsciScintilla::bytes(), //! QsciScintilla::text() virtual void styleText(int start, int end) = 0; //! \reimp virtual void setEditor(QsciScintilla *editor); //! \reimp This re-implementation returns 5 as the number of style bits //! needed. virtual int styleBitsNeeded() const; private slots: void handleStyleNeeded(int pos); private: QsciLexerCustom(const QsciLexerCustom &); QsciLexerCustom &operator=(const QsciLexerCustom &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscilexerhtml.h000066400000000000000000000343071463772530400277750ustar00rootroot00000000000000// This defines the interface to the QsciLexerHTML class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCILEXERHTML_H #define QSCILEXERHTML_H #include #include #include //! \brief The QsciLexerHTML class encapsulates the Scintilla HTML lexer. class QSCINTILLA_EXPORT QsciLexerHTML : public QsciLexer { Q_OBJECT public: //! This enum defines the meanings of the different styles used by the //! HTML lexer. enum { //! The default. Default = 0, //! A tag. Tag = 1, //! An unknown tag. UnknownTag = 2, //! An attribute. Attribute = 3, //! An unknown attribute. UnknownAttribute = 4, //! An HTML number. HTMLNumber = 5, //! An HTML double-quoted string. HTMLDoubleQuotedString = 6, //! An HTML single-quoted string. HTMLSingleQuotedString = 7, //! Other text within a tag. OtherInTag = 8, //! An HTML comment. HTMLComment = 9, //! An entity. Entity = 10, //! The end of an XML style tag. XMLTagEnd = 11, //! The start of an XML fragment. XMLStart = 12, //! The end of an XML fragment. XMLEnd = 13, //! A script tag. Script = 14, //! The start of an ASP fragment with @. ASPAtStart = 15, //! The start of an ASP fragment. ASPStart = 16, //! CDATA. CDATA = 17, //! The start of a PHP fragment. PHPStart = 18, //! An unquoted HTML value. HTMLValue = 19, //! An ASP X-Code comment. ASPXCComment = 20, //! The default for SGML. SGMLDefault = 21, //! An SGML command. SGMLCommand = 22, //! The first parameter of an SGML command. SGMLParameter = 23, //! An SGML double-quoted string. SGMLDoubleQuotedString = 24, //! An SGML single-quoted string. SGMLSingleQuotedString = 25, //! An SGML error. SGMLError = 26, //! An SGML special entity. SGMLSpecial = 27, //! An SGML entity. SGMLEntity = 28, //! An SGML comment. SGMLComment = 29, //! A comment with the first parameter of an SGML command. SGMLParameterComment = 30, //! The default for an SGML block. SGMLBlockDefault = 31, //! The start of a JavaScript fragment. JavaScriptStart = 40, //! The default for JavaScript. JavaScriptDefault = 41, //! A JavaScript comment. JavaScriptComment = 42, //! A JavaScript line comment. JavaScriptCommentLine = 43, //! A JavaDoc style JavaScript comment. JavaScriptCommentDoc = 44, //! A JavaScript number. JavaScriptNumber = 45, //! A JavaScript word. JavaScriptWord = 46, //! A JavaScript keyword. JavaScriptKeyword = 47, //! A JavaScript double-quoted string. JavaScriptDoubleQuotedString = 48, //! A JavaScript single-quoted string. JavaScriptSingleQuotedString = 49, //! A JavaScript symbol. JavaScriptSymbol = 50, //! The end of a JavaScript line where a string is not closed. JavaScriptUnclosedString = 51, //! A JavaScript regular expression. JavaScriptRegex = 52, //! The start of an ASP JavaScript fragment. ASPJavaScriptStart = 55, //! The default for ASP JavaScript. ASPJavaScriptDefault = 56, //! An ASP JavaScript comment. ASPJavaScriptComment = 57, //! An ASP JavaScript line comment. ASPJavaScriptCommentLine = 58, //! An ASP JavaDoc style JavaScript comment. ASPJavaScriptCommentDoc = 59, //! An ASP JavaScript number. ASPJavaScriptNumber = 60, //! An ASP JavaScript word. ASPJavaScriptWord = 61, //! An ASP JavaScript keyword. ASPJavaScriptKeyword = 62, //! An ASP JavaScript double-quoted string. ASPJavaScriptDoubleQuotedString = 63, //! An ASP JavaScript single-quoted string. ASPJavaScriptSingleQuotedString = 64, //! An ASP JavaScript symbol. ASPJavaScriptSymbol = 65, //! The end of an ASP JavaScript line where a string is not //! closed. ASPJavaScriptUnclosedString = 66, //! An ASP JavaScript regular expression. ASPJavaScriptRegex = 67, //! The start of a VBScript fragment. VBScriptStart = 70, //! The default for VBScript. VBScriptDefault = 71, //! A VBScript comment. VBScriptComment = 72, //! A VBScript number. VBScriptNumber = 73, //! A VBScript keyword. VBScriptKeyword = 74, //! A VBScript string. VBScriptString = 75, //! A VBScript identifier. VBScriptIdentifier = 76, //! The end of a VBScript line where a string is not closed. VBScriptUnclosedString = 77, //! The start of an ASP VBScript fragment. ASPVBScriptStart = 80, //! The default for ASP VBScript. ASPVBScriptDefault = 81, //! An ASP VBScript comment. ASPVBScriptComment = 82, //! An ASP VBScript number. ASPVBScriptNumber = 83, //! An ASP VBScript keyword. ASPVBScriptKeyword = 84, //! An ASP VBScript string. ASPVBScriptString = 85, //! An ASP VBScript identifier. ASPVBScriptIdentifier = 86, //! The end of an ASP VBScript line where a string is not //! closed. ASPVBScriptUnclosedString = 87, //! The start of a Python fragment. PythonStart = 90, //! The default for Python. PythonDefault = 91, //! A Python comment. PythonComment = 92, //! A Python number. PythonNumber = 93, //! A Python double-quoted string. PythonDoubleQuotedString = 94, //! A Python single-quoted string. PythonSingleQuotedString = 95, //! A Python keyword. PythonKeyword = 96, //! A Python triple single-quoted string. PythonTripleSingleQuotedString = 97, //! A Python triple double-quoted string. PythonTripleDoubleQuotedString = 98, //! The name of a Python class. PythonClassName = 99, //! The name of a Python function or method. PythonFunctionMethodName = 100, //! A Python operator. PythonOperator = 101, //! A Python identifier. PythonIdentifier = 102, //! The start of an ASP Python fragment. ASPPythonStart = 105, //! The default for ASP Python. ASPPythonDefault = 106, //! An ASP Python comment. ASPPythonComment = 107, //! An ASP Python number. ASPPythonNumber = 108, //! An ASP Python double-quoted string. ASPPythonDoubleQuotedString = 109, //! An ASP Python single-quoted string. ASPPythonSingleQuotedString = 110, //! An ASP Python keyword. ASPPythonKeyword = 111, //! An ASP Python triple single-quoted string. ASPPythonTripleSingleQuotedString = 112, //! An ASP Python triple double-quoted string. ASPPythonTripleDoubleQuotedString = 113, //! The name of an ASP Python class. ASPPythonClassName = 114, //! The name of an ASP Python function or method. ASPPythonFunctionMethodName = 115, //! An ASP Python operator. ASPPythonOperator = 116, //! An ASP Python identifier ASPPythonIdentifier = 117, //! The default for PHP. PHPDefault = 118, //! A PHP double-quoted string. PHPDoubleQuotedString = 119, //! A PHP single-quoted string. PHPSingleQuotedString = 120, //! A PHP keyword. PHPKeyword = 121, //! A PHP number. PHPNumber = 122, //! A PHP variable. PHPVariable = 123, //! A PHP comment. PHPComment = 124, //! A PHP line comment. PHPCommentLine = 125, //! A PHP double-quoted variable. PHPDoubleQuotedVariable = 126, //! A PHP operator. PHPOperator = 127 }; //! Construct a QsciLexerHTML with parent \a parent. \a parent is //! typically the QsciScintilla instance. QsciLexerHTML(QObject *parent = 0); //! Destroys the QsciLexerHTML instance. virtual ~QsciLexerHTML(); //! Returns the name of the language. const char *language() const; //! Returns the name of the lexer. Some lexers support a number of //! languages. const char *lexer() const; //! \internal Returns the auto-completion fillup characters. const char *autoCompletionFillups() const; //! Returns the string of characters that comprise a word. const char *wordCharacters() const; //! Returns the foreground colour of the text for style number \a style. //! //! \sa defaultPaper() QColor defaultColor(int style) const; //! Returns the end-of-line fill for style number \a style. bool defaultEolFill(int style) const; //! Returns the font for style number \a style. QFont defaultFont(int style) const; //! Returns the background colour of the text for style number \a style. //! //! \sa defaultColor() QColor defaultPaper(int style) const; //! Returns the set of keywords for the keyword set \a set recognised //! by the lexer as a space separated string. const char *keywords(int set) const; //! Returns the descriptive name for style number \a style. If the //! style is invalid for this language then an empty QString is returned. //! This is intended to be used in user preference dialogs. QString description(int style) const; //! Causes all properties to be refreshed by emitting the //! propertyChanged() signal as required. void refreshProperties(); //! Returns true if tags are case sensitive. //! //! \sa setCaseSensitiveTags() bool caseSensitiveTags() const {return case_sens_tags;} //! If \a enabled is true then Django templates are enabled. The default //! is false. //! //! \sa djangoTemplates() void setDjangoTemplates(bool enabled); //! Returns true if support for Django templates is enabled. //! //! \sa setDjangoTemplates() bool djangoTemplates() const {return django_templates;} //! Returns true if trailing blank lines are included in a fold block. //! //! \sa setFoldCompact() bool foldCompact() const {return fold_compact;} //! Returns true if preprocessor blocks can be folded. //! //! \sa setFoldPreprocessor() bool foldPreprocessor() const {return fold_preproc;} //! If \a fold is true then script comments can be folded. The default is //! false. //! //! \sa foldScriptComments() void setFoldScriptComments(bool fold); //! Returns true if script comments can be folded. //! //! \sa setFoldScriptComments() bool foldScriptComments() const {return fold_script_comments;} //! If \a fold is true then script heredocs can be folded. The default is //! false. //! //! \sa foldScriptHeredocs() void setFoldScriptHeredocs(bool fold); //! Returns true if script heredocs can be folded. //! //! \sa setFoldScriptHeredocs() bool foldScriptHeredocs() const {return fold_script_heredocs;} //! If \a enabled is true then Mako templates are enabled. The default is //! false. //! //! \sa makoTemplates() void setMakoTemplates(bool enabled); //! Returns true if support for Mako templates is enabled. //! //! \sa setMakoTemplates() bool makoTemplates() const {return mako_templates;} public slots: //! If \a fold is true then trailing blank lines are included in a fold //! block. The default is true. //! //! \sa foldCompact() virtual void setFoldCompact(bool fold); //! If \a fold is true then preprocessor blocks can be folded. The //! default is false. //! //! \sa foldPreprocessor() virtual void setFoldPreprocessor(bool fold); //! If \a sens is true then tags are case sensitive. The default is false. //! //! \sa caseSensitiveTags() virtual void setCaseSensitiveTags(bool sens); protected: //! The lexer's properties are read from the settings \a qs. \a prefix //! (which has a trailing '/') should be used as a prefix to the key of //! each setting. true is returned if there is no error. //! bool readProperties(QSettings &qs,const QString &prefix); //! The lexer's properties are written to the settings \a qs. //! \a prefix (which has a trailing '/') should be used as a prefix to //! the key of each setting. true is returned if there is no error. //! bool writeProperties(QSettings &qs,const QString &prefix) const; private: void setCompactProp(); void setPreprocProp(); void setCaseSensTagsProp(); void setScriptCommentsProp(); void setScriptHeredocsProp(); void setDjangoProp(); void setMakoProp(); bool fold_compact; bool fold_preproc; bool case_sens_tags; bool fold_script_comments; bool fold_script_heredocs; bool django_templates; bool mako_templates; QsciLexerHTML(const QsciLexerHTML &); QsciLexerHTML &operator=(const QsciLexerHTML &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscilexerjavascript.h000066400000000000000000000052271463772530400311760ustar00rootroot00000000000000// This defines the interface to the QsciLexerJavaScript class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCILEXERJSCRIPT_H #define QSCILEXERJSCRIPT_H #include #include #include //! \brief The QsciLexerJavaScript class encapsulates the Scintilla JavaScript //! lexer. class QSCINTILLA_EXPORT QsciLexerJavaScript : public QsciLexerCPP { Q_OBJECT public: //! Construct a QsciLexerJavaScript with parent \a parent. \a parent is //! typically the QsciScintilla instance. QsciLexerJavaScript(QObject *parent = 0); //! Destroys the QsciLexerJavaScript instance. virtual ~QsciLexerJavaScript(); //! Returns the name of the language. const char *language() const; //! Returns the foreground colour of the text for style number \a style. //! //! \sa defaultPaper() QColor defaultColor(int style) const; //! Returns the end-of-line fill for style number \a style. bool defaultEolFill(int style) const; //! Returns the font for style number \a style. QFont defaultFont(int style) const; //! Returns the background colour of the text for style number \a style. //! //! \sa defaultColor() QColor defaultPaper(int style) const; //! Returns the set of keywords for the keyword set \a set recognised //! by the lexer as a space separated string. const char *keywords(int set) const; //! Returns the descriptive name for style number \a style. If the //! style is invalid for this language then an empty QString is returned. //! This is intended to be used in user preference dialogs. QString description(int style) const; private: friend class QsciLexerHTML; static const char *keywordClass; QsciLexerJavaScript(const QsciLexerJavaScript &); QsciLexerJavaScript &operator=(const QsciLexerJavaScript &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscilexerjson.h000066400000000000000000000126471463772530400300050ustar00rootroot00000000000000// This defines the interface to the QsciLexerJSON class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCILEXERJSON_H #define QSCILEXERJSON_H #include #include #include //! \brief The QsciLexerJSON class encapsulates the Scintilla JSON lexer. class QSCINTILLA_EXPORT QsciLexerJSON : public QsciLexer { Q_OBJECT public: //! This enum defines the meanings of the different styles used by the //! JSON lexer. enum { //! The default. Default = 0, //! A number. Number = 1, //! A string. String = 2, //! An unclosed string. UnclosedString = 3, //! A property. Property = 4, //! An escape sequence. EscapeSequence = 5, //! A line comment. CommentLine = 6, //! A block comment. CommentBlock = 7, //! An operator. Operator = 8, //! An Internationalised Resource Identifier (IRI). IRI = 9, //! A JSON-LD compact IRI. IRICompact = 10, //! A JSON keyword. Keyword = 11, //! A JSON-LD keyword. KeywordLD = 12, //! A parsing error. Error = 13, }; //! Construct a QsciLexerJSON with parent \a parent. \a parent is //! typically the QsciScintilla instance. QsciLexerJSON(QObject *parent = 0); //! Destroys the QsciLexerJSON instance. virtual ~QsciLexerJSON(); //! Returns the name of the language. const char *language() const; //! Returns the name of the lexer. Some lexers support a number of //! languages. const char *lexer() const; //! Returns the foreground colour of the text for style number \a style. //! //! \sa defaultPaper() QColor defaultColor(int style) const; //! Returns the end-of-line fill for style number \a style. bool defaultEolFill(int style) const; //! Returns the font for style number \a style. QFont defaultFont(int style) const; //! Returns the background colour of the text for style number \a style. //! //! \sa defaultColor() QColor defaultPaper(int style) const; //! Returns the set of keywords for the keyword set \a set recognised //! by the lexer as a space separated string. const char *keywords(int set) const; //! Returns the descriptive name for style number \a style. If the //! style is invalid for this language then an empty QString is returned. //! This is intended to be used in user preference dialogs. QString description(int style) const; //! Causes all properties to be refreshed by emitting the //! propertyChanged() signal as required. void refreshProperties(); //! If \a highlight is true then line and block comments will be //! highlighted. The default is true. //! //! \sa hightlightComments() void setHighlightComments(bool highlight); //! Returns true if line and block comments are highlighted //! //! \sa setHightlightComments() bool highlightComments() const {return allow_comments;} //! If \a highlight is true then escape sequences in strings are //! highlighted. The default is true. //! //! \sa highlightEscapeSequences() void setHighlightEscapeSequences(bool highlight); //! Returns true if escape sequences in strings are highlighted. //! //! \sa setHighlightEscapeSequences() bool highlightEscapeSequences() const {return escape_sequence;} //! If \a fold is true then trailing blank lines are included in a fold //! block. The default is true. //! //! \sa foldCompact() void setFoldCompact(bool fold); //! Returns true if trailing blank lines are included in a fold block. //! //! \sa setFoldCompact() bool foldCompact() const {return fold_compact;} protected: //! The lexer's properties are read from the settings \a qs. \a prefix //! (which has a trailing '/') should be used as a prefix to the key of //! each setting. true is returned if there is no error. //! bool readProperties(QSettings &qs,const QString &prefix); //! The lexer's properties are written to the settings \a qs. //! \a prefix (which has a trailing '/') should be used as a prefix to //! the key of each setting. true is returned if there is no error. //! bool writeProperties(QSettings &qs,const QString &prefix) const; private: void setAllowCommentsProp(); void setEscapeSequenceProp(); void setCompactProp(); bool allow_comments; bool escape_sequence; bool fold_compact; QsciLexerJSON(const QsciLexerJSON &); QsciLexerJSON &operator=(const QsciLexerJSON &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscilexerpython.h000066400000000000000000000246671463772530400303620ustar00rootroot00000000000000// This defines the interface to the QsciLexerPython class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCILEXERPYTHON_H #define QSCILEXERPYTHON_H #include #include #include #include "Qsci/qsciscintillabase.h" //! \brief The QsciLexerPython class encapsulates the Scintilla Python lexer. class QSCINTILLA_EXPORT QsciLexerPython : public QsciLexer { Q_OBJECT public: //! This enum defines the meanings of the different styles used by the //! Python lexer. enum { //! The default. Default = 0, //! A comment. Comment = 1, //! A number. Number = 2, //! A double-quoted string. DoubleQuotedString = 3, //! A single-quoted string. SingleQuotedString = 4, //! A keyword. Keyword = 5, //! A triple single-quoted string. TripleSingleQuotedString = 6, //! A triple double-quoted string. TripleDoubleQuotedString = 7, //! The name of a class. ClassName = 8, //! The name of a function or method. FunctionMethodName = 9, //! An operator. Operator = 10, //! An identifier Identifier = 11, //! A comment block. CommentBlock = 12, //! The end of a line where a string is not closed. UnclosedString = 13, //! A highlighted identifier. These are defined by keyword set //! 2. Reimplement keywords() to define keyword set 2. HighlightedIdentifier = 14, //! A decorator. Decorator = 15, //! A double-quoted f-string. DoubleQuotedFString = 16, //! A single-quoted f-string. SingleQuotedFString = 17, //! A triple single-quoted f-string. TripleSingleQuotedFString = 18, //! A triple double-quoted f-string. TripleDoubleQuotedFString = 19, }; //! This enum defines the different conditions that can cause //! indentations to be displayed as being bad. enum IndentationWarning { //! Bad indentation is not displayed differently. NoWarning = 0, //! The indentation is inconsistent when compared to the //! previous line, ie. it is made up of a different combination //! of tabs and/or spaces. Inconsistent = 1, //! The indentation is made up of spaces followed by tabs. TabsAfterSpaces = 2, //! The indentation contains spaces. Spaces = 3, //! The indentation contains tabs. Tabs = 4 }; //! Construct a QsciLexerPython with parent \a parent. \a parent is //! typically the QsciScintilla instance. QsciLexerPython(QObject *parent = 0); //! Destroys the QsciLexerPython instance. virtual ~QsciLexerPython(); //! Returns the name of the language. const char *language() const; //! Returns the name of the lexer. Some lexers support a number of //! languages. const char *lexer() const; //! \internal Returns the character sequences that can separate //! auto-completion words. QStringList autoCompletionWordSeparators() const; //! \internal Returns the number of lines prior to the current one when //! determining the scope of a block when auto-indenting. int blockLookback() const; //! \internal Returns a space separated list of words or characters in //! a particular style that define the start of a block for //! auto-indentation. The styles is returned via \a style. const char *blockStart(int *style = 0) const; //! \internal Returns the style used for braces for brace matching. int braceStyle() const; //! Returns the foreground colour of the text for style number \a style. //! //! \sa defaultPaper() QColor defaultColor(int style) const; //! Returns the end-of-line fill for style number \a style. bool defaultEolFill(int style) const; //! Returns the font for style number \a style. QFont defaultFont(int style) const; //! Returns the background colour of the text for style number \a style. //! //! \sa defaultColor() QColor defaultPaper(int style) const; //! \internal Returns the view used for indentation guides. virtual int indentationGuideView() const; //! Returns the set of keywords for the keyword set \a set recognised //! by the lexer as a space separated string. const char *keywords(int set) const; //! Returns the descriptive name for style number \a style. If the //! style is invalid for this language then an empty QString is returned. //! This is intended to be used in user preference dialogs. QString description(int style) const; //! Causes all properties to be refreshed by emitting the //! propertyChanged() signal as required. void refreshProperties(); //! Returns true if indented comment blocks can be folded. //! //! \sa setFoldComments() bool foldComments() const {return fold_comments;} //! If \a fold is true then trailing blank lines are included in a fold //! block. The default is true. //! //! \sa foldCompact() void setFoldCompact(bool fold); //! Returns true if trailing blank lines are included in a fold block. //! //! \sa setFoldCompact() bool foldCompact() const {return fold_compact;} //! Returns true if triple quoted strings can be folded. //! //! \sa setFoldQuotes() bool foldQuotes() const {return fold_quotes;} //! Returns the condition that will cause bad indentations to be //! displayed. //! //! \sa setIndentationWarning() QsciLexerPython::IndentationWarning indentationWarning() const {return indent_warn;} //! If \a enabled is true then sub-identifiers defined in keyword set 2 //! will be highlighted. For example, if it is false and "open" is defined //! in keyword set 2 then "foo.open" will not be highlighted. The default //! is true. //! //! \sa highlightSubidentifiers() void setHighlightSubidentifiers(bool enabled); //! Returns true if string literals are allowed to span newline characters. //! //! \sa setHighlightSubidentifiers() bool highlightSubidentifiers() const {return highlight_subids;} //! If \a allowed is true then string literals are allowed to span newline //! characters. The default is false. //! //! \sa stringsOverNewlineAllowed() void setStringsOverNewlineAllowed(bool allowed); //! Returns true if string literals are allowed to span newline characters. //! //! \sa setStringsOverNewlineAllowed() bool stringsOverNewlineAllowed() const {return strings_over_newline;} //! If \a allowed is true then Python v2 unicode string literals (e.g. //! u"utf8") are allowed. The default is true. //! //! \sa v2UnicodeAllowed() void setV2UnicodeAllowed(bool allowed); //! Returns true if Python v2 unicode string literals (e.g. u"utf8") are //! allowed. //! //! \sa setV2UnicodeAllowed() bool v2UnicodeAllowed() const {return v2_unicode;} //! If \a allowed is true then Python v3 binary and octal literals (e.g. //! 0b1011, 0o712) are allowed. The default is true. //! //! \sa v3BinaryOctalAllowed() void setV3BinaryOctalAllowed(bool allowed); //! Returns true if Python v3 binary and octal literals (e.g. 0b1011, //! 0o712) are allowed. //! //! \sa setV3BinaryOctalAllowed() bool v3BinaryOctalAllowed() const {return v3_binary_octal;} //! If \a allowed is true then Python v3 bytes string literals (e.g. //! b"bytes") are allowed. The default is true. //! //! \sa v3BytesAllowed() void setV3BytesAllowed(bool allowed); //! Returns true if Python v3 bytes string literals (e.g. b"bytes") are //! allowed. //! //! \sa setV3BytesAllowed() bool v3BytesAllowed() const {return v3_bytes;} public slots: //! If \a fold is true then indented comment blocks can be folded. The //! default is false. //! //! \sa foldComments() virtual void setFoldComments(bool fold); //! If \a fold is true then triple quoted strings can be folded. The //! default is false. //! //! \sa foldQuotes() virtual void setFoldQuotes(bool fold); //! Sets the condition that will cause bad indentations to be //! displayed. //! //! \sa indentationWarning() virtual void setIndentationWarning(QsciLexerPython::IndentationWarning warn); protected: //! The lexer's properties are read from the settings \a qs. \a prefix //! (which has a trailing '/') should be used as a prefix to the key of //! each setting. true is returned if there is no error. //! bool readProperties(QSettings &qs,const QString &prefix); //! The lexer's properties are written to the settings \a qs. //! \a prefix (which has a trailing '/') should be used as a prefix to //! the key of each setting. true is returned if there is no error. //! bool writeProperties(QSettings &qs,const QString &prefix) const; private: void setCommentProp(); void setCompactProp(); void setQuotesProp(); void setTabWhingeProp(); void setStringsOverNewlineProp(); void setV2UnicodeProp(); void setV3BinaryOctalProp(); void setV3BytesProp(); void setHighlightSubidsProp(); bool fold_comments; bool fold_compact; bool fold_quotes; IndentationWarning indent_warn; bool strings_over_newline; bool v2_unicode; bool v3_binary_octal; bool v3_bytes; bool highlight_subids; friend class QsciLexerHTML; static const char *keywordClass; QsciLexerPython(const QsciLexerPython &); QsciLexerPython &operator=(const QsciLexerPython &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscilexersql.h000066400000000000000000000212751463772530400276300ustar00rootroot00000000000000// This defines the interface to the QsciLexerSQL class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCILEXERSQL_H #define QSCILEXERSQL_H #include #include #include //! \brief The QsciLexerSQL class encapsulates the Scintilla SQL lexer. class QSCINTILLA_EXPORT QsciLexerSQL : public QsciLexer { Q_OBJECT public: //! This enum defines the meanings of the different styles used by the //! SQL lexer. enum { //! The default. Default = 0, //! A comment. Comment = 1, //! A line comment. CommentLine = 2, //! A JavaDoc/Doxygen style comment. CommentDoc = 3, //! A number. Number = 4, //! A keyword. Keyword = 5, //! A double-quoted string. DoubleQuotedString = 6, //! A single-quoted string. SingleQuotedString = 7, //! An SQL*Plus keyword. PlusKeyword = 8, //! An SQL*Plus prompt. PlusPrompt = 9, //! An operator. Operator = 10, //! An identifier Identifier = 11, //! An SQL*Plus comment. PlusComment = 13, //! A '#' line comment. CommentLineHash = 15, //! A JavaDoc/Doxygen keyword. CommentDocKeyword = 17, //! A JavaDoc/Doxygen keyword error. CommentDocKeywordError = 18, //! A keyword defined in keyword set number 5. The class must be //! sub-classed and re-implement keywords() to make use of this style. //! Note that keywords must be defined using lower case. KeywordSet5 = 19, //! A keyword defined in keyword set number 6. The class must be //! sub-classed and re-implement keywords() to make use of this style. //! Note that keywords must be defined using lower case. KeywordSet6 = 20, //! A keyword defined in keyword set number 7. The class must be //! sub-classed and re-implement keywords() to make use of this style. //! Note that keywords must be defined using lower case. KeywordSet7 = 21, //! A keyword defined in keyword set number 8. The class must be //! sub-classed and re-implement keywords() to make use of this style. //! Note that keywords must be defined using lower case. KeywordSet8 = 22, //! A quoted identifier. QuotedIdentifier = 23, //! A quoted operator. QuotedOperator = 24, }; //! Construct a QsciLexerSQL with parent \a parent. \a parent is typically //! the QsciScintilla instance. QsciLexerSQL(QObject *parent = 0); //! Destroys the QsciLexerSQL instance. virtual ~QsciLexerSQL(); //! Returns the name of the language. const char *language() const; //! Returns the name of the lexer. Some lexers support a number of //! languages. const char *lexer() const; //! \internal Returns the style used for braces for brace matching. int braceStyle() const; //! Returns the foreground colour of the text for style number \a style. //! //! \sa defaultPaper() QColor defaultColor(int style) const; //! Returns the end-of-line fill for style number \a style. bool defaultEolFill(int style) const; //! Returns the font for style number \a style. QFont defaultFont(int style) const; //! Returns the background colour of the text for style number \a style. //! //! \sa defaultColor() QColor defaultPaper(int style) const; //! Returns the set of keywords for the keyword set \a set recognised by //! the lexer as a space separated string. const char *keywords(int set) const; //! Returns the descriptive name for style number \a style. If the style //! is invalid for this language then an empty QString is returned. This //! is intended to be used in user preference dialogs. QString description(int style) const; //! Causes all properties to be refreshed by emitting the //! propertyChanged() signal as required. void refreshProperties(); //! Returns true if backslash escapes are enabled. //! //! \sa setBackslashEscapes() bool backslashEscapes() const {return backslash_escapes;} //! If \a enable is true then words may contain dots (i.e. periods or full //! stops). The default is false. //! //! \sa dottedWords() void setDottedWords(bool enable); //! Returns true if words may contain dots (i.e. periods or full stops). //! //! \sa setDottedWords() bool dottedWords() const {return allow_dotted_word;} //! If \a fold is true then ELSE blocks can be folded. The default is //! false. //! //! \sa foldAtElse() void setFoldAtElse(bool fold); //! Returns true if ELSE blocks can be folded. //! //! \sa setFoldAtElse() bool foldAtElse() const {return at_else;} //! Returns true if multi-line comment blocks can be folded. //! //! \sa setFoldComments() bool foldComments() const {return fold_comments;} //! Returns true if trailing blank lines are included in a fold block. //! //! \sa setFoldCompact() bool foldCompact() const {return fold_compact;} //! If \a fold is true then only BEGIN blocks can be folded. The default //! is false. //! //! \sa foldOnlyBegin() void setFoldOnlyBegin(bool fold); //! Returns true if BEGIN blocks only can be folded. //! //! \sa setFoldOnlyBegin() bool foldOnlyBegin() const {return only_begin;} //! If \a enable is true then '#' is used as a comment character. It is //! typically enabled for MySQL and disabled for Oracle. The default is //! false. //! //! \sa hashComments() void setHashComments(bool enable); //! Returns true if '#' is used as a comment character. //! //! \sa setHashComments() bool hashComments() const {return numbersign_comment;} //! If \a enable is true then quoted identifiers are enabled. The default //! is false. //! //! \sa quotedIdentifiers() void setQuotedIdentifiers(bool enable); //! Returns true if quoted identifiers are enabled. //! //! \sa setQuotedIdentifiers() bool quotedIdentifiers() const {return backticks_identifier;} public slots: //! If \a enable is true then backslash escapes are enabled. The //! default is false. //! //! \sa backslashEscapes() virtual void setBackslashEscapes(bool enable); //! If \a fold is true then multi-line comment blocks can be folded. The //! default is false. //! //! \sa foldComments() virtual void setFoldComments(bool fold); //! If \a fold is true then trailing blank lines are included in a fold //! block. The default is true. //! //! \sa foldCompact() virtual void setFoldCompact(bool fold); protected: //! The lexer's properties are read from the settings \a qs. \a prefix //! (which has a trailing '/') should be used as a prefix to the key of //! each setting. true is returned if there is no error. //! bool readProperties(QSettings &qs, const QString &prefix); //! The lexer's properties are written to the settings \a qs. //! \a prefix (which has a trailing '/') should be used as a prefix to //! the key of each setting. true is returned if there is no error. //! bool writeProperties(QSettings &qs, const QString &prefix) const; private: void setAtElseProp(); void setCommentProp(); void setCompactProp(); void setOnlyBeginProp(); void setBackticksIdentifierProp(); void setNumbersignCommentProp(); void setBackslashEscapesProp(); void setAllowDottedWordProp(); bool at_else; bool fold_comments; bool fold_compact; bool only_begin; bool backticks_identifier; bool numbersign_comment; bool backslash_escapes; bool allow_dotted_word; QsciLexerSQL(const QsciLexerSQL &); QsciLexerSQL &operator=(const QsciLexerSQL &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscilexerxml.h000066400000000000000000000066021463772530400276260ustar00rootroot00000000000000// This defines the interface to the QsciLexerXML class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCILEXERXML_H #define QSCILEXERXML_H #include #include #include //! \brief The QsciLexerXML class encapsulates the Scintilla XML lexer. class QSCINTILLA_EXPORT QsciLexerXML : public QsciLexerHTML { Q_OBJECT public: //! Construct a QsciLexerXML with parent \a parent. \a parent is typically //! the QsciScintilla instance. QsciLexerXML(QObject *parent = 0); //! Destroys the QsciLexerXML instance. virtual ~QsciLexerXML(); //! Returns the name of the language. const char *language() const; //! Returns the name of the lexer. Some lexers support a number of //! languages. const char *lexer() const; //! Returns the foreground colour of the text for style number \a style. //! //! \sa defaultPaper() QColor defaultColor(int style) const; //! Returns the end-of-line fill for style number \a style. bool defaultEolFill(int style) const; //! Returns the font for style number \a style. QFont defaultFont(int style) const; //! Returns the background colour of the text for style number \a style. //! //! \sa defaultColor() QColor defaultPaper(int style) const; //! Returns the set of keywords for the keyword set \a set recognised //! by the lexer as a space separated string. const char *keywords(int set) const; //! Causes all properties to be refreshed by emitting the //! propertyChanged() signal as required. void refreshProperties(); //! If \a allowed is true then scripts are styled. The default is true. //! //! \sa scriptsStyled() void setScriptsStyled(bool styled); //! Returns true if scripts are styled. //! //! \sa setScriptsStyled() bool scriptsStyled() const; protected: //! The lexer's properties are read from the settings \a qs. \a prefix //! (which has a trailing '/') should be used as a prefix to the key of //! each setting. true is returned if there is no error. //! bool readProperties(QSettings &qs, const QString &prefix); //! The lexer's properties are written to the settings \a qs. //! \a prefix (which has a trailing '/') should be used as a prefix to //! the key of each setting. true is returned if there is no error. //! bool writeProperties(QSettings &qs, const QString &prefix) const; private: void setScriptsProp(); bool scripts; QsciLexerXML(const QsciLexerXML &); QsciLexerXML &operator=(const QsciLexerXML &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscimacro.h000066400000000000000000000053421463772530400270670ustar00rootroot00000000000000// This defines the interface to the QsciMacro class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCIMACRO_H #define QSCIMACRO_H #include #include #include #include class QsciScintilla; //! \brief The QsciMacro class represents a sequence of recordable editor //! commands. //! //! Methods are provided to convert convert a macro to and from a textual //! representation so that they can be easily written to and read from //! permanent storage. class QSCINTILLA_EXPORT QsciMacro : public QObject { Q_OBJECT public: //! Construct a QsciMacro with parent \a parent. QsciMacro(QsciScintilla *parent); //! Construct a QsciMacro from the printable ASCII representation \a asc, //! with parent \a parent. QsciMacro(const QString &asc, QsciScintilla *parent); //! Destroy the QsciMacro instance. virtual ~QsciMacro(); //! Clear the contents of the macro. void clear(); //! Load the macro from the printable ASCII representation \a asc. Returns //! true if there was no error. //! //! \sa save() bool load(const QString &asc); //! Return a printable ASCII representation of the macro. It is guaranteed //! that only printable ASCII characters are used and that double quote //! characters will not be used. //! //! \sa load() QString save() const; public slots: //! Play the macro. virtual void play(); //! Start recording user commands and add them to the macro. virtual void startRecording(); //! Stop recording user commands. virtual void endRecording(); private slots: void record(unsigned int msg, unsigned long wParam, void *lParam); private: struct Macro { unsigned int msg; unsigned long wParam; QByteArray text; }; QsciScintilla *qsci; QList macro; QsciMacro(const QsciMacro &); QsciMacro &operator=(const QsciMacro &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qsciprinter.h000066400000000000000000000075331463772530400274550ustar00rootroot00000000000000// This module defines interface to the QsciPrinter class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCIPRINTER_H #define QSCIPRINTER_H // This is needed for Qt v5.0.0-alpha. #if defined(B0) #undef B0 #endif #include #if !defined(QT_NO_PRINTER) #include #include QT_BEGIN_NAMESPACE class QRect; class QPainter; QT_END_NAMESPACE class QsciScintillaBase; //! \brief The QsciPrinter class is a sub-class of the Qt QPrinter class that //! is able to print the text of a Scintilla document. //! //! The class can be further sub-classed to alter to layout of the text, adding //! headers and footers for example. class QSCINTILLA_EXPORT QsciPrinter : public QPrinter { public: //! Constructs a printer paint device with mode \a mode. QsciPrinter(PrinterMode mode = ScreenResolution); //! Destroys the QsciPrinter instance. virtual ~QsciPrinter(); //! Format a page, by adding headers and footers for example, before the //! document text is drawn on it. \a painter is the painter to be used to //! add customised text and graphics. \a drawing is true if the page is //! actually being drawn rather than being sized. \a painter drawing //! methods must only be called when \a drawing is true. \a area is the //! area of the page that will be used to draw the text. This should be //! modified if it is necessary to reserve space for any customised text or //! graphics. By default the area is relative to the printable area of the //! page. Use QPrinter::setFullPage() because calling printRange() if you //! want to try and print over the whole page. \a pagenr is the number of //! the page. The first page is numbered 1. virtual void formatPage(QPainter &painter, bool drawing, QRect &area, int pagenr); //! Return the number of points to add to each font when printing. //! //! \sa setMagnification() int magnification() const {return mag;} //! Sets the number of points to add to each font when printing to \a //! magnification. //! //! \sa magnification() virtual void setMagnification(int magnification); //! Print a range of lines from the Scintilla instance \a qsb. \a from is //! the first line to print and a negative value signifies the first line //! of text. \a to is the last line to print and a negative value //! signifies the last line of text. true is returned if there was no //! error. virtual int printRange(QsciScintillaBase *qsb, int from = -1, int to = -1); //! Return the line wrap mode used when printing. The default is //! QsciScintilla::WrapWord. //! //! \sa setWrapMode() QsciScintilla::WrapMode wrapMode() const {return wrap;} //! Sets the line wrap mode used when printing to \a wmode. //! //! \sa wrapMode() virtual void setWrapMode(QsciScintilla::WrapMode wmode); private: int mag; QsciScintilla::WrapMode wrap; QsciPrinter(const QsciPrinter &); QsciPrinter &operator=(const QsciPrinter &); }; #endif #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qsciscintilla.h000066400000000000000000002503431463772530400277530ustar00rootroot00000000000000// This module defines the "official" high-level API of the Qt port of // Scintilla. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCISCINTILLA_H #define QSCISCINTILLA_H #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QAction; class QImage; class QIODevice; class QMenu; class QPoint; QT_END_NAMESPACE class QsciCommandSet; class QsciLexer; class QsciStyle; class QsciStyledText; class QsciListBoxQt; //! \brief The QsciScintilla class implements a higher level, more Qt-like, //! API to the Scintilla editor widget. //! //! QsciScintilla implements methods, signals and slots similar to those found //! in other Qt editor classes. It also provides a higher level interface to //! features specific to Scintilla such as syntax styling, call tips, //! auto-indenting and auto-completion than that provided by QsciScintillaBase. class QSCINTILLA_EXPORT QsciScintilla : public QsciScintillaBase { Q_OBJECT public: //! This enum defines the different auto-indentation styles. enum { //! A line is automatically indented to match the previous line. AiMaintain = 0x01, //! If the language supported by the current lexer has a specific start //! of block character (e.g. { in C++), then a line that begins with //! that character is indented as well as the lines that make up the //! block. It may be logically ored with AiClosing. AiOpening = 0x02, //! If the language supported by the current lexer has a specific end //! of block character (e.g. } in C++), then a line that begins with //! that character is indented as well as the lines that make up the //! block. It may be logically ored with AiOpening. AiClosing = 0x04 }; //! This enum defines the different annotation display styles. enum AnnotationDisplay { //! Annotations are not displayed. AnnotationHidden = ANNOTATION_HIDDEN, //! Annotations are drawn left justified with no adornment. AnnotationStandard = ANNOTATION_STANDARD, //! Annotations are surrounded by a box. AnnotationBoxed = ANNOTATION_BOXED, //! Annotations are indented to match the text. AnnotationIndented = ANNOTATION_INDENTED, }; //! This enum defines the behavior if an auto-completion list contains a //! single entry. enum AutoCompletionUseSingle { //! The single entry is not used automatically and the auto-completion //! list is displayed. AcusNever, //! The single entry is used automatically when auto-completion is //! explicitly requested (using autoCompleteFromAPIs() or //! autoCompleteFromDocument()) but not when auto-completion is //! triggered as the user types. AcusExplicit, //! The single entry is used automatically and the auto-completion list //! is not displayed. AcusAlways }; //! This enum defines the different sources for auto-completion lists. enum AutoCompletionSource { //! No sources are used, ie. automatic auto-completion is disabled. AcsNone, //! The source is all available sources. AcsAll, //! The source is the current document. AcsDocument, //! The source is any installed APIs. AcsAPIs }; //! This enum defines the different brace matching modes. The character //! pairs {}, [] and () are treated as braces. The Python lexer will also //! match a : with the end of the corresponding indented block. enum BraceMatch { //! Brace matching is disabled. NoBraceMatch, //! Brace matching is enabled for a brace immediately before the //! current position. StrictBraceMatch, //! Brace matching is enabled for a brace immediately before or after //! the current position. SloppyBraceMatch }; //! This enum defines the different call tip positions. enum CallTipsPosition { //! Call tips are placed below the text. CallTipsBelowText, //! Call tips are placed above the text. CallTipsAboveText, }; //! This enum defines the different call tip styles. enum CallTipsStyle { //! Call tips are disabled. CallTipsNone, //! Call tips are displayed without a context. A context is any scope //! (e.g. a C++ namespace or a Python module) prior to the function //! name. CallTipsNoContext, //! Call tips are displayed with a context only if the user hasn't //! already implicitly identified the context using autocompletion. //! Note that this style may not always be able to align the call tip //! with the text being entered. CallTipsNoAutoCompletionContext, //! Call tips are displayed with a context. Note that this style //! may not always be able to align the call tip with the text being //! entered. CallTipsContext }; //! This enum defines the different edge modes for long lines. enum EdgeMode { //! Long lines are not marked. EdgeNone = EDGE_NONE, //! A vertical line is drawn at the column set by setEdgeColumn(). //! This is recommended for monospace fonts. EdgeLine = EDGE_LINE, //! The background color of characters after the column limit is //! changed to the color set by setEdgeColor(). This is recommended //! for proportional fonts. EdgeBackground = EDGE_BACKGROUND, //! Multiple vertical lines are drawn at the columns defined by //! multiple calls to addEdgeColumn(). EdgeMultipleLines = EDGE_MULTILINE, }; //! This enum defines the different end-of-line modes. enum EolMode { //! A carriage return/line feed as used on Windows systems. EolWindows = SC_EOL_CRLF, //! A line feed as used on Unix systems, including OS/X. EolUnix = SC_EOL_LF, //! A carriage return as used on Mac systems prior to OS/X. EolMac = SC_EOL_CR }; //! This enum defines the different styles for the folding margin. enum FoldStyle { //! Folding is disabled. NoFoldStyle, //! Plain folding style using plus and minus symbols. PlainFoldStyle, //! Circled folding style using circled plus and minus symbols. CircledFoldStyle, //! Boxed folding style using boxed plus and minus symbols. BoxedFoldStyle, //! Circled tree style using a flattened tree with circled plus and //! minus symbols and rounded corners. CircledTreeFoldStyle, //! Boxed tree style using a flattened tree with boxed plus and minus //! symbols and right-angled corners. BoxedTreeFoldStyle }; //! This enum defines the different indicator styles. enum IndicatorStyle { //! A single straight underline. PlainIndicator = INDIC_PLAIN, //! A squiggly underline that requires 3 pixels of descender space. SquiggleIndicator = INDIC_SQUIGGLE, //! A line of small T shapes. TTIndicator = INDIC_TT, //! Diagonal hatching. DiagonalIndicator = INDIC_DIAGONAL, //! Strike out. StrikeIndicator = INDIC_STRIKE, //! An indicator with no visual appearence. HiddenIndicator = INDIC_HIDDEN, //! A rectangle around the text. BoxIndicator = INDIC_BOX, //! A rectangle with rounded corners around the text with the interior //! usually more transparent than the border. RoundBoxIndicator = INDIC_ROUNDBOX, //! A rectangle around the text with the interior usually more //! transparent than the border. It does not colour the top pixel of //! the line so that indicators on contiguous lines are visually //! distinct and disconnected. StraightBoxIndicator = INDIC_STRAIGHTBOX, //! A rectangle around the text with the interior usually more //! transparent than the border. Unlike StraightBoxIndicator it covers //! the entire character area. FullBoxIndicator = INDIC_FULLBOX, //! A dashed underline. DashesIndicator = INDIC_DASH, //! A dotted underline. DotsIndicator = INDIC_DOTS, //! A squiggly underline that requires 2 pixels of descender space and //! so will fit under smaller fonts. SquiggleLowIndicator = INDIC_SQUIGGLELOW, //! A dotted rectangle around the text with the interior usually more //! transparent than the border. DotBoxIndicator = INDIC_DOTBOX, //! A version of SquiggleIndicator that uses a pixmap. This is quicker //! but may be of lower quality. SquigglePixmapIndicator = INDIC_SQUIGGLEPIXMAP, //! A thick underline typically used for the target during Asian //! language input composition. ThickCompositionIndicator = INDIC_COMPOSITIONTHICK, //! A thin underline typically used for non-target ranges during Asian //! language input composition. ThinCompositionIndicator = INDIC_COMPOSITIONTHIN, //! The color of the text is set to the color of the indicator's //! foreground. TextColorIndicator = INDIC_TEXTFORE, //! A triangle below the start of the indicator range. TriangleIndicator = INDIC_POINT, //! A triangle below the centre of the first character in the indicator //! range. TriangleCharacterIndicator = INDIC_POINTCHARACTER, //! A vertical gradient between the indicator's foreground colour at //! top to fully transparent at the bottom. GradientIndicator = INDIC_GRADIENT, //! A vertical gradient with the indicator's foreground colour in the //! middle and fading to fully transparent at the top and bottom. CentreGradientIndicator = INDIC_GRADIENTCENTRE, }; //! This enum defines the different margin options. enum { //! Reset all margin options. MoNone = SC_MARGINOPTION_NONE, //! If this is set then only the first sub-line of a wrapped line will //! be selected when clicking on a margin. MoSublineSelect = SC_MARGINOPTION_SUBLINESELECT }; //! This enum defines the different margin types. enum MarginType { //! The margin contains symbols, including those used for folding. SymbolMargin = SC_MARGIN_SYMBOL, //! The margin contains symbols and uses the default foreground color //! as its background color. SymbolMarginDefaultForegroundColor = SC_MARGIN_FORE, //! The margin contains symbols and uses the default background color //! as its background color. SymbolMarginDefaultBackgroundColor = SC_MARGIN_BACK, //! The margin contains line numbers. NumberMargin = SC_MARGIN_NUMBER, //! The margin contains styled text. TextMargin = SC_MARGIN_TEXT, //! The margin contains right justified styled text. TextMarginRightJustified = SC_MARGIN_RTEXT, //! The margin contains symbols and uses the color set by //! setMarginBackgroundColor() as its background color. SymbolMarginColor = SC_MARGIN_COLOUR, }; //! This enum defines the different pre-defined marker symbols. enum MarkerSymbol { //! A circle. Circle = SC_MARK_CIRCLE, //! A rectangle. Rectangle = SC_MARK_ROUNDRECT, //! A triangle pointing to the right. RightTriangle = SC_MARK_ARROW, //! A smaller rectangle. SmallRectangle = SC_MARK_SMALLRECT, //! An arrow pointing to the right. RightArrow = SC_MARK_SHORTARROW, //! An invisible marker that allows code to track the movement //! of lines. Invisible = SC_MARK_EMPTY, //! A triangle pointing down. DownTriangle = SC_MARK_ARROWDOWN, //! A drawn minus sign. Minus = SC_MARK_MINUS, //! A drawn plus sign. Plus = SC_MARK_PLUS, //! A vertical line drawn in the background colour. VerticalLine = SC_MARK_VLINE, //! A bottom left corner drawn in the background colour. BottomLeftCorner = SC_MARK_LCORNER, //! A vertical line with a centre right horizontal line drawn //! in the background colour. LeftSideSplitter = SC_MARK_TCORNER, //! A drawn plus sign in a box. BoxedPlus = SC_MARK_BOXPLUS, //! A drawn plus sign in a connected box. BoxedPlusConnected = SC_MARK_BOXPLUSCONNECTED, //! A drawn minus sign in a box. BoxedMinus = SC_MARK_BOXMINUS, //! A drawn minus sign in a connected box. BoxedMinusConnected = SC_MARK_BOXMINUSCONNECTED, //! A rounded bottom left corner drawn in the background //! colour. RoundedBottomLeftCorner = SC_MARK_LCORNERCURVE, //! A vertical line with a centre right curved line drawn in the //! background colour. LeftSideRoundedSplitter = SC_MARK_TCORNERCURVE, //! A drawn plus sign in a circle. CircledPlus = SC_MARK_CIRCLEPLUS, //! A drawn plus sign in a connected box. CircledPlusConnected = SC_MARK_CIRCLEPLUSCONNECTED, //! A drawn minus sign in a circle. CircledMinus = SC_MARK_CIRCLEMINUS, //! A drawn minus sign in a connected circle. CircledMinusConnected = SC_MARK_CIRCLEMINUSCONNECTED, //! No symbol is drawn but the line is drawn with the same background //! color as the marker's. Background = SC_MARK_BACKGROUND, //! Three drawn dots. ThreeDots = SC_MARK_DOTDOTDOT, //! Three drawn arrows pointing right. ThreeRightArrows = SC_MARK_ARROWS, //! A full rectangle (ie. the margin background) using the marker's //! background color. FullRectangle = SC_MARK_FULLRECT, //! A left rectangle (ie. the left part of the margin background) using //! the marker's background color. LeftRectangle = SC_MARK_LEFTRECT, //! No symbol is drawn but the line is drawn underlined using the //! marker's background color. Underline = SC_MARK_UNDERLINE, //! A bookmark. Bookmark = SC_MARK_BOOKMARK, }; //! This enum defines how tab characters are drawn when whitespace is //! visible. enum TabDrawMode { //! An arrow stretching to the tab stop. TabLongArrow = SCTD_LONGARROW, //! A horizontal line stretching to the tab stop. TabStrikeOut = SCTD_STRIKEOUT, }; //! This enum defines the different whitespace visibility modes. When //! whitespace is visible spaces are displayed as small centred dots and //! tabs are displayed as light arrows pointing to the right. enum WhitespaceVisibility { //! Whitespace is invisible. WsInvisible = SCWS_INVISIBLE, //! Whitespace is always visible. WsVisible = SCWS_VISIBLEALWAYS, //! Whitespace is visible after the whitespace used for indentation. WsVisibleAfterIndent = SCWS_VISIBLEAFTERINDENT, //! Whitespace used for indentation is visible. WsVisibleOnlyInIndent = SCWS_VISIBLEONLYININDENT, }; //! This enum defines the different line wrap modes. enum WrapMode { //! Lines are not wrapped. WrapNone = SC_WRAP_NONE, //! Lines are wrapped at word boundaries. WrapWord = SC_WRAP_WORD, //! Lines are wrapped at character boundaries. WrapCharacter = SC_WRAP_CHAR, //! Lines are wrapped at whitespace boundaries. WrapWhitespace = SC_WRAP_WHITESPACE, }; //! This enum defines the different line wrap visual flags. enum WrapVisualFlag { //! No wrap flag is displayed. WrapFlagNone, //! A wrap flag is displayed by the text. WrapFlagByText, //! A wrap flag is displayed by the border. WrapFlagByBorder, //! A wrap flag is displayed in the line number margin. WrapFlagInMargin }; //! This enum defines the different line wrap indentation modes. enum WrapIndentMode { //! Wrapped sub-lines are indented by the amount set by //! setWrapVisualFlags(). WrapIndentFixed = SC_WRAPINDENT_FIXED, //! Wrapped sub-lines are indented by the same amount as the first //! sub-line. WrapIndentSame = SC_WRAPINDENT_SAME, //! Wrapped sub-lines are indented by the same amount as the first //! sub-line plus one more level of indentation. WrapIndentIndented = SC_WRAPINDENT_INDENT, //! Wrapped sub-lines are indented by the same amount as the first //! sub-line plus two more level of indentation. WrapIndentDeeplyIndented = SC_WRAPINDENT_DEEPINDENT }; //! Construct an empty QsciScintilla with parent \a parent. QsciScintilla(QWidget *parent = 0); //! Destroys the QsciScintilla instance. virtual ~QsciScintilla(); //! Returns the API context, which is a list of words, before the position //! \a pos in the document. The context can be used by auto-completion and //! call tips to help to identify which API call the user is referring to. //! In the default implementation the current lexer determines what //! characters make up a word, and what characters determine the boundaries //! of words (ie. the start characters). If there is no current lexer then //! the context will consist of a single word. On return \a context_start //! will contain the position in the document of the start of the context //! and \a last_word_start will contain the position in the document of the //! start of the last word of the context. virtual QStringList apiContext(int pos, int &context_start, int &last_word_start); //! Annotate the line \a line with the text \a text using the style number //! \a style. void annotate(int line, const QString &text, int style); //! Annotate the line \a line with the text \a text using the style \a //! style. void annotate(int line, const QString &text, const QsciStyle &style); //! Annotate the line \a line with the styled text \a text. void annotate(int line, const QsciStyledText &text); //! Annotate the line \a line with the list of styled text \a text. void annotate(int line, const QList &text); //! Returns the annotation on line \a line, if any. QString annotation(int line) const; //! Returns the display style for annotations. //! //! \sa setAnnotationDisplay() AnnotationDisplay annotationDisplay() const; //! The annotations on line \a line are removed. If \a line is negative //! then all annotations are removed. void clearAnnotations(int line = -1); //! Returns true if auto-completion lists are case sensitive. //! //! \sa setAutoCompletionCaseSensitivity() bool autoCompletionCaseSensitivity() const; //! Returns true if auto-completion fill-up characters are enabled. //! //! \sa setAutoCompletionFillups(), setAutoCompletionFillupsEnabled() bool autoCompletionFillupsEnabled() const; //! Returns true if the rest of the word to the right of the current cursor //! is removed when an item from an auto-completion list is selected. //! //! \sa setAutoCompletionReplaceWord() bool autoCompletionReplaceWord() const; //! Returns true if the only item in an auto-completion list with a single //! entry is automatically used and the list not displayed. Note that this //! is deprecated and autoCompletionUseSingle() should be used instead. //! //! \sa setAutoCompletionShowSingle() bool autoCompletionShowSingle() const; //! Returns the current source for the auto-completion list when it is //! being displayed automatically as the user types. //! //! \sa setAutoCompletionSource() AutoCompletionSource autoCompletionSource() const {return acSource;} //! Returns the current threshold for the automatic display of the //! auto-completion list as the user types. //! //! \sa setAutoCompletionThreshold() int autoCompletionThreshold() const {return acThresh;} //! Returns the current behavior when an auto-completion list contains a //! single entry. //! //! \sa setAutoCompletionUseSingle() AutoCompletionUseSingle autoCompletionUseSingle() const; //! Returns true if auto-indentation is enabled. //! //! \sa setAutoIndent() bool autoIndent() const {return autoInd;} //! Returns true if the backspace key unindents a line instead of deleting //! a character. The default is false. //! //! \sa setBackspaceUnindents(), tabIndents(), setTabIndents() bool backspaceUnindents() const; //! Mark the beginning of a sequence of actions that can be undone by a //! single call to undo(). //! //! \sa endUndoAction(), undo() void beginUndoAction(); //! Returns the brace matching mode. //! //! \sa setBraceMatching() BraceMatch braceMatching() const {return braceMode;} //! Returns the encoded text between positions \a start and \a end. This //! is typically used by QsciLexerCustom::styleText(). //! //! \sa text() QByteArray bytes(int start, int end) const; //! Returns the current call tip position. //! //! \sa setCallTipsPosition() CallTipsPosition callTipsPosition() const {return call_tips_position;} //! Returns the current call tip style. //! //! \sa setCallTipsStyle() CallTipsStyle callTipsStyle() const {return call_tips_style;} //! Returns the maximum number of call tips that are displayed. //! //! \sa setCallTipsVisible() int callTipsVisible() const {return maxCallTips;} //! Cancel any previous call to findFirst(), findFirstInSelection() or //! findNext() so that replace() does nothing. void cancelFind(); //! Cancel any current auto-completion or user defined list. void cancelList(); //! Returns true if the current language lexer is case sensitive. If there //! is no current lexer then true is returned. bool caseSensitive() const; //! Clear all current folds, i.e. ensure that all lines are displayed //! unfolded. //! //! \sa setFolding() void clearFolds(); //! Clears the range of text with indicator \a indicatorNumber starting at //! position \a indexFrom in line \a lineFrom and finishing at position //! \a indexTo in line \a lineTo. //! //! \sa fillIndicatorRange() void clearIndicatorRange(int lineFrom, int indexFrom, int lineTo, int indexTo, int indicatorNumber); //! Clear all registered images. //! //! \sa registerImage() void clearRegisteredImages(); //! Returns the widget's text (ie. foreground) colour. //! //! \sa setColor() QColor color() const; //! Returns a list of the line numbers that have contracted folds. This is //! typically used to save the fold state of a document. //! //! \sa setContractedFolds() QList contractedFolds() const; //! All the lines of the text have their end-of-lines converted to mode //! \a mode. //! //! \sa eolMode(), setEolMode() void convertEols(EolMode mode); //! Create the standard context menu which is shown when the user clicks //! with the right mouse button. It is called from contextMenuEvent(). //! The menu's ownership is transferred to the caller. QMenu *createStandardContextMenu(); //! Returns the attached document. //! //! \sa setDocument() QsciDocument document() const {return doc;} //! Mark the end of a sequence of actions that can be undone by a single //! call to undo(). //! //! \sa beginUndoAction(), undo() void endUndoAction(); //! Returns the color of the marker used to show that a line has exceeded //! the length set by setEdgeColumn(). //! //! \sa setEdgeColor(), \sa setEdgeColumn QColor edgeColor() const; //! Returns the number of the column after which lines are considered to be //! long. //! //! \sa setEdgeColumn() int edgeColumn() const; //! Returns the edge mode which determines how long lines are marked. //! //! \sa setEdgeMode() EdgeMode edgeMode() const; //! Set the default font. This has no effect if a language lexer has been //! set. void setFont(const QFont &f); //! Returns the end-of-line mode. //! //! \sa setEolMode() EolMode eolMode() const; //! Returns the visibility of end-of-lines. //! //! \sa setEolVisibility() bool eolVisibility() const; //! Returns the extra space added to the height of a line above the //! baseline of the text. //! //! \sa setExtraAscent(), extraDescent() int extraAscent() const; //! Returns the extra space added to the height of a line below the //! baseline of the text. //! //! \sa setExtraDescent(), extraAscent() int extraDescent() const; //! Fills the range of text with indicator \a indicatorNumber starting at //! position \a indexFrom in line \a lineFrom and finishing at position //! \a indexTo in line \a lineTo. //! //! \sa clearIndicatorRange() void fillIndicatorRange(int lineFrom, int indexFrom, int lineTo, int indexTo, int indicatorNumber); //! Find the first occurrence of the string \a expr and return true if //! \a expr was found, otherwise returns false. If \a expr is found it //! becomes the current selection. //! //! If \a re is true then \a expr is interpreted as a regular expression //! rather than a simple string. //! //! If \a cs is true then the search is case sensitive. //! //! If \a wo is true then the search looks for whole word matches only, //! otherwise it searches for any matching text. //! //! If \a wrap is true then the search wraps around the end of the text. //! //! If \a forward is true (the default) then the search is forward from the //! starting position to the end of the text, otherwise it is backwards to //! the beginning of the text. //! //! If either \a line or \a index are negative (the default) then the //! search begins from the current cursor position. Otherwise the search //! begins at position \a index of line \a line. //! //! If \a show is true (the default) then any text found is made visible //! (ie. it is unfolded). //! //! If \a posix is true then a regular expression is treated in a more //! POSIX compatible manner by interpreting bare ( and ) as tagged sections //! rather than \( and \). //! //! If \a cxx11 is true then a regular expression is treated as a Cxx11 //! regular expression. //! //! \sa cancelFind(), findFirstInSelection(), findNext(), replace() virtual bool findFirst(const QString &expr, bool re, bool cs, bool wo, bool wrap, bool forward = true, int line = -1, int index = -1, bool show = true, bool posix = false, bool cxx11 = false); //! Find the first occurrence of the string \a expr in the current //! selection and return true if \a expr was found, otherwise returns //! false. If \a expr is found it becomes the current selection. The //! original selection is restored when a subsequent call to findNext() //! returns false. //! //! If \a re is true then \a expr is interpreted as a regular expression //! rather than a simple string. //! //! If \a cs is true then the search is case sensitive. //! //! If \a wo is true then the search looks for whole word matches only, //! otherwise it searches for any matching text. //! //! If \a forward is true (the default) then the search is forward from the //! start to the end of the selection, otherwise it is backwards from the //! end to the start of the selection. //! //! If \a show is true (the default) then any text found is made visible //! (ie. it is unfolded). //! //! If \a posix is true then a regular expression is treated in a more //! POSIX compatible manner by interpreting bare ( and ) as tagged sections //! rather than \( and \). //! //! If \a cxx11 is true then a regular expression is treated as a Cxx11 //! regular expression. //! //! \sa cancelFind(), findFirst(), findNext(), replace() virtual bool findFirstInSelection(const QString &expr, bool re, bool cs, bool wo, bool forward = true, bool show = true, bool posix = false, bool cxx11 = false); //! Find the next occurence of the string found using findFirst() or //! findFirstInSelection(). //! //! \sa cancelFind(), findFirst(), findFirstInSelection(), replace() virtual bool findNext(); //! Returns the number of the first visible line. //! //! \sa setFirstVisibleLine() int firstVisibleLine() const; //! Returns the current folding style. //! //! \sa setFolding() FoldStyle folding() const {return fold;} //! Sets \a *line and \a *index to the line and index of the cursor. //! //! \sa setCursorPosition() void getCursorPosition(int *line, int *index) const; //! If there is a selection, \a *lineFrom is set to the line number in //! which the selection begins and \a *lineTo is set to the line number in //! which the selection ends. (They could be the same.) \a *indexFrom is //! set to the index at which the selection begins within \a *lineFrom, and //! \a *indexTo is set to the index at which the selection ends within //! \a *lineTo. If there is no selection, \a *lineFrom, \a *indexFrom, //! \a *lineTo and \a *indexTo are all set to -1. //! //! \sa setSelection() void getSelection(int *lineFrom, int *indexFrom, int *lineTo, int *indexTo) const; //! Returns true if some text is selected. //! //! \sa selectedText() bool hasSelectedText() const {return selText;} //! Returns the number of characters that line \a line is indented by. //! //! \sa setIndentation() int indentation(int line) const; //! Returns true if the display of indentation guides is enabled. //! //! \sa setIndentationGuides() bool indentationGuides() const; //! Returns true if indentations are created using tabs and spaces, rather //! than just spaces. The default is true. //! //! \sa setIndentationsUseTabs() bool indentationsUseTabs() const; //! Returns the indentation width in characters. The default is 0 which //! means that the value returned by tabWidth() is actually used. //! //! \sa setIndentationWidth(), tabWidth() int indentationWidth() const; //! Define a type of indicator using the style \a style with the indicator //! number \a indicatorNumber. If \a indicatorNumber is -1 then the //! indicator number is automatically allocated. The indicator number is //! returned or -1 if too many types of indicator have been defined. //! //! Indicators are used to display additional information over the top of //! styling. They can be used to show, for example, syntax errors, //! deprecated names and bad indentation by drawing lines under text or //! boxes around text. //! //! There may be up to 32 types of indicator defined at a time. The first //! 8 are normally used by lexers. By default indicator number 0 is a //! dark green SquiggleIndicator, 1 is a blue TTIndicator, and 2 is a red //! PlainIndicator. int indicatorDefine(IndicatorStyle style, int indicatorNumber = -1); //! Returns true if the indicator \a indicatorNumber is drawn under the //! text (i.e. in the background). The default is false. //! //! \sa setIndicatorDrawUnder() bool indicatorDrawUnder(int indicatorNumber) const; //! Returns true if a call tip is currently active. bool isCallTipActive() const; //! Returns true if an auto-completion or user defined list is currently //! active. bool isListActive() const; //! Returns true if the text has been modified. //! //! \sa setModified(), modificationChanged() bool isModified() const; //! Returns true if the text edit is read-only. //! //! \sa setReadOnly() bool isReadOnly() const; //! Returns true if there is something that can be redone. //! //! \sa redo() bool isRedoAvailable() const; //! Returns true if there is something that can be undone. //! //! \sa undo() bool isUndoAvailable() const; //! Returns true if text is interpreted as being UTF8 encoded. The default //! is to interpret the text as Latin1 encoded. //! //! \sa setUtf8() bool isUtf8() const; //! Returns true if character \a ch is a valid word character. //! //! \sa wordCharacters() bool isWordCharacter(char ch) const; //! Returns the line which is at \a point pixel coordinates or -1 if there //! is no line at that point. int lineAt(const QPoint &point) const; //! QScintilla uses the combination of a line number and a character index //! from the start of that line to specify the position of a character //! within the text. The underlying Scintilla instead uses a byte index //! from the start of the text. This will convert the \a position byte //! index to the \a *line line number and \a *index character index. //! //! \sa positionFromLineIndex() void lineIndexFromPosition(int position, int *line, int *index) const; //! Returns the length of line \a line int bytes or -1 if there is no such //! line. In order to get the length in characters use text(line).length(). int lineLength(int line) const; //! Returns the number of lines of text. int lines() const; //! Returns the length of the text edit's text in bytes. In order to get //! the length in characters use text().length(). int length() const; //! Returns the current language lexer used to style text. If it is 0 then //! syntax styling is disabled. //! //! \sa setLexer() QsciLexer *lexer() const; //! Returns the background color of margin \a margin. //! //! \sa setMarginBackgroundColor() QColor marginBackgroundColor(int margin) const; //! Returns true if line numbers are enabled for margin \a margin. //! //! \sa setMarginLineNumbers(), marginType(), SCI_GETMARGINTYPEN bool marginLineNumbers(int margin) const; //! Returns the marker mask of margin \a margin. //! //! \sa setMarginMask(), QsciMarker, SCI_GETMARGINMASKN int marginMarkerMask(int margin) const; //! Returns the margin options. The default is MoNone. //! //! \sa setMarginOptions(), MoNone, MoSublineSelect. int marginOptions() const; //! Returns true if margin \a margin is sensitive to mouse clicks. //! //! \sa setMarginSensitivity(), marginClicked(), SCI_GETMARGINTYPEN bool marginSensitivity(int margin) const; //! Returns the type of margin \a margin. //! //! \sa setMarginType(), SCI_GETMARGINTYPEN MarginType marginType(int margin) const; //! Returns the width in pixels of margin \a margin. //! //! \sa setMarginWidth(), SCI_GETMARGINWIDTHN int marginWidth(int margin) const; //! Returns the number of margins. //! //! \sa setMargins() int margins() const; //! Define a type of marker using the symbol \a sym with the marker number //! \a markerNumber. If \a markerNumber is -1 then the marker number is //! automatically allocated. The marker number is returned or -1 if too //! many types of marker have been defined. //! //! Markers are small geometric symbols and characters used, for example, //! to indicate the current line or, in debuggers, to indicate breakpoints. //! If a margin has a width of 0 then its markers are not drawn, but their //! background colours affect the background colour of the corresponding //! line of text. //! //! There may be up to 32 types of marker defined at a time and each line //! of text has a set of marker instances associated with it. Markers are //! drawn according to their numerical identifier. Markers try to move //! with their text by tracking where the start of their line moves to. //! For example, when a line is deleted its markers are added to previous //! line's markers. //! //! Each marker type is identified by a marker number. Each instance of a //! marker is identified by a marker handle. int markerDefine(MarkerSymbol sym, int markerNumber = -1); //! Define a marker using the character \a ch with the marker number //! \a markerNumber. If \a markerNumber is -1 then the marker number is //! automatically allocated. The marker number is returned or -1 if too //! many markers have been defined. int markerDefine(char ch, int markerNumber = -1); //! Define a marker using a copy of the pixmap \a pm with the marker number //! \a markerNumber. If \a markerNumber is -1 then the marker number is //! automatically allocated. The marker number is returned or -1 if too //! many markers have been defined. int markerDefine(const QPixmap &pm, int markerNumber = -1); //! Define a marker using a copy of the image \a im with the marker number //! \a markerNumber. If \a markerNumber is -1 then the marker number is //! automatically allocated. The marker number is returned or -1 if too //! many markers have been defined. int markerDefine(const QImage &im, int markerNumber = -1); //! Add an instance of marker number \a markerNumber to line number //! \a linenr. A handle for the marker is returned which can be used to //! track the marker's position, or -1 if the \a markerNumber was invalid. //! //! \sa markerDelete(), markerDeleteAll(), markerDeleteHandle() int markerAdd(int linenr, int markerNumber); //! Returns the 32 bit mask of marker numbers at line number \a linenr. //! //! \sa markerAdd() unsigned markersAtLine(int linenr) const; //! Delete all markers with the marker number \a markerNumber in the line //! \a linenr. If \a markerNumber is -1 then delete all markers from line //! \a linenr. //! //! \sa markerAdd(), markerDeleteAll(), markerDeleteHandle() void markerDelete(int linenr, int markerNumber = -1); //! Delete the all markers with the marker number \a markerNumber. If //! \a markerNumber is -1 then delete all markers. //! //! \sa markerAdd(), markerDelete(), markerDeleteHandle() void markerDeleteAll(int markerNumber = -1); //! Delete the the marker instance with the marker handle \a mhandle. //! //! \sa markerAdd(), markerDelete(), markerDeleteAll() void markerDeleteHandle(int mhandle); //! Return the line number that contains the marker instance with the //! marker handle \a mhandle. int markerLine(int mhandle) const; //! Return the number of the next line to contain at least one marker from //! a 32 bit mask of markers. \a linenr is the line number to start the //! search from. \a mask is the mask of markers to search for. //! //! \sa markerFindPrevious() int markerFindNext(int linenr, unsigned mask) const; //! Return the number of the previous line to contain at least one marker //! from a 32 bit mask of markers. \a linenr is the line number to start //! the search from. \a mask is the mask of markers to search for. //! //! \sa markerFindNext() int markerFindPrevious(int linenr, unsigned mask) const; //! Returns true if text entered by the user will overwrite existing text. //! //! \sa setOverwriteMode() bool overwriteMode() const; //! Returns the widget's paper (ie. background) colour. //! //! \sa setPaper() QColor paper() const; //! QScintilla uses the combination of a line number and a character index //! from the start of that line to specify the position of a character //! within the text. The underlying Scintilla instead uses a byte index //! from the start of the text. This will return the byte index //! corresponding to the \a line line number and \a index character index. //! //! \sa lineIndexFromPosition() int positionFromLineIndex(int line, int index) const; //! Reads the current document from the \a io device and returns true if //! there was no error. //! //! \sa write() bool read(QIODevice *io); //! Recolours the document between the \a start and \a end positions. //! \a start defaults to the start of the document and \a end defaults to //! the end of the document. virtual void recolor(int start = 0, int end = -1); //! Register an image \a pm with ID \a id. Registered images can be //! displayed in auto-completion lists. //! //! \sa clearRegisteredImages(), QsciLexer::apiLoad() void registerImage(int id, const QPixmap &pm); //! Register an image \a im with ID \a id. Registered images can be //! displayed in auto-completion lists. //! //! \sa clearRegisteredImages(), QsciLexer::apiLoad() void registerImage(int id, const QImage &im); //! Replace the current selection, set by a previous call to findFirst(), //! findFirstInSelection() or findNext(), with \a replaceStr. //! //! \sa cancelFind(), findFirst(), findFirstInSelection(), findNext() virtual void replace(const QString &replaceStr); //! Reset the fold margin colours to their defaults. //! //! \sa setFoldMarginColors() void resetFoldMarginColors(); //! Resets the background colour of an active hotspot area to the default. //! //! \sa setHotspotBackgroundColor(), resetHotspotForegroundColor() void resetHotspotBackgroundColor(); //! Resets the foreground colour of an active hotspot area to the default. //! //! \sa setHotspotForegroundColor(), resetHotspotBackgroundColor() void resetHotspotForegroundColor(); //! Gets the assumed document width in pixels. //! //! \sa setScrollWidth(), setScrollWidthTracking() int scrollWidth() const; //! Returns true if scroll width tracking is enabled. //! //! \sa scrollWidth(), setScrollWidthTracking() bool scrollWidthTracking() const; //! The fold margin may be drawn as a one pixel sized checkerboard pattern //! of two colours, \a fore and \a back. //! //! \sa resetFoldMarginColors() void setFoldMarginColors(const QColor &fore, const QColor &back); //! Set the display style for annotations. The default is //! AnnotationStandard. //! //! \sa annotationDisplay() void setAnnotationDisplay(AnnotationDisplay display); //! Enable the use of fill-up characters, either those explicitly set or //! those set by a lexer. By default, fill-up characters are disabled. //! //! \sa autoCompletionFillupsEnabled(), setAutoCompletionFillups() void setAutoCompletionFillupsEnabled(bool enabled); //! A fill-up character is one that, when entered while an auto-completion //! list is being displayed, causes the currently selected item from the //! list to be added to the text followed by the fill-up character. //! \a fillups is the set of fill-up characters. If a language lexer has //! been set then this is ignored and the lexer defines the fill-up //! characters. The default is that no fill-up characters are set. //! //! \sa autoCompletionFillupsEnabled(), setAutoCompletionFillupsEnabled() void setAutoCompletionFillups(const char *fillups); //! A word separator is a sequence of characters that, when entered, causes //! the auto-completion list to be displayed. If a language lexer has been //! set then this is ignored and the lexer defines the word separators. //! The default is that no word separators are set. //! //! \sa setAutoCompletionThreshold() void setAutoCompletionWordSeparators(const QStringList &separators); //! Set the background colour of call tips to \a col. The default is //! white. void setCallTipsBackgroundColor(const QColor &col); //! Set the foreground colour of call tips to \a col. The default is //! mid-gray. void setCallTipsForegroundColor(const QColor &col); //! Set the highlighted colour of call tip text to \a col. The default is //! dark blue. void setCallTipsHighlightColor(const QColor &col); //! Set the current call tip position. The default is CallTipsBelowText. //! //! \sa callTipsPosition() void setCallTipsPosition(CallTipsPosition position); //! Set the current call tip style. The default is CallTipsNoContext. //! //! \sa callTipsStyle() void setCallTipsStyle(CallTipsStyle style); //! Set the maximum number of call tips that are displayed to \a nr. If //! the maximum number is 0 then all applicable call tips are displayed. //! If the maximum number is -1 then one call tip will be displayed with up //! and down arrows that allow the use to scroll through the full list. //! The default is -1. //! //! \sa callTipsVisible() void setCallTipsVisible(int nr); //! Sets each line in the \a folds list of line numbers to be a contracted //! fold. This is typically used to restore the fold state of a document. //! //! \sa contractedFolds() void setContractedFolds(const QList &folds); //! Attach the document \a document, replacing the currently attached //! document. //! //! \sa document() void setDocument(const QsciDocument &document); //! Add \a colnr to the columns which are displayed with a vertical line. //! The edge mode must be set to EdgeMultipleLines. //! //! \sa clearEdgeColumns() void addEdgeColumn(int colnr, const QColor &col); //! Remove any columns added by previous calls to addEdgeColumn(). //! //! \sa addEdgeColumn() void clearEdgeColumns(); //! Set the color of the marker used to show that a line has exceeded the //! length set by setEdgeColumn(). //! //! \sa edgeColor(), \sa setEdgeColumn void setEdgeColor(const QColor &col); //! Set the number of the column after which lines are considered to be //! long. //! //! \sa edgeColumn() void setEdgeColumn(int colnr); //! Set the edge mode which determines how long lines are marked. //! //! \sa edgeMode() void setEdgeMode(EdgeMode mode); //! Set the number of the first visible line to \a linenr. //! //! \sa firstVisibleLine() void setFirstVisibleLine(int linenr); //! Enables or disables, according to \a under, if the indicator //! \a indicatorNumber is drawn under or over the text (i.e. in the //! background or foreground). If \a indicatorNumber is -1 then the state //! of all indicators is set. //! //! \sa indicatorDrawUnder() void setIndicatorDrawUnder(bool under, int indicatorNumber = -1); //! Set the foreground colour of indicator \a indicatorNumber to \a col. //! If \a indicatorNumber is -1 then the colour of all indicators is set. void setIndicatorForegroundColor(const QColor &col, int indicatorNumber = -1); //! Set the foreground colour of indicator \a indicatorNumber to \a col //! when the mouse is over it or the caret moved into it. If //! \a indicatorNumber is -1 then the colour of all indicators is set. void setIndicatorHoverForegroundColor(const QColor &col, int indicatorNumber = -1); //! Set the style of indicator \a indicatorNumber to \a style when the //! mouse is over it or the caret moved into it. If \a indicatorNumber is //! -1 then the style of all indicators is set. void setIndicatorHoverStyle(IndicatorStyle style, int indicatorNumber = -1); //! Set the outline colour of indicator \a indicatorNumber to \a col. //! If \a indicatorNumber is -1 then the colour of all indicators is set. //! At the moment only the alpha value of the colour has any affect. void setIndicatorOutlineColor(const QColor &col, int indicatorNumber = -1); //! Sets the background color of margin \a margin to \a col. //! //! \sa marginBackgroundColor() void setMarginBackgroundColor(int margin, const QColor &col); //! Set the margin options to \a options. //! //! \sa marginOptions(), MoNone, MoSublineSelect. void setMarginOptions(int options); //! Set the margin text of line \a line with the text \a text using the //! style number \a style. void setMarginText(int line, const QString &text, int style); //! Set the margin text of line \a line with the text \a text using the //! style \a style. void setMarginText(int line, const QString &text, const QsciStyle &style); //! Set the margin text of line \a line with the styled text \a text. void setMarginText(int line, const QsciStyledText &text); //! Set the margin text of line \a line with the list of styled text \a //! text. void setMarginText(int line, const QList &text); //! Set the type of margin \a margin to type \a type. //! //! \sa marginType(), SCI_SETMARGINTYPEN void setMarginType(int margin, MarginType type); //! The margin text on line \a line is removed. If \a line is negative //! then all margin text is removed. void clearMarginText(int line = -1); //! Set the number of margins to \a margins. //! //! \sa margins() void setMargins(int margins); //! Set the background colour, including the alpha component, of marker //! \a markerNumber to \a col. If \a markerNumber is -1 then the colour of //! all markers is set. The default is white. //! //! \sa setMarkerForegroundColor() void setMarkerBackgroundColor(const QColor &col, int markerNumber = -1); //! Set the foreground colour of marker \a markerNumber to \a col. If //! \a markerNumber is -1 then the colour of all markers is set. The //! default is black. //! //! \sa setMarkerBackgroundColor() void setMarkerForegroundColor(const QColor &col, int markerNumber = -1); //! Set the background colour used to display matched braces to \a col. It //! is ignored if an indicator is being used. The default is white. //! //! \sa setMatchedBraceForegroundColor(), setMatchedBraceIndicator() void setMatchedBraceBackgroundColor(const QColor &col); //! Set the foreground colour used to display matched braces to \a col. It //! is ignored if an indicator is being used. The default is red. //! //! \sa setMatchedBraceBackgroundColor(), setMatchedBraceIndicator() void setMatchedBraceForegroundColor(const QColor &col); //! Set the indicator used to display matched braces to \a indicatorNumber. //! The default is not to use an indicator. //! //! \sa resetMatchedBraceIndicator(), setMatchedBraceBackgroundColor() void setMatchedBraceIndicator(int indicatorNumber); //! Stop using an indicator to display matched braces. //! //! \sa setMatchedBraceIndicator() void resetMatchedBraceIndicator(); //! For performance, QScintilla does not measure the display width of the //! document to determine the properties of the horizontal scroll bar. //! Instead, an assumed width is used. This sets the document width in //! pixels assumed by QScintilla to \a pixelWidth. The default value is //! 2000. //! //! \sa scrollWidth(), setScrollWidthTracking() void setScrollWidth(int pixelWidth); //! If scroll width tracking is enabled then the scroll width is adjusted //! to ensure that all of the lines currently displayed can be completely //! scrolled. This mode never adjusts the scroll width to be narrower. //! This sets the scroll width tracking to \a enabled. //! //! \sa setScrollWidth(), scrollWidthTracking() void setScrollWidthTracking(bool enabled); //! Sets the mode used to draw tab characters when whitespace is visible to //! \a mode. The default is to use an arrow. //! //! \sa tabDrawMode() void setTabDrawMode(TabDrawMode mode); //! Set the background colour used to display unmatched braces to \a col. //! It is ignored if an indicator is being used. The default is white. //! //! \sa setUnmatchedBraceForegroundColor(), setUnmatchedBraceIndicator() void setUnmatchedBraceBackgroundColor(const QColor &col); //! Set the foreground colour used to display unmatched braces to \a col. //! It is ignored if an indicator is being used. The default is blue. //! //! \sa setUnmatchedBraceBackgroundColor(), setUnmatchedBraceIndicator() void setUnmatchedBraceForegroundColor(const QColor &col); //! Set the indicator used to display unmatched braces to //! \a indicatorNumber. The default is not to use an indicator. //! //! \sa resetUnmatchedBraceIndicator(), setUnmatchedBraceBackgroundColor() void setUnmatchedBraceIndicator(int indicatorNumber); //! Stop using an indicator to display unmatched braces. //! //! \sa setUnmatchedBraceIndicator() void resetUnmatchedBraceIndicator(); //! Set the visual flags displayed when a line is wrapped. \a endFlag //! determines if and where the flag at the end of a line is displayed. //! \a startFlag determines if and where the flag at the start of a line is //! displayed. \a indent is the number of characters a wrapped line is //! indented by. By default no visual flags are displayed. void setWrapVisualFlags(WrapVisualFlag endFlag, WrapVisualFlag startFlag = WrapFlagNone, int indent = 0); //! Returns the selected text or an empty string if there is no currently //! selected text. //! //! \sa hasSelectedText() QString selectedText() const; //! Returns whether or not the selection is drawn up to the right hand //! border. //! //! \sa setSelectionToEol() bool selectionToEol() const; //! Sets the background colour of an active hotspot area to \a col. //! //! \sa resetHotspotBackgroundColor(), setHotspotForegroundColor() void setHotspotBackgroundColor(const QColor &col); //! Sets the foreground colour of an active hotspot area to \a col. //! //! \sa resetHotspotForegroundColor(), setHotspotBackgroundColor() void setHotspotForegroundColor(const QColor &col); //! Enables or disables, according to \a enable, the underlining of an //! active hotspot area. The default is false. void setHotspotUnderline(bool enable); //! Enables or disables, according to \a enable, the wrapping of a hotspot //! area to following lines. The default is true. void setHotspotWrap(bool enable); //! Sets whether or not the selection is drawn up to the right hand border. //! \a filled is set if the selection is drawn to the border. //! //! \sa selectionToEol() void setSelectionToEol(bool filled); //! Sets the extra space added to the height of a line above the baseline //! of the text to \a extra. //! //! \sa extraAscent(), setExtraDescent() void setExtraAscent(int extra); //! Sets the extra space added to the height of a line below the baseline //! of the text to \a extra. //! //! \sa extraDescent(), setExtraAscent() void setExtraDescent(int extra); //! Text entered by the user will overwrite existing text if \a overwrite //! is true. //! //! \sa overwriteMode() void setOverwriteMode(bool overwrite); //! Sets the background colour of visible whitespace to \a col. If \a col //! is an invalid color (the default) then the color specified by the //! current lexer is used. void setWhitespaceBackgroundColor(const QColor &col); //! Sets the foreground colour of visible whitespace to \a col. If \a col //! is an invalid color (the default) then the color specified by the //! current lexer is used. void setWhitespaceForegroundColor(const QColor &col); //! Sets the size of the dots used to represent visible whitespace. //! //! \sa whitespaceSize() void setWhitespaceSize(int size); //! Sets the line wrap indentation mode to \a mode. The default is //! WrapIndentFixed. //! //! \sa wrapIndentMode() void setWrapIndentMode(WrapIndentMode mode); //! Displays a user defined list which can be interacted with like an //! auto-completion list. \a id is an identifier for the list which is //! passed as an argument to the userListActivated() signal and must be at //! least 1. \a list is the text with which the list is populated. //! //! \sa cancelList(), isListActive(), userListActivated() void showUserList(int id, const QStringList &list); //! The standard command set is returned. QsciCommandSet *standardCommands() const {return stdCmds;} //! Returns the mode used to draw tab characters when whitespace is //! visible. //! //! \sa setTabDrawMode() TabDrawMode tabDrawMode() const; //! Returns true if the tab key indents a line instead of inserting a tab //! character. The default is true. //! //! \sa setTabIndents(), backspaceUnindents(), setBackspaceUnindents() bool tabIndents() const; //! Returns the tab width in characters. The default is 8. //! //! \sa setTabWidth() int tabWidth() const; //! Returns the text of the current document. //! //! \sa setText() QString text() const; //! \overload //! //! Returns the text of line \a line. //! //! \sa setText() QString text(int line) const; //! \overload //! //! Returns the text between positions \a start and \a end. This is //! typically used by QsciLexerCustom::styleText(). //! //! \sa bytes(), setText() QString text(int start, int end) const; //! Returns the height in pixels of the text in line number \a linenr. int textHeight(int linenr) const; //! Returns the size of the dots used to represent visible whitespace. //! //! \sa setWhitespaceSize() int whitespaceSize() const; //! Returns the visibility of whitespace. //! //! \sa setWhitespaceVisibility() WhitespaceVisibility whitespaceVisibility() const; //! Returns the word at the \a line line number and \a index character //! index. QString wordAtLineIndex(int line, int index) const; //! Returns the word at the \a point pixel coordinates. QString wordAtPoint(const QPoint &point) const; //! Returns the set of valid word character as defined by the current //! language lexer. If there is no current lexer then the set contains an //! an underscore, numbers and all upper and lower case alphabetic //! characters. //! //! \sa isWordCharacter() const char *wordCharacters() const; //! Returns the line wrap mode. //! //! \sa setWrapMode() WrapMode wrapMode() const; //! Returns the line wrap indentation mode. //! //! \sa setWrapIndentMode() WrapIndentMode wrapIndentMode() const; //! Writes the current document to the \a io device and returns true if //! there was no error. //! //! \sa read() bool write(QIODevice *io) const; public slots: //! Appends the text \a text to the end of the text edit. Note that the //! undo/redo history is cleared by this function. virtual void append(const QString &text); //! Display an auto-completion list based on any installed APIs, the //! current contents of the document and the characters immediately to the //! left of the cursor. //! //! \sa autoCompleteFromAPIs(), autoCompleteFromDocument() virtual void autoCompleteFromAll(); //! Display an auto-completion list based on any installed APIs and the //! characters immediately to the left of the cursor. //! //! \sa autoCompleteFromAll(), autoCompleteFromDocument(), //! setAutoCompletionAPIs() virtual void autoCompleteFromAPIs(); //! Display an auto-completion list based on the current contents of the //! document and the characters immediately to the left of the cursor. //! //! \sa autoCompleteFromAll(), autoCompleteFromAPIs() virtual void autoCompleteFromDocument(); //! Display a call tip based on the the characters immediately to the left //! of the cursor. virtual void callTip(); //! Deletes all the text in the text edit. virtual void clear(); //! Copies any selected text to the clipboard. //! //! \sa copyAvailable(), cut(), paste() virtual void copy(); //! Copies any selected text to the clipboard and then deletes the text. //! //! \sa copy(), paste() virtual void cut(); //! Ensures that the cursor is visible. virtual void ensureCursorVisible(); //! Ensures that the line number \a line is visible. virtual void ensureLineVisible(int line); //! If any lines are currently folded then they are all unfolded. //! Otherwise all lines are folded. This has the same effect as clicking //! in the fold margin with the shift and control keys pressed. If //! \a children is not set (the default) then only the top level fold //! points are affected, otherwise the state of all fold points are //! changed. virtual void foldAll(bool children = false); //! If the line \a line is folded then it is unfolded. Otherwise it is //! folded. This has the same effect as clicking in the fold margin. virtual void foldLine(int line); //! Increases the indentation of line \a line by an indentation width. //! //! \sa unindent() virtual void indent(int line); //! Insert the text \a text at the current position. virtual void insert(const QString &text); //! Insert the text \a text in the line \a line at the position //! \a index. virtual void insertAt(const QString &text, int line, int index); //! If the cursor is either side of a brace character then move it to the //! position of the corresponding brace. virtual void moveToMatchingBrace(); //! Pastes any text from the clipboard into the text edit at the current //! cursor position. //! //! \sa copy(), cut() virtual void paste(); //! Redo the last change or sequence of changes. //! //! \sa isRedoAvailable() virtual void redo(); //! Removes any selected text. //! //! \sa replaceSelectedText() virtual void removeSelectedText(); //! Replaces any selected text with \a text. //! //! \sa removeSelectedText() virtual void replaceSelectedText(const QString &text); //! Resets the background colour of selected text to the default. //! //! \sa setSelectionBackgroundColor(), resetSelectionForegroundColor() virtual void resetSelectionBackgroundColor(); //! Resets the foreground colour of selected text to the default. //! //! \sa setSelectionForegroundColor(), resetSelectionBackgroundColor() virtual void resetSelectionForegroundColor(); //! If \a select is true (the default) then all the text is selected. If //! \a select is false then any currently selected text is deselected. virtual void selectAll(bool select = true); //! If the cursor is either side of a brace character then move it to the //! position of the corresponding brace and select the text between the //! braces. virtual void selectToMatchingBrace(); //! If \a cs is true then auto-completion lists are case sensitive. The //! default is true. Note that setting a lexer may change the case //! sensitivity. //! //! \sa autoCompletionCaseSensitivity() virtual void setAutoCompletionCaseSensitivity(bool cs); //! If \a replace is true then when an item from an auto-completion list is //! selected, the rest of the word to the right of the current cursor is //! removed. The default is false. //! //! \sa autoCompletionReplaceWord() virtual void setAutoCompletionReplaceWord(bool replace); //! If \a single is true then when there is only a single entry in an //! auto-completion list it is automatically used and the list is not //! displayed. This only has an effect when auto-completion is explicitly //! requested (using autoCompleteFromAPIs() and autoCompleteFromDocument()) //! and has no effect when auto-completion is triggered as the user types. //! The default is false. Note that this is deprecated and //! setAutoCompletionUseSingle() should be used instead. //! //! \sa autoCompletionShowSingle() virtual void setAutoCompletionShowSingle(bool single); //! Sets the source for the auto-completion list when it is being displayed //! automatically as the user types to \a source. The default is AcsNone, //! ie. it is disabled. //! //! \sa autoCompletionSource() virtual void setAutoCompletionSource(AutoCompletionSource source); //! Sets the threshold for the automatic display of the auto-completion //! list as the user types to \a thresh. The threshold is the number of //! characters that the user must type before the list is displayed. If //! the threshold is less than or equal to 0 then the list is disabled. //! The default is -1. //! //! \sa autoCompletionThreshold(), setAutoCompletionWordSeparators() virtual void setAutoCompletionThreshold(int thresh); //! Sets the behavior of the auto-completion list when it has a single //! entry. The default is AcusNever. //! //! \sa autoCompletionUseSingle() virtual void setAutoCompletionUseSingle(AutoCompletionUseSingle single); //! If \a autoindent is true then auto-indentation is enabled. The default //! is false. //! //! \sa autoIndent() virtual void setAutoIndent(bool autoindent); //! Sets the brace matching mode to \a bm. The default is NoBraceMatching. //! //! \sa braceMatching() virtual void setBraceMatching(BraceMatch bm); //! If \a deindent is true then the backspace key will unindent a line //! rather then delete a character. //! //! \sa backspaceUnindents(), tabIndents(), setTabIndents() virtual void setBackspaceUnindents(bool unindent); //! Sets the foreground colour of the caret to \a col. virtual void setCaretForegroundColor(const QColor &col); //! Sets the background colour, including the alpha component, of the line //! containing the caret to \a col. //! //! \sa setCaretLineVisible() virtual void setCaretLineBackgroundColor(const QColor &col); //! Sets the width of the frame of the line containing the caret to \a //! width. virtual void setCaretLineFrameWidth(int width); //! Enables or disables, according to \a enable, the background color of //! the line containing the caret. //! //! \sa setCaretLineBackgroundColor() virtual void setCaretLineVisible(bool enable); //! Sets the width of the caret to \a width pixels. A \a width of 0 makes //! the caret invisible. virtual void setCaretWidth(int width); //! The widget's text (ie. foreground) colour is set to \a c. This has no //! effect if a language lexer has been set. //! //! \sa color() virtual void setColor(const QColor &c); //! Sets the cursor to the line \a line at the position \a index. //! //! \sa getCursorPosition() virtual void setCursorPosition(int line, int index); //! Sets the end-of-line mode to \a mode. The default is the platform's //! natural mode. //! //! \sa eolMode() virtual void setEolMode(EolMode mode); //! If \a visible is true then end-of-lines are made visible. The default //! is that they are invisible. //! //! \sa eolVisibility() virtual void setEolVisibility(bool visible); //! Sets the folding style for margin \a margin to \a fold. The default //! style is NoFoldStyle (ie. folding is disabled) and the default margin //! is 2. //! //! \sa folding() virtual void setFolding(FoldStyle fold, int margin = 2); //! Sets the indentation of line \a line to \a indentation characters. //! //! \sa indentation() virtual void setIndentation(int line, int indentation); //! Enables or disables, according to \a enable, this display of //! indentation guides. //! //! \sa indentationGuides() virtual void setIndentationGuides(bool enable); //! Set the background colour of indentation guides to \a col. //! //! \sa setIndentationGuidesForegroundColor() virtual void setIndentationGuidesBackgroundColor(const QColor &col); //! Set the foreground colour of indentation guides to \a col. //! //! \sa setIndentationGuidesBackgroundColor() virtual void setIndentationGuidesForegroundColor(const QColor &col); //! If \a tabs is true then indentations are created using tabs and spaces, //! rather than just spaces. //! //! \sa indentationsUseTabs() virtual void setIndentationsUseTabs(bool tabs); //! Sets the indentation width to \a width characters. If \a width is 0 //! then the value returned by tabWidth() is used. //! //! \sa indentationWidth(), tabWidth() virtual void setIndentationWidth(int width); //! Sets the specific language lexer used to style text to \a lex. If //! \a lex is 0 then syntax styling is disabled. //! //! \sa lexer() virtual void setLexer(QsciLexer *lexer = 0); //! Set the background colour of all margins to \a col. The default is a //! gray. //! //! \sa setMarginsForegroundColor() virtual void setMarginsBackgroundColor(const QColor &col); //! Set the font used in all margins to \a f. virtual void setMarginsFont(const QFont &f); //! Set the foreground colour of all margins to \a col. The default is //! black. //! //! \sa setMarginsBackgroundColor() virtual void setMarginsForegroundColor(const QColor &col); //! Enables or disables, according to \a lnrs, the display of line numbers //! in margin \a margin. //! //! \sa marginLineNumbers(), setMarginType(), SCI_SETMARGINTYPEN virtual void setMarginLineNumbers(int margin, bool lnrs); //! Sets the marker mask of margin \a margin to \a mask. Only those //! markers whose bit is set in the mask are displayed in the margin. //! //! \sa marginMarkerMask(), QsciMarker, SCI_SETMARGINMASKN virtual void setMarginMarkerMask(int margin, int mask); //! Enables or disables, according to \a sens, the sensitivity of margin //! \a margin to mouse clicks. If the user clicks in a sensitive margin //! the marginClicked() signal is emitted. //! //! \sa marginSensitivity(), marginClicked(), SCI_SETMARGINSENSITIVEN virtual void setMarginSensitivity(int margin, bool sens); //! Sets the width of margin \a margin to \a width pixels. If the width of //! a margin is 0 then it is not displayed. //! //! \sa marginWidth(), SCI_SETMARGINWIDTHN virtual void setMarginWidth(int margin, int width); //! Sets the width of margin \a margin so that it is wide enough to display //! \a s in the current margin font. //! //! \sa marginWidth(), SCI_SETMARGINWIDTHN virtual void setMarginWidth(int margin, const QString &s); //! Sets the modified state of the text edit to \a m. Note that it is only //! possible to clear the modified state (where \a m is false). Attempts //! to set the modified state (where \a m is true) are ignored. //! //! \sa isModified(), modificationChanged() virtual void setModified(bool m); //! The widget's paper (ie. background) colour is set to \a c. This has no //! effect if a language lexer has been set. //! //! \sa paper() virtual void setPaper(const QColor &c); //! Sets the read-only state of the text edit to \a ro. //! //! \sa isReadOnly() virtual void setReadOnly(bool ro); //! Sets the selection which starts at position \a indexFrom in line //! \a lineFrom and ends at position \a indexTo in line \a lineTo. The //! cursor is moved to position \a indexTo in \a lineTo. //! //! \sa getSelection() virtual void setSelection(int lineFrom, int indexFrom, int lineTo, int indexTo); //! Sets the background colour, including the alpha component, of selected //! text to \a col. //! //! \sa resetSelectionBackgroundColor(), setSelectionForegroundColor() virtual void setSelectionBackgroundColor(const QColor &col); //! Sets the foreground colour of selected text to \a col. //! //! \sa resetSelectionForegroundColor(), setSelectionBackgroundColor() virtual void setSelectionForegroundColor(const QColor &col); //! If \a indent is true then the tab key will indent a line rather than //! insert a tab character. //! //! \sa tabIndents(), backspaceUnindents(), setBackspaceUnindents() virtual void setTabIndents(bool indent); //! Sets the tab width to \a width characters. //! //! \sa tabWidth() virtual void setTabWidth(int width); //! Replaces all of the current text with \a text. Note that the //! undo/redo history is cleared by this function. //! //! \sa text() virtual void setText(const QString &text); //! Sets the current text encoding. If \a cp is true then UTF8 is used, //! otherwise Latin1 is used. //! //! \sa isUtf8() virtual void setUtf8(bool cp); //! Sets the visibility of whitespace to mode \a mode. The default is that //! whitespace is invisible. //! //! \sa whitespaceVisibility() virtual void setWhitespaceVisibility(WhitespaceVisibility mode); //! Sets the line wrap mode to \a mode. The default is that lines are not //! wrapped. //! //! \sa wrapMode() virtual void setWrapMode(WrapMode mode); //! Undo the last change or sequence of changes. //! //! Scintilla has multiple level undo and redo. It will continue to record //! undoable actions until memory runs out. Sequences of typing or //! deleting are compressed into single actions to make it easier to undo //! and redo at a sensible level of detail. Sequences of actions can be //! combined into actions that are undone as a unit. These sequences occur //! between calls to beginUndoAction() and endUndoAction(). These //! sequences can be nested and only the top level sequences are undone as //! units. //! //! \sa beginUndoAction(), endUndoAction(), isUndoAvailable() virtual void undo(); //! Decreases the indentation of line \a line by an indentation width. //! //! \sa indent() virtual void unindent(int line); //! Zooms in on the text by by making the base font size \a range points //! larger and recalculating all font sizes. //! //! \sa zoomOut(), zoomTo() virtual void zoomIn(int range); //! \overload //! //! Zooms in on the text by by making the base font size one point larger //! and recalculating all font sizes. virtual void zoomIn(); //! Zooms out on the text by by making the base font size \a range points //! smaller and recalculating all font sizes. //! //! \sa zoomIn(), zoomTo() virtual void zoomOut(int range); //! \overload //! //! Zooms out on the text by by making the base font size one point larger //! and recalculating all font sizes. virtual void zoomOut(); //! Zooms the text by making the base font size \a size points and //! recalculating all font sizes. //! //! \sa zoomIn(), zoomOut() virtual void zoomTo(int size); signals: //! This signal is emitted whenever the cursor position changes. \a line //! contains the line number and \a index contains the character index //! within the line. void cursorPositionChanged(int line, int index); //! This signal is emitted whenever text is selected or de-selected. //! \a yes is true if text has been selected and false if text has been //! deselected. If \a yes is true then copy() can be used to copy the //! selection to the clipboard. If \a yes is false then copy() does //! nothing. //! //! \sa copy(), selectionChanged() void copyAvailable(bool yes); //! This signal is emitted whenever the user clicks on an indicator. \a //! line is the number of the line where the user clicked. \a index is the //! character index within the line. \a state is the state of the modifier //! keys (Qt::ShiftModifier, Qt::ControlModifier, Qt::AltModifer and //! Qt::MetaModifier) when the user clicked. //! //! \sa indicatorReleased() void indicatorClicked(int line, int index, Qt::KeyboardModifiers state); //! This signal is emitted whenever the user releases the mouse on an //! indicator. \a line is the number of the line where the user clicked. //! \a index is the character index within the line. \a state is the state //! of the modifier keys (Qt::ShiftModifier, Qt::ControlModifier, //! Qt::AltModifer and Qt::MetaModifier) when the user released the mouse. //! //! \sa indicatorClicked() void indicatorReleased(int line, int index, Qt::KeyboardModifiers state); //! This signal is emitted whenever the number of lines of text changes. void linesChanged(); //! This signal is emitted whenever the user clicks on a sensitive margin. //! \a margin is the margin. \a line is the number of the line where the //! user clicked. \a state is the state of the modifier keys //! (Qt::ShiftModifier, Qt::ControlModifier, Qt::AltModifer and //! Qt::MetaModifier) when the user clicked. //! //! \sa marginSensitivity(), setMarginSensitivity() void marginClicked(int margin, int line, Qt::KeyboardModifiers state); //! This signal is emitted whenever the user right-clicks on a sensitive //! margin. \a margin is the margin. \a line is the number of the line //! where the user clicked. \a state is the state of the modifier keys //! (Qt::ShiftModifier, Qt::ControlModifier, Qt::AltModifer and //! Qt::MetaModifier) when the user clicked. //! //! \sa marginSensitivity(), setMarginSensitivity() void marginRightClicked(int margin, int line, Qt::KeyboardModifiers state); //! This signal is emitted whenever the user attempts to modify read-only //! text. //! //! \sa isReadOnly(), setReadOnly() void modificationAttempted(); //! This signal is emitted whenever the modification state of the text //! changes. \a m is true if the text has been modified. //! //! \sa isModified(), setModified() void modificationChanged(bool m); //! This signal is emitted whenever the selection changes. //! //! \sa copyAvailable() void selectionChanged(); //! This signal is emitted whenever the text in the text edit changes. void textChanged(); //! This signal is emitted when an item in a user defined list is activated //! (selected). \a id is the list identifier. \a string is the text of //! the item. //! //! \sa showUserList() void userListActivated(int id, const QString &string); protected: //! \reimp virtual bool event(QEvent *e); //! \reimp virtual void changeEvent(QEvent *e); //! \reimp virtual void contextMenuEvent(QContextMenuEvent *e); //! \reimp virtual void wheelEvent(QWheelEvent *e); private slots: void handleCallTipClick(int dir); void handleCharAdded(int charadded); void handleIndicatorClick(int pos, int modifiers); void handleIndicatorRelease(int pos, int modifiers); void handleMarginClick(int pos, int margin, int modifiers); void handleMarginRightClick(int pos, int margin, int modifiers); void handleModified(int pos, int mtype, const char *text, int len, int added, int line, int foldNow, int foldPrev, int token, int annotationLinesAdded); void handlePropertyChange(const char *prop, const char *val); void handleSavePointReached(); void handleSavePointLeft(); void handleSelectionChanged(bool yes); void handleAutoCompletionSelection(); void handleUserListSelection(const char *text, int id); void handleStyleColorChange(const QColor &c, int style); void handleStyleEolFillChange(bool eolfill, int style); void handleStyleFontChange(const QFont &f, int style); void handleStylePaperChange(const QColor &c, int style); void handleUpdateUI(int updated); void delete_selection(); private: void detachLexer(); enum IndentState { isNone, isKeywordStart, isBlockStart, isBlockEnd }; void maintainIndentation(char ch, long pos); void autoIndentation(char ch, long pos); void autoIndentLine(long pos, int line, int indent); int blockIndent(int line); IndentState getIndentState(int line); bool rangeIsWhitespace(long spos, long epos); int findStyledWord(const char *text, int style, const char *words); void checkMarker(int &markerNumber); void checkIndicator(int &indicatorNumber); static void allocateId(int &id, unsigned &allocated, int min, int max); int currentIndent() const; int indentWidth() const; bool doFind(); int simpleFind(); void foldClick(int lineClick, int bstate); void foldChanged(int line, int levelNow, int levelPrev); void foldExpand(int &line, bool doExpand, bool force = false, int visLevels = 0, int level = -1); void setFoldMarker(int marknr, int mark = SC_MARK_EMPTY); void setLexerStyle(int style); void setStylesFont(const QFont &f, int style); void setEnabledColors(int style, QColor &fore, QColor &back); void braceMatch(); bool findMatchingBrace(long &brace, long &other, BraceMatch mode); long checkBrace(long pos, int brace_style, bool &colonMode); void gotoMatchingBrace(bool select); void startAutoCompletion(AutoCompletionSource acs, bool checkThresh, bool choose_single); int adjustedCallTipPosition(int ctshift) const; bool getSeparator(int &pos) const; QString getWord(int &pos) const; char getCharacter(int &pos) const; bool isStartChar(char ch) const; bool ensureRW(); void insertAtPos(const QString &text, int pos); static int mapModifiers(int modifiers); QString wordAtPosition(int position) const; ScintillaBytes styleText(const QList &styled_text, char **styles, int style_offset = 0); struct FindState { enum Status { Finding, FindingInSelection, Idle }; FindState() : status(Idle) {} Status status; QString expr; bool wrap; bool forward; int flags; long startpos, startpos_orig; long endpos, endpos_orig; bool show; }; FindState findState; unsigned allocatedMarkers; unsigned allocatedIndicators; int oldPos; int ctPos; bool selText; FoldStyle fold; int foldmargin; bool autoInd; BraceMatch braceMode; AutoCompletionSource acSource; int acThresh; QStringList wseps; const char *wchars; CallTipsPosition call_tips_position; CallTipsStyle call_tips_style; int maxCallTips; QStringList ct_entries; int ct_cursor; QList ct_shifts; AutoCompletionUseSingle use_single; QPointer lex; QsciCommandSet *stdCmds; QsciDocument doc; QColor nl_text_colour; QColor nl_paper_colour; QByteArray explicit_fillups; bool fillups_enabled; // The following allow QsciListBoxQt to distinguish between an // auto-completion list and a user list, and to return the full selection // of an auto-completion list. friend class QsciListBoxQt; QString acSelection; bool isAutoCompletionList() const; void set_shortcut(QAction *action, QsciCommand::Command cmd_id) const; QsciScintilla(const QsciScintilla &); QsciScintilla &operator=(const QsciScintilla &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qsciscintillabase.h000066400000000000000000002576621463772530400306210ustar00rootroot00000000000000// This class defines the "official" low-level API. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCISCINTILLABASE_H #define QSCISCINTILLABASE_H #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QColor; class QImage; class QMimeData; class QPainter; class QPixmap; class QUrl; QT_END_NAMESPACE class QsciScintillaQt; //! \brief The QsciScintillaBase class implements the Scintilla editor widget //! and its low-level API. //! //! Scintilla (http://www.scintilla.org) is a powerful C++ editor class that //! supports many features including syntax styling, error indicators, code //! completion and call tips. It is particularly useful as a programmer's //! editor. //! //! QsciScintillaBase is a port to Qt of Scintilla. It implements the standard //! Scintilla API which consists of a number of messages each taking up to //! two arguments. //! //! See QsciScintilla for the implementation of a higher level API that is more //! consistent with the rest of the Qt toolkit. class QSCINTILLA_EXPORT QsciScintillaBase : public QAbstractScrollArea { Q_OBJECT public: //! The low-level Scintilla API is implemented as a set of messages each of //! which takes up to two parameters (\a wParam and \a lParam) and //! optionally return a value. This enum defines all the possible messages. enum { //! SCI_START = 2000, //! SCI_OPTIONAL_START = 3000, //! SCI_LEXER_START = 4000, //! This message appends some text to the end of the document. //! \a wParam is the length of the text. //! \a lParam is the text to be appended. SCI_ADDTEXT = 2001, //! SCI_ADDSTYLEDTEXT = 2002, //! SCI_INSERTTEXT = 2003, //! SCI_CLEARALL = 2004, //! SCI_CLEARDOCUMENTSTYLE = 2005, //! SCI_GETLENGTH = 2006, //! SCI_GETCHARAT = 2007, //! This message returns the current position. //! //! \sa SCI_SETCURRENTPOS SCI_GETCURRENTPOS = 2008, //! This message returns the anchor. //! //! \sa SCI_SETANCHOR SCI_GETANCHOR = 2009, //! SCI_GETSTYLEAT = 2010, //! SCI_REDO = 2011, //! SCI_SETUNDOCOLLECTION = 2012, //! SCI_SELECTALL = 2013, //! This message marks the current state of the text as the the save //! point. This is usually done when the text is saved or loaded. //! //! \sa SCN_SAVEPOINTREACHED(), SCN_SAVEPOINTLEFT() SCI_SETSAVEPOINT = 2014, //! SCI_GETSTYLEDTEXT = 2015, //! SCI_CANREDO = 2016, //! This message returns the line that contains a particular instance //! of a marker. //! \a wParam is the handle of the marker. //! //! \sa SCI_MARKERADD SCI_MARKERLINEFROMHANDLE = 2017, //! This message removes a particular instance of a marker. //! \a wParam is the handle of the marker. //! //! \sa SCI_MARKERADD SCI_MARKERDELETEHANDLE = 2018, //! SCI_GETUNDOCOLLECTION = 2019, //! SCI_GETVIEWWS = 2020, //! SCI_SETVIEWWS = 2021, //! SCI_POSITIONFROMPOINT = 2022, //! SCI_POSITIONFROMPOINTCLOSE = 2023, //! SCI_GOTOLINE = 2024, //! This message clears the current selection and sets the current //! position. //! \a wParam is the new current position. //! //! \sa SCI_SETCURRENTPOS SCI_GOTOPOS = 2025, //! This message sets the anchor. //! \a wParam is the new anchor. //! //! \sa SCI_GETANCHOR SCI_SETANCHOR = 2026, //! SCI_GETCURLINE = 2027, //! This message returns the character position of the start of the //! text that needs to be syntax styled. //! //! \sa SCN_STYLENEEDED() SCI_GETENDSTYLED = 2028, //! SCI_CONVERTEOLS = 2029, //! SCI_GETEOLMODE = 2030, //! SCI_SETEOLMODE = 2031, //! SCI_STARTSTYLING = 2032, //! SCI_SETSTYLING = 2033, //! SCI_GETBUFFEREDDRAW = 2034, //! SCI_SETBUFFEREDDRAW = 2035, //! SCI_SETTABWIDTH = 2036, //! SCI_GETTABWIDTH = 2121, //! SCI_SETCODEPAGE = 2037, //! This message sets the symbol used to draw one of 32 markers. Some //! markers have pre-defined uses, see the SC_MARKNUM_* values. //! \a wParam is the number of the marker. //! \a lParam is the marker symbol and is one of the SC_MARK_* values. //! //! \sa SCI_MARKERADD, SCI_MARKERDEFINEPIXMAP, //! SCI_MARKERDEFINERGBAIMAGE SCI_MARKERDEFINE = 2040, //! This message sets the foreground colour used to draw a marker. A //! colour is represented as a 24 bit value. The 8 least significant //! bits correspond to red, the middle 8 bits correspond to green, and //! the 8 most significant bits correspond to blue. The default value //! is 0x000000. //! \a wParam is the number of the marker. //! \a lParam is the colour. //! //! \sa SCI_MARKERSETBACK SCI_MARKERSETFORE = 2041, //! This message sets the background colour used to draw a marker. A //! colour is represented as a 24 bit value. The 8 least significant //! bits correspond to red, the middle 8 bits correspond to green, and //! the 8 most significant bits correspond to blue. The default value //! is 0xffffff. //! \a wParam is the number of the marker. //! \a lParam is the colour. //! //! \sa SCI_MARKERSETFORE SCI_MARKERSETBACK = 2042, //! This message adds a marker to a line. A handle for the marker is //! returned which can be used to track the marker's position. //! \a wParam is the line number. //! \a lParam is the number of the marker. //! //! \sa SCI_MARKERDELETE, SCI_MARKERDELETEALL, //! SCI_MARKERDELETEHANDLE SCI_MARKERADD = 2043, //! This message deletes a marker from a line. //! \a wParam is the line number. //! \a lParam is the number of the marker. //! //! \sa SCI_MARKERADD, SCI_MARKERDELETEALL SCI_MARKERDELETE = 2044, //! This message deletes all occurences of a marker. //! \a wParam is the number of the marker. If \a wParam is -1 then all //! markers are removed. //! //! \sa SCI_MARKERADD, SCI_MARKERDELETE SCI_MARKERDELETEALL = 2045, //! This message returns the 32 bit mask of markers at a line. //! \a wParam is the line number. SCI_MARKERGET = 2046, //! This message looks for the next line to contain at least one marker //! contained in a 32 bit mask of markers and returns the line number. //! \a wParam is the line number to start the search from. //! \a lParam is the mask of markers to search for. //! //! \sa SCI_MARKERPREVIOUS SCI_MARKERNEXT = 2047, //! This message looks for the previous line to contain at least one //! marker contained in a 32 bit mask of markers and returns the line //! number. //! \a wParam is the line number to start the search from. //! \a lParam is the mask of markers to search for. //! //! \sa SCI_MARKERNEXT SCI_MARKERPREVIOUS = 2048, //! This message sets the symbol used to draw one of the 32 markers to //! a pixmap. Pixmaps use the SC_MARK_PIXMAP marker symbol. //! \a wParam is the number of the marker. //! \a lParam is a pointer to a QPixmap instance. Note that in other //! ports of Scintilla this is a pointer to either raw or textual XPM //! image data. //! //! \sa SCI_MARKERDEFINE, SCI_MARKERDEFINERGBAIMAGE SCI_MARKERDEFINEPIXMAP = 2049, //! This message sets what can be displayed in a margin. //! \a wParam is the number of the margin. //! \a lParam is the logical or of the SC_MARGIN_* values. //! //! \sa SCI_GETMARGINTYPEN SCI_SETMARGINTYPEN = 2240, //! This message returns what can be displayed in a margin. //! \a wParam is the number of the margin. //! //! \sa SCI_SETMARGINTYPEN SCI_GETMARGINTYPEN = 2241, //! This message sets the width of a margin in pixels. //! \a wParam is the number of the margin. //! \a lParam is the new margin width. //! //! \sa SCI_GETMARGINWIDTHN SCI_SETMARGINWIDTHN = 2242, //! This message returns the width of a margin in pixels. //! \a wParam is the number of the margin. //! //! \sa SCI_SETMARGINWIDTHN SCI_GETMARGINWIDTHN = 2243, //! This message sets the mask of a margin. The mask is a 32 value //! with one bit for each possible marker. If a bit is set then the //! corresponding marker is displayed. By default, all markers are //! displayed. //! \a wParam is the number of the margin. //! \a lParam is the new margin mask. //! //! \sa SCI_GETMARGINMASKN, SCI_MARKERDEFINE SCI_SETMARGINMASKN = 2244, //! This message returns the mask of a margin. //! \a wParam is the number of the margin. //! //! \sa SCI_SETMARGINMASKN SCI_GETMARGINMASKN = 2245, //! This message sets the sensitivity of a margin to mouse clicks. //! \a wParam is the number of the margin. //! \a lParam is non-zero to make the margin sensitive to mouse clicks. //! When the mouse is clicked the SCN_MARGINCLICK() signal is emitted. //! //! \sa SCI_GETMARGINSENSITIVEN, SCN_MARGINCLICK() SCI_SETMARGINSENSITIVEN = 2246, //! This message returns the sensitivity of a margin to mouse clicks. //! \a wParam is the number of the margin. //! //! \sa SCI_SETMARGINSENSITIVEN, SCN_MARGINCLICK() SCI_GETMARGINSENSITIVEN = 2247, //! This message sets the cursor shape displayed over a margin. //! \a wParam is the number of the margin. //! \a lParam is the cursor shape, normally either SC_CURSORARROW or //! SC_CURSORREVERSEARROW. Note that, currently, QScintilla implements //! both of these as Qt::ArrowCursor. //! //! \sa SCI_GETMARGINCURSORN SCI_SETMARGINCURSORN = 2248, //! This message returns the cursor shape displayed over a margin. //! \a wParam is the number of the margin. //! //! \sa SCI_SETMARGINCURSORN SCI_GETMARGINCURSORN = 2249, //! SCI_STYLECLEARALL = 2050, //! SCI_STYLESETFORE = 2051, //! SCI_STYLESETBACK = 2052, //! SCI_STYLESETBOLD = 2053, //! SCI_STYLESETITALIC = 2054, //! SCI_STYLESETSIZE = 2055, //! SCI_STYLESETFONT = 2056, //! SCI_STYLESETEOLFILLED = 2057, //! SCI_STYLERESETDEFAULT = 2058, //! SCI_STYLESETUNDERLINE = 2059, //! SCI_STYLESETCASE = 2060, //! SCI_STYLESETSIZEFRACTIONAL = 2061, //! SCI_STYLEGETSIZEFRACTIONAL = 2062, //! SCI_STYLESETWEIGHT = 2063, //! SCI_STYLEGETWEIGHT = 2064, //! SCI_STYLESETCHARACTERSET = 2066, //! SCI_SETSELFORE = 2067, //! SCI_SETSELBACK = 2068, //! SCI_SETCARETFORE = 2069, //! SCI_ASSIGNCMDKEY = 2070, //! SCI_CLEARCMDKEY = 2071, //! SCI_CLEARALLCMDKEYS = 2072, //! SCI_SETSTYLINGEX = 2073, //! SCI_STYLESETVISIBLE = 2074, //! SCI_GETCARETPERIOD = 2075, //! SCI_SETCARETPERIOD = 2076, //! SCI_SETWORDCHARS = 2077, //! SCI_BEGINUNDOACTION = 2078, //! SCI_ENDUNDOACTION = 2079, //! SCI_INDICSETSTYLE = 2080, //! SCI_INDICGETSTYLE = 2081, //! SCI_INDICSETFORE = 2082, //! SCI_INDICGETFORE = 2083, //! SCI_SETWHITESPACEFORE = 2084, //! SCI_SETWHITESPACEBACK = 2085, //! SCI_SETWHITESPACESIZE = 2086, //! SCI_GETWHITESPACESIZE = 2087, //! SCI_SETSTYLEBITS = 2090, //! SCI_GETSTYLEBITS = 2091, //! SCI_SETLINESTATE = 2092, //! SCI_GETLINESTATE = 2093, //! SCI_GETMAXLINESTATE = 2094, //! SCI_GETCARETLINEVISIBLE = 2095, //! SCI_SETCARETLINEVISIBLE = 2096, //! SCI_GETCARETLINEBACK = 2097, //! SCI_SETCARETLINEBACK = 2098, //! SCI_STYLESETCHANGEABLE = 2099, //! SCI_AUTOCSHOW = 2100, //! SCI_AUTOCCANCEL = 2101, //! SCI_AUTOCACTIVE = 2102, //! SCI_AUTOCPOSSTART = 2103, //! SCI_AUTOCCOMPLETE = 2104, //! SCI_AUTOCSTOPS = 2105, //! SCI_AUTOCSETSEPARATOR = 2106, //! SCI_AUTOCGETSEPARATOR = 2107, //! SCI_AUTOCSELECT = 2108, //! SCI_AUTOCSETCANCELATSTART = 2110, //! SCI_AUTOCGETCANCELATSTART = 2111, //! SCI_AUTOCSETFILLUPS = 2112, //! SCI_AUTOCSETCHOOSESINGLE = 2113, //! SCI_AUTOCGETCHOOSESINGLE = 2114, //! SCI_AUTOCSETIGNORECASE = 2115, //! SCI_AUTOCGETIGNORECASE = 2116, //! SCI_USERLISTSHOW = 2117, //! SCI_AUTOCSETAUTOHIDE = 2118, //! SCI_AUTOCGETAUTOHIDE = 2119, //! SCI_AUTOCSETDROPRESTOFWORD = 2270, //! SCI_AUTOCGETDROPRESTOFWORD = 2271, //! SCI_SETINDENT = 2122, //! SCI_GETINDENT = 2123, //! SCI_SETUSETABS = 2124, //! SCI_GETUSETABS = 2125, //! SCI_SETLINEINDENTATION = 2126, //! SCI_GETLINEINDENTATION = 2127, //! SCI_GETLINEINDENTPOSITION = 2128, //! SCI_GETCOLUMN = 2129, //! SCI_SETHSCROLLBAR = 2130, //! SCI_GETHSCROLLBAR = 2131, //! SCI_SETINDENTATIONGUIDES = 2132, //! SCI_GETINDENTATIONGUIDES = 2133, //! SCI_SETHIGHLIGHTGUIDE = 2134, //! SCI_GETHIGHLIGHTGUIDE = 2135, //! SCI_GETLINEENDPOSITION = 2136, //! SCI_GETCODEPAGE = 2137, //! SCI_GETCARETFORE = 2138, //! This message returns a non-zero value if the document is read-only. //! //! \sa SCI_SETREADONLY SCI_GETREADONLY = 2140, //! This message sets the current position. //! \a wParam is the new current position. //! //! \sa SCI_GETCURRENTPOS SCI_SETCURRENTPOS = 2141, //! SCI_SETSELECTIONSTART = 2142, //! SCI_GETSELECTIONSTART = 2143, //! SCI_SETSELECTIONEND = 2144, //! SCI_GETSELECTIONEND = 2145, //! SCI_SETPRINTMAGNIFICATION = 2146, //! SCI_GETPRINTMAGNIFICATION = 2147, //! SCI_SETPRINTCOLOURMODE = 2148, //! SCI_GETPRINTCOLOURMODE = 2149, //! SCI_FINDTEXT = 2150, //! SCI_FORMATRANGE = 2151, //! SCI_GETFIRSTVISIBLELINE = 2152, //! SCI_GETLINE = 2153, //! SCI_GETLINECOUNT = 2154, //! SCI_SETMARGINLEFT = 2155, //! SCI_GETMARGINLEFT = 2156, //! SCI_SETMARGINRIGHT = 2157, //! SCI_GETMARGINRIGHT = 2158, //! This message returns a non-zero value if the document has been //! modified. SCI_GETMODIFY = 2159, //! SCI_SETSEL = 2160, //! SCI_GETSELTEXT = 2161, //! SCI_GETTEXTRANGE = 2162, //! SCI_HIDESELECTION = 2163, //! SCI_POINTXFROMPOSITION = 2164, //! SCI_POINTYFROMPOSITION = 2165, //! SCI_LINEFROMPOSITION = 2166, //! SCI_POSITIONFROMLINE = 2167, //! SCI_LINESCROLL = 2168, //! SCI_SCROLLCARET = 2169, //! SCI_REPLACESEL = 2170, //! This message sets the read-only state of the document. //! \a wParam is the new read-only state of the document. //! //! \sa SCI_GETREADONLY SCI_SETREADONLY = 2171, //! SCI_NULL = 2172, //! SCI_CANPASTE = 2173, //! SCI_CANUNDO = 2174, //! This message empties the undo buffer. SCI_EMPTYUNDOBUFFER = 2175, //! SCI_UNDO = 2176, //! SCI_CUT = 2177, //! SCI_COPY = 2178, //! SCI_PASTE = 2179, //! SCI_CLEAR = 2180, //! This message sets the text of the document. //! \a wParam is unused. //! \a lParam is the new text of the document. //! //! \sa SCI_GETTEXT SCI_SETTEXT = 2181, //! This message gets the text of the document. //! \a wParam is size of the buffer that the text is copied to. //! \a lParam is the address of the buffer that the text is copied to. //! //! \sa SCI_SETTEXT SCI_GETTEXT = 2182, //! This message returns the length of the document. SCI_GETTEXTLENGTH = 2183, //! SCI_GETDIRECTFUNCTION = 2184, //! SCI_GETDIRECTPOINTER = 2185, //! SCI_SETOVERTYPE = 2186, //! SCI_GETOVERTYPE = 2187, //! SCI_SETCARETWIDTH = 2188, //! SCI_GETCARETWIDTH = 2189, //! SCI_SETTARGETSTART = 2190, //! SCI_GETTARGETSTART = 2191, //! SCI_SETTARGETEND = 2192, //! SCI_GETTARGETEND = 2193, //! SCI_REPLACETARGET = 2194, //! SCI_REPLACETARGETRE = 2195, //! SCI_SEARCHINTARGET = 2197, //! SCI_SETSEARCHFLAGS = 2198, //! SCI_GETSEARCHFLAGS = 2199, //! SCI_CALLTIPSHOW = 2200, //! SCI_CALLTIPCANCEL = 2201, //! SCI_CALLTIPACTIVE = 2202, //! SCI_CALLTIPPOSSTART = 2203, //! SCI_CALLTIPSETHLT = 2204, //! SCI_CALLTIPSETBACK = 2205, //! SCI_CALLTIPSETFORE = 2206, //! SCI_CALLTIPSETFOREHLT = 2207, //! SCI_AUTOCSETMAXWIDTH = 2208, //! SCI_AUTOCGETMAXWIDTH = 2209, //! This message is not implemented. SCI_AUTOCSETMAXHEIGHT = 2210, //! SCI_AUTOCGETMAXHEIGHT = 2211, //! SCI_CALLTIPUSESTYLE = 2212, //! SCI_CALLTIPSETPOSITION = 2213, //! SCI_CALLTIPSETPOSSTART = 2214, //! SCI_VISIBLEFROMDOCLINE = 2220, //! SCI_DOCLINEFROMVISIBLE = 2221, //! SCI_SETFOLDLEVEL = 2222, //! SCI_GETFOLDLEVEL = 2223, //! SCI_GETLASTCHILD = 2224, //! SCI_GETFOLDPARENT = 2225, //! SCI_SHOWLINES = 2226, //! SCI_HIDELINES = 2227, //! SCI_GETLINEVISIBLE = 2228, //! SCI_SETFOLDEXPANDED = 2229, //! SCI_GETFOLDEXPANDED = 2230, //! SCI_TOGGLEFOLD = 2231, //! SCI_ENSUREVISIBLE = 2232, //! SCI_SETFOLDFLAGS = 2233, //! SCI_ENSUREVISIBLEENFORCEPOLICY = 2234, //! SCI_WRAPCOUNT = 2235, //! SCI_GETALLLINESVISIBLE = 2236, //! SCI_FOLDLINE = 2237, //! SCI_FOLDCHILDREN = 2238, //! SCI_EXPANDCHILDREN = 2239, //! SCI_SETMARGINBACKN = 2250, //! SCI_GETMARGINBACKN = 2251, //! SCI_SETMARGINS = 2252, //! SCI_GETMARGINS = 2253, //! SCI_SETTABINDENTS = 2260, //! SCI_GETTABINDENTS = 2261, //! SCI_SETBACKSPACEUNINDENTS = 2262, //! SCI_GETBACKSPACEUNINDENTS = 2263, //! SCI_SETMOUSEDWELLTIME = 2264, //! SCI_GETMOUSEDWELLTIME = 2265, //! SCI_WORDSTARTPOSITION = 2266, //! SCI_WORDENDPOSITION = 2267, //! SCI_SETWRAPMODE = 2268, //! SCI_GETWRAPMODE = 2269, //! SCI_SETLAYOUTCACHE = 2272, //! SCI_GETLAYOUTCACHE = 2273, //! SCI_SETSCROLLWIDTH = 2274, //! SCI_GETSCROLLWIDTH = 2275, //! This message returns the width of some text when rendered in a //! particular style. //! \a wParam is the style number and is one of the STYLE_* values or //! one of the styles defined by a lexer. //! \a lParam is a pointer to the text. SCI_TEXTWIDTH = 2276, //! SCI_SETENDATLASTLINE = 2277, //! SCI_GETENDATLASTLINE = 2278, //! SCI_TEXTHEIGHT = 2279, //! SCI_SETVSCROLLBAR = 2280, //! SCI_GETVSCROLLBAR = 2281, //! SCI_APPENDTEXT = 2282, //! SCI_GETTWOPHASEDRAW = 2283, //! SCI_SETTWOPHASEDRAW = 2284, //! SCI_AUTOCGETTYPESEPARATOR = 2285, //! SCI_AUTOCSETTYPESEPARATOR = 2286, //! SCI_TARGETFROMSELECTION = 2287, //! SCI_LINESJOIN = 2288, //! SCI_LINESSPLIT = 2289, //! SCI_SETFOLDMARGINCOLOUR = 2290, //! SCI_SETFOLDMARGINHICOLOUR = 2291, //! SCI_MARKERSETBACKSELECTED = 2292, //! SCI_MARKERENABLEHIGHLIGHT = 2293, //! SCI_LINEDOWN = 2300, //! SCI_LINEDOWNEXTEND = 2301, //! SCI_LINEUP = 2302, //! SCI_LINEUPEXTEND = 2303, //! SCI_CHARLEFT = 2304, //! SCI_CHARLEFTEXTEND = 2305, //! SCI_CHARRIGHT = 2306, //! SCI_CHARRIGHTEXTEND = 2307, //! SCI_WORDLEFT = 2308, //! SCI_WORDLEFTEXTEND = 2309, //! SCI_WORDRIGHT = 2310, //! SCI_WORDRIGHTEXTEND = 2311, //! SCI_HOME = 2312, //! SCI_HOMEEXTEND = 2313, //! SCI_LINEEND = 2314, //! SCI_LINEENDEXTEND = 2315, //! SCI_DOCUMENTSTART = 2316, //! SCI_DOCUMENTSTARTEXTEND = 2317, //! SCI_DOCUMENTEND = 2318, //! SCI_DOCUMENTENDEXTEND = 2319, //! SCI_PAGEUP = 2320, //! SCI_PAGEUPEXTEND = 2321, //! SCI_PAGEDOWN = 2322, //! SCI_PAGEDOWNEXTEND = 2323, //! SCI_EDITTOGGLEOVERTYPE = 2324, //! SCI_CANCEL = 2325, //! SCI_DELETEBACK = 2326, //! SCI_TAB = 2327, //! SCI_BACKTAB = 2328, //! SCI_NEWLINE = 2329, //! SCI_FORMFEED = 2330, //! SCI_VCHOME = 2331, //! SCI_VCHOMEEXTEND = 2332, //! SCI_ZOOMIN = 2333, //! SCI_ZOOMOUT = 2334, //! SCI_DELWORDLEFT = 2335, //! SCI_DELWORDRIGHT = 2336, //! SCI_LINECUT = 2337, //! SCI_LINEDELETE = 2338, //! SCI_LINETRANSPOSE = 2339, //! SCI_LOWERCASE = 2340, //! SCI_UPPERCASE = 2341, //! SCI_LINESCROLLDOWN = 2342, //! SCI_LINESCROLLUP = 2343, //! SCI_DELETEBACKNOTLINE = 2344, //! SCI_HOMEDISPLAY = 2345, //! SCI_HOMEDISPLAYEXTEND = 2346, //! SCI_LINEENDDISPLAY = 2347, //! SCI_LINEENDDISPLAYEXTEND = 2348, //! SCI_MOVECARETINSIDEVIEW = 2401, //! SCI_LINELENGTH = 2350, //! SCI_BRACEHIGHLIGHT = 2351, //! SCI_BRACEBADLIGHT = 2352, //! SCI_BRACEMATCH = 2353, //! SCI_LINEREVERSE = 2354, //! SCI_GETVIEWEOL = 2355, //! SCI_SETVIEWEOL = 2356, //! SCI_GETDOCPOINTER = 2357, //! SCI_SETDOCPOINTER = 2358, //! SCI_SETMODEVENTMASK = 2359, //! SCI_GETEDGECOLUMN = 2360, //! SCI_SETEDGECOLUMN = 2361, //! SCI_GETEDGEMODE = 2362, //! SCI_SETEDGEMODE = 2363, //! SCI_GETEDGECOLOUR = 2364, //! SCI_SETEDGECOLOUR = 2365, //! SCI_SEARCHANCHOR = 2366, //! SCI_SEARCHNEXT = 2367, //! SCI_SEARCHPREV = 2368, //! SCI_LINESONSCREEN = 2370, //! SCI_USEPOPUP = 2371, //! SCI_SELECTIONISRECTANGLE = 2372, //! SCI_SETZOOM = 2373, //! SCI_GETZOOM = 2374, //! SCI_CREATEDOCUMENT = 2375, //! SCI_ADDREFDOCUMENT = 2376, //! SCI_RELEASEDOCUMENT = 2377, //! SCI_GETMODEVENTMASK = 2378, //! SCI_SETFOCUS = 2380, //! SCI_GETFOCUS = 2381, //! SCI_SETSTATUS = 2382, //! SCI_GETSTATUS = 2383, //! SCI_SETMOUSEDOWNCAPTURES = 2384, //! SCI_GETMOUSEDOWNCAPTURES = 2385, //! SCI_SETCURSOR = 2386, //! SCI_GETCURSOR = 2387, //! SCI_SETCONTROLCHARSYMBOL = 2388, //! SCI_GETCONTROLCHARSYMBOL = 2389, //! SCI_WORDPARTLEFT = 2390, //! SCI_WORDPARTLEFTEXTEND = 2391, //! SCI_WORDPARTRIGHT = 2392, //! SCI_WORDPARTRIGHTEXTEND = 2393, //! SCI_SETVISIBLEPOLICY = 2394, //! SCI_DELLINELEFT = 2395, //! SCI_DELLINERIGHT = 2396, //! SCI_SETXOFFSET = 2397, //! SCI_GETXOFFSET = 2398, //! SCI_CHOOSECARETX = 2399, //! SCI_GRABFOCUS = 2400, //! SCI_SETXCARETPOLICY = 2402, //! SCI_SETYCARETPOLICY = 2403, //! SCI_LINEDUPLICATE = 2404, //! This message takes a copy of an image and registers it so that it //! can be refered to by a unique integer identifier. //! \a wParam is the image's identifier. //! \a lParam is a pointer to a QPixmap instance. Note that in other //! ports of Scintilla this is a pointer to either raw or textual XPM //! image data. //! //! \sa SCI_CLEARREGISTEREDIMAGES, SCI_REGISTERRGBAIMAGE SCI_REGISTERIMAGE = 2405, //! SCI_SETPRINTWRAPMODE = 2406, //! SCI_GETPRINTWRAPMODE = 2407, //! This message de-registers all currently registered images. //! //! \sa SCI_REGISTERIMAGE, SCI_REGISTERRGBAIMAGE SCI_CLEARREGISTEREDIMAGES = 2408, //! SCI_STYLESETHOTSPOT = 2409, //! SCI_SETHOTSPOTACTIVEFORE = 2410, //! SCI_SETHOTSPOTACTIVEBACK = 2411, //! SCI_SETHOTSPOTACTIVEUNDERLINE = 2412, //! SCI_PARADOWN = 2413, //! SCI_PARADOWNEXTEND = 2414, //! SCI_PARAUP = 2415, //! SCI_PARAUPEXTEND = 2416, //! SCI_POSITIONBEFORE = 2417, //! SCI_POSITIONAFTER = 2418, //! SCI_COPYRANGE = 2419, //! SCI_COPYTEXT = 2420, //! SCI_SETHOTSPOTSINGLELINE = 2421, //! SCI_SETSELECTIONMODE = 2422, //! SCI_GETSELECTIONMODE = 2423, //! SCI_GETLINESELSTARTPOSITION = 2424, //! SCI_GETLINESELENDPOSITION = 2425, //! SCI_LINEDOWNRECTEXTEND = 2426, //! SCI_LINEUPRECTEXTEND = 2427, //! SCI_CHARLEFTRECTEXTEND = 2428, //! SCI_CHARRIGHTRECTEXTEND = 2429, //! SCI_HOMERECTEXTEND = 2430, //! SCI_VCHOMERECTEXTEND = 2431, //! SCI_LINEENDRECTEXTEND = 2432, //! SCI_PAGEUPRECTEXTEND = 2433, //! SCI_PAGEDOWNRECTEXTEND = 2434, //! SCI_STUTTEREDPAGEUP = 2435, //! SCI_STUTTEREDPAGEUPEXTEND = 2436, //! SCI_STUTTEREDPAGEDOWN = 2437, //! SCI_STUTTEREDPAGEDOWNEXTEND = 2438, //! SCI_WORDLEFTEND = 2439, //! SCI_WORDLEFTENDEXTEND = 2440, //! SCI_WORDRIGHTEND = 2441, //! SCI_WORDRIGHTENDEXTEND = 2442, //! SCI_SETWHITESPACECHARS = 2443, //! SCI_SETCHARSDEFAULT = 2444, //! SCI_AUTOCGETCURRENT = 2445, //! SCI_ALLOCATE = 2446, //! SCI_HOMEWRAP = 2349, //! SCI_HOMEWRAPEXTEND = 2450, //! SCI_LINEENDWRAP = 2451, //! SCI_LINEENDWRAPEXTEND = 2452, //! SCI_VCHOMEWRAP = 2453, //! SCI_VCHOMEWRAPEXTEND = 2454, //! SCI_LINECOPY = 2455, //! SCI_FINDCOLUMN = 2456, //! SCI_GETCARETSTICKY = 2457, //! SCI_SETCARETSTICKY = 2458, //! SCI_TOGGLECARETSTICKY = 2459, //! SCI_SETWRAPVISUALFLAGS = 2460, //! SCI_GETWRAPVISUALFLAGS = 2461, //! SCI_SETWRAPVISUALFLAGSLOCATION = 2462, //! SCI_GETWRAPVISUALFLAGSLOCATION = 2463, //! SCI_SETWRAPSTARTINDENT = 2464, //! SCI_GETWRAPSTARTINDENT = 2465, //! SCI_MARKERADDSET = 2466, //! SCI_SETPASTECONVERTENDINGS = 2467, //! SCI_GETPASTECONVERTENDINGS = 2468, //! SCI_SELECTIONDUPLICATE = 2469, //! SCI_SETCARETLINEBACKALPHA = 2470, //! SCI_GETCARETLINEBACKALPHA = 2471, //! SCI_SETWRAPINDENTMODE = 2472, //! SCI_GETWRAPINDENTMODE = 2473, //! SCI_MARKERSETALPHA = 2476, //! SCI_GETSELALPHA = 2477, //! SCI_SETSELALPHA = 2478, //! SCI_GETSELEOLFILLED = 2479, //! SCI_SETSELEOLFILLED = 2480, //! SCI_STYLEGETFORE = 2481, //! SCI_STYLEGETBACK = 2482, //! SCI_STYLEGETBOLD = 2483, //! SCI_STYLEGETITALIC = 2484, //! SCI_STYLEGETSIZE = 2485, //! SCI_STYLEGETFONT = 2486, //! SCI_STYLEGETEOLFILLED = 2487, //! SCI_STYLEGETUNDERLINE = 2488, //! SCI_STYLEGETCASE = 2489, //! SCI_STYLEGETCHARACTERSET = 2490, //! SCI_STYLEGETVISIBLE = 2491, //! SCI_STYLEGETCHANGEABLE = 2492, //! SCI_STYLEGETHOTSPOT = 2493, //! SCI_GETHOTSPOTACTIVEFORE = 2494, //! SCI_GETHOTSPOTACTIVEBACK = 2495, //! SCI_GETHOTSPOTACTIVEUNDERLINE = 2496, //! SCI_GETHOTSPOTSINGLELINE = 2497, //! SCI_BRACEHIGHLIGHTINDICATOR = 2498, //! SCI_BRACEBADLIGHTINDICATOR = 2499, //! SCI_SETINDICATORCURRENT = 2500, //! SCI_GETINDICATORCURRENT = 2501, //! SCI_SETINDICATORVALUE = 2502, //! SCI_GETINDICATORVALUE = 2503, //! SCI_INDICATORFILLRANGE = 2504, //! SCI_INDICATORCLEARRANGE = 2505, //! SCI_INDICATORALLONFOR = 2506, //! SCI_INDICATORVALUEAT = 2507, //! SCI_INDICATORSTART = 2508, //! SCI_INDICATOREND = 2509, //! SCI_INDICSETUNDER = 2510, //! SCI_INDICGETUNDER = 2511, //! SCI_SETCARETSTYLE = 2512, //! SCI_GETCARETSTYLE = 2513, //! SCI_SETPOSITIONCACHE = 2514, //! SCI_GETPOSITIONCACHE = 2515, //! SCI_SETSCROLLWIDTHTRACKING = 2516, //! SCI_GETSCROLLWIDTHTRACKING = 2517, //! SCI_DELWORDRIGHTEND = 2518, //! This message copies the selection. If the selection is empty then //! copy the line with the caret. SCI_COPYALLOWLINE = 2519, //! This message returns a pointer to the document text. Any //! subsequent message will invalidate the pointer. SCI_GETCHARACTERPOINTER = 2520, //! SCI_INDICSETALPHA = 2523, //! SCI_INDICGETALPHA = 2524, //! SCI_SETEXTRAASCENT = 2525, //! SCI_GETEXTRAASCENT = 2526, //! SCI_SETEXTRADESCENT = 2527, //! SCI_GETEXTRADESCENT = 2528, //! SCI_MARKERSYMBOLDEFINED = 2529, //! SCI_MARGINSETTEXT = 2530, //! SCI_MARGINGETTEXT = 2531, //! SCI_MARGINSETSTYLE = 2532, //! SCI_MARGINGETSTYLE = 2533, //! SCI_MARGINSETSTYLES = 2534, //! SCI_MARGINGETSTYLES = 2535, //! SCI_MARGINTEXTCLEARALL = 2536, //! SCI_MARGINSETSTYLEOFFSET = 2537, //! SCI_MARGINGETSTYLEOFFSET = 2538, //! SCI_SETMARGINOPTIONS = 2539, //! SCI_ANNOTATIONSETTEXT = 2540, //! SCI_ANNOTATIONGETTEXT = 2541, //! SCI_ANNOTATIONSETSTYLE = 2542, //! SCI_ANNOTATIONGETSTYLE = 2543, //! SCI_ANNOTATIONSETSTYLES = 2544, //! SCI_ANNOTATIONGETSTYLES = 2545, //! SCI_ANNOTATIONGETLINES = 2546, //! SCI_ANNOTATIONCLEARALL = 2547, //! SCI_ANNOTATIONSETVISIBLE = 2548, //! SCI_ANNOTATIONGETVISIBLE = 2549, //! SCI_ANNOTATIONSETSTYLEOFFSET = 2550, //! SCI_ANNOTATIONGETSTYLEOFFSET = 2551, //! SCI_RELEASEALLEXTENDEDSTYLES = 2552, //! SCI_ALLOCATEEXTENDEDSTYLES = 2553, //! SCI_SETEMPTYSELECTION = 2556, //! SCI_GETMARGINOPTIONS = 2557, //! SCI_INDICSETOUTLINEALPHA = 2558, //! SCI_INDICGETOUTLINEALPHA = 2559, //! SCI_ADDUNDOACTION = 2560, //! SCI_CHARPOSITIONFROMPOINT = 2561, //! SCI_CHARPOSITIONFROMPOINTCLOSE = 2562, //! SCI_SETMULTIPLESELECTION = 2563, //! SCI_GETMULTIPLESELECTION = 2564, //! SCI_SETADDITIONALSELECTIONTYPING = 2565, //! SCI_GETADDITIONALSELECTIONTYPING = 2566, //! SCI_SETADDITIONALCARETSBLINK = 2567, //! SCI_GETADDITIONALCARETSBLINK = 2568, //! SCI_SCROLLRANGE = 2569, //! SCI_GETSELECTIONS = 2570, //! SCI_CLEARSELECTIONS = 2571, //! SCI_SETSELECTION = 2572, //! SCI_ADDSELECTION = 2573, //! SCI_SETMAINSELECTION = 2574, //! SCI_GETMAINSELECTION = 2575, //! SCI_SETSELECTIONNCARET = 2576, //! SCI_GETSELECTIONNCARET = 2577, //! SCI_SETSELECTIONNANCHOR = 2578, //! SCI_GETSELECTIONNANCHOR = 2579, //! SCI_SETSELECTIONNCARETVIRTUALSPACE = 2580, //! SCI_GETSELECTIONNCARETVIRTUALSPACE = 2581, //! SCI_SETSELECTIONNANCHORVIRTUALSPACE = 2582, //! SCI_GETSELECTIONNANCHORVIRTUALSPACE = 2583, //! SCI_SETSELECTIONNSTART = 2584, //! SCI_GETSELECTIONNSTART = 2585, //! SCI_SETSELECTIONNEND = 2586, //! SCI_GETSELECTIONNEND = 2587, //! SCI_SETRECTANGULARSELECTIONCARET = 2588, //! SCI_GETRECTANGULARSELECTIONCARET = 2589, //! SCI_SETRECTANGULARSELECTIONANCHOR = 2590, //! SCI_GETRECTANGULARSELECTIONANCHOR = 2591, //! SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE = 2592, //! SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE = 2593, //! SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE = 2594, //! SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE = 2595, //! SCI_SETVIRTUALSPACEOPTIONS = 2596, //! SCI_GETVIRTUALSPACEOPTIONS = 2597, //! SCI_SETRECTANGULARSELECTIONMODIFIER = 2598, //! SCI_GETRECTANGULARSELECTIONMODIFIER = 2599, //! SCI_SETADDITIONALSELFORE = 2600, //! SCI_SETADDITIONALSELBACK = 2601, //! SCI_SETADDITIONALSELALPHA = 2602, //! SCI_GETADDITIONALSELALPHA = 2603, //! SCI_SETADDITIONALCARETFORE = 2604, //! SCI_GETADDITIONALCARETFORE = 2605, //! SCI_ROTATESELECTION = 2606, //! SCI_SWAPMAINANCHORCARET = 2607, //! SCI_SETADDITIONALCARETSVISIBLE = 2608, //! SCI_GETADDITIONALCARETSVISIBLE = 2609, //! SCI_AUTOCGETCURRENTTEXT = 2610, //! SCI_SETFONTQUALITY = 2611, //! SCI_GETFONTQUALITY = 2612, //! SCI_SETFIRSTVISIBLELINE = 2613, //! SCI_SETMULTIPASTE = 2614, //! SCI_GETMULTIPASTE = 2615, //! SCI_GETTAG = 2616, //! SCI_CHANGELEXERSTATE = 2617, //! SCI_CONTRACTEDFOLDNEXT = 2618, //! SCI_VERTICALCENTRECARET = 2619, //! SCI_MOVESELECTEDLINESUP = 2620, //! SCI_MOVESELECTEDLINESDOWN = 2621, //! SCI_SETIDENTIFIER = 2622, //! SCI_GETIDENTIFIER = 2623, //! This message sets the width of an RGBA image specified by a future //! call to SCI_MARKERDEFINERGBAIMAGE or SCI_REGISTERRGBAIMAGE. //! //! \sa SCI_RGBAIMAGESETHEIGHT, SCI_MARKERDEFINERGBAIMAGE, //! SCI_REGISTERRGBAIMAGE. SCI_RGBAIMAGESETWIDTH = 2624, //! This message sets the height of an RGBA image specified by a future //! call to SCI_MARKERDEFINERGBAIMAGE or SCI_REGISTERRGBAIMAGE. //! //! \sa SCI_RGBAIMAGESETWIDTH, SCI_MARKERDEFINERGBAIMAGE, //! SCI_REGISTERRGBAIMAGE. SCI_RGBAIMAGESETHEIGHT = 2625, //! This message sets the symbol used to draw one of the 32 markers to //! an RGBA image. RGBA images use the SC_MARK_RGBAIMAGE marker //! symbol. //! \a wParam is the number of the marker. //! \a lParam is a pointer to a QImage instance. Note that in other //! ports of Scintilla this is a pointer to raw RGBA image data. //! //! \sa SCI_MARKERDEFINE, SCI_MARKERDEFINEPIXMAP SCI_MARKERDEFINERGBAIMAGE = 2626, //! This message takes a copy of an image and registers it so that it //! can be refered to by a unique integer identifier. //! \a wParam is the image's identifier. //! \a lParam is a pointer to a QImage instance. Note that in other //! ports of Scintilla this is a pointer to raw RGBA image data. //! //! \sa SCI_CLEARREGISTEREDIMAGES, SCI_REGISTERIMAGE SCI_REGISTERRGBAIMAGE = 2627, //! SCI_SCROLLTOSTART = 2628, //! SCI_SCROLLTOEND = 2629, //! SCI_SETTECHNOLOGY = 2630, //! SCI_GETTECHNOLOGY = 2631, //! SCI_CREATELOADER = 2632, //! SCI_COUNTCHARACTERS = 2633, //! SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR = 2634, //! SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR = 2635, //! SCI_AUTOCSETMULTI = 2636, //! SCI_AUTOCGETMULTI = 2637, //! SCI_FINDINDICATORSHOW = 2640, //! SCI_FINDINDICATORFLASH = 2641, //! SCI_FINDINDICATORHIDE = 2642, //! SCI_GETRANGEPOINTER = 2643, //! SCI_GETGAPPOSITION = 2644, //! SCI_DELETERANGE = 2645, //! SCI_GETWORDCHARS = 2646, //! SCI_GETWHITESPACECHARS = 2647, //! SCI_SETPUNCTUATIONCHARS = 2648, //! SCI_GETPUNCTUATIONCHARS = 2649, //! SCI_GETSELECTIONEMPTY = 2650, //! SCI_RGBAIMAGESETSCALE = 2651, //! SCI_VCHOMEDISPLAY = 2652, //! SCI_VCHOMEDISPLAYEXTEND = 2653, //! SCI_GETCARETLINEVISIBLEALWAYS = 2654, //! SCI_SETCARETLINEVISIBLEALWAYS = 2655, //! SCI_SETLINEENDTYPESALLOWED = 2656, //! SCI_GETLINEENDTYPESALLOWED = 2657, //! SCI_GETLINEENDTYPESACTIVE = 2658, //! SCI_AUTOCSETORDER = 2660, //! SCI_AUTOCGETORDER = 2661, //! SCI_FOLDALL = 2662, //! SCI_SETAUTOMATICFOLD = 2663, //! SCI_GETAUTOMATICFOLD = 2664, //! SCI_SETREPRESENTATION = 2665, //! SCI_GETREPRESENTATION = 2666, //! SCI_CLEARREPRESENTATION = 2667, //! SCI_SETMOUSESELECTIONRECTANGULARSWITCH = 2668, //! SCI_GETMOUSESELECTIONRECTANGULARSWITCH = 2669, //! SCI_POSITIONRELATIVE = 2670, //! SCI_DROPSELECTIONN = 2671, //! SCI_CHANGEINSERTION = 2672, //! SCI_GETPHASESDRAW = 2673, //! SCI_SETPHASESDRAW = 2674, //! SCI_CLEARTABSTOPS = 2675, //! SCI_ADDTABSTOP = 2676, //! SCI_GETNEXTTABSTOP = 2677, //! SCI_GETIMEINTERACTION = 2678, //! SCI_SETIMEINTERACTION = 2679, //! SCI_INDICSETHOVERSTYLE = 2680, //! SCI_INDICGETHOVERSTYLE = 2681, //! SCI_INDICSETHOVERFORE = 2682, //! SCI_INDICGETHOVERFORE = 2683, //! SCI_INDICSETFLAGS = 2684, //! SCI_INDICGETFLAGS = 2685, //! SCI_SETTARGETRANGE = 2686, //! SCI_GETTARGETTEXT = 2687, //! SCI_MULTIPLESELECTADDNEXT = 2688, //! SCI_MULTIPLESELECTADDEACH = 2689, //! SCI_TARGETWHOLEDOCUMENT = 2690, //! SCI_ISRANGEWORD = 2691, //! SCI_SETIDLESTYLING = 2692, //! SCI_GETIDLESTYLING = 2693, //! SCI_MULTIEDGEADDLINE = 2694, //! SCI_MULTIEDGECLEARALL = 2695, //! SCI_SETMOUSEWHEELCAPTURES = 2696, //! SCI_GETMOUSEWHEELCAPTURES = 2697, //! SCI_GETTABDRAWMODE = 2698, //! SCI_SETTABDRAWMODE = 2699, //! SCI_TOGGLEFOLDSHOWTEXT = 2700, //! SCI_FOLDDISPLAYTEXTSETSTYLE = 2701, //! SCI_SETACCESSIBILITY = 2702, //! SCI_GETACCESSIBILITY = 2703, //! SCI_GETCARETLINEFRAME = 2704, //! SCI_SETCARETLINEFRAME = 2705, //! SCI_STARTRECORD = 3001, //! SCI_STOPRECORD = 3002, //! This message sets the number of the lexer to use for syntax //! styling. //! \a wParam is the number of the lexer and is one of the SCLEX_* //! values. SCI_SETLEXER = 4001, //! This message returns the number of the lexer being used for syntax //! styling. SCI_GETLEXER = 4002, //! SCI_COLOURISE = 4003, //! SCI_SETPROPERTY = 4004, //! SCI_SETKEYWORDS = 4005, //! This message sets the name of the lexer to use for syntax styling. //! \a wParam is unused. //! \a lParam is the name of the lexer. SCI_SETLEXERLANGUAGE = 4006, //! SCI_LOADLEXERLIBRARY = 4007, //! SCI_GETPROPERTY = 4008, //! SCI_GETPROPERTYEXPANDED = 4009, //! SCI_GETPROPERTYINT = 4010, //! SCI_GETSTYLEBITSNEEDED = 4011, //! SCI_GETLEXERLANGUAGE = 4012, //! SCI_PRIVATELEXERCALL = 4013, //! SCI_PROPERTYNAMES = 4014, //! SCI_PROPERTYTYPE = 4015, //! SCI_DESCRIBEPROPERTY = 4016, //! SCI_DESCRIBEKEYWORDSETS = 4017, //! SCI_GETLINEENDTYPESSUPPORTED = 4018, //! SCI_ALLOCATESUBSTYLES = 4020, //! SCI_GETSUBSTYLESSTART = 4021, //! SCI_GETSUBSTYLESLENGTH = 4022, //! SCI_GETSTYLEFROMSUBSTYLE = 4027, //! SCI_GETPRIMARYSTYLEFROMSTYLE = 4028, //! SCI_FREESUBSTYLES = 4023, //! SCI_SETIDENTIFIERS = 4024, //! SCI_DISTANCETOSECONDARYSTYLES = 4025, //! SCI_GETSUBSTYLEBASES = 4026, //! SCI_GETLINECHARACTERINDEX = 2710, //! SCI_ALLOCATELINECHARACTERINDEX = 2711, //! SCI_RELEASELINECHARACTERINDEX = 2712, //! SCI_LINEFROMINDEXPOSITION = 2713, //! SCI_INDEXPOSITIONFROMLINE = 2714, //! SCI_COUNTCODEUNITS = 2715, //! SCI_POSITIONRELATIVECODEUNITS = 2716, //! SCI_GETNAMEDSTYLES = 4029, //! SCI_NAMEOFSTYLE = 4030, //! SCI_TAGSOFSTYLE = 4031, //! SCI_DESCRIPTIONOFSTYLE = 4032, //! SCI_GETMOVEEXTENDSSELECTION = 2706, //! SCI_SETCOMMANDEVENTS = 2717, //! SCI_GETCOMMANDEVENTS = 2718, //! SCI_GETDOCUMENTOPTIONS = 2379, }; enum { SC_AC_FILLUP = 1, SC_AC_DOUBLECLICK = 2, SC_AC_TAB = 3, SC_AC_NEWLINE = 4, SC_AC_COMMAND = 5, }; enum { SC_ALPHA_TRANSPARENT = 0, SC_ALPHA_OPAQUE = 255, SC_ALPHA_NOALPHA = 256 }; enum { SC_CARETSTICKY_OFF = 0, SC_CARETSTICKY_ON = 1, SC_CARETSTICKY_WHITESPACE = 2 }; enum { SC_DOCUMENTOPTION_DEFAULT = 0x0000, SC_DOCUMENTOPTION_STYLES_NONE = 0x0001, SC_DOCUMENTOPTION_TEXT_LARGE = 0x0100, }; enum { SC_EFF_QUALITY_MASK = 0x0f, SC_EFF_QUALITY_DEFAULT = 0, SC_EFF_QUALITY_NON_ANTIALIASED = 1, SC_EFF_QUALITY_ANTIALIASED = 2, SC_EFF_QUALITY_LCD_OPTIMIZED = 3 }; enum { SC_IDLESTYLING_NONE = 0, SC_IDLESTYLING_TOVISIBLE = 1, SC_IDLESTYLING_AFTERVISIBLE = 2, SC_IDLESTYLING_ALL = 3, }; enum { SC_IME_WINDOWED = 0, SC_IME_INLINE = 1, }; enum { SC_LINECHARACTERINDEX_NONE = 0, SC_LINECHARACTERINDEX_UTF32 = 1, SC_LINECHARACTERINDEX_UTF16 = 2, }; enum { SC_MARGINOPTION_NONE = 0x00, SC_MARGINOPTION_SUBLINESELECT = 0x01 }; enum { SC_MULTIAUTOC_ONCE = 0, SC_MULTIAUTOC_EACH = 1 }; enum { SC_MULTIPASTE_ONCE = 0, SC_MULTIPASTE_EACH = 1 }; enum { SC_POPUP_NEVER = 0, SC_POPUP_ALL = 1, SC_POPUP_TEXT = 2, }; //! This enum defines the different selection modes. //! //! \sa SCI_GETSELECTIONMODE, SCI_SETSELECTIONMODE enum { SC_SEL_STREAM = 0, SC_SEL_RECTANGLE = 1, SC_SEL_LINES = 2, SC_SEL_THIN = 3 }; enum { SC_STATUS_OK = 0, SC_STATUS_FAILURE = 1, SC_STATUS_BADALLOC = 2, SC_STATUS_WARN_START = 1000, SC_STATUS_WARNREGEX = 1001, }; enum { SC_TYPE_BOOLEAN = 0, SC_TYPE_INTEGER = 1, SC_TYPE_STRING = 2 }; enum { SC_UPDATE_CONTENT = 0x01, SC_UPDATE_SELECTION = 0x02, SC_UPDATE_V_SCROLL = 0x04, SC_UPDATE_H_SCROLL = 0x08 }; enum { SC_WRAPVISUALFLAG_NONE = 0x0000, SC_WRAPVISUALFLAG_END = 0x0001, SC_WRAPVISUALFLAG_START = 0x0002, SC_WRAPVISUALFLAG_MARGIN = 0x0004 }; enum { SC_WRAPVISUALFLAGLOC_DEFAULT = 0x0000, SC_WRAPVISUALFLAGLOC_END_BY_TEXT = 0x0001, SC_WRAPVISUALFLAGLOC_START_BY_TEXT = 0x0002 }; enum { SCTD_LONGARROW = 0, SCTD_STRIKEOUT = 1, }; enum { SCVS_NONE = 0, SCVS_RECTANGULARSELECTION = 1, SCVS_USERACCESSIBLE = 2, SCVS_NOWRAPLINESTART = 4, }; enum { SCWS_INVISIBLE = 0, SCWS_VISIBLEALWAYS = 1, SCWS_VISIBLEAFTERINDENT = 2, SCWS_VISIBLEONLYININDENT = 3, }; enum { SC_EOL_CRLF = 0, SC_EOL_CR = 1, SC_EOL_LF = 2 }; enum { SC_CP_DBCS = 1, SC_CP_UTF8 = 65001 }; //! This enum defines the different marker symbols. //! //! \sa SCI_MARKERDEFINE enum { //! A circle. SC_MARK_CIRCLE = 0, //! A rectangle. SC_MARK_ROUNDRECT = 1, //! A triangle pointing to the right. SC_MARK_ARROW = 2, //! A smaller rectangle. SC_MARK_SMALLRECT = 3, //! An arrow pointing to the right. SC_MARK_SHORTARROW = 4, //! An invisible marker that allows code to track the movement //! of lines. SC_MARK_EMPTY = 5, //! A triangle pointing down. SC_MARK_ARROWDOWN = 6, //! A drawn minus sign. SC_MARK_MINUS = 7, //! A drawn plus sign. SC_MARK_PLUS = 8, //! A vertical line drawn in the background colour. SC_MARK_VLINE = 9, //! A bottom left corner drawn in the background colour. SC_MARK_LCORNER = 10, //! A vertical line with a centre right horizontal line drawn //! in the background colour. SC_MARK_TCORNER = 11, //! A drawn plus sign in a box. SC_MARK_BOXPLUS = 12, //! A drawn plus sign in a connected box. SC_MARK_BOXPLUSCONNECTED = 13, //! A drawn minus sign in a box. SC_MARK_BOXMINUS = 14, //! A drawn minus sign in a connected box. SC_MARK_BOXMINUSCONNECTED = 15, //! A rounded bottom left corner drawn in the background //! colour. SC_MARK_LCORNERCURVE = 16, //! A vertical line with a centre right curved line drawn in //! the background colour. SC_MARK_TCORNERCURVE = 17, //! A drawn plus sign in a circle. SC_MARK_CIRCLEPLUS = 18, //! A drawn plus sign in a connected box. SC_MARK_CIRCLEPLUSCONNECTED = 19, //! A drawn minus sign in a circle. SC_MARK_CIRCLEMINUS = 20, //! A drawn minus sign in a connected circle. SC_MARK_CIRCLEMINUSCONNECTED = 21, //! No symbol is drawn but the line is drawn with the same background //! color as the marker's. SC_MARK_BACKGROUND = 22, //! Three drawn dots. SC_MARK_DOTDOTDOT = 23, //! Three drawn arrows pointing right. SC_MARK_ARROWS = 24, //! An XPM format pixmap. SC_MARK_PIXMAP = 25, //! A full rectangle (ie. the margin background) using the marker's //! background color. SC_MARK_FULLRECT = 26, //! A left rectangle (ie. the left part of the margin background) using //! the marker's background color. SC_MARK_LEFTRECT = 27, //! The value is available for plugins to use. SC_MARK_AVAILABLE = 28, //! The line is underlined using the marker's background color. SC_MARK_UNDERLINE = 29, //! A RGBA format image. SC_MARK_RGBAIMAGE = 30, //! A bookmark. SC_MARK_BOOKMARK = 31, //! Characters can be used as symbols by adding this to the ASCII value //! of the character. SC_MARK_CHARACTER = 10000 }; enum { SC_MARKNUM_FOLDEREND = 25, SC_MARKNUM_FOLDEROPENMID = 26, SC_MARKNUM_FOLDERMIDTAIL = 27, SC_MARKNUM_FOLDERTAIL = 28, SC_MARKNUM_FOLDERSUB = 29, SC_MARKNUM_FOLDER = 30, SC_MARKNUM_FOLDEROPEN = 31, SC_MASK_FOLDERS = 0xfe000000 }; //! This enum defines what can be displayed in a margin. //! //! \sa SCI_GETMARGINTYPEN, SCI_SETMARGINTYPEN enum { //! The margin can display symbols. Note that all margins can display //! symbols. SC_MARGIN_SYMBOL = 0, //! The margin will display line numbers. SC_MARGIN_NUMBER = 1, //! The margin's background color will be set to the default background //! color. SC_MARGIN_BACK = 2, //! The margin's background color will be set to the default foreground //! color. SC_MARGIN_FORE = 3, //! The margin will display text. SC_MARGIN_TEXT = 4, //! The margin will display right justified text. SC_MARGIN_RTEXT = 5, //! The margin's background color will be set to the color set by //! SCI_SETMARGINBACKN. SC_MARGIN_COLOUR = 6, }; enum { STYLE_DEFAULT = 32, STYLE_LINENUMBER = 33, STYLE_BRACELIGHT = 34, STYLE_BRACEBAD = 35, STYLE_CONTROLCHAR = 36, STYLE_INDENTGUIDE = 37, STYLE_CALLTIP = 38, STYLE_FOLDDISPLAYTEXT = 39, STYLE_LASTPREDEFINED = 39, STYLE_MAX = 255 }; enum { SC_CHARSET_ANSI = 0, SC_CHARSET_DEFAULT = 1, SC_CHARSET_BALTIC = 186, SC_CHARSET_CHINESEBIG5 = 136, SC_CHARSET_EASTEUROPE = 238, SC_CHARSET_GB2312 = 134, SC_CHARSET_GREEK = 161, SC_CHARSET_HANGUL = 129, SC_CHARSET_MAC = 77, SC_CHARSET_OEM = 255, SC_CHARSET_RUSSIAN = 204, SC_CHARSET_OEM866 = 866, SC_CHARSET_CYRILLIC = 1251, SC_CHARSET_SHIFTJIS = 128, SC_CHARSET_SYMBOL = 2, SC_CHARSET_TURKISH = 162, SC_CHARSET_JOHAB = 130, SC_CHARSET_HEBREW = 177, SC_CHARSET_ARABIC = 178, SC_CHARSET_VIETNAMESE = 163, SC_CHARSET_THAI = 222, SC_CHARSET_8859_15 = 1000 }; enum { SC_CASE_MIXED = 0, SC_CASE_UPPER = 1, SC_CASE_LOWER = 2, SC_CASE_CAMEL = 3, }; //! This enum defines the different indentation guide views. //! //! \sa SCI_GETINDENTATIONGUIDES, SCI_SETINDENTATIONGUIDES enum { //! No indentation guides are shown. SC_IV_NONE = 0, //! Indentation guides are shown inside real indentation white space. SC_IV_REAL = 1, //! Indentation guides are shown beyond the actual indentation up to //! the level of the next non-empty line. If the previous non-empty //! line was a fold header then indentation guides are shown for one //! more level of indent than that line. This setting is good for //! Python. SC_IV_LOOKFORWARD = 2, //! Indentation guides are shown beyond the actual indentation up to //! the level of the next non-empty line or previous non-empty line //! whichever is the greater. This setting is good for most languages. SC_IV_LOOKBOTH = 3 }; enum { INDIC_PLAIN = 0, INDIC_SQUIGGLE = 1, INDIC_TT = 2, INDIC_DIAGONAL = 3, INDIC_STRIKE = 4, INDIC_HIDDEN = 5, INDIC_BOX = 6, INDIC_ROUNDBOX = 7, INDIC_STRAIGHTBOX = 8, INDIC_DASH = 9, INDIC_DOTS = 10, INDIC_SQUIGGLELOW = 11, INDIC_DOTBOX = 12, INDIC_SQUIGGLEPIXMAP = 13, INDIC_COMPOSITIONTHICK = 14, INDIC_COMPOSITIONTHIN = 15, INDIC_FULLBOX = 16, INDIC_TEXTFORE = 17, INDIC_POINT = 18, INDIC_POINTCHARACTER = 19, INDIC_GRADIENT = 20, INDIC_GRADIENTCENTRE = 21, INDIC_IME = 32, INDIC_IME_MAX = 35, INDIC_CONTAINER = 8, INDIC_MAX = 35, INDIC0_MASK = 0x20, INDIC1_MASK = 0x40, INDIC2_MASK = 0x80, INDICS_MASK = 0xe0, SC_INDICVALUEBIT = 0x01000000, SC_INDICVALUEMASK = 0x00ffffff, SC_INDICFLAG_VALUEBEFORE = 1, }; enum { SC_PRINT_NORMAL = 0, SC_PRINT_INVERTLIGHT = 1, SC_PRINT_BLACKONWHITE = 2, SC_PRINT_COLOURONWHITE = 3, SC_PRINT_COLOURONWHITEDEFAULTBG = 4, SC_PRINT_SCREENCOLOURS = 5, }; enum { SCFIND_WHOLEWORD = 2, SCFIND_MATCHCASE = 4, SCFIND_WORDSTART = 0x00100000, SCFIND_REGEXP = 0x00200000, SCFIND_POSIX = 0x00400000, SCFIND_CXX11REGEX = 0x00800000, }; enum { SC_FOLDDISPLAYTEXT_HIDDEN = 0, SC_FOLDDISPLAYTEXT_STANDARD = 1, SC_FOLDDISPLAYTEXT_BOXED = 2, }; enum { SC_FOLDLEVELBASE = 0x00400, SC_FOLDLEVELWHITEFLAG = 0x01000, SC_FOLDLEVELHEADERFLAG = 0x02000, SC_FOLDLEVELNUMBERMASK = 0x00fff }; enum { SC_FOLDFLAG_LINEBEFORE_EXPANDED = 0x0002, SC_FOLDFLAG_LINEBEFORE_CONTRACTED = 0x0004, SC_FOLDFLAG_LINEAFTER_EXPANDED = 0x0008, SC_FOLDFLAG_LINEAFTER_CONTRACTED = 0x0010, SC_FOLDFLAG_LEVELNUMBERS = 0x0040, SC_FOLDFLAG_LINESTATE = 0x0080, }; enum { SC_LINE_END_TYPE_DEFAULT = 0, SC_LINE_END_TYPE_UNICODE = 1, }; enum { SC_TIME_FOREVER = 10000000 }; enum { SC_WRAP_NONE = 0, SC_WRAP_WORD = 1, SC_WRAP_CHAR = 2, SC_WRAP_WHITESPACE = 3, }; enum { SC_WRAPINDENT_FIXED = 0, SC_WRAPINDENT_SAME = 1, SC_WRAPINDENT_INDENT = 2, SC_WRAPINDENT_DEEPINDENT = 3, }; enum { SC_CACHE_NONE = 0, SC_CACHE_CARET = 1, SC_CACHE_PAGE = 2, SC_CACHE_DOCUMENT = 3 }; enum { SC_PHASES_ONE = 0, SC_PHASES_TWO = 1, SC_PHASES_MULTIPLE = 2, }; enum { ANNOTATION_HIDDEN = 0, ANNOTATION_STANDARD = 1, ANNOTATION_BOXED = 2, ANNOTATION_INDENTED = 3, }; enum { EDGE_NONE = 0, EDGE_LINE = 1, EDGE_BACKGROUND = 2, EDGE_MULTILINE = 3, }; enum { SC_CURSORNORMAL = -1, SC_CURSORARROW = 2, SC_CURSORWAIT = 4, SC_CURSORREVERSEARROW = 7 }; enum { UNDO_MAY_COALESCE = 1 }; enum { VISIBLE_SLOP = 0x01, VISIBLE_STRICT = 0x04 }; enum { CARET_SLOP = 0x01, CARET_STRICT = 0x04, CARET_JUMPS = 0x10, CARET_EVEN = 0x08 }; enum { CARETSTYLE_INVISIBLE = 0, CARETSTYLE_LINE = 1, CARETSTYLE_BLOCK = 2 }; enum { SC_MOD_INSERTTEXT = 0x1, SC_MOD_DELETETEXT = 0x2, SC_MOD_CHANGESTYLE = 0x4, SC_MOD_CHANGEFOLD = 0x8, SC_PERFORMED_USER = 0x10, SC_PERFORMED_UNDO = 0x20, SC_PERFORMED_REDO = 0x40, SC_MULTISTEPUNDOREDO = 0x80, SC_LASTSTEPINUNDOREDO = 0x100, SC_MOD_CHANGEMARKER = 0x200, SC_MOD_BEFOREINSERT = 0x400, SC_MOD_BEFOREDELETE = 0x800, SC_MULTILINEUNDOREDO = 0x1000, SC_STARTACTION = 0x2000, SC_MOD_CHANGEINDICATOR = 0x4000, SC_MOD_CHANGELINESTATE = 0x8000, SC_MOD_CHANGEMARGIN = 0x10000, SC_MOD_CHANGEANNOTATION = 0x20000, SC_MOD_CONTAINER = 0x40000, SC_MOD_LEXERSTATE = 0x80000, SC_MOD_INSERTCHECK = 0x100000, SC_MOD_CHANGETABSTOPS = 0x200000, SC_MODEVENTMASKALL = 0x3fffff }; enum { SCK_DOWN = 300, SCK_UP = 301, SCK_LEFT = 302, SCK_RIGHT = 303, SCK_HOME = 304, SCK_END = 305, SCK_PRIOR = 306, SCK_NEXT = 307, SCK_DELETE = 308, SCK_INSERT = 309, SCK_ESCAPE = 7, SCK_BACK = 8, SCK_TAB = 9, SCK_RETURN = 13, SCK_ADD = 310, SCK_SUBTRACT = 311, SCK_DIVIDE = 312, SCK_WIN = 313, SCK_RWIN = 314, SCK_MENU = 315 }; //! This enum defines the different modifier keys. enum { //! No modifier key. SCMOD_NORM = 0, //! Shift key. SCMOD_SHIFT = 1, //! Control key (the Command key on OS/X, the Ctrl key on other //! platforms). SCMOD_CTRL = 2, //! Alt key. SCMOD_ALT = 4, //! This is the same as SCMOD_META on all platforms. SCMOD_SUPER = 8, //! Meta key (the Ctrl key on OS/X, the Windows key on other //! platforms). SCMOD_META = 16 }; //! This enum defines the different language lexers. //! //! \sa SCI_GETLEXER, SCI_SETLEXER enum { //! No lexer is selected and the SCN_STYLENEEDED signal is emitted so //! that the application can style the text as needed. This is the //! default. SCLEX_CONTAINER = 0, //! Select the null lexer that does no syntax styling. SCLEX_NULL = 1, //! Select the Python lexer. SCLEX_PYTHON = 2, //! Select the C++ lexer. SCLEX_CPP = 3, //! Select the HTML lexer. SCLEX_HTML = 4, //! Select the XML lexer. SCLEX_XML = 5, //! Select the Perl lexer. SCLEX_PERL = 6, //! Select the SQL lexer. SCLEX_SQL = 7, //! Select the Visual Basic lexer. SCLEX_VB = 8, //! Select the lexer for properties style files. SCLEX_PROPERTIES = 9, //! Select the lexer for error list style files. SCLEX_ERRORLIST = 10, //! Select the Makefile lexer. SCLEX_MAKEFILE = 11, //! Select the Windows batch file lexer. SCLEX_BATCH = 12, //! Select the LaTex lexer. SCLEX_LATEX = 14, //! Select the Lua lexer. SCLEX_LUA = 15, //! Select the lexer for diff output. SCLEX_DIFF = 16, //! Select the lexer for Apache configuration files. SCLEX_CONF = 17, //! Select the Pascal lexer. SCLEX_PASCAL = 18, //! Select the Avenue lexer. SCLEX_AVE = 19, //! Select the Ada lexer. SCLEX_ADA = 20, //! Select the Lisp lexer. SCLEX_LISP = 21, //! Select the Ruby lexer. SCLEX_RUBY = 22, //! Select the Eiffel lexer. SCLEX_EIFFEL = 23, //! Select the Eiffel lexer folding at keywords. SCLEX_EIFFELKW = 24, //! Select the Tcl lexer. SCLEX_TCL = 25, //! Select the lexer for nnCron files. SCLEX_NNCRONTAB = 26, //! Select the Bullant lexer. SCLEX_BULLANT = 27, //! Select the VBScript lexer. SCLEX_VBSCRIPT = 28, //! Select the ASP lexer. SCLEX_ASP = SCLEX_HTML, //! Select the PHP lexer. SCLEX_PHP = SCLEX_HTML, //! Select the Baan lexer. SCLEX_BAAN = 31, //! Select the Matlab lexer. SCLEX_MATLAB = 32, //! Select the Scriptol lexer. SCLEX_SCRIPTOL = 33, //! Select the assembler lexer (';' comment character). SCLEX_ASM = 34, //! Select the C++ lexer with case insensitive keywords. SCLEX_CPPNOCASE = 35, //! Select the FORTRAN lexer. SCLEX_FORTRAN = 36, //! Select the FORTRAN77 lexer. SCLEX_F77 = 37, //! Select the CSS lexer. SCLEX_CSS = 38, //! Select the POV lexer. SCLEX_POV = 39, //! Select the Basser Lout typesetting language lexer. SCLEX_LOUT = 40, //! Select the EScript lexer. SCLEX_ESCRIPT = 41, //! Select the PostScript lexer. SCLEX_PS = 42, //! Select the NSIS lexer. SCLEX_NSIS = 43, //! Select the MMIX assembly language lexer. SCLEX_MMIXAL = 44, //! Select the Clarion lexer. SCLEX_CLW = 45, //! Select the Clarion lexer with case insensitive keywords. SCLEX_CLWNOCASE = 46, //! Select the MPT text log file lexer. SCLEX_LOT = 47, //! Select the YAML lexer. SCLEX_YAML = 48, //! Select the TeX lexer. SCLEX_TEX = 49, //! Select the Metapost lexer. SCLEX_METAPOST = 50, //! Select the PowerBASIC lexer. SCLEX_POWERBASIC = 51, //! Select the Forth lexer. SCLEX_FORTH = 52, //! Select the Erlang lexer. SCLEX_ERLANG = 53, //! Select the Octave lexer. SCLEX_OCTAVE = 54, //! Select the MS SQL lexer. SCLEX_MSSQL = 55, //! Select the Verilog lexer. SCLEX_VERILOG = 56, //! Select the KIX-Scripts lexer. SCLEX_KIX = 57, //! Select the Gui4Cli lexer. SCLEX_GUI4CLI = 58, //! Select the Specman E lexer. SCLEX_SPECMAN = 59, //! Select the AutoIt3 lexer. SCLEX_AU3 = 60, //! Select the APDL lexer. SCLEX_APDL = 61, //! Select the Bash lexer. SCLEX_BASH = 62, //! Select the ASN.1 lexer. SCLEX_ASN1 = 63, //! Select the VHDL lexer. SCLEX_VHDL = 64, //! Select the Caml lexer. SCLEX_CAML = 65, //! Select the BlitzBasic lexer. SCLEX_BLITZBASIC = 66, //! Select the PureBasic lexer. SCLEX_PUREBASIC = 67, //! Select the Haskell lexer. SCLEX_HASKELL = 68, //! Select the PHPScript lexer. SCLEX_PHPSCRIPT = 69, //! Select the TADS3 lexer. SCLEX_TADS3 = 70, //! Select the REBOL lexer. SCLEX_REBOL = 71, //! Select the Smalltalk lexer. SCLEX_SMALLTALK = 72, //! Select the FlagShip lexer. SCLEX_FLAGSHIP = 73, //! Select the Csound lexer. SCLEX_CSOUND = 74, //! Select the FreeBasic lexer. SCLEX_FREEBASIC = 75, //! Select the InnoSetup lexer. SCLEX_INNOSETUP = 76, //! Select the Opal lexer. SCLEX_OPAL = 77, //! Select the Spice lexer. SCLEX_SPICE = 78, //! Select the D lexer. SCLEX_D = 79, //! Select the CMake lexer. SCLEX_CMAKE = 80, //! Select the GAP lexer. SCLEX_GAP = 81, //! Select the PLM lexer. SCLEX_PLM = 82, //! Select the Progress lexer. SCLEX_PROGRESS = 83, //! Select the Abaqus lexer. SCLEX_ABAQUS = 84, //! Select the Asymptote lexer. SCLEX_ASYMPTOTE = 85, //! Select the R lexer. SCLEX_R = 86, //! Select the MagikSF lexer. SCLEX_MAGIK = 87, //! Select the PowerShell lexer. SCLEX_POWERSHELL = 88, //! Select the MySQL lexer. SCLEX_MYSQL = 89, //! Select the gettext .po file lexer. SCLEX_PO = 90, //! Select the TAL lexer. SCLEX_TAL = 91, //! Select the COBOL lexer. SCLEX_COBOL = 92, //! Select the TACL lexer. SCLEX_TACL = 93, //! Select the Sorcus lexer. SCLEX_SORCUS = 94, //! Select the PowerPro lexer. SCLEX_POWERPRO = 95, //! Select the Nimrod lexer. SCLEX_NIMROD = 96, //! Select the SML lexer. SCLEX_SML = 97, //! Select the Markdown lexer. SCLEX_MARKDOWN = 98, //! Select the txt2tags lexer. SCLEX_TXT2TAGS = 99, //! Select the 68000 assembler lexer. SCLEX_A68K = 100, //! Select the Modula 3 lexer. SCLEX_MODULA = 101, //! Select the CoffeeScript lexer. SCLEX_COFFEESCRIPT = 102, //! Select the Take Command lexer. SCLEX_TCMD = 103, //! Select the AviSynth lexer. SCLEX_AVS = 104, //! Select the ECL lexer. SCLEX_ECL = 105, //! Select the OScript lexer. SCLEX_OSCRIPT = 106, //! Select the Visual Prolog lexer. SCLEX_VISUALPROLOG = 107, //! Select the Literal Haskell lexer. SCLEX_LITERATEHASKELL = 108, //! Select the Structured Text lexer. SCLEX_STTXT = 109, //! Select the KVIrc lexer. SCLEX_KVIRC = 110, //! Select the Rust lexer. SCLEX_RUST = 111, //! Select the MSC Nastran DMAP lexer. SCLEX_DMAP = 112, //! Select the assembler lexer ('#' comment character). SCLEX_AS = 113, //! Select the DMIS lexer. SCLEX_DMIS = 114, //! Select the lexer for Windows registry files. SCLEX_REGISTRY = 115, //! Select the BibTex lexer. SCLEX_BIBTEX = 116, //! Select the Motorola S-Record hex lexer. SCLEX_SREC = 117, //! Select the Intel hex lexer. SCLEX_IHEX = 118, //! Select the Tektronix extended hex lexer. SCLEX_TEHEX = 119, //! Select the JSON hex lexer. SCLEX_JSON = 120, //! Select the EDIFACT lexer. SCLEX_EDIFACT = 121, //! Select the pseudo-lexer used for the indentation-based folding of //! files. SCLEX_INDENT = 122, //! Select the Maxima lexer. SCLEX_MAXIMA = 123, //! Select the Stata lexer. SCLEX_STATA = 124, //! Select the SAS lexer. SCLEX_SAS = 125, }; enum { SC_WEIGHT_NORMAL = 400, SC_WEIGHT_SEMIBOLD = 600, SC_WEIGHT_BOLD = 700, }; enum { SC_TECHNOLOGY_DEFAULT = 0, SC_TECHNOLOGY_DIRECTWRITE = 1, SC_TECHNOLOGY_DIRECTWRITERETAIN = 2, SC_TECHNOLOGY_DIRECTWRITEDC = 3, }; enum { SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE = 0, SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE = 1, }; enum { SC_FONT_SIZE_MULTIPLIER = 100, }; enum { SC_FOLDACTION_CONTRACT = 0, SC_FOLDACTION_EXPAND = 1, SC_FOLDACTION_TOGGLE = 2, }; enum { SC_AUTOMATICFOLD_SHOW = 0x0001, SC_AUTOMATICFOLD_CLICK = 0x0002, SC_AUTOMATICFOLD_CHANGE = 0x0004, }; enum { SC_ORDER_PRESORTED = 0, SC_ORDER_PERFORMSORT = 1, SC_ORDER_CUSTOM = 2, }; //! Construct an empty QsciScintillaBase with parent \a parent. explicit QsciScintillaBase(QWidget *parent = 0); //! Destroys the QsciScintillaBase instance. virtual ~QsciScintillaBase(); //! Returns a pointer to a QsciScintillaBase instance, or 0 if there isn't //! one. This can be used by the higher level API to send messages that //! aren't associated with a particular instance. static QsciScintillaBase *pool(); //! Replaces the existing horizontal scroll bar with \a scrollBar. The //! existing scroll bar is deleted. This should be called instead of //! QAbstractScrollArea::setHorizontalScrollBar(). void replaceHorizontalScrollBar(QScrollBar *scrollBar); //! Replaces the existing vertical scroll bar with \a scrollBar. The //! existing scroll bar is deleted. This should be called instead of //! QAbstractScrollArea::setHorizontalScrollBar(). void replaceVerticalScrollBar(QScrollBar *scrollBar); //! Send the Scintilla message \a msg with the optional parameters \a //! wParam and \a lParam. long SendScintilla(unsigned int msg, unsigned long wParam = 0, long lParam = 0) const; //! \overload long SendScintilla(unsigned int msg, unsigned long wParam, void *lParam) const; //! \overload long SendScintilla(unsigned int msg, uintptr_t wParam, const char *lParam) const; //! \overload long SendScintilla(unsigned int msg, const char *lParam) const; //! \overload long SendScintilla(unsigned int msg, const char *wParam, const char *lParam) const; //! \overload long SendScintilla(unsigned int msg, long wParam) const; //! \overload long SendScintilla(unsigned int msg, int wParam) const; //! \overload long SendScintilla(unsigned int msg, long cpMin, long cpMax, char *lpstrText) const; //! \overload long SendScintilla(unsigned int msg, unsigned long wParam, const QColor &col) const; //! \overload long SendScintilla(unsigned int msg, const QColor &col) const; //! \overload long SendScintilla(unsigned int msg, unsigned long wParam, QPainter *hdc, const QRect &rc, long cpMin, long cpMax) const; //! \overload long SendScintilla(unsigned int msg, unsigned long wParam, const QPixmap &lParam) const; //! \overload long SendScintilla(unsigned int msg, unsigned long wParam, const QImage &lParam) const; //! Send the Scintilla message \a msg and return a pointer result. void *SendScintillaPtrResult(unsigned int msg) const; //! \internal static int commandKey(int qt_key, int &modifiers); signals: //! This signal is emitted when text is selected or de-selected. //! \a yes is true if text has been selected and false if text has been //! deselected. void QSCN_SELCHANGED(bool yes); //! This signal is emitted when the user cancels an auto-completion list. //! //! \sa SCN_AUTOCSELECTION() void SCN_AUTOCCANCELLED(); //! This signal is emitted when the user deletes a character when an //! auto-completion list is active. void SCN_AUTOCCHARDELETED(); //! This signal is emitted after an auto-completion has inserted its text. //! \a selection is the text of the selection. \a position is the start //! position of the word being completed. \a ch is the fillup character //! that triggered the selection if method is SC_AC_FILLUP. \a method is //! the method used to trigger the selection. //! //! \sa SCN_AUTOCCANCELLED(), SCN_AUTOCSELECTION() void SCN_AUTOCCOMPLETED(const char *selection, int position, int ch, int method); //! This signal is emitted when the user selects an item in an //! auto-completion list. It is emitted before the selection is inserted. //! The insertion can be cancelled by sending an SCI_AUTOCANCEL message //! from a connected slot. //! \a selection is the text of the selection. \a position is the start //! position of the word being completed. \a ch is the fillup character //! that triggered the selection if method is SC_AC_FILLUP. \a method is //! the method used to trigger the selection. //! //! \sa SCN_AUTOCCANCELLED(), SCN_AUTOCCOMPLETED() void SCN_AUTOCSELECTION(const char *selection, int position, int ch, int method); //! \overload void SCN_AUTOCSELECTION(const char *selection, int position); //! This signal is emitted when the user highlights an item in an //! auto-completion or user list. //! \a selection is the text of the selection. \a id is an identifier for //! the list which was passed as an argument to the SCI_USERLISTSHOW //! message or 0 if the list is an auto-completion list. \a position is //! the position that the list was displayed at. void SCN_AUTOCSELECTIONCHANGE(const char *selection, int id, int position); //! This signal is emitted when the document has changed for any reason. void SCEN_CHANGE(); //! This signal is emitted when the user clicks on a calltip. //! \a direction is 1 if the user clicked on the up arrow, 2 if the user //! clicked on the down arrow, and 0 if the user clicked elsewhere. void SCN_CALLTIPCLICK(int direction); //! This signal is emitted whenever the user enters an ordinary character //! into the text. //! \a charadded is the character. It can be used to decide to display a //! call tip or an auto-completion list. void SCN_CHARADDED(int charadded); //! This signal is emitted when the user double clicks. //! \a position is the position in the text where the click occured. //! \a line is the number of the line in the text where the click occured. //! \a modifiers is the logical or of the modifier keys that were pressed //! when the user double clicked. void SCN_DOUBLECLICK(int position, int line, int modifiers); //! This signal is emitted when the user moves the mouse (or presses a key) //! after keeping it in one position for the dwell period. //! \a position is the position in the text where the mouse dwells. //! \a x is the x-coordinate where the mouse dwells. \a y is the //! y-coordinate where the mouse dwells. //! //! \sa SCN_DWELLSTART, SCI_SETMOUSEDWELLTIME void SCN_DWELLEND(int position, int x, int y); //! This signal is emitted when the user keeps the mouse in one position //! for the dwell period. //! \a position is the position in the text where the mouse dwells. //! \a x is the x-coordinate where the mouse dwells. \a y is the //! y-coordinate where the mouse dwells. //! //! \sa SCN_DWELLEND, SCI_SETMOUSEDWELLTIME void SCN_DWELLSTART(int position, int x, int y); //! This signal is emitted when focus is received. void SCN_FOCUSIN(); //! This signal is emitted when focus is lost. void SCN_FOCUSOUT(); //! This signal is emitted when the user clicks on text in a style with the //! hotspot attribute set. //! \a position is the position in the text where the click occured. //! \a modifiers is the logical or of the modifier keys that were pressed //! when the user clicked. void SCN_HOTSPOTCLICK(int position, int modifiers); //! This signal is emitted when the user double clicks on text in a style //! with the hotspot attribute set. //! \a position is the position in the text where the double click occured. //! \a modifiers is the logical or of the modifier keys that were pressed //! when the user double clicked. void SCN_HOTSPOTDOUBLECLICK(int position, int modifiers); //! This signal is emitted when the user releases the mouse button on text //! in a style with the hotspot attribute set. //! \a position is the position in the text where the release occured. //! \a modifiers is the logical or of the modifier keys that were pressed //! when the user released the button. void SCN_HOTSPOTRELEASECLICK(int position, int modifiers); //! This signal is emitted when the user clicks on text that has an //! indicator. //! \a position is the position in the text where the click occured. //! \a modifiers is the logical or of the modifier keys that were pressed //! when the user clicked. void SCN_INDICATORCLICK(int position, int modifiers); //! This signal is emitted when the user releases the mouse button on text //! that has an indicator. //! \a position is the position in the text where the release occured. //! \a modifiers is the logical or of the modifier keys that were pressed //! when the user released. void SCN_INDICATORRELEASE(int position, int modifiers); //! This signal is emitted when a recordable editor command has been //! executed. void SCN_MACRORECORD(unsigned int, unsigned long, void *); //! This signal is emitted when the user clicks on a sensitive margin. //! \a position is the position of the start of the line against which the //! user clicked. //! \a modifiers is the logical or of the modifier keys that were pressed //! when the user clicked. //! \a margin is the number of the margin the user clicked in: 0, 1 or 2. //! //! \sa SCI_GETMARGINSENSITIVEN, SCI_SETMARGINSENSITIVEN void SCN_MARGINCLICK(int position, int modifiers, int margin); //! This signal is emitted when the user right-clicks on a sensitive //! margin. \a position is the position of the start of the line against //! which the user clicked. //! \a modifiers is the logical or of the modifier keys that were pressed //! when the user clicked. //! \a margin is the number of the margin the user clicked in: 0, 1 or 2. //! //! \sa SCI_GETMARGINSENSITIVEN, SCI_SETMARGINSENSITIVEN void SCN_MARGINRIGHTCLICK(int position, int modifiers, int margin); //! void SCN_MODIFIED(int, int, const char *, int, int, int, int, int, int, int); //! This signal is emitted when the user attempts to modify read-only //! text. void SCN_MODIFYATTEMPTRO(); //! void SCN_NEEDSHOWN(int, int); //! This signal is emitted when painting has been completed. It is useful //! to trigger some other change but to have the paint be done first to //! appear more reponsive to the user. void SCN_PAINTED(); //! This signal is emitted when the current state of the text no longer //! corresponds to the state of the text at the save point. //! //! \sa SCI_SETSAVEPOINT, SCN_SAVEPOINTREACHED() void SCN_SAVEPOINTLEFT(); //! This signal is emitted when the current state of the text corresponds //! to the state of the text at the save point. This allows feedback to be //! given to the user as to whether the text has been modified since it was //! last saved. //! //! \sa SCI_SETSAVEPOINT, SCN_SAVEPOINTLEFT() void SCN_SAVEPOINTREACHED(); //! This signal is emitted when a range of text needs to be syntax styled. //! The range is from the value returned by the SCI_GETENDSTYLED message //! and \a position. It is only emitted if the currently selected lexer is //! SCLEX_CONTAINER. //! //! \sa SCI_COLOURISE, SCI_GETENDSTYLED void SCN_STYLENEEDED(int position); //! This signal is emitted when a URI is dropped. //! \a url is the value of the URI. void SCN_URIDROPPED(const QUrl &url); //! This signal is emitted when either the text or styling of the text has //! changed or the selection range or scroll position has changed. //! \a updated contains the set of SC_UPDATE_* flags describing the changes //! since the signal was last emitted. void SCN_UPDATEUI(int updated); //! This signal is emitted when the user selects an item in a user list. //! \a selection is the text of the selection. \a id is an identifier for //! the list which was passed as an argument to the SCI_USERLISTSHOW //! message and must be at least 1. \a ch is the fillup character that //! triggered the selection if method is SC_AC_FILLUP. \a method is the //! method used to trigger the selection. \a position is the position that //! the list was displayed at. //! //! \sa SCI_USERLISTSHOW, SCN_AUTOCSELECTION() void SCN_USERLISTSELECTION(const char *selection, int id, int ch, int method, int position); //! \overload void SCN_USERLISTSELECTION(const char *selection, int id, int ch, int method); //! \overload void SCN_USERLISTSELECTION(const char *selection, int id); //! void SCN_ZOOM(); protected: //! Returns true if the contents of a MIME data object can be decoded and //! inserted into the document. It is called during drag and paste //! operations. //! \a source is the MIME data object. //! //! \sa fromMimeData(), toMimeData() virtual bool canInsertFromMimeData(const QMimeData *source) const; //! Returns the text of a MIME data object. It is called when a drag and //! drop is completed and when text is pasted from the clipboard. //! \a source is the MIME data object. On return \a rectangular is set if //! the text corresponds to a rectangular selection. //! //! \sa canInsertFromMimeData(), toMimeData() virtual QByteArray fromMimeData(const QMimeData *source, bool &rectangular) const; //! Returns a new MIME data object containing some text and whether it //! corresponds to a rectangular selection. It is called when a drag and //! drop is started and when the selection is copied to the clipboard. //! Ownership of the object is passed to the caller. \a text is the text. //! \a rectangular is set if the text corresponds to a rectangular //! selection. //! //! \sa canInsertFromMimeData(), fromMimeData() virtual QMimeData *toMimeData(const QByteArray &text, bool rectangular) const; //! \reimp virtual void changeEvent(QEvent *e); //! Re-implemented to handle the context menu. virtual void contextMenuEvent(QContextMenuEvent *e); //! Re-implemented to handle drag enters. virtual void dragEnterEvent(QDragEnterEvent *e); //! Re-implemented to handle drag leaves. virtual void dragLeaveEvent(QDragLeaveEvent *e); //! Re-implemented to handle drag moves. virtual void dragMoveEvent(QDragMoveEvent *e); //! Re-implemented to handle drops. virtual void dropEvent(QDropEvent *e); //! Re-implemented to tell Scintilla it has the focus. virtual void focusInEvent(QFocusEvent *e); //! Re-implemented to tell Scintilla it has lost the focus. virtual void focusOutEvent(QFocusEvent *e); //! Re-implemented to allow tabs to be entered as text. virtual bool focusNextPrevChild(bool next); //! Re-implemented to handle key presses. virtual void keyPressEvent(QKeyEvent *e); //! Re-implemented to handle composed characters. virtual void inputMethodEvent(QInputMethodEvent *event); virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; //! Re-implemented to handle mouse double-clicks. virtual void mouseDoubleClickEvent(QMouseEvent *e); //! Re-implemented to handle mouse moves. virtual void mouseMoveEvent(QMouseEvent *e); //! Re-implemented to handle mouse presses. virtual void mousePressEvent(QMouseEvent *e); //! Re-implemented to handle mouse releases. virtual void mouseReleaseEvent(QMouseEvent *e); //! Re-implemented to paint the viewport. virtual void paintEvent(QPaintEvent *e); //! Re-implemented to handle resizes. virtual void resizeEvent(QResizeEvent *e); //! \internal Re-implemented to handle scrolling. virtual void scrollContentsBy(int dx, int dy); //! \internal This helps to work around some Scintilla bugs. void setScrollBars(); //! \internal Qt4, Qt5 portability. typedef QByteArray ScintillaBytes; #define ScintillaBytesConstData(b) (b).constData() //! \internal Convert a QString to encoded bytes. ScintillaBytes textAsBytes(const QString &text) const; //! \internal Convert encoded bytes to a QString. QString bytesAsText(const char *bytes) const; //! \internal A helper for QsciScintilla::contextMenuEvent(). bool contextMenuNeeded(int x, int y) const; private slots: void handleVSb(int value); void handleHSb(int value); void handleSelection(); private: // This is needed to allow QsciScintillaQt to emit this class's signals. friend class QsciScintillaQt; QsciScintillaQt *sci; QPoint triple_click_at; QTimer triple_click; int preeditPos; int preeditNrBytes; QString preeditString; #if QT_VERSION >= 0x050000 bool clickCausedFocus; #endif void connectHorizontalScrollBar(); void connectVerticalScrollBar(); void acceptAction(QDropEvent *e); int eventModifiers(QMouseEvent *e); QsciScintillaBase(const QsciScintillaBase &); QsciScintillaBase &operator=(const QsciScintillaBase &); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscistyle.h000066400000000000000000000141221463772530400271220ustar00rootroot00000000000000// This module defines interface to the QsciStyle class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCISTYLE_H #define QSCISTYLE_H #include #include #include #include class QsciScintillaBase; //! \brief The QsciStyle class encapsulates all the attributes of a style. //! //! Each character of a document has an associated style which determines how //! the character is displayed, e.g. its font and color. A style is identified //! by a number. Lexers define styles for each of the language's features so //! that they are displayed differently. Some style numbers have hard-coded //! meanings, e.g. the style used for call tips. class QSCINTILLA_EXPORT QsciStyle { public: //! This enum defines the different ways the displayed case of the text can //! be changed. enum TextCase { //! The text is displayed as its original case. OriginalCase = 0, //! The text is displayed as upper case. UpperCase = 1, //! The text is displayed as lower case. LowerCase = 2 }; //! Constructs a QsciStyle instance for style number \a style. If \a style //! is negative then a new style number is automatically allocated if //! possible. If it is not possible then style() will return a negative //! value. //! //! \sa style() QsciStyle(int style = -1); //! Constructs a QsciStyle instance for style number \a style. If \a style //! is negative then a new style number is automatically allocated if //! possible. If it is not possible then style() will return a negative //! value. The styles description, color, paper color, font and //! end-of-line fill are set to \a description, \a color, \a paper, \a font //! and \a eolFill respectively. //! //! \sa style() QsciStyle(int style, const QString &description, const QColor &color, const QColor &paper, const QFont &font, bool eolFill = false); //! \internal Apply the style to a particular editor. void apply(QsciScintillaBase *sci) const; //! The style's number is set to \a style. //! //! \sa style() void setStyle(int style) {style_nr = style;} //! Returns the number of the style. This will be negative if the style is //! invalid. //! //! \sa setStyle() int style() const {return style_nr;} //! The style's description is set to \a description. //! //! \sa description() void setDescription(const QString &description) {style_description = description;} //! Returns the style's description. //! //! \sa setDescription() QString description() const {return style_description;} //! The style's foreground color is set to \a color. The default is taken //! from the application's default palette. //! //! \sa color() void setColor(const QColor &color); //! Returns the style's foreground color. //! //! \sa setColor() QColor color() const {return style_color;} //! The style's background color is set to \a paper. The default is taken //! from the application's default palette. //! //! \sa paper() void setPaper(const QColor &paper); //! Returns the style's background color. //! //! \sa setPaper() QColor paper() const {return style_paper;} //! The style's font is set to \a font. The default is the application's //! default font. //! //! \sa font() void setFont(const QFont &font); //! Returns the style's font. //! //! \sa setFont() QFont font() const {return style_font;} //! The style's end-of-line fill is set to \a fill. The default is false. //! //! \sa eolFill() void setEolFill(bool fill); //! Returns the style's end-of-line fill. //! //! \sa setEolFill() bool eolFill() const {return style_eol_fill;} //! The style's text case is set to \a text_case. The default is //! OriginalCase. //! //! \sa textCase() void setTextCase(TextCase text_case); //! Returns the style's text case. //! //! \sa setTextCase() TextCase textCase() const {return style_case;} //! The style's visibility is set to \a visible. The default is true. //! //! \sa visible() void setVisible(bool visible); //! Returns the style's visibility. //! //! \sa setVisible() bool visible() const {return style_visible;} //! The style's changeability is set to \a changeable. The default is //! true. //! //! \sa changeable() void setChangeable(bool changeable); //! Returns the style's changeability. //! //! \sa setChangeable() bool changeable() const {return style_changeable;} //! The style's sensitivity to mouse clicks is set to \a hotspot. The //! default is false. //! //! \sa hotspot() void setHotspot(bool hotspot); //! Returns the style's sensitivity to mouse clicks. //! //! \sa setHotspot() bool hotspot() const {return style_hotspot;} //! Refresh the style settings. void refresh(); private: int style_nr; QString style_description; QColor style_color; QColor style_paper; QFont style_font; bool style_eol_fill; TextCase style_case; bool style_visible; bool style_changeable; bool style_hotspot; void init(int style); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/Qsci/qscistyledtext.h000066400000000000000000000035521463772530400302000ustar00rootroot00000000000000// This module defines interface to the QsciStyledText class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef QSCISTYLEDTEXT_H #define QSCISTYLEDTEXT_H #include #include class QsciScintillaBase; class QsciStyle; //! \brief The QsciStyledText class is a container for a piece of text and the //! style used to display the text. class QSCINTILLA_EXPORT QsciStyledText { public: //! Constructs a QsciStyledText instance for text \a text and style number //! \a style. QsciStyledText(const QString &text, int style); //! Constructs a QsciStyledText instance for text \a text and style \a //! style. QsciStyledText(const QString &text, const QsciStyle &style); //! \internal Apply the style to a particular editor. void apply(QsciScintillaBase *sci) const; //! Returns a reference to the text. const QString &text() const {return styled_text;} //! Returns the number of the style. int style() const; private: QString styled_text; int style_nr; const QsciStyle *explicit_style; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/SciAccessibility.cpp000066400000000000000000000536661463772530400300040ustar00rootroot00000000000000// The implementation of the class that implements accessibility support. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include #if !defined(QT_NO_ACCESSIBILITY) #include "SciAccessibility.h" #include #include #include #include #include #include "Qsci/qsciscintillabase.h" // Set if the accessibility support needs initialising. bool QsciAccessibleScintillaBase::needs_initialising = true; // The list of all accessibles. QList QsciAccessibleScintillaBase::all_accessibles; // Forward declarations. static QAccessibleInterface *factory(const QString &classname, QObject *object); // The ctor. QsciAccessibleScintillaBase::QsciAccessibleScintillaBase(QWidget *widget) : QAccessibleWidget(widget, QAccessible::EditableText), current_cursor_offset(-1), is_selection(false) { all_accessibles.append(this); } // The dtor. QsciAccessibleScintillaBase::~QsciAccessibleScintillaBase() { all_accessibles.removeOne(this); } // Initialise the accessibility support. void QsciAccessibleScintillaBase::initialise() { if (needs_initialising) { QAccessible::installFactory(factory); needs_initialising = false; } } // Find the accessible for a widget. QsciAccessibleScintillaBase *QsciAccessibleScintillaBase::findAccessible( QsciScintillaBase *sb) { for (int i = 0; i < all_accessibles.size(); ++i) { QsciAccessibleScintillaBase *acc_sb = all_accessibles.at(i); if (acc_sb->sciWidget() == sb) return acc_sb; } return 0; } // Return the QsciScintillaBase instance. QsciScintillaBase *QsciAccessibleScintillaBase::sciWidget() const { return static_cast(widget()); } // Update the accessible when the selection has changed. void QsciAccessibleScintillaBase::selectionChanged(QsciScintillaBase *sb, bool selection) { QsciAccessibleScintillaBase *acc_sb = findAccessible(sb); if (!acc_sb) return; acc_sb->is_selection = selection; } // Update the accessibility when text has been inserted. void QsciAccessibleScintillaBase::textInserted(QsciScintillaBase *sb, int position, const char *text, int length) { Q_ASSERT(text); QString new_text = bytesAsText(sb, text, length); int offset = positionAsOffset(sb, position); QAccessibleTextInsertEvent ev(sb, offset, new_text); QAccessible::updateAccessibility(&ev); } // Return the fragment of text before an offset. QString QsciAccessibleScintillaBase::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const { QsciScintillaBase *sb = sciWidget(); // Initialise in case of errors. *startOffset = *endOffset = -1; int position = validPosition(offset); if (position < 0) return QString(); int start_position, end_position; if (!boundaries(sb, position, boundaryType, &start_position, &end_position)) return QString(); if (start_position == 0) return QString(); if (!boundaries(sb, start_position - 1, boundaryType, &start_position, &end_position)) return QString(); positionRangeAsOffsetRange(sb, start_position, end_position, startOffset, endOffset); return textRange(sb, start_position, end_position); } // Return the fragment of text after an offset. QString QsciAccessibleScintillaBase::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const { QsciScintillaBase *sb = sciWidget(); // Initialise in case of errors. *startOffset = *endOffset = -1; int position = validPosition(offset); if (position < 0) return QString(); int start_position, end_position; if (!boundaries(sb, position, boundaryType, &start_position, &end_position)) return QString(); if (end_position >= sb->SendScintilla(QsciScintillaBase::SCI_GETTEXTLENGTH)) return QString(); if (!boundaries(sb, end_position, boundaryType, &start_position, &end_position)) return QString(); positionRangeAsOffsetRange(sb, start_position, end_position, startOffset, endOffset); return textRange(sb, start_position, end_position); } // Return the fragment of text at an offset. QString QsciAccessibleScintillaBase::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const { QsciScintillaBase *sb = sciWidget(); // Initialise in case of errors. *startOffset = *endOffset = -1; int position = validPosition(offset); if (position < 0) return QString(); int start_position, end_position; if (!boundaries(sb, position, boundaryType, &start_position, &end_position)) return QString(); positionRangeAsOffsetRange(sb, start_position, end_position, startOffset, endOffset); return textRange(sb, start_position, end_position); } // Update the accessibility when text has been deleted. void QsciAccessibleScintillaBase::textDeleted(QsciScintillaBase *sb, int position, const char *text, int length) { Q_ASSERT(text); QString old_text = bytesAsText(sb, text, length); int offset = positionAsOffset(sb, position); QAccessibleTextRemoveEvent ev(sb, offset, old_text); QAccessible::updateAccessibility(&ev); } // Update the accessibility when the UI has been updated. void QsciAccessibleScintillaBase::updated(QsciScintillaBase *sb) { QsciAccessibleScintillaBase *acc_sb = findAccessible(sb); if (!acc_sb) return; int cursor_offset = positionAsOffset(sb, sb->SendScintilla(QsciScintillaBase::SCI_GETCURRENTPOS)); if (acc_sb->current_cursor_offset != cursor_offset) { acc_sb->current_cursor_offset = cursor_offset; QAccessibleTextCursorEvent ev(sb, cursor_offset); QAccessible::updateAccessibility(&ev); } } // Return a valid position from an offset or -1 if it was invalid. int QsciAccessibleScintillaBase::validPosition(int offset) const { // An offset of -1 is interpreted as the length of the text. int nr_chars = characterCount(); if (offset == -1) offset = nr_chars; // Check there is some text and the offset is within range. if (nr_chars == 0 || offset < 0 || offset > nr_chars) return -1; return offsetAsPosition(sciWidget(), offset); } // Get the start and end boundary positions for a type of boundary. true is // returned if the boundary positions are valid. bool QsciAccessibleScintillaBase::boundaries(QsciScintillaBase *sb, int position, QAccessible::TextBoundaryType boundaryType, int *start_position, int *end_position) { // This implementation is based on what Qt does although that may itself be // wrong. The cursor is in a word if it is before or after any character // in the word. If the cursor is not in a word (eg. is has a space each // side) then the previous word is current. switch (boundaryType) { case QAccessible::CharBoundary: *start_position = position; *end_position = sb->SendScintilla( QsciScintillaBase::SCI_POSITIONAFTER, position); break; case QAccessible::WordBoundary: *start_position = sb->SendScintilla( QsciScintillaBase::SCI_WORDSTARTPOSITION, position, 1); *end_position = sb->SendScintilla( QsciScintillaBase::SCI_WORDENDPOSITION, position, 1); // If the start and end positions are the same then we are not in a // word. if (*start_position == *end_position) { // We need the immediately preceding word. Note that Qt behaves // differently as it will not move before the current line. // Find the end of the preceding word. *end_position = sb->SendScintilla( QsciScintillaBase::SCI_WORDSTARTPOSITION, position, 0L); // If the end is 0 then there isn't a preceding word. if (*end_position == 0) return false; // Now find the start. *start_position = sb->SendScintilla( QsciScintillaBase::SCI_WORDSTARTPOSITION, *end_position, 1); } break; case QAccessible::SentenceBoundary: return false; case QAccessible::ParagraphBoundary: // Paragraph boundaries are supposed to be supported but it isn't clear // what this means in a code editor. return false; case QAccessible::LineBoundary: { int line = sb->SendScintilla( QsciScintillaBase::SCI_LINEFROMPOSITION, position); *start_position = sb->SendScintilla( QsciScintillaBase::SCI_POSITIONFROMLINE, line); *end_position = sb->SendScintilla( QsciScintillaBase::SCI_POSITIONFROMLINE, line + 1); // See if we are after the last end-of-line character. if (*start_position == *end_position) return false; } break; case QAccessible::NoBoundary: *start_position = 0; *end_position = sb->SendScintilla( QsciScintillaBase::SCI_GETTEXTLENGTH); break; } return true; } // Return the text between two positions. QString QsciAccessibleScintillaBase::textRange(QsciScintillaBase *sb, int start_position, int end_position) { QByteArray bytes(end_position - start_position + 1, '\0'); sb->SendScintilla(QsciScintillaBase::SCI_GETTEXTRANGE, start_position, end_position, bytes.data()); return bytesAsText(sb, bytes.constData(), bytes.size() - 1); } // Convert bytes to text. QString QsciAccessibleScintillaBase::bytesAsText(QsciScintillaBase *sb, const char *bytes, int length) { if (sb->SendScintilla(QsciScintillaBase::SCI_GETCODEPAGE) == QsciScintillaBase::SC_CP_UTF8) return QString::fromUtf8(bytes, length); return QString::fromLatin1(bytes, length); } // Convert text to bytes. QByteArray QsciAccessibleScintillaBase::textAsBytes(QsciScintillaBase *sb, const QString &text) { if (sb->SendScintilla(QsciScintillaBase::SCI_GETCODEPAGE) == QsciScintillaBase::SC_CP_UTF8) return text.toUtf8(); return text.toLatin1(); } // Convert a byte position to a character offset. int QsciAccessibleScintillaBase::positionAsOffset(QsciScintillaBase *sb, int position) { return sb->SendScintilla(QsciScintillaBase::SCI_COUNTCHARACTERS, 0, position); } // Convert a range of byte poisitions to character offsets. void QsciAccessibleScintillaBase::positionRangeAsOffsetRange( QsciScintillaBase *sb, int start_position, int end_position, int *startOffset, int *endOffset) { *startOffset = positionAsOffset(sb, start_position); *endOffset = positionAsOffset(sb, end_position); } // Convert character offset position to a byte position. int QsciAccessibleScintillaBase::offsetAsPosition(QsciScintillaBase *sb, int offset) { return sb->SendScintilla(QsciScintillaBase::SCI_POSITIONRELATIVE, 0, offset); } // Get the current selection if any. void QsciAccessibleScintillaBase::selection(int selectionIndex, int *startOffset, int *endOffset) const { int start, end; if (selectionIndex == 0 && is_selection) { QsciScintillaBase *sb = sciWidget(); int start_position = sb->SendScintilla( QsciScintillaBase::SCI_GETSELECTIONSTART); int end_position = sb->SendScintilla( QsciScintillaBase::SCI_GETSELECTIONEND); start = positionAsOffset(sb, start_position); end = positionAsOffset(sb, end_position); } else { start = end = 0; } *startOffset = start; *endOffset = end; } // Return the number of selections. int QsciAccessibleScintillaBase::selectionCount() const { return (is_selection ? 1 : 0); } // Add a selection. void QsciAccessibleScintillaBase::addSelection(int startOffset, int endOffset) { setSelection(0, startOffset, endOffset); } // Remove a selection. void QsciAccessibleScintillaBase::removeSelection(int selectionIndex) { if (selectionIndex == 0) sciWidget()->SendScintilla(QsciScintillaBase::SCI_CLEARSELECTIONS); } // Set the selection. void QsciAccessibleScintillaBase::setSelection(int selectionIndex, int startOffset, int endOffset) { if (selectionIndex == 0) { QsciScintillaBase *sb = sciWidget(); sb->SendScintilla(QsciScintillaBase::SCI_SETSELECTIONSTART, offsetAsPosition(sb, startOffset)); sb->SendScintilla(QsciScintillaBase::SCI_SETSELECTIONEND, offsetAsPosition(sb, endOffset)); } } // Return the current cursor offset. int QsciAccessibleScintillaBase::cursorPosition() const { return current_cursor_offset; } // Set the cursor offset. void QsciAccessibleScintillaBase::setCursorPosition(int position) { QsciScintillaBase *sb = sciWidget(); sb->SendScintilla(QsciScintillaBase::SCI_GOTOPOS, offsetAsPosition(sb, position)); } // Return the text between two offsets. QString QsciAccessibleScintillaBase::text(int startOffset, int endOffset) const { QsciScintillaBase *sb = sciWidget(); return textRange(sb, offsetAsPosition(sb, startOffset), offsetAsPosition(sb, endOffset)); } // Return the number of characters in the text. int QsciAccessibleScintillaBase::characterCount() const { QsciScintillaBase *sb = sciWidget(); return sb->SendScintilla(QsciScintillaBase::SCI_COUNTCHARACTERS, 0, sb->SendScintilla(QsciScintillaBase::SCI_GETTEXTLENGTH)); } QRect QsciAccessibleScintillaBase::characterRect(int offset) const { QsciScintillaBase *sb = sciWidget(); int position = offsetAsPosition(sb, offset); int x_vport = sb->SendScintilla(QsciScintillaBase::SCI_POINTXFROMPOSITION, position); int y_vport = sb->SendScintilla(QsciScintillaBase::SCI_POINTYFROMPOSITION, position); const QString ch = text(offset, offset + 1); // Get the character's font metrics. int style = sb->SendScintilla(QsciScintillaBase::SCI_GETSTYLEAT, position); QFontMetrics metrics(fontForStyle(style)); QRect rect(x_vport, y_vport, metrics.width(ch), metrics.height()); rect.moveTo(sb->viewport()->mapToGlobal(rect.topLeft())); return rect; } // Return the offset of the character at the given screen coordinates. int QsciAccessibleScintillaBase::offsetAtPoint(const QPoint &point) const { QsciScintillaBase *sb = sciWidget(); QPoint p = sb->viewport()->mapFromGlobal(point); int position = sb->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMPOINT, p.x(), p.y()); return (position >= 0) ? positionAsOffset(sb, position) : -1; } // Scroll to make sure an area of text is visible. void QsciAccessibleScintillaBase::scrollToSubstring(int startIndex, int endIndex) { QsciScintillaBase *sb = sciWidget(); int start = offsetAsPosition(sb, startIndex); int end = offsetAsPosition(sb, endIndex); sb->SendScintilla(QsciScintillaBase::SCI_SCROLLRANGE, end, start); } // Return the attributes of a character and surrounding text. QString QsciAccessibleScintillaBase::attributes(int offset, int *startOffset, int *endOffset) const { QsciScintillaBase *sb = sciWidget(); int position = offsetAsPosition(sb, offset); int style = sb->SendScintilla(QsciScintillaBase::SCI_GETSTYLEAT, position); // Find the start of the text with this style. int start_position = position; int start_text_position = offset; while (start_position > 0) { int before = sb->SendScintilla(QsciScintillaBase::SCI_POSITIONBEFORE, start_position); int s = sb->SendScintilla(QsciScintillaBase::SCI_GETSTYLEAT, before); if (s != style) break; start_position = before; --start_text_position; } *startOffset = start_text_position; // Find the end of the text with this style. int end_position = sb->SendScintilla(QsciScintillaBase::SCI_POSITIONAFTER, position); int end_text_position = offset + 1; int last_position = sb->SendScintilla( QsciScintillaBase::SCI_GETTEXTLENGTH); while (end_position < last_position) { int s = sb->SendScintilla(QsciScintillaBase::SCI_GETSTYLEAT, end_position); if (s != style) break; end_position = sb->SendScintilla(QsciScintillaBase::SCI_POSITIONAFTER, end_position); ++end_text_position; } *endOffset = end_text_position; // Convert the style to attributes. QString attrs; int back = sb->SendScintilla(QsciScintillaBase::SCI_STYLEGETBACK, style); addAttribute(attrs, "background-color", colourAsRGB(back)); int fore = sb->SendScintilla(QsciScintillaBase::SCI_STYLEGETFORE, style); addAttribute(attrs, "color", colourAsRGB(fore)); QFont font = fontForStyle(style); QString family = font.family(); family = family.replace('\\', QLatin1String("\\\\")); family = family.replace(':', QLatin1String("\\:")); family = family.replace(',', QLatin1String("\\,")); family = family.replace('=', QLatin1String("\\=")); family = family.replace(';', QLatin1String("\\;")); family = family.replace('\"', QLatin1String("\\\"")); addAttribute(attrs, "font-familly", QLatin1Char('"') + family + QLatin1Char('"')); int font_size = int(font.pointSize()); addAttribute(attrs, "font-size", QString::fromLatin1("%1pt").arg(font_size)); QFont::Style font_style = font.style(); addAttribute(attrs, "font-style", QString::fromLatin1((font_style == QFont::StyleItalic) ? "italic" : ((font_style == QFont::StyleOblique) ? "oblique": "normal"))); int font_weight = font.weight(); addAttribute(attrs, "font-weight", QString::fromLatin1( (font_weight > QFont::Normal) ? "bold" : "normal")); int underline = sb->SendScintilla(QsciScintillaBase::SCI_STYLEGETUNDERLINE, style); if (underline) addAttribute(attrs, "text-underline-type", QString::fromLatin1("single")); return attrs; } // Add an attribute name/value pair. void QsciAccessibleScintillaBase::addAttribute(QString &attrs, const char *name, const QString &value) { attrs.append(QLatin1String(name)); attrs.append(QChar(':')); attrs.append(value); attrs.append(QChar(';')); } // Convert a integer colour to an RGB string. QString QsciAccessibleScintillaBase::colourAsRGB(int colour) { return QString::fromLatin1("rgb(%1,%2,%3)").arg(colour & 0xff).arg((colour >> 8) & 0xff).arg((colour >> 16) & 0xff); } // Convert a integer colour to an RGB string. QFont QsciAccessibleScintillaBase::fontForStyle(int style) const { QsciScintillaBase *sb = sciWidget(); char fontName[64]; int len = sb->SendScintilla(QsciScintillaBase::SCI_STYLEGETFONT, style, fontName); int size = sb->SendScintilla(QsciScintillaBase::SCI_STYLEGETSIZE, style); bool italic = sb->SendScintilla(QsciScintillaBase::SCI_STYLEGETITALIC, style); int weight = sb->SendScintilla(QsciScintillaBase::SCI_STYLEGETWEIGHT, style); return QFont(QString::fromUtf8(fontName, len), size, weight, italic); } // Delete some text. void QsciAccessibleScintillaBase::deleteText(int startOffset, int endOffset) { addSelection(startOffset, endOffset); sciWidget()->SendScintilla(QsciScintillaBase::SCI_REPLACESEL, ""); } // Insert some text. void QsciAccessibleScintillaBase::insertText(int offset, const QString &text) { QsciScintillaBase *sb = sciWidget(); sb->SendScintilla(QsciScintillaBase::SCI_INSERTTEXT, offsetAsPosition(sb, offset), textAsBytes(sb, text).constData()); } // Replace some text. void QsciAccessibleScintillaBase::replaceText(int startOffset, int endOffset, const QString &text) { QsciScintillaBase *sb = sciWidget(); addSelection(startOffset, endOffset); sb->SendScintilla(QsciScintillaBase::SCI_REPLACESEL, textAsBytes(sb, text).constData()); } // Return the state. QAccessible::State QsciAccessibleScintillaBase::state() const { QAccessible::State st = QAccessibleWidget::state(); st.selectableText = true; st.multiLine = true; if (sciWidget()->SendScintilla(QsciScintillaBase::SCI_GETREADONLY)) st.readOnly = true; else st.editable = true; return st; } // Provide access to the indivual interfaces. void *QsciAccessibleScintillaBase::interface_cast(QAccessible::InterfaceType t) { if (t == QAccessible::TextInterface) return static_cast(this); if (t == QAccessible::EditableTextInterface) return static_cast(this); return QAccessibleWidget::interface_cast(t); } // The accessibility interface factory. static QAccessibleInterface *factory(const QString &classname, QObject *object) { if (classname == QLatin1String("QsciScintillaBase") && object && object->isWidgetType()) return new QsciAccessibleScintillaBase(static_cast(object)); return 0; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/SciAccessibility.h000066400000000000000000000110321463772530400274260ustar00rootroot00000000000000// The definition of the class that implements accessibility support. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef _SCIACCESSIBILITY_H #define _SCIACCESSIBILITY_H #include #if !defined(QT_NO_ACCESSIBILITY) #include #include #include #include #include #include #include #include class QsciScintillaBase; // The implementation of accessibility support. class QsciAccessibleScintillaBase : public QAccessibleWidget, public QAccessibleTextInterface, public QAccessibleEditableTextInterface { public: explicit QsciAccessibleScintillaBase(QWidget *widget); ~QsciAccessibleScintillaBase(); static void initialise(); static void selectionChanged(QsciScintillaBase *sb, bool selection); static void textInserted(QsciScintillaBase *sb, int position, const char *text, int length); static void textDeleted(QsciScintillaBase *sb, int position, const char *text, int length); static void updated(QsciScintillaBase *sb); void selection(int selectionIndex, int *startOffset, int *endOffset) const; int selectionCount() const; void addSelection(int startOffset, int endOffset); void removeSelection(int selectionIndex); void setSelection(int selectionIndex, int startOffset, int endOffset); int cursorPosition() const; void setCursorPosition(int position); QString text(int startOffset, int endOffset) const; QString textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const; QString textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const; QString textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const; int characterCount() const; QRect characterRect(int offset) const; int offsetAtPoint(const QPoint &point) const; void scrollToSubstring(int startIndex, int endIndex); QString attributes(int offset, int *startOffset, int *endOffset) const; void deleteText(int startOffset, int endOffset); void insertText(int offset, const QString &text); void replaceText(int startOffset, int endOffset, const QString &text); QAccessible::State state() const; void *interface_cast(QAccessible::InterfaceType t); private: static bool needs_initialising; static QList all_accessibles; int current_cursor_offset; bool is_selection; static QsciAccessibleScintillaBase *findAccessible(QsciScintillaBase *sb); QsciScintillaBase *sciWidget() const; int validPosition(int offset) const; static bool boundaries(QsciScintillaBase *sb, int position, QAccessible::TextBoundaryType boundaryType, int *start_position, int *end_position); static QString textRange(QsciScintillaBase *sb, int start_position, int end_position); static QString bytesAsText(QsciScintillaBase *sb, const char *bytes, int length); static QByteArray textAsBytes(QsciScintillaBase *sb, const QString &text); static int positionAsOffset(QsciScintillaBase *sb, int position); static void positionRangeAsOffsetRange(QsciScintillaBase *sb, int start_position, int end_position, int *startOffset, int *endOffset); static int offsetAsPosition(QsciScintillaBase *sb, int offset); static QString colourAsRGB(int colour); static void addAttribute(QString &attrs, const char *name, const QString &value); QFont fontForStyle(int style) const; }; #endif #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/SciClasses.cpp000066400000000000000000000113601463772530400265730ustar00rootroot00000000000000// The implementation of various Qt version independent classes used by the // rest of the port. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "SciClasses.h" #include #include #include #include #include #include #include "ScintillaQt.h" #include "ListBoxQt.h" // Create a call tip. QsciSciCallTip::QsciSciCallTip(QWidget *parent, QsciScintillaQt *sci_) : QWidget(parent, Qt::WindowFlags(Qt::Popup|Qt::FramelessWindowHint|Qt::WA_StaticContents)), sci(sci_) { // Ensure that the main window keeps the focus (and the caret flashing) // when this is displayed. setFocusProxy(parent); } // Destroy a call tip. QsciSciCallTip::~QsciSciCallTip() { // Ensure that the main window doesn't receive a focus out event when // this is destroyed. setFocusProxy(0); } // Paint a call tip. void QsciSciCallTip::paintEvent(QPaintEvent *) { Scintilla::Surface *surfaceWindow = Scintilla::Surface::Allocate( SC_TECHNOLOGY_DEFAULT); if (!surfaceWindow) return; QPainter p(this); surfaceWindow->Init(&p); surfaceWindow->SetUnicodeMode(sci->CodePage() == SC_CP_UTF8); sci->ct.PaintCT(surfaceWindow); delete surfaceWindow; } // Handle a mouse press in a call tip. void QsciSciCallTip::mousePressEvent(QMouseEvent *e) { Scintilla::Point pt; pt.x = e->x(); pt.y = e->y(); sci->ct.MouseClick(pt); sci->CallTipClick(); update(); } // Create the popup instance. QsciSciPopup::QsciSciPopup() { // Set up the mapper. connect(&mapper, SIGNAL(mapped(int)), this, SLOT(on_triggered(int))); } // Add an item and associated command to the popup and enable it if required. void QsciSciPopup::addItem(const QString &label, int cmd, bool enabled, QsciScintillaQt *sci_) { QAction *act = addAction(label, &mapper, SLOT(map())); mapper.setMapping(act, cmd); act->setEnabled(enabled); sci = sci_; } // A slot to handle a menu action being triggered. void QsciSciPopup::on_triggered(int cmd) { sci->Command(cmd); } QsciSciListBox::QsciSciListBox(QWidget *parent, QsciListBoxQt *lbx_) : QListWidget(parent), lbx(lbx_) { setAttribute(Qt::WA_StaticContents); #if defined(Q_OS_WIN) setWindowFlags(Qt::Tool|Qt::FramelessWindowHint); // This stops the main widget losing focus when the user clicks on this one // (which prevents this one being destroyed). setFocusPolicy(Qt::NoFocus); #else // This is the root of the focus problems under Gnome's window manager. We // have tried many flag combinations in the past. The consensus now seems // to be that the following works. However it might now work because of a // change in Qt so we only enable it for recent versions in order to // reduce the risk of breaking something that works with earlier versions. #if QT_VERSION >= 0x040500 setWindowFlags(Qt::ToolTip|Qt::WindowStaysOnTopHint); #else setWindowFlags(Qt::Tool|Qt::FramelessWindowHint); #endif // This may not be needed. setFocusProxy(parent); #endif setFrameShape(StyledPanel); setFrameShadow(Plain); } QsciSciListBox::~QsciSciListBox() { // Ensure that the main widget doesn't get a focus out event when this is // destroyed. setFocusProxy(0); } void QsciSciListBox::addItemPixmap(const QPixmap &pm, const QString &txt) { new QListWidgetItem(pm, txt, this); } int QsciSciListBox::find(const QString &prefix) { QList itms = findItems(prefix, Qt::MatchStartsWith|Qt::MatchCaseSensitive); if (itms.size() == 0) return -1; return row(itms[0]); } QString QsciSciListBox::text(int n) { QListWidgetItem *itm = item(n); if (!itm) return QString(); return itm->text(); } void QsciSciListBox::mouseDoubleClickEvent(QMouseEvent *) { lbx->handleDoubleClick(); } void QsciSciListBox::mouseReleaseEvent(QMouseEvent *) { lbx->handleRelease(); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/SciClasses.h000066400000000000000000000052641463772530400262460ustar00rootroot00000000000000// The definition of various Qt version independent classes used by the rest of // the port. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef _SCICLASSES_H #define _SCICLASSES_H #include #include #include #include #include class QsciScintillaQt; class QsciListBoxQt; // A simple QWidget sub-class to implement a call tip. This is not put into // the Scintilla namespace because of moc's problems with preprocessor macros. class QsciSciCallTip : public QWidget { Q_OBJECT public: QsciSciCallTip(QWidget *parent, QsciScintillaQt *sci_); ~QsciSciCallTip(); protected: void paintEvent(QPaintEvent *e); void mousePressEvent(QMouseEvent *e); private: QsciScintillaQt *sci; }; // A popup menu where options correspond to a numeric command. This is not put // into the Scintilla namespace because of moc's problems with preprocessor // macros. class QsciSciPopup : public QMenu { Q_OBJECT public: QsciSciPopup(); void addItem(const QString &label, int cmd, bool enabled, QsciScintillaQt *sci_); private slots: void on_triggered(int cmd); private: QsciScintillaQt *sci; QSignalMapper mapper; }; // This sub-class of QListBox is needed to provide slots from which we can call // QsciListBox's double-click callback (and you thought this was a C++ // program). This is not put into the Scintilla namespace because of moc's // problems with preprocessor macros. class QsciSciListBox : public QListWidget { Q_OBJECT public: QsciSciListBox(QWidget *parent, QsciListBoxQt *lbx_); virtual ~QsciSciListBox(); void addItemPixmap(const QPixmap &pm, const QString &txt); int find(const QString &prefix); QString text(int n); protected: void mouseDoubleClickEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); private: QsciListBoxQt *lbx; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/SciNamespace.h000066400000000000000000000024371463772530400265440ustar00rootroot00000000000000// Support for building the Scintilla code in the Scintilla namespace using the // -DSCI_NAMESPACE compiler flag. // // Copyright (c) 2018 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef _SCINAMESPACE_H #define _SCINAMESPACE_H #ifdef SCI_NAMESPACE #define QSCI_SCI_NAMESPACE(name) Scintilla::name #define QSCI_BEGIN_SCI_NAMESPACE namespace Scintilla { #define QSCI_END_SCI_NAMESPACE }; #else #define QSCI_SCI_NAMESPACE(name) name #define QSCI_BEGIN_SCI_NAMESPACE #define QSCI_END_SCI_NAMESPACE #endif #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/ScintillaQt.cpp000066400000000000000000000453671463772530400270040ustar00rootroot00000000000000// The implementation of the Qt specific subclass of ScintillaBase. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include #include #include #include #include #include #include #include #include #include "Qsci/qsciscintillabase.h" #include "ScintillaQt.h" #if !defined(QT_NO_ACCESSIBILITY) #include "SciAccessibility.h" #endif #include "SciClasses.h" // We want to use the Scintilla notification names as Qt signal names. #undef SCEN_CHANGE #undef SCN_AUTOCCANCELLED #undef SCN_AUTOCCHARDELETED #undef SCN_AUTOCCOMPLETED #undef SCN_AUTOCSELECTION #undef SCN_AUTOCSELECTIONCHANGE #undef SCN_CALLTIPCLICK #undef SCN_CHARADDED #undef SCN_DOUBLECLICK #undef SCN_DWELLEND #undef SCN_DWELLSTART #undef SCN_FOCUSIN #undef SCN_FOCUSOUT #undef SCN_HOTSPOTCLICK #undef SCN_HOTSPOTDOUBLECLICK #undef SCN_HOTSPOTRELEASECLICK #undef SCN_INDICATORCLICK #undef SCN_INDICATORRELEASE #undef SCN_MACRORECORD #undef SCN_MARGINCLICK #undef SCN_MARGINRIGHTCLICK #undef SCN_MODIFIED #undef SCN_MODIFYATTEMPTRO #undef SCN_NEEDSHOWN #undef SCN_PAINTED #undef SCN_SAVEPOINTLEFT #undef SCN_SAVEPOINTREACHED #undef SCN_STYLENEEDED #undef SCN_UPDATEUI #undef SCN_USERLISTSELECTION #undef SCN_ZOOM enum { SCEN_CHANGE = 768, SCN_AUTOCCANCELLED = 2025, SCN_AUTOCCHARDELETED = 2026, SCN_AUTOCCOMPLETED = 2030, SCN_AUTOCSELECTION = 2022, SCN_AUTOCSELECTIONCHANGE = 2032, SCN_CALLTIPCLICK = 2021, SCN_CHARADDED = 2001, SCN_DOUBLECLICK = 2006, SCN_DWELLEND = 2017, SCN_DWELLSTART = 2016, SCN_FOCUSIN = 2028, SCN_FOCUSOUT = 2029, SCN_HOTSPOTCLICK = 2019, SCN_HOTSPOTDOUBLECLICK = 2020, SCN_HOTSPOTRELEASECLICK = 2027, SCN_INDICATORCLICK = 2023, SCN_INDICATORRELEASE = 2024, SCN_MACRORECORD = 2009, SCN_MARGINCLICK = 2010, SCN_MARGINRIGHTCLICK = 2031, SCN_MODIFIED = 2008, SCN_MODIFYATTEMPTRO = 2004, SCN_NEEDSHOWN = 2011, SCN_PAINTED = 2013, SCN_SAVEPOINTLEFT = 2003, SCN_SAVEPOINTREACHED = 2002, SCN_STYLENEEDED = 2000, SCN_UPDATEUI = 2007, SCN_USERLISTSELECTION = 2014, SCN_ZOOM = 2018 }; // The ctor. QsciScintillaQt::QsciScintillaQt(QsciScintillaBase *qsb_) : vMax(0), hMax(0), vPage(0), hPage(0), capturedMouse(false), qsb(qsb_) { wMain = qsb->viewport(); // This is ignored. imeInteraction = imeInline; // Using pixmaps screws things up when moving to a different display // (although this could be because we haven't got the pixmap code right). // However Qt shouldn't need buffered drawing anyway. WndProc(SCI_SETBUFFEREDDRAW, 0, 0); for (int i = 0; i <= static_cast(tickPlatform); ++i) timers[i] = 0; Initialise(); } // The dtor. QsciScintillaQt::~QsciScintillaQt() { Finalise(); } // Initialise the instance. void QsciScintillaQt::Initialise() { } // Tidy up the instance. void QsciScintillaQt::Finalise() { for (int i = 0; i <= static_cast(tickPlatform); ++i) FineTickerCancel(static_cast(i)); ScintillaBase::Finalise(); } // Start a drag. void QsciScintillaQt::StartDrag() { inDragDrop = ddDragging; QDrag *qdrag = new QDrag(qsb); qdrag->setMimeData(mimeSelection(drag)); #if QT_VERSION >= 0x040300 Qt::DropAction action = qdrag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction); #else Qt::DropAction action = qdrag->start(Qt::MoveAction); #endif // Remove the dragged text if it was a move to another widget or // application. if (action == Qt::MoveAction && qdrag->target() != qsb->viewport()) ClearSelection(); SetDragPosition(Scintilla::SelectionPosition()); inDragDrop = ddNone; } // Re-implement to trap certain messages. sptr_t QsciScintillaQt::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { switch (iMessage) { case SCI_GETDIRECTFUNCTION: return reinterpret_cast(DirectFunction); case SCI_GETDIRECTPOINTER: return reinterpret_cast(this); } return ScintillaBase::WndProc(iMessage, wParam, lParam); } // Windows nonsense. sptr_t QsciScintillaQt::DefWndProc(unsigned int, uptr_t, sptr_t) { return 0; } // Grab or release the mouse (and keyboard). void QsciScintillaQt::SetMouseCapture(bool on) { if (mouseDownCaptures) { if (on) qsb->viewport()->grabMouse(); else qsb->viewport()->releaseMouse(); } capturedMouse = on; } // Return true if the mouse/keyboard are currently grabbed. bool QsciScintillaQt::HaveMouseCapture() { return capturedMouse; } // Set the position of the vertical scrollbar. void QsciScintillaQt::SetVerticalScrollPos() { QScrollBar *sb = qsb->verticalScrollBar(); bool was_blocked = sb->blockSignals(true); sb->setValue(topLine); sb->blockSignals(was_blocked); } // Set the position of the horizontal scrollbar. void QsciScintillaQt::SetHorizontalScrollPos() { QScrollBar *sb = qsb->horizontalScrollBar(); bool was_blocked = sb->blockSignals(true); sb->setValue(xOffset); sb->blockSignals(was_blocked); } // Set the extent of the vertical and horizontal scrollbars and return true if // the view needs re-drawing. bool QsciScintillaQt::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) { bool modified = false; QScrollBar *sb; int vNewPage = nPage; int vNewMax = nMax - vNewPage + 1; if (vMax != vNewMax || vPage != vNewPage) { vMax = vNewMax; vPage = vNewPage; modified = true; sb = qsb->verticalScrollBar(); sb->setMaximum(vMax); sb->setPageStep(vPage); } int hNewPage = GetTextRectangle().Width(); int hNewMax = (scrollWidth > hNewPage) ? scrollWidth - hNewPage : 0; int charWidth = vs.styles[STYLE_DEFAULT].aveCharWidth; sb = qsb->horizontalScrollBar(); if (hMax != hNewMax || hPage != hNewPage || sb->singleStep() != charWidth) { hMax = hNewMax; hPage = hNewPage; modified = true; sb->setMaximum(hMax); sb->setPageStep(hPage); sb->setSingleStep(charWidth); } return modified; } // Called after SCI_SETWRAPMODE and SCI_SETHSCROLLBAR. void QsciScintillaQt::ReconfigureScrollBars() { // Hide or show the scrollbars if needed. bool hsb = (horizontalScrollBarVisible && !Wrapping()); qsb->setHorizontalScrollBarPolicy(hsb ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); qsb->setVerticalScrollBarPolicy(verticalScrollBarVisible ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); } // Notify interested parties of any change in the document. void QsciScintillaQt::NotifyChange() { emit qsb->SCEN_CHANGE(); } // Notify interested parties of various events. This is the main mapping // between Scintilla notifications and Qt signals. void QsciScintillaQt::NotifyParent(SCNotification scn) { switch (scn.nmhdr.code) { case SCN_CALLTIPCLICK: emit qsb->SCN_CALLTIPCLICK(scn.position); break; case SCN_AUTOCCANCELLED: emit qsb->SCN_AUTOCCANCELLED(); break; case SCN_AUTOCCHARDELETED: emit qsb->SCN_AUTOCCHARDELETED(); break; case SCN_AUTOCCOMPLETED: emit qsb->SCN_AUTOCCOMPLETED(scn.text, scn.position, scn.ch, scn.listCompletionMethod); break; case SCN_AUTOCSELECTION: emit qsb->SCN_AUTOCSELECTION(scn.text, scn.position, scn.ch, scn.listCompletionMethod); emit qsb->SCN_AUTOCSELECTION(scn.text, scn.position); break; case SCN_AUTOCSELECTIONCHANGE: emit qsb->SCN_AUTOCSELECTIONCHANGE(scn.text, scn.listType, scn.position); break; case SCN_CHARADDED: emit qsb->SCN_CHARADDED(scn.ch); break; case SCN_DOUBLECLICK: emit qsb->SCN_DOUBLECLICK(scn.position, scn.line, scn.modifiers); break; case SCN_DWELLEND: emit qsb->SCN_DWELLEND(scn.position, scn.x, scn.y); break; case SCN_DWELLSTART: emit qsb->SCN_DWELLSTART(scn.position, scn.x, scn.y); break; case SCN_FOCUSIN: emit qsb->SCN_FOCUSIN(); break; case SCN_FOCUSOUT: emit qsb->SCN_FOCUSOUT(); break; case SCN_HOTSPOTCLICK: emit qsb->SCN_HOTSPOTCLICK(scn.position, scn.modifiers); break; case SCN_HOTSPOTDOUBLECLICK: emit qsb->SCN_HOTSPOTDOUBLECLICK(scn.position, scn.modifiers); break; case SCN_HOTSPOTRELEASECLICK: emit qsb->SCN_HOTSPOTRELEASECLICK(scn.position, scn.modifiers); break; case SCN_INDICATORCLICK: emit qsb->SCN_INDICATORCLICK(scn.position, scn.modifiers); break; case SCN_INDICATORRELEASE: emit qsb->SCN_INDICATORRELEASE(scn.position, scn.modifiers); break; case SCN_MACRORECORD: emit qsb->SCN_MACRORECORD(scn.message, scn.wParam, reinterpret_cast(scn.lParam)); break; case SCN_MARGINCLICK: emit qsb->SCN_MARGINCLICK(scn.position, scn.modifiers, scn.margin); break; case SCN_MARGINRIGHTCLICK: emit qsb->SCN_MARGINRIGHTCLICK(scn.position, scn.modifiers, scn.margin); break; case SCN_MODIFIED: { char *text; #if !defined(QT_NO_ACCESSIBILITY) if ((scn.modificationType & SC_MOD_INSERTTEXT) != 0) QsciAccessibleScintillaBase::textInserted(qsb, scn.position, scn.text, scn.length); else if ((scn.modificationType & SC_MOD_DELETETEXT) != 0) QsciAccessibleScintillaBase::textDeleted(qsb, scn.position, scn.text, scn.length); #endif // Give some protection to the Python bindings. if (scn.text && (scn.modificationType & (SC_MOD_INSERTTEXT|SC_MOD_DELETETEXT)) != 0) { text = new char[scn.length + 1]; memcpy(text, scn.text, scn.length); text[scn.length] = '\0'; } else { text = 0; } emit qsb->SCN_MODIFIED(scn.position, scn.modificationType, text, scn.length, scn.linesAdded, scn.line, scn.foldLevelNow, scn.foldLevelPrev, scn.token, scn.annotationLinesAdded); if (text) delete[] text; break; } case SCN_MODIFYATTEMPTRO: emit qsb->SCN_MODIFYATTEMPTRO(); break; case SCN_NEEDSHOWN: emit qsb->SCN_NEEDSHOWN(scn.position, scn.length); break; case SCN_PAINTED: emit qsb->SCN_PAINTED(); break; case SCN_SAVEPOINTLEFT: emit qsb->SCN_SAVEPOINTLEFT(); break; case SCN_SAVEPOINTREACHED: emit qsb->SCN_SAVEPOINTREACHED(); break; case SCN_STYLENEEDED: emit qsb->SCN_STYLENEEDED(scn.position); break; case SCN_UPDATEUI: #if !defined(QT_NO_ACCESSIBILITY) QsciAccessibleScintillaBase::updated(qsb); #endif emit qsb->SCN_UPDATEUI(scn.updated); break; case SCN_USERLISTSELECTION: emit qsb->SCN_USERLISTSELECTION(scn.text, scn.listType, scn.ch, scn.listCompletionMethod, scn.position); emit qsb->SCN_USERLISTSELECTION(scn.text, scn.listType, scn.ch, scn.listCompletionMethod); emit qsb->SCN_USERLISTSELECTION(scn.text, scn.listType); break; case SCN_ZOOM: emit qsb->SCN_ZOOM(); break; default: qWarning("Unknown notification: %u", scn.nmhdr.code); } } // Convert a selection to mime data. QMimeData *QsciScintillaQt::mimeSelection( const Scintilla::SelectionText &text) const { return qsb->toMimeData(QByteArray(text.Data()), text.rectangular); } // Copy the selected text to the clipboard. void QsciScintillaQt::CopyToClipboard( const Scintilla::SelectionText &selectedText) { QApplication::clipboard()->setMimeData(mimeSelection(selectedText)); } // Implement copy. void QsciScintillaQt::Copy() { if (!sel.Empty()) { Scintilla::SelectionText text; CopySelectionRange(&text); CopyToClipboard(text); } } // Implement pasting text. void QsciScintillaQt::Paste() { pasteFromClipboard(QClipboard::Clipboard); } // Paste text from either the clipboard or selection. void QsciScintillaQt::pasteFromClipboard(QClipboard::Mode mode) { int len; const char *s; bool rectangular; const QMimeData *source = QApplication::clipboard()->mimeData(mode); if (!source || !qsb->canInsertFromMimeData(source)) return; QByteArray text = qsb->fromMimeData(source, rectangular); len = text.length(); s = text.data(); std::string dest = Scintilla::Document::TransformLineEnds(s, len, pdoc->eolMode); Scintilla::SelectionText selText; selText.Copy(dest, (IsUnicodeMode() ? SC_CP_UTF8 : 0), vs.styles[STYLE_DEFAULT].characterSet, rectangular, false); Scintilla::UndoGroup ug(pdoc); ClearSelection(); InsertPasteShape(selText.Data(), selText.Length(), selText.rectangular ? pasteRectangular : pasteStream); EnsureCaretVisible(); } // Create a call tip window. void QsciScintillaQt::CreateCallTipWindow(Scintilla::PRectangle rc) { if (!ct.wCallTip.Created()) ct.wCallTip = new QsciSciCallTip(qsb, this); QsciSciCallTip *w = reinterpret_cast(ct.wCallTip.GetID()); w->resize(rc.right - rc.left, rc.bottom - rc.top); ct.wCallTip.Show(); } // Add an item to the right button menu. void QsciScintillaQt::AddToPopUp(const char *label, int cmd, bool enabled) { QsciSciPopup *pm = static_cast(popup.GetID()); if (*label) pm->addItem(qApp->translate("ContextMenu", label), cmd, enabled, this); else pm->addSeparator(); } // Claim the selection. void QsciScintillaQt::ClaimSelection() { bool isSel = !sel.Empty(); if (isSel) { QClipboard *cb = QApplication::clipboard(); // If we support X11 style selection then make it available now. if (cb->supportsSelection()) { Scintilla::SelectionText text; CopySelectionRange(&text); if (text.Data()) cb->setMimeData(mimeSelection(text), QClipboard::Selection); } primarySelection = true; } else primarySelection = false; #if !defined(QT_NO_ACCESSIBILITY) QsciAccessibleScintillaBase::selectionChanged(qsb, isSel); #endif emit qsb->QSCN_SELCHANGED(isSel); } // Unclaim the selection. void QsciScintillaQt::UnclaimSelection() { if (primarySelection) { primarySelection = false; qsb->viewport()->update(); } } // Implemented to provide compatibility with the Windows version. sptr_t QsciScintillaQt::DirectFunction(QsciScintillaQt *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return sciThis->WndProc(iMessage,wParam,lParam); } // Draw the contents of the widget. void QsciScintillaQt::paintEvent(QPaintEvent *e) { Scintilla::Surface *sw; const QRect &qr = e->rect(); rcPaint.left = qr.left(); rcPaint.top = qr.top(); rcPaint.right = qr.right() + 1; rcPaint.bottom = qr.bottom() + 1; Scintilla::PRectangle rcClient = GetClientRectangle(); paintingAllText = rcPaint.Contains(rcClient); sw = Scintilla::Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (!sw) return; QPainter painter(qsb->viewport()); paintState = painting; sw->Init(&painter); sw->SetUnicodeMode(CodePage() == SC_CP_UTF8); Paint(sw, rcPaint); delete sw; // If the painting area was insufficient to cover the new style or brace // highlight positions then repaint the whole thing. if (paintState == paintAbandoned) { // Do a full re-paint immediately. This may only be needed on OS X (to // avoid flicker). paintingAllText = true; sw = Scintilla::Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (!sw) return; QPainter painter(qsb->viewport()); paintState = painting; sw->Init(&painter); sw->SetUnicodeMode(CodePage() == SC_CP_UTF8); Paint(sw, rcPaint); delete sw; qsb->viewport()->update(); } paintState = notPainting; } // Re-implemented to drive the tickers. void QsciScintillaQt::timerEvent(QTimerEvent *e) { for (int i = 0; i <= static_cast(tickPlatform); ++i) if (timers[i] == e->timerId()) TickFor(static_cast(i)); } // Re-implemented to say we support fine tickers. bool QsciScintillaQt::FineTickerAvailable() { return true; } // Re-implemented to stop a ticker. void QsciScintillaQt::FineTickerCancel(TickReason reason) { int &ticker = timers[static_cast(reason)]; if (ticker != 0) { killTimer(ticker); ticker = 0; } } // Re-implemented to check if a particular ticker is running. bool QsciScintillaQt::FineTickerRunning(TickReason reason) { return (timers[static_cast(reason)] != 0); } // Re-implemented to start a ticker. void QsciScintillaQt::FineTickerStart(TickReason reason, int ms, int) { int &ticker = timers[static_cast(reason)]; if (ticker != 0) killTimer(ticker); ticker = startTimer(ms); } // Re-implemented to support idle processing. bool QsciScintillaQt::SetIdle(bool on) { if (on) { if (!idler.state) { QTimer *timer = reinterpret_cast(idler.idlerID); if (!timer) { idler.idlerID = timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(onIdle())); } timer->start(0); idler.state = true; } } else if (idler.state) { reinterpret_cast(idler.idlerID)->stop(); idler.state = false; } return true; } // Invoked to trigger any idle processing. void QsciScintillaQt::onIdle() { if (!Idle()) SetIdle(false); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/ScintillaQt.h000066400000000000000000000101421463772530400264300ustar00rootroot00000000000000// The definition of the Qt specific subclass of ScintillaBase. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #ifndef SCINTILLAQT_H #define SCINTILLAQT_H #include #include #include // These are needed because Scintilla class header files don't manage their own // dependencies properly. #include #include #include #include #include #include #include #include #include #include "ILexer.h" #include "ILoader.h" #include "Platform.h" #include "Scintilla.h" #include "SplitVector.h" #include "Partitioning.h" #include "Position.h" #include "UniqueString.h" #include "CellBuffer.h" #include "CharClassify.h" #include "RunStyles.h" #include "CaseFolder.h" #include "Decoration.h" #include "Document.h" #include "Style.h" #include "XPM.h" #include "LineMarker.h" #include "Indicator.h" #include "ViewStyle.h" #include "KeyMap.h" #include "ContractionState.h" #include "Selection.h" #include "PositionCache.h" #include "EditModel.h" #include "MarginView.h" #include "EditView.h" #include "Editor.h" #include "AutoComplete.h" #include "CallTip.h" #include "LexAccessor.h" #include "Accessor.h" #include "ScintillaBase.h" QT_BEGIN_NAMESPACE class QMimeData; class QPaintEvent; QT_END_NAMESPACE class QsciScintillaBase; class QsciSciCallTip; class QsciSciPopup; // This is an internal class but it is referenced by a public class so it has // to have a Qsci prefix rather than being put in the Scintilla namespace. // (However the reason for avoiding this no longer applies.) class QsciScintillaQt : public QObject, public Scintilla::ScintillaBase { Q_OBJECT friend class QsciScintillaBase; friend class QsciSciCallTip; friend class QsciSciPopup; public: QsciScintillaQt(QsciScintillaBase *qsb_); virtual ~QsciScintillaQt(); virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); protected: void timerEvent(QTimerEvent *e); private slots: void onIdle(); private: void Initialise(); void Finalise(); bool SetIdle(bool on); void StartDrag(); sptr_t DefWndProc(unsigned int, uptr_t, sptr_t); void SetMouseCapture(bool on); bool HaveMouseCapture(); void SetVerticalScrollPos(); void SetHorizontalScrollPos(); bool ModifyScrollBars(Sci::Line nMax, Sci::Line nPage); void ReconfigureScrollBars(); void NotifyChange(); void NotifyParent(SCNotification scn); void CopyToClipboard(const Scintilla::SelectionText &selectedText); void Copy(); void Paste(); void CreateCallTipWindow(Scintilla::PRectangle rc); void AddToPopUp(const char *label, int cmd = 0, bool enabled = true); void ClaimSelection(); void UnclaimSelection(); static sptr_t DirectFunction(QsciScintillaQt *sci, unsigned int iMessage, uptr_t wParam,sptr_t lParam); QMimeData *mimeSelection(const Scintilla::SelectionText &text) const; void paintEvent(QPaintEvent *e); void pasteFromClipboard(QClipboard::Mode mode); // tickPlatform is the last of the TickReason members. int timers[tickPlatform + 1]; bool FineTickerAvailable(); void FineTickerCancel(TickReason reason); bool FineTickerRunning(TickReason reason); void FineTickerStart(TickReason reason, int ms, int tolerance); int vMax, hMax, vPage, hPage; bool capturedMouse; QsciScintillaBase *qsb; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/features/000077500000000000000000000000001463772530400256505ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/features/qscintilla2.prf000066400000000000000000000011041463772530400306020ustar00rootroot00000000000000greaterThan(QT_MAJOR_VERSION, 4) { QT += widgets printsupport greaterThan(QT_MINOR_VERSION, 1) { macx:QT += macextras } } DEFINES += QSCINTILLA_DLL INCLUDEPATH += $$[QT_INSTALL_HEADERS] LIBS += -L$$[QT_INSTALL_LIBS] CONFIG(debug, debug|release) { mac: { LIBS += -lqscintilla2_qt$${QT_MAJOR_VERSION}_debug } else { win32: { LIBS += -lqscintilla2_qt$${QT_MAJOR_VERSION}d } else { LIBS += -lqscintilla2_qt$${QT_MAJOR_VERSION} } } } else { LIBS += -lqscintilla2_qt$${QT_MAJOR_VERSION} } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qsciabstractapis.cpp000066400000000000000000000026171463772530400301040ustar00rootroot00000000000000// This module implements the QsciAbstractAPIs class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qsciabstractapis.h" #include "Qsci/qscilexer.h" // The ctor. QsciAbstractAPIs::QsciAbstractAPIs(QsciLexer *lexer) : QObject(lexer), lex(lexer) { lexer->setAPIs(this); } // The dtor. QsciAbstractAPIs::~QsciAbstractAPIs() { } // Return the lexer. QsciLexer *QsciAbstractAPIs::lexer() const { return lex; } // Called when the user has made a selection from the auto-completion list. void QsciAbstractAPIs::autoCompletionSelected(const QString &selection) { Q_UNUSED(selection); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qsciapis.cpp000066400000000000000000000605611463772530400263620ustar00rootroot00000000000000// This module implements the QsciAPIs class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include #include "Qsci/qsciapis.h" #include #include #include #include #include #include #include #include #include #include "Qsci/qscilexer.h" // The version number of the prepared API information format. const unsigned char PreparedDataFormatVersion = 0; // This class contains prepared API information. struct QsciAPIsPrepared { // The word dictionary is a map of individual words and a list of positions // each occurs in the sorted list of APIs. A position is a tuple of the // index into the list of APIs and the index into the particular API. QMap wdict; // The case dictionary maps the case insensitive words to the form in which // they are to be used. It is only used if the language is case // insensitive. QMap cdict; // The raw API information. QStringList raw_apis; QStringList apiWords(int api_idx, const QStringList &wseps, bool strip_image) const; static QString apiBaseName(const QString &api); }; // Return a particular API entry as a list of words. QStringList QsciAPIsPrepared::apiWords(int api_idx, const QStringList &wseps, bool strip_image) const { QString base = apiBaseName(raw_apis[api_idx]); // Remove any embedded image reference if necessary. if (strip_image) { int tail = base.indexOf('?'); if (tail >= 0) base.truncate(tail); } if (wseps.isEmpty()) return QStringList(base); return base.split(wseps.first()); } // Return the name of an API function, ie. without the arguments. QString QsciAPIsPrepared::apiBaseName(const QString &api) { QString base = api; int tail = base.indexOf('('); if (tail >= 0) base.truncate(tail); return base.simplified(); } // The user event type that signals that the worker thread has started. const QEvent::Type WorkerStarted = static_cast(QEvent::User + 1012); // The user event type that signals that the worker thread has finished. const QEvent::Type WorkerFinished = static_cast(QEvent::User + 1013); // The user event type that signals that the worker thread has aborted. const QEvent::Type WorkerAborted = static_cast(QEvent::User + 1014); // This class is the worker thread that post-processes the API set. class QsciAPIsWorker : public QThread { public: QsciAPIsWorker(QsciAPIs *apis); virtual ~QsciAPIsWorker(); virtual void run(); QsciAPIsPrepared *prepared; private: QsciAPIs *proxy; bool abort; }; // The worker thread ctor. QsciAPIsWorker::QsciAPIsWorker(QsciAPIs *apis) : prepared(0), proxy(apis), abort(false) { } // The worker thread dtor. QsciAPIsWorker::~QsciAPIsWorker() { // Tell the thread to stop. There is no need to bother with a mutex. abort = true; // Wait for it to do so and hit it if it doesn't. if (!wait(500)) terminate(); if (prepared) delete prepared; } // The worker thread entry point. void QsciAPIsWorker::run() { // Sanity check. if (!prepared) return; // Tell the main thread we have started. QApplication::postEvent(proxy, new QEvent(WorkerStarted)); // Sort the full list. prepared->raw_apis.sort(); QStringList wseps = proxy->lexer()->autoCompletionWordSeparators(); bool cs = proxy->lexer()->caseSensitive(); // Split each entry into separate words but ignoring any arguments. for (int a = 0; a < prepared->raw_apis.count(); ++a) { // Check to see if we should stop. if (abort) break; QStringList words = prepared->apiWords(a, wseps, true); for (int w = 0; w < words.count(); ++w) { const QString &word = words[w]; // Add the word's position to any existing list for this word. QsciAPIs::WordIndexList wil = prepared->wdict[word]; // If the language is case insensitive and we haven't seen this // word before then save it in the case dictionary. if (!cs && wil.count() == 0) prepared->cdict[word.toUpper()] = word; wil.append(QsciAPIs::WordIndex(a, w)); prepared->wdict[word] = wil; } } // Tell the main thread we have finished. QApplication::postEvent(proxy, new QEvent(abort ? WorkerAborted : WorkerFinished)); } // The ctor. QsciAPIs::QsciAPIs(QsciLexer *lexer) : QsciAbstractAPIs(lexer), worker(0), origin_len(0) { prep = new QsciAPIsPrepared; } // The dtor. QsciAPIs::~QsciAPIs() { deleteWorker(); delete prep; } // Delete the worker thread if there is one. void QsciAPIs::deleteWorker() { if (worker) { delete worker; worker = 0; } } //! Handle termination events from the worker thread. bool QsciAPIs::event(QEvent *e) { switch (e->type()) { case WorkerStarted: emit apiPreparationStarted(); return true; case WorkerAborted: deleteWorker(); emit apiPreparationCancelled(); return true; case WorkerFinished: delete prep; old_context.clear(); prep = worker->prepared; worker->prepared = 0; deleteWorker(); // Allow the raw API information to be modified. apis = prep->raw_apis; emit apiPreparationFinished(); return true; default: break; } return QObject::event(e); } // Clear the current raw API entries. void QsciAPIs::clear() { apis.clear(); } // Clear out all API information. bool QsciAPIs::load(const QString &filename) { QFile f(filename); if (!f.open(QIODevice::ReadOnly)) return false; QTextStream ts(&f); for (;;) { QString line = ts.readLine(); if (line.isEmpty()) break; apis.append(line); } return true; } // Add a single API entry. void QsciAPIs::add(const QString &entry) { apis.append(entry); } // Remove a single API entry. void QsciAPIs::remove(const QString &entry) { int idx = apis.indexOf(entry); if (idx >= 0) apis.removeAt(idx); } // Position the "origin" cursor into the API entries according to the user // supplied context. QStringList QsciAPIs::positionOrigin(const QStringList &context, QString &path) { // Get the list of words and see if the context is the same as last time we // were called. QStringList new_context; bool same_context = (old_context.count() > 0 && old_context.count() < context.count()); for (int i = 0; i < context.count(); ++i) { QString word = context[i]; if (!lexer()->caseSensitive()) word = word.toUpper(); if (i < old_context.count() && old_context[i] != word) same_context = false; new_context << word; } // If the context has changed then reset the origin. if (!same_context) origin_len = 0; // If we have a current origin (ie. the user made a specific selection in // the current context) then adjust the origin to include the last complete // word as the user may have entered more parts of the name without using // auto-completion. if (origin_len > 0) { const QString wsep = lexer()->autoCompletionWordSeparators().first(); int start_new = old_context.count(); int end_new = new_context.count() - 1; if (start_new == end_new) { path = old_context.join(wsep); origin_len = path.length(); } else { QString fixed = *origin; fixed.truncate(origin_len); path = fixed; while (start_new < end_new) { // Add this word to the current path. path.append(wsep); path.append(new_context[start_new]); origin_len = path.length(); // Skip entries in the current origin that don't match the // path. while (origin != prep->raw_apis.end()) { // See if the current origin has come to an end. if (!originStartsWith(fixed, wsep)) origin = prep->raw_apis.end(); else if (originStartsWith(path, wsep)) break; else ++origin; } if (origin == prep->raw_apis.end()) break; ++start_new; } } // Terminate the path. path.append(wsep); // If the new text wasn't recognised then reset the origin. if (origin == prep->raw_apis.end()) origin_len = 0; } if (origin_len == 0) path.truncate(0); // Save the "committed" context for next time. old_context = new_context; old_context.removeLast(); return new_context; } // Return true if the origin starts with the given path. bool QsciAPIs::originStartsWith(const QString &path, const QString &wsep) { const QString &orig = *origin; if (!orig.startsWith(path)) return false; // Check that the path corresponds to the end of a word, ie. that what // follows in the origin is either a word separator or a (. QString tail = orig.mid(path.length()); return (!tail.isEmpty() && (tail.startsWith(wsep) || tail.at(0) == '(')); } // Add auto-completion words to an existing list. void QsciAPIs::updateAutoCompletionList(const QStringList &context, QStringList &list) { QString path; QStringList new_context = positionOrigin(context, path); if (origin_len > 0) { const QString wsep = lexer()->autoCompletionWordSeparators().first(); QStringList::const_iterator it = origin; unambiguous_context = path; while (it != prep->raw_apis.end()) { QString base = QsciAPIsPrepared::apiBaseName(*it); if (!base.startsWith(path)) break; // Make sure we have something after the path. if (base != path) { // Get the word we are interested in (ie. the one after the // current origin in path). QString w = base.mid(origin_len + wsep.length()).split(wsep).first(); // Append the space, we know the origin is unambiguous. w.append(' '); if (!list.contains(w)) list << w; } ++it; } } else { // At the moment we assume we will add words from multiple contexts so // mark the unambiguous context as unknown. unambiguous_context = QString(); bool unambig = true; QStringList with_context; if (new_context.last().isEmpty()) lastCompleteWord(new_context[new_context.count() - 2], with_context, unambig); else lastPartialWord(new_context.last(), with_context, unambig); for (int i = 0; i < with_context.count(); ++i) { // Remove any unambigious context (allowing for a possible image // identifier). QString noc = with_context[i]; if (unambig) { int op = noc.indexOf(QLatin1String(" (")); if (op >= 0) { int cl = noc.indexOf(QLatin1String(")")); if (cl > op) noc.remove(op, cl - op + 1); else noc.truncate(op); } } list << noc; } } } // Get the index list for a particular word if there is one. const QsciAPIs::WordIndexList *QsciAPIs::wordIndexOf(const QString &word) const { QString csword; // Indirect through the case dictionary if the language isn't case // sensitive. if (lexer()->caseSensitive()) csword = word; else { csword = prep->cdict[word]; if (csword.isEmpty()) return 0; } // Get the possible API entries if any. const WordIndexList *wl = &prep->wdict[csword]; if (wl->isEmpty()) return 0; return wl; } // Add auto-completion words based on the last complete word entered. void QsciAPIs::lastCompleteWord(const QString &word, QStringList &with_context, bool &unambig) { // Get the possible API entries if any. const WordIndexList *wl = wordIndexOf(word); if (wl) addAPIEntries(*wl, true, with_context, unambig); } // Add auto-completion words based on the last partial word entered. void QsciAPIs::lastPartialWord(const QString &word, QStringList &with_context, bool &unambig) { if (lexer()->caseSensitive()) { QMap::const_iterator it = prep->wdict.lowerBound(word); while (it != prep->wdict.end()) { if (!it.key().startsWith(word)) break; addAPIEntries(it.value(), false, with_context, unambig); ++it; } } else { QMap::const_iterator it = prep->cdict.lowerBound(word); while (it != prep->cdict.end()) { if (!it.key().startsWith(word)) break; addAPIEntries(prep->wdict[it.value()], false, with_context, unambig); ++it; } } } // Handle the selection of an entry in the auto-completion list. void QsciAPIs::autoCompletionSelected(const QString &selection) { // If the selection is an API (ie. it has a space separating the selected // word and the optional origin) then remember the origin. QStringList lst = selection.split(' '); if (lst.count() != 2) { origin_len = 0; return; } const QString &path = lst[1]; QString owords; if (path.isEmpty()) owords = unambiguous_context; else { // Check the parenthesis. if (!path.startsWith("(") || !path.endsWith(")")) { origin_len = 0; return; } // Remove the parenthesis. owords = path.mid(1, path.length() - 2); } origin = qLowerBound(prep->raw_apis, owords); /* * There is a bug somewhere, either in qLowerBound() or QList (or in GCC as * it seems to be Linux specific and the Qt code is the same on all * platforms) that the following line seems to fix. Note that it is * actually the call to detach() within begin() that is the important bit. */ prep->raw_apis.begin(); origin_len = owords.length(); } // Add auto-completion words for a particular word (defined by where it appears // in the APIs) and depending on whether the word was complete (when it's // actually the next word in the API entry that is of interest) or not. void QsciAPIs::addAPIEntries(const WordIndexList &wl, bool complete, QStringList &with_context, bool &unambig) { QStringList wseps = lexer()->autoCompletionWordSeparators(); for (int w = 0; w < wl.count(); ++w) { const WordIndex &wi = wl[w]; QStringList api_words = prep->apiWords(wi.first, wseps, false); int idx = wi.second; if (complete) { // Skip if this is the last word. if (++idx >= api_words.count()) continue; } QString api_word, org; if (idx == 0) { api_word = api_words[0] + ' '; org = QString::fromLatin1(""); } else { QStringList orgl = api_words.mid(0, idx); org = orgl.join(wseps.first()); // Add the context (allowing for a possible image identifier). QString w = api_words[idx]; QString type; int type_idx = w.indexOf(QLatin1String("?")); if (type_idx >= 0) { type = w.mid(type_idx); w.truncate(type_idx); } api_word = QString("%1 (%2)%3").arg(w).arg(org).arg(type); } // If the origin is different to the context then the context is // ambiguous. if (unambig) { if (unambiguous_context.isNull()) { unambiguous_context = org; } else if (unambiguous_context != org) { unambiguous_context.truncate(0); unambig = false; } } if (!with_context.contains(api_word)) with_context.append(api_word); } } // Return the call tip for a function. QStringList QsciAPIs::callTips(const QStringList &context, int commas, QsciScintilla::CallTipsStyle style, QList &shifts) { QString path; QStringList new_context = positionOrigin(context, path); QStringList wseps = lexer()->autoCompletionWordSeparators(); QStringList cts; if (origin_len > 0) { // The path should have a trailing word separator. const QString &wsep = wseps.first(); path.chop(wsep.length()); QStringList::const_iterator it = origin; QString prev; // Work out the length of the context. QStringList strip = path.split(wsep); strip.removeLast(); int ctstart = strip.join(wsep).length(); if (ctstart) ctstart += wsep.length(); int shift; if (style == QsciScintilla::CallTipsContext) { shift = ctstart; ctstart = 0; } else shift = 0; // Make sure we only look at the functions we are interested in. path.append('('); while (it != prep->raw_apis.end() && (*it).startsWith(path)) { QString w = (*it).mid(ctstart); if (w != prev && enoughCommas(w, commas)) { shifts << shift; cts << w; prev = w; } ++it; } } else { const QString &fname = new_context[new_context.count() - 2]; // Find everywhere the function name appears in the APIs. const WordIndexList *wil = wordIndexOf(fname); if (wil) for (int i = 0; i < wil->count(); ++i) { const WordIndex &wi = (*wil)[i]; QStringList awords = prep->apiWords(wi.first, wseps, true); // Check the word is the function name and not part of any // context. if (wi.second != awords.count() - 1) continue; const QString &api = prep->raw_apis[wi.first]; int tail = api.indexOf('('); if (tail < 0) continue; if (!enoughCommas(api, commas)) continue; if (style == QsciScintilla::CallTipsNoContext) { shifts << 0; cts << (fname + api.mid(tail)); } else { shifts << tail - fname.length(); // Remove any image type. int im_type = api.indexOf('?'); if (im_type <= 0) cts << api; else cts << (api.left(im_type - 1) + api.mid(tail)); } } } return cts; } // Return true if a string has enough commas in the argument list. bool QsciAPIs::enoughCommas(const QString &s, int commas) { int end = s.indexOf(')'); if (end < 0) return false; QString w = s.left(end); return (w.count(',') >= commas); } // Ensure the list is ready. void QsciAPIs::prepare() { // Handle the trivial case. if (worker) return; QsciAPIsPrepared *new_apis = new QsciAPIsPrepared; new_apis->raw_apis = apis; worker = new QsciAPIsWorker(this); worker->prepared = new_apis; worker->start(); } // Cancel any current preparation. void QsciAPIs::cancelPreparation() { deleteWorker(); } // Check that a prepared API file exists. bool QsciAPIs::isPrepared(const QString &filename) const { QString pname = prepName(filename); if (pname.isEmpty()) return false; QFileInfo fi(pname); return fi.exists(); } // Load the prepared API information. bool QsciAPIs::loadPrepared(const QString &filename) { QString pname = prepName(filename); if (pname.isEmpty()) return false; // Read the prepared data and decompress it. QFile pf(pname); if (!pf.open(QIODevice::ReadOnly)) return false; QByteArray cpdata = pf.readAll(); pf.close(); if (cpdata.count() == 0) return false; QByteArray pdata = qUncompress(cpdata); // Extract the data. QDataStream pds(pdata); unsigned char vers; pds >> vers; if (vers > PreparedDataFormatVersion) return false; char *lex_name; pds >> lex_name; if (qstrcmp(lex_name, lexer()->lexer()) != 0) { delete[] lex_name; return false; } delete[] lex_name; prep->wdict.clear(); pds >> prep->wdict; if (!lexer()->caseSensitive()) { // Build up the case dictionary. prep->cdict.clear(); QMap::const_iterator it = prep->wdict.begin(); while (it != prep->wdict.end()) { prep->cdict[it.key().toUpper()] = it.key(); ++it; } } prep->raw_apis.clear(); pds >> prep->raw_apis; // Allow the raw API information to be modified. apis = prep->raw_apis; return true; } // Save the prepared API information. bool QsciAPIs::savePrepared(const QString &filename) const { QString pname = prepName(filename, true); if (pname.isEmpty()) return false; // Write the prepared data to a memory buffer. QByteArray pdata; QDataStream pds(&pdata, QIODevice::WriteOnly); // Use a serialisation format supported by Qt v3.0 and later. pds.setVersion(QDataStream::Qt_3_0); pds << PreparedDataFormatVersion; pds << lexer()->lexer(); pds << prep->wdict; pds << prep->raw_apis; // Compress the data and write it. QFile pf(pname); if (!pf.open(QIODevice::WriteOnly|QIODevice::Truncate)) return false; if (pf.write(qCompress(pdata)) < 0) { pf.close(); return false; } pf.close(); return true; } // Return the name of the default prepared API file. QString QsciAPIs::defaultPreparedName() const { return prepName(QString()); } // Return the name of a prepared API file. QString QsciAPIs::prepName(const QString &filename, bool mkpath) const { // Handle the tivial case. if (!filename.isEmpty()) return filename; QString pdname; char *qsci = getenv("QSCIDIR"); if (qsci) pdname = qsci; else { static const char *qsci_dir = ".qsci"; QDir pd = QDir::home(); if (mkpath && !pd.exists(qsci_dir) && !pd.mkdir(qsci_dir)) return QString(); pdname = pd.filePath(qsci_dir); } return QString("%1/%2.pap").arg(pdname).arg(lexer()->lexer()); } // Return installed API files. QStringList QsciAPIs::installedAPIFiles() const { QString qtdir = QLibraryInfo::location(QLibraryInfo::DataPath); QDir apidir = QDir(QString("%1/qsci/api/%2").arg(qtdir).arg(lexer()->lexer())); QStringList filenames; QStringList filters; filters << "*.api"; QFileInfoList flist = apidir.entryInfoList(filters, QDir::Files, QDir::IgnoreCase); foreach (QFileInfo fi, flist) filenames << fi.absoluteFilePath(); return filenames; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscicommand.cpp000066400000000000000000000065021463772530400270370ustar00rootroot00000000000000// This module implements the QsciCommand class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscicommand.h" #include #include #include "Qsci/qsciscintilla.h" #include "Qsci/qsciscintillabase.h" static int convert(int key); // The ctor. QsciCommand::QsciCommand(QsciScintilla *qs, QsciCommand::Command cmd, int key, int altkey, const char *desc) : qsCmd(qs), scicmd(cmd), qkey(key), qaltkey(altkey), descCmd(desc) { scikey = convert(qkey); if (scikey) qsCmd->SendScintilla(QsciScintillaBase::SCI_ASSIGNCMDKEY, scikey, scicmd); scialtkey = convert(qaltkey); if (scialtkey) qsCmd->SendScintilla(QsciScintillaBase::SCI_ASSIGNCMDKEY, scialtkey, scicmd); } // Execute the command. void QsciCommand::execute() { qsCmd->SendScintilla(scicmd); } // Bind a key to a command. void QsciCommand::setKey(int key) { bindKey(key,qkey,scikey); } // Bind an alternate key to a command. void QsciCommand::setAlternateKey(int altkey) { bindKey(altkey,qaltkey,scialtkey); } // Do the hard work of binding a key. void QsciCommand::bindKey(int key,int &qk,int &scik) { int new_scikey; // Ignore if it is invalid, allowing for the fact that we might be // unbinding it. if (key) { new_scikey = convert(key); if (!new_scikey) return; } else new_scikey = 0; if (scik) qsCmd->SendScintilla(QsciScintillaBase::SCI_CLEARCMDKEY, scik); qk = key; scik = new_scikey; if (scik) qsCmd->SendScintilla(QsciScintillaBase::SCI_ASSIGNCMDKEY, scik, scicmd); } // See if a key is valid. bool QsciCommand::validKey(int key) { return convert(key); } // Convert a Qt character to the Scintilla equivalent. Return zero if it is // invalid. static int convert(int key) { // Convert the modifiers. int sci_mod = 0; if (key & Qt::SHIFT) sci_mod |= QsciScintillaBase::SCMOD_SHIFT; if (key & Qt::CTRL) sci_mod |= QsciScintillaBase::SCMOD_CTRL; if (key & Qt::ALT) sci_mod |= QsciScintillaBase::SCMOD_ALT; if (key & Qt::META) sci_mod |= QsciScintillaBase::SCMOD_META; key &= ~Qt::MODIFIER_MASK; // Convert the key. int sci_key = QsciScintillaBase::commandKey(key, sci_mod); if (sci_key) sci_key |= (sci_mod << 16); return sci_key; } // Return the translated user friendly description. QString QsciCommand::description() const { return qApp->translate("QsciCommand", descCmd); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscicommandset.cpp000066400000000000000000000655721463772530400275670ustar00rootroot00000000000000// This module implements the QsciCommandSet class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscicommandset.h" #include #include "Qsci/qscicommand.h" #include "Qsci/qsciscintilla.h" #include "Qsci/qsciscintillabase.h" // Starting with QScintilla v2.7 the standard OS/X keyboard shortcuts are used // where possible. In order to restore the behaviour of earlier versions then // #define DONT_USE_OSX_KEYS here or add it to the qmake project (.pro) file. #if defined(Q_OS_MAC) && !defined(DONT_USE_OSX_KEYS) #define USING_OSX_KEYS #else #undef USING_OSX_KEYS #endif // The ctor. QsciCommandSet::QsciCommandSet(QsciScintilla *qs) : qsci(qs) { struct sci_cmd { QsciCommand::Command cmd; int key; int altkey; const char *desc; }; static struct sci_cmd cmd_table[] = { { QsciCommand::LineDown, Qt::Key_Down, #if defined(USING_OSX_KEYS) Qt::Key_N | Qt::META, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Move down one line") }, { QsciCommand::LineDownExtend, Qt::Key_Down | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_N | Qt::META | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend selection down one line") }, { QsciCommand::LineDownRectExtend, Qt::Key_Down | Qt::ALT | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_N | Qt::META | Qt::ALT | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend rectangular selection down one line") }, { QsciCommand::LineScrollDown, Qt::Key_Down | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Scroll view down one line") }, { QsciCommand::LineUp, Qt::Key_Up, #if defined(USING_OSX_KEYS) Qt::Key_P | Qt::META, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Move up one line") }, { QsciCommand::LineUpExtend, Qt::Key_Up | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_P | Qt::META | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend selection up one line") }, { QsciCommand::LineUpRectExtend, Qt::Key_Up | Qt::ALT | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_P | Qt::META | Qt::ALT | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend rectangular selection up one line") }, { QsciCommand::LineScrollUp, Qt::Key_Up | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Scroll view up one line") }, { QsciCommand::ScrollToStart, #if defined(USING_OSX_KEYS) Qt::Key_Home, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Scroll to start of document") }, { QsciCommand::ScrollToEnd, #if defined(USING_OSX_KEYS) Qt::Key_End, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Scroll to end of document") }, { QsciCommand::VerticalCentreCaret, #if defined(USING_OSX_KEYS) Qt::Key_L | Qt::META, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Scroll vertically to centre current line") }, { QsciCommand::ParaDown, Qt::Key_BracketRight | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move down one paragraph") }, { QsciCommand::ParaDownExtend, Qt::Key_BracketRight | Qt::CTRL | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection down one paragraph") }, { QsciCommand::ParaUp, Qt::Key_BracketLeft | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move up one paragraph") }, { QsciCommand::ParaUpExtend, Qt::Key_BracketLeft | Qt::CTRL | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection up one paragraph") }, { QsciCommand::CharLeft, Qt::Key_Left, #if defined(USING_OSX_KEYS) Qt::Key_B | Qt::META, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Move left one character") }, { QsciCommand::CharLeftExtend, Qt::Key_Left | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_B | Qt::META | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend selection left one character") }, { QsciCommand::CharLeftRectExtend, Qt::Key_Left | Qt::ALT | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_B | Qt::META | Qt::ALT | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend rectangular selection left one character") }, { QsciCommand::CharRight, Qt::Key_Right, #if defined(USING_OSX_KEYS) Qt::Key_F | Qt::META, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Move right one character") }, { QsciCommand::CharRightExtend, Qt::Key_Right | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_F | Qt::META | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend selection right one character") }, { QsciCommand::CharRightRectExtend, Qt::Key_Right | Qt::ALT | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_F | Qt::META | Qt::ALT | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend rectangular selection right one character") }, { QsciCommand::WordLeft, #if defined(USING_OSX_KEYS) Qt::Key_Left | Qt::ALT, #else Qt::Key_Left | Qt::CTRL, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move left one word") }, { QsciCommand::WordLeftExtend, #if defined(USING_OSX_KEYS) Qt::Key_Left | Qt::ALT | Qt::SHIFT, #else Qt::Key_Left | Qt::CTRL | Qt::SHIFT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection left one word") }, { QsciCommand::WordRight, #if defined(USING_OSX_KEYS) 0, #else Qt::Key_Right | Qt::CTRL, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move right one word") }, { QsciCommand::WordRightExtend, Qt::Key_Right | Qt::CTRL | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection right one word") }, { QsciCommand::WordLeftEnd, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to end of previous word") }, { QsciCommand::WordLeftEndExtend, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to end of previous word") }, { QsciCommand::WordRightEnd, #if defined(USING_OSX_KEYS) Qt::Key_Right | Qt::ALT, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to end of next word") }, { QsciCommand::WordRightEndExtend, #if defined(USING_OSX_KEYS) Qt::Key_Right | Qt::ALT | Qt::SHIFT, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to end of next word") }, { QsciCommand::WordPartLeft, Qt::Key_Slash | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move left one word part") }, { QsciCommand::WordPartLeftExtend, Qt::Key_Slash | Qt::CTRL | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection left one word part") }, { QsciCommand::WordPartRight, Qt::Key_Backslash | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move right one word part") }, { QsciCommand::WordPartRightExtend, Qt::Key_Backslash | Qt::CTRL | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection right one word part") }, { QsciCommand::Home, #if defined(USING_OSX_KEYS) Qt::Key_A | Qt::META, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to start of document line") }, { QsciCommand::HomeExtend, #if defined(USING_OSX_KEYS) Qt::Key_A | Qt::META | Qt::SHIFT, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to start of document line") }, { QsciCommand::HomeRectExtend, #if defined(USING_OSX_KEYS) Qt::Key_A | Qt::META | Qt::ALT | Qt::SHIFT, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend rectangular selection to start of document line") }, { QsciCommand::HomeDisplay, #if defined(USING_OSX_KEYS) Qt::Key_Left | Qt::CTRL, #else Qt::Key_Home | Qt::ALT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to start of display line") }, { QsciCommand::HomeDisplayExtend, #if defined(USING_OSX_KEYS) Qt::Key_Left | Qt::CTRL | Qt::SHIFT, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to start of display line") }, { QsciCommand::HomeWrap, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to start of display or document line") }, { QsciCommand::HomeWrapExtend, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to start of display or document line") }, { QsciCommand::VCHome, #if defined(USING_OSX_KEYS) 0, #else Qt::Key_Home, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to first visible character in document line") }, { QsciCommand::VCHomeExtend, #if defined(USING_OSX_KEYS) 0, #else Qt::Key_Home | Qt::SHIFT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to first visible character in document line") }, { QsciCommand::VCHomeRectExtend, #if defined(USING_OSX_KEYS) 0, #else Qt::Key_Home | Qt::ALT | Qt::SHIFT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend rectangular selection to first visible character in document line") }, { QsciCommand::VCHomeWrap, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to first visible character of display in document line") }, { QsciCommand::VCHomeWrapExtend, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to first visible character in display or document line") }, { QsciCommand::LineEnd, #if defined(USING_OSX_KEYS) Qt::Key_E | Qt::META, #else Qt::Key_End, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to end of document line") }, { QsciCommand::LineEndExtend, #if defined(USING_OSX_KEYS) Qt::Key_E | Qt::META | Qt::SHIFT, #else Qt::Key_End | Qt::SHIFT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to end of document line") }, { QsciCommand::LineEndRectExtend, #if defined(USING_OSX_KEYS) Qt::Key_E | Qt::META | Qt::ALT | Qt::SHIFT, #else Qt::Key_End | Qt::ALT | Qt::SHIFT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend rectangular selection to end of document line") }, { QsciCommand::LineEndDisplay, #if defined(USING_OSX_KEYS) Qt::Key_Right | Qt::CTRL, #else Qt::Key_End | Qt::ALT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to end of display line") }, { QsciCommand::LineEndDisplayExtend, #if defined(USING_OSX_KEYS) Qt::Key_Right | Qt::CTRL | Qt::SHIFT, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to end of display line") }, { QsciCommand::LineEndWrap, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to end of display or document line") }, { QsciCommand::LineEndWrapExtend, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to end of display or document line") }, { QsciCommand::DocumentStart, #if defined(USING_OSX_KEYS) Qt::Key_Up | Qt::CTRL, #else Qt::Key_Home | Qt::CTRL, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to start of document") }, { QsciCommand::DocumentStartExtend, #if defined(USING_OSX_KEYS) Qt::Key_Up | Qt::CTRL | Qt::SHIFT, #else Qt::Key_Home | Qt::CTRL | Qt::SHIFT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to start of document") }, { QsciCommand::DocumentEnd, #if defined(USING_OSX_KEYS) Qt::Key_Down | Qt::CTRL, #else Qt::Key_End | Qt::CTRL, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Move to end of document") }, { QsciCommand::DocumentEndExtend, #if defined(USING_OSX_KEYS) Qt::Key_Down | Qt::CTRL | Qt::SHIFT, #else Qt::Key_End | Qt::CTRL | Qt::SHIFT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection to end of document") }, { QsciCommand::PageUp, Qt::Key_PageUp, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move up one page") }, { QsciCommand::PageUpExtend, Qt::Key_PageUp | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend selection up one page") }, { QsciCommand::PageUpRectExtend, Qt::Key_PageUp | Qt::ALT | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Extend rectangular selection up one page") }, { QsciCommand::PageDown, Qt::Key_PageDown, #if defined(USING_OSX_KEYS) Qt::Key_V | Qt::META, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Move down one page") }, { QsciCommand::PageDownExtend, Qt::Key_PageDown | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_V | Qt::META | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend selection down one page") }, { QsciCommand::PageDownRectExtend, Qt::Key_PageDown | Qt::ALT | Qt::SHIFT, #if defined(USING_OSX_KEYS) Qt::Key_V | Qt::META | Qt::ALT | Qt::SHIFT, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Extend rectangular selection down one page") }, { QsciCommand::StutteredPageUp, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Stuttered move up one page") }, { QsciCommand::StutteredPageUpExtend, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Stuttered extend selection up one page") }, { QsciCommand::StutteredPageDown, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Stuttered move down one page") }, { QsciCommand::StutteredPageDownExtend, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Stuttered extend selection down one page") }, { QsciCommand::Delete, Qt::Key_Delete, #if defined(USING_OSX_KEYS) Qt::Key_D | Qt::META, #else 0, #endif QT_TRANSLATE_NOOP("QsciCommand", "Delete current character") }, { QsciCommand::DeleteBack, Qt::Key_Backspace, #if defined(USING_OSX_KEYS) Qt::Key_H | Qt::META, #else Qt::Key_Backspace | Qt::SHIFT, #endif QT_TRANSLATE_NOOP("QsciCommand", "Delete previous character") }, { QsciCommand::DeleteBackNotLine, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Delete previous character if not at start of line") }, { QsciCommand::DeleteWordLeft, Qt::Key_Backspace | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Delete word to left") }, { QsciCommand::DeleteWordRight, Qt::Key_Delete | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Delete word to right") }, { QsciCommand::DeleteWordRightEnd, #if defined(USING_OSX_KEYS) Qt::Key_Delete | Qt::ALT, #else 0, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Delete right to end of next word") }, { QsciCommand::DeleteLineLeft, Qt::Key_Backspace | Qt::CTRL | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Delete line to left") }, { QsciCommand::DeleteLineRight, #if defined(USING_OSX_KEYS) Qt::Key_K | Qt::META, #else Qt::Key_Delete | Qt::CTRL | Qt::SHIFT, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Delete line to right") }, { QsciCommand::LineDelete, Qt::Key_L | Qt::CTRL | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Delete current line") }, { QsciCommand::LineCut, Qt::Key_L | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Cut current line") }, { QsciCommand::LineCopy, Qt::Key_T | Qt::CTRL | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Copy current line") }, { QsciCommand::LineTranspose, Qt::Key_T | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Transpose current and previous lines") }, { QsciCommand::LineDuplicate, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Duplicate the current line") }, { QsciCommand::SelectAll, Qt::Key_A | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Select all") }, { QsciCommand::MoveSelectedLinesUp, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move selected lines up one line") }, { QsciCommand::MoveSelectedLinesDown, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Move selected lines down one line") }, { QsciCommand::SelectionDuplicate, Qt::Key_D | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Duplicate selection") }, { QsciCommand::SelectionLowerCase, Qt::Key_U | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Convert selection to lower case") }, { QsciCommand::SelectionUpperCase, Qt::Key_U | Qt::CTRL | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "Convert selection to upper case") }, { QsciCommand::SelectionCut, Qt::Key_X | Qt::CTRL, Qt::Key_Delete | Qt::SHIFT, QT_TRANSLATE_NOOP("QsciCommand", "Cut selection") }, { QsciCommand::SelectionCopy, Qt::Key_C | Qt::CTRL, Qt::Key_Insert | Qt::CTRL, QT_TRANSLATE_NOOP("QsciCommand", "Copy selection") }, { QsciCommand::Paste, Qt::Key_V | Qt::CTRL, Qt::Key_Insert | Qt::SHIFT, QT_TRANSLATE_NOOP("QsciCommand", "Paste") }, { QsciCommand::EditToggleOvertype, Qt::Key_Insert, 0, QT_TRANSLATE_NOOP("QsciCommand", "Toggle insert/overtype") }, { QsciCommand::Newline, Qt::Key_Return, Qt::Key_Return | Qt::SHIFT, QT_TRANSLATE_NOOP("QsciCommand", "Insert newline") }, { QsciCommand::Formfeed, 0, 0, QT_TRANSLATE_NOOP("QsciCommand", "Formfeed") }, { QsciCommand::Tab, Qt::Key_Tab, 0, QT_TRANSLATE_NOOP("QsciCommand", "Indent one level") }, { QsciCommand::Backtab, Qt::Key_Tab | Qt::SHIFT, 0, QT_TRANSLATE_NOOP("QsciCommand", "De-indent one level") }, { QsciCommand::Cancel, Qt::Key_Escape, 0, QT_TRANSLATE_NOOP("QsciCommand", "Cancel") }, { QsciCommand::Undo, Qt::Key_Z | Qt::CTRL, Qt::Key_Backspace | Qt::ALT, QT_TRANSLATE_NOOP("QsciCommand", "Undo last command") }, { QsciCommand::Redo, #if defined(USING_OSX_KEYS) Qt::Key_Z | Qt::CTRL | Qt::SHIFT, #else Qt::Key_Y | Qt::CTRL, #endif 0, QT_TRANSLATE_NOOP("QsciCommand", "Redo last command") }, { QsciCommand::ZoomIn, Qt::Key_Plus | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Zoom in") }, { QsciCommand::ZoomOut, Qt::Key_Minus | Qt::CTRL, 0, QT_TRANSLATE_NOOP("QsciCommand", "Zoom out") }, }; // Clear the default map. qsci->SendScintilla(QsciScintillaBase::SCI_CLEARALLCMDKEYS); // By default control characters don't do anything (rather than insert the // control character into the text). for (int k = 'A'; k <= 'Z'; ++k) qsci->SendScintilla(QsciScintillaBase::SCI_ASSIGNCMDKEY, k + (QsciScintillaBase::SCMOD_CTRL << 16), QsciScintillaBase::SCI_NULL); for (int i = 0; i < sizeof (cmd_table) / sizeof (cmd_table[0]); ++i) cmds.append( new QsciCommand(qsci, cmd_table[i].cmd, cmd_table[i].key, cmd_table[i].altkey, cmd_table[i].desc)); } // The dtor. QsciCommandSet::~QsciCommandSet() { for (int i = 0; i < cmds.count(); ++i) delete cmds.at(i); } // Read the command set from settings. bool QsciCommandSet::readSettings(QSettings &qs, const char *prefix) { bool rc = true; QString skey; for (int i = 0; i < cmds.count(); ++i) { QsciCommand *cmd = cmds.at(i); skey.sprintf("%s/keymap/c%d/", prefix, static_cast(cmd->command())); int key; bool ok; // Read the key. ok = qs.contains(skey + "key"); key = qs.value(skey + "key", 0).toInt(); if (ok) cmd->setKey(key); else rc = false; // Read the alternate key. ok = qs.contains(skey + "alt"); key = qs.value(skey + "alt", 0).toInt(); if (ok) cmd->setAlternateKey(key); else rc = false; } return rc; } // Write the command set to settings. bool QsciCommandSet::writeSettings(QSettings &qs, const char *prefix) { bool rc = true; QString skey; for (int i = 0; i < cmds.count(); ++i) { QsciCommand *cmd = cmds.at(i); skey.sprintf("%s/keymap/c%d/", prefix, static_cast(cmd->command())); // Write the key. qs.setValue(skey + "key", cmd->key()); // Write the alternate key. qs.setValue(skey + "alt", cmd->alternateKey()); } return rc; } // Clear the key bindings. void QsciCommandSet::clearKeys() { for (int i = 0; i < cmds.count(); ++i) cmds.at(i)->setKey(0); } // Clear the alternate key bindings. void QsciCommandSet::clearAlternateKeys() { for (int i = 0; i < cmds.count(); ++i) cmds.at(i)->setAlternateKey(0); } // Find the command bound to a key. QsciCommand *QsciCommandSet::boundTo(int key) const { for (int i = 0; i < cmds.count(); ++i) { QsciCommand *cmd = cmds.at(i); if (cmd->key() == key || cmd->alternateKey() == key) return cmd; } return 0; } // Find a command. QsciCommand *QsciCommandSet::find(QsciCommand::Command command) const { for (int i = 0; i < cmds.count(); ++i) { QsciCommand *cmd = cmds.at(i); if (cmd->command() == command) return cmd; } // This should never happen. return 0; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscidocument.cpp000066400000000000000000000073211463772530400272370ustar00rootroot00000000000000// This module implements the QsciDocument class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscidocument.h" #include "Qsci/qsciscintillabase.h" // This internal class encapsulates the underlying document and is shared by // QsciDocument instances. class QsciDocumentP { public: QsciDocumentP() : doc(0), nr_displays(0), nr_attaches(1), modified(false) {} void *doc; // The Scintilla document. int nr_displays; // The number of displays. int nr_attaches; // The number of attaches. bool modified; // Set if not at a save point. }; // The ctor. QsciDocument::QsciDocument() { pdoc = new QsciDocumentP(); } // The dtor. QsciDocument::~QsciDocument() { detach(); } // The copy ctor. QsciDocument::QsciDocument(const QsciDocument &that) { attach(that); } // The assignment operator. QsciDocument &QsciDocument::operator=(const QsciDocument &that) { if (pdoc != that.pdoc) { detach(); attach(that); } return *this; } // Attach an existing document to this one. void QsciDocument::attach(const QsciDocument &that) { ++that.pdoc->nr_attaches; pdoc = that.pdoc; } // Detach the underlying document. void QsciDocument::detach() { if (!pdoc) return; if (--pdoc->nr_attaches == 0) { if (pdoc->doc && pdoc->nr_displays == 0) { QsciScintillaBase *qsb = QsciScintillaBase::pool(); // Release the explicit reference to the document. If the pool is // empty then we just accept the memory leak. if (qsb) qsb->SendScintilla(QsciScintillaBase::SCI_RELEASEDOCUMENT, 0, pdoc->doc); } delete pdoc; } pdoc = 0; } // Undisplay and detach the underlying document. void QsciDocument::undisplay(QsciScintillaBase *qsb) { if (--pdoc->nr_attaches == 0) delete pdoc; else if (--pdoc->nr_displays == 0) { // Create an explicit reference to the document to keep it alive. qsb->SendScintilla(QsciScintillaBase::SCI_ADDREFDOCUMENT, 0, pdoc->doc); } pdoc = 0; } // Display the underlying document. void QsciDocument::display(QsciScintillaBase *qsb, const QsciDocument *from) { void *ndoc = (from ? from->pdoc->doc : 0); // SCI_SETDOCPOINTER appears to reset the EOL mode so save and restore it. int eol_mode = qsb->SendScintilla(QsciScintillaBase::SCI_GETEOLMODE); qsb->SendScintilla(QsciScintillaBase::SCI_SETDOCPOINTER, 0, ndoc); ndoc = qsb->SendScintillaPtrResult(QsciScintillaBase::SCI_GETDOCPOINTER); qsb->SendScintilla(QsciScintillaBase::SCI_SETEOLMODE, eol_mode); pdoc->doc = ndoc; ++pdoc->nr_displays; } // Return the modified state of the document. bool QsciDocument::isModified() const { return pdoc->modified; } // Set the modified state of the document. void QsciDocument::setModified(bool m) { pdoc->modified = m; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscilexer.cpp000066400000000000000000000406371463772530400265470ustar00rootroot00000000000000// This module implements the QsciLexer class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscilexer.h" #include #include #include #include #include "Qsci/qsciapis.h" #include "Qsci/qsciscintilla.h" #include "Qsci/qsciscintillabase.h" // The ctor. QsciLexer::QsciLexer(QObject *parent) : QObject(parent), autoIndStyle(-1), apiSet(0), attached_editor(0) { #if defined(Q_OS_WIN) defFont = QFont("Verdana", 10); #elif defined(Q_OS_MAC) defFont = QFont("Menlo", 12); #else defFont = QFont("Bitstream Vera Sans", 9); #endif // Set the default fore and background colours. QPalette pal = QApplication::palette(); defColor = pal.text().color(); defPaper = pal.base().color(); // Putting this on the heap means we can keep the style getters const. style_map = new StyleDataMap; style_map->style_data_set = false; } // The dtor. QsciLexer::~QsciLexer() { delete style_map; } // Set the attached editor. void QsciLexer::setEditor(QsciScintilla *editor) { attached_editor = editor; } // Return the lexer name. const char *QsciLexer::lexer() const { return 0; } // Return the lexer identifier. int QsciLexer::lexerId() const { return QsciScintillaBase::SCLEX_CONTAINER; } // Return the number of style bits needed by the lexer. int QsciLexer::styleBitsNeeded() const { return 8; } // Make sure the style defaults have been set. void QsciLexer::setStyleDefaults() const { if (!style_map->style_data_set) { for (int i = 0; i <= QsciScintillaBase::STYLE_MAX; ++i) if (!description(i).isEmpty()) styleData(i); style_map->style_data_set = true; } } // Return a reference to a style's data, setting up the defaults if needed. QsciLexer::StyleData &QsciLexer::styleData(int style) const { StyleData &sd = style_map->style_data[style]; // See if this is a new style by checking if the colour is valid. if (!sd.color.isValid()) { sd.color = defaultColor(style); sd.paper = defaultPaper(style); sd.font = defaultFont(style); sd.eol_fill = defaultEolFill(style); } return sd; } // Set the APIs associated with the lexer. void QsciLexer::setAPIs(QsciAbstractAPIs *apis) { apiSet = apis; } // Return a pointer to the current APIs if there are any. QsciAbstractAPIs *QsciLexer::apis() const { return apiSet; } // Default implementation to return the set of fill up characters that can end // auto-completion. const char *QsciLexer::autoCompletionFillups() const { return "("; } // Default implementation to return the view used for indentation guides. int QsciLexer::indentationGuideView() const { return QsciScintillaBase::SC_IV_LOOKBOTH; } // Default implementation to return the list of character sequences that can // separate auto-completion words. QStringList QsciLexer::autoCompletionWordSeparators() const { return QStringList(); } // Default implementation to return the list of keywords that can start a // block. const char *QsciLexer::blockStartKeyword(int *) const { return 0; } // Default implementation to return the list of characters that can start a // block. const char *QsciLexer::blockStart(int *) const { return 0; } // Default implementation to return the list of characters that can end a // block. const char *QsciLexer::blockEnd(int *) const { return 0; } // Default implementation to return the style used for braces. int QsciLexer::braceStyle() const { return -1; } // Default implementation to return the number of lines to look back when // auto-indenting. int QsciLexer::blockLookback() const { return 20; } // Default implementation to return the case sensitivity of the language. bool QsciLexer::caseSensitive() const { return true; } // Default implementation to return the characters that make up a word. const char *QsciLexer::wordCharacters() const { return 0; } // Default implementation to return the style used for whitespace. int QsciLexer::defaultStyle() const { return 0; } // Returns the foreground colour of the text for a style. QColor QsciLexer::color(int style) const { return styleData(style).color; } // Returns the background colour of the text for a style. QColor QsciLexer::paper(int style) const { return styleData(style).paper; } // Returns the font for a style. QFont QsciLexer::font(int style) const { return styleData(style).font; } // Returns the end-of-line fill for a style. bool QsciLexer::eolFill(int style) const { return styleData(style).eol_fill; } // Returns the set of keywords. const char *QsciLexer::keywords(int) const { return 0; } // Returns the default EOL fill for a style. bool QsciLexer::defaultEolFill(int) const { return false; } // Returns the default font for a style. QFont QsciLexer::defaultFont(int) const { return defaultFont(); } // Returns the default font. QFont QsciLexer::defaultFont() const { return defFont; } // Sets the default font. void QsciLexer::setDefaultFont(const QFont &f) { defFont = f; } // Returns the default text colour for a style. QColor QsciLexer::defaultColor(int) const { return defaultColor(); } // Returns the default text colour. QColor QsciLexer::defaultColor() const { return defColor; } // Sets the default text colour. void QsciLexer::setDefaultColor(const QColor &c) { defColor = c; } // Returns the default paper colour for a styles. QColor QsciLexer::defaultPaper(int) const { return defaultPaper(); } // Returns the default paper colour. QColor QsciLexer::defaultPaper() const { return defPaper; } // Sets the default paper colour. void QsciLexer::setDefaultPaper(const QColor &c) { defPaper = c; // Normally the default values are only intended to provide defaults when a // lexer is first setup because once a style has been referenced then a // copy of the default is made. However the default paper is a special // case because there is no other way to set the background colour used // where there is no text. Therefore we also actively set it. setPaper(c, QsciScintillaBase::STYLE_DEFAULT); } // Read properties from the settings. bool QsciLexer::readProperties(QSettings &,const QString &) { return true; } // Refresh all properties. void QsciLexer::refreshProperties() { } // Write properties to the settings. bool QsciLexer::writeProperties(QSettings &,const QString &) const { return true; } // Restore the user settings. bool QsciLexer::readSettings(QSettings &qs,const char *prefix) { bool ok, flag, rc = true; int num; QString key, full_key; QStringList fdesc; setStyleDefaults(); // Read the styles. for (int i = 0; i <= QsciScintillaBase::STYLE_MAX; ++i) { // Ignore invalid styles. if (description(i).isEmpty()) continue; key.sprintf("%s/%s/style%d/",prefix,language(),i); // Read the foreground colour. full_key = key + "color"; ok = qs.contains(full_key); num = qs.value(full_key).toInt(); if (ok) setColor(QColor((num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff), i); else rc = false; // Read the end-of-line fill. full_key = key + "eolfill"; ok = qs.contains(full_key); flag = qs.value(full_key, false).toBool(); if (ok) setEolFill(flag, i); else rc = false; // Read the font. First try the deprecated format that uses an integer // point size. full_key = key + "font"; ok = qs.contains(full_key); fdesc = qs.value(full_key).toStringList(); if (ok && fdesc.count() == 5) { QFont f; f.setFamily(fdesc[0]); f.setPointSize(fdesc[1].toInt()); f.setBold(fdesc[2].toInt()); f.setItalic(fdesc[3].toInt()); f.setUnderline(fdesc[4].toInt()); setFont(f, i); } else rc = false; // Now try the newer font format that uses a floating point point size. // It is not an error if it doesn't exist. full_key = key + "font2"; ok = qs.contains(full_key); fdesc = qs.value(full_key).toStringList(); if (ok) { // Allow for future versions with more fields. if (fdesc.count() >= 5) { QFont f; f.setFamily(fdesc[0]); f.setPointSizeF(fdesc[1].toDouble()); f.setBold(fdesc[2].toInt()); f.setItalic(fdesc[3].toInt()); f.setUnderline(fdesc[4].toInt()); setFont(f, i); } else { rc = false; } } // Read the background colour. full_key = key + "paper"; ok = qs.contains(full_key); num = qs.value(full_key).toInt(); if (ok) setPaper(QColor((num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff), i); else rc = false; } // Read the properties. key.sprintf("%s/%s/properties/",prefix,language()); if (!readProperties(qs,key)) rc = false; refreshProperties(); // Read the rest. key.sprintf("%s/%s/",prefix,language()); // Read the default foreground colour. full_key = key + "defaultcolor"; ok = qs.contains(full_key); num = qs.value(full_key).toInt(); if (ok) setDefaultColor(QColor((num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff)); else rc = false; // Read the default background colour. full_key = key + "defaultpaper"; ok = qs.contains(full_key); num = qs.value(full_key).toInt(); if (ok) setDefaultPaper(QColor((num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff)); else rc = false; // Read the default font. First try the deprecated format that uses an // integer point size. full_key = key + "defaultfont"; ok = qs.contains(full_key); fdesc = qs.value(full_key).toStringList(); if (ok && fdesc.count() == 5) { QFont f; f.setFamily(fdesc[0]); f.setPointSize(fdesc[1].toInt()); f.setBold(fdesc[2].toInt()); f.setItalic(fdesc[3].toInt()); f.setUnderline(fdesc[4].toInt()); setDefaultFont(f); } else rc = false; // Now try the newer font format that uses a floating point point size. It // is not an error if it doesn't exist. full_key = key + "defaultfont2"; ok = qs.contains(full_key); fdesc = qs.value(full_key).toStringList(); if (ok) { // Allow for future versions with more fields. if (fdesc.count() >= 5) { QFont f; f.setFamily(fdesc[0]); f.setPointSizeF(fdesc[1].toDouble()); f.setBold(fdesc[2].toInt()); f.setItalic(fdesc[3].toInt()); f.setUnderline(fdesc[4].toInt()); setDefaultFont(f); } else { rc = false; } } full_key = key + "autoindentstyle"; ok = qs.contains(full_key); num = qs.value(full_key).toInt(); if (ok) setAutoIndentStyle(num); else rc = false; return rc; } // Save the user settings. bool QsciLexer::writeSettings(QSettings &qs,const char *prefix) const { bool rc = true; QString key, fmt("%1"); int num; QStringList fdesc; setStyleDefaults(); // Write the styles. for (int i = 0; i <= QsciScintillaBase::STYLE_MAX; ++i) { // Ignore invalid styles. if (description(i).isEmpty()) continue; QColor c; key.sprintf("%s/%s/style%d/",prefix,language(),i); // Write the foreground colour. c = color(i); num = (c.red() << 16) | (c.green() << 8) | c.blue(); qs.setValue(key + "color", num); // Write the end-of-line fill. qs.setValue(key + "eolfill", eolFill(i)); // Write the font using the deprecated format. QFont f = font(i); fdesc.clear(); fdesc += f.family(); fdesc += fmt.arg(f.pointSize()); // The casts are for Borland. fdesc += fmt.arg((int)f.bold()); fdesc += fmt.arg((int)f.italic()); fdesc += fmt.arg((int)f.underline()); qs.setValue(key + "font", fdesc); // Write the font using the newer format. fdesc[1] = fmt.arg(f.pointSizeF()); qs.setValue(key + "font2", fdesc); // Write the background colour. c = paper(i); num = (c.red() << 16) | (c.green() << 8) | c.blue(); qs.setValue(key + "paper", num); } // Write the properties. key.sprintf("%s/%s/properties/",prefix,language()); if (!writeProperties(qs,key)) rc = false; // Write the rest. key.sprintf("%s/%s/",prefix,language()); // Write the default foreground colour. num = (defColor.red() << 16) | (defColor.green() << 8) | defColor.blue(); qs.setValue(key + "defaultcolor", num); // Write the default background colour. num = (defPaper.red() << 16) | (defPaper.green() << 8) | defPaper.blue(); qs.setValue(key + "defaultpaper", num); // Write the default font using the deprecated format. fdesc.clear(); fdesc += defFont.family(); fdesc += fmt.arg(defFont.pointSize()); // The casts are for Borland. fdesc += fmt.arg((int)defFont.bold()); fdesc += fmt.arg((int)defFont.italic()); fdesc += fmt.arg((int)defFont.underline()); qs.setValue(key + "defaultfont", fdesc); // Write the font using the newer format. fdesc[1] = fmt.arg(defFont.pointSizeF()); qs.setValue(key + "defaultfont2", fdesc); qs.setValue(key + "autoindentstyle", autoIndStyle); return rc; } // Return the auto-indentation style. int QsciLexer::autoIndentStyle() { // We can't do this in the ctor because we want the virtuals to work. if (autoIndStyle < 0) autoIndStyle = (blockStartKeyword() || blockStart() || blockEnd()) ? 0 : QsciScintilla::AiMaintain; return autoIndStyle; } // Set the auto-indentation style. void QsciLexer::setAutoIndentStyle(int autoindentstyle) { autoIndStyle = autoindentstyle; } // Set the foreground colour for a style. void QsciLexer::setColor(const QColor &c, int style) { if (style >= 0) { styleData(style).color = c; emit colorChanged(c, style); } else for (int i = 0; i <= QsciScintillaBase::STYLE_MAX; ++i) if (!description(i).isEmpty()) setColor(c, i); } // Set the end-of-line fill for a style. void QsciLexer::setEolFill(bool eolfill, int style) { if (style >= 0) { styleData(style).eol_fill = eolfill; emit eolFillChanged(eolfill, style); } else for (int i = 0; i <= QsciScintillaBase::STYLE_MAX; ++i) if (!description(i).isEmpty()) setEolFill(eolfill, i); } // Set the font for a style. void QsciLexer::setFont(const QFont &f, int style) { if (style >= 0) { styleData(style).font = f; emit fontChanged(f, style); } else for (int i = 0; i <= QsciScintillaBase::STYLE_MAX; ++i) if (!description(i).isEmpty()) setFont(f, i); } // Set the background colour for a style. void QsciLexer::setPaper(const QColor &c, int style) { if (style >= 0) { styleData(style).paper = c; emit paperChanged(c, style); } else { for (int i = 0; i <= QsciScintillaBase::STYLE_MAX; ++i) if (!description(i).isEmpty()) setPaper(c, i); emit paperChanged(c, QsciScintillaBase::STYLE_DEFAULT); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscilexercpp.cpp000066400000000000000000000472511463772530400272510ustar00rootroot00000000000000// This module implements the QsciLexerCPP class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscilexercpp.h" #include #include #include // The ctor. QsciLexerCPP::QsciLexerCPP(QObject *parent, bool caseInsensitiveKeywords) : QsciLexer(parent), fold_atelse(false), fold_comments(false), fold_compact(true), fold_preproc(true), style_preproc(false), dollars(true), highlight_triple(false), highlight_hash(false), highlight_back(false), highlight_escape(false), vs_escape(false), nocase(caseInsensitiveKeywords) { } // The dtor. QsciLexerCPP::~QsciLexerCPP() { } // Returns the language name. const char *QsciLexerCPP::language() const { return "C++"; } // Returns the lexer name. const char *QsciLexerCPP::lexer() const { return (nocase ? "cppnocase" : "cpp"); } // Return the set of character sequences that can separate auto-completion // words. QStringList QsciLexerCPP::autoCompletionWordSeparators() const { QStringList wl; wl << "::" << "->" << "."; return wl; } // Return the list of keywords that can start a block. const char *QsciLexerCPP::blockStartKeyword(int *style) const { if (style) *style = Keyword; return "case catch class default do else finally for if private " "protected public struct try union while"; } // Return the list of characters that can start a block. const char *QsciLexerCPP::blockStart(int *style) const { if (style) *style = Operator; return "{"; } // Return the list of characters that can end a block. const char *QsciLexerCPP::blockEnd(int *style) const { if (style) *style = Operator; return "}"; } // Return the style used for braces. int QsciLexerCPP::braceStyle() const { return Operator; } // Return the string of characters that comprise a word. const char *QsciLexerCPP::wordCharacters() const { return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_#"; } // Returns the foreground colour of the text for a style. QColor QsciLexerCPP::defaultColor(int style) const { switch (style) { case Default: return QColor(0x80, 0x80, 0x80); case Comment: case CommentLine: return QColor(0x00, 0x7f, 0x00); case CommentDoc: case CommentLineDoc: case PreProcessorCommentLineDoc: return QColor(0x3f, 0x70, 0x3f); case Number: return QColor(0x00, 0x7f, 0x7f); case Keyword: return QColor(0x00, 0x00, 0x7f); case DoubleQuotedString: case SingleQuotedString: case RawString: return QColor(0x7f, 0x00, 0x7f); case PreProcessor: return QColor(0x7f, 0x7f, 0x00); case Operator: case UnclosedString: return QColor(0x00, 0x00, 0x00); case VerbatimString: case TripleQuotedVerbatimString: case HashQuotedString: return QColor(0x00, 0x7f, 0x00); case Regex: return QColor(0x3f, 0x7f, 0x3f); case CommentDocKeyword: return QColor(0x30, 0x60, 0xa0); case CommentDocKeywordError: return QColor(0x80, 0x40, 0x20); case PreProcessorComment: return QColor(0x65, 0x99, 0x00); case InactiveDefault: case InactiveUUID: case InactiveCommentLineDoc: case InactiveKeywordSet2: case InactiveCommentDocKeyword: case InactiveCommentDocKeywordError: case InactivePreProcessorCommentLineDoc: return QColor(0xc0, 0xc0, 0xc0); case InactiveComment: case InactiveCommentLine: case InactiveNumber: case InactiveVerbatimString: case InactiveTripleQuotedVerbatimString: case InactiveHashQuotedString: return QColor(0x90, 0xb0, 0x90); case InactiveCommentDoc: return QColor(0xd0, 0xd0, 0xd0); case InactiveKeyword: return QColor(0x90, 0x90, 0xb0); case InactiveDoubleQuotedString: case InactiveSingleQuotedString: case InactiveRawString: return QColor(0xb0, 0x90, 0xb0); case InactivePreProcessor: return QColor(0xb0, 0xb0, 0x90); case InactiveOperator: case InactiveIdentifier: case InactiveGlobalClass: return QColor(0xb0, 0xb0, 0xb0); case InactiveUnclosedString: return QColor(0x00, 0x00, 0x00); case InactiveRegex: return QColor(0x7f, 0xaf, 0x7f); case InactivePreProcessorComment: return QColor(0xa0, 0xc0, 0x90); case UserLiteral: return QColor(0xc0, 0x60, 0x00); case InactiveUserLiteral: return QColor(0xd7, 0xa0, 0x90); case TaskMarker: return QColor(0xbe, 0x07, 0xff); case InactiveTaskMarker: return QColor(0xc3, 0xa1, 0xcf); } return QsciLexer::defaultColor(style); } // Returns the end-of-line fill for a style. bool QsciLexerCPP::defaultEolFill(int style) const { switch (style) { case UnclosedString: case InactiveUnclosedString: case VerbatimString: case InactiveVerbatimString: case Regex: case InactiveRegex: case TripleQuotedVerbatimString: case InactiveTripleQuotedVerbatimString: case HashQuotedString: case InactiveHashQuotedString: return true; } return QsciLexer::defaultEolFill(style); } // Returns the font of the text for a style. QFont QsciLexerCPP::defaultFont(int style) const { QFont f; switch (style) { case Comment: case InactiveComment: case CommentLine: case InactiveCommentLine: case CommentDoc: case InactiveCommentDoc: case CommentLineDoc: case InactiveCommentLineDoc: case CommentDocKeyword: case InactiveCommentDocKeyword: case CommentDocKeywordError: case InactiveCommentDocKeywordError: case TaskMarker: case InactiveTaskMarker: #if defined(Q_OS_WIN) f = QFont("Comic Sans MS",9); #elif defined(Q_OS_MAC) f = QFont("Comic Sans MS", 12); #else f = QFont("Bitstream Vera Serif",9); #endif break; case Keyword: case InactiveKeyword: case Operator: case InactiveOperator: f = QsciLexer::defaultFont(style); f.setBold(true); break; case DoubleQuotedString: case InactiveDoubleQuotedString: case SingleQuotedString: case InactiveSingleQuotedString: case UnclosedString: case InactiveUnclosedString: case VerbatimString: case InactiveVerbatimString: case Regex: case InactiveRegex: case TripleQuotedVerbatimString: case InactiveTripleQuotedVerbatimString: case HashQuotedString: case InactiveHashQuotedString: #if defined(Q_OS_WIN) f = QFont("Courier New",10); #elif defined(Q_OS_MAC) f = QFont("Courier", 12); #else f = QFont("Bitstream Vera Sans Mono",9); #endif break; default: f = QsciLexer::defaultFont(style); } return f; } // Returns the set of keywords. const char *QsciLexerCPP::keywords(int set) const { if (set == 1) return "and and_eq asm auto bitand bitor bool break case " "catch char class compl const const_cast continue " "default delete do double dynamic_cast else enum " "explicit export extern false float for friend goto if " "inline int long mutable namespace new not not_eq " "operator or or_eq private protected public register " "reinterpret_cast return short signed sizeof static " "static_cast struct switch template this throw true " "try typedef typeid typename union unsigned using " "virtual void volatile wchar_t while xor xor_eq"; if (set == 3) return "a addindex addtogroup anchor arg attention author b " "brief bug c class code date def defgroup deprecated " "dontinclude e em endcode endhtmlonly endif " "endlatexonly endlink endverbatim enum example " "exception f$ f[ f] file fn hideinitializer " "htmlinclude htmlonly if image include ingroup " "internal invariant interface latexonly li line link " "mainpage name namespace nosubgrouping note overload " "p page par param post pre ref relates remarks return " "retval sa section see showinitializer since skip " "skipline struct subsection test throw todo typedef " "union until var verbatim verbinclude version warning " "weakgroup $ @ \\ & < > # { }"; return 0; } // Returns the user name of a style. QString QsciLexerCPP::description(int style) const { switch (style) { case Default: return tr("Default"); case InactiveDefault: return tr("Inactive default"); case Comment: return tr("C comment"); case InactiveComment: return tr("Inactive C comment"); case CommentLine: return tr("C++ comment"); case InactiveCommentLine: return tr("Inactive C++ comment"); case CommentDoc: return tr("JavaDoc style C comment"); case InactiveCommentDoc: return tr("Inactive JavaDoc style C comment"); case Number: return tr("Number"); case InactiveNumber: return tr("Inactive number"); case Keyword: return tr("Keyword"); case InactiveKeyword: return tr("Inactive keyword"); case DoubleQuotedString: return tr("Double-quoted string"); case InactiveDoubleQuotedString: return tr("Inactive double-quoted string"); case SingleQuotedString: return tr("Single-quoted string"); case InactiveSingleQuotedString: return tr("Inactive single-quoted string"); case UUID: return tr("IDL UUID"); case InactiveUUID: return tr("Inactive IDL UUID"); case PreProcessor: return tr("Pre-processor block"); case InactivePreProcessor: return tr("Inactive pre-processor block"); case Operator: return tr("Operator"); case InactiveOperator: return tr("Inactive operator"); case Identifier: return tr("Identifier"); case InactiveIdentifier: return tr("Inactive identifier"); case UnclosedString: return tr("Unclosed string"); case InactiveUnclosedString: return tr("Inactive unclosed string"); case VerbatimString: return tr("C# verbatim string"); case InactiveVerbatimString: return tr("Inactive C# verbatim string"); case Regex: return tr("JavaScript regular expression"); case InactiveRegex: return tr("Inactive JavaScript regular expression"); case CommentLineDoc: return tr("JavaDoc style C++ comment"); case InactiveCommentLineDoc: return tr("Inactive JavaDoc style C++ comment"); case KeywordSet2: return tr("Secondary keywords and identifiers"); case InactiveKeywordSet2: return tr("Inactive secondary keywords and identifiers"); case CommentDocKeyword: return tr("JavaDoc keyword"); case InactiveCommentDocKeyword: return tr("Inactive JavaDoc keyword"); case CommentDocKeywordError: return tr("JavaDoc keyword error"); case InactiveCommentDocKeywordError: return tr("Inactive JavaDoc keyword error"); case GlobalClass: return tr("Global classes and typedefs"); case InactiveGlobalClass: return tr("Inactive global classes and typedefs"); case RawString: return tr("C++ raw string"); case InactiveRawString: return tr("Inactive C++ raw string"); case TripleQuotedVerbatimString: return tr("Vala triple-quoted verbatim string"); case InactiveTripleQuotedVerbatimString: return tr("Inactive Vala triple-quoted verbatim string"); case HashQuotedString: return tr("Pike hash-quoted string"); case InactiveHashQuotedString: return tr("Inactive Pike hash-quoted string"); case PreProcessorComment: return tr("Pre-processor C comment"); case InactivePreProcessorComment: return tr("Inactive pre-processor C comment"); case PreProcessorCommentLineDoc: return tr("JavaDoc style pre-processor comment"); case InactivePreProcessorCommentLineDoc: return tr("Inactive JavaDoc style pre-processor comment"); case UserLiteral: return tr("User-defined literal"); case InactiveUserLiteral: return tr("Inactive user-defined literal"); case TaskMarker: return tr("Task marker"); case InactiveTaskMarker: return tr("Inactive task marker"); case EscapeSequence: return tr("Escape sequence"); case InactiveEscapeSequence: return tr("Inactive escape sequence"); } return QString(); } // Returns the background colour of the text for a style. QColor QsciLexerCPP::defaultPaper(int style) const { switch (style) { case UnclosedString: case InactiveUnclosedString: return QColor(0xe0,0xc0,0xe0); case VerbatimString: case InactiveVerbatimString: case TripleQuotedVerbatimString: case InactiveTripleQuotedVerbatimString: return QColor(0xe0,0xff,0xe0); case Regex: case InactiveRegex: return QColor(0xe0,0xf0,0xe0); case RawString: case InactiveRawString: return QColor(0xff,0xf3,0xff); case HashQuotedString: case InactiveHashQuotedString: return QColor(0xe7,0xff,0xd7); } return QsciLexer::defaultPaper(style); } // Refresh all properties. void QsciLexerCPP::refreshProperties() { setAtElseProp(); setCommentProp(); setCompactProp(); setPreprocProp(); setStylePreprocProp(); setDollarsProp(); setHighlightTripleProp(); setHighlightHashProp(); setHighlightBackProp(); setHighlightEscapeProp(); setVerbatimStringEscapeProp(); } // Read properties from the settings. bool QsciLexerCPP::readProperties(QSettings &qs,const QString &prefix) { fold_atelse = qs.value(prefix + "foldatelse", false).toBool(); fold_comments = qs.value(prefix + "foldcomments", false).toBool(); fold_compact = qs.value(prefix + "foldcompact", true).toBool(); fold_preproc = qs.value(prefix + "foldpreprocessor", true).toBool(); style_preproc = qs.value(prefix + "stylepreprocessor", false).toBool(); dollars = qs.value(prefix + "dollars", true).toBool(); highlight_triple = qs.value(prefix + "highlighttriple", false).toBool(); highlight_hash = qs.value(prefix + "highlighthash", false).toBool(); highlight_back = qs.value(prefix + "highlightback", false).toBool(); highlight_escape = qs.value(prefix + "highlightescape", false).toBool(); vs_escape = qs.value(prefix + "verbatimstringescape", false).toBool(); return true; } // Write properties to the settings. bool QsciLexerCPP::writeProperties(QSettings &qs,const QString &prefix) const { qs.setValue(prefix + "foldatelse", fold_atelse); qs.setValue(prefix + "foldcomments", fold_comments); qs.setValue(prefix + "foldcompact", fold_compact); qs.setValue(prefix + "foldpreprocessor", fold_preproc); qs.setValue(prefix + "stylepreprocessor", style_preproc); qs.setValue(prefix + "dollars", dollars); qs.setValue(prefix + "highlighttriple", highlight_triple); qs.setValue(prefix + "highlighthash", highlight_hash); qs.setValue(prefix + "highlightback", highlight_back); qs.setValue(prefix + "highlightescape", highlight_escape); qs.setValue(prefix + "verbatimstringescape", vs_escape); return true; } // Set if else can be folded. void QsciLexerCPP::setFoldAtElse(bool fold) { fold_atelse = fold; setAtElseProp(); } // Set the "fold.at.else" property. void QsciLexerCPP::setAtElseProp() { emit propertyChanged("fold.at.else",(fold_atelse ? "1" : "0")); } // Set if comments can be folded. void QsciLexerCPP::setFoldComments(bool fold) { fold_comments = fold; setCommentProp(); } // Set the "fold.comment" property. void QsciLexerCPP::setCommentProp() { emit propertyChanged("fold.comment",(fold_comments ? "1" : "0")); } // Set if folds are compact void QsciLexerCPP::setFoldCompact(bool fold) { fold_compact = fold; setCompactProp(); } // Set the "fold.compact" property. void QsciLexerCPP::setCompactProp() { emit propertyChanged("fold.compact",(fold_compact ? "1" : "0")); } // Set if preprocessor blocks can be folded. void QsciLexerCPP::setFoldPreprocessor(bool fold) { fold_preproc = fold; setPreprocProp(); } // Set the "fold.preprocessor" property. void QsciLexerCPP::setPreprocProp() { emit propertyChanged("fold.preprocessor",(fold_preproc ? "1" : "0")); } // Set if preprocessor lines are styled. void QsciLexerCPP::setStylePreprocessor(bool style) { style_preproc = style; setStylePreprocProp(); } // Set the "styling.within.preprocessor" property. void QsciLexerCPP::setStylePreprocProp() { emit propertyChanged("styling.within.preprocessor",(style_preproc ? "1" : "0")); } // Set if '$' characters are allowed. void QsciLexerCPP::setDollarsAllowed(bool allowed) { dollars = allowed; setDollarsProp(); } // Set the "lexer.cpp.allow.dollars" property. void QsciLexerCPP::setDollarsProp() { emit propertyChanged("lexer.cpp.allow.dollars",(dollars ? "1" : "0")); } // Set if triple quoted strings are highlighted. void QsciLexerCPP::setHighlightTripleQuotedStrings(bool enabled) { highlight_triple = enabled; setHighlightTripleProp(); } // Set the "lexer.cpp.triplequoted.strings" property. void QsciLexerCPP::setHighlightTripleProp() { emit propertyChanged("lexer.cpp.triplequoted.strings", (highlight_triple ? "1" : "0")); } // Set if hash quoted strings are highlighted. void QsciLexerCPP::setHighlightHashQuotedStrings(bool enabled) { highlight_hash = enabled; setHighlightHashProp(); } // Set the "lexer.cpp.hashquoted.strings" property. void QsciLexerCPP::setHighlightHashProp() { emit propertyChanged("lexer.cpp.hashquoted.strings", (highlight_hash ? "1" : "0")); } // Set if back-quoted strings are highlighted. void QsciLexerCPP::setHighlightBackQuotedStrings(bool enabled) { highlight_back = enabled; setHighlightBackProp(); } // Set the "lexer.cpp.backquoted.strings" property. void QsciLexerCPP::setHighlightBackProp() { emit propertyChanged("lexer.cpp.backquoted.strings", (highlight_back ? "1" : "0")); } // Set if escape sequences in strings are highlighted. void QsciLexerCPP::setHighlightEscapeSequences(bool enabled) { highlight_escape = enabled; setHighlightEscapeProp(); } // Set the "lexer.cpp.escape.sequence" property. void QsciLexerCPP::setHighlightEscapeProp() { emit propertyChanged("lexer.cpp.escape.sequence", (highlight_escape ? "1" : "0")); } // Set if escape sequences in verbatim strings are allowed. void QsciLexerCPP::setVerbatimStringEscapeSequencesAllowed(bool allowed) { vs_escape = allowed; setVerbatimStringEscapeProp(); } // Set the "lexer.cpp.verbatim.strings.allow.escapes" property. void QsciLexerCPP::setVerbatimStringEscapeProp() { emit propertyChanged("lexer.cpp.verbatim.strings.allow.escapes", (vs_escape ? "1" : "0")); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscilexercustom.cpp000066400000000000000000000051731463772530400277760ustar00rootroot00000000000000// This module implements the QsciLexerCustom class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscilexercustom.h" #include "Qsci/qsciscintilla.h" #include "Qsci/qsciscintillabase.h" #include "Qsci/qscistyle.h" // The ctor. QsciLexerCustom::QsciLexerCustom(QObject *parent) : QsciLexer(parent) { } // The dtor. QsciLexerCustom::~QsciLexerCustom() { } // Start styling. void QsciLexerCustom::startStyling(int start, int) { if (!editor()) return; editor()->SendScintilla(QsciScintillaBase::SCI_STARTSTYLING, start); } // Set the style for a number of characters. void QsciLexerCustom::setStyling(int length, int style) { if (!editor()) return; editor()->SendScintilla(QsciScintillaBase::SCI_SETSTYLING, length, style); } // Set the style for a number of characters. void QsciLexerCustom::setStyling(int length, const QsciStyle &style) { setStyling(length, style.style()); } // Set the attached editor. void QsciLexerCustom::setEditor(QsciScintilla *new_editor) { if (editor()) disconnect(editor(), SIGNAL(SCN_STYLENEEDED(int)), this, SLOT(handleStyleNeeded(int))); QsciLexer::setEditor(new_editor); if (editor()) connect(editor(), SIGNAL(SCN_STYLENEEDED(int)), this, SLOT(handleStyleNeeded(int))); } // Return the number of style bits needed by the lexer. int QsciLexerCustom::styleBitsNeeded() const { return 5; } // Handle a request to style some text. void QsciLexerCustom::handleStyleNeeded(int pos) { int start = editor()->SendScintilla(QsciScintillaBase::SCI_GETENDSTYLED); int line = editor()->SendScintilla(QsciScintillaBase::SCI_LINEFROMPOSITION, start); start = editor()->SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE, line); if (start != pos) styleText(start, pos); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscilexerhtml.cpp000066400000000000000000000740701463772530400274320ustar00rootroot00000000000000// This module implements the QsciLexerHTML class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscilexerhtml.h" #include #include #include #include "Qsci/qscilexerjavascript.h" #include "Qsci/qscilexerpython.h" // The ctor. QsciLexerHTML::QsciLexerHTML(QObject *parent) : QsciLexer(parent), fold_compact(true), fold_preproc(true), case_sens_tags(false), fold_script_comments(false), fold_script_heredocs(false), django_templates(false), mako_templates(false) { } // The dtor. QsciLexerHTML::~QsciLexerHTML() { } // Returns the language name. const char *QsciLexerHTML::language() const { return "HTML"; } // Returns the lexer name. const char *QsciLexerHTML::lexer() const { return "hypertext"; } // Return the auto-completion fillup characters. const char *QsciLexerHTML::autoCompletionFillups() const { return "/>"; } // Return the string of characters that comprise a word. const char *QsciLexerHTML::wordCharacters() const { return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"; } // Returns the foreground colour of the text for a style. QColor QsciLexerHTML::defaultColor(int style) const { switch (style) { case Default: case JavaScriptDefault: case JavaScriptWord: case JavaScriptSymbol: case ASPJavaScriptDefault: case ASPJavaScriptWord: case ASPJavaScriptSymbol: case VBScriptDefault: case ASPVBScriptDefault: case PHPOperator: return QColor(0x00,0x00,0x00); case Tag: case XMLTagEnd: case Script: case SGMLDefault: case SGMLCommand: case VBScriptKeyword: case VBScriptIdentifier: case VBScriptUnclosedString: case ASPVBScriptKeyword: case ASPVBScriptIdentifier: case ASPVBScriptUnclosedString: return QColor(0x00,0x00,0x80); case UnknownTag: case UnknownAttribute: return QColor(0xff,0x00,0x00); case Attribute: case VBScriptNumber: case ASPVBScriptNumber: return QColor(0x00,0x80,0x80); case HTMLNumber: case JavaScriptNumber: case ASPJavaScriptNumber: case PythonNumber: case PythonFunctionMethodName: case ASPPythonNumber: case ASPPythonFunctionMethodName: return QColor(0x00,0x7f,0x7f); case HTMLDoubleQuotedString: case HTMLSingleQuotedString: case JavaScriptDoubleQuotedString: case JavaScriptSingleQuotedString: case ASPJavaScriptDoubleQuotedString: case ASPJavaScriptSingleQuotedString: case PythonDoubleQuotedString: case PythonSingleQuotedString: case ASPPythonDoubleQuotedString: case ASPPythonSingleQuotedString: case PHPKeyword: return QColor(0x7f,0x00,0x7f); case OtherInTag: case Entity: case VBScriptString: case ASPVBScriptString: return QColor(0x80,0x00,0x80); case HTMLComment: case SGMLComment: return QColor(0x80,0x80,0x00); case XMLStart: case XMLEnd: case PHPStart: case PythonClassName: case ASPPythonClassName: return QColor(0x00,0x00,0xff); case HTMLValue: return QColor(0xff,0x00,0xff); case SGMLParameter: return QColor(0x00,0x66,0x00); case SGMLDoubleQuotedString: case SGMLError: return QColor(0x80,0x00,0x00); case SGMLSingleQuotedString: return QColor(0x99,0x33,0x00); case SGMLSpecial: return QColor(0x33,0x66,0xff); case SGMLEntity: return QColor(0x33,0x33,0x33); case SGMLBlockDefault: return QColor(0x00,0x00,0x66); case JavaScriptStart: case ASPJavaScriptStart: return QColor(0x7f,0x7f,0x00); case JavaScriptComment: case JavaScriptCommentLine: case ASPJavaScriptComment: case ASPJavaScriptCommentLine: case PythonComment: case ASPPythonComment: case PHPDoubleQuotedString: return QColor(0x00,0x7f,0x00); case JavaScriptCommentDoc: return QColor(0x3f,0x70,0x3f); case JavaScriptKeyword: case ASPJavaScriptKeyword: case PythonKeyword: case ASPPythonKeyword: case PHPVariable: case PHPDoubleQuotedVariable: return QColor(0x00,0x00,0x7f); case ASPJavaScriptCommentDoc: return QColor(0x7f,0x7f,0x7f); case VBScriptComment: case ASPVBScriptComment: return QColor(0x00,0x80,0x00); case PythonStart: case PythonDefault: case ASPPythonStart: case ASPPythonDefault: return QColor(0x80,0x80,0x80); case PythonTripleSingleQuotedString: case PythonTripleDoubleQuotedString: case ASPPythonTripleSingleQuotedString: case ASPPythonTripleDoubleQuotedString: return QColor(0x7f,0x00,0x00); case PHPDefault: return QColor(0x00,0x00,0x33); case PHPSingleQuotedString: return QColor(0x00,0x9f,0x00); case PHPNumber: return QColor(0xcc,0x99,0x00); case PHPComment: return QColor(0x99,0x99,0x99); case PHPCommentLine: return QColor(0x66,0x66,0x66); } return QsciLexer::defaultColor(style); } // Returns the end-of-line fill for a style. bool QsciLexerHTML::defaultEolFill(int style) const { switch (style) { case JavaScriptDefault: case JavaScriptComment: case JavaScriptCommentDoc: case JavaScriptUnclosedString: case ASPJavaScriptDefault: case ASPJavaScriptComment: case ASPJavaScriptCommentDoc: case ASPJavaScriptUnclosedString: case VBScriptDefault: case VBScriptComment: case VBScriptNumber: case VBScriptKeyword: case VBScriptString: case VBScriptIdentifier: case VBScriptUnclosedString: case ASPVBScriptDefault: case ASPVBScriptComment: case ASPVBScriptNumber: case ASPVBScriptKeyword: case ASPVBScriptString: case ASPVBScriptIdentifier: case ASPVBScriptUnclosedString: case PythonDefault: case PythonComment: case PythonNumber: case PythonDoubleQuotedString: case PythonSingleQuotedString: case PythonKeyword: case PythonTripleSingleQuotedString: case PythonTripleDoubleQuotedString: case PythonClassName: case PythonFunctionMethodName: case PythonOperator: case PythonIdentifier: case ASPPythonDefault: case ASPPythonComment: case ASPPythonNumber: case ASPPythonDoubleQuotedString: case ASPPythonSingleQuotedString: case ASPPythonKeyword: case ASPPythonTripleSingleQuotedString: case ASPPythonTripleDoubleQuotedString: case ASPPythonClassName: case ASPPythonFunctionMethodName: case ASPPythonOperator: case ASPPythonIdentifier: case PHPDefault: return true; } return QsciLexer::defaultEolFill(style); } // Returns the font of the text for a style. QFont QsciLexerHTML::defaultFont(int style) const { QFont f; switch (style) { case Default: case Entity: #if defined(Q_OS_WIN) f = QFont("Times New Roman",11); #elif defined(Q_OS_MAC) f = QFont("Times New Roman", 12); #else f = QFont("Bitstream Charter",10); #endif break; case HTMLComment: #if defined(Q_OS_WIN) f = QFont("Verdana",9); #elif defined(Q_OS_MAC) f = QFont("Verdana", 12); #else f = QFont("Bitstream Vera Sans",8); #endif break; case SGMLCommand: case PythonKeyword: case PythonClassName: case PythonFunctionMethodName: case PythonOperator: case ASPPythonKeyword: case ASPPythonClassName: case ASPPythonFunctionMethodName: case ASPPythonOperator: f = QsciLexer::defaultFont(style); f.setBold(true); break; case JavaScriptDefault: case JavaScriptCommentDoc: case JavaScriptKeyword: case JavaScriptSymbol: case ASPJavaScriptDefault: case ASPJavaScriptCommentDoc: case ASPJavaScriptKeyword: case ASPJavaScriptSymbol: #if defined(Q_OS_WIN) f = QFont("Comic Sans MS",9); #elif defined(Q_OS_MAC) f = QFont("Comic Sans MS", 12); #else f = QFont("Bitstream Vera Serif",9); #endif f.setBold(true); break; case JavaScriptComment: case JavaScriptCommentLine: case JavaScriptNumber: case JavaScriptWord: case JavaScriptDoubleQuotedString: case JavaScriptSingleQuotedString: case ASPJavaScriptComment: case ASPJavaScriptCommentLine: case ASPJavaScriptNumber: case ASPJavaScriptWord: case ASPJavaScriptDoubleQuotedString: case ASPJavaScriptSingleQuotedString: case VBScriptComment: case ASPVBScriptComment: case PythonComment: case ASPPythonComment: case PHPComment: #if defined(Q_OS_WIN) f = QFont("Comic Sans MS",9); #elif defined(Q_OS_MAC) f = QFont("Comic Sans MS", 12); #else f = QFont("Bitstream Vera Serif",9); #endif break; case VBScriptDefault: case VBScriptNumber: case VBScriptString: case VBScriptIdentifier: case VBScriptUnclosedString: case ASPVBScriptDefault: case ASPVBScriptNumber: case ASPVBScriptString: case ASPVBScriptIdentifier: case ASPVBScriptUnclosedString: #if defined(Q_OS_WIN) f = QFont("Lucida Sans Unicode",9); #elif defined(Q_OS_MAC) f = QFont("Lucida Grande", 12); #else f = QFont("Bitstream Vera Serif",9); #endif break; case VBScriptKeyword: case ASPVBScriptKeyword: #if defined(Q_OS_WIN) f = QFont("Lucida Sans Unicode",9); #elif defined(Q_OS_MAC) f = QFont("Lucida Grande", 12); #else f = QFont("Bitstream Vera Serif",9); #endif f.setBold(true); break; case PythonDoubleQuotedString: case PythonSingleQuotedString: case ASPPythonDoubleQuotedString: case ASPPythonSingleQuotedString: #if defined(Q_OS_WIN) f = QFont("Courier New",10); #elif defined(Q_OS_MAC) f = QFont("Courier New", 12); #else f = QFont("Bitstream Vera Sans Mono",9); #endif break; case PHPKeyword: case PHPVariable: case PHPDoubleQuotedVariable: f = QsciLexer::defaultFont(style); f.setItalic(true); break; case PHPCommentLine: #if defined(Q_OS_WIN) f = QFont("Comic Sans MS",9); #elif defined(Q_OS_MAC) f = QFont("Comic Sans MS", 12); #else f = QFont("Bitstream Vera Serif",9); #endif f.setItalic(true); break; default: f = QsciLexer::defaultFont(style); } return f; } // Returns the set of keywords. const char *QsciLexerHTML::keywords(int set) const { if (set == 1) return "a abbr acronym address applet area " "b base basefont bdo big blockquote body br button " "caption center cite code col colgroup " "dd del dfn dir div dl dt " "em " "fieldset font form frame frameset " "h1 h2 h3 h4 h5 h6 head hr html " "i iframe img input ins isindex " "kbd " "label legend li link " "map menu meta " "noframes noscript " "object ol optgroup option " "p param pre " "q " "s samp script select small span strike strong style " "sub sup " "table tbody td textarea tfoot th thead title tr tt " "u ul " "var " "xml xmlns " "abbr accept-charset accept accesskey action align " "alink alt archive axis " "background bgcolor border " "cellpadding cellspacing char charoff charset checked " "cite class classid clear codebase codetype color " "cols colspan compact content coords " "data datafld dataformatas datapagesize datasrc " "datetime declare defer dir disabled " "enctype event " "face for frame frameborder " "headers height href hreflang hspace http-equiv " "id ismap label lang language leftmargin link " "longdesc " "marginwidth marginheight maxlength media method " "multiple " "name nohref noresize noshade nowrap " "object onblur onchange onclick ondblclick onfocus " "onkeydown onkeypress onkeyup onload onmousedown " "onmousemove onmouseover onmouseout onmouseup onreset " "onselect onsubmit onunload " "profile prompt " "readonly rel rev rows rowspan rules " "scheme scope selected shape size span src standby " "start style summary " "tabindex target text title topmargin type " "usemap " "valign value valuetype version vlink vspace " "width " "text password checkbox radio submit reset file " "hidden image " "public !doctype"; if (set == 2) return QsciLexerJavaScript::keywordClass; if (set == 3) return // Move these to QsciLexerVisualBasic when we // get round to implementing it. "and begin case call continue do each else elseif end " "erase error event exit false for function get gosub " "goto if implement in load loop lset me mid new next " "not nothing on or property raiseevent rem resume " "return rset select set stop sub then to true unload " "until wend while with withevents attribute alias as " "boolean byref byte byval const compare currency date " "declare dim double enum explicit friend global " "integer let lib long module object option optional " "preserve private property public redim single static " "string type variant"; if (set == 4) return QsciLexerPython::keywordClass; if (set == 5) return "and argv as argc break case cfunction class continue " "declare default do die " "echo else elseif empty enddeclare endfor endforeach " "endif endswitch endwhile e_all e_parse e_error " "e_warning eval exit extends " "false for foreach function global " "http_cookie_vars http_get_vars http_post_vars " "http_post_files http_env_vars http_server_vars " "if include include_once list new not null " "old_function or " "parent php_os php_self php_version print " "require require_once return " "static switch stdclass this true var xor virtual " "while " "__file__ __line__ __sleep __wakeup"; if (set == 6) return "ELEMENT DOCTYPE ATTLIST ENTITY NOTATION"; return 0; } // Returns the user name of a style. QString QsciLexerHTML::description(int style) const { switch (style) { case Default: return tr("HTML default"); case Tag: return tr("Tag"); case UnknownTag: return tr("Unknown tag"); case Attribute: return tr("Attribute"); case UnknownAttribute: return tr("Unknown attribute"); case HTMLNumber: return tr("HTML number"); case HTMLDoubleQuotedString: return tr("HTML double-quoted string"); case HTMLSingleQuotedString: return tr("HTML single-quoted string"); case OtherInTag: return tr("Other text in a tag"); case HTMLComment: return tr("HTML comment"); case Entity: return tr("Entity"); case XMLTagEnd: return tr("End of a tag"); case XMLStart: return tr("Start of an XML fragment"); case XMLEnd: return tr("End of an XML fragment"); case Script: return tr("Script tag"); case ASPAtStart: return tr("Start of an ASP fragment with @"); case ASPStart: return tr("Start of an ASP fragment"); case CDATA: return tr("CDATA"); case PHPStart: return tr("Start of a PHP fragment"); case HTMLValue: return tr("Unquoted HTML value"); case ASPXCComment: return tr("ASP X-Code comment"); case SGMLDefault: return tr("SGML default"); case SGMLCommand: return tr("SGML command"); case SGMLParameter: return tr("First parameter of an SGML command"); case SGMLDoubleQuotedString: return tr("SGML double-quoted string"); case SGMLSingleQuotedString: return tr("SGML single-quoted string"); case SGMLError: return tr("SGML error"); case SGMLSpecial: return tr("SGML special entity"); case SGMLComment: return tr("SGML comment"); case SGMLParameterComment: return tr("First parameter comment of an SGML command"); case SGMLBlockDefault: return tr("SGML block default"); case JavaScriptStart: return tr("Start of a JavaScript fragment"); case JavaScriptDefault: return tr("JavaScript default"); case JavaScriptComment: return tr("JavaScript comment"); case JavaScriptCommentLine: return tr("JavaScript line comment"); case JavaScriptCommentDoc: return tr("JavaDoc style JavaScript comment"); case JavaScriptNumber: return tr("JavaScript number"); case JavaScriptWord: return tr("JavaScript word"); case JavaScriptKeyword: return tr("JavaScript keyword"); case JavaScriptDoubleQuotedString: return tr("JavaScript double-quoted string"); case JavaScriptSingleQuotedString: return tr("JavaScript single-quoted string"); case JavaScriptSymbol: return tr("JavaScript symbol"); case JavaScriptUnclosedString: return tr("JavaScript unclosed string"); case JavaScriptRegex: return tr("JavaScript regular expression"); case ASPJavaScriptStart: return tr("Start of an ASP JavaScript fragment"); case ASPJavaScriptDefault: return tr("ASP JavaScript default"); case ASPJavaScriptComment: return tr("ASP JavaScript comment"); case ASPJavaScriptCommentLine: return tr("ASP JavaScript line comment"); case ASPJavaScriptCommentDoc: return tr("JavaDoc style ASP JavaScript comment"); case ASPJavaScriptNumber: return tr("ASP JavaScript number"); case ASPJavaScriptWord: return tr("ASP JavaScript word"); case ASPJavaScriptKeyword: return tr("ASP JavaScript keyword"); case ASPJavaScriptDoubleQuotedString: return tr("ASP JavaScript double-quoted string"); case ASPJavaScriptSingleQuotedString: return tr("ASP JavaScript single-quoted string"); case ASPJavaScriptSymbol: return tr("ASP JavaScript symbol"); case ASPJavaScriptUnclosedString: return tr("ASP JavaScript unclosed string"); case ASPJavaScriptRegex: return tr("ASP JavaScript regular expression"); case VBScriptStart: return tr("Start of a VBScript fragment"); case VBScriptDefault: return tr("VBScript default"); case VBScriptComment: return tr("VBScript comment"); case VBScriptNumber: return tr("VBScript number"); case VBScriptKeyword: return tr("VBScript keyword"); case VBScriptString: return tr("VBScript string"); case VBScriptIdentifier: return tr("VBScript identifier"); case VBScriptUnclosedString: return tr("VBScript unclosed string"); case ASPVBScriptStart: return tr("Start of an ASP VBScript fragment"); case ASPVBScriptDefault: return tr("ASP VBScript default"); case ASPVBScriptComment: return tr("ASP VBScript comment"); case ASPVBScriptNumber: return tr("ASP VBScript number"); case ASPVBScriptKeyword: return tr("ASP VBScript keyword"); case ASPVBScriptString: return tr("ASP VBScript string"); case ASPVBScriptIdentifier: return tr("ASP VBScript identifier"); case ASPVBScriptUnclosedString: return tr("ASP VBScript unclosed string"); case PythonStart: return tr("Start of a Python fragment"); case PythonDefault: return tr("Python default"); case PythonComment: return tr("Python comment"); case PythonNumber: return tr("Python number"); case PythonDoubleQuotedString: return tr("Python double-quoted string"); case PythonSingleQuotedString: return tr("Python single-quoted string"); case PythonKeyword: return tr("Python keyword"); case PythonTripleDoubleQuotedString: return tr("Python triple double-quoted string"); case PythonTripleSingleQuotedString: return tr("Python triple single-quoted string"); case PythonClassName: return tr("Python class name"); case PythonFunctionMethodName: return tr("Python function or method name"); case PythonOperator: return tr("Python operator"); case PythonIdentifier: return tr("Python identifier"); case ASPPythonStart: return tr("Start of an ASP Python fragment"); case ASPPythonDefault: return tr("ASP Python default"); case ASPPythonComment: return tr("ASP Python comment"); case ASPPythonNumber: return tr("ASP Python number"); case ASPPythonDoubleQuotedString: return tr("ASP Python double-quoted string"); case ASPPythonSingleQuotedString: return tr("ASP Python single-quoted string"); case ASPPythonKeyword: return tr("ASP Python keyword"); case ASPPythonTripleDoubleQuotedString: return tr("ASP Python triple double-quoted string"); case ASPPythonTripleSingleQuotedString: return tr("ASP Python triple single-quoted string"); case ASPPythonClassName: return tr("ASP Python class name"); case ASPPythonFunctionMethodName: return tr("ASP Python function or method name"); case ASPPythonOperator: return tr("ASP Python operator"); case ASPPythonIdentifier: return tr("ASP Python identifier"); case PHPDefault: return tr("PHP default"); case PHPDoubleQuotedString: return tr("PHP double-quoted string"); case PHPSingleQuotedString: return tr("PHP single-quoted string"); case PHPKeyword: return tr("PHP keyword"); case PHPNumber: return tr("PHP number"); case PHPVariable: return tr("PHP variable"); case PHPComment: return tr("PHP comment"); case PHPCommentLine: return tr("PHP line comment"); case PHPDoubleQuotedVariable: return tr("PHP double-quoted variable"); case PHPOperator: return tr("PHP operator"); } return QString(); } // Returns the background colour of the text for a style. QColor QsciLexerHTML::defaultPaper(int style) const { switch (style) { case ASPAtStart: return QColor(0xff,0xff,0x00); case ASPStart: case CDATA: return QColor(0xff,0xdf,0x00); case PHPStart: return QColor(0xff,0xef,0xbf); case HTMLValue: return QColor(0xff,0xef,0xff); case SGMLDefault: case SGMLCommand: case SGMLParameter: case SGMLDoubleQuotedString: case SGMLSingleQuotedString: case SGMLSpecial: case SGMLEntity: case SGMLComment: return QColor(0xef,0xef,0xff); case SGMLError: return QColor(0xff,0x66,0x66); case SGMLBlockDefault: return QColor(0xcc,0xcc,0xe0); case JavaScriptDefault: case JavaScriptComment: case JavaScriptCommentLine: case JavaScriptCommentDoc: case JavaScriptNumber: case JavaScriptWord: case JavaScriptKeyword: case JavaScriptDoubleQuotedString: case JavaScriptSingleQuotedString: case JavaScriptSymbol: return QColor(0xf0,0xf0,0xff); case JavaScriptUnclosedString: case ASPJavaScriptUnclosedString: return QColor(0xbf,0xbb,0xb0); case JavaScriptRegex: case ASPJavaScriptRegex: return QColor(0xff,0xbb,0xb0); case ASPJavaScriptDefault: case ASPJavaScriptComment: case ASPJavaScriptCommentLine: case ASPJavaScriptCommentDoc: case ASPJavaScriptNumber: case ASPJavaScriptWord: case ASPJavaScriptKeyword: case ASPJavaScriptDoubleQuotedString: case ASPJavaScriptSingleQuotedString: case ASPJavaScriptSymbol: return QColor(0xdf,0xdf,0x7f); case VBScriptDefault: case VBScriptComment: case VBScriptNumber: case VBScriptKeyword: case VBScriptString: case VBScriptIdentifier: return QColor(0xef,0xef,0xff); case VBScriptUnclosedString: case ASPVBScriptUnclosedString: return QColor(0x7f,0x7f,0xff); case ASPVBScriptDefault: case ASPVBScriptComment: case ASPVBScriptNumber: case ASPVBScriptKeyword: case ASPVBScriptString: case ASPVBScriptIdentifier: return QColor(0xcf,0xcf,0xef); case PythonDefault: case PythonComment: case PythonNumber: case PythonDoubleQuotedString: case PythonSingleQuotedString: case PythonKeyword: case PythonTripleSingleQuotedString: case PythonTripleDoubleQuotedString: case PythonClassName: case PythonFunctionMethodName: case PythonOperator: case PythonIdentifier: return QColor(0xef,0xff,0xef); case ASPPythonDefault: case ASPPythonComment: case ASPPythonNumber: case ASPPythonDoubleQuotedString: case ASPPythonSingleQuotedString: case ASPPythonKeyword: case ASPPythonTripleSingleQuotedString: case ASPPythonTripleDoubleQuotedString: case ASPPythonClassName: case ASPPythonFunctionMethodName: case ASPPythonOperator: case ASPPythonIdentifier: return QColor(0xcf,0xef,0xcf); case PHPDefault: case PHPDoubleQuotedString: case PHPSingleQuotedString: case PHPKeyword: case PHPNumber: case PHPVariable: case PHPComment: case PHPCommentLine: case PHPDoubleQuotedVariable: case PHPOperator: return QColor(0xff,0xf8,0xf8); } return QsciLexer::defaultPaper(style); } // Refresh all properties. void QsciLexerHTML::refreshProperties() { setCompactProp(); setPreprocProp(); setCaseSensTagsProp(); setScriptCommentsProp(); setScriptHeredocsProp(); setDjangoProp(); setMakoProp(); } // Read properties from the settings. bool QsciLexerHTML::readProperties(QSettings &qs,const QString &prefix) { int rc = true; fold_compact = qs.value(prefix + "foldcompact", true).toBool(); fold_preproc = qs.value(prefix + "foldpreprocessor", false).toBool(); case_sens_tags = qs.value(prefix + "casesensitivetags", false).toBool(); fold_script_comments = qs.value(prefix + "foldscriptcomments", false).toBool(); fold_script_heredocs = qs.value(prefix + "foldscriptheredocs", false).toBool(); django_templates = qs.value(prefix + "djangotemplates", false).toBool(); mako_templates = qs.value(prefix + "makotemplates", false).toBool(); return rc; } // Write properties to the settings. bool QsciLexerHTML::writeProperties(QSettings &qs,const QString &prefix) const { int rc = true; qs.setValue(prefix + "foldcompact", fold_compact); qs.setValue(prefix + "foldpreprocessor", fold_preproc); qs.setValue(prefix + "casesensitivetags", case_sens_tags); qs.setValue(prefix + "foldscriptcomments", fold_script_comments); qs.setValue(prefix + "foldscriptheredocs", fold_script_heredocs); qs.setValue(prefix + "djangotemplates", django_templates); qs.setValue(prefix + "makotemplates", mako_templates); return rc; } // Set if tags are case sensitive. void QsciLexerHTML::setCaseSensitiveTags(bool sens) { case_sens_tags = sens; setCaseSensTagsProp(); } // Set the "html.tags.case.sensitive" property. void QsciLexerHTML::setCaseSensTagsProp() { emit propertyChanged("html.tags.case.sensitive",(case_sens_tags ? "1" : "0")); } // Set if folds are compact void QsciLexerHTML::setFoldCompact(bool fold) { fold_compact = fold; setCompactProp(); } // Set the "fold.compact" property. void QsciLexerHTML::setCompactProp() { emit propertyChanged("fold.compact",(fold_compact ? "1" : "0")); } // Set if preprocessor blocks can be folded. void QsciLexerHTML::setFoldPreprocessor(bool fold) { fold_preproc = fold; setPreprocProp(); } // Set the "fold.html.preprocessor" property. void QsciLexerHTML::setPreprocProp() { emit propertyChanged("fold.html.preprocessor",(fold_preproc ? "1" : "0")); } // Set if script comments can be folded. void QsciLexerHTML::setFoldScriptComments(bool fold) { fold_script_comments = fold; setScriptCommentsProp(); } // Set the "fold.hypertext.comment" property. void QsciLexerHTML::setScriptCommentsProp() { emit propertyChanged("fold.hypertext.comment",(fold_script_comments ? "1" : "0")); } // Set if script heredocs can be folded. void QsciLexerHTML::setFoldScriptHeredocs(bool fold) { fold_script_heredocs = fold; setScriptHeredocsProp(); } // Set the "fold.hypertext.heredoc" property. void QsciLexerHTML::setScriptHeredocsProp() { emit propertyChanged("fold.hypertext.heredoc",(fold_script_heredocs ? "1" : "0")); } // Set if Django templates are supported. void QsciLexerHTML::setDjangoTemplates(bool enable) { django_templates = enable; setDjangoProp(); } // Set the "lexer.html.django" property. void QsciLexerHTML::setDjangoProp() { emit propertyChanged("lexer.html.django", (django_templates ? "1" : "0")); } // Set if Mako templates are supported. void QsciLexerHTML::setMakoTemplates(bool enable) { mako_templates = enable; setMakoProp(); } // Set the "lexer.html.mako" property. void QsciLexerHTML::setMakoProp() { emit propertyChanged("lexer.html.mako", (mako_templates ? "1" : "0")); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscilexerjavascript.cpp000066400000000000000000000062071463772530400306310ustar00rootroot00000000000000// This module implements the QsciLexerJavaScript class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscilexerjavascript.h" #include #include // The list of JavaScript keywords that can be used by other friendly lexers. const char *QsciLexerJavaScript::keywordClass = "abstract boolean break byte case catch char class const continue " "debugger default delete do double else enum export extends final " "finally float for function goto if implements import in instanceof " "int interface long native new package private protected public " "return short static super switch synchronized this throw throws " "transient try typeof var void volatile while with"; // The ctor. QsciLexerJavaScript::QsciLexerJavaScript(QObject *parent) : QsciLexerCPP(parent) { } // The dtor. QsciLexerJavaScript::~QsciLexerJavaScript() { } // Returns the language name. const char *QsciLexerJavaScript::language() const { return "JavaScript"; } // Returns the foreground colour of the text for a style. QColor QsciLexerJavaScript::defaultColor(int style) const { if (style == Regex) return QColor(0x3f,0x7f,0x3f); return QsciLexerCPP::defaultColor(style); } // Returns the end-of-line fill for a style. bool QsciLexerJavaScript::defaultEolFill(int style) const { if (style == Regex) return true; return QsciLexerCPP::defaultEolFill(style); } // Returns the font of the text for a style. QFont QsciLexerJavaScript::defaultFont(int style) const { if (style == Regex) #if defined(Q_OS_WIN) return QFont("Courier New",10); #elif defined(Q_OS_MAC) return QFont("Courier", 12); #else return QFont("Bitstream Vera Sans Mono",9); #endif return QsciLexerCPP::defaultFont(style); } // Returns the set of keywords. const char *QsciLexerJavaScript::keywords(int set) const { if (set != 1) return 0; return keywordClass; } // Returns the user name of a style. QString QsciLexerJavaScript::description(int style) const { if (style == Regex) return tr("Regular expression"); return QsciLexerCPP::description(style); } // Returns the background colour of the text for a style. QColor QsciLexerJavaScript::defaultPaper(int style) const { if (style == Regex) return QColor(0xe0,0xf0,0xff); return QsciLexer::defaultPaper(style); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscilexerjson.cpp000066400000000000000000000142151463772530400274320ustar00rootroot00000000000000// This module implements the QsciLexerJSON class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscilexerjson.h" #include #include #include // The ctor. QsciLexerJSON::QsciLexerJSON(QObject *parent) : QsciLexer(parent), allow_comments(true), escape_sequence(true), fold_compact(true) { } // The dtor. QsciLexerJSON::~QsciLexerJSON() { } // Returns the language name. const char *QsciLexerJSON::language() const { return "JSON"; } // Returns the lexer name. const char *QsciLexerJSON::lexer() const { return "json"; } // Returns the foreground colour of the text for a style. QColor QsciLexerJSON::defaultColor(int style) const { switch (style) { case UnclosedString: case Error: return QColor(0xff, 0xff, 0xff); case Number: return QColor(0x00, 0x7f, 0x7f); case String: return QColor(0x7f, 0x00, 0x00); case Property: return QColor(0x88, 0x0a, 0xe8); case EscapeSequence: return QColor(0x0b, 0x98, 0x2e); case CommentLine: case CommentBlock: return QColor(0x05, 0xbb, 0xae); case Operator: return QColor(0x18, 0x64, 0x4a); case IRI: return QColor(0x00, 0x00, 0xff); case IRICompact: return QColor(0xd1, 0x37, 0xc1); case Keyword: return QColor(0x0b, 0xce, 0xa7); case KeywordLD: return QColor(0xec, 0x28, 0x06); } return QsciLexer::defaultColor(style); } // Returns the end-of-line fill for a style. bool QsciLexerJSON::defaultEolFill(int style) const { switch (style) { case UnclosedString: return true; } return QsciLexer::defaultEolFill(style); } // Returns the font of the text for a style. QFont QsciLexerJSON::defaultFont(int style) const { QFont f; switch (style) { case CommentLine: f = QsciLexer::defaultFont(style); f.setItalic(true); break; case Keyword: f = QsciLexer::defaultFont(style); f.setBold(true); break; default: f = QsciLexer::defaultFont(style); } return f; } // Returns the set of keywords. const char *QsciLexerJSON::keywords(int set) const { if (set == 1) return "false true null"; if (set == 2) return "@id @context @type @value @language @container @list @set " "@reverse @index @base @vocab @graph"; return 0; } // Returns the user name of a style. QString QsciLexerJSON::description(int style) const { switch (style) { case Default: return tr("Default"); case Number: return tr("Number"); case String: return tr("String"); case UnclosedString: return tr("Unclosed string"); case Property: return tr("Property"); case EscapeSequence: return tr("Escape sequence"); case CommentLine: return tr("Line comment"); case CommentBlock: return tr("Block comment"); case Operator: return tr("Operator"); case IRI: return tr("IRI"); case IRICompact: return tr("JSON-LD compact IRI"); case Keyword: return tr("JSON keyword"); case KeywordLD: return tr("JSON-LD keyword"); case Error: return tr("Parsing error"); } return QString(); } // Returns the background colour of the text for a style. QColor QsciLexerJSON::defaultPaper(int style) const { switch (style) { case UnclosedString: case Error: return QColor(0xff, 0x00, 0x00); } return QsciLexer::defaultPaper(style); } // Refresh all properties. void QsciLexerJSON::refreshProperties() { setAllowCommentsProp(); setEscapeSequenceProp(); setCompactProp(); } // Read properties from the settings. bool QsciLexerJSON::readProperties(QSettings &qs,const QString &prefix) { allow_comments = qs.value(prefix + "allowcomments", true).toBool(); escape_sequence = qs.value(prefix + "escapesequence", true).toBool(); fold_compact = qs.value(prefix + "foldcompact", true).toBool(); return true; } // Write properties to the settings. bool QsciLexerJSON::writeProperties(QSettings &qs,const QString &prefix) const { qs.setValue(prefix + "allowcomments", allow_comments); qs.setValue(prefix + "escapesequence", escape_sequence); qs.setValue(prefix + "foldcompact", fold_compact); return true; } // Set if comments are highlighted void QsciLexerJSON::setHighlightComments(bool highlight) { allow_comments = highlight; setAllowCommentsProp(); } // Set the "lexer.json.allow.comments" property. void QsciLexerJSON::setAllowCommentsProp() { emit propertyChanged("lexer.json.allow.comments", (allow_comments ? "1" : "0")); } // Set if escape sequences are highlighted. void QsciLexerJSON::setHighlightEscapeSequences(bool highlight) { escape_sequence = highlight; setEscapeSequenceProp(); } // Set the "lexer.json.escape.sequence" property. void QsciLexerJSON::setEscapeSequenceProp() { emit propertyChanged("lexer.json.escape.sequence", (escape_sequence ? "1" : "0")); } // Set if folds are compact. void QsciLexerJSON::setFoldCompact(bool fold) { fold_compact = fold; setCompactProp(); } // Set the "fold.compact" property. void QsciLexerJSON::setCompactProp() { emit propertyChanged("fold.compact", (fold_compact ? "1" : "0")); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscilexerpython.cpp000066400000000000000000000270271463772530400300070ustar00rootroot00000000000000// This module implements the QsciLexerPython class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscilexerpython.h" #include #include #include // The list of Python keywords that can be used by other friendly lexers. const char *QsciLexerPython::keywordClass = "and as assert break class continue def del elif else except exec " "finally for from global if import in is lambda None not or pass " "print raise return try while with yield"; // The ctor. QsciLexerPython::QsciLexerPython(QObject *parent) : QsciLexer(parent), fold_comments(false), fold_compact(true), fold_quotes(false), indent_warn(NoWarning), strings_over_newline(false), v2_unicode(true), v3_binary_octal(true), v3_bytes(true), highlight_subids(true) { } // The dtor. QsciLexerPython::~QsciLexerPython() { } // Returns the language name. const char *QsciLexerPython::language() const { return "Python"; } // Returns the lexer name. const char *QsciLexerPython::lexer() const { return "python"; } // Return the view used for indentation guides. int QsciLexerPython::indentationGuideView() const { return QsciScintillaBase::SC_IV_LOOKFORWARD; } // Return the set of character sequences that can separate auto-completion // words. QStringList QsciLexerPython::autoCompletionWordSeparators() const { QStringList wl; wl << "."; return wl; } // Return the list of characters that can start a block. const char *QsciLexerPython::blockStart(int *style) const { if (style) *style = Operator; return ":"; } // Return the number of lines to look back when auto-indenting. int QsciLexerPython::blockLookback() const { // This must be 0 otherwise de-indenting a Python block gets very // difficult. return 0; } // Return the style used for braces. int QsciLexerPython::braceStyle() const { return Operator; } // Returns the foreground colour of the text for a style. QColor QsciLexerPython::defaultColor(int style) const { switch (style) { case Default: return QColor(0x80,0x80,0x80); case Comment: return QColor(0x00,0x7f,0x00); case Number: return QColor(0x00,0x7f,0x7f); case DoubleQuotedString: case SingleQuotedString: case DoubleQuotedFString: case SingleQuotedFString: return QColor(0x7f,0x00,0x7f); case Keyword: return QColor(0x00,0x00,0x7f); case TripleSingleQuotedString: case TripleDoubleQuotedString: case TripleSingleQuotedFString: case TripleDoubleQuotedFString: return QColor(0x7f,0x00,0x00); case ClassName: return QColor(0x00,0x00,0xff); case FunctionMethodName: return QColor(0x00,0x7f,0x7f); case Operator: case Identifier: break; case CommentBlock: return QColor(0x7f,0x7f,0x7f); case UnclosedString: return QColor(0x00,0x00,0x00); case HighlightedIdentifier: return QColor(0x40,0x70,0x90); case Decorator: return QColor(0x80,0x50,0x00); } return QsciLexer::defaultColor(style); } // Returns the end-of-line fill for a style. bool QsciLexerPython::defaultEolFill(int style) const { if (style == UnclosedString) return true; return QsciLexer::defaultEolFill(style); } // Returns the font of the text for a style. QFont QsciLexerPython::defaultFont(int style) const { QFont f; switch (style) { case Comment: #if defined(Q_OS_WIN) f = QFont("Comic Sans MS",9); #elif defined(Q_OS_MAC) f = QFont("Comic Sans MS", 12); #else f = QFont("Bitstream Vera Serif",9); #endif break; case DoubleQuotedString: case SingleQuotedString: case DoubleQuotedFString: case SingleQuotedFString: case UnclosedString: #if defined(Q_OS_WIN) f = QFont("Courier New",10); #elif defined(Q_OS_MAC) f = QFont("Courier", 12); #else f = QFont("Bitstream Vera Sans Mono",9); #endif break; case Keyword: case ClassName: case FunctionMethodName: case Operator: f = QsciLexer::defaultFont(style); f.setBold(true); break; default: f = QsciLexer::defaultFont(style); } return f; } // Returns the set of keywords. const char *QsciLexerPython::keywords(int set) const { if (set != 1) return 0; return keywordClass; } // Returns the user name of a style. QString QsciLexerPython::description(int style) const { switch (style) { case Default: return tr("Default"); case Comment: return tr("Comment"); case Number: return tr("Number"); case DoubleQuotedString: return tr("Double-quoted string"); case SingleQuotedString: return tr("Single-quoted string"); case Keyword: return tr("Keyword"); case TripleSingleQuotedString: return tr("Triple single-quoted string"); case TripleDoubleQuotedString: return tr("Triple double-quoted string"); case ClassName: return tr("Class name"); case FunctionMethodName: return tr("Function or method name"); case Operator: return tr("Operator"); case Identifier: return tr("Identifier"); case CommentBlock: return tr("Comment block"); case UnclosedString: return tr("Unclosed string"); case HighlightedIdentifier: return tr("Highlighted identifier"); case Decorator: return tr("Decorator"); case DoubleQuotedFString: return tr("Double-quoted f-string"); case SingleQuotedFString: return tr("Single-quoted f-string"); case TripleSingleQuotedFString: return tr("Triple single-quoted f-string"); case TripleDoubleQuotedFString: return tr("Triple double-quoted f-string"); } return QString(); } // Returns the background colour of the text for a style. QColor QsciLexerPython::defaultPaper(int style) const { if (style == UnclosedString) return QColor(0xe0,0xc0,0xe0); return QsciLexer::defaultPaper(style); } // Refresh all properties. void QsciLexerPython::refreshProperties() { setCommentProp(); setCompactProp(); setQuotesProp(); setTabWhingeProp(); setStringsOverNewlineProp(); setV2UnicodeProp(); setV3BinaryOctalProp(); setV3BytesProp(); setHighlightSubidsProp(); } // Read properties from the settings. bool QsciLexerPython::readProperties(QSettings &qs,const QString &prefix) { int rc = true; fold_comments = qs.value(prefix + "foldcomments", false).toBool(); fold_compact = qs.value(prefix + "foldcompact", true).toBool(); fold_quotes = qs.value(prefix + "foldquotes", false).toBool(); indent_warn = (IndentationWarning)qs.value(prefix + "indentwarning", (int)NoWarning).toInt(); strings_over_newline = qs.value(prefix + "stringsovernewline", false).toBool(); v2_unicode = qs.value(prefix + "v2unicode", true).toBool(); v3_binary_octal = qs.value(prefix + "v3binaryoctal", true).toBool(); v3_bytes = qs.value(prefix + "v3bytes", true).toBool(); highlight_subids = qs.value(prefix + "highlightsubids", true).toBool(); return rc; } // Write properties to the settings. bool QsciLexerPython::writeProperties(QSettings &qs,const QString &prefix) const { int rc = true; qs.setValue(prefix + "foldcomments", fold_comments); qs.setValue(prefix + "foldcompact", fold_compact); qs.setValue(prefix + "foldquotes", fold_quotes); qs.setValue(prefix + "indentwarning", (int)indent_warn); qs.setValue(prefix + "stringsovernewline", strings_over_newline); qs.setValue(prefix + "v2unicode", v2_unicode); qs.setValue(prefix + "v3binaryoctal", v3_binary_octal); qs.setValue(prefix + "v3bytes", v3_bytes); qs.setValue(prefix + "highlightsubids", highlight_subids); return rc; } // Set if comments can be folded. void QsciLexerPython::setFoldComments(bool fold) { fold_comments = fold; setCommentProp(); } // Set the "fold.comment.python" property. void QsciLexerPython::setCommentProp() { emit propertyChanged("fold.comment.python",(fold_comments ? "1" : "0")); } // Set if folds are compact. void QsciLexerPython::setFoldCompact(bool fold) { fold_compact = fold; setCompactProp(); } // Set the "fold.compact" property. void QsciLexerPython::setCompactProp() { emit propertyChanged("fold.compact",(fold_compact ? "1" : "0")); } // Set if quotes can be folded. void QsciLexerPython::setFoldQuotes(bool fold) { fold_quotes = fold; setQuotesProp(); } // Set the "fold.quotes.python" property. void QsciLexerPython::setQuotesProp() { emit propertyChanged("fold.quotes.python",(fold_quotes ? "1" : "0")); } // Set the indentation warning. void QsciLexerPython::setIndentationWarning(QsciLexerPython::IndentationWarning warn) { indent_warn = warn; setTabWhingeProp(); } // Set the "tab.timmy.whinge.level" property. void QsciLexerPython::setTabWhingeProp() { emit propertyChanged("tab.timmy.whinge.level", QByteArray::number(indent_warn)); } // Set if string literals can span newlines. void QsciLexerPython::setStringsOverNewlineAllowed(bool allowed) { strings_over_newline = allowed; setStringsOverNewlineProp(); } // Set the "lexer.python.strings.u" property. void QsciLexerPython::setStringsOverNewlineProp() { emit propertyChanged("lexer.python.strings.over.newline", (strings_over_newline ? "1" : "0")); } // Set if v2 unicode string literals are allowed. void QsciLexerPython::setV2UnicodeAllowed(bool allowed) { v2_unicode = allowed; setV2UnicodeProp(); } // Set the "lexer.python.strings.u" property. void QsciLexerPython::setV2UnicodeProp() { emit propertyChanged("lexer.python.strings.u", (v2_unicode ? "1" : "0")); } // Set if v3 binary and octal literals are allowed. void QsciLexerPython::setV3BinaryOctalAllowed(bool allowed) { v3_binary_octal = allowed; setV3BinaryOctalProp(); } // Set the "lexer.python.literals.binary" property. void QsciLexerPython::setV3BinaryOctalProp() { emit propertyChanged("lexer.python.literals.binary", (v3_binary_octal ? "1" : "0")); } // Set if v3 bytes string literals are allowed. void QsciLexerPython::setV3BytesAllowed(bool allowed) { v3_bytes = allowed; setV3BytesProp(); } // Set the "lexer.python.strings.b" property. void QsciLexerPython::setV3BytesProp() { emit propertyChanged("lexer.python.strings.b",(v3_bytes ? "1" : "0")); } // Set if sub-identifiers are highlighted. void QsciLexerPython::setHighlightSubidentifiers(bool enabled) { highlight_subids = enabled; setHighlightSubidsProp(); } // Set the "lexer.python.keywords2.no.sub.identifiers" property. void QsciLexerPython::setHighlightSubidsProp() { emit propertyChanged("lexer.python.keywords2.no.sub.identifiers", (highlight_subids ? "0" : "1")); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscilexersql.cpp000066400000000000000000000326211463772530400272610ustar00rootroot00000000000000// This module implements the QsciLexerSQL class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscilexersql.h" #include #include #include // The ctor. QsciLexerSQL::QsciLexerSQL(QObject *parent) : QsciLexer(parent), at_else(false), fold_comments(false), fold_compact(true), only_begin(false), backticks_identifier(false), numbersign_comment(false), backslash_escapes(false), allow_dotted_word(false) { } // The dtor. QsciLexerSQL::~QsciLexerSQL() { } // Returns the language name. const char *QsciLexerSQL::language() const { return "SQL"; } // Returns the lexer name. const char *QsciLexerSQL::lexer() const { return "sql"; } // Return the style used for braces. int QsciLexerSQL::braceStyle() const { return Operator; } // Returns the foreground colour of the text for a style. QColor QsciLexerSQL::defaultColor(int style) const { switch (style) { case Default: return QColor(0x80,0x80,0x80); case Comment: case CommentLine: case PlusPrompt: case PlusComment: case CommentLineHash: return QColor(0x00,0x7f,0x00); case CommentDoc: return QColor(0x7f,0x7f,0x7f); case Number: return QColor(0x00,0x7f,0x7f); case Keyword: return QColor(0x00,0x00,0x7f); case DoubleQuotedString: case SingleQuotedString: return QColor(0x7f,0x00,0x7f); case PlusKeyword: return QColor(0x7f,0x7f,0x00); case Operator: case Identifier: break; case CommentDocKeyword: return QColor(0x30,0x60,0xa0); case CommentDocKeywordError: return QColor(0x80,0x40,0x20); case KeywordSet5: return QColor(0x4b,0x00,0x82); case KeywordSet6: return QColor(0xb0,0x00,0x40); case KeywordSet7: return QColor(0x8b,0x00,0x00); case KeywordSet8: return QColor(0x80,0x00,0x80); } return QsciLexer::defaultColor(style); } // Returns the end-of-line fill for a style. bool QsciLexerSQL::defaultEolFill(int style) const { if (style == PlusPrompt) return true; return QsciLexer::defaultEolFill(style); } // Returns the font of the text for a style. QFont QsciLexerSQL::defaultFont(int style) const { QFont f; switch (style) { case Comment: case CommentLine: case PlusComment: case CommentLineHash: case CommentDocKeyword: case CommentDocKeywordError: #if defined(Q_OS_WIN) f = QFont("Comic Sans MS",9); #elif defined(Q_OS_MAC) f = QFont("Comic Sans MS", 12); #else f = QFont("Bitstream Vera Serif",9); #endif break; case Keyword: case Operator: f = QsciLexer::defaultFont(style); f.setBold(true); break; case DoubleQuotedString: case SingleQuotedString: case PlusPrompt: #if defined(Q_OS_WIN) f = QFont("Courier New",10); #elif defined(Q_OS_MAC) f = QFont("Courier", 12); #else f = QFont("Bitstream Vera Sans Mono",9); #endif break; default: f = QsciLexer::defaultFont(style); } return f; } // Returns the set of keywords. const char *QsciLexerSQL::keywords(int set) const { if (set == 1) return "absolute action add admin after aggregate alias all " "allocate alter and any are array as asc assertion " "at authorization before begin binary bit blob " "boolean both breadth by call cascade cascaded case " "cast catalog char character check class clob close " "collate collation column commit completion connect " "connection constraint constraints constructor " "continue corresponding create cross cube current " "current_date current_path current_role current_time " "current_timestamp current_user cursor cycle data " "date day deallocate dec decimal declare default " "deferrable deferred delete depth deref desc " "describe descriptor destroy destructor " "deterministic dictionary diagnostics disconnect " "distinct domain double drop dynamic each else end " "end-exec equals escape every except exception exec " "execute external false fetch first float for " "foreign found from free full function general get " "global go goto grant group grouping having host " "hour identity if ignore immediate in indicator " "initialize initially inner inout input insert int " "integer intersect interval into is isolation " "iterate join key language large last lateral " "leading left less level like limit local localtime " "localtimestamp locator map match minute modifies " "modify module month names national natural nchar " "nclob new next no none not null numeric object of " "off old on only open operation option or order " "ordinality out outer output pad parameter " "parameters partial path postfix precision prefix " "preorder prepare preserve primary prior privileges " "procedure public read reads real recursive ref " "references referencing relative restrict result " "return returns revoke right role rollback rollup " "routine row rows savepoint schema scroll scope " "search second section select sequence session " "session_user set sets size smallint some| space " "specific specifictype sql sqlexception sqlstate " "sqlwarning start state statement static structure " "system_user table temporary terminate than then " "time timestamp timezone_hour timezone_minute to " "trailing transaction translation treat trigger " "true under union unique unknown unnest update usage " "user using value values varchar variable varying " "view when whenever where with without work write " "year zone"; if (set == 3) return "param author since return see deprecated todo"; if (set == 4) return "acc~ept a~ppend archive log attribute bre~ak " "bti~tle c~hange cl~ear col~umn comp~ute conn~ect " "copy def~ine del desc~ribe disc~onnect e~dit " "exec~ute exit get help ho~st i~nput l~ist passw~ord " "pau~se pri~nt pro~mpt quit recover rem~ark " "repf~ooter reph~eader r~un sav~e set sho~w shutdown " "spo~ol sta~rt startup store timi~ng tti~tle " "undef~ine var~iable whenever oserror whenever " "sqlerror"; if (set == 5) return "dbms_output.disable dbms_output.enable dbms_output.get_line " "dbms_output.get_lines dbms_output.new_line dbms_output.put " "dbms_output.put_line"; return 0; } // Returns the user name of a style. QString QsciLexerSQL::description(int style) const { switch (style) { case Default: return tr("Default"); case Comment: return tr("Comment"); case CommentLine: return tr("Comment line"); case CommentDoc: return tr("JavaDoc style comment"); case Number: return tr("Number"); case Keyword: return tr("Keyword"); case DoubleQuotedString: return tr("Double-quoted string"); case SingleQuotedString: return tr("Single-quoted string"); case PlusKeyword: return tr("SQL*Plus keyword"); case PlusPrompt: return tr("SQL*Plus prompt"); case Operator: return tr("Operator"); case Identifier: return tr("Identifier"); case PlusComment: return tr("SQL*Plus comment"); case CommentLineHash: return tr("# comment line"); case CommentDocKeyword: return tr("JavaDoc keyword"); case CommentDocKeywordError: return tr("JavaDoc keyword error"); case KeywordSet5: return tr("User defined 1"); case KeywordSet6: return tr("User defined 2"); case KeywordSet7: return tr("User defined 3"); case KeywordSet8: return tr("User defined 4"); case QuotedIdentifier: return tr("Quoted identifier"); case QuotedOperator: return tr("Quoted operator"); } return QString(); } // Returns the background colour of the text for a style. QColor QsciLexerSQL::defaultPaper(int style) const { if (style == PlusPrompt) return QColor(0xe0,0xff,0xe0); return QsciLexer::defaultPaper(style); } // Refresh all properties. void QsciLexerSQL::refreshProperties() { setAtElseProp(); setCommentProp(); setCompactProp(); setOnlyBeginProp(); setBackticksIdentifierProp(); setNumbersignCommentProp(); setBackslashEscapesProp(); setAllowDottedWordProp(); } // Read properties from the settings. bool QsciLexerSQL::readProperties(QSettings &qs, const QString &prefix) { int rc = true; at_else = qs.value(prefix + "atelse", false).toBool(); fold_comments = qs.value(prefix + "foldcomments", false).toBool(); fold_compact = qs.value(prefix + "foldcompact", true).toBool(); only_begin = qs.value(prefix + "onlybegin", false).toBool(); backticks_identifier = qs.value(prefix + "backticksidentifier", false).toBool(); numbersign_comment = qs.value(prefix + "numbersigncomment", false).toBool(); backslash_escapes = qs.value(prefix + "backslashescapes", false).toBool(); allow_dotted_word = qs.value(prefix + "allowdottedword", false).toBool(); return rc; } // Write properties to the settings. bool QsciLexerSQL::writeProperties(QSettings &qs, const QString &prefix) const { int rc = true; qs.value(prefix + "atelse", at_else); qs.value(prefix + "foldcomments", fold_comments); qs.value(prefix + "foldcompact", fold_compact); qs.value(prefix + "onlybegin", only_begin); qs.value(prefix + "backticksidentifier", backticks_identifier); qs.value(prefix + "numbersigncomment", numbersign_comment); qs.value(prefix + "backslashescapes", backslash_escapes); qs.value(prefix + "allowdottedword", allow_dotted_word); return rc; } // Set if ELSE blocks can be folded. void QsciLexerSQL::setFoldAtElse(bool fold) { at_else = fold; setAtElseProp(); } // Set the "fold.sql.at.else" property. void QsciLexerSQL::setAtElseProp() { emit propertyChanged("fold.sql.at.else", (at_else ? "1" : "0")); } // Set if comments can be folded. void QsciLexerSQL::setFoldComments(bool fold) { fold_comments = fold; setCommentProp(); } // Set the "fold.comment" property. void QsciLexerSQL::setCommentProp() { emit propertyChanged("fold.comment", (fold_comments ? "1" : "0")); } // Set if folds are compact void QsciLexerSQL::setFoldCompact(bool fold) { fold_compact = fold; setCompactProp(); } // Set the "fold.compact" property. void QsciLexerSQL::setCompactProp() { emit propertyChanged("fold.compact", (fold_compact ? "1" : "0")); } // Set if BEGIN blocks only can be folded. void QsciLexerSQL::setFoldOnlyBegin(bool fold) { only_begin = fold; setOnlyBeginProp(); } // Set the "fold.sql.only.begin" property. void QsciLexerSQL::setOnlyBeginProp() { emit propertyChanged("fold.sql.only.begin", (only_begin ? "1" : "0")); } // Enable quoted identifiers. void QsciLexerSQL::setQuotedIdentifiers(bool enable) { backticks_identifier = enable; setBackticksIdentifierProp(); } // Set the "lexer.sql.backticks.identifier" property. void QsciLexerSQL::setBackticksIdentifierProp() { emit propertyChanged("lexer.sql.backticks.identifier", (backticks_identifier ? "1" : "0")); } // Enable '#' as a comment character. void QsciLexerSQL::setHashComments(bool enable) { numbersign_comment = enable; setNumbersignCommentProp(); } // Set the "lexer.sql.numbersign.comment" property. void QsciLexerSQL::setNumbersignCommentProp() { emit propertyChanged("lexer.sql.numbersign.comment", (numbersign_comment ? "1" : "0")); } // Enable/disable backslash escapes. void QsciLexerSQL::setBackslashEscapes(bool enable) { backslash_escapes = enable; setBackslashEscapesProp(); } // Set the "sql.backslash.escapes" property. void QsciLexerSQL::setBackslashEscapesProp() { emit propertyChanged("sql.backslash.escapes", (backslash_escapes ? "1" : "0")); } // Enable dotted words. void QsciLexerSQL::setDottedWords(bool enable) { allow_dotted_word = enable; setAllowDottedWordProp(); } // Set the "lexer.sql.allow.dotted.word" property. void QsciLexerSQL::setAllowDottedWordProp() { emit propertyChanged("lexer.sql.allow.dotted.word", (allow_dotted_word ? "1" : "0")); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscilexerxml.cpp000066400000000000000000000122431463772530400272600ustar00rootroot00000000000000// This module implements the QsciLexerXML class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscilexerxml.h" #include #include #include // The ctor. QsciLexerXML::QsciLexerXML(QObject *parent) : QsciLexerHTML(parent), scripts(true) { } // The dtor. QsciLexerXML::~QsciLexerXML() { } // Returns the language name. const char *QsciLexerXML::language() const { return "XML"; } // Returns the lexer name. const char *QsciLexerXML::lexer() const { return "xml"; } // Returns the foreground colour of the text for a style. QColor QsciLexerXML::defaultColor(int style) const { switch (style) { case Default: return QColor(0x00,0x00,0x00); case Tag: case UnknownTag: case XMLTagEnd: case SGMLDefault: case SGMLCommand: return QColor(0x00,0x00,0x80); case Attribute: case UnknownAttribute: return QColor(0x00,0x80,0x80); case HTMLNumber: return QColor(0x00,0x7f,0x7f); case HTMLDoubleQuotedString: case HTMLSingleQuotedString: return QColor(0x7f,0x00,0x7f); case OtherInTag: case Entity: case XMLStart: case XMLEnd: return QColor(0x80,0x00,0x80); case HTMLComment: case SGMLComment: return QColor(0x80,0x80,0x00); case CDATA: case PHPStart: case SGMLDoubleQuotedString: case SGMLError: return QColor(0x80,0x00,0x00); case HTMLValue: return QColor(0x60,0x80,0x60); case SGMLParameter: return QColor(0x00,0x66,0x00); case SGMLSingleQuotedString: return QColor(0x99,0x33,0x00); case SGMLSpecial: return QColor(0x33,0x66,0xff); case SGMLEntity: return QColor(0x33,0x33,0x33); case SGMLBlockDefault: return QColor(0x00,0x00,0x66); } return QsciLexerHTML::defaultColor(style); } // Returns the end-of-line fill for a style. bool QsciLexerXML::defaultEolFill(int style) const { if (style == CDATA) return true; return QsciLexerHTML::defaultEolFill(style); } // Returns the font of the text for a style. QFont QsciLexerXML::defaultFont(int style) const { QFont f; switch (style) { case Default: case Entity: case CDATA: #if defined(Q_OS_WIN) f = QFont("Times New Roman",11); #elif defined(Q_OS_MAC) f = QFont("Times New Roman", 12); #else f = QFont("Bitstream Charter",10); #endif break; case XMLStart: case XMLEnd: case SGMLCommand: f = QsciLexer::defaultFont(style); f.setBold(true); break; default: f = QsciLexerHTML::defaultFont(style); } return f; } // Returns the set of keywords. const char *QsciLexerXML::keywords(int set) const { if (set == 6) return QsciLexerHTML::keywords(set); return 0; } // Returns the background colour of the text for a style. QColor QsciLexerXML::defaultPaper(int style) const { switch (style) { case CDATA: return QColor(0xff,0xf0,0xf0); case SGMLDefault: case SGMLCommand: case SGMLParameter: case SGMLDoubleQuotedString: case SGMLSingleQuotedString: case SGMLSpecial: case SGMLEntity: case SGMLComment: return QColor(0xef,0xef,0xff); case SGMLError: return QColor(0xff,0x66,0x66); case SGMLBlockDefault: return QColor(0xcc,0xcc,0xe0); } return QsciLexerHTML::defaultPaper(style); } // Refresh all properties. void QsciLexerXML::refreshProperties() { setScriptsProp(); } // Read properties from the settings. bool QsciLexerXML::readProperties(QSettings &qs, const QString &prefix) { int rc = QsciLexerHTML::readProperties(qs, prefix); scripts = qs.value(prefix + "scriptsstyled", true).toBool(); return rc; } // Write properties to the settings. bool QsciLexerXML::writeProperties(QSettings &qs, const QString &prefix) const { int rc = QsciLexerHTML::writeProperties(qs, prefix); qs.setValue(prefix + "scriptsstyled", scripts); return rc; } // Return true if scripts are styled. bool QsciLexerXML::scriptsStyled() const { return scripts; } // Set if scripts are styled. void QsciLexerXML::setScriptsStyled(bool styled) { scripts = styled; setScriptsProp(); } // Set the "lexer.xml.allow.scripts" property. void QsciLexerXML::setScriptsProp() { emit propertyChanged("lexer.xml.allow.scripts",(scripts ? "1" : "0")); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscimacro.cpp000066400000000000000000000164441463772530400265300ustar00rootroot00000000000000// This module implements the QsciMacro class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscimacro.h" #include #include "Qsci/qsciscintilla.h" static int fromHex(unsigned char ch); // The ctor. QsciMacro::QsciMacro(QsciScintilla *parent) : QObject(parent), qsci(parent) { } // The ctor that initialises the macro. QsciMacro::QsciMacro(const QString &asc, QsciScintilla *parent) : QObject(parent), qsci(parent) { load(asc); } // The dtor. QsciMacro::~QsciMacro() { } // Clear the contents of the macro. void QsciMacro::clear() { macro.clear(); } // Read a macro from a string. bool QsciMacro::load(const QString &asc) { bool ok = true; macro.clear(); QStringList fields = asc.split(' '); int f = 0; while (f < fields.size()) { Macro cmd; unsigned len; // Extract the 3 fixed fields. if (f + 3 > fields.size()) { ok = false; break; } cmd.msg = fields[f++].toUInt(&ok); if (!ok) break; cmd.wParam = fields[f++].toULong(&ok); if (!ok) break; len = fields[f++].toUInt(&ok); if (!ok) break; // Extract any text. if (len) { if (f + 1 > fields.size()) { ok = false; break; } QByteArray ba = fields[f++].toLatin1(); const char *sp = ba.data(); if (!sp) { ok = false; break; } // Because of historical bugs the length field is unreliable. bool embedded_null = false; unsigned char ch; while ((ch = *sp++) != '\0') { if (ch == '"' || ch <= ' ' || ch >= 0x7f) { ok = false; break; } if (ch == '\\') { int b1, b2; if ((b1 = fromHex(*sp++)) < 0 || (b2 = fromHex(*sp++)) < 0) { ok = false; break; } ch = (b1 << 4) + b2; } if (ch == '\0') { // Don't add it now as it may be the terminating '\0'. embedded_null = true; } else { if (embedded_null) { // Add the pending embedded '\0'. cmd.text += '\0'; embedded_null = false; } cmd.text += ch; } } if (!ok) break; } macro.append(cmd); } if (!ok) macro.clear(); return ok; } // Write a macro to a string. QString QsciMacro::save() const { QString ms; QList::const_iterator it; for (it = macro.begin(); it != macro.end(); ++it) { if (!ms.isEmpty()) ms += ' '; unsigned len = (*it).text.size(); QString m; ms += m.sprintf("%u %lu %u", (*it).msg, (*it).wParam, len); if (len) { // In Qt v3, if the length is greater than zero then it also // includes the '\0', so we need to make sure that Qt v4 writes the // '\0'. That the '\0' is written at all is a bug because // QCString::size() is used instead of QCString::length(). We // don't fix this so as not to break old macros. However this is // still broken because we have already written the unadjusted // length. So, in summary, the length field should be interpreted // as a zero/non-zero value, and the end of the data is either at // the next space or the very end of the data. ++len; ms += ' '; const char *cp = (*it).text.data(); while (len--) { unsigned char ch = *cp++; if (ch == '\\' || ch == '"' || ch <= ' ' || ch >= 0x7f) { QString buf; ms += buf.sprintf("\\%02x", ch); } else ms += ch; } } } return ms; } // Play the macro. void QsciMacro::play() { if (!qsci) return; QList::const_iterator it; for (it = macro.begin(); it != macro.end(); ++it) qsci->SendScintilla((*it).msg, static_cast((*it).wParam), (*it).text.constData()); } // Start recording. void QsciMacro::startRecording() { if (!qsci) return; macro.clear(); connect(qsci, SIGNAL(SCN_MACRORECORD(unsigned int, unsigned long, void *)), SLOT(record(unsigned int, unsigned long, void *))); qsci->SendScintilla(QsciScintillaBase::SCI_STARTRECORD); } // End recording. void QsciMacro::endRecording() { if (!qsci) return; qsci->SendScintilla(QsciScintillaBase::SCI_STOPRECORD); qsci->disconnect(this); } // Record a command. void QsciMacro::record(unsigned int msg, unsigned long wParam, void *lParam) { Macro m; m.msg = msg; m.wParam = wParam; // Determine commands which need special handling of the parameters. switch (msg) { case QsciScintillaBase::SCI_ADDTEXT: m.text = QByteArray(reinterpret_cast(lParam), wParam); break; case QsciScintillaBase::SCI_REPLACESEL: if (!macro.isEmpty() && macro.last().msg == QsciScintillaBase::SCI_REPLACESEL) { // This is the command used for ordinary user input so it's a // significant space reduction to append it to the previous // command. macro.last().text.append(reinterpret_cast(lParam)); return; } /* Drop through. */ case QsciScintillaBase::SCI_INSERTTEXT: case QsciScintillaBase::SCI_APPENDTEXT: case QsciScintillaBase::SCI_SEARCHNEXT: case QsciScintillaBase::SCI_SEARCHPREV: m.text.append(reinterpret_cast(lParam)); break; } macro.append(m); } // Return the given hex character as a binary. static int fromHex(unsigned char ch) { if (ch >= '0' && ch <= '9') return ch - '0'; if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; return -1; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_cs.qm000066400000000000000000001266101463772530400272270ustar00rootroot00000000000000<¸dÊÍ!¿`¡½ÝB¨U4yUU4‰ÆZw+rZw_Õè˜wÍ©Ôc:¬ô—&)[Äa]9L€G†GH˜‰u}L™b'L™bjâL™bwœL™b†»N–À–£Rx¼¦Rx¼ ÂRx¼88Rx¼f²VŠ¥$\ƒµ,^\ƒµ’ß^ t\oº´F‰sàç[„zªþ‹ {:³–VEˆ}£³ÒMì¥Ò÷=ï¶Ú´KnÇôèÌÛ…o2äoògÔäoòkUóeâbN&’eöž&{‚Õ¾{ò¨ÃtV&›%Ôƒ¤ôRÁm…o˜Ám…‹íÁm…“—Ám…˜ÐæÔ}ÐæÔ ÐæÔbÐæÔ%VÐæÔ.ÝÐæÔ2{ÐæÔ7ðÐæÔfpÐæÔm™ÐæÔs¡ÐæÔx¦ÐæÔ}ÐæÔJÐæÔˆÒÐæÔŽHÐæÔ˜ÝÐæÔÚú.àŽ‰(qàž‰(»àþ‰('â€˜âø³"å@U2å±å¹ ªÅ>Ì#õ‰Nhøµh2±¢_×TÊÓ9UÓpżuSOåï<9tÀW³”HÑUB…$E…®RõŒ„´ÛÁoµ‹XÏ¥ïñ?’UËøÅòç—I4œ%'´[¥å£[îuAfŠÓ+ùl&÷S;˜I¼ÁÓ~£Ű¹GÛÕ 4XË×ë¤a ãX|‡UëzÂ5Âß[ƽ0½d­½z«½‰ñ ò÷Oxvx Z6î|6ctAC Tä:{$<ÄLL,_—?½@ÙA3Æ@ÙAi@ÙAr^@ÙAI@ÙA”Ó@ÙB4!@ÙBia@ÙBr@ÙB¦@ÙB•0@ÙC4|@ÙCi¾@ÙCr¼@ÙC‘@ÙC•@ÙDj@ÙD‘`@ÙD•êAã*º\8Â\8ÂN\8 ö\8Â%˜\8Â/(\8Â3\8Â8p\8Âcî\8Âgj\8ÂmÞ\8Âp˜\8Ât@\8Âxé\8Â}W\8Â\8‰Z\8ÂŽŠ\8Â’¬\8”i\8™ \8šù\8ÂSró&Xró0]ró›kvBy¨™‚‚™‚‚zý¨Äk‡«58«5Å«5#«5-·«528«57¥«5f+«5mQ«5pS«5sY«5x`«5«5ˆ7«5ŒÝ«5’e«5”$«5˜—«5šU«5œÊ«Gh«Gqª°9\й°9\–ÿº:4†ñŽÔJà*ÄÃqs?^tH©_pÔ[}Ú&}Ú/¤}Ú8æ“Ïd­œ('`U «.5ú¶•§Cv½ÇWŸÈGÈ€ÈÚÈ%ÉÈ*È/bÈ3?È8§Èd Èg›ÈkÈnÈqÈttÈyÈÃȉŒÈŽ»È”šÈ™RÈ›.È…ѽ8 Ô‡„°àæ§Z —g;§• `î à©"J)6%)µo6|ÔŽô_uâR·d*zd*iyÛd*ÉzCd*ùzwiø*Eª¬’Šáª¶Ä‹0«¤„6«¤w„ «¤×„a«¤ç„Œ«¦wƒàÜŒ¤KòÝÀ©[%àä„:™ä]W _¤Dt&åµQ€*N°3g”gj½‚ å|Ö^K€ÓEÚ‡ã"1Ô‡ã"eS‡ã"rëŠlT ö~å ~å!)~å,’~åk¹•²´;¦2cq>°œ2aºûÅpèóä^¶ì‰=#ö2Dªù¦”O ~Õò &0'€ &0'‚w ?3ä_y @|U`¢ o” _ @t¤ ¨Ÿ×F ¬÷÷bÌ ¯²ÿ ±^÷W ´×Ç ´×µ ´×" ´×)’ ´×-= ´×7. ´×lÝ ´×w* ´×¹ ´׆I ´׌l º°~T ÉX$u¬ Ûí=yz iä ,E…$ ïÔTš ê4P 'ç4!¢ *²S *²Suä *²S„· Iq>º Sæµ~ƒ S浄â d85 d8l2 d8‘½ d8–G d<E d<> d< P d<5R d<6´ d<e… d<jx d<li d<nÆ d<o` d<v d<|’ d<}Á d<~Ç d<…p d<‹µ d<‘ó d<“ d<—„ d<™ß d<œZ d4!d hÁÒO kŸ,–× qe’E •ø$Ms œµdvŸ ¡úR) °ÖBAú ¼Œt‘ ¼Œt~ ¼Œtx ¼Œt Š ¼Œt!æ ¼Œt)\ ¼Œt,þ ¼Œt2 ¼Œt5‹ ¼Œt6z ¼Œt6ò ¼Œtc_ ¼Œtf ¼Œtjµ ¼Œtk÷ ¼Œtl¤ ¼Œtný ¼Œtoï ¼Œts ¼Œtvv ¼Œt|Ñ ¼Œt}𠼌tŽ ¼Œt…ï ¼ŒtŒD ¼Œt’- ¼Œt“î ¼Œt–{ ¼Œt˜` ¼Œtš ¼Œtœ“ ÑzäG… èZTPÕ ó¥ óZ5  _´TL ?Oê "…¶ ( „]Ò ;2Èÿ ;^·BU A¾\å E×Ä\ï _ Ô? cVå4× dóh( dN¤‡} e„að €4$\4 Ô'ï ÔFã Ô—K ¿yl Ç|#¤ Ç|.h Ç|| ÊBu|d Ó•åpÉ ÝO€- ÝO†ì ìÆ4E ìÆ4{1 Ø—P9 ðESõ )‹ )‹“M )‹—½ >ÖVÅ WöÜ=¸ fÎò* oÂX oÂwó oÂ‡Ê §'GC ÁÅ~ Ðæ·J[ ñ$x ÷ïÄD û'×Q þxŽ<¤  .vH  .…© ¦E_ú 943e½ @&4Yi @*$Y% _áe t}4¿ t}42» t}4c– t}4fä t}4sæ t}4šž ‚‰Ô$ Œ?D>o Ig'b Ig1y Ig3v Ig9½ IgdZ Igh² Igr Igu( Igƒ‹ Ig™Œ Igœ «ãt#J «ãt. «ãt" Â`åS¯ ×.„^A ñy@ÜÓWb› còb é+œ'»Ò }9 …@P=¤eUMV‰ÇX9W´\OE]‹gBÞe–TIohw„MiårZ`ld;RwægYß{Ô?‰›&4I'£ÇÈ£Ç&í£Ç*ý£Ç0û£Ç9B£ÇnN£Çt°£Ç{À£Çÿ£ÇŠC£ÇÔ£õBPython jméno funkce nebo metodyPython function or method name QsciLexerHTML(Python identifikátorPython identifier QsciLexerHTML(Python klí ové slovoPython keyword QsciLexerHTMLPython  íslo Python number QsciLexerHTMLPython operátorPython operator QsciLexerHTMLNPython string v jednoduchých uvozovkáchPython single-quoted string QsciLexerHTMLVPython string ve tYech dvojitých uvozovkách"Python triple double-quoted string QsciLexerHTMLNPython ve tYech jednoduchých uvozovkách"Python triple single-quoted string QsciLexerHTML&SGML defaultní blokSGML block default QsciLexerHTMLSGML pYíkaz SGML command QsciLexerHTMLSGML komentáY SGML comment QsciLexerHTMLÿÿÿÿ SGML default QsciLexerHTMLFSGML string ve dvojitých uvozovkáchSGML double-quoted string QsciLexerHTMLSGML chyba SGML error QsciLexerHTMLJSGML string v jednoduchých uvozovkáchSGML single-quoted string QsciLexerHTML*SGML speciální entitaSGML special entity QsciLexerHTMLTag skriptu Script tag QsciLexerHTML.Za átek JavaScript kóduStart of a JavaScript fragment QsciLexerHTML Za átek PHP kóduStart of a PHP fragment QsciLexerHTML&Za átek Python kóduStart of a Python fragment QsciLexerHTML*Za átek VBScript kóduStart of a VBScript fragment QsciLexerHTML6Za átek ASP JavaScript kódu#Start of an ASP JavaScript fragment QsciLexerHTML.Za átek ASP Python kóduStart of an ASP Python fragment QsciLexerHTML2Za átek ASP VBScript kódu!Start of an ASP VBScript fragment QsciLexerHTML Za átek ASP kóduStart of an ASP fragment QsciLexerHTML(Za átek ASP kódu s @Start of an ASP fragment with @ QsciLexerHTML"Za átek XML  ástiStart of an XML fragment QsciLexerHTMLÿÿÿÿTag QsciLexerHTML(Nedefinovaný atributUnknown attribute QsciLexerHTML Nedefinovaný tag Unknown tag QsciLexerHTML2HTML hodnota bez uvozovekUnquoted HTML value QsciLexerHTML"VBScript komentáYVBScript comment QsciLexerHTMLÿÿÿÿVBScript default QsciLexerHTML,VBScript identifikátorVBScript identifier QsciLexerHTML,VBScript klí ové slovoVBScript keyword QsciLexerHTMLVBScript  ísloVBScript number QsciLexerHTMLÿÿÿÿVBScript string QsciLexerHTML4VBScript neuzavYený stringVBScript unclosed string QsciLexerHTMLÿÿÿÿUUID QsciLexerIDLDefaultDefault QsciLexerJSON*JednoYádkový komentáY Line comment QsciLexerJSON  ísloNumber QsciLexerJSONOperátorOperator QsciLexerJSON"NeuzavYený stringUnclosed string QsciLexerJSONRegulární výrazRegular expressionQsciLexerJavaScriptZákladní funkceBasic functions QsciLexerLuaZnak Character QsciLexerLuaKomentáYComment QsciLexerLuaÿÿÿÿ%Coroutines, i/o and system facilities QsciLexerLuaÿÿÿÿDefault QsciLexerLuaIdentifikátor Identifier QsciLexerLuaKlí ové slovoKeyword QsciLexerLua NadpisLabel QsciLexerLua*JednoYádkový komentáY Line comment QsciLexerLuaÿÿÿÿLiteral string QsciLexerLua  ísloNumber QsciLexerLuaOperátorOperator QsciLexerLuaÿÿÿÿ Preprocessor QsciLexerLuaÿÿÿÿString QsciLexerLuaHString, tabulka a matematické funkce!String, table and maths functions QsciLexerLua"NeuzavYený stringUnclosed string QsciLexerLua.Definováno u~ivatelem 1User defined 1 QsciLexerLua.Definováno u~ivatelem 2User defined 2 QsciLexerLua.Definováno u~ivatelem 3User defined 3 QsciLexerLua.Definováno u~ivatelem 4User defined 4 QsciLexerLuaKomentáYCommentQsciLexerMakefileÿÿÿÿDefaultQsciLexerMakefile ChybaErrorQsciLexerMakefileOperátorOperatorQsciLexerMakefileÿÿÿÿ PreprocessorQsciLexerMakefileCílTargetQsciLexerMakefilePromnnáVariableQsciLexerMakefileDefaultDefaultQsciLexerMarkdown PYíkazCommandQsciLexerMatlabKomentáYCommentQsciLexerMatlabDefaultDefaultQsciLexerMatlab<String ve dvojitých uvozovkáchDouble-quoted stringQsciLexerMatlabIdentifikátor IdentifierQsciLexerMatlabKlí ové slovoKeywordQsciLexerMatlab  ísloNumberQsciLexerMatlabOperátorOperatorQsciLexerMatlab@String v jednoduchých uvozovkáchSingle-quoted stringQsciLexerMatlabKomentáYComment QsciLexerPODefaultDefault QsciLexerPOÿÿÿÿ Bad directive QsciLexerPOVKomentáYComment QsciLexerPOV*JednoYádkový komentáY Comment line QsciLexerPOVÿÿÿÿDefault QsciLexerPOVDirektiva Directive QsciLexerPOVIdentifikátor Identifier QsciLexerPOV  ísloNumber QsciLexerPOVÿÿÿÿObjects, CSG and appearance QsciLexerPOVOperátorOperator QsciLexerPOVÿÿÿÿPredefined functions QsciLexerPOVÿÿÿÿPredefined identifiers QsciLexerPOVÿÿÿÿString QsciLexerPOVÿÿÿÿTypes, modifiers and items QsciLexerPOV"NeuzavYený stringUnclosed string QsciLexerPOVÿÿÿÿUser defined 1 QsciLexerPOVÿÿÿÿUser defined 2 QsciLexerPOVÿÿÿÿUser defined 3 QsciLexerPOVZnak CharacterQsciLexerPascalDefaultDefaultQsciLexerPascalIdentifikátor IdentifierQsciLexerPascalKlí ové slovoKeywordQsciLexerPascal*JednoYádkový komentáY Line commentQsciLexerPascal  ísloNumberQsciLexerPascalOperátorOperatorQsciLexerPascal@String v jednoduchých uvozovkáchSingle-quoted stringQsciLexerPascal"NeuzavYený stringUnclosed stringQsciLexerPascalPoleArray QsciLexerPerlÿÿÿÿBacktick here document QsciLexerPerlÿÿÿÿ Backticks QsciLexerPerlKomentáYComment QsciLexerPerlÿÿÿÿ Data section QsciLexerPerlÿÿÿÿDefault QsciLexerPerlNZde je dokument ve dvojitých uvozovkáchDouble-quoted here document QsciLexerPerl<String ve dvojitých uvozovkáchDouble-quoted string QsciLexerPerl ChybaError QsciLexerPerlÿÿÿÿHash QsciLexerPerl4Zde je oddlova dokumentuHere document delimiter QsciLexerPerlIdentifikátor Identifier QsciLexerPerlKlí ové slovoKeyword QsciLexerPerl  ísloNumber QsciLexerPerlOperátorOperator QsciLexerPerlÿÿÿÿPOD QsciLexerPerlÿÿÿÿ POD verbatim QsciLexerPerlÿÿÿÿQuoted string (q) QsciLexerPerlÿÿÿÿQuoted string (qq) QsciLexerPerlÿÿÿÿQuoted string (qr) QsciLexerPerlÿÿÿÿQuoted string (qw) QsciLexerPerlÿÿÿÿQuoted string (qx) QsciLexerPerlRegulární výrazRegular expression QsciLexerPerl SkalárScalar QsciLexerPerlRZde je dokument v jednoduchých uvozovkáchSingle-quoted here document QsciLexerPerl@String v jednoduchých uvozovkáchSingle-quoted string QsciLexerPerlÿÿÿÿ Substitution QsciLexerPerlÿÿÿÿ Symbol table QsciLexerPerlKomentáYCommentQsciLexerPostScriptDefaultDefaultQsciLexerPostScriptKlí ové slovoKeywordQsciLexerPostScript  ísloNumberQsciLexerPostScriptÿÿÿÿ AssignmentQsciLexerPropertiesÿÿÿÿCommentQsciLexerPropertiesÿÿÿÿDefaultQsciLexerPropertiesÿÿÿÿ Default valueQsciLexerPropertiesÿÿÿÿSectionQsciLexerPropertiesJméno tYídy Class nameQsciLexerPythonKomentáYCommentQsciLexerPythonBlok komentáYe Comment blockQsciLexerPythonDekorátor DecoratorQsciLexerPythonÿÿÿÿDefaultQsciLexerPython<String ve dvojitých uvozovkáchDouble-quoted stringQsciLexerPython0Jméno funkce nebo metodyFunction or method nameQsciLexerPython0Zvýraznný identifikátorHighlighted identifierQsciLexerPythonIdentifikátor IdentifierQsciLexerPythonKlí ové slovoKeywordQsciLexerPython  ísloNumberQsciLexerPythonOperátorOperatorQsciLexerPython@String v jednoduchých uvozovkáchSingle-quoted stringQsciLexerPythonHString ve tYech dvojitých uvozovkáchTriple double-quoted stringQsciLexerPythonNString ve tYech jednoduchých uvozovkáchTriple single-quoted stringQsciLexerPython"NeuzavYený stringUnclosed stringQsciLexerPythonÿÿÿÿ %Q string QsciLexerRubyÿÿÿÿ %q string QsciLexerRubyÿÿÿÿ %r string QsciLexerRubyÿÿÿÿ %w string QsciLexerRubyÿÿÿÿ %x string QsciLexerRubyÿÿÿÿ Backticks QsciLexerRubyJméno tYídy Class name QsciLexerRubyPromnná tYídyClass variable QsciLexerRubyKomentáYComment QsciLexerRubyDatová sekce Data section QsciLexerRubyÿÿÿÿDefault QsciLexerRubyÿÿÿÿDemoted keyword QsciLexerRuby<String ve dvojitých uvozovkáchDouble-quoted string QsciLexerRuby ChybaError QsciLexerRuby0Jméno funkce nebo metodyFunction or method name QsciLexerRubyÿÿÿÿGlobal QsciLexerRubyZde je dokument Here document QsciLexerRuby4Zde je oddlova dokumentuHere document delimiter QsciLexerRubyIdentifikátor Identifier QsciLexerRuby"Promnná instanceInstance variable QsciLexerRubyKlí ové slovoKeyword QsciLexerRubyJméno modulu Module name QsciLexerRuby  ísloNumber QsciLexerRubyOperátorOperator QsciLexerRubyPODPOD QsciLexerRubyRegulární výrazRegular expression QsciLexerRuby@String v jednoduchých uvozovkáchSingle-quoted string QsciLexerRubyÿÿÿÿSymbol QsciLexerRubyÿÿÿÿstderr QsciLexerRubyÿÿÿÿstdin QsciLexerRubyÿÿÿÿstdout QsciLexerRuby.# jednoYádkový komentáY# comment line QsciLexerSQLKomentáYComment QsciLexerSQL*JednoYádkový komentáY Comment line QsciLexerSQLÿÿÿÿDefault QsciLexerSQL<String ve dvojitých uvozovkáchDouble-quoted string QsciLexerSQLIdentifikátor Identifier QsciLexerSQL*JavaDoc klí ové slovoJavaDoc keyword QsciLexerSQL6JavaDoc klí ové slovo chybyJavaDoc keyword error QsciLexerSQL*JavaDoc styl komentáYJavaDoc style comment QsciLexerSQLKlí ové slovoKeyword QsciLexerSQL  ísloNumber QsciLexerSQLOperátorOperator QsciLexerSQL"SQL*Plus komentáYSQL*Plus comment QsciLexerSQL,SQL*Plus klí ové slovoSQL*Plus keyword QsciLexerSQLÿÿÿÿSQL*Plus prompt QsciLexerSQL@String v jednoduchých uvozovkáchSingle-quoted string QsciLexerSQL.Definováno u~ivatelem 1User defined 1 QsciLexerSQL.Definováno u~ivatelem 2User defined 2 QsciLexerSQL.Definováno u~ivatelem 3User defined 3 QsciLexerSQL.Definováno u~ivatelem 4User defined 4 QsciLexerSQL PYíkazCommandQsciLexerSpiceKomentáYCommentQsciLexerSpiceDefaultDefaultQsciLexerSpiceIdentifikátor IdentifierQsciLexerSpice  ísloNumberQsciLexerSpiceHodnotaValueQsciLexerSpiceKomentáYComment QsciLexerTCLBlok komentáYe Comment block QsciLexerTCL*JednoYádkový komentáY Comment line QsciLexerTCLDefaultDefault QsciLexerTCLIdentifikátor Identifier QsciLexerTCL  ísloNumber QsciLexerTCLOperátorOperator QsciLexerTCL.Definováno u~ivatelem 1User defined 1 QsciLexerTCL.Definováno u~ivatelem 2User defined 2 QsciLexerTCL.Definováno u~ivatelem 3User defined 3 QsciLexerTCL.Definováno u~ivatelem 4User defined 4 QsciLexerTCL PYíkazCommand QsciLexerTeXÿÿÿÿDefault QsciLexerTeXSkupinaGroup QsciLexerTeXÿÿÿÿSpecial QsciLexerTeXÿÿÿÿSymbol QsciLexerTeXÿÿÿÿText QsciLexerTeXAtribut Attribute QsciLexerVHDLKomentáYComment QsciLexerVHDLBlok komentáYe Comment block QsciLexerVHDL*JednoYádkový komentáY Comment line QsciLexerVHDLDefaultDefault QsciLexerVHDLIdentifikátor Identifier QsciLexerVHDLKlí ové slovoKeyword QsciLexerVHDL  ísloNumber QsciLexerVHDLOperátorOperator QsciLexerVHDL"NeuzavYený stringUnclosed string QsciLexerVHDLKomentáYCommentQsciLexerVerilogDefaultDefaultQsciLexerVerilogIdentifikátor IdentifierQsciLexerVerilog*JednoYádkový komentáY Line commentQsciLexerVerilog  ísloNumberQsciLexerVerilogOperátorOperatorQsciLexerVerilogRSekundární klí ová slova a identifikátory"Secondary keywords and identifiersQsciLexerVerilog"NeuzavYený stringUnclosed stringQsciLexerVerilogKomentáYComment QsciLexerYAMLDefaultDefault QsciLexerYAMLIdentifikátor Identifier QsciLexerYAMLKlí ové slovoKeyword QsciLexerYAML  ísloNumber QsciLexerYAMLOperátorOperator QsciLexerYAMLˆsqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_cs.ts000066400000000000000000004500461463772530400272430ustar00rootroot00000000000000 QsciCommand Move down one line Posun o jednu řádku dolů Extend selection down one line Rozšířit výbÄ›r o jednu řádku dolů Scroll view down one line Rolovat pohled o jednu řádku dolů Extend rectangular selection down one line Rozšířit obdélníkový výbÄ›r o jednu řádku dolů Move up one line Posun o jednu řádku nahoru Extend selection up one line Rozšířit výbÄ›r o jednu řádku nahoru Scroll view up one line Rolovat pohled o jednu řádku nahoru Extend rectangular selection up one line Rozšířit obdélníkový výbÄ›r o jednu řádku nahoru Move up one paragraph Posun o jeden odstavec nahoru Extend selection up one paragraph Rozšířit výbÄ›r o jeden odstavec nahoru Move down one paragraph Posun o jeden odstavec dolů Scroll to start of document Scroll to end of document Scroll vertically to centre current line Extend selection down one paragraph Rozšířit výbÄ›r o jeden odstavec dolů Move left one character Posun o jedno písmeno doleva Extend selection left one character Rozšířit výbÄ›r o jedno písmeno doleva Move left one word Posun o jedno slovo vlevo Extend selection left one word Rozšířit výbÄ›r o jedno slovo doleva Extend rectangular selection left one character Rozšířit obdélníkový výbÄ›r o jedno písmeno doleva Move right one character Posun o jedno písmeno doprava Extend selection right one character Rozšířit výbÄ›r o jedno písmeno doprava Move right one word Posun o jedno slovo doprava Extend selection right one word Rozšířit výbÄ›r o jedno slovo doprava Extend rectangular selection right one character Rozšířit obdélníkový výbÄ›r o jedno písmeno doprava Move to end of previous word Extend selection to end of previous word Move to end of next word Extend selection to end of next word Move left one word part Posun o Äást slova doleva Extend selection left one word part Rozšířit výbÄ›r o Äást slova doleva Move right one word part Posun o Äást slova doprava Extend selection right one word part Rozšířit výbÄ›r o Äást slova doprava Move up one page Posun na pÅ™edchozí stranu Extend selection up one page Rozšířit výbÄ›r na pÅ™edchozí stranu Extend rectangular selection up one page Rozšířit obdélníkový výbÄ›r na pÅ™edchozí stranu Move down one page Posun na další stranu Extend selection down one page Rozšířit výbÄ›r na další stranu Extend rectangular selection down one page Rozšířit obdélníkový výbÄ›r na další stranu Delete current character Smazat aktuální znak Cut selection Vyjmout výbÄ›r Delete word to right Smazat slovo doprava Move to start of document line Extend selection to start of document line Extend rectangular selection to start of document line Move to start of display line Extend selection to start of display line Move to start of display or document line Extend selection to start of display or document line Move to first visible character in document line Extend selection to first visible character in document line Extend rectangular selection to first visible character in document line Move to first visible character of display in document line Extend selection to first visible character in display or document line Move to end of document line Extend selection to end of document line Extend rectangular selection to end of document line Move to end of display line Extend selection to end of display line Move to end of display or document line Extend selection to end of display or document line Move to start of document Extend selection to start of document Move to end of document Extend selection to end of document Stuttered move up one page Stuttered extend selection up one page Stuttered move down one page Stuttered extend selection down one page Delete previous character if not at start of line Delete right to end of next word Delete line to right Smazat řádku doprava Transpose current and previous lines Duplicate the current line Select all Select document Move selected lines up one line Move selected lines down one line Toggle insert/overtype PÅ™epnout vkládání/pÅ™episování Paste Vložit Copy selection Kopírovat výbÄ›r Insert newline De-indent one level Cancel ZruÅ¡it Delete previous character Smazat pÅ™edchozí znak Delete word to left Smazat slovo doleva Delete line to left Smazat řádku doleva Undo last command Redo last command Znovu použít poslední příkaz Indent one level Odsadit o jednu úroveň Zoom in ZvÄ›tÅ¡it Zoom out ZmenÅ¡it Formfeed Vysunout Cut current line Vyjmout aktuální řádku Delete current line Smazat aktuální řádku Copy current line Kopírovat aktuální řádku Convert selection to lower case Vybraný text pÅ™evést na malá písmena Convert selection to upper case Vybraný text pÅ™evést na velká písmena Duplicate selection Duplikovat výbÄ›r QsciLexerAVS Default Default Block comment Nested block comment Line comment Jednořádkový komentář Number Číslo Operator Operátor Identifier Identifikátor Double-quoted string String ve dvojitých uvozovkách Triple double-quoted string String ve tÅ™ech dvojitých uvozovkách Keyword KlíÄové slovo Filter Plugin Function Clip property User defined QsciLexerBash Default Default Error Chyba Comment Komentář Number Číslo Keyword KlíÄové slovo Double-quoted string String ve dvojitých uvozovkách Single-quoted string String v jednoduchých uvozovkách Operator Operátor Identifier Identifikátor Scalar Skalár Parameter expansion Rozklad parametru Backticks ZpÄ›tný chod Here document delimiter Zde je oddÄ›lovaÄ dokumentu Single-quoted here document Jednoduché uvozovky zde v dokumentu QsciLexerBatch Default Default Comment Komentář Keyword KlíÄové slovo Label Nadpis Hide command character Skrýt písmeno příkazu External command Externí příkaz Variable PromÄ›nná Operator Operátor QsciLexerCMake Default Default Comment Komentář String Left quoted string Right quoted string Function Variable PromÄ›nná Label Nadpis User defined WHILE block FOREACH block IF block MACRO block Variable within a string Number Číslo QsciLexerCPP Default Default Inactive default C comment C komentář Inactive C comment C++ comment C++ komentář Inactive C++ comment JavaDoc style C comment JavaDoc styl C komentáře Inactive JavaDoc style C comment Number Číslo Inactive number Keyword KlíÄové slovo Inactive keyword Double-quoted string String ve dvojitých uvozovkách Inactive double-quoted string Single-quoted string String v jednoduchých uvozovkách Inactive single-quoted string IDL UUID Inactive IDL UUID Pre-processor block Pre-procesor blok Inactive pre-processor block Operator Operátor Inactive operator Identifier Identifikátor Inactive identifier Unclosed string NeuzavÅ™ený string Inactive unclosed string C# verbatim string Inactive C# verbatim string JavaScript regular expression JavaSript regulární výraz Inactive JavaScript regular expression JavaDoc style C++ comment JavaDoc styl C++ komentáře Inactive JavaDoc style C++ comment Secondary keywords and identifiers Sekundární klíÄová slova a identifikátory Inactive secondary keywords and identifiers JavaDoc keyword JavaDoc klíÄové slovo Inactive JavaDoc keyword JavaDoc keyword error JavaDoc klíÄové slovo chyby Inactive JavaDoc keyword error Global classes and typedefs Globální třídy a definice typů Inactive global classes and typedefs C++ raw string Inactive C++ raw string Vala triple-quoted verbatim string Inactive Vala triple-quoted verbatim string Pike hash-quoted string Inactive Pike hash-quoted string Pre-processor C comment Inactive pre-processor C comment JavaDoc style pre-processor comment Inactive JavaDoc style pre-processor comment User-defined literal Inactive user-defined literal Task marker Inactive task marker Escape sequence Inactive escape sequence QsciLexerCSS Default Default Tag Tag Class selector Selektor třídy Pseudo-class Pseudotřída Unknown pseudo-class Nedefinovaná pseudotřída Operator Operátor CSS1 property CSS1 vlastnost Unknown property Nedefinovaná vlastnost Value Hodnota ID selector ID selektor Important Important @-rule @-pravidlo Double-quoted string String ve dvojitých uvozovkách Single-quoted string String v jednoduchých uvozovkách CSS2 property CSS2 vlastnost Attribute Atribut CSS3 property CSS2 vlastnost {3 ?} Pseudo-element Extended CSS property Extended pseudo-class Extended pseudo-element Media rule Variable PromÄ›nná QsciLexerCSharp Verbatim string QsciLexerCoffeeScript Default Default C-style comment C++-style comment JavaDoc C-style comment Number Číslo Keyword KlíÄové slovo Double-quoted string String ve dvojitých uvozovkách Single-quoted string String v jednoduchých uvozovkách IDL UUID Pre-processor block Pre-procesor blok Operator Operátor Identifier Identifikátor Unclosed string NeuzavÅ™ený string C# verbatim string Regular expression Regulární výraz JavaDoc C++-style comment Secondary keywords and identifiers Sekundární klíÄová slova a identifikátory JavaDoc keyword JavaDoc klíÄové slovo JavaDoc keyword error JavaDoc klíÄové slovo chyby Global classes Block comment Block regular expression Block regular expression comment Instance property QsciLexerD Default Default Block comment Line comment Jednořádkový komentář DDoc style block comment Nesting comment Number Číslo Keyword KlíÄové slovo Secondary keyword Documentation keyword Type definition String Unclosed string NeuzavÅ™ený string Character Znak Operator Operátor Identifier Identifikátor DDoc style line comment DDoc keyword DDoc keyword error Backquoted string Raw string User defined 1 Definováno uživatelem 1 User defined 2 Definováno uživatelem 2 User defined 3 Definováno uživatelem 3 QsciLexerDiff Default Default Comment Komentář Command Příkaz Header HlaviÄka Position Pozice Removed line Odebraná řádka Added line PÅ™idaná řádka Changed line Added adding patch Removed adding patch Added removing patch Removed removing patch QsciLexerEDIFACT Default Default Segment start Segment end Element separator Composite separator Release separator UNA segment header UNH segment header Badly formed segment QsciLexerFortran77 Default Default Comment Komentář Number Číslo Single-quoted string String v jednoduchých uvozovkách Double-quoted string String ve dvojitých uvozovkách Unclosed string NeuzavÅ™ený string Operator Operátor Identifier Identifikátor Keyword KlíÄové slovo Intrinsic function Extended function Pre-processor block Pre-procesor blok Dotted operator Label Nadpis Continuation QsciLexerHTML HTML default Tag Unknown tag Nedefinovaný tag Attribute Atribut Unknown attribute Nedefinovaný atribut HTML number HTML Äíslo HTML double-quoted string HTML string ve dojtých uvozovkách HTML single-quoted string HTML string v jednoduchých uvozovkách Other text in a tag Další text v tagu HTML comment HTML komentář Entity Entita End of a tag Konec tagu Start of an XML fragment ZaÄátek XML Äásti End of an XML fragment Konec XML Äásti Script tag Tag skriptu Start of an ASP fragment with @ ZaÄátek ASP kódu s @ Start of an ASP fragment ZaÄátek ASP kódu CDATA Start of a PHP fragment ZaÄátek PHP kódu Unquoted HTML value HTML hodnota bez uvozovek ASP X-Code comment ASP X-Code komentář SGML default SGML command SGML příkaz First parameter of an SGML command První parametr v SGML příkazu SGML double-quoted string SGML string ve dvojitých uvozovkách SGML single-quoted string SGML string v jednoduchých uvozovkách SGML error SGML chyba SGML special entity SGML speciální entita SGML comment SGML komentář First parameter comment of an SGML command Komentář prvního parametru SGML příkazu SGML block default SGML defaultní blok Start of a JavaScript fragment ZaÄátek JavaScript kódu JavaScript default JavaScript comment JavaScript komentář JavaScript line comment JavaScript jednořádkový komentář JavaDoc style JavaScript comment JavaDoc styl JavaScript komentáře JavaScript number JavaScript Äíslo JavaScript word JavaSript slovo JavaScript keyword JavaSript klíÄové slovo JavaScript double-quoted string JavaSript string ve dvojitých uvozovkách JavaScript single-quoted string JavaSript string v jednoduchých uvozovkách JavaScript symbol JavaScript unclosed string JavaSript neuzavÅ™ený string JavaScript regular expression JavaSript regulární výraz Start of an ASP JavaScript fragment ZaÄátek ASP JavaScript kódu ASP JavaScript default ASP JavaScript comment ASP JavaScript komentář ASP JavaScript line comment ASP JavaScript jednořádkový komenář JavaDoc style ASP JavaScript comment JavaDoc styl ASP JavaScript komentář ASP JavaScript number ASP JavaScript Äíslo ASP JavaScript word ASP JavaScript slovo ASP JavaScript keyword ASP JavaScript klíÄové slovo ASP JavaScript double-quoted string ASP JavaScript string ve dvojitých uvozovkách ASP JavaScript single-quoted string ASP JavaScript v jednoduchých uvozovkách ASP JavaScript symbol ASP JavaScript unclosed string ASP JavaScript neuzavÅ™ený string ASP JavaScript regular expression ASP JavaScript regulární výraz Start of a VBScript fragment ZaÄátek VBScript kódu VBScript default VBScript comment VBScript komentář VBScript number VBScript Äíslo VBScript keyword VBScript klíÄové slovo VBScript string VBScript identifier VBScript identifikátor VBScript unclosed string VBScript neuzavÅ™ený string Start of an ASP VBScript fragment ZaÄátek ASP VBScript kódu ASP VBScript default ASP VBScript comment ASP VBScript komentář ASP VBScript number ASP VBScript Äíslo ASP VBScript keyword ASP VBScript klíÄové slovo ASP VBScript string ASP VBScript identifier ASP VBScript identifikátor ASP VBScript unclosed string ASP VBScript neuzavÅ™ený string Start of a Python fragment ZaÄátek Python kódu Python default Python comment Python komentář Python number Python Äíslo Python double-quoted string Python string ve dojtých uvozovkách Python single-quoted string Python string v jednoduchých uvozovkách Python keyword Python klíÄové slovo Python triple double-quoted string Python string ve tÅ™ech dvojitých uvozovkách Python triple single-quoted string Python ve tÅ™ech jednoduchých uvozovkách Python class name Python jméno třídy Python function or method name Python jméno funkce nebo metody Python operator Python operátor Python identifier Python identifikátor Start of an ASP Python fragment ZaÄátek ASP Python kódu ASP Python default ASP Python comment ASP Python komentář ASP Python number ASP Python Äíslo ASP Python double-quoted string ASP Python string ve dvojitých uvozovkách ASP Python single-quoted string ASP Python v jednoduchých uvozovkách ASP Python keyword ASP Python klíÄové slovo ASP Python triple double-quoted string ASP Python ve tÅ™ech dvojitých uvozovkách ASP Python triple single-quoted string ASP Python ve tÅ™ech jednoduchých uvozovkách ASP Python class name ASP Python jméno třídy ASP Python function or method name ASP Python jméno funkce nebo metody ASP Python operator ASP Python operátor ASP Python identifier ASP Python identifikátor PHP default PHP double-quoted string PHP string ve dvojitých uvozovkách PHP single-quoted string PHP v jednoduchých uvozovkách PHP keyword PHP klíÄové slovo PHP number PHP Äíslo PHP variable PHP promÄ›nná PHP comment PHP komentář PHP line comment PHP jednořádkový komentář PHP double-quoted variable PHP promÄ›nná ve dvojitých uvozovkách PHP operator PHP operátor QsciLexerIDL UUID QsciLexerJSON Default Default Number Číslo String Unclosed string NeuzavÅ™ený string Property Escape sequence Line comment Jednořádkový komentář Block comment Operator Operátor IRI JSON-LD compact IRI JSON keyword JSON-LD keyword Parsing error QsciLexerJavaScript Regular expression Regulární výraz QsciLexerLua Default Comment Komentář Line comment Jednořádkový komentář Number Číslo Keyword KlíÄové slovo String Character Znak Literal string Preprocessor Operator Operátor Identifier Identifikátor Unclosed string NeuzavÅ™ený string Basic functions Základní funkce String, table and maths functions String, tabulka a matematické funkce Coroutines, i/o and system facilities User defined 1 Definováno uživatelem 1 User defined 2 Definováno uživatelem 2 User defined 3 Definováno uživatelem 3 User defined 4 Definováno uživatelem 4 Label Nadpis QsciLexerMakefile Default Comment Komentář Preprocessor Variable PromÄ›nná Operator Operátor Target Cíl Error Chyba QsciLexerMarkdown Default Default Special Strong emphasis using double asterisks Strong emphasis using double underscores Emphasis using single asterisks Emphasis using single underscores Level 1 header Level 2 header Level 3 header Level 4 header Level 5 header Level 6 header Pre-char Unordered list item Ordered list item Block quote Strike out Horizontal rule Link Code between backticks Code between double backticks Code block QsciLexerMatlab Default Default Comment Komentář Command Příkaz Number Číslo Keyword KlíÄové slovo Single-quoted string String v jednoduchých uvozovkách Operator Operátor Identifier Identifikátor Double-quoted string String ve dvojitých uvozovkách QsciLexerPO Default Default Comment Komentář Message identifier Message identifier text Message string Message string text Message context Message context text Fuzzy flag Programmer comment Reference Flags Message identifier text end-of-line Message string text end-of-line Message context text end-of-line QsciLexerPOV Default Comment Komentář Comment line Jednořádkový komentář Number Číslo Operator Operátor Identifier Identifikátor String Unclosed string NeuzavÅ™ený string Directive Direktiva Bad directive Objects, CSG and appearance Types, modifiers and items Predefined identifiers Predefined functions User defined 1 User defined 2 User defined 3 QsciLexerPascal Default Default Line comment Jednořádkový komentář Number Číslo Keyword KlíÄové slovo Single-quoted string String v jednoduchých uvozovkách Operator Operátor Identifier Identifikátor '{ ... }' style comment '(* ... *)' style comment '{$ ... }' style pre-processor block '(*$ ... *)' style pre-processor block Hexadecimal number Unclosed string NeuzavÅ™ený string Character Znak Inline asm QsciLexerPerl Default Error Chyba Comment Komentář POD Number Číslo Keyword KlíÄové slovo Double-quoted string String ve dvojitých uvozovkách Single-quoted string String v jednoduchých uvozovkách Operator Operátor Identifier Identifikátor Scalar Skalár Array Pole Hash Symbol table Regular expression Regulární výraz Substitution Backticks Data section Here document delimiter Zde je oddÄ›lovaÄ dokumentu Single-quoted here document Zde je dokument v jednoduchých uvozovkách Double-quoted here document Zde je dokument ve dvojitých uvozovkách Backtick here document Quoted string (q) Quoted string (qq) Quoted string (qx) Quoted string (qr) Quoted string (qw) POD verbatim Subroutine prototype Format identifier Format body Double-quoted string (interpolated variable) Translation Regular expression (interpolated variable) Substitution (interpolated variable) Backticks (interpolated variable) Double-quoted here document (interpolated variable) Backtick here document (interpolated variable) Quoted string (qq, interpolated variable) Quoted string (qx, interpolated variable) Quoted string (qr, interpolated variable) QsciLexerPostScript Default Default Comment Komentář DSC comment DSC comment value Number Číslo Name Keyword KlíÄové slovo Literal Immediately evaluated literal Array parenthesis Dictionary parenthesis Procedure parenthesis Text Hexadecimal string Base85 string Bad string character QsciLexerProperties Default Comment Section Assignment Default value Key QsciLexerPython Default Comment Komentář Number Číslo Double-quoted string String ve dvojitých uvozovkách Single-quoted string String v jednoduchých uvozovkách Keyword KlíÄové slovo Triple single-quoted string String ve tÅ™ech jednoduchých uvozovkách Triple double-quoted string String ve tÅ™ech dvojitých uvozovkách Class name Jméno třídy Function or method name Jméno funkce nebo metody Operator Operátor Identifier Identifikátor Comment block Blok komentáře Unclosed string NeuzavÅ™ený string Highlighted identifier ZvýraznÄ›ný identifikátor Decorator Dekorátor Double-quoted f-string Single-quoted f-string Triple single-quoted f-string Triple double-quoted f-string QsciLexerRuby Default Comment Komentář Number Číslo Double-quoted string String ve dvojitých uvozovkách Single-quoted string String v jednoduchých uvozovkách Keyword KlíÄové slovo Class name Jméno třídy Function or method name Jméno funkce nebo metody Operator Operátor Identifier Identifikátor Error Chyba POD POD Regular expression Regulární výraz Global Symbol Module name Jméno modulu Instance variable PromÄ›nná instance Class variable PromÄ›nná třídy Backticks Data section Datová sekce Here document delimiter Zde je oddÄ›lovaÄ dokumentu Here document Zde je dokument %q string %Q string %x string %r string %w string Demoted keyword stdin stdout stderr QsciLexerSQL Default Comment Komentář Number Číslo Keyword KlíÄové slovo Single-quoted string String v jednoduchých uvozovkách Operator Operátor Identifier Identifikátor Comment line Jednořádkový komentář JavaDoc style comment JavaDoc styl komentář Double-quoted string String ve dvojitých uvozovkách SQL*Plus keyword SQL*Plus klíÄové slovo SQL*Plus prompt SQL*Plus comment SQL*Plus komentář # comment line # jednořádkový komentář JavaDoc keyword JavaDoc klíÄové slovo JavaDoc keyword error JavaDoc klíÄové slovo chyby User defined 1 Definováno uživatelem 1 User defined 2 Definováno uživatelem 2 User defined 3 Definováno uživatelem 3 User defined 4 Definováno uživatelem 4 Quoted identifier Quoted operator QsciLexerSpice Default Default Identifier Identifikátor Command Příkaz Function Parameter Number Číslo Delimiter Value Hodnota Comment Komentář QsciLexerTCL Default Default Comment Komentář Comment line Jednořádkový komentář Number Číslo Quoted keyword Quoted string Operator Operátor Identifier Identifikátor Substitution Brace substitution Modifier Expand keyword TCL keyword Tk keyword iTCL keyword Tk command User defined 1 Definováno uživatelem 1 User defined 2 Definováno uživatelem 2 User defined 3 Definováno uživatelem 3 User defined 4 Definováno uživatelem 4 Comment box Comment block Blok komentáře QsciLexerTeX Default Special Group Skupina Symbol Command Příkaz Text QsciLexerVHDL Default Default Comment Komentář Comment line Jednořádkový komentář Number Číslo String Operator Operátor Identifier Identifikátor Unclosed string NeuzavÅ™ený string Keyword KlíÄové slovo Standard operator Attribute Atribut Standard function Standard package Standard type User defined Comment block Blok komentáře QsciLexerVerilog Default Default Inactive default Comment Komentář Inactive comment Line comment Jednořádkový komentář Inactive line comment Bang comment Inactive bang comment Number Číslo Inactive number Primary keywords and identifiers Inactive primary keywords and identifiers String Inactive string Secondary keywords and identifiers Sekundární klíÄová slova a identifikátory Inactive secondary keywords and identifiers System task Inactive system task Preprocessor block Inactive preprocessor block Operator Operátor Inactive operator Identifier Identifikátor Inactive identifier Unclosed string NeuzavÅ™ený string Inactive unclosed string User defined tasks and identifiers Inactive user defined tasks and identifiers Keyword comment Inactive keyword comment Input port declaration Inactive input port declaration Output port declaration Inactive output port declaration Input/output port declaration Inactive input/output port declaration Port connection Inactive port connection QsciLexerYAML Default Default Comment Komentář Identifier Identifikátor Keyword KlíÄové slovo Number Číslo Reference Document delimiter Text block marker Syntax error marker Operator Operátor QsciScintilla &Undo &Redo Cu&t &Copy &Paste Delete Select All sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_de.qm000066400000000000000000002337751463772530400272250ustar00rootroot00000000000000<¸dÊÍ!¿`¡½ÝB˜NiªrQÉå¸U4×ÐU4ô½Zw_’Zw¥«ÔwJ§Ô†è˜ÖN0K»H5㬩ԩt¬ôäs¬ôÞ I$L I$ /ÝT¼G'ƒtÄp)[ħG*¦y+‹¯+įI9ØBm­Î G†‹H˜‰Ð*L™b8áL™b´L™bÕL™bñ¸M'ãÁ4N–ÀCRx¼=RRx¼?0Rx¼zþRx¼¯îVŠ¥+²\ƒµ`|\ƒµÿi^ t¡±c¶Âúqoº´Šqsàç ~zªþö{}§|>H™–VEó€žëq£³Ò’B¥Ò÷­4~y¶¶Ú´¨ÇôøÿÌ/õ(ùÌÛ…ÅóÎå%Mäoò±:äoòµóeâ¨Tº¥*&õ^x^ 5'FÑ(&;v/À«>p3ùÐÅ:ë?Ï=ZÔAFkyÛ&R½5âeöž2Ów§t3Lw§taPw§tjÜw§t©¡{‚Õ-Ð{ò!sÃtšöäieb™õ4Ã2›%Ô"4¤ô–²¨¸ôd©>^Š©l"ßÖ²/WÁm´…u0XÁm…ÆÁm…÷Ám…´Ám…ÌÐæÔ5>ÐæÔ9»ÐæÔ=ÐæÔUxÐæÔgoÐæÔm¢ÐæÔz¶ÐæÔ¯¬ÐæÔ¿£ÐæÔÎZÐæÔ×#ÐæÔã&ÐæÔé›ÐæÔóÑÐæÔùWÐæÔÐæÔçÑ'r2Òû‰Ñ¸Õ‹ôïÚú.êàŽ‰ZÕàž‰[#àþ‰Z‡âèëâø³D‡å@U8å±å¿ ªÅø ±×ìd!ÍÂQ#õôNhø+Qdü¹ÓzfÁIh2 €ež2œUÕ‚…ƒì‡ó}»O˜bÎ <¢_י޶ХÆÈ4wLuÐ µ .Ó9U 2ÓpÅ äÓ«ž,Õ;% âñdòNÆñdòâ@þ@ È,ãou+Oå*«7 ’k©<9tJè8tVî‰3–W³”ŒmþDZÑUD…$ˆÃ…®—•ˆ¾õÝÒŒ„´ ¶M¾ÿ™”äÞa£¥í0ܪ{A¹š¤GE¼È$lûÁoµöyÏ¥ñÕ7TÌßêÄÕá^Þñ?’š¡ó31ÔøÅò…²3;ç—á$Š"œ4œ%ZQñ¥ë[¥å’[îu6fŠÓ`l&÷—ÛE dZkâ‰GY– …‡˜I¼¡®cMn¤[tcr¬,¥Æ¹ÃtcÁÓ~£Ű¹‹ßÐ:Â4“Ò(TÁ¹Õ 4«ÕIžh×뤦ñÛÙåõãX|ò\ëzÂs‘ô'ôn+÷ùD Ôÿ»“¼•ß ¾½h“½­‡½Ûýôè Ÿ•D; Ÿ•ª% ò÷“îvxº6îÞ06î%ct„ Tä}A$<Ä~*ŽtÂ,_—ƒ@ÙApy@ÙA²È@ÙAÊ5@ÙAüH@ÙA:@ÙBpÊ@ÙB³@ÙBʈ@ÙBü›@ÙB@ÙCq@ÙC³n@ÙCÊÛ@ÙCüî@ÙCà@ÙD³Á@ÙDýA@ÙD3Aã^™B”o8H¦ôª[“ôkZ\8Â6<\8Â9þ\8Â@\8ÂUº\8Âgº\8Ân‰\8Â{4\8«õ\8°Ò\8¿è\8ÂÇ}\8ÂÎí\8Â×f\8Âãà\8Âéà\8ÂôS\8Âù™\8Âþú\8Â\8ÂÒ\8¼\8Â*k'§róWjróhóróÌs½þ6¤vBØA{:•ë^—™‚‚:Å™‚‚ܽ¨ÄµO«54ÿ«59{«5EB«5e«5me«5z«5¯m«5¿a«5Ç>«5ÍÊ«5Öã«5éY«5ó@«5÷ú«5þ¹«5–«5O«5 '«5§«G@´«Go˜«G¬è«G±«GÉ#«G s«Gc¯Ê‚Õ°9\õ¬°9\«º:4ðÕÀ¾¬ÐäECÚ§“áÛâ¯t«NñŽÔ"øƒ„›ùå#Æ'qËË•)n)¬*ÄÃȺ8ÍÒQ?^tŒÅ]íu-(_pÔ3o?CL}ÚW}Úh4}Ú{¨~¯t½“ÏdHœ('¦1 «.sͶ•§†ð½ÇœcÇ#¶È6kÈ:.È=„ÈUéÈ^`ÈgòÈn¶È{iȬ%ȱȴÇÈÀÈÈ ÈÏÈ×–ÈêÈôƒÈùÈÈEÈ ÈïÈZѽ8±ÒçÂ`Ô‡„õjX2wÉj½‚UjÙäG™jè2wto1¤%á|Ö^W€Ó‰„ƒ›ò»ºƒœBÿ+‡ã"k$‡ã"®3‡ã"ÌüŠlT|~å=¿~åAD~å`ª~嵃•ŸI••²´~¼¦2cÈYªN¥.ô°œ2§›ºûÅÇÀÒOfØ,7Klß`â?å­E å­dØèóä¤H쉀öû¨ö2ˆ\ù¦”Ðþ@tu+ ~Õq èWë0 &0'6× &0'ëÍ 3ø¤™ ?3ä¥; @|U¦| A…ƒP\ A…ƒ˜ DQœâ« fÌɬ¨ o” ¤¸ / j @tû žž2N žž2 ˆ ¨Ÿ×‰ë ¬÷÷¨ú ¯²<¡ ±^÷›â ²¹V" ´×4 ´×8i ´×CÄ ´×[ö ´×d ´×y9 ´×¾ç ´×ÔE ´×çþ ´×ñ@ ´×÷ƒ º°åõ ÉX$ÐY Ûí=×û ù×$f0 iä· ,EïÍ óW?b Ï5ð ïÔ™@ ê4•$ =WQ œbº¹ œ‚º œ’º_ œ¢¹Q œ²¹« œÒ¸÷ " b 'ç4Bí )ì×JÅ *²S7¸ *²SÑ{ *²SïN +O4àô 0è‚Ír FYžoÕ Iq>:h Sæµæ6 Sæµï‹ ZŒs† ZÿU/¨ ^×Qû ^× d8rè d8¾8 d8ý” d8× d<7õ d<;Ú d<=ú d<s d<x d<®k d<´ d<¾o d<ÀÄ d<ÆG d<Ò? d<à³ d<äë d<æz d<ð d<öÈ d<ýÊ d<ÿì d<F d< ­ d<Ý d4B: g›$² hÁÒç kŸ,¼ kŸ,u qe’‰- s(ßB |‡C3 ’à’v> •ø$‘Õ œµdÒù ¡úR[q ©ì%ê °ÖB…R ¼Œt3ä ¼Œt80 ¼Œt< ¼Œt>6 ¼ŒtCŒ ¼Œt[¾ ¼ŒtcÁ ¼ŒtlÅ ¼ŒtsX ¼Œtv ¼Œtx§ ¼Œt©ì ¼Œt¯5 ¼Œt´S ¼Œt·7 ¼Œt¾¬ ¼ŒtÀý ¼ŒtÆÊ ¼ŒtÍ7 ¼ŒtÒÀ ¼Œtᜠ¼Œtå, ¼ŒtçC ¼Œt𜠼Œt÷K ¼Œtþ ¼Œtý ¼Œt ¼Œt ¼Œt ë ¼Œt Æíä Ñzä‹u èZT•k ó¥• óZ5# øÄ _´˜ð ?”n ¢´Å\ "…1\ $çç~ $•tË. '¬d,· ( „£8 8ˆ5&ç ;2Èî ;^·…­ A¾\Š E×Ä¢) _ Ô! cVåqÚ dó±¾ dN¤ò e„§ö pÓCd‚ v]wBz v]wb¡ v¸ql }TôFn €4$¡B ôÉÜ …%¤Ng ÔZM ÔŠÍ Ô £Ü ü £ü .® ¬¢;¦ ¿y S Ç|ST Ç|fú Ç|ø“ ÊBuÞú ÏzDj Ó•åǬ Û'(r* ܶô$ò ÝOèx ÝOñë ìÆ4:ù ìÆ4Üñ ñ)Þp Ø—”½ ðE˜™ )‹æ· )‹& )‹ Ötvä FB  Xp #×êN >Ö›“ J¬Ž4Æ J¬Ž>º J¬Žþ~ K†Bu˜ WL…áA WöÜ€° fÎò]¥ jßã·t oÂ9 oÂÖ| oÂòÙ §'‹9 ¯,lg ÁÅåk ÈkOé Èü%ź Èü%” ÐAŽzY Ðæ·Ž§ ÝGEÞ ç!v ñT ôÏrÏ ÷ïćš û'ו° ûóu š þxŽ’  .Òz  .ðV ¦E¥Ö '¸4,L 1“5µÁ 943®¥ @&4žG @*$ž _á­å c¥bxå t}45€ t}4mâ t}4«© t}4° t}4Ο t}4m wt¼Rt ‚‰ÔSÀ „\RÕõ …ã\× ‡—´ù Œ?D ”¹¢O ”¹¢0 IgX¸ Igj Igp Ig|u Ig­( Ig²j IgÉ× IgÏÉ Igí€ Ig ³ Igê ¡„E «ãtRú «ãtf— «ãtø9 ºut~ Â`å˜S ×.„£½ Ü}n’ Ý5Ë ä‡ÎJ0 åœÂÜ ñy„<ÓW¨ŸB‚H cò Ú é_¼'»Ò9 …ƒª=¤ešG2vHIªïO¨ Ô½V‰Ç W´\“™]‹g†:e–T™hw„‘qiårŸ`ld~LwægžÙ{Ô‚·‡ó-½¿ÚCß…‘óâú›&4O¡N¥Î£Ç;n£ÇWý£Ç_'£Çi£Ç|£ÇÀV£ÇÏ[£ÇÝf£Çê£Çõ@£ÇûÝ£õB5¥_jj¥¿´‚[­)wìõ´Î 踤45Ʀû0ÇnHÈÙ¤bÐL„îÓkCÉbà|¥èëj…tqìs4 `ö 5(tö²å¸ þ2Uþ2’“@’…"wàX#}w`ã'[Ì|2¡…^4+4+ç8Û42b9<3½#FkyÙÝRÎ’›Nm%wßu@Ô7ku@Ô@õu@Ô „Õ$l ‰2—)t)µnE.AÀ–Tž‘Ä””w*ÄÔ!ÙÍÁ#¶pÜå%%_á²Ää§å9r¬_ù¬•rœiDAbbrechenCancel QsciCommandHAuswahl in Kleinbuchstaben umwandelnConvert selection to lower case QsciCommandFAuswahl in Großbuchstaben umwandelnConvert selection to upper case QsciCommand.Aktuelle Zeile kopierenCopy current line QsciCommand Auswahl kopierenCopy selection QsciCommand6Aktuelle Zeile ausschneidenCut current line QsciCommand(Auswahl ausschneiden Cut selection QsciCommand(Eine Ebene ausrückenDe-indent one level QsciCommand2Aktuelles Zeichen löschenDelete current character QsciCommand,Aktuelle Zeile löschenDelete current line QsciCommand&Zeile links löschenDelete line to left QsciCommand(Zeile rechts löschenDelete line to right QsciCommand*Zeichen links löschenDelete previous character QsciCommandbZeichen links löschen, wenn nicht am Zeilenanfang1Delete previous character if not at start of line QsciCommand^Rechts bis zum Ende des nächsten Wortes löschen Delete right to end of next word QsciCommand$Wort links löschenDelete word to left QsciCommand&Wort rechts löschenDelete word to right QsciCommand&Auswahl duplizierenDuplicate selection QsciCommand4Aktuelle Zeile duplizierenDuplicate the current line QsciCommandlRechteckige Auswahl um eine Zeile nach unten erweitern*Extend rectangular selection down one line QsciCommandlRechteckige Auswahl um eine Seite nach unten erweitern*Extend rectangular selection down one page QsciCommandnRechteckige Auswahl um ein Zeichen nach links erweitern/Extend rectangular selection left one character QsciCommandpRechteckige Auswahl um ein Zeichen nach rechts erweitern0Extend rectangular selection right one character QsciCommandtRechteckige Auswahl zum Ende der Dokumentenzeile erweitern4Extend rectangular selection to end of document line QsciCommandšRechteckige Auswahl zum ersten sichtbaren Zeichen der Dokumentzeile erweiternHExtend rectangular selection to first visible character in document line QsciCommandxRechteckige Auswahl zum Beginn der Dokumentenzeile erweitern6Extend rectangular selection to start of document line QsciCommandjRechteckige Auswahl um eine Zeile nach oben erweitern(Extend rectangular selection up one line QsciCommandjRechteckige Auswahl um eine Seite nach oben erweitern(Extend rectangular selection up one page QsciCommandTAuswahl um eine Zeile nach unten erweiternExtend selection down one line QsciCommandTAuswahl um eine Seite nach unten erweiternExtend selection down one page QsciCommandXAuswahl um einen Absatz nach unten erweitern#Extend selection down one paragraph QsciCommandVAuswahl um ein Zeichen nach links erweitern#Extend selection left one character QsciCommandPAuswahl um ein Wort nach links erweiternExtend selection left one word QsciCommand\Auswahl um einen Wortteil nach links erweitern#Extend selection left one word part QsciCommandXAuswahl um ein Zeichen nach rechts erweitern$Extend selection right one character QsciCommandRAuswahl um ein Wort nach rechts erweiternExtend selection right one word QsciCommand^Auswahl um einen Wortteil nach rechts erweitern$Extend selection right one word part QsciCommandVAuswahl zum Ende der Anzeigezeile erweitern'Extend selection to end of display line QsciCommandRechteckige Auswahl zum Ende der Dokumenten- oder Anzeigezeile erweitern3Extend selection to end of display or document line QsciCommandHAuswahl zum Dokumentenende erweitern#Extend selection to end of document QsciCommand\Auswahl zum Ende der Dokumentenzeile erweitern(Extend selection to end of document line QsciCommanddAuswahl bis zum Ende des nächsten Wortes erweitern$Extend selection to end of next word QsciCommandbAuswahl bis zum Ende des vorigen Wortes erweitern(Extend selection to end of previous word QsciCommandžAuswahl zum ersten sichtbaren Zeichen der Dokument- oder Anzeigezeile erweiternGExtend selection to first visible character in display or document line QsciCommand‚Auswahl zum ersten sichtbaren Zeichen der Dokumentzeile erweiternInaktives JavaDoc SchlüsselwortInactive JavaDoc keyword QsciLexerCPPJInaktiver JavaDoc SchlüsselwortfehlerInactive JavaDoc keyword error QsciLexerCPP:Inaktiver JavaDoc C Kommentar Inactive JavaDoc style C comment QsciLexerCPP>Inaktiver JavaDoc C++ Kommentar"Inactive JavaDoc style C++ comment QsciLexerCPPNInaktiver JavaDoc Präprozessorkommentar,Inactive JavaDoc style pre-processor comment QsciLexerCPPNJavaScript Inaktiver Regulärer Ausdruck&Inactive JavaScript regular expression QsciLexerCPPfInaktive Pike Zeichenkette in '#-Anführungszeichen' Inactive Pike hash-quoted string QsciLexerCPPhInaktive Vala Zeichenkette in dreifachen Hochkommata+Inactive Vala triple-quoted verbatim string QsciLexerCPP$Inaktiver StandardInactive default QsciLexerCPPTInaktive Zeichenkette in AnführungszeichenInactive double-quoted string QsciLexerCPP.Inaktive Escape-SequenzInactive escape sequence QsciLexerCPPXInaktive globale Klassen und Typdefinitionen$Inactive global classes and typedefs QsciLexerCPP(Inaktiver BezeichnerInactive identifier QsciLexerCPP.Inaktives SchlüsselwortInactive keyword QsciLexerCPPInaktive ZahlInactive number QsciLexerCPP$Inaktiver OperatorInactive operator QsciLexerCPPBInaktiver C Präprozessorkommentar Inactive pre-processor C comment QsciLexerCPP6Inaktiver PräprozessorblockInactive pre-processor block QsciLexerCPPbInaktive sekundäre Schlusselwörter und Bezeichner+Inactive secondary keywords and identifiers QsciLexerCPPHInaktive Zeichenkette in HochkommataInactive single-quoted string QsciLexerCPP6Inaktive AufgabenmarkierungInactive task marker QsciLexerCPP@Inaktive unbeendete ZeichenketteInactive unclosed string QsciLexerCPPHInaktives Nutzer definiertes LiteralInactive user-defined literal QsciLexerCPP*JavaDoc SchlüsselwortJavaDoc keyword QsciLexerCPP6JavaDoc SchlüsselwortfehlerJavaDoc keyword error QsciLexerCPP&JavaDoc C KommentarJavaDoc style C comment QsciLexerCPP*JavaDoc C++ KommentarJavaDoc style C++ comment QsciLexerCPP:JavaDoc Präprozessorkommentar#JavaDoc style pre-processor comment QsciLexerCPP:JavaScript Regulärer AusdruckJavaScript regular expression QsciLexerCPPSchlüsselwortKeyword QsciLexerCPPZahlNumber QsciLexerCPPOperatorOperator QsciLexerCPPTPike Zeichenkette in '#-Anführungszeichen'Pike hash-quoted string QsciLexerCPP.C PräprozessorkommentarPre-processor C comment QsciLexerCPP"PräprozessorblockPre-processor block QsciLexerCPPPSekundäre Schlusselwörter und Bezeichner"Secondary keywords and identifiers QsciLexerCPP6Zeichenkette in HochkommataSingle-quoted string QsciLexerCPP$Aufgabenmarkierung Task marker QsciLexerCPP.Unbeendete ZeichenketteUnclosed string QsciLexerCPP4Nutzer definiertes LiteralUser-defined literal QsciLexerCPPVVala Zeichenkette in dreifachen Hochkommata"Vala triple-quoted verbatim string QsciLexerCPP@-Regel@-rule QsciLexerCSSAttribut Attribute QsciLexerCSS CSS1 Eigenschaft CSS1 property QsciLexerCSS CSS2 Eigenschaft CSS2 property QsciLexerCSS CSS3 Eigenschaft CSS3 property QsciLexerCSSKlassenselektorClass selector QsciLexerCSSStandardDefault QsciLexerCSSBZeichenkette in AnführungszeichenDouble-quoted string QsciLexerCSS4Erweiterte CSS EigenschaftExtended CSS property QsciLexerCSS.Erweiterte PseudoklasseExtended pseudo-class QsciLexerCSS2Erweitertes PseudoelementExtended pseudo-element QsciLexerCSSID-Selektor ID selector QsciLexerCSSWichtig Important QsciLexerCSSMedienregel Media rule QsciLexerCSSOperatorOperator QsciLexerCSSPseudoklasse Pseudo-class QsciLexerCSSPseudoelementPseudo-element QsciLexerCSS6Zeichenkette in HochkommataSingle-quoted string QsciLexerCSSTagTag QsciLexerCSS,Unbekannte EigenschaftUnknown property QsciLexerCSS.Unbekannte PseudoklasseUnknown pseudo-class QsciLexerCSSWertValue QsciLexerCSSVariableVariable QsciLexerCSS:Uninterpretierte ZeichenketteVerbatim stringQsciLexerCSharpBlockkommentar Block commentQsciLexerCoffeeScript0Regulärer AusdrucksblockBlock regular expressionQsciLexerCoffeeScriptBRegulärer Ausdrucksblockkommentar Block regular expression commentQsciLexerCoffeeScript@Uninterpretierte C# ZeichenketteC# verbatim stringQsciLexerCoffeeScriptC++ KommentarC++-style commentQsciLexerCoffeeScriptC KommentarC-style commentQsciLexerCoffeeScriptStandardDefaultQsciLexerCoffeeScriptBZeichenkette in AnführungszeichenDouble-quoted stringQsciLexerCoffeeScriptGlobale KlassenGlobal classesQsciLexerCoffeeScriptIDL UUIDIDL UUIDQsciLexerCoffeeScriptBezeichner IdentifierQsciLexerCoffeeScript&Instanz-EigenschaftInstance propertyQsciLexerCoffeeScript*JavaDoc C++ KommentarJavaDoc C++-style commentQsciLexerCoffeeScript&JavaDoc C KommentarJavaDoc C-style commentQsciLexerCoffeeScript*JavaDoc SchlüsselwortJavaDoc keywordQsciLexerCoffeeScript6JavaDoc SchlüsselwortfehlerJavaDoc keyword errorQsciLexerCoffeeScriptSchlüsselwortKeywordQsciLexerCoffeeScriptZahlNumberQsciLexerCoffeeScriptOperatorOperatorQsciLexerCoffeeScript"PräprozessorblockPre-processor blockQsciLexerCoffeeScript$Regulärer AusdruckRegular expressionQsciLexerCoffeeScriptPSekundäre Schlusselwörter und Bezeichner"Secondary keywords and identifiersQsciLexerCoffeeScript6Zeichenkette in HochkommataSingle-quoted stringQsciLexerCoffeeScript.Unbeendete ZeichenketteUnclosed stringQsciLexerCoffeeScriptBZeichenkette in RückwärtsstrichenBackquoted string QsciLexerDBlockkommentar Block comment QsciLexerDZeichen Character QsciLexerD$DDoc Schlüsselwort DDoc keyword QsciLexerD0DDoc SchlüsselwortfehlerDDoc keyword error QsciLexerD&DDoc BlockkommentarDDoc style block comment QsciLexerD(DDoc ZeilenkommentarDDoc style line comment QsciLexerDStandardDefault QsciLexerD6DokumentationsschlüsselwortDocumentation keyword QsciLexerDBezeichner Identifier QsciLexerDSchlüsselwortKeyword QsciLexerDZeilenkommentar Line comment QsciLexerD0schachtelbarer KommentarNesting comment QsciLexerDZahlNumber QsciLexerDOperatorOperator QsciLexerD"Rohe Zeichenkette Raw string QsciLexerD0Sekundäres SchlüsselwortSecondary keyword QsciLexerDZeichenketteString QsciLexerDTypdefinitionType definition QsciLexerD.Unbeendete ZeichenketteUnclosed string QsciLexerD$Nutzer definiert 1User defined 1 QsciLexerD$Nutzer definiert 2User defined 2 QsciLexerD$Nutzer definiert 3User defined 3 QsciLexerD:Hinzugefügter ErgänzungspatchAdded adding patch QsciLexerDiff$Hinzugefügte Zeile Added line QsciLexerDiff<Hinzugefügter EntfernungspatchAdded removing patch QsciLexerDiffGeänderte Zeile Changed line QsciLexerDiff BefehlCommand QsciLexerDiffKommentarComment QsciLexerDiffStandardDefault QsciLexerDiffKopfzeilenHeader QsciLexerDiffPositionPosition QsciLexerDiff4Entfernter ErgänzungspatchRemoved adding patch QsciLexerDiffEntfernte Zeile Removed line QsciLexerDiff6Entfernter EntfernungspatchRemoved removing patch QsciLexerDiff4Schlecht geformtes SegmentBadly formed segmentQsciLexerEDIFACT2Zusammengesetzter TrennerComposite separatorQsciLexerEDIFACTStandardDefaultQsciLexerEDIFACTElementtrennerElement separatorQsciLexerEDIFACTFreigabetrennerRelease separatorQsciLexerEDIFACTSegmentende Segment endQsciLexerEDIFACTSegmentstart Segment startQsciLexerEDIFACTUNA SegmentkopfUNA segment headerQsciLexerEDIFACTUNH SegmentkopfUNH segment headerQsciLexerEDIFACTKommentarCommentQsciLexerFortran77Fortsetzung ContinuationQsciLexerFortran77StandardDefaultQsciLexerFortran77Dotted OperatorDotted operatorQsciLexerFortran77BZeichenkette in AnführungszeichenDouble-quoted stringQsciLexerFortran77&Erweiterte FunktionExtended functionQsciLexerFortran77Bezeichner IdentifierQsciLexerFortran77$Intrinsic-FunktionIntrinsic functionQsciLexerFortran77SchlüsselwortKeywordQsciLexerFortran77 MarkeLabelQsciLexerFortran77ZahlNumberQsciLexerFortran77OperatorOperatorQsciLexerFortran77"PräprozessorblockPre-processor blockQsciLexerFortran776Zeichenkette in HochkommataSingle-quoted stringQsciLexerFortran77.Unbeendete ZeichenketteUnclosed stringQsciLexerFortran770ASP JavaScript KommentarASP JavaScript comment QsciLexerHTML.ASP JavaScript StandardASP JavaScript default QsciLexerHTML`ASP JavaScript Zeichenkette in Anführungszeichen#ASP JavaScript double-quoted string QsciLexerHTML8ASP JavaScript SchlüsselwortASP JavaScript keyword QsciLexerHTML<ASP JavaScript ZeilenkommentarASP JavaScript line comment QsciLexerHTML&ASP JavaScript ZahlASP JavaScript number QsciLexerHTMLBASP JavaScript Regulärer Ausdruck!ASP JavaScript regular expression QsciLexerHTMLTASP JavaScript Zeichenkette in Hochkommata#ASP JavaScript single-quoted string QsciLexerHTML*ASP JavaScript SymbolASP JavaScript symbol QsciLexerHTMLLASP JavaScript Unbeendete ZeichenketteASP JavaScript unclosed string QsciLexerHTML&ASP JavaScript WortASP JavaScript word QsciLexerHTML,ASP Python KlassennameASP Python class name QsciLexerHTML(ASP Python KommentarASP Python comment QsciLexerHTML&ASP Python StandardASP Python default QsciLexerHTMLXASP Python Zeichenkette in AnführungszeichenASP Python double-quoted string QsciLexerHTMLNASP Python Funktions- oder Methodenname"ASP Python function or method name QsciLexerHTML*ASP Python BezeichnerASP Python identifier QsciLexerHTML0ASP Python SchlüsselwortASP Python keyword QsciLexerHTMLASP Python ZahlASP Python number QsciLexerHTML&ASP Python OperatorASP Python operator QsciLexerHTMLLASP Python Zeichenkette in HochkommataASP Python single-quoted string QsciLexerHTMLnASP Python Zeichenkette in dreifachen Anführungszeichen&ASP Python triple double-quoted string QsciLexerHTMLbASP Python Zeichenkette in dreifachen Hochkommata&ASP Python triple single-quoted string QsciLexerHTML,ASP VBScript KommentarASP VBScript comment QsciLexerHTML*ASP VBScript StandardASP VBScript default QsciLexerHTML.ASP VBScript BezeichnerASP VBScript identifier QsciLexerHTML4ASP VBScript SchlüsselwortASP VBScript keyword QsciLexerHTML"ASP VBScript ZahlASP VBScript number QsciLexerHTML2ASP VBScript ZeichenketteASP VBScript string QsciLexerHTMLHASP VBScript Unbeendete ZeichenketteASP VBScript unclosed string QsciLexerHTML(ASP X-Code KommentarASP X-Code comment QsciLexerHTMLAttribut Attribute QsciLexerHTML CDATACDATA QsciLexerHTMLTagende End of a tag QsciLexerHTML2Ende eines XML FragmentesEnd of an XML fragment QsciLexerHTMLEntitätEntity QsciLexerHTMLdKommentar des ersten Parameters eines SGML Befehls*First parameter comment of an SGML command QsciLexerHTMLFErster Parameter eines SGML Befehls"First parameter of an SGML command QsciLexerHTMLHTML Kommentar HTML comment QsciLexerHTMLHTML Standard HTML default QsciLexerHTMLLHTML Zeichenkette in AnführungszeichenHTML double-quoted string QsciLexerHTMLHTML Zahl HTML number QsciLexerHTML@HTML Zeichenkette in HochkommataHTML single-quoted string QsciLexerHTML@JavaDoc ASP JavaScript Kommentar$JavaDoc style ASP JavaScript comment QsciLexerHTML8JavaDoc JavaScript Kommentar JavaDoc style JavaScript comment QsciLexerHTML(JavaScript KommentarJavaScript comment QsciLexerHTML&JavaScript StandardJavaScript default QsciLexerHTMLXJavaScript Zeichenkette in AnführungszeichenJavaScript double-quoted string QsciLexerHTML0JavaScript SchlüsselwortJavaScript keyword QsciLexerHTML4JavaScript ZeilenkommentarJavaScript line comment QsciLexerHTMLJavaScript ZahlJavaScript number QsciLexerHTML:JavaScript Regulärer AusdruckJavaScript regular expression QsciLexerHTMLLJavaScript Zeichenkette in HochkommataJavaScript single-quoted string QsciLexerHTML"JavaScript SymbolJavaScript symbol QsciLexerHTMLDJavaScript Unbeendete ZeichenketteJavaScript unclosed string QsciLexerHTMLJavaScript WortJavaScript word QsciLexerHTML2Anderer Text in einem TagOther text in a tag QsciLexerHTMLPHP Kommentar PHP comment QsciLexerHTMLPHP Standard PHP default QsciLexerHTMLJPHP Zeichenkette in AnführungszeichenPHP double-quoted string QsciLexerHTMLBPHP Variable in AnführungszeichenPHP double-quoted variable QsciLexerHTML"PHP Schlüsselwort PHP keyword QsciLexerHTML&PHP ZeilenkommentarPHP line comment QsciLexerHTMLPHP Zahl PHP number QsciLexerHTMLPHP Operator PHP operator QsciLexerHTML>PHP Zeichenkette in HochkommataPHP single-quoted string QsciLexerHTMLPHP Variable PHP variable QsciLexerHTML$Python KlassennamePython class name QsciLexerHTML Python KommentarPython comment QsciLexerHTMLPython StandardPython default QsciLexerHTMLPPython Zeichenkette in AnführungszeichenPython double-quoted string QsciLexerHTMLFPython Funktions- oder MethodennamePython function or method name QsciLexerHTML"Python BezeichnerPython identifier QsciLexerHTML(Python SchlüsselwortPython keyword QsciLexerHTMLPython Zahl Python number QsciLexerHTMLPython OperatorPython operator QsciLexerHTMLDPython Zeichenkette in HochkommataPython single-quoted string QsciLexerHTMLfPython Zeichenkette in dreifachen Anführungszeichen"Python triple double-quoted string QsciLexerHTMLZPython Zeichenkette in dreifachen Hochkommata"Python triple single-quoted string QsciLexerHTML$SGML StandardblockSGML block default QsciLexerHTMLSGML Befehl SGML command QsciLexerHTMLSGML Kommentar SGML comment QsciLexerHTMLSGML Standard SGML default QsciLexerHTMLLSGML Zeichenkette in AnführungszeichenSGML double-quoted string QsciLexerHTMLSGML Fehler SGML error QsciLexerHTML@SGML Zeichenkette in HochkommataSGML single-quoted string QsciLexerHTML,SGML Spezielle EntitätSGML special entity QsciLexerHTMLSkript Tag Script tag QsciLexerHTMLDBeginn eines JavaScript FragmentesStart of a JavaScript fragment QsciLexerHTML6Beginn eines PHP FragmentesStart of a PHP fragment QsciLexerHTML<Beginn eines Python FragmentesStart of a Python fragment QsciLexerHTML@Beginn eines VBScript FragmentesStart of a VBScript fragment QsciLexerHTMLLBeginn eines ASP JavaScript Fragmentes#Start of an ASP JavaScript fragment QsciLexerHTMLDBeginn eines ASP Python FragmentesStart of an ASP Python fragment QsciLexerHTMLHBeginn eines ASP VBScript Fragmentes!Start of an ASP VBScript fragment QsciLexerHTML6Beginn eines ASP FragmentesStart of an ASP fragment QsciLexerHTMLBBeginn eines ASP Fragmentes mit @Start of an ASP fragment with @ QsciLexerHTML6Beginn eines XML FragmentesStart of an XML fragment QsciLexerHTMLTagTag QsciLexerHTML(Unbekanntes AttributUnknown attribute QsciLexerHTMLUnbekanntes Tag Unknown tag QsciLexerHTML@HTML Wert ohne AnführungszeichenUnquoted HTML value QsciLexerHTML$VBScript KommentarVBScript comment QsciLexerHTML"VBScript StandardVBScript default QsciLexerHTML&VBScript BezeichnerVBScript identifier QsciLexerHTML,VBScript SchlüsselwortVBScript keyword QsciLexerHTMLVBScript ZahlVBScript number QsciLexerHTML*VBScript ZeichenketteVBScript string QsciLexerHTML@VBScript Unbeendete ZeichenketteVBScript unclosed string QsciLexerHTMLUUIDUUID QsciLexerIDLBlockkommentar Block comment QsciLexerJSONStandardDefault QsciLexerJSONEscape-SequenzEscape sequence QsciLexerJSONIRIIRI QsciLexerJSON$JSON Schlüsselwort JSON keyword QsciLexerJSON*JSON-LD kompaktes IRIJSON-LD compact IRI QsciLexerJSON*JSON-LD SchlüsselwortJSON-LD keyword QsciLexerJSONZeilenkommentar Line comment QsciLexerJSONZahlNumber QsciLexerJSONOperatorOperator QsciLexerJSONAnalysefehler Parsing error QsciLexerJSONEigenschaftProperty QsciLexerJSONZeichenketteString QsciLexerJSON.Unbeendete ZeichenketteUnclosed string QsciLexerJSON$Regulärer AusdruckRegular expressionQsciLexerJavaScriptBasisfunktionenBasic functions QsciLexerLuaZeichen Character QsciLexerLuaKommentarComment QsciLexerLuaJKoroutinen, I/O- und Systemfunktionen%Coroutines, i/o and system facilities QsciLexerLuaStandardDefault QsciLexerLuaBezeichner Identifier QsciLexerLuaSchlüsselwortKeyword QsciLexerLua MarkeLabel QsciLexerLuaZeilenkommentar Line comment QsciLexerLua:Uninterpretierte ZeichenketteLiteral string QsciLexerLuaZahlNumber QsciLexerLuaOperatorOperator QsciLexerLuaPräprozessor Preprocessor QsciLexerLuaZeichenketteString QsciLexerLuajZeichenketten-, Tabelle- und mathematische Funktionen!String, table and maths functions QsciLexerLua.Unbeendete ZeichenketteUnclosed string QsciLexerLua$Nutzer definiert 1User defined 1 QsciLexerLua$Nutzer definiert 2User defined 2 QsciLexerLua$Nutzer definiert 3User defined 3 QsciLexerLua$Nutzer definiert 4User defined 4 QsciLexerLuaKommentarCommentQsciLexerMakefileStandardDefaultQsciLexerMakefile FehlerErrorQsciLexerMakefileOperatorOperatorQsciLexerMakefilePräprozessor PreprocessorQsciLexerMakefileZielTargetQsciLexerMakefileVariableVariableQsciLexerMakefileBlockzitat Block quoteQsciLexerMarkdown.Code zwischen BackticksCode between backticksQsciLexerMarkdownBCode zwischen doppelten BackticksCode between double backticksQsciLexerMarkdownCodeblock Code blockQsciLexerMarkdownStandardDefaultQsciLexerMarkdownJKursive Schrift mit einfachen SternenEmphasis using single asterisksQsciLexerMarkdownVKursive Schrift mit einfachen Unterstrichen!Emphasis using single underscoresQsciLexerMarkdown"Horizontale LinieHorizontal ruleQsciLexerMarkdown&Überschrift Ebene 1Level 1 headerQsciLexerMarkdown&Überschrift Ebene 2Level 2 headerQsciLexerMarkdown&Überschrift Ebene 3Level 3 headerQsciLexerMarkdown&Überschrift Ebene 4Level 4 headerQsciLexerMarkdown&Überschrift Ebene 5Level 5 headerQsciLexerMarkdown&Überschrift Ebene 6Level 6 headerQsciLexerMarkdownHyperlinkLinkQsciLexerMarkdown4Nummeriertes ListenelementOrdered list itemQsciLexerMarkdown$EinleitungszeichenPre-charQsciLexerMarkdownSpezialSpecialQsciLexerMarkdownDurchgestrichen Strike outQsciLexerMarkdownBFettschrift mit doppelten Sternen&Strong emphasis using double asterisksQsciLexerMarkdownNFettschrift mit doppelten Unterstrichen(Strong emphasis using double underscoresQsciLexerMarkdown@Nicht nummeriertes ListenelementUnordered list itemQsciLexerMarkdown BefehlCommandQsciLexerMatlabKommentarCommentQsciLexerMatlabStandardDefaultQsciLexerMatlabBZeichenkette in AnführungszeichenDouble-quoted stringQsciLexerMatlabBezeichner IdentifierQsciLexerMatlabSchlüsselwortKeywordQsciLexerMatlabZahlNumberQsciLexerMatlabOperatorOperatorQsciLexerMatlab6Zeichenkette in HochkommataSingle-quoted stringQsciLexerMatlabKommentarComment QsciLexerPOStandardDefault QsciLexerPOMarkierungFlags QsciLexerPO"Unschrfmarkierung Fuzzy flag QsciLexerPOMeldungskontextMessage context QsciLexerPO&MeldungskontexttextMessage context text QsciLexerPO<Meldungskontexttext Zeilenende Message context text end-of-line QsciLexerPO$MeldungsbezeichnerMessage identifier QsciLexerPO,MeldungsbezeichnertextMessage identifier text QsciLexerPOBMeldungsbezeichnertext Zeilenende#Message identifier text end-of-line QsciLexerPO(MeldungszeichenketteMessage string QsciLexerPO2MeldungszeichenkettentextMessage string text QsciLexerPOHMeldungszeichenkettentext ZeilenendeMessage string text end-of-line QsciLexerPO,ProgrammiererkommentarProgrammer comment QsciLexerPOReferenz Reference QsciLexerPO&Ungültige Direktive Bad directive QsciLexerPOVKommentarComment QsciLexerPOVKommentarzeile Comment line QsciLexerPOVStandardDefault QsciLexerPOVDirektive Directive QsciLexerPOVBezeichner Identifier QsciLexerPOVZahlNumber QsciLexerPOV8Objekte, CSG und ErscheinungObjects, CSG and appearance QsciLexerPOVOperatorOperator QsciLexerPOV,Vordefinierte FunktionPredefined functions QsciLexerPOV2Vordefinierter BezeichnerPredefined identifiers QsciLexerPOVZeichenketteString QsciLexerPOV:Typen, Modifizierer und ItemsTypes, modifiers and items QsciLexerPOV.Unbeendete ZeichenketteUnclosed string QsciLexerPOV$Nutzer definiert 1User defined 1 QsciLexerPOV$Nutzer definiert 2User defined 2 QsciLexerPOV$Nutzer definiert 3User defined 3 QsciLexerPOV*'(* ... *)' Kommentar'(* ... *)' style commentQsciLexerPascal<'(*$ ... *)' Präprozessorblock&'(*$ ... *)' style pre-processor blockQsciLexerPascal&'{ ... }' Kommentar'{ ... }' style commentQsciLexerPascal8'{$ ... }' Präprozessorblock$'{$ ... }' style pre-processor blockQsciLexerPascalZeichen CharacterQsciLexerPascalStandardDefaultQsciLexerPascal"Hexadezimale ZahlHexadecimal numberQsciLexerPascalBezeichner IdentifierQsciLexerPascal Inline Assembler Inline asmQsciLexerPascalSchlüsselwortKeywordQsciLexerPascalZeilenkommentar Line commentQsciLexerPascalZahlNumberQsciLexerPascalOperatorOperatorQsciLexerPascal6Zeichenkette in HochkommataSingle-quoted stringQsciLexerPascal.Unbeendete ZeichenketteUnclosed stringQsciLexerPascalFeldArray QsciLexerPerl4Here Dokument in BackticksBacktick here document QsciLexerPerlfHere Dokument in Backticks (interpolierte Variable).Backtick here document (interpolated variable) QsciLexerPerlBackticks Backticks QsciLexerPerlDBackticks (interpolierte Variable)!Backticks (interpolated variable) QsciLexerPerlKommentarComment QsciLexerPerlDatensektion Data section QsciLexerPerlStandardDefault QsciLexerPerlDHere Dokument in AnführungszeichenDouble-quoted here document QsciLexerPerlvHere Dokument in Anführungszeichen (interpolierte Variable)3Double-quoted here document (interpolated variable) QsciLexerPerlBZeichenkette in AnführungszeichenDouble-quoted string QsciLexerPerltZeichenkette in Anführungszeichen (interpolierte Variable),Double-quoted string (interpolated variable) QsciLexerPerl FehlerError QsciLexerPerlFormatzweig Format body QsciLexerPerl&FormatidentifikatorFormat identifier QsciLexerPerlHashHash QsciLexerPerl.Here Dokument-BegrenzerHere document delimiter QsciLexerPerlBezeichner Identifier QsciLexerPerlSchlüsselwortKeyword QsciLexerPerlZahlNumber QsciLexerPerlOperatorOperator QsciLexerPerlPODPOD QsciLexerPerlPOD wörtlich POD verbatim QsciLexerPerl Zeichenkette (q)Quoted string (q) QsciLexerPerl"Zeichenkette (qq)Quoted string (qq) QsciLexerPerlRZeichenkette (qq, interpolierte Variable))Quoted string (qq, interpolated variable) QsciLexerPerl"Zeichenkette (qr)Quoted string (qr) QsciLexerPerlRZeichenkette (qr, interpolierte Variable))Quoted string (qr, interpolated variable) QsciLexerPerl"Zeichenkette (qw)Quoted string (qw) QsciLexerPerl"Zeichenkette (qx)Quoted string (qx) QsciLexerPerlRZeichenkette (qx, interpolierte Variable))Quoted string (qx, interpolated variable) QsciLexerPerl$Regulärer AusdruckRegular expression QsciLexerPerlVRegulärer Ausdruck (interpolierte Variable)*Regular expression (interpolated variable) QsciLexerPerl SkalarScalar QsciLexerPerl8Here Dokument in HochkommataSingle-quoted here document QsciLexerPerl6Zeichenkette in HochkommataSingle-quoted string QsciLexerPerl(Subroutinen PrototypSubroutine prototype QsciLexerPerlErsetzung Substitution QsciLexerPerlDErsetzung (interpolierte Variable)$Substitution (interpolated variable) QsciLexerPerlSymboltabelle Symbol table QsciLexerPerlÜbersetzung Translation QsciLexerPerlFeldklammernArray parenthesisQsciLexerPostScriptFUngültiges Zeichen für ZeichenketteBad string characterQsciLexerPostScript&Base85 Zeichenkette Base85 stringQsciLexerPostScriptKommentarCommentQsciLexerPostScriptDSC Kommentar DSC commentQsciLexerPostScript"DSC KommentarwertDSC comment valueQsciLexerPostScriptStandardDefaultQsciLexerPostScript&Dictionary-KlammernDictionary parenthesisQsciLexerPostScript2Hexadezimale ZeichenketteHexadecimal stringQsciLexerPostScript6Direkt ausgeführtes LiteralImmediately evaluated literalQsciLexerPostScriptSchlüsselwortKeywordQsciLexerPostScriptLiteralLiteralQsciLexerPostScriptNameNameQsciLexerPostScriptZahlNumberQsciLexerPostScript ProzedurklammernProcedure parenthesisQsciLexerPostScriptTextTextQsciLexerPostScriptZuweisung AssignmentQsciLexerPropertiesKommentarCommentQsciLexerPropertiesStandardDefaultQsciLexerPropertiesStandardwert Default valueQsciLexerPropertiesSchlüsselKeyQsciLexerPropertiesAbschnittSectionQsciLexerPropertiesKlassenname Class nameQsciLexerPythonKommentarCommentQsciLexerPythonKommentarblock Comment blockQsciLexerPythonDekorator DecoratorQsciLexerPythonStandardDefaultQsciLexerPythonFF-Zeichenkette in AnführungszeichenDouble-quoted f-stringQsciLexerPythonBZeichenkette in AnführungszeichenDouble-quoted stringQsciLexerPython8Funktions- oder MethodennameFunction or method nameQsciLexerPython4Hervorgehobener BezeichnerHighlighted identifierQsciLexerPythonBezeichner IdentifierQsciLexerPythonSchlüsselwortKeywordQsciLexerPythonZahlNumberQsciLexerPythonOperatorOperatorQsciLexerPython:F-Zeichenkette in HochkommataSingle-quoted f-stringQsciLexerPython6Zeichenkette in HochkommataSingle-quoted stringQsciLexerPython\F-Zeichenkette in dreifachen AnführungszeichenTriple double-quoted f-stringQsciLexerPythonXZeichenkette in dreifachen AnführungszeichenTriple double-quoted stringQsciLexerPythonPF-Zeichenkette in dreifachen HochkommataTriple single-quoted f-stringQsciLexerPythonLZeichenkette in dreifachen HochkommataTriple single-quoted stringQsciLexerPython.Unbeendete ZeichenketteUnclosed stringQsciLexerPython%Q Zeichenkette %Q string QsciLexerRuby%q Zeichenkette %q string QsciLexerRuby%r Zeichenkette %r string QsciLexerRuby%w Zeichenkette %w string QsciLexerRuby%x Zeichenkette %x string QsciLexerRubyBackticks Backticks QsciLexerRubyKlassenname Class name QsciLexerRubyKlassenvariableClass variable QsciLexerRubyKommentarComment QsciLexerRubyDatensektion Data section QsciLexerRubyStandardDefault QsciLexerRuby:zurückgestuftes SchlüsselwortDemoted keyword QsciLexerRubyBZeichenkette in AnführungszeichenDouble-quoted string QsciLexerRuby FehlerError QsciLexerRuby8Funktions- oder MethodennameFunction or method name QsciLexerRuby GlobalGlobal QsciLexerRubyHere Dokument Here document QsciLexerRuby.Here Dokument-BegrenzerHere document delimiter QsciLexerRubyBezeichner Identifier QsciLexerRubyInstanzvariableInstance variable QsciLexerRubySchlüsselwortKeyword QsciLexerRubyModulname Module name QsciLexerRubyZahlNumber QsciLexerRubyOperatorOperator QsciLexerRubyPODPOD QsciLexerRuby$Regulärer AusdruckRegular expression QsciLexerRuby6Zeichenkette in HochkommataSingle-quoted string QsciLexerRuby SymbolSymbol QsciLexerRuby Stderrstderr QsciLexerRuby Stdinstdin QsciLexerRuby Stdoutstdout QsciLexerRuby # Kommentarzeile# comment line QsciLexerSQLKommentarComment QsciLexerSQLKommentarzeile Comment line QsciLexerSQLStandardDefault QsciLexerSQLBZeichenkette in AnführungszeichenDouble-quoted string QsciLexerSQLBezeichner Identifier QsciLexerSQL*JavaDoc SchlüsselwortJavaDoc keyword QsciLexerSQL6JavaDoc SchlüsselwortfehlerJavaDoc keyword error QsciLexerSQL"JavaDoc KommentarJavaDoc style comment QsciLexerSQLSchlüsselwortKeyword QsciLexerSQLZahlNumber QsciLexerSQLOperatorOperator QsciLexerSQL>Bezeichner in AnführungszeichenQuoted identifier QsciLexerSQL:Operator in AnführungszeichenQuoted operator QsciLexerSQL$SQL*Plus KommentarSQL*Plus comment QsciLexerSQL,SQL*Plus SchlüsselwortSQL*Plus keyword QsciLexerSQL SQL*Plus EingabeSQL*Plus prompt QsciLexerSQL6Zeichenkette in HochkommataSingle-quoted string QsciLexerSQL$Nutzer definiert 1User defined 1 QsciLexerSQL$Nutzer definiert 2User defined 2 QsciLexerSQL$Nutzer definiert 3User defined 3 QsciLexerSQL$Nutzer definiert 4User defined 4 QsciLexerSQL BefehlCommandQsciLexerSpiceKommentarCommentQsciLexerSpiceStandardDefaultQsciLexerSpiceDelimiter DelimiterQsciLexerSpiceFunktionFunctionQsciLexerSpiceBezeichner IdentifierQsciLexerSpiceZahlNumberQsciLexerSpiceParameter ParameterQsciLexerSpiceWertValueQsciLexerSpice KlammerersetzungBrace substitution QsciLexerTCLKommentarComment QsciLexerTCLKommentarblock Comment block QsciLexerTCLKommentarbox Comment box QsciLexerTCLKommentarzeile Comment line QsciLexerTCLStandardDefault QsciLexerTCL2ErweiterungsschlüsselwortExpand keyword QsciLexerTCLBezeichner Identifier QsciLexerTCLModifiziererModifier QsciLexerTCLZahlNumber QsciLexerTCLOperatorOperator QsciLexerTCL2angeführtes SchlüsselwortQuoted keyword QsciLexerTCLZeichenkette Quoted string QsciLexerTCLErsetzung Substitution QsciLexerTCL"TCL Schlüsselwort TCL keyword QsciLexerTCLTk Befehl Tk command QsciLexerTCL Tk Schlüsselwort Tk keyword QsciLexerTCL$Nutzer definiert 1User defined 1 QsciLexerTCL$Nutzer definiert 2User defined 2 QsciLexerTCL$Nutzer definiert 3User defined 3 QsciLexerTCL$Nutzer definiert 4User defined 4 QsciLexerTCL$iTCL Schlüsselwort iTCL keyword QsciLexerTCL BefehlCommand QsciLexerTeXStandardDefault QsciLexerTeX GruppeGroup QsciLexerTeXSpezialSpecial QsciLexerTeX SymbolSymbol QsciLexerTeXTextText QsciLexerTeXAttribut Attribute QsciLexerVHDLKommentarComment QsciLexerVHDLKommentarblock Comment block QsciLexerVHDLKommentarzeile Comment line QsciLexerVHDLStandardDefault QsciLexerVHDLBezeichner Identifier QsciLexerVHDLSchlüsselwortKeyword QsciLexerVHDLZahlNumber QsciLexerVHDLOperatorOperator QsciLexerVHDL StandardfunktionStandard function QsciLexerVHDL StandardoperatorStandard operator QsciLexerVHDLStandardpaketStandard package QsciLexerVHDLStandardtyp Standard type QsciLexerVHDLZeichenketteString QsciLexerVHDL.Unbeendete ZeichenketteUnclosed string QsciLexerVHDL Nutzer definiert User defined QsciLexerVHDLBang Kommentar Bang commentQsciLexerVerilogKommentarCommentQsciLexerVerilogStandardDefaultQsciLexerVerilogBezeichner IdentifierQsciLexerVerilog0Inaktiver Bang KommentarInactive bang commentQsciLexerVerilog&Inaktiver KommentarInactive commentQsciLexerVerilog$Inaktiver StandardInactive defaultQsciLexerVerilog(Inaktiver BezeichnerInactive identifierQsciLexerVerilog<Inaktive EingabeportdefinitionInactive input port declarationQsciLexerVerilogFInaktive Ein-/Ausgabeportdefinition&Inactive input/output port declarationQsciLexerVerilog@Inaktiver SchlüsselwortkommentarInactive keyword commentQsciLexerVerilog2Inaktiver ZeilenkommentarInactive line commentQsciLexerVerilogInaktive ZahlInactive numberQsciLexerVerilog$Inaktiver OperatorInactive operatorQsciLexerVerilog<Inaktive Ausgabeportdefinition Inactive output port declarationQsciLexerVerilog.Inaktive PortverbindungInactive port connectionQsciLexerVerilog6Inaktiver PräprozessorblockInactive preprocessor blockQsciLexerVerilog^Inaktive primäre Schlusselwörter und Bezeichner)Inactive primary keywords and identifiersQsciLexerVerilogbInaktive sekundäre Schlusselwörter und Bezeichner+Inactive secondary keywords and identifiersQsciLexerVerilog*Inaktive ZeichenketteInactive stringQsciLexerVerilog(Inaktiver SystemtaskInactive system taskQsciLexerVerilog@Inaktive unbeendete ZeichenketteInactive unclosed stringQsciLexerVerilog\Inaktive nutzerdefinierte Tasks und Bezeichner+Inactive user defined tasks and identifiersQsciLexerVerilog*EingabeportdefinitionInput port declarationQsciLexerVerilog4Ein-/AusgabeportdefinitionInput/output port declarationQsciLexerVerilog,SchlüsselwortkommentarKeyword commentQsciLexerVerilogZeilenkommentar Line commentQsciLexerVerilogZahlNumberQsciLexerVerilogOperatorOperatorQsciLexerVerilog*AusgabeportdefinitionOutput port declarationQsciLexerVerilogPortverbindungPort connectionQsciLexerVerilog"PräprozessorblockPreprocessor blockQsciLexerVerilogLPrimäre Schlusselwörter und Bezeichner Primary keywords and identifiersQsciLexerVerilogPSekundäre Schlusselwörter und Bezeichner"Secondary keywords and identifiersQsciLexerVerilogZeichenketteStringQsciLexerVerilogSystemtask System taskQsciLexerVerilog.Unbeendete ZeichenketteUnclosed stringQsciLexerVerilogJNutzerdefinierte Tasks und Bezeichner"User defined tasks and identifiersQsciLexerVerilogKommentarComment QsciLexerYAMLStandardDefault QsciLexerYAML"DokumentbegrenzerDocument delimiter QsciLexerYAMLBezeichner Identifier QsciLexerYAMLSchlüsselwortKeyword QsciLexerYAMLZahlNumber QsciLexerYAMLOperatorOperator QsciLexerYAMLReferenz Reference QsciLexerYAML.Syntaxfehler MarkierungSyntax error marker QsciLexerYAML(Textblock MarkierungText block marker QsciLexerYAML&Kopieren&Copy QsciScintillaEin&fügen&Paste QsciScintilla"Wieder&herstellen&Redo QsciScintilla&Rückgängig&Undo QsciScintilla&AusschneidenCu&t QsciScintillaLöschenDelete QsciScintillaAlle auswählen Select All QsciScintillaˆsqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_de.ts000066400000000000000000004507431463772530400272320ustar00rootroot00000000000000 QsciCommand Move left one character Ein Zeichen nach links Move right one character Ein Zeichen nach rechts Move up one line Eine Zeile nach oben Move down one line Eine Zeile nach unten Move left one word part Ein Wortteil nach links Move right one word part Ein Wortteil nach rechts Move left one word Ein Wort nach links Move right one word Ein Wort nach rechts Scroll view down one line Eine Zeile nach unten rollen Scroll view up one line Eine Zeile nach oben rollen Move up one page Eine Seite hoch Move down one page Eine Seite nach unten Indent one level Eine Ebene einrücken Extend selection left one character Auswahl um ein Zeichen nach links erweitern Extend selection right one character Auswahl um ein Zeichen nach rechts erweitern Extend selection up one line Auswahl um eine Zeile nach oben erweitern Extend selection down one line Auswahl um eine Zeile nach unten erweitern Extend selection left one word part Auswahl um einen Wortteil nach links erweitern Extend selection right one word part Auswahl um einen Wortteil nach rechts erweitern Extend selection left one word Auswahl um ein Wort nach links erweitern Extend selection right one word Auswahl um ein Wort nach rechts erweitern Extend selection up one page Auswahl um eine Seite nach oben erweitern Extend selection down one page Auswahl um eine Seite nach unten erweitern Delete previous character Zeichen links löschen Delete current character Aktuelles Zeichen löschen Delete word to left Wort links löschen Delete word to right Wort rechts löschen Delete line to left Zeile links löschen Delete line to right Zeile rechts löschen Delete current line Aktuelle Zeile löschen Cut current line Aktuelle Zeile ausschneiden Cut selection Auswahl ausschneiden Copy selection Auswahl kopieren Paste Einfügen Redo last command Letzten Befehl wiederholen Cancel Abbrechen Toggle insert/overtype Einfügen/Überschreiben umschalten Scroll to start of document Zum Dokumentenanfang rollen Scroll to end of document Zum Dokumentenende rollen Scroll vertically to centre current line Vertical rollen, um aktuelle Zeile zu zentrieren Move to end of previous word Zum Ende des vorigen Wortes springen Extend selection to end of previous word Auswahl bis zum Ende des vorigen Wortes erweitern Move to end of next word Zum Ende des nächsten Wortes springen Extend selection to end of next word Auswahl bis zum Ende des nächsten Wortes erweitern Move to start of document line Zum Beginn der Dokumentenzeile springen Extend selection to start of document line Auswahl zum Beginn der Dokumentenzeile erweitern Extend rectangular selection to start of document line Rechteckige Auswahl zum Beginn der Dokumentenzeile erweitern Move to start of display line Zum Beginn der Anzeigezeile springen Extend selection to start of display line Auswahl zum Beginn der Anzeigezeile erweitern Move to start of display or document line Zum Beginn der Dokumenten- oder Anzeigezeile springen Extend selection to start of display or document line Rechteckige Auswahl zum Beginn der Dokumenten- oder Anzeigezeile erweitern Move to first visible character in document line Zum ersten sichtbaren Zeichen der Dokumentzeile springen Extend selection to first visible character in document line Auswahl zum ersten sichtbaren Zeichen der Dokumentzeile erweitern Extend rectangular selection to first visible character in document line Rechteckige Auswahl zum ersten sichtbaren Zeichen der Dokumentzeile erweitern Move to first visible character of display in document line Zum ersten angezeigten Zeichen der Dokumentzeile springen Extend selection to first visible character in display or document line Auswahl zum ersten sichtbaren Zeichen der Dokument- oder Anzeigezeile erweitern Move to end of document line Zum Ende der Dokumentzeile springen Extend selection to end of document line Auswahl zum Ende der Dokumentenzeile erweitern Extend rectangular selection to end of document line Rechteckige Auswahl zum Ende der Dokumentenzeile erweitern Move to end of display line Zum Ende der Anzeigezeile springen Extend selection to end of display line Auswahl zum Ende der Anzeigezeile erweitern Move to end of display or document line Zum Ende der Dokumenten- oder Anzeigezeile springen Extend selection to end of display or document line Rechteckige Auswahl zum Ende der Dokumenten- oder Anzeigezeile erweitern Move to start of document Zum Dokumentenanfang springen Extend selection to start of document Auswahl zum Dokumentenanfang erweitern Move to end of document Zum Dokumentenende springen Extend selection to end of document Auswahl zum Dokumentenende erweitern Stuttered move up one page "Stotternd" um eine Seite nach oben Stuttered extend selection up one page Auswahl "stotternd" um eine Seite nach oben erweitern Stuttered move down one page "Stotternd" um eine Seite nach unten Stuttered extend selection down one page Auswahl "stotternd" um eine Seite nach unten erweitern Delete previous character if not at start of line Zeichen links löschen, wenn nicht am Zeilenanfang Delete right to end of next word Rechts bis zum Ende des nächsten Wortes löschen Transpose current and previous lines Aktuelle und vorherige Zeile tauschen Duplicate the current line Aktuelle Zeile duplizieren Select all Select document Alle auswählen Move selected lines up one line Ausgewählte Zeilen um eine Zeile nach oben Move selected lines down one line Ausgewählte Zeilen um eine Zeile nach unten Convert selection to lower case Auswahl in Kleinbuchstaben umwandeln Convert selection to upper case Auswahl in Großbuchstaben umwandeln Insert newline Neue Zeile einfügen De-indent one level Eine Ebene ausrücken Undo last command Letzten Befehl rückgängig machen Zoom in Vergrößern Zoom out Verkleinern Move up one paragraph Einen Absatz nach oben Move down one paragraph Einen Absatz nach unten Extend selection up one paragraph Auswahl um einen Absatz nach oben erweitern Extend selection down one paragraph Auswahl um einen Absatz nach unten erweitern Copy current line Aktuelle Zeile kopieren Extend rectangular selection down one line Rechteckige Auswahl um eine Zeile nach unten erweitern Extend rectangular selection up one line Rechteckige Auswahl um eine Zeile nach oben erweitern Extend rectangular selection left one character Rechteckige Auswahl um ein Zeichen nach links erweitern Extend rectangular selection right one character Rechteckige Auswahl um ein Zeichen nach rechts erweitern Extend rectangular selection up one page Rechteckige Auswahl um eine Seite nach oben erweitern Extend rectangular selection down one page Rechteckige Auswahl um eine Seite nach unten erweitern Formfeed Seitenumbruch Duplicate selection Auswahl duplizieren QsciLexerAVS Default Standard Block comment Blockkommentar Nested block comment Verschachtelter Blockkommentar Line comment Zeilenkommentar Number Zahl Operator Operator Identifier Bezeichner Double-quoted string Zeichenkette in Anführungszeichen Triple double-quoted string Zeichenkette in dreifachen Anführungszeichen Keyword Schlüsselwort Filter Filter Plugin Plugin Function Funktion Clip property Clip Eigenschaft User defined Nutzer definiert QsciLexerBash Default Standard Error Fehler Comment Kommentar Number Zahl Keyword Schlüsselwort Double-quoted string Zeichenkette in Anführungszeichen Single-quoted string Zeichenkette in Hochkommata Operator Operator Identifier Bezeichner Scalar Skalar Parameter expansion Parametererweiterung Backticks Backticks Here document delimiter Here Dokument-Begrenzer Single-quoted here document Here Dokument in Hochkommata QsciLexerBatch Default Standard Comment Kommentar Keyword Schlüsselwort Label Marke Variable Variable Operator Operator Hide command character "Befehl verbergen" Zeichen External command Externer Befehl QsciLexerCMake Default Standard Comment Kommentar String Zeichenkette Left quoted string Links quotierte Zeichenkette Right quoted string Rechts quotierte Zeichenkette Function Funktion Variable Variable Label Marke User defined Nutzer definiert WHILE block WHILE Block FOREACH block FOREACH Block IF block IF Block MACRO block MACRO Block Variable within a string Variable in einer Zeichenkette Number Zahl QsciLexerCPP Number Zahl Keyword Schlüsselwort Double-quoted string Zeichenkette in Anführungszeichen Single-quoted string Zeichenkette in Hochkommata IDL UUID IDL UUID Pre-processor block Präprozessorblock Operator Operator Identifier Bezeichner Unclosed string Unbeendete Zeichenkette Default Standard Inactive default Inaktiver Standard C comment C Kommentar Inactive C comment Inaktiver C Kommentar C++ comment C++ Kommentar Inactive C++ comment Inaktiver C++ Kommentar JavaDoc style C comment JavaDoc C Kommentar Inactive JavaDoc style C comment Inaktiver JavaDoc C Kommentar Inactive number Inaktive Zahl Inactive keyword Inaktives Schlüsselwort Inactive double-quoted string Inaktive Zeichenkette in Anführungszeichen Inactive single-quoted string Inaktive Zeichenkette in Hochkommata Inactive IDL UUID Inaktive IDL UUID Inactive pre-processor block Inaktiver Präprozessorblock Inactive operator Inaktiver Operator Inactive identifier Inaktiver Bezeichner Inactive unclosed string Inaktive unbeendete Zeichenkette C# verbatim string Uninterpretierte C# Zeichenkette Inactive C# verbatim string Inaktive, Uninterpretierte C# Zeichenkette JavaScript regular expression JavaScript Regulärer Ausdruck Inactive JavaScript regular expression JavaScript Inaktiver Regulärer Ausdruck JavaDoc style C++ comment JavaDoc C++ Kommentar Inactive JavaDoc style C++ comment Inaktiver JavaDoc C++ Kommentar Inactive secondary keywords and identifiers Inaktive sekundäre Schlusselwörter und Bezeichner JavaDoc keyword JavaDoc Schlüsselwort Inactive JavaDoc keyword Inaktives JavaDoc Schlüsselwort JavaDoc keyword error JavaDoc Schlüsselwortfehler Inactive global classes and typedefs Inaktive globale Klassen und Typdefinitionen C++ raw string Rohe C++ Zeichenkette Inactive C++ raw string Inaktive rohe C++ Zeichenkette Vala triple-quoted verbatim string Vala Zeichenkette in dreifachen Hochkommata Inactive Vala triple-quoted verbatim string Inaktive Vala Zeichenkette in dreifachen Hochkommata Pike hash-quoted string Pike Zeichenkette in '#-Anführungszeichen' Inactive Pike hash-quoted string Inaktive Pike Zeichenkette in '#-Anführungszeichen' Pre-processor C comment C Präprozessorkommentar Inactive pre-processor C comment Inaktiver C Präprozessorkommentar JavaDoc style pre-processor comment JavaDoc Präprozessorkommentar Inactive JavaDoc style pre-processor comment Inaktiver JavaDoc Präprozessorkommentar User-defined literal Nutzer definiertes Literal Inactive user-defined literal Inaktives Nutzer definiertes Literal Task marker Aufgabenmarkierung Inactive task marker Inaktive Aufgabenmarkierung Escape sequence Escape-Sequenz Inactive escape sequence Inaktive Escape-Sequenz Secondary keywords and identifiers Sekundäre Schlusselwörter und Bezeichner Inactive JavaDoc keyword error Inaktiver JavaDoc Schlüsselwortfehler Global classes and typedefs Globale Klassen und Typdefinitionen QsciLexerCSS Default Standard Tag Tag Class selector Klassenselektor Pseudo-class Pseudoklasse Unknown pseudo-class Unbekannte Pseudoklasse Operator Operator CSS1 property CSS1 Eigenschaft Unknown property Unbekannte Eigenschaft Value Wert ID selector ID-Selektor Important Wichtig @-rule @-Regel Double-quoted string Zeichenkette in Anführungszeichen Single-quoted string Zeichenkette in Hochkommata CSS2 property CSS2 Eigenschaft Attribute Attribut CSS3 property CSS3 Eigenschaft Pseudo-element Pseudoelement Extended CSS property Erweiterte CSS Eigenschaft Extended pseudo-class Erweiterte Pseudoklasse Extended pseudo-element Erweitertes Pseudoelement Media rule Medienregel Variable Variable QsciLexerCSharp Verbatim string Uninterpretierte Zeichenkette QsciLexerCoffeeScript Default Standard C-style comment C Kommentar C++-style comment C++ Kommentar JavaDoc C-style comment JavaDoc C Kommentar Number Zahl Keyword Schlüsselwort Double-quoted string Zeichenkette in Anführungszeichen Single-quoted string Zeichenkette in Hochkommata IDL UUID IDL UUID Pre-processor block Präprozessorblock Operator Operator Identifier Bezeichner Unclosed string Unbeendete Zeichenkette C# verbatim string Uninterpretierte C# Zeichenkette Regular expression Regulärer Ausdruck JavaDoc C++-style comment JavaDoc C++ Kommentar Secondary keywords and identifiers Sekundäre Schlusselwörter und Bezeichner JavaDoc keyword JavaDoc Schlüsselwort JavaDoc keyword error JavaDoc Schlüsselwortfehler Global classes Globale Klassen Block comment Blockkommentar Block regular expression Regulärer Ausdrucksblock Block regular expression comment Regulärer Ausdrucksblockkommentar Instance property Instanz-Eigenschaft QsciLexerD Default Standard Block comment Blockkommentar Line comment Zeilenkommentar DDoc style block comment DDoc Blockkommentar Nesting comment schachtelbarer Kommentar Number Zahl Keyword Schlüsselwort Secondary keyword Sekundäres Schlüsselwort Documentation keyword Dokumentationsschlüsselwort Type definition Typdefinition String Zeichenkette Unclosed string Unbeendete Zeichenkette Character Zeichen Operator Operator Identifier Bezeichner DDoc style line comment DDoc Zeilenkommentar DDoc keyword DDoc Schlüsselwort DDoc keyword error DDoc Schlüsselwortfehler Backquoted string Zeichenkette in Rückwärtsstrichen Raw string Rohe Zeichenkette User defined 1 Nutzer definiert 1 User defined 2 Nutzer definiert 2 User defined 3 Nutzer definiert 3 QsciLexerDiff Default Standard Comment Kommentar Command Befehl Header Kopfzeilen Position Position Removed line Entfernte Zeile Added line Hinzugefügte Zeile Changed line Geänderte Zeile Added adding patch Hinzugefügter Ergänzungspatch Removed adding patch Entfernter Ergänzungspatch Added removing patch Hinzugefügter Entfernungspatch Removed removing patch Entfernter Entfernungspatch QsciLexerEDIFACT Default Standard Segment start Segmentstart Segment end Segmentende Element separator Elementtrenner Composite separator Zusammengesetzter Trenner Release separator Freigabetrenner UNA segment header UNA Segmentkopf UNH segment header UNH Segmentkopf Badly formed segment Schlecht geformtes Segment QsciLexerFortran77 Default Standard Comment Kommentar Number Zahl Single-quoted string Zeichenkette in Hochkommata Double-quoted string Zeichenkette in Anführungszeichen Unclosed string Unbeendete Zeichenkette Operator Operator Identifier Bezeichner Keyword Schlüsselwort Intrinsic function Intrinsic-Funktion Extended function Erweiterte Funktion Pre-processor block Präprozessorblock Dotted operator Dotted Operator Label Marke Continuation Fortsetzung QsciLexerHTML HTML default HTML Standard Tag Tag Unknown tag Unbekanntes Tag Attribute Attribut Unknown attribute Unbekanntes Attribut HTML number HTML Zahl HTML double-quoted string HTML Zeichenkette in Anführungszeichen HTML single-quoted string HTML Zeichenkette in Hochkommata Other text in a tag Anderer Text in einem Tag HTML comment HTML Kommentar Entity Entität End of a tag Tagende Start of an XML fragment Beginn eines XML Fragmentes End of an XML fragment Ende eines XML Fragmentes Script tag Skript Tag Start of an ASP fragment with @ Beginn eines ASP Fragmentes mit @ Start of an ASP fragment Beginn eines ASP Fragmentes CDATA CDATA Start of a PHP fragment Beginn eines PHP Fragmentes Unquoted HTML value HTML Wert ohne Anführungszeichen ASP X-Code comment ASP X-Code Kommentar SGML default SGML Standard SGML command SGML Befehl First parameter of an SGML command Erster Parameter eines SGML Befehls SGML double-quoted string SGML Zeichenkette in Anführungszeichen SGML single-quoted string SGML Zeichenkette in Hochkommata SGML error SGML Fehler SGML special entity SGML Spezielle Entität SGML comment SGML Kommentar First parameter comment of an SGML command Kommentar des ersten Parameters eines SGML Befehls SGML block default SGML Standardblock Start of a JavaScript fragment Beginn eines JavaScript Fragmentes JavaScript default JavaScript Standard JavaScript comment JavaScript Kommentar JavaScript line comment JavaScript Zeilenkommentar JavaDoc style JavaScript comment JavaDoc JavaScript Kommentar JavaScript number JavaScript Zahl JavaScript word JavaScript Wort JavaScript keyword JavaScript Schlüsselwort JavaScript double-quoted string JavaScript Zeichenkette in Anführungszeichen JavaScript single-quoted string JavaScript Zeichenkette in Hochkommata JavaScript symbol JavaScript Symbol JavaScript unclosed string JavaScript Unbeendete Zeichenkette JavaScript regular expression JavaScript Regulärer Ausdruck Start of an ASP JavaScript fragment Beginn eines ASP JavaScript Fragmentes ASP JavaScript default ASP JavaScript Standard ASP JavaScript comment ASP JavaScript Kommentar ASP JavaScript line comment ASP JavaScript Zeilenkommentar JavaDoc style ASP JavaScript comment JavaDoc ASP JavaScript Kommentar ASP JavaScript number ASP JavaScript Zahl ASP JavaScript word ASP JavaScript Wort ASP JavaScript keyword ASP JavaScript Schlüsselwort ASP JavaScript double-quoted string ASP JavaScript Zeichenkette in Anführungszeichen ASP JavaScript single-quoted string ASP JavaScript Zeichenkette in Hochkommata ASP JavaScript symbol ASP JavaScript Symbol ASP JavaScript unclosed string ASP JavaScript Unbeendete Zeichenkette ASP JavaScript regular expression ASP JavaScript Regulärer Ausdruck Start of a VBScript fragment Beginn eines VBScript Fragmentes VBScript default VBScript Standard VBScript comment VBScript Kommentar VBScript number VBScript Zahl VBScript keyword VBScript Schlüsselwort VBScript string VBScript Zeichenkette VBScript identifier VBScript Bezeichner VBScript unclosed string VBScript Unbeendete Zeichenkette Start of an ASP VBScript fragment Beginn eines ASP VBScript Fragmentes ASP VBScript default ASP VBScript Standard ASP VBScript comment ASP VBScript Kommentar ASP VBScript number ASP VBScript Zahl ASP VBScript keyword ASP VBScript Schlüsselwort ASP VBScript string ASP VBScript Zeichenkette ASP VBScript identifier ASP VBScript Bezeichner ASP VBScript unclosed string ASP VBScript Unbeendete Zeichenkette Start of a Python fragment Beginn eines Python Fragmentes Python default Python Standard Python comment Python Kommentar Python number Python Zahl Python double-quoted string Python Zeichenkette in Anführungszeichen Python single-quoted string Python Zeichenkette in Hochkommata Python keyword Python Schlüsselwort Python triple double-quoted string Python Zeichenkette in dreifachen Anführungszeichen Python triple single-quoted string Python Zeichenkette in dreifachen Hochkommata Python class name Python Klassenname Python function or method name Python Funktions- oder Methodenname Python operator Python Operator Python identifier Python Bezeichner Start of an ASP Python fragment Beginn eines ASP Python Fragmentes ASP Python default ASP Python Standard ASP Python comment ASP Python Kommentar ASP Python number ASP Python Zahl ASP Python double-quoted string ASP Python Zeichenkette in Anführungszeichen ASP Python single-quoted string ASP Python Zeichenkette in Hochkommata ASP Python keyword ASP Python Schlüsselwort ASP Python triple double-quoted string ASP Python Zeichenkette in dreifachen Anführungszeichen ASP Python triple single-quoted string ASP Python Zeichenkette in dreifachen Hochkommata ASP Python class name ASP Python Klassenname ASP Python function or method name ASP Python Funktions- oder Methodenname ASP Python operator ASP Python Operator ASP Python identifier ASP Python Bezeichner PHP default PHP Standard PHP double-quoted string PHP Zeichenkette in Anführungszeichen PHP single-quoted string PHP Zeichenkette in Hochkommata PHP keyword PHP Schlüsselwort PHP number PHP Zahl PHP comment PHP Kommentar PHP line comment PHP Zeilenkommentar PHP double-quoted variable PHP Variable in Anführungszeichen PHP operator PHP Operator PHP variable PHP Variable QsciLexerIDL UUID UUID QsciLexerJSON Default Standard Number Zahl String Zeichenkette Unclosed string Unbeendete Zeichenkette Property Eigenschaft Escape sequence Escape-Sequenz Line comment Zeilenkommentar Block comment Blockkommentar Operator Operator IRI IRI JSON-LD compact IRI JSON-LD kompaktes IRI JSON keyword JSON Schlüsselwort JSON-LD keyword JSON-LD Schlüsselwort Parsing error Analysefehler QsciLexerJavaScript Regular expression Regulärer Ausdruck QsciLexerLua Default Standard Comment Kommentar Line comment Zeilenkommentar Number Zahl Keyword Schlüsselwort String Zeichenkette Character Zeichen Literal string Uninterpretierte Zeichenkette Preprocessor Präprozessor Operator Operator Identifier Bezeichner Unclosed string Unbeendete Zeichenkette Basic functions Basisfunktionen String, table and maths functions Zeichenketten-, Tabelle- und mathematische Funktionen Coroutines, i/o and system facilities Koroutinen, I/O- und Systemfunktionen User defined 1 Nutzer definiert 1 User defined 2 Nutzer definiert 2 User defined 3 Nutzer definiert 3 User defined 4 Nutzer definiert 4 Label Marke QsciLexerMakefile Default Standard Comment Kommentar Preprocessor Präprozessor Variable Variable Operator Operator Target Ziel Error Fehler QsciLexerMarkdown Default Standard Special Spezial Strong emphasis using double asterisks Fettschrift mit doppelten Sternen Strong emphasis using double underscores Fettschrift mit doppelten Unterstrichen Emphasis using single asterisks Kursive Schrift mit einfachen Sternen Emphasis using single underscores Kursive Schrift mit einfachen Unterstrichen Level 1 header Überschrift Ebene 1 Level 2 header Überschrift Ebene 2 Level 3 header Überschrift Ebene 3 Level 4 header Überschrift Ebene 4 Level 5 header Überschrift Ebene 5 Level 6 header Überschrift Ebene 6 Pre-char Einleitungszeichen Unordered list item Nicht nummeriertes Listenelement Ordered list item Nummeriertes Listenelement Block quote Blockzitat Strike out Durchgestrichen Horizontal rule Horizontale Linie Link Hyperlink Code between backticks Code zwischen Backticks Code between double backticks Code zwischen doppelten Backticks Code block Codeblock QsciLexerMatlab Default Standard Comment Kommentar Command Befehl Number Zahl Keyword Schlüsselwort Single-quoted string Zeichenkette in Hochkommata Operator Operator Identifier Bezeichner Double-quoted string Zeichenkette in Anführungszeichen QsciLexerPO Default Standard Comment Kommentar Message identifier Meldungsbezeichner Message identifier text Meldungsbezeichnertext Message string Meldungszeichenkette Message string text Meldungszeichenkettentext Message context Meldungskontext Message context text Meldungskontexttext Fuzzy flag Unschrfmarkierung Programmer comment Programmiererkommentar Reference Referenz Flags Markierung Message identifier text end-of-line Meldungsbezeichnertext Zeilenende Message string text end-of-line Meldungszeichenkettentext Zeilenende Message context text end-of-line Meldungskontexttext Zeilenende QsciLexerPOV Default Standard Comment Kommentar Comment line Kommentarzeile Number Zahl Operator Operator Identifier Bezeichner String Zeichenkette Unclosed string Unbeendete Zeichenkette Directive Direktive Bad directive Ungültige Direktive Objects, CSG and appearance Objekte, CSG und Erscheinung Types, modifiers and items Typen, Modifizierer und Items Predefined identifiers Vordefinierter Bezeichner Predefined functions Vordefinierte Funktion User defined 1 Nutzer definiert 1 User defined 2 Nutzer definiert 2 User defined 3 Nutzer definiert 3 QsciLexerPascal Default Standard Line comment Zeilenkommentar Number Zahl Keyword Schlüsselwort Single-quoted string Zeichenkette in Hochkommata Operator Operator Identifier Bezeichner '{ ... }' style comment '{ ... }' Kommentar '(* ... *)' style comment '(* ... *)' Kommentar '{$ ... }' style pre-processor block '{$ ... }' Präprozessorblock '(*$ ... *)' style pre-processor block '(*$ ... *)' Präprozessorblock Hexadecimal number Hexadezimale Zahl Unclosed string Unbeendete Zeichenkette Character Zeichen Inline asm Inline Assembler QsciLexerPerl Default Standard Error Fehler Comment Kommentar POD POD Number Zahl Keyword Schlüsselwort Double-quoted string Zeichenkette in Anführungszeichen Single-quoted string Zeichenkette in Hochkommata Operator Operator Identifier Bezeichner Scalar Skalar Array Feld Hash Hash Symbol table Symboltabelle Regular expression Regulärer Ausdruck Substitution Ersetzung Backticks Backticks Data section Datensektion Here document delimiter Here Dokument-Begrenzer Single-quoted here document Here Dokument in Hochkommata Double-quoted here document Here Dokument in Anführungszeichen Backtick here document Here Dokument in Backticks Quoted string (q) Zeichenkette (q) Quoted string (qq) Zeichenkette (qq) Quoted string (qx) Zeichenkette (qx) Quoted string (qr) Zeichenkette (qr) Quoted string (qw) Zeichenkette (qw) POD verbatim POD wörtlich Subroutine prototype Subroutinen Prototyp Format identifier Formatidentifikator Format body Formatzweig Double-quoted string (interpolated variable) Zeichenkette in Anführungszeichen (interpolierte Variable) Translation Übersetzung Regular expression (interpolated variable) Regulärer Ausdruck (interpolierte Variable) Substitution (interpolated variable) Ersetzung (interpolierte Variable) Backticks (interpolated variable) Backticks (interpolierte Variable) Double-quoted here document (interpolated variable) Here Dokument in Anführungszeichen (interpolierte Variable) Backtick here document (interpolated variable) Here Dokument in Backticks (interpolierte Variable) Quoted string (qq, interpolated variable) Zeichenkette (qq, interpolierte Variable) Quoted string (qx, interpolated variable) Zeichenkette (qx, interpolierte Variable) Quoted string (qr, interpolated variable) Zeichenkette (qr, interpolierte Variable) QsciLexerPostScript Default Standard Comment Kommentar DSC comment DSC Kommentar DSC comment value DSC Kommentarwert Number Zahl Name Name Keyword Schlüsselwort Literal Literal Immediately evaluated literal Direkt ausgeführtes Literal Array parenthesis Feldklammern Dictionary parenthesis Dictionary-Klammern Procedure parenthesis Prozedurklammern Text Text Hexadecimal string Hexadezimale Zeichenkette Base85 string Base85 Zeichenkette Bad string character Ungültiges Zeichen für Zeichenkette QsciLexerProperties Default Standard Comment Kommentar Section Abschnitt Assignment Zuweisung Default value Standardwert Key Schlüssel QsciLexerPython Comment Kommentar Number Zahl Double-quoted string Zeichenkette in Anführungszeichen Single-quoted string Zeichenkette in Hochkommata Keyword Schlüsselwort Triple single-quoted string Zeichenkette in dreifachen Hochkommata Triple double-quoted string Zeichenkette in dreifachen Anführungszeichen Class name Klassenname Function or method name Funktions- oder Methodenname Operator Operator Identifier Bezeichner Comment block Kommentarblock Unclosed string Unbeendete Zeichenkette Double-quoted f-string F-Zeichenkette in Anführungszeichen Single-quoted f-string F-Zeichenkette in Hochkommata Triple single-quoted f-string F-Zeichenkette in dreifachen Hochkommata Triple double-quoted f-string F-Zeichenkette in dreifachen Anführungszeichen Default Standard Highlighted identifier Hervorgehobener Bezeichner Decorator Dekorator QsciLexerRuby Default Standard Comment Kommentar Number Zahl Double-quoted string Zeichenkette in Anführungszeichen Single-quoted string Zeichenkette in Hochkommata Keyword Schlüsselwort Class name Klassenname Function or method name Funktions- oder Methodenname Operator Operator Identifier Bezeichner Error Fehler POD POD Regular expression Regulärer Ausdruck Global Global Symbol Symbol Module name Modulname Instance variable Instanzvariable Class variable Klassenvariable Backticks Backticks Data section Datensektion Here document delimiter Here Dokument-Begrenzer Here document Here Dokument %q string %q Zeichenkette %Q string %Q Zeichenkette %x string %x Zeichenkette %r string %r Zeichenkette %w string %w Zeichenkette Demoted keyword zurückgestuftes Schlüsselwort stdin Stdin stdout Stdout stderr Stderr QsciLexerSQL Default Standard Comment Kommentar Number Zahl Keyword Schlüsselwort Single-quoted string Zeichenkette in Hochkommata Operator Operator Identifier Bezeichner Comment line Kommentarzeile JavaDoc style comment JavaDoc Kommentar Double-quoted string Zeichenkette in Anführungszeichen SQL*Plus keyword SQL*Plus Schlüsselwort SQL*Plus prompt SQL*Plus Eingabe SQL*Plus comment SQL*Plus Kommentar # comment line # Kommentarzeile JavaDoc keyword JavaDoc Schlüsselwort JavaDoc keyword error JavaDoc Schlüsselwortfehler User defined 1 Nutzer definiert 1 User defined 2 Nutzer definiert 2 User defined 3 Nutzer definiert 3 User defined 4 Nutzer definiert 4 Quoted identifier Bezeichner in Anführungszeichen Quoted operator Operator in Anführungszeichen QsciLexerSpice Default Standard Identifier Bezeichner Command Befehl Function Funktion Parameter Parameter Number Zahl Delimiter Delimiter Value Wert Comment Kommentar QsciLexerTCL Default Standard Comment Kommentar Comment line Kommentarzeile Number Zahl Quoted keyword angeführtes Schlüsselwort Quoted string Zeichenkette Operator Operator Identifier Bezeichner Substitution Ersetzung Brace substitution Klammerersetzung Modifier Modifizierer Expand keyword Erweiterungsschlüsselwort TCL keyword TCL Schlüsselwort Tk keyword Tk Schlüsselwort iTCL keyword iTCL Schlüsselwort Tk command Tk Befehl User defined 1 Nutzer definiert 1 User defined 2 Nutzer definiert 2 User defined 3 Nutzer definiert 3 User defined 4 Nutzer definiert 4 Comment box Kommentarbox Comment block Kommentarblock QsciLexerTeX Default Standard Special Spezial Group Gruppe Symbol Symbol Command Befehl Text Text QsciLexerVHDL Default Standard Comment Kommentar Comment line Kommentarzeile Number Zahl String Zeichenkette Operator Operator Identifier Bezeichner Unclosed string Unbeendete Zeichenkette Keyword Schlüsselwort Standard operator Standardoperator Attribute Attribut Standard function Standardfunktion Standard package Standardpaket Standard type Standardtyp User defined Nutzer definiert Comment block Kommentarblock QsciLexerVerilog Default Standard Inactive default Inaktiver Standard Comment Kommentar Inactive comment Inaktiver Kommentar Line comment Zeilenkommentar Inactive line comment Inaktiver Zeilenkommentar Bang comment Bang Kommentar Inactive bang comment Inaktiver Bang Kommentar Number Zahl Inactive number Inaktive Zahl Primary keywords and identifiers Primäre Schlusselwörter und Bezeichner Inactive primary keywords and identifiers Inaktive primäre Schlusselwörter und Bezeichner String Zeichenkette Inactive string Inaktive Zeichenkette Secondary keywords and identifiers Sekundäre Schlusselwörter und Bezeichner Inactive secondary keywords and identifiers Inaktive sekundäre Schlusselwörter und Bezeichner System task Systemtask Inactive system task Inaktiver Systemtask Preprocessor block Präprozessorblock Inactive preprocessor block Inaktiver Präprozessorblock Operator Operator Inactive operator Inaktiver Operator Identifier Bezeichner Inactive identifier Inaktiver Bezeichner Unclosed string Unbeendete Zeichenkette Inactive unclosed string Inaktive unbeendete Zeichenkette User defined tasks and identifiers Nutzerdefinierte Tasks und Bezeichner Inactive user defined tasks and identifiers Inaktive nutzerdefinierte Tasks und Bezeichner Keyword comment Schlüsselwortkommentar Inactive keyword comment Inaktiver Schlüsselwortkommentar Input port declaration Eingabeportdefinition Inactive input port declaration Inaktive Eingabeportdefinition Output port declaration Ausgabeportdefinition Inactive output port declaration Inaktive Ausgabeportdefinition Input/output port declaration Ein-/Ausgabeportdefinition Inactive input/output port declaration Inaktive Ein-/Ausgabeportdefinition Port connection Portverbindung Inactive port connection Inaktive Portverbindung QsciLexerYAML Default Standard Comment Kommentar Identifier Bezeichner Keyword Schlüsselwort Number Zahl Reference Referenz Document delimiter Dokumentbegrenzer Text block marker Textblock Markierung Syntax error marker Syntaxfehler Markierung Operator Operator QsciScintilla &Undo &Rückgängig &Redo Wieder&herstellen Cu&t &Ausschneiden &Copy &Kopieren &Paste Ein&fügen Delete Löschen Select All Alle auswählen sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_es.qm000066400000000000000000002376721463772530400272440ustar00rootroot00000000000000<¸dÊÍ!¿`¡½ÝBHNi¯QÉî U4ß>U4ûZwd’Zwª•Ôw¯§Ô&è˜Ý|0KÀŸH5ë̩Ԯv¬ô챬ôL I$P I$šÝTÁ»'ƒtÊF)[Ĭ5*¦y%Ä+‹¯&-+į&d9•ÌBm­Ô¾G†´H˜‰ÖÒL™b<õL™b¹ÚL™bÜ™L™b÷ŒM'ãÆ¤N–À ¯Rx¼AîRx¼CÜRx¼ŽRx¼µVŠ¥/<\ƒµe„\ƒµ9^ t¦Ÿc¶Âÿoº´sàç¥`zªþüh{‚O|>M#–VEù¶žë㣳җ6¥Ò÷…½­4~~D¶Ú´”~ÇôÿyÌ/õ,ÌÛ…ËáÎå%Q›äoò¶ZäoòºMóeâ­Nº¥-U&ëõ^|î 5'Kc/À«C3ùש:ëD=ZÔ›FkyâôR½5 „eöž6Éw§t7Nw§tf<w§tp<w§t®£{‚Õ1t{ò#ÍÃtŸòäij|™õ4Èä›%Ô$À¤ô›ž¨¸ô Ž©>^5©l"çþ²/WÆß´…u4DÁm…ÌgÁm…ýbÁm…°Ám…JÐæÔ9PÐæÔ> ÐæÔAªÐæÔZtÐæÔlÍÐæÔsXÐæÔFÐæÔ´ØÐæÔÅÐæÔÕÐæÔÞÐæÔëFÐæÔñmÐæÔúÐæÔÿçÐæÔ#ÐæÔ#üÑ'r%[Òû‰ØºÕ‹ô Úú.\àŽ‰_Õàž‰`àþ‰_‹âð½âø³IEå@U6å±åµ ªÅ†ž!ÍÂ#R#õúVNhø.Ådü¹ÚÂfÁM¬h2 ‰€ež£œUÉW‚…ƒ=‡ó}ÀÕ˜bÎÔ¢_מ–¶Š¥%ùÈ4wQÐ µÎÓ9U èÓpÅ Ó«žáÕ;%|ñdòSVñdò‹@ È,ëu.[Oå-ë7 ’q<9têVî‰7¤W³”ÙmþDÆÑU4…$e…®œˆ¾õåÜŒ„´"ÂM¾k”äÞf›¥í4ت{Fg¹š¤KÁ¼È$r¥ÁoµüÍÏ¥ÙÕ7TÒ…ßêÊ­ácÜñ?’Ÿ—ó35àøÅò²3 ç—’«$Š%N4œ%_Qñ¥e[¥å!b[îu òfŠÓe!l&÷œÓE Zk³‰G^– …¿˜I¼¡®cR ¤[thx¬,¥&ѹÃth ÁÓ~‹Ű¹£Ð:Â8¡Ò(TÇ)Õ 4¢‹ÕIží×뤫ÝÛÙå-ãX|ø*ëzÂxô'ôséÿ»“Á÷ߥ°½n½²½ãŸ½û< Ÿ•Hï Ÿ•¯9 ò÷˜ævx„6îæ>6î Kct‰G Täã$<Ä•l*ŽtÇ~,_—‡Ç@ÙAv9@ÙA·Ò@ÙAÐ?@ÙAÊ@ÙA f@ÙBv˜@ÙB¸3@ÙBР@ÙB+@ÙB Ç@ÙCv÷@ÙC¸”@ÙCÑ@ÙCŒ@ÙC (@ÙD¸õ@ÙDí@ÙD ‰Aãc™B”têH¦ô¯»[“ôpÈ\8Â:R\8Â>L\8ÂDÓ\8ÂZ¶\8Âm\8Ât;\8ÂÊ\8±\8µî\8ÂÅL\8ÂÍy\8ÂÕ\8ÂÞÐ\8Âì\8Âñ²\8Âú£\8Â)\8ÂÆ\8 \8Âf\8Ây\8Â$?k*ró\trón_ró ±s½þ:¾vBß­{:•G^™‚‚?™‚‚䑨噫59 «5=ë5Iî«5j.«5s«5~ž«5´“«5Ä¿«5Í4«5Ôv«5ÞG«5ñ%«5ùp«5þ\«5«5œ«5Ý«5ç«5#¶«GE~«GuJ«G²«G¶¡«GÏ#«G«G!P¯Ê‚á°9\ûþ°9\º:4öÃÀ¾|ÐäE³Ú§“éõâ¯t°hñŽÔ“âøƒ„Áùå& 'qËÑß)n,Ü*ÄÃδ8ÍÒV<?^t‘‡]íu0Ä_pÔ7 o?C"-}Ú\}Úm–}Ú€B“Ïdæœ('«% «.xÙ¶•§‹Š½Ç¡iÇ#»`È:…È>€ÈB&ÈZéÈc`ÈmTÈtlȀȱKȶ!ȺÈÅ‚ÈÎÈÕÓÈßÈñèÈú×È\È SȚȤÈ$sѽ8KÒçÇêÔ‡„@æà槤†—µ£wÔb%§•Zîî©"“$)6%Ï)µ*yYaa4û›FÎ5œtjã6|Ô]8¸ô ê@E%÷C«³ì>_uâœMb]zd*ád*iàd*Éâ,d*ùâiøbÕm;¼qª¬’ü4ª¶Äü™«¤ô]«¤wô «¤×ôš«¤çô׫¦wóã®×t£¯LÄYfÜŒ¤•ÝÀ©¥àä„sækÔ[ ðÓE™ä§‘ _¤Œ’þÊ&@Å''&åµ›"*˜+ü‰ÜÊ3g”u<.)YFkyàrKA\^]D£½‹i1KCŸjX2|9j½‚jÙäLjè2{Æo1¤(Õ|Ö^/€ÓŽ*ƒ›òÁ@ƒœBû‡ã"p‡ã"³K‡ã"ÓžŠlTh~åBa~åF,~åe´~åºÕ•ŸN;•²´ƒV¦2cÎSªN¥2аœ2¬ºûÅÌøÀÒSøØ,7Pß`êeå­Iµå­iìèóä©8쉄Áöûö2Œøù¦”®þ@ty_ ~ÕU &0':ñ &0'ò’ 3ø¤ß ?3äª' @|U«z A…ƒU A…ƒó DQœêà fÌÉ±Ú o” ©¦ /0 @t žž2R™ žž2÷ ¨Ÿ×Ž¡ ¬÷÷® ¯²A7 ±^÷ è ²¹[" ´×88 ´×<‹ ´×H† ´×`ø ´×i$ ´×}Õ ´×ÄS ´×Ûƒ ´×ïâ ´×÷" ´×ýó º°îA ÉX$× Ûí=ßi ù×$kf iäÅ ,Eõ§ óWD Ï5B ïÔžB ê4š =WUº œbÀA œ‚¿… œ’¿ã œ¢¾É œ²¿' œÒ¾k " ú 'ç4G« )ì×O *²S;Æ *²SØq *²Sõ +O4èú 0è‚Ô FYžu— Iq>>º Sæµî~ Sæµõ] ZŒsÝ ZÿU3Š ^×V¥ ^×l d8wê d8Ú d8N d8 ; d<< d<@h d<Bœ d<x! d<|¬ d<³… d<¹V d<ÃÓ d<Æ, d<Ì+ d<ÙQ d<è· d<í- d<îÊ d<õù d<ý& d<† d<Î d<¶ d<e d<"Ö d4G g›$ Ü hÁÒïb kŸ,Á~ kŸ, ß qe’Ï s(ç^ |‡Gó ’à’z` •ø$–» œµdÚ ¡úR`i ©ì% °ÖBŠ ¼Œt7ú ¼ŒtÖ ™ J¬Ž8Ô J¬ŽCf J¬ŽF K†ByÀ WL…éI WöÜ…Z fÎòb jßã½ oÂ=& oÂݪ oÂøÓ §'å ¯,qõ ÁÅíµ ÈkT… Èü%ˤ Èü%$­ ÐAŽ~é Ðæ·“g ÝGJ ç! ñXì ôÏr$ì ÷ïÄŒ( û'ך¬ ûóu $ þxŽ„>  .ÙŽ  .ö6 ¦EªÊ '¸4/È 1“5» 943³Á @&4£3 @*$¢í _á²ù c¥b}} t}49’ t}4s˜ t}4°Ã t}4µP t}4ÕG t}4" wt¼W ‚‰ÔXx „\RÝ …ãaÅ ‡—´” Œ?D†= ”¹¢S¤ ”¹¢Ý Ig]È Igos Igué Ig Ig²J Ig·€ IgÏí IgÖ} IgóŽ Igg Ig!× ¡„J3 «ãtW  «ãtkã «ãtþ¡ ºut Œ Â`åK ×.„¨© Ü}n[ Ý9å ä‡ÎNî åœÈ‚ ñyˆàÓW­B‚L cò X édÆ'»Ò9 …ˆR=¤eŸG2zÀHI° O¨ ÛíV‰Ç¡ùW´\˜]‹gŠîe–T’]hw„–Wiår¤Fld‚æwæg£Í{Ô‡g‡ó-Ã'ÚC矑óâ•›&4’¡N¥,£Ç?ü£Ç]£Çd'£Ço£Ç€ª£Çž£ÇÖ£Çåp£Çò$£Çû’£Ç_£õBƒÝ¥_oÎ¥¿´‡ ­)wó´Î[¸¤4AƦ´Çn`ÈÙ¤gÐL„ÊÓkCÏrà|¥öëj…yìs4ö 5+Žö²å¾þ2Yþþ2—‹@’‰±"wèh#}weí'[Òþ2¡…c4+4/k8Û46j9<3ÂFkyáRÎ’ Pm%w óu@Ô;ku@ÔEÏu@Ôº„Õ$q~‰2›í)tµnE1ýÀ–T£Ä””{pÄÔ$IÍÁ#»ÞÜå%(Iá²Äìçå9r±…ù¬•wœi'QCancelarCancel QsciCommand@Convertir selección a minúsculasConvert selection to lower case QsciCommand@Convertir selección a mayúsculasConvert selection to upper case QsciCommand&Copiar línea actualCopy current line QsciCommand Copiar selecciónCopy selection QsciCommand&Cortar línea actualCut current line QsciCommand Cortar selección Cut selection QsciCommand<Deshacer un nivel de indentadoDe-indent one level QsciCommand2Borrar el carácter actualDelete current character QsciCommand&Borrar línea actualDelete current line QsciCommand>Borrar línea hacia la izquierdaDelete line to left QsciCommand:Borrar línea hacia la derechaDelete line to right QsciCommand0Borrar carácter anteriorDelete previous character QsciCommandzBorrar carácter anterior si no está al principio de una línea1Delete previous character if not at start of line QsciCommandtBorrar a la derecha hasta el final de la siguiente palabra Delete right to end of next word QsciCommandBBorrar palabra hacia la izquierdaDelete word to left QsciCommand>Borrar palabra hacia la derechaDelete word to right QsciCommand$Duplicar selecciónDuplicate selection QsciCommand*Duplicar línea actualDuplicate the current line QsciCommandnExtender la selección rectangular una línea hacia abajo*Extend rectangular selection down one line QsciCommandpExtender la selección rectangular una página hacia abajo*Extend rectangular selection down one page QsciCommand€Extender la selección rectangular un carácter hacia la izquierda/Extend rectangular selection left one character QsciCommand|Extender la selección rectangular un carácter hacia la derecha0Extend rectangular selection right one character QsciCommand‚Extender selección rectangular al final de la línea del documento4Extend rectangular selection to end of document line QsciCommand¦Extender selección rectangular al primer carácter visible en la línea del documentoHExtend rectangular selection to first visible character in document line QsciCommandŠExtender selección rectangular al principio de la línea del documento6Extend rectangular selection to start of document line QsciCommandpExtender la selección rectangular una línea hacia arriba(Extend rectangular selection up one line QsciCommandrExtender la selección rectangular hacia arriba una página(Extend rectangular selection up one page QsciCommandVExtender la selección una línea hacia abajoExtend selection down one line QsciCommandXExtender la selección hacia abajo una páginaExtend selection down one page QsciCommandXExtender la selección un párrafo hacia abajo#Extend selection down one paragraph QsciCommandhExtender la selección un carácter hacia la izquierda#Extend selection left one character QsciCommand`Extender la selección una palabra a la izquierdaExtend selection left one word QsciCommandrExtender la selección parte de una palabra a la izquierda#Extend selection left one word part QsciCommanddExtender la selección un carácter hacia la derecha$Extend selection right one character QsciCommand\Extender la selección una palabra a la derechaExtend selection right one word QsciCommandnExtender la selección parte de una palabra a la derecha$Extend selection right one word part QsciCommandfExtender selección al final de la línea visualizada'Extend selection to end of display line QsciCommand†Extender selección al final de la línea visualizada o del documento3Extend selection to end of display or document line QsciCommandRExtender selección al final del documento#Extend selection to end of document QsciCommandjExtender selección al final de la línea del documento(Extend selection to end of document line QsciCommandxExtender la selección hasta el final de la palabra siguiente$Extend selection to end of next word QsciCommanddExtender selección al final de la palabra anterior(Extend selection to end of previous word QsciCommand”Extender selección al primer carácter de línea visualizada o del documentoGExtend selection to first visible character in display or document line QsciCommandŽExtender selección al primer carácter visible en la línea del documentoDesplazar una línea hacia abajoMove down one line QsciCommand8Mover hacia abajo una páginaMove down one page QsciCommand@Desplazar un párrafo hacia abajoMove down one paragraph QsciCommandHMover un carácter hacia la izquierdaMove left one character QsciCommandHMover una palabra hacia la izquierdaMove left one word QsciCommandZMover parte de una palabra hacia la izquierdaMove left one word part QsciCommandDMover un carácter hacia la derechaMove right one character QsciCommandDMover una palabra hacia la derechaMove right one word QsciCommandVMover parte de una palabra hacia la derechaMove right one word part QsciCommandhMover las líneas seleccionadas una línea hacia abajo!Move selected lines down one line QsciCommandjMover las líneas seleccionadas una línea hacia arribaMove selected lines up one line QsciCommandLMover al final de la línea visualizadaMove to end of display line QsciCommandlMover al final de la línea visualizada o del documento'Move to end of display or document line QsciCommand8Mover al final del documentoMove to end of document QsciCommandPMover al final de la línea del documentoMove to end of document line QsciCommandLMover al final de la palabra siguienteMove to end of next word QsciCommandDMover al final de palabra anteriorMove to end of previous word QsciCommandtMover al primer carácter visible en la línea del documento0Move to first visible character in document line QsciCommand–Extender selección al primer carácter visualizado en la línea del documento;Move to first visible character of display in document line QsciCommandTMover al principio de la línea visualizadaMove to start of display line QsciCommandtMover al principio de la línea visualizada o del documento)Move to start of display or document line QsciCommand@Mover al principio del documentoMove to start of document QsciCommandXMover al principio de la línea del documentoMove to start of document line QsciCommand@Desplazar una línea hacia arribaMove up one line QsciCommand:Mover hacia arriba una páginaMove up one page QsciCommandBDesplazar un párrafo hacia arribaMove up one paragraph QsciCommand PegarPaste QsciCommand,Rehacer último comandoRedo last command QsciCommand@Desplazar al final del documentoScroll to end of document QsciCommandHDesplazar al principio del documentoScroll to start of document QsciCommandhDesplazar verticalmente al centro de la línea actual(Scroll vertically to centre current line QsciCommandPDesplazar la vista una línea hacia abajoScroll view down one line QsciCommandRDesplazar la vista una línea hacia arribaScroll view up one line QsciCommand Seleccionar todo Select all QsciCommandrExtender progresivamente selección hacia abajo una página(Stuttered extend selection down one page QsciCommandtExtender progresivamente selección hacia arriba una página&Stuttered extend selection up one page QsciCommandXMover progresivamente una página hacia abajoStuttered move down one page QsciCommandZMover progresivamente una página hacia arribaStuttered move up one page QsciCommand>Conmutar insertar/sobreescribirToggle insert/overtype QsciCommandFTransponer líneas actual y anterior$Transpose current and previous lines QsciCommand.Deshacer último comandoUndo last command QsciCommandAumentar zoomZoom in QsciCommandDisminuir zoomZoom out QsciCommand(Comentario de bloque Block comment QsciLexerAVS(Propiedad de recorte Clip property QsciLexerAVSPor defectoDefault QsciLexerAVS4Cadena con comillas doblesDouble-quoted string QsciLexerAVS FiltroFilter QsciLexerAVSFunciónFunction QsciLexerAVSIdentificador Identifier QsciLexerAVSPalabra claveKeyword QsciLexerAVS&Comentario de línea Line comment QsciLexerAVS8Comentario de bloque anidadoNested block comment QsciLexerAVS NúmeroNumber QsciLexerAVSOperadorOperator QsciLexerAVS PluginPlugin QsciLexerAVS>Cadena con triple comilla dobleTriple double-quoted string QsciLexerAVS.Definido por el usuario User defined QsciLexerAVSComilla inversa Backticks QsciLexerBashComentarioComment QsciLexerBashPor defectoDefault QsciLexerBash4Cadena con comillas doblesDouble-quoted string QsciLexerBash ErrorError QsciLexerBashdDelimitador de documento integrado (here document)Here document delimiter QsciLexerBashIdentificador Identifier QsciLexerBashPalabra claveKeyword QsciLexerBash NúmeroNumber QsciLexerBashOperadorOperator QsciLexerBash.Expansión de parámetrosParameter expansion QsciLexerBashEscalarScalar QsciLexerBashlDocumento integrado (here document) con comilla simpleSingle-quoted here document QsciLexerBash6Cadena con comillas simplesSingle-quoted string QsciLexerBashComentarioCommentQsciLexerBatchPor defectoDefaultQsciLexerBatchComando externoExternal commandQsciLexerBatch:Ocultar caracteres de comandoHide command characterQsciLexerBatchPalabra claveKeywordQsciLexerBatchEtiquetaLabelQsciLexerBatchOperadorOperatorQsciLexerBatchVariableVariableQsciLexerBatchComentarioCommentQsciLexerCMakePor defectoDefaultQsciLexerCMakeBloque FOREACH FOREACH blockQsciLexerCMakeFunciónFunctionQsciLexerCMakeBloque IFIF blockQsciLexerCMakeEtiquetaLabelQsciLexerCMakeDCadena con comillas a la izquierdaLeft quoted stringQsciLexerCMakeBloque MACRO MACRO blockQsciLexerCMake NúmeroNumberQsciLexerCMake@Cadena con comillas a la derechaRight quoted stringQsciLexerCMake(Cadena de caracteresStringQsciLexerCMake.Definido por el usuario User definedQsciLexerCMakeVariableVariableQsciLexerCMake,Variable en una cadenaVariable within a stringQsciLexerCMakeBloque WHILE WHILE blockQsciLexerCMakeComentario C C comment QsciLexerCPP"Cadena C# textualC# verbatim string QsciLexerCPPComentario C++ C++ comment QsciLexerCPP&Cadena en bruto C++C++ raw string QsciLexerCPPPor defectoDefault QsciLexerCPP4Cadena con comillas doblesDouble-quoted string QsciLexerCPP&Secuencia de escapeEscape sequence QsciLexerCPP4Clases globales y typedefsGlobal classes and typedefs QsciLexerCPPIDL UUIDIDL UUID QsciLexerCPPIdentificador Identifier QsciLexerCPP*Comentario C inactivoInactive C comment QsciLexerCPP4Cadena C# textual inactivaInactive C# verbatim string QsciLexerCPP.Comentario C++ inactivoInactive C++ comment QsciLexerCPP&Cadena inactiva C++Inactive C++ raw string QsciLexerCPP"IDL UUID inactivoInactive IDL UUID QsciLexerCPPBPalabra clave de JavaDoc inactivaInactive JavaDoc keyword QsciLexerCPPTError en palabra clave de Javadoc inactivoInactive JavaDoc keyword error QsciLexerCPPHComentario C estilo JavaDoc inactivo Inactive JavaDoc style C comment QsciLexerCPPLComentario C++ estilo JavaDoc inactivo"Inactive JavaDoc style C++ comment QsciLexerCPPfComentario de preprocesador estilo JavaDoc inactivo,Inactive JavaDoc style pre-processor comment QsciLexerCPPJExpresión regular JavaScript inactiva&Inactive JavaScript regular expression QsciLexerCPPXCadena Pike con hash entrecomillado inactiva Inactive Pike hash-quoted string QsciLexerCPP^Cadena Vala con triple comilla textual inactiva+Inactive Vala triple-quoted verbatim string QsciLexerCPP(Por defecto inactivoInactive default QsciLexerCPPBCadena con doble comilla inactivaInactive double-quoted string QsciLexerCPP8Secuencia de escape inactivaInactive escape sequence QsciLexerCPPHClases globales y typedefs inactivos$Inactive global classes and typedefs QsciLexerCPP,Identificador inactivoInactive identifier QsciLexerCPP,Palabra clave inactivaInactive keyword QsciLexerCPPNúmero inactivoInactive number QsciLexerCPP"Operador inactivoInactive operator QsciLexerCPPLComentario C de preprocesador inactivo Inactive pre-processor C comment QsciLexerCPP@Bloque de preprocesador inactivoInactive pre-processor block QsciLexerCPPlIdentificadores y palabras clave secundarios inactivos+Inactive secondary keywords and identifiers QsciLexerCPPDCadena con comilla simple inactivaInactive single-quoted string QsciLexerCPP4Marcador de tarea inactivoInactive task marker QsciLexerCPP4Cadena sin cerrar inactivaInactive unclosed string QsciLexerCPPPLiteral inactivo definido por el usuarioInactive user-defined literal QsciLexerCPP0Palabra clave de JavadocJavaDoc keyword QsciLexerCPPBError en palabra clave de JavadocJavaDoc keyword error QsciLexerCPP<Comentario C de estilo JavaDocJavaDoc style C comment QsciLexerCPP@Comentario C++ de estilo JavaDocJavaDoc style C++ comment QsciLexerCPPTComentario de preprocesador estilo JavaDoc#JavaDoc style pre-processor comment QsciLexerCPP8Expresión regular JavaScriptJavaScript regular expression QsciLexerCPPPalabra claveKeyword QsciLexerCPP NúmeroNumber QsciLexerCPPOperadorOperator QsciLexerCPPFCadena Pike con hash entrecomilladoPike hash-quoted string QsciLexerCPP:Comentario C de preprocesadorPre-processor C comment QsciLexerCPP.Bloque de preprocesadorPre-processor block QsciLexerCPPXIdentificadores y palabras clave secundarios"Secondary keywords and identifiers QsciLexerCPP6Cadena con comillas simplesSingle-quoted string QsciLexerCPP"Marcador de tarea Task marker QsciLexerCPP"Cadena sin cerrarUnclosed string QsciLexerCPP>Literal definido por el usuarioUser-defined literal QsciLexerCPPLCadena Vala con triple comilla textual"Vala triple-quoted verbatim string QsciLexerCPPRegla-@@-rule QsciLexerCSSAtributo Attribute QsciLexerCSSPropiedad CSS1 CSS1 property QsciLexerCSSPropiedad CSS2 CSS2 property QsciLexerCSSPropiedad CSS3 CSS3 property QsciLexerCSS"Selector de claseClass selector QsciLexerCSSPor defectoDefault QsciLexerCSS4Cadena con comillas doblesDouble-quoted string QsciLexerCSS.Propiedad CSS extendidaExtended CSS property QsciLexerCSS*Pseudoclase extendidaExtended pseudo-class QsciLexerCSS0Pseudoelemento extendidoExtended pseudo-element QsciLexerCSSSelector de ID ID selector QsciLexerCSSImportante Important QsciLexerCSS"Regla de '@media' Media rule QsciLexerCSSOperadorOperator QsciLexerCSSPseudoclase Pseudo-class QsciLexerCSSPseudoelementoPseudo-element QsciLexerCSS6Cadena con comillas simplesSingle-quoted string QsciLexerCSSEtiquetaTag QsciLexerCSS*Propiedad desconocidaUnknown property QsciLexerCSS.Pseudoclase desconocidaUnknown pseudo-class QsciLexerCSS ValorValue QsciLexerCSSVariableVariable QsciLexerCSSCadena textualVerbatim stringQsciLexerCSharp(Comentario de bloque Block commentQsciLexerCoffeeScript6Expresión regular de bloqueBlock regular expressionQsciLexerCoffeeScriptRComentario de expresión regular de bloque Block regular expression commentQsciLexerCoffeeScript"Cadena C# textualC# verbatim stringQsciLexerCoffeeScript0Comentario de estilo C++C++-style commentQsciLexerCoffeeScript,Comentario de estilo CC-style commentQsciLexerCoffeeScriptPor defectoDefaultQsciLexerCoffeeScript4Cadena con comillas doblesDouble-quoted stringQsciLexerCoffeeScriptClases globalesGlobal classesQsciLexerCoffeeScriptIDL UUIDIDL UUIDQsciLexerCoffeeScriptIdentificador IdentifierQsciLexerCoffeeScript,Propiedad de instanciaInstance propertyQsciLexerCoffeeScript@Comentario de estilo JavaDoc C++JavaDoc C++-style commentQsciLexerCoffeeScript<Comentario de estilo JavaDoc CJavaDoc C-style commentQsciLexerCoffeeScript0Palabra clave de JavaDocJavaDoc keywordQsciLexerCoffeeScriptBError en palabra clave de JavaDocJavaDoc keyword errorQsciLexerCoffeeScriptPalabra claveKeywordQsciLexerCoffeeScript NúmeroNumberQsciLexerCoffeeScriptOperadorOperatorQsciLexerCoffeeScript.Bloque de preprocesadorPre-processor blockQsciLexerCoffeeScript"Expresión regularRegular expressionQsciLexerCoffeeScriptXIdentificadores y palabras clave secundarios"Secondary keywords and identifiersQsciLexerCoffeeScript2Cadena con comilla simpleSingle-quoted stringQsciLexerCoffeeScript"Cadena sin cerrarUnclosed stringQsciLexerCoffeeScript>Cadena con comillas hacia atrásBackquoted string QsciLexerD(Comentario de bloque Block comment QsciLexerDCarácter Character QsciLexerD$Palabra clave DDoc DDoc keyword QsciLexerD6Error en palabra clave DDOCDDoc keyword error QsciLexerD@Comentario de bloque estilo DDocDDoc style block comment QsciLexerD>Comentario de línea estilo DDocDDoc style line comment QsciLexerDPor defectoDefault QsciLexerD<Palabra clave de documentaciónDocumentation keyword QsciLexerDIdentificador Identifier QsciLexerDPalabra claveKeyword QsciLexerD&Comentario de línea Line comment QsciLexerD$Comentario anidadoNesting comment QsciLexerD NúmeroNumber QsciLexerDOperadorOperator QsciLexerDCadena en bruto Raw string QsciLexerD0Palabra clave secundariaSecondary keyword QsciLexerD(Cadena de caracteresString QsciLexerD$Definición de tipoType definition QsciLexerD"Cadena sin cerrarUnclosed string QsciLexerD2Definido por el usuario 1User defined 1 QsciLexerD2Definido por el usuario 2User defined 2 QsciLexerD2Definido por el usuario 3User defined 3 QsciLexerDLínea añadida Added line QsciLexerDiff Línea modificada Changed line QsciLexerDiffComandoCommand QsciLexerDiffComentarioComment QsciLexerDiffPor defectoDefault QsciLexerDiffEncabezadoHeader QsciLexerDiffPosiciónPosition QsciLexerDiffLínea eliminada Removed line QsciLexerDiff(Segmento mal formadoBadly formed segmentQsciLexerEDIFACT&Separador compuestoComposite separatorQsciLexerEDIFACTPor defectoDefaultQsciLexerEDIFACT*Separador de elementoElement separatorQsciLexerEDIFACT(Separador de releaseRelease separatorQsciLexerEDIFACT"Final de Segmento Segment endQsciLexerEDIFACT$Inicio de Segmento Segment startQsciLexerEDIFACT<Encabezamiento de segmento UNAUNA segment headerQsciLexerEDIFACT<Encabezamiento de segmento UNHUNH segment headerQsciLexerEDIFACTComentarioCommentQsciLexerFortran77Continuación ContinuationQsciLexerFortran77Por defectoDefaultQsciLexerFortran77"Operador punteadoDotted operatorQsciLexerFortran774Cadena con comillas doblesDouble-quoted stringQsciLexerFortran77"Función extendidaExtended functionQsciLexerFortran77Identificador IdentifierQsciLexerFortran77$Función intrínsecaIntrinsic functionQsciLexerFortran77Palabra claveKeywordQsciLexerFortran77EtiquetaLabelQsciLexerFortran77 NúmeroNumberQsciLexerFortran77OperadorOperatorQsciLexerFortran77.Bloque de preprocesadorPre-processor blockQsciLexerFortran776Cadena con comillas simplesSingle-quoted stringQsciLexerFortran77"Cadena sin cerrarUnclosed stringQsciLexerFortran778Comentario de ASP JavaScriptASP JavaScript comment QsciLexerHTML4ASP JavaScript por defectoASP JavaScript default QsciLexerHTMLRCadena ASP JavaScript con comillas dobles#ASP JavaScript double-quoted string QsciLexerHTML8Palabra clave ASP JavaScriptASP JavaScript keyword QsciLexerHTMLJComentario de línea de ASP JavaScriptASP JavaScript line comment QsciLexerHTML*Número ASP JavaScriptASP JavaScript number QsciLexerHTML@Expresión regular ASP JavaScript!ASP JavaScript regular expression QsciLexerHTMLTCadena ASP JavaScript con comillas simples#ASP JavaScript single-quoted string QsciLexerHTML,Símbolo ASP JavaScriptASP JavaScript symbol QsciLexerHTML@Cadena ASP JavaScript sin cerrarASP JavaScript unclosed string QsciLexerHTML,Palabra ASP JavaScriptASP JavaScript word QsciLexerHTML4Nombre de clase ASP PythonASP Python class name QsciLexerHTML*Comentario ASP PythonASP Python comment QsciLexerHTML,ASP Python por defectoASP Python default QsciLexerHTMLJCadena ASP Python con comillas doblesASP Python double-quoted string QsciLexerHTMLJNombre de método o función ASP Python"ASP Python function or method name QsciLexerHTML0Identificador ASP PythonASP Python identifier QsciLexerHTML6Palabra clave de ASP PythonASP Python keyword QsciLexerHTML"Número ASP PythonASP Python number QsciLexerHTML&Operador ASP PythonASP Python operator QsciLexerHTMLLCadena ASP Python con comillas simplesASP Python single-quoted string QsciLexerHTMLTCadena ASP Python con triple comilla doble&ASP Python triple double-quoted string QsciLexerHTMLVCadena ASP Python con triple comilla simple&ASP Python triple single-quoted string QsciLexerHTML4Comentario de ASP VBScriptASP VBScript comment QsciLexerHTML0ASP VBScript por defectoASP VBScript default QsciLexerHTML4Identificador ASP VBScriptASP VBScript identifier QsciLexerHTML4Palabra clave ASP VBScriptASP VBScript keyword QsciLexerHTML&Número ASP VBScriptASP VBScript number QsciLexerHTMLBCadena de caracteres ASP VBScriptASP VBScript string QsciLexerHTML<Cadena ASP VBScript sin cerrarASP VBScript unclosed string QsciLexerHTML*Comentario ASP X-CodeASP X-Code comment QsciLexerHTMLAtributo Attribute QsciLexerHTML CDATACDATA QsciLexerHTML*Final de una etiqueta End of a tag QsciLexerHTML.Fin de un fragmento XMLEnd of an XML fragment QsciLexerHTMLEntidadEntity QsciLexerHTMLbComentario de primer parametro de un comando SGML*First parameter comment of an SGML command QsciLexerHTMLFPrimer parametro de un comando SGML"First parameter of an SGML command QsciLexerHTMLComentario HTML HTML comment QsciLexerHTML HTML por defecto HTML default QsciLexerHTML>Cadena HTML con comillas doblesHTML double-quoted string QsciLexerHTMLNúmero HTML HTML number QsciLexerHTML@Cadena HTML con comillas simplesHTML single-quoted string QsciLexerHTMLVComentario ASP JavaScript de estilo JavaDoc$JavaDoc style ASP JavaScript comment QsciLexerHTMLNComentario JavaScript de estilo JavaDoc JavaDoc style JavaScript comment QsciLexerHTML*Comentario JavaScriptJavaScript comment QsciLexerHTML,JavaScript por defectoJavaScript default QsciLexerHTMLJCadena JavaScript con comillas doblesJavaScript double-quoted string QsciLexerHTML0Palabra clave JavaScriptJavaScript keyword QsciLexerHTMLBComentario de línea de JavaScriptJavaScript line comment QsciLexerHTML"Número JavaScriptJavaScript number QsciLexerHTML8Expresión regular JavaScriptJavaScript regular expression QsciLexerHTMLLCadena JavaScript con comillas simplesJavaScript single-quoted string QsciLexerHTML$Símbolo JavaScriptJavaScript symbol QsciLexerHTML8Cadena JavaScript sin cerrarJavaScript unclosed string QsciLexerHTML$Palabra JavaScriptJavaScript word QsciLexerHTML4Otro texto en una etiquetaOther text in a tag QsciLexerHTMLComentario PHP PHP comment QsciLexerHTMLPHP por defecto PHP default QsciLexerHTML<Cadena PHP con comillas doblesPHP double-quoted string QsciLexerHTML@Variable PHP con comillas doblesPHP double-quoted variable QsciLexerHTML"Palabra clave PHP PHP keyword QsciLexerHTML.Comentario de línea PHPPHP line comment QsciLexerHTMLNúmero PHP PHP number QsciLexerHTMLOperador PHP PHP operator QsciLexerHTML>Cadena PHP con comillas simplesPHP single-quoted string QsciLexerHTMLVariable PHP PHP variable QsciLexerHTML,Nombre de clase PythonPython class name QsciLexerHTML"Comentario PythonPython comment QsciLexerHTML$Python por defectoPython default QsciLexerHTMLBCadena Python con comillas doblesPython double-quoted string QsciLexerHTMLBNombre de método o función PythonPython function or method name QsciLexerHTML(Identificador PythonPython identifier QsciLexerHTML.Palabra clave de PythonPython keyword QsciLexerHTMLNúmero Python Python number QsciLexerHTMLOperador PythonPython operator QsciLexerHTMLDCadena Python con comillas simplesPython single-quoted string QsciLexerHTMLLCadena Python con triple comilla doble"Python triple double-quoted string QsciLexerHTMLNCadena Python con triple comilla simple"Python triple single-quoted string QsciLexerHTML.Bloque SGML por defectoSGML block default QsciLexerHTMLComando SGML SGML command QsciLexerHTMLComentario SGML SGML comment QsciLexerHTML SGML por defecto SGML default QsciLexerHTML>Cadena SGML con comillas doblesSGML double-quoted string QsciLexerHTMLError SGML SGML error QsciLexerHTML@Cadena SGML con comillas simplesSGML single-quoted string QsciLexerHTML*Entidad SGML especialSGML special entity QsciLexerHTML$Etiqueta de script Script tag QsciLexerHTMLBInicio de un fragmento JavaScriptStart of a JavaScript fragment QsciLexerHTML4Inicio de un fragmento PHPStart of a PHP fragment QsciLexerHTML:Inicio de un fragmento PythonStart of a Python fragment QsciLexerHTML>Inicio de un fragmento VBScriptStart of a VBScript fragment QsciLexerHTMLPInicio de un fragmento de ASP JavaScript#Start of an ASP JavaScript fragment QsciLexerHTMLBInicio de un fragmento ASP PythonStart of an ASP Python fragment QsciLexerHTMLLInicio de un fragmento de ASP VBScript!Start of an ASP VBScript fragment QsciLexerHTML4Inicio de un fragmento ASPStart of an ASP fragment QsciLexerHTML@Inicio de un fragmento ASP con @Start of an ASP fragment with @ QsciLexerHTML4Inicio de un fragmento XMLStart of an XML fragment QsciLexerHTMLEtiquetaTag QsciLexerHTML(Atributo desconocidoUnknown attribute QsciLexerHTML(Etiqueta desconocida Unknown tag QsciLexerHTML.Valor HTML sin comillasUnquoted HTML value QsciLexerHTML&Comentario VBScriptVBScript comment QsciLexerHTML(VBScript por defectoVBScript default QsciLexerHTML,Identificador VBScriptVBScript identifier QsciLexerHTML,Palabra clave VBScriptVBScript keyword QsciLexerHTMLNúmero VBScriptVBScript number QsciLexerHTML:Cadena de caracteres VBScriptVBScript string QsciLexerHTML4Cadena VBScript sin cerrarVBScript unclosed string QsciLexerHTMLUUIDUUID QsciLexerIDL(Comentario de bloque Block comment QsciLexerJSONPor defectoDefault QsciLexerJSON&Secuencia de escapeEscape sequence QsciLexerJSONIRIIRI QsciLexerJSON$Palabra clave JSON JSON keyword QsciLexerJSON&JSON-LD compact IRIJSON-LD compact IRI QsciLexerJSON*Palabra clave JSON-LDJSON-LD keyword QsciLexerJSON&Comentario de línea Line comment QsciLexerJSON NúmeroNumber QsciLexerJSONOperadorOperator QsciLexerJSON&Error de intérprete Parsing error QsciLexerJSONPropiedadProperty QsciLexerJSON CadenaString QsciLexerJSON"Cadena sin cerrarUnclosed string QsciLexerJSON"Expresión regularRegular expressionQsciLexerJavaScript"Funciones basicasBasic functions QsciLexerLuaCarácter Character QsciLexerLuaComentarioComment QsciLexerLuaNCo-rutinas, e/s y funciones del sistema%Coroutines, i/o and system facilities QsciLexerLuaPor defectoDefault QsciLexerLuaIdentificador Identifier QsciLexerLuaPalabra claveKeyword QsciLexerLuaEtiquetaLabel QsciLexerLua&Comentario de línea Line comment QsciLexerLuaCadena literalLiteral string QsciLexerLua NúmeroNumber QsciLexerLuaOperadorOperator QsciLexerLuaPreprocesador Preprocessor QsciLexerLua(Cadena de caracteresString QsciLexerLuaNFuncines de cadena, tabla y matemáticas!String, table and maths functions QsciLexerLua"Cadena sin cerrarUnclosed string QsciLexerLua2Definido por el usuario 1User defined 1 QsciLexerLua2Definido por el usuario 2User defined 2 QsciLexerLua2Definido por el usuario 3User defined 3 QsciLexerLua2Definido por el usuario 4User defined 4 QsciLexerLuaComentarioCommentQsciLexerMakefilePor defectoDefaultQsciLexerMakefile ErrorErrorQsciLexerMakefileOperadorOperatorQsciLexerMakefilePreprocesador PreprocessorQsciLexerMakefileObjetivoTargetQsciLexerMakefileVariableVariableQsciLexerMakefileBloque de cita Block quoteQsciLexerMarkdownBCódigo entre comillas hacia atrásCode between backticksQsciLexerMarkdownPCódigo entre comillas hacia atrás doblesCode between double backticksQsciLexerMarkdown Bloque de código Code blockQsciLexerMarkdownPor defectoDefaultQsciLexerMarkdownBÉnfasis usando asterisco sencilloEmphasis using single asterisksQsciLexerMarkdownDÉnfasis usando guión bajo sencillo!Emphasis using single underscoresQsciLexerMarkdown Regla horizontalHorizontal ruleQsciLexerMarkdown*Encabezado de nivel 1Level 1 headerQsciLexerMarkdown*Encabezado de nivel 2Level 2 headerQsciLexerMarkdown*Encabezado de nivel 3Level 3 headerQsciLexerMarkdown*Encabezado de nivel 4Level 4 headerQsciLexerMarkdown*Encabezado de nivel 5Level 5 headerQsciLexerMarkdown*Encabezado de nivel 6Level 6 headerQsciLexerMarkdown EnlaceLinkQsciLexerMarkdown4Elemento de lista ordenadaOrdered list itemQsciLexerMarkdownPre-charPre-charQsciLexerMarkdownEspecialSpecialQsciLexerMarkdown Tachar Strike outQsciLexerMarkdownJÉnfasis fuerte usando doble asterisco&Strong emphasis using double asterisksQsciLexerMarkdownLÉnfasis fuerte usando doble guión bajo(Strong emphasis using double underscoresQsciLexerMarkdown:Elemento de lista sin ordenarUnordered list itemQsciLexerMarkdownComandoCommandQsciLexerMatlabComentarioCommentQsciLexerMatlabPor defectoDefaultQsciLexerMatlab4Cadena con comillas doblesDouble-quoted stringQsciLexerMatlabIdentificador IdentifierQsciLexerMatlabPalabra claveKeywordQsciLexerMatlab NúmeroNumberQsciLexerMatlabOperadorOperatorQsciLexerMatlab6Cadena con comillas simplesSingle-quoted stringQsciLexerMatlabComentarioComment QsciLexerPOPor defectoDefault QsciLexerPOSeñaladoresFlags QsciLexerPO Señalador difuso Fuzzy flag QsciLexerPO&Contexto de mensajeMessage context QsciLexerPO8Texto de contexto de mensajeMessage context text QsciLexerPOXFin de línea de texto de contexto de mensaje Message context text end-of-line QsciLexerPO0Identificador de mensajeMessage identifier QsciLexerPO<Texto identificador de mensajeMessage identifier text QsciLexerPO\Fin de línea de texto identificador de mensaje#Message identifier text end-of-line QsciLexerPO"Cadena de mensajeMessage string QsciLexerPO4Texto de cadena de mensajeMessage string text QsciLexerPOTFin de línea de texto de cadena de mensajeMessage string text end-of-line QsciLexerPO2Comentario de programadorProgrammer comment QsciLexerPOReferencia Reference QsciLexerPOMala directiva Bad directive QsciLexerPOVComentarioComment QsciLexerPOV&Línea de comentario Comment line QsciLexerPOVPor defectoDefault QsciLexerPOVDirectiva Directive QsciLexerPOVIdentificador Identifier QsciLexerPOV NúmeroNumber QsciLexerPOV2Objetos, CSG y aparienciaObjects, CSG and appearance QsciLexerPOVOperadorOperator QsciLexerPOV,Funciones predefinidasPredefined functions QsciLexerPOV8Identificadores predefinidosPredefined identifiers QsciLexerPOV(Cadena de caracteresString QsciLexerPOV@Tipos, modificadores y elementosTypes, modifiers and items QsciLexerPOV"Cadena sin cerrarUnclosed string QsciLexerPOV2Definido por el usuario 1User defined 1 QsciLexerPOV2Definido por el usuario 2User defined 2 QsciLexerPOV2Definido por el usuario 3User defined 3 QsciLexerPOV@Comentario de estilo '(* ... *)''(* ... *)' style commentQsciLexerPascal\Bloque de preprocesador de estilo '(*$ ... *)'&'(*$ ... *)' style pre-processor blockQsciLexerPascal>Comentario de estilo '{ ... }' '{ ... }' style commentQsciLexerPascalXBloque de preprocesador de estilo '{$ ... }'$'{$ ... }' style pre-processor blockQsciLexerPascalCarácter CharacterQsciLexerPascalPor defectoDefaultQsciLexerPascal$Número hexadecimalHexadecimal numberQsciLexerPascalIdentificador IdentifierQsciLexerPascalasm inline  Inline asmQsciLexerPascalPalabra claveKeywordQsciLexerPascal&Comentario de línea Line commentQsciLexerPascal NúmeroNumberQsciLexerPascalOperadorOperatorQsciLexerPascal6Cadena con comillas simplesSingle-quoted stringQsciLexerPascal"Cadena sin cerrarUnclosed stringQsciLexerPascal ArrayArray QsciLexerPerlnDocumento integrado (here document) con comilla inversaBacktick here document QsciLexerPerlxHere document con comilla hacia atrás (variable interpolada).Backtick here document (interpolated variable) QsciLexerPerlComilla inversa Backticks QsciLexerPerlTComilla hacia atrás (variable interpolada)!Backticks (interpolated variable) QsciLexerPerlComentarioComment QsciLexerPerl Sección de datos Data section QsciLexerPerlPor defectoDefault QsciLexerPerljDocumento integrado (here document) con comilla dobleDouble-quoted here document QsciLexerPerllHere document con comilla doble (variable interpolada)3Double-quoted here document (interpolated variable) QsciLexerPerl4Cadena con comillas doblesDouble-quoted string QsciLexerPerl^Cadena con doble comilla (variable interpolada),Double-quoted string (interpolated variable) QsciLexerPerl ErrorError QsciLexerPerl"Cuerpo de formato Format body QsciLexerPerl0Identificador de formatoFormat identifier QsciLexerPerlHashHash QsciLexerPerldDelimitador de documento integrado (here document)Here document delimiter QsciLexerPerlIdentificador Identifier QsciLexerPerlPalabra claveKeyword QsciLexerPerl NúmeroNumber QsciLexerPerlOperadorOperator QsciLexerPerlPODPOD QsciLexerPerlPOD textual POD verbatim QsciLexerPerl.Cadena con comillas (q)Quoted string (q) QsciLexerPerl0Cadena con comillas (qq)Quoted string (qq) QsciLexerPerl`Cadena entrecomillada (qq, variable interpolada))Quoted string (qq, interpolated variable) QsciLexerPerl0Cadena con comillas (qr)Quoted string (qr) QsciLexerPerl`Cadena entrecomillada (qr, variable interpolada))Quoted string (qr, interpolated variable) QsciLexerPerl0Cadena con comillas (qw)Quoted string (qw) QsciLexerPerl0Cadena con comillas (qx)Quoted string (qx) QsciLexerPerl`Cadena entrecomillada (qx, variable interpolada))Quoted string (qx, interpolated variable) QsciLexerPerl"Expresión regularRegular expression QsciLexerPerlPExpresión regular (variable interpolada)*Regular expression (interpolated variable) QsciLexerPerlEscalarScalar QsciLexerPerllDocumento integrado (here document) con comilla simpleSingle-quoted here document QsciLexerPerl6Cadena con comillas simplesSingle-quoted string QsciLexerPerl,Prototipo de subrutinaSubroutine prototype QsciLexerPerlSustitución Substitution QsciLexerPerlFSubstitución (variable interpolada)$Substitution (interpolated variable) QsciLexerPerl"Tabla de símbolos Symbol table QsciLexerPerlTraducción Translation QsciLexerPerl&Paréntesis de arrayArray parenthesisQsciLexerPostScript.Carácter de cadena malaBad string characterQsciLexerPostScriptCadena Base85 Base85 stringQsciLexerPostScriptComentarioCommentQsciLexerPostScriptComentario DSC DSC commentQsciLexerPostScript.Valor de comentario DSCDSC comment valueQsciLexerPostScriptPor defectoDefaultQsciLexerPostScript2Paréntesis de diccionarioDictionary parenthesisQsciLexerPostScript$Cadena hexadecimalHexadecimal stringQsciLexerPostScript>Literal de evaluación inmediataImmediately evaluated literalQsciLexerPostScriptPalabra claveKeywordQsciLexerPostScriptLiteralLiteralQsciLexerPostScript NombreNameQsciLexerPostScript NúmeroNumberQsciLexerPostScript6Paréntesis de procedimientoProcedure parenthesisQsciLexerPostScript TextoTextQsciLexerPostScriptAsignación AssignmentQsciLexerPropertiesComentarioCommentQsciLexerPropertiesPor defectoDefaultQsciLexerProperties"Valor por defecto Default valueQsciLexerProperties ClaveKeyQsciLexerPropertiesSecciónSectionQsciLexerPropertiesNombre de clase Class nameQsciLexerPythonComentarioCommentQsciLexerPython(Bloque de comentario Comment blockQsciLexerPythonDecorador DecoratorQsciLexerPythonPor defectoDefaultQsciLexerPython4Cadena con comillas doblesDouble-quoted stringQsciLexerPython4Nombre de método o funciónFunction or method nameQsciLexerPython.Identificador resaltadoHighlighted identifierQsciLexerPythonIdentificador IdentifierQsciLexerPythonPalabra claveKeywordQsciLexerPython NúmeroNumberQsciLexerPythonOperadorOperatorQsciLexerPython6Cadena con comillas simplesSingle-quoted stringQsciLexerPython>Cadena con triple comilla dobleTriple double-quoted stringQsciLexerPython@Cadena con triple comilla simpleTriple single-quoted stringQsciLexerPython"Cadena sin cerrarUnclosed stringQsciLexerPythonCadena %Q %Q string QsciLexerRubyCadena %q %q string QsciLexerRubyCadena %r %r string QsciLexerRubyCadena %w %w string QsciLexerRubyCadena %x %x string QsciLexerRubyComilla inversa Backticks QsciLexerRubyNombre de clase Class name QsciLexerRuby"Variable de claseClass variable QsciLexerRubyComentarioComment QsciLexerRuby Sección de datos Data section QsciLexerRubyPor defectoDefault QsciLexerRuby.Palabra clave degradadaDemoted keyword QsciLexerRuby4Cadena con comillas doblesDouble-quoted string QsciLexerRuby ErrorError QsciLexerRuby4Nombre de método o funciónFunction or method name QsciLexerRuby GlobalGlobal QsciLexerRubyFDocumento integrado (here document) Here document QsciLexerRubydDelimitador de documento integrado (here document)Here document delimiter QsciLexerRubyIdentificador Identifier QsciLexerRuby*Variable de instanciaInstance variable QsciLexerRubyPalabra claveKeyword QsciLexerRuby Nombre de módulo Module name QsciLexerRuby NúmeroNumber QsciLexerRubyOperadorOperator QsciLexerRubyPODPOD QsciLexerRuby"Expresión regularRegular expression QsciLexerRuby6Cadena con comillas simplesSingle-quoted string QsciLexerRubySímboloSymbol QsciLexerRuby stderrstderr QsciLexerRuby stdinstdin QsciLexerRuby stdoutstdout QsciLexerRuby*# línea de comentario# comment line QsciLexerSQLComentarioComment QsciLexerSQL&Línea de comentario Comment line QsciLexerSQLPor defectoDefault QsciLexerSQL4Cadena con comillas doblesDouble-quoted string QsciLexerSQLIdentificador Identifier QsciLexerSQL0Palabra clave de JavadocJavaDoc keyword QsciLexerSQLBError en palabra clave de JavadocJavaDoc keyword error QsciLexerSQL8Comentario de estilo JavaDocJavaDoc style comment QsciLexerSQLPalabra claveKeyword QsciLexerSQL NúmeroNumber QsciLexerSQLOperadorOperator QsciLexerSQL8Identificador entrecomilladoQuoted identifier QsciLexerSQL.Operador entrecomilladoQuoted operator QsciLexerSQL&Comentario SQL*PlusSQL*Plus comment QsciLexerSQL,Palabra clave SQL*PlusSQL*Plus keyword QsciLexerSQLPrompt SQL*PlusSQL*Plus prompt QsciLexerSQL6Cadena con comillas simplesSingle-quoted string QsciLexerSQL2Definido por el usuario 1User defined 1 QsciLexerSQL2Definido por el usuario 2User defined 2 QsciLexerSQL2Definido por el usuario 3User defined 3 QsciLexerSQL2Definido por el usuario 4User defined 4 QsciLexerSQLComandoCommandQsciLexerSpiceComentarioCommentQsciLexerSpicePor defectoDefaultQsciLexerSpiceDelimitador DelimiterQsciLexerSpiceFunciónFunctionQsciLexerSpiceIdentificador IdentifierQsciLexerSpice NúmeroNumberQsciLexerSpiceParámetro ParameterQsciLexerSpice ValorValueQsciLexerSpice0Sustitución de corchetesBrace substitution QsciLexerTCLComentarioComment QsciLexerTCL(Bloque de comentario Comment block QsciLexerTCL$Caja de comentario Comment box QsciLexerTCL&Línea de comentario Comment line QsciLexerTCLPor defectoDefault QsciLexerTCL,Expandir palabra claveExpand keyword QsciLexerTCLIdentificador Identifier QsciLexerTCLModificadorModifier QsciLexerTCL NúmeroNumber QsciLexerTCLOperadorOperator QsciLexerTCL8Palabra clave entrecomilladaQuoted keyword QsciLexerTCL*Cadena entrecomillada Quoted string QsciLexerTCLSustitución Substitution QsciLexerTCL"Palabra clave TCL TCL keyword QsciLexerTCLComando Tk Tk command QsciLexerTCL Palabra clave Tk Tk keyword QsciLexerTCL2Definido por el usuario 1User defined 1 QsciLexerTCL2Definido por el usuario 2User defined 2 QsciLexerTCL2Definido por el usuario 3User defined 3 QsciLexerTCL2Definido por el usuario 4User defined 4 QsciLexerTCL$Palabra clave iTCL iTCL keyword QsciLexerTCLComandoCommand QsciLexerTeXPor defectoDefault QsciLexerTeX GrupoGroup QsciLexerTeXEspecialSpecial QsciLexerTeXSímboloSymbol QsciLexerTeX TextoText QsciLexerTeXAtributo Attribute QsciLexerVHDLComentarioComment QsciLexerVHDL(Bloque de comentario Comment block QsciLexerVHDL&Línea de comentario Comment line QsciLexerVHDLPor defectoDefault QsciLexerVHDLIdentificador Identifier QsciLexerVHDLPalabra claveKeyword QsciLexerVHDL NúmeroNumber QsciLexerVHDLOperadorOperator QsciLexerVHDL Función estándarStandard function QsciLexerVHDL"Operador estándarStandard operator QsciLexerVHDL Paquete estándarStandard package QsciLexerVHDLTipo estándar Standard type QsciLexerVHDL(Cadena de caracteresString QsciLexerVHDL"Cadena sin cerrarUnclosed string QsciLexerVHDL.Definido por el usuario User defined QsciLexerVHDLComentario Bang Bang commentQsciLexerVerilogComentarioCommentQsciLexerVerilogPor defectoDefaultQsciLexerVerilogIdentificador IdentifierQsciLexerVerilog0Comentario Bang inactivoInactive bang commentQsciLexerVerilog(Inactivo por defectoInactive defaultQsciLexerVerilog,Identificador inactivoInactive identifierQsciLexerVerilogNDeclaración de puerto de input inactivoInactive input port declarationQsciLexerVerilog\Declaración de puerto de input/output inactivo&Inactive input/output port declarationQsciLexerVerilogHComentario de palabra clave inactivaInactive keyword commentQsciLexerVerilog8Línea de comentario inactivaInactive line commentQsciLexerVerilogNúmero inactivoInactive numberQsciLexerVerilog"Operador inactivoInactive operatorQsciLexerVerilogPDeclaración de puerto de output inactivo Inactive output port declarationQsciLexerVerilog6Conexión inactiva de puertoInactive port connectionQsciLexerVeriloghPalabras clave primarias e identificadores inactivos)Inactive primary keywords and identifiersQsciLexerVeriloglIdentificadores y palabras clave secundarios inactivos+Inactive secondary keywords and identifiersQsciLexerVerilogCadena inactivaInactive stringQsciLexerVerilog2Tarea de sistema inactivaInactive system taskQsciLexerVerilog4Cadena sin cerrar inactivaInactive unclosed stringQsciLexerVerilogvTareas definidas por el usuario e identificadores inactivos+Inactive user defined tasks and identifiersQsciLexerVerilog<Declaración de puerto de inputInput port declarationQsciLexerVerilog\Declaración de puerto de input/output inactivoInput/output port declarationQsciLexerVerilog6Comentario de palabra claveKeyword commentQsciLexerVerilog&Comentario de línea Line commentQsciLexerVerilogÿÿÿÿNumberQsciLexerVerilogOperadorOperatorQsciLexerVerilog>Declaración de puerto de outputOutput port declarationQsciLexerVerilog$Conexión de puertoPort connectionQsciLexerVerilog.Bloque de preprocesadorPreprocessor blockQsciLexerVerilogTIdentificadores y palabras clave primarios Primary keywords and identifiersQsciLexerVerilogXPalabras clave e identificadores secundarios"Secondary keywords and identifiersQsciLexerVerilog CadenaStringQsciLexerVerilog Tarea de sistema System taskQsciLexerVerilog"Cadena sin cerrarUnclosed stringQsciLexerVerilogbTareas definidas por el usuario e identificadores"User defined tasks and identifiersQsciLexerVerilogComentarioComment QsciLexerYAMLPor defectoDefault QsciLexerYAML0Delimitador de documentoDocument delimiter QsciLexerYAMLIdentificador Identifier QsciLexerYAMLPalabra claveKeyword QsciLexerYAML NúmeroNumber QsciLexerYAMLOperadorOperator QsciLexerYAMLReferencia Reference QsciLexerYAML:Marcador de error de sintaxisSyntax error marker QsciLexerYAML6Marcador de bloque de textoText block marker QsciLexerYAML&Copiar&Copy QsciScintilla &Pegar&Paste QsciScintilla&Rehacer&Redo QsciScintilla&Deshacer&Undo QsciScintillaCor&tarCu&t QsciScintilla BorrarDelete QsciScintilla Seleccionar todo Select All QsciScintillaˆsqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_es.ts000066400000000000000000004537671463772530400272620ustar00rootroot00000000000000 QsciCommand Move down one line Desplazar una línea hacia abajo Extend selection down one line Extender la selección una línea hacia abajo Scroll view down one line Desplazar la vista una línea hacia abajo Extend rectangular selection down one line Extender la selección rectangular una línea hacia abajo Move up one line Desplazar una línea hacia arriba Extend selection up one line Extender la selección una línea hacia arriba Scroll view up one line Desplazar la vista una línea hacia arriba Extend rectangular selection up one line Extender la selección rectangular una línea hacia arriba Move up one paragraph Desplazar un párrafo hacia arriba Extend selection up one paragraph Extender la selección un párrafo hacia arriba Move down one paragraph Desplazar un párrafo hacia abajo Scroll to start of document Desplazar al principio del documento Scroll to end of document Desplazar al final del documento Scroll vertically to centre current line Desplazar verticalmente al centro de la línea actual Extend selection down one paragraph Extender la selección un párrafo hacia abajo Move left one character Mover un carácter hacia la izquierda Extend selection left one character Extender la selección un carácter hacia la izquierda Move left one word Mover una palabra hacia la izquierda Extend selection left one word Extender la selección una palabra a la izquierda Extend rectangular selection left one character Extender la selección rectangular un carácter hacia la izquierda Move right one character Mover un carácter hacia la derecha Extend selection right one character Extender la selección un carácter hacia la derecha Move right one word Mover una palabra hacia la derecha Extend selection right one word Extender la selección una palabra a la derecha Extend rectangular selection right one character Extender la selección rectangular un carácter hacia la derecha Move to end of previous word Mover al final de palabra anterior Extend selection to end of previous word Extender selección al final de la palabra anterior Move to end of next word Mover al final de la palabra siguiente Extend selection to end of next word Extender la selección hasta el final de la palabra siguiente Move left one word part Mover parte de una palabra hacia la izquierda Extend selection left one word part Extender la selección parte de una palabra a la izquierda Move right one word part Mover parte de una palabra hacia la derecha Extend selection right one word part Extender la selección parte de una palabra a la derecha Move up one page Mover hacia arriba una página Extend selection up one page Extender la selección hacia arriba una página Extend rectangular selection up one page Extender la selección rectangular hacia arriba una página Move down one page Mover hacia abajo una página Extend selection down one page Extender la selección hacia abajo una página Extend rectangular selection down one page Extender la selección rectangular una página hacia abajo Delete current character Borrar el carácter actual Cut selection Cortar selección Delete word to right Borrar palabra hacia la derecha Move to start of document line Mover al principio de la línea del documento Extend selection to start of document line Extender selección al principio de la línea del documento Extend rectangular selection to start of document line Extender selección rectangular al principio de la línea del documento Move to start of display line Mover al principio de la línea visualizada Extend selection to start of display line Extender selección al principio de la línea visualizada Move to start of display or document line Mover al principio de la línea visualizada o del documento Extend selection to start of display or document line Extender selección al principio de la línea visualizada o del documento Move to first visible character in document line Mover al primer carácter visible en la línea del documento Extend selection to first visible character in document line Extender selección al primer carácter visible en la línea del documento Extend rectangular selection to first visible character in document line Extender selección rectangular al primer carácter visible en la línea del documento Move to first visible character of display in document line Extender selección al primer carácter visualizado en la línea del documento Extend selection to first visible character in display or document line Extender selección al primer carácter de línea visualizada o del documento Move to end of document line Mover al final de la línea del documento Extend selection to end of document line Extender selección al final de la línea del documento Extend rectangular selection to end of document line Extender selección rectangular al final de la línea del documento Move to end of display line Mover al final de la línea visualizada Extend selection to end of display line Extender selección al final de la línea visualizada Move to end of display or document line Mover al final de la línea visualizada o del documento Extend selection to end of display or document line Extender selección al final de la línea visualizada o del documento Move to start of document Mover al principio del documento Extend selection to start of document Extender selección al principio del documento Move to end of document Mover al final del documento Extend selection to end of document Extender selección al final del documento Stuttered move up one page Mover progresivamente una página hacia arriba Stuttered extend selection up one page Extender progresivamente selección hacia arriba una página Stuttered move down one page Mover progresivamente una página hacia abajo Stuttered extend selection down one page Extender progresivamente selección hacia abajo una página Delete previous character if not at start of line Borrar carácter anterior si no está al principio de una línea Delete right to end of next word Borrar a la derecha hasta el final de la siguiente palabra Delete line to right Borrar línea hacia la derecha Transpose current and previous lines Transponer líneas actual y anterior Duplicate the current line Duplicar línea actual Select all Select document Seleccionar todo Move selected lines up one line Mover las líneas seleccionadas una línea hacia arriba Move selected lines down one line Mover las líneas seleccionadas una línea hacia abajo Toggle insert/overtype Conmutar insertar/sobreescribir Paste Pegar Copy selection Copiar selección Insert newline Insertar carácter de nueva línea De-indent one level Deshacer un nivel de indentado Cancel Cancelar Delete previous character Borrar carácter anterior Delete word to left Borrar palabra hacia la izquierda Delete line to left Borrar línea hacia la izquierda Undo last command Deshacer último comando Redo last command Rehacer último comando Indent one level Indentar un nivel Zoom in Aumentar zoom Zoom out Disminuir zoom Formfeed Carga de la página Cut current line Cortar línea actual Delete current line Borrar línea actual Copy current line Copiar línea actual Convert selection to lower case Convertir selección a minúsculas Convert selection to upper case Convertir selección a mayúsculas Duplicate selection Duplicar selección QsciLexerAVS Default Por defecto Block comment Comentario de bloque Nested block comment Comentario de bloque anidado Line comment Comentario de línea Number Número Operator Operador Identifier Identificador Double-quoted string Cadena con comillas dobles Triple double-quoted string Cadena con triple comilla doble Keyword Palabra clave Filter Filtro Plugin Plugin Function Función Clip property Propiedad de recorte User defined Definido por el usuario QsciLexerBash Default Por defecto Error Error Comment Comentario Number Número Keyword Palabra clave Double-quoted string Cadena con comillas dobles Single-quoted string Cadena con comillas simples Operator Operador Identifier Identificador Scalar Escalar Parameter expansion Expansión de parámetros Backticks Comilla inversa Here document delimiter Delimitador de documento integrado (here document) Single-quoted here document Documento integrado (here document) con comilla simple QsciLexerBatch Default Por defecto Comment Comentario Keyword Palabra clave Label Etiqueta Hide command character Ocultar caracteres de comando External command Comando externo Variable Variable Operator Operador QsciLexerCMake Default Por defecto Comment Comentario String Cadena de caracteres Left quoted string Cadena con comillas a la izquierda Right quoted string Cadena con comillas a la derecha Function Función Variable Variable Label Etiqueta User defined Definido por el usuario WHILE block Bloque WHILE FOREACH block Bloque FOREACH IF block Bloque IF MACRO block Bloque MACRO Variable within a string Variable en una cadena Number Número QsciLexerCPP Default Por defecto Inactive default Por defecto inactivo C comment Comentario C Inactive C comment Comentario C inactivo C++ comment Comentario C++ Inactive C++ comment Comentario C++ inactivo JavaDoc style C comment Comentario C de estilo JavaDoc Inactive JavaDoc style C comment Comentario C estilo JavaDoc inactivo Number Número Inactive number Número inactivo Keyword Palabra clave Inactive keyword Palabra clave inactiva Double-quoted string Cadena con comillas dobles Inactive double-quoted string Cadena con doble comilla inactiva Single-quoted string Cadena con comillas simples Inactive single-quoted string Cadena con comilla simple inactiva IDL UUID IDL UUID Inactive IDL UUID IDL UUID inactivo Pre-processor block Bloque de preprocesador Inactive pre-processor block Bloque de preprocesador inactivo Operator Operador Inactive operator Operador inactivo Identifier Identificador Inactive identifier Identificador inactivo Unclosed string Cadena sin cerrar Inactive unclosed string Cadena sin cerrar inactiva C# verbatim string Cadena C# textual Inactive C# verbatim string Cadena C# textual inactiva JavaScript regular expression Expresión regular JavaScript Inactive JavaScript regular expression Expresión regular JavaScript inactiva JavaDoc style C++ comment Comentario C++ de estilo JavaDoc Inactive JavaDoc style C++ comment Comentario C++ estilo JavaDoc inactivo Secondary keywords and identifiers Identificadores y palabras clave secundarios Inactive secondary keywords and identifiers Identificadores y palabras clave secundarios inactivos JavaDoc keyword Palabra clave de Javadoc Inactive JavaDoc keyword Palabra clave de JavaDoc inactiva JavaDoc keyword error Error en palabra clave de Javadoc Inactive JavaDoc keyword error Error en palabra clave de Javadoc inactivo Global classes and typedefs Clases globales y typedefs Inactive global classes and typedefs Clases globales y typedefs inactivos C++ raw string Cadena en bruto C++ Inactive C++ raw string Cadena inactiva C++ Vala triple-quoted verbatim string Cadena Vala con triple comilla textual Inactive Vala triple-quoted verbatim string Cadena Vala con triple comilla textual inactiva Pike hash-quoted string Cadena Pike con hash entrecomillado Inactive Pike hash-quoted string Cadena Pike con hash entrecomillado inactiva Pre-processor C comment Comentario C de preprocesador Inactive pre-processor C comment Comentario C de preprocesador inactivo JavaDoc style pre-processor comment Comentario de preprocesador estilo JavaDoc Inactive JavaDoc style pre-processor comment Comentario de preprocesador estilo JavaDoc inactivo User-defined literal Literal definido por el usuario Inactive user-defined literal Literal inactivo definido por el usuario Task marker Marcador de tarea Inactive task marker Marcador de tarea inactivo Escape sequence Secuencia de escape Inactive escape sequence Secuencia de escape inactiva QsciLexerCSS Default Por defecto Tag Etiqueta Class selector Selector de clase Pseudo-class Pseudoclase Unknown pseudo-class Pseudoclase desconocida Operator Operador CSS1 property Propiedad CSS1 Unknown property Propiedad desconocida Value Valor ID selector Selector de ID Important Importante @-rule Regla-@ Double-quoted string Cadena con comillas dobles Single-quoted string Cadena con comillas simples CSS2 property Propiedad CSS2 Attribute Atributo CSS3 property Propiedad CSS3 Pseudo-element Pseudoelemento Extended CSS property Propiedad CSS extendida Extended pseudo-class Pseudoclase extendida Extended pseudo-element Pseudoelemento extendido Media rule Regla de '@media' Variable Variable QsciLexerCSharp Verbatim string Cadena textual QsciLexerCoffeeScript Default Por defecto C-style comment Comentario de estilo C C++-style comment Comentario de estilo C++ JavaDoc C-style comment Comentario de estilo JavaDoc C Number Número Keyword Palabra clave Double-quoted string Cadena con comillas dobles Single-quoted string Cadena con comilla simple IDL UUID IDL UUID Pre-processor block Bloque de preprocesador Operator Operador Identifier Identificador Unclosed string Cadena sin cerrar C# verbatim string Cadena C# textual Regular expression Expresión regular JavaDoc C++-style comment Comentario de estilo JavaDoc C++ Secondary keywords and identifiers Identificadores y palabras clave secundarios JavaDoc keyword Palabra clave de JavaDoc JavaDoc keyword error Error en palabra clave de JavaDoc Global classes Clases globales Block comment Comentario de bloque Block regular expression Expresión regular de bloque Block regular expression comment Comentario de expresión regular de bloque Instance property Propiedad de instancia QsciLexerD Default Por defecto Block comment Comentario de bloque Line comment Comentario de línea DDoc style block comment Comentario de bloque estilo DDoc Nesting comment Comentario anidado Number Número Keyword Palabra clave Secondary keyword Palabra clave secundaria Documentation keyword Palabra clave de documentación Type definition Definición de tipo String Cadena de caracteres Unclosed string Cadena sin cerrar Character Carácter Operator Operador Identifier Identificador DDoc style line comment Comentario de línea estilo DDoc DDoc keyword Palabra clave DDoc DDoc keyword error Error en palabra clave DDOC Backquoted string Cadena con comillas hacia atrás Raw string Cadena en bruto User defined 1 Definido por el usuario 1 User defined 2 Definido por el usuario 2 User defined 3 Definido por el usuario 3 QsciLexerDiff Default Por defecto Comment Comentario Command Comando Header Encabezado Position Posición Removed line Línea eliminada Added line Línea añadida Changed line Línea modificada Added adding patch Removed adding patch Added removing patch Removed removing patch QsciLexerEDIFACT Default Por defecto Segment start Inicio de Segmento Segment end Final de Segmento Element separator Separador de elemento Composite separator Separador compuesto Release separator Separador de release UNA segment header Encabezamiento de segmento UNA UNH segment header Encabezamiento de segmento UNH Badly formed segment Segmento mal formado QsciLexerFortran77 Default Por defecto Comment Comentario Number Número Single-quoted string Cadena con comillas simples Double-quoted string Cadena con comillas dobles Unclosed string Cadena sin cerrar Operator Operador Identifier Identificador Keyword Palabra clave Intrinsic function Función intrínseca Extended function Función extendida Pre-processor block Bloque de preprocesador Dotted operator Operador punteado Label Etiqueta Continuation Continuación QsciLexerHTML HTML default HTML por defecto Tag Etiqueta Unknown tag Etiqueta desconocida Attribute Atributo Unknown attribute Atributo desconocido HTML number Número HTML HTML double-quoted string Cadena HTML con comillas dobles HTML single-quoted string Cadena HTML con comillas simples Other text in a tag Otro texto en una etiqueta HTML comment Comentario HTML Entity Entidad End of a tag Final de una etiqueta Start of an XML fragment Inicio de un fragmento XML End of an XML fragment Fin de un fragmento XML Script tag Etiqueta de script Start of an ASP fragment with @ Inicio de un fragmento ASP con @ Start of an ASP fragment Inicio de un fragmento ASP CDATA CDATA Start of a PHP fragment Inicio de un fragmento PHP Unquoted HTML value Valor HTML sin comillas ASP X-Code comment Comentario ASP X-Code SGML default SGML por defecto SGML command Comando SGML First parameter of an SGML command Primer parametro de un comando SGML SGML double-quoted string Cadena SGML con comillas dobles SGML single-quoted string Cadena SGML con comillas simples SGML error Error SGML SGML special entity Entidad SGML especial SGML comment Comentario SGML First parameter comment of an SGML command Comentario de primer parametro de un comando SGML SGML block default Bloque SGML por defecto Start of a JavaScript fragment Inicio de un fragmento JavaScript JavaScript default JavaScript por defecto JavaScript comment Comentario JavaScript JavaScript line comment Comentario de línea de JavaScript JavaDoc style JavaScript comment Comentario JavaScript de estilo JavaDoc JavaScript number Número JavaScript JavaScript word Palabra JavaScript JavaScript keyword Palabra clave JavaScript JavaScript double-quoted string Cadena JavaScript con comillas dobles JavaScript single-quoted string Cadena JavaScript con comillas simples JavaScript symbol Símbolo JavaScript JavaScript unclosed string Cadena JavaScript sin cerrar JavaScript regular expression Expresión regular JavaScript Start of an ASP JavaScript fragment Inicio de un fragmento de ASP JavaScript ASP JavaScript default ASP JavaScript por defecto ASP JavaScript comment Comentario de ASP JavaScript ASP JavaScript line comment Comentario de línea de ASP JavaScript JavaDoc style ASP JavaScript comment Comentario ASP JavaScript de estilo JavaDoc ASP JavaScript number Número ASP JavaScript ASP JavaScript word Palabra ASP JavaScript ASP JavaScript keyword Palabra clave ASP JavaScript ASP JavaScript double-quoted string Cadena ASP JavaScript con comillas dobles ASP JavaScript single-quoted string Cadena ASP JavaScript con comillas simples ASP JavaScript symbol Símbolo ASP JavaScript ASP JavaScript unclosed string Cadena ASP JavaScript sin cerrar ASP JavaScript regular expression Expresión regular ASP JavaScript Start of a VBScript fragment Inicio de un fragmento VBScript VBScript default VBScript por defecto VBScript comment Comentario VBScript VBScript number Número VBScript VBScript keyword Palabra clave VBScript VBScript string Cadena de caracteres VBScript VBScript identifier Identificador VBScript VBScript unclosed string Cadena VBScript sin cerrar Start of an ASP VBScript fragment Inicio de un fragmento de ASP VBScript ASP VBScript default ASP VBScript por defecto ASP VBScript comment Comentario de ASP VBScript ASP VBScript number Número ASP VBScript ASP VBScript keyword Palabra clave ASP VBScript ASP VBScript string Cadena de caracteres ASP VBScript ASP VBScript identifier Identificador ASP VBScript ASP VBScript unclosed string Cadena ASP VBScript sin cerrar Start of a Python fragment Inicio de un fragmento Python Python default Python por defecto Python comment Comentario Python Python number Número Python Python double-quoted string Cadena Python con comillas dobles Python single-quoted string Cadena Python con comillas simples Python keyword Palabra clave de Python Python triple double-quoted string Cadena Python con triple comilla doble Python triple single-quoted string Cadena Python con triple comilla simple Python class name Nombre de clase Python Python function or method name Nombre de método o función Python Python operator Operador Python Python identifier Identificador Python Start of an ASP Python fragment Inicio de un fragmento ASP Python ASP Python default ASP Python por defecto ASP Python comment Comentario ASP Python ASP Python number Número ASP Python ASP Python double-quoted string Cadena ASP Python con comillas dobles ASP Python single-quoted string Cadena ASP Python con comillas simples ASP Python keyword Palabra clave de ASP Python ASP Python triple double-quoted string Cadena ASP Python con triple comilla doble ASP Python triple single-quoted string Cadena ASP Python con triple comilla simple ASP Python class name Nombre de clase ASP Python ASP Python function or method name Nombre de método o función ASP Python ASP Python operator Operador ASP Python ASP Python identifier Identificador ASP Python PHP default PHP por defecto PHP double-quoted string Cadena PHP con comillas dobles PHP single-quoted string Cadena PHP con comillas simples PHP keyword Palabra clave PHP PHP number Número PHP PHP variable Variable PHP PHP comment Comentario PHP PHP line comment Comentario de línea PHP PHP double-quoted variable Variable PHP con comillas dobles PHP operator Operador PHP QsciLexerIDL UUID UUID QsciLexerJSON Default Por defecto Number Número String Cadena Unclosed string Cadena sin cerrar Property Propiedad Escape sequence Secuencia de escape Line comment Comentario de línea Block comment Comentario de bloque Operator Operador IRI IRI JSON-LD compact IRI JSON-LD compact IRI JSON keyword Palabra clave JSON JSON-LD keyword Palabra clave JSON-LD Parsing error Error de intérprete QsciLexerJavaScript Regular expression Expresión regular QsciLexerLua Default Por defecto Comment Comentario Line comment Comentario de línea Number Número Keyword Palabra clave String Cadena de caracteres Character Carácter Literal string Cadena literal Preprocessor Preprocesador Operator Operador Identifier Identificador Unclosed string Cadena sin cerrar Basic functions Funciones basicas String, table and maths functions Funcines de cadena, tabla y matemáticas Coroutines, i/o and system facilities Co-rutinas, e/s y funciones del sistema User defined 1 Definido por el usuario 1 User defined 2 Definido por el usuario 2 User defined 3 Definido por el usuario 3 User defined 4 Definido por el usuario 4 Label Etiqueta QsciLexerMakefile Default Por defecto Comment Comentario Preprocessor Preprocesador Variable Variable Operator Operador Target Objetivo Error Error QsciLexerMarkdown Default Por defecto Special Especial Strong emphasis using double asterisks Énfasis fuerte usando doble asterisco Strong emphasis using double underscores Énfasis fuerte usando doble guión bajo Emphasis using single asterisks Énfasis usando asterisco sencillo Emphasis using single underscores Énfasis usando guión bajo sencillo Level 1 header Encabezado de nivel 1 Level 2 header Encabezado de nivel 2 Level 3 header Encabezado de nivel 3 Level 4 header Encabezado de nivel 4 Level 5 header Encabezado de nivel 5 Level 6 header Encabezado de nivel 6 Pre-char Pre-char Unordered list item Elemento de lista sin ordenar Ordered list item Elemento de lista ordenada Block quote Bloque de cita Strike out Tachar Horizontal rule Regla horizontal Link Enlace Code between backticks Código entre comillas hacia atrás Code between double backticks Código entre comillas hacia atrás dobles Code block Bloque de código QsciLexerMatlab Default Por defecto Comment Comentario Command Comando Number Número Keyword Palabra clave Single-quoted string Cadena con comillas simples Operator Operador Identifier Identificador Double-quoted string Cadena con comillas dobles QsciLexerPO Default Por defecto Comment Comentario Message identifier Identificador de mensaje Message identifier text Texto identificador de mensaje Message string Cadena de mensaje Message string text Texto de cadena de mensaje Message context Contexto de mensaje Message context text Texto de contexto de mensaje Fuzzy flag Señalador difuso Programmer comment Comentario de programador Reference Referencia Flags Señaladores Message identifier text end-of-line Fin de línea de texto identificador de mensaje Message string text end-of-line Fin de línea de texto de cadena de mensaje Message context text end-of-line Fin de línea de texto de contexto de mensaje QsciLexerPOV Default Por defecto Comment Comentario Comment line Línea de comentario Number Número Operator Operador Identifier Identificador String Cadena de caracteres Unclosed string Cadena sin cerrar Directive Directiva Bad directive Mala directiva Objects, CSG and appearance Objetos, CSG y apariencia Types, modifiers and items Tipos, modificadores y elementos Predefined identifiers Identificadores predefinidos Predefined functions Funciones predefinidas User defined 1 Definido por el usuario 1 User defined 2 Definido por el usuario 2 User defined 3 Definido por el usuario 3 QsciLexerPascal Default Por defecto Line comment Comentario de línea Number Número Keyword Palabra clave Single-quoted string Cadena con comillas simples Operator Operador Identifier Identificador '{ ... }' style comment Comentario de estilo '{ ... }' '(* ... *)' style comment Comentario de estilo '(* ... *)' '{$ ... }' style pre-processor block Bloque de preprocesador de estilo '{$ ... }' '(*$ ... *)' style pre-processor block Bloque de preprocesador de estilo '(*$ ... *)' Hexadecimal number Número hexadecimal Unclosed string Cadena sin cerrar Character Carácter Inline asm asm inline QsciLexerPerl Default Por defecto Error Error Comment Comentario POD POD Number Número Keyword Palabra clave Double-quoted string Cadena con comillas dobles Single-quoted string Cadena con comillas simples Operator Operador Identifier Identificador Scalar Escalar Array Array Hash Hash Symbol table Tabla de símbolos Regular expression Expresión regular Substitution Sustitución Backticks Comilla inversa Data section Sección de datos Here document delimiter Delimitador de documento integrado (here document) Single-quoted here document Documento integrado (here document) con comilla simple Double-quoted here document Documento integrado (here document) con comilla doble Backtick here document Documento integrado (here document) con comilla inversa Quoted string (q) Cadena con comillas (q) Quoted string (qq) Cadena con comillas (qq) Quoted string (qx) Cadena con comillas (qx) Quoted string (qr) Cadena con comillas (qr) Quoted string (qw) Cadena con comillas (qw) POD verbatim POD textual Subroutine prototype Prototipo de subrutina Format identifier Identificador de formato Format body Cuerpo de formato Double-quoted string (interpolated variable) Cadena con doble comilla (variable interpolada) Translation Traducción Regular expression (interpolated variable) Expresión regular (variable interpolada) Substitution (interpolated variable) Substitución (variable interpolada) Backticks (interpolated variable) Comilla hacia atrás (variable interpolada) Double-quoted here document (interpolated variable) Here document con comilla doble (variable interpolada) Backtick here document (interpolated variable) Here document con comilla hacia atrás (variable interpolada) Quoted string (qq, interpolated variable) Cadena entrecomillada (qq, variable interpolada) Quoted string (qx, interpolated variable) Cadena entrecomillada (qx, variable interpolada) Quoted string (qr, interpolated variable) Cadena entrecomillada (qr, variable interpolada) QsciLexerPostScript Default Por defecto Comment Comentario DSC comment Comentario DSC DSC comment value Valor de comentario DSC Number Número Name Nombre Keyword Palabra clave Literal Literal Immediately evaluated literal Literal de evaluación inmediata Array parenthesis Paréntesis de array Dictionary parenthesis Paréntesis de diccionario Procedure parenthesis Paréntesis de procedimiento Text Texto Hexadecimal string Cadena hexadecimal Base85 string Cadena Base85 Bad string character Carácter de cadena mala QsciLexerProperties Default Por defecto Comment Comentario Section Sección Assignment Asignación Default value Valor por defecto Key Clave QsciLexerPython Default Por defecto Comment Comentario Number Número Double-quoted string Cadena con comillas dobles Single-quoted string Cadena con comillas simples Keyword Palabra clave Triple single-quoted string Cadena con triple comilla simple Triple double-quoted string Cadena con triple comilla doble Class name Nombre de clase Function or method name Nombre de método o función Operator Operador Identifier Identificador Comment block Bloque de comentario Unclosed string Cadena sin cerrar Highlighted identifier Identificador resaltado Decorator Decorador Double-quoted f-string Single-quoted f-string Triple single-quoted f-string Triple double-quoted f-string QsciLexerRuby Default Por defecto Comment Comentario Number Número Double-quoted string Cadena con comillas dobles Single-quoted string Cadena con comillas simples Keyword Palabra clave Class name Nombre de clase Function or method name Nombre de método o función Operator Operador Identifier Identificador Error Error POD POD Regular expression Expresión regular Global Global Symbol Símbolo Module name Nombre de módulo Instance variable Variable de instancia Class variable Variable de clase Backticks Comilla inversa Data section Sección de datos Here document delimiter Delimitador de documento integrado (here document) Here document Documento integrado (here document) %q string Cadena %q %Q string Cadena %Q %x string Cadena %x %r string Cadena %r %w string Cadena %w Demoted keyword Palabra clave degradada stdin stdin stdout stdout stderr stderr QsciLexerSQL Default Por defecto Comment Comentario Number Número Keyword Palabra clave Single-quoted string Cadena con comillas simples Operator Operador Identifier Identificador Comment line Línea de comentario JavaDoc style comment Comentario de estilo JavaDoc Double-quoted string Cadena con comillas dobles SQL*Plus keyword Palabra clave SQL*Plus SQL*Plus prompt Prompt SQL*Plus SQL*Plus comment Comentario SQL*Plus # comment line # línea de comentario JavaDoc keyword Palabra clave de Javadoc JavaDoc keyword error Error en palabra clave de Javadoc User defined 1 Definido por el usuario 1 User defined 2 Definido por el usuario 2 User defined 3 Definido por el usuario 3 User defined 4 Definido por el usuario 4 Quoted identifier Identificador entrecomillado Quoted operator Operador entrecomillado QsciLexerSpice Default Por defecto Identifier Identificador Command Comando Function Función Parameter Parámetro Number Número Delimiter Delimitador Value Valor Comment Comentario QsciLexerTCL Default Por defecto Comment Comentario Comment line Línea de comentario Number Número Quoted keyword Palabra clave entrecomillada Quoted string Cadena entrecomillada Operator Operador Identifier Identificador Substitution Sustitución Brace substitution Sustitución de corchetes Modifier Modificador Expand keyword Expandir palabra clave TCL keyword Palabra clave TCL Tk keyword Palabra clave Tk iTCL keyword Palabra clave iTCL Tk command Comando Tk User defined 1 Definido por el usuario 1 User defined 2 Definido por el usuario 2 User defined 3 Definido por el usuario 3 User defined 4 Definido por el usuario 4 Comment box Caja de comentario Comment block Bloque de comentario QsciLexerTeX Default Por defecto Special Especial Group Grupo Symbol Símbolo Command Comando Text Texto QsciLexerVHDL Default Por defecto Comment Comentario Comment line Línea de comentario Number Número String Cadena de caracteres Operator Operador Identifier Identificador Unclosed string Cadena sin cerrar Keyword Palabra clave Standard operator Operador estándar Attribute Atributo Standard function Función estándar Standard package Paquete estándar Standard type Tipo estándar User defined Definido por el usuario Comment block Bloque de comentario QsciLexerVerilog Default Por defecto Inactive default Inactivo por defecto Comment Comentario Inactive comment Line comment Comentario de línea Inactive line comment Línea de comentario inactiva Bang comment Comentario Bang Inactive bang comment Comentario Bang inactivo Number Inactive number Número inactivo Primary keywords and identifiers Identificadores y palabras clave primarios Inactive primary keywords and identifiers Palabras clave primarias e identificadores inactivos String Cadena Inactive string Cadena inactiva Secondary keywords and identifiers Palabras clave e identificadores secundarios Inactive secondary keywords and identifiers Identificadores y palabras clave secundarios inactivos System task Tarea de sistema Inactive system task Tarea de sistema inactiva Preprocessor block Bloque de preprocesador Inactive preprocessor block Operator Operador Inactive operator Operador inactivo Identifier Identificador Inactive identifier Identificador inactivo Unclosed string Cadena sin cerrar Inactive unclosed string Cadena sin cerrar inactiva User defined tasks and identifiers Tareas definidas por el usuario e identificadores Inactive user defined tasks and identifiers Tareas definidas por el usuario e identificadores inactivos Keyword comment Comentario de palabra clave Inactive keyword comment Comentario de palabra clave inactiva Input port declaration Declaración de puerto de input Inactive input port declaration Declaración de puerto de input inactivo Output port declaration Declaración de puerto de output Inactive output port declaration Declaración de puerto de output inactivo Input/output port declaration Declaración de puerto de input/output inactivo Inactive input/output port declaration Declaración de puerto de input/output inactivo Port connection Conexión de puerto Inactive port connection Conexión inactiva de puerto QsciLexerYAML Default Por defecto Comment Comentario Identifier Identificador Keyword Palabra clave Number Número Reference Referencia Document delimiter Delimitador de documento Text block marker Marcador de bloque de texto Syntax error marker Marcador de error de sintaxis Operator Operador QsciScintilla &Undo &Deshacer &Redo &Rehacer Cu&t Cor&tar &Copy &Copiar &Paste &Pegar Delete Borrar Select All Seleccionar todo sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_fr.qm000066400000000000000000001511221463772530400272250ustar00rootroot00000000000000<¸dÊÍ!¿`¡½ÝBøNiz¸QÉŸU4—¢U4©‚Zw8ÀZwu¯蘖H5T©Ôy˜¬ôÀ¬ô¸¦)[ÄwC9`|Bm­ÆG†ZHH˜‰“L™b&fL™b„íL™b•ßL™b¦¾N–À¸ Rx¼+Rx¼,zRx¼I$Rx¼ûVŠ¥%\ƒµ9¤\ƒµ³Î^ trCoº´Y­sàçq(zªþªï{L%£³Òaô¥Ò÷OÅ­4~Gâ¶Ú´_.Çô­ØÌÛ…Šäoò=äoò…dóeâxPº¥&Îõ^Fà=ZÔeöž ­w§t!(w§t:`w§t?éw§tyÅ{‚ÕY{ò‡Ãtk0›%ÔŠ¤ôfºÁm…Š©Ám…«ÍÁm…´˜Ám…¹¨ÐæÔ"öÐæÔ'NÐæÔ*ßÐæÔ2hÐæÔ<®ÐæÔA˜ÐæÔHèÐæÔÅÐæÔˆ/ÐæÔ‘ ÐæÔ–ûÐæÔÐæÔ¡÷ÐæÔ¨”ÐæÔ®@ÐæÔºyÐæÔÀUàŽ‰5¹àž‰6àþ‰5oâø³/uå@U4å±åÍ ªÅP¾!Í¿­#õ¨ËNhø h2š¢_×iÂÓ9U MÓpÅ @²—u*Oå²7 ’@¼<9t W³”[QÑUf…$Wá…®gŸŒ„´€Áoµ«>Ï¥ñ?’jÓøÅò¼ç—]!4œ%5Qñ¥-[¥åü[îu„fŠÓ9El&÷gç˜I¼ÁÓ~ÇŰ¹[Ð:Â"CÕ 4n×ë¤véãX|§dëzÂE ßqt½=æ½}†½™È½©­ Ÿ•/ Ÿ•z[ ò÷cÆvx 6î›g6îµÔctSu TäK»$<Ä`,_—Qã@ÙACF@ÙA‚í@ÙAއ@ÙA°c@ÙA¶@ÙBC£@ÙBƒL@ÙBŽæ@ÙB°Â@ÙB¶x@ÙCD@ÙCƒ«@ÙCE@ÙC±!@ÙC¶×@ÙD„ @ÙD±€@ÙD·6Aã7òH¦ôzÝ[“ô@y\8Â#\8Â'…\8Â,¬\8Â2ž\8Â<í\8ÂB\8ÂIZ\8Â{È\8€Ï\8ˆh\8‹³\8‘\8—2\8†\8¢0\8©\8®v\8³[\8µf\8º°\8½c\8ÂÀŒró3|ró>Jró½Ùs½þ#ïvB˜™‚‚(V™‚‚š$¨Ä…°«5"¯«5'«50«5;–«5AS«5H:«5~«5‡å«5‹l«5|«5–³«5¡­«5¨L«5¬Û«5³«5µ«5º1«5¼¿«5À «G,á«GB‰«G|ëG„«GQ«G» «G¾h°9\ª‘°9\¸qâ¯t{#ñŽÔ^’*ÄÃŒì?^t[ÿ]íu©_pÔ è}Ú3 }Ú=m}ÚIÔ“ÏdÔœ('v3 «.EÖ¶•§Uè½Çl³È#´È'¹È+IÈ2ÑÈ7·È=)ÈBPÈI“È{üÈÈ…$ȈžÈŒRÈ‘ÓÈ—fÈ¢fÈ©FÈ®©Èµ™ÈºäȽšÈÀÀѽ8'Ô‡„*àæ§p4—€€§• Ûî {©"]¸)6%Ô)µ 6|Ô®ä_uâg_d*˜Àd*i˜hd*É™d*ù™piø7{ª¬’ªÇª¶Ä«ÜŒ¤_¾ÝÀ©pËàä„KO™äs _¤W&åµf<*bÆ3g”5<.˜j½‚ Æo1¤|Ö^{€ÓXœƒœB³‡ã"@?‡ã"~:‡ã"¤ŠlT~å+†~å-~å9Ö~å…æ•²´M@¦2cŒ°œ2w›ºûÅ‹0èóät€ì‰N­ö2Wrù¦”· ~ÕD &0'$( &0'£. 3ø¤Ù ?3äuQ @|Uv~ fÌÉ|‡ o” tÞ @t¯Ž ¨Ÿ×Y ¬÷÷y ¯²*j ±^÷l ´×!¼ ´×%Þ ´×.’ ´×6Ä ´×; ´×GU ´ׇ[ ´וW ´× ® ´צ6 ´׬T º°ŸN ÉX$“E Ûí=—Í iä€ ïÔip ê4e 'ç4. *²S% *²S“½ *²S¤Ù +O4œƒ 0è‚" Iq>'õ S浟‹ Sæµ¥" d8Dë d8†  d8±ß d8·• d<%b d<)™ d<+Á d<E$ d<Fœ d<~v d<„i d<†Û d<‰f d<Šk d<” d<œ> d<ž> d<ŸÓ d<¥h d<« d<² d<´ d<¹ d<¼= d<¿1 d4-È kŸ,†e kŸ,¸; qe’XA s(›ý •ø$a} œµd”Ô ¡úR6M °ÖBT" ¼Œt!€ ¼Œt%¡ ¼Œt)Ù ¼Œt, ¼Œt.V ¼Œt6ˆ ¼Œt:Á ¼ŒtA ¼ŒtEc ¼ŒtF\ ¼ŒtG ¼Œtz ¼ŒtB ¼Œt„¬ ¼Œt†$ ¼Œt‡ ¼Œt‰£ ¼ŒtŠô ¼Œtã ¼Œt”— ¼ŒtœÔ ¼Œtžƒ ¼Œt o ¼Œt¥ù ¼Œt¬ ¼Œt²Y ¼Œt´ã ¼Œt·Í ¼Œt¹ô ¼Œt¼ ¼Œt¿p ÑzäZÅ èZTe_ ó¥é óZ5‰ _´i ?dZ "… 5 '¬d4 ( „s” ;2Èr ;^·T A¾\& E×Är© _ Ôø cVåD] dóÓ dN¤§˜ e„wþ €4$qæ Ô55 ÔZ Ô¸Õ ¿y÷ Ç|0– Ç|<= Ç|­p ÊBu›­ ӕ勿 ÝO¡8 ÝO¦ñ ìÆ4(Ž ìÆ4š\ Ø—d§ ðEhÁ )‹  )‹´@ )‹¹O >ÖkÅ J¬Ž"v J¬Ž,? J¬Ž²× WöÜOb fÎò7K oÂ&™ o–F o大 §'Zy ÁÅžÆ Èü%‰Þ Èü%Àü ÐAŽH‡ Ðæ·]û ñ1r ÷ïÄV¨ û'×e¨ þxŽN$  .”E  .¥§ ¦Euà '¸4¿ 943~´ @&4nÁ @*$ny _á}è t}4#, t}4AÌ t}4{r t}4€+ t}4‘E t}4½ ‚‰Ô0þ Œ?DPe Ig4Ž Ig?n IgBÖ IgJ× Ig} Ig‚{ IgŽ Ig’› Ig¤d Ig»p Ig¾» «ãt0H «ãt;æ «ãt­" Â`åh{ ×.„t ñyS ÓWxŸ còs é8ð'»ÒÎ9 …RŒ=¤ej_V‰ÇmgW´\co]‹gU(e–T\Õhw„a%iåroòldLÚwægo[{ÔQ…›&4\‡£Ç)£Ç4£Ç89£Ç>Þ£ÇJJ£Ljܣǒ£Çšß£Ç¢¤£Ǫ £ǯÜ£õBMÃ¥¿´Q%­)w£ÉƦ¯=Çn!ÐL„ wÓkC ëj…Fþ21ìþ2bI@’SÍ#}w:4+4VRÎ’k|u@Ô$Àu@Ô-2u@Ô»ã‰2fý)t2µnEÈÀ–ToÄÔá²Äöå9r|8ù¬•D£iÁ9AnnulerCancel QsciCommandZConversion de la ligne courante en minusculesConvert selection to lower case QsciCommandZConversion de la ligne courante en majusculesConvert selection to upper case QsciCommand0Copier la ligne couranteCopy current line QsciCommand&Copier la sélectionCopy selection QsciCommand0Couper la ligne couranteCut current line QsciCommand&Couper la sélection Cut selection QsciCommand>Effacement du caractère courantDelete current character QsciCommand@Suppression de la ligne couranteDelete current line QsciCommandHEffacer la partie gauche de la ligneDelete line to left QsciCommandVSuppression de la partie droite de la ligneDelete line to right QsciCommand@Suppression du dernier caractèreDelete previous character QsciCommand8Suppression du mot de gaucheDelete word to left QsciCommand8Suppression du mot de droiteDelete word to right QsciCommand~Extension de la sélection rectangulaire d'une ligne vers le bas*Extend rectangular selection down one line QsciCommand|Extension de la sélection rectangulaire d'une page vers le bas*Extend rectangular selection down one page QsciCommandŠExtension de la sélection rectangulaire d'un caractère vers la gauche/Extend rectangular selection left one character QsciCommandŠExtension de la sélection rectangulaire d'un caractère vers la droite0Extend rectangular selection right one character QsciCommand€Extension de la sélection rectangulaire d'une ligne vers le haut(Extend rectangular selection up one line QsciCommand~Extension de la sélection rectangulaire d'une page vers le haut(Extend rectangular selection up one page QsciCommandbExtension de la sélection d'une ligne vers le basExtend selection down one line QsciCommand`Extension de la sélection d'une page vers le basExtend selection down one page QsciCommandjExtension de la sélection d'un paragraphe vers le bas#Extend selection down one paragraph QsciCommandnExtension de la sélection d'un caractère vers la gauche#Extend selection left one character QsciCommandbExtension de la sélection d'un mot vers la gaucheExtend selection left one word QsciCommandtExtension de la sélection d'une part de mot vers la gauche#Extend selection left one word part QsciCommandnExtension de la sélection d'un caractère vers la droite$Extend selection right one character QsciCommandbExtension de la sélection d'un mot vers la droiteExtend selection right one word QsciCommandtExtension de la sélection d'une part de mot vers la droite$Extend selection right one word part QsciCommandbExtension de la sélection vers fin du mot suivant$Extend selection to end of next word QsciCommandfExtension de la sélection vers fin du mot précédent(Extend selection to end of previous word QsciCommandrExtension de la sélection vers début de ligne du document*Extend selection to start of document line QsciCommanddExtension de la sélection d'une ligne vers le hautExtend selection up one line QsciCommandbExtension de la sélection d'une page vers le hautExtend selection up one page QsciCommandlExtension de la sélection d'un paragraphe vers le haut!Extend selection up one paragraph QsciCommand*Chargement de la pageFormfeed QsciCommand.Indentation d'un niveauIndent one level QsciCommandFDéplacement d'une ligne vers le basMove down one line QsciCommandDDéplacement d'une page vers le basMove down one page QsciCommandNDéplacement d'un paragraphe vers le basMove down one paragraph QsciCommandRDéplacement d'un caractère vers la gaucheMove left one character QsciCommandFDéplacement d'un mot vers la gaucheMove left one word QsciCommandXDéplacement d'une part de mot vers la gaucheMove left one word part QsciCommandRDéplacement d'un caractère vers la droiteMove right one character QsciCommandFDéplacement d'un mot vers la droiteMove right one word QsciCommandXDéplacement d'une part de mot vers la droiteMove right one word part QsciCommandFDéplacement vers fin du mot suivantMove to end of next word QsciCommandJDéplacement vers fin du mot précédentMove to end of previous word QsciCommandVDéplacement vers début de ligne du documentMove to start of document line QsciCommandHDéplacement d'une ligne vers le hautMove up one line QsciCommandFDéplacement d'une page vers le hautMove up one page QsciCommandPDéplacement d'un paragraphe vers le hautMove up one paragraph QsciCommand CollerPaste QsciCommand8Refaire la dernière commandeRedo last command QsciCommand<Descendre à la fin du documentScroll to end of document QsciCommand:Remonter au début du documentScroll to start of document QsciCommandhDéfiler verticalement pour centrer la ligne courante(Scroll vertically to centre current line QsciCommand6Decendre la vue d'une ligneScroll view down one line QsciCommand6Remonter la vue d'une ligneScroll view up one line QsciCommandBBasculement Insertion /EcrasementToggle insert/overtype QsciCommandZoom avantZoom in QsciCommandZoom arrièreZoom out QsciCommand*Block de commentaires Block comment QsciLexerAVSPar défautDefault QsciLexerAVSRChaine de caractères (guillemets doubles)Double-quoted string QsciLexerAVS FiltreFilter QsciLexerAVSFonctionFunction QsciLexerAVSIdentificateur Identifier QsciLexerAVSMot-cléKeyword QsciLexerAVS(Commentaire de ligne Line comment QsciLexerAVS NombreNumber QsciLexerAVSOpérateurOperator QsciLexerAVSExtensionPlugin QsciLexerAVS\Chaine de caractères HTML (guillemets simples)Triple double-quoted string QsciLexerAVS,Définition utilisateur User defined QsciLexerAVSQuotes inverses Backticks QsciLexerBashCommentaireComment QsciLexerBashPar défautDefault QsciLexerBashRChaine de caractères (guillemets doubles)Double-quoted string QsciLexerBash ErreurError QsciLexerBash4Ici délimiteur de documentHere document delimiter QsciLexerBashIdentificateur Identifier QsciLexerBashMot-cléKeyword QsciLexerBash NombreNumber QsciLexerBashOpérateurOperator QsciLexerBash,Extension de paramètreParameter expansion QsciLexerBashScalaireScalar QsciLexerBashFDocument intégré guillemets simplesSingle-quoted here document QsciLexerBashRChaine de caractères (guillemets simples)Single-quoted string QsciLexerBashCommentaireCommentQsciLexerBatchPar défautDefaultQsciLexerBatch Commande externeExternal commandQsciLexerBatch<Cacher le caratère de commandeHide command characterQsciLexerBatchMot-cléKeywordQsciLexerBatch TitreLabelQsciLexerBatchOpérateurOperatorQsciLexerBatchVariableVariableQsciLexerBatchCommentaireCommentQsciLexerCMakePar défautDefaultQsciLexerCMakeFonctionFunctionQsciLexerCMake TitreLabelQsciLexerCMake NombreNumberQsciLexerCMake(Chaîne de caractèresStringQsciLexerCMake,Définition utilisateur User definedQsciLexerCMakeVariableVariableQsciLexerCMakeCommentaire C C comment QsciLexerCPPCommentaire C++ C++ comment QsciLexerCPPPar défautDefault QsciLexerCPPRChaine de caractères (guillemets doubles)Double-quoted string QsciLexerCPP,Séquence d'échappementEscape sequence QsciLexerCPPPClasses globales et définitions de typesGlobal classes and typedefs QsciLexerCPPIdentificateur Identifier QsciLexerCPPMot-clé JavaDocJavaDoc keyword QsciLexerCPP2Erreur de mot-clé JavaDocJavaDoc keyword error QsciLexerCPP<Commentaire C de style JavaDocJavaDoc style C comment QsciLexerCPP@Commentaire C++ de style JavaDocJavaDoc style C++ comment QsciLexerCPP>Expression régulière JavaScriptJavaScript regular expression QsciLexerCPPMot-cléKeyword QsciLexerCPP NombreNumber QsciLexerCPPOpérateurOperator QsciLexerCPP<Instructions de pré-processingPre-processor block QsciLexerCPPHSeconds mots-clés et identificateurs"Secondary keywords and identifiers QsciLexerCPPRChaine de caractères (guillemets simples)Single-quoted string QsciLexerCPPBChaine de caractères non referméeUnclosed string QsciLexerCPPrègle-@@-rule QsciLexerCSSAttribut Attribute QsciLexerCSSPropriété CSS1 CSS1 property QsciLexerCSSPropriété CSS2 CSS2 property QsciLexerCSSPropriété CSS3 CSS3 property QsciLexerCSS ClasseClass selector QsciLexerCSSPar défautDefault QsciLexerCSSRChaine de caractères (guillemets doubles)Double-quoted string QsciLexerCSSID ID selector QsciLexerCSSImportant Important QsciLexerCSSOpérateurOperator QsciLexerCSSPseudo-classe Pseudo-class QsciLexerCSSRChaine de caractères (guillemets simples)Single-quoted string QsciLexerCSS BaliseTag QsciLexerCSS$Propriété inconnueUnknown property QsciLexerCSS*Peudo-classe inconnueUnknown pseudo-class QsciLexerCSS ValeurValue QsciLexerCSSVariableVariable QsciLexerCSSChaine verbatimVerbatim stringQsciLexerCSharp*Block de commentaires Block commentQsciLexerCoffeeScriptPar défautDefaultQsciLexerCoffeeScriptRChaine de caractères (guillemets doubles)Double-quoted stringQsciLexerCoffeeScriptIdentificateur IdentifierQsciLexerCoffeeScriptMot-clé JavaDocJavaDoc keywordQsciLexerCoffeeScript2Erreur de mot-clé JavaDocJavaDoc keyword errorQsciLexerCoffeeScriptMot-cléKeywordQsciLexerCoffeeScript NombreNumberQsciLexerCoffeeScriptOpérateurOperatorQsciLexerCoffeeScript<Instructions de pré-processingPre-processor blockQsciLexerCoffeeScript(Expression régulièreRegular expressionQsciLexerCoffeeScriptHSeconds mots-clés et identificateurs"Secondary keywords and identifiersQsciLexerCoffeeScriptRChaine de caractères (guillemets simples)Single-quoted stringQsciLexerCoffeeScriptBChaine de caractères non referméeUnclosed stringQsciLexerCoffeeScript*Block de commentaires Block comment QsciLexerDCaractère Character QsciLexerDMot-clé DDoc DDoc keyword QsciLexerD,Erreur de mot-clé DDocDDoc keyword error QsciLexerDPar défautDefault QsciLexerDIdentificateur Identifier QsciLexerDMot-cléKeyword QsciLexerD(Commentaire de ligne Line comment QsciLexerD NombreNumber QsciLexerDOpérateurOperator QsciLexerD(Chaîne de caractèresString QsciLexerDBChaine de caractères non referméeUnclosed string QsciLexerD0Définition utilisateur 1User defined 1 QsciLexerD0Définition utilisateur 2User defined 2 QsciLexerD0Définition utilisateur 3User defined 3 QsciLexerDLigne ajoutée Added line QsciLexerDiffLigne changée Changed line QsciLexerDiffCommandeCommand QsciLexerDiffCommentaireComment QsciLexerDiffPar défautDefault QsciLexerDiffEn-têteHeader QsciLexerDiffPositionPosition QsciLexerDiffLigne supprimée Removed line QsciLexerDiffPar défautDefaultQsciLexerEDIFACTCommentaireCommentQsciLexerFortran77ÿÿÿÿ ContinuationQsciLexerFortran77Par défautDefaultQsciLexerFortran77RChaine de caractères (guillemets doubles)Double-quoted stringQsciLexerFortran77 Fonction étendueExtended functionQsciLexerFortran77Identificateur IdentifierQsciLexerFortran77(Fonction intrinsèqueIntrinsic functionQsciLexerFortran77Mot-cléKeywordQsciLexerFortran77 TitreLabelQsciLexerFortran77 NombreNumberQsciLexerFortran77OpérateurOperatorQsciLexerFortran77<Instructions de pré-processingPre-processor blockQsciLexerFortran77RChaine de caractères (guillemets simples)Single-quoted stringQsciLexerFortran77BChaine de caractères non referméeUnclosed stringQsciLexerFortran774Commentaire JavaScript ASPASP JavaScript comment QsciLexerHTML2JavaScript ASP par défautASP JavaScript default QsciLexerHTMLpChaine de caractères JavaScript ASP (guillemets doubles)#ASP JavaScript double-quoted string QsciLexerHTML.Mot-clé JavaScript ASP ASP JavaScript keyword QsciLexerHTMLFCommentaire de ligne JavaScript ASPASP JavaScript line comment QsciLexerHTML*Nombre JavaScript ASPASP JavaScript number QsciLexerHTMLFExpression régulière JavaScript ASP!ASP JavaScript regular expression QsciLexerHTMLpChaine de caractères JavaScript ASP (guillemets simples)#ASP JavaScript single-quoted string QsciLexerHTML,Symbole JavaScript ASPASP JavaScript symbol QsciLexerHTML`Chaine de caractères JavaScript ASP non referméeASP JavaScript unclosed string QsciLexerHTML$Mot JavaScript ASPASP JavaScript word QsciLexerHTML0Nom de classe Python ASPASP Python class name QsciLexerHTML,Commentaire Python ASPASP Python comment QsciLexerHTML*Python ASP par défautASP Python default QsciLexerHTMLhChaine de caractères Python ASP (guillemets doubles)ASP Python double-quoted string QsciLexerHTML<Méthode ou fonction Python ASP"ASP Python function or method name QsciLexerHTML2Identificateur Python ASPASP Python identifier QsciLexerHTML$Mot-clé Python ASPASP Python keyword QsciLexerHTML"Nombre Python ASPASP Python number QsciLexerHTML(Opérateur Python ASPASP Python operator QsciLexerHTMLhChaine de caractères Python ASP (guillemets simples)ASP Python single-quoted string QsciLexerHTMLxChaine de caractères Python ASP (triples guillemets doubles)&ASP Python triple double-quoted string QsciLexerHTMLxChaine de caractères Python ASP (triples guillemets simples)&ASP Python triple single-quoted string QsciLexerHTML0Commentaire VBScript ASPASP VBScript comment QsciLexerHTML.VBScript ASP par défautASP VBScript default QsciLexerHTML6Identificateur VBScript ASPASP VBScript identifier QsciLexerHTML*Mot-clé VBScript ASP ASP VBScript keyword QsciLexerHTML&Nombre VBScript ASPASP VBScript number QsciLexerHTMLBChaine de caractères VBScript ASPASP VBScript string QsciLexerHTML\Chaine de caractères VBScript ASP non referméeASP VBScript unclosed string QsciLexerHTML,Commentaire X-Code ASPASP X-Code comment QsciLexerHTMLAttribut Attribute QsciLexerHTML CDATACDATA QsciLexerHTMLBalise fermante End of a tag QsciLexerHTML Fin de block XMLEnd of an XML fragment QsciLexerHTML EntitéEntity QsciLexerHTMLbPremier paramètre de commentaire de commande SGML*First parameter comment of an SGML command QsciLexerHTMLDPremier paramètre de commande SGML"First parameter of an SGML command QsciLexerHTML Commentaire HTML HTML comment QsciLexerHTMLHTML par défaut HTML default QsciLexerHTML\Chaine de caractères HTML (guillemets doubles)HTML double-quoted string QsciLexerHTMLNombre HTML HTML number QsciLexerHTML\Chaine de caractères HTML (guillemets simples)HTML single-quoted string QsciLexerHTMLVCommentaire JavaScript ASP de style JavaDoc$JavaDoc style ASP JavaScript comment QsciLexerHTMLNCommentaire JavaScript de style JavaDoc JavaDoc style JavaScript comment QsciLexerHTML,Commentaire JavaScriptJavaScript comment QsciLexerHTML*JavaScript par défautJavaScript default QsciLexerHTMLhChaine de caractères JavaScript (guillemets doubles)JavaScript double-quoted string QsciLexerHTML$Mot-clé JavaScriptJavaScript keyword QsciLexerHTML>Commentaire de ligne JavaScriptJavaScript line comment QsciLexerHTML"Nombre JavaScriptJavaScript number QsciLexerHTML>Expression régulière JavaScriptJavaScript regular expression QsciLexerHTMLhChaine de caractères JavaScript (guillemets simples)JavaScript single-quoted string QsciLexerHTML$Symbole JavaScriptJavaScript symbol QsciLexerHTMLXChaine de caractères JavaScript non referméeJavaScript unclosed string QsciLexerHTMLMot JavaScriptJavaScript word QsciLexerHTML8Autre texte dans les balisesOther text in a tag QsciLexerHTMLCommentaire PHP PHP comment QsciLexerHTMLPHP par défaut PHP default QsciLexerHTMLZChaine de caractères PHP (guillemets doubles)PHP double-quoted string QsciLexerHTMLBVariable PHP (guillemets doubles)PHP double-quoted variable QsciLexerHTMLMot-clé PHP PHP keyword QsciLexerHTML0Commentaire de ligne PHPPHP line comment QsciLexerHTMLNombre PHP PHP number QsciLexerHTMLOpérateur PHP PHP operator QsciLexerHTMLZChaine de caractères PHP (guillemets simples)PHP single-quoted string QsciLexerHTMLVariable PHP PHP variable QsciLexerHTML(Nom de classe PythonPython class name QsciLexerHTML$Commentaire PythonPython comment QsciLexerHTML"Python par défautPython default QsciLexerHTML`Chaine de caractères Python (guillemets doubles)Python double-quoted string QsciLexerHTML4Méthode ou fonction PythonPython function or method name QsciLexerHTML*Identificateur PythonPython identifier QsciLexerHTMLMot-clé PythonPython keyword QsciLexerHTMLNombre Python Python number QsciLexerHTML Opérateur PythonPython operator QsciLexerHTML`Chaine de caractères Python (guillemets simples)Python single-quoted string QsciLexerHTMLpChaine de caractères Python (triples guillemets doubles)"Python triple double-quoted string QsciLexerHTMLpChaine de caractères Python (triples guillemets simples)"Python triple single-quoted string QsciLexerHTML*Block SGML par défautSGML block default QsciLexerHTMLCommande SGML SGML command QsciLexerHTML Commentaire SGML SGML comment QsciLexerHTMLSGML par défaut SGML default QsciLexerHTML\Chaine de caractères SGML (guillemets doubles)SGML double-quoted string QsciLexerHTMLErreur SGML SGML error QsciLexerHTML\Chaine de caractères SGML (guillemets simples)SGML single-quoted string QsciLexerHTML(Entité SGML spécialeSGML special entity QsciLexerHTML Balise de script Script tag QsciLexerHTML2Début de block JavaScriptStart of a JavaScript fragment QsciLexerHTML$Début de block PHPStart of a PHP fragment QsciLexerHTML*Début de block PythonStart of a Python fragment QsciLexerHTML.Début de block VBScriptStart of a VBScript fragment QsciLexerHTML:Début de block JavaScript ASP#Start of an ASP JavaScript fragment QsciLexerHTML2Début de block Python ASPStart of an ASP Python fragment QsciLexerHTML6Début de block VBScript ASP!Start of an ASP VBScript fragment QsciLexerHTML$Début de block ASPStart of an ASP fragment QsciLexerHTML2Début de block ASP avec @Start of an ASP fragment with @ QsciLexerHTML$Début de block XMLStart of an XML fragment QsciLexerHTML BaliseTag QsciLexerHTML Attribut inconnuUnknown attribute QsciLexerHTMLBalise inconnue Unknown tag QsciLexerHTML6Valeur HTML sans guillemetsUnquoted HTML value QsciLexerHTML(Commentaire VBScriptVBScript comment QsciLexerHTML&VBScript par défautVBScript default QsciLexerHTML.Identificateur VBScriptVBScript identifier QsciLexerHTML Mot-clé VBScriptVBScript keyword QsciLexerHTMLNombre VBScriptVBScript number QsciLexerHTML:Chaine de caractères VBScriptVBScript string QsciLexerHTMLTChaine de caractères VBScript non referméeVBScript unclosed string QsciLexerHTMLUUIDUUID QsciLexerIDL*Block de commentaires Block comment QsciLexerJSONPar défautDefault QsciLexerJSON,Séquence d'échappementEscape sequence QsciLexerJSONÿÿÿÿIRI QsciLexerJSONMot-clé JSON JSON keyword QsciLexerJSONMot-clé JSON-LDJSON-LD keyword QsciLexerJSON(Commentaire de ligne Line comment QsciLexerJSON NombreNumber QsciLexerJSONOpérateurOperator QsciLexerJSON Erreur d'analyse Parsing error QsciLexerJSONPropriétéProperty QsciLexerJSON(Chaîne de caractèresString QsciLexerJSONBChaine de caractères non referméeUnclosed string QsciLexerJSON(Expression régulièreRegular expressionQsciLexerJavaScript"Fonctions de baseBasic functions QsciLexerLuaCaractère Character QsciLexerLuaCommentaireComment QsciLexerLuaHCoroutines, i/o et fonctions système%Coroutines, i/o and system facilities QsciLexerLuaPar défautDefault QsciLexerLuaIdentificateur Identifier QsciLexerLuaMot-cléKeyword QsciLexerLua TitreLabel QsciLexerLua(Commentaire de ligne Line comment QsciLexerLua Chaîne littéraleLiteral string QsciLexerLua NombreNumber QsciLexerLuaOpérateurOperator QsciLexerLuaPréprocessing Preprocessor QsciLexerLua(Chaîne de caractèresString QsciLexerLuafFonctions sur les chaines, tables et fonctions math!String, table and maths functions QsciLexerLuaBChaine de caractères non referméeUnclosed string QsciLexerLua0Définition utilisateur 1User defined 1 QsciLexerLua0Définition utilisateur 2User defined 2 QsciLexerLua0Définition utilisateur 3User defined 3 QsciLexerLua0Définition utilisateur 4User defined 4 QsciLexerLuaCommentaireCommentQsciLexerMakefilePar défautDefaultQsciLexerMakefile ErreurErrorQsciLexerMakefileOpérateurOperatorQsciLexerMakefilePréprocessing PreprocessorQsciLexerMakefile CibleTargetQsciLexerMakefileVariableVariableQsciLexerMakefilePar défautDefaultQsciLexerMarkdownSpécialSpecialQsciLexerMarkdownCommandeCommandQsciLexerMatlabCommentaireCommentQsciLexerMatlabPar défautDefaultQsciLexerMatlabRChaine de caractères (guillemets doubles)Double-quoted stringQsciLexerMatlabIdentificateur IdentifierQsciLexerMatlabMot-cléKeywordQsciLexerMatlab NombreNumberQsciLexerMatlabOpérateurOperatorQsciLexerMatlabRChaine de caractères (guillemets simples)Single-quoted stringQsciLexerMatlabCommentaireComment QsciLexerPOPar défautDefault QsciLexerPORéférence Reference QsciLexerPO$Mauvaise directive Bad directive QsciLexerPOVCommentaireComment QsciLexerPOVLigne commentée Comment line QsciLexerPOVPar défautDefault QsciLexerPOVDirective Directive QsciLexerPOVIdentificateur Identifier QsciLexerPOV NombreNumber QsciLexerPOV0Objets, CSG et apparenceObjects, CSG and appearance QsciLexerPOVOpérateurOperator QsciLexerPOV*Fonctions prédéfiniesPredefined functions QsciLexerPOV.Identifiants prédéfinisPredefined identifiers QsciLexerPOV(Chaîne de caractèresString QsciLexerPOV:Types, modifieurs et élémentsTypes, modifiers and items QsciLexerPOVBChaine de caractères non referméeUnclosed string QsciLexerPOV0Définition utilisateur 1User defined 1 QsciLexerPOV0Définition utilisateur 2User defined 2 QsciLexerPOV0Définition utilisateur 3User defined 3 QsciLexerPOVCaractère CharacterQsciLexerPascalPar défautDefaultQsciLexerPascal$Nombre hexadécimalHexadecimal numberQsciLexerPascalIdentificateur IdentifierQsciLexerPascalAsm en ligne Inline asmQsciLexerPascalMot-cléKeywordQsciLexerPascal(Commentaire de ligne Line commentQsciLexerPascal NombreNumberQsciLexerPascalOpérateurOperatorQsciLexerPascalRChaine de caractères (guillemets simples)Single-quoted stringQsciLexerPascalBChaine de caractères non referméeUnclosed stringQsciLexerPascalTableauArray QsciLexerPerl@Document intégré quotes inversesBacktick here document QsciLexerPerlQuotes inverses Backticks QsciLexerPerlCommentaireComment QsciLexerPerl$Section de données Data section QsciLexerPerlPar défautDefault QsciLexerPerlFDocument intégré guillemets doublesDouble-quoted here document QsciLexerPerlRChaine de caractères (guillemets doubles)Double-quoted string QsciLexerPerl ErreurError QsciLexerPerlHashageHash QsciLexerPerl4Ici délimiteur de documentHere document delimiter QsciLexerPerlIdentificateur Identifier QsciLexerPerlMot-cléKeyword QsciLexerPerl NombreNumber QsciLexerPerlOpérateurOperator QsciLexerPerlPODPOD QsciLexerPerlPOD verbatim POD verbatim QsciLexerPerl"Chaine quotée (q)Quoted string (q) QsciLexerPerl$Chaine quotée (qq)Quoted string (qq) QsciLexerPerl$Chaine quotée (qr)Quoted string (qr) QsciLexerPerl$Chaine quotée (qw)Quoted string (qw) QsciLexerPerl$Chaine quotée (qx)Quoted string (qx) QsciLexerPerl(Expression régulièreRegular expression QsciLexerPerlScalaireScalar QsciLexerPerlFDocument intégré guillemets simplesSingle-quoted here document QsciLexerPerlRChaine de caractères (guillemets simples)Single-quoted string QsciLexerPerlSubstitution Substitution QsciLexerPerl"Table de symboles Symbol table QsciLexerPerlTraduction Translation QsciLexerPerlCommentaireCommentQsciLexerPostScriptCommentaire DSC DSC commentQsciLexerPostScriptPar défautDefaultQsciLexerPostScriptMot-cléKeywordQsciLexerPostScriptNomNameQsciLexerPostScript NombreNumberQsciLexerPostScript TexteTextQsciLexerPostScriptAffectation AssignmentQsciLexerPropertiesCommentaireCommentQsciLexerPropertiesPar défautDefaultQsciLexerProperties"Valeur par défaut Default valueQsciLexerPropertiesCléKeyQsciLexerPropertiesSectionSectionQsciLexerPropertiesNom de classe Class nameQsciLexerPythonCommentaireCommentQsciLexerPython*Block de commentaires Comment blockQsciLexerPythonPar défautDefaultQsciLexerPythonRChaine de caractères (guillemets doubles)Double-quoted stringQsciLexerPython:Nom de méthode ou de fonctionFunction or method nameQsciLexerPythonIdentificateur IdentifierQsciLexerPythonMot-cléKeywordQsciLexerPython NombreNumberQsciLexerPythonOpérateurOperatorQsciLexerPythonRChaine de caractères (guillemets simples)Single-quoted stringQsciLexerPython\Chaine de caractères HTML (guillemets simples)Triple double-quoted stringQsciLexerPython\Chaine de caractères HTML (guillemets simples)Triple single-quoted stringQsciLexerPythonBChaine de caractères non referméeUnclosed stringQsciLexerPythonQuotes inverses Backticks QsciLexerRubyNom de classe Class name QsciLexerRubyCommentaireComment QsciLexerRuby$Section de données Data section QsciLexerRubyPar défautDefault QsciLexerRubyRChaine de caractères (guillemets doubles)Double-quoted string QsciLexerRuby ErreurError QsciLexerRuby:Nom de méthode ou de fonctionFunction or method name QsciLexerRuby GlobalGlobal QsciLexerRubyIci document Here document QsciLexerRuby4Ici délimiteur de documentHere document delimiter QsciLexerRubyIdentificateur Identifier QsciLexerRubyMot-cléKeyword QsciLexerRubyNom de module Module name QsciLexerRuby NombreNumber QsciLexerRubyOpérateurOperator QsciLexerRubyPODPOD QsciLexerRuby(Expression régulièreRegular expression QsciLexerRubyRChaine de caractères (guillemets simples)Single-quoted string QsciLexerRubySymboleSymbol QsciLexerRubyÿÿÿÿstderr QsciLexerRubyÿÿÿÿstdin QsciLexerRubyÿÿÿÿstdout QsciLexerRuby"# Ligne commentée# comment line QsciLexerSQLCommentaireComment QsciLexerSQLLigne commentée Comment line QsciLexerSQLPar défautDefault QsciLexerSQLRChaine de caractères (guillemets doubles)Double-quoted string QsciLexerSQLIdentificateur Identifier QsciLexerSQLMot-clé JavaDocJavaDoc keyword QsciLexerSQL2Erreur de mot-clé JavaDocJavaDoc keyword error QsciLexerSQL2Commentaire style JavaDocJavaDoc style comment QsciLexerSQLMot-cléKeyword QsciLexerSQL NombreNumber QsciLexerSQLOpérateurOperator QsciLexerSQL(Commentaire SQL*PlusSQL*Plus comment QsciLexerSQL Mot-clé SQL*PlusSQL*Plus keyword QsciLexerSQLPrompt SQL*PlusSQL*Plus prompt QsciLexerSQLRChaine de caractères (guillemets simples)Single-quoted string QsciLexerSQL0Définition utilisateur 1User defined 1 QsciLexerSQL0Définition utilisateur 2User defined 2 QsciLexerSQL0Définition utilisateur 3User defined 3 QsciLexerSQL0Définition utilisateur 4User defined 4 QsciLexerSQLCommandeCommandQsciLexerSpiceCommentaireCommentQsciLexerSpicePar défautDefaultQsciLexerSpiceDélimiteur DelimiterQsciLexerSpiceFonctionFunctionQsciLexerSpiceIdentificateur IdentifierQsciLexerSpice NombreNumberQsciLexerSpiceParamètre ParameterQsciLexerSpice ValeurValueQsciLexerSpiceCommentaireComment QsciLexerTCL*Block de commentaires Comment block QsciLexerTCLLigne commentée Comment line QsciLexerTCLPar défautDefault QsciLexerTCLIdentificateur Identifier QsciLexerTCL NombreNumber QsciLexerTCLOpérateurOperator QsciLexerTCLSubstitution Substitution QsciLexerTCL0Définition utilisateur 1User defined 1 QsciLexerTCL0Définition utilisateur 2User defined 2 QsciLexerTCL0Définition utilisateur 3User defined 3 QsciLexerTCL0Définition utilisateur 4User defined 4 QsciLexerTCLCommandeCommand QsciLexerTeXPar défautDefault QsciLexerTeX GroupeGroup QsciLexerTeXSpécialSpecial QsciLexerTeXSymboleSymbol QsciLexerTeX TexteText QsciLexerTeXAttribut Attribute QsciLexerVHDLCommentaireComment QsciLexerVHDL*Block de commentaires Comment block QsciLexerVHDLLigne commentée Comment line QsciLexerVHDLPar défautDefault QsciLexerVHDLIdentificateur Identifier QsciLexerVHDLMot-cléKeyword QsciLexerVHDL NombreNumber QsciLexerVHDLOpérateurOperator QsciLexerVHDL(Chaîne de caractèresString QsciLexerVHDLBChaine de caractères non referméeUnclosed string QsciLexerVHDL,Définition utilisateur User defined QsciLexerVHDLCommentaireCommentQsciLexerVerilogPar défautDefaultQsciLexerVerilogIdentificateur IdentifierQsciLexerVerilog(Commentaire de ligne Line commentQsciLexerVerilog NombreNumberQsciLexerVerilogOpérateurOperatorQsciLexerVerilogHSeconds mots-clés et identificateurs"Secondary keywords and identifiersQsciLexerVerilog(Chaîne de caractèresStringQsciLexerVerilogBChaine de caractères non referméeUnclosed stringQsciLexerVerilogCommentaireComment QsciLexerYAMLPar défautDefault QsciLexerYAML,Délimiteur de documentDocument delimiter QsciLexerYAMLIdentificateur Identifier QsciLexerYAMLMot-cléKeyword QsciLexerYAML NombreNumber QsciLexerYAMLOpérateurOperator QsciLexerYAMLRéférence Reference QsciLexerYAMLˆsqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_fr.ts000066400000000000000000004504641463772530400272510ustar00rootroot00000000000000 QsciCommand Move down one line Déplacement d'une ligne vers le bas Extend selection down one line Extension de la sélection d'une ligne vers le bas Scroll view down one line Decendre la vue d'une ligne Extend rectangular selection down one line Extension de la sélection rectangulaire d'une ligne vers le bas Move up one line Déplacement d'une ligne vers le haut Extend selection up one line Extension de la sélection d'une ligne vers le haut Scroll view up one line Remonter la vue d'une ligne Extend rectangular selection up one line Extension de la sélection rectangulaire d'une ligne vers le haut Move up one paragraph Déplacement d'un paragraphe vers le haut Extend selection up one paragraph Extension de la sélection d'un paragraphe vers le haut Move down one paragraph Déplacement d'un paragraphe vers le bas Scroll to start of document Remonter au début du document Scroll to end of document Descendre à la fin du document Scroll vertically to centre current line Défiler verticalement pour centrer la ligne courante Extend selection down one paragraph Extension de la sélection d'un paragraphe vers le bas Move left one character Déplacement d'un caractère vers la gauche Extend selection left one character Extension de la sélection d'un caractère vers la gauche Move left one word Déplacement d'un mot vers la gauche Extend selection left one word Extension de la sélection d'un mot vers la gauche Extend rectangular selection left one character Extension de la sélection rectangulaire d'un caractère vers la gauche Move right one character Déplacement d'un caractère vers la droite Extend selection right one character Extension de la sélection d'un caractère vers la droite Move right one word Déplacement d'un mot vers la droite Extend selection right one word Extension de la sélection d'un mot vers la droite Extend rectangular selection right one character Extension de la sélection rectangulaire d'un caractère vers la droite Move to end of previous word Déplacement vers fin du mot précédent Extend selection to end of previous word Extension de la sélection vers fin du mot précédent Move to end of next word Déplacement vers fin du mot suivant Extend selection to end of next word Extension de la sélection vers fin du mot suivant Move left one word part Déplacement d'une part de mot vers la gauche Extend selection left one word part Extension de la sélection d'une part de mot vers la gauche Move right one word part Déplacement d'une part de mot vers la droite Extend selection right one word part Extension de la sélection d'une part de mot vers la droite Move up one page Déplacement d'une page vers le haut Extend selection up one page Extension de la sélection d'une page vers le haut Extend rectangular selection up one page Extension de la sélection rectangulaire d'une page vers le haut Move down one page Déplacement d'une page vers le bas Extend selection down one page Extension de la sélection d'une page vers le bas Extend rectangular selection down one page Extension de la sélection rectangulaire d'une page vers le bas Delete current character Effacement du caractère courant Cut selection Couper la sélection Delete word to right Suppression du mot de droite Move to start of document line Déplacement vers début de ligne du document Extend selection to start of document line Extension de la sélection vers début de ligne du document Extend rectangular selection to start of document line Move to start of display line Extend selection to start of display line Move to start of display or document line Extend selection to start of display or document line Move to first visible character in document line Extend selection to first visible character in document line Extend rectangular selection to first visible character in document line Move to first visible character of display in document line Extend selection to first visible character in display or document line Move to end of document line Extend selection to end of document line Extend rectangular selection to end of document line Move to end of display line Extend selection to end of display line Move to end of display or document line Extend selection to end of display or document line Move to start of document Extend selection to start of document Move to end of document Extend selection to end of document Stuttered move up one page Stuttered extend selection up one page Stuttered move down one page Stuttered extend selection down one page Delete previous character if not at start of line Delete right to end of next word Delete line to right Suppression de la partie droite de la ligne Transpose current and previous lines Duplicate the current line Select all Select document Move selected lines up one line Move selected lines down one line Toggle insert/overtype Basculement Insertion /Ecrasement Paste Coller Copy selection Copier la sélection Insert newline De-indent one level Cancel Annuler Delete previous character Suppression du dernier caractère Delete word to left Suppression du mot de gauche Delete line to left Effacer la partie gauche de la ligne Undo last command Redo last command Refaire la dernière commande Indent one level Indentation d'un niveau Zoom in Zoom avant Zoom out Zoom arrière Formfeed Chargement de la page Cut current line Couper la ligne courante Delete current line Suppression de la ligne courante Copy current line Copier la ligne courante Convert selection to lower case Conversion de la ligne courante en minuscules Convert selection to upper case Conversion de la ligne courante en majuscules Duplicate selection QsciLexerAVS Default Par défaut Block comment Block de commentaires Nested block comment Line comment Commentaire de ligne Number Nombre Operator Opérateur Identifier Identificateur Double-quoted string Chaine de caractères (guillemets doubles) Triple double-quoted string Chaine de caractères HTML (guillemets simples) Keyword Mot-clé Filter Filtre Plugin Extension Function Fonction Clip property User defined Définition utilisateur QsciLexerBash Default Par défaut Error Erreur Comment Commentaire Number Nombre Keyword Mot-clé Double-quoted string Chaine de caractères (guillemets doubles) Single-quoted string Chaine de caractères (guillemets simples) Operator Opérateur Identifier Identificateur Scalar Scalaire Parameter expansion Extension de paramètre Backticks Quotes inverses Here document delimiter Ici délimiteur de document Single-quoted here document Document intégré guillemets simples QsciLexerBatch Default Par défaut Comment Commentaire Keyword Mot-clé Label Titre Hide command character Cacher le caratère de commande External command Commande externe Variable Variable Operator Opérateur QsciLexerCMake Default Par défaut Comment Commentaire String Chaîne de caractères Left quoted string Right quoted string Function Fonction Variable Variable Label Titre User defined Définition utilisateur WHILE block FOREACH block IF block MACRO block Variable within a string Number Nombre QsciLexerCPP Default Par défaut Inactive default C comment Commentaire C Inactive C comment C++ comment Commentaire C++ Inactive C++ comment JavaDoc style C comment Commentaire C de style JavaDoc Inactive JavaDoc style C comment Number Nombre Inactive number Keyword Mot-clé Inactive keyword Double-quoted string Chaine de caractères (guillemets doubles) Inactive double-quoted string Single-quoted string Chaine de caractères (guillemets simples) Inactive single-quoted string IDL UUID Inactive IDL UUID Pre-processor block Instructions de pré-processing Inactive pre-processor block Operator Opérateur Inactive operator Identifier Identificateur Inactive identifier Unclosed string Chaine de caractères non refermée Inactive unclosed string C# verbatim string Inactive C# verbatim string JavaScript regular expression Expression régulière JavaScript Inactive JavaScript regular expression JavaDoc style C++ comment Commentaire C++ de style JavaDoc Inactive JavaDoc style C++ comment Secondary keywords and identifiers Seconds mots-clés et identificateurs Inactive secondary keywords and identifiers JavaDoc keyword Mot-clé JavaDoc Inactive JavaDoc keyword JavaDoc keyword error Erreur de mot-clé JavaDoc Inactive JavaDoc keyword error Global classes and typedefs Classes globales et définitions de types Inactive global classes and typedefs C++ raw string Inactive C++ raw string Vala triple-quoted verbatim string Inactive Vala triple-quoted verbatim string Pike hash-quoted string Inactive Pike hash-quoted string Pre-processor C comment Inactive pre-processor C comment JavaDoc style pre-processor comment Inactive JavaDoc style pre-processor comment User-defined literal Inactive user-defined literal Task marker Inactive task marker Escape sequence Séquence d'échappement Inactive escape sequence QsciLexerCSS Default Par défaut Tag Balise Class selector Classe Pseudo-class Pseudo-classe Unknown pseudo-class Peudo-classe inconnue Operator Opérateur CSS1 property Propriété CSS1 Unknown property Propriété inconnue Value Valeur ID selector ID Important Important @-rule règle-@ Double-quoted string Chaine de caractères (guillemets doubles) Single-quoted string Chaine de caractères (guillemets simples) CSS2 property Propriété CSS2 Attribute Attribut CSS3 property Propriété CSS3 Pseudo-element Extended CSS property Extended pseudo-class Extended pseudo-element Media rule Variable Variable QsciLexerCSharp Verbatim string Chaine verbatim QsciLexerCoffeeScript Default Par défaut C-style comment C++-style comment JavaDoc C-style comment Number Nombre Keyword Mot-clé Double-quoted string Chaine de caractères (guillemets doubles) Single-quoted string Chaine de caractères (guillemets simples) IDL UUID Pre-processor block Instructions de pré-processing Operator Opérateur Identifier Identificateur Unclosed string Chaine de caractères non refermée C# verbatim string Regular expression Expression régulière JavaDoc C++-style comment Secondary keywords and identifiers Seconds mots-clés et identificateurs JavaDoc keyword Mot-clé JavaDoc JavaDoc keyword error Erreur de mot-clé JavaDoc Global classes Block comment Block de commentaires Block regular expression Block regular expression comment Instance property QsciLexerD Default Par défaut Block comment Block de commentaires Line comment Commentaire de ligne DDoc style block comment Nesting comment Number Nombre Keyword Mot-clé Secondary keyword Documentation keyword Type definition String Chaîne de caractères Unclosed string Chaine de caractères non refermée Character Caractère Operator Opérateur Identifier Identificateur DDoc style line comment DDoc keyword Mot-clé DDoc DDoc keyword error Erreur de mot-clé DDoc Backquoted string Raw string User defined 1 Définition utilisateur 1 User defined 2 Définition utilisateur 2 User defined 3 Définition utilisateur 3 QsciLexerDiff Default Par défaut Comment Commentaire Command Commande Header En-tête Position Position Removed line Ligne supprimée Added line Ligne ajoutée Changed line Ligne changée Added adding patch Removed adding patch Added removing patch Removed removing patch QsciLexerEDIFACT Default Par défaut Segment start Segment end Element separator Composite separator Release separator UNA segment header UNH segment header Badly formed segment QsciLexerFortran77 Default Par défaut Comment Commentaire Number Nombre Single-quoted string Chaine de caractères (guillemets simples) Double-quoted string Chaine de caractères (guillemets doubles) Unclosed string Chaine de caractères non refermée Operator Opérateur Identifier Identificateur Keyword Mot-clé Intrinsic function Fonction intrinsèque Extended function Fonction étendue Pre-processor block Instructions de pré-processing Dotted operator Label Titre Continuation QsciLexerHTML HTML default HTML par défaut Tag Balise Unknown tag Balise inconnue Attribute Attribut Unknown attribute Attribut inconnu HTML number Nombre HTML HTML double-quoted string Chaine de caractères HTML (guillemets doubles) HTML single-quoted string Chaine de caractères HTML (guillemets simples) Other text in a tag Autre texte dans les balises HTML comment Commentaire HTML Entity Entité End of a tag Balise fermante Start of an XML fragment Début de block XML End of an XML fragment Fin de block XML Script tag Balise de script Start of an ASP fragment with @ Début de block ASP avec @ Start of an ASP fragment Début de block ASP CDATA CDATA Start of a PHP fragment Début de block PHP Unquoted HTML value Valeur HTML sans guillemets ASP X-Code comment Commentaire X-Code ASP SGML default SGML par défaut SGML command Commande SGML First parameter of an SGML command Premier paramètre de commande SGML SGML double-quoted string Chaine de caractères SGML (guillemets doubles) SGML single-quoted string Chaine de caractères SGML (guillemets simples) SGML error Erreur SGML SGML special entity Entité SGML spéciale SGML comment Commentaire SGML First parameter comment of an SGML command Premier paramètre de commentaire de commande SGML SGML block default Block SGML par défaut Start of a JavaScript fragment Début de block JavaScript JavaScript default JavaScript par défaut JavaScript comment Commentaire JavaScript JavaScript line comment Commentaire de ligne JavaScript JavaDoc style JavaScript comment Commentaire JavaScript de style JavaDoc JavaScript number Nombre JavaScript JavaScript word Mot JavaScript JavaScript keyword Mot-clé JavaScript JavaScript double-quoted string Chaine de caractères JavaScript (guillemets doubles) JavaScript single-quoted string Chaine de caractères JavaScript (guillemets simples) JavaScript symbol Symbole JavaScript JavaScript unclosed string Chaine de caractères JavaScript non refermée JavaScript regular expression Expression régulière JavaScript Start of an ASP JavaScript fragment Début de block JavaScript ASP ASP JavaScript default JavaScript ASP par défaut ASP JavaScript comment Commentaire JavaScript ASP ASP JavaScript line comment Commentaire de ligne JavaScript ASP JavaDoc style ASP JavaScript comment Commentaire JavaScript ASP de style JavaDoc ASP JavaScript number Nombre JavaScript ASP ASP JavaScript word Mot JavaScript ASP ASP JavaScript keyword Mot-clé JavaScript ASP ASP JavaScript double-quoted string Chaine de caractères JavaScript ASP (guillemets doubles) ASP JavaScript single-quoted string Chaine de caractères JavaScript ASP (guillemets simples) ASP JavaScript symbol Symbole JavaScript ASP ASP JavaScript unclosed string Chaine de caractères JavaScript ASP non refermée ASP JavaScript regular expression Expression régulière JavaScript ASP Start of a VBScript fragment Début de block VBScript VBScript default VBScript par défaut VBScript comment Commentaire VBScript VBScript number Nombre VBScript VBScript keyword Mot-clé VBScript VBScript string Chaine de caractères VBScript VBScript identifier Identificateur VBScript VBScript unclosed string Chaine de caractères VBScript non refermée Start of an ASP VBScript fragment Début de block VBScript ASP ASP VBScript default VBScript ASP par défaut ASP VBScript comment Commentaire VBScript ASP ASP VBScript number Nombre VBScript ASP ASP VBScript keyword Mot-clé VBScript ASP ASP VBScript string Chaine de caractères VBScript ASP ASP VBScript identifier Identificateur VBScript ASP ASP VBScript unclosed string Chaine de caractères VBScript ASP non refermée Start of a Python fragment Début de block Python Python default Python par défaut Python comment Commentaire Python Python number Nombre Python Python double-quoted string Chaine de caractères Python (guillemets doubles) Python single-quoted string Chaine de caractères Python (guillemets simples) Python keyword Mot-clé Python Python triple double-quoted string Chaine de caractères Python (triples guillemets doubles) Python triple single-quoted string Chaine de caractères Python (triples guillemets simples) Python class name Nom de classe Python Python function or method name Méthode ou fonction Python Python operator Opérateur Python Python identifier Identificateur Python Start of an ASP Python fragment Début de block Python ASP ASP Python default Python ASP par défaut ASP Python comment Commentaire Python ASP ASP Python number Nombre Python ASP ASP Python double-quoted string Chaine de caractères Python ASP (guillemets doubles) ASP Python single-quoted string Chaine de caractères Python ASP (guillemets simples) ASP Python keyword Mot-clé Python ASP ASP Python triple double-quoted string Chaine de caractères Python ASP (triples guillemets doubles) ASP Python triple single-quoted string Chaine de caractères Python ASP (triples guillemets simples) ASP Python class name Nom de classe Python ASP ASP Python function or method name Méthode ou fonction Python ASP ASP Python operator Opérateur Python ASP ASP Python identifier Identificateur Python ASP PHP default PHP par défaut PHP double-quoted string Chaine de caractères PHP (guillemets doubles) PHP single-quoted string Chaine de caractères PHP (guillemets simples) PHP keyword Mot-clé PHP PHP number Nombre PHP PHP variable Variable PHP PHP comment Commentaire PHP PHP line comment Commentaire de ligne PHP PHP double-quoted variable Variable PHP (guillemets doubles) PHP operator Opérateur PHP QsciLexerIDL UUID UUID QsciLexerJSON Default Par défaut Number Nombre String Chaîne de caractères Unclosed string Chaine de caractères non refermée Property Propriété Escape sequence Séquence d'échappement Line comment Commentaire de ligne Block comment Block de commentaires Operator Opérateur IRI JSON-LD compact IRI JSON keyword Mot-clé JSON JSON-LD keyword Mot-clé JSON-LD Parsing error Erreur d'analyse QsciLexerJavaScript Regular expression Expression régulière QsciLexerLua Default Par défaut Comment Commentaire Line comment Commentaire de ligne Number Nombre Keyword Mot-clé String Chaîne de caractères Character Caractère Literal string Chaîne littérale Preprocessor Préprocessing Operator Opérateur Identifier Identificateur Unclosed string Chaine de caractères non refermée Basic functions Fonctions de base String, table and maths functions Fonctions sur les chaines, tables et fonctions math Coroutines, i/o and system facilities Coroutines, i/o et fonctions système User defined 1 Définition utilisateur 1 User defined 2 Définition utilisateur 2 User defined 3 Définition utilisateur 3 User defined 4 Définition utilisateur 4 Label Titre QsciLexerMakefile Default Par défaut Comment Commentaire Preprocessor Préprocessing Variable Variable Operator Opérateur Target Cible Error Erreur QsciLexerMarkdown Default Par défaut Special Spécial Strong emphasis using double asterisks Strong emphasis using double underscores Emphasis using single asterisks Emphasis using single underscores Level 1 header Level 2 header Level 3 header Level 4 header Level 5 header Level 6 header Pre-char Unordered list item Ordered list item Block quote Strike out Horizontal rule Link Code between backticks Code between double backticks Code block QsciLexerMatlab Default Par défaut Comment Commentaire Command Commande Number Nombre Keyword Mot-clé Single-quoted string Chaine de caractères (guillemets simples) Operator Opérateur Identifier Identificateur Double-quoted string Chaine de caractères (guillemets doubles) QsciLexerPO Default Par défaut Comment Commentaire Message identifier Message identifier text Message string Message string text Message context Message context text Fuzzy flag Programmer comment Reference Référence Flags Message identifier text end-of-line Message string text end-of-line Message context text end-of-line QsciLexerPOV Default Par défaut Comment Commentaire Comment line Ligne commentée Number Nombre Operator Opérateur Identifier Identificateur String Chaîne de caractères Unclosed string Chaine de caractères non refermée Directive Directive Bad directive Mauvaise directive Objects, CSG and appearance Objets, CSG et apparence Types, modifiers and items Types, modifieurs et éléments Predefined identifiers Identifiants prédéfinis Predefined functions Fonctions prédéfinies User defined 1 Définition utilisateur 1 User defined 2 Définition utilisateur 2 User defined 3 Définition utilisateur 3 QsciLexerPascal Default Par défaut Line comment Commentaire de ligne Number Nombre Keyword Mot-clé Single-quoted string Chaine de caractères (guillemets simples) Operator Opérateur Identifier Identificateur '{ ... }' style comment '(* ... *)' style comment '{$ ... }' style pre-processor block '(*$ ... *)' style pre-processor block Hexadecimal number Nombre hexadécimal Unclosed string Chaine de caractères non refermée Character Caractère Inline asm Asm en ligne QsciLexerPerl Default Par défaut Error Erreur Comment Commentaire POD POD Number Nombre Keyword Mot-clé Double-quoted string Chaine de caractères (guillemets doubles) Single-quoted string Chaine de caractères (guillemets simples) Operator Opérateur Identifier Identificateur Scalar Scalaire Array Tableau Hash Hashage Symbol table Table de symboles Regular expression Expression régulière Substitution Substitution Backticks Quotes inverses Data section Section de données Here document delimiter Ici délimiteur de document Single-quoted here document Document intégré guillemets simples Double-quoted here document Document intégré guillemets doubles Backtick here document Document intégré quotes inverses Quoted string (q) Chaine quotée (q) Quoted string (qq) Chaine quotée (qq) Quoted string (qx) Chaine quotée (qx) Quoted string (qr) Chaine quotée (qr) Quoted string (qw) Chaine quotée (qw) POD verbatim POD verbatim Subroutine prototype Format identifier Format body Double-quoted string (interpolated variable) Translation Traduction Regular expression (interpolated variable) Substitution (interpolated variable) Backticks (interpolated variable) Double-quoted here document (interpolated variable) Backtick here document (interpolated variable) Quoted string (qq, interpolated variable) Quoted string (qx, interpolated variable) Quoted string (qr, interpolated variable) QsciLexerPostScript Default Par défaut Comment Commentaire DSC comment Commentaire DSC DSC comment value Number Nombre Name Nom Keyword Mot-clé Literal Immediately evaluated literal Array parenthesis Dictionary parenthesis Procedure parenthesis Text Texte Hexadecimal string Base85 string Bad string character QsciLexerProperties Default Par défaut Comment Commentaire Section Section Assignment Affectation Default value Valeur par défaut Key Clé QsciLexerPython Default Par défaut Comment Commentaire Number Nombre Double-quoted string Chaine de caractères (guillemets doubles) Single-quoted string Chaine de caractères (guillemets simples) Keyword Mot-clé Triple single-quoted string Chaine de caractères HTML (guillemets simples) Triple double-quoted string Chaine de caractères HTML (guillemets simples) Class name Nom de classe Function or method name Nom de méthode ou de fonction Operator Opérateur Identifier Identificateur Comment block Block de commentaires Unclosed string Chaine de caractères non refermée Highlighted identifier Decorator Double-quoted f-string Single-quoted f-string Triple single-quoted f-string Triple double-quoted f-string QsciLexerRuby Default Par défaut Comment Commentaire Number Nombre Double-quoted string Chaine de caractères (guillemets doubles) Single-quoted string Chaine de caractères (guillemets simples) Keyword Mot-clé Class name Nom de classe Function or method name Nom de méthode ou de fonction Operator Opérateur Identifier Identificateur Error Erreur POD POD Regular expression Expression régulière Global Global Symbol Symbole Module name Nom de module Instance variable Class variable Backticks Quotes inverses Data section Section de données Here document delimiter Ici délimiteur de document Here document Ici document %q string %Q string %x string %r string %w string Demoted keyword stdin stdout stderr QsciLexerSQL Default Par défaut Comment Commentaire Number Nombre Keyword Mot-clé Single-quoted string Chaine de caractères (guillemets simples) Operator Opérateur Identifier Identificateur Comment line Ligne commentée JavaDoc style comment Commentaire style JavaDoc Double-quoted string Chaine de caractères (guillemets doubles) SQL*Plus keyword Mot-clé SQL*Plus SQL*Plus prompt Prompt SQL*Plus SQL*Plus comment Commentaire SQL*Plus # comment line # Ligne commentée JavaDoc keyword Mot-clé JavaDoc JavaDoc keyword error Erreur de mot-clé JavaDoc User defined 1 Définition utilisateur 1 User defined 2 Définition utilisateur 2 User defined 3 Définition utilisateur 3 User defined 4 Définition utilisateur 4 Quoted identifier Quoted operator QsciLexerSpice Default Par défaut Identifier Identificateur Command Commande Function Fonction Parameter Paramètre Number Nombre Delimiter Délimiteur Value Valeur Comment Commentaire QsciLexerTCL Default Par défaut Comment Commentaire Comment line Ligne commentée Number Nombre Quoted keyword Quoted string Operator Opérateur Identifier Identificateur Substitution Substitution Brace substitution Modifier Expand keyword TCL keyword Tk keyword iTCL keyword Tk command User defined 1 Définition utilisateur 1 User defined 2 Définition utilisateur 2 User defined 3 Définition utilisateur 3 User defined 4 Définition utilisateur 4 Comment box Comment block Block de commentaires QsciLexerTeX Default Par défaut Special Spécial Group Groupe Symbol Symbole Command Commande Text Texte QsciLexerVHDL Default Par défaut Comment Commentaire Comment line Ligne commentée Number Nombre String Chaîne de caractères Operator Opérateur Identifier Identificateur Unclosed string Chaine de caractères non refermée Keyword Mot-clé Standard operator Attribute Attribut Standard function Standard package Standard type User defined Définition utilisateur Comment block Block de commentaires QsciLexerVerilog Default Par défaut Inactive default Comment Commentaire Inactive comment Line comment Commentaire de ligne Inactive line comment Bang comment Inactive bang comment Number Nombre Inactive number Primary keywords and identifiers Inactive primary keywords and identifiers String Chaîne de caractères Inactive string Secondary keywords and identifiers Seconds mots-clés et identificateurs Inactive secondary keywords and identifiers System task Inactive system task Preprocessor block Inactive preprocessor block Operator Opérateur Inactive operator Identifier Identificateur Inactive identifier Unclosed string Chaine de caractères non refermée Inactive unclosed string User defined tasks and identifiers Inactive user defined tasks and identifiers Keyword comment Inactive keyword comment Input port declaration Inactive input port declaration Output port declaration Inactive output port declaration Input/output port declaration Inactive input/output port declaration Port connection Inactive port connection QsciLexerYAML Default Par défaut Comment Commentaire Identifier Identificateur Keyword Mot-clé Number Nombre Reference Référence Document delimiter Délimiteur de document Text block marker Syntax error marker Operator Opérateur QsciScintilla &Undo &Redo Cu&t &Copy &Paste Delete Select All sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_pt_br.qm000066400000000000000000001404631463772530400277320ustar00rootroot00000000000000<¸dÊÍ!¿`¡½ÝBPU4‹ëU4œºZw/Zwlb蘊©Ôpy¬ô’ƒ¬ôª)[Än9V;G†OÍH˜‰†åL™bL™by»L™b‰ÖN–À©ðRx¼!ñRx¼#Rx¼>'Rx¼tÍVŠ¥‡\ƒµ0\ƒµ¦,^ th¸oº´O4sàçg‰{A4£³ÒWÉ¥Ò÷Dð¶Ú´TïÇô ÙÌÛ…~²äoòväoòz,óeâo3&„eöž›{‚Õ{òéÃtaO›%ÔΤô\¯Ám…6Ám…žªÐæÔ*ÐæÔÐæÔ!­ÐæÔ(FÐæÔ3ÐæÔ7áÐæÔ=ßÐæÔt‹ÐæÔ|õÐæÔ„×ÐæÔ‹:ÐæÔ’ÐæÔ–eÐæÔœ ÐæÔ¡AÐæÔ¬ÐæÔ±àŽ‰+Ãàž‰,àþ‰+uâø³%Uå@U6å±å¹ ªÅEûNhøh2¬¢_×_ÍÓ9U)ÓpÅÓu¶OåT7 ’6û<9tâW³”PîÑU<…$M`…®]žŒ„´òÁoµžÏ¥Ûñ?’`ôøÅòç—RÈ4œ%+[¥åž[îu8fŠÓ/±l&÷]ä˜I¼ÁÓ~‘Ű¹P¶Õ 4dl×ë¤mÄëzÂ;‹ßgÙ½4S½rT½5½œå ò÷Y£vx ™6îê6î§ÕctHÆ Tä@Ê$<ÄUÝ,_—G @ÙA9‹@ÙAwÕ@ÙAƒ@ÙA£˜@ÙA¨@ÙB9ä@ÙBx0@ÙBƒc@ÙB£ó@ÙB¨u@ÙC:=@ÙCx‹@ÙCƒ¾@ÙC¤N@ÙC¨Ð@ÙDxæ@ÙD¤©@ÙD©+Aã.@[“ô6¦\8µ\8ÂI\8Â#C\8Â(ˆ\8Â3Z\8Â8h\8Â>_\8Âq%\8Âu¯\8Â}:\8€2\8Â…h\8‹}\8Â’I\8–ª\8œL\8¡ƒ\8Â¥÷\8§i\8¬I\8®†\8±[ró)fró4±ró®úvBŒr™‚‚™‚‚‹¨Äzz«5å«5À«5%Ù«51ß«57ž«5=”«5tF«5|­«5í«5„«5Šô«5–«5›Ã«5ŸÄ«5¥°«5§$«5«À«5­ð«5°Ò«G#x«G8ЫGq“«Gvd«GÖ«G¬·«G¯™°9\Ѱ9\ªXñŽÔTS*ÄÃg?^tQ¢_pÔÜ}Ú(ô}Ú3Ø}Ú>דÏd”œ('lô «.;Ŷ•§K]½ÇbêÈèÈ}È"%È(»È.È3–È8™È>˜ÈqYÈuâÈyîÈ}pÈ€ÑÈ…žÈ‹±È–àÈœ€È¡¶È§œÈ¬}È®½È±ѽ8Ô‡„ éàæ§fƒ—uH§• î ©"Sk)6%ü)µN6|Ô¡ï_uâ]^d*‹d*iŒýd*ÉŽd*ùާiø-ÉÜŒ¤UÝÀ©g(àä„@`™äiš _¤L&åµ\%*X•3g”{j½‚ 2|Ö^7€ÓN%‡ã"6l‡ã"rþ‡ã"„ŠlT e~å"`~å#É~å0J~åz´•²´Be¦2c °œ2ntºûųèóäkì‰CÊö2Lóù¦”C ~Õê &0'! &0'—´ ?3äkü @|UmK o” kƒ @t¢¯ ¨Ÿ×Nœ ¬÷÷oí ¯²!: ±^÷b? ´×R ´×‚ ´×$ ´×,ð ´×1C ´×<û ´×| ´׉B ´ו ´×𠨬ן1 º°“Ê ÉX$‡ Ûí=Œ iä ® ïÔ_{ ê4Zó 'ç4$F *²SÅ *²S‡ª *²S™w Iq>· Sæµ” S浙 d8:â d8{h d8¥ d8©† d< d< u d<"› d<; d<< d<s: d<yA d<{¡ d<~D d<~ú d<‡õ d<‘‚ d<’ÿ d<”M d<š d<žn d<¥< d<¦^ d<ª÷ d<­x d<°` d4$ kŸ,{+ kŸ,ª qe’MÊ •ø$WT œµdˆ± ¡úR,k °ÖBI ¼Œt ¼ŒtM ¼Œt ³ ¼Œt"Ù ¼Œt$Ž ¼Œt,¼ ¼Œt1 ¼Œt7l ¼Œt;V ¼ŒtÖað WöÜD fÎò-ƒ oÂI oŠ3 §'Oþ ÁÅ“} Ðæ·S® ñ'\ ÷ïÄL+ û'×[… þxŽCG  .ˆ2  .šG ¦El— 943sv @&4e @*$dÊ _ár° t}4l t}48! t}4pÛ t}4tÿ t}4… t}4®9 ‚‰Ô&î Œ?DEŽ Ig*– Ig5ó Ig9 Ig?ê Igqã Igwe Ig‚˜ Ig†r Ig™ Ig­ Ig¯ì «ãt& «ãt2- «ãt  Â`å^† ×.„jœ ñyH_ÓWo‚ còk é/P'»Ò 9 …GÕ=¤e`vV‰ÇcªW´\YL]‹gJ‘e–TR|hw„VðiårfEldAõwæge¢{ÔF›&4R0£ÇߣÇ*£Ç.‡£Ç5U£Ç?O£Ç}¬£Ç…Ú£ÇT£Ç—£Ç;£Ç££õBB楿´Fd­)w˜[Ʀ¢LÇnCÐL„ ÏÓkC‚%ëj…;ýþ2'Ðþ2X@’I*#}w0ƒ4+4¸RÎ’a§‰2\þ)t¦µnE”À–TeVÄÔ_á²Ä’¹i±ÉCancelarCancel QsciCommandDConverter a seleção para minúsculaConvert selection to lower case QsciCommandDConverter a seleção para maiúsculaConvert selection to upper case QsciCommand$Copiar linha atualCopy current line QsciCommandCopiar seleçãoCopy selection QsciCommand,Configurar linha atualCut current line QsciCommand Recortar seleção Cut selection QsciCommand.Excluir caractere atualDelete current character QsciCommand&Excluir linha atualDelete current line QsciCommand0Excluir linha a esquerdaDelete line to left QsciCommand4Excluir linha para direitaDelete line to right QsciCommand4Excluir caractere anteriorDelete previous character QsciCommand4Excluir palavra a esquerdaDelete word to left QsciCommand8Excluir palavra para direitaDelete word to right QsciCommanddExtender a seleção retangular uma linha para baixo*Extend rectangular selection down one line QsciCommandfExtender a seleção retangular uma página para baixo*Extend rectangular selection down one page QsciCommandpExtender a seleção retangular um caractere para esquerda/Extend rectangular selection left one character QsciCommandnExtender a seleção retangular um caractere para direita0Extend rectangular selection right one character QsciCommandbExtender a seleção retangular uma linha para cima(Extend rectangular selection up one line QsciCommanddExtender a seleção retangular uma página para cima(Extend rectangular selection up one page QsciCommandNExtender a seleção uma linha para baixoExtend selection down one line QsciCommandPExtender a seleção uma página para baixoExtend selection down one page QsciCommandVExtender a seleção um paragrafo para baixo#Extend selection down one paragraph QsciCommandZExtender a seleção um caractere para esquerda#Extend selection left one character QsciCommandXExtender a seleção uma palavra para esquerdaExtend selection left one word QsciCommandjExtender a seleção uma parte de palavra para esquerda#Extend selection left one word part QsciCommandXExtender a seleção um caractere para direita$Extend selection right one character QsciCommandVExtender a seleção uma palavra para direitaExtend selection right one word QsciCommandhExtender a seleção uma parte de palavra para direita$Extend selection right one word part QsciCommandLExtender a seleção uma linha para cimaExtend selection up one line QsciCommandNExtender a seleção uma página para cimaExtend selection up one page QsciCommandRExtender a seleção um paragrafo para cima!Extend selection up one paragraph QsciCommand*Alimentação da PáginaFormfeed QsciCommand"Indentar um nívelIndent one level QsciCommand4Mover uma linha para baixoMove down one line QsciCommand6Mover uma página para baixoMove down one page QsciCommand:Mover um paragrafo para baixoMove down one paragraph QsciCommandDMover um caractere para a esquerdaMove left one character QsciCommand>Mover uma palavra para esquerdaMove left one word QsciCommandPMover uma parte da palavra para esquerdaMove left one word part QsciCommand>Mover um caractere para direitaMove right one character QsciCommand<Mover uma palavra para direitaMove right one word QsciCommandNMover uma parte da palavra para direitaMove right one word part QsciCommand2Mover uma linha para cimaMove up one line QsciCommand4Mover uma página para cimaMove up one page QsciCommand8Mover um paragrafo para cimaMove up one paragraph QsciCommand CopiarPaste QsciCommand,Refazer último comandoRedo last command QsciCommandFDescer a visão uma linha para baixoScroll view down one line QsciCommandBSubir a visão uma linha para cimaScroll view up one line QsciCommandXAlternar entre modo de inserir/sobreescreverToggle insert/overtype QsciCommandAumentar zoomZoom in QsciCommandDiminuir zoomZoom out QsciCommand PadrãoDefault QsciLexerAVS^Cadeia de caracteres envolvida por aspas duplasDouble-quoted string QsciLexerAVSIdentificador Identifier QsciLexerAVSPalavra ChaveKeyword QsciLexerAVSComentar Linha Line comment QsciLexerAVS NúmeroNumber QsciLexerAVSOperadorOperator QsciLexerAVShCadeia de caracteres envolvida por três aspas duplasTriple double-quoted string QsciLexerAVS Aspas Invertidas Backticks QsciLexerBashComentárioComment QsciLexerBash PadrãoDefault QsciLexerBash^Cadeia de caracteres envolvida por aspas duplasDouble-quoted string QsciLexerBash NúmeroError QsciLexerBash>Delimitador de "here documents"Here document delimiter QsciLexerBashIdentificador Identifier QsciLexerBashPalavra ChaveKeyword QsciLexerBash NúmeroNumber QsciLexerBashOperadorOperator QsciLexerBash*Parâmetro de ExpansãoParameter expansion QsciLexerBashEscalarScalar QsciLexerBashV"here document" envolvido por aspas simplesSingle-quoted here document QsciLexerBash`Cadeia de caracteres envolvida por aspas simplesSingle-quoted string QsciLexerBashComentárioCommentQsciLexerBatch PadrãoDefaultQsciLexerBatchComando externoExternal commandQsciLexerBatch:Esconder caractere de comandoHide command characterQsciLexerBatchPalavra ChaveKeywordQsciLexerBatch RótuloLabelQsciLexerBatchOperadorOperatorQsciLexerBatchVariávelVariableQsciLexerBatchComentárioCommentQsciLexerCMake PadrãoDefaultQsciLexerCMake RótuloLabelQsciLexerCMake NúmeroNumberQsciLexerCMake(Cadeia de CaracteresStringQsciLexerCMakeVariávelVariableQsciLexerCMakeComentário C C comment QsciLexerCPPComentário C++ C++ comment QsciLexerCPP PadrãoDefault QsciLexerCPP^Cadeia de caracteres envolvida por aspas duplasDouble-quoted string QsciLexerCPPHClasses e definições de tipo globaisGlobal classes and typedefs QsciLexerCPPIdentificador Identifier QsciLexerCPP*Palavra chave JavaDocJavaDoc keyword QsciLexerCPP@Erro de palavra chave do JavaDocJavaDoc keyword error QsciLexerCPP6Comentário JavaDoc estilo CJavaDoc style C comment QsciLexerCPP:Comentário JavaDoc estilo C++JavaDoc style C++ comment QsciLexerCPP8Expressão regular JavaScriptJavaScript regular expression QsciLexerCPPPalavra ChaveKeyword QsciLexerCPP NúmeroNumber QsciLexerCPPOperadorOperator QsciLexerCPP>Instruções de pré-processamentoPre-processor block QsciLexerCPPXIdentificadores e palavras chave secundárias"Secondary keywords and identifiers QsciLexerCPP`Cadeia de caracteres envolvida por aspas simplesSingle-quoted string QsciLexerCPP@Cadeia de caracteres não fechadaUnclosed string QsciLexerCPPregra-@@-rule QsciLexerCSSAtributo Attribute QsciLexerCSS Propriedade CSS1 CSS1 property QsciLexerCSS Propriedade CSS2 CSS2 property QsciLexerCSS,Propriedade CSS2 {3 ?} CSS3 property QsciLexerCSS"Seletor de classeClass selector QsciLexerCSS PadrãoDefault QsciLexerCSS^Cadeia de caracteres envolvida por aspas duplasDouble-quoted string QsciLexerCSSSeletor de ID ID selector QsciLexerCSSImportante Important QsciLexerCSSOperadorOperator QsciLexerCSSPseudo-classe Pseudo-class QsciLexerCSS`Cadeia de caracteres envolvida por aspas simplesSingle-quoted string QsciLexerCSSMarcadorTag QsciLexerCSS0Propriedade desconhecidaUnknown property QsciLexerCSS4Pseudo-classe desconhecidaUnknown pseudo-class QsciLexerCSS ValorValue QsciLexerCSSVariávelVariable QsciLexerCSSPCadeia de caracteres no formato verbatimVerbatim stringQsciLexerCSharp PadrãoDefaultQsciLexerCoffeeScript^Cadeia de caracteres envolvida por aspas duplasDouble-quoted stringQsciLexerCoffeeScriptIdentificador IdentifierQsciLexerCoffeeScript*Palavra chave JavaDocJavaDoc keywordQsciLexerCoffeeScript@Erro de palavra chave do JavaDocJavaDoc keyword errorQsciLexerCoffeeScriptPalavra ChaveKeywordQsciLexerCoffeeScript NúmeroNumberQsciLexerCoffeeScriptOperadorOperatorQsciLexerCoffeeScript>Instruções de pré-processamentoPre-processor blockQsciLexerCoffeeScript"Expressão RegularRegular expressionQsciLexerCoffeeScriptXIdentificadores e palavras chave secundárias"Secondary keywords and identifiersQsciLexerCoffeeScript`Cadeia de caracteres envolvida por aspas simplesSingle-quoted stringQsciLexerCoffeeScript@Cadeia de caracteres não fechadaUnclosed stringQsciLexerCoffeeScriptCaractere Character QsciLexerD*Palavra chave JavaDoc DDoc keyword QsciLexerD@Erro de palavra chave do JavaDocDDoc keyword error QsciLexerD PadrãoDefault QsciLexerDIdentificador Identifier QsciLexerDPalavra ChaveKeyword QsciLexerDComentar Linha Line comment QsciLexerD NúmeroNumber QsciLexerDOperadorOperator QsciLexerD(Cadeia de CaracteresString QsciLexerD@Cadeia de caracteres não fechadaUnclosed string QsciLexerD,Definição de usuário 1User defined 1 QsciLexerD,Definição de usuário 2User defined 2 QsciLexerD,Definição de usuário 3User defined 3 QsciLexerD Linha Adicionada Added line QsciLexerDiffComandoCommand QsciLexerDiffComentárioComment QsciLexerDiff PadrãoDefault QsciLexerDiffCabeçalhoHeader QsciLexerDiffPosiçãoPosition QsciLexerDiffLinha Removida Removed line QsciLexerDiff PadrãoDefaultQsciLexerEDIFACTComentárioCommentQsciLexerFortran77 PadrãoDefaultQsciLexerFortran77^Cadeia de caracteres envolvida por aspas duplasDouble-quoted stringQsciLexerFortran77Identificador IdentifierQsciLexerFortran77Palavra ChaveKeywordQsciLexerFortran77 RótuloLabelQsciLexerFortran77 NúmeroNumberQsciLexerFortran77OperadorOperatorQsciLexerFortran77>Instruções de pré-processamentoPre-processor blockQsciLexerFortran77`Cadeia de caracteres envolvida por aspas simplesSingle-quoted stringQsciLexerFortran77@Cadeia de caracteres não fechadaUnclosed stringQsciLexerFortran772Comentário JavaScript ASPASP JavaScript comment QsciLexerHTML2JavaScript ASP por padrãoASP JavaScript default QsciLexerHTML|Cadeia de caracteres JavaScript ASP envolvida por aspas duplas#ASP JavaScript double-quoted string QsciLexerHTML8Palavra chave JavaScript ASPASP JavaScript keyword QsciLexerHTMLDComentário de linha JavaScript ASPASP JavaScript line comment QsciLexerHTML*Número JavaScript ASPASP JavaScript number QsciLexerHTML@Expressão regular JavaScript ASP!ASP JavaScript regular expression QsciLexerHTML~Cadeia de caracteres JavaScript ASP envolvida por aspas simples#ASP JavaScript single-quoted string QsciLexerHTML,Símbolo JavaScript ASPASP JavaScript symbol QsciLexerHTML^Cadeia de caracteres JavaScript ASP não fechadaASP JavaScript unclosed string QsciLexerHTML8Palavra chave JavaScript ASPASP JavaScript word QsciLexerHTML2Nome de classe Python ASPASP Python class name QsciLexerHTML*Comentário Python ASPASP Python comment QsciLexerHTML*Python ASP por padrãoASP Python default QsciLexerHTMLtCadeia de caracteres Python ASP envolvida por aspas duplasASP Python double-quoted string QsciLexerHTMLFNome de método ou função Python ASP"ASP Python function or method name QsciLexerHTML0Identificador Python ASPASP Python identifier QsciLexerHTML0Palavra chave Python ASPASP Python keyword QsciLexerHTML"Número Python ASPASP Python number QsciLexerHTML&Operador Python ASPASP Python operator QsciLexerHTMLvCadeia de caracteres Python ASP envolvida por aspas simplesASP Python single-quoted string QsciLexerHTML„Cadeia de caracteres Python ASP envolvida por aspas triplas duplas&ASP Python triple double-quoted string QsciLexerHTML†Cadeia de caracteres Python ASP envolvida por aspas triplas simples&ASP Python triple single-quoted string QsciLexerHTML.Comentário VBScript ASPASP VBScript comment QsciLexerHTML.VBScript ASP por padrãoASP VBScript default QsciLexerHTML4Identificador VBScript ASPASP VBScript identifier QsciLexerHTML4Palavra chave VBScript ASPASP VBScript keyword QsciLexerHTML&Número VBScript ASPASP VBScript number QsciLexerHTMLBCadeia de caracteres VBScript ASPASP VBScript string QsciLexerHTMLZCadeia de caracteres VBScript ASP não fechadaASP VBScript unclosed string QsciLexerHTML*Comentário ASP X-CodeASP X-Code comment QsciLexerHTMLAtributo Attribute QsciLexerHTML CDATACDATA QsciLexerHTML(Final de um marcador End of a tag QsciLexerHTML*Final de um bloco XMLEnd of an XML fragment QsciLexerHTMLEntidadeEntity QsciLexerHTMLhPrimeiro comentário de parâmetro de uma comando SGML*First parameter comment of an SGML command QsciLexerHTMLJPrimeiro parâmetro em um comando SGML"First parameter of an SGML command QsciLexerHTMLComentário HTML HTML comment QsciLexerHTMLHTML por padrão HTML default QsciLexerHTMLhCadeia de caracteres HTML envolvida por aspas duplasHTML double-quoted string QsciLexerHTMLNúmero HTML HTML number QsciLexerHTMLjCadeia de caracteres HTML envolvida por aspas simplesHTML single-quoted string QsciLexerHTMLVComentário JavaScript ASP no estilo JavaDoc$JavaDoc style ASP JavaScript comment QsciLexerHTMLNComentário JavaScript no estilo JavaDoc JavaDoc style JavaScript comment QsciLexerHTML*Comentário JavaScriptJavaScript comment QsciLexerHTML*JavaScript por padrãoJavaScript default QsciLexerHTMLtCadeia de caracteres JavaScript envolvida por aspas duplasJavaScript double-quoted string QsciLexerHTML0Palavra chave JavaScriptJavaScript keyword QsciLexerHTML<Comentário de linha JavaScriptJavaScript line comment QsciLexerHTML"Número JavaScriptJavaScript number QsciLexerHTML8Expressão regular JavaScriptJavaScript regular expression QsciLexerHTMLvCadeia de caracteres JavaScript envolvida por aspas simplesJavaScript single-quoted string QsciLexerHTML$Símbolo JavaScriptJavaScript symbol QsciLexerHTMLVCadeia de caracteres JavaScript não fechadaJavaScript unclosed string QsciLexerHTML$Palavra JavaScriptJavaScript word QsciLexerHTML4Outro texto em um marcadorOther text in a tag QsciLexerHTMLComentário PHP PHP comment QsciLexerHTMLPHP por padrão PHP default QsciLexerHTMLfCadeia de caracteres PHP envolvida por aspas duplasPHP double-quoted string QsciLexerHTMLNVariável PHP envolvida por aspas duplasPHP double-quoted variable QsciLexerHTML"Palavra chave PHP PHP keyword QsciLexerHTML.Comentário de linha PHPPHP line comment QsciLexerHTMLNúmero PHP PHP number QsciLexerHTMLOperador PHP PHP operator QsciLexerHTMLhCadeia de caracteres PHP envolvida por aspas simplesPHP single-quoted string QsciLexerHTMLVariável PHP PHP variable QsciLexerHTML*Nome de classe PythonPython class name QsciLexerHTML"Comentário PythonPython comment QsciLexerHTML"Python por padrãoPython default QsciLexerHTMLlCadeia de caracteres Python envolvida por aspas duplasPython double-quoted string QsciLexerHTML>Nome de método ou função PythonPython function or method name QsciLexerHTML(Identificador PythonPython identifier QsciLexerHTML(Palavra chave PythonPython keyword QsciLexerHTMLNúmero Python Python number QsciLexerHTMLOperador PythonPython operator QsciLexerHTMLnCadeia de caracteres Python envolvida por aspas simplesPython single-quoted string QsciLexerHTML|Cadeia de caracteres Python envolvida por aspas triplas duplas"Python triple double-quoted string QsciLexerHTML~Cadeia de caracteres Python envolvida por aspas triplas simples"Python triple single-quoted string QsciLexerHTML*Bloco SGML por padrãoSGML block default QsciLexerHTMLComando SGML SGML command QsciLexerHTMLComando SGML SGML comment QsciLexerHTMLSGML por padrão SGML default QsciLexerHTMLhCadeia de caracteres SGML envolvida por aspas duplasSGML double-quoted string QsciLexerHTMLErro SGML SGML error QsciLexerHTMLjCadeia de caracteres SGML envolvida por aspas simplesSGML single-quoted string QsciLexerHTML,Entidade especial SGMLSGML special entity QsciLexerHTML$Marcador de script Script tag QsciLexerHTML:Início de um bloco JavascriptStart of a JavaScript fragment QsciLexerHTML,Início de um bloco PHPStart of a PHP fragment QsciLexerHTML2Início de um bloco PythonStart of a Python fragment QsciLexerHTML6Início de um bloco VBScriptStart of a VBScript fragment QsciLexerHTMLBInício de um bloco Javascript ASP#Start of an ASP JavaScript fragment QsciLexerHTML:Início de um bloco Python ASPStart of an ASP Python fragment QsciLexerHTML>Início de um bloco VBScript ASP!Start of an ASP VBScript fragment QsciLexerHTML,Início de um bloco ASPStart of an ASP fragment QsciLexerHTML8Início de um bloco ASP com @Start of an ASP fragment with @ QsciLexerHTML,Início de um bloco XMLStart of an XML fragment QsciLexerHTMLMarcadorTag QsciLexerHTML*Atributo desconhecidoUnknown attribute QsciLexerHTML*Marcador desconhecido Unknown tag QsciLexerHTMLDValor HTML não envolvido por aspasUnquoted HTML value QsciLexerHTML&Comentário VBScriptVBScript comment QsciLexerHTML&VBScript por padrãoVBScript default QsciLexerHTML,Identificador VBScriptVBScript identifier QsciLexerHTML,Palavra chave VBScriptVBScript keyword QsciLexerHTMLNúmero VBScriptVBScript number QsciLexerHTML:Cadeia de caracteres VBScriptVBScript string QsciLexerHTMLRCadeia de caracteres VBScript não fechadaVBScript unclosed string QsciLexerHTMLUUIDUUID QsciLexerIDL PadrãoDefault QsciLexerJSONComentar Linha Line comment QsciLexerJSON NúmeroNumber QsciLexerJSONOperadorOperator QsciLexerJSON(Cadeia de CaracteresString QsciLexerJSON@Cadeia de caracteres não fechadaUnclosed string QsciLexerJSON"Expressão RegularRegular expressionQsciLexerJavaScriptFunções básicasBasic functions QsciLexerLuaCaractere Character QsciLexerLuaComentárioComment QsciLexerLuaVFunções auxiiares, e/s e funções de sistema%Coroutines, i/o and system facilities QsciLexerLua PadrãoDefault QsciLexerLuaIdentificador Identifier QsciLexerLuaPalavra ChaveKeyword QsciLexerLua RótuloLabel QsciLexerLuaComentar Linha Line comment QsciLexerLua8Cadeia de caracteres literalLiteral string QsciLexerLua NúmeroNumber QsciLexerLuaOperadorOperator QsciLexerLuaPreprocessador Preprocessor QsciLexerLua(Cadeia de CaracteresString QsciLexerLuapFunções de cadeia de caracteres e de tabelas matemáticas!String, table and maths functions QsciLexerLua@Cadeia de caracteres não fechadaUnclosed string QsciLexerLua,Definição de usuário 1User defined 1 QsciLexerLua,Definição de usuário 2User defined 2 QsciLexerLua,Definição de usuário 3User defined 3 QsciLexerLua,Definição de usuário 4User defined 4 QsciLexerLuaComentárioCommentQsciLexerMakefile PadrãoDefaultQsciLexerMakefileErroErrorQsciLexerMakefileOperadorOperatorQsciLexerMakefilePreprocessador PreprocessorQsciLexerMakefileDestinoTargetQsciLexerMakefileVariávelVariableQsciLexerMakefile PadrãoDefaultQsciLexerMarkdownEspecialSpecialQsciLexerMarkdownComandoCommandQsciLexerMatlabComentárioCommentQsciLexerMatlab PadrãoDefaultQsciLexerMatlab^Cadeia de caracteres envolvida por aspas duplasDouble-quoted stringQsciLexerMatlabIdentificador IdentifierQsciLexerMatlabPalavra ChaveKeywordQsciLexerMatlab NúmeroNumberQsciLexerMatlabOperadorOperatorQsciLexerMatlab`Cadeia de caracteres envolvida por aspas simplesSingle-quoted stringQsciLexerMatlabComentárioComment QsciLexerPO PadrãoDefault QsciLexerPODiretiva ruim Bad directive QsciLexerPOVComentárioComment QsciLexerPOVComentar Linha Comment line QsciLexerPOV PadrãoDefault QsciLexerPOVDiretiva Directive QsciLexerPOVIdentificador Identifier QsciLexerPOV NúmeroNumber QsciLexerPOV0Objetos, CSG e aparênciaObjects, CSG and appearance QsciLexerPOVOperadorOperator QsciLexerPOV(Funções predefinidasPredefined functions QsciLexerPOV8Identificadores predefinidosPredefined identifiers QsciLexerPOV(Cadeia de CaracteresString QsciLexerPOV8Tipos, modificadores e itensTypes, modifiers and items QsciLexerPOV@Cadeia de caracteres não fechadaUnclosed string QsciLexerPOV,Definição de usuário 1User defined 1 QsciLexerPOV,Definição de usuário 2User defined 2 QsciLexerPOV,Definição de usuário 3User defined 3 QsciLexerPOVCaractere CharacterQsciLexerPascal PadrãoDefaultQsciLexerPascalIdentificador IdentifierQsciLexerPascalPalavra ChaveKeywordQsciLexerPascalComentar Linha Line commentQsciLexerPascal NúmeroNumberQsciLexerPascalOperadorOperatorQsciLexerPascal`Cadeia de caracteres envolvida por aspas simplesSingle-quoted stringQsciLexerPascal@Cadeia de caracteres não fechadaUnclosed stringQsciLexerPascal VetorArray QsciLexerPerl\"here document" envolvido por aspas invertidasBacktick here document QsciLexerPerl Aspas Invertidas Backticks QsciLexerPerlComentárioComment QsciLexerPerlSeção de dados Data section QsciLexerPerl PadrãoDefault QsciLexerPerlT"here document" envolvido por aspas duplasDouble-quoted here document QsciLexerPerl^Cadeia de caracteres envolvida por aspas duplasDouble-quoted string QsciLexerPerlErroError QsciLexerPerlHashHash QsciLexerPerlˆDelimitador de documentos criados através de redicionadores (>> e >)Here document delimiter QsciLexerPerlIdentificador Identifier QsciLexerPerlPalavra ChaveKeyword QsciLexerPerl NúmeroNumber QsciLexerPerlOperadorOperator QsciLexerPerlPODPOD QsciLexerPerl.POD em formato verbatim POD verbatim QsciLexerPerlXCadeia de caracteres envolvida por aspas (q)Quoted string (q) QsciLexerPerlZCadeia de caracteres envolvida por aspas (qq)Quoted string (qq) QsciLexerPerlZCadeia de caracteres envolvida por aspas (qr)Quoted string (qr) QsciLexerPerlZCadeia de caracteres envolvida por aspas (qw)Quoted string (qw) QsciLexerPerlZCadeia de caracteres envolvida por aspas (qx)Quoted string (qx) QsciLexerPerl"Expressão RegularRegular expression QsciLexerPerlEscalarScalar QsciLexerPerlV"here document" envolvido por aspas simplesSingle-quoted here document QsciLexerPerl`Cadeia de caracteres envolvida por aspas simplesSingle-quoted string QsciLexerPerlSubstituição Substitution QsciLexerPerl$Tabela de Símbolos Symbol table QsciLexerPerlComentárioCommentQsciLexerPostScript PadrãoDefaultQsciLexerPostScriptPalavra ChaveKeywordQsciLexerPostScript NúmeroNumberQsciLexerPostScript TextoTextQsciLexerPostScriptAtribuição AssignmentQsciLexerPropertiesComentárioCommentQsciLexerProperties PadrãoDefaultQsciLexerPropertiesValor Padrão Default valueQsciLexerProperties SeçãoSectionQsciLexerPropertiesNome da classe Class nameQsciLexerPythonComentárioCommentQsciLexerPython(Bloco de comentários Comment blockQsciLexerPython PadrãoDefaultQsciLexerPython^Cadeia de caracteres envolvida por aspas duplasDouble-quoted stringQsciLexerPython0Nome da função ou métodoFunction or method nameQsciLexerPythonIdentificador IdentifierQsciLexerPythonPalavra ChaveKeywordQsciLexerPython NúmeroNumberQsciLexerPythonOperadorOperatorQsciLexerPython`Cadeia de caracteres envolvida por aspas simplesSingle-quoted stringQsciLexerPythonhCadeia de caracteres envolvida por três aspas duplasTriple double-quoted stringQsciLexerPythonjCadeia de caracteres envolvida por três aspas simplesTriple single-quoted stringQsciLexerPython@Cadeia de caracteres não fechadaUnclosed stringQsciLexerPython Aspas Invertidas Backticks QsciLexerRubyNome da classe Class name QsciLexerRubyComentárioComment QsciLexerRubySeção de dados Data section QsciLexerRuby PadrãoDefault QsciLexerRuby^Cadeia de caracteres envolvida por aspas duplasDouble-quoted string QsciLexerRuby0Nome da função ou métodoFunction or method name QsciLexerRubyIdentificador Identifier QsciLexerRubyPalavra ChaveKeyword QsciLexerRuby NúmeroNumber QsciLexerRubyOperadorOperator QsciLexerRubyPODPOD QsciLexerRuby"Expressão RegularRegular expression QsciLexerRuby`Cadeia de caracteres envolvida por aspas simplesSingle-quoted string QsciLexerRubySímboloSymbol QsciLexerRuby8Comentário de linha usando ## comment line QsciLexerSQLComentárioComment QsciLexerSQL&Comentário de Linha Comment line QsciLexerSQL PadrãoDefault QsciLexerSQL^Cadeia de caracteres envolvida por aspas duplasDouble-quoted string QsciLexerSQLIdentificador Identifier QsciLexerSQL*Palavra chave JavaDocJavaDoc keyword QsciLexerSQL@Erro de palavra chave do JavaDocJavaDoc keyword error QsciLexerSQL2Comentário estilo JavaDocJavaDoc style comment QsciLexerSQLPalavra ChaveKeyword QsciLexerSQL NúmeroNumber QsciLexerSQLOperadorOperator QsciLexerSQL,Comentário do SQL*PlusSQL*Plus comment QsciLexerSQL2Palavra chave do SQL*PlusSQL*Plus keyword QsciLexerSQL$Prompt do SQL*PlusSQL*Plus prompt QsciLexerSQL`Cadeia de caracteres envolvida por aspas simplesSingle-quoted string QsciLexerSQL,Definição de usuário 1User defined 1 QsciLexerSQL,Definição de usuário 2User defined 2 QsciLexerSQL,Definição de usuário 3User defined 3 QsciLexerSQL,Definição de usuário 4User defined 4 QsciLexerSQLComandoCommandQsciLexerSpiceComentárioCommentQsciLexerSpice PadrãoDefaultQsciLexerSpiceIdentificador IdentifierQsciLexerSpice NúmeroNumberQsciLexerSpice ValorValueQsciLexerSpiceComentárioComment QsciLexerTCL(Bloco de comentários Comment block QsciLexerTCL PadrãoDefault QsciLexerTCLIdentificador Identifier QsciLexerTCL NúmeroNumber QsciLexerTCLOperadorOperator QsciLexerTCLSubstituição Substitution QsciLexerTCL,Definição de usuário 1User defined 1 QsciLexerTCL,Definição de usuário 2User defined 2 QsciLexerTCL,Definição de usuário 3User defined 3 QsciLexerTCL,Definição de usuário 4User defined 4 QsciLexerTCLComandoCommand QsciLexerTeX PadrãoDefault QsciLexerTeX GrupoGroup QsciLexerTeXEspecialSpecial QsciLexerTeXSímboloSymbol QsciLexerTeX TextoText QsciLexerTeXAtributo Attribute QsciLexerVHDLComentárioComment QsciLexerVHDL(Bloco de comentários Comment block QsciLexerVHDL PadrãoDefault QsciLexerVHDLIdentificador Identifier QsciLexerVHDLPalavra ChaveKeyword QsciLexerVHDL NúmeroNumber QsciLexerVHDLOperadorOperator QsciLexerVHDL(Cadeia de CaracteresString QsciLexerVHDL@Cadeia de caracteres não fechadaUnclosed string QsciLexerVHDLComentárioCommentQsciLexerVerilog PadrãoDefaultQsciLexerVerilogIdentificador IdentifierQsciLexerVerilogComentar Linha Line commentQsciLexerVerilog NúmeroNumberQsciLexerVerilogOperadorOperatorQsciLexerVerilogXIdentificadores e palavras chave secundárias"Secondary keywords and identifiersQsciLexerVerilog(Cadeia de CaracteresStringQsciLexerVerilog@Cadeia de caracteres não fechadaUnclosed stringQsciLexerVerilogComentárioComment QsciLexerYAML PadrãoDefault QsciLexerYAMLIdentificador Identifier QsciLexerYAMLPalavra ChaveKeyword QsciLexerYAML NúmeroNumber QsciLexerYAMLOperadorOperator QsciLexerYAMLsqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscintilla_pt_br.ts000066400000000000000000004553351463772530400277520ustar00rootroot00000000000000 QsciCommand Move down one line Mover uma linha para baixo Extend selection down one line Extender a seleção uma linha para baixo Scroll view down one line Descer a visão uma linha para baixo Extend rectangular selection down one line Extender a seleção retangular uma linha para baixo Move up one line Mover uma linha para cima Extend selection up one line Extender a seleção uma linha para cima Scroll view up one line Subir a visão uma linha para cima Extend rectangular selection up one line Extender a seleção retangular uma linha para cima Move up one paragraph Mover um paragrafo para cima Extend selection up one paragraph Extender a seleção um paragrafo para cima Move down one paragraph Mover um paragrafo para baixo Scroll to start of document Scroll to end of document Scroll vertically to centre current line Extend selection down one paragraph Extender a seleção um paragrafo para baixo Move left one character Mover um caractere para a esquerda Extend selection left one character Extender a seleção um caractere para esquerda Move left one word Mover uma palavra para esquerda Extend selection left one word Extender a seleção uma palavra para esquerda Extend rectangular selection left one character Extender a seleção retangular um caractere para esquerda Move right one character Mover um caractere para direita Extend selection right one character Extender a seleção um caractere para direita Move right one word Mover uma palavra para direita Extend selection right one word Extender a seleção uma palavra para direita Extend rectangular selection right one character Extender a seleção retangular um caractere para direita Move to end of previous word Extend selection to end of previous word Move to end of next word Extend selection to end of next word Move left one word part Mover uma parte da palavra para esquerda Extend selection left one word part Extender a seleção uma parte de palavra para esquerda Move right one word part Mover uma parte da palavra para direita Extend selection right one word part Extender a seleção uma parte de palavra para direita Move up one page Mover uma página para cima Extend selection up one page Extender a seleção uma página para cima Extend rectangular selection up one page Extender a seleção retangular uma página para cima Move down one page Mover uma página para baixo Extend selection down one page Extender a seleção uma página para baixo Extend rectangular selection down one page Extender a seleção retangular uma página para baixo Delete current character Excluir caractere atual Cut selection Recortar seleção Delete word to right Excluir palavra para direita Move to start of document line Extend selection to start of document line Extend rectangular selection to start of document line Move to start of display line Extend selection to start of display line Move to start of display or document line Extend selection to start of display or document line Move to first visible character in document line Extend selection to first visible character in document line Extend rectangular selection to first visible character in document line Move to first visible character of display in document line Extend selection to first visible character in display or document line Move to end of document line Extend selection to end of document line Extend rectangular selection to end of document line Move to end of display line Extend selection to end of display line Move to end of display or document line Extend selection to end of display or document line Move to start of document Extend selection to start of document Move to end of document Extend selection to end of document Stuttered move up one page Stuttered extend selection up one page Stuttered move down one page Stuttered extend selection down one page Delete previous character if not at start of line Delete right to end of next word Delete line to right Excluir linha para direita Transpose current and previous lines Duplicate the current line Select all Select document Move selected lines up one line Move selected lines down one line Toggle insert/overtype Alternar entre modo de inserir/sobreescrever Paste Copiar Copy selection Copiar seleção Insert newline De-indent one level Cancel Cancelar Delete previous character Excluir caractere anterior Delete word to left Excluir palavra a esquerda Delete line to left Excluir linha a esquerda Undo last command Redo last command Refazer último comando Indent one level Indentar um nível Zoom in Aumentar zoom Zoom out Diminuir zoom Formfeed Alimentação da Página Cut current line Configurar linha atual Delete current line Excluir linha atual Copy current line Copiar linha atual Convert selection to lower case Converter a seleção para minúscula Convert selection to upper case Converter a seleção para maiúscula Duplicate selection QsciLexerAVS Default Padrão Block comment Nested block comment Line comment Comentar Linha Number Número Operator Operador Identifier Identificador Double-quoted string Cadeia de caracteres envolvida por aspas duplas Triple double-quoted string Cadeia de caracteres envolvida por três aspas duplas Keyword Palavra Chave Filter Plugin Function Clip property User defined QsciLexerBash Default Padrão Error Número Comment Comentário Number Número Keyword Palavra Chave Double-quoted string Cadeia de caracteres envolvida por aspas duplas Single-quoted string Cadeia de caracteres envolvida por aspas simples Operator Operador Identifier Identificador Scalar Escalar Parameter expansion Parâmetro de Expansão Backticks Aspas Invertidas Here document delimiter Delimitador de "here documents" Single-quoted here document "here document" envolvido por aspas simples QsciLexerBatch Default Padrão Comment Comentário Keyword Palavra Chave Label Rótulo Hide command character Esconder caractere de comando External command Comando externo Variable Variável Operator Operador QsciLexerCMake Default Padrão Comment Comentário String Cadeia de Caracteres Left quoted string Right quoted string Function Variable Variável Label Rótulo User defined WHILE block FOREACH block IF block MACRO block Variable within a string Number Número QsciLexerCPP Default Padrão Inactive default C comment Comentário C Inactive C comment C++ comment Comentário C++ Inactive C++ comment JavaDoc style C comment Comentário JavaDoc estilo C Inactive JavaDoc style C comment Number Número Inactive number Keyword Palavra Chave Inactive keyword Double-quoted string Cadeia de caracteres envolvida por aspas duplas Inactive double-quoted string Single-quoted string Cadeia de caracteres envolvida por aspas simples Inactive single-quoted string IDL UUID Inactive IDL UUID Pre-processor block Instruções de pré-processamento Inactive pre-processor block Operator Operador Inactive operator Identifier Identificador Inactive identifier Unclosed string Cadeia de caracteres não fechada Inactive unclosed string C# verbatim string Inactive C# verbatim string JavaScript regular expression Expressão regular JavaScript Inactive JavaScript regular expression JavaDoc style C++ comment Comentário JavaDoc estilo C++ Inactive JavaDoc style C++ comment Secondary keywords and identifiers Identificadores e palavras chave secundárias Inactive secondary keywords and identifiers JavaDoc keyword Palavra chave JavaDoc Inactive JavaDoc keyword JavaDoc keyword error Erro de palavra chave do JavaDoc Inactive JavaDoc keyword error Global classes and typedefs Classes e definições de tipo globais Inactive global classes and typedefs C++ raw string Inactive C++ raw string Vala triple-quoted verbatim string Inactive Vala triple-quoted verbatim string Pike hash-quoted string Inactive Pike hash-quoted string Pre-processor C comment Inactive pre-processor C comment JavaDoc style pre-processor comment Inactive JavaDoc style pre-processor comment User-defined literal Inactive user-defined literal Task marker Inactive task marker Escape sequence Inactive escape sequence QsciLexerCSS Default Padrão Tag Marcador Class selector Seletor de classe Pseudo-class Pseudo-classe Unknown pseudo-class Pseudo-classe desconhecida Operator Operador CSS1 property Propriedade CSS1 Unknown property Propriedade desconhecida Value Valor ID selector Seletor de ID Important Importante @-rule regra-@ Double-quoted string Cadeia de caracteres envolvida por aspas duplas Single-quoted string Cadeia de caracteres envolvida por aspas simples CSS2 property Propriedade CSS2 Attribute Atributo CSS3 property Propriedade CSS2 {3 ?} Pseudo-element Extended CSS property Extended pseudo-class Extended pseudo-element Media rule Variable Variável QsciLexerCSharp Verbatim string Cadeia de caracteres no formato verbatim QsciLexerCoffeeScript Default Padrão C-style comment C++-style comment JavaDoc C-style comment Number Número Keyword Palavra Chave Double-quoted string Cadeia de caracteres envolvida por aspas duplas Single-quoted string Cadeia de caracteres envolvida por aspas simples IDL UUID Pre-processor block Instruções de pré-processamento Operator Operador Identifier Identificador Unclosed string Cadeia de caracteres não fechada C# verbatim string Regular expression Expressão Regular JavaDoc C++-style comment Secondary keywords and identifiers Identificadores e palavras chave secundárias JavaDoc keyword Palavra chave JavaDoc JavaDoc keyword error Erro de palavra chave do JavaDoc Global classes Block comment Block regular expression Block regular expression comment Instance property QsciLexerD Default Padrão Block comment Line comment Comentar Linha DDoc style block comment Nesting comment Number Número Keyword Palavra Chave Secondary keyword Documentation keyword Type definition String Cadeia de Caracteres Unclosed string Cadeia de caracteres não fechada Character Caractere Operator Operador Identifier Identificador DDoc style line comment DDoc keyword Palavra chave JavaDoc DDoc keyword error Erro de palavra chave do JavaDoc Backquoted string Raw string User defined 1 Definição de usuário 1 User defined 2 Definição de usuário 2 User defined 3 Definição de usuário 3 QsciLexerDiff Default Padrão Comment Comentário Command Comando Header Cabeçalho Position Posição Removed line Linha Removida Added line Linha Adicionada Changed line Added adding patch Removed adding patch Added removing patch Removed removing patch QsciLexerEDIFACT Default Padrão Segment start Segment end Element separator Composite separator Release separator UNA segment header UNH segment header Badly formed segment QsciLexerFortran77 Default Padrão Comment Comentário Number Número Single-quoted string Cadeia de caracteres envolvida por aspas simples Double-quoted string Cadeia de caracteres envolvida por aspas duplas Unclosed string Cadeia de caracteres não fechada Operator Operador Identifier Identificador Keyword Palavra Chave Intrinsic function Extended function Pre-processor block Instruções de pré-processamento Dotted operator Label Rótulo Continuation QsciLexerHTML HTML default HTML por padrão Tag Marcador Unknown tag Marcador desconhecido Attribute Atributo Unknown attribute Atributo desconhecido HTML number Número HTML HTML double-quoted string Cadeia de caracteres HTML envolvida por aspas duplas HTML single-quoted string Cadeia de caracteres HTML envolvida por aspas simples Other text in a tag Outro texto em um marcador HTML comment Comentário HTML Entity Entidade End of a tag Final de um marcador Start of an XML fragment Início de um bloco XML End of an XML fragment Final de um bloco XML Script tag Marcador de script Start of an ASP fragment with @ Início de um bloco ASP com @ Start of an ASP fragment Início de um bloco ASP CDATA CDATA Start of a PHP fragment Início de um bloco PHP Unquoted HTML value Valor HTML não envolvido por aspas ASP X-Code comment Comentário ASP X-Code SGML default SGML por padrão SGML command Comando SGML First parameter of an SGML command Primeiro parâmetro em um comando SGML SGML double-quoted string Cadeia de caracteres SGML envolvida por aspas duplas SGML single-quoted string Cadeia de caracteres SGML envolvida por aspas simples SGML error Erro SGML SGML special entity Entidade especial SGML SGML comment Comando SGML First parameter comment of an SGML command Primeiro comentário de parâmetro de uma comando SGML SGML block default Bloco SGML por padrão Start of a JavaScript fragment Início de um bloco Javascript JavaScript default JavaScript por padrão JavaScript comment Comentário JavaScript JavaScript line comment Comentário de linha JavaScript JavaDoc style JavaScript comment Comentário JavaScript no estilo JavaDoc JavaScript number Número JavaScript JavaScript word Palavra JavaScript JavaScript keyword Palavra chave JavaScript JavaScript double-quoted string Cadeia de caracteres JavaScript envolvida por aspas duplas JavaScript single-quoted string Cadeia de caracteres JavaScript envolvida por aspas simples JavaScript symbol Símbolo JavaScript JavaScript unclosed string Cadeia de caracteres JavaScript não fechada JavaScript regular expression Expressão regular JavaScript Start of an ASP JavaScript fragment Início de um bloco Javascript ASP ASP JavaScript default JavaScript ASP por padrão ASP JavaScript comment Comentário JavaScript ASP ASP JavaScript line comment Comentário de linha JavaScript ASP JavaDoc style ASP JavaScript comment Comentário JavaScript ASP no estilo JavaDoc ASP JavaScript number Número JavaScript ASP ASP JavaScript word Palavra chave JavaScript ASP ASP JavaScript keyword Palavra chave JavaScript ASP ASP JavaScript double-quoted string Cadeia de caracteres JavaScript ASP envolvida por aspas duplas ASP JavaScript single-quoted string Cadeia de caracteres JavaScript ASP envolvida por aspas simples ASP JavaScript symbol Símbolo JavaScript ASP ASP JavaScript unclosed string Cadeia de caracteres JavaScript ASP não fechada ASP JavaScript regular expression Expressão regular JavaScript ASP Start of a VBScript fragment Início de um bloco VBScript VBScript default VBScript por padrão VBScript comment Comentário VBScript VBScript number Número VBScript VBScript keyword Palavra chave VBScript VBScript string Cadeia de caracteres VBScript VBScript identifier Identificador VBScript VBScript unclosed string Cadeia de caracteres VBScript não fechada Start of an ASP VBScript fragment Início de um bloco VBScript ASP ASP VBScript default VBScript ASP por padrão ASP VBScript comment Comentário VBScript ASP ASP VBScript number Número VBScript ASP ASP VBScript keyword Palavra chave VBScript ASP ASP VBScript string Cadeia de caracteres VBScript ASP ASP VBScript identifier Identificador VBScript ASP ASP VBScript unclosed string Cadeia de caracteres VBScript ASP não fechada Start of a Python fragment Início de um bloco Python Python default Python por padrão Python comment Comentário Python Python number Número Python Python double-quoted string Cadeia de caracteres Python envolvida por aspas duplas Python single-quoted string Cadeia de caracteres Python envolvida por aspas simples Python keyword Palavra chave Python Python triple double-quoted string Cadeia de caracteres Python envolvida por aspas triplas duplas Python triple single-quoted string Cadeia de caracteres Python envolvida por aspas triplas simples Python class name Nome de classe Python Python function or method name Nome de método ou função Python Python operator Operador Python Python identifier Identificador Python Start of an ASP Python fragment Início de um bloco Python ASP ASP Python default Python ASP por padrão ASP Python comment Comentário Python ASP ASP Python number Número Python ASP ASP Python double-quoted string Cadeia de caracteres Python ASP envolvida por aspas duplas ASP Python single-quoted string Cadeia de caracteres Python ASP envolvida por aspas simples ASP Python keyword Palavra chave Python ASP ASP Python triple double-quoted string Cadeia de caracteres Python ASP envolvida por aspas triplas duplas ASP Python triple single-quoted string Cadeia de caracteres Python ASP envolvida por aspas triplas simples ASP Python class name Nome de classe Python ASP ASP Python function or method name Nome de método ou função Python ASP ASP Python operator Operador Python ASP ASP Python identifier Identificador Python ASP PHP default PHP por padrão PHP double-quoted string Cadeia de caracteres PHP envolvida por aspas duplas PHP single-quoted string Cadeia de caracteres PHP envolvida por aspas simples PHP keyword Palavra chave PHP PHP number Número PHP PHP variable Variável PHP PHP comment Comentário PHP PHP line comment Comentário de linha PHP PHP double-quoted variable Variável PHP envolvida por aspas duplas PHP operator Operador PHP QsciLexerIDL UUID UUID QsciLexerJSON Default Padrão Number Número String Cadeia de Caracteres Unclosed string Cadeia de caracteres não fechada Property Escape sequence Line comment Comentar Linha Block comment Operator Operador IRI JSON-LD compact IRI JSON keyword JSON-LD keyword Parsing error QsciLexerJavaScript Regular expression Expressão Regular QsciLexerLua Default Padrão Comment Comentário Line comment Comentar Linha Number Número Keyword Palavra Chave String Cadeia de Caracteres Character Caractere Literal string Cadeia de caracteres literal Preprocessor Preprocessador Operator Operador Identifier Identificador Unclosed string Cadeia de caracteres não fechada Basic functions Funções básicas String, table and maths functions Funções de cadeia de caracteres e de tabelas matemáticas Coroutines, i/o and system facilities Funções auxiiares, e/s e funções de sistema User defined 1 Definição de usuário 1 User defined 2 Definição de usuário 2 User defined 3 Definição de usuário 3 User defined 4 Definição de usuário 4 Label Rótulo QsciLexerMakefile Default Padrão Comment Comentário Preprocessor Preprocessador Variable Variável Operator Operador Target Destino Error Erro QsciLexerMarkdown Default Padrão Special Especial Strong emphasis using double asterisks Strong emphasis using double underscores Emphasis using single asterisks Emphasis using single underscores Level 1 header Level 2 header Level 3 header Level 4 header Level 5 header Level 6 header Pre-char Unordered list item Ordered list item Block quote Strike out Horizontal rule Link Code between backticks Code between double backticks Code block QsciLexerMatlab Default Padrão Comment Comentário Command Comando Number Número Keyword Palavra Chave Single-quoted string Cadeia de caracteres envolvida por aspas simples Operator Operador Identifier Identificador Double-quoted string Cadeia de caracteres envolvida por aspas duplas QsciLexerPO Default Padrão Comment Comentário Message identifier Message identifier text Message string Message string text Message context Message context text Fuzzy flag Programmer comment Reference Flags Message identifier text end-of-line Message string text end-of-line Message context text end-of-line QsciLexerPOV Default Padrão Comment Comentário Comment line Comentar Linha Number Número Operator Operador Identifier Identificador String Cadeia de Caracteres Unclosed string Cadeia de caracteres não fechada Directive Diretiva Bad directive Diretiva ruim Objects, CSG and appearance Objetos, CSG e aparência Types, modifiers and items Tipos, modificadores e itens Predefined identifiers Identificadores predefinidos Predefined functions Funções predefinidas User defined 1 Definição de usuário 1 User defined 2 Definição de usuário 2 User defined 3 Definição de usuário 3 QsciLexerPascal Default Padrão Line comment Comentar Linha Number Número Keyword Palavra Chave Single-quoted string Cadeia de caracteres envolvida por aspas simples Operator Operador Identifier Identificador '{ ... }' style comment '(* ... *)' style comment '{$ ... }' style pre-processor block '(*$ ... *)' style pre-processor block Hexadecimal number Unclosed string Cadeia de caracteres não fechada Character Caractere Inline asm QsciLexerPerl Default Padrão Error Erro Comment Comentário POD POD Number Número Keyword Palavra Chave Double-quoted string Cadeia de caracteres envolvida por aspas duplas Single-quoted string Cadeia de caracteres envolvida por aspas simples Operator Operador Identifier Identificador Scalar Escalar Array Vetor Hash Hash Symbol table Tabela de Símbolos Regular expression Expressão Regular Substitution Substituição Backticks Aspas Invertidas Data section Seção de dados Here document delimiter Delimitador de documentos criados através de redicionadores (>> e >) Single-quoted here document "here document" envolvido por aspas simples Double-quoted here document "here document" envolvido por aspas duplas Backtick here document "here document" envolvido por aspas invertidas Quoted string (q) Cadeia de caracteres envolvida por aspas (q) Quoted string (qq) Cadeia de caracteres envolvida por aspas (qq) Quoted string (qx) Cadeia de caracteres envolvida por aspas (qx) Quoted string (qr) Cadeia de caracteres envolvida por aspas (qr) Quoted string (qw) Cadeia de caracteres envolvida por aspas (qw) POD verbatim POD em formato verbatim Subroutine prototype Format identifier Format body Double-quoted string (interpolated variable) Translation Regular expression (interpolated variable) Substitution (interpolated variable) Backticks (interpolated variable) Double-quoted here document (interpolated variable) Backtick here document (interpolated variable) Quoted string (qq, interpolated variable) Quoted string (qx, interpolated variable) Quoted string (qr, interpolated variable) QsciLexerPostScript Default Padrão Comment Comentário DSC comment DSC comment value Number Número Name Keyword Palavra Chave Literal Immediately evaluated literal Array parenthesis Dictionary parenthesis Procedure parenthesis Text Texto Hexadecimal string Base85 string Bad string character QsciLexerProperties Default Padrão Comment Comentário Section Seção Assignment Atribuição Default value Valor Padrão Key QsciLexerPython Default Padrão Comment Comentário Number Número Double-quoted string Cadeia de caracteres envolvida por aspas duplas Single-quoted string Cadeia de caracteres envolvida por aspas simples Keyword Palavra Chave Triple single-quoted string Cadeia de caracteres envolvida por três aspas simples Triple double-quoted string Cadeia de caracteres envolvida por três aspas duplas Class name Nome da classe Function or method name Nome da função ou método Operator Operador Identifier Identificador Comment block Bloco de comentários Unclosed string Cadeia de caracteres não fechada Highlighted identifier Decorator Double-quoted f-string Single-quoted f-string Triple single-quoted f-string Triple double-quoted f-string QsciLexerRuby Default Padrão Comment Comentário Number Número Double-quoted string Cadeia de caracteres envolvida por aspas duplas Single-quoted string Cadeia de caracteres envolvida por aspas simples Keyword Palavra Chave Class name Nome da classe Function or method name Nome da função ou método Operator Operador Identifier Identificador Error POD POD Regular expression Expressão Regular Global Symbol Símbolo Module name Instance variable Class variable Backticks Aspas Invertidas Data section Seção de dados Here document delimiter Here document %q string %Q string %x string %r string %w string Demoted keyword stdin stdout stderr QsciLexerSQL Default Padrão Comment Comentário Number Número Keyword Palavra Chave Single-quoted string Cadeia de caracteres envolvida por aspas simples Operator Operador Identifier Identificador Comment line Comentário de Linha JavaDoc style comment Comentário estilo JavaDoc Double-quoted string Cadeia de caracteres envolvida por aspas duplas SQL*Plus keyword Palavra chave do SQL*Plus SQL*Plus prompt Prompt do SQL*Plus SQL*Plus comment Comentário do SQL*Plus # comment line Comentário de linha usando # JavaDoc keyword Palavra chave JavaDoc JavaDoc keyword error Erro de palavra chave do JavaDoc User defined 1 Definição de usuário 1 User defined 2 Definição de usuário 2 User defined 3 Definição de usuário 3 User defined 4 Definição de usuário 4 Quoted identifier Quoted operator QsciLexerSpice Default Padrão Identifier Identificador Command Comando Function Parameter Number Número Delimiter Value Valor Comment Comentário QsciLexerTCL Default Padrão Comment Comentário Comment line Number Número Quoted keyword Quoted string Operator Operador Identifier Identificador Substitution Substituição Brace substitution Modifier Expand keyword TCL keyword Tk keyword iTCL keyword Tk command User defined 1 Definição de usuário 1 User defined 2 Definição de usuário 2 User defined 3 Definição de usuário 3 User defined 4 Definição de usuário 4 Comment box Comment block Bloco de comentários QsciLexerTeX Default Padrão Special Especial Group Grupo Symbol Símbolo Command Comando Text Texto QsciLexerVHDL Default Padrão Comment Comentário Comment line Number Número String Cadeia de Caracteres Operator Operador Identifier Identificador Unclosed string Cadeia de caracteres não fechada Keyword Palavra Chave Standard operator Attribute Atributo Standard function Standard package Standard type User defined Comment block Bloco de comentários QsciLexerVerilog Default Padrão Inactive default Comment Comentário Inactive comment Line comment Comentar Linha Inactive line comment Bang comment Inactive bang comment Number Número Inactive number Primary keywords and identifiers Inactive primary keywords and identifiers String Cadeia de Caracteres Inactive string Secondary keywords and identifiers Identificadores e palavras chave secundárias Inactive secondary keywords and identifiers System task Inactive system task Preprocessor block Inactive preprocessor block Operator Operador Inactive operator Identifier Identificador Inactive identifier Unclosed string Cadeia de caracteres não fechada Inactive unclosed string User defined tasks and identifiers Inactive user defined tasks and identifiers Keyword comment Inactive keyword comment Input port declaration Inactive input port declaration Output port declaration Inactive output port declaration Input/output port declaration Inactive input/output port declaration Port connection Inactive port connection QsciLexerYAML Default Padrão Comment Comentário Identifier Identificador Keyword Palavra Chave Number Número Reference Document delimiter Text block marker Syntax error marker Operator Operador QsciScintilla &Undo &Redo Cu&t &Copy &Paste Delete Select All sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qsciprinter.cpp000066400000000000000000000112061463772530400271010ustar00rootroot00000000000000// This module implements the QsciPrinter class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qsciprinter.h" #if !defined(QT_NO_PRINTER) #include #include #include #include "Qsci/qsciscintillabase.h" // The ctor. QsciPrinter::QsciPrinter(QPrinter::PrinterMode mode) : QPrinter(mode), mag(0), wrap(QsciScintilla::WrapWord) { } // The dtor. QsciPrinter::~QsciPrinter() { } // Format the page before the document text is drawn. void QsciPrinter::formatPage(QPainter &, bool, QRect &, int) { } // Print a range of lines to a printer. int QsciPrinter::printRange(QsciScintillaBase *qsb, int from, int to) { // Sanity check. if (!qsb) return false; // Setup the printing area. QRect def_area; def_area.setX(0); def_area.setY(0); def_area.setWidth(width()); def_area.setHeight(height()); // Get the page range. int pgFrom, pgTo; pgFrom = fromPage(); pgTo = toPage(); // Find the position range. long startPos, endPos; endPos = qsb->SendScintilla(QsciScintillaBase::SCI_GETLENGTH); startPos = (from > 0 ? qsb -> SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE,from) : 0); if (to >= 0) { long toPos = qsb -> SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE,to + 1); if (endPos > toPos) endPos = toPos; } if (startPos >= endPos) return false; QPainter painter(this); bool reverse = (pageOrder() == LastPageFirst); bool needNewPage = false; qsb -> SendScintilla(QsciScintillaBase::SCI_SETPRINTMAGNIFICATION,mag); qsb -> SendScintilla(QsciScintillaBase::SCI_SETPRINTWRAPMODE,wrap); for (int i = 1; i <= numCopies(); ++i) { // If we are printing in reverse page order then remember the start // position of each page. QStack pageStarts; int currPage = 1; long pos = startPos; while (pos < endPos) { // See if we have finished the requested page range. if (pgTo > 0 && pgTo < currPage) break; // See if we are going to render this page, or just see how much // would fit onto it. bool render = false; if (pgFrom == 0 || pgFrom <= currPage) { if (reverse) pageStarts.push(pos); else { render = true; if (needNewPage) { if (!newPage()) return false; } else needNewPage = true; } } QRect area = def_area; formatPage(painter,render,area,currPage); pos = qsb -> SendScintilla(QsciScintillaBase::SCI_FORMATRANGE,render,&painter,area,pos,endPos); ++currPage; } // All done if we are printing in normal page order. if (!reverse) continue; // Now go through each page on the stack and really print it. while (!pageStarts.isEmpty()) { --currPage; long ePos = pos; pos = pageStarts.pop(); if (needNewPage) { if (!newPage()) return false; } else needNewPage = true; QRect area = def_area; formatPage(painter,true,area,currPage); qsb->SendScintilla(QsciScintillaBase::SCI_FORMATRANGE,true,&painter,area,pos,ePos); } } return true; } // Set the print magnification in points. void QsciPrinter::setMagnification(int magnification) { mag = magnification; } // Set the line wrap mode. void QsciPrinter::setWrapMode(QsciScintilla::WrapMode wmode) { wrap = wmode; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qsciscintilla.cpp000066400000000000000000003353731463772530400274160ustar00rootroot00000000000000// This module implements the "official" high-level API of the Qt port of // Scintilla. It is modelled on QTextEdit - a method of the same name should // behave in the same way. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qsciscintilla.h" #include #include #include #include #include #include #include #include #include #include #include #include "Qsci/qsciabstractapis.h" #include "Qsci/qscicommandset.h" #include "Qsci/qscilexer.h" #include "Qsci/qscistyle.h" #include "Qsci/qscistyledtext.h" // Make sure these match the values in Scintilla.h. We don't #include that // file because it just causes more clashes. #define KEYWORDSET_MAX 8 #define MARKER_MAX 31 // The list separators for auto-completion and user lists. const char acSeparator = '\x03'; const char userSeparator = '\x04'; // The default fold margin width. static const int defaultFoldMarginWidth = 14; // The default set of characters that make up a word. static const char *defaultWordChars = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // Forward declarations. static QColor asQColor(long sci_colour); // The ctor. QsciScintilla::QsciScintilla(QWidget *parent) : QsciScintillaBase(parent), allocatedMarkers(0), allocatedIndicators(7), oldPos(-1), selText(false), fold(NoFoldStyle), foldmargin(2), autoInd(false), braceMode(NoBraceMatch), acSource(AcsNone), acThresh(-1), wchars(defaultWordChars), call_tips_position(CallTipsBelowText), call_tips_style(CallTipsNoContext), maxCallTips(-1), use_single(AcusNever), explicit_fillups(""), fillups_enabled(false) { connect(this,SIGNAL(SCN_MODIFYATTEMPTRO()), SIGNAL(modificationAttempted())); connect(this,SIGNAL(SCN_MODIFIED(int,int,const char *,int,int,int,int,int,int,int)), SLOT(handleModified(int,int,const char *,int,int,int,int,int,int,int))); connect(this,SIGNAL(SCN_CALLTIPCLICK(int)), SLOT(handleCallTipClick(int))); connect(this,SIGNAL(SCN_CHARADDED(int)), SLOT(handleCharAdded(int))); connect(this,SIGNAL(SCN_INDICATORCLICK(int,int)), SLOT(handleIndicatorClick(int,int))); connect(this,SIGNAL(SCN_INDICATORRELEASE(int,int)), SLOT(handleIndicatorRelease(int,int))); connect(this,SIGNAL(SCN_MARGINCLICK(int,int,int)), SLOT(handleMarginClick(int,int,int))); connect(this,SIGNAL(SCN_MARGINRIGHTCLICK(int,int,int)), SLOT(handleMarginRightClick(int,int,int))); connect(this,SIGNAL(SCN_SAVEPOINTREACHED()), SLOT(handleSavePointReached())); connect(this,SIGNAL(SCN_SAVEPOINTLEFT()), SLOT(handleSavePointLeft())); connect(this,SIGNAL(SCN_UPDATEUI(int)), SLOT(handleUpdateUI(int))); connect(this,SIGNAL(QSCN_SELCHANGED(bool)), SLOT(handleSelectionChanged(bool))); connect(this,SIGNAL(SCN_AUTOCSELECTION(const char *,int)), SLOT(handleAutoCompletionSelection())); connect(this,SIGNAL(SCN_USERLISTSELECTION(const char *,int)), SLOT(handleUserListSelection(const char *,int))); // Set the default font. setFont(QApplication::font()); // Set the default fore and background colours. QPalette pal = QApplication::palette(); setColor(pal.text().color()); setPaper(pal.base().color()); setSelectionForegroundColor(pal.highlightedText().color()); setSelectionBackgroundColor(pal.highlight().color()); #if defined(Q_OS_WIN) setEolMode(EolWindows); #else // Note that EolMac is pre-OS/X. setEolMode(EolUnix); #endif // Capturing the mouse seems to cause problems on multi-head systems. Qt // should do the right thing anyway. SendScintilla(SCI_SETMOUSEDOWNCAPTURES, 0UL); setMatchedBraceForegroundColor(Qt::blue); setUnmatchedBraceForegroundColor(Qt::red); setAnnotationDisplay(AnnotationStandard); setLexer(); // Set the visible policy. These are the same as SciTE's defaults // which, presumably, are sensible. SendScintilla(SCI_SETVISIBLEPOLICY, VISIBLE_STRICT | VISIBLE_SLOP, 4); // The default behaviour is unexpected. SendScintilla(SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR, SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE); // Create the standard command set. stdCmds = new QsciCommandSet(this); doc.display(this,0); } // The dtor. QsciScintilla::~QsciScintilla() { // Detach any current lexer. detachLexer(); doc.undisplay(this); delete stdCmds; } // Return the current text colour. QColor QsciScintilla::color() const { return nl_text_colour; } // Set the text colour. void QsciScintilla::setColor(const QColor &c) { if (lex.isNull()) { // Assume style 0 applies to everything so that we don't need to use // SCI_STYLECLEARALL which clears everything. SendScintilla(SCI_STYLESETFORE, 0, c); nl_text_colour = c; } } // Return the overwrite mode. bool QsciScintilla::overwriteMode() const { return SendScintilla(SCI_GETOVERTYPE); } // Set the overwrite mode. void QsciScintilla::setOverwriteMode(bool overwrite) { SendScintilla(SCI_SETOVERTYPE, overwrite); } // Return the current paper colour. QColor QsciScintilla::paper() const { return nl_paper_colour; } // Set the paper colour. void QsciScintilla::setPaper(const QColor &c) { if (lex.isNull()) { // Assume style 0 applies to everything so that we don't need to use // SCI_STYLECLEARALL which clears everything. We still have to set the // default style as well for the background without any text. SendScintilla(SCI_STYLESETBACK, 0, c); SendScintilla(SCI_STYLESETBACK, STYLE_DEFAULT, c); nl_paper_colour = c; } } // Set the default font. void QsciScintilla::setFont(const QFont &f) { if (lex.isNull()) { // Assume style 0 applies to everything so that we don't need to use // SCI_STYLECLEARALL which clears everything. setStylesFont(f, 0); QWidget::setFont(f); } } // Enable/disable auto-indent. void QsciScintilla::setAutoIndent(bool autoindent) { autoInd = autoindent; } // Set the brace matching mode. void QsciScintilla::setBraceMatching(BraceMatch bm) { braceMode = bm; } // Handle the addition of a character. void QsciScintilla::handleCharAdded(int ch) { // Ignore if there is a selection. long pos = SendScintilla(SCI_GETSELECTIONSTART); if (pos != SendScintilla(SCI_GETSELECTIONEND) || pos == 0) return; // If auto-completion is already active then see if this character is a // start character. If it is then create a new list which will be a subset // of the current one. The case where it isn't a start character seems to // be handled correctly elsewhere. if (isListActive() && isStartChar(ch)) { cancelList(); startAutoCompletion(acSource, false, use_single == AcusAlways); return; } // Handle call tips. if (call_tips_style != CallTipsNone && !lex.isNull() && strchr("(),", ch) != NULL) callTip(); // Handle auto-indentation. if (autoInd) { if (lex.isNull() || (lex->autoIndentStyle() & AiMaintain)) maintainIndentation(ch, pos); else autoIndentation(ch, pos); } // See if we might want to start auto-completion. if (!isCallTipActive() && acSource != AcsNone) { if (isStartChar(ch)) startAutoCompletion(acSource, false, use_single == AcusAlways); else if (acThresh >= 1 && isWordCharacter(ch)) startAutoCompletion(acSource, true, use_single == AcusAlways); } } // See if a call tip is active. bool QsciScintilla::isCallTipActive() const { return SendScintilla(SCI_CALLTIPACTIVE); } // Handle a possible change to any current call tip. void QsciScintilla::callTip() { QsciAbstractAPIs *apis = lex->apis(); if (!apis) return; int pos, commas = 0; bool found = false; char ch; pos = SendScintilla(SCI_GETCURRENTPOS); // Move backwards through the line looking for the start of the current // call tip and working out which argument it is. while ((ch = getCharacter(pos)) != '\0') { if (ch == ',') ++commas; else if (ch == ')') { int depth = 1; // Ignore everything back to the start of the corresponding // parenthesis. while ((ch = getCharacter(pos)) != '\0') { if (ch == ')') ++depth; else if (ch == '(' && --depth == 0) break; } } else if (ch == '(') { found = true; break; } } // Cancel any existing call tip. SendScintilla(SCI_CALLTIPCANCEL); // Done if there is no new call tip to set. if (!found) return; QStringList context = apiContext(pos, pos, ctPos); if (context.isEmpty()) return; // The last word is complete, not partial. context << QString(); ct_cursor = 0; ct_shifts.clear(); ct_entries = apis->callTips(context, commas, call_tips_style, ct_shifts); int nr_entries = ct_entries.count(); if (nr_entries == 0) return; if (maxCallTips > 0 && maxCallTips < nr_entries) { ct_entries = ct_entries.mid(0, maxCallTips); nr_entries = maxCallTips; } int shift; QString ct; int nr_shifts = ct_shifts.count(); if (maxCallTips < 0 && nr_entries > 1) { shift = (nr_shifts > 0 ? ct_shifts.first() : 0); ct = ct_entries[0]; ct.prepend('\002'); } else { if (nr_shifts > nr_entries) nr_shifts = nr_entries; // Find the biggest shift. shift = 0; for (int i = 0; i < nr_shifts; ++i) { int sh = ct_shifts[i]; if (shift < sh) shift = sh; } ct = ct_entries.join("\n"); } ScintillaBytes ct_bytes = textAsBytes(ct); const char *cts = ScintillaBytesConstData(ct_bytes); SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), cts); // Done if there is more than one call tip. if (nr_entries > 1) return; // Highlight the current argument. const char *astart; if (commas == 0) astart = strchr(cts, '('); else for (astart = strchr(cts, ','); astart && --commas > 0; astart = strchr(astart + 1, ',')) ; if (!astart || !*++astart) return; // The end is at the next comma or unmatched closing parenthesis. const char *aend; int depth = 0; for (aend = astart; *aend; ++aend) { char ch = *aend; if (ch == ',' && depth == 0) break; else if (ch == '(') ++depth; else if (ch == ')') { if (depth == 0) break; --depth; } } if (astart != aend) SendScintilla(SCI_CALLTIPSETHLT, astart - cts, aend - cts); } // Handle a call tip click. void QsciScintilla::handleCallTipClick(int dir) { int nr_entries = ct_entries.count(); // Move the cursor while bounds checking. if (dir == 1) { if (ct_cursor - 1 < 0) return; --ct_cursor; } else if (dir == 2) { if (ct_cursor + 1 >= nr_entries) return; ++ct_cursor; } else return; int shift = (ct_shifts.count() > ct_cursor ? ct_shifts[ct_cursor] : 0); QString ct = ct_entries[ct_cursor]; // Add the arrows. if (ct_cursor < nr_entries - 1) ct.prepend('\002'); if (ct_cursor > 0) ct.prepend('\001'); ScintillaBytes ct_bytes = textAsBytes(ct); const char *cts = ScintillaBytesConstData(ct_bytes); SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), cts); } // Shift the position of the call tip (to take any context into account) but // don't go before the start of the line. int QsciScintilla::adjustedCallTipPosition(int ctshift) const { int ct = ctPos; if (ctshift) { int ctmin = SendScintilla(SCI_POSITIONFROMLINE, SendScintilla(SCI_LINEFROMPOSITION, ct)); if (ct - ctshift < ctmin) ct = ctmin; } return ct; } // Return the list of words that make up the context preceding the given // position. The list will only have more than one element if there is a lexer // set and it defines start strings. If so, then the last element might be // empty if a start string has just been typed. On return pos is at the start // of the context. QStringList QsciScintilla::apiContext(int pos, int &context_start, int &last_word_start) { enum { Either, Separator, Word }; QStringList words; int good_pos = pos, expecting = Either; last_word_start = -1; while (pos > 0) { if (getSeparator(pos)) { if (expecting == Either) words.prepend(QString()); else if (expecting == Word) break; good_pos = pos; expecting = Word; } else { QString word = getWord(pos); if (word.isEmpty() || expecting == Separator) break; words.prepend(word); good_pos = pos; expecting = Separator; // Return the position of the start of the last word if required. if (last_word_start < 0) last_word_start = pos; } // Strip any preceding spaces (mainly around operators). char ch; while ((ch = getCharacter(pos)) != '\0') { // This is the same definition of space that Scintilla uses. if (ch != ' ' && (ch < 0x09 || ch > 0x0d)) { ++pos; break; } } } // A valid sequence always starts with a word and so should be expecting a // separator. if (expecting != Separator) words.clear(); context_start = good_pos; return words; } // Try and get a lexer's word separator from the text before the current // position. Return true if one was found and adjust the position accordingly. bool QsciScintilla::getSeparator(int &pos) const { int opos = pos; // Go through each separator. for (int i = 0; i < wseps.count(); ++i) { const QString &ws = wseps[i]; // Work backwards. uint l; for (l = ws.length(); l; --l) { char ch = getCharacter(pos); if (ch == '\0' || ws.at(l - 1) != ch) break; } if (!l) return true; // Reset for the next separator. pos = opos; } return false; } // Try and get a word from the text before the current position. Return the // word if one was found and adjust the position accordingly. QString QsciScintilla::getWord(int &pos) const { QString word; bool numeric = true; char ch; while ((ch = getCharacter(pos)) != '\0') { if (!isWordCharacter(ch)) { ++pos; break; } if (ch < '0' || ch > '9') numeric = false; word.prepend(ch); } // We don't auto-complete numbers. if (numeric) word.truncate(0); return word; } // Get the "next" character (ie. the one before the current position) in the // current line. The character will be '\0' if there are no more. char QsciScintilla::getCharacter(int &pos) const { if (pos <= 0) return '\0'; char ch = SendScintilla(SCI_GETCHARAT, --pos); // Don't go past the end of the previous line. if (ch == '\n' || ch == '\r') { ++pos; return '\0'; } return ch; } // See if a character is an auto-completion start character, ie. the last // character of a word separator. bool QsciScintilla::isStartChar(char ch) const { QString s = QChar(ch); for (int i = 0; i < wseps.count(); ++i) if (wseps[i].endsWith(s)) return true; return false; } // Possibly start auto-completion. void QsciScintilla::startAutoCompletion(AutoCompletionSource acs, bool checkThresh, bool choose_single) { int start, ignore; QStringList context = apiContext(SendScintilla(SCI_GETCURRENTPOS), start, ignore); if (context.isEmpty()) return; // Get the last word's raw data and length. ScintillaBytes s = textAsBytes(context.last()); const char *last_data = ScintillaBytesConstData(s); int last_len = s.length(); if (checkThresh && last_len < acThresh) return; // Generate the string representing the valid words to select from. QStringList wlist; if ((acs == AcsAll || acs == AcsAPIs) && !lex.isNull()) { QsciAbstractAPIs *apis = lex->apis(); if (apis) apis->updateAutoCompletionList(context, wlist); } if (acs == AcsAll || acs == AcsDocument) { int sflags = SCFIND_WORDSTART; if (!SendScintilla(SCI_AUTOCGETIGNORECASE)) sflags |= SCFIND_MATCHCASE; SendScintilla(SCI_SETSEARCHFLAGS, sflags); int pos = 0; int dlen = SendScintilla(SCI_GETLENGTH); int caret = SendScintilla(SCI_GETCURRENTPOS); int clen = caret - start; char *orig_context = new char[clen + 1]; SendScintilla(SCI_GETTEXTRANGE, start, caret, orig_context); for (;;) { int fstart; SendScintilla(SCI_SETTARGETSTART, pos); SendScintilla(SCI_SETTARGETEND, dlen); if ((fstart = SendScintilla(SCI_SEARCHINTARGET, clen, orig_context)) < 0) break; // Move past the root part. pos = fstart + clen; // Skip if this is the context we are auto-completing. if (pos == caret) continue; // Get the rest of this word. QString w = last_data; while (pos < dlen) { char ch = SendScintilla(SCI_GETCHARAT, pos); if (!isWordCharacter(ch)) break; w += ch; ++pos; } // Add the word if it isn't already there. if (!w.isEmpty()) { bool keep; // If there are APIs then check if the word is already present // as an API word (i.e. with a trailing space). if (acs == AcsAll) { QString api_w = w; api_w.append(' '); keep = !wlist.contains(api_w); } else { keep = true; } if (keep && !wlist.contains(w)) wlist.append(w); } } delete []orig_context; } if (wlist.isEmpty()) return; wlist.sort(); SendScintilla(SCI_AUTOCSETCHOOSESINGLE, choose_single); SendScintilla(SCI_AUTOCSETSEPARATOR, acSeparator); ScintillaBytes wlist_s = textAsBytes(wlist.join(QChar(acSeparator))); SendScintilla(SCI_AUTOCSHOW, last_len, ScintillaBytesConstData(wlist_s)); } // Maintain the indentation of the previous line. void QsciScintilla::maintainIndentation(char ch, long pos) { if (ch != '\r' && ch != '\n') return; int curr_line = SendScintilla(SCI_LINEFROMPOSITION, pos); // Get the indentation of the preceding non-zero length line. int ind = 0; for (int line = curr_line - 1; line >= 0; --line) { if (SendScintilla(SCI_GETLINEENDPOSITION, line) > SendScintilla(SCI_POSITIONFROMLINE, line)) { ind = indentation(line); break; } } if (ind > 0) autoIndentLine(pos, curr_line, ind); } // Implement auto-indentation. void QsciScintilla::autoIndentation(char ch, long pos) { int curr_line = SendScintilla(SCI_LINEFROMPOSITION, pos); int ind_width = indentWidth(); long curr_line_start = SendScintilla(SCI_POSITIONFROMLINE, curr_line); const char *block_start = lex->blockStart(); bool start_single = (block_start && qstrlen(block_start) == 1); const char *block_end = lex->blockEnd(); bool end_single = (block_end && qstrlen(block_end) == 1); if (end_single && block_end[0] == ch) { if (!(lex->autoIndentStyle() & AiClosing) && rangeIsWhitespace(curr_line_start, pos - 1)) autoIndentLine(pos, curr_line, blockIndent(curr_line - 1) - ind_width); } else if (start_single && block_start[0] == ch) { // De-indent if we have already indented because the previous line was // a start of block keyword. if (!(lex->autoIndentStyle() & AiOpening) && curr_line > 0 && getIndentState(curr_line - 1) == isKeywordStart && rangeIsWhitespace(curr_line_start, pos - 1)) autoIndentLine(pos, curr_line, blockIndent(curr_line - 1) - ind_width); } else if (ch == '\r' || ch == '\n') { // Don't auto-indent the line (ie. preserve its existing indentation) // if we have inserted a new line above by pressing return at the start // of this line - in other words, if the previous line is empty. long prev_line_length = SendScintilla(SCI_GETLINEENDPOSITION, curr_line - 1) - SendScintilla(SCI_POSITIONFROMLINE, curr_line - 1); if (prev_line_length != 0) autoIndentLine(pos, curr_line, blockIndent(curr_line - 1)); } } // Set the indentation for a line. void QsciScintilla::autoIndentLine(long pos, int line, int indent) { if (indent < 0) return; long pos_before = SendScintilla(SCI_GETLINEINDENTPOSITION, line); SendScintilla(SCI_SETLINEINDENTATION, line, indent); long pos_after = SendScintilla(SCI_GETLINEINDENTPOSITION, line); long new_pos = -1; if (pos_after > pos_before) { new_pos = pos + (pos_after - pos_before); } else if (pos_after < pos_before && pos >= pos_after) { if (pos >= pos_before) new_pos = pos + (pos_after - pos_before); else new_pos = pos_after; } if (new_pos >= 0) SendScintilla(SCI_SETSEL, new_pos, new_pos); } // Return the indentation of the block defined by the given line (or something // significant before). int QsciScintilla::blockIndent(int line) { if (line < 0) return 0; // Handle the trvial case. if (!lex->blockStartKeyword() && !lex->blockStart() && !lex->blockEnd()) return indentation(line); int line_limit = line - lex->blockLookback(); if (line_limit < 0) line_limit = 0; for (int l = line; l >= line_limit; --l) { IndentState istate = getIndentState(l); if (istate != isNone) { int ind_width = indentWidth(); int ind = indentation(l); if (istate == isBlockStart) { if (!(lex -> autoIndentStyle() & AiOpening)) ind += ind_width; } else if (istate == isBlockEnd) { if (lex -> autoIndentStyle() & AiClosing) ind -= ind_width; if (ind < 0) ind = 0; } else if (line == l) ind += ind_width; return ind; } } return indentation(line); } // Return true if all characters starting at spos up to, but not including // epos, are spaces or tabs. bool QsciScintilla::rangeIsWhitespace(long spos, long epos) { while (spos < epos) { char ch = SendScintilla(SCI_GETCHARAT, spos); if (ch != ' ' && ch != '\t') return false; ++spos; } return true; } // Returns the indentation state of a line. QsciScintilla::IndentState QsciScintilla::getIndentState(int line) { IndentState istate; // Get the styled text. long spos = SendScintilla(SCI_POSITIONFROMLINE, line); long epos = SendScintilla(SCI_POSITIONFROMLINE, line + 1); char *text = new char[(epos - spos + 1) * 2]; SendScintilla(SCI_GETSTYLEDTEXT, spos, epos, text); int style, bstart_off, bend_off; // Block start/end takes precedence over keywords. const char *bstart_words = lex->blockStart(&style); bstart_off = findStyledWord(text, style, bstart_words); const char *bend_words = lex->blockEnd(&style); bend_off = findStyledWord(text, style, bend_words); // If there is a block start but no block end characters then ignore it // unless the block start is the last significant thing on the line, ie. // assume Python-like blocking. if (bstart_off >= 0 && !bend_words) for (int i = bstart_off * 2; text[i] != '\0'; i += 2) if (!QChar(text[i]).isSpace()) return isNone; if (bstart_off > bend_off) istate = isBlockStart; else if (bend_off > bstart_off) istate = isBlockEnd; else { const char *words = lex->blockStartKeyword(&style); istate = (findStyledWord(text,style,words) >= 0) ? isKeywordStart : isNone; } delete[] text; return istate; } // text is a pointer to some styled text (ie. a character byte followed by a // style byte). style is a style number. words is a space separated list of // words. Returns the position in the text immediately after the last one of // the words with the style. The reason we are after the last, and not the // first, occurance is that we are looking for words that start and end a block // where the latest one is the most significant. int QsciScintilla::findStyledWord(const char *text, int style, const char *words) { if (!words) return -1; // Find the range of text with the style we are looking for. const char *stext; for (stext = text; stext[1] != style; stext += 2) if (stext[0] == '\0') return -1; // Move to the last character. const char *etext = stext; while (etext[2] != '\0') etext += 2; // Backtrack until we find the style. There will be one. while (etext[1] != style) etext -= 2; // Look for each word in turn. while (words[0] != '\0') { // Find the end of the word. const char *eword = words; while (eword[1] != ' ' && eword[1] != '\0') ++eword; // Now search the text backwards. const char *wp = eword; for (const char *tp = etext; tp >= stext; tp -= 2) { if (tp[0] != wp[0] || tp[1] != style) { // Reset the search. wp = eword; continue; } // See if all the word has matched. if (wp-- == words) return ((tp - text) / 2) + (eword - words) + 1; } // Move to the start of the next word if there is one. words = eword + 1; if (words[0] == ' ') ++words; } return -1; } // Return true if the code page is UTF8. bool QsciScintilla::isUtf8() const { return (SendScintilla(SCI_GETCODEPAGE) == SC_CP_UTF8); } // Set the code page. void QsciScintilla::setUtf8(bool cp) { SendScintilla(SCI_SETCODEPAGE, (cp ? SC_CP_UTF8 : 0)); } // Return the end-of-line mode. QsciScintilla::EolMode QsciScintilla::eolMode() const { return (EolMode)SendScintilla(SCI_GETEOLMODE); } // Set the end-of-line mode. void QsciScintilla::setEolMode(EolMode mode) { SendScintilla(SCI_SETEOLMODE, mode); } // Convert the end-of-lines to a particular mode. void QsciScintilla::convertEols(EolMode mode) { SendScintilla(SCI_CONVERTEOLS, mode); } // Add an edge column. void QsciScintilla::addEdgeColumn(int colnr, const QColor &col) { SendScintilla(SCI_MULTIEDGEADDLINE, colnr, col); } // Clear all multi-edge columns. void QsciScintilla::clearEdgeColumns() { SendScintilla(SCI_MULTIEDGECLEARALL); } // Return the edge colour. QColor QsciScintilla::edgeColor() const { return asQColor(SendScintilla(SCI_GETEDGECOLOUR)); } // Set the edge colour. void QsciScintilla::setEdgeColor(const QColor &col) { SendScintilla(SCI_SETEDGECOLOUR, col); } // Return the edge column. int QsciScintilla::edgeColumn() const { return SendScintilla(SCI_GETEDGECOLUMN); } // Set the edge column. void QsciScintilla::setEdgeColumn(int colnr) { SendScintilla(SCI_SETEDGECOLUMN, colnr); } // Return the edge mode. QsciScintilla::EdgeMode QsciScintilla::edgeMode() const { return (EdgeMode)SendScintilla(SCI_GETEDGEMODE); } // Set the edge mode. void QsciScintilla::setEdgeMode(EdgeMode mode) { SendScintilla(SCI_SETEDGEMODE, mode); } // Return the end-of-line visibility. bool QsciScintilla::eolVisibility() const { return SendScintilla(SCI_GETVIEWEOL); } // Set the end-of-line visibility. void QsciScintilla::setEolVisibility(bool visible) { SendScintilla(SCI_SETVIEWEOL, visible); } // Return the extra ascent. int QsciScintilla::extraAscent() const { return SendScintilla(SCI_GETEXTRAASCENT); } // Set the extra ascent. void QsciScintilla::setExtraAscent(int extra) { SendScintilla(SCI_SETEXTRAASCENT, extra); } // Return the extra descent. int QsciScintilla::extraDescent() const { return SendScintilla(SCI_GETEXTRADESCENT); } // Set the extra descent. void QsciScintilla::setExtraDescent(int extra) { SendScintilla(SCI_SETEXTRADESCENT, extra); } // Return the whitespace size. int QsciScintilla::whitespaceSize() const { return SendScintilla(SCI_GETWHITESPACESIZE); } // Set the whitespace size. void QsciScintilla::setWhitespaceSize(int size) { SendScintilla(SCI_SETWHITESPACESIZE, size); } // Set the whitespace background colour. void QsciScintilla::setWhitespaceBackgroundColor(const QColor &col) { SendScintilla(SCI_SETWHITESPACEBACK, col.isValid(), col); } // Set the whitespace foreground colour. void QsciScintilla::setWhitespaceForegroundColor(const QColor &col) { SendScintilla(SCI_SETWHITESPACEFORE, col.isValid(), col); } // Return the whitespace visibility. QsciScintilla::WhitespaceVisibility QsciScintilla::whitespaceVisibility() const { return (WhitespaceVisibility)SendScintilla(SCI_GETVIEWWS); } // Set the whitespace visibility. void QsciScintilla::setWhitespaceVisibility(WhitespaceVisibility mode) { SendScintilla(SCI_SETVIEWWS, mode); } // Return the tab draw mode. QsciScintilla::TabDrawMode QsciScintilla::tabDrawMode() const { return (TabDrawMode)SendScintilla(SCI_GETTABDRAWMODE); } // Set the tab draw mode. void QsciScintilla::setTabDrawMode(TabDrawMode mode) { SendScintilla(SCI_SETTABDRAWMODE, mode); } // Return the line wrap mode. QsciScintilla::WrapMode QsciScintilla::wrapMode() const { return (WrapMode)SendScintilla(SCI_GETWRAPMODE); } // Set the line wrap mode. void QsciScintilla::setWrapMode(WrapMode mode) { SendScintilla(SCI_SETLAYOUTCACHE, (mode == WrapNone ? SC_CACHE_CARET : SC_CACHE_DOCUMENT)); SendScintilla(SCI_SETWRAPMODE, mode); } // Return the line wrap indent mode. QsciScintilla::WrapIndentMode QsciScintilla::wrapIndentMode() const { return (WrapIndentMode)SendScintilla(SCI_GETWRAPINDENTMODE); } // Set the line wrap indent mode. void QsciScintilla::setWrapIndentMode(WrapIndentMode mode) { SendScintilla(SCI_SETWRAPINDENTMODE, mode); } // Set the line wrap visual flags. void QsciScintilla::setWrapVisualFlags(WrapVisualFlag endFlag, WrapVisualFlag startFlag, int indent) { int flags = SC_WRAPVISUALFLAG_NONE; int loc = SC_WRAPVISUALFLAGLOC_DEFAULT; switch (endFlag) { case WrapFlagNone: break; case WrapFlagByText: flags |= SC_WRAPVISUALFLAG_END; loc |= SC_WRAPVISUALFLAGLOC_END_BY_TEXT; break; case WrapFlagByBorder: flags |= SC_WRAPVISUALFLAG_END; break; case WrapFlagInMargin: flags |= SC_WRAPVISUALFLAG_MARGIN; break; } switch (startFlag) { case WrapFlagNone: break; case WrapFlagByText: flags |= SC_WRAPVISUALFLAG_START; loc |= SC_WRAPVISUALFLAGLOC_START_BY_TEXT; break; case WrapFlagByBorder: flags |= SC_WRAPVISUALFLAG_START; break; case WrapFlagInMargin: flags |= SC_WRAPVISUALFLAG_MARGIN; break; } SendScintilla(SCI_SETWRAPVISUALFLAGS, flags); SendScintilla(SCI_SETWRAPVISUALFLAGSLOCATION, loc); SendScintilla(SCI_SETWRAPSTARTINDENT, indent); } // Set the folding style. void QsciScintilla::setFolding(FoldStyle folding, int margin) { fold = folding; foldmargin = margin; if (folding == NoFoldStyle) { SendScintilla(SCI_SETMARGINWIDTHN, margin, 0L); return; } int mask = SendScintilla(SCI_GETMODEVENTMASK); SendScintilla(SCI_SETMODEVENTMASK, mask | SC_MOD_CHANGEFOLD); SendScintilla(SCI_SETFOLDFLAGS, SC_FOLDFLAG_LINEAFTER_CONTRACTED); SendScintilla(SCI_SETMARGINTYPEN, margin, (long)SC_MARGIN_SYMBOL); SendScintilla(SCI_SETMARGINMASKN, margin, SC_MASK_FOLDERS); SendScintilla(SCI_SETMARGINSENSITIVEN, margin, 1); // Set the marker symbols to use. switch (folding) { case NoFoldStyle: break; case PlainFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_MINUS); setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_PLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB); setFoldMarker(SC_MARKNUM_FOLDERTAIL); setFoldMarker(SC_MARKNUM_FOLDEREND); setFoldMarker(SC_MARKNUM_FOLDEROPENMID); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL); break; case CircledFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS); setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB); setFoldMarker(SC_MARKNUM_FOLDERTAIL); setFoldMarker(SC_MARKNUM_FOLDEREND); setFoldMarker(SC_MARKNUM_FOLDEROPENMID); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL); break; case BoxedFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS); setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB); setFoldMarker(SC_MARKNUM_FOLDERTAIL); setFoldMarker(SC_MARKNUM_FOLDEREND); setFoldMarker(SC_MARKNUM_FOLDEROPENMID); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL); break; case CircledTreeFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS); setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE); setFoldMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE); setFoldMarker(SC_MARKNUM_FOLDEREND, SC_MARK_CIRCLEPLUSCONNECTED); setFoldMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_CIRCLEMINUSCONNECTED); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE); break; case BoxedTreeFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS); setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE); setFoldMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER); setFoldMarker(SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED); setFoldMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER); break; } SendScintilla(SCI_SETMARGINWIDTHN, margin, defaultFoldMarginWidth); } // Clear all current folds. void QsciScintilla::clearFolds() { recolor(); int maxLine = SendScintilla(SCI_GETLINECOUNT); for (int line = 0; line < maxLine; line++) { int level = SendScintilla(SCI_GETFOLDLEVEL, line); if (level & SC_FOLDLEVELHEADERFLAG) { SendScintilla(SCI_SETFOLDEXPANDED, line, 1); foldExpand(line, true, false, 0, level); line--; } } } // Set up a folder marker. void QsciScintilla::setFoldMarker(int marknr, int mark) { SendScintilla(SCI_MARKERDEFINE, marknr, mark); if (mark != SC_MARK_EMPTY) { SendScintilla(SCI_MARKERSETFORE, marknr, QColor(Qt::white)); SendScintilla(SCI_MARKERSETBACK, marknr, QColor(Qt::black)); } } // Handle a click in the fold margin. This is mostly taken from SciTE. void QsciScintilla::foldClick(int lineClick, int bstate) { bool shift = bstate & Qt::ShiftModifier; bool ctrl = bstate & Qt::ControlModifier; if (shift && ctrl) { foldAll(); return; } int levelClick = SendScintilla(SCI_GETFOLDLEVEL, lineClick); if (levelClick & SC_FOLDLEVELHEADERFLAG) { if (shift) { // Ensure all children are visible. SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 1); foldExpand(lineClick, true, true, 100, levelClick); } else if (ctrl) { if (SendScintilla(SCI_GETFOLDEXPANDED, lineClick)) { // Contract this line and all its children. SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 0L); foldExpand(lineClick, false, true, 0, levelClick); } else { // Expand this line and all its children. SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 1); foldExpand(lineClick, true, true, 100, levelClick); } } else { // Toggle this line. SendScintilla(SCI_TOGGLEFOLD, lineClick); } } } // Do the hard work of hiding and showing lines. This is mostly taken from // SciTE. void QsciScintilla::foldExpand(int &line, bool doExpand, bool force, int visLevels, int level) { int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD, line, level & SC_FOLDLEVELNUMBERMASK); line++; while (line <= lineMaxSubord) { if (force) { if (visLevels > 0) SendScintilla(SCI_SHOWLINES, line, line); else SendScintilla(SCI_HIDELINES, line, line); } else if (doExpand) SendScintilla(SCI_SHOWLINES, line, line); int levelLine = level; if (levelLine == -1) levelLine = SendScintilla(SCI_GETFOLDLEVEL, line); if (levelLine & SC_FOLDLEVELHEADERFLAG) { if (force) { if (visLevels > 1) SendScintilla(SCI_SETFOLDEXPANDED, line, 1); else SendScintilla(SCI_SETFOLDEXPANDED, line, 0L); foldExpand(line, doExpand, force, visLevels - 1); } else if (doExpand) { if (!SendScintilla(SCI_GETFOLDEXPANDED, line)) SendScintilla(SCI_SETFOLDEXPANDED, line, 1); foldExpand(line, true, force, visLevels - 1); } else foldExpand(line, false, force, visLevels - 1); } else line++; } } // Fully expand (if there is any line currently folded) all text. Otherwise, // fold all text. This is mostly taken from SciTE. void QsciScintilla::foldAll(bool children) { recolor(); int maxLine = SendScintilla(SCI_GETLINECOUNT); bool expanding = true; for (int lineSeek = 0; lineSeek < maxLine; lineSeek++) { if (SendScintilla(SCI_GETFOLDLEVEL,lineSeek) & SC_FOLDLEVELHEADERFLAG) { expanding = !SendScintilla(SCI_GETFOLDEXPANDED, lineSeek); break; } } for (int line = 0; line < maxLine; line++) { int level = SendScintilla(SCI_GETFOLDLEVEL, line); if (!(level & SC_FOLDLEVELHEADERFLAG)) continue; if (children || (SC_FOLDLEVELBASE == (level & SC_FOLDLEVELNUMBERMASK))) { if (expanding) { SendScintilla(SCI_SETFOLDEXPANDED, line, 1); foldExpand(line, true, false, 0, level); line--; } else { int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD, line, -1); SendScintilla(SCI_SETFOLDEXPANDED, line, 0L); if (lineMaxSubord > line) SendScintilla(SCI_HIDELINES, line + 1, lineMaxSubord); } } } } // Handle a fold change. This is mostly taken from SciTE. void QsciScintilla::foldChanged(int line,int levelNow,int levelPrev) { if (levelNow & SC_FOLDLEVELHEADERFLAG) { if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) SendScintilla(SCI_SETFOLDEXPANDED, line, 1); } else if (levelPrev & SC_FOLDLEVELHEADERFLAG) { if (!SendScintilla(SCI_GETFOLDEXPANDED, line)) { // Removing the fold from one that has been contracted so should // expand. Otherwise lines are left invisible with no way to make // them visible. foldExpand(line, true, false, 0, levelPrev); } } } // Toggle the fold for a line if it contains a fold marker. void QsciScintilla::foldLine(int line) { SendScintilla(SCI_TOGGLEFOLD, line); } // Return the list of folded lines. QList QsciScintilla::contractedFolds() const { QList folds; int linenr = 0, fold_line; while ((fold_line = SendScintilla(SCI_CONTRACTEDFOLDNEXT, linenr)) >= 0) { folds.append(fold_line); linenr = fold_line + 1; } return folds; } // Set the fold state from a list. void QsciScintilla::setContractedFolds(const QList &folds) { for (int i = 0; i < folds.count(); ++i) { int line = folds[i]; int last_line = SendScintilla(SCI_GETLASTCHILD, line, -1); SendScintilla(SCI_SETFOLDEXPANDED, line, 0L); SendScintilla(SCI_HIDELINES, line + 1, last_line); } } // Handle the SCN_MODIFIED notification. void QsciScintilla::handleModified(int pos, int mtype, const char *text, int len, int added, int line, int foldNow, int foldPrev, int token, int annotationLinesAdded) { Q_UNUSED(pos); Q_UNUSED(text); Q_UNUSED(len); Q_UNUSED(token); Q_UNUSED(annotationLinesAdded); if (mtype & SC_MOD_CHANGEFOLD) { if (fold) foldChanged(line, foldNow, foldPrev); } if (mtype & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { emit textChanged(); if (added != 0) emit linesChanged(); } } // Zoom in a number of points. void QsciScintilla::zoomIn(int range) { zoomTo(SendScintilla(SCI_GETZOOM) + range); } // Zoom in a single point. void QsciScintilla::zoomIn() { SendScintilla(SCI_ZOOMIN); } // Zoom out a number of points. void QsciScintilla::zoomOut(int range) { zoomTo(SendScintilla(SCI_GETZOOM) - range); } // Zoom out a single point. void QsciScintilla::zoomOut() { SendScintilla(SCI_ZOOMOUT); } // Set the zoom to a number of points. void QsciScintilla::zoomTo(int size) { if (size < -10) size = -10; else if (size > 20) size = 20; SendScintilla(SCI_SETZOOM, size); } // Find the first occurrence of a string. bool QsciScintilla::findFirst(const QString &expr, bool re, bool cs, bool wo, bool wrap, bool forward, int line, int index, bool show, bool posix, bool cxx11) { if (expr.isEmpty()) { findState.status = FindState::Idle; return false; } findState.status = FindState::Finding; findState.expr = expr; findState.wrap = wrap; findState.forward = forward; findState.flags = (cs ? SCFIND_MATCHCASE : 0) | (wo ? SCFIND_WHOLEWORD : 0) | (re ? SCFIND_REGEXP : 0) | (posix ? SCFIND_POSIX : 0) | (cxx11 ? SCFIND_CXX11REGEX : 0); if (line < 0 || index < 0) findState.startpos = SendScintilla(SCI_GETCURRENTPOS); else findState.startpos = positionFromLineIndex(line, index); if (forward) findState.endpos = SendScintilla(SCI_GETLENGTH); else findState.endpos = 0; findState.show = show; return doFind(); } // Find the first occurrence of a string in the current selection. bool QsciScintilla::findFirstInSelection(const QString &expr, bool re, bool cs, bool wo, bool forward, bool show, bool posix, bool cxx11) { if (expr.isEmpty()) { findState.status = FindState::Idle; return false; } findState.status = FindState::FindingInSelection; findState.expr = expr; findState.wrap = false; findState.forward = forward; findState.flags = (cs ? SCFIND_MATCHCASE : 0) | (wo ? SCFIND_WHOLEWORD : 0) | (re ? SCFIND_REGEXP : 0) | (posix ? SCFIND_POSIX : 0) | (cxx11 ? SCFIND_CXX11REGEX : 0); findState.startpos_orig = SendScintilla(SCI_GETSELECTIONSTART); findState.endpos_orig = SendScintilla(SCI_GETSELECTIONEND); if (forward) { findState.startpos = findState.startpos_orig; findState.endpos = findState.endpos_orig; } else { findState.startpos = findState.endpos_orig; findState.endpos = findState.startpos_orig; } findState.show = show; return doFind(); } // Cancel any current search. void QsciScintilla::cancelFind() { findState.status = FindState::Idle; } // Find the next occurrence of a string. bool QsciScintilla::findNext() { if (findState.status == FindState::Idle) return false; return doFind(); } // Do the hard work of the find methods. bool QsciScintilla::doFind() { SendScintilla(SCI_SETSEARCHFLAGS, findState.flags); int pos = simpleFind(); // See if it was found. If not and wraparound is wanted, try again. if (pos == -1 && findState.wrap) { if (findState.forward) { findState.startpos = 0; findState.endpos = SendScintilla(SCI_GETLENGTH); } else { findState.startpos = SendScintilla(SCI_GETLENGTH); findState.endpos = 0; } pos = simpleFind(); } if (pos == -1) { // Restore the original selection. if (findState.status == FindState::FindingInSelection) SendScintilla(SCI_SETSEL, findState.startpos_orig, findState.endpos_orig); findState.status = FindState::Idle; return false; } // It was found. long targstart = SendScintilla(SCI_GETTARGETSTART); long targend = SendScintilla(SCI_GETTARGETEND); // Ensure the text found is visible if required. if (findState.show) { int startLine = SendScintilla(SCI_LINEFROMPOSITION, targstart); int endLine = SendScintilla(SCI_LINEFROMPOSITION, targend); for (int i = startLine; i <= endLine; ++i) SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY, i); } // Now set the selection. SendScintilla(SCI_SETSEL, targstart, targend); // Finally adjust the start position so that we don't find the same one // again. if (findState.forward) findState.startpos = targend; else if ((findState.startpos = targstart - 1) < 0) findState.startpos = 0; return true; } // Do a simple find between the start and end positions. int QsciScintilla::simpleFind() { if (findState.startpos == findState.endpos) return -1; SendScintilla(SCI_SETTARGETSTART, findState.startpos); SendScintilla(SCI_SETTARGETEND, findState.endpos); ScintillaBytes s = textAsBytes(findState.expr); return SendScintilla(SCI_SEARCHINTARGET, s.length(), ScintillaBytesConstData(s)); } // Replace the text found with the previous find method. void QsciScintilla::replace(const QString &replaceStr) { if (findState.status == FindState::Idle) return; long start = SendScintilla(SCI_GETSELECTIONSTART); long orig_len = SendScintilla(SCI_GETSELECTIONEND) - start; SendScintilla(SCI_TARGETFROMSELECTION); int cmd = (findState.flags & SCFIND_REGEXP) ? SCI_REPLACETARGETRE : SCI_REPLACETARGET; ScintillaBytes s = textAsBytes(replaceStr); long len = SendScintilla(cmd, -1, ScintillaBytesConstData(s)); // Reset the selection. SendScintilla(SCI_SETSELECTIONSTART, start); SendScintilla(SCI_SETSELECTIONEND, start + len); // Fix the original selection. findState.endpos_orig += (len - orig_len); if (findState.forward) findState.startpos = start + len; } // Query the modified state. bool QsciScintilla::isModified() const { return doc.isModified(); } // Set the modified state. void QsciScintilla::setModified(bool m) { if (!m) SendScintilla(SCI_SETSAVEPOINT); } // Handle the SCN_INDICATORCLICK notification. void QsciScintilla::handleIndicatorClick(int pos, int modifiers) { int state = mapModifiers(modifiers); int line, index; lineIndexFromPosition(pos, &line, &index); emit indicatorClicked(line, index, Qt::KeyboardModifiers(state)); } // Handle the SCN_INDICATORRELEASE notification. void QsciScintilla::handleIndicatorRelease(int pos, int modifiers) { int state = mapModifiers(modifiers); int line, index; lineIndexFromPosition(pos, &line, &index); emit indicatorReleased(line, index, Qt::KeyboardModifiers(state)); } // Handle the SCN_MARGINCLICK notification. void QsciScintilla::handleMarginClick(int pos, int modifiers, int margin) { int state = mapModifiers(modifiers); int line = SendScintilla(SCI_LINEFROMPOSITION, pos); if (fold && margin == foldmargin) foldClick(line, state); else emit marginClicked(margin, line, Qt::KeyboardModifiers(state)); } // Handle the SCN_MARGINRIGHTCLICK notification. void QsciScintilla::handleMarginRightClick(int pos, int modifiers, int margin) { int state = mapModifiers(modifiers); int line = SendScintilla(SCI_LINEFROMPOSITION, pos); emit marginRightClicked(margin, line, Qt::KeyboardModifiers(state)); } // Handle the SCN_SAVEPOINTREACHED notification. void QsciScintilla::handleSavePointReached() { doc.setModified(false); emit modificationChanged(false); } // Handle the SCN_SAVEPOINTLEFT notification. void QsciScintilla::handleSavePointLeft() { doc.setModified(true); emit modificationChanged(true); } // Handle the QSCN_SELCHANGED signal. void QsciScintilla::handleSelectionChanged(bool yes) { selText = yes; emit copyAvailable(yes); emit selectionChanged(); } // Get the current selection. void QsciScintilla::getSelection(int *lineFrom, int *indexFrom, int *lineTo, int *indexTo) const { if (selText) { lineIndexFromPosition(SendScintilla(SCI_GETSELECTIONSTART), lineFrom, indexFrom); lineIndexFromPosition(SendScintilla(SCI_GETSELECTIONEND), lineTo, indexTo); } else *lineFrom = *indexFrom = *lineTo = *indexTo = -1; } // Sets the current selection. void QsciScintilla::setSelection(int lineFrom, int indexFrom, int lineTo, int indexTo) { SendScintilla(SCI_SETSEL, positionFromLineIndex(lineFrom, indexFrom), positionFromLineIndex(lineTo, indexTo)); } // Set the background colour of selected text. void QsciScintilla::setSelectionBackgroundColor(const QColor &col) { int alpha = col.alpha(); if (alpha == 255) alpha = SC_ALPHA_NOALPHA; SendScintilla(SCI_SETSELBACK, 1, col); SendScintilla(SCI_SETSELALPHA, alpha); } // Set the foreground colour of selected text. void QsciScintilla::setSelectionForegroundColor(const QColor &col) { SendScintilla(SCI_SETSELFORE, 1, col); } // Reset the background colour of selected text to the default. void QsciScintilla::resetSelectionBackgroundColor() { SendScintilla(SCI_SETSELALPHA, SC_ALPHA_NOALPHA); SendScintilla(SCI_SETSELBACK, 0UL); } // Reset the foreground colour of selected text to the default. void QsciScintilla::resetSelectionForegroundColor() { SendScintilla(SCI_SETSELFORE, 0UL); } // Set the fill to the end-of-line for the selection. void QsciScintilla::setSelectionToEol(bool filled) { SendScintilla(SCI_SETSELEOLFILLED, filled); } // Return the fill to the end-of-line for the selection. bool QsciScintilla::selectionToEol() const { return SendScintilla(SCI_GETSELEOLFILLED); } // Set the width of the caret. void QsciScintilla::setCaretWidth(int width) { SendScintilla(SCI_SETCARETWIDTH, width); } // Set the width of the frame of the line containing the caret. void QsciScintilla::setCaretLineFrameWidth(int width) { SendScintilla(SCI_SETCARETLINEFRAME, width); } // Set the foreground colour of the caret. void QsciScintilla::setCaretForegroundColor(const QColor &col) { SendScintilla(SCI_SETCARETFORE, col); } // Set the background colour of the line containing the caret. void QsciScintilla::setCaretLineBackgroundColor(const QColor &col) { int alpha = col.alpha(); if (alpha == 255) alpha = SC_ALPHA_NOALPHA; SendScintilla(SCI_SETCARETLINEBACK, col); SendScintilla(SCI_SETCARETLINEBACKALPHA, alpha); } // Set the state of the background colour of the line containing the caret. void QsciScintilla::setCaretLineVisible(bool enable) { SendScintilla(SCI_SETCARETLINEVISIBLE, enable); } // Set the background colour of a hotspot area. void QsciScintilla::setHotspotBackgroundColor(const QColor &col) { SendScintilla(SCI_SETHOTSPOTACTIVEBACK, 1, col); } // Set the foreground colour of a hotspot area. void QsciScintilla::setHotspotForegroundColor(const QColor &col) { SendScintilla(SCI_SETHOTSPOTACTIVEFORE, 1, col); } // Reset the background colour of a hotspot area to the default. void QsciScintilla::resetHotspotBackgroundColor() { SendScintilla(SCI_SETHOTSPOTACTIVEBACK, 0UL); } // Reset the foreground colour of a hotspot area to the default. void QsciScintilla::resetHotspotForegroundColor() { SendScintilla(SCI_SETHOTSPOTACTIVEFORE, 0UL); } // Set the underline of a hotspot area. void QsciScintilla::setHotspotUnderline(bool enable) { SendScintilla(SCI_SETHOTSPOTACTIVEUNDERLINE, enable); } // Set the wrapping of a hotspot area. void QsciScintilla::setHotspotWrap(bool enable) { SendScintilla(SCI_SETHOTSPOTSINGLELINE, !enable); } // Query the read-only state. bool QsciScintilla::isReadOnly() const { return SendScintilla(SCI_GETREADONLY); } // Set the read-only state. void QsciScintilla::setReadOnly(bool ro) { setAttribute(Qt::WA_InputMethodEnabled, !ro); SendScintilla(SCI_SETREADONLY, ro); } // Append the given text. void QsciScintilla::append(const QString &text) { bool ro = ensureRW(); ScintillaBytes s = textAsBytes(text); SendScintilla(SCI_APPENDTEXT, s.length(), ScintillaBytesConstData(s)); SendScintilla(SCI_EMPTYUNDOBUFFER); setReadOnly(ro); } // Insert the given text at the current position. void QsciScintilla::insert(const QString &text) { insertAtPos(text, -1); } // Insert the given text at the given line and offset. void QsciScintilla::insertAt(const QString &text, int line, int index) { insertAtPos(text, positionFromLineIndex(line, index)); } // Insert the given text at the given position. void QsciScintilla::insertAtPos(const QString &text, int pos) { bool ro = ensureRW(); SendScintilla(SCI_BEGINUNDOACTION); SendScintilla(SCI_INSERTTEXT, pos, ScintillaBytesConstData(textAsBytes(text))); SendScintilla(SCI_ENDUNDOACTION); setReadOnly(ro); } // Begin a sequence of undoable actions. void QsciScintilla::beginUndoAction() { SendScintilla(SCI_BEGINUNDOACTION); } // End a sequence of undoable actions. void QsciScintilla::endUndoAction() { SendScintilla(SCI_ENDUNDOACTION); } // Redo a sequence of actions. void QsciScintilla::redo() { SendScintilla(SCI_REDO); } // Undo a sequence of actions. void QsciScintilla::undo() { SendScintilla(SCI_UNDO); } // See if there is something to redo. bool QsciScintilla::isRedoAvailable() const { return SendScintilla(SCI_CANREDO); } // See if there is something to undo. bool QsciScintilla::isUndoAvailable() const { return SendScintilla(SCI_CANUNDO); } // Return the number of lines. int QsciScintilla::lines() const { return SendScintilla(SCI_GETLINECOUNT); } // Return the line at a position. int QsciScintilla::lineAt(const QPoint &pos) const { long chpos = SendScintilla(SCI_POSITIONFROMPOINTCLOSE, pos.x(), pos.y()); if (chpos < 0) return -1; return SendScintilla(SCI_LINEFROMPOSITION, chpos); } // Return the length of a line. int QsciScintilla::lineLength(int line) const { if (line < 0 || line >= SendScintilla(SCI_GETLINECOUNT)) return -1; return SendScintilla(SCI_LINELENGTH, line); } // Return the length of the current text. int QsciScintilla::length() const { return SendScintilla(SCI_GETTEXTLENGTH); } // Remove any selected text. void QsciScintilla::removeSelectedText() { SendScintilla(SCI_REPLACESEL, ""); } // Replace any selected text. void QsciScintilla::replaceSelectedText(const QString &text) { SendScintilla(SCI_REPLACESEL, ScintillaBytesConstData(textAsBytes(text))); } // Return the current selected text. QString QsciScintilla::selectedText() const { if (!selText) return QString(); char *buf = new char[SendScintilla(SCI_GETSELECTIONEND) - SendScintilla(SCI_GETSELECTIONSTART) + 1]; SendScintilla(SCI_GETSELTEXT, buf); QString qs = bytesAsText(buf); delete[] buf; return qs; } // Return the current text. QString QsciScintilla::text() const { int buflen = length() + 1; char *buf = new char[buflen]; SendScintilla(SCI_GETTEXT, buflen, buf); QString qs = bytesAsText(buf); delete[] buf; return qs; } // Return the text of a line. QString QsciScintilla::text(int line) const { int line_len = lineLength(line); if (line_len < 1) return QString(); char *buf = new char[line_len + 1]; SendScintilla(SCI_GETLINE, line, buf); buf[line_len] = '\0'; QString qs = bytesAsText(buf); delete[] buf; return qs; } // Return the text between two positions. QString QsciScintilla::text(int start, int end) const { char *buf = new char[end - start + 1]; SendScintilla(SCI_GETTEXTRANGE, start, end, buf); QString text = bytesAsText(buf); delete[] buf; return text; } // Return the text as encoded bytes between two positions. QByteArray QsciScintilla::bytes(int start, int end) const { QByteArray bytes(end - start + 1, '\0'); SendScintilla(SCI_GETTEXTRANGE, start, end, bytes.data()); return bytes; } // Set the given text. void QsciScintilla::setText(const QString &text) { bool ro = ensureRW(); SendScintilla(SCI_SETTEXT, ScintillaBytesConstData(textAsBytes(text))); SendScintilla(SCI_EMPTYUNDOBUFFER); setReadOnly(ro); } // Get the cursor position void QsciScintilla::getCursorPosition(int *line, int *index) const { lineIndexFromPosition(SendScintilla(SCI_GETCURRENTPOS), line, index); } // Set the cursor position void QsciScintilla::setCursorPosition(int line, int index) { SendScintilla(SCI_GOTOPOS, positionFromLineIndex(line, index)); } // Ensure the cursor is visible. void QsciScintilla::ensureCursorVisible() { SendScintilla(SCI_SCROLLCARET); } // Ensure a line is visible. void QsciScintilla::ensureLineVisible(int line) { SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY, line); } // Copy text to the clipboard. void QsciScintilla::copy() { SendScintilla(SCI_COPY); } // Cut text to the clipboard. void QsciScintilla::cut() { SendScintilla(SCI_CUT); } // Paste text from the clipboard. void QsciScintilla::paste() { SendScintilla(SCI_PASTE); } // Select all text, or deselect any selected text. void QsciScintilla::selectAll(bool select) { if (select) SendScintilla(SCI_SELECTALL); else SendScintilla(SCI_SETANCHOR, SendScintilla(SCI_GETCURRENTPOS)); } // Delete all text. void QsciScintilla::clear() { bool ro = ensureRW(); SendScintilla(SCI_BEGINUNDOACTION); SendScintilla(SCI_CLEARALL); SendScintilla(SCI_ENDUNDOACTION); setReadOnly(ro); } // Return the indentation of a line. int QsciScintilla::indentation(int line) const { return SendScintilla(SCI_GETLINEINDENTATION, line); } // Set the indentation of a line. void QsciScintilla::setIndentation(int line, int indentation) { SendScintilla(SCI_BEGINUNDOACTION); SendScintilla(SCI_SETLINEINDENTATION, line, indentation); SendScintilla(SCI_ENDUNDOACTION); } // Indent a line. void QsciScintilla::indent(int line) { setIndentation(line, indentation(line) + indentWidth()); } // Unindent a line. void QsciScintilla::unindent(int line) { int newIndent = indentation(line) - indentWidth(); if (newIndent < 0) newIndent = 0; setIndentation(line, newIndent); } // Return the indentation of the current line. int QsciScintilla::currentIndent() const { return indentation(SendScintilla(SCI_LINEFROMPOSITION, SendScintilla(SCI_GETCURRENTPOS))); } // Return the current indentation width. int QsciScintilla::indentWidth() const { int w = indentationWidth(); if (w == 0) w = tabWidth(); return w; } // Return the state of indentation guides. bool QsciScintilla::indentationGuides() const { return (SendScintilla(SCI_GETINDENTATIONGUIDES) != SC_IV_NONE); } // Enable and disable indentation guides. void QsciScintilla::setIndentationGuides(bool enable) { int iv; if (!enable) iv = SC_IV_NONE; else if (lex.isNull()) iv = SC_IV_REAL; else iv = lex->indentationGuideView(); SendScintilla(SCI_SETINDENTATIONGUIDES, iv); } // Set the background colour of indentation guides. void QsciScintilla::setIndentationGuidesBackgroundColor(const QColor &col) { SendScintilla(SCI_STYLESETBACK, STYLE_INDENTGUIDE, col); } // Set the foreground colour of indentation guides. void QsciScintilla::setIndentationGuidesForegroundColor(const QColor &col) { SendScintilla(SCI_STYLESETFORE, STYLE_INDENTGUIDE, col); } // Return the indentation width. int QsciScintilla::indentationWidth() const { return SendScintilla(SCI_GETINDENT); } // Set the indentation width. void QsciScintilla::setIndentationWidth(int width) { SendScintilla(SCI_SETINDENT, width); } // Return the tab width. int QsciScintilla::tabWidth() const { return SendScintilla(SCI_GETTABWIDTH); } // Set the tab width. void QsciScintilla::setTabWidth(int width) { SendScintilla(SCI_SETTABWIDTH, width); } // Return the effect of the backspace key. bool QsciScintilla::backspaceUnindents() const { return SendScintilla(SCI_GETBACKSPACEUNINDENTS); } // Set the effect of the backspace key. void QsciScintilla::setBackspaceUnindents(bool unindents) { SendScintilla(SCI_SETBACKSPACEUNINDENTS, unindents); } // Return the effect of the tab key. bool QsciScintilla::tabIndents() const { return SendScintilla(SCI_GETTABINDENTS); } // Set the effect of the tab key. void QsciScintilla::setTabIndents(bool indents) { SendScintilla(SCI_SETTABINDENTS, indents); } // Return the indentation use of tabs. bool QsciScintilla::indentationsUseTabs() const { return SendScintilla(SCI_GETUSETABS); } // Set the indentation use of tabs. void QsciScintilla::setIndentationsUseTabs(bool tabs) { SendScintilla(SCI_SETUSETABS, tabs); } // Return the number of margins. int QsciScintilla::margins() const { return SendScintilla(SCI_GETMARGINS); } // Set the number of margins. void QsciScintilla::setMargins(int margins) { SendScintilla(SCI_SETMARGINS, margins); } // Return the margin background colour. QColor QsciScintilla::marginBackgroundColor(int margin) const { return asQColor(SendScintilla(SCI_GETMARGINBACKN, margin)); } // Set the margin background colour. void QsciScintilla::setMarginBackgroundColor(int margin, const QColor &col) { SendScintilla(SCI_SETMARGINBACKN, margin, col); } // Return the margin options. int QsciScintilla::marginOptions() const { return SendScintilla(SCI_GETMARGINOPTIONS); } // Set the margin options. void QsciScintilla::setMarginOptions(int options) { SendScintilla(SCI_SETMARGINOPTIONS, options); } // Return the margin type. QsciScintilla::MarginType QsciScintilla::marginType(int margin) const { return (MarginType)SendScintilla(SCI_GETMARGINTYPEN, margin); } // Set the margin type. void QsciScintilla::setMarginType(int margin, QsciScintilla::MarginType type) { SendScintilla(SCI_SETMARGINTYPEN, margin, type); } // Clear margin text. void QsciScintilla::clearMarginText(int line) { if (line < 0) SendScintilla(SCI_MARGINTEXTCLEARALL); else SendScintilla(SCI_MARGINSETTEXT, line, (const char *)0); } // Annotate a line. void QsciScintilla::setMarginText(int line, const QString &text, int style) { int style_offset = SendScintilla(SCI_MARGINGETSTYLEOFFSET); SendScintilla(SCI_MARGINSETTEXT, line, ScintillaBytesConstData(textAsBytes(text))); SendScintilla(SCI_MARGINSETSTYLE, line, style - style_offset); } // Annotate a line. void QsciScintilla::setMarginText(int line, const QString &text, const QsciStyle &style) { style.apply(this); setMarginText(line, text, style.style()); } // Annotate a line. void QsciScintilla::setMarginText(int line, const QsciStyledText &text) { text.apply(this); setMarginText(line, text.text(), text.style()); } // Annotate a line. void QsciScintilla::setMarginText(int line, const QList &text) { char *styles; ScintillaBytes styled_text = styleText(text, &styles, SendScintilla(SCI_MARGINGETSTYLEOFFSET)); SendScintilla(SCI_MARGINSETTEXT, line, ScintillaBytesConstData(styled_text)); SendScintilla(SCI_MARGINSETSTYLES, line, styles); delete[] styles; } // Return the state of line numbers in a margin. bool QsciScintilla::marginLineNumbers(int margin) const { return SendScintilla(SCI_GETMARGINTYPEN, margin); } // Enable and disable line numbers in a margin. void QsciScintilla::setMarginLineNumbers(int margin, bool lnrs) { SendScintilla(SCI_SETMARGINTYPEN, margin, lnrs ? SC_MARGIN_NUMBER : SC_MARGIN_SYMBOL); } // Return the marker mask of a margin. int QsciScintilla::marginMarkerMask(int margin) const { return SendScintilla(SCI_GETMARGINMASKN, margin); } // Set the marker mask of a margin. void QsciScintilla::setMarginMarkerMask(int margin,int mask) { SendScintilla(SCI_SETMARGINMASKN, margin, mask); } // Return the state of a margin's sensitivity. bool QsciScintilla::marginSensitivity(int margin) const { return SendScintilla(SCI_GETMARGINSENSITIVEN, margin); } // Enable and disable a margin's sensitivity. void QsciScintilla::setMarginSensitivity(int margin,bool sens) { SendScintilla(SCI_SETMARGINSENSITIVEN, margin, sens); } // Return the width of a margin. int QsciScintilla::marginWidth(int margin) const { return SendScintilla(SCI_GETMARGINWIDTHN, margin); } // Set the width of a margin. void QsciScintilla::setMarginWidth(int margin, int width) { SendScintilla(SCI_SETMARGINWIDTHN, margin, width); } // Set the width of a margin to the width of some text. void QsciScintilla::setMarginWidth(int margin, const QString &s) { int width = SendScintilla(SCI_TEXTWIDTH, STYLE_LINENUMBER, ScintillaBytesConstData(textAsBytes(s))); setMarginWidth(margin, width); } // Set the background colour of all margins. void QsciScintilla::setMarginsBackgroundColor(const QColor &col) { handleStylePaperChange(col, STYLE_LINENUMBER); } // Set the foreground colour of all margins. void QsciScintilla::setMarginsForegroundColor(const QColor &col) { handleStyleColorChange(col, STYLE_LINENUMBER); } // Set the font of all margins. void QsciScintilla::setMarginsFont(const QFont &f) { setStylesFont(f, STYLE_LINENUMBER); } // Define an indicator. int QsciScintilla::indicatorDefine(IndicatorStyle style, int indicatorNumber) { checkIndicator(indicatorNumber); if (indicatorNumber >= 0) SendScintilla(SCI_INDICSETSTYLE, indicatorNumber, static_cast(style)); return indicatorNumber; } // Return the state of an indicator being drawn under the text. bool QsciScintilla::indicatorDrawUnder(int indicatorNumber) const { if (indicatorNumber < 0 || indicatorNumber >= INDIC_IME) return false; return SendScintilla(SCI_INDICGETUNDER, indicatorNumber); } // Set the state of indicators being drawn under the text. void QsciScintilla::setIndicatorDrawUnder(bool under, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) SendScintilla(SCI_INDICSETUNDER, i, under); } else { SendScintilla(SCI_INDICSETUNDER, indicatorNumber, under); } } } // Set the indicator foreground colour. void QsciScintilla::setIndicatorForegroundColor(const QColor &col, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { int alpha = col.alpha(); // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) { SendScintilla(SCI_INDICSETFORE, i, col); SendScintilla(SCI_INDICSETALPHA, i, alpha); } } else { SendScintilla(SCI_INDICSETFORE, indicatorNumber, col); SendScintilla(SCI_INDICSETALPHA, indicatorNumber, alpha); } } } // Set the indicator hover foreground colour. void QsciScintilla::setIndicatorHoverForegroundColor(const QColor &col, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) SendScintilla(SCI_INDICSETHOVERFORE, i, col); } else { SendScintilla(SCI_INDICSETHOVERFORE, indicatorNumber, col); } } } // Set the indicator hover style. void QsciScintilla::setIndicatorHoverStyle(IndicatorStyle style, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) SendScintilla(SCI_INDICSETHOVERSTYLE, i, static_cast(style)); } else { SendScintilla(SCI_INDICSETHOVERSTYLE, indicatorNumber, static_cast(style)); } } } // Set the indicator outline colour. void QsciScintilla::setIndicatorOutlineColor(const QColor &col, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { int alpha = col.alpha(); // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) SendScintilla(SCI_INDICSETOUTLINEALPHA, i, alpha); } else { SendScintilla(SCI_INDICSETOUTLINEALPHA, indicatorNumber, alpha); } } } // Fill a range with an indicator. void QsciScintilla::fillIndicatorRange(int lineFrom, int indexFrom, int lineTo, int indexTo, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { int start = positionFromLineIndex(lineFrom, indexFrom); int finish = positionFromLineIndex(lineTo, indexTo); // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) { SendScintilla(SCI_SETINDICATORCURRENT, i); SendScintilla(SCI_INDICATORFILLRANGE, start, finish - start); } } else { SendScintilla(SCI_SETINDICATORCURRENT, indicatorNumber); SendScintilla(SCI_INDICATORFILLRANGE, start, finish - start); } } } // Clear a range with an indicator. void QsciScintilla::clearIndicatorRange(int lineFrom, int indexFrom, int lineTo, int indexTo, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { int start = positionFromLineIndex(lineFrom, indexFrom); int finish = positionFromLineIndex(lineTo, indexTo); // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) { SendScintilla(SCI_SETINDICATORCURRENT, i); SendScintilla(SCI_INDICATORCLEARRANGE, start, finish - start); } } else { SendScintilla(SCI_SETINDICATORCURRENT, indicatorNumber); SendScintilla(SCI_INDICATORCLEARRANGE, start, finish - start); } } } // Define a marker based on a symbol. int QsciScintilla::markerDefine(MarkerSymbol sym, int markerNumber) { checkMarker(markerNumber); if (markerNumber >= 0) SendScintilla(SCI_MARKERDEFINE, markerNumber, static_cast(sym)); return markerNumber; } // Define a marker based on a character. int QsciScintilla::markerDefine(char ch, int markerNumber) { checkMarker(markerNumber); if (markerNumber >= 0) SendScintilla(SCI_MARKERDEFINE, markerNumber, static_cast(SC_MARK_CHARACTER) + ch); return markerNumber; } // Define a marker based on a QPixmap. int QsciScintilla::markerDefine(const QPixmap &pm, int markerNumber) { checkMarker(markerNumber); if (markerNumber >= 0) SendScintilla(SCI_MARKERDEFINEPIXMAP, markerNumber, pm); return markerNumber; } // Define a marker based on a QImage. int QsciScintilla::markerDefine(const QImage &im, int markerNumber) { checkMarker(markerNumber); if (markerNumber >= 0) { SendScintilla(SCI_RGBAIMAGESETHEIGHT, im.height()); SendScintilla(SCI_RGBAIMAGESETWIDTH, im.width()); SendScintilla(SCI_MARKERDEFINERGBAIMAGE, markerNumber, im); } return markerNumber; } // Add a marker to a line. int QsciScintilla::markerAdd(int linenr, int markerNumber) { if (markerNumber < 0 || markerNumber > MARKER_MAX || (allocatedMarkers & (1 << markerNumber)) == 0) return -1; return SendScintilla(SCI_MARKERADD, linenr, markerNumber); } // Get the marker mask for a line. unsigned QsciScintilla::markersAtLine(int linenr) const { return SendScintilla(SCI_MARKERGET, linenr); } // Delete a marker from a line. void QsciScintilla::markerDelete(int linenr, int markerNumber) { if (markerNumber <= MARKER_MAX) { if (markerNumber < 0) { unsigned am = allocatedMarkers; for (int m = 0; m <= MARKER_MAX; ++m) { if (am & 1) SendScintilla(SCI_MARKERDELETE, linenr, m); am >>= 1; } } else if (allocatedMarkers & (1 << markerNumber)) SendScintilla(SCI_MARKERDELETE, linenr, markerNumber); } } // Delete a marker from the text. void QsciScintilla::markerDeleteAll(int markerNumber) { if (markerNumber <= MARKER_MAX) { if (markerNumber < 0) SendScintilla(SCI_MARKERDELETEALL, -1); else if (allocatedMarkers & (1 << markerNumber)) SendScintilla(SCI_MARKERDELETEALL, markerNumber); } } // Delete a marker handle from the text. void QsciScintilla::markerDeleteHandle(int mhandle) { SendScintilla(SCI_MARKERDELETEHANDLE, mhandle); } // Return the line containing a marker instance. int QsciScintilla::markerLine(int mhandle) const { return SendScintilla(SCI_MARKERLINEFROMHANDLE, mhandle); } // Search forwards for a marker. int QsciScintilla::markerFindNext(int linenr, unsigned mask) const { return SendScintilla(SCI_MARKERNEXT, linenr, mask); } // Search backwards for a marker. int QsciScintilla::markerFindPrevious(int linenr, unsigned mask) const { return SendScintilla(SCI_MARKERPREVIOUS, linenr, mask); } // Set the marker background colour. void QsciScintilla::setMarkerBackgroundColor(const QColor &col, int markerNumber) { if (markerNumber <= MARKER_MAX) { int alpha = col.alpha(); // An opaque background would make the text invisible. if (alpha == 255) alpha = SC_ALPHA_NOALPHA; if (markerNumber < 0) { unsigned am = allocatedMarkers; for (int m = 0; m <= MARKER_MAX; ++m) { if (am & 1) { SendScintilla(SCI_MARKERSETBACK, m, col); SendScintilla(SCI_MARKERSETALPHA, m, alpha); } am >>= 1; } } else if (allocatedMarkers & (1 << markerNumber)) { SendScintilla(SCI_MARKERSETBACK, markerNumber, col); SendScintilla(SCI_MARKERSETALPHA, markerNumber, alpha); } } } // Set the marker foreground colour. void QsciScintilla::setMarkerForegroundColor(const QColor &col, int markerNumber) { if (markerNumber <= MARKER_MAX) { if (markerNumber < 0) { unsigned am = allocatedMarkers; for (int m = 0; m <= MARKER_MAX; ++m) { if (am & 1) SendScintilla(SCI_MARKERSETFORE, m, col); am >>= 1; } } else if (allocatedMarkers & (1 << markerNumber)) { SendScintilla(SCI_MARKERSETFORE, markerNumber, col); } } } // Check a marker, allocating a marker number if necessary. void QsciScintilla::checkMarker(int &markerNumber) { allocateId(markerNumber, allocatedMarkers, 0, MARKER_MAX); } // Check an indicator, allocating an indicator number if necessary. void QsciScintilla::checkIndicator(int &indicatorNumber) { allocateId(indicatorNumber, allocatedIndicators, INDIC_CONTAINER, INDIC_IME - 1); } // Make sure an identifier is valid and allocate it if necessary. void QsciScintilla::allocateId(int &id, unsigned &allocated, int min, int max) { if (id >= 0) { // Note that we allow existing identifiers to be explicitly redefined. if (id > max) id = -1; } else { unsigned aids = allocated >> min; // Find the smallest unallocated identifier. for (id = min; id <= max; ++id) { if ((aids & 1) == 0) break; aids >>= 1; } } // Allocate the identifier if it is valid. if (id >= 0) allocated |= (1 << id); } // Reset the fold margin colours. void QsciScintilla::resetFoldMarginColors() { SendScintilla(SCI_SETFOLDMARGINHICOLOUR, 0, 0L); SendScintilla(SCI_SETFOLDMARGINCOLOUR, 0, 0L); } // Set the fold margin colours. void QsciScintilla::setFoldMarginColors(const QColor &fore, const QColor &back) { SendScintilla(SCI_SETFOLDMARGINHICOLOUR, 1, fore); SendScintilla(SCI_SETFOLDMARGINCOLOUR, 1, back); } // Set the call tips background colour. void QsciScintilla::setCallTipsBackgroundColor(const QColor &col) { SendScintilla(SCI_CALLTIPSETBACK, col); } // Set the call tips foreground colour. void QsciScintilla::setCallTipsForegroundColor(const QColor &col) { SendScintilla(SCI_CALLTIPSETFORE, col); } // Set the call tips highlight colour. void QsciScintilla::setCallTipsHighlightColor(const QColor &col) { SendScintilla(SCI_CALLTIPSETFOREHLT, col); } // Set the matched brace background colour. void QsciScintilla::setMatchedBraceBackgroundColor(const QColor &col) { SendScintilla(SCI_STYLESETBACK, STYLE_BRACELIGHT, col); } // Set the matched brace foreground colour. void QsciScintilla::setMatchedBraceForegroundColor(const QColor &col) { SendScintilla(SCI_STYLESETFORE, STYLE_BRACELIGHT, col); } // Set the matched brace indicator. void QsciScintilla::setMatchedBraceIndicator(int indicatorNumber) { SendScintilla(SCI_BRACEHIGHLIGHTINDICATOR, 1, indicatorNumber); } // Reset the matched brace indicator. void QsciScintilla::resetMatchedBraceIndicator() { SendScintilla(SCI_BRACEHIGHLIGHTINDICATOR, 0, 0L); } // Set the unmatched brace background colour. void QsciScintilla::setUnmatchedBraceBackgroundColor(const QColor &col) { SendScintilla(SCI_STYLESETBACK, STYLE_BRACEBAD, col); } // Set the unmatched brace foreground colour. void QsciScintilla::setUnmatchedBraceForegroundColor(const QColor &col) { SendScintilla(SCI_STYLESETFORE, STYLE_BRACEBAD, col); } // Set the unmatched brace indicator. void QsciScintilla::setUnmatchedBraceIndicator(int indicatorNumber) { SendScintilla(SCI_BRACEBADLIGHTINDICATOR, 1, indicatorNumber); } // Reset the unmatched brace indicator. void QsciScintilla::resetUnmatchedBraceIndicator() { SendScintilla(SCI_BRACEBADLIGHTINDICATOR, 0, 0L); } // Detach any lexer. void QsciScintilla::detachLexer() { if (!lex.isNull()) { lex->setEditor(0); lex->disconnect(this); SendScintilla(SCI_STYLERESETDEFAULT); SendScintilla(SCI_STYLECLEARALL); } } // Set the lexer. void QsciScintilla::setLexer(QsciLexer *lexer) { // Detach any current lexer. detachLexer(); // Connect up the new lexer. lex = lexer; if (lex) { SendScintilla(SCI_CLEARDOCUMENTSTYLE); if (lex->lexer()) SendScintilla(SCI_SETLEXERLANGUAGE, lex->lexer()); else SendScintilla(SCI_SETLEXER, lex->lexerId()); lex->setEditor(this); connect(lex,SIGNAL(colorChanged(const QColor &, int)), SLOT(handleStyleColorChange(const QColor &, int))); connect(lex,SIGNAL(eolFillChanged(bool, int)), SLOT(handleStyleEolFillChange(bool, int))); connect(lex,SIGNAL(fontChanged(const QFont &, int)), SLOT(handleStyleFontChange(const QFont &, int))); connect(lex,SIGNAL(paperChanged(const QColor &, int)), SLOT(handleStylePaperChange(const QColor &, int))); connect(lex,SIGNAL(propertyChanged(const char *, const char *)), SLOT(handlePropertyChange(const char *, const char *))); SendScintilla(SCI_SETPROPERTY, "fold", "1"); SendScintilla(SCI_SETPROPERTY, "fold.html", "1"); // Set the keywords. Scintilla allows for sets numbered 0 to // KEYWORDSET_MAX (although the lexers only seem to exploit 0 to // KEYWORDSET_MAX - 1). We number from 1 in line with SciTE's property // files. for (int k = 0; k <= KEYWORDSET_MAX; ++k) { const char *kw = lex -> keywords(k + 1); if (!kw) kw = ""; SendScintilla(SCI_SETKEYWORDS, k, kw); } // Initialise each style. Do the default first so its (possibly // incorrect) font setting gets reset when style 0 is set. setLexerStyle(STYLE_DEFAULT); for (int s = 0; s <= STYLE_MAX; ++s) if (!lex->description(s).isEmpty()) setLexerStyle(s); // Initialise the properties. lex->refreshProperties(); // Set the auto-completion fillups and word separators. setAutoCompletionFillupsEnabled(fillups_enabled); wseps = lex->autoCompletionWordSeparators(); wchars = lex->wordCharacters(); if (!wchars) wchars = defaultWordChars; SendScintilla(SCI_AUTOCSETIGNORECASE, !lex->caseSensitive()); recolor(); } else { SendScintilla(SCI_SETLEXER, SCLEX_CONTAINER); setColor(nl_text_colour); setPaper(nl_paper_colour); SendScintilla(SCI_AUTOCSETFILLUPS, ""); SendScintilla(SCI_AUTOCSETIGNORECASE, false); wseps.clear(); wchars = defaultWordChars; } } // Set a particular style of the current lexer. void QsciScintilla::setLexerStyle(int style) { handleStyleColorChange(lex->color(style), style); handleStyleEolFillChange(lex->eolFill(style), style); handleStyleFontChange(lex->font(style), style); handleStylePaperChange(lex->paper(style), style); } // Get the current lexer. QsciLexer *QsciScintilla::lexer() const { return lex; } // Handle a change in lexer style foreground colour. void QsciScintilla::handleStyleColorChange(const QColor &c, int style) { SendScintilla(SCI_STYLESETFORE, style, c); } // Handle a change in lexer style end-of-line fill. void QsciScintilla::handleStyleEolFillChange(bool eolfill, int style) { SendScintilla(SCI_STYLESETEOLFILLED, style, eolfill); } // Handle a change in lexer style font. void QsciScintilla::handleStyleFontChange(const QFont &f, int style) { setStylesFont(f, style); if (style == lex->braceStyle()) { setStylesFont(f, STYLE_BRACELIGHT); setStylesFont(f, STYLE_BRACEBAD); } } // Set the font for a style. void QsciScintilla::setStylesFont(const QFont &f, int style) { SendScintilla(SCI_STYLESETFONT, style, f.family().toLatin1().data()); SendScintilla(SCI_STYLESETSIZEFRACTIONAL, style, long(f.pointSizeF() * SC_FONT_SIZE_MULTIPLIER)); // Pass the Qt weight via the back door. SendScintilla(SCI_STYLESETWEIGHT, style, -f.weight()); SendScintilla(SCI_STYLESETITALIC, style, f.italic()); SendScintilla(SCI_STYLESETUNDERLINE, style, f.underline()); // Tie the font settings of the default style to that of style 0 (the style // conventionally used for whitespace by lexers). This is needed so that // fold marks, indentations, edge columns etc are set properly. if (style == 0) setStylesFont(f, STYLE_DEFAULT); } // Handle a change in lexer style background colour. void QsciScintilla::handleStylePaperChange(const QColor &c, int style) { SendScintilla(SCI_STYLESETBACK, style, c); } // Handle a change in lexer property. void QsciScintilla::handlePropertyChange(const char *prop, const char *val) { SendScintilla(SCI_SETPROPERTY, prop, val); } // Handle a change to the user visible user interface. void QsciScintilla::handleUpdateUI(int) { int newPos = SendScintilla(SCI_GETCURRENTPOS); if (newPos != oldPos) { oldPos = newPos; int line = SendScintilla(SCI_LINEFROMPOSITION, newPos); int col = SendScintilla(SCI_GETCOLUMN, newPos); emit cursorPositionChanged(line, col); } if (braceMode != NoBraceMatch) braceMatch(); } // Handle brace matching. void QsciScintilla::braceMatch() { long braceAtCaret, braceOpposite; findMatchingBrace(braceAtCaret, braceOpposite, braceMode); if (braceAtCaret >= 0 && braceOpposite < 0) { SendScintilla(SCI_BRACEBADLIGHT, braceAtCaret); SendScintilla(SCI_SETHIGHLIGHTGUIDE, 0UL); } else { char chBrace = SendScintilla(SCI_GETCHARAT, braceAtCaret); SendScintilla(SCI_BRACEHIGHLIGHT, braceAtCaret, braceOpposite); long columnAtCaret = SendScintilla(SCI_GETCOLUMN, braceAtCaret); long columnOpposite = SendScintilla(SCI_GETCOLUMN, braceOpposite); if (chBrace == ':') { long lineStart = SendScintilla(SCI_LINEFROMPOSITION, braceAtCaret); long indentPos = SendScintilla(SCI_GETLINEINDENTPOSITION, lineStart); long indentPosNext = SendScintilla(SCI_GETLINEINDENTPOSITION, lineStart + 1); columnAtCaret = SendScintilla(SCI_GETCOLUMN, indentPos); long columnAtCaretNext = SendScintilla(SCI_GETCOLUMN, indentPosNext); long indentSize = SendScintilla(SCI_GETINDENT); if (columnAtCaretNext - indentSize > 1) columnAtCaret = columnAtCaretNext - indentSize; if (columnOpposite == 0) columnOpposite = columnAtCaret; } long column = columnAtCaret; if (column > columnOpposite) column = columnOpposite; SendScintilla(SCI_SETHIGHLIGHTGUIDE, column); } } // Check if the character at a position is a brace. long QsciScintilla::checkBrace(long pos, int brace_style, bool &colonMode) { long brace_pos = -1; char ch = SendScintilla(SCI_GETCHARAT, pos); if (ch == ':') { // A bit of a hack, we should really use a virtual. if (!lex.isNull() && qstrcmp(lex->lexer(), "python") == 0) { brace_pos = pos; colonMode = true; } } else if (ch && strchr("[](){}<>", ch)) { if (brace_style < 0) brace_pos = pos; else { int style = SendScintilla(SCI_GETSTYLEAT, pos) & 0x1f; if (style == brace_style) brace_pos = pos; } } return brace_pos; } // Find a brace and it's match. Return true if the current position is inside // a pair of braces. bool QsciScintilla::findMatchingBrace(long &brace, long &other,BraceMatch mode) { bool colonMode = false; int brace_style = (lex.isNull() ? -1 : lex->braceStyle()); brace = -1; other = -1; long caretPos = SendScintilla(SCI_GETCURRENTPOS); if (caretPos > 0) brace = checkBrace(caretPos - 1, brace_style, colonMode); bool isInside = false; if (brace < 0 && mode == SloppyBraceMatch) { brace = checkBrace(caretPos, brace_style, colonMode); if (brace >= 0 && !colonMode) isInside = true; } if (brace >= 0) { if (colonMode) { // Find the end of the Python indented block. long lineStart = SendScintilla(SCI_LINEFROMPOSITION, brace); long lineMaxSubord = SendScintilla(SCI_GETLASTCHILD, lineStart, -1); other = SendScintilla(SCI_GETLINEENDPOSITION, lineMaxSubord); } else other = SendScintilla(SCI_BRACEMATCH, brace, 0L); if (other > brace) isInside = !isInside; } return isInside; } // Move to the matching brace. void QsciScintilla::moveToMatchingBrace() { gotoMatchingBrace(false); } // Select to the matching brace. void QsciScintilla::selectToMatchingBrace() { gotoMatchingBrace(true); } // Move to the matching brace and optionally select the text. void QsciScintilla::gotoMatchingBrace(bool select) { long braceAtCaret; long braceOpposite; bool isInside = findMatchingBrace(braceAtCaret, braceOpposite, SloppyBraceMatch); if (braceOpposite >= 0) { // Convert the character positions into caret positions based on // whether the caret position was inside or outside the braces. if (isInside) { if (braceOpposite > braceAtCaret) braceAtCaret++; else braceOpposite++; } else { if (braceOpposite > braceAtCaret) braceOpposite++; else braceAtCaret++; } ensureLineVisible(SendScintilla(SCI_LINEFROMPOSITION, braceOpposite)); if (select) SendScintilla(SCI_SETSEL, braceAtCaret, braceOpposite); else SendScintilla(SCI_SETSEL, braceOpposite, braceOpposite); } } // Return a position from a line number and an index within the line. int QsciScintilla::positionFromLineIndex(int line, int index) const { int pos = SendScintilla(SCI_POSITIONFROMLINE, line); // Allow for multi-byte characters. for(int i = 0; i < index; i++) pos = SendScintilla(SCI_POSITIONAFTER, pos); return pos; } // Return a line number and an index within the line from a position. void QsciScintilla::lineIndexFromPosition(int position, int *line, int *index) const { int lin = SendScintilla(SCI_LINEFROMPOSITION, position); int linpos = SendScintilla(SCI_POSITIONFROMLINE, lin); int indx = 0; // Allow for multi-byte characters. while (linpos < position) { int new_linpos = SendScintilla(SCI_POSITIONAFTER, linpos); // If the position hasn't moved then we must be at the end of the text // (which implies that the position passed was beyond the end of the // text). if (new_linpos == linpos) break; linpos = new_linpos; ++indx; } *line = lin; *index = indx; } // Set the source of the automatic auto-completion list. void QsciScintilla::setAutoCompletionSource(AutoCompletionSource source) { acSource = source; } // Set the threshold for automatic auto-completion. void QsciScintilla::setAutoCompletionThreshold(int thresh) { acThresh = thresh; } // Set the auto-completion word separators if there is no current lexer. void QsciScintilla::setAutoCompletionWordSeparators(const QStringList &separators) { if (lex.isNull()) wseps = separators; } // Explicitly auto-complete from all sources. void QsciScintilla::autoCompleteFromAll() { startAutoCompletion(AcsAll, false, use_single != AcusNever); } // Explicitly auto-complete from the APIs. void QsciScintilla::autoCompleteFromAPIs() { startAutoCompletion(AcsAPIs, false, use_single != AcusNever); } // Explicitly auto-complete from the document. void QsciScintilla::autoCompleteFromDocument() { startAutoCompletion(AcsDocument, false, use_single != AcusNever); } // Check if a character can be in a word. bool QsciScintilla::isWordCharacter(char ch) const { return (strchr(wchars, ch) != NULL); } // Return the set of valid word characters. const char *QsciScintilla::wordCharacters() const { return wchars; } // Recolour the document. void QsciScintilla::recolor(int start, int end) { SendScintilla(SCI_COLOURISE, start, end); } // Registered a QPixmap image. void QsciScintilla::registerImage(int id, const QPixmap &pm) { SendScintilla(SCI_REGISTERIMAGE, id, pm); } // Registered a QImage image. void QsciScintilla::registerImage(int id, const QImage &im) { SendScintilla(SCI_RGBAIMAGESETHEIGHT, im.height()); SendScintilla(SCI_RGBAIMAGESETWIDTH, im.width()); SendScintilla(SCI_REGISTERRGBAIMAGE, id, im); } // Clear all registered images. void QsciScintilla::clearRegisteredImages() { SendScintilla(SCI_CLEARREGISTEREDIMAGES); } // Enable auto-completion fill-ups. void QsciScintilla::setAutoCompletionFillupsEnabled(bool enable) { const char *fillups; if (!enable) fillups = ""; else if (!lex.isNull()) fillups = lex->autoCompletionFillups(); else fillups = explicit_fillups.data(); SendScintilla(SCI_AUTOCSETFILLUPS, fillups); fillups_enabled = enable; } // See if auto-completion fill-ups are enabled. bool QsciScintilla::autoCompletionFillupsEnabled() const { return fillups_enabled; } // Set the fill-up characters for auto-completion if there is no current lexer. void QsciScintilla::setAutoCompletionFillups(const char *fillups) { explicit_fillups = fillups; setAutoCompletionFillupsEnabled(fillups_enabled); } // Set the case sensitivity for auto-completion. void QsciScintilla::setAutoCompletionCaseSensitivity(bool cs) { SendScintilla(SCI_AUTOCSETIGNORECASE, !cs); } // Return the case sensitivity for auto-completion. bool QsciScintilla::autoCompletionCaseSensitivity() const { return !SendScintilla(SCI_AUTOCGETIGNORECASE); } // Set the replace word mode for auto-completion. void QsciScintilla::setAutoCompletionReplaceWord(bool replace) { SendScintilla(SCI_AUTOCSETDROPRESTOFWORD, replace); } // Return the replace word mode for auto-completion. bool QsciScintilla::autoCompletionReplaceWord() const { return SendScintilla(SCI_AUTOCGETDROPRESTOFWORD); } // Set the single item mode for auto-completion. void QsciScintilla::setAutoCompletionUseSingle(AutoCompletionUseSingle single) { use_single = single; } // Return the single item mode for auto-completion. QsciScintilla::AutoCompletionUseSingle QsciScintilla::autoCompletionUseSingle() const { return use_single; } // Set the single item mode for auto-completion (deprecated). void QsciScintilla::setAutoCompletionShowSingle(bool single) { use_single = (single ? AcusExplicit : AcusNever); } // Return the single item mode for auto-completion (deprecated). bool QsciScintilla::autoCompletionShowSingle() const { return (use_single != AcusNever); } // Set current call tip position. void QsciScintilla::setCallTipsPosition(CallTipsPosition position) { SendScintilla(SCI_CALLTIPSETPOSITION, (position == CallTipsAboveText)); call_tips_position = position; } // Set current call tip style. void QsciScintilla::setCallTipsStyle(CallTipsStyle style) { call_tips_style = style; } // Set maximum number of call tips displayed. void QsciScintilla::setCallTipsVisible(int nr) { maxCallTips = nr; } // Set the document to display. void QsciScintilla::setDocument(const QsciDocument &document) { if (doc.pdoc != document.pdoc) { doc.undisplay(this); doc.attach(document); doc.display(this,&document); } } // Ensure the document is read-write and return true if was was read-only. bool QsciScintilla::ensureRW() { bool ro = isReadOnly(); if (ro) setReadOnly(false); return ro; } // Return the number of the first visible line. int QsciScintilla::firstVisibleLine() const { return SendScintilla(SCI_GETFIRSTVISIBLELINE); } // Set the number of the first visible line. void QsciScintilla::setFirstVisibleLine(int linenr) { SendScintilla(SCI_SETFIRSTVISIBLELINE, linenr); } // Return the height in pixels of the text in a particular line. int QsciScintilla::textHeight(int linenr) const { return SendScintilla(SCI_TEXTHEIGHT, linenr); } // See if auto-completion or user list is active. bool QsciScintilla::isListActive() const { return SendScintilla(SCI_AUTOCACTIVE); } // Cancel any current auto-completion or user list. void QsciScintilla::cancelList() { SendScintilla(SCI_AUTOCCANCEL); } // Handle a selection from the auto-completion list. void QsciScintilla::handleAutoCompletionSelection() { if (!lex.isNull()) { QsciAbstractAPIs *apis = lex->apis(); if (apis) apis->autoCompletionSelected(acSelection); } } // Display a user list. void QsciScintilla::showUserList(int id, const QStringList &list) { // Sanity check to make sure auto-completion doesn't get confused. if (id <= 0) return; SendScintilla(SCI_AUTOCSETSEPARATOR, userSeparator); ScintillaBytes s = textAsBytes(list.join(QChar(userSeparator))); SendScintilla(SCI_USERLISTSHOW, id, ScintillaBytesConstData(s)); } // Translate the SCN_USERLISTSELECTION notification into something more useful. void QsciScintilla::handleUserListSelection(const char *text, int id) { emit userListActivated(id, QString(text)); // Make sure the editor hasn't been deactivated as a side effect. activateWindow(); } // Return the case sensitivity of any lexer. bool QsciScintilla::caseSensitive() const { return lex.isNull() ? true : lex->caseSensitive(); } // Return true if the current list is an auto-completion list rather than a // user list. bool QsciScintilla::isAutoCompletionList() const { return (SendScintilla(SCI_AUTOCGETSEPARATOR) == acSeparator); } // Read the text from a QIODevice. bool QsciScintilla::read(QIODevice *io) { const int min_size = 1024 * 8; int buf_size = min_size; char *buf = new char[buf_size]; int data_len = 0; bool ok = true; qint64 part; // Read the whole lot in so we don't have to worry about character // boundaries. do { // Make sure there is a minimum amount of room. if (buf_size - data_len < min_size) { buf_size *= 2; char *new_buf = new char[buf_size * 2]; memcpy(new_buf, buf, data_len); delete[] buf; buf = new_buf; } part = io->read(buf + data_len, buf_size - data_len - 1); data_len += part; } while (part > 0); if (part < 0) ok = false; else { buf[data_len] = '\0'; bool ro = ensureRW(); SendScintilla(SCI_SETTEXT, buf); SendScintilla(SCI_EMPTYUNDOBUFFER); setReadOnly(ro); } delete[] buf; return ok; } // Write the text to a QIODevice. bool QsciScintilla::write(QIODevice *io) const { const char *buf = reinterpret_cast(SendScintillaPtrResult(SCI_GETCHARACTERPOINTER)); const char *bp = buf; uint buflen = qstrlen(buf); while (buflen > 0) { qint64 part = io->write(bp, buflen); if (part < 0) return false; bp += part; buflen -= part; } return true; } // Return the word at the given coordinates. QString QsciScintilla::wordAtLineIndex(int line, int index) const { return wordAtPosition(positionFromLineIndex(line, index)); } // Return the word at the given coordinates. QString QsciScintilla::wordAtPoint(const QPoint &point) const { long close_pos = SendScintilla(SCI_POSITIONFROMPOINTCLOSE, point.x(), point.y()); return wordAtPosition(close_pos); } // Return the word at the given position. QString QsciScintilla::wordAtPosition(int position) const { if (position < 0) return QString(); long start_pos = SendScintilla(SCI_WORDSTARTPOSITION, position, true); long end_pos = SendScintilla(SCI_WORDENDPOSITION, position, true); if (start_pos >= end_pos) return QString(); return text(start_pos, end_pos); } // Return the display style for annotations. QsciScintilla::AnnotationDisplay QsciScintilla::annotationDisplay() const { return (AnnotationDisplay)SendScintilla(SCI_ANNOTATIONGETVISIBLE); } // Set the display style for annotations. void QsciScintilla::setAnnotationDisplay(QsciScintilla::AnnotationDisplay display) { SendScintilla(SCI_ANNOTATIONSETVISIBLE, display); setScrollBars(); } // Clear annotations. void QsciScintilla::clearAnnotations(int line) { if (line >= 0) SendScintilla(SCI_ANNOTATIONSETTEXT, line, (const char *)0); else SendScintilla(SCI_ANNOTATIONCLEARALL); setScrollBars(); } // Annotate a line. void QsciScintilla::annotate(int line, const QString &text, int style) { int style_offset = SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET); ScintillaBytes s = textAsBytes(text); SendScintilla(SCI_ANNOTATIONSETTEXT, line, ScintillaBytesConstData(s)); SendScintilla(SCI_ANNOTATIONSETSTYLE, line, style - style_offset); setScrollBars(); } // Annotate a line. void QsciScintilla::annotate(int line, const QString &text, const QsciStyle &style) { style.apply(this); annotate(line, text, style.style()); } // Annotate a line. void QsciScintilla::annotate(int line, const QsciStyledText &text) { text.apply(this); annotate(line, text.text(), text.style()); } // Annotate a line. void QsciScintilla::annotate(int line, const QList &text) { char *styles; ScintillaBytes styled_text = styleText(text, &styles, SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET)); SendScintilla(SCI_ANNOTATIONSETTEXT, line, ScintillaBytesConstData(styled_text)); SendScintilla(SCI_ANNOTATIONSETSTYLES, line, styles); delete[] styles; } // Get the annotation for a line, if any. QString QsciScintilla::annotation(int line) const { char *buf = new char[SendScintilla(SCI_ANNOTATIONGETTEXT, line, (const char *)0) + 1]; buf[SendScintilla(SCI_ANNOTATIONGETTEXT, line, buf)] = '\0'; QString qs = bytesAsText(buf); delete[] buf; return qs; } // Convert a list of styled text to the low-level arrays. QsciScintillaBase::ScintillaBytes QsciScintilla::styleText(const QList &styled_text, char **styles, int style_offset) { QString text; int i; // Build the full text. for (i = 0; i < styled_text.count(); ++i) { const QsciStyledText &st = styled_text[i]; st.apply(this); text.append(st.text()); } ScintillaBytes s = textAsBytes(text); // There is a style byte for every byte. char *sp = *styles = new char[s.length()]; for (i = 0; i < styled_text.count(); ++i) { const QsciStyledText &st = styled_text[i]; ScintillaBytes part = textAsBytes(st.text()); int part_length = part.length(); for (int c = 0; c < part_length; ++c) *sp++ = (char)(st.style() - style_offset); } return s; } // Convert Scintilla modifiers to the Qt equivalent. int QsciScintilla::mapModifiers(int modifiers) { int state = 0; if (modifiers & SCMOD_SHIFT) state |= Qt::ShiftModifier; if (modifiers & SCMOD_CTRL) state |= Qt::ControlModifier; if (modifiers & SCMOD_ALT) state |= Qt::AltModifier; if (modifiers & (SCMOD_SUPER | SCMOD_META)) state |= Qt::MetaModifier; return state; } // Re-implemented to handle shortcut overrides. bool QsciScintilla::event(QEvent *e) { if (e->type() == QEvent::ShortcutOverride && !isReadOnly()) { QKeyEvent *ke = static_cast(e); if (ke->key()) { // We want ordinary characters. if ((ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier || ke->modifiers() == Qt::KeypadModifier) && ke->key() < Qt::Key_Escape) { ke->accept(); return true; } // We want any key that is bound. QsciCommand *cmd = stdCmds->boundTo(ke->key() | (ke->modifiers() & ~Qt::KeypadModifier)); if (cmd) { ke->accept(); return true; } } } return QsciScintillaBase::event(e); } // Re-implemented to zoom when the Control modifier is pressed. void QsciScintilla::wheelEvent(QWheelEvent *e) { #if defined(Q_OS_MAC) const Qt::KeyboardModifier zoom_modifier = Qt::MetaModifier; #else const Qt::KeyboardModifier zoom_modifier = Qt::ControlModifier; #endif if ((e->modifiers() & zoom_modifier) != 0) { if (e->delta() > 0) zoomIn(); else zoomOut(); } else { QsciScintillaBase::wheelEvent(e); } } // Re-implemented to handle chenges to the enabled state. void QsciScintilla::changeEvent(QEvent *e) { QsciScintillaBase::changeEvent(e); if (e->type() != QEvent::EnabledChange) return; if (isEnabled()) SendScintilla(SCI_SETCARETSTYLE, CARETSTYLE_LINE); else SendScintilla(SCI_SETCARETSTYLE, CARETSTYLE_INVISIBLE); QColor fore = palette().color(QPalette::Disabled, QPalette::Text); QColor back = palette().color(QPalette::Disabled, QPalette::Base); if (lex.isNull()) { if (isEnabled()) { fore = nl_text_colour; back = nl_paper_colour; } SendScintilla(SCI_STYLESETFORE, 0, fore); // Assume style 0 applies to everything so that we don't need to use // SCI_STYLECLEARALL which clears everything. We still have to set the // default style as well for the background without any text. SendScintilla(SCI_STYLESETBACK, 0, back); SendScintilla(SCI_STYLESETBACK, STYLE_DEFAULT, back); } else { setEnabledColors(STYLE_DEFAULT, fore, back); for (int s = 0; s <= STYLE_MAX; ++s) if (!lex->description(s).isNull()) setEnabledColors(s, fore, back); } } // Set the foreground and background colours for a style. void QsciScintilla::setEnabledColors(int style, QColor &fore, QColor &back) { if (isEnabled()) { fore = lex->color(style); back = lex->paper(style); } handleStyleColorChange(fore, style); handleStylePaperChange(back, style); } // Re-implemented to implement a more Qt-like context menu. void QsciScintilla::contextMenuEvent(QContextMenuEvent *e) { if (contextMenuNeeded(e->x(), e->y())) { QMenu *menu = createStandardContextMenu(); if (menu) { menu->setAttribute(Qt::WA_DeleteOnClose); menu->popup(e->globalPos()); } } } // Create an instance of the standard context menu. QMenu *QsciScintilla::createStandardContextMenu() { bool read_only = isReadOnly(); bool has_selection = hasSelectedText(); QMenu *menu = new QMenu(this); QAction *action; if (!read_only) { action = menu->addAction(tr("&Undo"), this, SLOT(undo())); set_shortcut(action, QsciCommand::Undo); action->setEnabled(isUndoAvailable()); action = menu->addAction(tr("&Redo"), this, SLOT(redo())); set_shortcut(action, QsciCommand::Redo); action->setEnabled(isRedoAvailable()); menu->addSeparator(); action = menu->addAction(tr("Cu&t"), this, SLOT(cut())); set_shortcut(action, QsciCommand::SelectionCut); action->setEnabled(has_selection); } action = menu->addAction(tr("&Copy"), this, SLOT(copy())); set_shortcut(action, QsciCommand::SelectionCopy); action->setEnabled(has_selection); if (!read_only) { action = menu->addAction(tr("&Paste"), this, SLOT(paste())); set_shortcut(action, QsciCommand::Paste); action->setEnabled(SendScintilla(SCI_CANPASTE)); action = menu->addAction(tr("Delete"), this, SLOT(delete_selection())); action->setEnabled(has_selection); } if (!menu->isEmpty()) menu->addSeparator(); action = menu->addAction(tr("Select All"), this, SLOT(selectAll())); set_shortcut(action, QsciCommand::SelectAll); action->setEnabled(length() != 0); return menu; } // Set the shortcut for an action using any current key binding. void QsciScintilla::set_shortcut(QAction *action, QsciCommand::Command cmd_id) const { QsciCommand *cmd = stdCmds->find(cmd_id); if (cmd && cmd->key()) action->setShortcut(QKeySequence(cmd->key())); } // Delete the current selection. void QsciScintilla::delete_selection() { SendScintilla(SCI_CLEAR); } // Convert a Scintilla colour to a QColor. static QColor asQColor(long sci_colour) { return QColor( ((int)sci_colour) & 0x00ff, ((int)(sci_colour >> 8)) & 0x00ff, ((int)(sci_colour >> 16)) & 0x00ff); } // Set the scroll width. void QsciScintilla::setScrollWidth(int pixelWidth) { SendScintilla(SCI_SETSCROLLWIDTH, pixelWidth); } // Get the scroll width. int QsciScintilla::scrollWidth() const { return SendScintilla(SCI_GETSCROLLWIDTH); } // Set scroll width tracking. void QsciScintilla::setScrollWidthTracking(bool enabled) { SendScintilla(SCI_SETSCROLLWIDTHTRACKING, enabled); } // Get scroll width tracking. bool QsciScintilla::scrollWidthTracking() const { return SendScintilla(SCI_GETSCROLLWIDTHTRACKING); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qsciscintillabase.cpp000066400000000000000000000537731463772530400302520ustar00rootroot00000000000000// This module implements the "official" low-level API. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qsciscintillabase.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "SciAccessibility.h" #include "ScintillaQt.h" // The #defines in Scintilla.h and the enums in qsciscintillabase.h conflict // (because we want to use the same names) so we have to undefine those we use // in this file. #undef SCI_SETCARETPERIOD #undef SCK_DOWN #undef SCK_UP #undef SCK_LEFT #undef SCK_RIGHT #undef SCK_HOME #undef SCK_END #undef SCK_PRIOR #undef SCK_NEXT #undef SCK_DELETE #undef SCK_INSERT #undef SCK_ESCAPE #undef SCK_BACK #undef SCK_TAB #undef SCK_RETURN #undef SCK_ADD #undef SCK_SUBTRACT #undef SCK_DIVIDE #undef SCK_WIN #undef SCK_RWIN #undef SCK_MENU #undef SCN_URIDROPPED // Remember if we have linked the lexers. static bool lexersLinked = false; // The list of instances. static QList poolList; // Mime support. static const QLatin1String mimeTextPlain("text/plain"); static const QLatin1String mimeRectangularWin("MSDEVColumnSelect"); static const QLatin1String mimeRectangular("text/x-qscintilla-rectangular"); #if (QT_VERSION >= 0x040200 && QT_VERSION < 0x050000 && defined(Q_OS_MAC)) || (QT_VERSION >= 0x050200 && defined(Q_OS_OSX)) extern void initialiseRectangularPasteboardMime(); #endif // The ctor. QsciScintillaBase::QsciScintillaBase(QWidget *parent) : QAbstractScrollArea(parent), preeditPos(-1), preeditNrBytes(0) #if QT_VERSION >= 0x050000 , clickCausedFocus(false) #endif { #if !defined(QT_NO_ACCESSIBILITY) QsciAccessibleScintillaBase::initialise(); #endif connectVerticalScrollBar(); connectHorizontalScrollBar(); setAcceptDrops(true); setFocusPolicy(Qt::WheelFocus); setAttribute(Qt::WA_KeyCompression); setAttribute(Qt::WA_InputMethodEnabled); #if QT_VERSION >= 0x050100 setInputMethodHints( Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhMultiLine); #elif QT_VERSION >= 0x040600 setInputMethodHints(Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText); #endif viewport()->setBackgroundRole(QPalette::Base); viewport()->setMouseTracking(true); viewport()->setAttribute(Qt::WA_NoSystemBackground); triple_click.setSingleShot(true); #if (QT_VERSION >= 0x040200 && QT_VERSION < 0x050000 && defined(Q_OS_MAC)) || (QT_VERSION >= 0x050200 && defined(Q_OS_OSX)) initialiseRectangularPasteboardMime(); #endif sci = new QsciScintillaQt(this); SendScintilla(SCI_SETCARETPERIOD, QApplication::cursorFlashTime() / 2); // Make sure the lexers are linked in. if (!lexersLinked) { Scintilla_LinkLexers(); lexersLinked = true; } QClipboard *cb = QApplication::clipboard(); if (cb->supportsSelection()) connect(cb, SIGNAL(selectionChanged()), SLOT(handleSelection())); // Add it to the pool. poolList.append(this); } // The dtor. QsciScintillaBase::~QsciScintillaBase() { // The QsciScintillaQt object isn't a child so delete it explicitly. delete sci; // Remove it from the pool. poolList.removeAt(poolList.indexOf(this)); } // Return an instance from the pool. QsciScintillaBase *QsciScintillaBase::pool() { return poolList.first(); } // Tell Scintilla to update the scroll bars. Scintilla should be doing this // itself. void QsciScintillaBase::setScrollBars() { sci->SetScrollBars(); } // Send a message to the real Scintilla widget using the low level Scintilla // API. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, long lParam) const { return sci->WndProc(msg, wParam, lParam); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, void *lParam) const { return sci->WndProc(msg, wParam, reinterpret_cast(lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, uintptr_t wParam, const char *lParam) const { return sci->WndProc(msg, wParam, reinterpret_cast(lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, const char *lParam) const { return sci->WndProc(msg, static_cast(0), reinterpret_cast(lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, const char *wParam, const char *lParam) const { return sci->WndProc(msg, reinterpret_cast(wParam), reinterpret_cast(lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, long wParam) const { return sci->WndProc(msg, static_cast(wParam), static_cast(0)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, int wParam) const { return sci->WndProc(msg, static_cast(wParam), static_cast(0)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, long cpMin, long cpMax, char *lpstrText) const { Sci_TextRange tr; tr.chrg.cpMin = cpMin; tr.chrg.cpMax = cpMax; tr.lpstrText = lpstrText; return sci->WndProc(msg, static_cast(0), reinterpret_cast(&tr)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, const QColor &col) const { sptr_t lParam = (col.blue() << 16) | (col.green() << 8) | col.red(); return sci->WndProc(msg, wParam, lParam); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, const QColor &col) const { uptr_t wParam = (col.blue() << 16) | (col.green() << 8) | col.red(); return sci->WndProc(msg, wParam, static_cast(0)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, QPainter *hdc, const QRect &rc, long cpMin, long cpMax) const { Sci_RangeToFormat rf; rf.hdc = rf.hdcTarget = reinterpret_cast(hdc); rf.rc.left = rc.left(); rf.rc.top = rc.top(); rf.rc.right = rc.right() + 1; rf.rc.bottom = rc.bottom() + 1; rf.chrg.cpMin = cpMin; rf.chrg.cpMax = cpMax; return sci->WndProc(msg, wParam, reinterpret_cast(&rf)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, const QPixmap &lParam) const { return sci->WndProc(msg, wParam, reinterpret_cast(&lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, const QImage &lParam) const { return sci->WndProc(msg, wParam, reinterpret_cast(&lParam)); } // Send a message to the real Scintilla widget using the low level Scintilla // API that returns a pointer result. void *QsciScintillaBase::SendScintillaPtrResult(unsigned int msg) const { return reinterpret_cast(sci->WndProc(msg, static_cast(0), static_cast(0))); } // Re-implemented to handle font changes void QsciScintillaBase::changeEvent(QEvent *e) { if (e->type() == QEvent::FontChange || e->type() == QEvent::ApplicationFontChange) sci->InvalidateStyleRedraw(); QAbstractScrollArea::changeEvent(e); } // Re-implemented to handle the context menu. void QsciScintillaBase::contextMenuEvent(QContextMenuEvent *e) { sci->ContextMenu(Scintilla::Point(e->globalX(), e->globalY())); } // Re-implemented to tell the widget it has the focus. void QsciScintillaBase::focusInEvent(QFocusEvent *e) { sci->SetFocusState(true); #if QT_VERSION >= 0x050000 clickCausedFocus = (e->reason() == Qt::MouseFocusReason); #endif QAbstractScrollArea::focusInEvent(e); } // Re-implemented to tell the widget it has lost the focus. void QsciScintillaBase::focusOutEvent(QFocusEvent *e) { if (e->reason() == Qt::ActiveWindowFocusReason) { // Only tell Scintilla we have lost focus if the new active window // isn't our auto-completion list. This is probably only an issue on // Linux and there are still problems because subsequent focus out // events don't always seem to get generated (at least with Qt5). QWidget *aw = QApplication::activeWindow(); if (!aw || aw->parent() != this || !aw->inherits("QsciSciListBox")) sci->SetFocusState(false); } else { sci->SetFocusState(false); } QAbstractScrollArea::focusOutEvent(e); } // Re-implemented to make sure tabs are passed to the editor. bool QsciScintillaBase::focusNextPrevChild(bool next) { if (!sci->pdoc->IsReadOnly()) return false; return QAbstractScrollArea::focusNextPrevChild(next); } // Handle the selection changing. void QsciScintillaBase::handleSelection() { if (!QApplication::clipboard()->ownsSelection()) sci->UnclaimSelection(); } // Handle key presses. void QsciScintillaBase::keyPressEvent(QKeyEvent *e) { int modifiers = 0; if (e->modifiers() & Qt::ShiftModifier) modifiers |= SCMOD_SHIFT; if (e->modifiers() & Qt::ControlModifier) modifiers |= SCMOD_CTRL; if (e->modifiers() & Qt::AltModifier) modifiers |= SCMOD_ALT; if (e->modifiers() & Qt::MetaModifier) modifiers |= SCMOD_META; int key = commandKey(e->key(), modifiers); if (key) { bool consumed = false; sci->KeyDownWithModifiers(key, modifiers, &consumed); if (consumed) { e->accept(); return; } } QString text = e->text(); if (!text.isEmpty() && text[0].isPrint()) { ScintillaBytes bytes = textAsBytes(text); sci->AddCharUTF(bytes.data(), bytes.length()); e->accept(); } else { QAbstractScrollArea::keyPressEvent(e); } } // Map a Qt key to a valid Scintilla command key, or 0 if none. int QsciScintillaBase::commandKey(int qt_key, int &modifiers) { int key; switch (qt_key) { case Qt::Key_Down: key = SCK_DOWN; break; case Qt::Key_Up: key = SCK_UP; break; case Qt::Key_Left: key = SCK_LEFT; break; case Qt::Key_Right: key = SCK_RIGHT; break; case Qt::Key_Home: key = SCK_HOME; break; case Qt::Key_End: key = SCK_END; break; case Qt::Key_PageUp: key = SCK_PRIOR; break; case Qt::Key_PageDown: key = SCK_NEXT; break; case Qt::Key_Delete: key = SCK_DELETE; break; case Qt::Key_Insert: key = SCK_INSERT; break; case Qt::Key_Escape: key = SCK_ESCAPE; break; case Qt::Key_Backspace: key = SCK_BACK; break; case Qt::Key_Tab: key = SCK_TAB; break; case Qt::Key_Backtab: // Scintilla assumes a backtab is shift-tab. key = SCK_TAB; modifiers |= SCMOD_SHIFT; break; case Qt::Key_Return: case Qt::Key_Enter: key = SCK_RETURN; break; case Qt::Key_Super_L: key = SCK_WIN; break; case Qt::Key_Super_R: key = SCK_RWIN; break; case Qt::Key_Menu: key = SCK_MENU; break; default: if ((key = qt_key) > 0x7f) key = 0; } return key; } // Encode a QString as bytes. QsciScintillaBase::ScintillaBytes QsciScintillaBase::textAsBytes(const QString &text) const { if (sci->IsUnicodeMode()) return text.toUtf8(); return text.toLatin1(); } // Decode bytes as a QString. QString QsciScintillaBase::bytesAsText(const char *bytes) const { if (sci->IsUnicodeMode()) return QString::fromUtf8(bytes); return QString::fromLatin1(bytes); } // Handle a mouse button double click. void QsciScintillaBase::mouseDoubleClickEvent(QMouseEvent *e) { if (e->button() != Qt::LeftButton) { e->ignore(); return; } setFocus(); // Make sure Scintilla will interpret this as a double-click. unsigned clickTime = sci->lastClickTime + Scintilla::Platform::DoubleClickTime() - 1; sci->ButtonDownWithModifiers(Scintilla::Point(e->x(), e->y()), clickTime, eventModifiers(e)); // Remember the current position and time in case it turns into a triple // click. triple_click_at = e->globalPos(); triple_click.start(QApplication::doubleClickInterval()); } // Handle a mouse move. void QsciScintillaBase::mouseMoveEvent(QMouseEvent *e) { sci->ButtonMoveWithModifiers(Scintilla::Point(e->x(), e->y()), 0, eventModifiers(e)); } // Handle a mouse button press. void QsciScintillaBase::mousePressEvent(QMouseEvent *e) { setFocus(); Scintilla::Point pt(e->x(), e->y()); if (e->button() == Qt::LeftButton || e->button() == Qt::RightButton) { unsigned clickTime; // It is a triple click if the timer is running and the mouse hasn't // moved too much. if (triple_click.isActive() && (e->globalPos() - triple_click_at).manhattanLength() < QApplication::startDragDistance()) clickTime = sci->lastClickTime + Scintilla::Platform::DoubleClickTime() - 1; else clickTime = sci->lastClickTime + Scintilla::Platform::DoubleClickTime() + 1; triple_click.stop(); // Scintilla uses the Alt modifier to initiate rectangular selection. // However the GTK port (under X11, not Windows) uses the Control // modifier (by default, although it is configurable). It does this // because most X11 window managers hijack Alt-drag to move the window. // We do the same, except that (for the moment at least) we don't allow // the modifier to be configured. bool shift = e->modifiers() & Qt::ShiftModifier; bool ctrl = e->modifiers() & Qt::ControlModifier; #if defined(Q_OS_MAC) || defined(Q_OS_WIN) bool alt = e->modifiers() & Qt::AltModifier; #else bool alt = ctrl; #endif if (e->button() == Qt::LeftButton) sci->ButtonDownWithModifiers(pt, clickTime, QsciScintillaQt::ModifierFlags(shift, ctrl, alt)); else sci->RightButtonDownWithModifiers(pt, clickTime, QsciScintillaQt::ModifierFlags(shift, ctrl, alt)); } else if (e->button() == Qt::MidButton) { QClipboard *cb = QApplication::clipboard(); if (cb->supportsSelection()) { int pos = sci->PositionFromLocation(pt); sci->sel.Clear(); sci->SetSelection(pos, pos); sci->pasteFromClipboard(QClipboard::Selection); } } } // Handle a mouse button releases. void QsciScintillaBase::mouseReleaseEvent(QMouseEvent *e) { if (e->button() != Qt::LeftButton) return; Scintilla::Point pt(e->x(), e->y()); if (sci->HaveMouseCapture()) { bool ctrl = e->modifiers() & Qt::ControlModifier; sci->ButtonUpWithModifiers(pt, 0, QsciScintillaQt::ModifierFlags(false, ctrl, false)); } #if QT_VERSION >= 0x050000 if (!sci->pdoc->IsReadOnly() && !sci->PointInSelMargin(pt) && qApp->autoSipEnabled()) { QStyle::RequestSoftwareInputPanel rsip = QStyle::RequestSoftwareInputPanel(style()->styleHint(QStyle::SH_RequestSoftwareInputPanel)); if (!clickCausedFocus || rsip == QStyle::RSIP_OnMouseClick) qApp->inputMethod()->show(); } clickCausedFocus = false; #endif } // Handle paint events. void QsciScintillaBase::paintEvent(QPaintEvent *e) { sci->paintEvent(e); } // Handle resize events. void QsciScintillaBase::resizeEvent(QResizeEvent *) { sci->ChangeSize(); } // Re-implemented to suppress the default behaviour as Scintilla works at a // more fundamental level. Note that this means that replacing the scrollbars // with custom versions does not work. void QsciScintillaBase::scrollContentsBy(int, int) { } // Handle the vertical scrollbar. void QsciScintillaBase::handleVSb(int value) { sci->ScrollTo(value); } // Handle the horizontal scrollbar. void QsciScintillaBase::handleHSb(int value) { sci->HorizontalScrollTo(value); } // Handle drag enters. void QsciScintillaBase::dragEnterEvent(QDragEnterEvent *e) { QsciScintillaBase::dragMoveEvent(e); } // Handle drag leaves. void QsciScintillaBase::dragLeaveEvent(QDragLeaveEvent *) { sci->SetDragPosition(Scintilla::SelectionPosition()); } // Handle drag moves. void QsciScintillaBase::dragMoveEvent(QDragMoveEvent *e) { if (e->mimeData()->hasUrls()) { e->acceptProposedAction(); } else { sci->SetDragPosition( sci->SPositionFromLocation( Scintilla::Point(e->pos().x(), e->pos().y()), false, false, sci->UserVirtualSpace())); acceptAction(e); } } // Handle drops. void QsciScintillaBase::dropEvent(QDropEvent *e) { if (e->mimeData()->hasUrls()) { e->acceptProposedAction(); foreach (const QUrl &url, e->mimeData()->urls()) emit SCN_URIDROPPED(url); return; } acceptAction(e); if (!e->isAccepted()) return; bool moving; int len; const char *s; bool rectangular; moving = (e->dropAction() == Qt::MoveAction); QByteArray text = fromMimeData(e->mimeData(), rectangular); len = text.length(); s = text.data(); std::string dest = Scintilla::Document::TransformLineEnds(s, len, sci->pdoc->eolMode); sci->DropAt(sci->posDrop, dest.c_str(), dest.length(), moving, rectangular); sci->Redraw(); } void QsciScintillaBase::acceptAction(QDropEvent *e) { if (sci->pdoc->IsReadOnly() || !canInsertFromMimeData(e->mimeData())) e->ignore(); else e->acceptProposedAction(); } // See if a MIME data object can be decoded. bool QsciScintillaBase::canInsertFromMimeData(const QMimeData *source) const { return source->hasFormat(mimeTextPlain); } // Create text from a MIME data object. QByteArray QsciScintillaBase::fromMimeData(const QMimeData *source, bool &rectangular) const { // See if it is rectangular. We try all of the different formats that // Scintilla supports in case we are working across different platforms. if (source->hasFormat(mimeRectangularWin)) rectangular = true; else if (source->hasFormat(mimeRectangular)) rectangular = true; else rectangular = false; // Note that we don't support Scintilla's hack of adding a '\0' as Qt // strips it off under the covers when pasting from another process. QString utf8 = source->text(); QByteArray text; if (sci->IsUnicodeMode()) text = utf8.toUtf8(); else text = utf8.toLatin1(); return text; } // Create a MIME data object for some text. QMimeData *QsciScintillaBase::toMimeData(const QByteArray &text, bool rectangular) const { QMimeData *mime = new QMimeData; QString utf8; if (sci->IsUnicodeMode()) utf8 = QString::fromUtf8(text.constData(), text.size()); else utf8 = QString::fromLatin1(text.constData(), text.size()); mime->setText(utf8); if (rectangular) { // Use the platform specific "standard" for specifying a rectangular // selection. #if defined(Q_OS_WIN) mime->setData(mimeRectangularWin, QByteArray()); #else mime->setData(mimeRectangular, QByteArray()); #endif } return mime; } // Connect up the vertical scroll bar. void QsciScintillaBase::connectVerticalScrollBar() { connect(verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(handleVSb(int))); } // Connect up the horizontal scroll bar. void QsciScintillaBase::connectHorizontalScrollBar() { connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(handleHSb(int))); } //! Replace the vertical scroll bar. void QsciScintillaBase::replaceVerticalScrollBar(QScrollBar *scrollBar) { setVerticalScrollBar(scrollBar); connectVerticalScrollBar(); } // Replace the horizontal scroll bar. void QsciScintillaBase::replaceHorizontalScrollBar(QScrollBar *scrollBar) { setHorizontalScrollBar(scrollBar); connectHorizontalScrollBar(); } // Return true if a context menu should be displayed. This is provided as a // helper to QsciScintilla::contextMenuEvent(). A proper design would break // backwards compatibility. bool QsciScintillaBase::contextMenuNeeded(int x, int y) const { Scintilla::Point pt(x, y); // Clear any selection if the mouse is outside. if (!sci->PointInSelection(pt)) sci->SetEmptySelection(sci->PositionFromLocation(pt)); // Respect SC_POPUP_*. return sci->ShouldDisplayPopup(pt); } // Return the Scintilla keyboard modifiers set for a mouse event. int QsciScintillaBase::eventModifiers(QMouseEvent *e) { bool shift = e->modifiers() & Qt::ShiftModifier; bool ctrl = e->modifiers() & Qt::ControlModifier; bool alt = e->modifiers() & Qt::AltModifier; return QsciScintillaQt::ModifierFlags(shift, ctrl, alt); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscistyle.cpp000066400000000000000000000116531463772530400265640ustar00rootroot00000000000000// This module implements the QsciStyle class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscistyle.h" #include #include "Qsci/qsciscintillabase.h" // A ctor. QsciStyle::QsciStyle(int style) { init(style); QPalette pal = QApplication::palette(); setColor(pal.text().color()); setPaper(pal.base().color()); setFont(QApplication::font()); setEolFill(false); } // A ctor. QsciStyle::QsciStyle(int style, const QString &description, const QColor &color, const QColor &paper, const QFont &font, bool eolFill) { init(style); setDescription(description); setColor(color); setPaper(paper); setFont(font); setEolFill(eolFill); } // Initialisation common to all ctors. void QsciStyle::init(int style) { // The next style number to allocate. The initial values corresponds to // the amount of space that Scintilla initially creates for styles. static int next_style_nr = 63; // See if a new style should be allocated. Note that we allow styles to be // passed in that are bigger than STYLE_MAX because the styles used for // annotations are allowed to be. if (style < 0) { // Note that we don't deal with the situation where the newly allocated // style number has already been used explicitly. if (next_style_nr > QsciScintillaBase::STYLE_LASTPREDEFINED) style = next_style_nr--; } style_nr = style; // Initialise the minor attributes. setTextCase(QsciStyle::OriginalCase); setVisible(true); setChangeable(true); setHotspot(false); } // Apply the style to a particular editor. void QsciStyle::apply(QsciScintillaBase *sci) const { // Don't do anything if the style is invalid. if (style_nr < 0) return; sci->SendScintilla(QsciScintillaBase::SCI_STYLESETFORE, style_nr, style_color); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETBACK, style_nr, style_paper); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETFONT, style_nr, style_font.family().toLatin1().data()); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETSIZEFRACTIONAL, style_nr, long(style_font.pointSizeF() * QsciScintillaBase::SC_FONT_SIZE_MULTIPLIER)); // Pass the Qt weight via the back door. sci->SendScintilla(QsciScintillaBase::SCI_STYLESETWEIGHT, style_nr, -style_font.weight()); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETITALIC, style_nr, style_font.italic()); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETUNDERLINE, style_nr, style_font.underline()); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETEOLFILLED, style_nr, style_eol_fill); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETCASE, style_nr, (long)style_case); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETVISIBLE, style_nr, style_visible); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETCHANGEABLE, style_nr, style_changeable); sci->SendScintilla(QsciScintillaBase::SCI_STYLESETHOTSPOT, style_nr, style_hotspot); } // Set the color attribute. void QsciStyle::setColor(const QColor &color) { style_color = color; } // Set the paper attribute. void QsciStyle::setPaper(const QColor &paper) { style_paper = paper; } // Set the font attribute. void QsciStyle::setFont(const QFont &font) { style_font = font; } // Set the eol fill attribute. void QsciStyle::setEolFill(bool eolFill) { style_eol_fill = eolFill; } // Set the text case attribute. void QsciStyle::setTextCase(QsciStyle::TextCase text_case) { style_case = text_case; } // Set the visible attribute. void QsciStyle::setVisible(bool visible) { style_visible = visible; } // Set the changeable attribute. void QsciStyle::setChangeable(bool changeable) { style_changeable = changeable; } // Set the hotspot attribute. void QsciStyle::setHotspot(bool hotspot) { style_hotspot = hotspot; } // Refresh the style. Note that since we had to add apply() then this can't do // anything useful so we leave it as a no-op. void QsciStyle::refresh() { } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/Qt4Qt5/qscistyledtext.cpp000066400000000000000000000031241463772530400276270ustar00rootroot00000000000000// This module implements the QsciStyledText class. // // Copyright (c) 2019 Riverbank Computing Limited // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qscistyledtext.h" #include "Qsci/qsciscintillabase.h" #include "Qsci/qscistyle.h" // A ctor. QsciStyledText::QsciStyledText(const QString &text, int style) : styled_text(text), style_nr(style), explicit_style(0) { } // A ctor. QsciStyledText::QsciStyledText(const QString &text, const QsciStyle &style) : styled_text(text), style_nr(-1) { explicit_style = new QsciStyle(style); } // Return the number of the style. int QsciStyledText::style() const { return explicit_style ? explicit_style->style() : style_nr; } // Apply any explicit style to an editor. void QsciStyledText::apply(QsciScintillaBase *sci) const { if (explicit_style) explicit_style->apply(sci); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/README000066400000000000000000000002131463772530400236440ustar00rootroot00000000000000All the documentation for QScintilla for Qt v4 and Qt v5 (including installation instructions) can be found in doc/html-Qt4Qt5/index.html. sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/000077500000000000000000000000001463772530400244135ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/ILexer.h000066400000000000000000000100341463772530400257520ustar00rootroot00000000000000// Scintilla source code edit control /** @file ILexer.h ** Interface between Scintilla and lexers. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef ILEXER_H #define ILEXER_H #include "Sci_Position.h" namespace Scintilla { enum { dvOriginal=0, dvLineEnd=1 }; class IDocument { public: virtual int SCI_METHOD Version() const = 0; virtual void SCI_METHOD SetErrorStatus(int status) = 0; virtual Sci_Position SCI_METHOD Length() const = 0; virtual void SCI_METHOD GetCharRange(char *buffer, Sci_Position position, Sci_Position lengthRetrieve) const = 0; virtual char SCI_METHOD StyleAt(Sci_Position position) const = 0; virtual Sci_Position SCI_METHOD LineFromPosition(Sci_Position position) const = 0; virtual Sci_Position SCI_METHOD LineStart(Sci_Position line) const = 0; virtual int SCI_METHOD GetLevel(Sci_Position line) const = 0; virtual int SCI_METHOD SetLevel(Sci_Position line, int level) = 0; virtual int SCI_METHOD GetLineState(Sci_Position line) const = 0; virtual int SCI_METHOD SetLineState(Sci_Position line, int state) = 0; virtual void SCI_METHOD StartStyling(Sci_Position position, char mask) = 0; virtual bool SCI_METHOD SetStyleFor(Sci_Position length, char style) = 0; virtual bool SCI_METHOD SetStyles(Sci_Position length, const char *styles) = 0; virtual void SCI_METHOD DecorationSetCurrentIndicator(int indicator) = 0; virtual void SCI_METHOD DecorationFillRange(Sci_Position position, int value, Sci_Position fillLength) = 0; virtual void SCI_METHOD ChangeLexerState(Sci_Position start, Sci_Position end) = 0; virtual int SCI_METHOD CodePage() const = 0; virtual bool SCI_METHOD IsDBCSLeadByte(char ch) const = 0; virtual const char * SCI_METHOD BufferPointer() = 0; virtual int SCI_METHOD GetLineIndentation(Sci_Position line) = 0; }; class IDocumentWithLineEnd : public IDocument { public: virtual Sci_Position SCI_METHOD LineEnd(Sci_Position line) const = 0; virtual Sci_Position SCI_METHOD GetRelativePosition(Sci_Position positionStart, Sci_Position characterOffset) const = 0; virtual int SCI_METHOD GetCharacterAndWidth(Sci_Position position, Sci_Position *pWidth) const = 0; }; enum { lvOriginal=0, lvSubStyles=1, lvMetaData=2 }; class ILexer { public: virtual int SCI_METHOD Version() const = 0; virtual void SCI_METHOD Release() = 0; virtual const char * SCI_METHOD PropertyNames() = 0; virtual int SCI_METHOD PropertyType(const char *name) = 0; virtual const char * SCI_METHOD DescribeProperty(const char *name) = 0; virtual Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) = 0; virtual const char * SCI_METHOD DescribeWordListSets() = 0; virtual Sci_Position SCI_METHOD WordListSet(int n, const char *wl) = 0; virtual void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) = 0; virtual void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) = 0; virtual void * SCI_METHOD PrivateCall(int operation, void *pointer) = 0; }; class ILexerWithSubStyles : public ILexer { public: virtual int SCI_METHOD LineEndTypesSupported() = 0; virtual int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles) = 0; virtual int SCI_METHOD SubStylesStart(int styleBase) = 0; virtual int SCI_METHOD SubStylesLength(int styleBase) = 0; virtual int SCI_METHOD StyleFromSubStyle(int subStyle) = 0; virtual int SCI_METHOD PrimaryStyleFromStyle(int style) = 0; virtual void SCI_METHOD FreeSubStyles() = 0; virtual void SCI_METHOD SetIdentifiers(int style, const char *identifiers) = 0; virtual int SCI_METHOD DistanceToSecondaryStyles() = 0; virtual const char * SCI_METHOD GetSubStyleBases() = 0; }; class ILexerWithMetaData : public ILexerWithSubStyles { public: virtual int SCI_METHOD NamedStyles() = 0; virtual const char * SCI_METHOD NameOfStyle(int style) = 0; virtual const char * SCI_METHOD TagsOfStyle(int style) = 0; virtual const char * SCI_METHOD DescriptionOfStyle(int style) = 0; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/ILoader.h000066400000000000000000000011371463772530400261050ustar00rootroot00000000000000// Scintilla source code edit control /** @file ILoader.h ** Interface for loading into a Scintilla document from a background thread. **/ // Copyright 1998-2017 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef ILOADER_H #define ILOADER_H #include "Sci_Position.h" class ILoader { public: virtual int SCI_METHOD Release() = 0; // Returns a status code from SC_STATUS_* virtual int SCI_METHOD AddData(const char *data, Sci_Position length) = 0; virtual void * SCI_METHOD ConvertToDocument() = 0; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/License.txt000066400000000000000000000015261463772530400265420ustar00rootroot00000000000000License for Scintilla and SciTE Copyright 1998-2003 by Neil Hodgson All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NEIL HODGSON 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.sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/Platform.h000066400000000000000000000365641463772530400263660ustar00rootroot00000000000000// Scintilla source code edit control /** @file Platform.h ** Interface to platform facilities. Also includes some basic utilities. ** Implemented in PlatGTK.cxx for GTK+/Linux, PlatWin.cxx for Windows, and PlatWX.cxx for wxWindows. **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef PLATFORM_H #define PLATFORM_H // PLAT_GTK = GTK+ on Linux or Win32 // PLAT_GTK_WIN32 is defined additionally when running PLAT_GTK under Win32 // PLAT_WIN = Win32 API on Win32 OS // PLAT_WX is wxWindows on any supported platform // PLAT_TK = Tcl/TK on Linux or Win32 #define PLAT_GTK 0 #define PLAT_GTK_WIN32 0 #define PLAT_GTK_MACOSX 0 #define PLAT_MACOSX 0 #define PLAT_WIN 0 #define PLAT_WX 0 #define PLAT_QT 0 #define PLAT_FOX 0 #define PLAT_CURSES 0 #define PLAT_TK 0 #define PLAT_HAIKU 0 #if defined(FOX) #undef PLAT_FOX #define PLAT_FOX 1 #elif defined(__WX__) #undef PLAT_WX #define PLAT_WX 1 #elif defined(CURSES) #undef PLAT_CURSES #define PLAT_CURSES 1 #elif defined(__HAIKU__) #undef PLAT_HAIKU #define PLAT_HAIKU 1 #elif defined(SCINTILLA_QT) #undef PLAT_QT #define PLAT_QT 1 #include QT_BEGIN_NAMESPACE class QPainter; QT_END_NAMESPACE // This is needed to work around an HP-UX bug with Qt4. #include #elif defined(TK) #undef PLAT_TK #define PLAT_TK 1 #elif defined(GTK) #undef PLAT_GTK #define PLAT_GTK 1 #if defined(__WIN32__) || defined(_MSC_VER) #undef PLAT_GTK_WIN32 #define PLAT_GTK_WIN32 1 #endif #if defined(__APPLE__) #undef PLAT_GTK_MACOSX #define PLAT_GTK_MACOSX 1 #endif #elif defined(__APPLE__) #undef PLAT_MACOSX #define PLAT_MACOSX 1 #else #undef PLAT_WIN #define PLAT_WIN 1 #endif namespace Scintilla { typedef float XYPOSITION; typedef double XYACCUMULATOR; // Underlying the implementation of the platform classes are platform specific types. // Sometimes these need to be passed around by client code so they are defined here typedef void *FontID; typedef void *SurfaceID; typedef void *WindowID; typedef void *MenuID; typedef void *TickerID; typedef void *Function; typedef void *IdlerID; /** * A geometric point class. * Point is similar to the Win32 POINT and GTK+ GdkPoint types. */ class Point { public: XYPOSITION x; XYPOSITION y; constexpr explicit Point(XYPOSITION x_=0, XYPOSITION y_=0) noexcept : x(x_), y(y_) { } static Point FromInts(int x_, int y_) noexcept { return Point(static_cast(x_), static_cast(y_)); } // Other automatically defined methods (assignment, copy constructor, destructor) are fine }; /** * A geometric rectangle class. * PRectangle is similar to Win32 RECT. * PRectangles contain their top and left sides, but not their right and bottom sides. */ class PRectangle { public: XYPOSITION left; XYPOSITION top; XYPOSITION right; XYPOSITION bottom; constexpr explicit PRectangle(XYPOSITION left_=0, XYPOSITION top_=0, XYPOSITION right_=0, XYPOSITION bottom_ = 0) noexcept : left(left_), top(top_), right(right_), bottom(bottom_) { } static PRectangle FromInts(int left_, int top_, int right_, int bottom_) noexcept { return PRectangle(static_cast(left_), static_cast(top_), static_cast(right_), static_cast(bottom_)); } // Other automatically defined methods (assignment, copy constructor, destructor) are fine bool operator==(const PRectangle &rc) const noexcept { return (rc.left == left) && (rc.right == right) && (rc.top == top) && (rc.bottom == bottom); } bool Contains(Point pt) const noexcept { return (pt.x >= left) && (pt.x <= right) && (pt.y >= top) && (pt.y <= bottom); } bool ContainsWholePixel(Point pt) const noexcept { // Does the rectangle contain all of the pixel to left/below the point return (pt.x >= left) && ((pt.x+1) <= right) && (pt.y >= top) && ((pt.y+1) <= bottom); } bool Contains(PRectangle rc) const noexcept { return (rc.left >= left) && (rc.right <= right) && (rc.top >= top) && (rc.bottom <= bottom); } bool Intersects(PRectangle other) const noexcept { return (right > other.left) && (left < other.right) && (bottom > other.top) && (top < other.bottom); } void Move(XYPOSITION xDelta, XYPOSITION yDelta) noexcept { left += xDelta; top += yDelta; right += xDelta; bottom += yDelta; } XYPOSITION Width() const noexcept { return right - left; } XYPOSITION Height() const noexcept { return bottom - top; } bool Empty() const noexcept { return (Height() <= 0) || (Width() <= 0); } }; /** * Holds an RGB colour with 8 bits for each component. */ constexpr const float componentMaximum = 255.0f; class ColourDesired { int co; public: explicit ColourDesired(int co_=0) noexcept : co(co_) { } ColourDesired(unsigned int red, unsigned int green, unsigned int blue) noexcept : co(red | (green << 8) | (blue << 16)) { } bool operator==(const ColourDesired &other) const noexcept { return co == other.co; } int AsInteger() const noexcept { return co; } // Red, green and blue values as bytes 0..255 unsigned char GetRed() const noexcept { return co & 0xff; } unsigned char GetGreen() const noexcept { return (co >> 8) & 0xff; } unsigned char GetBlue() const noexcept { return (co >> 16) & 0xff; } // Red, green and blue values as float 0..1.0 float GetRedComponent() const noexcept { return GetRed() / componentMaximum; } float GetGreenComponent() const noexcept { return GetGreen() / componentMaximum; } float GetBlueComponent() const noexcept { return GetBlue() / componentMaximum; } }; /** * Holds an RGBA colour. */ class ColourAlpha : public ColourDesired { public: explicit ColourAlpha(int co_ = 0) noexcept : ColourDesired(co_) { } ColourAlpha(unsigned int red, unsigned int green, unsigned int blue) noexcept : ColourDesired(red | (green << 8) | (blue << 16)) { } ColourAlpha(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha) noexcept : ColourDesired(red | (green << 8) | (blue << 16) | (alpha << 24)) { } ColourAlpha(ColourDesired cd, unsigned int alpha) noexcept : ColourDesired(cd.AsInteger() | (alpha << 24)) { } ColourDesired GetColour() const noexcept { return ColourDesired(AsInteger() & 0xffffff); } unsigned char GetAlpha() const noexcept { return (AsInteger() >> 24) & 0xff; } float GetAlphaComponent() const noexcept { return GetAlpha() / componentMaximum; } ColourAlpha MixedWith(ColourAlpha other) const noexcept { const unsigned int red = (GetRed() + other.GetRed()) / 2; const unsigned int green = (GetGreen() + other.GetGreen()) / 2; const unsigned int blue = (GetBlue() + other.GetBlue()) / 2; const unsigned int alpha = (GetAlpha() + other.GetAlpha()) / 2; return ColourAlpha(red, green, blue, alpha); } }; /** * Holds an element of a gradient with an RGBA colour and a relative position. */ class ColourStop { public: float position; ColourAlpha colour; ColourStop(float position_, ColourAlpha colour_) noexcept : position(position_), colour(colour_) { } }; /** * Font management. */ struct FontParameters { const char *faceName; float size; int weight; bool italic; int extraFontFlag; int technology; int characterSet; FontParameters( const char *faceName_, float size_=10, int weight_=400, bool italic_=false, int extraFontFlag_=0, int technology_=0, int characterSet_=0) noexcept : faceName(faceName_), size(size_), weight(weight_), italic(italic_), extraFontFlag(extraFontFlag_), technology(technology_), characterSet(characterSet_) { } }; class Font { protected: FontID fid; public: Font() noexcept; // Deleted so Font objects can not be copied Font(const Font &) = delete; Font(Font &&) = delete; Font &operator=(const Font &) = delete; Font &operator=(Font &&) = delete; virtual ~Font(); virtual void Create(const FontParameters &fp); virtual void Release(); FontID GetID() const noexcept { return fid; } // Alias another font - caller guarantees not to Release void SetID(FontID fid_) noexcept { fid = fid_; } friend class Surface; friend class SurfaceImpl; }; /** * A surface abstracts a place to draw. */ #if defined(PLAT_QT) class XPM; #endif class Surface { public: Surface() noexcept = default; Surface(const Surface &) = delete; Surface(Surface &&) = delete; Surface &operator=(const Surface &) = delete; Surface &operator=(Surface &&) = delete; virtual ~Surface() {} static Surface *Allocate(int technology); virtual void Init(WindowID wid)=0; virtual void Init(SurfaceID sid, WindowID wid)=0; virtual void InitPixMap(int width, int height, Surface *surface_, WindowID wid)=0; virtual void Release()=0; virtual bool Initialised()=0; virtual void PenColour(ColourDesired fore)=0; virtual int LogPixelsY()=0; virtual int DeviceHeightFont(int points)=0; virtual void MoveTo(int x_, int y_)=0; virtual void LineTo(int x_, int y_)=0; virtual void Polygon(Point *pts, size_t npts, ColourDesired fore, ColourDesired back)=0; virtual void RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back)=0; virtual void FillRectangle(PRectangle rc, ColourDesired back)=0; virtual void FillRectangle(PRectangle rc, Surface &surfacePattern)=0; virtual void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back)=0; virtual void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, ColourDesired outline, int alphaOutline, int flags)=0; enum class GradientOptions { leftToRight, topToBottom }; virtual void GradientRectangle(PRectangle rc, const std::vector &stops, GradientOptions options)=0; virtual void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) = 0; virtual void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back)=0; virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource)=0; virtual void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back)=0; virtual void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back)=0; virtual void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore)=0; virtual void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions)=0; virtual XYPOSITION WidthText(Font &font_, const char *s, int len)=0; virtual XYPOSITION Ascent(Font &font_)=0; virtual XYPOSITION Descent(Font &font_)=0; virtual XYPOSITION InternalLeading(Font &font_)=0; virtual XYPOSITION Height(Font &font_)=0; virtual XYPOSITION AverageCharWidth(Font &font_)=0; virtual void SetClip(PRectangle rc)=0; virtual void FlushCachedState()=0; virtual void SetUnicodeMode(bool unicodeMode_)=0; virtual void SetDBCSMode(int codePage)=0; #if defined(PLAT_QT) virtual void Init(QPainter *p)=0; virtual void DrawXPM(PRectangle rc, const XPM *xpm)=0; #endif }; /** * Class to hide the details of window manipulation. * Does not own the window which will normally have a longer life than this object. */ class Window { protected: WindowID wid; public: Window() noexcept : wid(nullptr), cursorLast(cursorInvalid) { } Window(const Window &source) = delete; Window(Window &&) = delete; Window &operator=(WindowID wid_) noexcept { wid = wid_; cursorLast = cursorInvalid; return *this; } Window &operator=(const Window &) = delete; Window &operator=(Window &&) = delete; virtual ~Window(); WindowID GetID() const noexcept { return wid; } bool Created() const noexcept { return wid != nullptr; } void Destroy(); PRectangle GetPosition() const; void SetPosition(PRectangle rc); void SetPositionRelative(PRectangle rc, const Window *relativeTo); PRectangle GetClientPosition() const; void Show(bool show=true); void InvalidateAll(); void InvalidateRectangle(PRectangle rc); virtual void SetFont(Font &font); enum Cursor { cursorInvalid, cursorText, cursorArrow, cursorUp, cursorWait, cursorHoriz, cursorVert, cursorReverseArrow, cursorHand }; void SetCursor(Cursor curs); PRectangle GetMonitorRect(Point pt); private: Cursor cursorLast; }; /** * Listbox management. */ // ScintillaBase implements IListBoxDelegate to receive ListBoxEvents from a ListBox struct ListBoxEvent { enum class EventType { selectionChange, doubleClick } event; ListBoxEvent(EventType event_) noexcept : event(event_) { } }; class IListBoxDelegate { public: virtual void ListNotify(ListBoxEvent *plbe)=0; }; class ListBox : public Window { public: ListBox() noexcept; ~ListBox() override; static ListBox *Allocate(); void SetFont(Font &font) override =0; virtual void Create(Window &parent, int ctrlID, Point location, int lineHeight_, bool unicodeMode_, int technology_)=0; virtual void SetAverageCharWidth(int width)=0; virtual void SetVisibleRows(int rows)=0; virtual int GetVisibleRows() const=0; virtual PRectangle GetDesiredRect()=0; virtual int CaretFromEdge()=0; virtual void Clear()=0; virtual void Append(char *s, int type = -1)=0; virtual int Length()=0; virtual void Select(int n)=0; virtual int GetSelection()=0; virtual int Find(const char *prefix)=0; virtual void GetValue(int n, char *value, int len)=0; virtual void RegisterImage(int type, const char *xpm_data)=0; virtual void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) = 0; virtual void ClearRegisteredImages()=0; virtual void SetDelegate(IListBoxDelegate *lbDelegate)=0; virtual void SetList(const char* list, char separator, char typesep)=0; }; /** * Menu management. */ class Menu { MenuID mid; public: Menu() noexcept; MenuID GetID() const noexcept { return mid; } void CreatePopUp(); void Destroy(); void Show(Point pt, Window &w); }; /** * Dynamic Library (DLL/SO/...) loading */ class DynamicLibrary { public: virtual ~DynamicLibrary() = default; /// @return Pointer to function "name", or NULL on failure. virtual Function FindFunction(const char *name) = 0; /// @return true if the library was loaded successfully. virtual bool IsValid() = 0; /// @return An instance of a DynamicLibrary subclass with "modulePath" loaded. static DynamicLibrary *Load(const char *modulePath); }; #if defined(__clang__) # if __has_feature(attribute_analyzer_noreturn) # define CLANG_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) # else # define CLANG_ANALYZER_NORETURN # endif #else # define CLANG_ANALYZER_NORETURN #endif /** * Platform class used to retrieve system wide parameters such as double click speed * and chrome colour. Not a creatable object, more of a module with several functions. */ class Platform { public: Platform() = default; Platform(const Platform &) = delete; Platform(Platform &&) = delete; Platform &operator=(const Platform &) = delete; Platform &operator=(Platform &&) = delete; ~Platform() = default; static ColourDesired Chrome(); static ColourDesired ChromeHighlight(); static const char *DefaultFont(); static int DefaultFontSize(); static unsigned int DoubleClickTime(); static void DebugDisplay(const char *s); static constexpr long LongFromTwoShorts(short a,short b) noexcept { return (a) | ((b) << 16); } static void DebugPrintf(const char *format, ...); static bool ShowAssertionPopUps(bool assertionPopUps_); static void Assert(const char *c, const char *file, int line) CLANG_ANALYZER_NORETURN; }; #ifdef NDEBUG #define PLATFORM_ASSERT(c) ((void)0) #else #define PLATFORM_ASSERT(c) ((c) ? (void)(0) : Scintilla::Platform::Assert(#c, __FILE__, __LINE__)) #endif } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/SciLexer.h000066400000000000000000001473571463772530400263230ustar00rootroot00000000000000/* Scintilla source code edit control */ /** @file SciLexer.h ** Interface to the added lexer functions in the SciLexer version of the edit control. **/ /* Copyright 1998-2002 by Neil Hodgson * The License.txt file describes the conditions under which this software may be distributed. */ /* Most of this file is automatically generated from the Scintilla.iface interface definition * file which contains any comments about the definitions. HFacer.py does the generation. */ #ifndef SCILEXER_H #define SCILEXER_H /* SciLexer features - not in standard Scintilla */ /* ++Autogenerated -- start of section automatically generated from Scintilla.iface */ #define SCLEX_CONTAINER 0 #define SCLEX_NULL 1 #define SCLEX_PYTHON 2 #define SCLEX_CPP 3 #define SCLEX_HTML 4 #define SCLEX_XML 5 #define SCLEX_PERL 6 #define SCLEX_SQL 7 #define SCLEX_VB 8 #define SCLEX_PROPERTIES 9 #define SCLEX_ERRORLIST 10 #define SCLEX_MAKEFILE 11 #define SCLEX_BATCH 12 #define SCLEX_XCODE 13 #define SCLEX_LATEX 14 #define SCLEX_LUA 15 #define SCLEX_DIFF 16 #define SCLEX_CONF 17 #define SCLEX_PASCAL 18 #define SCLEX_AVE 19 #define SCLEX_ADA 20 #define SCLEX_LISP 21 #define SCLEX_RUBY 22 #define SCLEX_EIFFEL 23 #define SCLEX_EIFFELKW 24 #define SCLEX_TCL 25 #define SCLEX_NNCRONTAB 26 #define SCLEX_BULLANT 27 #define SCLEX_VBSCRIPT 28 #define SCLEX_BAAN 31 #define SCLEX_MATLAB 32 #define SCLEX_SCRIPTOL 33 #define SCLEX_ASM 34 #define SCLEX_CPPNOCASE 35 #define SCLEX_FORTRAN 36 #define SCLEX_F77 37 #define SCLEX_CSS 38 #define SCLEX_POV 39 #define SCLEX_LOUT 40 #define SCLEX_ESCRIPT 41 #define SCLEX_PS 42 #define SCLEX_NSIS 43 #define SCLEX_MMIXAL 44 #define SCLEX_CLW 45 #define SCLEX_CLWNOCASE 46 #define SCLEX_LOT 47 #define SCLEX_YAML 48 #define SCLEX_TEX 49 #define SCLEX_METAPOST 50 #define SCLEX_POWERBASIC 51 #define SCLEX_FORTH 52 #define SCLEX_ERLANG 53 #define SCLEX_OCTAVE 54 #define SCLEX_MSSQL 55 #define SCLEX_VERILOG 56 #define SCLEX_KIX 57 #define SCLEX_GUI4CLI 58 #define SCLEX_SPECMAN 59 #define SCLEX_AU3 60 #define SCLEX_APDL 61 #define SCLEX_BASH 62 #define SCLEX_ASN1 63 #define SCLEX_VHDL 64 #define SCLEX_CAML 65 #define SCLEX_BLITZBASIC 66 #define SCLEX_PUREBASIC 67 #define SCLEX_HASKELL 68 #define SCLEX_PHPSCRIPT 69 #define SCLEX_TADS3 70 #define SCLEX_REBOL 71 #define SCLEX_SMALLTALK 72 #define SCLEX_FLAGSHIP 73 #define SCLEX_CSOUND 74 #define SCLEX_FREEBASIC 75 #define SCLEX_INNOSETUP 76 #define SCLEX_OPAL 77 #define SCLEX_SPICE 78 #define SCLEX_D 79 #define SCLEX_CMAKE 80 #define SCLEX_GAP 81 #define SCLEX_PLM 82 #define SCLEX_PROGRESS 83 #define SCLEX_ABAQUS 84 #define SCLEX_ASYMPTOTE 85 #define SCLEX_R 86 #define SCLEX_MAGIK 87 #define SCLEX_POWERSHELL 88 #define SCLEX_MYSQL 89 #define SCLEX_PO 90 #define SCLEX_TAL 91 #define SCLEX_COBOL 92 #define SCLEX_TACL 93 #define SCLEX_SORCUS 94 #define SCLEX_POWERPRO 95 #define SCLEX_NIMROD 96 #define SCLEX_SML 97 #define SCLEX_MARKDOWN 98 #define SCLEX_TXT2TAGS 99 #define SCLEX_A68K 100 #define SCLEX_MODULA 101 #define SCLEX_COFFEESCRIPT 102 #define SCLEX_TCMD 103 #define SCLEX_AVS 104 #define SCLEX_ECL 105 #define SCLEX_OSCRIPT 106 #define SCLEX_VISUALPROLOG 107 #define SCLEX_LITERATEHASKELL 108 #define SCLEX_STTXT 109 #define SCLEX_KVIRC 110 #define SCLEX_RUST 111 #define SCLEX_DMAP 112 #define SCLEX_AS 113 #define SCLEX_DMIS 114 #define SCLEX_REGISTRY 115 #define SCLEX_BIBTEX 116 #define SCLEX_SREC 117 #define SCLEX_IHEX 118 #define SCLEX_TEHEX 119 #define SCLEX_JSON 120 #define SCLEX_EDIFACT 121 #define SCLEX_INDENT 122 #define SCLEX_MAXIMA 123 #define SCLEX_STATA 124 #define SCLEX_SAS 125 #define SCLEX_LPEG 999 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 #define SCE_P_NUMBER 2 #define SCE_P_STRING 3 #define SCE_P_CHARACTER 4 #define SCE_P_WORD 5 #define SCE_P_TRIPLE 6 #define SCE_P_TRIPLEDOUBLE 7 #define SCE_P_CLASSNAME 8 #define SCE_P_DEFNAME 9 #define SCE_P_OPERATOR 10 #define SCE_P_IDENTIFIER 11 #define SCE_P_COMMENTBLOCK 12 #define SCE_P_STRINGEOL 13 #define SCE_P_WORD2 14 #define SCE_P_DECORATOR 15 #define SCE_P_FSTRING 16 #define SCE_P_FCHARACTER 17 #define SCE_P_FTRIPLE 18 #define SCE_P_FTRIPLEDOUBLE 19 #define SCE_C_DEFAULT 0 #define SCE_C_COMMENT 1 #define SCE_C_COMMENTLINE 2 #define SCE_C_COMMENTDOC 3 #define SCE_C_NUMBER 4 #define SCE_C_WORD 5 #define SCE_C_STRING 6 #define SCE_C_CHARACTER 7 #define SCE_C_UUID 8 #define SCE_C_PREPROCESSOR 9 #define SCE_C_OPERATOR 10 #define SCE_C_IDENTIFIER 11 #define SCE_C_STRINGEOL 12 #define SCE_C_VERBATIM 13 #define SCE_C_REGEX 14 #define SCE_C_COMMENTLINEDOC 15 #define SCE_C_WORD2 16 #define SCE_C_COMMENTDOCKEYWORD 17 #define SCE_C_COMMENTDOCKEYWORDERROR 18 #define SCE_C_GLOBALCLASS 19 #define SCE_C_STRINGRAW 20 #define SCE_C_TRIPLEVERBATIM 21 #define SCE_C_HASHQUOTEDSTRING 22 #define SCE_C_PREPROCESSORCOMMENT 23 #define SCE_C_PREPROCESSORCOMMENTDOC 24 #define SCE_C_USERLITERAL 25 #define SCE_C_TASKMARKER 26 #define SCE_C_ESCAPESEQUENCE 27 #define SCE_D_DEFAULT 0 #define SCE_D_COMMENT 1 #define SCE_D_COMMENTLINE 2 #define SCE_D_COMMENTDOC 3 #define SCE_D_COMMENTNESTED 4 #define SCE_D_NUMBER 5 #define SCE_D_WORD 6 #define SCE_D_WORD2 7 #define SCE_D_WORD3 8 #define SCE_D_TYPEDEF 9 #define SCE_D_STRING 10 #define SCE_D_STRINGEOL 11 #define SCE_D_CHARACTER 12 #define SCE_D_OPERATOR 13 #define SCE_D_IDENTIFIER 14 #define SCE_D_COMMENTLINEDOC 15 #define SCE_D_COMMENTDOCKEYWORD 16 #define SCE_D_COMMENTDOCKEYWORDERROR 17 #define SCE_D_STRINGB 18 #define SCE_D_STRINGR 19 #define SCE_D_WORD5 20 #define SCE_D_WORD6 21 #define SCE_D_WORD7 22 #define SCE_TCL_DEFAULT 0 #define SCE_TCL_COMMENT 1 #define SCE_TCL_COMMENTLINE 2 #define SCE_TCL_NUMBER 3 #define SCE_TCL_WORD_IN_QUOTE 4 #define SCE_TCL_IN_QUOTE 5 #define SCE_TCL_OPERATOR 6 #define SCE_TCL_IDENTIFIER 7 #define SCE_TCL_SUBSTITUTION 8 #define SCE_TCL_SUB_BRACE 9 #define SCE_TCL_MODIFIER 10 #define SCE_TCL_EXPAND 11 #define SCE_TCL_WORD 12 #define SCE_TCL_WORD2 13 #define SCE_TCL_WORD3 14 #define SCE_TCL_WORD4 15 #define SCE_TCL_WORD5 16 #define SCE_TCL_WORD6 17 #define SCE_TCL_WORD7 18 #define SCE_TCL_WORD8 19 #define SCE_TCL_COMMENT_BOX 20 #define SCE_TCL_BLOCK_COMMENT 21 #define SCE_H_DEFAULT 0 #define SCE_H_TAG 1 #define SCE_H_TAGUNKNOWN 2 #define SCE_H_ATTRIBUTE 3 #define SCE_H_ATTRIBUTEUNKNOWN 4 #define SCE_H_NUMBER 5 #define SCE_H_DOUBLESTRING 6 #define SCE_H_SINGLESTRING 7 #define SCE_H_OTHER 8 #define SCE_H_COMMENT 9 #define SCE_H_ENTITY 10 #define SCE_H_TAGEND 11 #define SCE_H_XMLSTART 12 #define SCE_H_XMLEND 13 #define SCE_H_SCRIPT 14 #define SCE_H_ASP 15 #define SCE_H_ASPAT 16 #define SCE_H_CDATA 17 #define SCE_H_QUESTION 18 #define SCE_H_VALUE 19 #define SCE_H_XCCOMMENT 20 #define SCE_H_SGML_DEFAULT 21 #define SCE_H_SGML_COMMAND 22 #define SCE_H_SGML_1ST_PARAM 23 #define SCE_H_SGML_DOUBLESTRING 24 #define SCE_H_SGML_SIMPLESTRING 25 #define SCE_H_SGML_ERROR 26 #define SCE_H_SGML_SPECIAL 27 #define SCE_H_SGML_ENTITY 28 #define SCE_H_SGML_COMMENT 29 #define SCE_H_SGML_1ST_PARAM_COMMENT 30 #define SCE_H_SGML_BLOCK_DEFAULT 31 #define SCE_HJ_START 40 #define SCE_HJ_DEFAULT 41 #define SCE_HJ_COMMENT 42 #define SCE_HJ_COMMENTLINE 43 #define SCE_HJ_COMMENTDOC 44 #define SCE_HJ_NUMBER 45 #define SCE_HJ_WORD 46 #define SCE_HJ_KEYWORD 47 #define SCE_HJ_DOUBLESTRING 48 #define SCE_HJ_SINGLESTRING 49 #define SCE_HJ_SYMBOLS 50 #define SCE_HJ_STRINGEOL 51 #define SCE_HJ_REGEX 52 #define SCE_HJA_START 55 #define SCE_HJA_DEFAULT 56 #define SCE_HJA_COMMENT 57 #define SCE_HJA_COMMENTLINE 58 #define SCE_HJA_COMMENTDOC 59 #define SCE_HJA_NUMBER 60 #define SCE_HJA_WORD 61 #define SCE_HJA_KEYWORD 62 #define SCE_HJA_DOUBLESTRING 63 #define SCE_HJA_SINGLESTRING 64 #define SCE_HJA_SYMBOLS 65 #define SCE_HJA_STRINGEOL 66 #define SCE_HJA_REGEX 67 #define SCE_HB_START 70 #define SCE_HB_DEFAULT 71 #define SCE_HB_COMMENTLINE 72 #define SCE_HB_NUMBER 73 #define SCE_HB_WORD 74 #define SCE_HB_STRING 75 #define SCE_HB_IDENTIFIER 76 #define SCE_HB_STRINGEOL 77 #define SCE_HBA_START 80 #define SCE_HBA_DEFAULT 81 #define SCE_HBA_COMMENTLINE 82 #define SCE_HBA_NUMBER 83 #define SCE_HBA_WORD 84 #define SCE_HBA_STRING 85 #define SCE_HBA_IDENTIFIER 86 #define SCE_HBA_STRINGEOL 87 #define SCE_HP_START 90 #define SCE_HP_DEFAULT 91 #define SCE_HP_COMMENTLINE 92 #define SCE_HP_NUMBER 93 #define SCE_HP_STRING 94 #define SCE_HP_CHARACTER 95 #define SCE_HP_WORD 96 #define SCE_HP_TRIPLE 97 #define SCE_HP_TRIPLEDOUBLE 98 #define SCE_HP_CLASSNAME 99 #define SCE_HP_DEFNAME 100 #define SCE_HP_OPERATOR 101 #define SCE_HP_IDENTIFIER 102 #define SCE_HPHP_COMPLEX_VARIABLE 104 #define SCE_HPA_START 105 #define SCE_HPA_DEFAULT 106 #define SCE_HPA_COMMENTLINE 107 #define SCE_HPA_NUMBER 108 #define SCE_HPA_STRING 109 #define SCE_HPA_CHARACTER 110 #define SCE_HPA_WORD 111 #define SCE_HPA_TRIPLE 112 #define SCE_HPA_TRIPLEDOUBLE 113 #define SCE_HPA_CLASSNAME 114 #define SCE_HPA_DEFNAME 115 #define SCE_HPA_OPERATOR 116 #define SCE_HPA_IDENTIFIER 117 #define SCE_HPHP_DEFAULT 118 #define SCE_HPHP_HSTRING 119 #define SCE_HPHP_SIMPLESTRING 120 #define SCE_HPHP_WORD 121 #define SCE_HPHP_NUMBER 122 #define SCE_HPHP_VARIABLE 123 #define SCE_HPHP_COMMENT 124 #define SCE_HPHP_COMMENTLINE 125 #define SCE_HPHP_HSTRING_VARIABLE 126 #define SCE_HPHP_OPERATOR 127 #define SCE_PL_DEFAULT 0 #define SCE_PL_ERROR 1 #define SCE_PL_COMMENTLINE 2 #define SCE_PL_POD 3 #define SCE_PL_NUMBER 4 #define SCE_PL_WORD 5 #define SCE_PL_STRING 6 #define SCE_PL_CHARACTER 7 #define SCE_PL_PUNCTUATION 8 #define SCE_PL_PREPROCESSOR 9 #define SCE_PL_OPERATOR 10 #define SCE_PL_IDENTIFIER 11 #define SCE_PL_SCALAR 12 #define SCE_PL_ARRAY 13 #define SCE_PL_HASH 14 #define SCE_PL_SYMBOLTABLE 15 #define SCE_PL_VARIABLE_INDEXER 16 #define SCE_PL_REGEX 17 #define SCE_PL_REGSUBST 18 #define SCE_PL_LONGQUOTE 19 #define SCE_PL_BACKTICKS 20 #define SCE_PL_DATASECTION 21 #define SCE_PL_HERE_DELIM 22 #define SCE_PL_HERE_Q 23 #define SCE_PL_HERE_QQ 24 #define SCE_PL_HERE_QX 25 #define SCE_PL_STRING_Q 26 #define SCE_PL_STRING_QQ 27 #define SCE_PL_STRING_QX 28 #define SCE_PL_STRING_QR 29 #define SCE_PL_STRING_QW 30 #define SCE_PL_POD_VERB 31 #define SCE_PL_SUB_PROTOTYPE 40 #define SCE_PL_FORMAT_IDENT 41 #define SCE_PL_FORMAT 42 #define SCE_PL_STRING_VAR 43 #define SCE_PL_XLAT 44 #define SCE_PL_REGEX_VAR 54 #define SCE_PL_REGSUBST_VAR 55 #define SCE_PL_BACKTICKS_VAR 57 #define SCE_PL_HERE_QQ_VAR 61 #define SCE_PL_HERE_QX_VAR 62 #define SCE_PL_STRING_QQ_VAR 64 #define SCE_PL_STRING_QX_VAR 65 #define SCE_PL_STRING_QR_VAR 66 #define SCE_RB_DEFAULT 0 #define SCE_RB_ERROR 1 #define SCE_RB_COMMENTLINE 2 #define SCE_RB_POD 3 #define SCE_RB_NUMBER 4 #define SCE_RB_WORD 5 #define SCE_RB_STRING 6 #define SCE_RB_CHARACTER 7 #define SCE_RB_CLASSNAME 8 #define SCE_RB_DEFNAME 9 #define SCE_RB_OPERATOR 10 #define SCE_RB_IDENTIFIER 11 #define SCE_RB_REGEX 12 #define SCE_RB_GLOBAL 13 #define SCE_RB_SYMBOL 14 #define SCE_RB_MODULE_NAME 15 #define SCE_RB_INSTANCE_VAR 16 #define SCE_RB_CLASS_VAR 17 #define SCE_RB_BACKTICKS 18 #define SCE_RB_DATASECTION 19 #define SCE_RB_HERE_DELIM 20 #define SCE_RB_HERE_Q 21 #define SCE_RB_HERE_QQ 22 #define SCE_RB_HERE_QX 23 #define SCE_RB_STRING_Q 24 #define SCE_RB_STRING_QQ 25 #define SCE_RB_STRING_QX 26 #define SCE_RB_STRING_QR 27 #define SCE_RB_STRING_QW 28 #define SCE_RB_WORD_DEMOTED 29 #define SCE_RB_STDIN 30 #define SCE_RB_STDOUT 31 #define SCE_RB_STDERR 40 #define SCE_RB_UPPER_BOUND 41 #define SCE_B_DEFAULT 0 #define SCE_B_COMMENT 1 #define SCE_B_NUMBER 2 #define SCE_B_KEYWORD 3 #define SCE_B_STRING 4 #define SCE_B_PREPROCESSOR 5 #define SCE_B_OPERATOR 6 #define SCE_B_IDENTIFIER 7 #define SCE_B_DATE 8 #define SCE_B_STRINGEOL 9 #define SCE_B_KEYWORD2 10 #define SCE_B_KEYWORD3 11 #define SCE_B_KEYWORD4 12 #define SCE_B_CONSTANT 13 #define SCE_B_ASM 14 #define SCE_B_LABEL 15 #define SCE_B_ERROR 16 #define SCE_B_HEXNUMBER 17 #define SCE_B_BINNUMBER 18 #define SCE_B_COMMENTBLOCK 19 #define SCE_B_DOCLINE 20 #define SCE_B_DOCBLOCK 21 #define SCE_B_DOCKEYWORD 22 #define SCE_PROPS_DEFAULT 0 #define SCE_PROPS_COMMENT 1 #define SCE_PROPS_SECTION 2 #define SCE_PROPS_ASSIGNMENT 3 #define SCE_PROPS_DEFVAL 4 #define SCE_PROPS_KEY 5 #define SCE_L_DEFAULT 0 #define SCE_L_COMMAND 1 #define SCE_L_TAG 2 #define SCE_L_MATH 3 #define SCE_L_COMMENT 4 #define SCE_L_TAG2 5 #define SCE_L_MATH2 6 #define SCE_L_COMMENT2 7 #define SCE_L_VERBATIM 8 #define SCE_L_SHORTCMD 9 #define SCE_L_SPECIAL 10 #define SCE_L_CMDOPT 11 #define SCE_L_ERROR 12 #define SCE_LUA_DEFAULT 0 #define SCE_LUA_COMMENT 1 #define SCE_LUA_COMMENTLINE 2 #define SCE_LUA_COMMENTDOC 3 #define SCE_LUA_NUMBER 4 #define SCE_LUA_WORD 5 #define SCE_LUA_STRING 6 #define SCE_LUA_CHARACTER 7 #define SCE_LUA_LITERALSTRING 8 #define SCE_LUA_PREPROCESSOR 9 #define SCE_LUA_OPERATOR 10 #define SCE_LUA_IDENTIFIER 11 #define SCE_LUA_STRINGEOL 12 #define SCE_LUA_WORD2 13 #define SCE_LUA_WORD3 14 #define SCE_LUA_WORD4 15 #define SCE_LUA_WORD5 16 #define SCE_LUA_WORD6 17 #define SCE_LUA_WORD7 18 #define SCE_LUA_WORD8 19 #define SCE_LUA_LABEL 20 #define SCE_ERR_DEFAULT 0 #define SCE_ERR_PYTHON 1 #define SCE_ERR_GCC 2 #define SCE_ERR_MS 3 #define SCE_ERR_CMD 4 #define SCE_ERR_BORLAND 5 #define SCE_ERR_PERL 6 #define SCE_ERR_NET 7 #define SCE_ERR_LUA 8 #define SCE_ERR_CTAG 9 #define SCE_ERR_DIFF_CHANGED 10 #define SCE_ERR_DIFF_ADDITION 11 #define SCE_ERR_DIFF_DELETION 12 #define SCE_ERR_DIFF_MESSAGE 13 #define SCE_ERR_PHP 14 #define SCE_ERR_ELF 15 #define SCE_ERR_IFC 16 #define SCE_ERR_IFORT 17 #define SCE_ERR_ABSF 18 #define SCE_ERR_TIDY 19 #define SCE_ERR_JAVA_STACK 20 #define SCE_ERR_VALUE 21 #define SCE_ERR_GCC_INCLUDED_FROM 22 #define SCE_ERR_ESCSEQ 23 #define SCE_ERR_ESCSEQ_UNKNOWN 24 #define SCE_ERR_ES_BLACK 40 #define SCE_ERR_ES_RED 41 #define SCE_ERR_ES_GREEN 42 #define SCE_ERR_ES_BROWN 43 #define SCE_ERR_ES_BLUE 44 #define SCE_ERR_ES_MAGENTA 45 #define SCE_ERR_ES_CYAN 46 #define SCE_ERR_ES_GRAY 47 #define SCE_ERR_ES_DARK_GRAY 48 #define SCE_ERR_ES_BRIGHT_RED 49 #define SCE_ERR_ES_BRIGHT_GREEN 50 #define SCE_ERR_ES_YELLOW 51 #define SCE_ERR_ES_BRIGHT_BLUE 52 #define SCE_ERR_ES_BRIGHT_MAGENTA 53 #define SCE_ERR_ES_BRIGHT_CYAN 54 #define SCE_ERR_ES_WHITE 55 #define SCE_BAT_DEFAULT 0 #define SCE_BAT_COMMENT 1 #define SCE_BAT_WORD 2 #define SCE_BAT_LABEL 3 #define SCE_BAT_HIDE 4 #define SCE_BAT_COMMAND 5 #define SCE_BAT_IDENTIFIER 6 #define SCE_BAT_OPERATOR 7 #define SCE_TCMD_DEFAULT 0 #define SCE_TCMD_COMMENT 1 #define SCE_TCMD_WORD 2 #define SCE_TCMD_LABEL 3 #define SCE_TCMD_HIDE 4 #define SCE_TCMD_COMMAND 5 #define SCE_TCMD_IDENTIFIER 6 #define SCE_TCMD_OPERATOR 7 #define SCE_TCMD_ENVIRONMENT 8 #define SCE_TCMD_EXPANSION 9 #define SCE_TCMD_CLABEL 10 #define SCE_MAKE_DEFAULT 0 #define SCE_MAKE_COMMENT 1 #define SCE_MAKE_PREPROCESSOR 2 #define SCE_MAKE_IDENTIFIER 3 #define SCE_MAKE_OPERATOR 4 #define SCE_MAKE_TARGET 5 #define SCE_MAKE_IDEOL 9 #define SCE_DIFF_DEFAULT 0 #define SCE_DIFF_COMMENT 1 #define SCE_DIFF_COMMAND 2 #define SCE_DIFF_HEADER 3 #define SCE_DIFF_POSITION 4 #define SCE_DIFF_DELETED 5 #define SCE_DIFF_ADDED 6 #define SCE_DIFF_CHANGED 7 #define SCE_DIFF_PATCH_ADD 8 #define SCE_DIFF_PATCH_DELETE 9 #define SCE_DIFF_REMOVED_PATCH_ADD 10 #define SCE_DIFF_REMOVED_PATCH_DELETE 11 #define SCE_CONF_DEFAULT 0 #define SCE_CONF_COMMENT 1 #define SCE_CONF_NUMBER 2 #define SCE_CONF_IDENTIFIER 3 #define SCE_CONF_EXTENSION 4 #define SCE_CONF_PARAMETER 5 #define SCE_CONF_STRING 6 #define SCE_CONF_OPERATOR 7 #define SCE_CONF_IP 8 #define SCE_CONF_DIRECTIVE 9 #define SCE_AVE_DEFAULT 0 #define SCE_AVE_COMMENT 1 #define SCE_AVE_NUMBER 2 #define SCE_AVE_WORD 3 #define SCE_AVE_STRING 6 #define SCE_AVE_ENUM 7 #define SCE_AVE_STRINGEOL 8 #define SCE_AVE_IDENTIFIER 9 #define SCE_AVE_OPERATOR 10 #define SCE_AVE_WORD1 11 #define SCE_AVE_WORD2 12 #define SCE_AVE_WORD3 13 #define SCE_AVE_WORD4 14 #define SCE_AVE_WORD5 15 #define SCE_AVE_WORD6 16 #define SCE_ADA_DEFAULT 0 #define SCE_ADA_WORD 1 #define SCE_ADA_IDENTIFIER 2 #define SCE_ADA_NUMBER 3 #define SCE_ADA_DELIMITER 4 #define SCE_ADA_CHARACTER 5 #define SCE_ADA_CHARACTEREOL 6 #define SCE_ADA_STRING 7 #define SCE_ADA_STRINGEOL 8 #define SCE_ADA_LABEL 9 #define SCE_ADA_COMMENTLINE 10 #define SCE_ADA_ILLEGAL 11 #define SCE_BAAN_DEFAULT 0 #define SCE_BAAN_COMMENT 1 #define SCE_BAAN_COMMENTDOC 2 #define SCE_BAAN_NUMBER 3 #define SCE_BAAN_WORD 4 #define SCE_BAAN_STRING 5 #define SCE_BAAN_PREPROCESSOR 6 #define SCE_BAAN_OPERATOR 7 #define SCE_BAAN_IDENTIFIER 8 #define SCE_BAAN_STRINGEOL 9 #define SCE_BAAN_WORD2 10 #define SCE_BAAN_WORD3 11 #define SCE_BAAN_WORD4 12 #define SCE_BAAN_WORD5 13 #define SCE_BAAN_WORD6 14 #define SCE_BAAN_WORD7 15 #define SCE_BAAN_WORD8 16 #define SCE_BAAN_WORD9 17 #define SCE_BAAN_TABLEDEF 18 #define SCE_BAAN_TABLESQL 19 #define SCE_BAAN_FUNCTION 20 #define SCE_BAAN_DOMDEF 21 #define SCE_BAAN_FUNCDEF 22 #define SCE_BAAN_OBJECTDEF 23 #define SCE_BAAN_DEFINEDEF 24 #define SCE_LISP_DEFAULT 0 #define SCE_LISP_COMMENT 1 #define SCE_LISP_NUMBER 2 #define SCE_LISP_KEYWORD 3 #define SCE_LISP_KEYWORD_KW 4 #define SCE_LISP_SYMBOL 5 #define SCE_LISP_STRING 6 #define SCE_LISP_STRINGEOL 8 #define SCE_LISP_IDENTIFIER 9 #define SCE_LISP_OPERATOR 10 #define SCE_LISP_SPECIAL 11 #define SCE_LISP_MULTI_COMMENT 12 #define SCE_EIFFEL_DEFAULT 0 #define SCE_EIFFEL_COMMENTLINE 1 #define SCE_EIFFEL_NUMBER 2 #define SCE_EIFFEL_WORD 3 #define SCE_EIFFEL_STRING 4 #define SCE_EIFFEL_CHARACTER 5 #define SCE_EIFFEL_OPERATOR 6 #define SCE_EIFFEL_IDENTIFIER 7 #define SCE_EIFFEL_STRINGEOL 8 #define SCE_NNCRONTAB_DEFAULT 0 #define SCE_NNCRONTAB_COMMENT 1 #define SCE_NNCRONTAB_TASK 2 #define SCE_NNCRONTAB_SECTION 3 #define SCE_NNCRONTAB_KEYWORD 4 #define SCE_NNCRONTAB_MODIFIER 5 #define SCE_NNCRONTAB_ASTERISK 6 #define SCE_NNCRONTAB_NUMBER 7 #define SCE_NNCRONTAB_STRING 8 #define SCE_NNCRONTAB_ENVIRONMENT 9 #define SCE_NNCRONTAB_IDENTIFIER 10 #define SCE_FORTH_DEFAULT 0 #define SCE_FORTH_COMMENT 1 #define SCE_FORTH_COMMENT_ML 2 #define SCE_FORTH_IDENTIFIER 3 #define SCE_FORTH_CONTROL 4 #define SCE_FORTH_KEYWORD 5 #define SCE_FORTH_DEFWORD 6 #define SCE_FORTH_PREWORD1 7 #define SCE_FORTH_PREWORD2 8 #define SCE_FORTH_NUMBER 9 #define SCE_FORTH_STRING 10 #define SCE_FORTH_LOCALE 11 #define SCE_MATLAB_DEFAULT 0 #define SCE_MATLAB_COMMENT 1 #define SCE_MATLAB_COMMAND 2 #define SCE_MATLAB_NUMBER 3 #define SCE_MATLAB_KEYWORD 4 #define SCE_MATLAB_STRING 5 #define SCE_MATLAB_OPERATOR 6 #define SCE_MATLAB_IDENTIFIER 7 #define SCE_MATLAB_DOUBLEQUOTESTRING 8 #define SCE_MAXIMA_OPERATOR 0 #define SCE_MAXIMA_COMMANDENDING 1 #define SCE_MAXIMA_COMMENT 2 #define SCE_MAXIMA_NUMBER 3 #define SCE_MAXIMA_STRING 4 #define SCE_MAXIMA_COMMAND 5 #define SCE_MAXIMA_VARIABLE 6 #define SCE_MAXIMA_UNKNOWN 7 #define SCE_SCRIPTOL_DEFAULT 0 #define SCE_SCRIPTOL_WHITE 1 #define SCE_SCRIPTOL_COMMENTLINE 2 #define SCE_SCRIPTOL_PERSISTENT 3 #define SCE_SCRIPTOL_CSTYLE 4 #define SCE_SCRIPTOL_COMMENTBLOCK 5 #define SCE_SCRIPTOL_NUMBER 6 #define SCE_SCRIPTOL_STRING 7 #define SCE_SCRIPTOL_CHARACTER 8 #define SCE_SCRIPTOL_STRINGEOL 9 #define SCE_SCRIPTOL_KEYWORD 10 #define SCE_SCRIPTOL_OPERATOR 11 #define SCE_SCRIPTOL_IDENTIFIER 12 #define SCE_SCRIPTOL_TRIPLE 13 #define SCE_SCRIPTOL_CLASSNAME 14 #define SCE_SCRIPTOL_PREPROCESSOR 15 #define SCE_ASM_DEFAULT 0 #define SCE_ASM_COMMENT 1 #define SCE_ASM_NUMBER 2 #define SCE_ASM_STRING 3 #define SCE_ASM_OPERATOR 4 #define SCE_ASM_IDENTIFIER 5 #define SCE_ASM_CPUINSTRUCTION 6 #define SCE_ASM_MATHINSTRUCTION 7 #define SCE_ASM_REGISTER 8 #define SCE_ASM_DIRECTIVE 9 #define SCE_ASM_DIRECTIVEOPERAND 10 #define SCE_ASM_COMMENTBLOCK 11 #define SCE_ASM_CHARACTER 12 #define SCE_ASM_STRINGEOL 13 #define SCE_ASM_EXTINSTRUCTION 14 #define SCE_ASM_COMMENTDIRECTIVE 15 #define SCE_F_DEFAULT 0 #define SCE_F_COMMENT 1 #define SCE_F_NUMBER 2 #define SCE_F_STRING1 3 #define SCE_F_STRING2 4 #define SCE_F_STRINGEOL 5 #define SCE_F_OPERATOR 6 #define SCE_F_IDENTIFIER 7 #define SCE_F_WORD 8 #define SCE_F_WORD2 9 #define SCE_F_WORD3 10 #define SCE_F_PREPROCESSOR 11 #define SCE_F_OPERATOR2 12 #define SCE_F_LABEL 13 #define SCE_F_CONTINUATION 14 #define SCE_CSS_DEFAULT 0 #define SCE_CSS_TAG 1 #define SCE_CSS_CLASS 2 #define SCE_CSS_PSEUDOCLASS 3 #define SCE_CSS_UNKNOWN_PSEUDOCLASS 4 #define SCE_CSS_OPERATOR 5 #define SCE_CSS_IDENTIFIER 6 #define SCE_CSS_UNKNOWN_IDENTIFIER 7 #define SCE_CSS_VALUE 8 #define SCE_CSS_COMMENT 9 #define SCE_CSS_ID 10 #define SCE_CSS_IMPORTANT 11 #define SCE_CSS_DIRECTIVE 12 #define SCE_CSS_DOUBLESTRING 13 #define SCE_CSS_SINGLESTRING 14 #define SCE_CSS_IDENTIFIER2 15 #define SCE_CSS_ATTRIBUTE 16 #define SCE_CSS_IDENTIFIER3 17 #define SCE_CSS_PSEUDOELEMENT 18 #define SCE_CSS_EXTENDED_IDENTIFIER 19 #define SCE_CSS_EXTENDED_PSEUDOCLASS 20 #define SCE_CSS_EXTENDED_PSEUDOELEMENT 21 #define SCE_CSS_MEDIA 22 #define SCE_CSS_VARIABLE 23 #define SCE_POV_DEFAULT 0 #define SCE_POV_COMMENT 1 #define SCE_POV_COMMENTLINE 2 #define SCE_POV_NUMBER 3 #define SCE_POV_OPERATOR 4 #define SCE_POV_IDENTIFIER 5 #define SCE_POV_STRING 6 #define SCE_POV_STRINGEOL 7 #define SCE_POV_DIRECTIVE 8 #define SCE_POV_BADDIRECTIVE 9 #define SCE_POV_WORD2 10 #define SCE_POV_WORD3 11 #define SCE_POV_WORD4 12 #define SCE_POV_WORD5 13 #define SCE_POV_WORD6 14 #define SCE_POV_WORD7 15 #define SCE_POV_WORD8 16 #define SCE_LOUT_DEFAULT 0 #define SCE_LOUT_COMMENT 1 #define SCE_LOUT_NUMBER 2 #define SCE_LOUT_WORD 3 #define SCE_LOUT_WORD2 4 #define SCE_LOUT_WORD3 5 #define SCE_LOUT_WORD4 6 #define SCE_LOUT_STRING 7 #define SCE_LOUT_OPERATOR 8 #define SCE_LOUT_IDENTIFIER 9 #define SCE_LOUT_STRINGEOL 10 #define SCE_ESCRIPT_DEFAULT 0 #define SCE_ESCRIPT_COMMENT 1 #define SCE_ESCRIPT_COMMENTLINE 2 #define SCE_ESCRIPT_COMMENTDOC 3 #define SCE_ESCRIPT_NUMBER 4 #define SCE_ESCRIPT_WORD 5 #define SCE_ESCRIPT_STRING 6 #define SCE_ESCRIPT_OPERATOR 7 #define SCE_ESCRIPT_IDENTIFIER 8 #define SCE_ESCRIPT_BRACE 9 #define SCE_ESCRIPT_WORD2 10 #define SCE_ESCRIPT_WORD3 11 #define SCE_PS_DEFAULT 0 #define SCE_PS_COMMENT 1 #define SCE_PS_DSC_COMMENT 2 #define SCE_PS_DSC_VALUE 3 #define SCE_PS_NUMBER 4 #define SCE_PS_NAME 5 #define SCE_PS_KEYWORD 6 #define SCE_PS_LITERAL 7 #define SCE_PS_IMMEVAL 8 #define SCE_PS_PAREN_ARRAY 9 #define SCE_PS_PAREN_DICT 10 #define SCE_PS_PAREN_PROC 11 #define SCE_PS_TEXT 12 #define SCE_PS_HEXSTRING 13 #define SCE_PS_BASE85STRING 14 #define SCE_PS_BADSTRINGCHAR 15 #define SCE_NSIS_DEFAULT 0 #define SCE_NSIS_COMMENT 1 #define SCE_NSIS_STRINGDQ 2 #define SCE_NSIS_STRINGLQ 3 #define SCE_NSIS_STRINGRQ 4 #define SCE_NSIS_FUNCTION 5 #define SCE_NSIS_VARIABLE 6 #define SCE_NSIS_LABEL 7 #define SCE_NSIS_USERDEFINED 8 #define SCE_NSIS_SECTIONDEF 9 #define SCE_NSIS_SUBSECTIONDEF 10 #define SCE_NSIS_IFDEFINEDEF 11 #define SCE_NSIS_MACRODEF 12 #define SCE_NSIS_STRINGVAR 13 #define SCE_NSIS_NUMBER 14 #define SCE_NSIS_SECTIONGROUP 15 #define SCE_NSIS_PAGEEX 16 #define SCE_NSIS_FUNCTIONDEF 17 #define SCE_NSIS_COMMENTBOX 18 #define SCE_MMIXAL_LEADWS 0 #define SCE_MMIXAL_COMMENT 1 #define SCE_MMIXAL_LABEL 2 #define SCE_MMIXAL_OPCODE 3 #define SCE_MMIXAL_OPCODE_PRE 4 #define SCE_MMIXAL_OPCODE_VALID 5 #define SCE_MMIXAL_OPCODE_UNKNOWN 6 #define SCE_MMIXAL_OPCODE_POST 7 #define SCE_MMIXAL_OPERANDS 8 #define SCE_MMIXAL_NUMBER 9 #define SCE_MMIXAL_REF 10 #define SCE_MMIXAL_CHAR 11 #define SCE_MMIXAL_STRING 12 #define SCE_MMIXAL_REGISTER 13 #define SCE_MMIXAL_HEX 14 #define SCE_MMIXAL_OPERATOR 15 #define SCE_MMIXAL_SYMBOL 16 #define SCE_MMIXAL_INCLUDE 17 #define SCE_CLW_DEFAULT 0 #define SCE_CLW_LABEL 1 #define SCE_CLW_COMMENT 2 #define SCE_CLW_STRING 3 #define SCE_CLW_USER_IDENTIFIER 4 #define SCE_CLW_INTEGER_CONSTANT 5 #define SCE_CLW_REAL_CONSTANT 6 #define SCE_CLW_PICTURE_STRING 7 #define SCE_CLW_KEYWORD 8 #define SCE_CLW_COMPILER_DIRECTIVE 9 #define SCE_CLW_RUNTIME_EXPRESSIONS 10 #define SCE_CLW_BUILTIN_PROCEDURES_FUNCTION 11 #define SCE_CLW_STRUCTURE_DATA_TYPE 12 #define SCE_CLW_ATTRIBUTE 13 #define SCE_CLW_STANDARD_EQUATE 14 #define SCE_CLW_ERROR 15 #define SCE_CLW_DEPRECATED 16 #define SCE_LOT_DEFAULT 0 #define SCE_LOT_HEADER 1 #define SCE_LOT_BREAK 2 #define SCE_LOT_SET 3 #define SCE_LOT_PASS 4 #define SCE_LOT_FAIL 5 #define SCE_LOT_ABORT 6 #define SCE_YAML_DEFAULT 0 #define SCE_YAML_COMMENT 1 #define SCE_YAML_IDENTIFIER 2 #define SCE_YAML_KEYWORD 3 #define SCE_YAML_NUMBER 4 #define SCE_YAML_REFERENCE 5 #define SCE_YAML_DOCUMENT 6 #define SCE_YAML_TEXT 7 #define SCE_YAML_ERROR 8 #define SCE_YAML_OPERATOR 9 #define SCE_TEX_DEFAULT 0 #define SCE_TEX_SPECIAL 1 #define SCE_TEX_GROUP 2 #define SCE_TEX_SYMBOL 3 #define SCE_TEX_COMMAND 4 #define SCE_TEX_TEXT 5 #define SCE_METAPOST_DEFAULT 0 #define SCE_METAPOST_SPECIAL 1 #define SCE_METAPOST_GROUP 2 #define SCE_METAPOST_SYMBOL 3 #define SCE_METAPOST_COMMAND 4 #define SCE_METAPOST_TEXT 5 #define SCE_METAPOST_EXTRA 6 #define SCE_ERLANG_DEFAULT 0 #define SCE_ERLANG_COMMENT 1 #define SCE_ERLANG_VARIABLE 2 #define SCE_ERLANG_NUMBER 3 #define SCE_ERLANG_KEYWORD 4 #define SCE_ERLANG_STRING 5 #define SCE_ERLANG_OPERATOR 6 #define SCE_ERLANG_ATOM 7 #define SCE_ERLANG_FUNCTION_NAME 8 #define SCE_ERLANG_CHARACTER 9 #define SCE_ERLANG_MACRO 10 #define SCE_ERLANG_RECORD 11 #define SCE_ERLANG_PREPROC 12 #define SCE_ERLANG_NODE_NAME 13 #define SCE_ERLANG_COMMENT_FUNCTION 14 #define SCE_ERLANG_COMMENT_MODULE 15 #define SCE_ERLANG_COMMENT_DOC 16 #define SCE_ERLANG_COMMENT_DOC_MACRO 17 #define SCE_ERLANG_ATOM_QUOTED 18 #define SCE_ERLANG_MACRO_QUOTED 19 #define SCE_ERLANG_RECORD_QUOTED 20 #define SCE_ERLANG_NODE_NAME_QUOTED 21 #define SCE_ERLANG_BIFS 22 #define SCE_ERLANG_MODULES 23 #define SCE_ERLANG_MODULES_ATT 24 #define SCE_ERLANG_UNKNOWN 31 #define SCE_MSSQL_DEFAULT 0 #define SCE_MSSQL_COMMENT 1 #define SCE_MSSQL_LINE_COMMENT 2 #define SCE_MSSQL_NUMBER 3 #define SCE_MSSQL_STRING 4 #define SCE_MSSQL_OPERATOR 5 #define SCE_MSSQL_IDENTIFIER 6 #define SCE_MSSQL_VARIABLE 7 #define SCE_MSSQL_COLUMN_NAME 8 #define SCE_MSSQL_STATEMENT 9 #define SCE_MSSQL_DATATYPE 10 #define SCE_MSSQL_SYSTABLE 11 #define SCE_MSSQL_GLOBAL_VARIABLE 12 #define SCE_MSSQL_FUNCTION 13 #define SCE_MSSQL_STORED_PROCEDURE 14 #define SCE_MSSQL_DEFAULT_PREF_DATATYPE 15 #define SCE_MSSQL_COLUMN_NAME_2 16 #define SCE_V_DEFAULT 0 #define SCE_V_COMMENT 1 #define SCE_V_COMMENTLINE 2 #define SCE_V_COMMENTLINEBANG 3 #define SCE_V_NUMBER 4 #define SCE_V_WORD 5 #define SCE_V_STRING 6 #define SCE_V_WORD2 7 #define SCE_V_WORD3 8 #define SCE_V_PREPROCESSOR 9 #define SCE_V_OPERATOR 10 #define SCE_V_IDENTIFIER 11 #define SCE_V_STRINGEOL 12 #define SCE_V_USER 19 #define SCE_V_COMMENT_WORD 20 #define SCE_V_INPUT 21 #define SCE_V_OUTPUT 22 #define SCE_V_INOUT 23 #define SCE_V_PORT_CONNECT 24 #define SCE_KIX_DEFAULT 0 #define SCE_KIX_COMMENT 1 #define SCE_KIX_STRING1 2 #define SCE_KIX_STRING2 3 #define SCE_KIX_NUMBER 4 #define SCE_KIX_VAR 5 #define SCE_KIX_MACRO 6 #define SCE_KIX_KEYWORD 7 #define SCE_KIX_FUNCTIONS 8 #define SCE_KIX_OPERATOR 9 #define SCE_KIX_COMMENTSTREAM 10 #define SCE_KIX_IDENTIFIER 31 #define SCE_GC_DEFAULT 0 #define SCE_GC_COMMENTLINE 1 #define SCE_GC_COMMENTBLOCK 2 #define SCE_GC_GLOBAL 3 #define SCE_GC_EVENT 4 #define SCE_GC_ATTRIBUTE 5 #define SCE_GC_CONTROL 6 #define SCE_GC_COMMAND 7 #define SCE_GC_STRING 8 #define SCE_GC_OPERATOR 9 #define SCE_SN_DEFAULT 0 #define SCE_SN_CODE 1 #define SCE_SN_COMMENTLINE 2 #define SCE_SN_COMMENTLINEBANG 3 #define SCE_SN_NUMBER 4 #define SCE_SN_WORD 5 #define SCE_SN_STRING 6 #define SCE_SN_WORD2 7 #define SCE_SN_WORD3 8 #define SCE_SN_PREPROCESSOR 9 #define SCE_SN_OPERATOR 10 #define SCE_SN_IDENTIFIER 11 #define SCE_SN_STRINGEOL 12 #define SCE_SN_REGEXTAG 13 #define SCE_SN_SIGNAL 14 #define SCE_SN_USER 19 #define SCE_AU3_DEFAULT 0 #define SCE_AU3_COMMENT 1 #define SCE_AU3_COMMENTBLOCK 2 #define SCE_AU3_NUMBER 3 #define SCE_AU3_FUNCTION 4 #define SCE_AU3_KEYWORD 5 #define SCE_AU3_MACRO 6 #define SCE_AU3_STRING 7 #define SCE_AU3_OPERATOR 8 #define SCE_AU3_VARIABLE 9 #define SCE_AU3_SENT 10 #define SCE_AU3_PREPROCESSOR 11 #define SCE_AU3_SPECIAL 12 #define SCE_AU3_EXPAND 13 #define SCE_AU3_COMOBJ 14 #define SCE_AU3_UDF 15 #define SCE_APDL_DEFAULT 0 #define SCE_APDL_COMMENT 1 #define SCE_APDL_COMMENTBLOCK 2 #define SCE_APDL_NUMBER 3 #define SCE_APDL_STRING 4 #define SCE_APDL_OPERATOR 5 #define SCE_APDL_WORD 6 #define SCE_APDL_PROCESSOR 7 #define SCE_APDL_COMMAND 8 #define SCE_APDL_SLASHCOMMAND 9 #define SCE_APDL_STARCOMMAND 10 #define SCE_APDL_ARGUMENT 11 #define SCE_APDL_FUNCTION 12 #define SCE_SH_DEFAULT 0 #define SCE_SH_ERROR 1 #define SCE_SH_COMMENTLINE 2 #define SCE_SH_NUMBER 3 #define SCE_SH_WORD 4 #define SCE_SH_STRING 5 #define SCE_SH_CHARACTER 6 #define SCE_SH_OPERATOR 7 #define SCE_SH_IDENTIFIER 8 #define SCE_SH_SCALAR 9 #define SCE_SH_PARAM 10 #define SCE_SH_BACKTICKS 11 #define SCE_SH_HERE_DELIM 12 #define SCE_SH_HERE_Q 13 #define SCE_ASN1_DEFAULT 0 #define SCE_ASN1_COMMENT 1 #define SCE_ASN1_IDENTIFIER 2 #define SCE_ASN1_STRING 3 #define SCE_ASN1_OID 4 #define SCE_ASN1_SCALAR 5 #define SCE_ASN1_KEYWORD 6 #define SCE_ASN1_ATTRIBUTE 7 #define SCE_ASN1_DESCRIPTOR 8 #define SCE_ASN1_TYPE 9 #define SCE_ASN1_OPERATOR 10 #define SCE_VHDL_DEFAULT 0 #define SCE_VHDL_COMMENT 1 #define SCE_VHDL_COMMENTLINEBANG 2 #define SCE_VHDL_NUMBER 3 #define SCE_VHDL_STRING 4 #define SCE_VHDL_OPERATOR 5 #define SCE_VHDL_IDENTIFIER 6 #define SCE_VHDL_STRINGEOL 7 #define SCE_VHDL_KEYWORD 8 #define SCE_VHDL_STDOPERATOR 9 #define SCE_VHDL_ATTRIBUTE 10 #define SCE_VHDL_STDFUNCTION 11 #define SCE_VHDL_STDPACKAGE 12 #define SCE_VHDL_STDTYPE 13 #define SCE_VHDL_USERWORD 14 #define SCE_VHDL_BLOCK_COMMENT 15 #define SCE_CAML_DEFAULT 0 #define SCE_CAML_IDENTIFIER 1 #define SCE_CAML_TAGNAME 2 #define SCE_CAML_KEYWORD 3 #define SCE_CAML_KEYWORD2 4 #define SCE_CAML_KEYWORD3 5 #define SCE_CAML_LINENUM 6 #define SCE_CAML_OPERATOR 7 #define SCE_CAML_NUMBER 8 #define SCE_CAML_CHAR 9 #define SCE_CAML_WHITE 10 #define SCE_CAML_STRING 11 #define SCE_CAML_COMMENT 12 #define SCE_CAML_COMMENT1 13 #define SCE_CAML_COMMENT2 14 #define SCE_CAML_COMMENT3 15 #define SCE_HA_DEFAULT 0 #define SCE_HA_IDENTIFIER 1 #define SCE_HA_KEYWORD 2 #define SCE_HA_NUMBER 3 #define SCE_HA_STRING 4 #define SCE_HA_CHARACTER 5 #define SCE_HA_CLASS 6 #define SCE_HA_MODULE 7 #define SCE_HA_CAPITAL 8 #define SCE_HA_DATA 9 #define SCE_HA_IMPORT 10 #define SCE_HA_OPERATOR 11 #define SCE_HA_INSTANCE 12 #define SCE_HA_COMMENTLINE 13 #define SCE_HA_COMMENTBLOCK 14 #define SCE_HA_COMMENTBLOCK2 15 #define SCE_HA_COMMENTBLOCK3 16 #define SCE_HA_PRAGMA 17 #define SCE_HA_PREPROCESSOR 18 #define SCE_HA_STRINGEOL 19 #define SCE_HA_RESERVED_OPERATOR 20 #define SCE_HA_LITERATE_COMMENT 21 #define SCE_HA_LITERATE_CODEDELIM 22 #define SCE_T3_DEFAULT 0 #define SCE_T3_X_DEFAULT 1 #define SCE_T3_PREPROCESSOR 2 #define SCE_T3_BLOCK_COMMENT 3 #define SCE_T3_LINE_COMMENT 4 #define SCE_T3_OPERATOR 5 #define SCE_T3_KEYWORD 6 #define SCE_T3_NUMBER 7 #define SCE_T3_IDENTIFIER 8 #define SCE_T3_S_STRING 9 #define SCE_T3_D_STRING 10 #define SCE_T3_X_STRING 11 #define SCE_T3_LIB_DIRECTIVE 12 #define SCE_T3_MSG_PARAM 13 #define SCE_T3_HTML_TAG 14 #define SCE_T3_HTML_DEFAULT 15 #define SCE_T3_HTML_STRING 16 #define SCE_T3_USER1 17 #define SCE_T3_USER2 18 #define SCE_T3_USER3 19 #define SCE_T3_BRACE 20 #define SCE_REBOL_DEFAULT 0 #define SCE_REBOL_COMMENTLINE 1 #define SCE_REBOL_COMMENTBLOCK 2 #define SCE_REBOL_PREFACE 3 #define SCE_REBOL_OPERATOR 4 #define SCE_REBOL_CHARACTER 5 #define SCE_REBOL_QUOTEDSTRING 6 #define SCE_REBOL_BRACEDSTRING 7 #define SCE_REBOL_NUMBER 8 #define SCE_REBOL_PAIR 9 #define SCE_REBOL_TUPLE 10 #define SCE_REBOL_BINARY 11 #define SCE_REBOL_MONEY 12 #define SCE_REBOL_ISSUE 13 #define SCE_REBOL_TAG 14 #define SCE_REBOL_FILE 15 #define SCE_REBOL_EMAIL 16 #define SCE_REBOL_URL 17 #define SCE_REBOL_DATE 18 #define SCE_REBOL_TIME 19 #define SCE_REBOL_IDENTIFIER 20 #define SCE_REBOL_WORD 21 #define SCE_REBOL_WORD2 22 #define SCE_REBOL_WORD3 23 #define SCE_REBOL_WORD4 24 #define SCE_REBOL_WORD5 25 #define SCE_REBOL_WORD6 26 #define SCE_REBOL_WORD7 27 #define SCE_REBOL_WORD8 28 #define SCE_SQL_DEFAULT 0 #define SCE_SQL_COMMENT 1 #define SCE_SQL_COMMENTLINE 2 #define SCE_SQL_COMMENTDOC 3 #define SCE_SQL_NUMBER 4 #define SCE_SQL_WORD 5 #define SCE_SQL_STRING 6 #define SCE_SQL_CHARACTER 7 #define SCE_SQL_SQLPLUS 8 #define SCE_SQL_SQLPLUS_PROMPT 9 #define SCE_SQL_OPERATOR 10 #define SCE_SQL_IDENTIFIER 11 #define SCE_SQL_SQLPLUS_COMMENT 13 #define SCE_SQL_COMMENTLINEDOC 15 #define SCE_SQL_WORD2 16 #define SCE_SQL_COMMENTDOCKEYWORD 17 #define SCE_SQL_COMMENTDOCKEYWORDERROR 18 #define SCE_SQL_USER1 19 #define SCE_SQL_USER2 20 #define SCE_SQL_USER3 21 #define SCE_SQL_USER4 22 #define SCE_SQL_QUOTEDIDENTIFIER 23 #define SCE_SQL_QOPERATOR 24 #define SCE_ST_DEFAULT 0 #define SCE_ST_STRING 1 #define SCE_ST_NUMBER 2 #define SCE_ST_COMMENT 3 #define SCE_ST_SYMBOL 4 #define SCE_ST_BINARY 5 #define SCE_ST_BOOL 6 #define SCE_ST_SELF 7 #define SCE_ST_SUPER 8 #define SCE_ST_NIL 9 #define SCE_ST_GLOBAL 10 #define SCE_ST_RETURN 11 #define SCE_ST_SPECIAL 12 #define SCE_ST_KWSEND 13 #define SCE_ST_ASSIGN 14 #define SCE_ST_CHARACTER 15 #define SCE_ST_SPEC_SEL 16 #define SCE_FS_DEFAULT 0 #define SCE_FS_COMMENT 1 #define SCE_FS_COMMENTLINE 2 #define SCE_FS_COMMENTDOC 3 #define SCE_FS_COMMENTLINEDOC 4 #define SCE_FS_COMMENTDOCKEYWORD 5 #define SCE_FS_COMMENTDOCKEYWORDERROR 6 #define SCE_FS_KEYWORD 7 #define SCE_FS_KEYWORD2 8 #define SCE_FS_KEYWORD3 9 #define SCE_FS_KEYWORD4 10 #define SCE_FS_NUMBER 11 #define SCE_FS_STRING 12 #define SCE_FS_PREPROCESSOR 13 #define SCE_FS_OPERATOR 14 #define SCE_FS_IDENTIFIER 15 #define SCE_FS_DATE 16 #define SCE_FS_STRINGEOL 17 #define SCE_FS_CONSTANT 18 #define SCE_FS_WORDOPERATOR 19 #define SCE_FS_DISABLEDCODE 20 #define SCE_FS_DEFAULT_C 21 #define SCE_FS_COMMENTDOC_C 22 #define SCE_FS_COMMENTLINEDOC_C 23 #define SCE_FS_KEYWORD_C 24 #define SCE_FS_KEYWORD2_C 25 #define SCE_FS_NUMBER_C 26 #define SCE_FS_STRING_C 27 #define SCE_FS_PREPROCESSOR_C 28 #define SCE_FS_OPERATOR_C 29 #define SCE_FS_IDENTIFIER_C 30 #define SCE_FS_STRINGEOL_C 31 #define SCE_CSOUND_DEFAULT 0 #define SCE_CSOUND_COMMENT 1 #define SCE_CSOUND_NUMBER 2 #define SCE_CSOUND_OPERATOR 3 #define SCE_CSOUND_INSTR 4 #define SCE_CSOUND_IDENTIFIER 5 #define SCE_CSOUND_OPCODE 6 #define SCE_CSOUND_HEADERSTMT 7 #define SCE_CSOUND_USERKEYWORD 8 #define SCE_CSOUND_COMMENTBLOCK 9 #define SCE_CSOUND_PARAM 10 #define SCE_CSOUND_ARATE_VAR 11 #define SCE_CSOUND_KRATE_VAR 12 #define SCE_CSOUND_IRATE_VAR 13 #define SCE_CSOUND_GLOBAL_VAR 14 #define SCE_CSOUND_STRINGEOL 15 #define SCE_INNO_DEFAULT 0 #define SCE_INNO_COMMENT 1 #define SCE_INNO_KEYWORD 2 #define SCE_INNO_PARAMETER 3 #define SCE_INNO_SECTION 4 #define SCE_INNO_PREPROC 5 #define SCE_INNO_INLINE_EXPANSION 6 #define SCE_INNO_COMMENT_PASCAL 7 #define SCE_INNO_KEYWORD_PASCAL 8 #define SCE_INNO_KEYWORD_USER 9 #define SCE_INNO_STRING_DOUBLE 10 #define SCE_INNO_STRING_SINGLE 11 #define SCE_INNO_IDENTIFIER 12 #define SCE_OPAL_SPACE 0 #define SCE_OPAL_COMMENT_BLOCK 1 #define SCE_OPAL_COMMENT_LINE 2 #define SCE_OPAL_INTEGER 3 #define SCE_OPAL_KEYWORD 4 #define SCE_OPAL_SORT 5 #define SCE_OPAL_STRING 6 #define SCE_OPAL_PAR 7 #define SCE_OPAL_BOOL_CONST 8 #define SCE_OPAL_DEFAULT 32 #define SCE_SPICE_DEFAULT 0 #define SCE_SPICE_IDENTIFIER 1 #define SCE_SPICE_KEYWORD 2 #define SCE_SPICE_KEYWORD2 3 #define SCE_SPICE_KEYWORD3 4 #define SCE_SPICE_NUMBER 5 #define SCE_SPICE_DELIMITER 6 #define SCE_SPICE_VALUE 7 #define SCE_SPICE_COMMENTLINE 8 #define SCE_CMAKE_DEFAULT 0 #define SCE_CMAKE_COMMENT 1 #define SCE_CMAKE_STRINGDQ 2 #define SCE_CMAKE_STRINGLQ 3 #define SCE_CMAKE_STRINGRQ 4 #define SCE_CMAKE_COMMANDS 5 #define SCE_CMAKE_PARAMETERS 6 #define SCE_CMAKE_VARIABLE 7 #define SCE_CMAKE_USERDEFINED 8 #define SCE_CMAKE_WHILEDEF 9 #define SCE_CMAKE_FOREACHDEF 10 #define SCE_CMAKE_IFDEFINEDEF 11 #define SCE_CMAKE_MACRODEF 12 #define SCE_CMAKE_STRINGVAR 13 #define SCE_CMAKE_NUMBER 14 #define SCE_GAP_DEFAULT 0 #define SCE_GAP_IDENTIFIER 1 #define SCE_GAP_KEYWORD 2 #define SCE_GAP_KEYWORD2 3 #define SCE_GAP_KEYWORD3 4 #define SCE_GAP_KEYWORD4 5 #define SCE_GAP_STRING 6 #define SCE_GAP_CHAR 7 #define SCE_GAP_OPERATOR 8 #define SCE_GAP_COMMENT 9 #define SCE_GAP_NUMBER 10 #define SCE_GAP_STRINGEOL 11 #define SCE_PLM_DEFAULT 0 #define SCE_PLM_COMMENT 1 #define SCE_PLM_STRING 2 #define SCE_PLM_NUMBER 3 #define SCE_PLM_IDENTIFIER 4 #define SCE_PLM_OPERATOR 5 #define SCE_PLM_CONTROL 6 #define SCE_PLM_KEYWORD 7 #define SCE_ABL_DEFAULT 0 #define SCE_ABL_NUMBER 1 #define SCE_ABL_WORD 2 #define SCE_ABL_STRING 3 #define SCE_ABL_CHARACTER 4 #define SCE_ABL_PREPROCESSOR 5 #define SCE_ABL_OPERATOR 6 #define SCE_ABL_IDENTIFIER 7 #define SCE_ABL_BLOCK 8 #define SCE_ABL_END 9 #define SCE_ABL_COMMENT 10 #define SCE_ABL_TASKMARKER 11 #define SCE_ABL_LINECOMMENT 12 #define SCE_ABAQUS_DEFAULT 0 #define SCE_ABAQUS_COMMENT 1 #define SCE_ABAQUS_COMMENTBLOCK 2 #define SCE_ABAQUS_NUMBER 3 #define SCE_ABAQUS_STRING 4 #define SCE_ABAQUS_OPERATOR 5 #define SCE_ABAQUS_WORD 6 #define SCE_ABAQUS_PROCESSOR 7 #define SCE_ABAQUS_COMMAND 8 #define SCE_ABAQUS_SLASHCOMMAND 9 #define SCE_ABAQUS_STARCOMMAND 10 #define SCE_ABAQUS_ARGUMENT 11 #define SCE_ABAQUS_FUNCTION 12 #define SCE_ASY_DEFAULT 0 #define SCE_ASY_COMMENT 1 #define SCE_ASY_COMMENTLINE 2 #define SCE_ASY_NUMBER 3 #define SCE_ASY_WORD 4 #define SCE_ASY_STRING 5 #define SCE_ASY_CHARACTER 6 #define SCE_ASY_OPERATOR 7 #define SCE_ASY_IDENTIFIER 8 #define SCE_ASY_STRINGEOL 9 #define SCE_ASY_COMMENTLINEDOC 10 #define SCE_ASY_WORD2 11 #define SCE_R_DEFAULT 0 #define SCE_R_COMMENT 1 #define SCE_R_KWORD 2 #define SCE_R_BASEKWORD 3 #define SCE_R_OTHERKWORD 4 #define SCE_R_NUMBER 5 #define SCE_R_STRING 6 #define SCE_R_STRING2 7 #define SCE_R_OPERATOR 8 #define SCE_R_IDENTIFIER 9 #define SCE_R_INFIX 10 #define SCE_R_INFIXEOL 11 #define SCE_MAGIK_DEFAULT 0 #define SCE_MAGIK_COMMENT 1 #define SCE_MAGIK_HYPER_COMMENT 16 #define SCE_MAGIK_STRING 2 #define SCE_MAGIK_CHARACTER 3 #define SCE_MAGIK_NUMBER 4 #define SCE_MAGIK_IDENTIFIER 5 #define SCE_MAGIK_OPERATOR 6 #define SCE_MAGIK_FLOW 7 #define SCE_MAGIK_CONTAINER 8 #define SCE_MAGIK_BRACKET_BLOCK 9 #define SCE_MAGIK_BRACE_BLOCK 10 #define SCE_MAGIK_SQBRACKET_BLOCK 11 #define SCE_MAGIK_UNKNOWN_KEYWORD 12 #define SCE_MAGIK_KEYWORD 13 #define SCE_MAGIK_PRAGMA 14 #define SCE_MAGIK_SYMBOL 15 #define SCE_POWERSHELL_DEFAULT 0 #define SCE_POWERSHELL_COMMENT 1 #define SCE_POWERSHELL_STRING 2 #define SCE_POWERSHELL_CHARACTER 3 #define SCE_POWERSHELL_NUMBER 4 #define SCE_POWERSHELL_VARIABLE 5 #define SCE_POWERSHELL_OPERATOR 6 #define SCE_POWERSHELL_IDENTIFIER 7 #define SCE_POWERSHELL_KEYWORD 8 #define SCE_POWERSHELL_CMDLET 9 #define SCE_POWERSHELL_ALIAS 10 #define SCE_POWERSHELL_FUNCTION 11 #define SCE_POWERSHELL_USER1 12 #define SCE_POWERSHELL_COMMENTSTREAM 13 #define SCE_POWERSHELL_HERE_STRING 14 #define SCE_POWERSHELL_HERE_CHARACTER 15 #define SCE_POWERSHELL_COMMENTDOCKEYWORD 16 #define SCE_MYSQL_DEFAULT 0 #define SCE_MYSQL_COMMENT 1 #define SCE_MYSQL_COMMENTLINE 2 #define SCE_MYSQL_VARIABLE 3 #define SCE_MYSQL_SYSTEMVARIABLE 4 #define SCE_MYSQL_KNOWNSYSTEMVARIABLE 5 #define SCE_MYSQL_NUMBER 6 #define SCE_MYSQL_MAJORKEYWORD 7 #define SCE_MYSQL_KEYWORD 8 #define SCE_MYSQL_DATABASEOBJECT 9 #define SCE_MYSQL_PROCEDUREKEYWORD 10 #define SCE_MYSQL_STRING 11 #define SCE_MYSQL_SQSTRING 12 #define SCE_MYSQL_DQSTRING 13 #define SCE_MYSQL_OPERATOR 14 #define SCE_MYSQL_FUNCTION 15 #define SCE_MYSQL_IDENTIFIER 16 #define SCE_MYSQL_QUOTEDIDENTIFIER 17 #define SCE_MYSQL_USER1 18 #define SCE_MYSQL_USER2 19 #define SCE_MYSQL_USER3 20 #define SCE_MYSQL_HIDDENCOMMAND 21 #define SCE_MYSQL_PLACEHOLDER 22 #define SCE_PO_DEFAULT 0 #define SCE_PO_COMMENT 1 #define SCE_PO_MSGID 2 #define SCE_PO_MSGID_TEXT 3 #define SCE_PO_MSGSTR 4 #define SCE_PO_MSGSTR_TEXT 5 #define SCE_PO_MSGCTXT 6 #define SCE_PO_MSGCTXT_TEXT 7 #define SCE_PO_FUZZY 8 #define SCE_PO_PROGRAMMER_COMMENT 9 #define SCE_PO_REFERENCE 10 #define SCE_PO_FLAGS 11 #define SCE_PO_MSGID_TEXT_EOL 12 #define SCE_PO_MSGSTR_TEXT_EOL 13 #define SCE_PO_MSGCTXT_TEXT_EOL 14 #define SCE_PO_ERROR 15 #define SCE_PAS_DEFAULT 0 #define SCE_PAS_IDENTIFIER 1 #define SCE_PAS_COMMENT 2 #define SCE_PAS_COMMENT2 3 #define SCE_PAS_COMMENTLINE 4 #define SCE_PAS_PREPROCESSOR 5 #define SCE_PAS_PREPROCESSOR2 6 #define SCE_PAS_NUMBER 7 #define SCE_PAS_HEXNUMBER 8 #define SCE_PAS_WORD 9 #define SCE_PAS_STRING 10 #define SCE_PAS_STRINGEOL 11 #define SCE_PAS_CHARACTER 12 #define SCE_PAS_OPERATOR 13 #define SCE_PAS_ASM 14 #define SCE_SORCUS_DEFAULT 0 #define SCE_SORCUS_COMMAND 1 #define SCE_SORCUS_PARAMETER 2 #define SCE_SORCUS_COMMENTLINE 3 #define SCE_SORCUS_STRING 4 #define SCE_SORCUS_STRINGEOL 5 #define SCE_SORCUS_IDENTIFIER 6 #define SCE_SORCUS_OPERATOR 7 #define SCE_SORCUS_NUMBER 8 #define SCE_SORCUS_CONSTANT 9 #define SCE_POWERPRO_DEFAULT 0 #define SCE_POWERPRO_COMMENTBLOCK 1 #define SCE_POWERPRO_COMMENTLINE 2 #define SCE_POWERPRO_NUMBER 3 #define SCE_POWERPRO_WORD 4 #define SCE_POWERPRO_WORD2 5 #define SCE_POWERPRO_WORD3 6 #define SCE_POWERPRO_WORD4 7 #define SCE_POWERPRO_DOUBLEQUOTEDSTRING 8 #define SCE_POWERPRO_SINGLEQUOTEDSTRING 9 #define SCE_POWERPRO_LINECONTINUE 10 #define SCE_POWERPRO_OPERATOR 11 #define SCE_POWERPRO_IDENTIFIER 12 #define SCE_POWERPRO_STRINGEOL 13 #define SCE_POWERPRO_VERBATIM 14 #define SCE_POWERPRO_ALTQUOTE 15 #define SCE_POWERPRO_FUNCTION 16 #define SCE_SML_DEFAULT 0 #define SCE_SML_IDENTIFIER 1 #define SCE_SML_TAGNAME 2 #define SCE_SML_KEYWORD 3 #define SCE_SML_KEYWORD2 4 #define SCE_SML_KEYWORD3 5 #define SCE_SML_LINENUM 6 #define SCE_SML_OPERATOR 7 #define SCE_SML_NUMBER 8 #define SCE_SML_CHAR 9 #define SCE_SML_STRING 11 #define SCE_SML_COMMENT 12 #define SCE_SML_COMMENT1 13 #define SCE_SML_COMMENT2 14 #define SCE_SML_COMMENT3 15 #define SCE_MARKDOWN_DEFAULT 0 #define SCE_MARKDOWN_LINE_BEGIN 1 #define SCE_MARKDOWN_STRONG1 2 #define SCE_MARKDOWN_STRONG2 3 #define SCE_MARKDOWN_EM1 4 #define SCE_MARKDOWN_EM2 5 #define SCE_MARKDOWN_HEADER1 6 #define SCE_MARKDOWN_HEADER2 7 #define SCE_MARKDOWN_HEADER3 8 #define SCE_MARKDOWN_HEADER4 9 #define SCE_MARKDOWN_HEADER5 10 #define SCE_MARKDOWN_HEADER6 11 #define SCE_MARKDOWN_PRECHAR 12 #define SCE_MARKDOWN_ULIST_ITEM 13 #define SCE_MARKDOWN_OLIST_ITEM 14 #define SCE_MARKDOWN_BLOCKQUOTE 15 #define SCE_MARKDOWN_STRIKEOUT 16 #define SCE_MARKDOWN_HRULE 17 #define SCE_MARKDOWN_LINK 18 #define SCE_MARKDOWN_CODE 19 #define SCE_MARKDOWN_CODE2 20 #define SCE_MARKDOWN_CODEBK 21 #define SCE_TXT2TAGS_DEFAULT 0 #define SCE_TXT2TAGS_LINE_BEGIN 1 #define SCE_TXT2TAGS_STRONG1 2 #define SCE_TXT2TAGS_STRONG2 3 #define SCE_TXT2TAGS_EM1 4 #define SCE_TXT2TAGS_EM2 5 #define SCE_TXT2TAGS_HEADER1 6 #define SCE_TXT2TAGS_HEADER2 7 #define SCE_TXT2TAGS_HEADER3 8 #define SCE_TXT2TAGS_HEADER4 9 #define SCE_TXT2TAGS_HEADER5 10 #define SCE_TXT2TAGS_HEADER6 11 #define SCE_TXT2TAGS_PRECHAR 12 #define SCE_TXT2TAGS_ULIST_ITEM 13 #define SCE_TXT2TAGS_OLIST_ITEM 14 #define SCE_TXT2TAGS_BLOCKQUOTE 15 #define SCE_TXT2TAGS_STRIKEOUT 16 #define SCE_TXT2TAGS_HRULE 17 #define SCE_TXT2TAGS_LINK 18 #define SCE_TXT2TAGS_CODE 19 #define SCE_TXT2TAGS_CODE2 20 #define SCE_TXT2TAGS_CODEBK 21 #define SCE_TXT2TAGS_COMMENT 22 #define SCE_TXT2TAGS_OPTION 23 #define SCE_TXT2TAGS_PREPROC 24 #define SCE_TXT2TAGS_POSTPROC 25 #define SCE_A68K_DEFAULT 0 #define SCE_A68K_COMMENT 1 #define SCE_A68K_NUMBER_DEC 2 #define SCE_A68K_NUMBER_BIN 3 #define SCE_A68K_NUMBER_HEX 4 #define SCE_A68K_STRING1 5 #define SCE_A68K_OPERATOR 6 #define SCE_A68K_CPUINSTRUCTION 7 #define SCE_A68K_EXTINSTRUCTION 8 #define SCE_A68K_REGISTER 9 #define SCE_A68K_DIRECTIVE 10 #define SCE_A68K_MACRO_ARG 11 #define SCE_A68K_LABEL 12 #define SCE_A68K_STRING2 13 #define SCE_A68K_IDENTIFIER 14 #define SCE_A68K_MACRO_DECLARATION 15 #define SCE_A68K_COMMENT_WORD 16 #define SCE_A68K_COMMENT_SPECIAL 17 #define SCE_A68K_COMMENT_DOXYGEN 18 #define SCE_MODULA_DEFAULT 0 #define SCE_MODULA_COMMENT 1 #define SCE_MODULA_DOXYCOMM 2 #define SCE_MODULA_DOXYKEY 3 #define SCE_MODULA_KEYWORD 4 #define SCE_MODULA_RESERVED 5 #define SCE_MODULA_NUMBER 6 #define SCE_MODULA_BASENUM 7 #define SCE_MODULA_FLOAT 8 #define SCE_MODULA_STRING 9 #define SCE_MODULA_STRSPEC 10 #define SCE_MODULA_CHAR 11 #define SCE_MODULA_CHARSPEC 12 #define SCE_MODULA_PROC 13 #define SCE_MODULA_PRAGMA 14 #define SCE_MODULA_PRGKEY 15 #define SCE_MODULA_OPERATOR 16 #define SCE_MODULA_BADSTR 17 #define SCE_COFFEESCRIPT_DEFAULT 0 #define SCE_COFFEESCRIPT_COMMENT 1 #define SCE_COFFEESCRIPT_COMMENTLINE 2 #define SCE_COFFEESCRIPT_COMMENTDOC 3 #define SCE_COFFEESCRIPT_NUMBER 4 #define SCE_COFFEESCRIPT_WORD 5 #define SCE_COFFEESCRIPT_STRING 6 #define SCE_COFFEESCRIPT_CHARACTER 7 #define SCE_COFFEESCRIPT_UUID 8 #define SCE_COFFEESCRIPT_PREPROCESSOR 9 #define SCE_COFFEESCRIPT_OPERATOR 10 #define SCE_COFFEESCRIPT_IDENTIFIER 11 #define SCE_COFFEESCRIPT_STRINGEOL 12 #define SCE_COFFEESCRIPT_VERBATIM 13 #define SCE_COFFEESCRIPT_REGEX 14 #define SCE_COFFEESCRIPT_COMMENTLINEDOC 15 #define SCE_COFFEESCRIPT_WORD2 16 #define SCE_COFFEESCRIPT_COMMENTDOCKEYWORD 17 #define SCE_COFFEESCRIPT_COMMENTDOCKEYWORDERROR 18 #define SCE_COFFEESCRIPT_GLOBALCLASS 19 #define SCE_COFFEESCRIPT_STRINGRAW 20 #define SCE_COFFEESCRIPT_TRIPLEVERBATIM 21 #define SCE_COFFEESCRIPT_COMMENTBLOCK 22 #define SCE_COFFEESCRIPT_VERBOSE_REGEX 23 #define SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT 24 #define SCE_COFFEESCRIPT_INSTANCEPROPERTY 25 #define SCE_AVS_DEFAULT 0 #define SCE_AVS_COMMENTBLOCK 1 #define SCE_AVS_COMMENTBLOCKN 2 #define SCE_AVS_COMMENTLINE 3 #define SCE_AVS_NUMBER 4 #define SCE_AVS_OPERATOR 5 #define SCE_AVS_IDENTIFIER 6 #define SCE_AVS_STRING 7 #define SCE_AVS_TRIPLESTRING 8 #define SCE_AVS_KEYWORD 9 #define SCE_AVS_FILTER 10 #define SCE_AVS_PLUGIN 11 #define SCE_AVS_FUNCTION 12 #define SCE_AVS_CLIPPROP 13 #define SCE_AVS_USERDFN 14 #define SCE_ECL_DEFAULT 0 #define SCE_ECL_COMMENT 1 #define SCE_ECL_COMMENTLINE 2 #define SCE_ECL_NUMBER 3 #define SCE_ECL_STRING 4 #define SCE_ECL_WORD0 5 #define SCE_ECL_OPERATOR 6 #define SCE_ECL_CHARACTER 7 #define SCE_ECL_UUID 8 #define SCE_ECL_PREPROCESSOR 9 #define SCE_ECL_UNKNOWN 10 #define SCE_ECL_IDENTIFIER 11 #define SCE_ECL_STRINGEOL 12 #define SCE_ECL_VERBATIM 13 #define SCE_ECL_REGEX 14 #define SCE_ECL_COMMENTLINEDOC 15 #define SCE_ECL_WORD1 16 #define SCE_ECL_COMMENTDOCKEYWORD 17 #define SCE_ECL_COMMENTDOCKEYWORDERROR 18 #define SCE_ECL_WORD2 19 #define SCE_ECL_WORD3 20 #define SCE_ECL_WORD4 21 #define SCE_ECL_WORD5 22 #define SCE_ECL_COMMENTDOC 23 #define SCE_ECL_ADDED 24 #define SCE_ECL_DELETED 25 #define SCE_ECL_CHANGED 26 #define SCE_ECL_MOVED 27 #define SCE_OSCRIPT_DEFAULT 0 #define SCE_OSCRIPT_LINE_COMMENT 1 #define SCE_OSCRIPT_BLOCK_COMMENT 2 #define SCE_OSCRIPT_DOC_COMMENT 3 #define SCE_OSCRIPT_PREPROCESSOR 4 #define SCE_OSCRIPT_NUMBER 5 #define SCE_OSCRIPT_SINGLEQUOTE_STRING 6 #define SCE_OSCRIPT_DOUBLEQUOTE_STRING 7 #define SCE_OSCRIPT_CONSTANT 8 #define SCE_OSCRIPT_IDENTIFIER 9 #define SCE_OSCRIPT_GLOBAL 10 #define SCE_OSCRIPT_KEYWORD 11 #define SCE_OSCRIPT_OPERATOR 12 #define SCE_OSCRIPT_LABEL 13 #define SCE_OSCRIPT_TYPE 14 #define SCE_OSCRIPT_FUNCTION 15 #define SCE_OSCRIPT_OBJECT 16 #define SCE_OSCRIPT_PROPERTY 17 #define SCE_OSCRIPT_METHOD 18 #define SCE_VISUALPROLOG_DEFAULT 0 #define SCE_VISUALPROLOG_KEY_MAJOR 1 #define SCE_VISUALPROLOG_KEY_MINOR 2 #define SCE_VISUALPROLOG_KEY_DIRECTIVE 3 #define SCE_VISUALPROLOG_COMMENT_BLOCK 4 #define SCE_VISUALPROLOG_COMMENT_LINE 5 #define SCE_VISUALPROLOG_COMMENT_KEY 6 #define SCE_VISUALPROLOG_COMMENT_KEY_ERROR 7 #define SCE_VISUALPROLOG_IDENTIFIER 8 #define SCE_VISUALPROLOG_VARIABLE 9 #define SCE_VISUALPROLOG_ANONYMOUS 10 #define SCE_VISUALPROLOG_NUMBER 11 #define SCE_VISUALPROLOG_OPERATOR 12 #define SCE_VISUALPROLOG_CHARACTER 13 #define SCE_VISUALPROLOG_CHARACTER_TOO_MANY 14 #define SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR 15 #define SCE_VISUALPROLOG_STRING 16 #define SCE_VISUALPROLOG_STRING_ESCAPE 17 #define SCE_VISUALPROLOG_STRING_ESCAPE_ERROR 18 #define SCE_VISUALPROLOG_STRING_EOL_OPEN 19 #define SCE_VISUALPROLOG_STRING_VERBATIM 20 #define SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL 21 #define SCE_VISUALPROLOG_STRING_VERBATIM_EOL 22 #define SCE_STTXT_DEFAULT 0 #define SCE_STTXT_COMMENT 1 #define SCE_STTXT_COMMENTLINE 2 #define SCE_STTXT_KEYWORD 3 #define SCE_STTXT_TYPE 4 #define SCE_STTXT_FUNCTION 5 #define SCE_STTXT_FB 6 #define SCE_STTXT_NUMBER 7 #define SCE_STTXT_HEXNUMBER 8 #define SCE_STTXT_PRAGMA 9 #define SCE_STTXT_OPERATOR 10 #define SCE_STTXT_CHARACTER 11 #define SCE_STTXT_STRING1 12 #define SCE_STTXT_STRING2 13 #define SCE_STTXT_STRINGEOL 14 #define SCE_STTXT_IDENTIFIER 15 #define SCE_STTXT_DATETIME 16 #define SCE_STTXT_VARS 17 #define SCE_STTXT_PRAGMAS 18 #define SCE_KVIRC_DEFAULT 0 #define SCE_KVIRC_COMMENT 1 #define SCE_KVIRC_COMMENTBLOCK 2 #define SCE_KVIRC_STRING 3 #define SCE_KVIRC_WORD 4 #define SCE_KVIRC_KEYWORD 5 #define SCE_KVIRC_FUNCTION_KEYWORD 6 #define SCE_KVIRC_FUNCTION 7 #define SCE_KVIRC_VARIABLE 8 #define SCE_KVIRC_NUMBER 9 #define SCE_KVIRC_OPERATOR 10 #define SCE_KVIRC_STRING_FUNCTION 11 #define SCE_KVIRC_STRING_VARIABLE 12 #define SCE_RUST_DEFAULT 0 #define SCE_RUST_COMMENTBLOCK 1 #define SCE_RUST_COMMENTLINE 2 #define SCE_RUST_COMMENTBLOCKDOC 3 #define SCE_RUST_COMMENTLINEDOC 4 #define SCE_RUST_NUMBER 5 #define SCE_RUST_WORD 6 #define SCE_RUST_WORD2 7 #define SCE_RUST_WORD3 8 #define SCE_RUST_WORD4 9 #define SCE_RUST_WORD5 10 #define SCE_RUST_WORD6 11 #define SCE_RUST_WORD7 12 #define SCE_RUST_STRING 13 #define SCE_RUST_STRINGR 14 #define SCE_RUST_CHARACTER 15 #define SCE_RUST_OPERATOR 16 #define SCE_RUST_IDENTIFIER 17 #define SCE_RUST_LIFETIME 18 #define SCE_RUST_MACRO 19 #define SCE_RUST_LEXERROR 20 #define SCE_RUST_BYTESTRING 21 #define SCE_RUST_BYTESTRINGR 22 #define SCE_RUST_BYTECHARACTER 23 #define SCE_DMAP_DEFAULT 0 #define SCE_DMAP_COMMENT 1 #define SCE_DMAP_NUMBER 2 #define SCE_DMAP_STRING1 3 #define SCE_DMAP_STRING2 4 #define SCE_DMAP_STRINGEOL 5 #define SCE_DMAP_OPERATOR 6 #define SCE_DMAP_IDENTIFIER 7 #define SCE_DMAP_WORD 8 #define SCE_DMAP_WORD2 9 #define SCE_DMAP_WORD3 10 #define SCE_DMIS_DEFAULT 0 #define SCE_DMIS_COMMENT 1 #define SCE_DMIS_STRING 2 #define SCE_DMIS_NUMBER 3 #define SCE_DMIS_KEYWORD 4 #define SCE_DMIS_MAJORWORD 5 #define SCE_DMIS_MINORWORD 6 #define SCE_DMIS_UNSUPPORTED_MAJOR 7 #define SCE_DMIS_UNSUPPORTED_MINOR 8 #define SCE_DMIS_LABEL 9 #define SCE_REG_DEFAULT 0 #define SCE_REG_COMMENT 1 #define SCE_REG_VALUENAME 2 #define SCE_REG_STRING 3 #define SCE_REG_HEXDIGIT 4 #define SCE_REG_VALUETYPE 5 #define SCE_REG_ADDEDKEY 6 #define SCE_REG_DELETEDKEY 7 #define SCE_REG_ESCAPED 8 #define SCE_REG_KEYPATH_GUID 9 #define SCE_REG_STRING_GUID 10 #define SCE_REG_PARAMETER 11 #define SCE_REG_OPERATOR 12 #define SCE_BIBTEX_DEFAULT 0 #define SCE_BIBTEX_ENTRY 1 #define SCE_BIBTEX_UNKNOWN_ENTRY 2 #define SCE_BIBTEX_KEY 3 #define SCE_BIBTEX_PARAMETER 4 #define SCE_BIBTEX_VALUE 5 #define SCE_BIBTEX_COMMENT 6 #define SCE_HEX_DEFAULT 0 #define SCE_HEX_RECSTART 1 #define SCE_HEX_RECTYPE 2 #define SCE_HEX_RECTYPE_UNKNOWN 3 #define SCE_HEX_BYTECOUNT 4 #define SCE_HEX_BYTECOUNT_WRONG 5 #define SCE_HEX_NOADDRESS 6 #define SCE_HEX_DATAADDRESS 7 #define SCE_HEX_RECCOUNT 8 #define SCE_HEX_STARTADDRESS 9 #define SCE_HEX_ADDRESSFIELD_UNKNOWN 10 #define SCE_HEX_EXTENDEDADDRESS 11 #define SCE_HEX_DATA_ODD 12 #define SCE_HEX_DATA_EVEN 13 #define SCE_HEX_DATA_UNKNOWN 14 #define SCE_HEX_DATA_EMPTY 15 #define SCE_HEX_CHECKSUM 16 #define SCE_HEX_CHECKSUM_WRONG 17 #define SCE_HEX_GARBAGE 18 #define SCE_JSON_DEFAULT 0 #define SCE_JSON_NUMBER 1 #define SCE_JSON_STRING 2 #define SCE_JSON_STRINGEOL 3 #define SCE_JSON_PROPERTYNAME 4 #define SCE_JSON_ESCAPESEQUENCE 5 #define SCE_JSON_LINECOMMENT 6 #define SCE_JSON_BLOCKCOMMENT 7 #define SCE_JSON_OPERATOR 8 #define SCE_JSON_URI 9 #define SCE_JSON_COMPACTIRI 10 #define SCE_JSON_KEYWORD 11 #define SCE_JSON_LDKEYWORD 12 #define SCE_JSON_ERROR 13 #define SCE_EDI_DEFAULT 0 #define SCE_EDI_SEGMENTSTART 1 #define SCE_EDI_SEGMENTEND 2 #define SCE_EDI_SEP_ELEMENT 3 #define SCE_EDI_SEP_COMPOSITE 4 #define SCE_EDI_SEP_RELEASE 5 #define SCE_EDI_UNA 6 #define SCE_EDI_UNH 7 #define SCE_EDI_BADSEGMENT 8 #define SCE_STATA_DEFAULT 0 #define SCE_STATA_COMMENT 1 #define SCE_STATA_COMMENTLINE 2 #define SCE_STATA_COMMENTBLOCK 3 #define SCE_STATA_NUMBER 4 #define SCE_STATA_OPERATOR 5 #define SCE_STATA_IDENTIFIER 6 #define SCE_STATA_STRING 7 #define SCE_STATA_TYPE 8 #define SCE_STATA_WORD 9 #define SCE_STATA_GLOBAL_MACRO 10 #define SCE_STATA_MACRO 11 #define SCE_SAS_DEFAULT 0 #define SCE_SAS_COMMENT 1 #define SCE_SAS_COMMENTLINE 2 #define SCE_SAS_COMMENTBLOCK 3 #define SCE_SAS_NUMBER 4 #define SCE_SAS_OPERATOR 5 #define SCE_SAS_IDENTIFIER 6 #define SCE_SAS_STRING 7 #define SCE_SAS_TYPE 8 #define SCE_SAS_WORD 9 #define SCE_SAS_GLOBAL_MACRO 10 #define SCE_SAS_MACRO 11 #define SCE_SAS_MACRO_KEYWORD 12 #define SCE_SAS_BLOCK_KEYWORD 13 #define SCE_SAS_MACRO_FUNCTION 14 #define SCE_SAS_STATEMENT 15 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/Sci_Position.h000066400000000000000000000014661463772530400271750ustar00rootroot00000000000000// Scintilla source code edit control /** @file Sci_Position.h ** Define the Sci_Position type used in Scintilla's external interfaces. ** These need to be available to clients written in C so are not in a C++ namespace. **/ // Copyright 2015 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef SCI_POSITION_H #define SCI_POSITION_H #include // Basic signed type used throughout interface typedef ptrdiff_t Sci_Position; // Unsigned variant used for ILexer::Lex and ILexer::Fold typedef size_t Sci_PositionU; // For Sci_CharacterRange which is defined as long to be compatible with Win32 CHARRANGE typedef long Sci_PositionCR; #ifdef _WIN32 #define SCI_METHOD __stdcall #else #define SCI_METHOD #endif #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/Scintilla.h000066400000000000000000001145241463772530400265150ustar00rootroot00000000000000/* Scintilla source code edit control */ /** @file Scintilla.h ** Interface to the edit control. **/ /* Copyright 1998-2003 by Neil Hodgson * The License.txt file describes the conditions under which this software may be distributed. */ /* Most of this file is automatically generated from the Scintilla.iface interface definition * file which contains any comments about the definitions. HFacer.py does the generation. */ #ifndef SCINTILLA_H #define SCINTILLA_H #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) /* Return false on failure: */ int Scintilla_RegisterClasses(void *hInstance); int Scintilla_ReleaseResources(void); #endif int Scintilla_LinkLexers(void); #ifdef __cplusplus } #endif // Include header that defines basic numeric types. #include // Define uptr_t, an unsigned integer type large enough to hold a pointer. typedef uintptr_t uptr_t; // Define sptr_t, a signed integer large enough to hold a pointer. typedef intptr_t sptr_t; #include "Sci_Position.h" typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam); /* ++Autogenerated -- start of section automatically generated from Scintilla.iface */ #define INVALID_POSITION -1 #define SCI_START 2000 #define SCI_OPTIONAL_START 3000 #define SCI_LEXER_START 4000 #define SCI_ADDTEXT 2001 #define SCI_ADDSTYLEDTEXT 2002 #define SCI_INSERTTEXT 2003 #define SCI_CHANGEINSERTION 2672 #define SCI_CLEARALL 2004 #define SCI_DELETERANGE 2645 #define SCI_CLEARDOCUMENTSTYLE 2005 #define SCI_GETLENGTH 2006 #define SCI_GETCHARAT 2007 #define SCI_GETCURRENTPOS 2008 #define SCI_GETANCHOR 2009 #define SCI_GETSTYLEAT 2010 #define SCI_REDO 2011 #define SCI_SETUNDOCOLLECTION 2012 #define SCI_SELECTALL 2013 #define SCI_SETSAVEPOINT 2014 #define SCI_GETSTYLEDTEXT 2015 #define SCI_CANREDO 2016 #define SCI_MARKERLINEFROMHANDLE 2017 #define SCI_MARKERDELETEHANDLE 2018 #define SCI_GETUNDOCOLLECTION 2019 #define SCWS_INVISIBLE 0 #define SCWS_VISIBLEALWAYS 1 #define SCWS_VISIBLEAFTERINDENT 2 #define SCWS_VISIBLEONLYININDENT 3 #define SCI_GETVIEWWS 2020 #define SCI_SETVIEWWS 2021 #define SCTD_LONGARROW 0 #define SCTD_STRIKEOUT 1 #define SCI_GETTABDRAWMODE 2698 #define SCI_SETTABDRAWMODE 2699 #define SCI_POSITIONFROMPOINT 2022 #define SCI_POSITIONFROMPOINTCLOSE 2023 #define SCI_GOTOLINE 2024 #define SCI_GOTOPOS 2025 #define SCI_SETANCHOR 2026 #define SCI_GETCURLINE 2027 #define SCI_GETENDSTYLED 2028 #define SC_EOL_CRLF 0 #define SC_EOL_CR 1 #define SC_EOL_LF 2 #define SCI_CONVERTEOLS 2029 #define SCI_GETEOLMODE 2030 #define SCI_SETEOLMODE 2031 #define SCI_STARTSTYLING 2032 #define SCI_SETSTYLING 2033 #define SCI_GETBUFFEREDDRAW 2034 #define SCI_SETBUFFEREDDRAW 2035 #define SCI_SETTABWIDTH 2036 #define SCI_GETTABWIDTH 2121 #define SCI_CLEARTABSTOPS 2675 #define SCI_ADDTABSTOP 2676 #define SCI_GETNEXTTABSTOP 2677 #define SC_CP_UTF8 65001 #define SCI_SETCODEPAGE 2037 #define SC_IME_WINDOWED 0 #define SC_IME_INLINE 1 #define SCI_GETIMEINTERACTION 2678 #define SCI_SETIMEINTERACTION 2679 #define MARKER_MAX 31 #define SC_MARK_CIRCLE 0 #define SC_MARK_ROUNDRECT 1 #define SC_MARK_ARROW 2 #define SC_MARK_SMALLRECT 3 #define SC_MARK_SHORTARROW 4 #define SC_MARK_EMPTY 5 #define SC_MARK_ARROWDOWN 6 #define SC_MARK_MINUS 7 #define SC_MARK_PLUS 8 #define SC_MARK_VLINE 9 #define SC_MARK_LCORNER 10 #define SC_MARK_TCORNER 11 #define SC_MARK_BOXPLUS 12 #define SC_MARK_BOXPLUSCONNECTED 13 #define SC_MARK_BOXMINUS 14 #define SC_MARK_BOXMINUSCONNECTED 15 #define SC_MARK_LCORNERCURVE 16 #define SC_MARK_TCORNERCURVE 17 #define SC_MARK_CIRCLEPLUS 18 #define SC_MARK_CIRCLEPLUSCONNECTED 19 #define SC_MARK_CIRCLEMINUS 20 #define SC_MARK_CIRCLEMINUSCONNECTED 21 #define SC_MARK_BACKGROUND 22 #define SC_MARK_DOTDOTDOT 23 #define SC_MARK_ARROWS 24 #define SC_MARK_PIXMAP 25 #define SC_MARK_FULLRECT 26 #define SC_MARK_LEFTRECT 27 #define SC_MARK_AVAILABLE 28 #define SC_MARK_UNDERLINE 29 #define SC_MARK_RGBAIMAGE 30 #define SC_MARK_BOOKMARK 31 #define SC_MARK_CHARACTER 10000 #define SC_MARKNUM_FOLDEREND 25 #define SC_MARKNUM_FOLDEROPENMID 26 #define SC_MARKNUM_FOLDERMIDTAIL 27 #define SC_MARKNUM_FOLDERTAIL 28 #define SC_MARKNUM_FOLDERSUB 29 #define SC_MARKNUM_FOLDER 30 #define SC_MARKNUM_FOLDEROPEN 31 #define SC_MASK_FOLDERS 0xFE000000 #define SCI_MARKERDEFINE 2040 #define SCI_MARKERSETFORE 2041 #define SCI_MARKERSETBACK 2042 #define SCI_MARKERSETBACKSELECTED 2292 #define SCI_MARKERENABLEHIGHLIGHT 2293 #define SCI_MARKERADD 2043 #define SCI_MARKERDELETE 2044 #define SCI_MARKERDELETEALL 2045 #define SCI_MARKERGET 2046 #define SCI_MARKERNEXT 2047 #define SCI_MARKERPREVIOUS 2048 #define SCI_MARKERDEFINEPIXMAP 2049 #define SCI_MARKERADDSET 2466 #define SCI_MARKERSETALPHA 2476 #define SC_MAX_MARGIN 4 #define SC_MARGIN_SYMBOL 0 #define SC_MARGIN_NUMBER 1 #define SC_MARGIN_BACK 2 #define SC_MARGIN_FORE 3 #define SC_MARGIN_TEXT 4 #define SC_MARGIN_RTEXT 5 #define SC_MARGIN_COLOUR 6 #define SCI_SETMARGINTYPEN 2240 #define SCI_GETMARGINTYPEN 2241 #define SCI_SETMARGINWIDTHN 2242 #define SCI_GETMARGINWIDTHN 2243 #define SCI_SETMARGINMASKN 2244 #define SCI_GETMARGINMASKN 2245 #define SCI_SETMARGINSENSITIVEN 2246 #define SCI_GETMARGINSENSITIVEN 2247 #define SCI_SETMARGINCURSORN 2248 #define SCI_GETMARGINCURSORN 2249 #define SCI_SETMARGINBACKN 2250 #define SCI_GETMARGINBACKN 2251 #define SCI_SETMARGINS 2252 #define SCI_GETMARGINS 2253 #define STYLE_DEFAULT 32 #define STYLE_LINENUMBER 33 #define STYLE_BRACELIGHT 34 #define STYLE_BRACEBAD 35 #define STYLE_CONTROLCHAR 36 #define STYLE_INDENTGUIDE 37 #define STYLE_CALLTIP 38 #define STYLE_FOLDDISPLAYTEXT 39 #define STYLE_LASTPREDEFINED 39 #define STYLE_MAX 255 #define SC_CHARSET_ANSI 0 #define SC_CHARSET_DEFAULT 1 #define SC_CHARSET_BALTIC 186 #define SC_CHARSET_CHINESEBIG5 136 #define SC_CHARSET_EASTEUROPE 238 #define SC_CHARSET_GB2312 134 #define SC_CHARSET_GREEK 161 #define SC_CHARSET_HANGUL 129 #define SC_CHARSET_MAC 77 #define SC_CHARSET_OEM 255 #define SC_CHARSET_RUSSIAN 204 #define SC_CHARSET_OEM866 866 #define SC_CHARSET_CYRILLIC 1251 #define SC_CHARSET_SHIFTJIS 128 #define SC_CHARSET_SYMBOL 2 #define SC_CHARSET_TURKISH 162 #define SC_CHARSET_JOHAB 130 #define SC_CHARSET_HEBREW 177 #define SC_CHARSET_ARABIC 178 #define SC_CHARSET_VIETNAMESE 163 #define SC_CHARSET_THAI 222 #define SC_CHARSET_8859_15 1000 #define SCI_STYLECLEARALL 2050 #define SCI_STYLESETFORE 2051 #define SCI_STYLESETBACK 2052 #define SCI_STYLESETBOLD 2053 #define SCI_STYLESETITALIC 2054 #define SCI_STYLESETSIZE 2055 #define SCI_STYLESETFONT 2056 #define SCI_STYLESETEOLFILLED 2057 #define SCI_STYLERESETDEFAULT 2058 #define SCI_STYLESETUNDERLINE 2059 #define SC_CASE_MIXED 0 #define SC_CASE_UPPER 1 #define SC_CASE_LOWER 2 #define SC_CASE_CAMEL 3 #define SCI_STYLEGETFORE 2481 #define SCI_STYLEGETBACK 2482 #define SCI_STYLEGETBOLD 2483 #define SCI_STYLEGETITALIC 2484 #define SCI_STYLEGETSIZE 2485 #define SCI_STYLEGETFONT 2486 #define SCI_STYLEGETEOLFILLED 2487 #define SCI_STYLEGETUNDERLINE 2488 #define SCI_STYLEGETCASE 2489 #define SCI_STYLEGETCHARACTERSET 2490 #define SCI_STYLEGETVISIBLE 2491 #define SCI_STYLEGETCHANGEABLE 2492 #define SCI_STYLEGETHOTSPOT 2493 #define SCI_STYLESETCASE 2060 #define SC_FONT_SIZE_MULTIPLIER 100 #define SCI_STYLESETSIZEFRACTIONAL 2061 #define SCI_STYLEGETSIZEFRACTIONAL 2062 #define SC_WEIGHT_NORMAL 400 #define SC_WEIGHT_SEMIBOLD 600 #define SC_WEIGHT_BOLD 700 #define SCI_STYLESETWEIGHT 2063 #define SCI_STYLEGETWEIGHT 2064 #define SCI_STYLESETCHARACTERSET 2066 #define SCI_STYLESETHOTSPOT 2409 #define SCI_SETSELFORE 2067 #define SCI_SETSELBACK 2068 #define SCI_GETSELALPHA 2477 #define SCI_SETSELALPHA 2478 #define SCI_GETSELEOLFILLED 2479 #define SCI_SETSELEOLFILLED 2480 #define SCI_SETCARETFORE 2069 #define SCI_ASSIGNCMDKEY 2070 #define SCI_CLEARCMDKEY 2071 #define SCI_CLEARALLCMDKEYS 2072 #define SCI_SETSTYLINGEX 2073 #define SCI_STYLESETVISIBLE 2074 #define SCI_GETCARETPERIOD 2075 #define SCI_SETCARETPERIOD 2076 #define SCI_SETWORDCHARS 2077 #define SCI_GETWORDCHARS 2646 #define SCI_BEGINUNDOACTION 2078 #define SCI_ENDUNDOACTION 2079 #define INDIC_PLAIN 0 #define INDIC_SQUIGGLE 1 #define INDIC_TT 2 #define INDIC_DIAGONAL 3 #define INDIC_STRIKE 4 #define INDIC_HIDDEN 5 #define INDIC_BOX 6 #define INDIC_ROUNDBOX 7 #define INDIC_STRAIGHTBOX 8 #define INDIC_DASH 9 #define INDIC_DOTS 10 #define INDIC_SQUIGGLELOW 11 #define INDIC_DOTBOX 12 #define INDIC_SQUIGGLEPIXMAP 13 #define INDIC_COMPOSITIONTHICK 14 #define INDIC_COMPOSITIONTHIN 15 #define INDIC_FULLBOX 16 #define INDIC_TEXTFORE 17 #define INDIC_POINT 18 #define INDIC_POINTCHARACTER 19 #define INDIC_GRADIENT 20 #define INDIC_GRADIENTCENTRE 21 #define INDIC_IME 32 #define INDIC_IME_MAX 35 #define INDIC_MAX 35 #define INDIC_CONTAINER 8 #define INDIC0_MASK 0x20 #define INDIC1_MASK 0x40 #define INDIC2_MASK 0x80 #define INDICS_MASK 0xE0 #define SCI_INDICSETSTYLE 2080 #define SCI_INDICGETSTYLE 2081 #define SCI_INDICSETFORE 2082 #define SCI_INDICGETFORE 2083 #define SCI_INDICSETUNDER 2510 #define SCI_INDICGETUNDER 2511 #define SCI_INDICSETHOVERSTYLE 2680 #define SCI_INDICGETHOVERSTYLE 2681 #define SCI_INDICSETHOVERFORE 2682 #define SCI_INDICGETHOVERFORE 2683 #define SC_INDICVALUEBIT 0x1000000 #define SC_INDICVALUEMASK 0xFFFFFF #define SC_INDICFLAG_VALUEFORE 1 #define SCI_INDICSETFLAGS 2684 #define SCI_INDICGETFLAGS 2685 #define SCI_SETWHITESPACEFORE 2084 #define SCI_SETWHITESPACEBACK 2085 #define SCI_SETWHITESPACESIZE 2086 #define SCI_GETWHITESPACESIZE 2087 #define SCI_SETLINESTATE 2092 #define SCI_GETLINESTATE 2093 #define SCI_GETMAXLINESTATE 2094 #define SCI_GETCARETLINEVISIBLE 2095 #define SCI_SETCARETLINEVISIBLE 2096 #define SCI_GETCARETLINEBACK 2097 #define SCI_SETCARETLINEBACK 2098 #define SCI_GETCARETLINEFRAME 2704 #define SCI_SETCARETLINEFRAME 2705 #define SCI_STYLESETCHANGEABLE 2099 #define SCI_AUTOCSHOW 2100 #define SCI_AUTOCCANCEL 2101 #define SCI_AUTOCACTIVE 2102 #define SCI_AUTOCPOSSTART 2103 #define SCI_AUTOCCOMPLETE 2104 #define SCI_AUTOCSTOPS 2105 #define SCI_AUTOCSETSEPARATOR 2106 #define SCI_AUTOCGETSEPARATOR 2107 #define SCI_AUTOCSELECT 2108 #define SCI_AUTOCSETCANCELATSTART 2110 #define SCI_AUTOCGETCANCELATSTART 2111 #define SCI_AUTOCSETFILLUPS 2112 #define SCI_AUTOCSETCHOOSESINGLE 2113 #define SCI_AUTOCGETCHOOSESINGLE 2114 #define SCI_AUTOCSETIGNORECASE 2115 #define SCI_AUTOCGETIGNORECASE 2116 #define SCI_USERLISTSHOW 2117 #define SCI_AUTOCSETAUTOHIDE 2118 #define SCI_AUTOCGETAUTOHIDE 2119 #define SCI_AUTOCSETDROPRESTOFWORD 2270 #define SCI_AUTOCGETDROPRESTOFWORD 2271 #define SCI_REGISTERIMAGE 2405 #define SCI_CLEARREGISTEREDIMAGES 2408 #define SCI_AUTOCGETTYPESEPARATOR 2285 #define SCI_AUTOCSETTYPESEPARATOR 2286 #define SCI_AUTOCSETMAXWIDTH 2208 #define SCI_AUTOCGETMAXWIDTH 2209 #define SCI_AUTOCSETMAXHEIGHT 2210 #define SCI_AUTOCGETMAXHEIGHT 2211 #define SCI_SETINDENT 2122 #define SCI_GETINDENT 2123 #define SCI_SETUSETABS 2124 #define SCI_GETUSETABS 2125 #define SCI_SETLINEINDENTATION 2126 #define SCI_GETLINEINDENTATION 2127 #define SCI_GETLINEINDENTPOSITION 2128 #define SCI_GETCOLUMN 2129 #define SCI_COUNTCHARACTERS 2633 #define SCI_COUNTCODEUNITS 2715 #define SCI_SETHSCROLLBAR 2130 #define SCI_GETHSCROLLBAR 2131 #define SC_IV_NONE 0 #define SC_IV_REAL 1 #define SC_IV_LOOKFORWARD 2 #define SC_IV_LOOKBOTH 3 #define SCI_SETINDENTATIONGUIDES 2132 #define SCI_GETINDENTATIONGUIDES 2133 #define SCI_SETHIGHLIGHTGUIDE 2134 #define SCI_GETHIGHLIGHTGUIDE 2135 #define SCI_GETLINEENDPOSITION 2136 #define SCI_GETCODEPAGE 2137 #define SCI_GETCARETFORE 2138 #define SCI_GETREADONLY 2140 #define SCI_SETCURRENTPOS 2141 #define SCI_SETSELECTIONSTART 2142 #define SCI_GETSELECTIONSTART 2143 #define SCI_SETSELECTIONEND 2144 #define SCI_GETSELECTIONEND 2145 #define SCI_SETEMPTYSELECTION 2556 #define SCI_SETPRINTMAGNIFICATION 2146 #define SCI_GETPRINTMAGNIFICATION 2147 #define SC_PRINT_NORMAL 0 #define SC_PRINT_INVERTLIGHT 1 #define SC_PRINT_BLACKONWHITE 2 #define SC_PRINT_COLOURONWHITE 3 #define SC_PRINT_COLOURONWHITEDEFAULTBG 4 #define SC_PRINT_SCREENCOLOURS 5 #define SCI_SETPRINTCOLOURMODE 2148 #define SCI_GETPRINTCOLOURMODE 2149 #define SCFIND_WHOLEWORD 0x2 #define SCFIND_MATCHCASE 0x4 #define SCFIND_WORDSTART 0x00100000 #define SCFIND_REGEXP 0x00200000 #define SCFIND_POSIX 0x00400000 #define SCFIND_CXX11REGEX 0x00800000 #define SCI_FINDTEXT 2150 #define SCI_FORMATRANGE 2151 #define SCI_GETFIRSTVISIBLELINE 2152 #define SCI_GETLINE 2153 #define SCI_GETLINECOUNT 2154 #define SCI_SETMARGINLEFT 2155 #define SCI_GETMARGINLEFT 2156 #define SCI_SETMARGINRIGHT 2157 #define SCI_GETMARGINRIGHT 2158 #define SCI_GETMODIFY 2159 #define SCI_SETSEL 2160 #define SCI_GETSELTEXT 2161 #define SCI_GETTEXTRANGE 2162 #define SCI_HIDESELECTION 2163 #define SCI_POINTXFROMPOSITION 2164 #define SCI_POINTYFROMPOSITION 2165 #define SCI_LINEFROMPOSITION 2166 #define SCI_POSITIONFROMLINE 2167 #define SCI_LINESCROLL 2168 #define SCI_SCROLLCARET 2169 #define SCI_SCROLLRANGE 2569 #define SCI_REPLACESEL 2170 #define SCI_SETREADONLY 2171 #define SCI_NULL 2172 #define SCI_CANPASTE 2173 #define SCI_CANUNDO 2174 #define SCI_EMPTYUNDOBUFFER 2175 #define SCI_UNDO 2176 #define SCI_CUT 2177 #define SCI_COPY 2178 #define SCI_PASTE 2179 #define SCI_CLEAR 2180 #define SCI_SETTEXT 2181 #define SCI_GETTEXT 2182 #define SCI_GETTEXTLENGTH 2183 #define SCI_GETDIRECTFUNCTION 2184 #define SCI_GETDIRECTPOINTER 2185 #define SCI_SETOVERTYPE 2186 #define SCI_GETOVERTYPE 2187 #define SCI_SETCARETWIDTH 2188 #define SCI_GETCARETWIDTH 2189 #define SCI_SETTARGETSTART 2190 #define SCI_GETTARGETSTART 2191 #define SCI_SETTARGETEND 2192 #define SCI_GETTARGETEND 2193 #define SCI_SETTARGETRANGE 2686 #define SCI_GETTARGETTEXT 2687 #define SCI_TARGETFROMSELECTION 2287 #define SCI_TARGETWHOLEDOCUMENT 2690 #define SCI_REPLACETARGET 2194 #define SCI_REPLACETARGETRE 2195 #define SCI_SEARCHINTARGET 2197 #define SCI_SETSEARCHFLAGS 2198 #define SCI_GETSEARCHFLAGS 2199 #define SCI_CALLTIPSHOW 2200 #define SCI_CALLTIPCANCEL 2201 #define SCI_CALLTIPACTIVE 2202 #define SCI_CALLTIPPOSSTART 2203 #define SCI_CALLTIPSETPOSSTART 2214 #define SCI_CALLTIPSETHLT 2204 #define SCI_CALLTIPSETBACK 2205 #define SCI_CALLTIPSETFORE 2206 #define SCI_CALLTIPSETFOREHLT 2207 #define SCI_CALLTIPUSESTYLE 2212 #define SCI_CALLTIPSETPOSITION 2213 #define SCI_VISIBLEFROMDOCLINE 2220 #define SCI_DOCLINEFROMVISIBLE 2221 #define SCI_WRAPCOUNT 2235 #define SC_FOLDLEVELBASE 0x400 #define SC_FOLDLEVELWHITEFLAG 0x1000 #define SC_FOLDLEVELHEADERFLAG 0x2000 #define SC_FOLDLEVELNUMBERMASK 0x0FFF #define SCI_SETFOLDLEVEL 2222 #define SCI_GETFOLDLEVEL 2223 #define SCI_GETLASTCHILD 2224 #define SCI_GETFOLDPARENT 2225 #define SCI_SHOWLINES 2226 #define SCI_HIDELINES 2227 #define SCI_GETLINEVISIBLE 2228 #define SCI_GETALLLINESVISIBLE 2236 #define SCI_SETFOLDEXPANDED 2229 #define SCI_GETFOLDEXPANDED 2230 #define SCI_TOGGLEFOLD 2231 #define SCI_TOGGLEFOLDSHOWTEXT 2700 #define SC_FOLDDISPLAYTEXT_HIDDEN 0 #define SC_FOLDDISPLAYTEXT_STANDARD 1 #define SC_FOLDDISPLAYTEXT_BOXED 2 #define SCI_FOLDDISPLAYTEXTSETSTYLE 2701 #define SC_FOLDACTION_CONTRACT 0 #define SC_FOLDACTION_EXPAND 1 #define SC_FOLDACTION_TOGGLE 2 #define SCI_FOLDLINE 2237 #define SCI_FOLDCHILDREN 2238 #define SCI_EXPANDCHILDREN 2239 #define SCI_FOLDALL 2662 #define SCI_ENSUREVISIBLE 2232 #define SC_AUTOMATICFOLD_SHOW 0x0001 #define SC_AUTOMATICFOLD_CLICK 0x0002 #define SC_AUTOMATICFOLD_CHANGE 0x0004 #define SCI_SETAUTOMATICFOLD 2663 #define SCI_GETAUTOMATICFOLD 2664 #define SC_FOLDFLAG_LINEBEFORE_EXPANDED 0x0002 #define SC_FOLDFLAG_LINEBEFORE_CONTRACTED 0x0004 #define SC_FOLDFLAG_LINEAFTER_EXPANDED 0x0008 #define SC_FOLDFLAG_LINEAFTER_CONTRACTED 0x0010 #define SC_FOLDFLAG_LEVELNUMBERS 0x0040 #define SC_FOLDFLAG_LINESTATE 0x0080 #define SCI_SETFOLDFLAGS 2233 #define SCI_ENSUREVISIBLEENFORCEPOLICY 2234 #define SCI_SETTABINDENTS 2260 #define SCI_GETTABINDENTS 2261 #define SCI_SETBACKSPACEUNINDENTS 2262 #define SCI_GETBACKSPACEUNINDENTS 2263 #define SC_TIME_FOREVER 10000000 #define SCI_SETMOUSEDWELLTIME 2264 #define SCI_GETMOUSEDWELLTIME 2265 #define SCI_WORDSTARTPOSITION 2266 #define SCI_WORDENDPOSITION 2267 #define SCI_ISRANGEWORD 2691 #define SC_IDLESTYLING_NONE 0 #define SC_IDLESTYLING_TOVISIBLE 1 #define SC_IDLESTYLING_AFTERVISIBLE 2 #define SC_IDLESTYLING_ALL 3 #define SCI_SETIDLESTYLING 2692 #define SCI_GETIDLESTYLING 2693 #define SC_WRAP_NONE 0 #define SC_WRAP_WORD 1 #define SC_WRAP_CHAR 2 #define SC_WRAP_WHITESPACE 3 #define SCI_SETWRAPMODE 2268 #define SCI_GETWRAPMODE 2269 #define SC_WRAPVISUALFLAG_NONE 0x0000 #define SC_WRAPVISUALFLAG_END 0x0001 #define SC_WRAPVISUALFLAG_START 0x0002 #define SC_WRAPVISUALFLAG_MARGIN 0x0004 #define SCI_SETWRAPVISUALFLAGS 2460 #define SCI_GETWRAPVISUALFLAGS 2461 #define SC_WRAPVISUALFLAGLOC_DEFAULT 0x0000 #define SC_WRAPVISUALFLAGLOC_END_BY_TEXT 0x0001 #define SC_WRAPVISUALFLAGLOC_START_BY_TEXT 0x0002 #define SCI_SETWRAPVISUALFLAGSLOCATION 2462 #define SCI_GETWRAPVISUALFLAGSLOCATION 2463 #define SCI_SETWRAPSTARTINDENT 2464 #define SCI_GETWRAPSTARTINDENT 2465 #define SC_WRAPINDENT_FIXED 0 #define SC_WRAPINDENT_SAME 1 #define SC_WRAPINDENT_INDENT 2 #define SC_WRAPINDENT_DEEPINDENT 3 #define SCI_SETWRAPINDENTMODE 2472 #define SCI_GETWRAPINDENTMODE 2473 #define SC_CACHE_NONE 0 #define SC_CACHE_CARET 1 #define SC_CACHE_PAGE 2 #define SC_CACHE_DOCUMENT 3 #define SCI_SETLAYOUTCACHE 2272 #define SCI_GETLAYOUTCACHE 2273 #define SCI_SETSCROLLWIDTH 2274 #define SCI_GETSCROLLWIDTH 2275 #define SCI_SETSCROLLWIDTHTRACKING 2516 #define SCI_GETSCROLLWIDTHTRACKING 2517 #define SCI_TEXTWIDTH 2276 #define SCI_SETENDATLASTLINE 2277 #define SCI_GETENDATLASTLINE 2278 #define SCI_TEXTHEIGHT 2279 #define SCI_SETVSCROLLBAR 2280 #define SCI_GETVSCROLLBAR 2281 #define SCI_APPENDTEXT 2282 #define SCI_GETTWOPHASEDRAW 2283 #define SCI_SETTWOPHASEDRAW 2284 #define SC_PHASES_ONE 0 #define SC_PHASES_TWO 1 #define SC_PHASES_MULTIPLE 2 #define SCI_GETPHASESDRAW 2673 #define SCI_SETPHASESDRAW 2674 #define SC_EFF_QUALITY_MASK 0xF #define SC_EFF_QUALITY_DEFAULT 0 #define SC_EFF_QUALITY_NON_ANTIALIASED 1 #define SC_EFF_QUALITY_ANTIALIASED 2 #define SC_EFF_QUALITY_LCD_OPTIMIZED 3 #define SCI_SETFONTQUALITY 2611 #define SCI_GETFONTQUALITY 2612 #define SCI_SETFIRSTVISIBLELINE 2613 #define SC_MULTIPASTE_ONCE 0 #define SC_MULTIPASTE_EACH 1 #define SCI_SETMULTIPASTE 2614 #define SCI_GETMULTIPASTE 2615 #define SCI_GETTAG 2616 #define SCI_LINESJOIN 2288 #define SCI_LINESSPLIT 2289 #define SCI_SETFOLDMARGINCOLOUR 2290 #define SCI_SETFOLDMARGINHICOLOUR 2291 #define SC_ACCESSIBILITY_DISABLED 0 #define SC_ACCESSIBILITY_ENABLED 1 #define SCI_SETACCESSIBILITY 2702 #define SCI_GETACCESSIBILITY 2703 #define SCI_LINEDOWN 2300 #define SCI_LINEDOWNEXTEND 2301 #define SCI_LINEUP 2302 #define SCI_LINEUPEXTEND 2303 #define SCI_CHARLEFT 2304 #define SCI_CHARLEFTEXTEND 2305 #define SCI_CHARRIGHT 2306 #define SCI_CHARRIGHTEXTEND 2307 #define SCI_WORDLEFT 2308 #define SCI_WORDLEFTEXTEND 2309 #define SCI_WORDRIGHT 2310 #define SCI_WORDRIGHTEXTEND 2311 #define SCI_HOME 2312 #define SCI_HOMEEXTEND 2313 #define SCI_LINEEND 2314 #define SCI_LINEENDEXTEND 2315 #define SCI_DOCUMENTSTART 2316 #define SCI_DOCUMENTSTARTEXTEND 2317 #define SCI_DOCUMENTEND 2318 #define SCI_DOCUMENTENDEXTEND 2319 #define SCI_PAGEUP 2320 #define SCI_PAGEUPEXTEND 2321 #define SCI_PAGEDOWN 2322 #define SCI_PAGEDOWNEXTEND 2323 #define SCI_EDITTOGGLEOVERTYPE 2324 #define SCI_CANCEL 2325 #define SCI_DELETEBACK 2326 #define SCI_TAB 2327 #define SCI_BACKTAB 2328 #define SCI_NEWLINE 2329 #define SCI_FORMFEED 2330 #define SCI_VCHOME 2331 #define SCI_VCHOMEEXTEND 2332 #define SCI_ZOOMIN 2333 #define SCI_ZOOMOUT 2334 #define SCI_DELWORDLEFT 2335 #define SCI_DELWORDRIGHT 2336 #define SCI_DELWORDRIGHTEND 2518 #define SCI_LINECUT 2337 #define SCI_LINEDELETE 2338 #define SCI_LINETRANSPOSE 2339 #define SCI_LINEREVERSE 2354 #define SCI_LINEDUPLICATE 2404 #define SCI_LOWERCASE 2340 #define SCI_UPPERCASE 2341 #define SCI_LINESCROLLDOWN 2342 #define SCI_LINESCROLLUP 2343 #define SCI_DELETEBACKNOTLINE 2344 #define SCI_HOMEDISPLAY 2345 #define SCI_HOMEDISPLAYEXTEND 2346 #define SCI_LINEENDDISPLAY 2347 #define SCI_LINEENDDISPLAYEXTEND 2348 #define SCI_HOMEWRAP 2349 #define SCI_HOMEWRAPEXTEND 2450 #define SCI_LINEENDWRAP 2451 #define SCI_LINEENDWRAPEXTEND 2452 #define SCI_VCHOMEWRAP 2453 #define SCI_VCHOMEWRAPEXTEND 2454 #define SCI_LINECOPY 2455 #define SCI_MOVECARETINSIDEVIEW 2401 #define SCI_LINELENGTH 2350 #define SCI_BRACEHIGHLIGHT 2351 #define SCI_BRACEHIGHLIGHTINDICATOR 2498 #define SCI_BRACEBADLIGHT 2352 #define SCI_BRACEBADLIGHTINDICATOR 2499 #define SCI_BRACEMATCH 2353 #define SCI_GETVIEWEOL 2355 #define SCI_SETVIEWEOL 2356 #define SCI_GETDOCPOINTER 2357 #define SCI_SETDOCPOINTER 2358 #define SCI_SETMODEVENTMASK 2359 #define EDGE_NONE 0 #define EDGE_LINE 1 #define EDGE_BACKGROUND 2 #define EDGE_MULTILINE 3 #define SCI_GETEDGECOLUMN 2360 #define SCI_SETEDGECOLUMN 2361 #define SCI_GETEDGEMODE 2362 #define SCI_SETEDGEMODE 2363 #define SCI_GETEDGECOLOUR 2364 #define SCI_SETEDGECOLOUR 2365 #define SCI_MULTIEDGEADDLINE 2694 #define SCI_MULTIEDGECLEARALL 2695 #define SCI_SEARCHANCHOR 2366 #define SCI_SEARCHNEXT 2367 #define SCI_SEARCHPREV 2368 #define SCI_LINESONSCREEN 2370 #define SC_POPUP_NEVER 0 #define SC_POPUP_ALL 1 #define SC_POPUP_TEXT 2 #define SCI_USEPOPUP 2371 #define SCI_SELECTIONISRECTANGLE 2372 #define SCI_SETZOOM 2373 #define SCI_GETZOOM 2374 #define SC_DOCUMENTOPTION_DEFAULT 0 #define SC_DOCUMENTOPTION_STYLES_NONE 0x1 #define SC_DOCUMENTOPTION_TEXT_LARGE 0x100 #define SCI_CREATEDOCUMENT 2375 #define SCI_ADDREFDOCUMENT 2376 #define SCI_RELEASEDOCUMENT 2377 #define SCI_GETDOCUMENTOPTIONS 2379 #define SCI_GETMODEVENTMASK 2378 #define SCI_SETCOMMANDEVENTS 2717 #define SCI_GETCOMMANDEVENTS 2718 #define SCI_SETFOCUS 2380 #define SCI_GETFOCUS 2381 #define SC_STATUS_OK 0 #define SC_STATUS_FAILURE 1 #define SC_STATUS_BADALLOC 2 #define SC_STATUS_WARN_START 1000 #define SC_STATUS_WARN_REGEX 1001 #define SCI_SETSTATUS 2382 #define SCI_GETSTATUS 2383 #define SCI_SETMOUSEDOWNCAPTURES 2384 #define SCI_GETMOUSEDOWNCAPTURES 2385 #define SCI_SETMOUSEWHEELCAPTURES 2696 #define SCI_GETMOUSEWHEELCAPTURES 2697 #define SC_CURSORNORMAL -1 #define SC_CURSORARROW 2 #define SC_CURSORWAIT 4 #define SC_CURSORREVERSEARROW 7 #define SCI_SETCURSOR 2386 #define SCI_GETCURSOR 2387 #define SCI_SETCONTROLCHARSYMBOL 2388 #define SCI_GETCONTROLCHARSYMBOL 2389 #define SCI_WORDPARTLEFT 2390 #define SCI_WORDPARTLEFTEXTEND 2391 #define SCI_WORDPARTRIGHT 2392 #define SCI_WORDPARTRIGHTEXTEND 2393 #define VISIBLE_SLOP 0x01 #define VISIBLE_STRICT 0x04 #define SCI_SETVISIBLEPOLICY 2394 #define SCI_DELLINELEFT 2395 #define SCI_DELLINERIGHT 2396 #define SCI_SETXOFFSET 2397 #define SCI_GETXOFFSET 2398 #define SCI_CHOOSECARETX 2399 #define SCI_GRABFOCUS 2400 #define CARET_SLOP 0x01 #define CARET_STRICT 0x04 #define CARET_JUMPS 0x10 #define CARET_EVEN 0x08 #define SCI_SETXCARETPOLICY 2402 #define SCI_SETYCARETPOLICY 2403 #define SCI_SETPRINTWRAPMODE 2406 #define SCI_GETPRINTWRAPMODE 2407 #define SCI_SETHOTSPOTACTIVEFORE 2410 #define SCI_GETHOTSPOTACTIVEFORE 2494 #define SCI_SETHOTSPOTACTIVEBACK 2411 #define SCI_GETHOTSPOTACTIVEBACK 2495 #define SCI_SETHOTSPOTACTIVEUNDERLINE 2412 #define SCI_GETHOTSPOTACTIVEUNDERLINE 2496 #define SCI_SETHOTSPOTSINGLELINE 2421 #define SCI_GETHOTSPOTSINGLELINE 2497 #define SCI_PARADOWN 2413 #define SCI_PARADOWNEXTEND 2414 #define SCI_PARAUP 2415 #define SCI_PARAUPEXTEND 2416 #define SCI_POSITIONBEFORE 2417 #define SCI_POSITIONAFTER 2418 #define SCI_POSITIONRELATIVE 2670 #define SCI_POSITIONRELATIVECODEUNITS 2716 #define SCI_COPYRANGE 2419 #define SCI_COPYTEXT 2420 #define SC_SEL_STREAM 0 #define SC_SEL_RECTANGLE 1 #define SC_SEL_LINES 2 #define SC_SEL_THIN 3 #define SCI_SETSELECTIONMODE 2422 #define SCI_GETSELECTIONMODE 2423 #define SCI_GETMOVEEXTENDSSELECTION 2706 #define SCI_GETLINESELSTARTPOSITION 2424 #define SCI_GETLINESELENDPOSITION 2425 #define SCI_LINEDOWNRECTEXTEND 2426 #define SCI_LINEUPRECTEXTEND 2427 #define SCI_CHARLEFTRECTEXTEND 2428 #define SCI_CHARRIGHTRECTEXTEND 2429 #define SCI_HOMERECTEXTEND 2430 #define SCI_VCHOMERECTEXTEND 2431 #define SCI_LINEENDRECTEXTEND 2432 #define SCI_PAGEUPRECTEXTEND 2433 #define SCI_PAGEDOWNRECTEXTEND 2434 #define SCI_STUTTEREDPAGEUP 2435 #define SCI_STUTTEREDPAGEUPEXTEND 2436 #define SCI_STUTTEREDPAGEDOWN 2437 #define SCI_STUTTEREDPAGEDOWNEXTEND 2438 #define SCI_WORDLEFTEND 2439 #define SCI_WORDLEFTENDEXTEND 2440 #define SCI_WORDRIGHTEND 2441 #define SCI_WORDRIGHTENDEXTEND 2442 #define SCI_SETWHITESPACECHARS 2443 #define SCI_GETWHITESPACECHARS 2647 #define SCI_SETPUNCTUATIONCHARS 2648 #define SCI_GETPUNCTUATIONCHARS 2649 #define SCI_SETCHARSDEFAULT 2444 #define SCI_AUTOCGETCURRENT 2445 #define SCI_AUTOCGETCURRENTTEXT 2610 #define SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE 0 #define SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE 1 #define SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR 2634 #define SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR 2635 #define SC_MULTIAUTOC_ONCE 0 #define SC_MULTIAUTOC_EACH 1 #define SCI_AUTOCSETMULTI 2636 #define SCI_AUTOCGETMULTI 2637 #define SC_ORDER_PRESORTED 0 #define SC_ORDER_PERFORMSORT 1 #define SC_ORDER_CUSTOM 2 #define SCI_AUTOCSETORDER 2660 #define SCI_AUTOCGETORDER 2661 #define SCI_ALLOCATE 2446 #define SCI_TARGETASUTF8 2447 #define SCI_SETLENGTHFORENCODE 2448 #define SCI_ENCODEDFROMUTF8 2449 #define SCI_FINDCOLUMN 2456 #define SCI_GETCARETSTICKY 2457 #define SCI_SETCARETSTICKY 2458 #define SC_CARETSTICKY_OFF 0 #define SC_CARETSTICKY_ON 1 #define SC_CARETSTICKY_WHITESPACE 2 #define SCI_TOGGLECARETSTICKY 2459 #define SCI_SETPASTECONVERTENDINGS 2467 #define SCI_GETPASTECONVERTENDINGS 2468 #define SCI_SELECTIONDUPLICATE 2469 #define SC_ALPHA_TRANSPARENT 0 #define SC_ALPHA_OPAQUE 255 #define SC_ALPHA_NOALPHA 256 #define SCI_SETCARETLINEBACKALPHA 2470 #define SCI_GETCARETLINEBACKALPHA 2471 #define CARETSTYLE_INVISIBLE 0 #define CARETSTYLE_LINE 1 #define CARETSTYLE_BLOCK 2 #define SCI_SETCARETSTYLE 2512 #define SCI_GETCARETSTYLE 2513 #define SCI_SETINDICATORCURRENT 2500 #define SCI_GETINDICATORCURRENT 2501 #define SCI_SETINDICATORVALUE 2502 #define SCI_GETINDICATORVALUE 2503 #define SCI_INDICATORFILLRANGE 2504 #define SCI_INDICATORCLEARRANGE 2505 #define SCI_INDICATORALLONFOR 2506 #define SCI_INDICATORVALUEAT 2507 #define SCI_INDICATORSTART 2508 #define SCI_INDICATOREND 2509 #define SCI_SETPOSITIONCACHE 2514 #define SCI_GETPOSITIONCACHE 2515 #define SCI_COPYALLOWLINE 2519 #define SCI_GETCHARACTERPOINTER 2520 #define SCI_GETRANGEPOINTER 2643 #define SCI_GETGAPPOSITION 2644 #define SCI_INDICSETALPHA 2523 #define SCI_INDICGETALPHA 2524 #define SCI_INDICSETOUTLINEALPHA 2558 #define SCI_INDICGETOUTLINEALPHA 2559 #define SCI_SETEXTRAASCENT 2525 #define SCI_GETEXTRAASCENT 2526 #define SCI_SETEXTRADESCENT 2527 #define SCI_GETEXTRADESCENT 2528 #define SCI_MARKERSYMBOLDEFINED 2529 #define SCI_MARGINSETTEXT 2530 #define SCI_MARGINGETTEXT 2531 #define SCI_MARGINSETSTYLE 2532 #define SCI_MARGINGETSTYLE 2533 #define SCI_MARGINSETSTYLES 2534 #define SCI_MARGINGETSTYLES 2535 #define SCI_MARGINTEXTCLEARALL 2536 #define SCI_MARGINSETSTYLEOFFSET 2537 #define SCI_MARGINGETSTYLEOFFSET 2538 #define SC_MARGINOPTION_NONE 0 #define SC_MARGINOPTION_SUBLINESELECT 1 #define SCI_SETMARGINOPTIONS 2539 #define SCI_GETMARGINOPTIONS 2557 #define SCI_ANNOTATIONSETTEXT 2540 #define SCI_ANNOTATIONGETTEXT 2541 #define SCI_ANNOTATIONSETSTYLE 2542 #define SCI_ANNOTATIONGETSTYLE 2543 #define SCI_ANNOTATIONSETSTYLES 2544 #define SCI_ANNOTATIONGETSTYLES 2545 #define SCI_ANNOTATIONGETLINES 2546 #define SCI_ANNOTATIONCLEARALL 2547 #define ANNOTATION_HIDDEN 0 #define ANNOTATION_STANDARD 1 #define ANNOTATION_BOXED 2 #define ANNOTATION_INDENTED 3 #define SCI_ANNOTATIONSETVISIBLE 2548 #define SCI_ANNOTATIONGETVISIBLE 2549 #define SCI_ANNOTATIONSETSTYLEOFFSET 2550 #define SCI_ANNOTATIONGETSTYLEOFFSET 2551 #define SCI_RELEASEALLEXTENDEDSTYLES 2552 #define SCI_ALLOCATEEXTENDEDSTYLES 2553 #define UNDO_MAY_COALESCE 1 #define SCI_ADDUNDOACTION 2560 #define SCI_CHARPOSITIONFROMPOINT 2561 #define SCI_CHARPOSITIONFROMPOINTCLOSE 2562 #define SCI_SETMOUSESELECTIONRECTANGULARSWITCH 2668 #define SCI_GETMOUSESELECTIONRECTANGULARSWITCH 2669 #define SCI_SETMULTIPLESELECTION 2563 #define SCI_GETMULTIPLESELECTION 2564 #define SCI_SETADDITIONALSELECTIONTYPING 2565 #define SCI_GETADDITIONALSELECTIONTYPING 2566 #define SCI_SETADDITIONALCARETSBLINK 2567 #define SCI_GETADDITIONALCARETSBLINK 2568 #define SCI_SETADDITIONALCARETSVISIBLE 2608 #define SCI_GETADDITIONALCARETSVISIBLE 2609 #define SCI_GETSELECTIONS 2570 #define SCI_GETSELECTIONEMPTY 2650 #define SCI_CLEARSELECTIONS 2571 #define SCI_SETSELECTION 2572 #define SCI_ADDSELECTION 2573 #define SCI_DROPSELECTIONN 2671 #define SCI_SETMAINSELECTION 2574 #define SCI_GETMAINSELECTION 2575 #define SCI_SETSELECTIONNCARET 2576 #define SCI_GETSELECTIONNCARET 2577 #define SCI_SETSELECTIONNANCHOR 2578 #define SCI_GETSELECTIONNANCHOR 2579 #define SCI_SETSELECTIONNCARETVIRTUALSPACE 2580 #define SCI_GETSELECTIONNCARETVIRTUALSPACE 2581 #define SCI_SETSELECTIONNANCHORVIRTUALSPACE 2582 #define SCI_GETSELECTIONNANCHORVIRTUALSPACE 2583 #define SCI_SETSELECTIONNSTART 2584 #define SCI_GETSELECTIONNSTART 2585 #define SCI_SETSELECTIONNEND 2586 #define SCI_GETSELECTIONNEND 2587 #define SCI_SETRECTANGULARSELECTIONCARET 2588 #define SCI_GETRECTANGULARSELECTIONCARET 2589 #define SCI_SETRECTANGULARSELECTIONANCHOR 2590 #define SCI_GETRECTANGULARSELECTIONANCHOR 2591 #define SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE 2592 #define SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE 2593 #define SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE 2594 #define SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE 2595 #define SCVS_NONE 0 #define SCVS_RECTANGULARSELECTION 1 #define SCVS_USERACCESSIBLE 2 #define SCVS_NOWRAPLINESTART 4 #define SCI_SETVIRTUALSPACEOPTIONS 2596 #define SCI_GETVIRTUALSPACEOPTIONS 2597 #define SCI_SETRECTANGULARSELECTIONMODIFIER 2598 #define SCI_GETRECTANGULARSELECTIONMODIFIER 2599 #define SCI_SETADDITIONALSELFORE 2600 #define SCI_SETADDITIONALSELBACK 2601 #define SCI_SETADDITIONALSELALPHA 2602 #define SCI_GETADDITIONALSELALPHA 2603 #define SCI_SETADDITIONALCARETFORE 2604 #define SCI_GETADDITIONALCARETFORE 2605 #define SCI_ROTATESELECTION 2606 #define SCI_SWAPMAINANCHORCARET 2607 #define SCI_MULTIPLESELECTADDNEXT 2688 #define SCI_MULTIPLESELECTADDEACH 2689 #define SCI_CHANGELEXERSTATE 2617 #define SCI_CONTRACTEDFOLDNEXT 2618 #define SCI_VERTICALCENTRECARET 2619 #define SCI_MOVESELECTEDLINESUP 2620 #define SCI_MOVESELECTEDLINESDOWN 2621 #define SCI_SETIDENTIFIER 2622 #define SCI_GETIDENTIFIER 2623 #define SCI_RGBAIMAGESETWIDTH 2624 #define SCI_RGBAIMAGESETHEIGHT 2625 #define SCI_RGBAIMAGESETSCALE 2651 #define SCI_MARKERDEFINERGBAIMAGE 2626 #define SCI_REGISTERRGBAIMAGE 2627 #define SCI_SCROLLTOSTART 2628 #define SCI_SCROLLTOEND 2629 #define SC_TECHNOLOGY_DEFAULT 0 #define SC_TECHNOLOGY_DIRECTWRITE 1 #define SC_TECHNOLOGY_DIRECTWRITERETAIN 2 #define SC_TECHNOLOGY_DIRECTWRITEDC 3 #define SCI_SETTECHNOLOGY 2630 #define SCI_GETTECHNOLOGY 2631 #define SCI_CREATELOADER 2632 #define SCI_FINDINDICATORSHOW 2640 #define SCI_FINDINDICATORFLASH 2641 #define SCI_FINDINDICATORHIDE 2642 #define SCI_VCHOMEDISPLAY 2652 #define SCI_VCHOMEDISPLAYEXTEND 2653 #define SCI_GETCARETLINEVISIBLEALWAYS 2654 #define SCI_SETCARETLINEVISIBLEALWAYS 2655 #define SC_LINE_END_TYPE_DEFAULT 0 #define SC_LINE_END_TYPE_UNICODE 1 #define SCI_SETLINEENDTYPESALLOWED 2656 #define SCI_GETLINEENDTYPESALLOWED 2657 #define SCI_GETLINEENDTYPESACTIVE 2658 #define SCI_SETREPRESENTATION 2665 #define SCI_GETREPRESENTATION 2666 #define SCI_CLEARREPRESENTATION 2667 #define SCI_STARTRECORD 3001 #define SCI_STOPRECORD 3002 #define SCI_SETLEXER 4001 #define SCI_GETLEXER 4002 #define SCI_COLOURISE 4003 #define SCI_SETPROPERTY 4004 #define KEYWORDSET_MAX 8 #define SCI_SETKEYWORDS 4005 #define SCI_SETLEXERLANGUAGE 4006 #define SCI_LOADLEXERLIBRARY 4007 #define SCI_GETPROPERTY 4008 #define SCI_GETPROPERTYEXPANDED 4009 #define SCI_GETPROPERTYINT 4010 #define SCI_GETLEXERLANGUAGE 4012 #define SCI_PRIVATELEXERCALL 4013 #define SCI_PROPERTYNAMES 4014 #define SC_TYPE_BOOLEAN 0 #define SC_TYPE_INTEGER 1 #define SC_TYPE_STRING 2 #define SCI_PROPERTYTYPE 4015 #define SCI_DESCRIBEPROPERTY 4016 #define SCI_DESCRIBEKEYWORDSETS 4017 #define SCI_GETLINEENDTYPESSUPPORTED 4018 #define SCI_ALLOCATESUBSTYLES 4020 #define SCI_GETSUBSTYLESSTART 4021 #define SCI_GETSUBSTYLESLENGTH 4022 #define SCI_GETSTYLEFROMSUBSTYLE 4027 #define SCI_GETPRIMARYSTYLEFROMSTYLE 4028 #define SCI_FREESUBSTYLES 4023 #define SCI_SETIDENTIFIERS 4024 #define SCI_DISTANCETOSECONDARYSTYLES 4025 #define SCI_GETSUBSTYLEBASES 4026 #define SCI_GETNAMEDSTYLES 4029 #define SCI_NAMEOFSTYLE 4030 #define SCI_TAGSOFSTYLE 4031 #define SCI_DESCRIPTIONOFSTYLE 4032 #define SC_MOD_INSERTTEXT 0x1 #define SC_MOD_DELETETEXT 0x2 #define SC_MOD_CHANGESTYLE 0x4 #define SC_MOD_CHANGEFOLD 0x8 #define SC_PERFORMED_USER 0x10 #define SC_PERFORMED_UNDO 0x20 #define SC_PERFORMED_REDO 0x40 #define SC_MULTISTEPUNDOREDO 0x80 #define SC_LASTSTEPINUNDOREDO 0x100 #define SC_MOD_CHANGEMARKER 0x200 #define SC_MOD_BEFOREINSERT 0x400 #define SC_MOD_BEFOREDELETE 0x800 #define SC_MULTILINEUNDOREDO 0x1000 #define SC_STARTACTION 0x2000 #define SC_MOD_CHANGEINDICATOR 0x4000 #define SC_MOD_CHANGELINESTATE 0x8000 #define SC_MOD_CHANGEMARGIN 0x10000 #define SC_MOD_CHANGEANNOTATION 0x20000 #define SC_MOD_CONTAINER 0x40000 #define SC_MOD_LEXERSTATE 0x80000 #define SC_MOD_INSERTCHECK 0x100000 #define SC_MOD_CHANGETABSTOPS 0x200000 #define SC_MODEVENTMASKALL 0x3FFFFF #define SC_UPDATE_CONTENT 0x1 #define SC_UPDATE_SELECTION 0x2 #define SC_UPDATE_V_SCROLL 0x4 #define SC_UPDATE_H_SCROLL 0x8 #define SCEN_CHANGE 768 #define SCEN_SETFOCUS 512 #define SCEN_KILLFOCUS 256 #define SCK_DOWN 300 #define SCK_UP 301 #define SCK_LEFT 302 #define SCK_RIGHT 303 #define SCK_HOME 304 #define SCK_END 305 #define SCK_PRIOR 306 #define SCK_NEXT 307 #define SCK_DELETE 308 #define SCK_INSERT 309 #define SCK_ESCAPE 7 #define SCK_BACK 8 #define SCK_TAB 9 #define SCK_RETURN 13 #define SCK_ADD 310 #define SCK_SUBTRACT 311 #define SCK_DIVIDE 312 #define SCK_WIN 313 #define SCK_RWIN 314 #define SCK_MENU 315 #define SCMOD_NORM 0 #define SCMOD_SHIFT 1 #define SCMOD_CTRL 2 #define SCMOD_ALT 4 #define SCMOD_SUPER 8 #define SCMOD_META 16 #define SC_AC_FILLUP 1 #define SC_AC_DOUBLECLICK 2 #define SC_AC_TAB 3 #define SC_AC_NEWLINE 4 #define SC_AC_COMMAND 5 #define SCN_STYLENEEDED 2000 #define SCN_CHARADDED 2001 #define SCN_SAVEPOINTREACHED 2002 #define SCN_SAVEPOINTLEFT 2003 #define SCN_MODIFYATTEMPTRO 2004 #define SCN_KEY 2005 #define SCN_DOUBLECLICK 2006 #define SCN_UPDATEUI 2007 #define SCN_MODIFIED 2008 #define SCN_MACRORECORD 2009 #define SCN_MARGINCLICK 2010 #define SCN_NEEDSHOWN 2011 #define SCN_PAINTED 2013 #define SCN_USERLISTSELECTION 2014 #define SCN_URIDROPPED 2015 #define SCN_DWELLSTART 2016 #define SCN_DWELLEND 2017 #define SCN_ZOOM 2018 #define SCN_HOTSPOTCLICK 2019 #define SCN_HOTSPOTDOUBLECLICK 2020 #define SCN_CALLTIPCLICK 2021 #define SCN_AUTOCSELECTION 2022 #define SCN_INDICATORCLICK 2023 #define SCN_INDICATORRELEASE 2024 #define SCN_AUTOCCANCELLED 2025 #define SCN_AUTOCCHARDELETED 2026 #define SCN_HOTSPOTRELEASECLICK 2027 #define SCN_FOCUSIN 2028 #define SCN_FOCUSOUT 2029 #define SCN_AUTOCCOMPLETED 2030 #define SCN_MARGINRIGHTCLICK 2031 #define SCN_AUTOCSELECTIONCHANGE 2032 #ifndef SCI_DISABLE_PROVISIONAL #define SC_LINECHARACTERINDEX_NONE 0 #define SC_LINECHARACTERINDEX_UTF32 1 #define SC_LINECHARACTERINDEX_UTF16 2 #define SCI_GETLINECHARACTERINDEX 2710 #define SCI_ALLOCATELINECHARACTERINDEX 2711 #define SCI_RELEASELINECHARACTERINDEX 2712 #define SCI_LINEFROMINDEXPOSITION 2713 #define SCI_INDEXPOSITIONFROMLINE 2714 #endif /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ /* These structures are defined to be exactly the same shape as the Win32 * CHARRANGE, TEXTRANGE, FINDTEXTEX, FORMATRANGE, and NMHDR structs. * So older code that treats Scintilla as a RichEdit will work. */ struct Sci_CharacterRange { Sci_PositionCR cpMin; Sci_PositionCR cpMax; }; struct Sci_TextRange { struct Sci_CharacterRange chrg; char *lpstrText; }; struct Sci_TextToFind { struct Sci_CharacterRange chrg; const char *lpstrText; struct Sci_CharacterRange chrgText; }; typedef void *Sci_SurfaceID; struct Sci_Rectangle { int left; int top; int right; int bottom; }; /* This structure is used in printing and requires some of the graphics types * from Platform.h. Not needed by most client code. */ struct Sci_RangeToFormat { Sci_SurfaceID hdc; Sci_SurfaceID hdcTarget; struct Sci_Rectangle rc; struct Sci_Rectangle rcPage; struct Sci_CharacterRange chrg; }; #ifndef __cplusplus /* For the GTK+ platform, g-ir-scanner needs to have these typedefs. This * is not required in C++ code and actually seems to break ScintillaEditPy */ typedef struct Sci_NotifyHeader Sci_NotifyHeader; typedef struct SCNotification SCNotification; #endif struct Sci_NotifyHeader { /* Compatible with Windows NMHDR. * hwndFrom is really an environment specific window handle or pointer * but most clients of Scintilla.h do not have this type visible. */ void *hwndFrom; uptr_t idFrom; unsigned int code; }; struct SCNotification { Sci_NotifyHeader nmhdr; Sci_Position position; /* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */ /* SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, SCN_CALLTIPCLICK, */ /* SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */ /* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */ /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */ int ch; /* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */ /* SCN_USERLISTSELECTION */ int modifiers; /* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */ /* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */ int modificationType; /* SCN_MODIFIED */ const char *text; /* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_URIDROPPED */ Sci_Position length; /* SCN_MODIFIED */ Sci_Position linesAdded; /* SCN_MODIFIED */ int message; /* SCN_MACRORECORD */ uptr_t wParam; /* SCN_MACRORECORD */ sptr_t lParam; /* SCN_MACRORECORD */ Sci_Position line; /* SCN_MODIFIED */ int foldLevelNow; /* SCN_MODIFIED */ int foldLevelPrev; /* SCN_MODIFIED */ int margin; /* SCN_MARGINCLICK */ int listType; /* SCN_USERLISTSELECTION */ int x; /* SCN_DWELLSTART, SCN_DWELLEND */ int y; /* SCN_DWELLSTART, SCN_DWELLEND */ int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */ Sci_Position annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */ int updated; /* SCN_UPDATEUI */ int listCompletionMethod; /* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION, */ }; #ifdef INCLUDE_DEPRECATED_FEATURES #define SCI_SETKEYSUNICODE 2521 #define SCI_GETKEYSUNICODE 2522 #define CharacterRange Sci_CharacterRange #define TextRange Sci_TextRange #define TextToFind Sci_TextToFind #define RangeToFormat Sci_RangeToFormat #define NotifyHeader Sci_NotifyHeader #define SCI_SETSTYLEBITS 2090 #define SCI_GETSTYLEBITS 2091 #define SCI_GETSTYLEBITSNEEDED 4011 #endif #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/Scintilla.iface000066400000000000000000004506001463772530400273330ustar00rootroot00000000000000## First line may be used for shbang ## This file defines the interface to Scintilla ## Copyright 2000-2003 by Neil Hodgson ## The License.txt file describes the conditions under which this software may be distributed. ## A line starting with ## is a pure comment and should be stripped by readers. ## A line starting with #! is for future shbang use ## A line starting with # followed by a space is a documentation comment and refers ## to the next feature definition. ## Each feature is defined by a line starting with fun, get, set, val or evt. ## cat -> start a category ## fun -> a function ## get -> a property get function ## set -> a property set function ## val -> definition of a constant ## evt -> an event ## enu -> associate an enumeration with a set of vals with a prefix ## lex -> associate a lexer with the lexical classes it produces ## ## All other feature names should be ignored. They may be defined in the future. ## A property may have a set function, a get function or both. Each will have ## "Get" or "Set" in their names and the corresponding name will have the obvious switch. ## A property may be subscripted, in which case the first parameter is the subscript. ## fun, get, and set features have a strict syntax: ## [=,) ## where stands for white space. ## param may be empty (null value) or is [=] ## Additional white space is allowed between elements. ## The syntax for evt is [=[,]*]) ## Feature names that contain an underscore are defined by Windows, so in these ## cases, using the Windows definition is preferred where available. ## The feature numbers are stable so features will not be renumbered. ## Features may be removed but they will go through a period of deprecation ## before removal which is signalled by moving them into the Deprecated category. ## ## enu has the syntax enu=[]* where all the val ## features in this file starting with a given are considered part of the ## enumeration. ## ## lex has the syntax lex=[]* ## where name is a reasonably capitalised (Python, XML) identifier or UI name, ## lexerVal is the val used to specify the lexer, and the list of prefixes is similar ## to enu. The name may not be the same as that used within the lexer so the lexerVal ## should be used to tie these entities together. ## Types: ## void ## int ## bool -> integer, 1=true, 0=false ## position -> integer position in a document ## colour -> colour integer containing red, green and blue bytes. ## string -> pointer to const character ## stringresult -> pointer to character, NULL-> return size of result ## cells -> pointer to array of cells, each cell containing a style byte and character byte ## textrange -> range of a min and a max position with an output string ## findtext -> searchrange, text -> foundposition ## keymod -> integer containing key in low half and modifiers in high half ## formatrange ## Types no longer used: ## findtextex -> searchrange ## charrange -> range of a min and a max position ## charrangeresult -> like charrange, but output param ## countedstring ## point -> x,y ## pointresult -> like point, but output param ## rectangle -> left,top,right,bottom ## Client code should ignore definitions containing types it does not understand, except ## for possibly #defining the constants ## Line numbers and positions start at 0. ## String arguments may contain NUL ('\0') characters where the calls provide a length ## argument and retrieve NUL characters. APIs marked as NUL-terminated also have a ## NUL appended but client code should calculate the size that will be returned rather ## than relying upon the NUL whenever possible. Allow for the extra NUL character when ## allocating buffers. The size to allocate for a stringresult (not including NUL) can be ## determined by calling with a NULL (0) pointer. cat Basics ################################################ ## For Scintilla.h val INVALID_POSITION=-1 # Define start of Scintilla messages to be greater than all Windows edit (EM_*) messages # as many EM_ messages can be used although that use is deprecated. val SCI_START=2000 val SCI_OPTIONAL_START=3000 val SCI_LEXER_START=4000 # Add text to the document at current position. fun void AddText=2001(int length, string text) # Add array of cells to document. fun void AddStyledText=2002(int length, cells c) # Insert string at a position. fun void InsertText=2003(position pos, string text) # Change the text that is being inserted in response to SC_MOD_INSERTCHECK fun void ChangeInsertion=2672(int length, string text) # Delete all text in the document. fun void ClearAll=2004(,) # Delete a range of text in the document. fun void DeleteRange=2645(position start, int lengthDelete) # Set all style bytes to 0, remove all folding information. fun void ClearDocumentStyle=2005(,) # Returns the number of bytes in the document. get int GetLength=2006(,) # Returns the character byte at the position. get int GetCharAt=2007(position pos,) # Returns the position of the caret. get position GetCurrentPos=2008(,) # Returns the position of the opposite end of the selection to the caret. get position GetAnchor=2009(,) # Returns the style byte at the position. get int GetStyleAt=2010(position pos,) # Redoes the next action on the undo history. fun void Redo=2011(,) # Choose between collecting actions into the undo # history and discarding them. set void SetUndoCollection=2012(bool collectUndo,) # Select all the text in the document. fun void SelectAll=2013(,) # Remember the current position in the undo history as the position # at which the document was saved. fun void SetSavePoint=2014(,) # Retrieve a buffer of cells. # Returns the number of bytes in the buffer not including terminating NULs. fun int GetStyledText=2015(, textrange tr) # Are there any redoable actions in the undo history? fun bool CanRedo=2016(,) # Retrieve the line number at which a particular marker is located. fun int MarkerLineFromHandle=2017(int markerHandle,) # Delete a marker. fun void MarkerDeleteHandle=2018(int markerHandle,) # Is undo history being collected? get bool GetUndoCollection=2019(,) enu WhiteSpace=SCWS_ val SCWS_INVISIBLE=0 val SCWS_VISIBLEALWAYS=1 val SCWS_VISIBLEAFTERINDENT=2 val SCWS_VISIBLEONLYININDENT=3 # Are white space characters currently visible? # Returns one of SCWS_* constants. get int GetViewWS=2020(,) # Make white space characters invisible, always visible or visible outside indentation. set void SetViewWS=2021(int viewWS,) enu TabDrawMode=SCTD_ val SCTD_LONGARROW=0 val SCTD_STRIKEOUT=1 # Retrieve the current tab draw mode. # Returns one of SCTD_* constants. get int GetTabDrawMode=2698(,) # Set how tabs are drawn when visible. set void SetTabDrawMode=2699(int tabDrawMode,) # Find the position from a point within the window. fun position PositionFromPoint=2022(int x, int y) # Find the position from a point within the window but return # INVALID_POSITION if not close to text. fun position PositionFromPointClose=2023(int x, int y) # Set caret to start of a line and ensure it is visible. fun void GotoLine=2024(int line,) # Set caret to a position and ensure it is visible. fun void GotoPos=2025(position caret,) # Set the selection anchor to a position. The anchor is the opposite # end of the selection from the caret. set void SetAnchor=2026(position anchor,) # Retrieve the text of the line containing the caret. # Returns the index of the caret on the line. # Result is NUL-terminated. fun int GetCurLine=2027(int length, stringresult text) # Retrieve the position of the last correctly styled character. get position GetEndStyled=2028(,) enu EndOfLine=SC_EOL_ val SC_EOL_CRLF=0 val SC_EOL_CR=1 val SC_EOL_LF=2 # Convert all line endings in the document to one mode. fun void ConvertEOLs=2029(int eolMode,) # Retrieve the current end of line mode - one of CRLF, CR, or LF. get int GetEOLMode=2030(,) # Set the current end of line mode. set void SetEOLMode=2031(int eolMode,) # Set the current styling position to start. # The unused parameter is no longer used and should be set to 0. fun void StartStyling=2032(position start, int unused) # Change style from current styling position for length characters to a style # and move the current styling position to after this newly styled segment. fun void SetStyling=2033(int length, int style) # Is drawing done first into a buffer or direct to the screen? get bool GetBufferedDraw=2034(,) # If drawing is buffered then each line of text is drawn into a bitmap buffer # before drawing it to the screen to avoid flicker. set void SetBufferedDraw=2035(bool buffered,) # Change the visible size of a tab to be a multiple of the width of a space character. set void SetTabWidth=2036(int tabWidth,) # Retrieve the visible size of a tab. get int GetTabWidth=2121(,) # Clear explicit tabstops on a line. fun void ClearTabStops=2675(int line,) # Add an explicit tab stop for a line. fun void AddTabStop=2676(int line, int x) # Find the next explicit tab stop position on a line after a position. fun int GetNextTabStop=2677(int line, int x) # The SC_CP_UTF8 value can be used to enter Unicode mode. # This is the same value as CP_UTF8 in Windows val SC_CP_UTF8=65001 # Set the code page used to interpret the bytes of the document as characters. # The SC_CP_UTF8 value can be used to enter Unicode mode. set void SetCodePage=2037(int codePage,) enu IMEInteraction=SC_IME_ val SC_IME_WINDOWED=0 val SC_IME_INLINE=1 # Is the IME displayed in a window or inline? get int GetIMEInteraction=2678(,) # Choose to display the the IME in a winow or inline. set void SetIMEInteraction=2679(int imeInteraction,) enu MarkerSymbol=SC_MARK_ val MARKER_MAX=31 val SC_MARK_CIRCLE=0 val SC_MARK_ROUNDRECT=1 val SC_MARK_ARROW=2 val SC_MARK_SMALLRECT=3 val SC_MARK_SHORTARROW=4 val SC_MARK_EMPTY=5 val SC_MARK_ARROWDOWN=6 val SC_MARK_MINUS=7 val SC_MARK_PLUS=8 # Shapes used for outlining column. val SC_MARK_VLINE=9 val SC_MARK_LCORNER=10 val SC_MARK_TCORNER=11 val SC_MARK_BOXPLUS=12 val SC_MARK_BOXPLUSCONNECTED=13 val SC_MARK_BOXMINUS=14 val SC_MARK_BOXMINUSCONNECTED=15 val SC_MARK_LCORNERCURVE=16 val SC_MARK_TCORNERCURVE=17 val SC_MARK_CIRCLEPLUS=18 val SC_MARK_CIRCLEPLUSCONNECTED=19 val SC_MARK_CIRCLEMINUS=20 val SC_MARK_CIRCLEMINUSCONNECTED=21 # Invisible mark that only sets the line background colour. val SC_MARK_BACKGROUND=22 val SC_MARK_DOTDOTDOT=23 val SC_MARK_ARROWS=24 val SC_MARK_PIXMAP=25 val SC_MARK_FULLRECT=26 val SC_MARK_LEFTRECT=27 val SC_MARK_AVAILABLE=28 val SC_MARK_UNDERLINE=29 val SC_MARK_RGBAIMAGE=30 val SC_MARK_BOOKMARK=31 val SC_MARK_CHARACTER=10000 enu MarkerOutline=SC_MARKNUM_ # Markers used for outlining column. val SC_MARKNUM_FOLDEREND=25 val SC_MARKNUM_FOLDEROPENMID=26 val SC_MARKNUM_FOLDERMIDTAIL=27 val SC_MARKNUM_FOLDERTAIL=28 val SC_MARKNUM_FOLDERSUB=29 val SC_MARKNUM_FOLDER=30 val SC_MARKNUM_FOLDEROPEN=31 val SC_MASK_FOLDERS=0xFE000000 # Set the symbol used for a particular marker number. fun void MarkerDefine=2040(int markerNumber, int markerSymbol) # Set the foreground colour used for a particular marker number. set void MarkerSetFore=2041(int markerNumber, colour fore) # Set the background colour used for a particular marker number. set void MarkerSetBack=2042(int markerNumber, colour back) # Set the background colour used for a particular marker number when its folding block is selected. set void MarkerSetBackSelected=2292(int markerNumber, colour back) # Enable/disable highlight for current folding bloc (smallest one that contains the caret) fun void MarkerEnableHighlight=2293(bool enabled,) # Add a marker to a line, returning an ID which can be used to find or delete the marker. fun int MarkerAdd=2043(int line, int markerNumber) # Delete a marker from a line. fun void MarkerDelete=2044(int line, int markerNumber) # Delete all markers with a particular number from all lines. fun void MarkerDeleteAll=2045(int markerNumber,) # Get a bit mask of all the markers set on a line. fun int MarkerGet=2046(int line,) # Find the next line at or after lineStart that includes a marker in mask. # Return -1 when no more lines. fun int MarkerNext=2047(int lineStart, int markerMask) # Find the previous line before lineStart that includes a marker in mask. fun int MarkerPrevious=2048(int lineStart, int markerMask) # Define a marker from a pixmap. fun void MarkerDefinePixmap=2049(int markerNumber, string pixmap) # Add a set of markers to a line. fun void MarkerAddSet=2466(int line, int markerSet) # Set the alpha used for a marker that is drawn in the text area, not the margin. set void MarkerSetAlpha=2476(int markerNumber, int alpha) val SC_MAX_MARGIN=4 enu MarginType=SC_MARGIN_ val SC_MARGIN_SYMBOL=0 val SC_MARGIN_NUMBER=1 val SC_MARGIN_BACK=2 val SC_MARGIN_FORE=3 val SC_MARGIN_TEXT=4 val SC_MARGIN_RTEXT=5 val SC_MARGIN_COLOUR=6 # Set a margin to be either numeric or symbolic. set void SetMarginTypeN=2240(int margin, int marginType) # Retrieve the type of a margin. get int GetMarginTypeN=2241(int margin,) # Set the width of a margin to a width expressed in pixels. set void SetMarginWidthN=2242(int margin, int pixelWidth) # Retrieve the width of a margin in pixels. get int GetMarginWidthN=2243(int margin,) # Set a mask that determines which markers are displayed in a margin. set void SetMarginMaskN=2244(int margin, int mask) # Retrieve the marker mask of a margin. get int GetMarginMaskN=2245(int margin,) # Make a margin sensitive or insensitive to mouse clicks. set void SetMarginSensitiveN=2246(int margin, bool sensitive) # Retrieve the mouse click sensitivity of a margin. get bool GetMarginSensitiveN=2247(int margin,) # Set the cursor shown when the mouse is inside a margin. set void SetMarginCursorN=2248(int margin, int cursor) # Retrieve the cursor shown in a margin. get int GetMarginCursorN=2249(int margin,) # Set the background colour of a margin. Only visible for SC_MARGIN_COLOUR. set void SetMarginBackN=2250(int margin, colour back) # Retrieve the background colour of a margin get colour GetMarginBackN=2251(int margin,) # Allocate a non-standard number of margins. set void SetMargins=2252(int margins,) # How many margins are there?. get int GetMargins=2253(,) # Styles in range 32..39 are predefined for parts of the UI and are not used as normal styles. enu StylesCommon=STYLE_ val STYLE_DEFAULT=32 val STYLE_LINENUMBER=33 val STYLE_BRACELIGHT=34 val STYLE_BRACEBAD=35 val STYLE_CONTROLCHAR=36 val STYLE_INDENTGUIDE=37 val STYLE_CALLTIP=38 val STYLE_FOLDDISPLAYTEXT=39 val STYLE_LASTPREDEFINED=39 val STYLE_MAX=255 # Character set identifiers are used in StyleSetCharacterSet. # The values are the same as the Windows *_CHARSET values. enu CharacterSet=SC_CHARSET_ val SC_CHARSET_ANSI=0 val SC_CHARSET_DEFAULT=1 val SC_CHARSET_BALTIC=186 val SC_CHARSET_CHINESEBIG5=136 val SC_CHARSET_EASTEUROPE=238 val SC_CHARSET_GB2312=134 val SC_CHARSET_GREEK=161 val SC_CHARSET_HANGUL=129 val SC_CHARSET_MAC=77 val SC_CHARSET_OEM=255 val SC_CHARSET_RUSSIAN=204 val SC_CHARSET_OEM866=866 val SC_CHARSET_CYRILLIC=1251 val SC_CHARSET_SHIFTJIS=128 val SC_CHARSET_SYMBOL=2 val SC_CHARSET_TURKISH=162 val SC_CHARSET_JOHAB=130 val SC_CHARSET_HEBREW=177 val SC_CHARSET_ARABIC=178 val SC_CHARSET_VIETNAMESE=163 val SC_CHARSET_THAI=222 val SC_CHARSET_8859_15=1000 # Clear all the styles and make equivalent to the global default style. fun void StyleClearAll=2050(,) # Set the foreground colour of a style. set void StyleSetFore=2051(int style, colour fore) # Set the background colour of a style. set void StyleSetBack=2052(int style, colour back) # Set a style to be bold or not. set void StyleSetBold=2053(int style, bool bold) # Set a style to be italic or not. set void StyleSetItalic=2054(int style, bool italic) # Set the size of characters of a style. set void StyleSetSize=2055(int style, int sizePoints) # Set the font of a style. set void StyleSetFont=2056(int style, string fontName) # Set a style to have its end of line filled or not. set void StyleSetEOLFilled=2057(int style, bool eolFilled) # Reset the default style to its state at startup fun void StyleResetDefault=2058(,) # Set a style to be underlined or not. set void StyleSetUnderline=2059(int style, bool underline) enu CaseVisible=SC_CASE_ val SC_CASE_MIXED=0 val SC_CASE_UPPER=1 val SC_CASE_LOWER=2 val SC_CASE_CAMEL=3 # Get the foreground colour of a style. get colour StyleGetFore=2481(int style,) # Get the background colour of a style. get colour StyleGetBack=2482(int style,) # Get is a style bold or not. get bool StyleGetBold=2483(int style,) # Get is a style italic or not. get bool StyleGetItalic=2484(int style,) # Get the size of characters of a style. get int StyleGetSize=2485(int style,) # Get the font of a style. # Returns the length of the fontName # Result is NUL-terminated. get int StyleGetFont=2486(int style, stringresult fontName) # Get is a style to have its end of line filled or not. get bool StyleGetEOLFilled=2487(int style,) # Get is a style underlined or not. get bool StyleGetUnderline=2488(int style,) # Get is a style mixed case, or to force upper or lower case. get int StyleGetCase=2489(int style,) # Get the character get of the font in a style. get int StyleGetCharacterSet=2490(int style,) # Get is a style visible or not. get bool StyleGetVisible=2491(int style,) # Get is a style changeable or not (read only). # Experimental feature, currently buggy. get bool StyleGetChangeable=2492(int style,) # Get is a style a hotspot or not. get bool StyleGetHotSpot=2493(int style,) # Set a style to be mixed case, or to force upper or lower case. set void StyleSetCase=2060(int style, int caseVisible) val SC_FONT_SIZE_MULTIPLIER=100 # Set the size of characters of a style. Size is in points multiplied by 100. set void StyleSetSizeFractional=2061(int style, int sizeHundredthPoints) # Get the size of characters of a style in points multiplied by 100 get int StyleGetSizeFractional=2062(int style,) enu FontWeight=SC_WEIGHT_ val SC_WEIGHT_NORMAL=400 val SC_WEIGHT_SEMIBOLD=600 val SC_WEIGHT_BOLD=700 # Set the weight of characters of a style. set void StyleSetWeight=2063(int style, int weight) # Get the weight of characters of a style. get int StyleGetWeight=2064(int style,) # Set the character set of the font in a style. set void StyleSetCharacterSet=2066(int style, int characterSet) # Set a style to be a hotspot or not. set void StyleSetHotSpot=2409(int style, bool hotspot) # Set the foreground colour of the main and additional selections and whether to use this setting. fun void SetSelFore=2067(bool useSetting, colour fore) # Set the background colour of the main and additional selections and whether to use this setting. fun void SetSelBack=2068(bool useSetting, colour back) # Get the alpha of the selection. get int GetSelAlpha=2477(,) # Set the alpha of the selection. set void SetSelAlpha=2478(int alpha,) # Is the selection end of line filled? get bool GetSelEOLFilled=2479(,) # Set the selection to have its end of line filled or not. set void SetSelEOLFilled=2480(bool filled,) # Set the foreground colour of the caret. set void SetCaretFore=2069(colour fore,) # When key+modifier combination keyDefinition is pressed perform sciCommand. fun void AssignCmdKey=2070(keymod keyDefinition, int sciCommand) # When key+modifier combination keyDefinition is pressed do nothing. fun void ClearCmdKey=2071(keymod keyDefinition,) # Drop all key mappings. fun void ClearAllCmdKeys=2072(,) # Set the styles for a segment of the document. fun void SetStylingEx=2073(int length, string styles) # Set a style to be visible or not. set void StyleSetVisible=2074(int style, bool visible) # Get the time in milliseconds that the caret is on and off. get int GetCaretPeriod=2075(,) # Get the time in milliseconds that the caret is on and off. 0 = steady on. set void SetCaretPeriod=2076(int periodMilliseconds,) # Set the set of characters making up words for when moving or selecting by word. # First sets defaults like SetCharsDefault. set void SetWordChars=2077(, string characters) # Get the set of characters making up words for when moving or selecting by word. # Returns the number of characters get int GetWordChars=2646(, stringresult characters) # Start a sequence of actions that is undone and redone as a unit. # May be nested. fun void BeginUndoAction=2078(,) # End a sequence of actions that is undone and redone as a unit. fun void EndUndoAction=2079(,) # Indicator style enumeration and some constants enu IndicatorStyle=INDIC_ val INDIC_PLAIN=0 val INDIC_SQUIGGLE=1 val INDIC_TT=2 val INDIC_DIAGONAL=3 val INDIC_STRIKE=4 val INDIC_HIDDEN=5 val INDIC_BOX=6 val INDIC_ROUNDBOX=7 val INDIC_STRAIGHTBOX=8 val INDIC_DASH=9 val INDIC_DOTS=10 val INDIC_SQUIGGLELOW=11 val INDIC_DOTBOX=12 val INDIC_SQUIGGLEPIXMAP=13 val INDIC_COMPOSITIONTHICK=14 val INDIC_COMPOSITIONTHIN=15 val INDIC_FULLBOX=16 val INDIC_TEXTFORE=17 val INDIC_POINT=18 val INDIC_POINTCHARACTER=19 val INDIC_GRADIENT=20 val INDIC_GRADIENTCENTRE=21 val INDIC_IME=32 val INDIC_IME_MAX=35 val INDIC_MAX=35 val INDIC_CONTAINER=8 val INDIC0_MASK=0x20 val INDIC1_MASK=0x40 val INDIC2_MASK=0x80 val INDICS_MASK=0xE0 # Set an indicator to plain, squiggle or TT. set void IndicSetStyle=2080(int indicator, int indicatorStyle) # Retrieve the style of an indicator. get int IndicGetStyle=2081(int indicator,) # Set the foreground colour of an indicator. set void IndicSetFore=2082(int indicator, colour fore) # Retrieve the foreground colour of an indicator. get colour IndicGetFore=2083(int indicator,) # Set an indicator to draw under text or over(default). set void IndicSetUnder=2510(int indicator, bool under) # Retrieve whether indicator drawn under or over text. get bool IndicGetUnder=2511(int indicator,) # Set a hover indicator to plain, squiggle or TT. set void IndicSetHoverStyle=2680(int indicator, int indicatorStyle) # Retrieve the hover style of an indicator. get int IndicGetHoverStyle=2681(int indicator,) # Set the foreground hover colour of an indicator. set void IndicSetHoverFore=2682(int indicator, colour fore) # Retrieve the foreground hover colour of an indicator. get colour IndicGetHoverFore=2683(int indicator,) val SC_INDICVALUEBIT=0x1000000 val SC_INDICVALUEMASK=0xFFFFFF enu IndicFlag=SC_INDICFLAG_ val SC_INDICFLAG_VALUEFORE=1 # Set the attributes of an indicator. set void IndicSetFlags=2684(int indicator, int flags) # Retrieve the attributes of an indicator. get int IndicGetFlags=2685(int indicator,) # Set the foreground colour of all whitespace and whether to use this setting. fun void SetWhitespaceFore=2084(bool useSetting, colour fore) # Set the background colour of all whitespace and whether to use this setting. fun void SetWhitespaceBack=2085(bool useSetting, colour back) # Set the size of the dots used to mark space characters. set void SetWhitespaceSize=2086(int size,) # Get the size of the dots used to mark space characters. get int GetWhitespaceSize=2087(,) # Used to hold extra styling information for each line. set void SetLineState=2092(int line, int state) # Retrieve the extra styling information for a line. get int GetLineState=2093(int line,) # Retrieve the last line number that has line state. get int GetMaxLineState=2094(,) # Is the background of the line containing the caret in a different colour? get bool GetCaretLineVisible=2095(,) # Display the background of the line containing the caret in a different colour. set void SetCaretLineVisible=2096(bool show,) # Get the colour of the background of the line containing the caret. get colour GetCaretLineBack=2097(,) # Set the colour of the background of the line containing the caret. set void SetCaretLineBack=2098(colour back,) # Retrieve the caret line frame width. # Width = 0 means this option is disabled. get int GetCaretLineFrame=2704(,) # Display the caret line framed. # Set width != 0 to enable this option and width = 0 to disable it. set void SetCaretLineFrame=2705(int width,) # Set a style to be changeable or not (read only). # Experimental feature, currently buggy. set void StyleSetChangeable=2099(int style, bool changeable) # Display a auto-completion list. # The lengthEntered parameter indicates how many characters before # the caret should be used to provide context. fun void AutoCShow=2100(int lengthEntered, string itemList) # Remove the auto-completion list from the screen. fun void AutoCCancel=2101(,) # Is there an auto-completion list visible? fun bool AutoCActive=2102(,) # Retrieve the position of the caret when the auto-completion list was displayed. fun position AutoCPosStart=2103(,) # User has selected an item so remove the list and insert the selection. fun void AutoCComplete=2104(,) # Define a set of character that when typed cancel the auto-completion list. fun void AutoCStops=2105(, string characterSet) # Change the separator character in the string setting up an auto-completion list. # Default is space but can be changed if items contain space. set void AutoCSetSeparator=2106(int separatorCharacter,) # Retrieve the auto-completion list separator character. get int AutoCGetSeparator=2107(,) # Select the item in the auto-completion list that starts with a string. fun void AutoCSelect=2108(, string select) # Should the auto-completion list be cancelled if the user backspaces to a # position before where the box was created. set void AutoCSetCancelAtStart=2110(bool cancel,) # Retrieve whether auto-completion cancelled by backspacing before start. get bool AutoCGetCancelAtStart=2111(,) # Define a set of characters that when typed will cause the autocompletion to # choose the selected item. set void AutoCSetFillUps=2112(, string characterSet) # Should a single item auto-completion list automatically choose the item. set void AutoCSetChooseSingle=2113(bool chooseSingle,) # Retrieve whether a single item auto-completion list automatically choose the item. get bool AutoCGetChooseSingle=2114(,) # Set whether case is significant when performing auto-completion searches. set void AutoCSetIgnoreCase=2115(bool ignoreCase,) # Retrieve state of ignore case flag. get bool AutoCGetIgnoreCase=2116(,) # Display a list of strings and send notification when user chooses one. fun void UserListShow=2117(int listType, string itemList) # Set whether or not autocompletion is hidden automatically when nothing matches. set void AutoCSetAutoHide=2118(bool autoHide,) # Retrieve whether or not autocompletion is hidden automatically when nothing matches. get bool AutoCGetAutoHide=2119(,) # Set whether or not autocompletion deletes any word characters # after the inserted text upon completion. set void AutoCSetDropRestOfWord=2270(bool dropRestOfWord,) # Retrieve whether or not autocompletion deletes any word characters # after the inserted text upon completion. get bool AutoCGetDropRestOfWord=2271(,) # Register an XPM image for use in autocompletion lists. fun void RegisterImage=2405(int type, string xpmData) # Clear all the registered XPM images. fun void ClearRegisteredImages=2408(,) # Retrieve the auto-completion list type-separator character. get int AutoCGetTypeSeparator=2285(,) # Change the type-separator character in the string setting up an auto-completion list. # Default is '?' but can be changed if items contain '?'. set void AutoCSetTypeSeparator=2286(int separatorCharacter,) # Set the maximum width, in characters, of auto-completion and user lists. # Set to 0 to autosize to fit longest item, which is the default. set void AutoCSetMaxWidth=2208(int characterCount,) # Get the maximum width, in characters, of auto-completion and user lists. get int AutoCGetMaxWidth=2209(,) # Set the maximum height, in rows, of auto-completion and user lists. # The default is 5 rows. set void AutoCSetMaxHeight=2210(int rowCount,) # Set the maximum height, in rows, of auto-completion and user lists. get int AutoCGetMaxHeight=2211(,) # Set the number of spaces used for one level of indentation. set void SetIndent=2122(int indentSize,) # Retrieve indentation size. get int GetIndent=2123(,) # Indentation will only use space characters if useTabs is false, otherwise # it will use a combination of tabs and spaces. set void SetUseTabs=2124(bool useTabs,) # Retrieve whether tabs will be used in indentation. get bool GetUseTabs=2125(,) # Change the indentation of a line to a number of columns. set void SetLineIndentation=2126(int line, int indentation) # Retrieve the number of columns that a line is indented. get int GetLineIndentation=2127(int line,) # Retrieve the position before the first non indentation character on a line. get position GetLineIndentPosition=2128(int line,) # Retrieve the column number of a position, taking tab width into account. get int GetColumn=2129(position pos,) # Count characters between two positions. fun int CountCharacters=2633(position start, position end) # Count code units between two positions. fun int CountCodeUnits=2715(position start, position end) # Show or hide the horizontal scroll bar. set void SetHScrollBar=2130(bool visible,) # Is the horizontal scroll bar visible? get bool GetHScrollBar=2131(,) enu IndentView=SC_IV_ val SC_IV_NONE=0 val SC_IV_REAL=1 val SC_IV_LOOKFORWARD=2 val SC_IV_LOOKBOTH=3 # Show or hide indentation guides. set void SetIndentationGuides=2132(int indentView,) # Are the indentation guides visible? get int GetIndentationGuides=2133(,) # Set the highlighted indentation guide column. # 0 = no highlighted guide. set void SetHighlightGuide=2134(int column,) # Get the highlighted indentation guide column. get int GetHighlightGuide=2135(,) # Get the position after the last visible characters on a line. get position GetLineEndPosition=2136(int line,) # Get the code page used to interpret the bytes of the document as characters. get int GetCodePage=2137(,) # Get the foreground colour of the caret. get colour GetCaretFore=2138(,) # In read-only mode? get bool GetReadOnly=2140(,) # Sets the position of the caret. set void SetCurrentPos=2141(position caret,) # Sets the position that starts the selection - this becomes the anchor. set void SetSelectionStart=2142(position anchor,) # Returns the position at the start of the selection. get position GetSelectionStart=2143(,) # Sets the position that ends the selection - this becomes the caret. set void SetSelectionEnd=2144(position caret,) # Returns the position at the end of the selection. get position GetSelectionEnd=2145(,) # Set caret to a position, while removing any existing selection. fun void SetEmptySelection=2556(position caret,) # Sets the print magnification added to the point size of each style for printing. set void SetPrintMagnification=2146(int magnification,) # Returns the print magnification. get int GetPrintMagnification=2147(,) enu PrintOption=SC_PRINT_ # PrintColourMode - use same colours as screen. # with the exception of line number margins, which use a white background val SC_PRINT_NORMAL=0 # PrintColourMode - invert the light value of each style for printing. val SC_PRINT_INVERTLIGHT=1 # PrintColourMode - force black text on white background for printing. val SC_PRINT_BLACKONWHITE=2 # PrintColourMode - text stays coloured, but all background is forced to be white for printing. val SC_PRINT_COLOURONWHITE=3 # PrintColourMode - only the default-background is forced to be white for printing. val SC_PRINT_COLOURONWHITEDEFAULTBG=4 # PrintColourMode - use same colours as screen, including line number margins. val SC_PRINT_SCREENCOLOURS=5 # Modify colours when printing for clearer printed text. set void SetPrintColourMode=2148(int mode,) # Returns the print colour mode. get int GetPrintColourMode=2149(,) enu FindOption=SCFIND_ val SCFIND_WHOLEWORD=0x2 val SCFIND_MATCHCASE=0x4 val SCFIND_WORDSTART=0x00100000 val SCFIND_REGEXP=0x00200000 val SCFIND_POSIX=0x00400000 val SCFIND_CXX11REGEX=0x00800000 # Find some text in the document. fun position FindText=2150(int searchFlags, findtext ft) # On Windows, will draw the document into a display context such as a printer. fun position FormatRange=2151(bool draw, formatrange fr) # Retrieve the display line at the top of the display. get int GetFirstVisibleLine=2152(,) # Retrieve the contents of a line. # Returns the length of the line. fun int GetLine=2153(int line, stringresult text) # Returns the number of lines in the document. There is always at least one. get int GetLineCount=2154(,) # Sets the size in pixels of the left margin. set void SetMarginLeft=2155(, int pixelWidth) # Returns the size in pixels of the left margin. get int GetMarginLeft=2156(,) # Sets the size in pixels of the right margin. set void SetMarginRight=2157(, int pixelWidth) # Returns the size in pixels of the right margin. get int GetMarginRight=2158(,) # Is the document different from when it was last saved? get bool GetModify=2159(,) # Select a range of text. fun void SetSel=2160(position anchor, position caret) # Retrieve the selected text. # Return the length of the text. # Result is NUL-terminated. fun int GetSelText=2161(, stringresult text) # Retrieve a range of text. # Return the length of the text. fun int GetTextRange=2162(, textrange tr) # Draw the selection either highlighted or in normal (non-highlighted) style. fun void HideSelection=2163(bool hide,) # Retrieve the x value of the point in the window where a position is displayed. fun int PointXFromPosition=2164(, position pos) # Retrieve the y value of the point in the window where a position is displayed. fun int PointYFromPosition=2165(, position pos) # Retrieve the line containing a position. fun int LineFromPosition=2166(position pos,) # Retrieve the position at the start of a line. fun position PositionFromLine=2167(int line,) # Scroll horizontally and vertically. fun void LineScroll=2168(int columns, int lines) # Ensure the caret is visible. fun void ScrollCaret=2169(,) # Scroll the argument positions and the range between them into view giving # priority to the primary position then the secondary position. # This may be used to make a search match visible. fun void ScrollRange=2569(position secondary, position primary) # Replace the selected text with the argument text. fun void ReplaceSel=2170(, string text) # Set to read only or read write. set void SetReadOnly=2171(bool readOnly,) # Null operation. fun void Null=2172(,) # Will a paste succeed? fun bool CanPaste=2173(,) # Are there any undoable actions in the undo history? fun bool CanUndo=2174(,) # Delete the undo history. fun void EmptyUndoBuffer=2175(,) # Undo one action in the undo history. fun void Undo=2176(,) # Cut the selection to the clipboard. fun void Cut=2177(,) # Copy the selection to the clipboard. fun void Copy=2178(,) # Paste the contents of the clipboard into the document replacing the selection. fun void Paste=2179(,) # Clear the selection. fun void Clear=2180(,) # Replace the contents of the document with the argument text. fun void SetText=2181(, string text) # Retrieve all the text in the document. # Returns number of characters retrieved. # Result is NUL-terminated. fun int GetText=2182(int length, stringresult text) # Retrieve the number of characters in the document. get int GetTextLength=2183(,) # Retrieve a pointer to a function that processes messages for this Scintilla. get int GetDirectFunction=2184(,) # Retrieve a pointer value to use as the first argument when calling # the function returned by GetDirectFunction. get int GetDirectPointer=2185(,) # Set to overtype (true) or insert mode. set void SetOvertype=2186(bool overType,) # Returns true if overtype mode is active otherwise false is returned. get bool GetOvertype=2187(,) # Set the width of the insert mode caret. set void SetCaretWidth=2188(int pixelWidth,) # Returns the width of the insert mode caret. get int GetCaretWidth=2189(,) # Sets the position that starts the target which is used for updating the # document without affecting the scroll position. set void SetTargetStart=2190(position start,) # Get the position that starts the target. get position GetTargetStart=2191(,) # Sets the position that ends the target which is used for updating the # document without affecting the scroll position. set void SetTargetEnd=2192(position end,) # Get the position that ends the target. get position GetTargetEnd=2193(,) # Sets both the start and end of the target in one call. fun void SetTargetRange=2686(position start, position end) # Retrieve the text in the target. get int GetTargetText=2687(, stringresult text) # Make the target range start and end be the same as the selection range start and end. fun void TargetFromSelection=2287(,) # Sets the target to the whole document. fun void TargetWholeDocument=2690(,) # Replace the target text with the argument text. # Text is counted so it can contain NULs. # Returns the length of the replacement text. fun int ReplaceTarget=2194(int length, string text) # Replace the target text with the argument text after \d processing. # Text is counted so it can contain NULs. # Looks for \d where d is between 1 and 9 and replaces these with the strings # matched in the last search operation which were surrounded by \( and \). # Returns the length of the replacement text including any change # caused by processing the \d patterns. fun int ReplaceTargetRE=2195(int length, string text) # Search for a counted string in the target and set the target to the found # range. Text is counted so it can contain NULs. # Returns length of range or -1 for failure in which case target is not moved. fun int SearchInTarget=2197(int length, string text) # Set the search flags used by SearchInTarget. set void SetSearchFlags=2198(int searchFlags,) # Get the search flags used by SearchInTarget. get int GetSearchFlags=2199(,) # Show a call tip containing a definition near position pos. fun void CallTipShow=2200(position pos, string definition) # Remove the call tip from the screen. fun void CallTipCancel=2201(,) # Is there an active call tip? fun bool CallTipActive=2202(,) # Retrieve the position where the caret was before displaying the call tip. fun position CallTipPosStart=2203(,) # Set the start position in order to change when backspacing removes the calltip. set void CallTipSetPosStart=2214(int posStart,) # Highlight a segment of the definition. fun void CallTipSetHlt=2204(int highlightStart, int highlightEnd) # Set the background colour for the call tip. set void CallTipSetBack=2205(colour back,) # Set the foreground colour for the call tip. set void CallTipSetFore=2206(colour fore,) # Set the foreground colour for the highlighted part of the call tip. set void CallTipSetForeHlt=2207(colour fore,) # Enable use of STYLE_CALLTIP and set call tip tab size in pixels. set void CallTipUseStyle=2212(int tabSize,) # Set position of calltip, above or below text. set void CallTipSetPosition=2213(bool above,) # Find the display line of a document line taking hidden lines into account. fun int VisibleFromDocLine=2220(int docLine,) # Find the document line of a display line taking hidden lines into account. fun int DocLineFromVisible=2221(int displayLine,) # The number of display lines needed to wrap a document line fun int WrapCount=2235(int docLine,) enu FoldLevel=SC_FOLDLEVEL val SC_FOLDLEVELBASE=0x400 val SC_FOLDLEVELWHITEFLAG=0x1000 val SC_FOLDLEVELHEADERFLAG=0x2000 val SC_FOLDLEVELNUMBERMASK=0x0FFF # Set the fold level of a line. # This encodes an integer level along with flags indicating whether the # line is a header and whether it is effectively white space. set void SetFoldLevel=2222(int line, int level) # Retrieve the fold level of a line. get int GetFoldLevel=2223(int line,) # Find the last child line of a header line. get int GetLastChild=2224(int line, int level) # Find the parent line of a child line. get int GetFoldParent=2225(int line,) # Make a range of lines visible. fun void ShowLines=2226(int lineStart, int lineEnd) # Make a range of lines invisible. fun void HideLines=2227(int lineStart, int lineEnd) # Is a line visible? get bool GetLineVisible=2228(int line,) # Are all lines visible? get bool GetAllLinesVisible=2236(,) # Show the children of a header line. set void SetFoldExpanded=2229(int line, bool expanded) # Is a header line expanded? get bool GetFoldExpanded=2230(int line,) # Switch a header line between expanded and contracted. fun void ToggleFold=2231(int line,) # Switch a header line between expanded and contracted and show some text after the line. fun void ToggleFoldShowText=2700(int line, string text) enu FoldDisplayTextStyle=SC_FOLDDISPLAYTEXT_ val SC_FOLDDISPLAYTEXT_HIDDEN=0 val SC_FOLDDISPLAYTEXT_STANDARD=1 val SC_FOLDDISPLAYTEXT_BOXED=2 # Set the style of fold display text set void FoldDisplayTextSetStyle=2701(int style,) enu FoldAction=SC_FOLDACTION_ val SC_FOLDACTION_CONTRACT=0 val SC_FOLDACTION_EXPAND=1 val SC_FOLDACTION_TOGGLE=2 # Expand or contract a fold header. fun void FoldLine=2237(int line, int action) # Expand or contract a fold header and its children. fun void FoldChildren=2238(int line, int action) # Expand a fold header and all children. Use the level argument instead of the line's current level. fun void ExpandChildren=2239(int line, int level) # Expand or contract all fold headers. fun void FoldAll=2662(int action,) # Ensure a particular line is visible by expanding any header line hiding it. fun void EnsureVisible=2232(int line,) enu AutomaticFold=SC_AUTOMATICFOLD_ val SC_AUTOMATICFOLD_SHOW=0x0001 val SC_AUTOMATICFOLD_CLICK=0x0002 val SC_AUTOMATICFOLD_CHANGE=0x0004 # Set automatic folding behaviours. set void SetAutomaticFold=2663(int automaticFold,) # Get automatic folding behaviours. get int GetAutomaticFold=2664(,) enu FoldFlag=SC_FOLDFLAG_ val SC_FOLDFLAG_LINEBEFORE_EXPANDED=0x0002 val SC_FOLDFLAG_LINEBEFORE_CONTRACTED=0x0004 val SC_FOLDFLAG_LINEAFTER_EXPANDED=0x0008 val SC_FOLDFLAG_LINEAFTER_CONTRACTED=0x0010 val SC_FOLDFLAG_LEVELNUMBERS=0x0040 val SC_FOLDFLAG_LINESTATE=0x0080 # Set some style options for folding. set void SetFoldFlags=2233(int flags,) # Ensure a particular line is visible by expanding any header line hiding it. # Use the currently set visibility policy to determine which range to display. fun void EnsureVisibleEnforcePolicy=2234(int line,) # Sets whether a tab pressed when caret is within indentation indents. set void SetTabIndents=2260(bool tabIndents,) # Does a tab pressed when caret is within indentation indent? get bool GetTabIndents=2261(,) # Sets whether a backspace pressed when caret is within indentation unindents. set void SetBackSpaceUnIndents=2262(bool bsUnIndents,) # Does a backspace pressed when caret is within indentation unindent? get bool GetBackSpaceUnIndents=2263(,) val SC_TIME_FOREVER=10000000 # Sets the time the mouse must sit still to generate a mouse dwell event. set void SetMouseDwellTime=2264(int periodMilliseconds,) # Retrieve the time the mouse must sit still to generate a mouse dwell event. get int GetMouseDwellTime=2265(,) # Get position of start of word. fun int WordStartPosition=2266(position pos, bool onlyWordCharacters) # Get position of end of word. fun int WordEndPosition=2267(position pos, bool onlyWordCharacters) # Is the range start..end considered a word? fun bool IsRangeWord=2691(position start, position end) enu IdleStyling=SC_IDLESTYLING_ val SC_IDLESTYLING_NONE=0 val SC_IDLESTYLING_TOVISIBLE=1 val SC_IDLESTYLING_AFTERVISIBLE=2 val SC_IDLESTYLING_ALL=3 # Sets limits to idle styling. set void SetIdleStyling=2692(int idleStyling,) # Retrieve the limits to idle styling. get int GetIdleStyling=2693(,) enu Wrap=SC_WRAP_ val SC_WRAP_NONE=0 val SC_WRAP_WORD=1 val SC_WRAP_CHAR=2 val SC_WRAP_WHITESPACE=3 # Sets whether text is word wrapped. set void SetWrapMode=2268(int wrapMode,) # Retrieve whether text is word wrapped. get int GetWrapMode=2269(,) enu WrapVisualFlag=SC_WRAPVISUALFLAG_ val SC_WRAPVISUALFLAG_NONE=0x0000 val SC_WRAPVISUALFLAG_END=0x0001 val SC_WRAPVISUALFLAG_START=0x0002 val SC_WRAPVISUALFLAG_MARGIN=0x0004 # Set the display mode of visual flags for wrapped lines. set void SetWrapVisualFlags=2460(int wrapVisualFlags,) # Retrive the display mode of visual flags for wrapped lines. get int GetWrapVisualFlags=2461(,) enu WrapVisualLocation=SC_WRAPVISUALFLAGLOC_ val SC_WRAPVISUALFLAGLOC_DEFAULT=0x0000 val SC_WRAPVISUALFLAGLOC_END_BY_TEXT=0x0001 val SC_WRAPVISUALFLAGLOC_START_BY_TEXT=0x0002 # Set the location of visual flags for wrapped lines. set void SetWrapVisualFlagsLocation=2462(int wrapVisualFlagsLocation,) # Retrive the location of visual flags for wrapped lines. get int GetWrapVisualFlagsLocation=2463(,) # Set the start indent for wrapped lines. set void SetWrapStartIndent=2464(int indent,) # Retrive the start indent for wrapped lines. get int GetWrapStartIndent=2465(,) enu WrapIndentMode=SC_WRAPINDENT_ val SC_WRAPINDENT_FIXED=0 val SC_WRAPINDENT_SAME=1 val SC_WRAPINDENT_INDENT=2 val SC_WRAPINDENT_DEEPINDENT=3 # Sets how wrapped sublines are placed. Default is fixed. set void SetWrapIndentMode=2472(int wrapIndentMode,) # Retrieve how wrapped sublines are placed. Default is fixed. get int GetWrapIndentMode=2473(,) enu LineCache=SC_CACHE_ val SC_CACHE_NONE=0 val SC_CACHE_CARET=1 val SC_CACHE_PAGE=2 val SC_CACHE_DOCUMENT=3 # Sets the degree of caching of layout information. set void SetLayoutCache=2272(int cacheMode,) # Retrieve the degree of caching of layout information. get int GetLayoutCache=2273(,) # Sets the document width assumed for scrolling. set void SetScrollWidth=2274(int pixelWidth,) # Retrieve the document width assumed for scrolling. get int GetScrollWidth=2275(,) # Sets whether the maximum width line displayed is used to set scroll width. set void SetScrollWidthTracking=2516(bool tracking,) # Retrieve whether the scroll width tracks wide lines. get bool GetScrollWidthTracking=2517(,) # Measure the pixel width of some text in a particular style. # NUL terminated text argument. # Does not handle tab or control characters. fun int TextWidth=2276(int style, string text) # Sets the scroll range so that maximum scroll position has # the last line at the bottom of the view (default). # Setting this to false allows scrolling one page below the last line. set void SetEndAtLastLine=2277(bool endAtLastLine,) # Retrieve whether the maximum scroll position has the last # line at the bottom of the view. get bool GetEndAtLastLine=2278(,) # Retrieve the height of a particular line of text in pixels. fun int TextHeight=2279(int line,) # Show or hide the vertical scroll bar. set void SetVScrollBar=2280(bool visible,) # Is the vertical scroll bar visible? get bool GetVScrollBar=2281(,) # Append a string to the end of the document without changing the selection. fun void AppendText=2282(int length, string text) # Is drawing done in two phases with backgrounds drawn before foregrounds? get bool GetTwoPhaseDraw=2283(,) # In twoPhaseDraw mode, drawing is performed in two phases, first the background # and then the foreground. This avoids chopping off characters that overlap the next run. set void SetTwoPhaseDraw=2284(bool twoPhase,) enu PhasesDraw=SC_PHASES_ val SC_PHASES_ONE=0 val SC_PHASES_TWO=1 val SC_PHASES_MULTIPLE=2 # How many phases is drawing done in? get int GetPhasesDraw=2673(,) # In one phase draw, text is drawn in a series of rectangular blocks with no overlap. # In two phase draw, text is drawn in a series of lines allowing runs to overlap horizontally. # In multiple phase draw, each element is drawn over the whole drawing area, allowing text # to overlap from one line to the next. set void SetPhasesDraw=2674(int phases,) # Control font anti-aliasing. enu FontQuality=SC_EFF_ val SC_EFF_QUALITY_MASK=0xF val SC_EFF_QUALITY_DEFAULT=0 val SC_EFF_QUALITY_NON_ANTIALIASED=1 val SC_EFF_QUALITY_ANTIALIASED=2 val SC_EFF_QUALITY_LCD_OPTIMIZED=3 # Choose the quality level for text from the FontQuality enumeration. set void SetFontQuality=2611(int fontQuality,) # Retrieve the quality level for text. get int GetFontQuality=2612(,) # Scroll so that a display line is at the top of the display. set void SetFirstVisibleLine=2613(int displayLine,) enu MultiPaste=SC_MULTIPASTE_ val SC_MULTIPASTE_ONCE=0 val SC_MULTIPASTE_EACH=1 # Change the effect of pasting when there are multiple selections. set void SetMultiPaste=2614(int multiPaste,) # Retrieve the effect of pasting when there are multiple selections. get int GetMultiPaste=2615(,) # Retrieve the value of a tag from a regular expression search. # Result is NUL-terminated. get int GetTag=2616(int tagNumber, stringresult tagValue) # Join the lines in the target. fun void LinesJoin=2288(,) # Split the lines in the target into lines that are less wide than pixelWidth # where possible. fun void LinesSplit=2289(int pixelWidth,) # Set one of the colours used as a chequerboard pattern in the fold margin fun void SetFoldMarginColour=2290(bool useSetting, colour back) # Set the other colour used as a chequerboard pattern in the fold margin fun void SetFoldMarginHiColour=2291(bool useSetting, colour fore) enu Accessibility=SC_ACCESSIBILITY_ val SC_ACCESSIBILITY_DISABLED=0 val SC_ACCESSIBILITY_ENABLED=1 # Enable or disable accessibility. set void SetAccessibility=2702(int accessibility,) # Report accessibility status. get int GetAccessibility=2703(,) ## New messages go here ## Start of key messages # Move caret down one line. fun void LineDown=2300(,) # Move caret down one line extending selection to new caret position. fun void LineDownExtend=2301(,) # Move caret up one line. fun void LineUp=2302(,) # Move caret up one line extending selection to new caret position. fun void LineUpExtend=2303(,) # Move caret left one character. fun void CharLeft=2304(,) # Move caret left one character extending selection to new caret position. fun void CharLeftExtend=2305(,) # Move caret right one character. fun void CharRight=2306(,) # Move caret right one character extending selection to new caret position. fun void CharRightExtend=2307(,) # Move caret left one word. fun void WordLeft=2308(,) # Move caret left one word extending selection to new caret position. fun void WordLeftExtend=2309(,) # Move caret right one word. fun void WordRight=2310(,) # Move caret right one word extending selection to new caret position. fun void WordRightExtend=2311(,) # Move caret to first position on line. fun void Home=2312(,) # Move caret to first position on line extending selection to new caret position. fun void HomeExtend=2313(,) # Move caret to last position on line. fun void LineEnd=2314(,) # Move caret to last position on line extending selection to new caret position. fun void LineEndExtend=2315(,) # Move caret to first position in document. fun void DocumentStart=2316(,) # Move caret to first position in document extending selection to new caret position. fun void DocumentStartExtend=2317(,) # Move caret to last position in document. fun void DocumentEnd=2318(,) # Move caret to last position in document extending selection to new caret position. fun void DocumentEndExtend=2319(,) # Move caret one page up. fun void PageUp=2320(,) # Move caret one page up extending selection to new caret position. fun void PageUpExtend=2321(,) # Move caret one page down. fun void PageDown=2322(,) # Move caret one page down extending selection to new caret position. fun void PageDownExtend=2323(,) # Switch from insert to overtype mode or the reverse. fun void EditToggleOvertype=2324(,) # Cancel any modes such as call tip or auto-completion list display. fun void Cancel=2325(,) # Delete the selection or if no selection, the character before the caret. fun void DeleteBack=2326(,) # If selection is empty or all on one line replace the selection with a tab character. # If more than one line selected, indent the lines. fun void Tab=2327(,) # Dedent the selected lines. fun void BackTab=2328(,) # Insert a new line, may use a CRLF, CR or LF depending on EOL mode. fun void NewLine=2329(,) # Insert a Form Feed character. fun void FormFeed=2330(,) # Move caret to before first visible character on line. # If already there move to first character on line. fun void VCHome=2331(,) # Like VCHome but extending selection to new caret position. fun void VCHomeExtend=2332(,) # Magnify the displayed text by increasing the sizes by 1 point. fun void ZoomIn=2333(,) # Make the displayed text smaller by decreasing the sizes by 1 point. fun void ZoomOut=2334(,) # Delete the word to the left of the caret. fun void DelWordLeft=2335(,) # Delete the word to the right of the caret. fun void DelWordRight=2336(,) # Delete the word to the right of the caret, but not the trailing non-word characters. fun void DelWordRightEnd=2518(,) # Cut the line containing the caret. fun void LineCut=2337(,) # Delete the line containing the caret. fun void LineDelete=2338(,) # Switch the current line with the previous. fun void LineTranspose=2339(,) # Reverse order of selected lines. fun void LineReverse=2354(,) # Duplicate the current line. fun void LineDuplicate=2404(,) # Transform the selection to lower case. fun void LowerCase=2340(,) # Transform the selection to upper case. fun void UpperCase=2341(,) # Scroll the document down, keeping the caret visible. fun void LineScrollDown=2342(,) # Scroll the document up, keeping the caret visible. fun void LineScrollUp=2343(,) # Delete the selection or if no selection, the character before the caret. # Will not delete the character before at the start of a line. fun void DeleteBackNotLine=2344(,) # Move caret to first position on display line. fun void HomeDisplay=2345(,) # Move caret to first position on display line extending selection to # new caret position. fun void HomeDisplayExtend=2346(,) # Move caret to last position on display line. fun void LineEndDisplay=2347(,) # Move caret to last position on display line extending selection to new # caret position. fun void LineEndDisplayExtend=2348(,) # Like Home but when word-wrap is enabled goes first to start of display line # HomeDisplay, then to start of document line Home. fun void HomeWrap=2349(,) # Like HomeExtend but when word-wrap is enabled extends first to start of display line # HomeDisplayExtend, then to start of document line HomeExtend. fun void HomeWrapExtend=2450(,) # Like LineEnd but when word-wrap is enabled goes first to end of display line # LineEndDisplay, then to start of document line LineEnd. fun void LineEndWrap=2451(,) # Like LineEndExtend but when word-wrap is enabled extends first to end of display line # LineEndDisplayExtend, then to start of document line LineEndExtend. fun void LineEndWrapExtend=2452(,) # Like VCHome but when word-wrap is enabled goes first to start of display line # VCHomeDisplay, then behaves like VCHome. fun void VCHomeWrap=2453(,) # Like VCHomeExtend but when word-wrap is enabled extends first to start of display line # VCHomeDisplayExtend, then behaves like VCHomeExtend. fun void VCHomeWrapExtend=2454(,) # Copy the line containing the caret. fun void LineCopy=2455(,) # Move the caret inside current view if it's not there already. fun void MoveCaretInsideView=2401(,) # How many characters are on a line, including end of line characters? fun int LineLength=2350(int line,) # Highlight the characters at two positions. fun void BraceHighlight=2351(position posA, position posB) # Use specified indicator to highlight matching braces instead of changing their style. fun void BraceHighlightIndicator=2498(bool useSetting, int indicator) # Highlight the character at a position indicating there is no matching brace. fun void BraceBadLight=2352(position pos,) # Use specified indicator to highlight non matching brace instead of changing its style. fun void BraceBadLightIndicator=2499(bool useSetting, int indicator) # Find the position of a matching brace or INVALID_POSITION if no match. # The maxReStyle must be 0 for now. It may be defined in a future release. fun position BraceMatch=2353(position pos, int maxReStyle) # Are the end of line characters visible? get bool GetViewEOL=2355(,) # Make the end of line characters visible or invisible. set void SetViewEOL=2356(bool visible,) # Retrieve a pointer to the document object. get int GetDocPointer=2357(,) # Change the document object used. set void SetDocPointer=2358(, int doc) # Set which document modification events are sent to the container. set void SetModEventMask=2359(int eventMask,) enu EdgeVisualStyle=EDGE_ val EDGE_NONE=0 val EDGE_LINE=1 val EDGE_BACKGROUND=2 val EDGE_MULTILINE=3 # Retrieve the column number which text should be kept within. get int GetEdgeColumn=2360(,) # Set the column number of the edge. # If text goes past the edge then it is highlighted. set void SetEdgeColumn=2361(int column,) # Retrieve the edge highlight mode. get int GetEdgeMode=2362(,) # The edge may be displayed by a line (EDGE_LINE/EDGE_MULTILINE) or by highlighting text that # goes beyond it (EDGE_BACKGROUND) or not displayed at all (EDGE_NONE). set void SetEdgeMode=2363(int edgeMode,) # Retrieve the colour used in edge indication. get colour GetEdgeColour=2364(,) # Change the colour used in edge indication. set void SetEdgeColour=2365(colour edgeColour,) # Add a new vertical edge to the view. fun void MultiEdgeAddLine=2694(int column, colour edgeColour) # Clear all vertical edges. fun void MultiEdgeClearAll=2695(,) # Sets the current caret position to be the search anchor. fun void SearchAnchor=2366(,) # Find some text starting at the search anchor. # Does not ensure the selection is visible. fun int SearchNext=2367(int searchFlags, string text) # Find some text starting at the search anchor and moving backwards. # Does not ensure the selection is visible. fun int SearchPrev=2368(int searchFlags, string text) # Retrieves the number of lines completely visible. get int LinesOnScreen=2370(,) enu PopUp=SC_POPUP_ val SC_POPUP_NEVER=0 val SC_POPUP_ALL=1 val SC_POPUP_TEXT=2 # Set whether a pop up menu is displayed automatically when the user presses # the wrong mouse button on certain areas. fun void UsePopUp=2371(int popUpMode,) # Is the selection rectangular? The alternative is the more common stream selection. get bool SelectionIsRectangle=2372(,) # Set the zoom level. This number of points is added to the size of all fonts. # It may be positive to magnify or negative to reduce. set void SetZoom=2373(int zoomInPoints,) # Retrieve the zoom level. get int GetZoom=2374(,) enu DocumentOption=SC_DOCUMENTOPTION_ val SC_DOCUMENTOPTION_DEFAULT=0 val SC_DOCUMENTOPTION_STYLES_NONE=0x1 val SC_DOCUMENTOPTION_TEXT_LARGE=0x100 # Create a new document object. # Starts with reference count of 1 and not selected into editor. fun int CreateDocument=2375(int bytes, int documentOptions) # Extend life of document. fun void AddRefDocument=2376(, int doc) # Release a reference to the document, deleting document if it fades to black. fun void ReleaseDocument=2377(, int doc) # Get which document options are set. get int GetDocumentOptions=2379(,) # Get which document modification events are sent to the container. get int GetModEventMask=2378(,) # Set whether command events are sent to the container. set void SetCommandEvents=2717(bool commandEvents,) # Get whether command events are sent to the container. get bool GetCommandEvents=2718(,) # Change internal focus flag. set void SetFocus=2380(bool focus,) # Get internal focus flag. get bool GetFocus=2381(,) enu Status=SC_STATUS_ val SC_STATUS_OK=0 val SC_STATUS_FAILURE=1 val SC_STATUS_BADALLOC=2 val SC_STATUS_WARN_START=1000 val SC_STATUS_WARN_REGEX=1001 # Change error status - 0 = OK. set void SetStatus=2382(int status,) # Get error status. get int GetStatus=2383(,) # Set whether the mouse is captured when its button is pressed. set void SetMouseDownCaptures=2384(bool captures,) # Get whether mouse gets captured. get bool GetMouseDownCaptures=2385(,) # Set whether the mouse wheel can be active outside the window. set void SetMouseWheelCaptures=2696(bool captures,) # Get whether mouse wheel can be active outside the window. get bool GetMouseWheelCaptures=2697(,) enu CursorShape=SC_CURSOR val SC_CURSORNORMAL=-1 val SC_CURSORARROW=2 val SC_CURSORWAIT=4 val SC_CURSORREVERSEARROW=7 # Sets the cursor to one of the SC_CURSOR* values. set void SetCursor=2386(int cursorType,) # Get cursor type. get int GetCursor=2387(,) # Change the way control characters are displayed: # If symbol is < 32, keep the drawn way, else, use the given character. set void SetControlCharSymbol=2388(int symbol,) # Get the way control characters are displayed. get int GetControlCharSymbol=2389(,) # Move to the previous change in capitalisation. fun void WordPartLeft=2390(,) # Move to the previous change in capitalisation extending selection # to new caret position. fun void WordPartLeftExtend=2391(,) # Move to the change next in capitalisation. fun void WordPartRight=2392(,) # Move to the next change in capitalisation extending selection # to new caret position. fun void WordPartRightExtend=2393(,) # Constants for use with SetVisiblePolicy, similar to SetCaretPolicy. enu VisiblePolicy=VISIBLE_ val VISIBLE_SLOP=0x01 val VISIBLE_STRICT=0x04 # Set the way the display area is determined when a particular line # is to be moved to by Find, FindNext, GotoLine, etc. fun void SetVisiblePolicy=2394(int visiblePolicy, int visibleSlop) # Delete back from the current position to the start of the line. fun void DelLineLeft=2395(,) # Delete forwards from the current position to the end of the line. fun void DelLineRight=2396(,) # Set the xOffset (ie, horizontal scroll position). set void SetXOffset=2397(int xOffset,) # Get the xOffset (ie, horizontal scroll position). get int GetXOffset=2398(,) # Set the last x chosen value to be the caret x position. fun void ChooseCaretX=2399(,) # Set the focus to this Scintilla widget. fun void GrabFocus=2400(,) enu CaretPolicy=CARET_ # Caret policy, used by SetXCaretPolicy and SetYCaretPolicy. # If CARET_SLOP is set, we can define a slop value: caretSlop. # This value defines an unwanted zone (UZ) where the caret is... unwanted. # This zone is defined as a number of pixels near the vertical margins, # and as a number of lines near the horizontal margins. # By keeping the caret away from the edges, it is seen within its context, # so it is likely that the identifier that the caret is on can be completely seen, # and that the current line is seen with some of the lines following it which are # often dependent on that line. val CARET_SLOP=0x01 # If CARET_STRICT is set, the policy is enforced... strictly. # The caret is centred on the display if slop is not set, # and cannot go in the UZ if slop is set. val CARET_STRICT=0x04 # If CARET_JUMPS is set, the display is moved more energetically # so the caret can move in the same direction longer before the policy is applied again. val CARET_JUMPS=0x10 # If CARET_EVEN is not set, instead of having symmetrical UZs, # the left and bottom UZs are extended up to right and top UZs respectively. # This way, we favour the displaying of useful information: the beginning of lines, # where most code reside, and the lines after the caret, eg. the body of a function. val CARET_EVEN=0x08 # Set the way the caret is kept visible when going sideways. # The exclusion zone is given in pixels. fun void SetXCaretPolicy=2402(int caretPolicy, int caretSlop) # Set the way the line the caret is on is kept visible. # The exclusion zone is given in lines. fun void SetYCaretPolicy=2403(int caretPolicy, int caretSlop) # Set printing to line wrapped (SC_WRAP_WORD) or not line wrapped (SC_WRAP_NONE). set void SetPrintWrapMode=2406(int wrapMode,) # Is printing line wrapped? get int GetPrintWrapMode=2407(,) # Set a fore colour for active hotspots. set void SetHotspotActiveFore=2410(bool useSetting, colour fore) # Get the fore colour for active hotspots. get colour GetHotspotActiveFore=2494(,) # Set a back colour for active hotspots. set void SetHotspotActiveBack=2411(bool useSetting, colour back) # Get the back colour for active hotspots. get colour GetHotspotActiveBack=2495(,) # Enable / Disable underlining active hotspots. set void SetHotspotActiveUnderline=2412(bool underline,) # Get whether underlining for active hotspots. get bool GetHotspotActiveUnderline=2496(,) # Limit hotspots to single line so hotspots on two lines don't merge. set void SetHotspotSingleLine=2421(bool singleLine,) # Get the HotspotSingleLine property get bool GetHotspotSingleLine=2497(,) # Move caret down one paragraph (delimited by empty lines). fun void ParaDown=2413(,) # Extend selection down one paragraph (delimited by empty lines). fun void ParaDownExtend=2414(,) # Move caret up one paragraph (delimited by empty lines). fun void ParaUp=2415(,) # Extend selection up one paragraph (delimited by empty lines). fun void ParaUpExtend=2416(,) # Given a valid document position, return the previous position taking code # page into account. Returns 0 if passed 0. fun position PositionBefore=2417(position pos,) # Given a valid document position, return the next position taking code # page into account. Maximum value returned is the last position in the document. fun position PositionAfter=2418(position pos,) # Given a valid document position, return a position that differs in a number # of characters. Returned value is always between 0 and last position in document. fun position PositionRelative=2670(position pos, int relative) # Given a valid document position, return a position that differs in a number # of UTF-16 code units. Returned value is always between 0 and last position in document. # The result may point half way (2 bytes) inside a non-BMP character. fun position PositionRelativeCodeUnits=2716(position pos, int relative) # Copy a range of text to the clipboard. Positions are clipped into the document. fun void CopyRange=2419(position start, position end) # Copy argument text to the clipboard. fun void CopyText=2420(int length, string text) enu SelectionMode=SC_SEL_ val SC_SEL_STREAM=0 val SC_SEL_RECTANGLE=1 val SC_SEL_LINES=2 val SC_SEL_THIN=3 # Set the selection mode to stream (SC_SEL_STREAM) or rectangular (SC_SEL_RECTANGLE/SC_SEL_THIN) or # by lines (SC_SEL_LINES). set void SetSelectionMode=2422(int selectionMode,) # Get the mode of the current selection. get int GetSelectionMode=2423(,) # Get whether or not regular caret moves will extend or reduce the selection. get bool GetMoveExtendsSelection=2706(,) # Retrieve the position of the start of the selection at the given line (INVALID_POSITION if no selection on this line). fun position GetLineSelStartPosition=2424(int line,) # Retrieve the position of the end of the selection at the given line (INVALID_POSITION if no selection on this line). fun position GetLineSelEndPosition=2425(int line,) ## RectExtended rectangular selection moves # Move caret down one line, extending rectangular selection to new caret position. fun void LineDownRectExtend=2426(,) # Move caret up one line, extending rectangular selection to new caret position. fun void LineUpRectExtend=2427(,) # Move caret left one character, extending rectangular selection to new caret position. fun void CharLeftRectExtend=2428(,) # Move caret right one character, extending rectangular selection to new caret position. fun void CharRightRectExtend=2429(,) # Move caret to first position on line, extending rectangular selection to new caret position. fun void HomeRectExtend=2430(,) # Move caret to before first visible character on line. # If already there move to first character on line. # In either case, extend rectangular selection to new caret position. fun void VCHomeRectExtend=2431(,) # Move caret to last position on line, extending rectangular selection to new caret position. fun void LineEndRectExtend=2432(,) # Move caret one page up, extending rectangular selection to new caret position. fun void PageUpRectExtend=2433(,) # Move caret one page down, extending rectangular selection to new caret position. fun void PageDownRectExtend=2434(,) # Move caret to top of page, or one page up if already at top of page. fun void StutteredPageUp=2435(,) # Move caret to top of page, or one page up if already at top of page, extending selection to new caret position. fun void StutteredPageUpExtend=2436(,) # Move caret to bottom of page, or one page down if already at bottom of page. fun void StutteredPageDown=2437(,) # Move caret to bottom of page, or one page down if already at bottom of page, extending selection to new caret position. fun void StutteredPageDownExtend=2438(,) # Move caret left one word, position cursor at end of word. fun void WordLeftEnd=2439(,) # Move caret left one word, position cursor at end of word, extending selection to new caret position. fun void WordLeftEndExtend=2440(,) # Move caret right one word, position cursor at end of word. fun void WordRightEnd=2441(,) # Move caret right one word, position cursor at end of word, extending selection to new caret position. fun void WordRightEndExtend=2442(,) # Set the set of characters making up whitespace for when moving or selecting by word. # Should be called after SetWordChars. set void SetWhitespaceChars=2443(, string characters) # Get the set of characters making up whitespace for when moving or selecting by word. get int GetWhitespaceChars=2647(, stringresult characters) # Set the set of characters making up punctuation characters # Should be called after SetWordChars. set void SetPunctuationChars=2648(, string characters) # Get the set of characters making up punctuation characters get int GetPunctuationChars=2649(, stringresult characters) # Reset the set of characters for whitespace and word characters to the defaults. fun void SetCharsDefault=2444(,) # Get currently selected item position in the auto-completion list get int AutoCGetCurrent=2445(,) # Get currently selected item text in the auto-completion list # Returns the length of the item text # Result is NUL-terminated. get int AutoCGetCurrentText=2610(, stringresult text) enu CaseInsensitiveBehaviour=SC_CASEINSENSITIVEBEHAVIOUR_ val SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE=0 val SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE=1 # Set auto-completion case insensitive behaviour to either prefer case-sensitive matches or have no preference. set void AutoCSetCaseInsensitiveBehaviour=2634(int behaviour,) # Get auto-completion case insensitive behaviour. get int AutoCGetCaseInsensitiveBehaviour=2635(,) enu MultiAutoComplete=SC_MULTIAUTOC_ val SC_MULTIAUTOC_ONCE=0 val SC_MULTIAUTOC_EACH=1 # Change the effect of autocompleting when there are multiple selections. set void AutoCSetMulti=2636(int multi,) # Retrieve the effect of autocompleting when there are multiple selections. get int AutoCGetMulti=2637(,) enu Ordering=SC_ORDER_ val SC_ORDER_PRESORTED=0 val SC_ORDER_PERFORMSORT=1 val SC_ORDER_CUSTOM=2 # Set the way autocompletion lists are ordered. set void AutoCSetOrder=2660(int order,) # Get the way autocompletion lists are ordered. get int AutoCGetOrder=2661(,) # Enlarge the document to a particular size of text bytes. fun void Allocate=2446(int bytes,) # Returns the target converted to UTF8. # Return the length in bytes. fun int TargetAsUTF8=2447(, stringresult s) # Set the length of the utf8 argument for calling EncodedFromUTF8. # Set to -1 and the string will be measured to the first nul. fun void SetLengthForEncode=2448(int bytes,) # Translates a UTF8 string into the document encoding. # Return the length of the result in bytes. # On error return 0. fun int EncodedFromUTF8=2449(string utf8, stringresult encoded) # Find the position of a column on a line taking into account tabs and # multi-byte characters. If beyond end of line, return line end position. fun int FindColumn=2456(int line, int column) # Can the caret preferred x position only be changed by explicit movement commands? get int GetCaretSticky=2457(,) # Stop the caret preferred x position changing when the user types. set void SetCaretSticky=2458(int useCaretStickyBehaviour,) enu CaretSticky=SC_CARETSTICKY_ val SC_CARETSTICKY_OFF=0 val SC_CARETSTICKY_ON=1 val SC_CARETSTICKY_WHITESPACE=2 # Switch between sticky and non-sticky: meant to be bound to a key. fun void ToggleCaretSticky=2459(,) # Enable/Disable convert-on-paste for line endings set void SetPasteConvertEndings=2467(bool convert,) # Get convert-on-paste setting get bool GetPasteConvertEndings=2468(,) # Duplicate the selection. If selection empty duplicate the line containing the caret. fun void SelectionDuplicate=2469(,) enu Alpha=SC_ALPHA_ val SC_ALPHA_TRANSPARENT=0 val SC_ALPHA_OPAQUE=255 val SC_ALPHA_NOALPHA=256 # Set background alpha of the caret line. set void SetCaretLineBackAlpha=2470(int alpha,) # Get the background alpha of the caret line. get int GetCaretLineBackAlpha=2471(,) enu CaretStyle=CARETSTYLE_ val CARETSTYLE_INVISIBLE=0 val CARETSTYLE_LINE=1 val CARETSTYLE_BLOCK=2 # Set the style of the caret to be drawn. set void SetCaretStyle=2512(int caretStyle,) # Returns the current style of the caret. get int GetCaretStyle=2513(,) # Set the indicator used for IndicatorFillRange and IndicatorClearRange set void SetIndicatorCurrent=2500(int indicator,) # Get the current indicator get int GetIndicatorCurrent=2501(,) # Set the value used for IndicatorFillRange set void SetIndicatorValue=2502(int value,) # Get the current indicator value get int GetIndicatorValue=2503(,) # Turn a indicator on over a range. fun void IndicatorFillRange=2504(position start, int lengthFill) # Turn a indicator off over a range. fun void IndicatorClearRange=2505(position start, int lengthClear) # Are any indicators present at pos? fun int IndicatorAllOnFor=2506(position pos,) # What value does a particular indicator have at a position? fun int IndicatorValueAt=2507(int indicator, position pos) # Where does a particular indicator start? fun int IndicatorStart=2508(int indicator, position pos) # Where does a particular indicator end? fun int IndicatorEnd=2509(int indicator, position pos) # Set number of entries in position cache set void SetPositionCache=2514(int size,) # How many entries are allocated to the position cache? get int GetPositionCache=2515(,) # Copy the selection, if selection empty copy the line with the caret fun void CopyAllowLine=2519(,) # Compact the document buffer and return a read-only pointer to the # characters in the document. get int GetCharacterPointer=2520(,) # Return a read-only pointer to a range of characters in the document. # May move the gap so that the range is contiguous, but will only move up # to lengthRange bytes. get int GetRangePointer=2643(position start, int lengthRange) # Return a position which, to avoid performance costs, should not be within # the range of a call to GetRangePointer. get position GetGapPosition=2644(,) # Set the alpha fill colour of the given indicator. set void IndicSetAlpha=2523(int indicator, int alpha) # Get the alpha fill colour of the given indicator. get int IndicGetAlpha=2524(int indicator,) # Set the alpha outline colour of the given indicator. set void IndicSetOutlineAlpha=2558(int indicator, int alpha) # Get the alpha outline colour of the given indicator. get int IndicGetOutlineAlpha=2559(int indicator,) # Set extra ascent for each line set void SetExtraAscent=2525(int extraAscent,) # Get extra ascent for each line get int GetExtraAscent=2526(,) # Set extra descent for each line set void SetExtraDescent=2527(int extraDescent,) # Get extra descent for each line get int GetExtraDescent=2528(,) # Which symbol was defined for markerNumber with MarkerDefine fun int MarkerSymbolDefined=2529(int markerNumber,) # Set the text in the text margin for a line set void MarginSetText=2530(int line, string text) # Get the text in the text margin for a line get int MarginGetText=2531(int line, stringresult text) # Set the style number for the text margin for a line set void MarginSetStyle=2532(int line, int style) # Get the style number for the text margin for a line get int MarginGetStyle=2533(int line,) # Set the style in the text margin for a line set void MarginSetStyles=2534(int line, string styles) # Get the styles in the text margin for a line get int MarginGetStyles=2535(int line, stringresult styles) # Clear the margin text on all lines fun void MarginTextClearAll=2536(,) # Get the start of the range of style numbers used for margin text set void MarginSetStyleOffset=2537(int style,) # Get the start of the range of style numbers used for margin text get int MarginGetStyleOffset=2538(,) enu MarginOption=SC_MARGINOPTION_ val SC_MARGINOPTION_NONE=0 val SC_MARGINOPTION_SUBLINESELECT=1 # Set the margin options. set void SetMarginOptions=2539(int marginOptions,) # Get the margin options. get int GetMarginOptions=2557(,) # Set the annotation text for a line set void AnnotationSetText=2540(int line, string text) # Get the annotation text for a line get int AnnotationGetText=2541(int line, stringresult text) # Set the style number for the annotations for a line set void AnnotationSetStyle=2542(int line, int style) # Get the style number for the annotations for a line get int AnnotationGetStyle=2543(int line,) # Set the annotation styles for a line set void AnnotationSetStyles=2544(int line, string styles) # Get the annotation styles for a line get int AnnotationGetStyles=2545(int line, stringresult styles) # Get the number of annotation lines for a line get int AnnotationGetLines=2546(int line,) # Clear the annotations from all lines fun void AnnotationClearAll=2547(,) enu AnnotationVisible=ANNOTATION_ val ANNOTATION_HIDDEN=0 val ANNOTATION_STANDARD=1 val ANNOTATION_BOXED=2 val ANNOTATION_INDENTED=3 # Set the visibility for the annotations for a view set void AnnotationSetVisible=2548(int visible,) # Get the visibility for the annotations for a view get int AnnotationGetVisible=2549(,) # Get the start of the range of style numbers used for annotations set void AnnotationSetStyleOffset=2550(int style,) # Get the start of the range of style numbers used for annotations get int AnnotationGetStyleOffset=2551(,) # Release all extended (>255) style numbers fun void ReleaseAllExtendedStyles=2552(,) # Allocate some extended (>255) style numbers and return the start of the range fun int AllocateExtendedStyles=2553(int numberStyles,) val UNDO_MAY_COALESCE=1 # Add a container action to the undo stack fun void AddUndoAction=2560(int token, int flags) # Find the position of a character from a point within the window. fun position CharPositionFromPoint=2561(int x, int y) # Find the position of a character from a point within the window. # Return INVALID_POSITION if not close to text. fun position CharPositionFromPointClose=2562(int x, int y) # Set whether switching to rectangular mode while selecting with the mouse is allowed. set void SetMouseSelectionRectangularSwitch=2668(bool mouseSelectionRectangularSwitch,) # Whether switching to rectangular mode while selecting with the mouse is allowed. get bool GetMouseSelectionRectangularSwitch=2669(,) # Set whether multiple selections can be made set void SetMultipleSelection=2563(bool multipleSelection,) # Whether multiple selections can be made get bool GetMultipleSelection=2564(,) # Set whether typing can be performed into multiple selections set void SetAdditionalSelectionTyping=2565(bool additionalSelectionTyping,) # Whether typing can be performed into multiple selections get bool GetAdditionalSelectionTyping=2566(,) # Set whether additional carets will blink set void SetAdditionalCaretsBlink=2567(bool additionalCaretsBlink,) # Whether additional carets will blink get bool GetAdditionalCaretsBlink=2568(,) # Set whether additional carets are visible set void SetAdditionalCaretsVisible=2608(bool additionalCaretsVisible,) # Whether additional carets are visible get bool GetAdditionalCaretsVisible=2609(,) # How many selections are there? get int GetSelections=2570(,) # Is every selected range empty? get bool GetSelectionEmpty=2650(,) # Clear selections to a single empty stream selection fun void ClearSelections=2571(,) # Set a simple selection fun void SetSelection=2572(position caret, position anchor) # Add a selection fun void AddSelection=2573(position caret, position anchor) # Drop one selection fun void DropSelectionN=2671(int selection,) # Set the main selection set void SetMainSelection=2574(int selection,) # Which selection is the main selection get int GetMainSelection=2575(,) # Set the caret position of the nth selection. set void SetSelectionNCaret=2576(int selection, position caret) # Return the caret position of the nth selection. get position GetSelectionNCaret=2577(int selection,) # Set the anchor position of the nth selection. set void SetSelectionNAnchor=2578(int selection, position anchor) # Return the anchor position of the nth selection. get position GetSelectionNAnchor=2579(int selection,) # Set the virtual space of the caret of the nth selection. set void SetSelectionNCaretVirtualSpace=2580(int selection, int space) # Return the virtual space of the caret of the nth selection. get int GetSelectionNCaretVirtualSpace=2581(int selection,) # Set the virtual space of the anchor of the nth selection. set void SetSelectionNAnchorVirtualSpace=2582(int selection, int space) # Return the virtual space of the anchor of the nth selection. get int GetSelectionNAnchorVirtualSpace=2583(int selection,) # Sets the position that starts the selection - this becomes the anchor. set void SetSelectionNStart=2584(int selection, position anchor) # Returns the position at the start of the selection. get position GetSelectionNStart=2585(int selection,) # Sets the position that ends the selection - this becomes the currentPosition. set void SetSelectionNEnd=2586(int selection, position caret) # Returns the position at the end of the selection. get position GetSelectionNEnd=2587(int selection,) # Set the caret position of the rectangular selection. set void SetRectangularSelectionCaret=2588(position caret,) # Return the caret position of the rectangular selection. get position GetRectangularSelectionCaret=2589(,) # Set the anchor position of the rectangular selection. set void SetRectangularSelectionAnchor=2590(position anchor,) # Return the anchor position of the rectangular selection. get position GetRectangularSelectionAnchor=2591(,) # Set the virtual space of the caret of the rectangular selection. set void SetRectangularSelectionCaretVirtualSpace=2592(int space,) # Return the virtual space of the caret of the rectangular selection. get int GetRectangularSelectionCaretVirtualSpace=2593(,) # Set the virtual space of the anchor of the rectangular selection. set void SetRectangularSelectionAnchorVirtualSpace=2594(int space,) # Return the virtual space of the anchor of the rectangular selection. get int GetRectangularSelectionAnchorVirtualSpace=2595(,) enu VirtualSpace=SCVS_ val SCVS_NONE=0 val SCVS_RECTANGULARSELECTION=1 val SCVS_USERACCESSIBLE=2 val SCVS_NOWRAPLINESTART=4 # Set options for virtual space behaviour. set void SetVirtualSpaceOptions=2596(int virtualSpaceOptions,) # Return options for virtual space behaviour. get int GetVirtualSpaceOptions=2597(,) # On GTK+, allow selecting the modifier key to use for mouse-based # rectangular selection. Often the window manager requires Alt+Mouse Drag # for moving windows. # Valid values are SCMOD_CTRL(default), SCMOD_ALT, or SCMOD_SUPER. set void SetRectangularSelectionModifier=2598(int modifier,) # Get the modifier key used for rectangular selection. get int GetRectangularSelectionModifier=2599(,) # Set the foreground colour of additional selections. # Must have previously called SetSelFore with non-zero first argument for this to have an effect. set void SetAdditionalSelFore=2600(colour fore,) # Set the background colour of additional selections. # Must have previously called SetSelBack with non-zero first argument for this to have an effect. set void SetAdditionalSelBack=2601(colour back,) # Set the alpha of the selection. set void SetAdditionalSelAlpha=2602(int alpha,) # Get the alpha of the selection. get int GetAdditionalSelAlpha=2603(,) # Set the foreground colour of additional carets. set void SetAdditionalCaretFore=2604(colour fore,) # Get the foreground colour of additional carets. get colour GetAdditionalCaretFore=2605(,) # Set the main selection to the next selection. fun void RotateSelection=2606(,) # Swap that caret and anchor of the main selection. fun void SwapMainAnchorCaret=2607(,) # Add the next occurrence of the main selection to the set of selections as main. # If the current selection is empty then select word around caret. fun void MultipleSelectAddNext=2688(,) # Add each occurrence of the main selection in the target to the set of selections. # If the current selection is empty then select word around caret. fun void MultipleSelectAddEach=2689(,) # Indicate that the internal state of a lexer has changed over a range and therefore # there may be a need to redraw. fun int ChangeLexerState=2617(position start, position end) # Find the next line at or after lineStart that is a contracted fold header line. # Return -1 when no more lines. fun int ContractedFoldNext=2618(int lineStart,) # Centre current line in window. fun void VerticalCentreCaret=2619(,) # Move the selected lines up one line, shifting the line above after the selection fun void MoveSelectedLinesUp=2620(,) # Move the selected lines down one line, shifting the line below before the selection fun void MoveSelectedLinesDown=2621(,) # Set the identifier reported as idFrom in notification messages. set void SetIdentifier=2622(int identifier,) # Get the identifier. get int GetIdentifier=2623(,) # Set the width for future RGBA image data. set void RGBAImageSetWidth=2624(int width,) # Set the height for future RGBA image data. set void RGBAImageSetHeight=2625(int height,) # Set the scale factor in percent for future RGBA image data. set void RGBAImageSetScale=2651(int scalePercent,) # Define a marker from RGBA data. # It has the width and height from RGBAImageSetWidth/Height fun void MarkerDefineRGBAImage=2626(int markerNumber, string pixels) # Register an RGBA image for use in autocompletion lists. # It has the width and height from RGBAImageSetWidth/Height fun void RegisterRGBAImage=2627(int type, string pixels) # Scroll to start of document. fun void ScrollToStart=2628(,) # Scroll to end of document. fun void ScrollToEnd=2629(,) enu Technology=SC_TECHNOLOGY_ val SC_TECHNOLOGY_DEFAULT=0 val SC_TECHNOLOGY_DIRECTWRITE=1 val SC_TECHNOLOGY_DIRECTWRITERETAIN=2 val SC_TECHNOLOGY_DIRECTWRITEDC=3 # Set the technology used. set void SetTechnology=2630(int technology,) # Get the tech. get int GetTechnology=2631(,) # Create an ILoader*. fun int CreateLoader=2632(int bytes, int documentOptions) # On OS X, show a find indicator. fun void FindIndicatorShow=2640(position start, position end) # On OS X, flash a find indicator, then fade out. fun void FindIndicatorFlash=2641(position start, position end) # On OS X, hide the find indicator. fun void FindIndicatorHide=2642(,) # Move caret to before first visible character on display line. # If already there move to first character on display line. fun void VCHomeDisplay=2652(,) # Like VCHomeDisplay but extending selection to new caret position. fun void VCHomeDisplayExtend=2653(,) # Is the caret line always visible? get bool GetCaretLineVisibleAlways=2654(,) # Sets the caret line to always visible. set void SetCaretLineVisibleAlways=2655(bool alwaysVisible,) # Line end types which may be used in addition to LF, CR, and CRLF # SC_LINE_END_TYPE_UNICODE includes U+2028 Line Separator, # U+2029 Paragraph Separator, and U+0085 Next Line enu LineEndType=SC_LINE_END_TYPE_ val SC_LINE_END_TYPE_DEFAULT=0 val SC_LINE_END_TYPE_UNICODE=1 # Set the line end types that the application wants to use. May not be used if incompatible with lexer or encoding. set void SetLineEndTypesAllowed=2656(int lineEndBitSet,) # Get the line end types currently allowed. get int GetLineEndTypesAllowed=2657(,) # Get the line end types currently recognised. May be a subset of the allowed types due to lexer limitation. get int GetLineEndTypesActive=2658(,) # Set the way a character is drawn. set void SetRepresentation=2665(string encodedCharacter, string representation) # Set the way a character is drawn. # Result is NUL-terminated. get int GetRepresentation=2666(string encodedCharacter, stringresult representation) # Remove a character representation. fun void ClearRepresentation=2667(string encodedCharacter,) # Start notifying the container of all key presses and commands. fun void StartRecord=3001(,) # Stop notifying the container of all key presses and commands. fun void StopRecord=3002(,) # Set the lexing language of the document. set void SetLexer=4001(int lexer,) # Retrieve the lexing language of the document. get int GetLexer=4002(,) # Colourise a segment of the document using the current lexing language. fun void Colourise=4003(position start, position end) # Set up a value that may be used by a lexer for some optional feature. set void SetProperty=4004(string key, string value) # Maximum value of keywordSet parameter of SetKeyWords. val KEYWORDSET_MAX=8 # Set up the key words used by the lexer. set void SetKeyWords=4005(int keyWordSet, string keyWords) # Set the lexing language of the document based on string name. set void SetLexerLanguage=4006(, string language) # Load a lexer library (dll / so). fun void LoadLexerLibrary=4007(, string path) # Retrieve a "property" value previously set with SetProperty. # Result is NUL-terminated. get int GetProperty=4008(string key, stringresult value) # Retrieve a "property" value previously set with SetProperty, # with "$()" variable replacement on returned buffer. # Result is NUL-terminated. get int GetPropertyExpanded=4009(string key, stringresult value) # Retrieve a "property" value previously set with SetProperty, # interpreted as an int AFTER any "$()" variable replacement. get int GetPropertyInt=4010(string key, int defaultValue) # Retrieve the name of the lexer. # Return the length of the text. # Result is NUL-terminated. get int GetLexerLanguage=4012(, stringresult language) # For private communication between an application and a known lexer. fun int PrivateLexerCall=4013(int operation, int pointer) # Retrieve a '\n' separated list of properties understood by the current lexer. # Result is NUL-terminated. fun int PropertyNames=4014(, stringresult names) enu TypeProperty=SC_TYPE_ val SC_TYPE_BOOLEAN=0 val SC_TYPE_INTEGER=1 val SC_TYPE_STRING=2 # Retrieve the type of a property. fun int PropertyType=4015(string name,) # Describe a property. # Result is NUL-terminated. fun int DescribeProperty=4016(string name, stringresult description) # Retrieve a '\n' separated list of descriptions of the keyword sets understood by the current lexer. # Result is NUL-terminated. fun int DescribeKeyWordSets=4017(, stringresult descriptions) # Bit set of LineEndType enumertion for which line ends beyond the standard # LF, CR, and CRLF are supported by the lexer. get int GetLineEndTypesSupported=4018(,) # Allocate a set of sub styles for a particular base style, returning start of range fun int AllocateSubStyles=4020(int styleBase, int numberStyles) # The starting style number for the sub styles associated with a base style get int GetSubStylesStart=4021(int styleBase,) # The number of sub styles associated with a base style get int GetSubStylesLength=4022(int styleBase,) # For a sub style, return the base style, else return the argument. get int GetStyleFromSubStyle=4027(int subStyle,) # For a secondary style, return the primary style, else return the argument. get int GetPrimaryStyleFromStyle=4028(int style,) # Free allocated sub styles fun void FreeSubStyles=4023(,) # Set the identifiers that are shown in a particular style set void SetIdentifiers=4024(int style, string identifiers) # Where styles are duplicated by a feature such as active/inactive code # return the distance between the two types. get int DistanceToSecondaryStyles=4025(,) # Get the set of base styles that can be extended with sub styles # Result is NUL-terminated. get int GetSubStyleBases=4026(, stringresult styles) # Retrieve the number of named styles for the lexer. get int GetNamedStyles=4029(,) # Retrieve the name of a style. # Result is NUL-terminated. fun int NameOfStyle=4030(int style, stringresult name) # Retrieve a ' ' separated list of style tags like "literal quoted string". # Result is NUL-terminated. fun int TagsOfStyle=4031(int style, stringresult tags) # Retrieve a description of a style. # Result is NUL-terminated. fun int DescriptionOfStyle=4032(int style, stringresult description) # Notifications # Type of modification and the action which caused the modification. # These are defined as a bit mask to make it easy to specify which notifications are wanted. # One bit is set from each of SC_MOD_* and SC_PERFORMED_*. enu ModificationFlags=SC_MOD_ SC_PERFORMED_ SC_MULTISTEPUNDOREDO SC_LASTSTEPINUNDOREDO SC_MULTILINEUNDOREDO SC_STARTACTION SC_MODEVENTMASKALL val SC_MOD_INSERTTEXT=0x1 val SC_MOD_DELETETEXT=0x2 val SC_MOD_CHANGESTYLE=0x4 val SC_MOD_CHANGEFOLD=0x8 val SC_PERFORMED_USER=0x10 val SC_PERFORMED_UNDO=0x20 val SC_PERFORMED_REDO=0x40 val SC_MULTISTEPUNDOREDO=0x80 val SC_LASTSTEPINUNDOREDO=0x100 val SC_MOD_CHANGEMARKER=0x200 val SC_MOD_BEFOREINSERT=0x400 val SC_MOD_BEFOREDELETE=0x800 val SC_MULTILINEUNDOREDO=0x1000 val SC_STARTACTION=0x2000 val SC_MOD_CHANGEINDICATOR=0x4000 val SC_MOD_CHANGELINESTATE=0x8000 val SC_MOD_CHANGEMARGIN=0x10000 val SC_MOD_CHANGEANNOTATION=0x20000 val SC_MOD_CONTAINER=0x40000 val SC_MOD_LEXERSTATE=0x80000 val SC_MOD_INSERTCHECK=0x100000 val SC_MOD_CHANGETABSTOPS=0x200000 val SC_MODEVENTMASKALL=0x3FFFFF enu Update=SC_UPDATE_ val SC_UPDATE_CONTENT=0x1 val SC_UPDATE_SELECTION=0x2 val SC_UPDATE_V_SCROLL=0x4 val SC_UPDATE_H_SCROLL=0x8 # For compatibility, these go through the COMMAND notification rather than NOTIFY # and should have had exactly the same values as the EN_* constants. # Unfortunately the SETFOCUS and KILLFOCUS are flipped over from EN_* # As clients depend on these constants, this will not be changed. val SCEN_CHANGE=768 val SCEN_SETFOCUS=512 val SCEN_KILLFOCUS=256 # Symbolic key codes and modifier flags. # ASCII and other printable characters below 256. # Extended keys above 300. enu Keys=SCK_ val SCK_DOWN=300 val SCK_UP=301 val SCK_LEFT=302 val SCK_RIGHT=303 val SCK_HOME=304 val SCK_END=305 val SCK_PRIOR=306 val SCK_NEXT=307 val SCK_DELETE=308 val SCK_INSERT=309 val SCK_ESCAPE=7 val SCK_BACK=8 val SCK_TAB=9 val SCK_RETURN=13 val SCK_ADD=310 val SCK_SUBTRACT=311 val SCK_DIVIDE=312 val SCK_WIN=313 val SCK_RWIN=314 val SCK_MENU=315 enu KeyMod=SCMOD_ val SCMOD_NORM=0 val SCMOD_SHIFT=1 val SCMOD_CTRL=2 val SCMOD_ALT=4 val SCMOD_SUPER=8 val SCMOD_META=16 enu CompletionMethods=SC_AC_ val SC_AC_FILLUP=1 val SC_AC_DOUBLECLICK=2 val SC_AC_TAB=3 val SC_AC_NEWLINE=4 val SC_AC_COMMAND=5 ################################################ # For SciLexer.h enu Lexer=SCLEX_ val SCLEX_CONTAINER=0 val SCLEX_NULL=1 val SCLEX_PYTHON=2 val SCLEX_CPP=3 val SCLEX_HTML=4 val SCLEX_XML=5 val SCLEX_PERL=6 val SCLEX_SQL=7 val SCLEX_VB=8 val SCLEX_PROPERTIES=9 val SCLEX_ERRORLIST=10 val SCLEX_MAKEFILE=11 val SCLEX_BATCH=12 val SCLEX_XCODE=13 val SCLEX_LATEX=14 val SCLEX_LUA=15 val SCLEX_DIFF=16 val SCLEX_CONF=17 val SCLEX_PASCAL=18 val SCLEX_AVE=19 val SCLEX_ADA=20 val SCLEX_LISP=21 val SCLEX_RUBY=22 val SCLEX_EIFFEL=23 val SCLEX_EIFFELKW=24 val SCLEX_TCL=25 val SCLEX_NNCRONTAB=26 val SCLEX_BULLANT=27 val SCLEX_VBSCRIPT=28 val SCLEX_BAAN=31 val SCLEX_MATLAB=32 val SCLEX_SCRIPTOL=33 val SCLEX_ASM=34 val SCLEX_CPPNOCASE=35 val SCLEX_FORTRAN=36 val SCLEX_F77=37 val SCLEX_CSS=38 val SCLEX_POV=39 val SCLEX_LOUT=40 val SCLEX_ESCRIPT=41 val SCLEX_PS=42 val SCLEX_NSIS=43 val SCLEX_MMIXAL=44 val SCLEX_CLW=45 val SCLEX_CLWNOCASE=46 val SCLEX_LOT=47 val SCLEX_YAML=48 val SCLEX_TEX=49 val SCLEX_METAPOST=50 val SCLEX_POWERBASIC=51 val SCLEX_FORTH=52 val SCLEX_ERLANG=53 val SCLEX_OCTAVE=54 val SCLEX_MSSQL=55 val SCLEX_VERILOG=56 val SCLEX_KIX=57 val SCLEX_GUI4CLI=58 val SCLEX_SPECMAN=59 val SCLEX_AU3=60 val SCLEX_APDL=61 val SCLEX_BASH=62 val SCLEX_ASN1=63 val SCLEX_VHDL=64 val SCLEX_CAML=65 val SCLEX_BLITZBASIC=66 val SCLEX_PUREBASIC=67 val SCLEX_HASKELL=68 val SCLEX_PHPSCRIPT=69 val SCLEX_TADS3=70 val SCLEX_REBOL=71 val SCLEX_SMALLTALK=72 val SCLEX_FLAGSHIP=73 val SCLEX_CSOUND=74 val SCLEX_FREEBASIC=75 val SCLEX_INNOSETUP=76 val SCLEX_OPAL=77 val SCLEX_SPICE=78 val SCLEX_D=79 val SCLEX_CMAKE=80 val SCLEX_GAP=81 val SCLEX_PLM=82 val SCLEX_PROGRESS=83 val SCLEX_ABAQUS=84 val SCLEX_ASYMPTOTE=85 val SCLEX_R=86 val SCLEX_MAGIK=87 val SCLEX_POWERSHELL=88 val SCLEX_MYSQL=89 val SCLEX_PO=90 val SCLEX_TAL=91 val SCLEX_COBOL=92 val SCLEX_TACL=93 val SCLEX_SORCUS=94 val SCLEX_POWERPRO=95 val SCLEX_NIMROD=96 val SCLEX_SML=97 val SCLEX_MARKDOWN=98 val SCLEX_TXT2TAGS=99 val SCLEX_A68K=100 val SCLEX_MODULA=101 val SCLEX_COFFEESCRIPT=102 val SCLEX_TCMD=103 val SCLEX_AVS=104 val SCLEX_ECL=105 val SCLEX_OSCRIPT=106 val SCLEX_VISUALPROLOG=107 val SCLEX_LITERATEHASKELL=108 val SCLEX_STTXT=109 val SCLEX_KVIRC=110 val SCLEX_RUST=111 val SCLEX_DMAP=112 val SCLEX_AS=113 val SCLEX_DMIS=114 val SCLEX_REGISTRY=115 val SCLEX_BIBTEX=116 val SCLEX_SREC=117 val SCLEX_IHEX=118 val SCLEX_TEHEX=119 val SCLEX_JSON=120 val SCLEX_EDIFACT=121 val SCLEX_INDENT=122 val SCLEX_MAXIMA=123 val SCLEX_STATA=124 val SCLEX_SAS=125 val SCLEX_LPEG=999 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. val SCLEX_AUTOMATIC=1000 # Lexical states for SCLEX_PYTHON lex Python=SCLEX_PYTHON SCE_P_ lex Nimrod=SCLEX_NIMROD SCE_P_ val SCE_P_DEFAULT=0 val SCE_P_COMMENTLINE=1 val SCE_P_NUMBER=2 val SCE_P_STRING=3 val SCE_P_CHARACTER=4 val SCE_P_WORD=5 val SCE_P_TRIPLE=6 val SCE_P_TRIPLEDOUBLE=7 val SCE_P_CLASSNAME=8 val SCE_P_DEFNAME=9 val SCE_P_OPERATOR=10 val SCE_P_IDENTIFIER=11 val SCE_P_COMMENTBLOCK=12 val SCE_P_STRINGEOL=13 val SCE_P_WORD2=14 val SCE_P_DECORATOR=15 val SCE_P_FSTRING=16 val SCE_P_FCHARACTER=17 val SCE_P_FTRIPLE=18 val SCE_P_FTRIPLEDOUBLE=19 # Lexical states for SCLEX_CPP # Lexical states for SCLEX_BULLANT # Lexical states for SCLEX_COBOL # Lexical states for SCLEX_TACL # Lexical states for SCLEX_TAL lex Cpp=SCLEX_CPP SCE_C_ lex BullAnt=SCLEX_BULLANT SCE_C_ lex COBOL=SCLEX_COBOL SCE_C_ lex TACL=SCLEX_TACL SCE_C_ lex TAL=SCLEX_TAL SCE_C_ val SCE_C_DEFAULT=0 val SCE_C_COMMENT=1 val SCE_C_COMMENTLINE=2 val SCE_C_COMMENTDOC=3 val SCE_C_NUMBER=4 val SCE_C_WORD=5 val SCE_C_STRING=6 val SCE_C_CHARACTER=7 val SCE_C_UUID=8 val SCE_C_PREPROCESSOR=9 val SCE_C_OPERATOR=10 val SCE_C_IDENTIFIER=11 val SCE_C_STRINGEOL=12 val SCE_C_VERBATIM=13 val SCE_C_REGEX=14 val SCE_C_COMMENTLINEDOC=15 val SCE_C_WORD2=16 val SCE_C_COMMENTDOCKEYWORD=17 val SCE_C_COMMENTDOCKEYWORDERROR=18 val SCE_C_GLOBALCLASS=19 val SCE_C_STRINGRAW=20 val SCE_C_TRIPLEVERBATIM=21 val SCE_C_HASHQUOTEDSTRING=22 val SCE_C_PREPROCESSORCOMMENT=23 val SCE_C_PREPROCESSORCOMMENTDOC=24 val SCE_C_USERLITERAL=25 val SCE_C_TASKMARKER=26 val SCE_C_ESCAPESEQUENCE=27 # Lexical states for SCLEX_D lex D=SCLEX_D SCE_D_ val SCE_D_DEFAULT=0 val SCE_D_COMMENT=1 val SCE_D_COMMENTLINE=2 val SCE_D_COMMENTDOC=3 val SCE_D_COMMENTNESTED=4 val SCE_D_NUMBER=5 val SCE_D_WORD=6 val SCE_D_WORD2=7 val SCE_D_WORD3=8 val SCE_D_TYPEDEF=9 val SCE_D_STRING=10 val SCE_D_STRINGEOL=11 val SCE_D_CHARACTER=12 val SCE_D_OPERATOR=13 val SCE_D_IDENTIFIER=14 val SCE_D_COMMENTLINEDOC=15 val SCE_D_COMMENTDOCKEYWORD=16 val SCE_D_COMMENTDOCKEYWORDERROR=17 val SCE_D_STRINGB=18 val SCE_D_STRINGR=19 val SCE_D_WORD5=20 val SCE_D_WORD6=21 val SCE_D_WORD7=22 # Lexical states for SCLEX_TCL lex TCL=SCLEX_TCL SCE_TCL_ val SCE_TCL_DEFAULT=0 val SCE_TCL_COMMENT=1 val SCE_TCL_COMMENTLINE=2 val SCE_TCL_NUMBER=3 val SCE_TCL_WORD_IN_QUOTE=4 val SCE_TCL_IN_QUOTE=5 val SCE_TCL_OPERATOR=6 val SCE_TCL_IDENTIFIER=7 val SCE_TCL_SUBSTITUTION=8 val SCE_TCL_SUB_BRACE=9 val SCE_TCL_MODIFIER=10 val SCE_TCL_EXPAND=11 val SCE_TCL_WORD=12 val SCE_TCL_WORD2=13 val SCE_TCL_WORD3=14 val SCE_TCL_WORD4=15 val SCE_TCL_WORD5=16 val SCE_TCL_WORD6=17 val SCE_TCL_WORD7=18 val SCE_TCL_WORD8=19 val SCE_TCL_COMMENT_BOX=20 val SCE_TCL_BLOCK_COMMENT=21 # Lexical states for SCLEX_HTML, SCLEX_XML lex HTML=SCLEX_HTML SCE_H_ SCE_HJ_ SCE_HJA_ SCE_HB_ SCE_HBA_ SCE_HP_ SCE_HPHP_ SCE_HPA_ lex XML=SCLEX_XML SCE_H_ SCE_HJ_ SCE_HJA_ SCE_HB_ SCE_HBA_ SCE_HP_ SCE_HPHP_ SCE_HPA_ val SCE_H_DEFAULT=0 val SCE_H_TAG=1 val SCE_H_TAGUNKNOWN=2 val SCE_H_ATTRIBUTE=3 val SCE_H_ATTRIBUTEUNKNOWN=4 val SCE_H_NUMBER=5 val SCE_H_DOUBLESTRING=6 val SCE_H_SINGLESTRING=7 val SCE_H_OTHER=8 val SCE_H_COMMENT=9 val SCE_H_ENTITY=10 # XML and ASP val SCE_H_TAGEND=11 val SCE_H_XMLSTART=12 val SCE_H_XMLEND=13 val SCE_H_SCRIPT=14 val SCE_H_ASP=15 val SCE_H_ASPAT=16 val SCE_H_CDATA=17 val SCE_H_QUESTION=18 # More HTML val SCE_H_VALUE=19 # X-Code val SCE_H_XCCOMMENT=20 # SGML val SCE_H_SGML_DEFAULT=21 val SCE_H_SGML_COMMAND=22 val SCE_H_SGML_1ST_PARAM=23 val SCE_H_SGML_DOUBLESTRING=24 val SCE_H_SGML_SIMPLESTRING=25 val SCE_H_SGML_ERROR=26 val SCE_H_SGML_SPECIAL=27 val SCE_H_SGML_ENTITY=28 val SCE_H_SGML_COMMENT=29 val SCE_H_SGML_1ST_PARAM_COMMENT=30 val SCE_H_SGML_BLOCK_DEFAULT=31 # Embedded Javascript val SCE_HJ_START=40 val SCE_HJ_DEFAULT=41 val SCE_HJ_COMMENT=42 val SCE_HJ_COMMENTLINE=43 val SCE_HJ_COMMENTDOC=44 val SCE_HJ_NUMBER=45 val SCE_HJ_WORD=46 val SCE_HJ_KEYWORD=47 val SCE_HJ_DOUBLESTRING=48 val SCE_HJ_SINGLESTRING=49 val SCE_HJ_SYMBOLS=50 val SCE_HJ_STRINGEOL=51 val SCE_HJ_REGEX=52 # ASP Javascript val SCE_HJA_START=55 val SCE_HJA_DEFAULT=56 val SCE_HJA_COMMENT=57 val SCE_HJA_COMMENTLINE=58 val SCE_HJA_COMMENTDOC=59 val SCE_HJA_NUMBER=60 val SCE_HJA_WORD=61 val SCE_HJA_KEYWORD=62 val SCE_HJA_DOUBLESTRING=63 val SCE_HJA_SINGLESTRING=64 val SCE_HJA_SYMBOLS=65 val SCE_HJA_STRINGEOL=66 val SCE_HJA_REGEX=67 # Embedded VBScript val SCE_HB_START=70 val SCE_HB_DEFAULT=71 val SCE_HB_COMMENTLINE=72 val SCE_HB_NUMBER=73 val SCE_HB_WORD=74 val SCE_HB_STRING=75 val SCE_HB_IDENTIFIER=76 val SCE_HB_STRINGEOL=77 # ASP VBScript val SCE_HBA_START=80 val SCE_HBA_DEFAULT=81 val SCE_HBA_COMMENTLINE=82 val SCE_HBA_NUMBER=83 val SCE_HBA_WORD=84 val SCE_HBA_STRING=85 val SCE_HBA_IDENTIFIER=86 val SCE_HBA_STRINGEOL=87 # Embedded Python val SCE_HP_START=90 val SCE_HP_DEFAULT=91 val SCE_HP_COMMENTLINE=92 val SCE_HP_NUMBER=93 val SCE_HP_STRING=94 val SCE_HP_CHARACTER=95 val SCE_HP_WORD=96 val SCE_HP_TRIPLE=97 val SCE_HP_TRIPLEDOUBLE=98 val SCE_HP_CLASSNAME=99 val SCE_HP_DEFNAME=100 val SCE_HP_OPERATOR=101 val SCE_HP_IDENTIFIER=102 # PHP val SCE_HPHP_COMPLEX_VARIABLE=104 # ASP Python val SCE_HPA_START=105 val SCE_HPA_DEFAULT=106 val SCE_HPA_COMMENTLINE=107 val SCE_HPA_NUMBER=108 val SCE_HPA_STRING=109 val SCE_HPA_CHARACTER=110 val SCE_HPA_WORD=111 val SCE_HPA_TRIPLE=112 val SCE_HPA_TRIPLEDOUBLE=113 val SCE_HPA_CLASSNAME=114 val SCE_HPA_DEFNAME=115 val SCE_HPA_OPERATOR=116 val SCE_HPA_IDENTIFIER=117 # PHP val SCE_HPHP_DEFAULT=118 val SCE_HPHP_HSTRING=119 val SCE_HPHP_SIMPLESTRING=120 val SCE_HPHP_WORD=121 val SCE_HPHP_NUMBER=122 val SCE_HPHP_VARIABLE=123 val SCE_HPHP_COMMENT=124 val SCE_HPHP_COMMENTLINE=125 val SCE_HPHP_HSTRING_VARIABLE=126 val SCE_HPHP_OPERATOR=127 # Lexical states for SCLEX_PERL lex Perl=SCLEX_PERL SCE_PL_ val SCE_PL_DEFAULT=0 val SCE_PL_ERROR=1 val SCE_PL_COMMENTLINE=2 val SCE_PL_POD=3 val SCE_PL_NUMBER=4 val SCE_PL_WORD=5 val SCE_PL_STRING=6 val SCE_PL_CHARACTER=7 val SCE_PL_PUNCTUATION=8 val SCE_PL_PREPROCESSOR=9 val SCE_PL_OPERATOR=10 val SCE_PL_IDENTIFIER=11 val SCE_PL_SCALAR=12 val SCE_PL_ARRAY=13 val SCE_PL_HASH=14 val SCE_PL_SYMBOLTABLE=15 val SCE_PL_VARIABLE_INDEXER=16 val SCE_PL_REGEX=17 val SCE_PL_REGSUBST=18 val SCE_PL_LONGQUOTE=19 val SCE_PL_BACKTICKS=20 val SCE_PL_DATASECTION=21 val SCE_PL_HERE_DELIM=22 val SCE_PL_HERE_Q=23 val SCE_PL_HERE_QQ=24 val SCE_PL_HERE_QX=25 val SCE_PL_STRING_Q=26 val SCE_PL_STRING_QQ=27 val SCE_PL_STRING_QX=28 val SCE_PL_STRING_QR=29 val SCE_PL_STRING_QW=30 val SCE_PL_POD_VERB=31 val SCE_PL_SUB_PROTOTYPE=40 val SCE_PL_FORMAT_IDENT=41 val SCE_PL_FORMAT=42 val SCE_PL_STRING_VAR=43 val SCE_PL_XLAT=44 val SCE_PL_REGEX_VAR=54 val SCE_PL_REGSUBST_VAR=55 val SCE_PL_BACKTICKS_VAR=57 val SCE_PL_HERE_QQ_VAR=61 val SCE_PL_HERE_QX_VAR=62 val SCE_PL_STRING_QQ_VAR=64 val SCE_PL_STRING_QX_VAR=65 val SCE_PL_STRING_QR_VAR=66 # Lexical states for SCLEX_RUBY lex Ruby=SCLEX_RUBY SCE_RB_ val SCE_RB_DEFAULT=0 val SCE_RB_ERROR=1 val SCE_RB_COMMENTLINE=2 val SCE_RB_POD=3 val SCE_RB_NUMBER=4 val SCE_RB_WORD=5 val SCE_RB_STRING=6 val SCE_RB_CHARACTER=7 val SCE_RB_CLASSNAME=8 val SCE_RB_DEFNAME=9 val SCE_RB_OPERATOR=10 val SCE_RB_IDENTIFIER=11 val SCE_RB_REGEX=12 val SCE_RB_GLOBAL=13 val SCE_RB_SYMBOL=14 val SCE_RB_MODULE_NAME=15 val SCE_RB_INSTANCE_VAR=16 val SCE_RB_CLASS_VAR=17 val SCE_RB_BACKTICKS=18 val SCE_RB_DATASECTION=19 val SCE_RB_HERE_DELIM=20 val SCE_RB_HERE_Q=21 val SCE_RB_HERE_QQ=22 val SCE_RB_HERE_QX=23 val SCE_RB_STRING_Q=24 val SCE_RB_STRING_QQ=25 val SCE_RB_STRING_QX=26 val SCE_RB_STRING_QR=27 val SCE_RB_STRING_QW=28 val SCE_RB_WORD_DEMOTED=29 val SCE_RB_STDIN=30 val SCE_RB_STDOUT=31 val SCE_RB_STDERR=40 val SCE_RB_UPPER_BOUND=41 # Lexical states for SCLEX_VB, SCLEX_VBSCRIPT, SCLEX_POWERBASIC, SCLEX_BLITZBASIC, SCLEX_PUREBASIC, SCLEX_FREEBASIC lex VB=SCLEX_VB SCE_B_ lex VBScript=SCLEX_VBSCRIPT SCE_B_ lex PowerBasic=SCLEX_POWERBASIC SCE_B_ lex BlitzBasic=SCLEX_BLITZBASIC SCE_B_ lex PureBasic=SCLEX_PUREBASIC SCE_B_ lex FreeBasic=SCLEX_FREEBASIC SCE_B_ val SCE_B_DEFAULT=0 val SCE_B_COMMENT=1 val SCE_B_NUMBER=2 val SCE_B_KEYWORD=3 val SCE_B_STRING=4 val SCE_B_PREPROCESSOR=5 val SCE_B_OPERATOR=6 val SCE_B_IDENTIFIER=7 val SCE_B_DATE=8 val SCE_B_STRINGEOL=9 val SCE_B_KEYWORD2=10 val SCE_B_KEYWORD3=11 val SCE_B_KEYWORD4=12 val SCE_B_CONSTANT=13 val SCE_B_ASM=14 val SCE_B_LABEL=15 val SCE_B_ERROR=16 val SCE_B_HEXNUMBER=17 val SCE_B_BINNUMBER=18 val SCE_B_COMMENTBLOCK=19 val SCE_B_DOCLINE=20 val SCE_B_DOCBLOCK=21 val SCE_B_DOCKEYWORD=22 # Lexical states for SCLEX_PROPERTIES lex Properties=SCLEX_PROPERTIES SCE_PROPS_ val SCE_PROPS_DEFAULT=0 val SCE_PROPS_COMMENT=1 val SCE_PROPS_SECTION=2 val SCE_PROPS_ASSIGNMENT=3 val SCE_PROPS_DEFVAL=4 val SCE_PROPS_KEY=5 # Lexical states for SCLEX_LATEX lex LaTeX=SCLEX_LATEX SCE_L_ val SCE_L_DEFAULT=0 val SCE_L_COMMAND=1 val SCE_L_TAG=2 val SCE_L_MATH=3 val SCE_L_COMMENT=4 val SCE_L_TAG2=5 val SCE_L_MATH2=6 val SCE_L_COMMENT2=7 val SCE_L_VERBATIM=8 val SCE_L_SHORTCMD=9 val SCE_L_SPECIAL=10 val SCE_L_CMDOPT=11 val SCE_L_ERROR=12 # Lexical states for SCLEX_LUA lex Lua=SCLEX_LUA SCE_LUA_ val SCE_LUA_DEFAULT=0 val SCE_LUA_COMMENT=1 val SCE_LUA_COMMENTLINE=2 val SCE_LUA_COMMENTDOC=3 val SCE_LUA_NUMBER=4 val SCE_LUA_WORD=5 val SCE_LUA_STRING=6 val SCE_LUA_CHARACTER=7 val SCE_LUA_LITERALSTRING=8 val SCE_LUA_PREPROCESSOR=9 val SCE_LUA_OPERATOR=10 val SCE_LUA_IDENTIFIER=11 val SCE_LUA_STRINGEOL=12 val SCE_LUA_WORD2=13 val SCE_LUA_WORD3=14 val SCE_LUA_WORD4=15 val SCE_LUA_WORD5=16 val SCE_LUA_WORD6=17 val SCE_LUA_WORD7=18 val SCE_LUA_WORD8=19 val SCE_LUA_LABEL=20 # Lexical states for SCLEX_ERRORLIST lex ErrorList=SCLEX_ERRORLIST SCE_ERR_ val SCE_ERR_DEFAULT=0 val SCE_ERR_PYTHON=1 val SCE_ERR_GCC=2 val SCE_ERR_MS=3 val SCE_ERR_CMD=4 val SCE_ERR_BORLAND=5 val SCE_ERR_PERL=6 val SCE_ERR_NET=7 val SCE_ERR_LUA=8 val SCE_ERR_CTAG=9 val SCE_ERR_DIFF_CHANGED=10 val SCE_ERR_DIFF_ADDITION=11 val SCE_ERR_DIFF_DELETION=12 val SCE_ERR_DIFF_MESSAGE=13 val SCE_ERR_PHP=14 val SCE_ERR_ELF=15 val SCE_ERR_IFC=16 val SCE_ERR_IFORT=17 val SCE_ERR_ABSF=18 val SCE_ERR_TIDY=19 val SCE_ERR_JAVA_STACK=20 val SCE_ERR_VALUE=21 val SCE_ERR_GCC_INCLUDED_FROM=22 val SCE_ERR_ESCSEQ=23 val SCE_ERR_ESCSEQ_UNKNOWN=24 val SCE_ERR_ES_BLACK=40 val SCE_ERR_ES_RED=41 val SCE_ERR_ES_GREEN=42 val SCE_ERR_ES_BROWN=43 val SCE_ERR_ES_BLUE=44 val SCE_ERR_ES_MAGENTA=45 val SCE_ERR_ES_CYAN=46 val SCE_ERR_ES_GRAY=47 val SCE_ERR_ES_DARK_GRAY=48 val SCE_ERR_ES_BRIGHT_RED=49 val SCE_ERR_ES_BRIGHT_GREEN=50 val SCE_ERR_ES_YELLOW=51 val SCE_ERR_ES_BRIGHT_BLUE=52 val SCE_ERR_ES_BRIGHT_MAGENTA=53 val SCE_ERR_ES_BRIGHT_CYAN=54 val SCE_ERR_ES_WHITE=55 # Lexical states for SCLEX_BATCH lex Batch=SCLEX_BATCH SCE_BAT_ val SCE_BAT_DEFAULT=0 val SCE_BAT_COMMENT=1 val SCE_BAT_WORD=2 val SCE_BAT_LABEL=3 val SCE_BAT_HIDE=4 val SCE_BAT_COMMAND=5 val SCE_BAT_IDENTIFIER=6 val SCE_BAT_OPERATOR=7 # Lexical states for SCLEX_TCMD lex TCMD=SCLEX_TCMD SCE_TCMD_ val SCE_TCMD_DEFAULT=0 val SCE_TCMD_COMMENT=1 val SCE_TCMD_WORD=2 val SCE_TCMD_LABEL=3 val SCE_TCMD_HIDE=4 val SCE_TCMD_COMMAND=5 val SCE_TCMD_IDENTIFIER=6 val SCE_TCMD_OPERATOR=7 val SCE_TCMD_ENVIRONMENT=8 val SCE_TCMD_EXPANSION=9 val SCE_TCMD_CLABEL=10 # Lexical states for SCLEX_MAKEFILE lex MakeFile=SCLEX_MAKEFILE SCE_MAKE_ val SCE_MAKE_DEFAULT=0 val SCE_MAKE_COMMENT=1 val SCE_MAKE_PREPROCESSOR=2 val SCE_MAKE_IDENTIFIER=3 val SCE_MAKE_OPERATOR=4 val SCE_MAKE_TARGET=5 val SCE_MAKE_IDEOL=9 # Lexical states for SCLEX_DIFF lex Diff=SCLEX_DIFF SCE_DIFF_ val SCE_DIFF_DEFAULT=0 val SCE_DIFF_COMMENT=1 val SCE_DIFF_COMMAND=2 val SCE_DIFF_HEADER=3 val SCE_DIFF_POSITION=4 val SCE_DIFF_DELETED=5 val SCE_DIFF_ADDED=6 val SCE_DIFF_CHANGED=7 val SCE_DIFF_PATCH_ADD=8 val SCE_DIFF_PATCH_DELETE=9 val SCE_DIFF_REMOVED_PATCH_ADD=10 val SCE_DIFF_REMOVED_PATCH_DELETE=11 # Lexical states for SCLEX_CONF (Apache Configuration Files Lexer) lex Conf=SCLEX_CONF SCE_CONF_ val SCE_CONF_DEFAULT=0 val SCE_CONF_COMMENT=1 val SCE_CONF_NUMBER=2 val SCE_CONF_IDENTIFIER=3 val SCE_CONF_EXTENSION=4 val SCE_CONF_PARAMETER=5 val SCE_CONF_STRING=6 val SCE_CONF_OPERATOR=7 val SCE_CONF_IP=8 val SCE_CONF_DIRECTIVE=9 # Lexical states for SCLEX_AVE, Avenue lex Avenue=SCLEX_AVE SCE_AVE_ val SCE_AVE_DEFAULT=0 val SCE_AVE_COMMENT=1 val SCE_AVE_NUMBER=2 val SCE_AVE_WORD=3 val SCE_AVE_STRING=6 val SCE_AVE_ENUM=7 val SCE_AVE_STRINGEOL=8 val SCE_AVE_IDENTIFIER=9 val SCE_AVE_OPERATOR=10 val SCE_AVE_WORD1=11 val SCE_AVE_WORD2=12 val SCE_AVE_WORD3=13 val SCE_AVE_WORD4=14 val SCE_AVE_WORD5=15 val SCE_AVE_WORD6=16 # Lexical states for SCLEX_ADA lex Ada=SCLEX_ADA SCE_ADA_ val SCE_ADA_DEFAULT=0 val SCE_ADA_WORD=1 val SCE_ADA_IDENTIFIER=2 val SCE_ADA_NUMBER=3 val SCE_ADA_DELIMITER=4 val SCE_ADA_CHARACTER=5 val SCE_ADA_CHARACTEREOL=6 val SCE_ADA_STRING=7 val SCE_ADA_STRINGEOL=8 val SCE_ADA_LABEL=9 val SCE_ADA_COMMENTLINE=10 val SCE_ADA_ILLEGAL=11 # Lexical states for SCLEX_BAAN lex Baan=SCLEX_BAAN SCE_BAAN_ val SCE_BAAN_DEFAULT=0 val SCE_BAAN_COMMENT=1 val SCE_BAAN_COMMENTDOC=2 val SCE_BAAN_NUMBER=3 val SCE_BAAN_WORD=4 val SCE_BAAN_STRING=5 val SCE_BAAN_PREPROCESSOR=6 val SCE_BAAN_OPERATOR=7 val SCE_BAAN_IDENTIFIER=8 val SCE_BAAN_STRINGEOL=9 val SCE_BAAN_WORD2=10 val SCE_BAAN_WORD3=11 val SCE_BAAN_WORD4=12 val SCE_BAAN_WORD5=13 val SCE_BAAN_WORD6=14 val SCE_BAAN_WORD7=15 val SCE_BAAN_WORD8=16 val SCE_BAAN_WORD9=17 val SCE_BAAN_TABLEDEF=18 val SCE_BAAN_TABLESQL=19 val SCE_BAAN_FUNCTION=20 val SCE_BAAN_DOMDEF=21 val SCE_BAAN_FUNCDEF=22 val SCE_BAAN_OBJECTDEF=23 val SCE_BAAN_DEFINEDEF=24 # Lexical states for SCLEX_LISP lex Lisp=SCLEX_LISP SCE_LISP_ val SCE_LISP_DEFAULT=0 val SCE_LISP_COMMENT=1 val SCE_LISP_NUMBER=2 val SCE_LISP_KEYWORD=3 val SCE_LISP_KEYWORD_KW=4 val SCE_LISP_SYMBOL=5 val SCE_LISP_STRING=6 val SCE_LISP_STRINGEOL=8 val SCE_LISP_IDENTIFIER=9 val SCE_LISP_OPERATOR=10 val SCE_LISP_SPECIAL=11 val SCE_LISP_MULTI_COMMENT=12 # Lexical states for SCLEX_EIFFEL and SCLEX_EIFFELKW lex Eiffel=SCLEX_EIFFEL SCE_EIFFEL_ lex EiffelKW=SCLEX_EIFFELKW SCE_EIFFEL_ val SCE_EIFFEL_DEFAULT=0 val SCE_EIFFEL_COMMENTLINE=1 val SCE_EIFFEL_NUMBER=2 val SCE_EIFFEL_WORD=3 val SCE_EIFFEL_STRING=4 val SCE_EIFFEL_CHARACTER=5 val SCE_EIFFEL_OPERATOR=6 val SCE_EIFFEL_IDENTIFIER=7 val SCE_EIFFEL_STRINGEOL=8 # Lexical states for SCLEX_NNCRONTAB (nnCron crontab Lexer) lex NNCronTab=SCLEX_NNCRONTAB SCE_NNCRONTAB_ val SCE_NNCRONTAB_DEFAULT=0 val SCE_NNCRONTAB_COMMENT=1 val SCE_NNCRONTAB_TASK=2 val SCE_NNCRONTAB_SECTION=3 val SCE_NNCRONTAB_KEYWORD=4 val SCE_NNCRONTAB_MODIFIER=5 val SCE_NNCRONTAB_ASTERISK=6 val SCE_NNCRONTAB_NUMBER=7 val SCE_NNCRONTAB_STRING=8 val SCE_NNCRONTAB_ENVIRONMENT=9 val SCE_NNCRONTAB_IDENTIFIER=10 # Lexical states for SCLEX_FORTH (Forth Lexer) lex Forth=SCLEX_FORTH SCE_FORTH_ val SCE_FORTH_DEFAULT=0 val SCE_FORTH_COMMENT=1 val SCE_FORTH_COMMENT_ML=2 val SCE_FORTH_IDENTIFIER=3 val SCE_FORTH_CONTROL=4 val SCE_FORTH_KEYWORD=5 val SCE_FORTH_DEFWORD=6 val SCE_FORTH_PREWORD1=7 val SCE_FORTH_PREWORD2=8 val SCE_FORTH_NUMBER=9 val SCE_FORTH_STRING=10 val SCE_FORTH_LOCALE=11 # Lexical states for SCLEX_MATLAB lex MatLab=SCLEX_MATLAB SCE_MATLAB_ val SCE_MATLAB_DEFAULT=0 val SCE_MATLAB_COMMENT=1 val SCE_MATLAB_COMMAND=2 val SCE_MATLAB_NUMBER=3 val SCE_MATLAB_KEYWORD=4 # single quoted string val SCE_MATLAB_STRING=5 val SCE_MATLAB_OPERATOR=6 val SCE_MATLAB_IDENTIFIER=7 val SCE_MATLAB_DOUBLEQUOTESTRING=8 # Lexical states for SCLEX_MAXIMA lex Maxima=SCLEX_MAXIMA SCE_MAXIMA_ val SCE_MAXIMA_OPERATOR=0 val SCE_MAXIMA_COMMANDENDING=1 val SCE_MAXIMA_COMMENT=2 val SCE_MAXIMA_NUMBER=3 val SCE_MAXIMA_STRING=4 val SCE_MAXIMA_COMMAND=5 val SCE_MAXIMA_VARIABLE=6 val SCE_MAXIMA_UNKNOWN=7 # Lexical states for SCLEX_SCRIPTOL lex Sol=SCLEX_SCRIPTOL SCE_SCRIPTOL_ val SCE_SCRIPTOL_DEFAULT=0 val SCE_SCRIPTOL_WHITE=1 val SCE_SCRIPTOL_COMMENTLINE=2 val SCE_SCRIPTOL_PERSISTENT=3 val SCE_SCRIPTOL_CSTYLE=4 val SCE_SCRIPTOL_COMMENTBLOCK=5 val SCE_SCRIPTOL_NUMBER=6 val SCE_SCRIPTOL_STRING=7 val SCE_SCRIPTOL_CHARACTER=8 val SCE_SCRIPTOL_STRINGEOL=9 val SCE_SCRIPTOL_KEYWORD=10 val SCE_SCRIPTOL_OPERATOR=11 val SCE_SCRIPTOL_IDENTIFIER=12 val SCE_SCRIPTOL_TRIPLE=13 val SCE_SCRIPTOL_CLASSNAME=14 val SCE_SCRIPTOL_PREPROCESSOR=15 # Lexical states for SCLEX_ASM, SCLEX_AS lex Asm=SCLEX_ASM SCE_ASM_ lex As=SCLEX_AS SCE_ASM_ val SCE_ASM_DEFAULT=0 val SCE_ASM_COMMENT=1 val SCE_ASM_NUMBER=2 val SCE_ASM_STRING=3 val SCE_ASM_OPERATOR=4 val SCE_ASM_IDENTIFIER=5 val SCE_ASM_CPUINSTRUCTION=6 val SCE_ASM_MATHINSTRUCTION=7 val SCE_ASM_REGISTER=8 val SCE_ASM_DIRECTIVE=9 val SCE_ASM_DIRECTIVEOPERAND=10 val SCE_ASM_COMMENTBLOCK=11 val SCE_ASM_CHARACTER=12 val SCE_ASM_STRINGEOL=13 val SCE_ASM_EXTINSTRUCTION=14 val SCE_ASM_COMMENTDIRECTIVE=15 # Lexical states for SCLEX_FORTRAN lex Fortran=SCLEX_FORTRAN SCE_F_ lex F77=SCLEX_F77 SCE_F_ val SCE_F_DEFAULT=0 val SCE_F_COMMENT=1 val SCE_F_NUMBER=2 val SCE_F_STRING1=3 val SCE_F_STRING2=4 val SCE_F_STRINGEOL=5 val SCE_F_OPERATOR=6 val SCE_F_IDENTIFIER=7 val SCE_F_WORD=8 val SCE_F_WORD2=9 val SCE_F_WORD3=10 val SCE_F_PREPROCESSOR=11 val SCE_F_OPERATOR2=12 val SCE_F_LABEL=13 val SCE_F_CONTINUATION=14 # Lexical states for SCLEX_CSS lex CSS=SCLEX_CSS SCE_CSS_ val SCE_CSS_DEFAULT=0 val SCE_CSS_TAG=1 val SCE_CSS_CLASS=2 val SCE_CSS_PSEUDOCLASS=3 val SCE_CSS_UNKNOWN_PSEUDOCLASS=4 val SCE_CSS_OPERATOR=5 val SCE_CSS_IDENTIFIER=6 val SCE_CSS_UNKNOWN_IDENTIFIER=7 val SCE_CSS_VALUE=8 val SCE_CSS_COMMENT=9 val SCE_CSS_ID=10 val SCE_CSS_IMPORTANT=11 val SCE_CSS_DIRECTIVE=12 val SCE_CSS_DOUBLESTRING=13 val SCE_CSS_SINGLESTRING=14 val SCE_CSS_IDENTIFIER2=15 val SCE_CSS_ATTRIBUTE=16 val SCE_CSS_IDENTIFIER3=17 val SCE_CSS_PSEUDOELEMENT=18 val SCE_CSS_EXTENDED_IDENTIFIER=19 val SCE_CSS_EXTENDED_PSEUDOCLASS=20 val SCE_CSS_EXTENDED_PSEUDOELEMENT=21 val SCE_CSS_MEDIA=22 val SCE_CSS_VARIABLE=23 # Lexical states for SCLEX_POV lex POV=SCLEX_POV SCE_POV_ val SCE_POV_DEFAULT=0 val SCE_POV_COMMENT=1 val SCE_POV_COMMENTLINE=2 val SCE_POV_NUMBER=3 val SCE_POV_OPERATOR=4 val SCE_POV_IDENTIFIER=5 val SCE_POV_STRING=6 val SCE_POV_STRINGEOL=7 val SCE_POV_DIRECTIVE=8 val SCE_POV_BADDIRECTIVE=9 val SCE_POV_WORD2=10 val SCE_POV_WORD3=11 val SCE_POV_WORD4=12 val SCE_POV_WORD5=13 val SCE_POV_WORD6=14 val SCE_POV_WORD7=15 val SCE_POV_WORD8=16 # Lexical states for SCLEX_LOUT lex LOUT=SCLEX_LOUT SCE_LOUT_ val SCE_LOUT_DEFAULT=0 val SCE_LOUT_COMMENT=1 val SCE_LOUT_NUMBER=2 val SCE_LOUT_WORD=3 val SCE_LOUT_WORD2=4 val SCE_LOUT_WORD3=5 val SCE_LOUT_WORD4=6 val SCE_LOUT_STRING=7 val SCE_LOUT_OPERATOR=8 val SCE_LOUT_IDENTIFIER=9 val SCE_LOUT_STRINGEOL=10 # Lexical states for SCLEX_ESCRIPT lex ESCRIPT=SCLEX_ESCRIPT SCE_ESCRIPT_ val SCE_ESCRIPT_DEFAULT=0 val SCE_ESCRIPT_COMMENT=1 val SCE_ESCRIPT_COMMENTLINE=2 val SCE_ESCRIPT_COMMENTDOC=3 val SCE_ESCRIPT_NUMBER=4 val SCE_ESCRIPT_WORD=5 val SCE_ESCRIPT_STRING=6 val SCE_ESCRIPT_OPERATOR=7 val SCE_ESCRIPT_IDENTIFIER=8 val SCE_ESCRIPT_BRACE=9 val SCE_ESCRIPT_WORD2=10 val SCE_ESCRIPT_WORD3=11 # Lexical states for SCLEX_PS lex PS=SCLEX_PS SCE_PS_ val SCE_PS_DEFAULT=0 val SCE_PS_COMMENT=1 val SCE_PS_DSC_COMMENT=2 val SCE_PS_DSC_VALUE=3 val SCE_PS_NUMBER=4 val SCE_PS_NAME=5 val SCE_PS_KEYWORD=6 val SCE_PS_LITERAL=7 val SCE_PS_IMMEVAL=8 val SCE_PS_PAREN_ARRAY=9 val SCE_PS_PAREN_DICT=10 val SCE_PS_PAREN_PROC=11 val SCE_PS_TEXT=12 val SCE_PS_HEXSTRING=13 val SCE_PS_BASE85STRING=14 val SCE_PS_BADSTRINGCHAR=15 # Lexical states for SCLEX_NSIS lex NSIS=SCLEX_NSIS SCE_NSIS_ val SCE_NSIS_DEFAULT=0 val SCE_NSIS_COMMENT=1 val SCE_NSIS_STRINGDQ=2 val SCE_NSIS_STRINGLQ=3 val SCE_NSIS_STRINGRQ=4 val SCE_NSIS_FUNCTION=5 val SCE_NSIS_VARIABLE=6 val SCE_NSIS_LABEL=7 val SCE_NSIS_USERDEFINED=8 val SCE_NSIS_SECTIONDEF=9 val SCE_NSIS_SUBSECTIONDEF=10 val SCE_NSIS_IFDEFINEDEF=11 val SCE_NSIS_MACRODEF=12 val SCE_NSIS_STRINGVAR=13 val SCE_NSIS_NUMBER=14 val SCE_NSIS_SECTIONGROUP=15 val SCE_NSIS_PAGEEX=16 val SCE_NSIS_FUNCTIONDEF=17 val SCE_NSIS_COMMENTBOX=18 # Lexical states for SCLEX_MMIXAL lex MMIXAL=SCLEX_MMIXAL SCE_MMIXAL_ val SCE_MMIXAL_LEADWS=0 val SCE_MMIXAL_COMMENT=1 val SCE_MMIXAL_LABEL=2 val SCE_MMIXAL_OPCODE=3 val SCE_MMIXAL_OPCODE_PRE=4 val SCE_MMIXAL_OPCODE_VALID=5 val SCE_MMIXAL_OPCODE_UNKNOWN=6 val SCE_MMIXAL_OPCODE_POST=7 val SCE_MMIXAL_OPERANDS=8 val SCE_MMIXAL_NUMBER=9 val SCE_MMIXAL_REF=10 val SCE_MMIXAL_CHAR=11 val SCE_MMIXAL_STRING=12 val SCE_MMIXAL_REGISTER=13 val SCE_MMIXAL_HEX=14 val SCE_MMIXAL_OPERATOR=15 val SCE_MMIXAL_SYMBOL=16 val SCE_MMIXAL_INCLUDE=17 # Lexical states for SCLEX_CLW lex Clarion=SCLEX_CLW SCE_CLW_ val SCE_CLW_DEFAULT=0 val SCE_CLW_LABEL=1 val SCE_CLW_COMMENT=2 val SCE_CLW_STRING=3 val SCE_CLW_USER_IDENTIFIER=4 val SCE_CLW_INTEGER_CONSTANT=5 val SCE_CLW_REAL_CONSTANT=6 val SCE_CLW_PICTURE_STRING=7 val SCE_CLW_KEYWORD=8 val SCE_CLW_COMPILER_DIRECTIVE=9 val SCE_CLW_RUNTIME_EXPRESSIONS=10 val SCE_CLW_BUILTIN_PROCEDURES_FUNCTION=11 val SCE_CLW_STRUCTURE_DATA_TYPE=12 val SCE_CLW_ATTRIBUTE=13 val SCE_CLW_STANDARD_EQUATE=14 val SCE_CLW_ERROR=15 val SCE_CLW_DEPRECATED=16 # Lexical states for SCLEX_LOT lex LOT=SCLEX_LOT SCE_LOT_ val SCE_LOT_DEFAULT=0 val SCE_LOT_HEADER=1 val SCE_LOT_BREAK=2 val SCE_LOT_SET=3 val SCE_LOT_PASS=4 val SCE_LOT_FAIL=5 val SCE_LOT_ABORT=6 # Lexical states for SCLEX_YAML lex YAML=SCLEX_YAML SCE_YAML_ val SCE_YAML_DEFAULT=0 val SCE_YAML_COMMENT=1 val SCE_YAML_IDENTIFIER=2 val SCE_YAML_KEYWORD=3 val SCE_YAML_NUMBER=4 val SCE_YAML_REFERENCE=5 val SCE_YAML_DOCUMENT=6 val SCE_YAML_TEXT=7 val SCE_YAML_ERROR=8 val SCE_YAML_OPERATOR=9 # Lexical states for SCLEX_TEX lex TeX=SCLEX_TEX SCE_TEX_ val SCE_TEX_DEFAULT=0 val SCE_TEX_SPECIAL=1 val SCE_TEX_GROUP=2 val SCE_TEX_SYMBOL=3 val SCE_TEX_COMMAND=4 val SCE_TEX_TEXT=5 lex Metapost=SCLEX_METAPOST SCE_METAPOST_ val SCE_METAPOST_DEFAULT=0 val SCE_METAPOST_SPECIAL=1 val SCE_METAPOST_GROUP=2 val SCE_METAPOST_SYMBOL=3 val SCE_METAPOST_COMMAND=4 val SCE_METAPOST_TEXT=5 val SCE_METAPOST_EXTRA=6 # Lexical states for SCLEX_ERLANG lex Erlang=SCLEX_ERLANG SCE_ERLANG_ val SCE_ERLANG_DEFAULT=0 val SCE_ERLANG_COMMENT=1 val SCE_ERLANG_VARIABLE=2 val SCE_ERLANG_NUMBER=3 val SCE_ERLANG_KEYWORD=4 val SCE_ERLANG_STRING=5 val SCE_ERLANG_OPERATOR=6 val SCE_ERLANG_ATOM=7 val SCE_ERLANG_FUNCTION_NAME=8 val SCE_ERLANG_CHARACTER=9 val SCE_ERLANG_MACRO=10 val SCE_ERLANG_RECORD=11 val SCE_ERLANG_PREPROC=12 val SCE_ERLANG_NODE_NAME=13 val SCE_ERLANG_COMMENT_FUNCTION=14 val SCE_ERLANG_COMMENT_MODULE=15 val SCE_ERLANG_COMMENT_DOC=16 val SCE_ERLANG_COMMENT_DOC_MACRO=17 val SCE_ERLANG_ATOM_QUOTED=18 val SCE_ERLANG_MACRO_QUOTED=19 val SCE_ERLANG_RECORD_QUOTED=20 val SCE_ERLANG_NODE_NAME_QUOTED=21 val SCE_ERLANG_BIFS=22 val SCE_ERLANG_MODULES=23 val SCE_ERLANG_MODULES_ATT=24 val SCE_ERLANG_UNKNOWN=31 # Lexical states for SCLEX_OCTAVE are identical to MatLab lex Octave=SCLEX_OCTAVE SCE_MATLAB_ # Lexical states for SCLEX_MSSQL lex MSSQL=SCLEX_MSSQL SCE_MSSQL_ val SCE_MSSQL_DEFAULT=0 val SCE_MSSQL_COMMENT=1 val SCE_MSSQL_LINE_COMMENT=2 val SCE_MSSQL_NUMBER=3 val SCE_MSSQL_STRING=4 val SCE_MSSQL_OPERATOR=5 val SCE_MSSQL_IDENTIFIER=6 val SCE_MSSQL_VARIABLE=7 val SCE_MSSQL_COLUMN_NAME=8 val SCE_MSSQL_STATEMENT=9 val SCE_MSSQL_DATATYPE=10 val SCE_MSSQL_SYSTABLE=11 val SCE_MSSQL_GLOBAL_VARIABLE=12 val SCE_MSSQL_FUNCTION=13 val SCE_MSSQL_STORED_PROCEDURE=14 val SCE_MSSQL_DEFAULT_PREF_DATATYPE=15 val SCE_MSSQL_COLUMN_NAME_2=16 # Lexical states for SCLEX_VERILOG lex Verilog=SCLEX_VERILOG SCE_V_ val SCE_V_DEFAULT=0 val SCE_V_COMMENT=1 val SCE_V_COMMENTLINE=2 val SCE_V_COMMENTLINEBANG=3 val SCE_V_NUMBER=4 val SCE_V_WORD=5 val SCE_V_STRING=6 val SCE_V_WORD2=7 val SCE_V_WORD3=8 val SCE_V_PREPROCESSOR=9 val SCE_V_OPERATOR=10 val SCE_V_IDENTIFIER=11 val SCE_V_STRINGEOL=12 val SCE_V_USER=19 val SCE_V_COMMENT_WORD=20 val SCE_V_INPUT=21 val SCE_V_OUTPUT=22 val SCE_V_INOUT=23 val SCE_V_PORT_CONNECT=24 # Lexical states for SCLEX_KIX lex Kix=SCLEX_KIX SCE_KIX_ val SCE_KIX_DEFAULT=0 val SCE_KIX_COMMENT=1 val SCE_KIX_STRING1=2 val SCE_KIX_STRING2=3 val SCE_KIX_NUMBER=4 val SCE_KIX_VAR=5 val SCE_KIX_MACRO=6 val SCE_KIX_KEYWORD=7 val SCE_KIX_FUNCTIONS=8 val SCE_KIX_OPERATOR=9 val SCE_KIX_COMMENTSTREAM=10 val SCE_KIX_IDENTIFIER=31 # Lexical states for SCLEX_GUI4CLI lex Gui4Cli=SCLEX_GUI4CLI SCE_GC_ val SCE_GC_DEFAULT=0 val SCE_GC_COMMENTLINE=1 val SCE_GC_COMMENTBLOCK=2 val SCE_GC_GLOBAL=3 val SCE_GC_EVENT=4 val SCE_GC_ATTRIBUTE=5 val SCE_GC_CONTROL=6 val SCE_GC_COMMAND=7 val SCE_GC_STRING=8 val SCE_GC_OPERATOR=9 # Lexical states for SCLEX_SPECMAN lex Specman=SCLEX_SPECMAN SCE_SN_ val SCE_SN_DEFAULT=0 val SCE_SN_CODE=1 val SCE_SN_COMMENTLINE=2 val SCE_SN_COMMENTLINEBANG=3 val SCE_SN_NUMBER=4 val SCE_SN_WORD=5 val SCE_SN_STRING=6 val SCE_SN_WORD2=7 val SCE_SN_WORD3=8 val SCE_SN_PREPROCESSOR=9 val SCE_SN_OPERATOR=10 val SCE_SN_IDENTIFIER=11 val SCE_SN_STRINGEOL=12 val SCE_SN_REGEXTAG=13 val SCE_SN_SIGNAL=14 val SCE_SN_USER=19 # Lexical states for SCLEX_AU3 lex Au3=SCLEX_AU3 SCE_AU3_ val SCE_AU3_DEFAULT=0 val SCE_AU3_COMMENT=1 val SCE_AU3_COMMENTBLOCK=2 val SCE_AU3_NUMBER=3 val SCE_AU3_FUNCTION=4 val SCE_AU3_KEYWORD=5 val SCE_AU3_MACRO=6 val SCE_AU3_STRING=7 val SCE_AU3_OPERATOR=8 val SCE_AU3_VARIABLE=9 val SCE_AU3_SENT=10 val SCE_AU3_PREPROCESSOR=11 val SCE_AU3_SPECIAL=12 val SCE_AU3_EXPAND=13 val SCE_AU3_COMOBJ=14 val SCE_AU3_UDF=15 # Lexical states for SCLEX_APDL lex APDL=SCLEX_APDL SCE_APDL_ val SCE_APDL_DEFAULT=0 val SCE_APDL_COMMENT=1 val SCE_APDL_COMMENTBLOCK=2 val SCE_APDL_NUMBER=3 val SCE_APDL_STRING=4 val SCE_APDL_OPERATOR=5 val SCE_APDL_WORD=6 val SCE_APDL_PROCESSOR=7 val SCE_APDL_COMMAND=8 val SCE_APDL_SLASHCOMMAND=9 val SCE_APDL_STARCOMMAND=10 val SCE_APDL_ARGUMENT=11 val SCE_APDL_FUNCTION=12 # Lexical states for SCLEX_BASH lex Bash=SCLEX_BASH SCE_SH_ val SCE_SH_DEFAULT=0 val SCE_SH_ERROR=1 val SCE_SH_COMMENTLINE=2 val SCE_SH_NUMBER=3 val SCE_SH_WORD=4 val SCE_SH_STRING=5 val SCE_SH_CHARACTER=6 val SCE_SH_OPERATOR=7 val SCE_SH_IDENTIFIER=8 val SCE_SH_SCALAR=9 val SCE_SH_PARAM=10 val SCE_SH_BACKTICKS=11 val SCE_SH_HERE_DELIM=12 val SCE_SH_HERE_Q=13 # Lexical states for SCLEX_ASN1 lex Asn1=SCLEX_ASN1 SCE_ASN1_ val SCE_ASN1_DEFAULT=0 val SCE_ASN1_COMMENT=1 val SCE_ASN1_IDENTIFIER=2 val SCE_ASN1_STRING=3 val SCE_ASN1_OID=4 val SCE_ASN1_SCALAR=5 val SCE_ASN1_KEYWORD=6 val SCE_ASN1_ATTRIBUTE=7 val SCE_ASN1_DESCRIPTOR=8 val SCE_ASN1_TYPE=9 val SCE_ASN1_OPERATOR=10 # Lexical states for SCLEX_VHDL lex VHDL=SCLEX_VHDL SCE_VHDL_ val SCE_VHDL_DEFAULT=0 val SCE_VHDL_COMMENT=1 val SCE_VHDL_COMMENTLINEBANG=2 val SCE_VHDL_NUMBER=3 val SCE_VHDL_STRING=4 val SCE_VHDL_OPERATOR=5 val SCE_VHDL_IDENTIFIER=6 val SCE_VHDL_STRINGEOL=7 val SCE_VHDL_KEYWORD=8 val SCE_VHDL_STDOPERATOR=9 val SCE_VHDL_ATTRIBUTE=10 val SCE_VHDL_STDFUNCTION=11 val SCE_VHDL_STDPACKAGE=12 val SCE_VHDL_STDTYPE=13 val SCE_VHDL_USERWORD=14 val SCE_VHDL_BLOCK_COMMENT=15 # Lexical states for SCLEX_CAML lex Caml=SCLEX_CAML SCE_CAML_ val SCE_CAML_DEFAULT=0 val SCE_CAML_IDENTIFIER=1 val SCE_CAML_TAGNAME=2 val SCE_CAML_KEYWORD=3 val SCE_CAML_KEYWORD2=4 val SCE_CAML_KEYWORD3=5 val SCE_CAML_LINENUM=6 val SCE_CAML_OPERATOR=7 val SCE_CAML_NUMBER=8 val SCE_CAML_CHAR=9 val SCE_CAML_WHITE=10 val SCE_CAML_STRING=11 val SCE_CAML_COMMENT=12 val SCE_CAML_COMMENT1=13 val SCE_CAML_COMMENT2=14 val SCE_CAML_COMMENT3=15 # Lexical states for SCLEX_HASKELL lex Haskell=SCLEX_HASKELL SCE_HA_ val SCE_HA_DEFAULT=0 val SCE_HA_IDENTIFIER=1 val SCE_HA_KEYWORD=2 val SCE_HA_NUMBER=3 val SCE_HA_STRING=4 val SCE_HA_CHARACTER=5 val SCE_HA_CLASS=6 val SCE_HA_MODULE=7 val SCE_HA_CAPITAL=8 val SCE_HA_DATA=9 val SCE_HA_IMPORT=10 val SCE_HA_OPERATOR=11 val SCE_HA_INSTANCE=12 val SCE_HA_COMMENTLINE=13 val SCE_HA_COMMENTBLOCK=14 val SCE_HA_COMMENTBLOCK2=15 val SCE_HA_COMMENTBLOCK3=16 val SCE_HA_PRAGMA=17 val SCE_HA_PREPROCESSOR=18 val SCE_HA_STRINGEOL=19 val SCE_HA_RESERVED_OPERATOR=20 val SCE_HA_LITERATE_COMMENT=21 val SCE_HA_LITERATE_CODEDELIM=22 # Lexical states of SCLEX_TADS3 lex TADS3=SCLEX_TADS3 SCE_T3_ val SCE_T3_DEFAULT=0 val SCE_T3_X_DEFAULT=1 val SCE_T3_PREPROCESSOR=2 val SCE_T3_BLOCK_COMMENT=3 val SCE_T3_LINE_COMMENT=4 val SCE_T3_OPERATOR=5 val SCE_T3_KEYWORD=6 val SCE_T3_NUMBER=7 val SCE_T3_IDENTIFIER=8 val SCE_T3_S_STRING=9 val SCE_T3_D_STRING=10 val SCE_T3_X_STRING=11 val SCE_T3_LIB_DIRECTIVE=12 val SCE_T3_MSG_PARAM=13 val SCE_T3_HTML_TAG=14 val SCE_T3_HTML_DEFAULT=15 val SCE_T3_HTML_STRING=16 val SCE_T3_USER1=17 val SCE_T3_USER2=18 val SCE_T3_USER3=19 val SCE_T3_BRACE=20 # Lexical states for SCLEX_REBOL lex Rebol=SCLEX_REBOL SCE_REBOL_ val SCE_REBOL_DEFAULT=0 val SCE_REBOL_COMMENTLINE=1 val SCE_REBOL_COMMENTBLOCK=2 val SCE_REBOL_PREFACE=3 val SCE_REBOL_OPERATOR=4 val SCE_REBOL_CHARACTER=5 val SCE_REBOL_QUOTEDSTRING=6 val SCE_REBOL_BRACEDSTRING=7 val SCE_REBOL_NUMBER=8 val SCE_REBOL_PAIR=9 val SCE_REBOL_TUPLE=10 val SCE_REBOL_BINARY=11 val SCE_REBOL_MONEY=12 val SCE_REBOL_ISSUE=13 val SCE_REBOL_TAG=14 val SCE_REBOL_FILE=15 val SCE_REBOL_EMAIL=16 val SCE_REBOL_URL=17 val SCE_REBOL_DATE=18 val SCE_REBOL_TIME=19 val SCE_REBOL_IDENTIFIER=20 val SCE_REBOL_WORD=21 val SCE_REBOL_WORD2=22 val SCE_REBOL_WORD3=23 val SCE_REBOL_WORD4=24 val SCE_REBOL_WORD5=25 val SCE_REBOL_WORD6=26 val SCE_REBOL_WORD7=27 val SCE_REBOL_WORD8=28 # Lexical states for SCLEX_SQL lex SQL=SCLEX_SQL SCE_SQL_ val SCE_SQL_DEFAULT=0 val SCE_SQL_COMMENT=1 val SCE_SQL_COMMENTLINE=2 val SCE_SQL_COMMENTDOC=3 val SCE_SQL_NUMBER=4 val SCE_SQL_WORD=5 val SCE_SQL_STRING=6 val SCE_SQL_CHARACTER=7 val SCE_SQL_SQLPLUS=8 val SCE_SQL_SQLPLUS_PROMPT=9 val SCE_SQL_OPERATOR=10 val SCE_SQL_IDENTIFIER=11 val SCE_SQL_SQLPLUS_COMMENT=13 val SCE_SQL_COMMENTLINEDOC=15 val SCE_SQL_WORD2=16 val SCE_SQL_COMMENTDOCKEYWORD=17 val SCE_SQL_COMMENTDOCKEYWORDERROR=18 val SCE_SQL_USER1=19 val SCE_SQL_USER2=20 val SCE_SQL_USER3=21 val SCE_SQL_USER4=22 val SCE_SQL_QUOTEDIDENTIFIER=23 val SCE_SQL_QOPERATOR=24 # Lexical states for SCLEX_SMALLTALK lex Smalltalk=SCLEX_SMALLTALK SCE_ST_ val SCE_ST_DEFAULT=0 val SCE_ST_STRING=1 val SCE_ST_NUMBER=2 val SCE_ST_COMMENT=3 val SCE_ST_SYMBOL=4 val SCE_ST_BINARY=5 val SCE_ST_BOOL=6 val SCE_ST_SELF=7 val SCE_ST_SUPER=8 val SCE_ST_NIL=9 val SCE_ST_GLOBAL=10 val SCE_ST_RETURN=11 val SCE_ST_SPECIAL=12 val SCE_ST_KWSEND=13 val SCE_ST_ASSIGN=14 val SCE_ST_CHARACTER=15 val SCE_ST_SPEC_SEL=16 # Lexical states for SCLEX_FLAGSHIP (clipper) lex FlagShip=SCLEX_FLAGSHIP SCE_FS_ val SCE_FS_DEFAULT=0 val SCE_FS_COMMENT=1 val SCE_FS_COMMENTLINE=2 val SCE_FS_COMMENTDOC=3 val SCE_FS_COMMENTLINEDOC=4 val SCE_FS_COMMENTDOCKEYWORD=5 val SCE_FS_COMMENTDOCKEYWORDERROR=6 val SCE_FS_KEYWORD=7 val SCE_FS_KEYWORD2=8 val SCE_FS_KEYWORD3=9 val SCE_FS_KEYWORD4=10 val SCE_FS_NUMBER=11 val SCE_FS_STRING=12 val SCE_FS_PREPROCESSOR=13 val SCE_FS_OPERATOR=14 val SCE_FS_IDENTIFIER=15 val SCE_FS_DATE=16 val SCE_FS_STRINGEOL=17 val SCE_FS_CONSTANT=18 val SCE_FS_WORDOPERATOR=19 val SCE_FS_DISABLEDCODE=20 val SCE_FS_DEFAULT_C=21 val SCE_FS_COMMENTDOC_C=22 val SCE_FS_COMMENTLINEDOC_C=23 val SCE_FS_KEYWORD_C=24 val SCE_FS_KEYWORD2_C=25 val SCE_FS_NUMBER_C=26 val SCE_FS_STRING_C=27 val SCE_FS_PREPROCESSOR_C=28 val SCE_FS_OPERATOR_C=29 val SCE_FS_IDENTIFIER_C=30 val SCE_FS_STRINGEOL_C=31 # Lexical states for SCLEX_CSOUND lex Csound=SCLEX_CSOUND SCE_CSOUND_ val SCE_CSOUND_DEFAULT=0 val SCE_CSOUND_COMMENT=1 val SCE_CSOUND_NUMBER=2 val SCE_CSOUND_OPERATOR=3 val SCE_CSOUND_INSTR=4 val SCE_CSOUND_IDENTIFIER=5 val SCE_CSOUND_OPCODE=6 val SCE_CSOUND_HEADERSTMT=7 val SCE_CSOUND_USERKEYWORD=8 val SCE_CSOUND_COMMENTBLOCK=9 val SCE_CSOUND_PARAM=10 val SCE_CSOUND_ARATE_VAR=11 val SCE_CSOUND_KRATE_VAR=12 val SCE_CSOUND_IRATE_VAR=13 val SCE_CSOUND_GLOBAL_VAR=14 val SCE_CSOUND_STRINGEOL=15 # Lexical states for SCLEX_INNOSETUP lex Inno=SCLEX_INNOSETUP SCE_INNO_ val SCE_INNO_DEFAULT=0 val SCE_INNO_COMMENT=1 val SCE_INNO_KEYWORD=2 val SCE_INNO_PARAMETER=3 val SCE_INNO_SECTION=4 val SCE_INNO_PREPROC=5 val SCE_INNO_INLINE_EXPANSION=6 val SCE_INNO_COMMENT_PASCAL=7 val SCE_INNO_KEYWORD_PASCAL=8 val SCE_INNO_KEYWORD_USER=9 val SCE_INNO_STRING_DOUBLE=10 val SCE_INNO_STRING_SINGLE=11 val SCE_INNO_IDENTIFIER=12 # Lexical states for SCLEX_OPAL lex Opal=SCLEX_OPAL SCE_OPAL_ val SCE_OPAL_SPACE=0 val SCE_OPAL_COMMENT_BLOCK=1 val SCE_OPAL_COMMENT_LINE=2 val SCE_OPAL_INTEGER=3 val SCE_OPAL_KEYWORD=4 val SCE_OPAL_SORT=5 val SCE_OPAL_STRING=6 val SCE_OPAL_PAR=7 val SCE_OPAL_BOOL_CONST=8 val SCE_OPAL_DEFAULT=32 # Lexical states for SCLEX_SPICE lex Spice=SCLEX_SPICE SCE_SPICE_ val SCE_SPICE_DEFAULT=0 val SCE_SPICE_IDENTIFIER=1 val SCE_SPICE_KEYWORD=2 val SCE_SPICE_KEYWORD2=3 val SCE_SPICE_KEYWORD3=4 val SCE_SPICE_NUMBER=5 val SCE_SPICE_DELIMITER=6 val SCE_SPICE_VALUE=7 val SCE_SPICE_COMMENTLINE=8 # Lexical states for SCLEX_CMAKE lex CMAKE=SCLEX_CMAKE SCE_CMAKE_ val SCE_CMAKE_DEFAULT=0 val SCE_CMAKE_COMMENT=1 val SCE_CMAKE_STRINGDQ=2 val SCE_CMAKE_STRINGLQ=3 val SCE_CMAKE_STRINGRQ=4 val SCE_CMAKE_COMMANDS=5 val SCE_CMAKE_PARAMETERS=6 val SCE_CMAKE_VARIABLE=7 val SCE_CMAKE_USERDEFINED=8 val SCE_CMAKE_WHILEDEF=9 val SCE_CMAKE_FOREACHDEF=10 val SCE_CMAKE_IFDEFINEDEF=11 val SCE_CMAKE_MACRODEF=12 val SCE_CMAKE_STRINGVAR=13 val SCE_CMAKE_NUMBER=14 # Lexical states for SCLEX_GAP lex Gap=SCLEX_GAP SCE_GAP_ val SCE_GAP_DEFAULT=0 val SCE_GAP_IDENTIFIER=1 val SCE_GAP_KEYWORD=2 val SCE_GAP_KEYWORD2=3 val SCE_GAP_KEYWORD3=4 val SCE_GAP_KEYWORD4=5 val SCE_GAP_STRING=6 val SCE_GAP_CHAR=7 val SCE_GAP_OPERATOR=8 val SCE_GAP_COMMENT=9 val SCE_GAP_NUMBER=10 val SCE_GAP_STRINGEOL=11 # Lexical state for SCLEX_PLM lex PLM=SCLEX_PLM SCE_PLM_ val SCE_PLM_DEFAULT=0 val SCE_PLM_COMMENT=1 val SCE_PLM_STRING=2 val SCE_PLM_NUMBER=3 val SCE_PLM_IDENTIFIER=4 val SCE_PLM_OPERATOR=5 val SCE_PLM_CONTROL=6 val SCE_PLM_KEYWORD=7 # Lexical state for SCLEX_PROGRESS lex Progress=SCLEX_PROGRESS SCE_ABL_ val SCE_ABL_DEFAULT=0 val SCE_ABL_NUMBER=1 val SCE_ABL_WORD=2 val SCE_ABL_STRING=3 val SCE_ABL_CHARACTER=4 val SCE_ABL_PREPROCESSOR=5 val SCE_ABL_OPERATOR=6 val SCE_ABL_IDENTIFIER=7 val SCE_ABL_BLOCK=8 val SCE_ABL_END=9 val SCE_ABL_COMMENT=10 val SCE_ABL_TASKMARKER=11 val SCE_ABL_LINECOMMENT=12 # Lexical states for SCLEX_ABAQUS lex ABAQUS=SCLEX_ABAQUS SCE_ABAQUS_ val SCE_ABAQUS_DEFAULT=0 val SCE_ABAQUS_COMMENT=1 val SCE_ABAQUS_COMMENTBLOCK=2 val SCE_ABAQUS_NUMBER=3 val SCE_ABAQUS_STRING=4 val SCE_ABAQUS_OPERATOR=5 val SCE_ABAQUS_WORD=6 val SCE_ABAQUS_PROCESSOR=7 val SCE_ABAQUS_COMMAND=8 val SCE_ABAQUS_SLASHCOMMAND=9 val SCE_ABAQUS_STARCOMMAND=10 val SCE_ABAQUS_ARGUMENT=11 val SCE_ABAQUS_FUNCTION=12 # Lexical states for SCLEX_ASYMPTOTE lex Asymptote=SCLEX_ASYMPTOTE SCE_ASY_ val SCE_ASY_DEFAULT=0 val SCE_ASY_COMMENT=1 val SCE_ASY_COMMENTLINE=2 val SCE_ASY_NUMBER=3 val SCE_ASY_WORD=4 val SCE_ASY_STRING=5 val SCE_ASY_CHARACTER=6 val SCE_ASY_OPERATOR=7 val SCE_ASY_IDENTIFIER=8 val SCE_ASY_STRINGEOL=9 val SCE_ASY_COMMENTLINEDOC=10 val SCE_ASY_WORD2=11 # Lexical states for SCLEX_R lex R=SCLEX_R SCE_R_ val SCE_R_DEFAULT=0 val SCE_R_COMMENT=1 val SCE_R_KWORD=2 val SCE_R_BASEKWORD=3 val SCE_R_OTHERKWORD=4 val SCE_R_NUMBER=5 val SCE_R_STRING=6 val SCE_R_STRING2=7 val SCE_R_OPERATOR=8 val SCE_R_IDENTIFIER=9 val SCE_R_INFIX=10 val SCE_R_INFIXEOL=11 # Lexical state for SCLEX_MAGIK lex MagikSF=SCLEX_MAGIK SCE_MAGIK_ val SCE_MAGIK_DEFAULT=0 val SCE_MAGIK_COMMENT=1 val SCE_MAGIK_HYPER_COMMENT=16 val SCE_MAGIK_STRING=2 val SCE_MAGIK_CHARACTER=3 val SCE_MAGIK_NUMBER=4 val SCE_MAGIK_IDENTIFIER=5 val SCE_MAGIK_OPERATOR=6 val SCE_MAGIK_FLOW=7 val SCE_MAGIK_CONTAINER=8 val SCE_MAGIK_BRACKET_BLOCK=9 val SCE_MAGIK_BRACE_BLOCK=10 val SCE_MAGIK_SQBRACKET_BLOCK=11 val SCE_MAGIK_UNKNOWN_KEYWORD=12 val SCE_MAGIK_KEYWORD=13 val SCE_MAGIK_PRAGMA=14 val SCE_MAGIK_SYMBOL=15 # Lexical state for SCLEX_POWERSHELL lex PowerShell=SCLEX_POWERSHELL SCE_POWERSHELL_ val SCE_POWERSHELL_DEFAULT=0 val SCE_POWERSHELL_COMMENT=1 val SCE_POWERSHELL_STRING=2 val SCE_POWERSHELL_CHARACTER=3 val SCE_POWERSHELL_NUMBER=4 val SCE_POWERSHELL_VARIABLE=5 val SCE_POWERSHELL_OPERATOR=6 val SCE_POWERSHELL_IDENTIFIER=7 val SCE_POWERSHELL_KEYWORD=8 val SCE_POWERSHELL_CMDLET=9 val SCE_POWERSHELL_ALIAS=10 val SCE_POWERSHELL_FUNCTION=11 val SCE_POWERSHELL_USER1=12 val SCE_POWERSHELL_COMMENTSTREAM=13 val SCE_POWERSHELL_HERE_STRING=14 val SCE_POWERSHELL_HERE_CHARACTER=15 val SCE_POWERSHELL_COMMENTDOCKEYWORD=16 # Lexical state for SCLEX_MYSQL lex MySQL=SCLEX_MYSQL SCE_MYSQL_ val SCE_MYSQL_DEFAULT=0 val SCE_MYSQL_COMMENT=1 val SCE_MYSQL_COMMENTLINE=2 val SCE_MYSQL_VARIABLE=3 val SCE_MYSQL_SYSTEMVARIABLE=4 val SCE_MYSQL_KNOWNSYSTEMVARIABLE=5 val SCE_MYSQL_NUMBER=6 val SCE_MYSQL_MAJORKEYWORD=7 val SCE_MYSQL_KEYWORD=8 val SCE_MYSQL_DATABASEOBJECT=9 val SCE_MYSQL_PROCEDUREKEYWORD=10 val SCE_MYSQL_STRING=11 val SCE_MYSQL_SQSTRING=12 val SCE_MYSQL_DQSTRING=13 val SCE_MYSQL_OPERATOR=14 val SCE_MYSQL_FUNCTION=15 val SCE_MYSQL_IDENTIFIER=16 val SCE_MYSQL_QUOTEDIDENTIFIER=17 val SCE_MYSQL_USER1=18 val SCE_MYSQL_USER2=19 val SCE_MYSQL_USER3=20 val SCE_MYSQL_HIDDENCOMMAND=21 val SCE_MYSQL_PLACEHOLDER=22 # Lexical state for SCLEX_PO lex Po=SCLEX_PO SCE_PO_ val SCE_PO_DEFAULT=0 val SCE_PO_COMMENT=1 val SCE_PO_MSGID=2 val SCE_PO_MSGID_TEXT=3 val SCE_PO_MSGSTR=4 val SCE_PO_MSGSTR_TEXT=5 val SCE_PO_MSGCTXT=6 val SCE_PO_MSGCTXT_TEXT=7 val SCE_PO_FUZZY=8 val SCE_PO_PROGRAMMER_COMMENT=9 val SCE_PO_REFERENCE=10 val SCE_PO_FLAGS=11 val SCE_PO_MSGID_TEXT_EOL=12 val SCE_PO_MSGSTR_TEXT_EOL=13 val SCE_PO_MSGCTXT_TEXT_EOL=14 val SCE_PO_ERROR=15 # Lexical states for SCLEX_PASCAL lex Pascal=SCLEX_PASCAL SCE_PAS_ val SCE_PAS_DEFAULT=0 val SCE_PAS_IDENTIFIER=1 val SCE_PAS_COMMENT=2 val SCE_PAS_COMMENT2=3 val SCE_PAS_COMMENTLINE=4 val SCE_PAS_PREPROCESSOR=5 val SCE_PAS_PREPROCESSOR2=6 val SCE_PAS_NUMBER=7 val SCE_PAS_HEXNUMBER=8 val SCE_PAS_WORD=9 val SCE_PAS_STRING=10 val SCE_PAS_STRINGEOL=11 val SCE_PAS_CHARACTER=12 val SCE_PAS_OPERATOR=13 val SCE_PAS_ASM=14 # Lexical state for SCLEX_SORCUS lex SORCUS=SCLEX_SORCUS SCE_SORCUS_ val SCE_SORCUS_DEFAULT=0 val SCE_SORCUS_COMMAND=1 val SCE_SORCUS_PARAMETER=2 val SCE_SORCUS_COMMENTLINE=3 val SCE_SORCUS_STRING=4 val SCE_SORCUS_STRINGEOL=5 val SCE_SORCUS_IDENTIFIER=6 val SCE_SORCUS_OPERATOR=7 val SCE_SORCUS_NUMBER=8 val SCE_SORCUS_CONSTANT=9 # Lexical state for SCLEX_POWERPRO lex PowerPro=SCLEX_POWERPRO SCE_POWERPRO_ val SCE_POWERPRO_DEFAULT=0 val SCE_POWERPRO_COMMENTBLOCK=1 val SCE_POWERPRO_COMMENTLINE=2 val SCE_POWERPRO_NUMBER=3 val SCE_POWERPRO_WORD=4 val SCE_POWERPRO_WORD2=5 val SCE_POWERPRO_WORD3=6 val SCE_POWERPRO_WORD4=7 val SCE_POWERPRO_DOUBLEQUOTEDSTRING=8 val SCE_POWERPRO_SINGLEQUOTEDSTRING=9 val SCE_POWERPRO_LINECONTINUE=10 val SCE_POWERPRO_OPERATOR=11 val SCE_POWERPRO_IDENTIFIER=12 val SCE_POWERPRO_STRINGEOL=13 val SCE_POWERPRO_VERBATIM=14 val SCE_POWERPRO_ALTQUOTE=15 val SCE_POWERPRO_FUNCTION=16 # Lexical states for SCLEX_SML lex SML=SCLEX_SML SCE_SML_ val SCE_SML_DEFAULT=0 val SCE_SML_IDENTIFIER=1 val SCE_SML_TAGNAME=2 val SCE_SML_KEYWORD=3 val SCE_SML_KEYWORD2=4 val SCE_SML_KEYWORD3=5 val SCE_SML_LINENUM=6 val SCE_SML_OPERATOR=7 val SCE_SML_NUMBER=8 val SCE_SML_CHAR=9 val SCE_SML_STRING=11 val SCE_SML_COMMENT=12 val SCE_SML_COMMENT1=13 val SCE_SML_COMMENT2=14 val SCE_SML_COMMENT3=15 # Lexical state for SCLEX_MARKDOWN lex Markdown=SCLEX_MARKDOWN SCE_MARKDOWN_ val SCE_MARKDOWN_DEFAULT=0 val SCE_MARKDOWN_LINE_BEGIN=1 val SCE_MARKDOWN_STRONG1=2 val SCE_MARKDOWN_STRONG2=3 val SCE_MARKDOWN_EM1=4 val SCE_MARKDOWN_EM2=5 val SCE_MARKDOWN_HEADER1=6 val SCE_MARKDOWN_HEADER2=7 val SCE_MARKDOWN_HEADER3=8 val SCE_MARKDOWN_HEADER4=9 val SCE_MARKDOWN_HEADER5=10 val SCE_MARKDOWN_HEADER6=11 val SCE_MARKDOWN_PRECHAR=12 val SCE_MARKDOWN_ULIST_ITEM=13 val SCE_MARKDOWN_OLIST_ITEM=14 val SCE_MARKDOWN_BLOCKQUOTE=15 val SCE_MARKDOWN_STRIKEOUT=16 val SCE_MARKDOWN_HRULE=17 val SCE_MARKDOWN_LINK=18 val SCE_MARKDOWN_CODE=19 val SCE_MARKDOWN_CODE2=20 val SCE_MARKDOWN_CODEBK=21 # Lexical state for SCLEX_TXT2TAGS lex Txt2tags=SCLEX_TXT2TAGS SCE_TXT2TAGS_ val SCE_TXT2TAGS_DEFAULT=0 val SCE_TXT2TAGS_LINE_BEGIN=1 val SCE_TXT2TAGS_STRONG1=2 val SCE_TXT2TAGS_STRONG2=3 val SCE_TXT2TAGS_EM1=4 val SCE_TXT2TAGS_EM2=5 val SCE_TXT2TAGS_HEADER1=6 val SCE_TXT2TAGS_HEADER2=7 val SCE_TXT2TAGS_HEADER3=8 val SCE_TXT2TAGS_HEADER4=9 val SCE_TXT2TAGS_HEADER5=10 val SCE_TXT2TAGS_HEADER6=11 val SCE_TXT2TAGS_PRECHAR=12 val SCE_TXT2TAGS_ULIST_ITEM=13 val SCE_TXT2TAGS_OLIST_ITEM=14 val SCE_TXT2TAGS_BLOCKQUOTE=15 val SCE_TXT2TAGS_STRIKEOUT=16 val SCE_TXT2TAGS_HRULE=17 val SCE_TXT2TAGS_LINK=18 val SCE_TXT2TAGS_CODE=19 val SCE_TXT2TAGS_CODE2=20 val SCE_TXT2TAGS_CODEBK=21 val SCE_TXT2TAGS_COMMENT=22 val SCE_TXT2TAGS_OPTION=23 val SCE_TXT2TAGS_PREPROC=24 val SCE_TXT2TAGS_POSTPROC=25 # Lexical states for SCLEX_A68K lex A68k=SCLEX_A68K SCE_A68K_ val SCE_A68K_DEFAULT=0 val SCE_A68K_COMMENT=1 val SCE_A68K_NUMBER_DEC=2 val SCE_A68K_NUMBER_BIN=3 val SCE_A68K_NUMBER_HEX=4 val SCE_A68K_STRING1=5 val SCE_A68K_OPERATOR=6 val SCE_A68K_CPUINSTRUCTION=7 val SCE_A68K_EXTINSTRUCTION=8 val SCE_A68K_REGISTER=9 val SCE_A68K_DIRECTIVE=10 val SCE_A68K_MACRO_ARG=11 val SCE_A68K_LABEL=12 val SCE_A68K_STRING2=13 val SCE_A68K_IDENTIFIER=14 val SCE_A68K_MACRO_DECLARATION=15 val SCE_A68K_COMMENT_WORD=16 val SCE_A68K_COMMENT_SPECIAL=17 val SCE_A68K_COMMENT_DOXYGEN=18 # Lexical states for SCLEX_MODULA lex Modula=SCLEX_MODULA SCE_MODULA_ val SCE_MODULA_DEFAULT=0 val SCE_MODULA_COMMENT=1 val SCE_MODULA_DOXYCOMM=2 val SCE_MODULA_DOXYKEY=3 val SCE_MODULA_KEYWORD=4 val SCE_MODULA_RESERVED=5 val SCE_MODULA_NUMBER=6 val SCE_MODULA_BASENUM=7 val SCE_MODULA_FLOAT=8 val SCE_MODULA_STRING=9 val SCE_MODULA_STRSPEC=10 val SCE_MODULA_CHAR=11 val SCE_MODULA_CHARSPEC=12 val SCE_MODULA_PROC=13 val SCE_MODULA_PRAGMA=14 val SCE_MODULA_PRGKEY=15 val SCE_MODULA_OPERATOR=16 val SCE_MODULA_BADSTR=17 # Lexical states for SCLEX_COFFEESCRIPT lex CoffeeScript=SCLEX_COFFEESCRIPT SCE_COFFEESCRIPT_ val SCE_COFFEESCRIPT_DEFAULT=0 val SCE_COFFEESCRIPT_COMMENT=1 val SCE_COFFEESCRIPT_COMMENTLINE=2 val SCE_COFFEESCRIPT_COMMENTDOC=3 val SCE_COFFEESCRIPT_NUMBER=4 val SCE_COFFEESCRIPT_WORD=5 val SCE_COFFEESCRIPT_STRING=6 val SCE_COFFEESCRIPT_CHARACTER=7 val SCE_COFFEESCRIPT_UUID=8 val SCE_COFFEESCRIPT_PREPROCESSOR=9 val SCE_COFFEESCRIPT_OPERATOR=10 val SCE_COFFEESCRIPT_IDENTIFIER=11 val SCE_COFFEESCRIPT_STRINGEOL=12 val SCE_COFFEESCRIPT_VERBATIM=13 val SCE_COFFEESCRIPT_REGEX=14 val SCE_COFFEESCRIPT_COMMENTLINEDOC=15 val SCE_COFFEESCRIPT_WORD2=16 val SCE_COFFEESCRIPT_COMMENTDOCKEYWORD=17 val SCE_COFFEESCRIPT_COMMENTDOCKEYWORDERROR=18 val SCE_COFFEESCRIPT_GLOBALCLASS=19 val SCE_COFFEESCRIPT_STRINGRAW=20 val SCE_COFFEESCRIPT_TRIPLEVERBATIM=21 val SCE_COFFEESCRIPT_COMMENTBLOCK=22 val SCE_COFFEESCRIPT_VERBOSE_REGEX=23 val SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT=24 val SCE_COFFEESCRIPT_INSTANCEPROPERTY=25 # Lexical states for SCLEX_AVS lex AVS=SCLEX_AVS SCE_AVS_ val SCE_AVS_DEFAULT=0 val SCE_AVS_COMMENTBLOCK=1 val SCE_AVS_COMMENTBLOCKN=2 val SCE_AVS_COMMENTLINE=3 val SCE_AVS_NUMBER=4 val SCE_AVS_OPERATOR=5 val SCE_AVS_IDENTIFIER=6 val SCE_AVS_STRING=7 val SCE_AVS_TRIPLESTRING=8 val SCE_AVS_KEYWORD=9 val SCE_AVS_FILTER=10 val SCE_AVS_PLUGIN=11 val SCE_AVS_FUNCTION=12 val SCE_AVS_CLIPPROP=13 val SCE_AVS_USERDFN=14 # Lexical states for SCLEX_ECL lex ECL=SCLEX_ECL SCE_ECL_ val SCE_ECL_DEFAULT=0 val SCE_ECL_COMMENT=1 val SCE_ECL_COMMENTLINE=2 val SCE_ECL_NUMBER=3 val SCE_ECL_STRING=4 val SCE_ECL_WORD0=5 val SCE_ECL_OPERATOR=6 val SCE_ECL_CHARACTER=7 val SCE_ECL_UUID=8 val SCE_ECL_PREPROCESSOR=9 val SCE_ECL_UNKNOWN=10 val SCE_ECL_IDENTIFIER=11 val SCE_ECL_STRINGEOL=12 val SCE_ECL_VERBATIM=13 val SCE_ECL_REGEX=14 val SCE_ECL_COMMENTLINEDOC=15 val SCE_ECL_WORD1=16 val SCE_ECL_COMMENTDOCKEYWORD=17 val SCE_ECL_COMMENTDOCKEYWORDERROR=18 val SCE_ECL_WORD2=19 val SCE_ECL_WORD3=20 val SCE_ECL_WORD4=21 val SCE_ECL_WORD5=22 val SCE_ECL_COMMENTDOC=23 val SCE_ECL_ADDED=24 val SCE_ECL_DELETED=25 val SCE_ECL_CHANGED=26 val SCE_ECL_MOVED=27 # Lexical states for SCLEX_OSCRIPT lex OScript=SCLEX_OSCRIPT SCE_OSCRIPT_ val SCE_OSCRIPT_DEFAULT=0 val SCE_OSCRIPT_LINE_COMMENT=1 val SCE_OSCRIPT_BLOCK_COMMENT=2 val SCE_OSCRIPT_DOC_COMMENT=3 val SCE_OSCRIPT_PREPROCESSOR=4 val SCE_OSCRIPT_NUMBER=5 val SCE_OSCRIPT_SINGLEQUOTE_STRING=6 val SCE_OSCRIPT_DOUBLEQUOTE_STRING=7 val SCE_OSCRIPT_CONSTANT=8 val SCE_OSCRIPT_IDENTIFIER=9 val SCE_OSCRIPT_GLOBAL=10 val SCE_OSCRIPT_KEYWORD=11 val SCE_OSCRIPT_OPERATOR=12 val SCE_OSCRIPT_LABEL=13 val SCE_OSCRIPT_TYPE=14 val SCE_OSCRIPT_FUNCTION=15 val SCE_OSCRIPT_OBJECT=16 val SCE_OSCRIPT_PROPERTY=17 val SCE_OSCRIPT_METHOD=18 # Lexical states for SCLEX_VISUALPROLOG lex VisualProlog=SCLEX_VISUALPROLOG SCE_VISUALPROLOG_ val SCE_VISUALPROLOG_DEFAULT=0 val SCE_VISUALPROLOG_KEY_MAJOR=1 val SCE_VISUALPROLOG_KEY_MINOR=2 val SCE_VISUALPROLOG_KEY_DIRECTIVE=3 val SCE_VISUALPROLOG_COMMENT_BLOCK=4 val SCE_VISUALPROLOG_COMMENT_LINE=5 val SCE_VISUALPROLOG_COMMENT_KEY=6 val SCE_VISUALPROLOG_COMMENT_KEY_ERROR=7 val SCE_VISUALPROLOG_IDENTIFIER=8 val SCE_VISUALPROLOG_VARIABLE=9 val SCE_VISUALPROLOG_ANONYMOUS=10 val SCE_VISUALPROLOG_NUMBER=11 val SCE_VISUALPROLOG_OPERATOR=12 val SCE_VISUALPROLOG_CHARACTER=13 val SCE_VISUALPROLOG_CHARACTER_TOO_MANY=14 val SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR=15 val SCE_VISUALPROLOG_STRING=16 val SCE_VISUALPROLOG_STRING_ESCAPE=17 val SCE_VISUALPROLOG_STRING_ESCAPE_ERROR=18 val SCE_VISUALPROLOG_STRING_EOL_OPEN=19 val SCE_VISUALPROLOG_STRING_VERBATIM=20 val SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL=21 val SCE_VISUALPROLOG_STRING_VERBATIM_EOL=22 # Lexical states for SCLEX_STTXT lex StructuredText=SCLEX_STTXT SCE_STTXT_ val SCE_STTXT_DEFAULT=0 val SCE_STTXT_COMMENT=1 val SCE_STTXT_COMMENTLINE=2 val SCE_STTXT_KEYWORD=3 val SCE_STTXT_TYPE=4 val SCE_STTXT_FUNCTION=5 val SCE_STTXT_FB=6 val SCE_STTXT_NUMBER=7 val SCE_STTXT_HEXNUMBER=8 val SCE_STTXT_PRAGMA=9 val SCE_STTXT_OPERATOR=10 val SCE_STTXT_CHARACTER=11 val SCE_STTXT_STRING1=12 val SCE_STTXT_STRING2=13 val SCE_STTXT_STRINGEOL=14 val SCE_STTXT_IDENTIFIER=15 val SCE_STTXT_DATETIME=16 val SCE_STTXT_VARS=17 val SCE_STTXT_PRAGMAS=18 # Lexical states for SCLEX_KVIRC lex KVIrc=SCLEX_KVIRC SCE_KVIRC_ val SCE_KVIRC_DEFAULT=0 val SCE_KVIRC_COMMENT=1 val SCE_KVIRC_COMMENTBLOCK=2 val SCE_KVIRC_STRING=3 val SCE_KVIRC_WORD=4 val SCE_KVIRC_KEYWORD=5 val SCE_KVIRC_FUNCTION_KEYWORD=6 val SCE_KVIRC_FUNCTION=7 val SCE_KVIRC_VARIABLE=8 val SCE_KVIRC_NUMBER=9 val SCE_KVIRC_OPERATOR=10 val SCE_KVIRC_STRING_FUNCTION=11 val SCE_KVIRC_STRING_VARIABLE=12 # Lexical states for SCLEX_RUST lex Rust=SCLEX_RUST SCE_RUST_ val SCE_RUST_DEFAULT=0 val SCE_RUST_COMMENTBLOCK=1 val SCE_RUST_COMMENTLINE=2 val SCE_RUST_COMMENTBLOCKDOC=3 val SCE_RUST_COMMENTLINEDOC=4 val SCE_RUST_NUMBER=5 val SCE_RUST_WORD=6 val SCE_RUST_WORD2=7 val SCE_RUST_WORD3=8 val SCE_RUST_WORD4=9 val SCE_RUST_WORD5=10 val SCE_RUST_WORD6=11 val SCE_RUST_WORD7=12 val SCE_RUST_STRING=13 val SCE_RUST_STRINGR=14 val SCE_RUST_CHARACTER=15 val SCE_RUST_OPERATOR=16 val SCE_RUST_IDENTIFIER=17 val SCE_RUST_LIFETIME=18 val SCE_RUST_MACRO=19 val SCE_RUST_LEXERROR=20 val SCE_RUST_BYTESTRING=21 val SCE_RUST_BYTESTRINGR=22 val SCE_RUST_BYTECHARACTER=23 # Lexical states for SCLEX_DMAP lex DMAP=SCLEX_DMAP SCE_DMAP_ val SCE_DMAP_DEFAULT=0 val SCE_DMAP_COMMENT=1 val SCE_DMAP_NUMBER=2 val SCE_DMAP_STRING1=3 val SCE_DMAP_STRING2=4 val SCE_DMAP_STRINGEOL=5 val SCE_DMAP_OPERATOR=6 val SCE_DMAP_IDENTIFIER=7 val SCE_DMAP_WORD=8 val SCE_DMAP_WORD2=9 val SCE_DMAP_WORD3=10 # Lexical states for SCLEX_DMIS lex DMIS=SCLEX_DMIS SCE_DMIS_ val SCE_DMIS_DEFAULT=0 val SCE_DMIS_COMMENT=1 val SCE_DMIS_STRING=2 val SCE_DMIS_NUMBER=3 val SCE_DMIS_KEYWORD=4 val SCE_DMIS_MAJORWORD=5 val SCE_DMIS_MINORWORD=6 val SCE_DMIS_UNSUPPORTED_MAJOR=7 val SCE_DMIS_UNSUPPORTED_MINOR=8 val SCE_DMIS_LABEL=9 # Lexical states for SCLEX_REGISTRY lex REG=SCLEX_REGISTRY SCE_REG_ val SCE_REG_DEFAULT=0 val SCE_REG_COMMENT=1 val SCE_REG_VALUENAME=2 val SCE_REG_STRING=3 val SCE_REG_HEXDIGIT=4 val SCE_REG_VALUETYPE=5 val SCE_REG_ADDEDKEY=6 val SCE_REG_DELETEDKEY=7 val SCE_REG_ESCAPED=8 val SCE_REG_KEYPATH_GUID=9 val SCE_REG_STRING_GUID=10 val SCE_REG_PARAMETER=11 val SCE_REG_OPERATOR=12 # Lexical state for SCLEX_BIBTEX lex BibTeX=SCLEX_BIBTEX SCE_BIBTEX_ val SCE_BIBTEX_DEFAULT=0 val SCE_BIBTEX_ENTRY=1 val SCE_BIBTEX_UNKNOWN_ENTRY=2 val SCE_BIBTEX_KEY=3 val SCE_BIBTEX_PARAMETER=4 val SCE_BIBTEX_VALUE=5 val SCE_BIBTEX_COMMENT=6 # Lexical state for SCLEX_SREC lex Srec=SCLEX_SREC SCE_HEX_ val SCE_HEX_DEFAULT=0 val SCE_HEX_RECSTART=1 val SCE_HEX_RECTYPE=2 val SCE_HEX_RECTYPE_UNKNOWN=3 val SCE_HEX_BYTECOUNT=4 val SCE_HEX_BYTECOUNT_WRONG=5 val SCE_HEX_NOADDRESS=6 val SCE_HEX_DATAADDRESS=7 val SCE_HEX_RECCOUNT=8 val SCE_HEX_STARTADDRESS=9 val SCE_HEX_ADDRESSFIELD_UNKNOWN=10 val SCE_HEX_EXTENDEDADDRESS=11 val SCE_HEX_DATA_ODD=12 val SCE_HEX_DATA_EVEN=13 val SCE_HEX_DATA_UNKNOWN=14 val SCE_HEX_DATA_EMPTY=15 val SCE_HEX_CHECKSUM=16 val SCE_HEX_CHECKSUM_WRONG=17 val SCE_HEX_GARBAGE=18 # Lexical state for SCLEX_IHEX (shared with Srec) lex IHex=SCLEX_IHEX SCE_HEX_ # Lexical state for SCLEX_TEHEX (shared with Srec) lex TEHex=SCLEX_TEHEX SCE_HEX_ # Lexical states for SCLEX_JSON lex JSON=SCLEX_JSON SCE_JSON_ val SCE_JSON_DEFAULT=0 val SCE_JSON_NUMBER=1 val SCE_JSON_STRING=2 val SCE_JSON_STRINGEOL=3 val SCE_JSON_PROPERTYNAME=4 val SCE_JSON_ESCAPESEQUENCE=5 val SCE_JSON_LINECOMMENT=6 val SCE_JSON_BLOCKCOMMENT=7 val SCE_JSON_OPERATOR=8 val SCE_JSON_URI=9 val SCE_JSON_COMPACTIRI=10 val SCE_JSON_KEYWORD=11 val SCE_JSON_LDKEYWORD=12 val SCE_JSON_ERROR=13 lex EDIFACT=SCLEX_EDIFACT SCE_EDI_ val SCE_EDI_DEFAULT=0 val SCE_EDI_SEGMENTSTART=1 val SCE_EDI_SEGMENTEND=2 val SCE_EDI_SEP_ELEMENT=3 val SCE_EDI_SEP_COMPOSITE=4 val SCE_EDI_SEP_RELEASE=5 val SCE_EDI_UNA=6 val SCE_EDI_UNH=7 val SCE_EDI_BADSEGMENT=8 # Lexical states for SCLEX_STATA lex STATA=SCLEX_STATA SCE_STATA_ val SCE_STATA_DEFAULT=0 val SCE_STATA_COMMENT=1 val SCE_STATA_COMMENTLINE=2 val SCE_STATA_COMMENTBLOCK=3 val SCE_STATA_NUMBER=4 val SCE_STATA_OPERATOR=5 val SCE_STATA_IDENTIFIER=6 val SCE_STATA_STRING=7 val SCE_STATA_TYPE=8 val SCE_STATA_WORD=9 val SCE_STATA_GLOBAL_MACRO=10 val SCE_STATA_MACRO=11 # Lexical states for SCLEX_SAS lex SAS=SCLEX_SAS SCE_SAS_ val SCE_SAS_DEFAULT=0 val SCE_SAS_COMMENT=1 val SCE_SAS_COMMENTLINE=2 val SCE_SAS_COMMENTBLOCK=3 val SCE_SAS_NUMBER=4 val SCE_SAS_OPERATOR=5 val SCE_SAS_IDENTIFIER=6 val SCE_SAS_STRING=7 val SCE_SAS_TYPE=8 val SCE_SAS_WORD=9 val SCE_SAS_GLOBAL_MACRO=10 val SCE_SAS_MACRO=11 val SCE_SAS_MACRO_KEYWORD=12 val SCE_SAS_BLOCK_KEYWORD=13 val SCE_SAS_MACRO_FUNCTION=14 val SCE_SAS_STATEMENT=15 # Events evt void StyleNeeded=2000(int position) evt void CharAdded=2001(int ch) evt void SavePointReached=2002(void) evt void SavePointLeft=2003(void) evt void ModifyAttemptRO=2004(void) # GTK+ Specific to work around focus and accelerator problems: evt void Key=2005(int ch, int modifiers) evt void DoubleClick=2006(int modifiers, int position, int line) evt void UpdateUI=2007(int updated) evt void Modified=2008(int position, int modificationType, string text, int length, int linesAdded, int line, int foldLevelNow, int foldLevelPrev, int token, int annotationLinesAdded) evt void MacroRecord=2009(int message, int wParam, int lParam) evt void MarginClick=2010(int modifiers, int position, int margin) evt void NeedShown=2011(int position, int length) evt void Painted=2013(void) evt void UserListSelection=2014(int listType, string text, int position, int ch, CompletionMethods listCompletionMethod) evt void URIDropped=2015(string text) evt void DwellStart=2016(int position, int x, int y) evt void DwellEnd=2017(int position, int x, int y) evt void Zoom=2018(void) evt void HotSpotClick=2019(int modifiers, int position) evt void HotSpotDoubleClick=2020(int modifiers, int position) evt void CallTipClick=2021(int position) evt void AutoCSelection=2022(string text, int position, int ch, CompletionMethods listCompletionMethod) evt void IndicatorClick=2023(int modifiers, int position) evt void IndicatorRelease=2024(int modifiers, int position) evt void AutoCCancelled=2025(void) evt void AutoCCharDeleted=2026(void) evt void HotSpotReleaseClick=2027(int modifiers, int position) evt void FocusIn=2028(void) evt void FocusOut=2029(void) evt void AutoCCompleted=2030(string text, int position, int ch, CompletionMethods listCompletionMethod) evt void MarginRightClick=2031(int modifiers, int position, int margin) evt void AutoCSelectionChange=2032(int listType, string text, int position) cat Provisional enu LineCharacterIndexType=SC_LINECHARACTERINDEX_ val SC_LINECHARACTERINDEX_NONE=0 val SC_LINECHARACTERINDEX_UTF32=1 val SC_LINECHARACTERINDEX_UTF16=2 # Retrieve line character index state. get int GetLineCharacterIndex=2710(,) # Request line character index be created or its use count increased. fun void AllocateLineCharacterIndex=2711(int lineCharacterIndex,) # Decrease use count of line character index and remove if 0. fun void ReleaseLineCharacterIndex=2712(int lineCharacterIndex,) # Retrieve the document line containing a position measured in index units. fun int LineFromIndexPosition=2713(position pos, int lineCharacterIndex) # Retrieve the position measured in index units at the start of a document line. fun position IndexPositionFromLine=2714(int line, int lineCharacterIndex) cat Deprecated # Divide each styling byte into lexical class bits (default: 5) and indicator # bits (default: 3). If a lexer requires more than 32 lexical states, then this # is used to expand the possible states. set void SetStyleBits=2090(int bits,) # Retrieve number of bits in style bytes used to hold the lexical state. get int GetStyleBits=2091(,) # Retrieve the number of bits the current lexer needs for styling. get int GetStyleBitsNeeded=4011(,) # Deprecated in 3.5.5 # Always interpret keyboard input as Unicode set void SetKeysUnicode=2521(bool keysUnicode,) # Are keys always interpreted as Unicode? get bool GetKeysUnicode=2522(,) sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/include/ScintillaWidget.h000066400000000000000000000051261463772530400276560ustar00rootroot00000000000000/* Scintilla source code edit control */ /* @file ScintillaWidget.h * Definition of Scintilla widget for GTK+. * Only needed by GTK+ code but is harmless on other platforms. * This comment is not a doc-comment as that causes warnings from g-ir-scanner. */ /* Copyright 1998-2001 by Neil Hodgson * The License.txt file describes the conditions under which this software may be distributed. */ #ifndef SCINTILLAWIDGET_H #define SCINTILLAWIDGET_H #if defined(GTK) #ifdef __cplusplus extern "C" { #endif #define SCINTILLA(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, scintilla_get_type (), ScintillaObject) #define SCINTILLA_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, scintilla_get_type (), ScintillaClass) #define IS_SCINTILLA(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, scintilla_get_type ()) #define SCINTILLA_TYPE_OBJECT (scintilla_object_get_type()) #define SCINTILLA_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SCINTILLA_TYPE_OBJECT, ScintillaObject)) #define SCINTILLA_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SCINTILLA_TYPE_OBJECT)) #define SCINTILLA_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SCINTILLA_TYPE_OBJECT, ScintillaObjectClass)) #define SCINTILLA_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SCINTILLA_TYPE_OBJECT)) #define SCINTILLA_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), SCINTILLA_TYPE_OBJECT, ScintillaObjectClass)) typedef struct _ScintillaObject ScintillaObject; typedef struct _ScintillaClass ScintillaObjectClass; struct _ScintillaObject { GtkContainer cont; void *pscin; }; struct _ScintillaClass { GtkContainerClass parent_class; void (* command) (ScintillaObject *sci, int cmd, GtkWidget *window); void (* notify) (ScintillaObject *sci, int id, SCNotification *scn); }; GType scintilla_object_get_type (void); GtkWidget* scintilla_object_new (void); gintptr scintilla_object_send_message (ScintillaObject *sci, unsigned int iMessage, guintptr wParam, gintptr lParam); GType scnotification_get_type (void); #define SCINTILLA_TYPE_NOTIFICATION (scnotification_get_type()) #ifndef G_IR_SCANNING /* The legacy names confuse the g-ir-scanner program */ typedef struct _ScintillaClass ScintillaClass; GType scintilla_get_type (void); GtkWidget* scintilla_new (void); void scintilla_set_id (ScintillaObject *sci, uptr_t id); sptr_t scintilla_send_message (ScintillaObject *sci,unsigned int iMessage, uptr_t wParam, sptr_t lParam); void scintilla_release_resources(void); #endif #define SCINTILLA_NOTIFY "sci-notify" #ifdef __cplusplus } #endif #endif #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexers/000077500000000000000000000000001463772530400242725ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexers/LexHTML.cpp000066400000000000000000002376541463772530400262340ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexHTML.cxx ** Lexer for HTML. **/ // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "StringCopy.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #include "OptionSet.h" #include "DefaultLexer.h" using namespace Scintilla; namespace { #define SCE_HA_JS (SCE_HJA_START - SCE_HJ_START) #define SCE_HA_VBS (SCE_HBA_START - SCE_HB_START) #define SCE_HA_PYTHON (SCE_HPA_START - SCE_HP_START) enum script_type { eScriptNone = 0, eScriptJS, eScriptVBS, eScriptPython, eScriptPHP, eScriptXML, eScriptSGML, eScriptSGMLblock, eScriptComment }; enum script_mode { eHtml = 0, eNonHtmlScript, eNonHtmlPreProc, eNonHtmlScriptPreProc }; inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_'); } inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } inline bool IsOperator(int ch) { if (IsASCII(ch) && isalnum(ch)) return false; // '.' left out as it is used to make up numbers if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || ch == '(' || ch == ')' || ch == '-' || ch == '+' || ch == '=' || ch == '|' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == ':' || ch == ';' || ch == '<' || ch == '>' || ch == ',' || ch == '/' || ch == '?' || ch == '!' || ch == '.' || ch == '~') return true; return false; } void GetTextSegment(Accessor &styler, Sci_PositionU start, Sci_PositionU end, char *s, size_t len) { Sci_PositionU i = 0; for (; (i < end - start + 1) && (i < len-1); i++) { s[i] = MakeLowerCase(styler[start + i]); } s[i] = '\0'; } std::string GetStringSegment(Accessor &styler, Sci_PositionU start, Sci_PositionU end) { std::string s; Sci_PositionU i = 0; for (; (i < end - start + 1); i++) { s.push_back(MakeLowerCase(styler[start + i])); } return s; } std::string GetNextWord(Accessor &styler, Sci_PositionU start) { std::string ret; Sci_PositionU i = 0; for (; i < 200; i++) { // Put an upper limit to bound time taken for unexpected text. const char ch = styler.SafeGetCharAt(start + i); if ((i == 0) && !IsAWordStart(ch)) break; if ((i > 0) && !IsAWordChar(ch)) break; ret.push_back(ch); } return ret; } script_type segIsScriptingIndicator(Accessor &styler, Sci_PositionU start, Sci_PositionU end, script_type prevValue) { char s[100]; GetTextSegment(styler, start, end, s, sizeof(s)); //Platform::DebugPrintf("Scripting indicator [%s]\n", s); if (strstr(s, "src")) // External script return eScriptNone; if (strstr(s, "vbs")) return eScriptVBS; if (strstr(s, "pyth")) return eScriptPython; if (strstr(s, "javas")) return eScriptJS; if (strstr(s, "jscr")) return eScriptJS; if (strstr(s, "php")) return eScriptPHP; if (strstr(s, "xml")) { const char *xml = strstr(s, "xml"); for (const char *t=s; t= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) { return eScriptPython; } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) { return eScriptVBS; } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) { return eScriptJS; } else if ((state >= SCE_HPHP_DEFAULT) && (state <= SCE_HPHP_COMMENTLINE)) { return eScriptPHP; } else if ((state >= SCE_H_SGML_DEFAULT) && (state < SCE_H_SGML_BLOCK_DEFAULT)) { return eScriptSGML; } else if (state == SCE_H_SGML_BLOCK_DEFAULT) { return eScriptSGMLblock; } else { return eScriptNone; } } int statePrintForState(int state, script_mode inScriptType) { int StateToPrint = state; if (state >= SCE_HJ_START) { if ((state >= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) { StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_PYTHON); } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) { StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_VBS); } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) { StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_JS); } } return StateToPrint; } int stateForPrintState(int StateToPrint) { int state; if ((StateToPrint >= SCE_HPA_START) && (StateToPrint <= SCE_HPA_IDENTIFIER)) { state = StateToPrint - SCE_HA_PYTHON; } else if ((StateToPrint >= SCE_HBA_START) && (StateToPrint <= SCE_HBA_STRINGEOL)) { state = StateToPrint - SCE_HA_VBS; } else if ((StateToPrint >= SCE_HJA_START) && (StateToPrint <= SCE_HJA_REGEX)) { state = StateToPrint - SCE_HA_JS; } else { state = StateToPrint; } return state; } inline bool IsNumber(Sci_PositionU start, Accessor &styler) { return IsADigit(styler[start]) || (styler[start] == '.') || (styler[start] == '-') || (styler[start] == '#'); } inline bool isStringState(int state) { bool bResult; switch (state) { case SCE_HJ_DOUBLESTRING: case SCE_HJ_SINGLESTRING: case SCE_HJA_DOUBLESTRING: case SCE_HJA_SINGLESTRING: case SCE_HB_STRING: case SCE_HBA_STRING: case SCE_HP_STRING: case SCE_HP_CHARACTER: case SCE_HP_TRIPLE: case SCE_HP_TRIPLEDOUBLE: case SCE_HPA_STRING: case SCE_HPA_CHARACTER: case SCE_HPA_TRIPLE: case SCE_HPA_TRIPLEDOUBLE: case SCE_HPHP_HSTRING: case SCE_HPHP_SIMPLESTRING: case SCE_HPHP_HSTRING_VARIABLE: case SCE_HPHP_COMPLEX_VARIABLE: bResult = true; break; default : bResult = false; break; } return bResult; } inline bool stateAllowsTermination(int state) { bool allowTermination = !isStringState(state); if (allowTermination) { switch (state) { case SCE_HB_COMMENTLINE: case SCE_HPHP_COMMENT: case SCE_HP_COMMENTLINE: case SCE_HPA_COMMENTLINE: allowTermination = false; } } return allowTermination; } // not really well done, since it's only comments that should lex the %> and <% inline bool isCommentASPState(int state) { bool bResult; switch (state) { case SCE_HJ_COMMENT: case SCE_HJ_COMMENTLINE: case SCE_HJ_COMMENTDOC: case SCE_HB_COMMENTLINE: case SCE_HP_COMMENTLINE: case SCE_HPHP_COMMENT: case SCE_HPHP_COMMENTLINE: bResult = true; break; default : bResult = false; break; } return bResult; } void classifyAttribHTML(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler) { const bool wordIsNumber = IsNumber(start, styler); char chAttr = SCE_H_ATTRIBUTEUNKNOWN; if (wordIsNumber) { chAttr = SCE_H_NUMBER; } else { std::string s = GetStringSegment(styler, start, end); if (keywords.InList(s.c_str())) chAttr = SCE_H_ATTRIBUTE; } if ((chAttr == SCE_H_ATTRIBUTEUNKNOWN) && !keywords) // No keywords -> all are known chAttr = SCE_H_ATTRIBUTE; styler.ColourTo(end, chAttr); } int classifyTagHTML(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler, bool &tagDontFold, bool caseSensitive, bool isXml, bool allowScripts, const std::set &nonFoldingTags) { std::string tag; // Copy after the '<' for (Sci_PositionU cPos = start; cPos <= end; cPos++) { const char ch = styler[cPos]; if ((ch != '<') && (ch != '/')) { tag.push_back(caseSensitive ? ch : MakeLowerCase(ch)); } } // if the current language is XML, I can fold any tag // if the current language is HTML, I don't want to fold certain tags (input, meta, etc.) //...to find it in the list of no-container-tags tagDontFold = (!isXml) && (nonFoldingTags.count(tag) > 0); // No keywords -> all are known char chAttr = SCE_H_TAGUNKNOWN; if (!tag.empty() && (tag[0] == '!')) { chAttr = SCE_H_SGML_DEFAULT; } else if (!keywords || keywords.InList(tag.c_str())) { chAttr = SCE_H_TAG; } styler.ColourTo(end, chAttr); if (chAttr == SCE_H_TAG) { if (allowScripts && (tag == "script")) { // check to see if this is a self-closing tag by sniffing ahead bool isSelfClose = false; for (Sci_PositionU cPos = end; cPos <= end + 200; cPos++) { const char ch = styler.SafeGetCharAt(cPos, '\0'); if (ch == '\0' || ch == '>') break; else if (ch == '/' && styler.SafeGetCharAt(cPos + 1, '\0') == '>') { isSelfClose = true; break; } } // do not enter a script state if the tag self-closed if (!isSelfClose) chAttr = SCE_H_SCRIPT; } else if (!isXml && (tag == "comment")) { chAttr = SCE_H_COMMENT; } } return chAttr; } void classifyWordHTJS(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler, script_mode inScriptType) { char s[30 + 1]; Sci_PositionU i = 0; for (; i < end - start + 1 && i < 30; i++) { s[i] = styler[start + i]; } s[i] = '\0'; char chAttr = SCE_HJ_WORD; const bool wordIsNumber = IsADigit(s[0]) || ((s[0] == '.') && IsADigit(s[1])); if (wordIsNumber) { chAttr = SCE_HJ_NUMBER; } else if (keywords.InList(s)) { chAttr = SCE_HJ_KEYWORD; } styler.ColourTo(end, statePrintForState(chAttr, inScriptType)); } int classifyWordHTVB(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler, script_mode inScriptType) { char chAttr = SCE_HB_IDENTIFIER; const bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.'); if (wordIsNumber) { chAttr = SCE_HB_NUMBER; } else { std::string s = GetStringSegment(styler, start, end); if (keywords.InList(s.c_str())) { chAttr = SCE_HB_WORD; if (s == "rem") chAttr = SCE_HB_COMMENTLINE; } } styler.ColourTo(end, statePrintForState(chAttr, inScriptType)); if (chAttr == SCE_HB_COMMENTLINE) return SCE_HB_COMMENTLINE; else return SCE_HB_DEFAULT; } void classifyWordHTPy(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler, std::string &prevWord, script_mode inScriptType, bool isMako) { const bool wordIsNumber = IsADigit(styler[start]); std::string s; for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) { s.push_back(styler[start + i]); } char chAttr = SCE_HP_IDENTIFIER; if (prevWord == "class") chAttr = SCE_HP_CLASSNAME; else if (prevWord == "def") chAttr = SCE_HP_DEFNAME; else if (wordIsNumber) chAttr = SCE_HP_NUMBER; else if (keywords.InList(s.c_str())) chAttr = SCE_HP_WORD; else if (isMako && (s == "block")) chAttr = SCE_HP_WORD; styler.ColourTo(end, statePrintForState(chAttr, inScriptType)); prevWord = s; } // Update the word colour to default or keyword // Called when in a PHP word void classifyWordHTPHP(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler) { char chAttr = SCE_HPHP_DEFAULT; const bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.' && start+1 <= end && IsADigit(styler[start+1])); if (wordIsNumber) { chAttr = SCE_HPHP_NUMBER; } else { std::string s = GetStringSegment(styler, start, end); if (keywords.InList(s.c_str())) chAttr = SCE_HPHP_WORD; } styler.ColourTo(end, chAttr); } bool isWordHSGML(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler) { std::string s; for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) { s.push_back(styler[start + i]); } return keywords.InList(s.c_str()); } bool isWordCdata(Sci_PositionU start, Sci_PositionU end, Accessor &styler) { std::string s; for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) { s.push_back(styler[start + i]); } return s == "[CDATA["; } // Return the first state to reach when entering a scripting language int StateForScript(script_type scriptLanguage) { int Result; switch (scriptLanguage) { case eScriptVBS: Result = SCE_HB_START; break; case eScriptPython: Result = SCE_HP_START; break; case eScriptPHP: Result = SCE_HPHP_DEFAULT; break; case eScriptXML: Result = SCE_H_TAGUNKNOWN; break; case eScriptSGML: Result = SCE_H_SGML_DEFAULT; break; case eScriptComment: Result = SCE_H_COMMENT; break; default : Result = SCE_HJ_START; break; } return Result; } inline bool issgmlwordchar(int ch) { return !IsASCII(ch) || (isalnum(ch) || ch == '.' || ch == '_' || ch == ':' || ch == '!' || ch == '#' || ch == '['); } inline bool IsPhpWordStart(int ch) { return (IsASCII(ch) && (isalpha(ch) || (ch == '_'))) || (ch >= 0x7f); } inline bool IsPhpWordChar(int ch) { return IsADigit(ch) || IsPhpWordStart(ch); } bool InTagState(int state) { return state == SCE_H_TAG || state == SCE_H_TAGUNKNOWN || state == SCE_H_SCRIPT || state == SCE_H_ATTRIBUTE || state == SCE_H_ATTRIBUTEUNKNOWN || state == SCE_H_NUMBER || state == SCE_H_OTHER || state == SCE_H_DOUBLESTRING || state == SCE_H_SINGLESTRING; } bool IsCommentState(const int state) { return state == SCE_H_COMMENT || state == SCE_H_SGML_COMMENT; } bool IsScriptCommentState(const int state) { return state == SCE_HJ_COMMENT || state == SCE_HJ_COMMENTLINE || state == SCE_HJA_COMMENT || state == SCE_HJA_COMMENTLINE || state == SCE_HB_COMMENTLINE || state == SCE_HBA_COMMENTLINE; } bool isLineEnd(int ch) { return ch == '\r' || ch == '\n'; } bool isMakoBlockEnd(const int ch, const int chNext, const std::string &blockType) { if (blockType.empty()) { return ((ch == '%') && (chNext == '>')); } else if ((blockType == "inherit") || (blockType == "namespace") || (blockType == "include") || (blockType == "page")) { return ((ch == '/') && (chNext == '>')); } else if (blockType == "%") { if (ch == '/' && isLineEnd(chNext)) return true; else return isLineEnd(ch); } else if (blockType == "{") { return ch == '}'; } else { return (ch == '>'); } } bool isDjangoBlockEnd(const int ch, const int chNext, const std::string &blockType) { if (blockType.empty()) { return false; } else if (blockType == "%") { return ((ch == '%') && (chNext == '}')); } else if (blockType == "{") { return ((ch == '}') && (chNext == '}')); } else { return false; } } bool isPHPStringState(int state) { return (state == SCE_HPHP_HSTRING) || (state == SCE_HPHP_SIMPLESTRING) || (state == SCE_HPHP_HSTRING_VARIABLE) || (state == SCE_HPHP_COMPLEX_VARIABLE); } Sci_Position FindPhpStringDelimiter(std::string &phpStringDelimiter, Sci_Position i, const Sci_Position lengthDoc, Accessor &styler, bool &isSimpleString) { Sci_Position j; const Sci_Position beginning = i - 1; bool isValidSimpleString = false; while (i < lengthDoc && (styler[i] == ' ' || styler[i] == '\t')) i++; char ch = styler.SafeGetCharAt(i); const char chNext = styler.SafeGetCharAt(i + 1); phpStringDelimiter.clear(); if (!IsPhpWordStart(ch)) { if (ch == '\'' && IsPhpWordStart(chNext)) { i++; ch = chNext; isSimpleString = true; } else { return beginning; } } phpStringDelimiter.push_back(ch); i++; for (j = i; j < lengthDoc && !isLineEnd(styler[j]); j++) { if (!IsPhpWordChar(styler[j])) { if (isSimpleString && (styler[j] == '\'') && isLineEnd(styler.SafeGetCharAt(j + 1))) { isValidSimpleString = true; j++; break; } else { phpStringDelimiter.clear(); return beginning; } } phpStringDelimiter.push_back(styler[j]); } if (isSimpleString && !isValidSimpleString) { phpStringDelimiter.clear(); return beginning; } return j - 1; } // Options used for LexerHTML struct OptionsHTML { int aspDefaultLanguage = eScriptJS; bool caseSensitive = false; bool allowScripts = true; bool isMako = false; bool isDjango = false; bool fold = false; bool foldHTML = false; bool foldHTMLPreprocessor = true; bool foldCompact = true; bool foldComment = false; bool foldHeredoc = false; OptionsHTML() noexcept { } }; const char * const htmlWordListDesc[] = { "HTML elements and attributes", "JavaScript keywords", "VBScript keywords", "Python keywords", "PHP keywords", "SGML and DTD keywords", 0, }; const char * const phpscriptWordListDesc[] = { "", //Unused "", //Unused "", //Unused "", //Unused "PHP keywords", "", //Unused 0, }; struct OptionSetHTML : public OptionSet { OptionSetHTML(bool isPHPScript_) { DefineProperty("asp.default.language", &OptionsHTML::aspDefaultLanguage, "Script in ASP code is initially assumed to be in JavaScript. " "To change this to VBScript set asp.default.language to 2. Python is 3."); DefineProperty("html.tags.case.sensitive", &OptionsHTML::caseSensitive, "For XML and HTML, setting this property to 1 will make tags match in a case " "sensitive way which is the expected behaviour for XML and XHTML."); DefineProperty("lexer.xml.allow.scripts", &OptionsHTML::allowScripts, "Set to 0 to disable scripts in XML."); DefineProperty("lexer.html.mako", &OptionsHTML::isMako, "Set to 1 to enable the mako template language."); DefineProperty("lexer.html.django", &OptionsHTML::isDjango, "Set to 1 to enable the django template language."); DefineProperty("fold", &OptionsHTML::fold); DefineProperty("fold.html", &OptionsHTML::foldHTML, "Folding is turned on or off for HTML and XML files with this option. " "The fold option must also be on for folding to occur."); DefineProperty("fold.html.preprocessor", &OptionsHTML::foldHTMLPreprocessor, "Folding is turned on or off for scripts embedded in HTML files with this option. " "The default is on."); DefineProperty("fold.compact", &OptionsHTML::foldCompact); DefineProperty("fold.hypertext.comment", &OptionsHTML::foldComment, "Allow folding for comments in scripts embedded in HTML. " "The default is off."); DefineProperty("fold.hypertext.heredoc", &OptionsHTML::foldHeredoc, "Allow folding for heredocs in scripts embedded in HTML. " "The default is off."); DefineWordListSets(isPHPScript_ ? phpscriptWordListDesc : htmlWordListDesc); } }; LexicalClass lexicalClassesHTML[] = { // Lexer HTML SCLEX_HTML SCE_H_ SCE_HJ_ SCE_HJA_ SCE_HB_ SCE_HBA_ SCE_HP_ SCE_HPHP_ SCE_HPA_: 0, "SCE_H_DEFAULT", "default", "Text", 1, "SCE_H_TAG", "tag", "Tags", 2, "SCE_H_ERRORTAGUNKNOWN", "error tag", "Unknown Tags", 3, "SCE_H_ATTRIBUTE", "attribute", "Attributes", 4, "SCE_H_ATTRIBUTEUNKNOWN", "error attribute", "Unknown Attributes", 5, "SCE_H_NUMBER", "literal numeric", "Numbers", 6, "SCE_H_DOUBLESTRING", "literal string", "Double quoted strings", 7, "SCE_H_SINGLESTRING", "literal string", "Single quoted strings", 8, "SCE_H_OTHER", "tag operator", "Other inside tag, including space and '='", 9, "SCE_H_COMMENT", "comment", "Comment", 10, "SCE_H_ENTITY", "literal", "Entities", 11, "SCE_H_TAGEND", "tag", "XML style tag ends '/>'", 12, "SCE_H_XMLSTART", "identifier", "XML identifier start ''", 14, "SCE_H_SCRIPT", "error", "Internal state which should never be visible", 15, "SCE_H_ASP", "preprocessor", "ASP <% ... %>", 16, "SCE_H_ASPAT", "preprocessor", "ASP <% ... %>", 17, "SCE_H_CDATA", "literal", "CDATA", 18, "SCE_H_QUESTION", "preprocessor", "PHP", 19, "SCE_H_VALUE", "literal string", "Unquoted values", 20, "SCE_H_XCCOMMENT", "comment", "JSP Comment <%-- ... --%>", 21, "SCE_H_SGML_DEFAULT", "default", "SGML tags ", 22, "SCE_H_SGML_COMMAND", "preprocessor", "SGML command", 23, "SCE_H_SGML_1ST_PARAM", "preprocessor", "SGML 1st param", 24, "SCE_H_SGML_DOUBLESTRING", "literal string", "SGML double string", 25, "SCE_H_SGML_SIMPLESTRING", "literal string", "SGML single string", 26, "SCE_H_SGML_ERROR", "error", "SGML error", 27, "SCE_H_SGML_SPECIAL", "literal", "SGML special (#XXXX type)", 28, "SCE_H_SGML_ENTITY", "literal", "SGML entity", 29, "SCE_H_SGML_COMMENT", "comment", "SGML comment", 30, "SCE_H_SGML_1ST_PARAM_COMMENT", "error comment", "SGML first parameter - lexer internal. It is an error if any text is in this style.", 31, "SCE_H_SGML_BLOCK_DEFAULT", "default", "SGML block", 32, "", "predefined", "", 33, "", "predefined", "", 34, "", "predefined", "", 35, "", "predefined", "", 36, "", "predefined", "", 37, "", "predefined", "", 38, "", "predefined", "", 39, "", "predefined", "", 40, "SCE_HJ_START", "client javascript default", "JS Start - allows eol filled background to not start on same line as SCRIPT tag", 41, "SCE_HJ_DEFAULT", "client javascript default", "JS Default", 42, "SCE_HJ_COMMENT", "client javascript comment", "JS Comment", 43, "SCE_HJ_COMMENTLINE", "client javascript comment line", "JS Line Comment", 44, "SCE_HJ_COMMENTDOC", "client javascript comment documentation", "JS Doc comment", 45, "SCE_HJ_NUMBER", "client javascript literal numeric", "JS Number", 46, "SCE_HJ_WORD", "client javascript identifier", "JS Word", 47, "SCE_HJ_KEYWORD", "client javascript keyword", "JS Keyword", 48, "SCE_HJ_DOUBLESTRING", "client javascript literal string", "JS Double quoted string", 49, "SCE_HJ_SINGLESTRING", "client javascript literal string", "JS Single quoted string", 50, "SCE_HJ_SYMBOLS", "client javascript operator", "JS Symbols", 51, "SCE_HJ_STRINGEOL", "client javascript error literal string", "JavaScript EOL", 52, "SCE_HJ_REGEX", "client javascript literal regex", "JavaScript RegEx", 53, "", "unused", "", 54, "", "unused", "", 55, "SCE_HJA_START", "server javascript default", "JS Start - allows eol filled background to not start on same line as SCRIPT tag", 56, "SCE_HJA_DEFAULT", "server javascript default", "JS Default", 57, "SCE_HJA_COMMENT", "server javascript comment", "JS Comment", 58, "SCE_HJA_COMMENTLINE", "server javascript comment line", "JS Line Comment", 59, "SCE_HJA_COMMENTDOC", "server javascript comment documentation", "JS Doc comment", 60, "SCE_HJA_NUMBER", "server javascript literal numeric", "JS Number", 61, "SCE_HJA_WORD", "server javascript identifier", "JS Word", 62, "SCE_HJA_KEYWORD", "server javascript keyword", "JS Keyword", 63, "SCE_HJA_DOUBLESTRING", "server javascript literal string", "JS Double quoted string", 64, "SCE_HJA_SINGLESTRING", "server javascript literal string", "JS Single quoted string", 65, "SCE_HJA_SYMBOLS", "server javascript operator", "JS Symbols", 66, "SCE_HJA_STRINGEOL", "server javascript error literal string", "JavaScript EOL", 67, "SCE_HJA_REGEX", "server javascript literal regex", "JavaScript RegEx", 68, "", "unused", "", 69, "", "unused", "", 70, "SCE_HB_START", "client basic default", "Start", 71, "SCE_HB_DEFAULT", "client basic default", "Default", 72, "SCE_HB_COMMENTLINE", "client basic comment line", "Comment", 73, "SCE_HB_NUMBER", "client basic literal numeric", "Number", 74, "SCE_HB_WORD", "client basic keyword", "KeyWord", 75, "SCE_HB_STRING", "client basic literal string", "String", 76, "SCE_HB_IDENTIFIER", "client basic identifier", "Identifier", 77, "SCE_HB_STRINGEOL", "client basic literal string", "Unterminated string", 78, "", "unused", "", 79, "", "unused", "", 80, "SCE_HBA_START", "server basic default", "Start", 81, "SCE_HBA_DEFAULT", "server basic default", "Default", 82, "SCE_HBA_COMMENTLINE", "server basic comment line", "Comment", 83, "SCE_HBA_NUMBER", "server basic literal numeric", "Number", 84, "SCE_HBA_WORD", "server basic keyword", "KeyWord", 85, "SCE_HBA_STRING", "server basic literal string", "String", 86, "SCE_HBA_IDENTIFIER", "server basic identifier", "Identifier", 87, "SCE_HBA_STRINGEOL", "server basic literal string", "Unterminated string", 88, "", "unused", "", 89, "", "unused", "", 90, "SCE_HP_START", "client python default", "Embedded Python", 91, "SCE_HP_DEFAULT", "client python default", "Embedded Python", 92, "SCE_HP_COMMENTLINE", "client python comment line", "Comment", 93, "SCE_HP_NUMBER", "client python literal numeric", "Number", 94, "SCE_HP_STRING", "client python literal string", "String", 95, "SCE_HP_CHARACTER", "client python literal string character", "Single quoted string", 96, "SCE_HP_WORD", "client python keyword", "Keyword", 97, "SCE_HP_TRIPLE", "client python literal string", "Triple quotes", 98, "SCE_HP_TRIPLEDOUBLE", "client python literal string", "Triple double quotes", 99, "SCE_HP_CLASSNAME", "client python identifier", "Class name definition", 100, "SCE_HP_DEFNAME", "client python identifier", "Function or method name definition", 101, "SCE_HP_OPERATOR", "client python operator", "Operators", 102, "SCE_HP_IDENTIFIER", "client python identifier", "Identifiers", 103, "", "unused", "", 104, "SCE_HPHP_COMPLEX_VARIABLE", "server php identifier", "PHP complex variable", 105, "SCE_HPA_START", "server python default", "ASP Python", 106, "SCE_HPA_DEFAULT", "server python default", "ASP Python", 107, "SCE_HPA_COMMENTLINE", "server python comment line", "Comment", 108, "SCE_HPA_NUMBER", "server python literal numeric", "Number", 109, "SCE_HPA_STRING", "server python literal string", "String", 110, "SCE_HPA_CHARACTER", "server python literal string character", "Single quoted string", 111, "SCE_HPA_WORD", "server python keyword", "Keyword", 112, "SCE_HPA_TRIPLE", "server python literal string", "Triple quotes", 113, "SCE_HPA_TRIPLEDOUBLE", "server python literal string", "Triple double quotes", 114, "SCE_HPA_CLASSNAME", "server python identifier", "Class name definition", 115, "SCE_HPA_DEFNAME", "server python identifier", "Function or method name definition", 116, "SCE_HPA_OPERATOR", "server python operator", "Operators", 117, "SCE_HPA_IDENTIFIER", "server python identifier", "Identifiers", 118, "SCE_HPHP_DEFAULT", "server php default", "Default", 119, "SCE_HPHP_HSTRING", "server php literal string", "Double quoted String", 120, "SCE_HPHP_SIMPLESTRING", "server php literal string", "Single quoted string", 121, "SCE_HPHP_WORD", "server php keyword", "Keyword", 122, "SCE_HPHP_NUMBER", "server php literal numeric", "Number", 123, "SCE_HPHP_VARIABLE", "server php identifier", "Variable", 124, "SCE_HPHP_COMMENT", "server php comment", "Comment", 125, "SCE_HPHP_COMMENTLINE", "server php comment line", "One line comment", 126, "SCE_HPHP_HSTRING_VARIABLE", "server php literal string identifier", "PHP variable in double quoted string", 127, "SCE_HPHP_OPERATOR", "server php operator", "PHP operator", }; LexicalClass lexicalClassesXML[] = { // Lexer.Secondary XML SCLEX_XML SCE_H_: 0, "SCE_H_DEFAULT", "default", "Default", 1, "SCE_H_TAG", "tag", "Tags", 2, "SCE_H_TAGUNKNOWN", "error tag", "Unknown Tags", 3, "SCE_H_ATTRIBUTE", "attribute", "Attributes", 4, "SCE_H_ERRORATTRIBUTEUNKNOWN", "error attribute", "Unknown Attributes", 5, "SCE_H_NUMBER", "literal numeric", "Numbers", 6, "SCE_H_DOUBLESTRING", "literal string", "Double quoted strings", 7, "SCE_H_SINGLESTRING", "literal string", "Single quoted strings", 8, "SCE_H_OTHER", "tag operator", "Other inside tag, including space and '='", 9, "SCE_H_COMMENT", "comment", "Comment", 10, "SCE_H_ENTITY", "literal", "Entities", 11, "SCE_H_TAGEND", "tag", "XML style tag ends '/>'", 12, "SCE_H_XMLSTART", "identifier", "XML identifier start ''", 14, "", "unused", "", 15, "", "unused", "", 16, "", "unused", "", 17, "SCE_H_CDATA", "literal", "CDATA", 18, "SCE_H_QUESTION", "preprocessor", "Question", 19, "SCE_H_VALUE", "literal string", "Unquoted Value", 20, "", "unused", "", 21, "SCE_H_SGML_DEFAULT", "default", "SGML tags ", 22, "SCE_H_SGML_COMMAND", "preprocessor", "SGML command", 23, "SCE_H_SGML_1ST_PARAM", "preprocessor", "SGML 1st param", 24, "SCE_H_SGML_DOUBLESTRING", "literal string", "SGML double string", 25, "SCE_H_SGML_SIMPLESTRING", "literal string", "SGML single string", 26, "SCE_H_SGML_ERROR", "error", "SGML error", 27, "SCE_H_SGML_SPECIAL", "literal", "SGML special (#XXXX type)", 28, "SCE_H_SGML_ENTITY", "literal", "SGML entity", 29, "SCE_H_SGML_COMMENT", "comment", "SGML comment", 30, "", "unused", "", 31, "SCE_H_SGML_BLOCK_DEFAULT", "default", "SGML block", }; const char *tagsThatDoNotFold[] = { "area", "base", "basefont", "br", "col", "command", "embed", "frame", "hr", "img", "input", "isindex", "keygen", "link", "meta", "param", "source", "track", "wbr" }; } class LexerHTML : public DefaultLexer { bool isXml; bool isPHPScript; WordList keywords; WordList keywords2; WordList keywords3; WordList keywords4; WordList keywords5; WordList keywords6; // SGML (DTD) keywords OptionsHTML options; OptionSetHTML osHTML; std::set nonFoldingTags; public: explicit LexerHTML(bool isXml_, bool isPHPScript_) : DefaultLexer(isXml_ ? lexicalClassesHTML : lexicalClassesXML, isXml_ ? ELEMENTS(lexicalClassesHTML) : ELEMENTS(lexicalClassesXML)), isXml(isXml_), isPHPScript(isPHPScript_), osHTML(isPHPScript_), nonFoldingTags(std::begin(tagsThatDoNotFold), std::end(tagsThatDoNotFold)) { } ~LexerHTML() override { } void SCI_METHOD Release() override { delete this; } const char *SCI_METHOD PropertyNames() override { return osHTML.PropertyNames(); } int SCI_METHOD PropertyType(const char *name) override { return osHTML.PropertyType(name); } const char *SCI_METHOD DescribeProperty(const char *name) override { return osHTML.DescribeProperty(name); } Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override; const char *SCI_METHOD DescribeWordListSets() override { return osHTML.DescribeWordListSets(); } Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override; void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override; // No Fold as all folding performs in Lex. static ILexer *LexerFactoryHTML() { return new LexerHTML(false, false); } static ILexer *LexerFactoryXML() { return new LexerHTML(true, false); } static ILexer *LexerFactoryPHPScript() { return new LexerHTML(false, true); } }; Sci_Position SCI_METHOD LexerHTML::PropertySet(const char *key, const char *val) { if (osHTML.PropertySet(&options, key, val)) { return 0; } return -1; } Sci_Position SCI_METHOD LexerHTML::WordListSet(int n, const char *wl) { WordList *wordListN = 0; switch (n) { case 0: wordListN = &keywords; break; case 1: wordListN = &keywords2; break; case 2: wordListN = &keywords3; break; case 3: wordListN = &keywords4; break; case 4: wordListN = &keywords5; break; case 5: wordListN = &keywords6; break; } Sci_Position firstModification = -1; if (wordListN) { WordList wlNew; wlNew.Set(wl); if (*wordListN != wlNew) { wordListN->Set(wl); firstModification = 0; } } return firstModification; } void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) { Accessor styler(pAccess, nullptr); if (isPHPScript && (startPos == 0)) { initStyle = SCE_HPHP_DEFAULT; } styler.StartAt(startPos); std::string prevWord; std::string phpStringDelimiter; int StateToPrint = initStyle; int state = stateForPrintState(StateToPrint); std::string makoBlockType; int makoComment = 0; std::string djangoBlockType; // If inside a tag, it may be a script tag, so reread from the start of line starting tag to ensure any language tags are seen if (InTagState(state)) { while ((startPos > 0) && (InTagState(styler.StyleAt(startPos - 1)))) { const Sci_Position backLineStart = styler.LineStart(styler.GetLine(startPos-1)); length += startPos - backLineStart; startPos = backLineStart; } state = SCE_H_DEFAULT; } // String can be heredoc, must find a delimiter first. Reread from beginning of line containing the string, to get the correct lineState if (isPHPStringState(state)) { while (startPos > 0 && (isPHPStringState(state) || !isLineEnd(styler[startPos - 1]))) { startPos--; length++; state = styler.StyleAt(startPos); } if (startPos == 0) state = SCE_H_DEFAULT; } styler.StartAt(startPos); /* Nothing handles getting out of these, so we need not start in any of them. * As we're at line start and they can't span lines, we'll re-detect them anyway */ switch (state) { case SCE_H_QUESTION: case SCE_H_XMLSTART: case SCE_H_XMLEND: case SCE_H_ASP: state = SCE_H_DEFAULT; break; } Sci_Position lineCurrent = styler.GetLine(startPos); int lineState; if (lineCurrent > 0) { lineState = styler.GetLineState(lineCurrent-1); } else { // Default client and ASP scripting language is JavaScript lineState = eScriptJS << 8; lineState |= options.aspDefaultLanguage << 4; } script_mode inScriptType = static_cast((lineState >> 0) & 0x03); // 2 bits of scripting mode bool tagOpened = (lineState >> 2) & 0x01; // 1 bit to know if we are in an opened tag bool tagClosing = (lineState >> 3) & 0x01; // 1 bit to know if we are in a closing tag bool tagDontFold = false; //some HTML tags should not be folded script_type aspScript = static_cast((lineState >> 4) & 0x0F); // 4 bits of script name script_type clientScript = static_cast((lineState >> 8) & 0x0F); // 4 bits of script name int beforePreProc = (lineState >> 12) & 0xFF; // 8 bits of state script_type scriptLanguage = ScriptOfState(state); // If eNonHtmlScript coincides with SCE_H_COMMENT, assume eScriptComment if (inScriptType == eNonHtmlScript && state == SCE_H_COMMENT) { scriptLanguage = eScriptComment; } script_type beforeLanguage = ScriptOfState(beforePreProc); const bool foldHTML = options.foldHTML; const bool fold = foldHTML && options.fold; const bool foldHTMLPreprocessor = foldHTML && options.foldHTMLPreprocessor; const bool foldCompact = options.foldCompact; const bool foldComment = fold && options.foldComment; const bool foldHeredoc = fold && options.foldHeredoc; const bool caseSensitive = options.caseSensitive; const bool allowScripts = options.allowScripts; const bool isMako = options.isMako; const bool isDjango = options.isDjango; const CharacterSet setHTMLWord(CharacterSet::setAlphaNum, ".-_:!#", 0x80, true); const CharacterSet setTagContinue(CharacterSet::setAlphaNum, ".-_:!#[", 0x80, true); const CharacterSet setAttributeContinue(CharacterSet::setAlphaNum, ".-_:!#/", 0x80, true); // TODO: also handle + and - (except if they're part of ++ or --) and return keywords const CharacterSet setOKBeforeJSRE(CharacterSet::setNone, "([{=,:;!%^&*|?~"); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; int visibleChars = 0; int lineStartVisibleChars = 0; int chPrev = ' '; int ch = ' '; int chPrevNonWhite = ' '; // look back to set chPrevNonWhite properly for better regex colouring if (scriptLanguage == eScriptJS && startPos > 0) { Sci_Position back = startPos; int style = 0; while (--back) { style = styler.StyleAt(back); if (style < SCE_HJ_DEFAULT || style > SCE_HJ_COMMENTDOC) // includes SCE_HJ_COMMENT & SCE_HJ_COMMENTLINE break; } if (style == SCE_HJ_SYMBOLS) { chPrevNonWhite = static_cast(styler.SafeGetCharAt(back)); } } styler.StartSegment(startPos); const Sci_Position lengthDoc = startPos + length; for (Sci_Position i = startPos; i < lengthDoc; i++) { const int chPrev2 = chPrev; chPrev = ch; if (!IsASpace(ch) && state != SCE_HJ_COMMENT && state != SCE_HJ_COMMENTLINE && state != SCE_HJ_COMMENTDOC) chPrevNonWhite = ch; ch = static_cast(styler[i]); int chNext = static_cast(styler.SafeGetCharAt(i + 1)); const int chNext2 = static_cast(styler.SafeGetCharAt(i + 2)); // Handle DBCS codepages if (styler.IsLeadByte(static_cast(ch))) { chPrev = ' '; i += 1; continue; } if ((!IsASpace(ch) || !foldCompact) && fold) visibleChars++; if (!IsASpace(ch)) lineStartVisibleChars++; // decide what is the current state to print (depending of the script tag) StateToPrint = statePrintForState(state, inScriptType); // handle script folding if (fold) { switch (scriptLanguage) { case eScriptJS: case eScriptPHP: //not currently supported case eScriptVBS: if ((state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (state != SCE_HJ_COMMENT) && (state != SCE_HJ_COMMENTLINE) && (state != SCE_HJ_COMMENTDOC) && (!isStringState(state))) { //Platform::DebugPrintf("state=%d, StateToPrint=%d, initStyle=%d\n", state, StateToPrint, initStyle); //if ((state == SCE_HPHP_OPERATOR) || (state == SCE_HPHP_DEFAULT) || (state == SCE_HJ_SYMBOLS) || (state == SCE_HJ_START) || (state == SCE_HJ_DEFAULT)) { if (ch == '#') { Sci_Position j = i + 1; while ((j < lengthDoc) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { j++; } if (styler.Match(j, "region") || styler.Match(j, "if")) { levelCurrent++; } else if (styler.Match(j, "end")) { levelCurrent--; } } else if ((ch == '{') || (ch == '}') || (foldComment && (ch == '/') && (chNext == '*'))) { levelCurrent += (((ch == '{') || (ch == '/')) ? 1 : -1); } } else if (((state == SCE_HPHP_COMMENT) || (state == SCE_HJ_COMMENT)) && foldComment && (ch == '*') && (chNext == '/')) { levelCurrent--; } break; case eScriptPython: if (state != SCE_HP_COMMENTLINE && !isMako) { if ((ch == ':') && ((chNext == '\n') || (chNext == '\r' && chNext2 == '\n'))) { levelCurrent++; } else if ((ch == '\n') && !((chNext == '\r') && (chNext2 == '\n')) && (chNext != '\n')) { // check if the number of tabs is lower than the level int Findlevel = (levelCurrent & ~SC_FOLDLEVELBASE) * 8; for (Sci_Position j = 0; Findlevel > 0; j++) { const char chTmp = styler.SafeGetCharAt(i + j + 1); if (chTmp == '\t') { Findlevel -= 8; } else if (chTmp == ' ') { Findlevel--; } else { break; } } if (Findlevel > 0) { levelCurrent -= Findlevel / 8; if (Findlevel % 8) levelCurrent--; } } } break; default: break; } } if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) // Avoid triggering two times on Dos/Win // New line -> record any line state onto /next/ line if (fold) { int lev = levelPrev; if (visibleChars == 0) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; styler.SetLevel(lineCurrent, lev); visibleChars = 0; levelPrev = levelCurrent; } styler.SetLineState(lineCurrent, ((inScriptType & 0x03) << 0) | ((tagOpened ? 1 : 0) << 2) | ((tagClosing ? 1 : 0) << 3) | ((aspScript & 0x0F) << 4) | ((clientScript & 0x0F) << 8) | ((beforePreProc & 0xFF) << 12)); lineCurrent++; lineStartVisibleChars = 0; } // handle start of Mako comment line if (isMako && ch == '#' && chNext == '#') { makoComment = 1; state = SCE_HP_COMMENTLINE; } // handle end of Mako comment line else if (isMako && makoComment && (ch == '\r' || ch == '\n')) { makoComment = 0; styler.ColourTo(i - 1, StateToPrint); if (scriptLanguage == eScriptPython) { state = SCE_HP_DEFAULT; } else { state = SCE_H_DEFAULT; } } // Allow falling through to mako handling code if newline is going to end a block if (((ch == '\r' && chNext != '\n') || (ch == '\n')) && (!isMako || (makoBlockType != "%"))) { } // Ignore everything in mako comment until the line ends else if (isMako && makoComment) { } // generic end of script processing else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) { // Check if it's the end of the script tag (or any other HTML tag) switch (state) { // in these cases, you can embed HTML tags (to confirm !!!!!!!!!!!!!!!!!!!!!!) case SCE_H_DOUBLESTRING: case SCE_H_SINGLESTRING: case SCE_HJ_COMMENT: case SCE_HJ_COMMENTDOC: //case SCE_HJ_COMMENTLINE: // removed as this is a common thing done to hide // the end of script marker from some JS interpreters. case SCE_HB_COMMENTLINE: case SCE_HBA_COMMENTLINE: case SCE_HJ_DOUBLESTRING: case SCE_HJ_SINGLESTRING: case SCE_HJ_REGEX: case SCE_HB_STRING: case SCE_HBA_STRING: case SCE_HP_STRING: case SCE_HP_TRIPLE: case SCE_HP_TRIPLEDOUBLE: case SCE_HPHP_HSTRING: case SCE_HPHP_SIMPLESTRING: case SCE_HPHP_COMMENT: case SCE_HPHP_COMMENTLINE: break; default : // check if the closing tag is a script tag if (const char *tag = state == SCE_HJ_COMMENTLINE || isXml ? "script" : state == SCE_H_COMMENT ? "comment" : 0) { Sci_Position j = i + 2; int chr; do { chr = static_cast(*tag++); } while (chr != 0 && chr == MakeLowerCase(styler.SafeGetCharAt(j++))); if (chr != 0) break; } // closing tag of the script (it's a closing HTML tag anyway) styler.ColourTo(i - 1, StateToPrint); state = SCE_H_TAGUNKNOWN; inScriptType = eHtml; scriptLanguage = eScriptNone; clientScript = eScriptJS; i += 2; visibleChars += 2; tagClosing = true; continue; } } ///////////////////////////////////// // handle the start of PHP pre-processor = Non-HTML else if ((state != SCE_H_ASPAT) && !isStringState(state) && (state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (ch == '<') && (chNext == '?') && !IsScriptCommentState(state)) { beforeLanguage = scriptLanguage; scriptLanguage = segIsScriptingIndicator(styler, i + 2, i + 6, isXml ? eScriptXML : eScriptPHP); if ((scriptLanguage != eScriptPHP) && (isStringState(state) || (state==SCE_H_COMMENT))) continue; styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; i++; visibleChars++; i += PrintScriptingIndicatorOffset(styler, styler.GetStartSegment() + 2, i + 6); if (scriptLanguage == eScriptXML) styler.ColourTo(i, SCE_H_XMLSTART); else styler.ColourTo(i, SCE_H_QUESTION); state = StateForScript(scriptLanguage); if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; // Fold whole script, but not if the XML first tag (all XML-like tags in this case) if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) { levelCurrent++; } // should be better ch = static_cast(styler.SafeGetCharAt(i)); continue; } // handle the start Mako template Python code else if (isMako && scriptLanguage == eScriptNone && ((ch == '<' && chNext == '%') || (lineStartVisibleChars == 1 && ch == '%') || (lineStartVisibleChars == 1 && ch == '/' && chNext == '%') || (ch == '$' && chNext == '{') || (ch == '<' && chNext == '/' && chNext2 == '%'))) { if (ch == '%' || ch == '/') makoBlockType = "%"; else if (ch == '$') makoBlockType = "{"; else if (chNext == '/') makoBlockType = GetNextWord(styler, i+3); else makoBlockType = GetNextWord(styler, i+2); styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; if (chNext == '/') { i += 2; visibleChars += 2; } else if (ch != '%') { i++; visibleChars++; } state = SCE_HP_START; scriptLanguage = eScriptPython; styler.ColourTo(i, SCE_H_ASP); if (ch != '%' && ch != '$' && ch != '/') { i += makoBlockType.length(); visibleChars += static_cast(makoBlockType.length()); if (keywords4.InList(makoBlockType.c_str())) styler.ColourTo(i, SCE_HP_WORD); else styler.ColourTo(i, SCE_H_TAGUNKNOWN); } ch = static_cast(styler.SafeGetCharAt(i)); continue; } // handle the start/end of Django comment else if (isDjango && state != SCE_H_COMMENT && (ch == '{' && chNext == '#')) { styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; beforeLanguage = scriptLanguage; if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; i += 1; visibleChars += 1; scriptLanguage = eScriptComment; state = SCE_H_COMMENT; styler.ColourTo(i, SCE_H_ASP); ch = static_cast(styler.SafeGetCharAt(i)); continue; } else if (isDjango && state == SCE_H_COMMENT && (ch == '#' && chNext == '}')) { styler.ColourTo(i - 1, StateToPrint); i += 1; visibleChars += 1; styler.ColourTo(i, SCE_H_ASP); state = beforePreProc; if (inScriptType == eNonHtmlScriptPreProc) inScriptType = eNonHtmlScript; else inScriptType = eHtml; scriptLanguage = beforeLanguage; continue; } // handle the start Django template code else if (isDjango && scriptLanguage != eScriptPython && scriptLanguage != eScriptComment && (ch == '{' && (chNext == '%' || chNext == '{'))) { if (chNext == '%') djangoBlockType = "%"; else djangoBlockType = "{"; styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; i += 1; visibleChars += 1; state = SCE_HP_START; beforeLanguage = scriptLanguage; scriptLanguage = eScriptPython; styler.ColourTo(i, SCE_H_ASP); ch = static_cast(styler.SafeGetCharAt(i)); continue; } // handle the start of ASP pre-processor = Non-HTML else if (!isMako && !isDjango && !isCommentASPState(state) && (ch == '<') && (chNext == '%') && !isPHPStringState(state)) { styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; if (chNext2 == '@') { i += 2; // place as if it was the second next char treated visibleChars += 2; state = SCE_H_ASPAT; } else if ((chNext2 == '-') && (styler.SafeGetCharAt(i + 3) == '-')) { styler.ColourTo(i + 3, SCE_H_ASP); state = SCE_H_XCCOMMENT; scriptLanguage = eScriptVBS; continue; } else { if (chNext2 == '=') { i += 2; // place as if it was the second next char treated visibleChars += 2; } else { i++; // place as if it was the next char treated visibleChars++; } state = StateForScript(aspScript); } scriptLanguage = eScriptVBS; styler.ColourTo(i, SCE_H_ASP); // fold whole script if (foldHTMLPreprocessor) levelCurrent++; // should be better ch = static_cast(styler.SafeGetCharAt(i)); continue; } ///////////////////////////////////// // handle the start of SGML language (DTD) else if (((scriptLanguage == eScriptNone) || (scriptLanguage == eScriptXML)) && (chPrev == '<') && (ch == '!') && (StateToPrint != SCE_H_CDATA) && (!IsCommentState(StateToPrint)) && (!IsScriptCommentState(StateToPrint))) { beforePreProc = state; styler.ColourTo(i - 2, StateToPrint); if ((chNext == '-') && (chNext2 == '-')) { state = SCE_H_COMMENT; // wait for a pending command styler.ColourTo(i + 2, SCE_H_COMMENT); i += 2; // follow styling after the -- } else if (isWordCdata(i + 1, i + 7, styler)) { state = SCE_H_CDATA; } else { styler.ColourTo(i, SCE_H_SGML_DEFAULT); // ') { i++; visibleChars++; } else if ((makoBlockType == "%") && ch == '/') { i++; visibleChars++; } if ((makoBlockType != "%") || ch == '/') { styler.ColourTo(i, SCE_H_ASP); } state = beforePreProc; if (inScriptType == eNonHtmlScriptPreProc) inScriptType = eNonHtmlScript; else inScriptType = eHtml; scriptLanguage = eScriptNone; continue; } // handle the end of Django template code else if (isDjango && ((inScriptType == eNonHtmlPreProc) || (inScriptType == eNonHtmlScriptPreProc)) && (scriptLanguage != eScriptNone) && stateAllowsTermination(state) && isDjangoBlockEnd(ch, chNext, djangoBlockType)) { if (state == SCE_H_ASPAT) { aspScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, aspScript); } if (state == SCE_HP_WORD) { classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako); } else { styler.ColourTo(i - 1, StateToPrint); } i += 1; visibleChars += 1; styler.ColourTo(i, SCE_H_ASP); state = beforePreProc; if (inScriptType == eNonHtmlScriptPreProc) inScriptType = eNonHtmlScript; else inScriptType = eHtml; scriptLanguage = beforeLanguage; continue; } // handle the end of a pre-processor = Non-HTML else if ((!isMako && !isDjango && ((inScriptType == eNonHtmlPreProc) || (inScriptType == eNonHtmlScriptPreProc)) && (((scriptLanguage != eScriptNone) && stateAllowsTermination(state))) && (((ch == '%') || (ch == '?')) && (chNext == '>'))) || ((scriptLanguage == eScriptSGML) && (ch == '>') && (state != SCE_H_SGML_COMMENT))) { if (state == SCE_H_ASPAT) { aspScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, aspScript); } // Bounce out of any ASP mode switch (state) { case SCE_HJ_WORD: classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType); break; case SCE_HB_WORD: classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType); break; case SCE_HP_WORD: classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako); break; case SCE_HPHP_WORD: classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler); break; case SCE_H_XCCOMMENT: styler.ColourTo(i - 1, state); break; default : styler.ColourTo(i - 1, StateToPrint); break; } if (scriptLanguage != eScriptSGML) { i++; visibleChars++; } if (ch == '%') styler.ColourTo(i, SCE_H_ASP); else if (scriptLanguage == eScriptXML) styler.ColourTo(i, SCE_H_XMLEND); else if (scriptLanguage == eScriptSGML) styler.ColourTo(i, SCE_H_SGML_DEFAULT); else styler.ColourTo(i, SCE_H_QUESTION); state = beforePreProc; if (inScriptType == eNonHtmlScriptPreProc) inScriptType = eNonHtmlScript; else inScriptType = eHtml; // Unfold all scripting languages, except for XML tag if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) { levelCurrent--; } scriptLanguage = beforeLanguage; continue; } ///////////////////////////////////// switch (state) { case SCE_H_DEFAULT: if (ch == '<') { // in HTML, fold on tag open and unfold on tag close tagOpened = true; tagClosing = (chNext == '/'); styler.ColourTo(i - 1, StateToPrint); if (chNext != '!') state = SCE_H_TAGUNKNOWN; } else if (ch == '&') { styler.ColourTo(i - 1, SCE_H_DEFAULT); state = SCE_H_ENTITY; } break; case SCE_H_SGML_DEFAULT: case SCE_H_SGML_BLOCK_DEFAULT: // if (scriptLanguage == eScriptSGMLblock) // StateToPrint = SCE_H_SGML_BLOCK_DEFAULT; if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SGML_DOUBLESTRING; } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SGML_SIMPLESTRING; } else if ((ch == '-') && (chPrev == '-')) { if (static_cast(styler.GetStartSegment()) <= (i - 2)) { styler.ColourTo(i - 2, StateToPrint); } state = SCE_H_SGML_COMMENT; } else if (IsASCII(ch) && isalpha(ch) && (chPrev == '%')) { styler.ColourTo(i - 2, StateToPrint); state = SCE_H_SGML_ENTITY; } else if (ch == '#') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SGML_SPECIAL; } else if (ch == '[') { styler.ColourTo(i - 1, StateToPrint); scriptLanguage = eScriptSGMLblock; state = SCE_H_SGML_BLOCK_DEFAULT; } else if (ch == ']') { if (scriptLanguage == eScriptSGMLblock) { styler.ColourTo(i, StateToPrint); scriptLanguage = eScriptSGML; } else { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, SCE_H_SGML_ERROR); } state = SCE_H_SGML_DEFAULT; } else if (scriptLanguage == eScriptSGMLblock) { if ((ch == '!') && (chPrev == '<')) { styler.ColourTo(i - 2, StateToPrint); styler.ColourTo(i, SCE_H_SGML_DEFAULT); state = SCE_H_SGML_COMMAND; } else if (ch == '>') { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, SCE_H_SGML_DEFAULT); } } break; case SCE_H_SGML_COMMAND: if ((ch == '-') && (chPrev == '-')) { styler.ColourTo(i - 2, StateToPrint); state = SCE_H_SGML_COMMENT; } else if (!issgmlwordchar(ch)) { if (isWordHSGML(styler.GetStartSegment(), i - 1, keywords6, styler)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SGML_1ST_PARAM; } else { state = SCE_H_SGML_ERROR; } } break; case SCE_H_SGML_1ST_PARAM: // wait for the beginning of the word if ((ch == '-') && (chPrev == '-')) { if (scriptLanguage == eScriptSGMLblock) { styler.ColourTo(i - 2, SCE_H_SGML_BLOCK_DEFAULT); } else { styler.ColourTo(i - 2, SCE_H_SGML_DEFAULT); } state = SCE_H_SGML_1ST_PARAM_COMMENT; } else if (issgmlwordchar(ch)) { if (scriptLanguage == eScriptSGMLblock) { styler.ColourTo(i - 1, SCE_H_SGML_BLOCK_DEFAULT); } else { styler.ColourTo(i - 1, SCE_H_SGML_DEFAULT); } // find the length of the word int size = 1; while (setHTMLWord.Contains(static_cast(styler.SafeGetCharAt(i + size)))) size++; styler.ColourTo(i + size - 1, StateToPrint); i += size - 1; visibleChars += size - 1; ch = static_cast(styler.SafeGetCharAt(i)); if (scriptLanguage == eScriptSGMLblock) { state = SCE_H_SGML_BLOCK_DEFAULT; } else { state = SCE_H_SGML_DEFAULT; } continue; } break; case SCE_H_SGML_ERROR: if ((ch == '-') && (chPrev == '-')) { styler.ColourTo(i - 2, StateToPrint); state = SCE_H_SGML_COMMENT; } break; case SCE_H_SGML_DOUBLESTRING: if (ch == '\"') { styler.ColourTo(i, StateToPrint); state = SCE_H_SGML_DEFAULT; } break; case SCE_H_SGML_SIMPLESTRING: if (ch == '\'') { styler.ColourTo(i, StateToPrint); state = SCE_H_SGML_DEFAULT; } break; case SCE_H_SGML_COMMENT: if ((ch == '-') && (chPrev == '-')) { styler.ColourTo(i, StateToPrint); state = SCE_H_SGML_DEFAULT; } break; case SCE_H_CDATA: if ((chPrev2 == ']') && (chPrev == ']') && (ch == '>')) { styler.ColourTo(i, StateToPrint); state = SCE_H_DEFAULT; levelCurrent--; } break; case SCE_H_COMMENT: if ((scriptLanguage != eScriptComment) && (chPrev2 == '-') && (chPrev == '-') && (ch == '>')) { styler.ColourTo(i, StateToPrint); state = SCE_H_DEFAULT; levelCurrent--; } break; case SCE_H_SGML_1ST_PARAM_COMMENT: if ((ch == '-') && (chPrev == '-')) { styler.ColourTo(i, SCE_H_SGML_COMMENT); state = SCE_H_SGML_1ST_PARAM; } break; case SCE_H_SGML_SPECIAL: if (!(IsASCII(ch) && isupper(ch))) { styler.ColourTo(i - 1, StateToPrint); if (isalnum(ch)) { state = SCE_H_SGML_ERROR; } else { state = SCE_H_SGML_DEFAULT; } } break; case SCE_H_SGML_ENTITY: if (ch == ';') { styler.ColourTo(i, StateToPrint); state = SCE_H_SGML_DEFAULT; } else if (!(IsASCII(ch) && isalnum(ch)) && ch != '-' && ch != '.') { styler.ColourTo(i, SCE_H_SGML_ERROR); state = SCE_H_SGML_DEFAULT; } break; case SCE_H_ENTITY: if (ch == ';') { styler.ColourTo(i, StateToPrint); state = SCE_H_DEFAULT; } if (ch != '#' && !(IsASCII(ch) && isalnum(ch)) // Should check that '#' follows '&', but it is unlikely anyway... && ch != '.' && ch != '-' && ch != '_' && ch != ':') { // valid in XML if (!IsASCII(ch)) // Possibly start of a multibyte character so don't allow this byte to be in entity style styler.ColourTo(i-1, SCE_H_TAGUNKNOWN); else styler.ColourTo(i, SCE_H_TAGUNKNOWN); state = SCE_H_DEFAULT; } break; case SCE_H_TAGUNKNOWN: if (!setTagContinue.Contains(ch) && !((ch == '/') && (chPrev == '<'))) { int eClass = classifyTagHTML(styler.GetStartSegment(), i - 1, keywords, styler, tagDontFold, caseSensitive, isXml, allowScripts, nonFoldingTags); if (eClass == SCE_H_SCRIPT || eClass == SCE_H_COMMENT) { if (!tagClosing) { inScriptType = eNonHtmlScript; scriptLanguage = eClass == SCE_H_SCRIPT ? clientScript : eScriptComment; } else { scriptLanguage = eScriptNone; } eClass = SCE_H_TAG; } if (ch == '>') { styler.ColourTo(i, eClass); if (inScriptType == eNonHtmlScript) { state = StateForScript(scriptLanguage); } else { state = SCE_H_DEFAULT; } tagOpened = false; if (!tagDontFold) { if (tagClosing) { levelCurrent--; } else { levelCurrent++; } } tagClosing = false; } else if (ch == '/' && chNext == '>') { if (eClass == SCE_H_TAGUNKNOWN) { styler.ColourTo(i + 1, SCE_H_TAGUNKNOWN); } else { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i + 1, SCE_H_TAGEND); } i++; ch = chNext; state = SCE_H_DEFAULT; tagOpened = false; } else { if (eClass != SCE_H_TAGUNKNOWN) { if (eClass == SCE_H_SGML_DEFAULT) { state = SCE_H_SGML_DEFAULT; } else { state = SCE_H_OTHER; } } } } break; case SCE_H_ATTRIBUTE: if (!setAttributeContinue.Contains(ch)) { if (inScriptType == eNonHtmlScript) { const int scriptLanguagePrev = scriptLanguage; clientScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, scriptLanguage); scriptLanguage = clientScript; if ((scriptLanguagePrev != scriptLanguage) && (scriptLanguage == eScriptNone)) inScriptType = eHtml; } classifyAttribHTML(styler.GetStartSegment(), i - 1, keywords, styler); if (ch == '>') { styler.ColourTo(i, SCE_H_TAG); if (inScriptType == eNonHtmlScript) { state = StateForScript(scriptLanguage); } else { state = SCE_H_DEFAULT; } tagOpened = false; if (!tagDontFold) { if (tagClosing) { levelCurrent--; } else { levelCurrent++; } } tagClosing = false; } else if (ch == '=') { styler.ColourTo(i, SCE_H_OTHER); state = SCE_H_VALUE; } else { state = SCE_H_OTHER; } } break; case SCE_H_OTHER: if (ch == '>') { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, SCE_H_TAG); if (inScriptType == eNonHtmlScript) { state = StateForScript(scriptLanguage); } else { state = SCE_H_DEFAULT; } tagOpened = false; if (!tagDontFold) { if (tagClosing) { levelCurrent--; } else { levelCurrent++; } } tagClosing = false; } else if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_DOUBLESTRING; } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SINGLESTRING; } else if (ch == '=') { styler.ColourTo(i, StateToPrint); state = SCE_H_VALUE; } else if (ch == '/' && chNext == '>') { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i + 1, SCE_H_TAGEND); i++; ch = chNext; state = SCE_H_DEFAULT; tagOpened = false; } else if (ch == '?' && chNext == '>') { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i + 1, SCE_H_XMLEND); i++; ch = chNext; state = SCE_H_DEFAULT; } else if (setHTMLWord.Contains(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_ATTRIBUTE; } break; case SCE_H_DOUBLESTRING: if (ch == '\"') { if (inScriptType == eNonHtmlScript) { scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); } styler.ColourTo(i, SCE_H_DOUBLESTRING); state = SCE_H_OTHER; } break; case SCE_H_SINGLESTRING: if (ch == '\'') { if (inScriptType == eNonHtmlScript) { scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); } styler.ColourTo(i, SCE_H_SINGLESTRING); state = SCE_H_OTHER; } break; case SCE_H_VALUE: if (!setHTMLWord.Contains(ch)) { if (ch == '\"' && chPrev == '=') { // Should really test for being first character state = SCE_H_DOUBLESTRING; } else if (ch == '\'' && chPrev == '=') { state = SCE_H_SINGLESTRING; } else { if (IsNumber(styler.GetStartSegment(), styler)) { styler.ColourTo(i - 1, SCE_H_NUMBER); } else { styler.ColourTo(i - 1, StateToPrint); } if (ch == '>') { styler.ColourTo(i, SCE_H_TAG); if (inScriptType == eNonHtmlScript) { state = StateForScript(scriptLanguage); } else { state = SCE_H_DEFAULT; } tagOpened = false; if (!tagDontFold) { if (tagClosing) { levelCurrent--; } else { levelCurrent++; } } tagClosing = false; } else { state = SCE_H_OTHER; } } } break; case SCE_HJ_DEFAULT: case SCE_HJ_START: case SCE_HJ_SYMBOLS: if (IsAWordStart(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_WORD; } else if (ch == '/' && chNext == '*') { styler.ColourTo(i - 1, StateToPrint); if (chNext2 == '*') state = SCE_HJ_COMMENTDOC; else state = SCE_HJ_COMMENT; if (chNext2 == '/') { // Eat the * so it isn't used for the end of the comment i++; } } else if (ch == '/' && chNext == '/') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; } else if (ch == '/' && setOKBeforeJSRE.Contains(chPrevNonWhite)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_REGEX; } else if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_DOUBLESTRING; } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_SINGLESTRING; } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && styler.SafeGetCharAt(i + 3) == '-') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; i += 2; } else if (IsOperator(ch)) { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType)); state = SCE_HJ_DEFAULT; } else if ((ch == ' ') || (ch == '\t')) { if (state == SCE_HJ_START) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_DEFAULT; } } break; case SCE_HJ_WORD: if (!IsAWordChar(ch)) { classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType); //styler.ColourTo(i - 1, eHTJSKeyword); state = SCE_HJ_DEFAULT; if (ch == '/' && chNext == '*') { if (chNext2 == '*') state = SCE_HJ_COMMENTDOC; else state = SCE_HJ_COMMENT; } else if (ch == '/' && chNext == '/') { state = SCE_HJ_COMMENTLINE; } else if (ch == '\"') { state = SCE_HJ_DOUBLESTRING; } else if (ch == '\'') { state = SCE_HJ_SINGLESTRING; } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; i += 2; } else if (IsOperator(ch)) { styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType)); state = SCE_HJ_DEFAULT; } } break; case SCE_HJ_COMMENT: case SCE_HJ_COMMENTDOC: if (ch == '/' && chPrev == '*') { styler.ColourTo(i, StateToPrint); state = SCE_HJ_DEFAULT; ch = ' '; } break; case SCE_HJ_COMMENTLINE: if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, statePrintForState(SCE_HJ_COMMENTLINE, inScriptType)); state = SCE_HJ_DEFAULT; ch = ' '; } break; case SCE_HJ_DOUBLESTRING: if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; } } else if (ch == '\"') { styler.ColourTo(i, statePrintForState(SCE_HJ_DOUBLESTRING, inScriptType)); state = SCE_HJ_DEFAULT; } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; i += 2; } else if (isLineEnd(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_STRINGEOL; } break; case SCE_HJ_SINGLESTRING: if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; } } else if (ch == '\'') { styler.ColourTo(i, statePrintForState(SCE_HJ_SINGLESTRING, inScriptType)); state = SCE_HJ_DEFAULT; } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; i += 2; } else if (isLineEnd(ch)) { styler.ColourTo(i - 1, StateToPrint); if (chPrev != '\\' && (chPrev2 != '\\' || chPrev != '\r' || ch != '\n')) { state = SCE_HJ_STRINGEOL; } } break; case SCE_HJ_STRINGEOL: if (!isLineEnd(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_DEFAULT; } else if (!isLineEnd(chNext)) { styler.ColourTo(i, StateToPrint); state = SCE_HJ_DEFAULT; } break; case SCE_HJ_REGEX: if (ch == '\r' || ch == '\n' || ch == '/') { if (ch == '/') { while (IsASCII(chNext) && islower(chNext)) { // gobble regex flags i++; ch = chNext; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } } styler.ColourTo(i, StateToPrint); state = SCE_HJ_DEFAULT; } else if (ch == '\\') { // Gobble up the quoted character if (chNext == '\\' || chNext == '/') { i++; ch = chNext; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } } break; case SCE_HB_DEFAULT: case SCE_HB_START: if (IsAWordStart(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_WORD; } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_COMMENTLINE; } else if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_STRING; } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && styler.SafeGetCharAt(i + 3) == '-') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_COMMENTLINE; } else if (IsOperator(ch)) { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType)); state = SCE_HB_DEFAULT; } else if ((ch == ' ') || (ch == '\t')) { if (state == SCE_HB_START) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_DEFAULT; } } break; case SCE_HB_WORD: if (!IsAWordChar(ch)) { state = classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType); if (state == SCE_HB_DEFAULT) { if (ch == '\"') { state = SCE_HB_STRING; } else if (ch == '\'') { state = SCE_HB_COMMENTLINE; } else if (IsOperator(ch)) { styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType)); state = SCE_HB_DEFAULT; } } } break; case SCE_HB_STRING: if (ch == '\"') { styler.ColourTo(i, StateToPrint); state = SCE_HB_DEFAULT; } else if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_STRINGEOL; } break; case SCE_HB_COMMENTLINE: if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_DEFAULT; } break; case SCE_HB_STRINGEOL: if (!isLineEnd(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_DEFAULT; } else if (!isLineEnd(chNext)) { styler.ColourTo(i, StateToPrint); state = SCE_HB_DEFAULT; } break; case SCE_HP_DEFAULT: case SCE_HP_START: if (IsAWordStart(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_WORD; } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && styler.SafeGetCharAt(i + 3) == '-') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_COMMENTLINE; } else if (ch == '#') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_COMMENTLINE; } else if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); if (chNext == '\"' && chNext2 == '\"') { i += 2; state = SCE_HP_TRIPLEDOUBLE; ch = ' '; chPrev = ' '; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } else { // state = statePrintForState(SCE_HP_STRING,inScriptType); state = SCE_HP_STRING; } } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); if (chNext == '\'' && chNext2 == '\'') { i += 2; state = SCE_HP_TRIPLE; ch = ' '; chPrev = ' '; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } else { state = SCE_HP_CHARACTER; } } else if (IsOperator(ch)) { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType)); } else if ((ch == ' ') || (ch == '\t')) { if (state == SCE_HP_START) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_DEFAULT; } } break; case SCE_HP_WORD: if (!IsAWordChar(ch)) { classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako); state = SCE_HP_DEFAULT; if (ch == '#') { state = SCE_HP_COMMENTLINE; } else if (ch == '\"') { if (chNext == '\"' && chNext2 == '\"') { i += 2; state = SCE_HP_TRIPLEDOUBLE; ch = ' '; chPrev = ' '; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } else { state = SCE_HP_STRING; } } else if (ch == '\'') { if (chNext == '\'' && chNext2 == '\'') { i += 2; state = SCE_HP_TRIPLE; ch = ' '; chPrev = ' '; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } else { state = SCE_HP_CHARACTER; } } else if (IsOperator(ch)) { styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType)); } } break; case SCE_HP_COMMENTLINE: if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_DEFAULT; } break; case SCE_HP_STRING: if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; ch = chNext; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } } else if (ch == '\"') { styler.ColourTo(i, StateToPrint); state = SCE_HP_DEFAULT; } break; case SCE_HP_CHARACTER: if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; ch = chNext; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } } else if (ch == '\'') { styler.ColourTo(i, StateToPrint); state = SCE_HP_DEFAULT; } break; case SCE_HP_TRIPLE: if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') { styler.ColourTo(i, StateToPrint); state = SCE_HP_DEFAULT; } break; case SCE_HP_TRIPLEDOUBLE: if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') { styler.ColourTo(i, StateToPrint); state = SCE_HP_DEFAULT; } break; ///////////// start - PHP state handling case SCE_HPHP_WORD: if (!IsAWordChar(ch)) { classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler); if (ch == '/' && chNext == '*') { i++; state = SCE_HPHP_COMMENT; } else if (ch == '/' && chNext == '/') { i++; state = SCE_HPHP_COMMENTLINE; } else if (ch == '#') { state = SCE_HPHP_COMMENTLINE; } else if (ch == '\"') { state = SCE_HPHP_HSTRING; phpStringDelimiter = "\""; } else if (styler.Match(i, "<<<")) { bool isSimpleString = false; i = FindPhpStringDelimiter(phpStringDelimiter, i + 3, lengthDoc, styler, isSimpleString); if (!phpStringDelimiter.empty()) { state = (isSimpleString ? SCE_HPHP_SIMPLESTRING : SCE_HPHP_HSTRING); if (foldHeredoc) levelCurrent++; } } else if (ch == '\'') { state = SCE_HPHP_SIMPLESTRING; phpStringDelimiter = "\'"; } else if (ch == '$' && IsPhpWordStart(chNext)) { state = SCE_HPHP_VARIABLE; } else if (IsOperator(ch)) { state = SCE_HPHP_OPERATOR; } else { state = SCE_HPHP_DEFAULT; } } break; case SCE_HPHP_NUMBER: // recognize bases 8,10 or 16 integers OR floating-point numbers if (!IsADigit(ch) && strchr(".xXabcdefABCDEF", ch) == NULL && ((ch != '-' && ch != '+') || (chPrev != 'e' && chPrev != 'E'))) { styler.ColourTo(i - 1, SCE_HPHP_NUMBER); if (IsOperator(ch)) state = SCE_HPHP_OPERATOR; else state = SCE_HPHP_DEFAULT; } break; case SCE_HPHP_VARIABLE: if (!IsPhpWordChar(chNext)) { styler.ColourTo(i, SCE_HPHP_VARIABLE); state = SCE_HPHP_DEFAULT; } break; case SCE_HPHP_COMMENT: if (ch == '/' && chPrev == '*') { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; } break; case SCE_HPHP_COMMENTLINE: if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HPHP_DEFAULT; } break; case SCE_HPHP_HSTRING: if (ch == '\\' && ((phpStringDelimiter == "\"") || chNext == '$' || chNext == '{')) { // skip the next char i++; } else if (((ch == '{' && chNext == '$') || (ch == '$' && chNext == '{')) && IsPhpWordStart(chNext2)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HPHP_COMPLEX_VARIABLE; } else if (ch == '$' && IsPhpWordStart(chNext)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HPHP_HSTRING_VARIABLE; } else if (styler.Match(i, phpStringDelimiter.c_str())) { if (phpStringDelimiter == "\"") { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; } else if (isLineEnd(chPrev)) { const int psdLength = static_cast(phpStringDelimiter.length()); const char chAfterPsd = styler.SafeGetCharAt(i + psdLength); const char chAfterPsd2 = styler.SafeGetCharAt(i + psdLength + 1); if (isLineEnd(chAfterPsd) || (chAfterPsd == ';' && isLineEnd(chAfterPsd2))) { i += (((i + psdLength) < lengthDoc) ? psdLength : lengthDoc) - 1; styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; if (foldHeredoc) levelCurrent--; } } } break; case SCE_HPHP_SIMPLESTRING: if (phpStringDelimiter == "\'") { if (ch == '\\') { // skip the next char i++; } else if (ch == '\'') { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; } } else if (isLineEnd(chPrev) && styler.Match(i, phpStringDelimiter.c_str())) { const int psdLength = static_cast(phpStringDelimiter.length()); const char chAfterPsd = styler.SafeGetCharAt(i + psdLength); const char chAfterPsd2 = styler.SafeGetCharAt(i + psdLength + 1); if (isLineEnd(chAfterPsd) || (chAfterPsd == ';' && isLineEnd(chAfterPsd2))) { i += (((i + psdLength) < lengthDoc) ? psdLength : lengthDoc) - 1; styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; if (foldHeredoc) levelCurrent--; } } break; case SCE_HPHP_HSTRING_VARIABLE: if (!IsPhpWordChar(chNext)) { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_HSTRING; } break; case SCE_HPHP_COMPLEX_VARIABLE: if (ch == '}') { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_HSTRING; } break; case SCE_HPHP_OPERATOR: case SCE_HPHP_DEFAULT: styler.ColourTo(i - 1, StateToPrint); if (IsADigit(ch) || (ch == '.' && IsADigit(chNext))) { state = SCE_HPHP_NUMBER; } else if (IsAWordStart(ch)) { state = SCE_HPHP_WORD; } else if (ch == '/' && chNext == '*') { i++; state = SCE_HPHP_COMMENT; } else if (ch == '/' && chNext == '/') { i++; state = SCE_HPHP_COMMENTLINE; } else if (ch == '#') { state = SCE_HPHP_COMMENTLINE; } else if (ch == '\"') { state = SCE_HPHP_HSTRING; phpStringDelimiter = "\""; } else if (styler.Match(i, "<<<")) { bool isSimpleString = false; i = FindPhpStringDelimiter(phpStringDelimiter, i + 3, lengthDoc, styler, isSimpleString); if (!phpStringDelimiter.empty()) { state = (isSimpleString ? SCE_HPHP_SIMPLESTRING : SCE_HPHP_HSTRING); if (foldHeredoc) levelCurrent++; } } else if (ch == '\'') { state = SCE_HPHP_SIMPLESTRING; phpStringDelimiter = "\'"; } else if (ch == '$' && IsPhpWordStart(chNext)) { state = SCE_HPHP_VARIABLE; } else if (IsOperator(ch)) { state = SCE_HPHP_OPERATOR; } else if ((state == SCE_HPHP_OPERATOR) && (IsASpace(ch))) { state = SCE_HPHP_DEFAULT; } break; ///////////// end - PHP state handling } // Some of the above terminated their lexeme but since the same character starts // the same class again, only reenter if non empty segment. const bool nonEmptySegment = i >= static_cast(styler.GetStartSegment()); if (state == SCE_HB_DEFAULT) { // One of the above succeeded if ((ch == '\"') && (nonEmptySegment)) { state = SCE_HB_STRING; } else if (ch == '\'') { state = SCE_HB_COMMENTLINE; } else if (IsAWordStart(ch)) { state = SCE_HB_WORD; } else if (IsOperator(ch)) { styler.ColourTo(i, SCE_HB_DEFAULT); } } else if (state == SCE_HBA_DEFAULT) { // One of the above succeeded if ((ch == '\"') && (nonEmptySegment)) { state = SCE_HBA_STRING; } else if (ch == '\'') { state = SCE_HBA_COMMENTLINE; } else if (IsAWordStart(ch)) { state = SCE_HBA_WORD; } else if (IsOperator(ch)) { styler.ColourTo(i, SCE_HBA_DEFAULT); } } else if (state == SCE_HJ_DEFAULT) { // One of the above succeeded if (ch == '/' && chNext == '*') { if (styler.SafeGetCharAt(i + 2) == '*') state = SCE_HJ_COMMENTDOC; else state = SCE_HJ_COMMENT; } else if (ch == '/' && chNext == '/') { state = SCE_HJ_COMMENTLINE; } else if ((ch == '\"') && (nonEmptySegment)) { state = SCE_HJ_DOUBLESTRING; } else if ((ch == '\'') && (nonEmptySegment)) { state = SCE_HJ_SINGLESTRING; } else if (IsAWordStart(ch)) { state = SCE_HJ_WORD; } else if (IsOperator(ch)) { styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType)); } } } switch (state) { case SCE_HJ_WORD: classifyWordHTJS(styler.GetStartSegment(), lengthDoc - 1, keywords2, styler, inScriptType); break; case SCE_HB_WORD: classifyWordHTVB(styler.GetStartSegment(), lengthDoc - 1, keywords3, styler, inScriptType); break; case SCE_HP_WORD: classifyWordHTPy(styler.GetStartSegment(), lengthDoc - 1, keywords4, styler, prevWord, inScriptType, isMako); break; case SCE_HPHP_WORD: classifyWordHTPHP(styler.GetStartSegment(), lengthDoc - 1, keywords5, styler); break; default: StateToPrint = statePrintForState(state, inScriptType); if (static_cast(styler.GetStartSegment()) < lengthDoc) styler.ColourTo(lengthDoc - 1, StateToPrint); break; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later if (fold) { const int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } styler.Flush(); } LexerModule lmHTML(SCLEX_HTML, LexerHTML::LexerFactoryHTML, "hypertext", htmlWordListDesc); LexerModule lmXML(SCLEX_XML, LexerHTML::LexerFactoryXML, "xml", htmlWordListDesc); LexerModule lmPHPSCRIPT(SCLEX_PHPSCRIPT, LexerHTML::LexerFactoryPHPScript, "phpscript", phpscriptWordListDesc); sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexers/LexJSON.cpp000066400000000000000000000326101463772530400262220ustar00rootroot00000000000000// Scintilla source code edit control /** * @file LexJSON.cxx * @date February 19, 2016 * @brief Lexer for JSON and JSON-LD formats * @author nkmathew * * The License.txt file describes the conditions under which this software may * be distributed. * */ #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #include "OptionSet.h" #include "DefaultLexer.h" using namespace Scintilla; static const char *const JSONWordListDesc[] = { "JSON Keywords", "JSON-LD Keywords", 0 }; /** * Used to detect compact IRI/URLs in JSON-LD without first looking ahead for the * colon separating the prefix and suffix * * https://www.w3.org/TR/json-ld/#dfn-compact-iri */ struct CompactIRI { int colonCount; bool foundInvalidChar; CharacterSet setCompactIRI; CompactIRI() { colonCount = 0; foundInvalidChar = false; setCompactIRI = CharacterSet(CharacterSet::setAlpha, "$_-"); } void resetState() { colonCount = 0; foundInvalidChar = false; } void checkChar(int ch) { if (ch == ':') { colonCount++; } else { foundInvalidChar |= !setCompactIRI.Contains(ch); } } bool shouldHighlight() const { return !foundInvalidChar && colonCount == 1; } }; /** * Keeps track of escaped characters in strings as per: * * https://tools.ietf.org/html/rfc7159#section-7 */ struct EscapeSequence { int digitsLeft; CharacterSet setHexDigits; CharacterSet setEscapeChars; EscapeSequence() { digitsLeft = 0; setHexDigits = CharacterSet(CharacterSet::setDigits, "ABCDEFabcdef"); setEscapeChars = CharacterSet(CharacterSet::setNone, "\\\"tnbfru/"); } // Returns true if the following character is a valid escaped character bool newSequence(int nextChar) { digitsLeft = 0; if (nextChar == 'u') { digitsLeft = 5; } else if (!setEscapeChars.Contains(nextChar)) { return false; } return true; } bool atEscapeEnd() const { return digitsLeft <= 0; } bool isInvalidChar(int currChar) const { return !setHexDigits.Contains(currChar); } }; struct OptionsJSON { bool foldCompact; bool fold; bool allowComments; bool escapeSequence; OptionsJSON() { foldCompact = false; fold = false; allowComments = false; escapeSequence = false; } }; struct OptionSetJSON : public OptionSet { OptionSetJSON() { DefineProperty("lexer.json.escape.sequence", &OptionsJSON::escapeSequence, "Set to 1 to enable highlighting of escape sequences in strings"); DefineProperty("lexer.json.allow.comments", &OptionsJSON::allowComments, "Set to 1 to enable highlighting of line/block comments in JSON"); DefineProperty("fold.compact", &OptionsJSON::foldCompact); DefineProperty("fold", &OptionsJSON::fold); DefineWordListSets(JSONWordListDesc); } }; class LexerJSON : public DefaultLexer { OptionsJSON options; OptionSetJSON optSetJSON; EscapeSequence escapeSeq; WordList keywordsJSON; WordList keywordsJSONLD; CharacterSet setOperators; CharacterSet setURL; CharacterSet setKeywordJSONLD; CharacterSet setKeywordJSON; CompactIRI compactIRI; static bool IsNextNonWhitespace(LexAccessor &styler, Sci_Position start, char ch) { Sci_Position i = 0; while (i < 50) { i++; char curr = styler.SafeGetCharAt(start+i, '\0'); char next = styler.SafeGetCharAt(start+i+1, '\0'); bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n'); if (curr == ch) { return true; } else if (!isspacechar(curr) || atEOL) { return false; } } return false; } /** * Looks for the colon following the end quote * * Assumes property names of lengths no longer than a 100 characters. * The colon is also expected to be less than 50 spaces after the end * quote for the string to be considered a property name */ static bool AtPropertyName(LexAccessor &styler, Sci_Position start) { Sci_Position i = 0; bool escaped = false; while (i < 100) { i++; char curr = styler.SafeGetCharAt(start+i, '\0'); if (escaped) { escaped = false; continue; } escaped = curr == '\\'; if (curr == '"') { return IsNextNonWhitespace(styler, start+i, ':'); } else if (!curr) { return false; } } return false; } static bool IsNextWordInList(WordList &keywordList, CharacterSet wordSet, StyleContext &context, LexAccessor &styler) { char word[51]; Sci_Position currPos = (Sci_Position) context.currentPos; int i = 0; while (i < 50) { char ch = styler.SafeGetCharAt(currPos + i); if (!wordSet.Contains(ch)) { break; } word[i] = ch; i++; } word[i] = '\0'; return keywordList.InList(word); } public: LexerJSON() : setOperators(CharacterSet::setNone, "[{}]:,"), setURL(CharacterSet::setAlphaNum, "-._~:/?#[]@!$&'()*+,),="), setKeywordJSONLD(CharacterSet::setAlpha, ":@"), setKeywordJSON(CharacterSet::setAlpha, "$_") { } virtual ~LexerJSON() {} int SCI_METHOD Version() const override { return lvOriginal; } void SCI_METHOD Release() override { delete this; } const char *SCI_METHOD PropertyNames() override { return optSetJSON.PropertyNames(); } int SCI_METHOD PropertyType(const char *name) override { return optSetJSON.PropertyType(name); } const char *SCI_METHOD DescribeProperty(const char *name) override { return optSetJSON.DescribeProperty(name); } Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override { if (optSetJSON.PropertySet(&options, key, val)) { return 0; } return -1; } Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override { WordList *wordListN = 0; switch (n) { case 0: wordListN = &keywordsJSON; break; case 1: wordListN = &keywordsJSONLD; break; } Sci_Position firstModification = -1; if (wordListN) { WordList wlNew; wlNew.Set(wl); if (*wordListN != wlNew) { wordListN->Set(wl); firstModification = 0; } } return firstModification; } void *SCI_METHOD PrivateCall(int, void *) override { return 0; } static ILexer *LexerFactoryJSON() { return new LexerJSON; } const char *SCI_METHOD DescribeWordListSets() override { return optSetJSON.DescribeWordListSets(); } void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override; void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override; }; void SCI_METHOD LexerJSON::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); StyleContext context(startPos, length, initStyle, styler); int stringStyleBefore = SCE_JSON_STRING; while (context.More()) { switch (context.state) { case SCE_JSON_BLOCKCOMMENT: if (context.Match("*/")) { context.Forward(); context.ForwardSetState(SCE_JSON_DEFAULT); } break; case SCE_JSON_LINECOMMENT: if (context.atLineEnd) { context.SetState(SCE_JSON_DEFAULT); } break; case SCE_JSON_STRINGEOL: if (context.atLineStart) { context.SetState(SCE_JSON_DEFAULT); } break; case SCE_JSON_ESCAPESEQUENCE: escapeSeq.digitsLeft--; if (!escapeSeq.atEscapeEnd()) { if (escapeSeq.isInvalidChar(context.ch)) { context.SetState(SCE_JSON_ERROR); } break; } if (context.ch == '"') { context.SetState(stringStyleBefore); context.ForwardSetState(SCE_C_DEFAULT); } else if (context.ch == '\\') { if (!escapeSeq.newSequence(context.chNext)) { context.SetState(SCE_JSON_ERROR); } context.Forward(); } else { context.SetState(stringStyleBefore); if (context.atLineEnd) { context.ChangeState(SCE_JSON_STRINGEOL); } } break; case SCE_JSON_PROPERTYNAME: case SCE_JSON_STRING: if (context.ch == '"') { if (compactIRI.shouldHighlight()) { context.ChangeState(SCE_JSON_COMPACTIRI); context.ForwardSetState(SCE_JSON_DEFAULT); compactIRI.resetState(); } else { context.ForwardSetState(SCE_JSON_DEFAULT); } } else if (context.atLineEnd) { context.ChangeState(SCE_JSON_STRINGEOL); } else if (context.ch == '\\') { stringStyleBefore = context.state; if (options.escapeSequence) { context.SetState(SCE_JSON_ESCAPESEQUENCE); if (!escapeSeq.newSequence(context.chNext)) { context.SetState(SCE_JSON_ERROR); } } context.Forward(); } else if (context.Match("https://") || context.Match("http://") || context.Match("ssh://") || context.Match("git://") || context.Match("svn://") || context.Match("ftp://") || context.Match("mailto:")) { // Handle most common URI schemes only stringStyleBefore = context.state; context.SetState(SCE_JSON_URI); } else if (context.ch == '@') { // https://www.w3.org/TR/json-ld/#dfn-keyword if (IsNextWordInList(keywordsJSONLD, setKeywordJSONLD, context, styler)) { stringStyleBefore = context.state; context.SetState(SCE_JSON_LDKEYWORD); } } else { compactIRI.checkChar(context.ch); } break; case SCE_JSON_LDKEYWORD: case SCE_JSON_URI: if ((!setKeywordJSONLD.Contains(context.ch) && (context.state == SCE_JSON_LDKEYWORD)) || (!setURL.Contains(context.ch))) { context.SetState(stringStyleBefore); } if (context.ch == '"') { context.ForwardSetState(SCE_JSON_DEFAULT); } else if (context.atLineEnd) { context.ChangeState(SCE_JSON_STRINGEOL); } break; case SCE_JSON_OPERATOR: case SCE_JSON_NUMBER: context.SetState(SCE_JSON_DEFAULT); break; case SCE_JSON_ERROR: if (context.atLineEnd) { context.SetState(SCE_JSON_DEFAULT); } break; case SCE_JSON_KEYWORD: if (!setKeywordJSON.Contains(context.ch)) { context.SetState(SCE_JSON_DEFAULT); } break; } if (context.state == SCE_JSON_DEFAULT) { if (context.ch == '"') { compactIRI.resetState(); context.SetState(SCE_JSON_STRING); Sci_Position currPos = static_cast(context.currentPos); if (AtPropertyName(styler, currPos)) { context.SetState(SCE_JSON_PROPERTYNAME); } } else if (setOperators.Contains(context.ch)) { context.SetState(SCE_JSON_OPERATOR); } else if (options.allowComments && context.Match("/*")) { context.SetState(SCE_JSON_BLOCKCOMMENT); context.Forward(); } else if (options.allowComments && context.Match("//")) { context.SetState(SCE_JSON_LINECOMMENT); } else if (setKeywordJSON.Contains(context.ch)) { if (IsNextWordInList(keywordsJSON, setKeywordJSON, context, styler)) { context.SetState(SCE_JSON_KEYWORD); } } bool numberStart = IsADigit(context.ch) && (context.chPrev == '+'|| context.chPrev == '-' || context.atLineStart || IsASpace(context.chPrev) || setOperators.Contains(context.chPrev)); bool exponentPart = tolower(context.ch) == 'e' && IsADigit(context.chPrev) && (IsADigit(context.chNext) || context.chNext == '+' || context.chNext == '-'); bool signPart = (context.ch == '-' || context.ch == '+') && ((tolower(context.chPrev) == 'e' && IsADigit(context.chNext)) || ((IsASpace(context.chPrev) || setOperators.Contains(context.chPrev)) && IsADigit(context.chNext))); bool adjacentDigit = IsADigit(context.ch) && IsADigit(context.chPrev); bool afterExponent = IsADigit(context.ch) && tolower(context.chPrev) == 'e'; bool dotPart = context.ch == '.' && IsADigit(context.chPrev) && IsADigit(context.chNext); bool afterDot = IsADigit(context.ch) && context.chPrev == '.'; if (numberStart || exponentPart || signPart || adjacentDigit || dotPart || afterExponent || afterDot) { context.SetState(SCE_JSON_NUMBER); } else if (context.state == SCE_JSON_DEFAULT && !IsASpace(context.ch)) { context.SetState(SCE_JSON_ERROR); } } context.Forward(); } context.Complete(); } void SCI_METHOD LexerJSON::Fold(Sci_PositionU startPos, Sci_Position length, int, IDocument *pAccess) { if (!options.fold) { return; } LexAccessor styler(pAccess); Sci_PositionU currLine = styler.GetLine(startPos); Sci_PositionU endPos = startPos + length; int currLevel = SC_FOLDLEVELBASE; if (currLine > 0) currLevel = styler.LevelAt(currLine - 1) >> 16; int nextLevel = currLevel; int visibleChars = 0; for (Sci_PositionU i = startPos; i < endPos; i++) { char curr = styler.SafeGetCharAt(i); char next = styler.SafeGetCharAt(i+1); bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n'); if (styler.StyleAt(i) == SCE_JSON_OPERATOR) { if (curr == '{' || curr == '[') { nextLevel++; } else if (curr == '}' || curr == ']') { nextLevel--; } } if (atEOL || i == (endPos-1)) { int level = currLevel | nextLevel << 16; if (!visibleChars && options.foldCompact) { level |= SC_FOLDLEVELWHITEFLAG; } else if (nextLevel > currLevel) { level |= SC_FOLDLEVELHEADERFLAG; } if (level != styler.LevelAt(currLine)) { styler.SetLevel(currLine, level); } currLine++; currLevel = nextLevel; visibleChars = 0; } if (!isspacechar(curr)) { visibleChars++; } } } LexerModule lmJSON(SCLEX_JSON, LexerJSON::LexerFactoryJSON, "json", JSONWordListDesc); sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexers/LexSQL.cpp000066400000000000000000000747251463772530400261250ustar00rootroot00000000000000//-*- coding: utf-8 -*- // Scintilla source code edit control /** @file LexSQL.cxx ** Lexer for SQL, including PL/SQL and SQL*Plus. ** Improved by Jérôme LAFORGE from 2010 to 2012. **/ // Copyright 1998-2012 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #include "OptionSet.h" #include "SparseState.h" #include "DefaultLexer.h" using namespace Scintilla; static inline bool IsAWordChar(int ch, bool sqlAllowDottedWord) { if (!sqlAllowDottedWord) return (ch < 0x80) && (isalnum(ch) || ch == '_'); else return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.'); } static inline bool IsAWordStart(int ch) { return (ch < 0x80) && (isalpha(ch) || ch == '_'); } static inline bool IsADoxygenChar(int ch) { return (islower(ch) || ch == '$' || ch == '@' || ch == '\\' || ch == '&' || ch == '<' || ch == '>' || ch == '#' || ch == '{' || ch == '}' || ch == '[' || ch == ']'); } static inline bool IsANumberChar(int ch, int chPrev) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && (isdigit(ch) || toupper(ch) == 'E' || ch == '.' || ((ch == '-' || ch == '+') && chPrev < 0x80 && toupper(chPrev) == 'E')); } typedef unsigned int sql_state_t; class SQLStates { public : void Set(Sci_Position lineNumber, unsigned short int sqlStatesLine) { sqlStatement.Set(lineNumber, sqlStatesLine); } sql_state_t IgnoreWhen (sql_state_t sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_IGNORE_WHEN; else sqlStatesLine &= ~MASK_IGNORE_WHEN; return sqlStatesLine; } sql_state_t IntoCondition (sql_state_t sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_INTO_CONDITION; else sqlStatesLine &= ~MASK_INTO_CONDITION; return sqlStatesLine; } sql_state_t IntoExceptionBlock (sql_state_t sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_INTO_EXCEPTION; else sqlStatesLine &= ~MASK_INTO_EXCEPTION; return sqlStatesLine; } sql_state_t IntoDeclareBlock (sql_state_t sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_INTO_DECLARE; else sqlStatesLine &= ~MASK_INTO_DECLARE; return sqlStatesLine; } sql_state_t IntoMergeStatement (sql_state_t sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_MERGE_STATEMENT; else sqlStatesLine &= ~MASK_MERGE_STATEMENT; return sqlStatesLine; } sql_state_t CaseMergeWithoutWhenFound (sql_state_t sqlStatesLine, bool found) { if (found) sqlStatesLine |= MASK_CASE_MERGE_WITHOUT_WHEN_FOUND; else sqlStatesLine &= ~MASK_CASE_MERGE_WITHOUT_WHEN_FOUND; return sqlStatesLine; } sql_state_t IntoSelectStatementOrAssignment (sql_state_t sqlStatesLine, bool found) { if (found) sqlStatesLine |= MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT; else sqlStatesLine &= ~MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT; return sqlStatesLine; } sql_state_t BeginCaseBlock (sql_state_t sqlStatesLine) { if ((sqlStatesLine & MASK_NESTED_CASES) < MASK_NESTED_CASES) { sqlStatesLine++; } return sqlStatesLine; } sql_state_t EndCaseBlock (sql_state_t sqlStatesLine) { if ((sqlStatesLine & MASK_NESTED_CASES) > 0) { sqlStatesLine--; } return sqlStatesLine; } sql_state_t IntoCreateStatement (sql_state_t sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_INTO_CREATE; else sqlStatesLine &= ~MASK_INTO_CREATE; return sqlStatesLine; } sql_state_t IntoCreateViewStatement (sql_state_t sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_INTO_CREATE_VIEW; else sqlStatesLine &= ~MASK_INTO_CREATE_VIEW; return sqlStatesLine; } sql_state_t IntoCreateViewAsStatement (sql_state_t sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_INTO_CREATE_VIEW_AS_STATEMENT; else sqlStatesLine &= ~MASK_INTO_CREATE_VIEW_AS_STATEMENT; return sqlStatesLine; } bool IsIgnoreWhen (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_IGNORE_WHEN) != 0; } bool IsIntoCondition (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_INTO_CONDITION) != 0; } bool IsIntoCaseBlock (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_NESTED_CASES) != 0; } bool IsIntoExceptionBlock (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_INTO_EXCEPTION) != 0; } bool IsIntoSelectStatementOrAssignment (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT) != 0; } bool IsCaseMergeWithoutWhenFound (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_CASE_MERGE_WITHOUT_WHEN_FOUND) != 0; } bool IsIntoDeclareBlock (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_INTO_DECLARE) != 0; } bool IsIntoMergeStatement (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_MERGE_STATEMENT) != 0; } bool IsIntoCreateStatement (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_INTO_CREATE) != 0; } bool IsIntoCreateViewStatement (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_INTO_CREATE_VIEW) != 0; } bool IsIntoCreateViewAsStatement (sql_state_t sqlStatesLine) { return (sqlStatesLine & MASK_INTO_CREATE_VIEW_AS_STATEMENT) != 0; } sql_state_t ForLine(Sci_Position lineNumber) { return sqlStatement.ValueAt(lineNumber); } SQLStates() {} private : SparseState sqlStatement; enum { MASK_NESTED_CASES = 0x0001FF, MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT = 0x000200, MASK_CASE_MERGE_WITHOUT_WHEN_FOUND = 0x000400, MASK_MERGE_STATEMENT = 0x000800, MASK_INTO_DECLARE = 0x001000, MASK_INTO_EXCEPTION = 0x002000, MASK_INTO_CONDITION = 0x004000, MASK_IGNORE_WHEN = 0x008000, MASK_INTO_CREATE = 0x010000, MASK_INTO_CREATE_VIEW = 0x020000, MASK_INTO_CREATE_VIEW_AS_STATEMENT = 0x040000 }; }; // Options used for LexerSQL struct OptionsSQL { bool fold; bool foldAtElse; bool foldComment; bool foldCompact; bool foldOnlyBegin; bool sqlBackticksIdentifier; bool sqlNumbersignComment; bool sqlBackslashEscapes; bool sqlAllowDottedWord; OptionsSQL() { fold = false; foldAtElse = false; foldComment = false; foldCompact = false; foldOnlyBegin = false; sqlBackticksIdentifier = false; sqlNumbersignComment = false; sqlBackslashEscapes = false; sqlAllowDottedWord = false; } }; static const char * const sqlWordListDesc[] = { "Keywords", "Database Objects", "PLDoc", "SQL*Plus", "User Keywords 1", "User Keywords 2", "User Keywords 3", "User Keywords 4", 0 }; struct OptionSetSQL : public OptionSet { OptionSetSQL() { DefineProperty("fold", &OptionsSQL::fold); DefineProperty("fold.sql.at.else", &OptionsSQL::foldAtElse, "This option enables SQL folding on a \"ELSE\" and \"ELSIF\" line of an IF statement."); DefineProperty("fold.comment", &OptionsSQL::foldComment); DefineProperty("fold.compact", &OptionsSQL::foldCompact); DefineProperty("fold.sql.only.begin", &OptionsSQL::foldOnlyBegin); DefineProperty("lexer.sql.backticks.identifier", &OptionsSQL::sqlBackticksIdentifier); DefineProperty("lexer.sql.numbersign.comment", &OptionsSQL::sqlNumbersignComment, "If \"lexer.sql.numbersign.comment\" property is set to 0 a line beginning with '#' will not be a comment."); DefineProperty("sql.backslash.escapes", &OptionsSQL::sqlBackslashEscapes, "Enables backslash as an escape character in SQL."); DefineProperty("lexer.sql.allow.dotted.word", &OptionsSQL::sqlAllowDottedWord, "Set to 1 to colourise recognized words with dots " "(recommended for Oracle PL/SQL objects)."); DefineWordListSets(sqlWordListDesc); } }; class LexerSQL : public DefaultLexer { public : LexerSQL() {} virtual ~LexerSQL() {} int SCI_METHOD Version () const override { return lvOriginal; } void SCI_METHOD Release() override { delete this; } const char * SCI_METHOD PropertyNames() override { return osSQL.PropertyNames(); } int SCI_METHOD PropertyType(const char *name) override { return osSQL.PropertyType(name); } const char * SCI_METHOD DescribeProperty(const char *name) override { return osSQL.DescribeProperty(name); } Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override { if (osSQL.PropertySet(&options, key, val)) { return 0; } return -1; } const char * SCI_METHOD DescribeWordListSets() override { return osSQL.DescribeWordListSets(); } Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override; void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override; void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override; void * SCI_METHOD PrivateCall(int, void *) override { return 0; } static ILexer *LexerFactorySQL() { return new LexerSQL(); } private: bool IsStreamCommentStyle(int style) { return style == SCE_SQL_COMMENT || style == SCE_SQL_COMMENTDOC || style == SCE_SQL_COMMENTDOCKEYWORD || style == SCE_SQL_COMMENTDOCKEYWORDERROR; } bool IsCommentStyle (int style) { switch (style) { case SCE_SQL_COMMENT : case SCE_SQL_COMMENTDOC : case SCE_SQL_COMMENTLINE : case SCE_SQL_COMMENTLINEDOC : case SCE_SQL_COMMENTDOCKEYWORD : case SCE_SQL_COMMENTDOCKEYWORDERROR : return true; default : return false; } } bool IsCommentLine (Sci_Position line, LexAccessor &styler) { Sci_Position pos = styler.LineStart(line); Sci_Position eol_pos = styler.LineStart(line + 1) - 1; for (Sci_Position i = pos; i + 1 < eol_pos; i++) { int style = styler.StyleAt(i); // MySQL needs -- comments to be followed by space or control char if (style == SCE_SQL_COMMENTLINE && styler.Match(i, "--")) return true; else if (!IsASpaceOrTab(styler[i])) return false; } return false; } OptionsSQL options; OptionSetSQL osSQL; SQLStates sqlStates; WordList keywords1; WordList keywords2; WordList kw_pldoc; WordList kw_sqlplus; WordList kw_user1; WordList kw_user2; WordList kw_user3; WordList kw_user4; }; Sci_Position SCI_METHOD LexerSQL::WordListSet(int n, const char *wl) { WordList *wordListN = 0; switch (n) { case 0: wordListN = &keywords1; break; case 1: wordListN = &keywords2; break; case 2: wordListN = &kw_pldoc; break; case 3: wordListN = &kw_sqlplus; break; case 4: wordListN = &kw_user1; break; case 5: wordListN = &kw_user2; break; case 6: wordListN = &kw_user3; break; case 7: wordListN = &kw_user4; } Sci_Position firstModification = -1; if (wordListN) { WordList wlNew; wlNew.Set(wl); if (*wordListN != wlNew) { wordListN->Set(wl); firstModification = 0; } } return firstModification; } void SCI_METHOD LexerSQL::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); StyleContext sc(startPos, length, initStyle, styler); int styleBeforeDCKeyword = SCE_SQL_DEFAULT; Sci_Position offset = 0; for (; sc.More(); sc.Forward(), offset++) { // Determine if the current state should terminate. switch (sc.state) { case SCE_SQL_OPERATOR: sc.SetState(SCE_SQL_DEFAULT); break; case SCE_SQL_NUMBER: // We stop the number definition on non-numerical non-dot non-eE non-sign char if (!IsANumberChar(sc.ch, sc.chPrev)) { sc.SetState(SCE_SQL_DEFAULT); } break; case SCE_SQL_IDENTIFIER: if (!IsAWordChar(sc.ch, options.sqlAllowDottedWord)) { int nextState = SCE_SQL_DEFAULT; char s[1000]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords1.InList(s)) { sc.ChangeState(SCE_SQL_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_SQL_WORD2); } else if (kw_sqlplus.InListAbbreviated(s, '~')) { sc.ChangeState(SCE_SQL_SQLPLUS); if (strncmp(s, "rem", 3) == 0) { nextState = SCE_SQL_SQLPLUS_COMMENT; } else if (strncmp(s, "pro", 3) == 0) { nextState = SCE_SQL_SQLPLUS_PROMPT; } } else if (kw_user1.InList(s)) { sc.ChangeState(SCE_SQL_USER1); } else if (kw_user2.InList(s)) { sc.ChangeState(SCE_SQL_USER2); } else if (kw_user3.InList(s)) { sc.ChangeState(SCE_SQL_USER3); } else if (kw_user4.InList(s)) { sc.ChangeState(SCE_SQL_USER4); } sc.SetState(nextState); } break; case SCE_SQL_QUOTEDIDENTIFIER: if (sc.ch == 0x60) { if (sc.chNext == 0x60) { sc.Forward(); // Ignore it } else { sc.ForwardSetState(SCE_SQL_DEFAULT); } } break; case SCE_SQL_COMMENT: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_SQL_DEFAULT); } break; case SCE_SQL_COMMENTDOC: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_SQL_DEFAULT); } else if (sc.ch == '@' || sc.ch == '\\') { // Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = SCE_SQL_COMMENTDOC; sc.SetState(SCE_SQL_COMMENTDOCKEYWORD); } } break; case SCE_SQL_COMMENTLINE: case SCE_SQL_COMMENTLINEDOC: case SCE_SQL_SQLPLUS_COMMENT: case SCE_SQL_SQLPLUS_PROMPT: if (sc.atLineStart) { sc.SetState(SCE_SQL_DEFAULT); } break; case SCE_SQL_COMMENTDOCKEYWORD: if ((styleBeforeDCKeyword == SCE_SQL_COMMENTDOC) && sc.Match('*', '/')) { sc.ChangeState(SCE_SQL_COMMENTDOCKEYWORDERROR); sc.Forward(); sc.ForwardSetState(SCE_SQL_DEFAULT); } else if (!IsADoxygenChar(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (!isspace(sc.ch) || !kw_pldoc.InList(s + 1)) { sc.ChangeState(SCE_SQL_COMMENTDOCKEYWORDERROR); } sc.SetState(styleBeforeDCKeyword); } break; case SCE_SQL_CHARACTER: if (options.sqlBackslashEscapes && sc.ch == '\\') { sc.Forward(); } else if (sc.ch == '\'') { if (sc.chNext == '\"') { sc.Forward(); } else { sc.ForwardSetState(SCE_SQL_DEFAULT); } } break; case SCE_SQL_STRING: if (options.sqlBackslashEscapes && sc.ch == '\\') { // Escape sequence sc.Forward(); } else if (sc.ch == '\"') { if (sc.chNext == '\"') { sc.Forward(); } else { sc.ForwardSetState(SCE_SQL_DEFAULT); } } break; case SCE_SQL_QOPERATOR: // Locate the unique Q operator character sc.Complete(); char qOperator = 0x00; for (Sci_Position styleStartPos = sc.currentPos; styleStartPos > 0; --styleStartPos) { if (styler.StyleAt(styleStartPos - 1) != SCE_SQL_QOPERATOR) { qOperator = styler.SafeGetCharAt(styleStartPos + 2); break; } } char qComplement = 0x00; if (qOperator == '<') { qComplement = '>'; } else if (qOperator == '(') { qComplement = ')'; } else if (qOperator == '{') { qComplement = '}'; } else if (qOperator == '[') { qComplement = ']'; } else { qComplement = qOperator; } if (sc.Match(qComplement, '\'')) { sc.Forward(); sc.ForwardSetState(SCE_SQL_DEFAULT); } break; } // Determine if a new state should be entered. if (sc.state == SCE_SQL_DEFAULT) { if (sc.Match('q', '\'') || sc.Match('Q', '\'')) { sc.SetState(SCE_SQL_QOPERATOR); sc.Forward(); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext)) || ((sc.ch == '-' || sc.ch == '+') && IsADigit(sc.chNext) && !IsADigit(sc.chPrev))) { sc.SetState(SCE_SQL_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_SQL_IDENTIFIER); } else if (sc.ch == 0x60 && options.sqlBackticksIdentifier) { sc.SetState(SCE_SQL_QUOTEDIDENTIFIER); } else if (sc.Match('/', '*')) { if (sc.Match("/**") || sc.Match("/*!")) { // Support of Doxygen doc. style sc.SetState(SCE_SQL_COMMENTDOC); } else { sc.SetState(SCE_SQL_COMMENT); } sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('-', '-')) { // MySQL requires a space or control char after -- // http://dev.mysql.com/doc/mysql/en/ansi-diff-comments.html // Perhaps we should enforce that with proper property: //~ } else if (sc.Match("-- ")) { sc.SetState(SCE_SQL_COMMENTLINE); } else if (sc.ch == '#' && options.sqlNumbersignComment) { sc.SetState(SCE_SQL_COMMENTLINEDOC); } else if (sc.ch == '\'') { sc.SetState(SCE_SQL_CHARACTER); } else if (sc.ch == '\"') { sc.SetState(SCE_SQL_STRING); } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_SQL_OPERATOR); } } } sc.Complete(); } void SCI_METHOD LexerSQL::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) { if (!options.fold) return; LexAccessor styler(pAccess); Sci_PositionU endPos = startPos + length; int visibleChars = 0; Sci_Position lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) { // Backtrack to previous line in case need to fix its fold status for folding block of single-line comments (i.e. '--'). Sci_Position lastNLPos = -1; // And keep going back until we find an operator ';' followed // by white-space and/or comments. This will improve folding. while (--startPos > 0) { char ch = styler[startPos]; if (ch == '\n' || (ch == '\r' && styler[startPos + 1] != '\n')) { lastNLPos = startPos; } else if (ch == ';' && styler.StyleAt(startPos) == SCE_SQL_OPERATOR) { bool isAllClear = true; for (Sci_Position tempPos = startPos + 1; tempPos < lastNLPos; ++tempPos) { int tempStyle = styler.StyleAt(tempPos); if (!IsCommentStyle(tempStyle) && tempStyle != SCE_SQL_DEFAULT) { isAllClear = false; break; } } if (isAllClear) { startPos = lastNLPos + 1; break; } } } lineCurrent = styler.GetLine(startPos); if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16; } // And because folding ends at ';', keep going until we find one // Otherwise if create ... view ... as is split over multiple // lines the folding won't always update immediately. Sci_PositionU docLength = styler.Length(); for (; endPos < docLength; ++endPos) { if (styler.SafeGetCharAt(endPos) == ';') { break; } } int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; bool endFound = false; bool isUnfoldingIgnored = false; // this statementFound flag avoids to fold when the statement is on only one line by ignoring ELSE or ELSIF // eg. "IF condition1 THEN ... ELSIF condition2 THEN ... ELSE ... END IF;" bool statementFound = false; sql_state_t sqlStatesCurrentLine = 0; if (!options.foldOnlyBegin) { sqlStatesCurrentLine = sqlStates.ForLine(lineCurrent); } for (Sci_PositionU i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (atEOL || (!IsCommentStyle(style) && ch == ';')) { if (endFound) { //Maybe this is the end of "EXCEPTION" BLOCK (eg. "BEGIN ... EXCEPTION ... END;") sqlStatesCurrentLine = sqlStates.IntoExceptionBlock(sqlStatesCurrentLine, false); } // set endFound and isUnfoldingIgnored to false if EOL is reached or ';' is found endFound = false; isUnfoldingIgnored = false; } if ((!IsCommentStyle(style) && ch == ';')) { if (sqlStates.IsIntoMergeStatement(sqlStatesCurrentLine)) { // This is the end of "MERGE" statement. if (!sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) levelNext--; sqlStatesCurrentLine = sqlStates.IntoMergeStatement(sqlStatesCurrentLine, false); levelNext--; } if (sqlStates.IsIntoSelectStatementOrAssignment(sqlStatesCurrentLine)) sqlStatesCurrentLine = sqlStates.IntoSelectStatementOrAssignment(sqlStatesCurrentLine, false); if (sqlStates.IsIntoCreateStatement(sqlStatesCurrentLine)) { if (sqlStates.IsIntoCreateViewStatement(sqlStatesCurrentLine)) { if (sqlStates.IsIntoCreateViewAsStatement(sqlStatesCurrentLine)) { levelNext--; sqlStatesCurrentLine = sqlStates.IntoCreateViewAsStatement(sqlStatesCurrentLine, false); } sqlStatesCurrentLine = sqlStates.IntoCreateViewStatement(sqlStatesCurrentLine, false); } sqlStatesCurrentLine = sqlStates.IntoCreateStatement(sqlStatesCurrentLine, false); } } if (ch == ':' && chNext == '=' && !IsCommentStyle(style)) sqlStatesCurrentLine = sqlStates.IntoSelectStatementOrAssignment(sqlStatesCurrentLine, true); if (options.foldComment && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelNext++; } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelNext--; } } if (options.foldComment && (style == SCE_SQL_COMMENTLINE)) { // MySQL needs -- comments to be followed by space or control char if ((ch == '-') && (chNext == '-')) { char chNext2 = styler.SafeGetCharAt(i + 2); char chNext3 = styler.SafeGetCharAt(i + 3); if (chNext2 == '{' || chNext3 == '{') { levelNext++; } else if (chNext2 == '}' || chNext3 == '}') { levelNext--; } } } // Fold block of single-line comments (i.e. '--'). if (options.foldComment && atEOL && IsCommentLine(lineCurrent, styler)) { if (!IsCommentLine(lineCurrent - 1, styler) && IsCommentLine(lineCurrent + 1, styler)) levelNext++; else if (IsCommentLine(lineCurrent - 1, styler) && !IsCommentLine(lineCurrent + 1, styler)) levelNext--; } if (style == SCE_SQL_OPERATOR) { if (ch == '(') { if (levelCurrent > levelNext) levelCurrent--; levelNext++; } else if (ch == ')') { levelNext--; } else if ((!options.foldOnlyBegin) && ch == ';') { sqlStatesCurrentLine = sqlStates.IgnoreWhen(sqlStatesCurrentLine, false); } } // If new keyword (cannot trigger on elseif or nullif, does less tests) if (style == SCE_SQL_WORD && stylePrev != SCE_SQL_WORD) { const int MAX_KW_LEN = 9; // Maximum length of folding keywords char s[MAX_KW_LEN + 2]; unsigned int j = 0; for (; j < MAX_KW_LEN + 1; j++) { if (!iswordchar(styler[i + j])) { break; } s[j] = static_cast(tolower(styler[i + j])); } if (j == MAX_KW_LEN + 1) { // Keyword too long, don't test it s[0] = '\0'; } else { s[j] = '\0'; } if (!options.foldOnlyBegin && strcmp(s, "select") == 0) { sqlStatesCurrentLine = sqlStates.IntoSelectStatementOrAssignment(sqlStatesCurrentLine, true); } else if (strcmp(s, "if") == 0) { if (endFound) { endFound = false; if (options.foldOnlyBegin && !isUnfoldingIgnored) { // this end isn't for begin block, but for if block ("end if;") // so ignore previous "end" by increment levelNext. levelNext++; } } else { if (!options.foldOnlyBegin) sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, true); if (levelCurrent > levelNext) { // doesn't include this line into the folding block // because doesn't hide IF (eg "END; IF") levelCurrent = levelNext; } } } else if (!options.foldOnlyBegin && strcmp(s, "then") == 0 && sqlStates.IsIntoCondition(sqlStatesCurrentLine)) { sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, false); if (!options.foldOnlyBegin) { if (levelCurrent > levelNext) { levelCurrent = levelNext; } if (!statementFound) levelNext++; statementFound = true; } else if (levelCurrent > levelNext) { // doesn't include this line into the folding block // because doesn't hide LOOP or CASE (eg "END; LOOP" or "END; CASE") levelCurrent = levelNext; } } else if (strcmp(s, "loop") == 0 || strcmp(s, "case") == 0) { if (endFound) { endFound = false; if (options.foldOnlyBegin && !isUnfoldingIgnored) { // this end isn't for begin block, but for loop block ("end loop;") or case block ("end case;") // so ignore previous "end" by increment levelNext. levelNext++; } if ((!options.foldOnlyBegin) && strcmp(s, "case") == 0) { sqlStatesCurrentLine = sqlStates.EndCaseBlock(sqlStatesCurrentLine); if (!sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) levelNext--; //again for the "end case;" and block when } } else if (!options.foldOnlyBegin) { if (strcmp(s, "case") == 0) { sqlStatesCurrentLine = sqlStates.BeginCaseBlock(sqlStatesCurrentLine); sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, true); } if (levelCurrent > levelNext) levelCurrent = levelNext; if (!statementFound) levelNext++; statementFound = true; } else if (levelCurrent > levelNext) { // doesn't include this line into the folding block // because doesn't hide LOOP or CASE (eg "END; LOOP" or "END; CASE") levelCurrent = levelNext; } } else if ((!options.foldOnlyBegin) && ( // folding for ELSE and ELSIF block only if foldAtElse is set // and IF or CASE aren't on only one line with ELSE or ELSIF (with flag statementFound) options.foldAtElse && !statementFound) && strcmp(s, "elsif") == 0) { sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, true); levelCurrent--; levelNext--; } else if ((!options.foldOnlyBegin) && ( // folding for ELSE and ELSIF block only if foldAtElse is set // and IF or CASE aren't on only one line with ELSE or ELSIF (with flag statementFound) options.foldAtElse && !statementFound) && strcmp(s, "else") == 0) { // prevent also ELSE is on the same line (eg. "ELSE ... END IF;") statementFound = true; if (sqlStates.IsIntoCaseBlock(sqlStatesCurrentLine) && sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) { sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, false); levelNext++; } else { // we are in same case "} ELSE {" in C language levelCurrent--; } } else if (strcmp(s, "begin") == 0) { levelNext++; sqlStatesCurrentLine = sqlStates.IntoDeclareBlock(sqlStatesCurrentLine, false); } else if ((strcmp(s, "end") == 0) || // SQL Anywhere permits IF ... ELSE ... ENDIF // will only be active if "endif" appears in the // keyword list. (strcmp(s, "endif") == 0)) { endFound = true; levelNext--; if (sqlStates.IsIntoSelectStatementOrAssignment(sqlStatesCurrentLine) && !sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) levelNext--; if (levelNext < SC_FOLDLEVELBASE) { levelNext = SC_FOLDLEVELBASE; isUnfoldingIgnored = true; } } else if ((!options.foldOnlyBegin) && strcmp(s, "when") == 0 && !sqlStates.IsIgnoreWhen(sqlStatesCurrentLine) && !sqlStates.IsIntoExceptionBlock(sqlStatesCurrentLine) && ( sqlStates.IsIntoCaseBlock(sqlStatesCurrentLine) || sqlStates.IsIntoMergeStatement(sqlStatesCurrentLine) ) ) { sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, true); // Don't foldind when CASE and WHEN are on the same line (with flag statementFound) (eg. "CASE selector WHEN expression1 THEN sequence_of_statements1;\n") // and same way for MERGE statement. if (!statementFound) { if (!sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) { levelCurrent--; levelNext--; } sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, false); } } else if ((!options.foldOnlyBegin) && strcmp(s, "exit") == 0) { sqlStatesCurrentLine = sqlStates.IgnoreWhen(sqlStatesCurrentLine, true); } else if ((!options.foldOnlyBegin) && !sqlStates.IsIntoDeclareBlock(sqlStatesCurrentLine) && strcmp(s, "exception") == 0) { sqlStatesCurrentLine = sqlStates.IntoExceptionBlock(sqlStatesCurrentLine, true); } else if ((!options.foldOnlyBegin) && (strcmp(s, "declare") == 0 || strcmp(s, "function") == 0 || strcmp(s, "procedure") == 0 || strcmp(s, "package") == 0)) { sqlStatesCurrentLine = sqlStates.IntoDeclareBlock(sqlStatesCurrentLine, true); } else if ((!options.foldOnlyBegin) && strcmp(s, "merge") == 0) { sqlStatesCurrentLine = sqlStates.IntoMergeStatement(sqlStatesCurrentLine, true); sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, true); levelNext++; statementFound = true; } else if ((!options.foldOnlyBegin) && strcmp(s, "create") == 0) { sqlStatesCurrentLine = sqlStates.IntoCreateStatement(sqlStatesCurrentLine, true); } else if ((!options.foldOnlyBegin) && strcmp(s, "view") == 0 && sqlStates.IsIntoCreateStatement(sqlStatesCurrentLine)) { sqlStatesCurrentLine = sqlStates.IntoCreateViewStatement(sqlStatesCurrentLine, true); } else if ((!options.foldOnlyBegin) && strcmp(s, "as") == 0 && sqlStates.IsIntoCreateViewStatement(sqlStatesCurrentLine) && ! sqlStates.IsIntoCreateViewAsStatement(sqlStatesCurrentLine)) { sqlStatesCurrentLine = sqlStates.IntoCreateViewAsStatement(sqlStatesCurrentLine, true); levelNext++; } } if (atEOL) { int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; if (visibleChars == 0 && options.foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; visibleChars = 0; statementFound = false; if (!options.foldOnlyBegin) sqlStates.Set(lineCurrent, sqlStatesCurrentLine); } if (!isspacechar(ch)) { visibleChars++; } } } LexerModule lmSQL(SCLEX_SQL, LexerSQL::LexerFactorySQL, "sql", sqlWordListDesc); sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexers/License.txt000066400000000000000000000015261463772530400264210ustar00rootroot00000000000000License for Scintilla and SciTE Copyright 1998-2003 by Neil Hodgson All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NEIL HODGSON 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.sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/000077500000000000000000000000001463772530400242475ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/Accessor.cpp000066400000000000000000000042011463772530400265120ustar00rootroot00000000000000// Scintilla source code edit control /** @file Accessor.cxx ** Interfaces between Scintilla and lexers. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" using namespace Scintilla; Accessor::Accessor(IDocument *pAccess_, PropSetSimple *pprops_) : LexAccessor(pAccess_), pprops(pprops_) { } int Accessor::GetPropertyInt(const char *key, int defaultValue) const { return pprops->GetInt(key, defaultValue); } int Accessor::IndentAmount(Sci_Position line, int *flags, PFNIsCommentLeader pfnIsCommentLeader) { const Sci_Position end = Length(); int spaceFlags = 0; // Determines the indentation level of the current line and also checks for consistent // indentation compared to the previous line. // Indentation is judged consistent when the indentation whitespace of each line lines // the same or the indentation of one line is a prefix of the other. Sci_Position pos = LineStart(line); char ch = (*this)[pos]; int indent = 0; bool inPrevPrefix = line > 0; Sci_Position posPrev = inPrevPrefix ? LineStart(line-1) : 0; while ((ch == ' ' || ch == '\t') && (pos < end)) { if (inPrevPrefix) { const char chPrev = (*this)[posPrev++]; if (chPrev == ' ' || chPrev == '\t') { if (chPrev != ch) spaceFlags |= wsInconsistent; } else { inPrevPrefix = false; } } if (ch == ' ') { spaceFlags |= wsSpace; indent++; } else { // Tab spaceFlags |= wsTab; if (spaceFlags & wsSpace) spaceFlags |= wsSpaceTab; indent = (indent / 8 + 1) * 8; } ch = (*this)[++pos]; } *flags = spaceFlags; indent += SC_FOLDLEVELBASE; // if completely empty line or the start of a comment... if ((LineStart(line) == Length()) || (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') || (pfnIsCommentLeader && (*pfnIsCommentLeader)(*this, pos, end-pos))) return indent | SC_FOLDLEVELWHITEFLAG; else return indent; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/Accessor.h000066400000000000000000000014751463772530400261710ustar00rootroot00000000000000// Scintilla source code edit control /** @file Accessor.h ** Interfaces between Scintilla and lexers. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef ACCESSOR_H #define ACCESSOR_H namespace Scintilla { enum { wsSpace=1, wsTab=2, wsSpaceTab=4, wsInconsistent=8 }; class Accessor; class WordList; class PropSetSimple; typedef bool (*PFNIsCommentLeader)(Accessor &styler, Sci_Position pos, Sci_Position len); class Accessor : public LexAccessor { public: PropSetSimple *pprops; Accessor(IDocument *pAccess_, PropSetSimple *pprops_); int GetPropertyInt(const char *, int defaultValue=0) const; int IndentAmount(Sci_Position line, int *flags, PFNIsCommentLeader pfnIsCommentLeader = 0); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/CharacterCategory.cpp000066400000000000000000001116151463772530400303520ustar00rootroot00000000000000// Scintilla source code edit control /** @file CharacterCategory.cxx ** Returns the Unicode general category of a character. ** Table automatically regenerated by scripts/GenerateCharacterCategory.py ** Should only be rarely regenerated for new versions of Unicode. **/ // Copyright 2013 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include "CharacterCategory.h" namespace Scintilla { namespace { // Use an unnamed namespace to protect the declarations from name conflicts const int catRanges[] = { //++Autogenerated -- start of section automatically generated // Created with Python 3.7.0, Unicode 11.0.0 25, 1046, 1073, 1171, 1201, 1293, 1326, 1361, 1394, 1425, 1452, 1489, 1544, 1873, 1938, 2033, 2080, 2925, 2961, 2990, 3028, 3051, 3092, 3105, 3949, 3986, 4014, 4050, 4089, 5142, 5169, 5203, 5333, 5361, 5396, 5429, 5444, 5487, 5522, 5562, 5589, 5620, 5653, 5682, 5706, 5780, 5793, 5841, 5908, 5930, 5956, 6000, 6026, 6129, 6144, 6898, 6912, 7137, 7922, 7937, 8192, 8225, 8256, 8289, 8320, 8353, 8384, 8417, 8448, 8481, 8512, 8545, 8576, 8609, 8640, 8673, 8704, 8737, 8768, 8801, 8832, 8865, 8896, 8929, 8960, 8993, 9024, 9057, 9088, 9121, 9152, 9185, 9216, 9249, 9280, 9313, 9344, 9377, 9408, 9441, 9472, 9505, 9536, 9569, 9600, 9633, 9664, 9697, 9728, 9761, 9792, 9825, 9856, 9889, 9920, 9953, 10016, 10049, 10080, 10113, 10144, 10177, 10208, 10241, 10272, 10305, 10336, 10369, 10400, 10433, 10464, 10497, 10560, 10593, 10624, 10657, 10688, 10721, 10752, 10785, 10816, 10849, 10880, 10913, 10944, 10977, 11008, 11041, 11072, 11105, 11136, 11169, 11200, 11233, 11264, 11297, 11328, 11361, 11392, 11425, 11456, 11489, 11520, 11553, 11584, 11617, 11648, 11681, 11712, 11745, 11776, 11809, 11840, 11873, 11904, 11937, 11968, 12001, 12032, 12097, 12128, 12161, 12192, 12225, 12320, 12385, 12416, 12449, 12480, 12545, 12576, 12673, 12736, 12865, 12896, 12961, 12992, 13089, 13184, 13249, 13280, 13345, 13376, 13409, 13440, 13473, 13504, 13569, 13600, 13633, 13696, 13729, 13760, 13825, 13856, 13953, 13984, 14017, 14048, 14113, 14180, 14208, 14241, 14340, 14464, 14498, 14529, 14560, 14594, 14625, 14656, 14690, 14721, 14752, 14785, 14816, 14849, 14880, 14913, 14944, 14977, 15008, 15041, 15072, 15105, 15136, 15169, 15200, 15233, 15296, 15329, 15360, 15393, 15424, 15457, 15488, 15521, 15552, 15585, 15616, 15649, 15680, 15713, 15744, 15777, 15808, 15841, 15904, 15938, 15969, 16000, 16033, 16064, 16161, 16192, 16225, 16256, 16289, 16320, 16353, 16384, 16417, 16448, 16481, 16512, 16545, 16576, 16609, 16640, 16673, 16704, 16737, 16768, 16801, 16832, 16865, 16896, 16929, 16960, 16993, 17024, 17057, 17088, 17121, 17152, 17185, 17216, 17249, 17280, 17313, 17344, 17377, 17408, 17441, 17472, 17505, 17536, 17569, 17600, 17633, 17664, 17697, 17728, 17761, 17792, 17825, 17856, 17889, 17920, 17953, 17984, 18017, 18240, 18305, 18336, 18401, 18464, 18497, 18528, 18657, 18688, 18721, 18752, 18785, 18816, 18849, 18880, 18913, 21124, 21153, 22019, 22612, 22723, 23124, 23555, 23732, 23939, 23988, 24003, 24052, 24581, 28160, 28193, 28224, 28257, 28291, 28340, 28352, 28385, 28445, 28483, 28513, 28625, 28640, 28701, 28820, 28864, 28913, 28928, 29053, 29056, 29117, 29120, 29185, 29216, 29789, 29792, 30081, 31200, 31233, 31296, 31393, 31488, 31521, 31552, 31585, 31616, 31649, 31680, 31713, 31744, 31777, 31808, 31841, 31872, 31905, 31936, 31969, 32000, 32033, 32064, 32097, 32128, 32161, 32192, 32225, 32384, 32417, 32466, 32480, 32513, 32544, 32609, 32672, 34305, 35840, 35873, 35904, 35937, 35968, 36001, 36032, 36065, 36096, 36129, 36160, 36193, 36224, 36257, 36288, 36321, 36352, 36385, 36416, 36449, 36480, 36513, 36544, 36577, 36608, 36641, 36672, 36705, 36736, 36769, 36800, 36833, 36864, 36897, 36949, 36965, 37127, 37184, 37217, 37248, 37281, 37312, 37345, 37376, 37409, 37440, 37473, 37504, 37537, 37568, 37601, 37632, 37665, 37696, 37729, 37760, 37793, 37824, 37857, 37888, 37921, 37952, 37985, 38016, 38049, 38080, 38113, 38144, 38177, 38208, 38241, 38272, 38305, 38336, 38369, 38400, 38433, 38464, 38497, 38528, 38561, 38592, 38625, 38656, 38689, 38720, 38753, 38784, 38817, 38848, 38881, 38912, 38977, 39008, 39041, 39072, 39105, 39136, 39169, 39200, 39233, 39264, 39297, 39328, 39361, 39424, 39457, 39488, 39521, 39552, 39585, 39616, 39649, 39680, 39713, 39744, 39777, 39808, 39841, 39872, 39905, 39936, 39969, 40000, 40033, 40064, 40097, 40128, 40161, 40192, 40225, 40256, 40289, 40320, 40353, 40384, 40417, 40448, 40481, 40512, 40545, 40576, 40609, 40640, 40673, 40704, 40737, 40768, 40801, 40832, 40865, 40896, 40929, 40960, 40993, 41024, 41057, 41088, 41121, 41152, 41185, 41216, 41249, 41280, 41313, 41344, 41377, 41408, 41441, 41472, 41505, 41536, 41569, 41600, 41633, 41664, 41697, 41728, 41761, 41792, 41825, 41856, 41889, 41920, 41953, 41984, 42017, 42048, 42081, 42112, 42145, 42176, 42209, 42240, 42273, 42304, 42337, 42368, 42401, 42432, 42465, 42525, 42528, 43773, 43811, 43857, 44033, 45361, 45388, 45437, 45493, 45555, 45597, 45605, 47052, 47077, 47121, 47141, 47217, 47237, 47313, 47333, 47389, 47620, 48509, 48612, 48753, 48829, 49178, 49362, 49457, 49523, 49553, 49621, 49669, 50033, 50074, 50109, 50129, 50180, 51203, 51236, 51557, 52232, 52561, 52676, 52741, 52772, 55953, 55972, 56005, 56250, 56277, 56293, 56483, 56549, 56629, 56645, 56772, 56840, 57156, 57269, 57316, 57361, 57821, 57850, 57860, 57893, 57924, 58885, 59773, 59812, 62661, 63012, 63069, 63496, 63812, 64869, 65155, 65237, 65265, 65347, 65405, 65445, 65491, 65540, 66245, 66371, 66405, 66691, 66725, 66819, 66853, 67037, 67089, 67581, 67588, 68389, 68509, 68561, 68605, 68612, 68989, 70660, 71357, 71364, 71645, 72293, 72794, 72805, 73830, 73860, 75589, 75622, 75653, 75684, 75718, 75813, 76070, 76197, 76230, 76292, 76325, 76548, 76869, 76945, 77000, 77329, 77347, 77380, 77861, 77894, 77981, 77988, 78269, 78308, 78397, 78436, 79165, 79172, 79421, 79428, 79485, 79556, 79709, 79749, 79780, 79814, 79909, 80061, 80102, 80189, 80230, 80293, 80324, 80381, 80614, 80669, 80772, 80861, 80868, 80965, 81053, 81096, 81412, 81491, 81546, 81749, 81779, 81796, 81841, 81861, 81917, 81957, 82022, 82077, 82084, 82301, 82404, 82493, 82532, 83261, 83268, 83517, 83524, 83613, 83620, 83709, 83716, 83805, 83845, 83901, 83910, 84005, 84093, 84197, 84285, 84325, 84445, 84517, 84573, 84772, 84925, 84932, 84989, 85192, 85509, 85572, 85669, 85713, 85757, 86053, 86118, 86173, 86180, 86493, 86500, 86621, 86628, 87357, 87364, 87613, 87620, 87709, 87716, 87901, 87941, 87972, 88006, 88101, 88285, 88293, 88358, 88413, 88422, 88485, 88541, 88580, 88637, 89092, 89157, 89245, 89288, 89617, 89651, 89693, 89892, 89925, 90141, 90149, 90182, 90269, 90276, 90557, 90596, 90685, 90724, 91453, 91460, 91709, 91716, 91805, 91812, 91997, 92037, 92068, 92102, 92133, 92166, 92197, 92349, 92390, 92477, 92518, 92581, 92637, 92869, 92902, 92957, 93060, 93149, 93156, 93253, 93341, 93384, 93717, 93732, 93770, 93981, 94277, 94308, 94365, 94372, 94589, 94660, 94781, 94788, 94941, 95012, 95101, 95108, 95165, 95172, 95261, 95332, 95421, 95492, 95613, 95684, 96093, 96198, 96261, 96294, 96381, 96454, 96573, 96582, 96677, 96733, 96772, 96829, 96998, 97053, 97480, 97802, 97909, 98099, 98133, 98173, 98309, 98342, 98437, 98468, 98749, 98756, 98877, 98884, 99645, 99652, 100189, 100260, 100293, 100390, 100541, 100549, 100669, 100677, 100829, 101029, 101117, 101124, 101245, 101380, 101445, 101533, 101576, 101917, 102154, 102389, 102404, 102437, 102470, 102545, 102564, 102845, 102852, 102973, 102980, 103741, 103748, 104093, 104100, 104285, 104325, 104356, 104390, 104421, 104454, 104637, 104645, 104678, 104765, 104774, 104837, 104925, 105126, 105213, 105412, 105469, 105476, 105541, 105629, 105672, 106013, 106020, 106109, 106501, 106566, 106653, 106660, 106941, 106948, 107069, 107076, 108389, 108452, 108486, 108581, 108733, 108742, 108861, 108870, 108965, 108996, 109045, 109085, 109188, 109286, 109322, 109540, 109637, 109725, 109768, 110090, 110389, 110404, 110621, 110662, 110749, 110756, 111357, 111428, 112221, 112228, 112541, 112548, 112605, 112644, 112893, 112965, 113021, 113126, 113221, 113341, 113349, 113405, 113414, 113693, 113864, 114205, 114246, 114321, 114365, 114724, 116261, 116292, 116357, 116605, 116723, 116740, 116931, 116965, 117233, 117256, 117585, 117661, 118820, 118909, 118916, 118973, 119012, 119101, 119108, 119165, 119204, 119261, 119428, 119581, 119588, 119837, 119844, 119965, 119972, 120029, 120036, 120093, 120132, 120221, 120228, 120357, 120388, 120453, 120669, 120677, 120740, 120797, 120836, 121021, 121027, 121085, 121093, 121309, 121352, 121693, 121732, 121885, 122884, 122933, 123025, 123509, 123537, 123573, 123653, 123733, 123912, 124234, 124565, 124581, 124629, 124645, 124693, 124709, 124749, 124782, 124813, 124846, 124870, 124932, 125213, 125220, 126397, 126501, 126950, 126981, 127153, 127173, 127236, 127397, 127773, 127781, 128957, 128981, 129221, 129269, 129469, 129493, 129553, 129717, 129841, 129917, 131076, 132454, 132517, 132646, 132677, 132870, 132901, 132966, 133029, 133092, 133128, 133457, 133636, 133830, 133893, 133956, 134085, 134180, 134214, 134308, 134374, 134596, 134693, 134820, 135237, 135270, 135333, 135398, 135589, 135620, 135654, 135688, 136006, 136101, 136149, 136192, 137437, 137440, 137501, 137632, 137693, 137729, 139121, 139139, 139169, 139268, 149821, 149828, 149981, 150020, 150269, 150276, 150333, 150340, 150493, 150532, 151869, 151876, 152029, 152068, 153149, 153156, 153309, 153348, 153597, 153604, 153661, 153668, 153821, 153860, 154365, 154372, 156221, 156228, 156381, 156420, 158589, 158629, 158737, 159018, 159677, 159748, 160277, 160605, 160768, 163549, 163585, 163805, 163852, 163876, 183729, 183780, 184342, 184356, 185197, 185230, 185277, 185348, 187761, 187849, 187940, 188221, 188420, 188861, 188868, 188997, 189117, 189444, 190021, 190129, 190205, 190468, 191045, 191133, 191492, 191933, 191940, 192061, 192069, 192157, 192516, 194181, 194246, 194277, 194502, 194757, 194790, 194853, 195217, 195299, 195345, 195443, 195460, 195493, 195549, 195592, 195933, 196106, 196445, 196625, 196812, 196849, 196965, 197082, 197117, 197128, 197469, 197636, 198755, 198788, 200509, 200708, 200869, 200932, 202021, 202052, 202109, 202244, 204509, 204804, 205821, 205829, 205926, 206053, 206118, 206237, 206342, 206405, 206438, 206629, 206749, 206869, 206909, 206993, 207048, 207364, 208349, 208388, 208573, 208900, 210333, 210436, 211293, 211464, 211786, 211837, 211925, 212996, 213733, 213798, 213861, 213917, 213969, 214020, 215718, 215749, 215782, 215813, 216061, 216069, 216102, 216133, 216166, 216229, 216486, 216677, 217021, 217061, 217096, 217437, 217608, 217949, 218129, 218339, 218385, 218589, 218629, 219079, 219133, 221189, 221318, 221348, 222853, 222886, 222917, 223078, 223109, 223142, 223301, 223334, 223396, 223645, 223752, 224081, 224309, 224613, 224917, 225213, 225285, 225350, 225380, 226342, 226373, 226502, 226565, 226630, 226661, 226756, 226824, 227140, 228549, 228582, 228613, 228678, 228773, 228806, 228837, 228934, 229021, 229265, 229380, 230534, 230789, 231046, 231109, 231197, 231281, 231432, 231773, 231844, 231944, 232260, 233219, 233425, 233473, 233789, 233984, 235389, 235424, 235537, 235805, 236037, 236145, 236165, 236582, 236613, 236836, 236965, 236996, 237126, 237189, 237220, 237286, 237317, 237405, 237569, 238979, 240993, 241411, 241441, 242531, 243717, 245597, 245605, 245760, 245793, 245824, 245857, 245888, 245921, 245952, 245985, 246016, 246049, 246080, 246113, 246144, 246177, 246208, 246241, 246272, 246305, 246336, 246369, 246400, 246433, 246464, 246497, 246528, 246561, 246592, 246625, 246656, 246689, 246720, 246753, 246784, 246817, 246848, 246881, 246912, 246945, 246976, 247009, 247040, 247073, 247104, 247137, 247168, 247201, 247232, 247265, 247296, 247329, 247360, 247393, 247424, 247457, 247488, 247521, 247552, 247585, 247616, 247649, 247680, 247713, 247744, 247777, 247808, 247841, 247872, 247905, 247936, 247969, 248000, 248033, 248064, 248097, 248128, 248161, 248192, 248225, 248256, 248289, 248320, 248353, 248384, 248417, 248448, 248481, 248512, 248545, 248576, 248609, 248640, 248673, 248704, 248737, 248768, 248801, 248832, 248865, 248896, 248929, 248960, 248993, 249024, 249057, 249088, 249121, 249152, 249185, 249216, 249249, 249280, 249313, 249344, 249377, 249408, 249441, 249472, 249505, 249536, 249569, 249600, 249633, 249664, 249697, 249728, 249761, 249792, 249825, 249856, 249889, 249920, 249953, 249984, 250017, 250048, 250081, 250112, 250145, 250176, 250209, 250240, 250273, 250304, 250337, 250368, 250401, 250432, 250465, 250496, 250529, 250816, 250849, 250880, 250913, 250944, 250977, 251008, 251041, 251072, 251105, 251136, 251169, 251200, 251233, 251264, 251297, 251328, 251361, 251392, 251425, 251456, 251489, 251520, 251553, 251584, 251617, 251648, 251681, 251712, 251745, 251776, 251809, 251840, 251873, 251904, 251937, 251968, 252001, 252032, 252065, 252096, 252129, 252160, 252193, 252224, 252257, 252288, 252321, 252352, 252385, 252416, 252449, 252480, 252513, 252544, 252577, 252608, 252641, 252672, 252705, 252736, 252769, 252800, 252833, 252864, 252897, 252928, 252961, 252992, 253025, 253056, 253089, 253120, 253153, 253184, 253217, 253248, 253281, 253312, 253345, 253376, 253409, 253440, 253473, 253504, 253537, 253568, 253601, 253632, 253665, 253696, 253729, 253760, 253793, 253824, 253857, 253888, 253921, 254208, 254465, 254685, 254720, 254941, 254977, 255232, 255489, 255744, 256001, 256221, 256256, 256477, 256513, 256797, 256800, 256861, 256864, 256925, 256928, 256989, 256992, 257025, 257280, 257537, 258013, 258049, 258306, 258561, 258818, 259073, 259330, 259585, 259773, 259777, 259840, 259970, 260020, 260033, 260084, 260161, 260285, 260289, 260352, 260482, 260532, 260609, 260765, 260801, 260864, 261021, 261044, 261121, 261376, 261556, 261661, 261697, 261821, 261825, 261888, 262018, 262068, 262141, 262166, 262522, 262668, 262865, 262927, 262960, 262989, 263023, 263088, 263117, 263151, 263185, 263447, 263480, 263514, 263670, 263697, 263983, 264016, 264049, 264171, 264241, 264338, 264365, 264398, 264433, 264786, 264817, 264843, 264881, 265206, 265242, 265405, 265434, 265738, 265763, 265821, 265866, 266066, 266157, 266190, 266211, 266250, 266578, 266669, 266702, 266749, 266755, 267197, 267283, 268317, 268805, 269223, 269349, 269383, 269477, 269885, 270357, 270400, 270453, 270560, 270613, 270657, 270688, 270785, 270848, 270945, 270997, 271008, 271061, 271122, 271136, 271317, 271488, 271541, 271552, 271605, 271616, 271669, 271680, 271829, 271841, 271872, 272001, 272036, 272161, 272213, 272257, 272320, 272402, 272544, 272577, 272725, 272754, 272789, 272833, 272885, 272906, 273417, 274528, 274561, 274601, 274730, 274773, 274845, 274962, 275125, 275282, 275349, 275474, 275509, 275570, 275605, 275666, 275701, 275922, 275957, 276946, 277013, 277074, 277109, 277138, 277173, 278162, 286741, 286989, 287022, 287053, 287086, 287125, 287762, 287829, 288045, 288078, 288117, 290706, 290741, 291698, 292501, 293778, 293973, 296189, 296981, 297341, 297994, 299925, 302410, 303125, 308978, 309013, 309298, 309333, 311058, 311317, 314866, 314901, 322829, 322862, 322893, 322926, 322957, 322990, 323021, 323054, 323085, 323118, 323149, 323182, 323213, 323246, 323274, 324245, 325650, 325805, 325838, 325874, 326861, 326894, 326925, 326958, 326989, 327022, 327053, 327086, 327117, 327150, 327186, 327701, 335890, 340077, 340110, 340141, 340174, 340205, 340238, 340269, 340302, 340333, 340366, 340397, 340430, 340461, 340494, 340525, 340558, 340589, 340622, 340653, 340686, 340717, 340750, 340786, 342797, 342830, 342861, 342894, 342930, 343949, 343982, 344018, 352277, 353810, 354485, 354546, 354741, 355997, 356053, 357085, 357141, 358717, 358741, 360445, 360448, 361981, 361985, 363517, 363520, 363553, 363584, 363681, 363744, 363777, 363808, 363841, 363872, 363905, 363936, 364065, 364096, 364129, 364192, 364225, 364419, 364480, 364577, 364608, 364641, 364672, 364705, 364736, 364769, 364800, 364833, 364864, 364897, 364928, 364961, 364992, 365025, 365056, 365089, 365120, 365153, 365184, 365217, 365248, 365281, 365312, 365345, 365376, 365409, 365440, 365473, 365504, 365537, 365568, 365601, 365632, 365665, 365696, 365729, 365760, 365793, 365824, 365857, 365888, 365921, 365952, 365985, 366016, 366049, 366080, 366113, 366144, 366177, 366208, 366241, 366272, 366305, 366336, 366369, 366400, 366433, 366464, 366497, 366528, 366561, 366592, 366625, 366656, 366689, 366720, 366753, 366784, 366817, 366848, 366881, 366912, 366945, 366976, 367009, 367040, 367073, 367104, 367137, 367168, 367201, 367232, 367265, 367296, 367329, 367360, 367393, 367424, 367457, 367488, 367521, 367552, 367585, 367616, 367649, 367680, 367713, 367797, 367968, 368001, 368032, 368065, 368101, 368192, 368225, 368285, 368433, 368554, 368593, 368641, 369885, 369889, 369949, 370081, 370141, 370180, 371997, 372195, 372241, 372285, 372709, 372740, 373501, 373764, 374013, 374020, 374269, 374276, 374525, 374532, 374781, 374788, 375037, 375044, 375293, 375300, 375549, 375556, 375805, 375813, 376849, 376911, 376944, 376975, 377008, 377041, 377135, 377168, 377201, 377231, 377264, 377297, 377580, 377617, 377676, 377713, 377743, 377776, 377809, 377871, 377904, 377933, 377966, 377997, 378030, 378061, 378094, 378125, 378158, 378193, 378339, 378385, 378700, 378769, 378892, 378929, 378957, 378993, 379389, 380949, 381789, 381813, 384669, 385045, 391901, 392725, 393117, 393238, 393265, 393365, 393379, 393412, 393449, 393485, 393518, 393549, 393582, 393613, 393646, 393677, 393710, 393741, 393774, 393813, 393869, 393902, 393933, 393966, 393997, 394030, 394061, 394094, 394124, 394157, 394190, 394261, 394281, 394565, 394694, 394764, 394787, 394965, 395017, 395107, 395140, 395185, 395221, 395293, 395300, 398077, 398117, 398196, 398243, 398308, 398348, 398372, 401265, 401283, 401380, 401437, 401572, 402973, 402980, 406013, 406037, 406090, 406229, 406532, 407421, 407573, 408733, 409092, 409621, 410621, 410634, 410965, 411914, 412181, 412202, 412693, 413706, 414037, 415274, 415765, 417789, 417813, 425988, 636637, 636949, 638980, 1310237, 1310724, 1311395, 1311428, 1348029, 1348117, 1349885, 1350148, 1351427, 1351633, 1351684, 1360259, 1360305, 1360388, 1360904, 1361220, 1361309, 1361920, 1361953, 1361984, 1362017, 1362048, 1362081, 1362112, 1362145, 1362176, 1362209, 1362240, 1362273, 1362304, 1362337, 1362368, 1362401, 1362432, 1362465, 1362496, 1362529, 1362560, 1362593, 1362624, 1362657, 1362688, 1362721, 1362752, 1362785, 1362816, 1362849, 1362880, 1362913, 1362944, 1362977, 1363008, 1363041, 1363072, 1363105, 1363136, 1363169, 1363200, 1363233, 1363264, 1363297, 1363328, 1363361, 1363396, 1363429, 1363463, 1363569, 1363589, 1363921, 1363939, 1363968, 1364001, 1364032, 1364065, 1364096, 1364129, 1364160, 1364193, 1364224, 1364257, 1364288, 1364321, 1364352, 1364385, 1364416, 1364449, 1364480, 1364513, 1364544, 1364577, 1364608, 1364641, 1364672, 1364705, 1364736, 1364769, 1364800, 1364833, 1364867, 1364933, 1364996, 1367241, 1367557, 1367633, 1367837, 1368084, 1368803, 1369108, 1369152, 1369185, 1369216, 1369249, 1369280, 1369313, 1369344, 1369377, 1369408, 1369441, 1369472, 1369505, 1369536, 1369569, 1369664, 1369697, 1369728, 1369761, 1369792, 1369825, 1369856, 1369889, 1369920, 1369953, 1369984, 1370017, 1370048, 1370081, 1370112, 1370145, 1370176, 1370209, 1370240, 1370273, 1370304, 1370337, 1370368, 1370401, 1370432, 1370465, 1370496, 1370529, 1370560, 1370593, 1370624, 1370657, 1370688, 1370721, 1370752, 1370785, 1370816, 1370849, 1370880, 1370913, 1370944, 1370977, 1371008, 1371041, 1371072, 1371105, 1371136, 1371169, 1371200, 1371233, 1371264, 1371297, 1371328, 1371361, 1371392, 1371425, 1371456, 1371489, 1371520, 1371553, 1371584, 1371617, 1371651, 1371681, 1371936, 1371969, 1372000, 1372033, 1372064, 1372129, 1372160, 1372193, 1372224, 1372257, 1372288, 1372321, 1372352, 1372385, 1372419, 1372468, 1372512, 1372545, 1372576, 1372609, 1372644, 1372672, 1372705, 1372736, 1372769, 1372864, 1372897, 1372928, 1372961, 1372992, 1373025, 1373056, 1373089, 1373120, 1373153, 1373184, 1373217, 1373248, 1373281, 1373312, 1373345, 1373376, 1373409, 1373440, 1373473, 1373504, 1373665, 1373696, 1373857, 1373888, 1373921, 1373952, 1373985, 1374045, 1375972, 1376003, 1376065, 1376100, 1376325, 1376356, 1376453, 1376484, 1376613, 1376644, 1377382, 1377445, 1377510, 1377557, 1377693, 1377802, 1378005, 1378067, 1378101, 1378141, 1378308, 1379985, 1380125, 1380358, 1380420, 1382022, 1382533, 1382621, 1382865, 1382920, 1383261, 1383429, 1384004, 1384209, 1384292, 1384337, 1384356, 1384421, 1384456, 1384772, 1385669, 1385937, 1385988, 1386725, 1387078, 1387165, 1387505, 1387524, 1388477, 1388549, 1388646, 1388676, 1390181, 1390214, 1390277, 1390406, 1390469, 1390502, 1390641, 1391069, 1391075, 1391112, 1391453, 1391569, 1391620, 1391781, 1391811, 1391844, 1392136, 1392452, 1392637, 1392644, 1393957, 1394150, 1394213, 1394278, 1394341, 1394429, 1394692, 1394789, 1394820, 1395077, 1395110, 1395165, 1395208, 1395549, 1395601, 1395716, 1396227, 1396260, 1396469, 1396548, 1396582, 1396613, 1396646, 1396676, 1398277, 1398308, 1398341, 1398436, 1398501, 1398564, 1398725, 1398788, 1398821, 1398852, 1398909, 1399652, 1399715, 1399761, 1399812, 1400166, 1400197, 1400262, 1400337, 1400388, 1400419, 1400486, 1400517, 1400573, 1400868, 1401085, 1401124, 1401341, 1401380, 1401597, 1401860, 1402109, 1402116, 1402365, 1402369, 1403764, 1403779, 1403905, 1404125, 1404417, 1406980, 1408102, 1408165, 1408198, 1408261, 1408294, 1408369, 1408390, 1408421, 1408477, 1408520, 1408861, 1409028, 1766557, 1766916, 1767677, 1767780, 1769373, 1769499, 1835036, 2039812, 2051549, 2051588, 2055005, 2056193, 2056445, 2056801, 2056989, 2057124, 2057157, 2057188, 2057522, 2057540, 2057981, 2057988, 2058173, 2058180, 2058237, 2058244, 2058333, 2058340, 2058429, 2058436, 2061908, 2062429, 2062948, 2074574, 2074605, 2074653, 2075140, 2077213, 2077252, 2079005, 2080260, 2080659, 2080693, 2080733, 2080773, 2081297, 2081517, 2081550, 2081585, 2081629, 2081797, 2082321, 2082348, 2082411, 2082477, 2082510, 2082541, 2082574, 2082605, 2082638, 2082669, 2082702, 2082733, 2082766, 2082797, 2082830, 2082861, 2082894, 2082925, 2082958, 2082993, 2083053, 2083086, 2083121, 2083243, 2083345, 2083453, 2083473, 2083596, 2083629, 2083662, 2083693, 2083726, 2083757, 2083790, 2083825, 2083922, 2083948, 2083986, 2084093, 2084113, 2084147, 2084177, 2084253, 2084356, 2084541, 2084548, 2088893, 2088954, 2088989, 2089009, 2089107, 2089137, 2089229, 2089262, 2089297, 2089330, 2089361, 2089388, 2089425, 2089480, 2089809, 2089874, 2089969, 2090016, 2090861, 2090897, 2090926, 2090964, 2090987, 2091028, 2091041, 2091885, 2091922, 2091950, 2091986, 2092013, 2092046, 2092081, 2092109, 2092142, 2092177, 2092228, 2092547, 2092580, 2094019, 2094084, 2095101, 2095172, 2095389, 2095428, 2095645, 2095684, 2095901, 2095940, 2096061, 2096147, 2096210, 2096244, 2096277, 2096307, 2096381, 2096405, 2096434, 2096565, 2096637, 2096954, 2097045, 2097117, 2097156, 2097565, 2097572, 2098429, 2098436, 2099069, 2099076, 2099165, 2099172, 2099677, 2099716, 2100189, 2101252, 2105213, 2105361, 2105469, 2105578, 2107037, 2107125, 2107401, 2109098, 2109237, 2109770, 2109845, 2109949, 2109973, 2110365, 2110485, 2110525, 2112021, 2113445, 2113501, 2117636, 2118589, 2118660, 2120253, 2120709, 2120746, 2121629, 2121732, 2122762, 2122909, 2123172, 2123817, 2123844, 2124105, 2124157, 2124292, 2125509, 2125693, 2125828, 2126813, 2126833, 2126852, 2128029, 2128132, 2128401, 2128425, 2128605, 2129920, 2131201, 2132484, 2135005, 2135048, 2135389, 2135552, 2136733, 2136833, 2138013, 2138116, 2139421, 2139652, 2141341, 2141681, 2141725, 2146308, 2156285, 2156548, 2157277, 2157572, 2157853, 2162692, 2162909, 2162948, 2163005, 2163012, 2164445, 2164452, 2164541, 2164612, 2164669, 2164708, 2165469, 2165489, 2165514, 2165764, 2166517, 2166570, 2166788, 2167805, 2168042, 2168349, 2169860, 2170493, 2170500, 2170589, 2170730, 2170884, 2171594, 2171805, 2171889, 2171908, 2172765, 2172913, 2172957, 2174980, 2176797, 2176906, 2176964, 2177034, 2177565, 2177610, 2179076, 2179109, 2179229, 2179237, 2179325, 2179461, 2179588, 2179741, 2179748, 2179869, 2179876, 2180829, 2180869, 2180989, 2181093, 2181130, 2181437, 2181649, 2181949, 2182148, 2183082, 2183153, 2183172, 2184106, 2184221, 2185220, 2185493, 2185508, 2186405, 2186493, 2186602, 2186769, 2187005, 2187268, 2189021, 2189105, 2189316, 2190045, 2190090, 2190340, 2190973, 2191114, 2191364, 2191965, 2192177, 2192317, 2192682, 2192925, 2195460, 2197821, 2199552, 2201213, 2201601, 2203261, 2203466, 2203652, 2204805, 2204957, 2205192, 2205533, 2214922, 2215933, 2220036, 2220970, 2221284, 2221341, 2221572, 2222277, 2222634, 2222769, 2222941, 2228230, 2228261, 2228294, 2228324, 2230021, 2230513, 2230749, 2230858, 2231496, 2231837, 2232293, 2232390, 2232420, 2233862, 2233957, 2234086, 2234149, 2234225, 2234298, 2234321, 2234461, 2234810, 2234845, 2234884, 2235709, 2235912, 2236253, 2236421, 2236516, 2237669, 2237830, 2237861, 2238141, 2238152, 2238481, 2238596, 2238630, 2238717, 2238980, 2240101, 2240145, 2240196, 2240253, 2240517, 2240582, 2240612, 2242150, 2242245, 2242534, 2242596, 2242737, 2242853, 2242993, 2243037, 2243080, 2243396, 2243441, 2243460, 2243505, 2243613, 2243626, 2244285, 2244612, 2245213, 2245220, 2246022, 2246117, 2246214, 2246277, 2246310, 2246341, 2246417, 2246597, 2246653, 2248708, 2248957, 2248964, 2249021, 2249028, 2249181, 2249188, 2249693, 2249700, 2250033, 2250077, 2250244, 2251749, 2251782, 2251877, 2252157, 2252296, 2252637, 2252805, 2252870, 2252957, 2252964, 2253245, 2253284, 2253373, 2253412, 2254141, 2254148, 2254397, 2254404, 2254493, 2254500, 2254685, 2254693, 2254756, 2254790, 2254853, 2254886, 2255037, 2255078, 2255165, 2255206, 2255325, 2255364, 2255421, 2255590, 2255645, 2255780, 2255942, 2256029, 2256069, 2256317, 2256389, 2256573, 2260996, 2262694, 2262789, 2263046, 2263109, 2263206, 2263237, 2263268, 2263409, 2263560, 2263901, 2263921, 2263965, 2263985, 2264005, 2264061, 2265092, 2266630, 2266725, 2266918, 2266949, 2266982, 2267109, 2267174, 2267205, 2267268, 2267345, 2267364, 2267421, 2267656, 2267997, 2273284, 2274790, 2274885, 2275037, 2275078, 2275205, 2275270, 2275301, 2275377, 2276100, 2276229, 2276317, 2277380, 2278918, 2279013, 2279270, 2279333, 2279366, 2279397, 2279473, 2279556, 2279613, 2279944, 2280285, 2280465, 2280893, 2281476, 2282853, 2282886, 2282917, 2282950, 2283013, 2283206, 2283237, 2283293, 2283528, 2283869, 2285572, 2286461, 2286501, 2286598, 2286661, 2286790, 2286821, 2287005, 2287112, 2287434, 2287505, 2287605, 2287645, 2293764, 2295174, 2295269, 2295558, 2295589, 2295665, 2295709, 2298880, 2299905, 2300936, 2301258, 2301565, 2301924, 2301981, 2310148, 2310181, 2310500, 2311781, 2311974, 2312004, 2312037, 2312177, 2312421, 2312477, 2312708, 2312741, 2312934, 2312997, 2313092, 2314397, 2314436, 2314565, 2314982, 2315013, 2315089, 2315172, 2315217, 2315389, 2316292, 2318141, 2326532, 2326845, 2326852, 2328038, 2328069, 2328317, 2328325, 2328518, 2328549, 2328580, 2328625, 2328797, 2329096, 2329418, 2330045, 2330129, 2330180, 2331165, 2331205, 2331933, 2331942, 2331973, 2332198, 2332229, 2332294, 2332325, 2332413, 2334724, 2334973, 2334980, 2335069, 2335076, 2336293, 2336509, 2336581, 2336637, 2336645, 2336733, 2336741, 2336964, 2336997, 2337053, 2337288, 2337629, 2337796, 2338013, 2338020, 2338109, 2338116, 2339142, 2339325, 2339333, 2339421, 2339430, 2339493, 2339526, 2339557, 2339588, 2339645, 2339848, 2340189, 2350084, 2350693, 2350758, 2350833, 2350909, 2359300, 2388829, 2392073, 2395645, 2395665, 2395837, 2396164, 2402461, 2490372, 2524669, 2654212, 2672893, 2949124, 2967357, 2967556, 2968573, 2968584, 2968925, 2969041, 2969117, 2972164, 2973149, 2973189, 2973361, 2973405, 2973700, 2975237, 2975473, 2975637, 2975747, 2975889, 2975925, 2975965, 2976264, 2976605, 2976618, 2976861, 2976868, 2977565, 2977700, 2978333, 3000320, 3001345, 3002378, 3003121, 3003261, 3006468, 3008701, 3009028, 3009062, 3010557, 3011045, 3011171, 3011613, 3013635, 3013725, 3014660, 3210845, 3211268, 3235453, 3538948, 3548157, 3550724, 3563421, 3637252, 3640701, 3640836, 3641277, 3641348, 3641661, 3641860, 3642205, 3642261, 3642277, 3642353, 3642394, 3642525, 3801109, 3808989, 3809301, 3810557, 3810613, 3812518, 3812581, 3812693, 3812774, 3812986, 3813221, 3813493, 3813541, 3813781, 3814725, 3814869, 3816765, 3817493, 3819589, 3819701, 3819741, 3824650, 3825309, 3825685, 3828477, 3828746, 3829565, 3833856, 3834689, 3835520, 3836353, 3836605, 3836609, 3837184, 3838017, 3838848, 3838909, 3838912, 3839005, 3839040, 3839101, 3839136, 3839229, 3839264, 3839421, 3839424, 3839681, 3839837, 3839841, 3839901, 3839905, 3840157, 3840161, 3840512, 3841345, 3842176, 3842269, 3842272, 3842429, 3842464, 3842749, 3842752, 3843005, 3843009, 3843840, 3843933, 3843936, 3844093, 3844096, 3844285, 3844288, 3844349, 3844416, 3844669, 3844673, 3845504, 3846337, 3847168, 3848001, 3848832, 3849665, 3850496, 3851329, 3852160, 3852993, 3853824, 3854657, 3855581, 3855616, 3856434, 3856449, 3857266, 3857281, 3857472, 3858290, 3858305, 3859122, 3859137, 3859328, 3860146, 3860161, 3860978, 3860993, 3861184, 3862002, 3862017, 3862834, 3862849, 3863040, 3863858, 3863873, 3864690, 3864705, 3864896, 3864929, 3864989, 3865032, 3866645, 3883013, 3884789, 3884901, 3886517, 3886757, 3886805, 3887237, 3887285, 3887345, 3887517, 3887973, 3888157, 3888165, 3888669, 3932165, 3932413, 3932421, 3932989, 3933029, 3933277, 3933285, 3933373, 3933381, 3933565, 3997700, 4004029, 4004074, 4004357, 4004605, 4005888, 4006977, 4008069, 4008317, 4008456, 4008797, 4008913, 4008989, 4034090, 4035989, 4036010, 4036115, 4036138, 4036285, 4046852, 4047005, 4047012, 4047901, 4047908, 4047997, 4048004, 4048061, 4048100, 4048157, 4048164, 4048509, 4048516, 4048669, 4048676, 4048733, 4048740, 4048797, 4048964, 4049021, 4049124, 4049181, 4049188, 4049245, 4049252, 4049309, 4049316, 4049437, 4049444, 4049533, 4049540, 4049597, 4049636, 4049693, 4049700, 4049757, 4049764, 4049821, 4049828, 4049885, 4049892, 4049949, 4049956, 4050045, 4050052, 4050109, 4050148, 4050301, 4050308, 4050557, 4050564, 4050717, 4050724, 4050877, 4050884, 4050941, 4050948, 4051293, 4051300, 4051869, 4052004, 4052125, 4052132, 4052317, 4052324, 4052893, 4054546, 4054621, 4063253, 4064669, 4064789, 4067997, 4068373, 4068861, 4068917, 4069405, 4069429, 4069917, 4069941, 4071133, 4071434, 4071869, 4071957, 4074909, 4075029, 4076989, 4078805, 4079741, 4080149, 4081565, 4081685, 4081981, 4082197, 4082269, 4082709, 4082909, 4087829, 4095860, 4096021, 4119229, 4119573, 4119997, 4120085, 4120413, 4120597, 4124317, 4124693, 4127549, 4128789, 4129181, 4129301, 4131101, 4131349, 4131677, 4131861, 4133149, 4133397, 4134365, 4136981, 4137373, 4137493, 4139005, 4139029, 4140605, 4140661, 4140797, 4140885, 4140925, 4140949, 4142205, 4142613, 4142941, 4143125, 4143229, 4143637, 4145181, 4148245, 4148701, 4194308, 5561085, 5562372, 5695165, 5695492, 5702621, 5702660, 5887069, 5887492, 6126653, 6225924, 6243293, 29360186, 29360221, 29361178, 29364253, 29368325, 29376029, 31457308, 33554397, 33554460, 35651549, //--Autogenerated -- end of section automatically generated }; const int maxUnicode = 0x10ffff; const int maskCategory = 0x1F; } // Each element in catRanges is the start of a range of Unicode characters in // one general category. // The value is comprised of a 21-bit character value shifted 5 bits and a 5 bit // category matching the CharacterCategory enumeration. // Initial version has 3249 entries and adds about 13K to the executable. // The array is in ascending order so can be searched using binary search. // Therefore the average call takes log2(3249) = 12 comparisons. // For speed, it may be useful to make a linear table for the common values, // possibly for 0..0xff for most Western European text or 0..0xfff for most // alphabetic languages. CharacterCategory CategoriseCharacter(int character) { if (character < 0 || character > maxUnicode) return ccCn; const int baseValue = character * (maskCategory+1) + maskCategory; const int *placeAfter = std::lower_bound(catRanges, std::end(catRanges), baseValue); return static_cast(*(placeAfter-1) & maskCategory); } // Implementation of character sets recommended for identifiers in Unicode Standard Annex #31. // http://unicode.org/reports/tr31/ namespace { enum class OtherID { oidNone, oidStart, oidContinue }; // Some characters are treated as valid for identifiers even // though most characters from their category are not. // Values copied from http://www.unicode.org/Public/9.0.0/ucd/PropList.txt OtherID OtherIDOfCharacter(int character) { if ( (character == 0x1885) || // MONGOLIAN LETTER ALI GALI BALUDA (character == 0x1886) || // MONGOLIAN LETTER ALI GALI THREE BALUDA (character == 0x2118) || // SCRIPT CAPITAL P (character == 0x212E) || // ESTIMATED SYMBOL (character == 0x309B) || // KATAKANA-HIRAGANA VOICED SOUND MARK (character == 0x309C)) { // KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK return OtherID::oidStart; } else if ( (character == 0x00B7) || // MIDDLE DOT (character == 0x0387) || // GREEK ANO TELEIA ((character >= 0x1369) && (character <= 0x1371)) || // ETHIOPIC DIGIT ONE..ETHIOPIC DIGIT NINE (character == 0x19DA)) { // NEW TAI LUE THAM DIGIT ONE return OtherID::oidContinue; } else { return OtherID::oidNone; } } // Determine if a character is in Ll|Lu|Lt|Lm|Lo|Nl|Mn|Mc|Nd|Pc and has // Pattern_Syntax|Pattern_White_Space. // As of Unicode 9, only VERTICAL TILDE which is in Lm and has Pattern_Syntax matches. // Should really generate from PropList.txt a list of Pattern_Syntax and Pattern_White_Space. bool IsIdPattern(int character) { return character == 0x2E2F; } bool OmitXidStart(int character) { switch (character) { case 0x037A: // GREEK YPOGEGRAMMENI case 0x0E33: // THAI CHARACTER SARA AM case 0x0EB3: // LAO VOWEL SIGN AM case 0x309B: // KATAKANA-HIRAGANA VOICED SOUND MARK case 0x309C: // KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK case 0xFC5E: // ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM case 0xFC5F: // ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM case 0xFC60: // ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM case 0xFC61: // ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM case 0xFC62: // ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM case 0xFC63: // ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM case 0xFDFA: // ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM case 0xFDFB: // ARABIC LIGATURE JALLAJALALOUHOU case 0xFE70: // ARABIC FATHATAN ISOLATED FORM case 0xFE72: // ARABIC DAMMATAN ISOLATED FORM case 0xFE74: // ARABIC KASRATAN ISOLATED FORM case 0xFE76: // ARABIC FATHA ISOLATED FORM case 0xFE78: // ARABIC DAMMA ISOLATED FORM case 0xFE7A: // ARABIC KASRA ISOLATED FORM case 0xFE7C: // ARABIC SHADDA ISOLATED FORM case 0xFE7E: // ARABIC SUKUN ISOLATED FORM case 0xFF9E: // HALFWIDTH KATAKANA VOICED SOUND MARK case 0xFF9F: // HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK return true; default: return false; } } bool OmitXidContinue(int character) { switch (character) { case 0x037A: // GREEK YPOGEGRAMMENI case 0x309B: // KATAKANA-HIRAGANA VOICED SOUND MARK case 0x309C: // KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK case 0xFC5E: // ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM case 0xFC5F: // ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM case 0xFC60: // ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM case 0xFC61: // ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM case 0xFC62: // ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM case 0xFC63: // ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM case 0xFDFA: // ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM case 0xFDFB: // ARABIC LIGATURE JALLAJALALOUHOU case 0xFE70: // ARABIC FATHATAN ISOLATED FORM case 0xFE72: // ARABIC DAMMATAN ISOLATED FORM case 0xFE74: // ARABIC KASRATAN ISOLATED FORM case 0xFE76: // ARABIC FATHA ISOLATED FORM case 0xFE78: // ARABIC DAMMA ISOLATED FORM case 0xFE7A: // ARABIC KASRA ISOLATED FORM case 0xFE7C: // ARABIC SHADDA ISOLATED FORM case 0xFE7E: // ARABIC SUKUN ISOLATED FORM return true; default: return false; } } } // UAX #31 defines ID_Start as // [[:L:][:Nl:][:Other_ID_Start:]--[:Pattern_Syntax:]--[:Pattern_White_Space:]] bool IsIdStart(int character) { if (IsIdPattern(character)) { return false; } const OtherID oid = OtherIDOfCharacter(character); if (oid == OtherID::oidStart) { return true; } const CharacterCategory c = CategoriseCharacter(character); return (c == ccLl || c == ccLu || c == ccLt || c == ccLm || c == ccLo || c == ccNl); } // UAX #31 defines ID_Continue as // [[:ID_Start:][:Mn:][:Mc:][:Nd:][:Pc:][:Other_ID_Continue:]--[:Pattern_Syntax:]--[:Pattern_White_Space:]] bool IsIdContinue(int character) { if (IsIdPattern(character)) { return false; } const OtherID oid = OtherIDOfCharacter(character); if (oid != OtherID::oidNone) { return true; } const CharacterCategory c = CategoriseCharacter(character); return (c == ccLl || c == ccLu || c == ccLt || c == ccLm || c == ccLo || c == ccNl || c == ccMn || c == ccMc || c == ccNd || c == ccPc); } // XID_Start is ID_Start modified for Normalization Form KC in UAX #31 bool IsXidStart(int character) { if (OmitXidStart(character)) { return false; } else { return IsIdStart(character); } } // XID_Continue is ID_Continue modified for Normalization Form KC in UAX #31 bool IsXidContinue(int character) { if (OmitXidContinue(character)) { return false; } else { return IsIdContinue(character); } } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/CharacterCategory.h000066400000000000000000000015221463772530400300120ustar00rootroot00000000000000// Scintilla source code edit control /** @file CharacterCategory.h ** Returns the Unicode general category of a character. **/ // Copyright 2013 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CHARACTERCATEGORY_H #define CHARACTERCATEGORY_H namespace Scintilla { enum CharacterCategory { ccLu, ccLl, ccLt, ccLm, ccLo, ccMn, ccMc, ccMe, ccNd, ccNl, ccNo, ccPc, ccPd, ccPs, ccPe, ccPi, ccPf, ccPo, ccSm, ccSc, ccSk, ccSo, ccZs, ccZl, ccZp, ccCc, ccCf, ccCs, ccCo, ccCn }; CharacterCategory CategoriseCharacter(int character); // Common definitions of allowable characters in identifiers from UAX #31. bool IsIdStart(int character); bool IsIdContinue(int character); bool IsXidStart(int character); bool IsXidContinue(int character); } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/CharacterSet.cpp000066400000000000000000000020651463772530400273260ustar00rootroot00000000000000// Scintilla source code edit control /** @file CharacterSet.cxx ** Simple case functions for ASCII. ** Lexer infrastructure. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include "CharacterSet.h" using namespace Scintilla; namespace Scintilla { int CompareCaseInsensitive(const char *a, const char *b) { while (*a && *b) { if (*a != *b) { const char upperA = MakeUpperCase(*a); const char upperB = MakeUpperCase(*b); if (upperA != upperB) return upperA - upperB; } a++; b++; } // Either *a or *b is nul return *a - *b; } int CompareNCaseInsensitive(const char *a, const char *b, size_t len) { while (*a && *b && len) { if (*a != *b) { const char upperA = MakeUpperCase(*a); const char upperB = MakeUpperCase(*b); if (upperA != upperB) return upperA - upperB; } a++; b++; len--; } if (len == 0) return 0; else // Either *a or *b is nul return *a - *b; } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/CharacterSet.h000066400000000000000000000106441463772530400267750ustar00rootroot00000000000000// Scintilla source code edit control /** @file CharacterSet.h ** Encapsulates a set of characters. Used to test if a character is within a set. **/ // Copyright 2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CHARACTERSET_H #define CHARACTERSET_H namespace Scintilla { class CharacterSet { int size; bool valueAfter; bool *bset; public: enum setBase { setNone=0, setLower=1, setUpper=2, setDigits=4, setAlpha=setLower|setUpper, setAlphaNum=setAlpha|setDigits }; CharacterSet(setBase base=setNone, const char *initialSet="", int size_=0x80, bool valueAfter_=false) { size = size_; valueAfter = valueAfter_; bset = new bool[size]; for (int i=0; i < size; i++) { bset[i] = false; } AddString(initialSet); if (base & setLower) AddString("abcdefghijklmnopqrstuvwxyz"); if (base & setUpper) AddString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); if (base & setDigits) AddString("0123456789"); } CharacterSet(const CharacterSet &other) { size = other.size; valueAfter = other.valueAfter; bset = new bool[size]; for (int i=0; i < size; i++) { bset[i] = other.bset[i]; } } CharacterSet &operator=(CharacterSet &&other) { if (this != &other) { delete []bset; size = other.size; valueAfter = other.valueAfter; bset = other.bset; other.size = 0; other.bset = nullptr; } return *this; } ~CharacterSet() { delete []bset; bset = nullptr; size = 0; } CharacterSet &operator=(const CharacterSet &other) { if (this != &other) { bool *bsetNew = new bool[other.size]; for (int i=0; i < other.size; i++) { bsetNew[i] = other.bset[i]; } delete []bset; size = other.size; valueAfter = other.valueAfter; bset = bsetNew; } return *this; } void Add(int val) { assert(val >= 0); assert(val < size); bset[val] = true; } void AddString(const char *setToAdd) { for (const char *cp=setToAdd; *cp; cp++) { int val = static_cast(*cp); assert(val >= 0); assert(val < size); bset[val] = true; } } bool Contains(int val) const { // val being -ve is valid (or there is a sign extension bug elsewhere. //assert(val >= 0); if (val < 0) return false; return (val < size) ? bset[val] : valueAfter; } }; // Functions for classifying characters inline bool IsASpace(int ch) { return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); } inline bool IsASpaceOrTab(int ch) { return (ch == ' ') || (ch == '\t'); } inline bool IsADigit(int ch) { return (ch >= '0') && (ch <= '9'); } inline bool IsADigit(int ch, int base) { if (base <= 10) { return (ch >= '0') && (ch < '0' + base); } else { return ((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch < 'A' + base - 10)) || ((ch >= 'a') && (ch < 'a' + base - 10)); } } inline bool IsASCII(int ch) { return (ch >= 0) && (ch < 0x80); } inline bool IsLowerCase(int ch) { return (ch >= 'a') && (ch <= 'z'); } inline bool IsUpperCase(int ch) { return (ch >= 'A') && (ch <= 'Z'); } inline bool IsAlphaNumeric(int ch) { return ((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')); } /** * Check if a character is a space. * This is ASCII specific but is safe with chars >= 0x80. */ inline bool isspacechar(int ch) { return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); } inline bool iswordchar(int ch) { return IsAlphaNumeric(ch) || ch == '.' || ch == '_'; } inline bool iswordstart(int ch) { return IsAlphaNumeric(ch) || ch == '_'; } inline bool isoperator(int ch) { if (IsAlphaNumeric(ch)) return false; if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || ch == '(' || ch == ')' || ch == '-' || ch == '+' || ch == '=' || ch == '|' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == ':' || ch == ';' || ch == '<' || ch == '>' || ch == ',' || ch == '/' || ch == '?' || ch == '!' || ch == '.' || ch == '~') return true; return false; } // Simple case functions for ASCII supersets. template inline T MakeUpperCase(T ch) { if (ch < 'a' || ch > 'z') return ch; else return ch - 'a' + 'A'; } template inline T MakeLowerCase(T ch) { if (ch < 'A' || ch > 'Z') return ch; else return ch - 'A' + 'a'; } int CompareCaseInsensitive(const char *a, const char *b); int CompareNCaseInsensitive(const char *a, const char *b, size_t len); } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/DefaultLexer.cpp000066400000000000000000000054041463772530400273420ustar00rootroot00000000000000// Scintilla source code edit control /** @file DefaultLexer.cxx ** A lexer base class that provides reasonable default behaviour. **/ // Copyright 2017 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "LexerModule.h" #include "DefaultLexer.h" using namespace Scintilla; static const char styleSubable[] = { 0 }; DefaultLexer::DefaultLexer(const LexicalClass *lexClasses_, size_t nClasses_) : lexClasses(lexClasses_), nClasses(nClasses_) { } DefaultLexer::~DefaultLexer() { } void SCI_METHOD DefaultLexer::Release() { delete this; } int SCI_METHOD DefaultLexer::Version() const { return lvMetaData; } const char * SCI_METHOD DefaultLexer::PropertyNames() { return ""; } int SCI_METHOD DefaultLexer::PropertyType(const char *) { return SC_TYPE_BOOLEAN; } const char * SCI_METHOD DefaultLexer::DescribeProperty(const char *) { return ""; } Sci_Position SCI_METHOD DefaultLexer::PropertySet(const char *, const char *) { return -1; } const char * SCI_METHOD DefaultLexer::DescribeWordListSets() { return ""; } Sci_Position SCI_METHOD DefaultLexer::WordListSet(int, const char *) { return -1; } void SCI_METHOD DefaultLexer::Fold(Sci_PositionU, Sci_Position, int, IDocument *) { } void * SCI_METHOD DefaultLexer::PrivateCall(int, void *) { return nullptr; } int SCI_METHOD DefaultLexer::LineEndTypesSupported() { return SC_LINE_END_TYPE_DEFAULT; } int SCI_METHOD DefaultLexer::AllocateSubStyles(int, int) { return -1; } int SCI_METHOD DefaultLexer::SubStylesStart(int) { return -1; } int SCI_METHOD DefaultLexer::SubStylesLength(int) { return 0; } int SCI_METHOD DefaultLexer::StyleFromSubStyle(int subStyle) { return subStyle; } int SCI_METHOD DefaultLexer::PrimaryStyleFromStyle(int style) { return style; } void SCI_METHOD DefaultLexer::FreeSubStyles() { } void SCI_METHOD DefaultLexer::SetIdentifiers(int, const char *) { } int SCI_METHOD DefaultLexer::DistanceToSecondaryStyles() { return 0; } const char * SCI_METHOD DefaultLexer::GetSubStyleBases() { return styleSubable; } int SCI_METHOD DefaultLexer::NamedStyles() { return static_cast(nClasses); } const char * SCI_METHOD DefaultLexer::NameOfStyle(int style) { return (style < NamedStyles()) ? lexClasses[style].name : ""; } const char * SCI_METHOD DefaultLexer::TagsOfStyle(int style) { return (style < NamedStyles()) ? lexClasses[style].tags : ""; } const char * SCI_METHOD DefaultLexer::DescriptionOfStyle(int style) { return (style < NamedStyles()) ? lexClasses[style].description : ""; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/DefaultLexer.h000066400000000000000000000044401463772530400270060ustar00rootroot00000000000000// Scintilla source code edit control /** @file DefaultLexer.h ** A lexer base class with default empty implementations of methods. ** For lexers that do not support all features so do not need real implementations. ** Does have real implementation for style metadata. **/ // Copyright 2017 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef DEFAULTLEXER_H #define DEFAULTLEXER_H namespace Scintilla { // A simple lexer with no state class DefaultLexer : public ILexerWithMetaData { const LexicalClass *lexClasses; size_t nClasses; public: DefaultLexer(const LexicalClass *lexClasses_ = nullptr, size_t nClasses_ = 0); virtual ~DefaultLexer(); void SCI_METHOD Release() override; int SCI_METHOD Version() const override; const char * SCI_METHOD PropertyNames() override; int SCI_METHOD PropertyType(const char *name) override; const char * SCI_METHOD DescribeProperty(const char *name) override; Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override; const char * SCI_METHOD DescribeWordListSets() override; Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override; void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override = 0; void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override; void * SCI_METHOD PrivateCall(int operation, void *pointer) override; int SCI_METHOD LineEndTypesSupported() override; int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles) override; int SCI_METHOD SubStylesStart(int styleBase) override; int SCI_METHOD SubStylesLength(int styleBase) override; int SCI_METHOD StyleFromSubStyle(int subStyle) override; int SCI_METHOD PrimaryStyleFromStyle(int style) override; void SCI_METHOD FreeSubStyles() override; void SCI_METHOD SetIdentifiers(int style, const char *identifiers) override; int SCI_METHOD DistanceToSecondaryStyles() override; const char * SCI_METHOD GetSubStyleBases() override; int SCI_METHOD NamedStyles() override; const char * SCI_METHOD NameOfStyle(int style) override; const char * SCI_METHOD TagsOfStyle(int style) override; const char * SCI_METHOD DescriptionOfStyle(int style) override; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/LexAccessor.h000066400000000000000000000126321463772530400266370ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexAccessor.h ** Interfaces between Scintilla and lexers. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LEXACCESSOR_H #define LEXACCESSOR_H namespace Scintilla { enum EncodingType { enc8bit, encUnicode, encDBCS }; class LexAccessor { private: IDocument *pAccess; enum {extremePosition=0x7FFFFFFF}; /** @a bufferSize is a trade off between time taken to copy the characters * and retrieval overhead. * @a slopSize positions the buffer before the desired position * in case there is some backtracking. */ enum {bufferSize=4000, slopSize=bufferSize/8}; char buf[bufferSize+1]; Sci_Position startPos; Sci_Position endPos; int codePage; enum EncodingType encodingType; Sci_Position lenDoc; char styleBuf[bufferSize]; Sci_Position validLen; Sci_PositionU startSeg; Sci_Position startPosStyling; int documentVersion; void Fill(Sci_Position position) { startPos = position - slopSize; if (startPos + bufferSize > lenDoc) startPos = lenDoc - bufferSize; if (startPos < 0) startPos = 0; endPos = startPos + bufferSize; if (endPos > lenDoc) endPos = lenDoc; pAccess->GetCharRange(buf, startPos, endPos-startPos); buf[endPos-startPos] = '\0'; } public: explicit LexAccessor(IDocument *pAccess_) : pAccess(pAccess_), startPos(extremePosition), endPos(0), codePage(pAccess->CodePage()), encodingType(enc8bit), lenDoc(pAccess->Length()), validLen(0), startSeg(0), startPosStyling(0), documentVersion(pAccess->Version()) { // Prevent warnings by static analyzers about uninitialized buf and styleBuf. buf[0] = 0; styleBuf[0] = 0; switch (codePage) { case 65001: encodingType = encUnicode; break; case 932: case 936: case 949: case 950: case 1361: encodingType = encDBCS; } } char operator[](Sci_Position position) { if (position < startPos || position >= endPos) { Fill(position); } return buf[position - startPos]; } IDocumentWithLineEnd *MultiByteAccess() const { if (documentVersion >= dvLineEnd) { return static_cast(pAccess); } return 0; } /** Safe version of operator[], returning a defined value for invalid position. */ char SafeGetCharAt(Sci_Position position, char chDefault=' ') { if (position < startPos || position >= endPos) { Fill(position); if (position < startPos || position >= endPos) { // Position is outside range of document return chDefault; } } return buf[position - startPos]; } bool IsLeadByte(char ch) const { return pAccess->IsDBCSLeadByte(ch); } EncodingType Encoding() const { return encodingType; } bool Match(Sci_Position pos, const char *s) { for (int i=0; *s; i++) { if (*s != SafeGetCharAt(pos+i)) return false; s++; } return true; } char StyleAt(Sci_Position position) const { return pAccess->StyleAt(position); } Sci_Position GetLine(Sci_Position position) const { return pAccess->LineFromPosition(position); } Sci_Position LineStart(Sci_Position line) const { return pAccess->LineStart(line); } Sci_Position LineEnd(Sci_Position line) { if (documentVersion >= dvLineEnd) { return (static_cast(pAccess))->LineEnd(line); } else { // Old interface means only '\r', '\n' and '\r\n' line ends. Sci_Position startNext = pAccess->LineStart(line+1); const char chLineEnd = SafeGetCharAt(startNext-1); if (chLineEnd == '\n' && (SafeGetCharAt(startNext-2) == '\r')) return startNext - 2; else return startNext - 1; } } int LevelAt(Sci_Position line) const { return pAccess->GetLevel(line); } Sci_Position Length() const { return lenDoc; } void Flush() { if (validLen > 0) { pAccess->SetStyles(validLen, styleBuf); startPosStyling += validLen; validLen = 0; } } int GetLineState(Sci_Position line) const { return pAccess->GetLineState(line); } int SetLineState(Sci_Position line, int state) { return pAccess->SetLineState(line, state); } // Style setting void StartAt(Sci_PositionU start) { pAccess->StartStyling(start, '\377'); startPosStyling = start; } Sci_PositionU GetStartSegment() const { return startSeg; } void StartSegment(Sci_PositionU pos) { startSeg = pos; } void ColourTo(Sci_PositionU pos, int chAttr) { // Only perform styling if non empty range if (pos != startSeg - 1) { assert(pos >= startSeg); if (pos < startSeg) { return; } if (validLen + (pos - startSeg + 1) >= bufferSize) Flush(); const char attr = static_cast(chAttr); if (validLen + (pos - startSeg + 1) >= bufferSize) { // Too big for buffer so send directly pAccess->SetStyleFor(pos - startSeg + 1, attr); } else { for (Sci_PositionU i = startSeg; i <= pos; i++) { assert((startPosStyling + validLen) < Length()); styleBuf[validLen++] = attr; } } } startSeg = pos+1; } void SetLevel(Sci_Position line, int level) { pAccess->SetLevel(line, level); } void IndicatorFill(Sci_Position start, Sci_Position end, int indicator, int value) { pAccess->DecorationSetCurrentIndicator(indicator); pAccess->DecorationFillRange(start, value, end - start); } void ChangeLexerState(Sci_Position start, Sci_Position end) { pAccess->ChangeLexerState(start, end); } }; struct LexicalClass { int value; const char *name; const char *tags; const char *description; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/LexerBase.cpp000066400000000000000000000061311463772530400266260ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexerBase.cxx ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "LexerModule.h" #include "LexerBase.h" using namespace Scintilla; static const char styleSubable[] = { 0 }; LexerBase::LexerBase(const LexicalClass *lexClasses_, size_t nClasses_) : lexClasses(lexClasses_), nClasses(nClasses_) { for (int wl = 0; wl < numWordLists; wl++) keyWordLists[wl] = new WordList; keyWordLists[numWordLists] = 0; } LexerBase::~LexerBase() { for (int wl = 0; wl < numWordLists; wl++) { delete keyWordLists[wl]; keyWordLists[wl] = 0; } keyWordLists[numWordLists] = 0; } void SCI_METHOD LexerBase::Release() { delete this; } int SCI_METHOD LexerBase::Version() const { return lvMetaData; } const char * SCI_METHOD LexerBase::PropertyNames() { return ""; } int SCI_METHOD LexerBase::PropertyType(const char *) { return SC_TYPE_BOOLEAN; } const char * SCI_METHOD LexerBase::DescribeProperty(const char *) { return ""; } Sci_Position SCI_METHOD LexerBase::PropertySet(const char *key, const char *val) { const char *valOld = props.Get(key); if (strcmp(val, valOld) != 0) { props.Set(key, val, strlen(key), strlen(val)); return 0; } else { return -1; } } const char * SCI_METHOD LexerBase::DescribeWordListSets() { return ""; } Sci_Position SCI_METHOD LexerBase::WordListSet(int n, const char *wl) { if (n < numWordLists) { WordList wlNew; wlNew.Set(wl); if (*keyWordLists[n] != wlNew) { keyWordLists[n]->Set(wl); return 0; } } return -1; } void * SCI_METHOD LexerBase::PrivateCall(int, void *) { return nullptr; } int SCI_METHOD LexerBase::LineEndTypesSupported() { return SC_LINE_END_TYPE_DEFAULT; } int SCI_METHOD LexerBase::AllocateSubStyles(int, int) { return -1; } int SCI_METHOD LexerBase::SubStylesStart(int) { return -1; } int SCI_METHOD LexerBase::SubStylesLength(int) { return 0; } int SCI_METHOD LexerBase::StyleFromSubStyle(int subStyle) { return subStyle; } int SCI_METHOD LexerBase::PrimaryStyleFromStyle(int style) { return style; } void SCI_METHOD LexerBase::FreeSubStyles() { } void SCI_METHOD LexerBase::SetIdentifiers(int, const char *) { } int SCI_METHOD LexerBase::DistanceToSecondaryStyles() { return 0; } const char * SCI_METHOD LexerBase::GetSubStyleBases() { return styleSubable; } int SCI_METHOD LexerBase::NamedStyles() { return static_cast(nClasses); } const char * SCI_METHOD LexerBase::NameOfStyle(int style) { return (style < NamedStyles()) ? lexClasses[style].name : ""; } const char * SCI_METHOD LexerBase::TagsOfStyle(int style) { return (style < NamedStyles()) ? lexClasses[style].tags : ""; } const char * SCI_METHOD LexerBase::DescriptionOfStyle(int style) { return (style < NamedStyles()) ? lexClasses[style].description : ""; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/LexerBase.h000066400000000000000000000043251463772530400262760ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexerBase.h ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LEXERBASE_H #define LEXERBASE_H namespace Scintilla { // A simple lexer with no state class LexerBase : public ILexerWithMetaData { protected: const LexicalClass *lexClasses; size_t nClasses; PropSetSimple props; enum {numWordLists=KEYWORDSET_MAX+1}; WordList *keyWordLists[numWordLists+1]; public: LexerBase(const LexicalClass *lexClasses_=nullptr, size_t nClasses_=0); virtual ~LexerBase(); void SCI_METHOD Release() override; int SCI_METHOD Version() const override; const char * SCI_METHOD PropertyNames() override; int SCI_METHOD PropertyType(const char *name) override; const char * SCI_METHOD DescribeProperty(const char *name) override; Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override; const char * SCI_METHOD DescribeWordListSets() override; Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override; void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override = 0; void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override = 0; void * SCI_METHOD PrivateCall(int operation, void *pointer) override; int SCI_METHOD LineEndTypesSupported() override; int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles) override; int SCI_METHOD SubStylesStart(int styleBase) override; int SCI_METHOD SubStylesLength(int styleBase) override; int SCI_METHOD StyleFromSubStyle(int subStyle) override; int SCI_METHOD PrimaryStyleFromStyle(int style) override; void SCI_METHOD FreeSubStyles() override; void SCI_METHOD SetIdentifiers(int style, const char *identifiers) override; int SCI_METHOD DistanceToSecondaryStyles() override; const char * SCI_METHOD GetSubStyleBases() override; int SCI_METHOD NamedStyles() override; const char * SCI_METHOD NameOfStyle(int style) override; const char * SCI_METHOD TagsOfStyle(int style) override; const char * SCI_METHOD DescriptionOfStyle(int style) override; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/LexerModule.cpp000066400000000000000000000057211463772530400272050ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexerModule.cxx ** Colourise for particular languages. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "LexerModule.h" #include "LexerBase.h" #include "LexerSimple.h" using namespace Scintilla; LexerModule::LexerModule(int language_, LexerFunction fnLexer_, const char *languageName_, LexerFunction fnFolder_, const char *const wordListDescriptions_[], const LexicalClass *lexClasses_, size_t nClasses_) : language(language_), fnLexer(fnLexer_), fnFolder(fnFolder_), fnFactory(nullptr), wordListDescriptions(wordListDescriptions_), lexClasses(lexClasses_), nClasses(nClasses_), languageName(languageName_) { } LexerModule::LexerModule(int language_, LexerFactoryFunction fnFactory_, const char *languageName_, const char * const wordListDescriptions_[]) : language(language_), fnLexer(nullptr), fnFolder(nullptr), fnFactory(fnFactory_), wordListDescriptions(wordListDescriptions_), lexClasses(nullptr), nClasses(0), languageName(languageName_) { } LexerModule::~LexerModule() { } int LexerModule::GetLanguage() const { return language; } int LexerModule::GetNumWordLists() const { if (!wordListDescriptions) { return -1; } else { int numWordLists = 0; while (wordListDescriptions[numWordLists]) { ++numWordLists; } return numWordLists; } } const char *LexerModule::GetWordListDescription(int index) const { assert(index < GetNumWordLists()); if (!wordListDescriptions || (index >= GetNumWordLists())) { return ""; } else { return wordListDescriptions[index]; } } const LexicalClass *LexerModule::LexClasses() const { return lexClasses; } size_t LexerModule::NamedStyles() const { return nClasses; } ILexer *LexerModule::Create() const { if (fnFactory) return fnFactory(); else return new LexerSimple(this); } void LexerModule::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler) const { if (fnLexer) fnLexer(startPos, lengthDoc, initStyle, keywordlists, styler); } void LexerModule::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler) const { if (fnFolder) { Sci_Position lineCurrent = styler.GetLine(startPos); // Move back one line in case deletion wrecked current line fold state if (lineCurrent > 0) { lineCurrent--; const Sci_Position newStartPos = styler.LineStart(lineCurrent); lengthDoc += startPos - newStartPos; startPos = newStartPos; initStyle = 0; if (startPos > 0) { initStyle = styler.StyleAt(startPos - 1); } } fnFolder(startPos, lengthDoc, initStyle, keywordlists, styler); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/LexerModule.h000066400000000000000000000047021463772530400266500ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexerModule.h ** Colourise for particular languages. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LEXERMODULE_H #define LEXERMODULE_H namespace Scintilla { class Accessor; class WordList; struct LexicalClass; typedef void (*LexerFunction)(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler); typedef ILexer *(*LexerFactoryFunction)(); /** * A LexerModule is responsible for lexing and folding a particular language. * The Catalogue class maintains a list of LexerModules which can be searched to find a * module appropriate to a particular language. * The ExternalLexerModule subclass holds lexers loaded from DLLs or shared libraries. */ class LexerModule { protected: int language; LexerFunction fnLexer; LexerFunction fnFolder; LexerFactoryFunction fnFactory; const char * const * wordListDescriptions; const LexicalClass *lexClasses; size_t nClasses; public: const char *languageName; LexerModule( int language_, LexerFunction fnLexer_, const char *languageName_=nullptr, LexerFunction fnFolder_= nullptr, const char * const wordListDescriptions_[]=nullptr, const LexicalClass *lexClasses_=nullptr, size_t nClasses_=0); LexerModule( int language_, LexerFactoryFunction fnFactory_, const char *languageName_, const char * const wordListDescriptions_[]=nullptr); virtual ~LexerModule(); int GetLanguage() const; // -1 is returned if no WordList information is available int GetNumWordLists() const; const char *GetWordListDescription(int index) const; const LexicalClass *LexClasses() const; size_t NamedStyles() const; ILexer *Create() const; virtual void Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler) const; virtual void Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler) const; friend class Catalogue; }; inline int Maximum(int a, int b) { return (a > b) ? a : b; } // Shut up annoying Visual C++ warnings: #ifdef _MSC_VER #pragma warning(disable: 4244 4456 4457) #endif // Turn off shadow warnings for lexers as may be maintained by others #if defined(__GNUC__) #pragma GCC diagnostic ignored "-Wshadow" #endif } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/LexerNoExceptions.cpp000066400000000000000000000036531463772530400304000ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexerNoExceptions.cxx ** A simple lexer with no state which does not throw exceptions so can be used in an external lexer. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "LexerModule.h" #include "LexerBase.h" #include "LexerNoExceptions.h" using namespace Scintilla; Sci_Position SCI_METHOD LexerNoExceptions::PropertySet(const char *key, const char *val) { try { return LexerBase::PropertySet(key, val); } catch (...) { // Should not throw into caller as may be compiled with different compiler or options } return -1; } Sci_Position SCI_METHOD LexerNoExceptions::WordListSet(int n, const char *wl) { try { return LexerBase::WordListSet(n, wl); } catch (...) { // Should not throw into caller as may be compiled with different compiler or options } return -1; } void SCI_METHOD LexerNoExceptions::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) { try { Accessor astyler(pAccess, &props); Lexer(startPos, lengthDoc, initStyle, pAccess, astyler); astyler.Flush(); } catch (...) { // Should not throw into caller as may be compiled with different compiler or options pAccess->SetErrorStatus(SC_STATUS_FAILURE); } } void SCI_METHOD LexerNoExceptions::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) { try { Accessor astyler(pAccess, &props); Folder(startPos, lengthDoc, initStyle, pAccess, astyler); astyler.Flush(); } catch (...) { // Should not throw into caller as may be compiled with different compiler or options pAccess->SetErrorStatus(SC_STATUS_FAILURE); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/LexerNoExceptions.h000066400000000000000000000021571463772530400300430ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexerNoExceptions.h ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LEXERNOEXCEPTIONS_H #define LEXERNOEXCEPTIONS_H namespace Scintilla { // A simple lexer with no state class LexerNoExceptions : public LexerBase { public: // TODO Also need to prevent exceptions in constructor and destructor Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override; Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override; void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override; void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *) override; virtual void Lexer(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess, Accessor &styler) = 0; virtual void Folder(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess, Accessor &styler) = 0; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/LexerSimple.cpp000066400000000000000000000027261463772530400272130ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexerSimple.cxx ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "LexerModule.h" #include "LexerBase.h" #include "LexerSimple.h" using namespace Scintilla; LexerSimple::LexerSimple(const LexerModule *module_) : LexerBase(module_->LexClasses(), module_->NamedStyles()), module(module_) { for (int wl = 0; wl < module->GetNumWordLists(); wl++) { if (!wordLists.empty()) wordLists += "\n"; wordLists += module->GetWordListDescription(wl); } } const char * SCI_METHOD LexerSimple::DescribeWordListSets() { return wordLists.c_str(); } void SCI_METHOD LexerSimple::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) { Accessor astyler(pAccess, &props); module->Lex(startPos, lengthDoc, initStyle, keyWordLists, astyler); astyler.Flush(); } void SCI_METHOD LexerSimple::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) { if (props.GetInt("fold")) { Accessor astyler(pAccess, &props); module->Fold(startPos, lengthDoc, initStyle, keyWordLists, astyler); astyler.Flush(); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/LexerSimple.h000066400000000000000000000014511463772530400266520ustar00rootroot00000000000000// Scintilla source code edit control /** @file LexerSimple.h ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LEXERSIMPLE_H #define LEXERSIMPLE_H namespace Scintilla { // A simple lexer with no state class LexerSimple : public LexerBase { const LexerModule *module; std::string wordLists; public: explicit LexerSimple(const LexerModule *module_); const char * SCI_METHOD DescribeWordListSets() override; void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override; void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/License.txt000066400000000000000000000015261463772530400263760ustar00rootroot00000000000000License for Scintilla and SciTE Copyright 1998-2003 by Neil Hodgson All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NEIL HODGSON 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.sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/OptionSet.h000066400000000000000000000065751463772530400263610ustar00rootroot00000000000000// Scintilla source code edit control /** @file OptionSet.h ** Manage descriptive information about an options struct for a lexer. ** Hold the names, positions, and descriptions of boolean, integer and string options and ** allow setting options and retrieving metadata about the options. **/ // Copyright 2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef OPTIONSET_H #define OPTIONSET_H namespace Scintilla { template class OptionSet { typedef T Target; typedef bool T::*plcob; typedef int T::*plcoi; typedef std::string T::*plcos; struct Option { int opType; union { plcob pb; plcoi pi; plcos ps; }; std::string description; Option() : opType(SC_TYPE_BOOLEAN), pb(0), description("") { } Option(plcob pb_, std::string description_="") : opType(SC_TYPE_BOOLEAN), pb(pb_), description(description_) { } Option(plcoi pi_, std::string description_) : opType(SC_TYPE_INTEGER), pi(pi_), description(description_) { } Option(plcos ps_, std::string description_) : opType(SC_TYPE_STRING), ps(ps_), description(description_) { } bool Set(T *base, const char *val) const { switch (opType) { case SC_TYPE_BOOLEAN: { bool option = atoi(val) != 0; if ((*base).*pb != option) { (*base).*pb = option; return true; } break; } case SC_TYPE_INTEGER: { int option = atoi(val); if ((*base).*pi != option) { (*base).*pi = option; return true; } break; } case SC_TYPE_STRING: { if ((*base).*ps != val) { (*base).*ps = val; return true; } break; } } return false; } }; typedef std::map OptionMap; OptionMap nameToDef; std::string names; std::string wordLists; void AppendName(const char *name) { if (!names.empty()) names += "\n"; names += name; } public: virtual ~OptionSet() { } void DefineProperty(const char *name, plcob pb, std::string description="") { nameToDef[name] = Option(pb, description); AppendName(name); } void DefineProperty(const char *name, plcoi pi, std::string description="") { nameToDef[name] = Option(pi, description); AppendName(name); } void DefineProperty(const char *name, plcos ps, std::string description="") { nameToDef[name] = Option(ps, description); AppendName(name); } const char *PropertyNames() const { return names.c_str(); } int PropertyType(const char *name) { typename OptionMap::iterator it = nameToDef.find(name); if (it != nameToDef.end()) { return it->second.opType; } return SC_TYPE_BOOLEAN; } const char *DescribeProperty(const char *name) { typename OptionMap::iterator it = nameToDef.find(name); if (it != nameToDef.end()) { return it->second.description.c_str(); } return ""; } bool PropertySet(T *base, const char *name, const char *val) { typename OptionMap::iterator it = nameToDef.find(name); if (it != nameToDef.end()) { return it->second.Set(base, val); } return false; } void DefineWordListSets(const char * const wordListDescriptions[]) { if (wordListDescriptions) { for (size_t wl = 0; wordListDescriptions[wl]; wl++) { if (!wordLists.empty()) wordLists += "\n"; wordLists += wordListDescriptions[wl]; } } } const char *DescribeWordListSets() const { return wordLists.c_str(); } }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/PropSetSimple.cpp000066400000000000000000000103561463772530400275260ustar00rootroot00000000000000// Scintilla source code edit control /** @file PropSetSimple.cxx ** A basic string to string map. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. // Maintain a dictionary of properties #include #include #include #include #include "PropSetSimple.h" using namespace Scintilla; namespace { typedef std::map mapss; mapss *PropsFromPointer(void *impl) { return static_cast(impl); } } PropSetSimple::PropSetSimple() { mapss *props = new mapss; impl = static_cast(props); } PropSetSimple::~PropSetSimple() { mapss *props = PropsFromPointer(impl); delete props; impl = 0; } void PropSetSimple::Set(const char *key, const char *val, size_t lenKey, size_t lenVal) { mapss *props = PropsFromPointer(impl); if (!*key) // Empty keys are not supported return; (*props)[std::string(key, lenKey)] = std::string(val, lenVal); } static bool IsASpaceCharacter(unsigned int ch) { return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); } void PropSetSimple::Set(const char *keyVal) { while (IsASpaceCharacter(*keyVal)) keyVal++; const char *endVal = keyVal; while (*endVal && (*endVal != '\n')) endVal++; const char *eqAt = strchr(keyVal, '='); if (eqAt) { Set(keyVal, eqAt + 1, eqAt-keyVal, endVal - eqAt - 1); } else if (*keyVal) { // No '=' so assume '=1' Set(keyVal, "1", endVal-keyVal, 1); } } void PropSetSimple::SetMultiple(const char *s) { const char *eol = strchr(s, '\n'); while (eol) { Set(s); s = eol + 1; eol = strchr(s, '\n'); } Set(s); } const char *PropSetSimple::Get(const char *key) const { mapss *props = PropsFromPointer(impl); mapss::const_iterator keyPos = props->find(std::string(key)); if (keyPos != props->end()) { return keyPos->second.c_str(); } else { return ""; } } // There is some inconsistency between GetExpanded("foo") and Expand("$(foo)"). // A solution is to keep a stack of variables that have been expanded, so that // recursive expansions can be skipped. For now I'll just use the C++ stack // for that, through a recursive function and a simple chain of pointers. struct VarChain { VarChain(const char *var_=nullptr, const VarChain *link_= nullptr): var(var_), link(link_) {} bool contains(const char *testVar) const { return (var && (0 == strcmp(var, testVar))) || (link && link->contains(testVar)); } const char *var; const VarChain *link; }; static int ExpandAllInPlace(const PropSetSimple &props, std::string &withVars, int maxExpands, const VarChain &blankVars) { size_t varStart = withVars.find("$("); while ((varStart != std::string::npos) && (maxExpands > 0)) { const size_t varEnd = withVars.find(')', varStart+2); if (varEnd == std::string::npos) { break; } // For consistency, when we see '$(ab$(cde))', expand the inner variable first, // regardless whether there is actually a degenerate variable named 'ab$(cde'. size_t innerVarStart = withVars.find("$(", varStart+2); while ((innerVarStart != std::string::npos) && (innerVarStart > varStart) && (innerVarStart < varEnd)) { varStart = innerVarStart; innerVarStart = withVars.find("$(", varStart+2); } std::string var(withVars.c_str(), varStart + 2, varEnd - varStart - 2); std::string val = props.Get(var.c_str()); if (blankVars.contains(var.c_str())) { val = ""; // treat blankVar as an empty string (e.g. to block self-reference) } if (--maxExpands >= 0) { maxExpands = ExpandAllInPlace(props, val, maxExpands, VarChain(var.c_str(), &blankVars)); } withVars.erase(varStart, varEnd-varStart+1); withVars.insert(varStart, val.c_str(), val.length()); varStart = withVars.find("$("); } return maxExpands; } int PropSetSimple::GetExpanded(const char *key, char *result) const { std::string val = Get(key); ExpandAllInPlace(*this, val, 100, VarChain(key)); const int n = static_cast(val.size()); if (result) { memcpy(result, val.c_str(), n+1); } return n; // Not including NUL } int PropSetSimple::GetInt(const char *key, int defaultValue) const { std::string val = Get(key); ExpandAllInPlace(*this, val, 100, VarChain(key)); if (!val.empty()) { return atoi(val.c_str()); } return defaultValue; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/PropSetSimple.h000066400000000000000000000013251463772530400271670ustar00rootroot00000000000000// Scintilla source code edit control /** @file PropSetSimple.h ** A basic string to string map. **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef PROPSETSIMPLE_H #define PROPSETSIMPLE_H namespace Scintilla { class PropSetSimple { void *impl; void Set(const char *keyVal); public: PropSetSimple(); virtual ~PropSetSimple(); void Set(const char *key, const char *val, size_t lenKey, size_t lenVal); void SetMultiple(const char *); const char *Get(const char *key) const; int GetExpanded(const char *key, char *result) const; int GetInt(const char *key, int defaultValue=0) const; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/SparseState.h000066400000000000000000000056731463772530400266710ustar00rootroot00000000000000// Scintilla source code edit control /** @file SparseState.h ** Hold lexer state that may change rarely. ** This is often per-line state such as whether a particular type of section has been entered. ** A state continues until it is changed. **/ // Copyright 2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef SPARSESTATE_H #define SPARSESTATE_H namespace Scintilla { template class SparseState { struct State { Sci_Position position; T value; State(Sci_Position position_, T value_) : position(position_), value(value_) { } inline bool operator<(const State &other) const { return position < other.position; } inline bool operator==(const State &other) const { return (position == other.position) && (value == other.value); } }; Sci_Position positionFirst; typedef std::vector stateVector; stateVector states; typename stateVector::iterator Find(Sci_Position position) { State searchValue(position, T()); return std::lower_bound(states.begin(), states.end(), searchValue); } public: explicit SparseState(Sci_Position positionFirst_=-1) { positionFirst = positionFirst_; } void Set(Sci_Position position, T value) { Delete(position); if (states.empty() || (value != states[states.size()-1].value)) { states.push_back(State(position, value)); } } T ValueAt(Sci_Position position) { if (states.empty()) return T(); if (position < states[0].position) return T(); typename stateVector::iterator low = Find(position); if (low == states.end()) { return states[states.size()-1].value; } else { if (low->position > position) { --low; } return low->value; } } bool Delete(Sci_Position position) { typename stateVector::iterator low = Find(position); if (low != states.end()) { states.erase(low, states.end()); return true; } return false; } size_t size() const { return states.size(); } // Returns true if Merge caused a significant change bool Merge(const SparseState &other, Sci_Position ignoreAfter) { // Changes caused beyond ignoreAfter are not significant Delete(ignoreAfter+1); bool different = true; bool changed = false; typename stateVector::iterator low = Find(other.positionFirst); if (static_cast(states.end() - low) == other.states.size()) { // Same number in other as after positionFirst in this different = !std::equal(low, states.end(), other.states.begin()); } if (different) { if (low != states.end()) { states.erase(low, states.end()); changed = true; } typename stateVector::const_iterator startOther = other.states.begin(); if (!states.empty() && !other.states.empty() && states.back().value == startOther->value) ++startOther; if (startOther != other.states.end()) { states.insert(states.end(), startOther, other.states.end()); changed = true; } } return changed; } }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/StringCopy.h000066400000000000000000000015251463772530400265240ustar00rootroot00000000000000// Scintilla source code edit control /** @file StringCopy.h ** Safe string copy function which always NUL terminates. ** ELEMENTS macro for determining array sizes. **/ // Copyright 2013 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef STRINGCOPY_H #define STRINGCOPY_H namespace Scintilla { // Safer version of string copy functions like strcpy, wcsncpy, etc. // Instantiate over fixed length strings of both char and wchar_t. // May truncate if source doesn't fit into dest with room for NUL. template void StringCopy(T (&dest)[count], const T* source) { for (size_t i=0; i // This file is in the public domain. #include #include #include #include "ILexer.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" using namespace Scintilla; bool StyleContext::MatchIgnoreCase(const char *s) { if (MakeLowerCase(ch) != static_cast(*s)) return false; s++; if (MakeLowerCase(chNext) != static_cast(*s)) return false; s++; for (int n = 2; *s; n++) { if (*s != MakeLowerCase(styler.SafeGetCharAt(currentPos + n, 0))) return false; s++; } return true; } static void getRange(Sci_PositionU start, Sci_PositionU end, LexAccessor &styler, char *s, Sci_PositionU len) { Sci_PositionU i = 0; while ((i < end - start + 1) && (i < len-1)) { s[i] = styler[start + i]; i++; } s[i] = '\0'; } void StyleContext::GetCurrent(char *s, Sci_PositionU len) { getRange(styler.GetStartSegment(), currentPos - 1, styler, s, len); } static void getRangeLowered(Sci_PositionU start, Sci_PositionU end, LexAccessor &styler, char *s, Sci_PositionU len) { Sci_PositionU i = 0; while ((i < end - start + 1) && (i < len-1)) { s[i] = MakeLowerCase(styler[start + i]); i++; } s[i] = '\0'; } void StyleContext::GetCurrentLowered(char *s, Sci_PositionU len) { getRangeLowered(styler.GetStartSegment(), currentPos - 1, styler, s, len); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/StyleContext.h000066400000000000000000000136121463772530400270700ustar00rootroot00000000000000// Scintilla source code edit control /** @file StyleContext.h ** Lexer infrastructure. **/ // Copyright 1998-2004 by Neil Hodgson // This file is in the public domain. #ifndef STYLECONTEXT_H #define STYLECONTEXT_H namespace Scintilla { // All languages handled so far can treat all characters >= 0x80 as one class // which just continues the current token or starts an identifier if in default. // DBCS treated specially as the second character can be < 0x80 and hence // syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80 class StyleContext { LexAccessor &styler; IDocumentWithLineEnd *multiByteAccess; Sci_PositionU endPos; Sci_PositionU lengthDocument; // Used for optimizing GetRelativeCharacter Sci_PositionU posRelative; Sci_PositionU currentPosLastRelative; Sci_Position offsetRelative; void GetNextChar() { if (multiByteAccess) { chNext = multiByteAccess->GetCharacterAndWidth(currentPos+width, &widthNext); } else { chNext = static_cast(styler.SafeGetCharAt(currentPos+width, 0)); widthNext = 1; } // End of line determined from line end position, allowing CR, LF, // CRLF and Unicode line ends as set by document. if (currentLine < lineDocEnd) atLineEnd = static_cast(currentPos) >= (lineStartNext-1); else // Last line atLineEnd = static_cast(currentPos) >= lineStartNext; } public: Sci_PositionU currentPos; Sci_Position currentLine; Sci_Position lineDocEnd; Sci_Position lineStartNext; bool atLineStart; bool atLineEnd; int state; int chPrev; int ch; Sci_Position width; int chNext; Sci_Position widthNext; StyleContext(Sci_PositionU startPos, Sci_PositionU length, int initStyle, LexAccessor &styler_, char chMask='\377') : styler(styler_), multiByteAccess(nullptr), endPos(startPos + length), posRelative(0), currentPosLastRelative(0x7FFFFFFF), offsetRelative(0), currentPos(startPos), currentLine(-1), lineStartNext(-1), atLineEnd(false), state(initStyle & chMask), // Mask off all bits which aren't in the chMask. chPrev(0), ch(0), width(0), chNext(0), widthNext(1) { if (styler.Encoding() != enc8bit) { multiByteAccess = styler.MultiByteAccess(); } styler.StartAt(startPos /*, chMask*/); styler.StartSegment(startPos); currentLine = styler.GetLine(startPos); lineStartNext = styler.LineStart(currentLine+1); lengthDocument = static_cast(styler.Length()); if (endPos == lengthDocument) endPos++; lineDocEnd = styler.GetLine(lengthDocument); atLineStart = static_cast(styler.LineStart(currentLine)) == startPos; // Variable width is now 0 so GetNextChar gets the char at currentPos into chNext/widthNext width = 0; GetNextChar(); ch = chNext; width = widthNext; GetNextChar(); } // Deleted so StyleContext objects can not be copied. StyleContext(const StyleContext &) = delete; StyleContext &operator=(const StyleContext &) = delete; void Complete() { styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state); styler.Flush(); } bool More() const { return currentPos < endPos; } void Forward() { if (currentPos < endPos) { atLineStart = atLineEnd; if (atLineStart) { currentLine++; lineStartNext = styler.LineStart(currentLine+1); } chPrev = ch; currentPos += width; ch = chNext; width = widthNext; GetNextChar(); } else { atLineStart = false; chPrev = ' '; ch = ' '; chNext = ' '; atLineEnd = true; } } void Forward(Sci_Position nb) { for (Sci_Position i = 0; i < nb; i++) { Forward(); } } void ForwardBytes(Sci_Position nb) { const Sci_PositionU forwardPos = currentPos + nb; while (forwardPos > currentPos) { const Sci_PositionU currentPosStart = currentPos; Forward(); if (currentPos == currentPosStart) { // Reached end return; } } } void ChangeState(int state_) { state = state_; } void SetState(int state_) { styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state); state = state_; } void ForwardSetState(int state_) { Forward(); styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state); state = state_; } Sci_Position LengthCurrent() const { return currentPos - styler.GetStartSegment(); } int GetRelative(Sci_Position n) { return static_cast(styler.SafeGetCharAt(currentPos+n, 0)); } int GetRelativeCharacter(Sci_Position n) { if (n == 0) return ch; if (multiByteAccess) { if ((currentPosLastRelative != currentPos) || ((n > 0) && ((offsetRelative < 0) || (n < offsetRelative))) || ((n < 0) && ((offsetRelative > 0) || (n > offsetRelative)))) { posRelative = currentPos; offsetRelative = 0; } const Sci_Position diffRelative = n - offsetRelative; const Sci_Position posNew = multiByteAccess->GetRelativePosition(posRelative, diffRelative); const int chReturn = multiByteAccess->GetCharacterAndWidth(posNew, nullptr); posRelative = posNew; currentPosLastRelative = currentPos; offsetRelative = n; return chReturn; } else { // fast version for single byte encodings return static_cast(styler.SafeGetCharAt(currentPos + n, 0)); } } bool Match(char ch0) const { return ch == static_cast(ch0); } bool Match(char ch0, char ch1) const { return (ch == static_cast(ch0)) && (chNext == static_cast(ch1)); } bool Match(const char *s) { if (ch != static_cast(*s)) return false; s++; if (!*s) return true; if (chNext != static_cast(*s)) return false; s++; for (int n=2; *s; n++) { if (*s != styler.SafeGetCharAt(currentPos+n, 0)) return false; s++; } return true; } // Non-inline bool MatchIgnoreCase(const char *s); void GetCurrent(char *s, Sci_PositionU len); void GetCurrentLowered(char *s, Sci_PositionU len); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/SubStyles.h000066400000000000000000000107601463772530400263610ustar00rootroot00000000000000// Scintilla source code edit control /** @file SubStyles.h ** Manage substyles for a lexer. **/ // Copyright 2012 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef SUBSTYLES_H #define SUBSTYLES_H namespace Scintilla { class WordClassifier { int baseStyle; int firstStyle; int lenStyles; std::map wordToStyle; public: explicit WordClassifier(int baseStyle_) : baseStyle(baseStyle_), firstStyle(0), lenStyles(0) { } void Allocate(int firstStyle_, int lenStyles_) { firstStyle = firstStyle_; lenStyles = lenStyles_; wordToStyle.clear(); } int Base() const { return baseStyle; } int Start() const { return firstStyle; } int Last() const { return firstStyle + lenStyles - 1; } int Length() const { return lenStyles; } void Clear() { firstStyle = 0; lenStyles = 0; wordToStyle.clear(); } int ValueFor(const std::string &s) const { std::map::const_iterator it = wordToStyle.find(s); if (it != wordToStyle.end()) return it->second; else return -1; } bool IncludesStyle(int style) const { return (style >= firstStyle) && (style < (firstStyle + lenStyles)); } void SetIdentifiers(int style, const char *identifiers) { while (*identifiers) { const char *cpSpace = identifiers; while (*cpSpace && !(*cpSpace == ' ' || *cpSpace == '\t' || *cpSpace == '\r' || *cpSpace == '\n')) cpSpace++; if (cpSpace > identifiers) { std::string word(identifiers, cpSpace - identifiers); wordToStyle[word] = style; } identifiers = cpSpace; if (*identifiers) identifiers++; } } }; class SubStyles { int classifications; const char *baseStyles; int styleFirst; int stylesAvailable; int secondaryDistance; int allocated; std::vector classifiers; int BlockFromBaseStyle(int baseStyle) const { for (int b=0; b < classifications; b++) { if (baseStyle == baseStyles[b]) return b; } return -1; } int BlockFromStyle(int style) const { int b = 0; for (std::vector::const_iterator it=classifiers.begin(); it != classifiers.end(); ++it) { if (it->IncludesStyle(style)) return b; b++; } return -1; } public: SubStyles(const char *baseStyles_, int styleFirst_, int stylesAvailable_, int secondaryDistance_) : classifications(0), baseStyles(baseStyles_), styleFirst(styleFirst_), stylesAvailable(stylesAvailable_), secondaryDistance(secondaryDistance_), allocated(0) { while (baseStyles[classifications]) { classifiers.push_back(WordClassifier(baseStyles[classifications])); classifications++; } } int Allocate(int styleBase, int numberStyles) { const int block = BlockFromBaseStyle(styleBase); if (block >= 0) { if ((allocated + numberStyles) > stylesAvailable) return -1; const int startBlock = styleFirst + allocated; allocated += numberStyles; classifiers[block].Allocate(startBlock, numberStyles); return startBlock; } else { return -1; } } int Start(int styleBase) { const int block = BlockFromBaseStyle(styleBase); return (block >= 0) ? classifiers[block].Start() : -1; } int Length(int styleBase) { const int block = BlockFromBaseStyle(styleBase); return (block >= 0) ? classifiers[block].Length() : 0; } int BaseStyle(int subStyle) const { const int block = BlockFromStyle(subStyle); if (block >= 0) return classifiers[block].Base(); else return subStyle; } int DistanceToSecondaryStyles() const { return secondaryDistance; } int FirstAllocated() const { int start = 257; for (std::vector::const_iterator it = classifiers.begin(); it != classifiers.end(); ++it) { if (start > it->Start()) start = it->Start(); } return (start < 256) ? start : -1; } int LastAllocated() const { int last = -1; for (std::vector::const_iterator it = classifiers.begin(); it != classifiers.end(); ++it) { if (last < it->Last()) last = it->Last(); } return last; } void SetIdentifiers(int style, const char *identifiers) { const int block = BlockFromStyle(style); if (block >= 0) classifiers[block].SetIdentifiers(style, identifiers); } void Free() { allocated = 0; for (std::vector::iterator it=classifiers.begin(); it != classifiers.end(); ++it) it->Clear(); } const WordClassifier &Classifier(int baseStyle) const { const int block = BlockFromBaseStyle(baseStyle); return classifiers[block >= 0 ? block : 0]; } }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/WordList.cpp000066400000000000000000000153471463772530400265340ustar00rootroot00000000000000// Scintilla source code edit control /** @file WordList.cxx ** Hold a list of words. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "WordList.h" using namespace Scintilla; /** * Creates an array that points into each word in the string and puts \0 terminators * after each word. */ static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = false) { int prev = '\n'; int words = 0; // For rapid determination of whether a character is a separator, build // a look up table. bool wordSeparator[256] = {}; // Initialise all to false. wordSeparator[static_cast('\r')] = true; wordSeparator[static_cast('\n')] = true; if (!onlyLineEnds) { wordSeparator[static_cast(' ')] = true; wordSeparator[static_cast('\t')] = true; } for (int j = 0; wordlist[j]; j++) { const int curr = static_cast(wordlist[j]); if (!wordSeparator[curr] && wordSeparator[prev]) words++; prev = curr; } char **keywords = new char *[words + 1]; int wordsStore = 0; const size_t slen = strlen(wordlist); if (words) { prev = '\0'; for (size_t k = 0; k < slen; k++) { if (!wordSeparator[static_cast(wordlist[k])]) { if (!prev) { keywords[wordsStore] = &wordlist[k]; wordsStore++; } } else { wordlist[k] = '\0'; } prev = wordlist[k]; } } assert(wordsStore < (words + 1)); keywords[wordsStore] = &wordlist[slen]; *len = wordsStore; return keywords; } WordList::WordList(bool onlyLineEnds_) : words(0), list(0), len(0), onlyLineEnds(onlyLineEnds_) { // Prevent warnings by static analyzers about uninitialized starts. starts[0] = -1; } WordList::~WordList() { Clear(); } WordList::operator bool() const { return len ? true : false; } bool WordList::operator!=(const WordList &other) const { if (len != other.len) return true; for (int i=0; i(a), *static_cast(b)); } static void SortWordList(char **words, unsigned int len) { qsort(words, len, sizeof(*words), cmpWords); } #endif void WordList::Set(const char *s) { Clear(); const size_t lenS = strlen(s) + 1; list = new char[lenS]; memcpy(list, s, lenS); words = ArrayFromWordList(list, &len, onlyLineEnds); #ifdef _MSC_VER std::sort(words, words + len, cmpWords); #else SortWordList(words, len); #endif std::fill(starts, std::end(starts), -1); for (int l = len - 1; l >= 0; l--) { unsigned char indexChar = words[l][0]; starts[indexChar] = l; } } /** Check whether a string is in the list. * List elements are either exact matches or prefixes. * Prefix elements start with '^' and match all strings that start with the rest of the element * so '^GTK_' matches 'GTK_X', 'GTK_MAJOR_VERSION', and 'GTK_'. */ bool WordList::InList(const char *s) const { if (0 == words) return false; const unsigned char firstChar = s[0]; int j = starts[firstChar]; if (j >= 0) { while (words[j][0] == firstChar) { if (s[1] == words[j][1]) { const char *a = words[j] + 1; const char *b = s + 1; while (*a && *a == *b) { a++; b++; } if (!*a && !*b) return true; } j++; } } j = starts[static_cast('^')]; if (j >= 0) { while (words[j][0] == '^') { const char *a = words[j] + 1; const char *b = s; while (*a && *a == *b) { a++; b++; } if (!*a) return true; j++; } } return false; } /** similar to InList, but word s can be a substring of keyword. * eg. the keyword define is defined as def~ine. This means the word must start * with def to be a keyword, but also defi, defin and define are valid. * The marker is ~ in this case. */ bool WordList::InListAbbreviated(const char *s, const char marker) const { if (0 == words) return false; const unsigned char firstChar = s[0]; int j = starts[firstChar]; if (j >= 0) { while (words[j][0] == firstChar) { bool isSubword = false; int start = 1; if (words[j][1] == marker) { isSubword = true; start++; } if (s[1] == words[j][start]) { const char *a = words[j] + start; const char *b = s + 1; while (*a && *a == *b) { a++; if (*a == marker) { isSubword = true; a++; } b++; } if ((!*a || isSubword) && !*b) return true; } j++; } } j = starts[static_cast('^')]; if (j >= 0) { while (words[j][0] == '^') { const char *a = words[j] + 1; const char *b = s; while (*a && *a == *b) { a++; b++; } if (!*a) return true; j++; } } return false; } /** similar to InListAbbreviated, but word s can be a abridged version of a keyword. * eg. the keyword is defined as "after.~:". This means the word must have a prefix (begins with) of * "after." and suffix (ends with) of ":" to be a keyword, Hence "after.field:" , "after.form.item:" are valid. * Similarly "~.is.valid" keyword is suffix only... hence "field.is.valid" , "form.is.valid" are valid. * The marker is ~ in this case. * No multiple markers check is done and wont work. */ bool WordList::InListAbridged(const char *s, const char marker) const { if (0 == words) return false; const unsigned char firstChar = s[0]; int j = starts[firstChar]; if (j >= 0) { while (words[j][0] == firstChar) { const char *a = words[j]; const char *b = s; while (*a && *a == *b) { a++; if (*a == marker) { a++; const size_t suffixLengthA = strlen(a); const size_t suffixLengthB = strlen(b); if (suffixLengthA >= suffixLengthB) break; b = b + suffixLengthB - suffixLengthA - 1; } b++; } if (!*a && !*b) return true; j++; } } j = starts[static_cast(marker)]; if (j >= 0) { while (words[j][0] == marker) { const char *a = words[j] + 1; const char *b = s; const size_t suffixLengthA = strlen(a); const size_t suffixLengthB = strlen(b); if (suffixLengthA > suffixLengthB) { j++; continue; } b = b + suffixLengthB - suffixLengthA; while (*a && *a == *b) { a++; b++; } if (!*a && !*b) return true; j++; } } return false; } const char *WordList::WordAt(int n) const { return words[n]; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/lexlib/WordList.h000066400000000000000000000017051463772530400261720ustar00rootroot00000000000000// Scintilla source code edit control /** @file WordList.h ** Hold a list of words. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef WORDLIST_H #define WORDLIST_H namespace Scintilla { /** */ class WordList { // Each word contains at least one character - a empty word acts as sentinel at the end. char **words; char *list; int len; bool onlyLineEnds; ///< Delimited by any white space or only line ends int starts[256]; public: explicit WordList(bool onlyLineEnds_ = false); ~WordList(); operator bool() const; bool operator!=(const WordList &other) const; int Length() const; void Clear(); void Set(const char *s); bool InList(const char *s) const; bool InListAbbreviated(const char *s, const char marker) const; bool InListAbridged(const char *s, const char marker) const; const char *WordAt(int n) const; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/000077500000000000000000000000001463772530400235575ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/AutoComplete.cpp000066400000000000000000000162361463772530400266740ustar00rootroot00000000000000// Scintilla source code edit control /** @file AutoComplete.cxx ** Defines the auto completion list box. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "CharacterSet.h" #include "Position.h" #include "AutoComplete.h" using namespace Scintilla; AutoComplete::AutoComplete() : active(false), separator(' '), typesep('?'), ignoreCase(false), chooseSingle(false), posStart(0), startLen(0), cancelAtStartPos(true), autoHide(true), dropRestOfWord(false), ignoreCaseBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE), widthLBDefault(100), heightLBDefault(100), autoSort(SC_ORDER_PRESORTED) { lb.reset(ListBox::Allocate()); } AutoComplete::~AutoComplete() { if (lb) { lb->Destroy(); } } bool AutoComplete::Active() const noexcept { return active; } void AutoComplete::Start(Window &parent, int ctrlID, Sci::Position position, Point location, Sci::Position startLen_, int lineHeight, bool unicodeMode, int technology) { if (active) { Cancel(); } lb->Create(parent, ctrlID, location, lineHeight, unicodeMode, technology); lb->Clear(); active = true; startLen = startLen_; posStart = position; } void AutoComplete::SetStopChars(const char *stopChars_) { stopChars = stopChars_; } bool AutoComplete::IsStopChar(char ch) const noexcept { return ch && (stopChars.find(ch) != std::string::npos); } void AutoComplete::SetFillUpChars(const char *fillUpChars_) { fillUpChars = fillUpChars_; } bool AutoComplete::IsFillUpChar(char ch) const noexcept { return ch && (fillUpChars.find(ch) != std::string::npos); } void AutoComplete::SetSeparator(char separator_) { separator = separator_; } char AutoComplete::GetSeparator() const noexcept { return separator; } void AutoComplete::SetTypesep(char separator_) { typesep = separator_; } char AutoComplete::GetTypesep() const noexcept { return typesep; } struct Sorter { AutoComplete *ac; const char *list; std::vector indices; Sorter(AutoComplete *ac_, const char *list_) : ac(ac_), list(list_) { int i = 0; while (list[i]) { indices.push_back(i); // word start while (list[i] != ac->GetTypesep() && list[i] != ac->GetSeparator() && list[i]) ++i; indices.push_back(i); // word end if (list[i] == ac->GetTypesep()) { while (list[i] != ac->GetSeparator() && list[i]) ++i; } if (list[i] == ac->GetSeparator()) { ++i; // preserve trailing separator as blank entry if (!list[i]) { indices.push_back(i); indices.push_back(i); } } } indices.push_back(i); // index of last position } bool operator()(int a, int b) { const int lenA = indices[a * 2 + 1] - indices[a * 2]; const int lenB = indices[b * 2 + 1] - indices[b * 2]; const int len = std::min(lenA, lenB); int cmp; if (ac->ignoreCase) cmp = CompareNCaseInsensitive(list + indices[a * 2], list + indices[b * 2], len); else cmp = strncmp(list + indices[a * 2], list + indices[b * 2], len); if (cmp == 0) cmp = lenA - lenB; return cmp < 0; } }; void AutoComplete::SetList(const char *list) { if (autoSort == SC_ORDER_PRESORTED) { lb->SetList(list, separator, typesep); sortMatrix.clear(); for (int i = 0; i < lb->Length(); ++i) sortMatrix.push_back(i); return; } Sorter IndexSort(this, list); sortMatrix.clear(); for (int i = 0; i < static_cast(IndexSort.indices.size()) / 2; ++i) sortMatrix.push_back(i); std::sort(sortMatrix.begin(), sortMatrix.end(), IndexSort); if (autoSort == SC_ORDER_CUSTOM || sortMatrix.size() < 2) { lb->SetList(list, separator, typesep); PLATFORM_ASSERT(lb->Length() == static_cast(sortMatrix.size())); return; } std::string sortedList; char item[maxItemLen]; for (size_t i = 0; i < sortMatrix.size(); ++i) { int wordLen = IndexSort.indices[sortMatrix[i] * 2 + 2] - IndexSort.indices[sortMatrix[i] * 2]; if (wordLen > maxItemLen-2) wordLen = maxItemLen - 2; memcpy(item, list + IndexSort.indices[sortMatrix[i] * 2], wordLen); if ((i+1) == sortMatrix.size()) { // Last item so remove separator if present if ((wordLen > 0) && (item[wordLen-1] == separator)) wordLen--; } else { // Item before last needs a separator if ((wordLen == 0) || (item[wordLen-1] != separator)) { item[wordLen] = separator; wordLen++; } } item[wordLen] = '\0'; sortedList += item; } for (int i = 0; i < static_cast(sortMatrix.size()); ++i) sortMatrix[i] = i; lb->SetList(sortedList.c_str(), separator, typesep); } int AutoComplete::GetSelection() const { return lb->GetSelection(); } std::string AutoComplete::GetValue(int item) const { char value[maxItemLen]; lb->GetValue(item, value, sizeof(value)); return std::string(value); } void AutoComplete::Show(bool show) { lb->Show(show); if (show) lb->Select(0); } void AutoComplete::Cancel() { if (lb->Created()) { lb->Clear(); lb->Destroy(); active = false; } } void AutoComplete::Move(int delta) { const int count = lb->Length(); int current = lb->GetSelection(); current += delta; if (current >= count) current = count - 1; if (current < 0) current = 0; lb->Select(current); } void AutoComplete::Select(const char *word) { const size_t lenWord = strlen(word); int location = -1; int start = 0; // lower bound of the api array block to search int end = lb->Length() - 1; // upper bound of the api array block to search while ((start <= end) && (location == -1)) { // Binary searching loop int pivot = (start + end) / 2; char item[maxItemLen]; lb->GetValue(sortMatrix[pivot], item, maxItemLen); int cond; if (ignoreCase) cond = CompareNCaseInsensitive(word, item, lenWord); else cond = strncmp(word, item, lenWord); if (!cond) { // Find first match while (pivot > start) { lb->GetValue(sortMatrix[pivot-1], item, maxItemLen); if (ignoreCase) cond = CompareNCaseInsensitive(word, item, lenWord); else cond = strncmp(word, item, lenWord); if (0 != cond) break; --pivot; } location = pivot; if (ignoreCase && ignoreCaseBehaviour == SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) { // Check for exact-case match for (; pivot <= end; pivot++) { lb->GetValue(sortMatrix[pivot], item, maxItemLen); if (!strncmp(word, item, lenWord)) { location = pivot; break; } if (CompareNCaseInsensitive(word, item, lenWord)) break; } } } else if (cond < 0) { end = pivot - 1; } else if (cond > 0) { start = pivot + 1; } } if (location == -1) { if (autoHide) Cancel(); else lb->Select(-1); } else { if (autoSort == SC_ORDER_CUSTOM) { // Check for a logically earlier match char item[maxItemLen]; for (int i = location + 1; i <= end; ++i) { lb->GetValue(sortMatrix[i], item, maxItemLen); if (CompareNCaseInsensitive(word, item, lenWord)) break; if (sortMatrix[i] < sortMatrix[location] && !strncmp(word, item, lenWord)) location = i; } } lb->Select(sortMatrix[location]); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/AutoComplete.h000066400000000000000000000053421463772530400263350ustar00rootroot00000000000000// Scintilla source code edit control /** @file AutoComplete.h ** Defines the auto completion list box. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef AUTOCOMPLETE_H #define AUTOCOMPLETE_H namespace Scintilla { /** */ class AutoComplete { bool active; std::string stopChars; std::string fillUpChars; char separator; char typesep; // Type seperator enum { maxItemLen=1000 }; std::vector sortMatrix; public: bool ignoreCase; bool chooseSingle; std::unique_ptr lb; Sci::Position posStart; Sci::Position startLen; /// Should autocompletion be canceled if editor's currentPos <= startPos? bool cancelAtStartPos; bool autoHide; bool dropRestOfWord; unsigned int ignoreCaseBehaviour; int widthLBDefault; int heightLBDefault; /** SC_ORDER_PRESORTED: Assume the list is presorted; selection will fail if it is not alphabetical
* SC_ORDER_PERFORMSORT: Sort the list alphabetically; start up performance cost for sorting
* SC_ORDER_CUSTOM: Handle non-alphabetical entries; start up performance cost for generating a sorted lookup table */ int autoSort; AutoComplete(); ~AutoComplete(); /// Is the auto completion list displayed? bool Active() const noexcept; /// Display the auto completion list positioned to be near a character position void Start(Window &parent, int ctrlID, Sci::Position position, Point location, Sci::Position startLen_, int lineHeight, bool unicodeMode, int technology); /// The stop chars are characters which, when typed, cause the auto completion list to disappear void SetStopChars(const char *stopChars_); bool IsStopChar(char ch) const noexcept; /// The fillup chars are characters which, when typed, fill up the selected word void SetFillUpChars(const char *fillUpChars_); bool IsFillUpChar(char ch) const noexcept; /// The separator character is used when interpreting the list in SetList void SetSeparator(char separator_); char GetSeparator() const noexcept; /// The typesep character is used for separating the word from the type void SetTypesep(char separator_); char GetTypesep() const noexcept; /// The list string contains a sequence of words separated by the separator character void SetList(const char *list); /// Return the position of the currently selected list item int GetSelection() const; /// Return the value of an item in the list std::string GetValue(int item) const; void Show(bool show); void Cancel(); /// Move the current list element by delta, scrolling appropriately void Move(int delta); /// Select a list element that starts with word as the current element void Select(const char *word); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CallTip.cpp000066400000000000000000000262021463772530400256150ustar00rootroot00000000000000// Scintilla source code edit control /** @file CallTip.cxx ** Code for displaying call tips. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "StringCopy.h" #include "Position.h" #include "IntegerRectangle.h" #include "CallTip.h" using namespace Scintilla; CallTip::CallTip() { wCallTip = 0; inCallTipMode = false; posStartCallTip = 0; rectUp = PRectangle(0,0,0,0); rectDown = PRectangle(0,0,0,0); lineHeight = 1; offsetMain = 0; startHighlight = 0; endHighlight = 0; tabSize = 0; above = false; useStyleCallTip = false; // for backwards compatibility insetX = 5; widthArrow = 14; borderHeight = 2; // Extra line for border and an empty line at top and bottom. verticalOffset = 1; #ifdef __APPLE__ // proper apple colours for the default colourBG = ColourDesired(0xff, 0xff, 0xc6); colourUnSel = ColourDesired(0, 0, 0); #else colourBG = ColourDesired(0xff, 0xff, 0xff); colourUnSel = ColourDesired(0x80, 0x80, 0x80); #endif colourSel = ColourDesired(0, 0, 0x80); colourShade = ColourDesired(0, 0, 0); colourLight = ColourDesired(0xc0, 0xc0, 0xc0); codePage = 0; clickPlace = 0; } CallTip::~CallTip() { font.Release(); wCallTip.Destroy(); } // Although this test includes 0, we should never see a \0 character. static bool IsArrowCharacter(char ch) { return (ch == 0) || (ch == '\001') || (ch == '\002'); } // We ignore tabs unless a tab width has been set. bool CallTip::IsTabCharacter(char ch) const { return (tabSize > 0) && (ch == '\t'); } int CallTip::NextTabPos(int x) const { if (tabSize > 0) { // paranoia... not called unless this is true x -= insetX; // position relative to text x = (x + tabSize) / tabSize; // tab "number" return tabSize*x + insetX; // position of next tab } else { return x + 1; // arbitrary } } // Draw a section of the call tip that does not include \n in one colour. // The text may include up to numEnds tabs or arrow characters. void CallTip::DrawChunk(Surface *surface, int &x, const char *s, int posStart, int posEnd, int ytext, PRectangle rcClient, bool highlight, bool draw) { s += posStart; const int len = posEnd - posStart; // Divide the text into sections that are all text, or that are // single arrows or single tab characters (if tabSize > 0). int maxEnd = 0; const int numEnds = 10; int ends[numEnds + 2]; for (int i=0; i 0) ends[maxEnd++] = i; ends[maxEnd++] = i+1; } } ends[maxEnd++] = len; int startSeg = 0; int xEnd; for (int seg = 0; seg startSeg) { if (IsArrowCharacter(s[startSeg])) { xEnd = x + widthArrow; const bool upArrow = s[startSeg] == '\001'; rcClient.left = static_cast(x); rcClient.right = static_cast(xEnd); if (draw) { const int halfWidth = widthArrow / 2 - 3; const int quarterWidth = halfWidth / 2; const int centreX = x + widthArrow / 2 - 1; const int centreY = static_cast(rcClient.top + rcClient.bottom) / 2; surface->FillRectangle(rcClient, colourBG); const PRectangle rcClientInner(rcClient.left + 1, rcClient.top + 1, rcClient.right - 2, rcClient.bottom - 1); surface->FillRectangle(rcClientInner, colourUnSel); if (upArrow) { // Up arrow Point pts[] = { Point::FromInts(centreX - halfWidth, centreY + quarterWidth), Point::FromInts(centreX + halfWidth, centreY + quarterWidth), Point::FromInts(centreX, centreY - halfWidth + quarterWidth), }; surface->Polygon(pts, ELEMENTS(pts), colourBG, colourBG); } else { // Down arrow Point pts[] = { Point::FromInts(centreX - halfWidth, centreY - quarterWidth), Point::FromInts(centreX + halfWidth, centreY - quarterWidth), Point::FromInts(centreX, centreY + halfWidth - quarterWidth), }; surface->Polygon(pts, ELEMENTS(pts), colourBG, colourBG); } } offsetMain = xEnd; if (upArrow) { rectUp = rcClient; } else { rectDown = rcClient; } } else if (IsTabCharacter(s[startSeg])) { xEnd = NextTabPos(x); } else { xEnd = x + static_cast(lround(surface->WidthText(font, s + startSeg, endSeg - startSeg))); if (draw) { rcClient.left = static_cast(x); rcClient.right = static_cast(xEnd); surface->DrawTextTransparent(rcClient, font, static_cast(ytext), s+startSeg, endSeg - startSeg, highlight ? colourSel : colourUnSel); } } x = xEnd; startSeg = endSeg; } } } int CallTip::PaintContents(Surface *surfaceWindow, bool draw) { const PRectangle rcClientPos = wCallTip.GetClientPosition(); const PRectangle rcClientSize(0.0f, 0.0f, rcClientPos.right - rcClientPos.left, rcClientPos.bottom - rcClientPos.top); PRectangle rcClient(1.0f, 1.0f, rcClientSize.right - 1, rcClientSize.bottom - 1); // To make a nice small call tip window, it is only sized to fit most normal characters without accents const int ascent = static_cast(lround(surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font))); // For each line... // Draw the definition in three parts: before highlight, highlighted, after highlight int ytext = static_cast(rcClient.top) + ascent + 1; rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1; const char *chunkVal = val.c_str(); bool moreChunks = true; int maxWidth = 0; while (moreChunks) { const char *chunkEnd = strchr(chunkVal, '\n'); if (!chunkEnd) { chunkEnd = chunkVal + strlen(chunkVal); moreChunks = false; } const int chunkOffset = static_cast(chunkVal - val.c_str()); const int chunkLength = static_cast(chunkEnd - chunkVal); const int chunkEndOffset = chunkOffset + chunkLength; int thisStartHighlight = std::max(startHighlight, chunkOffset); thisStartHighlight = std::min(thisStartHighlight, chunkEndOffset); thisStartHighlight -= chunkOffset; int thisEndHighlight = std::max(endHighlight, chunkOffset); thisEndHighlight = std::min(thisEndHighlight, chunkEndOffset); thisEndHighlight -= chunkOffset; rcClient.top = static_cast(ytext - ascent - 1); int x = insetX; // start each line at this inset DrawChunk(surfaceWindow, x, chunkVal, 0, thisStartHighlight, ytext, rcClient, false, draw); DrawChunk(surfaceWindow, x, chunkVal, thisStartHighlight, thisEndHighlight, ytext, rcClient, true, draw); DrawChunk(surfaceWindow, x, chunkVal, thisEndHighlight, chunkLength, ytext, rcClient, false, draw); chunkVal = chunkEnd + 1; ytext += lineHeight; rcClient.bottom += lineHeight; maxWidth = std::max(maxWidth, x); } return maxWidth; } void CallTip::PaintCT(Surface *surfaceWindow) { if (val.empty()) return; const PRectangle rcClientPos = wCallTip.GetClientPosition(); const PRectangle rcClientSize(0.0f, 0.0f, rcClientPos.right - rcClientPos.left, rcClientPos.bottom - rcClientPos.top); const PRectangle rcClient(1.0f, 1.0f, rcClientSize.right - 1, rcClientSize.bottom - 1); surfaceWindow->FillRectangle(rcClient, colourBG); offsetMain = insetX; // initial alignment assuming no arrows PaintContents(surfaceWindow, true); #ifndef __APPLE__ // OSX doesn't put borders on "help tags" // Draw a raised border around the edges of the window const IntegerRectangle ircClientSize(rcClientSize); surfaceWindow->MoveTo(0, ircClientSize.bottom - 1); surfaceWindow->PenColour(colourShade); surfaceWindow->LineTo(ircClientSize.right - 1, ircClientSize.bottom - 1); surfaceWindow->LineTo(ircClientSize.right - 1, 0); surfaceWindow->PenColour(colourLight); surfaceWindow->LineTo(0, 0); surfaceWindow->LineTo(0, ircClientSize.bottom - 1); #endif } void CallTip::MouseClick(Point pt) { clickPlace = 0; if (rectUp.Contains(pt)) clickPlace = 1; if (rectDown.Contains(pt)) clickPlace = 2; } PRectangle CallTip::CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn, const char *faceName, int size, int codePage_, int characterSet, int technology, const Window &wParent) { clickPlace = 0; val = defn; codePage = codePage_; std::unique_ptr surfaceMeasure(Surface::Allocate(technology)); surfaceMeasure->Init(wParent.GetID()); surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage); surfaceMeasure->SetDBCSMode(codePage); startHighlight = 0; endHighlight = 0; inCallTipMode = true; posStartCallTip = pos; const XYPOSITION deviceHeight = static_cast(surfaceMeasure->DeviceHeightFont(size)); const FontParameters fp(faceName, deviceHeight / SC_FONT_SIZE_MULTIPLIER, SC_WEIGHT_NORMAL, false, 0, technology, characterSet); font.Create(fp); // Look for multiple lines in the text // Only support \n here - simply means container must avoid \r! const int numLines = 1 + static_cast(std::count(val.begin(), val.end(), '\n')); rectUp = PRectangle(0,0,0,0); rectDown = PRectangle(0,0,0,0); offsetMain = insetX; // changed to right edge of any arrows const int width = PaintContents(surfaceMeasure.get(), false) + insetX; lineHeight = static_cast(lround(surfaceMeasure->Height(font))); // The returned // rectangle is aligned to the right edge of the last arrow encountered in // the tip text, else to the tip text left edge. const int height = lineHeight * numLines - static_cast(surfaceMeasure->InternalLeading(font)) + borderHeight * 2; if (above) { return PRectangle(pt.x - offsetMain, pt.y - verticalOffset - height, pt.x + width - offsetMain, pt.y - verticalOffset); } else { return PRectangle(pt.x - offsetMain, pt.y + verticalOffset + textHeight, pt.x + width - offsetMain, pt.y + verticalOffset + textHeight + height); } } void CallTip::CallTipCancel() { inCallTipMode = false; if (wCallTip.Created()) { wCallTip.Destroy(); } } void CallTip::SetHighlight(int start, int end) { // Avoid flashing by checking something has really changed if ((start != startHighlight) || (end != endHighlight)) { startHighlight = start; endHighlight = (end > start) ? end : start; if (wCallTip.Created()) { wCallTip.InvalidateAll(); } } } // Set the tab size (sizes > 0 enable the use of tabs). This also enables the // use of the STYLE_CALLTIP. void CallTip::SetTabSize(int tabSz) { tabSize = tabSz; useStyleCallTip = true; } // Set the calltip position, below the text by default or if above is false // else above the text. void CallTip::SetPosition(bool aboveText) { above = aboveText; } // It might be better to have two access functions for this and to use // them for all settings of colours. void CallTip::SetForeBack(const ColourDesired &fore, const ColourDesired &back) { colourBG = back; colourUnSel = fore; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CallTip.h000066400000000000000000000054051463772530400252640ustar00rootroot00000000000000// Scintilla source code edit control /** @file CallTip.h ** Interface to the call tip control. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CALLTIP_H #define CALLTIP_H namespace Scintilla { /** */ class CallTip { int startHighlight; // character offset to start and... int endHighlight; // ...end of highlighted text std::string val; Font font; PRectangle rectUp; // rectangle of last up angle in the tip PRectangle rectDown; // rectangle of last down arrow in the tip int lineHeight; // vertical line spacing int offsetMain; // The alignment point of the call tip int tabSize; // Tab size in pixels, <=0 no TAB expand bool useStyleCallTip; // if true, STYLE_CALLTIP should be used bool above; // if true, display calltip above text void DrawChunk(Surface *surface, int &x, const char *s, int posStart, int posEnd, int ytext, PRectangle rcClient, bool highlight, bool draw); int PaintContents(Surface *surfaceWindow, bool draw); bool IsTabCharacter(char ch) const; int NextTabPos(int x) const; public: Window wCallTip; Window wDraw; bool inCallTipMode; Sci::Position posStartCallTip; ColourDesired colourBG; ColourDesired colourUnSel; ColourDesired colourSel; ColourDesired colourShade; ColourDesired colourLight; int codePage; int clickPlace; int insetX; // text inset in x from calltip border int widthArrow; int borderHeight; int verticalOffset; // pixel offset up or down of the calltip with respect to the line CallTip(); // Deleted so CallTip objects can not be copied. CallTip(const CallTip &) = delete; CallTip(CallTip &&) = delete; CallTip &operator=(const CallTip &) = delete; CallTip &operator=(CallTip &&) = delete; ~CallTip(); void PaintCT(Surface *surfaceWindow); void MouseClick(Point pt); /// Setup the calltip and return a rectangle of the area required. PRectangle CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn, const char *faceName, int size, int codePage_, int characterSet, int technology, const Window &wParent); void CallTipCancel(); /// Set a range of characters to be displayed in a highlight style. /// Commonly used to highlight the current parameter. void SetHighlight(int start, int end); /// Set the tab size in pixels for the call tip. 0 or -ve means no tab expand. void SetTabSize(int tabSz); /// Set calltip position. void SetPosition(bool aboveText); /// Used to determine which STYLE_xxxx to use for call tip information bool UseStyleCallTip() const { return useStyleCallTip;} // Modify foreground and background colours void SetForeBack(const ColourDesired &fore, const ColourDesired &back); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CaseConvert.cpp000066400000000000000000000611561463772530400265100ustar00rootroot00000000000000// Scintilla source code edit control // Encoding: UTF-8 /** @file CaseConvert.cxx ** Case fold characters and convert them to upper or lower case. ** Tables automatically regenerated by scripts/GenerateCaseConvert.py ** Should only be rarely regenerated for new versions of Unicode. **/ // Copyright 2013 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "StringCopy.h" #include "CaseConvert.h" #include "UniConversion.h" using namespace Scintilla; namespace { // Use an unnamed namespace to protect the declarations from name conflicts // Unicode code points are ordered by groups and follow patterns. // Most characters (pitch==1) are in ranges for a particular alphabet and their // upper case forms are a fixed distance away. // Another pattern (pitch==2) is where each lower case letter is preceded by // the upper case form. These are also grouped into ranges. int symmetricCaseConversionRanges[] = { //lower, upper, range length, range pitch //++Autogenerated -- start of section automatically generated //**\(\*\n\) 97,65,26,1, 224,192,23,1, 248,216,7,1, 257,256,24,2, 314,313,8,2, 331,330,23,2, 462,461,8,2, 479,478,9,2, 505,504,20,2, 547,546,9,2, 583,582,5,2, 945,913,17,1, 963,931,9,1, 985,984,12,2, 1072,1040,32,1, 1104,1024,16,1, 1121,1120,17,2, 1163,1162,27,2, 1218,1217,7,2, 1233,1232,48,2, 1377,1329,38,1, 4304,7312,43,1, 7681,7680,75,2, 7841,7840,48,2, 7936,7944,8,1, 7952,7960,6,1, 7968,7976,8,1, 7984,7992,8,1, 8000,8008,6,1, 8032,8040,8,1, 8560,8544,16,1, 9424,9398,26,1, 11312,11264,47,1, 11393,11392,50,2, 11520,4256,38,1, 42561,42560,23,2, 42625,42624,14,2, 42787,42786,7,2, 42803,42802,31,2, 42879,42878,5,2, 42903,42902,10,2, 65345,65313,26,1, 66600,66560,40,1, 66776,66736,36,1, 68800,68736,51,1, 71872,71840,32,1, 93792,93760,32,1, 125218,125184,34,1, //--Autogenerated -- end of section automatically generated }; // Code points that are symmetric but don't fit into a range of similar characters // are listed here. int symmetricCaseConversions[] = { //lower, upper //++Autogenerated -- start of section automatically generated //**1 \(\*\n\) 255,376, 307,306, 309,308, 311,310, 378,377, 380,379, 382,381, 384,579, 387,386, 389,388, 392,391, 396,395, 402,401, 405,502, 409,408, 410,573, 414,544, 417,416, 419,418, 421,420, 424,423, 429,428, 432,431, 436,435, 438,437, 441,440, 445,444, 447,503, 454,452, 457,455, 460,458, 477,398, 499,497, 501,500, 572,571, 575,11390, 576,11391, 578,577, 592,11375, 593,11373, 594,11376, 595,385, 596,390, 598,393, 599,394, 601,399, 603,400, 604,42923, 608,403, 609,42924, 611,404, 613,42893, 614,42922, 616,407, 617,406, 618,42926, 619,11362, 620,42925, 623,412, 625,11374, 626,413, 629,415, 637,11364, 640,422, 643,425, 647,42929, 648,430, 649,580, 650,433, 651,434, 652,581, 658,439, 669,42930, 670,42928, 881,880, 883,882, 887,886, 891,1021, 892,1022, 893,1023, 940,902, 941,904, 942,905, 943,906, 972,908, 973,910, 974,911, 983,975, 1010,1017, 1011,895, 1016,1015, 1019,1018, 1231,1216, 4349,7357, 4350,7358, 4351,7359, 7545,42877, 7549,11363, 8017,8025, 8019,8027, 8021,8029, 8023,8031, 8048,8122, 8049,8123, 8050,8136, 8051,8137, 8052,8138, 8053,8139, 8054,8154, 8055,8155, 8056,8184, 8057,8185, 8058,8170, 8059,8171, 8060,8186, 8061,8187, 8112,8120, 8113,8121, 8144,8152, 8145,8153, 8160,8168, 8161,8169, 8165,8172, 8526,8498, 8580,8579, 11361,11360, 11365,570, 11366,574, 11368,11367, 11370,11369, 11372,11371, 11379,11378, 11382,11381, 11500,11499, 11502,11501, 11507,11506, 11559,4295, 11565,4301, 42874,42873, 42876,42875, 42892,42891, 42897,42896, 42899,42898, 42933,42932, 42935,42934, 42937,42936, 43859,42931, //--Autogenerated -- end of section automatically generated }; // Characters that have complex case conversions are listed here. // This includes cases where more than one character is needed for a conversion, // folding is different to lowering, or (as appropriate) upper(lower(x)) != x or // lower(upper(x)) != x. const char *complexCaseConversions = // Original | Folded | Upper | Lower | //++Autogenerated -- start of section automatically generated //**2 \(\*\n\) "\xc2\xb5|\xce\xbc|\xce\x9c||" "\xc3\x9f|ss|SS||" "\xc4\xb0|i\xcc\x87||i\xcc\x87|" "\xc4\xb1||I||" "\xc5\x89|\xca\xbcn|\xca\xbcN||" "\xc5\xbf|s|S||" "\xc7\x85|\xc7\x86|\xc7\x84|\xc7\x86|" "\xc7\x88|\xc7\x89|\xc7\x87|\xc7\x89|" "\xc7\x8b|\xc7\x8c|\xc7\x8a|\xc7\x8c|" "\xc7\xb0|j\xcc\x8c|J\xcc\x8c||" "\xc7\xb2|\xc7\xb3|\xc7\xb1|\xc7\xb3|" "\xcd\x85|\xce\xb9|\xce\x99||" "\xce\x90|\xce\xb9\xcc\x88\xcc\x81|\xce\x99\xcc\x88\xcc\x81||" "\xce\xb0|\xcf\x85\xcc\x88\xcc\x81|\xce\xa5\xcc\x88\xcc\x81||" "\xcf\x82|\xcf\x83|\xce\xa3||" "\xcf\x90|\xce\xb2|\xce\x92||" "\xcf\x91|\xce\xb8|\xce\x98||" "\xcf\x95|\xcf\x86|\xce\xa6||" "\xcf\x96|\xcf\x80|\xce\xa0||" "\xcf\xb0|\xce\xba|\xce\x9a||" "\xcf\xb1|\xcf\x81|\xce\xa1||" "\xcf\xb4|\xce\xb8||\xce\xb8|" "\xcf\xb5|\xce\xb5|\xce\x95||" "\xd6\x87|\xd5\xa5\xd6\x82|\xd4\xb5\xd5\x92||" "\xe1\x8e\xa0|||\xea\xad\xb0|" "\xe1\x8e\xa1|||\xea\xad\xb1|" "\xe1\x8e\xa2|||\xea\xad\xb2|" "\xe1\x8e\xa3|||\xea\xad\xb3|" "\xe1\x8e\xa4|||\xea\xad\xb4|" "\xe1\x8e\xa5|||\xea\xad\xb5|" "\xe1\x8e\xa6|||\xea\xad\xb6|" "\xe1\x8e\xa7|||\xea\xad\xb7|" "\xe1\x8e\xa8|||\xea\xad\xb8|" "\xe1\x8e\xa9|||\xea\xad\xb9|" "\xe1\x8e\xaa|||\xea\xad\xba|" "\xe1\x8e\xab|||\xea\xad\xbb|" "\xe1\x8e\xac|||\xea\xad\xbc|" "\xe1\x8e\xad|||\xea\xad\xbd|" "\xe1\x8e\xae|||\xea\xad\xbe|" "\xe1\x8e\xaf|||\xea\xad\xbf|" "\xe1\x8e\xb0|||\xea\xae\x80|" "\xe1\x8e\xb1|||\xea\xae\x81|" "\xe1\x8e\xb2|||\xea\xae\x82|" "\xe1\x8e\xb3|||\xea\xae\x83|" "\xe1\x8e\xb4|||\xea\xae\x84|" "\xe1\x8e\xb5|||\xea\xae\x85|" "\xe1\x8e\xb6|||\xea\xae\x86|" "\xe1\x8e\xb7|||\xea\xae\x87|" "\xe1\x8e\xb8|||\xea\xae\x88|" "\xe1\x8e\xb9|||\xea\xae\x89|" "\xe1\x8e\xba|||\xea\xae\x8a|" "\xe1\x8e\xbb|||\xea\xae\x8b|" "\xe1\x8e\xbc|||\xea\xae\x8c|" "\xe1\x8e\xbd|||\xea\xae\x8d|" "\xe1\x8e\xbe|||\xea\xae\x8e|" "\xe1\x8e\xbf|||\xea\xae\x8f|" "\xe1\x8f\x80|||\xea\xae\x90|" "\xe1\x8f\x81|||\xea\xae\x91|" "\xe1\x8f\x82|||\xea\xae\x92|" "\xe1\x8f\x83|||\xea\xae\x93|" "\xe1\x8f\x84|||\xea\xae\x94|" "\xe1\x8f\x85|||\xea\xae\x95|" "\xe1\x8f\x86|||\xea\xae\x96|" "\xe1\x8f\x87|||\xea\xae\x97|" "\xe1\x8f\x88|||\xea\xae\x98|" "\xe1\x8f\x89|||\xea\xae\x99|" "\xe1\x8f\x8a|||\xea\xae\x9a|" "\xe1\x8f\x8b|||\xea\xae\x9b|" "\xe1\x8f\x8c|||\xea\xae\x9c|" "\xe1\x8f\x8d|||\xea\xae\x9d|" "\xe1\x8f\x8e|||\xea\xae\x9e|" "\xe1\x8f\x8f|||\xea\xae\x9f|" "\xe1\x8f\x90|||\xea\xae\xa0|" "\xe1\x8f\x91|||\xea\xae\xa1|" "\xe1\x8f\x92|||\xea\xae\xa2|" "\xe1\x8f\x93|||\xea\xae\xa3|" "\xe1\x8f\x94|||\xea\xae\xa4|" "\xe1\x8f\x95|||\xea\xae\xa5|" "\xe1\x8f\x96|||\xea\xae\xa6|" "\xe1\x8f\x97|||\xea\xae\xa7|" "\xe1\x8f\x98|||\xea\xae\xa8|" "\xe1\x8f\x99|||\xea\xae\xa9|" "\xe1\x8f\x9a|||\xea\xae\xaa|" "\xe1\x8f\x9b|||\xea\xae\xab|" "\xe1\x8f\x9c|||\xea\xae\xac|" "\xe1\x8f\x9d|||\xea\xae\xad|" "\xe1\x8f\x9e|||\xea\xae\xae|" "\xe1\x8f\x9f|||\xea\xae\xaf|" "\xe1\x8f\xa0|||\xea\xae\xb0|" "\xe1\x8f\xa1|||\xea\xae\xb1|" "\xe1\x8f\xa2|||\xea\xae\xb2|" "\xe1\x8f\xa3|||\xea\xae\xb3|" "\xe1\x8f\xa4|||\xea\xae\xb4|" "\xe1\x8f\xa5|||\xea\xae\xb5|" "\xe1\x8f\xa6|||\xea\xae\xb6|" "\xe1\x8f\xa7|||\xea\xae\xb7|" "\xe1\x8f\xa8|||\xea\xae\xb8|" "\xe1\x8f\xa9|||\xea\xae\xb9|" "\xe1\x8f\xaa|||\xea\xae\xba|" "\xe1\x8f\xab|||\xea\xae\xbb|" "\xe1\x8f\xac|||\xea\xae\xbc|" "\xe1\x8f\xad|||\xea\xae\xbd|" "\xe1\x8f\xae|||\xea\xae\xbe|" "\xe1\x8f\xaf|||\xea\xae\xbf|" "\xe1\x8f\xb0|||\xe1\x8f\xb8|" "\xe1\x8f\xb1|||\xe1\x8f\xb9|" "\xe1\x8f\xb2|||\xe1\x8f\xba|" "\xe1\x8f\xb3|||\xe1\x8f\xbb|" "\xe1\x8f\xb4|||\xe1\x8f\xbc|" "\xe1\x8f\xb5|||\xe1\x8f\xbd|" "\xe1\x8f\xb8|\xe1\x8f\xb0|\xe1\x8f\xb0||" "\xe1\x8f\xb9|\xe1\x8f\xb1|\xe1\x8f\xb1||" "\xe1\x8f\xba|\xe1\x8f\xb2|\xe1\x8f\xb2||" "\xe1\x8f\xbb|\xe1\x8f\xb3|\xe1\x8f\xb3||" "\xe1\x8f\xbc|\xe1\x8f\xb4|\xe1\x8f\xb4||" "\xe1\x8f\xbd|\xe1\x8f\xb5|\xe1\x8f\xb5||" "\xe1\xb2\x80|\xd0\xb2|\xd0\x92||" "\xe1\xb2\x81|\xd0\xb4|\xd0\x94||" "\xe1\xb2\x82|\xd0\xbe|\xd0\x9e||" "\xe1\xb2\x83|\xd1\x81|\xd0\xa1||" "\xe1\xb2\x84|\xd1\x82|\xd0\xa2||" "\xe1\xb2\x85|\xd1\x82|\xd0\xa2||" "\xe1\xb2\x86|\xd1\x8a|\xd0\xaa||" "\xe1\xb2\x87|\xd1\xa3|\xd1\xa2||" "\xe1\xb2\x88|\xea\x99\x8b|\xea\x99\x8a||" "\xe1\xba\x96|h\xcc\xb1|H\xcc\xb1||" "\xe1\xba\x97|t\xcc\x88|T\xcc\x88||" "\xe1\xba\x98|w\xcc\x8a|W\xcc\x8a||" "\xe1\xba\x99|y\xcc\x8a|Y\xcc\x8a||" "\xe1\xba\x9a|a\xca\xbe|A\xca\xbe||" "\xe1\xba\x9b|\xe1\xb9\xa1|\xe1\xb9\xa0||" "\xe1\xba\x9e|ss||\xc3\x9f|" "\xe1\xbd\x90|\xcf\x85\xcc\x93|\xce\xa5\xcc\x93||" "\xe1\xbd\x92|\xcf\x85\xcc\x93\xcc\x80|\xce\xa5\xcc\x93\xcc\x80||" "\xe1\xbd\x94|\xcf\x85\xcc\x93\xcc\x81|\xce\xa5\xcc\x93\xcc\x81||" "\xe1\xbd\x96|\xcf\x85\xcc\x93\xcd\x82|\xce\xa5\xcc\x93\xcd\x82||" "\xe1\xbe\x80|\xe1\xbc\x80\xce\xb9|\xe1\xbc\x88\xce\x99||" "\xe1\xbe\x81|\xe1\xbc\x81\xce\xb9|\xe1\xbc\x89\xce\x99||" "\xe1\xbe\x82|\xe1\xbc\x82\xce\xb9|\xe1\xbc\x8a\xce\x99||" "\xe1\xbe\x83|\xe1\xbc\x83\xce\xb9|\xe1\xbc\x8b\xce\x99||" "\xe1\xbe\x84|\xe1\xbc\x84\xce\xb9|\xe1\xbc\x8c\xce\x99||" "\xe1\xbe\x85|\xe1\xbc\x85\xce\xb9|\xe1\xbc\x8d\xce\x99||" "\xe1\xbe\x86|\xe1\xbc\x86\xce\xb9|\xe1\xbc\x8e\xce\x99||" "\xe1\xbe\x87|\xe1\xbc\x87\xce\xb9|\xe1\xbc\x8f\xce\x99||" "\xe1\xbe\x88|\xe1\xbc\x80\xce\xb9|\xe1\xbc\x88\xce\x99|\xe1\xbe\x80|" "\xe1\xbe\x89|\xe1\xbc\x81\xce\xb9|\xe1\xbc\x89\xce\x99|\xe1\xbe\x81|" "\xe1\xbe\x8a|\xe1\xbc\x82\xce\xb9|\xe1\xbc\x8a\xce\x99|\xe1\xbe\x82|" "\xe1\xbe\x8b|\xe1\xbc\x83\xce\xb9|\xe1\xbc\x8b\xce\x99|\xe1\xbe\x83|" "\xe1\xbe\x8c|\xe1\xbc\x84\xce\xb9|\xe1\xbc\x8c\xce\x99|\xe1\xbe\x84|" "\xe1\xbe\x8d|\xe1\xbc\x85\xce\xb9|\xe1\xbc\x8d\xce\x99|\xe1\xbe\x85|" "\xe1\xbe\x8e|\xe1\xbc\x86\xce\xb9|\xe1\xbc\x8e\xce\x99|\xe1\xbe\x86|" "\xe1\xbe\x8f|\xe1\xbc\x87\xce\xb9|\xe1\xbc\x8f\xce\x99|\xe1\xbe\x87|" "\xe1\xbe\x90|\xe1\xbc\xa0\xce\xb9|\xe1\xbc\xa8\xce\x99||" "\xe1\xbe\x91|\xe1\xbc\xa1\xce\xb9|\xe1\xbc\xa9\xce\x99||" "\xe1\xbe\x92|\xe1\xbc\xa2\xce\xb9|\xe1\xbc\xaa\xce\x99||" "\xe1\xbe\x93|\xe1\xbc\xa3\xce\xb9|\xe1\xbc\xab\xce\x99||" "\xe1\xbe\x94|\xe1\xbc\xa4\xce\xb9|\xe1\xbc\xac\xce\x99||" "\xe1\xbe\x95|\xe1\xbc\xa5\xce\xb9|\xe1\xbc\xad\xce\x99||" "\xe1\xbe\x96|\xe1\xbc\xa6\xce\xb9|\xe1\xbc\xae\xce\x99||" "\xe1\xbe\x97|\xe1\xbc\xa7\xce\xb9|\xe1\xbc\xaf\xce\x99||" "\xe1\xbe\x98|\xe1\xbc\xa0\xce\xb9|\xe1\xbc\xa8\xce\x99|\xe1\xbe\x90|" "\xe1\xbe\x99|\xe1\xbc\xa1\xce\xb9|\xe1\xbc\xa9\xce\x99|\xe1\xbe\x91|" "\xe1\xbe\x9a|\xe1\xbc\xa2\xce\xb9|\xe1\xbc\xaa\xce\x99|\xe1\xbe\x92|" "\xe1\xbe\x9b|\xe1\xbc\xa3\xce\xb9|\xe1\xbc\xab\xce\x99|\xe1\xbe\x93|" "\xe1\xbe\x9c|\xe1\xbc\xa4\xce\xb9|\xe1\xbc\xac\xce\x99|\xe1\xbe\x94|" "\xe1\xbe\x9d|\xe1\xbc\xa5\xce\xb9|\xe1\xbc\xad\xce\x99|\xe1\xbe\x95|" "\xe1\xbe\x9e|\xe1\xbc\xa6\xce\xb9|\xe1\xbc\xae\xce\x99|\xe1\xbe\x96|" "\xe1\xbe\x9f|\xe1\xbc\xa7\xce\xb9|\xe1\xbc\xaf\xce\x99|\xe1\xbe\x97|" "\xe1\xbe\xa0|\xe1\xbd\xa0\xce\xb9|\xe1\xbd\xa8\xce\x99||" "\xe1\xbe\xa1|\xe1\xbd\xa1\xce\xb9|\xe1\xbd\xa9\xce\x99||" "\xe1\xbe\xa2|\xe1\xbd\xa2\xce\xb9|\xe1\xbd\xaa\xce\x99||" "\xe1\xbe\xa3|\xe1\xbd\xa3\xce\xb9|\xe1\xbd\xab\xce\x99||" "\xe1\xbe\xa4|\xe1\xbd\xa4\xce\xb9|\xe1\xbd\xac\xce\x99||" "\xe1\xbe\xa5|\xe1\xbd\xa5\xce\xb9|\xe1\xbd\xad\xce\x99||" "\xe1\xbe\xa6|\xe1\xbd\xa6\xce\xb9|\xe1\xbd\xae\xce\x99||" "\xe1\xbe\xa7|\xe1\xbd\xa7\xce\xb9|\xe1\xbd\xaf\xce\x99||" "\xe1\xbe\xa8|\xe1\xbd\xa0\xce\xb9|\xe1\xbd\xa8\xce\x99|\xe1\xbe\xa0|" "\xe1\xbe\xa9|\xe1\xbd\xa1\xce\xb9|\xe1\xbd\xa9\xce\x99|\xe1\xbe\xa1|" "\xe1\xbe\xaa|\xe1\xbd\xa2\xce\xb9|\xe1\xbd\xaa\xce\x99|\xe1\xbe\xa2|" "\xe1\xbe\xab|\xe1\xbd\xa3\xce\xb9|\xe1\xbd\xab\xce\x99|\xe1\xbe\xa3|" "\xe1\xbe\xac|\xe1\xbd\xa4\xce\xb9|\xe1\xbd\xac\xce\x99|\xe1\xbe\xa4|" "\xe1\xbe\xad|\xe1\xbd\xa5\xce\xb9|\xe1\xbd\xad\xce\x99|\xe1\xbe\xa5|" "\xe1\xbe\xae|\xe1\xbd\xa6\xce\xb9|\xe1\xbd\xae\xce\x99|\xe1\xbe\xa6|" "\xe1\xbe\xaf|\xe1\xbd\xa7\xce\xb9|\xe1\xbd\xaf\xce\x99|\xe1\xbe\xa7|" "\xe1\xbe\xb2|\xe1\xbd\xb0\xce\xb9|\xe1\xbe\xba\xce\x99||" "\xe1\xbe\xb3|\xce\xb1\xce\xb9|\xce\x91\xce\x99||" "\xe1\xbe\xb4|\xce\xac\xce\xb9|\xce\x86\xce\x99||" "\xe1\xbe\xb6|\xce\xb1\xcd\x82|\xce\x91\xcd\x82||" "\xe1\xbe\xb7|\xce\xb1\xcd\x82\xce\xb9|\xce\x91\xcd\x82\xce\x99||" "\xe1\xbe\xbc|\xce\xb1\xce\xb9|\xce\x91\xce\x99|\xe1\xbe\xb3|" "\xe1\xbe\xbe|\xce\xb9|\xce\x99||" "\xe1\xbf\x82|\xe1\xbd\xb4\xce\xb9|\xe1\xbf\x8a\xce\x99||" "\xe1\xbf\x83|\xce\xb7\xce\xb9|\xce\x97\xce\x99||" "\xe1\xbf\x84|\xce\xae\xce\xb9|\xce\x89\xce\x99||" "\xe1\xbf\x86|\xce\xb7\xcd\x82|\xce\x97\xcd\x82||" "\xe1\xbf\x87|\xce\xb7\xcd\x82\xce\xb9|\xce\x97\xcd\x82\xce\x99||" "\xe1\xbf\x8c|\xce\xb7\xce\xb9|\xce\x97\xce\x99|\xe1\xbf\x83|" "\xe1\xbf\x92|\xce\xb9\xcc\x88\xcc\x80|\xce\x99\xcc\x88\xcc\x80||" "\xe1\xbf\x93|\xce\xb9\xcc\x88\xcc\x81|\xce\x99\xcc\x88\xcc\x81||" "\xe1\xbf\x96|\xce\xb9\xcd\x82|\xce\x99\xcd\x82||" "\xe1\xbf\x97|\xce\xb9\xcc\x88\xcd\x82|\xce\x99\xcc\x88\xcd\x82||" "\xe1\xbf\xa2|\xcf\x85\xcc\x88\xcc\x80|\xce\xa5\xcc\x88\xcc\x80||" "\xe1\xbf\xa3|\xcf\x85\xcc\x88\xcc\x81|\xce\xa5\xcc\x88\xcc\x81||" "\xe1\xbf\xa4|\xcf\x81\xcc\x93|\xce\xa1\xcc\x93||" "\xe1\xbf\xa6|\xcf\x85\xcd\x82|\xce\xa5\xcd\x82||" "\xe1\xbf\xa7|\xcf\x85\xcc\x88\xcd\x82|\xce\xa5\xcc\x88\xcd\x82||" "\xe1\xbf\xb2|\xe1\xbd\xbc\xce\xb9|\xe1\xbf\xba\xce\x99||" "\xe1\xbf\xb3|\xcf\x89\xce\xb9|\xce\xa9\xce\x99||" "\xe1\xbf\xb4|\xcf\x8e\xce\xb9|\xce\x8f\xce\x99||" "\xe1\xbf\xb6|\xcf\x89\xcd\x82|\xce\xa9\xcd\x82||" "\xe1\xbf\xb7|\xcf\x89\xcd\x82\xce\xb9|\xce\xa9\xcd\x82\xce\x99||" "\xe1\xbf\xbc|\xcf\x89\xce\xb9|\xce\xa9\xce\x99|\xe1\xbf\xb3|" "\xe2\x84\xa6|\xcf\x89||\xcf\x89|" "\xe2\x84\xaa|k||k|" "\xe2\x84\xab|\xc3\xa5||\xc3\xa5|" "\xea\xad\xb0|\xe1\x8e\xa0|\xe1\x8e\xa0||" "\xea\xad\xb1|\xe1\x8e\xa1|\xe1\x8e\xa1||" "\xea\xad\xb2|\xe1\x8e\xa2|\xe1\x8e\xa2||" "\xea\xad\xb3|\xe1\x8e\xa3|\xe1\x8e\xa3||" "\xea\xad\xb4|\xe1\x8e\xa4|\xe1\x8e\xa4||" "\xea\xad\xb5|\xe1\x8e\xa5|\xe1\x8e\xa5||" "\xea\xad\xb6|\xe1\x8e\xa6|\xe1\x8e\xa6||" "\xea\xad\xb7|\xe1\x8e\xa7|\xe1\x8e\xa7||" "\xea\xad\xb8|\xe1\x8e\xa8|\xe1\x8e\xa8||" "\xea\xad\xb9|\xe1\x8e\xa9|\xe1\x8e\xa9||" "\xea\xad\xba|\xe1\x8e\xaa|\xe1\x8e\xaa||" "\xea\xad\xbb|\xe1\x8e\xab|\xe1\x8e\xab||" "\xea\xad\xbc|\xe1\x8e\xac|\xe1\x8e\xac||" "\xea\xad\xbd|\xe1\x8e\xad|\xe1\x8e\xad||" "\xea\xad\xbe|\xe1\x8e\xae|\xe1\x8e\xae||" "\xea\xad\xbf|\xe1\x8e\xaf|\xe1\x8e\xaf||" "\xea\xae\x80|\xe1\x8e\xb0|\xe1\x8e\xb0||" "\xea\xae\x81|\xe1\x8e\xb1|\xe1\x8e\xb1||" "\xea\xae\x82|\xe1\x8e\xb2|\xe1\x8e\xb2||" "\xea\xae\x83|\xe1\x8e\xb3|\xe1\x8e\xb3||" "\xea\xae\x84|\xe1\x8e\xb4|\xe1\x8e\xb4||" "\xea\xae\x85|\xe1\x8e\xb5|\xe1\x8e\xb5||" "\xea\xae\x86|\xe1\x8e\xb6|\xe1\x8e\xb6||" "\xea\xae\x87|\xe1\x8e\xb7|\xe1\x8e\xb7||" "\xea\xae\x88|\xe1\x8e\xb8|\xe1\x8e\xb8||" "\xea\xae\x89|\xe1\x8e\xb9|\xe1\x8e\xb9||" "\xea\xae\x8a|\xe1\x8e\xba|\xe1\x8e\xba||" "\xea\xae\x8b|\xe1\x8e\xbb|\xe1\x8e\xbb||" "\xea\xae\x8c|\xe1\x8e\xbc|\xe1\x8e\xbc||" "\xea\xae\x8d|\xe1\x8e\xbd|\xe1\x8e\xbd||" "\xea\xae\x8e|\xe1\x8e\xbe|\xe1\x8e\xbe||" "\xea\xae\x8f|\xe1\x8e\xbf|\xe1\x8e\xbf||" "\xea\xae\x90|\xe1\x8f\x80|\xe1\x8f\x80||" "\xea\xae\x91|\xe1\x8f\x81|\xe1\x8f\x81||" "\xea\xae\x92|\xe1\x8f\x82|\xe1\x8f\x82||" "\xea\xae\x93|\xe1\x8f\x83|\xe1\x8f\x83||" "\xea\xae\x94|\xe1\x8f\x84|\xe1\x8f\x84||" "\xea\xae\x95|\xe1\x8f\x85|\xe1\x8f\x85||" "\xea\xae\x96|\xe1\x8f\x86|\xe1\x8f\x86||" "\xea\xae\x97|\xe1\x8f\x87|\xe1\x8f\x87||" "\xea\xae\x98|\xe1\x8f\x88|\xe1\x8f\x88||" "\xea\xae\x99|\xe1\x8f\x89|\xe1\x8f\x89||" "\xea\xae\x9a|\xe1\x8f\x8a|\xe1\x8f\x8a||" "\xea\xae\x9b|\xe1\x8f\x8b|\xe1\x8f\x8b||" "\xea\xae\x9c|\xe1\x8f\x8c|\xe1\x8f\x8c||" "\xea\xae\x9d|\xe1\x8f\x8d|\xe1\x8f\x8d||" "\xea\xae\x9e|\xe1\x8f\x8e|\xe1\x8f\x8e||" "\xea\xae\x9f|\xe1\x8f\x8f|\xe1\x8f\x8f||" "\xea\xae\xa0|\xe1\x8f\x90|\xe1\x8f\x90||" "\xea\xae\xa1|\xe1\x8f\x91|\xe1\x8f\x91||" "\xea\xae\xa2|\xe1\x8f\x92|\xe1\x8f\x92||" "\xea\xae\xa3|\xe1\x8f\x93|\xe1\x8f\x93||" "\xea\xae\xa4|\xe1\x8f\x94|\xe1\x8f\x94||" "\xea\xae\xa5|\xe1\x8f\x95|\xe1\x8f\x95||" "\xea\xae\xa6|\xe1\x8f\x96|\xe1\x8f\x96||" "\xea\xae\xa7|\xe1\x8f\x97|\xe1\x8f\x97||" "\xea\xae\xa8|\xe1\x8f\x98|\xe1\x8f\x98||" "\xea\xae\xa9|\xe1\x8f\x99|\xe1\x8f\x99||" "\xea\xae\xaa|\xe1\x8f\x9a|\xe1\x8f\x9a||" "\xea\xae\xab|\xe1\x8f\x9b|\xe1\x8f\x9b||" "\xea\xae\xac|\xe1\x8f\x9c|\xe1\x8f\x9c||" "\xea\xae\xad|\xe1\x8f\x9d|\xe1\x8f\x9d||" "\xea\xae\xae|\xe1\x8f\x9e|\xe1\x8f\x9e||" "\xea\xae\xaf|\xe1\x8f\x9f|\xe1\x8f\x9f||" "\xea\xae\xb0|\xe1\x8f\xa0|\xe1\x8f\xa0||" "\xea\xae\xb1|\xe1\x8f\xa1|\xe1\x8f\xa1||" "\xea\xae\xb2|\xe1\x8f\xa2|\xe1\x8f\xa2||" "\xea\xae\xb3|\xe1\x8f\xa3|\xe1\x8f\xa3||" "\xea\xae\xb4|\xe1\x8f\xa4|\xe1\x8f\xa4||" "\xea\xae\xb5|\xe1\x8f\xa5|\xe1\x8f\xa5||" "\xea\xae\xb6|\xe1\x8f\xa6|\xe1\x8f\xa6||" "\xea\xae\xb7|\xe1\x8f\xa7|\xe1\x8f\xa7||" "\xea\xae\xb8|\xe1\x8f\xa8|\xe1\x8f\xa8||" "\xea\xae\xb9|\xe1\x8f\xa9|\xe1\x8f\xa9||" "\xea\xae\xba|\xe1\x8f\xaa|\xe1\x8f\xaa||" "\xea\xae\xbb|\xe1\x8f\xab|\xe1\x8f\xab||" "\xea\xae\xbc|\xe1\x8f\xac|\xe1\x8f\xac||" "\xea\xae\xbd|\xe1\x8f\xad|\xe1\x8f\xad||" "\xea\xae\xbe|\xe1\x8f\xae|\xe1\x8f\xae||" "\xea\xae\xbf|\xe1\x8f\xaf|\xe1\x8f\xaf||" "\xef\xac\x80|ff|FF||" "\xef\xac\x81|fi|FI||" "\xef\xac\x82|fl|FL||" "\xef\xac\x83|ffi|FFI||" "\xef\xac\x84|ffl|FFL||" "\xef\xac\x85|st|ST||" "\xef\xac\x86|st|ST||" "\xef\xac\x93|\xd5\xb4\xd5\xb6|\xd5\x84\xd5\x86||" "\xef\xac\x94|\xd5\xb4\xd5\xa5|\xd5\x84\xd4\xb5||" "\xef\xac\x95|\xd5\xb4\xd5\xab|\xd5\x84\xd4\xbb||" "\xef\xac\x96|\xd5\xbe\xd5\xb6|\xd5\x8e\xd5\x86||" "\xef\xac\x97|\xd5\xb4\xd5\xad|\xd5\x84\xd4\xbd||" //--Autogenerated -- end of section automatically generated ; class CaseConverter : public ICaseConverter { // Maximum length of a case conversion result is 6 bytes in UTF-8 enum { maxConversionLength=6 }; struct ConversionString { char conversion[maxConversionLength+1]; ConversionString() : conversion{} { } }; // Conversions are initially store in a vector of structs but then decomposed into // parallel arrays as that is about 10% faster to search. struct CharacterConversion { int character; ConversionString conversion; CharacterConversion(int character_=0, const char *conversion_="") noexcept : character(character_) { StringCopy(conversion.conversion, conversion_); } bool operator<(const CharacterConversion &other) const noexcept { return character < other.character; } }; typedef std::vector CharacterToConversion; CharacterToConversion characterToConversion; // The parallel arrays std::vector characters; std::vector conversions; public: CaseConverter() { } virtual ~CaseConverter() = default; bool Initialised() const { return characters.size() > 0; } void Add(int character, const char *conversion) { characterToConversion.emplace_back(character, conversion); } const char *Find(int character) { const std::vector::iterator it = std::lower_bound(characters.begin(), characters.end(), character); if (it == characters.end()) return nullptr; else if (*it == character) return conversions[it - characters.begin()].conversion; else return nullptr; } size_t CaseConvertString(char *converted, size_t sizeConverted, const char *mixed, size_t lenMixed) override { size_t lenConverted = 0; size_t mixedPos = 0; unsigned char bytes[UTF8MaxBytes + 1]{}; while (mixedPos < lenMixed) { const unsigned char leadByte = mixed[mixedPos]; const char *caseConverted = nullptr; size_t lenMixedChar = 1; if (UTF8IsAscii(leadByte)) { caseConverted = Find(leadByte); } else { bytes[0] = leadByte; const int widthCharBytes = UTF8BytesOfLead[leadByte]; for (int b=1; b= sizeConverted) return 0; } } else { // Character has no conversion so copy the input to output for (size_t i=0; i= sizeConverted) return 0; } } mixedPos += lenMixedChar; } return lenConverted; } void FinishedAdding() { std::sort(characterToConversion.begin(), characterToConversion.end()); characters.reserve(characterToConversion.size()); conversions.reserve(characterToConversion.size()); for (const CharacterConversion &chConv : characterToConversion) { characters.push_back(chConv.character); conversions.push_back(chConv.conversion); } // Empty the original calculated data completely CharacterToConversion().swap(characterToConversion); } }; CaseConverter caseConvFold; CaseConverter caseConvUp; CaseConverter caseConvLow; void AddSymmetric(enum CaseConversion conversion, int lower,int upper) { char lowerUTF8[UTF8MaxBytes+1]; UTF8FromUTF32Character(lower, lowerUTF8); char upperUTF8[UTF8MaxBytes+1]; UTF8FromUTF32Character(upper, upperUTF8); switch (conversion) { case CaseConversionFold: caseConvFold.Add(upper, lowerUTF8); break; case CaseConversionUpper: caseConvUp.Add(lower, upperUTF8); break; case CaseConversionLower: caseConvLow.Add(upper, lowerUTF8); break; } } void SetupConversions(enum CaseConversion conversion) { // First initialize for the symmetric ranges for (size_t i=0; iInitialised()) SetupConversions(conversion); return pCaseConv; } const char *CaseConvert(int character, enum CaseConversion conversion) { CaseConverter *pCaseConv = ConverterForConversion(conversion); if (!pCaseConv->Initialised()) SetupConversions(conversion); return pCaseConv->Find(character); } size_t CaseConvertString(char *converted, size_t sizeConverted, const char *mixed, size_t lenMixed, enum CaseConversion conversion) { CaseConverter *pCaseConv = ConverterForConversion(conversion); if (!pCaseConv->Initialised()) SetupConversions(conversion); return pCaseConv->CaseConvertString(converted, sizeConverted, mixed, lenMixed); } std::string CaseConvertString(const std::string &s, enum CaseConversion conversion) { std::string retMapped(s.length() * maxExpansionCaseConversion, 0); const size_t lenMapped = CaseConvertString(&retMapped[0], retMapped.length(), s.c_str(), s.length(), conversion); retMapped.resize(lenMapped); return retMapped; } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CaseConvert.h000066400000000000000000000031011463772530400261370ustar00rootroot00000000000000// Scintilla source code edit control // Encoding: UTF-8 /** @file CaseConvert.h ** Performs Unicode case conversions. ** Does not handle locale-sensitive case conversion. **/ // Copyright 2013 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CASECONVERT_H #define CASECONVERT_H namespace Scintilla { enum CaseConversion { CaseConversionFold, CaseConversionUpper, CaseConversionLower }; class ICaseConverter { public: virtual size_t CaseConvertString(char *converted, size_t sizeConverted, const char *mixed, size_t lenMixed) = 0; }; ICaseConverter *ConverterFor(enum CaseConversion conversion); // Returns a UTF-8 string. Empty when no conversion const char *CaseConvert(int character, enum CaseConversion conversion); // When performing CaseConvertString, the converted value may be up to 3 times longer than the input. // Ligatures are often decomposed into multiple characters and long cases include: // Î "\xce\x90" folds to Î¹ÌˆÌ "\xce\xb9\xcc\x88\xcc\x81" const int maxExpansionCaseConversion=3; // Converts a mixed case string using a particular conversion. // Result may be a different length to input and the length is the return value. // If there is not enough space then 0 is returned. size_t CaseConvertString(char *converted, size_t sizeConverted, const char *mixed, size_t lenMixed, enum CaseConversion conversion); // Converts a mixed case string using a particular conversion. std::string CaseConvertString(const std::string &s, enum CaseConversion conversion); } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CaseFolder.cpp000066400000000000000000000032571463772530400263010ustar00rootroot00000000000000// Scintilla source code edit control /** @file CaseFolder.cxx ** Classes for case folding. **/ // Copyright 1998-2013 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include "CaseFolder.h" #include "CaseConvert.h" using namespace Scintilla; CaseFolder::~CaseFolder() { } CaseFolderTable::CaseFolderTable() : mapping{} { for (size_t iChar=0; iChar(iChar); } } CaseFolderTable::~CaseFolderTable() { } size_t CaseFolderTable::Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { if (lenMixed > sizeFolded) { return 0; } else { for (size_t i=0; i(mixed[i])]; } return lenMixed; } } void CaseFolderTable::SetTranslation(char ch, char chTranslation) { mapping[static_cast(ch)] = chTranslation; } void CaseFolderTable::StandardASCII() { for (size_t iChar=0; iChar= 'A' && iChar <= 'Z') { mapping[iChar] = static_cast(iChar - 'A' + 'a'); } else { mapping[iChar] = static_cast(iChar); } } } CaseFolderUnicode::CaseFolderUnicode() { StandardASCII(); converter = ConverterFor(CaseConversionFold); } size_t CaseFolderUnicode::Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { if ((lenMixed == 1) && (sizeFolded > 0)) { folded[0] = mapping[static_cast(mixed[0])]; return 1; } else { return converter->CaseConvertString(folded, sizeFolded, mixed, lenMixed); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CaseFolder.h000066400000000000000000000017621463772530400257450ustar00rootroot00000000000000// Scintilla source code edit control /** @file CaseFolder.h ** Classes for case folding. **/ // Copyright 1998-2013 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CASEFOLDER_H #define CASEFOLDER_H namespace Scintilla { class CaseFolder { public: virtual ~CaseFolder(); virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) = 0; }; class CaseFolderTable : public CaseFolder { protected: char mapping[256]; public: CaseFolderTable(); ~CaseFolderTable() override; size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override; void SetTranslation(char ch, char chTranslation); void StandardASCII(); }; class ICaseConverter; class CaseFolderUnicode : public CaseFolderTable { ICaseConverter *converter; public: CaseFolderUnicode(); size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Catalogue.cpp000066400000000000000000000040661463772530400261750ustar00rootroot00000000000000// Scintilla source code edit control /** @file Catalogue.cxx ** Lexer infrastructure. ** Contains a list of LexerModules which can be searched to find a module appropriate for a ** particular language. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "LexerModule.h" #include "Catalogue.h" using namespace Scintilla; static std::vector lexerCatalogue; static int nextLanguage = SCLEX_AUTOMATIC+1; const LexerModule *Catalogue::Find(int language) { Scintilla_LinkLexers(); for (const LexerModule *lm : lexerCatalogue) { if (lm->GetLanguage() == language) { return lm; } } return nullptr; } const LexerModule *Catalogue::Find(const char *languageName) { Scintilla_LinkLexers(); if (languageName) { for (const LexerModule *lm : lexerCatalogue) { if (lm->languageName && (0 == strcmp(lm->languageName, languageName))) { return lm; } } } return nullptr; } void Catalogue::AddLexerModule(LexerModule *plm) { if (plm->GetLanguage() == SCLEX_AUTOMATIC) { plm->language = nextLanguage; nextLanguage++; } lexerCatalogue.push_back(plm); } // To add or remove a lexer, add or remove its file and run LexGen.py. // Force a reference to all of the Scintilla lexers so that the linker will // not remove the code of the lexers. int Scintilla_LinkLexers() { static int initialised = 0; if (initialised) return 0; initialised = 1; // Shorten the code that declares a lexer and ensures it is linked in by calling a method. #define LINK_LEXER(lexer) extern LexerModule lexer; Catalogue::AddLexerModule(&lexer); //++Autogenerated -- run scripts/LexGen.py to regenerate //**\(\tLINK_LEXER(\*);\n\) LINK_LEXER(lmSQL); LINK_LEXER(lmJSON); LINK_LEXER(lmHTML); LINK_LEXER(lmXML); //--Autogenerated -- end of automatically generated section return 1; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Catalogue.h000066400000000000000000000011571463772530400256400ustar00rootroot00000000000000// Scintilla source code edit control /** @file Catalogue.h ** Lexer infrastructure. ** Contains a list of LexerModules which can be searched to find a module appropriate for a ** particular language. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CATALOGUE_H #define CATALOGUE_H namespace Scintilla { class Catalogue { public: static const LexerModule *Find(int language); static const LexerModule *Find(const char *languageName); static void AddLexerModule(LexerModule *plm); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CellBuffer.cpp000066400000000000000000001075721463772530400263100ustar00rootroot00000000000000// Scintilla source code edit control /** @file CellBuffer.cxx ** Manages a buffer of cells. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "Position.h" #include "SplitVector.h" #include "Partitioning.h" #include "CellBuffer.h" #include "UniConversion.h" namespace Scintilla { struct CountWidths { // Measures the number of characters in a string divided into those // from the Base Multilingual Plane and those from other planes. Sci::Position countBasePlane; Sci::Position countOtherPlanes; CountWidths(Sci::Position countBasePlane_=0, Sci::Position countOtherPlanes_=0) noexcept : countBasePlane(countBasePlane_), countOtherPlanes(countOtherPlanes_) { } CountWidths operator-() const noexcept { return CountWidths(-countBasePlane , -countOtherPlanes); } Sci::Position WidthUTF32() const noexcept { // All code points take one code unit in UTF-32. return countBasePlane + countOtherPlanes; } Sci::Position WidthUTF16() const noexcept { // UTF-16 takes 2 code units for other planes return countBasePlane + 2 * countOtherPlanes; } void CountChar(int lenChar) noexcept { if (lenChar == 4) { countOtherPlanes++; } else { countBasePlane++; } } }; class ILineVector { public: virtual void Init() = 0; virtual void SetPerLine(PerLine *pl) = 0; virtual void InsertText(Sci::Line line, Sci::Position delta) = 0; virtual void InsertLine(Sci::Line line, Sci::Position position, bool lineStart) = 0; virtual void SetLineStart(Sci::Line line, Sci::Position position) noexcept = 0; virtual void RemoveLine(Sci::Line line) = 0; virtual Sci::Line Lines() const noexcept = 0; virtual Sci::Line LineFromPosition(Sci::Position pos) const noexcept = 0; virtual Sci::Position LineStart(Sci::Line line) const noexcept = 0; virtual void InsertCharacters(Sci::Line line, CountWidths delta) = 0; virtual void SetLineCharactersWidth(Sci::Line line, CountWidths width) = 0; virtual int LineCharacterIndex() const noexcept = 0; virtual bool AllocateLineCharacterIndex(int lineCharacterIndex, Sci::Line lines) = 0; virtual bool ReleaseLineCharacterIndex(int lineCharacterIndex) = 0; virtual Sci::Position IndexLineStart(Sci::Line line, int lineCharacterIndex) const noexcept = 0; virtual Sci::Line LineFromPositionIndex(Sci::Position pos, int lineCharacterIndex) const noexcept = 0; virtual ~ILineVector() {} }; } using namespace Scintilla; template class LineStartIndex { public: int refCount; Partitioning starts; LineStartIndex() : refCount(0), starts(4) { // Minimal initial allocation } // Deleted so LineStartIndex objects can not be copied. LineStartIndex(const LineStartIndex &) = delete; LineStartIndex(LineStartIndex &&) = delete; void operator=(const LineStartIndex &) = delete; void operator=(LineStartIndex &&) = delete; virtual ~LineStartIndex() { starts.DeleteAll(); } bool Allocate(Sci::Line lines) { refCount++; Sci::Position length = starts.PositionFromPartition(starts.Partitions()); for (Sci::Line line = starts.Partitions(); line < lines; line++) { // Produce an ascending sequence that will be filled in with correct widths later length++; starts.InsertPartition(static_cast(line), static_cast(length)); } return refCount == 1; } bool Release() { if (refCount == 1) { starts.DeleteAll(); } refCount--; return refCount == 0; } bool Active() const noexcept { return refCount > 0; } Sci::Position LineWidth(Sci::Line line) const noexcept { return starts.PositionFromPartition(static_cast(line) + 1) - starts.PositionFromPartition(static_cast(line)); } void SetLineWidth(Sci::Line line, Sci::Position width) { const Sci::Position widthCurrent = LineWidth(line); starts.InsertText(static_cast(line), static_cast(width - widthCurrent)); } }; template class LineVector : public ILineVector { Partitioning starts; PerLine *perLine; LineStartIndex startsUTF16; LineStartIndex startsUTF32; public: LineVector() : starts(256), perLine(nullptr) { Init(); } // Deleted so LineVector objects can not be copied. LineVector(const LineVector &) = delete; LineVector(LineVector &&) = delete; LineVector &operator=(const LineVector &) = delete; LineVector &operator=(LineVector &&) = delete; ~LineVector() override { } void Init() override { starts.DeleteAll(); if (perLine) { perLine->Init(); } startsUTF32.starts.DeleteAll(); startsUTF16.starts.DeleteAll(); } void SetPerLine(PerLine *pl) override { perLine = pl; } void InsertText(Sci::Line line, Sci::Position delta) override { starts.InsertText(static_cast(line), static_cast(delta)); } void InsertLine(Sci::Line line, Sci::Position position, bool lineStart) override { const POS lineAsPos = static_cast(line); starts.InsertPartition(lineAsPos, static_cast(position)); if (startsUTF32.Active()) { startsUTF32.starts.InsertPartition(lineAsPos, static_cast(startsUTF32.starts.PositionFromPartition(lineAsPos - 1) + 1)); } if (startsUTF16.Active()) { startsUTF16.starts.InsertPartition(lineAsPos, static_cast(startsUTF16.starts.PositionFromPartition(lineAsPos - 1) + 1)); } if (perLine) { if ((line > 0) && lineStart) line--; perLine->InsertLine(line); } } void SetLineStart(Sci::Line line, Sci::Position position) noexcept override { starts.SetPartitionStartPosition(static_cast(line), static_cast(position)); } void RemoveLine(Sci::Line line) override { starts.RemovePartition(static_cast(line)); if (startsUTF32.Active()) { startsUTF32.starts.RemovePartition(static_cast(line)); } if (startsUTF16.Active()) { startsUTF16.starts.RemovePartition(static_cast(line)); } if (perLine) { perLine->RemoveLine(line); } } Sci::Line Lines() const noexcept override { return static_cast(starts.Partitions()); } Sci::Line LineFromPosition(Sci::Position pos) const noexcept override { return static_cast(starts.PartitionFromPosition(static_cast(pos))); } Sci::Position LineStart(Sci::Line line) const noexcept override { return starts.PositionFromPartition(static_cast(line)); } void InsertCharacters(Sci::Line line, CountWidths delta) override { if (startsUTF32.Active()) { startsUTF32.starts.InsertText(static_cast(line), static_cast(delta.WidthUTF32())); } if (startsUTF16.Active()) { startsUTF16.starts.InsertText(static_cast(line), static_cast(delta.WidthUTF16())); } } void SetLineCharactersWidth(Sci::Line line, CountWidths width) override { if (startsUTF32.Active()) { assert(startsUTF32.starts.Partitions() == starts.Partitions()); startsUTF32.SetLineWidth(line, width.WidthUTF32()); } if (startsUTF16.Active()) { assert(startsUTF16.starts.Partitions() == starts.Partitions()); startsUTF16.SetLineWidth(line, width.WidthUTF16()); } } int LineCharacterIndex() const noexcept override { int retVal = 0; if (startsUTF32.Active()) { retVal |= SC_LINECHARACTERINDEX_UTF32; } if (startsUTF16.Active()) { retVal |= SC_LINECHARACTERINDEX_UTF16; } return retVal; } bool AllocateLineCharacterIndex(int lineCharacterIndex, Sci::Line lines) override { bool changed = false; if ((lineCharacterIndex & SC_LINECHARACTERINDEX_UTF32) != 0) { changed = startsUTF32.Allocate(lines) || changed; assert(startsUTF32.starts.Partitions() == starts.Partitions()); } if ((lineCharacterIndex & SC_LINECHARACTERINDEX_UTF16) != 0) { changed = startsUTF16.Allocate(lines) || changed; assert(startsUTF16.starts.Partitions() == starts.Partitions()); } return changed; } bool ReleaseLineCharacterIndex(int lineCharacterIndex) override { bool changed = false; if ((lineCharacterIndex & SC_LINECHARACTERINDEX_UTF32) != 0) { changed = startsUTF32.Release() || changed; } if ((lineCharacterIndex & SC_LINECHARACTERINDEX_UTF16) != 0) { changed = startsUTF16.Release() || changed; } return changed; } Sci::Position IndexLineStart(Sci::Line line, int lineCharacterIndex) const noexcept override { if (lineCharacterIndex == SC_LINECHARACTERINDEX_UTF32) { return startsUTF32.starts.PositionFromPartition(static_cast(line)); } else { return startsUTF16.starts.PositionFromPartition(static_cast(line)); } } Sci::Line LineFromPositionIndex(Sci::Position pos, int lineCharacterIndex) const noexcept override { if (lineCharacterIndex == SC_LINECHARACTERINDEX_UTF32) { return static_cast(startsUTF32.starts.PartitionFromPosition(static_cast(pos))); } else { return static_cast(startsUTF16.starts.PartitionFromPosition(static_cast(pos))); } } }; Action::Action() { at = startAction; position = 0; lenData = 0; mayCoalesce = false; } Action::~Action() { } void Action::Create(actionType at_, Sci::Position position_, const char *data_, Sci::Position lenData_, bool mayCoalesce_) { data = nullptr; position = position_; at = at_; if (lenData_) { data = std::unique_ptr(new char[lenData_]); memcpy(&data[0], data_, lenData_); } lenData = lenData_; mayCoalesce = mayCoalesce_; } void Action::Clear() { data = nullptr; lenData = 0; } // The undo history stores a sequence of user operations that represent the user's view of the // commands executed on the text. // Each user operation contains a sequence of text insertion and text deletion actions. // All the user operations are stored in a list of individual actions with 'start' actions used // as delimiters between user operations. // Initially there is one start action in the history. // As each action is performed, it is recorded in the history. The action may either become // part of the current user operation or may start a new user operation. If it is to be part of the // current operation, then it overwrites the current last action. If it is to be part of a new // operation, it is appended after the current last action. // After writing the new action, a new start action is appended at the end of the history. // The decision of whether to start a new user operation is based upon two factors. If a // compound operation has been explicitly started by calling BeginUndoAction and no matching // EndUndoAction (these calls nest) has been called, then the action is coalesced into the current // operation. If there is no outstanding BeginUndoAction call then a new operation is started // unless it looks as if the new action is caused by the user typing or deleting a stream of text. // Sequences that look like typing or deletion are coalesced into a single user operation. UndoHistory::UndoHistory() { actions.resize(3); maxAction = 0; currentAction = 0; undoSequenceDepth = 0; savePoint = 0; tentativePoint = -1; actions[currentAction].Create(startAction); } UndoHistory::~UndoHistory() { } void UndoHistory::EnsureUndoRoom() { // Have to test that there is room for 2 more actions in the array // as two actions may be created by the calling function if (static_cast(currentAction) >= (actions.size() - 2)) { // Run out of undo nodes so extend the array actions.resize(actions.size() * 2); } } const char *UndoHistory::AppendAction(actionType at, Sci::Position position, const char *data, Sci::Position lengthData, bool &startSequence, bool mayCoalesce) { EnsureUndoRoom(); //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction); //Platform::DebugPrintf("^ %d action %d %d\n", actions[currentAction - 1].at, // actions[currentAction - 1].position, actions[currentAction - 1].lenData); if (currentAction < savePoint) { savePoint = -1; } int oldCurrentAction = currentAction; if (currentAction >= 1) { if (0 == undoSequenceDepth) { // Top level actions may not always be coalesced int targetAct = -1; const Action *actPrevious = &(actions[currentAction + targetAct]); // Container actions may forward the coalesce state of Scintilla Actions. while ((actPrevious->at == containerAction) && actPrevious->mayCoalesce) { targetAct--; actPrevious = &(actions[currentAction + targetAct]); } // See if current action can be coalesced into previous action // Will work if both are inserts or deletes and position is same if ((currentAction == savePoint) || (currentAction == tentativePoint)) { currentAction++; } else if (!actions[currentAction].mayCoalesce) { // Not allowed to coalesce if this set currentAction++; } else if (!mayCoalesce || !actPrevious->mayCoalesce) { currentAction++; } else if (at == containerAction || actions[currentAction].at == containerAction) { ; // A coalescible containerAction } else if ((at != actPrevious->at) && (actPrevious->at != startAction)) { currentAction++; } else if ((at == insertAction) && (position != (actPrevious->position + actPrevious->lenData))) { // Insertions must be immediately after to coalesce currentAction++; } else if (at == removeAction) { if ((lengthData == 1) || (lengthData == 2)) { if ((position + lengthData) == actPrevious->position) { ; // Backspace -> OK } else if (position == actPrevious->position) { ; // Delete -> OK } else { // Removals must be at same position to coalesce currentAction++; } } else { // Removals must be of one character to coalesce currentAction++; } } else { // Action coalesced. } } else { // Actions not at top level are always coalesced unless this is after return to top level if (!actions[currentAction].mayCoalesce) currentAction++; } } else { currentAction++; } startSequence = oldCurrentAction != currentAction; const int actionWithData = currentAction; actions[currentAction].Create(at, position, data, lengthData, mayCoalesce); currentAction++; actions[currentAction].Create(startAction); maxAction = currentAction; return actions[actionWithData].data.get(); } void UndoHistory::BeginUndoAction() { EnsureUndoRoom(); if (undoSequenceDepth == 0) { if (actions[currentAction].at != startAction) { currentAction++; actions[currentAction].Create(startAction); maxAction = currentAction; } actions[currentAction].mayCoalesce = false; } undoSequenceDepth++; } void UndoHistory::EndUndoAction() { PLATFORM_ASSERT(undoSequenceDepth > 0); EnsureUndoRoom(); undoSequenceDepth--; if (0 == undoSequenceDepth) { if (actions[currentAction].at != startAction) { currentAction++; actions[currentAction].Create(startAction); maxAction = currentAction; } actions[currentAction].mayCoalesce = false; } } void UndoHistory::DropUndoSequence() { undoSequenceDepth = 0; } void UndoHistory::DeleteUndoHistory() { for (int i = 1; i < maxAction; i++) actions[i].Clear(); maxAction = 0; currentAction = 0; actions[currentAction].Create(startAction); savePoint = 0; tentativePoint = -1; } void UndoHistory::SetSavePoint() { savePoint = currentAction; } bool UndoHistory::IsSavePoint() const { return savePoint == currentAction; } void UndoHistory::TentativeStart() { tentativePoint = currentAction; } void UndoHistory::TentativeCommit() { tentativePoint = -1; // Truncate undo history maxAction = currentAction; } int UndoHistory::TentativeSteps() { // Drop any trailing startAction if (actions[currentAction].at == startAction && currentAction > 0) currentAction--; if (tentativePoint >= 0) return currentAction - tentativePoint; else return -1; } bool UndoHistory::CanUndo() const { return (currentAction > 0) && (maxAction > 0); } int UndoHistory::StartUndo() { // Drop any trailing startAction if (actions[currentAction].at == startAction && currentAction > 0) currentAction--; // Count the steps in this action int act = currentAction; while (actions[act].at != startAction && act > 0) { act--; } return currentAction - act; } const Action &UndoHistory::GetUndoStep() const { return actions[currentAction]; } void UndoHistory::CompletedUndoStep() { currentAction--; } bool UndoHistory::CanRedo() const { return maxAction > currentAction; } int UndoHistory::StartRedo() { // Drop any leading startAction if (currentAction < maxAction && actions[currentAction].at == startAction) currentAction++; // Count the steps in this action int act = currentAction; while (act < maxAction && actions[act].at != startAction) { act++; } return act - currentAction; } const Action &UndoHistory::GetRedoStep() const { return actions[currentAction]; } void UndoHistory::CompletedRedoStep() { currentAction++; } CellBuffer::CellBuffer(bool hasStyles_, bool largeDocument_) : hasStyles(hasStyles_), largeDocument(largeDocument_) { readOnly = false; utf8Substance = false; utf8LineEnds = 0; collectingUndo = true; if (largeDocument) plv = std::unique_ptr>(new LineVector()); else plv = std::unique_ptr>(new LineVector()); } CellBuffer::~CellBuffer() { } char CellBuffer::CharAt(Sci::Position position) const noexcept { return substance.ValueAt(position); } unsigned char CellBuffer::UCharAt(Sci::Position position) const noexcept { return substance.ValueAt(position); } void CellBuffer::GetCharRange(char *buffer, Sci::Position position, Sci::Position lengthRetrieve) const { if (lengthRetrieve <= 0) return; if (position < 0) return; if ((position + lengthRetrieve) > substance.Length()) { Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n", position, lengthRetrieve, substance.Length()); return; } substance.GetRange(buffer, position, lengthRetrieve); } char CellBuffer::StyleAt(Sci::Position position) const noexcept { return hasStyles ? style.ValueAt(position) : 0; } void CellBuffer::GetStyleRange(unsigned char *buffer, Sci::Position position, Sci::Position lengthRetrieve) const { if (lengthRetrieve < 0) return; if (position < 0) return; if (!hasStyles) { std::fill(buffer, buffer + lengthRetrieve, static_cast(0)); return; } if ((position + lengthRetrieve) > style.Length()) { Platform::DebugPrintf("Bad GetStyleRange %d for %d of %d\n", position, lengthRetrieve, style.Length()); return; } style.GetRange(reinterpret_cast(buffer), position, lengthRetrieve); } const char *CellBuffer::BufferPointer() { return substance.BufferPointer(); } const char *CellBuffer::RangePointer(Sci::Position position, Sci::Position rangeLength) { return substance.RangePointer(position, rangeLength); } Sci::Position CellBuffer::GapPosition() const { return substance.GapPosition(); } // The char* returned is to an allocation owned by the undo history const char *CellBuffer::InsertString(Sci::Position position, const char *s, Sci::Position insertLength, bool &startSequence) { // InsertString and DeleteChars are the bottleneck though which all changes occur const char *data = s; if (!readOnly) { if (collectingUndo) { // Save into the undo/redo stack, but only the characters - not the formatting // This takes up about half load time data = uh.AppendAction(insertAction, position, s, insertLength, startSequence); } BasicInsertString(position, s, insertLength); } return data; } bool CellBuffer::SetStyleAt(Sci::Position position, char styleValue) { if (!hasStyles) { return false; } const char curVal = style.ValueAt(position); if (curVal != styleValue) { style.SetValueAt(position, styleValue); return true; } else { return false; } } bool CellBuffer::SetStyleFor(Sci::Position position, Sci::Position lengthStyle, char styleValue) { if (!hasStyles) { return false; } bool changed = false; PLATFORM_ASSERT(lengthStyle == 0 || (lengthStyle > 0 && lengthStyle + position <= style.Length())); while (lengthStyle--) { const char curVal = style.ValueAt(position); if (curVal != styleValue) { style.SetValueAt(position, styleValue); changed = true; } position++; } return changed; } // The char* returned is to an allocation owned by the undo history const char *CellBuffer::DeleteChars(Sci::Position position, Sci::Position deleteLength, bool &startSequence) { // InsertString and DeleteChars are the bottleneck though which all changes occur PLATFORM_ASSERT(deleteLength > 0); const char *data = nullptr; if (!readOnly) { if (collectingUndo) { // Save into the undo/redo stack, but only the characters - not the formatting // The gap would be moved to position anyway for the deletion so this doesn't cost extra data = substance.RangePointer(position, deleteLength); data = uh.AppendAction(removeAction, position, data, deleteLength, startSequence); } BasicDeleteChars(position, deleteLength); } return data; } Sci::Position CellBuffer::Length() const noexcept { return substance.Length(); } void CellBuffer::Allocate(Sci::Position newSize) { substance.ReAllocate(newSize); if (hasStyles) { style.ReAllocate(newSize); } } void CellBuffer::SetUTF8Substance(bool utf8Substance_) { if (utf8Substance != utf8Substance_) { utf8Substance = utf8Substance_; ResetLineEnds(); } } void CellBuffer::SetLineEndTypes(int utf8LineEnds_) { if (utf8LineEnds != utf8LineEnds_) { const int indexes = plv->LineCharacterIndex(); utf8LineEnds = utf8LineEnds_; ResetLineEnds(); AllocateLineCharacterIndex(indexes); } } bool CellBuffer::ContainsLineEnd(const char *s, Sci::Position length) const { unsigned char chBeforePrev = 0; unsigned char chPrev = 0; for (Sci::Position i = 0; i < length; i++) { const unsigned char ch = s[i]; if ((ch == '\r') || (ch == '\n')) { return true; } else if (utf8LineEnds) { const unsigned char back3[3] = { chBeforePrev, chPrev, ch }; if (UTF8IsSeparator(back3) || UTF8IsNEL(back3 + 1)) { return true; } } chBeforePrev = chPrev; chPrev = ch; } return false; } void CellBuffer::SetPerLine(PerLine *pl) { plv->SetPerLine(pl); } int CellBuffer::LineCharacterIndex() const noexcept { return plv->LineCharacterIndex(); } void CellBuffer::AllocateLineCharacterIndex(int lineCharacterIndex) { if (utf8Substance) { if (plv->AllocateLineCharacterIndex(lineCharacterIndex, Lines())) { // Changed so recalculate whole file RecalculateIndexLineStarts(0, Lines() - 1); } } } void CellBuffer::ReleaseLineCharacterIndex(int lineCharacterIndex) { plv->ReleaseLineCharacterIndex(lineCharacterIndex); } Sci::Line CellBuffer::Lines() const noexcept { return plv->Lines(); } Sci::Position CellBuffer::LineStart(Sci::Line line) const noexcept { if (line < 0) return 0; else if (line >= Lines()) return Length(); else return plv->LineStart(line); } Sci::Line CellBuffer::LineFromPosition(Sci::Position pos) const noexcept { return plv->LineFromPosition(pos); } Sci::Position CellBuffer::IndexLineStart(Sci::Line line, int lineCharacterIndex) const noexcept { return plv->IndexLineStart(line, lineCharacterIndex); } Sci::Line CellBuffer::LineFromPositionIndex(Sci::Position pos, int lineCharacterIndex) const noexcept { return plv->LineFromPositionIndex(pos, lineCharacterIndex); } bool CellBuffer::IsReadOnly() const { return readOnly; } void CellBuffer::SetReadOnly(bool set) { readOnly = set; } bool CellBuffer::IsLarge() const { return largeDocument; } bool CellBuffer::HasStyles() const { return hasStyles; } void CellBuffer::SetSavePoint() { uh.SetSavePoint(); } bool CellBuffer::IsSavePoint() const { return uh.IsSavePoint(); } void CellBuffer::TentativeStart() { uh.TentativeStart(); } void CellBuffer::TentativeCommit() { uh.TentativeCommit(); } int CellBuffer::TentativeSteps() { return uh.TentativeSteps(); } bool CellBuffer::TentativeActive() const { return uh.TentativeActive(); } // Without undo void CellBuffer::InsertLine(Sci::Line line, Sci::Position position, bool lineStart) { plv->InsertLine(line, position, lineStart); } void CellBuffer::RemoveLine(Sci::Line line) { plv->RemoveLine(line); } bool CellBuffer::UTF8LineEndOverlaps(Sci::Position position) const { const unsigned char bytes[] = { static_cast(substance.ValueAt(position-2)), static_cast(substance.ValueAt(position-1)), static_cast(substance.ValueAt(position)), static_cast(substance.ValueAt(position+1)), }; return UTF8IsSeparator(bytes) || UTF8IsSeparator(bytes+1) || UTF8IsNEL(bytes+1); } bool CellBuffer::UTF8IsCharacterBoundary(Sci::Position position) const { assert(position >= 0 && position <= Length()); if (position > 0) { std::string back; for (int i = 0; i < UTF8MaxBytes; i++) { const Sci::Position posBack = position - i; if (posBack < 0) { return false; } back.insert(0, 1, substance.ValueAt(posBack)); if (!UTF8IsTrailByte(back.front())) { if (i > 0) { // Have reached a non-trail const int cla = UTF8Classify(reinterpret_cast(back.data()), back.size()); if ((cla & UTF8MaskInvalid) || (cla != i)) { return false; } } break; } } } if (position < Length()) { const unsigned char fore = substance.ValueAt(position); if (UTF8IsTrailByte(fore)) { return false; } } return true; } void CellBuffer::ResetLineEnds() { // Reinitialize line data -- too much work to preserve plv->Init(); const Sci::Position position = 0; const Sci::Position length = Length(); Sci::Line lineInsert = 1; const bool atLineStart = true; plv->InsertText(lineInsert-1, length); unsigned char chBeforePrev = 0; unsigned char chPrev = 0; for (Sci::Position i = 0; i < length; i++) { const unsigned char ch = substance.ValueAt(position + i); if (ch == '\r') { InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; } else if (ch == '\n') { if (chPrev == '\r') { // Patch up what was end of line plv->SetLineStart(lineInsert - 1, (position + i) + 1); } else { InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; } } else if (utf8LineEnds) { const unsigned char back3[3] = {chBeforePrev, chPrev, ch}; if (UTF8IsSeparator(back3) || UTF8IsNEL(back3+1)) { InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; } } chBeforePrev = chPrev; chPrev = ch; } } namespace { CountWidths CountCharacterWidthsUTF8(const char *s, size_t len) noexcept { CountWidths cw; size_t remaining = len; while (remaining > 0) { const int utf8Status = UTF8Classify(reinterpret_cast(s), len); const int lenChar = utf8Status & UTF8MaskWidth; cw.CountChar(lenChar); s += lenChar; remaining -= lenChar; } return cw; } } bool CellBuffer::MaintainingLineCharacterIndex() const noexcept { return plv->LineCharacterIndex() != SC_LINECHARACTERINDEX_NONE; } void CellBuffer::RecalculateIndexLineStarts(Sci::Line lineFirst, Sci::Line lineLast) { std::string text; Sci::Position posLineEnd = LineStart(lineFirst); for (Sci::Line line = lineFirst; line <= lineLast; line++) { // Find line start and end, retrieve text of line, count characters and update line width const Sci::Position posLineStart = posLineEnd; posLineEnd = LineStart(line+1); const Sci::Position width = posLineEnd - posLineStart; text.resize(width); GetCharRange(const_cast(text.data()), posLineStart, width); const CountWidths cw = CountCharacterWidthsUTF8(text.data(), text.size()); plv->SetLineCharactersWidth(line, cw); } } void CellBuffer::BasicInsertString(Sci::Position position, const char *s, Sci::Position insertLength) { if (insertLength == 0) return; PLATFORM_ASSERT(insertLength > 0); const unsigned char chAfter = substance.ValueAt(position); bool breakingUTF8LineEnd = false; if (utf8LineEnds && UTF8IsTrailByte(chAfter)) { breakingUTF8LineEnd = UTF8LineEndOverlaps(position); } const Sci::Line linePosition = plv->LineFromPosition(position); Sci::Line lineInsert = linePosition + 1; // A simple insertion is one that inserts valid text on a single line at a character boundary bool simpleInsertion = false; const bool maintainingIndex = MaintainingLineCharacterIndex(); // Check for breaking apart a UTF-8 sequence and inserting invalid UTF-8 if (utf8Substance && maintainingIndex) { // Actually, don't need to check that whole insertion is valid just that there // are no potential fragments at ends. simpleInsertion = UTF8IsCharacterBoundary(position) && UTF8IsValid(s, insertLength); } substance.InsertFromArray(position, s, 0, insertLength); if (hasStyles) { style.InsertValue(position, insertLength, 0); } const bool atLineStart = plv->LineStart(lineInsert-1) == position; // Point all the lines after the insertion point further along in the buffer plv->InsertText(lineInsert-1, insertLength); unsigned char chBeforePrev = substance.ValueAt(position - 2); unsigned char chPrev = substance.ValueAt(position - 1); if (chPrev == '\r' && chAfter == '\n') { // Splitting up a crlf pair at position InsertLine(lineInsert, position, false); lineInsert++; } if (breakingUTF8LineEnd) { RemoveLine(lineInsert); } unsigned char ch = ' '; for (Sci::Position i = 0; i < insertLength; i++) { ch = s[i]; if (ch == '\r') { InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; simpleInsertion = false; } else if (ch == '\n') { if (chPrev == '\r') { // Patch up what was end of line plv->SetLineStart(lineInsert - 1, (position + i) + 1); } else { InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; } simpleInsertion = false; } else if (utf8LineEnds) { const unsigned char back3[3] = {chBeforePrev, chPrev, ch}; if (UTF8IsSeparator(back3) || UTF8IsNEL(back3+1)) { InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; simpleInsertion = false; } } chBeforePrev = chPrev; chPrev = ch; } // Joining two lines where last insertion is cr and following substance starts with lf if (chAfter == '\n') { if (ch == '\r') { // End of line already in buffer so drop the newly created one RemoveLine(lineInsert - 1); simpleInsertion = false; } } else if (utf8LineEnds && !UTF8IsAscii(chAfter)) { // May have end of UTF-8 line end in buffer and start in insertion for (int j = 0; j < UTF8SeparatorLength-1; j++) { const unsigned char chAt = substance.ValueAt(position + insertLength + j); const unsigned char back3[3] = {chBeforePrev, chPrev, chAt}; if (UTF8IsSeparator(back3)) { InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart); lineInsert++; simpleInsertion = false; } if ((j == 0) && UTF8IsNEL(back3+1)) { InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart); lineInsert++; simpleInsertion = false; } chBeforePrev = chPrev; chPrev = chAt; } } if (maintainingIndex) { if (simpleInsertion) { const CountWidths cw = CountCharacterWidthsUTF8(s, insertLength); plv->InsertCharacters(linePosition, cw); } else { RecalculateIndexLineStarts(linePosition, lineInsert - 1); } } } void CellBuffer::BasicDeleteChars(Sci::Position position, Sci::Position deleteLength) { if (deleteLength == 0) return; Sci::Line lineRecalculateStart = INVALID_POSITION; if ((position == 0) && (deleteLength == substance.Length())) { // If whole buffer is being deleted, faster to reinitialise lines data // than to delete each line. plv->Init(); } else { // Have to fix up line positions before doing deletion as looking at text in buffer // to work out which lines have been removed const Sci::Line linePosition = plv->LineFromPosition(position); Sci::Line lineRemove = linePosition + 1; plv->InsertText(lineRemove-1, - (deleteLength)); const unsigned char chPrev = substance.ValueAt(position - 1); const unsigned char chBefore = chPrev; unsigned char chNext = substance.ValueAt(position); // Check for breaking apart a UTF-8 sequence // Needs further checks that text is UTF-8 or that some other break apart is occurring if (utf8Substance && MaintainingLineCharacterIndex()) { const Sci::Position posEnd = position + deleteLength; const Sci::Line lineEndRemove = plv->LineFromPosition(posEnd); const bool simpleDeletion = (linePosition == lineEndRemove) && UTF8IsCharacterBoundary(position) && UTF8IsCharacterBoundary(posEnd); if (simpleDeletion) { std::string text(deleteLength, '\0'); GetCharRange(const_cast(text.data()), position, deleteLength); if (UTF8IsValid(text.data(), text.size())) { // Everything is good const CountWidths cw = CountCharacterWidthsUTF8(text.data(), text.size()); plv->InsertCharacters(linePosition, -cw); } else { lineRecalculateStart = linePosition; } } else { lineRecalculateStart = linePosition; } } bool ignoreNL = false; if (chPrev == '\r' && chNext == '\n') { // Move back one plv->SetLineStart(lineRemove, position); lineRemove++; ignoreNL = true; // First \n is not real deletion } if (utf8LineEnds && UTF8IsTrailByte(chNext)) { if (UTF8LineEndOverlaps(position)) { RemoveLine(lineRemove); } } unsigned char ch = chNext; for (Sci::Position i = 0; i < deleteLength; i++) { chNext = substance.ValueAt(position + i + 1); if (ch == '\r') { if (chNext != '\n') { RemoveLine(lineRemove); } } else if (ch == '\n') { if (ignoreNL) { ignoreNL = false; // Further \n are real deletions } else { RemoveLine(lineRemove); } } else if (utf8LineEnds) { if (!UTF8IsAscii(ch)) { const unsigned char next3[3] = {ch, chNext, static_cast(substance.ValueAt(position + i + 2))}; if (UTF8IsSeparator(next3) || UTF8IsNEL(next3)) { RemoveLine(lineRemove); } } } ch = chNext; } // May have to fix up end if last deletion causes cr to be next to lf // or removes one of a crlf pair const char chAfter = substance.ValueAt(position + deleteLength); if (chBefore == '\r' && chAfter == '\n') { // Using lineRemove-1 as cr ended line before start of deletion RemoveLine(lineRemove - 1); plv->SetLineStart(lineRemove - 1, position + 1); } } substance.DeleteRange(position, deleteLength); if (lineRecalculateStart >= 0) { RecalculateIndexLineStarts(lineRecalculateStart, lineRecalculateStart); } if (hasStyles) { style.DeleteRange(position, deleteLength); } } bool CellBuffer::SetUndoCollection(bool collectUndo) { collectingUndo = collectUndo; uh.DropUndoSequence(); return collectingUndo; } bool CellBuffer::IsCollectingUndo() const { return collectingUndo; } void CellBuffer::BeginUndoAction() { uh.BeginUndoAction(); } void CellBuffer::EndUndoAction() { uh.EndUndoAction(); } void CellBuffer::AddUndoAction(Sci::Position token, bool mayCoalesce) { bool startSequence; uh.AppendAction(containerAction, token, nullptr, 0, startSequence, mayCoalesce); } void CellBuffer::DeleteUndoHistory() { uh.DeleteUndoHistory(); } bool CellBuffer::CanUndo() const { return uh.CanUndo(); } int CellBuffer::StartUndo() { return uh.StartUndo(); } const Action &CellBuffer::GetUndoStep() const { return uh.GetUndoStep(); } void CellBuffer::PerformUndoStep() { const Action &actionStep = uh.GetUndoStep(); if (actionStep.at == insertAction) { if (substance.Length() < actionStep.lenData) { throw std::runtime_error( "CellBuffer::PerformUndoStep: deletion must be less than document length."); } BasicDeleteChars(actionStep.position, actionStep.lenData); } else if (actionStep.at == removeAction) { BasicInsertString(actionStep.position, actionStep.data.get(), actionStep.lenData); } uh.CompletedUndoStep(); } bool CellBuffer::CanRedo() const { return uh.CanRedo(); } int CellBuffer::StartRedo() { return uh.StartRedo(); } const Action &CellBuffer::GetRedoStep() const { return uh.GetRedoStep(); } void CellBuffer::PerformRedoStep() { const Action &actionStep = uh.GetRedoStep(); if (actionStep.at == insertAction) { BasicInsertString(actionStep.position, actionStep.data.get(), actionStep.lenData); } else if (actionStep.at == removeAction) { BasicDeleteChars(actionStep.position, actionStep.lenData); } uh.CompletedRedoStep(); } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CellBuffer.h000066400000000000000000000160571463772530400257520ustar00rootroot00000000000000// Scintilla source code edit control /** @file CellBuffer.h ** Manages the text of the document. **/ // Copyright 1998-2004 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CELLBUFFER_H #define CELLBUFFER_H namespace Scintilla { // Interface to per-line data that wants to see each line insertion and deletion class PerLine { public: virtual ~PerLine() {} virtual void Init()=0; virtual void InsertLine(Sci::Line line)=0; virtual void RemoveLine(Sci::Line line)=0; }; /** * The line vector contains information about each of the lines in a cell buffer. */ class ILineVector; enum actionType { insertAction, removeAction, startAction, containerAction }; /** * Actions are used to store all the information required to perform one undo/redo step. */ class Action { public: actionType at; Sci::Position position; std::unique_ptr data; Sci::Position lenData; bool mayCoalesce; Action(); // Deleted so Action objects can not be copied. Action(const Action &other) = delete; Action &operator=(const Action &other) = delete; Action &operator=(const Action &&other) = delete; // Move constructor allows vector to be resized without reallocating. Action(Action &&other) noexcept = default; ~Action(); void Create(actionType at_, Sci::Position position_=0, const char *data_=nullptr, Sci::Position lenData_=0, bool mayCoalesce_=true); void Clear(); }; /** * */ class UndoHistory { std::vector actions; int maxAction; int currentAction; int undoSequenceDepth; int savePoint; int tentativePoint; void EnsureUndoRoom(); public: UndoHistory(); // Deleted so UndoHistory objects can not be copied. UndoHistory(const UndoHistory &) = delete; UndoHistory(UndoHistory &&) = delete; void operator=(const UndoHistory &) = delete; void operator=(UndoHistory &&) = delete; ~UndoHistory(); const char *AppendAction(actionType at, Sci::Position position, const char *data, Sci::Position lengthData, bool &startSequence, bool mayCoalesce=true); void BeginUndoAction(); void EndUndoAction(); void DropUndoSequence(); void DeleteUndoHistory(); /// The save point is a marker in the undo stack where the container has stated that /// the buffer was saved. Undo and redo can move over the save point. void SetSavePoint(); bool IsSavePoint() const; // Tentative actions are used for input composition so that it can be undone cleanly void TentativeStart(); void TentativeCommit(); bool TentativeActive() const noexcept { return tentativePoint >= 0; } int TentativeSteps(); /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is /// called that many times. Similarly for redo. bool CanUndo() const; int StartUndo(); const Action &GetUndoStep() const; void CompletedUndoStep(); bool CanRedo() const; int StartRedo(); const Action &GetRedoStep() const; void CompletedRedoStep(); }; /** * Holder for an expandable array of characters that supports undo and line markers. * Based on article "Data Structures in a Bit-Mapped Text Editor" * by Wilfred J. Hansen, Byte January 1987, page 183. */ class CellBuffer { private: bool hasStyles; bool largeDocument; SplitVector substance; SplitVector style; bool readOnly; bool utf8Substance; int utf8LineEnds; bool collectingUndo; UndoHistory uh; std::unique_ptr plv; bool UTF8LineEndOverlaps(Sci::Position position) const; bool UTF8IsCharacterBoundary(Sci::Position position) const; void ResetLineEnds(); void RecalculateIndexLineStarts(Sci::Line lineFirst, Sci::Line lineLast); bool MaintainingLineCharacterIndex() const noexcept; /// Actions without undo void BasicInsertString(Sci::Position position, const char *s, Sci::Position insertLength); void BasicDeleteChars(Sci::Position position, Sci::Position deleteLength); public: CellBuffer(bool hasStyles_, bool largeDocument_); // Deleted so CellBuffer objects can not be copied. CellBuffer(const CellBuffer &) = delete; CellBuffer(CellBuffer &&) = delete; void operator=(const CellBuffer &) = delete; void operator=(CellBuffer &&) = delete; ~CellBuffer(); /// Retrieving positions outside the range of the buffer works and returns 0 char CharAt(Sci::Position position) const noexcept; unsigned char UCharAt(Sci::Position position) const noexcept; void GetCharRange(char *buffer, Sci::Position position, Sci::Position lengthRetrieve) const; char StyleAt(Sci::Position position) const noexcept; void GetStyleRange(unsigned char *buffer, Sci::Position position, Sci::Position lengthRetrieve) const; const char *BufferPointer(); const char *RangePointer(Sci::Position position, Sci::Position rangeLength); Sci::Position GapPosition() const; Sci::Position Length() const noexcept; void Allocate(Sci::Position newSize); void SetUTF8Substance(bool utf8Substance_); int GetLineEndTypes() const { return utf8LineEnds; } void SetLineEndTypes(int utf8LineEnds_); bool ContainsLineEnd(const char *s, Sci::Position length) const; void SetPerLine(PerLine *pl); int LineCharacterIndex() const noexcept; void AllocateLineCharacterIndex(int lineCharacterIndex); void ReleaseLineCharacterIndex(int lineCharacterIndex); Sci::Line Lines() const noexcept; Sci::Position LineStart(Sci::Line line) const noexcept; Sci::Position IndexLineStart(Sci::Line line, int lineCharacterIndex) const noexcept; Sci::Line LineFromPosition(Sci::Position pos) const noexcept; Sci::Line LineFromPositionIndex(Sci::Position pos, int lineCharacterIndex) const noexcept; void InsertLine(Sci::Line line, Sci::Position position, bool lineStart); void RemoveLine(Sci::Line line); const char *InsertString(Sci::Position position, const char *s, Sci::Position insertLength, bool &startSequence); /// Setting styles for positions outside the range of the buffer is safe and has no effect. /// @return true if the style of a character is changed. bool SetStyleAt(Sci::Position position, char styleValue); bool SetStyleFor(Sci::Position position, Sci::Position lengthStyle, char styleValue); const char *DeleteChars(Sci::Position position, Sci::Position deleteLength, bool &startSequence); bool IsReadOnly() const; void SetReadOnly(bool set); bool IsLarge() const; bool HasStyles() const; /// The save point is a marker in the undo stack where the container has stated that /// the buffer was saved. Undo and redo can move over the save point. void SetSavePoint(); bool IsSavePoint() const; void TentativeStart(); void TentativeCommit(); bool TentativeActive() const; int TentativeSteps(); bool SetUndoCollection(bool collectUndo); bool IsCollectingUndo() const; void BeginUndoAction(); void EndUndoAction(); void AddUndoAction(Sci::Position token, bool mayCoalesce); void DeleteUndoHistory(); /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is /// called that many times. Similarly for redo. bool CanUndo() const; int StartUndo(); const Action &GetUndoStep() const; void PerformUndoStep(); bool CanRedo() const; int StartRedo(); const Action &GetRedoStep() const; void PerformRedoStep(); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CharClassify.cpp000066400000000000000000000030641463772530400266410ustar00rootroot00000000000000// Scintilla source code edit control /** @file CharClassify.cxx ** Character classifications used by Document and RESearch. **/ // Copyright 2006 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include "CharClassify.h" using namespace Scintilla; CharClassify::CharClassify() : charClass{} { SetDefaultCharClasses(true); } void CharClassify::SetDefaultCharClasses(bool includeWordClass) { // Initialize all char classes to default values for (int ch = 0; ch < 256; ch++) { if (ch == '\r' || ch == '\n') charClass[ch] = ccNewLine; else if (ch < 0x20 || ch == ' ') charClass[ch] = ccSpace; else if (includeWordClass && (ch >= 0x80 || isalnum(ch) || ch == '_')) charClass[ch] = ccWord; else charClass[ch] = ccPunctuation; } } void CharClassify::SetCharClasses(const unsigned char *chars, cc newCharClass) { // Apply the newCharClass to the specifed chars if (chars) { while (*chars) { charClass[*chars] = static_cast(newCharClass); chars++; } } } int CharClassify::GetCharsOfClass(cc characterClass, unsigned char *buffer) const { // Get characters belonging to the given char class; return the number // of characters (if the buffer is NULL, don't write to it). int count = 0; for (int ch = maxChar - 1; ch >= 0; --ch) { if (charClass[ch] == characterClass) { ++count; if (buffer) { *buffer = static_cast(ch); buffer++; } } } return count; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/CharClassify.h000066400000000000000000000016421463772530400263060ustar00rootroot00000000000000// Scintilla source code edit control /** @file CharClassify.h ** Character classifications used by Document and RESearch. **/ // Copyright 2006-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CHARCLASSIFY_H #define CHARCLASSIFY_H namespace Scintilla { class CharClassify { public: CharClassify(); enum cc { ccSpace, ccNewLine, ccWord, ccPunctuation }; void SetDefaultCharClasses(bool includeWordClass); void SetCharClasses(const unsigned char *chars, cc newCharClass); int GetCharsOfClass(cc characterClass, unsigned char *buffer) const; cc GetClass(unsigned char ch) const { return static_cast(charClass[ch]);} bool IsWord(unsigned char ch) const { return static_cast(charClass[ch]) == ccWord;} private: enum { maxChar=256 }; unsigned char charClass[maxChar]; // not type cc to save space }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/ContractionState.cpp000066400000000000000000000271401463772530400275530ustar00rootroot00000000000000// Scintilla source code edit control /** @file ContractionState.cxx ** Manages visibility of lines for folding and wrapping. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "Platform.h" #include "Position.h" #include "UniqueString.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "SparseVector.h" #include "ContractionState.h" using namespace Scintilla; namespace { template class ContractionState final : public IContractionState { // These contain 1 element for every document line. std::unique_ptr> visible; std::unique_ptr> expanded; std::unique_ptr> heights; std::unique_ptr> foldDisplayTexts; std::unique_ptr> displayLines; LINE linesInDocument; void EnsureData(); bool OneToOne() const noexcept { // True when each document line is exactly one display line so need for // complex data structures. return visible == nullptr; } void InsertLine(Sci::Line lineDoc); void DeleteLine(Sci::Line lineDoc); public: ContractionState() noexcept; // Deleted so ContractionState objects can not be copied. ContractionState(const ContractionState &) = delete; void operator=(const ContractionState &) = delete; ContractionState(ContractionState &&) = delete; void operator=(ContractionState &&) = delete; ~ContractionState() override; void Clear() noexcept override; Sci::Line LinesInDoc() const override; Sci::Line LinesDisplayed() const override; Sci::Line DisplayFromDoc(Sci::Line lineDoc) const override; Sci::Line DisplayLastFromDoc(Sci::Line lineDoc) const override; Sci::Line DocFromDisplay(Sci::Line lineDisplay) const override; void InsertLines(Sci::Line lineDoc, Sci::Line lineCount) override; void DeleteLines(Sci::Line lineDoc, Sci::Line lineCount) override; bool GetVisible(Sci::Line lineDoc) const override; bool SetVisible(Sci::Line lineDocStart, Sci::Line lineDocEnd, bool isVisible) override; bool HiddenLines() const override; const char *GetFoldDisplayText(Sci::Line lineDoc) const override; bool GetFoldDisplayTextShown(Sci::Line lineDoc) const override; bool SetFoldDisplayText(Sci::Line lineDoc, const char *text) override; bool GetExpanded(Sci::Line lineDoc) const override; bool SetExpanded(Sci::Line lineDoc, bool isExpanded) override; Sci::Line ContractedNext(Sci::Line lineDocStart) const override; int GetHeight(Sci::Line lineDoc) const override; bool SetHeight(Sci::Line lineDoc, int height) override; void ShowAll() override; void Check() const; }; template ContractionState::ContractionState() noexcept : linesInDocument(1) { } template ContractionState::~ContractionState() { Clear(); } template void ContractionState::EnsureData() { if (OneToOne()) { visible = std::unique_ptr>(new RunStyles()); expanded = std::unique_ptr>(new RunStyles()); heights = std::unique_ptr>(new RunStyles()); foldDisplayTexts = std::unique_ptr>(new SparseVector()); displayLines = std::unique_ptr>(new Partitioning(4)); InsertLines(0, linesInDocument); } } template void ContractionState::InsertLine(Sci::Line lineDoc) { if (OneToOne()) { linesInDocument++; } else { const LINE lineDocCast = static_cast(lineDoc); visible->InsertSpace(lineDocCast, 1); visible->SetValueAt(lineDocCast, 1); expanded->InsertSpace(lineDocCast, 1); expanded->SetValueAt(lineDocCast, 1); heights->InsertSpace(lineDocCast, 1); heights->SetValueAt(lineDocCast, 1); foldDisplayTexts->InsertSpace(lineDocCast, 1); foldDisplayTexts->SetValueAt(lineDocCast, nullptr); const Sci::Line lineDisplay = DisplayFromDoc(lineDoc); displayLines->InsertPartition(lineDocCast, static_cast(lineDisplay)); displayLines->InsertText(lineDocCast, 1); } } template void ContractionState::DeleteLine(Sci::Line lineDoc) { if (OneToOne()) { linesInDocument--; } else { const LINE lineDocCast = static_cast(lineDoc); if (GetVisible(lineDoc)) { displayLines->InsertText(lineDocCast, -heights->ValueAt(lineDocCast)); } displayLines->RemovePartition(lineDocCast); visible->DeleteRange(lineDocCast, 1); expanded->DeleteRange(lineDocCast, 1); heights->DeleteRange(lineDocCast, 1); foldDisplayTexts->DeletePosition(lineDocCast); } } template void ContractionState::Clear() noexcept { visible.reset(); expanded.reset(); heights.reset(); foldDisplayTexts.reset(); displayLines.reset(); linesInDocument = 1; } template Sci::Line ContractionState::LinesInDoc() const { if (OneToOne()) { return linesInDocument; } else { return displayLines->Partitions() - 1; } } template Sci::Line ContractionState::LinesDisplayed() const { if (OneToOne()) { return linesInDocument; } else { return displayLines->PositionFromPartition(static_cast(LinesInDoc())); } } template Sci::Line ContractionState::DisplayFromDoc(Sci::Line lineDoc) const { if (OneToOne()) { return (lineDoc <= linesInDocument) ? lineDoc : linesInDocument; } else { if (lineDoc > displayLines->Partitions()) lineDoc = displayLines->Partitions(); return displayLines->PositionFromPartition(static_cast(lineDoc)); } } template Sci::Line ContractionState::DisplayLastFromDoc(Sci::Line lineDoc) const { return DisplayFromDoc(lineDoc) + GetHeight(lineDoc) - 1; } template Sci::Line ContractionState::DocFromDisplay(Sci::Line lineDisplay) const { if (OneToOne()) { return lineDisplay; } else { if (lineDisplay <= 0) { return 0; } if (lineDisplay > LinesDisplayed()) { return displayLines->PartitionFromPosition(static_cast(LinesDisplayed())); } const Sci::Line lineDoc = displayLines->PartitionFromPosition(static_cast(lineDisplay)); PLATFORM_ASSERT(GetVisible(lineDoc)); return lineDoc; } } template void ContractionState::InsertLines(Sci::Line lineDoc, Sci::Line lineCount) { for (int l = 0; l < lineCount; l++) { InsertLine(lineDoc + l); } Check(); } template void ContractionState::DeleteLines(Sci::Line lineDoc, Sci::Line lineCount) { for (Sci::Line l = 0; l < lineCount; l++) { DeleteLine(lineDoc); } Check(); } template bool ContractionState::GetVisible(Sci::Line lineDoc) const { if (OneToOne()) { return true; } else { if (lineDoc >= visible->Length()) return true; return visible->ValueAt(static_cast(lineDoc)) == 1; } } template bool ContractionState::SetVisible(Sci::Line lineDocStart, Sci::Line lineDocEnd, bool isVisible) { if (OneToOne() && isVisible) { return false; } else { EnsureData(); Sci::Line delta = 0; Check(); if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) { for (Sci::Line line = lineDocStart; line <= lineDocEnd; line++) { if (GetVisible(line) != isVisible) { const int heightLine = heights->ValueAt(static_cast(line)); const int difference = isVisible ? heightLine : -heightLine; visible->SetValueAt(static_cast(line), isVisible ? 1 : 0); displayLines->InsertText(static_cast(line), difference); delta += difference; } } } else { return false; } Check(); return delta != 0; } } template bool ContractionState::HiddenLines() const { if (OneToOne()) { return false; } else { return !visible->AllSameAs(1); } } template const char *ContractionState::GetFoldDisplayText(Sci::Line lineDoc) const { Check(); return foldDisplayTexts->ValueAt(lineDoc).get(); } template bool ContractionState::GetFoldDisplayTextShown(Sci::Line lineDoc) const { return !GetExpanded(lineDoc) && GetFoldDisplayText(lineDoc); } template bool ContractionState::SetFoldDisplayText(Sci::Line lineDoc, const char *text) { EnsureData(); const char *foldText = foldDisplayTexts->ValueAt(lineDoc).get(); if (!foldText || !text || 0 != strcmp(text, foldText)) { UniqueString uns = UniqueStringCopy(text); foldDisplayTexts->SetValueAt(lineDoc, std::move(uns)); Check(); return true; } else { Check(); return false; } } template bool ContractionState::GetExpanded(Sci::Line lineDoc) const { if (OneToOne()) { return true; } else { Check(); return expanded->ValueAt(static_cast(lineDoc)) == 1; } } template bool ContractionState::SetExpanded(Sci::Line lineDoc, bool isExpanded) { if (OneToOne() && isExpanded) { return false; } else { EnsureData(); if (isExpanded != (expanded->ValueAt(static_cast(lineDoc)) == 1)) { expanded->SetValueAt(static_cast(lineDoc), isExpanded ? 1 : 0); Check(); return true; } else { Check(); return false; } } } template Sci::Line ContractionState::ContractedNext(Sci::Line lineDocStart) const { if (OneToOne()) { return -1; } else { Check(); if (!expanded->ValueAt(static_cast(lineDocStart))) { return lineDocStart; } else { const Sci::Line lineDocNextChange = expanded->EndRun(static_cast(lineDocStart)); if (lineDocNextChange < LinesInDoc()) return lineDocNextChange; else return -1; } } } template int ContractionState::GetHeight(Sci::Line lineDoc) const { if (OneToOne()) { return 1; } else { return heights->ValueAt(static_cast(lineDoc)); } } // Set the number of display lines needed for this line. // Return true if this is a change. template bool ContractionState::SetHeight(Sci::Line lineDoc, int height) { if (OneToOne() && (height == 1)) { return false; } else if (lineDoc < LinesInDoc()) { EnsureData(); if (GetHeight(lineDoc) != height) { if (GetVisible(lineDoc)) { displayLines->InsertText(static_cast(lineDoc), height - GetHeight(lineDoc)); } heights->SetValueAt(static_cast(lineDoc), height); Check(); return true; } else { Check(); return false; } } else { return false; } } template void ContractionState::ShowAll() { const LINE lines = static_cast(LinesInDoc()); Clear(); linesInDocument = lines; } // Debugging checks template void ContractionState::Check() const { #ifdef CHECK_CORRECTNESS for (Sci::Line vline = 0; vline < LinesDisplayed(); vline++) { const Sci::Line lineDoc = DocFromDisplay(vline); PLATFORM_ASSERT(GetVisible(lineDoc)); } for (Sci::Line lineDoc = 0; lineDoc < LinesInDoc(); lineDoc++) { const Sci::Line displayThis = DisplayFromDoc(lineDoc); const Sci::Line displayNext = DisplayFromDoc(lineDoc + 1); const Sci::Line height = displayNext - displayThis; PLATFORM_ASSERT(height >= 0); if (GetVisible(lineDoc)) { PLATFORM_ASSERT(GetHeight(lineDoc) == height); } else { PLATFORM_ASSERT(0 == height); } } #endif } } namespace Scintilla { std::unique_ptr ContractionStateCreate(bool largeDocument) { if (largeDocument) return std::unique_ptr>(new ContractionState()); else return std::unique_ptr>(new ContractionState()); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/ContractionState.h000066400000000000000000000032361463772530400272200ustar00rootroot00000000000000// Scintilla source code edit control /** @file ContractionState.h ** Manages visibility of lines for folding and wrapping. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CONTRACTIONSTATE_H #define CONTRACTIONSTATE_H namespace Scintilla { /** */ class IContractionState { public: virtual ~IContractionState() {}; virtual void Clear()=0; virtual Sci::Line LinesInDoc() const=0; virtual Sci::Line LinesDisplayed() const=0; virtual Sci::Line DisplayFromDoc(Sci::Line lineDoc) const=0; virtual Sci::Line DisplayLastFromDoc(Sci::Line lineDoc) const=0; virtual Sci::Line DocFromDisplay(Sci::Line lineDisplay) const=0; virtual void InsertLines(Sci::Line lineDoc, Sci::Line lineCount)=0; virtual void DeleteLines(Sci::Line lineDoc, Sci::Line lineCount)=0; virtual bool GetVisible(Sci::Line lineDoc) const=0; virtual bool SetVisible(Sci::Line lineDocStart, Sci::Line lineDocEnd, bool isVisible)=0; virtual bool HiddenLines() const=0; virtual const char *GetFoldDisplayText(Sci::Line lineDoc) const=0; virtual bool GetFoldDisplayTextShown(Sci::Line lineDoc) const=0; virtual bool SetFoldDisplayText(Sci::Line lineDoc, const char *text)=0; virtual bool GetExpanded(Sci::Line lineDoc) const=0; virtual bool SetExpanded(Sci::Line lineDoc, bool isExpanded)=0; virtual Sci::Line ContractedNext(Sci::Line lineDocStart) const=0; virtual int GetHeight(Sci::Line lineDoc) const=0; virtual bool SetHeight(Sci::Line lineDoc, int height)=0; virtual void ShowAll()=0; }; std::unique_ptr ContractionStateCreate(bool largeDocument); } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/DBCS.cpp000066400000000000000000000021231463772530400247740ustar00rootroot00000000000000// Scintilla source code edit control /** @file DBCS.cxx ** Functions to handle DBCS double byte encodings like Shift-JIS. **/ // Copyright 2017 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include "DBCS.h" using namespace Scintilla; namespace Scintilla { bool DBCSIsLeadByte(int codePage, char ch) noexcept { // Byte ranges found in Wikipedia articles with relevant search strings in each case const unsigned char uch = ch; switch (codePage) { case 932: // Shift_jis return ((uch >= 0x81) && (uch <= 0x9F)) || ((uch >= 0xE0) && (uch <= 0xFC)); // Lead bytes F0 to FC may be a Microsoft addition. case 936: // GBK return (uch >= 0x81) && (uch <= 0xFE); case 949: // Korean Wansung KS C-5601-1987 return (uch >= 0x81) && (uch <= 0xFE); case 950: // Big5 return (uch >= 0x81) && (uch <= 0xFE); case 1361: // Korean Johab KS C-5601-1992 return ((uch >= 0x84) && (uch <= 0xD3)) || ((uch >= 0xD8) && (uch <= 0xDE)) || ((uch >= 0xE0) && (uch <= 0xF9)); } return false; } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/DBCS.h000066400000000000000000000006151463772530400244450ustar00rootroot00000000000000// Scintilla source code edit control /** @file DBCS.h ** Functions to handle DBCS double byte encodings like Shift-JIS. **/ // Copyright 2017 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef DBCS_H #define DBCS_H namespace Scintilla { bool DBCSIsLeadByte(int codePage, char ch) noexcept; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Decoration.cpp000066400000000000000000000224621463772530400263600ustar00rootroot00000000000000/** @file Decoration.cxx ** Visual elements added over text. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "Position.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "Decoration.h" using namespace Scintilla; namespace { template class Decoration : public IDecoration { int indicator; public: RunStyles rs; explicit Decoration(int indicator_) : indicator(indicator_) { } ~Decoration() override { } bool Empty() const override { return (rs.Runs() == 1) && (rs.AllSameAs(0)); } int Indicator() const override { return indicator; } Sci::Position Length() const override { return rs.Length(); } int ValueAt(Sci::Position position) const override { return rs.ValueAt(static_cast(position)); } Sci::Position StartRun(Sci::Position position) const override { return rs.StartRun(static_cast(position)); } Sci::Position EndRun(Sci::Position position) const override { return rs.EndRun(static_cast(position)); } void SetValueAt(Sci::Position position, int value) override { rs.SetValueAt(static_cast(position), value); } void InsertSpace(Sci::Position position, Sci::Position insertLength) override { rs.InsertSpace(static_cast(position), static_cast(insertLength)); } Sci::Position Runs() const override { return rs.Runs(); } }; template class DecorationList : public IDecorationList { int currentIndicator; int currentValue; Decoration *current; // Cached so FillRange doesn't have to search for each call. Sci::Position lengthDocument; // Ordered by indicator std::vector>> decorationList; std::vector decorationView; // Read-only view of decorationList bool clickNotified; Decoration *DecorationFromIndicator(int indicator); Decoration *Create(int indicator, Sci::Position length); void Delete(int indicator); void DeleteAnyEmpty(); void SetView(); public: DecorationList(); ~DecorationList() override; const std::vector &View() const override { return decorationView; } void SetCurrentIndicator(int indicator) override; int GetCurrentIndicator() const override { return currentIndicator; } void SetCurrentValue(int value) override; int GetCurrentValue() const override { return currentValue; } // Returns changed=true if some values may have changed FillResult FillRange(Sci::Position position, int value, Sci::Position fillLength) override; void InsertSpace(Sci::Position position, Sci::Position insertLength) override; void DeleteRange(Sci::Position position, Sci::Position deleteLength) override; void DeleteLexerDecorations() override; int AllOnFor(Sci::Position position) const override; int ValueAt(int indicator, Sci::Position position) override; Sci::Position Start(int indicator, Sci::Position position) override; Sci::Position End(int indicator, Sci::Position position) override; bool ClickNotified() const override { return clickNotified; } void SetClickNotified(bool notified) override { clickNotified = notified; } }; template DecorationList::DecorationList() : currentIndicator(0), currentValue(1), current(nullptr), lengthDocument(0), clickNotified(false) { } template DecorationList::~DecorationList() { current = nullptr; } template Decoration *DecorationList::DecorationFromIndicator(int indicator) { for (const std::unique_ptr> &deco : decorationList) { if (deco->Indicator() == indicator) { return deco.get(); } } return nullptr; } template Decoration *DecorationList::Create(int indicator, Sci::Position length) { currentIndicator = indicator; std::unique_ptr> decoNew = std::unique_ptr>(new Decoration(indicator)); decoNew->rs.InsertSpace(0, static_cast(length)); typename std::vector>>::iterator it = std::lower_bound( decorationList.begin(), decorationList.end(), decoNew, [](const std::unique_ptr> &a, const std::unique_ptr> &b) { return a->Indicator() < b->Indicator(); }); typename std::vector>>::iterator itAdded = decorationList.insert(it, std::move(decoNew)); SetView(); return itAdded->get(); } template void DecorationList::Delete(int indicator) { decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(), [indicator](const std::unique_ptr> &deco) { return deco->Indicator() == indicator; }), decorationList.end()); current = nullptr; SetView(); } template void DecorationList::SetCurrentIndicator(int indicator) { currentIndicator = indicator; current = DecorationFromIndicator(indicator); currentValue = 1; } template void DecorationList::SetCurrentValue(int value) { currentValue = value ? value : 1; } template FillResult DecorationList::FillRange(Sci::Position position, int value, Sci::Position fillLength) { if (!current) { current = DecorationFromIndicator(currentIndicator); if (!current) { current = Create(currentIndicator, lengthDocument); } } // Converting result from POS to Sci::Position as callers not polymorphic. const FillResult frInPOS = current->rs.FillRange(static_cast(position), value, static_cast(fillLength)); const FillResult fr { frInPOS.changed, frInPOS.position, frInPOS.fillLength }; if (current->Empty()) { Delete(currentIndicator); } return fr; } template void DecorationList::InsertSpace(Sci::Position position, Sci::Position insertLength) { const bool atEnd = position == lengthDocument; lengthDocument += insertLength; for (const std::unique_ptr> &deco : decorationList) { deco->rs.InsertSpace(static_cast(position), static_cast(insertLength)); if (atEnd) { deco->rs.FillRange(static_cast(position), 0, static_cast(insertLength)); } } } template void DecorationList::DeleteRange(Sci::Position position, Sci::Position deleteLength) { lengthDocument -= deleteLength; for (const std::unique_ptr> &deco : decorationList) { deco->rs.DeleteRange(static_cast(position), static_cast(deleteLength)); } DeleteAnyEmpty(); if (decorationList.size() != decorationView.size()) { // One or more empty decorations deleted so update view. current = nullptr; SetView(); } } template void DecorationList::DeleteLexerDecorations() { decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(), [](const std::unique_ptr> &deco) { return deco->Indicator() < INDIC_CONTAINER; }), decorationList.end()); current = nullptr; SetView(); } template void DecorationList::DeleteAnyEmpty() { if (lengthDocument == 0) { decorationList.clear(); } else { decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(), [](const std::unique_ptr> &deco) { return deco->Empty(); }), decorationList.end()); } } template void DecorationList::SetView() { decorationView.clear(); for (const std::unique_ptr> &deco : decorationList) { decorationView.push_back(deco.get()); } } template int DecorationList::AllOnFor(Sci::Position position) const { int mask = 0; for (const std::unique_ptr> &deco : decorationList) { if (deco->rs.ValueAt(static_cast(position))) { if (deco->Indicator() < INDIC_IME) { mask |= 1 << deco->Indicator(); } } } return mask; } template int DecorationList::ValueAt(int indicator, Sci::Position position) { const Decoration *deco = DecorationFromIndicator(indicator); if (deco) { return deco->rs.ValueAt(static_cast(position)); } return 0; } template Sci::Position DecorationList::Start(int indicator, Sci::Position position) { const Decoration *deco = DecorationFromIndicator(indicator); if (deco) { return deco->rs.StartRun(static_cast(position)); } return 0; } template Sci::Position DecorationList::End(int indicator, Sci::Position position) { const Decoration *deco = DecorationFromIndicator(indicator); if (deco) { return deco->rs.EndRun(static_cast(position)); } return 0; } } namespace Scintilla { std::unique_ptr DecorationCreate(bool largeDocument, int indicator) { if (largeDocument) return std::unique_ptr>(new Decoration(indicator)); else return std::unique_ptr>(new Decoration(indicator)); } std::unique_ptr DecorationListCreate(bool largeDocument) { if (largeDocument) return std::unique_ptr>(new DecorationList()); else return std::unique_ptr>(new DecorationList()); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Decoration.h000066400000000000000000000040301463772530400260140ustar00rootroot00000000000000/** @file Decoration.h ** Visual elements added over text. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef DECORATION_H #define DECORATION_H namespace Scintilla { class IDecoration { public: virtual ~IDecoration() {} virtual bool Empty() const = 0; virtual int Indicator() const = 0; virtual Sci::Position Length() const = 0; virtual int ValueAt(Sci::Position position) const = 0; virtual Sci::Position StartRun(Sci::Position position) const = 0; virtual Sci::Position EndRun(Sci::Position position) const = 0; virtual void SetValueAt(Sci::Position position, int value) = 0; virtual void InsertSpace(Sci::Position position, Sci::Position insertLength) = 0; virtual Sci::Position Runs() const = 0; }; class IDecorationList { public: virtual ~IDecorationList() {} virtual const std::vector &View() const =0; virtual void SetCurrentIndicator(int indicator) = 0; virtual int GetCurrentIndicator() const = 0; virtual void SetCurrentValue(int value) = 0; virtual int GetCurrentValue() const = 0; // Returns with changed=true if some values may have changed virtual FillResult FillRange(Sci::Position position, int value, Sci::Position fillLength) = 0; virtual void InsertSpace(Sci::Position position, Sci::Position insertLength) = 0; virtual void DeleteRange(Sci::Position position, Sci::Position deleteLength) = 0; virtual void DeleteLexerDecorations() = 0; virtual int AllOnFor(Sci::Position position) const = 0; virtual int ValueAt(int indicator, Sci::Position position) = 0; virtual Sci::Position Start(int indicator, Sci::Position position) = 0; virtual Sci::Position End(int indicator, Sci::Position position) = 0; virtual bool ClickNotified() const = 0; virtual void SetClickNotified(bool notified) = 0; }; std::unique_ptr DecorationCreate(bool largeDocument, int indicator); std::unique_ptr DecorationListCreate(bool largeDocument); } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Document.cpp000066400000000000000000003002461463772530400260460ustar00rootroot00000000000000// Scintilla source code edit control /** @file Document.cxx ** Text document that handles notifications, DBCS, styling, words and end of line. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NO_CXX11_REGEX #include #endif #include "Platform.h" #include "ILoader.h" #include "ILexer.h" #include "Scintilla.h" #include "CharacterSet.h" #include "CharacterCategory.h" #include "Position.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "CellBuffer.h" #include "PerLine.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "RESearch.h" #include "UniConversion.h" #include "ElapsedPeriod.h" using namespace Scintilla; void LexInterface::Colourise(Sci::Position start, Sci::Position end) { if (pdoc && instance && !performingStyle) { // Protect against reentrance, which may occur, for example, when // fold points are discovered while performing styling and the folding // code looks for child lines which may trigger styling. performingStyle = true; const Sci::Position lengthDoc = pdoc->Length(); if (end == -1) end = lengthDoc; const Sci::Position len = end - start; PLATFORM_ASSERT(len >= 0); PLATFORM_ASSERT(start + len <= lengthDoc); int styleStart = 0; if (start > 0) styleStart = pdoc->StyleAt(start - 1); if (len > 0) { instance->Lex(start, len, styleStart, pdoc); instance->Fold(start, len, styleStart, pdoc); } performingStyle = false; } } int LexInterface::LineEndTypesSupported() { if (instance) { const int interfaceVersion = instance->Version(); if (interfaceVersion >= lvSubStyles) { ILexerWithSubStyles *ssinstance = static_cast(instance); return ssinstance->LineEndTypesSupported(); } } return 0; } ActionDuration::ActionDuration(double duration_, double minDuration_, double maxDuration_) noexcept : duration(duration_), minDuration(minDuration_), maxDuration(maxDuration_) { } void ActionDuration::AddSample(size_t numberActions, double durationOfActions) noexcept { // Only adjust for multiple actions to avoid instability if (numberActions < 8) return; // Alpha value for exponential smoothing. // Most recent value contributes 25% to smoothed value. const double alpha = 0.25; const double durationOne = durationOfActions / numberActions; duration = Sci::clamp(alpha * durationOne + (1.0 - alpha) * duration, minDuration, maxDuration); } double ActionDuration::Duration() const noexcept { return duration; } Document::Document(int options) : cb((options & SC_DOCUMENTOPTION_STYLES_NONE) == 0, (options & SC_DOCUMENTOPTION_TEXT_LARGE) != 0), durationStyleOneLine(0.00001, 0.000001, 0.0001) { refCount = 0; #ifdef _WIN32 eolMode = SC_EOL_CRLF; #else eolMode = SC_EOL_LF; #endif dbcsCodePage = SC_CP_UTF8; lineEndBitSet = SC_LINE_END_TYPE_DEFAULT; endStyled = 0; styleClock = 0; enteredModification = 0; enteredStyling = 0; enteredReadOnlyCount = 0; insertionSet = false; tabInChars = 8; indentInChars = 0; actualIndentInChars = 8; useTabs = true; tabIndents = true; backspaceUnindents = false; matchesValid = false; perLineData[ldMarkers].reset(new LineMarkers()); perLineData[ldLevels].reset(new LineLevels()); perLineData[ldState].reset(new LineState()); perLineData[ldMargin].reset(new LineAnnotation()); perLineData[ldAnnotation].reset(new LineAnnotation()); decorations = DecorationListCreate(IsLarge()); cb.SetPerLine(this); cb.SetUTF8Substance(SC_CP_UTF8 == dbcsCodePage); } Document::~Document() { for (const WatcherWithUserData &watcher : watchers) { watcher.watcher->NotifyDeleted(this, watcher.userData); } } // Increase reference count and return its previous value. int Document::AddRef() { return refCount++; } // Decrease reference count and return its previous value. // Delete the document if reference count reaches zero. int SCI_METHOD Document::Release() { const int curRefCount = --refCount; if (curRefCount == 0) delete this; return curRefCount; } void Document::Init() { for (const std::unique_ptr &pl : perLineData) { if (pl) pl->Init(); } } void Document::InsertLine(Sci::Line line) { for (const std::unique_ptr &pl : perLineData) { if (pl) pl->InsertLine(line); } } void Document::RemoveLine(Sci::Line line) { for (const std::unique_ptr &pl : perLineData) { if (pl) pl->RemoveLine(line); } } LineMarkers *Document::Markers() const { return static_cast(perLineData[ldMarkers].get()); } LineLevels *Document::Levels() const { return static_cast(perLineData[ldLevels].get()); } LineState *Document::States() const { return static_cast(perLineData[ldState].get()); } LineAnnotation *Document::Margins() const { return static_cast(perLineData[ldMargin].get()); } LineAnnotation *Document::Annotations() const { return static_cast(perLineData[ldAnnotation].get()); } int Document::LineEndTypesSupported() const { if ((SC_CP_UTF8 == dbcsCodePage) && pli) return pli->LineEndTypesSupported(); else return 0; } bool Document::SetDBCSCodePage(int dbcsCodePage_) { if (dbcsCodePage != dbcsCodePage_) { dbcsCodePage = dbcsCodePage_; SetCaseFolder(nullptr); cb.SetLineEndTypes(lineEndBitSet & LineEndTypesSupported()); cb.SetUTF8Substance(SC_CP_UTF8 == dbcsCodePage); ModifiedAt(0); // Need to restyle whole document return true; } else { return false; } } bool Document::SetLineEndTypesAllowed(int lineEndBitSet_) { if (lineEndBitSet != lineEndBitSet_) { lineEndBitSet = lineEndBitSet_; const int lineEndBitSetActive = lineEndBitSet & LineEndTypesSupported(); if (lineEndBitSetActive != cb.GetLineEndTypes()) { ModifiedAt(0); cb.SetLineEndTypes(lineEndBitSetActive); return true; } else { return false; } } else { return false; } } void Document::SetSavePoint() { cb.SetSavePoint(); NotifySavePoint(true); } void Document::TentativeUndo() { if (!TentativeActive()) return; CheckReadOnly(); if (enteredModification == 0) { enteredModification++; if (!cb.IsReadOnly()) { const bool startSavePoint = cb.IsSavePoint(); bool multiLine = false; const int steps = cb.TentativeSteps(); //Platform::DebugPrintf("Steps=%d\n", steps); for (int step = 0; step < steps; step++) { const Sci::Line prevLinesTotal = LinesTotal(); const Action &action = cb.GetUndoStep(); if (action.at == removeAction) { NotifyModified(DocModification( SC_MOD_BEFOREINSERT | SC_PERFORMED_UNDO, action)); } else if (action.at == containerAction) { DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_UNDO); dm.token = action.position; NotifyModified(dm); } else { NotifyModified(DocModification( SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action)); } cb.PerformUndoStep(); if (action.at != containerAction) { ModifiedAt(action.position); } int modFlags = SC_PERFORMED_UNDO; // With undo, an insertion action becomes a deletion notification if (action.at == removeAction) { modFlags |= SC_MOD_INSERTTEXT; } else if (action.at == insertAction) { modFlags |= SC_MOD_DELETETEXT; } if (steps > 1) modFlags |= SC_MULTISTEPUNDOREDO; const Sci::Line linesAdded = LinesTotal() - prevLinesTotal; if (linesAdded != 0) multiLine = true; if (step == steps - 1) { modFlags |= SC_LASTSTEPINUNDOREDO; if (multiLine) modFlags |= SC_MULTILINEUNDOREDO; } NotifyModified(DocModification(modFlags, action.position, action.lenData, linesAdded, action.data.get())); } const bool endSavePoint = cb.IsSavePoint(); if (startSavePoint != endSavePoint) NotifySavePoint(endSavePoint); cb.TentativeCommit(); } enteredModification--; } } int Document::GetMark(Sci::Line line) const { return Markers()->MarkValue(line); } Sci::Line Document::MarkerNext(Sci::Line lineStart, int mask) const { return Markers()->MarkerNext(lineStart, mask); } int Document::AddMark(Sci::Line line, int markerNum) { if (line >= 0 && line <= LinesTotal()) { const int prev = Markers()->AddMark(line, markerNum, LinesTotal()); const DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, nullptr, line); NotifyModified(mh); return prev; } else { return -1; } } void Document::AddMarkSet(Sci::Line line, int valueSet) { if (line < 0 || line > LinesTotal()) { return; } unsigned int m = valueSet; for (int i = 0; m; i++, m >>= 1) { if (m & 1) Markers()->AddMark(line, i, LinesTotal()); } const DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, nullptr, line); NotifyModified(mh); } void Document::DeleteMark(Sci::Line line, int markerNum) { Markers()->DeleteMark(line, markerNum, false); const DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, nullptr, line); NotifyModified(mh); } void Document::DeleteMarkFromHandle(int markerHandle) { Markers()->DeleteMarkFromHandle(markerHandle); DocModification mh(SC_MOD_CHANGEMARKER); mh.line = -1; NotifyModified(mh); } void Document::DeleteAllMarks(int markerNum) { bool someChanges = false; for (Sci::Line line = 0; line < LinesTotal(); line++) { if (Markers()->DeleteMark(line, markerNum, true)) someChanges = true; } if (someChanges) { DocModification mh(SC_MOD_CHANGEMARKER); mh.line = -1; NotifyModified(mh); } } Sci::Line Document::LineFromHandle(int markerHandle) const { return Markers()->LineFromHandle(markerHandle); } Sci_Position SCI_METHOD Document::LineStart(Sci_Position line) const { return cb.LineStart(static_cast(line)); } bool Document::IsLineStartPosition(Sci::Position position) const { return LineStart(LineFromPosition(position)) == position; } Sci_Position SCI_METHOD Document::LineEnd(Sci_Position line) const { if (line >= LinesTotal() - 1) { return LineStart(line + 1); } else { Sci::Position position = LineStart(line + 1); if (SC_CP_UTF8 == dbcsCodePage) { const unsigned char bytes[] = { cb.UCharAt(position-3), cb.UCharAt(position-2), cb.UCharAt(position-1), }; if (UTF8IsSeparator(bytes)) { return position - UTF8SeparatorLength; } if (UTF8IsNEL(bytes+1)) { return position - UTF8NELLength; } } position--; // Back over CR or LF // When line terminator is CR+LF, may need to go back one more if ((position > LineStart(line)) && (cb.CharAt(position - 1) == '\r')) { position--; } return position; } } void SCI_METHOD Document::SetErrorStatus(int status) { // Tell the watchers an error has occurred. for (const WatcherWithUserData &watcher : watchers) { watcher.watcher->NotifyErrorOccurred(this, watcher.userData, status); } } Sci_Position SCI_METHOD Document::LineFromPosition(Sci_Position pos) const { return cb.LineFromPosition(pos); } Sci::Line Document::SciLineFromPosition(Sci::Position pos) const noexcept { // Avoids casting in callers for this very common function return cb.LineFromPosition(pos); } Sci::Position Document::LineEndPosition(Sci::Position position) const { return LineEnd(LineFromPosition(position)); } bool Document::IsLineEndPosition(Sci::Position position) const { return LineEnd(LineFromPosition(position)) == position; } bool Document::IsPositionInLineEnd(Sci::Position position) const { return position >= LineEnd(LineFromPosition(position)); } Sci::Position Document::VCHomePosition(Sci::Position position) const { const Sci::Line line = SciLineFromPosition(position); const Sci::Position startPosition = LineStart(line); const Sci::Position endLine = LineEnd(line); Sci::Position startText = startPosition; while (startText < endLine && (cb.CharAt(startText) == ' ' || cb.CharAt(startText) == '\t')) startText++; if (position == startText) return startPosition; else return startText; } Sci::Position Document::IndexLineStart(Sci::Line line, int lineCharacterIndex) const { return cb.IndexLineStart(line, lineCharacterIndex); } Sci::Line Document::LineFromPositionIndex(Sci::Position pos, int lineCharacterIndex) const { return cb.LineFromPositionIndex(pos, lineCharacterIndex); } int SCI_METHOD Document::SetLevel(Sci_Position line, int level) { const int prev = Levels()->SetLevel(static_cast(line), level, LinesTotal()); if (prev != level) { DocModification mh(SC_MOD_CHANGEFOLD | SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, nullptr, static_cast(line)); mh.foldLevelNow = level; mh.foldLevelPrev = prev; NotifyModified(mh); } return prev; } int SCI_METHOD Document::GetLevel(Sci_Position line) const { return Levels()->GetLevel(static_cast(line)); } void Document::ClearLevels() { Levels()->ClearLevels(); } static bool IsSubordinate(int levelStart, int levelTry) { if (levelTry & SC_FOLDLEVELWHITEFLAG) return true; else return LevelNumber(levelStart) < LevelNumber(levelTry); } Sci::Line Document::GetLastChild(Sci::Line lineParent, int level, Sci::Line lastLine) { if (level == -1) level = LevelNumber(GetLevel(lineParent)); const Sci::Line maxLine = LinesTotal(); const Sci::Line lookLastLine = (lastLine != -1) ? std::min(LinesTotal() - 1, lastLine) : -1; Sci::Line lineMaxSubord = lineParent; while (lineMaxSubord < maxLine - 1) { EnsureStyledTo(LineStart(lineMaxSubord + 2)); if (!IsSubordinate(level, GetLevel(lineMaxSubord + 1))) break; if ((lookLastLine != -1) && (lineMaxSubord >= lookLastLine) && !(GetLevel(lineMaxSubord) & SC_FOLDLEVELWHITEFLAG)) break; lineMaxSubord++; } if (lineMaxSubord > lineParent) { if (level > LevelNumber(GetLevel(lineMaxSubord + 1))) { // Have chewed up some whitespace that belongs to a parent so seek back if (GetLevel(lineMaxSubord) & SC_FOLDLEVELWHITEFLAG) { lineMaxSubord--; } } } return lineMaxSubord; } Sci::Line Document::GetFoldParent(Sci::Line line) const { const int level = LevelNumber(GetLevel(line)); Sci::Line lineLook = line - 1; while ((lineLook > 0) && ( (!(GetLevel(lineLook) & SC_FOLDLEVELHEADERFLAG)) || (LevelNumber(GetLevel(lineLook)) >= level)) ) { lineLook--; } if ((GetLevel(lineLook) & SC_FOLDLEVELHEADERFLAG) && (LevelNumber(GetLevel(lineLook)) < level)) { return lineLook; } else { return -1; } } void Document::GetHighlightDelimiters(HighlightDelimiter &highlightDelimiter, Sci::Line line, Sci::Line lastLine) { const int level = GetLevel(line); const Sci::Line lookLastLine = std::max(line, lastLine) + 1; Sci::Line lookLine = line; int lookLineLevel = level; int lookLineLevelNum = LevelNumber(lookLineLevel); while ((lookLine > 0) && ((lookLineLevel & SC_FOLDLEVELWHITEFLAG) || ((lookLineLevel & SC_FOLDLEVELHEADERFLAG) && (lookLineLevelNum >= LevelNumber(GetLevel(lookLine + 1)))))) { lookLineLevel = GetLevel(--lookLine); lookLineLevelNum = LevelNumber(lookLineLevel); } Sci::Line beginFoldBlock = (lookLineLevel & SC_FOLDLEVELHEADERFLAG) ? lookLine : GetFoldParent(lookLine); if (beginFoldBlock == -1) { highlightDelimiter.Clear(); return; } Sci::Line endFoldBlock = GetLastChild(beginFoldBlock, -1, lookLastLine); Sci::Line firstChangeableLineBefore = -1; if (endFoldBlock < line) { lookLine = beginFoldBlock - 1; lookLineLevel = GetLevel(lookLine); lookLineLevelNum = LevelNumber(lookLineLevel); while ((lookLine >= 0) && (lookLineLevelNum >= SC_FOLDLEVELBASE)) { if (lookLineLevel & SC_FOLDLEVELHEADERFLAG) { if (GetLastChild(lookLine, -1, lookLastLine) == line) { beginFoldBlock = lookLine; endFoldBlock = line; firstChangeableLineBefore = line - 1; } } if ((lookLine > 0) && (lookLineLevelNum == SC_FOLDLEVELBASE) && (LevelNumber(GetLevel(lookLine - 1)) > lookLineLevelNum)) break; lookLineLevel = GetLevel(--lookLine); lookLineLevelNum = LevelNumber(lookLineLevel); } } if (firstChangeableLineBefore == -1) { for (lookLine = line - 1, lookLineLevel = GetLevel(lookLine), lookLineLevelNum = LevelNumber(lookLineLevel); lookLine >= beginFoldBlock; lookLineLevel = GetLevel(--lookLine), lookLineLevelNum = LevelNumber(lookLineLevel)) { if ((lookLineLevel & SC_FOLDLEVELWHITEFLAG) || (lookLineLevelNum > LevelNumber(level))) { firstChangeableLineBefore = lookLine; break; } } } if (firstChangeableLineBefore == -1) firstChangeableLineBefore = beginFoldBlock - 1; Sci::Line firstChangeableLineAfter = -1; for (lookLine = line + 1, lookLineLevel = GetLevel(lookLine), lookLineLevelNum = LevelNumber(lookLineLevel); lookLine <= endFoldBlock; lookLineLevel = GetLevel(++lookLine), lookLineLevelNum = LevelNumber(lookLineLevel)) { if ((lookLineLevel & SC_FOLDLEVELHEADERFLAG) && (lookLineLevelNum < LevelNumber(GetLevel(lookLine + 1)))) { firstChangeableLineAfter = lookLine; break; } } if (firstChangeableLineAfter == -1) firstChangeableLineAfter = endFoldBlock + 1; highlightDelimiter.beginFoldBlock = beginFoldBlock; highlightDelimiter.endFoldBlock = endFoldBlock; highlightDelimiter.firstChangeableLineBefore = firstChangeableLineBefore; highlightDelimiter.firstChangeableLineAfter = firstChangeableLineAfter; } Sci::Position Document::ClampPositionIntoDocument(Sci::Position pos) const { return Sci::clamp(pos, static_cast(0), static_cast(Length())); } bool Document::IsCrLf(Sci::Position pos) const { if (pos < 0) return false; if (pos >= (Length() - 1)) return false; return (cb.CharAt(pos) == '\r') && (cb.CharAt(pos + 1) == '\n'); } int Document::LenChar(Sci::Position pos) { if (pos < 0) { return 1; } else if (IsCrLf(pos)) { return 2; } else if (SC_CP_UTF8 == dbcsCodePage) { const unsigned char leadByte = cb.UCharAt(pos); const int widthCharBytes = UTF8BytesOfLead[leadByte]; const Sci::Position lengthDoc = Length(); if ((pos + widthCharBytes) > lengthDoc) return static_cast(lengthDoc - pos); else return widthCharBytes; } else if (dbcsCodePage) { return IsDBCSLeadByteNoExcept(cb.CharAt(pos)) ? 2 : 1; } else { return 1; } } bool Document::InGoodUTF8(Sci::Position pos, Sci::Position &start, Sci::Position &end) const noexcept { Sci::Position trail = pos; while ((trail>0) && (pos-trail < UTF8MaxBytes) && UTF8IsTrailByte(cb.UCharAt(trail-1))) trail--; start = (trail > 0) ? trail-1 : trail; const unsigned char leadByte = cb.UCharAt(start); const int widthCharBytes = UTF8BytesOfLead[leadByte]; if (widthCharBytes == 1) { return false; } else { const int trailBytes = widthCharBytes - 1; const Sci::Position len = pos - start; if (len > trailBytes) // pos too far from lead return false; unsigned char charBytes[UTF8MaxBytes] = {leadByte,0,0,0}; for (Sci::Position b=1; b= Length()) return Length(); // PLATFORM_ASSERT(pos > 0 && pos < Length()); if (checkLineEnd && IsCrLf(pos - 1)) { if (moveDir > 0) return pos + 1; else return pos - 1; } if (dbcsCodePage) { if (SC_CP_UTF8 == dbcsCodePage) { const unsigned char ch = cb.UCharAt(pos); // If ch is not a trail byte then pos is valid intercharacter position if (UTF8IsTrailByte(ch)) { Sci::Position startUTF = pos; Sci::Position endUTF = pos; if (InGoodUTF8(pos, startUTF, endUTF)) { // ch is a trail byte within a UTF-8 character if (moveDir > 0) pos = endUTF; else pos = startUTF; } // Else invalid UTF-8 so return position of isolated trail byte } } else { // Anchor DBCS calculations at start of line because start of line can // not be a DBCS trail byte. const Sci::Position posStartLine = LineStart(LineFromPosition(pos)); if (pos == posStartLine) return pos; // Step back until a non-lead-byte is found. Sci::Position posCheck = pos; while ((posCheck > posStartLine) && IsDBCSLeadByteNoExcept(cb.CharAt(posCheck-1))) posCheck--; // Check from known start of character. while (posCheck < pos) { const int mbsize = IsDBCSLeadByteNoExcept(cb.CharAt(posCheck)) ? 2 : 1; if (posCheck + mbsize == pos) { return pos; } else if (posCheck + mbsize > pos) { if (moveDir > 0) { return posCheck + mbsize; } else { return posCheck; } } posCheck += mbsize; } } } return pos; } // NextPosition moves between valid positions - it can not handle a position in the middle of a // multi-byte character. It is used to iterate through text more efficiently than MovePositionOutsideChar. // A \r\n pair is treated as two characters. Sci::Position Document::NextPosition(Sci::Position pos, int moveDir) const noexcept { // If out of range, just return minimum/maximum value. const int increment = (moveDir > 0) ? 1 : -1; if (pos + increment <= 0) return 0; if (pos + increment >= cb.Length()) return cb.Length(); if (dbcsCodePage) { if (SC_CP_UTF8 == dbcsCodePage) { if (increment == 1) { // Simple forward movement case so can avoid some checks const unsigned char leadByte = cb.UCharAt(pos); if (UTF8IsAscii(leadByte)) { // Single byte character or invalid pos++; } else { const int widthCharBytes = UTF8BytesOfLead[leadByte]; unsigned char charBytes[UTF8MaxBytes] = {leadByte,0,0,0}; for (int b=1; b 0) { const int mbsize = IsDBCSLeadByteNoExcept(cb.CharAt(pos)) ? 2 : 1; pos += mbsize; if (pos > cb.Length()) pos = cb.Length(); } else { // Anchor DBCS calculations at start of line because start of line can // not be a DBCS trail byte. const Sci::Position posStartLine = cb.LineStart(cb.LineFromPosition(pos)); // See http://msdn.microsoft.com/en-us/library/cc194792%28v=MSDN.10%29.aspx // http://msdn.microsoft.com/en-us/library/cc194790.aspx if ((pos - 1) <= posStartLine) { return pos - 1; } else if (IsDBCSLeadByteNoExcept(cb.CharAt(pos - 1))) { // Must actually be trail byte return pos - 2; } else { // Otherwise, step back until a non-lead-byte is found. Sci::Position posTemp = pos - 1; while (posStartLine <= --posTemp && IsDBCSLeadByteNoExcept(cb.CharAt(posTemp))) ; // Now posTemp+1 must point to the beginning of a character, // so figure out whether we went back an even or an odd // number of bytes and go back 1 or 2 bytes, respectively. return (pos - 1 - ((pos - posTemp) & 1)); } } } } else { pos += increment; } return pos; } bool Document::NextCharacter(Sci::Position &pos, int moveDir) const noexcept { // Returns true if pos changed Sci::Position posNext = NextPosition(pos, moveDir); if (posNext == pos) { return false; } else { pos = posNext; return true; } } Document::CharacterExtracted Document::CharacterAfter(Sci::Position position) const { if (position >= Length()) { return CharacterExtracted(unicodeReplacementChar, 0); } const unsigned char leadByte = cb.UCharAt(position); if (!dbcsCodePage || UTF8IsAscii(leadByte)) { // Common case: ASCII character return CharacterExtracted(leadByte, 1); } if (SC_CP_UTF8 == dbcsCodePage) { const int widthCharBytes = UTF8BytesOfLead[leadByte]; unsigned char charBytes[UTF8MaxBytes] = { leadByte, 0, 0, 0 }; for (int b = 1; b(endUTF - startUTF); unsigned char charBytes[UTF8MaxBytes] = { 0, 0, 0, 0 }; for (int b = 0; b 0) ? 1 : -1; while (characterOffset != 0) { const Sci::Position posNext = NextPosition(pos, increment); if (posNext == pos) return INVALID_POSITION; pos = posNext; characterOffset -= increment; } } else { pos = positionStart + characterOffset; if ((pos < 0) || (pos > Length())) return INVALID_POSITION; } return pos; } Sci::Position Document::GetRelativePositionUTF16(Sci::Position positionStart, Sci::Position characterOffset) const { Sci::Position pos = positionStart; if (dbcsCodePage) { const int increment = (characterOffset > 0) ? 1 : -1; while (characterOffset != 0) { const Sci::Position posNext = NextPosition(pos, increment); if (posNext == pos) return INVALID_POSITION; if (std::abs(pos-posNext) > 3) // 4 byte character = 2*UTF16. characterOffset -= increment; pos = posNext; characterOffset -= increment; } } else { pos = positionStart + characterOffset; if ((pos < 0) || (pos > Length())) return INVALID_POSITION; } return pos; } int SCI_METHOD Document::GetCharacterAndWidth(Sci_Position position, Sci_Position *pWidth) const { int character; int bytesInCharacter = 1; if (dbcsCodePage) { const unsigned char leadByte = cb.UCharAt(position); if (SC_CP_UTF8 == dbcsCodePage) { if (UTF8IsAscii(leadByte)) { // Single byte character or invalid character = leadByte; } else { const int widthCharBytes = UTF8BytesOfLead[leadByte]; unsigned char charBytes[UTF8MaxBytes] = {leadByte,0,0,0}; for (int b=1; b= 0x81) && (uch <= 0x9F)) || ((uch >= 0xE0) && (uch <= 0xFC)); // Lead bytes F0 to FC may be a Microsoft addition. case 936: // GBK return (uch >= 0x81) && (uch <= 0xFE); case 949: // Korean Wansung KS C-5601-1987 return (uch >= 0x81) && (uch <= 0xFE); case 950: // Big5 return (uch >= 0x81) && (uch <= 0xFE); case 1361: // Korean Johab KS C-5601-1992 return ((uch >= 0x84) && (uch <= 0xD3)) || ((uch >= 0xD8) && (uch <= 0xDE)) || ((uch >= 0xE0) && (uch <= 0xF9)); } return false; } bool Document::IsDBCSLeadByteInvalid(char ch) const noexcept { const unsigned char lead = ch; switch (dbcsCodePage) { case 932: // Shift_jis return (lead == 0x85) || (lead == 0x86) || (lead == 0xEB) || (lead == 0xEC) || (lead == 0xEF) || (lead == 0xFA) || (lead == 0xFB) || (lead == 0xFC); case 936: // GBK return (lead == 0x80) || (lead == 0xFF); case 949: // Korean Wansung KS C-5601-1987 return (lead == 0x80) || (lead == 0xC9) || (lead >= 0xFE); case 950: // Big5 return ((lead >= 0x80) && (lead <= 0xA0)) || (lead == 0xC8) || (lead >= 0xFA); case 1361: // Korean Johab KS C-5601-1992 return ((lead >= 0x80) && (lead <= 0x83)) || ((lead >= 0xD4) && (lead <= 0xD8)) || (lead == 0xDF) || (lead >= 0xFA); } return false; } bool Document::IsDBCSTrailByteInvalid(char ch) const noexcept { const unsigned char trail = ch; switch (dbcsCodePage) { case 932: // Shift_jis return (trail <= 0x3F) || (trail == 0x7F) || (trail >= 0xFD); case 936: // GBK return (trail <= 0x3F) || (trail == 0x7F) || (trail == 0xFF); case 949: // Korean Wansung KS C-5601-1987 return (trail <= 0x40) || ((trail >= 0x5B) && (trail <= 0x60)) || ((trail >= 0x7B) && (trail <= 0x80)) || (trail == 0xFF); case 950: // Big5 return (trail <= 0x3F) || ((trail >= 0x7F) && (trail <= 0xA0)) || (trail == 0xFF); case 1361: // Korean Johab KS C-5601-1992 return (trail <= 0x30) || (trail == 0x7F) || (trail == 0x80) || (trail == 0xFF); } return false; } int Document::DBCSDrawBytes(const char *text, int len) const noexcept { if (len <= 1) { return len; } if (IsDBCSLeadByteNoExcept(text[0])) { return IsDBCSTrailByteInvalid(text[1]) ? 1 : 2; } else { return 1; } } static inline bool IsSpaceOrTab(int ch) noexcept { return ch == ' ' || ch == '\t'; } // Need to break text into segments near lengthSegment but taking into // account the encoding to not break inside a UTF-8 or DBCS character // and also trying to avoid breaking inside a pair of combining characters. // The segment length must always be long enough (more than 4 bytes) // so that there will be at least one whole character to make a segment. // For UTF-8, text must consist only of valid whole characters. // In preference order from best to worst: // 1) Break after space // 2) Break before punctuation // 3) Break after whole character int Document::SafeSegment(const char *text, int length, int lengthSegment) const noexcept { if (length <= lengthSegment) return length; int lastSpaceBreak = -1; int lastPunctuationBreak = -1; int lastEncodingAllowedBreak = 0; for (int j=0; j < lengthSegment;) { const unsigned char ch = text[j]; if (j > 0) { if (IsSpaceOrTab(text[j - 1]) && !IsSpaceOrTab(text[j])) { lastSpaceBreak = j; } if (ch < 'A') { lastPunctuationBreak = j; } } lastEncodingAllowedBreak = j; if (dbcsCodePage == SC_CP_UTF8) { j += UTF8BytesOfLead[ch]; } else if (dbcsCodePage) { j += IsDBCSLeadByteNoExcept(ch) ? 2 : 1; } else { j++; } } if (lastSpaceBreak >= 0) { return lastSpaceBreak; } else if (lastPunctuationBreak >= 0) { return lastPunctuationBreak; } return lastEncodingAllowedBreak; } EncodingFamily Document::CodePageFamily() const noexcept { if (SC_CP_UTF8 == dbcsCodePage) return efUnicode; else if (dbcsCodePage) return efDBCS; else return efEightBit; } void Document::ModifiedAt(Sci::Position pos) noexcept { if (endStyled > pos) endStyled = pos; } void Document::CheckReadOnly() { if (cb.IsReadOnly() && enteredReadOnlyCount == 0) { enteredReadOnlyCount++; NotifyModifyAttempt(); enteredReadOnlyCount--; } } // Document only modified by gateways DeleteChars, InsertString, Undo, Redo, and SetStyleAt. // SetStyleAt does not change the persistent state of a document bool Document::DeleteChars(Sci::Position pos, Sci::Position len) { if (pos < 0) return false; if (len <= 0) return false; if ((pos + len) > Length()) return false; CheckReadOnly(); if (enteredModification != 0) { return false; } else { enteredModification++; if (!cb.IsReadOnly()) { NotifyModified( DocModification( SC_MOD_BEFOREDELETE | SC_PERFORMED_USER, pos, len, 0, 0)); const Sci::Line prevLinesTotal = LinesTotal(); const bool startSavePoint = cb.IsSavePoint(); bool startSequence = false; const char *text = cb.DeleteChars(pos, len, startSequence); if (startSavePoint && cb.IsCollectingUndo()) NotifySavePoint(!startSavePoint); if ((pos < Length()) || (pos == 0)) ModifiedAt(pos); else ModifiedAt(pos-1); NotifyModified( DocModification( SC_MOD_DELETETEXT | SC_PERFORMED_USER | (startSequence?SC_STARTACTION:0), pos, len, LinesTotal() - prevLinesTotal, text)); } enteredModification--; } return !cb.IsReadOnly(); } /** * Insert a string with a length. */ Sci::Position Document::InsertString(Sci::Position position, const char *s, Sci::Position insertLength) { if (insertLength <= 0) { return 0; } CheckReadOnly(); // Application may change read only state here if (cb.IsReadOnly()) { return 0; } if (enteredModification != 0) { return 0; } enteredModification++; insertionSet = false; insertion.clear(); NotifyModified( DocModification( SC_MOD_INSERTCHECK, position, insertLength, 0, s)); if (insertionSet) { s = insertion.c_str(); insertLength = insertion.length(); } NotifyModified( DocModification( SC_MOD_BEFOREINSERT | SC_PERFORMED_USER, position, insertLength, 0, s)); const Sci::Line prevLinesTotal = LinesTotal(); const bool startSavePoint = cb.IsSavePoint(); bool startSequence = false; const char *text = cb.InsertString(position, s, insertLength, startSequence); if (startSavePoint && cb.IsCollectingUndo()) NotifySavePoint(!startSavePoint); ModifiedAt(position); NotifyModified( DocModification( SC_MOD_INSERTTEXT | SC_PERFORMED_USER | (startSequence?SC_STARTACTION:0), position, insertLength, LinesTotal() - prevLinesTotal, text)); if (insertionSet) { // Free memory as could be large std::string().swap(insertion); } enteredModification--; return insertLength; } void Document::ChangeInsertion(const char *s, Sci::Position length) { insertionSet = true; insertion.assign(s, length); } int SCI_METHOD Document::AddData(const char *data, Sci_Position length) { try { const Sci::Position position = Length(); InsertString(position, data, length); } catch (std::bad_alloc &) { return SC_STATUS_BADALLOC; } catch (...) { return SC_STATUS_FAILURE; } return 0; } void * SCI_METHOD Document::ConvertToDocument() { return this; } Sci::Position Document::Undo() { Sci::Position newPos = -1; CheckReadOnly(); if ((enteredModification == 0) && (cb.IsCollectingUndo())) { enteredModification++; if (!cb.IsReadOnly()) { const bool startSavePoint = cb.IsSavePoint(); bool multiLine = false; const int steps = cb.StartUndo(); //Platform::DebugPrintf("Steps=%d\n", steps); Sci::Position coalescedRemovePos = -1; Sci::Position coalescedRemoveLen = 0; Sci::Position prevRemoveActionPos = -1; Sci::Position prevRemoveActionLen = 0; for (int step = 0; step < steps; step++) { const Sci::Line prevLinesTotal = LinesTotal(); const Action &action = cb.GetUndoStep(); if (action.at == removeAction) { NotifyModified(DocModification( SC_MOD_BEFOREINSERT | SC_PERFORMED_UNDO, action)); } else if (action.at == containerAction) { DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_UNDO); dm.token = action.position; NotifyModified(dm); if (!action.mayCoalesce) { coalescedRemovePos = -1; coalescedRemoveLen = 0; prevRemoveActionPos = -1; prevRemoveActionLen = 0; } } else { NotifyModified(DocModification( SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action)); } cb.PerformUndoStep(); if (action.at != containerAction) { ModifiedAt(action.position); newPos = action.position; } int modFlags = SC_PERFORMED_UNDO; // With undo, an insertion action becomes a deletion notification if (action.at == removeAction) { newPos += action.lenData; modFlags |= SC_MOD_INSERTTEXT; if ((coalescedRemoveLen > 0) && (action.position == prevRemoveActionPos || action.position == (prevRemoveActionPos + prevRemoveActionLen))) { coalescedRemoveLen += action.lenData; newPos = coalescedRemovePos + coalescedRemoveLen; } else { coalescedRemovePos = action.position; coalescedRemoveLen = action.lenData; } prevRemoveActionPos = action.position; prevRemoveActionLen = action.lenData; } else if (action.at == insertAction) { modFlags |= SC_MOD_DELETETEXT; coalescedRemovePos = -1; coalescedRemoveLen = 0; prevRemoveActionPos = -1; prevRemoveActionLen = 0; } if (steps > 1) modFlags |= SC_MULTISTEPUNDOREDO; const Sci::Line linesAdded = LinesTotal() - prevLinesTotal; if (linesAdded != 0) multiLine = true; if (step == steps - 1) { modFlags |= SC_LASTSTEPINUNDOREDO; if (multiLine) modFlags |= SC_MULTILINEUNDOREDO; } NotifyModified(DocModification(modFlags, action.position, action.lenData, linesAdded, action.data.get())); } const bool endSavePoint = cb.IsSavePoint(); if (startSavePoint != endSavePoint) NotifySavePoint(endSavePoint); } enteredModification--; } return newPos; } Sci::Position Document::Redo() { Sci::Position newPos = -1; CheckReadOnly(); if ((enteredModification == 0) && (cb.IsCollectingUndo())) { enteredModification++; if (!cb.IsReadOnly()) { const bool startSavePoint = cb.IsSavePoint(); bool multiLine = false; const int steps = cb.StartRedo(); for (int step = 0; step < steps; step++) { const Sci::Line prevLinesTotal = LinesTotal(); const Action &action = cb.GetRedoStep(); if (action.at == insertAction) { NotifyModified(DocModification( SC_MOD_BEFOREINSERT | SC_PERFORMED_REDO, action)); } else if (action.at == containerAction) { DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_REDO); dm.token = action.position; NotifyModified(dm); } else { NotifyModified(DocModification( SC_MOD_BEFOREDELETE | SC_PERFORMED_REDO, action)); } cb.PerformRedoStep(); if (action.at != containerAction) { ModifiedAt(action.position); newPos = action.position; } int modFlags = SC_PERFORMED_REDO; if (action.at == insertAction) { newPos += action.lenData; modFlags |= SC_MOD_INSERTTEXT; } else if (action.at == removeAction) { modFlags |= SC_MOD_DELETETEXT; } if (steps > 1) modFlags |= SC_MULTISTEPUNDOREDO; const Sci::Line linesAdded = LinesTotal() - prevLinesTotal; if (linesAdded != 0) multiLine = true; if (step == steps - 1) { modFlags |= SC_LASTSTEPINUNDOREDO; if (multiLine) modFlags |= SC_MULTILINEUNDOREDO; } NotifyModified( DocModification(modFlags, action.position, action.lenData, linesAdded, action.data.get())); } const bool endSavePoint = cb.IsSavePoint(); if (startSavePoint != endSavePoint) NotifySavePoint(endSavePoint); } enteredModification--; } return newPos; } void Document::DelChar(Sci::Position pos) { DeleteChars(pos, LenChar(pos)); } void Document::DelCharBack(Sci::Position pos) { if (pos <= 0) { return; } else if (IsCrLf(pos - 2)) { DeleteChars(pos - 2, 2); } else if (dbcsCodePage) { const Sci::Position startChar = NextPosition(pos, -1); DeleteChars(startChar, pos - startChar); } else { DeleteChars(pos - 1, 1); } } static Sci::Position NextTab(Sci::Position pos, Sci::Position tabSize) noexcept { return ((pos / tabSize) + 1) * tabSize; } static std::string CreateIndentation(Sci::Position indent, int tabSize, bool insertSpaces) { std::string indentation; if (!insertSpaces) { while (indent >= tabSize) { indentation += '\t'; indent -= tabSize; } } while (indent > 0) { indentation += ' '; indent--; } return indentation; } int SCI_METHOD Document::GetLineIndentation(Sci_Position line) { int indent = 0; if ((line >= 0) && (line < LinesTotal())) { const Sci::Position lineStart = LineStart(line); const Sci::Position length = Length(); for (Sci::Position i = lineStart; i < length; i++) { const char ch = cb.CharAt(i); if (ch == ' ') indent++; else if (ch == '\t') indent = static_cast(NextTab(indent, tabInChars)); else return indent; } } return indent; } Sci::Position Document::SetLineIndentation(Sci::Line line, Sci::Position indent) { const int indentOfLine = GetLineIndentation(line); if (indent < 0) indent = 0; if (indent != indentOfLine) { std::string linebuf = CreateIndentation(indent, tabInChars, !useTabs); const Sci::Position thisLineStart = LineStart(line); const Sci::Position indentPos = GetLineIndentPosition(line); UndoGroup ug(this); DeleteChars(thisLineStart, indentPos - thisLineStart); return thisLineStart + InsertString(thisLineStart, linebuf.c_str(), linebuf.length()); } else { return GetLineIndentPosition(line); } } Sci::Position Document::GetLineIndentPosition(Sci::Line line) const { if (line < 0) return 0; Sci::Position pos = LineStart(line); const Sci::Position length = Length(); while ((pos < length) && IsSpaceOrTab(cb.CharAt(pos))) { pos++; } return pos; } Sci::Position Document::GetColumn(Sci::Position pos) { Sci::Position column = 0; const Sci::Line line = SciLineFromPosition(pos); if ((line >= 0) && (line < LinesTotal())) { for (Sci::Position i = LineStart(line); i < pos;) { const char ch = cb.CharAt(i); if (ch == '\t') { column = NextTab(column, tabInChars); i++; } else if (ch == '\r') { return column; } else if (ch == '\n') { return column; } else if (i >= Length()) { return column; } else { column++; i = NextPosition(i, 1); } } } return column; } Sci::Position Document::CountCharacters(Sci::Position startPos, Sci::Position endPos) const { startPos = MovePositionOutsideChar(startPos, 1, false); endPos = MovePositionOutsideChar(endPos, -1, false); Sci::Position count = 0; Sci::Position i = startPos; while (i < endPos) { count++; i = NextPosition(i, 1); } return count; } Sci::Position Document::CountUTF16(Sci::Position startPos, Sci::Position endPos) const { startPos = MovePositionOutsideChar(startPos, 1, false); endPos = MovePositionOutsideChar(endPos, -1, false); Sci::Position count = 0; Sci::Position i = startPos; while (i < endPos) { count++; const Sci::Position next = NextPosition(i, 1); if ((next - i) > 3) count++; i = next; } return count; } Sci::Position Document::FindColumn(Sci::Line line, Sci::Position column) { Sci::Position position = LineStart(line); if ((line >= 0) && (line < LinesTotal())) { Sci::Position columnCurrent = 0; while ((columnCurrent < column) && (position < Length())) { const char ch = cb.CharAt(position); if (ch == '\t') { columnCurrent = NextTab(columnCurrent, tabInChars); if (columnCurrent > column) return position; position++; } else if (ch == '\r') { return position; } else if (ch == '\n') { return position; } else { columnCurrent++; position = NextPosition(position, 1); } } } return position; } void Document::Indent(bool forwards, Sci::Line lineBottom, Sci::Line lineTop) { // Dedent - suck white space off the front of the line to dedent by equivalent of a tab for (Sci::Line line = lineBottom; line >= lineTop; line--) { const Sci::Position indentOfLine = GetLineIndentation(line); if (forwards) { if (LineStart(line) < LineEnd(line)) { SetLineIndentation(line, indentOfLine + IndentSize()); } } else { SetLineIndentation(line, indentOfLine - IndentSize()); } } } // Convert line endings for a piece of text to a particular mode. // Stop at len or when a NUL is found. std::string Document::TransformLineEnds(const char *s, size_t len, int eolModeWanted) { std::string dest; for (size_t i = 0; (i < len) && (s[i]); i++) { if (s[i] == '\n' || s[i] == '\r') { if (eolModeWanted == SC_EOL_CR) { dest.push_back('\r'); } else if (eolModeWanted == SC_EOL_LF) { dest.push_back('\n'); } else { // eolModeWanted == SC_EOL_CRLF dest.push_back('\r'); dest.push_back('\n'); } if ((s[i] == '\r') && (i+1 < len) && (s[i+1] == '\n')) { i++; } } else { dest.push_back(s[i]); } } return dest; } void Document::ConvertLineEnds(int eolModeSet) { UndoGroup ug(this); for (Sci::Position pos = 0; pos < Length(); pos++) { if (cb.CharAt(pos) == '\r') { if (cb.CharAt(pos + 1) == '\n') { // CRLF if (eolModeSet == SC_EOL_CR) { DeleteChars(pos + 1, 1); // Delete the LF } else if (eolModeSet == SC_EOL_LF) { DeleteChars(pos, 1); // Delete the CR } else { pos++; } } else { // CR if (eolModeSet == SC_EOL_CRLF) { pos += InsertString(pos + 1, "\n", 1); // Insert LF } else if (eolModeSet == SC_EOL_LF) { pos += InsertString(pos, "\n", 1); // Insert LF DeleteChars(pos, 1); // Delete CR pos--; } } } else if (cb.CharAt(pos) == '\n') { // LF if (eolModeSet == SC_EOL_CRLF) { pos += InsertString(pos, "\r", 1); // Insert CR } else if (eolModeSet == SC_EOL_CR) { pos += InsertString(pos, "\r", 1); // Insert CR DeleteChars(pos, 1); // Delete LF pos--; } } } } int Document::Options() const { return (IsLarge() ? SC_DOCUMENTOPTION_TEXT_LARGE : 0) | (cb.HasStyles() ? 0 : SC_DOCUMENTOPTION_STYLES_NONE); } bool Document::IsWhiteLine(Sci::Line line) const { Sci::Position currentChar = LineStart(line); const Sci::Position endLine = LineEnd(line); while (currentChar < endLine) { if (!IsSpaceOrTab(cb.CharAt(currentChar))) { return false; } ++currentChar; } return true; } Sci::Position Document::ParaUp(Sci::Position pos) const { Sci::Line line = SciLineFromPosition(pos); line--; while (line >= 0 && IsWhiteLine(line)) { // skip empty lines line--; } while (line >= 0 && !IsWhiteLine(line)) { // skip non-empty lines line--; } line++; return LineStart(line); } Sci::Position Document::ParaDown(Sci::Position pos) const { Sci::Line line = SciLineFromPosition(pos); while (line < LinesTotal() && !IsWhiteLine(line)) { // skip non-empty lines line++; } while (line < LinesTotal() && IsWhiteLine(line)) { // skip empty lines line++; } if (line < LinesTotal()) return LineStart(line); else // end of a document return LineEnd(line-1); } bool Document::IsASCIIWordByte(unsigned char ch) const { if (IsASCII(ch)) { return charClass.GetClass(ch) == CharClassify::ccWord; } else { return false; } } CharClassify::cc Document::WordCharacterClass(unsigned int ch) const { if (dbcsCodePage && (!UTF8IsAscii(ch))) { if (SC_CP_UTF8 == dbcsCodePage) { // Use hard coded Unicode class const CharacterCategory cc = CategoriseCharacter(ch); switch (cc) { // Separator, Line/Paragraph case ccZl: case ccZp: return CharClassify::ccNewLine; // Separator, Space case ccZs: // Other case ccCc: case ccCf: case ccCs: case ccCo: case ccCn: return CharClassify::ccSpace; // Letter case ccLu: case ccLl: case ccLt: case ccLm: case ccLo: // Number case ccNd: case ccNl: case ccNo: // Mark - includes combining diacritics case ccMn: case ccMc: case ccMe: return CharClassify::ccWord; // Punctuation case ccPc: case ccPd: case ccPs: case ccPe: case ccPi: case ccPf: case ccPo: // Symbol case ccSm: case ccSc: case ccSk: case ccSo: return CharClassify::ccPunctuation; } } else { // Asian DBCS return CharClassify::ccWord; } } return charClass.GetClass(static_cast(ch)); } /** * Used by commmands that want to select whole words. * Finds the start of word at pos when delta < 0 or the end of the word when delta >= 0. */ Sci::Position Document::ExtendWordSelect(Sci::Position pos, int delta, bool onlyWordCharacters) const { CharClassify::cc ccStart = CharClassify::ccWord; if (delta < 0) { if (!onlyWordCharacters) { const CharacterExtracted ce = CharacterBefore(pos); ccStart = WordCharacterClass(ce.character); } while (pos > 0) { const CharacterExtracted ce = CharacterBefore(pos); if (WordCharacterClass(ce.character) != ccStart) break; pos -= ce.widthBytes; } } else { if (!onlyWordCharacters && pos < Length()) { const CharacterExtracted ce = CharacterAfter(pos); ccStart = WordCharacterClass(ce.character); } while (pos < Length()) { const CharacterExtracted ce = CharacterAfter(pos); if (WordCharacterClass(ce.character) != ccStart) break; pos += ce.widthBytes; } } return MovePositionOutsideChar(pos, delta, true); } /** * Find the start of the next word in either a forward (delta >= 0) or backwards direction * (delta < 0). * This is looking for a transition between character classes although there is also some * additional movement to transit white space. * Used by cursor movement by word commands. */ Sci::Position Document::NextWordStart(Sci::Position pos, int delta) const { if (delta < 0) { while (pos > 0) { const CharacterExtracted ce = CharacterBefore(pos); if (WordCharacterClass(ce.character) != CharClassify::ccSpace) break; pos -= ce.widthBytes; } if (pos > 0) { CharacterExtracted ce = CharacterBefore(pos); const CharClassify::cc ccStart = WordCharacterClass(ce.character); while (pos > 0) { ce = CharacterBefore(pos); if (WordCharacterClass(ce.character) != ccStart) break; pos -= ce.widthBytes; } } } else { CharacterExtracted ce = CharacterAfter(pos); const CharClassify::cc ccStart = WordCharacterClass(ce.character); while (pos < Length()) { ce = CharacterAfter(pos); if (WordCharacterClass(ce.character) != ccStart) break; pos += ce.widthBytes; } while (pos < Length()) { ce = CharacterAfter(pos); if (WordCharacterClass(ce.character) != CharClassify::ccSpace) break; pos += ce.widthBytes; } } return pos; } /** * Find the end of the next word in either a forward (delta >= 0) or backwards direction * (delta < 0). * This is looking for a transition between character classes although there is also some * additional movement to transit white space. * Used by cursor movement by word commands. */ Sci::Position Document::NextWordEnd(Sci::Position pos, int delta) const { if (delta < 0) { if (pos > 0) { CharacterExtracted ce = CharacterBefore(pos); const CharClassify::cc ccStart = WordCharacterClass(ce.character); if (ccStart != CharClassify::ccSpace) { while (pos > 0) { ce = CharacterBefore(pos); if (WordCharacterClass(ce.character) != ccStart) break; pos -= ce.widthBytes; } } while (pos > 0) { ce = CharacterBefore(pos); if (WordCharacterClass(ce.character) != CharClassify::ccSpace) break; pos -= ce.widthBytes; } } } else { while (pos < Length()) { const CharacterExtracted ce = CharacterAfter(pos); if (WordCharacterClass(ce.character) != CharClassify::ccSpace) break; pos += ce.widthBytes; } if (pos < Length()) { CharacterExtracted ce = CharacterAfter(pos); const CharClassify::cc ccStart = WordCharacterClass(ce.character); while (pos < Length()) { ce = CharacterAfter(pos); if (WordCharacterClass(ce.character) != ccStart) break; pos += ce.widthBytes; } } } return pos; } /** * Check that the character at the given position is a word or punctuation character and that * the previous character is of a different character class. */ bool Document::IsWordStartAt(Sci::Position pos) const { if (pos >= Length()) return false; if (pos > 0) { const CharacterExtracted cePos = CharacterAfter(pos); const CharClassify::cc ccPos = WordCharacterClass(cePos.character); const CharacterExtracted cePrev = CharacterBefore(pos); const CharClassify::cc ccPrev = WordCharacterClass(cePrev.character); return (ccPos == CharClassify::ccWord || ccPos == CharClassify::ccPunctuation) && (ccPos != ccPrev); } return true; } /** * Check that the character at the given position is a word or punctuation character and that * the next character is of a different character class. */ bool Document::IsWordEndAt(Sci::Position pos) const { if (pos <= 0) return false; if (pos < Length()) { const CharacterExtracted cePos = CharacterAfter(pos); const CharClassify::cc ccPos = WordCharacterClass(cePos.character); const CharacterExtracted cePrev = CharacterBefore(pos); const CharClassify::cc ccPrev = WordCharacterClass(cePrev.character); return (ccPrev == CharClassify::ccWord || ccPrev == CharClassify::ccPunctuation) && (ccPrev != ccPos); } return true; } /** * Check that the given range is has transitions between character classes at both * ends and where the characters on the inside are word or punctuation characters. */ bool Document::IsWordAt(Sci::Position start, Sci::Position end) const { return (start < end) && IsWordStartAt(start) && IsWordEndAt(end); } bool Document::MatchesWordOptions(bool word, bool wordStart, Sci::Position pos, Sci::Position length) const { return (!word && !wordStart) || (word && IsWordAt(pos, pos + length)) || (wordStart && IsWordStartAt(pos)); } bool Document::HasCaseFolder() const noexcept { return pcf != nullptr; } void Document::SetCaseFolder(CaseFolder *pcf_) { pcf.reset(pcf_); } Document::CharacterExtracted Document::ExtractCharacter(Sci::Position position) const noexcept { const unsigned char leadByte = cb.UCharAt(position); if (UTF8IsAscii(leadByte)) { // Common case: ASCII character return CharacterExtracted(leadByte, 1); } const int widthCharBytes = UTF8BytesOfLead[leadByte]; unsigned char charBytes[UTF8MaxBytes] = { leadByte, 0, 0, 0 }; for (int b=1; b maxPos to do a backward search) * Has not been tested with backwards DBCS searches yet. */ Sci::Position Document::FindText(Sci::Position minPos, Sci::Position maxPos, const char *search, int flags, Sci::Position *length) { if (*length <= 0) return minPos; const bool caseSensitive = (flags & SCFIND_MATCHCASE) != 0; const bool word = (flags & SCFIND_WHOLEWORD) != 0; const bool wordStart = (flags & SCFIND_WORDSTART) != 0; const bool regExp = (flags & SCFIND_REGEXP) != 0; if (regExp) { if (!regex) regex = std::unique_ptr(CreateRegexSearch(&charClass)); return regex->FindText(this, minPos, maxPos, search, caseSensitive, word, wordStart, flags, length); } else { const bool forward = minPos <= maxPos; const int increment = forward ? 1 : -1; // Range endpoints should not be inside DBCS characters, but just in case, move them. const Sci::Position startPos = MovePositionOutsideChar(minPos, increment, false); const Sci::Position endPos = MovePositionOutsideChar(maxPos, increment, false); // Compute actual search ranges needed const Sci::Position lengthFind = *length; //Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind); const Sci::Position limitPos = std::max(startPos, endPos); Sci::Position pos = startPos; if (!forward) { // Back all of a character pos = NextPosition(pos, increment); } if (caseSensitive) { const Sci::Position endSearch = (startPos <= endPos) ? endPos - lengthFind + 1 : endPos; const char charStartSearch = search[0]; while (forward ? (pos < endSearch) : (pos >= endSearch)) { if (CharAt(pos) == charStartSearch) { bool found = (pos + lengthFind) <= limitPos; for (int indexSearch = 1; (indexSearch < lengthFind) && found; indexSearch++) { found = CharAt(pos + indexSearch) == search[indexSearch]; } if (found && MatchesWordOptions(word, wordStart, pos, lengthFind)) { return pos; } } if (!NextCharacter(pos, increment)) break; } } else if (SC_CP_UTF8 == dbcsCodePage) { const size_t maxFoldingExpansion = 4; std::vector searchThing((lengthFind+1) * UTF8MaxBytes * maxFoldingExpansion + 1); const size_t lenSearch = pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind); char bytes[UTF8MaxBytes + 1] = ""; char folded[UTF8MaxBytes * maxFoldingExpansion + 1] = ""; while (forward ? (pos < endPos) : (pos >= endPos)) { int widthFirstCharacter = 0; Sci::Position posIndexDocument = pos; size_t indexSearch = 0; bool characterMatches = true; for (;;) { const unsigned char leadByte = cb.UCharAt(posIndexDocument); bytes[0] = leadByte; int widthChar = 1; if (!UTF8IsAscii(leadByte)) { const int widthCharBytes = UTF8BytesOfLead[leadByte]; for (int b=1; b(bytes), widthCharBytes) & UTF8MaskWidth; } if (!widthFirstCharacter) widthFirstCharacter = widthChar; if ((posIndexDocument + widthChar) > limitPos) break; const size_t lenFlat = pcf->Fold(folded, sizeof(folded), bytes, widthChar); // memcmp may examine lenFlat bytes in both arguments so assert it doesn't read past end of searchThing assert((indexSearch + lenFlat) <= searchThing.size()); // Does folded match the buffer characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat); if (!characterMatches) break; posIndexDocument += widthChar; indexSearch += lenFlat; if (indexSearch >= lenSearch) break; } if (characterMatches && (indexSearch == lenSearch)) { if (MatchesWordOptions(word, wordStart, pos, posIndexDocument - pos)) { *length = posIndexDocument - pos; return pos; } } if (forward) { pos += widthFirstCharacter; } else { if (!NextCharacter(pos, increment)) break; } } } else if (dbcsCodePage) { const size_t maxBytesCharacter = 2; const size_t maxFoldingExpansion = 4; std::vector searchThing((lengthFind+1) * maxBytesCharacter * maxFoldingExpansion + 1); const size_t lenSearch = pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind); while (forward ? (pos < endPos) : (pos >= endPos)) { Sci::Position indexDocument = 0; size_t indexSearch = 0; bool characterMatches = true; while (characterMatches && ((pos + indexDocument) < limitPos) && (indexSearch < lenSearch)) { char bytes[maxBytesCharacter + 1]; bytes[0] = cb.CharAt(pos + indexDocument); const Sci::Position widthChar = IsDBCSLeadByteNoExcept(bytes[0]) ? 2 : 1; if (widthChar == 2) bytes[1] = cb.CharAt(pos + indexDocument + 1); if ((pos + indexDocument + widthChar) > limitPos) break; char folded[maxBytesCharacter * maxFoldingExpansion + 1]; const size_t lenFlat = pcf->Fold(folded, sizeof(folded), bytes, widthChar); // memcmp may examine lenFlat bytes in both arguments so assert it doesn't read past end of searchThing assert((indexSearch + lenFlat) <= searchThing.size()); // Does folded match the buffer characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat); indexDocument += widthChar; indexSearch += lenFlat; } if (characterMatches && (indexSearch == lenSearch)) { if (MatchesWordOptions(word, wordStart, pos, indexDocument)) { *length = indexDocument; return pos; } } if (!NextCharacter(pos, increment)) break; } } else { const Sci::Position endSearch = (startPos <= endPos) ? endPos - lengthFind + 1 : endPos; std::vector searchThing(lengthFind + 1); pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind); while (forward ? (pos < endSearch) : (pos >= endSearch)) { bool found = (pos + lengthFind) <= limitPos; for (int indexSearch = 0; (indexSearch < lengthFind) && found; indexSearch++) { const char ch = CharAt(pos + indexSearch); char folded[2]; pcf->Fold(folded, sizeof(folded), &ch, 1); found = folded[0] == searchThing[indexSearch]; } if (found && MatchesWordOptions(word, wordStart, pos, lengthFind)) { return pos; } if (!NextCharacter(pos, increment)) break; } } } //Platform::DebugPrintf("Not found\n"); return -1; } const char *Document::SubstituteByPosition(const char *text, Sci::Position *length) { if (regex) return regex->SubstituteByPosition(this, text, length); else return nullptr; } int Document::LineCharacterIndex() const { return cb.LineCharacterIndex(); } void Document::AllocateLineCharacterIndex(int lineCharacterIndex) { return cb.AllocateLineCharacterIndex(lineCharacterIndex); } void Document::ReleaseLineCharacterIndex(int lineCharacterIndex) { return cb.ReleaseLineCharacterIndex(lineCharacterIndex); } Sci::Line Document::LinesTotal() const noexcept { return cb.Lines(); } void Document::SetDefaultCharClasses(bool includeWordClass) { charClass.SetDefaultCharClasses(includeWordClass); } void Document::SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass) { charClass.SetCharClasses(chars, newCharClass); } int Document::GetCharsOfClass(CharClassify::cc characterClass, unsigned char *buffer) const { return charClass.GetCharsOfClass(characterClass, buffer); } void SCI_METHOD Document::StartStyling(Sci_Position position, char) { endStyled = position; } bool SCI_METHOD Document::SetStyleFor(Sci_Position length, char style) { if (enteredStyling != 0) { return false; } else { enteredStyling++; const Sci::Position prevEndStyled = endStyled; if (cb.SetStyleFor(endStyled, length, style)) { const DocModification mh(SC_MOD_CHANGESTYLE | SC_PERFORMED_USER, prevEndStyled, length); NotifyModified(mh); } endStyled += length; enteredStyling--; return true; } } bool SCI_METHOD Document::SetStyles(Sci_Position length, const char *styles) { if (enteredStyling != 0) { return false; } else { enteredStyling++; bool didChange = false; Sci::Position startMod = 0; Sci::Position endMod = 0; for (int iPos = 0; iPos < length; iPos++, endStyled++) { PLATFORM_ASSERT(endStyled < Length()); if (cb.SetStyleAt(endStyled, styles[iPos])) { if (!didChange) { startMod = endStyled; } didChange = true; endMod = endStyled; } } if (didChange) { const DocModification mh(SC_MOD_CHANGESTYLE | SC_PERFORMED_USER, startMod, endMod - startMod + 1); NotifyModified(mh); } enteredStyling--; return true; } } void Document::EnsureStyledTo(Sci::Position pos) { if ((enteredStyling == 0) && (pos > GetEndStyled())) { IncrementStyleClock(); if (pli && !pli->UseContainerLexing()) { const Sci::Line lineEndStyled = SciLineFromPosition(GetEndStyled()); const Sci::Position endStyledTo = LineStart(lineEndStyled); pli->Colourise(endStyledTo, pos); } else { // Ask the watchers to style, and stop as soon as one responds. for (std::vector::iterator it = watchers.begin(); (pos > GetEndStyled()) && (it != watchers.end()); ++it) { it->watcher->NotifyStyleNeeded(this, it->userData, pos); } } } } void Document::StyleToAdjustingLineDuration(Sci::Position pos) { const Sci::Line lineFirst = SciLineFromPosition(GetEndStyled()); ElapsedPeriod epStyling; EnsureStyledTo(pos); const Sci::Line lineLast = SciLineFromPosition(GetEndStyled()); durationStyleOneLine.AddSample(lineLast - lineFirst, epStyling.Duration()); } void Document::LexerChanged() { // Tell the watchers the lexer has changed. for (const WatcherWithUserData &watcher : watchers) { watcher.watcher->NotifyLexerChanged(this, watcher.userData); } } LexInterface *Document::GetLexInterface() const { return pli.get(); } void Document::SetLexInterface(LexInterface *pLexInterface) { pli.reset(pLexInterface); } int SCI_METHOD Document::SetLineState(Sci_Position line, int state) { const int statePrevious = States()->SetLineState(static_cast(line), state); if (state != statePrevious) { const DocModification mh(SC_MOD_CHANGELINESTATE, LineStart(line), 0, 0, nullptr, static_cast(line)); NotifyModified(mh); } return statePrevious; } int SCI_METHOD Document::GetLineState(Sci_Position line) const { return States()->GetLineState(static_cast(line)); } Sci::Line Document::GetMaxLineState() const { return States()->GetMaxLineState(); } void SCI_METHOD Document::ChangeLexerState(Sci_Position start, Sci_Position end) { const DocModification mh(SC_MOD_LEXERSTATE, start, end-start, 0, 0, 0); NotifyModified(mh); } StyledText Document::MarginStyledText(Sci::Line line) const { const LineAnnotation *pla = Margins(); return StyledText(pla->Length(line), pla->Text(line), pla->MultipleStyles(line), pla->Style(line), pla->Styles(line)); } void Document::MarginSetText(Sci::Line line, const char *text) { Margins()->SetText(line, text); const DocModification mh(SC_MOD_CHANGEMARGIN, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } void Document::MarginSetStyle(Sci::Line line, int style) { Margins()->SetStyle(line, style); NotifyModified(DocModification(SC_MOD_CHANGEMARGIN, LineStart(line), 0, 0, 0, line)); } void Document::MarginSetStyles(Sci::Line line, const unsigned char *styles) { Margins()->SetStyles(line, styles); NotifyModified(DocModification(SC_MOD_CHANGEMARGIN, LineStart(line), 0, 0, 0, line)); } void Document::MarginClearAll() { const Sci::Line maxEditorLine = LinesTotal(); for (Sci::Line l=0; lClearAll(); } StyledText Document::AnnotationStyledText(Sci::Line line) const { const LineAnnotation *pla = Annotations(); return StyledText(pla->Length(line), pla->Text(line), pla->MultipleStyles(line), pla->Style(line), pla->Styles(line)); } void Document::AnnotationSetText(Sci::Line line, const char *text) { if (line >= 0 && line < LinesTotal()) { const Sci::Line linesBefore = AnnotationLines(line); Annotations()->SetText(line, text); const int linesAfter = AnnotationLines(line); DocModification mh(SC_MOD_CHANGEANNOTATION, LineStart(line), 0, 0, 0, line); mh.annotationLinesAdded = linesAfter - linesBefore; NotifyModified(mh); } } void Document::AnnotationSetStyle(Sci::Line line, int style) { Annotations()->SetStyle(line, style); const DocModification mh(SC_MOD_CHANGEANNOTATION, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } void Document::AnnotationSetStyles(Sci::Line line, const unsigned char *styles) { if (line >= 0 && line < LinesTotal()) { Annotations()->SetStyles(line, styles); } } int Document::AnnotationLines(Sci::Line line) const { return Annotations()->Lines(line); } void Document::AnnotationClearAll() { const Sci::Line maxEditorLine = LinesTotal(); for (Sci::Line l=0; lClearAll(); } void Document::IncrementStyleClock() noexcept { styleClock = (styleClock + 1) % 0x100000; } void SCI_METHOD Document::DecorationSetCurrentIndicator(int indicator) { decorations->SetCurrentIndicator(indicator); } void SCI_METHOD Document::DecorationFillRange(Sci_Position position, int value, Sci_Position fillLength) { const FillResult fr = decorations->FillRange( position, value, fillLength); if (fr.changed) { const DocModification mh(SC_MOD_CHANGEINDICATOR | SC_PERFORMED_USER, fr.position, fr.fillLength); NotifyModified(mh); } } bool Document::AddWatcher(DocWatcher *watcher, void *userData) { const WatcherWithUserData wwud(watcher, userData); std::vector::iterator it = std::find(watchers.begin(), watchers.end(), wwud); if (it != watchers.end()) return false; watchers.push_back(wwud); return true; } bool Document::RemoveWatcher(DocWatcher *watcher, void *userData) { std::vector::iterator it = std::find(watchers.begin(), watchers.end(), WatcherWithUserData(watcher, userData)); if (it != watchers.end()) { watchers.erase(it); return true; } return false; } void Document::NotifyModifyAttempt() { for (const WatcherWithUserData &watcher : watchers) { watcher.watcher->NotifyModifyAttempt(this, watcher.userData); } } void Document::NotifySavePoint(bool atSavePoint) { for (const WatcherWithUserData &watcher : watchers) { watcher.watcher->NotifySavePoint(this, watcher.userData, atSavePoint); } } void Document::NotifyModified(DocModification mh) { if (mh.modificationType & SC_MOD_INSERTTEXT) { decorations->InsertSpace(mh.position, mh.length); } else if (mh.modificationType & SC_MOD_DELETETEXT) { decorations->DeleteRange(mh.position, mh.length); } for (const WatcherWithUserData &watcher : watchers) { watcher.watcher->NotifyModified(this, mh, watcher.userData); } } // Used for word part navigation. static bool IsASCIIPunctuationCharacter(unsigned int ch) noexcept { switch (ch) { case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case '[': case '\\': case ']': case '^': case '_': case '`': case '{': case '|': case '}': case '~': return true; default: return false; } } bool Document::IsWordPartSeparator(unsigned int ch) const { return (WordCharacterClass(ch) == CharClassify::ccWord) && IsASCIIPunctuationCharacter(ch); } Sci::Position Document::WordPartLeft(Sci::Position pos) const { if (pos > 0) { pos -= CharacterBefore(pos).widthBytes; CharacterExtracted ceStart = CharacterAfter(pos); if (IsWordPartSeparator(ceStart.character)) { while (pos > 0 && IsWordPartSeparator(CharacterAfter(pos).character)) { pos -= CharacterBefore(pos).widthBytes; } } if (pos > 0) { ceStart = CharacterAfter(pos); pos -= CharacterBefore(pos).widthBytes; if (IsLowerCase(ceStart.character)) { while (pos > 0 && IsLowerCase(CharacterAfter(pos).character)) pos -= CharacterBefore(pos).widthBytes; if (!IsUpperCase(CharacterAfter(pos).character) && !IsLowerCase(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (IsUpperCase(ceStart.character)) { while (pos > 0 && IsUpperCase(CharacterAfter(pos).character)) pos -= CharacterBefore(pos).widthBytes; if (!IsUpperCase(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (IsADigit(ceStart.character)) { while (pos > 0 && IsADigit(CharacterAfter(pos).character)) pos -= CharacterBefore(pos).widthBytes; if (!IsADigit(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (IsASCIIPunctuationCharacter(ceStart.character)) { while (pos > 0 && IsASCIIPunctuationCharacter(CharacterAfter(pos).character)) pos -= CharacterBefore(pos).widthBytes; if (!IsASCIIPunctuationCharacter(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (isspacechar(ceStart.character)) { while (pos > 0 && isspacechar(CharacterAfter(pos).character)) pos -= CharacterBefore(pos).widthBytes; if (!isspacechar(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (!IsASCII(ceStart.character)) { while (pos > 0 && !IsASCII(CharacterAfter(pos).character)) pos -= CharacterBefore(pos).widthBytes; if (IsASCII(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else { pos += CharacterAfter(pos).widthBytes; } } } return pos; } Sci::Position Document::WordPartRight(Sci::Position pos) const { CharacterExtracted ceStart = CharacterAfter(pos); const Sci::Position length = Length(); if (IsWordPartSeparator(ceStart.character)) { while (pos < length && IsWordPartSeparator(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; ceStart = CharacterAfter(pos); } if (!IsASCII(ceStart.character)) { while (pos < length && !IsASCII(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (IsLowerCase(ceStart.character)) { while (pos < length && IsLowerCase(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (IsUpperCase(ceStart.character)) { if (IsLowerCase(CharacterAfter(pos + ceStart.widthBytes).character)) { pos += CharacterAfter(pos).widthBytes; while (pos < length && IsLowerCase(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else { while (pos < length && IsUpperCase(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } if (IsLowerCase(CharacterAfter(pos).character) && IsUpperCase(CharacterBefore(pos).character)) pos -= CharacterBefore(pos).widthBytes; } else if (IsADigit(ceStart.character)) { while (pos < length && IsADigit(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (IsASCIIPunctuationCharacter(ceStart.character)) { while (pos < length && IsASCIIPunctuationCharacter(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else if (isspacechar(ceStart.character)) { while (pos < length && isspacechar(CharacterAfter(pos).character)) pos += CharacterAfter(pos).widthBytes; } else { pos += CharacterAfter(pos).widthBytes; } return pos; } static bool IsLineEndChar(char c) noexcept { return (c == '\n' || c == '\r'); } Sci::Position Document::ExtendStyleRange(Sci::Position pos, int delta, bool singleLine) { const int sStart = cb.StyleAt(pos); if (delta < 0) { while (pos > 0 && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos)))) pos--; pos++; } else { while (pos < (Length()) && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos)))) pos++; } return pos; } static char BraceOpposite(char ch) noexcept { switch (ch) { case '(': return ')'; case ')': return '('; case '[': return ']'; case ']': return '['; case '{': return '}'; case '}': return '{'; case '<': return '>'; case '>': return '<'; default: return '\0'; } } // TODO: should be able to extend styled region to find matching brace Sci::Position Document::BraceMatch(Sci::Position position, Sci::Position /*maxReStyle*/) { const char chBrace = CharAt(position); const char chSeek = BraceOpposite(chBrace); if (chSeek == '\0') return - 1; const int styBrace = StyleIndexAt(position); int direction = -1; if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<') direction = 1; int depth = 1; position = NextPosition(position, direction); while ((position >= 0) && (position < Length())) { const char chAtPos = CharAt(position); const int styAtPos = StyleIndexAt(position); if ((position > GetEndStyled()) || (styAtPos == styBrace)) { if (chAtPos == chBrace) depth++; if (chAtPos == chSeek) depth--; if (depth == 0) return position; } const Sci::Position positionBeforeMove = position; position = NextPosition(position, direction); if (position == positionBeforeMove) break; } return - 1; } /** * Implementation of RegexSearchBase for the default built-in regular expression engine */ class BuiltinRegex : public RegexSearchBase { public: explicit BuiltinRegex(CharClassify *charClassTable) : search(charClassTable) {} BuiltinRegex(const BuiltinRegex &) = delete; BuiltinRegex(BuiltinRegex &&) = delete; BuiltinRegex &operator=(const BuiltinRegex &) = delete; BuiltinRegex &operator=(BuiltinRegex &&) = delete; ~BuiltinRegex() override = default; Sci::Position FindText(Document *doc, Sci::Position minPos, Sci::Position maxPos, const char *s, bool caseSensitive, bool word, bool wordStart, int flags, Sci::Position *length) override; const char *SubstituteByPosition(Document *doc, const char *text, Sci::Position *length) override; private: RESearch search; std::string substituted; }; namespace { /** * RESearchRange keeps track of search range. */ class RESearchRange { public: const Document *doc; int increment; Sci::Position startPos; Sci::Position endPos; Sci::Line lineRangeStart; Sci::Line lineRangeEnd; Sci::Line lineRangeBreak; RESearchRange(const Document *doc_, Sci::Position minPos, Sci::Position maxPos) : doc(doc_) { increment = (minPos <= maxPos) ? 1 : -1; // Range endpoints should not be inside DBCS characters or between a CR and LF, // but just in case, move them. startPos = doc->MovePositionOutsideChar(minPos, 1, true); endPos = doc->MovePositionOutsideChar(maxPos, 1, true); lineRangeStart = doc->SciLineFromPosition(startPos); lineRangeEnd = doc->SciLineFromPosition(endPos); lineRangeBreak = lineRangeEnd + increment; } Range LineRange(Sci::Line line) const { Range range(doc->LineStart(line), doc->LineEnd(line)); if (increment == 1) { if (line == lineRangeStart) range.start = startPos; if (line == lineRangeEnd) range.end = endPos; } else { if (line == lineRangeEnd) range.start = endPos; if (line == lineRangeStart) range.end = startPos; } return range; } }; // Define a way for the Regular Expression code to access the document class DocumentIndexer : public CharacterIndexer { Document *pdoc; Sci::Position end; public: DocumentIndexer(Document *pdoc_, Sci::Position end_) noexcept : pdoc(pdoc_), end(end_) { } DocumentIndexer(const DocumentIndexer &) = delete; DocumentIndexer(DocumentIndexer &&) = delete; DocumentIndexer &operator=(const DocumentIndexer &) = delete; DocumentIndexer &operator=(DocumentIndexer &&) = delete; ~DocumentIndexer() override = default; char CharAt(Sci::Position index) const noexcept override { if (index < 0 || index >= end) return 0; else return pdoc->CharAt(index); } }; #ifndef NO_CXX11_REGEX class ByteIterator { public: typedef std::bidirectional_iterator_tag iterator_category; typedef char value_type; typedef ptrdiff_t difference_type; typedef char* pointer; typedef char& reference; const Document *doc; Sci::Position position; ByteIterator(const Document *doc_=nullptr, Sci::Position position_=0) noexcept : doc(doc_), position(position_) { } ByteIterator(const ByteIterator &other) noexcept { doc = other.doc; position = other.position; } ByteIterator(ByteIterator &&other) noexcept { doc = other.doc; position = other.position; } ByteIterator &operator=(const ByteIterator &other) noexcept { if (this != &other) { doc = other.doc; position = other.position; } return *this; } ByteIterator &operator=(ByteIterator &&) noexcept = default; ~ByteIterator() = default; char operator*() const noexcept { return doc->CharAt(position); } ByteIterator &operator++() noexcept { position++; return *this; } ByteIterator operator++(int) noexcept { ByteIterator retVal(*this); position++; return retVal; } ByteIterator &operator--() noexcept { position--; return *this; } bool operator==(const ByteIterator &other) const noexcept { return doc == other.doc && position == other.position; } bool operator!=(const ByteIterator &other) const noexcept { return doc != other.doc || position != other.position; } Sci::Position Pos() const noexcept { return position; } Sci::Position PosRoundUp() const noexcept { return position; } }; // On Windows, wchar_t is 16 bits wide and on Unix it is 32 bits wide. // Would be better to use sizeof(wchar_t) or similar to differentiate // but easier for now to hard-code platforms. // C++11 has char16_t and char32_t but neither Clang nor Visual C++ // appear to allow specializing basic_regex over these. #ifdef _WIN32 #define WCHAR_T_IS_16 1 #else #define WCHAR_T_IS_16 0 #endif #if WCHAR_T_IS_16 // On Windows, report non-BMP characters as 2 separate surrogates as that // matches wregex since it is based on wchar_t. class UTF8Iterator { // These 3 fields determine the iterator position and are used for comparisons const Document *doc; Sci::Position position; size_t characterIndex; // Remaining fields are derived from the determining fields so are excluded in comparisons unsigned int lenBytes; size_t lenCharacters; wchar_t buffered[2]; public: typedef std::bidirectional_iterator_tag iterator_category; typedef wchar_t value_type; typedef ptrdiff_t difference_type; typedef wchar_t* pointer; typedef wchar_t& reference; UTF8Iterator(const Document *doc_=nullptr, Sci::Position position_=0) noexcept : doc(doc_), position(position_), characterIndex(0), lenBytes(0), lenCharacters(0), buffered{} { buffered[0] = 0; buffered[1] = 0; if (doc) { ReadCharacter(); } } UTF8Iterator(const UTF8Iterator &other) noexcept : buffered{} { doc = other.doc; position = other.position; characterIndex = other.characterIndex; lenBytes = other.lenBytes; lenCharacters = other.lenCharacters; buffered[0] = other.buffered[0]; buffered[1] = other.buffered[1]; } UTF8Iterator(UTF8Iterator &&other) noexcept = default; UTF8Iterator &operator=(const UTF8Iterator &other) noexcept { if (this != &other) { doc = other.doc; position = other.position; characterIndex = other.characterIndex; lenBytes = other.lenBytes; lenCharacters = other.lenCharacters; buffered[0] = other.buffered[0]; buffered[1] = other.buffered[1]; } return *this; } UTF8Iterator &operator=(UTF8Iterator &&) noexcept = default; ~UTF8Iterator() = default; wchar_t operator*() const noexcept { assert(lenCharacters != 0); return buffered[characterIndex]; } UTF8Iterator &operator++() noexcept { if ((characterIndex + 1) < (lenCharacters)) { characterIndex++; } else { position += lenBytes; ReadCharacter(); characterIndex = 0; } return *this; } UTF8Iterator operator++(int) noexcept { UTF8Iterator retVal(*this); if ((characterIndex + 1) < (lenCharacters)) { characterIndex++; } else { position += lenBytes; ReadCharacter(); characterIndex = 0; } return retVal; } UTF8Iterator &operator--() noexcept { if (characterIndex) { characterIndex--; } else { position = doc->NextPosition(position, -1); ReadCharacter(); characterIndex = lenCharacters - 1; } return *this; } bool operator==(const UTF8Iterator &other) const noexcept { // Only test the determining fields, not the character widths and values derived from this return doc == other.doc && position == other.position && characterIndex == other.characterIndex; } bool operator!=(const UTF8Iterator &other) const noexcept { // Only test the determining fields, not the character widths and values derived from this return doc != other.doc || position != other.position || characterIndex != other.characterIndex; } Sci::Position Pos() const noexcept { return position; } Sci::Position PosRoundUp() const noexcept { if (characterIndex) return position + lenBytes; // Force to end of character else return position; } private: void ReadCharacter() noexcept { const Document::CharacterExtracted charExtracted = doc->ExtractCharacter(position); lenBytes = charExtracted.widthBytes; if (charExtracted.character == unicodeReplacementChar) { lenCharacters = 1; buffered[0] = static_cast(charExtracted.character); } else { lenCharacters = UTF16FromUTF32Character(charExtracted.character, buffered); } } }; #else // On Unix, report non-BMP characters as single characters class UTF8Iterator { const Document *doc; Sci::Position position; public: typedef std::bidirectional_iterator_tag iterator_category; typedef wchar_t value_type; typedef ptrdiff_t difference_type; typedef wchar_t* pointer; typedef wchar_t& reference; UTF8Iterator(const Document *doc_=nullptr, Sci::Position position_=0) noexcept : doc(doc_), position(position_) { } UTF8Iterator(const UTF8Iterator &other) noexcept { doc = other.doc; position = other.position; } UTF8Iterator(UTF8Iterator &&other) noexcept = default; UTF8Iterator &operator=(const UTF8Iterator &other) noexcept { if (this != &other) { doc = other.doc; position = other.position; } return *this; } UTF8Iterator &operator=(UTF8Iterator &&) noexcept = default; ~UTF8Iterator() = default; wchar_t operator*() const noexcept { const Document::CharacterExtracted charExtracted = doc->ExtractCharacter(position); return charExtracted.character; } UTF8Iterator &operator++() noexcept { position = doc->NextPosition(position, 1); return *this; } UTF8Iterator operator++(int) noexcept { UTF8Iterator retVal(*this); position = doc->NextPosition(position, 1); return retVal; } UTF8Iterator &operator--() noexcept { position = doc->NextPosition(position, -1); return *this; } bool operator==(const UTF8Iterator &other) const noexcept { return doc == other.doc && position == other.position; } bool operator!=(const UTF8Iterator &other) const noexcept { return doc != other.doc || position != other.position; } Sci::Position Pos() const noexcept { return position; } Sci::Position PosRoundUp() const noexcept { return position; } }; #endif std::regex_constants::match_flag_type MatchFlags(const Document *doc, Sci::Position startPos, Sci::Position endPos) { std::regex_constants::match_flag_type flagsMatch = std::regex_constants::match_default; if (!doc->IsLineStartPosition(startPos)) flagsMatch |= std::regex_constants::match_not_bol; if (!doc->IsLineEndPosition(endPos)) flagsMatch |= std::regex_constants::match_not_eol; return flagsMatch; } template bool MatchOnLines(const Document *doc, const Regex ®exp, const RESearchRange &resr, RESearch &search) { std::match_results match; // MSVC and libc++ have problems with ^ and $ matching line ends inside a range. // CRLF line ends are also a problem as ^ and $ only treat LF as a line end. // The std::regex::multiline option was added to C++17 to improve behaviour but // has not been implemented by compiler runtimes with MSVC always in multiline // mode and libc++ and libstdc++ always in single-line mode. // If multiline regex worked well then the line by line iteration could be removed // for the forwards case and replaced with the following 4 lines: #ifdef REGEX_MULTILINE Iterator itStart(doc, resr.startPos); Iterator itEnd(doc, resr.endPos); const std::regex_constants::match_flag_type flagsMatch = MatchFlags(doc, resr.startPos, resr.endPos); const bool matched = std::regex_search(itStart, itEnd, match, regexp, flagsMatch); #else // Line by line. bool matched = false; for (Sci::Line line = resr.lineRangeStart; line != resr.lineRangeBreak; line += resr.increment) { const Range lineRange = resr.LineRange(line); Iterator itStart(doc, lineRange.start); Iterator itEnd(doc, lineRange.end); std::regex_constants::match_flag_type flagsMatch = MatchFlags(doc, lineRange.start, lineRange.end); matched = std::regex_search(itStart, itEnd, match, regexp, flagsMatch); // Check for the last match on this line. if (matched) { if (resr.increment == -1) { while (matched) { Iterator itNext(doc, match[0].second.PosRoundUp()); flagsMatch = MatchFlags(doc, itNext.Pos(), lineRange.end); std::match_results matchNext; matched = std::regex_search(itNext, itEnd, matchNext, regexp, flagsMatch); if (matched) { if (match[0].first == match[0].second) { // Empty match means failure so exit return false; } match = matchNext; } } matched = true; } break; } } #endif if (matched) { for (size_t co = 0; co < match.size(); co++) { search.bopat[co] = match[co].first.Pos(); search.eopat[co] = match[co].second.PosRoundUp(); const Sci::Position lenMatch = search.eopat[co] - search.bopat[co]; search.pat[co].resize(lenMatch); for (Sci::Position iPos = 0; iPos < lenMatch; iPos++) { search.pat[co][iPos] = doc->CharAt(iPos + search.bopat[co]); } } } return matched; } Sci::Position Cxx11RegexFindText(const Document *doc, Sci::Position minPos, Sci::Position maxPos, const char *s, bool caseSensitive, Sci::Position *length, RESearch &search) { const RESearchRange resr(doc, minPos, maxPos); try { //ElapsedPeriod ep; std::regex::flag_type flagsRe = std::regex::ECMAScript; // Flags that apper to have no effect: // | std::regex::collate | std::regex::extended; if (!caseSensitive) flagsRe = flagsRe | std::regex::icase; // Clear the RESearch so can fill in matches search.Clear(); bool matched = false; if (SC_CP_UTF8 == doc->dbcsCodePage) { const size_t lenS = strlen(s); std::vector ws(lenS + 1); #if WCHAR_T_IS_16 const size_t outLen = UTF16FromUTF8(s, lenS, &ws[0], lenS); #else const size_t outLen = UTF32FromUTF8(s, lenS, reinterpret_cast(&ws[0]), lenS); #endif ws[outLen] = 0; std::wregex regexp; regexp.assign(&ws[0], flagsRe); matched = MatchOnLines(doc, regexp, resr, search); } else { std::regex regexp; regexp.assign(s, flagsRe); matched = MatchOnLines(doc, regexp, resr, search); } Sci::Position posMatch = -1; if (matched) { posMatch = search.bopat[0]; *length = search.eopat[0] - search.bopat[0]; } // Example - search in doc/ScintillaHistory.html for // [[:upper:]]eta[[:space:]] // On MacBook, normally around 1 second but with locale imbued -> 14 seconds. //const double durSearch = ep.Duration(true); //Platform::DebugPrintf("Search:%9.6g \n", durSearch); return posMatch; } catch (std::regex_error &) { // Failed to create regular expression throw RegexError(); } catch (...) { // Failed in some other way return -1; } } #endif } Sci::Position BuiltinRegex::FindText(Document *doc, Sci::Position minPos, Sci::Position maxPos, const char *s, bool caseSensitive, bool, bool, int flags, Sci::Position *length) { #ifndef NO_CXX11_REGEX if (flags & SCFIND_CXX11REGEX) { return Cxx11RegexFindText(doc, minPos, maxPos, s, caseSensitive, length, search); } #endif const RESearchRange resr(doc, minPos, maxPos); const bool posix = (flags & SCFIND_POSIX) != 0; const char *errmsg = search.Compile(s, *length, caseSensitive, posix); if (errmsg) { return -1; } // Find a variable in a property file: \$(\([A-Za-z0-9_.]+\)) // Replace first '.' with '-' in each property file variable reference: // Search: \$(\([A-Za-z0-9_-]+\)\.\([A-Za-z0-9_.]+\)) // Replace: $(\1-\2) Sci::Position pos = -1; Sci::Position lenRet = 0; const bool searchforLineStart = s[0] == '^'; const char searchEnd = s[*length - 1]; const char searchEndPrev = (*length > 1) ? s[*length - 2] : '\0'; const bool searchforLineEnd = (searchEnd == '$') && (searchEndPrev != '\\'); for (Sci::Line line = resr.lineRangeStart; line != resr.lineRangeBreak; line += resr.increment) { Sci::Position startOfLine = doc->LineStart(line); Sci::Position endOfLine = doc->LineEnd(line); if (resr.increment == 1) { if (line == resr.lineRangeStart) { if ((resr.startPos != startOfLine) && searchforLineStart) continue; // Can't match start of line if start position after start of line startOfLine = resr.startPos; } if (line == resr.lineRangeEnd) { if ((resr.endPos != endOfLine) && searchforLineEnd) continue; // Can't match end of line if end position before end of line endOfLine = resr.endPos; } } else { if (line == resr.lineRangeEnd) { if ((resr.endPos != startOfLine) && searchforLineStart) continue; // Can't match start of line if end position after start of line startOfLine = resr.endPos; } if (line == resr.lineRangeStart) { if ((resr.startPos != endOfLine) && searchforLineEnd) continue; // Can't match end of line if start position before end of line endOfLine = resr.startPos; } } const DocumentIndexer di(doc, endOfLine); int success = search.Execute(di, startOfLine, endOfLine); if (success) { pos = search.bopat[0]; // Ensure only whole characters selected search.eopat[0] = doc->MovePositionOutsideChar(search.eopat[0], 1, false); lenRet = search.eopat[0] - search.bopat[0]; // There can be only one start of a line, so no need to look for last match in line if ((resr.increment == -1) && !searchforLineStart) { // Check for the last match on this line. int repetitions = 1000; // Break out of infinite loop while (success && (search.eopat[0] <= endOfLine) && (repetitions--)) { success = search.Execute(di, pos+1, endOfLine); if (success) { if (search.eopat[0] <= minPos) { pos = search.bopat[0]; lenRet = search.eopat[0] - search.bopat[0]; } else { success = 0; } } } } break; } } *length = lenRet; return pos; } const char *BuiltinRegex::SubstituteByPosition(Document *doc, const char *text, Sci::Position *length) { substituted.clear(); const DocumentIndexer di(doc, doc->Length()); search.GrabMatches(di); for (int j = 0; j < *length; j++) { if (text[j] == '\\') { if (text[j + 1] >= '0' && text[j + 1] <= '9') { const unsigned int patNum = text[j + 1] - '0'; const Sci::Position len = search.eopat[patNum] - search.bopat[patNum]; if (!search.pat[patNum].empty()) // Will be null if try for a match that did not occur substituted.append(search.pat[patNum].c_str(), len); j++; } else { j++; switch (text[j]) { case 'a': substituted.push_back('\a'); break; case 'b': substituted.push_back('\b'); break; case 'f': substituted.push_back('\f'); break; case 'n': substituted.push_back('\n'); break; case 'r': substituted.push_back('\r'); break; case 't': substituted.push_back('\t'); break; case 'v': substituted.push_back('\v'); break; case '\\': substituted.push_back('\\'); break; default: substituted.push_back('\\'); j--; } } } else { substituted.push_back(text[j]); } } *length = substituted.length(); return substituted.c_str(); } #ifndef SCI_OWNREGEX RegexSearchBase *Scintilla::CreateRegexSearch(CharClassify *charClassTable) { return new BuiltinRegex(charClassTable); } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Document.h000066400000000000000000000521731463772530400255160ustar00rootroot00000000000000// Scintilla source code edit control /** @file Document.h ** Text document that handles notifications, DBCS, styling, words and end of line. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef DOCUMENT_H #define DOCUMENT_H namespace Scintilla { class DocWatcher; class DocModification; class Document; class LineMarkers; class LineLevels; class LineState; class LineAnnotation; enum EncodingFamily { efEightBit, efUnicode, efDBCS }; /** * The range class represents a range of text in a document. * The two values are not sorted as one end may be more significant than the other * as is the case for the selection where the end position is the position of the caret. * If either position is invalidPosition then the range is invalid and most operations will fail. */ class Range { public: Sci::Position start; Sci::Position end; explicit Range(Sci::Position pos=0) noexcept : start(pos), end(pos) { } Range(Sci::Position start_, Sci::Position end_) noexcept : start(start_), end(end_) { } bool operator==(const Range &other) const noexcept { return (start == other.start) && (end == other.end); } bool Valid() const noexcept { return (start != Sci::invalidPosition) && (end != Sci::invalidPosition); } Sci::Position First() const noexcept { return (start <= end) ? start : end; } Sci::Position Last() const noexcept { return (start > end) ? start : end; } // Is the position within the range? bool Contains(Sci::Position pos) const noexcept { if (start < end) { return (pos >= start && pos <= end); } else { return (pos <= start && pos >= end); } } // Is the character after pos within the range? bool ContainsCharacter(Sci::Position pos) const noexcept { if (start < end) { return (pos >= start && pos < end); } else { return (pos < start && pos >= end); } } bool Contains(Range other) const noexcept { return Contains(other.start) && Contains(other.end); } bool Overlaps(Range other) const noexcept { return Contains(other.start) || Contains(other.end) || other.Contains(start) || other.Contains(end); } }; /** * Interface class for regular expression searching */ class RegexSearchBase { public: virtual ~RegexSearchBase() {} virtual Sci::Position FindText(Document *doc, Sci::Position minPos, Sci::Position maxPos, const char *s, bool caseSensitive, bool word, bool wordStart, int flags, Sci::Position *length) = 0; ///@return String with the substitutions, must remain valid until the next call or destruction virtual const char *SubstituteByPosition(Document *doc, const char *text, Sci::Position *length) = 0; }; /// Factory function for RegexSearchBase extern RegexSearchBase *CreateRegexSearch(CharClassify *charClassTable); struct StyledText { size_t length; const char *text; bool multipleStyles; size_t style; const unsigned char *styles; StyledText(size_t length_, const char *text_, bool multipleStyles_, int style_, const unsigned char *styles_) noexcept : length(length_), text(text_), multipleStyles(multipleStyles_), style(style_), styles(styles_) { } // Return number of bytes from start to before '\n' or end of text. // Return 1 when start is outside text size_t LineLength(size_t start) const noexcept { size_t cur = start; while ((cur < length) && (text[cur] != '\n')) cur++; return cur-start; } size_t StyleAt(size_t i) const noexcept { return multipleStyles ? styles[i] : style; } }; class HighlightDelimiter { public: HighlightDelimiter() : isEnabled(false) { Clear(); } void Clear() { beginFoldBlock = -1; endFoldBlock = -1; firstChangeableLineBefore = -1; firstChangeableLineAfter = -1; } bool NeedsDrawing(Sci::Line line) const { return isEnabled && (line <= firstChangeableLineBefore || line >= firstChangeableLineAfter); } bool IsFoldBlockHighlighted(Sci::Line line) const { return isEnabled && beginFoldBlock != -1 && beginFoldBlock <= line && line <= endFoldBlock; } bool IsHeadOfFoldBlock(Sci::Line line) const { return beginFoldBlock == line && line < endFoldBlock; } bool IsBodyOfFoldBlock(Sci::Line line) const { return beginFoldBlock != -1 && beginFoldBlock < line && line < endFoldBlock; } bool IsTailOfFoldBlock(Sci::Line line) const { return beginFoldBlock != -1 && beginFoldBlock < line && line == endFoldBlock; } Sci::Line beginFoldBlock; // Begin of current fold block Sci::Line endFoldBlock; // End of current fold block Sci::Line firstChangeableLineBefore; // First line that triggers repaint before starting line that determined current fold block Sci::Line firstChangeableLineAfter; // First line that triggers repaint after starting line that determined current fold block bool isEnabled; }; inline int LevelNumber(int level) noexcept { return level & SC_FOLDLEVELNUMBERMASK; } class LexInterface { protected: Document *pdoc; ILexer *instance; bool performingStyle; ///< Prevent reentrance public: explicit LexInterface(Document *pdoc_) : pdoc(pdoc_), instance(nullptr), performingStyle(false) { } virtual ~LexInterface() { } void Colourise(Sci::Position start, Sci::Position end); virtual int LineEndTypesSupported(); bool UseContainerLexing() const { return instance == nullptr; } }; struct RegexError : public std::runtime_error { RegexError() : std::runtime_error("regex failure") {} }; /** * The ActionDuration class stores the average time taken for some action such as styling or * wrapping a line. It is used to decide how many repetitions of that action can be performed * on idle to maximize efficiency without affecting application responsiveness. * The duration changes if the time for the action changes. For example, if a simple lexer is * changed to a complex lexer. Changes are damped and clamped to avoid short periods of easy * or difficult processing moving the value too far leading to inefficiency or poor user * experience. */ class ActionDuration { double duration; const double minDuration; const double maxDuration; public: ActionDuration(double duration_, double minDuration_, double maxDuration_) noexcept; void AddSample(size_t numberActions, double durationOfActions) noexcept; double Duration() const noexcept; }; /** */ class Document : PerLine, public IDocumentWithLineEnd, public ILoader { public: /** Used to pair watcher pointer with user data. */ struct WatcherWithUserData { DocWatcher *watcher; void *userData; WatcherWithUserData(DocWatcher *watcher_=nullptr, void *userData_=nullptr) noexcept : watcher(watcher_), userData(userData_) { } bool operator==(const WatcherWithUserData &other) const noexcept { return (watcher == other.watcher) && (userData == other.userData); } }; private: int refCount; CellBuffer cb; CharClassify charClass; std::unique_ptr pcf; Sci::Position endStyled; int styleClock; int enteredModification; int enteredStyling; int enteredReadOnlyCount; bool insertionSet; std::string insertion; std::vector watchers; // ldSize is not real data - it is for dimensions and loops enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldSize }; std::unique_ptr perLineData[ldSize]; LineMarkers *Markers() const; LineLevels *Levels() const; LineState *States() const; LineAnnotation *Margins() const; LineAnnotation *Annotations() const; bool matchesValid; std::unique_ptr regex; std::unique_ptr pli; public: struct CharacterExtracted { unsigned int character; unsigned int widthBytes; CharacterExtracted(unsigned int character_, unsigned int widthBytes_) noexcept : character(character_), widthBytes(widthBytes_) { } // For DBCS characters turn 2 bytes into an int static CharacterExtracted DBCS(unsigned char lead, unsigned char trail) noexcept { return CharacterExtracted((lead << 8) | trail, 2); } }; int eolMode; /// Can also be SC_CP_UTF8 to enable UTF-8 mode int dbcsCodePage; int lineEndBitSet; int tabInChars; int indentInChars; int actualIndentInChars; bool useTabs; bool tabIndents; bool backspaceUnindents; ActionDuration durationStyleOneLine; std::unique_ptr decorations; Document(int options); // Deleted so Document objects can not be copied. Document(const Document &) = delete; Document(Document &&) = delete; void operator=(const Document &) = delete; Document &operator=(Document &&) = delete; ~Document() override; int AddRef(); int SCI_METHOD Release() override; // From PerLine void Init() override; void InsertLine(Sci::Line line) override; void RemoveLine(Sci::Line line) override; int LineEndTypesSupported() const; bool SetDBCSCodePage(int dbcsCodePage_); int GetLineEndTypesAllowed() const { return cb.GetLineEndTypes(); } bool SetLineEndTypesAllowed(int lineEndBitSet_); int GetLineEndTypesActive() const { return cb.GetLineEndTypes(); } int SCI_METHOD Version() const override { return dvLineEnd; } void SCI_METHOD SetErrorStatus(int status) override; Sci_Position SCI_METHOD LineFromPosition(Sci_Position pos) const override; Sci::Line SciLineFromPosition(Sci::Position pos) const noexcept; // Avoids casting LineFromPosition Sci::Position ClampPositionIntoDocument(Sci::Position pos) const; bool ContainsLineEnd(const char *s, Sci::Position length) const { return cb.ContainsLineEnd(s, length); } bool IsCrLf(Sci::Position pos) const; int LenChar(Sci::Position pos); bool InGoodUTF8(Sci::Position pos, Sci::Position &start, Sci::Position &end) const noexcept; Sci::Position MovePositionOutsideChar(Sci::Position pos, Sci::Position moveDir, bool checkLineEnd=true) const; Sci::Position NextPosition(Sci::Position pos, int moveDir) const noexcept; bool NextCharacter(Sci::Position &pos, int moveDir) const noexcept; // Returns true if pos changed Document::CharacterExtracted CharacterAfter(Sci::Position position) const; Document::CharacterExtracted CharacterBefore(Sci::Position position) const; Sci_Position SCI_METHOD GetRelativePosition(Sci_Position positionStart, Sci_Position characterOffset) const override; Sci::Position GetRelativePositionUTF16(Sci::Position positionStart, Sci::Position characterOffset) const; int SCI_METHOD GetCharacterAndWidth(Sci_Position position, Sci_Position *pWidth) const override; int SCI_METHOD CodePage() const override; bool SCI_METHOD IsDBCSLeadByte(char ch) const override; bool IsDBCSLeadByteNoExcept(char ch) const noexcept; bool IsDBCSLeadByteInvalid(char ch) const noexcept; bool IsDBCSTrailByteInvalid(char ch) const noexcept; int DBCSDrawBytes(const char *text, int len) const noexcept; int SafeSegment(const char *text, int length, int lengthSegment) const noexcept; EncodingFamily CodePageFamily() const noexcept; // Gateways to modifying document void ModifiedAt(Sci::Position pos) noexcept; void CheckReadOnly(); bool DeleteChars(Sci::Position pos, Sci::Position len); Sci::Position InsertString(Sci::Position position, const char *s, Sci::Position insertLength); void ChangeInsertion(const char *s, Sci::Position length); int SCI_METHOD AddData(const char *data, Sci_Position length) override; void * SCI_METHOD ConvertToDocument() override; Sci::Position Undo(); Sci::Position Redo(); bool CanUndo() const { return cb.CanUndo(); } bool CanRedo() const { return cb.CanRedo(); } void DeleteUndoHistory() { cb.DeleteUndoHistory(); } bool SetUndoCollection(bool collectUndo) { return cb.SetUndoCollection(collectUndo); } bool IsCollectingUndo() const { return cb.IsCollectingUndo(); } void BeginUndoAction() { cb.BeginUndoAction(); } void EndUndoAction() { cb.EndUndoAction(); } void AddUndoAction(Sci::Position token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); } void SetSavePoint(); bool IsSavePoint() const { return cb.IsSavePoint(); } void TentativeStart() { cb.TentativeStart(); } void TentativeCommit() { cb.TentativeCommit(); } void TentativeUndo(); bool TentativeActive() const { return cb.TentativeActive(); } const char * SCI_METHOD BufferPointer() override { return cb.BufferPointer(); } const char *RangePointer(Sci::Position position, Sci::Position rangeLength) { return cb.RangePointer(position, rangeLength); } Sci::Position GapPosition() const { return cb.GapPosition(); } int SCI_METHOD GetLineIndentation(Sci_Position line) override; Sci::Position SetLineIndentation(Sci::Line line, Sci::Position indent); Sci::Position GetLineIndentPosition(Sci::Line line) const; Sci::Position GetColumn(Sci::Position pos); Sci::Position CountCharacters(Sci::Position startPos, Sci::Position endPos) const; Sci::Position CountUTF16(Sci::Position startPos, Sci::Position endPos) const; Sci::Position FindColumn(Sci::Line line, Sci::Position column); void Indent(bool forwards, Sci::Line lineBottom, Sci::Line lineTop); static std::string TransformLineEnds(const char *s, size_t len, int eolModeWanted); void ConvertLineEnds(int eolModeSet); void SetReadOnly(bool set) { cb.SetReadOnly(set); } bool IsReadOnly() const { return cb.IsReadOnly(); } bool IsLarge() const { return cb.IsLarge(); } int Options() const; void DelChar(Sci::Position pos); void DelCharBack(Sci::Position pos); char CharAt(Sci::Position position) const noexcept { return cb.CharAt(position); } void SCI_METHOD GetCharRange(char *buffer, Sci_Position position, Sci_Position lengthRetrieve) const override { cb.GetCharRange(buffer, position, lengthRetrieve); } char SCI_METHOD StyleAt(Sci_Position position) const override { return cb.StyleAt(position); } int StyleIndexAt(Sci_Position position) const noexcept { return static_cast(cb.StyleAt(position)); } void GetStyleRange(unsigned char *buffer, Sci::Position position, Sci::Position lengthRetrieve) const { cb.GetStyleRange(buffer, position, lengthRetrieve); } int GetMark(Sci::Line line) const; Sci::Line MarkerNext(Sci::Line lineStart, int mask) const; int AddMark(Sci::Line line, int markerNum); void AddMarkSet(Sci::Line line, int valueSet); void DeleteMark(Sci::Line line, int markerNum); void DeleteMarkFromHandle(int markerHandle); void DeleteAllMarks(int markerNum); Sci::Line LineFromHandle(int markerHandle) const; Sci_Position SCI_METHOD LineStart(Sci_Position line) const override; bool IsLineStartPosition(Sci::Position position) const; Sci_Position SCI_METHOD LineEnd(Sci_Position line) const override; Sci::Position LineEndPosition(Sci::Position position) const; bool IsLineEndPosition(Sci::Position position) const; bool IsPositionInLineEnd(Sci::Position position) const; Sci::Position VCHomePosition(Sci::Position position) const; Sci::Position IndexLineStart(Sci::Line line, int lineCharacterIndex) const; Sci::Line LineFromPositionIndex(Sci::Position pos, int lineCharacterIndex) const; int SCI_METHOD SetLevel(Sci_Position line, int level) override; int SCI_METHOD GetLevel(Sci_Position line) const override; void ClearLevels(); Sci::Line GetLastChild(Sci::Line lineParent, int level=-1, Sci::Line lastLine=-1); Sci::Line GetFoldParent(Sci::Line line) const; void GetHighlightDelimiters(HighlightDelimiter &highlightDelimiter, Sci::Line line, Sci::Line lastLine); Sci::Position ExtendWordSelect(Sci::Position pos, int delta, bool onlyWordCharacters=false) const; Sci::Position NextWordStart(Sci::Position pos, int delta) const; Sci::Position NextWordEnd(Sci::Position pos, int delta) const; Sci_Position SCI_METHOD Length() const override { return cb.Length(); } void Allocate(Sci::Position newSize) { cb.Allocate(newSize); } CharacterExtracted ExtractCharacter(Sci::Position position) const noexcept; bool IsWordStartAt(Sci::Position pos) const; bool IsWordEndAt(Sci::Position pos) const; bool IsWordAt(Sci::Position start, Sci::Position end) const; bool MatchesWordOptions(bool word, bool wordStart, Sci::Position pos, Sci::Position length) const; bool HasCaseFolder() const noexcept; void SetCaseFolder(CaseFolder *pcf_); Sci::Position FindText(Sci::Position minPos, Sci::Position maxPos, const char *search, int flags, Sci::Position *length); const char *SubstituteByPosition(const char *text, Sci::Position *length); int LineCharacterIndex() const; void AllocateLineCharacterIndex(int lineCharacterIndex); void ReleaseLineCharacterIndex(int lineCharacterIndex); Sci::Line LinesTotal() const noexcept; void SetDefaultCharClasses(bool includeWordClass); void SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass); int GetCharsOfClass(CharClassify::cc characterClass, unsigned char *buffer) const; void SCI_METHOD StartStyling(Sci_Position position, char mask) override; bool SCI_METHOD SetStyleFor(Sci_Position length, char style) override; bool SCI_METHOD SetStyles(Sci_Position length, const char *styles) override; Sci::Position GetEndStyled() const noexcept { return endStyled; } void EnsureStyledTo(Sci::Position pos); void StyleToAdjustingLineDuration(Sci::Position pos); void LexerChanged(); int GetStyleClock() const noexcept { return styleClock; } void IncrementStyleClock() noexcept; void SCI_METHOD DecorationSetCurrentIndicator(int indicator) override; void SCI_METHOD DecorationFillRange(Sci_Position position, int value, Sci_Position fillLength) override; LexInterface *GetLexInterface() const; void SetLexInterface(LexInterface *pLexInterface); int SCI_METHOD SetLineState(Sci_Position line, int state) override; int SCI_METHOD GetLineState(Sci_Position line) const override; Sci::Line GetMaxLineState() const; void SCI_METHOD ChangeLexerState(Sci_Position start, Sci_Position end) override; StyledText MarginStyledText(Sci::Line line) const; void MarginSetStyle(Sci::Line line, int style); void MarginSetStyles(Sci::Line line, const unsigned char *styles); void MarginSetText(Sci::Line line, const char *text); void MarginClearAll(); StyledText AnnotationStyledText(Sci::Line line) const; void AnnotationSetText(Sci::Line line, const char *text); void AnnotationSetStyle(Sci::Line line, int style); void AnnotationSetStyles(Sci::Line line, const unsigned char *styles); int AnnotationLines(Sci::Line line) const; void AnnotationClearAll(); bool AddWatcher(DocWatcher *watcher, void *userData); bool RemoveWatcher(DocWatcher *watcher, void *userData); bool IsASCIIWordByte(unsigned char ch) const; CharClassify::cc WordCharacterClass(unsigned int ch) const; bool IsWordPartSeparator(unsigned int ch) const; Sci::Position WordPartLeft(Sci::Position pos) const; Sci::Position WordPartRight(Sci::Position pos) const; Sci::Position ExtendStyleRange(Sci::Position pos, int delta, bool singleLine = false); bool IsWhiteLine(Sci::Line line) const; Sci::Position ParaUp(Sci::Position pos) const; Sci::Position ParaDown(Sci::Position pos) const; int IndentSize() const noexcept { return actualIndentInChars; } Sci::Position BraceMatch(Sci::Position position, Sci::Position maxReStyle); private: void NotifyModifyAttempt(); void NotifySavePoint(bool atSavePoint); void NotifyModified(DocModification mh); }; class UndoGroup { Document *pdoc; bool groupNeeded; public: UndoGroup(Document *pdoc_, bool groupNeeded_=true) : pdoc(pdoc_), groupNeeded(groupNeeded_) { if (groupNeeded) { pdoc->BeginUndoAction(); } } ~UndoGroup() { if (groupNeeded) { pdoc->EndUndoAction(); } } bool Needed() const noexcept { return groupNeeded; } }; /** * To optimise processing of document modifications by DocWatchers, a hint is passed indicating the * scope of the change. * If the DocWatcher is a document view then this can be used to optimise screen updating. */ class DocModification { public: int modificationType; Sci::Position position; Sci::Position length; Sci::Line linesAdded; /**< Negative if lines deleted. */ const char *text; /**< Only valid for changes to text, not for changes to style. */ Sci::Line line; int foldLevelNow; int foldLevelPrev; Sci::Line annotationLinesAdded; Sci::Position token; DocModification(int modificationType_, Sci::Position position_=0, Sci::Position length_=0, Sci::Line linesAdded_=0, const char *text_=nullptr, Sci::Line line_=0) noexcept : modificationType(modificationType_), position(position_), length(length_), linesAdded(linesAdded_), text(text_), line(line_), foldLevelNow(0), foldLevelPrev(0), annotationLinesAdded(0), token(0) {} DocModification(int modificationType_, const Action &act, Sci::Line linesAdded_=0) noexcept : modificationType(modificationType_), position(act.position), length(act.lenData), linesAdded(linesAdded_), text(act.data.get()), line(0), foldLevelNow(0), foldLevelPrev(0), annotationLinesAdded(0), token(0) {} }; /** * A class that wants to receive notifications from a Document must be derived from DocWatcher * and implement the notification methods. It can then be added to the watcher list with AddWatcher. */ class DocWatcher { public: virtual ~DocWatcher() {} virtual void NotifyModifyAttempt(Document *doc, void *userData) = 0; virtual void NotifySavePoint(Document *doc, void *userData, bool atSavePoint) = 0; virtual void NotifyModified(Document *doc, DocModification mh, void *userData) = 0; virtual void NotifyDeleted(Document *doc, void *userData) = 0; virtual void NotifyStyleNeeded(Document *doc, void *userData, Sci::Position endPos) = 0; virtual void NotifyLexerChanged(Document *doc, void *userData) = 0; virtual void NotifyErrorOccurred(Document *doc, void *userData, int status) = 0; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/EditModel.cpp000066400000000000000000000035131463772530400261330ustar00rootroot00000000000000// Scintilla source code edit control /** @file EditModel.cxx ** Defines the editor state that must be visible to EditorView. **/ // Copyright 1998-2014 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILoader.h" #include "ILexer.h" #include "Scintilla.h" #include "Position.h" #include "UniqueString.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "KeyMap.h" #include "Indicator.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" #include "EditModel.h" using namespace Scintilla; Caret::Caret() : active(false), on(false), period(500) {} EditModel::EditModel() : braces{} { inOverstrike = false; xOffset = 0; trackLineWidth = false; posDrag = SelectionPosition(Sci::invalidPosition); braces[0] = Sci::invalidPosition; braces[1] = Sci::invalidPosition; bracesMatchStyle = STYLE_BRACEBAD; highlightGuideColumn = 0; primarySelection = true; imeInteraction = imeWindowed; foldFlags = 0; foldDisplayTextStyle = SC_FOLDDISPLAYTEXT_HIDDEN; hotspot = Range(Sci::invalidPosition); hoverIndicatorPos = Sci::invalidPosition; wrapWidth = LineLayout::wrapWidthInfinite; pdoc = new Document(SC_DOCUMENTOPTION_DEFAULT); pdoc->AddRef(); pcs = ContractionStateCreate(pdoc->IsLarge()); } EditModel::~EditModel() { pdoc->Release(); pdoc = nullptr; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/EditModel.h000066400000000000000000000027161463772530400256040ustar00rootroot00000000000000// Scintilla source code edit control /** @file EditModel.h ** Defines the editor state that must be visible to EditorView. **/ // Copyright 1998-2014 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef EDITMODEL_H #define EDITMODEL_H namespace Scintilla { /** */ class Caret { public: bool active; bool on; int period; Caret(); }; class EditModel { public: bool inOverstrike; int xOffset; ///< Horizontal scrolled amount in pixels bool trackLineWidth; SpecialRepresentations reprs; Caret caret; SelectionPosition posDrag; Sci::Position braces[2]; int bracesMatchStyle; int highlightGuideColumn; Selection sel; bool primarySelection; enum IMEInteraction { imeWindowed, imeInline } imeInteraction; int foldFlags; int foldDisplayTextStyle; std::unique_ptr pcs; // Hotspot support Range hotspot; Sci::Position hoverIndicatorPos; // Wrapping support int wrapWidth; Document *pdoc; EditModel(); // Deleted so EditModel objects can not be copied. EditModel(const EditModel &) = delete; EditModel(EditModel &&) = delete; EditModel &operator=(const EditModel &) = delete; EditModel &operator=(EditModel &&) = delete; virtual ~EditModel(); virtual Sci::Line TopLineOfMain() const = 0; virtual Point GetVisibleOriginInMain() const = 0; virtual Sci::Line LinesOnScreen() const = 0; virtual Range GetHotSpotRange() const = 0; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/EditView.cpp000066400000000000000000003056431463772530400260160ustar00rootroot00000000000000// Scintilla source code edit control /** @file EditView.cxx ** Defines the appearance of the main text area of the editor window. **/ // Copyright 1998-2014 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILoader.h" #include "ILexer.h" #include "Scintilla.h" #include "StringCopy.h" #include "CharacterSet.h" #include "Position.h" #include "IntegerRectangle.h" #include "UniqueString.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "PerLine.h" #include "KeyMap.h" #include "Indicator.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" #include "EditModel.h" #include "MarginView.h" #include "EditView.h" #include "ElapsedPeriod.h" using namespace Scintilla; static inline bool IsControlCharacter(int ch) { // iscntrl returns true for lots of chars > 127 which are displayable return ch >= 0 && ch < ' '; } PrintParameters::PrintParameters() { magnification = 0; colourMode = SC_PRINT_NORMAL; wrapState = eWrapWord; } namespace Scintilla { bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) { if (st.multipleStyles) { for (size_t iStyle = 0; iStyle(surface->WidthText(fontText, text + start, static_cast(endSegment - start + 1))); start = endSegment + 1; } return width; } int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st) { int widthMax = 0; size_t start = 0; while (start < st.length) { const size_t lenLine = st.LineLength(start); int widthSubLine; if (st.multipleStyles) { widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); } else { FontAlias fontText = vs.styles[styleOffset + st.style].font; widthSubLine = static_cast(surface->WidthText(fontText, st.text + start, static_cast(lenLine))); } if (widthSubLine > widthMax) widthMax = widthSubLine; start += lenLine + 1; } return widthMax; } void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase, const char *s, int len, DrawPhase phase) { FontAlias fontText = style.font; if (phase & drawBack) { if (phase & drawText) { // Drawing both surface->DrawTextNoClip(rc, fontText, ybase, s, len, style.fore, style.back); } else { surface->FillRectangle(rc, style.back); } } else if (phase & drawText) { surface->DrawTextTransparent(rc, fontText, ybase, s, len, style.fore); } } void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, const StyledText &st, size_t start, size_t length, DrawPhase phase) { if (st.multipleStyles) { int x = static_cast(rcText.left); size_t i = 0; while (i < length) { size_t end = i; size_t style = st.styles[i + start]; while (end < length - 1 && st.styles[start + end + 1] == style) end++; style += styleOffset; FontAlias fontText = vs.styles[style].font; const int width = static_cast(surface->WidthText(fontText, st.text + start + i, static_cast(end - i + 1))); PRectangle rcSegment = rcText; rcSegment.left = static_cast(x); rcSegment.right = static_cast(x + width + 1); DrawTextNoClipPhase(surface, rcSegment, vs.styles[style], rcText.top + vs.maxAscent, st.text + start + i, static_cast(end - i + 1), phase); x += width; i = end + 1; } } else { const size_t style = st.style + styleOffset; DrawTextNoClipPhase(surface, rcText, vs.styles[style], rcText.top + vs.maxAscent, st.text + start, static_cast(length), phase); } } } const XYPOSITION epsilon = 0.0001f; // A small nudge to avoid floating point precision issues EditView::EditView() { tabWidthMinimumPixels = 2; // needed for calculating tab stops for fractional proportional fonts hideSelection = false; drawOverstrikeCaret = true; bufferedDraw = true; phasesDraw = phasesTwo; lineWidthMaxSeen = 0; additionalCaretsBlink = true; additionalCaretsVisible = true; imeCaretBlockOverride = false; llc.SetLevel(LineLayoutCache::llcCaret); posCache.SetSize(0x400); tabArrowHeight = 4; customDrawTabArrow = nullptr; customDrawWrapMarker = nullptr; } EditView::~EditView() { } bool EditView::SetTwoPhaseDraw(bool twoPhaseDraw) { const PhasesDraw phasesDrawNew = twoPhaseDraw ? phasesTwo : phasesOne; const bool redraw = phasesDraw != phasesDrawNew; phasesDraw = phasesDrawNew; return redraw; } bool EditView::SetPhasesDraw(int phases) { const PhasesDraw phasesDrawNew = static_cast(phases); const bool redraw = phasesDraw != phasesDrawNew; phasesDraw = phasesDrawNew; return redraw; } bool EditView::LinesOverlap() const { return phasesDraw == phasesMultiple; } void EditView::ClearAllTabstops() { ldTabstops.reset(); } XYPOSITION EditView::NextTabstopPos(Sci::Line line, XYPOSITION x, XYPOSITION tabWidth) const { const int next = GetNextTabstop(line, static_cast(x + tabWidthMinimumPixels)); if (next > 0) return static_cast(next); return (static_cast((x + tabWidthMinimumPixels) / tabWidth) + 1) * tabWidth; } bool EditView::ClearTabstops(Sci::Line line) { return ldTabstops && ldTabstops->ClearTabstops(line); } bool EditView::AddTabstop(Sci::Line line, int x) { if (!ldTabstops) { ldTabstops.reset(new LineTabstops()); } return ldTabstops && ldTabstops->AddTabstop(line, x); } int EditView::GetNextTabstop(Sci::Line line, int x) const { if (ldTabstops) { return ldTabstops->GetNextTabstop(line, x); } else { return 0; } } void EditView::LinesAddedOrRemoved(Sci::Line lineOfPos, Sci::Line linesAdded) { if (ldTabstops) { if (linesAdded > 0) { for (Sci::Line line = lineOfPos; line < lineOfPos + linesAdded; line++) { ldTabstops->InsertLine(line); } } else { for (Sci::Line line = (lineOfPos + -linesAdded) - 1; line >= lineOfPos; line--) { ldTabstops->RemoveLine(line); } } } } void EditView::DropGraphics(bool freeObjects) { if (freeObjects) { pixmapLine.reset(); pixmapIndentGuide.reset(); pixmapIndentGuideHighlight.reset(); } else { if (pixmapLine) pixmapLine->Release(); if (pixmapIndentGuide) pixmapIndentGuide->Release(); if (pixmapIndentGuideHighlight) pixmapIndentGuideHighlight->Release(); } } void EditView::AllocateGraphics(const ViewStyle &vsDraw) { if (!pixmapLine) pixmapLine.reset(Surface::Allocate(vsDraw.technology)); if (!pixmapIndentGuide) pixmapIndentGuide.reset(Surface::Allocate(vsDraw.technology)); if (!pixmapIndentGuideHighlight) pixmapIndentGuideHighlight.reset(Surface::Allocate(vsDraw.technology)); } static const char *ControlCharacterString(unsigned char ch) { const char * const reps[] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" }; if (ch < ELEMENTS(reps)) { return reps[ch]; } else { return "BAD"; } } static void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid, const ViewStyle &vsDraw) { const IntegerRectangle ircTab(rcTab); if ((rcTab.left + 2) < (rcTab.right - 1)) surface->MoveTo(ircTab.left + 2, ymid); else surface->MoveTo(ircTab.right - 1, ymid); surface->LineTo(ircTab.right - 1, ymid); // Draw the arrow head if needed if (vsDraw.tabDrawMode == tdLongArrow) { int ydiff = (ircTab.bottom - ircTab.top) / 2; int xhead = ircTab.right - 1 - ydiff; if (xhead <= rcTab.left) { ydiff -= ircTab.left - xhead - 1; xhead = ircTab.left - 1; } surface->LineTo(xhead, ymid - ydiff); surface->MoveTo(ircTab.right - 1, ymid); surface->LineTo(xhead, ymid + ydiff); } } void EditView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) { if (!pixmapIndentGuide->Initialised()) { // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line pixmapIndentGuide->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid); pixmapIndentGuideHighlight->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid); const PRectangle rcIG = PRectangle::FromInts(0, 0, 1, vsDraw.lineHeight); pixmapIndentGuide->FillRectangle(rcIG, vsDraw.styles[STYLE_INDENTGUIDE].back); pixmapIndentGuide->PenColour(vsDraw.styles[STYLE_INDENTGUIDE].fore); pixmapIndentGuideHighlight->FillRectangle(rcIG, vsDraw.styles[STYLE_BRACELIGHT].back); pixmapIndentGuideHighlight->PenColour(vsDraw.styles[STYLE_BRACELIGHT].fore); for (int stripe = 1; stripe < vsDraw.lineHeight + 1; stripe += 2) { const PRectangle rcPixel = PRectangle::FromInts(0, stripe, 1, stripe + 1); pixmapIndentGuide->FillRectangle(rcPixel, vsDraw.styles[STYLE_INDENTGUIDE].fore); pixmapIndentGuideHighlight->FillRectangle(rcPixel, vsDraw.styles[STYLE_BRACELIGHT].fore); } } } LineLayout *EditView::RetrieveLineLayout(Sci::Line lineNumber, const EditModel &model) { const Sci::Position posLineStart = model.pdoc->LineStart(lineNumber); const Sci::Position posLineEnd = model.pdoc->LineStart(lineNumber + 1); PLATFORM_ASSERT(posLineEnd >= posLineStart); const Sci::Line lineCaret = model.pdoc->SciLineFromPosition(model.sel.MainCaret()); return llc.Retrieve(lineNumber, lineCaret, static_cast(posLineEnd - posLineStart), model.pdoc->GetStyleClock(), model.LinesOnScreen() + 1, model.pdoc->LinesTotal()); } /** * Fill in the LineLayout data for the given line. * Copy the given @a line and its styles from the document into local arrays. * Also determine the x position at which each character starts. */ void EditView::LayoutLine(const EditModel &model, Sci::Line line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, int width) { if (!ll) return; PLATFORM_ASSERT(line < model.pdoc->LinesTotal()); PLATFORM_ASSERT(ll->chars != NULL); const Sci::Position posLineStart = model.pdoc->LineStart(line); Sci::Position posLineEnd = model.pdoc->LineStart(line + 1); // If the line is very long, limit the treatment to a length that should fit in the viewport if (posLineEnd >(posLineStart + ll->maxLineLength)) { posLineEnd = posLineStart + ll->maxLineLength; } if (ll->validity == LineLayout::llCheckTextAndStyle) { Sci::Position lineLength = posLineEnd - posLineStart; if (!vstyle.viewEOL) { lineLength = model.pdoc->LineEnd(line) - posLineStart; } if (lineLength == ll->numCharsInLine) { // See if chars, styles, indicators, are all the same bool allSame = true; // Check base line layout int styleByte = 0; int numCharsInLine = 0; while (numCharsInLine < lineLength) { const Sci::Position charInDoc = numCharsInLine + posLineStart; const char chDoc = model.pdoc->CharAt(charInDoc); styleByte = model.pdoc->StyleIndexAt(charInDoc); allSame = allSame && (ll->styles[numCharsInLine] == styleByte); if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed) allSame = allSame && (ll->chars[numCharsInLine] == chDoc); else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) allSame = allSame && (ll->chars[numCharsInLine] == MakeLowerCase(chDoc)); else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseUpper) allSame = allSame && (ll->chars[numCharsInLine] == MakeUpperCase(chDoc)); else { // Style::caseCamel if ((model.pdoc->IsASCIIWordByte(ll->chars[numCharsInLine])) && ((numCharsInLine == 0) || (!model.pdoc->IsASCIIWordByte(ll->chars[numCharsInLine - 1])))) { allSame = allSame && (ll->chars[numCharsInLine] == MakeUpperCase(chDoc)); } else { allSame = allSame && (ll->chars[numCharsInLine] == MakeLowerCase(chDoc)); } } numCharsInLine++; } allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled if (allSame) { ll->validity = LineLayout::llPositions; } else { ll->validity = LineLayout::llInvalid; } } else { ll->validity = LineLayout::llInvalid; } } if (ll->validity == LineLayout::llInvalid) { ll->widthLine = LineLayout::wrapWidthInfinite; ll->lines = 1; if (vstyle.edgeState == EDGE_BACKGROUND) { Sci::Position edgePosition = model.pdoc->FindColumn(line, vstyle.theEdge.column); if (edgePosition >= posLineStart) { edgePosition -= posLineStart; } ll->edgeColumn = static_cast(edgePosition); } else { ll->edgeColumn = -1; } // Fill base line layout const int lineLength = static_cast(posLineEnd - posLineStart); model.pdoc->GetCharRange(ll->chars.get(), posLineStart, lineLength); model.pdoc->GetStyleRange(ll->styles.get(), posLineStart, lineLength); const int numCharsBeforeEOL = static_cast(model.pdoc->LineEnd(line) - posLineStart); const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL; for (Sci::Position styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) { const unsigned char styleByte = ll->styles[styleInLine]; ll->styles[styleInLine] = styleByte; } const unsigned char styleByteLast = (lineLength > 0) ? ll->styles[lineLength - 1] : 0; if (vstyle.someStylesForceCase) { for (int charInLine = 0; charInLinechars[charInLine]; if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseUpper) ll->chars[charInLine] = MakeUpperCase(chDoc); else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseLower) ll->chars[charInLine] = MakeLowerCase(chDoc); else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseCamel) { if ((model.pdoc->IsASCIIWordByte(ll->chars[charInLine])) && ((charInLine == 0) || (!model.pdoc->IsASCIIWordByte(ll->chars[charInLine - 1])))) { ll->chars[charInLine] = MakeUpperCase(chDoc); } else { ll->chars[charInLine] = MakeLowerCase(chDoc); } } } } ll->xHighlightGuide = 0; // Extra element at the end of the line to hold end x position and act as ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character ll->styles[numCharsInLine] = styleByteLast; // For eolFilled // Layout the line, determining the position of each character, // with an extra element at the end for the end of the line. ll->positions[0] = 0; bool lastSegItalics = false; BreakFinder bfLayout(ll, nullptr, Range(0, numCharsInLine), posLineStart, 0, false, model.pdoc, &model.reprs, nullptr); while (bfLayout.More()) { const TextSegment ts = bfLayout.Next(); std::fill(&ll->positions[ts.start + 1], &ll->positions[ts.end() + 1], 0.0f); if (vstyle.styles[ll->styles[ts.start]].visible) { if (ts.representation) { XYPOSITION representationWidth = vstyle.controlCharWidth; if (ll->chars[ts.start] == '\t') { // Tab is a special case of representation, taking a variable amount of space const XYPOSITION x = ll->positions[ts.start]; representationWidth = NextTabstopPos(line, x, vstyle.tabWidth) - ll->positions[ts.start]; } else { if (representationWidth <= 0.0) { XYPOSITION positionsRepr[256]; // Should expand when needed posCache.MeasureWidths(surface, vstyle, STYLE_CONTROLCHAR, ts.representation->stringRep.c_str(), static_cast(ts.representation->stringRep.length()), positionsRepr, model.pdoc); representationWidth = positionsRepr[ts.representation->stringRep.length() - 1] + vstyle.ctrlCharPadding; } } for (int ii = 0; ii < ts.length; ii++) ll->positions[ts.start + 1 + ii] = representationWidth; } else { if ((ts.length == 1) && (' ' == ll->chars[ts.start])) { // Over half the segments are single characters and of these about half are space characters. ll->positions[ts.start + 1] = vstyle.styles[ll->styles[ts.start]].spaceWidth; } else { posCache.MeasureWidths(surface, vstyle, ll->styles[ts.start], &ll->chars[ts.start], ts.length, &ll->positions[ts.start + 1], model.pdoc); } } lastSegItalics = (!ts.representation) && ((ll->chars[ts.end() - 1] != ' ') && vstyle.styles[ll->styles[ts.start]].italic); } for (Sci::Position posToIncrease = ts.start + 1; posToIncrease <= ts.end(); posToIncrease++) { ll->positions[posToIncrease] += ll->positions[ts.start]; } } // Small hack to make lines that end with italics not cut off the edge of the last character if (lastSegItalics) { ll->positions[numCharsInLine] += vstyle.lastSegItalicsOffset; } ll->numCharsInLine = numCharsInLine; ll->numCharsBeforeEOL = numCharsBeforeEOL; ll->validity = LineLayout::llPositions; } // Hard to cope when too narrow, so just assume there is space if (width < 20) { width = 20; } if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) { ll->widthLine = width; if (width == LineLayout::wrapWidthInfinite) { ll->lines = 1; } else if (width > ll->positions[ll->numCharsInLine]) { // Simple common case where line does not need wrapping. ll->lines = 1; } else { if (vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { width -= static_cast(vstyle.aveCharWidth); // take into account the space for end wrap mark } XYPOSITION wrapAddIndent = 0; // This will be added to initial indent of line switch (vstyle.wrapIndentMode) { case SC_WRAPINDENT_FIXED: wrapAddIndent = vstyle.wrapVisualStartIndent * vstyle.aveCharWidth; break; case SC_WRAPINDENT_INDENT: wrapAddIndent = model.pdoc->IndentSize() * vstyle.spaceWidth; break; case SC_WRAPINDENT_DEEPINDENT: wrapAddIndent = model.pdoc->IndentSize() * 2 * vstyle.spaceWidth; break; } ll->wrapIndent = wrapAddIndent; if (vstyle.wrapIndentMode != SC_WRAPINDENT_FIXED) { for (int i = 0; i < ll->numCharsInLine; i++) { if (!IsSpaceOrTab(ll->chars[i])) { ll->wrapIndent += ll->positions[i]; // Add line indent break; } } } // Check for text width minimum if (ll->wrapIndent > width - static_cast(vstyle.aveCharWidth) * 15) ll->wrapIndent = wrapAddIndent; // Check for wrapIndent minimum if ((vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < vstyle.aveCharWidth)) ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual ll->lines = 0; // Calculate line start positions based upon width. Sci::Position lastGoodBreak = 0; Sci::Position lastLineStart = 0; XYACCUMULATOR startOffset = 0; Sci::Position p = 0; while (p < ll->numCharsInLine) { if ((ll->positions[p + 1] - startOffset) >= width) { if (lastGoodBreak == lastLineStart) { // Try moving to start of last character if (p > 0) { lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) - posLineStart; } if (lastGoodBreak == lastLineStart) { // Ensure at least one character on line. lastGoodBreak = model.pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) - posLineStart; } } lastLineStart = lastGoodBreak; ll->lines++; ll->SetLineStart(ll->lines, static_cast(lastGoodBreak)); startOffset = ll->positions[lastGoodBreak]; // take into account the space for start wrap mark and indent startOffset -= ll->wrapIndent; p = lastGoodBreak + 1; continue; } if (p > 0) { if (vstyle.wrapState == eWrapChar) { lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) - posLineStart; p = model.pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart; continue; } else if ((vstyle.wrapState == eWrapWord) && (ll->styles[p] != ll->styles[p - 1])) { lastGoodBreak = p; } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) { lastGoodBreak = p; } } p++; } ll->lines++; } ll->validity = LineLayout::llLines; } } Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, Sci::Line topLine, const ViewStyle &vs, PointEnd pe) { Point pt; if (pos.Position() == INVALID_POSITION) return pt; Sci::Line lineDoc = model.pdoc->SciLineFromPosition(pos.Position()); Sci::Position posLineStart = model.pdoc->LineStart(lineDoc); if ((pe & peLineEnd) && (lineDoc > 0) && (pos.Position() == posLineStart)) { // Want point at end of first line lineDoc--; posLineStart = model.pdoc->LineStart(lineDoc); } const Sci::Line lineVisible = model.pcs->DisplayFromDoc(lineDoc); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); if (surface && ll) { LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); const int posInLine = static_cast(pos.Position() - posLineStart); pt = ll->PointFromPosition(posInLine, vs.lineHeight, pe); pt.y += (lineVisible - topLine) * vs.lineHeight; pt.x += vs.textStart - model.xOffset; } pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth; return pt; } Range EditView::RangeDisplayLine(Surface *surface, const EditModel &model, Sci::Line lineVisible, const ViewStyle &vs) { Range rangeSubLine = Range(0, 0); if (lineVisible < 0) { return rangeSubLine; } const Sci::Line lineDoc = model.pcs->DocFromDisplay(lineVisible); const Sci::Position positionLineStart = model.pdoc->LineStart(lineDoc); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); if (surface && ll) { LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); const Sci::Line lineStartSet = model.pcs->DisplayFromDoc(lineDoc); const int subLine = static_cast(lineVisible - lineStartSet); if (subLine < ll->lines) { rangeSubLine = ll->SubLineRange(subLine, LineLayout::Scope::visibleOnly); if (subLine == ll->lines-1) { rangeSubLine.end = model.pdoc->LineStart(lineDoc + 1) - positionLineStart; } } } rangeSubLine.start += positionLineStart; rangeSubLine.end += positionLineStart; return rangeSubLine; } SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditModel &model, PointDocument pt, bool canReturnInvalid, bool charPosition, bool virtualSpace, const ViewStyle &vs) { pt.x = pt.x - vs.textStart; Sci::Line visibleLine = static_cast(floor(pt.y / vs.lineHeight)); if (!canReturnInvalid && (visibleLine < 0)) visibleLine = 0; const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine); if (canReturnInvalid && (lineDoc < 0)) return SelectionPosition(INVALID_POSITION); if (lineDoc >= model.pdoc->LinesTotal()) return SelectionPosition(canReturnInvalid ? INVALID_POSITION : model.pdoc->Length()); const Sci::Position posLineStart = model.pdoc->LineStart(lineDoc); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); if (surface && ll) { LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); const Sci::Line lineStartSet = model.pcs->DisplayFromDoc(lineDoc); const int subLine = static_cast(visibleLine - lineStartSet); if (subLine < ll->lines) { const Range rangeSubLine = ll->SubLineRange(subLine, LineLayout::Scope::visibleOnly); const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; if (subLine > 0) // Wrapped pt.x -= ll->wrapIndent; const Sci::Position positionInLine = ll->FindPositionFromX(static_cast(pt.x + subLineStart), rangeSubLine, charPosition); if (positionInLine < rangeSubLine.end) { return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); } if (virtualSpace) { const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; const int spaceOffset = static_cast( (pt.x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); } else if (canReturnInvalid) { if (pt.x < (ll->positions[rangeSubLine.end] - subLineStart)) { return SelectionPosition(model.pdoc->MovePositionOutsideChar(rangeSubLine.end + posLineStart, 1)); } } else { return SelectionPosition(rangeSubLine.end + posLineStart); } } if (!canReturnInvalid) return SelectionPosition(ll->numCharsInLine + posLineStart); } return SelectionPosition(canReturnInvalid ? INVALID_POSITION : posLineStart); } /** * Find the document position corresponding to an x coordinate on a particular document line. * Ensure is between whole characters when document is in multi-byte or UTF-8 mode. * This method is used for rectangular selections and does not work on wrapped lines. */ SelectionPosition EditView::SPositionFromLineX(Surface *surface, const EditModel &model, Sci::Line lineDoc, int x, const ViewStyle &vs) { AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); if (surface && ll) { const Sci::Position posLineStart = model.pdoc->LineStart(lineDoc); LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); const Range rangeSubLine = ll->SubLineRange(0, LineLayout::Scope::visibleOnly); const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; const Sci::Position positionInLine = ll->FindPositionFromX(x + subLineStart, rangeSubLine, false); if (positionInLine < rangeSubLine.end) { return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); } const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; const int spaceOffset = static_cast( (x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); } return SelectionPosition(0); } Sci::Line EditView::DisplayFromPosition(Surface *surface, const EditModel &model, Sci::Position pos, const ViewStyle &vs) { const Sci::Line lineDoc = model.pdoc->SciLineFromPosition(pos); Sci::Line lineDisplay = model.pcs->DisplayFromDoc(lineDoc); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); if (surface && ll) { LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); const Sci::Position posLineStart = model.pdoc->LineStart(lineDoc); const Sci::Position posInLine = pos - posLineStart; lineDisplay--; // To make up for first increment ahead. for (int subLine = 0; subLine < ll->lines; subLine++) { if (posInLine >= ll->LineStart(subLine)) { lineDisplay++; } } } return lineDisplay; } Sci::Position EditView::StartEndDisplayLine(Surface *surface, const EditModel &model, Sci::Position pos, bool start, const ViewStyle &vs) { const Sci::Line line = model.pdoc->SciLineFromPosition(pos); AutoLineLayout ll(llc, RetrieveLineLayout(line, model)); Sci::Position posRet = INVALID_POSITION; if (surface && ll) { const Sci::Position posLineStart = model.pdoc->LineStart(line); LayoutLine(model, line, surface, vs, ll, model.wrapWidth); const Sci::Position posInLine = pos - posLineStart; if (posInLine <= ll->maxLineLength) { for (int subLine = 0; subLine < ll->lines; subLine++) { if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1)) && (posInLine <= ll->numCharsBeforeEOL)) { if (start) { posRet = ll->LineStart(subLine) + posLineStart; } else { if (subLine == ll->lines - 1) posRet = ll->numCharsBeforeEOL + posLineStart; else posRet = ll->LineStart(subLine + 1) + posLineStart - 1; } } } } } return posRet; } static ColourDesired SelectionBackground(const ViewStyle &vsDraw, bool main, bool primarySelection) { return main ? (primarySelection ? vsDraw.selColours.back : vsDraw.selBackground2) : vsDraw.selAdditionalBackground; } static ColourDesired TextBackground(const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, ColourOptional background, int inSelection, bool inHotspot, int styleMain, Sci::Position i) { if (inSelection == 1) { if (vsDraw.selColours.back.isSet && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { return SelectionBackground(vsDraw, true, model.primarySelection); } } else if (inSelection == 2) { if (vsDraw.selColours.back.isSet && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) { return SelectionBackground(vsDraw, false, model.primarySelection); } } else { if ((vsDraw.edgeState == EDGE_BACKGROUND) && (i >= ll->edgeColumn) && (i < ll->numCharsBeforeEOL)) return vsDraw.theEdge.colour; if (inHotspot && vsDraw.hotspotColours.back.isSet) return vsDraw.hotspotColours.back; } if (background.isSet && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) { return background; } else { return vsDraw.styles[styleMain].back; } } void EditView::DrawIndentGuide(Surface *surface, Sci::Line lineVisible, int lineHeight, XYPOSITION start, PRectangle rcSegment, bool highlight) { const Point from = Point::FromInts(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0); const PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom); surface->Copy(rcCopyArea, from, highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide); } static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha) { if (alpha != SC_ALPHA_NOALPHA) { surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0); } } static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment, const char *s, ColourDesired textBack, ColourDesired textFore, bool fillBackground) { if (rcSegment.Empty()) return; if (fillBackground) { surface->FillRectangle(rcSegment, textBack); } FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; const int normalCharHeight = static_cast(ceil(vsDraw.styles[STYLE_CONTROLCHAR].capitalHeight)); PRectangle rcCChar = rcSegment; rcCChar.left = rcCChar.left + 1; rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; PRectangle rcCentral = rcCChar; rcCentral.top++; rcCentral.bottom--; surface->FillRectangle(rcCentral, textFore); PRectangle rcChar = rcCChar; rcChar.left++; rcChar.right--; surface->DrawTextClipped(rcChar, ctrlCharsFont, rcSegment.top + vsDraw.maxAscent, s, static_cast(s ? strlen(s) : 0), textBack, textFore); } static void DrawFrame(Surface *surface, ColourDesired colour, int alpha, PRectangle rcFrame) { if (alpha != SC_ALPHA_NOALPHA) surface->AlphaRectangle(rcFrame, 0, colour, alpha, colour, alpha, 0); else surface->FillRectangle(rcFrame, colour); } static void DrawCaretLineFramed(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, int subLine) { const int width = vsDraw.GetFrameWidth(); if (subLine == 0 || ll->wrapIndent == 0 || vsDraw.caretLineAlpha != SC_ALPHA_NOALPHA) { // Left DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha, PRectangle(rcLine.left, rcLine.top, rcLine.left + width, rcLine.bottom)); } if (subLine == 0) { // Top DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha, PRectangle(rcLine.left + width, rcLine.top, rcLine.right - width, rcLine.top + width)); } if (subLine == ll->lines - 1 || vsDraw.caretLineAlpha != SC_ALPHA_NOALPHA) { // Right DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha, PRectangle(rcLine.right - width, rcLine.top, rcLine.right, rcLine.bottom)); } if (subLine == ll->lines - 1) { // Bottom DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha, PRectangle(rcLine.left + width, rcLine.bottom - width, rcLine.right - width, rcLine.bottom)); } } void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, Sci::Line line, Sci::Position lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, ColourOptional background) { const Sci::Position posLineStart = model.pdoc->LineStart(line); PRectangle rcSegment = rcLine; const bool lastSubLine = subLine == (ll->lines - 1); XYPOSITION virtualSpace = 0; if (lastSubLine) { const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; virtualSpace = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)) * spaceWidth; } const XYPOSITION xEol = static_cast(ll->positions[lineEnd] - subLineStart); // Fill the virtual space and show selections within it if (virtualSpace > 0.0f) { rcSegment.left = xEol + xStart; rcSegment.right = xEol + xStart + virtualSpace; surface->FillRectangle(rcSegment, background.isSet ? background : vsDraw.styles[ll->styles[ll->numCharsInLine]].back); if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) { const SelectionSegment virtualSpaceRange(SelectionPosition(model.pdoc->LineEnd(line)), SelectionPosition(model.pdoc->LineEnd(line), model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)))); for (size_t r = 0; rEndLineStyle()].spaceWidth; rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - static_cast(subLineStart)+portion.start.VirtualSpace() * spaceWidth; rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - static_cast(subLineStart)+portion.end.VirtualSpace() * spaceWidth; rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection)); } } } } } int eolInSelection = 0; int alpha = SC_ALPHA_NOALPHA; if (!hideSelection) { const Sci::Position posAfterLineEnd = model.pdoc->LineStart(line + 1); eolInSelection = (lastSubLine == true) ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0; alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; } // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on XYPOSITION blobsWidth = 0; if (lastSubLine) { for (Sci::Position eolPos = ll->numCharsBeforeEOL; eolPosnumCharsInLine; eolPos++) { rcSegment.left = xStart + ll->positions[eolPos] - static_cast(subLineStart)+virtualSpace; rcSegment.right = xStart + ll->positions[eolPos + 1] - static_cast(subLineStart)+virtualSpace; blobsWidth += rcSegment.Width(); char hexits[4] = ""; const char *ctrlChar; const unsigned char chEOL = ll->chars[eolPos]; const int styleMain = ll->styles[eolPos]; const ColourDesired textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, styleMain, eolPos); if (UTF8IsAscii(chEOL)) { ctrlChar = ControlCharacterString(chEOL); } else { const Representation *repr = model.reprs.RepresentationFromCharacter(&ll->chars[eolPos], ll->numCharsInLine - eolPos); if (repr) { ctrlChar = repr->stringRep.c_str(); eolPos = ll->numCharsInLine; } else { sprintf(hexits, "x%2X", chEOL); ctrlChar = hexits; } } ColourDesired textFore = vsDraw.styles[styleMain].fore; if (eolInSelection && vsDraw.selColours.fore.isSet) { textFore = (eolInSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground; } if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1)) { if (alpha == SC_ALPHA_NOALPHA) { surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); } else { surface->FillRectangle(rcSegment, textBack); } } else { surface->FillRectangle(rcSegment, textBack); } DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, phasesDraw == phasesOne); if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); } } } // Draw the eol-is-selected rectangle rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); } else { if (background.isSet) { surface->FillRectangle(rcSegment, background); } else if (line < model.pdoc->LinesTotal() - 1) { surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); } else { surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); } if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); } } rcSegment.left = rcSegment.right; if (rcSegment.left < rcLine.left) rcSegment.left = rcLine.left; rcSegment.right = rcLine.right; const bool fillRemainder = !lastSubLine || model.foldDisplayTextStyle == SC_FOLDDISPLAYTEXT_HIDDEN || !model.pcs->GetFoldDisplayTextShown(line); if (fillRemainder) { // Fill the remainder of the line FillLineRemainder(surface, model, vsDraw, ll, line, rcSegment, subLine); } bool drawWrapMarkEnd = false; if (subLine + 1 < ll->lines) { if (vsDraw.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0; } if (vsDraw.IsLineFrameOpaque(model.caret.active, ll->containsCaret)) { const int width = vsDraw.GetFrameWidth(); // Draw right of frame under marker DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha, PRectangle(rcLine.right - width, rcLine.top, rcLine.right, rcLine.bottom)); } } if (drawWrapMarkEnd) { PRectangle rcPlace = rcSegment; if (vsDraw.wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { rcPlace.left = xEol + xStart + virtualSpace; rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; } else { // rcLine is clipped to text area rcPlace.right = rcLine.right; rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; } if (!customDrawWrapMarker) { DrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour()); } else { customDrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour()); } } } static void DrawIndicator(int indicNum, Sci::Position startPos, Sci::Position endPos, Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, int xStart, PRectangle rcLine, Sci::Position secondCharacter, int subLine, Indicator::DrawState drawState, int value) { const XYPOSITION subLineStart = ll->positions[ll->LineStart(subLine)]; const PRectangle rcIndic( ll->positions[startPos] + xStart - subLineStart, rcLine.top + vsDraw.maxAscent, ll->positions[endPos] + xStart - subLineStart, rcLine.top + vsDraw.maxAscent + 3); PRectangle rcFirstCharacter = rcIndic; // Allow full descent space for character indicators rcFirstCharacter.bottom = rcLine.top + vsDraw.maxAscent + vsDraw.maxDescent; if (secondCharacter >= 0) { rcFirstCharacter.right = ll->positions[secondCharacter] + xStart - subLineStart; } else { // Indicator continued from earlier line so make an empty box and don't draw rcFirstCharacter.right = rcFirstCharacter.left; } vsDraw.indicators[indicNum].Draw(surface, rcIndic, rcLine, rcFirstCharacter, drawState, value); } static void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, Sci::Position lineEnd, bool under, Sci::Position hoverIndicatorPos) { // Draw decorators const Sci::Position posLineStart = model.pdoc->LineStart(line); const Sci::Position lineStart = ll->LineStart(subLine); const Sci::Position posLineEnd = posLineStart + lineEnd; for (const IDecoration *deco : model.pdoc->decorations->View()) { if (under == vsDraw.indicators[deco->Indicator()].under) { Sci::Position startPos = posLineStart + lineStart; if (!deco->ValueAt(startPos)) { startPos = deco->EndRun(startPos); } while ((startPos < posLineEnd) && (deco->ValueAt(startPos))) { const Range rangeRun(deco->StartRun(startPos), deco->EndRun(startPos)); const Sci::Position endPos = std::min(rangeRun.end, posLineEnd); const bool hover = vsDraw.indicators[deco->Indicator()].IsDynamic() && rangeRun.ContainsCharacter(hoverIndicatorPos); const int value = deco->ValueAt(startPos); const Indicator::DrawState drawState = hover ? Indicator::drawHover : Indicator::drawNormal; const Sci::Position posSecond = model.pdoc->MovePositionOutsideChar(rangeRun.First() + 1, 1); DrawIndicator(deco->Indicator(), startPos - posLineStart, endPos - posLineStart, surface, vsDraw, ll, xStart, rcLine, posSecond - posLineStart, subLine, drawState, value); startPos = endPos; if (!deco->ValueAt(startPos)) { startPos = deco->EndRun(startPos); } } } } // Use indicators to highlight matching braces if ((vsDraw.braceHighlightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACELIGHT)) || (vsDraw.braceBadLightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACEBAD))) { const int braceIndicator = (model.bracesMatchStyle == STYLE_BRACELIGHT) ? vsDraw.braceHighlightIndicator : vsDraw.braceBadLightIndicator; if (under == vsDraw.indicators[braceIndicator].under) { const Range rangeLine(posLineStart + lineStart, posLineEnd); if (rangeLine.ContainsCharacter(model.braces[0])) { const Sci::Position braceOffset = model.braces[0] - posLineStart; if (braceOffset < ll->numCharsInLine) { const Sci::Position secondOffset = model.pdoc->MovePositionOutsideChar(model.braces[0] + 1, 1) - posLineStart; DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, secondOffset, subLine, Indicator::drawNormal, 1); } } if (rangeLine.ContainsCharacter(model.braces[1])) { const Sci::Position braceOffset = model.braces[1] - posLineStart; if (braceOffset < ll->numCharsInLine) { const Sci::Position secondOffset = model.pdoc->MovePositionOutsideChar(model.braces[1] + 1, 1) - posLineStart; DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, secondOffset, subLine, Indicator::drawNormal, 1); } } } } } void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, XYACCUMULATOR subLineStart, DrawPhase phase) { const bool lastSubLine = subLine == (ll->lines - 1); if (!lastSubLine) return; if ((model.foldDisplayTextStyle == SC_FOLDDISPLAYTEXT_HIDDEN) || !model.pcs->GetFoldDisplayTextShown(line)) return; PRectangle rcSegment = rcLine; const char *foldDisplayText = model.pcs->GetFoldDisplayText(line); const int lengthFoldDisplayText = static_cast(strlen(foldDisplayText)); FontAlias fontText = vsDraw.styles[STYLE_FOLDDISPLAYTEXT].font; const int widthFoldDisplayText = static_cast(surface->WidthText(fontText, foldDisplayText, lengthFoldDisplayText)); int eolInSelection = 0; int alpha = SC_ALPHA_NOALPHA; if (!hideSelection) { const Sci::Position posAfterLineEnd = model.pdoc->LineStart(line + 1); eolInSelection = (subLine == (ll->lines - 1)) ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0; alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; } const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; const XYPOSITION virtualSpace = model.sel.VirtualSpaceFor( model.pdoc->LineEnd(line)) * spaceWidth; rcSegment.left = xStart + static_cast(ll->positions[ll->numCharsInLine] - subLineStart) + virtualSpace + vsDraw.aveCharWidth; rcSegment.right = rcSegment.left + static_cast(widthFoldDisplayText); const ColourOptional background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); FontAlias textFont = vsDraw.styles[STYLE_FOLDDISPLAYTEXT].font; ColourDesired textFore = vsDraw.styles[STYLE_FOLDDISPLAYTEXT].fore; if (eolInSelection && (vsDraw.selColours.fore.isSet)) { textFore = (eolInSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground; } const ColourDesired textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, STYLE_FOLDDISPLAYTEXT, -1); if (model.trackLineWidth) { if (rcSegment.right + 1> lineWidthMaxSeen) { // Fold display text border drawn on rcSegment.right with width 1 is the last visble object of the line lineWidthMaxSeen = static_cast(rcSegment.right + 1); } } if (phase & drawBack) { surface->FillRectangle(rcSegment, textBack); // Fill Remainder of the line PRectangle rcRemainder = rcSegment; rcRemainder.left = rcRemainder.right; if (rcRemainder.left < rcLine.left) rcRemainder.left = rcLine.left; rcRemainder.right = rcLine.right; FillLineRemainder(surface, model, vsDraw, ll, line, rcRemainder, subLine); } if (phase & drawText) { if (phasesDraw != phasesOne) { surface->DrawTextTransparent(rcSegment, textFont, rcSegment.top + vsDraw.maxAscent, foldDisplayText, lengthFoldDisplayText, textFore); } else { surface->DrawTextNoClip(rcSegment, textFont, rcSegment.top + vsDraw.maxAscent, foldDisplayText, lengthFoldDisplayText, textFore, textBack); } } if (phase & drawIndicatorsFore) { if (model.foldDisplayTextStyle == SC_FOLDDISPLAYTEXT_BOXED) { surface->PenColour(textFore); PRectangle rcBox = rcSegment; rcBox.left = round(rcSegment.left); rcBox.right = round(rcSegment.right); const IntegerRectangle ircBox(rcBox); surface->MoveTo(ircBox.left, ircBox.top); surface->LineTo(ircBox.left, ircBox.bottom); surface->MoveTo(ircBox.right, ircBox.top); surface->LineTo(ircBox.right, ircBox.bottom); surface->MoveTo(ircBox.left, ircBox.top); surface->LineTo(ircBox.right, ircBox.top); surface->MoveTo(ircBox.left, ircBox.bottom - 1); surface->LineTo(ircBox.right, ircBox.bottom - 1); } } if (phase & drawSelectionTranslucent) { if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && alpha != SC_ALPHA_NOALPHA) { SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); } } } static constexpr bool AnnotationBoxedOrIndented(int annotationVisible) noexcept { return annotationVisible == ANNOTATION_BOXED || annotationVisible == ANNOTATION_INDENTED; } void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { const int indent = static_cast(model.pdoc->GetLineIndentation(line) * vsDraw.spaceWidth); PRectangle rcSegment = rcLine; const int annotationLine = subLine - ll->lines; const StyledText stAnnotation = model.pdoc->AnnotationStyledText(line); if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) { if (phase & drawBack) { surface->FillRectangle(rcSegment, vsDraw.styles[0].back); } rcSegment.left = static_cast(xStart); if (model.trackLineWidth || AnnotationBoxedOrIndented(vsDraw.annotationVisible)) { // Only care about calculating width if tracking or need to draw indented box int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation); if (AnnotationBoxedOrIndented(vsDraw.annotationVisible)) { widthAnnotation += static_cast(vsDraw.spaceWidth * 2); // Margins rcSegment.left = static_cast(xStart + indent); rcSegment.right = rcSegment.left + widthAnnotation; } if (widthAnnotation > lineWidthMaxSeen) lineWidthMaxSeen = widthAnnotation; } const int annotationLines = model.pdoc->AnnotationLines(line); size_t start = 0; size_t lengthAnnotation = stAnnotation.LineLength(start); int lineInAnnotation = 0; while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) { start += lengthAnnotation + 1; lengthAnnotation = stAnnotation.LineLength(start); lineInAnnotation++; } PRectangle rcText = rcSegment; if ((phase & drawBack) && AnnotationBoxedOrIndented(vsDraw.annotationVisible)) { surface->FillRectangle(rcText, vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back); rcText.left += vsDraw.spaceWidth; } DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, stAnnotation, start, lengthAnnotation, phase); if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) { surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore); const IntegerRectangle ircSegment(rcSegment); surface->MoveTo(ircSegment.left, ircSegment.top); surface->LineTo(ircSegment.left, ircSegment.bottom); surface->MoveTo(ircSegment.right, ircSegment.top); surface->LineTo(ircSegment.right, ircSegment.bottom); if (subLine == ll->lines) { surface->MoveTo(ircSegment.left, ircSegment.top); surface->LineTo(ircSegment.right, ircSegment.top); } if (subLine == ll->lines + annotationLines - 1) { surface->MoveTo(ircSegment.left, ircSegment.bottom - 1); surface->LineTo(ircSegment.right, ircSegment.bottom - 1); } } } } static void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, int subLine, int xStart, Sci::Position offset, Sci::Position posCaret, PRectangle rcCaret, ColourDesired caretColour) { const Sci::Position lineStart = ll->LineStart(subLine); Sci::Position posBefore = posCaret; Sci::Position posAfter = model.pdoc->MovePositionOutsideChar(posCaret + 1, 1); Sci::Position numCharsToDraw = posAfter - posCaret; // Work out where the starting and ending offsets are. We need to // see if the previous character shares horizontal space, such as a // glyph / combining character. If so we'll need to draw that too. Sci::Position offsetFirstChar = offset; Sci::Position offsetLastChar = offset + (posAfter - posCaret); while ((posBefore > 0) && ((offsetLastChar - numCharsToDraw) >= lineStart)) { if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) { // The char does not share horizontal space break; } // Char shares horizontal space, update the numChars to draw // Update posBefore to point to the prev char posBefore = model.pdoc->MovePositionOutsideChar(posBefore - 1, -1); numCharsToDraw = posAfter - posBefore; offsetFirstChar = offset - (posCaret - posBefore); } // See if the next character shares horizontal space, if so we'll // need to draw that too. if (offsetFirstChar < 0) offsetFirstChar = 0; numCharsToDraw = offsetLastChar - offsetFirstChar; while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) { // Update posAfter to point to the 2nd next char, this is where // the next character ends, and 2nd next begins. We'll need // to compare these two posBefore = posAfter; posAfter = model.pdoc->MovePositionOutsideChar(posAfter + 1, 1); offsetLastChar = offset + (posAfter - posCaret); if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) { // The char does not share horizontal space break; } // Char shares horizontal space, update the numChars to draw numCharsToDraw = offsetLastChar - offsetFirstChar; } // We now know what to draw, update the caret drawing rectangle rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart; rcCaret.right = ll->positions[offsetFirstChar + numCharsToDraw] - ll->positions[lineStart] + xStart; // Adjust caret position to take into account any word wrapping symbols. if ((ll->wrapIndent != 0) && (lineStart != 0)) { const XYPOSITION wordWrapCharWidth = ll->wrapIndent; rcCaret.left += wordWrapCharWidth; rcCaret.right += wordWrapCharWidth; } // This character is where the caret block is, we override the colours // (inversed) for drawing the caret here. const int styleMain = ll->styles[offsetFirstChar]; FontAlias fontText = vsDraw.styles[styleMain].font; surface->DrawTextClipped(rcCaret, fontText, rcCaret.top + vsDraw.maxAscent, &ll->chars[offsetFirstChar], static_cast(numCharsToDraw), vsDraw.styles[styleMain].back, caretColour); } void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line lineDoc, int xStart, PRectangle rcLine, int subLine) const { // When drag is active it is the only caret drawn const bool drawDrag = model.posDrag.IsValid(); if (hideSelection && !drawDrag) return; const Sci::Position posLineStart = model.pdoc->LineStart(lineDoc); // For each selection draw for (size_t r = 0; (r model.sel.Range(r).anchor) { if (posCaret.VirtualSpace() > 0) posCaret.SetVirtualSpace(posCaret.VirtualSpace() - 1); else posCaret.SetPosition(model.pdoc->MovePositionOutsideChar(posCaret.Position()-1, -1)); } const int offset = static_cast(posCaret.Position() - posLineStart); const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; const XYPOSITION virtualOffset = posCaret.VirtualSpace() * spaceWidth; if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) { XYPOSITION xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)]; if (ll->wrapIndent != 0) { const Sci::Position lineStart = ll->LineStart(subLine); if (lineStart != 0) // Wrapped xposCaret += ll->wrapIndent; } const bool caretBlinkState = (model.caret.active && model.caret.on) || (!additionalCaretsBlink && !mainCaret); const bool caretVisibleState = additionalCaretsVisible || mainCaret; if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) && ((model.posDrag.IsValid()) || (caretBlinkState && caretVisibleState))) { bool caretAtEOF = false; bool caretAtEOL = false; bool drawBlockCaret = false; XYPOSITION widthOverstrikeCaret; XYPOSITION caretWidthOffset = 0; PRectangle rcCaret = rcLine; if (posCaret.Position() == model.pdoc->Length()) { // At end of document caretAtEOF = true; widthOverstrikeCaret = vsDraw.aveCharWidth; } else if ((posCaret.Position() - posLineStart) >= ll->numCharsInLine) { // At end of line caretAtEOL = true; widthOverstrikeCaret = vsDraw.aveCharWidth; } else { const int widthChar = model.pdoc->LenChar(posCaret.Position()); widthOverstrikeCaret = ll->positions[offset + widthChar] - ll->positions[offset]; } if (widthOverstrikeCaret < 3) // Make sure its visible widthOverstrikeCaret = 3; if (xposCaret > 0) caretWidthOffset = 0.51f; // Move back so overlaps both character cells. xposCaret += xStart; if (model.posDrag.IsValid()) { /* Dragging text, use a line caret */ rcCaret.left = round(xposCaret - caretWidthOffset); rcCaret.right = rcCaret.left + vsDraw.caretWidth; } else if (model.inOverstrike && drawOverstrikeCaret) { /* Overstrike (insert mode), use a modified bar caret */ rcCaret.top = rcCaret.bottom - 2; rcCaret.left = xposCaret + 1; rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; } else if ((vsDraw.caretStyle == CARETSTYLE_BLOCK) || imeCaretBlockOverride) { /* Block caret */ rcCaret.left = xposCaret; if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) { drawBlockCaret = true; rcCaret.right = xposCaret + widthOverstrikeCaret; } else { rcCaret.right = xposCaret + vsDraw.aveCharWidth; } } else { /* Line caret */ rcCaret.left = round(xposCaret - caretWidthOffset); rcCaret.right = rcCaret.left + vsDraw.caretWidth; } const ColourDesired caretColour = mainCaret ? vsDraw.caretcolour : vsDraw.additionalCaretColour; if (drawBlockCaret) { DrawBlockCaret(surface, model, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour); } else { surface->FillRectangle(rcCaret, caretColour); } } } if (drawDrag) break; } } static void DrawWrapIndentAndMarker(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, int xStart, PRectangle rcLine, ColourOptional background, DrawWrapMarkerFn customDrawWrapMarker, bool caretActive) { // default bgnd here.. surface->FillRectangle(rcLine, background.isSet ? background : vsDraw.styles[STYLE_DEFAULT].back); if (vsDraw.IsLineFrameOpaque(caretActive, ll->containsCaret)) { const int width = vsDraw.GetFrameWidth(); // Draw left of frame under marker DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha, PRectangle(rcLine.left, rcLine.top, rcLine.left + width, rcLine.bottom)); } if (vsDraw.wrapVisualFlags & SC_WRAPVISUALFLAG_START) { // draw continuation rect PRectangle rcPlace = rcLine; rcPlace.left = static_cast(xStart); rcPlace.right = rcPlace.left + ll->wrapIndent; if (vsDraw.wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT) rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; else rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; if (!customDrawWrapMarker) { DrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour()); } else { customDrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour()); } } } void EditView::DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart, int subLine, ColourOptional background) const { const bool selBackDrawn = vsDraw.SelectionBackgroundDrawn(); bool inIndentation = subLine == 0; // Do not handle indentation except on first subline. const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; // Does not take margin into account but not significant const int xStartVisible = static_cast(subLineStart)-xStart; BreakFinder bfBack(ll, &model.sel, lineRange, posLineStart, xStartVisible, selBackDrawn, model.pdoc, &model.reprs, nullptr); const bool drawWhitespaceBackground = vsDraw.WhitespaceBackgroundDrawn() && !background.isSet; // Background drawing loop while (bfBack.More()) { const TextSegment ts = bfBack.Next(); const Sci::Position i = ts.end() - 1; const Sci::Position iDoc = i + posLineStart; PRectangle rcSegment = rcLine; rcSegment.left = ll->positions[ts.start] + xStart - static_cast(subLineStart); rcSegment.right = ll->positions[ts.end()] + xStart - static_cast(subLineStart); // Only try to draw if really visible - enhances performance by not calling environment to // draw strings that are completely past the right side of the window. if (!rcSegment.Empty() && rcSegment.Intersects(rcLine)) { // Clip to line rectangle, since may have a huge position which will not work with some platforms if (rcSegment.left < rcLine.left) rcSegment.left = rcLine.left; if (rcSegment.right > rcLine.right) rcSegment.right = rcLine.right; const int inSelection = hideSelection ? 0 : model.sel.CharacterInSelection(iDoc); const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc); ColourDesired textBack = TextBackground(model, vsDraw, ll, background, inSelection, inHotspot, ll->styles[i], i); if (ts.representation) { if (ll->chars[i] == '\t') { // Tab display if (drawWhitespaceBackground && vsDraw.WhiteSpaceVisible(inIndentation)) textBack = vsDraw.whitespaceColours.back; } else { // Blob display inIndentation = false; } surface->FillRectangle(rcSegment, textBack); } else { // Normal text display surface->FillRectangle(rcSegment, textBack); if (vsDraw.viewWhitespace != wsInvisible) { for (int cpos = 0; cpos <= i - ts.start; cpos++) { if (ll->chars[cpos + ts.start] == ' ') { if (drawWhitespaceBackground && vsDraw.WhiteSpaceVisible(inIndentation)) { const PRectangle rcSpace( ll->positions[cpos + ts.start] + xStart - static_cast(subLineStart), rcSegment.top, ll->positions[cpos + ts.start + 1] + xStart - static_cast(subLineStart), rcSegment.bottom); surface->FillRectangle(rcSpace, vsDraw.whitespaceColours.back); } } else { inIndentation = false; } } } } } else if (rcSegment.left > rcLine.right) { break; } } } static void DrawEdgeLine(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, Range lineRange, int xStart) { if (vsDraw.edgeState == EDGE_LINE) { PRectangle rcSegment = rcLine; const int edgeX = static_cast(vsDraw.theEdge.column * vsDraw.spaceWidth); rcSegment.left = static_cast(edgeX + xStart); if ((ll->wrapIndent != 0) && (lineRange.start != 0)) rcSegment.left -= ll->wrapIndent; rcSegment.right = rcSegment.left + 1; surface->FillRectangle(rcSegment, vsDraw.theEdge.colour); } else if (vsDraw.edgeState == EDGE_MULTILINE) { for (size_t edge = 0; edge < vsDraw.theMultiEdge.size(); edge++) { if (vsDraw.theMultiEdge[edge].column >= 0) { PRectangle rcSegment = rcLine; const int edgeX = static_cast(vsDraw.theMultiEdge[edge].column * vsDraw.spaceWidth); rcSegment.left = static_cast(edgeX + xStart); if ((ll->wrapIndent != 0) && (lineRange.start != 0)) rcSegment.left -= ll->wrapIndent; rcSegment.right = rcSegment.left + 1; surface->FillRectangle(rcSegment, vsDraw.theMultiEdge[edge].colour); } } } } // Draw underline mark as part of background if not transparent static void DrawMarkUnderline(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, Sci::Line line, PRectangle rcLine) { int marks = model.pdoc->GetMark(line); for (int markBit = 0; (markBit < 32) && marks; markBit++) { if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) && (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { PRectangle rcUnderline = rcLine; rcUnderline.top = rcUnderline.bottom - 2; surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back); } marks >>= 1; } } static void DrawTranslucentSelection(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcLine, int subLine, Range lineRange, int xStart) { if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA)) { const Sci::Position posLineStart = model.pdoc->LineStart(line); const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; // For each selection draw Sci::Position virtualSpaces = 0; if (subLine == (ll->lines - 1)) { virtualSpaces = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)); } const SelectionPosition posStart(posLineStart + lineRange.start); const SelectionPosition posEnd(posLineStart + lineRange.end, virtualSpaces); const SelectionSegment virtualSpaceRange(posStart, posEnd); for (size_t r = 0; r < model.sel.Count(); r++) { const int alpha = (r == model.sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; if (alpha != SC_ALPHA_NOALPHA) { const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); if (!portion.Empty()) { const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; PRectangle rcSegment = rcLine; rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - static_cast(subLineStart)+portion.start.VirtualSpace() * spaceWidth; rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - static_cast(subLineStart)+portion.end.VirtualSpace() * spaceWidth; if ((ll->wrapIndent != 0) && (lineRange.start != 0)) { if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) rcSegment.left -= static_cast(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here } rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; if (rcSegment.right > rcLine.left) SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection), alpha); } } } } } // Draw any translucent whole line states static void DrawTranslucentLineState(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcLine, int subLine) { if ((model.caret.active || vsDraw.alwaysShowCaretLineBackground) && vsDraw.showCaretLineBackground && ll->containsCaret && vsDraw.caretLineAlpha != SC_ALPHA_NOALPHA) { if (vsDraw.caretLineFrame) { DrawCaretLineFramed(surface, vsDraw, ll, rcLine, subLine); } else { SimpleAlphaRectangle(surface, rcLine, vsDraw.caretLineBackground, vsDraw.caretLineAlpha); } } const int marksOfLine = model.pdoc->GetMark(line); int marksDrawnInText = marksOfLine & vsDraw.maskDrawInText; for (int markBit = 0; (markBit < 32) && marksDrawnInText; markBit++) { if (marksDrawnInText & 1) { if (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) { SimpleAlphaRectangle(surface, rcLine, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); } else if (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) { PRectangle rcUnderline = rcLine; rcUnderline.top = rcUnderline.bottom - 2; SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); } } marksDrawnInText >>= 1; } int marksDrawnInLine = marksOfLine & vsDraw.maskInLine; for (int markBit = 0; (markBit < 32) && marksDrawnInLine; markBit++) { if (marksDrawnInLine & 1) { SimpleAlphaRectangle(surface, rcLine, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); } marksDrawnInLine >>= 1; } } void EditView::DrawForeground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line lineVisible, PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart, int subLine, ColourOptional background) { const bool selBackDrawn = vsDraw.SelectionBackgroundDrawn(); const bool drawWhitespaceBackground = vsDraw.WhitespaceBackgroundDrawn() && !background.isSet; bool inIndentation = subLine == 0; // Do not handle indentation except on first subline. const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; const XYPOSITION indentWidth = model.pdoc->IndentSize() * vsDraw.spaceWidth; // Does not take margin into account but not significant const int xStartVisible = static_cast(subLineStart)-xStart; // Foreground drawing loop BreakFinder bfFore(ll, &model.sel, lineRange, posLineStart, xStartVisible, (((phasesDraw == phasesOne) && selBackDrawn) || vsDraw.selColours.fore.isSet), model.pdoc, &model.reprs, &vsDraw); while (bfFore.More()) { const TextSegment ts = bfFore.Next(); const Sci::Position i = ts.end() - 1; const Sci::Position iDoc = i + posLineStart; PRectangle rcSegment = rcLine; rcSegment.left = ll->positions[ts.start] + xStart - static_cast(subLineStart); rcSegment.right = ll->positions[ts.end()] + xStart - static_cast(subLineStart); // Only try to draw if really visible - enhances performance by not calling environment to // draw strings that are completely past the right side of the window. if (rcSegment.Intersects(rcLine)) { const int styleMain = ll->styles[i]; ColourDesired textFore = vsDraw.styles[styleMain].fore; FontAlias textFont = vsDraw.styles[styleMain].font; //hotspot foreground const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc); if (inHotspot) { if (vsDraw.hotspotColours.fore.isSet) textFore = vsDraw.hotspotColours.fore; } if (vsDraw.indicatorsSetFore) { // At least one indicator sets the text colour so see if it applies to this segment for (const IDecoration *deco : model.pdoc->decorations->View()) { const int indicatorValue = deco->ValueAt(ts.start + posLineStart); if (indicatorValue) { const Indicator &indicator = vsDraw.indicators[deco->Indicator()]; const bool hover = indicator.IsDynamic() && ((model.hoverIndicatorPos >= ts.start + posLineStart) && (model.hoverIndicatorPos <= ts.end() + posLineStart)); if (hover) { if (indicator.sacHover.style == INDIC_TEXTFORE) { textFore = indicator.sacHover.fore; } } else { if (indicator.sacNormal.style == INDIC_TEXTFORE) { if (indicator.Flags() & SC_INDICFLAG_VALUEFORE) textFore = ColourDesired(indicatorValue & SC_INDICVALUEMASK); else textFore = indicator.sacNormal.fore; } } } } } const int inSelection = hideSelection ? 0 : model.sel.CharacterInSelection(iDoc); if (inSelection && (vsDraw.selColours.fore.isSet)) { textFore = (inSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground; } ColourDesired textBack = TextBackground(model, vsDraw, ll, background, inSelection, inHotspot, styleMain, i); if (ts.representation) { if (ll->chars[i] == '\t') { // Tab display if (phasesDraw == phasesOne) { if (drawWhitespaceBackground && vsDraw.WhiteSpaceVisible(inIndentation)) textBack = vsDraw.whitespaceColours.back; surface->FillRectangle(rcSegment, textBack); } if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { for (int indentCount = static_cast((ll->positions[i] + epsilon) / indentWidth); indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth; indentCount++) { if (indentCount > 0) { const XYPOSITION xIndent = floor(indentCount * indentWidth); DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, (ll->xHighlightGuide == xIndent)); } } } if (vsDraw.viewWhitespace != wsInvisible) { if (vsDraw.WhiteSpaceVisible(inIndentation)) { if (vsDraw.whitespaceColours.fore.isSet) textFore = vsDraw.whitespaceColours.fore; surface->PenColour(textFore); const PRectangle rcTab(rcSegment.left + 1, rcSegment.top + tabArrowHeight, rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); const int segmentTop = static_cast(rcSegment.top + vsDraw.lineHeight / 2); if (!customDrawTabArrow) DrawTabArrow(surface, rcTab, segmentTop, vsDraw); else customDrawTabArrow(surface, rcTab, segmentTop); } } } else { inIndentation = false; if (vsDraw.controlCharSymbol >= 32) { // Using one font for all control characters so it can be controlled independently to ensure // the box goes around the characters tightly. Seems to be no way to work out what height // is taken by an individual character - internal leading gives varying results. FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; const char cc[2] = { static_cast(vsDraw.controlCharSymbol), '\0' }; surface->DrawTextNoClip(rcSegment, ctrlCharsFont, rcSegment.top + vsDraw.maxAscent, cc, 1, textBack, textFore); } else { DrawTextBlob(surface, vsDraw, rcSegment, ts.representation->stringRep.c_str(), textBack, textFore, phasesDraw == phasesOne); } } } else { // Normal text display if (vsDraw.styles[styleMain].visible) { if (phasesDraw != phasesOne) { surface->DrawTextTransparent(rcSegment, textFont, rcSegment.top + vsDraw.maxAscent, &ll->chars[ts.start], static_cast(i - ts.start + 1), textFore); } else { surface->DrawTextNoClip(rcSegment, textFont, rcSegment.top + vsDraw.maxAscent, &ll->chars[ts.start], static_cast(i - ts.start + 1), textFore, textBack); } } if (vsDraw.viewWhitespace != wsInvisible || (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { for (int cpos = 0; cpos <= i - ts.start; cpos++) { if (ll->chars[cpos + ts.start] == ' ') { if (vsDraw.viewWhitespace != wsInvisible) { if (vsDraw.whitespaceColours.fore.isSet) textFore = vsDraw.whitespaceColours.fore; if (vsDraw.WhiteSpaceVisible(inIndentation)) { const XYPOSITION xmid = (ll->positions[cpos + ts.start] + ll->positions[cpos + ts.start + 1]) / 2; if ((phasesDraw == phasesOne) && drawWhitespaceBackground) { textBack = vsDraw.whitespaceColours.back; const PRectangle rcSpace( ll->positions[cpos + ts.start] + xStart - static_cast(subLineStart), rcSegment.top, ll->positions[cpos + ts.start + 1] + xStart - static_cast(subLineStart), rcSegment.bottom); surface->FillRectangle(rcSpace, textBack); } const int halfDotWidth = vsDraw.whitespaceSize / 2; PRectangle rcDot(xmid + xStart - halfDotWidth - static_cast(subLineStart), rcSegment.top + vsDraw.lineHeight / 2, 0.0f, 0.0f); rcDot.right = rcDot.left + vsDraw.whitespaceSize; rcDot.bottom = rcDot.top + vsDraw.whitespaceSize; surface->FillRectangle(rcDot, textFore); } } if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { for (int indentCount = static_cast((ll->positions[cpos + ts.start] + epsilon) / indentWidth); indentCount <= (ll->positions[cpos + ts.start + 1] - epsilon) / indentWidth; indentCount++) { if (indentCount > 0) { const XYPOSITION xIndent = floor(indentCount * indentWidth); DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, (ll->xHighlightGuide == xIndent)); } } } } else { inIndentation = false; } } } } if (ll->hotspot.Valid() && vsDraw.hotspotUnderline && ll->hotspot.ContainsCharacter(iDoc)) { PRectangle rcUL = rcSegment; rcUL.top = rcUL.top + vsDraw.maxAscent + 1; rcUL.bottom = rcUL.top + 1; if (vsDraw.hotspotColours.fore.isSet) surface->FillRectangle(rcUL, vsDraw.hotspotColours.fore); else surface->FillRectangle(rcUL, textFore); } else if (vsDraw.styles[styleMain].underline) { PRectangle rcUL = rcSegment; rcUL.top = rcUL.top + vsDraw.maxAscent + 1; rcUL.bottom = rcUL.top + 1; surface->FillRectangle(rcUL, textFore); } } else if (rcSegment.left > rcLine.right) { break; } } } void EditView::DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, Sci::Line lineVisible, PRectangle rcLine, int xStart, int subLine) { if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth) && (subLine == 0)) { const Sci::Position posLineStart = model.pdoc->LineStart(line); int indentSpace = model.pdoc->GetLineIndentation(line); int xStartText = static_cast(ll->positions[model.pdoc->GetLineIndentPosition(line) - posLineStart]); // Find the most recent line with some text Sci::Line lineLastWithText = line; while (lineLastWithText > std::max(line - 20, static_cast(0)) && model.pdoc->IsWhiteLine(lineLastWithText)) { lineLastWithText--; } if (lineLastWithText < line) { xStartText = 100000; // Don't limit to visible indentation on empty line // This line is empty, so use indentation of last line with text int indentLastWithText = model.pdoc->GetLineIndentation(lineLastWithText); const int isFoldHeader = model.pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG; if (isFoldHeader) { // Level is one more level than parent indentLastWithText += model.pdoc->IndentSize(); } if (vsDraw.viewIndentationGuides == ivLookForward) { // In viLookForward mode, previous line only used if it is a fold header if (isFoldHeader) { indentSpace = std::max(indentSpace, indentLastWithText); } } else { // viLookBoth indentSpace = std::max(indentSpace, indentLastWithText); } } Sci::Line lineNextWithText = line; while (lineNextWithText < std::min(line + 20, model.pdoc->LinesTotal()) && model.pdoc->IsWhiteLine(lineNextWithText)) { lineNextWithText++; } if (lineNextWithText > line) { xStartText = 100000; // Don't limit to visible indentation on empty line // This line is empty, so use indentation of first next line with text indentSpace = std::max(indentSpace, model.pdoc->GetLineIndentation(lineNextWithText)); } for (int indentPos = model.pdoc->IndentSize(); indentPos < indentSpace; indentPos += model.pdoc->IndentSize()) { const XYPOSITION xIndent = floor(indentPos * vsDraw.spaceWidth); if (xIndent < xStartText) { DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcLine, (ll->xHighlightGuide == xIndent)); } } } } void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, Sci::Line lineVisible, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { if (subLine >= ll->lines) { DrawAnnotation(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, phase); return; // No further drawing } // See if something overrides the line background color. const ColourOptional background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); const Sci::Position posLineStart = model.pdoc->LineStart(line); const Range lineRange = ll->SubLineRange(subLine, LineLayout::Scope::visibleOnly); const Range lineRangeIncludingEnd = ll->SubLineRange(subLine, LineLayout::Scope::includeEnd); const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; if ((ll->wrapIndent != 0) && (subLine > 0)) { if (phase & drawBack) { DrawWrapIndentAndMarker(surface, vsDraw, ll, xStart, rcLine, background, customDrawWrapMarker, model.caret.active); } xStart += static_cast(ll->wrapIndent); } if (phasesDraw != phasesOne) { if (phase & drawBack) { DrawBackground(surface, model, vsDraw, ll, rcLine, lineRange, posLineStart, xStart, subLine, background); DrawFoldDisplayText(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, subLineStart, drawBack); phase = static_cast(phase & ~drawBack); // Remove drawBack to not draw again in DrawFoldDisplayText DrawEOL(surface, model, vsDraw, ll, rcLine, line, lineRange.end, xStart, subLine, subLineStart, background); if (vsDraw.IsLineFrameOpaque(model.caret.active, ll->containsCaret)) DrawCaretLineFramed(surface, vsDraw, ll, rcLine, subLine); } if (phase & drawIndicatorsBack) { DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRangeIncludingEnd.end, true, model.hoverIndicatorPos); DrawEdgeLine(surface, vsDraw, ll, rcLine, lineRange, xStart); DrawMarkUnderline(surface, model, vsDraw, line, rcLine); } } if (phase & drawText) { DrawForeground(surface, model, vsDraw, ll, lineVisible, rcLine, lineRange, posLineStart, xStart, subLine, background); } if (phase & drawIndentationGuides) { DrawIndentGuidesOverEmpty(surface, model, vsDraw, ll, line, lineVisible, rcLine, xStart, subLine); } if (phase & drawIndicatorsFore) { DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRangeIncludingEnd.end, false, model.hoverIndicatorPos); } DrawFoldDisplayText(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, subLineStart, phase); if (phasesDraw == phasesOne) { DrawEOL(surface, model, vsDraw, ll, rcLine, line, lineRange.end, xStart, subLine, subLineStart, background); if (vsDraw.IsLineFrameOpaque(model.caret.active, ll->containsCaret)) DrawCaretLineFramed(surface, vsDraw, ll, rcLine, subLine); DrawEdgeLine(surface, vsDraw, ll, rcLine, lineRange, xStart); DrawMarkUnderline(surface, model, vsDraw, line, rcLine); } if (!hideSelection && (phase & drawSelectionTranslucent)) { DrawTranslucentSelection(surface, model, vsDraw, ll, line, rcLine, subLine, lineRange, xStart); } if (phase & drawLineTranslucent) { DrawTranslucentLineState(surface, model, vsDraw, ll, line, rcLine, subLine); } } static void DrawFoldLines(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, Sci::Line line, PRectangle rcLine) { const bool expanded = model.pcs->GetExpanded(line); const int level = model.pdoc->GetLevel(line); const int levelNext = model.pdoc->GetLevel(line + 1); if ((level & SC_FOLDLEVELHEADERFLAG) && (LevelNumber(level) < LevelNumber(levelNext))) { // Paint the line above the fold if ((expanded && (model.foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED)) || (!expanded && (model.foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) { PRectangle rcFoldLine = rcLine; rcFoldLine.bottom = rcFoldLine.top + 1; surface->FillRectangle(rcFoldLine, vsDraw.styles[STYLE_DEFAULT].fore); } // Paint the line below the fold if ((expanded && (model.foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED)) || (!expanded && (model.foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { PRectangle rcFoldLine = rcLine; rcFoldLine.top = rcFoldLine.bottom - 1; surface->FillRectangle(rcFoldLine, vsDraw.styles[STYLE_DEFAULT].fore); } } } void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectangle rcArea, PRectangle rcClient, const ViewStyle &vsDraw) { // Allow text at start of line to overlap 1 pixel into the margin as this displays // serifs and italic stems for aliased text. const int leftTextOverlap = ((model.xOffset == 0) && (vsDraw.leftMarginWidth > 0)) ? 1 : 0; // Do the painting if (rcArea.right > vsDraw.textStart - leftTextOverlap) { Surface *surface = surfaceWindow; if (bufferedDraw) { surface = pixmapLine.get(); PLATFORM_ASSERT(pixmapLine->Initialised()); } surface->SetUnicodeMode(SC_CP_UTF8 == model.pdoc->dbcsCodePage); surface->SetDBCSMode(model.pdoc->dbcsCodePage); const Point ptOrigin = model.GetVisibleOriginInMain(); const int screenLinePaintFirst = static_cast(rcArea.top) / vsDraw.lineHeight; const int xStart = vsDraw.textStart - model.xOffset + static_cast(ptOrigin.x); SelectionPosition posCaret = model.sel.RangeMain().caret; if (model.posDrag.IsValid()) posCaret = model.posDrag; const Sci::Line lineCaret = model.pdoc->SciLineFromPosition(posCaret.Position()); PRectangle rcTextArea = rcClient; if (vsDraw.marginInside) { rcTextArea.left += vsDraw.textStart; rcTextArea.right -= vsDraw.rightMarginWidth; } else { rcTextArea = rcArea; } // Remove selection margin from drawing area so text will not be drawn // on it in unbuffered mode. if (!bufferedDraw && vsDraw.marginInside) { PRectangle rcClipText = rcTextArea; rcClipText.left -= leftTextOverlap; surfaceWindow->SetClip(rcClipText); } // Loop on visible lines #if defined(TIME_PAINTING) double durLayout = 0.0; double durPaint = 0.0; double durCopy = 0.0; ElapsedPeriod epWhole; #endif const bool bracesIgnoreStyle = ((vsDraw.braceHighlightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACELIGHT)) || (vsDraw.braceBadLightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACEBAD))); Sci::Line lineDocPrevious = -1; // Used to avoid laying out one document line multiple times AutoLineLayout ll(llc, nullptr); std::vector phases; if ((phasesDraw == phasesMultiple) && !bufferedDraw) { for (DrawPhase phase = drawBack; phase <= drawCarets; phase = static_cast(phase * 2)) { phases.push_back(phase); } } else { phases.push_back(drawAll); } for (const DrawPhase &phase : phases) { int ypos = 0; if (!bufferedDraw) ypos += screenLinePaintFirst * vsDraw.lineHeight; int yposScreen = screenLinePaintFirst * vsDraw.lineHeight; Sci::Line visibleLine = model.TopLineOfMain() + screenLinePaintFirst; while (visibleLine < model.pcs->LinesDisplayed() && yposScreen < rcArea.bottom) { const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine); // Only visible lines should be handled by the code within the loop PLATFORM_ASSERT(model.pcs->GetVisible(lineDoc)); const Sci::Line lineStartSet = model.pcs->DisplayFromDoc(lineDoc); const int subLine = static_cast(visibleLine - lineStartSet); // Copy this line and its styles from the document into local arrays // and determine the x position at which each character starts. #if defined(TIME_PAINTING) ElapsedPeriod ep; #endif if (lineDoc != lineDocPrevious) { ll.Set(nullptr); ll.Set(RetrieveLineLayout(lineDoc, model)); LayoutLine(model, lineDoc, surface, vsDraw, ll, model.wrapWidth); lineDocPrevious = lineDoc; } #if defined(TIME_PAINTING) durLayout += ep.Duration(true); #endif if (ll) { ll->containsCaret = !hideSelection && (lineDoc == lineCaret); ll->hotspot = model.GetHotSpotRange(); PRectangle rcLine = rcTextArea; rcLine.top = static_cast(ypos); rcLine.bottom = static_cast(ypos + vsDraw.lineHeight); const Range rangeLine(model.pdoc->LineStart(lineDoc), model.pdoc->LineStart(lineDoc + 1)); // Highlight the current braces if any ll->SetBracesHighlight(rangeLine, model.braces, static_cast(model.bracesMatchStyle), static_cast(model.highlightGuideColumn * vsDraw.spaceWidth), bracesIgnoreStyle); if (leftTextOverlap && (bufferedDraw || ((phasesDraw < phasesMultiple) && (phase & drawBack)))) { // Clear the left margin PRectangle rcSpacer = rcLine; rcSpacer.right = rcSpacer.left; rcSpacer.left -= 1; surface->FillRectangle(rcSpacer, vsDraw.styles[STYLE_DEFAULT].back); } DrawLine(surface, model, vsDraw, ll, lineDoc, visibleLine, xStart, rcLine, subLine, phase); #if defined(TIME_PAINTING) durPaint += ep.Duration(true); #endif // Restore the previous styles for the brace highlights in case layout is in cache. ll->RestoreBracesHighlight(rangeLine, model.braces, bracesIgnoreStyle); if (phase & drawFoldLines) { DrawFoldLines(surface, model, vsDraw, lineDoc, rcLine); } if (phase & drawCarets) { DrawCarets(surface, model, vsDraw, ll, lineDoc, xStart, rcLine, subLine); } if (bufferedDraw) { const Point from = Point::FromInts(vsDraw.textStart - leftTextOverlap, 0); const PRectangle rcCopyArea = PRectangle::FromInts(vsDraw.textStart - leftTextOverlap, yposScreen, static_cast(rcClient.right - vsDraw.rightMarginWidth), yposScreen + vsDraw.lineHeight); surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); } lineWidthMaxSeen = std::max( lineWidthMaxSeen, static_cast(ll->positions[ll->numCharsInLine])); #if defined(TIME_PAINTING) durCopy += ep.Duration(true); #endif } if (!bufferedDraw) { ypos += vsDraw.lineHeight; } yposScreen += vsDraw.lineHeight; visibleLine++; } } ll.Set(nullptr); #if defined(TIME_PAINTING) if (durPaint < 0.00000001) durPaint = 0.00000001; #endif // Right column limit indicator PRectangle rcBeyondEOF = (vsDraw.marginInside) ? rcClient : rcArea; rcBeyondEOF.left = static_cast(vsDraw.textStart); rcBeyondEOF.right = rcBeyondEOF.right - ((vsDraw.marginInside) ? vsDraw.rightMarginWidth : 0); rcBeyondEOF.top = static_cast((model.pcs->LinesDisplayed() - model.TopLineOfMain()) * vsDraw.lineHeight); if (rcBeyondEOF.top < rcBeyondEOF.bottom) { surfaceWindow->FillRectangle(rcBeyondEOF, vsDraw.styles[STYLE_DEFAULT].back); if (vsDraw.edgeState == EDGE_LINE) { const int edgeX = static_cast(vsDraw.theEdge.column * vsDraw.spaceWidth); rcBeyondEOF.left = static_cast(edgeX + xStart); rcBeyondEOF.right = rcBeyondEOF.left + 1; surfaceWindow->FillRectangle(rcBeyondEOF, vsDraw.theEdge.colour); } else if (vsDraw.edgeState == EDGE_MULTILINE) { for (size_t edge = 0; edge < vsDraw.theMultiEdge.size(); edge++) { if (vsDraw.theMultiEdge[edge].column >= 0) { const int edgeX = static_cast(vsDraw.theMultiEdge[edge].column * vsDraw.spaceWidth); rcBeyondEOF.left = static_cast(edgeX + xStart); rcBeyondEOF.right = rcBeyondEOF.left + 1; surfaceWindow->FillRectangle(rcBeyondEOF, vsDraw.theMultiEdge[edge].colour); } } } } //Platform::DebugPrintf("start display %d, offset = %d\n", model.pdoc->Length(), model.xOffset); #if defined(TIME_PAINTING) Platform::DebugPrintf( "Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n", durLayout, durPaint, durLayout / durPaint, durCopy, epWhole.Duration()); #endif } } void EditView::FillLineRemainder(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcArea, int subLine) const { int eolInSelection = 0; int alpha = SC_ALPHA_NOALPHA; if (!hideSelection) { const Sci::Position posAfterLineEnd = model.pdoc->LineStart(line + 1); eolInSelection = (subLine == (ll->lines - 1)) ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0; alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; } const ColourOptional background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { surface->FillRectangle(rcArea, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); } else { if (background.isSet) { surface->FillRectangle(rcArea, background); } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { surface->FillRectangle(rcArea, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); } else { surface->FillRectangle(rcArea, vsDraw.styles[STYLE_DEFAULT].back); } if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { SimpleAlphaRectangle(surface, rcArea, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); } } } // Space (3 space characters) between line numbers and text when printing. #define lineNumberPrintSpace " " static ColourDesired InvertedLight(ColourDesired orig) { unsigned int r = orig.GetRed(); unsigned int g = orig.GetGreen(); unsigned int b = orig.GetBlue(); const unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye const unsigned int il = 0xff - l; if (l == 0) return ColourDesired(0xff, 0xff, 0xff); r = r * il / l; g = g * il / l; b = b * il / l; return ColourDesired(std::min(r, 0xffu), std::min(g, 0xffu), std::min(b, 0xffu)); } Sci::Position EditView::FormatRange(bool draw, const Sci_RangeToFormat *pfr, Surface *surface, Surface *surfaceMeasure, const EditModel &model, const ViewStyle &vs) { // Can't use measurements cached for screen posCache.Clear(); ViewStyle vsPrint(vs); vsPrint.technology = SC_TECHNOLOGY_DEFAULT; // Modify the view style for printing as do not normally want any of the transient features to be printed // Printing supports only the line number margin. int lineNumberIndex = -1; for (size_t margin = 0; margin < vs.ms.size(); margin++) { if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) { lineNumberIndex = static_cast(margin); } else { vsPrint.ms[margin].width = 0; } } vsPrint.fixedColumnWidth = 0; vsPrint.zoomLevel = printParameters.magnification; // Don't show indentation guides // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT vsPrint.viewIndentationGuides = ivNone; // Don't show the selection when printing vsPrint.selColours.back.isSet = false; vsPrint.selColours.fore.isSet = false; vsPrint.selAlpha = SC_ALPHA_NOALPHA; vsPrint.selAdditionalAlpha = SC_ALPHA_NOALPHA; vsPrint.whitespaceColours.back.isSet = false; vsPrint.whitespaceColours.fore.isSet = false; vsPrint.showCaretLineBackground = false; vsPrint.alwaysShowCaretLineBackground = false; // Don't highlight matching braces using indicators vsPrint.braceHighlightIndicatorSet = false; vsPrint.braceBadLightIndicatorSet = false; // Set colours for printing according to users settings for (size_t sty = 0; sty < vsPrint.styles.size(); sty++) { if (printParameters.colourMode == SC_PRINT_INVERTLIGHT) { vsPrint.styles[sty].fore = InvertedLight(vsPrint.styles[sty].fore); vsPrint.styles[sty].back = InvertedLight(vsPrint.styles[sty].back); } else if (printParameters.colourMode == SC_PRINT_BLACKONWHITE) { vsPrint.styles[sty].fore = ColourDesired(0, 0, 0); vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); } else if (printParameters.colourMode == SC_PRINT_COLOURONWHITE) { vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); } else if (printParameters.colourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) { if (sty <= STYLE_DEFAULT) { vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); } } } // White background for the line numbers if SC_PRINT_SCREENCOLOURS isn't used if (printParameters.colourMode != SC_PRINT_SCREENCOLOURS) vsPrint.styles[STYLE_LINENUMBER].back = ColourDesired(0xff, 0xff, 0xff); // Printing uses different margins, so reset screen margins vsPrint.leftMarginWidth = 0; vsPrint.rightMarginWidth = 0; vsPrint.Refresh(*surfaceMeasure, model.pdoc->tabInChars); // Determining width must happen after fonts have been realised in Refresh int lineNumberWidth = 0; if (lineNumberIndex >= 0) { lineNumberWidth = static_cast(surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, "99999" lineNumberPrintSpace, 5 + static_cast(strlen(lineNumberPrintSpace)))); vsPrint.ms[lineNumberIndex].width = lineNumberWidth; vsPrint.Refresh(*surfaceMeasure, model.pdoc->tabInChars); // Recalculate fixedColumnWidth } const Sci::Line linePrintStart = model.pdoc->SciLineFromPosition(static_cast(pfr->chrg.cpMin)); Sci::Line linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1; if (linePrintLast < linePrintStart) linePrintLast = linePrintStart; const Sci::Line linePrintMax = model.pdoc->SciLineFromPosition(static_cast(pfr->chrg.cpMax)); if (linePrintLast > linePrintMax) linePrintLast = linePrintMax; //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n", // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight, // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font)); Sci::Position endPosPrint = model.pdoc->Length(); if (linePrintLast < model.pdoc->LinesTotal()) endPosPrint = model.pdoc->LineStart(linePrintLast + 1); // Ensure we are styled to where we are formatting. model.pdoc->EnsureStyledTo(endPosPrint); const int xStart = vsPrint.fixedColumnWidth + pfr->rc.left; int ypos = pfr->rc.top; Sci::Line lineDoc = linePrintStart; Sci::Position nPrintPos = static_cast(pfr->chrg.cpMin); int visibleLine = 0; int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth; if (printParameters.wrapState == eWrapNone) widthPrint = LineLayout::wrapWidthInfinite; while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) { // When printing, the hdc and hdcTarget may be the same, so // changing the state of surfaceMeasure may change the underlying // state of surface. Therefore, any cached state is discarded before // using each surface. surfaceMeasure->FlushCachedState(); // Copy this line and its styles from the document into local arrays // and determine the x position at which each character starts. LineLayout ll(static_cast(model.pdoc->LineStart(lineDoc + 1) - model.pdoc->LineStart(lineDoc) + 1)); LayoutLine(model, lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint); ll.containsCaret = false; PRectangle rcLine = PRectangle::FromInts( pfr->rc.left, ypos, pfr->rc.right - 1, ypos + vsPrint.lineHeight); // When document line is wrapped over multiple display lines, find where // to start printing from to ensure a particular position is on the first // line of the page. if (visibleLine == 0) { const Sci::Position startWithinLine = nPrintPos - model.pdoc->LineStart(lineDoc); for (int iwl = 0; iwl < ll.lines - 1; iwl++) { if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) { visibleLine = -iwl; } } if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) { visibleLine = -(ll.lines - 1); } } if (draw && lineNumberWidth && (ypos + vsPrint.lineHeight <= pfr->rc.bottom) && (visibleLine >= 0)) { const std::string number = std::to_string(lineDoc + 1) + lineNumberPrintSpace; PRectangle rcNumber = rcLine; rcNumber.right = rcNumber.left + lineNumberWidth; // Right justify rcNumber.left = rcNumber.right - surfaceMeasure->WidthText( vsPrint.styles[STYLE_LINENUMBER].font, number.c_str(), static_cast(number.length())); surface->FlushCachedState(); surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font, static_cast(ypos + vsPrint.maxAscent), number.c_str(), static_cast(number.length()), vsPrint.styles[STYLE_LINENUMBER].fore, vsPrint.styles[STYLE_LINENUMBER].back); } // Draw the line surface->FlushCachedState(); for (int iwl = 0; iwl < ll.lines; iwl++) { if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) { if (visibleLine >= 0) { if (draw) { rcLine.top = static_cast(ypos); rcLine.bottom = static_cast(ypos + vsPrint.lineHeight); DrawLine(surface, model, vsPrint, &ll, lineDoc, visibleLine, xStart, rcLine, iwl, drawAll); } ypos += vsPrint.lineHeight; } visibleLine++; if (iwl == ll.lines - 1) nPrintPos = model.pdoc->LineStart(lineDoc + 1); else nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl); } } ++lineDoc; } // Clear cache so measurements are not used for screen posCache.Clear(); return nPrintPos; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/EditView.h000066400000000000000000000173631463772530400254620ustar00rootroot00000000000000// Scintilla source code edit control /** @file EditView.h ** Defines the appearance of the main text area of the editor window. **/ // Copyright 1998-2014 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef EDITVIEW_H #define EDITVIEW_H namespace Scintilla { struct PrintParameters { int magnification; int colourMode; WrapMode wrapState; PrintParameters(); }; /** * The view may be drawn in separate phases. */ enum DrawPhase { drawBack = 0x1, drawIndicatorsBack = 0x2, drawText = 0x4, drawIndentationGuides = 0x8, drawIndicatorsFore = 0x10, drawSelectionTranslucent = 0x20, drawLineTranslucent = 0x40, drawFoldLines = 0x80, drawCarets = 0x100, drawAll = 0x1FF }; bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st); int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st); void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase, const char *s, int len, DrawPhase phase); void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, const StyledText &st, size_t start, size_t length, DrawPhase phase); typedef void (*DrawTabArrowFn)(Surface *surface, PRectangle rcTab, int ymid); class LineTabstops; /** * EditView draws the main text area. */ class EditView { public: PrintParameters printParameters; std::unique_ptr ldTabstops; int tabWidthMinimumPixels; bool hideSelection; bool drawOverstrikeCaret; /** In bufferedDraw mode, graphics operations are drawn to a pixmap and then copied to * the screen. This avoids flashing but is about 30% slower. */ bool bufferedDraw; /** In phasesTwo mode, drawing is performed in two phases, first the background * and then the foreground. This avoids chopping off characters that overlap the next run. * In multiPhaseDraw mode, drawing is performed in multiple phases with each phase drawing * one feature over the whole drawing area, instead of within one line. This allows text to * overlap from one line to the next. */ enum PhasesDraw { phasesOne, phasesTwo, phasesMultiple }; PhasesDraw phasesDraw; int lineWidthMaxSeen; bool additionalCaretsBlink; bool additionalCaretsVisible; bool imeCaretBlockOverride; std::unique_ptr pixmapLine; std::unique_ptr pixmapIndentGuide; std::unique_ptr pixmapIndentGuideHighlight; LineLayoutCache llc; PositionCache posCache; int tabArrowHeight; // draw arrow heads this many pixels above/below line midpoint /** Some platforms, notably PLAT_CURSES, do not support Scintilla's native * DrawTabArrow function for drawing tab characters. Allow those platforms to * override it instead of creating a new method in the Surface class that * existing platforms must implement as empty. */ DrawTabArrowFn customDrawTabArrow; DrawWrapMarkerFn customDrawWrapMarker; EditView(); // Deleted so EditView objects can not be copied. EditView(const EditView &) = delete; EditView(EditView &&) = delete; void operator=(const EditView &) = delete; void operator=(EditView &&) = delete; virtual ~EditView(); bool SetTwoPhaseDraw(bool twoPhaseDraw); bool SetPhasesDraw(int phases); bool LinesOverlap() const; void ClearAllTabstops(); XYPOSITION NextTabstopPos(Sci::Line line, XYPOSITION x, XYPOSITION tabWidth) const; bool ClearTabstops(Sci::Line line); bool AddTabstop(Sci::Line line, int x); int GetNextTabstop(Sci::Line line, int x) const; void LinesAddedOrRemoved(Sci::Line lineOfPos, Sci::Line linesAdded); void DropGraphics(bool freeObjects); void AllocateGraphics(const ViewStyle &vsDraw); void RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw); LineLayout *RetrieveLineLayout(Sci::Line lineNumber, const EditModel &model); void LayoutLine(const EditModel &model, Sci::Line line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, int width = LineLayout::wrapWidthInfinite); Point LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, Sci::Line topLine, const ViewStyle &vs, PointEnd pe); Range RangeDisplayLine(Surface *surface, const EditModel &model, Sci::Line lineVisible, const ViewStyle &vs); SelectionPosition SPositionFromLocation(Surface *surface, const EditModel &model, PointDocument pt, bool canReturnInvalid, bool charPosition, bool virtualSpace, const ViewStyle &vs); SelectionPosition SPositionFromLineX(Surface *surface, const EditModel &model, Sci::Line lineDoc, int x, const ViewStyle &vs); Sci::Line DisplayFromPosition(Surface *surface, const EditModel &model, Sci::Position pos, const ViewStyle &vs); Sci::Position StartEndDisplayLine(Surface *surface, const EditModel &model, Sci::Position pos, bool start, const ViewStyle &vs); void DrawIndentGuide(Surface *surface, Sci::Line lineVisible, int lineHeight, XYPOSITION start, PRectangle rcSegment, bool highlight); void DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, Sci::Line line, Sci::Position lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, ColourOptional background); void DrawFoldDisplayText(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, XYACCUMULATOR subLineStart, DrawPhase phase); void DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase); void DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line lineDoc, int xStart, PRectangle rcLine, int subLine) const; void DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart, int subLine, ColourOptional background) const; void DrawForeground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line lineVisible, PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart, int subLine, ColourOptional background); void DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, Sci::Line lineVisible, PRectangle rcLine, int xStart, int subLine); void DrawLine(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, Sci::Line lineVisible, int xStart, PRectangle rcLine, int subLine, DrawPhase phase); void PaintText(Surface *surfaceWindow, const EditModel &model, PRectangle rcArea, PRectangle rcClient, const ViewStyle &vsDraw); void FillLineRemainder(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcArea, int subLine) const; Sci::Position FormatRange(bool draw, const Sci_RangeToFormat *pfr, Surface *surface, Surface *surfaceMeasure, const EditModel &model, const ViewStyle &vs); }; /** * Convenience class to ensure LineLayout objects are always disposed. */ class AutoLineLayout { LineLayoutCache &llc; LineLayout *ll; public: AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) noexcept : llc(llc_), ll(ll_) {} AutoLineLayout(const AutoLineLayout &) = delete; AutoLineLayout(AutoLineLayout &&) = delete; AutoLineLayout &operator=(const AutoLineLayout &) = delete; AutoLineLayout &operator=(AutoLineLayout &&) = delete; ~AutoLineLayout() { llc.Dispose(ll); ll = nullptr; } LineLayout *operator->() const noexcept { return ll; } operator LineLayout *() const noexcept { return ll; } void Set(LineLayout *ll_) { llc.Dispose(ll); ll = ll_; } }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Editor.cpp000066400000000000000000007454511463772530400255310ustar00rootroot00000000000000// Scintilla source code edit control /** @file Editor.cxx ** Main code for the edit control. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILoader.h" #include "ILexer.h" #include "Scintilla.h" #include "StringCopy.h" #include "CharacterSet.h" #include "Position.h" #include "UniqueString.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "PerLine.h" #include "KeyMap.h" #include "Indicator.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" #include "EditModel.h" #include "MarginView.h" #include "EditView.h" #include "Editor.h" #include "ElapsedPeriod.h" using namespace Scintilla; /* return whether this modification represents an operation that may reasonably be deferred (not done now OR [possibly] at all) */ static bool CanDeferToLastStep(const DocModification &mh) { if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) return true; // CAN skip if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO))) return false; // MUST do if (mh.modificationType & SC_MULTISTEPUNDOREDO) return true; // CAN skip return false; // PRESUMABLY must do } static bool CanEliminate(const DocModification &mh) { return (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0; } /* return whether this modification represents the FINAL step in a [possibly lengthy] multi-step Undo/Redo sequence */ static bool IsLastStep(const DocModification &mh) { return (mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0 && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0 && (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0 && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0; } Timer::Timer() : ticking(false), ticksToWait(0), tickerID{} {} Idler::Idler() : state(false), idlerID(0) {} static inline bool IsAllSpacesOrTabs(const char *s, unsigned int len) { for (unsigned int i = 0; i < len; i++) { // This is safe because IsSpaceOrTab() will return false for null terminators if (!IsSpaceOrTab(s[i])) return false; } return true; } Editor::Editor() : durationWrapOneLine(0.00001, 0.000001, 0.0001) { ctrlID = 0; stylesValid = false; technology = SC_TECHNOLOGY_DEFAULT; scaleRGBAImage = 100.0f; cursorMode = SC_CURSORNORMAL; hasFocus = false; errorStatus = 0; mouseDownCaptures = true; mouseWheelCaptures = true; lastClickTime = 0; doubleClickCloseThreshold = Point(3, 3); dwellDelay = SC_TIME_FOREVER; ticksToDwell = SC_TIME_FOREVER; dwelling = false; ptMouseLast.x = 0; ptMouseLast.y = 0; inDragDrop = ddNone; dropWentOutside = false; posDrop = SelectionPosition(Sci::invalidPosition); hotSpotClickPos = INVALID_POSITION; selectionType = selChar; lastXChosen = 0; lineAnchorPos = 0; originalAnchorPos = 0; wordSelectAnchorStartPos = 0; wordSelectAnchorEndPos = 0; wordSelectInitialCaretPos = -1; caretXPolicy = CARET_SLOP | CARET_EVEN; caretXSlop = 50; caretYPolicy = CARET_EVEN; caretYSlop = 0; visiblePolicy = 0; visibleSlop = 0; searchAnchor = 0; xCaretMargin = 50; horizontalScrollBarVisible = true; scrollWidth = 2000; verticalScrollBarVisible = true; endAtLastLine = true; caretSticky = SC_CARETSTICKY_OFF; marginOptions = SC_MARGINOPTION_NONE; mouseSelectionRectangularSwitch = false; multipleSelection = false; additionalSelectionTyping = false; multiPasteMode = SC_MULTIPASTE_ONCE; virtualSpaceOptions = SCVS_NONE; targetStart = 0; targetEnd = 0; searchFlags = 0; topLine = 0; posTopLine = 0; lengthForEncode = -1; needUpdateUI = 0; ContainerNeedsUpdate(SC_UPDATE_CONTENT); paintState = notPainting; paintAbandonedByStyling = false; paintingAllText = false; willRedrawAll = false; idleStyling = SC_IDLESTYLING_NONE; needIdleStyling = false; modEventMask = SC_MODEVENTMASKALL; commandEvents = true; pdoc->AddWatcher(this, 0); recordingMacro = false; foldAutomatic = 0; convertPastes = true; SetRepresentations(); } Editor::~Editor() { pdoc->RemoveWatcher(this, 0); DropGraphics(true); } void Editor::Finalise() { SetIdle(false); CancelModes(); } void Editor::SetRepresentations() { reprs.Clear(); // C0 control set const char *const reps[] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" }; for (size_t j=0; j < ELEMENTS(reps); j++) { const char c[2] = { static_cast(j), 0 }; reprs.SetRepresentation(c, reps[j]); } // C1 control set // As well as Unicode mode, ISO-8859-1 should use these if (IsUnicodeMode()) { const char *const repsC1[] = { "PAD", "HOP", "BPH", "NBH", "IND", "NEL", "SSA", "ESA", "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3", "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA", "SOS", "SGCI", "SCI", "CSI", "ST", "OSC", "PM", "APC" }; for (size_t j=0; j < ELEMENTS(repsC1); j++) { const char c1[3] = { '\xc2', static_cast(0x80+j), 0 }; reprs.SetRepresentation(c1, repsC1[j]); } reprs.SetRepresentation("\xe2\x80\xa8", "LS"); reprs.SetRepresentation("\xe2\x80\xa9", "PS"); } // UTF-8 invalid bytes if (IsUnicodeMode()) { for (int k=0x80; k < 0x100; k++) { const char hiByte[2] = { static_cast(k), 0 }; char hexits[5]; // Really only needs 4 but that causes warning from gcc 7.1 sprintf(hexits, "x%2X", k); reprs.SetRepresentation(hiByte, hexits); } } else if (pdoc->dbcsCodePage) { // DBCS invalid single lead bytes for (int k = 0x80; k < 0x100; k++) { const char ch = static_cast(k); if (pdoc->IsDBCSLeadByteNoExcept(ch) || pdoc->IsDBCSLeadByteInvalid(ch)) { const char hiByte[2] = { ch, 0 }; char hexits[5]; // Really only needs 4 but that causes warning from gcc 7.1 sprintf(hexits, "x%2X", k); reprs.SetRepresentation(hiByte, hexits); } } } } void Editor::DropGraphics(bool freeObjects) { marginView.DropGraphics(freeObjects); view.DropGraphics(freeObjects); } void Editor::AllocateGraphics() { marginView.AllocateGraphics(vs); view.AllocateGraphics(vs); } void Editor::InvalidateStyleData() { stylesValid = false; vs.technology = technology; DropGraphics(false); AllocateGraphics(); view.llc.Invalidate(LineLayout::llInvalid); view.posCache.Clear(); } void Editor::InvalidateStyleRedraw() { NeedWrapping(); InvalidateStyleData(); Redraw(); } void Editor::RefreshStyleData() { if (!stylesValid) { stylesValid = true; AutoSurface surface(this); if (surface) { vs.Refresh(*surface, pdoc->tabInChars); } SetScrollBars(); SetRectangularRange(); } } Point Editor::GetVisibleOriginInMain() const { return Point(0, 0); } PointDocument Editor::DocumentPointFromView(Point ptView) const { PointDocument ptDocument(ptView); if (wMargin.GetID()) { const Point ptOrigin = GetVisibleOriginInMain(); ptDocument.x += ptOrigin.x; ptDocument.y += ptOrigin.y; } else { ptDocument.x += xOffset; ptDocument.y += topLine * vs.lineHeight; } return ptDocument; } Sci::Line Editor::TopLineOfMain() const { if (wMargin.GetID()) return 0; else return topLine; } PRectangle Editor::GetClientRectangle() const { return wMain.GetClientPosition(); } PRectangle Editor::GetClientDrawingRectangle() { return GetClientRectangle(); } PRectangle Editor::GetTextRectangle() const { PRectangle rc = GetClientRectangle(); rc.left += vs.textStart; rc.right -= vs.rightMarginWidth; return rc; } Sci::Line Editor::LinesOnScreen() const { const PRectangle rcClient = GetClientRectangle(); const int htClient = static_cast(rcClient.bottom - rcClient.top); //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1); return htClient / vs.lineHeight; } Sci::Line Editor::LinesToScroll() const { const Sci::Line retVal = LinesOnScreen() - 1; if (retVal < 1) return 1; else return retVal; } Sci::Line Editor::MaxScrollPos() const { //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n", //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1); Sci::Line retVal = pcs->LinesDisplayed(); if (endAtLastLine) { retVal -= LinesOnScreen(); } else { retVal--; } if (retVal < 0) { return 0; } else { return retVal; } } SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const { if (sp.Position() < 0) { return SelectionPosition(0); } else if (sp.Position() > pdoc->Length()) { return SelectionPosition(pdoc->Length()); } else { // If not at end of line then set offset to 0 if (!pdoc->IsLineEndPosition(sp.Position())) sp.SetVirtualSpace(0); return sp; } } Point Editor::LocationFromPosition(SelectionPosition pos, PointEnd pe) { RefreshStyleData(); AutoSurface surface(this); return view.LocationFromPosition(surface, *this, pos, topLine, vs, pe); } Point Editor::LocationFromPosition(Sci::Position pos, PointEnd pe) { return LocationFromPosition(SelectionPosition(pos), pe); } int Editor::XFromPosition(SelectionPosition sp) { const Point pt = LocationFromPosition(sp); return static_cast(pt.x) - vs.textStart + xOffset; } SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace) { RefreshStyleData(); AutoSurface surface(this); if (canReturnInvalid) { PRectangle rcClient = GetTextRectangle(); // May be in scroll view coordinates so translate back to main view const Point ptOrigin = GetVisibleOriginInMain(); rcClient.Move(-ptOrigin.x, -ptOrigin.y); if (!rcClient.Contains(pt)) return SelectionPosition(INVALID_POSITION); if (pt.x < vs.textStart) return SelectionPosition(INVALID_POSITION); if (pt.y < 0) return SelectionPosition(INVALID_POSITION); } const PointDocument ptdoc = DocumentPointFromView(pt); return view.SPositionFromLocation(surface, *this, ptdoc, canReturnInvalid, charPosition, virtualSpace, vs); } Sci::Position Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) { return SPositionFromLocation(pt, canReturnInvalid, charPosition, false).Position(); } /** * Find the document position corresponding to an x coordinate on a particular document line. * Ensure is between whole characters when document is in multi-byte or UTF-8 mode. * This method is used for rectangular selections and does not work on wrapped lines. */ SelectionPosition Editor::SPositionFromLineX(Sci::Line lineDoc, int x) { RefreshStyleData(); if (lineDoc >= pdoc->LinesTotal()) return SelectionPosition(pdoc->Length()); //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); AutoSurface surface(this); return view.SPositionFromLineX(surface, *this, lineDoc, x, vs); } Sci::Position Editor::PositionFromLineX(Sci::Line lineDoc, int x) { return SPositionFromLineX(lineDoc, x).Position(); } Sci::Line Editor::LineFromLocation(Point pt) const { return pcs->DocFromDisplay(static_cast(pt.y) / vs.lineHeight + topLine); } void Editor::SetTopLine(Sci::Line topLineNew) { if ((topLine != topLineNew) && (topLineNew >= 0)) { topLine = topLineNew; ContainerNeedsUpdate(SC_UPDATE_V_SCROLL); } posTopLine = pdoc->LineStart(pcs->DocFromDisplay(topLine)); } /** * If painting then abandon the painting because a wider redraw is needed. * @return true if calling code should stop drawing. */ bool Editor::AbandonPaint() { if ((paintState == painting) && !paintingAllText) { paintState = paintAbandoned; } return paintState == paintAbandoned; } void Editor::RedrawRect(PRectangle rc) { //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom); // Clip the redraw rectangle into the client area const PRectangle rcClient = GetClientRectangle(); if (rc.top < rcClient.top) rc.top = rcClient.top; if (rc.bottom > rcClient.bottom) rc.bottom = rcClient.bottom; if (rc.left < rcClient.left) rc.left = rcClient.left; if (rc.right > rcClient.right) rc.right = rcClient.right; if ((rc.bottom > rc.top) && (rc.right > rc.left)) { wMain.InvalidateRectangle(rc); } } void Editor::DiscardOverdraw() { // Overridden on platforms that may draw outside visible area. } void Editor::Redraw() { //Platform::DebugPrintf("Redraw all\n"); const PRectangle rcClient = GetClientRectangle(); wMain.InvalidateRectangle(rcClient); if (wMargin.GetID()) wMargin.InvalidateAll(); //wMain.InvalidateAll(); } void Editor::RedrawSelMargin(Sci::Line line, bool allAfter) { const bool markersInText = vs.maskInLine || vs.maskDrawInText; if (!wMargin.GetID() || markersInText) { // May affect text area so may need to abandon and retry if (AbandonPaint()) { return; } } if (wMargin.GetID() && markersInText) { Redraw(); return; } PRectangle rcMarkers = GetClientRectangle(); if (!markersInText) { // Normal case: just draw the margin rcMarkers.right = rcMarkers.left + vs.fixedColumnWidth; } if (line != -1) { PRectangle rcLine = RectangleFromRange(Range(pdoc->LineStart(line)), 0); // Inflate line rectangle if there are image markers with height larger than line height if (vs.largestMarkerHeight > vs.lineHeight) { const int delta = (vs.largestMarkerHeight - vs.lineHeight + 1) / 2; rcLine.top -= delta; rcLine.bottom += delta; if (rcLine.top < rcMarkers.top) rcLine.top = rcMarkers.top; if (rcLine.bottom > rcMarkers.bottom) rcLine.bottom = rcMarkers.bottom; } rcMarkers.top = rcLine.top; if (!allAfter) rcMarkers.bottom = rcLine.bottom; if (rcMarkers.Empty()) return; } if (wMargin.GetID()) { const Point ptOrigin = GetVisibleOriginInMain(); rcMarkers.Move(-ptOrigin.x, -ptOrigin.y); wMargin.InvalidateRectangle(rcMarkers); } else { wMain.InvalidateRectangle(rcMarkers); } } PRectangle Editor::RectangleFromRange(Range r, int overlap) { const Sci::Line minLine = pcs->DisplayFromDoc( pdoc->SciLineFromPosition(r.First())); const Sci::Line maxLine = pcs->DisplayLastFromDoc( pdoc->SciLineFromPosition(r.Last())); const PRectangle rcClientDrawing = GetClientDrawingRectangle(); PRectangle rc; const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0; rc.left = static_cast(vs.textStart - leftTextOverlap); rc.top = static_cast((minLine - TopLineOfMain()) * vs.lineHeight - overlap); if (rc.top < rcClientDrawing.top) rc.top = rcClientDrawing.top; // Extend to right of prepared area if any to prevent artifacts from caret line highlight rc.right = rcClientDrawing.right; rc.bottom = static_cast((maxLine - TopLineOfMain() + 1) * vs.lineHeight + overlap); return rc; } void Editor::InvalidateRange(Sci::Position start, Sci::Position end) { RedrawRect(RectangleFromRange(Range(start, end), view.LinesOverlap() ? vs.lineOverlap : 0)); } Sci::Position Editor::CurrentPosition() const { return sel.MainCaret(); } bool Editor::SelectionEmpty() const { return sel.Empty(); } SelectionPosition Editor::SelectionStart() { return sel.RangeMain().Start(); } SelectionPosition Editor::SelectionEnd() { return sel.RangeMain().End(); } void Editor::SetRectangularRange() { if (sel.IsRectangular()) { const int xAnchor = XFromPosition(sel.Rectangular().anchor); int xCaret = XFromPosition(sel.Rectangular().caret); if (sel.selType == Selection::selThin) { xCaret = xAnchor; } const Sci::Line lineAnchorRect = pdoc->SciLineFromPosition(sel.Rectangular().anchor.Position()); const Sci::Line lineCaret = pdoc->SciLineFromPosition(sel.Rectangular().caret.Position()); const int increment = (lineCaret > lineAnchorRect) ? 1 : -1; for (Sci::Line line=lineAnchorRect; line != lineCaret+increment; line += increment) { SelectionRange range(SPositionFromLineX(line, xCaret), SPositionFromLineX(line, xAnchor)); if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) == 0) range.ClearVirtualSpace(); if (line == lineAnchorRect) sel.SetSelection(range); else sel.AddSelectionWithoutTrim(range); } } } void Editor::ThinRectangularRange() { if (sel.IsRectangular()) { sel.selType = Selection::selThin; if (sel.Rectangular().caret < sel.Rectangular().anchor) { sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).caret, sel.Range(0).anchor); } else { sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).anchor, sel.Range(0).caret); } SetRectangularRange(); } } void Editor::InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection) { if (sel.Count() > 1 || !(sel.RangeMain().anchor == newMain.anchor) || sel.IsRectangular()) { invalidateWholeSelection = true; } Sci::Position firstAffected = std::min(sel.RangeMain().Start().Position(), newMain.Start().Position()); // +1 for lastAffected ensures caret repainted Sci::Position lastAffected = std::max(newMain.caret.Position()+1, newMain.anchor.Position()); lastAffected = std::max(lastAffected, sel.RangeMain().End().Position()); if (invalidateWholeSelection) { for (size_t r=0; r anchor_) { anchor_ = SelectionPosition( pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position()))); currentPos_ = SelectionPosition( pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position()))); } else { currentPos_ = SelectionPosition( pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position()))); anchor_ = SelectionPosition( pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position()))); } return SelectionRange(currentPos_, anchor_); } void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_) { currentPos_ = ClampPositionIntoDocument(currentPos_); anchor_ = ClampPositionIntoDocument(anchor_); const Sci::Line currentLine = pdoc->SciLineFromPosition(currentPos_.Position()); SelectionRange rangeNew(currentPos_, anchor_); if (sel.selType == Selection::selLines) { rangeNew = LineSelectionRange(currentPos_, anchor_); } if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { InvalidateSelection(rangeNew); } sel.RangeMain() = rangeNew; SetRectangularRange(); ClaimSelection(); SetHoverIndicatorPosition(sel.MainCaret()); if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } QueueIdleWork(WorkNeeded::workUpdateUI); } void Editor::SetSelection(Sci::Position currentPos_, Sci::Position anchor_) { SetSelection(SelectionPosition(currentPos_), SelectionPosition(anchor_)); } // Just move the caret on the main selection void Editor::SetSelection(SelectionPosition currentPos_) { currentPos_ = ClampPositionIntoDocument(currentPos_); const Sci::Line currentLine = pdoc->SciLineFromPosition(currentPos_.Position()); if (sel.Count() > 1 || !(sel.RangeMain().caret == currentPos_)) { InvalidateSelection(SelectionRange(currentPos_)); } if (sel.IsRectangular()) { sel.Rectangular() = SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor); SetRectangularRange(); } else if (sel.selType == Selection::selLines) { sel.RangeMain() = LineSelectionRange(currentPos_, sel.RangeMain().anchor); } else { sel.RangeMain() = SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor); } ClaimSelection(); SetHoverIndicatorPosition(sel.MainCaret()); if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } QueueIdleWork(WorkNeeded::workUpdateUI); } void Editor::SetSelection(int currentPos_) { SetSelection(SelectionPosition(currentPos_)); } void Editor::SetEmptySelection(SelectionPosition currentPos_) { const Sci::Line currentLine = pdoc->SciLineFromPosition(currentPos_.Position()); SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_)); if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { InvalidateSelection(rangeNew); } sel.Clear(); sel.RangeMain() = rangeNew; SetRectangularRange(); ClaimSelection(); SetHoverIndicatorPosition(sel.MainCaret()); if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } QueueIdleWork(WorkNeeded::workUpdateUI); } void Editor::SetEmptySelection(Sci::Position currentPos_) { SetEmptySelection(SelectionPosition(currentPos_)); } void Editor::MultipleSelectAdd(AddNumber addNumber) { if (SelectionEmpty() || !multipleSelection) { // Select word at caret const Sci::Position startWord = pdoc->ExtendWordSelect(sel.MainCaret(), -1, true); const Sci::Position endWord = pdoc->ExtendWordSelect(startWord, 1, true); TrimAndSetSelection(endWord, startWord); } else { if (!pdoc->HasCaseFolder()) pdoc->SetCaseFolder(CaseFolderForEncoding()); const Range rangeMainSelection(sel.RangeMain().Start().Position(), sel.RangeMain().End().Position()); const std::string selectedText = RangeText(rangeMainSelection.start, rangeMainSelection.end); const Range rangeTarget(targetStart, targetEnd); std::vector searchRanges; // Search should be over the target range excluding the current selection so // may need to search 2 ranges, after the selection then before the selection. if (rangeTarget.Overlaps(rangeMainSelection)) { // Common case is that the selection is completely within the target but // may also have overlap at start or end. if (rangeMainSelection.end < rangeTarget.end) searchRanges.push_back(Range(rangeMainSelection.end, rangeTarget.end)); if (rangeTarget.start < rangeMainSelection.start) searchRanges.push_back(Range(rangeTarget.start, rangeMainSelection.start)); } else { // No overlap searchRanges.push_back(rangeTarget); } for (std::vector::const_iterator it = searchRanges.begin(); it != searchRanges.end(); ++it) { Sci::Position searchStart = it->start; const Sci::Position searchEnd = it->end; for (;;) { Sci::Position lengthFound = selectedText.length(); const Sci::Position pos = pdoc->FindText(searchStart, searchEnd, selectedText.c_str(), searchFlags, &lengthFound); if (pos >= 0) { sel.AddSelection(SelectionRange(pos + lengthFound, pos)); ScrollRange(sel.RangeMain()); Redraw(); if (addNumber == addOne) return; searchStart = pos + lengthFound; } else { break; } } } } } bool Editor::RangeContainsProtected(Sci::Position start, Sci::Position end) const { if (vs.ProtectionActive()) { if (start > end) { const Sci::Position t = start; start = end; end = t; } for (Sci::Position pos = start; pos < end; pos++) { if (vs.styles[pdoc->StyleIndexAt(pos)].IsProtected()) return true; } } return false; } bool Editor::SelectionContainsProtected() { for (size_t r=0; rMovePositionOutsideChar(pos.Position(), moveDir, checkLineEnd); if (posMoved != pos.Position()) pos.SetPosition(posMoved); if (vs.ProtectionActive()) { if (moveDir > 0) { if ((pos.Position() > 0) && vs.styles[pdoc->StyleIndexAt(pos.Position() - 1)].IsProtected()) { while ((pos.Position() < pdoc->Length()) && (vs.styles[pdoc->StyleIndexAt(pos.Position())].IsProtected())) pos.Add(1); } } else if (moveDir < 0) { if (vs.styles[pdoc->StyleIndexAt(pos.Position())].IsProtected()) { while ((pos.Position() > 0) && (vs.styles[pdoc->StyleIndexAt(pos.Position() - 1)].IsProtected())) pos.Add(-1); } } } return pos; } void Editor::MovedCaret(SelectionPosition newPos, SelectionPosition previousPos, bool ensureVisible) { const Sci::Line currentLine = pdoc->SciLineFromPosition(newPos.Position()); if (ensureVisible) { // In case in need of wrapping to ensure DisplayFromDoc works. if (currentLine >= wrapPending.start) { if (WrapLines(WrapScope::wsAll)) { Redraw(); } } const XYScrollPosition newXY = XYScrollToMakeVisible( SelectionRange(posDrag.IsValid() ? posDrag : newPos), xysDefault); if (previousPos.IsValid() && (newXY.xOffset == xOffset)) { // simple vertical scroll then invalidate ScrollTo(newXY.topLine); InvalidateSelection(SelectionRange(previousPos), true); } else { SetXYScroll(newXY); } } ShowCaretAtCurrentPosition(); NotifyCaretMove(); ClaimSelection(); SetHoverIndicatorPosition(sel.MainCaret()); QueueIdleWork(WorkNeeded::workUpdateUI); if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } } void Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) { const SelectionPosition spCaret = ((sel.Count() == 1) && sel.Empty()) ? sel.Last() : SelectionPosition(INVALID_POSITION); const Sci::Position delta = newPos.Position() - sel.MainCaret(); newPos = ClampPositionIntoDocument(newPos); newPos = MovePositionOutsideChar(newPos, delta); if (!multipleSelection && sel.IsRectangular() && (selt == Selection::selStream)) { // Can't turn into multiple selection so clear additional selections InvalidateSelection(SelectionRange(newPos), true); sel.DropAdditionalRanges(); } if (!sel.IsRectangular() && (selt == Selection::selRectangle)) { // Switching to rectangular InvalidateSelection(sel.RangeMain(), false); SelectionRange rangeMain = sel.RangeMain(); sel.Clear(); sel.Rectangular() = rangeMain; } if (selt != Selection::noSel) { sel.selType = selt; } if (selt != Selection::noSel || sel.MoveExtends()) { SetSelection(newPos); } else { SetEmptySelection(newPos); } MovedCaret(newPos, spCaret, ensureVisible); } void Editor::MovePositionTo(Sci::Position newPos, Selection::selTypes selt, bool ensureVisible) { MovePositionTo(SelectionPosition(newPos), selt, ensureVisible); } SelectionPosition Editor::MovePositionSoVisible(SelectionPosition pos, int moveDir) { pos = ClampPositionIntoDocument(pos); pos = MovePositionOutsideChar(pos, moveDir); const Sci::Line lineDoc = pdoc->SciLineFromPosition(pos.Position()); if (pcs->GetVisible(lineDoc)) { return pos; } else { Sci::Line lineDisplay = pcs->DisplayFromDoc(lineDoc); if (moveDir > 0) { // lineDisplay is already line before fold as lines in fold use display line of line after fold lineDisplay = Sci::clamp(lineDisplay, static_cast(0), pcs->LinesDisplayed()); return SelectionPosition( pdoc->LineStart(pcs->DocFromDisplay(lineDisplay))); } else { lineDisplay = Sci::clamp(lineDisplay - 1, static_cast(0), pcs->LinesDisplayed()); return SelectionPosition( pdoc->LineEnd(pcs->DocFromDisplay(lineDisplay))); } } } SelectionPosition Editor::MovePositionSoVisible(Sci::Position pos, int moveDir) { return MovePositionSoVisible(SelectionPosition(pos), moveDir); } Point Editor::PointMainCaret() { return LocationFromPosition(sel.Range(sel.Main()).caret); } /** * Choose the x position that the caret will try to stick to * as it moves up and down. */ void Editor::SetLastXChosen() { const Point pt = PointMainCaret(); lastXChosen = static_cast(pt.x) + xOffset; } void Editor::ScrollTo(Sci::Line line, bool moveThumb) { const Sci::Line topLineNew = Sci::clamp(line, static_cast(0), MaxScrollPos()); if (topLineNew != topLine) { // Try to optimise small scrolls #ifndef UNDER_CE const Sci::Line linesToMove = topLine - topLineNew; const bool performBlit = (std::abs(linesToMove) <= 10) && (paintState == notPainting); willRedrawAll = !performBlit; #endif SetTopLine(topLineNew); // Optimize by styling the view as this will invalidate any needed area // which could abort the initial paint if discovered later. StyleAreaBounded(GetClientRectangle(), true); #ifndef UNDER_CE // Perform redraw rather than scroll if many lines would be redrawn anyway. if (performBlit) { ScrollText(linesToMove); } else { Redraw(); } willRedrawAll = false; #else Redraw(); #endif if (moveThumb) { SetVerticalScrollPos(); } } } void Editor::ScrollText(Sci::Line /* linesToMove */) { //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove); Redraw(); } void Editor::HorizontalScrollTo(int xPos) { //Platform::DebugPrintf("HorizontalScroll %d\n", xPos); if (xPos < 0) xPos = 0; if (!Wrapping() && (xOffset != xPos)) { xOffset = xPos; ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); SetHorizontalScrollPos(); RedrawRect(GetClientRectangle()); } } void Editor::VerticalCentreCaret() { const Sci::Line lineDoc = pdoc->SciLineFromPosition(sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret()); const Sci::Line lineDisplay = pcs->DisplayFromDoc(lineDoc); const Sci::Line newTop = lineDisplay - (LinesOnScreen() / 2); if (topLine != newTop) { SetTopLine(newTop > 0 ? newTop : 0); RedrawRect(GetClientRectangle()); } } void Editor::MoveSelectedLines(int lineDelta) { // if selection doesn't start at the beginning of the line, set the new start Sci::Position selectionStart = SelectionStart().Position(); const Sci::Line startLine = pdoc->SciLineFromPosition(selectionStart); const Sci::Position beginningOfStartLine = pdoc->LineStart(startLine); selectionStart = beginningOfStartLine; // if selection doesn't end at the beginning of a line greater than that of the start, // then set it at the beginning of the next one Sci::Position selectionEnd = SelectionEnd().Position(); const Sci::Line endLine = pdoc->SciLineFromPosition(selectionEnd); const Sci::Position beginningOfEndLine = pdoc->LineStart(endLine); bool appendEol = false; if (selectionEnd > beginningOfEndLine || selectionStart == selectionEnd) { selectionEnd = pdoc->LineStart(endLine + 1); appendEol = (selectionEnd == pdoc->Length() && pdoc->SciLineFromPosition(selectionEnd) == endLine); } // if there's nowhere for the selection to move // (i.e. at the beginning going up or at the end going down), // stop it right there! if ((selectionStart == 0 && lineDelta < 0) || (selectionEnd == pdoc->Length() && lineDelta > 0) || selectionStart == selectionEnd) { return; } UndoGroup ug(pdoc); if (lineDelta > 0 && selectionEnd == pdoc->LineStart(pdoc->LinesTotal() - 1)) { SetSelection(pdoc->MovePositionOutsideChar(selectionEnd - 1, -1), selectionEnd); ClearSelection(); selectionEnd = CurrentPosition(); } SetSelection(selectionStart, selectionEnd); SelectionText selectedText; CopySelectionRange(&selectedText); Sci::Position selectionLength = SelectionRange(selectionStart, selectionEnd).Length(); const Point currentLocation = LocationFromPosition(CurrentPosition()); const Sci::Line currentLine = LineFromLocation(currentLocation); if (appendEol) SetSelection(pdoc->MovePositionOutsideChar(selectionStart - 1, -1), selectionEnd); ClearSelection(); const char *eol = StringFromEOLMode(pdoc->eolMode); if (currentLine + lineDelta >= pdoc->LinesTotal()) pdoc->InsertString(pdoc->Length(), eol, strlen(eol)); GoToLine(currentLine + lineDelta); selectionLength = pdoc->InsertString(CurrentPosition(), selectedText.Data(), selectionLength); if (appendEol) { const Sci::Position lengthInserted = pdoc->InsertString(CurrentPosition() + selectionLength, eol, strlen(eol)); selectionLength += lengthInserted; } SetSelection(CurrentPosition(), CurrentPosition() + selectionLength); } void Editor::MoveSelectedLinesUp() { MoveSelectedLines(-1); } void Editor::MoveSelectedLinesDown() { MoveSelectedLines(1); } void Editor::MoveCaretInsideView(bool ensureVisible) { const PRectangle rcClient = GetTextRectangle(); const Point pt = PointMainCaret(); if (pt.y < rcClient.top) { MovePositionTo(SPositionFromLocation( Point::FromInts(lastXChosen - xOffset, static_cast(rcClient.top)), false, false, UserVirtualSpace()), Selection::noSel, ensureVisible); } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) { const ptrdiff_t yOfLastLineFullyDisplayed = static_cast(rcClient.top) + (LinesOnScreen() - 1) * vs.lineHeight; MovePositionTo(SPositionFromLocation( Point::FromInts(lastXChosen - xOffset, static_cast(rcClient.top + yOfLastLineFullyDisplayed)), false, false, UserVirtualSpace()), Selection::noSel, ensureVisible); } } Sci::Line Editor::DisplayFromPosition(Sci::Position pos) { AutoSurface surface(this); return view.DisplayFromPosition(surface, *this, pos, vs); } /** * Ensure the caret is reasonably visible in context. * Caret policy in SciTE If slop is set, we can define a slop value. This value defines an unwanted zone (UZ) where the caret is... unwanted. This zone is defined as a number of pixels near the vertical margins, and as a number of lines near the horizontal margins. By keeping the caret away from the edges, it is seen within its context, so it is likely that the identifier that the caret is on can be completely seen, and that the current line is seen with some of the lines following it which are often dependent on that line. If strict is set, the policy is enforced... strictly. The caret is centred on the display if slop is not set, and cannot go in the UZ if slop is set. If jumps is set, the display is moved more energetically so the caret can move in the same direction longer before the policy is applied again. '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin. If even is not set, instead of having symmetrical UZs, the left and bottom UZs are extended up to right and top UZs respectively. This way, we favour the displaying of useful information: the beginning of lines, where most code reside, and the lines after the caret, eg. the body of a function. | | | | | slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of | | | | | visibility or going into the UZ) display is... -----+--------+-------+------+--------------------------------------------+-------------------------------------------------------------- 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right 0 | 0 | 0 | 1 | Yes | moved by one position 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right 0 | 0 | 1 | 1 | Yes | centred on the caret 0 | 1 | - | 0 | Caret is always on top/on right of display | - 0 | 1 | - | 1 | No, caret is always centred | - 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | - 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin */ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const SelectionRange &range, const XYScrollOptions options) { const PRectangle rcClient = GetTextRectangle(); Point pt = LocationFromPosition(range.caret); Point ptAnchor = LocationFromPosition(range.anchor); const Point ptOrigin = GetVisibleOriginInMain(); pt.x += ptOrigin.x; pt.y += ptOrigin.y; ptAnchor.x += ptOrigin.x; ptAnchor.y += ptOrigin.y; const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1); XYScrollPosition newXY(xOffset, topLine); if (rcClient.Empty()) { return newXY; } // Vertical positioning if ((options & xysVertical) && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) { const Sci::Line lineCaret = DisplayFromPosition(range.caret.Position()); const Sci::Line linesOnScreen = LinesOnScreen(); const Sci::Line halfScreen = std::max(linesOnScreen - 1, static_cast(2)) / 2; const bool bSlop = (caretYPolicy & CARET_SLOP) != 0; const bool bStrict = (caretYPolicy & CARET_STRICT) != 0; const bool bJump = (caretYPolicy & CARET_JUMPS) != 0; const bool bEven = (caretYPolicy & CARET_EVEN) != 0; // It should be possible to scroll the window to show the caret, // but this fails to remove the caret on GTK+ if (bSlop) { // A margin is defined Sci::Line yMoveT, yMoveB; if (bStrict) { Sci::Line yMarginT, yMarginB; if (!(options & xysUseMargin)) { // In drag mode, avoid moves // otherwise, a double click will select several lines. yMarginT = yMarginB = 0; } else { // yMarginT must equal to caretYSlop, with a minimum of 1 and // a maximum of slightly less than half the heigth of the text area. yMarginT = Sci::clamp(static_cast(caretYSlop), static_cast(1), halfScreen); if (bEven) { yMarginB = yMarginT; } else { yMarginB = linesOnScreen - yMarginT - 1; } } yMoveT = yMarginT; if (bEven) { if (bJump) { yMoveT = Sci::clamp(static_cast(caretYSlop * 3), static_cast(1), halfScreen); } yMoveB = yMoveT; } else { yMoveB = linesOnScreen - yMoveT - 1; } if (lineCaret < topLine + yMarginT) { // Caret goes too high newXY.topLine = lineCaret - yMoveT; } else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) { // Caret goes too low newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB; } } else { // Not strict yMoveT = bJump ? caretYSlop * 3 : caretYSlop; yMoveT = Sci::clamp(yMoveT, static_cast(1), halfScreen); if (bEven) { yMoveB = yMoveT; } else { yMoveB = linesOnScreen - yMoveT - 1; } if (lineCaret < topLine) { // Caret goes too high newXY.topLine = lineCaret - yMoveT; } else if (lineCaret > topLine + linesOnScreen - 1) { // Caret goes too low newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB; } } } else { // No slop if (!bStrict && !bJump) { // Minimal move if (lineCaret < topLine) { // Caret goes too high newXY.topLine = lineCaret; } else if (lineCaret > topLine + linesOnScreen - 1) { // Caret goes too low if (bEven) { newXY.topLine = lineCaret - linesOnScreen + 1; } else { newXY.topLine = lineCaret; } } } else { // Strict or going out of display if (bEven) { // Always center caret newXY.topLine = lineCaret - halfScreen; } else { // Always put caret on top of display newXY.topLine = lineCaret; } } } if (!(range.caret == range.anchor)) { const Sci::Line lineAnchor = DisplayFromPosition(range.anchor.Position()); if (lineAnchor < lineCaret) { // Shift up to show anchor or as much of range as possible newXY.topLine = std::min(newXY.topLine, lineAnchor); newXY.topLine = std::max(newXY.topLine, lineCaret - LinesOnScreen()); } else { // Shift down to show anchor or as much of range as possible newXY.topLine = std::max(newXY.topLine, lineAnchor - LinesOnScreen()); newXY.topLine = std::min(newXY.topLine, lineCaret); } } newXY.topLine = Sci::clamp(newXY.topLine, static_cast(0), MaxScrollPos()); } // Horizontal positioning if ((options & xysHorizontal) && !Wrapping()) { const int halfScreen = std::max(static_cast(rcClient.Width()) - 4, 4) / 2; const bool bSlop = (caretXPolicy & CARET_SLOP) != 0; const bool bStrict = (caretXPolicy & CARET_STRICT) != 0; const bool bJump = (caretXPolicy & CARET_JUMPS) != 0; const bool bEven = (caretXPolicy & CARET_EVEN) != 0; if (bSlop) { // A margin is defined int xMoveL, xMoveR; if (bStrict) { int xMarginL, xMarginR; if (!(options & xysUseMargin)) { // In drag mode, avoid moves unless very near of the margin // otherwise, a simple click will select text. xMarginL = xMarginR = 2; } else { // xMargin must equal to caretXSlop, with a minimum of 2 and // a maximum of slightly less than half the width of the text area. xMarginR = Sci::clamp(caretXSlop, 2, halfScreen); if (bEven) { xMarginL = xMarginR; } else { xMarginL = static_cast(rcClient.Width()) - xMarginR - 4; } } if (bJump && bEven) { // Jump is used only in even mode xMoveL = xMoveR = Sci::clamp(caretXSlop * 3, 1, halfScreen); } else { xMoveL = xMoveR = 0; // Not used, avoid a warning } if (pt.x < rcClient.left + xMarginL) { // Caret is on the left of the display if (bJump && bEven) { newXY.xOffset -= xMoveL; } else { // Move just enough to allow to display the caret newXY.xOffset -= static_cast((rcClient.left + xMarginL) - pt.x); } } else if (pt.x >= rcClient.right - xMarginR) { // Caret is on the right of the display if (bJump && bEven) { newXY.xOffset += xMoveR; } else { // Move just enough to allow to display the caret newXY.xOffset += static_cast(pt.x - (rcClient.right - xMarginR) + 1); } } } else { // Not strict xMoveR = bJump ? caretXSlop * 3 : caretXSlop; xMoveR = Sci::clamp(xMoveR, 1, halfScreen); if (bEven) { xMoveL = xMoveR; } else { xMoveL = static_cast(rcClient.Width()) - xMoveR - 4; } if (pt.x < rcClient.left) { // Caret is on the left of the display newXY.xOffset -= xMoveL; } else if (pt.x >= rcClient.right) { // Caret is on the right of the display newXY.xOffset += xMoveR; } } } else { // No slop if (bStrict || (bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) { // Strict or going out of display if (bEven) { // Center caret newXY.xOffset += static_cast(pt.x - rcClient.left - halfScreen); } else { // Put caret on right newXY.xOffset += static_cast(pt.x - rcClient.right + 1); } } else { // Move just enough to allow to display the caret if (pt.x < rcClient.left) { // Caret is on the left of the display if (bEven) { newXY.xOffset -= static_cast(rcClient.left - pt.x); } else { newXY.xOffset += static_cast(pt.x - rcClient.right) + 1; } } else if (pt.x >= rcClient.right) { // Caret is on the right of the display newXY.xOffset += static_cast(pt.x - rcClient.right) + 1; } } } // In case of a jump (find result) largely out of display, adjust the offset to display the caret if (pt.x + xOffset < rcClient.left + newXY.xOffset) { newXY.xOffset = static_cast(pt.x + xOffset - rcClient.left) - 2; } else if (pt.x + xOffset >= rcClient.right + newXY.xOffset) { newXY.xOffset = static_cast(pt.x + xOffset - rcClient.right) + 2; if ((vs.caretStyle == CARETSTYLE_BLOCK) || view.imeCaretBlockOverride) { // Ensure we can see a good portion of the block caret newXY.xOffset += static_cast(vs.aveCharWidth); } } if (!(range.caret == range.anchor)) { if (ptAnchor.x < pt.x) { // Shift to left to show anchor or as much of range as possible const int maxOffset = static_cast(ptAnchor.x + xOffset - rcClient.left) - 1; const int minOffset = static_cast(pt.x + xOffset - rcClient.right) + 1; newXY.xOffset = std::min(newXY.xOffset, maxOffset); newXY.xOffset = std::max(newXY.xOffset, minOffset); } else { // Shift to right to show anchor or as much of range as possible const int minOffset = static_cast(ptAnchor.x + xOffset - rcClient.right) + 1; const int maxOffset = static_cast(pt.x + xOffset - rcClient.left) - 1; newXY.xOffset = std::max(newXY.xOffset, minOffset); newXY.xOffset = std::min(newXY.xOffset, maxOffset); } } if (newXY.xOffset < 0) { newXY.xOffset = 0; } } return newXY; } void Editor::SetXYScroll(XYScrollPosition newXY) { if ((newXY.topLine != topLine) || (newXY.xOffset != xOffset)) { if (newXY.topLine != topLine) { SetTopLine(newXY.topLine); SetVerticalScrollPos(); } if (newXY.xOffset != xOffset) { xOffset = newXY.xOffset; ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); if (newXY.xOffset > 0) { const PRectangle rcText = GetTextRectangle(); if (horizontalScrollBarVisible && rcText.Width() + xOffset > scrollWidth) { scrollWidth = xOffset + static_cast(rcText.Width()); SetScrollBars(); } } SetHorizontalScrollPos(); } Redraw(); UpdateSystemCaret(); } } void Editor::ScrollRange(SelectionRange range) { SetXYScroll(XYScrollToMakeVisible(range, xysDefault)); } void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret), static_cast((useMargin?xysUseMargin:0)|(vert?xysVertical:0)|(horiz?xysHorizontal:0)))); } void Editor::ShowCaretAtCurrentPosition() { if (hasFocus) { caret.active = true; caret.on = true; FineTickerCancel(tickCaret); if (caret.period > 0) FineTickerStart(tickCaret, caret.period, caret.period/10); } else { caret.active = false; caret.on = false; FineTickerCancel(tickCaret); } InvalidateCaret(); } void Editor::DropCaret() { caret.active = false; FineTickerCancel(tickCaret); InvalidateCaret(); } void Editor::CaretSetPeriod(int period) { if (caret.period != period) { caret.period = period; caret.on = true; FineTickerCancel(tickCaret); if ((caret.active) && (caret.period > 0)) FineTickerStart(tickCaret, caret.period, caret.period/10); InvalidateCaret(); } } void Editor::InvalidateCaret() { if (posDrag.IsValid()) { InvalidateRange(posDrag.Position(), posDrag.Position() + 1); } else { for (size_t r=0; rlines; } return pcs->SetHeight(lineToWrap, linesWrapped + (vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0)); } // Perform wrapping for a subset of the lines needing wrapping. // wsAll: wrap all lines which need wrapping in this single call // wsVisible: wrap currently visible lines // wsIdle: wrap one page + 100 lines // Return true if wrapping occurred. bool Editor::WrapLines(WrapScope ws) { Sci::Line goodTopLine = topLine; bool wrapOccurred = false; if (!Wrapping()) { if (wrapWidth != LineLayout::wrapWidthInfinite) { wrapWidth = LineLayout::wrapWidthInfinite; for (Sci::Line lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) { pcs->SetHeight(lineDoc, 1 + (vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0)); } wrapOccurred = true; } wrapPending.Reset(); } else if (wrapPending.NeedsWrap()) { wrapPending.start = std::min(wrapPending.start, pdoc->LinesTotal()); if (!SetIdle(true)) { // Idle processing not supported so full wrap required. ws = WrapScope::wsAll; } // Decide where to start wrapping Sci::Line lineToWrap = wrapPending.start; Sci::Line lineToWrapEnd = std::min(wrapPending.end, pdoc->LinesTotal()); const Sci::Line lineDocTop = pcs->DocFromDisplay(topLine); const Sci::Line subLineTop = topLine - pcs->DisplayFromDoc(lineDocTop); if (ws == WrapScope::wsVisible) { lineToWrap = Sci::clamp(lineDocTop-5, wrapPending.start, pdoc->LinesTotal()); // Priority wrap to just after visible area. // Since wrapping could reduce display lines, treat each // as taking only one display line. lineToWrapEnd = lineDocTop; Sci::Line lines = LinesOnScreen() + 1; while ((lineToWrapEnd < pcs->LinesInDoc()) && (lines>0)) { if (pcs->GetVisible(lineToWrapEnd)) lines--; lineToWrapEnd++; } // .. and if the paint window is outside pending wraps if ((lineToWrap > wrapPending.end) || (lineToWrapEnd < wrapPending.start)) { // Currently visible text does not need wrapping return false; } } else if (ws == WrapScope::wsIdle) { // Try to keep time taken by wrapping reasonable so interaction remains smooth. const double secondsAllowed = 0.01; const Sci::Line linesInAllowedTime = Sci::clamp( static_cast(secondsAllowed / durationWrapOneLine.Duration()), LinesOnScreen() + 50, static_cast(0x10000)); lineToWrapEnd = lineToWrap + linesInAllowedTime; } const Sci::Line lineEndNeedWrap = std::min(wrapPending.end, pdoc->LinesTotal()); lineToWrapEnd = std::min(lineToWrapEnd, lineEndNeedWrap); // Ensure all lines being wrapped are styled. pdoc->EnsureStyledTo(pdoc->LineStart(lineToWrapEnd)); if (lineToWrap < lineToWrapEnd) { PRectangle rcTextArea = GetClientRectangle(); rcTextArea.left = static_cast(vs.textStart); rcTextArea.right -= vs.rightMarginWidth; wrapWidth = static_cast(rcTextArea.Width()); RefreshStyleData(); AutoSurface surface(this); if (surface) { //Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd); const Sci::Line linesBeingWrapped = lineToWrapEnd - lineToWrap; ElapsedPeriod epWrapping; while (lineToWrap < lineToWrapEnd) { if (WrapOneLine(surface, lineToWrap)) { wrapOccurred = true; } wrapPending.Wrapped(lineToWrap); lineToWrap++; } durationWrapOneLine.AddSample(linesBeingWrapped, epWrapping.Duration()); goodTopLine = pcs->DisplayFromDoc(lineDocTop) + std::min( subLineTop, static_cast(pcs->GetHeight(lineDocTop)-1)); } } // If wrapping is done, bring it to resting position if (wrapPending.start >= lineEndNeedWrap) { wrapPending.Reset(); } } if (wrapOccurred) { SetScrollBars(); SetTopLine(Sci::clamp(goodTopLine, static_cast(0), MaxScrollPos())); SetVerticalScrollPos(); } return wrapOccurred; } void Editor::LinesJoin() { if (!RangeContainsProtected(targetStart, targetEnd)) { UndoGroup ug(pdoc); bool prevNonWS = true; for (Sci::Position pos = targetStart; pos < targetEnd; pos++) { if (pdoc->IsPositionInLineEnd(pos)) { targetEnd -= pdoc->LenChar(pos); pdoc->DelChar(pos); if (prevNonWS) { // Ensure at least one space separating previous lines const Sci::Position lengthInserted = pdoc->InsertString(pos, " ", 1); targetEnd += lengthInserted; } } else { prevNonWS = pdoc->CharAt(pos) != ' '; } } } } const char *Editor::StringFromEOLMode(int eolMode) { if (eolMode == SC_EOL_CRLF) { return "\r\n"; } else if (eolMode == SC_EOL_CR) { return "\r"; } else { return "\n"; } } void Editor::LinesSplit(int pixelWidth) { if (!RangeContainsProtected(targetStart, targetEnd)) { if (pixelWidth == 0) { const PRectangle rcText = GetTextRectangle(); pixelWidth = static_cast(rcText.Width()); } const Sci::Line lineStart = pdoc->SciLineFromPosition(targetStart); Sci::Line lineEnd = pdoc->SciLineFromPosition(targetEnd); const char *eol = StringFromEOLMode(pdoc->eolMode); UndoGroup ug(pdoc); for (Sci::Line line = lineStart; line <= lineEnd; line++) { AutoSurface surface(this); AutoLineLayout ll(view.llc, view.RetrieveLineLayout(line, *this)); if (surface && ll) { const Sci::Position posLineStart = pdoc->LineStart(line); view.LayoutLine(*this, line, surface, vs, ll, pixelWidth); Sci::Position lengthInsertedTotal = 0; for (int subLine = 1; subLine < ll->lines; subLine++) { const Sci::Position lengthInserted = pdoc->InsertString( posLineStart + lengthInsertedTotal + ll->LineStart(subLine), eol, strlen(eol)); targetEnd += lengthInserted; lengthInsertedTotal += lengthInserted; } } lineEnd = pdoc->SciLineFromPosition(targetEnd); } } } void Editor::PaintSelMargin(Surface *surfaceWindow, const PRectangle &rc) { if (vs.fixedColumnWidth == 0) return; AllocateGraphics(); RefreshStyleData(); RefreshPixMaps(surfaceWindow); // On GTK+ with Ubuntu overlay scroll bars, the surface may have been finished // at this point. The Initialised call checks for this case and sets the status // to be bad which avoids crashes in following calls. if (!surfaceWindow->Initialised()) { return; } PRectangle rcMargin = GetClientRectangle(); const Point ptOrigin = GetVisibleOriginInMain(); rcMargin.Move(0, -ptOrigin.y); rcMargin.left = 0; rcMargin.right = static_cast(vs.fixedColumnWidth); if (!rc.Intersects(rcMargin)) return; Surface *surface; if (view.bufferedDraw) { surface = marginView.pixmapSelMargin.get(); } else { surface = surfaceWindow; } // Clip vertically to paint area to avoid drawing line numbers if (rcMargin.bottom > rc.bottom) rcMargin.bottom = rc.bottom; if (rcMargin.top < rc.top) rcMargin.top = rc.top; marginView.PaintMargin(surface, topLine, rc, rcMargin, *this, vs); if (view.bufferedDraw) { surfaceWindow->Copy(rcMargin, Point(rcMargin.left, rcMargin.top), *marginView.pixmapSelMargin); } } void Editor::RefreshPixMaps(Surface *surfaceWindow) { view.RefreshPixMaps(surfaceWindow, wMain.GetID(), vs); marginView.RefreshPixMaps(surfaceWindow, wMain.GetID(), vs); if (view.bufferedDraw) { const PRectangle rcClient = GetClientRectangle(); if (!view.pixmapLine->Initialised()) { view.pixmapLine->InitPixMap(static_cast(rcClient.Width()), vs.lineHeight, surfaceWindow, wMain.GetID()); } if (!marginView.pixmapSelMargin->Initialised()) { marginView.pixmapSelMargin->InitPixMap(vs.fixedColumnWidth, static_cast(rcClient.Height()), surfaceWindow, wMain.GetID()); } } } void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n", // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); AllocateGraphics(); RefreshStyleData(); if (paintState == paintAbandoned) return; // Scroll bars may have changed so need redraw RefreshPixMaps(surfaceWindow); paintAbandonedByStyling = false; StyleAreaBounded(rcArea, false); const PRectangle rcClient = GetClientRectangle(); //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n", // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); if (NotifyUpdateUI()) { RefreshStyleData(); RefreshPixMaps(surfaceWindow); } // Wrap the visible lines if needed. if (WrapLines(WrapScope::wsVisible)) { // The wrapping process has changed the height of some lines so // abandon this paint for a complete repaint. if (AbandonPaint()) { return; } RefreshPixMaps(surfaceWindow); // In case pixmaps invalidated by scrollbar change } PLATFORM_ASSERT(marginView.pixmapSelPattern->Initialised()); if (!view.bufferedDraw) surfaceWindow->SetClip(rcArea); if (paintState != paintAbandoned) { if (vs.marginInside) { PaintSelMargin(surfaceWindow, rcArea); PRectangle rcRightMargin = rcClient; rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth; if (rcArea.Intersects(rcRightMargin)) { surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back); } } else { // Else separate view so separate paint event but leftMargin included to allow overlap PRectangle rcLeftMargin = rcArea; rcLeftMargin.left = 0; rcLeftMargin.right = rcLeftMargin.left + vs.leftMarginWidth; if (rcArea.Intersects(rcLeftMargin)) { surfaceWindow->FillRectangle(rcLeftMargin, vs.styles[STYLE_DEFAULT].back); } } } if (paintState == paintAbandoned) { // Either styling or NotifyUpdateUI noticed that painting is needed // outside the current painting rectangle //Platform::DebugPrintf("Abandoning paint\n"); if (Wrapping()) { if (paintAbandonedByStyling) { // Styling has spilled over a line end, such as occurs by starting a multiline // comment. The width of subsequent text may have changed, so rewrap. NeedWrapping(pcs->DocFromDisplay(topLine)); } } return; } view.PaintText(surfaceWindow, *this, rcArea, rcClient, vs); if (horizontalScrollBarVisible && trackLineWidth && (view.lineWidthMaxSeen > scrollWidth)) { scrollWidth = view.lineWidthMaxSeen; if (!FineTickerRunning(tickWiden)) { FineTickerStart(tickWiden, 50, 5); } } NotifyPainted(); } // This is mostly copied from the Paint method but with some things omitted // such as the margin markers, line numbers, selection and caret // Should be merged back into a combined Draw method. Sci::Position Editor::FormatRange(bool draw, const Sci_RangeToFormat *pfr) { if (!pfr) return 0; AutoSurface surface(pfr->hdc, this, SC_TECHNOLOGY_DEFAULT); if (!surface) return 0; AutoSurface surfaceMeasure(pfr->hdcTarget, this, SC_TECHNOLOGY_DEFAULT); if (!surfaceMeasure) { return 0; } return view.FormatRange(draw, pfr, surface, surfaceMeasure, *this, vs); } int Editor::TextWidth(int style, const char *text) { RefreshStyleData(); AutoSurface surface(this); if (surface) { return static_cast(surface->WidthText(vs.styles[style].font, text, static_cast(strlen(text)))); } else { return 1; } } // Empty method is overridden on GTK+ to show / hide scrollbars void Editor::ReconfigureScrollBars() {} void Editor::SetScrollBars() { RefreshStyleData(); const Sci::Line nMax = MaxScrollPos(); const Sci::Line nPage = LinesOnScreen(); const bool modified = ModifyScrollBars(nMax + nPage - 1, nPage); if (modified) { DwellEnd(true); } // TODO: ensure always showing as many lines as possible // May not be, if, for example, window made larger if (topLine > MaxScrollPos()) { SetTopLine(Sci::clamp(topLine, static_cast(0), MaxScrollPos())); SetVerticalScrollPos(); Redraw(); } if (modified) { if (!AbandonPaint()) Redraw(); } //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage); } void Editor::ChangeSize() { DropGraphics(false); SetScrollBars(); if (Wrapping()) { PRectangle rcTextArea = GetClientRectangle(); rcTextArea.left = static_cast(vs.textStart); rcTextArea.right -= vs.rightMarginWidth; if (wrapWidth != rcTextArea.Width()) { NeedWrapping(); Redraw(); } } } Sci::Position Editor::RealizeVirtualSpace(Sci::Position position, Sci::Position virtualSpace) { if (virtualSpace > 0) { const Sci::Line line = pdoc->SciLineFromPosition(position); const Sci::Position indent = pdoc->GetLineIndentPosition(line); if (indent == position) { return pdoc->SetLineIndentation(line, pdoc->GetLineIndentation(line) + virtualSpace); } else { std::string spaceText(virtualSpace, ' '); const Sci::Position lengthInserted = pdoc->InsertString(position, spaceText.c_str(), virtualSpace); position += lengthInserted; } } return position; } SelectionPosition Editor::RealizeVirtualSpace(const SelectionPosition &position) { // Return the new position with no virtual space return SelectionPosition(RealizeVirtualSpace(position.Position(), position.VirtualSpace())); } void Editor::AddChar(char ch) { char s[2]; s[0] = ch; s[1] = '\0'; AddCharUTF(s, 1); } void Editor::FilterSelections() { if (!additionalSelectionTyping && (sel.Count() > 1)) { InvalidateWholeSelection(); sel.DropAdditionalRanges(); } } // AddCharUTF inserts an array of bytes which may or may not be in UTF-8. void Editor::AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS) { FilterSelections(); { UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike); // Vector elements point into selection in order to change selection. std::vector selPtrs; for (size_t r = 0; r < sel.Count(); r++) { selPtrs.push_back(&sel.Range(r)); } // Order selections by position in document. std::sort(selPtrs.begin(), selPtrs.end(), [](const SelectionRange *a, const SelectionRange *b) {return *a < *b;}); // Loop in reverse to avoid disturbing positions of selections yet to be processed. for (std::vector::reverse_iterator rit = selPtrs.rbegin(); rit != selPtrs.rend(); ++rit) { SelectionRange *currentSel = *rit; if (!RangeContainsProtected(currentSel->Start().Position(), currentSel->End().Position())) { Sci::Position positionInsert = currentSel->Start().Position(); if (!currentSel->Empty()) { if (currentSel->Length()) { pdoc->DeleteChars(positionInsert, currentSel->Length()); currentSel->ClearVirtualSpace(); } else { // Range is all virtual so collapse to start of virtual space currentSel->MinimizeVirtualSpace(); } } else if (inOverstrike) { if (positionInsert < pdoc->Length()) { if (!pdoc->IsPositionInLineEnd(positionInsert)) { pdoc->DelChar(positionInsert); currentSel->ClearVirtualSpace(); } } } positionInsert = RealizeVirtualSpace(positionInsert, currentSel->caret.VirtualSpace()); const Sci::Position lengthInserted = pdoc->InsertString(positionInsert, s, len); if (lengthInserted > 0) { currentSel->caret.SetPosition(positionInsert + lengthInserted); currentSel->anchor.SetPosition(positionInsert + lengthInserted); } currentSel->ClearVirtualSpace(); // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information if (Wrapping()) { AutoSurface surface(this); if (surface) { if (WrapOneLine(surface, pdoc->SciLineFromPosition(positionInsert))) { SetScrollBars(); SetVerticalScrollPos(); Redraw(); } } } } } } if (Wrapping()) { SetScrollBars(); } ThinRectangularRange(); // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information EnsureCaretVisible(); // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); if ((caretSticky == SC_CARETSTICKY_OFF) || ((caretSticky == SC_CARETSTICKY_WHITESPACE) && !IsAllSpacesOrTabs(s, len))) { SetLastXChosen(); } if (treatAsDBCS) { NotifyChar((static_cast(s[0]) << 8) | static_cast(s[1])); } else if (len > 0) { int byte = static_cast(s[0]); if ((byte < 0xC0) || (1 == len)) { // Handles UTF-8 characters between 0x01 and 0x7F and single byte // characters when not in UTF-8 mode. // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid // characters representing themselves. } else { unsigned int utf32[1] = { 0 }; UTF32FromUTF8(s, len, utf32, ELEMENTS(utf32)); byte = utf32[0]; } NotifyChar(byte); } if (recordingMacro) { NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast(s)); } } void Editor::ClearBeforeTentativeStart() { // Make positions for the first composition string. FilterSelections(); UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike); for (size_t r = 0; rDeleteChars(positionInsert, sel.Range(r).Length()); sel.Range(r).ClearVirtualSpace(); } else { // Range is all virtual so collapse to start of virtual space sel.Range(r).MinimizeVirtualSpace(); } } RealizeVirtualSpace(positionInsert, sel.Range(r).caret.VirtualSpace()); sel.Range(r).ClearVirtualSpace(); } } } void Editor::InsertPaste(const char *text, Sci::Position len) { if (multiPasteMode == SC_MULTIPASTE_ONCE) { SelectionPosition selStart = sel.Start(); selStart = RealizeVirtualSpace(selStart); const Sci::Position lengthInserted = pdoc->InsertString(selStart.Position(), text, len); if (lengthInserted > 0) { SetEmptySelection(selStart.Position() + lengthInserted); } } else { // SC_MULTIPASTE_EACH for (size_t r=0; rDeleteChars(positionInsert, sel.Range(r).Length()); sel.Range(r).ClearVirtualSpace(); } else { // Range is all virtual so collapse to start of virtual space sel.Range(r).MinimizeVirtualSpace(); } } positionInsert = RealizeVirtualSpace(positionInsert, sel.Range(r).caret.VirtualSpace()); const Sci::Position lengthInserted = pdoc->InsertString(positionInsert, text, len); if (lengthInserted > 0) { sel.Range(r).caret.SetPosition(positionInsert + lengthInserted); sel.Range(r).anchor.SetPosition(positionInsert + lengthInserted); } sel.Range(r).ClearVirtualSpace(); } } } } void Editor::InsertPasteShape(const char *text, Sci::Position len, PasteShape shape) { std::string convertedText; if (convertPastes) { // Convert line endings of the paste into our local line-endings mode convertedText = Document::TransformLineEnds(text, len, pdoc->eolMode); len = convertedText.length(); text = convertedText.c_str(); } if (shape == pasteRectangular) { PasteRectangular(sel.Start(), text, len); } else { if (shape == pasteLine) { const Sci::Position insertPos = pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())); Sci::Position lengthInserted = pdoc->InsertString(insertPos, text, len); // add the newline if necessary if ((len > 0) && (text[len - 1] != '\n' && text[len - 1] != '\r')) { const char *endline = StringFromEOLMode(pdoc->eolMode); const Sci::Position length = strlen(endline); lengthInserted += pdoc->InsertString(insertPos + lengthInserted, endline, length); } if (sel.MainCaret() == insertPos) { SetEmptySelection(sel.MainCaret() + lengthInserted); } } else { InsertPaste(text, len); } } } void Editor::ClearSelection(bool retainMultipleSelections) { if (!sel.IsRectangular() && !retainMultipleSelections) FilterSelections(); UndoGroup ug(pdoc); for (size_t r=0; rDeleteChars(sel.Range(r).Start().Position(), sel.Range(r).Length()); sel.Range(r) = SelectionRange(sel.Range(r).Start()); } } } ThinRectangularRange(); sel.RemoveDuplicates(); ClaimSelection(); SetHoverIndicatorPosition(sel.MainCaret()); } void Editor::ClearAll() { { UndoGroup ug(pdoc); if (0 != pdoc->Length()) { pdoc->DeleteChars(0, pdoc->Length()); } if (!pdoc->IsReadOnly()) { pcs->Clear(); pdoc->AnnotationClearAll(); pdoc->MarginClearAll(); } } view.ClearAllTabstops(); sel.Clear(); SetTopLine(0); SetVerticalScrollPos(); InvalidateStyleRedraw(); } void Editor::ClearDocumentStyle() { pdoc->decorations->DeleteLexerDecorations(); pdoc->StartStyling(0, '\377'); pdoc->SetStyleFor(pdoc->Length(), 0); pcs->ShowAll(); SetAnnotationHeights(0, pdoc->LinesTotal()); pdoc->ClearLevels(); } void Editor::CopyAllowLine() { SelectionText selectedText; CopySelectionRange(&selectedText, true); CopyToClipboard(selectedText); } void Editor::Cut() { pdoc->CheckReadOnly(); if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) { Copy(); ClearSelection(); } } void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, Sci::Position len) { if (pdoc->IsReadOnly() || SelectionContainsProtected()) { return; } sel.Clear(); sel.RangeMain() = SelectionRange(pos); Sci::Line line = pdoc->SciLineFromPosition(sel.MainCaret()); UndoGroup ug(pdoc); sel.RangeMain().caret = RealizeVirtualSpace(sel.RangeMain().caret); const int xInsert = XFromPosition(sel.RangeMain().caret); bool prevCr = false; while ((len > 0) && IsEOLChar(ptr[len-1])) len--; for (Sci::Position i = 0; i < len; i++) { if (IsEOLChar(ptr[i])) { if ((ptr[i] == '\r') || (!prevCr)) line++; if (line >= pdoc->LinesTotal()) { if (pdoc->eolMode != SC_EOL_LF) pdoc->InsertString(pdoc->Length(), "\r", 1); if (pdoc->eolMode != SC_EOL_CR) pdoc->InsertString(pdoc->Length(), "\n", 1); } // Pad the end of lines with spaces if required sel.RangeMain().caret.SetPosition(PositionFromLineX(line, xInsert)); if ((XFromPosition(sel.RangeMain().caret) < xInsert) && (i + 1 < len)) { while (XFromPosition(sel.RangeMain().caret) < xInsert) { assert(pdoc); const Sci::Position lengthInserted = pdoc->InsertString(sel.MainCaret(), " ", 1); sel.RangeMain().caret.Add(lengthInserted); } } prevCr = ptr[i] == '\r'; } else { const Sci::Position lengthInserted = pdoc->InsertString(sel.MainCaret(), ptr + i, 1); sel.RangeMain().caret.Add(lengthInserted); prevCr = false; } } SetEmptySelection(pos); } bool Editor::CanPaste() { return !pdoc->IsReadOnly() && !SelectionContainsProtected(); } void Editor::Clear() { // If multiple selections, don't delete EOLS if (sel.Empty()) { bool singleVirtual = false; if ((sel.Count() == 1) && !RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1) && sel.RangeMain().Start().VirtualSpace()) { singleVirtual = true; } UndoGroup ug(pdoc, (sel.Count() > 1) || singleVirtual); for (size_t r=0; rIsPositionInLineEnd(sel.Range(r).caret.Position())) { pdoc->DelChar(sel.Range(r).caret.Position()); sel.Range(r).ClearVirtualSpace(); } // else multiple selection so don't eat line ends } else { sel.Range(r).ClearVirtualSpace(); } } } else { ClearSelection(); } sel.RemoveDuplicates(); ShowCaretAtCurrentPosition(); // Avoid blinking } void Editor::SelectAll() { sel.Clear(); SetSelection(0, pdoc->Length()); Redraw(); } void Editor::Undo() { if (pdoc->CanUndo()) { InvalidateCaret(); const Sci::Position newPos = pdoc->Undo(); if (newPos >= 0) SetEmptySelection(newPos); EnsureCaretVisible(); } } void Editor::Redo() { if (pdoc->CanRedo()) { const Sci::Position newPos = pdoc->Redo(); if (newPos >= 0) SetEmptySelection(newPos); EnsureCaretVisible(); } } void Editor::DelCharBack(bool allowLineStartDeletion) { RefreshStyleData(); if (!sel.IsRectangular()) FilterSelections(); if (sel.IsRectangular()) allowLineStartDeletion = false; UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty()); if (sel.Empty()) { for (size_t r=0; rSciLineFromPosition(sel.Range(r).caret.Position()); if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.Range(r).caret.Position())) { if (pdoc->GetColumn(sel.Range(r).caret.Position()) <= pdoc->GetLineIndentation(lineCurrentPos) && pdoc->GetColumn(sel.Range(r).caret.Position()) > 0 && pdoc->backspaceUnindents) { UndoGroup ugInner(pdoc, !ug.Needed()); const int indentation = pdoc->GetLineIndentation(lineCurrentPos); const int indentationStep = pdoc->IndentSize(); int indentationChange = indentation % indentationStep; if (indentationChange == 0) indentationChange = indentationStep; const Sci::Position posSelect = pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationChange); // SetEmptySelection sel.Range(r) = SelectionRange(posSelect); } else { pdoc->DelCharBack(sel.Range(r).caret.Position()); } } } } else { sel.Range(r).ClearVirtualSpace(); } } ThinRectangularRange(); } else { ClearSelection(); } sel.RemoveDuplicates(); ContainerNeedsUpdate(SC_UPDATE_SELECTION); // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); } int Editor::ModifierFlags(bool shift, bool ctrl, bool alt, bool meta, bool super) noexcept { return (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0) | (meta ? SCI_META : 0) | (super ? SCI_SUPER : 0); } void Editor::NotifyFocus(bool focus) { SCNotification scn = {}; scn.nmhdr.code = focus ? SCN_FOCUSIN : SCN_FOCUSOUT; NotifyParent(scn); } void Editor::SetCtrlID(int identifier) { ctrlID = identifier; } void Editor::NotifyStyleToNeeded(Sci::Position endStyleNeeded) { SCNotification scn = {}; scn.nmhdr.code = SCN_STYLENEEDED; scn.position = endStyleNeeded; NotifyParent(scn); } void Editor::NotifyStyleNeeded(Document *, void *, Sci::Position endStyleNeeded) { NotifyStyleToNeeded(endStyleNeeded); } void Editor::NotifyLexerChanged(Document *, void *) { } void Editor::NotifyErrorOccurred(Document *, void *, int status) { errorStatus = status; } void Editor::NotifyChar(int ch) { SCNotification scn = {}; scn.nmhdr.code = SCN_CHARADDED; scn.ch = ch; NotifyParent(scn); } void Editor::NotifySavePoint(bool isSavePoint) { SCNotification scn = {}; if (isSavePoint) { scn.nmhdr.code = SCN_SAVEPOINTREACHED; } else { scn.nmhdr.code = SCN_SAVEPOINTLEFT; } NotifyParent(scn); } void Editor::NotifyModifyAttempt() { SCNotification scn = {}; scn.nmhdr.code = SCN_MODIFYATTEMPTRO; NotifyParent(scn); } void Editor::NotifyDoubleClick(Point pt, int modifiers) { SCNotification scn = {}; scn.nmhdr.code = SCN_DOUBLECLICK; scn.line = LineFromLocation(pt); scn.position = PositionFromLocation(pt, true); scn.modifiers = modifiers; NotifyParent(scn); } void Editor::NotifyHotSpotDoubleClicked(Sci::Position position, int modifiers) { SCNotification scn = {}; scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK; scn.position = position; scn.modifiers = modifiers; NotifyParent(scn); } void Editor::NotifyHotSpotClicked(Sci::Position position, int modifiers) { SCNotification scn = {}; scn.nmhdr.code = SCN_HOTSPOTCLICK; scn.position = position; scn.modifiers = modifiers; NotifyParent(scn); } void Editor::NotifyHotSpotReleaseClick(Sci::Position position, int modifiers) { SCNotification scn = {}; scn.nmhdr.code = SCN_HOTSPOTRELEASECLICK; scn.position = position; scn.modifiers = modifiers; NotifyParent(scn); } bool Editor::NotifyUpdateUI() { if (needUpdateUI) { SCNotification scn = {}; scn.nmhdr.code = SCN_UPDATEUI; scn.updated = needUpdateUI; NotifyParent(scn); needUpdateUI = 0; return true; } return false; } void Editor::NotifyPainted() { SCNotification scn = {}; scn.nmhdr.code = SCN_PAINTED; NotifyParent(scn); } void Editor::NotifyIndicatorClick(bool click, Sci::Position position, int modifiers) { const int mask = pdoc->decorations->AllOnFor(position); if ((click && mask) || pdoc->decorations->ClickNotified()) { SCNotification scn = {}; pdoc->decorations->SetClickNotified(click); scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE; scn.modifiers = modifiers; scn.position = position; NotifyParent(scn); } } bool Editor::NotifyMarginClick(Point pt, int modifiers) { const int marginClicked = vs.MarginFromLocation(pt); if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) { const Sci::Position position = pdoc->LineStart(LineFromLocation(pt)); if ((vs.ms[marginClicked].mask & SC_MASK_FOLDERS) && (foldAutomatic & SC_AUTOMATICFOLD_CLICK)) { const bool ctrl = (modifiers & SCI_CTRL) != 0; const bool shift = (modifiers & SCI_SHIFT) != 0; const Sci::Line lineClick = pdoc->SciLineFromPosition(position); if (shift && ctrl) { FoldAll(SC_FOLDACTION_TOGGLE); } else { const int levelClick = pdoc->GetLevel(lineClick); if (levelClick & SC_FOLDLEVELHEADERFLAG) { if (shift) { // Ensure all children visible FoldExpand(lineClick, SC_FOLDACTION_EXPAND, levelClick); } else if (ctrl) { FoldExpand(lineClick, SC_FOLDACTION_TOGGLE, levelClick); } else { // Toggle this line FoldLine(lineClick, SC_FOLDACTION_TOGGLE); } } } return true; } SCNotification scn = {}; scn.nmhdr.code = SCN_MARGINCLICK; scn.modifiers = modifiers; scn.position = position; scn.margin = marginClicked; NotifyParent(scn); return true; } else { return false; } } bool Editor::NotifyMarginRightClick(Point pt, int modifiers) { const int marginRightClicked = vs.MarginFromLocation(pt); if ((marginRightClicked >= 0) && vs.ms[marginRightClicked].sensitive) { const Sci::Position position = pdoc->LineStart(LineFromLocation(pt)); SCNotification scn = {}; scn.nmhdr.code = SCN_MARGINRIGHTCLICK; scn.modifiers = modifiers; scn.position = position; scn.margin = marginRightClicked; NotifyParent(scn); return true; } else { return false; } } void Editor::NotifyNeedShown(Sci::Position pos, Sci::Position len) { SCNotification scn = {}; scn.nmhdr.code = SCN_NEEDSHOWN; scn.position = pos; scn.length = len; NotifyParent(scn); } void Editor::NotifyDwelling(Point pt, bool state) { SCNotification scn = {}; scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND; scn.position = PositionFromLocation(pt, true); scn.x = static_cast(pt.x + vs.ExternalMarginWidth()); scn.y = static_cast(pt.y); NotifyParent(scn); } void Editor::NotifyZoom() { SCNotification scn = {}; scn.nmhdr.code = SCN_ZOOM; NotifyParent(scn); } // Notifications from document void Editor::NotifyModifyAttempt(Document *, void *) { //Platform::DebugPrintf("** Modify Attempt\n"); NotifyModifyAttempt(); } void Editor::NotifySavePoint(Document *, void *, bool atSavePoint) { //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off"); NotifySavePoint(atSavePoint); } void Editor::CheckModificationForWrap(DocModification mh) { if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { view.llc.Invalidate(LineLayout::llCheckTextAndStyle); const Sci::Line lineDoc = pdoc->SciLineFromPosition(mh.position); const Sci::Line lines = std::max(static_cast(0), mh.linesAdded); if (Wrapping()) { NeedWrapping(lineDoc, lineDoc + lines + 1); } RefreshStyleData(); // Fix up annotation heights SetAnnotationHeights(lineDoc, lineDoc + lines + 2); } } // Move a position so it is still after the same character as before the insertion. static inline Sci::Position MovePositionForInsertion(Sci::Position position, Sci::Position startInsertion, Sci::Position length) { if (position > startInsertion) { return position + length; } return position; } // Move a position so it is still after the same character as before the deletion if that // character is still present else after the previous surviving character. static inline Sci::Position MovePositionForDeletion(Sci::Position position, Sci::Position startDeletion, Sci::Position length) { if (position > startDeletion) { const Sci::Position endDeletion = startDeletion + length; if (position > endDeletion) { return position - length; } else { return startDeletion; } } else { return position; } } void Editor::NotifyModified(Document *, DocModification mh, void *) { ContainerNeedsUpdate(SC_UPDATE_CONTENT); if (paintState == painting) { CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length)); } if (mh.modificationType & SC_MOD_CHANGELINESTATE) { if (paintState == painting) { CheckForChangeOutsidePaint( Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1))); } else { // Could check that change is before last visible line. Redraw(); } } if (mh.modificationType & SC_MOD_CHANGETABSTOPS) { Redraw(); } if (mh.modificationType & SC_MOD_LEXERSTATE) { if (paintState == painting) { CheckForChangeOutsidePaint( Range(mh.position, mh.position + mh.length)); } else { Redraw(); } } if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) { if (mh.modificationType & SC_MOD_CHANGESTYLE) { pdoc->IncrementStyleClock(); } if (paintState == notPainting) { const Sci::Line lineDocTop = pcs->DocFromDisplay(topLine); if (mh.position < pdoc->LineStart(lineDocTop)) { // Styling performed before this view Redraw(); } else { InvalidateRange(mh.position, mh.position + mh.length); } } if (mh.modificationType & SC_MOD_CHANGESTYLE) { view.llc.Invalidate(LineLayout::llCheckTextAndStyle); } } else { // Move selection and brace highlights if (mh.modificationType & SC_MOD_INSERTTEXT) { sel.MovePositions(true, mh.position, mh.length); braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length); braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length); } else if (mh.modificationType & SC_MOD_DELETETEXT) { sel.MovePositions(false, mh.position, mh.length); braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length); braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length); } if ((mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) && pcs->HiddenLines()) { // Some lines are hidden so may need shown. const Sci::Line lineOfPos = pdoc->SciLineFromPosition(mh.position); Sci::Position endNeedShown = mh.position; if (mh.modificationType & SC_MOD_BEFOREINSERT) { if (pdoc->ContainsLineEnd(mh.text, mh.length) && (mh.position != pdoc->LineStart(lineOfPos))) endNeedShown = pdoc->LineStart(lineOfPos+1); } else if (mh.modificationType & SC_MOD_BEFOREDELETE) { // If the deletion includes any EOL then we extend the need shown area. endNeedShown = mh.position + mh.length; Sci::Line lineLast = pdoc->SciLineFromPosition(mh.position+mh.length); for (Sci::Line line = lineOfPos + 1; line <= lineLast; line++) { const Sci::Line lineMaxSubord = pdoc->GetLastChild(line, -1, -1); if (lineLast < lineMaxSubord) { lineLast = lineMaxSubord; endNeedShown = pdoc->LineEnd(lineLast); } } } NeedShown(mh.position, endNeedShown - mh.position); } if (mh.linesAdded != 0) { // Update contraction state for inserted and removed lines // lineOfPos should be calculated in context of state before modification, shouldn't it Sci::Line lineOfPos = pdoc->SciLineFromPosition(mh.position); if (mh.position > pdoc->LineStart(lineOfPos)) lineOfPos++; // Affecting subsequent lines if (mh.linesAdded > 0) { pcs->InsertLines(lineOfPos, mh.linesAdded); } else { pcs->DeleteLines(lineOfPos, -mh.linesAdded); } view.LinesAddedOrRemoved(lineOfPos, mh.linesAdded); } if (mh.modificationType & SC_MOD_CHANGEANNOTATION) { const Sci::Line lineDoc = pdoc->SciLineFromPosition(mh.position); if (vs.annotationVisible) { if (pcs->SetHeight(lineDoc, pcs->GetHeight(lineDoc) + static_cast(mh.annotationLinesAdded))) { SetScrollBars(); } Redraw(); } } CheckModificationForWrap(mh); if (mh.linesAdded != 0) { // Avoid scrolling of display if change before current display if (mh.position < posTopLine && !CanDeferToLastStep(mh)) { const Sci::Line newTop = Sci::clamp(topLine + mh.linesAdded, static_cast(0), MaxScrollPos()); if (newTop != topLine) { SetTopLine(newTop); SetVerticalScrollPos(); } } if (paintState == notPainting && !CanDeferToLastStep(mh)) { QueueIdleWork(WorkNeeded::workStyle, pdoc->Length()); Redraw(); } } else { if (paintState == notPainting && mh.length && !CanEliminate(mh)) { QueueIdleWork(WorkNeeded::workStyle, mh.position + mh.length); InvalidateRange(mh.position, mh.position + mh.length); } } } if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) { SetScrollBars(); } if ((mh.modificationType & SC_MOD_CHANGEMARKER) || (mh.modificationType & SC_MOD_CHANGEMARGIN)) { if ((!willRedrawAll) && ((paintState == notPainting) || !PaintContainsMargin())) { if (mh.modificationType & SC_MOD_CHANGEFOLD) { // Fold changes can affect the drawing of following lines so redraw whole margin RedrawSelMargin(marginView.highlightDelimiter.isEnabled ? -1 : mh.line - 1, true); } else { RedrawSelMargin(mh.line); } } } if ((mh.modificationType & SC_MOD_CHANGEFOLD) && (foldAutomatic & SC_AUTOMATICFOLD_CHANGE)) { FoldChanged(mh.line, mh.foldLevelNow, mh.foldLevelPrev); } // NOW pay the piper WRT "deferred" visual updates if (IsLastStep(mh)) { SetScrollBars(); Redraw(); } // If client wants to see this modification if (mh.modificationType & modEventMask) { if (commandEvents) { if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) { // Real modification made to text of document. NotifyChange(); // Send EN_CHANGE } } SCNotification scn = {}; scn.nmhdr.code = SCN_MODIFIED; scn.position = mh.position; scn.modificationType = mh.modificationType; scn.text = mh.text; scn.length = mh.length; scn.linesAdded = mh.linesAdded; scn.line = mh.line; scn.foldLevelNow = mh.foldLevelNow; scn.foldLevelPrev = mh.foldLevelPrev; scn.token = static_cast(mh.token); scn.annotationLinesAdded = mh.annotationLinesAdded; NotifyParent(scn); } } void Editor::NotifyDeleted(Document *, void *) { /* Do nothing */ } void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { // Enumerates all macroable messages switch (iMessage) { case SCI_CUT: case SCI_COPY: case SCI_PASTE: case SCI_CLEAR: case SCI_REPLACESEL: case SCI_ADDTEXT: case SCI_INSERTTEXT: case SCI_APPENDTEXT: case SCI_CLEARALL: case SCI_SELECTALL: case SCI_GOTOLINE: case SCI_GOTOPOS: case SCI_SEARCHANCHOR: case SCI_SEARCHNEXT: case SCI_SEARCHPREV: case SCI_LINEDOWN: case SCI_LINEDOWNEXTEND: case SCI_PARADOWN: case SCI_PARADOWNEXTEND: case SCI_LINEUP: case SCI_LINEUPEXTEND: case SCI_PARAUP: case SCI_PARAUPEXTEND: case SCI_CHARLEFT: case SCI_CHARLEFTEXTEND: case SCI_CHARRIGHT: case SCI_CHARRIGHTEXTEND: case SCI_WORDLEFT: case SCI_WORDLEFTEXTEND: case SCI_WORDRIGHT: case SCI_WORDRIGHTEXTEND: case SCI_WORDPARTLEFT: case SCI_WORDPARTLEFTEXTEND: case SCI_WORDPARTRIGHT: case SCI_WORDPARTRIGHTEXTEND: case SCI_WORDLEFTEND: case SCI_WORDLEFTENDEXTEND: case SCI_WORDRIGHTEND: case SCI_WORDRIGHTENDEXTEND: case SCI_HOME: case SCI_HOMEEXTEND: case SCI_LINEEND: case SCI_LINEENDEXTEND: case SCI_HOMEWRAP: case SCI_HOMEWRAPEXTEND: case SCI_LINEENDWRAP: case SCI_LINEENDWRAPEXTEND: case SCI_DOCUMENTSTART: case SCI_DOCUMENTSTARTEXTEND: case SCI_DOCUMENTEND: case SCI_DOCUMENTENDEXTEND: case SCI_STUTTEREDPAGEUP: case SCI_STUTTEREDPAGEUPEXTEND: case SCI_STUTTEREDPAGEDOWN: case SCI_STUTTEREDPAGEDOWNEXTEND: case SCI_PAGEUP: case SCI_PAGEUPEXTEND: case SCI_PAGEDOWN: case SCI_PAGEDOWNEXTEND: case SCI_EDITTOGGLEOVERTYPE: case SCI_CANCEL: case SCI_DELETEBACK: case SCI_TAB: case SCI_BACKTAB: case SCI_FORMFEED: case SCI_VCHOME: case SCI_VCHOMEEXTEND: case SCI_VCHOMEWRAP: case SCI_VCHOMEWRAPEXTEND: case SCI_VCHOMEDISPLAY: case SCI_VCHOMEDISPLAYEXTEND: case SCI_DELWORDLEFT: case SCI_DELWORDRIGHT: case SCI_DELWORDRIGHTEND: case SCI_DELLINELEFT: case SCI_DELLINERIGHT: case SCI_LINECOPY: case SCI_LINECUT: case SCI_LINEDELETE: case SCI_LINETRANSPOSE: case SCI_LINEREVERSE: case SCI_LINEDUPLICATE: case SCI_LOWERCASE: case SCI_UPPERCASE: case SCI_LINESCROLLDOWN: case SCI_LINESCROLLUP: case SCI_DELETEBACKNOTLINE: case SCI_HOMEDISPLAY: case SCI_HOMEDISPLAYEXTEND: case SCI_LINEENDDISPLAY: case SCI_LINEENDDISPLAYEXTEND: case SCI_SETSELECTIONMODE: case SCI_LINEDOWNRECTEXTEND: case SCI_LINEUPRECTEXTEND: case SCI_CHARLEFTRECTEXTEND: case SCI_CHARRIGHTRECTEXTEND: case SCI_HOMERECTEXTEND: case SCI_VCHOMERECTEXTEND: case SCI_LINEENDRECTEXTEND: case SCI_PAGEUPRECTEXTEND: case SCI_PAGEDOWNRECTEXTEND: case SCI_SELECTIONDUPLICATE: case SCI_COPYALLOWLINE: case SCI_VERTICALCENTRECARET: case SCI_MOVESELECTEDLINESUP: case SCI_MOVESELECTEDLINESDOWN: case SCI_SCROLLTOSTART: case SCI_SCROLLTOEND: break; // Filter out all others like display changes. Also, newlines are redundant // with char insert messages. case SCI_NEWLINE: default: // printf("Filtered out %ld of macro recording\n", iMessage); return; } // Send notification SCNotification scn = {}; scn.nmhdr.code = SCN_MACRORECORD; scn.message = iMessage; scn.wParam = wParam; scn.lParam = lParam; NotifyParent(scn); } // Something has changed that the container should know about void Editor::ContainerNeedsUpdate(int flags) { needUpdateUI |= flags; } /** * Force scroll and keep position relative to top of window. * * If stuttered = true and not already at first/last row, move to first/last row of window. * If stuttered = true and already at first/last row, scroll as normal. */ void Editor::PageMove(int direction, Selection::selTypes selt, bool stuttered) { Sci::Line topLineNew; SelectionPosition newPos; const Sci::Line currentLine = pdoc->SciLineFromPosition(sel.MainCaret()); const Sci::Line topStutterLine = topLine + caretYSlop; const Sci::Line bottomStutterLine = pdoc->SciLineFromPosition(PositionFromLocation( Point::FromInts(lastXChosen - xOffset, direction * vs.lineHeight * static_cast(LinesToScroll())))) - caretYSlop - 1; if (stuttered && (direction < 0 && currentLine > topStutterLine)) { topLineNew = topLine; newPos = SPositionFromLocation(Point::FromInts(lastXChosen - xOffset, vs.lineHeight * caretYSlop), false, false, UserVirtualSpace()); } else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) { topLineNew = topLine; newPos = SPositionFromLocation(Point::FromInts(lastXChosen - xOffset, vs.lineHeight * static_cast(LinesToScroll() - caretYSlop)), false, false, UserVirtualSpace()); } else { const Point pt = LocationFromPosition(sel.MainCaret()); topLineNew = Sci::clamp( topLine + direction * LinesToScroll(), static_cast(0), MaxScrollPos()); newPos = SPositionFromLocation( Point::FromInts(lastXChosen - xOffset, static_cast(pt.y) + direction * (vs.lineHeight * static_cast(LinesToScroll()))), false, false, UserVirtualSpace()); } if (topLineNew != topLine) { SetTopLine(topLineNew); MovePositionTo(newPos, selt); Redraw(); SetVerticalScrollPos(); } else { MovePositionTo(newPos, selt); } } void Editor::ChangeCaseOfSelection(int caseMapping) { UndoGroup ug(pdoc); for (size_t r=0; r 0) { std::string sText = RangeText(currentNoVS.Start().Position(), currentNoVS.End().Position()); std::string sMapped = CaseMapString(sText, caseMapping); if (sMapped != sText) { size_t firstDifference = 0; while (sMapped[firstDifference] == sText[firstDifference]) firstDifference++; size_t lastDifferenceText = sText.size() - 1; size_t lastDifferenceMapped = sMapped.size() - 1; while (sMapped[lastDifferenceMapped] == sText[lastDifferenceText]) { lastDifferenceText--; lastDifferenceMapped--; } const size_t endDifferenceText = sText.size() - 1 - lastDifferenceText; pdoc->DeleteChars( currentNoVS.Start().Position() + firstDifference, rangeBytes - firstDifference - endDifferenceText); const Sci::Position lengthChange = lastDifferenceMapped - firstDifference + 1; const Sci::Position lengthInserted = pdoc->InsertString( currentNoVS.Start().Position() + firstDifference, sMapped.c_str() + firstDifference, lengthChange); // Automatic movement changes selection so reset to exactly the same as it was. const Sci::Position diffSizes = sMapped.size() - sText.size() + lengthInserted - lengthChange; if (diffSizes != 0) { if (current.anchor > current.caret) current.anchor.Add(diffSizes); else current.caret.Add(diffSizes); } sel.Range(r) = current; } } } } void Editor::LineTranspose() { const Sci::Line line = pdoc->SciLineFromPosition(sel.MainCaret()); if (line > 0) { UndoGroup ug(pdoc); const Sci::Position startPrevious = pdoc->LineStart(line - 1); const std::string linePrevious = RangeText(startPrevious, pdoc->LineEnd(line - 1)); Sci::Position startCurrent = pdoc->LineStart(line); const std::string lineCurrent = RangeText(startCurrent, pdoc->LineEnd(line)); pdoc->DeleteChars(startCurrent, lineCurrent.length()); pdoc->DeleteChars(startPrevious, linePrevious.length()); startCurrent -= linePrevious.length(); startCurrent += pdoc->InsertString(startPrevious, lineCurrent.c_str(), lineCurrent.length()); pdoc->InsertString(startCurrent, linePrevious.c_str(), linePrevious.length()); // Move caret to start of current line MovePositionTo(SelectionPosition(startCurrent)); } } void Editor::LineReverse() { const Sci::Line lineStart = pdoc->SciLineFromPosition(sel.RangeMain().Start().Position()); const Sci::Line lineEnd = pdoc->SciLineFromPosition(sel.RangeMain().End().Position()-1); const Sci::Line lineDiff = lineEnd - lineStart; if (lineDiff <= 0) return; UndoGroup ug(pdoc); for (Sci::Line i=(lineDiff+1)/2-1; i>=0; --i) { const Sci::Line lineNum2 = lineEnd - i; const Sci::Line lineNum1 = lineStart + i; Sci::Position lineStart2 = pdoc->LineStart(lineNum2); const Sci::Position lineStart1 = pdoc->LineStart(lineNum1); const std::string line2 = RangeText(lineStart2, pdoc->LineEnd(lineNum2)); const std::string line1 = RangeText(lineStart1, pdoc->LineEnd(lineNum1)); const Sci::Position lineLen2 = line2.length(); const Sci::Position lineLen1 = line1.length(); pdoc->DeleteChars(lineStart2, lineLen2); pdoc->DeleteChars(lineStart1, lineLen1); lineStart2 -= lineLen1; pdoc->InsertString(lineStart2, line1.c_str(), lineLen1); pdoc->InsertString(lineStart1, line2.c_str(), lineLen2); } // Wholly select all affected lines sel.RangeMain() = SelectionRange(pdoc->LineStart(lineStart), pdoc->LineStart(lineEnd+1)); } void Editor::Duplicate(bool forLine) { if (sel.Empty()) { forLine = true; } UndoGroup ug(pdoc); const char *eol = ""; Sci::Position eolLen = 0; if (forLine) { eol = StringFromEOLMode(pdoc->eolMode); eolLen = strlen(eol); } for (size_t r=0; rSciLineFromPosition(sel.Range(r).caret.Position()); start = SelectionPosition(pdoc->LineStart(line)); end = SelectionPosition(pdoc->LineEnd(line)); } std::string text = RangeText(start.Position(), end.Position()); Sci::Position lengthInserted = eolLen; if (forLine) lengthInserted = pdoc->InsertString(end.Position(), eol, eolLen); pdoc->InsertString(end.Position() + lengthInserted, text.c_str(), text.length()); } if (sel.Count() && sel.IsRectangular()) { SelectionPosition last = sel.Last(); if (forLine) { const Sci::Line line = pdoc->SciLineFromPosition(last.Position()); last = SelectionPosition(last.Position() + pdoc->LineStart(line+1) - pdoc->LineStart(line)); } if (sel.Rectangular().anchor > sel.Rectangular().caret) sel.Rectangular().anchor = last; else sel.Rectangular().caret = last; SetRectangularRange(); } } void Editor::CancelModes() { sel.SetMoveExtends(false); } void Editor::NewLine() { InvalidateWholeSelection(); if (sel.IsRectangular() || !additionalSelectionTyping) { // Remove non-main ranges sel.DropAdditionalRanges(); } UndoGroup ug(pdoc, !sel.Empty() || (sel.Count() > 1)); // Clear each range if (!sel.Empty()) { ClearSelection(); } // Insert each line end size_t countInsertions = 0; for (size_t r = 0; r < sel.Count(); r++) { sel.Range(r).ClearVirtualSpace(); const char *eol = StringFromEOLMode(pdoc->eolMode); const Sci::Position positionInsert = sel.Range(r).caret.Position(); const Sci::Position insertLength = pdoc->InsertString(positionInsert, eol, strlen(eol)); if (insertLength > 0) { sel.Range(r) = SelectionRange(positionInsert + insertLength); countInsertions++; } } // Perform notifications after all the changes as the application may change the // selections in response to the characters. for (size_t i = 0; i < countInsertions; i++) { const char *eol = StringFromEOLMode(pdoc->eolMode); while (*eol) { NotifyChar(*eol); if (recordingMacro) { char txt[2]; txt[0] = *eol; txt[1] = '\0'; NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast(txt)); } eol++; } } SetLastXChosen(); SetScrollBars(); EnsureCaretVisible(); // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); } SelectionPosition Editor::PositionUpOrDown(SelectionPosition spStart, int direction, int lastX) { const Point pt = LocationFromPosition(spStart); int skipLines = 0; if (vs.annotationVisible) { const Sci::Line lineDoc = pdoc->SciLineFromPosition(spStart.Position()); const Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc)); const int subLine = static_cast(pt.y - ptStartLine.y) / vs.lineHeight; if (direction < 0 && subLine == 0) { const Sci::Line lineDisplay = pcs->DisplayFromDoc(lineDoc); if (lineDisplay > 0) { skipLines = pdoc->AnnotationLines(pcs->DocFromDisplay(lineDisplay - 1)); } } else if (direction > 0 && subLine >= (pcs->GetHeight(lineDoc) - 1 - pdoc->AnnotationLines(lineDoc))) { skipLines = pdoc->AnnotationLines(lineDoc); } } const Sci::Line newY = static_cast(pt.y) + (1 + skipLines) * direction * vs.lineHeight; if (lastX < 0) { lastX = static_cast(pt.x) + xOffset; } SelectionPosition posNew = SPositionFromLocation( Point::FromInts(lastX - xOffset, static_cast(newY)), false, false, UserVirtualSpace()); if (direction < 0) { // Line wrapping may lead to a location on the same line, so // seek back if that is the case. Point ptNew = LocationFromPosition(posNew.Position()); while ((posNew.Position() > 0) && (pt.y == ptNew.y)) { posNew.Add(-1); posNew.SetVirtualSpace(0); ptNew = LocationFromPosition(posNew.Position()); } } else if (direction > 0 && posNew.Position() != pdoc->Length()) { // There is an equivalent case when moving down which skips // over a line. Point ptNew = LocationFromPosition(posNew.Position()); while ((posNew.Position() > spStart.Position()) && (ptNew.y > newY)) { posNew.Add(-1); posNew.SetVirtualSpace(0); ptNew = LocationFromPosition(posNew.Position()); } } return posNew; } void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { if ((selt == Selection::noSel) && sel.MoveExtends()) { selt = !sel.IsRectangular() ? Selection::selStream : Selection::selRectangle; } SelectionPosition caretToUse = sel.Range(sel.Main()).caret; if (sel.IsRectangular()) { if (selt == Selection::noSel) { caretToUse = (direction > 0) ? sel.Limits().end : sel.Limits().start; } else { caretToUse = sel.Rectangular().caret; } } if (selt == Selection::selRectangle) { const SelectionRange rangeBase = sel.IsRectangular() ? sel.Rectangular() : sel.RangeMain(); if (!sel.IsRectangular()) { InvalidateWholeSelection(); sel.DropAdditionalRanges(); } const SelectionPosition posNew = MovePositionSoVisible( PositionUpOrDown(caretToUse, direction, lastXChosen), direction); sel.selType = Selection::selRectangle; sel.Rectangular() = SelectionRange(posNew, rangeBase.anchor); SetRectangularRange(); MovedCaret(posNew, caretToUse, true); } else if (sel.selType == Selection::selLines && sel.MoveExtends()) { // Calculate new caret position and call SetSelection(), which will ensure whole lines are selected. const SelectionPosition posNew = MovePositionSoVisible( PositionUpOrDown(caretToUse, direction, -1), direction); SetSelection(posNew, sel.Range(sel.Main()).anchor); } else { InvalidateWholeSelection(); if (!additionalSelectionTyping || (sel.IsRectangular())) { sel.DropAdditionalRanges(); } sel.selType = Selection::selStream; for (size_t r = 0; r < sel.Count(); r++) { const int lastX = (r == sel.Main()) ? lastXChosen : -1; const SelectionPosition spCaretNow = sel.Range(r).caret; const SelectionPosition posNew = MovePositionSoVisible( PositionUpOrDown(spCaretNow, direction, lastX), direction); sel.Range(r) = selt == Selection::selStream ? SelectionRange(posNew, sel.Range(r).anchor) : SelectionRange(posNew); } sel.RemoveDuplicates(); MovedCaret(sel.RangeMain().caret, caretToUse, true); } } void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) { Sci::Line lineDoc; const Sci::Position savedPos = sel.MainCaret(); do { MovePositionTo(SelectionPosition(direction > 0 ? pdoc->ParaDown(sel.MainCaret()) : pdoc->ParaUp(sel.MainCaret())), selt); lineDoc = pdoc->SciLineFromPosition(sel.MainCaret()); if (direction > 0) { if (sel.MainCaret() >= pdoc->Length() && !pcs->GetVisible(lineDoc)) { if (selt == Selection::noSel) { MovePositionTo(SelectionPosition(pdoc->LineEndPosition(savedPos))); } break; } } } while (!pcs->GetVisible(lineDoc)); } Range Editor::RangeDisplayLine(Sci::Line lineVisible) { RefreshStyleData(); AutoSurface surface(this); return view.RangeDisplayLine(surface, *this, lineVisible, vs); } Sci::Position Editor::StartEndDisplayLine(Sci::Position pos, bool start) { RefreshStyleData(); AutoSurface surface(this); const Sci::Position posRet = view.StartEndDisplayLine(surface, *this, pos, start, vs); if (posRet == INVALID_POSITION) { return pos; } else { return posRet; } } namespace { constexpr short HighShortFromWParam(uptr_t x) { return static_cast(x >> 16); } constexpr short LowShortFromWParam(uptr_t x) { return static_cast(x & 0xffff); } unsigned int WithExtends(unsigned int iMessage) { switch (iMessage) { case SCI_CHARLEFT: return SCI_CHARLEFTEXTEND; case SCI_CHARRIGHT: return SCI_CHARRIGHTEXTEND; case SCI_WORDLEFT: return SCI_WORDLEFTEXTEND; case SCI_WORDRIGHT: return SCI_WORDRIGHTEXTEND; case SCI_WORDLEFTEND: return SCI_WORDLEFTENDEXTEND; case SCI_WORDRIGHTEND: return SCI_WORDRIGHTENDEXTEND; case SCI_WORDPARTLEFT: return SCI_WORDPARTLEFTEXTEND; case SCI_WORDPARTRIGHT: return SCI_WORDPARTRIGHTEXTEND; case SCI_HOME: return SCI_HOMEEXTEND; case SCI_HOMEDISPLAY: return SCI_HOMEDISPLAYEXTEND; case SCI_HOMEWRAP: return SCI_HOMEWRAPEXTEND; case SCI_VCHOME: return SCI_VCHOMEEXTEND; case SCI_VCHOMEDISPLAY: return SCI_VCHOMEDISPLAYEXTEND; case SCI_VCHOMEWRAP: return SCI_VCHOMEWRAPEXTEND; case SCI_LINEEND: return SCI_LINEENDEXTEND; case SCI_LINEENDDISPLAY: return SCI_LINEENDDISPLAYEXTEND; case SCI_LINEENDWRAP: return SCI_LINEENDWRAPEXTEND; default: return iMessage; } } int NaturalDirection(unsigned int iMessage) { switch (iMessage) { case SCI_CHARLEFT: case SCI_CHARLEFTEXTEND: case SCI_CHARLEFTRECTEXTEND: case SCI_WORDLEFT: case SCI_WORDLEFTEXTEND: case SCI_WORDLEFTEND: case SCI_WORDLEFTENDEXTEND: case SCI_WORDPARTLEFT: case SCI_WORDPARTLEFTEXTEND: case SCI_HOME: case SCI_HOMEEXTEND: case SCI_HOMEDISPLAY: case SCI_HOMEDISPLAYEXTEND: case SCI_HOMEWRAP: case SCI_HOMEWRAPEXTEND: // VC_HOME* mostly goes back case SCI_VCHOME: case SCI_VCHOMEEXTEND: case SCI_VCHOMEDISPLAY: case SCI_VCHOMEDISPLAYEXTEND: case SCI_VCHOMEWRAP: case SCI_VCHOMEWRAPEXTEND: return -1; default: return 1; } } bool IsRectExtend(unsigned int iMessage, bool isRectMoveExtends) { switch (iMessage) { case SCI_CHARLEFTRECTEXTEND: case SCI_CHARRIGHTRECTEXTEND: case SCI_HOMERECTEXTEND: case SCI_VCHOMERECTEXTEND: case SCI_LINEENDRECTEXTEND: return true; default: if (isRectMoveExtends) { // Handle SCI_SETSELECTIONMODE(SC_SEL_RECTANGLE) and subsequent movements. switch (iMessage) { case SCI_CHARLEFTEXTEND: case SCI_CHARRIGHTEXTEND: case SCI_HOMEEXTEND: case SCI_VCHOMEEXTEND: case SCI_LINEENDEXTEND: return true; default: return false; } } return false; } } } Sci::Position Editor::VCHomeDisplayPosition(Sci::Position position) { const Sci::Position homePos = pdoc->VCHomePosition(position); const Sci::Position viewLineStart = StartEndDisplayLine(position, true); if (viewLineStart > homePos) return viewLineStart; else return homePos; } Sci::Position Editor::VCHomeWrapPosition(Sci::Position position) { const Sci::Position homePos = pdoc->VCHomePosition(position); const Sci::Position viewLineStart = StartEndDisplayLine(position, true); if ((viewLineStart < position) && (viewLineStart > homePos)) return viewLineStart; else return homePos; } Sci::Position Editor::LineEndWrapPosition(Sci::Position position) { const Sci::Position endPos = StartEndDisplayLine(position, false); const Sci::Position realEndPos = pdoc->LineEndPosition(position); if (endPos > realEndPos // if moved past visible EOLs || position >= endPos) // if at end of display line already return realEndPos; else return endPos; } int Editor::HorizontalMove(unsigned int iMessage) { if (sel.selType == Selection::selLines) { return 0; // horizontal moves with line selection have no effect } if (sel.MoveExtends()) { iMessage = WithExtends(iMessage); } if (!multipleSelection && !sel.IsRectangular()) { // Simplify selection down to 1 sel.SetSelection(sel.RangeMain()); } // Invalidate each of the current selections InvalidateWholeSelection(); if (IsRectExtend(iMessage, sel.IsRectangular() && sel.MoveExtends())) { const SelectionRange rangeBase = sel.IsRectangular() ? sel.Rectangular() : sel.RangeMain(); if (!sel.IsRectangular()) { sel.DropAdditionalRanges(); } // Will change to rectangular if not currently rectangular SelectionPosition spCaret = rangeBase.caret; switch (iMessage) { case SCI_CHARLEFTRECTEXTEND: case SCI_CHARLEFTEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() if (pdoc->IsLineEndPosition(spCaret.Position()) && spCaret.VirtualSpace()) { spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); } else if ((virtualSpaceOptions & SCVS_NOWRAPLINESTART) == 0 || pdoc->GetColumn(spCaret.Position()) > 0) { spCaret = SelectionPosition(spCaret.Position() - 1); } break; case SCI_CHARRIGHTRECTEXTEND: case SCI_CHARRIGHTEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) { spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); } else { spCaret = SelectionPosition(spCaret.Position() + 1); } break; case SCI_HOMERECTEXTEND: case SCI_HOMEEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() spCaret = SelectionPosition( pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position()))); break; case SCI_VCHOMERECTEXTEND: case SCI_VCHOMEEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() spCaret = SelectionPosition(pdoc->VCHomePosition(spCaret.Position())); break; case SCI_LINEENDRECTEXTEND: case SCI_LINEENDEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() spCaret = SelectionPosition(pdoc->LineEndPosition(spCaret.Position())); break; } const int directionMove = (spCaret < rangeBase.caret) ? -1 : 1; spCaret = MovePositionSoVisible(spCaret, directionMove); sel.selType = Selection::selRectangle; sel.Rectangular() = SelectionRange(spCaret, rangeBase.anchor); SetRectangularRange(); } else if (sel.IsRectangular()) { // Not a rectangular extension so switch to stream. SelectionPosition selAtLimit = (NaturalDirection(iMessage) > 0) ? sel.Limits().end : sel.Limits().start; switch (iMessage) { case SCI_HOME: selAtLimit = SelectionPosition( pdoc->LineStart(pdoc->LineFromPosition(selAtLimit.Position()))); break; case SCI_VCHOME: selAtLimit = SelectionPosition(pdoc->VCHomePosition(selAtLimit.Position())); break; case SCI_LINEEND: selAtLimit = SelectionPosition(pdoc->LineEndPosition(selAtLimit.Position())); break; } sel.selType = Selection::selStream; sel.SetSelection(SelectionRange(selAtLimit)); } else { if (!additionalSelectionTyping) { InvalidateWholeSelection(); sel.DropAdditionalRanges(); } for (size_t r = 0; r < sel.Count(); r++) { const SelectionPosition spCaretNow = sel.Range(r).caret; SelectionPosition spCaret = spCaretNow; switch (iMessage) { case SCI_CHARLEFT: case SCI_CHARLEFTEXTEND: if (spCaret.VirtualSpace()) { spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); } else if ((virtualSpaceOptions & SCVS_NOWRAPLINESTART) == 0 || pdoc->GetColumn(spCaret.Position()) > 0) { spCaret = SelectionPosition(spCaret.Position() - 1); } break; case SCI_CHARRIGHT: case SCI_CHARRIGHTEXTEND: if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(spCaret.Position())) { spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); } else { spCaret = SelectionPosition(spCaret.Position() + 1); } break; case SCI_WORDLEFT: case SCI_WORDLEFTEXTEND: spCaret = SelectionPosition(pdoc->NextWordStart(spCaret.Position(), -1)); break; case SCI_WORDRIGHT: case SCI_WORDRIGHTEXTEND: spCaret = SelectionPosition(pdoc->NextWordStart(spCaret.Position(), 1)); break; case SCI_WORDLEFTEND: case SCI_WORDLEFTENDEXTEND: spCaret = SelectionPosition(pdoc->NextWordEnd(spCaret.Position(), -1)); break; case SCI_WORDRIGHTEND: case SCI_WORDRIGHTENDEXTEND: spCaret = SelectionPosition(pdoc->NextWordEnd(spCaret.Position(), 1)); break; case SCI_WORDPARTLEFT: case SCI_WORDPARTLEFTEXTEND: spCaret = SelectionPosition(pdoc->WordPartLeft(spCaret.Position())); break; case SCI_WORDPARTRIGHT: case SCI_WORDPARTRIGHTEXTEND: spCaret = SelectionPosition(pdoc->WordPartRight(spCaret.Position())); break; case SCI_HOME: case SCI_HOMEEXTEND: spCaret = SelectionPosition( pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position()))); break; case SCI_HOMEDISPLAY: case SCI_HOMEDISPLAYEXTEND: spCaret = SelectionPosition(StartEndDisplayLine(spCaret.Position(), true)); break; case SCI_HOMEWRAP: case SCI_HOMEWRAPEXTEND: spCaret = MovePositionSoVisible(StartEndDisplayLine(spCaret.Position(), true), -1); if (spCaretNow <= spCaret) spCaret = SelectionPosition( pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position()))); break; case SCI_VCHOME: case SCI_VCHOMEEXTEND: // VCHome alternates between beginning of line and beginning of text so may move back or forwards spCaret = SelectionPosition(pdoc->VCHomePosition(spCaret.Position())); break; case SCI_VCHOMEDISPLAY: case SCI_VCHOMEDISPLAYEXTEND: spCaret = SelectionPosition(VCHomeDisplayPosition(spCaret.Position())); break; case SCI_VCHOMEWRAP: case SCI_VCHOMEWRAPEXTEND: spCaret = SelectionPosition(VCHomeWrapPosition(spCaret.Position())); break; case SCI_LINEEND: case SCI_LINEENDEXTEND: spCaret = SelectionPosition(pdoc->LineEndPosition(spCaret.Position())); break; case SCI_LINEENDDISPLAY: case SCI_LINEENDDISPLAYEXTEND: spCaret = SelectionPosition(StartEndDisplayLine(spCaret.Position(), false)); break; case SCI_LINEENDWRAP: case SCI_LINEENDWRAPEXTEND: spCaret = SelectionPosition(LineEndWrapPosition(spCaret.Position())); break; default: PLATFORM_ASSERT(false); } const int directionMove = (spCaret < spCaretNow) ? -1 : 1; spCaret = MovePositionSoVisible(spCaret, directionMove); // Handle move versus extend, and special behaviour for non-empty left/right switch (iMessage) { case SCI_CHARLEFT: case SCI_CHARRIGHT: if (sel.Range(r).Empty()) { sel.Range(r) = SelectionRange(spCaret); } else { sel.Range(r) = SelectionRange( (iMessage == SCI_CHARLEFT) ? sel.Range(r).Start() : sel.Range(r).End()); } break; case SCI_WORDLEFT: case SCI_WORDRIGHT: case SCI_WORDLEFTEND: case SCI_WORDRIGHTEND: case SCI_WORDPARTLEFT: case SCI_WORDPARTRIGHT: case SCI_HOME: case SCI_HOMEDISPLAY: case SCI_HOMEWRAP: case SCI_VCHOME: case SCI_VCHOMEDISPLAY: case SCI_VCHOMEWRAP: case SCI_LINEEND: case SCI_LINEENDDISPLAY: case SCI_LINEENDWRAP: sel.Range(r) = SelectionRange(spCaret); break; case SCI_CHARLEFTEXTEND: case SCI_CHARRIGHTEXTEND: case SCI_WORDLEFTEXTEND: case SCI_WORDRIGHTEXTEND: case SCI_WORDLEFTENDEXTEND: case SCI_WORDRIGHTENDEXTEND: case SCI_WORDPARTLEFTEXTEND: case SCI_WORDPARTRIGHTEXTEND: case SCI_HOMEEXTEND: case SCI_HOMEDISPLAYEXTEND: case SCI_HOMEWRAPEXTEND: case SCI_VCHOMEEXTEND: case SCI_VCHOMEDISPLAYEXTEND: case SCI_VCHOMEWRAPEXTEND: case SCI_LINEENDEXTEND: case SCI_LINEENDDISPLAYEXTEND: case SCI_LINEENDWRAPEXTEND: { SelectionRange rangeNew = SelectionRange(spCaret, sel.Range(r).anchor); sel.TrimOtherSelections(r, SelectionRange(rangeNew)); sel.Range(r) = rangeNew; } break; default: PLATFORM_ASSERT(false); } } } sel.RemoveDuplicates(); MovedCaret(sel.RangeMain().caret, SelectionPosition(INVALID_POSITION), true); // Invalidate the new state of the selection InvalidateWholeSelection(); SetLastXChosen(); // Need the line moving and so forth from MovePositionTo return 0; } int Editor::DelWordOrLine(unsigned int iMessage) { // Virtual space may be realised for SCI_DELWORDRIGHT or SCI_DELWORDRIGHTEND // which means 2 actions so wrap in an undo group. // Rightwards and leftwards deletions differ in treatment of virtual space. // Clear virtual space for leftwards, realise for rightwards. const bool leftwards = (iMessage == SCI_DELWORDLEFT) || (iMessage == SCI_DELLINELEFT); if (!additionalSelectionTyping) { InvalidateWholeSelection(); sel.DropAdditionalRanges(); } UndoGroup ug0(pdoc, (sel.Count() > 1) || !leftwards); for (size_t r = 0; r < sel.Count(); r++) { if (leftwards) { // Delete to the left so first clear the virtual space. sel.Range(r).ClearVirtualSpace(); } else { // Delete to the right so first realise the virtual space. sel.Range(r) = SelectionRange( RealizeVirtualSpace(sel.Range(r).caret)); } Range rangeDelete; switch (iMessage) { case SCI_DELWORDLEFT: rangeDelete = Range( pdoc->NextWordStart(sel.Range(r).caret.Position(), -1), sel.Range(r).caret.Position()); break; case SCI_DELWORDRIGHT: rangeDelete = Range( sel.Range(r).caret.Position(), pdoc->NextWordStart(sel.Range(r).caret.Position(), 1)); break; case SCI_DELWORDRIGHTEND: rangeDelete = Range( sel.Range(r).caret.Position(), pdoc->NextWordEnd(sel.Range(r).caret.Position(), 1)); break; case SCI_DELLINELEFT: rangeDelete = Range( pdoc->LineStart(pdoc->LineFromPosition(sel.Range(r).caret.Position())), sel.Range(r).caret.Position()); break; case SCI_DELLINERIGHT: rangeDelete = Range( sel.Range(r).caret.Position(), pdoc->LineEnd(pdoc->LineFromPosition(sel.Range(r).caret.Position()))); break; } if (!RangeContainsProtected(rangeDelete.start, rangeDelete.end)) { pdoc->DeleteChars(rangeDelete.start, rangeDelete.end - rangeDelete.start); } } // May need something stronger here: can selections overlap at this point? sel.RemoveDuplicates(); MovedCaret(sel.RangeMain().caret, SelectionPosition(INVALID_POSITION), true); // Invalidate the new state of the selection InvalidateWholeSelection(); SetLastXChosen(); return 0; } int Editor::KeyCommand(unsigned int iMessage) { switch (iMessage) { case SCI_LINEDOWN: CursorUpOrDown(1, Selection::noSel); break; case SCI_LINEDOWNEXTEND: CursorUpOrDown(1, Selection::selStream); break; case SCI_LINEDOWNRECTEXTEND: CursorUpOrDown(1, Selection::selRectangle); break; case SCI_PARADOWN: ParaUpOrDown(1, Selection::noSel); break; case SCI_PARADOWNEXTEND: ParaUpOrDown(1, Selection::selStream); break; case SCI_LINESCROLLDOWN: ScrollTo(topLine + 1); MoveCaretInsideView(false); break; case SCI_LINEUP: CursorUpOrDown(-1, Selection::noSel); break; case SCI_LINEUPEXTEND: CursorUpOrDown(-1, Selection::selStream); break; case SCI_LINEUPRECTEXTEND: CursorUpOrDown(-1, Selection::selRectangle); break; case SCI_PARAUP: ParaUpOrDown(-1, Selection::noSel); break; case SCI_PARAUPEXTEND: ParaUpOrDown(-1, Selection::selStream); break; case SCI_LINESCROLLUP: ScrollTo(topLine - 1); MoveCaretInsideView(false); break; case SCI_CHARLEFT: case SCI_CHARLEFTEXTEND: case SCI_CHARLEFTRECTEXTEND: case SCI_CHARRIGHT: case SCI_CHARRIGHTEXTEND: case SCI_CHARRIGHTRECTEXTEND: case SCI_WORDLEFT: case SCI_WORDLEFTEXTEND: case SCI_WORDRIGHT: case SCI_WORDRIGHTEXTEND: case SCI_WORDLEFTEND: case SCI_WORDLEFTENDEXTEND: case SCI_WORDRIGHTEND: case SCI_WORDRIGHTENDEXTEND: case SCI_WORDPARTLEFT: case SCI_WORDPARTLEFTEXTEND: case SCI_WORDPARTRIGHT: case SCI_WORDPARTRIGHTEXTEND: case SCI_HOME: case SCI_HOMEEXTEND: case SCI_HOMERECTEXTEND: case SCI_HOMEDISPLAY: case SCI_HOMEDISPLAYEXTEND: case SCI_HOMEWRAP: case SCI_HOMEWRAPEXTEND: case SCI_VCHOME: case SCI_VCHOMEEXTEND: case SCI_VCHOMERECTEXTEND: case SCI_VCHOMEDISPLAY: case SCI_VCHOMEDISPLAYEXTEND: case SCI_VCHOMEWRAP: case SCI_VCHOMEWRAPEXTEND: case SCI_LINEEND: case SCI_LINEENDEXTEND: case SCI_LINEENDRECTEXTEND: case SCI_LINEENDDISPLAY: case SCI_LINEENDDISPLAYEXTEND: case SCI_LINEENDWRAP: case SCI_LINEENDWRAPEXTEND: return HorizontalMove(iMessage); case SCI_DOCUMENTSTART: MovePositionTo(0); SetLastXChosen(); break; case SCI_DOCUMENTSTARTEXTEND: MovePositionTo(0, Selection::selStream); SetLastXChosen(); break; case SCI_DOCUMENTEND: MovePositionTo(pdoc->Length()); SetLastXChosen(); break; case SCI_DOCUMENTENDEXTEND: MovePositionTo(pdoc->Length(), Selection::selStream); SetLastXChosen(); break; case SCI_STUTTEREDPAGEUP: PageMove(-1, Selection::noSel, true); break; case SCI_STUTTEREDPAGEUPEXTEND: PageMove(-1, Selection::selStream, true); break; case SCI_STUTTEREDPAGEDOWN: PageMove(1, Selection::noSel, true); break; case SCI_STUTTEREDPAGEDOWNEXTEND: PageMove(1, Selection::selStream, true); break; case SCI_PAGEUP: PageMove(-1); break; case SCI_PAGEUPEXTEND: PageMove(-1, Selection::selStream); break; case SCI_PAGEUPRECTEXTEND: PageMove(-1, Selection::selRectangle); break; case SCI_PAGEDOWN: PageMove(1); break; case SCI_PAGEDOWNEXTEND: PageMove(1, Selection::selStream); break; case SCI_PAGEDOWNRECTEXTEND: PageMove(1, Selection::selRectangle); break; case SCI_EDITTOGGLEOVERTYPE: inOverstrike = !inOverstrike; ContainerNeedsUpdate(SC_UPDATE_SELECTION); ShowCaretAtCurrentPosition(); break; case SCI_CANCEL: // Cancel any modes - handled in subclass // Also unselect text CancelModes(); if ((sel.Count() > 1) && !sel.IsRectangular()) { // Drop additional selections InvalidateWholeSelection(); sel.DropAdditionalRanges(); } break; case SCI_DELETEBACK: DelCharBack(true); if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); break; case SCI_DELETEBACKNOTLINE: DelCharBack(false); if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); break; case SCI_TAB: Indent(true); if (caretSticky == SC_CARETSTICKY_OFF) { SetLastXChosen(); } EnsureCaretVisible(); ShowCaretAtCurrentPosition(); // Avoid blinking break; case SCI_BACKTAB: Indent(false); if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); ShowCaretAtCurrentPosition(); // Avoid blinking break; case SCI_NEWLINE: NewLine(); break; case SCI_FORMFEED: AddChar('\f'); break; case SCI_ZOOMIN: if (vs.zoomLevel < 20) { vs.zoomLevel++; InvalidateStyleRedraw(); NotifyZoom(); } break; case SCI_ZOOMOUT: if (vs.zoomLevel > -10) { vs.zoomLevel--; InvalidateStyleRedraw(); NotifyZoom(); } break; case SCI_DELWORDLEFT: case SCI_DELWORDRIGHT: case SCI_DELWORDRIGHTEND: case SCI_DELLINELEFT: case SCI_DELLINERIGHT: return DelWordOrLine(iMessage); case SCI_LINECOPY: { const Sci::Line lineStart = pdoc->SciLineFromPosition(SelectionStart().Position()); const Sci::Line lineEnd = pdoc->SciLineFromPosition(SelectionEnd().Position()); CopyRangeToClipboard(pdoc->LineStart(lineStart), pdoc->LineStart(lineEnd + 1)); } break; case SCI_LINECUT: { const Sci::Line lineStart = pdoc->SciLineFromPosition(SelectionStart().Position()); const Sci::Line lineEnd = pdoc->SciLineFromPosition(SelectionEnd().Position()); const Sci::Position start = pdoc->LineStart(lineStart); const Sci::Position end = pdoc->LineStart(lineEnd + 1); SetSelection(start, end); Cut(); SetLastXChosen(); } break; case SCI_LINEDELETE: { const Sci::Line line = pdoc->SciLineFromPosition(sel.MainCaret()); const Sci::Position start = pdoc->LineStart(line); const Sci::Position end = pdoc->LineStart(line + 1); pdoc->DeleteChars(start, end - start); } break; case SCI_LINETRANSPOSE: LineTranspose(); break; case SCI_LINEREVERSE: LineReverse(); break; case SCI_LINEDUPLICATE: Duplicate(true); break; case SCI_SELECTIONDUPLICATE: Duplicate(false); break; case SCI_LOWERCASE: ChangeCaseOfSelection(cmLower); break; case SCI_UPPERCASE: ChangeCaseOfSelection(cmUpper); break; case SCI_SCROLLTOSTART: ScrollTo(0); break; case SCI_SCROLLTOEND: ScrollTo(MaxScrollPos()); break; } return 0; } int Editor::KeyDefault(int, int) { return 0; } int Editor::KeyDownWithModifiers(int key, int modifiers, bool *consumed) { DwellEnd(false); const int msg = kmap.Find(key, modifiers); if (msg) { if (consumed) *consumed = true; return static_cast(WndProc(msg, 0, 0)); } else { if (consumed) *consumed = false; return KeyDefault(key, modifiers); } } void Editor::Indent(bool forwards) { UndoGroup ug(pdoc); for (size_t r=0; rSciLineFromPosition(sel.Range(r).anchor.Position()); Sci::Position caretPosition = sel.Range(r).caret.Position(); const Sci::Line lineCurrentPos = pdoc->SciLineFromPosition(caretPosition); if (lineOfAnchor == lineCurrentPos) { if (forwards) { pdoc->DeleteChars(sel.Range(r).Start().Position(), sel.Range(r).Length()); caretPosition = sel.Range(r).caret.Position(); if (pdoc->GetColumn(caretPosition) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) && pdoc->tabIndents) { const int indentation = pdoc->GetLineIndentation(lineCurrentPos); const int indentationStep = pdoc->IndentSize(); const Sci::Position posSelect = pdoc->SetLineIndentation( lineCurrentPos, indentation + indentationStep - indentation % indentationStep); sel.Range(r) = SelectionRange(posSelect); } else { if (pdoc->useTabs) { const Sci::Position lengthInserted = pdoc->InsertString(caretPosition, "\t", 1); sel.Range(r) = SelectionRange(caretPosition + lengthInserted); } else { int numSpaces = (pdoc->tabInChars) - (pdoc->GetColumn(caretPosition) % (pdoc->tabInChars)); if (numSpaces < 1) numSpaces = pdoc->tabInChars; const std::string spaceText(numSpaces, ' '); const Sci::Position lengthInserted = pdoc->InsertString(caretPosition, spaceText.c_str(), spaceText.length()); sel.Range(r) = SelectionRange(caretPosition + lengthInserted); } } } else { if (pdoc->GetColumn(caretPosition) <= pdoc->GetLineIndentation(lineCurrentPos) && pdoc->tabIndents) { const int indentation = pdoc->GetLineIndentation(lineCurrentPos); const int indentationStep = pdoc->IndentSize(); const Sci::Position posSelect = pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep); sel.Range(r) = SelectionRange(posSelect); } else { Sci::Position newColumn = ((pdoc->GetColumn(caretPosition) - 1) / pdoc->tabInChars) * pdoc->tabInChars; if (newColumn < 0) newColumn = 0; Sci::Position newPos = caretPosition; while (pdoc->GetColumn(newPos) > newColumn) newPos--; sel.Range(r) = SelectionRange(newPos); } } } else { // Multiline const Sci::Position anchorPosOnLine = sel.Range(r).anchor.Position() - pdoc->LineStart(lineOfAnchor); const Sci::Position currentPosPosOnLine = caretPosition - pdoc->LineStart(lineCurrentPos); // Multiple lines selected so indent / dedent const Sci::Line lineTopSel = std::min(lineOfAnchor, lineCurrentPos); Sci::Line lineBottomSel = std::max(lineOfAnchor, lineCurrentPos); if (pdoc->LineStart(lineBottomSel) == sel.Range(r).anchor.Position() || pdoc->LineStart(lineBottomSel) == caretPosition) lineBottomSel--; // If not selecting any characters on a line, do not indent pdoc->Indent(forwards, lineBottomSel, lineTopSel); if (lineOfAnchor < lineCurrentPos) { if (currentPosPosOnLine == 0) sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); else sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor)); } else { if (anchorPosOnLine == 0) sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); else sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1)); } } } ContainerNeedsUpdate(SC_UPDATE_SELECTION); } class CaseFolderASCII : public CaseFolderTable { public: CaseFolderASCII() { StandardASCII(); } ~CaseFolderASCII() override { } }; CaseFolder *Editor::CaseFolderForEncoding() { // Simple default that only maps ASCII upper case to lower case. return new CaseFolderASCII(); } /** * Search of a text in the document, in the given range. * @return The position of the found text, -1 if not found. */ Sci::Position Editor::FindText( uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD, ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX. sptr_t lParam) { ///< @c Sci_TextToFind structure: The text to search for in the given range. Sci_TextToFind *ft = static_cast(PtrFromSPtr(lParam)); Sci::Position lengthFound = strlen(ft->lpstrText); if (!pdoc->HasCaseFolder()) pdoc->SetCaseFolder(CaseFolderForEncoding()); try { const Sci::Position pos = pdoc->FindText( static_cast(ft->chrg.cpMin), static_cast(ft->chrg.cpMax), ft->lpstrText, static_cast(wParam), &lengthFound); if (pos != -1) { ft->chrgText.cpMin = static_cast(pos); ft->chrgText.cpMax = static_cast(pos + lengthFound); } return pos; } catch (RegexError &) { errorStatus = SC_STATUS_WARN_REGEX; return -1; } } /** * Relocatable search support : Searches relative to current selection * point and sets the selection to the found text range with * each search. */ /** * Anchor following searches at current selection start: This allows * multiple incremental interactive searches to be macro recorded * while still setting the selection to found text so the find/select * operation is self-contained. */ void Editor::SearchAnchor() { searchAnchor = SelectionStart().Position(); } /** * Find text from current search anchor: Must call @c SearchAnchor first. * Used for next text and previous text requests. * @return The position of the found text, -1 if not found. */ Sci::Position Editor::SearchText( unsigned int iMessage, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV. uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD, ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX. sptr_t lParam) { ///< The text to search for. const char *txt = CharPtrFromSPtr(lParam); Sci::Position pos = INVALID_POSITION; Sci::Position lengthFound = strlen(txt); if (!pdoc->HasCaseFolder()) pdoc->SetCaseFolder(CaseFolderForEncoding()); try { if (iMessage == SCI_SEARCHNEXT) { pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, static_cast(wParam), &lengthFound); } else { pos = pdoc->FindText(searchAnchor, 0, txt, static_cast(wParam), &lengthFound); } } catch (RegexError &) { errorStatus = SC_STATUS_WARN_REGEX; return INVALID_POSITION; } if (pos != INVALID_POSITION) { SetSelection(pos, pos + lengthFound); } return pos; } std::string Editor::CaseMapString(const std::string &s, int caseMapping) { std::string ret(s); for (char &ch : ret) { switch (caseMapping) { case cmUpper: ch = MakeUpperCase(ch); break; case cmLower: ch = MakeLowerCase(ch); break; } } return ret; } /** * Search for text in the target range of the document. * @return The position of the found text, -1 if not found. */ Sci::Position Editor::SearchInTarget(const char *text, Sci::Position length) { Sci::Position lengthFound = length; if (!pdoc->HasCaseFolder()) pdoc->SetCaseFolder(CaseFolderForEncoding()); try { const Sci::Position pos = pdoc->FindText(targetStart, targetEnd, text, searchFlags, &lengthFound); if (pos != -1) { targetStart = pos; targetEnd = pos + lengthFound; } return pos; } catch (RegexError &) { errorStatus = SC_STATUS_WARN_REGEX; return -1; } } void Editor::GoToLine(Sci::Line lineNo) { if (lineNo > pdoc->LinesTotal()) lineNo = pdoc->LinesTotal(); if (lineNo < 0) lineNo = 0; SetEmptySelection(pdoc->LineStart(lineNo)); ShowCaretAtCurrentPosition(); EnsureCaretVisible(); } static bool Close(Point pt1, Point pt2, Point threshold) { if (std::abs(pt1.x - pt2.x) > threshold.x) return false; if (std::abs(pt1.y - pt2.y) > threshold.y) return false; return true; } std::string Editor::RangeText(Sci::Position start, Sci::Position end) const { if (start < end) { const Sci::Position len = end - start; std::string ret(len, '\0'); pdoc->GetCharRange(const_cast(ret.data()), start, len); return ret; } return std::string(); } void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) { if (sel.Empty()) { if (allowLineCopy) { const Sci::Line currentLine = pdoc->SciLineFromPosition(sel.MainCaret()); const Sci::Position start = pdoc->LineStart(currentLine); const Sci::Position end = pdoc->LineEnd(currentLine); std::string text = RangeText(start, end); if (pdoc->eolMode != SC_EOL_LF) text.push_back('\r'); if (pdoc->eolMode != SC_EOL_CR) text.push_back('\n'); ss->Copy(text, pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true); } } else { std::string text; std::vector rangesInOrder = sel.RangesCopy(); if (sel.selType == Selection::selRectangle) std::sort(rangesInOrder.begin(), rangesInOrder.end()); for (const SelectionRange ¤t : rangesInOrder) { text.append(RangeText(current.Start().Position(), current.End().Position())); if (sel.selType == Selection::selRectangle) { if (pdoc->eolMode != SC_EOL_LF) text.push_back('\r'); if (pdoc->eolMode != SC_EOL_CR) text.push_back('\n'); } } ss->Copy(text, pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, sel.IsRectangular(), sel.selType == Selection::selLines); } } void Editor::CopyRangeToClipboard(Sci::Position start, Sci::Position end) { start = pdoc->ClampPositionIntoDocument(start); end = pdoc->ClampPositionIntoDocument(end); SelectionText selectedText; std::string text = RangeText(start, end); selectedText.Copy(text, pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); CopyToClipboard(selectedText); } void Editor::CopyText(size_t length, const char *text) { SelectionText selectedText; selectedText.Copy(std::string(text, length), pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); CopyToClipboard(selectedText); } void Editor::SetDragPosition(SelectionPosition newPos) { if (newPos.Position() >= 0) { newPos = MovePositionOutsideChar(newPos, 1); posDrop = newPos; } if (!(posDrag == newPos)) { caret.on = true; FineTickerCancel(tickCaret); if ((caret.active) && (caret.period > 0) && (newPos.Position() < 0)) FineTickerStart(tickCaret, caret.period, caret.period/10); InvalidateCaret(); posDrag = newPos; InvalidateCaret(); } } void Editor::DisplayCursor(Window::Cursor c) { if (cursorMode == SC_CURSORNORMAL) wMain.SetCursor(c); else wMain.SetCursor(static_cast(cursorMode)); } bool Editor::DragThreshold(Point ptStart, Point ptNow) { const XYPOSITION xMove = ptStart.x - ptNow.x; const XYPOSITION yMove = ptStart.y - ptNow.y; const XYPOSITION distanceSquared = xMove * xMove + yMove * yMove; return distanceSquared > 16.0f; } void Editor::StartDrag() { // Always handled by subclasses //SetMouseCapture(true); //DisplayCursor(Window::cursorArrow); } void Editor::DropAt(SelectionPosition position, const char *value, size_t lengthValue, bool moving, bool rectangular) { //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position); if (inDragDrop == ddDragging) dropWentOutside = false; const bool positionWasInSelection = PositionInSelection(position.Position()); const bool positionOnEdgeOfSelection = (position == SelectionStart()) || (position == SelectionEnd()); if ((inDragDrop != ddDragging) || !(positionWasInSelection) || (positionOnEdgeOfSelection && !moving)) { const SelectionPosition selStart = SelectionStart(); const SelectionPosition selEnd = SelectionEnd(); UndoGroup ug(pdoc); SelectionPosition positionAfterDeletion = position; if ((inDragDrop == ddDragging) && moving) { // Remove dragged out text if (rectangular || sel.selType == Selection::selLines) { for (size_t r=0; r= sel.Range(r).Start()) { if (position > sel.Range(r).End()) { positionAfterDeletion.Add(-sel.Range(r).Length()); } else { positionAfterDeletion.Add(-SelectionRange(position, sel.Range(r).Start()).Length()); } } } } else { if (position > selStart) { positionAfterDeletion.Add(-SelectionRange(selEnd, selStart).Length()); } } ClearSelection(); } position = positionAfterDeletion; std::string convertedText = Document::TransformLineEnds(value, lengthValue, pdoc->eolMode); if (rectangular) { PasteRectangular(position, convertedText.c_str(), convertedText.length()); // Should try to select new rectangle but it may not be a rectangle now so just select the drop position SetEmptySelection(position); } else { position = MovePositionOutsideChar(position, sel.MainCaret() - position.Position()); position = RealizeVirtualSpace(position); const Sci::Position lengthInserted = pdoc->InsertString( position.Position(), convertedText.c_str(), convertedText.length()); if (lengthInserted > 0) { SelectionPosition posAfterInsertion = position; posAfterInsertion.Add(lengthInserted); SetSelection(posAfterInsertion, position); } } } else if (inDragDrop == ddDragging) { SetEmptySelection(position); } } void Editor::DropAt(SelectionPosition position, const char *value, bool moving, bool rectangular) { DropAt(position, value, strlen(value), moving, rectangular); } /** * @return true if given position is inside the selection, */ bool Editor::PositionInSelection(Sci::Position pos) { pos = MovePositionOutsideChar(pos, sel.MainCaret() - pos); for (size_t r=0; r ptPos.x) { hit = false; } } if (hit) return true; } } return false; } bool Editor::PointInSelMargin(Point pt) const { // Really means: "Point in a margin" if (vs.fixedColumnWidth > 0) { // There is a margin PRectangle rcSelMargin = GetClientRectangle(); rcSelMargin.right = static_cast(vs.textStart - vs.leftMarginWidth); rcSelMargin.left = static_cast(vs.textStart - vs.fixedColumnWidth); const Point ptOrigin = GetVisibleOriginInMain(); rcSelMargin.Move(0, -ptOrigin.y); return rcSelMargin.ContainsWholePixel(pt); } else { return false; } } Window::Cursor Editor::GetMarginCursor(Point pt) const { int x = 0; for (const MarginStyle &m : vs.ms) { if ((pt.x >= x) && (pt.x < x + m.width)) return static_cast(m.cursor); x += m.width; } return Window::cursorReverseArrow; } void Editor::TrimAndSetSelection(Sci::Position currentPos_, Sci::Position anchor_) { sel.TrimSelection(SelectionRange(currentPos_, anchor_)); SetSelection(currentPos_, anchor_); } void Editor::LineSelection(Sci::Position lineCurrentPos_, Sci::Position lineAnchorPos_, bool wholeLine) { Sci::Position selCurrentPos, selAnchorPos; if (wholeLine) { const Sci::Line lineCurrent_ = pdoc->SciLineFromPosition(lineCurrentPos_); const Sci::Line lineAnchor_ = pdoc->SciLineFromPosition(lineAnchorPos_); if (lineAnchorPos_ < lineCurrentPos_) { selCurrentPos = pdoc->LineStart(lineCurrent_ + 1); selAnchorPos = pdoc->LineStart(lineAnchor_); } else if (lineAnchorPos_ > lineCurrentPos_) { selCurrentPos = pdoc->LineStart(lineCurrent_); selAnchorPos = pdoc->LineStart(lineAnchor_ + 1); } else { // Same line, select it selCurrentPos = pdoc->LineStart(lineAnchor_ + 1); selAnchorPos = pdoc->LineStart(lineAnchor_); } } else { if (lineAnchorPos_ < lineCurrentPos_) { selCurrentPos = StartEndDisplayLine(lineCurrentPos_, false) + 1; selCurrentPos = pdoc->MovePositionOutsideChar(selCurrentPos, 1); selAnchorPos = StartEndDisplayLine(lineAnchorPos_, true); } else if (lineAnchorPos_ > lineCurrentPos_) { selCurrentPos = StartEndDisplayLine(lineCurrentPos_, true); selAnchorPos = StartEndDisplayLine(lineAnchorPos_, false) + 1; selAnchorPos = pdoc->MovePositionOutsideChar(selAnchorPos, 1); } else { // Same line, select it selCurrentPos = StartEndDisplayLine(lineAnchorPos_, false) + 1; selCurrentPos = pdoc->MovePositionOutsideChar(selCurrentPos, 1); selAnchorPos = StartEndDisplayLine(lineAnchorPos_, true); } } TrimAndSetSelection(selCurrentPos, selAnchorPos); } void Editor::WordSelection(Sci::Position pos) { if (pos < wordSelectAnchorStartPos) { // Extend backward to the word containing pos. // Skip ExtendWordSelect if the line is empty or if pos is after the last character. // This ensures that a series of empty lines isn't counted as a single "word". if (!pdoc->IsLineEndPosition(pos)) pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos + 1, 1), -1); TrimAndSetSelection(pos, wordSelectAnchorEndPos); } else if (pos > wordSelectAnchorEndPos) { // Extend forward to the word containing the character to the left of pos. // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line. // This ensures that a series of empty lines isn't counted as a single "word". if (pos > pdoc->LineStart(pdoc->LineFromPosition(pos))) pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos - 1, -1), 1); TrimAndSetSelection(pos, wordSelectAnchorStartPos); } else { // Select only the anchored word if (pos >= originalAnchorPos) TrimAndSetSelection(wordSelectAnchorEndPos, wordSelectAnchorStartPos); else TrimAndSetSelection(wordSelectAnchorStartPos, wordSelectAnchorEndPos); } } void Editor::DwellEnd(bool mouseMoved) { if (mouseMoved) ticksToDwell = dwellDelay; else ticksToDwell = SC_TIME_FOREVER; if (dwelling && (dwellDelay < SC_TIME_FOREVER)) { dwelling = false; NotifyDwelling(ptMouseLast, dwelling); } FineTickerCancel(tickDwell); } void Editor::MouseLeave() { SetHotSpotRange(nullptr); if (!HaveMouseCapture()) { ptMouseLast = Point(-1, -1); DwellEnd(true); } } static constexpr bool AllowVirtualSpace(int virtualSpaceOptions, bool rectangular) noexcept { return (!rectangular && ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0)) || (rectangular && ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) != 0)); } void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers) { SetHoverIndicatorPoint(pt); //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop); ptMouseLast = pt; const bool ctrl = (modifiers & SCI_CTRL) != 0; const bool shift = (modifiers & SCI_SHIFT) != 0; const bool alt = (modifiers & SCI_ALT) != 0; SelectionPosition newPos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, alt)); newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position()); SelectionPosition newCharPos = SPositionFromLocation(pt, false, true, false); newCharPos = MovePositionOutsideChar(newCharPos, -1); inDragDrop = ddNone; sel.SetMoveExtends(false); if (NotifyMarginClick(pt, modifiers)) return; NotifyIndicatorClick(true, newPos.Position(), modifiers); const bool inSelMargin = PointInSelMargin(pt); // In margin ctrl+(double)click should always select everything if (ctrl && inSelMargin) { SelectAll(); lastClickTime = curTime; lastClick = pt; return; } if (shift && !inSelMargin) { SetSelection(newPos); } if ((curTime < (lastClickTime+Platform::DoubleClickTime())) && Close(pt, lastClick, doubleClickCloseThreshold)) { //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime); SetMouseCapture(true); FineTickerStart(tickScroll, 100, 10); if (!ctrl || !multipleSelection || (selectionType != selChar && selectionType != selWord)) SetEmptySelection(newPos.Position()); bool doubleClick = false; if (inSelMargin) { // Inside margin selection type should be either selSubLine or selWholeLine. if (selectionType == selSubLine) { // If it is selSubLine, we're inside a *double* click and word wrap is enabled, // so we switch to selWholeLine in order to select whole line. selectionType = selWholeLine; } else if (selectionType != selSubLine && selectionType != selWholeLine) { // If it is neither, reset selection type to line selection. selectionType = (Wrapping() && (marginOptions & SC_MARGINOPTION_SUBLINESELECT)) ? selSubLine : selWholeLine; } } else { if (selectionType == selChar) { selectionType = selWord; doubleClick = true; } else if (selectionType == selWord) { // Since we ended up here, we're inside a *triple* click, which should always select // whole line regardless of word wrap being enabled or not. selectionType = selWholeLine; } else { selectionType = selChar; originalAnchorPos = sel.MainCaret(); } } if (selectionType == selWord) { Sci::Position charPos = originalAnchorPos; if (sel.MainCaret() == originalAnchorPos) { charPos = PositionFromLocation(pt, false, true); charPos = MovePositionOutsideChar(charPos, -1); } Sci::Position startWord, endWord; if ((sel.MainCaret() >= originalAnchorPos) && !pdoc->IsLineEndPosition(charPos)) { startWord = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(charPos + 1, 1), -1); endWord = pdoc->ExtendWordSelect(charPos, 1); } else { // Selecting backwards, or anchor beyond last character on line. In these cases, // we select the word containing the character to the *left* of the anchor. if (charPos > pdoc->LineStart(pdoc->LineFromPosition(charPos))) { startWord = pdoc->ExtendWordSelect(charPos, -1); endWord = pdoc->ExtendWordSelect(startWord, 1); } else { // Anchor at start of line; select nothing to begin with. startWord = charPos; endWord = charPos; } } wordSelectAnchorStartPos = startWord; wordSelectAnchorEndPos = endWord; wordSelectInitialCaretPos = sel.MainCaret(); WordSelection(wordSelectInitialCaretPos); } else if (selectionType == selSubLine || selectionType == selWholeLine) { lineAnchorPos = newPos.Position(); LineSelection(lineAnchorPos, lineAnchorPos, selectionType == selWholeLine); //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos); } else { SetEmptySelection(sel.MainCaret()); } //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos); if (doubleClick) { NotifyDoubleClick(pt, modifiers); if (PositionIsHotspot(newCharPos.Position())) NotifyHotSpotDoubleClicked(newCharPos.Position(), modifiers); } } else { // Single click if (inSelMargin) { if (sel.IsRectangular() || (sel.Count() > 1)) { InvalidateWholeSelection(); sel.Clear(); } sel.selType = Selection::selStream; if (!shift) { // Single click in margin: select whole line or only subline if word wrap is enabled lineAnchorPos = newPos.Position(); selectionType = (Wrapping() && (marginOptions & SC_MARGINOPTION_SUBLINESELECT)) ? selSubLine : selWholeLine; LineSelection(lineAnchorPos, lineAnchorPos, selectionType == selWholeLine); } else { // Single shift+click in margin: select from line anchor to clicked line if (sel.MainAnchor() > sel.MainCaret()) lineAnchorPos = sel.MainAnchor() - 1; else lineAnchorPos = sel.MainAnchor(); // Reset selection type if there is an empty selection. // This ensures that we don't end up stuck in previous selection mode, which is no longer valid. // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine. // This ensures that we continue selecting in the same selection mode. if (sel.Empty() || (selectionType != selSubLine && selectionType != selWholeLine)) selectionType = (Wrapping() && (marginOptions & SC_MARGINOPTION_SUBLINESELECT)) ? selSubLine : selWholeLine; LineSelection(newPos.Position(), lineAnchorPos, selectionType == selWholeLine); } SetDragPosition(SelectionPosition(Sci::invalidPosition)); SetMouseCapture(true); FineTickerStart(tickScroll, 100, 10); } else { if (PointIsHotspot(pt)) { NotifyHotSpotClicked(newCharPos.Position(), modifiers); hotSpotClickPos = newCharPos.Position(); } if (!shift) { if (PointInSelection(pt) && !SelectionEmpty()) inDragDrop = ddInitial; else inDragDrop = ddNone; } SetMouseCapture(true); FineTickerStart(tickScroll, 100, 10); if (inDragDrop != ddInitial) { SetDragPosition(SelectionPosition(Sci::invalidPosition)); if (!shift) { if (ctrl && multipleSelection) { const SelectionRange range(newPos); sel.TentativeSelection(range); InvalidateSelection(range, true); } else { InvalidateSelection(SelectionRange(newPos), true); if (sel.Count() > 1) Redraw(); if ((sel.Count() > 1) || (sel.selType != Selection::selStream)) sel.Clear(); sel.selType = alt ? Selection::selRectangle : Selection::selStream; SetSelection(newPos, newPos); } } SelectionPosition anchorCurrent = newPos; if (shift) anchorCurrent = sel.IsRectangular() ? sel.Rectangular().anchor : sel.RangeMain().anchor; sel.selType = alt ? Selection::selRectangle : Selection::selStream; selectionType = selChar; originalAnchorPos = sel.MainCaret(); sel.Rectangular() = SelectionRange(newPos, anchorCurrent); SetRectangularRange(); } } } lastClickTime = curTime; lastClick = pt; lastXChosen = static_cast(pt.x) + xOffset; ShowCaretAtCurrentPosition(); } void Editor::RightButtonDownWithModifiers(Point pt, unsigned int, int modifiers) { if (NotifyMarginRightClick(pt, modifiers)) return; } bool Editor::PositionIsHotspot(Sci::Position position) const { return vs.styles[pdoc->StyleIndexAt(position)].hotspot; } bool Editor::PointIsHotspot(Point pt) { const Sci::Position pos = PositionFromLocation(pt, true, true); if (pos == INVALID_POSITION) return false; return PositionIsHotspot(pos); } void Editor::SetHoverIndicatorPosition(Sci::Position position) { const Sci::Position hoverIndicatorPosPrev = hoverIndicatorPos; hoverIndicatorPos = INVALID_POSITION; if (!vs.indicatorsDynamic) return; if (position != INVALID_POSITION) { for (const IDecoration *deco : pdoc->decorations->View()) { if (vs.indicators[deco->Indicator()].IsDynamic()) { if (pdoc->decorations->ValueAt(deco->Indicator(), position)) { hoverIndicatorPos = position; } } } } if (hoverIndicatorPosPrev != hoverIndicatorPos) { Redraw(); } } void Editor::SetHoverIndicatorPoint(Point pt) { if (!vs.indicatorsDynamic) { SetHoverIndicatorPosition(INVALID_POSITION); } else { SetHoverIndicatorPosition(PositionFromLocation(pt, true, true)); } } void Editor::SetHotSpotRange(const Point *pt) { if (pt) { const Sci::Position pos = PositionFromLocation(*pt, false, true); // If we don't limit this to word characters then the // range can encompass more than the run range and then // the underline will not be drawn properly. Range hsNew; hsNew.start = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine); hsNew.end = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine); // Only invalidate the range if the hotspot range has changed... if (!(hsNew == hotspot)) { if (hotspot.Valid()) { InvalidateRange(hotspot.start, hotspot.end); } hotspot = hsNew; InvalidateRange(hotspot.start, hotspot.end); } } else { if (hotspot.Valid()) { InvalidateRange(hotspot.start, hotspot.end); } hotspot = Range(Sci::invalidPosition); } } Range Editor::GetHotSpotRange() const { return hotspot; } void Editor::ButtonMoveWithModifiers(Point pt, unsigned int, int modifiers) { if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) { DwellEnd(true); } SelectionPosition movePos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular())); movePos = MovePositionOutsideChar(movePos, sel.MainCaret() - movePos.Position()); if (inDragDrop == ddInitial) { if (DragThreshold(ptMouseLast, pt)) { SetMouseCapture(false); FineTickerCancel(tickScroll); SetDragPosition(movePos); CopySelectionRange(&drag); StartDrag(); } return; } ptMouseLast = pt; PRectangle rcClient = GetClientRectangle(); const Point ptOrigin = GetVisibleOriginInMain(); rcClient.Move(0, -ptOrigin.y); if ((dwellDelay < SC_TIME_FOREVER) && rcClient.Contains(pt)) { FineTickerStart(tickDwell, dwellDelay, dwellDelay/10); } //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y); if (HaveMouseCapture()) { // Slow down autoscrolling/selection autoScrollTimer.ticksToWait -= timer.tickSize; if (autoScrollTimer.ticksToWait > 0) return; autoScrollTimer.ticksToWait = autoScrollDelay; // Adjust selection if (posDrag.IsValid()) { SetDragPosition(movePos); } else { if (selectionType == selChar) { if (sel.selType == Selection::selStream && (modifiers & SCI_ALT) && mouseSelectionRectangularSwitch) { sel.selType = Selection::selRectangle; } if (sel.IsRectangular()) { sel.Rectangular() = SelectionRange(movePos, sel.Rectangular().anchor); SetSelection(movePos, sel.RangeMain().anchor); } else if (sel.Count() > 1) { InvalidateSelection(sel.RangeMain(), false); const SelectionRange range(movePos, sel.RangeMain().anchor); sel.TentativeSelection(range); InvalidateSelection(range, true); } else { SetSelection(movePos, sel.RangeMain().anchor); } } else if (selectionType == selWord) { // Continue selecting by word if (movePos.Position() == wordSelectInitialCaretPos) { // Didn't move // No need to do anything. Previously this case was lumped // in with "Moved forward", but that can be harmful in this // case: a handler for the NotifyDoubleClick re-adjusts // the selection for a fancier definition of "word" (for // example, in Perl it is useful to include the leading // '$', '%' or '@' on variables for word selection). In this // the ButtonMove() called via TickFor() for auto-scrolling // could result in the fancier word selection adjustment // being unmade. } else { wordSelectInitialCaretPos = -1; WordSelection(movePos.Position()); } } else { // Continue selecting by line LineSelection(movePos.Position(), lineAnchorPos, selectionType == selWholeLine); } } // Autoscroll const Sci::Line lineMove = DisplayFromPosition(movePos.Position()); if (pt.y > rcClient.bottom) { ScrollTo(lineMove - LinesOnScreen() + 1); Redraw(); } else if (pt.y < rcClient.top) { ScrollTo(lineMove); Redraw(); } EnsureCaretVisible(false, false, true); if (hotspot.Valid() && !PointIsHotspot(pt)) SetHotSpotRange(nullptr); if (hotSpotClickPos != INVALID_POSITION && PositionFromLocation(pt, true, true) != hotSpotClickPos) { if (inDragDrop == ddNone) { DisplayCursor(Window::cursorText); } hotSpotClickPos = INVALID_POSITION; } } else { if (vs.fixedColumnWidth > 0) { // There is a margin if (PointInSelMargin(pt)) { DisplayCursor(GetMarginCursor(pt)); SetHotSpotRange(nullptr); return; // No need to test for selection } } // Display regular (drag) cursor over selection if (PointInSelection(pt) && !SelectionEmpty()) { DisplayCursor(Window::cursorArrow); } else { SetHoverIndicatorPoint(pt); if (PointIsHotspot(pt)) { DisplayCursor(Window::cursorHand); SetHotSpotRange(&pt); } else { if (hoverIndicatorPos != Sci::invalidPosition) DisplayCursor(Window::cursorHand); else DisplayCursor(Window::cursorText); SetHotSpotRange(nullptr); } } } } void Editor::ButtonUpWithModifiers(Point pt, unsigned int curTime, int modifiers) { //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop); SelectionPosition newPos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular())); if (hoverIndicatorPos != INVALID_POSITION) InvalidateRange(newPos.Position(), newPos.Position() + 1); newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position()); if (inDragDrop == ddInitial) { inDragDrop = ddNone; SetEmptySelection(newPos); selectionType = selChar; originalAnchorPos = sel.MainCaret(); } if (hotSpotClickPos != INVALID_POSITION && PointIsHotspot(pt)) { hotSpotClickPos = INVALID_POSITION; SelectionPosition newCharPos = SPositionFromLocation(pt, false, true, false); newCharPos = MovePositionOutsideChar(newCharPos, -1); NotifyHotSpotReleaseClick(newCharPos.Position(), modifiers & SCI_CTRL); } if (HaveMouseCapture()) { if (PointInSelMargin(pt)) { DisplayCursor(GetMarginCursor(pt)); } else { DisplayCursor(Window::cursorText); SetHotSpotRange(nullptr); } ptMouseLast = pt; SetMouseCapture(false); FineTickerCancel(tickScroll); NotifyIndicatorClick(false, newPos.Position(), 0); if (inDragDrop == ddDragging) { const SelectionPosition selStart = SelectionStart(); const SelectionPosition selEnd = SelectionEnd(); if (selStart < selEnd) { if (drag.Length()) { const Sci::Position length = drag.Length(); if (modifiers & SCI_CTRL) { const Sci::Position lengthInserted = pdoc->InsertString( newPos.Position(), drag.Data(), length); if (lengthInserted > 0) { SetSelection(newPos.Position(), newPos.Position() + lengthInserted); } } else if (newPos < selStart) { pdoc->DeleteChars(selStart.Position(), drag.Length()); const Sci::Position lengthInserted = pdoc->InsertString( newPos.Position(), drag.Data(), length); if (lengthInserted > 0) { SetSelection(newPos.Position(), newPos.Position() + lengthInserted); } } else if (newPos > selEnd) { pdoc->DeleteChars(selStart.Position(), drag.Length()); newPos.Add(-static_cast(drag.Length())); const Sci::Position lengthInserted = pdoc->InsertString( newPos.Position(), drag.Data(), length); if (lengthInserted > 0) { SetSelection(newPos.Position(), newPos.Position() + lengthInserted); } } else { SetEmptySelection(newPos.Position()); } drag.Clear(); } selectionType = selChar; } } else { if (selectionType == selChar) { if (sel.Count() > 1) { sel.RangeMain() = SelectionRange(newPos, sel.Range(sel.Count() - 1).anchor); InvalidateWholeSelection(); } else { SetSelection(newPos, sel.RangeMain().anchor); } } sel.CommitTentative(); } SetRectangularRange(); lastClickTime = curTime; lastClick = pt; lastXChosen = static_cast(pt.x) + xOffset; if (sel.selType == Selection::selStream) { SetLastXChosen(); } inDragDrop = ddNone; EnsureCaretVisible(false); } } bool Editor::Idle() { bool needWrap = Wrapping() && wrapPending.NeedsWrap(); if (needWrap) { // Wrap lines during idle. WrapLines(WrapScope::wsIdle); // No more wrapping needWrap = wrapPending.NeedsWrap(); } else if (needIdleStyling) { IdleStyling(); } // Add more idle things to do here, but make sure idleDone is // set correctly before the function returns. returning // false will stop calling this idle function until SetIdle() is // called again. const bool idleDone = !needWrap && !needIdleStyling; // && thatDone && theOtherThingDone... return !idleDone; } void Editor::TickFor(TickReason reason) { switch (reason) { case tickCaret: caret.on = !caret.on; if (caret.active) { InvalidateCaret(); } break; case tickScroll: // Auto scroll ButtonMoveWithModifiers(ptMouseLast, 0, 0); break; case tickWiden: SetScrollBars(); FineTickerCancel(tickWiden); break; case tickDwell: if ((!HaveMouseCapture()) && (ptMouseLast.y >= 0)) { dwelling = true; NotifyDwelling(ptMouseLast, dwelling); } FineTickerCancel(tickDwell); break; default: // tickPlatform handled by subclass break; } } // FineTickerStart is be overridden by subclasses that support fine ticking so // this method should never be called. bool Editor::FineTickerRunning(TickReason) { assert(false); return false; } // FineTickerStart is be overridden by subclasses that support fine ticking so // this method should never be called. void Editor::FineTickerStart(TickReason, int, int) { assert(false); } // FineTickerCancel is be overridden by subclasses that support fine ticking so // this method should never be called. void Editor::FineTickerCancel(TickReason) { assert(false); } void Editor::SetFocusState(bool focusState) { hasFocus = focusState; NotifyFocus(hasFocus); if (!hasFocus) { CancelModes(); } ShowCaretAtCurrentPosition(); } Sci::Position Editor::PositionAfterArea(PRectangle rcArea) const { // The start of the document line after the display line after the area // This often means that the line after a modification is restyled which helps // detect multiline comment additions and heals single line comments const Sci::Line lineAfter = TopLineOfMain() + static_cast(rcArea.bottom - 1) / vs.lineHeight + 1; if (lineAfter < pcs->LinesDisplayed()) return pdoc->LineStart(pcs->DocFromDisplay(lineAfter) + 1); else return pdoc->Length(); } // Style to a position within the view. If this causes a change at end of last line then // affects later lines so style all the viewed text. void Editor::StyleToPositionInView(Sci::Position pos) { Sci::Position endWindow = PositionAfterArea(GetClientDrawingRectangle()); if (pos > endWindow) pos = endWindow; const int styleAtEnd = pdoc->StyleIndexAt(pos-1); pdoc->EnsureStyledTo(pos); if ((endWindow > pos) && (styleAtEnd != pdoc->StyleIndexAt(pos-1))) { // Style at end of line changed so is multi-line change like starting a comment // so require rest of window to be styled. DiscardOverdraw(); // Prepared bitmaps may be invalid // DiscardOverdraw may have truncated client drawing area so recalculate endWindow endWindow = PositionAfterArea(GetClientDrawingRectangle()); pdoc->EnsureStyledTo(endWindow); } } Sci::Position Editor::PositionAfterMaxStyling(Sci::Position posMax, bool scrolling) const { if ((idleStyling == SC_IDLESTYLING_NONE) || (idleStyling == SC_IDLESTYLING_AFTERVISIBLE)) { // Both states do not limit styling return posMax; } // Try to keep time taken by styling reasonable so interaction remains smooth. // When scrolling, allow less time to ensure responsive const double secondsAllowed = scrolling ? 0.005 : 0.02; const Sci::Line linesToStyle = Sci::clamp(static_cast(secondsAllowed / pdoc->durationStyleOneLine.Duration()), 10, 0x10000); const Sci::Line stylingMaxLine = std::min( pdoc->SciLineFromPosition(pdoc->GetEndStyled()) + linesToStyle, pdoc->LinesTotal()); return std::min(pdoc->LineStart(stylingMaxLine), posMax); } void Editor::StartIdleStyling(bool truncatedLastStyling) { if ((idleStyling == SC_IDLESTYLING_ALL) || (idleStyling == SC_IDLESTYLING_AFTERVISIBLE)) { if (pdoc->GetEndStyled() < pdoc->Length()) { // Style remainder of document in idle time needIdleStyling = true; } } else if (truncatedLastStyling) { needIdleStyling = true; } if (needIdleStyling) { SetIdle(true); } } // Style for an area but bound the amount of styling to remain responsive void Editor::StyleAreaBounded(PRectangle rcArea, bool scrolling) { const Sci::Position posAfterArea = PositionAfterArea(rcArea); const Sci::Position posAfterMax = PositionAfterMaxStyling(posAfterArea, scrolling); if (posAfterMax < posAfterArea) { // Idle styling may be performed before current visible area // Style a bit now then style further in idle time pdoc->StyleToAdjustingLineDuration(posAfterMax); } else { // Can style all wanted now. StyleToPositionInView(posAfterArea); } StartIdleStyling(posAfterMax < posAfterArea); } void Editor::IdleStyling() { const Sci::Position posAfterArea = PositionAfterArea(GetClientRectangle()); const Sci::Position endGoal = (idleStyling >= SC_IDLESTYLING_AFTERVISIBLE) ? pdoc->Length() : posAfterArea; const Sci::Position posAfterMax = PositionAfterMaxStyling(endGoal, false); pdoc->StyleToAdjustingLineDuration(posAfterMax); if (pdoc->GetEndStyled() >= endGoal) { needIdleStyling = false; } } void Editor::IdleWork() { // Style the line after the modification as this allows modifications that change just the // line of the modification to heal instead of propagating to the rest of the window. if (workNeeded.items & WorkNeeded::workStyle) { StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(workNeeded.upTo) + 2)); } NotifyUpdateUI(); workNeeded.Reset(); } void Editor::QueueIdleWork(WorkNeeded::workItems items, Sci::Position upTo) { workNeeded.Need(items, upTo); } bool Editor::PaintContains(PRectangle rc) { if (rc.Empty()) { return true; } else { return rcPaint.Contains(rc); } } bool Editor::PaintContainsMargin() { if (wMargin.GetID()) { // With separate margin view, paint of text view // never contains margin. return false; } PRectangle rcSelMargin = GetClientRectangle(); rcSelMargin.right = static_cast(vs.textStart); return PaintContains(rcSelMargin); } void Editor::CheckForChangeOutsidePaint(Range r) { if (paintState == painting && !paintingAllText) { //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end); if (!r.Valid()) return; PRectangle rcRange = RectangleFromRange(r, 0); const PRectangle rcText = GetTextRectangle(); if (rcRange.top < rcText.top) { rcRange.top = rcText.top; } if (rcRange.bottom > rcText.bottom) { rcRange.bottom = rcText.bottom; } if (!PaintContains(rcRange)) { AbandonPaint(); paintAbandonedByStyling = true; } } } void Editor::SetBraceHighlight(Sci::Position pos0, Sci::Position pos1, int matchStyle) { if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) { if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) { CheckForChangeOutsidePaint(Range(braces[0])); CheckForChangeOutsidePaint(Range(pos0)); braces[0] = pos0; } if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) { CheckForChangeOutsidePaint(Range(braces[1])); CheckForChangeOutsidePaint(Range(pos1)); braces[1] = pos1; } bracesMatchStyle = matchStyle; if (paintState == notPainting) { Redraw(); } } } void Editor::SetAnnotationHeights(Sci::Line start, Sci::Line end) { if (vs.annotationVisible) { RefreshStyleData(); bool changedHeight = false; for (Sci::Line line=start; lineLinesTotal(); line++) { int linesWrapped = 1; if (Wrapping()) { AutoSurface surface(this); AutoLineLayout ll(view.llc, view.RetrieveLineLayout(line, *this)); if (surface && ll) { view.LayoutLine(*this, line, surface, vs, ll, wrapWidth); linesWrapped = ll->lines; } } if (pcs->SetHeight(line, pdoc->AnnotationLines(line) + linesWrapped)) changedHeight = true; } if (changedHeight) { Redraw(); } } } void Editor::SetDocPointer(Document *document) { //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document); pdoc->RemoveWatcher(this, 0); pdoc->Release(); if (!document) { pdoc = new Document(SC_DOCUMENTOPTION_DEFAULT); } else { pdoc = document; } pdoc->AddRef(); pcs = ContractionStateCreate(pdoc->IsLarge()); // Ensure all positions within document sel.Clear(); targetStart = 0; targetEnd = 0; braces[0] = Sci::invalidPosition; braces[1] = Sci::invalidPosition; vs.ReleaseAllExtendedStyles(); SetRepresentations(); // Reset the contraction state to fully shown. pcs->Clear(); pcs->InsertLines(0, pdoc->LinesTotal() - 1); SetAnnotationHeights(0, pdoc->LinesTotal()); view.llc.Deallocate(); NeedWrapping(); hotspot = Range(Sci::invalidPosition); hoverIndicatorPos = Sci::invalidPosition; view.ClearAllTabstops(); pdoc->AddWatcher(this, 0); SetScrollBars(); Redraw(); } void Editor::SetAnnotationVisible(int visible) { if (vs.annotationVisible != visible) { const bool changedFromOrToHidden = ((vs.annotationVisible != 0) != (visible != 0)); vs.annotationVisible = visible; if (changedFromOrToHidden) { const int dir = vs.annotationVisible ? 1 : -1; for (Sci::Line line=0; lineLinesTotal(); line++) { const int annotationLines = pdoc->AnnotationLines(line); if (annotationLines > 0) { pcs->SetHeight(line, pcs->GetHeight(line) + annotationLines * dir); } } SetScrollBars(); } Redraw(); } } /** * Recursively expand a fold, making lines visible except where they have an unexpanded parent. */ Sci::Line Editor::ExpandLine(Sci::Line line) { const Sci::Line lineMaxSubord = pdoc->GetLastChild(line); line++; while (line <= lineMaxSubord) { pcs->SetVisible(line, line, true); const int level = pdoc->GetLevel(line); if (level & SC_FOLDLEVELHEADERFLAG) { if (pcs->GetExpanded(line)) { line = ExpandLine(line); } else { line = pdoc->GetLastChild(line); } } line++; } return lineMaxSubord; } void Editor::SetFoldExpanded(Sci::Line lineDoc, bool expanded) { if (pcs->SetExpanded(lineDoc, expanded)) { RedrawSelMargin(); } } void Editor::FoldLine(Sci::Line line, int action) { if (line >= 0) { if (action == SC_FOLDACTION_TOGGLE) { if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) { line = pdoc->GetFoldParent(line); if (line < 0) return; } action = (pcs->GetExpanded(line)) ? SC_FOLDACTION_CONTRACT : SC_FOLDACTION_EXPAND; } if (action == SC_FOLDACTION_CONTRACT) { const Sci::Line lineMaxSubord = pdoc->GetLastChild(line); if (lineMaxSubord > line) { pcs->SetExpanded(line, false); pcs->SetVisible(line + 1, lineMaxSubord, false); const Sci::Line lineCurrent = pdoc->SciLineFromPosition(sel.MainCaret()); if (lineCurrent > line && lineCurrent <= lineMaxSubord) { // This does not re-expand the fold EnsureCaretVisible(); } } } else { if (!(pcs->GetVisible(line))) { EnsureLineVisible(line, false); GoToLine(line); } pcs->SetExpanded(line, true); ExpandLine(line); } SetScrollBars(); Redraw(); } } void Editor::FoldExpand(Sci::Line line, int action, int level) { bool expanding = action == SC_FOLDACTION_EXPAND; if (action == SC_FOLDACTION_TOGGLE) { expanding = !pcs->GetExpanded(line); } // Ensure child lines lexed and fold information extracted before // flipping the state. pdoc->GetLastChild(line, LevelNumber(level)); SetFoldExpanded(line, expanding); if (expanding && (pcs->HiddenLines() == 0)) // Nothing to do return; const Sci::Line lineMaxSubord = pdoc->GetLastChild(line, LevelNumber(level)); line++; pcs->SetVisible(line, lineMaxSubord, expanding); while (line <= lineMaxSubord) { const int levelLine = pdoc->GetLevel(line); if (levelLine & SC_FOLDLEVELHEADERFLAG) { SetFoldExpanded(line, expanding); } line++; } SetScrollBars(); Redraw(); } Sci::Line Editor::ContractedFoldNext(Sci::Line lineStart) const { for (Sci::Line line = lineStart; lineLinesTotal();) { if (!pcs->GetExpanded(line) && (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG)) return line; line = pcs->ContractedNext(line+1); if (line < 0) return -1; } return -1; } /** * Recurse up from this line to find any folds that prevent this line from being visible * and unfold them all. */ void Editor::EnsureLineVisible(Sci::Line lineDoc, bool enforcePolicy) { // In case in need of wrapping to ensure DisplayFromDoc works. if (lineDoc >= wrapPending.start) { if (WrapLines(WrapScope::wsAll)) { Redraw(); } } if (!pcs->GetVisible(lineDoc)) { // Back up to find a non-blank line Sci::Line lookLine = lineDoc; int lookLineLevel = pdoc->GetLevel(lookLine); while ((lookLine > 0) && (lookLineLevel & SC_FOLDLEVELWHITEFLAG)) { lookLineLevel = pdoc->GetLevel(--lookLine); } Sci::Line lineParent = pdoc->GetFoldParent(lookLine); if (lineParent < 0) { // Backed up to a top level line, so try to find parent of initial line lineParent = pdoc->GetFoldParent(lineDoc); } if (lineParent >= 0) { if (lineDoc != lineParent) EnsureLineVisible(lineParent, enforcePolicy); if (!pcs->GetExpanded(lineParent)) { pcs->SetExpanded(lineParent, true); ExpandLine(lineParent); } } SetScrollBars(); Redraw(); } if (enforcePolicy) { const Sci::Line lineDisplay = pcs->DisplayFromDoc(lineDoc); if (visiblePolicy & VISIBLE_SLOP) { if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) { SetTopLine(Sci::clamp(lineDisplay - visibleSlop, static_cast(0), MaxScrollPos())); SetVerticalScrollPos(); Redraw(); } else if ((lineDisplay > topLine + LinesOnScreen() - 1) || ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) { SetTopLine(Sci::clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, static_cast(0), MaxScrollPos())); SetVerticalScrollPos(); Redraw(); } } else { if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) { SetTopLine(Sci::clamp(lineDisplay - LinesOnScreen() / 2 + 1, static_cast(0), MaxScrollPos())); SetVerticalScrollPos(); Redraw(); } } } } void Editor::FoldAll(int action) { pdoc->EnsureStyledTo(pdoc->Length()); const Sci::Line maxLine = pdoc->LinesTotal(); bool expanding = action == SC_FOLDACTION_EXPAND; if (action == SC_FOLDACTION_TOGGLE) { // Discover current state for (int lineSeek = 0; lineSeek < maxLine; lineSeek++) { if (pdoc->GetLevel(lineSeek) & SC_FOLDLEVELHEADERFLAG) { expanding = !pcs->GetExpanded(lineSeek); break; } } } if (expanding) { pcs->SetVisible(0, maxLine-1, true); for (int line = 0; line < maxLine; line++) { const int levelLine = pdoc->GetLevel(line); if (levelLine & SC_FOLDLEVELHEADERFLAG) { SetFoldExpanded(line, true); } } } else { for (Sci::Line line = 0; line < maxLine; line++) { const int level = pdoc->GetLevel(line); if ((level & SC_FOLDLEVELHEADERFLAG) && (SC_FOLDLEVELBASE == LevelNumber(level))) { SetFoldExpanded(line, false); const Sci::Line lineMaxSubord = pdoc->GetLastChild(line, -1); if (lineMaxSubord > line) { pcs->SetVisible(line + 1, lineMaxSubord, false); } } } } SetScrollBars(); Redraw(); } void Editor::FoldChanged(Sci::Line line, int levelNow, int levelPrev) { if (levelNow & SC_FOLDLEVELHEADERFLAG) { if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) { // Adding a fold point. if (pcs->SetExpanded(line, true)) { RedrawSelMargin(); } FoldExpand(line, SC_FOLDACTION_EXPAND, levelPrev); } } else if (levelPrev & SC_FOLDLEVELHEADERFLAG) { const Sci::Line prevLine = line - 1; const int prevLineLevel = pdoc->GetLevel(prevLine); // Combining two blocks where the first block is collapsed (e.g. by deleting the line(s) which separate(s) the two blocks) if ((LevelNumber(prevLineLevel) == LevelNumber(levelNow)) && !pcs->GetVisible(prevLine)) FoldLine(pdoc->GetFoldParent(prevLine), SC_FOLDACTION_EXPAND); if (!pcs->GetExpanded(line)) { // Removing the fold from one that has been contracted so should expand // otherwise lines are left invisible with no way to make them visible if (pcs->SetExpanded(line, true)) { RedrawSelMargin(); } // Combining two blocks where the second one is collapsed (e.g. by adding characters in the line which separates the two blocks) FoldExpand(line, SC_FOLDACTION_EXPAND, levelPrev); } } if (!(levelNow & SC_FOLDLEVELWHITEFLAG) && (LevelNumber(levelPrev) > LevelNumber(levelNow))) { if (pcs->HiddenLines()) { // See if should still be hidden const Sci::Line parentLine = pdoc->GetFoldParent(line); if ((parentLine < 0) || (pcs->GetExpanded(parentLine) && pcs->GetVisible(parentLine))) { pcs->SetVisible(line, line, true); SetScrollBars(); Redraw(); } } } // Combining two blocks where the first one is collapsed (e.g. by adding characters in the line which separates the two blocks) if (!(levelNow & SC_FOLDLEVELWHITEFLAG) && (LevelNumber(levelPrev) < LevelNumber(levelNow))) { if (pcs->HiddenLines()) { const Sci::Line parentLine = pdoc->GetFoldParent(line); if (!pcs->GetExpanded(parentLine) && pcs->GetVisible(line)) FoldLine(parentLine, SC_FOLDACTION_EXPAND); } } } void Editor::NeedShown(Sci::Position pos, Sci::Position len) { if (foldAutomatic & SC_AUTOMATICFOLD_SHOW) { const Sci::Line lineStart = pdoc->SciLineFromPosition(pos); const Sci::Line lineEnd = pdoc->SciLineFromPosition(pos+len); for (Sci::Line line = lineStart; line <= lineEnd; line++) { EnsureLineVisible(line, false); } } else { NotifyNeedShown(pos, len); } } Sci::Position Editor::GetTag(char *tagValue, int tagNumber) { const char *text = nullptr; Sci::Position length = 0; if ((tagNumber >= 1) && (tagNumber <= 9)) { char name[3] = "\\?"; name[1] = static_cast(tagNumber + '0'); length = 2; text = pdoc->SubstituteByPosition(name, &length); } if (tagValue) { if (text) memcpy(tagValue, text, length + 1); else *tagValue = '\0'; } return length; } Sci::Position Editor::ReplaceTarget(bool replacePatterns, const char *text, Sci::Position length) { UndoGroup ug(pdoc); if (length == -1) length = strlen(text); if (replacePatterns) { text = pdoc->SubstituteByPosition(text, &length); if (!text) { return 0; } } if (targetStart != targetEnd) pdoc->DeleteChars(targetStart, targetEnd - targetStart); targetEnd = targetStart; const Sci::Position lengthInserted = pdoc->InsertString(targetStart, text, length); targetEnd = targetStart + lengthInserted; return length; } bool Editor::IsUnicodeMode() const { return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage); } int Editor::CodePage() const { if (pdoc) return pdoc->dbcsCodePage; else return 0; } Sci::Line Editor::WrapCount(Sci::Line line) { AutoSurface surface(this); AutoLineLayout ll(view.llc, view.RetrieveLineLayout(line, *this)); if (surface && ll) { view.LayoutLine(*this, line, surface, vs, ll, wrapWidth); return ll->lines; } else { return 1; } } void Editor::AddStyledText(const char *buffer, Sci::Position appendLength) { // The buffer consists of alternating character bytes and style bytes const Sci::Position textLength = appendLength / 2; std::string text(textLength, '\0'); Sci::Position i; for (i = 0; i < textLength; i++) { text[i] = buffer[i*2]; } const Sci::Position lengthInserted = pdoc->InsertString(CurrentPosition(), text.c_str(), textLength); for (i = 0; i < textLength; i++) { text[i] = buffer[i*2+1]; } pdoc->StartStyling(CurrentPosition(), static_cast(0xff)); pdoc->SetStyles(textLength, text.c_str()); SetEmptySelection(sel.MainCaret() + lengthInserted); } bool Editor::ValidMargin(uptr_t wParam) const { return wParam < vs.ms.size(); } void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { vs.EnsureStyle(wParam); switch (iMessage) { case SCI_STYLESETFORE: vs.styles[wParam].fore = ColourDesired(static_cast(lParam)); break; case SCI_STYLESETBACK: vs.styles[wParam].back = ColourDesired(static_cast(lParam)); break; case SCI_STYLESETBOLD: vs.styles[wParam].weight = lParam != 0 ? SC_WEIGHT_BOLD : SC_WEIGHT_NORMAL; break; case SCI_STYLESETWEIGHT: vs.styles[wParam].weight = static_cast(lParam); break; case SCI_STYLESETITALIC: vs.styles[wParam].italic = lParam != 0; break; case SCI_STYLESETEOLFILLED: vs.styles[wParam].eolFilled = lParam != 0; break; case SCI_STYLESETSIZE: vs.styles[wParam].size = static_cast(lParam * SC_FONT_SIZE_MULTIPLIER); break; case SCI_STYLESETSIZEFRACTIONAL: vs.styles[wParam].size = static_cast(lParam); break; case SCI_STYLESETFONT: if (lParam != 0) { vs.SetStyleFontName(static_cast(wParam), CharPtrFromSPtr(lParam)); } break; case SCI_STYLESETUNDERLINE: vs.styles[wParam].underline = lParam != 0; break; case SCI_STYLESETCASE: vs.styles[wParam].caseForce = static_cast(lParam); break; case SCI_STYLESETCHARACTERSET: vs.styles[wParam].characterSet = static_cast(lParam); pdoc->SetCaseFolder(nullptr); break; case SCI_STYLESETVISIBLE: vs.styles[wParam].visible = lParam != 0; break; case SCI_STYLESETCHANGEABLE: vs.styles[wParam].changeable = lParam != 0; break; case SCI_STYLESETHOTSPOT: vs.styles[wParam].hotspot = lParam != 0; break; } InvalidateStyleRedraw(); } sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { vs.EnsureStyle(wParam); switch (iMessage) { case SCI_STYLEGETFORE: return vs.styles[wParam].fore.AsInteger(); case SCI_STYLEGETBACK: return vs.styles[wParam].back.AsInteger(); case SCI_STYLEGETBOLD: return vs.styles[wParam].weight > SC_WEIGHT_NORMAL; case SCI_STYLEGETWEIGHT: return vs.styles[wParam].weight; case SCI_STYLEGETITALIC: return vs.styles[wParam].italic ? 1 : 0; case SCI_STYLEGETEOLFILLED: return vs.styles[wParam].eolFilled ? 1 : 0; case SCI_STYLEGETSIZE: return vs.styles[wParam].size / SC_FONT_SIZE_MULTIPLIER; case SCI_STYLEGETSIZEFRACTIONAL: return vs.styles[wParam].size; case SCI_STYLEGETFONT: return StringResult(lParam, vs.styles[wParam].fontName); case SCI_STYLEGETUNDERLINE: return vs.styles[wParam].underline ? 1 : 0; case SCI_STYLEGETCASE: return static_cast(vs.styles[wParam].caseForce); case SCI_STYLEGETCHARACTERSET: return vs.styles[wParam].characterSet; case SCI_STYLEGETVISIBLE: return vs.styles[wParam].visible ? 1 : 0; case SCI_STYLEGETCHANGEABLE: return vs.styles[wParam].changeable ? 1 : 0; case SCI_STYLEGETHOTSPOT: return vs.styles[wParam].hotspot ? 1 : 0; } return 0; } void Editor::SetSelectionNMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { InvalidateRange(sel.Range(wParam).Start().Position(), sel.Range(wParam).End().Position()); switch (iMessage) { case SCI_SETSELECTIONNCARET: sel.Range(wParam).caret.SetPosition(lParam); break; case SCI_SETSELECTIONNANCHOR: sel.Range(wParam).anchor.SetPosition(lParam); break; case SCI_SETSELECTIONNCARETVIRTUALSPACE: sel.Range(wParam).caret.SetVirtualSpace(lParam); break; case SCI_SETSELECTIONNANCHORVIRTUALSPACE: sel.Range(wParam).anchor.SetVirtualSpace(lParam); break; case SCI_SETSELECTIONNSTART: sel.Range(wParam).anchor.SetPosition(lParam); break; case SCI_SETSELECTIONNEND: sel.Range(wParam).caret.SetPosition(lParam); break; } InvalidateRange(sel.Range(wParam).Start().Position(), sel.Range(wParam).End().Position()); ContainerNeedsUpdate(SC_UPDATE_SELECTION); } sptr_t Editor::StringResult(sptr_t lParam, const char *val) { const size_t len = val ? strlen(val) : 0; if (lParam) { char *ptr = CharPtrFromSPtr(lParam); if (val) memcpy(ptr, val, len+1); else *ptr = 0; } return len; // Not including NUL } sptr_t Editor::BytesResult(sptr_t lParam, const unsigned char *val, size_t len) { // No NUL termination: len is number of valid/displayed bytes if ((lParam) && (len > 0)) { char *ptr = CharPtrFromSPtr(lParam); if (val) memcpy(ptr, val, len); else *ptr = 0; } return val ? len : 0; } sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam); // Optional macro recording hook if (recordingMacro) NotifyMacroRecord(iMessage, wParam, lParam); switch (iMessage) { case SCI_GETTEXT: { if (lParam == 0) return pdoc->Length() + 1; if (wParam == 0) return 0; char *ptr = CharPtrFromSPtr(lParam); unsigned int iChar = 0; for (; iChar < wParam - 1; iChar++) ptr[iChar] = pdoc->CharAt(iChar); ptr[iChar] = '\0'; return iChar; } case SCI_SETTEXT: { if (lParam == 0) return 0; UndoGroup ug(pdoc); pdoc->DeleteChars(0, pdoc->Length()); SetEmptySelection(0); const char *text = CharPtrFromSPtr(lParam); pdoc->InsertString(0, text, strlen(text)); return 1; } case SCI_GETTEXTLENGTH: return pdoc->Length(); case SCI_CUT: Cut(); SetLastXChosen(); break; case SCI_COPY: Copy(); break; case SCI_COPYALLOWLINE: CopyAllowLine(); break; case SCI_VERTICALCENTRECARET: VerticalCentreCaret(); break; case SCI_MOVESELECTEDLINESUP: MoveSelectedLinesUp(); break; case SCI_MOVESELECTEDLINESDOWN: MoveSelectedLinesDown(); break; case SCI_COPYRANGE: CopyRangeToClipboard(static_cast(wParam), lParam); break; case SCI_COPYTEXT: CopyText(wParam, CharPtrFromSPtr(lParam)); break; case SCI_PASTE: Paste(); if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); break; case SCI_CLEAR: Clear(); SetLastXChosen(); EnsureCaretVisible(); break; case SCI_UNDO: Undo(); SetLastXChosen(); break; case SCI_CANUNDO: return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0; case SCI_EMPTYUNDOBUFFER: pdoc->DeleteUndoHistory(); return 0; case SCI_GETFIRSTVISIBLELINE: return topLine; case SCI_SETFIRSTVISIBLELINE: ScrollTo(static_cast(wParam)); break; case SCI_GETLINE: { // Risk of overwriting the end of the buffer const Sci::Position lineStart = pdoc->LineStart(static_cast(wParam)); const Sci::Position lineEnd = pdoc->LineStart(static_cast(wParam + 1)); if (lParam == 0) { return lineEnd - lineStart; } char *ptr = CharPtrFromSPtr(lParam); Sci::Position iPlace = 0; for (Sci::Position iChar = lineStart; iChar < lineEnd; iChar++) { ptr[iPlace++] = pdoc->CharAt(iChar); } return iPlace; } case SCI_GETLINECOUNT: if (pdoc->LinesTotal() == 0) return 1; else return pdoc->LinesTotal(); case SCI_GETMODIFY: return !pdoc->IsSavePoint(); case SCI_SETSEL: { Sci::Position nStart = static_cast(wParam); Sci::Position nEnd = lParam; if (nEnd < 0) nEnd = pdoc->Length(); if (nStart < 0) nStart = nEnd; // Remove selection InvalidateSelection(SelectionRange(nStart, nEnd)); sel.Clear(); sel.selType = Selection::selStream; SetSelection(nEnd, nStart); EnsureCaretVisible(); } break; case SCI_GETSELTEXT: { SelectionText selectedText; CopySelectionRange(&selectedText); if (lParam == 0) { return selectedText.LengthWithTerminator(); } else { char *ptr = CharPtrFromSPtr(lParam); unsigned int iChar = 0; if (selectedText.Length()) { for (; iChar < selectedText.LengthWithTerminator(); iChar++) ptr[iChar] = selectedText.Data()[iChar]; } else { ptr[0] = '\0'; } return iChar; } } case SCI_LINEFROMPOSITION: if (static_cast(wParam) < 0) return 0; return pdoc->LineFromPosition(static_cast(wParam)); case SCI_POSITIONFROMLINE: if (static_cast(wParam) < 0) wParam = pdoc->LineFromPosition(SelectionStart().Position()); if (wParam == 0) return 0; // Even if there is no text, there is a first line that starts at 0 if (static_cast(wParam) > pdoc->LinesTotal()) return -1; //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway... // return -1; return pdoc->LineStart(static_cast(wParam)); // Replacement of the old Scintilla interpretation of EM_LINELENGTH case SCI_LINELENGTH: if ((static_cast(wParam) < 0) || (static_cast(wParam) > pdoc->LineFromPosition(pdoc->Length()))) return 0; return pdoc->LineStart(static_cast(wParam) + 1) - pdoc->LineStart(static_cast(wParam)); case SCI_REPLACESEL: { if (lParam == 0) return 0; UndoGroup ug(pdoc); ClearSelection(); const char *replacement = CharPtrFromSPtr(lParam); const Sci::Position lengthInserted = pdoc->InsertString( sel.MainCaret(), replacement, strlen(replacement)); SetEmptySelection(sel.MainCaret() + lengthInserted); SetLastXChosen(); EnsureCaretVisible(); } break; case SCI_SETTARGETSTART: targetStart = static_cast(wParam); break; case SCI_GETTARGETSTART: return targetStart; case SCI_SETTARGETEND: targetEnd = static_cast(wParam); break; case SCI_GETTARGETEND: return targetEnd; case SCI_SETTARGETRANGE: targetStart = static_cast(wParam); targetEnd = lParam; break; case SCI_TARGETWHOLEDOCUMENT: targetStart = 0; targetEnd = pdoc->Length(); break; case SCI_TARGETFROMSELECTION: if (sel.MainCaret() < sel.MainAnchor()) { targetStart = sel.MainCaret(); targetEnd = sel.MainAnchor(); } else { targetStart = sel.MainAnchor(); targetEnd = sel.MainCaret(); } break; case SCI_GETTARGETTEXT: { std::string text = RangeText(targetStart, targetEnd); return BytesResult(lParam, reinterpret_cast(text.c_str()), text.length()); } case SCI_REPLACETARGET: PLATFORM_ASSERT(lParam); return ReplaceTarget(false, CharPtrFromSPtr(lParam), static_cast(wParam)); case SCI_REPLACETARGETRE: PLATFORM_ASSERT(lParam); return ReplaceTarget(true, CharPtrFromSPtr(lParam), static_cast(wParam)); case SCI_SEARCHINTARGET: PLATFORM_ASSERT(lParam); return SearchInTarget(CharPtrFromSPtr(lParam), static_cast(wParam)); case SCI_SETSEARCHFLAGS: searchFlags = static_cast(wParam); break; case SCI_GETSEARCHFLAGS: return searchFlags; case SCI_GETTAG: return GetTag(CharPtrFromSPtr(lParam), static_cast(wParam)); case SCI_POSITIONBEFORE: return pdoc->MovePositionOutsideChar(static_cast(wParam) - 1, -1, true); case SCI_POSITIONAFTER: return pdoc->MovePositionOutsideChar(static_cast(wParam) + 1, 1, true); case SCI_POSITIONRELATIVE: return Sci::clamp(pdoc->GetRelativePosition( static_cast(wParam), lParam), static_cast(0), pdoc->Length()); case SCI_POSITIONRELATIVECODEUNITS: return Sci::clamp(pdoc->GetRelativePositionUTF16( static_cast(wParam), lParam), static_cast(0), pdoc->Length()); case SCI_LINESCROLL: ScrollTo(topLine + static_cast(lParam)); HorizontalScrollTo(xOffset + static_cast(wParam) * static_cast(vs.spaceWidth)); return 1; case SCI_SETXOFFSET: xOffset = static_cast(wParam); ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); SetHorizontalScrollPos(); Redraw(); break; case SCI_GETXOFFSET: return xOffset; case SCI_CHOOSECARETX: SetLastXChosen(); break; case SCI_SCROLLCARET: EnsureCaretVisible(); break; case SCI_SETREADONLY: pdoc->SetReadOnly(wParam != 0); return 1; case SCI_GETREADONLY: return pdoc->IsReadOnly(); case SCI_CANPASTE: return CanPaste(); case SCI_POINTXFROMPOSITION: if (lParam < 0) { return 0; } else { const Point pt = LocationFromPosition(lParam); // Convert to view-relative return static_cast(pt.x) - vs.textStart + vs.fixedColumnWidth; } case SCI_POINTYFROMPOSITION: if (lParam < 0) { return 0; } else { const Point pt = LocationFromPosition(lParam); return static_cast(pt.y); } case SCI_FINDTEXT: return FindText(wParam, lParam); case SCI_GETTEXTRANGE: { if (lParam == 0) return 0; Sci_TextRange *tr = static_cast(PtrFromSPtr(lParam)); Sci::Position cpMax = static_cast(tr->chrg.cpMax); if (cpMax == -1) cpMax = pdoc->Length(); PLATFORM_ASSERT(cpMax <= pdoc->Length()); Sci::Position len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len); // Spec says copied text is terminated with a NUL tr->lpstrText[len] = '\0'; return len; // Not including NUL } case SCI_HIDESELECTION: view.hideSelection = wParam != 0; Redraw(); break; case SCI_FORMATRANGE: return FormatRange(wParam != 0, static_cast(PtrFromSPtr(lParam))); case SCI_GETMARGINLEFT: return vs.leftMarginWidth; case SCI_GETMARGINRIGHT: return vs.rightMarginWidth; case SCI_SETMARGINLEFT: lastXChosen += static_cast(lParam) - vs.leftMarginWidth; vs.leftMarginWidth = static_cast(lParam); InvalidateStyleRedraw(); break; case SCI_SETMARGINRIGHT: vs.rightMarginWidth = static_cast(lParam); InvalidateStyleRedraw(); break; // Control specific mesages case SCI_ADDTEXT: { if (lParam == 0) return 0; const Sci::Position lengthInserted = pdoc->InsertString( CurrentPosition(), CharPtrFromSPtr(lParam), static_cast(wParam)); SetEmptySelection(sel.MainCaret() + lengthInserted); return 0; } case SCI_ADDSTYLEDTEXT: if (lParam) AddStyledText(CharPtrFromSPtr(lParam), static_cast(wParam)); return 0; case SCI_INSERTTEXT: { if (lParam == 0) return 0; Sci::Position insertPos = static_cast(wParam); if (insertPos == -1) insertPos = CurrentPosition(); Sci::Position newCurrent = CurrentPosition(); const char *sz = CharPtrFromSPtr(lParam); const Sci::Position lengthInserted = pdoc->InsertString(insertPos, sz, strlen(sz)); if (newCurrent > insertPos) newCurrent += lengthInserted; SetEmptySelection(newCurrent); return 0; } case SCI_CHANGEINSERTION: PLATFORM_ASSERT(lParam); pdoc->ChangeInsertion(CharPtrFromSPtr(lParam), static_cast(wParam)); return 0; case SCI_APPENDTEXT: pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), static_cast(wParam)); return 0; case SCI_CLEARALL: ClearAll(); return 0; case SCI_DELETERANGE: pdoc->DeleteChars(static_cast(wParam), lParam); return 0; case SCI_CLEARDOCUMENTSTYLE: ClearDocumentStyle(); return 0; case SCI_SETUNDOCOLLECTION: pdoc->SetUndoCollection(wParam != 0); return 0; case SCI_GETUNDOCOLLECTION: return pdoc->IsCollectingUndo(); case SCI_BEGINUNDOACTION: pdoc->BeginUndoAction(); return 0; case SCI_ENDUNDOACTION: pdoc->EndUndoAction(); return 0; case SCI_GETCARETPERIOD: return caret.period; case SCI_SETCARETPERIOD: CaretSetPeriod(static_cast(wParam)); break; case SCI_GETWORDCHARS: return pdoc->GetCharsOfClass(CharClassify::ccWord, UCharPtrFromSPtr(lParam)); case SCI_SETWORDCHARS: { pdoc->SetDefaultCharClasses(false); if (lParam == 0) return 0; pdoc->SetCharClasses(ConstUCharPtrFromSPtr(lParam), CharClassify::ccWord); } break; case SCI_GETWHITESPACECHARS: return pdoc->GetCharsOfClass(CharClassify::ccSpace, UCharPtrFromSPtr(lParam)); case SCI_SETWHITESPACECHARS: { if (lParam == 0) return 0; pdoc->SetCharClasses(ConstUCharPtrFromSPtr(lParam), CharClassify::ccSpace); } break; case SCI_GETPUNCTUATIONCHARS: return pdoc->GetCharsOfClass(CharClassify::ccPunctuation, UCharPtrFromSPtr(lParam)); case SCI_SETPUNCTUATIONCHARS: { if (lParam == 0) return 0; pdoc->SetCharClasses(ConstUCharPtrFromSPtr(lParam), CharClassify::ccPunctuation); } break; case SCI_SETCHARSDEFAULT: pdoc->SetDefaultCharClasses(true); break; case SCI_GETLENGTH: return pdoc->Length(); case SCI_ALLOCATE: pdoc->Allocate(static_cast(wParam)); break; case SCI_GETCHARAT: return pdoc->CharAt(static_cast(wParam)); case SCI_SETCURRENTPOS: if (sel.IsRectangular()) { sel.Rectangular().caret.SetPosition(static_cast(wParam)); SetRectangularRange(); Redraw(); } else { SetSelection(static_cast(wParam), sel.MainAnchor()); } break; case SCI_GETCURRENTPOS: return sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret(); case SCI_SETANCHOR: if (sel.IsRectangular()) { sel.Rectangular().anchor.SetPosition(static_cast(wParam)); SetRectangularRange(); Redraw(); } else { SetSelection(sel.MainCaret(), static_cast(wParam)); } break; case SCI_GETANCHOR: return sel.IsRectangular() ? sel.Rectangular().anchor.Position() : sel.MainAnchor(); case SCI_SETSELECTIONSTART: SetSelection(std::max(sel.MainCaret(), static_cast(wParam)), static_cast(wParam)); break; case SCI_GETSELECTIONSTART: return sel.LimitsForRectangularElseMain().start.Position(); case SCI_SETSELECTIONEND: SetSelection(static_cast(wParam), std::min(sel.MainAnchor(), static_cast(wParam))); break; case SCI_GETSELECTIONEND: return sel.LimitsForRectangularElseMain().end.Position(); case SCI_SETEMPTYSELECTION: SetEmptySelection(static_cast(wParam)); break; case SCI_SETPRINTMAGNIFICATION: view.printParameters.magnification = static_cast(wParam); break; case SCI_GETPRINTMAGNIFICATION: return view.printParameters.magnification; case SCI_SETPRINTCOLOURMODE: view.printParameters.colourMode = static_cast(wParam); break; case SCI_GETPRINTCOLOURMODE: return view.printParameters.colourMode; case SCI_SETPRINTWRAPMODE: view.printParameters.wrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone; break; case SCI_GETPRINTWRAPMODE: return view.printParameters.wrapState; case SCI_GETSTYLEAT: if (static_cast(wParam) >= pdoc->Length()) return 0; else return pdoc->StyleAt(static_cast(wParam)); case SCI_REDO: Redo(); break; case SCI_SELECTALL: SelectAll(); break; case SCI_SETSAVEPOINT: pdoc->SetSavePoint(); break; case SCI_GETSTYLEDTEXT: { if (lParam == 0) return 0; Sci_TextRange *tr = static_cast(PtrFromSPtr(lParam)); int iPlace = 0; for (long iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) { tr->lpstrText[iPlace++] = pdoc->CharAt(iChar); tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar); } tr->lpstrText[iPlace] = '\0'; tr->lpstrText[iPlace + 1] = '\0'; return iPlace; } case SCI_CANREDO: return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0; case SCI_MARKERLINEFROMHANDLE: return pdoc->LineFromHandle(static_cast(wParam)); case SCI_MARKERDELETEHANDLE: pdoc->DeleteMarkFromHandle(static_cast(wParam)); break; case SCI_GETVIEWWS: return vs.viewWhitespace; case SCI_SETVIEWWS: vs.viewWhitespace = static_cast(wParam); Redraw(); break; case SCI_GETTABDRAWMODE: return vs.tabDrawMode; case SCI_SETTABDRAWMODE: vs.tabDrawMode = static_cast(wParam); Redraw(); break; case SCI_GETWHITESPACESIZE: return vs.whitespaceSize; case SCI_SETWHITESPACESIZE: vs.whitespaceSize = static_cast(wParam); Redraw(); break; case SCI_POSITIONFROMPOINT: return PositionFromLocation(Point::FromInts(static_cast(wParam) - vs.ExternalMarginWidth(), static_cast(lParam)), false, false); case SCI_POSITIONFROMPOINTCLOSE: return PositionFromLocation(Point::FromInts(static_cast(wParam) - vs.ExternalMarginWidth(), static_cast(lParam)), true, false); case SCI_CHARPOSITIONFROMPOINT: return PositionFromLocation(Point::FromInts(static_cast(wParam) - vs.ExternalMarginWidth(), static_cast(lParam)), false, true); case SCI_CHARPOSITIONFROMPOINTCLOSE: return PositionFromLocation(Point::FromInts(static_cast(wParam) - vs.ExternalMarginWidth(), static_cast(lParam)), true, true); case SCI_GOTOLINE: GoToLine(static_cast(wParam)); break; case SCI_GOTOPOS: SetEmptySelection(static_cast(wParam)); EnsureCaretVisible(); break; case SCI_GETCURLINE: { const Sci::Line lineCurrentPos = pdoc->SciLineFromPosition(sel.MainCaret()); const Sci::Position lineStart = pdoc->LineStart(lineCurrentPos); const Sci::Position lineEnd = pdoc->LineStart(lineCurrentPos + 1); if (lParam == 0) { return 1 + lineEnd - lineStart; } PLATFORM_ASSERT(wParam > 0); char *ptr = CharPtrFromSPtr(lParam); unsigned int iPlace = 0; for (Sci::Position iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) { ptr[iPlace++] = pdoc->CharAt(iChar); } ptr[iPlace] = '\0'; return sel.MainCaret() - lineStart; } case SCI_GETENDSTYLED: return pdoc->GetEndStyled(); case SCI_GETEOLMODE: return pdoc->eolMode; case SCI_SETEOLMODE: pdoc->eolMode = static_cast(wParam); break; case SCI_SETLINEENDTYPESALLOWED: if (pdoc->SetLineEndTypesAllowed(static_cast(wParam))) { pcs->Clear(); pcs->InsertLines(0, pdoc->LinesTotal() - 1); SetAnnotationHeights(0, pdoc->LinesTotal()); InvalidateStyleRedraw(); } break; case SCI_GETLINEENDTYPESALLOWED: return pdoc->GetLineEndTypesAllowed(); case SCI_GETLINEENDTYPESACTIVE: return pdoc->GetLineEndTypesActive(); case SCI_STARTSTYLING: pdoc->StartStyling(static_cast(wParam), static_cast(lParam)); break; case SCI_SETSTYLING: if (static_cast(wParam) < 0) errorStatus = SC_STATUS_FAILURE; else pdoc->SetStyleFor(static_cast(wParam), static_cast(lParam)); break; case SCI_SETSTYLINGEX: // Specify a complete styling buffer if (lParam == 0) return 0; pdoc->SetStyles(static_cast(wParam), CharPtrFromSPtr(lParam)); break; case SCI_SETBUFFEREDDRAW: view.bufferedDraw = wParam != 0; break; case SCI_GETBUFFEREDDRAW: return view.bufferedDraw; case SCI_GETTWOPHASEDRAW: return view.phasesDraw == EditView::phasesTwo; case SCI_SETTWOPHASEDRAW: if (view.SetTwoPhaseDraw(wParam != 0)) InvalidateStyleRedraw(); break; case SCI_GETPHASESDRAW: return view.phasesDraw; case SCI_SETPHASESDRAW: if (view.SetPhasesDraw(static_cast(wParam))) InvalidateStyleRedraw(); break; case SCI_SETFONTQUALITY: vs.extraFontFlag &= ~SC_EFF_QUALITY_MASK; vs.extraFontFlag |= (wParam & SC_EFF_QUALITY_MASK); InvalidateStyleRedraw(); break; case SCI_GETFONTQUALITY: return (vs.extraFontFlag & SC_EFF_QUALITY_MASK); case SCI_SETTABWIDTH: if (wParam > 0) { pdoc->tabInChars = static_cast(wParam); if (pdoc->indentInChars == 0) pdoc->actualIndentInChars = pdoc->tabInChars; } InvalidateStyleRedraw(); break; case SCI_GETTABWIDTH: return pdoc->tabInChars; case SCI_CLEARTABSTOPS: if (view.ClearTabstops(static_cast(wParam))) { const DocModification mh(SC_MOD_CHANGETABSTOPS, 0, 0, 0, nullptr, static_cast(wParam)); NotifyModified(pdoc, mh, nullptr); } break; case SCI_ADDTABSTOP: if (view.AddTabstop(static_cast(wParam), static_cast(lParam))) { const DocModification mh(SC_MOD_CHANGETABSTOPS, 0, 0, 0, nullptr, static_cast(wParam)); NotifyModified(pdoc, mh, nullptr); } break; case SCI_GETNEXTTABSTOP: return view.GetNextTabstop(static_cast(wParam), static_cast(lParam)); case SCI_SETINDENT: pdoc->indentInChars = static_cast(wParam); if (pdoc->indentInChars != 0) pdoc->actualIndentInChars = pdoc->indentInChars; else pdoc->actualIndentInChars = pdoc->tabInChars; InvalidateStyleRedraw(); break; case SCI_GETINDENT: return pdoc->indentInChars; case SCI_SETUSETABS: pdoc->useTabs = wParam != 0; InvalidateStyleRedraw(); break; case SCI_GETUSETABS: return pdoc->useTabs; case SCI_SETLINEINDENTATION: pdoc->SetLineIndentation(static_cast(wParam), lParam); break; case SCI_GETLINEINDENTATION: return pdoc->GetLineIndentation(static_cast(wParam)); case SCI_GETLINEINDENTPOSITION: return pdoc->GetLineIndentPosition(static_cast(wParam)); case SCI_SETTABINDENTS: pdoc->tabIndents = wParam != 0; break; case SCI_GETTABINDENTS: return pdoc->tabIndents; case SCI_SETBACKSPACEUNINDENTS: pdoc->backspaceUnindents = wParam != 0; break; case SCI_GETBACKSPACEUNINDENTS: return pdoc->backspaceUnindents; case SCI_SETMOUSEDWELLTIME: dwellDelay = static_cast(wParam); ticksToDwell = dwellDelay; break; case SCI_GETMOUSEDWELLTIME: return dwellDelay; case SCI_WORDSTARTPOSITION: return pdoc->ExtendWordSelect(static_cast(wParam), -1, lParam != 0); case SCI_WORDENDPOSITION: return pdoc->ExtendWordSelect(static_cast(wParam), 1, lParam != 0); case SCI_ISRANGEWORD: return pdoc->IsWordAt(static_cast(wParam), lParam); case SCI_SETIDLESTYLING: idleStyling = static_cast(wParam); break; case SCI_GETIDLESTYLING: return idleStyling; case SCI_SETWRAPMODE: if (vs.SetWrapState(static_cast(wParam))) { xOffset = 0; ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); InvalidateStyleRedraw(); ReconfigureScrollBars(); } break; case SCI_GETWRAPMODE: return vs.wrapState; case SCI_SETWRAPVISUALFLAGS: if (vs.SetWrapVisualFlags(static_cast(wParam))) { InvalidateStyleRedraw(); ReconfigureScrollBars(); } break; case SCI_GETWRAPVISUALFLAGS: return vs.wrapVisualFlags; case SCI_SETWRAPVISUALFLAGSLOCATION: if (vs.SetWrapVisualFlagsLocation(static_cast(wParam))) { InvalidateStyleRedraw(); } break; case SCI_GETWRAPVISUALFLAGSLOCATION: return vs.wrapVisualFlagsLocation; case SCI_SETWRAPSTARTINDENT: if (vs.SetWrapVisualStartIndent(static_cast(wParam))) { InvalidateStyleRedraw(); ReconfigureScrollBars(); } break; case SCI_GETWRAPSTARTINDENT: return vs.wrapVisualStartIndent; case SCI_SETWRAPINDENTMODE: if (vs.SetWrapIndentMode(static_cast(wParam))) { InvalidateStyleRedraw(); ReconfigureScrollBars(); } break; case SCI_GETWRAPINDENTMODE: return vs.wrapIndentMode; case SCI_SETLAYOUTCACHE: view.llc.SetLevel(static_cast(wParam)); break; case SCI_GETLAYOUTCACHE: return view.llc.GetLevel(); case SCI_SETPOSITIONCACHE: view.posCache.SetSize(wParam); break; case SCI_GETPOSITIONCACHE: return view.posCache.GetSize(); case SCI_SETSCROLLWIDTH: PLATFORM_ASSERT(wParam > 0); if ((wParam > 0) && (wParam != static_cast(scrollWidth))) { view.lineWidthMaxSeen = 0; scrollWidth = static_cast(wParam); SetScrollBars(); } break; case SCI_GETSCROLLWIDTH: return scrollWidth; case SCI_SETSCROLLWIDTHTRACKING: trackLineWidth = wParam != 0; break; case SCI_GETSCROLLWIDTHTRACKING: return trackLineWidth; case SCI_LINESJOIN: LinesJoin(); break; case SCI_LINESSPLIT: LinesSplit(static_cast(wParam)); break; case SCI_TEXTWIDTH: PLATFORM_ASSERT(wParam < vs.styles.size()); PLATFORM_ASSERT(lParam); return TextWidth(static_cast(wParam), CharPtrFromSPtr(lParam)); case SCI_TEXTHEIGHT: RefreshStyleData(); return vs.lineHeight; case SCI_SETENDATLASTLINE: PLATFORM_ASSERT((wParam == 0) || (wParam == 1)); if (endAtLastLine != (wParam != 0)) { endAtLastLine = wParam != 0; SetScrollBars(); } break; case SCI_GETENDATLASTLINE: return endAtLastLine; case SCI_SETCARETSTICKY: PLATFORM_ASSERT(wParam <= SC_CARETSTICKY_WHITESPACE); if (wParam <= SC_CARETSTICKY_WHITESPACE) { caretSticky = static_cast(wParam); } break; case SCI_GETCARETSTICKY: return caretSticky; case SCI_TOGGLECARETSTICKY: caretSticky = !caretSticky; break; case SCI_GETCOLUMN: return pdoc->GetColumn(static_cast(wParam)); case SCI_FINDCOLUMN: return pdoc->FindColumn(static_cast(wParam), lParam); case SCI_SETHSCROLLBAR : if (horizontalScrollBarVisible != (wParam != 0)) { horizontalScrollBarVisible = wParam != 0; SetScrollBars(); ReconfigureScrollBars(); } break; case SCI_GETHSCROLLBAR: return horizontalScrollBarVisible; case SCI_SETVSCROLLBAR: if (verticalScrollBarVisible != (wParam != 0)) { verticalScrollBarVisible = wParam != 0; SetScrollBars(); ReconfigureScrollBars(); if (verticalScrollBarVisible) SetVerticalScrollPos(); } break; case SCI_GETVSCROLLBAR: return verticalScrollBarVisible; case SCI_SETINDENTATIONGUIDES: vs.viewIndentationGuides = static_cast(wParam); Redraw(); break; case SCI_GETINDENTATIONGUIDES: return vs.viewIndentationGuides; case SCI_SETHIGHLIGHTGUIDE: if ((highlightGuideColumn != static_cast(wParam)) || (wParam > 0)) { highlightGuideColumn = static_cast(wParam); Redraw(); } break; case SCI_GETHIGHLIGHTGUIDE: return highlightGuideColumn; case SCI_GETLINEENDPOSITION: return pdoc->LineEnd(static_cast(wParam)); case SCI_SETCODEPAGE: if (ValidCodePage(static_cast(wParam))) { if (pdoc->SetDBCSCodePage(static_cast(wParam))) { pcs->Clear(); pcs->InsertLines(0, pdoc->LinesTotal() - 1); SetAnnotationHeights(0, pdoc->LinesTotal()); InvalidateStyleRedraw(); SetRepresentations(); } } break; case SCI_GETCODEPAGE: return pdoc->dbcsCodePage; case SCI_SETIMEINTERACTION: imeInteraction = static_cast(wParam); break; case SCI_GETIMEINTERACTION: return imeInteraction; case SCI_GETLINECHARACTERINDEX: return pdoc->LineCharacterIndex(); case SCI_ALLOCATELINECHARACTERINDEX: pdoc->AllocateLineCharacterIndex(static_cast(wParam)); break; case SCI_RELEASELINECHARACTERINDEX: pdoc->ReleaseLineCharacterIndex(static_cast(wParam)); break; case SCI_LINEFROMINDEXPOSITION: return pdoc->LineFromPositionIndex(static_cast(wParam), static_cast(lParam)); case SCI_INDEXPOSITIONFROMLINE: return pdoc->IndexLineStart(static_cast(wParam), static_cast(lParam)); // Marker definition and setting case SCI_MARKERDEFINE: if (wParam <= MARKER_MAX) { vs.markers[wParam].markType = static_cast(lParam); vs.CalcLargestMarkerHeight(); } InvalidateStyleData(); RedrawSelMargin(); break; case SCI_MARKERSYMBOLDEFINED: if (wParam <= MARKER_MAX) return vs.markers[wParam].markType; else return 0; case SCI_MARKERSETFORE: if (wParam <= MARKER_MAX) vs.markers[wParam].fore = ColourDesired(static_cast(lParam)); InvalidateStyleData(); RedrawSelMargin(); break; case SCI_MARKERSETBACKSELECTED: if (wParam <= MARKER_MAX) vs.markers[wParam].backSelected = ColourDesired(static_cast(lParam)); InvalidateStyleData(); RedrawSelMargin(); break; case SCI_MARKERENABLEHIGHLIGHT: marginView.highlightDelimiter.isEnabled = wParam == 1; RedrawSelMargin(); break; case SCI_MARKERSETBACK: if (wParam <= MARKER_MAX) vs.markers[wParam].back = ColourDesired(static_cast(lParam)); InvalidateStyleData(); RedrawSelMargin(); break; case SCI_MARKERSETALPHA: if (wParam <= MARKER_MAX) vs.markers[wParam].alpha = static_cast(lParam); InvalidateStyleRedraw(); break; case SCI_MARKERADD: { const int markerID = pdoc->AddMark(static_cast(wParam), static_cast(lParam)); return markerID; } case SCI_MARKERADDSET: if (lParam != 0) pdoc->AddMarkSet(static_cast(wParam), static_cast(lParam)); break; case SCI_MARKERDELETE: pdoc->DeleteMark(static_cast(wParam), static_cast(lParam)); break; case SCI_MARKERDELETEALL: pdoc->DeleteAllMarks(static_cast(wParam)); break; case SCI_MARKERGET: return pdoc->GetMark(static_cast(wParam)); case SCI_MARKERNEXT: return pdoc->MarkerNext(static_cast(wParam), static_cast(lParam)); case SCI_MARKERPREVIOUS: { for (Sci::Line iLine = static_cast(wParam); iLine >= 0; iLine--) { if ((pdoc->GetMark(iLine) & lParam) != 0) return iLine; } } return -1; case SCI_MARKERDEFINEPIXMAP: if (wParam <= MARKER_MAX) { vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam)); vs.CalcLargestMarkerHeight(); } InvalidateStyleData(); RedrawSelMargin(); break; case SCI_RGBAIMAGESETWIDTH: sizeRGBAImage.x = static_cast(wParam); break; case SCI_RGBAIMAGESETHEIGHT: sizeRGBAImage.y = static_cast(wParam); break; case SCI_RGBAIMAGESETSCALE: scaleRGBAImage = static_cast(wParam); break; case SCI_MARKERDEFINERGBAIMAGE: if (wParam <= MARKER_MAX) { vs.markers[wParam].SetRGBAImage(sizeRGBAImage, scaleRGBAImage / 100.0f, ConstUCharPtrFromSPtr(lParam)); vs.CalcLargestMarkerHeight(); } InvalidateStyleData(); RedrawSelMargin(); break; case SCI_SETMARGINTYPEN: if (ValidMargin(wParam)) { vs.ms[wParam].style = static_cast(lParam); InvalidateStyleRedraw(); } break; case SCI_GETMARGINTYPEN: if (ValidMargin(wParam)) return vs.ms[wParam].style; else return 0; case SCI_SETMARGINWIDTHN: if (ValidMargin(wParam)) { // Short-circuit if the width is unchanged, to avoid unnecessary redraw. if (vs.ms[wParam].width != lParam) { lastXChosen += static_cast(lParam) - vs.ms[wParam].width; vs.ms[wParam].width = static_cast(lParam); InvalidateStyleRedraw(); } } break; case SCI_GETMARGINWIDTHN: if (ValidMargin(wParam)) return vs.ms[wParam].width; else return 0; case SCI_SETMARGINMASKN: if (ValidMargin(wParam)) { vs.ms[wParam].mask = static_cast(lParam); InvalidateStyleRedraw(); } break; case SCI_GETMARGINMASKN: if (ValidMargin(wParam)) return vs.ms[wParam].mask; else return 0; case SCI_SETMARGINSENSITIVEN: if (ValidMargin(wParam)) { vs.ms[wParam].sensitive = lParam != 0; InvalidateStyleRedraw(); } break; case SCI_GETMARGINSENSITIVEN: if (ValidMargin(wParam)) return vs.ms[wParam].sensitive ? 1 : 0; else return 0; case SCI_SETMARGINCURSORN: if (ValidMargin(wParam)) vs.ms[wParam].cursor = static_cast(lParam); break; case SCI_GETMARGINCURSORN: if (ValidMargin(wParam)) return vs.ms[wParam].cursor; else return 0; case SCI_SETMARGINBACKN: if (ValidMargin(wParam)) { vs.ms[wParam].back = ColourDesired(static_cast(lParam)); InvalidateStyleRedraw(); } break; case SCI_GETMARGINBACKN: if (ValidMargin(wParam)) return vs.ms[wParam].back.AsInteger(); else return 0; case SCI_SETMARGINS: if (wParam < 1000) vs.ms.resize(wParam); break; case SCI_GETMARGINS: return vs.ms.size(); case SCI_STYLECLEARALL: vs.ClearStyles(); InvalidateStyleRedraw(); break; case SCI_STYLESETFORE: case SCI_STYLESETBACK: case SCI_STYLESETBOLD: case SCI_STYLESETWEIGHT: case SCI_STYLESETITALIC: case SCI_STYLESETEOLFILLED: case SCI_STYLESETSIZE: case SCI_STYLESETSIZEFRACTIONAL: case SCI_STYLESETFONT: case SCI_STYLESETUNDERLINE: case SCI_STYLESETCASE: case SCI_STYLESETCHARACTERSET: case SCI_STYLESETVISIBLE: case SCI_STYLESETCHANGEABLE: case SCI_STYLESETHOTSPOT: StyleSetMessage(iMessage, wParam, lParam); break; case SCI_STYLEGETFORE: case SCI_STYLEGETBACK: case SCI_STYLEGETBOLD: case SCI_STYLEGETWEIGHT: case SCI_STYLEGETITALIC: case SCI_STYLEGETEOLFILLED: case SCI_STYLEGETSIZE: case SCI_STYLEGETSIZEFRACTIONAL: case SCI_STYLEGETFONT: case SCI_STYLEGETUNDERLINE: case SCI_STYLEGETCASE: case SCI_STYLEGETCHARACTERSET: case SCI_STYLEGETVISIBLE: case SCI_STYLEGETCHANGEABLE: case SCI_STYLEGETHOTSPOT: return StyleGetMessage(iMessage, wParam, lParam); case SCI_STYLERESETDEFAULT: vs.ResetDefaultStyle(); InvalidateStyleRedraw(); break; #ifdef INCLUDE_DEPRECATED_FEATURES case SCI_SETSTYLEBITS: vs.EnsureStyle(0xff); break; case SCI_GETSTYLEBITS: return 8; #endif case SCI_SETLINESTATE: return pdoc->SetLineState(static_cast(wParam), static_cast(lParam)); case SCI_GETLINESTATE: return pdoc->GetLineState(static_cast(wParam)); case SCI_GETMAXLINESTATE: return pdoc->GetMaxLineState(); case SCI_GETCARETLINEVISIBLE: return vs.showCaretLineBackground; case SCI_SETCARETLINEVISIBLE: vs.showCaretLineBackground = wParam != 0; InvalidateStyleRedraw(); break; case SCI_GETCARETLINEVISIBLEALWAYS: return vs.alwaysShowCaretLineBackground; case SCI_SETCARETLINEVISIBLEALWAYS: vs.alwaysShowCaretLineBackground = wParam != 0; InvalidateStyleRedraw(); break; case SCI_GETCARETLINEFRAME: return vs.caretLineFrame; case SCI_SETCARETLINEFRAME: vs.caretLineFrame = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_GETCARETLINEBACK: return vs.caretLineBackground.AsInteger(); case SCI_SETCARETLINEBACK: vs.caretLineBackground = ColourDesired(static_cast(wParam)); InvalidateStyleRedraw(); break; case SCI_GETCARETLINEBACKALPHA: return vs.caretLineAlpha; case SCI_SETCARETLINEBACKALPHA: vs.caretLineAlpha = static_cast(wParam); InvalidateStyleRedraw(); break; // Folding messages case SCI_VISIBLEFROMDOCLINE: return pcs->DisplayFromDoc(static_cast(wParam)); case SCI_DOCLINEFROMVISIBLE: return pcs->DocFromDisplay(static_cast(wParam)); case SCI_WRAPCOUNT: return WrapCount(static_cast(wParam)); case SCI_SETFOLDLEVEL: { const int prev = pdoc->SetLevel(static_cast(wParam), static_cast(lParam)); if (prev != static_cast(lParam)) RedrawSelMargin(); return prev; } case SCI_GETFOLDLEVEL: return pdoc->GetLevel(static_cast(wParam)); case SCI_GETLASTCHILD: return pdoc->GetLastChild(static_cast(wParam), static_cast(lParam)); case SCI_GETFOLDPARENT: return pdoc->GetFoldParent(static_cast(wParam)); case SCI_SHOWLINES: pcs->SetVisible(static_cast(wParam), static_cast(lParam), true); SetScrollBars(); Redraw(); break; case SCI_HIDELINES: if (wParam > 0) pcs->SetVisible(static_cast(wParam), static_cast(lParam), false); SetScrollBars(); Redraw(); break; case SCI_GETLINEVISIBLE: return pcs->GetVisible(static_cast(wParam)); case SCI_GETALLLINESVISIBLE: return pcs->HiddenLines() ? 0 : 1; case SCI_SETFOLDEXPANDED: SetFoldExpanded(static_cast(wParam), lParam != 0); break; case SCI_GETFOLDEXPANDED: return pcs->GetExpanded(static_cast(wParam)); case SCI_SETAUTOMATICFOLD: foldAutomatic = static_cast(wParam); break; case SCI_GETAUTOMATICFOLD: return foldAutomatic; case SCI_SETFOLDFLAGS: foldFlags = static_cast(wParam); Redraw(); break; case SCI_TOGGLEFOLDSHOWTEXT: pcs->SetFoldDisplayText(static_cast(wParam), CharPtrFromSPtr(lParam)); FoldLine(static_cast(wParam), SC_FOLDACTION_TOGGLE); break; case SCI_FOLDDISPLAYTEXTSETSTYLE: foldDisplayTextStyle = static_cast(wParam); Redraw(); break; case SCI_TOGGLEFOLD: FoldLine(static_cast(wParam), SC_FOLDACTION_TOGGLE); break; case SCI_FOLDLINE: FoldLine(static_cast(wParam), static_cast(lParam)); break; case SCI_FOLDCHILDREN: FoldExpand(static_cast(wParam), static_cast(lParam), pdoc->GetLevel(static_cast(wParam))); break; case SCI_FOLDALL: FoldAll(static_cast(wParam)); break; case SCI_EXPANDCHILDREN: FoldExpand(static_cast(wParam), SC_FOLDACTION_EXPAND, static_cast(lParam)); break; case SCI_CONTRACTEDFOLDNEXT: return ContractedFoldNext(static_cast(wParam)); case SCI_ENSUREVISIBLE: EnsureLineVisible(static_cast(wParam), false); break; case SCI_ENSUREVISIBLEENFORCEPOLICY: EnsureLineVisible(static_cast(wParam), true); break; case SCI_SCROLLRANGE: ScrollRange(SelectionRange(static_cast(wParam), lParam)); break; case SCI_SEARCHANCHOR: SearchAnchor(); break; case SCI_SEARCHNEXT: case SCI_SEARCHPREV: return SearchText(iMessage, wParam, lParam); case SCI_SETXCARETPOLICY: caretXPolicy = static_cast(wParam); caretXSlop = static_cast(lParam); break; case SCI_SETYCARETPOLICY: caretYPolicy = static_cast(wParam); caretYSlop = static_cast(lParam); break; case SCI_SETVISIBLEPOLICY: visiblePolicy = static_cast(wParam); visibleSlop = static_cast(lParam); break; case SCI_LINESONSCREEN: return LinesOnScreen(); case SCI_SETSELFORE: vs.selColours.fore = ColourOptional(wParam, lParam); vs.selAdditionalForeground = ColourDesired(static_cast(lParam)); InvalidateStyleRedraw(); break; case SCI_SETSELBACK: vs.selColours.back = ColourOptional(wParam, lParam); vs.selAdditionalBackground = ColourDesired(static_cast(lParam)); InvalidateStyleRedraw(); break; case SCI_SETSELALPHA: vs.selAlpha = static_cast(wParam); vs.selAdditionalAlpha = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_GETSELALPHA: return vs.selAlpha; case SCI_GETSELEOLFILLED: return vs.selEOLFilled; case SCI_SETSELEOLFILLED: vs.selEOLFilled = wParam != 0; InvalidateStyleRedraw(); break; case SCI_SETWHITESPACEFORE: vs.whitespaceColours.fore = ColourOptional(wParam, lParam); InvalidateStyleRedraw(); break; case SCI_SETWHITESPACEBACK: vs.whitespaceColours.back = ColourOptional(wParam, lParam); InvalidateStyleRedraw(); break; case SCI_SETCARETFORE: vs.caretcolour = ColourDesired(static_cast(wParam)); InvalidateStyleRedraw(); break; case SCI_GETCARETFORE: return vs.caretcolour.AsInteger(); case SCI_SETCARETSTYLE: if (wParam <= CARETSTYLE_BLOCK) vs.caretStyle = static_cast(wParam); else /* Default to the line caret */ vs.caretStyle = CARETSTYLE_LINE; InvalidateStyleRedraw(); break; case SCI_GETCARETSTYLE: return vs.caretStyle; case SCI_SETCARETWIDTH: vs.caretWidth = Sci::clamp(static_cast(wParam), 0, 3); InvalidateStyleRedraw(); break; case SCI_GETCARETWIDTH: return vs.caretWidth; case SCI_ASSIGNCMDKEY: kmap.AssignCmdKey(LowShortFromWParam(wParam), HighShortFromWParam(wParam), static_cast(lParam)); break; case SCI_CLEARCMDKEY: kmap.AssignCmdKey(LowShortFromWParam(wParam), HighShortFromWParam(wParam), SCI_NULL); break; case SCI_CLEARALLCMDKEYS: kmap.Clear(); break; case SCI_INDICSETSTYLE: if (wParam <= INDIC_MAX) { vs.indicators[wParam].sacNormal.style = static_cast(lParam); vs.indicators[wParam].sacHover.style = static_cast(lParam); InvalidateStyleRedraw(); } break; case SCI_INDICGETSTYLE: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].sacNormal.style : 0; case SCI_INDICSETFORE: if (wParam <= INDIC_MAX) { vs.indicators[wParam].sacNormal.fore = ColourDesired(static_cast(lParam)); vs.indicators[wParam].sacHover.fore = ColourDesired(static_cast(lParam)); InvalidateStyleRedraw(); } break; case SCI_INDICGETFORE: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].sacNormal.fore.AsInteger() : 0; case SCI_INDICSETHOVERSTYLE: if (wParam <= INDIC_MAX) { vs.indicators[wParam].sacHover.style = static_cast(lParam); InvalidateStyleRedraw(); } break; case SCI_INDICGETHOVERSTYLE: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].sacHover.style : 0; case SCI_INDICSETHOVERFORE: if (wParam <= INDIC_MAX) { vs.indicators[wParam].sacHover.fore = ColourDesired(static_cast(lParam)); InvalidateStyleRedraw(); } break; case SCI_INDICGETHOVERFORE: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].sacHover.fore.AsInteger() : 0; case SCI_INDICSETFLAGS: if (wParam <= INDIC_MAX) { vs.indicators[wParam].SetFlags(static_cast(lParam)); InvalidateStyleRedraw(); } break; case SCI_INDICGETFLAGS: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].Flags() : 0; case SCI_INDICSETUNDER: if (wParam <= INDIC_MAX) { vs.indicators[wParam].under = lParam != 0; InvalidateStyleRedraw(); } break; case SCI_INDICGETUNDER: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0; case SCI_INDICSETALPHA: if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) { vs.indicators[wParam].fillAlpha = static_cast(lParam); InvalidateStyleRedraw(); } break; case SCI_INDICGETALPHA: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fillAlpha : 0; case SCI_INDICSETOUTLINEALPHA: if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) { vs.indicators[wParam].outlineAlpha = static_cast(lParam); InvalidateStyleRedraw(); } break; case SCI_INDICGETOUTLINEALPHA: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].outlineAlpha : 0; case SCI_SETINDICATORCURRENT: pdoc->DecorationSetCurrentIndicator(static_cast(wParam)); break; case SCI_GETINDICATORCURRENT: return pdoc->decorations->GetCurrentIndicator(); case SCI_SETINDICATORVALUE: pdoc->decorations->SetCurrentValue(static_cast(wParam)); break; case SCI_GETINDICATORVALUE: return pdoc->decorations->GetCurrentValue(); case SCI_INDICATORFILLRANGE: pdoc->DecorationFillRange(static_cast(wParam), pdoc->decorations->GetCurrentValue(), lParam); break; case SCI_INDICATORCLEARRANGE: pdoc->DecorationFillRange(static_cast(wParam), 0, lParam); break; case SCI_INDICATORALLONFOR: return pdoc->decorations->AllOnFor(static_cast(wParam)); case SCI_INDICATORVALUEAT: return pdoc->decorations->ValueAt(static_cast(wParam), lParam); case SCI_INDICATORSTART: return pdoc->decorations->Start(static_cast(wParam), lParam); case SCI_INDICATOREND: return pdoc->decorations->End(static_cast(wParam), lParam); case SCI_LINEDOWN: case SCI_LINEDOWNEXTEND: case SCI_PARADOWN: case SCI_PARADOWNEXTEND: case SCI_LINEUP: case SCI_LINEUPEXTEND: case SCI_PARAUP: case SCI_PARAUPEXTEND: case SCI_CHARLEFT: case SCI_CHARLEFTEXTEND: case SCI_CHARRIGHT: case SCI_CHARRIGHTEXTEND: case SCI_WORDLEFT: case SCI_WORDLEFTEXTEND: case SCI_WORDRIGHT: case SCI_WORDRIGHTEXTEND: case SCI_WORDLEFTEND: case SCI_WORDLEFTENDEXTEND: case SCI_WORDRIGHTEND: case SCI_WORDRIGHTENDEXTEND: case SCI_HOME: case SCI_HOMEEXTEND: case SCI_LINEEND: case SCI_LINEENDEXTEND: case SCI_HOMEWRAP: case SCI_HOMEWRAPEXTEND: case SCI_LINEENDWRAP: case SCI_LINEENDWRAPEXTEND: case SCI_DOCUMENTSTART: case SCI_DOCUMENTSTARTEXTEND: case SCI_DOCUMENTEND: case SCI_DOCUMENTENDEXTEND: case SCI_SCROLLTOSTART: case SCI_SCROLLTOEND: case SCI_STUTTEREDPAGEUP: case SCI_STUTTEREDPAGEUPEXTEND: case SCI_STUTTEREDPAGEDOWN: case SCI_STUTTEREDPAGEDOWNEXTEND: case SCI_PAGEUP: case SCI_PAGEUPEXTEND: case SCI_PAGEDOWN: case SCI_PAGEDOWNEXTEND: case SCI_EDITTOGGLEOVERTYPE: case SCI_CANCEL: case SCI_DELETEBACK: case SCI_TAB: case SCI_BACKTAB: case SCI_NEWLINE: case SCI_FORMFEED: case SCI_VCHOME: case SCI_VCHOMEEXTEND: case SCI_VCHOMEWRAP: case SCI_VCHOMEWRAPEXTEND: case SCI_VCHOMEDISPLAY: case SCI_VCHOMEDISPLAYEXTEND: case SCI_ZOOMIN: case SCI_ZOOMOUT: case SCI_DELWORDLEFT: case SCI_DELWORDRIGHT: case SCI_DELWORDRIGHTEND: case SCI_DELLINELEFT: case SCI_DELLINERIGHT: case SCI_LINECOPY: case SCI_LINECUT: case SCI_LINEDELETE: case SCI_LINETRANSPOSE: case SCI_LINEREVERSE: case SCI_LINEDUPLICATE: case SCI_LOWERCASE: case SCI_UPPERCASE: case SCI_LINESCROLLDOWN: case SCI_LINESCROLLUP: case SCI_WORDPARTLEFT: case SCI_WORDPARTLEFTEXTEND: case SCI_WORDPARTRIGHT: case SCI_WORDPARTRIGHTEXTEND: case SCI_DELETEBACKNOTLINE: case SCI_HOMEDISPLAY: case SCI_HOMEDISPLAYEXTEND: case SCI_LINEENDDISPLAY: case SCI_LINEENDDISPLAYEXTEND: case SCI_LINEDOWNRECTEXTEND: case SCI_LINEUPRECTEXTEND: case SCI_CHARLEFTRECTEXTEND: case SCI_CHARRIGHTRECTEXTEND: case SCI_HOMERECTEXTEND: case SCI_VCHOMERECTEXTEND: case SCI_LINEENDRECTEXTEND: case SCI_PAGEUPRECTEXTEND: case SCI_PAGEDOWNRECTEXTEND: case SCI_SELECTIONDUPLICATE: return KeyCommand(iMessage); case SCI_BRACEHIGHLIGHT: SetBraceHighlight(static_cast(wParam), lParam, STYLE_BRACELIGHT); break; case SCI_BRACEHIGHLIGHTINDICATOR: if (lParam >= 0 && lParam <= INDIC_MAX) { vs.braceHighlightIndicatorSet = wParam != 0; vs.braceHighlightIndicator = static_cast(lParam); } break; case SCI_BRACEBADLIGHT: SetBraceHighlight(static_cast(wParam), -1, STYLE_BRACEBAD); break; case SCI_BRACEBADLIGHTINDICATOR: if (lParam >= 0 && lParam <= INDIC_MAX) { vs.braceBadLightIndicatorSet = wParam != 0; vs.braceBadLightIndicator = static_cast(lParam); } break; case SCI_BRACEMATCH: // wParam is position of char to find brace for, // lParam is maximum amount of text to restyle to find it return pdoc->BraceMatch(static_cast(wParam), lParam); case SCI_GETVIEWEOL: return vs.viewEOL; case SCI_SETVIEWEOL: vs.viewEOL = wParam != 0; InvalidateStyleRedraw(); break; case SCI_SETZOOM: { const int zoomLevel = static_cast(wParam); if (zoomLevel != vs.zoomLevel) { vs.zoomLevel = zoomLevel; InvalidateStyleRedraw(); NotifyZoom(); } break; } case SCI_GETZOOM: return vs.zoomLevel; case SCI_GETEDGECOLUMN: return vs.theEdge.column; case SCI_SETEDGECOLUMN: vs.theEdge.column = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_GETEDGEMODE: return vs.edgeState; case SCI_SETEDGEMODE: vs.edgeState = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_GETEDGECOLOUR: return vs.theEdge.colour.AsInteger(); case SCI_SETEDGECOLOUR: vs.theEdge.colour = ColourDesired(static_cast(wParam)); InvalidateStyleRedraw(); break; case SCI_MULTIEDGEADDLINE: vs.theMultiEdge.push_back(EdgeProperties(wParam, lParam)); InvalidateStyleRedraw(); break; case SCI_MULTIEDGECLEARALL: std::vector().swap(vs.theMultiEdge); // Free vector and memory, C++03 compatible InvalidateStyleRedraw(); break; case SCI_GETACCESSIBILITY: return SC_ACCESSIBILITY_DISABLED; case SCI_SETACCESSIBILITY: // May be implemented by platform code. break; case SCI_GETDOCPOINTER: return reinterpret_cast(pdoc); case SCI_SETDOCPOINTER: CancelModes(); SetDocPointer(static_cast(PtrFromSPtr(lParam))); return 0; case SCI_CREATEDOCUMENT: { Document *doc = new Document(static_cast(lParam)); doc->AddRef(); doc->Allocate(static_cast(wParam)); pcs = ContractionStateCreate(pdoc->IsLarge()); return reinterpret_cast(doc); } case SCI_ADDREFDOCUMENT: (static_cast(PtrFromSPtr(lParam)))->AddRef(); break; case SCI_RELEASEDOCUMENT: (static_cast(PtrFromSPtr(lParam)))->Release(); break; case SCI_GETDOCUMENTOPTIONS: return pdoc->Options(); case SCI_CREATELOADER: { Document *doc = new Document(static_cast(lParam)); doc->AddRef(); doc->Allocate(static_cast(wParam)); doc->SetUndoCollection(false); pcs = ContractionStateCreate(pdoc->IsLarge()); return reinterpret_cast(static_cast(doc)); } case SCI_SETMODEVENTMASK: modEventMask = static_cast(wParam); return 0; case SCI_GETMODEVENTMASK: return modEventMask; case SCI_SETCOMMANDEVENTS: commandEvents = static_cast(wParam); return 0; case SCI_GETCOMMANDEVENTS: return commandEvents; case SCI_CONVERTEOLS: pdoc->ConvertLineEnds(static_cast(wParam)); SetSelection(sel.MainCaret(), sel.MainAnchor()); // Ensure selection inside document return 0; case SCI_SETLENGTHFORENCODE: lengthForEncode = static_cast(wParam); return 0; case SCI_SELECTIONISRECTANGLE: return sel.selType == Selection::selRectangle ? 1 : 0; case SCI_SETSELECTIONMODE: { switch (wParam) { case SC_SEL_STREAM: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream)); sel.selType = Selection::selStream; break; case SC_SEL_RECTANGLE: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle)); sel.selType = Selection::selRectangle; sel.Rectangular() = sel.RangeMain(); // adjust current selection break; case SC_SEL_LINES: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines)); sel.selType = Selection::selLines; SetSelection(sel.RangeMain().caret, sel.RangeMain().anchor); // adjust current selection break; case SC_SEL_THIN: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin)); sel.selType = Selection::selThin; break; default: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream)); sel.selType = Selection::selStream; } InvalidateWholeSelection(); break; } case SCI_GETSELECTIONMODE: switch (sel.selType) { case Selection::selStream: return SC_SEL_STREAM; case Selection::selRectangle: return SC_SEL_RECTANGLE; case Selection::selLines: return SC_SEL_LINES; case Selection::selThin: return SC_SEL_THIN; default: // ?! return SC_SEL_STREAM; } case SCI_GETMOVEEXTENDSSELECTION: return sel.MoveExtends(); case SCI_GETLINESELSTARTPOSITION: case SCI_GETLINESELENDPOSITION: { const SelectionSegment segmentLine( SelectionPosition(pdoc->LineStart(static_cast(wParam))), SelectionPosition(pdoc->LineEnd(static_cast(wParam)))); for (size_t r=0; r(wParam); break; case SCI_GETSTATUS: return errorStatus; case SCI_SETMOUSEDOWNCAPTURES: mouseDownCaptures = wParam != 0; break; case SCI_GETMOUSEDOWNCAPTURES: return mouseDownCaptures; case SCI_SETMOUSEWHEELCAPTURES: mouseWheelCaptures = wParam != 0; break; case SCI_GETMOUSEWHEELCAPTURES: return mouseWheelCaptures; case SCI_SETCURSOR: cursorMode = static_cast(wParam); DisplayCursor(Window::cursorText); break; case SCI_GETCURSOR: return cursorMode; case SCI_SETCONTROLCHARSYMBOL: vs.controlCharSymbol = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_GETCONTROLCHARSYMBOL: return vs.controlCharSymbol; case SCI_SETREPRESENTATION: reprs.SetRepresentation(ConstCharPtrFromUPtr(wParam), ConstCharPtrFromSPtr(lParam)); break; case SCI_GETREPRESENTATION: { const Representation *repr = reprs.RepresentationFromCharacter( ConstCharPtrFromUPtr(wParam), UTF8MaxBytes); if (repr) { return StringResult(lParam, repr->stringRep.c_str()); } return 0; } case SCI_CLEARREPRESENTATION: reprs.ClearRepresentation(ConstCharPtrFromUPtr(wParam)); break; case SCI_STARTRECORD: recordingMacro = true; return 0; case SCI_STOPRECORD: recordingMacro = false; return 0; case SCI_MOVECARETINSIDEVIEW: MoveCaretInsideView(); break; case SCI_SETFOLDMARGINCOLOUR: vs.foldmarginColour = ColourOptional(wParam, lParam); InvalidateStyleRedraw(); break; case SCI_SETFOLDMARGINHICOLOUR: vs.foldmarginHighlightColour = ColourOptional(wParam, lParam); InvalidateStyleRedraw(); break; case SCI_SETHOTSPOTACTIVEFORE: vs.hotspotColours.fore = ColourOptional(wParam, lParam); InvalidateStyleRedraw(); break; case SCI_GETHOTSPOTACTIVEFORE: return vs.hotspotColours.fore.AsInteger(); case SCI_SETHOTSPOTACTIVEBACK: vs.hotspotColours.back = ColourOptional(wParam, lParam); InvalidateStyleRedraw(); break; case SCI_GETHOTSPOTACTIVEBACK: return vs.hotspotColours.back.AsInteger(); case SCI_SETHOTSPOTACTIVEUNDERLINE: vs.hotspotUnderline = wParam != 0; InvalidateStyleRedraw(); break; case SCI_GETHOTSPOTACTIVEUNDERLINE: return vs.hotspotUnderline ? 1 : 0; case SCI_SETHOTSPOTSINGLELINE: vs.hotspotSingleLine = wParam != 0; InvalidateStyleRedraw(); break; case SCI_GETHOTSPOTSINGLELINE: return vs.hotspotSingleLine ? 1 : 0; case SCI_SETPASTECONVERTENDINGS: convertPastes = wParam != 0; break; case SCI_GETPASTECONVERTENDINGS: return convertPastes ? 1 : 0; case SCI_GETCHARACTERPOINTER: return reinterpret_cast(pdoc->BufferPointer()); case SCI_GETRANGEPOINTER: return reinterpret_cast(pdoc->RangePointer( static_cast(wParam), lParam)); case SCI_GETGAPPOSITION: return pdoc->GapPosition(); case SCI_SETEXTRAASCENT: vs.extraAscent = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_GETEXTRAASCENT: return vs.extraAscent; case SCI_SETEXTRADESCENT: vs.extraDescent = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_GETEXTRADESCENT: return vs.extraDescent; case SCI_MARGINSETSTYLEOFFSET: vs.marginStyleOffset = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_MARGINGETSTYLEOFFSET: return vs.marginStyleOffset; case SCI_SETMARGINOPTIONS: marginOptions = static_cast(wParam); break; case SCI_GETMARGINOPTIONS: return marginOptions; case SCI_MARGINSETTEXT: pdoc->MarginSetText(static_cast(wParam), CharPtrFromSPtr(lParam)); break; case SCI_MARGINGETTEXT: { const StyledText st = pdoc->MarginStyledText(static_cast(wParam)); return BytesResult(lParam, reinterpret_cast(st.text), st.length); } case SCI_MARGINSETSTYLE: pdoc->MarginSetStyle(static_cast(wParam), static_cast(lParam)); break; case SCI_MARGINGETSTYLE: { const StyledText st = pdoc->MarginStyledText(static_cast(wParam)); return st.style; } case SCI_MARGINSETSTYLES: pdoc->MarginSetStyles(static_cast(wParam), ConstUCharPtrFromSPtr(lParam)); break; case SCI_MARGINGETSTYLES: { const StyledText st = pdoc->MarginStyledText(static_cast(wParam)); return BytesResult(lParam, st.styles, st.length); } case SCI_MARGINTEXTCLEARALL: pdoc->MarginClearAll(); break; case SCI_ANNOTATIONSETTEXT: pdoc->AnnotationSetText(static_cast(wParam), CharPtrFromSPtr(lParam)); break; case SCI_ANNOTATIONGETTEXT: { const StyledText st = pdoc->AnnotationStyledText(static_cast(wParam)); return BytesResult(lParam, reinterpret_cast(st.text), st.length); } case SCI_ANNOTATIONGETSTYLE: { const StyledText st = pdoc->AnnotationStyledText(static_cast(wParam)); return st.style; } case SCI_ANNOTATIONSETSTYLE: pdoc->AnnotationSetStyle(static_cast(wParam), static_cast(lParam)); break; case SCI_ANNOTATIONSETSTYLES: pdoc->AnnotationSetStyles(static_cast(wParam), ConstUCharPtrFromSPtr(lParam)); break; case SCI_ANNOTATIONGETSTYLES: { const StyledText st = pdoc->AnnotationStyledText(static_cast(wParam)); return BytesResult(lParam, st.styles, st.length); } case SCI_ANNOTATIONGETLINES: return pdoc->AnnotationLines(static_cast(wParam)); case SCI_ANNOTATIONCLEARALL: pdoc->AnnotationClearAll(); break; case SCI_ANNOTATIONSETVISIBLE: SetAnnotationVisible(static_cast(wParam)); break; case SCI_ANNOTATIONGETVISIBLE: return vs.annotationVisible; case SCI_ANNOTATIONSETSTYLEOFFSET: vs.annotationStyleOffset = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_ANNOTATIONGETSTYLEOFFSET: return vs.annotationStyleOffset; case SCI_RELEASEALLEXTENDEDSTYLES: vs.ReleaseAllExtendedStyles(); break; case SCI_ALLOCATEEXTENDEDSTYLES: return vs.AllocateExtendedStyles(static_cast(wParam)); case SCI_ADDUNDOACTION: pdoc->AddUndoAction(static_cast(wParam), lParam & UNDO_MAY_COALESCE); break; case SCI_SETMOUSESELECTIONRECTANGULARSWITCH: mouseSelectionRectangularSwitch = wParam != 0; break; case SCI_GETMOUSESELECTIONRECTANGULARSWITCH: return mouseSelectionRectangularSwitch; case SCI_SETMULTIPLESELECTION: multipleSelection = wParam != 0; InvalidateCaret(); break; case SCI_GETMULTIPLESELECTION: return multipleSelection; case SCI_SETADDITIONALSELECTIONTYPING: additionalSelectionTyping = wParam != 0; InvalidateCaret(); break; case SCI_GETADDITIONALSELECTIONTYPING: return additionalSelectionTyping; case SCI_SETMULTIPASTE: multiPasteMode = static_cast(wParam); break; case SCI_GETMULTIPASTE: return multiPasteMode; case SCI_SETADDITIONALCARETSBLINK: view.additionalCaretsBlink = wParam != 0; InvalidateCaret(); break; case SCI_GETADDITIONALCARETSBLINK: return view.additionalCaretsBlink; case SCI_SETADDITIONALCARETSVISIBLE: view.additionalCaretsVisible = wParam != 0; InvalidateCaret(); break; case SCI_GETADDITIONALCARETSVISIBLE: return view.additionalCaretsVisible; case SCI_GETSELECTIONS: return sel.Count(); case SCI_GETSELECTIONEMPTY: return sel.Empty(); case SCI_CLEARSELECTIONS: sel.Clear(); ContainerNeedsUpdate(SC_UPDATE_SELECTION); Redraw(); break; case SCI_SETSELECTION: sel.SetSelection(SelectionRange(static_cast(wParam), lParam)); Redraw(); break; case SCI_ADDSELECTION: sel.AddSelection(SelectionRange(static_cast(wParam), lParam)); ContainerNeedsUpdate(SC_UPDATE_SELECTION); Redraw(); break; case SCI_DROPSELECTIONN: sel.DropSelection(static_cast(wParam)); ContainerNeedsUpdate(SC_UPDATE_SELECTION); Redraw(); break; case SCI_SETMAINSELECTION: sel.SetMain(static_cast(wParam)); ContainerNeedsUpdate(SC_UPDATE_SELECTION); Redraw(); break; case SCI_GETMAINSELECTION: return sel.Main(); case SCI_SETSELECTIONNCARET: case SCI_SETSELECTIONNANCHOR: case SCI_SETSELECTIONNCARETVIRTUALSPACE: case SCI_SETSELECTIONNANCHORVIRTUALSPACE: case SCI_SETSELECTIONNSTART: case SCI_SETSELECTIONNEND: SetSelectionNMessage(iMessage, wParam, lParam); break; case SCI_GETSELECTIONNCARET: return sel.Range(wParam).caret.Position(); case SCI_GETSELECTIONNANCHOR: return sel.Range(wParam).anchor.Position(); case SCI_GETSELECTIONNCARETVIRTUALSPACE: return sel.Range(wParam).caret.VirtualSpace(); case SCI_GETSELECTIONNANCHORVIRTUALSPACE: return sel.Range(wParam).anchor.VirtualSpace(); case SCI_GETSELECTIONNSTART: return sel.Range(wParam).Start().Position(); case SCI_GETSELECTIONNEND: return sel.Range(wParam).End().Position(); case SCI_SETRECTANGULARSELECTIONCARET: if (!sel.IsRectangular()) sel.Clear(); sel.selType = Selection::selRectangle; sel.Rectangular().caret.SetPosition(static_cast(wParam)); SetRectangularRange(); Redraw(); break; case SCI_GETRECTANGULARSELECTIONCARET: return sel.Rectangular().caret.Position(); case SCI_SETRECTANGULARSELECTIONANCHOR: if (!sel.IsRectangular()) sel.Clear(); sel.selType = Selection::selRectangle; sel.Rectangular().anchor.SetPosition(static_cast(wParam)); SetRectangularRange(); Redraw(); break; case SCI_GETRECTANGULARSELECTIONANCHOR: return sel.Rectangular().anchor.Position(); case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE: if (!sel.IsRectangular()) sel.Clear(); sel.selType = Selection::selRectangle; sel.Rectangular().caret.SetVirtualSpace(static_cast(wParam)); SetRectangularRange(); Redraw(); break; case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE: return sel.Rectangular().caret.VirtualSpace(); case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE: if (!sel.IsRectangular()) sel.Clear(); sel.selType = Selection::selRectangle; sel.Rectangular().anchor.SetVirtualSpace(static_cast(wParam)); SetRectangularRange(); Redraw(); break; case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE: return sel.Rectangular().anchor.VirtualSpace(); case SCI_SETVIRTUALSPACEOPTIONS: virtualSpaceOptions = static_cast(wParam); break; case SCI_GETVIRTUALSPACEOPTIONS: return virtualSpaceOptions; case SCI_SETADDITIONALSELFORE: vs.selAdditionalForeground = ColourDesired(static_cast(wParam)); InvalidateStyleRedraw(); break; case SCI_SETADDITIONALSELBACK: vs.selAdditionalBackground = ColourDesired(static_cast(wParam)); InvalidateStyleRedraw(); break; case SCI_SETADDITIONALSELALPHA: vs.selAdditionalAlpha = static_cast(wParam); InvalidateStyleRedraw(); break; case SCI_GETADDITIONALSELALPHA: return vs.selAdditionalAlpha; case SCI_SETADDITIONALCARETFORE: vs.additionalCaretColour = ColourDesired(static_cast(wParam)); InvalidateStyleRedraw(); break; case SCI_GETADDITIONALCARETFORE: return vs.additionalCaretColour.AsInteger(); case SCI_ROTATESELECTION: sel.RotateMain(); InvalidateWholeSelection(); break; case SCI_SWAPMAINANCHORCARET: InvalidateSelection(sel.RangeMain()); sel.RangeMain().Swap(); break; case SCI_MULTIPLESELECTADDNEXT: MultipleSelectAdd(addOne); break; case SCI_MULTIPLESELECTADDEACH: MultipleSelectAdd(addEach); break; case SCI_CHANGELEXERSTATE: pdoc->ChangeLexerState(static_cast(wParam), lParam); break; case SCI_SETIDENTIFIER: SetCtrlID(static_cast(wParam)); break; case SCI_GETIDENTIFIER: return GetCtrlID(); case SCI_SETTECHNOLOGY: // No action by default break; case SCI_GETTECHNOLOGY: return technology; case SCI_COUNTCHARACTERS: return pdoc->CountCharacters(static_cast(wParam), lParam); case SCI_COUNTCODEUNITS: return pdoc->CountUTF16(static_cast(wParam), lParam); default: return DefWndProc(iMessage, wParam, lParam); } //Platform::DebugPrintf("end wnd proc\n"); return 0; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Editor.h000066400000000000000000000547701463772530400251730ustar00rootroot00000000000000// Scintilla source code edit control /** @file Editor.h ** Defines the main editor class. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef EDITOR_H #define EDITOR_H namespace Scintilla { /** */ class Timer { public: bool ticking; int ticksToWait; enum {tickSize = 100}; TickerID tickerID; Timer(); }; /** */ class Idler { public: bool state; IdlerID idlerID; Idler(); }; /** * When platform has a way to generate an event before painting, * accumulate needed styling range and other work items in * WorkNeeded to avoid unnecessary work inside paint handler */ class WorkNeeded { public: enum workItems { workNone=0, workStyle=1, workUpdateUI=2 }; enum workItems items; Sci::Position upTo; WorkNeeded() : items(workNone), upTo(0) {} void Reset() { items = workNone; upTo = 0; } void Need(workItems items_, Sci::Position pos) { if ((items_ & workStyle) && (upTo < pos)) upTo = pos; items = static_cast(items | items_); } }; /** * Hold a piece of text selected for copying or dragging, along with encoding and selection format information. */ class SelectionText { std::string s; public: bool rectangular; bool lineCopy; int codePage; int characterSet; SelectionText() : rectangular(false), lineCopy(false), codePage(0), characterSet(0) {} void Clear() { s.clear(); rectangular = false; lineCopy = false; codePage = 0; characterSet = 0; } void Copy(const std::string &s_, int codePage_, int characterSet_, bool rectangular_, bool lineCopy_) { s = s_; codePage = codePage_; characterSet = characterSet_; rectangular = rectangular_; lineCopy = lineCopy_; FixSelectionForClipboard(); } void Copy(const SelectionText &other) { Copy(other.s, other.codePage, other.characterSet, other.rectangular, other.lineCopy); } const char *Data() const { return s.c_str(); } size_t Length() const { return s.length(); } size_t LengthWithTerminator() const { return s.length() + 1; } bool Empty() const { return s.empty(); } private: void FixSelectionForClipboard() { // To avoid truncating the contents of the clipboard when pasted where the // clipboard contains NUL characters, replace NUL characters by spaces. std::replace(s.begin(), s.end(), '\0', ' '); } }; struct WrapPending { // The range of lines that need to be wrapped enum { lineLarge = 0x7ffffff }; Sci::Line start; // When there are wraps pending, will be in document range Sci::Line end; // May be lineLarge to indicate all of document after start WrapPending() { start = lineLarge; end = lineLarge; } void Reset() { start = lineLarge; end = lineLarge; } void Wrapped(Sci::Line line) { if (start == line) start++; } bool NeedsWrap() const { return start < end; } bool AddRange(Sci::Line lineStart, Sci::Line lineEnd) { const bool neededWrap = NeedsWrap(); bool changed = false; if (start > lineStart) { start = lineStart; changed = true; } if ((end < lineEnd) || !neededWrap) { end = lineEnd; changed = true; } return changed; } }; /** */ class Editor : public EditModel, public DocWatcher { protected: // ScintillaBase subclass needs access to much of Editor /** On GTK+, Scintilla is a container widget holding two scroll bars * whereas on Windows there is just one window with both scroll bars turned on. */ Window wMain; ///< The Scintilla parent window Window wMargin; ///< May be separate when using a scroll view for wMain /** Style resources may be expensive to allocate so are cached between uses. * When a style attribute is changed, this cache is flushed. */ bool stylesValid; ViewStyle vs; int technology; Point sizeRGBAImage; float scaleRGBAImage; MarginView marginView; EditView view; int cursorMode; bool hasFocus; bool mouseDownCaptures; bool mouseWheelCaptures; int xCaretMargin; ///< Ensure this many pixels visible on both sides of caret bool horizontalScrollBarVisible; int scrollWidth; bool verticalScrollBarVisible; bool endAtLastLine; int caretSticky; int marginOptions; bool mouseSelectionRectangularSwitch; bool multipleSelection; bool additionalSelectionTyping; int multiPasteMode; int virtualSpaceOptions; KeyMap kmap; Timer timer; Timer autoScrollTimer; enum { autoScrollDelay = 200 }; Idler idler; Point lastClick; unsigned int lastClickTime; Point doubleClickCloseThreshold; int dwellDelay; int ticksToDwell; bool dwelling; enum { selChar, selWord, selSubLine, selWholeLine } selectionType; Point ptMouseLast; enum { ddNone, ddInitial, ddDragging } inDragDrop; bool dropWentOutside; SelectionPosition posDrop; Sci::Position hotSpotClickPos; int lastXChosen; Sci::Position lineAnchorPos; Sci::Position originalAnchorPos; Sci::Position wordSelectAnchorStartPos; Sci::Position wordSelectAnchorEndPos; Sci::Position wordSelectInitialCaretPos; Sci::Position targetStart; Sci::Position targetEnd; int searchFlags; Sci::Line topLine; Sci::Position posTopLine; Sci::Position lengthForEncode; int needUpdateUI; enum { notPainting, painting, paintAbandoned } paintState; bool paintAbandonedByStyling; PRectangle rcPaint; bool paintingAllText; bool willRedrawAll; WorkNeeded workNeeded; int idleStyling; bool needIdleStyling; int modEventMask; bool commandEvents; SelectionText drag; int caretXPolicy; int caretXSlop; ///< Ensure this many pixels visible on both sides of caret int caretYPolicy; int caretYSlop; ///< Ensure this many lines visible on both sides of caret int visiblePolicy; int visibleSlop; Sci::Position searchAnchor; bool recordingMacro; int foldAutomatic; // Wrapping support WrapPending wrapPending; ActionDuration durationWrapOneLine; bool convertPastes; Editor(); // Deleted so Editor objects can not be copied. Editor(const Editor &) = delete; Editor(Editor &&) = delete; Editor &operator=(const Editor &) = delete; Editor &operator=(Editor &&) = delete; ~Editor() override; virtual void Initialise() = 0; virtual void Finalise(); void InvalidateStyleData(); void InvalidateStyleRedraw(); void RefreshStyleData(); void SetRepresentations(); void DropGraphics(bool freeObjects); void AllocateGraphics(); // The top left visible point in main window coordinates. Will be 0,0 except for // scroll views where it will be equivalent to the current scroll position. Point GetVisibleOriginInMain() const override; PointDocument DocumentPointFromView(Point ptView) const; // Convert a point from view space to document Sci::Line TopLineOfMain() const override; // Return the line at Main's y coordinate 0 virtual PRectangle GetClientRectangle() const; virtual PRectangle GetClientDrawingRectangle(); PRectangle GetTextRectangle() const; Sci::Line LinesOnScreen() const override; Sci::Line LinesToScroll() const; Sci::Line MaxScrollPos() const; SelectionPosition ClampPositionIntoDocument(SelectionPosition sp) const; Point LocationFromPosition(SelectionPosition pos, PointEnd pe=peDefault); Point LocationFromPosition(Sci::Position pos, PointEnd pe=peDefault); int XFromPosition(SelectionPosition sp); SelectionPosition SPositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false, bool virtualSpace=true); Sci::Position PositionFromLocation(Point pt, bool canReturnInvalid = false, bool charPosition = false); SelectionPosition SPositionFromLineX(Sci::Line lineDoc, int x); Sci::Position PositionFromLineX(Sci::Line lineDoc, int x); Sci::Line LineFromLocation(Point pt) const; void SetTopLine(Sci::Line topLineNew); virtual bool AbandonPaint(); virtual void RedrawRect(PRectangle rc); virtual void DiscardOverdraw(); virtual void Redraw(); void RedrawSelMargin(Sci::Line line=-1, bool allAfter=false); PRectangle RectangleFromRange(Range r, int overlap); void InvalidateRange(Sci::Position start, Sci::Position end); bool UserVirtualSpace() const { return ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0); } Sci::Position CurrentPosition() const; bool SelectionEmpty() const; SelectionPosition SelectionStart(); SelectionPosition SelectionEnd(); void SetRectangularRange(); void ThinRectangularRange(); void InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection=false); void InvalidateWholeSelection(); SelectionRange LineSelectionRange(SelectionPosition currentPos_, SelectionPosition anchor_) const; void SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_); void SetSelection(Sci::Position currentPos_, Sci::Position anchor_); void SetSelection(SelectionPosition currentPos_); void SetSelection(int currentPos_); void SetEmptySelection(SelectionPosition currentPos_); void SetEmptySelection(Sci::Position currentPos_); enum AddNumber { addOne, addEach }; void MultipleSelectAdd(AddNumber addNumber); bool RangeContainsProtected(Sci::Position start, Sci::Position end) const; bool SelectionContainsProtected(); Sci::Position MovePositionOutsideChar(Sci::Position pos, Sci::Position moveDir, bool checkLineEnd=true) const; SelectionPosition MovePositionOutsideChar(SelectionPosition pos, Sci::Position moveDir, bool checkLineEnd=true) const; void MovedCaret(SelectionPosition newPos, SelectionPosition previousPos, bool ensureVisible); void MovePositionTo(SelectionPosition newPos, Selection::selTypes selt=Selection::noSel, bool ensureVisible=true); void MovePositionTo(Sci::Position newPos, Selection::selTypes selt=Selection::noSel, bool ensureVisible=true); SelectionPosition MovePositionSoVisible(SelectionPosition pos, int moveDir); SelectionPosition MovePositionSoVisible(Sci::Position pos, int moveDir); Point PointMainCaret(); void SetLastXChosen(); void ScrollTo(Sci::Line line, bool moveThumb=true); virtual void ScrollText(Sci::Line linesToMove); void HorizontalScrollTo(int xPos); void VerticalCentreCaret(); void MoveSelectedLines(int lineDelta); void MoveSelectedLinesUp(); void MoveSelectedLinesDown(); void MoveCaretInsideView(bool ensureVisible=true); Sci::Line DisplayFromPosition(Sci::Position pos); struct XYScrollPosition { int xOffset; Sci::Line topLine; XYScrollPosition(int xOffset_, Sci::Line topLine_) : xOffset(xOffset_), topLine(topLine_) {} bool operator==(const XYScrollPosition &other) const { return (xOffset == other.xOffset) && (topLine == other.topLine); } }; enum XYScrollOptions { xysUseMargin=0x1, xysVertical=0x2, xysHorizontal=0x4, xysDefault=xysUseMargin|xysVertical|xysHorizontal}; XYScrollPosition XYScrollToMakeVisible(const SelectionRange &range, const XYScrollOptions options); void SetXYScroll(XYScrollPosition newXY); void EnsureCaretVisible(bool useMargin=true, bool vert=true, bool horiz=true); void ScrollRange(SelectionRange range); void ShowCaretAtCurrentPosition(); void DropCaret(); void CaretSetPeriod(int period); void InvalidateCaret(); virtual void NotifyCaretMove(); virtual void UpdateSystemCaret(); bool Wrapping() const; void NeedWrapping(Sci::Line docLineStart=0, Sci::Line docLineEnd=WrapPending::lineLarge); bool WrapOneLine(Surface *surface, Sci::Line lineToWrap); enum class WrapScope {wsAll, wsVisible, wsIdle}; bool WrapLines(WrapScope ws); void LinesJoin(); void LinesSplit(int pixelWidth); void PaintSelMargin(Surface *surfaceWindow, const PRectangle &rc); void RefreshPixMaps(Surface *surfaceWindow); void Paint(Surface *surfaceWindow, PRectangle rcArea); Sci::Position FormatRange(bool draw, const Sci_RangeToFormat *pfr); int TextWidth(int style, const char *text); virtual void SetVerticalScrollPos() = 0; virtual void SetHorizontalScrollPos() = 0; virtual bool ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) = 0; virtual void ReconfigureScrollBars(); void SetScrollBars(); void ChangeSize(); void FilterSelections(); Sci::Position RealizeVirtualSpace(Sci::Position position, Sci::Position virtualSpace); SelectionPosition RealizeVirtualSpace(const SelectionPosition &position); void AddChar(char ch); virtual void AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS=false); void ClearBeforeTentativeStart(); void InsertPaste(const char *text, Sci::Position len); enum PasteShape { pasteStream=0, pasteRectangular = 1, pasteLine = 2 }; void InsertPasteShape(const char *text, Sci::Position len, PasteShape shape); void ClearSelection(bool retainMultipleSelections = false); void ClearAll(); void ClearDocumentStyle(); virtual void Cut(); void PasteRectangular(SelectionPosition pos, const char *ptr, Sci::Position len); virtual void Copy() = 0; virtual void CopyAllowLine(); virtual bool CanPaste(); virtual void Paste() = 0; void Clear(); virtual void SelectAll(); virtual void Undo(); virtual void Redo(); void DelCharBack(bool allowLineStartDeletion); virtual void ClaimSelection() = 0; static int ModifierFlags(bool shift, bool ctrl, bool alt, bool meta=false, bool super=false) noexcept; virtual void NotifyChange() = 0; virtual void NotifyFocus(bool focus); virtual void SetCtrlID(int identifier); virtual int GetCtrlID() { return ctrlID; } virtual void NotifyParent(SCNotification scn) = 0; virtual void NotifyStyleToNeeded(Sci::Position endStyleNeeded); void NotifyChar(int ch); void NotifySavePoint(bool isSavePoint); void NotifyModifyAttempt(); virtual void NotifyDoubleClick(Point pt, int modifiers); void NotifyHotSpotClicked(Sci::Position position, int modifiers); void NotifyHotSpotDoubleClicked(Sci::Position position, int modifiers); void NotifyHotSpotReleaseClick(Sci::Position position, int modifiers); bool NotifyUpdateUI(); void NotifyPainted(); void NotifyIndicatorClick(bool click, Sci::Position position, int modifiers); bool NotifyMarginClick(Point pt, int modifiers); bool NotifyMarginRightClick(Point pt, int modifiers); void NotifyNeedShown(Sci::Position pos, Sci::Position len); void NotifyDwelling(Point pt, bool state); void NotifyZoom(); void NotifyModifyAttempt(Document *document, void *userData) override; void NotifySavePoint(Document *document, void *userData, bool atSavePoint) override; void CheckModificationForWrap(DocModification mh); void NotifyModified(Document *document, DocModification mh, void *userData) override; void NotifyDeleted(Document *document, void *userData) override; void NotifyStyleNeeded(Document *doc, void *userData, Sci::Position endStyleNeeded) override; void NotifyLexerChanged(Document *doc, void *userData) override; void NotifyErrorOccurred(Document *doc, void *userData, int status) override; void NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam); void ContainerNeedsUpdate(int flags); void PageMove(int direction, Selection::selTypes selt=Selection::noSel, bool stuttered = false); enum { cmSame, cmUpper, cmLower }; virtual std::string CaseMapString(const std::string &s, int caseMapping); void ChangeCaseOfSelection(int caseMapping); void LineTranspose(); void LineReverse(); void Duplicate(bool forLine); virtual void CancelModes(); void NewLine(); SelectionPosition PositionUpOrDown(SelectionPosition spStart, int direction, int lastX); void CursorUpOrDown(int direction, Selection::selTypes selt); void ParaUpOrDown(int direction, Selection::selTypes selt); Range RangeDisplayLine(Sci::Line lineVisible); Sci::Position StartEndDisplayLine(Sci::Position pos, bool start); Sci::Position VCHomeDisplayPosition(Sci::Position position); Sci::Position VCHomeWrapPosition(Sci::Position position); Sci::Position LineEndWrapPosition(Sci::Position position); int HorizontalMove(unsigned int iMessage); int DelWordOrLine(unsigned int iMessage); virtual int KeyCommand(unsigned int iMessage); virtual int KeyDefault(int /* key */, int /*modifiers*/); int KeyDownWithModifiers(int key, int modifiers, bool *consumed); void Indent(bool forwards); virtual CaseFolder *CaseFolderForEncoding(); Sci::Position FindText(uptr_t wParam, sptr_t lParam); void SearchAnchor(); Sci::Position SearchText(unsigned int iMessage, uptr_t wParam, sptr_t lParam); Sci::Position SearchInTarget(const char *text, Sci::Position length); void GoToLine(Sci::Line lineNo); virtual void CopyToClipboard(const SelectionText &selectedText) = 0; std::string RangeText(Sci::Position start, Sci::Position end) const; void CopySelectionRange(SelectionText *ss, bool allowLineCopy=false); void CopyRangeToClipboard(Sci::Position start, Sci::Position end); void CopyText(size_t length, const char *text); void SetDragPosition(SelectionPosition newPos); virtual void DisplayCursor(Window::Cursor c); virtual bool DragThreshold(Point ptStart, Point ptNow); virtual void StartDrag(); void DropAt(SelectionPosition position, const char *value, size_t lengthValue, bool moving, bool rectangular); void DropAt(SelectionPosition position, const char *value, bool moving, bool rectangular); /** PositionInSelection returns true if position in selection. */ bool PositionInSelection(Sci::Position pos); bool PointInSelection(Point pt); bool PointInSelMargin(Point pt) const; Window::Cursor GetMarginCursor(Point pt) const; void TrimAndSetSelection(Sci::Position currentPos_, Sci::Position anchor_); void LineSelection(Sci::Position lineCurrentPos_, Sci::Position lineAnchorPos_, bool wholeLine); void WordSelection(Sci::Position pos); void DwellEnd(bool mouseMoved); void MouseLeave(); virtual void ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers); virtual void RightButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers); void ButtonMoveWithModifiers(Point pt, unsigned int curTime, int modifiers); void ButtonUpWithModifiers(Point pt, unsigned int curTime, int modifiers); bool Idle(); enum TickReason { tickCaret, tickScroll, tickWiden, tickDwell, tickPlatform }; virtual void TickFor(TickReason reason); virtual bool FineTickerRunning(TickReason reason); virtual void FineTickerStart(TickReason reason, int millis, int tolerance); virtual void FineTickerCancel(TickReason reason); virtual bool SetIdle(bool) { return false; } virtual void SetMouseCapture(bool on) = 0; virtual bool HaveMouseCapture() = 0; void SetFocusState(bool focusState); Sci::Position PositionAfterArea(PRectangle rcArea) const; void StyleToPositionInView(Sci::Position pos); Sci::Position PositionAfterMaxStyling(Sci::Position posMax, bool scrolling) const; void StartIdleStyling(bool truncatedLastStyling); void StyleAreaBounded(PRectangle rcArea, bool scrolling); void IdleStyling(); virtual void IdleWork(); virtual void QueueIdleWork(WorkNeeded::workItems items, Sci::Position upTo=0); virtual bool PaintContains(PRectangle rc); bool PaintContainsMargin(); void CheckForChangeOutsidePaint(Range r); void SetBraceHighlight(Sci::Position pos0, Sci::Position pos1, int matchStyle); void SetAnnotationHeights(Sci::Line start, Sci::Line end); virtual void SetDocPointer(Document *document); void SetAnnotationVisible(int visible); Sci::Line ExpandLine(Sci::Line line); void SetFoldExpanded(Sci::Line lineDoc, bool expanded); void FoldLine(Sci::Line line, int action); void FoldExpand(Sci::Line line, int action, int level); Sci::Line ContractedFoldNext(Sci::Line lineStart) const; void EnsureLineVisible(Sci::Line lineDoc, bool enforcePolicy); void FoldChanged(Sci::Line line, int levelNow, int levelPrev); void NeedShown(Sci::Position pos, Sci::Position len); void FoldAll(int action); Sci::Position GetTag(char *tagValue, int tagNumber); Sci::Position ReplaceTarget(bool replacePatterns, const char *text, Sci::Position length=-1); bool PositionIsHotspot(Sci::Position position) const; bool PointIsHotspot(Point pt); void SetHotSpotRange(const Point *pt); Range GetHotSpotRange() const override; void SetHoverIndicatorPosition(Sci::Position position); void SetHoverIndicatorPoint(Point pt); int CodePage() const; virtual bool ValidCodePage(int /* codePage */) const { return true; } Sci::Line WrapCount(Sci::Line line); void AddStyledText(const char *buffer, Sci::Position appendLength); virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) = 0; bool ValidMargin(uptr_t wParam) const; void StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); sptr_t StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); void SetSelectionNMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); static const char *StringFromEOLMode(int eolMode); // Coercion functions for transforming WndProc parameters into pointers static void *PtrFromSPtr(sptr_t lParam) { return reinterpret_cast(lParam); } static const char *ConstCharPtrFromSPtr(sptr_t lParam) { return static_cast(PtrFromSPtr(lParam)); } static const unsigned char *ConstUCharPtrFromSPtr(sptr_t lParam) { return static_cast(PtrFromSPtr(lParam)); } static char *CharPtrFromSPtr(sptr_t lParam) { return static_cast(PtrFromSPtr(lParam)); } static unsigned char *UCharPtrFromSPtr(sptr_t lParam) { return static_cast(PtrFromSPtr(lParam)); } static void *PtrFromUPtr(uptr_t wParam) { return reinterpret_cast(wParam); } static const char *ConstCharPtrFromUPtr(uptr_t wParam) { return static_cast(PtrFromUPtr(wParam)); } static sptr_t StringResult(sptr_t lParam, const char *val); static sptr_t BytesResult(sptr_t lParam, const unsigned char *val, size_t len); public: // Public so the COM thunks can access it. bool IsUnicodeMode() const; // Public so scintilla_send_message can use it. virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); // Public so scintilla_set_id can use it. int ctrlID; // Public so COM methods for drag and drop can set it. int errorStatus; friend class AutoSurface; }; /** * A smart pointer class to ensure Surfaces are set up and deleted correctly. */ class AutoSurface { private: std::unique_ptr surf; public: AutoSurface(Editor *ed, int technology = -1) { if (ed->wMain.GetID()) { surf.reset(Surface::Allocate(technology != -1 ? technology : ed->technology)); surf->Init(ed->wMain.GetID()); surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); surf->SetDBCSMode(ed->CodePage()); } } AutoSurface(SurfaceID sid, Editor *ed, int technology = -1) { if (ed->wMain.GetID()) { surf.reset(Surface::Allocate(technology != -1 ? technology : ed->technology)); surf->Init(sid, ed->wMain.GetID()); surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); surf->SetDBCSMode(ed->CodePage()); } } // Deleted so AutoSurface objects can not be copied. AutoSurface(const AutoSurface &) = delete; AutoSurface(AutoSurface &&) = delete; void operator=(const AutoSurface &) = delete; void operator=(AutoSurface &&) = delete; ~AutoSurface() { } Surface *operator->() const noexcept { return surf.get(); } operator Surface *() const noexcept { return surf.get(); } }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/ElapsedPeriod.h000066400000000000000000000017121463772530400264510ustar00rootroot00000000000000// Scintilla source code edit control /** @file ElapsedPeriod.h ** Encapsulate C++ to simplify use. **/ // Copyright 2018 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef ELAPSEDPERIOD_H #define ELAPSEDPERIOD_H namespace Scintilla { // Simplified access to high precision timing. class ElapsedPeriod { std::chrono::high_resolution_clock::time_point tp; public: /// Capture the moment ElapsedPeriod() : tp(std::chrono::high_resolution_clock::now()) { } /// Return duration as floating point seconds double Duration(bool reset=false) { const std::chrono::high_resolution_clock::time_point tpNow = std::chrono::high_resolution_clock::now(); const std::chrono::duration stylingDuration = std::chrono::duration_cast>(tpNow - tp); if (reset) { tp = tpNow; } return stylingDuration.count(); } }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/ExternalLexer.cpp000066400000000000000000000067621463772530400270600ustar00rootroot00000000000000// Scintilla source code edit control /** @file ExternalLexer.cxx ** Support external lexers in DLLs or shared libraries. **/ // Copyright 2001 Simon Steele , portions copyright Neil Hodgson. // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "Platform.h" #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "LexerModule.h" #include "Catalogue.h" #include "ExternalLexer.h" using namespace Scintilla; std::unique_ptr LexerManager::theInstance; //------------------------------------------ // // ExternalLexerModule // //------------------------------------------ void ExternalLexerModule::SetExternal(GetLexerFactoryFunction fFactory, int index) { fneFactory = fFactory; fnFactory = fFactory(index); } //------------------------------------------ // // LexerLibrary // //------------------------------------------ LexerLibrary::LexerLibrary(const char *moduleName_) { // Load the DLL lib.reset(DynamicLibrary::Load(moduleName_)); if (lib->IsValid()) { moduleName = moduleName_; //Cannot use reinterpret_cast because: ANSI C++ forbids casting between pointers to functions and objects GetLexerCountFn GetLexerCount = (GetLexerCountFn)(sptr_t)lib->FindFunction("GetLexerCount"); if (GetLexerCount) { // Find functions in the DLL GetLexerNameFn GetLexerName = (GetLexerNameFn)(sptr_t)lib->FindFunction("GetLexerName"); GetLexerFactoryFunction fnFactory = (GetLexerFactoryFunction)(sptr_t)lib->FindFunction("GetLexerFactory"); const int nl = GetLexerCount(); for (int i = 0; i < nl; i++) { // Assign a buffer for the lexer name. char lexname[100] = ""; GetLexerName(i, lexname, sizeof(lexname)); ExternalLexerModule *lex = new ExternalLexerModule(SCLEX_AUTOMATIC, nullptr, lexname, nullptr); // This is storing a second reference to lex in the Catalogue as well as in modules. // TODO: Should use std::shared_ptr or similar to ensure allocation safety. Catalogue::AddLexerModule(lex); // Remember ExternalLexerModule so we don't leak it modules.push_back(std::unique_ptr(lex)); // The external lexer needs to know how to call into its DLL to // do its lexing and folding, we tell it here. lex->SetExternal(fnFactory, i); } } } } LexerLibrary::~LexerLibrary() { } //------------------------------------------ // // LexerManager // //------------------------------------------ /// Return the single LexerManager instance... LexerManager *LexerManager::GetInstance() { if (!theInstance) theInstance.reset(new LexerManager); return theInstance.get(); } /// Delete any LexerManager instance... void LexerManager::DeleteInstance() { theInstance.reset(); } /// protected constructor - this is a singleton... LexerManager::LexerManager() { } LexerManager::~LexerManager() { Clear(); } void LexerManager::Load(const char *path) { for (const std::unique_ptr &ll : libraries) { if (ll->moduleName == path) return; } LexerLibrary *lib = new LexerLibrary(path); libraries.push_back(std::unique_ptr(lib)); } void LexerManager::Clear() { libraries.clear(); } //------------------------------------------ // // LMMinder -- trigger to clean up at exit. // //------------------------------------------ LMMinder::~LMMinder() { LexerManager::DeleteInstance(); } LMMinder minder; sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/ExternalLexer.h000066400000000000000000000040561463772530400265170ustar00rootroot00000000000000// Scintilla source code edit control /** @file ExternalLexer.h ** Support external lexers in DLLs or shared libraries. **/ // Copyright 2001 Simon Steele , portions copyright Neil Hodgson. // The License.txt file describes the conditions under which this software may be distributed. #ifndef EXTERNALLEXER_H #define EXTERNALLEXER_H #if PLAT_WIN #define EXT_LEXER_DECL __stdcall #elif PLAT_QT #include #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) #define EXT_LEXER_DECL __stdcall #else #define EXT_LEXER_DECL #endif #else #define EXT_LEXER_DECL #endif namespace Scintilla { typedef int (EXT_LEXER_DECL *GetLexerCountFn)(); typedef void (EXT_LEXER_DECL *GetLexerNameFn)(unsigned int Index, char *name, int buflength); typedef LexerFactoryFunction(EXT_LEXER_DECL *GetLexerFactoryFunction)(unsigned int Index); /// Sub-class of LexerModule to use an external lexer. class ExternalLexerModule : public LexerModule { protected: GetLexerFactoryFunction fneFactory; std::string name; public: ExternalLexerModule(int language_, LexerFunction fnLexer_, const char *languageName_=nullptr, LexerFunction fnFolder_=nullptr) : LexerModule(language_, fnLexer_, nullptr, fnFolder_), fneFactory(nullptr), name(languageName_){ languageName = name.c_str(); } virtual void SetExternal(GetLexerFactoryFunction fFactory, int index); }; /// LexerLibrary exists for every External Lexer DLL, contains ExternalLexerModules. class LexerLibrary { std::unique_ptr lib; std::vector> modules; public: explicit LexerLibrary(const char *moduleName_); ~LexerLibrary(); std::string moduleName; }; /// LexerManager manages external lexers, contains LexerLibrarys. class LexerManager { public: ~LexerManager(); static LexerManager *GetInstance(); static void DeleteInstance(); void Load(const char *path); void Clear(); private: LexerManager(); static std::unique_ptr theInstance; std::vector> libraries; }; class LMMinder { public: ~LMMinder(); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/FontQuality.h000066400000000000000000000014551463772530400262140ustar00rootroot00000000000000// Scintilla source code edit control /** @file FontQuality.h ** Definitions to control font anti-aliasing. ** Redefine constants from Scintilla.h to avoid including Scintilla.h in PlatWin.cxx. **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef FONTQUALITY_H #define FONTQUALITY_H namespace Scintilla { // These definitions match Scintilla.h #define SC_EFF_QUALITY_MASK 0xF #define SC_EFF_QUALITY_DEFAULT 0 #define SC_EFF_QUALITY_NON_ANTIALIASED 1 #define SC_EFF_QUALITY_ANTIALIASED 2 #define SC_EFF_QUALITY_LCD_OPTIMIZED 3 // These definitions must match SC_TECHNOLOGY_* in Scintilla.h #define SCWIN_TECH_GDI 0 #define SCWIN_TECH_DIRECTWRITE 1 } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Indicator.cpp000066400000000000000000000172331463772530400262050ustar00rootroot00000000000000// Scintilla source code edit control /** @file Indicator.cxx ** Defines the style of indicators which are text decorations such as underlining. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "StringCopy.h" #include "IntegerRectangle.h" #include "Indicator.h" #include "XPM.h" using namespace Scintilla; static PRectangle PixelGridAlign(const PRectangle &rc) { // Move left and right side to nearest pixel to avoid blurry visuals return PRectangle(round(rc.left), floor(rc.top), round(rc.right), floor(rc.bottom)); } void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine, const PRectangle &rcCharacter, DrawState drawState, int value) const { StyleAndColour sacDraw = sacNormal; if (Flags() & SC_INDICFLAG_VALUEFORE) { sacDraw.fore = ColourDesired(value & SC_INDICVALUEMASK); } if (drawState == drawHover) { sacDraw = sacHover; } const IntegerRectangle irc(rc); surface->PenColour(sacDraw.fore); const int ymid = (irc.bottom + irc.top) / 2; if (sacDraw.style == INDIC_SQUIGGLE) { const IntegerRectangle ircSquiggle(PixelGridAlign(rc)); int x = ircSquiggle.left; const int xLast = ircSquiggle.right; int y = 0; surface->MoveTo(x, irc.top + y); while (x < xLast) { if ((x + 2) > xLast) { y = 1; x = xLast; } else { x += 2; y = 2 - y; } surface->LineTo(x, irc.top + y); } } else if (sacDraw.style == INDIC_SQUIGGLEPIXMAP) { const PRectangle rcSquiggle = PixelGridAlign(rc); const int width = std::min(4000, static_cast(rcSquiggle.Width())); RGBAImage image(width, 3, 1.0, nullptr); enum { alphaFull = 0xff, alphaSide = 0x2f, alphaSide2=0x5f }; for (int x = 0; x < width; x++) { if (x%2) { // Two halfway columns have a full pixel in middle flanked by light pixels image.SetPixel(x, 0, sacDraw.fore, alphaSide); image.SetPixel(x, 1, sacDraw.fore, alphaFull); image.SetPixel(x, 2, sacDraw.fore, alphaSide); } else { // Extreme columns have a full pixel at bottom or top and a mid-tone pixel in centre image.SetPixel(x, (x % 4) ? 0 : 2, sacDraw.fore, alphaFull); image.SetPixel(x, 1, sacDraw.fore, alphaSide2); } } surface->DrawRGBAImage(rcSquiggle, image.GetWidth(), image.GetHeight(), image.Pixels()); } else if (sacDraw.style == INDIC_SQUIGGLELOW) { surface->MoveTo(irc.left, irc.top); int x = irc.left + 3; int y = 0; while (x < rc.right) { surface->LineTo(x - 1, irc.top + y); y = 1 - y; surface->LineTo(x, irc.top + y); x += 3; } surface->LineTo(irc.right, irc.top + y); // Finish the line } else if (sacDraw.style == INDIC_TT) { surface->MoveTo(irc.left, ymid); int x = irc.left + 5; while (x < rc.right) { surface->LineTo(x, ymid); surface->MoveTo(x-3, ymid); surface->LineTo(x-3, ymid+2); x++; surface->MoveTo(x, ymid); x += 5; } surface->LineTo(irc.right, ymid); // Finish the line if (x - 3 <= rc.right) { surface->MoveTo(x-3, ymid); surface->LineTo(x-3, ymid+2); } } else if (sacDraw.style == INDIC_DIAGONAL) { int x = irc.left; while (x < rc.right) { surface->MoveTo(x, irc.top + 2); int endX = x+3; int endY = irc.top - 1; if (endX > rc.right) { endY += endX - irc.right; endX = irc.right; } surface->LineTo(endX, endY); x += 4; } } else if (sacDraw.style == INDIC_STRIKE) { surface->MoveTo(irc.left, irc.top - 4); surface->LineTo(irc.right, irc.top - 4); } else if ((sacDraw.style == INDIC_HIDDEN) || (sacDraw.style == INDIC_TEXTFORE)) { // Draw nothing } else if (sacDraw.style == INDIC_BOX) { surface->MoveTo(irc.left, ymid + 1); surface->LineTo(irc.right, ymid + 1); const int lineTop = static_cast(rcLine.top) + 1; surface->LineTo(irc.right, lineTop); surface->LineTo(irc.left, lineTop); surface->LineTo(irc.left, ymid + 1); } else if (sacDraw.style == INDIC_ROUNDBOX || sacDraw.style == INDIC_STRAIGHTBOX || sacDraw.style == INDIC_FULLBOX) { PRectangle rcBox = rcLine; if (sacDraw.style != INDIC_FULLBOX) rcBox.top = rcLine.top + 1; rcBox.left = rc.left; rcBox.right = rc.right; surface->AlphaRectangle(rcBox, (sacDraw.style == INDIC_ROUNDBOX) ? 1 : 0, sacDraw.fore, fillAlpha, sacDraw.fore, outlineAlpha, 0); } else if (sacDraw.style == INDIC_GRADIENT || sacDraw.style == INDIC_GRADIENTCENTRE) { PRectangle rcBox = rc; rcBox.top = rcLine.top + 1; rcBox.bottom = rcLine.bottom; const Surface::GradientOptions options = Surface::GradientOptions::topToBottom; const ColourAlpha start(sacNormal.fore, fillAlpha); const ColourAlpha end(sacNormal.fore, 0); std::vector stops; switch (sacDraw.style) { case INDIC_GRADIENT: stops.push_back(ColourStop(0.0, start)); stops.push_back(ColourStop(1.0, end)); break; case INDIC_GRADIENTCENTRE: stops.push_back(ColourStop(0.0, end)); stops.push_back(ColourStop(0.5, start)); stops.push_back(ColourStop(1.0, end)); break; } surface->GradientRectangle(rcBox, stops, options); } else if (sacDraw.style == INDIC_DOTBOX) { PRectangle rcBox = PixelGridAlign(rc); rcBox.top = rcLine.top + 1; rcBox.bottom = rcLine.bottom; IntegerRectangle ircBox(rcBox); // Cap width at 4000 to avoid large allocations when mistakes made const int width = std::min(ircBox.Width(), 4000); RGBAImage image(width, ircBox.Height(), 1.0, nullptr); // Draw horizontal lines top and bottom for (int x=0; xDrawRGBAImage(rcBox, image.GetWidth(), image.GetHeight(), image.Pixels()); } else if (sacDraw.style == INDIC_DASH) { int x = irc.left; while (x < rc.right) { surface->MoveTo(x, ymid); surface->LineTo(std::min(x + 4, irc.right), ymid); x += 7; } } else if (sacDraw.style == INDIC_DOTS) { int x = irc.left; while (x < irc.right) { const PRectangle rcDot = PRectangle::FromInts(x, ymid, x + 1, ymid + 1); surface->FillRectangle(rcDot, sacDraw.fore); x += 2; } } else if (sacDraw.style == INDIC_COMPOSITIONTHICK) { const PRectangle rcComposition(rc.left+1, rcLine.bottom-2, rc.right-1, rcLine.bottom); surface->FillRectangle(rcComposition, sacDraw.fore); } else if (sacDraw.style == INDIC_COMPOSITIONTHIN) { const PRectangle rcComposition(rc.left+1, rcLine.bottom-2, rc.right-1, rcLine.bottom-1); surface->FillRectangle(rcComposition, sacDraw.fore); } else if (sacDraw.style == INDIC_POINT || sacDraw.style == INDIC_POINTCHARACTER) { if (rcCharacter.Width() >= 0.1) { const XYPOSITION pixelHeight = floor(rc.Height() - 1.0f); // 1 pixel onto next line if multiphase const XYPOSITION x = (sacDraw.style == INDIC_POINT) ? (rcCharacter.left) : ((rcCharacter.right + rcCharacter.left) / 2); const XYPOSITION ix = round(x); const XYPOSITION iy = floor(rc.top + 1.0f); Point pts[] = { Point(ix - pixelHeight, iy + pixelHeight), // Left Point(ix + pixelHeight, iy + pixelHeight), // Right Point(ix, iy) // Top }; surface->Polygon(pts, ELEMENTS(pts), sacDraw.fore, sacDraw.fore); } } else { // Either INDIC_PLAIN or unknown surface->MoveTo(irc.left, ymid); surface->LineTo(irc.right, ymid); } } void Indicator::SetFlags(int attributes_) { attributes = attributes_; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Indicator.h000066400000000000000000000032121463772530400256420ustar00rootroot00000000000000// Scintilla source code edit control /** @file Indicator.h ** Defines the style of indicators which are text decorations such as underlining. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef INDICATOR_H #define INDICATOR_H namespace Scintilla { struct StyleAndColour { int style; ColourDesired fore; StyleAndColour() : style(INDIC_PLAIN), fore(0, 0, 0) { } StyleAndColour(int style_, ColourDesired fore_ = ColourDesired(0, 0, 0)) : style(style_), fore(fore_) { } bool operator==(const StyleAndColour &other) const { return (style == other.style) && (fore == other.fore); } }; /** */ class Indicator { public: enum DrawState { drawNormal, drawHover }; StyleAndColour sacNormal; StyleAndColour sacHover; bool under; int fillAlpha; int outlineAlpha; int attributes; Indicator() : under(false), fillAlpha(30), outlineAlpha(50), attributes(0) { } Indicator(int style_, ColourDesired fore_=ColourDesired(0,0,0), bool under_=false, int fillAlpha_=30, int outlineAlpha_=50) : sacNormal(style_, fore_), sacHover(style_, fore_), under(under_), fillAlpha(fillAlpha_), outlineAlpha(outlineAlpha_), attributes(0) { } void Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine, const PRectangle &rcCharacter, DrawState drawState, int value) const; bool IsDynamic() const { return !(sacNormal == sacHover); } bool OverridesTextFore() const { return sacNormal.style == INDIC_TEXTFORE || sacHover.style == INDIC_TEXTFORE; } int Flags() const { return attributes; } void SetFlags(int attributes_); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/IntegerRectangle.h000066400000000000000000000013371463772530400271560ustar00rootroot00000000000000// Scintilla source code edit control /** @file IntegerRectangle.h ** A rectangle with integer coordinates. **/ // Copyright 2018 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef INTEGERRECTANGLE_H #define INTEGERRECTANGLE_H namespace Scintilla { struct IntegerRectangle { int left; int top; int right; int bottom; explicit IntegerRectangle(PRectangle rc) noexcept : left(static_cast(rc.left)), top(static_cast(rc.top)), right(static_cast(rc.right)), bottom(static_cast(rc.bottom)) { } int Width() const noexcept { return right - left; } int Height() const noexcept { return bottom - top; } }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/KeyMap.cpp000066400000000000000000000124721463772530400254570ustar00rootroot00000000000000// Scintilla source code edit control /** @file KeyMap.cxx ** Defines a mapping between keystrokes and commands. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "KeyMap.h" using namespace Scintilla; KeyMap::KeyMap() { for (int i = 0; MapDefault[i].key; i++) { AssignCmdKey(MapDefault[i].key, MapDefault[i].modifiers, MapDefault[i].msg); } } KeyMap::~KeyMap() { Clear(); } void KeyMap::Clear() { kmap.clear(); } void KeyMap::AssignCmdKey(int key, int modifiers, unsigned int msg) { kmap[KeyModifiers(key, modifiers)] = msg; } unsigned int KeyMap::Find(int key, int modifiers) const { std::map::const_iterator it = kmap.find(KeyModifiers(key, modifiers)); return (it == kmap.end()) ? 0 : it->second; } const std::map &KeyMap::GetKeyMap() const { return kmap; } #if PLAT_GTK_MACOSX #define OS_X_KEYS 1 #else #define OS_X_KEYS 0 #endif // Define a modifier that is exactly Ctrl key on all platforms // Most uses of Ctrl map to Cmd on OS X but some can't so use SCI_[S]CTRL_META #if OS_X_KEYS #define SCI_CTRL_META SCI_META #define SCI_SCTRL_META (SCI_META | SCI_SHIFT) #else #define SCI_CTRL_META SCI_CTRL #define SCI_SCTRL_META (SCI_CTRL | SCI_SHIFT) #endif const KeyToCommand KeyMap::MapDefault[] = { #if OS_X_KEYS {SCK_DOWN, SCI_CTRL, SCI_DOCUMENTEND}, {SCK_DOWN, SCI_CSHIFT, SCI_DOCUMENTENDEXTEND}, {SCK_UP, SCI_CTRL, SCI_DOCUMENTSTART}, {SCK_UP, SCI_CSHIFT, SCI_DOCUMENTSTARTEXTEND}, {SCK_LEFT, SCI_CTRL, SCI_VCHOME}, {SCK_LEFT, SCI_CSHIFT, SCI_VCHOMEEXTEND}, {SCK_RIGHT, SCI_CTRL, SCI_LINEEND}, {SCK_RIGHT, SCI_CSHIFT, SCI_LINEENDEXTEND}, #endif {SCK_DOWN, SCI_NORM, SCI_LINEDOWN}, {SCK_DOWN, SCI_SHIFT, SCI_LINEDOWNEXTEND}, {SCK_DOWN, SCI_CTRL_META, SCI_LINESCROLLDOWN}, {SCK_DOWN, SCI_ASHIFT, SCI_LINEDOWNRECTEXTEND}, {SCK_UP, SCI_NORM, SCI_LINEUP}, {SCK_UP, SCI_SHIFT, SCI_LINEUPEXTEND}, {SCK_UP, SCI_CTRL_META, SCI_LINESCROLLUP}, {SCK_UP, SCI_ASHIFT, SCI_LINEUPRECTEXTEND}, {'[', SCI_CTRL, SCI_PARAUP}, {'[', SCI_CSHIFT, SCI_PARAUPEXTEND}, {']', SCI_CTRL, SCI_PARADOWN}, {']', SCI_CSHIFT, SCI_PARADOWNEXTEND}, {SCK_LEFT, SCI_NORM, SCI_CHARLEFT}, {SCK_LEFT, SCI_SHIFT, SCI_CHARLEFTEXTEND}, {SCK_LEFT, SCI_CTRL_META, SCI_WORDLEFT}, {SCK_LEFT, SCI_SCTRL_META, SCI_WORDLEFTEXTEND}, {SCK_LEFT, SCI_ASHIFT, SCI_CHARLEFTRECTEXTEND}, {SCK_RIGHT, SCI_NORM, SCI_CHARRIGHT}, {SCK_RIGHT, SCI_SHIFT, SCI_CHARRIGHTEXTEND}, {SCK_RIGHT, SCI_CTRL_META, SCI_WORDRIGHT}, {SCK_RIGHT, SCI_SCTRL_META, SCI_WORDRIGHTEXTEND}, {SCK_RIGHT, SCI_ASHIFT, SCI_CHARRIGHTRECTEXTEND}, {'/', SCI_CTRL, SCI_WORDPARTLEFT}, {'/', SCI_CSHIFT, SCI_WORDPARTLEFTEXTEND}, {'\\', SCI_CTRL, SCI_WORDPARTRIGHT}, {'\\', SCI_CSHIFT, SCI_WORDPARTRIGHTEXTEND}, {SCK_HOME, SCI_NORM, SCI_VCHOME}, {SCK_HOME, SCI_SHIFT, SCI_VCHOMEEXTEND}, {SCK_HOME, SCI_CTRL, SCI_DOCUMENTSTART}, {SCK_HOME, SCI_CSHIFT, SCI_DOCUMENTSTARTEXTEND}, {SCK_HOME, SCI_ALT, SCI_HOMEDISPLAY}, {SCK_HOME, SCI_ASHIFT, SCI_VCHOMERECTEXTEND}, {SCK_END, SCI_NORM, SCI_LINEEND}, {SCK_END, SCI_SHIFT, SCI_LINEENDEXTEND}, {SCK_END, SCI_CTRL, SCI_DOCUMENTEND}, {SCK_END, SCI_CSHIFT, SCI_DOCUMENTENDEXTEND}, {SCK_END, SCI_ALT, SCI_LINEENDDISPLAY}, {SCK_END, SCI_ASHIFT, SCI_LINEENDRECTEXTEND}, {SCK_PRIOR, SCI_NORM, SCI_PAGEUP}, {SCK_PRIOR, SCI_SHIFT, SCI_PAGEUPEXTEND}, {SCK_PRIOR, SCI_ASHIFT, SCI_PAGEUPRECTEXTEND}, {SCK_NEXT, SCI_NORM, SCI_PAGEDOWN}, {SCK_NEXT, SCI_SHIFT, SCI_PAGEDOWNEXTEND}, {SCK_NEXT, SCI_ASHIFT, SCI_PAGEDOWNRECTEXTEND}, {SCK_DELETE, SCI_NORM, SCI_CLEAR}, {SCK_DELETE, SCI_SHIFT, SCI_CUT}, {SCK_DELETE, SCI_CTRL, SCI_DELWORDRIGHT}, {SCK_DELETE, SCI_CSHIFT, SCI_DELLINERIGHT}, {SCK_INSERT, SCI_NORM, SCI_EDITTOGGLEOVERTYPE}, {SCK_INSERT, SCI_SHIFT, SCI_PASTE}, {SCK_INSERT, SCI_CTRL, SCI_COPY}, {SCK_ESCAPE, SCI_NORM, SCI_CANCEL}, {SCK_BACK, SCI_NORM, SCI_DELETEBACK}, {SCK_BACK, SCI_SHIFT, SCI_DELETEBACK}, {SCK_BACK, SCI_CTRL, SCI_DELWORDLEFT}, {SCK_BACK, SCI_ALT, SCI_UNDO}, {SCK_BACK, SCI_CSHIFT, SCI_DELLINELEFT}, {'Z', SCI_CTRL, SCI_UNDO}, #if OS_X_KEYS {'Z', SCI_CSHIFT, SCI_REDO}, #else {'Y', SCI_CTRL, SCI_REDO}, #endif {'X', SCI_CTRL, SCI_CUT}, {'C', SCI_CTRL, SCI_COPY}, {'V', SCI_CTRL, SCI_PASTE}, {'A', SCI_CTRL, SCI_SELECTALL}, {SCK_TAB, SCI_NORM, SCI_TAB}, {SCK_TAB, SCI_SHIFT, SCI_BACKTAB}, {SCK_RETURN, SCI_NORM, SCI_NEWLINE}, {SCK_RETURN, SCI_SHIFT, SCI_NEWLINE}, {SCK_ADD, SCI_CTRL, SCI_ZOOMIN}, {SCK_SUBTRACT, SCI_CTRL, SCI_ZOOMOUT}, {SCK_DIVIDE, SCI_CTRL, SCI_SETZOOM}, {'L', SCI_CTRL, SCI_LINECUT}, {'L', SCI_CSHIFT, SCI_LINEDELETE}, {'T', SCI_CSHIFT, SCI_LINECOPY}, {'T', SCI_CTRL, SCI_LINETRANSPOSE}, {'D', SCI_CTRL, SCI_SELECTIONDUPLICATE}, {'U', SCI_CTRL, SCI_LOWERCASE}, {'U', SCI_CSHIFT, SCI_UPPERCASE}, {0,0,0}, }; sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/KeyMap.h000066400000000000000000000024631463772530400251230ustar00rootroot00000000000000// Scintilla source code edit control /** @file KeyMap.h ** Defines a mapping between keystrokes and commands. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef KEYMAP_H #define KEYMAP_H namespace Scintilla { #define SCI_NORM 0 #define SCI_SHIFT SCMOD_SHIFT #define SCI_CTRL SCMOD_CTRL #define SCI_ALT SCMOD_ALT #define SCI_META SCMOD_META #define SCI_SUPER SCMOD_SUPER #define SCI_CSHIFT (SCI_CTRL | SCI_SHIFT) #define SCI_ASHIFT (SCI_ALT | SCI_SHIFT) /** */ class KeyModifiers { public: int key; int modifiers; KeyModifiers(int key_, int modifiers_) : key(key_), modifiers(modifiers_) { } bool operator<(const KeyModifiers &other) const { if (key == other.key) return modifiers < other.modifiers; else return key < other.key; } }; /** */ class KeyToCommand { public: int key; int modifiers; unsigned int msg; }; /** */ class KeyMap { std::map kmap; static const KeyToCommand MapDefault[]; public: KeyMap(); ~KeyMap(); void Clear(); void AssignCmdKey(int key, int modifiers, unsigned int msg); unsigned int Find(int key, int modifiers) const; // 0 returned on failure const std::map &GetKeyMap() const; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/License.txt000066400000000000000000000015261463772530400257060ustar00rootroot00000000000000License for Scintilla and SciTE Copyright 1998-2003 by Neil Hodgson All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NEIL HODGSON 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.sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/LineMarker.cpp000066400000000000000000000360521463772530400263220ustar00rootroot00000000000000// Scintilla source code edit control /** @file LineMarker.cxx ** Defines the look of a line marker in the margin. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "StringCopy.h" #include "IntegerRectangle.h" #include "XPM.h" #include "LineMarker.h" using namespace Scintilla; LineMarker::~LineMarker() { } LineMarker::LineMarker() { markType = SC_MARK_CIRCLE; fore = ColourDesired(0, 0, 0); back = ColourDesired(0xff, 0xff, 0xff); backSelected = ColourDesired(0xff, 0x00, 0x00); alpha = SC_ALPHA_NOALPHA; customDraw = nullptr; } LineMarker::LineMarker(const LineMarker &) { // Defined to avoid pxpm and image being blindly copied, not as a complete copy constructor. markType = SC_MARK_CIRCLE; fore = ColourDesired(0, 0, 0); back = ColourDesired(0xff, 0xff, 0xff); backSelected = ColourDesired(0xff, 0x00, 0x00); alpha = SC_ALPHA_NOALPHA; pxpm.reset(); image.reset(); customDraw = nullptr; } LineMarker &LineMarker::operator=(const LineMarker &other) { // Defined to avoid pxpm and image being blindly copied, not as a complete assignment operator. if (this != &other) { markType = SC_MARK_CIRCLE; fore = ColourDesired(0, 0, 0); back = ColourDesired(0xff, 0xff, 0xff); backSelected = ColourDesired(0xff, 0x00, 0x00); alpha = SC_ALPHA_NOALPHA; pxpm.reset(); image.reset(); customDraw = nullptr; } return *this; } void LineMarker::SetXPM(const char *textForm) { pxpm.reset(new XPM(textForm)); markType = SC_MARK_PIXMAP; } void LineMarker::SetXPM(const char *const *linesForm) { pxpm.reset(new XPM(linesForm)); markType = SC_MARK_PIXMAP; } void LineMarker::SetRGBAImage(Point sizeRGBAImage, float scale, const unsigned char *pixelsRGBAImage) { image.reset(new RGBAImage(static_cast(sizeRGBAImage.x), static_cast(sizeRGBAImage.y), scale, pixelsRGBAImage)); markType = SC_MARK_RGBAIMAGE; } static void DrawBox(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore, ColourDesired back) { const PRectangle rc = PRectangle::FromInts( centreX - armSize, centreY - armSize, centreX + armSize + 1, centreY + armSize + 1); surface->RectangleDraw(rc, back, fore); } static void DrawCircle(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore, ColourDesired back) { const PRectangle rcCircle = PRectangle::FromInts( centreX - armSize, centreY - armSize, centreX + armSize + 1, centreY + armSize + 1); surface->Ellipse(rcCircle, back, fore); } static void DrawPlus(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore) { const PRectangle rcV = PRectangle::FromInts(centreX, centreY - armSize + 2, centreX + 1, centreY + armSize - 2 + 1); surface->FillRectangle(rcV, fore); const PRectangle rcH = PRectangle::FromInts(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY + 1); surface->FillRectangle(rcH, fore); } static void DrawMinus(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore) { const PRectangle rcH = PRectangle::FromInts(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY + 1); surface->FillRectangle(rcH, fore); } void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharacter, typeOfFold tFold, int marginStyle) const { if (customDraw) { customDraw(surface, rcWhole, fontForCharacter, tFold, marginStyle, this); return; } ColourDesired colourHead = back; ColourDesired colourBody = back; ColourDesired colourTail = back; switch (tFold) { case LineMarker::head : case LineMarker::headWithTail : colourHead = backSelected; colourTail = backSelected; break; case LineMarker::body : colourHead = backSelected; colourBody = backSelected; break; case LineMarker::tail : colourBody = backSelected; colourTail = backSelected; break; default : // LineMarker::undefined break; } if ((markType == SC_MARK_PIXMAP) && (pxpm)) { pxpm->Draw(surface, rcWhole); return; } if ((markType == SC_MARK_RGBAIMAGE) && (image)) { // Make rectangle just large enough to fit image centred on centre of rcWhole PRectangle rcImage; rcImage.top = ((rcWhole.top + rcWhole.bottom) - image->GetScaledHeight()) / 2; rcImage.bottom = rcImage.top + image->GetScaledHeight(); rcImage.left = ((rcWhole.left + rcWhole.right) - image->GetScaledWidth()) / 2; rcImage.right = rcImage.left + image->GetScaledWidth(); surface->DrawRGBAImage(rcImage, image->GetWidth(), image->GetHeight(), image->Pixels()); return; } const IntegerRectangle ircWhole(rcWhole); // Restrict most shapes a bit const PRectangle rc(rcWhole.left, rcWhole.top + 1, rcWhole.right, rcWhole.bottom - 1); // Ensure does not go beyond edge const int minDim = std::min(ircWhole.Width(), ircWhole.Height()-2) - 1; int centreX = (ircWhole.right + ircWhole.left) / 2; const int centreY = (ircWhole.bottom + ircWhole.top) / 2; const int dimOn2 = minDim / 2; const int dimOn4 = minDim / 4; const int blobSize = dimOn2-1; const int armSize = dimOn2-2; if (marginStyle == SC_MARGIN_NUMBER || marginStyle == SC_MARGIN_TEXT || marginStyle == SC_MARGIN_RTEXT) { // On textual margins move marker to the left to try to avoid overlapping the text centreX = ircWhole.left + dimOn2 + 1; } if (markType == SC_MARK_ROUNDRECT) { PRectangle rcRounded = rc; rcRounded.left = rc.left + 1; rcRounded.right = rc.right - 1; surface->RoundedRectangle(rcRounded, fore, back); } else if (markType == SC_MARK_CIRCLE) { const PRectangle rcCircle = PRectangle::FromInts( centreX - dimOn2, centreY - dimOn2, centreX + dimOn2, centreY + dimOn2); surface->Ellipse(rcCircle, fore, back); } else if (markType == SC_MARK_ARROW) { Point pts[] = { Point::FromInts(centreX - dimOn4, centreY - dimOn2), Point::FromInts(centreX - dimOn4, centreY + dimOn2), Point::FromInts(centreX + dimOn2 - dimOn4, centreY), }; surface->Polygon(pts, ELEMENTS(pts), fore, back); } else if (markType == SC_MARK_ARROWDOWN) { Point pts[] = { Point::FromInts(centreX - dimOn2, centreY - dimOn4), Point::FromInts(centreX + dimOn2, centreY - dimOn4), Point::FromInts(centreX, centreY + dimOn2 - dimOn4), }; surface->Polygon(pts, ELEMENTS(pts), fore, back); } else if (markType == SC_MARK_PLUS) { Point pts[] = { Point::FromInts(centreX - armSize, centreY - 1), Point::FromInts(centreX - 1, centreY - 1), Point::FromInts(centreX - 1, centreY - armSize), Point::FromInts(centreX + 1, centreY - armSize), Point::FromInts(centreX + 1, centreY - 1), Point::FromInts(centreX + armSize, centreY -1), Point::FromInts(centreX + armSize, centreY +1), Point::FromInts(centreX + 1, centreY + 1), Point::FromInts(centreX + 1, centreY + armSize), Point::FromInts(centreX - 1, centreY + armSize), Point::FromInts(centreX - 1, centreY + 1), Point::FromInts(centreX - armSize, centreY + 1), }; surface->Polygon(pts, ELEMENTS(pts), fore, back); } else if (markType == SC_MARK_MINUS) { Point pts[] = { Point::FromInts(centreX - armSize, centreY - 1), Point::FromInts(centreX + armSize, centreY -1), Point::FromInts(centreX + armSize, centreY +1), Point::FromInts(centreX - armSize, centreY + 1), }; surface->Polygon(pts, ELEMENTS(pts), fore, back); } else if (markType == SC_MARK_SMALLRECT) { PRectangle rcSmall; rcSmall.left = rc.left + 1; rcSmall.top = rc.top + 2; rcSmall.right = rc.right - 1; rcSmall.bottom = rc.bottom - 2; surface->RectangleDraw(rcSmall, fore, back); } else if (markType == SC_MARK_EMPTY || markType == SC_MARK_BACKGROUND || markType == SC_MARK_UNDERLINE || markType == SC_MARK_AVAILABLE) { // An invisible marker so don't draw anything } else if (markType == SC_MARK_VLINE) { surface->PenColour(colourBody); surface->MoveTo(centreX, ircWhole.top); surface->LineTo(centreX, ircWhole.bottom); } else if (markType == SC_MARK_LCORNER) { surface->PenColour(colourTail); surface->MoveTo(centreX, ircWhole.top); surface->LineTo(centreX, centreY); surface->LineTo(ircWhole.right - 1, centreY); } else if (markType == SC_MARK_TCORNER) { surface->PenColour(colourTail); surface->MoveTo(centreX, centreY); surface->LineTo(ircWhole.right - 1, centreY); surface->PenColour(colourBody); surface->MoveTo(centreX, ircWhole.top); surface->LineTo(centreX, centreY + 1); surface->PenColour(colourHead); surface->LineTo(centreX, ircWhole.bottom); } else if (markType == SC_MARK_LCORNERCURVE) { surface->PenColour(colourTail); surface->MoveTo(centreX, ircWhole.top); surface->LineTo(centreX, centreY-3); surface->LineTo(centreX+3, centreY); surface->LineTo(ircWhole.right - 1, centreY); } else if (markType == SC_MARK_TCORNERCURVE) { surface->PenColour(colourTail); surface->MoveTo(centreX, centreY-3); surface->LineTo(centreX+3, centreY); surface->LineTo(ircWhole.right - 1, centreY); surface->PenColour(colourBody); surface->MoveTo(centreX, ircWhole.top); surface->LineTo(centreX, centreY-2); surface->PenColour(colourHead); surface->LineTo(centreX, ircWhole.bottom); } else if (markType == SC_MARK_BOXPLUS) { DrawBox(surface, centreX, centreY, blobSize, fore, colourHead); DrawPlus(surface, centreX, centreY, blobSize, colourTail); } else if (markType == SC_MARK_BOXPLUSCONNECTED) { if (tFold == LineMarker::headWithTail) surface->PenColour(colourTail); else surface->PenColour(colourBody); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, ircWhole.bottom); surface->PenColour(colourBody); surface->MoveTo(centreX, ircWhole.top); surface->LineTo(centreX, centreY - blobSize); DrawBox(surface, centreX, centreY, blobSize, fore, colourHead); DrawPlus(surface, centreX, centreY, blobSize, colourTail); if (tFold == LineMarker::body) { surface->PenColour(colourTail); surface->MoveTo(centreX + 1, centreY + blobSize); surface->LineTo(centreX + blobSize + 1, centreY + blobSize); surface->MoveTo(centreX + blobSize, centreY + blobSize); surface->LineTo(centreX + blobSize, centreY - blobSize); surface->MoveTo(centreX + 1, centreY - blobSize); surface->LineTo(centreX + blobSize + 1, centreY - blobSize); } } else if (markType == SC_MARK_BOXMINUS) { DrawBox(surface, centreX, centreY, blobSize, fore, colourHead); DrawMinus(surface, centreX, centreY, blobSize, colourTail); surface->PenColour(colourHead); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, ircWhole.bottom); } else if (markType == SC_MARK_BOXMINUSCONNECTED) { DrawBox(surface, centreX, centreY, blobSize, fore, colourHead); DrawMinus(surface, centreX, centreY, blobSize, colourTail); surface->PenColour(colourHead); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, ircWhole.bottom); surface->PenColour(colourBody); surface->MoveTo(centreX, ircWhole.top); surface->LineTo(centreX, centreY - blobSize); if (tFold == LineMarker::body) { surface->PenColour(colourTail); surface->MoveTo(centreX + 1, centreY + blobSize); surface->LineTo(centreX + blobSize + 1, centreY + blobSize); surface->MoveTo(centreX + blobSize, centreY + blobSize); surface->LineTo(centreX + blobSize, centreY - blobSize); surface->MoveTo(centreX + 1, centreY - blobSize); surface->LineTo(centreX + blobSize + 1, centreY - blobSize); } } else if (markType == SC_MARK_CIRCLEPLUS) { DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead); DrawPlus(surface, centreX, centreY, blobSize, colourTail); } else if (markType == SC_MARK_CIRCLEPLUSCONNECTED) { if (tFold == LineMarker::headWithTail) surface->PenColour(colourTail); else surface->PenColour(colourBody); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, ircWhole.bottom); surface->PenColour(colourBody); surface->MoveTo(centreX, ircWhole.top); surface->LineTo(centreX, centreY - blobSize); DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead); DrawPlus(surface, centreX, centreY, blobSize, colourTail); } else if (markType == SC_MARK_CIRCLEMINUS) { surface->PenColour(colourHead); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, ircWhole.bottom); DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead); DrawMinus(surface, centreX, centreY, blobSize, colourTail); } else if (markType == SC_MARK_CIRCLEMINUSCONNECTED) { surface->PenColour(colourHead); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, ircWhole.bottom); surface->PenColour(colourBody); surface->MoveTo(centreX, ircWhole.top); surface->LineTo(centreX, centreY - blobSize); DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead); DrawMinus(surface, centreX, centreY, blobSize, colourTail); } else if (markType >= SC_MARK_CHARACTER) { char character[1]; character[0] = static_cast(markType - SC_MARK_CHARACTER); const XYPOSITION width = surface->WidthText(fontForCharacter, character, 1); PRectangle rcText = rc; rcText.left += (rc.Width() - width) / 2; rcText.right = rc.left + width; surface->DrawTextClipped(rcText, fontForCharacter, rcText.bottom - 2, character, 1, fore, back); } else if (markType == SC_MARK_DOTDOTDOT) { XYPOSITION right = static_cast(centreX - 6); for (int b=0; b<3; b++) { const PRectangle rcBlob(right, rc.bottom - 4, right + 2, rc.bottom-2); surface->FillRectangle(rcBlob, fore); right += 5.0f; } } else if (markType == SC_MARK_ARROWS) { surface->PenColour(fore); int right = centreX - 2; const int armLength = dimOn2 - 1; for (int b = 0; b<3; b++) { surface->MoveTo(right, centreY); surface->LineTo(right - armLength, centreY - armLength); surface->MoveTo(right, centreY); surface->LineTo(right - armLength, centreY + armLength); right += 4; } } else if (markType == SC_MARK_SHORTARROW) { Point pts[] = { Point::FromInts(centreX, centreY + dimOn2), Point::FromInts(centreX + dimOn2, centreY), Point::FromInts(centreX, centreY - dimOn2), Point::FromInts(centreX, centreY - dimOn4), Point::FromInts(centreX - dimOn4, centreY - dimOn4), Point::FromInts(centreX - dimOn4, centreY + dimOn4), Point::FromInts(centreX, centreY + dimOn4), Point::FromInts(centreX, centreY + dimOn2), }; surface->Polygon(pts, ELEMENTS(pts), fore, back); } else if (markType == SC_MARK_LEFTRECT) { PRectangle rcLeft = rcWhole; rcLeft.right = rcLeft.left + 4; surface->FillRectangle(rcLeft, back); } else if (markType == SC_MARK_BOOKMARK) { const int halfHeight = minDim / 3; Point pts[] = { Point::FromInts(ircWhole.left, centreY-halfHeight), Point::FromInts(ircWhole.right - 3, centreY - halfHeight), Point::FromInts(ircWhole.right - 3 - halfHeight, centreY), Point::FromInts(ircWhole.right - 3, centreY + halfHeight), Point::FromInts(ircWhole.left, centreY + halfHeight), }; surface->Polygon(pts, ELEMENTS(pts), fore, back); } else { // SC_MARK_FULLRECT surface->FillRectangle(rcWhole, back); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/LineMarker.h000066400000000000000000000027461463772530400257720ustar00rootroot00000000000000// Scintilla source code edit control /** @file LineMarker.h ** Defines the look of a line marker in the margin . **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LINEMARKER_H #define LINEMARKER_H namespace Scintilla { class XPM; class RGBAImage; typedef void (*DrawLineMarkerFn)(Surface *surface, PRectangle &rcWhole, Font &fontForCharacter, int tFold, int marginStyle, const void *lineMarker); /** */ class LineMarker { public: enum typeOfFold { undefined, head, body, tail, headWithTail }; int markType; ColourDesired fore; ColourDesired back; ColourDesired backSelected; int alpha; std::unique_ptr pxpm; std::unique_ptr image; /** Some platforms, notably PLAT_CURSES, do not support Scintilla's native * Draw function for drawing line markers. Allow those platforms to override * it instead of creating a new method(s) in the Surface class that existing * platforms must implement as empty. */ DrawLineMarkerFn customDraw; LineMarker(); LineMarker(const LineMarker &); virtual ~LineMarker(); LineMarker &operator=(const LineMarker &other); void SetXPM(const char *textForm); void SetXPM(const char *const *linesForm); void SetRGBAImage(Point sizeRGBAImage, float scale, const unsigned char *pixelsRGBAImage); void Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharacter, typeOfFold tFold, int marginStyle) const; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/MarginView.cpp000066400000000000000000000406631463772530400263440ustar00rootroot00000000000000// Scintilla source code edit control /** @file MarginView.cxx ** Defines the appearance of the editor margin. **/ // Copyright 1998-2014 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILoader.h" #include "ILexer.h" #include "Scintilla.h" #include "Position.h" #include "IntegerRectangle.h" #include "UniqueString.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "KeyMap.h" #include "Indicator.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" #include "EditModel.h" #include "MarginView.h" #include "EditView.h" using namespace Scintilla; namespace Scintilla { void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour) { surface->PenColour(wrapColour); const IntegerRectangle ircPlace(rcPlace); enum { xa = 1 }; // gap before start const int w = ircPlace.Width() - xa - 1; const bool xStraight = isEndMarker; // x-mirrored symbol for start marker const int x0 = xStraight ? ircPlace.left : ircPlace.right - 1; const int y0 = ircPlace.top; const int dy = ircPlace.Height() / 5; const int y = ircPlace.Height() / 2 + dy; struct Relative { Surface *surface; int xBase; int xDir; int yBase; int yDir; void MoveTo(int xRelative, int yRelative) { surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative); } void LineTo(int xRelative, int yRelative) { surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative); } }; Relative rel = { surface, x0, xStraight ? 1 : -1, y0, 1 }; // arrow head rel.MoveTo(xa, y); rel.LineTo(xa + 2 * w / 3, y - dy); rel.MoveTo(xa, y); rel.LineTo(xa + 2 * w / 3, y + dy); // arrow body rel.MoveTo(xa, y); rel.LineTo(xa + w, y); rel.LineTo(xa + w, y - 2 * dy); rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not... y - 2 * dy); } MarginView::MarginView() { wrapMarkerPaddingRight = 3; customDrawWrapMarker = nullptr; } void MarginView::DropGraphics(bool freeObjects) { if (freeObjects) { pixmapSelMargin.reset(); pixmapSelPattern.reset(); pixmapSelPatternOffset1.reset(); } else { if (pixmapSelMargin) pixmapSelMargin->Release(); if (pixmapSelPattern) pixmapSelPattern->Release(); if (pixmapSelPatternOffset1) pixmapSelPatternOffset1->Release(); } } void MarginView::AllocateGraphics(const ViewStyle &vsDraw) { if (!pixmapSelMargin) pixmapSelMargin.reset(Surface::Allocate(vsDraw.technology)); if (!pixmapSelPattern) pixmapSelPattern.reset(Surface::Allocate(vsDraw.technology)); if (!pixmapSelPatternOffset1) pixmapSelPatternOffset1.reset(Surface::Allocate(vsDraw.technology)); } void MarginView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) { if (!pixmapSelPattern->Initialised()) { const int patternSize = 8; pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wid); pixmapSelPatternOffset1->InitPixMap(patternSize, patternSize, surfaceWindow, wid); // This complex procedure is to reproduce the checkerboard dithered pattern used by windows // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half // way between the chrome colour and the chrome highlight colour making a nice transition // between the window chrome and the content area. And it works in low colour depths. const PRectangle rcPattern = PRectangle::FromInts(0, 0, patternSize, patternSize); // Initialize default colours based on the chrome colour scheme. Typically the highlight is white. ColourDesired colourFMFill = vsDraw.selbar; ColourDesired colourFMStripes = vsDraw.selbarlight; if (!(vsDraw.selbarlight == ColourDesired(0xff, 0xff, 0xff))) { // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. // (Typically, the highlight colour is white.) colourFMFill = vsDraw.selbarlight; } if (vsDraw.foldmarginColour.isSet) { // override default fold margin colour colourFMFill = vsDraw.foldmarginColour; } if (vsDraw.foldmarginHighlightColour.isSet) { // override default fold margin highlight colour colourFMStripes = vsDraw.foldmarginHighlightColour; } pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); pixmapSelPatternOffset1->FillRectangle(rcPattern, colourFMStripes); for (int y = 0; y < patternSize; y++) { for (int x = y % 2; x < patternSize; x += 2) { const PRectangle rcPixel = PRectangle::FromInts(x, y, x + 1, y + 1); pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes); pixmapSelPatternOffset1->FillRectangle(rcPixel, colourFMFill); } } } } static int SubstituteMarkerIfEmpty(int markerCheck, int markerDefault, const ViewStyle &vs) { if (vs.markers[markerCheck].markType == SC_MARK_EMPTY) return markerDefault; return markerCheck; } void MarginView::PaintMargin(Surface *surface, Sci::Line topLine, PRectangle rc, PRectangle rcMargin, const EditModel &model, const ViewStyle &vs) { PRectangle rcSelMargin = rcMargin; rcSelMargin.right = rcMargin.left; if (rcSelMargin.bottom < rc.bottom) rcSelMargin.bottom = rc.bottom; const Point ptOrigin = model.GetVisibleOriginInMain(); FontAlias fontLineNumber = vs.styles[STYLE_LINENUMBER].font; for (size_t margin = 0; margin < vs.ms.size(); margin++) { if (vs.ms[margin].width > 0) { rcSelMargin.left = rcSelMargin.right; rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; if (vs.ms[margin].style != SC_MARGIN_NUMBER) { if (vs.ms[margin].mask & SC_MASK_FOLDERS) { // Required because of special way brush is created for selection margin // Ensure patterns line up when scrolling with separate margin view // by choosing correctly aligned variant. const bool invertPhase = static_cast(ptOrigin.y) & 1; surface->FillRectangle(rcSelMargin, invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1); } else { ColourDesired colour; switch (vs.ms[margin].style) { case SC_MARGIN_BACK: colour = vs.styles[STYLE_DEFAULT].back; break; case SC_MARGIN_FORE: colour = vs.styles[STYLE_DEFAULT].fore; break; case SC_MARGIN_COLOUR: colour = vs.ms[margin].back; break; default: colour = vs.styles[STYLE_LINENUMBER].back; break; } surface->FillRectangle(rcSelMargin, colour); } } else { surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back); } const int lineStartPaint = static_cast(rcMargin.top + ptOrigin.y) / vs.lineHeight; Sci::Line visibleLine = model.TopLineOfMain() + lineStartPaint; Sci::Position yposScreen = lineStartPaint * vs.lineHeight - static_cast(ptOrigin.y); // Work out whether the top line is whitespace located after a // lessening of fold level which implies a 'fold tail' but which should not // be displayed until the last of a sequence of whitespace. bool needWhiteClosure = false; if (vs.ms[margin].mask & SC_MASK_FOLDERS) { const int level = model.pdoc->GetLevel(model.pcs->DocFromDisplay(visibleLine)); if (level & SC_FOLDLEVELWHITEFLAG) { Sci::Line lineBack = model.pcs->DocFromDisplay(visibleLine); int levelPrev = level; while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) { lineBack--; levelPrev = model.pdoc->GetLevel(lineBack); } if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) { if (LevelNumber(level) < LevelNumber(levelPrev)) needWhiteClosure = true; } } if (highlightDelimiter.isEnabled) { const Sci::Line lastLine = model.pcs->DocFromDisplay(topLine + model.LinesOnScreen()) + 1; model.pdoc->GetHighlightDelimiters(highlightDelimiter, model.pdoc->SciLineFromPosition(model.sel.MainCaret()), lastLine); } } // Old code does not know about new markers needed to distinguish all cases const int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID, SC_MARKNUM_FOLDEROPEN, vs); const int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND, SC_MARKNUM_FOLDER, vs); while ((visibleLine < model.pcs->LinesDisplayed()) && yposScreen < rc.bottom) { PLATFORM_ASSERT(visibleLine < model.pcs->LinesDisplayed()); const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine); PLATFORM_ASSERT(model.pcs->GetVisible(lineDoc)); const Sci::Line firstVisibleLine = model.pcs->DisplayFromDoc(lineDoc); const Sci::Line lastVisibleLine = model.pcs->DisplayLastFromDoc(lineDoc); const bool firstSubLine = visibleLine == firstVisibleLine; const bool lastSubLine = visibleLine == lastVisibleLine; int marks = model.pdoc->GetMark(lineDoc); if (!firstSubLine) marks = 0; bool headWithTail = false; if (vs.ms[margin].mask & SC_MASK_FOLDERS) { // Decide which fold indicator should be displayed const int level = model.pdoc->GetLevel(lineDoc); const int levelNext = model.pdoc->GetLevel(lineDoc + 1); const int levelNum = LevelNumber(level); const int levelNextNum = LevelNumber(levelNext); if (level & SC_FOLDLEVELHEADERFLAG) { if (firstSubLine) { if (levelNum < levelNextNum) { if (model.pcs->GetExpanded(lineDoc)) { if (levelNum == SC_FOLDLEVELBASE) marks |= 1 << SC_MARKNUM_FOLDEROPEN; else marks |= 1 << folderOpenMid; } else { if (levelNum == SC_FOLDLEVELBASE) marks |= 1 << SC_MARKNUM_FOLDER; else marks |= 1 << folderEnd; } } else if (levelNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } else { if (levelNum < levelNextNum) { if (model.pcs->GetExpanded(lineDoc)) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } else if (levelNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } else if (levelNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } needWhiteClosure = false; const Sci::Line firstFollowupLine = model.pcs->DocFromDisplay(model.pcs->DisplayFromDoc(lineDoc + 1)); const int firstFollowupLineLevel = model.pdoc->GetLevel(firstFollowupLine); const int secondFollowupLineLevelNum = LevelNumber(model.pdoc->GetLevel(firstFollowupLine + 1)); if (!model.pcs->GetExpanded(lineDoc)) { if ((firstFollowupLineLevel & SC_FOLDLEVELWHITEFLAG) && (levelNum > secondFollowupLineLevelNum)) needWhiteClosure = true; if (highlightDelimiter.IsFoldBlockHighlighted(firstFollowupLine)) headWithTail = true; } } else if (level & SC_FOLDLEVELWHITEFLAG) { if (needWhiteClosure) { if (levelNext & SC_FOLDLEVELWHITEFLAG) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } else if (levelNextNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; needWhiteClosure = false; } else { marks |= 1 << SC_MARKNUM_FOLDERTAIL; needWhiteClosure = false; } } else if (levelNum > SC_FOLDLEVELBASE) { if (levelNextNum < levelNum) { if (levelNextNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; } else { marks |= 1 << SC_MARKNUM_FOLDERTAIL; } } else { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } } else if (levelNum > SC_FOLDLEVELBASE) { if (levelNextNum < levelNum) { needWhiteClosure = false; if (levelNext & SC_FOLDLEVELWHITEFLAG) { marks |= 1 << SC_MARKNUM_FOLDERSUB; needWhiteClosure = true; } else if (lastSubLine) { if (levelNextNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; } else { marks |= 1 << SC_MARKNUM_FOLDERTAIL; } } else { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } else { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } } marks &= vs.ms[margin].mask; PRectangle rcMarker = rcSelMargin; rcMarker.top = static_cast(yposScreen); rcMarker.bottom = static_cast(yposScreen + vs.lineHeight); if (vs.ms[margin].style == SC_MARGIN_NUMBER) { if (firstSubLine) { std::string sNumber; if (lineDoc >= 0) { sNumber = std::to_string(lineDoc + 1); } if (model.foldFlags & (SC_FOLDFLAG_LEVELNUMBERS | SC_FOLDFLAG_LINESTATE)) { char number[100] = ""; if (model.foldFlags & SC_FOLDFLAG_LEVELNUMBERS) { const int lev = model.pdoc->GetLevel(lineDoc); sprintf(number, "%c%c %03X %03X", (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_', (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_', LevelNumber(lev), lev >> 16 ); } else { const int state = model.pdoc->GetLineState(lineDoc); sprintf(number, "%0X", state); } sNumber = number; } PRectangle rcNumber = rcMarker; // Right justify const XYPOSITION width = surface->WidthText(fontLineNumber, sNumber.c_str(), static_cast(sNumber.length())); const XYPOSITION xpos = rcNumber.right - width - vs.marginNumberPadding; rcNumber.left = xpos; DrawTextNoClipPhase(surface, rcNumber, vs.styles[STYLE_LINENUMBER], rcNumber.top + vs.maxAscent, sNumber.c_str(), static_cast(sNumber.length()), drawAll); } else if (vs.wrapVisualFlags & SC_WRAPVISUALFLAG_MARGIN) { PRectangle rcWrapMarker = rcMarker; rcWrapMarker.right -= wrapMarkerPaddingRight; rcWrapMarker.left = rcWrapMarker.right - vs.styles[STYLE_LINENUMBER].aveCharWidth; if (!customDrawWrapMarker) { DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore); } else { customDrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore); } } } else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) { const StyledText stMargin = model.pdoc->MarginStyledText(lineDoc); if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { if (firstSubLine) { surface->FillRectangle(rcMarker, vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back); if (vs.ms[margin].style == SC_MARGIN_RTEXT) { const int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); rcMarker.left = rcMarker.right - width - 3; } DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, stMargin, 0, stMargin.length, drawAll); } else { // if we're displaying annotation lines, color the margin to match the associated document line const int annotationLines = model.pdoc->AnnotationLines(lineDoc); if (annotationLines && (visibleLine > lastVisibleLine - annotationLines)) { surface->FillRectangle(rcMarker, vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back); } } } } if (marks) { for (int markBit = 0; (markBit < 32) && marks; markBit++) { if (marks & 1) { LineMarker::typeOfFold tFold = LineMarker::undefined; if ((vs.ms[margin].mask & SC_MASK_FOLDERS) && highlightDelimiter.IsFoldBlockHighlighted(lineDoc)) { if (highlightDelimiter.IsBodyOfFoldBlock(lineDoc)) { tFold = LineMarker::body; } else if (highlightDelimiter.IsHeadOfFoldBlock(lineDoc)) { if (firstSubLine) { tFold = headWithTail ? LineMarker::headWithTail : LineMarker::head; } else { if (model.pcs->GetExpanded(lineDoc) || headWithTail) { tFold = LineMarker::body; } else { tFold = LineMarker::undefined; } } } else if (highlightDelimiter.IsTailOfFoldBlock(lineDoc)) { tFold = LineMarker::tail; } } vs.markers[markBit].Draw(surface, rcMarker, fontLineNumber, tFold, vs.ms[margin].style); } marks >>= 1; } } visibleLine++; yposScreen += vs.lineHeight; } } } PRectangle rcBlankMargin = rcMargin; rcBlankMargin.left = rcSelMargin.right; surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/MarginView.h000066400000000000000000000030501463772530400257760ustar00rootroot00000000000000// Scintilla source code edit control /** @file MarginView.h ** Defines the appearance of the editor margin. **/ // Copyright 1998-2014 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef MARGINVIEW_H #define MARGINVIEW_H namespace Scintilla { void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour); typedef void (*DrawWrapMarkerFn)(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour); /** * MarginView draws the margins. */ class MarginView { public: std::unique_ptr pixmapSelMargin; std::unique_ptr pixmapSelPattern; std::unique_ptr pixmapSelPatternOffset1; // Highlight current folding block HighlightDelimiter highlightDelimiter; int wrapMarkerPaddingRight; // right-most pixel padding of wrap markers /** Some platforms, notably PLAT_CURSES, do not support Scintilla's native * DrawWrapMarker function for drawing wrap markers. Allow those platforms to * override it instead of creating a new method in the Surface class that * existing platforms must implement as empty. */ DrawWrapMarkerFn customDrawWrapMarker; MarginView(); void DropGraphics(bool freeObjects); void AllocateGraphics(const ViewStyle &vsDraw); void RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw); void PaintMargin(Surface *surface, Sci::Line topLine, PRectangle rc, PRectangle rcMargin, const EditModel &model, const ViewStyle &vs); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Partitioning.h000066400000000000000000000132531463772530400264030ustar00rootroot00000000000000// Scintilla source code edit control /** @file Partitioning.h ** Data structure used to partition an interval. Used for holding line start/end positions. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef PARTITIONING_H #define PARTITIONING_H namespace Scintilla { /// A split vector of integers with a method for adding a value to all elements /// in a range. /// Used by the Partitioning class. template class SplitVectorWithRangeAdd : public SplitVector { public: explicit SplitVectorWithRangeAdd(ptrdiff_t growSize_) { this->SetGrowSize(growSize_); this->ReAllocate(growSize_); } // Deleted so SplitVectorWithRangeAdd objects can not be copied. SplitVectorWithRangeAdd(const SplitVectorWithRangeAdd &) = delete; SplitVectorWithRangeAdd(SplitVectorWithRangeAdd &&) = delete; void operator=(const SplitVectorWithRangeAdd &) = delete; void operator=(SplitVectorWithRangeAdd &&) = delete; ~SplitVectorWithRangeAdd() { } void RangeAddDelta(ptrdiff_t start, ptrdiff_t end, T delta) noexcept { // end is 1 past end, so end-start is number of elements to change ptrdiff_t i = 0; const ptrdiff_t rangeLength = end - start; ptrdiff_t range1Length = rangeLength; const ptrdiff_t part1Left = this->part1Length - start; if (range1Length > part1Left) range1Length = part1Left; while (i < range1Length) { this->body[start++] += delta; i++; } start += this->gapLength; while (i < rangeLength) { this->body[start++] += delta; i++; } } }; /// Divide an interval into multiple partitions. /// Useful for breaking a document down into sections such as lines. /// A 0 length interval has a single 0 length partition, numbered 0 /// If interval not 0 length then each partition non-zero length /// When needed, positions after the interval are considered part of the last partition /// but the end of the last partition can be found with PositionFromPartition(last+1). template class Partitioning { private: // To avoid calculating all the partition positions whenever any text is inserted // there may be a step somewhere in the list. T stepPartition; T stepLength; std::unique_ptr> body; // Move step forward void ApplyStep(T partitionUpTo) noexcept { if (stepLength != 0) { body->RangeAddDelta(stepPartition+1, partitionUpTo + 1, stepLength); } stepPartition = partitionUpTo; if (stepPartition >= body->Length()-1) { stepPartition = Partitions(); stepLength = 0; } } // Move step backward void BackStep(T partitionDownTo) noexcept { if (stepLength != 0) { body->RangeAddDelta(partitionDownTo+1, stepPartition+1, -stepLength); } stepPartition = partitionDownTo; } void Allocate(ptrdiff_t growSize) { body.reset(new SplitVectorWithRangeAdd(growSize)); stepPartition = 0; stepLength = 0; body->Insert(0, 0); // This value stays 0 for ever body->Insert(1, 0); // This is the end of the first partition and will be the start of the second } public: explicit Partitioning(int growSize) : stepPartition(0), stepLength(0) { Allocate(growSize); } // Deleted so Partitioning objects can not be copied. Partitioning(const Partitioning &) = delete; Partitioning(Partitioning &&) = delete; void operator=(const Partitioning &) = delete; void operator=(Partitioning &&) = delete; ~Partitioning() { } T Partitions() const noexcept { return static_cast(body->Length())-1; } void InsertPartition(T partition, T pos) { if (stepPartition < partition) { ApplyStep(partition); } body->Insert(partition, pos); stepPartition++; } void SetPartitionStartPosition(T partition, T pos) noexcept { ApplyStep(partition+1); if ((partition < 0) || (partition > body->Length())) { return; } body->SetValueAt(partition, pos); } void InsertText(T partitionInsert, T delta) { // Point all the partitions after the insertion point further along in the buffer if (stepLength != 0) { if (partitionInsert >= stepPartition) { // Fill in up to the new insertion point ApplyStep(partitionInsert); stepLength += delta; } else if (partitionInsert >= (stepPartition - body->Length() / 10)) { // Close to step but before so move step back BackStep(partitionInsert); stepLength += delta; } else { ApplyStep(Partitions()); stepPartition = partitionInsert; stepLength = delta; } } else { stepPartition = partitionInsert; stepLength = delta; } } void RemovePartition(T partition) { if (partition > stepPartition) { ApplyStep(partition); stepPartition--; } else { stepPartition--; } body->Delete(partition); } T PositionFromPartition(T partition) const noexcept { PLATFORM_ASSERT(partition >= 0); PLATFORM_ASSERT(partition < body->Length()); const ptrdiff_t lengthBody = body->Length(); if ((partition < 0) || (partition >= lengthBody)) { return 0; } T pos = body->ValueAt(partition); if (partition > stepPartition) pos += stepLength; return pos; } /// Return value in range [0 .. Partitions() - 1] even for arguments outside interval T PartitionFromPosition(T pos) const noexcept { if (body->Length() <= 1) return 0; if (pos >= (PositionFromPartition(Partitions()))) return Partitions() - 1; T lower = 0; T upper = Partitions(); do { const T middle = (upper + lower + 1) / 2; // Round high T posMiddle = body->ValueAt(middle); if (middle > stepPartition) posMiddle += stepLength; if (pos < posMiddle) { upper = middle - 1; } else { lower = middle; } } while (lower < upper); return lower; } void DeleteAll() { Allocate(body->GetGrowSize()); } }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/PerLine.cpp000066400000000000000000000312051463772530400256220ustar00rootroot00000000000000// Scintilla source code edit control /** @file PerLine.cxx ** Manages data associated with each line of the document **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "Position.h" #include "SplitVector.h" #include "Partitioning.h" #include "CellBuffer.h" #include "PerLine.h" using namespace Scintilla; MarkerHandleSet::MarkerHandleSet() { } MarkerHandleSet::~MarkerHandleSet() { mhList.clear(); } bool MarkerHandleSet::Empty() const noexcept { return mhList.empty(); } int MarkerHandleSet::MarkValue() const noexcept { unsigned int m = 0; for (const MarkerHandleNumber &mhn : mhList) { m |= (1 << mhn.number); } return m; } bool MarkerHandleSet::Contains(int handle) const noexcept { for (const MarkerHandleNumber &mhn : mhList) { if (mhn.handle == handle) { return true; } } return false; } bool MarkerHandleSet::InsertHandle(int handle, int markerNum) { mhList.push_front(MarkerHandleNumber(handle, markerNum)); return true; } void MarkerHandleSet::RemoveHandle(int handle) { mhList.remove_if([handle](const MarkerHandleNumber &mhn) { return mhn.handle == handle; }); } bool MarkerHandleSet::RemoveNumber(int markerNum, bool all) { bool performedDeletion = false; mhList.remove_if([&](const MarkerHandleNumber &mhn) { if ((all || !performedDeletion) && (mhn.number == markerNum)) { performedDeletion = true; return true; } return false; }); return performedDeletion; } void MarkerHandleSet::CombineWith(MarkerHandleSet *other) { mhList.splice_after(mhList.before_begin(), other->mhList); } LineMarkers::~LineMarkers() { markers.DeleteAll(); } void LineMarkers::Init() { markers.DeleteAll(); } void LineMarkers::InsertLine(Sci::Line line) { if (markers.Length()) { markers.Insert(line, 0); } } void LineMarkers::RemoveLine(Sci::Line line) { // Retain the markers from the deleted line by oring them into the previous line if (markers.Length()) { if (line > 0) { MergeMarkers(line - 1); } markers.Delete(line); } } Sci::Line LineMarkers::LineFromHandle(int markerHandle) { if (markers.Length()) { for (Sci::Line line = 0; line < markers.Length(); line++) { if (markers[line]) { if (markers[line]->Contains(markerHandle)) { return line; } } } } return -1; } void LineMarkers::MergeMarkers(Sci::Line line) { if (markers[line + 1]) { if (!markers[line]) markers[line].reset(new MarkerHandleSet); markers[line]->CombineWith(markers[line + 1].get()); markers[line + 1].reset(); } } int LineMarkers::MarkValue(Sci::Line line) noexcept { if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) return markers[line]->MarkValue(); else return 0; } Sci::Line LineMarkers::MarkerNext(Sci::Line lineStart, int mask) const { if (lineStart < 0) lineStart = 0; const Sci::Line length = static_cast(markers.Length()); for (Sci::Line iLine = lineStart; iLine < length; iLine++) { const MarkerHandleSet *onLine = markers[iLine].get(); if (onLine && ((onLine->MarkValue() & mask) != 0)) return iLine; } return -1; } int LineMarkers::AddMark(Sci::Line line, int markerNum, Sci::Line lines) { handleCurrent++; if (!markers.Length()) { // No existing markers so allocate one element per line markers.InsertEmpty(0, lines); } if (line >= markers.Length()) { return -1; } if (!markers[line]) { // Need new structure to hold marker handle markers[line].reset(new MarkerHandleSet()); } markers[line]->InsertHandle(handleCurrent, markerNum); return handleCurrent; } bool LineMarkers::DeleteMark(Sci::Line line, int markerNum, bool all) { bool someChanges = false; if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) { if (markerNum == -1) { someChanges = true; markers[line].reset(); } else { someChanges = markers[line]->RemoveNumber(markerNum, all); if (markers[line]->Empty()) { markers[line].reset(); } } } return someChanges; } void LineMarkers::DeleteMarkFromHandle(int markerHandle) { const Sci::Line line = LineFromHandle(markerHandle); if (line >= 0) { markers[line]->RemoveHandle(markerHandle); if (markers[line]->Empty()) { markers[line].reset(); } } } LineLevels::~LineLevels() { } void LineLevels::Init() { levels.DeleteAll(); } void LineLevels::InsertLine(Sci::Line line) { if (levels.Length()) { const int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE; levels.InsertValue(line, 1, level); } } void LineLevels::RemoveLine(Sci::Line line) { if (levels.Length()) { // Move up following lines but merge header flag from this line // to line before to avoid a temporary disappearence causing expansion. int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG; levels.Delete(line); if (line == levels.Length()-1) // Last line loses the header flag levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG; else if (line > 0) levels[line-1] |= firstHeader; } } void LineLevels::ExpandLevels(Sci::Line sizeNew) { levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE); } void LineLevels::ClearLevels() { levels.DeleteAll(); } int LineLevels::SetLevel(Sci::Line line, int level, Sci::Line lines) { int prev = 0; if ((line >= 0) && (line < lines)) { if (!levels.Length()) { ExpandLevels(lines + 1); } prev = levels[line]; if (prev != level) { levels[line] = level; } } return prev; } int LineLevels::GetLevel(Sci::Line line) const { if (levels.Length() && (line >= 0) && (line < levels.Length())) { return levels[line]; } else { return SC_FOLDLEVELBASE; } } LineState::~LineState() { } void LineState::Init() { lineStates.DeleteAll(); } void LineState::InsertLine(Sci::Line line) { if (lineStates.Length()) { lineStates.EnsureLength(line); const int val = (line < lineStates.Length()) ? lineStates[line] : 0; lineStates.Insert(line, val); } } void LineState::RemoveLine(Sci::Line line) { if (lineStates.Length() > line) { lineStates.Delete(line); } } int LineState::SetLineState(Sci::Line line, int state) { lineStates.EnsureLength(line + 1); const int stateOld = lineStates[line]; lineStates[line] = state; return stateOld; } int LineState::GetLineState(Sci::Line line) { if (line < 0) return 0; lineStates.EnsureLength(line + 1); return lineStates[line]; } Sci::Line LineState::GetMaxLineState() const { return static_cast(lineStates.Length()); } static int NumberLines(const char *text) noexcept { if (text) { int newLines = 0; while (*text) { if (*text == '\n') newLines++; text++; } return newLines+1; } else { return 0; } } // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader // and then has text and optional styles. static const int IndividualStyles = 0x100; struct AnnotationHeader { short style; // Style IndividualStyles implies array of styles short lines; int length; }; LineAnnotation::~LineAnnotation() { ClearAll(); } void LineAnnotation::Init() { ClearAll(); } void LineAnnotation::InsertLine(Sci::Line line) { if (annotations.Length()) { annotations.EnsureLength(line); annotations.Insert(line, std::unique_ptr()); } } void LineAnnotation::RemoveLine(Sci::Line line) { if (annotations.Length() && (line > 0) && (line <= annotations.Length())) { annotations[line-1].reset(); annotations.Delete(line-1); } } bool LineAnnotation::MultipleStyles(Sci::Line line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return reinterpret_cast(annotations[line].get())->style == IndividualStyles; else return false; } int LineAnnotation::Style(Sci::Line line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return reinterpret_cast(annotations[line].get())->style; else return 0; } const char *LineAnnotation::Text(Sci::Line line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return annotations[line].get()+sizeof(AnnotationHeader); else return nullptr; } const unsigned char *LineAnnotation::Styles(Sci::Line line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line] && MultipleStyles(line)) return reinterpret_cast(annotations[line].get() + sizeof(AnnotationHeader) + Length(line)); else return nullptr; } static char *AllocateAnnotation(int length, int style) { const size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0); char *ret = new char[len](); return ret; } void LineAnnotation::SetText(Sci::Line line, const char *text) { if (text && (line >= 0)) { annotations.EnsureLength(line+1); const int style = Style(line); annotations[line].reset(AllocateAnnotation(static_cast(strlen(text)), style)); char *pa = annotations[line].get(); assert(pa); AnnotationHeader *pah = reinterpret_cast(pa); pah->style = static_cast(style); pah->length = static_cast(strlen(text)); pah->lines = static_cast(NumberLines(text)); memcpy(pa+sizeof(AnnotationHeader), text, pah->length); } else { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) { annotations[line].reset(); } } } void LineAnnotation::ClearAll() { annotations.DeleteAll(); } void LineAnnotation::SetStyle(Sci::Line line, int style) { annotations.EnsureLength(line+1); if (!annotations[line]) { annotations[line].reset(AllocateAnnotation(0, style)); } reinterpret_cast(annotations[line].get())->style = static_cast(style); } void LineAnnotation::SetStyles(Sci::Line line, const unsigned char *styles) { if (line >= 0) { annotations.EnsureLength(line+1); if (!annotations[line]) { annotations[line].reset(AllocateAnnotation(0, IndividualStyles)); } else { const AnnotationHeader *pahSource = reinterpret_cast(annotations[line].get()); if (pahSource->style != IndividualStyles) { char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles); AnnotationHeader *pahAlloc = reinterpret_cast(allocation); pahAlloc->length = pahSource->length; pahAlloc->lines = pahSource->lines; memcpy(allocation + sizeof(AnnotationHeader), annotations[line].get() + sizeof(AnnotationHeader), pahSource->length); annotations[line].reset(allocation); } } AnnotationHeader *pah = reinterpret_cast(annotations[line].get()); pah->style = IndividualStyles; memcpy(annotations[line].get() + sizeof(AnnotationHeader) + pah->length, styles, pah->length); } } int LineAnnotation::Length(Sci::Line line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return reinterpret_cast(annotations[line].get())->length; else return 0; } int LineAnnotation::Lines(Sci::Line line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return reinterpret_cast(annotations[line].get())->lines; else return 0; } LineTabstops::~LineTabstops() { tabstops.DeleteAll(); } void LineTabstops::Init() { tabstops.DeleteAll(); } void LineTabstops::InsertLine(Sci::Line line) { if (tabstops.Length()) { tabstops.EnsureLength(line); tabstops.Insert(line, nullptr); } } void LineTabstops::RemoveLine(Sci::Line line) { if (tabstops.Length() > line) { tabstops[line].reset(); tabstops.Delete(line); } } bool LineTabstops::ClearTabstops(Sci::Line line) { if (line < tabstops.Length()) { TabstopList *tl = tabstops[line].get(); if (tl) { tl->clear(); return true; } } return false; } bool LineTabstops::AddTabstop(Sci::Line line, int x) { tabstops.EnsureLength(line + 1); if (!tabstops[line]) { tabstops[line].reset(new TabstopList()); } TabstopList *tl = tabstops[line].get(); if (tl) { // tabstop positions are kept in order - insert in the right place std::vector::iterator it = std::lower_bound(tl->begin(), tl->end(), x); // don't insert duplicates if (it == tl->end() || *it != x) { tl->insert(it, x); return true; } } return false; } int LineTabstops::GetNextTabstop(Sci::Line line, int x) const { if (line < tabstops.Length()) { TabstopList *tl = tabstops[line].get(); if (tl) { for (const int i : *tl) { if (i > x) { return i; } } } } return 0; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/PerLine.h000066400000000000000000000117541463772530400252760ustar00rootroot00000000000000// Scintilla source code edit control /** @file PerLine.h ** Manages data associated with each line of the document **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef PERLINE_H #define PERLINE_H namespace Scintilla { /** * This holds the marker identifier and the marker type to display. * MarkerHandleNumbers are members of lists. */ struct MarkerHandleNumber { int handle; int number; MarkerHandleNumber(int handle_, int number_) : handle(handle_), number(number_) {} }; /** * A marker handle set contains any number of MarkerHandleNumbers. */ class MarkerHandleSet { std::forward_list mhList; public: MarkerHandleSet(); // Deleted so MarkerHandleSet objects can not be copied. MarkerHandleSet(const MarkerHandleSet &) = delete; MarkerHandleSet(MarkerHandleSet &&) = delete; void operator=(const MarkerHandleSet &) = delete; void operator=(MarkerHandleSet &&) = delete; ~MarkerHandleSet(); bool Empty() const noexcept; int MarkValue() const noexcept; ///< Bit set of marker numbers. bool Contains(int handle) const noexcept; bool InsertHandle(int handle, int markerNum); void RemoveHandle(int handle); bool RemoveNumber(int markerNum, bool all); void CombineWith(MarkerHandleSet *other); }; class LineMarkers : public PerLine { SplitVector> markers; /// Handles are allocated sequentially and should never have to be reused as 32 bit ints are very big. int handleCurrent; public: LineMarkers() : handleCurrent(0) { } // Deleted so LineMarkers objects can not be copied. LineMarkers(const LineMarkers &) = delete; LineMarkers(LineMarkers &&) = delete; void operator=(const LineMarkers &) = delete; void operator=(LineMarkers &&) = delete; ~LineMarkers() override; void Init() override; void InsertLine(Sci::Line line) override; void RemoveLine(Sci::Line line) override; int MarkValue(Sci::Line line) noexcept; Sci::Line MarkerNext(Sci::Line lineStart, int mask) const; int AddMark(Sci::Line line, int markerNum, Sci::Line lines); void MergeMarkers(Sci::Line line); bool DeleteMark(Sci::Line line, int markerNum, bool all); void DeleteMarkFromHandle(int markerHandle); Sci::Line LineFromHandle(int markerHandle); }; class LineLevels : public PerLine { SplitVector levels; public: LineLevels() { } // Deleted so LineLevels objects can not be copied. LineLevels(const LineLevels &) = delete; LineLevels(LineLevels &&) = delete; void operator=(const LineLevels &) = delete; void operator=(LineLevels &&) = delete; ~LineLevels() override; void Init() override; void InsertLine(Sci::Line line) override; void RemoveLine(Sci::Line line) override; void ExpandLevels(Sci::Line sizeNew=-1); void ClearLevels(); int SetLevel(Sci::Line line, int level, Sci::Line lines); int GetLevel(Sci::Line line) const; }; class LineState : public PerLine { SplitVector lineStates; public: LineState() { } // Deleted so LineState objects can not be copied. LineState(const LineState &) = delete; LineState(LineState &&) = delete; void operator=(const LineState &) = delete; void operator=(LineState &&) = delete; ~LineState() override; void Init() override; void InsertLine(Sci::Line line) override; void RemoveLine(Sci::Line line) override; int SetLineState(Sci::Line line, int state); int GetLineState(Sci::Line line); Sci::Line GetMaxLineState() const; }; class LineAnnotation : public PerLine { SplitVector> annotations; public: LineAnnotation() { } // Deleted so LineAnnotation objects can not be copied. LineAnnotation(const LineAnnotation &) = delete; LineAnnotation(LineAnnotation &&) = delete; void operator=(const LineAnnotation &) = delete; void operator=(LineAnnotation &&) = delete; ~LineAnnotation() override; void Init() override; void InsertLine(Sci::Line line) override; void RemoveLine(Sci::Line line) override; bool MultipleStyles(Sci::Line line) const; int Style(Sci::Line line) const; const char *Text(Sci::Line line) const; const unsigned char *Styles(Sci::Line line) const; void SetText(Sci::Line line, const char *text); void ClearAll(); void SetStyle(Sci::Line line, int style); void SetStyles(Sci::Line line, const unsigned char *styles); int Length(Sci::Line line) const; int Lines(Sci::Line line) const; }; typedef std::vector TabstopList; class LineTabstops : public PerLine { SplitVector> tabstops; public: LineTabstops() { } // Deleted so LineTabstops objects can not be copied. LineTabstops(const LineTabstops &) = delete; LineTabstops(LineTabstops &&) = delete; void operator=(const LineTabstops &) = delete; void operator=(LineTabstops &&) = delete; ~LineTabstops() override; void Init() override; void InsertLine(Sci::Line line) override; void RemoveLine(Sci::Line line) override; bool ClearTabstops(Sci::Line line); bool AddTabstop(Sci::Line line, int x); int GetNextTabstop(Sci::Line line, int x) const; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/Position.h000066400000000000000000000014731463772530400255410ustar00rootroot00000000000000// Scintilla source code edit control /** @file Position.h ** Defines global type name Position in the Sci internal namespace. **/ // Copyright 2015 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef POSITION_H #define POSITION_H /** * A Position is a position within a document between two characters or at the beginning or end. * Sometimes used as a character index where it identifies the character after the position. * A Line is a document or screen line. */ namespace Sci { typedef ptrdiff_t Position; typedef ptrdiff_t Line; const Position invalidPosition = -1; template inline constexpr T clamp(T val, T minVal, T maxVal) { return (val > maxVal) ? maxVal : ((val < minVal) ? minVal : val); } } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/PositionCache.cpp000066400000000000000000000500251463772530400270150ustar00rootroot00000000000000// Scintilla source code edit control /** @file PositionCache.cxx ** Classes for caching layout information. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILoader.h" #include "ILexer.h" #include "Scintilla.h" #include "Position.h" #include "UniqueString.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "KeyMap.h" #include "Indicator.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" using namespace Scintilla; LineLayout::LineLayout(int maxLineLength_) : lenLineStarts(0), lineNumber(-1), inCache(false), maxLineLength(-1), numCharsInLine(0), numCharsBeforeEOL(0), validity(llInvalid), xHighlightGuide(0), highlightColumn(false), containsCaret(false), edgeColumn(0), bracePreviousStyles{}, hotspot(0,0), widthLine(wrapWidthInfinite), lines(1), wrapIndent(0) { Resize(maxLineLength_); } LineLayout::~LineLayout() { Free(); } void LineLayout::Resize(int maxLineLength_) { if (maxLineLength_ > maxLineLength) { Free(); chars.reset(new char[maxLineLength_ + 1]); styles.reset(new unsigned char[maxLineLength_ + 1]); // Extra position allocated as sometimes the Windows // GetTextExtentExPoint API writes an extra element. positions.reset(new XYPOSITION[maxLineLength_ + 1 + 1]); maxLineLength = maxLineLength_; } } void LineLayout::Free() { chars.reset(); styles.reset(); positions.reset(); lineStarts.reset(); } void LineLayout::Invalidate(validLevel validity_) { if (validity > validity_) validity = validity_; } int LineLayout::LineStart(int line) const { if (line <= 0) { return 0; } else if ((line >= lines) || !lineStarts) { return numCharsInLine; } else { return lineStarts[line]; } } int LineLayout::LineLastVisible(int line, Scope scope) const { if (line < 0) { return 0; } else if ((line >= lines-1) || !lineStarts) { return scope == Scope::visibleOnly ? numCharsBeforeEOL : numCharsInLine; } else { return lineStarts[line+1]; } } Range LineLayout::SubLineRange(int subLine, Scope scope) const { return Range(LineStart(subLine), LineLastVisible(subLine, scope)); } bool LineLayout::InLine(int offset, int line) const { return ((offset >= LineStart(line)) && (offset < LineStart(line + 1))) || ((offset == numCharsInLine) && (line == (lines-1))); } void LineLayout::SetLineStart(int line, int start) { if ((line >= lenLineStarts) && (line != 0)) { int newMaxLines = line + 20; int *newLineStarts = new int[newMaxLines]; for (int i = 0; i < newMaxLines; i++) { if (i < lenLineStarts) newLineStarts[i] = lineStarts[i]; else newLineStarts[i] = 0; } lineStarts.reset(newLineStarts); lenLineStarts = newMaxLines; } lineStarts[line] = start; } void LineLayout::SetBracesHighlight(Range rangeLine, const Sci::Position braces[], char bracesMatchStyle, int xHighlight, bool ignoreStyle) { if (!ignoreStyle && rangeLine.ContainsCharacter(braces[0])) { const Sci::Position braceOffset = braces[0] - rangeLine.start; if (braceOffset < numCharsInLine) { bracePreviousStyles[0] = styles[braceOffset]; styles[braceOffset] = bracesMatchStyle; } } if (!ignoreStyle && rangeLine.ContainsCharacter(braces[1])) { const Sci::Position braceOffset = braces[1] - rangeLine.start; if (braceOffset < numCharsInLine) { bracePreviousStyles[1] = styles[braceOffset]; styles[braceOffset] = bracesMatchStyle; } } if ((braces[0] >= rangeLine.start && braces[1] <= rangeLine.end) || (braces[1] >= rangeLine.start && braces[0] <= rangeLine.end)) { xHighlightGuide = xHighlight; } } void LineLayout::RestoreBracesHighlight(Range rangeLine, const Sci::Position braces[], bool ignoreStyle) { if (!ignoreStyle && rangeLine.ContainsCharacter(braces[0])) { const Sci::Position braceOffset = braces[0] - rangeLine.start; if (braceOffset < numCharsInLine) { styles[braceOffset] = bracePreviousStyles[0]; } } if (!ignoreStyle && rangeLine.ContainsCharacter(braces[1])) { const Sci::Position braceOffset = braces[1] - rangeLine.start; if (braceOffset < numCharsInLine) { styles[braceOffset] = bracePreviousStyles[1]; } } xHighlightGuide = 0; } int LineLayout::FindBefore(XYPOSITION x, Range range) const { Sci::Position lower = range.start; Sci::Position upper = range.end; do { const Sci::Position middle = (upper + lower + 1) / 2; // Round high const XYPOSITION posMiddle = positions[middle]; if (x < posMiddle) { upper = middle - 1; } else { lower = middle; } } while (lower < upper); return static_cast(lower); } int LineLayout::FindPositionFromX(XYPOSITION x, Range range, bool charPosition) const { int pos = FindBefore(x, range); while (pos < range.end) { if (charPosition) { if (x < (positions[pos + 1])) { return pos; } } else { if (x < ((positions[pos] + positions[pos + 1]) / 2)) { return pos; } } pos++; } return static_cast(range.end); } Point LineLayout::PointFromPosition(int posInLine, int lineHeight, PointEnd pe) const { Point pt; // In case of very long line put x at arbitrary large position if (posInLine > maxLineLength) { pt.x = positions[maxLineLength] - positions[LineStart(lines)]; } for (int subLine = 0; subLine < lines; subLine++) { const Range rangeSubLine = SubLineRange(subLine, Scope::visibleOnly); if (posInLine >= rangeSubLine.start) { pt.y = static_cast(subLine*lineHeight); if (posInLine <= rangeSubLine.end) { pt.x = positions[posInLine] - positions[rangeSubLine.start]; if (rangeSubLine.start != 0) // Wrapped lines may be indented pt.x += wrapIndent; if (pe & peSubLineEnd) // Return end of first subline not start of next break; } else if ((pe & peLineEnd) && (subLine == (lines-1))) { pt.x = positions[numCharsInLine] - positions[rangeSubLine.start]; if (rangeSubLine.start != 0) // Wrapped lines may be indented pt.x += wrapIndent; } } else { break; } } return pt; } int LineLayout::EndLineStyle() const { return styles[numCharsBeforeEOL > 0 ? numCharsBeforeEOL-1 : 0]; } LineLayoutCache::LineLayoutCache() : level(0), allInvalidated(false), styleClock(-1), useCount(0) { Allocate(0); } LineLayoutCache::~LineLayoutCache() { Deallocate(); } void LineLayoutCache::Allocate(size_t length_) { PLATFORM_ASSERT(cache.empty()); allInvalidated = false; cache.resize(length_); } void LineLayoutCache::AllocateForLevel(Sci::Line linesOnScreen, Sci::Line linesInDoc) { PLATFORM_ASSERT(useCount == 0); size_t lengthForLevel = 0; if (level == llcCaret) { lengthForLevel = 1; } else if (level == llcPage) { lengthForLevel = linesOnScreen + 1; } else if (level == llcDocument) { lengthForLevel = linesInDoc; } if (lengthForLevel > cache.size()) { Deallocate(); Allocate(lengthForLevel); } else { if (lengthForLevel < cache.size()) { for (size_t i = lengthForLevel; i < cache.size(); i++) { cache[i].reset(); } } cache.resize(lengthForLevel); } PLATFORM_ASSERT(cache.size() == lengthForLevel); } void LineLayoutCache::Deallocate() { PLATFORM_ASSERT(useCount == 0); cache.clear(); } void LineLayoutCache::Invalidate(LineLayout::validLevel validity_) { if (!cache.empty() && !allInvalidated) { for (const std::unique_ptr &ll : cache) { if (ll) { ll->Invalidate(validity_); } } if (validity_ == LineLayout::llInvalid) { allInvalidated = true; } } } void LineLayoutCache::SetLevel(int level_) { allInvalidated = false; if ((level_ != -1) && (level != level_)) { level = level_; Deallocate(); } } LineLayout *LineLayoutCache::Retrieve(Sci::Line lineNumber, Sci::Line lineCaret, int maxChars, int styleClock_, Sci::Line linesOnScreen, Sci::Line linesInDoc) { AllocateForLevel(linesOnScreen, linesInDoc); if (styleClock != styleClock_) { Invalidate(LineLayout::llCheckTextAndStyle); styleClock = styleClock_; } allInvalidated = false; Sci::Position pos = -1; LineLayout *ret = nullptr; if (level == llcCaret) { pos = 0; } else if (level == llcPage) { if (lineNumber == lineCaret) { pos = 0; } else if (cache.size() > 1) { pos = 1 + (lineNumber % (cache.size() - 1)); } } else if (level == llcDocument) { pos = lineNumber; } if (pos >= 0) { PLATFORM_ASSERT(useCount == 0); if (!cache.empty() && (pos < static_cast(cache.size()))) { if (cache[pos]) { if ((cache[pos]->lineNumber != lineNumber) || (cache[pos]->maxLineLength < maxChars)) { cache[pos].reset(); } } if (!cache[pos]) { cache[pos].reset(new LineLayout(maxChars)); } cache[pos]->lineNumber = lineNumber; cache[pos]->inCache = true; ret = cache[pos].get(); useCount++; } } if (!ret) { ret = new LineLayout(maxChars); ret->lineNumber = lineNumber; } return ret; } void LineLayoutCache::Dispose(LineLayout *ll) { allInvalidated = false; if (ll) { if (!ll->inCache) { delete ll; } else { useCount--; } } } // Simply pack the (maximum 4) character bytes into an int static unsigned int KeyFromString(const char *charBytes, size_t len) { PLATFORM_ASSERT(len <= 4); unsigned int k=0; for (size_t i=0; isecond); } return nullptr; } bool SpecialRepresentations::Contains(const char *charBytes, size_t len) const { PLATFORM_ASSERT(len <= 4); const unsigned char ucStart = charBytes[0]; if (!startByteHasReprs[ucStart]) return false; MapRepresentation::const_iterator it = mapReprs.find(KeyFromString(charBytes, len)); return it != mapReprs.end(); } void SpecialRepresentations::Clear() { mapReprs.clear(); const short none = 0; std::fill(startByteHasReprs, std::end(startByteHasReprs), none); } void BreakFinder::Insert(Sci::Position val) { const int posInLine = static_cast(val); if (posInLine > nextBreak) { const std::vector::iterator it = std::lower_bound(selAndEdge.begin(), selAndEdge.end(), posInLine); if (it == selAndEdge.end()) { selAndEdge.push_back(posInLine); } else if (*it != posInLine) { selAndEdge.insert(it, 1, posInLine); } } } BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, Range lineRange_, Sci::Position posLineStart_, int xStart, bool breakForSelection, const Document *pdoc_, const SpecialRepresentations *preprs_, const ViewStyle *pvsDraw) : ll(ll_), lineRange(lineRange_), posLineStart(posLineStart_), nextBreak(static_cast(lineRange_.start)), saeCurrentPos(0), saeNext(0), subBreak(-1), pdoc(pdoc_), encodingFamily(pdoc_->CodePageFamily()), preprs(preprs_) { // Search for first visible break // First find the first visible character if (xStart > 0.0f) nextBreak = ll->FindBefore(static_cast(xStart), lineRange); // Now back to a style break while ((nextBreak > lineRange.start) && (ll->styles[nextBreak] == ll->styles[nextBreak - 1])) { nextBreak--; } if (breakForSelection) { const SelectionPosition posStart(posLineStart); const SelectionPosition posEnd(posLineStart + lineRange.end); const SelectionSegment segmentLine(posStart, posEnd); for (size_t r=0; rCount(); r++) { const SelectionSegment portion = psel->Range(r).Intersect(segmentLine); if (!(portion.start == portion.end)) { if (portion.start.IsValid()) Insert(portion.start.Position() - posLineStart); if (portion.end.IsValid()) Insert(portion.end.Position() - posLineStart); } } } if (pvsDraw && pvsDraw->indicatorsSetFore) { for (const IDecoration *deco : pdoc->decorations->View()) { if (pvsDraw->indicators[deco->Indicator()].OverridesTextFore()) { Sci::Position startPos = deco->EndRun(posLineStart); while (startPos < (posLineStart + lineRange.end)) { Insert(startPos - posLineStart); startPos = deco->EndRun(startPos); } } } } Insert(ll->edgeColumn); Insert(lineRange.end); saeNext = (!selAndEdge.empty()) ? selAndEdge[0] : -1; } BreakFinder::~BreakFinder() { } TextSegment BreakFinder::Next() { if (subBreak == -1) { const int prev = nextBreak; while (nextBreak < lineRange.end) { int charWidth = 1; if (encodingFamily == efUnicode) charWidth = UTF8DrawBytes(reinterpret_cast(&ll->chars[nextBreak]), static_cast(lineRange.end - nextBreak)); else if (encodingFamily == efDBCS) charWidth = pdoc->DBCSDrawBytes( &ll->chars[nextBreak], static_cast(lineRange.end - nextBreak)); const Representation *repr = preprs->RepresentationFromCharacter(&ll->chars[nextBreak], charWidth); if (((nextBreak > 0) && (ll->styles[nextBreak] != ll->styles[nextBreak - 1])) || repr || (nextBreak == saeNext)) { while ((nextBreak >= saeNext) && (saeNext < lineRange.end)) { saeCurrentPos++; saeNext = static_cast((saeCurrentPos < selAndEdge.size()) ? selAndEdge[saeCurrentPos] : lineRange.end); } if ((nextBreak > prev) || repr) { // Have a segment to report if (nextBreak == prev) { nextBreak += charWidth; } else { repr = nullptr; // Optimize -> should remember repr } if ((nextBreak - prev) < lengthStartSubdivision) { return TextSegment(prev, nextBreak - prev, repr); } else { break; } } } nextBreak += charWidth; } if ((nextBreak - prev) < lengthStartSubdivision) { return TextSegment(prev, nextBreak - prev); } subBreak = prev; } // Splitting up a long run from prev to nextBreak in lots of approximately lengthEachSubdivision. // For very long runs add extra breaks after spaces or if no spaces before low punctuation. const int startSegment = subBreak; if ((nextBreak - subBreak) <= lengthEachSubdivision) { subBreak = -1; return TextSegment(startSegment, nextBreak - startSegment); } else { subBreak += pdoc->SafeSegment(&ll->chars[subBreak], nextBreak-subBreak, lengthEachSubdivision); if (subBreak >= nextBreak) { subBreak = -1; return TextSegment(startSegment, nextBreak - startSegment); } else { return TextSegment(startSegment, subBreak - startSegment); } } } bool BreakFinder::More() const { return (subBreak >= 0) || (nextBreak < lineRange.end); } PositionCacheEntry::PositionCacheEntry() : styleNumber(0), len(0), clock(0), positions(nullptr) { } // Copy constructor not currently used, but needed for being element in std::vector. PositionCacheEntry::PositionCacheEntry(const PositionCacheEntry &other) : styleNumber(other.styleNumber), len(other.styleNumber), clock(other.styleNumber), positions(nullptr) { if (other.positions) { const size_t lenData = len + (len / sizeof(XYPOSITION)) + 1; positions.reset(new XYPOSITION[lenData]); memcpy(positions.get(), other.positions.get(), lenData * sizeof(XYPOSITION)); } } void PositionCacheEntry::Set(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_, unsigned int clock_) { Clear(); styleNumber = styleNumber_; len = len_; clock = clock_; if (s_ && positions_) { positions.reset(new XYPOSITION[len + (len / sizeof(XYPOSITION)) + 1]); for (unsigned int i=0; i other.clock; } void PositionCacheEntry::ResetClock() { if (clock > 0) { clock = 1; } } PositionCache::PositionCache() { clock = 1; pces.resize(0x400); allClear = true; } PositionCache::~PositionCache() { Clear(); } void PositionCache::Clear() { if (!allClear) { for (PositionCacheEntry &pce : pces) { pce.Clear(); } } clock = 1; allClear = true; } void PositionCache::SetSize(size_t size_) { Clear(); pces.resize(size_); } void PositionCache::MeasureWidths(Surface *surface, const ViewStyle &vstyle, unsigned int styleNumber, const char *s, unsigned int len, XYPOSITION *positions, const Document *pdoc) { allClear = false; size_t probe = pces.size(); // Out of bounds if ((!pces.empty()) && (len < 30)) { // Only store short strings in the cache so it doesn't churn with // long comments with only a single comment. // Two way associative: try two probe positions. const unsigned int hashValue = PositionCacheEntry::Hash(styleNumber, s, len); probe = hashValue % pces.size(); if (pces[probe].Retrieve(styleNumber, s, len, positions)) { return; } const unsigned int probe2 = (hashValue * 37) % pces.size(); if (pces[probe2].Retrieve(styleNumber, s, len, positions)) { return; } // Not found. Choose the oldest of the two slots to replace if (pces[probe].NewerThan(pces[probe2])) { probe = probe2; } } if (len > BreakFinder::lengthStartSubdivision) { // Break up into segments unsigned int startSegment = 0; XYPOSITION xStartSegment = 0; while (startSegment < len) { const unsigned int lenSegment = pdoc->SafeSegment(s + startSegment, len - startSegment, BreakFinder::lengthEachSubdivision); FontAlias fontStyle = vstyle.styles[styleNumber].font; surface->MeasureWidths(fontStyle, s + startSegment, lenSegment, positions + startSegment); for (unsigned int inSeg = 0; inSeg < lenSegment; inSeg++) { positions[startSegment + inSeg] += xStartSegment; } xStartSegment = positions[startSegment + lenSegment - 1]; startSegment += lenSegment; } } else { FontAlias fontStyle = vstyle.styles[styleNumber].font; surface->MeasureWidths(fontStyle, s, len, positions); } if (probe < pces.size()) { // Store into cache clock++; if (clock > 60000) { // Since there are only 16 bits for the clock, wrap it round and // reset all cache entries so none get stuck with a high clock. for (PositionCacheEntry &pce : pces) { pce.ResetClock(); } clock = 2; } pces[probe].Set(styleNumber, s, len, positions, clock); } } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/PositionCache.h000066400000000000000000000171331463772530400264650ustar00rootroot00000000000000// Scintilla source code edit control /** @file PositionCache.h ** Classes for caching layout information. **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef POSITIONCACHE_H #define POSITIONCACHE_H namespace Scintilla { inline constexpr bool IsEOLChar(int ch) noexcept { return (ch == '\r') || (ch == '\n'); } inline constexpr bool IsSpaceOrTab(int ch) noexcept { return ch == ' ' || ch == '\t'; } /** * A point in document space. * Uses double for sufficient resolution in large (>20,000,000 line) documents. */ class PointDocument { public: double x; double y; explicit PointDocument(double x_ = 0, double y_ = 0) noexcept : x(x_), y(y_) { } // Conversion from Point. explicit PointDocument(Point pt) noexcept : x(pt.x), y(pt.y) { } }; // There are two points for some positions and this enumeration // can choose between the end of the first line or subline // and the start of the next line or subline. enum PointEnd { peDefault = 0x0, peLineEnd = 0x1, peSubLineEnd = 0x2 }; /** */ class LineLayout { private: friend class LineLayoutCache; std::unique_ptrlineStarts; int lenLineStarts; /// Drawing is only performed for @a maxLineLength characters on each line. Sci::Line lineNumber; bool inCache; public: enum { wrapWidthInfinite = 0x7ffffff }; int maxLineLength; int numCharsInLine; int numCharsBeforeEOL; enum validLevel { llInvalid, llCheckTextAndStyle, llPositions, llLines } validity; int xHighlightGuide; bool highlightColumn; bool containsCaret; int edgeColumn; std::unique_ptr chars; std::unique_ptr styles; std::unique_ptr positions; char bracePreviousStyles[2]; // Hotspot support Range hotspot; // Wrapped line support int widthLine; int lines; XYPOSITION wrapIndent; // In pixels explicit LineLayout(int maxLineLength_); // Deleted so LineLayout objects can not be copied. LineLayout(const LineLayout &) = delete; LineLayout(LineLayout &&) = delete; void operator=(const LineLayout &) = delete; void operator=(LineLayout &&) = delete; virtual ~LineLayout(); void Resize(int maxLineLength_); void Free(); void Invalidate(validLevel validity_); int LineStart(int line) const; enum class Scope { visibleOnly, includeEnd }; int LineLastVisible(int line, Scope scope) const; Range SubLineRange(int subLine, Scope scope) const; bool InLine(int offset, int line) const; void SetLineStart(int line, int start); void SetBracesHighlight(Range rangeLine, const Sci::Position braces[], char bracesMatchStyle, int xHighlight, bool ignoreStyle); void RestoreBracesHighlight(Range rangeLine, const Sci::Position braces[], bool ignoreStyle); int FindBefore(XYPOSITION x, Range range) const; int FindPositionFromX(XYPOSITION x, Range range, bool charPosition) const; Point PointFromPosition(int posInLine, int lineHeight, PointEnd pe) const; int EndLineStyle() const; }; /** */ class LineLayoutCache { int level; std::vector>cache; bool allInvalidated; int styleClock; int useCount; void Allocate(size_t length_); void AllocateForLevel(Sci::Line linesOnScreen, Sci::Line linesInDoc); public: LineLayoutCache(); // Deleted so LineLayoutCache objects can not be copied. LineLayoutCache(const LineLayoutCache &) = delete; LineLayoutCache(LineLayoutCache &&) = delete; void operator=(const LineLayoutCache &) = delete; void operator=(LineLayoutCache &&) = delete; virtual ~LineLayoutCache(); void Deallocate(); enum { llcNone=SC_CACHE_NONE, llcCaret=SC_CACHE_CARET, llcPage=SC_CACHE_PAGE, llcDocument=SC_CACHE_DOCUMENT }; void Invalidate(LineLayout::validLevel validity_); void SetLevel(int level_); int GetLevel() const { return level; } LineLayout *Retrieve(Sci::Line lineNumber, Sci::Line lineCaret, int maxChars, int styleClock_, Sci::Line linesOnScreen, Sci::Line linesInDoc); void Dispose(LineLayout *ll); }; class PositionCacheEntry { unsigned int styleNumber:8; unsigned int len:8; unsigned int clock:16; std::unique_ptr positions; public: PositionCacheEntry(); // Copy constructor not currently used, but needed for being element in std::vector. PositionCacheEntry(const PositionCacheEntry &); // PositionCacheEntry objects should not be moved but MSVC 2015 requires this. PositionCacheEntry(PositionCacheEntry &&) = default; void operator=(const PositionCacheEntry &) = delete; void operator=(PositionCacheEntry &&) = delete; ~PositionCacheEntry(); void Set(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_, unsigned int clock_); void Clear(); bool Retrieve(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_) const; static unsigned int Hash(unsigned int styleNumber_, const char *s, unsigned int len_); bool NewerThan(const PositionCacheEntry &other) const; void ResetClock(); }; class Representation { public: std::string stringRep; explicit Representation(const char *value="") : stringRep(value) { } }; typedef std::map MapRepresentation; class SpecialRepresentations { MapRepresentation mapReprs; short startByteHasReprs[0x100]; public: SpecialRepresentations(); void SetRepresentation(const char *charBytes, const char *value); void ClearRepresentation(const char *charBytes); const Representation *RepresentationFromCharacter(const char *charBytes, size_t len) const; bool Contains(const char *charBytes, size_t len) const; void Clear(); }; struct TextSegment { int start; int length; const Representation *representation; TextSegment(int start_=0, int length_=0, const Representation *representation_=nullptr) noexcept : start(start_), length(length_), representation(representation_) { } int end() const noexcept { return start + length; } }; // Class to break a line of text into shorter runs at sensible places. class BreakFinder { const LineLayout *ll; Range lineRange; Sci::Position posLineStart; int nextBreak; std::vector selAndEdge; unsigned int saeCurrentPos; int saeNext; int subBreak; const Document *pdoc; EncodingFamily encodingFamily; const SpecialRepresentations *preprs; void Insert(Sci::Position val); public: // If a whole run is longer than lengthStartSubdivision then subdivide // into smaller runs at spaces or punctuation. enum { lengthStartSubdivision = 300 }; // Try to make each subdivided run lengthEachSubdivision or shorter. enum { lengthEachSubdivision = 100 }; BreakFinder(const LineLayout *ll_, const Selection *psel, Range lineRange_, Sci::Position posLineStart_, int xStart, bool breakForSelection, const Document *pdoc_, const SpecialRepresentations *preprs_, const ViewStyle *pvsDraw); // Deleted so BreakFinder objects can not be copied. BreakFinder(const BreakFinder &) = delete; BreakFinder(BreakFinder &&) = delete; void operator=(const BreakFinder &) = delete; void operator=(BreakFinder &&) = delete; ~BreakFinder(); TextSegment Next(); bool More() const; }; class PositionCache { std::vector pces; unsigned int clock; bool allClear; public: PositionCache(); // Deleted so PositionCache objects can not be copied. PositionCache(const PositionCache &) = delete; PositionCache(PositionCache &&) = delete; void operator=(const PositionCache &) = delete; void operator=(PositionCache &&) = delete; ~PositionCache(); void Clear(); void SetSize(size_t size_); size_t GetSize() const { return pces.size(); } void MeasureWidths(Surface *surface, const ViewStyle &vstyle, unsigned int styleNumber, const char *s, unsigned int len, XYPOSITION *positions, const Document *pdoc); }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/RESearch.cpp000066400000000000000000000637041463772530400257310ustar00rootroot00000000000000// Scintilla source code edit control /** @file RESearch.cxx ** Regular expression search library. **/ /* * regex - Regular expression pattern matching and replacement * * By: Ozan S. Yigit (oz) * Dept. of Computer Science * York University * * Original code available from http://www.cs.yorku.ca/~oz/ * Translation to C++ by Neil Hodgson neilh@scintilla.org * Removed all use of register. * Converted to modern function prototypes. * Put all global/static variables into an object so this code can be * used from multiple threads, etc. * Some extensions by Philippe Lhoste PhiLho(a)GMX.net * '?' extensions by Michael Mullin masmullin@gmail.com * * These routines are the PUBLIC DOMAIN equivalents of regex * routines as found in 4.nBSD UN*X, with minor extensions. * * These routines are derived from various implementations found * in software tools books, and Conroy's grep. They are NOT derived * from licensed/restricted software. * For more interesting/academic/complicated implementations, * see Henry Spencer's regexp routines, or GNU Emacs pattern * matching module. * * Modification history removed. * * Interfaces: * RESearch::Compile: compile a regular expression into a NFA. * * const char *RESearch::Compile(const char *pattern, int length, * bool caseSensitive, bool posix) * * Returns a short error string if they fail. * * RESearch::Execute: execute the NFA to match a pattern. * * int RESearch::Execute(characterIndexer &ci, int lp, int endp) * * re_fail: failure routine for RESearch::Execute. (no longer used) * * void re_fail(char *msg, char op) * * Regular Expressions: * * [1] char matches itself, unless it is a special * character (metachar): . \ [ ] * + ? ^ $ * and ( ) if posix option. * * [2] . matches any character. * * [3] \ matches the character following it, except: * - \a, \b, \f, \n, \r, \t, \v match the corresponding C * escape char, respectively BEL, BS, FF, LF, CR, TAB and VT; * Note that \r and \n are never matched because Scintilla * regex searches are made line per line * (stripped of end-of-line chars). * - if not in posix mode, when followed by a * left or right round bracket (see [8]); * - when followed by a digit 1 to 9 (see [9]); * - when followed by a left or right angle bracket * (see [10]); * - when followed by d, D, s, S, w or W (see [11]); * - when followed by x and two hexa digits (see [12]. * Backslash is used as an escape character for all * other meta-characters, and itself. * * [4] [set] matches one of the characters in the set. * If the first character in the set is "^", * it matches the characters NOT in the set, i.e. * complements the set. A shorthand S-E (start dash end) * is used to specify a set of characters S up to * E, inclusive. S and E must be characters, otherwise * the dash is taken literally (eg. in expression [\d-a]). * The special characters "]" and "-" have no special * meaning if they appear as the first chars in the set. * To include both, put - first: [-]A-Z] * (or just backslash them). * examples: match: * * [-]|] matches these 3 chars, * * []-|] matches from ] to | chars * * [a-z] any lowercase alpha * * [^-]] any char except - and ] * * [^A-Z] any char except uppercase * alpha * * [a-zA-Z] any alpha * * [5] * any regular expression form [1] to [4] * (except [8], [9] and [10] forms of [3]), * followed by closure char (*) * matches zero or more matches of that form. * * [6] + same as [5], except it matches one or more. * * [5-6] Both [5] and [6] are greedy (they match as much as possible). * Unless they are followed by the 'lazy' quantifier (?) * In which case both [5] and [6] try to match as little as possible * * [7] ? same as [5] except it matches zero or one. * * [8] a regular expression in the form [1] to [13], enclosed * as \(form\) (or (form) with posix flag) matches what * form matches. The enclosure creates a set of tags, * used for [9] and for pattern substitution. * The tagged forms are numbered starting from 1. * * [9] a \ followed by a digit 1 to 9 matches whatever a * previously tagged regular expression ([8]) matched. * * [10] \< a regular expression starting with a \< construct * \> and/or ending with a \> construct, restricts the * pattern matching to the beginning of a word, and/or * the end of a word. A word is defined to be a character * string beginning and/or ending with the characters * A-Z a-z 0-9 and _. Scintilla extends this definition * by user setting. The word must also be preceded and/or * followed by any character outside those mentioned. * * [11] \l a backslash followed by d, D, s, S, w or W, * becomes a character class (both inside and * outside sets []). * d: decimal digits * D: any char except decimal digits * s: whitespace (space, \t \n \r \f \v) * S: any char except whitespace (see above) * w: alphanumeric & underscore (changed by user setting) * W: any char except alphanumeric & underscore (see above) * * [12] \xHH a backslash followed by x and two hexa digits, * becomes the character whose Ascii code is equal * to these digits. If not followed by two digits, * it is 'x' char itself. * * [13] a composite regular expression xy where x and y * are in the form [1] to [12] matches the longest * match of x followed by a match for y. * * [14] ^ a regular expression starting with a ^ character * $ and/or ending with a $ character, restricts the * pattern matching to the beginning of the line, * or the end of line. [anchors] Elsewhere in the * pattern, ^ and $ are treated as ordinary characters. * * * Acknowledgements: * * HCR's Hugh Redelmeier has been most helpful in various * stages of development. He convinced me to include BOW * and EOW constructs, originally invented by Rob Pike at * the University of Toronto. * * References: * Software tools Kernighan & Plauger * Software tools in Pascal Kernighan & Plauger * Grep [rsx-11 C dist] David Conroy * ed - text editor Un*x Programmer's Manual * Advanced editing on Un*x B. W. Kernighan * RegExp routines Henry Spencer * * Notes: * * This implementation uses a bit-set representation for character * classes for speed and compactness. Each character is represented * by one bit in a 256-bit block. Thus, CCL always takes a * constant 32 bytes in the internal nfa, and RESearch::Execute does a single * bit comparison to locate the character in the set. * * Examples: * * pattern: foo*.* * compile: CHR f CHR o CLO CHR o END CLO ANY END END * matches: fo foo fooo foobar fobar foxx ... * * pattern: fo[ob]a[rz] * compile: CHR f CHR o CCL bitset CHR a CCL bitset END * matches: fobar fooar fobaz fooaz * * pattern: foo\\+ * compile: CHR f CHR o CHR o CHR \ CLO CHR \ END END * matches: foo\ foo\\ foo\\\ ... * * pattern: \(foo\)[1-3]\1 (same as foo[1-3]foo) * compile: BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END * matches: foo1foo foo2foo foo3foo * * pattern: \(fo.*\)-\1 * compile: BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END * matches: foo-foo fo-fo fob-fob foobar-foobar ... */ #include #include #include #include #include #include #include "Position.h" #include "CharClassify.h" #include "RESearch.h" using namespace Scintilla; #define OKP 1 #define NOP 0 #define CHR 1 #define ANY 2 #define CCL 3 #define BOL 4 #define EOL 5 #define BOT 6 #define EOT 7 #define BOW 8 #define EOW 9 #define REF 10 #define CLO 11 #define CLQ 12 /* 0 to 1 closure */ #define LCLO 13 /* lazy closure */ #define END 0 /* * The following defines are not meant to be changeable. * They are for readability only. */ #define BLKIND 0370 #define BITIND 07 static const char bitarr[] = { 1, 2, 4, 8, 16, 32, 64, '\200' }; #define badpat(x) (*nfa = END, x) /* * Character classification table for word boundary operators BOW * and EOW is passed in by the creator of this object (Scintilla * Document). The Document default state is that word chars are: * 0-9, a-z, A-Z and _ */ RESearch::RESearch(CharClassify *charClassTable) { failure = 0; charClass = charClassTable; sta = NOP; /* status of lastpat */ bol = 0; const unsigned char nul=0; std::fill(bittab, std::end(bittab), nul); std::fill(tagstk, std::end(tagstk), 0); std::fill(nfa, std::end(nfa), '\0'); Clear(); } RESearch::~RESearch() { Clear(); } void RESearch::Clear() { for (int i = 0; i < MAXTAG; i++) { pat[i].clear(); bopat[i] = NOTFOUND; eopat[i] = NOTFOUND; } } void RESearch::GrabMatches(const CharacterIndexer &ci) { for (unsigned int i = 0; i < MAXTAG; i++) { if ((bopat[i] != NOTFOUND) && (eopat[i] != NOTFOUND)) { Sci::Position len = eopat[i] - bopat[i]; pat[i].resize(len); for (Sci::Position j = 0; j < len; j++) pat[i][j] = ci.CharAt(bopat[i] + j); } } } void RESearch::ChSet(unsigned char c) { bittab[((c) & BLKIND) >> 3] |= bitarr[(c) & BITIND]; } void RESearch::ChSetWithCase(unsigned char c, bool caseSensitive) { ChSet(c); if (!caseSensitive) { if ((c >= 'a') && (c <= 'z')) { ChSet(c - 'a' + 'A'); } else if ((c >= 'A') && (c <= 'Z')) { ChSet(c - 'A' + 'a'); } } } static unsigned char escapeValue(unsigned char ch) { switch (ch) { case 'a': return '\a'; case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; case 'v': return '\v'; } return 0; } static int GetHexaChar(unsigned char hd1, unsigned char hd2) { int hexValue = 0; if (hd1 >= '0' && hd1 <= '9') { hexValue += 16 * (hd1 - '0'); } else if (hd1 >= 'A' && hd1 <= 'F') { hexValue += 16 * (hd1 - 'A' + 10); } else if (hd1 >= 'a' && hd1 <= 'f') { hexValue += 16 * (hd1 - 'a' + 10); } else { return -1; } if (hd2 >= '0' && hd2 <= '9') { hexValue += hd2 - '0'; } else if (hd2 >= 'A' && hd2 <= 'F') { hexValue += hd2 - 'A' + 10; } else if (hd2 >= 'a' && hd2 <= 'f') { hexValue += hd2 - 'a' + 10; } else { return -1; } return hexValue; } /** * Called when the parser finds a backslash not followed * by a valid expression (like \( in non-Posix mode). * @param pattern : pointer on the char after the backslash. * @param incr : (out) number of chars to skip after expression evaluation. * @return the char if it resolves to a simple char, * or -1 for a char class. In this case, bittab is changed. */ int RESearch::GetBackslashExpression( const char *pattern, int &incr) { // Since error reporting is primitive and messages are not used anyway, // I choose to interpret unexpected syntax in a logical way instead // of reporting errors. Otherwise, we can stick on, eg., PCRE behavior. incr = 0; // Most of the time, will skip the char "naturally". int c; int result = -1; const unsigned char bsc = *pattern; if (!bsc) { // Avoid overrun result = '\\'; // \ at end of pattern, take it literally return result; } switch (bsc) { case 'a': case 'b': case 'n': case 'f': case 'r': case 't': case 'v': result = escapeValue(bsc); break; case 'x': { const unsigned char hd1 = *(pattern + 1); const unsigned char hd2 = *(pattern + 2); const int hexValue = GetHexaChar(hd1, hd2); if (hexValue >= 0) { result = hexValue; incr = 2; // Must skip the digits } else { result = 'x'; // \x without 2 digits: see it as 'x' } } break; case 'd': for (c = '0'; c <= '9'; c++) { ChSet(static_cast(c)); } break; case 'D': for (c = 0; c < MAXCHR; c++) { if (c < '0' || c > '9') { ChSet(static_cast(c)); } } break; case 's': ChSet(' '); ChSet('\t'); ChSet('\n'); ChSet('\r'); ChSet('\f'); ChSet('\v'); break; case 'S': for (c = 0; c < MAXCHR; c++) { if (c != ' ' && !(c >= 0x09 && c <= 0x0D)) { ChSet(static_cast(c)); } } break; case 'w': for (c = 0; c < MAXCHR; c++) { if (iswordc(static_cast(c))) { ChSet(static_cast(c)); } } break; case 'W': for (c = 0; c < MAXCHR; c++) { if (!iswordc(static_cast(c))) { ChSet(static_cast(c)); } } break; default: result = bsc; } return result; } const char *RESearch::Compile(const char *pattern, Sci::Position length, bool caseSensitive, bool posix) { char *mp=nfa; /* nfa pointer */ char *lp; /* saved pointer */ char *sp=nfa; /* another one */ char *mpMax = mp + MAXNFA - BITBLK - 10; int tagi = 0; /* tag stack index */ int tagc = 1; /* actual tag count */ int n; char mask; /* xor mask -CCL/NCL */ int c1, c2, prevChar; if (!pattern || !length) { if (sta) return nullptr; else return badpat("No previous regular expression"); } sta = NOP; const char *p=pattern; /* pattern pointer */ for (int i=0; i mpMax) return badpat("Pattern too long"); lp = mp; switch (*p) { case '.': /* match any char */ *mp++ = ANY; break; case '^': /* match beginning */ if (p == pattern) { *mp++ = BOL; } else { *mp++ = CHR; *mp++ = *p; } break; case '$': /* match endofline */ if (!*(p+1)) { *mp++ = EOL; } else { *mp++ = CHR; *mp++ = *p; } break; case '[': /* match char class */ *mp++ = CCL; prevChar = 0; i++; if (*++p == '^') { mask = '\377'; i++; p++; } else { mask = 0; } if (*p == '-') { /* real dash */ i++; prevChar = *p; ChSet(*p++); } if (*p == ']') { /* real brace */ i++; prevChar = *p; ChSet(*p++); } while (*p && *p != ']') { if (*p == '-') { if (prevChar < 0) { // Previous def. was a char class like \d, take dash literally prevChar = *p; ChSet(*p); } else if (*(p+1)) { if (*(p+1) != ']') { c1 = prevChar + 1; i++; c2 = static_cast(*++p); if (c2 == '\\') { if (!*(p+1)) { // End of RE return badpat("Missing ]"); } else { i++; p++; int incr; c2 = GetBackslashExpression(p, incr); i += incr; p += incr; if (c2 >= 0) { // Convention: \c (c is any char) is case sensitive, whatever the option ChSet(static_cast(c2)); prevChar = c2; } else { // bittab is already changed prevChar = -1; } } } if (prevChar < 0) { // Char after dash is char class like \d, take dash literally prevChar = '-'; ChSet('-'); } else { // Put all chars between c1 and c2 included in the char set while (c1 <= c2) { ChSetWithCase(static_cast(c1++), caseSensitive); } } } else { // Dash before the ], take it literally prevChar = *p; ChSet(*p); } } else { return badpat("Missing ]"); } } else if (*p == '\\' && *(p+1)) { i++; p++; int incr; int c = GetBackslashExpression(p, incr); i += incr; p += incr; if (c >= 0) { // Convention: \c (c is any char) is case sensitive, whatever the option ChSet(static_cast(c)); prevChar = c; } else { // bittab is already changed prevChar = -1; } } else { prevChar = static_cast(*p); ChSetWithCase(*p, caseSensitive); } i++; p++; } if (!*p) return badpat("Missing ]"); for (n = 0; n < BITBLK; bittab[n++] = 0) *mp++ = static_cast(mask ^ bittab[n]); break; case '*': /* match 0 or more... */ case '+': /* match 1 or more... */ case '?': if (p == pattern) return badpat("Empty closure"); lp = sp; /* previous opcode */ if (*lp == CLO || *lp == LCLO) /* equivalence... */ break; switch (*lp) { case BOL: case BOT: case EOT: case BOW: case EOW: case REF: return badpat("Illegal closure"); default: break; } if (*p == '+') for (sp = mp; lp < sp; lp++) *mp++ = *lp; *mp++ = END; *mp++ = END; sp = mp; while (--mp > lp) *mp = mp[-1]; if (*p == '?') *mp = CLQ; else if (*(p+1) == '?') *mp = LCLO; else *mp = CLO; mp = sp; break; case '\\': /* tags, backrefs... */ i++; switch (*++p) { case '<': *mp++ = BOW; break; case '>': if (*sp == BOW) return badpat("Null pattern inside \\<\\>"); *mp++ = EOW; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = *p-'0'; if (tagi > 0 && tagstk[tagi] == n) return badpat("Cyclical reference"); if (tagc > n) { *mp++ = REF; *mp++ = static_cast(n); } else { return badpat("Undetermined reference"); } break; default: if (!posix && *p == '(') { if (tagc < MAXTAG) { tagstk[++tagi] = tagc; *mp++ = BOT; *mp++ = static_cast(tagc++); } else { return badpat("Too many \\(\\) pairs"); } } else if (!posix && *p == ')') { if (*sp == BOT) return badpat("Null pattern inside \\(\\)"); if (tagi > 0) { *mp++ = EOT; *mp++ = static_cast(tagstk[tagi--]); } else { return badpat("Unmatched \\)"); } } else { int incr; int c = GetBackslashExpression(p, incr); i += incr; p += incr; if (c >= 0) { *mp++ = CHR; *mp++ = static_cast(c); } else { *mp++ = CCL; mask = 0; for (n = 0; n < BITBLK; bittab[n++] = 0) *mp++ = static_cast(mask ^ bittab[n]); } } } break; default : /* an ordinary char */ if (posix && *p == '(') { if (tagc < MAXTAG) { tagstk[++tagi] = tagc; *mp++ = BOT; *mp++ = static_cast(tagc++); } else { return badpat("Too many () pairs"); } } else if (posix && *p == ')') { if (*sp == BOT) return badpat("Null pattern inside ()"); if (tagi > 0) { *mp++ = EOT; *mp++ = static_cast(tagstk[tagi--]); } else { return badpat("Unmatched )"); } } else { unsigned char c = *p; if (!c) // End of RE c = '\\'; // We take it as raw backslash if (caseSensitive || !iswordc(c)) { *mp++ = CHR; *mp++ = c; } else { *mp++ = CCL; mask = 0; ChSetWithCase(c, false); for (n = 0; n < BITBLK; bittab[n++] = 0) *mp++ = static_cast(mask ^ bittab[n]); } } break; } sp = lp; } if (tagi > 0) return badpat((posix ? "Unmatched (" : "Unmatched \\(")); *mp = END; sta = OKP; return nullptr; } /* * RESearch::Execute: * execute nfa to find a match. * * special cases: (nfa[0]) * BOL * Match only once, starting from the * beginning. * CHR * First locate the character without * calling PMatch, and if found, call * PMatch for the remaining string. * END * RESearch::Compile failed, poor luser did not * check for it. Fail fast. * * If a match is found, bopat[0] and eopat[0] are set * to the beginning and the end of the matched fragment, * respectively. * */ int RESearch::Execute(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp) { unsigned char c; Sci::Position ep = NOTFOUND; char *ap = nfa; bol = lp; failure = 0; Clear(); switch (*ap) { case BOL: /* anchored: match from BOL only */ ep = PMatch(ci, lp, endp, ap); break; case EOL: /* just searching for end of line normal path doesn't work */ if (*(ap+1) == END) { lp = endp; ep = lp; break; } else { return 0; } case CHR: /* ordinary char: locate it fast */ c = *(ap+1); while ((lp < endp) && (static_cast(ci.CharAt(lp)) != c)) lp++; if (lp >= endp) /* if EOS, fail, else fall through. */ return 0; // Falls through. default: /* regular matching all the way. */ while (lp < endp) { ep = PMatch(ci, lp, endp, ap); if (ep != NOTFOUND) break; lp++; } break; case END: /* munged automaton. fail always */ return 0; } if (ep == NOTFOUND) return 0; bopat[0] = lp; eopat[0] = ep; return 1; } /* * PMatch: internal routine for the hard part * * This code is partly snarfed from an early grep written by * David Conroy. The backref and tag stuff, and various other * innovations are by oz. * * special case optimizations: (nfa[n], nfa[n+1]) * CLO ANY * We KNOW .* will match everything up to the * end of line. Thus, directly go to the end of * line, without recursive PMatch calls. As in * the other closure cases, the remaining pattern * must be matched by moving backwards on the * string recursively, to find a match for xy * (x is ".*" and y is the remaining pattern) * where the match satisfies the LONGEST match for * x followed by a match for y. * CLO CHR * We can again scan the string forward for the * single char and at the point of failure, we * execute the remaining nfa recursively, same as * above. * * At the end of a successful match, bopat[n] and eopat[n] * are set to the beginning and end of subpatterns matched * by tagged expressions (n = 1 to 9). */ extern void re_fail(char *,char); static inline int isinset(const char *ap, unsigned char c) { return ap[(c & BLKIND) >> 3] & bitarr[c & BITIND]; } /* * skip values for CLO XXX to skip past the closure */ #define ANYSKIP 2 /* [CLO] ANY END */ #define CHRSKIP 3 /* [CLO] CHR chr END */ #define CCLSKIP 34 /* [CLO] CCL 32 bytes END */ Sci::Position RESearch::PMatch(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp, char *ap) { int op, c, n; Sci::Position e; /* extra pointer for CLO */ Sci::Position bp; /* beginning of subpat... */ Sci::Position ep; /* ending of subpat... */ Sci::Position are; /* to save the line ptr. */ Sci::Position llp; /* lazy lp for LCLO */ while ((op = *ap++) != END) switch (op) { case CHR: if (ci.CharAt(lp++) != *ap++) return NOTFOUND; break; case ANY: if (lp++ >= endp) return NOTFOUND; break; case CCL: if (lp >= endp) return NOTFOUND; if (!isinset(ap, ci.CharAt(lp++))) return NOTFOUND; ap += BITBLK; break; case BOL: if (lp != bol) return NOTFOUND; break; case EOL: if (lp < endp) return NOTFOUND; break; case BOT: bopat[static_cast(*ap++)] = lp; break; case EOT: eopat[static_cast(*ap++)] = lp; break; case BOW: if ((lp!=bol && iswordc(ci.CharAt(lp-1))) || !iswordc(ci.CharAt(lp))) return NOTFOUND; break; case EOW: if (lp==bol || !iswordc(ci.CharAt(lp-1)) || iswordc(ci.CharAt(lp))) return NOTFOUND; break; case REF: n = *ap++; bp = bopat[n]; ep = eopat[n]; while (bp < ep) if (ci.CharAt(bp++) != ci.CharAt(lp++)) return NOTFOUND; break; case LCLO: case CLQ: case CLO: are = lp; switch (*ap) { case ANY: if (op == CLO || op == LCLO) while (lp < endp) lp++; else if (lp < endp) lp++; n = ANYSKIP; break; case CHR: c = *(ap+1); if (op == CLO || op == LCLO) while ((lp < endp) && (c == ci.CharAt(lp))) lp++; else if ((lp < endp) && (c == ci.CharAt(lp))) lp++; n = CHRSKIP; break; case CCL: while ((lp < endp) && isinset(ap+1, ci.CharAt(lp))) lp++; n = CCLSKIP; break; default: failure = true; //re_fail("closure: bad nfa.", *ap); return NOTFOUND; } ap += n; llp = lp; e = NOTFOUND; while (llp >= are) { Sci::Position q; if ((q = PMatch(ci, llp, endp, ap)) != NOTFOUND) { e = q; lp = llp; if (op != LCLO) return e; } if (*ap == END) return e; --llp; } if (*ap == EOT) PMatch(ci, lp, endp, ap); return e; default: //re_fail("RESearch::Execute: bad nfa.", static_cast(op)); return NOTFOUND; } return lp; } sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/RESearch.h000066400000000000000000000033201463772530400253620ustar00rootroot00000000000000// Scintilla source code edit control /** @file RESearch.h ** Interface to the regular expression search library. **/ // Written by Neil Hodgson // Based on the work of Ozan S. Yigit. // This file is in the public domain. #ifndef RESEARCH_H #define RESEARCH_H namespace Scintilla { /* * The following defines are not meant to be changeable. * They are for readability only. */ #define MAXCHR 256 #define CHRBIT 8 #define BITBLK MAXCHR/CHRBIT class CharacterIndexer { public: virtual char CharAt(Sci::Position index) const=0; virtual ~CharacterIndexer() { } }; class RESearch { public: explicit RESearch(CharClassify *charClassTable); // No dynamic allocation so default copy constructor and assignment operator are OK. ~RESearch(); void Clear(); void GrabMatches(const CharacterIndexer &ci); const char *Compile(const char *pattern, Sci::Position length, bool caseSensitive, bool posix); int Execute(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp); enum { MAXTAG=10 }; enum { MAXNFA=4096 }; enum { NOTFOUND=-1 }; Sci::Position bopat[MAXTAG]; Sci::Position eopat[MAXTAG]; std::string pat[MAXTAG]; private: void ChSet(unsigned char c); void ChSetWithCase(unsigned char c, bool caseSensitive); int GetBackslashExpression(const char *pattern, int &incr); Sci::Position PMatch(const CharacterIndexer &ci, Sci::Position lp, Sci::Position endp, char *ap); Sci::Position bol; Sci::Position tagstk[MAXTAG]; /* subpat tag stack */ char nfa[MAXNFA]; /* automaton */ int sta; unsigned char bittab[BITBLK]; /* bit table for CCL pre-set bits */ int failure; CharClassify *charClass; bool iswordc(unsigned char x) const { return charClass->IsWord(x); } }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/libs/qscintilla/src/RunStyles.cpp000066400000000000000000000226041463772530400262370ustar00rootroot00000000000000/** @file RunStyles.cxx ** Data structure used to store sparse styles. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "Position.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" using namespace Scintilla; // Find the first run at a position template DISTANCE RunStyles::RunFromPosition(DISTANCE position) const noexcept { DISTANCE run = starts->PartitionFromPosition(position); // Go to first element with this position while ((run > 0) && (position == starts->PositionFromPartition(run-1))) { run--; } return run; } // If there is no run boundary at position, insert one continuing style. template DISTANCE RunStyles::SplitRun(DISTANCE position) { DISTANCE run = RunFromPosition(position); const DISTANCE posRun = starts->PositionFromPartition(run); if (posRun < position) { STYLE runStyle = ValueAt(position); run++; starts->InsertPartition(run, position); styles->InsertValue(run, 1, runStyle); } return run; } template void RunStyles::RemoveRun(DISTANCE run) { starts->RemovePartition(run); styles->DeleteRange(run, 1); } template void RunStyles::RemoveRunIfEmpty(DISTANCE run) { if ((run < starts->Partitions()) && (starts->Partitions() > 1)) { if (starts->PositionFromPartition(run) == starts->PositionFromPartition(run+1)) { RemoveRun(run); } } } template void RunStyles::RemoveRunIfSameAsPrevious(DISTANCE run) { if ((run > 0) && (run < starts->Partitions())) { if (styles->ValueAt(run-1) == styles->ValueAt(run)) { RemoveRun(run); } } } template RunStyles::RunStyles() { starts.reset(new Partitioning(8)); styles.reset(new SplitVector" ""); // Insert the columns in a set, since they could be non-contiguous. std::set colsInIndexes, rowsInIndexes; for(const QModelIndex & idx : qAsConst(indices)) { colsInIndexes.insert(idx.column()); rowsInIndexes.insert(idx.row()); } const QString fieldSepText = "\t"; #ifdef Q_OS_WIN const QString rowSepText = "\r\n"; #else const QString rowSepText = "\n"; #endif int firstColumn = *colsInIndexes.begin(); QString sqlInsertStatement; // Table headers if (withHeaders || inSQL) { if (inSQL) sqlInsertStatement = QString("INSERT INTO %1 (").arg(QString::fromStdString(m->currentTableName().toString())); else htmlResult.append(""); } } QProgressDialog progress(this); progress.setWindowModality(Qt::ApplicationModal); // Disable context help button on Windows progress.setWindowFlags(progress.windowFlags() & ~Qt::WindowContextHelpButtonHint); progress.setRange(*rowsInIndexes.begin(), *rowsInIndexes.end()); progress.setMinimumDuration(2000); // Iterate over rows x cols checking if the index actually exists when needed, in order // to support non-rectangular selections. for(const int row : rowsInIndexes) { // Beginning of row if (inSQL) result.append(sqlInsertStatement); else htmlResult.append(""); for(const int column : colsInIndexes) { const QModelIndex index = indices.first().sibling(row, column); const bool isContained = indices.contains(index); if (column != firstColumn) { // Add text separators if (inSQL) result.append(", "); else result.append(fieldSepText); } if(isContained) { QFont font; font.fromString(index.data(Qt::FontRole).toString()); const Qt::Alignment align(index.data(Qt::TextAlignmentRole).toInt()); const QString textAlign(CondFormat::alignmentTexts().at(CondFormat::fromCombinedAlignment(align)).toLower()); htmlResult.append(QString(""); } // End of row if (inSQL) result.append(");"); else htmlResult.append(""); result.append(rowSepText); progress.setValue(row); // Abort the operation if the user pressed ESC key or Cancel button if (progress.wasCanceled()) { return; } } if (!inSQL) { htmlResult.append("
"); for(int col : colsInIndexes) { QByteArray headerText = model()->headerData(col, Qt::Horizontal, Qt::EditRole).toByteArray(); if (col != firstColumn) { if (inSQL) sqlInsertStatement.append(", "); else { result.append(fieldSepText); htmlResult.append(""); } } if (inSQL) sqlInsertStatement.append(sqlb::escapeIdentifier(headerText)); else { result.append(headerText); htmlResult.append(headerText); } } if (inSQL) sqlInsertStatement.append(") VALUES ("); else { result.append(rowSepText); htmlResult.append("
").arg( font.family().toHtmlEscaped(), // font-family QString::number(font.pointSize()), // font-size font.italic() ? "italic" : "normal", // font-style, font.bold() ? "bold" : "normal", // font-weigth, font.underline() ? " text-decoration: underline;" : "", // text-decoration, index.data(Qt::BackgroundRole).toString(), // background-color index.data(Qt::ForegroundRole).toString(), // color textAlign)); } else { htmlResult.append(""); } QImage img; const QVariant bArrdata = isContained ? index.data(Qt::EditRole) : QVariant(); if (bArrdata.isNull()) { // NULL data: NULL in SQL, empty in HTML or text. if (inSQL) result.append("NULL"); } else if(!m->isBinary(index)) { // Text data QByteArray text = bArrdata.toByteArray(); if (inSQL) result.append(sqlb::escapeString(text)); else { result.append(text); // Table cell data: text if (text.contains('\n') || text.contains('\t')) htmlResult.append(QString("
%1
").arg(QString(text).toHtmlEscaped())); else htmlResult.append(QString(text).toHtmlEscaped()); } } else if (inSQL) { // Table cell data: binary in SQL. Save as BLOB literal. result.append(QString("X'%1'").arg(QString(bArrdata.toByteArray().toHex()))); } else if (img.loadFromData(bArrdata.toByteArray())) { // Table cell data: image. Store it as an embedded image in HTML QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); img.save(&buffer, "PNG"); buffer.close(); htmlResult.append(QString("\"Image\"") .arg(QString(ba.toBase64()))); result.append(index.data(Qt::DisplayRole).toByteArray()); } // End of column // Add HTML cell terminator htmlResult.append("
"); mimeData->setHtml(htmlResult); } mimeData->setText(result); } void ExtendedTableWidget::copy(const bool withHeaders, const bool inSQL ) { QMimeData *mimeData = new QMimeData; copyMimeData(selectionModel()->selectedIndexes(), mimeData, withHeaders, inSQL); qApp->clipboard()->setMimeData(mimeData); } void ExtendedTableWidget::paste() { // Get list of selected items QItemSelectionModel* selection = selectionModel(); QModelIndexList indices = selection->selectedIndexes(); // Abort if there's nowhere to paste if(indices.isEmpty()) return; SqliteTableModel* m = qobject_cast(model()); // We're also checking for system clipboard data first. Only if the data in the system clipboard is not ours, we use the system // clipboard, otherwise we prefer the internal buffer. That's because the data in the internal buffer is easier to parse and more // accurate, too. However, if we always preferred the internal copy-paste buffer there would be no way to copy data from other // applications in here once the internal buffer has been filled. // If clipboard contains an image and no text, just insert the image const QMimeData* mimeClipboard = qApp->clipboard()->mimeData(); if (mimeClipboard->hasImage() && !mimeClipboard->hasText()) { QImage img = qApp->clipboard()->image(); QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); img.save(&buffer, "PNG"); // We're always converting the image format to PNG here. TODO: Is that correct? buffer.close(); m->setTypedData(indices.first(), /* isBlob = */ !isTextOnly(ba), ba); return; } // Get the clipboard text QString clipboard = qApp->clipboard()->text(); // If data in system clipboard is ours and the internal copy-paste buffer is filled, use the internal buffer; otherwise parse the // system clipboard contents (case for data copied by other application). std::vector clipboardTable; std::vector* source; if(mimeClipboard->hasHtml() && mimeClipboard->html().contains(m_generatorStamp) && !m_buffer.empty()) { source = &m_buffer; } else { clipboardTable = parseClipboard(clipboard); source = &clipboardTable; } // Stop here if there's nothing to paste if(!source->size()) return; // Starting from assumption that selection is rectangular, and then first index is upper-left corner and last is lower-right. int rows = static_cast(source->size()); int columns = static_cast(source->front().size()); int firstRow = indices.front().row(); int firstColumn = indices.front().column(); int selectedRows = indices.back().row() - firstRow + 1; int selectedColumns = indices.back().column() - firstColumn + 1; // If last row and column are after table size, clamp it int lastRow = qMin(firstRow + rows - 1, m->rowCount() - 1); int lastColumn = qMin(firstColumn + columns - 1, m->columnCount() - 1); // Special case: if there is only one cell of data to be pasted, paste it into all selected fields if(rows == 1 && columns == 1) { QByteArray bArrdata = source->front().front(); for(int row=firstRow;rowsetTypedData(m->index(row, column), !isTextOnly(bArrdata), bArrdata); } return; } // If more than one cell was selected, check if the selection matches the cliboard dimensions if(selectedRows != rows || selectedColumns != columns) { // Ask user if they are sure about this if(QMessageBox::question(this, QApplication::applicationName(), tr("The content of the clipboard is bigger than the range selected.\nDo you want to insert it anyway?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { // If the user doesn't want to paste the clipboard data anymore, stop now return; } } // If we get here, we can definitely start pasting: either the ranges match in their size or the user agreed to paste anyway // Copy the data cell by cell and as-is from the source buffer to the table int row = firstRow; for(const auto& source_row : *source) { int column = firstColumn; for(const QByteArray& source_cell : source_row) { m->setData(m->index(row, column), source_cell); column++; if (column > lastColumn) break; } row++; if (row > lastRow) break; } } void ExtendedTableWidget::cut() { const QModelIndexList& indices = selectionModel()->selectedIndexes(); SqliteTableModel* m = qobject_cast(model()); sqlb::TablePtr currentTable = m->db().getTableByName(m->currentTableName()); copy(false, false); // Check if the column in the selection has a NOT NULL constraint, then update with an empty string, else with NULL if(currentTable) { for(const QModelIndex& index : indices) { // Do not process rowid column if(index.column() != 0) { const size_t indexField = static_cast(index.column()-1); const sqlb::Field& field = currentTable->fields.at(indexField); const QVariant newValue = field.notnull() ? QVariant("") : QVariant(); // Update aborting in case of any error (to avoid repetitive errors like "Database is locked") if(!model()->setData(index, newValue)) return; } } } } void ExtendedTableWidget::useAsFilter(const QString& filterOperator, bool binary, const QString& operatorSuffix) { QModelIndex index = selectionModel()->currentIndex(); SqliteTableModel* m = qobject_cast(model()); // Abort if there's nothing to filter if (!index.isValid() || !selectionModel()->hasSelection() || m->isBinary(index)) return; QVariant bArrdata = model()->data(index, Qt::EditRole); QString value; if (bArrdata.isNull()) value = "NULL"; else if (bArrdata.toString().isEmpty()) value = "''"; else value = bArrdata.toString(); // When Containing filter is requested (empty operator) and the value starts with // an operator character, the character is escaped. if (filterOperator.isEmpty()) value.replace(QRegExp("^(<|>|=|/)"), Settings::getValue("databrowser", "filter_escape").toString() + QString("\\1")); // If binary operator, the cell data is used as first value and // the second value must be added by the user. size_t column = static_cast(index.column()); if (binary) m_tableHeader->setFilter(column, value + filterOperator); else m_tableHeader->setFilter(column, filterOperator + value + operatorSuffix); m_tableHeader->setFocusColumn(column); } void ExtendedTableWidget::duplicateUpperCell() { const QModelIndex& currentIndex = selectionModel()->currentIndex(); QModelIndex upperIndex = currentIndex.sibling(currentIndex.row() - 1, currentIndex.column()); if (upperIndex.isValid()) { SqliteTableModel* m = qobject_cast(model()); // When the data is binary, just copy it, since it cannot be edited inline. if (m->isBinary(upperIndex)) m->setData(currentIndex, m->data(upperIndex, Qt::EditRole), Qt::EditRole); else { // Open the inline editor and set the value (this mimics the behaviour of LibreOffice Calc) edit(currentIndex); QLineEdit* editor = qobject_cast(indexWidget(currentIndex)); editor->setText(upperIndex.data().toString()); } } } void ExtendedTableWidget::keyPressEvent(QKeyEvent* event) { // Call a custom copy method when Ctrl-C is pressed if(event->matches(QKeySequence::Copy)) { copy(false, false); return; } else if(event->matches(QKeySequence::Cut)) { // Call a custom cut method when Ctrl-X is pressed cut(); } else if(event->matches(QKeySequence::Paste)) { // Call a custom paste method when Ctrl-V is pressed paste(); } else if(event->matches(QKeySequence::Print)) { openPrintDialog(); } else if(event->modifiers().testFlag(Qt::ControlModifier) && event->modifiers().testFlag(Qt::ShiftModifier) && (event->key() == Qt::Key_C)) { // Call copy with headers when Ctrl-Shift-C is pressed copy(true, false); } else if(event->modifiers().testFlag(Qt::ControlModifier) && event->modifiers().testFlag(Qt::AltModifier) && (event->key() == Qt::Key_C)) { // Call copy in SQL format when Ctrl-Alt-C is pressed copy(false, true); } else if(event->modifiers().testFlag(Qt::ControlModifier) && (event->key() == Qt::Key_Apostrophe)) { // Call duplicateUpperCell when Ctrl-' is pressed (this is used by spreadsheets for "Copy Formula from Cell Above") duplicateUpperCell(); } else if(event->key() == Qt::Key_Tab && hasFocus() && selectedIndexes().count() == 1 && selectedIndexes().at(0).row() == model()->rowCount()-1 && selectedIndexes().at(0).column() == model()->columnCount()-1) { // If the Tab key was pressed while the focus was on the last cell of the last row insert a new row automatically model()->insertRow(model()->rowCount()); } else if ((event->key() == Qt::Key_Delete) || (event->key() == Qt::Key_Backspace)) { // Check if entire rows are selected. We call the selectedRows() method here not only for simplicity reasons but also because it distinguishes between // "an entire row is selected" and "all cells of a row are selected", the former is e.g. the case when the row number is clicked, the latter when all cells // are selected manually. This is an important distinction (especially when a table has only one column!) to match the users' expectations. Also never // delete records when the backspace key was pressed. if(event->key() == Qt::Key_Delete && selectionModel()->selectedRows().size()) { // At least on entire row is selected. Because we don't allow completely arbitrary selections (at least at the moment) but only block selections, // this means that only entire entire rows are selected. If an entire row is (or multiple entire rows are) selected, we delete that record instead // of deleting only the cell contents. emit selectedRowsToBeDeleted(); } else { // No entire row is selected. So just set the selected cells to null or empty string depending on the modifier keys if(event->modifiers().testFlag(Qt::AltModifier)) { // When pressing Alt+Delete set the value to NULL setToNull(selectedIndexes()); } else { // When pressing Delete only set the value to empty string for(const QModelIndex& index : selectedIndexes()) { if(!model()->setData(index, "")) return; } } } } else if(event->modifiers().testFlag(Qt::ControlModifier) && (event->key() == Qt::Key_PageUp || event->key() == Qt::Key_PageDown)) { // When pressing Ctrl + Page up/down send a signal indicating the user wants to change the current table emit switchTable(event->key() == Qt::Key_PageDown); return; } // Discoverability of Ctrl+Shift+Click to follow foreign keys or URLs if(event->modifiers().testFlag(Qt::ControlModifier) && event->modifiers().testFlag(Qt::ShiftModifier)) QApplication::setOverrideCursor(Qt::PointingHandCursor); // This prevents the current selection from being changed when pressing tab to move to the next filter. Note that this is in an 'if' condition, // not in an 'else if' because this way, when the tab key was pressed and the focus was on the last cell, a new row is inserted and then the tab // key press is processed a second time to move the cursor as well if((event->key() != Qt::Key_Tab && event->key() != Qt::Key_Backtab) || hasFocus()) QTableView::keyPressEvent(event); } void ExtendedTableWidget::keyReleaseEvent(QKeyEvent* event) { // Restore the PointingHandCursor override if(!event->modifiers().testFlag(Qt::ControlModifier) || !event->modifiers().testFlag(Qt::ShiftModifier)) QApplication::restoreOverrideCursor(); QTableView::keyReleaseEvent(event); } void ExtendedTableWidget::updateGeometries() { // Call the parent implementation first - it does most of the actual logic QTableView::updateGeometries(); // Update frozen columns view too if(m_frozen_table_view) m_frozen_table_view->updateGeometries(); // Check if a model has already been set yet if(model()) { // If so and if it is a SqliteTableModel and if the parent implementation of this method decided that a scrollbar is needed, update its maximum value SqliteTableModel* m = qobject_cast(model()); if(m && verticalScrollBar()->maximum()) { verticalScrollBar()->setMaximum(m->rowCount() - numVisibleRows() + 1); if(m_frozen_table_view) m_frozen_table_view->verticalScrollBar()->setMaximum(verticalScrollBar()->maximum()); } } } void ExtendedTableWidget::vscrollbarChanged(int value) { // Cancel if there is no model set yet - this shouldn't happen (because without a model there should be no scrollbar) but just to be sure... if(!model()) return; // Fetch more data from the DB if necessary const auto nrows = model()->rowCount(); if(nrows == 0) return; if(auto * m = dynamic_cast(model())) { int row_begin = std::min(value, nrows - 1); int row_end = std::min(value + numVisibleRows(), nrows); m->triggerCacheLoad(row_begin, row_end); } } int ExtendedTableWidget::numVisibleRows() const { if(!isVisible() || !model() || !verticalHeader()) return 0; // Get the row numbers of the rows currently visible at the top and the bottom of the widget int row_top = rowAt(0) == -1 ? 0 : verticalHeader()->visualIndexAt(0) + 1; // Adjust the height so we don't count rows visible only less than a half of the default height int adjusted_height = viewport()->height() - (verticalHeader()->defaultSectionSize() / 2); int row_bottom = verticalHeader()->visualIndexAt(adjusted_height) == -1 ? model()->rowCount() : (verticalHeader()->visualIndexAt(adjusted_height) + 1); // Calculate the number of visible rows return row_bottom - row_top + 1; } std::unordered_set ExtendedTableWidget::selectedCols() const { std::unordered_set selectedCols; for(const auto& idx : selectionModel()->selectedColumns()) selectedCols.insert(static_cast(idx.column())); return selectedCols; } std::unordered_set ExtendedTableWidget::colsInSelection() const { std::unordered_set colsInSelection; for(const QModelIndex & idx : selectedIndexes()) colsInSelection.insert(static_cast(idx.column())); return colsInSelection; } std::set ExtendedTableWidget::rowsInSelection() const { std::set rowsInSelection; for(const QModelIndex & idx : selectedIndexes()) rowsInSelection.insert(static_cast(idx.row())); return rowsInSelection; } void ExtendedTableWidget::cellClicked(const QModelIndex& index) { // If Ctrl-Shift is pressed try to jump to the row referenced by the foreign key of the clicked cell if(qApp->keyboardModifiers().testFlag(Qt::ControlModifier) && qApp->keyboardModifiers().testFlag(Qt::ShiftModifier) && model()) { SqliteTableModel* m = qobject_cast(model()); auto fk = m->getForeignKeyClause(static_cast(index.column()-1)); if(fk) emit foreignKeyClicked(sqlb::ObjectIdentifier(m->currentTableName().schema(), fk->table()), fk->columns().size() ? fk->columns().at(0) : "", m->data(index, Qt::EditRole).toByteArray()); else { // If this column does not have a foreign-key, try to interpret it as a filename/URL and open it in external application. // TODO: Qt is doing a contiguous selection when Control+Click is pressed. It should be disabled, but at least moving the // current index gives better result. setCurrentIndex(index); emit requestUrlOrFileOpen(model()->data(index, Qt::EditRole).toString()); } } } void ExtendedTableWidget::dragEnterEvent(QDragEnterEvent* event) { event->accept(); } void ExtendedTableWidget::dragMoveEvent(QDragMoveEvent* event) { event->accept(); } void ExtendedTableWidget::dropEvent(QDropEvent* event) { QModelIndex index = indexAt(event->pos()); if (!index.isValid()) { if (event->mimeData()->hasUrls() && event->mimeData()->urls().first().isLocalFile()) emit openFileFromDropEvent(event->mimeData()->urls().first().toLocalFile()); return; } model()->dropMimeData(event->mimeData(), Qt::CopyAction, index.row(), index.column(), QModelIndex()); event->acceptProposedAction(); } void ExtendedTableWidget::selectTableLine(int lineToSelect) { SqliteTableModel* m = qobject_cast(model()); // Are there even that many lines? if(lineToSelect >= m->rowCount()) return; QApplication::setOverrideCursor( Qt::WaitCursor ); m->triggerCacheLoad(lineToSelect); // Select it clearSelection(); selectRow(lineToSelect); scrollTo(currentIndex(), QAbstractItemView::PositionAtTop); QApplication::restoreOverrideCursor(); } void ExtendedTableWidget::selectTableLines(int firstLine, int count) { SqliteTableModel* m = qobject_cast(model()); int lastLine = firstLine+count-1; // Are there even that many lines? if(lastLine >= m->rowCount()) return; selectTableLine(firstLine); QModelIndex topLeft = m->index(firstLine, 0); QModelIndex bottomRight = m->index(lastLine, m->columnCount()-1); selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select | QItemSelectionModel::Rows); } void ExtendedTableWidget::selectAll() { SqliteTableModel* m = qobject_cast(model()); // Fetch all the data if needed and user accepts, then call parent's selectAll() QMessageBox::StandardButton answer = QMessageBox::Yes; // If we can fetch more data, ask user if they are sure about it. if (!m->isCacheComplete()) { answer = QMessageBox::question(this, QApplication::applicationName(), tr("

Not all data has been loaded. Do you want to load all data before selecting all the rows?

" "

Answering No means that no more data will be loaded and the selection will not be performed.
" "Answering Yes might take some time while the data is loaded but the selection will be complete.

" "Warning: Loading all the data might require a great amount of memory for big tables."), QMessageBox::Yes | QMessageBox::No); if (answer == QMessageBox::Yes) m->completeCache(); } if (answer == QMessageBox::Yes) QTableView::selectAll(); } void ExtendedTableWidget::openPrintDialog() { QMimeData *mimeData = new QMimeData; QModelIndexList indices; // Print the selection, if active, or the entire table otherwise. // Given that simply clicking over a cell, selects it, one-cell selections are ignored. if (selectionModel()->hasSelection() && selectionModel()->selectedIndexes().count() > 1) indices = selectionModel()->selectedIndexes(); else for (int row=0; row < model()->rowCount(); row++) for (int column=0; column < model()->columnCount(); column++) indices << model()->index(row, column); // Copy the specified indices content to mimeData for getting the HTML representation of // the table with headers. We can then print it using an HTML text document. copyMimeData(indices, mimeData, true, false); QPrinter printer; QPrintPreviewDialog *dialog = new QPrintPreviewDialog(&printer); connect(dialog, &QPrintPreviewDialog::paintRequested, this, [mimeData](QPrinter *previewPrinter) { QTextDocument document; document.setHtml(mimeData->html()); document.print(previewPrinter); }); dialog->exec(); delete dialog; delete mimeData; } void ExtendedTableWidget::sortByColumns(const std::vector& columns) { // Are there even any columns to sort by? if(columns.size() == 0) return; // We only support sorting for SqliteTableModels with support for multiple and named sort columns SqliteTableModel* sqlite_model = dynamic_cast(model()); if(sqlite_model) sqlite_model->sort(columns); } void ExtendedTableWidget::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { QTableView::currentChanged(current, previous); emit currentIndexChanged(current, previous); } void ExtendedTableWidget::setToNull(const QModelIndexList& indices) { SqliteTableModel* m = qobject_cast(model()); sqlb::TablePtr currentTable = m->db().getTableByName(m->currentTableName()); // Check if some column in the selection has a NOT NULL constraint, before trying to update the cells. if(currentTable) { for(const QModelIndex& index : indices) { // Do not process rowid column if(index.column() != 0) { const size_t indexField = static_cast(index.column()-1); const sqlb::Field& field = currentTable->fields.at(indexField); if(field.notnull()) { QMessageBox::warning(nullptr, qApp->applicationName(), tr("Cannot set selection to NULL. Column %1 has a NOT NULL constraint."). arg(QString::fromStdString(field.name()))); return; } } } } for(const QModelIndex& index : indices) { // Update aborting in case of any error (to avoid repetitive errors like "Database is locked") if(!model()->setData(index, QVariant())) return; } } void ExtendedTableWidget::setFrozenColumns(size_t count) { if(!m_frozen_table_view) return; m_frozen_column_count = count; // Set up frozen table view widget m_frozen_table_view->setModel(model()); m_frozen_table_view->setSelectionModel(selectionModel()); for(int i=0;icolumnCount();i++) m_frozen_table_view->setItemDelegateForColumn(i, nullptr); m_frozen_table_view->setItemDelegateForColumn(static_cast(m_frozen_column_count-1), m_item_border_delegate); // Only show frozen columns in extra table view and copy column widths m_frozen_table_view->horizontalHeader()->blockSignals(true); // Signals need to be blocked because hiding a column would emit resizedSection for(size_t col=0;col(model()->columnCount());++col) m_frozen_table_view->setColumnHidden(static_cast(col), col >= count); m_frozen_table_view->horizontalHeader()->blockSignals(false); for(int col=0;col(count);++col) m_frozen_table_view->setColumnWidth(col, columnWidth(col)); updateFrozenTableGeometry(); // Only show extra table view when there are frozen columns to see if(count) m_frozen_table_view->show(); else m_frozen_table_view->hide(); } void ExtendedTableWidget::generateFilters(size_t number, bool show_rowid) { m_tableHeader->generateFilters(number, m_frozen_column_count); if(m_frozen_table_view) { size_t frozen_columns = std::min(m_frozen_column_count, number); m_frozen_table_view->m_tableHeader->generateFilters(frozen_columns, show_rowid ? 0 : 1); } } void ExtendedTableWidget::updateSectionWidth(int logicalIndex, int /* oldSize */, int newSize) { if(!m_frozen_table_view) return; if(logicalIndex < static_cast(m_frozen_column_count)) { m_frozen_table_view->setColumnWidth(logicalIndex, newSize); setColumnWidth(logicalIndex, newSize); updateFrozenTableGeometry(); } } void ExtendedTableWidget::updateSectionHeight(int logicalIndex, int /* oldSize */, int newSize) { if(!m_frozen_table_view) return; m_frozen_table_view->setRowHeight(logicalIndex, newSize); } void ExtendedTableWidget::resizeEvent(QResizeEvent* event) { QTableView::resizeEvent(event); updateFrozenTableGeometry(); } QModelIndex ExtendedTableWidget::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) { QModelIndex current = QTableView::moveCursor(cursorAction, modifiers); if(!m_frozen_table_view) return current; int width = 0; for(int i=0;i(m_frozen_column_count);i++) width += m_frozen_table_view->columnWidth(i); if(cursorAction == MoveLeft && current.column() > 0 && visualRect(current).topLeft().x() < width) { const int newValue = horizontalScrollBar()->value() + visualRect(current).topLeft().x() - width; horizontalScrollBar()->setValue(newValue); } return current; } void ExtendedTableWidget::scrollTo(const QModelIndex& index, ScrollHint hint) { if(index.column() >= static_cast(m_frozen_column_count)) QTableView::scrollTo(index, hint); } void ExtendedTableWidget::updateFrozenTableGeometry() { if(!m_frozen_table_view) return; int width = 0; for(int i=0;i(m_frozen_column_count);i++) { if(!isColumnHidden(i)) width += columnWidth(i); } m_frozen_table_view->setGeometry(verticalHeader()->width() + frameWidth(), frameWidth(), width, viewport()->height() + horizontalHeader()->height()); } void ExtendedTableWidget::setEditTriggers(QAbstractItemView::EditTriggers editTriggers) { QTableView::setEditTriggers(editTriggers); if(m_frozen_table_view) m_frozen_table_view->setEditTriggers(editTriggers); } void ExtendedTableWidget::setFilter(size_t column, const QString& value) { filterHeader()->setFilter(column, value); if(m_frozen_table_view) m_frozen_table_view->filterHeader()->setFilter(column, value); } sqlitebrowser-sqlitebrowser-5733cb7/src/ExtendedTableWidget.h000066400000000000000000000117571463772530400245230ustar00rootroot00000000000000#ifndef EXTENDEDTABLEWIDGET_H #define EXTENDEDTABLEWIDGET_H #include #include #include #include #include #include "sql/Query.h" class QMenu; class QMimeData; class QDropEvent; class QDragMoveEvent; class FilterTableHeader; class ItemBorderDelegate; namespace sqlb { class ObjectIdentifier; } // Filter proxy model that only accepts distinct non-empty values. class UniqueFilterModel : public QSortFilterProxyModel { Q_OBJECT public: explicit UniqueFilterModel(QObject* parent = nullptr); bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; private: std::unordered_set m_uniqueValues; }; // We use this class to provide editor widgets for the ExtendedTableWidget. It's used for every cell in the table view. class ExtendedTableWidgetEditorDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit ExtendedTableWidgetEditorDelegate(QObject* parent = nullptr); QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override; void setEditorData(QWidget* editor, const QModelIndex& index) const override; void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override; signals: void dataAboutToBeEdited(QModelIndex index) const; }; class ExtendedTableWidget : public QTableView { Q_OBJECT public: explicit ExtendedTableWidget(QWidget* parent = nullptr); ~ExtendedTableWidget() override; FilterTableHeader* filterHeader() { return m_tableHeader; } void generateFilters(size_t number, bool show_rowid); public: // Get set of selected columns (all cells in column has to be selected) std::unordered_set selectedCols() const; // Get set of columns traversed by selection (only some cells in column have to be selected) std::unordered_set colsInSelection() const; // Get set of ordered rows traversed by selection (only some cells in row have to be selected) std::set rowsInSelection() const; int numVisibleRows() const; void sortByColumns(const std::vector& columns); void setFrozenColumns(size_t count); void setModel(QAbstractItemModel* item_model) override; void setEditTriggers(QAbstractItemView::EditTriggers editTriggers); public slots: void reloadSettings(); void selectTableLine(int lineToSelect); void selectTableLines(int firstLine, int count); void selectAll() override; void openPrintDialog(); void setFilter(size_t column, const QString& value); signals: void foreignKeyClicked(const sqlb::ObjectIdentifier& table, const std::string& column, const QByteArray& value); void switchTable(bool next); // 'next' parameter is set to true if next table should be selected and to false if previous table should be selected void openFileFromDropEvent(QString); void selectedRowsToBeDeleted(); void editCondFormats(int column); void currentIndexChanged(const QModelIndex ¤t, const QModelIndex &previous); void dataAboutToBeEdited(const QModelIndex& index); void requestUrlOrFileOpen(const QString& urlString); private: void copyMimeData(const QModelIndexList& fromIndices, QMimeData* mimeData, const bool withHeaders, const bool inSQL); void copy(const bool withHeaders, const bool inSQL); void paste(); void cut(); void useAsFilter(const QString& filterOperator, bool binary = false, const QString& operatorSuffix = QString()); void duplicateUpperCell(); void setToNull(const QModelIndexList& indices); static std::vector> m_buffer; static QString m_generatorStamp; ExtendedTableWidget* m_frozen_table_view; size_t m_frozen_column_count; ItemBorderDelegate* m_item_border_delegate; void updateFrozenTableGeometry(); private slots: void vscrollbarChanged(int value); void cellClicked(const QModelIndex& index); void updateSectionWidth(int logicalIndex, int oldSize, int newSize); void updateSectionHeight(int logicalIndex, int oldSize, int newSize); protected: void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; void updateGeometries() override; void dragEnterEvent(QDragEnterEvent* event) override; void dragMoveEvent(QDragMoveEvent* event) override; void dropEvent(QDropEvent* event) override; void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override; void resizeEvent(QResizeEvent* event) override; QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override; void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible) override; FilterTableHeader* m_tableHeader; QMenu* m_contextMenu; ExtendedTableWidgetEditorDelegate* m_editorDelegate; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/FileDialog.cpp000066400000000000000000000064541463772530400231770ustar00rootroot00000000000000#include "FileDialog.h" #include "Settings.h" QString FileDialog::getOpenFileName(const FileDialogTypes dialogType, QWidget* parent, const QString& caption, const QString &filter, QString *selectedFilter, Options options) { QString result = QFileDialog::getOpenFileName(parent, caption, getFileDialogPath(dialogType), filter, selectedFilter, options); if(!result.isEmpty()) setFileDialogPath(dialogType, result); return result; } QStringList FileDialog::getOpenFileNames(const FileDialogTypes dialogType, QWidget *parent, const QString &caption, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { QStringList result = QFileDialog::getOpenFileNames(parent, caption, getFileDialogPath(dialogType), filter, selectedFilter, options); if(!result.isEmpty()) { QFileInfo path = QFileInfo(result.first()); setFileDialogPath(dialogType, path.absolutePath()); } return result; } QString FileDialog::getSaveFileName(const FileDialogTypes dialogType, QWidget* parent, const QString& caption, const QString& filter, const QString& defaultFileName, QString* selectedFilter, Options options) { QString dir = getFileDialogPath(dialogType); if(!defaultFileName.isEmpty()) dir += "/" + defaultFileName; QString result = QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options); if(!result.isEmpty()) setFileDialogPath(dialogType, result); return result; } QString FileDialog::getExistingDirectory(const FileDialogTypes dialogType, QWidget* parent, const QString& caption, Options options) { QString result = QFileDialog::getExistingDirectory(parent, caption, getFileDialogPath(dialogType), options); if(!result.isEmpty()) setFileDialogPath(dialogType, result); return result; } QString FileDialog::getFileDialogPath(const FileDialogTypes dialogType) { switch(Settings::getValue("db", "savedefaultlocation").toInt()) { case 0: // Remember last location case 2: { // Remember last location for current session only QHash lastLocations = Settings::getValue("db", "lastlocations").toHash(); return lastLocations[QString(dialogType)].toString(); } case 1: // Always use this locations return Settings::getValue("db", "defaultlocation").toString(); default: return QString(); } } void FileDialog::setFileDialogPath(const FileDialogTypes dialogType, const QString& new_path) { QString dir = QFileInfo(new_path).absolutePath(); QHash lastLocations = Settings::getValue("db", "lastlocations").toHash(); lastLocations[QString(dialogType)] = dir; switch(Settings::getValue("db", "savedefaultlocation").toInt()) { case 0: // Remember last location Settings::setValue("db", "lastlocations", lastLocations); break; case 2: // Remember last location for current session only Settings::setValue("db", "lastlocations", lastLocations, false); break; case 1: // Always use this locations break; // Do nothing } } QString FileDialog::getSqlDatabaseFileFilter() { return Settings::getValue("General", "DBFileExtensions").toString() + ";;" + QObject::tr("All files (*)"); //Always add "All files (*)" to the available filters } sqlitebrowser-sqlitebrowser-5733cb7/src/FileDialog.h000066400000000000000000000103341463772530400226340ustar00rootroot00000000000000#ifndef FILEDIALOG_H #define FILEDIALOG_H #include // // File Extensions Filters // - space separated list of file extensions in QString // - used during import/export // - passed to QFileDialog to filter files shown based on extension // // SQLite DB File Extensions static const QString FILE_FILTER_SQLDB(QObject::tr("SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3)")); // SQLite DB Project File Extensions static const QString FILE_FILTER_SQLPRJ(QObject::tr("DB Browser for SQLite Project Files (*.sqbpro)")); static const QString FILE_EXT_SQLPRJ_DEFAULT(".sqbpro"); // SQL File Extensions Filter static const QString FILE_FILTER_SQL(QObject::tr("SQL Files (*.sql)")); static const QString FILE_EXT_SQL_DEFAULT(".sql"); // All Files Extensions Filter static const QString FILE_FILTER_ALL(QObject::tr("All Files (*)")); // Text Files Extensions Filter static const QString FILE_FILTER_TXT(QObject::tr("Text Files (*.txt)")); static const QString FILE_EXT_TXT_DEFAULT(".txt"); // Comma,Tab,or Delimiter-Separated Values File Extensions Filter static const QString FILE_FILTER_CSV(QObject::tr("Comma-Separated Values Files (*.csv)")); static const QString FILE_EXT_CSV_DEFAULT(".csv"); static const QString FILE_FILTER_TSV(QObject::tr("Tab-Separated Values Files (*.tsv)")); static const QString FILE_FILTER_DSV(QObject::tr("Delimiter-Separated Values Files (*.dsv)")); static const QString FILE_FILTER_DAT(QObject::tr("Concordance DAT files (*.dat)")); // JSON File Extensions Filter static const QString FILE_FILTER_JSON(QObject::tr("JSON Files (*.json *.js)")); static const QString FILE_EXT_JSON_DEFAULT(".json"); // XML File Extensions Filter static const QString FILE_FILTER_XML(QObject::tr("XML Files (*.xml)")); static const QString FILE_EXT_XML_DEFAULT(".xml"); // Binary File Extensions Filter static const QString FILE_FILTER_BIN(QObject::tr("Binary Files (*.bin *.dat)")); static const QString FILE_EXT_BIN_DEFAULT(".bin"); // Scalar Vector Graphics File Extensions Filter static const QString FILE_FILTER_SVG(QObject::tr("SVG Files (*.svg)")); static const QString FILE_EXT_SVG_DEFAULT(".svg"); // Hex-Dump File Extension Filter static const QString FILE_FILTER_HEX(QObject::tr("Hex Dump Files (*.dat *.bin)")); // Dynamic/Shared Objects File Extension Filter static const QString FILE_FILTER_DYN(QObject::tr("Extensions (*.so *.dylib *.dll)")); // Initialization File Extension Filter static const QString FILE_FILTER_INI(QObject::tr("Initialization File (*.ini)")); enum FileDialogTypes { NoSpecificType, CreateProjectFile, OpenProjectFile, CreateDatabaseFile, OpenDatabaseFile, CreateSQLFile, OpenSQLFile, OpenCSVFile, CreateDataFile, OpenDataFile, OpenExtensionFile, OpenCertificateFile, CreateSettingsFile, OpenSettingsFile }; class FileDialog : public QFileDialog { Q_OBJECT public: static QString getOpenFileName(const FileDialogTypes dialogType, QWidget* parent = nullptr, const QString& caption = QString(), const QString& filter = QString(), QString* selectedFilter = nullptr, Options options = Options()); static QStringList getOpenFileNames(const FileDialogTypes dialogType, QWidget* parent = nullptr, const QString& caption = QString(), const QString& filter = QString(), QString* selectedFilter = nullptr, Options options = Options()); static QString getSaveFileName(const FileDialogTypes dialogType, QWidget* parent = nullptr, const QString& caption = QString(), const QString& filter = QString(), const QString& defaultFileName = QString(), QString* selectedFilter = nullptr, Options options = Options()); static QString getExistingDirectory(const FileDialogTypes dialogType, QWidget* parent = nullptr, const QString& caption = QString(), Options options = Options()); static QString getSqlDatabaseFileFilter(); private: static QString getFileDialogPath(const FileDialogTypes dialogType); static void setFileDialogPath(const FileDialogTypes dialogType, const QString& new_path); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/FileExtensionManager.cpp000066400000000000000000000067511463772530400252470ustar00rootroot00000000000000#include "FileExtensionManager.h" #include "ui_FileExtensionManager.h" #include FileExtensionManager::FileExtensionManager(QStringList init, QWidget *parent) : QDialog(parent), ui(new Ui::FileExtensionManager) { ui->setupUi(this); int i = 0; for(const QString& itemString : init) { QString description = itemString.left(itemString.indexOf('(')).trimmed(); QString extension = itemString; extension = extension.remove (0, itemString.indexOf('(')+1).remove(')').simplified().trimmed(); QTableWidgetItem *newItemDescription = new QTableWidgetItem(description); QTableWidgetItem *newItemExtension = new QTableWidgetItem(extension); ui->tableExtensions->insertRow(i); ui->tableExtensions->setItem(i, 0, newItemDescription); ui->tableExtensions->setItem(i, 1, newItemExtension); i++; } connect(ui->buttonAdd, SIGNAL(clicked(bool)), this, SLOT(addItem())); connect(ui->buttonRemove, SIGNAL(clicked(bool)), this, SLOT(removeItem())); connect(ui->buttonDown, SIGNAL(clicked(bool)), this, SLOT(downItem())); connect(ui->buttonUp, SIGNAL(clicked(bool)), this, SLOT(upItem())); } FileExtensionManager::~FileExtensionManager() { delete ui; } void FileExtensionManager::addItem() { int i = ui->tableExtensions->rowCount(); ui->tableExtensions->insertRow(i); QTableWidgetItem *newItemDescription = new QTableWidgetItem(tr("Description")); QTableWidgetItem *newItemExtension = new QTableWidgetItem(tr("*.extension")); ui->tableExtensions->setItem(i, 0, newItemDescription); ui->tableExtensions->setItem(i, 1, newItemExtension); } void FileExtensionManager::removeItem() { std::set selectedRows; for (const QTableWidgetItem* item : ui->tableExtensions->selectedItems()) selectedRows.insert(item->row()); for(int row : selectedRows) ui->tableExtensions->removeRow(row); } void FileExtensionManager::upItem() { if (ui->tableExtensions->selectedItems().isEmpty()) return; int selectedRow = ui->tableExtensions->selectedItems().first()->row(); if(selectedRow == 0) return; QTableWidgetItem *t1, *t2; t1 = ui->tableExtensions->takeItem(selectedRow, 0); t2 = ui->tableExtensions->takeItem(selectedRow, 1); ui->tableExtensions->removeRow(selectedRow); ui->tableExtensions->insertRow(selectedRow-1); ui->tableExtensions->setItem(selectedRow-1, 0, t1); ui->tableExtensions->setItem(selectedRow-1, 1, t2); ui->tableExtensions->selectRow(selectedRow-1); } void FileExtensionManager::downItem() { if (ui->tableExtensions->selectedItems().isEmpty()) return; int selectedRow = ui->tableExtensions->selectedItems().first()->row(); if(selectedRow == ui->tableExtensions->rowCount() - 1) return; QTableWidgetItem *t1, *t2; t1 = ui->tableExtensions->takeItem(selectedRow, 0); t2 = ui->tableExtensions->takeItem(selectedRow, 1); ui->tableExtensions->removeRow(selectedRow); ui->tableExtensions->insertRow(selectedRow+1); ui->tableExtensions->setItem(selectedRow+1, 0, t1); ui->tableExtensions->setItem(selectedRow+1, 1, t2); ui->tableExtensions->selectRow(selectedRow+1); } QStringList FileExtensionManager::getDBFileExtensions() const { QStringList result; for (int i = 0; i < ui->tableExtensions->rowCount(); ++i) { result.append(QString("%1 (%2)").arg(ui->tableExtensions->item(i, 0)->text(), ui->tableExtensions->item(i, 1)->text())); } return result; } sqlitebrowser-sqlitebrowser-5733cb7/src/FileExtensionManager.h000066400000000000000000000010341463772530400247010ustar00rootroot00000000000000#ifndef FILEEXTENSIONMANAGER_H #define FILEEXTENSIONMANAGER_H #include namespace Ui { class FileExtensionManager; } class FileExtensionManager : public QDialog { Q_OBJECT public: explicit FileExtensionManager(QStringList init, QWidget *parent = nullptr); ~FileExtensionManager() override; QStringList getDBFileExtensions() const; private: Ui::FileExtensionManager *ui; public slots: void addItem(); void removeItem(); void upItem(); void downItem(); }; #endif // FILEEXTENSIONMANAGER_H sqlitebrowser-sqlitebrowser-5733cb7/src/FileExtensionManager.ui000066400000000000000000000077241463772530400251030ustar00rootroot00000000000000 FileExtensionManager 0 0 578 463 File Extension Manager &Up :/icons/up:/icons/up &Down :/icons/down:/icons/down Qt::Horizontal 40 20 &Add :/icons/field_add:/icons/field_add &Remove :/icons/field_delete:/icons/field_delete QAbstractScrollArea::AdjustToContents true 100 100 Description Extensions Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() FileExtensionManager accept() 248 254 157 274 buttonBox rejected() FileExtensionManager reject() 316 260 286 274 sqlitebrowser-sqlitebrowser-5733cb7/src/FilterLineEdit.cpp000066400000000000000000000240431463772530400240350ustar00rootroot00000000000000#include "FilterLineEdit.h" #include "Settings.h" #include #include #include #include FilterLineEdit::FilterLineEdit(QWidget* parent, std::vector* filters, size_t columnnum) : QLineEdit(parent), filterList(filters), columnNumber(columnnum), conditional_format(true) { setPlaceholderText(tr("Filter")); setClearButtonEnabled(true); setProperty("column", static_cast(columnnum)); // Store the column number for later use // Introduce a timer for delaying the signal triggered whenever the user changes the filter value. // The idea here is that the textChanged() event isn't connected to the update filter slot directly anymore // but instead there this timer mechanism in between: whenever the user changes the filter the delay timer // is (re)started. As soon as the user stops typing the timer has a chance to trigger and call the // delayedSignalTimerTriggered() method which then stops the timer and emits the delayed signal. delaySignalTimer = new QTimer(this); delaySignalTimer->setInterval(Settings::getValue("databrowser", "filter_delay").toInt()); // This is the milliseconds of not-typing we want to wait before triggering connect(this, &FilterLineEdit::textChanged, delaySignalTimer, static_cast(&QTimer::start)); connect(delaySignalTimer, &QTimer::timeout, this, &FilterLineEdit::delayedSignalTimerTriggered); setWhatsThis(tr("These input fields allow you to perform quick filters in the currently selected table.\n" "By default, the rows containing the input text are filtered out.\n" "The following operators are also supported:\n" "%\tWildcard\n" ">\tGreater than\n" "<\tLess than\n" ">=\tEqual to or greater\n" "<=\tEqual to or less\n" "=\tEqual to: exact match\n" "<>\tUnequal: exact inverse match\n" "x~y\tRange: values between x and y\n" "/regexp/\tValues matching the regular expression")); // Immediately emit the delayed filter value changed signal if the user presses the enter or the return key or // the line edit widget loses focus connect(this, &FilterLineEdit::editingFinished, this, &FilterLineEdit::delayedSignalTimerTriggered); // Prepare for adding the What's This information and filter helper actions to the context menu setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &FilterLineEdit::customContextMenuRequested, this, &FilterLineEdit::showContextMenu); } void FilterLineEdit::delayedSignalTimerTriggered() { // Stop the timer first to avoid triggering in intervals delaySignalTimer->stop(); // Only emit text changed signal if the text has actually changed in comparison to the last emitted signal. This is necessary // because this method is also called whenever the line edit loses focus and not only when its text has definitely been changed. if(text() != lastValue) { // Emit the delayed signal using the current value emit delayedTextChanged(text()); // Remember this value for the next time lastValue = text(); } } void FilterLineEdit::keyReleaseEvent(QKeyEvent* event) { bool actedUponKey = false; if(event->key() == Qt::Key_Tab) { if(filterList && columnNumber < filterList->size() - 1) { filterList->at(columnNumber + 1)->setFocus(); } else { QWidget* grandParent = parentWidget()->parentWidget(); // Pass focus to the table (grandparent). // Parent would be the table header, which would cycle back to the first // column (due to proxying). if(grandParent) grandParent->setFocus(); } actedUponKey = true; } else if(event->key() == Qt::Key_Backtab) { if(filterList && columnNumber > 0) { filterList->at(columnNumber - 1)->setFocus(); actedUponKey = true; } } if(!actedUponKey) QLineEdit::keyReleaseEvent(event); } void FilterLineEdit::focusInEvent(QFocusEvent* event) { QLineEdit::focusInEvent(event); emit filterFocused(); } void FilterLineEdit::clear() { // When programmatically clearing the line edit's value make sure the effects are applied immediately, i.e. // bypass the delayed signal timer QLineEdit::clear(); delayedSignalTimerTriggered(); } void FilterLineEdit::setText(const QString& text) { // When programmatically setting the line edit's value make sure the effects are applied immediately, i.e. // bypass the delayed signal timer QLineEdit::setText(text); delayedSignalTimerTriggered(); } void FilterLineEdit::setFilterHelper(const QString& filterOperator, const QString& operatorSuffix) { setText(filterOperator + "?" + operatorSuffix); // Select the value for easy editing of the expression setSelection(filterOperator.length(), 1); } void FilterLineEdit::showContextMenu(const QPoint &pos) { // This has to be created here, otherwise the set of enabled options would not update accordingly. QMenu* editContextMenu = createStandardContextMenu(); editContextMenu->addSeparator(); QMenu* filterMenu = editContextMenu->addMenu(tr("Set Filter Expression")); QAction* whatsThisAction = new QAction(QIcon(":/icons/whatis"), tr("What's This?"), editContextMenu); connect(whatsThisAction, &QAction::triggered, this, [&]() { QWhatsThis::showText(pos, whatsThis(), this); }); QAction* isNullAction = new QAction(tr("Is NULL"), editContextMenu); connect(isNullAction, &QAction::triggered, this, [&]() { setText("=NULL"); }); QAction* isNotNullAction = new QAction(tr("Is not NULL"), editContextMenu); connect(isNotNullAction, &QAction::triggered, this, [&]() { setText("<>NULL"); }); QAction* isEmptyAction = new QAction(tr("Is empty"), editContextMenu); connect(isEmptyAction, &QAction::triggered, this, [&]() { setText("=''"); }); QAction* isNotEmptyAction = new QAction(tr("Is not empty"), editContextMenu); connect(isNotEmptyAction, &QAction::triggered, this, [&]() { setText("<>''"); }); // Simplify this if we ever support a NOT LIKE filter QAction* notContainingAction = new QAction(tr("Not containing..."), editContextMenu); connect(notContainingAction, &QAction::triggered, this, [&]() { setFilterHelper(QString ("/^((?!"), QString(").)*$/")); }); QAction* equalToAction = new QAction(tr("Equal to..."), editContextMenu); connect(equalToAction, &QAction::triggered, this, [&]() { setFilterHelper(QString ("=")); }); QAction* notEqualToAction = new QAction(tr("Not equal to..."), editContextMenu); connect(notEqualToAction, &QAction::triggered, this, [&]() { setFilterHelper(QString ("<>")); }); QAction* greaterThanAction = new QAction(tr("Greater than..."), editContextMenu); connect(greaterThanAction, &QAction::triggered, this, [&]() { setFilterHelper(QString (">")); }); QAction* lessThanAction = new QAction(tr("Less than..."), editContextMenu); connect(lessThanAction, &QAction::triggered, this, [&]() { setFilterHelper(QString ("<")); }); QAction* greaterEqualAction = new QAction(tr("Greater or equal..."), editContextMenu); connect(greaterEqualAction, &QAction::triggered, this, [&]() { setFilterHelper(QString (">=")); }); QAction* lessEqualAction = new QAction(tr("Less or equal..."), editContextMenu); connect(lessEqualAction, &QAction::triggered, this, [&]() { setFilterHelper(QString ("<=")); }); QAction* inRangeAction = new QAction(tr("In range..."), editContextMenu); connect(inRangeAction, &QAction::triggered, this, [&]() { setFilterHelper(QString ("?~")); }); QAction* regexpAction = new QAction(tr("Regular expression..."), editContextMenu); connect(regexpAction, &QAction::triggered, this, [&]() { setFilterHelper(QString ("/"), QString ("/")); }); if(conditional_format) { QAction* conditionalFormatAction; if (text().isEmpty()) { conditionalFormatAction = new QAction(QIcon(":/icons/clear_cond_formats"), tr("Clear All Conditional Formats"), editContextMenu); connect(conditionalFormatAction, &QAction::triggered, this, [&]() { emit clearAllCondFormats(); }); } else { conditionalFormatAction = new QAction(QIcon(":/icons/add_cond_format"), tr("Use for Conditional Format"), editContextMenu); connect(conditionalFormatAction, &QAction::triggered, this, [&]() { emit addFilterAsCondFormat(text()); }); } QAction* editCondFormatsAction = new QAction(QIcon(":/icons/edit_cond_formats"), tr("Edit Conditional Formats..."), editContextMenu); connect(editCondFormatsAction, &QAction::triggered, this, [&]() { emit editCondFormats(); }); editContextMenu->addSeparator(); editContextMenu->addAction(conditionalFormatAction); editContextMenu->addAction(editCondFormatsAction); } filterMenu->addAction(whatsThisAction); filterMenu->addSeparator(); filterMenu->addAction(isNullAction); filterMenu->addAction(isNotNullAction); filterMenu->addAction(isEmptyAction); filterMenu->addAction(isNotEmptyAction); filterMenu->addSeparator(); filterMenu->addAction(notContainingAction); filterMenu->addAction(equalToAction); filterMenu->addAction(notEqualToAction); filterMenu->addAction(greaterThanAction); filterMenu->addAction(lessThanAction); filterMenu->addAction(greaterEqualAction); filterMenu->addAction(lessEqualAction); filterMenu->addAction(inRangeAction); filterMenu->addAction(regexpAction); editContextMenu->exec(mapToGlobal(pos)); } sqlitebrowser-sqlitebrowser-5733cb7/src/FilterLineEdit.h000066400000000000000000000023151463772530400235000ustar00rootroot00000000000000#ifndef FILTERLINEEDIT_H #define FILTERLINEEDIT_H #include #include class QTimer; class QKeyEvent; class FilterLineEdit : public QLineEdit { Q_OBJECT public: explicit FilterLineEdit(QWidget* parent, std::vector* filters = nullptr, size_t columnnum = 0); // Override methods for programmatically changing the value of the line edit void clear(); void setText(const QString& text); void setConditionFormatContextMenuEnabled(bool enable) { conditional_format = enable; } private slots: void delayedSignalTimerTriggered(); signals: void delayedTextChanged(QString text); void addFilterAsCondFormat(QString text); void clearAllCondFormats(); void editCondFormats(); void filterFocused(); protected: void keyReleaseEvent(QKeyEvent* event) override; void focusInEvent(QFocusEvent* event) override; void setFilterHelper(const QString& filterOperator, const QString& operatorSuffix = QString()); private: std::vector* filterList; size_t columnNumber; QTimer* delaySignalTimer; QString lastValue; bool conditional_format; private slots: void showContextMenu(const QPoint &pos); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/FilterTableHeader.cpp000066400000000000000000000126771463772530400245120ustar00rootroot00000000000000#include "FilterTableHeader.h" #include "FilterLineEdit.h" #include #include #include FilterTableHeader::FilterTableHeader(QTableView* parent) : QHeaderView(Qt::Horizontal, parent) { // Activate the click signals to allow sorting setSectionsClickable(true); // But use our own indicators allowing multi-column sorting setSortIndicatorShown(false); // Make sure to not automatically resize the columns according to the contents setSectionResizeMode(QHeaderView::Interactive); // Highlight column headers of selected cells to emulate spreadsheet behaviour setHighlightSections(true); // Do some connects: Basically just resize and reposition the input widgets whenever anything changes connect(this, &FilterTableHeader::sectionResized, this, &FilterTableHeader::adjustPositions); connect(this, &FilterTableHeader::sectionClicked, this, &FilterTableHeader::adjustPositions); connect(parent->horizontalScrollBar(), &QScrollBar::valueChanged, this, &FilterTableHeader::adjustPositions); connect(parent->verticalScrollBar(), &QScrollBar::valueChanged, this, &FilterTableHeader::adjustPositions); // Set custom context menu handling setContextMenuPolicy(Qt::CustomContextMenu); } void FilterTableHeader::generateFilters(size_t number, size_t number_of_hidden_filters) { // Delete all the current filter widgets qDeleteAll(filterWidgets); filterWidgets.clear(); // And generate a bunch of new ones for(size_t i=0; i < number; ++i) { FilterLineEdit* l = new FilterLineEdit(this, &filterWidgets, i); l->setVisible(i >= number_of_hidden_filters); // Set as focus proxy the first non-row-id visible filter-line. if(i!=0 && l->isVisible() && !focusProxy()) setFocusProxy(l); connect(l, &FilterLineEdit::delayedTextChanged, this, &FilterTableHeader::inputChanged); connect(l, &FilterLineEdit::filterFocused, this, [this](){emit filterFocused();}); connect(l, &FilterLineEdit::addFilterAsCondFormat, this, &FilterTableHeader::addFilterAsCondFormat); connect(l, &FilterLineEdit::clearAllCondFormats, this, &FilterTableHeader::clearAllCondFormats); connect(l, &FilterLineEdit::editCondFormats, this, &FilterTableHeader::editCondFormats); filterWidgets.push_back(l); } // Position them correctly updateGeometries(); } QSize FilterTableHeader::sizeHint() const { // For the size hint just take the value of the standard implementation and add the height of a input widget to it if necessary QSize s = QHeaderView::sizeHint(); if(filterWidgets.size()) s.setHeight(s.height() + filterWidgets.at(0)->sizeHint().height() + 4); // The 4 adds just adds some extra space return s; } void FilterTableHeader::updateGeometries() { // If there are any input widgets add a viewport margin to the header to generate some empty space for them which is not affected by scrolling if(filterWidgets.size()) setViewportMargins(0, 0, 0, filterWidgets.at(0)->sizeHint().height()); else setViewportMargins(0, 0, 0, 0); // Now just call the parent implementation and reposition the input widgets QHeaderView::updateGeometries(); adjustPositions(); } void FilterTableHeader::adjustPositions() { // The two adds some extra space between the header label and the input widget const int y = QHeaderView::sizeHint().height() + 2; // Loop through all widgets for(int i=0;i < static_cast(filterWidgets.size()); ++i) { // Get the current widget, move it and resize it QWidget* w = filterWidgets.at(static_cast(i)); if (QApplication::layoutDirection() == Qt::RightToLeft) w->move(width() - (sectionPosition(i) + sectionSize(i) - offset()), y); else w->move(sectionPosition(i) - offset(), y); w->resize(sectionSize(i), w->sizeHint().height()); } } void FilterTableHeader::inputChanged(const QString& new_value) { adjustPositions(); // Just get the column number and the new value and send them to anybody interested in filter changes emit filterChanged(sender()->property("column").toUInt(), new_value); } void FilterTableHeader::addFilterAsCondFormat(const QString& filter) { // Just get the column number and the new value and send them to anybody interested in new conditional formatting emit addCondFormat(sender()->property("column").toUInt(), filter); } void FilterTableHeader::clearAllCondFormats() { // Just get the column number and send it to anybody responsible or interested in clearing conditional formatting emit allCondFormatsCleared(sender()->property("column").toUInt()); } void FilterTableHeader::editCondFormats() { // Just get the column number and the new value and send them to anybody interested in editing conditional formatting emit condFormatsEdited(sender()->property("column").toUInt()); } void FilterTableHeader::clearFilters() { for(FilterLineEdit* filterLineEdit : filterWidgets) filterLineEdit->clear(); } void FilterTableHeader::setFilter(size_t column, const QString& value) { if(column < filterWidgets.size()) filterWidgets.at(column)->setText(value); } QString FilterTableHeader::filterValue(size_t column) const { return filterWidgets[column]->text(); } void FilterTableHeader::setFocusColumn(size_t column) { if(column < filterWidgets.size()) filterWidgets.at(column)->setFocus(); } sqlitebrowser-sqlitebrowser-5733cb7/src/FilterTableHeader.h000066400000000000000000000022541463772530400241450ustar00rootroot00000000000000#ifndef FILTERTABLEHEADER_H #define FILTERTABLEHEADER_H #include #include class QTableView; class FilterLineEdit; class FilterTableHeader : public QHeaderView { Q_OBJECT public: explicit FilterTableHeader(QTableView* parent = nullptr); QSize sizeHint() const override; bool hasFilters() const {return (filterWidgets.size() > 0);} QString filterValue(size_t column) const; void setFocusColumn(size_t column); public slots: void generateFilters(size_t number, size_t number_of_hidden_filters = 1); void adjustPositions(); void clearFilters(); void setFilter(size_t column, const QString& value); signals: void filterChanged(size_t column, QString value); void filterFocused(); void addCondFormat(size_t column, QString filter); void allCondFormatsCleared(size_t column); void condFormatsEdited(size_t column); protected: void updateGeometries() override; private slots: void inputChanged(const QString& new_value); void addFilterAsCondFormat(const QString& filter); void clearAllCondFormats(); void editCondFormats(); private: std::vector filterWidgets; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/FindReplaceDialog.cpp000066400000000000000000000152121463772530400244640ustar00rootroot00000000000000#include "FindReplaceDialog.h" #include "ui_FindReplaceDialog.h" #include "ExtendedScintilla.h" #include FindReplaceDialog::FindReplaceDialog(QWidget* parent) : QDialog(parent), ui(new Ui::FindReplaceDialog), m_scintilla(nullptr), foundIndicatorNumber(0), findInProgress(false) { // Create UI ui->setupUi(this); } FindReplaceDialog::~FindReplaceDialog() { delete ui; } void FindReplaceDialog::setExtendedScintilla(ExtendedScintilla* scintilla) { m_scintilla = scintilla; // Create indicator for find-all and replace-all occurrences foundIndicatorNumber = m_scintilla->indicatorDefine(QsciScintilla::StraightBoxIndicator); m_scintilla->setIndicatorForegroundColor(Qt::magenta, foundIndicatorNumber); m_scintilla->setIndicatorDrawUnder(true, foundIndicatorNumber); bool isWriteable = ! m_scintilla->isReadOnly(); ui->replaceWithText->setEnabled(isWriteable); ui->replaceButton->setEnabled(isWriteable); ui->replaceAllButton->setEnabled(isWriteable); connect(m_scintilla, &ExtendedScintilla::destroyed, this, &FindReplaceDialog::hide); connect(ui->findText, &QLineEdit::editingFinished, this, &FindReplaceDialog::cancelFind); connect(ui->regexpCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); connect(ui->caseCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); connect(ui->wholeWordsCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); connect(ui->wrapCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); connect(ui->backwardsCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); connect(ui->selectionCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); connect(ui->selectionCheckBox, &QCheckBox::toggled, ui->wrapCheckBox, &QCheckBox::setDisabled); } bool FindReplaceDialog::findFirst(bool wrap, bool forward) { if (ui->selectionCheckBox->isChecked()) return m_scintilla->findFirstInSelection (ui->findText->text(), ui->regexpCheckBox->isChecked(), ui->caseCheckBox->isChecked(), ui->wholeWordsCheckBox->isChecked(), forward, /* show */ true, /* posix */ true, /* cxx11 */ true); else return m_scintilla->findFirst (ui->findText->text(), ui->regexpCheckBox->isChecked(), ui->caseCheckBox->isChecked(), ui->wholeWordsCheckBox->isChecked(), wrap, forward, /* line */ -1, /* index */ -1, /* show */ true, /* posix */ true, /* cxx11 */ true); } bool FindReplaceDialog::findNext() { clearIndicators(); if (findInProgress) findInProgress = m_scintilla->findNext(); else findInProgress = findFirst(ui->wrapCheckBox->isChecked(), !ui->backwardsCheckBox->isChecked()); if (!findInProgress) ui->messageLabel->setText(tr("The searched text was not found")); return findInProgress; } void FindReplaceDialog::showFindReplaceDialog(bool hasReplace) { ui->replaceWithText->setVisible(hasReplace); ui->replaceButton->setVisible(hasReplace); ui->replaceWithLabel->setVisible(hasReplace); ui->replaceAllButton->setVisible(hasReplace); show(); } void FindReplaceDialog::show() { ui->findText->setFocus(); // If there is multi-line selected text set automatically the selection // check box. If it's only part of a line, use it as text to find. if (m_scintilla->hasSelectedText()) if (m_scintilla->selectedText().contains("\n")) ui->selectionCheckBox->setChecked(true); else { ui->findText->setText(m_scintilla->selectedText()); ui->selectionCheckBox->setChecked(false); } else ui->selectionCheckBox->setChecked(false); ui->findText->selectAll(); QDialog::show(); } void FindReplaceDialog::replace() { if (m_scintilla->hasSelectedText()) m_scintilla->replace(ui->replaceWithText->text()); findNext(); } void FindReplaceDialog::indicateSelection() { int fromRow, fromIndex, toRow, toIndex; m_scintilla->getSelection(&fromRow, &fromIndex, &toRow, &toIndex); m_scintilla->fillIndicatorRange(fromRow, fromIndex, toRow, toIndex, foundIndicatorNumber); } void FindReplaceDialog::searchAll(bool replace) { clearIndicators(); if (!ui->selectionCheckBox->isChecked()) m_scintilla->setCursorPosition(0, 0); bool found = findFirst(/* wrap */ false, /* fordward */ true); int occurrences = 0; while (found) { if (replace) m_scintilla->replace(ui->replaceWithText->text()); indicateSelection(); ++occurrences; found = m_scintilla->findNext(); } if (!ui->selectionCheckBox->isChecked()) m_scintilla->clearSelection(); QString message; switch (occurrences) { case 0: message = tr("The searched text was not found."); break; case 1: if (replace) message = tr("The searched text was replaced one time."); else message = tr("The searched text was found one time."); break; default: if (replace) message = tr("The searched text was replaced %1 times.").arg(occurrences); else message = tr("The searched text was found %1 times.").arg(occurrences); break; } ui->messageLabel->setText(message); } void FindReplaceDialog::findAll() { searchAll(/* replace */ false); } void FindReplaceDialog::replaceAll() { searchAll(/* replace */ true); } void FindReplaceDialog::cancelFind() { m_scintilla->findFirst(QString(), false, false, false, false); clearIndicators(); findInProgress = false; ui->messageLabel->setText(""); } void FindReplaceDialog::help() { QWhatsThis::enterWhatsThisMode(); } void FindReplaceDialog::clearIndicators() { m_scintilla->clearIndicatorRange(0, 0, m_scintilla->lines(), m_scintilla->lineLength(m_scintilla->lines()), foundIndicatorNumber); ui->messageLabel->setText(""); } void FindReplaceDialog::close() { m_scintilla->clearSelection(); // Reset any previous find so it does not interfere with the next time // the dialog is open. cancelFind(); QDialog::close(); } void FindReplaceDialog::buttonBox_clicked(QAbstractButton* button) { if (button == ui->buttonBox->button(QDialogButtonBox::Help)) help(); else if (button == ui->buttonBox->button(QDialogButtonBox::Close)) close(); } void FindReplaceDialog::reject() { close(); QDialog::reject(); } sqlitebrowser-sqlitebrowser-5733cb7/src/FindReplaceDialog.h000066400000000000000000000017201463772530400241300ustar00rootroot00000000000000#ifndef FindReplaceDialog_H #define FindReplaceDialog_H #include class QAbstractButton; class ExtendedScintilla; namespace Ui { class FindReplaceDialog; } class FindReplaceDialog : public QDialog { Q_OBJECT public: explicit FindReplaceDialog(QWidget* parent = nullptr); ~FindReplaceDialog() override; void setExtendedScintilla(ExtendedScintilla* scintilla); void show(); void showFindReplaceDialog(bool hasReplace); private slots: bool findNext(); void replace(); void findAll(); void replaceAll(); void cancelFind(); void help(); void close(); void reject() override; void buttonBox_clicked(QAbstractButton* button); private: bool findFirst(bool wrap, bool forward); void searchAll(bool replace); void indicateSelection(); void clearIndicators(); Ui::FindReplaceDialog* ui; ExtendedScintilla* m_scintilla; int foundIndicatorNumber; bool findInProgress; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/FindReplaceDialog.ui000066400000000000000000000226421463772530400243240ustar00rootroot00000000000000 FindReplaceDialog 0 0 451 288 Find and Replace true 0 0 0 0 QFormLayout::ExpandingFieldsGrow Fi&nd text: findText Re&place with: replaceWithText Match &exact case false Match &only whole words When enabled, the search continues from the other end when it reaches one end of the page &Wrap around When set, the search goes backwards from cursor position, otherwise it goes forward Search &backwards <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> &Selection only <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Use regular e&xpressions 7 QLayout::SetDefaultConstraint 0 Find the next occurrence from the cursor position and in the direction set by "Search backwards" &Find Next F3 &Replace Highlight all the occurrences of the text in the page F&ind All Replace all the occurrences of the text in the page Replace &All Qt::Vertical 20 40 75 true Qt::AlignCenter QDialogButtonBox::Close|QDialogButtonBox::Help findText replaceWithText caseCheckBox wholeWordsCheckBox wrapCheckBox backwardsCheckBox selectionCheckBox regexpCheckBox findNextButton replaceButton findAllButton replaceAllButton findNextButton clicked() FindReplaceDialog findNext() 225 242 225 132 replaceButton clicked() FindReplaceDialog replace() 225 242 225 132 findAllButton clicked() FindReplaceDialog findAll() 225 242 225 132 replaceAllButton clicked() FindReplaceDialog replaceAll() 225 242 225 132 buttonBox clicked(QAbstractButton*) FindReplaceDialog buttonBox_clicked(QAbstractButton*) 225 265 225 143 updatePreview() checkInput() updateSelection(bool) matchSimilar() sqlitebrowser-sqlitebrowser-5733cb7/src/ForeignKeyEditorDelegate.cpp000066400000000000000000000170221463772530400260350ustar00rootroot00000000000000#include "sqlitedb.h" #include "ForeignKeyEditorDelegate.h" #include #include #include #include Q_DECLARE_METATYPE(sqlb::StringVector) class ForeignKeyEditor : public QWidget { Q_OBJECT public: explicit ForeignKeyEditor(QWidget* parent = nullptr) : QWidget(parent) , tablesComboBox(new QComboBox(this)) , idsComboBox(new QComboBox(this)) , clauseEdit(new QLineEdit(this)) , m_btnReset(new QPushButton(tr("&Reset"), this)) { idsComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); clauseEdit->setPlaceholderText(tr("Foreign key clauses (ON UPDATE, ON DELETE etc.)")); QHBoxLayout* layout = new QHBoxLayout(this); layout->addWidget(tablesComboBox); layout->addWidget(idsComboBox); layout->addWidget(clauseEdit); layout->addWidget(m_btnReset); layout->setSpacing(0); layout->setMargin(0); setLayout(layout); connect(m_btnReset, &QPushButton::clicked, this, [&] { tablesComboBox->setCurrentIndex(-1); idsComboBox->setCurrentIndex(-1); clauseEdit->clear(); }); connect(tablesComboBox, static_cast(&QComboBox::currentIndexChanged), this, [=](int index) { // reset ids combo box idsComboBox->setCurrentIndex(-1); // disable clauses editor if none of tables is selected bool enableClausesEditor = (index!= -1); clauseEdit->setEnabled(enableClausesEditor); }); } QString getSql() const { if (tablesComboBox->currentText().isEmpty()) return QString(); const QString table = sqlb::escapeIdentifier(tablesComboBox->currentText()); const QString clauses = clauseEdit->text(); QString id = idsComboBox->currentText(); if (!id.isEmpty()) id = QString("(%1)").arg(sqlb::escapeIdentifier(id)); return QString("%1%2 %3").arg( table, id, clauses) .trimmed(); } QComboBox* tablesComboBox; QComboBox* idsComboBox; QLineEdit* clauseEdit; // for ON CASCADE and such std::shared_ptr foreignKey; // This can be used for storing a pointer to the foreign key object currently edited private: QPushButton* m_btnReset; }; ForeignKeyEditorDelegate::ForeignKeyEditorDelegate(const DBBrowserDB& db, sqlb::Table& table, QObject* parent) : QStyledItemDelegate(parent) , m_db(db) , m_table(table) { for(const auto& it : m_db.schemata) { for(const auto& jt : it.second.tables) { // Don't insert the current table into the list. The name and fields of the current table are always taken from the m_table reference if(jt.first != m_table.name()) m_tablesIds.insert({jt.first, jt.second->fieldNames()}); } } } QWidget* ForeignKeyEditorDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_UNUSED(option) Q_UNUSED(index) ForeignKeyEditor* editor = new ForeignKeyEditor(parent); editor->setAutoFillBackground(true); connect(editor->tablesComboBox, static_cast(&QComboBox::currentIndexChanged), this, [=](int idx) { QString tableName = editor->tablesComboBox->itemText(idx); QComboBox* box = editor->idsComboBox; box->clear(); box->addItem(QString()); // for those heroes who don't like to specify key explicitly // For recursive foreign keys get the field list from the m_table reference. For other foreign keys from the prepared field lists. if(tableName.toStdString() == m_table.name()) { for(const auto& n : m_table.fieldNames()) box->addItem(QString::fromStdString(n)); } else { for(const auto& n : m_tablesIds[tableName.toStdString()]) box->addItem(QString::fromStdString(n)); } box->setCurrentIndex(0); }); editor->tablesComboBox->clear(); editor->tablesComboBox->addItem(QString::fromStdString(m_table.name())); // For recursive foreign keys editor->tablesComboBox->insertSeparator(1); for(const auto& i : m_tablesIds) editor->tablesComboBox->addItem(QString::fromStdString(i.first)); return editor; } void ForeignKeyEditorDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { ForeignKeyEditor* fkEditor = static_cast(editor); // First try to get the fields list by assuming this is called for a constraints table in which the first column contains a list of fields. // If this fails, assume this is called for a fields table in which the first column contains the name of a single table field. sqlb::StringVector fields = index.sibling(index.row(), 0).data(Qt::UserRole).value(); if(fields.empty()) fields.push_back(index.sibling(index.row(), 0).data().toString().toStdString()); fkEditor->foreignKey = m_table.foreignKey(fields); if (fkEditor->foreignKey) { fkEditor->tablesComboBox->setCurrentText(QString::fromStdString(fkEditor->foreignKey->table())); fkEditor->clauseEdit->setText(QString::fromStdString(fkEditor->foreignKey->constraint())); if (!fkEditor->foreignKey->columns().empty()) fkEditor->idsComboBox->setCurrentText(QString::fromStdString(fkEditor->foreignKey->columns().front())); } else { fkEditor->tablesComboBox->setCurrentIndex(-1); } } void ForeignKeyEditorDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { ForeignKeyEditor* fkEditor = static_cast(editor); QString sql = fkEditor->getSql(); // First try to get the fields list by assuming this is called for a constraints table in which the first column contains a list of fields. // If this fails, assume this is called for a fields table in which the first column contains the name of a single table field. sqlb::StringVector fields = index.sibling(index.row(), 0).data(Qt::UserRole).value(); if(fields.empty()) fields.push_back(index.sibling(index.row(), 0).data().toString().toStdString()); if (sql.isEmpty() && fkEditor->foreignKey) { // Remove the foreign key m_table.removeConstraint(fkEditor->foreignKey); } else { // Create a new foreign key object if required if(!fkEditor->foreignKey) { fkEditor->foreignKey = std::make_shared(); m_table.addConstraint(fields, fkEditor->foreignKey); } // Set data const auto table = fkEditor->tablesComboBox->currentText().toStdString(); const auto id = fkEditor->idsComboBox->currentText().toStdString(); const auto clause = fkEditor->clauseEdit->text().trimmed().toStdString(); fkEditor->foreignKey->setTable(table); if(id.empty()) fkEditor->foreignKey->setColumns({}); else fkEditor->foreignKey->setColumns({id}); fkEditor->foreignKey->setConstraint(clause); } model->setData(index, sql); } void ForeignKeyEditorDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_UNUSED(index) editor->setGeometry(option.rect); } #include "ForeignKeyEditorDelegate.moc" sqlitebrowser-sqlitebrowser-5733cb7/src/ForeignKeyEditorDelegate.h000066400000000000000000000017461463772530400255100ustar00rootroot00000000000000#ifndef FOREIGNKEYDELEGATE_H #define FOREIGNKEYDELEGATE_H #include #include #include #include class DBBrowserDB; namespace sqlb { class Table; } class ForeignKeyEditorDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit ForeignKeyEditorDelegate(const DBBrowserDB& db, sqlb::Table& table, QObject* parent = nullptr); QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override; void setEditorData(QWidget* editor, const QModelIndex& index) const override; void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: const DBBrowserDB& m_db; sqlb::Table& m_table; mutable std::map> m_tablesIds; }; #endif // FOREIGNKEYDELEGATE_H sqlitebrowser-sqlitebrowser-5733cb7/src/IconCache.cpp000066400000000000000000000013331463772530400230030ustar00rootroot00000000000000#include "IconCache.h" QIcon IconCache::null_icon; std::unordered_map IconCache::icons; const QIcon& IconCache::get(const std::string& name) { // Check if we already have an icon object with that name in the cache. If so, just return that auto it = icons.find(name); if(it != icons.end()) return it->second; // If now, try to load an icon with that name and insert it into the cache QIcon icon(":/icons/" + QString::fromStdString(name)); auto ins = icons.insert({name, icon}); // If the insertion was successful, return the inserted icon object. If it was not, return a null icon. if(ins.second) return ins.first->second; else return null_icon; } sqlitebrowser-sqlitebrowser-5733cb7/src/IconCache.h000066400000000000000000000004741463772530400224550ustar00rootroot00000000000000#ifndef ICONCACHE_H #define ICONCACHE_H #include #include #include class IconCache { public: IconCache() = delete; static const QIcon& get(const std::string& name); private: static QIcon null_icon; static std::unordered_map icons; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/ImageViewer.cpp000066400000000000000000000141721463772530400234000ustar00rootroot00000000000000#include "ImageViewer.h" #include "ui_ImageViewer.h" #include #include #include #include #include #include #include ImageViewer::ImageViewer(QWidget* parent) : QWidget(parent), ui(new Ui::ImageViewer), m_image_size(0, 0), m_pan_mode{false} { ui->setupUi(this); ui->scrollArea->viewport()->installEventFilter(this); connect(ui->buttonOriginalSize, &QToolButton::clicked, this, [this]{ scaleImage(100); }); ui->labelView->addAction(ui->actionPrintImage); } ImageViewer::~ImageViewer() { delete ui; } void ImageViewer::resetImage() { ui->labelView->setPixmap(QPixmap(0, 0)); } void ImageViewer::setImage(const QImage& image) { auto widget_size = ui->scrollArea->viewport()->size(); m_image_size = image.size(); ui->labelView->setMaximumSize(m_image_size.scaled(widget_size, Qt::KeepAspectRatio)); ui->labelView->setPixmap(QPixmap::fromImage(image)); // If the image is larger than the viewport scale it to fit the viewport. // If the image is smaller than the viewport show it in its original size. if(!isQSizeCovered(m_image_size)) ui->buttonFitToWindow->setChecked(true); else scaleImage(100); } bool ImageViewer::isQSizeCovered(QSize rect) { auto widget_size = ui->scrollArea->viewport()->size(); return widget_size.width() >= rect.width() && widget_size.height() >= rect.height(); } bool ImageViewer::eventFilter(QObject* /*obj*/, QEvent* e) { auto e_type = e->type(); if (e_type == QEvent::Wheel) { auto *wheel_event = static_cast(e); auto step = ui->sliderScale->pageStep(); if (wheel_event->angleDelta().y() < 0) { step = -step; } scaleImage(ui->sliderScale->value() + step); e->accept(); return true; } if (ui->buttonFitToWindow->isChecked()) { if (e_type == QEvent::Resize) scaleToFitWindow(true); } else if (e_type >= QEvent::MouseButtonPress && e_type <= QEvent::MouseMove) { auto *mouse_event = static_cast(e); if (e_type == QEvent::MouseButtonPress && mouse_event->button() == Qt::LeftButton && !isQSizeCovered(ui->labelView->size())) { m_mouse_down = mouse_event->globalPos(); m_pan_mode = true; ui->scrollArea->setCursor(Qt::ClosedHandCursor); } else if (e_type == QEvent::MouseMove && m_pan_mode) { auto dx = mouse_event->globalX() - m_mouse_down.x(); auto dy = mouse_event->globalY() - m_mouse_down.y(); m_mouse_down = mouse_event->globalPos(); if (dx != 0) { ui->scrollArea->horizontalScrollBar()->setValue(ui->scrollArea->horizontalScrollBar()->value() - dx); } if (dy != 0) { ui->scrollArea->verticalScrollBar()->setValue(ui->scrollArea->verticalScrollBar()->value() - dy); } } else if (e_type == QEvent::MouseButtonRelease && mouse_event->button() == Qt::LeftButton) { m_pan_mode = false; ui->scrollArea->setCursor(Qt::ArrowCursor); } } return false; } void ImageViewer::openPrintImageDialog() { QPrinter printer; QPrintPreviewDialog dialog(&printer); connect(&dialog, &QPrintPreviewDialog::paintRequested, &dialog, [&](QPrinter* previewPrinter) { QPainter painter(previewPrinter); QRect rect = painter.viewport(); #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) QPixmap pixmap = *ui->labelView->pixmap(); #else QPixmap pixmap = ui->labelView->pixmap(Qt::ReturnByValue); #endif QSize size = pixmap.size(); size.scale(rect.size(), Qt::KeepAspectRatio); painter.setViewport(rect.x(), rect.y(), size.width(), size.height()); painter.setWindow(pixmap.rect()); painter.drawPixmap(0, 0, pixmap); }); dialog.exec(); } void ImageViewer::scaleToFitWindow(bool enabled) { // Enable/disable the automatic resizing of the label inside the scrollbar ui->scrollArea->setWidgetResizable(enabled); // When disabling the fit to window scaling, revert back to the original image size if(!enabled) { scaleImage(100); } else { ui->labelView->setMaximumSize(m_image_size.scaled(ui->scrollArea->viewport()->size(), Qt::KeepAspectRatio)); setSliderValueWithoutSignal(static_cast(ui->labelView->maximumWidth() / static_cast(m_image_size.width()) * 100)); } } void ImageViewer::setNoFitWithoutSignal() { if (ui->buttonFitToWindow->isChecked()) { ui->buttonFitToWindow->blockSignals(true); ui->scrollArea->setWidgetResizable(false); ui->buttonFitToWindow->setChecked(false); ui->buttonFitToWindow->blockSignals(false); } } void ImageViewer::setSliderValueWithoutSignal(int value) { ui->sliderScale->blockSignals(true); ui->sliderScale->setValue(value); ui->sliderScale->blockSignals(false); } void ImageViewer::scaleImage(int scale) { // Clamp scale to the sliderScale min/max scale = std::min(ui->sliderScale->maximum(), std::max(ui->sliderScale->minimum(), scale)); // Make sure the slider is updated when this is called programmatically setSliderValueWithoutSignal(scale); // Uncheck the fit to window button setNoFitWithoutSignal(); // Update our scale factor auto scale_factor = scale / 100.0; // Resize the image auto max_size_old = ui->labelView->maximumSize(); ui->labelView->setMaximumSize(m_image_size * scale_factor); ui->labelView->resize(ui->labelView->maximumSize()); auto factor_change = ui->labelView->maximumWidth() / static_cast(max_size_old.width()); // Fix scroll bars to zoom into center of viewport instead of the upper left corner const auto adjust_scrollbar = [](QScrollBar* scroll_bar, qreal factor) { scroll_bar->setValue(static_cast(factor * scroll_bar->value() + ((factor - 1) * scroll_bar->pageStep() / 2))); }; adjust_scrollbar(ui->scrollArea->horizontalScrollBar(), factor_change); adjust_scrollbar(ui->scrollArea->verticalScrollBar(), factor_change); } sqlitebrowser-sqlitebrowser-5733cb7/src/ImageViewer.h000066400000000000000000000013411463772530400230370ustar00rootroot00000000000000#ifndef IMAGEVIEWER_H #define IMAGEVIEWER_H #include namespace Ui { class ImageViewer; } class ImageViewer : public QWidget { Q_OBJECT public: explicit ImageViewer(QWidget* parent = nullptr); ~ImageViewer() override; void resetImage(); void setImage(const QImage& image); public slots: void openPrintImageDialog(); private slots: void scaleToFitWindow(bool enabled); void scaleImage(int scale); private: Ui::ImageViewer* ui; QSize m_image_size; bool m_pan_mode; QPoint m_mouse_down; bool eventFilter(QObject *obj, QEvent *e) override; bool isQSizeCovered(QSize rect); void setNoFitWithoutSignal(); void setSliderValueWithoutSignal(int value); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/ImageViewer.ui000066400000000000000000000115601463772530400232310ustar00rootroot00000000000000 ImageViewer 0 0 433 307 Image Viewer 0 0 0 0 0 Qt::AlignCenter 0 0 431 280 0 0 Qt::ActionsContextMenu true Qt::Horizontal 40 20 1 800 100 Qt::Horizontal Reset the scaling to match the original size of the image. :/icons/view:/icons/view Set the scaling to match the size of the viewport. :/icons/monitor_link:/icons/monitor_link true :/icons/print:/icons/print Print... Open preview dialog for printing displayed image Ctrl+P actionPrintImage triggered() ImageViewer openPrintImageDialog() -1 -1 308 190 sliderScale valueChanged(int) ImageViewer scaleImage(int) 280 294 216 153 buttonFitToWindow toggled(bool) ImageViewer scaleToFitWindow(bool) 419 294 216 153 scaleImage(int) scaleToFitWindow(bool) sqlitebrowser-sqlitebrowser-5733cb7/src/ImportCsvDialog.cpp000066400000000000000000001075551463772530400242520ustar00rootroot00000000000000#include "ImportCsvDialog.h" #include "ui_ImportCsvDialog.h" #include "sqlitedb.h" #include "csvparser.h" #include "sqlite.h" #include "Settings.h" #include "Data.h" #include #include #include #include #include #include #include #include #include #include #include // Enable this line to show basic performance stats after each imported CSV file. Please keep in mind that while these // numbers might help to estimate the performance of the algorithm, this is not a proper benchmark. //#define CSV_BENCHMARK #ifdef CSV_BENCHMARK #include #endif QChar ImportCsvDialog::getSettingsChar(const std::string& group, const std::string& name) { QVariant value = Settings::getValue(group, name); // QVariant is not able to return the character as a QChar when QString is stored. // We do it manually, since it is versatile, when the option is passed from the command line, // for example. if(value.userType() == QMetaType::QString) return value.toString().at(0); else return value.toChar(); } ImportCsvDialog::ImportCsvDialog(const std::vector& filenames, DBBrowserDB* db, QWidget* parent, const QString& table) : QDialog(parent), ui(new Ui::ImportCsvDialog), csvFilenames(filenames), pdb(db) { ui->setupUi(this); // Hide "Advanced" section of the settings toggleAdvancedSection(false); if(!table.isEmpty()) { ui->editName->setText(table); } else { // Get the actual file name out of the provided path and use it as the default table name for import // For importing several files at once, the fields have to be the same so we can safely use the first QFileInfo file(filenames.front()); ui->editName->setText(file.baseName()); } // Create a list of all available encodings and create an auto completion list from them encodingCompleter = new QCompleter(toStringList(QTextCodec::availableCodecs()), this); encodingCompleter->setCaseSensitivity(Qt::CaseInsensitive); ui->editCustomEncoding->setCompleter(encodingCompleter); // Load last used settings and apply them ui->checkboxHeader->blockSignals(true); ui->checkBoxTrimFields->blockSignals(true); ui->checkBoxSeparateTables->blockSignals(true); ui->checkLocalConventions->blockSignals(true); ui->comboSeparator->blockSignals(true); ui->comboQuote->blockSignals(true); ui->comboEncoding->blockSignals(true); ui->checkboxHeader->setChecked(Settings::getValue("importcsv", "firstrowheader").toBool()); ui->checkBoxTrimFields->setChecked(Settings::getValue("importcsv", "trimfields").toBool()); ui->checkBoxSeparateTables->setChecked(Settings::getValue("importcsv", "separatetables").toBool()); ui->checkLocalConventions->setChecked(Settings::getValue("importcsv", "localconventions").toBool()); setSeparatorChar(getSettingsChar("importcsv", "separator")); setQuoteChar(getSettingsChar("importcsv", "quotecharacter")); setEncoding(Settings::getValue("importcsv", "encoding").toString()); ui->checkboxHeader->blockSignals(false); ui->checkBoxTrimFields->blockSignals(false); ui->checkBoxSeparateTables->blockSignals(false); ui->checkLocalConventions->blockSignals(false); ui->comboSeparator->blockSignals(false); ui->comboQuote->blockSignals(false); ui->comboEncoding->blockSignals(false); // Prepare and show interface depending on how many files are selected if (csvFilenames.size() > 1) { ui->separateTables->setVisible(true); ui->checkBoxSeparateTables->setVisible(true); ui->filePickerBlock->setVisible(true); selectFiles(); } else if (csvFilenames.size() == 1) { ui->separateTables->setVisible(false); ui->checkBoxSeparateTables->setVisible(false); ui->filePickerBlock->setVisible(false); } selectedFile = csvFilenames.front(); updatePreview(); checkInput(); } ImportCsvDialog::~ImportCsvDialog() { delete ui; } namespace { void rollback( ImportCsvDialog* dialog, DBBrowserDB* pdb, DBBrowserDB::db_pointer_type* db_ptr, const std::string& savepointName, size_t nRecord, const QString& message) { // Release DB handle. This needs to be done before calling revertToSavepoint as that function needs to be able to acquire its own handle. if(db_ptr) *db_ptr = nullptr; QApplication::restoreOverrideCursor(); // restore original cursor if(!message.isEmpty()) { QString sCSVInfo = QObject::tr("Error importing data"); if(nRecord) sCSVInfo += QObject::tr(" from record number %1").arg(nRecord); QString error = sCSVInfo + QObject::tr(".\n%1").arg(message); QMessageBox::warning(dialog, QApplication::applicationName(), error); } pdb->revertToSavepoint(savepointName); } } class CSVImportProgress : public CSVProgress { public: explicit CSVImportProgress(int64_t filesize) : m_pProgressDlg(new QProgressDialog( QObject::tr("Importing CSV file..."), QObject::tr("Cancel"), 0, 10000)), totalFileSize(filesize) { m_pProgressDlg->setWindowModality(Qt::ApplicationModal); // Disable context help button on Windows m_pProgressDlg->setWindowFlags(m_pProgressDlg->windowFlags() & ~Qt::WindowContextHelpButtonHint); } CSVImportProgress(const CSVImportProgress&) = delete; bool operator=(const CSVImportProgress&) = delete; void start() override { m_pProgressDlg->show(); } bool update(int64_t pos) override { m_pProgressDlg->setValue(static_cast((static_cast(pos) / static_cast(totalFileSize)) * 10000.0f)); qApp->processEvents(); return !m_pProgressDlg->wasCanceled(); } void end() override { m_pProgressDlg->hide(); } private: std::unique_ptr m_pProgressDlg; int64_t totalFileSize; }; void ImportCsvDialog::accept() { // Save settings Settings::setValue("importcsv", "firstrowheader", ui->checkboxHeader->isChecked()); Settings::setValue("importcsv", "separator", currentSeparatorChar()); Settings::setValue("importcsv", "quotecharacter", currentQuoteChar()); Settings::setValue("importcsv", "trimfields", ui->checkBoxTrimFields->isChecked()); Settings::setValue("importcsv", "separatetables", ui->checkBoxSeparateTables->isChecked()); Settings::setValue("importcsv", "localconventions", ui->checkLocalConventions->isChecked()); Settings::setValue("importcsv", "encoding", currentEncoding()); // Get all the selected files and start the import if (ui->filePickerBlock->isVisible()) { bool filesLeft = false; // Loop through all the rows in the file picker list for (int i = 0; i < ui->filePicker->count(); i++) { auto item = ui->filePicker->item(i); int row = ui->filePicker->row(item); // Check for files that aren't hidden (=imported) yet but that are checked and thus marked for import if (item->checkState() == Qt::Checked && !ui->filePicker->isRowHidden(row)) { if(!importCsv(item->data(Qt::DisplayRole).toString(), item->data(Qt::UserRole).toString())) { // If we're supposed to cancel the import process, we always have at least one file left (the cancelled one). Also // we stop looping through the rest of the CSV files. filesLeft = true; break; } // Hide each row after it's done ui->filePicker->setRowHidden(row, true); } else if(!ui->filePicker->isRowHidden(row)) { // Check for files that aren't hidden yet but that aren't checked either. These are files that are still left // to be imported filesLeft = true; } } // Don't close the window if there are still files left to be imported if(filesLeft) { QApplication::restoreOverrideCursor(); // restore original cursor return; } } else { importCsv(csvFilenames.front()); } QApplication::restoreOverrideCursor(); // restore original cursor QDialog::accept(); } void ImportCsvDialog::updatePreview() { // Show/hide custom quote/separator input fields ui->editCustomQuote->setVisible(ui->comboQuote->currentIndex() == ui->comboQuote->count() - OtherPrintable); ui->editCustomSeparator->setVisible(ui->comboSeparator->currentIndex() == ui->comboSeparator->count() - OtherPrintable); ui->spinBoxQuote->setVisible(ui->comboQuote->currentIndex() == ui->comboQuote->count() - OtherCode); ui->spinBoxSeparator->setVisible(ui->comboSeparator->currentIndex() == ui->comboSeparator->count() - OtherCode); ui->editCustomEncoding->setVisible(ui->comboEncoding->currentIndex() == ui->comboEncoding->count()-1); // Reset preview widget ui->tablePreview->clear(); ui->tablePreview->setColumnCount(0); ui->tablePreview->setRowCount(0); // Analyse CSV file sqlb::FieldVector fieldList = generateFieldList(selectedFile); // Reset preview widget ui->tablePreview->clear(); ui->tablePreview->setColumnCount(static_cast(fieldList.size())); // Exit if there are no lines to preview at all if(fieldList.size() == 0) return; // Set horizontal header data QStringList horizontalHeader; std::transform(fieldList.begin(), fieldList.end(), std::back_inserter(horizontalHeader), [](const auto& field) { return QString::fromStdString(field.name()); }); ui->tablePreview->setHorizontalHeaderLabels(horizontalHeader); // Parse file parseCSV(selectedFile, [this](size_t rowNum, const CSVRow& rowData) -> bool { // Skip first row if it is to be used as header if(rowNum == 0 && ui->checkboxHeader->isChecked()) return true; // Decrease the row number by one if the header checkbox is checked to take into account that the first row was used for the table header labels // and therefore all data rows move one row up. if(ui->checkboxHeader->isChecked()) rowNum--; // Fill data section ui->tablePreview->setRowCount(ui->tablePreview->rowCount() + 1); for(size_t i=0;itablePreview->setVerticalHeaderItem(static_cast(rowNum), new QTableWidgetItem(QString::number(rowNum + 1))); // Add table item. Limit data length to a maximum character count to avoid a sluggish UI. And it's very unlikely that this // many characters are going to be needed anyway for a preview. uint64_t data_length = rowData.fields[i].data_length; if(data_length > 1024) data_length = 1024; ui->tablePreview->setItem( static_cast(rowNum), static_cast(i), new QTableWidgetItem(QString::fromUtf8(rowData.fields[i].data, static_cast(data_length)))); } return true; }, 20); } void ImportCsvDialog::checkInput() { bool allowImporting = false; if (ui->filePickerBlock->isVisible()) { bool checkedItem = false; for (int i = 0; i < ui->filePicker->count(); i++) { if (ui->filePicker->item(i)->checkState() == Qt::Checked) checkedItem = true; } allowImporting = !ui->editName->text().isEmpty() && checkedItem; } else { allowImporting = !ui->editName->text().isEmpty(); } if (ui->filePicker->currentItem() && ui->checkBoxSeparateTables->isChecked()) { ui->filePicker->currentItem()->setData(Qt::UserRole, ui->editName->text()); } ui->matchSimilar->setEnabled(ui->filePicker->currentItem() != nullptr); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowImporting); } void ImportCsvDialog::selectFiles() { for (const auto& fileName : csvFilenames) { auto fInfo = QFileInfo(fileName); auto item = new QListWidgetItem(); item->setText(fileName); item->setData(Qt::UserRole, fInfo.baseName()); item->setCheckState(Qt::Checked); ui->filePicker->addItem(item); } connect(ui->filePicker, &QListWidget::itemSelectionChanged, this, &ImportCsvDialog::updateSelectedFilePreview); } void ImportCsvDialog::updateSelectedFilePreview() { auto selection = ui->filePicker->selectedItems(); if(!selection.isEmpty()) { auto item = selection.first(); selectedFile = item->data(Qt::DisplayRole).toString(); ui->editName->setText(item->data(Qt::UserRole).toString()); updatePreview(); checkInput(); } } void ImportCsvDialog::updateSelection(bool selected) { for (int i = 0; i < ui->filePicker->count(); i++) ui->filePicker->item(i)->setCheckState(selected ? Qt::Checked : Qt::Unchecked); ui->toggleSelected->setText(selected ? tr("Deselect All") : tr("Select All")); checkInput(); } void ImportCsvDialog::matchSimilar() { auto selectedHeader = generateFieldList(ui->filePicker->currentItem()->data(Qt::DisplayRole).toString()); for (int i = 0; i < ui->filePicker->count(); i++) { auto item = ui->filePicker->item(i); auto header = generateFieldList(item->data(Qt::DisplayRole).toString()); if (selectedHeader.size() == header.size()) { bool matchingHeader = std::equal(selectedHeader.begin(), selectedHeader.end(), header.begin(), [](const sqlb::Field& item1, const sqlb::Field& item2) -> bool { return (item1.name() == item2.name()); }); if (matchingHeader) { item->setCheckState(Qt::Checked); item->setBackground(Qt::green); } } else { item->setCheckState(Qt::Unchecked); item->setBackground(Qt::white); } } checkInput(); } CSVParser::ParserResult ImportCsvDialog::parseCSV(const QString &fileName, std::function rowFunction, size_t count) const { // Parse all csv data QFile file(fileName); file.open(QIODevice::ReadOnly); CSVParser csv(ui->checkBoxTrimFields->isChecked(), toUtf8(currentSeparatorChar()), toUtf8(currentQuoteChar())); // Only show progress dialog if we parse all rows. The assumption here is that if a row count limit has been set, it won't be a very high one. if(count == 0) csv.setCSVProgress(new CSVImportProgress(file.size())); QTextStream tstream(&file); tstream.setCodec(currentEncoding().toUtf8()); return csv.parse(rowFunction, tstream, count); } sqlb::FieldVector ImportCsvDialog::generateFieldList(const QString& filename) const { sqlb::FieldVector fieldList; // List of fields in the file // Parse the first couple of records of the CSV file and only analyse them parseCSV(filename, [this, &fieldList](size_t rowNum, const CSVRow& rowData) -> bool { // Has this row more columns than the previous one? Then add more fields to the field list as necessary. for(size_t i=fieldList.size();icheckboxHeader->isChecked()) { // Take field name from CSV fieldname = std::string(rowData.fields[i].data, rowData.fields[i].data_length); } // If we don't have a field name by now, generate one if(fieldname.empty()) fieldname = "field" + std::to_string(i + 1); // Add field to the column list. For now we set the data type to nothing but this might be overwritten later in the automatic // type detection code. fieldList.emplace_back(fieldname, ""); } // Try to find out a data type for each column. Skip the header row if there is one. if(!ui->checkNoTypeDetection->isChecked() && !(rowNum == 0 && ui->checkboxHeader->isChecked())) { for(size_t i=0;i(rowData.fields[i].data_length)); const QLocale &locale = ui->checkLocalConventions->isChecked() ? QLocale::system() : QLocale::c(); // Check if the content can be converted to an integer or to real bool convert_to_integer, convert_to_real; locale.toLongLong(content, &convert_to_integer); locale.toDouble(content, &convert_to_real); // Set new data type. If we don't find any better data type, we fall back to the TEXT data type std::string new_type = "TEXT"; if(old_type == "INTEGER" && !convert_to_integer && convert_to_real) // So far it's integer, but now it's only convertible to float new_type = "REAL"; else if(old_type.empty() && convert_to_integer) // No type yet, but this bit is convertible to integer new_type = "INTEGER"; else if(old_type.empty() && convert_to_real) // No type yet and only convertible to float (less 'difficult' than integer) new_type = "REAL"; else if(old_type == "REAL" && convert_to_real) // It was float so far and still is new_type = "INTEGER"; else if(old_type == "INTEGER" && convert_to_integer) // It was integer so far and still is new_type = "INTEGER"; fieldList.at(i).setType(new_type); } } } // All good return true; }, 20); return fieldList; } bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name) { // This function returns a boolean to indicate whether to continue or abort the import process. It's worth keeping in mind that // this doesn't correlate 100% to this import being a success or not. The general rule is that if there was some internal error // when writing to the database, we stop the entire import process. Also, if the user has clicked Cancel during the import of one // file, we stop the entire import process, i.e. also the import of the remaining files. Furthermore, if the user clicks the Cancel // button in a message box we (obviously) cancel the import process, too. In all other cases we return true to indicate that the import // should continue. #ifdef CSV_BENCHMARK // If benchmark mode is enabled start measuring the performance now qint64 timesRowFunction = 0; QElapsedTimer timer; timer.start(); #endif QString tableName; if (csvFilenames.size() > 1 && ui->checkBoxSeparateTables->isChecked()) { if (name.isEmpty()) { QFileInfo fileInfo(fileName); tableName = fileInfo.baseName(); } else { tableName = name; } } else { tableName = ui->editName->text(); } // Analyse CSV file sqlb::FieldVector fieldList = generateFieldList(fileName); if(fieldList.size() == 0) return true; // Are we importing into an existing table? bool importToExistingTable = false; const sqlb::TablePtr tbl = pdb->getTableByName(sqlb::ObjectIdentifier("main", tableName.toStdString())); if(tbl) { if(tbl->fields.size() != fieldList.size()) { QMessageBox::warning(this, QApplication::applicationName(), tr("There is already a table named '%1' and an import into an existing table is only possible if the number of columns match.").arg(tableName)); return true; } else { // Only ask whether to import into any table if the 'Yes to All' button has not been clicked (yet) (empty string is included). // Only ask whether to import into the existing table if the 'Yes' button has not been clicked (yet) for that table. if(!dontAskForExistingTableAgain.contains("") && !dontAskForExistingTableAgain.contains(tableName)) { int answer = QMessageBox::question(this, QApplication::applicationName(), tr("There is already a table named '%1'. Do you want to import the data into it?").arg(tableName), QMessageBox::Yes | QMessageBox::No | QMessageBox::YesAll | QMessageBox::Cancel, QMessageBox::No); // Stop now if the No button has been clicked switch (answer) { case QMessageBox::No: return true; // Stop now if the Cancel button has been clicked. But also indicate, that the entire import process should be stopped. case QMessageBox::Cancel: return false; // If the 'Yes' button has been clicked, save the answer for that table for later case QMessageBox::Yes: dontAskForExistingTableAgain.append(tableName); break; // If the 'Yes to All' button has been clicked, save the answer for any future table name. An empty string is used in that case. case QMessageBox::YesAll: dontAskForExistingTableAgain.append(""); break; } } // If we reached this point, this means that either the 'Yes' or the 'Yes all' button has been clicked or that no message box was shown at all // because the 'Yes all' button has been clicked for a previous file importToExistingTable = true; } } // Create a savepoint, so we can rollback in case of any errors during importing // db needs to be saved or an error will occur std::string restorepointName = pdb->generateSavepointName("csvimport"); if(!pdb->setSavepoint(restorepointName)) { rollback(this, pdb, nullptr, restorepointName, 0, tr("Creating restore point failed: %1").arg(pdb->lastError())); return false; } // Create table std::vector nullValues; std::vector failOnMissingFieldList; bool ignoreDefaults = ui->checkIgnoreDefaults->isChecked(); bool failOnMissing = ui->checkFailOnMissing->isChecked(); if(!importToExistingTable) { if(!pdb->createTable(sqlb::ObjectIdentifier("main", tableName.toStdString()), fieldList)) { rollback(this, pdb, nullptr, restorepointName, 0, tr("Creating the table failed: %1").arg(pdb->lastError())); return false; } // If we're creating the table in this import session, don't ask the user if it's okay to import more data into it. It seems // safe to just assume that's what they want. dontAskForExistingTableAgain.append(tableName); } else { // Importing into an existing table. So find out something about it's structure. // Prepare the values for each table column that are to be inserted if the field in the CSV file is empty. Depending on the data type // and the constraints of a field, we need to handle this case differently. if(tbl) { for(const sqlb::Field& f : tbl->fields) { // For determining the value for empty fields we follow a set of rules // Normally we don't have to fail the import when importing an empty field. This last value of the vector // is changed to true later if we actually do want to fail the import for this field. failOnMissingFieldList.push_back(false); // If a field has a default value, that gets priority over everything else. // Exception: if the user wants to ignore default values we never use them. if(!ignoreDefaults && !f.defaultValue().empty()) { nullValues.push_back(f.defaultValue().c_str()); } else { // If it has no default value, check if the field is NOT NULL if(f.notnull()) { // The field is NOT NULL // If this is an integer column insert 0. Otherwise insert an empty string. if(f.isInteger()) nullValues.push_back("0"); else nullValues.push_back(""); // If the user wants to fail the import, remember this field if(failOnMissing) failOnMissingFieldList.back() = true; } else { // The field is not NOT NULL (stupid double negation here! NULL values are allowed in this case) // Just insert a NULL value nullValues.push_back(QByteArray()); } } } } } // Prepare the INSERT statement. The prepared statement can then be reused for each row to insert std::string sQuery = "INSERT " + currentOnConflictStrategy() + " INTO " + sqlb::escapeIdentifier(tableName.toStdString()) + " VALUES("; for(size_t i=1;i<=fieldList.size();i++) sQuery += "?" + std::to_string(i) + ","; sQuery.pop_back(); // Remove last comma sQuery.append(")"); sqlite3_stmt* stmt; auto pDb = pdb->get(tr("importing CSV")); if(sqlite3_prepare_v2(pDb.get(), sQuery.c_str(), static_cast(sQuery.size()), &stmt, nullptr) != SQLITE_OK) { rollback(this, pdb, nullptr, restorepointName, 0, tr("Could not prepare INSERT statement: %1").arg(pdb->lastError())); return false; } // Parse entire file size_t lastRowNum = 0; CSVParser::ParserResult result = parseCSV(fileName, [&](size_t rowNum, const CSVRow& rowData) -> bool { // Process the parser results row by row #ifdef CSV_BENCHMARK qint64 timeAtStartOfRowFunction = timer.elapsed(); #endif // Save row num for later use. This is used in the case of an error to tell the user in which row the error occurred lastRowNum = rowNum; // If this is the first row and we want to use the first row as table header, skip it now because this is the data import, not the header parsing if(rowNum == 0 && ui->checkboxHeader->isChecked()) return true; // Bind all values for(size_t i=0;i i) { // Do we want to fail when trying to import an empty value into this field? Then exit with an error. if(failOnMissingFieldList.at(i)) return false; // This is an empty value. We'll need to look up how to handle it depending on the field to be inserted into. const QByteArray& val = nullValues.at(i); if(!val.isNull()) // No need to bind NULL values here as that is the default bound value in SQLite sqlite3_bind_text(stmt, static_cast(i)+1, val, val.size(), SQLITE_STATIC); // When importing into a new table, use the missing values setting directly } else if(!importToExistingTable && rowData.fields[i].data_length == 0) { // No need to bind NULL values here as that is the default bound value in SQLite } else { // This is a non-empty value, or we want to insert the empty string. Just add it to the statement. bool convert_ok = false; if(ui->checkLocalConventions->isChecked()) { // Find the correct data type taking into account the locale. QString content = QString::fromUtf8(rowData.fields[i].data, static_cast(rowData.fields[i].data_length)); sqlite_int64 int64_value = QLocale::system().toLongLong(content, &convert_ok); if(convert_ok) { sqlite3_bind_int64(stmt, static_cast(i)+1, int64_value); } else { double value = QLocale::system().toDouble(content, &convert_ok); if(convert_ok) sqlite3_bind_double(stmt, static_cast(i)+1, value); } } if(!convert_ok) { // If we don't find any better data type or we want SQLite to apply the type affinity // (impossible when using local conventions), we fall back to the TEXT data type. sqlite3_bind_text(stmt, static_cast(i)+1, rowData.fields[i].data, static_cast(rowData.fields[i].data_length), SQLITE_STATIC); } } } // Insert row if(sqlite3_step(stmt) != SQLITE_DONE) return false; // Reset statement for next use. Also reset all bindings to NULL. This is important, so we don't need to bind missing columns or empty values in NULL // columns manually. sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); #ifdef CSV_BENCHMARK timesRowFunction += timer.elapsed() - timeAtStartOfRowFunction; #endif return true; }); // Success? if(result != CSVParser::ParserResult::ParserResultSuccess) { // Some error occurred or the user cancelled the action // Rollback the entire import. If the action was cancelled, don't show an error message. If it errored, show an error message. QString message; if(result == CSVParser::ParserResult::ParserResultError) { QString error(sqlite3_errmsg(pDb.get())); message = tr("Inserting row failed: %1").arg(error); } else if(result == CSVParser::ParserResult::ParserResultUnexpectedEOF) { message = tr("Unexpected end of file. Please make sure that you have configured the correct quote characters and " "the file is not malformed."); } sqlite3_finalize(stmt); rollback(this, pdb, &pDb, restorepointName, lastRowNum, message); return false; } // Clean up prepared statement sqlite3_finalize(stmt); #ifdef CSV_BENCHMARK QMessageBox::information(this, qApp->applicationName(), tr("Importing the file '%1' took %2ms. Of this %3ms were spent in the row function.") .arg(fileName) .arg(timer.elapsed()) .arg(timesRowFunction)); #endif return true; } void ImportCsvDialog::setQuoteChar(QChar c) { QComboBox* combo = ui->comboQuote; int index = combo->findText(QString(c)); ui->spinBoxQuote->setValue(c.unicode()); if(index == -1) { if(c.isPrint()) { combo->setCurrentIndex(combo->count() - OtherPrintable); ui->editCustomQuote->setText(QString(c)); } else { combo->setCurrentIndex(combo->count() - OtherCode); } } else { combo->setCurrentIndex(index); } } QChar ImportCsvDialog::currentQuoteChar() const { QString value; // The last item in the combobox is the 'Other' item; if it is selected return the text of the line edit field instead if(ui->comboQuote->currentIndex() == ui->comboQuote->count() - OtherPrintable) value = ui->editCustomQuote->text().length() ? ui->editCustomQuote->text() : ""; else if(ui->comboQuote->currentIndex() == ui->comboQuote->count() - OtherCode) value = QString(QChar(ui->spinBoxQuote->value())); else if(ui->comboQuote->currentText().length()) value = ui->comboQuote->currentText(); return value.size() ? value.at(0) : QChar(); } void ImportCsvDialog::setSeparatorChar(QChar c) { QComboBox* combo = ui->comboSeparator; QString sText = c == '\t' ? QString("Tab") : QString(c); int index = combo->findText(sText); ui->spinBoxSeparator->setValue(c.unicode()); if(index == -1) { if(c.isPrint()) { combo->setCurrentIndex(combo->count() - OtherPrintable); ui->editCustomSeparator->setText(QString(c)); } else { combo->setCurrentIndex(combo->count() - OtherCode); } } else { combo->setCurrentIndex(index); } } QChar ImportCsvDialog::currentSeparatorChar() const { QString value; // The last options in the combobox are the 'Other (*)' items; // if one of them is selected return the text or code of the corresponding field instead if(ui->comboSeparator->currentIndex() == ui->comboSeparator->count() - OtherPrintable) value = ui->editCustomSeparator->text().length() ? ui->editCustomSeparator->text() : ""; else if(ui->comboSeparator->currentIndex() == ui->comboSeparator->count() - OtherCode) value = QString(QChar(ui->spinBoxSeparator->value())); else value = ui->comboSeparator->currentText() == tr("Tab") ? "\t" : ui->comboSeparator->currentText(); return value.size() ? value.at(0) : QChar(); } void ImportCsvDialog::setEncoding(const QString& sEnc) { QComboBox* combo = ui->comboEncoding; int index = combo->findText(sEnc); if(index == -1) { combo->setCurrentIndex(combo->count() - 1); ui->editCustomEncoding->setText(sEnc); } else { combo->setCurrentIndex(index); } } QString ImportCsvDialog::currentEncoding() const { // The last item in the combobox is the 'Other' item; if it is selected return the text of the line edit field instead if(ui->comboEncoding->currentIndex() == ui->comboEncoding->count()-1) return ui->editCustomEncoding->text().length() ? ui->editCustomEncoding->text() : "UTF-8"; else return ui->comboEncoding->currentText(); } std::string ImportCsvDialog::currentOnConflictStrategy() const { switch(ui->comboOnConflictStrategy->currentIndex()) { case 1: return "OR IGNORE"; case 2: return "OR REPLACE"; default: return {}; } } void ImportCsvDialog::toggleAdvancedSection(bool show) { ui->labelNoTypeDetection->setVisible(show); ui->checkNoTypeDetection->setVisible(show); ui->labelLocalConventions->setVisible(show); ui->checkLocalConventions->setVisible(show); ui->labelFailOnMissing->setVisible(show); ui->checkFailOnMissing->setVisible(show); ui->labelIgnoreDefaults->setVisible(show); ui->checkIgnoreDefaults->setVisible(show); ui->labelOnConflictStrategy->setVisible(show); ui->comboOnConflictStrategy->setVisible(show); } char32_t ImportCsvDialog::toUtf8(const QString& s) const { if(s.isEmpty()) return 0; QByteArray ba = s.toUtf8(); char32_t result = 0; for(int i=std::min(ba.size()-1,3);i>=0;i--) result = (result << 8) + static_cast(ba.at(i)); return result; } sqlitebrowser-sqlitebrowser-5733cb7/src/ImportCsvDialog.h000066400000000000000000000033131463772530400237020ustar00rootroot00000000000000#ifndef IMPORTCSVDIALOG_H #define IMPORTCSVDIALOG_H #include "csvparser.h" #include "sql/sqlitetypes.h" #include #include class DBBrowserDB; class QCompleter; namespace Ui { class ImportCsvDialog; } class ImportCsvDialog : public QDialog { Q_OBJECT public: explicit ImportCsvDialog(const std::vector& filenames, DBBrowserDB* db, QWidget* parent = nullptr, const QString& table = QString()); ~ImportCsvDialog() override; private slots: void accept() override; void updatePreview(); void checkInput(); void selectFiles(); void updateSelectedFilePreview(); void updateSelection(bool); void matchSimilar(); void toggleAdvancedSection(bool show); private: // Positions for combos starting at the bottom enum {OtherCode = 1, OtherPrintable = 2}; Ui::ImportCsvDialog* ui; std::vector csvFilenames; QString selectedFile; DBBrowserDB* pdb; QCompleter* encodingCompleter; QStringList dontAskForExistingTableAgain; CSVParser::ParserResult parseCSV(const QString& fileName, std::function rowFunction, size_t count = 0) const; sqlb::FieldVector generateFieldList(const QString& filename) const; bool importCsv(const QString& f, const QString& n = QString()); void setQuoteChar(QChar c); QChar currentQuoteChar() const; void setSeparatorChar(QChar c); QChar currentSeparatorChar() const; void setEncoding(const QString& sEnc); QString currentEncoding() const; std::string currentOnConflictStrategy() const; char32_t toUtf8(const QString& s) const; static QChar getSettingsChar(const std::string& group, const std::string& name); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/ImportCsvDialog.ui000066400000000000000000000524301463772530400240740ustar00rootroot00000000000000 ImportCsvDialog 0 0 788 717 Import CSV file QFormLayout::ExpandingFieldsGrow Table na&me editName &Column names in first line checkboxHeader Field &separator comboSeparator , ; Tab | Other (printable) Other (code) 1 1114112 Qt::Horizontal 40 20 &Quote character comboQuote " ' Other (printable) Other (code) 1 1114112 Qt::Horizontal 40 20 &Encoding comboEncoding UTF-8 UTF-16 ISO-8859-1 Other Qt::Horizontal 40 20 Trim fields? checkBoxTrimFields true Separate tables checkBoxSeparateTables Advanced :/icons/down:/icons/down true When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Ignore default &values checkIgnoreDefaults Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Fail on missing values checkFailOnMissing Disable data type detection checkNoTypeDetection Disable the automatic data type detection when creating a new table. Use local number conventions checkLocalConventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Abort import Ignore row Replace existing row Conflict strategy comboOnConflictStrategy Qt::Vertical false true 0 0 0 0 7 QLayout::SetDefaultConstraint 0 Deselect All true true false Match Similar Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok editName checkboxHeader comboSeparator editCustomSeparator comboQuote editCustomQuote comboEncoding editCustomEncoding checkBoxTrimFields checkBoxSeparateTables buttonAdvanced checkIgnoreDefaults checkNoTypeDetection checkLocalConventions checkFailOnMissing comboOnConflictStrategy filePicker toggleSelected matchSimilar tablePreview comboSeparator currentIndexChanged(int) ImportCsvDialog updatePreview() 245 92 445 64 editName textChanged(QString) ImportCsvDialog checkInput() 609 13 631 45 editCustomSeparator textChanged(QString) ImportCsvDialog updatePreview() 511 92 577 76 editCustomQuote textChanged(QString) ImportCsvDialog updatePreview() 511 126 530 90 editCustomEncoding textChanged(QString) ImportCsvDialog updatePreview() 524 160 540 133 checkBoxTrimFields toggled(bool) ImportCsvDialog updatePreview() 192 182 368 244 comboEncoding currentIndexChanged(int) ImportCsvDialog updatePreview() 271 160 572 121 checkboxHeader toggled(bool) ImportCsvDialog updatePreview() 192 56 354 45 toggleSelected toggled(bool) ImportCsvDialog updateSelection(bool) 777 385 368 244 comboQuote currentIndexChanged(int) ImportCsvDialog updatePreview() 245 126 350 88 buttonBox accepted() ImportCsvDialog accept() 281 707 157 274 buttonBox rejected() ImportCsvDialog reject() 349 707 286 274 checkBoxSeparateTables toggled(bool) ImportCsvDialog checkInput() 192 206 368 244 matchSimilar pressed() ImportCsvDialog matchSimilar() 777 418 368 244 buttonAdvanced toggled(bool) ImportCsvDialog toggleAdvancedSection(bool) 265 241 393 358 spinBoxQuote valueChanged(int) ImportCsvDialog updatePreview() 529 111 393 358 spinBoxSeparator valueChanged(int) ImportCsvDialog updatePreview() 529 77 393 358 updatePreview() checkInput() updateSelection(bool) matchSimilar() toggleAdvancedSection(bool) sqlitebrowser-sqlitebrowser-5733cb7/src/MainWindow.cpp000066400000000000000000005230071463772530400232520ustar00rootroot00000000000000#include "MainWindow.h" #include "ui_MainWindow.h" #include "Application.h" #include "EditIndexDialog.h" #include "AboutDialog.h" #include "EditTableDialog.h" #include "ImportCsvDialog.h" #include "ExportDataDialog.h" #include "Settings.h" #include "PreferencesDialog.h" #include "EditDialog.h" #include "sqlitetablemodel.h" #include "SqlExecutionArea.h" #include "VacuumDialog.h" #include "DbStructureModel.h" #include "version.h" #include "sqlite.h" #include "CipherDialog.h" #include "ExportSqlDialog.h" #include "SqlUiLexer.h" #include "FileDialog.h" #include "RemoteDock.h" #include "FindReplaceDialog.h" #include "RunSql.h" #include "ExtendedTableWidget.h" #include "Data.h" #include "TableBrowser.h" #include "TableBrowserDock.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_MACX //Needed only on macOS #include #endif #include int MainWindow::MaxRecentFiles; MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow), db(), editDock(new EditDialog(this)), plotDock(new PlotDock(this)), remoteDock(new RemoteDock(this)), currentTableBrowser(nullptr), findReplaceDialog(new FindReplaceDialog(this)), execute_sql_worker(nullptr), isProjectModified(false) { ui->setupUi(this); init(); activateFields(false); updateRecentFileActions(); if (Settings::getValue("General", "autoLoadLastDBFileAtStartup").toBool()) recentFileActs[0]->trigger(); } MainWindow::~MainWindow() { delete dbSelected; delete dockDbSelected; delete ui; } void MainWindow::init() { // Load window settings tabifyDockWidget(ui->dockLog, ui->dockPlot); tabifyDockWidget(ui->dockLog, ui->dockSchema); tabifyDockWidget(ui->dockLog, ui->dockRemote); #ifdef Q_OS_MACX // Add OpenGL Context for macOS QOpenGLWidget *ogl = new QOpenGLWidget(this); ui->verticalLayout->addWidget(ogl); ogl->setHidden(true); #endif // Automatic update check #ifdef CHECKNEWVERSION // Check for a new version if automatic update check aren't disabled in the settings dialog if(Settings::getValue("checkversion", "enabled").toBool()) { RemoteNetwork::get().fetch(QUrl("https://download.sqlitebrowser.org/currentrelease"), RemoteNetwork::RequestTypeCustom, QString(), [this](const QByteArray& reply) { QList info = reply.split('\n'); if(info.size() >= 2) { QString version = info.at(0).trimmed(); QString url = info.at(1).trimmed(); checkNewVersion(version, url); } }, false, true); } #endif // create facade objects to dbTreeWidgets dbSelected = new DbStructureQItemViewFacade(*ui->dbTreeWidget); dockDbSelected = new DbStructureQItemViewFacade(*ui->treeSchemaDock); // Connect SQL logging and database state setting to main window connect(&db, &DBBrowserDB::dbChanged, this, &MainWindow::dbState, Qt::QueuedConnection); connect(&db, &DBBrowserDB::sqlExecuted, this, &MainWindow::logSql, Qt::QueuedConnection); connect(&db, &DBBrowserDB::requestCollation, this, &MainWindow::requestCollation); // Set up DB structure tab dbStructureModel = new DbStructureModel(db, this); connect(&db, &DBBrowserDB::structureUpdated, this, [this]() { std::vector old_tables; for(const auto& d : allTableBrowserDocks()) old_tables.push_back(d->tableBrowser()->currentlyBrowsedTableName()); dbStructureModel->reloadData(); populateStructure(old_tables); }); ui->dbTreeWidget->setModel(dbStructureModel); ui->dbTreeWidget->setColumnWidth(DbStructureModel::ColumnName, 300); ui->dbTreeWidget->setColumnHidden(DbStructureModel::ColumnObjectType, true); ui->dbTreeWidget->setColumnHidden(DbStructureModel::ColumnSchema, true); // Set up DB schema dock ui->treeSchemaDock->setModel(dbStructureModel); ui->treeSchemaDock->setColumnHidden(DbStructureModel::ColumnObjectType, true); ui->treeSchemaDock->setColumnHidden(DbStructureModel::ColumnSchema, true); // Create initial table browser tab ui->tabBrowsers->setWindowFlags(Qt::Widget); ui->tabBrowsers->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); newTableBrowserTab(); // Create docks ui->dockEdit->setWidget(editDock); ui->dockPlot->setWidget(plotDock); ui->dockRemote->setWidget(remoteDock); // Set up edit dock editDock->setReadOnly(true); // Restore window geometry restoreGeometry(Settings::getValue("MainWindow", "geometry").toByteArray()); // Save default and restore window state defaultWindowState = saveState(); restoreState(Settings::getValue("MainWindow", "windowState").toByteArray()); // Save default and restore open tab order if the openTabs setting is saved. defaultOpenTabs = saveOpenTabs(); restoreOpenTabs(Settings::getValue("MainWindow", "openTabs").toString()); // Restore dock state settings ui->comboLogSubmittedBy->setCurrentIndex(ui->comboLogSubmittedBy->findText(Settings::getValue("SQLLogDock", "Log").toString())); // Add keyboard shortcuts QShortcut* shortcutBrowseRefreshF5 = new QShortcut(QKeySequence("F5"), this); connect(shortcutBrowseRefreshF5, &QShortcut::activated, this, &MainWindow::refresh); QShortcut* shortcutBrowseRefreshCtrlR = new QShortcut(QKeySequence("Ctrl+R"), this); connect(shortcutBrowseRefreshCtrlR, &QShortcut::activated, this, &MainWindow::refresh); QShortcut* shortcutBrowseRefreshCtrlEnter = new QShortcut(QKeySequence("Ctrl+Enter"), this); connect(shortcutBrowseRefreshCtrlEnter, &QShortcut::activated, this, &MainWindow::refresh); // Add print shortcut for the DB Structure tab (dbTreeWidget) with context to the widget, so other print shortcuts aren't eclipsed. QShortcut* shortcutPrint = new QShortcut(QKeySequence(QKeySequence::Print), ui->dbTreeWidget, nullptr, nullptr, Qt::WidgetShortcut); connect(shortcutPrint, &QShortcut::activated, this, &MainWindow::printDbStructure); QShortcut* closeTabShortcut = new QShortcut(tr("Ctrl+W"), ui->tabSqlAreas, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); connect(closeTabShortcut, &QShortcut::activated, this, [this]() { if(ui->tabSqlAreas->currentIndex() >= 0) closeSqlTab(ui->tabSqlAreas->currentIndex()); }); // Shortcuts for advancing and going back in the SQL Execution area tabs, independently of the widget which has focus. // This emulates the shortcuts provided by QTabWidget. QShortcut* shortcutNextTab = new QShortcut(QKeySequence(tr("Ctrl+Tab")), ui->tabSqlAreas, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); connect(shortcutNextTab, &QShortcut::activated, this, [this]() { if(ui->tabSqlAreas->currentIndex() == ui->tabSqlAreas->count() - 1) ui->tabSqlAreas->setCurrentIndex(0); else ui->tabSqlAreas->setCurrentIndex(ui->tabSqlAreas->currentIndex() + 1); focusSqlEditor(); }); QShortcut* shortcutPreviousTab = new QShortcut(QKeySequence(tr("Ctrl+Shift+Tab")), ui->tabSqlAreas, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); connect(shortcutPreviousTab, &QShortcut::activated, this, [this]() { if(ui->tabSqlAreas->currentIndex() == 0) ui->tabSqlAreas->setCurrentIndex(ui->tabSqlAreas->count() - 1); else ui->tabSqlAreas->setCurrentIndex(ui->tabSqlAreas->currentIndex() - 1); focusSqlEditor(); }); // Get MaxRecentFiles value from QSettings. MaxRecentFiles = Settings::getValue("General", "maxRecentFiles").toInt(); recentFileActs.resize(MaxRecentFiles); // Create the actions for the recently opened dbs list for(int i = 0; i < MaxRecentFiles; ++i) { recentFileActs[i] = new QAction(this); recentFileActs[i]->setVisible(false); connect(recentFileActs[i], &QAction::triggered, this, &MainWindow::openRecentFile); } for(int i = 0; i < MaxRecentFiles; ++i) ui->fileRecentFiles->insertAction(ui->fileExitAction, recentFileActs[i]); recentSeparatorAct = ui->fileRecentFiles->insertSeparator(ui->fileExitAction); optionToAutoLoadLastDBFileAtStartup = ui->fileRecentFiles->addAction(tr("Automatically load the last opened DB file at startup")); optionToAutoLoadLastDBFileAtStartup->setCheckable(true); optionToAutoLoadLastDBFileAtStartup->setChecked(Settings::getValue("General", "autoLoadLastDBFileAtStartup").toBool()); clearRecentFilesAction = ui->fileRecentFiles->addAction(tr("Clear List")); ui->fileRecentFiles->insertAction(ui->fileExitAction, clearRecentFilesAction); connect(optionToAutoLoadLastDBFileAtStartup, &QAction::triggered, this, &MainWindow::toggleAutoLoadLastDBFileAtStartupOption); connect(clearRecentFilesAction, &QAction::triggered, this, &MainWindow::clearRecentFiles); // Create popup menus popupTableMenu = new QMenu(this); popupTableMenu->addAction(ui->actionEditBrowseTable); popupTableMenu->addAction(ui->editModifyObjectAction); popupTableMenu->addAction(ui->editDeleteObjectAction); popupTableMenu->addAction(ui->fileDetachAction); popupTableMenu->addSeparator(); popupTableMenu->addAction(ui->actionEditCopyCreateStatement); popupTableMenu->addAction(ui->actionExportCsvPopup); popupSchemaDockMenu = new QMenu(this); popupSchemaDockMenu->addAction(ui->actionPopupSchemaDockBrowseTable); popupSchemaDockMenu->addAction(ui->actionPopupSchemaDockDetachDatabase); popupSchemaDockMenu->addSeparator(); popupSchemaDockMenu->addAction(ui->actionDropSelectQueryCheck); popupSchemaDockMenu->addAction(ui->actionDropQualifiedCheck); popupSchemaDockMenu->addAction(ui->actionEnquoteNamesCheck); popupOpenDbMenu = new QMenu(this); popupOpenDbMenu->addAction(ui->fileOpenAction); popupOpenDbMenu->addAction(ui->fileOpenReadOnlyAction); ui->fileOpenActionPopup->setMenu(popupOpenDbMenu); popupSaveSqlFileMenu = new QMenu(this); popupSaveSqlFileMenu->addAction(ui->actionSqlSaveFile); popupSaveSqlFileMenu->addAction(ui->actionSqlSaveFileAs); ui->actionSqlSaveFilePopup->setMenu(popupSaveSqlFileMenu); popupSaveSqlResultsMenu = new QMenu(this); popupSaveSqlResultsMenu->addAction(ui->actionSqlResultsExportCsv); popupSaveSqlResultsMenu->addAction(ui->actionSqlResultsExportJson); popupSaveSqlResultsMenu->addAction(ui->actionSqlResultsSaveAsView); ui->actionSqlResultsSave->setMenu(popupSaveSqlResultsMenu); qobject_cast(ui->toolbarSql->widgetForAction(ui->actionSqlResultsSave))->setPopupMode(QToolButton::InstantPopup); // Add menu item for log dock ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockLog->toggleViewAction()); ui->viewMenu->actions().at(0)->setShortcut(QKeySequence(tr("Ctrl+L"))); ui->viewMenu->actions().at(0)->setIcon(QIcon(":/icons/log_dock")); // Add menu item for plot dock ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockPlot->toggleViewAction()); ui->viewMenu->actions().at(1)->setShortcut(QKeySequence(tr("Ctrl+D"))); ui->viewMenu->actions().at(1)->setIcon(QIcon(":/icons/log_dock")); // Add menu item for schema dock ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockSchema->toggleViewAction()); ui->viewMenu->actions().at(2)->setShortcut(QKeySequence(tr("Ctrl+I"))); ui->viewMenu->actions().at(2)->setIcon(QIcon(":/icons/log_dock")); // Add menu item for edit dock ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockEdit->toggleViewAction()); ui->viewMenu->actions().at(3)->setShortcut(QKeySequence(tr("Ctrl+E"))); ui->viewMenu->actions().at(3)->setIcon(QIcon(":/icons/log_dock")); // Add menu item for plot dock ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockRemote->toggleViewAction()); ui->viewMenu->actions().at(4)->setIcon(QIcon(":/icons/log_dock")); // Set checked state if toolbar is visible ui->viewDBToolbarAction->setChecked(!ui->toolbarDB->isHidden()); ui->viewExtraDBToolbarAction->setChecked(!ui->toolbarExtraDB->isHidden()); ui->viewProjectToolbarAction->setChecked(!ui->toolbarProject->isHidden()); // Add separator between docks and toolbars ui->viewMenu->insertSeparator(ui->viewDBToolbarAction); // Connect the tabCloseRequested to the actual closeTab function. // This must be done before the connections for checking the actions in the View menu so // they are updated accordingly. connect(ui->mainTab, &QTabWidget::tabCloseRequested, this, &MainWindow::closeTab); // Add entries for toggling the visibility of main tabs for (QWidget* widget : {ui->structure, ui->browser, ui->pragmas, ui->query}) { QAction* action = ui->viewMenu->addAction(QIcon(":/icons/open_sql"), widget->accessibleName()); action->setObjectName(widget->accessibleName()); action->setCheckable(true); action->setChecked(ui->mainTab->indexOf(widget) != -1); connect(action, &QAction::toggled, this, [=](bool show) { toggleTabVisible(widget, show); }); // Connect tabCloseRequested for setting checked the appropriate menu entry. // Note these are called after the actual tab is closed only because they are connected // after connecting closeTab. connect(ui->mainTab, &QTabWidget::tabCloseRequested, this, [=](int /*index*/) { action->setChecked(ui->mainTab->indexOf(widget) != -1); }); } ui->viewMenu->addSeparator(); QMenu* layoutMenu = new QMenu(tr("Window Layout"), this); ui->viewMenu->addMenu(layoutMenu); QAction* resetLayoutAction = layoutMenu->addAction(tr("Reset Window Layout")); resetLayoutAction->setShortcut(QKeySequence(tr("Ctrl+Alt+0"))); connect(resetLayoutAction, &QAction::triggered, this, [=]() { restoreState(defaultWindowState); restoreOpenTabs(defaultOpenTabs); ui->viewDBToolbarAction->setChecked(!ui->toolbarDB->isHidden()); ui->viewExtraDBToolbarAction->setChecked(!ui->toolbarExtraDB->isHidden()); ui->viewProjectToolbarAction->setChecked(!ui->toolbarProject->isHidden()); }); QAction* simplifyLayoutAction = layoutMenu->addAction(tr("Simplify Window Layout")); simplifyLayoutAction->setShortcut(QKeySequence(tr("Alt+Shift+0"))); connect(simplifyLayoutAction, &QAction::triggered, this, [=]() { ui->viewMenu->findChild(ui->pragmas->accessibleName())->activate(QAction::Trigger); ui->dockLog->hide(); ui->dockPlot->hide(); ui->dockSchema->hide(); ui->dockEdit->hide(); ui->dockRemote->hide(); }); QAction* atBottomLayoutAction = layoutMenu->addAction(tr("Dock Windows at Bottom")); connect(atBottomLayoutAction, &QAction::triggered, this, [=]() { moveDocksTo(Qt::BottomDockWidgetArea); }); QAction* atLeftLayoutAction = layoutMenu->addAction(tr("Dock Windows at Left Side")); connect(atLeftLayoutAction, &QAction::triggered, this, [=]() { moveDocksTo(Qt::LeftDockWidgetArea); }); QAction* atTopLayoutAction = layoutMenu->addAction(tr("Dock Windows at Top")); connect(atTopLayoutAction, &QAction::triggered, this, [=]() { moveDocksTo(Qt::TopDockWidgetArea); }); // If we're not compiling in SQLCipher, hide its FAQ link in the help menu #ifndef ENABLE_SQLCIPHER ui->actionSqlCipherFaq->setVisible(false); #endif // Set statusbar fields statusBusyLabel = new QLabel(ui->statusbar); statusBusyLabel->setEnabled(false); statusBusyLabel->setVisible(false); statusBusyLabel->setToolTip(tr("The database is currently busy.")); ui->statusbar->addPermanentWidget(statusBusyLabel); statusStopButton = new QToolButton(ui->statusbar); statusStopButton->setVisible(false); statusStopButton->setIcon(QIcon(":icons/cancel")); statusStopButton->setToolTip(tr("Click here to interrupt the currently running query.")); statusStopButton->setMaximumSize(ui->statusbar->geometry().height() - 6, ui->statusbar->geometry().height() - 6); statusStopButton->setAutoRaise(true); ui->statusbar->addPermanentWidget(statusStopButton); statusEncryptionLabel = new QLabel(ui->statusbar); statusEncryptionLabel->setEnabled(false); statusEncryptionLabel->setVisible(false); statusEncryptionLabel->setText(tr("Encrypted")); statusEncryptionLabel->setToolTip(tr("Database is encrypted using SQLCipher")); ui->statusbar->addPermanentWidget(statusEncryptionLabel); statusReadOnlyLabel = new QLabel(ui->statusbar); statusReadOnlyLabel->setEnabled(false); statusReadOnlyLabel->setVisible(false); statusReadOnlyLabel->setText(tr("Read only")); statusReadOnlyLabel->setToolTip(tr("Database file is read only. Editing the database is disabled.")); ui->statusbar->addPermanentWidget(statusReadOnlyLabel); statusEncodingLabel = new QLabel(ui->statusbar); statusEncodingLabel->setEnabled(false); statusEncodingLabel->setText("UTF-8"); statusEncodingLabel->setToolTip(tr("Database encoding")); ui->statusbar->addPermanentWidget(statusEncodingLabel); // When changing the text of the toolbar actions, also automatically change their icon text and their tooltip text connect(ui->editModifyObjectAction, &QAction::changed, this, [=]() { ui->editModifyObjectAction->setIconText(ui->editModifyObjectAction->text()); ui->editModifyObjectAction->setToolTip(ui->editModifyObjectAction->text()); }); connect(ui->editDeleteObjectAction, &QAction::changed, this, [=]() { ui->editDeleteObjectAction->setIconText(ui->editDeleteObjectAction->text()); ui->editDeleteObjectAction->setToolTip(ui->editDeleteObjectAction->text()); }); // When clicking the interrupt query button in the status bar, ask SQLite to interrupt the current query connect(statusStopButton, &QToolButton::clicked, this, [this]() { db.interruptQuery(); }); // Connect some more signals and slots connect(editDock, &EditDialog::recordTextUpdated, this, &MainWindow::updateRecordText); connect(editDock, &EditDialog::evaluateText, this, &MainWindow::evaluateText); connect(editDock, &EditDialog::requestUrlOrFileOpen, this, &MainWindow::openUrlOrFile); connect(ui->dbTreeWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::changeTreeSelection); connect(ui->dockEdit, &QDockWidget::visibilityChanged, this, &MainWindow::toggleEditDock); connect(remoteDock, SIGNAL(openFile(QString)), this, SLOT(fileOpen(QString))); connect(ui->actionDropSelectQueryCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropSelectQuery); connect(ui->actionDropQualifiedCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropQualifiedNames); connect(ui->actionEnquoteNamesCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropEnquotedNames); connect(&db, &DBBrowserDB::databaseInUseChanged, this, &MainWindow::updateDatabaseBusyStatus); ui->actionDropSelectQueryCheck->setChecked(Settings::getValue("SchemaDock", "dropSelectQuery").toBool()); ui->actionDropQualifiedCheck->setChecked(Settings::getValue("SchemaDock", "dropQualifiedNames").toBool()); ui->actionEnquoteNamesCheck->setChecked(Settings::getValue("SchemaDock", "dropEnquotedNames").toBool()); connect(ui->actionSqlStop, &QAction::triggered, this, [this]() { if(execute_sql_worker && execute_sql_worker->isRunning()) execute_sql_worker->stop(); }); // Connect tool pragmas connect(ui->actionIntegrityCheck, &QAction::triggered, this, [this]() { runSqlNewTab("PRAGMA integrity_check;", ui->actionIntegrityCheck->text(), "https://www.sqlite.org/pragma.html#pragma_integrity_check"); }); connect(ui->actionQuickCheck, &QAction::triggered, this, [this]() { runSqlNewTab("PRAGMA quick_check;", ui->actionQuickCheck->text(), "https://www.sqlite.org/pragma.html#pragma_quick_check"); }); connect(ui->actionForeignKeyCheck, &QAction::triggered, this, [this]() { runSqlNewTab("PRAGMA foreign_key_check;", ui->actionForeignKeyCheck->text(), "https://www.sqlite.org/pragma.html#pragma_foreign_key_check"); }); connect(ui->actionOptimize, &QAction::triggered, this, [this]() { runSqlNewTab("PRAGMA optimize;", ui->actionOptimize->text(), "https://www.sqlite.org/pragma.html#pragma_optimize"); }); // Action for switching the table via the Database Structure tab connect(ui->actionPopupSchemaDockBrowseTable, &QAction::triggered, this, [this]() { switchToBrowseDataTab(dockDbSelected->object()); refresh(); // Required in case the Browse Data tab already was the active main tab }); // Set other window settings setAcceptDrops(true); setWindowTitle(QApplication::applicationName()); // Add the documentation of shortcuts, which aren't otherwise visible in the user interface, to some buttons. addShortcutsTooltip(ui->actionDbPrint); addShortcutsTooltip(ui->actionSqlOpenTab); addShortcutsTooltip(ui->actionSqlOpenFile); addShortcutsTooltip(ui->actionSqlPrint); addShortcutsTooltip(ui->actionExecuteSql, {shortcutBrowseRefreshF5->key(), shortcutBrowseRefreshCtrlR->key()}); addShortcutsTooltip(ui->actionSqlExecuteLine); addShortcutsTooltip(ui->actionSqlFind); addShortcutsTooltip(ui->actionSqlFindReplace); addShortcutsTooltip(ui->actionSqlToggleComment); // Since in some keyboards pressing F keys is cumbersome, add an alternate shortcut and document // it in the toolbar. ui->fileCloseAction->setShortcuts({QKeySequence(tr("Ctrl+F4")), QKeySequence(tr("Ctrl+Alt+W"))}); ui->actionCloseProject->setShortcuts({QKeySequence(tr("Ctrl+Shift+W")), QKeySequence(tr("Ctrl+Shift+F4"))}); addShortcutsTooltip(ui->fileCloseAction); // Load all settings reloadSettings(); #ifndef ENABLE_SQLCIPHER // Only show encryption menu action when SQLCipher support is enabled ui->actionEncryption->setVisible(false); #endif /* Remove all the '&' signs from the dock titles. On at least Windows and * OSX, Qt doesn't seem to support them properly, so they end up being * visible instead of creating a keyboard shortcut */ ui->dockEdit->setWindowTitle(ui->dockEdit->windowTitle().remove('&')); ui->dockLog->setWindowTitle(ui->dockLog->windowTitle().remove('&')); ui->dockPlot->setWindowTitle(ui->dockPlot->windowTitle().remove('&')); ui->dockSchema->setWindowTitle(ui->dockSchema->windowTitle().remove('&')); ui->dockRemote->setWindowTitle(ui->dockRemote->windowTitle().remove('&')); } bool MainWindow::fileOpen(const QString& fileName, bool openFromProject, bool readOnly) { bool retval = false; QString wFile = fileName; // QFile::exist will produce error message if passed empty string. // Test string length before usage w/ QFile to silence warning if (wFile.isEmpty() || !QFile::exists(wFile)) { wFile = FileDialog::getOpenFileName( OpenDatabaseFile, this, tr("Choose a database file") #ifndef Q_OS_MAC // Filters on OS X are buggy , FileDialog::getSqlDatabaseFileFilter() #endif ); } // catch situation where user has canceled file selection from dialog if(!wFile.isEmpty() && QFile::exists(wFile) ) { // Try opening it as a project file first. If confirmed, this will include closing current // database and project files. switch (loadProject(wFile, readOnly)) { case Success: return true; case Aborted: return false; case NotValidFormat: // It's not a project. Continue trying to open the file as CSV or DB. break; } if(isTextOnlyFile(wFile)) { // If it's a text file, cannot be an SQLite/SQLCipher database, // so try to import it as CSV. importCSVfiles({wFile}); } else { // Close the database. If the user didn't want to close it, though, stop here if (db.isOpen()) if(!fileClose()) return false; // No project file; so it should be a database file if(db.open(wFile, readOnly)) { // Close all open but empty SQL tabs for(int i=ui->tabSqlAreas->count()-1;i>=0;i--) { if(qobject_cast(ui->tabSqlAreas->widget(i))->getSql().trimmed().isEmpty()) closeSqlTab(i, true); } statusEncodingLabel->setText(db.getPragma("encoding")); statusEncryptionLabel->setVisible(db.encrypted()); statusReadOnlyLabel->setVisible(db.readOnly()); setCurrentFile(wFile); if(!openFromProject) { addToRecentFilesMenu(wFile, readOnly); // When a new DB file has been open while a project is open, set the project modified. if(!currentProjectFilename.isEmpty()) isProjectModified = true; } if(ui->tabSqlAreas->count() == 0) openSqlTab(true); else if(ui->mainTab->currentWidget() == ui->pragmas) loadPragmas(); refreshTableBrowsers(); // Update remote dock remoteDock->fileOpened(wFile); retval = true; } else { QMessageBox::warning(this, qApp->applicationName(), tr("Could not open database file.\nReason: %1").arg(db.lastError())); retval = false; } } } return retval; } void MainWindow::fileNew() { QString fileName = FileDialog::getSaveFileName( CreateDatabaseFile, this, tr("Choose a filename to save under"), FileDialog::getSqlDatabaseFileFilter()); if(!fileName.isEmpty()) { if(QFile::exists(fileName)) QFile::remove(fileName); db.create(fileName); setCurrentFile(fileName); addToRecentFilesMenu(fileName); statusEncodingLabel->setText(db.getPragma("encoding")); statusEncryptionLabel->setVisible(false); statusReadOnlyLabel->setVisible(false); refreshTableBrowsers(); if(ui->tabSqlAreas->count() == 0) openSqlTab(true); createTable(); } } void MainWindow::fileNewInMemoryDatabase(bool open_create_dialog) { // Open an in-memory database. We use open() instead of create() here because the extra work create() does is not needed // when no files are stored on disk. db.open(":memory:"); setCurrentFile(tr("In-Memory database")); statusEncodingLabel->setText(db.getPragma("encoding")); statusEncryptionLabel->setVisible(false); statusReadOnlyLabel->setVisible(false); remoteDock->fileOpened(":memory:"); refreshTableBrowsers(); if(ui->tabSqlAreas->count() == 0) openSqlTab(true); if(open_create_dialog) createTable(); } void MainWindow::populateStructure(const std::vector& old_tables) { // Refresh the structure tab ui->dbTreeWidget->setRootIndex(dbStructureModel->index(1, 0)); // Show the 'All' part of the db structure ui->dbTreeWidget->expandToDepth(0); ui->treeSchemaDock->setRootIndex(dbStructureModel->index(1, 0)); // Show the 'All' part of the db structure ui->treeSchemaDock->expandToDepth(0); // Refresh the browse data tabs const auto all_table_browsers = allTableBrowserDocks(); for(int i=0;i(old_tables.size());i++) all_table_browsers.at(i)->tableBrowser()->setStructure(dbStructureModel, old_tables.at(static_cast(i))); // Cancel here if no database is opened if(!db.isOpen()) return; // Update table and column names for syntax highlighting SqlUiLexer::QualifiedTablesMap qualifiedTablesMap; for(const auto& it : db.schemata) { SqlUiLexer::TablesAndColumnsMap tablesToColumnsMap; for(const auto& jt : it.second.tables) { QString objectname = QString::fromStdString(jt.first); for(const auto& f : jt.second->fields) tablesToColumnsMap[objectname].push_back(QString::fromStdString(f.name())); } qualifiedTablesMap[QString::fromStdString(it.first)] = tablesToColumnsMap; } SqlTextEdit::sqlLexer->setTableNames(qualifiedTablesMap); ui->editLogApplication->reloadKeywords(); ui->editLogUser->reloadKeywords(); for(int i=0;itabSqlAreas->count();i++) qobject_cast(ui->tabSqlAreas->widget(i))->getEditor()->reloadKeywords(); // Resize SQL column to fit contents ui->dbTreeWidget->resizeColumnToContents(DbStructureModel::ColumnSQL); ui->treeSchemaDock->resizeColumnToContents(DbStructureModel::ColumnSQL); // Resize also the Name column in the Dock since it has usually // short content and there is little space there. ui->treeSchemaDock->resizeColumnToContents(DbStructureModel::ColumnName); } void MainWindow::refreshTableBrowsers(bool all) { QApplication::setOverrideCursor(Qt::WaitCursor); for(const auto& d : allTableBrowserDocks()) { // When in the Browse Data tab update all docks. Otherwise just update the floating ones because they might // be visible even when another tab is active. if(all || ui->mainTab->currentWidget() == ui->browser || d->isFloating()) { TableBrowser* t = d->tableBrowser(); if(t) t->refresh(); } } QApplication::restoreOverrideCursor(); } bool MainWindow::fileSaveAs() { QString fileName = FileDialog::getSaveFileName( OpenDatabaseFile, this, tr("Choose a database file to save under"), FileDialog::getSqlDatabaseFileFilter() ); // catch situation where user has canceled file selection from dialog if(!fileName.isEmpty()) { bool result = db.saveAs(fileName.toStdString()); if(result) { setCurrentFile(fileName); addToRecentFilesMenu(fileName); } else { QMessageBox::warning(this, QApplication::applicationName(), tr("Error while saving the database to the new file.")); } return result; } else { return false; } } bool MainWindow::fileClose() { // Stop any running SQL statements before closing the database if(execute_sql_worker && execute_sql_worker->isRunning()) { if(QMessageBox::warning(this, qApp->applicationName(), tr("You are still executing SQL statements. Closing the database now will stop their execution, possibly " "leaving the database in an inconsistent state. Are you sure you want to close the database?"), QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Cancel) return false; execute_sql_worker->stop(); execute_sql_worker->wait(); } // Close the database but stop the closing process here if the user pressed the cancel button in there if(!db.close()) return false; TableBrowser::resetSharedSettings(); setCurrentFile(QString()); loadPragmas(); statusEncryptionLabel->setVisible(false); statusReadOnlyLabel->setVisible(false); // Reset the table browser of the Browse Data tab. // We call delete here to avoid the closed() signal being emitted // which would open a new dock. for(auto d : allTableBrowserDocks()) delete d; newTableBrowserTab(); allTableBrowserDocks().at(0)->tableBrowser()->setEnabled(false); // Clear edit dock editDock->setCurrentIndex(QModelIndex()); // Clear the SQL Log ui->editLogApplication->clear(); ui->editLogUser->clear(); ui->editLogErrorLog->clear(); // Remove completion and highlighting for identifiers SqlTextEdit::sqlLexer->setTableNames(SqlUiLexer::QualifiedTablesMap()); for(int i=0; i < ui->tabSqlAreas->count(); i++) qobject_cast(ui->tabSqlAreas->widget(i))->getEditor()->reloadKeywords(); // Clear remote dock remoteDock->fileOpened(QString()); return true; } void MainWindow::closeEvent( QCloseEvent* event ) { if(closeFiles()) { Settings::setValue("MainWindow", "geometry", saveGeometry()); Settings::setValue("MainWindow", "windowState", saveState()); Settings::setValue("MainWindow", "openTabs", saveOpenTabs()); Settings::setValue("SQLLogDock", "Log", ui->comboLogSubmittedBy->currentText()); Settings::setValue("SchemaDock", "dropSelectQuery", ui->actionDropSelectQueryCheck->isChecked()); Settings::setValue("SchemaDock", "dropQualifiedNames", ui->actionDropQualifiedCheck->isChecked()); Settings::setValue("SchemaDock", "dropEnquotedNames", ui->actionEnquoteNamesCheck->isChecked()); SqlExecutionArea::saveState(); Settings::sync(); QMainWindow::closeEvent(event); } else { event->ignore(); } } bool MainWindow::closeFiles() { bool ignoreUnattachedBuffers = false; // Ask for saving all modified open SQL files in their files and all the unattached tabs in a project file. for(int i=0; itabSqlAreas->count(); i++) { // Ask for saving and comply with cancel answer. if(!askSaveSqlTab(i, ignoreUnattachedBuffers)) return false; } bool projectClosed = closeProject(); if (projectClosed) { // Now all tabs can be closed at once without asking user. // Close tabs in reverse order (so indexes are not changed in the process). for(int i=ui->tabSqlAreas->count()-1; i>=0; i--) closeSqlTab(i, /* force */ true, /* askSaving */ false); } return projectClosed; } bool MainWindow::closeProject() { if(!currentProjectFilename.isEmpty() && isProjectModified) { QMessageBox::StandardButton reply = QMessageBox::question (nullptr, QApplication::applicationName(), tr("Do you want to save the changes made to the project file '%1'?"). arg(QFileInfo(currentProjectFilename).fileName()), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); switch(reply) { case QMessageBox::Save: saveProject(); break; case QMessageBox::Cancel: return false; default: break; } } currentProjectFilename.clear(); return fileClose(); } void MainWindow::attachPlot(ExtendedTableWidget* tableWidget, SqliteTableModel* model, BrowseDataTableSettings* settings, bool keepOrResetSelection) { plotDock->updatePlot(model, settings, true, keepOrResetSelection); // Disconnect previous connection disconnect(plotDock, &PlotDock::pointsSelected, nullptr, nullptr); if(tableWidget) { // Connect plot selection to the current table results widget. connect(plotDock, &PlotDock::pointsSelected, tableWidget, &ExtendedTableWidget::selectTableLines); connect(tableWidget, &ExtendedTableWidget::destroyed, plotDock, &PlotDock::resetPlot); // Disconnect requestUrlOrFileOpen in order to make sure that there is only one connection. Otherwise we can open it several times. disconnect(tableWidget, &ExtendedTableWidget::requestUrlOrFileOpen, this, &MainWindow::openUrlOrFile); connect(tableWidget, &ExtendedTableWidget::requestUrlOrFileOpen, this, &MainWindow::openUrlOrFile); } } void MainWindow::refresh() { // What the Refresh function does depends on the currently active tab. This way the keyboard shortcuts (F5 and Ctrl+R) // always perform some meaningful task; they just happen to be context dependent in the function they trigger. QWidget* currentTab = ui->mainTab->currentWidget(); if (currentTab == ui->structure) { // Refresh the schema db.updateSchema(); } else if (currentTab == ui->browser) { // Refresh the schema and reload the current table refreshTableBrowsers(); } else if (currentTab == ui->pragmas) { // Reload pragma values loadPragmas(); } else if (currentTab == ui->query) { // (Re-)Run the current SQL query executeQuery(); } } void MainWindow::createTable() { EditTableDialog dialog(db, sqlb::ObjectIdentifier(), true, this); if(dialog.exec()) { refreshTableBrowsers(); } } void MainWindow::createIndex() { EditIndexDialog dialog(db, sqlb::ObjectIdentifier(), true, this); if(dialog.exec()) refreshTableBrowsers(); } void MainWindow::compact() { VacuumDialog dialog(&db, this); dialog.exec(); } void MainWindow::deleteObject() { // Get name and type of object to delete sqlb::ObjectIdentifier obj = dbSelected->object(); QString type = dbSelected->objectType(); // Due to different grammar in languages (e.g. gender or declension), each message must be given separately to translation. QString message; if (type == "table") message = tr("Are you sure you want to delete the table '%1'?\nAll data associated with the table will be lost."); else if (type == "view") message = tr("Are you sure you want to delete the view '%1'?"); else if (type == "trigger") message = tr("Are you sure you want to delete the trigger '%1'?"); else if (type == "index") message = tr("Are you sure you want to delete the index '%1'?"); // Ask user if he really wants to delete that table if(QMessageBox::warning(this, QApplication::applicationName(), message.arg(QString::fromStdString(obj.name())), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { // Delete the table QString statement = QString("DROP %1 %2;").arg(type.toUpper(), QString::fromStdString(obj.toString())); if(!db.executeSQL(statement.toStdString())) { if (type == "table") message = tr("Error: could not delete the table."); else if (type == "view") message = tr("Error: could not delete the view."); else if (type == "trigger") message = tr("Error: could not delete the trigger."); else if (type == "index") message = tr("Error: could not delete the index."); QString error = tr("Message from database engine:\n%1").arg(db.lastError()); QMessageBox::warning(this, QApplication::applicationName(), message + " " + error); } else { refreshTableBrowsers(); changeTreeSelection(); } } } void MainWindow::editObject() { if(!dbSelected->hasSelection()) return; // Get name and type of the object to edit sqlb::ObjectIdentifier obj = dbSelected->object(); QString type = dbSelected->objectType(); if(type == "table") { // For a safe and possibly complex table modification we must follow the steps documented in // https://www.sqlite.org/lang_altertable.html // Paragraph (first procedure): Making Other Kinds Of Table Schema Changes QString foreign_keys = db.getPragma("foreign_keys"); if (foreign_keys == "1") { if(db.getDirty() && QMessageBox::question(this, QApplication::applicationName(), tr("Editing the table requires to save all pending changes now.\nAre you sure you want to save the database?"), QMessageBox::Save | QMessageBox::Default, QMessageBox::Cancel | QMessageBox::Escape) != QMessageBox::Save) return; // Commit all changes so the foreign_keys can be effective. fileSave(); db.setPragma("foreign_keys", "0"); } EditTableDialog dialog(db, obj, false, this); bool ok = dialog.exec(); // If foreign_keys were enabled, we must commit or rollback the transaction so the foreign_keys pragma can be restored. if (foreign_keys == "1") { if (!db.querySingleValueFromDb("PRAGMA " + sqlb::escapeIdentifier(obj.schema()) + ".foreign_key_check").isNull()) { // Raise warning for accepted modification. When rejected, warn user also since we know now that the table has problems, // but it wasn't our fault. if (ok) QMessageBox::warning(this, QApplication::applicationName(), tr("Error checking foreign keys after table modification. The changes will be reverted.")); else QMessageBox::warning(this, QApplication::applicationName(), tr("This table did not pass a foreign-key check.
" "You should run 'Tools | Foreign-Key Check' and fix the reported issues.")); db.revertAll(); } else { // Commit all changes so the foreign_keys can be effective. fileSave(); } db.setPragma("foreign_keys", foreign_keys); } if(ok) { for(const auto& d : allTableBrowserDocks()) { if(d->tableBrowser()->currentlyBrowsedTableName() == obj) d->tableBrowser()->clearFilters(); } refreshTableBrowsers(); } } else if(type == "index") { EditIndexDialog dialog(db, obj, false, this); if(dialog.exec()) refreshTableBrowsers(); } else if(type == "view") { sqlb::TablePtr view = db.getTableByName(obj); runSqlNewTab(QString("DROP VIEW IF EXISTS %1;\n%2").arg(QString::fromStdString(obj.toString()), QString::fromStdString(view->sql())), tr("Edit View %1").arg(QString::fromStdString(obj.toDisplayString())), "https://www.sqlite.org/lang_createview.html", /* autoRun */ false); } else if(type == "trigger") { sqlb::TriggerPtr trigger = db.getTriggerByName(obj); runSqlNewTab(QString("DROP TRIGGER %1;\n%2").arg(QString::fromStdString(obj.toString()), QString::fromStdString(trigger->sql())), tr("Edit Trigger %1").arg(QString::fromStdString(obj.toDisplayString())), "https://www.sqlite.org/lang_createtrigger.html", /* autoRun */ false); } } void MainWindow::helpWhatsThis() { QWhatsThis::enterWhatsThisMode (); } void MainWindow::helpAbout() { AboutDialog dialog(this); dialog.exec(); } void MainWindow::updateRecordText(const QPersistentModelIndex& idx, const QByteArray& text, bool isBlob) { m_currentTabTableModel->setTypedData(idx, isBlob, text); } void MainWindow::evaluateText(const QPersistentModelIndex& idx, const std::string& text) { QByteArray value = db.querySingleValueFromDb("SELECT " + text, /* log */ true, DBBrowserDB::Wait); m_currentTabTableModel->setTypedData(idx, !isTextOnly(value), value); } void MainWindow::toggleEditDock(bool visible) { if (!visible) { // Update main window ui->tabBrowsers->setFocus(); } else { // fill edit dock with actual data, when the current index has changed while the dock was invisible. // (note that this signal is also emitted when the widget is docked or undocked, so we have to avoid // reloading data when the user is editing and (un)docks the editor). if (currentTableBrowser && editDock->currentIndex() != currentTableBrowser->currentIndex()) editDock->setCurrentIndex(currentTableBrowser->currentIndex()); } } void MainWindow::doubleClickTable(const QModelIndex& index) { // Cancel on invalid index if (!index.isValid()) { return; } // * Don't allow editing of other objects than tables and editable views bool isEditingAllowed = !db.readOnly() && currentTableBrowser && m_currentTabTableModel == currentTableBrowser->model() && currentTableBrowser->model()->isEditable(index); // Enable or disable the Apply, Null, & Import buttons in the Edit Cell // dock depending on the value of the "isEditingAllowed" bool above editDock->setReadOnly(!isEditingAllowed); editDock->setCurrentIndex(index); // Show the edit dock ui->dockEdit->setVisible(true); // Set focus on the edit dock editDock->setFocus(); } void MainWindow::dataTableSelectionChanged(const QModelIndex& index) { // Cancel on invalid index if(!index.isValid()) { editDock->setCurrentIndex(QModelIndex()); return; } TableBrowserDock* dock = qobject_cast(index.model()->parent()->parent()); if(dock) changeTableBrowserTab(dock); bool editingAllowed = !db.readOnly() && currentTableBrowser && m_currentTabTableModel == currentTableBrowser->model() && currentTableBrowser->model()->isEditable(index); // Don't allow editing of other objects than tables and editable views editDock->setReadOnly(!editingAllowed); // If the Edit Cell dock is visible, load the new value into it if (editDock->isVisible()) { editDock->setCurrentIndex(index); } } /* * I'm still not happy how the results are represented to the user * right now you only see the result of the last executed statement. * A better experience would be tabs on the bottom with query results * for all the executed statements. */ void MainWindow::executeQuery() { // Make sure a database is opened. This is necessary because we allow opened SQL editor tabs even if no database is loaded. Hitting F5 or similar // then might call this function. if(!db.isOpen()) return; // Check if other task is still running and stop it if necessary if(execute_sql_worker && execute_sql_worker->isRunning()) { // Ask the user and do nothing if he/she doesn't want to interrupt the running query if(QMessageBox::warning(this, qApp->applicationName(), tr("You are already executing SQL statements. Do you want to stop them in order to execute the current " "statements instead? Note that this might leave the database in an inconsistent state."), QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Cancel) return; // Stop the running query execute_sql_worker->stop(); execute_sql_worker->wait(); } // Get current SQL tab and editor SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); SqlTextEdit* editor = sqlWidget->getEditor(); auto* current_tab = ui->tabSqlAreas->currentWidget(); const QString tabName = ui->tabSqlAreas->tabText(ui->tabSqlAreas->currentIndex()).remove('&'); // Remove any error indicators editor->clearErrorIndicators(); sqlWidget->getStatusEdit()->clear(); sqlWidget->getStatusEdit()->setStyleSheet(""); // Determine execution mode: execute all, execute selection or execute current line enum executionMode { All, Selection, Line } mode; if(sender() && sender()->objectName() == "actionSqlExecuteLine") mode = Line; else if(!sqlWidget->getSelectedSql().isEmpty()) mode = Selection; else mode = All; // Get SQL code to execute. This depends on the execution mode. int execute_from_position = 0; // Where we want to start the execution in the query string int execute_to_position = 0; // Where we roughly want to end the execution in the query string switch(mode) { case Selection: { // Start and end positions are start and end positions from the selection int execute_from_line, execute_from_index, execute_to_line, execute_to_index; editor->getSelection(&execute_from_line, &execute_from_index, &execute_to_line, &execute_to_index); execute_from_position = editor->positionFromLineIndex(execute_from_line, execute_from_index); execute_to_position = editor->positionFromLineIndex(execute_to_line, execute_to_index); db.logSQL(tr("-- EXECUTING SELECTION IN '%1'\n--").arg(tabName), kLogMsg_User); } break; case Line: { // Start position is the first character of the current line, except for those cases where we're in the middle of a // statement which started on one the previous line. In that case the start position is actually a bit earlier. For // the end position we set the last character of the current line. If the statement(s) continue(s) into the next line, // SQLite will execute it/them anyway and we'll stop afterwards. int execute_from_line, dummy; editor->getCursorPosition(&execute_from_line, &dummy); execute_from_position = editor->positionFromLineIndex(execute_from_line, 0); // Need to set the end position here before adjusting the start line int execute_to_line = execute_from_line; int execute_to_index = editor->text(execute_to_line).remove('\n').remove('\r').length(); // This chops the line break at the end of the line execute_to_position = editor->positionFromLineIndex(execute_to_line, execute_to_index); QByteArray firstPartEntireSQL = sqlWidget->getSql().toUtf8().left(execute_from_position); if(firstPartEntireSQL.lastIndexOf(';') != -1) { execute_from_position -= firstPartEntireSQL.length() - firstPartEntireSQL.lastIndexOf(';') - 1; } else { // No semicolon before the current line, execute from the first line. execute_from_position = editor->positionFromLineIndex(0, 0); } db.logSQL(tr("-- EXECUTING LINE IN '%1'\n--").arg(tabName), kLogMsg_User); } break; case All: { // Start position is the first byte, end position the last. // Note that we use byte positions that might differ from character positions. execute_to_position = editor->length(); db.logSQL(tr("-- EXECUTING ALL IN '%1'\n--").arg(tabName), kLogMsg_User); } break; } // Prepare a lambda function for logging the results of a query auto logged_queries = std::make_shared(); auto query_logger = [sqlWidget, editor, logged_queries](bool ok, const QString& status_message, int from_position, int to_position) { int execute_from_line, execute_from_index; editor->lineIndexFromPosition(from_position, &execute_from_line, &execute_from_index); // Special case: if the start position is at the end of a line, then move to the beginning of next line. // Otherwise for the typical case, the line reference is one less than expected. // Note that execute_from_index uses character positions and not byte positions, so at() can be used. QChar char_at_index = editor->text(execute_from_line).at(execute_from_index); if (char_at_index == '\r' || char_at_index == '\n') { execute_from_line++; // The next lines could be empty, so skip all of them too. while(editor->text(execute_from_line).trimmed().isEmpty()) execute_from_line++; execute_from_index = 0; } // If there was an error highlight the erroneous SQL statement if(!ok) { int end_of_current_statement_line, end_of_current_statement_index; editor->lineIndexFromPosition(to_position, &end_of_current_statement_line, &end_of_current_statement_index); editor->setErrorIndicator(execute_from_line, execute_from_index, end_of_current_statement_line, end_of_current_statement_index); editor->setCursorPosition(execute_from_line, execute_from_index); } // Log the query and the result message. // The query takes the last placeholder as it may itself contain the sequence '%' + number. QString query = editor->text(from_position, to_position); QString log_message = "-- " + tr("At line %1:").arg(execute_from_line+1) + "\n" + query.trimmed() + "\n-- " + tr("Result: %1").arg(status_message); logged_queries->append(log_message + "\n"); // Update the execution area log_message = tr("Result: %2").arg(status_message) + "\n" + tr("At line %1:").arg(execute_from_line+1) + "\n" + query.trimmed(); sqlWidget->finishExecution(log_message, ok); }; // Get the statement(s) to execute. When in selection mode crop the query string at exactly the end of the selection to make sure SQLite has // no chance to execute any further. QString sql = sqlWidget->getSql(); if(mode == Selection) sql = sql.toUtf8().left(execute_to_position); // We have to convert to a QByteArray here because QScintilla gives us the position in bytes, not in characters. // Prepare the SQL worker to run the query. We set the context of each signal-slot connection to the current SQL execution area. // This means that if the tab is closed all these signals are automatically disconnected so the lambdas won't be called for a not // existing execution area. execute_sql_worker.reset(new RunSql(db, sql, execute_from_position, execute_to_position, true)); connect(execute_sql_worker.get(), &RunSql::structureUpdated, sqlWidget, [this]() { db.updateSchema(); }, Qt::QueuedConnection); connect(execute_sql_worker.get(), &RunSql::statementErrored, sqlWidget, [query_logger, this](const QString& status_message, int from_position, int to_position) { ui->actionSqlResultsSave->setEnabled(false); ui->actionSqlResultsSaveAsView->setEnabled(false); query_logger(false, status_message, from_position, to_position); }, Qt::QueuedConnection); connect(execute_sql_worker.get(), &RunSql::statementExecuted, sqlWidget, [query_logger, this](const QString& status_message, int from_position, int to_position) { ui->actionSqlResultsSave->setEnabled(false); ui->actionSqlResultsSaveAsView->setEnabled(false); query_logger(true, status_message, from_position, to_position); execute_sql_worker->startNextStatement(); }, Qt::QueuedConnection); connect(execute_sql_worker.get(), &RunSql::statementReturnsRows, sqlWidget, [query_logger, this, sqlWidget](const QString& query, int from_position, int to_position, qint64 time_in_ms_so_far) { auto time_start = std::chrono::high_resolution_clock::now(); ui->actionSqlResultsSave->setEnabled(true); ui->actionSqlResultsSaveAsView->setEnabled(!db.readOnly()); auto * model = sqlWidget->getModel(); model->setQuery(query); // Wait until the initial loading of data (= first chunk and row count) has been performed auto conn = std::make_shared(); *conn = connect(model, &SqliteTableModel::finishedFetch, this, [=](int begin, int end) { // Skip callback if it's is a chunk load. // Now query_logger displays the correct value for "rows returned", not "Prefetch block size" if (begin == 0 && end > 0) { return; } disconnect(*conn); attachPlot(sqlWidget->getTableResult(), sqlWidget->getModel()); connect(sqlWidget->getTableResult()->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::dataTableSelectionChanged); connect(sqlWidget->getTableResult(), &QTableView::doubleClicked, this, &MainWindow::doubleClickTable); auto time_end = std::chrono::high_resolution_clock::now(); auto time_in_ms = std::chrono::duration_cast(time_end-time_start); query_logger(true, tr("%1 rows returned in %2ms").arg(model->rowCount()).arg(time_in_ms.count()+time_in_ms_so_far), from_position, to_position); execute_sql_worker->startNextStatement(); }); }, Qt::QueuedConnection); connect(execute_sql_worker.get(), &RunSql::confirmSaveBeforePragmaOrVacuum, sqlWidget, [this]() { if(QMessageBox::question(nullptr, QApplication::applicationName(), tr("Setting PRAGMA values or vacuuming will commit your current transaction.\nAre you sure?"), QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape) == QMessageBox::No) execute_sql_worker->stop(); }, Qt::BlockingQueuedConnection); connect(execute_sql_worker.get(), &RunSql::finished, sqlWidget, [this, current_tab, sqlWidget, logged_queries]() { // Update the SQL log db.logSQL(*logged_queries, kLogMsg_User); // We work with a pointer to the current tab here instead of its index because the user might reorder the tabs in the meantime. // We set different icons for general tabs, which are either new or loaded from the project file, and for tabs loaded from a file. if(sqlWidget->fileName().isEmpty()) ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->indexOf(current_tab), QIcon(":/icons/open_sql")); else ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->indexOf(current_tab), QIcon(":/icons/document_open")); // Set no-running-query state ui->tabSqlAreas->tabBar()->setTabData(ui->tabSqlAreas->indexOf(current_tab), QVariant(false)); // We don't need to check for the current SQL tab here because two concurrently running queries are not allowed ui->actionSqlExecuteLine->setEnabled(true); ui->actionExecuteSql->setEnabled(true); ui->actionSqlStop->setEnabled(false); sqlWidget->getEditor()->setReadOnly(false); // Show Done message if(sqlWidget->inErrorState()) sqlWidget->getStatusEdit()->setPlainText(tr("Execution finished with errors.") + "\n" + sqlWidget->getStatusEdit()->toPlainText()); else sqlWidget->getStatusEdit()->setPlainText(tr("Execution finished without errors.") + "\n" + sqlWidget->getStatusEdit()->toPlainText()); }); // Add an hourglass icon to the current tab to indicate that there's a running execution in there. ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->currentIndex(), QIcon(":icons/hourglass")); // We use the tab data to check whether a specific SQL tab is currently running a query or not. ui->tabSqlAreas->tabBar()->setTabData(ui->tabSqlAreas->currentIndex(), QVariant(true)); // Deactivate the buttons to start a query and activate the button to stop the query ui->actionSqlExecuteLine->setEnabled(false); ui->actionExecuteSql->setEnabled(false); ui->actionSqlStop->setEnabled(true); // Make the SQL editor widget read-only. We do this because the error indicators would be misplaced if the user changed the SQL text during execution sqlWidget->getEditor()->setReadOnly(true); // Reset model and clear plot dock sqlWidget->getModel()->reset(); attachPlot(sqlWidget->getTableResult(), sqlWidget->getModel()); // Start the execution execute_sql_worker->start(); } void MainWindow::mainTabSelected(int /*tabindex*/) { editDock->setReadOnly(true); if(ui->mainTab->currentWidget() == ui->browser) { refreshTableBrowsers(); } else if(ui->mainTab->currentWidget() == ui->pragmas) { loadPragmas(); } else if(ui->mainTab->currentWidget() == ui->query) { SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); if (sqlWidget) { m_currentTabTableModel = sqlWidget->getModel(); dataTableSelectionChanged(sqlWidget->getTableResult()->currentIndex()); } } } void MainWindow::importCSVfiles(const std::vector& inputFiles, const QString& table) { if (!inputFiles.empty()) { // Allow importing to a new in-memory database that can be saved later. if(!db.isOpen()) fileNewInMemoryDatabase(/* open_create_dialog */ false); ImportCsvDialog dialog(inputFiles, &db, this, table); if (dialog.exec()) refreshTableBrowsers(); } } void MainWindow::importTableFromCSV() { std::vector validFiles; // Are we importing from a file or from the clipboard? if(sender() == ui->fileImportCSVAction) { // Ask user to specify file(s) QStringList file_filter; file_filter << FILE_FILTER_CSV << FILE_FILTER_TSV << FILE_FILTER_DSV << FILE_FILTER_TXT << FILE_FILTER_DAT << FILE_FILTER_ALL; const QStringList wFiles = FileDialog::getOpenFileNames( OpenCSVFile, this, tr("Choose text files"), file_filter.join(";;")); for(const auto& file : wFiles) { if (QFile::exists(file)) validFiles.push_back(file); } importCSVfiles(validFiles); } else if(sender() == ui->actionFileImportCsvClipboard) { // Save clipboard content to temporary file QTemporaryFile temp("csv_clipboard"); temp.open(); QClipboard* clipboard = QGuiApplication::clipboard(); temp.write(clipboard->text().toUtf8()); temp.close(); validFiles.push_back(temp.fileName()); // Note that the temporary file will be removed when the object is // destroyed, so the reading must be done in the same scope. importCSVfiles(validFiles); } } void MainWindow::exportTableToCSV() { // Get the current table name if we are in the Browse Data tab sqlb::ObjectIdentifier current_table; if(ui->mainTab->currentWidget() == ui->structure) { QString type = dbSelected->objectType(); if(type == "table" || type == "view") { current_table = dbSelected->object(); } } else if(ui->mainTab->currentWidget() == ui->browser) { current_table = currentlyBrowsedTableName(); } // Open dialog ExportDataDialog dialog(db, ExportDataDialog::ExportFormatCsv, this, "", current_table); dialog.exec(); } void MainWindow::exportTableToJson() { // Get the current table name if we are in the Browse Data tab sqlb::ObjectIdentifier current_table; if(ui->mainTab->currentWidget() == ui->structure) { QString type = dbSelected->objectType(); if(type == "table" || type == "view") { current_table = dbSelected->object(); } } else if(ui->mainTab->currentWidget() == ui->browser) { current_table = currentlyBrowsedTableName(); } // Open dialog ExportDataDialog dialog(db, ExportDataDialog::ExportFormatJson, this, "", current_table); dialog.exec(); } void MainWindow::dbState(bool dirty) { ui->fileSaveAction->setEnabled(dirty); ui->fileRevertAction->setEnabled(dirty); ui->undoAction->setEnabled(dirty); // Unfortunately, sqlite does not allow to backup the DB while there are pending savepoints, // so we cannot "Save As" when the DB is dirty. ui->fileSaveAsAction->setEnabled(!dirty); } void MainWindow::fileSave() { if(db.isOpen()) { if(!db.releaseAllSavepoints()) { QMessageBox::warning(this, QApplication::applicationName(), tr("Error while saving the database file. This means that not all changes to the database were " "saved. You need to resolve the following error first.\n\n%1").arg(db.lastError())); } } } void MainWindow::fileRevert() { if (db.isOpen()){ QString msg = tr("Are you sure you want to undo all changes made to the database file '%1' since the last save?").arg(db.currentFile()); if(QMessageBox::question(this, QApplication::applicationName(), msg, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape) == QMessageBox::Yes) { db.revertAll(); refreshTableBrowsers(); } } } void MainWindow::undo() { if (db.isOpen()) { db.revertToUndoSavepoint(); refreshTableBrowsers(); } } void MainWindow::exportDatabaseToSQL() { QString current_table; if(ui->mainTab->currentWidget() == ui->browser) current_table = QString::fromStdString(currentlyBrowsedTableName().name()); ExportSqlDialog dialog(&db, this, current_table); dialog.exec(); } void MainWindow::importDatabaseFromSQL() { QStringList file_filter; file_filter << FILE_FILTER_SQL << FILE_FILTER_TXT << FILE_FILTER_ALL; // Get file name to import QString fileName = FileDialog::getOpenFileName( OpenSQLFile, this, tr("Choose a file to import"), file_filter.join(";;")); // Cancel when file doesn't exist if(!QFile::exists(fileName)) return; // If there is already a database file opened ask the user whether to import into // this one or a new one. If no DB is opened just ask for a DB name directly QString newDbFile; if((db.isOpen() && QMessageBox::question(this, QApplication::applicationName(), tr("Do you want to create a new database file to hold the imported data?\n" "If you answer no we will attempt to import the data in the SQL file to the current database."), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) || !db.isOpen()) { newDbFile = FileDialog::getSaveFileName( CreateDatabaseFile, this, tr("Choose a filename to save under"), FileDialog::getSqlDatabaseFileFilter()); if(QFile::exists(newDbFile)) { QMessageBox::information(this, QApplication::applicationName(), tr("File %1 already exists. Please choose a different name.").arg(newDbFile)); return; } else if(newDbFile.size() == 0) { return; } // Create the new file and open it in the browser db.create(newDbFile); db.close(); fileOpen(newDbFile); } // Defer foreign keys. Just deferring them instead of disabling them should work fine because in the import we only expect CREATE and INSERT // statements which unlike in the Edit Table dialog shouldn't trigger any problems. QString foreignKeysOldSettings = db.getPragma("defer_foreign_keys"); db.setPragma("defer_foreign_keys", "1"); // Open, read, execute and close file QApplication::setOverrideCursor(Qt::WaitCursor); QFile f(fileName); f.open(QIODevice::ReadOnly); QByteArray filedata = f.readAll(); removeBom(filedata); bool ok = db.executeMultiSQL(filedata, newDbFile.size() == 0); // Restore cursor before asking the user to accept the message QApplication::restoreOverrideCursor(); if(!ok) QMessageBox::warning(this, QApplication::applicationName(), tr("Error importing data: %1").arg(db.lastError())); else if(db.getPragma("foreign_keys") == "1" && !db.querySingleValueFromDb("PRAGMA foreign_key_check").isNull()) QMessageBox::warning(this, QApplication::applicationName(), tr("Import completed. Some foreign key constraints are violated. Please fix them before saving.")); else QMessageBox::information(this, QApplication::applicationName(), tr("Import completed.")); f.close(); // Restore the former foreign key settings db.setPragma("defer_foreign_keys", foreignKeysOldSettings); // Refresh views db.updateSchema(); refreshTableBrowsers(); } void MainWindow::openPreferences() { PreferencesDialog dialog(this); if(dialog.exec()) reloadSettings(); } //** Db Tree Context Menu void MainWindow::createTreeContextMenu(const QPoint &qPoint) { if(!dbSelected->hasSelection()) return; QString type = dbSelected->objectType(); if(type == "table" || type == "view" || type == "trigger" || type == "index" || type == "database") { // needed for first click on treeView as for first time change QItemSelectionModel::currentChanged doesn't fire changeTreeSelection(); popupTableMenu->exec(ui->dbTreeWidget->mapToGlobal(qPoint)); } } //** DB Schema Dock Context Menu void MainWindow::createSchemaDockContextMenu(const QPoint &qPoint) { bool enable_browse_table = false; bool enable_detach_file = false; if(dockDbSelected->hasSelection()) { QString type = dockDbSelected->objectType(); if(type == "table" || type == "view") enable_browse_table = true; else if(type == "database" && dockDbSelected->schema() != "main" && dockDbSelected->schema() != "temp") enable_detach_file = true; } ui->actionPopupSchemaDockBrowseTable->setEnabled(enable_browse_table); ui->actionPopupSchemaDockDetachDatabase->setEnabled(enable_detach_file); popupSchemaDockMenu->exec(ui->treeSchemaDock->mapToGlobal(qPoint)); } void MainWindow::changeTreeSelection() { // Just assume first that something's selected that can not be edited at all ui->editDeleteObjectAction->setEnabled(false); ui->editModifyObjectAction->setEnabled(false); ui->actionEditBrowseTable->setEnabled(false); ui->actionExportCsvPopup->setEnabled(false); ui->fileDetachAction->setEnabled(false); ui->actionEditCopyCreateStatement->setEnabled(false); ui->fileDetachAction->setVisible(false); if(!dbSelected->hasSelection()) return; // Change the text and tooltips of the actions QString type = dbSelected->objectType(); QString schema = dbSelected->schema(); if (type.isEmpty()) { ui->editDeleteObjectAction->setIcon(QIcon(":icons/table_delete")); ui->editModifyObjectAction->setIcon(QIcon(":icons/table_modify")); } else { ui->editDeleteObjectAction->setIcon(QIcon(QString(":icons/%1_delete").arg(type))); ui->editModifyObjectAction->setIcon(QIcon(QString(":icons/%1_modify").arg(type))); } if (type == "view") { ui->editDeleteObjectAction->setText(tr("Delete View")); ui->editModifyObjectAction->setText(tr("Modify View")); } else if(type == "trigger") { ui->editDeleteObjectAction->setText(tr("Delete Trigger")); ui->editModifyObjectAction->setText(tr("Modify Trigger")); } else if(type == "index") { ui->editDeleteObjectAction->setText(tr("Delete Index")); ui->editModifyObjectAction->setText(tr("Modify Index")); } else if(type == "table") { ui->editDeleteObjectAction->setText(tr("Delete Table")); ui->editModifyObjectAction->setText(tr("Modify Table")); } else if(type == "database") { ui->editDeleteObjectAction->setVisible(false); ui->editModifyObjectAction->setVisible(false); ui->fileDetachAction->setVisible(true); ui->fileDetachAction->setEnabled(!(schema == "main" || schema == "temp")); return; } else { // Nothing to do for other types. Set the buttons not visible and return. ui->editDeleteObjectAction->setVisible(false); ui->editModifyObjectAction->setVisible(false); ui->fileDetachAction->setVisible(false); ui->actionEditCopyCreateStatement->setEnabled(true); return; } ui->editDeleteObjectAction->setVisible(true); ui->editModifyObjectAction->setVisible(true); ui->actionEditCopyCreateStatement->setEnabled(true); // Activate actions ui->editDeleteObjectAction->setEnabled(!db.readOnly()); ui->editModifyObjectAction->setEnabled(!db.readOnly()); if(type == "table" || type == "view") { ui->actionEditBrowseTable->setEnabled(true); ui->actionExportCsvPopup->setEnabled(true); } } void MainWindow::openRecentFile() { QAction *action = qobject_cast(sender()); if (action) { QString file = action->data().toString(); bool read_only = false; if(file.startsWith("[ro]")) // Check if file is in read-only { file = file.mid(4); read_only = true; } // Holding the Shift key while opening a recent file inverts the read only flag if(Application::keyboardModifiers().testFlag(Qt::ShiftModifier)) read_only = !read_only; if(fileOpen(file, false, read_only)) { if(read_only) ui->statusbar->showMessage(tr("Opened '%1' in read-only mode from recent file list").arg(file)); else ui->statusbar->showMessage(tr("Opened '%1' from recent file list").arg(file)); } } } void MainWindow::updateRecentFileActions() { // Get recent files list from settings QStringList files = Settings::getValue("General", "recentFileList").toStringList(); // Check if files still exist and remove any non-existent file for(int i=0;isetText(text); recentFileActs[i]->setData(files[i]); recentFileActs[i]->setVisible(true); // Add shortcut for opening the file using the keyboard. However, if the application is configured to store // more than nine recently opened files don't set shortcuts for the later ones which wouldn't be single digit anymore. if(i < 9) { recentFileActs[i]->setShortcuts({ QKeySequence(static_cast(Qt::CTRL + (Qt::Key_1+static_cast(i)))), QKeySequence(static_cast(Qt::CTRL + Qt::SHIFT + (Qt::Key_1+static_cast(i)))) }); } } for (int j = numRecentFiles; j < MaxRecentFiles; ++j) recentFileActs[j]->setVisible(false); } void MainWindow::setCurrentFile(const QString &fileName) { setWindowFilePath(fileName); if(currentProjectFilename.isEmpty() && fileName.isEmpty()) setWindowTitle(QApplication::applicationName()); else if(currentProjectFilename.isEmpty()) setWindowTitle(QApplication::applicationName() + " - " + QDir::toNativeSeparators(fileName)); else { QFileInfo projectFileInfo(currentProjectFilename); QFileInfo dbFileInfo(fileName); QString dbFileName; if(dbFileInfo.path() == projectFileInfo.path()) dbFileName = dbFileInfo.fileName(); else dbFileName = QDir::toNativeSeparators(fileName); setWindowTitle(QApplication::applicationName() + " - " + QDir::toNativeSeparators(currentProjectFilename) + " [" + dbFileName + "]"); } activateFields(!fileName.isEmpty()); if(!fileName.isEmpty()) dbState(db.getDirty()); } void MainWindow::addToRecentFilesMenu(const QString& filename, bool read_only) { QFileInfo info(filename); QString path = info.absoluteFilePath(); if(read_only) path = "[ro]" + path; QStringList files = Settings::getValue("General", "recentFileList").toStringList(); files.removeAll(path); files.prepend(path); while (files.size() > MaxRecentFiles) files.removeLast(); Settings::setValue("General", "recentFileList", files); for(QWidget* widget : QApplication::topLevelWidgets()) { MainWindow *mainWin = qobject_cast(widget); if (mainWin) mainWin->updateRecentFileActions(); } } void MainWindow::dragEnterEvent(QDragEnterEvent *event) { if( event->mimeData()->hasFormat("text/uri-list") ) event->acceptProposedAction(); } void MainWindow::dropEvent(QDropEvent *event) { const QList urls = event->mimeData()->urls(); if( urls.isEmpty() ) return; QString fileName = urls.first().toLocalFile(); if(!fileName.isEmpty()) { // If there is no open database, the only possible option is to open the file. if (!db.isOpen()) { fileOpen(fileName); return; } bool ok; const QString open = tr("Open Database or Project"); const QString attach = tr("Attach Database..."); const QString import = tr("Import CSV file(s)..."); QString action = QInputDialog::getItem(this, qApp->applicationName(), tr("Select the action to apply to the dropped file(s).
" "Note: only 'Import' will process more than one file.", "Note for translation: Although there is no %n in the original, " "you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. " "Including %n in the translation will also work.", urls.count()), {open, attach, import}, 0, false, &ok); if(ok) { if (action == open) { fileOpen(fileName); } else if (action == attach) { fileAttach(fileName); } else if (action == import) { std::vector validFiles; for(const auto& url : urls) { if (QFile::exists(url.toLocalFile())) validFiles.push_back(url.toLocalFile()); } ImportCsvDialog dialog(validFiles, &db, this); if (dialog.exec()) refreshTableBrowsers(); } } } } void MainWindow::activateFields(bool enable) { bool write = !db.readOnly(); bool tempDb = db.currentFile() == ":memory:"; ui->fileCloseAction->setEnabled(enable); ui->fileSaveAsAction->setEnabled(enable); ui->fileAttachAction->setEnabled(enable); ui->fileCompactAction->setEnabled(enable && write); ui->fileExportJsonAction->setEnabled(enable); ui->fileExportCSVAction->setEnabled(enable); ui->fileExportSQLAction->setEnabled(enable); ui->fileImportCSVAction->setEnabled(enable && write); ui->actionFileImportCsvClipboard->setEnabled(enable && write); ui->editCreateTableAction->setEnabled(enable && write); ui->editCreateIndexAction->setEnabled(enable && write); ui->actionRefreshStructure->setEnabled(enable); ui->actionDbPrint->setEnabled(enable); ui->scrollAreaWidgetContents->setEnabled(enable); ui->buttonBoxPragmas->setEnabled(enable && write); ui->actionExecuteSql->setEnabled(enable); ui->actionLoadExtension->setEnabled(enable); ui->actionSqlExecuteLine->setEnabled(enable); ui->actionSaveProject->setEnabled(enable && !tempDb); ui->actionSaveProjectAs->setEnabled(enable && !tempDb); ui->actionSaveAll->setEnabled(enable && !tempDb); ui->actionEncryption->setEnabled(enable && write && !tempDb); ui->actionIntegrityCheck->setEnabled(enable); ui->actionQuickCheck->setEnabled(enable); ui->actionForeignKeyCheck->setEnabled(enable); ui->actionOptimize->setEnabled(enable); ui->actionRowCounts->setEnabled(enable); ui->dockEdit->setEnabled(enable); ui->dockPlot->setEnabled(enable); if(!enable) ui->actionSqlResultsSave->setEnabled(false); remoteDock->enableButtons(); for(const auto& d : allTableBrowserDocks()) d->tableBrowser()->setEnabled(enable); } void MainWindow::resizeEvent(QResizeEvent*) { for(const auto& d : allTableBrowserDocks()) d->tableBrowser()->updateRecordsetLabel(); } void MainWindow::loadPragmas() { pragmaValues.autovacuum = db.getPragma("auto_vacuum").toInt(); pragmaValues.automatic_index = db.getPragma("automatic_index").toInt(); pragmaValues.checkpoint_fullsync = db.getPragma("checkpoint_fullfsync").toInt(); pragmaValues.foreign_keys = db.getPragma("foreign_keys").toInt(); pragmaValues.fullfsync = db.getPragma("fullfsync").toInt(); pragmaValues.ignore_check_constraints = db.getPragma("ignore_check_constraints").toInt(); pragmaValues.journal_mode = db.getPragma("journal_mode").toUpper(); pragmaValues.journal_size_limit = db.getPragma("journal_size_limit").toInt(); pragmaValues.locking_mode = db.getPragma("locking_mode").toUpper(); pragmaValues.max_page_count = db.getPragma("max_page_count").toInt(); pragmaValues.page_size = db.getPragma("page_size").toInt(); pragmaValues.recursive_triggers = db.getPragma("recursive_triggers").toInt(); pragmaValues.secure_delete = db.getPragma("secure_delete").toInt(); pragmaValues.synchronous = db.getPragma("synchronous").toInt(); pragmaValues.temp_store = db.getPragma("temp_store").toInt(); pragmaValues.user_version = db.getPragma("user_version").toInt(); pragmaValues.wal_autocheckpoint = db.getPragma("wal_autocheckpoint").toInt(); pragmaValues.case_sensitive_like = db.getPragma("case_sensitive_like").toInt(); updatePragmaUi(); } void MainWindow::updatePragmaUi() { ui->comboboxPragmaAutoVacuum->setCurrentIndex(pragmaValues.autovacuum); ui->checkboxPragmaAutomaticIndex->setChecked(pragmaValues.automatic_index); ui->checkboxPragmaCheckpointFullFsync->setChecked(pragmaValues.checkpoint_fullsync); ui->checkboxPragmaForeignKeys->setChecked(pragmaValues.foreign_keys); ui->checkboxPragmaFullFsync->setChecked(pragmaValues.fullfsync); ui->checkboxPragmaIgnoreCheckConstraints->setChecked(pragmaValues.ignore_check_constraints); ui->comboboxPragmaJournalMode->setCurrentIndex(ui->comboboxPragmaJournalMode->findText(pragmaValues.journal_mode, Qt::MatchFixedString)); ui->spinPragmaJournalSizeLimit->setValue(pragmaValues.journal_size_limit); ui->comboboxPragmaLockingMode->setCurrentIndex(ui->comboboxPragmaLockingMode->findText(pragmaValues.locking_mode, Qt::MatchFixedString)); ui->spinPragmaMaxPageCount->setValue(pragmaValues.max_page_count); ui->comboPragmaPageSize->setCurrentIndex(ui->comboPragmaPageSize->findText(QString::number(pragmaValues.page_size), Qt::MatchFixedString)); ui->checkboxPragmaRecursiveTriggers->setChecked(pragmaValues.recursive_triggers); ui->checkboxPragmaSecureDelete->setChecked(pragmaValues.secure_delete); ui->comboboxPragmaSynchronous->setCurrentIndex(pragmaValues.synchronous); ui->comboboxPragmaTempStore->setCurrentIndex(pragmaValues.temp_store); ui->spinPragmaUserVersion->setValue(pragmaValues.user_version); ui->spinPragmaWalAutoCheckpoint->setValue(pragmaValues.wal_autocheckpoint); ui->checkboxPragmaCaseSensitiveLike->setChecked(pragmaValues.case_sensitive_like); } void MainWindow::savePragmas() { if( db.getDirty() ) { QString msg = tr("Setting PRAGMA values will commit your current transaction.\nAre you sure?"); if(QMessageBox::question(this, QApplication::applicationName(), msg, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape) == QMessageBox::No) { return; // abort } } db.setPragma("auto_vacuum", ui->comboboxPragmaAutoVacuum->currentIndex(), pragmaValues.autovacuum); db.setPragma("automatic_index", ui->checkboxPragmaAutomaticIndex->isChecked(), pragmaValues.automatic_index); db.setPragma("checkpoint_fullfsync", ui->checkboxPragmaCheckpointFullFsync->isChecked(), pragmaValues.checkpoint_fullsync); db.setPragma("foreign_keys", ui->checkboxPragmaForeignKeys->isChecked(), pragmaValues.foreign_keys); db.setPragma("fullfsync", ui->checkboxPragmaFullFsync->isChecked(), pragmaValues.fullfsync); db.setPragma("ignore_check_constraints", ui->checkboxPragmaIgnoreCheckConstraints->isChecked(), pragmaValues.ignore_check_constraints); db.setPragma("journal_mode", ui->comboboxPragmaJournalMode->currentText().toUpper(), pragmaValues.journal_mode); db.setPragma("journal_size_limit", ui->spinPragmaJournalSizeLimit->value(), pragmaValues.journal_size_limit); db.setPragma("locking_mode", ui->comboboxPragmaLockingMode->currentText().toUpper(), pragmaValues.locking_mode); db.setPragma("max_page_count", ui->spinPragmaMaxPageCount->value(), pragmaValues.max_page_count); db.setPragma("page_size", ui->comboPragmaPageSize->currentText().toInt(), pragmaValues.page_size); db.setPragma("recursive_triggers", ui->checkboxPragmaRecursiveTriggers->isChecked(), pragmaValues.recursive_triggers); db.setPragma("secure_delete", ui->checkboxPragmaSecureDelete->isChecked(), pragmaValues.secure_delete); db.setPragma("synchronous", ui->comboboxPragmaSynchronous->currentIndex(), pragmaValues.synchronous); db.setPragma("temp_store", ui->comboboxPragmaTempStore->currentIndex(), pragmaValues.temp_store); db.setPragma("user_version", ui->spinPragmaUserVersion->value(), pragmaValues.user_version); db.setPragma("wal_autocheckpoint", ui->spinPragmaWalAutoCheckpoint->value(), pragmaValues.wal_autocheckpoint); db.setPragma("case_sensitive_like", ui->checkboxPragmaCaseSensitiveLike->isChecked(), pragmaValues.case_sensitive_like); isProjectModified = true; updatePragmaUi(); } void MainWindow::logSql(const QString& sql, int msgtype) { if(msgtype == kLogMsg_User) { ui->editLogUser->append(sql + "\n"); ui->editLogUser->verticalScrollBar()->setValue(ui->editLogUser->verticalScrollBar()->maximum()); } else if(msgtype == kLogMsg_App) { ui->editLogApplication->append(sql + "\n"); ui->editLogApplication->verticalScrollBar()->setValue(ui->editLogApplication->verticalScrollBar()->maximum()); } else if(msgtype == kLogMsg_ErrorLog) { ui->editLogErrorLog->append(sql + "\n"); ui->editLogErrorLog->verticalScrollBar()->setValue(ui->editLogErrorLog->verticalScrollBar()->maximum()); } } // Ask user to save the buffer in the specified tab index. // ignoreUnattachedBuffers is used to store answer about buffers not linked to files, so user is only asked once about them. // Return true unless user wants to cancel the invoking action. bool MainWindow::askSaveSqlTab(int index, bool& ignoreUnattachedBuffers) { SqlExecutionArea* sqlExecArea = qobject_cast(ui->tabSqlAreas->widget(index)); const bool isPromptSQLTabsInNewProject = Settings::getValue("General", "promptsqltabsinnewproject").toBool(); if(sqlExecArea->getEditor()->isModified()) { if(sqlExecArea->fileName().isEmpty() && !ignoreUnattachedBuffers && isPromptSQLTabsInNewProject) { // Once the project is saved, remaining SQL tabs will not be modified, so this is only expected to be asked once. QString message = currentProjectFilename.isEmpty() ? tr("Do you want to save the changes made to SQL tabs in a new project file?") : tr("Do you want to save the changes made to SQL tabs in the project file '%1'?"). arg(QFileInfo(currentProjectFilename).fileName()); QMessageBox::StandardButton reply = QMessageBox::question(nullptr, QApplication::applicationName(), message, QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); switch(reply) { case QMessageBox::Save: saveProject(); break; case QMessageBox::Cancel: return false; default: ignoreUnattachedBuffers = true; break; } } else if(!sqlExecArea->fileName().isEmpty()) { QMessageBox::StandardButton reply = QMessageBox::question(nullptr, QApplication::applicationName(), tr("Do you want to save the changes made to the SQL file %1?"). arg(QFileInfo(sqlExecArea->fileName()).fileName()), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); switch(reply) { case QMessageBox::Save: saveSqlFile(index); break; case QMessageBox::Cancel: return false; default: break; } } } return true; } void MainWindow::closeSqlTab(int index, bool force, bool askSaving) { // Check if we're still executing statements from this tab and stop them before proceeding if(ui->tabSqlAreas->tabBar()->tabData(index).toBool()) { if(QMessageBox::warning(this, qApp->applicationName(), tr("The statements in the tab '%1' are still executing. Closing the tab will stop the " "execution. This might leave the database in an inconsistent state. Are you sure " "you want to close the tab?").arg(ui->tabSqlAreas->tabBar()->tabText(index)), QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Cancel) return; execute_sql_worker->stop(); execute_sql_worker->wait(); } // Ask for saving and comply with cancel answer. bool ignoreUnattachedBuffers = false; if (askSaving && !askSaveSqlTab(index, ignoreUnattachedBuffers)) return; // Remove the tab and delete the widget QWidget* w = ui->tabSqlAreas->widget(index); ui->tabSqlAreas->removeTab(index); delete w; // Don't let an empty tab widget if(ui->tabSqlAreas->count() == 0 && !force) openSqlTab(true); // Set focus to the currently selected editor tab. focusSqlEditor(); } int MainWindow::openSqlTab(bool resetCounter) { static int tabNumber = 0; if(resetCounter) tabNumber = 0; // Create new tab, add it to the tab widget and select it SqlExecutionArea* w = new SqlExecutionArea(db, this); int index = ui->tabSqlAreas->addTab(w, QString("SQL %1").arg(++tabNumber)); ui->tabSqlAreas->setCurrentIndex(index); w->setFindFrameVisibility(ui->actionSqlFind->isChecked()); // Disable the find dialog in the SQL tabs, since the shortcut // would interfere with the search bar and it'd be anyway redundant. w->getEditor()->setEnabledFindDialog(false); w->getEditor()->setFocus(); connect(w, &SqlExecutionArea::findFrameVisibilityChanged, ui->actionSqlFind, &QAction::setChecked); // Add (and remove) an asterisk next to the filename of modified file tabs. connect(w->getEditor(), &SqlTextEdit::modificationChanged, this, [this](bool) { for(int i=0; i < ui->tabSqlAreas->count(); ++i) { SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->widget(i)); QString currentText = ui->tabSqlAreas->tabText(i); if(!currentText.endsWith("*")) { if(sqlWidget->getEditor()->isModified()) { ui->tabSqlAreas->setTabText(i, currentText + "*"); } } else { if(!sqlWidget->getEditor()->isModified()) { currentText.chop(1); ui->tabSqlAreas->setTabText(i, currentText); } } } }); // Connect now the find shortcut to the editor with widget context, so it isn't ambiguous with other Scintilla Widgets. QShortcut* shortcutFind = new QShortcut(ui->actionSqlFind->shortcut(), w->getEditor(), nullptr, nullptr, Qt::WidgetShortcut); connect(shortcutFind, &QShortcut::activated, ui->actionSqlFind, &QAction::toggle); ui->tabSqlAreas->setTabIcon(index, QIcon(":icons/open_sql")); // The new tab is not currently running a query ui->tabSqlAreas->tabBar()->setTabData(index, false); return index; } void MainWindow::changeSqlTab(int index) { // Instead of figuring out if there are some execution results in the new tab and which statement was used to generate them, // we just disable the export buttons in the toolbar. ui->actionSqlResultsSave->setEnabled(false); // Check if the new tab is currently running a query or not if(!ui->tabSqlAreas->tabBar()->tabData(index).toBool()) { // Not running a query ui->actionSqlExecuteLine->setEnabled(db.isOpen()); ui->actionExecuteSql->setEnabled(db.isOpen()); ui->actionSqlStop->setEnabled(false); } else { // Running a query ui->actionSqlExecuteLine->setEnabled(false); ui->actionExecuteSql->setEnabled(false); ui->actionSqlStop->setEnabled(true); } SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); if (sqlWidget) { m_currentTabTableModel = sqlWidget->getModel(); dataTableSelectionChanged(sqlWidget->getTableResult()->currentIndex()); } } void MainWindow::openSqlFile(int tabindex, QString filename) { SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->widget(tabindex)); sqlarea->openFile(filename); QFileInfo fileinfo(filename); ui->tabSqlAreas->setTabText(tabindex, fileinfo.fileName()); ui->tabSqlAreas->setTabIcon(tabindex, QIcon(":/icons/document_open")); } void MainWindow::openSqlFile() { const QStringList wfiles = FileDialog::getOpenFileNames( OpenSQLFile, this, tr("Select SQL file to open"), tr("Text files(*.sql *.txt);;All files(*)")); for(const QString& file: wfiles) { if(QFile::exists(file)) { // Decide whether to open a new tab or take the current one int index; SqlExecutionArea* current_tab = qobject_cast(ui->tabSqlAreas->currentWidget()); if(current_tab && current_tab->getSql().isEmpty() && current_tab->getModel()->rowCount() == 0) index = ui->tabSqlAreas->currentIndex(); else index = openSqlTab(); openSqlFile(index, file); } } } void MainWindow::saveSqlFile(int tabIndex) { SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->widget(tabIndex)); if(!sqlarea) return; // If this SQL file hasn't been saved before open the Save As dialog. Otherwise just use the old file name for saving if(sqlarea->fileName().isEmpty()) { saveSqlFileAs(); } else { sqlarea->saveFile(sqlarea->fileName()); } } void MainWindow::saveSqlFile() { saveSqlFile(ui->tabSqlAreas->currentIndex()); } void MainWindow::saveSqlFileAs() { SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->currentWidget()); if(!sqlarea) return; QStringList file_filter; file_filter << FILE_FILTER_SQL << FILE_FILTER_TXT << FILE_FILTER_ALL; QString file = FileDialog::getSaveFileName( CreateSQLFile, this, tr("Select file name"), file_filter.join(";;")); if(!file.isEmpty()) { sqlarea->saveFile(file); QFileInfo fileinfo(file); ui->tabSqlAreas->setTabText(ui->tabSqlAreas->currentIndex(), fileinfo.fileName()); ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->currentIndex(), QIcon(":/icons/document_open")); } } void MainWindow::saveSqlResultsAsCsv() { qobject_cast(ui->tabSqlAreas->currentWidget())->saveAsCsv(); } void MainWindow::saveSqlResultsAsJson() { qobject_cast(ui->tabSqlAreas->currentWidget())->saveAsJson(); } void MainWindow::saveSqlResultsAsView() { saveAsView(qobject_cast(ui->tabSqlAreas->currentWidget())->getModel()->query()); } void MainWindow::loadExtension() { QStringList file_filter; file_filter << FILE_FILTER_DYN << FILE_FILTER_ALL; QString file = FileDialog::getOpenFileName( OpenExtensionFile, this, tr("Select extension file"), file_filter.join(";;")); if(file.isEmpty()) return; if(db.loadExtension(file)) QMessageBox::information(this, QApplication::applicationName(), tr("Extension successfully loaded.")); else QMessageBox::warning(this, QApplication::applicationName(), tr("Error loading extension: %1").arg(db.lastError())); } void MainWindow::reloadSettings() { // Set default application font size qobject_cast(qApp)->reloadSettings(); // Set data browser font for(const auto& d : allTableBrowserDocks()) d->tableBrowser()->reloadSettings(); // Set max recent files const int newMaxRecentFiles = Settings::getValue("General", "maxRecentFiles").toInt(); if(MaxRecentFiles < newMaxRecentFiles) { // If user increase max recent files value. ui->fileRecentFiles->removeAction(clearRecentFilesAction); recentFileActs.resize(newMaxRecentFiles); for(int i = MaxRecentFiles; i < newMaxRecentFiles; ++i) { recentFileActs[i] = new QAction(this); recentFileActs[i]->setVisible(false); connect(recentFileActs[i], &QAction::triggered, this, &MainWindow::openRecentFile); } for(int i = 0; i < newMaxRecentFiles; ++i) ui->fileRecentFiles->insertAction(ui->fileExitAction, recentFileActs[i]); ui->fileRecentFiles->insertSeparator(ui->fileExitAction); ui->fileRecentFiles->insertAction(ui->fileExitAction, clearRecentFilesAction); MaxRecentFiles = newMaxRecentFiles; updateRecentFileActions(); } else if (MaxRecentFiles > newMaxRecentFiles) { // If user decrease max recent files value. for(int i = (MaxRecentFiles - 1); i >= newMaxRecentFiles; --i) { ui->fileRecentFiles->removeAction(recentFileActs[i]); delete recentFileActs[i]; } recentFileActs.resize(newMaxRecentFiles); MaxRecentFiles = newMaxRecentFiles; updateRecentFileActions(); } Settings::AppStyle style = static_cast(Settings::getValue("General", "appStyle").toInt()); switch (style) { case Settings::FollowDesktopStyle : qApp->setStyleSheet(""); break; case Settings::DarkStyle : case Settings::LightStyle : QFile f(style == Settings::DarkStyle ? ":qdarkstyle/dark/darkstyle.qss" : ":qdarkstyle/light/lightstyle.qss"); if (!f.exists()) { QMessageBox::warning(this, qApp->applicationName(), tr("Could not find resource file: %1").arg(f.fileName())); } else { f.open(QFile::ReadOnly | QFile::Text); QTextStream ts(&f); qApp->setStyleSheet(ts.readAll()); } break; } ui->toolbarDB->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyle").toInt())); ui->dbToolbar->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyleStructure").toInt())); ui->toolbarSql->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyleSql").toInt())); // Other toolbars will follow Main Window ToolBar Style ui->toolbarExtraDB->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyle").toInt())); ui->toolbarProject->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyle").toInt())); // Set prefetch sizes for lazy population of table models for(int i=0;itabSqlAreas->count();++i) qobject_cast(ui->tabSqlAreas->widget(i))->reloadSettings(); // Prepare log font QFont logfont("Monospace"); logfont.setStyleHint(QFont::TypeWriter); logfont.setPointSize(Settings::getValue("log", "fontsize").toInt()); // Set font for SQL logs and edit dialog ui->editLogApplication->reloadSettings(); ui->editLogUser->reloadSettings(); ui->editLogErrorLog->reloadSettings(); ui->editLogApplication->setFont(logfont); ui->editLogUser->setFont(logfont); ui->editLogErrorLog->setFont(logfont); editDock->reloadSettings(); // Set font for database structure views QFont structure_font = ui->dbTreeWidget->font(); structure_font.setPointSize(Settings::getValue("db", "fontsize").toInt()); ui->dbTreeWidget->setFont(structure_font); ui->treeSchemaDock->setFont(structure_font); // Load extensions db.loadExtensionsFromSettings(); // Refresh view emit db.structureUpdated(); refreshTableBrowsers(); // Hide or show the remote dock as needed bool showRemoteActions = Settings::getValue("remote", "active").toBool(); ui->viewMenu->actions().at(4)->setVisible(showRemoteActions); if(!showRemoteActions) ui->dockRemote->setHidden(true); // Reload remote dock settings remoteDock->reloadSettings(); sqlb::setIdentifierQuoting(static_cast(Settings::getValue("editor", "identifier_quotes").toInt())); ui->tabSqlAreas->setTabsClosable(Settings::getValue("editor", "close_button_on_tabs").toBool()); } void MainWindow::checkNewVersion(const QString& versionstring, const QString& url) { // versionstring contains a major.minor.patch version string QStringList versiontokens = versionstring.split("."); if(versiontokens.size() < 3) return; int major = versiontokens[0].toInt(); int minor = versiontokens[1].toInt(); int patch = versiontokens[2].toInt(); bool newversion = false; if(major > MAJOR_VERSION) newversion = true; else if(major == MAJOR_VERSION) { if(minor > MINOR_VERSION) newversion = true; else if(minor == MINOR_VERSION) { if(patch > PATCH_VERSION) newversion = true; } } if(newversion) { int ignmajor = Settings::getValue("checkversion", "ignmajor").toInt(); int ignminor = Settings::getValue("checkversion", "ignminor").toInt(); int ignpatch = Settings::getValue("checkversion", "ignpatch").toInt(); // check if the user doesn't care about the current update if(!(ignmajor == major && ignminor == minor && ignpatch == patch)) { QMessageBox msgBox; QPushButton *idontcarebutton = msgBox.addButton(tr("Don't show again"), QMessageBox::ActionRole); msgBox.addButton(QMessageBox::Ok); msgBox.setTextFormat(Qt::RichText); msgBox.setWindowTitle(tr("New version available.")); msgBox.setText(tr("A new DB Browser for SQLite version is available (%1.%2.%3).

" "Please download at
%4.").arg(major).arg(minor).arg(patch). arg(url)); msgBox.exec(); if(msgBox.clickedButton() == idontcarebutton) { // save that the user don't want to get bothered about this update Settings::setValue("checkversion", "ignmajor", major); Settings::setValue("checkversion", "ignminor", minor); Settings::setValue("checkversion", "ignpatch", patch); } } } } void MainWindow::openLinkWiki() const { QDesktopServices::openUrl(QUrl("https://github.com/sqlitebrowser/sqlitebrowser/wiki")); } // 'Help | Bug Report...' link will set an appropriate body, add the system information and set the label 'bug' automatically to the issue void MainWindow::openLinkBugReport() const { const QString version = Application::versionString(); const QString os = QSysInfo::prettyProductName(); const QString kernelType = QSysInfo::kernelType(); const QString kernelVersion = QSysInfo::kernelVersion(); const QString arch = QSysInfo::currentCpuArchitecture(); const QString built_for = QSysInfo::buildAbi(); QString sqlite_version, sqlcipher_version; DBBrowserDB::getSqliteVersion(sqlite_version, sqlcipher_version); if(sqlcipher_version.isNull()) sqlite_version = QString("SQLite Version ") + sqlite_version; else sqlite_version = QString("SQLCipher Version ") + sqlcipher_version + QString(" (based on SQLite %1)").arg(sqlite_version); const QString body = QString("Details for the issue\n" "--------------------\n\n" "#### What did you do?\n\n\n" "#### What did you expect to see?\n\n\n" "#### What did you see instead?\n\n\n" "Useful extra information\n" "-------------------------\n" "> DB4S v%1 [built for %2] on %3 (%4/%5) [%6]\n" "> using %7\n" "> and Qt %8") .arg(version, built_for, os, kernelType, kernelVersion, arch, sqlite_version, QT_VERSION_STR); QUrlQuery query; query.addQueryItem("labels", "bug"); query.addQueryItem("body", body); QUrl url("https://github.com/sqlitebrowser/sqlitebrowser/issues/new"); url.setQuery(query); QDesktopServices::openUrl(url); } // 'Help | Feature Request...' link will set an appropriate body and add the label 'enhancement' automatically to the issue void MainWindow::openLinkFeatureRequest() const { QUrlQuery query; // Add the label enhancement and use the Feature request template that // we have in GitHub. query.addQueryItem("labels", "enhancement"); query.addQueryItem("template", "Feature_request.md"); QUrl url("https://github.com/sqlitebrowser/sqlitebrowser/issues/new"); url.setQuery(query); QDesktopServices::openUrl(url); } void MainWindow::openLinkSqlCipherFaq() const { QDesktopServices::openUrl(QUrl("https://discuss.zetetic.net/c/sqlcipher/sqlcipher-faq")); } void MainWindow::openLinkWebsite() const { QDesktopServices::openUrl(QUrl("https://sqlitebrowser.org")); } void MainWindow::openLinkDonatePatreon() const { QDesktopServices::openUrl(QUrl("https://www.patreon.com/bePatron?u=11578749")); } static void loadCondFormatMap(BrowseDataTableSettings::CondFormatMap& condFormats, QXmlStreamReader& xml, const QString& encoding) { const QStringRef name = xml.name(); while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != name) { if (xml.name() == "column") { size_t index = xml.attributes().value("index").toUInt(); while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "column") { if(xml.name() == "format") { QFont font; if (xml.attributes().hasAttribute("font")) font.fromString(xml.attributes().value("font").toString()); else Settings::getValue("databrowser", "font").toString(); CondFormat::Alignment align; if (xml.attributes().hasAttribute("align")) align = static_cast(xml.attributes().value("align").toInt()); else align = CondFormat::AlignLeft; condFormats[index].emplace_back(xml.attributes().value("condition").toString(), QColor(xml.attributes().value("foreground").toString()), QColor(xml.attributes().value("background").toString()), font, align, encoding); xml.skipCurrentElement(); } } } } } static void loadBrowseDataTableSettings(BrowseDataTableSettings& settings, sqlb::TablePtr obj, QXmlStreamReader& xml) { settings.showRowid = xml.attributes().value("show_row_id").toInt(); settings.encoding = xml.attributes().value("encoding").toString(); settings.plotXAxis = xml.attributes().value("plot_x_axis").toString(); settings.unlockViewPk = xml.attributes().value("unlock_view_pk").toString(); if(xml.attributes().hasAttribute("freeze_columns")) settings.frozenColumns = xml.attributes().value("freeze_columns").toUInt(); while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "table") { if(xml.name() == "sort") { while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "sort") { if(xml.name() == "column") { int index = xml.attributes().value("index").toInt(); int mode = xml.attributes().value("mode").toInt(); if(static_cast(index) < obj->fields.size()) settings.sortColumns.emplace_back(obj->fields.at(static_cast(index)).name(), mode == Qt::AscendingOrder ? sqlb::OrderBy::Ascending : sqlb::OrderBy::Descending); xml.skipCurrentElement(); } } } else if(xml.name() == "column_widths") { while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "column_widths") { if (xml.name() == "column") { int index = xml.attributes().value("index").toInt(); settings.columnWidths[index] = xml.attributes().value("value").toInt(); xml.skipCurrentElement(); } } } else if(xml.name() == "filter_values") { while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "filter_values") { if (xml.name() == "column") { size_t index = xml.attributes().value("index").toUInt(); QString value = xml.attributes().value("value").toString(); if(!value.isEmpty()) settings.filterValues[obj->fields.at(index).name()] = value; xml.skipCurrentElement(); } } } else if(xml.name() == "conditional_formats") { loadCondFormatMap(settings.condFormats, xml, settings.encoding); } else if(xml.name() == "row_id_formats") { loadCondFormatMap(settings.rowIdFormats, xml, settings.encoding); } else if(xml.name() == "display_formats") { while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "display_formats") { if (xml.name() == "column") { size_t index = xml.attributes().value("index").toUInt(); settings.displayFormats[index] = xml.attributes().value("value").toString(); xml.skipCurrentElement(); } } } else if(xml.name() == "hidden_columns") { while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "hidden_columns") { if (xml.name() == "column") { int index = xml.attributes().value("index").toInt(); settings.hiddenColumns[index] = xml.attributes().value("value").toInt(); xml.skipCurrentElement(); } } } else if(xml.name() == "plot_y_axes") { while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "plot_y_axes") { QString y1AxisName; QString y2AxisName; PlotDock::PlotSettings y1AxisSettings; PlotDock::PlotSettings y2AxisSettings; if (xml.name() == "y_axis") { y1AxisName = xml.attributes().value("name").toString(); y1AxisSettings.lineStyle = xml.attributes().value("line_style").toInt(); y1AxisSettings.pointShape = xml.attributes().value("point_shape").toInt(); y1AxisSettings.colour = QColor (xml.attributes().value("colour").toString()); y1AxisSettings.active = xml.attributes().value("active").toInt(); xml.skipCurrentElement(); } settings.plotYAxes[0][y1AxisName] = y1AxisSettings; if (xml.name() == "y2_axis") { y2AxisName = xml.attributes().value("name").toString(); y2AxisSettings.lineStyle = xml.attributes().value("line_style").toInt(); y2AxisSettings.pointShape = xml.attributes().value("point_shape").toInt(); y2AxisSettings.colour = QColor (xml.attributes().value("colour").toString()); y2AxisSettings.active = xml.attributes().value("active").toInt(); xml.skipCurrentElement(); } settings.plotYAxes[1][y2AxisName] = y2AxisSettings; } } else if(xml.name() == "global_filter") { while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "global_filter") { if(xml.name() == "filter") { QString value = xml.attributes().value("value").toString(); settings.globalFilters.push_back(value); xml.skipCurrentElement(); } } } } } MainWindow::LoadAttempResult MainWindow::loadProject(QString filename, bool readOnly) { // Show the open file dialog when no filename was passed as parameter if(filename.isEmpty()) { filename = FileDialog::getOpenFileName( OpenProjectFile, this, tr("Choose a project file to open"), tr("DB Browser for SQLite project file (*.sqbpro)")); } if(!filename.isEmpty()) { QFile file(filename); file.open(QFile::ReadOnly | QFile::Text); QXmlStreamReader xml(&file); xml.readNext(); // token == QXmlStreamReader::StartDocument xml.readNext(); // name == sqlb_project if(xml.name() != "sqlb_project") return NotValidFormat; // We are going to open a new project, so close the possible current one before opening another. // Stop the opening process here if the user pressed the cancel button in there. if(!closeFiles()) return Aborted; addToRecentFilesMenu(filename, readOnly); currentProjectFilename = filename; while(!xml.atEnd() && !xml.hasError()) { // Read next token QXmlStreamReader::TokenType token = xml.readNext(); // Handle element start if(token == QXmlStreamReader::StartElement) { if(xml.name() == "db") { // Read only? if(xml.attributes().hasAttribute("readonly") && xml.attributes().value("readonly").toInt()) readOnly = true; // DB file QString dbfilename = xml.attributes().value("path").toString(); if(!QFile::exists(dbfilename)) { dbfilename = QFileInfo(filename).absolutePath() + QDir::separator() + dbfilename; // New DB filename is pending to be saved isProjectModified = true; } if(!fileOpen(dbfilename, true, readOnly)) { qWarning() << tr("DB file '%1' could not be opened").arg(dbfilename); } ui->dbTreeWidget->collapseAll(); // PRAGMAs if(xml.attributes().hasAttribute("foreign_keys")) db.setPragma("foreign_keys", xml.attributes().value("foreign_keys").toString()); if(xml.attributes().hasAttribute("case_sensitive_like")) db.setPragma("case_sensitive_like", xml.attributes().value("case_sensitive_like").toString()); if(xml.attributes().hasAttribute("temp_store")) db.setPragma("temp_store", xml.attributes().value("temp_store").toString()); if(xml.attributes().hasAttribute("wal_autocheckpoint")) db.setPragma("wal_autocheckpoint", xml.attributes().value("wal_autocheckpoint").toString()); if(xml.attributes().hasAttribute("synchronous")) db.setPragma("synchronous", xml.attributes().value("synchronous").toString()); loadPragmas(); } else if(xml.name() == "attached") { while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "attached") { if(xml.name() == "db") { db.attach(xml.attributes().value("path").toString(), xml.attributes().value("schema").toString()); xml.skipCurrentElement(); } } } else if(xml.name() == "window") { // Window settings while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "window") { if(xml.name() == "main_tabs") { // Currently open tabs restoreOpenTabs(xml.attributes().value("open").toString()); // Currently selected open tab ui->mainTab->setCurrentIndex(xml.attributes().value("current").toString().toInt()); xml.skipCurrentElement(); } else if(xml.name() == "current_tab") { // Currently selected tab (3.11 or older format, first restore default open tabs) restoreOpenTabs(defaultOpenTabs); ui->mainTab->setCurrentIndex(xml.attributes().value("id").toString().toInt()); xml.skipCurrentElement(); } } } else if(xml.name() == "tab_structure") { // Database Structure tab settings while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_structure") { if(xml.name() == "column_width") { // Tree view column widths ui->dbTreeWidget->setColumnWidth(xml.attributes().value("id").toString().toInt(), xml.attributes().value("width").toString().toInt()); xml.skipCurrentElement(); } else if(xml.name() == "expanded_item") { // Tree view expanded items int parent = xml.attributes().value("parent").toString().toInt(); QModelIndex idx; if(parent == -1) idx = ui->dbTreeWidget->model()->index(xml.attributes().value("id").toString().toInt(), 0); else idx = ui->dbTreeWidget->model()->index(xml.attributes().value("id").toString().toInt(), 0, ui->dbTreeWidget->model()->index(parent, 0)); ui->dbTreeWidget->expand(idx); xml.skipCurrentElement(); } } } else if(xml.name() == "tab_browse") { // Close all open tabs first. We call delete here to avoid the // closed() signal being emitted which would open a new dock. for(auto d : allTableBrowserDocks()) delete d; // Browse Data tab settings while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_browse") { if(xml.name() == "current_table") { // TODO This attribute was only created until version 3.12.0 which means we can remove support for this // in the future. // Currently selected table QString table_name = xml.attributes().value("name").toString(); sqlb::ObjectIdentifier currentTable; if(!currentTable.fromSerialised(table_name.toStdString())) { // This is an old project file format which doesn't yet contain serialised table identifiers. This means // we have to try our best to unserialise this one manually. The only problem is when the name of an // attached database or of a table contains a dot character. In that case the name becomes ambigious and // we just try to split it at the first dot. I don't think it affects many (if any) project files. But if // it turn out to be wrong, we can always add a loop here which checks for any possible combination of schema // and table name whether an object with that combination exists. // TODO: Delete this code in the future when we don't expect there to be any project files in the old format anymore. if(table_name.contains('.')) { currentTable.setSchema(table_name.left(table_name.indexOf('.')).toStdString()); currentTable.setName(table_name.mid(table_name.indexOf('.')+1).toStdString()); } else { currentTable.setName(table_name.toStdString()); } } if (!currentTable.isEmpty()) newTableBrowserTab(currentTable); xml.skipCurrentElement(); } else if(xml.name() == "table") { // New browser tab sqlb::ObjectIdentifier table; table.fromSerialised(xml.attributes().value("table").toString().toStdString()); QDockWidget* dock = newTableBrowserTab(table); dock->setWindowTitle(xml.attributes().value("title").toString()); unsigned int dock_id = xml.attributes().value("dock_id").toUInt(); if(dock_id) dock->setObjectName("dockBrowse" + QString::number(dock_id)); if(xml.attributes().value("custom_title").toString() == "1") dock->setProperty("custom_title", true); xml.skipCurrentElement(); } else if(xml.name() == "dock_state") { // Dock state ui->tabBrowsers->restoreState(QByteArray::fromHex(xml.attributes().value("state").toString().toUtf8())); xml.skipCurrentElement(); } else if(xml.name() == "default_encoding") { // Default text encoding TableBrowser::setDefaultEncoding(xml.attributes().value("codec").toString()); xml.skipCurrentElement(); } else if(xml.name() == "browsetable_info") { // This tag is only found in old project files. In newer versions (>= 3.11) it is replaced by a new implementation. // 3.12 is the last version to support loading this file format, so just show a warning here. if(!Settings::getValue("idontcare", "projectBrowseTable").toBool()) { QMessageBox msgBox; QPushButton* idontcarebutton = msgBox.addButton(tr("Don't show again"), QMessageBox::ActionRole); msgBox.addButton(QMessageBox::Ok); msgBox.setTextFormat(Qt::RichText); msgBox.setWindowTitle(qApp->applicationName()); msgBox.setText(tr("This project file is using an old file format because it was created using DB Browser for SQLite " "version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load " "it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format.")); msgBox.exec(); if(msgBox.clickedButton() == idontcarebutton) Settings::setValue("idontcare", "projectBrowseTable", false); } xml.skipCurrentElement(); } else if(xml.name() == "browse_table_settings") { while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "browse_table_settings") { if (xml.name() == "table") { sqlb::ObjectIdentifier tableIdentifier = sqlb::ObjectIdentifier (xml.attributes().value("schema").toString().toStdString(), xml.attributes().value("name").toString().toStdString()); sqlb::TablePtr table = db.getTableByName(tableIdentifier); if(table == nullptr) { qWarning() << tr("Table '%1' not found; settings ignored") .arg(QString::fromStdString(tableIdentifier.toString())); } else { BrowseDataTableSettings settings; loadBrowseDataTableSettings(settings, table, xml); TableBrowser::setSettings(tableIdentifier, settings); } } } } else { xml.skipCurrentElement(); } } } else if(xml.name() == "tab_sql") { // Close all open tabs first for(int i=ui->tabSqlAreas->count()-1;i>=0;i--) closeSqlTab(i, true); // Execute SQL tab data while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_sql") { if(xml.name() == "sql") { // SQL editor tab int index = openSqlTab(); // if it has the filename attribute, it's a linked file, otherwise it's // a free SQL buffer saved in the project. if(xml.attributes().hasAttribute("filename")) { openSqlFile(index, xml.attributes().value("filename").toString()); xml.skipCurrentElement(); } else { ui->tabSqlAreas->setTabText(index, xml.attributes().value("name").toString()); SqlTextEdit* sqlEditor = qobject_cast(ui->tabSqlAreas->widget(index))->getEditor(); sqlEditor->setText(xml.readElementText()); sqlEditor->setModified(false); } } else if(xml.name() == "current_tab") { // Currently selected tab ui->tabSqlAreas->setCurrentIndex(xml.attributes().value("id").toString().toInt()); xml.skipCurrentElement(); } } } } } file.close(); if(ui->mainTab->currentWidget() == ui->browser) { refreshTableBrowsers(); // Refresh view } isProjectModified = false; return !xml.hasError()? Success : Aborted; } else { // No project was opened return Aborted; } } static void saveDbTreeState(const QTreeView* tree, QXmlStreamWriter& xml, QModelIndex index = QModelIndex(), int parent_row = -1) { for(int i=0;imodel()->rowCount(index);i++) { if(tree->isExpanded(tree->model()->index(i, 0, index))) { xml.writeStartElement("expanded_item"); xml.writeAttribute("id", QString::number(i)); xml.writeAttribute("parent", QString::number(parent_row)); xml.writeEndElement(); } saveDbTreeState(tree, xml, tree->model()->index(i, 0, index), i); } } static void saveCondFormatMap(const QString& elementName, const BrowseDataTableSettings::CondFormatMap& condFormats, QXmlStreamWriter& xml) { xml.writeStartElement(elementName); for(auto iter=condFormats.cbegin(); iter!=condFormats.cend(); ++iter) { xml.writeStartElement("column"); xml.writeAttribute("index", QString::number(iter->first)); for(const auto& format : iter->second) { xml.writeStartElement("format"); xml.writeAttribute("condition", format.filter()); xml.writeAttribute("background", format.backgroundColor().name()); xml.writeAttribute("foreground", format.foregroundColor().name()); xml.writeAttribute("font", format.font().toString()); xml.writeAttribute("align", QString().setNum(format.alignment())); xml.writeEndElement(); } xml.writeEndElement(); } xml.writeEndElement(); } static void saveBrowseDataTableSettings(const BrowseDataTableSettings& object, sqlb::TablePtr obj, QXmlStreamWriter& xml) { xml.writeAttribute("show_row_id", QString::number(object.showRowid)); xml.writeAttribute("encoding", object.encoding); xml.writeAttribute("plot_x_axis", object.plotXAxis); xml.writeAttribute("unlock_view_pk", object.unlockViewPk); xml.writeAttribute("freeze_columns", QString::number(object.frozenColumns)); xml.writeStartElement("sort"); for(const auto& column : object.sortColumns) { xml.writeStartElement("column"); xml.writeAttribute("index", QString::number(sqlb::getFieldNumber(obj, column.expr))); xml.writeAttribute("mode", QString::number(column.direction)); xml.writeEndElement(); } xml.writeEndElement(); xml.writeStartElement("column_widths"); for(auto iter=object.columnWidths.cbegin(); iter!=object.columnWidths.cend(); ++iter) { xml.writeStartElement("column"); xml.writeAttribute("index", QString::number(iter->first)); xml.writeAttribute("value", QString::number(iter->second)); xml.writeEndElement(); } xml.writeEndElement(); xml.writeStartElement("filter_values"); for(auto iter=object.filterValues.cbegin(); iter!=object.filterValues.cend(); ++iter) { xml.writeStartElement("column"); xml.writeAttribute("index", QString::number(sqlb::getFieldNumber(obj, iter->first))); xml.writeAttribute("value", iter->second); xml.writeEndElement(); } xml.writeEndElement(); saveCondFormatMap("conditional_formats", object.condFormats, xml); saveCondFormatMap("row_id_formats", object.rowIdFormats, xml); xml.writeStartElement("display_formats"); for(auto iter=object.displayFormats.cbegin(); iter!=object.displayFormats.cend(); ++iter) { xml.writeStartElement("column"); xml.writeAttribute("index", QString::number(iter->first)); xml.writeAttribute("value", iter->second); xml.writeEndElement(); } xml.writeEndElement(); xml.writeStartElement("hidden_columns"); for(auto iter=object.hiddenColumns.cbegin(); iter!=object.hiddenColumns.cend(); ++iter) { xml.writeStartElement("column"); xml.writeAttribute("index", QString::number(iter->first)); xml.writeAttribute("value", QString::number(iter->second)); xml.writeEndElement(); } xml.writeEndElement(); xml.writeStartElement("plot_y_axes"); for(auto iter=object.plotYAxes[0].cbegin(); iter!=object.plotYAxes[0].cend(); ++iter) { PlotDock::PlotSettings plotSettings = iter->second; xml.writeStartElement("y_axis"); xml.writeAttribute("name", iter->first); xml.writeAttribute("line_style", QString::number(plotSettings.lineStyle)); xml.writeAttribute("point_shape", QString::number(plotSettings.pointShape)); xml.writeAttribute("colour", plotSettings.colour.name()); xml.writeAttribute("active", QString::number(plotSettings.active)); xml.writeEndElement(); } for(auto iter=object.plotYAxes[1].cbegin(); iter!=object.plotYAxes[1].cend(); ++iter) { PlotDock::PlotSettings plotSettings = iter->second; xml.writeStartElement("y2_axis"); xml.writeAttribute("name", iter->first); xml.writeAttribute("line_style", QString::number(plotSettings.lineStyle)); xml.writeAttribute("point_shape", QString::number(plotSettings.pointShape)); xml.writeAttribute("colour", plotSettings.colour.name()); xml.writeAttribute("active", QString::number(plotSettings.active)); xml.writeEndElement(); } xml.writeEndElement(); xml.writeStartElement("global_filter"); for(const auto& v : object.globalFilters) { xml.writeStartElement("filter"); xml.writeAttribute("value", v); xml.writeEndElement(); } xml.writeEndElement(); } void MainWindow::saveProject(const QString& currentFilename) { QString filename; if(currentFilename.isEmpty()) { QString basePathName = db.currentFile(); // Remove database suffix basePathName.chop(QFileInfo(basePathName).suffix().size()+1); filename = FileDialog::getSaveFileName( CreateProjectFile, this, tr("Choose a filename to save under"), FILE_FILTER_SQLPRJ, basePathName); } else filename = currentFilename; if(!filename.isEmpty()) { // Make sure the file has got a .sqbpro ending if(!filename.endsWith(FILE_EXT_SQLPRJ_DEFAULT, Qt::CaseInsensitive)) filename.append(FILE_EXT_SQLPRJ_DEFAULT); QSaveFile file(filename); bool opened = file.open(QFile::WriteOnly | QFile::Text); if(!opened) { QMessageBox::warning(this, qApp->applicationName(), tr("Could not open project file for writing.\nReason: %1").arg(file.errorString())); currentProjectFilename.clear(); return; } currentProjectFilename = filename; QApplication::setOverrideCursor(Qt::WaitCursor); QXmlStreamWriter xml(&file); xml.writeStartDocument(); xml.writeStartElement("sqlb_project"); // Database file name xml.writeStartElement("db"); QFileInfo dbFileInfo (db.currentFile()); QFileInfo projectFileInfo (filename); // Store a relative filename if the path to project and to DB is the same. if(dbFileInfo.absolutePath() == projectFileInfo.absolutePath()) xml.writeAttribute("path", dbFileInfo.fileName()); else xml.writeAttribute("path", db.currentFile()); xml.writeAttribute("readonly", QString::number(db.readOnly())); xml.writeAttribute("foreign_keys", db.getPragma("foreign_keys")); xml.writeAttribute("case_sensitive_like", db.getPragma("case_sensitive_like")); xml.writeAttribute("temp_store", db.getPragma("temp_store")); xml.writeAttribute("wal_autocheckpoint", db.getPragma("wal_autocheckpoint")); xml.writeAttribute("synchronous", db.getPragma("synchronous")); xml.writeEndElement(); // Attached databases xml.writeStartElement("attached"); db.executeSQL("PRAGMA database_list;", false, true, [&xml](int, std::vector values, std::vector) -> bool { auto schema = values.at(1); if(schema != "main" && schema != "temp") { auto path = values.at(2); xml.writeStartElement("db"); xml.writeAttribute("schema", schema); xml.writeAttribute("path", path); xml.writeEndElement(); } return false; }); xml.writeEndElement(); // Window settings xml.writeStartElement("window"); xml.writeStartElement("main_tabs"); // Currently open tabs xml.writeAttribute("open", saveOpenTabs()); xml.writeAttribute("current", QString::number(ui->mainTab->currentIndex())); xml.writeEndElement(); xml.writeEndElement(); // Database Structure tab settings xml.writeStartElement("tab_structure"); for(int i=0;idbTreeWidget->model()->columnCount();i++) // Widths of tree view columns { xml.writeStartElement("column_width"); xml.writeAttribute("id", QString::number(i)); xml.writeAttribute("width", QString::number(ui->dbTreeWidget->columnWidth(i))); xml.writeEndElement(); } saveDbTreeState(ui->dbTreeWidget, xml); // Expanded tree items xml.writeEndElement(); // Browse Data tab settings xml.writeStartElement("tab_browse"); for(const auto d : allTableBrowserDocks()) { xml.writeStartElement("table"); xml.writeAttribute("title", d->windowTitle()); xml.writeAttribute("custom_title", d->property("custom_title").toBool() ? "1" : "0"); xml.writeAttribute("dock_id", d->objectName().mid(10)); // 10 is the length of "dockBrowse" xml.writeAttribute("table", QString::fromStdString(d->tableBrowser()->currentlyBrowsedTableName().toSerialised())); xml.writeEndElement(); } xml.writeStartElement("dock_state"); xml.writeAttribute("state", ui->tabBrowsers->saveState().toHex()); xml.writeEndElement(); xml.writeStartElement("default_encoding"); // Default encoding for text stored in tables xml.writeAttribute("codec", TableBrowser::defaultEncoding()); xml.writeEndElement(); xml.writeStartElement("browse_table_settings"); const auto settings = TableBrowser::allSettings(); for(auto tableIt=settings.cbegin(); tableIt!=settings.cend(); ++tableIt) { xml.writeStartElement("table"); xml.writeAttribute("schema", QString::fromStdString(tableIt->first.schema())); xml.writeAttribute("name", QString::fromStdString(tableIt->first.name())); auto obj = db.getTableByName(tableIt->first); saveBrowseDataTableSettings(tableIt->second, obj, xml); xml.writeEndElement(); } // xml.writeEndElement(); // xml.writeEndElement(); // Execute SQL tab data xml.writeStartElement("tab_sql"); for(int i=0;itabSqlAreas->count();i++) // All SQL tabs content { SqlExecutionArea* sqlArea = qobject_cast(ui->tabSqlAreas->widget(i)); QString sqlFilename = sqlArea->fileName(); xml.writeStartElement("sql"); xml.writeAttribute("name", ui->tabSqlAreas->tabText(i)); if(sqlFilename.isEmpty()) { xml.writeCharacters(sqlArea->getSql()); sqlArea->getEditor()->setModified(false); } else { xml.writeAttribute("filename", sqlFilename); // Backwards compatibility, so older versions do not break. xml.writeCharacters(tr("-- Reference to file \"%1\" (not supported by this version) --").arg(sqlFilename)); } xml.writeEndElement(); } xml.writeStartElement("current_tab"); // Currently selected tab xml.writeAttribute("id", QString::number(ui->tabSqlAreas->currentIndex())); xml.writeEndElement(); xml.writeEndElement(); xml.writeEndElement(); xml.writeEndDocument(); file.commit(); addToRecentFilesMenu(filename); setCurrentFile(db.currentFile()); isProjectModified = false; showStatusMessage5s(tr("Project saved to file '%1'").arg(currentProjectFilename)); QApplication::restoreOverrideCursor(); } } void MainWindow::saveProject() { saveProject(currentProjectFilename); } void MainWindow::saveProjectAs() { saveProject(QString()); } void MainWindow::fileAttach(const QString& fileName) { QString file; if (fileName.isEmpty()) { // Get file name of database to attach file = FileDialog::getOpenFileName( OpenDatabaseFile, this, tr("Choose a database file"), FileDialog::getSqlDatabaseFileFilter()); } else file = fileName; if(!QFile::exists(file)) return; // Attach it db.attach(file); isProjectModified = true; } void MainWindow::editEncryption() { #ifdef ENABLE_SQLCIPHER CipherDialog cipherDialog(this, true); if(cipherDialog.exec()) { // Show progress dialog even though we can't provide any detailed progress information but this // process might take some time. QProgressDialog progress(this); progress.setCancelButton(nullptr); // Disable context help button on Windows progress.setWindowFlags(progress.windowFlags() & ~Qt::WindowContextHelpButtonHint); progress.setWindowModality(Qt::ApplicationModal); progress.show(); qApp->processEvents(); // Apply all unsaved changes bool ok = db.releaseAllSavepoints(); qApp->processEvents(); const QString temporalFile = db.currentFile() + ".enctemp"; // Create the new file first or it won't work if(ok) { QFile file(temporalFile); file.open(QFile::WriteOnly); file.close(); } CipherSettings cipherSettings = cipherDialog.getCipherSettings(); // Attach a new database using the new settings qApp->processEvents(); if(ok) ok = db.executeSQL("ATTACH DATABASE '" + temporalFile.toStdString() + "' AS sqlitebrowser_edit_encryption KEY " + cipherSettings.getPassword() + ";", false, false); qApp->processEvents(); if(ok) ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_page_size = " + std::to_string(cipherSettings.getPageSize()), false, false); if(ok) ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_hmac_algorithm = " + cipherSettings.getHmacAlgorithm(), false, false); if(ok) ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_kdf_algorithm = " + cipherSettings.getKdfAlgorithm(), false, false); if(ok) ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.kdf_iter = " + std::to_string(cipherSettings.getKdfIterations()), false, false); if (ok) ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_plaintext_header_size = " + std::to_string(cipherSettings.getPlaintextHeaderSize()), false, false); // Export the current database to the new one qApp->processEvents(); if(ok) ok = db.executeSQL("SELECT sqlcipher_export('sqlitebrowser_edit_encryption');", false, false); // Set user version of the new database qApp->processEvents(); if (ok) ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.user_version = " + std::to_string(db.getPragma("user_version").toInt()) + ";", false, false); // We need to detach the database before proceeding qApp->processEvents(); if (ok) ok = db.executeSQL("DETACH sqlitebrowser_edit_encryption;", false, false); // Check for errors qApp->processEvents(); if(ok) { // No errors: Then close the current database, switch names, open the new one and if that succeeded delete the old one const QString currentFile = db.currentFile(); fileClose(); QFile::rename(currentFile, temporalFile + "old"); QFile::rename(temporalFile, currentFile); if(fileOpen(currentFile)) QFile::remove(temporalFile + "old"); } else { QMessageBox::warning(this, qApp->applicationName(), db.lastError()); } } #endif } void MainWindow::switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse) { // If no table name was provided get the currently selected table fromt he structure tab if(tableToBrowse.isEmpty()) { // Cancel here if there is no selection if(!dbSelected->hasSelection()) return; tableToBrowse.setSchema(dbSelected->schema().toStdString()); tableToBrowse.setName(dbSelected->name().toStdString()); } TableBrowserDock* d = newTableBrowserTab(tableToBrowse); if (ui->mainTab->indexOf(ui->browser) == -1) ui->mainTab->addTab(ui->browser, ui->browser->accessibleName()); // Don't emit a main tab changed signal here because all it would do is refreshing the just loaded table view ui->mainTab->blockSignals(true); ui->mainTab->setCurrentWidget(ui->browser); ui->mainTab->blockSignals(false); // Bring new tab to foreground Application::processEvents(); // For some reason this is required for raise() to work here. d->raise(); } void MainWindow::fileDetachDbTree() { fileDetachTreeViewSelected(ui->dbTreeWidget); } void MainWindow::fileDetachTreeSchemaDock() { fileDetachTreeViewSelected(ui->treeSchemaDock); } void MainWindow::fileDetachTreeViewSelected(QTreeView* treeView) { // Cancel here if there is no selection if (!treeView || !treeView->selectionModel()->hasSelection()) { return; } // get the currently selected attached database from treeView parameter std::string attached_as = treeView->model()->data(treeView->currentIndex().sibling(treeView->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(); if (db.detach(attached_as)) { db.updateSchema(); refreshTableBrowsers(/* all */ true); isProjectModified = true; } } void MainWindow::copyCurrentCreateStatement() { // Cancel if no field is currently selected if(!dbSelected->hasSelection()) return; // Get the CREATE statement from the SQL column QString stmt = dbSelected->sql(); // Copy the statement to the global application clipboard QApplication::clipboard()->setText(stmt); } void MainWindow::fileOpenReadOnly() { // Redirect to 'standard' fileOpen(), with the read only flag set fileOpen(QString(), false, true); } void MainWindow::requestCollation(const QString& name, int eTextRep) { // Show message box if(!Settings::getValue("db", "dont_ask_collation").toBool()) { QMessageBox msgbox; QPushButton* button_dont_ask_again = msgbox.addButton(tr("Yes. Don't ask again"), QMessageBox::ActionRole); msgbox.addButton(QMessageBox::Yes); msgbox.addButton(QMessageBox::No); msgbox.setTextFormat(Qt::RichText); msgbox.setWindowTitle(tr("Collation needed! Proceed?")); msgbox.setText(tr("A table in this database requires a special collation function '%1' " "that this application can't provide without further knowledge.\n" "If you choose to proceed, be aware bad things can happen to your database.\n" "Create a backup!").arg(name)); int reply = msgbox.exec(); // Remember Don't ask again setting and proceed if either that button or the Yes button was clicked. // Cancel here if the No button was clicked if(msgbox.clickedButton() == button_dont_ask_again) { Settings::setValue("db", "dont_ask_collation", false); } else if(reply == QMessageBox::No) { return; } } // Add collation auto pDb = db.get(tr("creating collation")); sqlite3_create_collation(pDb.get(), name.toUtf8(), eTextRep, nullptr, collCompare); } void MainWindow::renameSqlTab(int index) { QString new_name = QInputDialog::getText(this, qApp->applicationName(), tr("Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut."), QLineEdit::EchoMode::Normal, ui->tabSqlAreas->tabText(index)); if(!new_name.isNull()) // Don't do anything if the Cancel button was clicked ui->tabSqlAreas->setTabText(index, new_name); } void MainWindow::setFindFrameVisibility(bool show) { // Set the find frame visibility for all tabs, but leave the // current as the last, to retain there the focus. for(int i=0;itabSqlAreas->count();i++) if (i != ui->tabSqlAreas->currentIndex()) qobject_cast(ui->tabSqlAreas->widget(i))->setFindFrameVisibility(show); if (ui->tabSqlAreas->count()>0) qobject_cast(ui->tabSqlAreas->currentWidget())->setFindFrameVisibility(show); } void MainWindow::openFindReplaceDialog() { // The slot for the shortcut must discover which sqltexedit widget has the focus and then open its dialog. SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); if (sqlWidget) sqlWidget->getEditor()->openFindReplaceDialog(); } void MainWindow::toggleSqlBlockComment() { // The slot for the shortcut must discover which sqltexedit widget has the focus SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); if (sqlWidget) sqlWidget->getEditor()->toggleBlockComment(); } void MainWindow::openSqlPrintDialog() { // The slot for the shortcut must discover which sqltexedit widget has the focus and then open its dialog. SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); if (sqlWidget) sqlWidget->getEditor()->openPrintDialog(); } void MainWindow::saveAsView(const std::string& query) { // Let the user select a name for the new view and make sure it doesn't already exist QString name; while(true) { name = QInputDialog::getText(this, qApp->applicationName(), tr("Please specify the view name")).trimmed(); if(name.isNull()) return; if(db.getTableByName(sqlb::ObjectIdentifier("main", name.toStdString()))) QMessageBox::warning(this, qApp->applicationName(), tr("There is already an object with that name. Please choose a different name.")); else break; } // Create the view if(db.executeSQL("CREATE VIEW " + sqlb::escapeIdentifier(name.toStdString()) + " AS " + query + ";")) QMessageBox::information(this, qApp->applicationName(), tr("View successfully created.")); else QMessageBox::warning(this, qApp->applicationName(), tr("Error creating view: %1").arg(db.lastError())); } void MainWindow::runSqlNewTab(const QString& query, const QString& title, const QString& helpUrl, const bool autoRun) { QString message; if(autoRun) message = tr("This action will open a new SQL tab for running:"); else message = tr("This action will open a new SQL tab with the following statements for you to edit and run:"); message += QString("
%1
").arg(query.size() > 1000 ? query.left(1000) + "\n[...]" : query); if(!helpUrl.isEmpty()) message += tr("Press Help for opening the corresponding SQLite reference page."); QString windowTitle = title; windowTitle.remove('&'); auto result = QMessageBox::information(this, windowTitle, message, QMessageBox::Ok | QMessageBox::Default, QMessageBox::Cancel | QMessageBox::Escape, helpUrl.isEmpty() ? 0 : QMessageBox::Help); switch (result) { case QMessageBox::Ok: { if (ui->mainTab->indexOf(ui->query) == -1) ui->mainTab->addTab(ui->query, ui->query->accessibleName()); ui->mainTab->setCurrentWidget(ui->query); int index = openSqlTab(); ui->tabSqlAreas->setTabText(index, title); qobject_cast(ui->tabSqlAreas->widget(index))->getEditor()->setText(query); if(autoRun) executeQuery(); break; } case QMessageBox::Help: { QDesktopServices::openUrl(QUrl(helpUrl)); break; } default: return; } } void MainWindow::printDbStructure () { const QTreeView* treeView = ui->dbTreeWidget; const QAbstractItemModel* model = treeView->model(); const int rowCount = model->rowCount(treeView->rootIndex()); const int columnCount = model->columnCount(treeView->rootIndex()); QString strStream; QTextStream out(&strStream); out << "" << QString("%1").arg(treeView->windowTitle()) << ""; for (int row = 0; row < rowCount; row++) { QModelIndex headerIndex = model->index(row, 0, treeView->rootIndex()); QString strData = model->data(headerIndex).toString().toHtmlEscaped(); out << QString("

%1

").arg(strData); // Open a new table for each group of objects out << ""; for (int column = 0; column < columnCount; column++) { // Headers if (!treeView->isColumnHidden(column)) out << QString("").arg(model->headerData(column, Qt::Horizontal).toString().toHtmlEscaped()); } out << ""; for (int column = 0; column < columnCount; column++) { QModelIndex groupIndex = model->index(row, column, treeView->rootIndex()); // A row for the object name for (int rowChild = 0; rowChild < model->rowCount(groupIndex); rowChild++) { QModelIndex objectIndex = model->index(rowChild, column, groupIndex); out << ""; for (int column2 = 0; column2 < columnCount; column2++) { if (!treeView->isColumnHidden(column2)) { QModelIndex cellIndex = model->index(rowChild, column2, groupIndex); QString header_data = model->data(cellIndex).toString().toHtmlEscaped(); if (column2 != DbStructureModel::ColumnSQL) out << QString("").arg((!header_data.isEmpty()) ? header_data : QString(" ")); else out << QString("").arg((!header_data.isEmpty()) ? header_data : QString(" ")); } } out << ""; // One row for each object's fields for (int rowChild2 = 0; rowChild2 < model->rowCount(objectIndex); rowChild2++) { out << ""; for (int column2 = 0; column2 < columnCount; column2++) { if (!treeView->isColumnHidden(column2)) { QModelIndex fieldIndex = model->index(rowChild2, column2, objectIndex); QString field_data = model->data(fieldIndex).toString().toHtmlEscaped(); out << QString("").arg((!field_data.isEmpty()) ? field_data : QString(" ")); } } out << ""; } } } out << "
%1

%1

%1
%1
"; } out << ""; QPrinter printer; printer.setDocName(treeView->windowTitle()); QPrintPreviewDialog *dialog = new QPrintPreviewDialog(&printer); connect(dialog, &QPrintPreviewDialog::paintRequested, this, [strStream](QPrinter *previewPrinter) { QTextDocument document; document.setHtml(strStream); document.print(previewPrinter); }); dialog->exec(); delete dialog; } void MainWindow::updateDatabaseBusyStatus(bool busy, const QString& user) { statusBusyLabel->setText(tr("Busy (%1)").arg(user)); statusBusyLabel->setVisible(busy); statusStopButton->setVisible(busy); } void MainWindow::closeTab(int index) { ui->mainTab->removeTab(index); } void MainWindow::toggleTabVisible(QWidget* tabWidget, bool show) { if (show) ui->mainTab->addTab(tabWidget, tabWidget->accessibleName()); else ui->mainTab->removeTab(ui->mainTab->indexOf(tabWidget)); } void MainWindow::restoreOpenTabs(QString tabs) { // Split the tab list, skipping the empty parts so the empty string turns to an empty list // and not a list of one empty string. #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) const QStringList tabList = tabs.split(' ', QString::SkipEmptyParts); #else const QStringList tabList = tabs.split(' ', Qt::SkipEmptyParts); #endif // Clear the tabs and then add them in the order specified by the setting. // Use the accessibleName attribute for restoring the tab label. if (!tabList.isEmpty()) { // Avoid flickering while clearing and adding tabs. ui->mainTab->setUpdatesEnabled(false); ui->mainTab->clear(); for (const auto& objectName : tabList) { for (QWidget* widget : {ui->structure, ui->browser, ui->pragmas, ui->query}) if (widget->objectName() == objectName) { ui->mainTab->addTab(widget, widget->accessibleName()); break; } } ui->mainTab->setUpdatesEnabled(true); // Force the update of the View menu toggable entries // (it doesn't seem to be a better way) emit ui->mainTab->tabCloseRequested(-1); } } QString MainWindow::saveOpenTabs() { QString openTabs; for (int i=0; i < ui->mainTab->count(); i++) openTabs.append(ui->mainTab->widget(i)->objectName() + ' '); openTabs.chop(1); return openTabs; } void MainWindow::showStatusMessage5s(QString message) { ui->statusbar->showMessage(message, 5000); } void MainWindow::saveAll() { for(int i=0; itabSqlAreas->count(); i++) { SqlExecutionArea* sqlExecArea = qobject_cast(ui->tabSqlAreas->widget(i)); if(sqlExecArea->getEditor()->isModified() && !sqlExecArea->fileName().isEmpty()) saveSqlFile(i); } if(!currentProjectFilename.isEmpty()) saveProject(); fileSave(); } void MainWindow::showContextMenuSqlTabBar(const QPoint& pos) { // Don't show context menu if the mouse click was outside of all the tabs int tab = ui->tabSqlAreas->tabBar()->tabAt(pos); if(tab == -1) return; // Prepare all menu actions QAction* actionRename = new QAction(this); actionRename->setText(tr("Rename Tab")); connect(actionRename, &QAction::triggered, this, [this, tab]() { renameSqlTab(tab); }); QAction* actionDuplicate = new QAction(this); actionDuplicate->setText(tr("Duplicate Tab")); connect(actionDuplicate, &QAction::triggered, this, [this, tab]() { QString tab_name = ui->tabSqlAreas->tabText(tab).remove("&").remove(QRegExp(" \\(\\d+\\)$")); QString new_tab_name; for(int i=1;;i++) { new_tab_name = tab_name + QString(" (%1)").arg(i); bool name_already_exists = false; for(int j=0;jtabSqlAreas->count();j++) { if(ui->tabSqlAreas->tabText(j).remove("&") == new_tab_name) { name_already_exists = true; break; } } if(!name_already_exists) break; } int new_tab = openSqlTab(); ui->tabSqlAreas->setTabText(new_tab, new_tab_name); SqlExecutionArea* old_area = qobject_cast(ui->tabSqlAreas->widget(tab)); SqlExecutionArea* new_area = qobject_cast(ui->tabSqlAreas->widget(new_tab)); new_area->setSql(old_area->getSql()); }); QAction* actionClose = new QAction(this); actionClose->setText(tr("Close Tab")); actionClose->setShortcut(tr("Ctrl+W")); connect(actionClose, &QAction::triggered, this, [this, tab]() { closeSqlTab(tab); }); // Show menu QMenu* menuTabs = new QMenu(this); menuTabs->addAction(actionRename); menuTabs->addAction(actionDuplicate); menuTabs->addAction(actionClose); menuTabs->exec(ui->tabSqlAreas->mapToGlobal(pos)); } void MainWindow::openUrlOrFile(const QString& urlString) { QUrl url = QUrl::fromUserInput(urlString, QFileInfo(db.currentFile()).path(), QUrl::AssumeLocalFile); if(url.isValid()) { if(QDesktopServices::openUrl(url)) showStatusMessage5s(tr("Opening '%1'...").arg(url.toDisplayString())); else showStatusMessage5s(tr("There was an error opening '%1'...").arg(url.toDisplayString())); } else showStatusMessage5s(tr("Value is not a valid URL or filename: %1").arg(url.errorString())); } void MainWindow::focusSqlEditor() { SqlExecutionArea* sqlArea = qobject_cast(ui->tabSqlAreas->currentWidget()); if(sqlArea) sqlArea->getEditor()->setFocus(); } void MainWindow::moveDocksTo(Qt::DockWidgetArea area) { addDockWidget(area, ui->dockEdit); addDockWidget(area, ui->dockLog); tabifyDockWidget(ui->dockLog, ui->dockPlot); tabifyDockWidget(ui->dockLog, ui->dockSchema); tabifyDockWidget(ui->dockLog, ui->dockRemote); } void MainWindow::clearRecentFiles() { Settings::clearValue("General", "recentFileList"); for(int i=0; i < MaxRecentFiles; ++i) recentFileActs[i]->setVisible(false); } sqlb::ObjectIdentifier MainWindow::currentlyBrowsedTableName() const { if(currentTableBrowser) return currentTableBrowser->currentlyBrowsedTableName(); else return sqlb::ObjectIdentifier{}; } void MainWindow::tableBrowserTabClosed() { // The closed() signal is emitted before the dock is destroyed. Since we // always want to have at least one dock open we need to check if this is // the last dock which is closed instead of if there is no dock remaining. if(allTableBrowserDocks().size() == 1) { newTableBrowserTab({}, /* forceHideTitlebar */ true); } else { // If only one dock will be left, make sure its titlebar is hidden, // unless it's floating, so it can be closed or restored. if(allTableBrowserDocks().size() == 2) { for(auto dock : allTableBrowserDocks()) if(!dock->isFloating()) dock->setTitleBarWidget(new QWidget(dock)); } // If the currently active tab is closed activate another tab if(currentTableBrowser && sender() == currentTableBrowser->parent()) { auto all_docks = allTableBrowserDocks(); all_docks.front()->activateWindow(); changeTableBrowserTab(all_docks.front()); } } } TableBrowserDock* MainWindow::newTableBrowserTab(const sqlb::ObjectIdentifier& tableToBrowse, bool forceHideTitleBar) { // Prepare new dock TableBrowserDock* d = new TableBrowserDock(ui->tabBrowsers, this); connect(d, &TableBrowserDock::closed, this, &MainWindow::tableBrowserTabClosed); // Initialise widget d->tableBrowser()->setStructure(dbStructureModel, tableToBrowse); d->tableBrowser()->setEnabled(ui->fileCloseAction->isEnabled()); // Connect signals and slots connect(d, &TableBrowserDock::newDockRequested, this, [this]() { newTableBrowserTab(); }); connect(d->tableBrowser(), &TableBrowser::projectModified, this, [this]() { isProjectModified = true; }); connect(d->tableBrowser()->model(), &SqliteTableModel::dataChanged, this, &MainWindow::dataTableSelectionChanged); connect(d->tableBrowser(), &TableBrowser::dataAboutToBeEdited, this, &MainWindow::dataTableSelectionChanged); connect(d->tableBrowser(), &TableBrowser::selectionChanged, this, &MainWindow::dataTableSelectionChanged); connect(d->tableBrowser(), &TableBrowser::selectionChangedByDoubleClick, this, &MainWindow::doubleClickTable); connect(d->tableBrowser(), &TableBrowser::updatePlot, this, &MainWindow::attachPlot); connect(d->tableBrowser(), &TableBrowser::createView, this, &MainWindow::saveAsView); connect(d->tableBrowser(), &TableBrowser::requestFileOpen, this, [this](const QString& file) { fileOpen(file); }); connect(d->tableBrowser(), &TableBrowser::statusMessageRequested, ui->statusbar, [this](const QString& message) { ui->statusbar->showMessage(message); }); connect(d->tableBrowser(), &TableBrowser::foreignKeyClicked, this, [this](const sqlb::ObjectIdentifier& table, const std::string& column, const QByteArray& value) { TableBrowserDock* foreign_key_dock = newTableBrowserTab(table); foreign_key_dock->tableBrowser()->jumpToRow(table, column, value); Application::processEvents(); // For some reason this is required for raise() to work here. foreign_key_dock->raise(); }); connect(d->tableBrowser()->model(), &SqliteTableModel::finishedFetch, this, [this, d](){ auto& settings = d->tableBrowser()->settings(d->tableBrowser()->currentlyBrowsedTableName()); plotDock->updatePlot(d->tableBrowser()->model(), &settings, true, false); }); connect(d->tableBrowser(), &TableBrowser::prepareForFilter, editDock, &EditDialog::promptSaveData); // Restore titlebar for any other widget for(auto dock : allTableBrowserDocks()) dock->setTitleBarWidget(nullptr); // Hide titlebar if it is the only one dock if(allTableBrowserDocks().size() == 1 || forceHideTitleBar) d->setTitleBarWidget(new QWidget(d)); // Set up dock and add it to the tab ui->tabBrowsers->addDockWidget(Qt::TopDockWidgetArea, d); if(allTableBrowserDocks().size() > 1) #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) ui->tabBrowsers->tabifyDockWidget(allTableBrowserDocks().front(), d); #else ui->tabBrowsers->tabifyDockWidget(allTableBrowserDocks().constFirst(), d); #endif // Set current model and browser d->activateWindow(); changeTableBrowserTab(d); d->tableBrowser()->refresh(); return d; } void MainWindow::changeTableBrowserTab(TableBrowserDock* dock) { currentTableBrowser = dock->tableBrowser(); if(dock->tableBrowser() && dock->tableBrowser()->model() != m_currentTabTableModel) { // Make sure only the title of the active dock is highlighted for(auto d : allTableBrowserDocks()) d->setFocusStyle(false); dock->setFocusStyle(true); m_currentTabTableModel = dock->tableBrowser()->model(); const auto current_table_name = dock->tableBrowser()->currentlyBrowsedTableName(); if(!current_table_name.isEmpty()) plotDock->updatePlot(m_currentTabTableModel, &dock->tableBrowser()->settings(current_table_name), true, false); } } QList MainWindow::allTableBrowserDocks() const { return ui->tabBrowsers->findChildren(); } void MainWindow::newRowCountsTab() { QString sql; for(const auto& it : db.schemata["main"].tables) { sql += QString("SELECT %1 AS \"name\", '%2' AS \"type\", COUNT(*) AS \"rows\" FROM %3\nUNION ").arg( QString::fromStdString(sqlb::escapeString(it.first)), QString::fromStdString(it.second->isView() ? "view" : "table"), QString::fromStdString(sqlb::escapeIdentifier(it.first))); } sql.chop(7); // Remove the last "\nUNION " at the end runSqlNewTab(sql, ui->actionRowCounts->text()); } void MainWindow::toggleAutoLoadLastDBFileAtStartupOption() { optionToAutoLoadLastDBFileAtStartup->isChecked() ? Settings::setValue("General", "autoLoadLastDBFileAtStartup", true) : Settings::setValue("General", "autoLoadLastDBFileAtStartup", false); } sqlitebrowser-sqlitebrowser-5733cb7/src/MainWindow.h000066400000000000000000000176321463772530400227210ustar00rootroot00000000000000#ifndef MAINWINDOW_H #define MAINWINDOW_H #include "dbstructureqitemviewfacade.h" #include "sqlitedb.h" #include #include #include struct BrowseDataTableSettings; class DbStructureModel; class EditDialog; class ExtendedTableWidget; class FindReplaceDialog; class PlotDock; class RemoteDock; class RunSql; class SqliteTableModel; class TableBrowser; class TableBrowserDock; class QDragEnterEvent; class QModelIndex; class QLabel; class QPersistentModelIndex; class QToolButton; namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT friend TableBrowserDock; public: explicit MainWindow(QWidget* parent = nullptr); ~MainWindow() override; DBBrowserDB& getDb() { return db; } private: enum LoadAttempResult { Success, NotValidFormat, Aborted }; struct PragmaValues { int autovacuum; int automatic_index; int checkpoint_fullsync; int foreign_keys; int fullfsync; int ignore_check_constraints; QString journal_mode; int journal_size_limit; QString locking_mode; int max_page_count; int page_size; int recursive_triggers; int secure_delete; int synchronous; int temp_store; int user_version; int wal_autocheckpoint; int case_sensitive_like; } pragmaValues; Ui::MainWindow* ui; DBBrowserDB db; SqliteTableModel* m_currentTabTableModel; QMenu* popupTableMenu; QMenu* popupSchemaDockMenu; QMenu* recentFilesMenu; QMenu* popupOpenDbMenu; QMenu* popupSaveSqlFileMenu; QMenu* popupSaveSqlResultsMenu; QLabel* statusEncodingLabel; QLabel* statusEncryptionLabel; QLabel* statusReadOnlyLabel; QToolButton* statusStopButton; QLabel* statusBusyLabel; DbStructureModel* dbStructureModel; static int MaxRecentFiles; QVector recentFileActs; QAction* clearRecentFilesAction; QAction* optionToAutoLoadLastDBFileAtStartup; QAction* recentSeparatorAct; /** * @brief dbSelected provides a simple read only interface to the actual selected node of ui->dbTreeWidget */ DbStructureQItemViewFacade *dbSelected; /** * @brief dockDbSelected provides a simple read only interface to the actual selected node of ui->treeSchemaDock */ DbStructureQItemViewFacade *dockDbSelected; EditDialog* editDock; PlotDock* plotDock; RemoteDock* remoteDock; TableBrowser* currentTableBrowser; FindReplaceDialog* findReplaceDialog; std::unique_ptr execute_sql_worker; QString defaultOpenTabs; QByteArray defaultWindowState; QString currentProjectFilename; bool isProjectModified; void init(); void clearCompleterModelsFields(); void updateRecentFileActions(); void clearRecentFiles(); void toggleAutoLoadLastDBFileAtStartupOption(); void setCurrentFile(const QString& fileName); void addToRecentFilesMenu(const QString& filename, bool read_only = false); void activateFields(bool enable = true); void saveAsView(const std::string& query); void attachPlot(ExtendedTableWidget* tableWidget, SqliteTableModel* model, BrowseDataTableSettings* settings = nullptr, bool keepOrResetSelection = true); void toggleTabVisible(QWidget* tabWidget, bool show); void restoreOpenTabs(QString tabs); QString saveOpenTabs(); void saveProject(const QString& currentFilename); bool closeProject(); bool askSaveSqlTab(int index, bool& ignoreUnattachedBuffers); void focusSqlEditor(); void moveDocksTo(Qt::DockWidgetArea area); // Identifier of the currently browsed table in the current data browser tab sqlb::ObjectIdentifier currentlyBrowsedTableName() const; QList allTableBrowserDocks() const; protected: void closeEvent(QCloseEvent *) override; void dragEnterEvent(QDragEnterEvent *event) override; void dropEvent(QDropEvent *event) override; void resizeEvent(QResizeEvent *event) override; public slots: bool fileOpen(const QString& fileName = QString(), bool openFromProject = false, bool readOnly = false); void logSql(const QString &sql, int msgtype); void dbState(bool dirty); void refresh(); void switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse = sqlb::ObjectIdentifier()); void populateStructure(const std::vector& old_tables = {}); void fileDetachDbTree(); void fileDetachTreeSchemaDock(); void fileDetachTreeViewSelected(QTreeView* treeView); void reloadSettings(); bool closeFiles(); void importCSVfiles(const std::vector& inputFiles, const QString& table = QString()); private slots: void createTreeContextMenu(const QPoint & qPoint); void createSchemaDockContextMenu(const QPoint & qPoint); void changeTreeSelection(); void fileNew(); void fileNewInMemoryDatabase(bool open_create_dialog = true); // Refresh visible table browsers. When all is true, refresh all browsers. void refreshTableBrowsers(bool all = false); bool fileClose(); bool fileSaveAs(); void createTable(); void createIndex(); void compact(); void deleteObject(); void editObject(); void helpWhatsThis(); void helpAbout(); void updateRecordText(const QPersistentModelIndex& idx, const QByteArray& text, bool isBlob); void evaluateText(const QPersistentModelIndex& idx, const std::string& text); void toggleEditDock(bool visible); void dataTableSelectionChanged(const QModelIndex& index); void doubleClickTable(const QModelIndex& index); void executeQuery(); void importTableFromCSV(); void exportTableToCSV(); void exportTableToJson(); void fileSave(); void fileRevert(); void undo(); void exportDatabaseToSQL(); void importDatabaseFromSQL(); void openRecentFile(); void loadPragmas(); void updatePragmaUi(); void savePragmas(); void mainTabSelected( int tabindex ); void openSqlFile(int tabindex, QString filename); void openSqlFile(); void saveSqlFile(); void saveSqlFileAs(); void saveSqlResultsAsCsv(); void saveSqlResultsAsJson(); void saveSqlResultsAsView(); void loadExtension(); void checkNewVersion(const QString& versionstring, const QString& url); void openLinkWiki() const; void openLinkBugReport() const; void openLinkFeatureRequest() const; void openLinkSqlCipherFaq() const; void openLinkWebsite() const; void openLinkDonatePatreon() const; LoadAttempResult loadProject(QString filename = QString(), bool readOnly = false); void saveProject(); void saveProjectAs(); void fileAttach(const QString& fileName = QString()); void editEncryption(); void copyCurrentCreateStatement(); void fileOpenReadOnly(); void requestCollation(const QString& name, int eTextRep); void setFindFrameVisibility(bool show); void openFindReplaceDialog(); void toggleSqlBlockComment(); void openSqlPrintDialog(); void runSqlNewTab(const QString& query, const QString& title, const QString& helpUrl = QString(), const bool autoRun = true); void printDbStructure(); void updateDatabaseBusyStatus(bool busy, const QString& user); void openPreferences(); void closeTab(int index); void showStatusMessage5s(QString message); void saveSqlFile(int tabIndex); void saveAll(); void openUrlOrFile(const QString& urlString); void newRowCountsTab(); int openSqlTab(bool resetCounter = false); void closeSqlTab(int index, bool force = false, bool askSaving = true); void changeSqlTab(int index); void renameSqlTab(int index); void showContextMenuSqlTabBar(const QPoint& pos); TableBrowserDock* newTableBrowserTab(const sqlb::ObjectIdentifier& tableToBrowse = {}, bool forceHideTitleBar = false); void tableBrowserTabClosed(); void changeTableBrowserTab(TableBrowserDock* dock); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/MainWindow.ui000066400000000000000000003540231463772530400231050ustar00rootroot00000000000000 MainWindow 0 0 1037 630 DB Browser for SQLite :/icons/appicon:/icons/appicon 3 3 3 3 3 0 true true &Database Structure &Database Structure 3 3 3 3 3 toolBar1 Qt::ToolButtonTextBesideIcon Qt::CustomContextMenu This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. true QAbstractItemView::DragDrop true QAbstractItemView::ScrollPerPixel true &Browse Data &Browse Data 0 0 0 0 0 Qt::CustomContextMenu QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks Edit P&ragmas Edit P&ragmas 3 3 3 3 3 true 0 0 640 526 QFormLayout::ExpandingFieldsGrow <html><head/><body><p>Auto Vacuum <a href="http://www.sqlite.org/pragma.html#pragma_auto_vacuum"><img src=":/icons/whatis"/></a></p></body></html> true Qt::LinksAccessibleByMouse comboboxPragmaAutoVacuum None Full Incremental <html><head/><body><p>Automatic Index <a href="http://www.sqlite.org/pragma.html#pragma_automatic_index"><img src=":/icons/whatis"/></a></p></body></html> true checkboxPragmaAutomaticIndex <html><head/><body><p>Case Sensitive Like <a href="https://www.sqlite.org/pragma.html#pragma_case_sensitive_like"><img src=":/icons/whatis"/></a></a></p></body></html> true checkboxPragmaCaseSensitiveLike Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. <html><head/><body><p>Checkpoint Full FSYNC <a href="https://www.sqlite.org/pragma.html#pragma_checkpoint_fullfsync"><img src=":/icons/whatis"/></a></a></p></body></html> true checkboxPragmaCheckpointFullFsync <html><head/><body><p>Foreign Keys <a href="https://www.sqlite.org/pragma.html#pragma_foreign_keys"><img src=":/icons/whatis"/></a></a></p></body></html> true checkboxPragmaForeignKeys <html><head/><body><p>Full FSYNC <a href="https://www.sqlite.org/pragma.html#pragma_fullfsync"><img src=":/icons/whatis"/></a></a></p></body></html> true checkboxPragmaFullFsync <html><head/><body><p>Ignore Check Constraints <a href="https://www.sqlite.org/pragma.html#pragma_ignore_check_constraints"><img src=":/icons/whatis"/></a></a></p></body></html> true checkboxPragmaIgnoreCheckConstraints <html><head/><body><p>Journal Mode <a href="https://www.sqlite.org/pragma.html#pragma_journal_mode"><img src=":/icons/whatis"/></a></a></p></body></html> true comboboxPragmaJournalMode Delete Truncate Persist Memory WAL Off <html><head/><body><p>Journal Size Limit <a href="https://www.sqlite.org/pragma.html#pragma_journal_size_limit"><img src=":/icons/whatis"/></a></a></p></body></html> true spinPragmaJournalSizeLimit -1 100000 <html><head/><body><p>Locking Mode <a href="https://www.sqlite.org/pragma.html#pragma_locking_mode"><img src=":/icons/whatis"/></a></a></p></body></html> true comboboxPragmaLockingMode Normal Exclusive <html><head/><body><p>Max Page Count <a href="https://www.sqlite.org/pragma.html#pragma_max_page_count"><img src=":/icons/whatis"/></a></a></p></body></html> true spinPragmaMaxPageCount 2000000000 <html><head/><body><p>Page Size <a href="https://www.sqlite.org/pragma.html#pragma_page_size"><img src=":/icons/whatis"/></a></a></p></body></html> true comboPragmaPageSize 512 1024 2048 4096 8192 16384 32768 65536 <html><head/><body><p>Recursive Triggers <a href="https://www.sqlite.org/pragma.html#pragma_recursive_triggers"><img src=":/icons/whatis"/></a></a></p></body></html> true checkboxPragmaRecursiveTriggers <html><head/><body><p>Secure Delete <a href="https://www.sqlite.org/pragma.html#pragma_secure_delete"><img src=":/icons/whatis"/></a></a></p></body></html> true checkboxPragmaSecureDelete <html><head/><body><p>Synchronous <a href="https://www.sqlite.org/pragma.html#pragma_synchronous"><img src=":/icons/whatis"/></a></a></p></body></html> true comboboxPragmaSynchronous Off Normal Full <html><head/><body><p>Temp Store <a href="https://www.sqlite.org/pragma.html#pragma_temp_store"><img src=":/icons/whatis"/></a></a></p></body></html> true comboboxPragmaTempStore Default File Memory <html><head/><body><p>User Version <a href="https://www.sqlite.org/pragma.html#pragma_user_version"><img src=":/icons/whatis"/></a></a></p></body></html> true spinPragmaUserVersion 2147483647 <html><head/><body><p>WAL Auto Checkpoint <a href="https://www.sqlite.org/pragma.html#pragma_wal_autocheckpoint"><img src=":/icons/whatis"/></a></a></p></body></html> true spinPragmaWalAutoCheckpoint 10000 QDialogButtonBox::Cancel|QDialogButtonBox::Save false E&xecute SQL E&xecute SQL 3 3 3 3 3 toolBar1 Qt::CustomContextMenu -1 true 0 0 1037 22 &File &Import &Export &Recent Files &Edit &View &Help Too&ls DB Toolbar Qt::ToolButtonTextBesideIcon TopToolBarArea false Edit Database &Cell 2 SQL &Log 2 2 0 2 0 0 30 Show S&QL submitted by comboLogSubmittedBy 0 30 User Application Error Log Qt::Horizontal 20 20 0 30 This button clears the contents of the SQL logs &Clear This panel lets you examine a log of all SQL commands issued by the application or by yourself 0 Monospace 8 true Monospace 8 true Monospace 8 true &Plot 2 DB Sche&ma 2 2 0 2 0 Qt::CustomContextMenu This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. QFrame::NoFrame QFrame::Plain true QAbstractItemView::DragDrop true QAbstractItemView::ExtendedSelection QAbstractItemView::SelectItems QAbstractItemView::ScrollPerPixel true &Remote 2 Project Toolbar Qt::ToolButtonTextBesideIcon TopToolBarArea false true Extra DB toolbar Close the current database file Qt::ToolButtonTextBesideIcon TopToolBarArea false :/icons/db_new:/icons/db_new &New Database... &New Database Create a new database file Create a new database file This option is used to create a new database file. Ctrl+N QAction::NoRole :/icons/db_open:/icons/db_open &Open Database... Open an existing database file Open an existing database file This option is used to open an existing database file. Ctrl+O QAction::NoRole false :/icons/close:/icons/close &Close Database Close the current database file Close the current database file This button closes the connection to the currently open database file Ctrl+F4 QAction::NoRole false :/icons/db_revert:/icons/db_revert &Revert Changes Revert database to last saved state Revert database to last saved state This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. QAction::NoRole false :/icons/undo.svg:/icons/undo.svg &Undo Undo last change to the database Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. QAction::NoRole false :/icons/db_save:/icons/db_save &Write Changes Write changes to the database file Write changes to the database file This option is used to save changes to the database file. Ctrl+S QAction::NoRole false Compact &Database... Compact the database file, removing space wasted by deleted records Compact the database file, removing space wasted by deleted records. Compact the database file, removing space wasted by deleted records. QAction::NoRole E&xit Ctrl+Q QAction::QuitRole &Database from SQL file... Import data from an .sql dump text file into a new or existing database. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. QAction::NoRole &Table from CSV file... Open a wizard that lets you import data from a comma separated text file into a database table. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. QAction::NoRole &Database to SQL file... Export a database to a .sql dump text file. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. QAction::NoRole &Table(s) as CSV file... Export a database table as a comma separated text file. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. QAction::NoRole false :/icons/table_create:/icons/table_create &Create Table... Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database QAction::NoRole false :/icons/table_delete:/icons/table_delete &Delete Table... Delete Table Open the Delete Table wizard, where you can select a database table to be dropped. QAction::NoRole false :/icons/table_modify:/icons/table_modify &Modify Table... Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. QAction::NoRole false :/icons/index_create:/icons/index_create Create &Index... Open the Create Index wizard, where it is possible to define a new index on an existing database table. QAction::NoRole :/icons/settings:/icons/settings &Preferences... Open the preferences window. Open the preferences window. QAction::PreferencesRole true :/icons/toolbar:/icons/toolbar &DB Toolbar Shows or hides the Database toolbar. QAction::NoRole :/icons/whatis:/icons/whatis W&hat's This? Shift+F1 QAction::NoRole &About QAction::AboutRole &Recently opened :/icons/new_tab:/icons/new_tab New &tab This button opens a new tab for the SQL editor Ctrl+T :/icons/run:/icons/run &Execute SQL Execute all/selected SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Ctrl+Return :/icons/document_open:/icons/document_open Open SQL file(s) This button opens files containing SQL statements and loads them in new editor tabs Ctrl+Shift+T :/icons/save_sql:/icons/save_sql Save SQL file false :/icons/load_extension:/icons/load_extension &Load Extension... QAction::NoRole :/icons/run_line:/icons/run_line Execute current line Execute line Execute current line This button executes the SQL statement present in the current editor line Shift+F5 false Export as CSV file Export table as comma separated values file :/icons/browser_open:/icons/browser_open &Wiki F1 QAction::NoRole :/icons/browser_open:/icons/browser_open Bug &Report... QAction::NoRole :/icons/browser_open:/icons/browser_open Feature Re&quest... QAction::NoRole :/icons/browser_open:/icons/browser_open Web&site QAction::NoRole :/icons/browser_open:/icons/browser_open &Donate on Patreon... QAction::NoRole :/icons/project_save:/icons/project_save Sa&ve Project &Save Project Save the current session to a file Save the current session to a file This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file QAction::NoRole :/icons/project_open:/icons/project_open Open &Project... Open &Project Load a working session from a file Load a working session from a file This button lets you open a DB Browser for SQLite project file QAction::NoRole false :/icons/db_attach:/icons/db_attach &Attach Database... Add another database file to the current database connection Add another database file to the current database connection This button lets you add another database file to the current database connection QAction::NoRole :/icons/encryption:/icons/encryption &Set Encryption... QAction::NoRole :/icons/save_sql:/icons/save_sql Save SQL file as Save SQL file as :/icons/save_sql:/icons/save_sql Save SQL file Save SQL file This button saves the content of the current SQL editor tab to a file :/icons/table:/icons/table &Browse Table :/icons/copy:/icons/copy Copy Create statement Copy the CREATE statement of the item to the clipboard :/icons/browser_open:/icons/browser_open SQLCipher &FAQ Opens the SQLCipher FAQ in a browser window Table(&s) to JSON... Export one or more table(s) to a JSON file QAction::NoRole :/icons/db_open:/icons/db_open Open Data&base Read Only... Open an existing database file in read only mode Open an existing database file This option is used to open an existing database file. Ctrl+Shift+O QAction::NoRole :/icons/save_table:/icons/save_table Save results Save the results view This button lets you save the results of the last executed query true :/icons/find:/icons/find Find text in SQL editor Find Find text in SQL editor This button opens the search bar of the editor Ctrl+F Qt::WidgetShortcut false :/icons/text_replace:/icons/text_replace Find or replace text in SQL editor Find or replace Find or replace text in SQL editor This button opens the find/replace dialog for the current editor tab Ctrl+H Qt::WidgetShortcut Export to &CSV Export to &JSON Save as &view Save as view true false :/icons/toolbar:/icons/toolbar Project Toolbar Shows or hides the Project toolbar. QAction::NoRole true :/icons/toolbar:/icons/toolbar Extra DB Toolbar :/icons/db_open:/icons/db_open &Open Database... &Open Database Open an existing database file Open an existing database file This option is used to open an existing database file. QAction::TextHeuristicRole New In-&Memory Database true Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor When dragging fields from the same table or a single table, drop a SELECT query into the editor true Drag && Drop Qualified Names Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor true Drag && Drop Enquoted Names Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor &Integrity Check Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. &Foreign-Key Check Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab &Quick Integrity Check Run a quick integrity check over the open DB Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. &Optimize Attempt to optimize the database Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. :/icons/print:/icons/print Print Print text from current SQL editor tab Open a dialog for printing the text in the current SQL editor tab Ctrl+P Qt::WidgetShortcut false :/icons/print:/icons/print Print Print the structure of the opened database Open a dialog for printing the structure of the opened database Ctrl+P Qt::WidgetShortcut :/icons/comment_block:/icons/comment_block Un/comment block of SQL code Un/comment block Comment or uncomment current line or selected block of code Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Ctrl+/ Qt::WidgetShortcut :/icons/cancel:/icons/cancel Stop SQL execution Stop execution Stop the currently running SQL script :/icons/project_save_as:/icons/project_save_as &Save Project As... Save the project in a file selected in a dialog Save the project in a file selected in a dialog Save the project in a file selected in a dialog :/icons/save_all:/icons/save_all Save A&ll Save DB file, project file and opened SQL files Save DB file, project file and opened SQL files Save DB file, project file and opened SQL files Ctrl+Shift+S :/icons/table:/icons/table Browse Table Close Pro&ject Close project and database files and return to the initial state Close project and database files and return to the initial state Ctrl+Shift+W :/icons/db_detach:/icons/db_detach Detach Database Detach database file attached to the current database connection :/icons/db_detach:/icons/db_detach Detach Database Detach database file attached to the current database connection Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. false :/icons/db_save:/icons/db_save Save Database &As... Save the current database as a different file :/icons/refresh:/icons/refresh Refresh Reload the database structure SqlTextEdit QWidget
sqltextedit.h
1
ExtendedScintilla QTextEdit
ExtendedScintilla.h
1
mainTab dbTreeWidget comboLogSubmittedBy buttonLogClear treeSchemaDock scrollareaPragmas comboboxPragmaAutoVacuum checkboxPragmaAutomaticIndex checkboxPragmaCaseSensitiveLike checkboxPragmaCheckpointFullFsync checkboxPragmaForeignKeys checkboxPragmaFullFsync checkboxPragmaIgnoreCheckConstraints comboboxPragmaJournalMode spinPragmaJournalSizeLimit comboboxPragmaLockingMode spinPragmaMaxPageCount comboPragmaPageSize checkboxPragmaSecureDelete checkboxPragmaRecursiveTriggers comboboxPragmaSynchronous comboboxPragmaTempStore spinPragmaUserVersion spinPragmaWalAutoCheckpoint tabSqlAreas fileExitAction triggered() MainWindow close() -1 -1 399 299 fileOpenAction triggered() MainWindow fileOpen() -1 -1 399 299 fileNewAction triggered() MainWindow fileNew() -1 -1 399 299 fileCloseAction triggered() MainWindow fileClose() -1 -1 399 299 fileSaveAsAction triggered() MainWindow fileSaveAs() -1 -1 399 299 fileCompactAction triggered() MainWindow compact() -1 -1 399 299 helpWhatsThisAction triggered() MainWindow helpWhatsThis() -1 -1 399 299 helpAboutAction triggered() MainWindow helpAbout() -1 -1 399 299 mainTab currentChanged(int) MainWindow mainTabSelected(int) 399 315 399 299 fileImportCSVAction triggered() MainWindow importTableFromCSV() -1 -1 399 299 fileExportCSVAction triggered() MainWindow exportTableToCSV() -1 -1 399 299 fileRevertAction triggered() MainWindow fileRevert() -1 -1 399 299 undoAction triggered() MainWindow undo() -1 -1 399 299 fileSaveAction triggered() MainWindow fileSave() -1 -1 399 299 editCreateIndexAction triggered() MainWindow createIndex() -1 -1 399 299 editDeleteObjectAction triggered() MainWindow deleteObject() -1 -1 399 299 editModifyObjectAction triggered() MainWindow editObject() -1 -1 399 299 fileExportSQLAction triggered() MainWindow exportDatabaseToSQL() -1 -1 399 299 fileImportSQLAction triggered() MainWindow importDatabaseFromSQL() -1 -1 399 299 viewPreferencesAction triggered() MainWindow openPreferences() -1 -1 399 299 dbTreeWidget customContextMenuRequested(QPoint) MainWindow createTreeContextMenu(QPoint) 111 261 399 299 treeSchemaDock customContextMenuRequested(QPoint) MainWindow createSchemaDockContextMenu(QPoint) 111 261 399 299 viewDBToolbarAction toggled(bool) toolbarDB setVisible(bool) -1 -1 399 34 actionSqlFind toggled(bool) MainWindow setFindFrameVisibility(bool) -1 -1 399 34 actionSqlFindReplace triggered() MainWindow openFindReplaceDialog() -1 -1 399 34 editCreateTableAction triggered() MainWindow createTable() -1 -1 399 299 buttonBoxPragmas rejected() MainWindow loadPragmas() 111 540 -1 470 buttonBoxPragmas accepted() MainWindow savePragmas() 111 540 802 522 buttonLogClear clicked() editLogApplication clear() 989 126 632 173 buttonLogClear clicked() editLogUser clear() 989 126 1028 230 buttonLogClear clicked() editLogErrorLog clear() 989 126 632 173 comboLogSubmittedBy currentIndexChanged(int) stackLog setCurrentIndex(int) 772 135 1028 230 tabSqlAreas tabCloseRequested(int) MainWindow closeSqlTab(int) 91 259 -1 51 tabSqlAreas currentChanged(int) MainWindow changeSqlTab(int) 91 259 -1 51 actionExecuteSql triggered() MainWindow executeQuery() -1 -1 399 299 actionSqlOpenTab triggered() MainWindow openSqlTab() -1 -1 399 299 actionSqlOpenFile triggered() MainWindow openSqlFile() -1 -1 399 299 actionSqlSaveFile triggered() MainWindow saveSqlFile() -1 -1 399 299 actionLoadExtension triggered() MainWindow loadExtension() -1 -1 399 299 actionSqlExecuteLine triggered() MainWindow executeQuery() -1 -1 399 299 actionExportCsvPopup triggered() MainWindow exportTableToCSV() -1 -1 399 299 actionOpenProject triggered() MainWindow loadProject() -1 -1 399 299 actionSaveProject triggered() MainWindow saveProject() -1 -1 399 299 fileAttachAction triggered() MainWindow fileAttach() -1 -1 499 314 fileDetachAction triggered() MainWindow fileDetachDbTree() -1 -1 499 314 actionEncryption triggered() MainWindow editEncryption() -1 -1 499 314 actionSqlSaveFilePopup triggered() MainWindow saveSqlFile() -1 -1 499 314 actionSqlSaveFileAs triggered() MainWindow saveSqlFileAs() -1 -1 499 314 actionEditBrowseTable triggered() MainWindow switchToBrowseDataTab() -1 -1 499 314 actionEditCopyCreateStatement triggered() MainWindow copyCurrentCreateStatement() -1 -1 499 314 fileExportJsonAction triggered() MainWindow exportTableToJson() -1 -1 518 314 fileOpenReadOnlyAction triggered() MainWindow fileOpenReadOnly() -1 -1 518 314 actionSqlResultsExportCsv triggered() MainWindow saveSqlResultsAsCsv() -1 -1 518 314 actionSqlResultsExportJson triggered() MainWindow saveSqlResultsAsJson() -1 -1 518 314 actionSqlResultsSaveAsView triggered() MainWindow saveSqlResultsAsView() -1 -1 518 314 tabSqlAreas tabBarDoubleClicked(int) MainWindow renameSqlTab(int) 330 372 518 314 viewProjectToolbarAction toggled(bool) toolbarProject setVisible(bool) -1 -1 887 44 viewExtraDBToolbarAction toggled(bool) toolbarExtraDB setVisible(bool) -1 -1 737 44 MainWindow toolButtonStyleChanged(Qt::ToolButtonStyle) toolbarDB setToolButtonStyle(Qt::ToolButtonStyle) 518 314 296 44 MainWindow toolButtonStyleChanged(Qt::ToolButtonStyle) toolbarExtraDB setToolButtonStyle(Qt::ToolButtonStyle) 518 314 737 44 MainWindow toolButtonStyleChanged(Qt::ToolButtonStyle) toolbarProject setToolButtonStyle(Qt::ToolButtonStyle) 518 314 959 44 fileOpenActionPopup triggered() MainWindow fileOpen() -1 -1 518 314 fileNewInMemoryDatabaseAction triggered() MainWindow fileNewInMemoryDatabase() -1 -1 20 20 actionSqlPrint triggered() MainWindow openSqlPrintDialog() -1 -1 518 314 actionDbPrint triggered() MainWindow printDbStructure() -1 -1 518 314 actionSqlToggleComment triggered() MainWindow toggleSqlBlockComment() -1 -1 518 314 labelPragmaAutomaticIndex linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaCaseSensitiveLike linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaCheckpointFullFsync linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaForeignKeys linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaFullFsync linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaIgnoreCheckConstraints linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaJournalMode linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaLockingMode linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaMaxPageCount linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaPageSize linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaRecursiveTriggers linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaSecureDelete linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaSynchronous linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaTempStore linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaUserVersion linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaWalAutoCheckpoint linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaAutoVacuum linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelPragmaAutoVacuum linkHovered(QString) MainWindow showStatusMessage5s(QString) 85 133 518 314 labelJournalSizeLimit linkHovered(QString) MainWindow showStatusMessage5s(QString) 99 345 518 314 actionSaveProjectAs triggered() MainWindow saveProjectAs() -1 -1 518 314 actionSaveAll triggered() MainWindow saveAll() -1 -1 518 314 tabSqlAreas customContextMenuRequested(QPoint) MainWindow showContextMenuSqlTabBar(QPoint) -1 -1 20 20 actionCloseProject triggered() MainWindow closeFiles() -1 -1 518 314 actionFileImportCsvClipboard triggered() MainWindow importTableFromCSV() -1 -1 518 314 actionRowCounts triggered() MainWindow newRowCountsTab() -1 -1 518 314 actionWiki triggered() MainWindow openLinkWiki() -1 -1 -1 -1 actionBug_report triggered() MainWindow openLinkBugReport() -1 -1 -1 -1 actionFeature_Request triggered() MainWindow openLinkFeatureRequest() -1 -1 -1 -1 actionSqlCipherFaq triggered() MainWindow openLinkSqlCipherFaq() -1 -1 -1 -1 actionWebsite triggered() MainWindow openLinkWebsite() -1 -1 -1 -1 actionDonatePatreon triggered() MainWindow openLinkDonatePatreon() -1 -1 -1 -1 actionRefreshStructure triggered() MainWindow refresh() -1 -1 518 314 fileOpen() fileClose() browseFind(bool) refresh() compact() helpWhatsThis() mainTabSelected(int) executeQuery() importTableFromCSV() exportTableToCSV() fileRevert() undo() fileSave() deleteIndex() createIndex() createTable() deleteObject() editObject() editTablePopup() addField() editField() exportDatabaseToSQL() importDatabaseFromSQL() openPreferences() createTreeContextMenu(QPoint) changeTreeSelection() fileNew() helpAbout() deleteField() loadPragmas() savePragmas() copy() closeSqlTab(int) openSqlTab() openSqlFile() saveSqlFile() loadExtension() loadProject() saveProject() fileAttach() fileDetachDbTree() fileDetachTreeSchemaDock() editEncryption() saveSqlFileAs() switchToBrowseDataTab() copyCurrentCreateStatement() browseDataFetchAllData() exportTableToJson() fileOpenReadOnly() saveSqlResultsAsCsv() saveSqlResultsAsView() changeSqlTab(int) renameSqlTab(int) fileNewInMemoryDatabase() showContextMenuSqlTabBar(QPoint) closeTableBrowserTab(int) openTableBrowserTab() changeTableBrowserTab(int) renameTableBrowserTab(int) showContextMenuTableBrowserTabBar(QPoint) newRowCountsTab() openLinkWiki() openLinkBugReport() openLinkFeatureRequest() openLinkSqlCipherFaq() openLinkWebsite() openLinkDonatePatreon()
sqlitebrowser-sqlitebrowser-5733cb7/src/Palette.cpp000066400000000000000000000046561463772530400226000ustar00rootroot00000000000000#include "Palette.h" #include Palette::Palette() : m_lastColourIndex(0) { } QColor Palette::nextSerialColor(bool dark) { if (dark) { switch(m_lastColourIndex++) { case 0: return QColor(0, 69, 134); case 1: return QColor(255, 66, 14); case 2: return QColor(255, 211, 32); case 3: return QColor(87, 157, 28); case 4: return QColor(126, 0, 33); case 5: return QColor(131, 202, 255); case 6: return QColor(49, 64, 4); case 7: return QColor(174, 207, 0); case 8: return QColor(75, 31, 111); case 9: return QColor(255, 149, 14); case 10: return QColor(197, 00, 11); case 11: // Since this is the last colour in our table, reset the counter back // to the first colour m_lastColourIndex = 0; return QColor(0, 132, 209); default: // NOTE: This shouldn't happen! m_lastColourIndex = 0; return QColor(0, 0, 0); } } else { // TODO: review the bright colours switch(m_lastColourIndex++) { case 0: return QColor(Qt::yellow); case 1: return QColor(Qt::cyan); case 2: return QColor(Qt::green); case 3: return QColor(Qt::magenta); case 4: return QColor(Qt::lightGray); case 5: return QColor("beige"); case 6: return QColor("lightblue"); case 7: return QColor("turquoise"); case 8: return QColor("mediumspringgreen"); case 9: return QColor("lightskyblue"); case 10: return QColor("moccasin"); case 11: // Since this is the last colour in our table, reset the counter back // to the first colour m_lastColourIndex = 0; return QColor("pink"); default: // NOTE: This shouldn't happen! return QColor(0, 0, 0); } } } bool Palette::appHasDarkTheme() { QColor backgroundColour = QPalette().color(QPalette::Active, QPalette::Base); QColor foregroundColour = QPalette().color(QPalette::Active, QPalette::Text); return backgroundColour.value() < foregroundColour.value(); } sqlitebrowser-sqlitebrowser-5733cb7/src/Palette.h000066400000000000000000000004711463772530400222340ustar00rootroot00000000000000#ifndef PALETTE_H #define PALETTE_H #include // Class providing series of colours in a given dark or light side of // the spectrum. class Palette { public: Palette(); QColor nextSerialColor(bool dark = true); static bool appHasDarkTheme(); private: int m_lastColourIndex; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/PlotDock.cpp000066400000000000000000001273331463772530400227170ustar00rootroot00000000000000#define QT_NO_FLOAT16_OPERATORS // This works around https://bugreports.qt.io/browse/QTBUG-72073 which makes the build fail on MSVC 2017 and Qt 5.12 #include "PlotDock.h" #include "ui_PlotDock.h" #include "Settings.h" #include "sqlitetablemodel.h" #include "FileDialog.h" #include "TableBrowser.h" // Just for BrowseDataTableSettings, not for the actual table browser class #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) #include #endif // Enable this line to show the most basic performance stats after pressing the fetch-all-data button. Please keep in mind that while these // numbers might help to estimate the performance of the data loading procedure, this is not a proper benchmark. //#define LOAD_DATA_BENCHMARK #ifdef LOAD_DATA_BENCHMARK #include #endif #include #include static int random_number(int from, int to) { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) return QRandomGenerator::global()->bounded(from, to); #else return qrand() % to + from; #endif } PlotDock::PlotDock(QWidget* parent) : QDialog(parent), ui(new Ui::PlotDock), m_currentPlotModel(nullptr), m_currentTableSettings(nullptr), m_showLegend(false), m_stackedBars(false), m_fixedFormat(false), m_xtype(QVariant::Invalid) { ui->setupUi(this); // Init widgets ui->treePlotColumns->setSelectionMode(QAbstractItemView::NoSelection); // Restore state ui->splitterForPlot->restoreState(Settings::getValue("PlotDock", "splitterSize").toByteArray()); ui->comboLineType->setCurrentIndex(Settings::getValue("PlotDock", "lineType").toInt()); ui->comboPointShape->setCurrentIndex(Settings::getValue("PlotDock", "pointShape").toInt()); // Connect signals connect(ui->plotWidget, &QCustomPlot::selectionChangedByUser, this, &PlotDock::selectionChanged); // connect slots that takes care that when an axis is selected, only that direction can be dragged and zoomed: connect(ui->plotWidget, &QCustomPlot::mousePress, this, &PlotDock::mousePress); connect(ui->plotWidget, &QCustomPlot::mouseWheel, this, &PlotDock::mouseWheel); connect(ui->plotWidget, &QCustomPlot::mouseMove, this, &PlotDock::mouseMove); // Enable: click on items to select them, Ctrl+Click for multi-selection, mouse-wheel for zooming and mouse drag for // changing the visible range. // Select one axis for zoom and drag applying only to that orientation. ui->plotWidget->setInteractions(QCP::iSelectPlottables | QCP::iMultiSelect | QCP::iRangeZoom | QCP::iRangeDrag | QCP::iSelectAxes); ui->plotWidget->setSelectionRectMode(QCP::srmNone); QShortcut* shortcutCopy = new QShortcut(QKeySequence::Copy, ui->plotWidget, nullptr, nullptr, Qt::WidgetShortcut); connect(shortcutCopy, &QShortcut::activated, this, &PlotDock::copy); QShortcut* shortcutPrint = new QShortcut(QKeySequence::Print, ui->plotWidget, nullptr, nullptr, Qt::WidgetShortcut); connect(shortcutPrint, &QShortcut::activated, this, &PlotDock::openPrintDialog); ui->plotWidget->setContextMenuPolicy(Qt::CustomContextMenu); // Set up context menu m_contextMenu = new QMenu(this); QAction* copyAction = new QAction(QIcon(":/icons/copy"), tr("Copy"), m_contextMenu); copyAction->setShortcut(shortcutCopy->key()); m_contextMenu->addAction(copyAction); connect(copyAction, &QAction::triggered, this, [&]() { copy(); }); QAction* printAction = new QAction(QIcon(":/icons/print"), tr("Print..."), m_contextMenu); printAction->setShortcut(shortcutPrint->key()); m_contextMenu->addAction(printAction); connect(printAction, &QAction::triggered, this, [&]() { openPrintDialog(); }); QAction* showLegendAction = new QAction(tr("Show legend"), m_contextMenu); showLegendAction->setCheckable(true); m_contextMenu->addAction(showLegendAction); connect(showLegendAction, &QAction::toggled, this, &PlotDock::toggleLegendVisible); QAction* stackedBarsAction = new QAction(tr("Stacked bars"), m_contextMenu); stackedBarsAction->setCheckable(true); m_contextMenu->addAction(stackedBarsAction); connect(stackedBarsAction, &QAction::toggled, this, &PlotDock::toggleStackedBars); QAction* fixedFormatsAction = new QAction(tr("Fixed number format"), m_contextMenu); fixedFormatsAction->setCheckable(true); m_contextMenu->addAction(fixedFormatsAction); connect(fixedFormatsAction, &QAction::toggled, this, [=](bool fixed) { m_fixedFormat = fixed; adjustAxisFormat(); ui->plotWidget->replot(); }); connect(ui->plotWidget, &QTableView::customContextMenuRequested, this, [=](const QPoint& pos) { // Show menu m_contextMenu->popup(ui->plotWidget->mapToGlobal(pos)); }); // Initialise the y axes and plotcolumn indices for y axes yAxes = {ui->plotWidget->yAxis, ui->plotWidget->yAxis2}; PlotColumnY = {PlotColumnY1, PlotColumnY2}; } PlotDock::~PlotDock() { // Save state Settings::setValue("PlotDock", "splitterSize", ui->splitterForPlot->saveState()); Settings::setValue("PlotDock", "lineType", ui->comboLineType->currentIndex()); Settings::setValue("PlotDock", "pointShape", ui->comboPointShape->currentIndex()); // Finally, delete all widgets delete ui; } void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* settings, bool update, bool keepOrResetSelection) { // Each column has an id that we use internally, starting from 0. However, at the beginning of the columns list we want to add // the virtual 'Row #' column which needs a separate unique id for internal use. This id is defined here as -1. const int RowNumId = -1; // add columns to x/y selection tree widget if(update) { // Store pointer to the current browse table settings in the main window m_currentTableSettings = settings; // disable tree plot columns item changed updates ui->treePlotColumns->blockSignals(true); m_currentPlotModel = model; // save current selected columns, so we can restore them after the update QString sItemX; // selected X column std::vector> mapItemsY = {std::map(), std::map()}; if(keepOrResetSelection) { // Store the currently selected plot columns to restore them later for(int i = 0; i < ui->treePlotColumns->topLevelItemCount(); ++i) { QTreeWidgetItem* item = ui->treePlotColumns->topLevelItem(i); if(item->checkState(PlotColumnX) == Qt::Checked) sItemX = item->text(PlotColumnField); for(size_t y_ind = 0; y_ind < 2; y_ind++) if(item->checkState(PlotColumnY[y_ind]) == Qt::Checked) mapItemsY[y_ind][item->text(PlotColumnField)] = PlotSettings( 0, 0, item->background(PlotColumnY[y_ind]).color(), item->checkState(PlotColumnY[y_ind]) == Qt::Checked); } } else { // Get the plot columns to select from the stored browse table information sItemX = m_currentTableSettings->plotXAxis; mapItemsY[0] = m_currentTableSettings->plotYAxes[0]; mapItemsY[1] = m_currentTableSettings->plotYAxes[1]; } ui->treePlotColumns->clear(); if(model) { // Add each column with a supported data type to the column selection view for(int i=0;icolumnCount();++i) { QVariant::Type columntype = guessDataType(model, i); if(columntype != QVariant::Invalid) { QTreeWidgetItem* columnitem = new QTreeWidgetItem(ui->treePlotColumns); switch (columntype) { case QVariant::DateTime: columnitem->setText(PlotColumnType, tr("Date/Time")); break; case QVariant::Date: columnitem->setText(PlotColumnType, tr("Date")); break; case QVariant::Time: columnitem->setText(PlotColumnType, tr("Time")); break; case QVariant::Double: columnitem->setText(PlotColumnType, tr("Numeric")); break; case QVariant::String: columnitem->setText(PlotColumnType, tr("Label")); break; default: // This is not actually expected columnitem->setText(PlotColumnType, tr("Invalid")); } // Store the model column index in the PlotColumnField and the type // in the PlotColumnType, both using the User Role. columnitem->setData(PlotColumnField, Qt::UserRole, i); columnitem->setData(PlotColumnType, Qt::UserRole, static_cast(columntype)); columnitem->setText(PlotColumnField, model->headerData(i, Qt::Horizontal, Qt::EditRole).toString()); // restore previous check state for(size_t y_ind = 0; y_ind < 2; y_ind++) { if(contains(mapItemsY[y_ind], columnitem->text(PlotColumnField))) { columnitem->setCheckState(PlotColumnY[y_ind], mapItemsY[y_ind][columnitem->text(PlotColumnField)].active ? Qt::Checked : Qt::Unchecked); columnitem->setBackground(PlotColumnY[y_ind], mapItemsY[y_ind][columnitem->text(PlotColumnField)].colour); } else { if (columntype == QVariant::Double) columnitem->setCheckState(PlotColumnY[y_ind], Qt::Unchecked); } } if(sItemX == columnitem->text(PlotColumnField)) columnitem->setCheckState(PlotColumnX, Qt::Checked); else columnitem->setCheckState(PlotColumnX, Qt::Unchecked); } } ui->treePlotColumns->resizeColumnToContents(PlotColumnField); // Add a row number column at the beginning of the column list, but only when there were (other) columns added if(ui->treePlotColumns->topLevelItemCount()) { QTreeWidgetItem* columnitem = new QTreeWidgetItem(ui->treePlotColumns); // Just set RowNumId in the user role information field here to somehow indicate what column this is columnitem->setData(PlotColumnField, Qt::UserRole, RowNumId); columnitem->setText(PlotColumnField, tr("Row #")); columnitem->setData(PlotColumnType, Qt::UserRole, static_cast(QVariant::Double)); columnitem->setText(PlotColumnType, tr("Numeric")); // restore previous check state for(size_t y_ind = 0; y_ind < 2; y_ind++) { if(contains(mapItemsY[y_ind], columnitem->text(PlotColumnField))) { columnitem->setCheckState(PlotColumnY[y_ind], mapItemsY[y_ind][columnitem->text(PlotColumnField)].active ? Qt::Checked : Qt::Unchecked); columnitem->setBackground(PlotColumnY[y_ind], mapItemsY[y_ind][columnitem->text(PlotColumnField)].colour); } else { columnitem->setCheckState(PlotColumnY[y_ind], Qt::Unchecked); } } if(sItemX == columnitem->text(PlotColumnField)) columnitem->setCheckState(PlotColumnX, Qt::Checked); else columnitem->setCheckState(PlotColumnX, Qt::Unchecked); ui->treePlotColumns->takeTopLevelItem(ui->treePlotColumns->indexOfTopLevelItem(columnitem)); ui->treePlotColumns->insertTopLevelItem(0, columnitem); } } yAxes[0]->setLabel("Y1"); yAxes[1]->setLabel("Y2"); ui->plotWidget->xAxis->setLabel("X"); ui->treePlotColumns->blockSignals(false); } // search for the x axis select QTreeWidgetItem* xitem = nullptr; for(int i = 0; i < ui->treePlotColumns->topLevelItemCount(); ++i) { xitem = ui->treePlotColumns->topLevelItem(i); if(xitem->checkState(PlotColumnX) == Qt::Checked) break; xitem = nullptr; } std::vector yAxisLabels = {QStringList(), QStringList()}; // Clear graphs and axis labels ui->plotWidget->clearPlottables(); ui->plotWidget->xAxis->setLabel(QString()); yAxes[0]->setLabel(QString()); yAxes[1]->setLabel(QString()); if(xitem) { // regain the model column index and the datatype // right now datatype is only important for X axis (Y is always numeric) int x = xitem->data(PlotColumnField, Qt::UserRole).toInt(); m_xtype = xitem->data(PlotColumnType, Qt::UserRole).toUInt(); ui->plotWidget->xAxis->setTickLabelRotation(0); // check if we have a x axis with datetime data switch (m_xtype) { case QVariant::Date: { QSharedPointer ticker(new QCPAxisTickerDateTime); ticker->setDateTimeFormat("yyyy-MM-dd"); ui->plotWidget->xAxis->setTicker(ticker); break; } case QVariant::DateTime: { QSharedPointer ticker(new QCPAxisTickerDateTime); ticker->setDateTimeFormat("yyyy-MM-dd\nhh:mm:ss"); ui->plotWidget->xAxis->setTicker(ticker); break; } case QVariant::Time: { QSharedPointer ticker(new QCPAxisTickerDateTime); ticker->setDateTimeFormat("hh:mm:ss"); ticker->setDateTimeSpec(Qt::UTC); ui->plotWidget->xAxis->setTicker(ticker); break; } case QVariant::String: { // Ticker is set when we have got the labels ui->plotWidget->xAxis->setTickLabelRotation(60); break; } default: { QSharedPointer ticker(new QCPAxisTickerFixed); ticker->setTickStepStrategy(QCPAxisTicker::tssReadability); ticker->setScaleStrategy(QCPAxisTickerFixed::ssMultiples); ui->plotWidget->xAxis->setTicker(ticker); } } // Boolean to decide whether secondary y axis should be displayed bool displayY2Axis = false; // add graph for each selected y axis for(int i = 0; i < ui->treePlotColumns->topLevelItemCount(); ++i) { QTreeWidgetItem* item = ui->treePlotColumns->topLevelItem(i); std::vector yItemBool = {false, false}; if(item->checkState((PlotColumnY[0])) == Qt::Checked || item->checkState((PlotColumnY[1])) == Qt::Checked) { for(size_t y_ind = 0; y_ind < 2; y_ind++) if(item->checkState((PlotColumnY[y_ind])) == Qt::Checked) yItemBool[y_ind] = true; if(yItemBool[1]) displayY2Axis = true; // regain the model column index int column = item->data(PlotColumnField, Qt::UserRole).toInt(); bool isSorted = true; // prepare the data vectors for qcustomplot // possible improvement might be a QVector subclass that directly // access the model data, to save memory, we are copying here auto nrows = model->rowCount(); std::vector> ydata{QVector(nrows), QVector(nrows)}; QVector xdata(nrows), tdata(nrows); QVector labels; for(int j = 0; j < nrows; ++j) { tdata[j] = j; if(x != RowNumId && model->data(model->index(j, x), Qt::EditRole).isNull()) { // NULL values produce gaps in the linear graphs. We use NaN values in // that case as required by QCustomPlot. // Bar plots will display the configured string for NULL values. if(m_xtype == QVariant::String) { xdata[j] = j+1; labels << model->data(model->index(j, x), Qt::DisplayRole).toString(); } else xdata[j] = qQNaN(); } else { // convert x type axis if it's datetime switch (m_xtype) { case QVariant::DateTime: case QVariant::Date: { QString s = model->data(model->index(j, x)).toString(); QDateTime d = QDateTime::fromString(s, Qt::ISODate); xdata[j] = static_cast(d.toMSecsSinceEpoch()) / 1000.0; break; } case QVariant::Time: { QString s = model->data(model->index(j, x)).toString(); QTime t = QTime::fromString(s); xdata[j] = t.msecsSinceStartOfDay() / 1000.0; break; } case QVariant::String: { xdata[j] = j+1; labels << model->data(model->index(j, x)).toString(); break; } default: { // Get the x value for this point. If the selected column is -1, i.e. the row number, just use the current row number from the loop // instead of retrieving some value from the model. if(x == RowNumId) xdata[j] = j+1; else xdata[j] = model->data(model->index(j, x)).toDouble(); } } } if (j != 0) isSorted &= (xdata[j-1] <= xdata[j]); // Get the y value for this point. If the selected column is -1, i.e. the row number, just use the current row number from the loop // instead of retrieving some value from the model. QVariant pointdata; if(column == RowNumId) pointdata = j+1; else pointdata = model->data(model->index(j, column), Qt::EditRole); for(size_t y_ind = 0; y_ind < 2; y_ind++) { if(pointdata.isNull()){ if(yItemBool[y_ind]) ydata[y_ind][j] = qQNaN(); } else{ if(yItemBool[y_ind]) ydata[y_ind][j] = pointdata.toDouble(); } } } // Line type and point shape are not supported by the String X type (Bars) ui->comboLineType->setEnabled(m_xtype != QVariant::String); ui->comboPointShape->setEnabled(m_xtype != QVariant::String); // WARN: ssDot is removed int shapeIdx = ui->comboPointShape->currentIndex(); if (shapeIdx > 0) shapeIdx += 1; QCPScatterStyle scatterStyle = QCPScatterStyle(static_cast(shapeIdx), 5); QCPAbstractPlottable* plottable = nullptr; // When the X type is String, we draw a bar chart. // When it is already sorted by x, we draw a graph. // When it is not sorted by x, we draw a curve, so the order selected by the user in the table or in the query is // respected. In this case the line will have loops and only None and Line is supported as line style. // TODO: how to make the user aware of this without disturbing. if (m_xtype == QVariant::String) { for(size_t y_ind = 0; y_ind < 2; y_ind++) { if(yItemBool[y_ind]) { QCPBars* bars = new QCPBars(ui->plotWidget->xAxis, yAxes[y_ind]); plottable = bars; bars->setData(xdata, ydata[y_ind]); // Set ticker once if (ui->plotWidget->plottableCount() == 1) { QSharedPointer ticker(new QCPAxisTickerText); ticker->addTicks(xdata, labels); ui->plotWidget->xAxis->setTicker(ticker); } QColor color = item->background(PlotColumnY[y_ind]).color(); bars->setBrush(color); plottable->setPen(QPen(color.darker(150))); } } } else { if (isSorted) { for(size_t y_ind = 0; y_ind < 2; y_ind++) { if(yItemBool[y_ind]) { QCPGraph* graph = ui->plotWidget->addGraph(ui->plotWidget->xAxis, yAxes[y_ind]); plottable = graph; graph->setData(xdata, ydata[y_ind], /*alreadySorted*/ true); // set some graph styles not supported by the abstract plottable graph->setLineStyle(static_cast(ui->comboLineType->currentIndex())); graph->setScatterStyle(scatterStyle); plottable->setPen(QPen(item->background(PlotColumnY[y_ind]).color())); } } } else { for(size_t y_ind = 0; y_ind < 2; y_ind++) { if(yItemBool[y_ind]) { QCPCurve* curve = new QCPCurve(ui->plotWidget->xAxis, yAxes[y_ind]); plottable = curve; curve->setData(tdata, xdata, ydata[y_ind], /*alreadySorted*/ true); // set some curve styles not supported by the abstract plottable if (ui->comboLineType->currentIndex() == QCPCurve::lsNone) curve->setLineStyle(QCPCurve::lsNone); else curve->setLineStyle(QCPCurve::lsLine); curve->setScatterStyle(scatterStyle); plottable->setPen(QPen(item->background(PlotColumnY[y_ind]).color())); } } } } if(plottable) { plottable->setSelectable(QCP::stDataRange); plottable->setName(item->text(PlotColumnField)); } for(size_t y_ind = 0; y_ind < 2; y_ind++) { if(yItemBool[y_ind]) { // gather Y label column names if(column == RowNumId) yAxisLabels[y_ind] << tr("Row #"); else yAxisLabels[y_ind] << model->headerData(column, Qt::Horizontal, Qt::EditRole).toString(); } } } } ui->plotWidget->rescaleAxes(true); ui->plotWidget->legend->setVisible(m_showLegend); // Legend with slightly transparent background brush: ui->plotWidget->legend->setBrush(QColor(255, 255, 255, 150)); // set axis labels if(x == RowNumId) ui->plotWidget->xAxis->setLabel(tr("Row #")); else ui->plotWidget->xAxis->setLabel(model->headerData(x, Qt::Horizontal, Qt::EditRole).toString()); for(size_t y_ind = 0; y_ind < 2; y_ind++) yAxes[y_ind]->setLabel(yAxisLabels[y_ind].join("|")); if(displayY2Axis){ yAxes[1]->setVisible(true); yAxes[1]->setTickLabels(true); }else{ yAxes[1]->setVisible(false); yAxes[1]->setTickLabels(false); } } adjustBars(); adjustAxisFormat(); ui->plotWidget->replot(); // Warn user if not all data has been fetched and hint about the button for loading all the data if (model && (model->rowCountAvailable() != SqliteTableModel::RowCount::Complete || !model->isCacheComplete())) { ui->buttonLoadAllData->setEnabled(true); ui->buttonLoadAllData->setStyleSheet("QToolButton {color: white; background-color: rgb(255, 102, 102)}"); ui->buttonLoadAllData->setToolTip(tr("Load all data and redraw plot.\n" "Warning: not all data has been fetched from the table yet due to the partial fetch mechanism.")); } else { ui->buttonLoadAllData->setEnabled(false); ui->buttonLoadAllData->setStyleSheet(""); ui->buttonLoadAllData->setToolTip(tr("Load all data and redraw plot")); } } void PlotDock::resetPlot() { updatePlot(nullptr); } void PlotDock::columnItemChanged(QTreeWidgetItem* changeitem, int column) { // disable change updates, or we get unwanted redrawing and weird behavior ui->treePlotColumns->blockSignals(true); // make sure only 1 X axis is selected if(column == PlotColumnX) { for(int i = 0; i < ui->treePlotColumns->topLevelItemCount(); ++i) { QTreeWidgetItem* item = ui->treePlotColumns->topLevelItem(i); if(item->checkState(column) == Qt::Checked && item != changeitem) { item->setCheckState(column, Qt::Unchecked); } } // Save settings for this table if(m_currentTableSettings) { if(changeitem->checkState(column) == Qt::Checked) m_currentTableSettings->plotXAxis = changeitem->text(PlotColumnField); else m_currentTableSettings->plotXAxis = QString(); } } else if(column == PlotColumnY[0] || column == PlotColumnY[1]) { // Save check state of this column for(size_t y_ind = 0; y_ind < 2; y_ind++) { if(column == PlotColumnY[y_ind]) { if(m_currentTableSettings) { PlotSettings& plot_settings = m_currentTableSettings->plotYAxes[y_ind][changeitem->text(PlotColumnField)]; plot_settings.active = (changeitem->checkState(column) == Qt::Checked); } if(changeitem->checkState(column) == Qt::Checked) { // Generate a default colour if none is set yet QColor colour = changeitem->background(column).color(); if(!colour.isValid() || colour == changeitem->background(PlotColumnField).color()) colour = m_graphPalette.nextSerialColor(true); // Set colour to cell background changeitem->setBackground(column, colour); // Save settings for this table if(m_currentTableSettings) { PlotSettings& plot_settings = m_currentTableSettings->plotYAxes[y_ind][changeitem->text(PlotColumnField)]; plot_settings.colour = colour; plot_settings.lineStyle = ui->comboLineType->currentIndex(); plot_settings.pointShape = (ui->comboPointShape->currentIndex() > 0 ? (ui->comboPointShape->currentIndex()+1) : ui->comboPointShape->currentIndex()); } } } } } ui->treePlotColumns->blockSignals(false); updatePlot(m_currentPlotModel, m_currentTableSettings, false); } void PlotDock::columnItemDoubleClicked(QTreeWidgetItem* item, int column) { // disable change updates, or we get unwanted redrawing and weird behavior ui->treePlotColumns->blockSignals(true); unsigned int type = item->data(PlotColumnType, Qt::UserRole).toUInt(); for(size_t y_ind = 0; y_ind < 2; y_ind++) { if(column == PlotColumnY[y_ind] && type == QVariant::Double) { // On double click open the colordialog QColorDialog colordialog(this); QColor curbkcolor = item->background(column).color(); QColor precolor = !curbkcolor.isValid() ? static_cast(random_number(5, 13)) : curbkcolor; QColor color = colordialog.getColor(precolor, this, tr("Choose an axis color")); if(color.isValid()) { item->setCheckState(column, Qt::Checked); item->setBackground(column, color); // Save settings for this table if(m_currentTableSettings) { PlotSettings& plot_settings = m_currentTableSettings->plotYAxes[y_ind][item->text(PlotColumnField)]; plot_settings.active = (item->checkState(column) == Qt::Checked); plot_settings.colour = color; plot_settings.lineStyle = ui->comboLineType->currentIndex(); plot_settings.pointShape = (ui->comboPointShape->currentIndex() > 0 ? (ui->comboPointShape->currentIndex()+1) : ui->comboPointShape->currentIndex()); } } else { item->setCheckState(column, Qt::Unchecked); // Save settings for this table if(m_currentTableSettings) m_currentTableSettings->plotYAxes[y_ind].erase(item->text(PlotColumnField)); } } } ui->treePlotColumns->blockSignals(false); updatePlot(m_currentPlotModel, m_currentTableSettings, false); } void PlotDock::savePlot() { QString fileName = FileDialog::getSaveFileName( CreateDataFile, this, tr("Choose a filename to save under"), tr("PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*)")); if(!fileName.isEmpty()) { if(fileName.endsWith(".png", Qt::CaseInsensitive)) { ui->plotWidget->savePng(fileName); } else if(fileName.endsWith(".jpg", Qt::CaseInsensitive)) { ui->plotWidget->saveJpg(fileName); } else if(fileName.endsWith(".pdf", Qt::CaseInsensitive)) { ui->plotWidget->savePdf(fileName); } else if(fileName.endsWith(".bmp", Qt::CaseInsensitive)) { ui->plotWidget->saveBmp(fileName); } else { fileName += ".png"; ui->plotWidget->savePng(fileName); } } } void PlotDock::lineTypeChanged(int index) { Q_ASSERT(index >= QCPGraph::lsNone && index <= QCPGraph::lsImpulse); bool hasCurves = (ui->plotWidget->plottableCount() > ui->plotWidget->graphCount()); QCPGraph::LineStyle lineStyle = static_cast(index); if (lineStyle > QCPGraph::lsLine && hasCurves) { QMessageBox::warning(this, qApp->applicationName(), tr("There are curves in this plot and the selected line style can only be applied to graphs sorted by X. " "Either sort the table or query by X to remove curves or select one of the styles supported by curves: " "None or Line.")); return; } for (int i = 0, ie = ui->plotWidget->graphCount(); i < ie; ++i) { QCPGraph * graph = ui->plotWidget->graph(i); if (graph) graph->setLineStyle(lineStyle); } // We have changed the style only for graphs, but not for curves. // If there are any in the plot, we have to update it completely in order to apply the new style if (hasCurves) updatePlot(m_currentPlotModel, m_currentTableSettings, false); else ui->plotWidget->replot(); // Save settings for this table if(m_currentTableSettings) { for(size_t y_ind = 0; y_ind < 2; y_ind++) { std::map& graphs = m_currentTableSettings->plotYAxes[y_ind]; auto it = graphs.begin(); while(it != graphs.end()) { it->second.lineStyle = lineStyle; ++it; } } } } void PlotDock::pointShapeChanged(int index) { // WARN: because ssDot point shape is removed if (index > 0) index += 1; Q_ASSERT(index >= QCPScatterStyle::ssNone && index < QCPScatterStyle::ssPixmap); bool hasCurves = (ui->plotWidget->plottableCount() > ui->plotWidget->graphCount()); QCPScatterStyle::ScatterShape shape = static_cast(index); for (int i = 0, ie = ui->plotWidget->graphCount(); i < ie; ++i) { QCPGraph * graph = ui->plotWidget->graph(i); if (graph) graph->setScatterStyle(QCPScatterStyle(shape, 5)); } // We have changed the style only for graphs, but not for curves. // If there are any in the plot, we have to update it completely in order to apply the new style if (hasCurves) updatePlot(m_currentPlotModel, m_currentTableSettings, false); else ui->plotWidget->replot(); // Save settings for this table if(m_currentTableSettings) { for(size_t y_ind = 0; y_ind < 2; y_ind++) { std::map& graphs = m_currentTableSettings->plotYAxes[y_ind]; auto it = graphs.begin(); while(it != graphs.end()) { it->second.pointShape = shape; ++it; } } } } QVariant::Type PlotDock::guessDataType(SqliteTableModel* model, int column) const { QVariant::Type type = QVariant::Invalid; for(int i = 0; i < std::min(10, model->rowCount()) && type != QVariant::String; ++i) { QVariant varData = model->data(model->index(i, column), Qt::EditRole); if(varData.isNull() || varData.convert(QVariant::Double)) { type = QVariant::Double; } else { QString s = model->data(model->index(i, column)).toString(); QDateTime dt = QDateTime::fromString(s, Qt::ISODate); QTime t = QTime::fromString(s); if (dt.isValid()) // Since the way to discriminate dates with times and pure dates is that the time part is 0, we must take into account // that some DateTimes could have "00:00:00" as time part and still the entire column has time information, so a single // final Date should not set the type to Date if it has already been guessed as DateTime. if (type != QVariant::DateTime && dt.time().msecsSinceStartOfDay() == 0) type = QVariant::Date; else type = QVariant::DateTime; else if (t.isValid()) type = QVariant::Time; else type = QVariant::String; } } return type; } void PlotDock::fetchAllData() { if(m_currentPlotModel) { #ifdef LOAD_DATA_BENCHMARK // If benchmark mode is enabled start measuring the performance now QElapsedTimer timer; timer.start(); #endif // Make sure all data is loaded m_currentPlotModel->completeCache(); #ifdef LOAD_DATA_BENCHMARK QMessageBox::information(this, qApp->applicationName(), tr("Loading all remaining data for this table took %1ms.") .arg(timer.elapsed())); #endif // Update plot updatePlot(m_currentPlotModel, m_currentTableSettings); } } void PlotDock::selectionChanged() { for (const QCPAbstractPlottable* plottable : ui->plotWidget->selectedPlottables()) { for (const QCPDataRange& dataRange : plottable->selection().dataRanges()) { int index = dataRange.begin(); if (dataRange.length() != 0) { emit pointsSelected(index, dataRange.length()); break; } } } } void PlotDock::mousePress() { // Allow user to reset the plot ui->buttonLoadAllData->setEnabled(true); // if an axis (or axis labels) is selected, only allow the direction of that axis to be dragged // if no axis (or axis labels) is selected, all three axes may be dragged if (ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) || ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spAxisLabel)) { QList< QCPAxis *> axList = {ui->plotWidget->xAxis}; ui->plotWidget->axisRect()->setRangeDragAxes(axList); } else if (yAxes[0]->selectedParts().testFlag(QCPAxis::spAxis) || yAxes[0]->selectedParts().testFlag(QCPAxis::spTickLabels) || yAxes[0]->selectedParts().testFlag(QCPAxis::spAxisLabel)) { QList< QCPAxis *> axList = {yAxes[0]}; ui->plotWidget->axisRect()->setRangeDragAxes(axList); } else if (yAxes[1]->selectedParts().testFlag(QCPAxis::spAxis) || yAxes[1]->selectedParts().testFlag(QCPAxis::spTickLabels) || yAxes[1]->selectedParts().testFlag(QCPAxis::spAxisLabel)) { QList< QCPAxis *> axList = {yAxes[1]}; ui->plotWidget->axisRect()->setRangeDragAxes(axList); } else{ QList< QCPAxis *> axList = {ui->plotWidget->xAxis,yAxes[0], yAxes[1]}; ui->plotWidget->axisRect()->setRangeDragAxes(axList); } } void PlotDock::mouseMove(QMouseEvent* event) { double x = ui->plotWidget->xAxis->pixelToCoord(event->pos().x()); double y = ui->plotWidget->yAxis->pixelToCoord(event->pos().y()); QString xLabel; switch (m_xtype) { case QVariant::Date: xLabel = QDateTime::fromMSecsSinceEpoch(static_cast(x*1000.0)).toString("yyyy-MM-dd, "); break; case QVariant::Time: xLabel = QDateTime::fromMSecsSinceEpoch(static_cast(x*1000.0), Qt::UTC).toString("hh:mm:ss, "); break; case QVariant::DateTime: xLabel = QDateTime::fromMSecsSinceEpoch(static_cast(x*1000.0)).toString("yyyy-MM-dd hh:mm:ss, "); break; case QVariant::String: // In this case, only the y value is displayed xLabel = QString("y="); break; default: xLabel = QLocale().toString(x) + ", "; } ui->plotWidget->setToolTip(xLabel + QLocale().toString(y)); } void PlotDock::mouseWheel() { // Allow user to reset the plot ui->buttonLoadAllData->setEnabled(true); // if an axis (or axis labels) is selected, only allow the direction of that axis to be zoomed // if no axis (or axis labels) is selected, all three axes may be zoomed if (ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) || ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spAxisLabel)) { QList< QCPAxis *> axList = {ui->plotWidget->xAxis}; ui->plotWidget->axisRect()->setRangeZoomAxes(axList); } else if (yAxes[0]->selectedParts().testFlag(QCPAxis::spAxis) || yAxes[0]->selectedParts().testFlag(QCPAxis::spTickLabels) || yAxes[0]->selectedParts().testFlag(QCPAxis::spAxisLabel)) { QList< QCPAxis *> axList = {yAxes[0]}; ui->plotWidget->axisRect()->setRangeZoomAxes(axList); } else if (yAxes[1]->selectedParts().testFlag(QCPAxis::spAxis) || yAxes[1]->selectedParts().testFlag(QCPAxis::spTickLabels) || yAxes[1]->selectedParts().testFlag(QCPAxis::spAxisLabel)) { QList< QCPAxis *> axList = {yAxes[1]}; ui->plotWidget->axisRect()->setRangeZoomAxes(axList); } else{ QList< QCPAxis *> axList = {ui->plotWidget->xAxis,yAxes[0], yAxes[1]}; ui->plotWidget->axisRect()->setRangeZoomAxes(axList); } } void PlotDock::copy() { QApplication::clipboard()->setPixmap(ui->plotWidget->toPixmap()); } void PlotDock::toggleLegendVisible(bool visible) { m_showLegend = visible; ui->plotWidget->legend->setVisible(m_showLegend); ui->plotWidget->replot(); } // Stack or group bars and set the appropriate bar width (since it is not automatically done by QCustomPlot). void PlotDock::adjustBars() { const double padding = 0.15; int plottableCount = ui->plotWidget->plottableCount(); if (plottableCount == 0) return; const double groupedWidth = 1.0 / plottableCount; QCPBars* previousBar = nullptr; QCPBarsGroup* barsGroup = m_stackedBars ? nullptr : new QCPBarsGroup(ui->plotWidget); for (int i = 0, ie = plottableCount; i < ie; ++i) { QCPBars* bar = qobject_cast(ui->plotWidget->plottable(i)); if (bar) { if (m_stackedBars) { // Ungroup if grouped bar->setBarsGroup(nullptr); if (previousBar) bar->moveAbove(previousBar); // Set width to ocuppy the full coordinate space, less padding bar->setWidth(1.0 - padding); } else { // Unstack if stacked bar->moveAbove(nullptr); bar->setBarsGroup(barsGroup); // Set width to a plot coordinate width, less padding bar->setWidth(groupedWidth - padding); } previousBar = bar; } } } namespace { void adjustOneAxisFormat (QCPAxis* axis, bool fixedFormat) { const QString format = fixedFormat? "f" : "gb"; axis->setNumberFormat(format); int precision; // Different values for big numbers and small numbers. if (axis->range().center() > 999 && axis->range().size() > 10) precision = fixedFormat? 0 : 2; else precision = fixedFormat? 2 : 6; axis->setNumberPrecision(precision); } } void PlotDock::adjustAxisFormat() { adjustOneAxisFormat(ui->plotWidget->xAxis, m_fixedFormat); adjustOneAxisFormat(ui->plotWidget->yAxis, m_fixedFormat); adjustOneAxisFormat(ui->plotWidget->yAxis2, m_fixedFormat); } void PlotDock::toggleStackedBars(bool stacked) { m_stackedBars = stacked; adjustBars(); ui->plotWidget->replot(); } void PlotDock::reject() { // We override this, to ensure the Escape key doesn't make this dialog // dock go away return; } void PlotDock::openPrintDialog() { QPrinter printer; QPrintPreviewDialog previewDialog(&printer, this); connect(&previewDialog, &QPrintPreviewDialog::paintRequested, this, &PlotDock::renderPlot); previewDialog.exec(); } void PlotDock::renderPlot(QPrinter* printer) { QCPPainter painter(printer); QRectF pageRect = printer->pageRect(QPrinter::DevicePixel); int plotWidth = ui->plotWidget->viewport().width(); int plotHeight = ui->plotWidget->viewport().height(); double scale = pageRect.width()/static_cast(plotWidth); painter.setMode(QCPPainter::pmVectorized); painter.setMode(QCPPainter::pmNoCaching); painter.scale(scale, scale); ui->plotWidget->toPainter(&painter, plotWidth, plotHeight); } sqlitebrowser-sqlitebrowser-5733cb7/src/PlotDock.h000066400000000000000000000062621463772530400223610ustar00rootroot00000000000000#ifndef PLOTDOCK_H #define PLOTDOCK_H #include "Palette.h" #include #include #include class QMenu; class QPrinter; class QTreeWidgetItem; class QCPAxis; class QMouseEvent; class SqliteTableModel; struct BrowseDataTableSettings; namespace Ui { class PlotDock; } class PlotDock : public QDialog { Q_OBJECT public: explicit PlotDock(QWidget* parent = nullptr); ~PlotDock() override; struct PlotSettings { int lineStyle; int pointShape; QColor colour; bool active; PlotSettings() : lineStyle(0), pointShape(0), active(false) {} PlotSettings(int _lineStyle, int _pointShape, QColor _colour, bool _active) : lineStyle(_lineStyle), pointShape(_pointShape), colour(_colour), active(_active) {} friend QDataStream& operator<<(QDataStream& stream, const PlotDock::PlotSettings& object) { stream << object.lineStyle; stream << object.pointShape; stream << object.colour; stream << object.active; return stream; } friend QDataStream& operator>>(QDataStream& stream, PlotDock::PlotSettings& object) { stream >> object.lineStyle; stream >> object.pointShape; stream >> object.colour; if(!stream.atEnd()) stream >> object.active; return stream; } }; public slots: void updatePlot(SqliteTableModel* model, BrowseDataTableSettings* settings = nullptr, bool update = true, bool keepOrResetSelection = true); void fetchAllData(); void resetPlot(); void reject() override; signals: void pointsSelected(int firstIndex, int count); private: enum PlotColumns { PlotColumnField = 0, PlotColumnX = 1, PlotColumnY1 = 2, PlotColumnY2 = 3, PlotColumnType = 4, }; Ui::PlotDock* ui; SqliteTableModel* m_currentPlotModel; BrowseDataTableSettings* m_currentTableSettings; QMenu* m_contextMenu; bool m_showLegend; bool m_stackedBars; bool m_fixedFormat; Palette m_graphPalette; std::vector yAxes; std::vector PlotColumnY; unsigned int m_xtype; /*! * \brief guessdatatype try to parse the first 10 rows and decide the datatype * \param model model to check the data * \param column index of the column to check * \return the guessed datatype */ QVariant::Type guessDataType(SqliteTableModel* model, int column) const; void adjustBars(); void adjustAxisFormat(); private slots: void columnItemChanged(QTreeWidgetItem* item, int column); void columnItemDoubleClicked(QTreeWidgetItem* item, int column); void savePlot(); void lineTypeChanged(int index); void pointShapeChanged(int index); void selectionChanged(); void mousePress(); void mouseWheel(); void mouseMove(QMouseEvent* event); void copy(); void toggleLegendVisible(bool visible); void toggleStackedBars(bool stacked); void openPrintDialog(); void renderPlot(QPrinter* printer); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/PlotDock.ui000066400000000000000000000343351463772530400225510ustar00rootroot00000000000000 PlotDock 0 0 515 553 Plot 2 0 2 0 Qt::Vertical 0 2 <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> true 5 100 false Columns X Y1 Y2 Axis Type 0 8 Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Line type: comboLineType 0 0 0 0 0 0 50 0 1 None Line StepLeft StepRight StepCenter Impulse Point shape: comboPointShape 0 0 50 0 0 None Cross Plus Circle Disc Square Diamond Star Triangle TriangleInverted CrossSquare PlusSquare CrossCircle PlusCircle Peace Qt::Horizontal 40 20 <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> Save current plot... :/icons/image_save:/icons/image_save false false false false Load all data and redraw plot :/icons/refresh:/icons/refresh QCustomPlot QWidget
qcustomplot.h
1
buttonLoadAllData clicked() PlotDock fetchAllData() 463 526 477 495 treePlotColumns itemChanged(QTreeWidgetItem*,int) PlotDock columnItemChanged(QTreeWidgetItem*,int) -1 -1 -1 -1 treePlotColumns itemDoubleClicked(QTreeWidgetItem*,int) PlotDock columnItemDoubleClicked(QTreeWidgetItem*,int) -1 -1 -1 -1 butSavePlot clicked() PlotDock savePlot() -1 -1 -1 -1 comboLineType currentIndexChanged(int) PlotDock lineTypeChanged(int) -1 -1 -1 -1 comboPointShape currentIndexChanged(int) PlotDock pointShapeChanged(int) -1 -1 -1 -1 fetchAllData() columnItemChanged(QTreeWidgetItem*,int) columnItemDoubleClicked(QTreeWidgetItem*,int) savePlot() lineTypeChanged(int) pointShapeChanged(int)
sqlitebrowser-sqlitebrowser-5733cb7/src/PreferencesDialog.cpp000066400000000000000000001125451463772530400245600ustar00rootroot00000000000000#include "PreferencesDialog.h" #include "ui_PreferencesDialog.h" #include "FileDialog.h" #include "Settings.h" #include "Application.h" #include "MainWindow.h" #include "RemoteNetwork.h" #include "FileExtensionManager.h" #include "ProxyDialog.h" #include #include #include #include #include #include #include PreferencesDialog::PreferencesDialog(QWidget* parent, Tabs tab) : QDialog(parent), ui(new Ui::PreferencesDialog), m_proxyDialog(new ProxyDialog(this)), m_dbFileExtensions(Settings::getValue("General", "DBFileExtensions").toString().split(";;")) { ui->setupUi(this); ui->treeSyntaxHighlighting->setColumnHidden(0, true); ui->tableClientCerts->setColumnHidden(0, true); ui->fr_bin_bg->installEventFilter(this); ui->fr_bin_fg->installEventFilter(this); ui->fr_reg_bg->installEventFilter(this); ui->fr_reg_fg->installEventFilter(this); ui->fr_null_bg->installEventFilter(this); ui->fr_null_fg->installEventFilter(this); ui->fr_formatted_bg->installEventFilter(this); ui->fr_formatted_fg->installEventFilter(this); connect(ui->comboDataBrowserFont, static_cast(&QFontComboBox::currentIndexChanged), this, &PreferencesDialog::updatePreviewFont); connect(ui->spinDataBrowserFontSize, static_cast(&QSpinBox::valueChanged), this, &PreferencesDialog::updatePreviewFont); #ifndef CHECKNEWVERSION ui->labelUpdates->setVisible(false); ui->checkUpdates->setVisible(false); #endif createBuiltinExtensionList(); loadSettings(); connect(ui->appStyleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(adjustColorsToStyle(int))); // Avoid different heights due to having check boxes or not ui->treeSyntaxHighlighting->setUniformRowHeights(true); // Set current tab ui->tabWidget->setCurrentIndex(tab); // Connect 'Export Settings' and 'Import Settings' buttons connect(ui->buttonExportSettings, &QPushButton::clicked, this, &PreferencesDialog::exportSettings); connect(ui->buttonImportSettings, &QPushButton::clicked, this, &PreferencesDialog::importSettings); } /* * Destroys the object and frees any allocated resources */ PreferencesDialog::~PreferencesDialog() { delete ui; } void PreferencesDialog::chooseLocation() { QString s = FileDialog::getExistingDirectory( NoSpecificType, this, tr("Choose a directory"), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if(!s.isEmpty()) ui->locationEdit->setText(s); } void PreferencesDialog::loadSettings() { ui->encodingComboBox->setCurrentIndex(ui->encodingComboBox->findText(Settings::getValue("db", "defaultencoding").toString(), Qt::MatchFixedString)); ui->comboDefaultLocation->setCurrentIndex(Settings::getValue("db", "savedefaultlocation").toInt()); ui->locationEdit->setText(QDir::toNativeSeparators(Settings::getValue("db", "defaultlocation").toString())); ui->checkPromptSQLTabsInNewProject->setChecked(Settings::getValue("General", "promptsqltabsinnewproject").toBool()); ui->checkUpdates->setChecked(Settings::getValue("checkversion", "enabled").toBool()); ui->checkHideSchemaLinebreaks->setChecked(Settings::getValue("db", "hideschemalinebreaks").toBool()); ui->foreignKeysCheckBox->setChecked(Settings::getValue("db", "foreignkeys").toBool()); ui->spinPrefetchSize->setValue(Settings::getValue("db", "prefetchsize").toInt()); ui->editDatabaseDefaultSqlText->setText(Settings::getValue("db", "defaultsqltext").toString()); ui->defaultFieldTypeComboBox->addItems(DBBrowserDB::Datatypes); int defaultFieldTypeIndex = Settings::getValue("db", "defaultfieldtype").toInt(); if (defaultFieldTypeIndex < DBBrowserDB::Datatypes.count()) { ui->defaultFieldTypeComboBox->setCurrentIndex(defaultFieldTypeIndex); } ui->spinStructureFontSize->setValue(Settings::getValue("db", "fontsize").toInt()); // Gracefully handle the preferred Data Browser font not being available int matchingFont = ui->comboDataBrowserFont->findText(Settings::getValue("databrowser", "font").toString(), Qt::MatchExactly); if (matchingFont == -1) matchingFont = ui->comboDataBrowserFont->findText(Settings::getDefaultValue("databrowser", "font").toString()); ui->comboDataBrowserFont->setCurrentIndex(matchingFont); ui->spinDataBrowserFontSize->setValue(Settings::getValue("databrowser", "fontsize").toInt()); loadColorSetting(ui->fr_null_fg, "null_fg"); loadColorSetting(ui->fr_null_bg, "null_bg"); loadColorSetting(ui->fr_bin_fg, "bin_fg"); loadColorSetting(ui->fr_bin_bg, "bin_bg"); loadColorSetting(ui->fr_reg_fg, "reg_fg"); loadColorSetting(ui->fr_reg_bg, "reg_bg"); loadColorSetting(ui->fr_formatted_fg, "formatted_fg"); loadColorSetting(ui->fr_formatted_bg, "formatted_bg"); ui->spinSymbolLimit->setValue(Settings::getValue("databrowser", "symbol_limit").toInt()); ui->spinCompleteThreshold->setValue(Settings::getValue("databrowser", "complete_threshold").toInt()); ui->checkShowImagesInline->setChecked(Settings::getValue("databrowser", "image_preview").toBool()); ui->txtNull->setText(Settings::getValue("databrowser", "null_text").toString()); ui->txtBlob->setText(Settings::getValue("databrowser", "blob_text").toString()); ui->editFilterEscape->setText(Settings::getValue("databrowser", "filter_escape").toString()); ui->spinFilterDelay->setValue(Settings::getValue("databrowser", "filter_delay").toInt()); ui->treeSyntaxHighlighting->resizeColumnToContents(1); for(int i=0; i < ui->treeSyntaxHighlighting->topLevelItemCount(); ++i) { std::string name = ui->treeSyntaxHighlighting->topLevelItem(i)->text(0).toStdString(); QString colorname = Settings::getValue("syntaxhighlighter", name + "_colour").toString(); QColor color = QColor(colorname); ui->treeSyntaxHighlighting->topLevelItem(i)->setForeground(2, color); ui->treeSyntaxHighlighting->topLevelItem(i)->setBackground(2, color); ui->treeSyntaxHighlighting->topLevelItem(i)->setText(2, colorname); // Add font properties except for colour-only entries if (name != "null" && name != "currentline" && name != "background" && name != "foreground" && name != "highlight" && name != "selected_fg" && name != "selected_bg") { ui->treeSyntaxHighlighting->topLevelItem(i)->setCheckState(3, Settings::getValue("syntaxhighlighter", name + "_bold").toBool() ? Qt::Checked : Qt::Unchecked); ui->treeSyntaxHighlighting->topLevelItem(i)->setCheckState(4, Settings::getValue("syntaxhighlighter", name + "_italic").toBool() ? Qt::Checked : Qt::Unchecked); ui->treeSyntaxHighlighting->topLevelItem(i)->setCheckState(5, Settings::getValue("syntaxhighlighter", name + "_underline").toBool() ? Qt::Checked : Qt::Unchecked); } } // Remote settings ui->checkUseRemotes->setChecked(Settings::getValue("remote", "active").toBool()); { auto ca_certs = RemoteNetwork::get().caCertificates(); ui->tableCaCerts->setRowCount(ca_certs.size()); for(int i=0;isetFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableCaCerts->setItem(i, 0, cert_cn); QTableWidgetItem* cert_o = new QTableWidgetItem(cert.subjectInfo(QSslCertificate::Organization).at(0)); cert_o->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableCaCerts->setItem(i, 1, cert_o); QTableWidgetItem* cert_from = new QTableWidgetItem(cert.effectiveDate().toString()); cert_from->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableCaCerts->setItem(i, 2, cert_from); QTableWidgetItem* cert_to = new QTableWidgetItem(cert.expiryDate().toString()); cert_to->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableCaCerts->setItem(i, 3, cert_to); QTableWidgetItem* cert_serialno = new QTableWidgetItem(QString(cert.serialNumber())); cert_serialno->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableCaCerts->setItem(i, 4, cert_serialno); } } { const QStringList client_certs = Settings::getValue("remote", "client_certificates").toStringList(); for(const QString& file : client_certs) { const auto certs = QSslCertificate::fromPath(file); for(const QSslCertificate& cert : certs) addClientCertToTable(file, cert); } } ui->editRemoteCloneDirectory->setText(QDir::toNativeSeparators(Settings::getValue("remote", "clonedirectory").toString())); // Gracefully handle the preferred Editor font not being available matchingFont = ui->comboEditorFont->findText(Settings::getValue("editor", "font").toString(), Qt::MatchExactly); if (matchingFont == -1) matchingFont = ui->comboDataBrowserFont->findText(Settings::getDefaultValue("editor", "font").toString()); ui->comboEditorFont->setCurrentIndex(matchingFont); ui->spinEditorFontSize->setValue(Settings::getValue("editor", "fontsize").toInt()); ui->spinTabSize->setValue(Settings::getValue("editor", "tabsize").toInt()); ui->checkIndentationUseTabs->setChecked(Settings::getValue("editor", "indentation_use_tabs").toBool()); ui->spinLogFontSize->setValue(Settings::getValue("log", "fontsize").toInt()); ui->wrapComboBox->setCurrentIndex(Settings::getValue("editor", "wrap_lines").toInt()); ui->quoteComboBox->setCurrentIndex(Settings::getValue("editor", "identifier_quotes").toInt()); ui->checkAutoCompletion->setChecked(Settings::getValue("editor", "auto_completion").toBool()); ui->checkCompleteUpper->setEnabled(Settings::getValue("editor", "auto_completion").toBool()); ui->checkCompleteUpper->setChecked(Settings::getValue("editor", "upper_keywords").toBool()); ui->checkErrorIndicators->setChecked(Settings::getValue("editor", "error_indicators").toBool()); ui->checkHorizontalTiling->setChecked(Settings::getValue("editor", "horizontal_tiling").toBool()); ui->checkCloseButtonOnTabs->setChecked(Settings::getValue("editor", "close_button_on_tabs").toBool()); ui->listExtensions->addItems(Settings::getValue("extensions", "list").toStringList()); for (int i=0;ilistBuiltinExtensions->count();++i) { QListWidgetItem* item = ui->listBuiltinExtensions->item(i); item->setCheckState(Settings::getValue("extensions", "builtin").toMap().value(item->text()).toBool() ? Qt::Checked : Qt::Unchecked); } ui->checkRegexDisabled->setChecked(Settings::getValue("extensions", "disableregex").toBool()); ui->checkAllowLoadExtension->setChecked(Settings::getValue("extensions", "enable_load_extension").toBool()); fillLanguageBox(); ui->appStyleCombo->setCurrentIndex(Settings::getValue("General", "appStyle").toInt()); ui->toolbarStyleComboMain->setCurrentIndex(Settings::getValue("General", "toolbarStyle").toInt()); ui->toolbarStyleComboStructure->setCurrentIndex(Settings::getValue("General", "toolbarStyleStructure").toInt()); ui->toolbarStyleComboBrowse->setCurrentIndex(Settings::getValue("General", "toolbarStyleBrowse").toInt()); ui->toolbarStyleComboSql->setCurrentIndex(Settings::getValue("General", "toolbarStyleSql").toInt()); ui->toolbarStyleComboEditCell->setCurrentIndex(Settings::getValue("General", "toolbarStyleEditCell").toInt()); ui->spinGeneralFontSize->setValue(Settings::getValue("General", "fontsize").toInt()); ui->spinMaxRecentFiles->setValue(Settings::getValue("General", "maxRecentFiles").toInt()); } void PreferencesDialog::saveSettings(bool accept) { QApplication::setOverrideCursor(Qt::WaitCursor); Settings::setValue("db", "defaultencoding", ui->encodingComboBox->currentText()); Settings::setValue("db", "defaultlocation", ui->locationEdit->text()); Settings::setValue("db", "savedefaultlocation", ui->comboDefaultLocation->currentIndex()); Settings::setValue("db", "hideschemalinebreaks", ui->checkHideSchemaLinebreaks->isChecked()); Settings::setValue("db", "foreignkeys", ui->foreignKeysCheckBox->isChecked()); Settings::setValue("db", "prefetchsize", ui->spinPrefetchSize->value()); Settings::setValue("db", "defaultsqltext", ui->editDatabaseDefaultSqlText->text()); Settings::setValue("db", "defaultfieldtype", ui->defaultFieldTypeComboBox->currentIndex()); Settings::setValue("db", "fontsize", ui->spinStructureFontSize->value()); Settings::setValue("checkversion", "enabled", ui->checkUpdates->isChecked()); Settings::setValue("databrowser", "font", ui->comboDataBrowserFont->currentText()); Settings::setValue("databrowser", "fontsize", ui->spinDataBrowserFontSize->value()); Settings::setValue("databrowser", "image_preview", ui->checkShowImagesInline->isChecked()); saveColorSetting(ui->fr_null_fg, "null_fg"); saveColorSetting(ui->fr_null_bg, "null_bg"); saveColorSetting(ui->fr_reg_fg, "reg_fg"); saveColorSetting(ui->fr_reg_bg, "reg_bg"); saveColorSetting(ui->fr_formatted_fg, "formatted_fg"); saveColorSetting(ui->fr_formatted_bg, "formatted_bg"); saveColorSetting(ui->fr_bin_fg, "bin_fg"); saveColorSetting(ui->fr_bin_bg, "bin_bg"); Settings::setValue("databrowser", "symbol_limit", ui->spinSymbolLimit->value()); Settings::setValue("databrowser", "complete_threshold", ui->spinCompleteThreshold->value()); Settings::setValue("databrowser", "null_text", ui->txtNull->text()); Settings::setValue("databrowser", "blob_text", ui->txtBlob->text()); Settings::setValue("databrowser", "filter_escape", ui->editFilterEscape->text()); Settings::setValue("databrowser", "filter_delay", ui->spinFilterDelay->value()); for(int i=0; i < ui->treeSyntaxHighlighting->topLevelItemCount(); ++i) { std::string name = ui->treeSyntaxHighlighting->topLevelItem(i)->text(0).toStdString(); Settings::setValue("syntaxhighlighter", name + "_colour", ui->treeSyntaxHighlighting->topLevelItem(i)->text(2)); Settings::setValue("syntaxhighlighter", name + "_bold", ui->treeSyntaxHighlighting->topLevelItem(i)->checkState(3) == Qt::Checked); Settings::setValue("syntaxhighlighter", name + "_italic", ui->treeSyntaxHighlighting->topLevelItem(i)->checkState(4) == Qt::Checked); Settings::setValue("syntaxhighlighter", name + "_underline", ui->treeSyntaxHighlighting->topLevelItem(i)->checkState(5) == Qt::Checked); } Settings::setValue("editor", "font", ui->comboEditorFont->currentText()); Settings::setValue("editor", "fontsize", ui->spinEditorFontSize->value()); Settings::setValue("editor", "tabsize", ui->spinTabSize->value()); Settings::setValue("editor", "indentation_use_tabs", ui->checkIndentationUseTabs->isChecked()); Settings::setValue("log", "fontsize", ui->spinLogFontSize->value()); Settings::setValue("editor", "wrap_lines", ui->wrapComboBox->currentIndex()); Settings::setValue("editor", "identifier_quotes", ui->quoteComboBox->currentIndex()); Settings::setValue("editor", "auto_completion", ui->checkAutoCompletion->isChecked()); Settings::setValue("editor", "upper_keywords", ui->checkCompleteUpper->isChecked()); Settings::setValue("editor", "error_indicators", ui->checkErrorIndicators->isChecked()); Settings::setValue("editor", "horizontal_tiling", ui->checkHorizontalTiling->isChecked()); Settings::setValue("editor", "close_button_on_tabs", ui->checkCloseButtonOnTabs->isChecked()); QStringList extList; for(int i=0;ilistExtensions->count();++i) extList.append(ui->listExtensions->item(i)->text()); Settings::setValue("extensions", "list", extList); Settings::setValue("extensions", "disableregex", ui->checkRegexDisabled->isChecked()); Settings::setValue("extensions", "enable_load_extension", ui->checkAllowLoadExtension->isChecked()); QVariantMap builtinExtList; for (int i=0;ilistBuiltinExtensions->count();++i) builtinExtList.insert(ui->listBuiltinExtensions->item(i)->text(), ui->listBuiltinExtensions->item(i)->checkState()); Settings::setValue("extensions", "builtin", QVariant::fromValue(builtinExtList)); // Save remote settings Settings::setValue("remote", "active", ui->checkUseRemotes->isChecked()); QStringList old_client_certs = Settings::getValue("remote", "client_certificates").toStringList(); QStringList new_client_certs; for(int i=0;itableClientCerts->rowCount();i++) { // Loop through the new list of client certs // If this certificate was already imported, remove it from the list of old certificates. All remaining certificates on this // list will be deleted later on. QString path = ui->tableClientCerts->item(i, 0)->text(); if(old_client_certs.contains(path)) { // This is a cert that is already imported old_client_certs.removeAll(path); new_client_certs.push_back(path); } else { // This is a new certificate. Copy file to a safe place. // Generate unique destination file name QString copy_to = QStandardPaths::writableLocation( #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) QStandardPaths::AppDataLocation #else QStandardPaths::GenericDataLocation #endif ).append("/").append(QFileInfo(path).fileName()); int suffix = 0; do { suffix++; } while(QFile::exists(copy_to + QString::number(suffix))); // Copy file copy_to.append(QString::number(suffix)); QDir().mkpath(QStandardPaths::writableLocation( #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) QStandardPaths::AppDataLocation #else QStandardPaths::GenericDataLocation #endif )); QFile::copy(path, copy_to); new_client_certs.push_back(copy_to); } } for(const QString& file : qAsConst(old_client_certs)) { // Now only the deleted client certs are still in the old list. Delete the cert files associated with them. QFile::remove(file); } Settings::setValue("remote", "client_certificates", new_client_certs); Settings::setValue("remote", "clonedirectory", ui->editRemoteCloneDirectory->text()); // Warn about restarting to change language QVariant newLanguage = ui->languageComboBox->itemData(ui->languageComboBox->currentIndex()); if (newLanguage != Settings::getValue("General", "language")) QMessageBox::information(this, QApplication::applicationName(), tr("The language will change after you restart the application.")); Settings::setValue("General", "language", newLanguage); Settings::setValue("General", "appStyle", ui->appStyleCombo->currentIndex()); Settings::setValue("General", "toolbarStyle", ui->toolbarStyleComboMain->currentIndex()); Settings::setValue("General", "toolbarStyleStructure", ui->toolbarStyleComboStructure->currentIndex()); Settings::setValue("General", "toolbarStyleBrowse", ui->toolbarStyleComboBrowse->currentIndex()); Settings::setValue("General", "toolbarStyleSql", ui->toolbarStyleComboSql->currentIndex()); Settings::setValue("General", "toolbarStyleEditCell", ui->toolbarStyleComboEditCell->currentIndex()); Settings::setValue("General", "DBFileExtensions", m_dbFileExtensions.join(";;") ); Settings::setValue("General", "fontsize", ui->spinGeneralFontSize->value()); Settings::setValue("General", "maxRecentFiles", ui->spinMaxRecentFiles->value()); Settings::setValue("General", "promptsqltabsinnewproject", ui->checkPromptSQLTabsInNewProject->isChecked()); m_proxyDialog->saveSettings(); if(accept) PreferencesDialog::accept(); QApplication::restoreOverrideCursor(); } void PreferencesDialog::showColourDialog(QTreeWidgetItem* item, int column) { QString text = item->text(column); if(!text.size() || text.at(0) != '#') return; QColor colour = QColorDialog::getColor(text, this); if(colour.isValid()) { item->setForeground(column, colour); item->setBackground(column, colour); item->setText(column, colour.name()); } } bool PreferencesDialog::eventFilter(QObject *obj, QEvent *event) { // Use mouse click and enter press on the frames to pop up a colour dialog if (obj == ui->fr_bin_bg || obj == ui->fr_bin_fg || obj == ui->fr_reg_bg || obj == ui->fr_reg_fg || obj == ui->fr_formatted_bg || obj == ui->fr_formatted_fg || obj == ui->fr_null_bg || obj == ui->fr_null_fg) { if (event->type() == QEvent::KeyPress) { QKeyEvent *key = static_cast(event); // Not interesting, so send to the parent (might be shortcuts) if((key->key() != Qt::Key_Enter) && (key->key() != Qt::Key_Return)) { return QDialog::eventFilter(obj, event); } } else if (event->type() != QEvent::MouseButtonPress) { // Not a key event neither a mouse event, send to the parent return QDialog::eventFilter(obj, event); } QFrame *frame = qobject_cast(obj); QColor oldColour = frame->palette().color(frame->backgroundRole()); QColor colour = QColorDialog::getColor(oldColour, frame); if (colour.isValid()) { setColorSetting(frame, colour); } // Consume return true; } // Send any other events to the parent return QDialog::eventFilter(obj, event); } void PreferencesDialog::addExtension() { QString file = FileDialog::getOpenFileName( OpenExtensionFile, this, tr("Select extension file"), tr("Extensions(*.so *.dylib *.dll);;All files(*)")); if(QFile::exists(file)) ui->listExtensions->addItem(file); } void PreferencesDialog::removeExtension() { if(ui->listExtensions->currentIndex().isValid()) ui->listExtensions->takeItem(ui->listExtensions->currentIndex().row()); } void PreferencesDialog::createBuiltinExtensionList() { QDir dir; QStringList files; // If we upgrade Qt framework version to 6.x at some point, use 'macos' instead of 'osx.' // For further information, see the https://doc.qt.io/qt-6/qsysinfo.html if (QSysInfo::productType() == "osx") { dir.setPath(qApp->applicationDirPath() + "/../Extensions/"); files = dir.entryList(QStringList() << "*.dylib", QDir::Files); } else if (QSysInfo::productType() == "windows") { dir.setPath(qApp->applicationDirPath() + "/extensions/"); files = dir.entryList(QStringList() << "*.dll", QDir::Files); } else { const QString productType (QSysInfo::productType()); const QString cpuArchitecture (QSysInfo::currentCpuArchitecture()); if (productType == "fedora" || productType == "redhat") { if (cpuArchitecture.contains("64")) dir.setPath("/usr/lib64/"); else dir.setPath("/usr/lib/"); } else { if (cpuArchitecture == "arm") { dir.setPath("/usr/lib/aarch-linux-gnu/"); } else if (cpuArchitecture == "arm64") { dir.setPath("/usr/lib/aarch64-linux-gnu/"); } else if (cpuArchitecture == "i386") { dir.setPath("/usr/lib/i386-linux-gnu/"); } else if (cpuArchitecture == "x86_64") { dir.setPath("/usr/lib/x86_64-linux-gnu/"); } else { dir.setPath("/usr/lib/"); } } // There is no single naming convention for SQLite extension libraries, // but this gives good results, at least on Debian based systems. // The patterns have to exclude "libsqlite3.so", which is the SQLite3 // library, not an extension. files = dir.entryList(QStringList() << "libsqlite3[!.]*.so" << "mod_*.so" << "lib?*sqlite*.so", QDir::Files); } for (const QString& file: files) { QString absoluteFilePath = dir.absoluteFilePath(file); QListWidgetItem* item = new QListWidgetItem(absoluteFilePath, ui->listBuiltinExtensions); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // The check state is redetermined after the 'loadSettings()' function call. item->setCheckState(Qt::Unchecked); ui->listBuiltinExtensions->addItem(item); } } void PreferencesDialog::fillLanguageBox() { QDir translationsDir(QCoreApplication::applicationDirPath() + "/translations", "sqlb_*.qm"); QLocale systemLocale = QLocale::system(); // Add default language if (systemLocale.name() == "en_US") { ui->languageComboBox->addItem(QIcon(":/flags/en_US"), "English (United States) [System Language]", "en_US"); } else { ui->languageComboBox->addItem(QIcon(":/flags/en_US"), "English (United States) [Default Language]", "en_US"); } // Get available *.qm files from translation dir near executable as well as from resources QFileInfoList file_infos = translationsDir.entryInfoList(); file_infos += QDir(":/translations").entryInfoList(); for(const QFileInfo& file : qAsConst(file_infos)) { QLocale locale(file.baseName().remove("sqlb_")); // Skip invalid locales if(locale.name() == "C") continue; // Skip translations that were already loaded if (ui->languageComboBox->findData(locale.name(), Qt::UserRole, Qt::MatchExactly) != -1) continue; QString language = QLocale::languageToString(locale.language()) + " (" + QLocale::countryToString(locale.country()) + ")"; if (locale == systemLocale) language += " [System language]"; ui->languageComboBox->addItem(QIcon(":/flags/" + locale.name()), language, locale.name()); } ui->languageComboBox->model()->sort(0); // Try to select the language for the stored locale int index = ui->languageComboBox->findData(Settings::getValue("General", "language"), Qt::UserRole, Qt::MatchExactly); // If there's no translation for the current locale, default to English if(index < 0) index = ui->languageComboBox->findData("en_US", Qt::UserRole, Qt::MatchExactly); QString chosenLanguage = ui->languageComboBox->itemText(index); QVariant chosenLocale = ui->languageComboBox->itemData(index); QIcon chosenIcon = ui->languageComboBox->itemIcon(index); // There's no "move" method, so we remove and add the chosen language again at the top ui->languageComboBox->removeItem(index); ui->languageComboBox->insertItem(0, chosenIcon, chosenLanguage, chosenLocale); ui->languageComboBox->setCurrentIndex(0); // This is a workaround needed for QDarkStyleSheet. // See https://github.com/ColinDuquesnoy/QDarkStyleSheet/issues/169 QStyledItemDelegate* styledItemDelegate = new QStyledItemDelegate(ui->languageComboBox); ui->languageComboBox->setItemDelegate(styledItemDelegate); } void PreferencesDialog::loadColorSetting(QFrame *frame, const std::string& settingName) { QColor color = QColor(Settings::getValue("databrowser", settingName + "_colour").toString()); setColorSetting(frame, color); } void PreferencesDialog::setColorSetting(QFrame *frame, const QColor &color) { QPalette::ColorRole role; QLineEdit *line; if (frame == ui->fr_bin_bg) { line = ui->txtBlob; role = line->backgroundRole(); } else if (frame == ui->fr_bin_fg) { line = ui->txtBlob; role = line->foregroundRole(); } else if (frame == ui->fr_reg_bg) { line = ui->txtRegular; role = line->backgroundRole(); } else if (frame == ui->fr_reg_fg) { line = ui->txtRegular; role = line->foregroundRole(); } else if (frame == ui->fr_formatted_bg) { line = ui->txtFormatted; role = line->backgroundRole(); } else if (frame == ui->fr_formatted_fg) { line = ui->txtFormatted; role = line->foregroundRole(); } else if (frame == ui->fr_null_bg) { line = ui->txtNull; role = line->backgroundRole(); } else if (frame == ui->fr_null_fg) { line = ui->txtNull; role = line->foregroundRole(); } else return; QPalette palette = frame->palette(); palette.setColor(frame->backgroundRole(), color); frame->setPalette(palette); frame->setStyleSheet(QString(".QFrame {background-color: %2}").arg(color.name())); palette = line->palette(); palette.setColor(role, color); line->setPalette(palette); line->setStyleSheet(QString(".QLineEdit {color: %1; background-color: %2}").arg(palette.color(line->foregroundRole()).name(), palette.color(line->backgroundRole()).name())); } void PreferencesDialog::saveColorSetting(QFrame* frame, const std::string& settingName) { Settings::setValue("databrowser", settingName + "_colour", frame->palette().color(frame->backgroundRole())); } void PreferencesDialog::adjustColorsToStyle(int style) { Settings::AppStyle appStyle = static_cast(style); setColorSetting(ui->fr_null_fg, Settings::getDefaultColorValue("databrowser", "null_fg_colour", appStyle)); setColorSetting(ui->fr_null_bg, Settings::getDefaultColorValue("databrowser", "null_bg_colour", appStyle)); setColorSetting(ui->fr_bin_fg, Settings::getDefaultColorValue("databrowser", "bin_fg_colour", appStyle)); setColorSetting(ui->fr_bin_bg, Settings::getDefaultColorValue("databrowser", "bin_bg_colour", appStyle)); setColorSetting(ui->fr_reg_fg, Settings::getDefaultColorValue("databrowser", "reg_fg_colour", appStyle)); setColorSetting(ui->fr_reg_bg, Settings::getDefaultColorValue("databrowser", "reg_bg_colour", appStyle)); setColorSetting(ui->fr_formatted_fg, Settings::getDefaultColorValue("databrowser", "formatted_fg_colour", appStyle)); setColorSetting(ui->fr_formatted_bg, Settings::getDefaultColorValue("databrowser", "formatted_bg_colour", appStyle)); for(int i=0; i < ui->treeSyntaxHighlighting->topLevelItemCount(); ++i) { std::string name = ui->treeSyntaxHighlighting->topLevelItem(i)->text(0).toStdString(); QColor color = Settings::getDefaultColorValue("syntaxhighlighter", name + "_colour", appStyle); ui->treeSyntaxHighlighting->topLevelItem(i)->setForeground(2, color); ui->treeSyntaxHighlighting->topLevelItem(i)->setBackground(2, color); ui->treeSyntaxHighlighting->topLevelItem(i)->setText(2, color.name()); } } void PreferencesDialog::activateRemoteTab(bool active) { ui->tabWidget->setTabEnabled(ui->tabWidget->indexOf(ui->tabRemote), active); } void PreferencesDialog::addClientCertificate() { // Get certificate file to import and abort here if no file gets selected // NOTE: We assume here that this file contains both, certificate and private key! QString path = FileDialog::getOpenFileName(OpenCertificateFile, this, tr("Import certificate file"), "*.pem"); if(path.isEmpty()) return; // Open file and check if any certificates were imported auto certs = QSslCertificate::fromPath(path); if(certs.size() == 0) { QMessageBox::warning(this, qApp->applicationName(), tr("No certificates found in this file.")); return; } // Add certificates to list for(int i=0;itableClientCerts->currentRow(); if(row == -1) return; // Double check if(QMessageBox::question(this, qApp->applicationName(), tr("Are you sure you want do remove this certificate? All certificate " "data will be deleted from the application settings!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { ui->tableClientCerts->removeRow(row); } } void PreferencesDialog::addClientCertToTable(const QString& path, const QSslCertificate& cert) { // Do nothing if the file doesn't even exist if(!QFile::exists(path)) return; // Add new row int row = ui->tableClientCerts->rowCount(); ui->tableClientCerts->setRowCount(row + 1); // Fill row with data QTableWidgetItem* cert_file = new QTableWidgetItem(path); cert_file->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableClientCerts->setItem(row, 0, cert_file); QTableWidgetItem* cert_subject_cn = new QTableWidgetItem(cert.subjectInfo(QSslCertificate::CommonName).at(0)); cert_subject_cn->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableClientCerts->setItem(row, 1, cert_subject_cn); QTableWidgetItem* cert_issuer_cn = new QTableWidgetItem(cert.issuerInfo(QSslCertificate::CommonName).at(0)); cert_issuer_cn->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableClientCerts->setItem(row, 2, cert_issuer_cn); QTableWidgetItem* cert_from = new QTableWidgetItem(cert.effectiveDate().toString()); cert_from->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableClientCerts->setItem(row, 3, cert_from); QTableWidgetItem* cert_to = new QTableWidgetItem(cert.expiryDate().toString()); cert_to->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableClientCerts->setItem(row, 4, cert_to); QTableWidgetItem* cert_serialno = new QTableWidgetItem(QString(cert.serialNumber())); cert_serialno->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ui->tableClientCerts->setItem(row, 5, cert_serialno); } void PreferencesDialog::chooseRemoteCloneDirectory() { QString s = FileDialog::getExistingDirectory( NoSpecificType, this, tr("Choose a directory"), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if(!s.isEmpty() && QDir().mkpath(s)) ui->editRemoteCloneDirectory->setText(s); } void PreferencesDialog::updatePreviewFont() { if (ui->spinDataBrowserFontSize->value() != 0) { QFont textFont(ui->comboDataBrowserFont->currentText()); textFont.setPointSize(ui->spinDataBrowserFontSize->value()); ui->txtRegular->setFont(textFont); ui->txtFormatted->setFont(textFont); textFont.setItalic(true); ui->txtNull->setFont(textFont); ui->txtBlob->setFont(textFont); } } void PreferencesDialog::showFileExtensionManager() { FileExtensionManager *manager = new FileExtensionManager(m_dbFileExtensions, this); if(manager->exec() == QDialog::Accepted) { m_dbFileExtensions = manager->getDBFileExtensions(); } } void PreferencesDialog::buttonBoxClicked(QAbstractButton* button) { if (button == ui->buttonBox->button(QDialogButtonBox::Cancel)) reject(); else if (button == ui->buttonBox->button(QDialogButtonBox::Save)) saveSettings(); else if (button == ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)) { if (QMessageBox::warning(this, QApplication::applicationName(), tr("Are you sure you want to clear all the saved settings?\nAll your preferences will be lost and default values will be used."), QMessageBox::RestoreDefaults | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::RestoreDefaults) { Settings::restoreDefaults(); accept(); } } } void PreferencesDialog::configureProxy() { m_proxyDialog->show(); } void PreferencesDialog::exportSettings() { saveSettings(false); const QString fileName = FileDialog::getSaveFileName(CreateSettingsFile, this, tr("Save Settings File"), tr("Initialization File (*.ini)")); if(!fileName.isEmpty()) { Settings::exportSettings(fileName); QMessageBox::information(this, QApplication::applicationName(), (tr("The settings file has been saved in location :\n") + fileName)); } } void PreferencesDialog::importSettings() { const QString fileName = FileDialog::getOpenFileName(OpenSettingsFile, this, tr("Open Settings File"), tr("Initialization File (*.ini)")); const QVariant existingLanguage = Settings::getValue("General", "language"); if(!fileName.isEmpty()) { if(Settings::importSettings(fileName)) { QMessageBox::information(this, QApplication::applicationName(), tr("The settings file was loaded properly.")); if (existingLanguage != Settings::getValue("General", "language")) QMessageBox::information(this, QApplication::applicationName(), tr("The language will change after you restart the application.")); accept(); } else { QMessageBox::critical(this, QApplication::applicationName(), tr("The selected settings file is not a normal settings file.\nPlease check again.")); } } } sqlitebrowser-sqlitebrowser-5733cb7/src/PreferencesDialog.h000066400000000000000000000032571463772530400242240ustar00rootroot00000000000000#ifndef PREFERENCESDIALOG_H #define PREFERENCESDIALOG_H #include class QTreeWidgetItem; class QFrame; class QSslCertificate; class QAbstractButton; class ProxyDialog; namespace Ui { class PreferencesDialog; } class PreferencesDialog : public QDialog { Q_OBJECT public: enum Tabs { TabGeneral, TabDatabase, TabDataBrowser, TabSql, TabExtensions, TabRemote }; explicit PreferencesDialog(QWidget* parent = nullptr, Tabs tab = TabGeneral); ~PreferencesDialog() override; private slots: void loadSettings(); void saveSettings(bool accept=true); void chooseLocation(); void showColourDialog(QTreeWidgetItem* item, int column); void addExtension(); void createBuiltinExtensionList(); void removeExtension(); void activateRemoteTab(bool active); void addClientCertificate(); void removeClientCertificate(); void chooseRemoteCloneDirectory(); void updatePreviewFont(); void adjustColorsToStyle(int style); void configureProxy(); void showFileExtensionManager(); void buttonBoxClicked(QAbstractButton* button); private: Ui::PreferencesDialog* ui; ProxyDialog* m_proxyDialog; QStringList m_dbFileExtensions; void fillLanguageBox(); void loadColorSetting(QFrame *frame, const std::string& name); void setColorSetting(QFrame* frame, const QColor &color); void saveColorSetting(QFrame* frame, const std::string& name); void addClientCertToTable(const QString& path, const QSslCertificate& cert); void exportSettings(); void importSettings(); protected: bool eventFilter(QObject *obj, QEvent *event) override; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/PreferencesDialog.ui000066400000000000000000002370451463772530400244160ustar00rootroot00000000000000 PreferencesDialog 0 0 756 625 Preferences true 0 &General Default &location locationEdit Remember last location Always use this location Remember last location for session only false 0 0 316 0 ... Lan&guage languageComboBox 0 0 QComboBox::AdjustToContents 35 20 15 Toolbar style toolbarStyleComboMain 0 0 2 QComboBox::AdjustToContents 35 20 15 Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style 0 0 2 QComboBox::AdjustToContents 35 20 15 Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style 0 0 0 QComboBox::AdjustToContents 35 20 15 Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style 0 0 0 QComboBox::AdjustToContents 35 20 15 Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style Show remote options checkUseRemotes enabled true Automatic &updates checkUpdates enabled DB file extensions buttonManageFileExtension Manage Main Window 20 toolbarStyleComboMain Database Structure 20 toolbarStyleComboStructure Browse Data 20 toolbarStyleComboBrowse Execute SQL 20 toolbarStyleComboSql 0 0 0 QComboBox::AdjustToContents 35 20 15 Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style Edit Database Cell 20 toolbarStyleComboEditCell 0 0 When this value is changed, all the other color preferences are also set to matching colors. 0 QComboBox::AdjustToContents 35 20 15 Follow the desktop style Dark style Light style Application style toolbarStyleComboStructure This sets the font size for all UI elements which do not have their own font size option. Font size spinGeneralFontSize Max Recent Files spinMaxRecentFiles 1 40 Prompt to save SQL tabs in new project file checkPromptSQLTabsInNewProject If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. enabled true &Database QFormLayout::FieldsStayAtSizeHint Database &encoding encodingComboBox Open databases with foreign keys enabled. &Foreign keys foreignKeysCheckBox Remove line breaks in schema &view checkHideSchemaLinebreaks Prefetch block si&ze spinPrefetchSize Default field type defaultFieldTypeComboBox 255 1000000 When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. enabled enabled UTF-8 UTF-16 Database structure font size spinStructureFontSize SQ&L to execute after opening database editDatabaseDefaultSqlText 20 0 16777215 16777215 Data &Browser 0 0 Font Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter &Font Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter comboDataBrowserFont 0 0 Font si&ze Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter spinDataBrowserFontSize Field display 0 0 Displayed &text Qt::AlignCenter txtNull NULL Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Binary Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Formatted Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Regular Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Qt::StrongFocus Click to set this color true QFrame::StyledPanel QFrame::Raised Qt::StrongFocus Click to set this color true QFrame::StyledPanel QFrame::Raised 0 0 Text color Qt::AlignCenter Qt::StrongFocus Click to set this color true QFrame::StyledPanel QFrame::Raised 0 0 Background color Qt::AlignCenter Qt::StrongFocus Click to set this color true QFrame::StyledPanel QFrame::Raised Qt::StrongFocus Click to set this color true QFrame::StyledPanel QFrame::Raised Qt::StrongFocus Click to set this color true QFrame::StyledPanel QFrame::Raised Qt::StrongFocus Click to set this color true QFrame::StyledPanel QFrame::Raised Qt::StrongFocus Click to set this color true QFrame::StyledPanel QFrame::Raised 0 0 true NULL 0 0 false Preview only (N/A) true 0 0 false Preview only (N/A) true 0 0 true BLOB false 0 0 Content Symbol limit in cell spinSymbolLimit Threshold for completion and calculation on selection spinCompleteThreshold Show images in cell checkShowImagesInline 1 20000 This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. 0 100000000 Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. 0 0 Filters QLayout::SetDefaultConstraint Delay time (&ms) spinFilterDelay Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. 5000 Escape character editFilterEscape 1 &SQL false false Settings name Context Colour Bold Italic Underline keyword Keyword function Function table Table comment Comment identifier Identifier string String currentline Current line background Background foreground Foreground selected_bg Selection background selected_fg Selection foreground highlight Highlight SQL editor &font comboEditorFont SQL &editor font size Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter spinEditorFontSize 1 SQL &results font size spinLogFontSize 1 Tab size spinTabSize 1 16 4 Use tabs for indentation checkAutoCompletion When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. enabled &Wrap lines wrapComboBox Never At word boundaries At character boundaries At whitespace boundaries &Quotes for identifiers quoteComboBox Choose the quoting mechanism used by the application for identifiers in SQL code. "Double quotes" - Standard SQL (recommended) `Grave accents` - Traditional MySQL quotes [Square brackets] - Traditional MS SQL Server quotes Code co&mpletion checkAutoCompletion enabled Keywords in &UPPER CASE checkCompleteUpper When set, the SQL keywords are completed in UPPER CASE letters. enabled Error indicators checkErrorIndicators When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background enabled Hori&zontal tiling checkHorizontalTiling If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. enabled Close button on tabs checkCloseButtonOnTabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. enabled &Extensions Select extensions to load for every database: listExtensions QAbstractItemView::NoEditTriggers false Add extension :/icons/load_extension:/icons/load_extension Remove extension :/icons/remove_extension:/icons/remove_extension Qt::Vertical 20 40 Select built-in extensions to load for every database: true <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> Disable Regular Expression extension <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> Allow loading extensions from SQL code Remote 0 Your certificates 550 0 QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows QAbstractItemView::ScrollPerPixel false File Subject CN Subject Common Name Issuer CN Issuer Common Name Valid from Valid to Serial number :/icons/trigger_create:/icons/trigger_create ... :/icons/trigger_delete:/icons/trigger_delete Qt::Vertical 20 40 CA certificates 550 0 QAbstractItemView::SingleSelection QAbstractItemView::SelectRows QAbstractItemView::ScrollPerPixel false Subject CN Common Name Subject O Organization Valid from Valid to Serial number Clone databases into editRemoteCloneDirectory false 0 0 316 0 ... Proxy buttonProxy Configure Export Settings Import Settings Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save SqlTextEdit QTextEdit
sqltextedit.h
1
tabWidget comboDefaultLocation locationEdit setLocationButton languageComboBox appStyleCombo spinGeneralFontSize spinMaxRecentFiles toolbarStyleComboMain toolbarStyleComboStructure toolbarStyleComboBrowse toolbarStyleComboSql toolbarStyleComboEditCell checkPromptSQLTabsInNewProject checkUseRemotes checkUpdates buttonManageFileExtension encodingComboBox foreignKeysCheckBox checkHideSchemaLinebreaks spinPrefetchSize defaultFieldTypeComboBox spinStructureFontSize editDatabaseDefaultSqlText comboDataBrowserFont spinDataBrowserFontSize fr_null_fg fr_null_bg txtNull fr_bin_fg fr_bin_bg txtBlob fr_formatted_fg fr_formatted_bg txtFormatted fr_reg_fg fr_reg_bg txtRegular spinSymbolLimit spinCompleteThreshold checkShowImagesInline spinFilterDelay editFilterEscape treeSyntaxHighlighting comboEditorFont spinEditorFontSize spinLogFontSize spinTabSize checkIndentationUseTabs wrapComboBox quoteComboBox checkAutoCompletion checkCompleteUpper checkErrorIndicators checkHorizontalTiling checkCloseButtonOnTabs listExtensions buttonAddExtension buttonRemoveExtension checkRegexDisabled checkAllowLoadExtension tabCertificates tableClientCerts buttonClientCertAdd buttonClientCertRemove buttonProxy editRemoteCloneDirectory buttonRemoteBrowseCloneDirectory tableCaCerts buttonExportSettings buttonImportSettings buttonAddExtension clicked() PreferencesDialog addExtension() 733 94 245 137 buttonRemoveExtension clicked() PreferencesDialog removeExtension() 733 123 245 137 treeSyntaxHighlighting itemDoubleClicked(QTreeWidgetItem*,int) PreferencesDialog showColourDialog(QTreeWidgetItem*,int) 103 48 395 0 setLocationButton clicked() PreferencesDialog chooseLocation() 733 103 294 202 checkUseRemotes toggled(bool) PreferencesDialog activateRemoteTab(bool) 301 503 382 572 buttonClientCertAdd clicked() PreferencesDialog addClientCertificate() 723 108 596 243 buttonClientCertRemove clicked() PreferencesDialog removeClientCertificate() 723 137 597 295 buttonRemoteBrowseCloneDirectory clicked() PreferencesDialog chooseRemoteCloneDirectory() 733 568 595 41 checkAutoCompletion toggled(bool) checkCompleteUpper setEnabled(bool) 733 444 733 474 buttonBox clicked(QAbstractButton*) PreferencesDialog buttonBoxClicked(QAbstractButton*) 644 614 385 306 buttonProxy clicked() PreferencesDialog configureProxy() 251 537 385 306 buttonManageFileExtension clicked() PreferencesDialog showFileExtensionManager() -1 -1 -1 -1 saveSettings() chooseLocation() showColourDialog(QTreeWidgetItem*,int) addExtension() removeExtension() activateRemoteTab(bool) addClientCertificate() removeClientCertificate() chooseRemoteCloneDirectory() configureProxy() buttonBoxClicked() showFileExtensionManager()
sqlitebrowser-sqlitebrowser-5733cb7/src/ProxyDialog.cpp000066400000000000000000000046001463772530400234300ustar00rootroot00000000000000#include "ProxyDialog.h" #include "ui_ProxyDialog.h" #include "Settings.h" ProxyDialog::ProxyDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ProxyDialog) { ui->setupUi(this); // Add different proxy types. We use user data strings for addressing them later ui->comboType->addItem(tr("None"), "none"); ui->comboType->addItem(tr("System settings"), "system"); ui->comboType->addItem(tr("HTTP"), "http"); ui->comboType->addItem(tr("SOCKS5"), "socks5"); // Load current settings ui->comboType->setCurrentIndex(ui->comboType->findData(Settings::getValue("proxy", "type").toString())); ui->editHost->setText(Settings::getValue("proxy", "host").toString()); ui->spinPort->setValue(Settings::getValue("proxy", "port").toInt()); ui->checkAuthentication->setChecked(Settings::getValue("proxy", "authentication").toBool()); ui->editUser->setText(Settings::getValue("proxy", "user").toString()); ui->editPassword->setText(Settings::getValue("proxy", "password").toString()); } ProxyDialog::~ProxyDialog() { delete ui; } void ProxyDialog::proxyTypeChanged(int /*new_index*/) { // When selecting the "None" or "System settings" proxy types, disable all the other input fields bool proxy_configuration = (ui->comboType->currentData() != "none" && ui->comboType->currentData() != "system"); ui->editHost->setEnabled(proxy_configuration); ui->spinPort->setEnabled(proxy_configuration); ui->checkAuthentication->setEnabled(proxy_configuration); ui->editUser->setEnabled(ui->checkAuthentication->isChecked() && proxy_configuration); // Enable user name and password only if the... ui->editPassword->setEnabled(ui->checkAuthentication->isChecked() && proxy_configuration); // ... Authentication Required checkbox is checked } void ProxyDialog::authenticationRequiredChanged(bool required) { ui->editUser->setEnabled(required); ui->editPassword->setEnabled(required); } void ProxyDialog::saveSettings() const { Settings::setValue("proxy", "type", ui->comboType->currentData()); Settings::setValue("proxy", "host", ui->editHost->text()); Settings::setValue("proxy", "port", ui->spinPort->value()); Settings::setValue("proxy", "authentication", ui->checkAuthentication->isChecked()); Settings::setValue("proxy", "user", ui->editUser->text()); Settings::setValue("proxy", "password", ui->editPassword->text()); } sqlitebrowser-sqlitebrowser-5733cb7/src/ProxyDialog.h000066400000000000000000000006621463772530400231010ustar00rootroot00000000000000#ifndef PROXYDIALOG_H #define PROXYDIALOG_H #include namespace Ui { class ProxyDialog; } class ProxyDialog : public QDialog { Q_OBJECT public: explicit ProxyDialog(QWidget* parent = nullptr); ~ProxyDialog() override; void saveSettings() const; private slots: void proxyTypeChanged(int new_index); void authenticationRequiredChanged(bool required); private: Ui::ProxyDialog* ui; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/ProxyDialog.ui000066400000000000000000000120131463772530400232600ustar00rootroot00000000000000 ProxyDialog 0 0 535 231 Proxy Configuration Pro&xy Type comboType Host Na&me editHost Port spinPort 1 65536 Authentication Re&quired checkAuthentication &User Name editUser Password editPassword QLineEdit::Password Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok comboType editHost spinPort checkAuthentication editUser editPassword buttonBox accepted() ProxyDialog accept() 227 210 157 230 buttonBox rejected() ProxyDialog reject() 295 216 286 230 comboType currentIndexChanged(int) ProxyDialog proxyTypeChanged(int) 343 22 267 115 checkAuthentication toggled(bool) ProxyDialog authenticationRequiredChanged(bool) 343 114 267 115 proxyTypeChanged(int) authenticationRequiredChanged(bool) sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteCommitsModel.cpp000066400000000000000000000124041463772530400247400ustar00rootroot00000000000000#include #include "Data.h" #include "RemoteCommitsModel.h" #include "Settings.h" using json = nlohmann::json; RemoteCommitsModel::RemoteCommitsModel(QObject* parent) : QAbstractItemModel(parent) { QStringList header; header << tr("Commit ID") << tr("Message") << tr("Date") << tr("Author") << tr("Size"); rootItem = new QTreeWidgetItem(header); } RemoteCommitsModel::~RemoteCommitsModel() { delete rootItem; } void RemoteCommitsModel::clear() { beginResetModel(); // Remove all data except for the root item while(rootItem->childCount()) delete rootItem->child(0); endResetModel(); } void RemoteCommitsModel::refresh(const std::string& json_data, const std::string& last_commit_id, const std::string& current_commit_id) { // Clear previous items clear(); beginResetModel(); // Read in all commits json j = json::parse(json_data, nullptr, false); std::unordered_map commit_to_iterator; for(auto it=j.begin();it!=j.end();++it) commit_to_iterator.insert({it.value()["id"], it}); // Starting from the last commit add follow the chain up to the first commit std::string parent_id = last_commit_id; while(true) { if(commit_to_iterator.find(parent_id) == commit_to_iterator.end()) break; json commit = commit_to_iterator[parent_id].value(); QTreeWidgetItem* item = new QTreeWidgetItem(rootItem); item->setText(ColumnCommitId, QString::fromStdString(commit["id"])); item->setText(ColumnMessage, QString::fromStdString(commit["message"])); item->setToolTip(ColumnMessage, QString::fromStdString(commit["message"])); item->setText(ColumnDate, isoDateTimeStringToLocalDateTimeString(QString::fromStdString(commit["timestamp"]))); QString authored_by = QString::fromStdString(commit["author_name"]) + " <" + QString::fromStdString(commit["author_email"]) + ">"; QString committed_by = QString::fromStdString(commit["committer_name"]) + " <" + QString::fromStdString(commit["committer_email"]) + ">"; item->setText(ColumnAuthor, authored_by); if(committed_by == " <>" || authored_by == committed_by) // The first check effectively checks for no committer details item->setToolTip(ColumnAuthor, tr("Authored and committed by %1").arg(authored_by)); else item->setToolTip(ColumnAuthor, tr("Authored by %1, committed by %2").arg(authored_by, committed_by)); for(const auto& e : commit["tree"]["entries"]) { if(e["entry_type"] == "db") { item->setText(ColumnSize, humanReadableSize(e["size"])); break; } } // Make the currently checked out commit id bold if(current_commit_id == commit["id"]) { QFont bold_font = item->font(ColumnCommitId); bold_font.setBold(true); item->setFont(0, bold_font); } parent_id = commit["parent"].get(); } // Refresh the view endResetModel(); } QModelIndex RemoteCommitsModel::index(int row, int column, const QModelIndex& parent) const { if(!hasIndex(row, column, parent)) return QModelIndex(); QTreeWidgetItem *parentItem; if(!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); QTreeWidgetItem* childItem = parentItem->child(row); if(childItem) return createIndex(row, column, childItem); else return QModelIndex(); } QModelIndex RemoteCommitsModel::parent(const QModelIndex& index) const { if(!index.isValid()) return QModelIndex(); QTreeWidgetItem* childItem = static_cast(index.internalPointer()); QTreeWidgetItem* parentItem = childItem->parent(); if(parentItem == rootItem) return QModelIndex(); else return createIndex(0, 0, parentItem); } QVariant RemoteCommitsModel::data(const QModelIndex& index, int role) const { if(!index.isValid()) return QVariant(); // Get the item the index points at QTreeWidgetItem* item = static_cast(index.internalPointer()); // Return data depending on the role switch(role) { case Qt::DisplayRole: case Qt::EditRole: return item->text(index.column()); case Qt::ToolTipRole: return item->toolTip(index.column()); case Qt::FontRole: return item->font(0); // Choose font for the entire row depending on the first column default: return QVariant(); } } QVariant RemoteCommitsModel::headerData(int section, Qt::Orientation orientation, int role) const { // Get the header string from the root item if(orientation == Qt::Horizontal && role == Qt::DisplayRole) return rootItem->data(section, role); return QVariant(); } int RemoteCommitsModel::rowCount(const QModelIndex& parent) const { if(parent.column() > 0) return 0; if(!parent.isValid()) return rootItem->childCount(); else return static_cast(parent.internalPointer())->childCount(); } int RemoteCommitsModel::columnCount(const QModelIndex& /*parent*/) const { return rootItem->columnCount(); } sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteCommitsModel.h000066400000000000000000000022451463772530400244070ustar00rootroot00000000000000#ifndef REMOTECOMMITSMODEL_H #define REMOTECOMMITSMODEL_H #include #include class QTreeWidgetItem; class RemoteCommitsModel : public QAbstractItemModel { Q_OBJECT public: explicit RemoteCommitsModel(QObject* parent); ~RemoteCommitsModel() override; void clear(); void refresh(const std::string& json_data, const std::string& last_commit_id, const std::string& current_commit_id); QModelIndex index(int row, int column,const QModelIndex& parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& index) const override; QVariant data(const QModelIndex& index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; enum Columns { ColumnCommitId, ColumnMessage, ColumnDate, ColumnAuthor, ColumnSize, }; private: // Pointer to the root item. This contains all the actual item data. QTreeWidgetItem* rootItem; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteDatabase.cpp000066400000000000000000000406571463772530400240630ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "FileDialog.h" #include "RemoteDatabase.h" #include "Settings.h" #include "sqlite.h" #include "version.h" RemoteDatabase::RemoteDatabase() : m_dbLocal(nullptr) { } RemoteDatabase::~RemoteDatabase() { // Close local storage db - but only if it was created/opened in the meantime if(m_dbLocal) sqlite3_close(m_dbLocal); } void RemoteDatabase::localAssureOpened() { // This function should be called first in each RemoteDatabase::local* function. It assures the database for storing // the local database information is opened and ready. If the database file doesn't exist yet it is created by this // function. If the database file is already created and opened this function does nothing. The reason to open the // database on first use instead of doing that in the constructor of this class is that this way no database file is // going to be created and no database handle is held when it's not actually needed. For people not interested in // the dbhub.io functionality this means no unnecessary files being created. // Check if database is already opened and return if it is if(m_dbLocal) return; // Make sure the directory exists QString database_directory = QStandardPaths::writableLocation( #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) QStandardPaths::AppDataLocation #else QStandardPaths::GenericDataLocation #endif ); QDir().mkpath(database_directory); // Open file QString database_file = database_directory + "/remotedbs.db"; if(sqlite3_open_v2(database_file.toUtf8(), &m_dbLocal, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) { QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error opening local databases list.\n%1").arg(QString::fromUtf8(sqlite3_errmsg(m_dbLocal)))); return; } // Create local local table if it doesn't exists yet char* errmsg; QString statement = QString("CREATE TABLE IF NOT EXISTS \"local\"(" "\"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," "\"identity\" TEXT NOT NULL," "\"name\" TEXT NOT NULL," "\"url\" TEXT NOT NULL," "\"commit_id\" TEXT NOT NULL," "\"file\" TEXT NOT NULL UNIQUE," "\"modified\" INTEGER DEFAULT 0," "\"branch\" TEXT NOT NULL DEFAULT \"main\"" ")"); if(sqlite3_exec(m_dbLocal, statement.toUtf8(), nullptr, nullptr, &errmsg) != SQLITE_OK) { QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error creating local databases list.\n%1").arg(QString::fromUtf8(errmsg))); sqlite3_free(errmsg); sqlite3_close(m_dbLocal); m_dbLocal = nullptr; return; } } QString RemoteDatabase::localAdd(QString filename, QString identity, const QUrl& url, const std::string& new_commit_id, const std::string& branch) { localAssureOpened(); // Remove the path QFileInfo f(identity); identity = f.fileName(); // Check if this file has already been checked in std::string last_commit_id = localLastCommitId(identity, url.toString(), branch); if(last_commit_id.empty()) { // The file hasn't been checked in yet. So add a new record for it. // Generate a new file name to save the file under filename = QString("%2_%1.remotedb").arg(QDateTime::currentMSecsSinceEpoch()).arg(filename); // Insert database into local database list QString sql = QString("INSERT INTO local(identity, name, url, commit_id, file, branch) VALUES(?, ?, ?, ?, ?, ?)"); sqlite3_stmt* stmt; if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) return QString(); if(sqlite3_bind_text(stmt, 1, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_bind_text(stmt, 2, url.fileName().toUtf8(), url.fileName().toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_bind_text(stmt, 3, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(), url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_bind_text(stmt, 4, new_commit_id.c_str(), static_cast(new_commit_id.size()), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_bind_text(stmt, 5, filename.toUtf8(), filename.size(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_bind_text(stmt, 6, branch.c_str(), static_cast(branch.size()), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_step(stmt) != SQLITE_DONE) { sqlite3_finalize(stmt); return QString(); } sqlite3_finalize(stmt); // Return full path to the new file return Settings::getValue("remote", "clonedirectory").toString() + "/" + filename; } // If we get here, the file has been checked in before. Check next if it has been updated in the meantime. if(last_commit_id != new_commit_id) { // The file has already been checked in and the commit ids are different. If they weren't we wouldn't need to update anything QString sql = QString("UPDATE local SET commit_id=? WHERE identity=? AND url=? AND branch=?"); sqlite3_stmt* stmt; if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) return QString(); if(sqlite3_bind_text(stmt, 1, new_commit_id.c_str(), static_cast(new_commit_id.size()), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_bind_text(stmt, 2, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_bind_text(stmt, 3, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(), url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_bind_text(stmt, 4, branch.c_str(), static_cast(branch.size()), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_step(stmt) != SQLITE_DONE) { sqlite3_finalize(stmt); return QString(); } sqlite3_finalize(stmt); } // If we got here, the file was already checked in (and was either updated or not (obviously)). This mean we can just return the file name as // we know it. return localExists(url, identity, branch); } QString RemoteDatabase::localExists(const QUrl& url, QString identity, const std::string& branch) { localAssureOpened(); // Extract commit id from url and remove query part afterwards QString url_commit_id = QUrlQuery(url).queryItemValue("commit"); // Query commit id and filename for the given combination of url and identity QString sql = QString("SELECT id, commit_id, file FROM local WHERE url=? AND identity=? AND branch=?"); sqlite3_stmt* stmt; if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) return QString(); if(sqlite3_bind_text(stmt, 1, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(), url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } QFileInfo f(identity); // Remove the path identity = f.fileName(); if(sqlite3_bind_text(stmt, 2, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_bind_text(stmt, 3, branch.c_str(), static_cast(branch.size()), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return QString(); } if(sqlite3_step(stmt) != SQLITE_ROW) { // If there was either an error or no record was found for this combination of url and // identity, stop here. sqlite3_finalize(stmt); return QString(); } // Having come here we can assume that at least some local clone for the given combination of // url, identity and branch exists. So extract all the information we have on it. QString local_commit_id = QString::fromUtf8(reinterpret_cast(sqlite3_column_text(stmt, 1))); QString local_file = QString::fromUtf8(reinterpret_cast(sqlite3_column_text(stmt, 2))); sqlite3_finalize(stmt); // There are three possibilities now: either we didn't get any commit id in the URL in which case we just return the file we got, no matter what. // Or the requested commit id is the same as the local commit id in which case we return the file we got as well. // Or the requested commit id differ in which case we return no match. if(url_commit_id.isNull() || local_commit_id == url_commit_id) { // Both commit ids are the same. That's the perfect match, so we can open the local file if it still exists return localCheckFile(local_file); } else { // The commit ids differ. This means we have no match return QString(); } } QString RemoteDatabase::localCheckFile(const QString& local_file) { // This function takes the file name of a locally cloned database and checks if this file still exists. If it has been deleted in the meantime it returns // an empty string and deletes the file from the clone database. If the file still exists, it returns the full path to the file. localAssureOpened(); // Build the full path to where the file should be QString full_path = Settings::getValue("remote", "clonedirectory").toString() + "/" + local_file; // Check if the database still exists. If so return its path, if not return an empty string to redownload it if(QFile::exists(full_path)) { return full_path; } else { // Remove the apparently invalid entry from the local clones database to avoid future lookups and confusions. The file column should // be unique for the entire table because the files are all in the same directory and their names need to be unique because of this. localDeleteFile(local_file); // Return empty string to indicate a redownload request return QString(); } } std::string RemoteDatabase::localLastCommitId(QString identity, const QUrl& url, const std::string& branch) { localAssureOpened(); // Query commit id for that file name QString sql = QString("SELECT commit_id FROM local WHERE identity=? AND url=? AND branch=?"); sqlite3_stmt* stmt; if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) return std::string(); QFileInfo f(identity); // Remove the path identity = f.fileName(); if(sqlite3_bind_text(stmt, 1, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return std::string(); } if(sqlite3_bind_text(stmt, 2, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(), url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().size(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return std::string(); } if(sqlite3_bind_text(stmt, 3, branch.c_str(), static_cast(branch.size()), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return std::string(); } if(sqlite3_step(stmt) != SQLITE_ROW) { // If there was either an error or no record was found for this file name, stop here. sqlite3_finalize(stmt); return std::string(); } // Having come here we can assume that at least some local clone with the given file name std::string local_commit_id = reinterpret_cast(sqlite3_column_text(stmt, 0)); sqlite3_finalize(stmt); return local_commit_id; } std::vector RemoteDatabase::localGetLocalFiles(QString identity) { localAssureOpened(); // Get all rows for this identity QString sql = QString("SELECT name, url, commit_id, file, branch FROM local WHERE identity=? ORDER BY url"); sqlite3_stmt* stmt; if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) return {}; QFileInfo f(identity); identity = f.fileName(); if(sqlite3_bind_text(stmt, 1, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return {}; } std::vector result; while(sqlite3_step(stmt) == SQLITE_ROW) { result.emplace_back(reinterpret_cast(sqlite3_column_text(stmt, 0)), reinterpret_cast(sqlite3_column_text(stmt, 1)), reinterpret_cast(sqlite3_column_text(stmt, 2)), reinterpret_cast(sqlite3_column_text(stmt, 3)), reinterpret_cast(sqlite3_column_text(stmt, 4)), identity.toStdString()); } sqlite3_finalize(stmt); return result; } RemoteDatabase::LocalFileInfo RemoteDatabase::localGetLocalFileInfo(QString filename) { localAssureOpened(); // Find this file in our database QString sql = QString("SELECT name, url, commit_id, branch, identity FROM local WHERE file=?"); sqlite3_stmt* stmt; if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) return {}; // Remove the path for querying the file name filename = QFileInfo(filename).fileName(); if(sqlite3_bind_text(stmt, 1, filename.toUtf8(), filename.toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return {}; } if(sqlite3_step(stmt) != SQLITE_ROW) { // If there was either an error or no record was found for this file name, stop here. sqlite3_finalize(stmt); return {}; } // Retrieve and return all the information we have RemoteDatabase::LocalFileInfo result(reinterpret_cast(sqlite3_column_text(stmt, 0)), reinterpret_cast(sqlite3_column_text(stmt, 1)), reinterpret_cast(sqlite3_column_text(stmt, 2)), filename.toStdString(), reinterpret_cast(sqlite3_column_text(stmt, 3)), reinterpret_cast(sqlite3_column_text(stmt, 4))); sqlite3_finalize(stmt); return result; } void RemoteDatabase::localDeleteFile(QString filename) { localAssureOpened(); // Remove the file's entry in our database QString sql = QString("DELETE FROM local WHERE file=?"); sqlite3_stmt* stmt; if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) return; if(sqlite3_bind_text(stmt, 1, filename.toUtf8(), filename.toUtf8().length(), SQLITE_TRANSIENT)) { sqlite3_finalize(stmt); return; } if(sqlite3_step(stmt) != SQLITE_DONE) { sqlite3_finalize(stmt); return; } sqlite3_finalize(stmt); // Delete the actual file on disk QFile::remove(Settings::getValue("remote", "clonedirectory").toString() + "/" + filename); } QString RemoteDatabase::LocalFileInfo::user_name() const { // Figure out the user name from the URL QString path = QUrl(QString::fromStdString(url)).path(); if(path.count('/') < 2 || !path.startsWith('/')) return QString(); else return path.mid(1, path.indexOf('/', 1) - 1); } sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteDatabase.h000066400000000000000000000067171463772530400235270ustar00rootroot00000000000000#ifndef REMOTEDATABASE_H #define REMOTEDATABASE_H #include #include #include struct sqlite3; class RemoteDatabase : public QObject { Q_OBJECT public: RemoteDatabase(); ~RemoteDatabase() override; // This class compiles all the information on a lcao database file class LocalFileInfo { public: LocalFileInfo() {} LocalFileInfo(const std::string& _name, const std::string& _url, const std::string& _commit_id, const std::string& _file, const std::string& _branch, const std::string& _identity) : name(_name), url(_url), commit_id(_commit_id), file(_file), branch(_branch), identity(_identity) {} void clear() { name = url = commit_id = file = branch = identity = {}; } QString user_name() const; std::string name; // Database name std::string url; // URL for cloning std::string commit_id; // Commit ID at the time of the cloning std::string file; // Name of the local file on disk std::string branch; // Cloned branch std::string identity; // Identity used for cloning }; // Return a list of all checked out databases for a given identity std::vector localGetLocalFiles(QString identity); // Return information on a single file LocalFileInfo localGetLocalFileInfo(QString filename); // Delete a local database clone void localDeleteFile(QString filename); // This function checks if there already is a clone for the given combination of url and identity. It returns the filename // of this clone if there is or a null string if there isn't a clone yet. The identity needs to be part of this check because // with the url alone there could be corner cases where different versions or whatever may not be accessible for all users. // If the URL contains a commit id (optional), this commit id is part of the check. QString localExists(const QUrl& url, QString identity, const std::string& branch); // This function takes a file name and checks with which commit id we had checked out this file or last pushed it. std::string localLastCommitId(QString clientCert, const QUrl& url, const std::string& branch); // This function adds a new local database clone to our internal list. It does so by adding a single // new record to the remote dbs database. All the fields are extracted from the filename, the identity // and (most importantly) the url parameters. Note that for the commit id field to be correctly filled we // require the commit id to be part of the url parameter. Also note that this function doesn't care if the // database has already been added to the list or not. If you need this information you need to check it before // calling this function, ideally even before sending out a request to the network. The function returns the full // path of the newly created/updated file. QString localAdd(QString filename, QString identity, const QUrl& url, const std::string& new_commit_id, const std::string& branch); private: // Helper functions for managing the list of locally available databases void localAssureOpened(); QString localCheckFile(const QString& local_file); sqlite3* m_dbLocal; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteDock.cpp000066400000000000000000000722521463772530400232330ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "RemoteDock.h" #include "ui_RemoteDock.h" #include "Settings.h" #include "RemoteCommitsModel.h" #include "RemoteDatabase.h" #include "RemoteLocalFilesModel.h" #include "RemoteModel.h" #include "MainWindow.h" #include "RemotePushDialog.h" #include "PreferencesDialog.h" using json = nlohmann::json; RemoteDock::RemoteDock(MainWindow* parent) : QDialog(parent), ui(new Ui::RemoteDock), mainWindow(parent), remoteModel(new RemoteModel(this)), remoteLocalFilesModel(new RemoteLocalFilesModel(this, remoteDatabase)), remoteCommitsModel(new RemoteCommitsModel(this)) { ui->setupUi(this); // Set models ui->treeRemote->setModel(remoteModel); ui->treeLocal->setModel(remoteLocalFilesModel); ui->treeDatabaseCommits->setModel(remoteCommitsModel); // Set initial column widths for tree views ui->treeRemote->setColumnWidth(0, 300); // Make name column wider ui->treeRemote->setColumnWidth(2, 80); // Make size column narrower ui->treeLocal->setColumnWidth(RemoteLocalFilesModel::ColumnName, 300); // Make name column wider ui->treeLocal->setColumnWidth(RemoteLocalFilesModel::ColumnSize, 80); // Make size column narrower ui->treeLocal->setColumnHidden(RemoteLocalFilesModel::ColumnFile, true); // Hide local file name // Handle finished uploads and downloads of databases connect(&RemoteNetwork::get(), &RemoteNetwork::fetchFinished, this, &RemoteDock::fetchFinished); connect(&RemoteNetwork::get(), &RemoteNetwork::pushFinished, this, &RemoteDock::pushFinished); // Whenever a new directory listing has been parsed, check if it was a new root dir and, if so, open the user's directory connect(remoteModel, &RemoteModel::directoryListingParsed, this, &RemoteDock::newDirectoryNode); // When the Preferences link is clicked in the no-certificates-label, open the preferences dialog. For other links than the ones we know, // just open them in a web browser connect(ui->labelNoCert, &QLabel::linkActivated, this, [this](const QString& link) { if(link == "#preferences") { PreferencesDialog dialog(mainWindow, PreferencesDialog::TabRemote); if(dialog.exec()) mainWindow->reloadSettings(); } else { QDesktopServices::openUrl(QUrl(link)); } }); // When changing the current branch in the branches combo box, update the tree view accordingly connect(ui->comboDatabaseBranch, static_cast(&QComboBox::currentIndexChanged), this, [this](int /*index*/) { remoteCommitsModel->refresh(current_commit_json, ui->comboDatabaseBranch->currentData().toString().toStdString(), currently_opened_file_info.commit_id); ui->treeDatabaseCommits->expandAll(); }); // Fetch latest commit action connect(ui->actionFetchLatestCommit, &QAction::triggered, this, [this]() { // Fetch last commit of current branch // The URL and the branch name is that of the currently opened database file. // The latest commit id is stored in the data bits of the branch combo box. QUrl url(QString::fromStdString(currently_opened_file_info.url)); QUrlQuery query; query.addQueryItem("branch", QString::fromStdString(currently_opened_file_info.branch)); query.addQueryItem("commit", ui->comboDatabaseBranch->itemData( ui->comboDatabaseBranch->findText(QString::fromStdString(currently_opened_file_info.branch))).toString()); url.setQuery(query); fetchDatabase(url.toString()); }); // Prepare context menu for list of remote databases connect(ui->treeRemote->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex& index, const QModelIndex&) { // Only enable database actions when a database was selected bool enable = index.isValid() && remoteModel->modelIndexToItem(index)->value(RemoteModelColumnType).toString() == "database"; ui->actionCloneDatabaseDoubleClick->setEnabled(enable); }); emit ui->treeRemote->selectionModel()->currentChanged(QModelIndex(), QModelIndex()); // Enable/disable all action initially connect(ui->actionCloneDatabaseDoubleClick, &QAction::triggered, this, [this]() { fetchDatabase(ui->treeRemote->currentIndex()); }); ui->treeRemote->addAction(ui->actionCloneDatabaseDoubleClick); // Prepare context menu for list of local clones connect(ui->treeLocal->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex& index, const QModelIndex&) { // Only enable database actions when a database was selected bool enable = index.isValid() && !index.sibling(index.row(), RemoteLocalFilesModel::ColumnFile).data().isNull(); ui->actionOpenLocalDatabase->setEnabled(enable); ui->actionPushLocalDatabase->setEnabled(enable); ui->actionDeleteDatabase->setEnabled(enable); }); emit ui->treeLocal->selectionModel()->currentChanged(QModelIndex(), QModelIndex()); // Enable/disable all action initially connect(ui->actionOpenLocalDatabase, &QAction::triggered, this, [this]() { openLocalFile(ui->treeLocal->currentIndex()); }); connect(ui->actionDeleteDatabase, &QAction::triggered, this, [this]() { deleteLocalDatabase(ui->treeLocal->currentIndex()); }); ui->treeLocal->addAction(ui->actionOpenLocalDatabase); ui->treeLocal->addAction(ui->actionPushLocalDatabase); ui->treeLocal->addAction(ui->actionDeleteDatabase); // Prepare context menu for list of commits connect(ui->treeDatabaseCommits->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex& index, const QModelIndex&) { // Only enable database actions when a commit was selected bool enable = index.isValid(); ui->actionFetchCommit->setEnabled(enable); ui->actionDownloadCommit->setEnabled(enable); }); emit ui->treeDatabaseCommits->selectionModel()->currentChanged(QModelIndex(), QModelIndex()); // Enable/disable all action initially connect(ui->actionFetchCommit, &QAction::triggered, this, [this]() { fetchCommit(ui->treeDatabaseCommits->currentIndex()); }); connect(ui->actionDownloadCommit, &QAction::triggered, this, [this]() { fetchCommit(ui->treeDatabaseCommits->currentIndex(), RemoteNetwork::RequestTypeDownload); }); ui->treeDatabaseCommits->addAction(ui->actionFetchCommit); ui->treeDatabaseCommits->addAction(ui->actionDownloadCommit); // Initial setup reloadSettings(); } RemoteDock::~RemoteDock() { delete ui; } void RemoteDock::reloadSettings() { // Clear list of client certificates and add a dummy entry which does nothing except serve as // an explanation to the user. ui->comboUser->clear(); ui->comboUser->addItem(tr("Select an identity to connect"), "dummy"); // Load list of client certs const QStringList client_certs = Settings::getValue("remote", "client_certificates").toStringList(); for(const QString& file : client_certs) { const auto certs = QSslCertificate::fromPath(file); for(const QSslCertificate& cert : certs) ui->comboUser->addItem(cert.subjectInfo(QSslCertificate::CommonName).at(0), file); } // Add public certificate for anonymous read-only access to dbhub.io ui->comboUser->addItem(tr("Public"), ":/user_certs/public.cert.pem"); } void RemoteDock::setNewIdentity(const QString& identity) { // Do nothing if the dummy entry was selected if(ui->comboUser->currentData() == "dummy") return; // Check if the dummy item is still there and remove it if it is if(ui->comboUser->itemData(0) == "dummy") { ui->comboUser->blockSignals(true); ui->comboUser->removeItem(0); ui->comboUser->blockSignals(false); } // Get certificate file name QString cert = ui->comboUser->itemData(ui->comboUser->findText(identity), Qt::UserRole).toString(); if(cert.isEmpty()) return; // Open root directory. Get host name from client cert remoteModel->setNewRootDir(RemoteNetwork::get().getInfoFromClientCert(cert, RemoteNetwork::CertInfoServer), cert); // Reset list of local checkouts remoteLocalFilesModel->setIdentity(cert); refreshLocalFileList(); // Enable buttons if necessary enableButtons(); } void RemoteDock::fetchDatabase(const QModelIndex& idx) { if(!idx.isValid()) return; // Get item const RemoteModelItem* item = remoteModel->modelIndexToItem(idx); // Only open database file if(item->value(RemoteModelColumnType).toString() == "database") fetchDatabase(item->value(RemoteModelColumnUrl).toString()); } void RemoteDock::fetchDatabase(QString url_string, RemoteNetwork::RequestType request_type) { // If no URL was provided ask the user. Default to the current clipboard contents if(url_string.isEmpty()) { url_string = QInputDialog::getText(this, qApp->applicationName(), tr("This downloads a database from a remote server for local editing.\n" "Please enter the URL to clone from. You can generate this URL by\n" "clicking the 'Clone Database in DB4S' button on the web page\n" "of the database."), QLineEdit::Normal, QApplication::clipboard()->text()); } if(url_string.isEmpty()) return; // Check the URL QUrl url(url_string); if(url.authority() != QUrl(RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoServer)).authority()) { QMessageBox::warning(this, qApp->applicationName(), tr("Invalid URL: The host name does not match the host name of the current identity.")); return; } if(!QUrlQuery(url).hasQueryItem("branch")) { QMessageBox::warning(this, qApp->applicationName(), tr("Invalid URL: No branch name specified.")); return; } if(!QUrlQuery(url).hasQueryItem("commit")) { QMessageBox::warning(this, qApp->applicationName(), tr("Invalid URL: No commit ID specified.")); return; } // For the user name, take the path, remove the database name and the initial slash QString username = url.path().remove("/" + url.fileName()).mid(1); // There is a chance that we've already cloned that database. So check for that first QString exists = remoteDatabase.localExists(url, remoteModel->currentClientCertificate(), QUrlQuery(url).queryItemValue("branch").toStdString()); if(!exists.isEmpty() && request_type == RemoteNetwork::RequestTypeDatabase) { // Check for modifications bool modified = isLocalDatabaseModified(exists, username, url.fileName(), remoteModel->currentClientCertificate(), QUrlQuery(url).queryItemValue("commit").toStdString()); // Database has already been cloned! So open the local file instead of fetching the one from the // server again. If the local file has been modified don't open it but try to download the last known // commit again. if(!modified) { emit openFile(exists); return; } } // Check if we already have a clone of this database branch and, if so, figure out its local file name. // For this we do not care about the currently checked out commit id because we only have one file per // database and branch on the disk. QUrl url_without_commit_id(url); QUrlQuery url_without_commit_id_query(url_without_commit_id); url_without_commit_id_query.removeQueryItem("commit"); url_without_commit_id.setQuery(url_without_commit_id_query); QString local_file = remoteDatabase.localExists(url_without_commit_id, remoteModel->currentClientCertificate(), QUrlQuery(url).queryItemValue("branch").toStdString()); if(request_type == RemoteNetwork::RequestTypeDatabase && !local_file.isEmpty()) { // If there is a local clone of this dtabase and branch, figure out if the local file has been modified // Get the last local commit id std::string last_commit_id = remoteDatabase.localLastCommitId(remoteModel->currentClientCertificate(), url, QUrlQuery(url).queryItemValue("branch").toStdString()); // Check for modifications bool modified = isLocalDatabaseModified(local_file, username, url.fileName(), remoteModel->currentClientCertificate(), last_commit_id); // Only if the local file has been modified show a warning that checking out this commit overrides local changes if(modified) { if(QMessageBox::warning(nullptr, QApplication::applicationName(), tr("You have modified the local clone of the database. Fetching this commit overrides these local changes.\n" "Are you sure you want to proceed?"), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } // Clone the database RemoteNetwork::get().fetch(url.toString(), request_type, remoteModel->currentClientCertificate()); } void RemoteDock::fetchCommit(const QModelIndex& idx, RemoteNetwork::RequestType request_type) { // Fetch selected commit QUrl url(QString::fromStdString(currently_opened_file_info.url)); QUrlQuery query; query.addQueryItem("branch", ui->comboDatabaseBranch->currentText()); query.addQueryItem("commit", idx.sibling(idx.row(), RemoteCommitsModel::ColumnCommitId).data().toString()); url.setQuery(query); fetchDatabase(url.toString(), request_type); } void RemoteDock::enableButtons() { bool db_opened = mainWindow->getDb().isOpen() && mainWindow->getDb().currentFile() != ":memory:"; bool logged_in = !remoteModel->currentClientCertificate().isEmpty(); ui->buttonPushDatabase->setEnabled(db_opened && logged_in); ui->actionRefresh->setEnabled(logged_in); ui->actionCloneDatabaseLink->setEnabled(logged_in); ui->actionDatabaseOpenBrowser->setEnabled(db_opened && logged_in); ui->actionFetchLatestCommit->setEnabled(db_opened && logged_in); } void RemoteDock::pushCurrentlyOpenedDatabase() { // Show a warning when trying to push a database with unsaved changes if(mainWindow->getDb().getDirty()) { if(QMessageBox::warning(this, QApplication::applicationName(), tr("The database has unsaved changes. Are you sure you want to push it before saving?"), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Cancel) return; } // Push currently opened file pushDatabase(mainWindow->getDb().currentFile(), QString::fromStdString(currently_opened_file_info.branch)); } void RemoteDock::pushSelectedLocalDatabase() { // Return if no file is selected if(!ui->treeLocal->currentIndex().isValid()) return; const int row = ui->treeLocal->currentIndex().row(); const QString filename = ui->treeLocal->currentIndex().sibling(row, RemoteLocalFilesModel::ColumnFile).data().toString(); if(filename.isEmpty()) return; // Push selected file const QString branch = ui->treeLocal->currentIndex().sibling(row, RemoteLocalFilesModel::ColumnBranch).data().toString(); pushDatabase(Settings::getValue("remote", "clonedirectory").toString() + "/" + filename, branch); } void RemoteDock::pushDatabase(const QString& path, const QString& branch) { // If the currently active identity is the read-only public access to dbhub.io, don't show the Push Database dialog because it won't work anyway. // Instead switch to an explanation offering some advice to create and import a proper certificate. if(remoteModel->currentClientCertificate() == ":/user_certs/public.cert.pem") { ui->stack->setCurrentIndex(1); return; } // The default suggestion for a database name is the local file name. If it is a remote file (like when it initially was fetched using DB4S), // the extra bit of information at the end of the name gets removed first. QString name = QFileInfo(path).fileName(); name = name.remove(QRegExp("_[0-9]+.remotedb$")); // Show the user a dialog for setting all the commit details QString host = RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoServer); RemotePushDialog pushDialog(this, host, remoteModel->currentClientCertificate(), name, branch); if(pushDialog.exec() != QDialog::Accepted) return; // Build push URL QString url = host; url.append(pushDialog.user()); url.append("/"); url.append(pushDialog.name()); // Check if we are pushing a cloned database. Only in this case we provide the last known commit id. // For this check we use the branch name which was used for cloning this database rather than the // branch name which was selected in the push dialog. This is because we want to figure out the // current commit id of we are currently looking at rather than some other commit id or none at all // when creating a new branch. QString commit_id; if(path.startsWith(Settings::getValue("remote", "clonedirectory").toString())) commit_id = QString::fromStdString(remoteDatabase.localLastCommitId(remoteModel->currentClientCertificate(), url, branch.toStdString())); // Push database RemoteNetwork::get().push(path, url, remoteModel->currentClientCertificate(), pushDialog.name(), pushDialog.commitMessage(), pushDialog.licence(), pushDialog.isPublic(), pushDialog.branch(), pushDialog.forcePush(), commit_id); } void RemoteDock::newDirectoryNode(const QModelIndex& parent) { // Was this a new root dir? if(!parent.isValid()) { // Then check if there is a directory with the current user name // Get current user name QString user = RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoUser); for(int i=0;irowCount();i++) { QModelIndex child = remoteModel->index(i, RemoteModelColumnName); if(child.data().toString() == user) { ui->treeRemote->expand(child); break; } } } } void RemoteDock::reject() { // We override this, to ensure the Escape key doesn't make this dialog // dock go away return; } void RemoteDock::switchToMainView() { ui->stack->setCurrentIndex(0); } void RemoteDock::refreshLocalFileList() { remoteLocalFilesModel->refresh(); // Expand node for current user QString user = RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoUser); for(int i=0;irowCount();i++) { QModelIndex child = remoteLocalFilesModel->index(i, RemoteLocalFilesModel::ColumnName); if(child.data().toString() == user) { ui->treeLocal->expand(child); break; } } } void RemoteDock::openLocalFile(const QModelIndex& idx) { if(!idx.isValid()) return; QString file = idx.sibling(idx.row(), RemoteLocalFilesModel::ColumnFile).data().toString(); if(!file.isEmpty()) emit openFile(Settings::getValue("remote", "clonedirectory").toString() + "/" + file); } void RemoteDock::fileOpened(const QString& filename) { // Clear data first currently_opened_file_info.clear(); remoteCommitsModel->clear(); ui->comboDatabaseBranch->clear(); ui->editDatabaseUser->clear(); ui->editDatabaseFile->clear(); ui->editDatabaseBranch->clear(); // Do nothing if the file name is empty (indicating a closed database) or this is an in-memory database if(filename.isEmpty() || filename == ":memory:") return; // Check if it is a tracked remote database file and retrieve the information we have on it if(filename.startsWith(Settings::getValue("remote", "clonedirectory").toString())) currently_opened_file_info = remoteDatabase.localGetLocalFileInfo(filename); // Is this actually a clone of a remote database? if(!currently_opened_file_info.file.empty()) { // Copy information to view ui->editDatabaseUser->setText(currently_opened_file_info.user_name()); ui->editDatabaseFile->setText(QString::fromStdString(currently_opened_file_info.name)); ui->editDatabaseBranch->setText(QString::fromStdString(currently_opened_file_info.branch)); // Make sure the current identity matches the identity used to clone this file in the first place. // A mismatch is possible when the local database file has been opened using a recent files menu item or some similar technique. if(QString::fromStdString(currently_opened_file_info.identity) != QFileInfo(remoteModel->currentClientCertificate()).fileName()) ui->comboUser->setCurrentIndex(ui->comboUser->findData("/" + QString::fromStdString(currently_opened_file_info.identity), Qt::UserRole, Qt::MatchEndsWith)); // Query more information on database from server refreshMetadata(currently_opened_file_info.user_name(), QString::fromStdString(currently_opened_file_info.name)); // Switch to "Current Database" tab ui->tabs->setCurrentIndex(2); } } void RemoteDock::refreshMetadata(const QString& username, const QString& dbname) { // Make request for meta data QUrl url(RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoServer) + "/metadata/get"); QUrlQuery query; query.addQueryItem("username", username); query.addQueryItem("folder", "/"); query.addQueryItem("dbname", dbname); url.setQuery(query); RemoteNetwork::get().fetch(url.toString(), RemoteNetwork::RequestTypeCustom, remoteModel->currentClientCertificate(), [this](const QByteArray& reply) { // Read and check results json obj = json::parse(reply, nullptr, false); if(obj.is_discarded() || !obj.is_object()) return; // Store all the commit information as-is json obj_commits = obj["commits"]; current_commit_json = obj_commits.dump(); // Store the link to the web page in the action for opening that link in a browser ui->actionDatabaseOpenBrowser->setData(QString::fromStdString(obj["web_page"])); // Fill branches combo box json obj_branches = obj["branches"]; ui->comboDatabaseBranch->clear(); for(auto it=obj_branches.cbegin();it!=obj_branches.cend();++it) ui->comboDatabaseBranch->addItem(QString::fromStdString(it.key()), QString::fromStdString(it.value()["commit"])); ui->comboDatabaseBranch->setCurrentIndex(ui->comboDatabaseBranch->findText(ui->editDatabaseBranch->text())); }); } void RemoteDock::deleteLocalDatabase(const QModelIndex& index) { if(!index.isValid()) return; QString filename = index.sibling(index.row(), RemoteLocalFilesModel::ColumnFile).data().toString(); QString path = Settings::getValue("remote", "clonedirectory").toString() + "/" + filename; // Warn when trying to delete a currently opened database file if(mainWindow->getDb().currentFile() == path) { QMessageBox::warning(this, QApplication::applicationName(), tr("The database you are trying to delete is currently opened. " "Please close it before deleting.")); return; } // Let user confirm deleting the database if(QMessageBox::warning(this, QApplication::applicationName(), tr("This deletes the local version of this database with all the " "changes you have not committed yet. Are you sure you want to " "delete this database?"), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Cancel) { return; } // Delete the file remoteLocalFilesModel->removeRow(index.row(), index.parent()); } void RemoteDock::openCurrentDatabaseInBrowser() const { QDesktopServices::openUrl(ui->actionDatabaseOpenBrowser->data().toUrl()); } void RemoteDock::refresh() { // Refresh Remote tab remoteModel->refresh(); // Refresh Local tab refreshLocalFileList(); // Refresh Current Database tab if(!currently_opened_file_info.file.empty()) refreshMetadata(currently_opened_file_info.user_name(), QString::fromStdString(currently_opened_file_info.name)); } void RemoteDock::pushFinished(const QString& filename, const QString& identity, const QUrl& url, const std::string& new_commit_id, const std::string& branch, const QString& source_file) { // Create or update the record in our local checkout database QString saveFileAs = remoteDatabase.localAdd(filename, identity, url, new_commit_id, branch); // If the name of the source file and the name we're saving as differ, we're doing an initial push. In this case, copy the source file to // the destination path to avoid redownloading it when it's first used. if(saveFileAs != source_file) QFile::copy(source_file, saveFileAs); // Update info on currently opened file if(currently_opened_file_info.file == QFileInfo(saveFileAs).fileName().toStdString()) currently_opened_file_info = remoteDatabase.localGetLocalFileInfo(saveFileAs); // Refresh view refresh(); } void RemoteDock::fetchFinished(const QString& filename, const QString& identity, const QUrl& url, const std::string& new_commit_id, const std::string& branch, const QDateTime& last_modified, QIODevice* device) { // Add cloned database to list of local databases QString saveFileAs = remoteDatabase.localAdd(filename, identity, url, new_commit_id, branch); // Save the downloaded data under the generated file name QFile file(saveFileAs); file.open(QIODevice::WriteOnly); file.write(device->readAll()); // Set last modified data of the new file to the one provided by the server // Before version 5.10, Qt didn't offer any option to set this attribute, so we're not setting it at the moment #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) file.setFileTime(last_modified, QFileDevice::FileModificationTime); #endif // Close file file.close(); // Update info on currently opened file currently_opened_file_info = remoteDatabase.localGetLocalFileInfo(saveFileAs); // Refresh data refreshLocalFileList(); // Tell the application to open this file emit openFile(saveFileAs); } bool RemoteDock::isLocalDatabaseModified(const QString& local_file, const QString& username, const QString& dbname, const QString& identity, const std::string& commit_id) { // Fetch metadata on database QUrl url(RemoteNetwork::get().getInfoFromClientCert(identity, RemoteNetwork::CertInfoServer) + "/metadata/get"); QUrlQuery query; query.addQueryItem("username", username); query.addQueryItem("folder", "/"); query.addQueryItem("dbname", dbname); url.setQuery(query); bool modified = true; // By default we assume the database has been modified RemoteNetwork::get().fetch(url, RemoteNetwork::RequestTypeCustom, identity, [commit_id, dbname, local_file, &modified](const QByteArray& reply) { // Read and check results json obj = json::parse(reply, nullptr, false); if(obj.is_discarded() || !obj.is_object()) return; // Search tree entry for currently checked out commit json tree = obj["commits"][commit_id]["tree"]["entries"]; for(const auto& it : tree) { if(it["entry_type"] == "db" && it["name"] == dbname.toStdString()) { // When we have found it, check if the current file matches the remote file by first checking if the // file size is equal and then comparing their SHA256 hashes if(QFileInfo(local_file).size() == it["size"]) { QFile file(local_file); if(!file.open(QFile::ReadOnly)) return; QCryptographicHash hash(QCryptographicHash::Sha256); hash.addData(&file); if(hash.result().toHex().toStdString() == it["sha256"]) { modified = false; return; } } break; } } }, true); return modified; } sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteDock.h000066400000000000000000000051311463772530400226700ustar00rootroot00000000000000#ifndef REMOTEDOCK_H #define REMOTEDOCK_H #include #include "RemoteDatabase.h" #include "RemoteNetwork.h" class RemoteCommitsModel; class RemoteLocalFilesModel; class RemoteModel; class MainWindow; namespace Ui { class RemoteDock; } class RemoteDock : public QDialog { Q_OBJECT public: explicit RemoteDock(MainWindow* parent); ~RemoteDock() override; void reloadSettings(); void enableButtons(); // This function should be called whenever a database file is opened. // It checks whether the file is a checkout of a tracked remote database // and updates some of the fields in the remote dock if it is. // Call it with an empty file name if the database is closed. void fileOpened(const QString& filename); public slots: void reject() override; private slots: void setNewIdentity(const QString& identity); void fetchDatabase(const QModelIndex& idx); void fetchDatabase(QString url = QString(), RemoteNetwork::RequestType request_type = RemoteNetwork::RequestTypeDatabase); void fetchCommit(const QModelIndex& idx, RemoteNetwork::RequestType request_type = RemoteNetwork::RequestTypeDatabase); void pushCurrentlyOpenedDatabase(); void pushSelectedLocalDatabase(); void newDirectoryNode(const QModelIndex& parent); void switchToMainView(); void openLocalFile(const QModelIndex& idx); void deleteLocalDatabase(const QModelIndex& index); void openCurrentDatabaseInBrowser() const; void refresh(); void pushFinished(const QString& filename, const QString& identity, const QUrl& url, const std::string& new_commit_id, const std::string& branch, const QString& source_file); void fetchFinished(const QString& filename, const QString& identity, const QUrl& url, const std::string& new_commit_id, const std::string& branch, const QDateTime& last_modified, QIODevice* device); signals: void openFile(QString file); private: Ui::RemoteDock* ui; MainWindow* mainWindow; RemoteDatabase remoteDatabase; RemoteModel* remoteModel; RemoteLocalFilesModel* remoteLocalFilesModel; RemoteCommitsModel* remoteCommitsModel; std::string current_commit_json; RemoteDatabase::LocalFileInfo currently_opened_file_info; void refreshLocalFileList(); void refreshMetadata(const QString& username, const QString& dbname); bool isLocalDatabaseModified(const QString& local_file, const QString& username, const QString& dbname, const QString& identity, const std::string& commit_id); void pushDatabase(const QString& path, const QString& branch); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteDock.ui000066400000000000000000000605751463772530400230730ustar00rootroot00000000000000 RemoteDock 0 0 534 387 Remote 2 0 2 0 0 0 0 0 0 Identity comboUser QComboBox::AdjustToContents Qt::Horizontal 40 20 Push currently opened database to server Upload :/icons/push_database:/icons/push_database Qt::ToolButtonTextBesideIcon 0 DBHub.io 2 0 2 0 false false Qt::ActionsContextMenu <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> Local 2 0 2 0 Qt::ActionsContextMenu Current Database 2 0 2 0 true 0 0 520 319 0 0 0 0 false false Clone 0 &User editDatabaseUser true &Database editDatabaseFile true Branch editDatabaseBranch true Commits 2 0 2 0 Commits for Qt::ActionsContextMenu 0 0 0 0 Qt::Vertical 20 85 Qt::Horizontal 40 20 <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> true Back Qt::Horizontal 40 20 Qt::Vertical 20 85 :/icons/close:/icons/close Delete Database Delete the local clone of this database :/icons/browser_open:/icons/browser_open Open in Web Browser Open the web page for the current database in your browser :/icons/clone_database:/icons/clone_database Clone from Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. :/icons/refresh:/icons/refresh Refresh Reload all data and update the views :/icons/clone_database:/icons/clone_database Clone Database 75 true :/icons/db_open:/icons/db_open Open Database Open the local copy of this database 75 true Check out Commit Download and open this specific commit 75 true :/icons/db_revert:/icons/db_revert Check out Latest Commit Check out the latest commit of the current branch Save Revision to File Saves the selected revision of the database to another file :/icons/push_database:/icons/push_database Upload Database Upload this database as a new commit comboUser buttonPushDatabase tabs treeRemote treeLocal comboDatabaseBranch treeDatabaseCommits buttonNoCertBack comboUser currentTextChanged(QString) RemoteDock setNewIdentity(QString) 134 25 419 24 treeRemote doubleClicked(QModelIndex) RemoteDock fetchDatabase(QModelIndex) 215 148 204 37 buttonPushDatabase clicked() RemoteDock pushCurrentlyOpenedDatabase() 530 25 287 154 buttonNoCertBack clicked() RemoteDock switchToMainView() 93 23 266 148 treeLocal doubleClicked(QModelIndex) RemoteDock openLocalFile(QModelIndex) 266 179 266 148 actionCloneDatabaseLink triggered() RemoteDock fetchDatabase() -1 -1 266 178 actionDatabaseOpenBrowser triggered() RemoteDock openCurrentDatabaseInBrowser() -1 -1 266 189 actionRefresh triggered() RemoteDock refresh() -1 -1 266 193 treeDatabaseCommits doubleClicked(QModelIndex) RemoteDock fetchCommit(QModelIndex) 266 337 266 193 actionPushLocalDatabase triggered() RemoteDock pushSelectedLocalDatabase() -1 -1 266 193 setNewIdentity(QString) fetchDatabase(QModelIndex) pushCurrentlyOpenedDatabase() pushSelectedLocalDatabase() switchToMainView() openLocalFile(QModelIndex) fetchDatabase() openCurrentDatabaseInBrowser() refresh() fetchCommit(QModelIndex) sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteLocalFilesModel.cpp000066400000000000000000000135401463772530400253440ustar00rootroot00000000000000#include #include #include #include #include #include "Data.h" #include "RemoteDatabase.h" #include "RemoteLocalFilesModel.h" #include "RemoteNetwork.h" #include "Settings.h" using json = nlohmann::json; RemoteLocalFilesModel::RemoteLocalFilesModel(QObject* parent, RemoteDatabase& remote) : QAbstractItemModel(parent), remoteDatabase(remote) { QStringList header; header << tr("Name") << tr("Branch") << tr("Last modified") << tr("Size") << tr("Commit") << tr("File"); rootItem = new QTreeWidgetItem(header); } RemoteLocalFilesModel::~RemoteLocalFilesModel() { delete rootItem; } void RemoteLocalFilesModel::setIdentity(const QString& cert_filename) { current_cert_filename = cert_filename; current_user_name = RemoteNetwork::get().getInfoFromClientCert(cert_filename, RemoteNetwork::CertInfoUser); refresh(); } void RemoteLocalFilesModel::refresh() { beginResetModel(); // Remove all data except for the root item while(rootItem->childCount()) delete rootItem->child(0); // Get list of locally checked out databases auto files = remoteDatabase.localGetLocalFiles(current_cert_filename); // Loop through that list for(const auto& file : files) { QString user_name = file.user_name(); // Check if there is already a node for this user QTreeWidgetItem* user_node = nullptr; for(int i=0;ichildCount();i++) { if(rootItem->child(i)->text(ColumnName) == user_name) { user_node = rootItem->child(i); break; } } // If there is no node for this user yet create one if(user_node == nullptr) { user_node = new QTreeWidgetItem(rootItem); user_node->setText(ColumnName, user_name); user_node->setIcon(ColumnName, QIcon(user_name == current_user_name ? ":/icons/folder_user" : ":/icons/folder")); } // Get file information QFile file_info(Settings::getValue("remote", "clonedirectory").toString() + "/" + QString::fromStdString(file.file)); // Add file to user node QTreeWidgetItem* file_node = new QTreeWidgetItem(user_node); file_node->setText(ColumnName, QString::fromStdString(file.name)); file_node->setIcon(ColumnName, QIcon(":/icons/database")); file_node->setText(ColumnBranch, QString::fromStdString(file.branch)); file_node->setText(ColumnLastModified, QLocale::system().toString(QFileInfo(file_info).lastModified().toLocalTime(), QLocale::ShortFormat)); file_node->setText(ColumnSize, humanReadableSize(static_cast(file_info.size()))); file_node->setText(ColumnCommit, QString::fromStdString(file.commit_id)); file_node->setText(ColumnFile, QString::fromStdString(file.file)); } // Refresh the view endResetModel(); } QModelIndex RemoteLocalFilesModel::index(int row, int column, const QModelIndex& parent) const { if(!hasIndex(row, column, parent)) return QModelIndex(); QTreeWidgetItem *parentItem; if(!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); QTreeWidgetItem* childItem = parentItem->child(row); if(childItem) return createIndex(row, column, childItem); else return QModelIndex(); } QModelIndex RemoteLocalFilesModel::parent(const QModelIndex& index) const { if(!index.isValid()) return QModelIndex(); QTreeWidgetItem* childItem = static_cast(index.internalPointer()); QTreeWidgetItem* parentItem = childItem->parent(); if(parentItem == rootItem) return QModelIndex(); else return createIndex(0, 0, parentItem); } QVariant RemoteLocalFilesModel::data(const QModelIndex& index, int role) const { if(!index.isValid()) return QVariant(); // Get the item the index points at QTreeWidgetItem* item = static_cast(index.internalPointer()); // Return data depending on the role switch(role) { case Qt::DisplayRole: case Qt::EditRole: return item->text(index.column()); case Qt::DecorationRole: return item->icon(index.column()); default: return QVariant(); } } QVariant RemoteLocalFilesModel::headerData(int section, Qt::Orientation orientation, int role) const { // Get the header string from the root item if(orientation == Qt::Horizontal && role == Qt::DisplayRole) return rootItem->data(section, role); return QVariant(); } int RemoteLocalFilesModel::rowCount(const QModelIndex& parent) const { if(parent.column() > 0) return 0; if(!parent.isValid()) return rootItem->childCount(); else return static_cast(parent.internalPointer())->childCount(); } int RemoteLocalFilesModel::columnCount(const QModelIndex& /*parent*/) const { return rootItem->columnCount(); } bool RemoteLocalFilesModel::removeRows(int row, int count, const QModelIndex& parent) { for(int i=0;i=0;i--) { auto item = static_cast(index(row + i, 0, parent).internalPointer()); item->parent()->removeChild(item); } endRemoveRows(); // If parent node is empty, remove that one too. Make sure to not remove the root node if(parent.isValid() && !index(0, 0, parent).isValid()) { beginRemoveRows(parent.parent(), 0, 0); auto item = static_cast(parent.internalPointer()); item->parent()->removeChild(item); endRemoveRows(); } return true; } sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteLocalFilesModel.h000066400000000000000000000030471463772530400250120ustar00rootroot00000000000000#ifndef REMOTELOCALFILESMODEL_H #define REMOTELOCALFILESMODEL_H #include #include class RemoteDatabase; class QTreeWidgetItem; class RemoteLocalFilesModel : public QAbstractItemModel { Q_OBJECT public: explicit RemoteLocalFilesModel(QObject* parent, RemoteDatabase& remote); ~RemoteLocalFilesModel() override; void setIdentity(const QString& cert_filename); void refresh(); QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& index) const override; QVariant data(const QModelIndex& index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; enum Columns { ColumnName, ColumnBranch, ColumnLastModified, ColumnSize, ColumnCommit, ColumnFile, }; private: // Pointer to the root item. This contains all the actual item data. QTreeWidgetItem* rootItem; // Reference to the remote database object which is stored somewhere in the main window. RemoteDatabase& remoteDatabase; // This stores the currently used network identity for further requests QString current_cert_filename; QString current_user_name; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteModel.cpp000066400000000000000000000262411463772530400234100ustar00rootroot00000000000000#include #include "Data.h" #include "RemoteModel.h" #include "RemoteNetwork.h" using json = nlohmann::json; RemoteModelItem::RemoteModelItem(RemoteModelItem* parent) : m_parent(parent), m_fetchedDirectoryList(false) { } RemoteModelItem::~RemoteModelItem() { qDeleteAll(m_children); } QVariant RemoteModelItem::value(RemoteModelColumns column) const { return m_values[column]; } void RemoteModelItem::setValue(RemoteModelColumns column, QVariant value) { m_values[column] = value; } void RemoteModelItem::appendChild(RemoteModelItem *item) { m_children.push_back(item); } RemoteModelItem* RemoteModelItem::child(int row) const { return m_children[static_cast(row)]; } RemoteModelItem* RemoteModelItem::parent() const { return m_parent; } int RemoteModelItem::childCount() const { return static_cast(m_children.size()); } int RemoteModelItem::row() const { if(m_parent) { auto f = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), const_cast(this)); if(f == m_parent->m_children.end()) return -1; else return static_cast(std::distance(m_parent->m_children.begin(), f)); } return 0; } bool RemoteModelItem::fetchedDirectoryList() const { return m_fetchedDirectoryList; } void RemoteModelItem::setFetchedDirectoryList(bool fetched) { m_fetchedDirectoryList = fetched; } std::vector RemoteModelItem::loadArray(const json& array, RemoteModelItem* parent) { std::vector items; // Loop through all directory items for(const auto& elem : array) { // Create a new model item with the specified parent RemoteModelItem* item = new RemoteModelItem(parent); // Save all relevant values. Some of the values are only available for databases. item->setValue(RemoteModelColumnName, QString::fromStdString(elem["name"])); item->setValue(RemoteModelColumnType, QString::fromStdString(elem["type"])); item->setValue(RemoteModelColumnUrl, QString::fromStdString(elem["url"])); item->setValue(RemoteModelColumnLastModified, isoDateTimeStringToLocalDateTimeString(QString::fromStdString(elem["last_modified"]))); if(item->value(RemoteModelColumnType).toString() == "database") { item->setValue(RemoteModelColumnCommitId, QString::fromStdString(elem["commit_id"])); item->setValue(RemoteModelColumnSize, QString::number(static_cast(elem["size"]))); item->setValue(RemoteModelColumnDefaultBranch, QString::fromStdString(elem["default_branch"])); item->setValue(RemoteModelColumnLicence, QString::fromStdString(elem["licence"])); item->setValue(RemoteModelColumnOneLineDescription, QString::fromStdString(elem["one_line_description"])); item->setValue(RemoteModelColumnPublic, static_cast(elem["public"])); item->setValue(RemoteModelColumnSha256, QString::fromStdString(elem["sha256"])); item->setValue(RemoteModelColumnRepoModified, isoDateTimeStringToLocalDateTimeString(QString::fromStdString(elem["repo_modified"]))); } items.push_back(item); } return items; } RemoteModel::RemoteModel(QObject* parent) : QAbstractItemModel(parent), headerList({tr("Name"), tr("Last modified"), tr("Size"), tr("Commit")}), rootItem(new RemoteModelItem()) { } RemoteModel::~RemoteModel() { delete rootItem; } void RemoteModel::setNewRootDir(const QString& url, const QString& cert) { // Get user name from client cert currentUserName = RemoteNetwork::get().getInfoFromClientCert(cert, RemoteNetwork::CertInfoUser); // Save settings currentRootDirectory = url; currentClientCert = cert; // Fetch root directory refresh(); } void RemoteModel::refresh() { // Fetch root directory and put the reply data under the root item RemoteNetwork::get().fetch(currentRootDirectory, RemoteNetwork::RequestTypeCustom, currentClientCert, [this](const QByteArray& reply) { parseDirectoryListing(reply, QModelIndex()); }); } void RemoteModel::parseDirectoryListing(const QString& text, QModelIndex parent) { // Load new JSON root document assuming it's an array json array = json::parse(text.toStdString(), nullptr, false); if(array.is_discarded() || !array.is_array()) return; // Get model index to store the new data under RemoteModelItem* parentItem = const_cast(modelIndexToItem(parent)); // An invalid model index indicates that this is a new root item. This means the old one needs to be entirely deleted first. if(!parent.isValid()) { // Clear root item beginResetModel(); delete rootItem; rootItem = new RemoteModelItem(); endResetModel(); // Set parent model index and parent item to the new values parent = QModelIndex(); parentItem = rootItem; } // Insert data std::vector items = RemoteModelItem::loadArray(array, parentItem); beginInsertRows(parent, 0, static_cast(items.size() - 1)); for(RemoteModelItem* item : items) parentItem->appendChild(item); endInsertRows(); // Emit directory listing parsed signal emit directoryListingParsed(parent); } QModelIndex RemoteModel::index(int row, int column, const QModelIndex& parent) const { if(!hasIndex(row, column, parent)) return QModelIndex(); const RemoteModelItem* parentItem = modelIndexToItem(parent); RemoteModelItem* childItem = parentItem->child(row); if(childItem) return createIndex(row, column, childItem); else return QModelIndex(); } QModelIndex RemoteModel::parent(const QModelIndex& index) const { if(!index.isValid()) return QModelIndex(); const RemoteModelItem* childItem = modelIndexToItem(index); RemoteModelItem* parentItem = childItem->parent(); if(parentItem == rootItem) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem); } QVariant RemoteModel::data(const QModelIndex& index, int role) const { // Don't return data for invalid indices if(!index.isValid()) return QVariant(); // Type of item const RemoteModelItem* item = modelIndexToItem(index); QString type = item->value(RemoteModelColumnType).toString(); // Decoration role? Only for first column! if(role == Qt::DecorationRole && index.column() == 0) { // Use different icons depending on item type if(type == "folder" && index.parent() == QModelIndex() && item->value(RemoteModelColumnName) == currentUserName) return QImage(":/icons/folder_user"); else if(type == "folder") return QImage(":/icons/folder"); else if(type == "database") return QImage(":/icons/database"); } else if(role == Qt::ToolTipRole) { if(type == "database") { // Use URL to generate user name and database name. This avoids using the name of the parent item which // might not contain the user name when the server sends a different directory structure. QString result = "" + item->value(RemoteModelColumnUrl).toUrl().path().mid(1) + ""; if(!item->value(RemoteModelColumnOneLineDescription).toString().isEmpty()) result += "
" + item->value(RemoteModelColumnOneLineDescription).toString(); result += "
" + tr("Size: ") + humanReadableSize(item->value(RemoteModelColumnSize).toULongLong()); result += "
" + tr("Last Modified: ") + item->value(RemoteModelColumnLastModified).toString(); result += "
" + tr("Licence: ") + item->value(RemoteModelColumnLicence).toString(); result += "
" + tr("Default Branch: ") + item->value(RemoteModelColumnDefaultBranch).toString(); return result; } } else if(role == Qt::DisplayRole) { // Display role? // Return different value depending on column switch(index.column()) { case 0: { return item->value(RemoteModelColumnName); } case 1: { return item->value(RemoteModelColumnLastModified); } case 2: { // Folders don't have a size if(type == "folder") return QVariant(); // Convert size to human readable format unsigned int size = item->value(RemoteModelColumnSize).toUInt(); return humanReadableSize(size); } case 3: { if(type == "folder") return QVariant(); return item->value(RemoteModelColumnCommitId); } } } return QVariant(); } QVariant RemoteModel::headerData(int section, Qt::Orientation orientation, int role) const { // Call default implementation for vertical headers and for non-display roles if(role != Qt::DisplayRole || orientation != Qt::Horizontal) return QAbstractItemModel::headerData(section, orientation, role); // Return header string depending on column return headerList.at(static_cast(section)); } int RemoteModel::rowCount(const QModelIndex& parent) const { if(parent.column() > 0) return 0; const RemoteModelItem* parentItem = modelIndexToItem(parent); return parentItem->childCount(); } int RemoteModel::columnCount(const QModelIndex& /*parent*/) const { return static_cast(headerList.size()); } bool RemoteModel::hasChildren(const QModelIndex& parent) const { if(!parent.isValid()) return true; // If the item actually has children or is of type "folder" (and may have no children yet), we say that it actually has children const RemoteModelItem* item = modelIndexToItem(parent); return item->childCount() || item->value(RemoteModelColumnType) == "folder"; } bool RemoteModel::canFetchMore(const QModelIndex& parent) const { if(!parent.isValid()) return false; // If the item is of type "folder" and we haven't tried fetching a directory listing yet, we indicate that there might be more data to load const RemoteModelItem* item = modelIndexToItem(parent); return item->value(RemoteModelColumnType) == "folder" && !item->fetchedDirectoryList(); } void RemoteModel::fetchMore(const QModelIndex& parent) { // Can we even fetch more data? if(!canFetchMore(parent)) return; // Get parent item RemoteModelItem* item = static_cast(parent.internalPointer()); // Fetch item URL item->setFetchedDirectoryList(true); RemoteNetwork::get().fetch(item->value(RemoteModelColumnUrl).toUrl(), RemoteNetwork::RequestTypeCustom, currentClientCert, [this, parent](const QByteArray& reply) { parseDirectoryListing(reply, parent); }); } const QString& RemoteModel::currentClientCertificate() const { return currentClientCert; } const RemoteModelItem* RemoteModel::modelIndexToItem(const QModelIndex& idx) const { if(!idx.isValid()) return rootItem; else return static_cast(idx.internalPointer()); } sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteModel.h000066400000000000000000000102261463772530400230510ustar00rootroot00000000000000#ifndef REMOTEMODEL_H #define REMOTEMODEL_H #include #include #include // List of fields stored in the JSON data enum RemoteModelColumns { RemoteModelColumnName, RemoteModelColumnType, RemoteModelColumnUrl, RemoteModelColumnCommitId, RemoteModelColumnSize, RemoteModelColumnLastModified, RemoteModelColumnDefaultBranch, RemoteModelColumnLicence, RemoteModelColumnOneLineDescription, RemoteModelColumnPublic, RemoteModelColumnRepoModified, RemoteModelColumnSha256, RemoteModelColumnCount }; class RemoteModelItem { public: explicit RemoteModelItem(RemoteModelItem* parent = nullptr); ~RemoteModelItem(); QVariant value(RemoteModelColumns column) const; void setValue(RemoteModelColumns column, QVariant value); bool fetchedDirectoryList() const; void setFetchedDirectoryList(bool fetched); void appendChild(RemoteModelItem* item); RemoteModelItem* child(int row) const; RemoteModelItem* parent() const; int childCount() const; int row() const; // This function assumes the JSON value it's getting passed is an array ("[{...}, {...}, {...}, ...]"). It returns a list of model items, one // per array entry and each with the specified parent set. static std::vector loadArray(const nlohmann::json& array, RemoteModelItem* parent = nullptr); private: // These are just the fields from the json objects returned by the dbhub.io server QVariant m_values[RemoteModelColumnCount]; // Child items and parent item std::vector m_children; RemoteModelItem* m_parent; // Indicates whether we already tried fetching a directory listing for this item. This serves two purposes: // 1) When having an empty directory this allows us to remove the expandable flag for this item. // 2) Between sending a network request and getting the reply this flag is already set, avoiding a second or third request being sent in the meantime. bool m_fetchedDirectoryList; }; class RemoteModel : public QAbstractItemModel { Q_OBJECT public: explicit RemoteModel(QObject* parent); ~RemoteModel() override; void setNewRootDir(const QString& url, const QString& cert); void refresh(); QModelIndex index(int row, int column,const QModelIndex& parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& index) const override; QVariant data(const QModelIndex& index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; bool hasChildren(const QModelIndex& parent) const override; bool canFetchMore(const QModelIndex& parent) const override; void fetchMore(const QModelIndex& parent) override; // This helper function takes a model index and returns the according model item. An invalid model index is used to indicate the // root item, so if the index is invalid the root item is returned. This means that if you need to check for actual invalid indices // this needs to be done prior to calling this function. const RemoteModelItem* modelIndexToItem(const QModelIndex& idx) const; // Returns the current client certificate const QString& currentClientCertificate() const; signals: // This signal is emitted whenever a directory listing has been received and parsed void directoryListingParsed(QModelIndex parent); private slots: // This is called whenever a network reply containing a directory listing arrives void parseDirectoryListing(const QString& text, QModelIndex parent); private: // The header list is a list of column titles const std::vector headerList; // Pointer to the root item. This contains all the actual item data. RemoteModelItem* rootItem; // This stores the currently used network identity so it can be used for further requests, e.g. for // lazy population. QUrl currentRootDirectory; QString currentClientCert; QString currentUserName; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteNetwork.cpp000066400000000000000000000516461463772530400240100ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FileDialog.h" #include "RemoteNetwork.h" #include "Settings.h" #include "sqlite.h" #include "version.h" using json = nlohmann::json; RemoteNetwork::RemoteNetwork() : m_manager(new QNetworkAccessManager), m_progress(nullptr), m_sslConfiguration(QSslConfiguration::defaultConfiguration()) { // Set up SSL configuration m_sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer); // Load CA certs from resource file QDir dirCaCerts(":/certs"); const QStringList caCertsList = dirCaCerts.entryList(); QList caCerts; for(const QString& caCertName : caCertsList) caCerts += QSslCertificate::fromPath(":/certs/" + caCertName); m_sslConfiguration.setCaCertificates(caCerts); // Load settings and set up some more stuff while doing so reloadSettings(); // Set up signals connect(m_manager, &QNetworkAccessManager::encrypted, this, &RemoteNetwork::gotEncrypted); connect(m_manager, &QNetworkAccessManager::sslErrors, this, &RemoteNetwork::gotError); } RemoteNetwork::~RemoteNetwork() { delete m_manager; delete m_progress; } void RemoteNetwork::reloadSettings() { // Load all configured client certificates m_clientCertFiles.clear(); const auto client_certs = Settings::getValue("remote", "client_certificates").toStringList(); for(const QString& path : client_certs) { QFile file(path); file.open(QFile::ReadOnly); QSslCertificate cert(&file); file.close(); m_clientCertFiles.insert({path, cert}); } // Always add the default certificate for anonymous access to dbhub.io { QFile file(":/user_certs/public.cert.pem"); file.open(QFile::ReadOnly); QSslCertificate cert(&file); file.close(); m_clientCertFiles.insert({":/user_certs/public.cert.pem", cert}); } // Configure proxy to use { QString type = Settings::getValue("proxy", "type").toString(); QNetworkProxy proxy; if(type == "system") { // For system settings we have to get the system-wide proxy and use that // Get list of proxies for accessing dbhub.io via HTTPS and use the first one auto list = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(QUrl("https://db4s.dbhub.io/"))); proxy = list.front(); } else { // For any other type we have to set up our own proxy configuration // Retrieve the required settings QString host = Settings::getValue("proxy", "host").toString(); unsigned short port = static_cast(Settings::getValue("proxy", "port").toUInt()); bool authentication = Settings::getValue("proxy", "authentication").toBool(); if(type == "http") proxy.setType(QNetworkProxy::HttpProxy); else if(type == "socks5") proxy.setType(QNetworkProxy::Socks5Proxy); else proxy.setType(QNetworkProxy::NoProxy); proxy.setHostName(host); proxy.setPort(port); // Only set authentication details when authentication is required if(authentication) { QString user = Settings::getValue("proxy", "user").toString(); QString password = Settings::getValue("proxy", "password").toString(); proxy.setUser(user); proxy.setPassword(password); } } // Start using the new proxy configuration QNetworkProxy::setApplicationProxy(proxy); } } void RemoteNetwork::gotEncrypted(QNetworkReply* reply) { #ifdef Q_OS_MAC // Temporary workaround for now, as Qt 5.8 and below doesn't support // verifying certificates on OSX: https://bugreports.qt.io/browse/QTBUG-56973 // Hopefully this is fixed in Qt 5.9 return; #else // Verify the server's certificate using our CA certs auto verificationErrors = reply->sslConfiguration().peerCertificate().verify(m_sslConfiguration.caCertificates()); bool good = false; if(verificationErrors.size() == 0) { good = true; } else if(verificationErrors.size() == 1) { // Ignore any self signed certificate errors if(verificationErrors.at(0).error() == QSslError::SelfSignedCertificate || verificationErrors.at(0).error() == QSslError::SelfSignedCertificateInChain) good = true; } // If the server certificate didn't turn out to be good, abort the reply here if(!good) reply->abort(); #endif } void RemoteNetwork::gotReply(QNetworkReply* reply) { // What type of data is this? RequestType type = static_cast(reply->property("type").toInt()); // Hide progress dialog before opening a file dialog to make sure the progress dialog doesn't interfer with the file dialog if(type == RequestTypeDatabase || type == RequestTypePush) m_progress->reset(); // Handle the reply data switch(type) { case RequestTypeDatabase: { // It's a database file. // Get last modified date as provided by the server QDateTime last_modified; QString content_disposition = reply->rawHeader("Content-Disposition"); QRegExp regex("^.*modification-date=\"(.+)\";.*$"); regex.setMinimal(true); // Set to non-greedy matching if(regex.indexIn(content_disposition) != -1) last_modified = QDateTime::fromString(regex.cap(1), Qt::ISODate); // Extract all other information from reply and send it to slots emit fetchFinished(reply->url().fileName(), reply->property("certfile").toString(), reply->url(), QUrlQuery(reply->url()).queryItemValue("commit").toStdString(), QUrlQuery(reply->url()).queryItemValue("branch").toStdString(), last_modified, reply); } break; case RequestTypePush: { // Read and check results json obj = json::parse(reply->readAll(), nullptr, false); if(obj.is_discarded() || !obj.is_object()) break; // Extract all information from reply and send it to slots emit pushFinished(reply->url().fileName(), reply->property("certfile").toString(), QString::fromStdString(obj["url"]), obj["commit_id"], QUrlQuery(QUrl(QString::fromStdString(obj["url"]))).queryItemValue("branch").toStdString(), reply->property("source_file").toString()); break; } case RequestTypeDownload: { // It's a download // Where should we save it? QString path = FileDialog::getSaveFileName(FileDialogTypes::CreateDatabaseFile, nullptr, tr("Choose a location to save the file"), QString(), reply->url().fileName() + "_" + QUrlQuery(reply->url()).queryItemValue("commit") + ".db"); if(path.isEmpty()) break; // Save the downloaded data in that file QFile file(path); file.open(QIODevice::WriteOnly); file.write(reply->readAll()); file.close(); } break; case RequestTypeCustom: break; } // Delete reply later, i.e. after returning from this slot function reply->deleteLater(); } void RemoteNetwork::gotError(QNetworkReply* reply, const QList& errors) { // Are there any errors in here that aren't about self-signed certificates and non-matching hostnames? bool serious_errors = std::any_of(errors.begin(), errors.end(), [](const QSslError& error) { return error.error() != QSslError::SelfSignedCertificate; }); // Just stop the error checking here and accept the reply if there were no 'serious' errors if(!serious_errors) { reply->ignoreSslErrors(errors); return; } // Build an error message and short it to the user QString message = tr("Error opening remote file at %1.\n%2").arg(reply->url().toString(), errors.at(0).errorString()); QMessageBox::warning(nullptr, qApp->applicationName(), message); // Delete reply later, i.e. after returning from this slot function if(m_progress) m_progress->reset(); reply->deleteLater(); } void RemoteNetwork::updateProgress(qint64 bytesTransmitted, qint64 bytesTotal) { // Find out to which pending reply this progress update belongs QNetworkReply* reply = qobject_cast(QObject::sender()); // Update progress dialog if(bytesTotal == -1) { // We don't know anything about the current progress, but it's still downloading m_progress->setMinimum(0); m_progress->setMaximum(0); m_progress->setValue(0); } else if(bytesTransmitted == bytesTotal) { // The download has finished m_progress->reset(); } else { // It's still downloading and we know the current progress // Were using a range 0 to 10000 here, the progress dialog will calculate 0% to 100% values from that. The reason we're not using // the byte counts as-is is that they're 64bit wide while the progress dialog takes only 32bit values, so for large files the values // would lose precision. The reason why we're not using a range 0 to 100 is that our range increases the precision a bit and this way // we're prepared if the progress dialog will show decimal numbers one day on one platform. m_progress->setMinimum(0); m_progress->setMaximum(10000); m_progress->setValue(static_cast((static_cast(bytesTransmitted) / static_cast(bytesTotal)) * 10000.0f)); } // Check if the Cancel button has been pressed if(reply && m_progress->wasCanceled()) { reply->abort(); m_progress->reset(); } } const QList& RemoteNetwork::caCertificates() const { static QList certs = m_sslConfiguration.caCertificates(); return certs; } QString RemoteNetwork::getInfoFromClientCert(const QString& cert, CertInfo info) const { // Get the common name of the certificate and split it into user name and server address QString cn = m_clientCertFiles.at(cert).subjectInfo(QSslCertificate::CommonName).at(0); QStringList cn_parts = cn.split("@"); if(cn_parts.size() < 2) return QString(); // Return requested part of the CN if(info == CertInfoUser) { return cn_parts.first(); } else if(info == CertInfoServer) { // Assemble the full URL from the host name. We use port 443 by default but for // local development purposes we use 5550 instead. QString host = cn_parts.last(); host = QString("https://%1%2/").arg(host, host.contains("docker-dev") ? ":5550" : ""); return host; } return QString(); } bool RemoteNetwork::prepareSsl(QNetworkRequest* request, const QString& clientCert) { // Check if client cert exists const QSslCertificate& cert = m_clientCertFiles[clientCert]; if(cert.isNull()) { QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error: Invalid client certificate specified.")); return false; } // Load private key for the client certificate QFile fileClientCert(clientCert); fileClientCert.open(QFile::ReadOnly); QSslKey clientKey(&fileClientCert, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); while(clientKey.isNull()) { // If the private key couldn't be read, we assume it's password protected. So ask the user for the correct password and try reading it // again. If the user cancels the password dialog, abort the whole process. QString password = QInputDialog::getText(nullptr, qApp->applicationName(), tr("Please enter the passphrase for this client certificate in order to authenticate.")); if(password.isEmpty()) return false; clientKey = QSslKey(&fileClientCert, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, password.toUtf8()); } fileClientCert.close(); // Set client certificate (from the cache) and private key (just loaded) m_sslConfiguration.setLocalCertificate(cert); m_sslConfiguration.setPrivateKey(clientKey); // Apply SSL configuration request->setSslConfiguration(m_sslConfiguration); return true; } void RemoteNetwork::prepareProgressDialog(QNetworkReply* reply, bool upload, const QUrl& url) { // Instantiate progress dialog and apply some basic settings if(!m_progress) m_progress = new QProgressDialog(); m_progress->reset(); // Disable context help button on Windows m_progress->setWindowFlags(m_progress->windowFlags() & ~Qt::WindowContextHelpButtonHint); m_progress->setWindowModality(Qt::NonModal); m_progress->setCancelButtonText(tr("Cancel")); // Set dialog text QString url_for_display = url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery); if(upload) m_progress->setLabelText(tr("Uploading remote database to\n%1").arg(url_for_display)); else m_progress->setLabelText(tr("Downloading remote database from\n%1").arg(url_for_display)); // Show dialog m_progress->show(); // Make sure the dialog is updated if(upload) connect(reply, &QNetworkReply::uploadProgress, this, &RemoteNetwork::updateProgress); else connect(reply, &QNetworkReply::downloadProgress, this, &RemoteNetwork::updateProgress); } void RemoteNetwork::fetch(const QUrl& url, RequestType type, const QString& clientCert, std::function when_finished, bool synchronous, bool ignore_errors) { // Build network request QNetworkRequest request; request.setUrl(url); request.setRawHeader("User-Agent", QString("%1 %2").arg(qApp->organizationName(), APP_VERSION).toUtf8()); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); #endif // Set SSL configuration when trying to access a file via the HTTPS protocol. // Skip this step when no client certificate was specified. In this case the default HTTPS configuration is used. bool https = url.scheme().compare("https", Qt::CaseInsensitive) == 0; if(https && !clientCert.isNull()) { // If configuring the SSL connection fails, abort the request here if(!prepareSsl(&request, clientCert)) return; } // Clear access cache if necessary clearAccessCache(clientCert); // Fetch database and prepare pending reply for future processing QNetworkReply* reply = m_manager->get(request); reply->setProperty("type", type); reply->setProperty("certfile", clientCert); reply->setProperty("ignore_errors", ignore_errors); // Hook up custom handler when there is one and global handler otherwise if(when_finished) { connect(reply, &QNetworkReply::finished, reply, [this, when_finished, reply]() { if(handleReply(reply)) when_finished(reply->readAll()); }); } else { connect(reply, &QNetworkReply::finished, this, [this, reply]() { if(handleReply(reply)) gotReply(reply); }); } // When the synchrounous flag is set we wait for the request to finish before continuing if(synchronous) { QEventLoop loop; connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); } // Initialise the progress dialog for this request, but only if this is a database file or a download. // Directory listing and similar are small enough to be loaded without progress dialog. if(type == RequestTypeDatabase || type == RequestTypeDownload) prepareProgressDialog(reply, false, url); } void RemoteNetwork::push(const QString& filename, const QUrl& url, const QString& clientCert, const QString& remotename, const QString& commitMessage, const QString& licence, bool isPublic, const QString& branch, bool forcePush, const QString& last_commit) { // Open the file to send and check if it exists QFile* file = new QFile(filename); if(!file->open(QFile::ReadOnly)) { delete file; QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error: Cannot open the file for sending.")); return; } // Build network request QNetworkRequest request; request.setUrl(url); request.setRawHeader("User-Agent", QString("%1 %2").arg(qApp->organizationName(), APP_VERSION).toUtf8()); // Get the last modified date of the file and prepare it for conversion into the ISO date format QDateTime last_modified = QFileInfo(filename).lastModified().toOffsetFromUtc(0); // Prepare HTTP multi part data containing all the information about the commit we're about to push QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType); addPart(multipart, "file", file, remotename); addPart(multipart, "commitmsg", commitMessage); addPart(multipart, "licence", licence); addPart(multipart, "public", isPublic ? "true" : "false"); addPart(multipart, "branch", branch); addPart(multipart, "force", forcePush ? "true" : "false"); addPart(multipart, "lastmodified", last_modified.toString("yyyy-MM-dd'T'HH:mm:ss'Z'")); // Only add commit id if one was provided if(!last_commit.isEmpty()) addPart(multipart, "commit", last_commit); // Set SSL configuration when trying to access a file via the HTTPS protocol bool https = url.scheme().compare("https", Qt::CaseInsensitive) == 0; if(https) { // If configuring the SSL connection fails, abort the request here if(!prepareSsl(&request, clientCert)) { delete file; return; } } // Clear access cache if necessary clearAccessCache(clientCert); // Put database to remote server and save pending reply for future processing QNetworkReply* reply = m_manager->post(request, multipart); reply->setProperty("type", RequestTypePush); reply->setProperty("certfile", clientCert); reply->setProperty("source_file", filename); multipart->setParent(reply); // Delete the multi-part object along with the reply // Connect reply handler connect(reply, &QNetworkReply::finished, this, [this, reply]() { if(handleReply(reply)) gotReply(reply); }); // Initialise the progress dialog for this request prepareProgressDialog(reply, true, url); } void RemoteNetwork::addPart(QHttpMultiPart* multipart, const QString& name, const QString& value) const { QHttpPart part; part.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(name)); part.setBody(value.toUtf8()); multipart->append(part); } void RemoteNetwork::addPart(QHttpMultiPart* multipart, const QString& name, QFile* file, const QString& filename) const { QHttpPart part; part.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"; filename=\"%2\"").arg(name, filename)); part.setBodyDevice(file); file->setParent(multipart); // Close the file and delete the file object as soon as the multi-part object is destroyed multipart->append(part); } void RemoteNetwork::clearAccessCache(const QString& clientCert) { // When the client certificate is different from the one before, clear the access and authentication cache. // Otherwise Qt might use the old certificate again. static QString lastClientCert; if(lastClientCert != clientCert) { lastClientCert = clientCert; m_manager->clearAccessCache(); } } bool RemoteNetwork::handleReply(QNetworkReply* reply) { // Check if request was successful if(reply->error() != QNetworkReply::NoError) { // Do not show error message when operation was cancelled on purpose if(reply->error() != QNetworkReply::OperationCanceledError && !reply->property("ignore_errors").toBool()) { QMessageBox::warning(nullptr, qApp->applicationName(), reply->errorString() + "\n" + reply->readAll()); } reply->deleteLater(); return false; } return true; } sqlitebrowser-sqlitebrowser-5733cb7/src/RemoteNetwork.h000066400000000000000000000066311463772530400234470ustar00rootroot00000000000000#ifndef REMOTENETWORK_H #define REMOTENETWORK_H #include #include #include #include class QNetworkAccessManager; class QNetworkReply; class QProgressDialog; class QNetworkRequest; class QHttpMultiPart; class QFile; class RemoteNetwork : public QObject { Q_OBJECT public: static RemoteNetwork& get() { static RemoteNetwork instance; return instance; } void reloadSettings(); enum CertInfo { CertInfoUser, CertInfoServer, }; const QList& caCertificates() const; const std::map& clientCertificates() const { return m_clientCertFiles; } QString getInfoFromClientCert(const QString& cert, CertInfo info) const; enum RequestType { RequestTypeCustom, RequestTypeDatabase, RequestTypePush, RequestTypeDownload, }; void fetch(const QUrl& url, RequestType type, const QString& clientCert = QString(), std::function when_finished = {}, bool synchronous = false, bool ignore_errors = false); void push(const QString& filename, const QUrl& url, const QString& clientCert, const QString& remotename, const QString& commitMessage = QString(), const QString& licence = QString(), bool isPublic = false, const QString& branch = QString("main"), bool forcePush = false, const QString& last_commit = QString()); signals: // The fetchFinished() signal is emitted when a fetch() call for a database is finished void fetchFinished(QString filename, QString identity, const QUrl& url, std::string new_commit_id, std::string branch, QDateTime last_modified, QIODevice* device); // The pushFinished() signal is emitted when a push() call is finished, i.e. a database upload has completed. void pushFinished(QString filename, QString identity, const QUrl& url, std::string new_commit_id, std::string branch, QString source_file); private: RemoteNetwork(); ~RemoteNetwork() override; void gotEncrypted(QNetworkReply* reply); void gotReply(QNetworkReply* reply); void gotError(QNetworkReply* reply, const QList& errors); void updateProgress(qint64 bytesTransmitted, qint64 bytesTotal); bool prepareSsl(QNetworkRequest* request, const QString& clientCert); void prepareProgressDialog(QNetworkReply* reply, bool upload, const QUrl& url); // Helper functions for building multi-part HTTP requests void addPart(QHttpMultiPart* multipart, const QString& name, const QString& value) const; void addPart(QHttpMultiPart* multipart, const QString& name, QFile* file, const QString& filename) const; // Before using a new client certificate we need to clear the access and authentication cache of the network manager // object. Otherwise Qt might reuse the old certificate if the requested URL has been used before. void clearAccessCache(const QString& clientCert); // This function is called for all network replies we get whether they are handled globally or individually. // It mainly does some error checking and returns true if the actual handler should be called. bool handleReply(QNetworkReply* reply); QNetworkAccessManager* m_manager; QProgressDialog* m_progress; QSslConfiguration m_sslConfiguration; std::map m_clientCertFiles; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/RemotePushDialog.cpp000066400000000000000000000131521463772530400244040ustar00rootroot00000000000000#include #include #include #include #include "RemotePushDialog.h" #include "ui_RemotePushDialog.h" #include "RemoteNetwork.h" using json = nlohmann::json; RemotePushDialog::RemotePushDialog(QWidget* parent, const QString& host, const QString& clientCert, const QString& name, const QString& branch, const QString& user) : QDialog(parent), ui(new Ui::RemotePushDialog), m_host(host), m_clientCert(clientCert), m_nameValidator(new QRegExpValidator(QRegExp("^[a-z,A-Z,0-9,\\.,\\-,\\_,\\(,\\),\\+,\\ ]+$"), this)), m_branchValidator(new QRegExpValidator(QRegExp("^[a-z,A-Z,0-9,\\^,\\.,\\-,\\_,\\/,\\(,\\),\\:,\\&,\\ )]+$"), this)) { // Create UI ui->setupUi(this); ui->editName->setValidator(m_nameValidator); ui->comboBranch->setValidator(m_branchValidator); ui->comboUser->setValidator(m_nameValidator); // Set start values ui->editName->setText(name); // Fill in usernames ui->comboUser->addItem(RemoteNetwork::get().getInfoFromClientCert(m_clientCert, RemoteNetwork::CertInfoUser)); if(!user.isEmpty()) ui->comboUser->addItem(user); // Enable/disable accept button checkInput(); // Fetch list of available licences RemoteNetwork::get().fetch(host + "licence/list", RemoteNetwork::RequestTypeCustom, clientCert, [this](const QByteArray& reply) { // Clear licence list ui->comboLicence->clear(); // Read and check results json obj = json::parse(reply, nullptr, false); if(obj.is_discarded() || !obj.is_object()) return; // Parse data and build ordered licence map: order -> (short name, long name) std::map> licences; for(auto it=obj.cbegin();it!=obj.cend();++it) licences.insert({it.value()["order"], {it.key(), it.value()["full_name"]}}); // Parse licence list and fill combo box. Show the full name to the user and use the short name as user data. for(auto it=licences.begin();it!=licences.end();++it) ui->comboLicence->addItem(QString::fromStdString(it->second.second), QString::fromStdString(it->second.first)); }); // Fetch list of existing branches reloadBranchList(branch); } RemotePushDialog::~RemotePushDialog() { delete ui; } void RemotePushDialog::checkInput() { // Update public/private check box text if(ui->checkPublic->isChecked()) ui->checkPublic->setText(tr("Database will be public. Everyone has read access to it.")); else ui->checkPublic->setText(tr("Database will be private. Only you have access to it.")); // Update the foce push check box text if(ui->checkForce->isChecked()) ui->checkForce->setText(tr("Use with care. This can cause remote commits to be deleted.")); else ui->checkForce->setText(" "); // The space character here is required to avoid annoying resizes when toggling the checkbox // Check input bool valid = true; if(ui->editName->text().trimmed().isEmpty()) valid = false; if(ui->editCommitMessage->toPlainText().size() > 1024) valid = false; if(ui->comboBranch->currentText().size() < 1 || ui->comboBranch->currentText().size() > 32) valid = false; if(ui->comboUser->currentText().trimmed().isEmpty()) valid = false; ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); } void RemotePushDialog::accept() { QDialog::accept(); } QString RemotePushDialog::name() const { return ui->editName->text().trimmed(); } QString RemotePushDialog::commitMessage() const { return ui->editCommitMessage->toPlainText().trimmed(); } QString RemotePushDialog::licence() const { return ui->comboLicence->currentData(Qt::UserRole).toString(); } bool RemotePushDialog::isPublic() const { return ui->checkPublic->isChecked(); } QString RemotePushDialog::branch() const { return ui->comboBranch->currentText(); } QString RemotePushDialog::user() const { return ui->comboUser->currentText(); } bool RemotePushDialog::forcePush() const { return ui->checkForce->isChecked(); } void RemotePushDialog::reloadBranchList(const QString& select_branch) { QUrl url(m_host + "branch/list"); QUrlQuery query; query.addQueryItem("username", ui->comboUser->currentText()); query.addQueryItem("folder", "/"); query.addQueryItem("dbname", ui->editName->text()); url.setQuery(query); RemoteNetwork::get().fetch(url.toString(), RemoteNetwork::RequestTypeCustom, m_clientCert, [this, select_branch](const QByteArray& reply) { // Read and check results json obj = json::parse(reply, nullptr, false); if(obj.is_discarded() || !obj.is_object()) return; json obj_branches = obj["branches"]; // Get default branch std::string default_branch = (obj.contains("default_branch") && !obj["default_branch"].empty()) ? obj["default_branch"] : "main"; // Clear branch list and add the default branch ui->comboBranch->clear(); ui->comboBranch->addItem(QString::fromStdString(default_branch)); // Parse data and assemble branch list std::vector branches; for(auto it=obj_branches.cbegin();it!=obj_branches.cend();++it) { if(it.key() != default_branch) ui->comboBranch->addItem(QString::fromStdString(it.key())); } // If a branch was suggested, select it now if(!select_branch.isEmpty()) ui->comboBranch->setCurrentIndex(ui->comboBranch->findText(select_branch)); }, false, true); } sqlitebrowser-sqlitebrowser-5733cb7/src/RemotePushDialog.h000066400000000000000000000020041463772530400240430ustar00rootroot00000000000000#ifndef REMOTEPUSHDIALOG_H #define REMOTEPUSHDIALOG_H #include class QRegExpValidator; namespace Ui { class RemotePushDialog; } class RemotePushDialog : public QDialog { Q_OBJECT public: explicit RemotePushDialog(QWidget* parent, const QString& host, const QString& clientCert, const QString& name = QString(), const QString& branch = QString(), const QString& user = QString()); ~RemotePushDialog() override; QString name() const; QString commitMessage() const; QString licence() const; bool isPublic() const; QString branch() const; QString user() const; bool forcePush() const; private: Ui::RemotePushDialog* ui; // Connection details QString m_host; QString m_clientCert; // Validators QRegExpValidator* m_nameValidator; QRegExpValidator* m_branchValidator; protected slots: void checkInput(); void reloadBranchList(const QString& select_branch = QString()); void accept() override; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/RemotePushDialog.ui000066400000000000000000000210061463772530400242340ustar00rootroot00000000000000 RemotePushDialog 0 0 583 315 Push database Database na&me to push to editName 256 Commit message editCommitMessage <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> false Database licence comboLicence 0 0 Public checkPublic Branch comboBranch true true Force push checkForce Username comboUser true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok editName editCommitMessage comboBranch checkPublic comboLicence comboUser checkForce buttonBox accepted() RemotePushDialog accept() 257 305 157 274 buttonBox rejected() RemotePushDialog reject() 325 305 286 274 editName textChanged(QString) RemotePushDialog checkInput() 201 25 217 3 checkPublic toggled(bool) RemotePushDialog checkInput() 345 181 210 175 editCommitMessage textChanged() RemotePushDialog checkInput() 175 113 91 111 editName textChanged(QString) RemotePushDialog reloadBranchList() 176 25 77 3 comboBranch currentTextChanged(QString) RemotePushDialog checkInput() 346 160 33 151 checkForce toggled(bool) RemotePushDialog checkInput() 342 269 62 229 comboUser currentTextChanged(QString) RemotePushDialog reloadBranchList() 373 235 291 157 comboUser currentTextChanged(QString) RemotePushDialog checkInput() 373 235 291 157 checkInput() reloadBranchList() sqlitebrowser-sqlitebrowser-5733cb7/src/RowCache.h000066400000000000000000000154501463772530400223340ustar00rootroot00000000000000#ifndef ROW_CACHE_H #define ROW_CACHE_H #include #include #include #include /** cache structure adapted to the existing access patterns in SqliteTableModel. handles many large segments with gaps in between well. logical structure resembling a std::vector>, but implementation avoids actually allocating space for the non-empty optionals, and supports (hopefully) more efficient insertion / deletion. actually, this is not even a "cache" - once set, elements are never thrown away to make space for new elements. TODO introduce maximum segment size? **/ template class RowCache { public: using value_type = T; /// constructs an empty cache explicit RowCache (); /// \returns number of cached rows size_t numSet () const; /// \returns number of segments size_t numSegments () const; /// \returns 1 if specified row is loaded, 0 otherwise size_t count (size_t pos) const; /// \returns specified row. \throws if not available const T & at (size_t pos) const; T & at (size_t pos); /// assigns value to specified row; may increase numSet() by one void set (size_t pos, T && value); /// insert new element; increases numSet() by one void insert (size_t pos, T && value); /// delete element; decreases numSet() by one void erase (size_t pos); /// reset to state after construction void clear (); /// given a range of rows (end is exclusive), narrow it in order /// to remove already-loaded rows from both ends. void smallestNonAvailableRange (size_t & row_begin, size_t & row_end) const; private: /// a single segment containing contiguous entries struct Segment { size_t pos_begin; std::vector entries; /// returns past-the-end position of this segment size_t pos_end () const { return pos_begin + entries.size(); } }; /// collection of non-overlapping segments, in order of increasing /// position using Segments = std::vector; Segments segments; // ------------------------------------------------------------------------------ /// \returns first segment that definitely cannot contain 'pos', /// because it starts at some later position. typename Segments::const_iterator getSegmentBeyond (size_t pos) const { // first segment whose pos_begin > pos (so can't contain pos itself): return std::upper_bound(segments.begin(), segments.end(), pos, pred); } typename Segments::iterator getSegmentBeyond (size_t pos) { return std::upper_bound(segments.begin(), segments.end(), pos, pred); } static bool pred (size_t pos, const Segment & s) { return pos < s.pos_begin; } // ------------------------------------------------------------------------------ /// \returns segment containing 'pos' typename Segments::const_iterator getSegmentContaining (size_t pos) const { auto it = getSegmentBeyond(pos); if(it != segments.begin()) { auto prev_it = it - 1; if(pos < prev_it->pos_end()) return prev_it; } return segments.end(); } }; template RowCache::RowCache () { } template size_t RowCache::numSet () const { return std::accumulate(segments.begin(), segments.end(), size_t(0), [](size_t r, const Segment & s) { return r + s.entries.size(); }); } template size_t RowCache::numSegments () const { return segments.size(); } template size_t RowCache::count (size_t pos) const { return getSegmentContaining(pos) != segments.end(); } template const T & RowCache::at (size_t pos) const { auto it = getSegmentContaining(pos); if(it != segments.end()) return it->entries[pos - it->pos_begin]; throw std::out_of_range("no matching segment found"); } template T & RowCache::at (size_t pos) { return const_cast(static_cast(*this).at(pos)); } template void RowCache::set (size_t pos, T && value) { auto it = getSegmentBeyond(pos); if(it != segments.begin()) { auto prev_it = it - 1; auto d = pos - prev_it->pos_begin; // distance from segment start (>=0) if(d < prev_it->entries.size()) { // replace value prev_it->entries[d] = std::move(value); return; } if(d == prev_it->entries.size()) { // extend existing segment prev_it->entries.insert(prev_it->entries.end(), std::move(value)); return; } } // make new segment segments.insert(it, { pos, { std::move(value) } }); } template void RowCache::insert (size_t pos, T && value) { auto it = getSegmentBeyond(pos); if(it != segments.begin()) { auto prev_it = it - 1; auto d = pos - prev_it->pos_begin; // distance from segment start (>=0) if(d <= prev_it->entries.size()) { // can extend existing segment prev_it->entries.insert(prev_it->entries.begin() + d, std::move(value)); goto push; } } // make new segment it = segments.insert(it, { pos, { std::move(value) } }) + 1; push: // push back all later segments std::for_each(it, segments.end(), [](Segment &s){ s.pos_begin++; }); } template void RowCache::erase (size_t pos) { auto it = getSegmentBeyond(pos); // if previous segment actually contains pos, shorten it if(it != segments.begin()) { auto prev_it = it - 1; auto d = pos - prev_it->pos_begin; // distance from segment start (>=0) if(d < prev_it->entries.size()) { prev_it->entries.erase(prev_it->entries.begin() + d); if(prev_it->entries.empty()) { it = segments.erase(prev_it); } } } // pull forward all later segments std::for_each(it, segments.end(), [](Segment &s){ s.pos_begin--; }); } template void RowCache::clear () { segments.clear(); } template void RowCache::smallestNonAvailableRange (size_t & row_begin, size_t & row_end) const { if(row_end < row_begin) throw std::invalid_argument("end must be >= begin"); while(row_begin < row_end) { auto it = getSegmentContaining(row_begin); if(it == segments.end()) break; row_begin = it->pos_end(); } while(row_end > row_begin) { auto it = getSegmentContaining(row_end - 1); if(it == segments.end()) break; row_end = it->pos_begin; } if(row_end < row_begin) row_end = row_begin; } #endif // SEGMENTING_CACHE_H sqlitebrowser-sqlitebrowser-5733cb7/src/RowLoader.cpp000066400000000000000000000206531463772530400230730ustar00rootroot00000000000000#include #include "RowLoader.h" #include "sqlite.h" namespace { QString rtrimChar(const QString& s, QChar c) { QString r = s.trimmed(); while(r.endsWith(c)) r.chop(1); return r; } } // anon ns RowLoader::RowLoader (std::function(void)> db_getter_, std::function statement_logger_, std::vector & headers_, std::mutex & cache_mutex_, Cache & cache_data_ ) : db_getter(db_getter_), statement_logger(statement_logger_) , headers(headers_) , cache_mutex(cache_mutex_), cache_data(cache_data_) , query() , countQuery() , first_chunk_loaded(false) , num_tasks(0) , pDb(nullptr) , stop_requested(false) , current_task(nullptr) , next_task(nullptr) { } void RowLoader::setQuery (const QString& new_query, const QString& newCountQuery) { std::lock_guard lk(m); query = new_query; first_chunk_loaded = false; if (newCountQuery.isEmpty()) // If it is a normal query - hopefully starting with SELECT - just do a COUNT on it and return the results countQuery = QString("SELECT COUNT(*) FROM (%1);").arg(rtrimChar(query, ';')); else countQuery = newCountQuery; } void RowLoader::triggerRowCountDetermination(int token) { std::unique_lock lk(m); num_tasks++; nosync_ensureDbAccess(); // do a count query to get the full row count in a fast manner row_counter = std::async(std::launch::async, [this, token]() { auto nrows = countRows(); if(nrows >= 0) emit rowCountComplete(token, nrows); std::lock_guard lk2(m); nosync_taskDone(); }); } void RowLoader::nosync_ensureDbAccess () { if(!pDb) pDb = db_getter(); } std::shared_ptr RowLoader::getDb () const { std::lock_guard lk(m); return pDb; } int RowLoader::countRows() const { int retval = -1; // Use a different approach of determining the row count when a EXPLAIN or a PRAGMA statement is used because a COUNT fails on these queries if(query.startsWith("EXPLAIN", Qt::CaseInsensitive) || query.startsWith("PRAGMA", Qt::CaseInsensitive)) { // So just execute the statement as it is and fetch all results counting the rows sqlite3_stmt* stmt; QByteArray utf8Query = query.toUtf8(); if(sqlite3_prepare_v2(pDb.get(), utf8Query, utf8Query.size(), &stmt, nullptr) == SQLITE_OK) { retval = 0; while(sqlite3_step(stmt) == SQLITE_ROW) retval++; sqlite3_finalize(stmt); return retval; } } else { statement_logger(countQuery); QByteArray utf8Query = countQuery.toUtf8(); sqlite3_stmt* stmt; if(sqlite3_prepare_v2(pDb.get(), utf8Query, utf8Query.size(), &stmt, nullptr) == SQLITE_OK) { if(sqlite3_step(stmt) == SQLITE_ROW) retval = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); } else { qWarning() << "Count query failed: " << countQuery; } } return retval; } void RowLoader::triggerFetch (int token, size_t row_begin, size_t row_end) { std::unique_lock lk(m); if(pDb) { if(!row_counter.valid() || row_counter.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { // only if row count is complete, we can safely interrupt SQLite to speed up cancellation sqlite3_interrupt(pDb.get()); } } if(current_task) current_task->cancel = true; nosync_ensureDbAccess(); // (forget a possibly already existing "next task") next_task.reset(new Task{ *this, token, row_begin, row_end }); lk.unlock(); cv.notify_all(); } void RowLoader::nosync_taskDone() { if(--num_tasks == 0) { pDb = nullptr; } } void RowLoader::cancel () { std::unique_lock lk(m); if(pDb) sqlite3_interrupt(pDb.get()); if(current_task) current_task->cancel = true; next_task = nullptr; cv.notify_all(); } void RowLoader::stop () { cancel(); std::unique_lock lk(m); stop_requested = true; cv.notify_all(); } bool RowLoader::readingData () const { std::unique_lock lk(m); return pDb != nullptr; } void RowLoader::waitUntilIdle () const { if(row_counter.valid()) row_counter.wait(); std::unique_lock lk(m); cv.wait(lk, [this](){ return stop_requested || (!current_task && !next_task); }); } void RowLoader::run () { for(;;) { std::unique_lock lk(m); current_task = nullptr; cv.notify_all(); cv.wait(lk, [this](){ return stop_requested || next_task; }); if(stop_requested) return; current_task = std::move(next_task); lk.unlock(); process(*current_task); } } void RowLoader::process (Task & t) { QString sLimitQuery; if(query.startsWith("PRAGMA", Qt::CaseInsensitive) || query.startsWith("EXPLAIN", Qt::CaseInsensitive) || // With RETURNING keyword DELETE,INSERT,UPDATE can return rows // https://www.sqlite.org/lang_returning.html query.startsWith("DELETE", Qt::CaseInsensitive) || query.startsWith("INSERT", Qt::CaseInsensitive) || query.startsWith("UPDATE", Qt::CaseInsensitive)) { sLimitQuery = query; } else { // Remove trailing trailing semicolon QString queryTemp = rtrimChar(query, ';'); // If the query ends with a LIMIT statement or contains a compound operator take it as it is, // if not append our own LIMIT part for lazy population. The compound operator test is a very // weak check and does not detect whether the keyword is in a string or similar. This means // that lazy population is disabled for more queries than necessary. We should fix this once // we have a parser for SELECT statements but until then it is better to disable lazy population // for more statements than required instead of failing to run some statements entirely. if(queryTemp.contains(QRegExp("LIMIT\\s+.+\\s*((,|\\b(OFFSET)\\b)\\s*.+\\s*)?$", Qt::CaseInsensitive)) || queryTemp.contains(QRegExp("\\s(UNION)|(INTERSECT)|(EXCEPT)\\s", Qt::CaseInsensitive))) sLimitQuery = queryTemp; else sLimitQuery = queryTemp + QString(" LIMIT %1 OFFSET %2;").arg(t.row_end-t.row_begin).arg(t.row_begin); } statement_logger(sLimitQuery); QByteArray utf8Query = sLimitQuery.toUtf8(); sqlite3_stmt *stmt; auto row = t.row_begin; if(sqlite3_prepare_v2(pDb.get(), utf8Query, utf8Query.size(), &stmt, nullptr) == SQLITE_OK) { while(!t.cancel && sqlite3_step(stmt) == SQLITE_ROW) { size_t num_columns = static_cast(sqlite3_data_count(stmt)); // Construct a new row object with the right number of columns Cache::value_type rowdata(num_columns); for(size_t i=0;i(i)) != SQLITE_NULL) { int bytes = sqlite3_column_bytes(stmt, static_cast(i)); if(bytes) rowdata[i] = QByteArray(static_cast(sqlite3_column_blob(stmt, static_cast(i))), bytes); else rowdata[i] = ""; } } std::lock_guard lk(cache_mutex); cache_data.set(row++, std::move(rowdata)); } sqlite3_finalize(stmt); // Query the total row count if and only if: // - this is the first batch of data we load for this query // - we got exactly the number of rows back we queried (which indicates there might be more rows) // If there is no need to query the row count this means the number of rows we just got is the total row count. if(!first_chunk_loaded) { first_chunk_loaded = true; if(row == t.row_end) triggerRowCountDetermination(t.token); else emit rowCountComplete(t.token, static_cast(row-t.row_begin)); } } emit fetched(t.token, t.row_begin, row); } sqlitebrowser-sqlitebrowser-5733cb7/src/RowLoader.h000066400000000000000000000061301463772530400225320ustar00rootroot00000000000000#ifndef ROW_LOADER_H #define ROW_LOADER_H #include #include #include #include #include #include #include #include #include #include "RowCache.h" struct sqlite3; class RowLoader : public QThread { Q_OBJECT void run() override; public: using Cache = RowCache>; /// set up worker thread to handle row loading explicit RowLoader ( std::function(void)> db_getter, std::function statement_logger, std::vector & headers, std::mutex & cache_mutex, Cache & cache_data ); void setQuery (const QString& new_query, const QString& newCountQuery = QString()); void triggerRowCountDetermination (int token); /// trigger asynchronous reading of specified row range, /// cancelling previous tasks; 'row_end' is exclusive; \param /// token is eventually returned through the 'fetched' /// signal. depending on how and when tasks are cancelled, not /// every triggerFetch() will result in a 'fetched' signal, or the /// 'fetched' signal may be for a narrower row range. void triggerFetch (int token, size_t row_begin, size_t row_end); /// cancel everything void cancel (); /// cancel everything and terminate worker thread void stop (); /// currently reading any data, or anything in "queue"? bool readingData () const; /// wait until not reading any data void waitUntilIdle () const; /// get current database - note that the worker thread might be /// working on it, too... \returns current db, or nullptr. std::shared_ptr getDb () const; signals: void fetched(int token, size_t row_begin, size_t row_end); void rowCountComplete(int token, int num_rows); private: const std::function()> db_getter; const std::function statement_logger; std::vector & headers; std::mutex & cache_mutex; Cache & cache_data; mutable std::mutex m; mutable std::condition_variable cv; QString query; QString countQuery; mutable std::future row_counter; bool first_chunk_loaded; size_t num_tasks; std::shared_ptr pDb; //< exclusive access while held... bool stop_requested; struct Task { RowLoader & row_loader; int token; size_t row_begin; size_t row_end; //< exclusive std::atomic cancel; Task(RowLoader & row_loader_, int t, size_t a, size_t b) : row_loader(row_loader_), token(t), row_begin(a), row_end(b), cancel(false) { row_loader.num_tasks++; } ~Task() { // (... mutex being held ...) row_loader.nosync_taskDone(); } }; std::unique_ptr current_task; std::unique_ptr next_task; int countRows () const; void process (Task &); void nosync_ensureDbAccess (); void nosync_taskDone (); }; #endif // ROW_LOADER_H sqlitebrowser-sqlitebrowser-5733cb7/src/RunSql.cpp000066400000000000000000000343121463772530400224160ustar00rootroot00000000000000#include "RunSql.h" #include "sqlite.h" #include "sqlitedb.h" #include "Data.h" #include #include #include RunSql::RunSql(DBBrowserDB& _db, QString query, int execute_from_position, int _execute_to_position, bool _interrupt_after_statements) : db(_db), may_continue_with_execution(true), interrupt_after_statements(_interrupt_after_statements), execute_current_position(execute_from_position), execute_to_position(_execute_to_position), structure_updated(false), savepoint_created(false), was_dirty(db.getDirty()), modified(false) { // Get lock to set up everything std::unique_lock lk(m); // Cancel if there is nothing to execute if(query.trimmed().isEmpty() || query.trimmed() == ";" || execute_from_position == execute_to_position || query.mid(execute_from_position, execute_to_position-execute_from_position).trimmed().isEmpty() || query.mid(execute_from_position, execute_to_position-execute_from_position).trimmed() == ";") return; // All replacements in the query should be made by the same amount of characters, so the positions in the file // for error indicators and line and column logs are not displaced. // Whitespace and comments are discarded by SQLite, so it is better to just let it ignore them. query = query.replace(QRegExp("^(\\s*)BEGIN TRANSACTION;", Qt::CaseInsensitive), "\\1 "); query = query.replace(QRegExp("COMMIT;(\\s*)$", Qt::CaseInsensitive), " \\1"); // Convert query to byte array which we will use from now on, starting from the determined start position and // until the end of the SQL code. By doing so we go further than the determined end position because in Line // mode the last statement might go beyond that point. queries_left_to_execute = query.toUtf8().mid(execute_from_position); } void RunSql::run() { // Execute statement by statement for(;;) { if(!executeNextStatement()) break; } // Execution finished // If the DB structure was changed by some command in this SQL script, send a signal if(structure_updated) emit structureUpdated(); } void RunSql::startNextStatement() { std::unique_lock lk(m); may_continue_with_execution = true; cv.notify_one(); } void RunSql::stop() { std::unique_lock lk(m); stopExecution(); if(pDb) sqlite3_interrupt(pDb.get()); may_continue_with_execution = true; cv.notify_all(); } bool RunSql::executeNextStatement() { std::unique_lock lk(m); // Is there anything left to do? if(queries_left_to_execute.isEmpty()) return false; // Start execution timer auto time_start = std::chrono::high_resolution_clock::now(); // Prepare next statement const char* tail = queries_left_to_execute.data(); int tail_length = queries_left_to_execute.length(); const char* qbegin = tail; acquireDbAccess(); sqlite3_stmt* vm; int sql3status = sqlite3_prepare_v2(pDb.get(), tail, tail_length, &vm, &tail); QString executed_query = QString::fromUtf8(qbegin, static_cast(tail - qbegin)).trimmed(); int tail_length_before = tail_length; tail_length -= static_cast(tail - qbegin); int end_of_current_statement_position = execute_current_position + tail_length_before - tail_length; queries_left_to_execute = QByteArray(tail); // Save remaining statements lk.unlock(); // Measure time up until here. We do that to not include the time spent on opening any message boxes or creating savepoints // because both are not part of the actual query execution. auto time_end_prepare = std::chrono::high_resolution_clock::now(); auto time_for_prepare_in_ms = std::chrono::duration_cast(time_end_prepare - time_start); // Execute prepared statement QString error; if (sql3status == SQLITE_OK) { // What type of query was this? StatementType query_type = getQueryType(executed_query); // Check whether the DB structure will be changed by actually running this statement if(!structure_updated && (query_type == AlterStatement || query_type == CreateStatement || query_type == DropStatement || query_type == RollbackStatement || query_type == AttachStatement || query_type == DetachStatement)) structure_updated = true; // Check whether this is trying to set a pragma or to vacuum the database if((query_type == PragmaStatement && executed_query.contains('=') && !executed_query.contains("defer_foreign_keys", Qt::CaseInsensitive)) || query_type == VacuumStatement) { // We're trying to set a pragma. If the database has been modified it needs to be committed first. We'll need to ask the // user about that if(db.getDirty()) { // Ask user, then check if we should abort execution or continue with it. We depend on a BlockingQueueConnection here which makes sure to // block this worker thread until the slot function in the main thread is completed and could tell us about its decision. emit confirmSaveBeforePragmaOrVacuum(); if(!queries_left_to_execute.isEmpty()) { // Commit all changes db.releaseAllSavepoints(); } else { // Abort emit statementErrored(tr("Execution aborted by user"), execute_current_position, execute_current_position + (query_type == PragmaStatement ? 5 : 6)); return false; } } } else { // We're not trying to set a pragma or to vacuum the database. In this case make sure a savepoint has been created in order to avoid committing // all changes to the database immediately. Don't set more than one savepoint. if(!savepoint_created && !db.readOnly()) { // We have to start a transaction before we create the prepared statement otherwise every executed // statement will get committed after the prepared statement gets finalized releaseDbAccess(); // Allow later undoing of this single execution with a non-unique savepoint. db.setUndoSavepoint(); // And set the unique savepoint (if not already set) for the full current transaction. db.setSavepoint(); acquireDbAccess(); savepoint_created = true; } } // Start measuring time from here again time_start = std::chrono::high_resolution_clock::now(); // Check if this statement returned any data. We skip this check if this is an ALTER TABLE statement which, for some reason, are reported to return one column. if(query_type != AlterStatement && sqlite3_column_count(vm)) { // It did. So it is definitely some SELECT statement or similar and we don't need to actually execute it here sql3status = SQLITE_ROW; } else { // It did not. So it's probably some modifying SQL statement and we want to execute it here. If for some reason // it turns out to return data after all, we just change the status sql3status = sqlite3_step(vm); // SQLite returns SQLITE_DONE when a valid SELECT statement was executed but returned no results. To run into the branch that updates // the status message and the table view anyway manipulate the status value here. This is also done for PRAGMA statements as they (sometimes) // return rows just like SELECT statements, too. if((query_type == SelectStatement || query_type == PragmaStatement) && sql3status == SQLITE_DONE) sql3status = SQLITE_ROW; } // Destroy statement sqlite3_finalize(vm); switch(sql3status) { case SQLITE_ROW: { // If we get here, the SQL statement returns some sort of data. So hand it over to the model for display. Don't set the modified flag // because statements that display data don't change data as well, except if the statement are one of INSERT/UPDATE/DELETE that could // return datas with the RETURNING keyword. releaseDbAccess(); lk.lock(); // Set the modified flag to true if the statement was one of INSERT/UPDATE/DELETE triggered by a possible RETURNING keyword. if (query_type == InsertStatement || query_type == UpdateStatement || query_type == DeleteStatement) modified = true; may_continue_with_execution = false; auto time_end = std::chrono::high_resolution_clock::now(); auto time_in_ms = std::chrono::duration_cast(time_end - time_start) + time_for_prepare_in_ms; emit statementReturnsRows(executed_query, execute_current_position, end_of_current_statement_position, time_in_ms.count()); // Make sure the next statement isn't executed until we're told to do so if(interrupt_after_statements) cv.wait(lk, [this](){ return may_continue_with_execution; }); lk.unlock(); break; } case SQLITE_DONE: case SQLITE_OK: { // If we get here, the SQL statement doesn't return data and just executes. Don't run it again because it has already been executed. // But do set the modified flag because statements that don't return data, often modify the database. QString stmtHasChangedDatabase; if(query_type == InsertStatement || query_type == UpdateStatement || query_type == DeleteStatement) stmtHasChangedDatabase = tr(", %1 rows affected").arg(sqlite3_changes(pDb.get())); releaseDbAccess(); lk.lock(); // Attach/Detach statements don't modify the original database if(query_type != StatementType::AttachStatement && query_type != StatementType::DetachStatement) modified = true; may_continue_with_execution = false; auto time_end = std::chrono::high_resolution_clock::now(); auto time_in_ms = std::chrono::duration_cast(time_end - time_start) + time_for_prepare_in_ms; emit statementExecuted(tr("query executed successfully. Took %1ms%2").arg(time_in_ms.count()).arg(stmtHasChangedDatabase), execute_current_position, end_of_current_statement_position); // Make sure the next statement isn't executed until we're told to do so if(interrupt_after_statements) cv.wait(lk, [this](){ return may_continue_with_execution; }); lk.unlock(); break; } case SQLITE_MISUSE: break; default: error = QString::fromUtf8(sqlite3_errmsg(pDb.get())); } } else { error = QString::fromUtf8(sqlite3_errmsg(pDb.get())); } // Release the database lk.lock(); releaseDbAccess(); // Release savepoints now if they weren't needed. We need to do this here because there are some rare cases where the next statement might // be affected by what is only a temporary and unnecessary savepoint. For example in this case: // ATTACH 'xxx' AS 'db2' // SELECT * FROM db2.xy; -- Savepoint created here // DETACH db2; -- Savepoint makes this statement fail // // Note that a revert would also work for most cases, but we have to take into account that there are SELECT queries running functions // which might have side effects. In those cases, it is better to err in the safe side by releasing the savepoint and immediately // saving that side effect, than preventing the user to use those functions in our application. // Examples of those queries can be found in the Spatialite extension: // SELECT InitSpatialMetaData() // SELECT RenameTable('main','Table1','Table2') if(!modified && !was_dirty && savepoint_created) { db.releaseSavepoint(); db.releaseUndoSavepoint(); savepoint_created = false; } if(!error.isEmpty()) { emit statementErrored(error, execute_current_position, end_of_current_statement_position); stopExecution(); return false; } // Update the start position for the next statement and check if we are at // the end of the part we want to execute. If so, stop the execution now. execute_current_position = end_of_current_statement_position; if(execute_current_position >= execute_to_position) { stopExecution(); return false; } return true; } void RunSql::stopExecution() { queries_left_to_execute.clear(); } RunSql::StatementType RunSql::getQueryType(const QString& query) { // Helper function for getting the type of a given query if(query.startsWith("SELECT", Qt::CaseInsensitive)) return SelectStatement; if(query.startsWith("ALTER", Qt::CaseInsensitive)) return AlterStatement; if(query.startsWith("DROP", Qt::CaseInsensitive)) return DropStatement; if(query.startsWith("ROLLBACK", Qt::CaseInsensitive)) return RollbackStatement; if(query.startsWith("PRAGMA", Qt::CaseInsensitive)) return PragmaStatement; if(query.startsWith("VACUUM", Qt::CaseInsensitive)) return VacuumStatement; if(query.startsWith("INSERT", Qt::CaseInsensitive)) return InsertStatement; if(query.startsWith("UPDATE", Qt::CaseInsensitive)) return UpdateStatement; if(query.startsWith("DELETE", Qt::CaseInsensitive)) return DeleteStatement; if(query.startsWith("CREATE", Qt::CaseInsensitive)) return CreateStatement; if(query.startsWith("ATTACH", Qt::CaseInsensitive)) return AttachStatement; if(query.startsWith("DETACH", Qt::CaseInsensitive)) return DetachStatement; return OtherStatement; } void RunSql::acquireDbAccess() { pDb = db.get(tr("executing query"), true); } void RunSql::releaseDbAccess() { pDb = nullptr; } sqlitebrowser-sqlitebrowser-5733cb7/src/RunSql.h000066400000000000000000000046221463772530400220640ustar00rootroot00000000000000#ifndef RUNSQL_H #define RUNSQL_H #include #include #include #include class DBBrowserDB; struct sqlite3; class RunSql : public QThread { Q_OBJECT void run() override; public: /** * @param db Reference to the database connection to execute the statements with * @param query The query to execute * @param execute_from_position The index of the first character to execute in the query parameter * @param execute_to_position The index of the last character to execute in the query parameter (see exact_execute_to_position) * @param interrupt_after_statements Set to true to stop execution after each statement until startNextStatement() is called. Set to false to execute all statements * in one go. */ RunSql(DBBrowserDB& db, QString query, int execute_from_position, int execute_to_position, bool interrupt_after_statements = false); ~RunSql() override = default; enum StatementType { SelectStatement, AlterStatement, DropStatement, RollbackStatement, PragmaStatement, VacuumStatement, InsertStatement, UpdateStatement, DeleteStatement, CreateStatement, AttachStatement, DetachStatement, OtherStatement, }; static StatementType getQueryType(const QString& query); void startNextStatement(); void stop(); signals: void statementErrored(QString message, int from_position, int to_position); void statementExecuted(QString message, int from_position, int to_position); void statementReturnsRows(QString query, int from_position, int to_position, qint64 time_in_ms); void structureUpdated(); /** * This signal must be connected with a Qt::BlockingQueuedConnection in order to work as expected! */ void confirmSaveBeforePragmaOrVacuum(); private: DBBrowserDB& db; std::shared_ptr pDb; mutable std::mutex m; mutable std::condition_variable cv; bool may_continue_with_execution; bool interrupt_after_statements; QByteArray queries_left_to_execute; int execute_current_position; int execute_to_position; bool structure_updated; bool savepoint_created; bool was_dirty; bool modified; void stopExecution(); bool executeNextStatement(); void acquireDbAccess(); void releaseDbAccess(); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/SelectItemsPopup.cpp000066400000000000000000000076031463772530400244420ustar00rootroot00000000000000#include "SelectItemsPopup.h" #include "ui_SelectItemsPopup.h" #include SelectItemsPopup::SelectItemsPopup(const std::vector& available, const std::vector& selected, QWidget* parent) : QDialog(parent), ui(new Ui::SelectItemsPopup) { ui->setupUi(this); setWindowFlags(Qt::Popup); // Load initial items for(const auto& s : available) { if(std::find(selected.begin(), selected.end(), s) == selected.end()) new QListWidgetItem(QString::fromStdString(s), ui->listAvailable); } for(const auto& s : selected) new QListWidgetItem(QString::fromStdString(s), ui->listSelected); } SelectItemsPopup::~SelectItemsPopup() { delete ui; } std::vector SelectItemsPopup::selectedItems() const { std::vector result; for(int i=0;ilistSelected->count();i++) result.push_back(ui->listSelected->item(i)->text().toStdString()); return result; } void SelectItemsPopup::selectItem(const QModelIndex& idx) { // Get currently selected iitem if none was provided QListWidgetItem* item; if(idx.isValid()) item = ui->listAvailable->item(idx.row()); else item = ui->listAvailable->currentItem(); if(!item) return; // Add it to the selected items list new QListWidgetItem(item->text(), ui->listSelected); // Remove it from available items list delete item; } void SelectItemsPopup::unselectItem(const QModelIndex& idx) { // Get currently selected iitem if none was provided QListWidgetItem* item; if(idx.isValid()) item = ui->listSelected->item(idx.row()); else item = ui->listSelected->currentItem(); if(!item) return; // Add it to the available items list new QListWidgetItem(item->text(), ui->listAvailable); // Remove it from selected items list delete item; } void SelectItemsPopup::resizeEvent(QResizeEvent*) { // We modify the shape of the dialog to add an arrow shaped edge. See the ascii art image below for details. The edges // are numbered, their order is the same as in the polygon definition. /* /3\ / \ 1---2 4--------5 | | | | 7------------------6 */ const int arrow_height = ui->spacer->geometry().height(); const int arrow_width = arrow_height * 3; const int arrow_position_div = 5; QPolygon poly; poly << QPoint(rect().x(), rect().y() + arrow_height) << QPoint(rect().x() + rect().width() / arrow_position_div - arrow_width / 2, rect().y() + arrow_height) << QPoint(rect().x() + rect().width() / arrow_position_div, rect().y()) << QPoint(rect().x() + rect().width() / arrow_position_div + arrow_width / 2, rect().y() + arrow_height) << QPoint(rect().x() + rect().width(), rect().y() + arrow_height) << QPoint(rect().x() + rect().width(), rect().y() + rect().height()) << QPoint(rect().x(), rect().y() + rect().height()); setMask(QRegion(poly)); } void SelectItemsPopup::buttonBoxClicked(QAbstractButton* button) { if(button == ui->buttonBox->button(QDialogButtonBox::Apply)) accept(); } void SelectItemsPopup::moveItemUp() { moveCurrentItem(false); } void SelectItemsPopup::moveItemDown() { moveCurrentItem(true); } void SelectItemsPopup::moveCurrentItem(bool down) { // Get current row number and calculate row number after the movement. Check the values int currentRow = ui->listSelected->currentRow(); if(currentRow == -1) return; int newRow = currentRow + (down ? 1 : -1); if(newRow < 0) return; if(newRow >= ui->listSelected->count()) return; // Swap items ui->listSelected->insertItem(newRow, ui->listSelected->takeItem(currentRow)); // Select old item at new position ui->listSelected->setCurrentRow(newRow); } sqlitebrowser-sqlitebrowser-5733cb7/src/SelectItemsPopup.h000066400000000000000000000015621463772530400241050ustar00rootroot00000000000000#ifndef SELECTITEMS_H #define SELECTITEMS_H #include #include #include #include class QAbstractButton; namespace Ui { class SelectItemsPopup; } class SelectItemsPopup : public QDialog { Q_OBJECT public: explicit SelectItemsPopup(const std::vector& available, const std::vector& selected = {}, QWidget* parent = nullptr); ~SelectItemsPopup() override; std::vector selectedItems() const; private slots: void buttonBoxClicked(QAbstractButton* button); void selectItem(const QModelIndex& idx = QModelIndex()); void unselectItem(const QModelIndex& idx = QModelIndex()); void moveItemUp(); void moveItemDown(); protected: void resizeEvent(QResizeEvent* ev) override; private: Ui::SelectItemsPopup* ui; void moveCurrentItem(bool down); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/SelectItemsPopup.ui000066400000000000000000000202131463772530400242650ustar00rootroot00000000000000 SelectItemsPopup 0 0 537 290 Qt::Vertical 0 15 A&vailable listAvailable QAbstractItemView::NoEditTriggers false true Qt::Vertical 20 40 Qt::RightArrow Qt::LeftArrow Qt::Vertical 20 40 Sele&cted listSelected QAbstractItemView::NoEditTriggers false QAbstractItemView::InternalMove true Qt::Vertical 20 40 Qt::UpArrow Qt::DownArrow Qt::Vertical 20 40 QDialogButtonBox::Apply|QDialogButtonBox::Cancel listAvailable listSelected buttonSelect buttonUnselect buttonSelect clicked() SelectItemsPopup selectItem() 263 115 2 203 buttonUnselect clicked() SelectItemsPopup unselectItem() 257 159 515 186 listAvailable doubleClicked(QModelIndex) SelectItemsPopup selectItem(QModelIndex) 124 45 115 0 listSelected doubleClicked(QModelIndex) SelectItemsPopup unselectItem(QModelIndex) 377 96 383 4 buttonBox rejected() SelectItemsPopup reject() 262 258 262 140 buttonBox clicked(QAbstractButton*) SelectItemsPopup buttonBoxClicked(QAbstractButton*) 262 258 262 140 buttonDown clicked() SelectItemsPopup moveItemDown() 513 153 268 144 buttonUp clicked() SelectItemsPopup moveItemUp() 513 124 268 144 selectItem(QModelIndex) unselectItem(QModelIndex) selectItem() unselectItem() buttonBoxClicked(QAbstractButton*) moveItemUp() moveItemDown() sqlitebrowser-sqlitebrowser-5733cb7/src/Settings.cpp000066400000000000000000000524121463772530400227730ustar00rootroot00000000000000#include "Settings.h" #include #include #include #include #include #include #include #include #include QString Settings::userSettingsFile; QSettings* Settings::settings; std::unordered_map Settings::m_hCache; int Settings::m_defaultFontSize; static bool ends_with(const std::string& str, const std::string& with) { return str.rfind(with) == str.size() - with.size(); } void Settings::setUserSettingsFile(const QString& userSettingsFileArg) { userSettingsFile = userSettingsFileArg; } bool Settings::isVaildSettingsFile(const QString& userSettingsFile) { /* Variable that stores whether or not the settings file requested by the user is a normal settings file If the file does not exist and is newly created, the if statement below is not executed, so the default value is set to true */ bool isNormalUserSettingsFile = true; // Code that verifies that the settings file requested by the user is a normal settings file if(userSettingsFile != nullptr) { QFile *file = new QFile; file->setFileName(userSettingsFile); if(file->open(QIODevice::ReadOnly | QIODevice::Text)) { if(file->exists() && QString::compare(QString("[%General]\n"), file->readLine(), Qt::CaseInsensitive) != 0) isNormalUserSettingsFile = false; } file->close(); } return isNormalUserSettingsFile; } void Settings::setSettingsObject() { // If an object has already been created, it is terminated to reduce overhead if(settings) return; const bool isNormalUserSettingsFile = isVaildSettingsFile(userSettingsFile); if(userSettingsFile == nullptr) { settings = new QSettings(QCoreApplication::organizationName(), QCoreApplication::organizationName()); } else { if(isNormalUserSettingsFile) { settings = new QSettings(userSettingsFile, QSettings::IniFormat); // Code to verify that the user does not have access to the requested settings file if(settings->status() == QSettings::AccessError) { qWarning() << qPrintable("The given settings file can NOT access. Please check the permission for the file."); qWarning() << qPrintable("So, the -S/--settings option is ignored."); // Since you do not have permission to the file, delete the existing assignment and assign the standard delete settings; settings = new QSettings(QCoreApplication::organizationName(), QCoreApplication::organizationName()); } } else { qWarning() << qPrintable("The given settings file is not a normal settings file. Please check again."); qWarning() << qPrintable("So, the -S/--settings option is ignored."); settings = new QSettings(QCoreApplication::organizationName(), QCoreApplication::organizationName()); } } } QVariant Settings::getValue(const std::string& group, const std::string& name) { // Have a look in the cache first auto cacheIndex = m_hCache.find(group + name); if(cacheIndex != m_hCache.end()) { return cacheIndex->second; } else { // Nothing found in the cache, so get the value from the settings file or get the default value if there is no value set yet setSettingsObject(); QVariant value = settings->value(QString::fromStdString(group + "/" + name), getDefaultValue(group, name)); // Store this value in the cache for further usage and return it afterwards m_hCache.insert({group + name, value}); return value; } } void Settings::setValue(const std::string& group, const std::string& name, const QVariant& value, bool save_to_disk) { // Sometime the value has to be saved for the current session only but get discarded when the application exits. // In order to achieve this this flag can be set which disables the save to disk mechanism and only leaves the save to cache part active. if(save_to_disk) { setSettingsObject(); // Set the group and save the given value settings->beginGroup(QString::fromStdString(group)); settings->setValue(QString::fromStdString(name), value); settings->endGroup(); } // Also change it in the cache m_hCache[group + name] = value; } QVariant Settings::getDefaultValue(const std::string& group, const std::string& name) { // db/defaultencoding? if(group == "db" && name == "defaultencoding") return "UTF-8"; // db/savedefaultlocation? if(group == "db" && name == "savedefaultlocation") return 2; // db/defaultlocation? if(group == "db" && name == "defaultlocation") return QDir::homePath(); // db/lastlocation? if(group == "db" && name == "lastlocation") return getValue("db", "defaultlocation"); // db/hideschemalinebreaks? if(group == "db" && name == "hideschemalinebreaks") return true; // db/foreignkeys? if(group == "db" && name == "foreignkeys") return true; // db/prefetchsize? if(group == "db" && name == "prefetchsize") return 50000U; // db/defaultsqltext? if(group == "db" && name == "defaultsqltext") return QString(); // db/fontsize? if(group == "db" && name == "fontsize") return 10; // exportcsv/firstrowheader? if(group == "exportcsv" && name == "firstrowheader") return true; // exportcsv/separator? if(group == "exportcsv" && name == "separator") return ','; // exportcsv/quotecharacter? if(group == "exportcsv" && name == "quotecharacter") return '"'; // importcsv group? if(group == "importcsv") { if(name == "firstrowheader") return false; if(name == "trimfields") return true; if(name == "separatetables") return false; if(name == "separator") return ','; if(name == "quotecharacter") return '"'; if(name == "encoding") return "UTF-8"; if(name == "localconventions") return false; } // exportsql group? if(group == "exportsql") { if(name == "insertcolnames" || name == "insertmultiple" || name == "keeporiginal") return false; if(name == "oldschema") return 0; } // newline character if (group == "exportcsv" && name == "newlinecharacters") #ifdef Q_OS_WIN return "\r\n"; #else return "\n"; #endif // exportjson/prettyprint? if(group == "exportjson" && name == "prettyprint") return true; // MainWindow/geometry? if(group == "MainWindow" && name == "geometry") return QString(); // MainWindow/windowState? if(group == "MainWindow" && name == "windowState") return QString(); // MainWindow/openTabs? if(group == "MainWindow" && name == "openTabs") return QString(); // SQLLogDock/Log? if(group == "SQLLogDock" && name == "Log") return "Application"; // General/recentFileList? if(group == "General" && name == "recentFileList") return QStringList(); // General/maxRecentFiles? if(group == "General" && name == "maxRecentFiles") return 5; // General/language? if(group == "General" && name == "language") return QLocale::system().name(); // General/appStyle if(group == "General" && name == "appStyle") return static_cast(FollowDesktopStyle); // General/toolbarStyle if(group == "General" && name == "toolbarStyle") return static_cast(Qt::ToolButtonTextBesideIcon); // General/toolbarStyleStructure if(group == "General" && name == "toolbarStyleStructure") return static_cast(Qt::ToolButtonTextBesideIcon); // General/toolbarStyleBrowse if(group == "General" && name == "toolbarStyleBrowse") return static_cast(Qt::ToolButtonIconOnly); // General/toolbarStyleSql if(group == "General" && name == "toolbarStyleSql") return static_cast(Qt::ToolButtonIconOnly); // General/toolbarStyleEditCell if(group == "General" && name == "toolbarStyleEditCell") return static_cast(Qt::ToolButtonIconOnly); if(group == "General" && name == "DBFileExtensions") return QObject::tr("SQLite database files (*.db *.sqlite *.sqlite3 *.db3)"); // General/fontsize if(group == "General" && name == "fontsize") return m_defaultFontSize; // General/promptsqltabsinnewproject if(group == "General" && name == "promptsqltabsinnewproject") return true; // checkversion group? if(group == "checkversion") { if(name == "enabled") return true; if(name == "ignmajor") return 999; if(name == "ignminor" || name == "ignpatch") return 0; } // Data Browser/NULL Fields if(group == "databrowser") { if(name == "font") { QFont font("Monospace"); font.setStyleHint(QFont::TypeWriter); return QFontInfo(font).family(); } if(name == "fontsize") return 10; if(name == "symbol_limit") return 5000; if (name == "rows_limit") return 10'000'000; if(name == "complete_threshold") return 1000; if(name == "image_preview") return false; if(name == "indent_compact") return false; if(name == "auto_switch_mode") return true; if(name == "editor_word_wrap") return true; if(name == "null_text") return "NULL"; if(name == "blob_text") return "BLOB"; if(name == "filter_escape") return "\\"; if(name == "filter_delay") return 200; if(ends_with(name, "colour")) return getDefaultColorValue(group, name, FollowDesktopStyle); } // syntaxhighlighter? if(group == "syntaxhighlighter") { // Bold? Only tables, functions and keywords are bold by default if(ends_with(name, "bold")) return name == "keyword_bold" || name == "table_bold" || name == "function_bold"; // Italic? Nothing by default if(ends_with(name, "italic")) return false; // Underline? Nothing by default if(ends_with(name, "underline")) return false; // Colour? if(ends_with(name, "colour")) return getDefaultColorValue(group, name, FollowDesktopStyle); } // editor/font? if(group == "editor" && name == "font") { QFont font("Monospace"); font.setStyleHint(QFont::TypeWriter); return QFontInfo(font).family(); } // editor/fontsize or log/fontsize? if((group == "editor" || group == "log") && name == "fontsize") #ifdef Q_OS_MAC // Use 12 pt size as the default on macOS return 12; #else return 9; #endif if(group == "editor") { if(name == "tabsize") return 4; if(name == "indentation_use_tabs") return true; } // editor/wrap_lines if(group == "editor" && name == "wrap_lines") return 0; // QsciScintilla::WrapNone // editor/identifier_quotes if(group == "editor" && name == "identifier_quotes") return 0; // sqlb::DoubleQuotes // editor/auto_completion? if(group == "editor" && name == "auto_completion") return true; // editor/upper_keywords? if(group == "editor" && name == "upper_keywords") return true; // editor/error_indicators? if(group == "editor" && name == "error_indicators") return true; // editor/horizontal_tiling? if(group == "editor" && name == "horizontal_tiling") return false; // editor/splitter1_sizes? if(group == "editor" && name == "splitter1_sizes") return QVariant(); // editor/splitter2_sizes? if(group == "editor" && name == "splitter2_sizes") return QVariant(); // editor/close_button_on_tabs? if(group == "editor" && name == "close_button_on_tabs") return true; // extensions/list? if(group == "extensions" && name == "list") return QStringList(); // extensions/disableregex? if(group == "extension" && name == "disableregex") return false; // extensions/enable_load_extension? if(group == "extension" && name == "enable_load_extension") return false; // PlotDock/lineType or pointShape? if(group == "PlotDock") { // QCPGraph::lsLine if(name == "lineType") return 1; // QCPScatterStyle::ssDisk if(name == "pointShape") return 4; } // SchemaDock Drag & drop settings if(group == "SchemaDock") { if(name == "dropSelectQuery") return true; if(name == "dropQualifiedNames") return false; if(name == "dropEnquotedNames") return true; } // Remote settings? if(group == "remote") { // Enable the File → Remote menu by default if(name == "active") return true; // Clone directory if(name == "clonedirectory") #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); #else return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); #endif } // Proxy settings if(group == "proxy") { // Use system settings by default if(name == "type") return "system"; } // Unknown combination of group and name? Return an invalid QVariant! return QVariant(); } QColor Settings::getDefaultColorValue(const std::string& group, const std::string& name, AppStyle style) { // Data Browser/NULL & Binary Fields if(group == "databrowser") { // The switch on style can be removed if the following issue is fixed: // https://github.com/ColinDuquesnoy/QDarkStyleSheet/issues/171 switch (style) { case FollowDesktopStyle : if(name == "null_fg_colour") return QColor(Qt::lightGray).name(); if(name == "null_bg_colour") return QPalette().color(QPalette::Active, QPalette::Base).name(); if(name == "reg_fg_colour") return QPalette().color(QPalette::Active, QPalette::Text).name(); if(name == "reg_bg_colour") return QPalette().color(QPalette::Active, QPalette::Base).name(); if(name == "formatted_fg_colour") return QPalette().color(QPalette::Active, QPalette::Text).name(); if(name == "formatted_bg_colour") return QPalette().color(QPalette::Active, QPalette::AlternateBase).name(); if(name == "bin_fg_colour") return QColor(Qt::lightGray).name(); if(name == "bin_bg_colour") return QPalette().color(QPalette::Active, QPalette::Base).name(); break; case DarkStyle : if(name == "null_fg_colour") return QColor(0x78, 0x78, 0x78); if(name == "null_bg_colour") return QColor(0x19, 0x23, 0x2D); if(name == "reg_fg_colour") return QColor(0xF0, 0xF0, 0xF0); if(name == "reg_bg_colour") return QColor(0x19, 0x23, 0x2D); if(name == "formatted_fg_colour") return QColor(0xF0, 0xF0, 0xF0); if(name == "formatted_bg_colour") return QColor(0x19, 0x23, 0x2D); if(name == "bin_fg_colour") return QColor(0x78, 0x78, 0x78); if(name == "bin_bg_colour") return QColor(0x19, 0x23, 0x2D); break; case LightStyle : if(name == "null_fg_colour" || name == "bin_fg_colour") return QColor(0xA5, 0xA9, 0xAC); if(name == "null_bg_colour" || name == "bin_bg_colour") return QColor(0xFA, 0xFA, 0xFA); if(name == "reg_fg_colour") return QColor(0x00, 0x00, 0x00); if(name == "reg_bg_colour") return QColor(0xFA, 0xFA, 0xFA); if(name == "formatted_fg_colour") return QColor(0x00, 0x00, 0x00); if(name == "formatted_bg_colour") return QColor(0xFA, 0xFA, 0xFA); break; } } // syntaxhighlighter? if(group == "syntaxhighlighter") { // Colour? if(ends_with(name, "colour")) { QColor backgroundColour; QColor foregroundColour; switch (style) { case FollowDesktopStyle : backgroundColour = QPalette().color(QPalette::Active, QPalette::Base); foregroundColour = QPalette().color(QPalette::Active, QPalette::Text); break; case DarkStyle : foregroundColour = QColor(0xF0, 0xF0, 0xF0); backgroundColour = QColor(0x19, 0x23, 0x2D); break; case LightStyle : foregroundColour = QColor(0x00, 0x00, 0x00); backgroundColour = QColor(0xFA, 0xFA, 0xFA); break; } if(name == "foreground_colour") return foregroundColour; else if(name == "background_colour") return backgroundColour; else if(name == "selected_fg_colour") return QPalette().color(QPalette::Active, QPalette::HighlightedText); else if(name == "selected_bg_colour") return QPalette().color(QPalette::Active, QPalette::Highlight); // Detect and provide sensible defaults for dark themes if (backgroundColour.value() < foregroundColour.value()) { if(name == "keyword_colour") return QColor(82, 148, 226); else if(name == "function_colour") return QColor(Qt::yellow); else if(name == "table_colour") return QColor(Qt::cyan); else if(name == "comment_colour") return QColor(Qt::green); else if(name == "identifier_colour") return QColor(221, 160, 221); else if(name == "string_colour") return QColor(Qt::lightGray); else if(name == "currentline_colour") return backgroundColour.lighter(150); else if(name == "highlight_colour") return QColor(79, 148, 205); } else { if(name == "keyword_colour") return QColor(Qt::darkBlue); else if(name == "function_colour") return QColor(Qt::blue); else if(name == "table_colour") return QColor(Qt::darkCyan); else if(name == "comment_colour") return QColor(Qt::darkGreen); else if(name == "identifier_colour") return QColor(Qt::darkMagenta); else if(name == "string_colour") return QColor(Qt::red); else if(name == "currentline_colour") return QColor(236, 236, 245); else if(name == "highlight_colour") return QColor(Qt::cyan); } } } // Unknown combination of group and name? Return an invalid QColor! return QColor(); } void Settings::clearValue(const std::string& group, const std::string& name) { setSettingsObject(); settings->beginGroup(QString::fromStdString(group)); settings->remove(QString::fromStdString(name)); settings->endGroup(); m_hCache.clear(); } void Settings::restoreDefaults () { setSettingsObject(); settings->clear(); m_hCache.clear(); } void Settings::exportSettings(const QString& fileName) { QSettings exportSettings(fileName, QSettings::IniFormat); const QStringList groups = settings->childGroups(); for(const QString& currentGroup : groups) { settings->beginGroup(currentGroup); const QStringList keys = settings->childKeys(); for(const QString& currentKey : keys) { exportSettings.beginGroup(currentGroup); exportSettings.setValue(currentKey, getValue((currentGroup.toStdString()), (currentKey.toStdString()))); exportSettings.endGroup(); } settings->endGroup(); } } bool Settings::importSettings(const QString& fileName) { if(!isVaildSettingsFile(fileName)) return false; QSettings importSettings(fileName, QSettings::IniFormat); const QStringList groups = importSettings.childGroups(); for(const QString& currentGroup : groups) { importSettings.beginGroup(currentGroup); const QStringList keys = importSettings.childKeys(); for(const QString& currentKey : keys) { settings->beginGroup(currentGroup); settings->setValue(currentKey, importSettings.value(currentKey)); settings->endGroup(); } importSettings.endGroup(); } m_hCache.clear(); return true; } void Settings::sync() { settings->sync(); } sqlitebrowser-sqlitebrowser-5733cb7/src/Settings.h000066400000000000000000000037311463772530400224400ustar00rootroot00000000000000#ifndef SETTINGS_H #define SETTINGS_H #include #include #include class Settings { friend class PreferencesDialog; public: enum AppStyle { FollowDesktopStyle, DarkStyle, LightStyle }; static void setUserSettingsFile(const QString& userSettingsFileArg); static QVariant getValue(const std::string& group, const std::string& name); static void setValue(const std::string& group, const std::string& name, const QVariant& value, bool save_to_disk = true); static void clearValue(const std::string& group, const std::string& name); static void restoreDefaults(); static void rememberDefaultFontSize(int size) { m_defaultFontSize = size; } static void exportSettings(const QString& fileName); static bool importSettings(const QString& fileName); static void sync(); private: Settings() = delete; // class is fully static // This works similar to getValue but returns the default value instead of the value set by the user static QVariant getDefaultValue(const std::string& group, const std::string& name); // This works similar to getDefaultValue but returns the default color value based on the passed application style // instead of the current palette. static QColor getDefaultColorValue(const std::string& group, const std::string& name, AppStyle style); // User settings file path static QString userSettingsFile; // QSettings object static QSettings* settings; // This works verify that the settings file provided by the user is a normal settings file static bool isVaildSettingsFile(const QString& userSettingsFile); // This works initialize QSettings object static void setSettingsObject(); // Cache for storing the settings to avoid repeatedly reading the settings file all the time static std::unordered_map m_hCache; // Default UI font size static int m_defaultFontSize; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/SqlExecutionArea.cpp000066400000000000000000000276561463772530400244230ustar00rootroot00000000000000#include "SqlExecutionArea.h" #include "ui_SqlExecutionArea.h" #include "sqltextedit.h" #include "sqlitetablemodel.h" #include "sqlitedb.h" #include "Settings.h" #include "ExportDataDialog.h" #include "FilterTableHeader.h" #include #include #include #include SqlExecutionArea::SqlExecutionArea(DBBrowserDB& _db, QWidget* parent) : QWidget(parent), db(_db), ui(new Ui::SqlExecutionArea), m_columnsResized(false), error_state(false), follow_mode(false) { // Create UI ui->setupUi(this); // Create model model = new SqliteTableModel(db, this); ui->tableResult->setModel(model); connect(model, &SqliteTableModel::finishedFetch, this, &SqlExecutionArea::fetchedData); connect(ui->tableResult->filterHeader(), &FilterTableHeader::sectionPressed, ui->tableResult, &QTableView::selectColumn); ui->findFrame->hide(); QShortcut* shortcutHideFind = new QShortcut(QKeySequence("ESC"), ui->findLineEdit); connect(shortcutHideFind, &QShortcut::activated, this, &SqlExecutionArea::hideFindFrame); QShortcut* shortcutFocusEditor = new QShortcut(QKeySequence(tr("Ctrl+PgUp")), this, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); connect(shortcutFocusEditor, &QShortcut::activated, this, [this]() { ui->editEditor->setFocus(); }); QShortcut* shortcutFocusResults = new QShortcut(QKeySequence(tr("Ctrl+PgDown")), this, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); connect(shortcutFocusResults, &QShortcut::activated, this, [this]() { ui->tableResult->setFocus(); }); connect(ui->findLineEdit, &QLineEdit::textChanged, this, &SqlExecutionArea::findLineEdit_textChanged); connect(ui->previousToolButton, &QToolButton::clicked, this, &SqlExecutionArea::findPrevious); connect(ui->nextToolButton, &QToolButton::clicked, this, &SqlExecutionArea::findNext); connect(ui->findLineEdit, &QLineEdit::returnPressed, this, &SqlExecutionArea::findNext); connect(ui->hideFindButton, &QToolButton::clicked, this, &SqlExecutionArea::hideFindFrame); connect(&fileSystemWatch, &QFileSystemWatcher::fileChanged, this, &SqlExecutionArea::fileChanged); // Save to settings when sppliter is moved, but only to memory. connect(ui->splitter, &QSplitter::splitterMoved, this, [this]() { Settings::setValue("editor", "splitter1_sizes", ui->splitter->saveState(), /* save_to_disk */ false); }); connect(ui->splitter_2, &QSplitter::splitterMoved, this, [this]() { Settings::setValue("editor", "splitter2_sizes", ui->splitter_2->saveState(), /* save_to_disk */ false); }); // Set collapsible the editErrors panel ui->splitter_2->setCollapsible(1, true); // Load settings reloadSettings(); } SqlExecutionArea::~SqlExecutionArea() { delete ui; } QString SqlExecutionArea::getSql() const { return ui->editEditor->text(); } QString SqlExecutionArea::getSelectedSql() const { return ui->editEditor->selectedText().trimmed().replace(QChar(0x2029), '\n'); } void SqlExecutionArea::setSql(const QString& sql) { ui->editEditor->setText(sql); } void SqlExecutionArea::finishExecution(const QString& result, const bool ok) { error_state = !ok; m_columnsResized = false; ui->editErrors->setPlainText(result); // Set reddish background when not ok if (showErrorIndicators) { if (ok) ui->editErrors->setStyleSheet(""); else ui->editErrors->setStyleSheet("QTextEdit {color: white; background-color: rgb(255, 102, 102)}"); } } void SqlExecutionArea::fetchedData() { // Don't resize the columns more than once to fit their contents. This is necessary because the finishedFetch signal of the model // is emitted for each loaded prefetch block and we want to avoid resizes while scrolling down. if(m_columnsResized) return; m_columnsResized = true; // Set column widths according to their contents but make sure they don't exceed a certain size ui->tableResult->resizeColumnsToContents(); for(int i = 0; i < model->columnCount(); i++) { if(ui->tableResult->columnWidth(i) > 300) ui->tableResult->setColumnWidth(i, 300); } } SqlTextEdit *SqlExecutionArea::getEditor() { return ui->editEditor; } ExtendedTableWidget *SqlExecutionArea::getTableResult() { return ui->tableResult; } QTextEdit* SqlExecutionArea::getStatusEdit() { return ui->editErrors; } void SqlExecutionArea::saveAsCsv() { ExportDataDialog dialog(db, ExportDataDialog::ExportFormatCsv, this, model->query()); dialog.exec(); } void SqlExecutionArea::saveAsJson() { ExportDataDialog dialog(db, ExportDataDialog::ExportFormatJson, this, model->query()); dialog.exec(); } void SqlExecutionArea::reloadSettings() { // Reload editor and table settings ui->editEditor->reloadSettings(); ui->tableResult->reloadSettings(); // Set font QFont logfont(Settings::getValue("editor", "font").toString()); logfont.setStyleHint(QFont::TypeWriter); logfont.setPointSize(Settings::getValue("log", "fontsize").toInt()); ui->editErrors->setFont(logfont); // Apply horizontal/vertical tiling option if(Settings::getValue("editor", "horizontal_tiling").toBool()) ui->splitter->setOrientation(Qt::Horizontal); else ui->splitter->setOrientation(Qt::Vertical); ui->splitter->restoreState(Settings::getValue("editor", "splitter1_sizes").toByteArray()); ui->splitter_2->restoreState(Settings::getValue("editor", "splitter2_sizes").toByteArray()); // Reload model settings model->reloadSettings(); // Check if error indicators are enabled for the not-ok background clue showErrorIndicators = Settings::getValue("editor", "error_indicators").toBool(); if (!showErrorIndicators) ui->editErrors->setStyleSheet(""); } void SqlExecutionArea::find(QString expr, bool forward) { bool found = ui->editEditor->findText (expr, ui->regexpCheckBox->isChecked(), ui->caseCheckBox->isChecked(), ui->wholeWordsCheckBox->isChecked(), /* wrap */ true, forward); // Set reddish background when not found if (found || expr.isEmpty()) ui->findLineEdit->setStyleSheet(""); else ui->findLineEdit->setStyleSheet("QLineEdit {color: white; background-color: rgb(255, 102, 102)}"); } void SqlExecutionArea::findPrevious() { find(ui->findLineEdit->text(), false); } void SqlExecutionArea::findNext() { find(ui->findLineEdit->text(), true); } void SqlExecutionArea::findLineEdit_textChanged(const QString &) { // When the text changes, perform an incremental search from cursor // position, or from begin of the selection position. // For incremental search while typing we need to start from the // beginning of the current selection, otherwise we'd jump to the // next occurrence if (ui->editEditor->hasSelectedText()) { int lineFrom; int indexFrom; int lineTo; int indexTo; ui->editEditor->getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo); ui->editEditor->setCursorPosition(lineFrom, indexFrom); } find(ui->findLineEdit->text(), true); } void SqlExecutionArea::hideFindFrame() { ui->editEditor->setFocus(); ui->findFrame->hide(); emit findFrameVisibilityChanged(false); } void SqlExecutionArea::setFindFrameVisibility(bool show) { if (show) { ui->findFrame->show(); ui->findLineEdit->setFocus(); ui->findLineEdit->selectAll(); emit findFrameVisibilityChanged(true); } else { hideFindFrame(); } } void SqlExecutionArea::openFile(const QString& filename) { // Open file for reading QFile f(filename); f.open(QIODevice::ReadOnly); if(!f.isOpen()) { QMessageBox::warning(this, qApp->applicationName(), tr("Couldn't read file \"%1\": %2.").arg(filename, f.errorString())); return; } // Read in the entire file ui->editEditor->setText(f.readAll()); // No modifications yet ui->editEditor->setModified(false); // Remember file name sqlFileName = filename; // Start watching this file for changes and unwatch the previously watched file, if any if(!fileSystemWatch.files().empty()) fileSystemWatch.removePaths(fileSystemWatch.files()); fileSystemWatch.addPath(filename); } void SqlExecutionArea::saveFile(const QString& filename) { // Unwatch all files now. By unwatching them before the actual saving, we are not notified of our own changes if(!fileSystemWatch.files().empty()) fileSystemWatch.removePaths(fileSystemWatch.files()); // Open file for writing QFile f(filename); f.open(QIODevice::WriteOnly); if(!f.isOpen()) { QMessageBox::warning(this, qApp->applicationName(), tr("Couldn't save file: %1.").arg(f.errorString())); return; } // Write to the file if(f.write(getSql().toUtf8()) != -1) { // Close file now. If we let the destructor close it, we can get change notifications. f.close(); // Set modified to false so we can get control of unsaved changes when closing. ui->editEditor->setModified(false); // Remember file name sqlFileName = filename; // Start watching this file fileSystemWatch.addPath(filename); } else { QMessageBox::warning(this, qApp->applicationName(), tr("Couldn't save file: %1.").arg(f.errorString())); return; } } void SqlExecutionArea::fileChanged(const QString& filename) { // Ignore the signal if the file is already removed from the watcher. if(!fileSystemWatch.files().contains(filename)) return; // When in follow_mode and the file is not modified, reload without prompt. if(follow_mode && !ui->editEditor->isModified()) { openFile(filename); return; } // Stop watching the file while the dialog is open. fileSystemWatch.removePath(filename); // Check if there are unsaved changes in the file QString changes; if(ui->editEditor->isModified()) changes = QString(" ") + tr("Your changes will be lost when reloading it!") + QString(""); // Ask user whether to reload the modified file QMessageBox::StandardButton reply = QMessageBox::question( this, qApp->applicationName(), tr("The file \"%1\" was modified by another program. Do you want to reload it?%2").arg(filename, changes) + QString("
  • ") + tr("Answer \"Yes to All\" to reload the file on any external update without further prompting.") + QString("
  • ") + tr("Answer \"No to All\" to ignore any external update without further prompting.") + QString("
") + tr("Modifying and saving the file will restore prompting."), QMessageBox::Yes | QMessageBox::No | QMessageBox::YesToAll | QMessageBox::NoToAll); switch (reply) { case QMessageBox::Yes: case QMessageBox::YesToAll: // Read in the file. This will restore the watcher. openFile(filename); break; case QMessageBox::No: // The file does not match the file on the disk anymore. So set the modified flag. ui->editEditor->setModified(true); // Start watching the file again for further prompting. fileSystemWatch.addPath(filename); break; case QMessageBox::NoToAll: // Set the modified flag and the watch is not restored until the file is saved again to disk. ui->editEditor->setModified(true); break; default: break; } follow_mode = reply == QMessageBox::YesToAll; } void SqlExecutionArea::saveState() { // Save to disk last stored splitter sizes Settings::setValue("editor", "splitter1_sizes", Settings::getValue("editor", "splitter1_sizes")); Settings::setValue("editor", "splitter2_sizes", Settings::getValue("editor", "splitter2_sizes")); } sqlitebrowser-sqlitebrowser-5733cb7/src/SqlExecutionArea.h000066400000000000000000000036051463772530400240540ustar00rootroot00000000000000#ifndef SQLEXECUTIONAREA_H #define SQLEXECUTIONAREA_H #include #include class SqlTextEdit; class SqliteTableModel; class DBBrowserDB; class ExtendedTableWidget; class QTextEdit; namespace Ui { class SqlExecutionArea; } class SqlExecutionArea : public QWidget { Q_OBJECT public: explicit SqlExecutionArea(DBBrowserDB& _db, QWidget* parent = nullptr); ~SqlExecutionArea() override; QString getSql() const; QString getSelectedSql() const; void setSql(const QString& sql); void openFile(const QString& filename); void saveFile(const QString& filename); QString fileName() const { return sqlFileName; } void setFileName(const QString& filename) { sqlFileName = filename; } SqliteTableModel* getModel() { return model; } SqlTextEdit* getEditor(); ExtendedTableWidget *getTableResult(); QTextEdit* getStatusEdit(); bool inErrorState() const { return error_state; } // Save window state to settings static void saveState(); public slots: void finishExecution(const QString& result, const bool ok); void saveAsCsv(); void saveAsJson(); void reloadSettings(); void fetchedData(); void setFindFrameVisibility(bool show); private slots: void findPrevious(); void findNext(); void findLineEdit_textChanged(const QString& text); void hideFindFrame(); void fileChanged(const QString& filename); signals: void findFrameVisibilityChanged(bool visible); private: void find(QString expr, bool forward); DBBrowserDB& db; SqliteTableModel* model; QString sqlFileName; QFileSystemWatcher fileSystemWatch; Ui::SqlExecutionArea* ui; bool m_columnsResized; // This is set to true if the columns of the table view were already adjusted to fit their contents bool showErrorIndicators; bool error_state; bool follow_mode; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/SqlExecutionArea.ui000066400000000000000000000235731463772530400242500ustar00rootroot00000000000000 SqlExecutionArea 0 0 579 482 Form 3 3 3 3 3 Qt::Vertical false 0 16777215 31 QFrame::StyledPanel QFrame::Raised 1 1 1 1 3 Find previous match [Shift+F3] Find previous match with wrapping :/icons/up:/icons/up Shift+F3 Qt::Horizontal The found pattern must be a whole word Whole Words Qt::DefaultContextMenu Text pattern to find considering the checks in this frame Find in editor true The found pattern must match in letter case Case Sensitive Find next match [Enter, F3] Find next match with wrapping :/icons/down:/icons/down F3 Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Qt::Horizontal 40 20 Close Find Bar Close Find Bar :/icons/close:/icons/close true Qt::Vertical false QAbstractItemView::NoEditTriggers 0 120 Monospace 8 false <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> This field shows the results and status codes of the last executed statements. QFrame::StyledPanel QFrame::Sunken true false true Results of the last executed statements SqlTextEdit QTextEdit
sqltextedit.h
1
ExtendedTableWidget QTableWidget
ExtendedTableWidget.h
foreignKeyClicked(QString,QString,QByteArray) foreignKeyClicked(sqlb::ObjectIdentifier,QString,QByteArray)
editEditor findLineEdit tableResult editErrors previousToolButton nextToolButton caseCheckBox wholeWordsCheckBox saveAsCsv() saveAsJson() saveAsView()
sqlitebrowser-sqlitebrowser-5733cb7/src/SqlUiLexer.cpp000066400000000000000000000523061463772530400232320ustar00rootroot00000000000000#include #include "SqlUiLexer.h" #include "Qsci/qsciapis.h" #include "Settings.h" #include "sqlitedb.h" #include "sqlite3.h" namespace { const int SQLITE_VER_NUMBER_3_35 = 3035000; bool enabledMathFunctions() { bool enabled = (sqlite3_libversion_number() >= SQLITE_VER_NUMBER_3_35) && ((sqlite3_compileoption_used("SQLITE_OMIT_COMPILEOPTION_DIAGS") == 1) || (sqlite3_compileoption_used("SQLITE_ENABLE_MATH_FUNCTIONS") == 1 ) ); return enabled; } } const QStringList SqlUiLexer::keywordPatterns = QStringList({ // Keywords "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ALWAYS", "ANALYZE", "AND", "ANY", "AS", "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT", "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DO", "DROP", "EACH", "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN", "FAIL", "FILTER", "FOLLOWING", "FOR", "FOREIGN", "FROM", "FULL", "GENERATED", "GLOB", "GROUP", "HAVING", "IF", "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTHING", "NOTNULL", "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "OVER", "PARTITION", "PLAN", "PRAGMA", "PRECEDING", "PRIMARY", "QUERY", "RAISE", "RANGE", "RECURSIVE", "REFERENCES", "REGEXP", "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RETURNING", "RIGHT", "ROLLBACK", "ROWID", "ROW", "ROWS", "SAVEPOINT", "SELECT", "SET", "STORED", "STRICT", "TABLE", "TEMP", "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNBOUNDED", "UNION", "UNIQUE", "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", "WINDOW", "WITH", "WITHOUT", // Data types "INT", "INTEGER", "REAL", "TEXT", "BLOB", "NUMERIC", "CHAR" }); SqlUiLexer::SqlUiLexer(QObject* parent) : QsciLexerSQL(parent) { // Setup auto completion autocompleteApi = new QsciAPIs(this); setupAutoCompletion(); // Setup folding setFoldComments(true); setFoldCompact(false); } void SqlUiLexer::setupAutoCompletion() { bool upperKeywords = Settings::getValue("editor", "upper_keywords").toBool(); for(const QString& keyword : qAsConst(keywordPatterns)) { if (upperKeywords) autocompleteApi->add(keyword + "?" + QString::number(ApiCompleterIconIdKeyword)); else autocompleteApi->add(keyword.toLower() + "?" + QString::number(ApiCompleterIconIdKeyword)); } // Functions std::vector> functionPatterns = { // Core functions {"abs", tr("(X) The abs(X) function returns the absolute value of the numeric argument X.")}, {"changes", tr("() The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement.")}, {"char", tr("(X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. ")}, {"coalesce", tr("(X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL")}, {"glob", tr("(X,Y) The glob(X,Y) function is equivalent to the expression \"Y GLOB X\".")}, {"ifnull", tr("(X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL.")}, {"instr", tr("(X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X.")}, {"hex", tr("(X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob.")}, {"iif", tr("(X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise.")}, {"last_insert_rowid", tr("() The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function.")}, {"length", tr("(X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character.")}, {"like", tr("(X,Y) The like() function is used to implement the \"Y LIKE X\" expression.")}, {"like", tr("(X,Y,Z) The like() function is used to implement the \"Y LIKE X ESCAPE Z\" expression.")}, {"load_extension", tr("(X) The load_extension(X) function loads SQLite extensions out of the shared library file named X.\nUse of this function must be authorized from Preferences.")}, {"load_extension", tr("(X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y.\nUse of this function must be authorized from Preferences.")}, {"lower", tr("(X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case.")}, {"ltrim", tr("(X) ltrim(X) removes spaces from the left side of X.")}, {"ltrim", tr("(X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X.")}, {"max", tr("(X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL.")}, {"min", tr("(X,Y,...) The multi-argument min() function returns the argument with the minimum value.")}, {"nullif", tr("(X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same.")}, {"printf", tr("(FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library.")}, {"quote", tr("(X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement.")}, {"random", tr("() The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807.")}, {"randomblob", tr("(N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes.")}, {"replace", tr("(X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X.")}, {"round", tr("(X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point.")}, {"round", tr("(X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point.")}, {"rtrim", tr("(X) rtrim(X) removes spaces from the right side of X.")}, {"rtrim", tr("(X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X.")}, {"soundex", tr("(X) The soundex(X) function returns a string that is the soundex encoding of the string X.")}, {"substr", tr("(X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th.")}, {"substr", tr("(X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long.")}, {"total_changes", tr("() The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened.")}, {"trim", tr("(X) trim(X) removes spaces from both ends of X.")}, {"trim", tr("(X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X.")}, {"typeof", tr("(X) The typeof(X) function returns a string that indicates the datatype of the expression X.")}, {"unicode", tr("(X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X.")}, {"upper", tr("(X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent.")}, {"zeroblob", tr("(N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00.")}, // Date and time functions {"date", tr("(timestring,modifier,modifier,...)")}, {"time", tr("(timestring,modifier,modifier,...)")}, {"datetime", tr("(timestring,modifier,modifier,...)")}, {"julianday", tr("(timestring,modifier,modifier,...)")}, {"strftime", tr("(format,timestring,modifier,modifier,...)")}, // Aggregate functions {"avg", tr("(X) The avg() function returns the average value of all non-NULL X within a group.")}, {"count", tr("(X) The count(X) function returns a count of the number of times that X is not NULL in a group.")}, {"group_concat", tr("(X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X.")}, {"group_concat", tr("(X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X.")}, {"max", tr("(X) The max() aggregate function returns the maximum value of all values in the group.")}, {"min", tr("(X) The min() aggregate function returns the minimum non-NULL value of all values in the group.")}, {"sum", tr("(X) The sum() and total() aggregate functions return sum of all non-NULL values in the group.")}, {"total", tr("(X) The sum() and total() aggregate functions return sum of all non-NULL values in the group.")}, // Window functions {"row_number", tr("() The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise.")}, {"rank", tr("() The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1.")}, {"dense_rank", tr("() The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. ")}, {"percent_rank", tr("() Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. ")}, {"cume_dist", tr("() The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition.")}, {"ntile", tr("(N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of.")}, {"lag", tr("(expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL.")}, {"lag", tr("(expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned.")}, {"lag", tr("(expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist.")}, {"lead", tr("(expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL.")}, {"lead", tr("(expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned.")}, {"lead", tr("(expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist.")}, {"first_value", tr("(expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row.")}, {"last_value", tr("(expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row.")}, {"nth_value", tr("(expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned.")} }; if (enabledMathFunctions()) { functionPatterns.insert(functionPatterns.end(), { // Math functions introduced from SQLite 3.35 {"acos", tr("(X) Return the arccosine of X. The result is in radians.")}, {"acosh", tr("(X) Return the hyperbolic arccosine of X.")}, {"asin", tr("(X) Return the arcsine of X. The result is in radians.")}, {"asinh", tr("(X) Return the hyperbolic arcsine of X.")}, {"atan", tr("(X) Return the arctangent of X. The result is in radians.")}, {"atan2", tr("(X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y.")}, {"atanh", tr("(X) Return the hyperbolic arctangent of X.")}, {"ceil", tr("(X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero.")}, {"ceiling", tr("(X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero.")}, {"cos", tr("(X) Return the cosine of X. X is in radians.")}, {"cosh", tr("(X) Return the hyperbolic cosine of X.")}, {"degrees", tr("(X) Convert value X from radians into degrees.")}, {"exp", tr("(X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X.")}, {"floor", tr("(X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero.")}, {"ln", tr("(X) Return the natural logarithm of X.")}, {"log", tr("(B,X) Return the base-B logarithm of X.")}, {"log", tr("(X) Return the base-10 logarithm for X.")}, {"log10", tr("(X) Return the base-10 logarithm for X.")}, {"log2", tr("(X) Return the logarithm base-2 for the number X.")}, {"mod", tr("(X,Y) Return the remainder after dividing X by Y.")}, {"pi", tr("() Return an approximation for Ï€.")}, {"pow", tr("(X,Y) Compute X raised to the power Y.")}, {"power", tr("(X,Y) Compute X raised to the power Y.")}, {"radians", tr("(X) Convert X from degrees into radians.")}, {"sin", tr("(X) Return the sine of X. X is in radians.")}, {"sinh", tr("(X) Return the hyperbolic sine of X.")}, {"sqrt", tr("(X) Return the square root of X. NULL is returned if X is negative.")}, {"tan", tr("(X) Return the tangent of X. X is in radians.")}, {"tanh", tr("(X) Return the hyperbolic tangent of X.")}, {"trunc", tr("(X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero.")} }); } listFunctions.clear(); for(const auto& keyword : functionPatterns) { autocompleteApi->add(keyword.first + "?" + QString::number(ApiCompleterIconIdFunction) + keyword.second); autocompleteApi->add(keyword.first.toUpper() + "?" + QString::number(ApiCompleterIconIdFunction) + keyword.second); // Store all function names in order to highlight them in a different colour listFunctions.append(keyword.first); } autocompleteApi->prepare(); } void SqlUiLexer::setTableNames(const QualifiedTablesMap& tables) { // Update list for auto completion autocompleteApi->clear(); listTables.clear(); for(const auto& itSchemas : tables) { for(const auto& itTables : itSchemas.second) { // Completion for schema.table autocompleteApi->add(itSchemas.first + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdSchema) + "." + itTables.first + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdTable)); for(const QString& field : itTables.second) { // Completion for table.field autocompleteApi->add(itTables.first + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdTable) + "." + field + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdColumn)); // Completion for isolated field autocompleteApi->add(field + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdColumn)); } // Store the table name list in order to highlight them in a different colour listTables.append(itTables.first); } } setupAutoCompletion(); } const char* SqlUiLexer::keywords(int set) const { // Function and table names are generated automatically but need to be returned to the calling functions. // In order to not have them deleted after this function ends they are stored as static variables. Because // the keywords and functions lists don't change after the first call it's initialised here whereas the tables // list, which can change, is updated for each call static std::string sqliteKeywords = keywordPatterns.join(" ").toLower().toUtf8().constData(); static std::string functions = listFunctions.join(" ").toUtf8().constData(); static std::string tables; if(set == 1) { // This corresponds to the QsciLexerSQL::Keyword style in SqlTextEdit return sqliteKeywords.c_str(); } else if(set == 6) // This corresponds to the QsciLexerSQL::KeywordSet6 style in SqlTextEdit { tables = listTables.join(" ").toLower().toUtf8().constData(); return tables.c_str(); } else if(set == 7) { // This corresponds to the QsciLexerSQL::KeywordSet7 style in SqlTextEdit return functions.c_str(); } else { // For all other keyword sets simply call the parent implementation return QsciLexerSQL::keywords(set); } } QStringList SqlUiLexer::autoCompletionWordSeparators() const { // The only word separator for auto completion in SQL is "." as in "tablename.columnname". // Because this isn't implemented in the default QScintilla SQL lexer for some reason we add it here. // We also need to consider quoted identifiers as in "tablename"."columnname" with whatever quote character // is configured. QStringList wl; QString escapeSeparator = sqlb::escapeIdentifier(QString(".")); // Case for non symmetric quotes, e.g. "[.]" to "].[" std::reverse(escapeSeparator.begin(), escapeSeparator.end()); wl << "." << escapeSeparator; return wl; } bool SqlUiLexer::caseSensitive() const { return false; } sqlitebrowser-sqlitebrowser-5733cb7/src/SqlUiLexer.h000066400000000000000000000017411463772530400226740ustar00rootroot00000000000000#ifndef SQLUILEXER_H #define SQLUILEXER_H #include "Qsci/qscilexersql.h" #include class QsciAPIs; class SqlUiLexer : public QsciLexerSQL { Q_OBJECT public: explicit SqlUiLexer(QObject *parent = nullptr); enum ApiCompleterIconId { ApiCompleterIconIdKeyword = 1, ApiCompleterIconIdFunction, ApiCompleterIconIdTable, ApiCompleterIconIdColumn, ApiCompleterIconIdSchema, }; using TablesAndColumnsMap = std::map>; using QualifiedTablesMap = std::map; void setTableNames(const QualifiedTablesMap& tables); const char* keywords(int set) const override; QStringList autoCompletionWordSeparators() const override; bool caseSensitive() const override; private: QsciAPIs* autocompleteApi; void setupAutoCompletion(); QStringList listTables; QStringList listFunctions; static const QStringList keywordPatterns; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/TableBrowser.cpp000066400000000000000000002140331463772530400235650ustar00rootroot00000000000000#include "AddRecordDialog.h" #include "Application.h" #include "ColumnDisplayFormatDialog.h" #include "CondFormatManager.h" #include "Data.h" #include "DbStructureModel.h" #include "ExportDataDialog.h" #include "FilterTableHeader.h" #include "TableBrowser.h" #include "Settings.h" #include "sqlitedb.h" #include "sqlitetablemodel.h" #include "ui_TableBrowser.h" #include #include #include #include #include #include #include #include std::map TableBrowser::m_settings; QString TableBrowser::m_defaultEncoding; TableBrowser::TableBrowser(DBBrowserDB* _db, QWidget* parent) : QWidget(parent), ui(new Ui::TableBrowser), gotoValidator(new QIntValidator(0, 0, this)), db(_db), dbStructureModel(nullptr), m_model(nullptr), m_adjustRows(false), m_columnsResized(false) { ui->setupUi(this); // Set the validator for the goto line edit ui->editGoto->setValidator(gotoValidator); // Set custom placeholder text for global filter field and disable conditional formats ui->editGlobalFilter->setPlaceholderText(tr("Filter in any column")); ui->editGlobalFilter->setConditionFormatContextMenuEnabled(false); // Set up popup menus popupNewRecordMenu = new QMenu(this); popupNewRecordMenu->addAction(ui->newRecordAction); popupNewRecordMenu->addAction(ui->insertValuesAction); ui->actionNewRecord->setMenu(popupNewRecordMenu); popupSaveFilterAsMenu = new QMenu(this); popupSaveFilterAsMenu->addAction(ui->actionFilteredTableExportCsv); popupSaveFilterAsMenu->addAction(ui->actionFilteredTableExportJson); popupSaveFilterAsMenu->addAction(ui->actionFilterSaveAsView); ui->actionSaveFilterAsPopup->setMenu(popupSaveFilterAsMenu); qobject_cast(ui->browseToolbar->widgetForAction(ui->actionSaveFilterAsPopup))->setPopupMode(QToolButton::InstantPopup); popupHeaderMenu = new QMenu(this); popupHeaderMenu->addAction(ui->actionShowRowidColumn); popupHeaderMenu->addAction(ui->actionFreezeColumns); popupHeaderMenu->addAction(ui->actionHideColumns); popupHeaderMenu->addAction(ui->actionShowAllColumns); popupHeaderMenu->addAction(ui->actionSelectColumn); popupHeaderMenu->addSeparator(); popupHeaderMenu->addAction(ui->actionUnlockViewEditing); popupHeaderMenu->addAction(ui->actionBrowseTableEditDisplayFormat); popupHeaderMenu->addSeparator(); popupHeaderMenu->addAction(ui->actionSetTableEncoding); popupHeaderMenu->addAction(ui->actionSetAllTablesEncoding); popupHeaderMenu->addSeparator(); popupHeaderMenu->addAction(ui->actionCopyColumnName); connect(ui->actionSelectColumn, &QAction::triggered, this, [this]() { ui->dataTable->selectColumn(ui->actionBrowseTableEditDisplayFormat->property("clicked_column").toInt()); }); connect(ui->actionFreezeColumns, &QAction::triggered, this, [this](bool checked) { if(checked) freezeColumns(ui->actionBrowseTableEditDisplayFormat->property("clicked_column").toUInt() + 1); else freezeColumns(0); }); // Set up shortcuts QShortcut* dittoRecordShortcut = new QShortcut(QKeySequence("Ctrl+\""), this); connect(dittoRecordShortcut, &QShortcut::activated, this, [this]() { int currentRow = ui->dataTable->currentIndex().row(); duplicateRecord(currentRow); }); // Lambda function for keyboard shortcuts for selecting next/previous table in Browse Data tab connect(ui->dataTable, &ExtendedTableWidget::switchTable, this, [this](bool next) { int index = ui->comboBrowseTable->currentIndex(); int num_items = ui->comboBrowseTable->count(); if(next) { if(++index >= num_items) index = 0; } else { if(--index < 0) index = num_items - 1; } ui->comboBrowseTable->setCurrentIndex(index); refresh(); }); // This is a workaround needed for QDarkStyleSheet. // See https://github.com/ColinDuquesnoy/QDarkStyleSheet/issues/169 QStyledItemDelegate* styledItemDelegate = new QStyledItemDelegate(ui->comboBrowseTable); ui->comboBrowseTable->setItemDelegate(styledItemDelegate); // Add the documentation of shortcuts, which aren't otherwise visible in the user interface, to some buttons. addShortcutsTooltip(ui->actionRefresh, {QKeySequence(tr("Ctrl+R"))}); addShortcutsTooltip(ui->actionPrintTable); // Set up filters connect(ui->dataTable->filterHeader(), &FilterTableHeader::filterChanged, this, &TableBrowser::updateFilter); connect(ui->dataTable->filterHeader(), &FilterTableHeader::filterFocused, this, [this]() { emit prepareForFilter(); }); connect(ui->dataTable->filterHeader(), &FilterTableHeader::addCondFormat, this, &TableBrowser::addCondFormatFromFilter); connect(ui->dataTable->filterHeader(), &FilterTableHeader::allCondFormatsCleared, this, &TableBrowser::clearAllCondFormats); connect(ui->dataTable->filterHeader(), &FilterTableHeader::condFormatsEdited, this, &TableBrowser::editCondFormats); connect(ui->dataTable, &ExtendedTableWidget::editCondFormats, this, &TableBrowser::editCondFormats); connect(ui->dataTable, &ExtendedTableWidget::dataAboutToBeEdited, this, &TableBrowser::dataAboutToBeEdited); // Set up global filter connect(ui->editGlobalFilter, &FilterLineEdit::filterFocused, this, [this]() { emit prepareForFilter(); }); connect(ui->editGlobalFilter, &FilterLineEdit::delayedTextChanged, this, [this](const QString& value) { // Split up filter values #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) QStringList values = value.trimmed().split(" ", QString::SkipEmptyParts); #else QStringList values = value.trimmed().split(" ", Qt::SkipEmptyParts); #endif std::vector filters; std::copy(values.begin(), values.end(), std::back_inserter(filters)); ui->actionClearFilters->setEnabled(m_model->filterCount() > 0 || !ui->editGlobalFilter->text().isEmpty()); // Have they changed? BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; if(filters != settings.globalFilters) { // Set global filters m_model->updateGlobalFilter(filters); updateRecordsetLabel(); // Save them settings.globalFilters = filters; emit projectModified(); } }); connect(ui->dataTable, &ExtendedTableWidget::doubleClicked, this, &TableBrowser::selectionChangedByDoubleClick); connect(ui->dataTable->filterHeader(), &FilterTableHeader::sectionClicked, this, &TableBrowser::headerClicked); connect(ui->dataTable->filterHeader(), &QHeaderView::sectionDoubleClicked, ui->dataTable, &QTableView::selectColumn); connect(ui->dataTable->verticalScrollBar(), &QScrollBar::valueChanged, this, &TableBrowser::updateRecordsetLabel); connect(ui->dataTable->horizontalHeader(), &QHeaderView::sectionResized, this, &TableBrowser::updateRecordsetLabel); connect(ui->dataTable->verticalHeader(), &QHeaderView::sectionResized, this, &TableBrowser::updateRecordsetLabel); connect(ui->dataTable->horizontalHeader(), &QHeaderView::sectionResized, this, &TableBrowser::updateColumnWidth); connect(ui->dataTable->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &TableBrowser::showDataColumnPopupMenu); connect(ui->dataTable->verticalHeader(), &QHeaderView::customContextMenuRequested, this, &TableBrowser::showRecordPopupMenu); connect(ui->dataTable, &ExtendedTableWidget::openFileFromDropEvent, this, &TableBrowser::requestFileOpen); connect(ui->dataTable, &ExtendedTableWidget::selectedRowsToBeDeleted, this, &TableBrowser::deleteRecord); connect(ui->dataTable, &ExtendedTableWidget::foreignKeyClicked, this, [this](const sqlb::ObjectIdentifier& table, const std::string& column, const QByteArray& value) { // Just select the column that was just clicked instead of selecting an entire range which // happens because of the Ctrl and Shift keys. ui->dataTable->selectionModel()->select(ui->dataTable->currentIndex(), QItemSelectionModel::ClearAndSelect); // Emit the foreign key clicked signal emit foreignKeyClicked(table, column, value); }); connect(ui->actionAddDock, &QAction::triggered, this, [this]() { emit newDockRequested(); }); connect(ui->actionRefresh, &QAction::triggered, this, [this]() { db->updateSchema(); refresh(); }); connect(ui->fontComboBox, &QFontComboBox::currentFontChanged, this, [this](const QFont &font) { modifyFormat([font](CondFormat& format) { format.setFontFamily(font.family()); }); }); connect(ui->fontSizeBox, static_cast(&QSpinBox::valueChanged), this, [this](int pointSize) { modifyFormat([pointSize](CondFormat& format) { format.setFontPointSize(pointSize); }); }); connect(ui->actionFontColor, &QAction::triggered, this, [this]() { QColor color = QColorDialog::getColor(QColor(m_model->data(currentIndex(), Qt::ForegroundRole).toString())); if(color.isValid()) modifyFormat([color](CondFormat& format) { format.setForegroundColor(color); }); }); connect(ui->actionBackgroundColor, &QAction::triggered, this, [this]() { QColor color = QColorDialog::getColor(QColor(m_model->data(currentIndex(), Qt::BackgroundRole).toString())); if(color.isValid()) modifyFormat([color](CondFormat& format) { format.setBackgroundColor(color); }); }); connect(ui->actionBold, &QAction::toggled, this, [this](bool checked) { modifyFormat([checked](CondFormat& format) { format.setBold(checked); }); }); connect(ui->actionItalic, &QAction::toggled, this, [this](bool checked) { modifyFormat([checked](CondFormat& format) { format.setItalic(checked); }); }); connect(ui->actionUnderline, &QAction::toggled, this, [this](bool checked) { modifyFormat([checked](CondFormat& format) { format.setUnderline(checked); }); }); connect(ui->actionLeftAlign, &QAction::triggered, this, [this]() { ui->actionLeftAlign->setChecked(true); ui->actionRightAlign->setChecked(false); ui->actionCenter->setChecked(false); ui->actionJustify->setChecked(false); modifyFormat([](CondFormat& format) { format.setAlignment(CondFormat::AlignLeft); }); }); connect(ui->actionRightAlign, &QAction::triggered, this, [this]() { ui->actionLeftAlign->setChecked(false); ui->actionRightAlign->setChecked(true); ui->actionCenter->setChecked(false); ui->actionJustify->setChecked(false); modifyFormat([](CondFormat& format) { format.setAlignment(CondFormat::AlignRight); }); }); connect(ui->actionCenter, &QAction::triggered, this, [this]() { ui->actionLeftAlign->setChecked(false); ui->actionRightAlign->setChecked(false); ui->actionCenter->setChecked(true); ui->actionJustify->setChecked(false); modifyFormat([](CondFormat& format) { format.setAlignment(CondFormat::AlignCenter); }); }); connect(ui->actionJustify, &QAction::triggered, this, [this]() { ui->actionLeftAlign->setChecked(false); ui->actionRightAlign->setChecked(false); ui->actionCenter->setChecked(false); ui->actionJustify->setChecked(true); modifyFormat([](CondFormat& format) { format.setAlignment(CondFormat::AlignJustify); }); }); connect(ui->actionEditCondFormats, &QAction::triggered, this, [this]() { editCondFormats(static_cast(currentIndex().column())); }); connect(ui->actionClearFormat, &QAction::triggered, this, [this]() { for (const size_t column : ui->dataTable->selectedCols()) clearAllCondFormats(column); for (const QModelIndex& index : ui->dataTable->selectionModel()->selectedIndexes()) clearRowIdFormats(index); }); connect(ui->dataTable, &ExtendedTableWidget::currentIndexChanged, this, [this](const QModelIndex ¤t, const QModelIndex &) { // Get cell current format for updating the format toolbar values. Block signals, so the format change is not reapplied. QString font_string = m_model->data(current, Qt::FontRole).toString(); QFont font; if(!font_string.isEmpty()) font.fromString(font_string); ui->fontComboBox->blockSignals(true); ui->fontComboBox->setCurrentFont(font); ui->fontComboBox->blockSignals(false); ui->fontSizeBox->blockSignals(true); ui->fontSizeBox->setValue(font.pointSize()); ui->fontSizeBox->blockSignals(false); ui->actionBold->blockSignals(true); ui->actionBold->setChecked(font.bold()); ui->actionBold->blockSignals(false); ui->actionItalic->blockSignals(true); ui->actionItalic->setChecked(font.italic()); ui->actionItalic->blockSignals(false); ui->actionUnderline->blockSignals(true); ui->actionUnderline->setChecked(font.underline()); ui->actionUnderline->blockSignals(false); Qt::Alignment align = Qt::Alignment(m_model->data(current, Qt::TextAlignmentRole).toInt()); ui->actionLeftAlign->blockSignals(true); ui->actionLeftAlign->setChecked(align.testFlag(Qt::AlignLeft)); ui->actionLeftAlign->blockSignals(false); ui->actionRightAlign->blockSignals(true); ui->actionRightAlign->setChecked(align.testFlag(Qt::AlignRight)); ui->actionRightAlign->blockSignals(false); ui->actionCenter->blockSignals(true); ui->actionCenter->setChecked(align.testFlag(Qt::AlignCenter)); ui->actionCenter->blockSignals(false); ui->actionJustify->blockSignals(true); ui->actionJustify->setChecked(align.testFlag(Qt::AlignJustify)); ui->actionJustify->blockSignals(false); }); connect(ui->actionToggleFormatToolbar, &QAction::toggled, ui->formatFrame, &QFrame::setVisible); ui->actionToggleFormatToolbar->setChecked(false); ui->formatFrame->setVisible(false); // Set up find frame ui->frameFind->hide(); QShortcut* shortcutHideFindFrame = new QShortcut(QKeySequence("ESC"), ui->editFindExpression); connect(shortcutHideFindFrame, &QShortcut::activated, ui->buttonFindClose, &QToolButton::click); QShortcut* shortcutActionFind = new QShortcut(QKeySequence("Ctrl+F"), this, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); connect(shortcutActionFind, &QShortcut::activated, ui->actionFind, &QAction::trigger); connect(ui->actionFind, &QAction::triggered, this, [this](bool checked) { if(checked) { ui->widgetReplace->hide(); ui->frameFind->show(); ui->editFindExpression->setFocus(); ui->actionReplace->setChecked(false); } else { ui->buttonFindClose->click(); } }); QShortcut* shortcutActionReplace = new QShortcut(QKeySequence("Ctrl+H"), this, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); connect(shortcutActionReplace, &QShortcut::activated, ui->actionReplace, &QAction::trigger); connect(ui->actionReplace, &QAction::triggered, this, [this](bool checked) { if(checked) { ui->widgetReplace->show(); ui->frameFind->show(); ui->editFindExpression->setFocus(); ui->actionFind->setChecked(false); } else { ui->buttonFindClose->click(); } }); connect(ui->editFindExpression, &QLineEdit::returnPressed, ui->buttonFindNext, &QToolButton::click); connect(ui->editFindExpression, &QLineEdit::textChanged, this, [this]() { // When the text has changed but neither Return nor F3 or similar nor any buttons were pressed, we want to include the current // cell in the search as well. This makes sure the selected cell does not jump around every time the text is changed but only // when the current cell does not match the search expression anymore. find(ui->editFindExpression->text(), true, true); }); connect(ui->buttonFindClose, &QToolButton::clicked, this, [this](){ ui->dataTable->setFocus(); ui->frameFind->hide(); ui->actionFind->setChecked(false); ui->actionReplace->setChecked(false); }); connect(ui->buttonFindPrevious, &QToolButton::clicked, this, [this](){ find(ui->editFindExpression->text(), false); }); connect(ui->buttonFindNext, &QToolButton::clicked, this, [this](){ find(ui->editFindExpression->text(), true); }); connect(ui->buttonReplaceNext, &QToolButton::clicked, this, [this](){ find(ui->editFindExpression->text(), true, true, ReplaceMode::ReplaceNext); }); connect(ui->buttonReplaceAll, &QToolButton::clicked, this, [this](){ find(ui->editFindExpression->text(), true, true, ReplaceMode::ReplaceAll); }); QShortcut* shortcutActionFilter = new QShortcut(QKeySequence("Ctrl+Shift+F"), this, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); connect(shortcutActionFilter, &QShortcut::activated, this, [this](){ // Restore cursor because in the ExtendedTableWidget it is changed to a hand when Ctrl+Shift // is pressed. QApplication::restoreOverrideCursor(); FilterTableHeader* header = qobject_cast(ui->dataTable->horizontalHeader()); // Set the focus to the current column if valid, otherwise, set focus to the first visible // column. if(!header) { ui->dataTable->horizontalHeader()->setFocus(); } else if(currentIndex().isValid()) { header->setFocusColumn(static_cast(currentIndex().column())); } else { for(int col = 0; col < ui->dataTable->model()->columnCount(); col++) { if(!ui->dataTable->isColumnHidden(col)) { header->setFocusColumn(static_cast(col)); break; } } } }); QShortcut* shortcutActionGlobalFilter = new QShortcut(QKeySequence("Ctrl+Alt+F"), this, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); connect(shortcutActionGlobalFilter, &QShortcut::activated, this, [this](){ ui->editGlobalFilter->setFocus(); }); // Recreate the model if(m_model) delete m_model; m_model = new SqliteTableModel(*db, this, QString(), true); // Connect slots connect(m_model, &SqliteTableModel::finishedFetch, this, &TableBrowser::fetchedData); // Load initial settings reloadSettings(); } TableBrowser::~TableBrowser() { delete gotoValidator; delete ui; } void TableBrowser::reset() { // Reset the model m_model->reset(); // Reset the recordset label inside the Browse tab now updateRecordsetLabel(); // Clear filters clearFilters(); // Reset the plot dock model and connection emit updatePlot(nullptr, nullptr, nullptr, true); } void TableBrowser::resetSharedSettings() { // Remove all stored table information browse data tab m_settings.clear(); m_defaultEncoding = QString(); } sqlb::ObjectIdentifier TableBrowser::currentlyBrowsedTableName() const { return sqlb::ObjectIdentifier(dbStructureModel->index(ui->comboBrowseTable->currentIndex(), DbStructureModel::ColumnSchema, ui->comboBrowseTable->rootModelIndex()).data().toString().toStdString(), ui->comboBrowseTable->currentData(Qt::EditRole).toString().toStdString()); // Use the edit role here to make sure we actually get the // table name without the schema bit in front of it. } BrowseDataTableSettings& TableBrowser::settings(const sqlb::ObjectIdentifier& object) { return m_settings[object]; } void TableBrowser::setSettings(const sqlb::ObjectIdentifier& table, const BrowseDataTableSettings& table_settings) { m_settings[table] = table_settings; } void TableBrowser::setStructure(QAbstractItemModel* model, const sqlb::ObjectIdentifier& old_table) { dbStructureModel = model; ui->comboBrowseTable->blockSignals(true); ui->comboBrowseTable->setModel(model); ui->comboBrowseTable->setRootModelIndex(dbStructureModel->index(0, 0)); // Show the 'browsable' section of the db structure tree ui->comboBrowseTable->blockSignals(false); int old_table_index = ui->comboBrowseTable->findText(QString::fromStdString(old_table.toDisplayString())); if(old_table_index == -1 && ui->comboBrowseTable->count()) // If the old table couldn't be found anymore but there is another table, select that ui->comboBrowseTable->setCurrentIndex(0); else if(old_table_index == -1) // If there aren't any tables to be selected anymore, clear the table view clear(); else // Under normal circumstances just select the old table again ui->comboBrowseTable->setCurrentIndex(old_table_index); emit currentTableChanged(currentlyBrowsedTableName()); } QModelIndex TableBrowser::currentIndex() const { return ui->dataTable->currentIndex(); } void TableBrowser::setEnabled(bool enable) { ui->browseToolbar->setEnabled(enable); ui->editGlobalFilter->setEnabled(enable); ui->formatFrame->setEnabled(enable); ui->frameFind->setEnabled(enable); ui->buttonNext->setEnabled(enable); ui->buttonPrevious->setEnabled(enable); ui->buttonBegin->setEnabled(enable); ui->buttonEnd->setEnabled(enable); ui->buttonGoto->setEnabled(enable); ui->editGoto->setEnabled(enable); updateInsertDeleteRecordButton(); } void TableBrowser::refresh() { // If the list of table names is empty, i.e. there are no tables to browse, clear the view // to make sure any left over data is removed and do not add any new information. if(ui->comboBrowseTable->model()->rowCount(ui->comboBrowseTable->rootModelIndex()) == 0) { clear(); return; } // Reset the minimum width of the vertical header which could have been modified in updateFilter // or in headerClicked. ui->dataTable->verticalHeader()->setMinimumWidth(0); // Reset the model if it was cleared before // Because setting a new model creates a new selection mode, reconnect the slots to its signals. if(ui->dataTable->model() == nullptr) { ui->dataTable->setModel(m_model); connect(ui->dataTable->selectionModel(), &QItemSelectionModel::currentChanged, this, &TableBrowser::selectionChanged); connect(ui->dataTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this](const QItemSelection&, const QItemSelection&) { updateInsertDeleteRecordButton(); const QModelIndexList& sel = ui->dataTable->selectionModel()->selectedIndexes(); QString statusMessage; if (sel.count() > 1) { int rows = static_cast(ui->dataTable->rowsInSelection().size()); statusMessage = tr("%n row(s)", "", rows); int columns = static_cast(ui->dataTable->colsInSelection().size()); statusMessage += tr(", %n column(s)", "", columns); if (sel.count() < Settings::getValue("databrowser", "complete_threshold").toInt()) { double sum = 0; double first = m_model->data(sel.first(), Qt::EditRole).toDouble(); double min = first; double max = first; for (const QModelIndex& index : sel) { double dblData = m_model->data(index, Qt::EditRole).toDouble(); sum += dblData; min = std::min(min, dblData); max = std::max(max, dblData); } statusMessage += tr(". Sum: %1; Average: %2; Min: %3; Max: %4").arg(sum).arg(sum/sel.count()).arg(min).arg(max); } } emit statusMessageRequested(statusMessage); }); } // Delete settings of no-longer existent tables for (auto it = m_settings.cbegin(); it != m_settings.cend(); ) { if (!db->getTableByName(it->first)) { it = m_settings.erase(it); } else { ++it; } } // Retrieve the stored data for this table if there is any. If there are no settings for this table, // this will insert and return a settings object with default values. const sqlb::ObjectIdentifier tablename = currentlyBrowsedTableName(); const BrowseDataTableSettings& storedData = m_settings[tablename]; // Set column widths to match contents when no column widths were provided in the stored settings. // This needs to be done before setting the query because the data is returned asynchronously and // so this information can be needed any time. if(storedData.columnWidths.empty()) m_columnsResized = false; // Current table changed emit currentTableChanged(tablename); // Build query and apply settings applyModelSettings(storedData, buildQuery(storedData, tablename)); applyViewportSettings(storedData, tablename); emit updatePlot(ui->dataTable, m_model, &m_settings[tablename], true); } void TableBrowser::clearFilters() { ui->dataTable->filterHeader()->clearFilters(); ui->editGlobalFilter->clear(); } void TableBrowser::reloadSettings() { ui->dataTable->reloadSettings(); ui->browseToolbar->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyleBrowse").toInt())); m_model->reloadSettings(); } void TableBrowser::setCurrentTable(const sqlb::ObjectIdentifier& name) { int index = ui->comboBrowseTable->findText(QString::fromStdString(name.toDisplayString())); if(index != -1) ui->comboBrowseTable->setCurrentIndex(index); } void TableBrowser::clear() { // This function unset the model in the data view. So if no model is set at the moment, // this indicates that this function has already been called and does not need to // executed another time. if (!ui->dataTable->model()) return; // Unset the model ui->dataTable->setModel(nullptr); // Remove any filters, not just the values but the fields too if(qobject_cast(ui->dataTable->horizontalHeader())) qobject_cast(ui->dataTable->horizontalHeader())->generateFilters(0); ui->editGlobalFilter->clear(); } void TableBrowser::updateFilter(size_t column, const QString& value) { // Set minimum width to the vertical header in order to avoid flickering while a filter is being updated. ui->dataTable->verticalHeader()->setMinimumWidth(ui->dataTable->verticalHeader()->width()); // Update the filter in the model and its query const std::string column_name = model()->headerData(static_cast(column), Qt::Horizontal, Qt::EditRole).toString().toStdString(); m_model->updateFilter(column_name, value); ui->actionClearFilters->setEnabled(m_model->filterCount() > 0 || !ui->editGlobalFilter->text().isEmpty()); // Save the new filter settings BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; if(value.isEmpty()) { if(settings.filterValues.erase(column_name) > 0) emit projectModified(); } else { if (settings.filterValues[column_name] != value) { settings.filterValues[column_name] = value; emit projectModified(); } } } void TableBrowser::addCondFormatFromFilter(size_t column, const QString& value) { QFont font = QFont(Settings::getValue("databrowser", "font").toString()); font.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); // Create automatically a new conditional format with the next serial background color according to the theme and the regular foreground // color and font in the settings. CondFormat newCondFormat(value, QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()), m_condFormatPalette.nextSerialColor(Palette::appHasDarkTheme()), font, CondFormat::AlignLeft, m_model->encoding()); addCondFormat(false, column, newCondFormat); } void TableBrowser::addCondFormat(bool isRowIdFormat, size_t column, const CondFormat& newCondFormat) { BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; std::vector& formats = isRowIdFormat ? settings.rowIdFormats[column] : settings.condFormats[column]; m_model->addCondFormat(isRowIdFormat, column, newCondFormat); // Conditionless formats are pushed back and others inserted at the beginning, so they aren't eclipsed. if (newCondFormat.filter().isEmpty()) formats.push_back(newCondFormat); else formats.insert(formats.begin(), newCondFormat); emit projectModified(); } void TableBrowser::clearAllCondFormats(size_t column) { m_model->setCondFormats(false, column, {}); m_settings[currentlyBrowsedTableName()].condFormats[column].clear(); emit projectModified(); } void TableBrowser::clearRowIdFormats(const QModelIndex index) { std::vector& rowIdFormats = m_settings[currentlyBrowsedTableName()].rowIdFormats[static_cast(index.column())]; rowIdFormats.erase(std::remove_if(rowIdFormats.begin(), rowIdFormats.end(), [&](const CondFormat& format) { return format.filter() == QString("=%1").arg(m_model->data(index.sibling(index.row(), 0)).toString()); }), rowIdFormats.end()); m_model->setCondFormats(true, static_cast(index.column()), rowIdFormats); emit projectModified(); } void TableBrowser::editCondFormats(size_t column) { CondFormatManager condFormatDialog(m_settings[currentlyBrowsedTableName()].condFormats[column], m_model->encoding(), this); condFormatDialog.setWindowTitle(tr("Conditional formats for \"%1\""). arg(m_model->headerData(static_cast(column), Qt::Horizontal, Qt::EditRole).toString())); if (condFormatDialog.exec()) { std::vector condFormatVector = condFormatDialog.getCondFormats(); m_model->setCondFormats(false, column, condFormatVector); m_settings[currentlyBrowsedTableName()].condFormats[column] = condFormatVector; emit projectModified(); } } void TableBrowser::modifySingleFormat(const bool isRowIdFormat, const QString& filter, const QModelIndex refIndex, std::function changeFunction) { const size_t column = static_cast(refIndex.column()); BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; std::vector& formats = isRowIdFormat ? settings.rowIdFormats[column] : settings.condFormats[column]; auto it = std::find_if(formats.begin(), formats.end(), [&filter](const CondFormat& format) { return format.filter() == filter; }); if(it != formats.end()) { changeFunction(*it); m_model->addCondFormat(isRowIdFormat, column, *it); } else { // Create a new conditional format based on the current reference index and then modify it as requested using the passed function. CondFormat newCondFormat(filter, m_model, refIndex, m_model->encoding()); changeFunction(newCondFormat); addCondFormat(isRowIdFormat, column, newCondFormat); } } void TableBrowser::modifyFormat(std::function changeFunction) { // Modify the conditional formats from entirely selected columns having the current filter value, // or modify the row-id formats of selected cells, when the selection does not cover entire columns. const std::unordered_set& columns = ui->dataTable->selectedCols(); if (columns.size() > 0) { for (size_t column : columns) { QString filter; const std::string column_name = model()->headerData(static_cast(column), Qt::Horizontal, Qt::EditRole).toString().toStdString(); if (m_settings[currentlyBrowsedTableName()].filterValues.count(column_name) > 0) filter = m_settings[currentlyBrowsedTableName()].filterValues.at(column_name); modifySingleFormat(false, filter, currentIndex().sibling(currentIndex().row(), static_cast(column)), changeFunction); } } else { for(const QModelIndex& index : ui->dataTable->selectionModel()->selectedIndexes()) { const QString filter = QString("=%1").arg(m_model->data(index.sibling(index.row(), 0)).toString()); modifySingleFormat(true, filter, index, changeFunction); } } emit projectModified(); } void TableBrowser::updateRecordsetLabel() { // Get all the numbers, i.e. the number of the first row and the last row as well as the total number of rows int from = ui->dataTable->verticalHeader()->visualIndexAt(0) + 1; int total = m_model->rowCount(); int real_total = m_model->realRowCount(); int to = from + ui->dataTable->numVisibleRows() - 1; if(to < 0) to = 0; // Adjust visible rows to contents if necessary, and then take the new visible rows, which might have changed. if(m_adjustRows) { for(int i=from; i<=to; i++) ui->dataTable->resizeRowToContents(i); from = ui->dataTable->verticalHeader()->visualIndexAt(0) + 1; to = from + ui->dataTable->numVisibleRows() - 1; } // Update the validator of the goto row field gotoValidator->setRange(0, total); // When there is no query for this table (i.e. no table is selected), there is no row count query either which in turn means // that the row count query will never finish. And because of this the row count will be forever unknown. To avoid always showing // a misleading "determining row count" text in the UI we set the row count status to complete here for empty queries. auto row_count_available = m_model->rowCountAvailable(); if(m_model->query().empty()) row_count_available = SqliteTableModel::RowCount::Complete; // Update the label showing the current position QString txt; switch(row_count_available) { case SqliteTableModel::RowCount::Unknown: txt = tr("determining row count..."); break; case SqliteTableModel::RowCount::Partial: txt = tr("%L1 - %L2 of >= %L3").arg(from).arg(to).arg(total); break; case SqliteTableModel::RowCount::Complete: txt = tr("%L1 - %L2 of %L3").arg(from).arg(to).arg(real_total); if (real_total != total) { txt.append(tr(" (clipped at %L1 rows)").arg(total)); } break; } ui->labelRecordset->setText(txt); // Enable editing only for tables or views with editing unlocked for which the row count is already available bool is_table_or_unlocked_view = false; sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); if(!current_table.isEmpty() && !m_model->query().empty()) { auto obj = db->getTableByName(current_table); is_table_or_unlocked_view = obj && ( (obj->isView() && m_model->hasPseudoPk()) || (!obj->isView())); } enableEditing(m_model->rowCountAvailable() != SqliteTableModel::RowCount::Unknown && is_table_or_unlocked_view); // Show filters unless the table is empty const bool needs_filters = total > 0 || m_model->filterCount() > 0; FilterTableHeader* header = qobject_cast(ui->dataTable->horizontalHeader()); if(header) { if(needs_filters && !header->hasFilters()) { generateFilters(); ui->dataTable->adjustSize(); } else if(!needs_filters && header->hasFilters()) { ui->dataTable->generateFilters(0, false); } } } sqlb::Query TableBrowser::buildQuery(const BrowseDataTableSettings& storedData, const sqlb::ObjectIdentifier& tablename) const { const auto table = db->getTableByName(tablename); sqlb::Query query(tablename, table && table->isView()); // Construct a query from the retrieved settings // Sorting query.setOrderBy(storedData.sortColumns); ui->actionClearSorting->setEnabled(storedData.sortColumns.size() > 0); // Filters for(auto it=storedData.filterValues.cbegin();it!=storedData.filterValues.cend();++it) query.where().insert({it->first, CondFormat::filterToSqlCondition(it->second, m_model->encoding())}); // Global filter for(const auto& f : storedData.globalFilters) query.globalWhere().push_back(CondFormat::filterToSqlCondition(f, m_model->encoding())); // Display formats bool only_defaults = true; if(table) { // When there is at least one custom display format, we have to set all columns for the query explicitly here for(size_t i=0; ifields.size(); ++i) { QString format = contains(storedData.displayFormats, i+1) ? storedData.displayFormats.at(i+1) : QString(); if(format.size()) { query.selectedColumns().emplace_back(table->fields.at(i).name(), format.toStdString()); only_defaults = false; } else { query.selectedColumns().emplace_back(table->fields.at(i).name(), table->fields.at(i).name()); } } } if(only_defaults) query.selectedColumns().clear(); // Unlock view editing query.setRowIdColumn(storedData.unlockViewPk.toStdString()); return query; } void TableBrowser::applyModelSettings(const BrowseDataTableSettings& storedData, const sqlb::Query& query) { // Set query which also resets the model m_model->setQuery(query); // Regular conditional formats for(auto formatIt=storedData.condFormats.cbegin(); formatIt!=storedData.condFormats.cend(); ++formatIt) m_model->setCondFormats(false, formatIt->first, formatIt->second); // Row Id formats for(auto formatIt=storedData.rowIdFormats.cbegin(); formatIt!=storedData.rowIdFormats.cend(); ++formatIt) m_model->setCondFormats(true, formatIt->first, formatIt->second); // Encoding m_model->setEncoding(storedData.encoding); } void TableBrowser::applyViewportSettings(const BrowseDataTableSettings& storedData, const sqlb::ObjectIdentifier& tablename) { // Show rowid column. This also takes care of the filters. showRowidColumn(storedData.showRowid); // Enable editing in general and (un)lock view editing depending on the settings unlockViewEditing(!storedData.unlockViewPk.isEmpty() && storedData.unlockViewPk != "_rowid_", storedData.unlockViewPk); // Column hidden status showAllColumns(); for(auto hiddenIt=storedData.hiddenColumns.cbegin();hiddenIt!=storedData.hiddenColumns.cend();++hiddenIt) hideColumns(hiddenIt->first, hiddenIt->second); // Column widths std::map w = storedData.columnWidths; // We're working with a copy here because the map can get modified in the process for(auto widthIt=w.cbegin();widthIt!=w.cend();++widthIt) { if(widthIt->first < ui->dataTable->model()->columnCount()) ui->dataTable->setColumnWidth(widthIt->first, widthIt->second); } m_columnsResized = !w.empty(); // Global filters QString text; for(const auto& f : storedData.globalFilters) text += f + " "; text.chop(1); ui->editGlobalFilter->setText(text); // Show/hide some menu options depending on whether this is a table or a view const auto table = db->getTableByName(tablename); if(!table->isView()) { // Table ui->actionUnlockViewEditing->setVisible(false); ui->actionShowRowidColumn->setVisible(!table->withoutRowidTable()); } else { // View ui->actionUnlockViewEditing->setVisible(true); ui->actionShowRowidColumn->setVisible(false); } // Frozen columns freezeColumns(storedData.frozenColumns); } void TableBrowser::enableEditing(bool enable_edit) { // Don't enable anything if this is a read only database bool edit = enable_edit && !db->readOnly(); // Apply settings ui->dataTable->setEditTriggers(edit ? QAbstractItemView::SelectedClicked | QAbstractItemView::AnyKeyPressed | QAbstractItemView::EditKeyPressed : QAbstractItemView::NoEditTriggers); updateInsertDeleteRecordButton(); } void TableBrowser::showRowidColumn(bool show) { // Disconnect the resized signal from the horizontal header. Otherwise it's resetting the automatic column widths disconnect(ui->dataTable->horizontalHeader(), &QHeaderView::sectionResized, this, &TableBrowser::updateColumnWidth); // WORKAROUND // Set the opposite hidden/visible status of what we actually want for the rowid column. This is to work around a Qt bug which // is present in at least version 5.7.1. The problem is this: when you browse a table/view with n columns, then switch to a table/view // with less than n columns, you'll be able to resize the first (hidden!) column by resizing the section to the left of the first visible // column. By doing so the table view gets messed up. But even when not resizing the first hidden column, tab-ing through the fields // will stop at the not-so-much-hidden rowid column, too. All this can be fixed by this line. I haven't managed to find another workaround // or way to fix this yet. ui->dataTable->setColumnHidden(0, show); // Show/hide rowid column ui->dataTable->setColumnHidden(0, !show); if(show) ui->dataTable->setColumnWidth(0, ui->dataTable->horizontalHeader()->defaultSectionSize()); // Update checked status of the popup menu action ui->actionShowRowidColumn->setChecked(show); // Save settings for this table sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); if (m_settings[current_table].showRowid != show) { emit projectModified(); m_settings[current_table].showRowid = show; } // Update the filter row generateFilters(); // Re-enable signal connect(ui->dataTable->horizontalHeader(), &QHeaderView::sectionResized, this, &TableBrowser::updateColumnWidth); ui->dataTable->update(); } void TableBrowser::freezeColumns(size_t columns) { // Update checked status of the popup menu action ui->actionFreezeColumns->setChecked(columns != 0); // Save settings for this table sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); if (m_settings[current_table].frozenColumns != columns) { emit projectModified(); m_settings[current_table].frozenColumns = columns; } // Apply settings ui->dataTable->horizontalHeader()->blockSignals(true); ui->dataTable->setFrozenColumns(columns); generateFilters(); ui->dataTable->horizontalHeader()->blockSignals(false); } void TableBrowser::generateFilters() { // Generate a new row of filter line edits const auto& settings = m_settings[currentlyBrowsedTableName()]; ui->dataTable->generateFilters(static_cast(m_model->columnCount()), settings.showRowid); // Apply the stored filter strings to the new row of line edits // Set filters blocking signals for this since the filter is already applied to the browse table model FilterTableHeader* filterHeader = qobject_cast(ui->dataTable->horizontalHeader()); bool oldState = filterHeader->blockSignals(true); auto obj = db->getTableByName(currentlyBrowsedTableName()); for(auto filterIt=settings.filterValues.cbegin();filterIt!=settings.filterValues.cend();++filterIt) ui->dataTable->setFilter(sqlb::getFieldNumber(obj, filterIt->first) + 1, filterIt->second); filterHeader->blockSignals(oldState); ui->actionClearFilters->setEnabled(m_model->filterCount() > 0 || !ui->editGlobalFilter->text().isEmpty()); } void TableBrowser::unlockViewEditing(bool unlock, QString pk) { sqlb::ObjectIdentifier currentTable = currentlyBrowsedTableName(); sqlb::TablePtr view = db->getTableByName(currentTable); // If this isn't a view just unlock editing and return if(!view) { m_model->setPseudoPk(m_model->pseudoPk()); enableEditing(true); return; } // If the view gets unlocked for editing and we don't have a 'primary key' for this view yet, then ask for one if(unlock && pk.isEmpty()) { while(true) { bool ok; QStringList options; for(const auto& n : view->fieldNames()) options.push_back(QString::fromStdString(n)); // Ask for a PK pk = QInputDialog::getItem(this, qApp->applicationName(), tr("Please enter a pseudo-primary key in order to enable editing on this view. " "This should be the name of a unique column in the view."), options, 0, false, &ok); // Cancelled? if(!ok || pk.isEmpty()) { ui->actionUnlockViewEditing->setChecked(false); return; } // Do some basic testing of the input and if the input appears to be good, go on if(db->executeSQL("SELECT " + sqlb::escapeIdentifier(pk.toStdString()) + " FROM " + currentTable.toString() + " LIMIT 1;", false, true)) break; } } else if(!unlock) { // Locking the view is done by unsetting the pseudo-primary key pk = "_rowid_"; } // (De)activate editing enableEditing(unlock); m_model->setPseudoPk({pk.toStdString()}); // Update checked status of the popup menu action ui->actionUnlockViewEditing->blockSignals(true); ui->actionUnlockViewEditing->setChecked(unlock); ui->actionUnlockViewEditing->blockSignals(false); // If the settings didn't change, do not try to reapply them. // This avoids an infinite mutual recursion. BrowseDataTableSettings& settings = m_settings[currentTable]; if(settings.unlockViewPk != pk) { // Save settings for this table settings.unlockViewPk = pk; // The filter row might move up one row when we change the query, so we need to regenerate it here generateFilters(); emit projectModified(); } } void TableBrowser::hideColumns(int column, bool hide) { sqlb::ObjectIdentifier tableName = currentlyBrowsedTableName(); // Select columns to (un)hide std::unordered_set columns; if(column == -1) { if(ui->dataTable->selectedCols().size() == 0) columns.insert(ui->actionBrowseTableEditDisplayFormat->property("clicked_column").toInt()); else { auto cols = ui->dataTable->selectedCols(); columns.insert(cols.begin(), cols.end()); } } else { columns.insert(column); } // (Un)hide requested column(s) for(int col : columns) { if(col >= ui->dataTable->model()->columnCount()) continue; ui->dataTable->setColumnHidden(col, hide); if(!hide) ui->dataTable->setColumnWidth(col, ui->dataTable->horizontalHeader()->defaultSectionSize()); m_settings[tableName].hiddenColumns[col] = hide; } // check to see if all the columns are hidden bool allHidden = true; for(int col = 1; col < ui->dataTable->model()->columnCount(); col++) { if(!ui->dataTable->isColumnHidden(col)) { allHidden = false; break; } } if(allHidden && ui->dataTable->model()->columnCount() > 1) hideColumns(1, false); emit projectModified(); } void TableBrowser::showAllColumns() { for(int col = 1; col < ui->dataTable->model()->columnCount(); col++) { if(ui->dataTable->isColumnHidden(col)) hideColumns(col, false); } } void TableBrowser::updateInsertDeleteRecordButton() { // Update the delete record button to reflect number of selected records int rows = 0; // If there is no model yet (because e.g. no database file is opened) there is no selection model either. So we need to check for that here // in order to avoid null pointer dereferences. If no selection model exists we will just continue as if no row is selected because without a // model you could argue there actually is no row to be selected. if(ui->dataTable->selectionModel()) { const auto & sel = ui->dataTable->selectionModel()->selectedIndexes(); if(sel.count()) rows = sel.last().row() - sel.first().row() + 1; } // Enable the insert and delete buttons only if the currently browsed table or view is editable. For the delete button we additionally require // at least one row to be selected. For the insert button there is an extra rule to disable it when we are browsing a view because inserting // into a view isn't supported yet. bool isEditable = m_model->isEditable() && !db->readOnly(); ui->actionNewRecord->setEnabled(isEditable); ui->actionDeleteRecord->setEnabled(isEditable && rows != 0); if(rows > 1) ui->actionDeleteRecord->setText(tr("Delete Records")); else ui->actionDeleteRecord->setText(tr("Delete Record")); } void TableBrowser::duplicateRecord(int currentRow) { auto row = m_model->dittoRecord(currentRow); if (row.isValid()) ui->dataTable->setCurrentIndex(row); else QMessageBox::warning(this, qApp->applicationName(), db->lastError()); } void TableBrowser::headerClicked(int logicalindex) { BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; // Set minimum width to the vertical header in order to avoid flickering when sorting. ui->dataTable->verticalHeader()->setMinimumWidth(ui->dataTable->verticalHeader()->width()); // Get the current list of sort columns auto& columns = settings.sortColumns; // Get the name of the column the user clicked on std::string column = model()->headerData(logicalindex, Qt::Horizontal, Qt::EditRole).toString().toStdString(); // Before sorting, first check if the Control key is pressed. If it is, we want to append this column to the list of sort columns. If it is not, // we want to sort only by the new column. if(QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) { // Multi column sorting // If the column was control+clicked again, change its sort order. // If not already in the sort order, add the column as a new sort column to the list. bool present = false; for(sqlb::OrderBy& sortedCol : columns) { if(sortedCol.expr == column) { sortedCol.direction = (sortedCol.direction == sqlb::OrderBy::Ascending ? sqlb::OrderBy::Descending : sqlb::OrderBy::Ascending); present = true; break; } } if(!present) columns.emplace_back(column, sqlb::OrderBy::Ascending); } else { // Single column sorting // If we have exactly one sort column and it is the column which was just clicked, change its sort order. // If not, clear the list of sorting columns and replace it by a single new sort column. if(columns.size() == 1 && columns.front().expr == column) { columns.front().direction = (columns.front().direction == sqlb::OrderBy::Ascending ? sqlb::OrderBy::Descending : sqlb::OrderBy::Ascending); } else { columns.clear(); columns.emplace_back(column, sqlb::OrderBy::Ascending); } } // Do the actual sorting ui->dataTable->sortByColumns(columns); ui->actionClearSorting->setEnabled(columns.size() > 0); // select the first item in the column so the header is bold // we might try to select the last selected item ui->dataTable->setCurrentIndex(ui->dataTable->currentIndex().sibling(0, logicalindex)); emit updatePlot(ui->dataTable, m_model, &m_settings[currentlyBrowsedTableName()], true); emit projectModified(); } void TableBrowser::updateColumnWidth(int section, int /*old_size*/, int new_size) { std::unordered_set selectedCols = ui->dataTable->selectedCols(); sqlb::ObjectIdentifier tableName = currentlyBrowsedTableName(); if (selectedCols.find(static_cast(section)) == selectedCols.end()) { if (m_settings[tableName].columnWidths[section] != new_size) { emit projectModified(); m_settings[tableName].columnWidths[section] = new_size; } } else { ui->dataTable->blockSignals(true); for(size_t col : selectedCols) { ui->dataTable->setColumnWidth(static_cast(col), new_size); if (m_settings[tableName].columnWidths[static_cast(col)] != new_size) { emit projectModified(); m_settings[tableName].columnWidths[static_cast(col)] = new_size; } } ui->dataTable->blockSignals(false); } } void TableBrowser::showDataColumnPopupMenu(const QPoint& pos) { // Get the index of the column which the user has clicked on and store it in the action. This is sort of hack-ish and it might be the heat in my room // but I haven't come up with a better solution so far int logical_index = ui->dataTable->horizontalHeader()->logicalIndexAt(pos); if(logical_index == -1) // Don't open the popup menu if the user hasn't clicked on a column header return; ui->actionBrowseTableEditDisplayFormat->setProperty("clicked_column", logical_index); // Calculate the proper position for the context menu and display it popupHeaderMenu->exec(ui->dataTable->horizontalHeader()->mapToGlobal(pos)); } void TableBrowser::showRecordPopupMenu(const QPoint& pos) { int row = ui->dataTable->verticalHeader()->logicalIndexAt(pos); if (row == -1) return; QMenu popupRecordMenu(this); // "Delete and duplicate records" can only be done on writable objects if(db->getTableByName(currentlyBrowsedTableName()) && !db->readOnly()) { // Select the row if it is not already in the selection. QModelIndexList rowList = ui->dataTable->selectionModel()->selectedRows(); bool found = false; for (const QModelIndex& index : qAsConst(rowList)) { if (row == index.row()) { found = true; break; } } if (!found) ui->dataTable->selectRow(row); rowList = ui->dataTable->selectionModel()->selectedRows(); QString duplicateText = rowList.count() > 1 ? tr("Duplicate records") : tr("Duplicate record"); QAction* action = new QAction(duplicateText, &popupRecordMenu); // Set shortcut for documentation purposes (the actual functional shortcut is not set here) action->setShortcut(QKeySequence(tr("Ctrl+\""))); popupRecordMenu.addAction(action); connect(action, &QAction::triggered, this, [rowList, this]() { for (const QModelIndex& index : rowList) duplicateRecord(index.row()); }); QAction* deleteRecordAction = new QAction(QIcon(":icons/delete_record"), ui->actionDeleteRecord->text(), &popupRecordMenu); popupRecordMenu.addAction(deleteRecordAction); connect(deleteRecordAction, &QAction::triggered, this, [&]() { deleteRecord(); }); popupRecordMenu.addSeparator(); } // "Adjust rows" can be done on any object QAction* adjustRowHeightAction = new QAction(tr("Adjust rows to contents"), &popupRecordMenu); adjustRowHeightAction->setCheckable(true); adjustRowHeightAction->setChecked(m_adjustRows); popupRecordMenu.addAction(adjustRowHeightAction); connect(adjustRowHeightAction, &QAction::toggled, this, [&](bool checked) { m_adjustRows = checked; refresh(); }); popupRecordMenu.exec(ui->dataTable->verticalHeader()->mapToGlobal(pos)); } void TableBrowser::addRecord() { int row = m_model->rowCount(); // If table has pseudo_pk, then it must be an editable view. Jump straight to inserting by pop-up dialog. if(!m_model->hasPseudoPk() && m_model->insertRow(row)) { selectTableLine(row); } else { // Error inserting empty row. // User has to provide values accomplishing the constraints. Open Add Record Dialog. insertValues(); } updateRecordsetLabel(); } void TableBrowser::insertValues() { std::vector pseudo_pk = m_model->hasPseudoPk() ? m_model->pseudoPk() : std::vector(); AddRecordDialog dialog(*db, currentlyBrowsedTableName(), this, pseudo_pk); if (dialog.exec()) refresh(); } void TableBrowser::deleteRecord() { if(ui->dataTable->selectionModel()->hasSelection()) { // If only filter header is selected if(ui->dataTable->selectionModel()->selectedIndexes().isEmpty()) return; while(ui->dataTable->selectionModel()->hasSelection()) { std::set row_set = ui->dataTable->rowsInSelection(); int first_selected_row = static_cast(*row_set.begin()); int rows_to_remove = 0; int previous_row = first_selected_row - 1; // Non-contiguous selection: remove only the contiguous // rows in the selection in each cycle until the entire // selection has been removed. for(size_t row : row_set) { if(previous_row == static_cast(row - 1)) rows_to_remove++; else break; } if(!m_model->removeRows(first_selected_row, rows_to_remove)) { QMessageBox::warning(this, QApplication::applicationName(), tr("Error deleting record:\n%1").arg(db->lastError())); break; } } } else { QMessageBox::information( this, QApplication::applicationName(), tr("Please select a record first")); } updateRecordsetLabel(); } void TableBrowser::navigatePrevious() { int curRow = ui->dataTable->currentIndex().row(); curRow -= ui->dataTable->numVisibleRows() - 1; if(curRow < 0) curRow = 0; selectTableLine(curRow); } void TableBrowser::navigateNext() { int curRow = ui->dataTable->currentIndex().row(); curRow += ui->dataTable->numVisibleRows() - 1; if(curRow >= m_model->rowCount()) curRow = m_model->rowCount() - 1; selectTableLine(curRow); } void TableBrowser::navigateBegin() { selectTableLine(0); } void TableBrowser::navigateEnd() { selectTableLine(m_model->rowCount()-1); } void TableBrowser::navigateGoto() { int row = ui->editGoto->text().toInt(); if(row <= 0) row = 1; if(row > m_model->rowCount()) row = m_model->rowCount(); selectTableLine(row - 1); ui->editGoto->setText(QString::number(row)); } void TableBrowser::selectTableLine(int lineToSelect) { ui->dataTable->selectTableLine(lineToSelect); } void TableBrowser::clearSorting() { // Get the current list of sort columns auto& columns = m_settings[currentlyBrowsedTableName()].sortColumns; columns.clear(); // Set cleared vector of sort-by columns m_model->sort(columns); ui->actionClearSorting->setEnabled(false); } void TableBrowser::editDisplayFormat() { // Get the current table name and fetch its table object, then retrieve the fields of that table and look up the index of the clicked table header // section using it as the table field array index. Subtract one from the header index to get the column index because in the the first (though hidden) // column is always the rowid column. Ultimately, get the column name from the column object sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); size_t field_number = sender()->property("clicked_column").toUInt(); QString field_name = QString::fromStdString(db->getTableByName(current_table)->fields.at(field_number-1).name()); // Get the current display format of the field QString current_displayformat = m_settings[current_table].displayFormats[field_number]; // Open the dialog ColumnDisplayFormatDialog dialog(*db, current_table, field_name, current_displayformat, this); if(dialog.exec()) { // Set the newly selected display format QString new_format = dialog.selectedDisplayFormat(); if(new_format.size()) m_settings[current_table].displayFormats[field_number] = new_format; else m_settings[current_table].displayFormats.erase(field_number); emit projectModified(); // Refresh view refresh(); } } void TableBrowser::exportCsvFilteredTable() { ExportDataDialog dialog(*db, ExportDataDialog::ExportFormatCsv, this, m_model->customQuery(false)); dialog.exec(); } void TableBrowser::exportJsonFilteredTable() { ExportDataDialog dialog(*db, ExportDataDialog::ExportFormatJson, this, m_model->customQuery(false)); dialog.exec(); } void TableBrowser::saveFilterAsView() { // Save as view a custom query without rowid emit createView(m_model->customQuery(false)); } void TableBrowser::setTableEncoding(bool forAllTables) { // Get the old encoding QString encoding = m_model->encoding(); // Ask the user for a new encoding bool ok; QString question; QStringList availableCodecs = toStringList(QTextCodec::availableCodecs()); availableCodecs.removeDuplicates(); int currentItem = availableCodecs.indexOf(encoding); if(forAllTables) question = tr("Please choose a new encoding for all tables."); else question = tr("Please choose a new encoding for this table."); encoding = QInputDialog::getItem(this, tr("Set encoding"), tr("%1\nLeave the field empty for using the database encoding.").arg(question), availableCodecs, currentItem, true, // editable &ok); // Only set the new encoding if the user clicked the OK button if(ok) { // Check if encoding is valid if(!encoding.isEmpty() && !QTextCodec::codecForName(encoding.toUtf8())) { QMessageBox::warning(this, qApp->applicationName(), tr("This encoding is either not valid or not supported.")); return; } // Set encoding for current table m_model->setEncoding(encoding); // Save encoding for this table m_settings[currentlyBrowsedTableName()].encoding = encoding; // Set default encoding if requested to and change all stored table encodings if(forAllTables) { m_defaultEncoding = encoding; for(auto it=m_settings.begin();it!=m_settings.end();++it) it->second.encoding = encoding; } emit projectModified(); } } void TableBrowser::setDefaultTableEncoding() { setTableEncoding(true); } void TableBrowser::copyColumnName(){ sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); int col_index = ui->actionBrowseTableEditDisplayFormat->property("clicked_column").toInt(); QString field_name = QString::fromStdString(db->getTableByName(current_table)->fields.at(col_index - 1).name()); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(field_name); } void TableBrowser::jumpToRow(const sqlb::ObjectIdentifier& table, std::string column, const QByteArray& value) { // First check if table exists sqlb::TablePtr obj = db->getTableByName(table); if(!obj) return; // If no column name is set, assume the primary key is meant if(!column.size()) column = obj->primaryKeyColumns().front().name(); // If column doesn't exist don't do anything auto column_it = sqlb::findField(obj, column); if(column_it == obj->fields.end()) return; // Jump to table setCurrentTable(table); // Set filter m_settings[table].filterValues[column_it->name()] = value; refresh(); } static QString replaceInValue(QString value, const QString& find, const QString& replace, Qt::MatchFlags flags) { // Helper function which replaces a string in another string by a third string. It uses regular expressions if told so. if(flags.testFlag(Qt::MatchRegExp)) { QRegularExpression reg_exp(find, (flags.testFlag(Qt::MatchCaseSensitive) ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption)); if(!flags.testFlag(Qt::MatchContains)) { #if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) reg_exp.setPattern("\\A(" + reg_exp.pattern() + ")\\Z"); #else reg_exp.setPattern(QRegularExpression::anchoredPattern(reg_exp.pattern())); #endif } return value.replace(reg_exp, replace); } else { return value.replace(find, replace, flags.testFlag(Qt::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive); } } void TableBrowser::find(const QString& expr, bool forward, bool include_first, ReplaceMode replace) { // Reset the colour of the line edit, assuming there is no error. ui->editFindExpression->setStyleSheet(""); // You are not allowed to search for an empty string if(expr.isEmpty()) return; // Get the cell from which the search should be started. If there is a selected cell, use that. If there is no selected cell, start at the first cell. QModelIndex start; if(ui->dataTable->selectionModel()->hasSelection()) start = ui->dataTable->selectionModel()->selectedIndexes().front(); else start = m_model->index(0, 0); // Prepare the match flags with all the search settings Qt::MatchFlags flags = Qt::MatchWrap; if(ui->checkFindCaseSensitive->isChecked()) flags |= Qt::MatchCaseSensitive; if(ui->checkFindWholeCell->isChecked()) flags |= Qt::MatchFixedString; else flags |= Qt::MatchContains; if(ui->checkFindRegEx->isChecked()) flags |= Qt::MatchRegExp; // Prepare list of columns to search in. We only search in non-hidden rows std::vector column_list; sqlb::ObjectIdentifier tableName = currentlyBrowsedTableName(); if(m_settings[tableName].showRowid) column_list.push_back(0); for(int i=1;icolumnCount();i++) { if(contains(m_settings[tableName].hiddenColumns, i) == false) column_list.push_back(i); else if(m_settings[tableName].hiddenColumns[i] == false) column_list.push_back(i); } // Are we only searching for text or are we supposed to replace text? switch(replace) { case ReplaceMode::NoReplace: { // Perform the actual search using the model class const auto match = m_model->nextMatch(start, column_list, expr, flags, !forward, include_first); // Select the next match if we found one if(match.isValid()) ui->dataTable->setCurrentIndex(match); // Make the expression control red if no results were found if(!match.isValid()) ui->editFindExpression->setStyleSheet("QLineEdit {color: white; background-color: rgb(255, 102, 102)}"); } break; case ReplaceMode::ReplaceNext: { // Find the next match const auto match = m_model->nextMatch(start, column_list, expr, flags, !forward, include_first); // If there was a match, perform the replacement on the cell and select it if(match.isValid()) { m_model->setData(match, replaceInValue(match.data(Qt::EditRole).toString(), expr, ui->editReplaceExpression->text(), flags)); ui->dataTable->setCurrentIndex(match); } // Make the expression control red if no results were found if(!match.isValid()) ui->editFindExpression->setStyleSheet("QLineEdit {color: white; background-color: rgb(255, 102, 102)}"); } break; case ReplaceMode::ReplaceAll: { // Find all matches std::set all_matches; while(true) { // Find the next match const auto match = m_model->nextMatch(start, column_list, expr, flags, !forward, include_first); // If there was a match, perform the replacement and continue from that position. If there was no match, stop looking for other matches. // Additionally, keep track of all the matches so far in order to avoid running over them again indefinitely, e.g. when replacing "1" by "10". if(match.isValid() && all_matches.find(match) == all_matches.end()) { all_matches.insert(match); m_model->setData(match, replaceInValue(match.data(Qt::EditRole).toString(), expr, ui->editReplaceExpression->text(), flags)); // Start searching from the last match onwards in order to not search through the same cells over and over again. start = match; include_first = false; } else { break; } } // Make the expression control red if no results were found if(!all_matches.empty()) QMessageBox::information(this, qApp->applicationName(), tr("%1 replacement(s) made.").arg(all_matches.size())); else ui->editFindExpression->setStyleSheet("QLineEdit {color: white; background-color: rgb(255, 102, 102)}"); } break; } } void TableBrowser::fetchedData() { updateRecordsetLabel(); // Don't resize the columns more than once to fit their contents. This is necessary because the finishedFetch signal of the model // is emitted for each loaded prefetch block and we want to avoid column resizes while scrolling down. if(m_columnsResized) return; m_columnsResized = true; // Set column widths according to their contents but make sure they don't exceed a certain size ui->dataTable->resizeColumnsToContents(); for(int i = 0; i < m_model->columnCount(); i++) { if(ui->dataTable->columnWidth(i) > 300) ui->dataTable->setColumnWidth(i, 300); } } sqlitebrowser-sqlitebrowser-5733cb7/src/TableBrowser.h000066400000000000000000000141221463772530400232270ustar00rootroot00000000000000#ifndef TABLEBROWSER_H #define TABLEBROWSER_H #include "CondFormat.h" #include "PlotDock.h" #include "sql/Query.h" #include #include #include #include #include #include class DBBrowserDB; class ExtendedTableWidget; class SqliteTableModel; class QAbstractItemModel; class QIntValidator; namespace Ui { class TableBrowser; } struct BrowseDataTableSettings { using CondFormatMap = std::map>; std::vector sortColumns; std::map columnWidths; std::map filterValues; CondFormatMap condFormats; CondFormatMap rowIdFormats; std::map displayFormats; bool showRowid; QString encoding; QString plotXAxis; std::vector> plotYAxes; QString unlockViewPk; std::map hiddenColumns; std::vector globalFilters; size_t frozenColumns; BrowseDataTableSettings() : showRowid(false), plotYAxes({std::map(), std::map()}), unlockViewPk("_rowid_"), frozenColumns(0) { } }; class TableBrowser : public QWidget { Q_OBJECT public: explicit TableBrowser(DBBrowserDB* _db, QWidget* parent = nullptr); ~TableBrowser() override; void reset(); static void resetSharedSettings(); sqlb::ObjectIdentifier currentlyBrowsedTableName() const; static std::map allSettings() { return m_settings; } static BrowseDataTableSettings& settings(const sqlb::ObjectIdentifier& object); static void setSettings(const sqlb::ObjectIdentifier& table, const BrowseDataTableSettings& table_settings); void setStructure(QAbstractItemModel* model, const sqlb::ObjectIdentifier& old_table = sqlb::ObjectIdentifier{}); SqliteTableModel* model() { return m_model; } QModelIndex currentIndex() const; static void setDefaultEncoding(const QString& encoding) { m_defaultEncoding = encoding; } static QString defaultEncoding() { return m_defaultEncoding; } public slots: void setEnabled(bool enable); void refresh(); void clearFilters(); void reloadSettings(); void setCurrentTable(const sqlb::ObjectIdentifier& name); void updateRecordsetLabel(); void jumpToRow(const sqlb::ObjectIdentifier& table, std::string column, const QByteArray& value); signals: void projectModified(); void selectionChanged(QModelIndex index); void selectionChangedByDoubleClick(QModelIndex index); void statusMessageRequested(QString message); void updatePlot(ExtendedTableWidget* tableWidget, SqliteTableModel* model, BrowseDataTableSettings* settings, bool keepOrResetSelection); void createView(std::string sql); void requestFileOpen(QString file); void currentTableChanged(sqlb::ObjectIdentifier table); void foreignKeyClicked(sqlb::ObjectIdentifier table, std::string column, QByteArray value); void dataAboutToBeEdited(const QModelIndex& index); void prepareForFilter(); void newDockRequested(); private slots: void clear(); void updateFilter(size_t column, const QString& value); void addCondFormatFromFilter(size_t column, const QString& value); void addCondFormat(bool isRowIdFormat, size_t column, const CondFormat& newCondFormat); void clearAllCondFormats(size_t column); void clearRowIdFormats(const QModelIndex index); void editCondFormats(size_t column); void enableEditing(bool enable_edit); void showRowidColumn(bool show); void freezeColumns(size_t columns); void unlockViewEditing(bool unlock, QString pk = QString()); void hideColumns(int column = -1, bool hide = true); void showAllColumns(); void updateInsertDeleteRecordButton(); void duplicateRecord(int currentRow); void headerClicked(int logicalindex); void updateColumnWidth(int section, int /*old_size*/, int new_size); void showDataColumnPopupMenu(const QPoint& pos); void showRecordPopupMenu(const QPoint& pos); void addRecord(); void insertValues(); void deleteRecord(); void navigatePrevious(); void navigateNext(); void navigateBegin(); void navigateEnd(); void navigateGoto(); void selectTableLine(int lineToSelect); void clearSorting(); void editDisplayFormat(); void exportCsvFilteredTable(); void exportJsonFilteredTable(); void saveFilterAsView(); void setTableEncoding(bool forAllTables = false); void setDefaultTableEncoding(); void copyColumnName(); void fetchedData(); private: enum class ReplaceMode { NoReplace, ReplaceNext, ReplaceAll, }; void find(const QString& expr, bool forward, bool include_first = false, ReplaceMode replace = ReplaceMode::NoReplace); private: Ui::TableBrowser* ui; QIntValidator* gotoValidator; QMenu* popupNewRecordMenu; QMenu* popupSaveFilterAsMenu; QMenu* popupHeaderMenu; DBBrowserDB* db; QAbstractItemModel* dbStructureModel; /// the table model used in the "Browse Data" page (re-used and /// re-initialized when switching to another table) SqliteTableModel* m_model; static std::map m_settings; // This is static, so settings are shared between instances static QString m_defaultEncoding; Palette m_condFormatPalette; bool m_adjustRows; bool m_columnsResized; void modifySingleFormat(const bool isRowIdFormat, const QString& filter, const QModelIndex refIndex, std::function changeFunction); void modifyFormat(std::function changeFunction); sqlb::Query buildQuery(const BrowseDataTableSettings& storedData, const sqlb::ObjectIdentifier& tablename) const; void applyModelSettings(const BrowseDataTableSettings& storedData, const sqlb::Query& query); void applyViewportSettings(const BrowseDataTableSettings& storedData, const sqlb::ObjectIdentifier& tablename); void generateFilters(); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/TableBrowser.ui000066400000000000000000001367371463772530400234360ustar00rootroot00000000000000 TableBrowser 0 0 695 400 Browse Data 1 0 0 0 0 2 2 &Table: comboBrowseTable 150 0 Select a table to browse data Use this list to select a table to be displayed in the database view 30 QComboBox::AdjustToContents Qt::ToolButtonIconOnly Qt::Horizontal QSizePolicy::MinimumExpanding 0 20 5 2 0 2 0 50 16777215 1 Qt::ToolButtonIconOnly true This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. QAbstractItemView::NoEditTriggers QAbstractItemView::DragDrop Qt::CopyAction QAbstractItemView::ExtendedSelection 16777215 62 QFrame::StyledPanel QFrame::Raised 1 1 1 1 1 3 0 0 0 0 Qt::DefaultContextMenu Text pattern to find considering the checks in this frame Find in table true Find previous match [Shift+F3] Find previous match with wrapping :/icons/up:/icons/up Shift+F3 Find next match [Enter, F3] Find next match with wrapping :/icons/down:/icons/down F3 The found pattern must match in letter case Case Sensitive The found pattern must be a whole word Whole Cell Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Qt::Horizontal 40 20 Close Find Bar Close Find Bar :/icons/close:/icons/close true 3 0 0 0 0 Qt::DefaultContextMenu Text to replace with Replace with true Replace next match Replace Replace all matches Replace all Qt::Horizontal 40 20 2 2 2 2 <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> |< :/icons/resultset_first:/icons/resultset_first Scroll one page upwards <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> < :/icons/resultset_previous:/icons/resultset_previous 0 - 0 of 0 Scroll one page downwards <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> > :/icons/run:/icons/run Scroll to the end <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> >| :/icons/run_line:/icons/run_line Qt::Horizontal 40 20 <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> Go to: Enter record number to browse Type a record number in this area and click the Go to: button to display the record in the database view 1 true Show rowid column Toggle the visibility of the rowid column true Unlock view editing This unlocks the current view for editing. However, you will need appropriate triggers for editing. Edit display format Edit the display format of the data in this column :/icons/add_record:/icons/add_record New Record Insert a new record in the current table Insert a new record in the current table <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> :/icons/delete_record:/icons/delete_record Delete Record Delete the current record This button deletes the record or records currently selected in the table This button deletes the record or records currently selected in the table :/icons/add_record:/icons/add_record New Record Insert new record using default values in browsed table Insert new record using default values in browsed table Insert Values... Open a dialog for inserting values in a new record Open a dialog for inserting values in a new record Export to &CSV Export the filtered data to CSV Export the filtered data to CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Export to &JSON Export the filtered data to JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Save as &view Save the current filter, sort column and display formats as a view Save the current filter, sort column and display formats as a view This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. :/icons/save_table:/icons/save_table Save Table As... Save the table as currently displayed Save the table as currently displayed <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> Hide column(s) Hide selected column(s) Show all columns Show all columns that were hidden Set encoding Change the encoding of the text in the table cells Set encoding for all tables Change the default encoding assumed for all tables in the database Copy column name Copy the database table column name to your clipboard :/icons/clear_filters:/icons/clear_filters Clear Filters Clear all filters This button clears all the filters set in the header input fields for the currently browsed table. This button clears all the filters set in the header input fields for the currently browsed table. :/icons/clear_sorting:/icons/clear_sorting Clear Sorting Reset the order of rows to the default This button clears the sorting columns specified for the currently browsed table and returns to the default order. This button clears the sorting columns specified for the currently browsed table and returns to the default order. :/icons/print:/icons/print Print Print currently browsed table data Print currently browsed table data. Print selection if more than one cell is selected. Ctrl+P Qt::WidgetShortcut :/icons/new_tab:/icons/new_tab New Data Browser Add a new docked Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. :/icons/refresh:/icons/refresh Refresh Refresh the data in the selected table This button refreshes the data in the currently selected table. F5 Qt::WidgetShortcut true :/icons/find:/icons/find Find in cells Open the find tool bar which allows you to search for values in the table view below. true :/icons/text_bold:/icons/text_bold Bold Bold Ctrl+B true :/icons/text_italic:/icons/text_italic Italic Italic true :/icons/text_underline:/icons/text_underline Underline Underline Ctrl+U true :/icons/text_align_right:/icons/text_align_right Align Right Align Right true :/icons/text_align_left:/icons/text_align_left Align Left Align Left true :/icons/text_align_center:/icons/text_align_center Center Horizontally Center Horizontally true :/icons/text_align_justify:/icons/text_align_justify Justify Justify :/icons/edit_cond_formats:/icons/edit_cond_formats Edit Conditional Formats... Edit Conditional Formats... Edit conditional formats for the current column :/icons/clear_cond_formats:/icons/clear_cond_formats Clear Format Clear All Formats Clear all cell formatting from selected cells and all conditional formats from selected columns Clear all cell formatting from selected cells and all conditional formats from selected columns :/icons/foreground_color:/icons/foreground_color Font Color Font Color :/icons/background_color:/icons/background_color Background Color Background Color true :/icons/cond_formats:/icons/cond_formats Toggle Format Toolbar Show/hide format toolbar This button shows or hides the formatting toolbar of the Data Browser This button shows or hides the formatting toolbar of the Data Browser Select column Ctrl+Space true :/icons/text_replace:/icons/text_replace Replace Replace text in cells true Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally ExtendedTableWidget QTableWidget
ExtendedTableWidget.h
foreignKeyClicked(sqlb::ObjectIdentifier,QString,QByteArray)
FilterLineEdit QLineEdit
FilterLineEdit.h
comboBrowseTable editGlobalFilter fontComboBox fontSizeBox dataTable editFindExpression editReplaceExpression buttonFindPrevious buttonFindNext checkFindCaseSensitive checkFindWholeCell checkFindRegEx buttonFindClose buttonReplaceNext buttonReplaceAll buttonBegin buttonPrevious buttonNext buttonEnd buttonGoto editGoto comboBrowseTable activated(QString) TableBrowser refresh() 159 31 399 299 buttonPrevious clicked() TableBrowser navigatePrevious() 55 395 399 299 buttonNext clicked() TableBrowser navigateNext() 140 395 399 299 buttonGoto clicked() TableBrowser navigateGoto() 452 397 399 299 editGoto returnPressed() TableBrowser navigateGoto() 648 397 399 299 buttonEnd clicked() TableBrowser navigateEnd() 170 395 499 314 buttonBegin clicked() TableBrowser navigateBegin() 25 395 499 314 actionShowRowidColumn triggered(bool) TableBrowser showRowidColumn(bool) -1 -1 518 314 actionUnlockViewEditing toggled(bool) TableBrowser unlockViewEditing(bool) -1 -1 518 314 actionBrowseTableEditDisplayFormat triggered() TableBrowser editDisplayFormat() -1 -1 518 314 actionNewRecord triggered() TableBrowser addRecord() -1 -1 518 314 actionDeleteRecord triggered() TableBrowser deleteRecord() -1 -1 399 299 newRecordAction triggered() TableBrowser addRecord() -1 -1 518 314 insertValuesAction triggered() TableBrowser insertValues() -1 -1 20 20 actionFilteredTableExportCsv triggered() TableBrowser exportCsvFilteredTable() -1 -1 518 314 actionFilteredTableExportJson triggered() TableBrowser exportJsonFilteredTable() -1 -1 518 314 actionFilterSaveAsView triggered() TableBrowser saveFilterAsView() -1 -1 518 314 actionSetTableEncoding triggered() TableBrowser setTableEncoding() -1 -1 518 314 actionCopyColumnName triggered() TableBrowser copyColumnName() -1 -1 518 314 actionSetAllTablesEncoding triggered() TableBrowser setDefaultTableEncoding() -1 -1 518 314 actionHideColumns triggered() TableBrowser hideColumns() -1 -1 518 314 actionPrintTable triggered() dataTable openPrintDialog() -1 -1 326 291 actionClearFilters triggered() TableBrowser clearFilters() -1 -1 -1 -1 actionClearSorting triggered() TableBrowser clearSorting() -1 -1 -1 -1 actionShowAllColumns triggered() TableBrowser showAllColumns() -1 -1 -1 -1 refresh() selectionChanged(QModelIndex) navigatePrevious() navigateNext() navigateBegin() navigateEnd() navigateGoto() showRowidColumn(bool) unlockViewEditing(bool) editDisplayFormat() addRecord() deleteRecord() insertValues() exportCsvFilteredTable exportJsonFilteredTable saveFilterAsView setDefaultTableEncoding() hideColumns() setTableEncoding() clearFilters() clearSorting() showAllColumns()
sqlitebrowser-sqlitebrowser-5733cb7/src/TableBrowserDock.cpp000066400000000000000000000071161463772530400243700ustar00rootroot00000000000000#include #include #include #include #include "TableBrowser.h" #include "TableBrowserDock.h" #include "MainWindow.h" TableBrowserDock::TableBrowserDock(QWidget* parent, MainWindow* mainWindow) : QDockWidget(parent), main_window(mainWindow), browser(new TableBrowser(&mainWindow->db, this)) { // Set context menu setContextMenuPolicy(Qt::CustomContextMenu); // Normally dock widgets are not deleted when they are closed. Make sure to delete these // because they can consume a lot of memory and we would need to figure out if they are // visible whenever we loop over them. setAttribute(Qt::WA_DeleteOnClose, true); // Set object name static unsigned int counter = 0; setObjectName("dockBrowse" + QString::number(++counter)); // Connect dock signals connect(this, &TableBrowserDock::customContextMenuRequested, this, &TableBrowserDock::showContextMenuTableBrowserTabBar); // Connect browser signals connect(browser, &TableBrowser::currentTableChanged, this, [this](const sqlb::ObjectIdentifier& table) { // Only update dock name when no custom name was set if(!property("custom_title").toBool()) setWindowTitle(QString::fromStdString(table.toDisplayString())); }); connect(browser, &TableBrowser::newDockRequested, this, &TableBrowserDock::newDockRequested); // Update view browser->refresh(); // Set browser widget setWidget(browser); } void TableBrowserDock::closeEvent(QCloseEvent*) { emit closed(); } void TableBrowserDock::setFocusStyle(bool on) { // Highlight title bar when dock widget is active if(on) setStyleSheet(QStringLiteral( "QDockWidget::title {" "background:palette(AlternateBase);" "text-align: center;" "border-bottom: 2px solid palette(highlight);" "}")); else setStyleSheet(QStringLiteral( "QDockWidget::title {" "text-align: center;" "}")); } void TableBrowserDock::showContextMenuTableBrowserTabBar(const QPoint& pos) { // Prepare all menu actions QAction* actionNewDock = new QAction(this); actionNewDock->setText(tr("New Data Browser")); connect(actionNewDock, &QAction::triggered, this, &TableBrowserDock::newDockRequested); QAction* actionRename = new QAction(this); actionRename->setText(tr("Rename Data Browser")); connect(actionRename, &QAction::triggered, this, [this]() { renameTableBrowserTab(); }); QAction* actionClose = new QAction(this); actionClose->setText(tr("Close Data Browser")); connect(actionClose, &QAction::triggered, this, [this]() { deleteLater(); }); // Show menu QMenu* menuTabs = new QMenu(this); menuTabs->addAction(actionNewDock); menuTabs->addAction(actionRename); menuTabs->addAction(actionClose); menuTabs->exec(mapToGlobal(pos)); } void TableBrowserDock::renameTableBrowserTab() { QString new_name = QInputDialog::getText(this, qApp->applicationName(), tr("Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut."), QLineEdit::EchoMode::Normal, windowTitle()); if(!new_name.isNull()) // Don't do anything if the Cancel button was clicked { setWindowTitle(new_name); setProperty("custom_title", true); } } sqlitebrowser-sqlitebrowser-5733cb7/src/TableBrowserDock.h000066400000000000000000000012001463772530400240210ustar00rootroot00000000000000#ifndef TABLEBROWSERDOCK_H #define TABLEBROWSERDOCK_H #include class MainWindow; class TableBrowser; class TableBrowserDock : public QDockWidget { Q_OBJECT public: explicit TableBrowserDock(QWidget* parent, MainWindow* mainWindow); void setFocusStyle(bool on); TableBrowser* tableBrowser() { return browser; } signals: void closed(); void newDockRequested(); protected: void closeEvent(QCloseEvent* event) override; private: MainWindow* main_window; TableBrowser* browser; void showContextMenuTableBrowserTabBar(const QPoint& pos); void renameTableBrowserTab(); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/VacuumDialog.cpp000066400000000000000000000030401463772530400235440ustar00rootroot00000000000000#include "VacuumDialog.h" #include "ui_VacuumDialog.h" #include "sqlitedb.h" #include VacuumDialog::VacuumDialog(DBBrowserDB* _db, QWidget* parent) : QDialog(parent), ui(new Ui::VacuumDialog), db(_db) { // Create UI ui->setupUi(this); // Show warning if DB is dirty ui->labelSavepointWarning->setVisible(db->getDirty()); // Populate list of objects to compact. We just support vacuuming the different schemas here. for(const auto& it : db->schemata) { QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeDatabases); item->setText(0, QString::fromStdString(it.first)); item->setIcon(0, QIcon(QString(":icons/database"))); ui->treeDatabases->addTopLevelItem(item); } // Select the first item which should always be the main schema ui->treeDatabases->setCurrentItem(ui->treeDatabases->topLevelItem(0)); } VacuumDialog::~VacuumDialog() { delete ui; } void VacuumDialog::accept() { if(ui->treeDatabases->selectedItems().count() == 0) return QDialog::reject(); QApplication::setOverrideCursor(Qt::WaitCursor); // Commit all changes first db->releaseAllSavepoints(); // Loop through all selected databases and vacuum them individually const QList selection = ui->treeDatabases->selectedItems(); for(const QTreeWidgetItem* item : selection) db->executeSQL("VACUUM " + sqlb::escapeIdentifier(item->text(0).toStdString()), false); QApplication::restoreOverrideCursor(); QDialog::accept(); } sqlitebrowser-sqlitebrowser-5733cb7/src/VacuumDialog.h000066400000000000000000000006211463772530400232130ustar00rootroot00000000000000#ifndef VACUUMDIALOG_H #define VACUUMDIALOG_H #include namespace Ui { class VacuumDialog; } class DBBrowserDB; class VacuumDialog : public QDialog { Q_OBJECT public: explicit VacuumDialog(DBBrowserDB* _db, QWidget* parent = nullptr); ~VacuumDialog() override; private: Ui::VacuumDialog* ui; DBBrowserDB* db; protected slots: void accept() override; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/VacuumDialog.ui000066400000000000000000000061001463772530400233770ustar00rootroot00000000000000 VacuumDialog 0 0 475 439 Compact Database 75 true Warning: Compacting the database will commit all of your changes. true 5 Please select the databases to co&mpact: treeDatabases QAbstractItemView::NoEditTriggers false QAbstractItemView::ExtendedSelection false false false false 1 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok treeDatabases buttonBox buttonBox accepted() VacuumDialog accept() 222 374 157 274 buttonBox rejected() VacuumDialog reject() 290 380 286 274 sqlitebrowser-sqlitebrowser-5733cb7/src/app.plist000066400000000000000000000041171463772530400223230ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleDocumentTypes CFBundleTypeExtensions db db3 sqlite sqlite3 CFBundleTypeName Database Document CFBundleTypeOSTypes **** CFBundleTypeRole Editor CFBundleTypeExtensions sqbpro CFBundleTypeName DB Browser for SQLite Project CFBundleTypeOSTypes **** CFBundleTypeRole Editor CFBundleTypeExtensions * CFBundleTypeName Other Document Type CFBundleTypeOSTypes **** CFBundleTypeRole Editor CFBundleExecutable @EXECUTABLE@ CFBundleGetInfoString 3.13.99 CFBundleIconFile @ICON@ CFBundleIdentifier net.sourceforge.sqlitebrowser CFBundleInfoDictionaryVersion 6.0 CFBundleName DB Browser for SQLite CFBundlePackageType APPL CFBundleShortVersionString 3.13.99 CFBundleSignature SqLB CFBundleVersion 3.13.99 NSPrincipalClass NSApplication NSHighResolutionCapable NSSupportsAutomaticGraphicsSwitching sqlitebrowser-sqlitebrowser-5733cb7/src/certs/000077500000000000000000000000001463772530400216035ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/certs/CaCerts.qrc000066400000000000000000000003601463772530400236350ustar00rootroot00000000000000 ca-chain-development.crt ca-chain-docker.crt public.cert.pem sqlitebrowser-sqlitebrowser-5733cb7/src/certs/ca-chain-development.crt000066400000000000000000000102101463772530400262720ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIF7DCCA9SgAwIBAgIJAKtqE1Cz9EmfMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDERMA8GA1UECgwIREJIdWIuaW8xJzAl BgNVBAsMHkRCSHViLmlvIENlcnRpZmljYXRlIEF1dGhvcml0eTElMCMGA1UEAwwc REJIdWIuaW8gREVWRUxPUE1FTlQgUm9vdCBDQTAeFw0xNzAzMDQxMDE1MzBaFw0z NzAzMDQxMDE1MzBaMIGCMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDER MA8GA1UECgwIREJIdWIuaW8xJzAlBgNVBAsMHkRCSHViLmlvIENlcnRpZmljYXRl IEF1dGhvcml0eTElMCMGA1UEAwwcREJIdWIuaW8gREVWRUxPUE1FTlQgUm9vdCBD QTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMlg1CFBIRwv87u2A8Gl IqIJgGBlEIF9EREF6UyIylHuvwEV7efOUwwaAoF2N1V4w7MlHPeW7o7eKMt0LFI/ fDBRb6xz3bxnR8Mxr9p4zn77qocDU/AJDAk/ZMMRi4urIQg6tFBp1gsbSaWgsVFm wgewTyXSUu51PAgRtXPhiiMKwabjOjxZJGZY7vCP1vl6bL5Dp9pvoShSD/BcCB1a b2FiPBSTfl45Ovs+oW7enKOik/jKXqqGMtDCyjLl71wObTyn3Sv8uKuuMc0bY7ui 747sNmUWQFwP27BsXtHY27Q1dgC7oR1o3uyE9nLlOHrycLoVz/WuS5+UwbVlH+9x ixxuW8fhAHXO1hUG8ZNsUVqiBKaVryMsWgM76kCiRRHbwLXsSKu/zwo+HcHhnqku tq/+ibV9R0u1reSZ46rVhmLCuD1BWO5OEQRujlpGBAQPu0ajm7Ym+vG3MHTOeI3p LqAM+0QnLKhDDC6kwVpFmZkcvTsKBtIFRw26H6pGXmapzxrcuAzM6MKIQGiJaduf Vn8RvrTzSxGqWHb10DLAosfV2dBAT7qUpGw9yAtpjpKudjuZ6WDcAGUrPwozxfqo cWjamTMML8r2Lsm/DBtmMHcpxqLw17FzWSzkP8HVvLMJYkkkO6uixdUMnSTm5H7V VzZZSpbtRtcrVMFR9sqB+y41AgMBAAGjYzBhMB0GA1UdDgQWBBSHZI71PcSJIxOh 4sspAvBhGwivJTAfBgNVHSMEGDAWgBSHZI71PcSJIxOh4sspAvBhGwivJTAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEA Uxjm+WdsvoQwZFQfcYAJDB4hLKe2257jBcfRJdC8kuU2hlNKLwJIoepd5ByMtFMz pYkcHvOVYPiYXBT+b6ReluvnNun3bELWa+XvhYdDIkgEqYnnIhnVKKjONOQOo1mh pvuA5iW7G9zxYHrdu3WFCPTIQU/YdRnN1X9uqS8AdPWIsuOqHl6+mivjSAgLDq1J 5mYatCKRIC1OxZDPqXRgyd0LwD9sU0ImBb/icLDa0bAWt/gXid75rZV08zOOzd8f 4CmDO679o7D0S4opf3JSpyjWg5ALncmygcX83Uk6AaNvlEKvwKTp5vCNsiHml7IO KuPXRqJJxAFErpjbaboon+WX3zpOh0w4DRS6UB7mmWeZ8/rbSG5KyHUvCy6gAEoW i1EKfrt0T+7xx2jERdSTX0Vy3+G5CrS74MRgdDz+QYFVevY1zGc34U/+3l32VtMZ x7I5jLXb+LiZ5JQrzfPf62xO9jJogczt9DuHQ4BOAtqAFTzZvMRnyCgxD49IfsZ6 YZ/CNNlqdoPJkXmR/BHiUk/k6ZC3vYa/Am3tniQp7RxeV6s4hTB8XS6CN2Aq8cnS a5dtZbFSXNMB4QfBKGDg/gUwxU3j6VyoQJnmKt2QVgQqG6Sz1Px+YfmQXOMoGiFM IhGSBh8DEnh/aNtGXBF3OaYjAfSg9zfq9ATUmSzjzxY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8DCCA9igAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAkdC MRAwDgYDVQQIDAdFbmdsYW5kMREwDwYDVQQKDAhEQkh1Yi5pbzEnMCUGA1UECwwe REJIdWIuaW8gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYDVQQDDBxEQkh1Yi5p byBERVZFTE9QTUVOVCBSb290IENBMB4XDTE3MDMwNDEwNTI0NloXDTI3MDMwNTEw NTI0NlowgYoxCzAJBgNVBAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMREwDwYDVQQK DAhEQkh1Yi5pbzEnMCUGA1UECwweREJIdWIuaW8gQ2VydGlmaWNhdGUgQXV0aG9y aXR5MS0wKwYDVQQDDCREQkh1Yi5pbyBERVZFTE9QTUVOVCBJbnRlcm1lZGlhdGUg Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKOkhcRjOBkxQdzDie S6dfXIiQ9Qk2iCqfBVGPCFMjNrzUywjLvi0ZVbo7CaR4gveaXwcH94C8sxaqmm+7 SB3FimcgRfq1fwPS78wKyeAtb37TGu+Xwu/+4l320BwdmaCLx10kjT2pOf29t7MH qBLF3p4+7Jza5IPL3Ddq4O8iyUEvd3QfHZ2RgzY1M2APezG51DLRUHX7s5d8Bbe8 HcHmsrWCbJpbPzGCj2C4UiaT5ZCMPLFW+pbUnnZemVriDHekPBSNgo8AdSnnUypm YgdidlUFdZ8LAMqJYouY6On32+huXWK8QXnWz/TuGnP2mV4KgVPIkM89gymLakAL x8UX44csekodLsq4xmHnBZq9eDddjRKK/A6iG95GqYW4g3QbnjU56UCe4NlzRRj1 jATjLvJ3KHG45YyW8qjlr3vvVDNLiYPUs3ZDo4N8qChYFKbGKUljay6JpHjek16g 6Lmy6+8NUopKh+Q7vIH2LLpgh5xNlCRvHHOpE7TR2XtmCOvp2FHCSUqym+inOuvN CoSwVpooi5y4yvnVmSa9gxAp5AoptGzo/ucEsRvvf7giu7JnWIImYv1xvFOnqN2G GxRpXujAvrgpH79zdaj3VNUNebUw9PLeEksj4SuoAt3CxPrPnv+QecMXzRjLCgS4 PAygRceqJfsUl/dRhZTpoZr5ywIDAQABo2YwZDAdBgNVHQ4EFgQUzl/NZNsCDfwl RFDAZBt/2KfiH+UwHwYDVR0jBBgwFoAUh2SO9T3EiSMToeLLKQLwYRsIryUwEgYD VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD ggIBABKx6uDYuvYPrJtfyNpW63ELWukVVNMHojipg4M2dlV+phgooRGqJwE1Nx8s dQ3lDIIpIqi7eVfkm2SSYsMN3AUHhLnX9VeyWe4ffKs2mHCaQ6nIk+niE01zZC4z bGHNZwJNkgKa8s2E+iK1Z/QB1QicS9PiQoJHHkLbnS7v0YqowdXgMniU1yqIjmf7 aWhK0Gt51iXFgVcz0lXHsJkdgl85JW6nN/EB1rtZ+tWDgfBpPL8JObVmr1qMUsNe nWaAf91DA+3DDWVCCMdtgvTIRc7srjYl7rpBW36Ztijm8fTvEWdB6zVT4BUl4lh9 mECVV/Gx39oMyCMLq6X0jQ49tAuTjlCYRtQ1vRhKpfO+hJma01WBKPSrtJ3Yiiyk DFyi3Rs0w8GDN5FXRTfachExt5A1DAsUnxFz3JkdEJnmEgzzipa+FDAOC1JZvgxP I0GCJaQT60YuSyUsM+IPuedy2izRUImFLWXocn9y0Kbsqn7GY8pUYn4cXO7s2X/2 PsOQyFHLmAiTrhTISO/58NUzLsudMY9d1V5ymVHXYBDwgRMMVoTQqniU3ArCIRWZ XgqjSf6psZaXS4/9wf4y6c+/WgkfAMbCGGj7mKLu2a9Lo5zfdCB73ZhEATJbMFwk KTYOLQO4zJEK2h+hmyqMaKv7EDB0BjLmbnFCcuvWL27aB5FL -----END CERTIFICATE----- sqlitebrowser-sqlitebrowser-5733cb7/src/certs/ca-chain-docker.crt000066400000000000000000000106141463772530400252270ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIGSjCCBDKgAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwga8xCzAJBgNVBAYTAkdC MRAwDgYDVQQIDAdFbmdsYW5kMREwDwYDVQQKDAhEQkh1Yi5pbzEnMCUGA1UECwwe REJIdWIuaW8gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSwwKgYDVQQDDCNEQkh1Yi5p byBEb2NrZXIgRGV2ZWxvcG1lbnQgUm9vdCBDQTEkMCIGCSqGSIb3DQEJARYVanVz dGluQHBvc3RncmVzcWwub3JnMB4XDTIxMDUwMjExMjkxM1oXDTMxMDUwMzExMjkx M1owgbcxCzAJBgNVBAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMREwDwYDVQQKDAhE Qkh1Yi5pbzEnMCUGA1UECwweREJIdWIuaW8gQ2VydGlmaWNhdGUgQXV0aG9yaXR5 MTQwMgYDVQQDDCtEQkh1Yi5pbyBEb2NrZXIgRGV2ZWxvcG1lbnQgSW50ZXJtZWRp YXRlIENBMSQwIgYJKoZIhvcNAQkBFhVqdXN0aW5AcG9zdGdyZXNxbC5vcmcwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGwn/4kHEK3wBol8/fTLZI15Ie HH88Vk8ks++S7FTg7GeN3ITNHvvEFQ9qlV3OZRMckvP/UBVbqupnewQjOQO3f6H+ FW7Pfn9bynZmCb5uaWhzxdqLJye9jSEw57tAkAwXEY2RSFJTYr4UVU3Lmow+Iqj/ sAOXsPTIKkIIUSzC+khla6eXyZzeK0/uroQQYHGIJRLuihP33xQ520GRpVdLDeKr JJIw85YitMpdm0RfH1kEDPrQZVtC8XMjpA3G+4BrYcJazO8s+txwQQxgT5SOkvT1 XNUlGSLMKFvY2Ufy5J1mouGU4H90b82tf30cfyHDRjQlVMHAhN+AJA1jdj/aJBl5 HUNOB0tpL2OSYymEgyqnDyt1crMKjZU8PEM7LgbeRTHj8p2NeFPMJXOIhsN6gw0W 8+lbau70RPmPyFki0umM45PFomwKdYAO3GnC4vDWyoU1aPA82lzbTKTlbNQj5idM vrPZW0LCRZ0rnwHyCLqYTItYUlSItVBJnVJ77z1xVi1bNNHBBy8/1etM+LKMWLMu HmTKZK1dcpOqVZ9oIg3fvL3/8kdkaFVuloj6sU0SpNwDiF839O0sv5a0URrX+23K wjmtLNmXfZtz6ikSfc87mCZePHRqVejv1lQJYf9a5aw9Xm3FTSJDLPThNttsjCKg jVDRnvlT22ywtLNOlQIDAQABo2YwZDAdBgNVHQ4EFgQU/sG8zdpEuNy3LzZho0MA bWZ/qoowHwYDVR0jBBgwFoAUQRp62y8gTl4irm8Q2gz7NNf9WSAwEgYDVR0TAQH/ BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJkN 0y0PnBdC6OwKHEIFXVDauiKvVTdm5/1AGtvE7C1t8cnVb22Jygzaw7TyekYqTaTV sVW8zXCgNMNvTZOfB17A1jn7zxXjHYi3/IZw5NAzz02SPutxWgetuas4EdDwD9iT thHxkq2c6/1LaY/ZVHuQvnrIIfec01ZK6LzAlQyD8/v6CIoBTBqEIerVo9YNTimd l/UF4DVnX17jyZKWJuKqyL8HCC42QqC9smGPGvnE8mVdo0ed40+Dsx82n2vWLNVr nltNTCww4ryRcmtsuEsdRv1b+MJLJfFVEm9nevXZplAs0XwjEtETvlFWvPQz+zOH hm6LglP3LXLYIIzHnwSV9e9Qwr4yXAReBZxnfVdUzw0JDZdVUniA7sUSMlRQIg1F KXU42sT1AcCOuWUaD72MF29xpfOt5pWOM5R76y3xC6bhuRwkneUX9Nf5iHAkwG23 MwpurAVZiO5VR/LCYuL1vPP2XOmC5a10qbCQzP5hACCTXr5P8xXVtB4tyMZ46Vnw wnGxZ9bxhiXU8OO/FISWKmb9XFbbiNcJyRFQSjVU1prypvRpbbmwVg9bL1JgemH+ VQK3XIKr3GHWqAwRVGcNYD4LVLO0HX5kKkeIB2NzfvR8Bxn1WIjJPPZFyc4gAoLg v57ad/lF+jA0wlW68dB8AGV0HKjxq6b9jAeR+W2h -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGUTCCBDmgAwIBAgIUROzwAIHBoAT1lP4XR65lSC/C+uEwDQYJKoZIhvcNAQEL BQAwga8xCzAJBgNVBAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMREwDwYDVQQKDAhE Qkh1Yi5pbzEnMCUGA1UECwweREJIdWIuaW8gQ2VydGlmaWNhdGUgQXV0aG9yaXR5 MSwwKgYDVQQDDCNEQkh1Yi5pbyBEb2NrZXIgRGV2ZWxvcG1lbnQgUm9vdCBDQTEk MCIGCSqGSIb3DQEJARYVanVzdGluQHBvc3RncmVzcWwub3JnMB4XDTIxMDUwMjEx MTk0MVoXDTMxMDUwMzExMTk0MVowga8xCzAJBgNVBAYTAkdCMRAwDgYDVQQIDAdF bmdsYW5kMREwDwYDVQQKDAhEQkh1Yi5pbzEnMCUGA1UECwweREJIdWIuaW8gQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MSwwKgYDVQQDDCNEQkh1Yi5pbyBEb2NrZXIgRGV2 ZWxvcG1lbnQgUm9vdCBDQTEkMCIGCSqGSIb3DQEJARYVanVzdGluQHBvc3RncmVz cWwub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAx45dv4Ue1YZ8 7NxY26n3ccMhmtifRatdyCV0XWIIe8zBYQ3R1qSGIDmrNjNSA2i+DVIcktEsWO+B xPPGneI0NPv1sKnhWBpC93hVm0q8cCh07ud37BsYZEOu+j04Z3hZmJ+LBKhC9kJA p8bsZPAJokF1ThHmfMCD8Cr0EntnZdRsY+uVpw0AsHvC2PHmQvs5f2K49R4SwVD6 ehkKaM5qjb5e+TkeuIg16qKeIwyz0qiL41Z07+THw5JBbkVuThLrGQ721iydpxPR 3CJbRtJemNDdrZCEyvcgq8w6jRe519McmCUCEuYZy1rbodng5MOybUyvnLi5AwzA EeDsHk18yF0P9JhVmPGg8bSswoscYQk3p821IMZpL4DFVLdA0nHdwZeZoD7fw0TV p5h4oD5t0tsFR/N9cBEUvunwJ4P1WU1MstLrfQf4YVWzYOoZgl8nBf7zqoGwYN9t NkTgr4fnWZM8rZTzm93Mpr2nZ2r/7hMzadfrQFPRgR4BYFrZzMutUisLqMG5qMdJ 4/z3qRP6+Gwr8cZjRJw7Pv6dDJes/uq1PHdJ8c4pYR+GGmpT2rM8jHX2n8C2vJFG x19BEjNaqhY34zonTAA/WrFYcrGamzojqIyRBEcc572E0HWShC053HlMmjMHSukh 6uwQ3U6x2ABAqP76qGaj89skELSi6RkCAwEAAaNjMGEwHQYDVR0OBBYEFEEaetsv IE5eIq5vENoM+zTX/VkgMB8GA1UdIwQYMBaAFEEaetsvIE5eIq5vENoM+zTX/Vkg MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA A4ICAQAjZKP5sTXPEXdzv65XCBsEj8kVR6SDs3WTVCU/gU2Lylqe/gB0kKRh2C9K /DafSfsEYx0qwHXt4qRlTU7ih87CY+QnCw5IBaye0wVCofc1FqjP6T7RC7QNhni8 mUzeAl9eOf6Idex1wzEhgk+lulrJ3igHczLfR+layr8RLY7De9pO23xPIQoV23Yo /kYJicKBKOs6U/tM4nzoZsiB9yEUIdnOkF8SGWBbYVMOkxt8CYtChHGqJFeEveuc 5uY5Ot1iPrAPVP30JeVpGu6TQmFWNjXo18eqj/lmw5G1iSAAxSfIeHb1njFlw/++ irpAnICe6ggSSi8IgEeuwlZfNtTAGjXpqU3xFKvv6vg9Y7D4UlA1ln/Xd2P1Ea7t Yy0UhBs6a4SbEm7Au4m7SwEMA+ImGcbUacgiLX/EDLqUjM02WtwNeXq3dK4bIbo5 DhvKvYg11LQT1A1XJQopMFRMo6YNnsWXxy3MWq3l6GAqxmet+vslTAuOUdorS/5t 0yhQo1JtjcxZV7m+7TcwvFs+oeseaBXiLHkHM9P5TKsTJ9vKQuohEc0o1+YS+TqA Oie7rmViMy8+IKE9pFGNjo9KBtRshqDpz9C5z8X4WDpM7lB+EcFKIMbz0P4vPIcZ KDeX5COGCBbVnqBR7+MD+jU5k0376ShF+BAM3Ob9qF09aw0vMg== -----END CERTIFICATE----- sqlitebrowser-sqlitebrowser-5733cb7/src/certs/public.cert.pem000066400000000000000000000064021463772530400245220ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEmjCCAoKgAwIBAgIQRKcXCIHx/VM6mM4J+w/BnTANBgkqhkiG9w0BAQsFADCB ijELMAkGA1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQxETAPBgNVBAoMCERCSHVi LmlvMScwJQYDVQQLDB5EQkh1Yi5pbyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxLTAr BgNVBAMMJERCSHViLmlvIERFVkVMT1BNRU5UIEludGVybWVkaWF0ZSBDQTAeFw0y MTA1MDIxMzM0MjFaFw0yNjA1MDIxMzM0MjFaMD8xHjAcBgNVBAoTFURCIEJyb3dz ZXIgZm9yIFNRTGl0ZTEdMBsGA1UEAwwUcHVibGljQGRiNHMuZGJodWIuaW8wggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtS1Ik94JMX6bZJArL6xPddEZv yhAyv5BFKSJwm+NjvGQNR0guAZSeWRBVn/pQLvfGQnY+DkX7CQ5Mp6jJARRMjM8+ MQXkbsoZ3kyFTrMjoezEIoiNI7ndyAwauk1Hh2VfjQ6Ce2FMfFGYZk48dd3m4bvr nPgdcDnnBFIQ6Np/W76bHSUhkNRivcFyGgWWBCKYlLmMBviN7an9D4zBex7LhL37 FFCrGgo9vs0qLtX8m5Chtdlvj18CVOvYgSGvqRIj5y2peF+jAgbtyTtWmnT9iqK3 cBudd2PiWk1l4SvEcR1+ULsyw4LReSin4aHrpZ45WLLBsQICTtcPlqSVrr+tAgMB AAGjRjBEMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYDVR0j BBgwFoAUzl/NZNsCDfwlRFDAZBt/2KfiH+UwDQYJKoZIhvcNAQELBQADggIBAA16 XYqgzJFZjcrYC2lhpOEgmwlavBMwEP4e/ly37+PbsirIak4bNVyY0zw6tEZCF55r Rij2LNgaxFJnrZrWdP7yFua9wzf4wQOd+dLLHE9K8E4mAAz8wuof+C0J9nljmD66 6p3HH6X5TrDaMBILQB4moWrjgGBfey2DufFd8w05M1vPIWisZiUN6gkrAImhGLBt aXEnCKY5Kby4+SHv2ks+yk7U/cDIOOSwQU2Sgc2gaUM3joofsab5JsChyQrQbEDd yIM1PtpvZCvyTjlrBb1ic+TlRgDtRCDOEBL7uHgaHJp1s+XZ0axLx9U+qYuBS0P9 qDTxpewB3JSLZfUu4noeW5Oe9MhiRky7tPTAADehjeuYYWiCBtL1F73x21MUoey9 +yCnHuWOrr6iMlG7R2Joa+KPZZ1RnMdaH42/DxYzB5rEymqvNQQvwsQJ1KIb3gVp 72AHYXiIbcw0EtDU2Js6K6KfNd14wQmBcyIhfY6NT3GUrFuVamWLiEQZh8H6fBn+ iSv3QeDF1TJxJ8G88BJbwm+gAsQTL4oyVzZSAFvuGwE1ODmNLm8J52jzsuduTWeb 30/dBeFXL/TC6xw8BsXMjP92CDTI9RM/rpe+b0m+StEOp27k8i6qg/ozTCpdf4dH XOjJ0KVw3giAvF8+p6WiZnm2UJPqS9hVP9QDBsZR -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEA7UtSJPeCTF+m2SQKy+sT3XRGb8oQMr+QRSkicJvjY7xkDUdI LgGUnlkQVZ/6UC73xkJ2Pg5F+wkOTKeoyQEUTIzPPjEF5G7KGd5MhU6zI6HsxCKI jSO53cgMGrpNR4dlX40OgnthTHxRmGZOPHXd5uG765z4HXA55wRSEOjaf1u+mx0l IZDUYr3BchoFlgQimJS5jAb4je2p/Q+MwXsey4S9+xRQqxoKPb7NKi7V/JuQobXZ b49fAlTr2IEhr6kSI+ctqXhfowIG7ck7Vpp0/Yqit3AbnXdj4lpNZeErxHEdflC7 MsOC0Xkop+Gh66WeOViywbECAk7XD5akla6/rQIDAQABAoIBABz90dhwYPwBx7nJ 3IPTgcbRuPVZg6cfnnnEr8+ATETYNIUmy1vLl6PND+DWPdfkFSOk5Rtp1QT5s0SM S2PbfOZpYbygcq7ZFloYvdKfreVRmELSUUqlLcU59rihQGXX1fvZmQc6GcYlfjaX cUGTyPu3YqVDtVCrcHeYIIquWFus1p/MdQg1kDcr/vRAm3A5Evn4zv3D+jN0SX/h ZO0D3PejDy/TBFEIQnn0c8XKRkVuVAeA8ZRB+lLsOXDzTpDf2QNVOscS/icQ0cXR 1jnGRlr3zATgO1fSh17cWCZgNVNxtijJOE1avHXSGxZMPjkSC8cK4IzfcteplEex G5kOfCECgYEA9U2NhIyomrUpYb6pnCdHQHTV/Ew2s8ud3wBKAtrmAW9lIHn1j1kX /I/C0sNuyAaU5Zh81gHcx3KcuwHooTWUVf56FNKqxElafpwCTQTXF0dF3uycVopq Mt60fntD0LqQ1EhEpnYjIOuu1f4+2Y3o2URUovRVIwbajQ06UFKqi5kCgYEA96Rc zBMEiffgNRszzYKsBxkKk/ysXXWovZXz998TZ51o1jn50q35HfJPj8yEAlUn1yF9 htvrWxLRuYuIkDOJmKbG94O3F14p0tuWx5TrnVxLYikCQAl++UZJWEb4a+YhVGra VGgfioQpYPD0dF2Z1CxGSe9w6u+s0UYxYaceQTUCgYAZR67H9D8EApuLKT0NjLa5 G9FZuPkCOn/AlaUK+kgt6a8AU9FMvp/MNXycf+uQzazWpIpo+7QnEda5Jw80XfM1 kY4/Sx6yL+UVmzpZeaA5E+1NdhD+kjEzoOP1DPsGLdPzLKd2iEJCiEdyYktT3F4c 1f/q80c63t/zHWPfF0XgMQKBgHQwpO2HGsEVERg5rCOHZOlroV/v1HuBQeu52J77 BmK+IzsoNoPX5qNbVmMUxPdHNwskBn5o3tN7T/Vrd2aZF70MuxvUq+oF3z+0kdkQ kT/i1ue2b/zVt8KDbNRDcDlH32l5PPkPZYUbH0MBquCSLiOzpkL4WhWQ4JfMBE1a GMLlAoGAOOYr6tCW+MP9PYWWqmoIxwX4q3a72mPkf9Yk2JzMWb0LFuJltXwOx8az K0c1sviqvzTK75KEHxYYK0ISCsFcEqD/Jf3EYs2v3ORuDvEykSAc4pj3LS4EgoVP XvP1QYG8f8W5uSB8O3HzoTXVYtAeVtsdvdipzDcnWH+wSi/3EPQ= -----END RSA PRIVATE KEY----- sqlitebrowser-sqlitebrowser-5733cb7/src/csvparser.cpp000066400000000000000000000277471463772530400232200ustar00rootroot00000000000000#include "csvparser.h" #include CSVParser::CSVParser(bool trimfields, char32_t fieldseparator, char32_t quotechar) : m_bTrimFields(trimfields) , m_iNumExtraBytesFieldSeparator(0) , m_iNumExtraBytesQuoteChar(0) , m_pCSVProgress(nullptr) , m_nBufferSize(4096) { for(int i=0;i<4;i++) { m_cFieldSeparator[i] = static_cast((fieldseparator >> i*8) & 0xFF); m_cQuoteChar[i] = static_cast((quotechar >> i*8) & 0xFF); if(i && m_cFieldSeparator[i]) m_iNumExtraBytesFieldSeparator = i; if(i && m_cQuoteChar[i]) m_iNumExtraBytesQuoteChar = i; } } CSVParser::~CSVParser() { delete m_pCSVProgress; } namespace { // This function adds a character to an existing field structure. If necessary, it extends the buffer size. inline void addChar(CSVField* field, char c) { // Increase buffer size if it is too small if(field->buffer_length >= field->buffer_max_length) { field->buffer_max_length += 64; field->buffer = static_cast(realloc(field->buffer, field->buffer_max_length)); } // Add char to the end of the buffer and increase length by one field->buffer[field->buffer_length++] = c; } // This function increases the size of the field list of an existing row. However, it only does so if the field list is currently full. inline void increaseRowSize(CSVRow& r) { // Check if field list is full if(r.num_fields >= r.max_num_fields) { // Increase field list size r.max_num_fields += 5; r.fields = static_cast(realloc(r.fields, r.max_num_fields*sizeof(CSVField))); // Initialise the newly created field structures for(size_t i=r.num_fields;idata = field->buffer; field->data_length = field->buffer_length; // If we have to trim the field, do this by manipulating the data start and data length variables if(trim) { // Check for trailing spaces and omit them while(field->data_length && isspace(*field->data)) { field->data++; field->data_length--; } // Check for pending spaces and omit them while(field->data_length && isspace(field->data[field->data_length-1])) field->data_length--; } // We assume here that the field object has been constructed in-place. So all we need to do for adding it to the row structure // is increasing the field count by one to make sure the newly constructed field object is used. r.num_fields++; // Clear field buffer for next use field->buffer_length = 0; // Increase field list size if it is too small increaseRowSize(r); // Return pointer to the next field return &r.fields[r.num_fields]; } // This function takes a parsed CSV row and hands it back to the caller of the CSV parser. It returns a null pointer if the parsing should be // aborted, otherwise it returns a pointer to a new field object that can be used for storing the contents of the first field of the next row. inline CSVField* addRow(CSVParser::csvRowFunction f, CSVRow& r, size_t& rowCount) { // Call row function if(!f(rowCount, r)) return nullptr; // Reset the field list by setting the field count to 0. No need to deconstruct anything else. r.num_fields = 0; // Increase row count by one, as we're now starting to parse the next row rowCount++; // Return a pointer to the first field in the row object because we're starting with the first field of the next row now return r.fields; } } CSVParser::ParserResult CSVParser::parse(csvRowFunction insertFunction, QTextStream& stream, size_t nMaxRecords) { ParseStates state = StateNormal; // State of the parser QByteArray sBuffer; // Buffer for reading the file CSVRow record; // Buffer for parsing the current row size_t parsedRows = 0; // Number of rows parsed so far CSVField* field; // Buffer for parsing the current field if(m_pCSVProgress) m_pCSVProgress->start(); // Initialise row buffer and get pointer to the first field record = { nullptr, 0, 0 }; increaseRowSize(record); field = record.fields; // Make sure all buffers are freed when we're done here class FieldBufferDealloc { public: explicit FieldBufferDealloc(CSVRow& row) : m_row(row) {} ~FieldBufferDealloc() { for(size_t i=0;i 0 && parsedRows >= nMaxRecords) return ParserResult::ParserResultSuccess; } if(m_pCSVProgress && parsedRows % 100 == 0) { if(!m_pCSVProgress->update(bufferPos)) return ParserResult::ParserResultCancelled; } } if(record.num_fields || record.fields->buffer_length) { addColumn(record, field, m_bTrimFields); if(!addRow(insertFunction, record, parsedRows)) return ParserResult::ParserResultError; } if(m_pCSVProgress) m_pCSVProgress->end(); // Check if we are in StateNormal or StateEndQuote state. The first is what we should be in for unquoted data and all files which // end with a line break. The latter is what we are in for quoted data with no final line break. return (state == StateNormal || state == StateEndQuote) ? ParserResult::ParserResultSuccess : ParserResult::ParserResultUnexpectedEOF; } bool CSVParser::look_ahead(QTextStream& stream, QByteArray& sBuffer, const char** it, const char** sBufferEnd, char expected) { // look ahead for next byte auto nit = *it + 1; // In order to check what the next byte is we must make sure that that byte is already loaded. Assume we're at an m_nBufferSize // boundary but not at the end of the file when we hit a \r character. Now we're going to be at the end of the sBuffer string // because of the m_nBufferSize boundary. But this means that the following check won't work properly because we can't check the // next byte when we really should be able to do so because there's more data coming. To fix this we'll check for this particular // case and, if this is what's happening, we'll just load an extra byte. if(nit == *sBufferEnd && !stream.atEnd()) { // Load one more byte sBuffer.append(stream.read(1).toUtf8()); *sBufferEnd = sBuffer.constEnd(); // Restore both iterators. sBufferEnd points to the imagined char after the last one in the string. So the extra byte we've // just loaded is the one before that, i.e. the actual last one, and the original last char is the one before that. *it = *sBufferEnd - 2; nit = *sBufferEnd - 1; } // Check whether there actually is one more byte and it is the expected one return nit != *sBufferEnd && *nit == expected; } sqlitebrowser-sqlitebrowser-5733cb7/src/csvparser.h000066400000000000000000000061551463772530400226530ustar00rootroot00000000000000#ifndef CSVPARSER_H #define CSVPARSER_H #include #include #include class QByteArray; class QTextStream; /*! * \brief The CSVProgress class * * This is an abstract class, an implementation of which you can pass to the CSVParser to get progress updates. */ class CSVProgress { public: virtual ~CSVProgress() = default; virtual void start() = 0; virtual bool update(int64_t pos) = 0; virtual void end() = 0; }; /* * This structure represents one parsed column in a CSV row */ struct CSVField { // These variables are used internally by the parser. Usually there should be no need to access them from outside the parser char* buffer; // Start of the field buffer uint64_t buffer_length; // Current length of the buffer content. The content is NOT null-terminated uint64_t buffer_max_length; // Size of the entire buffer // These variables point to the parsed contents of the field and can be directly passed to SQLite functions char* data; // Pointer to the start of the field contents uint64_t data_length; // Length of the field contents }; /* * This structure holds all columns of a single parsed CSV row */ struct CSVRow { CSVField* fields; // Pointer to the field list/the first element in the list size_t num_fields; // Number of fields in the row size_t max_num_fields; // Size of the field list. Used internally by the parser only }; class CSVParser { public: using csvRowFunction = std::function; explicit CSVParser(bool trimfields = true, char32_t fieldseparator = ',', char32_t quotechar = '"'); ~CSVParser(); enum ParserResult { ParserResultSuccess, ParserResultCancelled, ParserResultError, ParserResultUnexpectedEOF }; /*! * \brief parse the given stream * @param insertFunction A function pointer that is called for each parsed row. It is passed two parameters, the row number and a list of all parsed columns * in the row. The called function may return false if an error occurred to stop the import process. Otherwise it should return true. * \param stream Stream with the CSV parser * \param nMaxRecords Max records too read, 0 if unlimited * \return ParserResult value that indicated whether action finished normally, was cancelled or errored. */ ParserResult parse(csvRowFunction insertFunction, QTextStream& stream, size_t nMaxRecords = 0); void setCSVProgress(CSVProgress* csvp) { m_pCSVProgress = csvp; } private: enum ParseStates { StateNormal, StateInQuote, StateEndQuote }; private: bool m_bTrimFields; char m_cFieldSeparator[4]; char m_cQuoteChar[4]; int m_iNumExtraBytesFieldSeparator; int m_iNumExtraBytesQuoteChar; CSVProgress* m_pCSVProgress; int64_t m_nBufferSize; //! internal buffer read size bool look_ahead(QTextStream& stream, QByteArray& sBuffer, const char** it, const char** sBufferEnd, char expected); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/dbstructureqitemviewfacade.cpp000066400000000000000000000036051463772530400266200ustar00rootroot00000000000000#include "DbStructureModel.h" #include "dbstructureqitemviewfacade.h" DbStructureQItemViewFacade::DbStructureQItemViewFacade(QAbstractItemView& aitemView) : QObject(&aitemView), m_itemView(aitemView) { } const QAbstractItemView& DbStructureQItemViewFacade::itemView() const { return m_itemView; } bool DbStructureQItemViewFacade::hasSelection() const { return m_itemView.selectionModel()->hasSelection(); } QString DbStructureQItemViewFacade::displayName() const { QAbstractItemModel *model = m_itemView.model(); QModelIndex index = m_itemView.currentIndex(); return model->data(index.sibling(index.row(), DbStructureModel::ColumnName), Qt::DisplayRole).toString(); } QString DbStructureQItemViewFacade::name() const { QAbstractItemModel *model = m_itemView.model(); QModelIndex index = m_itemView.currentIndex(); return model->data(index.sibling(index.row(), DbStructureModel::ColumnName), Qt::EditRole).toString(); } QString DbStructureQItemViewFacade::objectType() const { QAbstractItemModel *model = m_itemView.model(); QModelIndex index = m_itemView.currentIndex(); return model->data(index.sibling(index.row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString(); } QString DbStructureQItemViewFacade::schema() const { QAbstractItemModel *model = m_itemView.model(); QModelIndex index = m_itemView.currentIndex(); return model->data(index.sibling(index.row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString(); } QString DbStructureQItemViewFacade::sql() const { QAbstractItemModel *model = m_itemView.model(); QModelIndex index = m_itemView.currentIndex(); return model->data(index.sibling(index.row(), DbStructureModel::ColumnSQL), Qt::EditRole).toString(); } sqlb::ObjectIdentifier DbStructureQItemViewFacade::object() const { return sqlb::ObjectIdentifier(schema().toStdString(), name().toStdString()); } sqlitebrowser-sqlitebrowser-5733cb7/src/dbstructureqitemviewfacade.h000066400000000000000000000062311463772530400262630ustar00rootroot00000000000000#ifndef DBSTRUCTUREQITEMVIEWFACADE_H #define DBSTRUCTUREQITEMVIEWFACADE_H #include #include #include #include #include #include /** * @brief The DbStructureQItemViewFacade class * Provides a simple read only interface to a QAbstractItemView (e.g. QTreeView) that holds a model() of type DBStructureModel. * * It is designed to simplify the access to the actual selected node. * * The Class follows the facade design pattern. * But it doesn't control the lifecycle of the itemView it is connected to. * */ class DbStructureQItemViewFacade : public QObject { Q_OBJECT public: explicit DbStructureQItemViewFacade(QAbstractItemView& aitemView); /** * @brief itemView returns the itemView that is hiding behind the facade. * ItemView is connected on construction, the facadeObject has to be destroyed before the itemView. * * @return connected itemView */ const QAbstractItemView& itemView() const; /** * @brief hasSelection returns true, if the itemView() has a selected Item. * itemView().selectionModel().hasSelection() * * @return true, if the itemView() has a selected Item. ***/ bool hasSelection() const; /** * @brief displayName returns the displayName of the itemViews selectedItem. * * It is taken from the model().data() with column=ColumnName and role=Qt::DisplayRole * * For the display role and the browsable branch of the tree we want to show the column name including the schema name if necessary (i.e. * for schemata != "main"). For the normal structure branch of the tree we don't want to add the schema name because it's already obvious from * the position of the item in the tree. * * @return displayName of selectedItem */ QString displayName() const; /** * @brief returns the name of the itemViews selectedItem without decorations. * It is taken from the model().data() with column=ColumnName and role=Qt::EditRole * * @return name of selectedItem */ QString name() const; /** * @brief objectType returns the objectType of the itemViews selectedItem. * * It is taken from the model().data() with column=ColumnObjectType and role=Qt::EditRole * * @return */ QString objectType() const; /** * @brief schema returns the schema of the itemViews selectedItem. * * It is taken from the model().data() with column=ColumnSchema and role=Qt::EditRole * * @return */ QString schema() const; /** * @brief sql returns the sql statement of the itemViews selectedItem. * * It is taken from the model().data() with column=ColumnSQL and role=Qt::EditRole * * @return */ QString sql() const; /** * @brief Object returns a sqlb::ObjectIdentifier to the selected itemView item. * Object identifier consisting of schema name and object name. * * @return sqlb::ObjectIdentifier to selected item */ sqlb::ObjectIdentifier object() const; private: QAbstractItemView& m_itemView; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/docktextedit.cpp000066400000000000000000000112561463772530400236670ustar00rootroot00000000000000#include "docktextedit.h" #include "Settings.h" #include "SqlUiLexer.h" #include #include #include QsciLexerJSON* DockTextEdit::jsonLexer = nullptr; QsciLexerXML* DockTextEdit::xmlLexer = nullptr; DockTextEdit::DockTextEdit(QWidget* parent) : SqlTextEdit(parent) { // Create lexer objects if not done yet if(jsonLexer == nullptr) jsonLexer = new QsciLexerJSON(this); if(xmlLexer == nullptr) xmlLexer = new QsciLexerXML(this); // Set plain text as default setLanguage(PlainText); jsonLexer->setFoldCompact(false); jsonLexer->setHighlightComments(true); // Do rest of initialisation reloadSettings(); } void DockTextEdit::reloadSettings() { // Set the parent settings for all lexers SqlTextEdit::reloadSettings(); reloadLexerSettings(jsonLexer); reloadLexerSettings(xmlLexer); // Set the databrowser font for the plain text editor. plainTextFont = QFont(Settings::getValue("databrowser", "font").toString()); plainTextFont.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); setFont(plainTextFont); setupSyntaxHighlightingFormat(jsonLexer, "comment", QsciLexerJSON::CommentLine); setupSyntaxHighlightingFormat(jsonLexer, "comment", QsciLexerJSON::CommentBlock); setupSyntaxHighlightingFormat(jsonLexer, "keyword", QsciLexerJSON::Keyword); setupSyntaxHighlightingFormat(jsonLexer, "keyword", QsciLexerJSON::KeywordLD); setupSyntaxHighlightingFormat(jsonLexer, "function", QsciLexerJSON::Operator); setupSyntaxHighlightingFormat(jsonLexer, "string", QsciLexerJSON::String); setupSyntaxHighlightingFormat(jsonLexer, "table", QsciLexerJSON::Number); setupSyntaxHighlightingFormat(jsonLexer, "identifier", QsciLexerJSON::Property); // The default style for invalid JSON or unclosed strings uses red // background and white foreground, but the current line has // precedence, so it is by default white over gray. We change the // default to something more readable for the current line at // invalid JSON. QColor stringColor = QColor(Settings::getValue("syntaxhighlighter", "string_colour").toString()); jsonLexer->setColor(stringColor, QsciLexerJSON::Error); jsonLexer->setColor(stringColor, QsciLexerJSON::UnclosedString); QFont errorFont(Settings::getValue("editor", "font").toString()); errorFont.setPointSize(Settings::getValue("editor", "fontsize").toInt()); errorFont.setItalic(true); jsonLexer->setFont(errorFont, QsciLexerJSON::Error); jsonLexer->setFont(errorFont, QsciLexerJSON::UnclosedString); jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::Error); jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::UnclosedString); xmlLexer->setColor(QColor(Settings::getValue("syntaxhighlighter", "foreground_colour").toString())); setupSyntaxHighlightingFormat(xmlLexer, "comment", QsciLexerHTML::HTMLComment); setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::Tag); setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::XMLTagEnd); setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::XMLStart); setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::XMLEnd); setupSyntaxHighlightingFormat(xmlLexer, "string", QsciLexerHTML::HTMLDoubleQuotedString); setupSyntaxHighlightingFormat(xmlLexer, "string", QsciLexerHTML::HTMLSingleQuotedString); setupSyntaxHighlightingFormat(xmlLexer, "table", QsciLexerHTML::HTMLNumber); setupSyntaxHighlightingFormat(xmlLexer, "identifier", QsciLexerHTML::Attribute); } void DockTextEdit::setLanguage(Language lang) { m_language = lang; switch (lang) { case PlainText: { setLexer(nullptr); setFolding(QsciScintilla::NoFoldStyle); // This appears to be reset by setLexer setFont(plainTextFont); break; } case JSON: setLexer(jsonLexer); setFolding(QsciScintilla::BoxedTreeFoldStyle); break; case XML: setLexer(xmlLexer); setFolding(QsciScintilla::BoxedTreeFoldStyle); break; case SQL: setLexer(sqlLexer); setFolding(QsciScintilla::BoxedTreeFoldStyle); break; } } void DockTextEdit::setTextInMargin(const QString& text) { clearMarginText(); setMarginType(0, QsciScintilla::TextMargin); setMarginText(0, text, QsciStyle(QsciScintillaBase::STYLE_LINENUMBER)); setMarginWidth(0, text); reloadCommonSettings(); } void DockTextEdit::clearTextInMargin() { clearMarginText(); setMarginLineNumbers(0, true); reloadCommonSettings(); emit linesChanged(); } sqlitebrowser-sqlitebrowser-5733cb7/src/docktextedit.h000066400000000000000000000017661463772530400233410ustar00rootroot00000000000000#ifndef DOCKTEXTEDIT_H #define DOCKTEXTEDIT_H #include "sqltextedit.h" class QsciLexerJSON; class QsciLexerXML; class SqlUiLexer; /** * @brief The DockTextEdit class * This class extends our QScintilla SQL Text Edit adding XML, JSON and plain text modes. */ class DockTextEdit : public SqlTextEdit { Q_OBJECT public: explicit DockTextEdit(QWidget *parent = nullptr); // Enumeration of supported languages enum Language { PlainText, JSON, XML, SQL }; void setLanguage(Language lang); Language language() const { return m_language; } // Disables the line-number margin and sets this text in the first line. void setTextInMargin(const QString& text); // Resets margin to their original line-number mode void clearTextInMargin(); public slots: void reloadSettings(); protected: static QsciLexerJSON* jsonLexer; static QsciLexerXML* xmlLexer; private: Language m_language; QFont plainTextFont; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/extensions/000077500000000000000000000000001463772530400226625ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/extensions/extension-formats.c000066400000000000000000000723501463772530400265220ustar00rootroot00000000000000/*** Extension-formats * * This file adds the following file format support to SQLite. * * Plist - An XML like encoding * Base64 - Standard binary to text conversion * * Compile using: * * gcc -g -fPIC -shared extension-formats.c -o libsqlite-formats.so */ #include #include #include #include #include #include #include #define COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE 1 #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #define INDENT_INCREMENT 4 #define ERROR_NONE 0 #define ERROR_INSUFFICIENT_MEMORY 1 #define ERROR_INVALID_HEADER 2 #define ERROR_INVALID_TRAILER 3 #define ERROR_INVALID_OFFSET 4 #define ERROR_INVALID_OBJECT_LENGTH 5 #define ERROR_INVALID_REFERENCE 6 #define ERROR_INVALID_CHARACTER 7 typedef struct KEY { struct OBJECT *key; struct OBJECT *value; } KEY; typedef struct OBJECT { int type; int length; union { time_t date; double real; long integer; unsigned long uid; unsigned char binary[1]; char text[1]; short int utf16[1]; int refs[1]; KEY keys[1]; struct OBJECT *objects[1]; } data; } OBJECT; typedef struct CONFIG { int bytesPerOffset; int bytesPerReference; int objectCount; int rootObjectReference; int offsetTableOffset; size_t bufferLength; size_t outputBufferLength; size_t outputBufferIn; long *offsetTable; unsigned char *buffer; unsigned char *outputBuffer; } CONFIG; int createObject(int type, int length, int extra, OBJECT **ptr2); int readObject(CONFIG *cfg, long offset, OBJECT **ptr2); static int indent = 2; int outputText(CONFIG *cfg, const char *text) { size_t textLength = strlen(text); size_t availableSpace = cfg->outputBufferLength - cfg->outputBufferIn; while (textLength >= availableSpace) { unsigned char *tmp = cfg->outputBuffer; cfg->outputBufferLength += textLength + 1024; cfg->outputBuffer = (unsigned char *)realloc(cfg->outputBuffer, cfg->outputBufferLength); if (cfg->outputBuffer == NULL) { if (tmp != NULL) free(tmp); return ERROR_INSUFFICIENT_MEMORY; } availableSpace = cfg->outputBufferLength - cfg->outputBufferIn; } strcpy((char *)(cfg->outputBuffer+cfg->outputBufferIn), text); cfg->outputBufferIn += textLength; return ERROR_NONE; } int printWithIndent(CONFIG *cfg, const char *text, int newline) { int err = ERROR_NONE; char spaces[9] = " "; int n = indent; while ((n > 8) && (err == ERROR_NONE)) { err = outputText(cfg, spaces); n -= 8; } if ((n > 0) && (err == ERROR_NONE)) err = outputText(cfg, spaces + 8 - n); if (err == ERROR_NONE) err = outputText(cfg, text); if (newline && (err == ERROR_NONE)) err = outputText(cfg, "\n"); return err; } int readHeader(CONFIG *cfg) { if ((cfg->bufferLength < 40) || (strncmp((const char *)(cfg->buffer), "bplist0", 7) != 0) || ((cfg->buffer[7] != '0') && (cfg->buffer[7] != '1'))) return ERROR_INVALID_HEADER; return ERROR_NONE; } int readTrailer(CONFIG *cfg) { int i, j; int objectCount = 0; int rootObjectReference = 0; int offsetTableOffset = 0; unsigned char *ptr; unsigned char *buffer = cfg->buffer + cfg->bufferLength - 32; // Extract the relevant fields for (i=12; i < 16; i++) objectCount = (objectCount << 8) + buffer[i]; for (i=20; i < 24; i++) rootObjectReference = (rootObjectReference << 8) + buffer[i]; for (i=28; i < 32; i++) offsetTableOffset = (offsetTableOffset << 8) + buffer[i]; // Populate the configurartion structure cfg->bytesPerOffset = buffer[6]; cfg->bytesPerReference = buffer[7]; cfg->objectCount = objectCount; cfg->rootObjectReference = rootObjectReference; cfg->offsetTableOffset = offsetTableOffset; cfg->offsetTable = (long *)malloc((size_t)objectCount * sizeof(long)); if (cfg->offsetTable == NULL) return ERROR_INSUFFICIENT_MEMORY; ptr = cfg->buffer + offsetTableOffset; for (i=0; i < objectCount; i++) { long n = 0; for (j=0; j < cfg->bytesPerOffset; j++) n = (n << 8) | *(ptr++); cfg->offsetTable[i] = n; } return ERROR_NONE; } int createObject(int type, int length, int extra, OBJECT **ptr2) { *ptr2 = NULL; OBJECT *ptr = (OBJECT *)malloc(sizeof(OBJECT) + (size_t)extra); if (ptr == NULL) return ERROR_INSUFFICIENT_MEMORY; ptr->type = type; ptr->length = length; *ptr2 = ptr; return ERROR_NONE; } long readInteger(unsigned char *ptr, int desc) { long value = 0L; int n = 1 << (desc & 0x03); while (n--) value = (value << 8) | (long)(*(ptr++)); return value; } unsigned long readUid(unsigned char *ptr, int desc) { unsigned long value = 0L; int n = 1 << (desc & 0x03); while (n--) value = (value << 8) | (unsigned long)(*(ptr++)); return value; } double readDouble(unsigned char *ptr, int desc) { union { double v; float f[2]; unsigned char b[8]; } value; int n = 1 << (desc & 0x03); for (int i=0; i < n; i++) value.b[7-i] = *(ptr++); if (n == 4) value.v = (double)(value.f[1]); return value.v; } int readArray(CONFIG *cfg, unsigned char *ptr, int type, int length, OBJECT **array2) { int i; long offset; OBJECT *array; int err = createObject(type, length, ((length-1) * (int)sizeof(OBJECT)), &array); *array2 = NULL; for (i=0; (i < length) && (err == ERROR_NONE); i++) { offset = 0L; for (int j=0; j < cfg->bytesPerReference; j++) offset = (offset << 8) | (long)(*(ptr++)); if (offset >= cfg->objectCount) return ERROR_INVALID_REFERENCE; offset = cfg->offsetTable[offset]; err = readObject(cfg, offset, &(array->data.objects[i])); } if (err == ERROR_NONE) *array2 = array; return err; } int readDictionary(CONFIG *cfg, unsigned char *ptr, int type, int length, OBJECT **dict2) { int i; long offset; OBJECT *dict; int err = createObject(type, length, ((length-1) * (int)sizeof(KEY)), &dict); *dict2 = NULL; if (err != ERROR_NONE) return err; for (i=0; (i < length) && (err == ERROR_NONE); i++) { offset = 0L; for (int j=0; j < cfg->bytesPerReference; j++) offset = (offset << 8) | (long)(*(ptr++)); if (offset >= cfg->objectCount) return ERROR_INVALID_REFERENCE; offset = cfg->offsetTable[offset]; err = readObject(cfg, offset, &(dict->data.keys[i].key)); } for (i=0; (i < length) && (err == ERROR_NONE); i++) { offset = 0L; for (int j=0; j < cfg->bytesPerReference; j++) offset = (offset << 8) | (long)(*(ptr++)); if (offset >= cfg->objectCount) return ERROR_INVALID_REFERENCE; offset = cfg->offsetTable[offset]; err = readObject(cfg, offset, &(dict->data.keys[i].value)); } if (err == ERROR_NONE) *dict2 = dict; return err; } int readObject(CONFIG *cfg, long offset, OBJECT **ptr2) { int i; int length; int type; int err = ERROR_NONE; OBJECT *obj; unsigned char *ptr; *ptr2 = NULL; if ((size_t)offset >= cfg->bufferLength) return ERROR_INVALID_OFFSET; ptr = cfg->buffer + offset; type = *(ptr++); length = (type & 0x0F); type >>= 4; if ((type != 0) && (length == 0x0F)) { length = *(ptr++); if ((length >> 4) != 0x01) return ERROR_INVALID_OBJECT_LENGTH; i = (int)readInteger(ptr, length); ptr += (1 << (length & 0x03)); length = i; } switch (type) { case 0x00: // Singleton err = createObject(type, length, 5, &obj); if (err != ERROR_NONE) return err; switch(length) { case 0: // NULL strcpy(obj->data.text, ""); break; case 8: // False strcpy(obj->data.text, ""); break; case 9: // True strcpy(obj->data.text, ""); break; case 15: // Fill strcpy(obj->data.text, ""); break; default: // Illegal strcpy(obj->data.text, "***Error***"); break; } break; case 0x01: // Integer err = createObject(type, length, 0, &obj); if (err != ERROR_NONE) return err; obj->data.integer = readInteger(ptr, length); break; case 0x02: // Float err = createObject(type, length, 0, &obj); if (err != ERROR_NONE) return err; obj->data.real = readDouble(ptr, length); break; case 0x03: // Date in Elapsed seconds err = createObject(type, length, 0, &obj); if (err != ERROR_NONE) return err; obj->data.date = (time_t)readDouble(ptr, length); break; case 0x04: // binary data err = createObject(type, length, length, &obj); if (err != ERROR_NONE) return err; for (i=0; i < length; i++) obj->data.binary[i] = *(ptr++); break; case 0x05: // ASCII string err = createObject(type, length, length, &obj); if (err != ERROR_NONE) return err; for (i=0; i < length; i++) obj->data.text[i] = (char)*(ptr++); obj->data.text[length] = '\0'; break; case 0x06: // UTF16 string err = createObject(type, length, 2 * length, &obj); if (err != ERROR_NONE) return err; for (i=0; i < length; i++) { short int d = *(ptr++); obj->data.utf16[i] = (short int)((d << 8) | *(ptr++)); } obj->data.utf16[length] = '\0'; break; case 0x08: // UID err = createObject(type, length, 0, &obj); if (err != ERROR_NONE) return err; obj->data.uid = readUid(ptr, length); break; case 0x0A: // Array err = readArray(cfg, ptr, type, length, &obj); break; case 0x0D: // Dictionary err = readDictionary(cfg, ptr, type, length, &obj); break; default: fprintf(stderr, "Unknown object type: %d\n", type); err = createObject(type, length, 0, &obj); break; } if (err == ERROR_NONE) *ptr2 = obj; return err; } void displayHex(CONFIG *cfg, int data) { static int in = 0; static char buffer[76]; static long offset = 0L; static char hex[] = "0123456789ABCDEF"; char *tmp; // If -ve then flush buffer if (data < 0) { if (in > 0) { tmp = buffer + in * 3 + 8 + 2 * (in / 8); while (tmp < buffer+59) *(tmp++) = ' '; buffer[in+59] = '\0'; printWithIndent(cfg, buffer, 1); } offset = 0L; in = 0; return; } // If start of line add offset if (in == 0) { sprintf((char *)buffer, "%06lX ", offset); offset += 16; buffer[8] = '\0'; } // Add Byte in hex tmp = buffer + in * 3 + 8 + 2 * (in / 8); *(tmp++) = hex[(data >> 4) & 0x0F]; *(tmp++) = hex[data & 0x0F]; *(tmp++) = ' '; // Add to character buffer buffer[in+59] = (char)data; // Check if midpoint of buffer if (++in == 8) { *(tmp++) = '-'; *(tmp++) = ' '; } // Check if buffer full if (in == 16) { buffer[75] = '\0'; printWithIndent(cfg, buffer, 1); in = 0; } return; } int displayObject(CONFIG *cfg, OBJECT *obj, int raw) { char text[32]; switch (obj->type) { case 0x00: // Singleton printWithIndent(cfg, obj->data.text, 1); break; case 0x01: // Integer if (raw == 0) printWithIndent(cfg, "", 0); sprintf(text, "%ld", obj->data.integer); outputText(cfg, text); if (raw == 0) outputText(cfg, "\n"); break; case 0x02: // Float if (raw == 0) printWithIndent(cfg, "", 0); sprintf(text, "%f", obj->data.real); outputText(cfg, text); if (raw == 0) outputText(cfg, "\n"); break; case 0x03: // Date if (raw == 0) printWithIndent(cfg, "", 0); outputText(cfg, ctime(&(obj->data.date))); if (raw == 0) outputText(cfg, "\n"); break; case 0x04: // Binary data if (raw == 0) printWithIndent(cfg, "", 1); indent += INDENT_INCREMENT; for (int i=0; i < obj->length; i++) displayHex(cfg, obj->data.binary[i]); displayHex(cfg, -1); indent -= INDENT_INCREMENT; if (raw == 0) printWithIndent(cfg, "", 1); break; case 0x05: // String if (raw == 0) printWithIndent(cfg, "", 0); outputText(cfg, (obj->data.text)); if (raw == 0) outputText(cfg, "\n"); break; case 0x06: // UTF16 string if (raw == 0) printWithIndent(cfg, "", 1); indent += INDENT_INCREMENT; for (int i=0; i < obj->length; i++) displayHex(cfg, obj->data.binary[i]); displayHex(cfg, -1); indent -= INDENT_INCREMENT; if (raw == 0) printWithIndent(cfg, "", 1); break; case 0x08: // UID if (raw == 0) printWithIndent(cfg, "", 0); sprintf(text, "%lu", obj->data.uid); outputText(cfg, text); if (raw == 0) outputText(cfg, "\n"); break; case 0x0A: // Array printWithIndent(cfg, "", 1); indent += INDENT_INCREMENT; for (int i=0; i < obj->length; i++) displayObject(cfg, obj->data.objects[i], 0); indent -= INDENT_INCREMENT; printWithIndent(cfg, "", 1); break; case 0x0D: // Dictionary printWithIndent(cfg, "", 1); indent += INDENT_INCREMENT; for (int i=0; i < obj->length; i++) { printWithIndent(cfg, "", 0); displayObject(cfg, obj->data.keys[i].key, 1); outputText(cfg, "\n"); displayObject(cfg, obj->data.keys[i].value, 0); } indent -= INDENT_INCREMENT; printWithIndent(cfg, "", 1); break; default: sprintf(text, "Cannot display type: %d\n", obj->type); outputText(cfg, text); break; } return ERROR_NONE; } int releaseObject(OBJECT *obj) { int i; switch (obj->type) { case 0x00: // Singleton case 0x01: // Int case 0x02: // Float case 0x03: // Date case 0x04: // Binary case 0x05: // ASCII case 0x06: // UTF16 case 0x08: // UID break; case 0x0A: // Array for (i=0; i < obj->length; i++) releaseObject(obj->data.objects[i]); break; case 0x0D: // Dictionary for (i=0; i < obj->length; i++) { releaseObject(obj->data.keys[i].key); releaseObject(obj->data.keys[i].value); } break; } free(obj); return ERROR_NONE; } int parsePlist(char **result, const char *data, int dataLength) { CONFIG cfg; char *ptr; OBJECT *obj; int err = ERROR_NONE; int version; long offset; long length; char text[32]; // Determine the file size and save cfg.buffer = (unsigned char *)data; cfg.bufferLength = dataLength; // Preset the output buffer cfg.outputBufferLength = 0; cfg.outputBufferIn = 0; cfg.outputBuffer = NULL; // Read the header err = readHeader(&cfg); if (err != ERROR_NONE) return err; version = (int)(cfg.buffer[7] - '0'); // Read the trailer err = readTrailer(&cfg); if (err != ERROR_NONE) return err; // ERROR_INVALID_TRAILER; // Locate and read the root object offset = cfg.offsetTable[cfg.rootObjectReference]; err = readObject(&cfg, offset, &obj); // If no error display the root object and hence the whole object tree if (err != ERROR_NONE) return err; sprintf(text, "\n", version); outputText(&cfg, text); displayObject(&cfg, obj, 0); outputText(&cfg, "\n"); // Create return data length = strlen((const char *)(cfg.outputBuffer)); ptr = malloc(length + 1); *result = ptr; if (ptr != NULL) { for (int i=0; i < length; i++) *(ptr++) = cfg.outputBuffer[i]; *ptr = '\0'; } else err = ERROR_INSUFFICIENT_MEMORY; // Release assigned memory releaseObject(obj); free(cfg.offsetTable); free(cfg.outputBuffer); return err; } static char map[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** Encode Base64 * */ int encodeBase64(char **result, const unsigned char *data, int dataLength) { unsigned char d; int b; int bitsLeft = 0; int in = 0; int out = 0; int encodedLength = dataLength * 4 / 3 + 4; char *encoded = malloc(encodedLength); *result = encoded; if (encoded == NULL) return ERROR_INSUFFICIENT_MEMORY; while (out < dataLength) { d = data[out++]; switch (bitsLeft) { case 0: encoded[in++] = map[d >> 2]; b = d & 0x03; bitsLeft = 2; break; case 2: b = (b << 8) | d; encoded[in++] = map[b >> 4]; b &= 0x0F; bitsLeft = 4; break; case 4: b = (b << 8) | d; encoded[in++] = map[b >> 6]; encoded[in++] = map[b & 0x03F]; bitsLeft = 0; break; } } /* Flush remaining bits */ switch (bitsLeft) { case 2: encoded[in++] = map[b << 4]; encoded[in++] = '='; encoded[in++] = '='; break; case 4: encoded[in++] = map[b << 2]; encoded[in++] = '='; break; default: break; } /* Terminate as string */ encoded[in] = '\0'; return ERROR_NONE; } static unsigned char unmap[256] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 00 - 07 0x81, 0x80, 0x81, 0x80, 0x80, 0x81, 0x80, 0x80, // 08 - 0F 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 10 - 17 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 18 - 1F 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 20 - 27 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, // 28 - 2F 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 30 - 37 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80, // 38 - 3F 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 40 - 47 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 48 - 4F 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 50 - 57 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80, // 58 - 5F 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 60 - 67 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 68 - 6F 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 70 - 77 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, // 78 - 7F 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 80 - 87 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 88 - 8F 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 90 - 97 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 98 - 9F 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // A0 - A7 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // A8 - AF 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // B0 - B7 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // B8 - BF 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // C0 - C7 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // C8 - CF 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // D0 - D7 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // D8 - DF 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // E0 - E7 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // E8 - EF 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // F0 - F7 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // F8 - FF }; /*** decodeBase64 * * Returns decoded data and length. */ int decodeBase64(unsigned char **result, int *resultLength, const char *data, int dataLength) { int bitsLeft = 8; int in = 0; unsigned char b; unsigned char d; unsigned char *decoded = malloc(dataLength * 3 / 4 + 3); *result = decoded; *resultLength = 0; if (decoded == NULL) return ERROR_INSUFFICIENT_MEMORY; while (*data != '\0') { // Get character and check valid d = unmap[*(data++)]; if (d > 0x3F) { if (d == 0x80) { free(decoded); return ERROR_INVALID_CHARACTER; } break; // padding space } switch (bitsLeft) { case 8: decoded[in] = d; bitsLeft = 2; break; case 2: decoded[in] = (decoded[in] << 2) | (d >> 4); decoded[++in] = d & 0x0F; bitsLeft = 4; break; case 4: decoded[in] = (decoded[in] << 4) | (d >> 2); decoded[++in] = d & 0x03; bitsLeft = 6; break; case 6: decoded[in] = (decoded[in] << 6) | d; in++; bitsLeft = 8; break; } } *resultLength = in; return ERROR_NONE; } /** Wrapper functions * */ void freeResult(void *ptr) { if (ptr != NULL) free(ptr); return; } static void plistFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ int resultLength; int errorCode = 0; char *result = NULL; assert( argc==1 ); switch( sqlite3_value_type(argv[0]) ){ case SQLITE_TEXT: case SQLITE_BLOB: { const char *data = sqlite3_value_text(argv[0]); const int dataLength = sqlite3_value_bytes(argv[0]); errorCode = parsePlist(&result, data, dataLength); if (errorCode == ERROR_NONE) { resultLength = strlen(result); sqlite3_result_text(context, result, resultLength, &freeResult); } else { if (sqlite3_value_type(argv[0]) == SQLITE_TEXT) sqlite3_result_text(context, data, dataLength, NULL); else sqlite3_result_blob(context, data, dataLength, NULL); } break; } default: { sqlite3_result_null(context); break; } } } static void encodeBase64Func(sqlite3_context *context, int argc, sqlite3_value **argv){ int resultLength; int errorCode = 0; int dataLength; const unsigned char *data; char *result = NULL; assert( argc==1 ); switch( sqlite3_value_type(argv[0]) ){ case SQLITE_BLOB: data = sqlite3_value_blob(argv[0]); dataLength = sqlite3_value_bytes(argv[0]); errorCode = encodeBase64(&result, data, dataLength); if (errorCode == ERROR_NONE) { resultLength = strlen(result); sqlite3_result_text(context, result, resultLength, &freeResult); } else { sqlite3_result_blob(context, data, dataLength, NULL); } break; case SQLITE_TEXT: { data = sqlite3_value_text(argv[0]); dataLength = sqlite3_value_bytes(argv[0]); sqlite3_result_text(context, data, dataLength, NULL); errorCode = encodeBase64(&result, data, dataLength); if (errorCode == ERROR_NONE) { resultLength = strlen(result); sqlite3_result_text(context, result, resultLength, &freeResult); } else { sqlite3_result_text(context, data, dataLength, NULL); } break; } default: { sqlite3_result_null(context); break; } } } /*** isText * * Returns zero if supplied data is entirely * ASCII printable characters or white space. */ int isText(unsigned char *data, int dataLength) { static unsigned char map[256] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; int result = 0; for (int i=0; i < dataLength; i++) result |= map[*(data++)]; return result; } /** isUTF8 * * Returns one if the characters conform to UTF8 format in so * far as all the byte lengths are consistent. It does not * check for overlong encodings or invalid characters. A zero * is returned if the format is not consistent. * Note that a file of all zeros will be returned as UTF8. */ int isUTF8(unsigned char *data, int length) { int count = 0; while (length-- > 0) { unsigned char d = *(data++); switch (count) { case 0: /* First character */ if ((d & 0x80) == 0) continue; /* 7 bit ASCII */ if ((d & 0xE0) == 0xC0) { count = 1; /* 2 byte code */ break; } if ((d & 0xF0) == 0xE0) { count = 2; /* 3 byte code */ break; } if ((d & 0xF8) == 0xF0) { count = 3; /* 4 byte code */ break; } return 0; default: count--; if ((d & 0xC0) != 0x80) return 0; break; } } return (count == 0) ? 1 : 0; } static void decodeBase64Func(sqlite3_context *context, int argc, sqlite3_value **argv){ int resultLength; int errorCode = 0; unsigned char *result = NULL; assert( argc==1 ); switch( sqlite3_value_type(argv[0]) ){ case SQLITE_BLOB: case SQLITE_TEXT: { const char *data = sqlite3_value_text(argv[0]); int dataLength = sqlite3_value_bytes(argv[0]); errorCode = decodeBase64(&result, &resultLength, data, dataLength); if (errorCode == ERROR_NONE) { if (isUTF8(result, resultLength)) sqlite3_result_text(context, result, resultLength, &freeResult); else sqlite3_result_blob(context, result, resultLength, &freeResult); } else { if (sqlite3_value_type(argv[0]) == SQLITE_TEXT) sqlite3_result_text(context, data, dataLength, NULL); else sqlite3_result_blob(context, data, dataLength, NULL); } break; } default: { sqlite3_result_null(context); break; } } } /** RegisterExtensionFormats * * Register the parsing functions with sqlite */ int RegisterExtensionFormats(sqlite3 *db) { sqlite3_create_function(db, "plist", 1, 0, db, plistFunc, 0, 0); sqlite3_create_function(db, "unBase64", 1, 0, db, decodeBase64Func, 0, 0); sqlite3_create_function(db, "toBase64", 1, 0, db, encodeBase64Func, 0, 0); } #ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); RegisterExtensionFormats(db); return rc; } #endif sqlitebrowser-sqlitebrowser-5733cb7/src/extensions/extension-formats.def000066400000000000000000000001371463772530400270300ustar00rootroot00000000000000EXPORTS RegisterExtensionFormats sqlite3_api sqlite3_extension_init freeResult sqlitebrowser-sqlitebrowser-5733cb7/src/extensions/extension-functions.c000066400000000000000000001457361463772530400270700ustar00rootroot00000000000000/* This library will provide common mathematical and string functions in SQL queries using the operating system libraries or provided definitions. It includes the following functions: Math: acos, asin, atan, atn2, atan2, acosh, asinh, atanh, difference, degrees, radians, cos, sin, tan, cot, cosh, sinh, tanh, coth, exp, log, log10, power, sign, sqrt, square, ceil, floor, pi. String: replicate, charindex, leftstr, rightstr, ltrim, rtrim, trim, replace, reverse, proper, padl, padr, padc, strfilter. Aggregate: stdev, variance, mode, median, lower_quartile, upper_quartile. The string functions ltrim, rtrim, trim, replace are included in recent versions of SQLite and so by default do not build. Compilation instructions: Compile this C source file into a dynamic library as follows: * Linux: gcc -fPIC -lm -shared extension-functions.c -o libsqlitefunctions.so * macOS: gcc -fno-common -dynamiclib extension-functions.c -o libsqlitefunctions.dylib (You may need to add flags -I /opt/local/include/ -L/opt/local/lib -lsqlite3 if your sqlite3 is installed from Mac ports, or -I /sw/include/ -L/sw/lib -lsqlite3 if installed with Fink.) * Windows: 1. Install MinGW (http://www.mingw.org/) and you will get the gcc (gnu compiler collection) 2. add the path to your path variable (isn't done during the installation!) 3. compile: gcc -shared -I "path" -o libsqlitefunctions.so extension-functions.c (path = path of sqlite3ext.h; i.e. C:\programs\sqlite) Usage instructions for applications calling the sqlite3 API functions: In your application, call sqlite3_enable_load_extension(db,1) to allow loading external libraries. Then load the library libsqlitefunctions using sqlite3_load_extension; the third argument should be 0. See http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions. Select statements may now use these functions, as in SELECT cos(radians(inclination)) FROM satsum WHERE satnum = 25544; Usage instructions for the sqlite3 program: If the program is built so that loading extensions is permitted, the following will work: sqlite> SELECT load_extension('./libsqlitefunctions.so'); sqlite> select cos(radians(45)); 0.707106781186548 Note: Loading extensions is by default prohibited as a security measure; see "Security Considerations" in http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions. If the sqlite3 program and library are built this way, you cannot use these functions from the program, you must write your own program using the sqlite3 API, and call sqlite3_enable_load_extension as described above, or else rebuilt the sqlite3 program to allow loadable extensions. Alterations: The instructions are for Linux, Mac OS X, and Windows; users of other OSes may need to modify this procedure. In particular, if your math library lacks one or more of the needed trig or log functions, comment out the appropriate HAVE_ #define at the top of file. If you do not wish to make a loadable module, comment out the define for COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE. If you are using a version of SQLite without the trim functions and replace, comment out the HAVE_TRIM #define. Liam Healy History: 2010-01-06 Correct check for argc in squareFunc, and add Windows compilation instructions. 2009-06-24 Correct check for argc in properFunc. 2008-09-14 Add check that memory was actually allocated after sqlite3_malloc or sqlite3StrDup, call sqlite3_result_error_nomem if not. Thanks to Robert Simpson. 2008-06-13 Change to instructions to indicate use of the math library and that program might work. 2007-10-01 Minor clarification to instructions. 2007-09-29 Compilation as loadable module is optional with COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE. 2007-09-28 Use sqlite3_extension_init and macros SQLITE_EXTENSION_INIT1, SQLITE_EXTENSION_INIT2, so that it works with sqlite3_load_extension. Thanks to Eric Higashino and Joe Wilson. New instructions for Mac compilation. 2007-09-17 With help from Joe Wilson and Nuno Luca, made use of external interfaces so that compilation is no longer dependent on SQLite source code. Merged source, header, and README into a single file. Added casts so that Mac will compile without warnings (unsigned and signed char). 2007-09-05 Included some definitions from sqlite 3.3.13 so that this will continue to work in newer versions of sqlite. Completed description of functions available. 2007-03-27 Revised description. 2007-03-23 Small cleanup and a bug fix on the code. This was mainly letting errno flag errors encountered in the math library and checking the result, rather than pre-checking. This fixes a bug in power that would cause an error if any non-positive number was raised to any power. 2007-02-07 posted by Mikey C to sqlite mailing list. Original code 2006 June 05 by relicoder. */ //#include "config.h" #define COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE 1 #define HAVE_ACOSH 1 #define HAVE_ASINH 1 #define HAVE_ATANH 1 #define HAVE_SINH 1 #define HAVE_COSH 1 #define HAVE_TANH 1 #define HAVE_LOG10 1 #define HAVE_ISBLANK 1 #define SQLITE_SOUNDEX 1 #define HAVE_TRIM 1 /* LMH 2007-03-25 if sqlite has trim functions */ #ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #else #include "sqlite3.h" #endif #include /* relicoder */ #include #include #include #include /* LMH 2007-03-25 */ #include #include #ifndef _MAP_H_ #define _MAP_H_ #include /* ** Simple binary tree implementation to use in median, mode and quartile calculations ** Tree is not necessarily balanced. That would require something like red&black trees of AVL */ typedef int(*cmp_func)(const void *, const void *); typedef void(*map_iterator)(void*, int64_t, void*); typedef struct node{ struct node *l; struct node *r; void* data; int64_t count; } node; typedef struct map{ node *base; cmp_func cmp; short free; } map; /* ** creates a map given a comparison function */ map map_make(cmp_func cmp); /* ** inserts the element e into map m */ void map_insert(map *m, void *e); /* ** executes function iter over all elements in the map, in key increasing order */ void map_iterate(map *m, map_iterator iter, void* p); /* ** frees all memory used by a map */ void map_destroy(map *m); /* ** compares 2 integers ** to use with map_make */ int int_cmp(const void *a, const void *b); /* ** compares 2 doubles ** to use with map_make */ int double_cmp(const void *a, const void *b); #endif /* _MAP_H_ */ typedef uint8_t u8; typedef uint16_t u16; typedef int64_t i64; static char *sqlite3StrDup( const char *z ) { char *res = sqlite3_malloc( strlen(z)+1 ); return strcpy( res, z ); } /* ** These are copied verbatim from fun.c so as to not have the names exported */ /* LMH from sqlite3 3.3.13 */ /* ** This table maps from the first byte of a UTF-8 character to the number ** of trailing bytes expected. A value '4' indicates that the table key ** is not a legal first byte for a UTF-8 character. */ static const u8 xtra_utf8_bytes[256] = { /* 0xxxxxxx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10wwwwww */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* 110yyyyy */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1110zzzz */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 11110yyy */ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, }; /* ** This table maps from the number of trailing bytes in a UTF-8 character ** to an integer constant that is effectively calculated for each character ** read by a naive implementation of a UTF-8 character reader. The code ** in the READ_UTF8 macro explains things best. */ static const int xtra_utf8_bits[] = { 0, 12416, /* (0xC0 << 6) + (0x80) */ 925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */ 63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */ }; /* ** If a UTF-8 character contains N bytes extra bytes (N bytes follow ** the initial byte so that the total character length is N+1) then ** masking the character with utf8_mask[N] must produce a non-zero ** result. Otherwise, we have an (illegal) overlong encoding. */ static const int utf_mask[] = { 0x00000000, 0xffffff80, 0xfffff800, 0xffff0000, }; /* LMH salvaged from sqlite3 3.3.13 source code src/utf.c */ #define READ_UTF8(zIn, c) { \ int xtra; \ c = *(zIn)++; \ xtra = xtra_utf8_bytes[c]; \ switch( xtra ){ \ case 4: c = (int)0xFFFD; break; \ case 3: c = (c<<6) + *(zIn)++; \ case 2: c = (c<<6) + *(zIn)++; \ case 1: c = (c<<6) + *(zIn)++; \ c -= xtra_utf8_bits[xtra]; \ if( (utf_mask[xtra]&c)==0 \ || (c&0xFFFFF800)==0xD800 \ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ } \ } static int sqlite3ReadUtf8(const unsigned char *z){ int c; READ_UTF8(z, c); return c; } #define SKIP_UTF8(zIn) { \ zIn += (xtra_utf8_bytes[*(u8 *)zIn] + 1); \ } /* ** pZ is a UTF-8 encoded unicode string. If nByte is less than zero, ** return the number of unicode characters in pZ up to (but not including) ** the first 0x00 byte. If nByte is not less than zero, return the ** number of unicode characters in the first nByte of pZ (or up to ** the first 0x00, whichever comes first). */ static int sqlite3Utf8CharLen(const char *z, int nByte){ int r = 0; const char *zTerm; if( nByte>=0 ){ zTerm = &z[nByte]; }else{ zTerm = (const char *)(-1); } assert( z<=zTerm ); while( *z!=0 && z 0) ? 1: ( iVal < 0 ) ? -1: 0; sqlite3_result_int64(context, iVal); break; } case SQLITE_NULL: { sqlite3_result_null(context); break; } default: { /* 2nd change below. Line for abs was: if( rVal<0 ) rVal = rVal * -1.0; */ rVal = sqlite3_value_double(argv[0]); rVal = ( rVal > 0) ? 1: ( rVal < 0 ) ? -1: 0; sqlite3_result_double(context, rVal); break; } } } /* ** smallest integer value not less than argument */ static void ceilFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ double rVal=0.0; i64 iVal=0; assert( argc==1 ); switch( sqlite3_value_type(argv[0]) ){ case SQLITE_INTEGER: { i64 iVal = sqlite3_value_int64(argv[0]); sqlite3_result_int64(context, iVal); break; } case SQLITE_NULL: { sqlite3_result_null(context); break; } default: { rVal = sqlite3_value_double(argv[0]); sqlite3_result_int64(context, (i64) ceil(rVal)); break; } } } /* ** largest integer value not greater than argument */ static void floorFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ double rVal=0.0; i64 iVal=0; assert( argc==1 ); switch( sqlite3_value_type(argv[0]) ){ case SQLITE_INTEGER: { i64 iVal = sqlite3_value_int64(argv[0]); sqlite3_result_int64(context, iVal); break; } case SQLITE_NULL: { sqlite3_result_null(context); break; } default: { rVal = sqlite3_value_double(argv[0]); sqlite3_result_int64(context, (i64) floor(rVal)); break; } } } /* ** Given a string (s) in the first argument and an integer (n) in the second returns the ** string that constains s contatenated n times */ static void replicateFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ unsigned char *z; /* input string */ unsigned char *zo; /* result string */ i64 iCount; /* times to repeat */ i64 nLen; /* length of the input string (no multibyte considerations) */ i64 nTLen; /* length of the result string (no multibyte considerations) */ i64 i=0; if( argc!=2 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; iCount = sqlite3_value_int64(argv[1]); if( iCount<0 ){ sqlite3_result_error(context, "domain error", -1); }else{ nLen = sqlite3_value_bytes(argv[0]); nTLen = nLen*iCount; z=sqlite3_malloc(nTLen+1); zo=sqlite3_malloc(nLen+1); if (!z || !zo){ sqlite3_result_error_nomem(context); if (z) sqlite3_free(z); if (zo) sqlite3_free(zo); return; } strcpy((char*)zo, (char*)sqlite3_value_text(argv[0])); for(i=0; i=n it's a NOP ** padl(NULL) = NULL */ static void padlFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ i64 ilen; /* length to pad to */ i64 zl; /* length of the input string (UTF-8 chars) */ int i = 0; const char *zi; /* input string */ char *zo; /* output string */ char *zt; assert( argc==2 ); if( sqlite3_value_type(argv[0]) == SQLITE_NULL ){ sqlite3_result_null(context); }else{ zi = (char *)sqlite3_value_text(argv[0]); ilen = sqlite3_value_int64(argv[1]); /* check domain */ if(ilen<0){ sqlite3_result_error(context, "domain error", -1); return; } zl = sqlite3Utf8CharLen(zi, -1); if( zl>=ilen ){ /* string is longer than the requested pad length, return the same string (dup it) */ zo = sqlite3StrDup(zi); if (!zo){ sqlite3_result_error_nomem(context); return; } sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); }else{ zo = sqlite3_malloc(strlen(zi)+ilen-zl+1); if (!zo){ sqlite3_result_error_nomem(context); return; } zt = zo; for(i=1; i+zl<=ilen; ++i){ *(zt++)=' '; } /* no need to take UTF-8 into consideration here */ strcpy(zt,zi); } sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); sqlite3_free(zo); } } /* ** given an input string (s) and an integer (n) appends spaces at the end of s ** until it has a length of n characters. ** When s has a length >=n it's a NOP ** padl(NULL) = NULL */ static void padrFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ i64 ilen; /* length to pad to */ i64 zl; /* length of the input string (UTF-8 chars) */ i64 zll; /* length of the input string (bytes) */ int i = 0; const char *zi; /* input string */ char *zo; /* output string */ char *zt; assert( argc==2 ); if( sqlite3_value_type(argv[0]) == SQLITE_NULL ){ sqlite3_result_null(context); }else{ zi = (char *)sqlite3_value_text(argv[0]); ilen = sqlite3_value_int64(argv[1]); /* check domain */ if(ilen<0){ sqlite3_result_error(context, "domain error", -1); return; } zl = sqlite3Utf8CharLen(zi, -1); if( zl>=ilen ){ /* string is longer than the requested pad length, return the same string (dup it) */ zo = sqlite3StrDup(zi); if (!zo){ sqlite3_result_error_nomem(context); return; } sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); }else{ zll = strlen(zi); zo = sqlite3_malloc(zll+ilen-zl+1); if (!zo){ sqlite3_result_error_nomem(context); return; } zt = strcpy(zo,zi)+zll; for(i=1; i+zl<=ilen; ++i){ *(zt++) = ' '; } *zt = '\0'; } sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); sqlite3_free(zo); } } /* ** given an input string (s) and an integer (n) appends spaces at the end of s ** and adds spaces at the beginning of s until it has a length of n characters. ** Tries to add has many characters at the left as at the right. ** When s has a length >=n it's a NOP ** padl(NULL) = NULL */ static void padcFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ i64 ilen; /* length to pad to */ i64 zl; /* length of the input string (UTF-8 chars) */ i64 zll; /* length of the input string (bytes) */ int i = 0; const char *zi; /* input string */ char *zo; /* output string */ char *zt; assert( argc==2 ); if( sqlite3_value_type(argv[0]) == SQLITE_NULL ){ sqlite3_result_null(context); }else{ zi = (char *)sqlite3_value_text(argv[0]); ilen = sqlite3_value_int64(argv[1]); /* check domain */ if(ilen<0){ sqlite3_result_error(context, "domain error", -1); return; } zl = sqlite3Utf8CharLen(zi, -1); if( zl>=ilen ){ /* string is longer than the requested pad length, return the same string (dup it) */ zo = sqlite3StrDup(zi); if (!zo){ sqlite3_result_error_nomem(context); return; } sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); }else{ zll = strlen(zi); zo = sqlite3_malloc(zll+ilen-zl+1); if (!zo){ sqlite3_result_error_nomem(context); return; } zt = zo; for(i=1; 2*i+zl<=ilen; ++i){ *(zt++) = ' '; } strcpy(zt, zi); zt+=zll; for(; i+zl<=ilen; ++i){ *(zt++) = ' '; } *zt = '\0'; } sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); sqlite3_free(zo); } } /* ** given 2 string (s1,s2) returns the string s1 with the characters NOT in s2 removed ** assumes strings are UTF-8 encoded */ static void strfilterFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ const char *zi1; /* first parameter string (searched string) */ const char *zi2; /* second parameter string (vcontains valid characters) */ const char *z1; const char *z21; const char *z22; char *zo; /* output string */ char *zot; int c1 = 0; int c2 = 0; assert( argc==2 ); if( sqlite3_value_type(argv[0]) == SQLITE_NULL || sqlite3_value_type(argv[1]) == SQLITE_NULL ){ sqlite3_result_null(context); }else{ zi1 = (char *)sqlite3_value_text(argv[0]); zi2 = (char *)sqlite3_value_text(argv[1]); /* ** maybe I could allocate less, but that would imply 2 passes, rather waste ** (possibly) some memory */ zo = sqlite3_malloc(strlen(zi1)+1); if (!zo){ sqlite3_result_error_nomem(context); return; } zot = zo; z1 = zi1; while( (c1=sqliteCharVal((unsigned char *)z1))!=0 ){ z21=zi2; while( (c2=sqliteCharVal((unsigned char *)z21))!=0 && c2!=c1 ){ sqliteNextChar(z21); } if( c2!=0){ z22=z21; sqliteNextChar(z22); strncpy(zot, z21, z22-z21); zot+=z22-z21; } sqliteNextChar(z1); } *zot = '\0'; sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); sqlite3_free(zo); } } /* ** Given a string z1, retutns the (0 based) index of it's first occurence ** in z2 after the first s characters. ** Returns -1 when there isn't a match. ** updates p to point to the character where the match occured. ** This is an auxiliary function. */ static int _substr(const char* z1, const char* z2, int s, const char** p){ int c = 0; int rVal=-1; const char* zt1; const char* zt2; int c1,c2; if( '\0'==*z1 ){ return -1; } while( (sqliteCharVal((unsigned char *)z2) != 0) && (c++)=0 ? rVal+s : rVal; } /* ** given 2 input strings (s1,s2) and an integer (n) searches from the nth character ** for the string s1. Returns the position where the match occured. ** Characters are counted from 1. ** 0 is returned when no match occurs. */ static void charindexFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ const u8 *z1; /* s1 string */ u8 *z2; /* s2 string */ int s=0; int rVal=0; assert( argc==3 ||argc==2); if( SQLITE_NULL==sqlite3_value_type(argv[0]) || SQLITE_NULL==sqlite3_value_type(argv[1])){ sqlite3_result_null(context); return; } z1 = sqlite3_value_text(argv[0]); if( z1==0 ) return; z2 = (u8*) sqlite3_value_text(argv[1]); if(argc==3){ s = sqlite3_value_int(argv[2])-1; if(s<0){ s=0; } }else{ s = 0; } rVal = _substr((char *)z1,(char *)z2,s,NULL); sqlite3_result_int(context, rVal+1); } /* ** given a string (s) and an integer (n) returns the n leftmost (UTF-8) characters ** if the string has a length<=n or is NULL this function is NOP */ static void leftFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ int c=0; int cc=0; int l=0; const unsigned char *z; /* input string */ const unsigned char *zt; unsigned char *rz; /* output string */ assert( argc==2); if( SQLITE_NULL==sqlite3_value_type(argv[0]) || SQLITE_NULL==sqlite3_value_type(argv[1])){ sqlite3_result_null(context); return; } z = sqlite3_value_text(argv[0]); l = sqlite3_value_int(argv[1]); zt = z; while( sqliteCharVal(zt) && c++ 0 ){ sqliteNextChar(zt); } rz = sqlite3_malloc(ze-zt+1); if (!rz){ sqlite3_result_error_nomem(context); return; } strcpy((char*) rz, (char*) (zt)); sqlite3_result_text(context, (char*)rz, -1, SQLITE_TRANSIENT); sqlite3_free(rz); } #ifndef HAVE_TRIM /* ** removes the whitespaces at the beginning of a string. */ const char* ltrim(const char* s){ while( *s==' ' ) ++s; return s; } /* ** removes the whitespaces at the end of a string. ** !mutates the input string! */ void rtrim(char* s){ char* ss = s+strlen(s)-1; while( ss>=s && *ss==' ' ) --ss; *(ss+1)='\0'; } /* ** Removes the whitespace at the beginning of a string */ static void ltrimFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ const char *z; assert( argc==1); if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ sqlite3_result_null(context); return; } z = sqlite3_value_text(argv[0]); sqlite3_result_text(context, ltrim(z), -1, SQLITE_TRANSIENT); } /* ** Removes the whitespace at the end of a string */ static void rtrimFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ const char *z; char *rz; /* try not to change data in argv */ assert( argc==1); if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ sqlite3_result_null(context); return; } z = sqlite3_value_text(argv[0]); rz = sqlite3StrDup(z); rtrim(rz); sqlite3_result_text(context, rz, -1, SQLITE_TRANSIENT); sqlite3_free(rz); } /* ** Removes the whitespace at the beginning and end of a string */ static void trimFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ const char *z; char *rz; /* try not to change data in argv */ assert( argc==1); if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ sqlite3_result_null(context); return; } z = sqlite3_value_text(argv[0]); rz = sqlite3StrDup(z); rtrim(rz); sqlite3_result_text(context, ltrim(rz), -1, SQLITE_TRANSIENT); sqlite3_free(rz); } #endif /* ** given a pointer to a string s1, the length of that string (l1), a new string (s2) ** and it's length (l2) appends s2 to s1. ** All lengths in bytes. ** This is just an auxiliary function */ // static void _append(char **s1, int l1, const char *s2, int l2){ // *s1 = realloc(*s1, (l1+l2+1)*sizeof(char)); // strncpy((*s1)+l1, s2, l2); // *(*(s1)+l1+l2) = '\0'; // } #ifndef HAVE_TRIM /* ** given strings s, s1 and s2 replaces occurrences of s1 in s by s2 */ static void replaceFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ const char *z1; /* string s (first parameter) */ const char *z2; /* string s1 (second parameter) string to look for */ const char *z3; /* string s2 (third parameter) string to replace occurrences of s1 with */ int lz1; int lz2; int lz3; int lzo=0; char *zo=0; int ret=0; const char *zt1; const char *zt2; assert( 3==argc ); if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ sqlite3_result_null(context); return; } z1 = sqlite3_value_text(argv[0]); z2 = sqlite3_value_text(argv[1]); z3 = sqlite3_value_text(argv[2]); /* handle possible null values */ if( 0==z2 ){ z2=""; } if( 0==z3 ){ z3=""; } lz1 = strlen(z1); lz2 = strlen(z2); lz3 = strlen(z3); #if 0 /* special case when z2 is empty (or null) nothing will be changed */ if( 0==lz2 ){ sqlite3_result_text(context, z1, -1, SQLITE_TRANSIENT); return; } #endif zt1=z1; zt2=z1; while(1){ ret=_substr(z2,zt1 , 0, &zt2); if( ret<0 ) break; _append(&zo, lzo, zt1, zt2-zt1); lzo+=zt2-zt1; _append(&zo, lzo, z3, lz3); lzo+=lz3; zt1=zt2+lz2; } _append(&zo, lzo, zt1, lz1-(zt1-z1)); sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); sqlite3_free(zo); } #endif /* ** given a string returns the same string but with the characters in reverse order */ static void reverseFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ const char *z; const char *zt; char *rz; char *rzt; int l = 0; int i = 0; assert( 1==argc ); if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ sqlite3_result_null(context); return; } z = (char *)sqlite3_value_text(argv[0]); l = strlen(z); rz = sqlite3_malloc(l+1); if (!rz){ sqlite3_result_error_nomem(context); return; } rzt = rz+l; *(rzt--) = '\0'; zt=z; while( sqliteCharVal((unsigned char *)zt)!=0 ){ z=zt; sqliteNextChar(zt); for(i=1; zt-i>=z; ++i){ *(rzt--)=*(zt-i); } } sqlite3_result_text(context, rz, -1, SQLITE_TRANSIENT); sqlite3_free(rz); } /* ** An instance of the following structure holds the context of a ** stdev() or variance() aggregate computation. ** implementaion of http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Algorithm_II ** less prone to rounding errors */ typedef struct StdevCtx StdevCtx; struct StdevCtx { double rM; double rS; i64 cnt; /* number of elements */ }; /* ** An instance of the following structure holds the context of a ** mode() or median() aggregate computation. ** Depends on structures defined in map.c (see map & map) ** These aggregate functions only work for integers and floats although ** they could be made to work for strings. This is usually considered meaningless. ** Only usuall order (for median), no use of collation functions (would this even make sense?) */ typedef struct ModeCtx ModeCtx; struct ModeCtx { i64 riM; /* integer value found so far */ double rdM; /* double value found so far */ i64 cnt; /* number of elements so far */ double pcnt; /* number of elements smaller than a percentile */ i64 mcnt; /* maximum number of occurrences (for mode) */ i64 mn; /* number of occurrences (for mode and percentiles) */ i64 is_double; /* whether the computation is being done for doubles (>0) or integers (=0) */ map* m; /* map structure used for the computation */ int done; /* whether the answer has been found */ }; /* ** called for each value received during a calculation of stdev or variance */ static void varianceStep(sqlite3_context *context, int argc, sqlite3_value **argv){ StdevCtx *p; double delta; double x; assert( argc==1 ); p = sqlite3_aggregate_context(context, sizeof(*p)); /* only consider non-null values */ if( SQLITE_NULL != sqlite3_value_numeric_type(argv[0]) ){ p->cnt++; x = sqlite3_value_double(argv[0]); delta = (x-p->rM); p->rM += delta/p->cnt; p->rS += delta*(x-p->rM); } } /* ** called for each value received during a calculation of mode of median */ static void modeStep(sqlite3_context *context, int argc, sqlite3_value **argv){ ModeCtx *p; i64 xi=0; double xd=0.0; i64 *iptr; double *dptr; int type; assert( argc==1 ); type = sqlite3_value_numeric_type(argv[0]); if( type == SQLITE_NULL) return; p = sqlite3_aggregate_context(context, sizeof(*p)); if( 0==(p->m) ){ p->m = calloc(1, sizeof(map)); if( type==SQLITE_INTEGER ){ /* map will be used for integers */ *(p->m) = map_make(int_cmp); p->is_double = 0; }else{ p->is_double = 1; /* map will be used for doubles */ *(p->m) = map_make(double_cmp); } } ++(p->cnt); if( 0==p->is_double ){ xi = sqlite3_value_int64(argv[0]); iptr = (i64*)calloc(1,sizeof(i64)); *iptr = xi; map_insert(p->m, iptr); }else{ xd = sqlite3_value_double(argv[0]); dptr = (double*)calloc(1,sizeof(double)); *dptr = xd; map_insert(p->m, dptr); } } /* ** Auxiliary function that iterates all elements in a map and finds the mode ** (most frequent value) */ static void modeIterate(void* e, i64 c, void* pp){ i64 ei; double ed; ModeCtx *p = (ModeCtx*)pp; if( 0==p->is_double ){ ei = *(int*)(e); if( p->mcnt==c ){ ++p->mn; }else if( p->mcntriM = ei; p->mcnt = c; p->mn=1; } }else{ ed = *(double*)(e); if( p->mcnt==c ){ ++p->mn; }else if(p->mcntrdM = ed; p->mcnt = c; p->mn=1; } } } /* ** Auxiliary function that iterates all elements in a map and finds the median ** (the value such that the number of elements smaller is equal the the number of ** elements larger) */ static void medianIterate(void* e, i64 c, void* pp){ i64 ei; double ed; double iL; double iR; int il; int ir; ModeCtx *p = (ModeCtx*)pp; if(p->done>0) return; iL = p->pcnt; iR = p->cnt - p->pcnt; il = p->mcnt + c; ir = p->cnt - p->mcnt; if( il >= iL ){ if( ir >= iR ){ ++p->mn; if( 0==p->is_double ){ ei = *(int*)(e); p->riM += ei; }else{ ed = *(double*)(e); p->rdM += ed; } }else{ p->done=1; } } p->mcnt+=c; } /* ** Returns the mode value */ static void modeFinalize(sqlite3_context *context){ ModeCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->m ){ map_iterate(p->m, modeIterate, p); map_destroy(p->m); free(p->m); if( 1==p->mn ){ if( 0==p->is_double ) sqlite3_result_int64(context, p->riM); else sqlite3_result_double(context, p->rdM); } } } /* ** auxiliary function for percentiles */ static void _medianFinalize(sqlite3_context *context){ ModeCtx *p; p = (ModeCtx*) sqlite3_aggregate_context(context, 0); if( p && p->m ){ p->done=0; map_iterate(p->m, medianIterate, p); map_destroy(p->m); free(p->m); if( 0==p->is_double ) if( 1==p->mn ) sqlite3_result_int64(context, p->riM); else sqlite3_result_double(context, p->riM*1.0/p->mn); else sqlite3_result_double(context, p->rdM/p->mn); } } /* ** Returns the median value */ static void medianFinalize(sqlite3_context *context){ ModeCtx *p; p = (ModeCtx*) sqlite3_aggregate_context(context, 0); if( p!=0 ){ p->pcnt = (p->cnt)/2.0; _medianFinalize(context); } } /* ** Returns the lower_quartile value */ static void lower_quartileFinalize(sqlite3_context *context){ ModeCtx *p; p = (ModeCtx*) sqlite3_aggregate_context(context, 0); if( p!=0 ){ p->pcnt = (p->cnt)/4.0; _medianFinalize(context); } } /* ** Returns the upper_quartile value */ static void upper_quartileFinalize(sqlite3_context *context){ ModeCtx *p; p = (ModeCtx*) sqlite3_aggregate_context(context, 0); if( p!=0 ){ p->pcnt = (p->cnt)*3/4.0; _medianFinalize(context); } } /* ** Returns the stdev value */ static void stdevFinalize(sqlite3_context *context){ StdevCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>1 ){ sqlite3_result_double(context, sqrt(p->rS/(p->cnt-1))); }else{ sqlite3_result_double(context, 0.0); } } /* ** Returns the variance value */ static void varianceFinalize(sqlite3_context *context){ StdevCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>1 ){ sqlite3_result_double(context, p->rS/(p->cnt-1)); }else{ sqlite3_result_double(context, 0.0); } } #ifdef SQLITE_SOUNDEX /* relicoder factored code */ /* ** Calculates the soundex value of a string */ static void soundex(const u8 *zIn, char *zResult){ int i, j; static const unsigned char iCode[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, }; for(i=0; zIn[i] && !isalpha(zIn[i]); i++){} if( zIn[i] ){ zResult[0] = toupper(zIn[i]); for(j=1; j<4 && zIn[i]; i++){ int code = iCode[zIn[i]&0x7f]; if( code>0 ){ zResult[j++] = code + '0'; } } while( j<4 ){ zResult[j++] = '0'; } zResult[j] = 0; }else{ strcpy(zResult, "?000"); } } /* ** computes the number of different characters between the soundex value fo 2 strings */ static void differenceFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ char zResult1[8]; char zResult2[8]; char *zR1 = zResult1; char *zR2 = zResult2; int rVal = 0; int i = 0; const u8 *zIn1; const u8 *zIn2; assert( argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL || sqlite3_value_type(argv[1])==SQLITE_NULL ){ sqlite3_result_null(context); return; } zIn1 = (u8*)sqlite3_value_text(argv[0]); zIn2 = (u8*)sqlite3_value_text(argv[1]); soundex(zIn1, zR1); soundex(zIn2, zR2); for(i=0; i<4; ++i){ if( sqliteCharVal((unsigned char *)zR1)==sqliteCharVal((unsigned char *)zR2) ) ++rVal; sqliteNextChar(zR1); sqliteNextChar(zR2); } sqlite3_result_int(context, rVal); } #endif /* ** This function registered all of the above C functions as SQL ** functions. This should be the only routine in this file with ** external linkage. */ int RegisterExtensionFunctions(sqlite3 *db){ static const struct FuncDef { char *zName; signed char nArg; u8 argType; /* 0: none. 1: db 2: (-1) */ u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */ u8 needCollSeq; void (*xFunc)(sqlite3_context*,int,sqlite3_value **); } aFuncs[] = { /* math.h */ { "acos", 1, 0, SQLITE_UTF8, 0, acosFunc }, { "asin", 1, 0, SQLITE_UTF8, 0, asinFunc }, { "atan", 1, 0, SQLITE_UTF8, 0, atanFunc }, { "atn2", 2, 0, SQLITE_UTF8, 0, atn2Func }, /* XXX alias */ { "atan2", 2, 0, SQLITE_UTF8, 0, atn2Func }, { "acosh", 1, 0, SQLITE_UTF8, 0, acoshFunc }, { "asinh", 1, 0, SQLITE_UTF8, 0, asinhFunc }, { "atanh", 1, 0, SQLITE_UTF8, 0, atanhFunc }, { "difference", 2, 0, SQLITE_UTF8, 0, differenceFunc}, { "degrees", 1, 0, SQLITE_UTF8, 0, rad2degFunc }, { "radians", 1, 0, SQLITE_UTF8, 0, deg2radFunc }, { "cos", 1, 0, SQLITE_UTF8, 0, cosFunc }, { "sin", 1, 0, SQLITE_UTF8, 0, sinFunc }, { "tan", 1, 0, SQLITE_UTF8, 0, tanFunc }, { "cot", 1, 0, SQLITE_UTF8, 0, cotFunc }, { "cosh", 1, 0, SQLITE_UTF8, 0, coshFunc }, { "sinh", 1, 0, SQLITE_UTF8, 0, sinhFunc }, { "tanh", 1, 0, SQLITE_UTF8, 0, tanhFunc }, { "coth", 1, 0, SQLITE_UTF8, 0, cothFunc }, { "exp", 1, 0, SQLITE_UTF8, 0, expFunc }, { "log", 1, 0, SQLITE_UTF8, 0, logFunc }, { "log10", 1, 0, SQLITE_UTF8, 0, log10Func }, { "power", 2, 0, SQLITE_UTF8, 0, powerFunc }, { "sign", 1, 0, SQLITE_UTF8, 0, signFunc }, { "sqrt", 1, 0, SQLITE_UTF8, 0, sqrtFunc }, { "square", 1, 0, SQLITE_UTF8, 0, squareFunc }, { "ceil", 1, 0, SQLITE_UTF8, 0, ceilFunc }, { "floor", 1, 0, SQLITE_UTF8, 0, floorFunc }, { "pi", 0, 0, SQLITE_UTF8, 1, piFunc }, /* string */ { "replicate", 2, 0, SQLITE_UTF8, 0, replicateFunc }, { "charindex", 2, 0, SQLITE_UTF8, 0, charindexFunc }, { "charindex", 3, 0, SQLITE_UTF8, 0, charindexFunc }, { "leftstr", 2, 0, SQLITE_UTF8, 0, leftFunc }, { "rightstr", 2, 0, SQLITE_UTF8, 0, rightFunc }, #ifndef HAVE_TRIM { "ltrim", 1, 0, SQLITE_UTF8, 0, ltrimFunc }, { "rtrim", 1, 0, SQLITE_UTF8, 0, rtrimFunc }, { "trim", 1, 0, SQLITE_UTF8, 0, trimFunc }, { "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc }, #endif { "reverse", 1, 0, SQLITE_UTF8, 0, reverseFunc }, { "proper", 1, 0, SQLITE_UTF8, 0, properFunc }, { "padl", 2, 0, SQLITE_UTF8, 0, padlFunc }, { "padr", 2, 0, SQLITE_UTF8, 0, padrFunc }, { "padc", 2, 0, SQLITE_UTF8, 0, padcFunc }, { "strfilter", 2, 0, SQLITE_UTF8, 0, strfilterFunc }, }; /* Aggregate functions */ static const struct FuncDefAgg { char *zName; signed char nArg; u8 argType; u8 needCollSeq; void (*xStep)(sqlite3_context*,int,sqlite3_value**); void (*xFinalize)(sqlite3_context*); } aAggs[] = { { "stdev", 1, 0, 0, varianceStep, stdevFinalize }, { "variance", 1, 0, 0, varianceStep, varianceFinalize }, { "mode", 1, 0, 0, modeStep, modeFinalize }, { "median", 1, 0, 0, modeStep, medianFinalize }, { "lower_quartile", 1, 0, 0, modeStep, lower_quartileFinalize }, { "upper_quartile", 1, 0, 0, modeStep, upper_quartileFinalize }, }; int i; for(i=0; ineedCollSeq = 1; } } #endif } for(i=0; ineedCollSeq = 1; } } #endif } return 0; } #ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE int sqlite3_extension_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi){ SQLITE_EXTENSION_INIT2(pApi); RegisterExtensionFunctions(db); return 0; } #endif /* COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE */ map map_make(cmp_func cmp){ map r; r.cmp=cmp; r.base = 0; return r; } void* xcalloc(size_t nmemb, size_t size, char* s){ void* ret = calloc(nmemb, size); return ret; } void xfree(void* p){ free(p); } void node_insert(node** n, cmp_func cmp, void *e){ int c; node* nn; if(*n==0){ nn = (node*)xcalloc(1,sizeof(node), "for node"); nn->data = e; nn->count = 1; *n=nn; }else{ c=cmp((*n)->data,e); if(0==c){ ++((*n)->count); xfree(e); }else if(c>0){ /* put it right here */ node_insert(&((*n)->l), cmp, e); }else{ node_insert(&((*n)->r), cmp, e); } } } void map_insert(map *m, void *e){ node_insert(&(m->base), m->cmp, e); } void node_iterate(node *n, map_iterator iter, void* p){ if(n){ if(n->l) node_iterate(n->l, iter, p); iter(n->data, n->count, p); if(n->r) node_iterate(n->r, iter, p); } } void map_iterate(map *m, map_iterator iter, void* p){ node_iterate(m->base, iter, p); } void node_destroy(node *n){ if(0!=n){ xfree(n->data); if(n->l) node_destroy(n->l); if(n->r) node_destroy(n->r); xfree(n); } } void map_destroy(map *m){ node_destroy(m->base); } int int_cmp(const void *a, const void *b){ int64_t aa = *(int64_t *)(a); int64_t bb = *(int64_t *)(b); /* printf("cmp %d <=> %d\n",aa,bb); */ if(aa==bb) return 0; else if(aa %d\n",aa,bb); */ if(aa==bb) return 0; else if(aa %lld\n", ee,c); } sqlitebrowser-sqlitebrowser-5733cb7/src/extensions/extension-functions.def000066400000000000000000000004001463772530400273560ustar00rootroot00000000000000EXPORTS RegisterExtensionFunctions double_cmp int_cmp map_destroy map_insert map_iterate map_make node_destroy node_insert node_iterate print_elem sqlite3_api sqlite3_extension_init xcalloc xfree sqlitebrowser-sqlitebrowser-5733cb7/src/iconos2.ico000066400000000000000000002126401463772530400225400ustar00rootroot00000000000000BA(HCI   ÿÿÿCI  BA(CI  @ÿÿÿCI  BA(ØCI   @€ÿÿÿCI   @@BA(CI@@ E €ÿÿÿCI@@ U €€€À———ÂÂÂÞÞÞÀÀÀ’’’rrraaaUUUIII???555---%%%sss¾¾¾çççÌÌÌ•••pppaaaUUUIII???555---%%%rrrŠŠŠÄÄÄéééÌÌÌ•••ssscccXXXNNNDDD888---$$$sssŠŠŠ£££šššŠŠŠƒƒƒ}}}|||yyytttkkkWWW;;;"""```ttt£££¤¤¤ŽŽŽyyylllccc[[[XXX[[[eeerrrOOO$$$EEEvvvºººâââÊÊÊ“““ppp```TTTHHH>>>444---///333&&&sssˆˆˆÄÄÄíííÒÒÒ———sssaaaUUUJJJ@@@555,,,###rrr‹‹‹¯¯¯ªªª“““ƒƒƒ|||wwwtttrrrkkk]]]III111iiiyyyˆˆˆ———ššš|||rrriiidddcccgggooooooEEE DDDtttµµµÞÞÞÆÆÆ“““ppp```TTTHHH>>>555111888===)))ooo†††ÄÄÄíííÔÔÔ˜˜˜rrraaaUUUIII???444,,,###rrr‹‹‹¸¸¸ºººŸŸŸ†††yyyrrrmmmhhh___QQQ???+++ooo}}}†††………†††ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆ€€€kkk;;;<<>>===>>>EEEUUUlllƒƒƒ………UUU'''---UUU“““¦¦¦ÊÊÊååååååÐÐм¼¼ˆˆˆvvvkkkddd]]]WWWQQQLLLFFFAAA<<<777333---***)))555WWW=== JJJccc•••­­­ÒÒÒéééçççØØØÄÄÄŸŸŸ†††vvvkkkddd]]]WWWQQQLLLFFFAAA<<<777333...***&&&""" ***yyy€€€•••­­­ØØØíííëëëÞÞÞÌÌÌŸŸŸ†††vvvkkkddd]]]WWWQQQLLLFFFAAA<<<777333...***&&&###ppp•••­­­ÚÚÚïïïïïïâââÒÒÒ«««“““€€€pppggg]]]WWWRRRNNNHHHCCC===777333...***&&&### ppp“““³³³ÜÜÜâââÎÎα±±ššš†††zzzrrrllliiigggeeedddccc___ZZZTTTLLLBBB777---&&&###ppp€€€¡¡¡¯¯¯œœœ†††zzzyyyzzz‚‚‚………ˆˆˆˆˆˆŠŠŠŠŠŠŠŠŠˆˆˆ†††ƒƒƒ€€€yyyrrreeeVVVCCC///!!!rrr‚‚‚vvv|||ƒƒƒˆˆˆ‹‹‹‹‹‹†††ƒƒƒ€€€}}}zzzzzzzzz|||€€€ƒƒƒŠŠŠ‹‹‹………yyydddDDD###ggggggzzzŠŠŠ’’’¡¡¡¯¯¯¯¯¯¨¨¨˜˜˜ˆˆˆwwwllleee___XXXRRRNNNJJJHHHGGGJJJQQQ___rrrƒƒƒŠŠŠwwwIII!!!<<<```ŸŸŸÀÀÀÞÞÞâââÎÎκººˆˆˆvvvkkkddd]]]WWWQQQLLLFFFAAA<<<666222......666NNNtttLLL%%%222WWW———«««ÐÐÐççççççÔÔÔ†††vvvkkkddd]]]WWWQQQLLLFFFAAA<<<777333...***%%%###)))###&&&|||}}}•••­­­ÖÖÖëëëëëëÜÜÜÊÊÊŸŸŸ†††vvvkkkddd]]]WWWQQQLLLFFFAAA<<<777333...***&&&###+++ppp•••­­­ÚÚÚííííííâââÒÒÒ¤¤¤zzzmmmeee]]]WWWQQQLLLFFFAAA<<<777333...***&&&### ppp“““¯¯¯ÞÞÞíííçççÐÐз··œœœˆˆˆyyymmmggg```]]][[[XXXTTTOOOHHHAAA999111***&&&###pppœœœºººººº£££‹‹‹|||vvvvvvwwwzzz}}}€€€€€€}}}zzzwwwrrriiiaaaTTTEEE444&&&ppp†††€€€www|||‚‚‚ˆˆˆŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆ‚‚‚yyyhhhPPP333mmmlllsss‚‚‚ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ€€€hhh;;;LLLeee‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆTTT((("""FFF‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ƒƒƒ111DDD|||ŽŽŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽ‹‹‹ppp333###???aaazzzˆˆˆŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ†††tttXXX555###///===MMMXXXccckkkmmmrrrpppmmmiii```VVVHHH888+++ÿÿ€ÿÿÿøÿÿÀÿþÿø?ðàÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀàðøüÿÿÿÀÿÿü?ÿÿÿÀÿÿ¾¾¾µµµªªªŸŸŸ•••ƒƒƒzzzrrrllliiieeeccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999777åååâââØØØÌÌÌÀÀÀ···«««¡¡¡•••ƒƒƒzzzrrrllliiigggccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999666444222000...,,,ÀÀÀÎÎÎÚÚÚååååååÚÚÚÐÐÐÄÄĺºº±±±£££•••ƒƒƒzzzrrrllliiigggccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999666444222000---,,,)))(((&&&œœœ¦¦¦±±±ÂÂÂÒÒÒÜÜÜééééééÜÜÜÒÒÒÈÈȾ¾¾µµµ£££•••ƒƒƒzzzrrrllliiigggccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999666444222000---,,,)))(((%%%$$$###†††ššš¤¤¤±±±ÄÄÄÖÖÖàààééééééàààÖÖÖÌÌÌÄÄĺºº¤¤¤•••ƒƒƒzzzrrrllliiigggccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" }}}………ŽŽŽššš¤¤¤±±±ÆÆÆØØØâââëëëëëëâââÚÚÚÐÐÐÈÈȾ¾¾¦¦¦•••ƒƒƒzzzrrrllliiigggccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" tttzzzƒƒƒŽŽŽššš¤¤¤±±±ÊÊÊÜÜÜåååííííííåååÜÜÜÔÔÔÌÌÌÄÄĦ¦¦•••ƒƒƒzzzrrrllliiigggccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" lllrrrzzzƒƒƒŽŽŽššš¤¤¤±±±ÎÎÎàààçççïïïïïïçççàààØØØÒÒÒÈÈȦ¦¦•••ƒƒƒzzzrrrllliiigggccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" kkkrrrzzzƒƒƒŽŽŽššš¤¤¤±±±ÒÒÒâââéééïïïïïïéééâââÜÜÜÖÖÖÌÌ̦¦¦•••ƒƒƒzzzrrrllliiigggccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" kkkpppzzzƒƒƒŽŽŽššš¤¤¤³³³ÔÔÔåååëëëòòòòòòëëëåååÞÞÞØØØÎÎΦ¦¦•••‹‹‹‚‚‚yyyrrrllliiieeeccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEECCC@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" kkkpppzzzƒƒƒŽŽŽššš¤¤¤³³³ÖÖÖåååëëëòòòòòòëëëåååÞÞÞØØØÐÐеµµ¨¨¨ŸŸŸ•••‹‹‹‚‚‚zzztttooohhhccc\\\ZZZWWWTTTQQQOOOLLLHHHEEECCC@@@===;;;888666444222000---,,,)))(((%%%$$$""" kkkpppzzzƒƒƒŽŽŽššš¤¤¤³³³ÖÖÖåååëëëòòòòòòëëëåååÜÜÜÔÔÔÈÈȼ¼¼¯¯¯£££•••ŠŠŠtttlllhhhddd___\\\[[[[[[[[[ZZZXXXXXXVVVTTTPPPMMMHHHCCC>>>999444222///---,,,)))(((%%%$$$""" kkkpppzzzƒƒƒŽŽŽššš¤¤¤···ØØØåååééééééÞÞÞÈÈȵµµ¡¡¡ŽŽŽ}}}rrrhhhccc_________```aaacccdddeeeeeeeeeeeedddcccaaaaaa```]]]]]]\\\\\\[[[WWWTTTNNNGGG===333---)))'''%%%$$$""" kkkpppzzzƒƒƒŽŽŽœœœµµµÎÎÎÔÔÔÈÈÈ···¡¡¡ˆˆˆvvvkkkeeedddhhhmmmssswww|||ƒƒƒ………†††††††††ˆˆˆˆˆˆˆˆˆˆˆˆ††††††………………‚‚‚}}}zzzvvvrrrlllgggaaa___]]][[[VVVMMMAAA333(((###""" kkkpppzzzƒƒƒ˜˜˜¸¸¸ÀÀÀ¯¯¯•••|||mmmgggiiirrrzzz‚‚‚†††ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆ………wwwmmmeee```]]]XXXMMM:::))) kkkpppzzz———­­­ššš|||iiieeemmmzzzƒƒƒŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆ€€€ttthhh```\\\TTT<<<$$$kkkrrrˆˆˆ‹‹‹pppaaagggvvvƒƒƒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠˆˆˆ†††………ƒƒƒ‚‚‚€€€}}}€€€‚‚‚ƒƒƒ†††ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆoooaaa\\\NNN,,,kkkppplll]]]aaawwwˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠ“““•••———•••’’’‹‹‹………}}}tttooolllhhheeeaaa]]][[[XXXVVVUUURRRPPPQQQRRRUUUWWW\\\cccmmmwww€€€ˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‚‚‚mmm___UUU---kkkddd[[[ggg‚‚‚‹‹‹‹‹‹‹‹‹‹‹‹“““¡¡¡³³³¼¼¼¾¾¾¼¼¼µµµ«««¡¡¡•••ƒƒƒzzzrrrllliiieeeccc___\\\XXXVVVRRRPPPMMMJJJGGGDDDBBB???===;;;:::;;;???EEEQQQdddwww………‹‹‹‹‹‹‹‹‹ŠŠŠvvv___QQQ###]]]MMMQQQ€€€‹‹‹‹‹‹’’’¡¡¡···ÎÎÎâââçççÜÜÜÐÐÐÆÆÆººº±±±£££•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666333111///...222;;;MMMhhh‚‚‚‹‹‹hhhJJJ///DDD///GGGŠŠŠ‹‹‹œœœ­­­ÂÂÂÔÔÔÞÞÞééééééÜÜÜÔÔÔÊÊÊÀÀÀ···£££•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---+++)))''')))444QQQwwwŽŽŽppp222(((999)))}}}ššš¦¦¦±±±ÆÆÆÖÖÖàààëëëéééàààÖÖÖÎÎÎÄÄĺºº¤¤¤•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%###"""+++PPPLLLŠŠŠ$$$///zzzššš¤¤¤±±±ÊÊÊÚÚÚâââëëëëëëâââÚÚÚÒÒÒÈÈȾ¾¾¤¤¤•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" $$$ÿÿÿyyyrrr………ŽŽŽššš¤¤¤±±±ÌÌÌÜÜÜåååííííííåååÜÜÜÖÖÖÎÎÎÄÄĤ¤¤•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" NNN’’’yyyzzz………ŽŽŽššš¤¤¤³³³ÐÐÐàààçççïïïïïïçççàààÚÚÚÒÒÒÈÈȦ¦¦•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" ###mmmrrrzzz………ŽŽŽššš¤¤¤³³³ÔÔÔâââéééòòòïïïéééâââÜÜÜÖÖÖÌÌ̦¦¦•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" kkkrrrzzz………ŽŽŽššš¤¤¤³³³ÖÖÖåååëëëòòòòòòëëëåååÞÞÞØØØÎÎΤ¤¤•••‹‹‹‚‚‚zzzrrrllliiieeeccc___\\\XXXVVVRRRPPPMMMJJJGGGEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" kkkrrrzzz………ŽŽŽššš¤¤¤µµµØØØåååëëëòòòòòòëëëåååÞÞÞØØØÐÐкºº¯¯¯¦¦¦“““ˆˆˆwwwpppiiiccc\\\ZZZWWWUUURRRPPPMMMIIIFFFCCC@@@>>>;;;888666333222000---,,,)))(((%%%$$$""" kkkrrrzzz………ŽŽŽššš¤¤¤µµµØØØåååëëëòòòòòòéééàààÖÖÖÊÊʼ¼¼¯¯¯¡¡¡’’’………|||rrrkkkeeeccc```]]]\\\[[[[[[[[[[[[[[[ZZZXXXWWWUUUQQQNNNHHHBBB<<<777333///---+++)))(((%%%$$$""" kkkrrrzzz………ŽŽŽššš¦¦¦ºººÜÜÜååååååàààÎÎη··¡¡¡ŽŽŽ}}}ooogggaaa``````aaadddggghhhiiikkklllmmmmmmlllkkkiiihhhgggdddaaa```___]]]\\\[[[XXXTTTNNNDDD999000***'''%%%$$$""" kkkrrrzzzƒƒƒŽŽŽ¡¡¡¾¾¾ÐÐÐÌÌ̸¸¸£££wwwkkkgggeeeiiipppwww|||€€€ƒƒƒ†††ˆˆˆŠŠŠŠŠŠŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠˆˆˆ†††………‚‚‚zzzsssmmmgggccc___\\\ZZZTTTIII:::,,,$$$!!! kkkrrrzzz………¡¡¡¼¼¼···ƒƒƒppphhhhhhpppzzzƒƒƒˆˆˆŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ………tttkkkddd___[[[TTTCCC///"""kkkppp}}}¦¦¦ˆˆˆooodddhhhvvv‚‚‚ˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ†††}}}oooccc]]]XXXEEE)))kkksssˆˆˆ}}}eee```mmmŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ†††‚‚‚}}}|||yyyvvvssspppooooooooooooooopppssswww|||€€€ƒƒƒˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹………wwweee]]]TTT333llloooeee\\\iii€€€‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‹‹‹ŽŽŽ•••œœœŸŸŸ¡¡¡¡¡¡œœœ•••‹‹‹ƒƒƒzzzrrrllliiieeeccc___[[[XXXUUURRRPPPMMMJJJHHHGGGGGGGGGIIIMMMUUU___kkkvvv€€€ŠŠŠ‹‹‹‹‹‹‹‹‹†††sss```ZZZ333iii```ZZZmmmˆˆˆ‹‹‹‹‹‹‹‹‹•••£££ºººÌÌÌÐÐÐÊÊʸ¸¸­­­¡¡¡———‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVRRRPPPMMMJJJGGGEEEBBB@@@===:::888666555666<<>>;;;999666444222///---+++---555IIIhhh………iiiEEE---???***EEEŠŠŠ“““¡¡¡±±±ÄÄÄÔÔÔÞÞÞééééééÞÞÞÔÔÔÊÊÊÀÀÀ···£££•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))'''%%%'''666[[[ƒƒƒlll,,,$$$:::(((}}}ššš¦¦¦±±±ÆÆÆØØØàààëëëëëëàààØØØÎÎÎÆÆÆ¼¼¼¤¤¤•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%###!!!"""444777***¯¯¯333FFF‚‚‚ŽŽŽššš¤¤¤±±±ÊÊÊÚÚÚâââíííëëëâââÚÚÚÒÒÒÊÊÊÀÀÀ¤¤¤•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" ;;;ççç………yyy………ŽŽŽššš¤¤¤±±±ÎÎÎÞÞÞçççííííííåååÞÞÞÖÖÖÎÎÎÆÆÆ¦¦¦•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" III€€€tttzzzƒƒƒŽŽŽššš¤¤¤³³³ÒÒÒâââéééïïïïïïéééàààÚÚÚÔÔÔÊÊʦ¦¦•••‹‹‹ƒƒƒzzzrrrllliiieeeccc```\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" 222lllrrrzzzƒƒƒŽŽŽššš¤¤¤³³³ÖÖÖåååëëëòòòòòòéééåååÞÞÞØØØÌÌ̦¦¦•••‹‹‹ƒƒƒzzzrrrllliiieeeccc___\\\ZZZVVVTTTPPPNNNJJJHHHEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" kkkrrrzzzƒƒƒŽŽŽššš¤¤¤³³³ÖÖÖåååëëëòòòòòòéééåååÞÞÞØØØÎÎΨ¨¨˜˜˜†††}}}tttoookkkgggddd```\\\XXXVVVRRRPPPMMMJJJGGGEEEBBB@@@>>>;;;999666444222000---,,,)))(((%%%$$$""" kkkrrrzzzƒƒƒŽŽŽššš¤¤¤µµµØØØåååëëëòòòòòòëëëåååÞÞÞØØØÒÒÒ¸¸¸¯¯¯¤¤¤ššš‚‚‚yyypppiiiccc\\\[[[ZZZWWWVVVTTTQQQNNNJJJGGGCCC@@@<<<999666333222///---,,,)))(((%%%$$$""" kkkrrrzzzƒƒƒŽŽŽššš¤¤¤µµµØØØåååëëëòòòïïïâââÔÔÔÆÆÆµµµ£££“““………wwwmmmhhhccc```]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[ZZZXXXVVVRRRMMMFFF???888222---+++)))(((%%%$$$""" kkkrrrzzzƒƒƒŽŽŽšššªªªÄÄÄÜÜÜÜÜÜÖÖÖÈÈȱ±±˜˜˜………tttiiidddcccdddeeeiiimmmrrrtttvvvwwwyyyzzz|||zzzyyywwwvvvvvvsssppplllhhheeeccc```]]]\\\[[[WWWPPPFFF;;;111)))%%%###""" kkkrrrzzzƒƒƒ«««ÆÆÆÈÈÈ···†††ttthhhgggiiipppwww}}}ƒƒƒ†††ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠˆˆˆ………€€€zzztttmmmggg```]]][[[VVVIII777)))""" kkkrrrzzzŠŠŠ«««µµµƒƒƒooogggkkksss}}}†††ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆ‚‚‚yyyoooeee___[[[QQQ>>>)))kkkpppƒƒƒŽŽŽpppcccgggttt‚‚‚ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹†††|||mmmaaa\\\TTT777 kkksssiii]]]hhh|||ˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ƒƒƒrrraaa[[[BBB kkkiii______tttˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹€€€ggg]]]AAAeeeXXXWWWwww‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹………cccRRR***NNN;;;NNNˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹lll<<<,,,666###<<<ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽccc$$$)))aaaŽŽŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‚‚‚///]]]‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽyyy444<<>>===<<<;;;999888777ÚÚÚÔÔÔÎÎÎÈÈȼ¼¼¸¸¸³³³­­­¨¨¨£££˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222111àààéééçççàààÚÚÚÔÔÔÐÐÐÊÊÊÄÄľ¾¾¸¸¸µµµ¯¯¯ªªª¤¤¤˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...------ÆÆÆÎÎÎÔÔÔÚÚÚàààççççççâââÜÜÜÖÖÖÒÒÒÌÌÌÆÆÆÀÀÀ¼¼¼···±±±«««¦¦¦˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***))))))µµµºººÂÂÂÈÈÈÐÐÐÖÖÖÜÜÜâââééééééâââÞÞÞØØØÔÔÔÎÎÎÈÈȾ¾¾¸¸¸µµµ¯¯¯¦¦¦˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%ªªª­­­³³³ºººÆÆÆÎÎÎÔÔÔÚÚÚÞÞÞåååëëëëëëåååÞÞÞÚÚÚÔÔÔÐÐÐÊÊÊÄÄÄÀÀÀ¼¼¼···±±±¨¨¨˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$###£££¨¨¨­­­³³³ºººÊÊÊÐÐÐÖÖÖÚÚÚàààåååëëëëëëåååàààÜÜÜÖÖÖÒÒÒÌÌÌÆÆÆÂ¾¾¾¸¸¸µµµ¨¨¨˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!!’’’———£££¨¨¨­­­³³³¼¼¼ÊÊÊÒÒÒØØØÜÜÜàààçççëëëëëëçççàààÜÜÜØØØÒÒÒÎÎÎÈÈÈÄÄÄÀÀÀ¼¼¼···ªªª˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! ˆˆˆ‹‹‹’’’———œœœ£££¨¨¨­­­³³³¼¼¼ÎÎÎÔÔÔØØØÞÞÞâââçççííííííçççâââÞÞÞØØØÔÔÔÐÐÐÊÊÊÆÆÆÂ¾¾¾ººº«««˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" ƒƒƒ†††‹‹‹’’’———£££¨¨¨­­­³³³¾¾¾ÎÎÎÖÖÖÚÚÚÞÞÞâââéééííííííéééâââÞÞÞÚÚÚÖÖÖÒÒÒÎÎÎÈÈÈÄÄÄÀÀÀ¼¼¼«««˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! zzz}}}‚‚‚†††‹‹‹’’’———£££¨¨¨­­­³³³ÀÀÀÐÐÐÖÖÖÜÜÜàààåååéééííííííéééåååàààÜÜÜØØØÔÔÔÐÐÐÌÌÌÈÈȾ¾¾«««˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! vvvyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­³³³ÂÂÂÔÔÔØØØÜÜÜâââçççëëëïïïïïïëëëçççâââÞÞÞÚÚÚÖÖÖÒÒÒÎÎÎÊÊÊÆÆÆÀÀÀ«««˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! tttwww|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­³³³ÂÂÂÖÖÖÚÚÚÞÞÞâââçççëëëïïïïïïëëëçççâââàààÜÜÜØØØÔÔÔÐÐÐÌÌÌÈÈÈÄÄÄ­­­˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! pppssswww|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­³³³ÆÆÆØØØÜÜÜàààåååéééíííïïïïïïëëëéééåååàààÜÜÜÚÚÚÖÖÖÒÒÒÎÎÎÊÊÊÆÆÆ­­­˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! lllooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­³³³ÈÈÈÚÚÚÞÞÞâââçççéééíííòòòòòòíííéééçççâââÞÞÞÚÚÚØØØÔÔÔÐÐÐÎÎÎÈÈÈ­­­˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! kkkooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­³³³ÊÊÊÜÜÜàààâââçççëëëïïïòòòòòòíííëëëçççåååàààÜÜÜÚÚÚÖÖÖÔÔÔÐÐÐÊÊÊ­­­˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! kkkooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­³³³ÌÌÌÞÞÞàààåååéééëëëïïïòòòòòòïïïëëëéééåååâââÞÞÞÜÜÜØØØÖÖÖÒÒÒÎÎΫ««˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! gggkkkooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­µµµÎÎÎÞÞÞâââåååéééëëëïïïòòòòòòïïïëëëéééçççâââàààÜÜÜÚÚÚÖÖÖÔÔÔÎÎΫ««˜˜˜“““ŽŽŽŠŠŠ†††‚‚‚}}}wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­µµµÎÎÎÞÞÞâââåååéééëëëïïïòòòòòòïïïëëëéééçççâââàààÜÜÜÚÚÚÖÖÖÔÔÔÎÎΪªª˜˜˜“““ŽŽŽŠŠŠ………€€€|||wwwtttpppmmmlllkkkhhhgggeeedddaaa```___]]]\\\ZZZXXXWWWVVVTTTRRRQQQPPPNNNMMMLLLJJJHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­µµµÐÐÐÞÞÞâââåååéééëëëïïïòòòòòòïïïëëëéééçççâââàààÜÜÜÚÚÚÖÖÖÔÔÔÎÎΫ««ŸŸŸššš•••‹‹‹†††‚‚‚|||wwwsssooolllkkkiiihhheeeeeecccaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFEEECCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­µµµÒÒÒÞÞÞâââåååéééëëëïïïòòòòòòïïïëëëéééçççâââàààÜÜÜÚÚÚÖÖÖÔÔÔÐÐÐÀÀÀººº···³³³­­­ªªª¦¦¦¡¡¡ššš•••‹‹‹†††ƒƒƒ€€€}}}yyytttpppkkkgggccc___\\\[[[XXXWWWVVVUUUTTTQQQPPPOOONNNLLLJJJHHHGGGEEEDDDCCCBBB@@@???>>>===<<<:::999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­···ÔÔÔÞÞÞâââåååéééëëëïïïòòòòòòïïïëëëéééçççâââàààÜÜÜÚÚÚØØØÔÔÔÒÒÒÎÎÎÊÊÊÆÆÆÂ¾¾¾ººº···³³³­­­¨¨¨£££œœœ’’’ŠŠŠ‚‚‚|||wwwsssoooiiieeeaaa]]]\\\\\\\\\\\\[[[[[[[[[ZZZXXXXXXWWWWWWUUUTTTQQQOOOLLLIIIFFFCCCBBB@@@>>>;;;:::999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­···ÔÔÔÞÞÞâââåååéééëëëïïïòòòòòòïïïëëëéééçççåååàààÚÚÚÖÖÖÐÐÐÆÆÆ¾¾¾···¯¯¯ªªª£££ššš………}}}vvvooohhhccc```___\\\[[[[[[[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[ZZZXXXVVVTTTPPPLLLGGGBBB===:::777444333333111000///...---,,,+++***)))((('''&&&%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­···ÖÖÖÞÞÞâââåååéééëëëïïïôôôôôôïïïéééÞÞÞÔÔÔÈÈȾ¾¾···­­­¤¤¤“““ˆˆˆ}}}tttkkkddd```]]][[[[[[[[[[[[[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ZZZWWWTTTNNNGGGBBB<<<666222///------,,,+++***)))((('''&&&%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’———£££¨¨¨­­­¼¼¼ØØØÞÞÞâââçççéééíííëëëéééÚÚÚÈÈȸ¸¸«««¤¤¤———ŠŠŠ}}}rrrgggaaa___\\\[[[[[[[[[[[[[[[\\\\\\]]]___```aaaaaacccdddeeegggggghhhiiikkklllllllllkkkiiihhhggggggeeedddcccaaaaaa```___]]]\\\\\\[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]]]]]][[[ZZZVVVMMMCCC:::222---***))))))((('''&&&%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’———œœœ£££¯¯¯ÀÀÀÒÒÒÚÚÚÞÞÞàààÞÞÞÔÔÔÈÈȺºº­­­¤¤¤œœœ“““†††zzzmmmddd___[[[[[[[[[\\\]]]```ccceeehhhlllooosssvvvzzz‚‚‚………††††††††††††ˆˆˆˆˆˆˆˆˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠˆˆˆˆˆˆˆˆˆ††††††††††††………‚‚‚zzzwwwssspppllliiieeeccc```]]]\\\[[[\\\\\\\\\\\\\\\\\\\\\]]]\\\ZZZTTTIII???555---)))&&&&&&%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’———£££···ÊÊÊÔÔÔØØØÖÖÖÌÌ̼¼¼­­­¦¦¦ŸŸŸ———ŠŠŠzzzlllaaa]]][[[[[[]]]```ccciiiooottt|||‚‚‚††††††ˆˆˆŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠˆˆˆˆˆˆ†††‚‚‚|||tttoooiiiddd```]]]\\\[[[\\\\\\\\\\\\\\\]]]\\\XXXQQQCCC333)))%%%$$$######"""!!! gggiiiooosssyyy|||‚‚‚†††‹‹‹’’’¤¤¤ÀÀÀÎÎÎÐÐÐÊÊʾ¾¾¯¯¯¤¤¤œœœ€€€rrreee___[[[\\\___eeemmmtttzzz‚‚‚†††ˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆ†††‚‚‚|||tttmmmeee```\\\\\\\\\\\\\\\\\\\\\]]]XXXMMM;;;---%%%"""!!! gggiiiooosssyyy|||‚‚‚†††ŽŽŽªªªÂÂÂÈÈȾ¾¾³³³¦¦¦œœœ|||kkk```\\\[[[___dddmmmvvv€€€†††‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆ€€€wwwmmmddd___\\\\\\\\\\\\\\\]]]\\\UUUEEE333%%% gggiiiooosssyyy|||‚‚‚¯¯¯ÀÀÀ¸¸¸«««zzzkkk```[[[\\\aaakkkttt†††ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ†††vvvlllaaa\\\\\\\\\\\\\\\]]]ZZZJJJ333###gggiiiooossswww|||ŽŽŽ±±±¸¸¸¨¨¨“““}}}kkk```[[[[[[___hhhttt‚‚‚ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠƒƒƒvvvhhh___\\\\\\\\\\\\]]]ZZZHHH---hhhkkkooossswww¯¯¯¦¦¦ŠŠŠrrrccc\\\[[[\\\dddppp}}}ˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆpppddd]]]\\\\\\\\\]]]VVV;;;###iiikkkooosssˆˆˆ¡¡¡………iii___[[[[[[]]]eeewww………‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠˆˆˆ†††………………ƒƒƒ‚‚‚€€€}}}|||zzzyyyvvvtttvvvvvvwwwwwwyyyyyyzzz||||||}}}‚‚‚………†††ˆˆˆŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹………wwwggg]]]\\\\\\\\\\\\HHH&&&iiikkkooozzz………lll\\\[[[\\\\\\dddvvv†††‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽŽŽŽŽŽŽŽŽŽ‹‹‹ˆˆˆ………€€€|||wwwrrrpppmmmlllkkkhhhgggeeecccaaa___]]][[[ZZZZZZXXXWWWVVVUUUTTTRRRQQQQQQPPPPPPRRRUUUXXX]]]aaaeeekkkpppvvv|||‚‚‚†††ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹†††wwwddd\\\\\\\\\]]]NNN)))iiikkkooopppaaa[[[\\\\\\]]]mmmƒƒƒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‹‹‹ŽŽŽ’’’———œœœŸŸŸ¡¡¡¡¡¡ŸŸŸœœœ———“““ŽŽŽŠŠŠ………€€€|||wwwsssooommmllliiihhhgggeeecccaaa```___]]][[[ZZZXXXWWWUUUTTTRRRPPPOOONNNMMMJJJIIIHHHFFFEEEDDDBBBBBBBBBBBBBBBBBBEEEMMMVVV___iiivvv€€€………ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ƒƒƒooo___\\\\\\]]]OOO%%%iiikkklllaaa\\\\\\\\\```vvvŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‹‹‹˜˜˜¦¦¦¯¯¯µµµººº¼¼¼ººº···³³³­­­ªªª£££˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBB@@@???>>>===;;;:::888888999;;;>>>FFFOOOXXXhhhzzz………‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠwww```\\\\\\]]]GGGiiikkkeee\\\\\\[[[```zzz‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‹‹‹ŽŽŽ———¨¨¨¼¼¼ÎÎÎØØØØØØÖÖÖÐÐÐÊÊÊÆÆÆÀÀÀºººµµµ¯¯¯«««¤¤¤˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888666555444333111111333777CCCTTTgggzzz………‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹|||```[[[\\\[[[333kkkgggVVVQQQQQQTTTrrr‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹’’’­­­ÀÀÀÒÒÒàààëëëéééâââÜÜÜÖÖÖÒÒÒÌÌÌÈÈȼ¼¼···³³³­­­¦¦¦˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333111000...------///333@@@QQQeee|||ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹tttTTTQQQRRRDDDooo[[[EEEBBBBBBUUU†††‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽ˜˜˜¨¨¨ºººÈÈÈÒÒÒÚÚÚÞÞÞåååëëëéééåååÞÞÞØØØÒÒÒÎÎÎÊÊÊÄÄľ¾¾¸¸¸µµµ±±±¦¦¦˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,***))))))+++333GGGccc}}}‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹†††VVVBBBCCC@@@###vvvMMM555444555___‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ššš¦¦¦³³³¼¼¼ÊÊÊÐÐÐÔÔÔÚÚÚàààçççëëëëëëåååÞÞÞÚÚÚÔÔÔÐÐÐÌÌÌÆÆÆÀÀÀ¼¼¼···³³³¨¨¨˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))(((&&&%%%(((222LLLooo†††‹‹‹‹‹‹‹‹‹aaa555444444###………>>>))))))***___‹‹‹‹‹‹‹‹‹ŽŽŽ———¡¡¡¨¨¨­­­µµµ¾¾¾ÌÌÌÒÒÒÖÖÖÜÜÜàààçççíííëëëåååàààÚÚÚÖÖÖÒÒÒÎÎÎÈÈȾ¾¾ºººµµµ¨¨¨˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%######)))>>>ccc………‹‹‹aaa+++)))))) ;;; HHH‹‹‹‹‹‹‹‹‹———£££¨¨¨­­­µµµ¾¾¾ÌÌÌÔÔÔØØØÜÜÜâââçççíííëëëçççàààÜÜÜØØØÔÔÔÎÎÎÊÊÊÄÄÄÀÀÀ¼¼¼¸¸¸ªªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$###""" %%%:::eee†††ŽŽŽJJJFFF###sss‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­µµµÀÀÀÎÎÎÔÔÔÚÚÚÞÞÞâââéééííííííçççâââÞÞÞÚÚÚÔÔÔÐÐÐÌÌÌÈÈȾ¾¾ºººªªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" $$$AAAddd%%%$$$œœœ%%%$$$iiiˆˆˆ’’’˜˜˜œœœ£££¨¨¨­­­µµµÂÂÂÒÒÒÖÖÖÚÚÚàààåååéééïïïíííéééåååÞÞÞÚÚÚÖÖÖÒÒÒÎÎÎÊÊÊÆÆÆÀÀÀ¼¼¼ªªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" """///ÿÿÿVVV)))hhh‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­µµµÂÂÂÔÔÔØØØÜÜÜàààåååëëëïïïïïïéééåååàààÜÜÜØØØÔÔÔÐÐÐÌÌÌÈÈÈÄÄÄÀÀÀ«««˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######"""  “““ÿÿÿÒÒÒMMMhhh}}}‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­µµµÄÄÄÖÖÖÚÚÚÞÞÞâââçççëëëïïïïïïëëëçççâââÞÞÞÚÚÚÖÖÖÒÒÒÎÎÎÊÊÊÆÆÆÂ«««˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" [[[ÿÿÿÿÿÿ¼¼¼|||yyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­µµµÆÆÆØØØÜÜÜàààâââçççíííïïïïïïëëëçççåååÞÞÞÜÜÜØØØÔÔÔÐÐÐÌÌÌÈÈÈÄÄÄ«««˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" 888íííÒÒÒ€€€ssswww|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­µµµÈÈÈÚÚÚÞÞÞàààåååéééíííòòòòòòíííéééåååàààÞÞÞÚÚÚÖÖÖÒÒÒÎÎÎÌÌÌÆÆÆ«««˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" OOO………rrrsssyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­µµµÊÊÊÜÜÜÞÞÞâââçççëëëíííòòòòòòíííéééçççâââÞÞÞÜÜÜØØØÔÔÔÒÒÒÎÎÎÈÈȪªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" ###ooooootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­µµµÎÎÎÞÞÞàààåååçççëëëïïïòòòòòòïïïëëëçççåååàààÞÞÞÚÚÚØØØÔÔÔÐÐÐÊÊʪªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" lllllloootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­···ÐÐÐÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââÞÞÞÜÜÜØØØÖÖÖÔÔÔÌÌ̪ªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­···ÒÒÒÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜÚÚÚÖÖÖÔÔÔÌĮ̀¨¨˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­···ÔÔÔÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜÚÚÚÖÖÖÔÔÔÌĮ̀¨¨œœœ———“““ŽŽŽŠŠŠ………€€€|||wwwsssooommmkkkiiihhhgggeeecccaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­···ÔÔÔÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜÚÚÚÖÖÖÔÔÔÌÌ̯¯¯¦¦¦ŸŸŸœœœ———’’’‹‹‹†††‚‚‚}}}wwwssspppooolllkkkhhhgggdddccc```___]]][[[ZZZXXXWWWUUUTTTRRRPPPOOONNNMMMJJJIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­···ÖÖÖÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜØØØÖÖÖÔÔÔÐÐÐÊÊÊÈÈÈÄÄÄÀÀÀ¼¼¼ºººµµµ±±±­­­¨¨¨£££˜˜˜’’’ˆˆˆƒƒƒ}}}wwwpppiiiddd___\\\[[[ZZZXXXXXXWWWVVVUUUTTTQQQPPPOOOMMMJJJHHHGGGEEECCCBBB@@@???>>>===;;;:::999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­¸¸¸ÖÖÖÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜÚÚÚÖÖÖÒÒÒÎÎÎÈÈȼ¼¼¸¸¸µµµ­­­¨¨¨£££šššˆˆˆ€€€yyyrrrlllhhhdddcccaaaaaa```___\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[ZZZWWWVVVTTTQQQOOOLLLIIIFFFBBB???<<<:::777666555444333333111000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­¸¸¸ØØØÞÞÞàààåååéééíííïïïòòòôôôïïïíííéééåååÞÞÞØØØÐÐÐÆÆÆ¼¼¼µµµ­­­¤¤¤•••ŠŠŠtttlllgggaaa```]]]\\\[[[[[[[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[ZZZWWWRRRMMMGGGBBB<<<888555333111000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨­­­ºººØØØÞÞÞàààåååéééíííïïïôôôòòòçççØØØÈÈȼ¼¼³³³ªªª£££œœœ………zzzrrrhhhaaa___\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\\\\\\\\\]]]]]]]]]]]]___]]]]]]]]]\\\\\\\\\\\\[[[[[[[[[[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]]]\\\[[[XXXUUUOOOHHHAAA888222...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’˜˜˜œœœ£££¨¨¨³³³ÆÆÆÚÚÚÞÞÞâââççççççåååÜÜÜÎÎξ¾¾¯¯¯¦¦¦———‹‹‹ssshhhaaa]]][[[[[[[[[[[[\\\]]]]]]___```ccceeeiiillloooppprrrsssssstttvvvwwwyyyzzz|||||||||zzzyyywwwvvvtttssssssrrrpppooolllhhheeeaaa```___]]]]]]\\\[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\]]]\\\XXXQQQGGG>>>444---***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’———œœœ¨¨¨ºººÎÎÎØØØÜÜÜÜÜÜÖÖÖÊÊʼ¼¼¯¯¯¨¨¨ŸŸŸ———ŠŠŠ|||oooddd___\\\[[[[[[\\\___aaaggglllppptttyyy|||ƒƒƒ†††ˆˆˆˆˆˆŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠˆˆˆ††††††ƒƒƒ|||wwwtttppplllgggaaa___]]]\\\\\\\\\\\\\\\\\\\\\\\\]]][[[WWWOOODDD999---(((%%%%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††’’’ššš­­­ÆÆÆÒÒÒÔÔÔÒÒÒÈÈȸ¸¸ªªª¡¡¡ššš€€€rrreee___[[[[[[]]]aaaeeelllrrryyy………ˆˆˆŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠˆˆˆ………wwwrrrkkkeee```___\\\\\\\\\\\\\\\\\\]]]]]][[[RRRCCC333((($$$######""" iiikkkoootttyyy|||‚‚‚†††˜˜˜µµµÈÈÈÌÌÌÆÆÆººº­­­£££———ˆˆˆwwwiii```\\\[[[]]]ccckkkttt}}}………ˆˆˆŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ†††ƒƒƒ|||sssiiiaaa]]]\\\\\\\\\\\\\\\\\\]]]XXXMMM;;;,,,$$$!!! iiikkkoootttyyy|||‚‚‚ˆˆˆœœœ¸¸¸ÆÆÆ¼¼¼¯¯¯£££———†††tttggg]]][[[]]]aaaiiisss}}}………ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ………|||rrrhhhaaa]]]\\\\\\\\\\\\]]]\\\UUUDDD///###iiikkkoootttyyy|||ƒƒƒ¡¡¡¼¼¼ººº«««ššš†††ttteee]]][[[\\\cccooo|||………ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆƒƒƒzzzmmmaaa\\\\\\\\\\\\\\\]]]WWWDDD,,, iiikkkoootttwww€€€¡¡¡¸¸¸ªªª’’’zzzggg]]][[[\\\```iiiwww………‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠƒƒƒvvvhhh___\\\\\\\\\\\\]]]VVV<<<$$$iiikkkooosss}}}ŸŸŸ¨¨¨ˆˆˆoooaaa\\\[[[\\\dddsss€€€ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠˆˆˆˆˆˆˆˆˆˆˆˆ††††††………ƒƒƒ‚‚‚‚‚‚‚‚‚ƒƒƒ………………………………††††††††††††ˆˆˆˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆpppccc\\\\\\\\\\\\\\\LLL---iiikkkooowww’’’‹‹‹kkk]]][[[\\\\\\dddttt………‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ†††ƒƒƒ€€€|||wwwtttsssrrrooommmkkkhhhgggdddccc```___]]]]]]\\\[[[[[[[[[[[[[[[[[[[[[\\\]]]aaaeeeiiimmmsssyyy‚‚‚………†††ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ƒƒƒsssccc\\\\\\\\\]]]UUU222iiikkkooozzzppp]]][[[\\\\\\```rrr………‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‹‹‹ŽŽŽ’’’•••˜˜˜šššššš˜˜˜———’’’ŽŽŽŠŠŠ………€€€|||wwwsssooommmkkkiiihhhgggdddcccaaa```___\\\[[[ZZZXXXVVVUUUTTTRRRPPPOOOMMMLLLJJJIIIGGGFFFFFFFFFFFFFFFFFFHHHMMMPPPVVV```iiittt………ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ƒƒƒooo___\\\\\\]]]XXX444iiikkkooohhh\\\\\\\\\\\\ggg‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‹‹‹ŽŽŽ•••¤¤¤ªªª¯¯¯³³³³³³¯¯¯«««¨¨¨£££˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBB@@@???>>><<<;;;:::;;;===@@@GGGPPPZZZeeerrrˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ|||ddd\\\\\\]]]WWW---iiikkkiii___\\\\\\\\\kkk………‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽ•••¤¤¤···ÆÆÆÐÐÐÐÐÐÎÎÎÊÊÊÆÆÆ¾¾¾¸¸¸µµµ¯¯¯ªªª¤¤¤˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<:::999888666555333333333555;;;HHHXXXlll}}}†††‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‚‚‚hhh\\\\\\]]]PPP###iiiiii___XXXXXXXXXhhh†††‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹’’’­­­ÀÀÀÖÖÖåååéééâââÜÜÜÖÖÖÐÐÐÌÌÌÆÆÆÂ¼¼¼···±±±­­­¤¤¤˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333222111000......111777EEEVVVkkk}}}ˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ƒƒƒdddXXXXXXZZZ777lllaaaNNNJJJJJJTTT‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹œœœ­­­ÀÀÀÌÌÌÖÖÖÞÞÞåååëëëéééâââÞÞÞØØØÒÒÒÎÎÎÈÈÈÄÄľ¾¾¸¸¸³³³¯¯¯¦¦¦˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,******---333FFF```|||ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹zzzQQQJJJLLLBBBrrrTTT===<<<<<<___‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹“““ŸŸŸ­­­ºººÈÈÈÐÐÐÔÔÔÚÚÚÞÞÞåååëëëëëëåååÞÞÞÚÚÚÔÔÔÐÐÐÊÊÊÆÆÆÀÀÀººº···³³³¨¨¨˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))(((&&&)))111EEEgggƒƒƒ‹‹‹‹‹‹‹‹‹ŠŠŠWWW<<<===:::"""rrrDDD//////222hhh‹‹‹‹‹‹‹‹‹’’’œœœ¦¦¦­­­µµµ¼¼¼ÊÊÊÐÐÐÖÖÖÚÚÚàààçççíííëëëåååàààÚÚÚÖÖÖÐÐÐÌÌÌÆÆÆÂ¼¼¼¸¸¸µµµ¨¨¨˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%###'''777WWWzzz‹‹‹]]]000//////""":::$$$$$$&&&___‹‹‹‹‹‹ŽŽŽ•••œœœ£££¨¨¨­­­³³³¾¾¾ÌÌÌÒÒÒØØØÜÜÜàààçççíííëëëçççàààÜÜÜØØØÒÒÒÎÎÎÈÈÈÄÄÄÀÀÀººº···ªªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$###"""###///RRR|||ŽŽŽTTT$$$$$$$$$666>>>ˆˆˆ‹‹‹’’’˜˜˜£££¨¨¨­­­³³³¾¾¾ÎÎÎÔÔÔØØØÞÞÞâââéééííííííçççâââÞÞÞØØØÔÔÔÐÐÐÌÌÌÆÆÆÂ¾¾¾¸¸¸ªªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######!!! !!!///ZZZ}}}444QQQ"""tttˆˆˆ‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­³³³ÀÀÀÐÐÐÖÖÖÚÚÚÞÞÞåååéééííííííéééåååÞÞÞÚÚÚÖÖÖÒÒÒÎÎÎÊÊÊÄÄÄÀÀÀ¼¼¼ªªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" !!!111(((ÌÌÌ111QQQ†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­³³³ÂÂÂÒÒÒØØØÜÜÜàààåååëëëïïïíííéééåååàààÜÜÜØØØÔÔÔÐÐÐÌÌÌÆÆÆÂ¾¾¾«««˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" eeeÿÿÿ€€€(((VVV}}}‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­³³³ÄÄÄÔÔÔÚÚÚÞÞÞâââçççëëëïïïïïïëëëçççàààÜÜÜÚÚÚÖÖÖÒÒÒÎÎÎÊÊÊÆÆÆÀÀÀ«««˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" AAAöööÿÿÿÔÔÔtttwww}}}‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­³³³ÆÆÆÖÖÖÚÚÚÞÞÞâââçççëëëïïïïïïëëëçççâââÞÞÞÜÜÜØØØÔÔÔÐÐÐÌÌÌÈÈȪªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" \\\ÿÿÿïïï’’’tttwww|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­³³³ÈÈÈÚÚÚÜÜÜàààåååéééíííòòòïïïëëëéééåååàààÜÜÜÚÚÚÖÖÖÒÒÒÎÎÎÊÊÊÆÆÆ«««˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" ###†††ŸŸŸtttsssyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­µµµÊÊÊÜÜÜÞÞÞâââçççéééíííòòòòòòíííéééçççâââÞÞÞÜÜÜØØØÔÔÔÐÐÐÎÎÎÈÈÈ«««˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" 222sssooosssyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­µµµÌÌÌÞÞÞàààåååçççëëëïïïòòòòòòíííëëëçççåååàààÜÜÜÚÚÚÖÖÖÒÒÒÐÐÐÊÊʪªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" """pppllloootttyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­µµµÎÎÎÞÞÞàààåååéééëëëïïïòòòòòòïïïëëëéééåååâââÞÞÞÜÜÜØØØÖÖÖÒÒÒÌÌ̪ªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­µµµÐÐÐÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜÚÚÚÖÖÖÔÔÔÌÌ̪ªª˜˜˜“““ŽŽŽŠŠŠ………€€€}}}yyyssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­···ÒÒÒÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜÚÚÚÖÖÖÔÔÔÌĮ̀¨¨˜˜˜“““ŽŽŽŠŠŠ………€€€|||wwwssspppmmmlllkkkhhhgggeeedddaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­···ÔÔÔÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜÚÚÚÖÖÖÔÔÔÌÌ̪ªªŸŸŸššš•••‹‹‹†††‚‚‚}}}yyysssooolllkkkiiihhheeedddcccaaa```___]]][[[ZZZXXXWWWUUUTTTRRRQQQOOONNNMMMLLLIIIHHHGGGFFFDDDCCCBBBAAA@@@>>>===<<<;;;999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­···ÖÖÖÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜÚÚÚÖÖÖÔÔÔÐÐÐÄÄľ¾¾ººº···±±±­­­¨¨¨¤¤¤ŸŸŸššš“““ŽŽŽ‹‹‹ˆˆˆƒƒƒ€€€zzzvvvrrrmmmiiiddd___[[[[[[ZZZWWWVVVUUUTTTRRRPPPOOONNNMMMJJJHHHGGGEEEDDDCCCBBB@@@???>>>===<<<:::999888777666444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­···ÖÖÖÞÞÞàààåååéééíííïïïòòòòòòïïïëëëéééåååâââàààÜÜÜÚÚÚÖÖÖÔÔÔÒÒÒÌÌÌÈÈÈÄÄļ¼¼¸¸¸µµµ¯¯¯¨¨¨¤¤¤•••‹‹‹ƒƒƒ|||wwwsssmmmiiieeeaaa___]]]\\\\\\\\\\\\\\\[[[[[[[[[ZZZZZZXXXXXXWWWUUURRRPPPNNNJJJHHHEEEBBBAAA???<<<:::999888666555444333333222000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­¸¸¸ØØØÞÞÞàààåååéééíííïïïòòòòòòïïïíííéééçççâââÞÞÞØØØÒÒÒÊÊÊÀÀÀ¸¸¸³³³«««£££œœœ“““ˆˆˆ}}}vvvooohhhccc```___\\\[[[[[[[[[[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[ZZZXXXVVVTTTOOOIIIDDD???:::777555333222111000///...---,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨­­­ºººØØØÞÞÞàààåååéééíííïïïôôôôôôíííçççÚÚÚÌÌ̸¸¸±±±¨¨¨ŸŸŸ˜˜˜‚‚‚wwwoooeee```]]][[[[[[[[[[[[[[[[[[\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[ZZZVVVPPPJJJEEE>>>888333///------,,,+++***)))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’˜˜˜œœœ£££¨¨¨¯¯¯ÀÀÀÚÚÚÞÞÞâââçççéééëëëéééâââÒÒÒÀÀÀ±±±¨¨¨¡¡¡šššƒƒƒwwwlllccc```\\\[[[[[[[[[[[[[[[\\\\\\]]]___```aaadddeeeggghhhiiiiiikkklllmmmoooppppppoooooommmlllkkkiiihhhggggggeeedddaaa```___]]]\\\\\\[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]]]\\\[[[WWWPPPFFF<<<333...+++))))))((('''&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’———œœœ£££±±±ÆÆÆÔÔÔÜÜÜÞÞÞÞÞÞÚÚÚÎÎÎÀÀÀ³³³¨¨¨¡¡¡˜˜˜ssshhhaaa]]][[[[[[[[[]]]___cccgggiiilllpppssswwwzzz‚‚‚………††††††ˆˆˆˆˆˆˆˆˆŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠˆˆˆˆˆˆˆˆˆ††††††………‚‚‚zzzvvvssspppllliiieeeaaa___]]]\\\[[[\\\\\\\\\\\\\\\\\\\\\]]][[[VVVNNNCCC888///)))&&&&&&%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹’’’———¤¤¤¼¼¼ÎÎÎÔÔÔÖÖÖÔÔÔÆÆÆµµµ¨¨¨£££œœœ’’’‚‚‚sssggg___\\\[[[\\\___aaagggmmmsssyyy€€€………ˆˆˆŠŠŠŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠˆˆˆˆˆˆ………yyyssslllgggaaa___]]]\\\\\\\\\\\\\\\\\\]]]]]]ZZZUUUFFF666***%%%$$$######""" iiikkkoootttyyy|||‚‚‚†††‹‹‹“““ªªªÄÄÄÎÎÎÎÎÎÆÆÆ¸¸¸«««¡¡¡———ˆˆˆyyykkkaaa\\\[[[]]]aaaiiirrryyy………ˆˆˆŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠˆˆˆ………wwwppphhhaaa]]]\\\\\\\\\\\\\\\\\\]]]ZZZPPP>>>...%%%"""!!! iiikkkoootttyyy|||‚‚‚†††“““¯¯¯ÄÄÄÄÄĸ¸¸­­­£££———†††ttteee]]][[[\\\```hhhrrrzzzƒƒƒŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆƒƒƒzzzpppggg```]]]\\\\\\\\\\\\]]]\\\WWWHHH666&&& iiikkkoootttyyy|||‚‚‚•••µµµÀÀÀ···¦¦¦———………ssseee]]][[[]]]dddoooyyyƒƒƒˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆ‚‚‚yyymmmccc]]]\\\\\\\\\\\\]]][[[NNN555$$$iiikkkoootttwww}}}•••···µµµ¡¡¡vvveee]]][[[\\\aaalllzzz†††‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹………yyykkk```\\\\\\\\\\\\]]][[[LLL///iiikkkooosssyyy“““¯¯¯€€€lll```[[[[[[___hhhttt‚‚‚ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ€€€ssseee]]]\\\\\\\\\]]]WWW>>>###iiikkkoootttœœœ|||ddd\\\[[[[[[___kkk|||ˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹†††zzzhhh]]]\\\\\\\\\\\\III'''iiikkkooo|||eee\\\\\\\\\\\\hhh|||ˆˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆˆˆyyyeee\\\\\\\\\]]]OOO)))iiikkkooommm___\\\\\\\\\```sss†††‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹………ppp___\\\\\\]]]OOO%%%iiikkklll```\\\\\\\\\ccc|||‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠyyyaaa\\\\\\]]]FFFiiikkkddd\\\\\\[[[ccc‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹|||```[[[\\\[[[111llleeeTTTPPPPPPUUUwww‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹sssRRRPPPQQQBBBpppXXXBBBAAA@@@ZZZŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹†††TTT@@@AAA>>>!!!rrrHHH333333444eee‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹\\\333333333"""ttt;;;''''''***ddd‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽZZZ(((''''''444JJJ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹AAA///###ttt‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹lll888333‚‚‚‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹zzz,,, 888}}}‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹www000---mmm‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ggg(((LLL€€€‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹|||FFF)))XXX‚‚‚ŽŽŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹QQQ%%%+++PPPvvvŠŠŠŽŽŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽˆˆˆrrrJJJ(((888___‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹}}}ZZZ444%%%EEEkkk€€€‹‹‹ŽŽŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽŠŠŠ}}}gggBBB###%%%999RRRooo‚‚‚‹‹‹ŽŽŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽ‹‹‹€€€lllOOO666###(((===VVVrrr†††ŽŽŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽ………}}}oooTTT:::%%%..."""###000>>>OOOaaattt†††ŽŽŽŽŽŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŽŽŽŽŽ†††sss___MMM===...""";;;***%%%111???JJJUUU```lllwww|||€€€………ŠŠŠŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŠŠŠ………€€€|||vvvkkk___TTTIII>>>///###<<<444...%%%!!! '''...666???FFFIIIMMMPPPTTTWWW[[[___cccgggkkkllliiieeeaaa]]]ZZZWWWRRRPPPMMMIIIEEE>>>555---&&&  UUUQQQ555+++###$$$$$$UUU\\\QQQ888333...$$$ ---///)))•••mmmoooPPP<<<999555///)))### $$$''''''%%%000???444NNNëë뜜œtttssspppeeePPPCCC>>><<<:::888666333111///---)))&&&$$$###$$$%%%(((***,,,---///000111222222000111>>>LLLQQQMMMDDDaaasqlitebrowser-sqlitebrowser-5733cb7/src/icons/000077500000000000000000000000001463772530400215765ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/application_go.svg000066400000000000000000000023101463772530400253030ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/application_link.svg000066400000000000000000000032701463772530400256410ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/application_side_list.svg000066400000000000000000000022371463772530400266650ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/arrow_refresh_small.svg000066400000000000000000000014101463772530400263530ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/bullet_arrow_bottom.svg000066400000000000000000000014571463772530400264130ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/bullet_arrow_down.svg000066400000000000000000000010521463772530400260450ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/bullet_arrow_top.svg000066400000000000000000000014601463772530400257030ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/bullet_arrow_up.svg000066400000000000000000000010531463772530400255230ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/cancel.svg000066400000000000000000000022231463772530400235430ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/chart_curve.svg000066400000000000000000000023471463772530400246320ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/clear_sorting.svg000066400000000000000000000157721463772530400251660ustar00rootroot00000000000000 image/svg+xml Arrow Up Arrow Up Arrow Up Top sqlitebrowser-sqlitebrowser-5733cb7/src/icons/cog.svg000066400000000000000000000021341463772530400230670ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/cog_go.svg000066400000000000000000000031451463772530400235570ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/color_swatch.svg000066400000000000000000000006521463772530400250110ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/color_wheel.svg000066400000000000000000000046471463772530400246340ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/cross.svg000066400000000000000000000015321463772530400234510ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/database.svg000066400000000000000000000020171463772530400240630ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/database_add.svg000066400000000000000000000027451463772530400247030ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/database_go.svg000066400000000000000000000030301463772530400245440ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/database_link.svg000066400000000000000000000040101463772530400250730ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/database_refresh.svg000066400000000000000000000032471463772530400256070ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/database_save.svg000066400000000000000000000036001463772530400251000ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/edit_cut.svg000066400000000000000000000255351463772530400241310ustar00rootroot00000000000000 sqlitebrowser-sqlitebrowser-5733cb7/src/icons/find_edit.svg000066400000000000000000000266361463772530400242610ustar00rootroot00000000000000 image/svg+xml Find Edit Find Edit Find Edit sqlitebrowser-sqlitebrowser-5733cb7/src/icons/folder.svg000066400000000000000000000023121463772530400235700ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/folder_page.svg000066400000000000000000000046211463772530400245710ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/folder_user.svg000066400000000000000000000071731463772530400246400ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/font.svg000066400000000000000000000013551463772530400232710ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/font_add.svg000066400000000000000000000023051463772530400240750ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/font_delete.svg000066400000000000000000000022611463772530400246100ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/font_edit.svg000066400000000000000000000055721463772530400243030ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/funnel.svg000066400000000000000000000027121463772530400236100ustar00rootroot00000000000000 Funnel Funnel sqlitebrowser-sqlitebrowser-5733cb7/src/icons/funnel_delete.svg000066400000000000000000000041321463772530400251300ustar00rootroot00000000000000 Funnel Delete Funnel Delete sqlitebrowser-sqlitebrowser-5733cb7/src/icons/help.svg000066400000000000000000000017361463772530400232560ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/hourglass.svg000066400000000000000000000065401463772530400243330ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/icons.qrc000066400000000000000000000133611463772530400234240ustar00rootroot00000000000000 application_go.svg application_link.svg application_side_list.svg arrow_refresh_small.svg bullet_arrow_bottom.svg bullet_arrow_down.svg bullet_arrow_top.svg bullet_arrow_up.svg cancel.svg chart_curve.svg funnel_delete.svg clear_sorting.svg cog.svg cog_go.svg color_swatch.svg cross.svg edit_cut.svg database.svg database_add.svg database_go.svg database_link.svg database_refresh.svg database_save.svg database_save.svg funnel.svg folder.svg folder_page.svg folder_user.svg font.svg font_add.svg font_delete.svg font_edit.svg help.svg hourglass.svg key.svg layout_sidebar.svg link_break.svg monitor_link.svg package.svg package_go.svg package_rename.svg package_save.svg page_add.svg page_copy.svg script_copy.svg page_delete.svg page_edit.svg page_find.svg page_green.svg page_key.svg page_link.svg page_white_color.svg page_paste.svg page_save.svg page_white_copy.svg page_white_database.svg page_white_text.svg picture.svg picture_add.svg picture_delete.svg picture_edit.svg picture_save.svg plugin_add.svg plugin_delete.svg printer.svg resultset_first.svg resultset_last.svg resultset_next.svg resultset_previous.svg script.svg script_add.svg script_delete.svg script_edit.svg script_link.svg server_add.svg server_go.svg sqlitebrowser.png tab.svg tab_add.svg table.svg table_add.svg table_delete.svg table_edit.svg table_key.svg table_row_delete.svg table_row_insert.svg table_save.svg tag_blue.svg tag_blue_add.svg tag_blue_delete.svg tag_blue_edit.svg text_align_center.svg text_align_justify.svg text_align_left.svg text_align_right.svg text_bold.svg text_italic.svg text_padding_left.svg text_padding_top.svg color_wheel.svg find_edit.svg text_underlined.svg textfield_delete.svg wrench.svg undo.svg sqlitebrowser-sqlitebrowser-5733cb7/src/icons/key.svg000066400000000000000000000025171463772530400231140ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/layout_sidebar.svg000066400000000000000000000024221463772530400253250ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/link_break.svg000066400000000000000000000021141463772530400244160ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/monitor_link.svg000066400000000000000000000053431463772530400250300ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/package.svg000066400000000000000000000037611463772530400237210ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/package_go.svg000066400000000000000000000047721463772530400244110ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/package_rename.svg000066400000000000000000000201671463772530400252470ustar00rootroot00000000000000 image/svg+xml Package Package Package Software sqlitebrowser-sqlitebrowser-5733cb7/src/icons/package_save.svg000066400000000000000000000333411463772530400247340ustar00rootroot00000000000000 image/svg+xml Package Package Package Software sqlitebrowser-sqlitebrowser-5733cb7/src/icons/package_world.svg000066400000000000000000000070661463772530400251320ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_add.svg000066400000000000000000000036351463772530400240520ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_copy.svg000066400000000000000000000017441463772530400242730ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_delete.svg000066400000000000000000000036111463772530400245560ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_edit.svg000066400000000000000000000071241463772530400242440ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_find.svg000066400000000000000000000067561463772530400242510ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_green.svg000066400000000000000000000027071463772530400244210ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_key.svg000066400000000000000000000052611463772530400241070ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_link.svg000066400000000000000000000047001463772530400242510ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_paste.svg000066400000000000000000000033531463772530400244330ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_save.svg000066400000000000000000000044701463772530400242560ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_white_color.svg000066400000000000000000000075661463772530400256470ustar00rootroot00000000000000 White Page Color White Page Color sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_white_copy.svg000066400000000000000000000012361463772530400254670ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_white_database.svg000066400000000000000000000032441463772530400262620ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/page_white_text.svg000066400000000000000000000017621463772530400255050ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/picture.svg000066400000000000000000000026301463772530400237730ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/picture_add.svg000066400000000000000000000035561463772530400246130ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/picture_delete.svg000066400000000000000000000035321463772530400253170ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/picture_edit.svg000066400000000000000000000070441463772530400250040ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/picture_save.svg000066400000000000000000000044111463772530400250100ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/plugin_add.svg000066400000000000000000000025661463772530400244360ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/plugin_delete.svg000066400000000000000000000025421463772530400251420ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/printer.svg000066400000000000000000000050261463772530400240050ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/resultset_first.svg000066400000000000000000000014701463772530400255620ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/resultset_last.svg000066400000000000000000000014711463772530400253770ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/resultset_next.svg000066400000000000000000000013511463772530400254070ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/resultset_previous.svg000066400000000000000000000013461463772530400263110ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/script.svg000066400000000000000000000015261463772530400236270ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/script_add.svg000066400000000000000000000024541463772530400244400ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/script_copy.svg000066400000000000000000000115231463772530400246570ustar00rootroot00000000000000 image/svg+xml Script Script Script sqlitebrowser-sqlitebrowser-5733cb7/src/icons/script_delete.svg000066400000000000000000000024301463772530400251440ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/script_edit.svg000066400000000000000000000057421463772530400246400ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/script_link.svg000066400000000000000000000035171463772530400246460ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/server_add.svg000066400000000000000000000040221463772530400244330ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/server_go.svg000066400000000000000000000041051463772530400243120ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/sqlitebrowser.png000066400000000000000000000353071463772530400252210ustar00rootroot00000000000000‰PNG  IHDR\r¨f pHYsÃÃÇo¨dtEXtSoftwarewww.inkscape.org›î< tEXtTitlelogoO–r&tEXtDescriptionDB Browser for SQLite LogoW’*þtEXtCreation Time2020Jun05V‹ tEXtSourcehttps://sqlitebrowser.org^?G”DtEXtCopyrightCC Attribution http://creativecommons.org/licenses/by/4.0/i×] IDATxÚí}y#×}Þ÷ûÆ`ν¸»¢V\Jä:¢D—i•y•(YR4µtŠÇJÉåØ9lÇ–íT\›¤JŽœ”-GIE%›´,R¤J+Q6I‘Ö-ë4eR¢È]qÉ%—{ÌîÌ` n Ï—?¸¯ÙÀèÆ9˜™ßWÕ…«4ý}¿ó½@ @ @ @Ø.`t & wÞy甦i)ÆØclŠsfŒ%cA Ó4ƒŒ±€$ç< ž ˆµ|d€¿å¹D˯¨´ìS¹ü¼P°í[æœ×câ~@Y’¤Šiš ÆX‰s^ôx<9UU³²,ç}ôÑ2ýÃ$; ï|ç;Ãápx¯®ëó’$í°À9Ÿ0uyKµÜ—¶ñéPää/ßæ8ç9I’r¦i®H’´Ì9_’$颢(ËO>ù¤BW ÀÄâÝï~·_–åýŒ±ƒŒ±+LÓœgŒí° À€Ým,2Á=V,Xâœ_”$éç|‰s~ÀËo}ë[—Ž;fÒi")É%IÚ%ËòÎùÎùÕŒ±ÃØÀCgiÓ ¸à €3œó3Œ±3’$1 ã…Ç{¬F§ˆÀŽ=Ô4í°aoaŒ½À5Þ `žÎΖ„à cì9Îù ÆØ I’ž“eù•ãÇtzv°¼ï}ï»Â0Œ·^&º ûA²æ;u?eŒ=Ï9?à9¿ßÿÌñãÇó$ÛÓ²ÇUU}€ëMÓ¼ž1öv³“|Ì~¿¡P@Á`^¯>Ÿ²,ÃçóÁçóÁãñ4Ý÷ûýe²,7}Ž­¯·BUU˜æë!5窪¾îokt]‡¢(Ð4 †a Ñh@×õ¦ûº®£Ñh ^¯[·š¦Mò)çN3ÆžâœÿsþÔüüü³Ÿüä'5€-†ÅÅÅ«cï`Œ]Ï9;€7a“3ë^¯‘H‘HÑh‘H¡PÁ`Ð"¹¸ ƒ`lûé²!ö­Z­¢R© R© \.£Z­6 Ñ&¡àG~à)Y–ÿñ‘GY&˜<Âï•$éÎù-n07ÖÈb±‰‰¢Ñ¨Er±r¼{1Çœ£V«Y¢P*•P­VQ*•°¾¾Žb±ˆjµº‡v’sþuÆØ×ý~ÿ??~¼H0~—>Õh4nbŒ ¿qÔßéñxÇ-’'“Ië6‹Áã¡ÔÁ¸¡ª* … …Ö××­û…BårœóQ‚àŸ… hšöý­Ø·°%àŽ;îØÃ97€E·ðŽê»Âá0Òé4¦¦¦077gÝï;& †a`}}«««ÈårÈf³XYYµ×Pð ÆØqŸÏ÷÷[Å;˜X¸óÎ;¯ÒuýNÆØÞ:ìcõx<˜ÅÜÜfffN§‘N§áõz‰AÛÕjÙlkkkX[[Ã¥K—°¾¾> oAáœ]’¤/J’ôè¿øÅ € \.ÏýkÆØ/84ÌÏN&“˜ŸŸ·¶™™rÝ PU/^Äòò2VVV°¼¼ŒZm¨ýC€ïxPÓ´Ï>ùä“%n¼ñÆ@4½“1öënÆ2öŒ1ÌÍÍaï޽ؽ{7æçç éj'¸B¡PÀòò2.\¸€sçΡP( 3Lø<€û}ôÑïàµòã΀ÅÅÅ«%Iº—sþAéA?/‘H`ß¾}ÖF™wÂ0C‡¥¥%œ;w¯¼ò *•Ê0>ö4€‡t]ÿ›'žxâÜN¶¸¸øÆØø¹A>ÈçóáÀ8pàöîÝ‹h4JW*aäàœ#—Ëáܹs8}ú4–––Í!è>Ë9ÿ=öØÉm)ÇŽ“~ü㿇sþ'®ë÷s‚Á 8€ƒâÀ”°#l:^yå¼òÊ+8sæÌ À—LÓüÈã?þƒm!ï~÷»ý^¯÷Wü€7ôóÑh‡•W^‰]»vmË.9Âö€¦ixõÕWñÒK/áå—_D þÑ4Íÿþøã}Ë ÀwܱÈ9ÿ^6ÛÛA1†½{÷âÚk¯Å•W^ I’èê"l)(Š‚—_~'OžÄ¹sý…øŒ±ïpÎÿã>úã-#ï}ï{¯•$éÿ¸¡×÷¦R)\sÍ5¸úê« …è*"l ¬­­áĉ8yò$êõz¯9.IÒƒ’$ýοøÅÜÄ À7ÞˆÇãÿ…sþxmn:×Ö~ÿþýxûÛߎ={öÐÕBض0 /¼ðžzê)äó½>¾<÷âoýýßÿý§'Nn¿ýökcŸãœê…ø‡Âõ×_™™º:;œsœ>}O=õVVVzz¯$IßÑ4íŽ/}éKë!‹‹‹ÿÖãñü…iš>·Äó›ßŒë¯¿Éd’®ÂŽÆÙ³gñƒüKKK½xUY–ïú¾ðåM€£GzEù8€ßtûž}ûöᦛnÂôô4ýó‚ çÎÃ7¾ñ d³Y׎„ÏçûÓÏþóÿyì°¸¸’eùqÃ0nr³$Á­·ÞŠ+¯¼’þi¡KŽà©§žÂ?ýÓ?Á0ÜM[èõz¿ò…/|á¶± ÀÑ£Gƒ†a|U×uWYþÇãÖ[oÝ0=@h\.‡Ç™LÆ­üxjjêú~¦0ëi8ܱcǤL&ó¤¦i¿àâ ð®w½ 7Üp¥'z@(Â[Þò(Š‚åeçYÈLÓœWUõ}?ÿó?ÿ×Ï<óŒ92˜™™ùsEQîqÚ/ãýï?8@ÿ&Ð$IÂFñꫯ:Ž70 cÖ4Íw¼ÿýïà[ßúºÜyç¿ iÚ'ÜÄû÷Üs%ú„!`vvét§OŸv]ׯ(•J¡'N|u¨ð¡}ÈkÆSš¦umÏ ¸çž{¨¼G SSSH$xùå—Ýì~Ñ#Gž:qâ„«]5Ù+ŠòŸjµZ×1ûŒ1,..ù „àðáøî:ç´š¦s~ßââbhh ëú‡cè¶]sÍ5¸âŠ+èŸ"F„w¼ãH§Óp⢦i ‘Hä·‡üîïþî-…BáCbU™v›ßïÇí·ßNãó „B’$D"œ={Ýø(I$IzS:þøÙ³g»Vës~¿ÿß;M¯uðàA½G ŒD*•rœ¸T×õ=3337øÚ@Àû§&ž½{÷Ò?C ŒÉ Ø»w/^}õÕ®ûqÎÁ9\<Ï”“H$èŸ!Æ„T*åØ d4M;âôYŽàóù|NÍØC Œ"ïÖ Ff€P(äQ”îKž9½N †]×§½/•JXÂá0¯Õj] ižtà•JÅÑÐuÝ7á´C$A¹\îºO¡P€iš #F±X缫`š¦¿ßÏC¡ãøäL&ƒ¹¹9ú‡„"“É8Zÿµµ5׋•¸)";Ö …’É$û'F„õõuWñÿêêªëÏt5P?À4MGUÉd2صk…ÂÑh4P(\Y§ÝWLeŒ! :ö 뺎ååe˜¦Iÿ0$¨ªjÍÔœs¼ð =}¶kS-˲«^UU±²²âzN3ÐÝò»åÓOúÓžéÉWƒ®¦÷R—.]¢þaT*×ä?þ<.^¼Øówô$Œ1D£QLOO;z"e àœsd2×Ùü••œ:uª¯ï’û98Î98€J¥‚L&ÓqTÎ9òùŸG±XlÊfš¦‰B¡€b±ˆx<ŽX,ÇCWa[CQ”J¥ž Ì9Ç… pæÌ×ù±€ s&“ÁÌÌ B¡êõº¥j¡P¡P ¨T*X__G©T²^çœ[B‡Fá÷û)O@Ø60MÕj•JÅõ ;J¥N:…J¥2ôŠÚÐÖìâœcmm Éd‰DŠ¢4ýXI’¬\®ë( X__·8ç¨T*¨T*ðx<ˆD"ˆÅb´¬aK[ûJ¥‚jµÚWcœ¢(8{ö,.]º4²RúÐÙ%†§R)øýþ B¼ÖU(BUU-@ˆa(‹(•J‡Ã…B"&š¦¡V«¡R©@UÕ¾…cii /^yGíHÌk¥R¦i˜žžF(B0„¢(M¡€ÏçÃÌÌ fff6ˆçõzÝ!áp˜Ä€01PUõzµZ­/_@”Ë———aÆXèäQž”ÕÕULMMYy€`0ˆF£z½ÞvÀP«T*”J%+SÚh4Ðh4Ëåà÷û‡ áóùè*$Œ œs(Š‚Z­†jµ:pR®Z­âÂ… Vçß8;gG`›¦‰\.MÓÇÁ³Ä@„Ü$ŸÏ‡T*…T*Ã0P*•,10MŠ¢Xc <‚Á €ëñ B/„×4ÍòFÆÀ$åœ#—ËaeeÅbÑÕpû-'årš¦!™LÂëõZËÅLCÂ}ê4ŒØãñ ™L"™L‚sŽZ­†r¹Œr¹Œz½Ã0¬"x½^k#A ôJN]×-oµÑh -¯V«Èd2Èd2Ðu}ÓÇÉŒªªbmm ±X Ñh´‰ÜÑh±X Š¢ Z­v£cV`nnÎ „ ˜¦ MÓ iš51‚ÇãßïG €ßï‡Ïç£æ#‚Ã0,Rx¦Ã$¦®ëÈårX]]EµZ»›? ”µ\.C×uÄãñ –Y¸ð"Þ.W·“eìõÖJ¥ÒTU¨ÕjM}Ö>ŸÏ¯× ŸÏG½;„욦AUU4 (Š2ÔÆ»Á+ ÈårVßË$ŽŠÝßXQd³YD"D"‘¶V> ![û×ëuÇzª$IˆF£–‡¡ë:ªÕ*Êåò†²ŒªªPUµiú$á)AaëÆí‚ìbÙí×”h×Õ¤S@œ˜jµ UU‹Å:Íž/˜šš²*"6ëúãdñxñxÜúƒªÕªµµNX"<…Öï÷ù|ÖŒH^¯×ºO¥È͇®ëÑí÷; Q&LÓ´ÂÏb±h];[iþ yþÀB¡€`0ˆp8옰b æ@a‚“n=™LZß-:µ:åDɧÝìFŒ±&A÷=µ¿> ÀaÁí·ã$›0Z‚ôÕjuÓ²÷ÛFìaªªV¿€òH’„p8ŒH$‚™™Ë‚ÛË5NB"‘°7µç ÄÖ-äàœ[®e'ïÅãñ4‰‚ð$IjºÝIùÓ4aš& ðnÁáÅíf§¸žD^IÓv™åjâêc¢7 ‹õ<ƒÝågŒÁ4MK ÄÖ- {•¢Ñh4 ‚¢(®ÿ|QNrwJ’Ô´µŠ„˜ùµõ¾xl~”PX¼ÖÛÖûvr·~É#Ä\^tõÙcøí8µÝDÈÅ4èb’$Y…øóDC‡pëUUí/Š^‚T*ÕØE¥V« |q’ íÄÀI ZV“žÀ”ì⤷‹Óvýí[BF©¶²,[Õñ'Û/!Š¢´uAc–(ˆ\‚½l)’”Fc¤g7ç&c}=Ih¯ñ«ªº#ÉNÐ>Ÿ^¯·é¢0 Ã*išÖ”ˆ²Ÿ¨TƒÁ Ÿ]DÝ™ÖL.ìÿ‹½ô§iZSX²]Ýx€A’$øý~øýþ Q»¤Ukœk÷6Z/X‘L   HÂö€MëgE ‹<ÂNç\†ä)  l=0ÆÖÆØ:•$„-‰  €išßß !@·’[§î=aÂñaxÿ°™!@;Âuz®_’wúœNÄ'ò¶tÃ0þa`8qâÄW¼º™Ðéq7ÂvÚ߉ðíÈN=ê„-ˆ¿;~üøÅàØ±c&çün–¸!¶[ëïF:í×N„ …ÉûnvtÕ055õWNlFÀ)6ïEHœÄ¥›»ßÉ+ &÷=ôÐCÏ Mnºé&À¯P6ÃpCv7ûv#o7 OÖŸ°…pZ×õßw»³ëNÀ;ï¼óÆØïû×ô;ÜÔ`t"v7«Oa‚QaŒÝuüøñâÐn¿ýö×ëõ¿gÐ-FwŠëÝXo7"ÐM„ Æ;ú™Ï|æù^ÞÔ“=z4~üøñ_(û±øö[êtbÂhÏ÷åkBŠ¢<}ôèÑøHàž{îùõzýñ¥O?ý4¾õ­od’ÊN]w½ºïý^¨nÉOè,Þ„ÑÃ0 T«Uký EQ<Ï#\ÿ ®V¯\\\LxÒ4ͦý³Ù,Ο?½{÷"X+Ï k“$ ²,[U§•nì›ýy'qè¥ì×î9± H¯•ƒ^^#ÚA¬NÕÆ(î¿öÚkó'NœxjhÀôôôŸkšÖvýîL&ƒ‡~?ýéOG8•õºyÝ< 7ù§Ù|ÉâQ0Nˆ%ÉÛ‘€˜_ò#øÀæ‡"GõÕjµi_òºu“Xk•[·VÚíEçöu·åE²ÒŒ’$ášk®A2™çÝø¨ëzØ0ŒEöïßÿk¼b…œv["‘À‘#GF²Ôµ›~þNϹiëu; ¨S8@ Œ{öìÁ]wÝ…·½ím¸á†Ћ~¿>Ÿ~ýW~åWbNŸí8+°ÇãùÕ@ ÐuŸ«®º §­ ?¨›ÜJP1w½}ûÖÏo÷Nƒˆº‘½›pÅ#ŒÊ“Ú½{7®½öZLOO[Ï/,,`ff¥R©ëû5M‹†q €/$Œ±7úýþ®ûìÞ½»kÌ"~P?di‘nä¶‹C7¢÷òš›ä 0LâïÛ·GŽA"‘èÈ·W^yÅ1W`Æ €Çã‰9y¡PÈñ`LÓlÊèât‚^r Nî~·Ç”ð" Ä›ßüæ ‹É¶"É“—ט|ãÀ!@ ð*Š2”ÄX³N,Ži_úʉÀ­•v!€[Qp;ÏÍ D5âñ8<ˆ7¼á pò´í|sÚ·^¯ÀôÀ …$'¸üe®É,°T>Ÿ¯«š¹õº¹þ½’ÜÍ$#D~B¿ðz½Ø·o®¼òJ¤R©žß¯ªª£pùúô,‘HµZ­ë>¥R »víêù‡˜¦‰F£a ßï·Š:åÜ¿›‹îTpC|*z…$I˜Åþýû±{÷y¯!q­Vsô4Msõy®À)ãX­V¡ªª(?ôõ£E¢(¨T*–WкL¶XA·]8ÐJðvã ºÞÉpÊÈ%˘žžÆž={°{÷nx½Þ?3—ËYõþn‚“×îZ¼^/"‘ˆ£¢¬®®bÏž=ÿ@á4 ‹Eøý~„Ãa„Ãax<ž&hÍ!tóܾ›Å§0€àŸÏ‡¹¹9ìÙ³sss®ó\n¹±¶¶æhý×ÖÖÜ‹”›b±ªÕj×}ÄJ¹NÌ^=!ù|~¿¡P¡PÁ`Ð"»išÖØ·Ë_÷BøNž A–e¤Ói¤ÓiÌÎÎ"¬7dmm ’$uÿMÓÄÊÊÊpÀçóYëÓ;¹'~¿(®Ž“H’„`0ˆp8ŒH$²¡馩§AèöY„ǃD"T*…™™¤Óé¡Zùny¶Z­æfŸ9sƵûïZ 8z¦ibyyóóó#ÖïªV«¨V«Èd2e‘HÄ ÂápÛ†¡^·~¼ ÂöA @"‘@2™D2™D*• áí¨T*ÈçWè«×ëŽ B} €p=F×ý ÃÀòò2fffKÄ®ë( ( ^¯•ÚC†N±S7òÓ¼€;ËD"H$ˆÅb˜ššrlr‡åÏçóŽ×šišøÉO~Òóür/;ûý~+cï$+++H¥RˆÅb›râZCá¾kЄ×ëíêR ê%&Œ1ƒAD"k‹Åbm½ÆÍ‚išÈår¨T*®®õ“'O¢X,öü=r¯o…BH§Ó¨T*]¿sŽ\.‡z½Žt:ÝwÝs˜3¨´†2²,Ãï÷C–eø|>Ȳ<ÇKœè¢œ,ˆ.rFãvã{¢(X[[sUËçœãÅ_Ä¥K—úózú±¬‚Ô³³³Èd2(‹-a­VÃÅ‹‘L&F'ò„‹ÎÄv.¡¨¹J’dm4pr I’åуAƒAƒA„B¡-%äœsäóyǾûþ§NÂ… ý/à-÷ûÆb±ˆT*…½{÷B×uär9är¹¶D2 Ùlår©Tj¬¹Qƒ°.$£·à>Ÿ>ŸÏ ×Ä&ˆÞoóÙ¤¿V«!ŸÏw¼ÞÚqêùçŸG&“,ï1ÈA ¤ÓiȲŒÙÙYLOO£P( ŸÏ·mVËˡÃH$[úÏãœÃ0 ǤKëåvÓí”\c ²,[ÇK–eȲ ¯×ÛDtY–·õùÄ/ PUÕõûjµž{î9”ËåAôäóyK •J!•J¡Ñh —Ë¡P(l ‰ˆÃƒÁ ‰Ä–ñú=Gvèê–Š¡Óvah÷¸u_ûs­c Ãè(8¢yÊÞB-D«ÝsÂãaŒY¿Ãî ‰¡Ù[§«"¼öˆšÛž}K—.áÅ_ÚlÜò0~L6›ÅÔÔÂá°U& صkæççQ,±¾¾¾!£Y¯×Q¯×­Zkë@ ÓNr‚ŠÐ?Ä„žÅbѵ«/Ðh4ðâ‹/"›ÍÕ[šµ¾¾Ã0,ë/~ $IV…¦i–؇7 ¬¬¬XuØh4ºíÝ?ÂÎA£Ñ@¹\FµZ홼œs,--áÌ™3#Yƒc¨,«T*0M3330Mõz½é ½^¯Õ7]¯×­Æá‰f1H”mÈ"¶Dɹ\.÷ßÛ‘ËåpúôéŽS€Oœ·~uuÓÓÓˆÅbÐ4mƒ°J5óóóV"DÄDö&žõõu„B!„Ãa OúZ­†jµŠF£Ñ7i×ÖÖpþüy”Ëå‘'‡Gâg«ªŠ••¤Ói„B!øý~躎Z­Ö6é!ÚuP­VQ,-10 årårÙjGîÔëO Œº®£^¯£V« d©9çÈd2XZZrÕý7Ñ Ùl±X ‰D^¯ñxÜ‚Nn‘ ÷ÂÂJ¥’?™¦‰Z­†Z­†l6kuyƒÁ‘>"ì1}£Ñ‹rÌ“ÕÕU,--õ4µÞÄ €=/ ë:¦¦¦¬É@‰LÓ„¢(¨Õj“@@333PU¥R ¥RÉJ¦ˆ*ðzŸ¿-(‰H¶•›(¹‚Z­†µµ5,//‹å¼6å·…%Š¢`uu‰DápØ"¬°öªª6‘¹|>Ÿ•@ž@©Tj ì}þ¢[L þ!A ôй*Û寒µµ5d2ËÍßì°±±BtªªŠD"ÑÔ"&M$V,Õ-s*I’5¸caaõzÝÊÔj5kÕ^á5Á±/ŸD E‚ ¥˜RQ¨ª: owñK¥ÖÖÖËå&®ësìf±Ñh ›Í"# n v4E,ƒa–Wà4pûEù±R©X›x¯ÈЊeÑ©&ÖRu«mOˆÖmaáGQ[7 Ã*q¯¯¯[=1“Øî½)~±iš( P¥cÓÇã±Ä@L*ÜíDJ’„X,fÍC ë:*• Êå2*•ŠU…àœCÓ´ U I’Ú>¡^„­Ó4¡ª*4Mk"ü( ¨ëºÕäV(,/bÒÇxlj`¬( 4M³~:ÁãñX.¿ð"†+ï@–e$ k5UU­\AµZÝŵÏJÜ* ^¯·íÀ‡Í!¹¦iÖˆM!æÃvá»}µZm2.[…ô#âd "F"ÇAŒ1«1ˆ1Ã0š¼§®+aÑ“Éd“‡ ¡“ ˆªE»²¯×Û4ÊMT=(¬èÏ]ä÷ ðH?’·“˜ùZ~;Œäœ˜Ô¸iš(—Ëh4‡Ã®‡ ï ‚1¶¡dãÔ‘ÕŠJƒ˜aIDATê!ˆæz½n‰‚ÓÀnâ DK’¤¦á¯bHl»ÛíæQˆÑŠb3 úmÝ6ƒÜâx‘×Aë¨Ê퀉«†J¥‚h4Ú×|ÂÇãñ&—¾V«YaC·!˜’$YåÉt:m…*ÂßÑËEêvî€VÁ¢ ‹a¶öá·­·âýö ‡x½õ;c~‡}h±ý9qÁÛ‡·»µ“]f‰¶a ”ø_EWŸ=g°çj˜Øâø°¬€˜NÌ,'m-ý¨ªÚñ¥C6ˆ\‚ý¢b˜.°py Ã50öÿ^Ôú·bü¾­`”„Çã±Zˆíqœ=k,²È(r öYE±ˆbë&,„Ñ^?­%?EQšJr´Èë€Nž‚Èò‹EIÅ&²Ì")eOLÙSx "ü°»—b³{$ ƒ{‰öÿF¸è m‰@ÐßIºœ¼k7­–=C-’[öðz£R+„u²[)§pd'YpqEbPÜ Â·KÊÙIÆ ‘¹o·š=ž·gÁEÂL–å aˆ€®ëMÍ,ö[A€­JêÖª€ìv!ívN $[ö 3;-;ÖúØ4M+înë¹n¯½>.îwòH쓆özÞ;‘±õÛM\Ú:Yi7ËM'ØÑ}©óvDd¤äï!‹]t]‡Çã±îwŠ‘}Ž\r€#ö„ €&2ŠûíHÛ©)FT"Dâ±r‘u%ŒŠ¢X=àíšaº5Ê8½F Œ%<%ÌU'H(@ ì4 €°@!  lI4†!YÂÖç<3°0Æ^& º6a º÷’tz`àœw3I׎pà `ëçv«¹·«¡“¶¾5°˜¦ùùIðºÖ­eî$&ˆÝM8ç&Y–¿:°Ü}÷ÝÏøçIñœ¼7¢Ðé¹v$o÷ydý [ŸzઠÀeüñ$xn¬¶Û|‚“kßø$„ GÙãñü™«<›îºë®¯1ƾ4î_ÑmHh7âwò œò zè;õ×Rð„ð'>øàòÐc°<Î_á›w#w¯C^;¼“'@d%L"c_:tèÐÿv»¿k¸ãŽ;V%Iº—1¦SzÍÈ»­¸±îÝÆí“Å&L ^äœß{ìØ1sè‹‹‹_7 ã×ðq €«ÝËg9… ½ˆÂÔ›.aB¿×ÎEÎùm=ôÐz/ïëy,À¸±ÄƒznÜþnSw Ój“¨z…a¨V«Ð4m À3÷Þ{ox$ðK¿ôK» Ãx@\¤gÏžÅ#<‚b±8ò`PKî–dn< ê$L ÄB·â:Tå ªª`C€P(ôˆ®ë^ûsÙlÇÇ™3g6MœîDênÖ}Ü!ån9Q­VQ¯×7¼¦iÚ;ï¹çžßªÜ{ï½7—J¥·µ{MQ<ñÄxòÉ'‡¸‰Ñâ÷^¬w?"A!aœÐ4 år¹ãŠU—ç©üèÑ£Gw M¼^ïÇÅb’¶jµ ¿ß?ô•mÝÌ2;Œ|€ÛR#% ›D"Ûn» ³³³–áé´éº’eù¿¹ù\ÇIA?üáÇÏ;w•X\³n¾ùfë†I »¥µ[ÜnϹ±èíÄdý‡¨ì8räÞô¦7A’$øý~\¼xÑÍ[?pï½÷þÑ<H|>ß¿óù|]ýÜd2‰ùùù ±ì0Üd;ùìi%ë{:=ïæ¾Ó(@ £F0ÄáÇqÕUWA–_§éôô4öíÛ‡ÕÕÕ®ï×uݧªêÝþÏ@àñxnv²þû÷ïïøš}škÇ3ЉäÝDÁmEÀÍüÛe0 Íä"‰àª«®Â¡C‡:òåŠ+®@¡Ð½ä/Iêõú €×ëÝã§ N,ìèõz{Ê´ÆãÝ,¿Dï”èöx+‹…“‡t:Çcß¾}Ž×v<‡' Ñh8 ËrÈɰ»(Ý`š&E¦ie>ŸÏ•WÐ)η‹B§×º½Ɉ¿Õ-)‘2àóù°wï^:tÉdÒõû¼^/œ8ic3 @0dNjÓëJµ¦iZË`˲ ¿ßßQÑÚyíâüNa‚Óc7$ßnƒ°¹ç~vvû÷ïǾ}ûú ‹UUuô8çÑ «NjS.—û>!b}½z½Ž@ €@ ŸÏ×1Ð*nÅ kï†øT $ôBú©©)ìÞ½W\q‚Áà@ŸW.—]ynà(‘H¤âFmêõú@?Ì4MÔj5Ôj5x<ƒAëLjUs{§)Àœ,ûv#=‰ÖøH¿gÏìÞ½¡Ph(Ÿ«ªªe,»¡V« G<‹Å (Ý×Y]]ÅW\1”)8T«Ux<„B!k³R¸O­¥Â^.ú~I? !—kN!Àhàõz177‡]»vann^¯wèß±ººêø¹ÕjªªG ‹9ºùõz•J‘Hd¨?Ø0 ”Ëe”Ëe0Æ …‡›¡•”ݬ¾ÛIBÆí )·dYF2™ÄÔÔÒé4ÒéôÐ;a[­zµZu´þgÏžuÿÜìäóù …ãŠ\.¿ß?å©×ë¨×ëÈår$ Á`‘H‘HápØ5aݹSÜO9€éÖÇãqÌÌÌ`zzzä„oÍ•­­­5åÇ:YÿL&3\^ëLªV«ŽqüÊÊ æçç]—išV¨ \#áD"ƒÁ¶•7ãüö!l²‡Ãa$‰¦m\„oõ‚WVV`š¦cÀ /¼Ó4‡/¢Ù) ë:–——Guƒ¦i(‹ÖŒ1øý~+™ ;fOÝXø^"!løý~ÄãqkK&“ŽÖv\×ôêêjÇÑvœ;w¹\®·0¦×“dš¦ãÁ躎K—.azzzhÙÏ~C†F£F£Ñ¤ì>Ÿ@^¯>Ÿ²,wõXÆPrn Yù¡H$⪅v°¾¾Žb±èêš(‹xöÙg{rýûAî½{÷BQd2™& Ûîàjµ¦§§›6¦inð„H’d‰Â(bAòz;W¢ƒT„xâ~0KjP¹\Î1Ô(•JøÑ~ä*Dš…šššÂßøFT«Ud³ÙŽójš†ååe„Ãa¤R©¾Ú7†at¬€Ø“Ä|ýæˆü¯»évoÌçóY}>ü~ÿD“~¯±B¡€R©äú=kkkxþùç{nÅŠpÎQ(055…p8Œp8 EQÍfQ(6†sŽJ¥‚jµŠD"X,¶)ÕQx½X-û¤)’$Y™]Aþ~ܸI5잓ȵH’Y–­çÄ­ ùv¸.z¹~J¥ …‚ëÿ…sŽsçÎáôéÓƒ‹í ŸÏç133c¹d»víÂüü<ŠÅ"òùü†Ò!çëëë( ˆF£ˆÇã[Ö]ëÕemwßé‚`ŸWAÜ·¯hß·Ûôeö}:µR ÏÆþ\ë´S’$YÞ¸do½OhÏb±ˆr¹ÜÓ\šš¦áäÉ“Èf³Ãñ¶†ñCÖÖÖ0== ¯× MÓ I’É$’É$òù< …B“«Â9G©TB¹\ÞQBЫhˆpi«…M„öÐuÅb•J¥go/“ÉàÅ_t‹2g³Y$“IÄb1ÔëuëÇ,,,`aa•JÅÊnÚ-Q©TB©TB(B4ÝÔÒ!0 Ôj5T*ÔjµžC°F£—^z ÙlvèáÛPMn¡P€iš˜šš²†øÚXÔ\P,±¾¾Þ"ØG†ÃaÄb±±7ôöÕj¥R©¯Da8þ<Ο??²U¸†îs ×fzzñxFŠ¢4 ÇãA*•B*•‚®ë( (‹–†ay@ÀJ2’L˜t†a Úi·p‡Ûϸté.\¸0Tw,¼62peeÅê …BPUµZmCÜ#˲5’ÊÞÊ+Ä@Ôæóù<|>Ÿ5ø‡<Â$Yúz½ŽZ­¶Áë횦áÒ¥KXZZ‚®ëc©ÖÈ£<)™LÆ*ù‰FF£ÑV€×ÆS 1ÐuårÙÊ”Ú;ø …ü~¿%.^¯—²Í„±BLÌQ­V¶Òªªbii ËËË0 c¬eÚ‘¦ÝE¯€®ëH¥R`ŒYZªªZáAÛ»<Ö:™LÂ4Í&10 ÃõõukX°hý¤jaTV^Ì~5Œ˜¼X,beeÙl¶©Ì;NŒ…)µZ º®#™LÂï÷[{ƒA†ayݺíÄ(-bˆ¨8ˆaÁ¹\²,7µˆ’ ú!¼¢(ÖüƒtÛµZûL&ƒL&3P¸°¥@œÐl6‹X,†h4j¹ìǪhšæ*Ž^Äìì¬*”J%T*†]×Q©TP©T¬ïí£bÛIÝfgOUx”bá×ze …VWW›Jà“€±›ÆJ¥UU‘H$šÆ[Ûwˆ?D¨o·f8ç¨Õj(—ËVÍx=3kŸ(QÌ­ ­sÊ#ì ²‹)éEêvþ¼^ zûóù<ŠÅâØ’z/ÀkÙÎ\.gYþVâ‰\h„jµÚ5ö³¸ˆ©ÁÄLÕJår¹©,£i4M³¼»§ „akCäŠ4MƒªªÖýQz¹¢^ôöOú¯M ŽkµTUE,ë8ºKä ¦¦¦,1åÁn'X’$Kdæææ iš•+¨V«†þ O¡õûŨ4±É²lÍ@Ø|’ëºMÓ¬[AøQ“ÏîqŠöÞ­6W¤< `±X„ÏçC4u¬ï‹0AŒ a‚ÈÐvƒ×ëµævŠm„vv—±8µqKy†á\‚äb6*±‰çÆ>4 T*”J%T«Õ&×~+瞘ô¸¦i( –ëïÆº —_„öÅEÜx²,7U ð:ªÕj×Ê„“8ˆãkò*&Ãbwâ¨91rÑ0 ëV×õ&²‹ÛÍ$• ¼¸Êå²Bl—¹&®>¦( TUE4íyÒǃh4ŠX,f ‚¨ÛŠ­[ h¯HØGˆŠ–^Æm‹¥Ï܈™Y–›Û‡Þڇߊ}ìÏö!È¢i¥uh²išÖ&öäÏO"ìU(ñ_Ûs¶ã„-[ F£…½AHT ì nC¢l(Vom­Pˆ‹eЋC€³Òö™‰ìç¢õ±ÉÖco%èv›Yœkш&Œ„¦iÛšì[JFõˆ‘†áp¸)a#Ä@UU+‰ÔÎrÛ“’vQ‘=ÆPkɽž;'R車¦i–Ð×ëu(вí-; @S”ýì…a–Ø7»¥ïÍIv+cßÄÅGnXb¯èºnåfìaÊN'; @!„Z/"‘¤²'¬ì‰-Î9dYÞSVI\ ¢óL„$$í¯‘C°ŸwAöv™xZ¸…`äâ J€–³g¹í‰1Q* …B~§èA·×³í·ÛI Äùh­ ØÅTÛí°€‰}FÜVqh}lÏ¢‡B¡¦äœý\ïAĶ­á‰Ý+ÕÐR1I¨=¯ÐnâÑN•ÖÉL;›¬8 ÀŽ€(áÙ/xñ¸õ|ˆé³…ØÝc»×!2Ý¢ŠÜƒÝ“hG¸Öïk%v7’öú «{¸ÕÜX»%·LT:ÕÇYí¥@‘h.¿xÝþÞNä„|d…I&Ê ˜ä¹F£a­ßÖ:W;Qèg"$a¤¹¬I€IwÝ €€@Ø~`¶$ô€sž# ¶$² cì" y„-‰ þ¿Ý µ´Öîqëkä&œóo,¦i~€¹YÐŽlž„äNûØ…ÈOØ $é‰àî»ï~À×7S:‰A7K݉äí,º[± f ?üð7‡À4ÍnÆ/íÀn,u?a…“uïôÜVÈOv¼ûÿ§øPàèÑ£_çœ?º™!€[÷ÛÉâ»!²“Ø7J& Œ±ïö³Ÿ}ÐU˜Ð .Ê Ã€^­¹·¾›GÑ©÷¾Û>¡lšæÝXÿžà®»îZð¯0æ„`':tëDÎnq|7èt,ä&&çüW~øáSnßÐS+ðûÞ÷¾'c¿µ™@¯V·Ÿá¯öÛÖ<% “öóß~øá‡ÿ®—7õ<`qqñœó?Þ¬€›ø½‹Þå§aÉÿ{=ôÐÿëõ} Z\\üS¿½Æ£ò†÷óy” LTÎùzè¡¿èçÍ}|Ï{Þó7Œ±÷XwÀ-‰ÝîÓ«å'ò&Kœó›>ó™Ï<Ôï 4ø]ïz×—dY¾ÀÇåôÚ‘çÆ’»!'A €°IxB×õŸyðÁjÕx>€[o½õL*•ºž1ö‡ÔQ@/Ößmøà4‡^§ãpsLÂQ`ŒýƧ?ýé÷>üð×å‡2!Èu×]§ÝrË-eŒý€§Gå¸IöÓúÛHP@38€‡cWýíßþí'á²Îï„¡N zóÍ7?Ã9û·¿ýí{c`vXÐ\soç~·>çÔ(ä†ä­SaÓ  Â&àiI’~çþûïÿî°?xè³3Æ8€Oó›ß|D–åøCsÃòcMDw#nãÿn9 DØü˜sþ§ŸúÔ§>?,‹?r¸é¦›*þòË_þò_ÇãñÃû ƒzÈ߉ô½Žóïä%а`Âñ=½ÿþûõ|]€Ûn»­ à/Ÿ~úé¿âœÀï÷"í<·÷ÝÄêN–¾SÈ@9ÂaxŒsþ‘ûî»ï‡ãúÒ±- rÝu×Õ|ìsŸûÜÇßð†7ÜàC~ €Ç­Àžpã8YûnBÐ-_@@.rÎ4 ã“÷ßÿ™qùØWºûî» _ðµgŸ}vcì~À¾^=»t{_§çzˆÈOx`aaáÉcÇŽé›u ›º4Ø‘#G.øèç>÷¹ÿuøðá_dŒý:€Û;yí,}'1èen€^<Jútñà!MÓ>sß}÷å'á &bmÀË^Ác»páB°ÑhÜ à(€Û9çqÓ4›VÏí¥è–ð¬{·V`"?Á€bŒ7 ãóŸøÄ'.NÚNÜâ {öì© 18}ú´À;c‹œó_æœÏÚÉ-–Õvã ¸%¼ñ) 8 Æû€ãçÑ}ìc…I>؉^øÊ+¯TD¾€sþ{ËËË?Ë»À-œóŸà+éÚÅ [Û°Ók­ûØýLQFØöÐ.»öß4M󛌱ï}üãW¶ÊÁË[å@c:€ï^Þþë¥K—BççÜzyûØZ›ÝZp·‚@¤'ØbùS¾ËûšÏçûÊG?úÑâVý1òV=ð………šð \.O†ñ Œ±ŸeŒ]à_¹!µá‚°­QðÏŒ±š¦ù”išßžt·~G@+¢Ñè€Ï_ÞÀ9÷T*•71ÆÞ à­œóZ½7ÂÐ8¶,t/1ƞ᜗1ö½P(ô±cÇÌíúƒåíúÃc€“—·O@>ŸK’tçüZW3ÆÞÂ9? ÜÉÊ‹Á@$ÛËœó“N\¾ýI>Ÿö“Ÿü¤¶“N‚¼“~l*•*âµUŽšV:Z[[[PUõ0çüjÆØ[/‹ÂÕö$ aK‚uÎùOœ·¦i>ÿ‘|d•Î΀N˜žž¾à’È'œ?~AÓ´ÃŒ±œóÄöq:sƒugcg8çM·ÇŽ;C§‡ /ìÝ»WÃüä'?™aŒ¼,{ÌØ×†>‹[ÅÀ¬Xp‘1¶Â9¿È»Ä{À™T*uî7~ã74:U}zHt F‡ï}ï{3gN×õÝœó9Ã0v˜2 # ešæç<Å9O™¦™âœ3‘s°çD>BÜ:=×Ï{ÆõÙŒ±¢ayÆXŽsž7M3 Ï9ÏqÎWcKV<ÏR8ιIv ¾öµ¯MÕëõ”$I)Ã0RœóˆišI~ÎyˆsgŒùMÓŒˆ˜¦é¿Š„8ç~QιlËY0Îy¢…>á–çj”–çŠxm¥A\Ã4Íç\P圗c ç¼dšfsÞ`Œ8ç Îys^äœW$IÊ뺞—$)?77—¿ÜöM @ @ @ @2þ?ͱÏÝg{ûIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/icons/tab.svg000066400000000000000000000015461463772530400230730ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/tab_add.svg000066400000000000000000000024741463772530400237040ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/table.svg000066400000000000000000000022001463772530400234000ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/table_add.svg000066400000000000000000000031261463772530400242200ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/table_delete.svg000066400000000000000000000031021463772530400247240ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/table_edit.svg000066400000000000000000000064141463772530400244200ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/table_key.svg000066400000000000000000000045521463772530400242640ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/table_row_delete.svg000066400000000000000000000032321463772530400256170ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/table_row_insert.svg000066400000000000000000000031721463772530400256640ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/table_save.svg000066400000000000000000000037611463772530400244330ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/tag_blue.svg000066400000000000000000000015541463772530400241060ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/tag_blue_add.svg000066400000000000000000000025021463772530400247100ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/tag_blue_delete.svg000066400000000000000000000024561463772530400254320ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/tag_blue_edit.svg000066400000000000000000000057701463772530400251170ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/text_align_center.svg000066400000000000000000000006251463772530400260200ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/text_align_justify.svg000066400000000000000000000006171463772530400262360ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/text_align_left.svg000066400000000000000000000006111463772530400254650ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/text_align_right.svg000066400000000000000000000006131463772530400256520ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/text_bold.svg000066400000000000000000000006341463772530400243060ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/text_italic.svg000066400000000000000000000005321463772530400246300ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/text_padding_left.svg000066400000000000000000000014171463772530400260060ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/text_padding_top.svg000066400000000000000000000014001463772530400256460ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/text_underlined.svg000066400000000000000000000006421463772530400255160ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/textfield_delete.svg000066400000000000000000000013741463772530400256360ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/icons/undo.svg000066400000000000000000000025121463772530400232640ustar00rootroot00000000000000 Undo Undo sqlitebrowser-sqlitebrowser-5733cb7/src/icons/wrench.svg000066400000000000000000000026701463772530400236120ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/iconwin.ico000066400000000000000000002576461463772530400226510ustar00rootroot00000000000000 hF  ¨®@@ (BV€€ (~W(  ÃÃ×××]]]çççïïï1ÝÝÝUÆÆÆs±±±†¦¦¦œœœŽ“““„‰‰‰pSvvv.nnn iiiµµµÈÈÈhããã¿òòòçãããøÇÇÇþ±±±ÿ¦¦¦ÿœœœÿ’’’ÿ‰‰‰ý÷uuuælll½cccf\\\´´´qÄÄÄùåååÿ÷÷÷ÿêêêÿÊÊÊÿ³³³ÿ¦¦¦ÿœœœÿ“““ÿ‰‰‰ÿ~~~ÿtttÿkkkÿbbbù[[[s³³³ŽÅÅÅÿÞÞÞÿÞÞÞÿÐÐÐÿÂÂÂÿºººÿµµµÿ²²²ÿ®®®ÿ¨¨¨ÿžžžÿŽŽŽÿxxxÿcccÿZZZ‘­­­Ž¼¼¼ÿÅÅÅÿÊÊÊÿÊÊÊÿÃÃÃÿºººÿ´´´ÿ¯¯¯ÿ«««ÿ«««ÿ­­­ÿ±±±ÿ°°°ÿ“““ÿkkk‘‡‡‡~···þÝÝÝÿïïïÿãããÿÇÇÇÿ±±±ÿ¥¥¥ÿ›››ÿ’’’ÿˆˆˆÿ€€€ÿ{{{ÿÿ‰‰‰þppp|­­­~ÃÃÃþæææÿ÷÷÷ÿêêêÿÊÊÊÿ³³³ÿ¦¦¦ÿœœœÿ“““ÿ‰‰‰ÿ~~~ÿtttÿiiiÿ```þZZZ{´´´‘ÆÆÆÿÝÝÝÿÜÜÜÿÎÎÎÿÂÂÂÿºººÿ¶¶¶ÿ³³³ÿ°°°ÿªªªÿ¡¡¡ÿ‘‘‘ÿzzzÿdddÿZZZެ¬¬‘»»»ÿÆÆÆÿÌÌÌÿÌÌÌÿÄÄÄÿ¹¹¹ÿ²²²ÿ¬¬¬ÿ¨¨¨ÿ§§§ÿ©©©ÿ®®®ÿ°°°ÿ•••ÿlllŽˆˆˆ¸¸¸þÞÞÞÿñññÿäääÿÇÇÇÿ±±±ÿ¥¥¥ÿ›››ÿ‘‘‘ÿˆˆˆÿÿyyyÿ|||ÿ„„„þnnny¯¯¯‚ÃÃÃÿæææÿ÷÷÷ÿêêêÿÊÊÊÿ³³³ÿ¦¦¦ÿÿ”””ÿŠŠŠÿÿtttÿiiiÿ```þZZZ~´´´‘ÆÆÆÿÛÛÛÿÙÙÙÿÌÌÌÿÁÁÁÿ»»»ÿ¸¸¸ÿµµµÿ³³³ÿ­­­ÿ¤¤¤ÿ”””ÿ~~~ÿeeeÿZZZªªª‘»»»ÿÂÂÂÿÁÁÁÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÂÂÂÿºººÿšššÿnnnŽssso¡¡¡÷ÁÁÁÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÁÁÁÿôjjjh>>> hhh`ŠŠŠ¹   å­­­÷´´´ý¸¸¸ÿºººÿºººÿ¸¸¸ÿ´´´ý¬¬¬öŸŸŸâˆˆˆ´eeeX;;; ÿÿÿ--- RRR-fffRqqqqxxx…{{{{{{www„pppodddPPPP**** ttt€À( @ ÃÃÍÍÍÑÑÑÊÊÊÀÀÀ µµµ­­­¨¨¨ £££"ŸŸŸ"ššš•••‹‹‹ ˆˆˆ………ˆˆˆÛÛÛnnnèèè òòò&îîîLãããrØØØ“ÌÌÌ­ÀÀÀÀµµµÍ­­­Ö¨¨¨Û£££ÞŸŸŸÝšššÚ•••ÔË‹‹‹¼†††©‚‚‚}}}lxxxGsss"ooozzzmmmÆÆÆÁÁÁÍÍÍ-ÙÙÙyèèè¼óóóåðððùæææÿÜÜÜÿÍÍÍÿÀÀÀÿµµµÿ­­­ÿ¨¨¨ÿ£££ÿŸŸŸÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿÿ}}}ÿxxxøsssânnn·iiiseee)```bbb¹¹¹¶¶¶ÀÀÀ‡ËËËæÙÙÙÿëëëÿõõõÿóóóÿêêêÿàààÿÎÎÎÿÀÀÀÿµµµÿ­­­ÿ¨¨¨ÿ£££ÿŸŸŸÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿÿ}}}ÿxxxÿsssÿnnnÿiiiþdddã```„\\\]]]§§§´´´–¾¾¾ÿËËËÿÚÚÚÿîîîÿ÷÷÷ÿõõõÿîîîÿåååÿÎÎÎÿÀÀÀÿµµµÿ­­­ÿ¨¨¨ÿ£££ÿŸŸŸÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿÿ}}}ÿxxxÿsssÿnnnÿiiiÿdddÿ___þ[[[—WWW¬¬¬²²²Ø¾¾¾ÿËËËÿÛÛÛÿðððÿøøøÿ÷÷÷ÿñññÿéééÿÒÒÒÿÄÄÄÿ¹¹¹ÿ°°°ÿªªªÿ¤¤¤ÿŸŸŸÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿÿ|||ÿwwwÿsssÿnnnÿiiiÿdddÿ___ÿ[[[ÛXXX ¬¬¬ ²²²Ü¾¾¾ÿËËËÿÜÜÜÿòòòÿ÷÷÷ÿòòòÿçççÿÛÛÛÿÎÎÎÿÂÂÂÿ¹¹¹ÿ²²²ÿ¬¬¬ÿ¨¨¨ÿ¥¥¥ÿ£££ÿ¡¡¡ÿžžžÿ™™™ÿ“““ÿŒŒŒÿ„„„ÿ|||ÿtttÿmmmÿhhhÿdddÿ___ÿ[[[ßXXX#¬¬¬ ²²²Û¾¾¾ÿÐÐÐÿÞÞÞÿÜÜÜÿÑÑÑÿÅÅÅÿ¾¾¾ÿ»»»ÿºººÿ»»»ÿ½½½ÿ¾¾¾ÿ¿¿¿ÿÀÀÀÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿ½½½ÿ»»»ÿ¸¸¸ÿ´´´ÿ­­­ÿ¤¤¤ÿ———ÿ‡‡‡ÿtttÿfffÿ^^^ÿ[[[ßXXX#¬¬¬ ³³³ÛÁÁÁÿÆÆÆÿÀÀÀÿ½½½ÿ¾¾¾ÿÀÀÀÿÂÂÂÿÃÃÃÿÄÄÄÿÃÃÃÿÂÂÂÿÀÀÀÿ¿¿¿ÿ¾¾¾ÿ½½½ÿ½½½ÿ½½½ÿ¾¾¾ÿÀÀÀÿÂÂÂÿÃÃÃÿÄÄÄÿÃÃÃÿ¿¿¿ÿ···ÿ¨¨¨ÿÿoooÿ[[[ßXXX#««« «««Ü°°°ÿ»»»ÿÂÂÂÿÆÆÆÿÍÍÍÿÓÓÓÿÔÔÔÿÑÑÑÿÊÊÊÿÁÁÁÿ···ÿ¯¯¯ÿ«««ÿ¦¦¦ÿ¡¡¡ÿÿšššÿ———ÿ–––ÿ–––ÿ™™™ÿ   ÿ©©©ÿ´´´ÿ¿¿¿ÿÃÃÃÿ»»»ÿ   ÿsssßTTT#ŠŠŠ‚‚‚Û®®®ÿÇÇÇÿÐÐÐÿáááÿðððÿðððÿçççÿÜÜÜÿÍÍÍÿÀÀÀÿµµµÿ­­­ÿ¨¨¨ÿ£££ÿžžžÿ™™™ÿ”””ÿÿŠŠŠÿ………ÿ€€€ÿ|||ÿxxxÿyyyÿÿ”””ÿ°°°ÿ§§§ÿwwwÜ___ QQQ iii­ªªªÿÌÌÌÿÚÚÚÿìììÿõõõÿóóóÿëëëÿáááÿÍÍÍÿÀÀÀÿµµµÿ­­­ÿ¨¨¨ÿ£££ÿŸŸŸÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿÿ|||ÿwwwÿrrrÿmmmÿhhhÿlllÿnnnÿXXX¦\\\««« ¯¯¯­½½½ÿËËËÿÚÚÚÿïïïÿ÷÷÷ÿõõõÿïïïÿåååÿÎÎÎÿÀÀÀÿµµµÿ­­­ÿ¨¨¨ÿ£££ÿŸŸŸÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿÿ|||ÿxxxÿsssÿnnnÿiiiÿdddÿ^^^ÿZZZ¥WWW¬¬¬!³³³Ý¾¾¾ÿËËËÿÛÛÛÿñññÿøøøÿ÷÷÷ÿñññÿéééÿÒÒÒÿÅÅÅÿ¹¹¹ÿ°°°ÿªªªÿ¤¤¤ÿžžžÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿÿ|||ÿwwwÿsssÿnnnÿiiiÿdddÿ___ÿ[[[ÙXXX¬¬¬#²²²ß¾¾¾ÿËËËÿÝÝÝÿòòòÿöööÿïïïÿãããÿ×××ÿÊÊÊÿÀÀÀÿ¸¸¸ÿ±±±ÿ­­­ÿ©©©ÿ§§§ÿ¦¦¦ÿ£££ÿ   ÿœœœÿ–––ÿÿ‡‡‡ÿ~~~ÿuuuÿmmmÿhhhÿdddÿ___ÿ[[[ÜXXX ¬¬¬#²²²ß¿¿¿ÿÑÑÑÿÜÜÜÿ×××ÿÌÌÌÿÂÂÂÿ½½½ÿ»»»ÿ»»»ÿ½½½ÿ¾¾¾ÿÀÀÀÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿ¿¿¿ÿ¾¾¾ÿ»»»ÿ···ÿ±±±ÿ¨¨¨ÿ›››ÿ‹‹‹ÿxxxÿgggÿ^^^ÿ[[[ÛXXX ¬¬¬#³³³ßÀÀÀÿÃÃÃÿ¾¾¾ÿ½½½ÿ¿¿¿ÿÁÁÁÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÀÀÀÿ¾¾¾ÿ¼¼¼ÿºººÿ¹¹¹ÿ¸¸¸ÿ¸¸¸ÿ¹¹¹ÿ»»»ÿ¾¾¾ÿÁÁÁÿÃÃÃÿÄÄÄÿÁÁÁÿºººÿ¬¬¬ÿ”””ÿrrrÿ[[[ÛWWW ªªª#©©©ß¯¯¯ÿ½½½ÿÃÃÃÿÉÉÉÿÓÓÓÿÙÙÙÿÙÙÙÿÔÔÔÿËËËÿÀÀÀÿ¶¶¶ÿ®®®ÿ©©©ÿ¤¤¤ÿŸŸŸÿ›››ÿ———ÿ“““ÿ‘‘‘ÿÿ‘‘‘ÿ–––ÿŸŸŸÿ«««ÿ¹¹¹ÿÁÁÁÿ½½½ÿ¢¢¢ÿvvvÜTTT „„„!~~~Ü®®®ÿÈÈÈÿÒÒÒÿåååÿòòòÿñññÿèèèÿÝÝÝÿÍÍÍÿÀÀÀÿµµµÿ­­­ÿ¨¨¨ÿ£££ÿžžžÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿ€€€ÿ{{{ÿwwwÿuuuÿyyyÿˆˆˆÿ¦¦¦ÿ¡¡¡ÿttt×___GGG qqq­¯¯¯ÿÌÌÌÿÚÚÚÿìììÿõõõÿóóóÿëëëÿáááÿÍÍÍÿÀÀÀÿµµµÿ­­­ÿ¨¨¨ÿ£££ÿŸŸŸÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿÿ|||ÿxxxÿsssÿmmmÿgggÿgggÿgggÿWWWŸ[[[¬¬¬²²²¹¾¾¾ÿËËËÿÚÚÚÿïïïÿ÷÷÷ÿöööÿïïïÿæææÿÍÍÍÿÀÀÀÿµµµÿ­­­ÿ¨¨¨ÿ£££ÿžžžÿšššÿ•••ÿÿ‹‹‹ÿ†††ÿÿ|||ÿxxxÿsssÿnnnÿiiiÿdddÿ___ÿ[[[²WWW ¬¬¬"³³³Ý¾¾¾ÿËËËÿÛÛÛÿñññÿøøøÿ÷÷÷ÿòòòÿéééÿÔÔÔÿÇÇÇÿ»»»ÿ±±±ÿªªªÿ¤¤¤ÿžžžÿšššÿ–––ÿ‘‘‘ÿŒŒŒÿ†††ÿÿ|||ÿwwwÿrrrÿnnnÿiiiÿdddÿ___ÿ[[[ÛXXX¬¬¬#²²²ß¾¾¾ÿËËËÿÞÞÞÿñññÿòòòÿéééÿÜÜÜÿÐÐÐÿÅÅÅÿ¼¼¼ÿ¶¶¶ÿ²²²ÿ¯¯¯ÿ­­­ÿ«««ÿªªªÿ¨¨¨ÿ¥¥¥ÿ¡¡¡ÿœœœÿ•••ÿŒŒŒÿ‚‚‚ÿxxxÿoooÿhhhÿdddÿ___ÿ[[[ÜXXX ¬¬¬#²²²ÞÀÀÀÿÒÒÒÿØØØÿÐÐÐÿÆÆÆÿ¿¿¿ÿ¼¼¼ÿ¼¼¼ÿ½½½ÿ¿¿¿ÿÀÀÀÿÁÁÁÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÁÁÁÿÀÀÀÿ¾¾¾ÿ»»»ÿ¶¶¶ÿ¯¯¯ÿ£££ÿ“““ÿÿkkkÿ___ÿZZZÜXXX ¬¬¬#³³³Þ¾¾¾ÿ¿¿¿ÿ½½½ÿ¾¾¾ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÂÂÂÿ½½½ÿ²²²ÿœœœÿzzzÿ]]]ÜWWW §§§#¤¤¤ß¯¯¯ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ¦¦¦ÿzzzÜUUU }}}vvvÙ¬¬¬ÿÅÅÅÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÅÅÅÿ¢¢¢ÿnnnÔ___^^^PPPŒvvvü´´´ÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÅÅÅÿÄÄÄÿ­­­ÿllløOOOzfffMMMLLLMMMxeeeÝŒŒŒý¬¬¬ÿ½½½ÿÄÄÄÿÅÅÅÿÅÅÅÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÅÅÅÿÅÅÅÿÃÃÃÿ»»»ÿ¨¨¨ÿ†††ü```ÒLLLeNNN OOOGGGFFFEEE#MMMk\\\±ooo߃ƒƒ÷•••ÿ¤¤¤ÿ®®®ÿµµµÿºººÿ½½½ÿ¾¾¾ÿ¿¿¿ÿ¿¿¿ÿ¾¾¾ÿ¼¼¼ÿ¹¹¹ÿ´´´ÿ­­­ÿ¢¢¢ÿ“““þ€€€ôlllÙYYY¨KKK_EEEKKKHHHJJJ888AAA GGGDNNNkVVV]]]©ddd¾jjjÌoooÕrrrÛsssÞsssÝqqqÚnnnÔiiiÊccc»\\\¥UUU‰MMMeFFF>@@@555>>>111 888<<<>>> >>>">>>"===;;;777/// \\\ÿ€ÿðÀ€€Àøÿ€ÿ(@€ @Ãý½½½½½¼¼¼¸¸¸²²² ®®®¬¬¬©©©§§§¥¥¥¢¢¢   ›››™™™–––”””’’’‹‹‹˜˜˜‡‡‡ÿÿÿçççëëëååå àààÚÚÚ2ÔÔÔJÏÏÏeÉÉÉ|ÃÃÃ’½½½¥¸¸¸´²²²Á®®®Ê¬¬¬ÑªªªØ§§§Ü¥¥¥Þ¢¢¢à   ßÝ›››Ú™™™Õ–––Í”””Æ‘‘‘»­ŒŒŒŠŠŠˆˆˆˆr………[ƒƒƒC,~~~{{{vvvxxxÚÚÚÿÿÿçççïïïôôôCñññoìììœæææ¾áááÛÛÛÛíÕÕÕùÏÏÏþÉÉÉÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿžžžÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ýƒƒƒö€€€é~~~Ô{{{µyyywwwdttt9rrrqqqrrroooÑÑÑÞÞÞÖÖÖ ÜÜÜ3ääärêêê¯ðððÜõõõöòòòþíííÿèèèÿãããÿÞÞÞÿØØØÿÐÐÐÿÉÉÉÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿžžžÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿƒƒƒÿ€€€ÿ~~~ÿ{{{ÿyyyÿwwwýtttñrrrÔooo£mmmfkkk+hhhjjjgggÄÄÄ•••ÉÉÉÏÏÏdÕÕÕ·ÛÛÛìåååþìììÿñññÿöööÿôôôÿïïïÿêêêÿåååÿàààÿÛÛÛÿÐÐÐÿÉÉÉÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿžžžÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿƒƒƒÿ€€€ÿ~~~ÿ{{{ÿyyyÿwwwÿtttÿqqqÿoooÿmmmýjjjæhhh­fff[cccˆˆˆbbb¼¼¼¿¿¿½½½ÂÂÂlÈÈÈÐÎÎÎüÕÕÕÿÜÜÜÿçççÿíííÿòòòÿöööÿõõõÿðððÿìììÿçççÿãããÿÝÝÝÿÑÑÑÿÉÉÉÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿžžžÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿƒƒƒÿ€€€ÿ~~~ÿ{{{ÿyyyÿwwwÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeúcccÊaaae___```[[[³³³ººº¶¶¶,»»»´ÁÁÁûÈÈÈÿÎÎÎÿÕÕÕÿÜÜÜÿéééÿïïïÿóóóÿ÷÷÷ÿöööÿñññÿíííÿéééÿåååÿàààÿÑÑÑÿÉÉÉÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿžžžÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿƒƒƒÿ€€€ÿ~~~ÿ{{{ÿyyyÿwwwÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaú^^^°\\\*^^^[[[²²²°°°&µµµÈ»»»ÿÁÁÁÿÈÈÈÿÎÎÎÿÔÔÔÿÝÝÝÿëëëÿñññÿõõõÿøøøÿöööÿóóóÿïïïÿëëëÿèèèÿâââÿÑÑÑÿÉÉÉÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿžžžÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿƒƒƒÿ€€€ÿ~~~ÿ{{{ÿyyyÿwwwÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿ```ÿ^^^ÿ\\\ÈZZZ'ZZZ¬¬¬¤¤¤¯¯¯”´´´ÿ»»»ÿÁÁÁÿÈÈÈÿÎÎÎÿÔÔÔÿÞÞÞÿíííÿòòòÿöööÿùùùÿ÷÷÷ÿôôôÿñññÿíííÿêêêÿäääÿÑÑÑÿÉÉÉÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿžžžÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿƒƒƒÿ€€€ÿ~~~ÿ{{{ÿyyyÿwwwÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿ```ÿ^^^ÿ\\\ÿZZZšVVVXXX¬¬¬«««¯¯¯Ð´´´ÿ»»»ÿÁÁÁÿÈÈÈÿÎÎÎÿÔÔÔÿßßßÿïïïÿóóóÿöööÿùùùÿøøøÿõõõÿòòòÿïïïÿìììÿæææÿÑÑÑÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿžžžÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿƒƒƒÿ€€€ÿ~~~ÿ{{{ÿyyyÿwwwÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿ```ÿ^^^ÿ\\\ÿZZZ×XXXXXX¬¬¬«««¯¯¯Ú´´´ÿ»»»ÿÁÁÁÿÈÈÈÿÎÎÎÿÔÔÔÿßßßÿïïïÿóóóÿöööÿùùùÿøøøÿõõõÿòòòÿïïïÿíííÿæææÿÓÓÓÿÌÌÌÿÆÆÆÿÀÀÀÿ»»»ÿµµµÿ±±±ÿ®®®ÿ«««ÿ¨¨¨ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ“““ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿƒƒƒÿ€€€ÿ~~~ÿ{{{ÿyyyÿwwwÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿ```ÿ^^^ÿ\\\ÿYYYáXXXXXX¬¬¬«««¯¯¯Ú´´´ÿ»»»ÿÁÁÁÿÈÈÈÿÎÎÎÿÔÔÔÿàààÿðððÿóóóÿöööÿùùùÿøøøÿõõõÿóóóÿðððÿíííÿéééÿãããÿÞÞÞÿÙÙÙÿÓÓÓÿÌÌÌÿÅÅÅÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ¬¬¬ÿ§§§ÿ¢¢¢ÿ¡¡¡ÿ   ÿžžžÿÿ›››ÿ™™™ÿ———ÿ”””ÿ‘‘‘ÿŽŽŽÿŠŠŠÿ‡‡‡ÿƒƒƒÿ€€€ÿ}}}ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿ```ÿ^^^ÿ\\\ÿYYYáXXXXXX¬¬¬«««¯¯¯Ú´´´ÿ»»»ÿÁÁÁÿÈÈÈÿÎÎÎÿÔÔÔÿáááÿðððÿôôôÿ÷÷÷ÿùùùÿõõõÿïïïÿèèèÿáááÿØØØÿÏÏÏÿÆÆÆÿ½½½ÿµµµÿ¯¯¯ÿ«««ÿ¨¨¨ÿ§§§ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ§§§ÿ§§§ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¡¡¡ÿ   ÿžžžÿ›››ÿ˜˜˜ÿ“““ÿÿ†††ÿÿyyyÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿ```ÿ^^^ÿ\\\ÿYYYáXXXXXX¬¬¬«««¯¯¯Ú´´´ÿ»»»ÿÁÁÁÿÈÈÈÿÏÏÏÿÛÛÛÿéééÿîîîÿìììÿæææÿÞÞÞÿÓÓÓÿÈÈÈÿ½½½ÿµµµÿ°°°ÿ®®®ÿ¯¯¯ÿ±±±ÿ´´´ÿ···ÿ¹¹¹ÿ»»»ÿ½½½ÿ¾¾¾ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿÀÀÀÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿ¾¾¾ÿ½½½ÿ¼¼¼ÿ»»»ÿ¹¹¹ÿ···ÿ´´´ÿ±±±ÿ®®®ÿªªªÿ§§§ÿ¤¤¤ÿ¡¡¡ÿÿ˜˜˜ÿÿ„„„ÿxxxÿoooÿjjjÿgggÿeeeÿcccÿaaaÿ^^^ÿ\\\ÿYYYáXXXXXX¬¬¬«««¯¯¯Ú´´´ÿ»»»ÿÁÁÁÿËËËÿÛÛÛÿãããÿÞÞÞÿÔÔÔÿÉÉÉÿ¿¿¿ÿ···ÿ´´´ÿµµµÿ¸¸¸ÿ¼¼¼ÿ¿¿¿ÿÂÂÂÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÁÁÁÿ¿¿¿ÿ¼¼¼ÿ···ÿ²²²ÿ¬¬¬ÿ§§§ÿ£££ÿÿ“““ÿ„„„ÿrrrÿfffÿbbbÿ```ÿ^^^ÿ\\\ÿYYYáXXXXXX¬¬¬«««¯¯¯Ú´´´ÿ»»»ÿÈÈÈÿ×××ÿÔÔÔÿÇÇÇÿ»»»ÿ¶¶¶ÿ¶¶¶ÿ»»»ÿ¿¿¿ÿÂÂÂÿÃÃÃÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÂÂÂÿ¿¿¿ÿ¹¹¹ÿ±±±ÿ©©©ÿ£££ÿœœœÿŒŒŒÿsssÿbbbÿ]]]ÿ\\\ÿYYYáXXXXXX¬¬¬«««¯¯¯ÚµµµÿÃÃÃÿÊÊÊÿ¼¼¼ÿ±±±ÿ³³³ÿºººÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÁÁÁÿÀÀÀÿ¿¿¿ÿ¾¾¾ÿ½½½ÿ¼¼¼ÿ»»»ÿ»»»ÿ»»»ÿºººÿ»»»ÿ¼¼¼ÿ½½½ÿ¾¾¾ÿ¿¿¿ÿÁÁÁÿÂÂÂÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÀÀÀÿ¹¹¹ÿ­­­ÿ¥¥¥ÿžžžÿ‰‰‰ÿhhhÿ[[[ÿYYYáXXXXXX¬¬¬«««®®®Ú´´´ÿ³³³ÿ¨¨¨ÿ¯¯¯ÿ¼¼¼ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÂÂÂÿÃÃÃÿÅÅÅÿÇÇÇÿÉÉÉÿËËËÿËËËÿÉÉÉÿÇÇÇÿÃÃÃÿ¿¿¿ÿ¹¹¹ÿ´´´ÿ°°°ÿ®®®ÿ«««ÿ©©©ÿ¦¦¦ÿ¤¤¤ÿ¡¡¡ÿŸŸŸÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ™™™ÿšššÿœœœÿŸŸŸÿ£££ÿ©©©ÿ°°°ÿ···ÿ½½½ÿÁÁÁÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿºººÿ«««ÿ£££ÿ•••ÿlllÿYYYáXXXXXX¬¬¬­­­©©©Ú£££ÿ¢¢¢ÿ´´´ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÆÆÆÿÍÍÍÿØØØÿßßßÿâââÿâââÿßßßÿÛÛÛÿÖÖÖÿÏÏÏÿÉÉÉÿÃÃÃÿ½½½ÿ···ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ“““ÿ‘‘‘ÿŽŽŽÿŒŒŒÿ‰‰‰ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿƒƒƒÿ‡‡‡ÿŽŽŽÿšššÿ§§§ÿ´´´ÿ¾¾¾ÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÁÁÁÿ¯¯¯ÿ¢¢¢ÿ“““ÿdddáSSSXXX¢¢¢¢¢¢”””ÛŽŽŽÿ¥¥¥ÿÃÃÃÿÃÃÃÿÃÃÃÿÅÅÅÿÌÌÌÿ×××ÿãããÿîîîÿõõõÿóóóÿîîîÿèèèÿãããÿÞÞÞÿØØØÿÏÏÏÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ™™™ÿ–––ÿ“““ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ}}}ÿ{{{ÿxxxÿuuuÿuuuÿxxxÿ‚‚‚ÿ”””ÿªªªÿ¼¼¼ÿÄÄÄÿÄÄÄÿÀÀÀÿœœœÿŽŽŽÿtttáSSSYYY………………tttÙpppÿ¢¢¢ÿÄÄÄÿÄÄÄÿÊÊÊÿÒÒÒÿÜÜÜÿçççÿíííÿòòòÿöööÿôôôÿïïïÿêêêÿåååÿàààÿÛÛÛÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ™™™ÿ–––ÿ“““ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿnnnÿlllÿmmmÿzzzÿ•••ÿ³³³ÿÃÃÃÿ‘‘‘ÿoooÿjjjÚYYYZZZqqqwwwYYY­TTTÿ‡‡‡ÿÃÃÃÿÈÈÈÿÏÏÏÿÕÕÕÿÜÜÜÿèèèÿîîîÿóóóÿ÷÷÷ÿôôôÿðððÿìììÿçççÿãããÿÝÝÝÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ™™™ÿ–––ÿ“““ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿgggÿeeeÿnnnÿ‹‹‹ÿkkkÿTTTÿXXX¦]]]YYYYYYSSSPPPCoooë©©©ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿÝÝÝÿêêêÿðððÿôôôÿ÷÷÷ÿõõõÿñññÿíííÿéééÿæææÿàààÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ™™™ÿ–––ÿ“““ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿbbbÿ```ÿZZZÿRRRàQQQ4QQQRRR²²²¬¬¬¯¯¯@²²²ê¼¼¼ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿÞÞÞÿìììÿñññÿõõõÿøøøÿöööÿóóóÿïïïÿìììÿèèèÿâââÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ™™™ÿ–––ÿ“““ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿ```ÿ^^^ÿ[[[àZZZ4[[[\\\¬¬¬ªªª¯¯¯­µµµÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿßßßÿîîîÿóóóÿöööÿùùùÿ÷÷÷ÿôôôÿñññÿîîîÿëëëÿäääÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ™™™ÿ–––ÿ“““ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿZZZ£XXXYYY¬¬¬¬¬¬¯¯¯Û´´´ÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿàààÿðððÿóóóÿ÷÷÷ÿùùùÿøøøÿõõõÿòòòÿïïïÿìììÿåååÿÐÐÐÿÈÈÈÿÃÃÃÿ½½½ÿ···ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ“““ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYÔXXXXXX¬¬¬¬¬¬¯¯¯áµµµÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿàààÿðððÿóóóÿ÷÷÷ÿùùùÿøøøÿõõõÿòòòÿïïïÿíííÿæææÿÕÕÕÿÏÏÏÿÉÉÉÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ³³³ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ£££ÿ   ÿÿ›››ÿ™™™ÿ–––ÿ“““ÿ‘‘‘ÿŽŽŽÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯áµµµÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿáááÿðððÿóóóÿ÷÷÷ÿùùùÿøøøÿöööÿóóóÿïïïÿìììÿèèèÿâââÿÝÝÝÿ×××ÿÐÐÐÿÉÉÉÿÂÂÂÿ»»»ÿ´´´ÿ¯¯¯ÿªªªÿ¦¦¦ÿ¢¢¢ÿ¡¡¡ÿ   ÿŸŸŸÿžžžÿÿ›››ÿ™™™ÿ———ÿ”””ÿ‘‘‘ÿÿ‰‰‰ÿ………ÿÿ~~~ÿ{{{ÿxxxÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯áµµµÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿãããÿñññÿôôôÿ÷÷÷ÿ÷÷÷ÿòòòÿêêêÿâââÿÙÙÙÿÏÏÏÿÆÆÆÿ½½½ÿ´´´ÿ®®®ÿ«««ÿ¨¨¨ÿ§§§ÿ¨¨¨ÿ¨¨¨ÿ©©©ÿªªªÿªªªÿ«««ÿ«««ÿªªªÿªªªÿ©©©ÿ¨¨¨ÿ§§§ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ¢¢¢ÿ   ÿžžžÿœœœÿ˜˜˜ÿ’’’ÿŒŒŒÿ„„„ÿ|||ÿvvvÿqqqÿnnnÿlllÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯áµµµÿ»»»ÿÂÂÂÿÈÈÈÿÐÐÐÿÞÞÞÿêêêÿëëëÿçççÿßßßÿÕÕÕÿÊÊÊÿ¿¿¿ÿ···ÿ²²²ÿ¯¯¯ÿ°°°ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ¼¼¼ÿ¾¾¾ÿ¿¿¿ÿÀÀÀÿÁÁÁÿÁÁÁÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÁÁÁÿÁÁÁÿÀÀÀÿ¿¿¿ÿ½½½ÿ»»»ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ¯¯¯ÿ«««ÿ§§§ÿ¤¤¤ÿ¡¡¡ÿœœœÿ•••ÿ‹‹‹ÿÿrrrÿjjjÿgggÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯áµµµÿ»»»ÿÂÂÂÿÎÎÎÿÞÞÞÿàààÿØØØÿÍÍÍÿÂÂÂÿ¹¹¹ÿµµµÿµµµÿ¸¸¸ÿ¼¼¼ÿÀÀÀÿÂÂÂÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ···ÿ±±±ÿ«««ÿ¥¥¥ÿ¡¡¡ÿ™™™ÿŒŒŒÿyyyÿiiiÿbbbÿ```ÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯á´´´ÿ¼¼¼ÿÌÌÌÿÖÖÖÿÍÍÍÿ¿¿¿ÿ¶¶¶ÿµµµÿ¹¹¹ÿ¾¾¾ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÁÁÁÿ½½½ÿ¶¶¶ÿ­­­ÿ¦¦¦ÿ   ÿ“““ÿ{{{ÿeeeÿ]]]ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯á¶¶¶ÿÄÄÄÿÃÃÃÿ´´´ÿ¯¯¯ÿ¶¶¶ÿ¾¾¾ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÂÂÂÿÀÀÀÿ½½½ÿ»»»ÿ¹¹¹ÿ···ÿ¶¶¶ÿ´´´ÿ³³³ÿ²²²ÿ±±±ÿ±±±ÿ±±±ÿ±±±ÿ²²²ÿ´´´ÿ¶¶¶ÿ¸¸¸ÿ»»»ÿ¾¾¾ÿÀÀÀÿÂÂÂÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ¼¼¼ÿ²²²ÿ§§§ÿ¡¡¡ÿÿnnnÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬®®®á±±±ÿ­­­ÿ§§§ÿ´´´ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÃÃÃÿÄÄÄÿÇÇÇÿËËËÿÎÎÎÿÑÑÑÿÑÑÑÿÏÏÏÿÌÌÌÿÈÈÈÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¤¤¤ÿ¢¢¢ÿŸŸŸÿÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ’’’ÿ‘‘‘ÿÿÿ‘‘‘ÿ”””ÿ˜˜˜ÿžžžÿ¦¦¦ÿ¯¯¯ÿ···ÿ¾¾¾ÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ¯¯¯ÿ¤¤¤ÿšššÿqqqÿYYYÚXXXXXX¬¬¬­­­§§§á   ÿ£££ÿ¹¹¹ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÆÆÆÿÍÍÍÿÙÙÙÿåååÿêêêÿéééÿæææÿâââÿÜÜÜÿ×××ÿÏÏÏÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ„„„ÿÿÿ~~~ÿ}}}ÿ€€€ÿ†††ÿ’’’ÿ¡¡¡ÿ±±±ÿ½½½ÿÃÃÃÿÄÄÄÿÄÄÄÿÂÂÂÿ²²²ÿ¡¡¡ÿ•••ÿgggÚRRRXXX››››››ŽŽŽá‰‰‰ÿ¨¨¨ÿÄÄÄÿÃÃÃÿÄÄÄÿÉÉÉÿÒÒÒÿßßßÿéééÿñññÿöööÿóóóÿîîîÿéééÿäääÿßßßÿÙÙÙÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿƒƒƒÿ€€€ÿ~~~ÿ{{{ÿxxxÿuuuÿsssÿqqqÿtttÿÿ“““ÿ¬¬¬ÿ¾¾¾ÿÅÅÅÿÁÁÁÿ™™™ÿ‰‰‰ÿsssÚSSSYYY|||{{{nnnÛkkkÿ¡¡¡ÿÄÄÄÿÆÆÆÿÌÌÌÿÔÔÔÿÜÜÜÿçççÿíííÿòòòÿöööÿôôôÿïïïÿêêêÿæææÿáááÿÜÜÜÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿlllÿiiiÿlllÿ}}}ÿŸŸŸÿºººÿ‰‰‰ÿiiiÿfffÎXXXZZZjjjrrrUUU¦TTTÿÿÃÃÃÿÈÈÈÿÏÏÏÿÕÕÕÿÜÜÜÿéééÿîîîÿóóóÿ÷÷÷ÿõõõÿñññÿìììÿèèèÿäääÿÞÞÞÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿgggÿdddÿeeeÿuuuÿbbbÿRRRÿVVVŠpppYYYfff]]]<†††ìµµµÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿÝÝÝÿëëëÿðððÿôôôÿøøøÿöööÿòòòÿîîîÿêêêÿæææÿáááÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿ___ÿ\\\ÿVVVÙSSS$TTT®®®µµµ±±±bµµµ÷¼¼¼ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿÞÞÞÿíííÿòòòÿõõõÿùùùÿ÷÷÷ÿóóóÿðððÿìììÿéééÿãããÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ\\\ñZZZW[[[ZZZ¬¬¬«««¯¯¯Ã´´´ÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿßßßÿïïïÿóóóÿöööÿùùùÿøøøÿõõõÿñññÿîîîÿìììÿåååÿÐÐÐÿÉÉÉÿÃÃÃÿ½½½ÿ¸¸¸ÿ²²²ÿ®®®ÿ¬¬¬ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYY»WWW XXX¬¬¬«««¯¯¯ßµµµÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿàààÿðððÿóóóÿ÷÷÷ÿùùùÿøøøÿõõõÿòòòÿïïïÿíííÿåååÿÐÐÐÿÈÈÈÿÃÃÃÿ½½½ÿ···ÿ²²²ÿ®®®ÿ«««ÿ©©©ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ   ÿÿ›››ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ………ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYØXXXXXX¬¬¬¬¬¬¯¯¯áµµµÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÕÕÕÿàààÿðððÿóóóÿ÷÷÷ÿùùùÿøøøÿõõõÿòòòÿïïïÿíííÿèèèÿÛÛÛÿÕÕÕÿÐÐÐÿËËËÿÅÅÅÿ¿¿¿ÿºººÿµµµÿ°°°ÿ¬¬¬ÿ§§§ÿ£££ÿ   ÿžžžÿœœœÿšššÿ———ÿ•••ÿ’’’ÿÿŒŒŒÿŠŠŠÿ‡‡‡ÿ„„„ÿ‚‚‚ÿ€€€ÿ~~~ÿ{{{ÿyyyÿvvvÿtttÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯àµµµÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÔÔÔÿáááÿðððÿóóóÿ÷÷÷ÿúúúÿøøøÿõõõÿñññÿíííÿèèèÿâââÿÜÜÜÿÕÕÕÿÍÍÍÿÆÆÆÿ¾¾¾ÿ···ÿ²²²ÿ­­­ÿ©©©ÿ¦¦¦ÿ¤¤¤ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ   ÿ   ÿŸŸŸÿÿœœœÿšššÿ———ÿ”””ÿÿ‹‹‹ÿ†††ÿÿ|||ÿxxxÿvvvÿsssÿqqqÿoooÿmmmÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯àµµµÿ»»»ÿÂÂÂÿÈÈÈÿÎÎÎÿÖÖÖÿåååÿñññÿóóóÿóóóÿðððÿèèèÿÞÞÞÿÕÕÕÿÊÊÊÿÀÀÀÿ···ÿ±±±ÿ¬¬¬ÿªªªÿªªªÿ«««ÿ­­­ÿ¯¯¯ÿ°°°ÿ±±±ÿ²²²ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ²²²ÿ±±±ÿ°°°ÿ¯¯¯ÿ­­­ÿ«««ÿ©©©ÿ§§§ÿ¥¥¥ÿ£££ÿ¡¡¡ÿžžžÿ›››ÿ–––ÿŽŽŽÿ………ÿ|||ÿtttÿoooÿlllÿjjjÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯àµµµÿ»»»ÿÁÁÁÿÈÈÈÿÔÔÔÿãããÿèèèÿäääÿÝÝÝÿÓÓÓÿÇÇÇÿ½½½ÿ¶¶¶ÿ²²²ÿ²²²ÿ´´´ÿ¸¸¸ÿ»»»ÿ¾¾¾ÿÀÀÀÿÁÁÁÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÁÁÁÿÀÀÀÿ¾¾¾ÿ»»»ÿ···ÿ³³³ÿ¯¯¯ÿªªªÿ¦¦¦ÿ¢¢¢ÿžžžÿ———ÿŒŒŒÿ}}}ÿpppÿhhhÿeeeÿcccÿaaaÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯àµµµÿ»»»ÿÃÃÃÿÓÓÓÿÝÝÝÿØØØÿÍÍÍÿÁÁÁÿ¹¹¹ÿ¶¶¶ÿ···ÿ»»»ÿ¾¾¾ÿÁÁÁÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÃÃÃÿÁÁÁÿ¾¾¾ÿ¹¹¹ÿ²²²ÿ«««ÿ¦¦¦ÿ¡¡¡ÿ˜˜˜ÿˆˆˆÿsssÿdddÿ```ÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯à´´´ÿ¿¿¿ÿÏÏÏÿÏÏÏÿÁÁÁÿ¶¶¶ÿ´´´ÿ¹¹¹ÿ¾¾¾ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÂÂÂÿ½½½ÿµµµÿ«««ÿ¤¤¤ÿÿ‹‹‹ÿoooÿ^^^ÿ[[[ÿYYYÚXXXXXX¬¬¬¬¬¬¯¯¯à···ÿÁÁÁÿ···ÿ­­­ÿ²²²ÿ¼¼¼ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿºººÿ­­­ÿ¤¤¤ÿ›››ÿ|||ÿ^^^ÿYYYÚXXXXXX¬¬¬¬¬¬­­­à¬¬¬ÿ¦¦¦ÿªªªÿ»»»ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ···ÿ¦¦¦ÿ¡¡¡ÿÿ[[[ÚWWWXXXªªª«««¡¡¡ášššÿ¥¥¥ÿ¿¿¿ÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¸¸¸ÿŸŸŸÿ–––ÿmmmÚPPPXXXƒƒƒá€€€ÿ¨¨¨ÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ–––ÿÿqqqÙUUUZZZvvvvvveeeÒaaaÿ™™™ÿÅÅÅÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿÿ```ÿ```ÂYYYYYYbbbéééRRR…NNNÿfffÿ±±±ÿÅÅÅÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿœœœÿVVVÿOOOøSSSgJJJXXXQQQRRROOO²MMMÿhhhÿ¥¥¥ÿÂÂÂÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÅÅÅÿ¾¾¾ÿ“““ÿYYYÿMMMøPPP‹UUU SSSWWWMMMOOONNN—MMMóWWWÿÿªªªÿÀÀÀÿÅÅÅÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿ¼¼¼ÿžžžÿpppÿQQQÿMMMâOOOmRRR QQQNNNNNNNNNOMMM·MMMôWWWÿsssÿ———ÿ±±±ÿÀÀÀÿÄÄÄÿÅÅÅÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÅÅÅÿÄÄÄÿ½½½ÿ«««ÿŒŒŒÿiiiÿRRRÿLLLèNNN™NNN1RRRPPPPPPMMMNNN NNNHMMMœLLLÝOOOú[[[ÿpppÿŠŠŠÿ¢¢¢ÿ³³³ÿ½½½ÿÂÂÂÿÄÄÄÿÅÅÅÿÅÅÅÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÅÅÅÿÅÅÅÿÄÄÄÿÁÁÁÿºººÿ®®®ÿ›››ÿ‚‚‚ÿiiiÿVVVÿMMMõLLLÍMMMƒNNN2NNNNNNMMMNNNNNN!NNNXMMM˜LLLÌMMMíRRRý[[[ÿiiiÿxxxÿ‰‰‰ÿ˜˜˜ÿ¥¥¥ÿ¯¯¯ÿ¶¶¶ÿ»»»ÿ¾¾¾ÿÁÁÁÿÂÂÂÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÂÂÂÿÀÀÀÿ½½½ÿºººÿ´´´ÿ¬¬¬ÿ¢¢¢ÿ”””ÿ………ÿtttÿdddÿWWWÿPPPùLLLåLLL½MMM…NNNENNNLLLMMMNNNNNNNNNNNN3MMM]LLL‹LLL²LLLÑMMMæOOOôSSSýXXXÿ^^^ÿeeeÿkkkÿqqqÿxxxÿ|||ÿÿƒƒƒÿ………ÿ†††ÿ†††ÿ„„„ÿƒƒƒÿÿ{{{ÿvvvÿoooÿiiiÿcccÿ[[[ÿVVVÿQQQûNNNòLLLâLLLÈLLL¦MMM}NNNONNN(NNN NNNNNNNNNMMMNNNNNNNNN'NNN@MMM[MMMtLLL‹LLL KKK°KKK¾LLLÈLLLÏLLL×LLLÛLLLÞLLLàLLLßLLLÝLLLÚLLLÕLLLÍLLLÅKKKºLLL«LLLšLLL„MMMlMMMSNNN:NNN#NNNNNNQQQKKKMMMLLLNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMNNNÿÿÿÿÿÿÿÿÿÿüÿÿÿþÿÿàÿÿÿø?ðàÀ€€€€€€€€€€€€€€ÀÀ€€€€€€€€€€€€€€ÀÀ€€€€€€€€€€€€€€Ààðü?ÿÿÿàÿÿþÿÿÿÿüÿÿÿÿÿÿÿÿÿÿ(€ Ãö¶¶···²²²¯¯¯ ­­­ ­­­«««ªªª©©©¨¨¨§§§¥¥¥¤¤¤£££¢¢¢¡¡¡ŸŸŸ››››››™™™™™™———––– ••• ’’’’’’²²²;;;ÓÓÓÓÓÓÑÑÑÍÍÍÊÊÊÇÇÇ ÅÅÅ3ÂÂÂG¿¿¿X¼¼¼f¹¹¹u¶¶¶ƒ´´´’±±±ž¯¯¯¨®®®±­­­¹«««ÂªªªÊ©©©Ò¨¨¨Ö§§§×¥¥¥Ü¤¤¤Ý£££á¢¢¢ã¡¡¡áŸŸŸÝžžžÜלœœÖšššÒ™™™Ê˜˜˜Â———º–––±”””©“““Ÿ’’’’‘‘‘„vŽŽŽhZ‹‹‹J‹‹‹6ŠŠŠ"ˆˆˆ‡‡‡‡‡‡ ˆˆˆ‡‡‡äääæææäääâââßßß!ÜÜÜ=ÙÙÙXÖÖÖsÓÓÓÐÐШÍÍ;ÊÊÊÒÈÈÈãÅÅÅëÂÂÂò¿¿¿÷¼¼¼ü¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ–––ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽü÷ŒŒŒò‹‹‹ì‰‰‰åˆˆˆÕ‡‡‡Á†††­………”ƒƒƒ}‚‚‚eJ€€€/}}} {{{|||óóóñññóóó ðððííí?êêêbççç‚äää£áááÇßßßâÜÜÜîÙÙÙ÷ÖÖÖþÓÓÓÿÐÐÐÿÎÎÎÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ûó€€€éÔ}}}³|||‘zzzmyyyKxxx(wwwvvvttt{{{êêêèèèíííððð1ôôô]õõõ†óóó¯ðððØíííïêêêúèèèÿåååÿâââÿßßßÿÝÝÝÿÚÚÚÿ×××ÿÔÔÔÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ýyyyóxxxæwwwÈvvvœuuuptttDrrrrrr tttsssÙÙÙÂÂÂààà äää(çççZéééŽíííÂðððéóóóùöööÿóóóÿñññÿîîîÿëëëÿéééÿçççÿäääÿáááÿÞÞÞÿÜÜÜÿÙÙÙÿÖÖÖÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿzzzÿxxxÿwwwÿvvvÿuuuýsssñrrrÛqqq®pppvnnnBnnnmmmmmmÓÓÓÇÇÇ××× ÚÚÚ.ÝÝÝkáááªåååáèèèøëëëÿïïïÿòòòÿôôôÿöööÿôôôÿòòòÿïïïÿìììÿêêêÿçççÿåååÿâââÿßßßÿÝÝÝÿÚÚÚÿ×××ÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppýnnnðnnnÑlll•kkkWjjjiiiiiiÏÏÏÏÏÏÑÑÑÓÓÓ_ÖÖÖ°ÚÚÚæÝÝÝûãããÿçççÿêêêÿíííÿðððÿòòòÿõõõÿ÷÷÷ÿõõõÿòòòÿðððÿíííÿëëëÿèèèÿæææÿãããÿáááÿÞÞÞÿÜÜÜÿÙÙÙÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿoooÿmmmÿlllÿkkk÷jjjØhhh—gggLgggccceeeÉÉÉÉÉÉÊÊÊ4ÍÍ͈ÐÐÐÒÓÓÓøÖÖÖÿÙÙÙÿÝÝÝÿäääÿèèèÿëëëÿíííÿðððÿóóóÿõõõÿ÷÷÷ÿõõõÿóóóÿðððÿîîîÿëëëÿéééÿæææÿäääÿâââÿàààÿÝÝÝÿÚÚÚÿÓÓÓÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggófffÆddduccc%ccccccÂÂÂÁÁÁÃÃÃ4ÆÆÆ“ÊÊÊäÌÌÌþÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿÝÝÝÿåååÿéééÿìììÿîîîÿñññÿóóóÿöööÿ÷÷÷ÿõõõÿóóóÿñññÿîîîÿìììÿêêêÿèèèÿåååÿãããÿáááÿÞÞÞÿÛÛÛÿÓÓÓÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿiiiÿgggÿfffÿeeeüdddÙbbb…```+``````½½½ÿÿÿ¾¾¾!ÀÀÀˆÃÃÃ䯯ÆþÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿÝÝÝÿæææÿêêêÿíííÿïïïÿñññÿôôôÿöööÿøøøÿöööÿôôôÿñññÿïïïÿíííÿëëëÿéééÿçççÿäääÿâââÿàààÿÝÝÝÿÓÓÓÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbþaaaÜ```y___``````¹¹¹¸¸¸ºººM½½½ÈÀÀÀýÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿÝÝÝÿçççÿëëëÿîîîÿðððÿòòòÿôôôÿ÷÷÷ÿøøøÿöööÿôôôÿòòòÿðððÿîîîÿìììÿêêêÿèèèÿæææÿäääÿáááÿÞÞÞÿÓÓÓÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```û___À^^^EZZZ\\\µµµ³³³ ···p¹¹¹ê¼¼¼ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿÞÞÞÿéééÿìììÿîîîÿðððÿóóóÿõõõÿ÷÷÷ÿøøøÿ÷÷÷ÿõõõÿóóóÿñññÿïïïÿíííÿëëëÿéééÿçççÿåååÿãããÿàààÿÓÓÓÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ^^^å]]]kZZZ[[[²²²±±±´´´y¶¶¶ó¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿÞÞÞÿêêêÿíííÿïïïÿñññÿóóóÿõõõÿ÷÷÷ÿùùùÿ÷÷÷ÿõõõÿóóóÿñññÿðððÿîîîÿìììÿêêêÿèèèÿæææÿäääÿáááÿÓÓÓÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ò[[[xYYYZZZ®®®iii°°°_³³³ð¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿßßßÿëëëÿîîîÿðððÿòòòÿôôôÿöööÿøøøÿùùùÿ÷÷÷ÿöööÿôôôÿòòòÿðððÿïïïÿíííÿëëëÿéééÿçççÿæææÿâââÿÓÓÓÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ñZZZdZZZZZZ®®®­­­&°°°Ô³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿàààÿìììÿïïïÿñññÿóóóÿõõõÿöööÿøøøÿùùùÿøøøÿöööÿõõõÿóóóÿñññÿðððÿîîîÿìììÿëëëÿéééÿçççÿãããÿÓÓÓÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÙYYY-YYY«««µµµ­­­v¯¯¯þ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿáááÿîîîÿðððÿòòòÿóóóÿõõõÿ÷÷÷ÿùùùÿúúúÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿðððÿïïïÿíííÿìììÿêêêÿéééÿäääÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYƒIIIWWW«««««« ­­­²¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿâââÿïïïÿñññÿòòòÿôôôÿõõõÿ÷÷÷ÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿêêêÿåååÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÁXXXXXX¬¬¬«««­­­Í¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿãããÿïïïÿñññÿóóóÿôôôÿõõõÿ÷÷÷ÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿòòòÿðððÿïïïÿíííÿìììÿëëëÿåååÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ···ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÝXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿäääÿïïïÿñññÿóóóÿôôôÿõõõÿ÷÷÷ÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿëëëÿäääÿÒÒÒÿÍÍÍÿÊÊÊÿÇÇÇÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿäääÿðððÿñññÿóóóÿôôôÿõõõÿ÷÷÷ÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿëëëÿäääÿÔÔÔÿÐÐÐÿÍÍÍÿÊÊÊÿÇÇÇÿÄÄÄÿÁÁÁÿ¾¾¾ÿ»»»ÿ¸¸¸ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ§§§ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿœœœÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÙÙÙÿåååÿðððÿñññÿóóóÿôôôÿõõõÿ÷÷÷ÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿêêêÿèèèÿäääÿâââÿàààÿÝÝÝÿÛÛÛÿÙÙÙÿÖÖÖÿÔÔÔÿÑÑÑÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÄÄÄÿÂÂÂÿ¾¾¾ÿ»»»ÿ¸¸¸ÿ´´´ÿ±±±ÿ®®®ÿ©©©ÿ¥¥¥ÿ¢¢¢ÿ¡¡¡ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ‘‘‘ÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿ€€€ÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿæææÿðððÿñññÿóóóÿôôôÿõõõÿ÷÷÷ÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿòòòÿðððÿïïïÿíííÿìììÿëëëÿéééÿçççÿåååÿãããÿáááÿßßßÿÜÜÜÿÚÚÚÿ×××ÿÔÔÔÿÑÑÑÿÌÌÌÿÇÇÇÿÂÂÂÿ½½½ÿ¹¹¹ÿµµµÿ±±±ÿ®®®ÿªªªÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ   ÿ   ÿŸŸŸÿŸŸŸÿžžžÿÿ›››ÿ™™™ÿ˜˜˜ÿ–––ÿ”””ÿ‘‘‘ÿŽŽŽÿ‹‹‹ÿ‰‰‰ÿ‡‡‡ÿ………ÿƒƒƒÿÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿzzzÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿçççÿðððÿñññÿóóóÿôôôÿõõõÿ÷÷÷ÿùùùÿúúúÿùùùÿøøøÿöööÿõõõÿôôôÿñññÿîîîÿëëëÿæææÿãããÿßßßÿÜÜÜÿÙÙÙÿÔÔÔÿÐÐÐÿÌÌÌÿÆÆÆÿ¿¿¿ÿ¹¹¹ÿ´´´ÿ¯¯¯ÿ©©©ÿ¦¦¦ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ   ÿŸŸŸÿÿšššÿ———ÿ“““ÿÿŠŠŠÿ†††ÿ‚‚‚ÿÿ|||ÿzzzÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿèèèÿðððÿñññÿóóóÿôôôÿöööÿøøøÿùùùÿúúúÿøøøÿôôôÿïïïÿèèèÿãããÿÞÞÞÿÙÙÙÿÕÕÕÿÑÑÑÿÎÎÎÿÉÉÉÿÂÂÂÿ»»»ÿ³³³ÿ­­­ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¢¢¢ÿ£££ÿ£££ÿ¤¤¤ÿ¤¤¤ÿ¥¥¥ÿ¥¥¥ÿ¥¥¥ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ§§§ÿ§§§ÿ¨¨¨ÿ§§§ÿ§§§ÿ§§§ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¥¥¥ÿ¥¥¥ÿ¤¤¤ÿ¤¤¤ÿ¤¤¤ÿ£££ÿ£££ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ   ÿŸŸŸÿœœœÿ———ÿ‘‘‘ÿ‹‹‹ÿ„„„ÿ~~~ÿyyyÿvvvÿtttÿsssÿrrrÿqqqÿpppÿoooÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÓÓÓÿ×××ÿàààÿëëëÿðððÿñññÿóóóÿôôôÿôôôÿóóóÿíííÿæææÿßßßÿØØØÿÔÔÔÿÒÒÒÿÎÎÎÿÊÊÊÿÄÄÄÿ¼¼¼ÿ´´´ÿ¬¬¬ÿ¦¦¦ÿ¤¤¤ÿ¢¢¢ÿ£££ÿ¤¤¤ÿ¥¥¥ÿ¨¨¨ÿ«««ÿ­­­ÿ°°°ÿ²²²ÿ³³³ÿ¶¶¶ÿ···ÿ¹¹¹ÿºººÿ»»»ÿ½½½ÿ¾¾¾ÿ¿¿¿ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¿¿¿ÿ¾¾¾ÿ½½½ÿ¼¼¼ÿ»»»ÿºººÿ¸¸¸ÿ···ÿµµµÿ³³³ÿ±±±ÿ¯¯¯ÿ¬¬¬ÿªªªÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¢¢¢ÿ   ÿÿ–––ÿŽŽŽÿ†††ÿ}}}ÿuuuÿqqqÿoooÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÊÊÊÿÌÌÌÿÐÐÐÿÙÙÙÿäääÿëëëÿîîîÿïïïÿîîîÿêêêÿäääÿÝÝÝÿÖÖÖÿÓÓÓÿÑÑÑÿÎÎÎÿÊÊÊÿÂÂÂÿ¹¹¹ÿ°°°ÿ©©©ÿ¦¦¦ÿ¥¥¥ÿ¦¦¦ÿªªªÿ®®®ÿ²²²ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÀÀÀÿÁÁÁÿÂÂÂÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÂÂÂÿÂÂÂÿÁÁÁÿÀÀÀÿ¾¾¾ÿ»»»ÿ¸¸¸ÿ´´´ÿ°°°ÿ­­­ÿ©©©ÿ¦¦¦ÿ¤¤¤ÿ¢¢¢ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¡¡¡ÿžžžÿ———ÿÿ‚‚‚ÿwwwÿoooÿkkkÿjjjÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÆÆÆÿÉÉÉÿÐÐÐÿÝÝÝÿçççÿëëëÿéééÿåååÿÞÞÞÿ×××ÿÓÓÓÿÑÑÑÿÏÏÏÿËËËÿÄÄÄÿºººÿ±±±ÿªªªÿ§§§ÿ©©©ÿ®®®ÿ²²²ÿ···ÿ¼¼¼ÿ¿¿¿ÿÁÁÁÿÂÂÂÿÃÃÃÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÂÂÂÿÁÁÁÿ¿¿¿ÿ»»»ÿ¶¶¶ÿ±±±ÿ¬¬¬ÿ§§§ÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¡¡¡ÿœœœÿ‘‘‘ÿƒƒƒÿuuuÿlllÿhhhÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÃÃÃÿÇÇÇÿÑÑÑÿàààÿæææÿãããÿÜÜÜÿÖÖÖÿÒÒÒÿÐÐÐÿÎÎÎÿÉÉÉÿ¿¿¿ÿµµµÿ¬¬¬ÿ©©©ÿ¬¬¬ÿ²²²ÿ···ÿ½½½ÿÁÁÁÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÂÂÂÿ¿¿¿ÿ»»»ÿµµµÿ°°°ÿ©©©ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¢¢¢ÿÿÿÿoooÿfffÿdddÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿ¿¿¿ÿÅÅÅÿÔÔÔÿàààÿÞÞÞÿ×××ÿÒÒÒÿÐÐÐÿÍÍÍÿÆÆÆÿ»»»ÿ°°°ÿªªªÿ«««ÿ±±±ÿ¸¸¸ÿ¾¾¾ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÀÀÀÿ¼¼¼ÿµµµÿ®®®ÿ§§§ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¡¡¡ÿ™™™ÿ‡‡‡ÿqqqÿeeeÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ¼¼¼ÿÄÄÄÿÕÕÕÿÚÚÚÿÖÖÖÿÑÑÑÿÍÍÍÿÆÆÆÿºººÿ®®®ÿ¨¨¨ÿ«««ÿ³³³ÿ»»»ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ¿¿¿ÿ¸¸¸ÿ°°°ÿ§§§ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¢¢¢ÿœœœÿ‰‰‰ÿqqqÿbbbÿ___ÿ___ÿ^^^ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿÃÃÃÿÓÓÓÿÕÕÕÿÏÏÏÿÈÈÈÿ¼¼¼ÿ®®®ÿ¦¦¦ÿ¨¨¨ÿ°°°ÿºººÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ···ÿ¬¬¬ÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿœœœÿ†††ÿjjjÿ^^^ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ¶¶¶ÿÁÁÁÿÏÏÏÿÍÍÍÿÁÁÁÿ²²²ÿ§§§ÿ£££ÿ¨¨¨ÿ´´´ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÂÂÂÿÁÁÁÿÁÁÁÿÀÀÀÿ¿¿¿ÿ¾¾¾ÿ½½½ÿ»»»ÿºººÿºººÿ¹¹¹ÿ¸¸¸ÿ···ÿ···ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿµµµÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¸¸¸ÿ¹¹¹ÿºººÿ»»»ÿ½½½ÿ¾¾¾ÿ¿¿¿ÿÀÀÀÿÁÁÁÿÂÂÂÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ»»»ÿ¯¯¯ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ———ÿwwwÿ___ÿ\\\ÿ[[[ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ³³³ÿ½½½ÿÆÆÆÿ»»»ÿ«««ÿ¤¤¤ÿ¡¡¡ÿ¨¨¨ÿµµµÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÅÅÅÿÅÅÅÿÆÆÆÿÆÆÆÿÅÅÅÿÄÄÄÿÂÂÂÿÀÀÀÿ¾¾¾ÿ»»»ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ­­­ÿ«««ÿªªªÿ¨¨¨ÿ§§§ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ¢¢¢ÿ¡¡¡ÿ   ÿŸŸŸÿžžžÿÿœœœÿ›››ÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ˜˜˜ÿ™™™ÿ›››ÿÿŸŸŸÿ¡¡¡ÿ£££ÿ§§§ÿ«««ÿ¯¯¯ÿ´´´ÿ¸¸¸ÿ½½½ÿ¿¿¿ÿÁÁÁÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ¼¼¼ÿ®®®ÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ£££ÿŸŸŸÿ‚‚‚ÿaaaÿZZZÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò¯¯¯ÿ²²²ÿ³³³ÿ©©©ÿ¢¢¢ÿ¡¡¡ÿ£££ÿ°°°ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÃÃÃÿÄÄÄÿÆÆÆÿÉÉÉÿÌÌÌÿÏÏÏÿÐÐÐÿÑÑÑÿÑÑÑÿÐÐÐÿÏÏÏÿÌÌÌÿÊÊÊÿÇÇÇÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ°°°ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ‘‘‘ÿÿÿÿŒŒŒÿ‹‹‹ÿŠŠŠÿŠŠŠÿŠŠŠÿŠŠŠÿ‹‹‹ÿÿ’’’ÿ˜˜˜ÿŸŸŸÿ¥¥¥ÿ­­­ÿ¶¶¶ÿ¼¼¼ÿ¿¿¿ÿÂÂÂÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ¸¸¸ÿ©©©ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ‡‡‡ÿ```ÿZZZÿYYYãXXXXXX¬¬¬«««­­­Ò­­­ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¥¥¥ÿ¶¶¶ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÃÃÃÿÅÅÅÿÈÈÈÿÍÍÍÿÓÓÓÿÙÙÙÿÝÝÝÿàààÿáááÿàààÿÞÞÞÿÜÜÜÿÙÙÙÿ×××ÿÔÔÔÿÐÐÐÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿ‚‚‚ÿÿ€€€ÿ€€€ÿÿƒƒƒÿ‡‡‡ÿÿ˜˜˜ÿ£££ÿ¯¯¯ÿºººÿ¿¿¿ÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ­­­ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ‚‚‚ÿ\\\ÿXXXãXXXXXX¬¬¬¬¬¬¬¬¬Ò¥¥¥ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¤¤¤ÿ···ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÇÇÇÿÎÎÎÿÙÙÙÿãããÿíííÿïïïÿïïïÿîîîÿëëëÿèèèÿåååÿãããÿàààÿÝÝÝÿÚÚÚÿØØØÿÕÕÕÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ{{{ÿzzzÿxxxÿxxxÿ{{{ÿ€€€ÿ‹‹‹ÿ———ÿ¥¥¥ÿµµµÿ¾¾¾ÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ­­­ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿÿqqqÿXXXãXXXXXX¬¬¬¯¯¯£££Ò———ÿ–––ÿ–––ÿ———ÿ®®®ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÅÅÅÿÉÉÉÿÒÒÒÿÛÛÛÿäääÿëëëÿñññÿõõõÿöööÿôôôÿñññÿîîîÿìììÿéééÿæææÿäääÿáááÿÞÞÞÿÜÜÜÿÙÙÙÿÖÖÖÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿuuuÿsssÿrrrÿtttÿzzzÿ………ÿ•••ÿ©©©ÿ¹¹¹ÿÁÁÁÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ½½½ÿŸŸŸÿ–––ÿ–––ÿ———ÿ„„„ÿ\\\ãUUUXXX¢¢¢¨¨¨’’’Ö‡‡‡ÿ‡‡‡ÿ†††ÿ‘‘‘ÿ»»»ÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÈÈÈÿÎÎÎÿÖÖÖÿàààÿæææÿêêêÿíííÿïïïÿòòòÿõõõÿöööÿôôôÿñññÿïïïÿíííÿêêêÿçççÿåååÿâââÿàààÿÝÝÝÿÛÛÛÿØØØÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿpppÿoooÿnnnÿqqqÿzzzÿÿ¤¤¤ÿ¸¸¸ÿÂÂÂÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¨¨¨ÿ‡‡‡ÿ‡‡‡ÿ‡‡‡ÿƒƒƒÿcccãTTTXXXŽŽŽ’’’ÚxxxÿxxxÿwwwÿÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÈÈÈÿÎÎÎÿÕÕÕÿÚÚÚÿÞÞÞÿäääÿèèèÿêêêÿíííÿðððÿòòòÿõõõÿ÷÷÷ÿôôôÿòòòÿïïïÿíííÿëëëÿèèèÿæææÿãããÿáááÿÞÞÞÿÜÜÜÿÙÙÙÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿkkkÿiiiÿlllÿwwwÿÿªªªÿ¾¾¾ÿÄÄÄÿÄÄÄÿÃÃÃÿÄÄÄÿ¯¯¯ÿ|||ÿxxxÿxxxÿwwwÿdddàTTTXXX‚‚‚ˆˆˆrrrÎiiiÿiiiÿhhhÿ„„„ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÄÄÄÿÆÆÆÿËËËÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿÝÝÝÿåååÿéééÿëëëÿîîîÿñññÿóóóÿöööÿ÷÷÷ÿõõõÿòòòÿðððÿîîîÿìììÿéééÿçççÿåååÿâââÿàààÿÝÝÝÿÚÚÚÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿfffÿlllÿ€€€ÿ   ÿ»»»ÿÄÄÄÿÅÅÅÿªªªÿnnnÿiiiÿiiiÿhhhÿ___ËUUUXXX~~~¢¢¢bbbœZZZÿZZZÿYYYÿgggÿ±±±ÿÄÄÄÿÃÃÃÿÆÆÆÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿÞÞÞÿæææÿêêêÿìììÿïïïÿñññÿôôôÿöööÿ÷÷÷ÿõõõÿóóóÿñññÿïïïÿìììÿêêêÿèèèÿæææÿãããÿáááÿßßßÿÜÜÜÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿcccÿfffÿyyyÿžžžÿ¼¼¼ÿŽŽŽÿZZZÿZZZÿZZZÿZZZÿZZZ–UUUXXXWWWZZZQQQQôOOOÿNNNÿUUUÿšššÿÂÂÂÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿÞÞÞÿçççÿëëëÿíííÿïïïÿòòòÿôôôÿ÷÷÷ÿøøøÿöööÿóóóÿñññÿïïïÿíííÿëëëÿéééÿçççÿåååÿâââÿáááÿÝÝÝÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿaaaÿdddÿxxxÿbbbÿOOOÿOOOÿOOOÿRRRéWWW@UUUŒŒŒXXX[[[ RRR§MMMÿ[[[ÿÿ¸¸¸ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿÞÞÞÿèèèÿìììÿîîîÿðððÿóóóÿõõõÿ÷÷÷ÿøøøÿöööÿôôôÿòòòÿðððÿîîîÿìììÿêêêÿèèèÿæææÿäääÿâââÿÞÞÞÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ___ÿ]]]ÿUUUÿOOOÿOOOüSSS†^^^XXXRRRNNN+dddÑšššÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿßßßÿêêêÿíííÿïïïÿñññÿóóóÿõõõÿøøøÿøøøÿ÷÷÷ÿõõõÿóóóÿñññÿïïïÿíííÿëëëÿéééÿçççÿåååÿãããÿàààÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿWWWÿSSS­VVVUUU¯¯¯±±±$®®®Ê¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿàààÿëëëÿîîîÿðððÿòòòÿôôôÿõõõÿøøøÿùùùÿ÷÷÷ÿõõõÿóóóÿòòòÿðððÿîîîÿìììÿêêêÿèèèÿæææÿåååÿáááÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[­[[[[[[¯¯¯®®® ±±±Ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿáááÿìììÿïïïÿðððÿòòòÿôôôÿöööÿøøøÿùùùÿøøøÿöööÿôôôÿòòòÿñññÿïïïÿíííÿëëëÿéééÿèèèÿæææÿâââÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[üZZZ†XXXYYY¨¨¨¯¯¯­­­Q°°°ò³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿâââÿíííÿðððÿñññÿóóóÿõõõÿ÷÷÷ÿùùùÿùùùÿøøøÿöööÿõõõÿóóóÿñññÿðððÿîîîÿìììÿëëëÿéééÿèèèÿâââÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZèYYY=YYY¬¬¬ªªª­­­¢°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿãããÿîîîÿñññÿòòòÿôôôÿõõõÿ÷÷÷ÿùùùÿúúúÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿêêêÿéééÿãããÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYY[[[YYY¬¬¬¬¬¬­­­Ñ°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿäääÿïïïÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿêêêÿãããÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYY¾XXXXXX¬¬¬¬¬¬­­­á°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÚÚÚÿäääÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿïïïÿíííÿìììÿëëëÿãããÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÐXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿåååÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿëëëÿâââÿÑÑÑÿÍÍÍÿÊÊÊÿÇÇÇÿÄÄÄÿÁÁÁÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ°°°ÿ¯¯¯ÿ­­­ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ§§§ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿæææÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿëëëÿäääÿÙÙÙÿÕÕÕÿÓÓÓÿÐÐÐÿÍÍÍÿÊÊÊÿÆÆÆÿÃÃÃÿÀÀÀÿ¼¼¼ÿ¸¸¸ÿµµµÿ³³³ÿ²²²ÿ°°°ÿ¯¯¯ÿ­­­ÿ¬¬¬ÿªªªÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ“““ÿ‘‘‘ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿçççÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿëëëÿéééÿçççÿåååÿäääÿâââÿàààÿÞÞÞÿÜÜÜÿÚÚÚÿØØØÿ×××ÿÕÕÕÿÒÒÒÿÎÎÎÿËËËÿÇÇÇÿÄÄÄÿ¿¿¿ÿºººÿµµµÿ°°°ÿ¬¬¬ÿ¨¨¨ÿ¤¤¤ÿ¢¢¢ÿ¡¡¡ÿ   ÿ   ÿŸŸŸÿžžžÿžžžÿœœœÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ”””ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿèèèÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿòòòÿðððÿïïïÿíííÿëëëÿéééÿæææÿãããÿàààÿÞÞÞÿÛÛÛÿÙÙÙÿÕÕÕÿÑÑÑÿÍÍÍÿÇÇÇÿÁÁÁÿ¼¼¼ÿ···ÿ³³³ÿ®®®ÿªªªÿ§§§ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ   ÿŸŸŸÿÿœœœÿšššÿ———ÿ•••ÿ’’’ÿÿŒŒŒÿˆˆˆÿ………ÿƒƒƒÿÿÿ~~~ÿ}}}ÿ|||ÿzzzÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÛÛÛÿèèèÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿøøøÿöööÿóóóÿðððÿíííÿçççÿâââÿÞÞÞÿÛÛÛÿØØØÿÓÓÓÿÏÏÏÿËËËÿÄÄÄÿ½½½ÿ···ÿ±±±ÿ«««ÿ§§§ÿ¥¥¥ÿ£££ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ   ÿžžžÿ›››ÿ———ÿ“““ÿÿŠŠŠÿ„„„ÿÿ|||ÿyyyÿwwwÿwwwÿuuuÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÛÛÛÿêêêÿðððÿñññÿóóóÿõõõÿöööÿøøøÿùùùÿ÷÷÷ÿòòòÿëëëÿãããÿÝÝÝÿØØØÿÔÔÔÿÒÒÒÿÎÎÎÿÉÉÉÿÂÂÂÿ»»»ÿµµµÿ®®®ÿ§§§ÿ¤¤¤ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¢¢¢ÿ£££ÿ¤¤¤ÿ¥¥¥ÿ¦¦¦ÿ§§§ÿ©©©ÿªªªÿ«««ÿ¬¬¬ÿ®®®ÿ¯¯¯ÿ¯¯¯ÿ°°°ÿ°°°ÿ±±±ÿ±±±ÿ±±±ÿ±±±ÿ±±±ÿ°°°ÿ°°°ÿ°°°ÿ¯¯¯ÿ®®®ÿ­­­ÿ¬¬¬ÿ«««ÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¢¢¢ÿ¡¡¡ÿŸŸŸÿ›››ÿ–––ÿÿˆˆˆÿ€€€ÿzzzÿvvvÿsssÿqqqÿqqqÿoooÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÔÔÔÿÜÜÜÿæææÿíííÿðððÿñññÿòòòÿòòòÿîîîÿèèèÿáááÿÚÚÚÿÕÕÕÿÒÒÒÿÏÏÏÿÌÌÌÿÆÆÆÿ¾¾¾ÿ¶¶¶ÿ®®®ÿ§§§ÿ¤¤¤ÿ£££ÿ£££ÿ¦¦¦ÿ©©©ÿ¬¬¬ÿ¯¯¯ÿ²²²ÿµµµÿ···ÿ¹¹¹ÿ»»»ÿ½½½ÿ¿¿¿ÿÀÀÀÿÀÀÀÿÁÁÁÿÁÁÁÿÂÂÂÿÂÂÂÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÂÂÂÿÂÂÂÿÁÁÁÿÁÁÁÿÁÁÁÿÀÀÀÿ¿¿¿ÿ¾¾¾ÿ¼¼¼ÿºººÿ¸¸¸ÿµµµÿ³³³ÿ°°°ÿ­­­ÿªªªÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¡¡¡ÿŸŸŸÿšššÿ’’’ÿ‰‰‰ÿ~~~ÿvvvÿqqqÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÔÔÔÿàààÿéééÿíííÿíííÿìììÿçççÿßßßÿÙÙÙÿÔÔÔÿÑÑÑÿÏÏÏÿÌÌÌÿÆÆÆÿ½½½ÿ´´´ÿ¬¬¬ÿ§§§ÿ¦¦¦ÿ§§§ÿ«««ÿ°°°ÿ´´´ÿ¸¸¸ÿ»»»ÿ¿¿¿ÿÁÁÁÿÂÂÂÿÂÂÂÿÃÃÃÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÂÂÂÿÁÁÁÿÀÀÀÿ¾¾¾ÿºººÿ···ÿ³³³ÿ®®®ÿªªªÿ¦¦¦ÿ¤¤¤ÿ¢¢¢ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¢¢¢ÿŸŸŸÿšššÿÿ„„„ÿwwwÿnnnÿjjjÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÆÆÆÿÊÊÊÿÖÖÖÿäääÿéééÿèèèÿâââÿÜÜÜÿÕÕÕÿÒÒÒÿÐÐÐÿÎÎÎÿÉÉÉÿÀÀÀÿ¶¶¶ÿ­­­ÿ©©©ÿ©©©ÿ­­­ÿ³³³ÿ¸¸¸ÿ½½½ÿÀÀÀÿÁÁÁÿÃÃÃÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÂÂÂÿÁÁÁÿ¿¿¿ÿºººÿµµµÿ°°°ÿªªªÿ¦¦¦ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¡¡¡ÿœœœÿ’’’ÿƒƒƒÿtttÿjjjÿfffÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÊÊÊÿÙÙÙÿãããÿâââÿÜÜÜÿÕÕÕÿÑÑÑÿÐÐÐÿÍÍÍÿÅÅÅÿ»»»ÿ±±±ÿªªªÿªªªÿ¯¯¯ÿ¶¶¶ÿ¼¼¼ÿÀÀÀÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÁÁÁÿ¾¾¾ÿ¸¸¸ÿ²²²ÿ¬¬¬ÿ¦¦¦ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¢¢¢ÿœœœÿŽŽŽÿ|||ÿlllÿdddÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿËËËÿÛÛÛÿÞÞÞÿ×××ÿÒÒÒÿÐÐÐÿÌÌÌÿÃÃÃÿ¸¸¸ÿ®®®ÿ©©©ÿ¬¬¬ÿ´´´ÿ»»»ÿÀÀÀÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ¾¾¾ÿ···ÿ¯¯¯ÿ¨¨¨ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ   ÿ–––ÿ€€€ÿkkkÿbbbÿ```ÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ¾¾¾ÿËËËÿØØØÿÖÖÖÿÑÑÑÿÍÍÍÿÄÄÄÿ¸¸¸ÿ¬¬¬ÿ§§§ÿ«««ÿ´´´ÿ½½½ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ¸¸¸ÿ¯¯¯ÿ§§§ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¡¡¡ÿ———ÿ€€€ÿiiiÿ```ÿ^^^ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¶¶¶ÿ»»»ÿÊÊÊÿÔÔÔÿÐÐÐÿÇÇÇÿºººÿ®®®ÿ¥¥¥ÿ§§§ÿ±±±ÿ»»»ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÁÁÁÿÁÁÁÿÁÁÁÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿÀÀÀÿÀÀÀÿÀÀÀÿÁÁÁÿÁÁÁÿÂÂÂÿÂÂÂÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿµµµÿªªªÿ£££ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¢¢¢ÿ•••ÿwwwÿaaaÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿ³³³ÿ¸¸¸ÿÈÈÈÿÍÍÍÿÁÁÁÿ²²²ÿ¦¦¦ÿ¢¢¢ÿ§§§ÿ³³³ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÂÂÂÿÀÀÀÿ¿¿¿ÿ½½½ÿºººÿ¸¸¸ÿ¶¶¶ÿ´´´ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ¨¨¨ÿ§§§ÿ¥¥¥ÿ¥¥¥ÿ¤¤¤ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ£££ÿ¤¤¤ÿ¥¥¥ÿ¦¦¦ÿ§§§ÿ©©©ÿ¬¬¬ÿ®®®ÿ±±±ÿ´´´ÿ¸¸¸ÿ¼¼¼ÿ¾¾¾ÿ¿¿¿ÿÁÁÁÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÀÀÀÿ···ÿ«««ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ£££ÿŸŸŸÿ†††ÿeeeÿ[[[ÿ[[[ÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã°°°ÿµµµÿ¾¾¾ÿ»»»ÿ­­­ÿ¤¤¤ÿ¡¡¡ÿ¥¥¥ÿ±±±ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÃÃÃÿÄÄÄÿÅÅÅÿÇÇÇÿÉÉÉÿÊÊÊÿËËËÿÌÌÌÿÌÌÌÿÊÊÊÿÉÉÉÿÇÇÇÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ°°°ÿ¯¯¯ÿ­­­ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ§§§ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¡¡¡ÿ   ÿŸŸŸÿžžžÿœœœÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ’’’ÿ‘‘‘ÿÿÿÿÿÿÿÿ’’’ÿ–––ÿšššÿ   ÿ¥¥¥ÿ«««ÿ±±±ÿ¸¸¸ÿ½½½ÿÀÀÀÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ···ÿ©©©ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿÿiiiÿZZZÿZZZÿYYYÒXXXXXX¬¬¬¬¬¬­­­ã¯¯¯ÿ®®®ÿ©©©ÿ¢¢¢ÿ¡¡¡ÿ¢¢¢ÿ©©©ÿºººÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÃÃÃÿÅÅÅÿÈÈÈÿÍÍÍÿÒÒÒÿÖÖÖÿÙÙÙÿÛÛÛÿÜÜÜÿÚÚÚÿØØØÿÖÖÖÿÓÓÓÿÐÐÐÿÍÍÍÿÊÊÊÿÈÈÈÿÅÅÅÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ´´´ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿ‡‡‡ÿ†††ÿ………ÿƒƒƒÿƒƒƒÿ„„„ÿ„„„ÿ†††ÿŒŒŒÿ”””ÿÿ¥¥¥ÿ¯¯¯ÿ¸¸¸ÿ¾¾¾ÿÂÂÂÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ¯¯¯ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ’’’ÿgggÿYYYÿYYYÒXXXXXX¬¬¬¬¬¬­­­ãªªªÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¬¬¬ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÃÃÃÿÆÆÆÿÌÌÌÿÕÕÕÿÝÝÝÿäääÿéééÿêêêÿéééÿèèèÿåååÿâââÿàààÿÝÝÝÿÚÚÚÿ×××ÿÔÔÔÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ†††ÿ„„„ÿƒƒƒÿ‚‚‚ÿ€€€ÿÿ~~~ÿ|||ÿ{{{ÿ{{{ÿ}}}ÿ€€€ÿ‰‰‰ÿ•••ÿ¢¢¢ÿ¯¯¯ÿ»»»ÿÀÀÀÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ´´´ÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ£££ÿŒŒŒÿ___ÿXXXÒXXXXXX¬¬¬­­­©©©ã   ÿžžžÿžžžÿžžžÿ¨¨¨ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÈÈÈÿÐÐÐÿÙÙÙÿãããÿìììÿóóóÿöööÿôôôÿñññÿîîîÿëëëÿéééÿæææÿãããÿáááÿÞÞÞÿÛÛÛÿÙÙÙÿÖÖÖÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿwwwÿvvvÿtttÿuuuÿxxxÿÿÿžžžÿ¯¯¯ÿ¼¼¼ÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ±±±ÿŸŸŸÿžžžÿŸŸŸÿÿuuuÿXXXÒXXXXXX¨¨¨¬¬¬œœœã‘‘‘ÿ‘‘‘ÿÿ•••ÿ¶¶¶ÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÇÇÇÿÎÎÎÿØØØÿáááÿçççÿìììÿïïïÿòòòÿõõõÿöööÿôôôÿñññÿïïïÿìììÿêêêÿçççÿäääÿâââÿßßßÿÝÝÝÿÚÚÚÿ×××ÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿqqqÿpppÿpppÿtttÿ~~~ÿ“““ÿ§§§ÿºººÿÂÂÂÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿžžžÿÿ‘‘‘ÿ‘‘‘ÿƒƒƒÿ]]]ÒUUUXXX•••™™™ŠŠŠãÿ‚‚‚ÿÿ•••ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÅÅÅÿÊÊÊÿÑÑÑÿØØØÿÝÝÝÿäääÿèèèÿêêêÿíííÿðððÿòòòÿõõõÿ÷÷÷ÿôôôÿòòòÿïïïÿíííÿêêêÿèèèÿåååÿãããÿàààÿÞÞÞÿÜÜÜÿÙÙÙÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿlllÿkkkÿnnnÿyyyÿÿªªªÿ½½½ÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÄÄÄÿ§§§ÿ‚‚‚ÿÿ‚‚‚ÿ~~~ÿbbbÒSSSXXX‚‚‚„„„yyyârrrÿsssÿqqqÿ“““ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÅÅÅÿÉÉÉÿÎÎÎÿÓÓÓÿ×××ÿÚÚÚÿÝÝÝÿäääÿéééÿëëëÿîîîÿðððÿóóóÿöööÿ÷÷÷ÿõõõÿòòòÿðððÿîîîÿëëëÿéééÿæææÿäääÿáááÿßßßÿÝÝÝÿÚÚÚÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿjjjÿiiiÿgggÿlllÿ}}}ÿ›››ÿ¸¸¸ÿÃÃÃÿÄÄÄÿÄÄÄÿªªªÿvvvÿrrrÿsssÿqqqÿaaaËSSSXXXyyy~~~lllÑcccÿcccÿbbbÿÿ¿¿¿ÿÃÃÃÿÃÃÃÿÅÅÅÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿÝÝÝÿåååÿêêêÿìììÿîîîÿñññÿóóóÿöööÿ÷÷÷ÿõõõÿóóóÿñññÿîîîÿìììÿêêêÿçççÿåååÿãããÿàààÿßßßÿÛÛÛÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿjjjÿhhhÿgggÿeeeÿfffÿuuuÿ•••ÿµµµÿÅÅÅÿœœœÿeeeÿcccÿdddÿcccÿ]]]ªTTT XXXtttŸŸŸ]]]”UUUÿUUUÿTTTÿ```ÿ¬¬¬ÿÃÃÃÿÃÃÃÿÆÆÆÿÊÊÊÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿÞÞÞÿçççÿëëëÿíííÿïïïÿñññÿôôôÿöööÿøøøÿöööÿóóóÿñññÿïïïÿíííÿëëëÿéééÿæææÿäääÿâââÿàààÿÝÝÝÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿdddÿcccÿcccÿrrrÿ•••ÿtttÿTTTÿUUUÿUUUÿVVVúXXXhWWWYYYVVVXXX@PPPêMMMÿPPPÿsssÿ¯¯¯ÿÁÁÁÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿÞÞÞÿèèèÿëëëÿíííÿðððÿòòòÿôôôÿ÷÷÷ÿøøøÿöööÿôôôÿòòòÿðððÿîîîÿìììÿêêêÿèèèÿåååÿãããÿáááÿÞÞÞÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿdddÿbbbÿ```ÿaaaÿ[[[ÿRRRÿNNNÿNNNÿRRRÂYYYWWWWWW]]]QQQˆSSSü€€€ÿ³³³ÿ¾¾¾ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿßßßÿéééÿìììÿîîîÿñññÿóóóÿõõõÿ÷÷÷ÿøøøÿöööÿôôôÿóóóÿñññÿîîîÿìììÿëëëÿéééÿçççÿäääÿãããÿßßßÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ[[[ÿSSSÿPPPâTTTEQQQVVVwwwppp#Ô²²²ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿßßßÿêêêÿíííÿïïïÿñññÿóóóÿõõõÿøøøÿùùùÿ÷÷÷ÿõõõÿóóóÿñññÿïïïÿíííÿìììÿêêêÿèèèÿæææÿäääÿàààÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ[[[ÿYYY [[[ZZZ¯¯¯¨¨¨²²²k´´´ó¶¶¶ÿ¹¹¹ÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿàààÿëëëÿîîîÿðððÿòòòÿôôôÿöööÿøøøÿùùùÿ÷÷÷ÿõõõÿôôôÿòòòÿðððÿîîîÿíííÿëëëÿéééÿçççÿæææÿáááÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[êZZZTfffXXX®®®®®®1°°°Ý³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿáááÿíííÿïïïÿñññÿóóóÿõõõÿöööÿùùùÿùùùÿøøøÿöööÿôôôÿóóóÿñññÿïïïÿîîîÿìììÿêêêÿéééÿçççÿâââÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÎYYY"YYY«««­­­†°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿâââÿîîîÿðððÿòòòÿóóóÿõõõÿ÷÷÷ÿùùùÿúúúÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿðððÿïïïÿíííÿëëëÿêêêÿéééÿãããÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZýYYYr^^^VVV¬¬¬«««­­­Á°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿãããÿïïïÿñññÿòòòÿôôôÿöööÿ÷÷÷ÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿêêêÿãããÿÒÒÒÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYY°WWW XXX¬¬¬¬¬¬­­­Ý°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿäääÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿïïïÿíííÿìììÿëëëÿãããÿÑÑÑÿÍÍÍÿÊÊÊÿÈÈÈÿÄÄÄÿÂÂÂÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿXXXÍWWWXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿåååÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿëëëÿãããÿÑÑÑÿÍÍÍÿÊÊÊÿÇÇÇÿÄÄÄÿÁÁÁÿ¿¿¿ÿ¼¼¼ÿ¹¹¹ÿ¶¶¶ÿ³³³ÿ±±±ÿ¯¯¯ÿ®®®ÿ¬¬¬ÿ«««ÿªªªÿ©©©ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿ×××ÿÙÙÙÿåååÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿëëëÿãããÿÓÓÓÿÏÏÏÿÌÌÌÿÊÊÊÿÆÆÆÿÃÃÃÿÁÁÁÿ½½½ÿºººÿ···ÿ´´´ÿ±±±ÿ¯¯¯ÿ­­­ÿ¬¬¬ÿ«««ÿ©©©ÿ©©©ÿ§§§ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ———ÿ•••ÿ”””ÿ“““ÿ’’’ÿÿÿŽŽŽÿÿŒŒŒÿŠŠŠÿ‰‰‰ÿˆˆˆÿ‡‡‡ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿæææÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿêêêÿèèèÿäääÿáááÿßßßÿÝÝÝÿÛÛÛÿØØØÿÖÖÖÿÔÔÔÿÑÑÑÿÎÎÎÿËËËÿÈÈÈÿÆÆÆÿÄÄÄÿÁÁÁÿ¾¾¾ÿºººÿ···ÿ´´´ÿ±±±ÿ­­­ÿ©©©ÿ¥¥¥ÿ¢¢¢ÿ¡¡¡ÿ   ÿŸŸŸÿžžžÿÿ›››ÿšššÿ™™™ÿ˜˜˜ÿ–––ÿ•••ÿ”””ÿ’’’ÿ‘‘‘ÿÿŽŽŽÿÿ‹‹‹ÿŠŠŠÿ‰‰‰ÿˆˆˆÿ†††ÿ………ÿ„„„ÿƒƒƒÿ‚‚‚ÿÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿçççÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿïïïÿíííÿìììÿëëëÿéééÿçççÿåååÿãããÿáááÿÞÞÞÿÜÜÜÿÚÚÚÿ×××ÿÔÔÔÿÑÑÑÿÌÌÌÿÇÇÇÿÂÂÂÿ½½½ÿ¹¹¹ÿµµµÿ±±±ÿ®®®ÿªªªÿ§§§ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ   ÿ   ÿŸŸŸÿŸŸŸÿÿœœœÿ›››ÿ™™™ÿ———ÿ–––ÿ“““ÿ‘‘‘ÿŽŽŽÿ‹‹‹ÿ‰‰‰ÿ‡‡‡ÿ………ÿƒƒƒÿ‚‚‚ÿ€€€ÿÿ~~~ÿ}}}ÿ|||ÿ{{{ÿyyyÿxxxÿwwwÿvvvÿtttÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿèèèÿðððÿñññÿòòòÿôôôÿöööÿøøøÿùùùÿúúúÿùùùÿ÷÷÷ÿöööÿõõõÿóóóÿñññÿîîîÿëëëÿçççÿãããÿßßßÿÛÛÛÿÙÙÙÿÔÔÔÿÐÐÐÿÌÌÌÿÆÆÆÿ¿¿¿ÿ¹¹¹ÿ´´´ÿ¯¯¯ÿ©©©ÿ¦¦¦ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ   ÿŸŸŸÿœœœÿ™™™ÿ–––ÿ’’’ÿŽŽŽÿ‰‰‰ÿ………ÿÿÿ|||ÿzzzÿyyyÿxxxÿwwwÿvvvÿuuuÿsssÿrrrÿqqqÿpppÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÖÖÖÿÚÚÚÿéééÿðððÿñññÿòòòÿôôôÿöööÿøøøÿúúúÿúúúÿøøøÿôôôÿîîîÿèèèÿâââÿÞÞÞÿÙÙÙÿÕÕÕÿÑÑÑÿÎÎÎÿÉÉÉÿÂÂÂÿ»»»ÿ³³³ÿ­­­ÿ§§§ÿ¥¥¥ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¢¢¢ÿ£££ÿ£££ÿ¤¤¤ÿ¤¤¤ÿ¥¥¥ÿ¥¥¥ÿ¥¥¥ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ§§§ÿ§§§ÿ§§§ÿ§§§ÿ§§§ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¥¥¥ÿ¥¥¥ÿ¥¥¥ÿ¤¤¤ÿ¤¤¤ÿ¤¤¤ÿ£££ÿ£££ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¡¡¡ÿ   ÿŸŸŸÿœœœÿ–––ÿÿŠŠŠÿƒƒƒÿ}}}ÿyyyÿuuuÿtttÿsssÿrrrÿqqqÿpppÿoooÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿØØØÿáááÿìììÿðððÿñññÿóóóÿõõõÿôôôÿóóóÿíííÿæææÿßßßÿØØØÿÔÔÔÿÒÒÒÿÎÎÎÿÊÊÊÿÄÄÄÿ¼¼¼ÿ´´´ÿ¬¬¬ÿ¦¦¦ÿ¤¤¤ÿ¢¢¢ÿ£££ÿ¤¤¤ÿ¥¥¥ÿ¨¨¨ÿªªªÿ­­­ÿ°°°ÿ²²²ÿ´´´ÿµµµÿ···ÿ¹¹¹ÿºººÿ»»»ÿ¼¼¼ÿ¾¾¾ÿ¿¿¿ÿ¿¿¿ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿ¾¾¾ÿ½½½ÿ¼¼¼ÿ»»»ÿºººÿ¸¸¸ÿ¶¶¶ÿ´´´ÿ²²²ÿ°°°ÿ®®®ÿ¬¬¬ÿ©©©ÿ¦¦¦ÿ¥¥¥ÿ¤¤¤ÿ£££ÿ¢¢¢ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¡¡¡ÿŸŸŸÿœœœÿ•••ÿÿ………ÿ|||ÿuuuÿqqqÿoooÿnnnÿmmmÿlllÿkkkÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÉÉÉÿÍÍÍÿÑÑÑÿÙÙÙÿåååÿìììÿîîîÿïïïÿîîîÿêêêÿãããÿÝÝÝÿÖÖÖÿÒÒÒÿÐÐÐÿÎÎÎÿÉÉÉÿÂÂÂÿ¹¹¹ÿ°°°ÿ¨¨¨ÿ¦¦¦ÿ¥¥¥ÿ¦¦¦ÿªªªÿ®®®ÿ²²²ÿ¶¶¶ÿ¹¹¹ÿ¼¼¼ÿ¿¿¿ÿÀÀÀÿÁÁÁÿÂÂÂÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÂÂÂÿÁÁÁÿÀÀÀÿÀÀÀÿ½½½ÿ»»»ÿ···ÿ´´´ÿ°°°ÿ¬¬¬ÿ¨¨¨ÿ¥¥¥ÿ¤¤¤ÿ¢¢¢ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ£££ÿ¡¡¡ÿÿ–––ÿŒŒŒÿÿvvvÿoooÿkkkÿjjjÿiiiÿhhhÿgggÿfffÿeeeÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÆÆÆÿÉÉÉÿÑÑÑÿÞÞÞÿçççÿëëëÿéééÿäääÿÞÞÞÿ×××ÿÒÒÒÿÑÑÑÿÏÏÏÿËËËÿÃÃÃÿºººÿ°°°ÿ©©©ÿ§§§ÿ©©©ÿ®®®ÿ³³³ÿ···ÿ¼¼¼ÿÀÀÀÿÁÁÁÿÂÂÂÿÃÃÃÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÂÂÂÿÀÀÀÿ¾¾¾ÿºººÿµµµÿ°°°ÿ«««ÿ¦¦¦ÿ¤¤¤ÿ¢¢¢ÿ¡¡¡ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ£££ÿ   ÿ›››ÿÿÿtttÿkkkÿhhhÿgggÿfffÿeeeÿdddÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÃÃÃÿÇÇÇÿÒÒÒÿáááÿæææÿãããÿÜÜÜÿÕÕÕÿÒÒÒÿÐÐÐÿÍÍÍÿÈÈÈÿ¿¿¿ÿ´´´ÿ¬¬¬ÿ©©©ÿ¬¬¬ÿ²²²ÿ¸¸¸ÿ½½½ÿÁÁÁÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿÁÁÁÿ¿¿¿ÿºººÿ´´´ÿ¯¯¯ÿ¨¨¨ÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¡¡¡ÿœœœÿŽŽŽÿ|||ÿmmmÿfffÿdddÿcccÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿºººÿ½½½ÿÀÀÀÿÆÆÆÿÕÕÕÿàààÿÝÝÝÿ×××ÿÒÒÒÿÐÐÐÿÍÍÍÿÆÆÆÿ»»»ÿ°°°ÿªªªÿ¬¬¬ÿ±±±ÿ¸¸¸ÿ¿¿¿ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿÀÀÀÿ»»»ÿ´´´ÿ­­­ÿ¦¦¦ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ   ÿ———ÿ………ÿpppÿdddÿbbbÿaaaÿ```ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿ½½½ÿÅÅÅÿÖÖÖÿÚÚÚÿÕÕÕÿÑÑÑÿÍÍÍÿÅÅÅÿ¹¹¹ÿ­­­ÿ¨¨¨ÿ¬¬¬ÿ³³³ÿ¼¼¼ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ¾¾¾ÿ···ÿ¯¯¯ÿ§§§ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ£££ÿ¢¢¢ÿ›››ÿ‡‡‡ÿoooÿbbbÿ___ÿ___ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿ¹¹¹ÿÄÄÄÿÓÓÓÿÔÔÔÿÏÏÏÿÈÈÈÿ»»»ÿ®®®ÿ¦¦¦ÿ¨¨¨ÿ±±±ÿ»»»ÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ¾¾¾ÿµµµÿ«««ÿ¤¤¤ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ›››ÿ„„„ÿhhhÿ^^^ÿ]]]ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¶¶¶ÿÂÂÂÿÐÐÐÿÌÌÌÿÀÀÀÿ±±±ÿ§§§ÿ£££ÿ©©©ÿµµµÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿºººÿ®®®ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ•••ÿtttÿ___ÿ\\\ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ¾¾¾ÿÆÆÆÿºººÿ«««ÿ£££ÿ¢¢¢ÿ¨¨¨ÿ¶¶¶ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ»»»ÿ­­­ÿ£££ÿ¢¢¢ÿ¢¢¢ÿ£££ÿÿ~~~ÿ___ÿ[[[ÿZZZÿYYYÓXXXXXX¬¬¬¬¬¬­­­â°°°ÿ³³³ÿ³³³ÿ¨¨¨ÿ¢¢¢ÿ¡¡¡ÿ¤¤¤ÿ±±±ÿ¿¿¿ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ···ÿ¨¨¨ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ   ÿƒƒƒÿ___ÿYYYÿYYYÓXXXXXX¬¬¬¬¬¬­­­â¬¬¬ÿ¥¥¥ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¦¦¦ÿ···ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ½½½ÿ«««ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ   ÿ~~~ÿ[[[ÿXXXÓXXXXXX¬¬¬­­­«««â¤¤¤ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¥¥¥ÿ¹¹¹ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¿¿¿ÿ«««ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ›››ÿmmmÿXXXÓXXXXXX«««®®®¢¢¢â———ÿ–––ÿ–––ÿ———ÿ°°°ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ»»»ÿÿ–––ÿ–––ÿ———ÿ€€€ÿ[[[ÓVVVXXX¡¡¡‘‘‘⇇‡ÿ‡‡‡ÿ†††ÿ“““ÿ½½½ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¤¤¤ÿ‡‡‡ÿ‡‡‡ÿ‡‡‡ÿÿaaaÓTTTXXXˆˆˆ‹‹‹âxxxÿxxxÿwwwÿ•••ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿ«««ÿ{{{ÿxxxÿxxxÿvvvÿcccÐTTTXXX{{{qqqÛiiiÿiiiÿhhhÿŠŠŠÿÁÁÁÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿ¤¤¤ÿlllÿiiiÿiiiÿhhhÿ___»UUUXXXxxx……… ccc®ZZZÿZZZÿYYYÿlllÿ···ÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÂÂÂÿ‡‡‡ÿYYYÿZZZÿZZZÿZZZÿYYY†???VVVmmmQQQXXX`QQQùOOOÿOOOÿQQQÿ‹‹‹ÿÂÂÂÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿ¨¨¨ÿ\\\ÿNNNÿOOOÿOOOÿRRRáWWW5VVVWWWZZZQQQ¶NNNÿNNNÿMMMÿWWWÿ™™™ÿÂÂÂÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿ°°°ÿjjjÿMMMÿNNNÿNNNÿOOOùTTTwcccYYYSSSRRRSSS8OOOØNNNÿNNNÿMMMÿXXXÿ’’’ÿ¾¾¾ÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿ¨¨¨ÿiiiÿMMMÿNNNÿNNNÿNNNüQQQ™ZZZVVVUUU¢¢¢QQQHOOOÙNNNÿNNNÿMMMÿSSSÿ{{{ÿ¯¯¯ÿÃÃÃÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿ»»»ÿÿ]]]ÿMMMÿNNNÿNNNÿNNN÷PPP–UUUTTTSSSvvvOOO;NNNÃNNNþNNNÿNNNÿMMMÿ```ÿÿµµµÿÃÃÃÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿ¼¼¼ÿžžžÿpppÿQQQÿMMMÿNNNÿNNNÿNNNéPPPvTTTRRRLLLWWWOOO NNN’NNNîNNNÿNNNÿMMMÿOOOÿcccÿ‹‹‹ÿ±±±ÿÁÁÁÿÅÅÅÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÃÃÃÿ¹¹¹ÿšššÿoooÿTTTÿMMMÿNNNÿNNNÿNNNûNNNÀOOOGSSSPPPOOOOOONNNLNNN¸NNNöNNNÿNNNÿMMMÿOOOÿ]]]ÿ|||ÿžžžÿ¹¹¹ÿÃÃÃÿÅÅÅÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿ¾¾¾ÿ¬¬¬ÿŠŠŠÿgggÿRRRÿMMMÿNNNÿNNNÿNNNýNNNØNNNvOOO666RRRQQQCCCNNNNNNZNNN¶NNNóNNNÿNNNÿMMMÿLLLÿSSSÿhhhÿ………ÿ   ÿ···ÿÂÂÂÿÅÅÅÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÅÅÅÿÄÄÄÿ¼¼¼ÿ¬¬¬ÿÿrrrÿYYYÿNNNÿMMMÿNNNÿNNNÿNNNûNNNÕNNN~NNN'SSSPPPQQQNNNNNNQNNN£NNNãNNNüNNNÿNNNÿMMMÿMMMÿSSSÿdddÿ}}}ÿ•••ÿ­­­ÿ»»»ÿÂÂÂÿÅÅÅÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÅÅÅÿÄÄÄÿ¾¾¾ÿµµµÿ¡¡¡ÿ‡‡‡ÿmmmÿXXXÿOOOÿLLLÿMMMÿNNNÿNNNÿNNNñNNNÂNNNrNNN"LLLMMMXXXKKKNNNNNN/NNNxNNNÂNNNîNNNýNNNÿNNNÿMMMÿLLLÿPPPÿXXXÿjjjÿ€€€ÿ”””ÿ¨¨¨ÿ···ÿ¾¾¾ÿÃÃÃÿÅÅÅÿÅÅÅÿÄÄÄÿÄÄÄÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿÅÅÅÿÄÄÄÿÀÀÀÿºººÿ®®®ÿ›››ÿ‡‡‡ÿrrrÿ^^^ÿSSSÿMMMÿMMMÿMMMÿNNNÿNNNÿNNNõNNNÖNNN”NNNHNNNMMMNNNMMMLLLNNNNNN`œåÅh4LÀȃÑp‰!a“1yÑ qTÊE(×–;¥´P þ›üqíÝ}NOK/‡ù’uÖÚëúýÿë[k}kŸs*ÂKSSÓø©S§ÎÖ0õoI^¼x1µ¢¢bœâÅ• ¯¸KÑSåõŒ7®ûùóç=zn?zôèmÊGR*†£óõë××UVV¾# _Æ/ IJ¾¾¾yê»¶··wÚPÇPÏÔß}µ¿®pMÄœQÞg¥ÿ-‚µo· ÍÍÍ+«ªªÞŸ‰uJY€Ž‹>€-ù‰ƒÁ¹Ï3GÉ›$ø…>LÔÆQ:{öl?)(Å™Àü—-[0\N”G˜/_ÎÂ=‚;wpp—ÀCÄ}Γ~P ö$-Á2ñHyÕ…ãÅ›,ƒ¶èÎÝ,ìmº¦6ùÓKG€àúÈìsˆývÊì{3²Î¨9 8\$Ð7 Ý?„c‰˜7¯î˜ñb ‘Ë8˜¼Ó§O÷«ž"€RÀjcccò5_=1 ÆD¸'ê³q²‚â\dH¡®ƒO ž=kˆ˜TÚEÌl³œÞñ2„ü¬äŽ€ ˸páÂÀ÷ñ»Ï€•Îv˜÷ 0ƒË+Ž<ôõíýôæ"È(d•¹ÐØ/Aô¦8Y¼ÁŒ¸åÑ1lzv1Ó<ë Ÿ‘£#KÏ–Åš×ËÏDWž‹IAhD§ì|Q·¿Ì:À2Ø †Q ƒµI:ƒ±Æfi0>¤Yf¾`QnAtAÞI¸Ë‹ÅE pCÀ±±û³@àÈÇì …(B>ib›K²KÂ3ï?Ž!Áã8y´wÛ¸þ@é’ “˜qwjÓ7ãGÌ”÷Ò( (K>1ùŽé×Ádè—ºôe ql}†¿yzi… šYˆ<~ŽA9?ÎËïuóRw úrûÌé5Ïrª% kÀ]jû¼>‡9/…1E€Öç? f3Ëç˜Y+w‘®)o(E€6¦Ýª{nÎÁ€“oS-g¤o·ÂîXÇûöíûשS§z–òJ“bòÚfû«g-Ë.éÙŸ"`Á‚¿’¿\ÕÒÒ’€Œ+f  ÌD˜¬  à’ÄI¤M¹Vúý(Æ•:äæ6áúâsNÇ€b°N¼còÊEðYøaÄÒ¥KÉ'’_’‰„-Òï#ë˜"@à+iÄåÇ;:i.5¸¿1NCV9ì8h\äø)_üN€[-ºÊM®1xâz™ðPJòŽ/ƒå,'àåÙ¤Cb ÜqR0Jx–x¦\ãqĸ³do‘˜?z3±—.]Jý@"E€|ø‡ Ì:WH–C|ç†ümÂÕ«W÷ØÞ Š #¹ÐÅÊ­Ô?çÉ޹ÇUçrÄ’æJ,2R_§ !fŽé0ÛsöýãŽIãé²b20Gò~â}"¶ã™6ÄÔE|‘~ŠÍêÀ²å"Çì3¿Ðìg«¥—¥TÆOçÝk‰N¸a‘ã4P” Ôf8ÊÀ\׉ô?þ|2¡ycô³*Ñ YO:BXäñ›Ä¯§<ÛIæ|°,™0£#V„þèÉ[` ¯äàÊ0‰°á±ÁˆÀL ³ÅD ¬SÌw$°lÆŒIÌò#m³æ!¥p·)J•Ä¿a§ 3w~õ«(žy ‰R˜>Ä{={};¶õÐ_PÜǪcÀSÇB“Àd1î`O¢ `@£c  ð®ØÈ·BJ r°›(ùƒÆ… úgÚ{ ú$`ÂÓ·ë–D•cöÝØ13‰ùÇ3Mš£ŠY±©„´€ F}ƒsìúÅô±^¥ÄÃB@<³ŽŸ8À;må1Á»,î{$Ò©Ëà?8¹2Z å>Œ™Â‘ú_QŠ™òáBcyv "ηÙj_Fù¿‹uI ãã*<WpÐ6MÒˆ‰ˆIp™Û•YÜ"Wú§±N)vìØÑ«5ܬ ÇâJ¤M@LBœgL€¸l?cõ,½É­oÞ»wïÿ)ÓoÔ?E©ò×õ›oªü õ( °BÁàYÔqý$1ö—¤Âw8ðÛ,dø(øxäÈ‘é:e*tcœ"BÆ \µâÅÂö¼Ké§rŸ»·mÛÆßçGEþšGÎA¹®ËñIEND®B`‚ic07.‰PNG  IHDR€€Ã>aËsRGB®ÎéDeXIfMM*‡i  € €HŽwIDATxí{¬WUvÇøD¼D‘‡¢t0ØV0#4ÓQAãhSÕ?ZM;˜tŒÉLÓiKúOŸ˜šhCR+£µ8Œ‚Õ>&ÆI§ ƒv@Ñ"W¤PÁ ŠŠ]Ÿß{×osöùó»¿{¿{ïYɾk¿k}÷Úûì³Ïï&IEZƒúúèo¹å–¡GŽ=hРQ_ýõ¹6žÆÏ2>ÜÜ0‹~<<ØÂ'™;Ó\Œ>·„CÇà·²­ŽýæˆßûÕW_í6¾{èС­\¹rÿñ¼}–µ;-\¸pâ)§œ2Åq¡¹ñ¦ˆ LÚÍ77ÖÜéæZE_XûÌm7÷Ö¿÷¬ÛÌ~gÿþý/½ôÒgæo[j˜¢/8餓f™ð¾aÒºÔÜÔãnhÛJ¯~ÇŽZ–í6¦ÍGÝd|ƒdý!C6šõ8R¿xÏçh ÌlŸef{® eŽ å*æ,s#»3\Obf9u§vZròÉ''ðSO=51 ’:ÕO|H_~ùebæ=¶~%Ö¿äóÏ?Oˆÿâ‹/’Ï>û, :t(M Ë— c9Þ40¼jãÿ™µ·æ¹çžë(YGS²÷ X§M˜×Ø€¯µÏ·žÏ0Çš\ˆP؈#’3Ï<³ÓqÆÉðáÓÓO?=6lXªèB•5!@9|øpê8à>ùä“”›ÙOöíÛ—|úé§e[úÀ üÌäóoæ}úé§ß+[A#ù{ ×^{í›y7[§™CéCêuEŸsÎ9ɹ瞛Œ5*9rdröÙg§J®W¶ÝÒ±{÷îM>þøãÔíÚµ+ùè£Rpé«á Ë÷¼ñ•Ï>ûìkEÊ4’§©X´hÑÖ‰[ü[6Ûç›c×I–'9ï¼ó’±cÇ&ãÆK•~ÖYlÞû7±´|øá‡É|¼÷Þ{ÉŽ;RK’7jÁV“å?ZžÇW­Zõv^Þ²iMÀM7Ýt‰­cKL©w™y–Õ D2f̘䢋.J&Mš”*Ÿµy “)6µÛ·oO¶nÝšÀ±úÚd¼ÖÊüímVÙFòئ%’¹Ht·`3~¶)ñ/¬Ã¿fP³|âĉɴiÓ’É“'÷IS^DˆÍÌæËÐÑÑ‘¼ýöÛQë`²Ýe“îOÌŠþý²eË¢ˆ©×·”V¯é7ÜpÃt{”ù[ÛØýzV~Lûå—_žL:5Ý eå©âêK€§,›o¾™‚AO)¾¤a…ï·}Ârã_û´"þR¸ûî»O±ÍŸÚŒÿ¾u®f}ç1lúôéÉW\‘š÷"WyŠK€ÇÏ×_=Y¿~}ú´–4ùÿáú§žzêÝ0-/\‹/ž`ë΋6ë/öbæg̘‘Ì™3'}Dói•¿ùÀ lذ!yå•WNxÔ´}ÖQÂìòÏ‹¶\7ß|ó¯Xå/Ú¶fƒÇî}Á‚é£ZÑ«|Í‘{…5kÖ$ëÖ­KX*<Ù!ØjÁb‹«»$ÔÀ]wÝu¥r¬±OV#Ìúy󿥿žÝ}E­“”«W¯NÏ|/ kgΜyõÒ¥KkÑá3™¿fÒ{¼eqëÍìwâp´zã7&—^ziR)?”Xï‡9 ½ä’K’;w¦§‘êY… v5ã­·ÞZ©¸,ž{;zôèglóÑù¶™ò/¼ð¬ºª¸I€w vÜž¦ù.Ø’ýíÛo¿ý7}\èÀvü“wïÞ}µ/pÕUW%\ÀÛØŠÚM¼ü²s™„§1‡Lf½´e ªçÎu]…Äí,þí…FçÏ©ÝìÙ³•\ñ6”/ÌfÍš•lÚ´É÷nŒ(]g«}¤üQØZ?ËŸÍó’†õ¿¢ö–Çìï¿ÿ~g'±övò[Qöšu$¯_E¼~­¨ý%`'´5ç1À^Q‹õÊ‘¿QbâÈJ";ÂaûÖ]´\Ó L!t,@‚ÅBh-D˜‚º˜M €@jGŠÈk³Õi(Uæ_ãdô½·Ê¢é(;#˜•2ïX Ê{`` A`¤Á N‚•Ÿp+H@„ËüÓw9ú-ekŒ­ègØfËvHa Ïs ”tœ,Š„/Žb”G S{ÔáÉ+K~•U{Ô§z§¼>ìëm7ÓÀ|³¡{A–ÐÅIWqŸ8PI1¤Cð,¥)_,ͧ§õÑ?mf3'‹Rv=ŽB½R½¿¿(­™Xë‘÷¸ºYîÜ›UoUÏ1 D`J<ÐBªÐ}-˜ £·w¢°f;mº u4ÚÿþVΰ56¦(¬ÐOc…êÅûu—¼(Ó+Ô‡å÷eñWÔ} ˜ÿ9VK7n\e…ê_*˨YÊ÷Yˆùtù³¸òW¼! üôÉ'Ÿ|9V2 €¥ö]¹ÑXÁ.Åj ♹YŠ$Nú}þ°¼ÊT¼´›,¿›W* Ù/ƒü‹½w.½xeÊï;!å+-‹\EKÀäwÿŠ+~‘WC.î¼óÎo¾ð ×ðÃDeH õeù¸<¿òW¼¸xç`g(ß›7o^îYO.l#¸Â^½üòËéïÑ‘YÊô]WzVœÒ<÷ù*¾/Ë8@³#ð‰vuï¯òJDpï½÷^gïæÏ×ëT~™Šï yõ¥i^y¡ßöiÄû0~¯¨˜ÆŸ‰#7éÍüßá×Ùc5D̓Ýàù}ÝÖ¡0¯oùuFà—B=Ç:)^Q¾¸ªÏï3¢~5Ì/Ù&×SÍð31˲j‰À^ÑNá—èüóϯQ¾^°p #¤P™>L^Â!÷y¤|Å¥™«?'H€;ü"+¿¿¬‰É-+¯7 ÙÝÍ_6Vv¯눈K!éÍïó¹íëÁà•'…ûòŠó\eÄ Η¨~dÁd¼øâ‹ÓßaeCØ_¦A†öàˆ˜¼¢À*9¬Y®Â¼WGÙžP@Áq¡ p±ƒ†uåŠü^Ñ*/E‹+a)^‘ý',3ó&LH&Mš”.Ç1™psÊ[®š(¢·<|Ì«W)޹øÉ?sˆ‘né°wÐ¥P] Áàëb<Ö^ŽGgüòfsç•7òg’z À7y€)ì õË÷Ø@ÊÍ#É£ŽÏ”± |*F}l&¥hÍr…CNºòäµ×_Ò ßYðÕ.kÙ•ÉÊw^7œðä–GQP“® „Q å‹ fv¢Œn¾‚Fö tÇma ’|R¸¸Q¤¾–‡+íL f+Jg¶#ïF¡hf¿ÙÙ¯„¦2U\Ϙµ( ó¯%¤ÑëRÎò’Õ^Zwßq"„tçŸåê`,;3œ‰ƒâõdÐ(g–3)Ñ'þÙzªGu€ÿ @Ÿ&Ñp0³ùô‹Át‡Øl†Nê\z²ÀO_ÚmIh0d}Ù¤ q£³ºž<ÑWåüD¢ òá÷ø€"TT‚rhˆÇ>î@ù|ãÇž€A8&Læ¼HÃEò ð,`P–™…C– ćñû<Ô Á½#N@£nü8ù#NJÇOzoýEþ|9¤q©}¬2ÿ]¤ÈÌW™B 3;Le½bÖÃ@ C|Œ%`McÓ×[‚Q;RŽÖß8ÊÕÒ*ž±²¿â"ü¦½ˆ €ÊÊÆ hfòˆ‚e¤±1CXëXóÂsƒ"ªò“³')žåYë ‡(øqöhYéaþ0\ a˜žO1ýX:Ç€cm ¬O¬C¬¼BñŸF~z܆gÍvJ ~ L™F©4hˆË&Ggé$0À @`¦Yp,„:1k±¬L"6Õøc˜éì»8l£l#³Þ×ߨ€†1ù¬M(\7(6…œàè<æ 00–,@ÐΙüZÓ}'û“y!#)žIcb1Óy #Ì*4"§† Æ@.ã¼@³s‘æ-yp œ„p€Î~_GÙr(®¨òë>“Ù"Gâ$£T€MúÓmÐIg,‡(G'Y”GÊ(( Œ8Mœ,åY.üã ÐÎ_¼7@B¿/Ë Eã3F8á²³‹Àøe%©ƒ¶¼š¤óšjšÕÂ'„žP ¦ 0Ž€gðäa³…éʃPòˆ:¨@Èï9e ãBò–Ÿ~à‡ãPn3B=ŒÐ˵ی6ÂñÅÂMé< ÐÚX$\„‚H€…Í%‚àÁ;òùöð“OeÒ‚-üCP,ýÄ16Ì9qyüz»»-@Ö ™¹Ú J8†L+Š•yÅOºã…, õ¤`¥8õQ}§Ï8ŸOþ¬ñ·*®mÀ`½gý÷À@˜„ÙgÀ½“ Q€fð(øQy!qêáW;p凫=âå”_aÕÓμé`° Y„¢X'®f~)PÖ®8ñzJR_¥0¸W¢÷‡iÍ_«ëéà©åq^é­n_h?ú]@w:ßL µcïNߪ²µˆÀŸ—¨¶žšP€q´C ëöMЛ(,_¯þ@„@ã¹üAŸ«`I ØdŽþû(l½]aí4´›CqYŽ~+^cðaùÃÍ—òV¼! |nrý§XÉ(n½õVPó“XÁ¼x¯@ò¡XÏå—³¸êH V–€Év¹}"¾3VA0%ü®±=±Â±øP¡ä#.$–!\ ”X¹°Ép³¸~/¯T.ì"¶Ùáˆ2ä•'Ū¼Âpȇc~•­xq —åý>úè¾¼R¹¸í¶Û¾±víÚ{žþùôX3¯"Ÿ–§Ü0_Lé>Þ—©üõ%À„åìÄŽÄxÇw{Ã)– 3?²SµÁ\ízæ™gÒW¾‘zj¢½òŸAéŠSØsQÖò¨¾Ì9å,²3ݰðcyòˆ`É’%³í^ß½kç>‹ÌH‘jXañ0ž°Ò²¸òW<..ÏÌ™3§ó•»ôf Xl?11V2zlW¿¿Ãå L›6-}ßNŠŠQ–Ãü +¯ê$ z_Y˜”Åó’ŒOÅgΜ™*¹­Y³¦³…ÛRp—EüYg¤óD`_Êûx@A•ˆsy˲Rž¸Ê†²¸òz. ¨|Å»$ÀÒÉ“''—]vYªx¥pÿÒëx»Vö«Jyvwo(ïÕEYŸ8¡ ½n%K")’pèWœ¸Ò=—òáY £ì@$.àò/|'Ùï0ûCB†ºw©4»Lý’÷ÄŽ—²J \O„¹ÉÖ€W¶ÜÖ\í¢s(NΗ¡“îýŠó<Í<€ÿ ϱcǦ?¡ÿ»»oЙäU& »°¹ ´1EÜP7nœ‚'p¢AWƹôÉ… ;<¤`*‘?ä´íÛ?¡Á~œ0åüF¿ùƒŠ®y Àæ=¢°N|’ü2@Üþõ‹UŽU`‰c@ºãÇ­aüR¶”ìÃò{k§?Ä39PŠæ»Kfy–yÏ+räco¡y$ä›Í<Š€BìüQ$7lDXãQ¦´'¿n¿ê·Y*°´cƒ)… â±zûb<Êfܘu&rÄù vÙq¡#>e‚Š%?áu§4Ïs@Ff,;N¾õQf?O ¨,Ñ9-*‹•õ8„¡%Cé}3@ÎŒDáp–B߈ÌbãGŽÌüPÑ[¶l©ûó0ÔY( åL:µóë_”igÓ‡Éb€Ý%Ú¡^,¬OB#DŸpÄc)ð÷  )EKáX3…{²?ÌzöY,ÉžŸ‰óáhª *¡1>Fdc‚ÂõÉ Àô€nÖ/¿þi¼L”ì …#t¡‹yáÞ©¼â|8\¤y×[@ÓxBN¿‘?Êg,ž˜<˜}Nl‹R!P•Ó(;SÖ,Ö/Ö–_¬‚|â1s­ívg=-*¸Þ·‰gêœ?l¥3óý¦=Ì“. 6ü6Vaó˜Bk@HZïEEI€ÙÎæ™g{x~ B›ó¬°Aàx´„°X—IíuÊB`à×£ZO?}0VÀêc#Ìøá„Ë(‹¼(YR–•ø2õHVexS 8&ž³‚˜Ñ˜yÒ4`Á 0B連ˆ¹¤MA T˜4Úð!-²f(ñšu(‚7C!ÈÉ[G/ЄýIîÁ?Mý,* ÁÌe߀ qÇLÂz°\ Õ ´¿€“W K3ÙÕ¥p+9}a,2ÿ1q¤IÙEeÖci:í$3S뾄#ŽÀ‚Ì+ñøášMãðg£Ñ¾e•Ci´/G?ÔGúF{%“·•ÊÎG ÙƒdÇ\#@@"AzŽ_a)G³0a™tõúÃ:¼°=µ©:TO–ÐÛ)®í€ÀY#áÌ(¯™&.¥VœW®W¢WŠð óiŠÏ+ÛNŠl´/} (µžÓÌlT ­\ù—ù$Äìiù]{³ê¬êé’@ÞïÊVÎW œ¼z!wí¥×`6»|¥¼Z?Ëh<—¿L=UÞL lÈŒµÈ(ìÔíÇ–ÞuÉ,VCF<ë0$ ˆ+.äR´ò…/òWÔ°ŽÚÔ£±ÒQ,^¼˜ë¤Ñ_–ˆUH<Š”ö?$…gq•'­¢Æ%`{¨?ñÄÑŸû‰€&Í |רֲÍKiR,å'¿O ã”&^QCØnçKòJæàúë¯ßk…ùÏÓ]_‰æÕv< JyR&IÞ¯j—Ç•·â¥$°ÏfÿM+W®Ìýßq¹ ¹E‹­3åÌ5oþ®o(Sä›çÓc~•«x1 ˜âwÚœÿøãÿw½u@×]wÝvóMóþ¼^…¤‡Š¬W&ÌO "+R¯|•^#ÿ0³¥­ûëkb#B ìÂ… ·Ø™ü\C×÷-ØõÙpFÅ^¡$û0þ0. Kñ*gm¦eª?¹Øoòºgùòå¿‘÷«`a …@ÁùóçyÍ5×ü¥=VL³à2s™ÿ® Å…J”â©'ôÎr²”©(*Õ—ÙäœfÊG']ëo´HWBCïæÎËg'÷¬[·îïŒÿ‘¹Íuýz„ )õX([ñÊ'®2ž«|Åk$°ß,ã?ØÒü×<òHáýYM hªäÊ+¯ü…ù¿ýꫯN´Ë¿gþß17Ú+Ïû)GXäÓB¿,¼¢ ó‡íBÌ=öرÿÓW“\.Ð-¨©Ù³go7ÿšÐÑÑ1ßü¿mÈ¼Éøp]»"¯”/ÆÅ@@¾Nÿkã_eòùáÃ?üZ3eѨCf’Øðó²?±ïÒ‡Xü›ÉØÌIùR6eå‡kæ+n€Z>Ãþ/“׿›{á(´£G–e©©ðÛÕo¾ezú¸ãƒ†ËL©ß²ðÕÆçš;%£àP銇Ëùºû¡Ÿ§ªWÍ­µñþ§]k{ñ¡‡ú´7ÆÙc;oß l´8ܤÙ÷Ɇî9æeî—là³ÌDá„ÀAþ~D(ûMs¯›Û`ãý¹Ý~~íÁÌ}´î©ñ÷ÂØ¿‹Ûbq¸Î_²´ec¢)K1ÝÜÈTKŸbn‚¹¾F»­Ã6†Í6^ÆtØrø–ñMK—.íúÉ•ªOœ°lݺuˆ-!ãmO1Î2ÑîýáknŒ…ÇXx”ùG›eá!æ:—~§EÁ†Ëäµ²G,?¿ž¾޳¸-ü¡ù·›‡õa‡Äm7%÷Š ï.~úÊ Ò~Øú4SÆ03«#¬?\8Ô3’: (œU¤¿~iŠ"*½c˜zŽùXYÍÎý–ç°•=d7‘÷Ù/‡ï»ï¾ÃÊ[ñJýBÿ5ý]„ôÉIEND®B`‚ic13BX‰PNG  IHDR\r¨fsRGB®ÎéDeXIfMM*‡i   gêI@IDATxí{ô^Uyç_®r ’BÂ=@AP«©ŠZ‡‚ERR,PvÚ)v­ÎÌZ:¶Nÿ(½èØ5ÓU[W«bÇ*"¨+ê’Ku¼€UPB \s'$! ˆ¨0Ïçðû†';çœ÷œóž÷öû={­ýîÛ³oÏÞÏw?{Ÿ}ÎÛé„ ‚Áà@p`êq`©×åÉÕãw¾óÓ~þóŸ¸Ç{°Ï>ûJï^|ñÅÌy…zú /ìiéÓƵðAF·Ùç̿åýÂÂO¹pÇòoÛk¯½Ìyág¿øÅ/¶ï»ï¾ÛöÞ{ïg—.]úœ§ ÿøq `ÈcvöÙgï}ÀÌ4¡›i<Ó„l– å¬=÷Üs¦5m¦ùq1{à„Å€>Øì0Í Vù6³ÛÍ>;á~Öú³Åú²Éü›¬/OÈO{à 7à†2ú8]tÑa?ýéOç™Ï·jæ›PÌ3÷(³ ÌÎ6;Ël¶j›;Õ à‘¹kGkŒ?«Ì¿ ¿i«M³Yi@°„éz`¬ ø¾&àÇØ„=É&ï‰VÔ æ.°0‚޳J‡éÆË'§«Í]ešÄcVÔæ_aà°âµ¯}íê+®¸ Ówá…ÎyþùçO± x‚M>}á„Àmþ½+$ýág+&샃ùï7p¸ïë_ÿú.çý©~üK HÆÐÕæšpŸi“éLK’“Epô9°Þšx'ÖÆóN…e_ýêWýf¶…SLØYÉß`Âþjcûéf_evÚ`‡`°µí·ß~¹Ú!]Ç´œÜ´I¹Áúr—÷M›»Óžl|ï_ÿõ_Š)k¦ \~ùåû¬_¿þLøEfÅ&Á"uáFÊXÛ:ûï¿Aµ§™_a›°{R¥ábí‘\ç¯xEǧ©CŠS¸®û³Ÿý¬cý²lƯŽwd A¼­¨;éÇŽçž{®ƒûì³Ïvžyæ™Q—‡­ƒß3û]ãý÷®¿þúåæ1ëôø™´`×ö;øàƒßh÷ͼåkÍî?¬1EX­=iÓ¦u:è Ì+!ÇEèv@`²4 @ (ÈO=õTfŸ~úéÎöíÛw‚Îx°ÙæÌm6ß5÷›gžyæ“ù qRÍ´w¼ãÇÚã£smà~Í&Ï[Íò¼| Æêízè¡;-‚.Ç`‡éλ Aî“O>ÙÙ²eKgÛ¶m\Lê^P{OXQ7 |Ýê½i²Ý_k`•Ÿ>}ú›mÒœkƒ„儾o†•¡FÐ;ì°ÌJ艟Œ+wߘٰ`„ëÖ­lÞ¼9sm¢Ïæ›kwØ3Î8ã‡ã®Œس÷½ì°ê-6ЗÙ`\`n_nÃÙ!Q&èGqDgöìÙ;-ª|˜Ñ䇘O<ñDgÆ ™Ý´iS«sŒ>´z³•ù%›‡Ÿ5Í€s„±;; @èí@ém†º¿eLþ ³­ÞžC}GÐçÌ™Ó9üðÃ3Ë „op@  €Ãºuë:7nä}‰V;fss¥•ùE³Ÿ70øQ«…÷±°‘€Å‹Ÿn ý}³Z;±çÀmîܹ#<2³?'æa¦Ð‚µk×vÖ¬YÓ±§Cžl´h´²®±…åŸí1ãšËm½¨‘®×Úý¦ ýZoßÐF<ðÀÎÑGÝ™7o^&ð3fÌh£Ø(c’p€s´aåÊ•U«Vµ?7}Åæò?šVðMó·«v´Àÿ‘®Û _fªÔ¶~q—¾±±225¡?öØc3¡'.Lp  4„Gy¤óØceà`B\%kÍ +ãSVö•v#qKá Ó†.öèîTS¿ÿÜ:ÍÞ¾±Îc¶ãŽ;®sÌ1Çtü¢oƒdnÔ598À£G€@€À¹BæiËûÌ~ø+_ùʆÊi%ëÐàüóÏ?ÆVå?µ^üžÙF‚Ï ¸ã?¾³páÂLðãЮ•9…”pág›°lÙ²ÎC=ÔˆçL#ø¤ÉÀ‡† |Þ‹ÿ3ãñïš­ý&'ö ,È„þÄO̮ÖŒW$úÆ®F<ð@çÑGmzA‰§|Ô쇯»îº­}klAÁ;Ü›nòþÒ:úÖ–} ÚSͳx»xÑ9餓Bè ¹ Ãâ—î¹çžÎ]wÝ•Ý`lÐŽm–çÏíæã?~ë[ßêiQ§îAÀöÖÝo›àÿoSyø Neã9Ô{ŸÇva‚£ÎÑ ž&Ô=<49Yn—~ïÆo¼}}í+œwÞyGð,Ô:òŽ:á9½½„Ñ9í´Ó²—eêä ÚàÀ¨p€«Ê?þñ3Í ÎÁ¡Æ‹vžõQ;|üÓü[[ïZßÀVýwZ'xìQù¡;'÷¯yÍk2á+·­u8$ð†ãí·ßžAkÉ&?«íÑøyöØðÞ~5½°‡ôý±5øš:S©|„ýÕ¯~uçu¯{]ön{¿:å†ÉÞlüþ÷¿Ÿ[…Šæ¶~ÿ—¿üå¨H_‹¬’€V-ÑÿkìÿµÎñf^W>°¿_´hQ<·ïÊ­ ˜,àÍÅû·ËžTí“ÉÕµ—V¥¯Jר…žCm%¿É„ÿ¬*•sªÎ9çdoÙU¡šàÀdãÀŠ+:·ÜrKåט îš5kÖk¯¼òÊÖ^\hÎ=÷܃mÿ~»íoNé6H\Öùå_þåÎë_ÿúxÛ®³"}Òs€/$Ý|óÍÙ]‚*µCõ‡í"ÒÉwÞyg+ Ð3ðòŽZ~Ó^àéúâ×um›]ä©ÒÙ  LÜ}÷Ý[o½µÒÍBûäCvïàTûôùO{åOÏ/¼›ð²Šðóžý{Þóžþ^G,òOJ¼êU¯ê\|ñÅ•>gòv¼}Oò6¾“Ñ+3z€%K–\b¹¬[#x ÷’K.É>ˆÙ6ÒƒS•\v»ôÒK³Ævã]C~µ \Ù®[zc±ÇüÓl?òmÛ÷—~#‹mReŸ¯îÖ˜HLu°Mæ·ûï¿¿ë7 ìÀý {|~—]A~ )ßk‡rÈ'lõ/ýê.â°÷üCø›ŽNä›’àC³\pA×Cr.٠ë.»ì²Ê—íR†6Òx±ÇT« „güöI¯Ž=¶HëŒpp 8Ð…úÊ4ÁWØ“µ}ï½÷Þo”Ñ¥ pQâ탙4ôÙ !/²¼µÇk»a‚Áf°?Î>=_$cÄÛ!<ömQ>¢I-µßǧ«ð7˾¸CøÝ&8hÎ;äËîËpk°‹±;xû¼Çhþ¦ Ýnɵ5€?ú£?:Ð^P˜Í×xŠ,§þìc‚½q€Þp–V$kÄó.-Ê7©©6Ìœ9ó|•§¬AóçÏoÒ–È$@Öø|}™¼Mhã§q6—d﬽0´9“Æ”{BP–iÁà@  Mó÷geÆnîi[ïS†(ªlj€!ÒŒn€J&8h‡Zý»•fgµ¹ÕÛ¼Ø ê|ý¤[§"=80Õ9`ú²-@&žðQÒÚÿ“Yì¦ÒÓeOh$ÿý&8h‡¼1X&sv!/«ÈîÔ~¹¯6Ø›HÏØ‹¥×ù_wn)ñ#Lp 8М|m˜¾L놦©© TÄ-%¾sVføêIÜ,ãP¤ºs€2.~JèEãnÓ¦M+Õh_Då/¶C €a‚õ9€êÏê^hÚÝž”ÕÜx6ɧ»©¼Ì€^¼ &8¨ÇþøÇbÛr—fä]nrXV@# @„*3¤ó%T¶ a‚Áj`Ï °Ø»‘[ëâyåÔ¾ ¨BPí«<ïç, ÛyÊ 78ètªỄ>Øu+ÞŸ€‚ùxù,3 [þb9Lp 8PÎd­¹›nõêÕÝȺ¦—Ko×ììE…nûŠÕ°a‚ÁÝ9À>~Æ •´e¶Öü)‹k¯¦xƒQ±d¶Üýg;À¡û’"ƒÀ_*óÐx:PÄ¥ˆŸj@&*7h¡½ãŽ;Jå¬ÿzÖ¨ ¡ø6,;°¿ï¬Y³¦ÒÕéHÐÆÈ ðÖ­[WIø¹ñ÷£ý¨ëá{>ô¬¨2‰½‹½.Ü™1cFgëÖ­ªŸN7ÙÃp8m`¤y#˜ `!ä¤_×x»õ µáïåÖ_^­…s#‰Ç\æF,jÿ¦M›rN§Ö®]›}.œmDl ò†(â&xVý:·÷XLÙóm›V€Æñ‡‚¼¼ÀÁÆôéÓ3‹°ƒxtÞ^àGs ´Ü h{˜£¼as€ý=s_wû«¶‡òÈîTÍS‡®u r:Ê5`4¡ ùT7õDÀ«?H‡Æ€6t{ÄX§£A|æ5 \ùÿ Àá _0ë”Q…¶/@Åtš½>Û@@×Ù"ð›§ÐY„ü@På1c•ÎMp`P@ÅGèë¨újçc¬ú~TZÛn߀†Â¾ÌÁ ˆ†À{4óZf :òcy‚Ê E°à¡â³¥m"¼È·ûØ*{9ég_û 4\×€Vr\B®Ž¡Ž%M€îð$K<  ¯¤*¸ÁarÁež³Úu óœ—zØïKS®[FSú¾ ƒ1ÜrBíç%"V~AŠtΙ3'³¬þhœ ÀX˜ƒ hBlšäkÊ$„ž¿©Ðr>€Ðs/* MÛV'ß@€¡|$•á‡T#PPû±|fKø¦°Ê\âN¸n›@8™Ã<–ù×Ô>–Õ‚¯¶ ¨ŽsÀÁ€Ç}8~Ô¨ôŒ@äi‡XÀ@š.` -ghÒ2˜83íËæ+s’E ·‰zïëdž®_¿¾óøã·v•×—ßÄ?P  ‚ òñ¸h0\ûÿ´S€î0 hº`Ae¬Â”v @ˆ­BÊÍ{07R-F¬øm¬ÎlcúAîù~•ùjŒÔ(´Vm ‹°¢À|€[d¼f e¢°5` <5М3`„ÐàÌÔ4Ò5G˜s½®òâ$ÚÏðÙö–ÍaÑËÐaVy¶Ü@]÷AÅ¢%H+À-3–ËFТ  `À xP‘† PÀ[ˆeï4´C/ðmöð`µçê;.á64ˆ6Û˜–5T 10f¾ìñSd•G¨9퇡 +=jZ™Ñ*Ï“òi« h{á5´ õ¡`\CS(ãöè¥1ŸdoŸ mÃbîðˆ_B?ê‚/> Ô›bðæÀ ÀúÕœ¼e O· h0ñy2”)ãA0(¤`%úpÇ挷:a?¦m·†¹ÇBÂÂ…àë‰@?ël»*od€!|Ú¿s X&`œl`¼Nkn&@™áœ‹v@^„͵  Ä£yÐÓ8/äøº~ ºo=cÏÜd[É/ ËãÉÆƒ²þLIH‚P XV{ Ç[V „=5¨îZbe ÓdcÂa ‡é—€œ0Fc*?€’I M_++«;“M.ÂîUHŠt1IUW   Š«I*ºp‹9 ^‹ÿðŽqÀÕ¥nqi‘Ps -èdŸ¬ZYpp&¨·Ä)útû@éB À¤¦¬©bÄCžàÒ\YñžxÿTáQÛý h‘£:dcõgrbü$xWéÜ:$^aå' H­V@C´-v¥µ¢ÔõÍ÷Ýûé‡hÔåMùØZ㢠ñØh°ú޳¡ý)HäMr €‚'>N¬¼r}ÏT&qâ3n¿òäÑú:Â?šha\PϽ" BŠWšâäJ½‹_a fžpçã©'óéÞm˜àhaè1B&¡•›§´"WÂÚBÓ¢ˆà@)v½*VJ:ÜÄQŠt=\NEíÁê¨Î«  L:Œ Œ2çCåщ¶•q  ôç’{Y+--¶]ÉSž&#ůžp§6Øj·¥ ¬¾F2ôµãQxp "LF6U$ÝIVìäzÝÎÜôŒ2Ä`€!ª*ä€]2[[˜XPìõ¿”Õ×èAuøzÊÂJóô}e@(çÀÖ… ./'Ù=µ6\rÉ%«­˜‡v/ª¿1EW_Ô/°Ê›Ò¦ñ>œç å`„‡Ào^qÅõ¾.c¬ »zÐDðd$„>NirE£0n}­è}ùE/××þàÀ8ð/Mêmö¶Û§¬²fßÁjÒJË#a“ªΣñé>O·xŸîËU¼\•np`ˆxØþsðëMêo‹/fðñ&6Í#!$¿üB…ë–íó©,•/W4JWا׭7èƒ-sà|ë[ßjôx¾ÐxûÌõ_›³¡åŽç°¨$AùóH|šür=½âp½õ4á ˜·^{íµK›ÖÙÎ?ÿ|ž9þ~ÓŠëæ“À‘¯Ì¯r¡‘Éóû¸”Ni¸ÞBçÓ|Xe„ ¶Øcùÿhõ½<ÙkVިǶ7Ø øßÖ¬³y*x¢8ï—Àú8üÑËÍ‹SšÜ,ãÄâR×Ó„?80 >3ñµè=ͽáÝï~÷œ^êl †>¿cÿ‚sš*¾ñot~øÃ*ªuWBIÁ©0Ö©,Í›†}YiáÔzúðúÁä‹ÿ§äƒ¯2Ú|­…-·)ìaÿ"Án¹å–]ªô^ÝÿV\4Ï3söÙg7ú¾g£LVáŸp"_fÎ:ë,. eÉ,£«“&&àrâ/×—‘—¦+ìËË‹+J'^Vù ´É#Ž8¢³hÑ¢ÎÝwßݹ뮻J‹¶¹xìœ9sÎ5¢J s€©'óO6E†ÿÄ;î¸ã²dþ#aÊ $t©ð_%NÕæµEeCãÓå÷é¢QœhT~¸Á¦à¯ãX<‘æôé§ŸÞY¾¼ü-߉yÈ… ÚP{ ð¡}èVÑ^@‘=öØcwSÿ% MãóIà$€¤).õ+ŸOWœhóÒÒ²–«2Ò°âà Ôáÿ7ùÊW¾²³dÉ’ÎñÇ¿S~¦OŸÞ9üðà eM2hu½Å^®-ϵ5Sýß\¶úÓi\d8ÈÐßcÑÅKØoˆW\‘zÒd¼_q¸Äû´¢°âEÛ&Àùö„rsÁ·ytN=õÔ—gfÏžÝõ¯å9“3Ma¡å/W’ j€ ïün°ÿþû'Õìä‘‚ƒ ´MØ•ª8$á“ÐIø‹sä§HxIU™¢¬öå(¸Á2 C'žxbç”SNÉV÷2Z¶ÔÝd09šgåôL¸÷-B*u¢Š@@ƒ6€å$“CE ËŒ„ROØûÉëÃÞ¯rUF¿Â*7Üà@f̘Ñ9á„:ÇsL¶øåѤqÌã*2gsû°4o·pm À²£ñ袎¸áÄ}zÊîÖYÊN…_ž¦UmåyS(R:_Føƒp wÞ¼yÙÞÞNëk3…›e2‡ü`LÊWМšk€©#[PñQß‹ Ï-›Ê@ë7zaCà%´e§U»|YiœÊ%>¥SX®ò†H9À r ,èp(^&Ài>ææŸFïýMå2j€ Ó |p&¨¾ÞO£iÔAä£+û.ýá&—!€¤€-«BɃ!^†¸4¬4¹E‚œÆ+,·[~¥‡;µ8€luÔQùóçwð÷j6oÞ¼Ë"˜WÞÆó¢+ÅÕJ6mZ©͆ ùePo,gÀ‚f€0JÀÓƒDŸ¦²pSVZ·ø4]a¹*'Ü©Çæä‘GÙ9úè£;¬úm; L{`þmݺµq•€™U¾l ûË€E[†:·mÛ–Y˜"0 =0£6 ŠË«¿Hp/7Í«øÔMé">öØcit­p# „ŒU^+n^­4Ð>WÜ™;wn‡½|¿ màm),õI3Ð@ÒÁÊdâ0eiyí}^ZÄ/˜;¨ó<¶CèYÈe8ß´©ûßü±ÍîEý§?€ÌœÒƒRexüñÇ‚šjmÂ>ñÄYÛË@í©$ÌÞU™>®È/ÚpÇ‹¨ôøÃ;¬3sæÌÒ•·Ÿ½CølæX™AûíöŽ@Y~¥õ¬¬€@·çþlX™u§Y•ÊÕvý†v£%h2‚Ó6 {Ÿæ‹ðhrag!@3d»hß³ÌÜôy­Gígåï&ü¤ÿä'?ÙùÊ^ÚÚP13i<4T*Ðv˜†¶<õÔS™U;À€' rÓ­ƒhÃè©‚ΜCðy¹f„=å ‹ÜU +¿³*ôe4=…#P<á”uŸ7ϰWçd Fi èÖ´&–¶rŽ!×Ó…x`ŒÐäd¥Ù!ðù¨´cVý"™IÛÿÐCuÖ¬Y“F7·ÔÎi<{'Þlbueÿ]t> m•GÕ j1@yO;L@ü¸ØnêÛ¨öu”Û%í FÐÑ:%ðøáû¸æ r‚ÜT™3ЬX±¢õ¯o· '’€*ApSÃÒ@l^XeÇÉ Í”= Чt€(^i¨´,Îbð#è²ÄA7™ #‚Ÿ·°äõ“ùsß}÷uÖ­[——ÜS\«€@°7á9)~Ô0,‡„Ü  Ó©ÐÀ ¶]Æ Š¸Ï ¥‚­€A“Ztrá, ©x\Å+®¨îAÆ{í‡-’úǪí?cK'þš´¨iœð30ðèŸ<Ær ÈÉìT9€“Àt¨¼tø Xâóâ|¾¼úSÁ\…Ó1ó¾ÛÓ²´$ä„•¿êù@š¿J¸u RÏ$Q˜8ܦ²-@#5QÉËeÒЃ¢göÐNu#„ð6Ìèp€9ÍJÏ>¿ÎŠOûPù= ÷£w}JÃy" ȨútLFÛn ¢Þp*„„yºÙúXqĽpG•Ì{0ætúT©J›Yõ9ì« UÊΣéP‚ÌAÛ„µŸŽùŸ•‹C@¬GÐ hX´Ád9'ȈO0GYíÙÆúù]µ7ä{øá‡³íqÕ.a°¢Ã¬ å Ëy¶ )¨ X@·¹¦ÊYü 3Z`ACp™«MV{zƒ,ðǺhËýV÷ó¸×wP¥.d¥×3\T~Vý<ÄL·Œ†– G”G€`c,n‡Û/ è=[TæaSƒà¯^½:»"? ÁW»T(¤ä®+7«=`€6€Íc„ß"  f!ø `ˆ`Ù;ù "qx¨!·0ÇV*l/BO;˜çk×®Í^øa¾ç-~½´·nÞCmbKÀ-@„”ƒ=­à¤ÁdÜ<°•À‚Ä€ Í@`Ày´‚@&´ƒ<ŽF\XhT }BÊ\åTŸÇ”×F™ym¯7p /§þ<ïGø1VpPæ3EŒBƒD° ) @`±¨jX e8r2¶Äq€ù¨ÅƒÕ¾hªË,ÊåÕ^½3J‚¯¾ ¨f °0›Ý?âã(ÂÊ¡¡¸lP¸¸¢ëÇ”  °MP> 0ub¨C`€‡‰[¦ÄsBó—Å¢-£yÍǶtÔü²¾ Ô(@Ú@ºoG°u!ˆA’J&¡VÞHx\ˆÅP¾î  0@ÊðåÝCPÈX5Ö?g\­îygM½t’9ÅCàQñYù5Ïz)wy‡táfßÎvÁõÚ€˜€0¢°m`‹ õ¾Û¡ «;–Û‡ ¼À-Áƒ†dd  íÈkŸò„;0¶Ì/èøû)ˆÌA]m§î~ÖÕ/®Ž¨s¨û0u>ÕDƒË=¶ ÀÁsª}?cÄÁeüð+Ü~m»–HÚ^òšzúq|õl¤€F¡ °OgÕFýïvX'áC¨„UÚ¤Ì ´º…Äc”¢½!ñЦá Ðnü€~¹iž¿ÌÆÞ"hXï—Rب‹yÀ¡[~´–øA¶ãeµï9P^PVñª¬¬Ð@ÏV?“ˆÔA"{À2£ Jl0Ò,@IXf˜´»xh“À@€@‹v’ºeuS‚Œ6å]ù%ì¸Ð S°¨[s…ñ–V8Ì6õ{œGè¸m ®aæÌKh¼lpu~€–€@˜Ún¤[ƒníShG7X¤ @œâIKý «ì4L<ùŠLº}BH½!]B*—>¥ñ„%à¢ó匊Ÿ¶i,q[ú#;*íìg;FÔq¤ ꫊4È‚0³r—i œK`L òË2ŠVÿºí§}Q*„uË ú—8ÀX1¶kž±"£ùðõÔùR++$j?+=&ª>… "PÐDñe°šê£âÉËäP°€C[  :Â-ç É8À <®’©*ìy\›ÒÇ@A‡w·&‹&KûVù}9äõOH#/@ @ÐÄÌ_VøË9ÿá­€š0~ÆÇ {y)S;5 âø³Ú£þóä@ @V„X€€Ë„T.´îéíF_´\¬&³§›ª~ÏKñ!ðúqðþ©Ê¯&ýhÂ5—A'ú„&".ÐD–KP!/š†7Ð ¼ËÄ÷ª¬Ï3N~x#È¥ÏX8ñJ|_é§âƩϣÚÖ€> ¡G}{:‘Æeâ+̹Fqj&é‰_ µ"*W‚}ÛFezW~Ú‹!Œ_Va[´¸Þ¯|ŠË ŠŸ¾r`,@a𬆾¡H(äÇ•‘`pÎ € N«%†_B†+P@“ð A¼ÊSÔ£8ïWºwóÒ§2D¯xÜ0£Å±€ÑbÝî­aÂk”*N®VDïBëÃN¹* 7ÏOÙÜ*þÝ[¾kŒ/#-wWÊ;ZAn,r€‡à Èyn^\mï2ÏßB¢ˆ)Ê—õËg€&þ(6s2oMF‘ßѦö8Ð/Z`b1 …íQip`48ÐÂ8„Уˆž9`gGµŸùÖÛ‹?ÝsKg ˜Y¦l!ÚZ·ÃµÀ*ÙT·’6èÚàb”1É9P[6k€]L¹{LP§¯·[x|‰:ƒø¹ÝYV—µÀ*^þrfÝÒKø¼@RTQ|•j”W´i¸(^trEnp`X0ÍüÇK—.Ý^·þÚð®w½ëy«ìúºõJ°ÉHð|œÒäŠFaܼ¸¼xOçëP¼\_vøƒÃä€ÍÉÏ7©¿6LTò/M*ë%„·ÈˆÆ§ÑçŧùEããGŠ7@ôU†?80hì°kãŸmRi#¸ð o¶É[“ ›æIOåH‹ÒEçÝn´¾Ì<Ú¢t_GøƒäÀ?˜ú¿±I}`¢¢˜[¼7iMI/t)\’e—$/ÈJPœ/Kq¢ÁUº\Åy˜à@›È›‹9åo4 ôÃ9ñ•¢À’%K¾m5|¬R--yf´åO›¥rq½:öþ´ŒÉŽ-ÍhŒb…qxÑžÊý§k®¹fKÓ7*´jþ±9µ=4ml*˜^½_å+./¬´Ô-nšæÃøe}žðÈ\}õÕ_饾žàœsÎyÆ þº@¼ô—»½´¤K^/lÄ¢,UÓEç]ü©¥O“.jKÄúÄí/ÿ½×²{*ÿô§?=ûk_ûÚ4¾8Óo#Á¤žT }œo‡è|\]¿ÊÈsW·ÌQ¦ŸŒ}e~×mŠ1áÿ©üíúÏ-u 2ú½äÙ™eñâŇØç©þÝþ7íÀ5kÖtŽ;î¸ì“Úì]úaù–>‘¥ýQž›W÷ÎFOx4É«¸ÐYŠ#uÊŸçæÅU©;+4~‚@øùļiÞ§œqÆ/Ü{|Å56=ivp•­ü3¨}Ó¦Më®».ûcÏÆ­é’QBY]áIé}UiZ®BëiÂèвùÓæ'Ö¿x÷»ß}v/u5»¸Èþ ë|_ù–-[:_úÒ—:k×®õÑ­ù%˜*Pa¹uãÓ|äWœwñ˦4>^õ‡h“Ì1Ÿ•ßÓö0PøÂE]ôÒÿÝûÄŠþÆ`ßÀÿT^|Mà¶ÛnÛùÌ<º&q6ÜÔ(-'œG/:¥ùü>®ˆÎÓ‹&Üà@›`Ž™gÿL]tÆfg‡Ûg繓ÓÈ4€Ë/¿ü•Û¶m;±¨Fn{“RÁ+Ê[5^ˆëMöiÞïé¼_4ŠÃõ~ŸîÓ?\«L†¾Œkø/‰ÓO?=k> PdH³¼Ï´€#‹hÊâ}ØãþŠ¿È*3‹-Êþx P}•4/p~’ïꓸ4Í·%ÏOœâåª<¥ÉõñUÚ4Á*˜={vùáoí8à€ÎÍ7ßÜ-Û¾ö§3¿gDÙ0MoVÈ›ø¬"zrÊ);“SáÜ™PÓ“ ¤p¥ù8_¼Ò‰«ã‡6¥W8Móõ³_ýç>ŒcÛùÿH;ÙÏž¦If.\ØùÁ~}v¾¬O¦ üŽ¥÷®¸âŠ}×­[w¨þ™&¯QGqÄήñéL,¾y¯Gy>­Šß \‘ ûr #‰÷»Ì¯4Ü<¿Êòij¯?üÁ*`•?í´Ó:'žxân²Ábº`Á‚ÎÊ•+K‹²CÂc.½ôÒv-¸œ0)¥¶pä‘G¾î‰'žÈþÔ2)kgpÖ¬Y;ý©¡aß‚«?ÕLiª„É/á.òw+‡|2øÓp^šèD«°h'ƒ`6˜QäOaÑ”O8á„Ry:üðÃ;?þxi£8|·ÅõuFÔ_°‹Ç•©ÿ´DëfÐ8ÙáüŸ²|^Øü$­\ÕSöõA¯°ò¤a•np Œ,¨öóçÏÏæ-iÈS7™CŽL¦æv++M¯­jíÓ­1´²¼0Ú0à`±[Ù*ƒ:$øÄù°÷+Mùª†}ðû°ÊHã|ã쟬ýæ˜  GuTçä“OîvØaµš‚|T‘ ·z[+šÀöÿe“D×bëô5†¼¨ÇÁêT½~Åù°üä%݇Užò…•×ÓÉ/×Ó¨œpƒžÓ§OÏõtMÞ§Uõ#Ý0Sûjÿ®V¡E6ù_¤Sk‘™¸«\I½IË@¸è0Ô´ëÆöJø1¤#иò«Œ4¬xå#=5iaYO«8OŸçó„jr€ÅËÎÊ2æÌ™¹ PUÎ0Ƕoßž{¨®2Ð&¦6PÉ´iÓ2!)«póæÍ/z1 ÇJ+ üá!` @HWz˜——¶©H«Ä‹&-3ÂS‹,T=j~¯Bï9Ç?OóÔ¬LxúéæÿÕÓx^ ê”F4}䗖͆H+ 8@úIØS7- ¡-2E­øÔ-*gœãá_ƹom¶ýàƒîpiÁŸ1cÆn‹Mumܸ±Tø©ƒwpššFÀ Œðñjb™á Á^µ€¼òÙb`) -h%¸M^ «Ë&h”.z¥‰Þ§Ëïi<]?Îá<~ŒsÚj;ÛP{.sçέô´«—ºYD‹²ÕŸ—„ìZ~ãjµ!léÛIi+ìmÁV‚™¦·¶—!2­Í€¢.@H'!ö®ÚàãäWšw•–ºžfÜý“Ah£h¯œwñØŽ…ŒÓ{i—ýcd˾³‘m}ËêZ¾|ùίŒ®(­1 lhÝ´ThËn5®n4™pyåŒB\«ç(ô£¬ ô‘EGÐq ͇²²ÚLãl áï6ŸXxÛxã¶'€Y2&Юs(Èj<,Pé©‚Ú€ð”K˜• ÌäCý¸¥u›|ãÖY1÷°l±ÃXÝËxÇ~9©Âÿûî»/[|ËÊ«’ÖPÌE°®'Ÿ|²°N:ÅvõkØH«†‚¤€‚7h muˆ•6û¶†ÿe0V,Hhx¬æœa±ý|¹Í|¨óØ*ÂÿðÃwÖ¯_߬¢$WÏ@yì½a4@€º¯=xRWD瀃ƒ„l `ÆE§ô² €e¢ÉÀ0Ø„ßhh:Vg;9áq3,@,Œé\+êǪU«:@[¦ 1œ G}tÖ:U„hhöJq¶ïâ”u\VV€›wðI˜œü ¹Ü*¨že‘µ{ÐÍh”Ò¾äò4¡ÇMŸì ºmÕÇœ`¡ä~ÕùñÈ#´*üô¥5 0n$1P 17¢¸$ÐIÇ:M<ê7‡0ƒ> ômiÃO&îc—' €^‚æ]øDvX¦­ºé‹sB+7a„+?é;îT0ìõÙ.sH]Å0'|ðÁ«[c£z[ EÅ¥p•[R\œ Ã\l`õ÷&pêÉàs6€J7Ù ‚ífÐ1ð ãOÃišŸ(SV™¸¾-ÐI“Q¥¯¶ËG8õó28áGªªûäD>î¹çžÒóµ—k¨ïk˜4ÜÐcPÓ&a,jééÁtœ€¢=ðHf÷sõÙ_žC‚XN©£Îm·ÛŹ´äY¶lY-ÀHËèn¨@õGàdO«‰Á ðt­¿ ´$,ŽÂ³Yµ-Üà@ ê³àÕ|46öûüÛš]?M_@ F¸¹;Ð#Ø^ýG;àr´T#ÿVôXâõì–}c˜àÀ(sE»e+œwXÜ­íÈÌŠ+jƒF·r‹Òû.Q¬òÔzÎ@EXÆþ‘'X4žáÇ@ 3±z¶ÛƒŒ5ñ3"@»EÍgãi˜´Ý:Í#ߣ>šm›ä¯S—§í;P™Ð{:Ȥ‰V ³€|€4˜¤Ç€šA€Îð’ÌKÍI¿­Ó€ƒ/þ²íí·ºŸ×®#ðò!àºV|è55’3,¥R H 'Ë#šú0Á~r  ¡§}þêÕ«³}Ã|ñh`@…0OïèR.Ìà ¤Eu‡›GŠ@ÀV 0à Ë^ôA3Ðã+u6Üà@] Ž£²€•ÍѪåR—à´âRÝÏkã@€ °üÉë2˜X-m¬ðâå³=å²°GiµW½;T !&Ï>vm |PôUÀaÖÓòˆPº30”‡Å üy/Ÿ(øÑ/?Âȹ“,BŸø6 å1·˜Ç?+Ûu´Ù^_ÖЀÆÀ,”bKwáAÔþz€@Öw(õ£MèžiiÞ†&5ô-àÄyCXtÞO¾4¾*Η1J~Ú¨q”«y’òb”ÚÝf[Fèl[ƒÁÄç©+=atˆ[ ò³ziòTÕÈWÅÐoÚ‚Ã4ç"츺üÐ`ÅKùG­/£Üž±€Qe¤ሼIéÁ@~èð“`ÐB}Ôd×ʆ«ÉHŒëdW¿åŠr%Ü„¡Q?½+¿xns4ç]åœÒ4¡5Ó°Ÿô¤ù-•ù|R¥§.é*ܶŒÚ¬òÔ&Õ¡>ˆÉU¼\â•×—éýYæøé+úÊÞz…û-~¬„„’¼Í­… á¦~…I ¤AàÇúòäÇõ~꥜4.¥óéÞ¯v+Žp˜Ñá@@ c!a Ư°\ѧ‰Fì]è$¤Ê§tòáǨînþ4°LZñ>NtáN>´0¦º5&AoÛE1!”- V± v½&¶KÒh$£Õª—ZãU÷Ql_´)8PÄ€"ÎD|p` p  …A  &FCá@m°ým{Ï”jt9¶5˜¤S’¶•¿ªšÃ•Ú`•<•SNߣúÎâ¨`Ì9`2²µnj€ÝzÛT·’6èGÚè_”è•&#OÔ-£6Ø#¯{¬’Ý?…S·æ1 ÷ ƒ¿(gc0˜S ‰¶8ßY·›µà²Ë.{Æ*¹«nE½ÒëÙº/GBéÓ§—ùZŸOe)Òòâ‹Ò”wÝÉb“¡=Ì'.\¸¼nþÚ@Æè¥u+j‹^)!Ì+·ˆFñäñùS¿«ü4¯häŠ.ÜàÀ08`2yíW\Qû€¾X?kv /³{ƒ½ð)Ýlj®Ìõô©?¯LÑ䥕ÕiÁ>ràE»þÉ&å7€%K–¬7¸²I…Mó ž±N¹*ËçQœ/OqÐ)>u}ãì÷}ç~LѶ/ý¾pw“¾7*2Äù 9ÛšTÚ$¯J^?™å—«ü¾¼4 ʼnN®OKý„ÃÌgí VÖ´ÎÆð®w½ëq«ô¿6­¸I> a*œ”¥4•+¥åÅû4Ÿ_yå*o}§p Ÿ°½ÿ»úê«jZGc ÂÅ‹_eεM+¯›Ï []?uù8оð¹Ï}îã½”ÓP±}Êêw͹½—FTÍë…<ÒÔß­<å«ê¦åùv¨Œ”&ÂÁ>sà;öEëß鵎žà-oyËÛƒ\` á‚P_6ùåR±ürË#š*.4Þ¦u©Œ²ú"-8ÐLíÿ͹ >ýéOïèµÌž€œwÞyí¢Î[ÍÛ× BeBØ+#ÊòKÀó\Å•å‡4›TãÐÌhc§óÿlåÿÕk®¹fKÌhhÈù矿É>aõ&ˆÚhX^^ØäoêR~Y^ÒdËh}þ0Á>ràû"ô¹ŸúÔ§^úÿú*j hË\`¤úôo˜à|¤…¶íV„HŸH|žIã–KùS·( ºÔB+(\Ó'=/¾jœ/;¯Lçi}ùãæWŸÆ­ÝS ½Ëmqyƒ _ÕÖ@òö·¿ýzó¿ÊìW׫›'lš¸©[§.å%÷« ÅáùEnp %ðo°ÿËþxöÌÏ|æ3µßò«Ú†¾~ømo{ÛZkȯûÛß¾ØP ›]µaet!*wêú¹lÙ²ÿ`Œú/þ5³»l˜¤X/øi˜2•Ž¿ÈÏ•­8…=]QœòŒ«ëû8®}Ñvßg¼ý¸Ù«®¼òÊm£ÖÆ‘1Æ©üvùòå3Ì]bö2³o0&îÁD•µ¸]x/ø„Eãód‘?¢IãÒxå÷ñyq¾œðOY¬´žsféÇ>ö±ïŽ2F<³N>ùdnòé±+z衣̽оDt‘ Þ"„Ï3r ½\"I÷áŒp"^~¹E‚ìãñˤñ>M4ãæÂ«ÉÐ!ò}µñïËf—þÓ?ýÓ÷¬/O˜!6ª[Õ# ¾ñÇüj ÿ=vÕªU§Ú„E38×þ;PÙÓ ;ÀàþüLtlžQZ^ºO“?¯ŒqŒËëï8öc€mf±—¿ÉæÛuùÈG¾oþüI5ÀFÕ­jlÀwlþüù÷ZûkÖ¬™aß#x«Mà_µð¯›+áÔ¤NÃF“™¢ø¼ô"Ú¢x•1.nh•FŠÅú¦ñêÓD¿öÑ~tM¥\#L4–àù9oÞ<¶ üOÁRÆ=7oÞ|¦¹~»Ùט}…ÙÆ ¬ü$ÊïÝ™§‘?!» ý³žµ˜˜½ÙøsÓôéÓÔäÛû»•:Bcž—†Ìü1Â'ì_Ú ím/SðBÒ¯Xçg›–Ù] “¿W»Kc ´õö{§ñâ»¶­üž=–þ¡­ò?Ãá¬ÜäIi¯m ùCÞ¤Âþ½ ùvÝò$SßYøW̾Îì fwyÔháÌ”‚häB;ÎfÜÛ߀÷ÏYž{mŽ|ßú~ûÞ{ïýÝ~ðƒœ3M)3© Il¤”ˆØ&ÝßÇü;È9ÓügZ­á ³…ñ¶pLŒ7YƤ¹u›Éç³î3{§·ð–í·ß~÷˜:?Ð{÷u=ú)y µ‰Ï$X6a¯‚Æ&ÉžëÖ­;Á&Ê«,ýt‹:Ñ,šî~fÃŒ&Pá´1š÷r®IDAT{ÐÆn¹:§ôw™ å/íG“E»¶jÊÀ®ìx)dˆ³„&ì=ÍÊ•+ݱcÇ/HœbtÇš{¬¥c¹¾àà™Õÿãû#Æw^*ò²/³ðƒ&èOõ§ÊÉ[j| ¶Å±ýÉO~r¨}0˜k+гDæ(,<ßܽÍÍÔíª®åÉZ‰ëýD¦q>ÝûÛ¤ícYÜ—_g|yÄ„œÕ|§Ÿx ?ò|u>LKh‰‘UŠù⿸—=¶<ÂN—çýL{l†Mô™6ágØŸi‡“‡›;Cá w‹ËŠÇõ~"Ó8ŸîýÝh»¥×)k‚ÖœQ½7[?6ã7•?q-Lp7Y¿7Ú!Üš÷¿ÿýÌ… Èì&U]ýõÓL@ö7a9Èè`sñhvº•·¿ Ô"‡Lø÷§Kƒnç“ £!~?‹#³—ÅAívËÿ3 ¿”bûnqψÖ\2m%Ýèž·¶ûJï^|ñÅÌy…zú /ìiéÓƵðAF·Ùç̿åýÂÂO¹pÇòoÛk¯½Ìyág¿øÅ/¶ï»ï¾ÛöÞ{ïg—.]úœ§ ÿøq `ÈcvöÙgï}ÀÌ4¡›i<Ó„l– å¬=÷Üs¦5m¦ùq1{à„Å€>Øì0Í Vù6³ÛÍ>;á~Öú³Åú²Éü›¬/OÈO{à 7à†2ú8]tÑa?ýéOç™Ï·jæ›PÌ3÷(³ ÌÎ6;Ël¶j›;Õ à‘¹kGkŒ?«Ì¿ ¿i«M³Yi@°„éz`¬ ø¾&àÇØ„=É&ï‰VÔ æ.°0‚޳J‡éÆË'§«Í]ešÄcVÔæ_aà°âµ¯}íê+®¸ Ówá…ÎyþùçO± x‚M>}á„Àmþ½+$ýág+&샃ùï7p¸ïë_ÿú.çý©~üK HÆÐÕæšpŸi“éLK’“Epô9°Þšx'ÖÆóN…e_ýêWýf¶…SLØYÉß`Âþjcûéf_evÚ`‡`°µí·ß~¹Ú!]Ç´œÜ´I¹Áúr—÷M›»Óžl|ï_ÿõ_Š)k¦ \~ùåû¬_¿þLøEfÅ&Á"uáFÊXÛ:ûï¿Aµ§™_a›°{R¥ábí‘\ç¯xEǧ©CŠS¸®û³Ÿý¬cý²lƯŽwd A¼­¨;éÇŽçž{®ƒûì³Ïvžyæ™Q—‡­ƒß3û]ãý÷®¿þúåæ1ëôø™´`×ö;øàƒßh÷ͼåkÍî?¬1EX­=iÓ¦u:è Ì+!ÇEèv@`²4 @ (ÈO=õTfŸ~úéÎöíÛw‚Îx°ÙæÌm6ß5÷›gžyæ“ù qRÍ´w¼ãÇÚã£smà~Í&Ï[Íò¼| Æêízè¡;-‚.Ç`‡éλ Aî“O>ÙÙ²eKgÛ¶m\Lê^P{OXQ7 |Ýê½i²Ý_k`•Ÿ>}ú›mÒœkƒ„儾o†•¡FÐ;ì°ÌJ艟Œ+wߘٰ`„ëÖ­lÞ¼9sm¢Ïæ›kwØ3Î8ã‡ã®Œس÷½ì°ê-6ЗÙ`\`n_nÃÙ!Q&èGqDgöìÙ;-ª|˜Ñ䇘O<ñDgÆ ™Ý´iS«sŒ>´z³•ù%›‡Ÿ5Í€s„±;; @èí@ém†º¿eLþ ³­ÞžC}GÐçÌ™Ó9üðÃ3Ë „op@  €Ãºuë:7nä}‰V;fss¥•ùE³Ÿ70øQ«…÷±°‘€Å‹Ÿn ý}³Z;±çÀmîܹ#<2³?'æa¦Ð‚µk×vÖ¬YÓ±§Cžl´h´²®±…åŸí1ãšËm½¨‘®×Úý¦ ýZoßÐF<ðÀÎÑGÝ™7o^&ð3fÌh£Ø(c’p€s´aåÊ•U«Vµ?7}Åæò?šVðMó·«v´Àÿ‘®Û _fªÔ¶~q—¾±±225¡?öØc3¡'.Lp  4„Gy¤óØceà`B\%kÍ +ãSVö•v#qKá Ó†.öèîTS¿ÿÜ:ÍÞ¾±Îc¶ãŽ;®sÌ1Çtü¢oƒdnÔ598À£G€@€À¹BæiËûÌ~ø+_ùʆÊi%ëÐàüóÏ?ÆVå?µ^üžÙF‚Ï ¸ã?¾³páÂLðãЮ•9…”pág›°lÙ²ÎC=ÔˆçL#ø¤ÉÀ‡† |Þ‹ÿ3ãñïš­ý&'ö ,È„þÄO̮ÖŒW$úÆ®F<ð@çÑGmzA‰§|Ô쇯»îº­}klAÁ;Ü›nòþÒ:úÖ–} ÚSͳx»xÑ9餓Bè ¹ Ãâ—î¹çžÎ]wÝ•Ý`lÐŽm–çÏíæã?~ë[ßêiQ§îAÀöÖÝo›àÿoSyø Neã9Ô{ŸÇva‚£ÎÑ ž&Ô=<49Yn—~ïÆo¼}}í+œwÞyGð,Ô:òŽ:á9½½„Ñ9í´Ó²—eêä ÚàÀ¨p€«Ê?þñ3Í ÎÁ¡Æ‹vžõQ;|üÓü[[ïZßÀVýwZ'xìQù¡;'÷¯yÍk2á+·­u8$ð†ãí·ßžAkÉ&?«íÑøyöØðÞ~5½°‡ôý±5øš:S©|„ýÕ¯~uçu¯{]ön{¿:å†ÉÞlüþ÷¿Ÿ[…Šæ¶~ÿ—¿üå¨H_‹¬’€V-ÑÿkìÿµÎñf^W>°¿_´hQ<·ïÊ­ ˜,àÍÅû·ËžTí“ÉÕµ—V¥¯Jר…žCm%¿É„ÿ¬*•sªÎ9çdoÙU¡šàÀdãÀŠ+:·ÜrKåט îš5kÖk¯¼òÊÖ^\hÎ=÷܃mÿ~»íoNé6H\Öùå_þåÎë_ÿúxÛ®³"}Òs€/$Ý|óÍÙ]‚*µCõ‡í"ÒÉwÞyg+ Ð3ðòŽZ~Ó^àéúâ×um›]ä©ÒÙ  LÜ}÷Ý[o½µÒÍBûäCvïàTûôùO{åOÏ/¼›ð²Šðóžý{Þóžþ^G,òOJ¼êU¯ê\|ñÅ•>gòv¼}Oò6¾“Ñ+3z€%K–\b¹¬[#x ÷’K.É>ˆÙ6ÒƒS•\v»ôÒK³Ævã]C~µ \Ù®[zc±ÇüÓl?òmÛ÷—~#‹mReŸ¯îÖ˜HLu°Mæ·ûï¿¿ë7 ìÀý {|~—]A~ )ßk‡rÈ'lõ/ýê.â°÷üCø›ŽNä›’àC³\pA×Cr.٠ë.»ì²Ê—íR†6Òx±ÇT« „güöI¯Ž=¶HëŒpp 8Ð…úÊ4ÁWØ“µ}ï½÷Þo”Ñ¥ pQâ탙4ôÙ !/²¼µÇk»a‚Áf°?Î>=_$cÄÛ!<ömQ>¢I-µßǧ«ð7˾¸CøÝ&8hÎ;äËîËpk°‹±;xû¼Çhþ¦ Ýnɵ5€?ú£?:Ð^P˜Í×xŠ,§þìc‚½q€Þp–V$kÄó.-Ê7©©6Ìœ9ó|•§¬AóçÏoÒ–È$@Öø|}™¼Mhã§q6—d﬽0´9“Æ”{BP–iÁà@  Mó÷geÆnîi[ïS†(ªlj€!ÒŒn€J&8h‡Zý»•fgµ¹ÕÛ¼Ø ê|ý¤[§"=80Õ9`ú²-@&žðQÒÚÿ“Yì¦ÒÓeOh$ÿý&8h‡¼1X&sv!/«ÈîÔ~¹¯6Ø›HÏØ‹¥×ù_wn)ñ#Lp 8М|m˜¾L놦©© TÄ-%¾sVføêIÜ,ãP¤ºs€2.~JèEãnÓ¦M+Õh_Då/¶C €a‚õ9€êÏê^hÚÝž”ÕÜx6ɧ»©¼Ì€^¼ &8¨ÇþøÇbÛr—fä]nrXV@# @„*3¤ó%T¶ a‚Áj`Ï °Ø»‘[ëâyåÔ¾ ¨BPí«<ïç, ÛyÊ 78ètªỄ>Øu+ÞŸ€‚ùxù,3 [þb9Lp 8PÎd­¹›nõêÕÝȺ¦—Ko×ììE…nûŠÕ°a‚ÁÝ9À>~Æ •´e¶Öü)‹k¯¦xƒQ±d¶Üýg;À¡û’"ƒÀ_*óÐx:PÄ¥ˆŸj@&*7h¡½ãŽ;Jå¬ÿzÖ¨ ¡ø6,;°¿ï¬Y³¦ÒÕéHÐÆÈ ðÖ­[WIø¹ñ÷£ý¨ëá{>ô¬¨2‰½‹½.Ü™1cFgëÖ­ªŸN7ÙÃp8m`¤y#˜ `!ä¤_×x»õ µáïåÖ_^­…s#‰Ç\æF,jÿ¦M›rN§Ö®]›}.œmDl ò†(â&xVý:·÷XLÙóm›V€Æñ‡‚¼¼ÀÁÆôéÓ3‹°ƒxtÞ^àGs ´Ü h{˜£¼as€ý=s_wû«¶‡òÈîTÍS‡®u r:Ê5`4¡ ùT7õDÀ«?H‡Æ€6t{ÄX§£A|æ5 \ùÿ Àá _0ë”Q…¶/@Åtš½>Û@@×Ù"ð›§ÐY„ü@På1c•ÎMp`P@ÅGèë¨újçc¬ú~TZÛn߀†Â¾ÌÁ ˆ†À{4óZf :òcy‚Ê E°à¡â³¥m"¼È·ûØ*{9ég_û 4\×€Vr\B®Ž¡Ž%M€îð$K<  ¯¤*¸ÁarÁež³Úu óœ—zØïKS®[FSú¾ ƒ1ÜrBíç%"V~AŠtΙ3'³¬þhœ ÀX˜ƒ hBlšäkÊ$„ž¿©Ðr>€Ðs/* MÛV'ß@€¡|$•á‡T#PPû±|fKø¦°Ê\âN¸n›@8™Ã<–ù×Ô>–Õ‚¯¶ ¨ŽsÀÁ€Ç}8~Ô¨ôŒ@äi‡XÀ@š.` -ghÒ2˜83íËæ+s’E ·‰zïëdž®_¿¾óøã·v•×—ßÄ?P  ‚ òñ¸h0\ûÿ´S€î0 hº`Ae¬Â”v @ˆ­BÊÍ{07R-F¬øm¬ÎlcúAîù~•ùjŒÔ(´Vm ‹°¢À|€[d¼f e¢°5` <5М3`„ÐàÌÔ4Ò5G˜s½®òâ$ÚÏðÙö–ÍaÑËÐaVy¶Ü@]÷AÅ¢%H+À-3–ËFТ  `À xP‘† PÀ[ˆeï4´C/ðmöð`µçê;.á64ˆ6Û˜–5T 10f¾ìñSd•G¨9퇡 +=jZ™Ñ*Ï“òi« h{á5´ õ¡`\CS(ãöè¥1ŸdoŸ mÃbîðˆ_B?ê‚/> Ô›bðæÀ ÀúÕœ¼e O· h0ñy2”)ãA0(¤`%úpÇ挷:a?¦m·†¹ÇBÂÂ…àë‰@?ël»*od€!|Ú¿s X&`œl`¼Nkn&@™áœ‹v@^„͵  Ä£yÐÓ8/äøº~ ºo=cÏÜd[É/ ËãÉÆƒ²þLIH‚P XV{ Ç[V „=5¨îZbe ÓdcÂa ‡é—€œ0Fc*?€’I M_++«;“M.ÂîUHŠt1IUW   Š«I*ºp‹9 ^‹ÿðŽqÀÕ¥nqi‘Ps -èdŸ¬ZYpp&¨·Ä)útû@éB À¤¦¬©bÄCžàÒ\YñžxÿTáQÛý h‘£:dcõgrbü$xWéÜ:$^aå' H­V@C´-v¥µ¢ÔõÍ÷Ýûé‡hÔåMùØZ㢠ñØh°ú޳¡ý)HäMr €‚'>N¬¼r}ÏT&qâ3n¿òäÑú:Â?šha\PϽ" BŠWšâäJ½‹_a fžpçã©'óéÞm˜àhaè1B&¡•›§´"WÂÚBÓ¢ˆà@)v½*VJ:ÜÄQŠt=\NEíÁê¨Î«  L:Œ Œ2çCåщ¶•q  ôç’{Y+--¶]ÉSž&#ůžp§6Øj·¥ ¬¾F2ôµãQxp "LF6U$ÝIVìäzÝÎÜôŒ2Ä`€!ª*ä€]2[[˜XPìõ¿”Õ×èAuøzÊÂJóô}e@(çÀÖ… ./'Ù=µ6\rÉ%«­˜‡v/ª¿1EW_Ô/°Ê›Ò¦ñ>œç å`„‡Ào^qÅõ¾.c¬ »zÐDðd$„>NirE£0n}­è}ùE/××þàÀ8ð/Mêmö¶Û§¬²fßÁjÒJË#a“ªΣñé>O·xŸîËU¼\•np`ˆxØþsðëMêo‹/fðñ&6Í#!$¿üB…ë–íó©,•/W4JWا׭7èƒ-sà|ë[ßjôx¾ÐxûÌõ_›³¡åŽç°¨$AùóH|šür=½âp½õ4á ˜·^{íµK›ÖÙÎ?ÿ|ž9þ~ÓŠëæ“À‘¯Ì¯r¡‘Éóû¸”Ni¸ÞBçÓ|Xe„ ¶Øcùÿhõ½<ÙkVިǶ7Ø øßÖ¬³y*x¢8ï—Àú8üÑËÍ‹SšÜ,ãÄâR×Ó„?80 >3ñµè=ͽáÝï~÷œ^êl †>¿cÿ‚sš*¾ñot~øÃ*ªuWBIÁ©0Ö©,Í›†}YiáÔzúðúÁä‹ÿ§äƒ¯2Ú|­…-·)ìaÿ"Án¹å–]ªô^ÝÿV\4Ï3söÙg7ú¾g£LVáŸp"_fÎ:ë,. eÉ,£«“&&àrâ/×—‘—¦+ìËË‹+J'^Vù ´É#Ž8¢³hÑ¢ÎÝwßݹ뮻J‹¶¹xìœ9sÎ5¢J s€©'óO6E†ÿÄ;î¸ã²dþ#aÊ $t©ð_%NÕæµEeCãÓå÷é¢QœhT~¸Á¦à¯ãX<‘æôé§ŸÞY¾¼ü-߉yÈ… ÚP{ ð¡}èVÑ^@‘=öØcwSÿ% MãóIà$€¤).õ+ŸOWœhóÒÒ²–«2Ò°âà Ôáÿ7ùÊW¾²³dÉ’ÎñÇ¿S~¦OŸÞ9üðà eM2hu½Å^®-ϵ5Sýß\¶úÓi\d8ÈÐßcÑÅKØoˆW\‘zÒd¼_q¸Äû´¢°âEÛ&Àùö„rsÁ·ytN=õÔ—gfÏžÝõ¯å9“3Ma¡å/W’ j€ ïün°ÿþû'Õìä‘‚ƒ ´MØ•ª8$á“ÐIø‹sä§HxIU™¢¬öå(¸Á2 C'žxbç”SNÉV÷2Z¶ÔÝd09šgåôL¸÷-B*u¢Š@@ƒ6€å$“CE ËŒ„ROØûÉëÃÞ¯rUF¿Â*7Üà@f̘Ñ9á„:ÇsL¶øåѤqÌã*2gsû°4o·pm À²£ñ袎¸áÄ}zÊîÖYÊN…_ž¦UmåyS(R:_Føƒp wÞ¼yÙÞÞNëk3…›e2‡ü`LÊWМšk€©#[PñQß‹ Ï-›Ê@ë7zaCà%´e§U»|YiœÊ%>¥SX®ò†H9À r ,èp(^&Ài>ææŸFïýMå2j€ Ó |p&¨¾ÞO£iÔAä£+û.ýá&—!€¤€-«BɃ!^†¸4¬4¹E‚œÆ+,·[~¥‡;µ8€luÔQùóçwð÷j6oÞ¼Ë"˜WÞÆó¢+ÅÕJ6mZ©͆ ùePo,gÀ‚f€0JÀÓƒDŸ¦²pSVZ·ø4]a¹*'Ü©Çæä‘GÙ9úè£;¬úm; L{`þmݺµq•€™U¾l ûË€E[†:·mÛ–Y˜"0 =0£6 ŠË«¿Hp/7Í«øÔMé">öØcit­p# „ŒU^+n^­4Ð>WÜ™;wn‡½|¿ màm),õI3Ð@ÒÁÊdâ0eiyí}^ZÄ/˜;¨ó<¶CèYÈe8ß´©ûßü±ÍîEý§?€ÌœÒƒRexüñÇ‚šjmÂ>ñÄYÛË@í©$ÌÞU™>®È/ÚpÇ‹¨ôøÃ;¬3sæÌÒ•·Ÿ½CølæX™AûíöŽ@Y~¥õ¬¬€@·çþlX™u§Y•ÊÕvý†v£%h2‚Ó6 {Ÿæ‹ðhrag!@3d»hß³ÌÜôy­Gígåï&ü¤ÿä'?ÙùÊ^ÚÚP13i<4T*Ðv˜†¶<õÔS™U;À€' rÓ­ƒhÃè©‚ΜCðy¹f„=å ‹ÜU +¿³*ôe4=…#P<á”uŸ7ϰWçd Fi èÖ´&–¶rŽ!×Ó…x`ŒÐäd¥Ù!ðù¨´cVý"™IÛÿÐCuÖ¬Y“F7·ÔÎi<{'Þlbueÿ]t> m•GÕ j1@yO;L@ü¸ØnêÛ¨öu”Û%í FÐÑ:%ðøáû¸æ r‚ÜT™3ЬX±¢õ¯o· '’€*ApSÃÒ@l^XeÇÉ Í”= Чt€(^i¨´,Îbð#è²ÄA7™ #‚Ÿ·°äõ“ùsß}÷uÖ­[——ÜS\«€@°7á9)~Ô0,‡„Ü  Ó©ÐÀ ¶]Æ Š¸Ï ¥‚­€A“Ztrá, ©x\Å+®¨îAÆ{í‡-’úǪí?cK'þš´¨iœð30ðèŸ<Ær ÈÉìT9€“Àt¨¼tø Xâóâ|¾¼úSÁ\…Ó1ó¾ÛÓ²´$ä„•¿êù@š¿J¸u RÏ$Q˜8ܦ²-@#5QÉËeÒЃ¢göÐNu#„ð6Ìèp€9ÍJÏ>¿ÎŠOûPù= ÷£w}JÃy" ȨútLFÛn ¢Þp*„„yºÙúXqĽpG•Ì{0ætúT©J›Yõ9ì« UÊΣéP‚ÌAÛ„µŸŽùŸ•‹C@¬GÐ hX´Ád9'ȈO0GYíÙÆúù]µ7ä{øá‡³íqÕ.a°¢Ã¬ å Ëy¶ )¨ X@·¹¦ÊYü 3Z`ACp™«MV{zƒ,ðǺhËýV÷ó¸×wP¥.d¥×3\T~Vý<ÄL·Œ†– G”G€`c,n‡Û/ è=[TæaSƒà¯^½:»"? ÁW»T(¤ä®+7«=`€6€Íc„ß"  f!ø `ˆ`Ù;ù "qx¨!·0ÇV*l/BO;˜çk×®Í^øa¾ç-~½´·nÞCmbKÀ-@„”ƒ=­à¤ÁdÜ<°•À‚Ä€ Í@`Ày´‚@&´ƒ<ŽF\XhT }BÊ\åTŸÇ”×F™ym¯7p /§þ<ïGø1VpPæ3EŒBƒD° ) @`±¨jX e8r2¶Äq€ù¨ÅƒÕ¾hªË,ÊåÕ^½3J‚¯¾ ¨f °0›Ý?âã(ÂÊ¡¡¸lP¸¸¢ëÇ”  °MP> 0ub¨C`€‡‰[¦ÄsBó—Å¢-£yÍǶtÔü²¾ Ô(@Ú@ºoG°u!ˆA’J&¡VÞHx\ˆÅP¾î  0@ÊðåÝCPÈX5Ö?g\­îygM½t’9ÅCàQñYù5Ïz)wy‡táfßÎvÁõÚ€˜€0¢°m`‹ õ¾Û¡ «;–Û‡ ¼À-Áƒ†dd  íÈkŸò„;0¶Ì/èøû)ˆÌA]m§î~ÖÕ/®Ž¨s¨û0u>ÕDƒË=¶ ÀÁsª}?cÄÁeüð+Ü~m»–HÚ^òšzúq|õl¤€F¡ °OgÕFýïvX'áC¨„UÚ¤Ì ´º…Äc”¢½!ñЦá Ðnü€~¹iž¿ÌÆÞ"hXï—Rب‹yÀ¡[~´–øA¶ãeµï9P^PVñª¬¬Ð@ÏV?“ˆÔA"{À2£ Jl0Ò,@IXf˜´»xh“À@€@‹v’ºeuS‚Œ6å]ù%ì¸Ð S°¨[s…ñ–V8Ì6õ{œGè¸m ®aæÌKh¼lpu~€–€@˜Ún¤[ƒníShG7X¤ @œâIKý «ì4L<ùŠLº}BH½!]B*—>¥ñ„%à¢ó匊Ÿ¶i,q[ú#;*íìg;FÔq¤ ꫊4È‚0³r—i œK`L òË2ŠVÿºí§}Q*„uË ú—8ÀX1¶kž±"£ùðõÔùR++$j?+=&ª>… "PÐDñe°šê£âÉËäP°€C[  :Â-ç É8À <®’©*ìy\›ÒÇ@A‡w·&‹&KûVù}9äõOH#/@ @ÐÄÌ_VøË9ÿá­€š0~ÆÇ {y)S;5 âø³Ú£þóä@ @V„X€€Ë„T.´îéíF_´\¬&³§›ª~ÏKñ!ðúqðþ©Ê¯&ýhÂ5—A'ú„&".ÐD–KP!/š†7Ð ¼ËÄ÷ª¬Ï3N~x#È¥ÏX8ñJ|_é§âƩϣÚÖ€> ¡G}{:‘Æeâ+̹Fqj&é‰_ µ"*W‚}ÛFezW~Ú‹!Œ_Va[´¸Þ¯|ŠË ŠŸ¾r`,@a𬆾¡H(äÇ•‘`pÎ € N«%†_B†+P@“ð A¼ÊSÔ£8ïWºwóÒ§2D¯xÜ0£Å±€ÑbÝî­aÂk”*N®VDïBëÃN¹* 7ÏOÙÜ*þÝ[¾kŒ/#-wWÊ;ZAn,r€‡à Èyn^\mï2ÏßB¢ˆ)Ê—õËg€&þ(6s2oMF‘ßѦö8Ð/Z`b1 …íQip`48ÐÂ8„Уˆž9`gGµŸùÖÛ‹?ÝsKg ˜Y¦l!ÚZ·ÃµÀ*ÙT·’6èÚàb”1É9P[6k€]L¹{LP§¯·[x|‰:ƒø¹ÝYV—µÀ*^þrfÝÒKø¼@RTQ|•j”W´i¸(^trEnp`X0ÍüÇK—.Ý^·þÚð®w½ëy«ìúºõJ°ÉHð|œÒäŠFaܼ¸¼xOçëP¼\_vøƒÃä€ÍÉÏ7©¿6LTò/M*ë%„·ÈˆÆ§ÑçŧùEããGŠ7@ôU†?80hì°kãŸmRi#¸ð o¶É[“ ›æIOåH‹ÒEçÝn´¾Ì<Ú¢t_GøƒäÀ?˜ú¿±I}`¢¢˜[¼7iMI/t)\’e—$/ÈJPœ/Kq¢ÁUº\Åy˜à@›È›‹9åo4 ôÃ9ñ•¢À’%K¾m5|¬R--yf´åO›¥rq½:öþ´ŒÉŽ-ÍhŒb…qxÑžÊý§k®¹fKÓ7*´jþ±9µ=4ml*˜^½_å+./¬´Ô-nšæÃøe}žðÈ\}õÕ_饾žàœsÎyÆ þº@¼ô—»½´¤K^/lÄ¢,UÓEç]ü©¥O“.jKÄúÄí/ÿ½×²{*ÿô§?=ûk_ûÚ4¾8Óo#Á¤žT }œo‡è|\]¿ÊÈsW·ÌQ¦ŸŒ}e~×mŠ1áÿ©üíúÏ-u 2ú½äÙ™eñâŇØç©þÝþ7íÀ5kÖtŽ;î¸ì“Úì]úaù–>‘¥ýQž›W÷ÎFOx4É«¸ÐYŠ#uÊŸçæÅU©;+4~‚@øùļiÞ§œqÆ/Ü{|Å56=ivp•­ü3¨}Ó¦Më®».ûcÏÆ­é’QBY]áIé}UiZ®BëiÂèвùÓæ'Ö¿x÷»ß}v/u5»¸Èþ ë|_ù–-[:_úÒ—:k×®õÑ­ù%˜*Pa¹uãÓ|äWœwñ˦4>^õ‡h“Ì1Ÿ•ßÓö0PøÂE]ôÒÿÝûÄŠþÆ`ßÀÿT^|Mà¶ÛnÛùÌ<º&q6ÜÔ(-'œG/:¥ùü>®ˆÎÓ‹&Üà@›`Ž™gÿL]tÆfg‡Ûg繓ÓÈ4€Ë/¿ü•Û¶m;±¨Fn{“RÁ+Ê[5^ˆëMöiÞïé¼_4ŠÃõ~ŸîÓ?\«L†¾Œkø/‰ÓO?=k> PdH³¼Ï´€#‹hÊâ}ØãþŠ¿È*3‹-Êþx P}•4/p~’ïꓸ4Í·%ÏOœâåª<¥ÉõñUÚ4Á*˜={vùáoí8à€ÎÍ7ßÜ-Û¾ö§3¿gDÙ0MoVÈ›ø¬"zrÊ);“SáÜ™PÓ“ ¤p¥ù8_¼Ò‰«ã‡6¥W8Móõ³_ýç>ŒcÛùÿH;ÙÏž¦If.\ØùÁ~}v¾¬O¦ üŽ¥÷®¸âŠ}×­[w¨þ™&¯QGqÄήñéL,¾y¯Gy>­Šß \‘ ûr #‰÷»Ì¯4Ü<¿Êòij¯?üÁ*`•?í´Ó:'žxân²Ábº`Á‚ÎÊ•+K‹²CÂc.½ôÒv-¸œ0)¥¶pä‘G¾î‰'žÈþÔ2)kgpÖ¬Y;ý©¡aß‚«?ÕLiª„É/á.òw+‡|2øÓp^šèD«°h'ƒ`6˜QäOaÑ”O8á„Ry:üðÃ;?þxi£8|·ÅõuFÔ_°‹Ç•©ÿ´DëfÐ8ÙáüŸ²|^Øü$­\ÕSöõA¯°ò¤a•np Œ,¨öóçÏÏæ-iÈS7™CŽL¦æv++M¯­jíÓ­1´²¼0Ú0à`±[Ù*ƒ:$øÄù°÷+Mùª†}ðû°ÊHã|ã쟬ýæ˜  GuTçä“OîvØaµš‚|T‘ ·z[+šÀöÿe“D×bëô5†¼¨ÇÁêT½~Åù°üä%݇Užò…•×ÓÉ/×Ó¨œpƒžÓ§OÏõtMÞ§Uõ#Ý0Sûjÿ®V¡E6ù_¤Sk‘™¸«\I½IË@¸è0Ô´ëÆöJø1¤#иò«Œ4¬xå#=5iaYO«8OŸçó„jr€ÅËÎÊ2æÌ™¹ PUÎ0Ƕoßž{¨®2Ð&¦6PÉ´iÓ2!)«póæÍ/z1 ÇJ+ üá!` @HWz˜——¶©H«Ä‹&-3ÂS‹,T=j~¯Bï9Ç?OóÔ¬LxúéæÿÕÓx^ ê”F4}䗖͆H+ 8@úIØS7- ¡-2E­øÔ-*gœãá_ƹom¶ýàƒîpiÁŸ1cÆn‹Mumܸ±Tø©ƒwpššFÀ Œðñjb™á Á^µ€¼òÙb`) -h%¸M^ «Ë&h”.z¥‰Þ§Ëïi<]?Îá<~ŒsÚj;ÛP{.sçέô´«—ºYD‹²ÕŸ—„ìZ~ãjµ!léÛIi+ìmÁV‚™¦·¶—!2­Í€¢.@H'!ö®ÚàãäWšw•–ºžfÜý“Ah£h¯œwñØŽ…ŒÓ{i—ýcd˾³‘m}ËêZ¾|ùίŒ®(­1 lhÝ´ThËn5®n4™pyåŒB\«ç(ô£¬ ô‘EGÐq ͇²²ÚLãl áï6ŸXxÛxã¶'€Y2&Юs(Èj<,Pé©‚Ú€ð”K˜• ÌäCý¸¥u›|ãÖY1÷°l±ÃXÝËxÇ~9©Âÿûî»/[|ËÊ«’ÖPÌE°®'Ÿ|²°N:ÅvõkØH«†‚¤€‚7h muˆ•6û¶†ÿe0V,Hhx¬æœa±ý|¹Í|¨óØ*ÂÿðÃwÖ¯_߬¢$WÏ@yì½a4@€º¯=xRWD瀃ƒ„l `ÆE§ô² €e¢ÉÀ0Ø„ßhh:Vg;9áq3,@,Œé\+êǪU«:@[¦ 1œ G}tÖ:U„hhöJq¶ïâ”u\VV€›wðI˜œü ¹Ü*¨že‘µ{ÐÍh”Ò¾äò4¡ÇMŸì ºmÕÇœ`¡ä~ÕùñÈ#´*üô¥5 0n$1P 17¢¸$ÐIÇ:M<ê7‡0ƒ> ômiÃO&îc—' €^‚æ]øDvX¦­ºé‹sB+7a„+?é;îT0ìõÙ.sH]Å0'|ðÁ«[c£z[ EÅ¥p•[R\œ Ã\l`õ÷&pêÉàs6€J7Ù ‚ífÐ1ð ãOÃišŸ(SV™¸¾-ÐI“Q¥¯¶ËG8õó28áGªªûäD>î¹çžÒóµ—k¨ïk˜4ÜÐcPÓ&a,jééÁtœ€¢=ðHf÷sõÙ_žC‚XN©£Îm·ÛŹ´äY¶lY-ÀHËèn¨@õGàdO«‰Á ðt­¿ ´$,ŽÂ³Yµ-Üà@ ê³àÕ|46öûüÛš]?M_@ F¸¹;Ð#Ø^ýG;àr´T#ÿVôXâõì–}c˜àÀ(sE»e+œwXÜ­íÈÌŠ+jƒF·r‹Òû.Q¬òÔzÎ@EXÆþ‘'X4žáÇ@ 3±z¶ÛƒŒ5ñ3"@»EÍgãi˜´Ý:Í#ߣ>šm›ä¯S—§í;P™Ð{:Ȥ‰V ³€|€4˜¤Ç€šA€Îð’ÌKÍI¿­Ó€ƒ/þ²íí·ºŸ×®#ðò!àºV|è55’3,¥R H 'Ë#šú0Á~r  ¡§}þêÕ«³}Ã|ñh`@…0OïèR.Ìà ¤Eu‡›GŠ@ÀV 0à Ë^ôA3Ðã+u6Üà@] Ž£²€•ÍѪåR—à´âRÝÏkã@€ °üÉë2˜X-m¬ðâå³=å²°GiµW½;T !&Ï>vm |PôUÀaÖÓòˆPº30”‡Å üy/Ÿ(øÑ/?Âȹ“,BŸø6 å1·˜Ç?+Ûu´Ù^_ÖЀÆÀ,”bKwáAÔþz€@Öw(õ£MèžiiÞ†&5ô-àÄyCXtÞO¾4¾*Η1J~Ú¨q”«y’òb”ÚÝf[Fèl[ƒÁÄç©+=atˆ[ ò³ziòTÕÈWÅÐoÚ‚Ã4ç"츺üÐ`ÅKùG­/£Üž±€Qe¤ሼIéÁ@~èð“`ÐB}Ôd×ʆ«ÉHŒëdW¿åŠr%Ü„¡Q?½+¿xns4ç]åœÒ4¡5Ó°Ÿô¤ù-•ù|R¥§.é*ܶŒÚ¬òÔ&Õ¡>ˆÉU¼\â•×—éýYæøé+úÊÞz…û-~¬„„’¼Í­… á¦~…I ¤AàÇúòäÇõ~꥜4.¥óéÞ¯v+Žp˜Ñá@@ c!a Ư°\ѧ‰Fì]è$¤Ê§tòáǨînþ4°LZñ>NtáN>´0¦º5&AoÛE1!”- V± v½&¶KÒh$£Õª—ZãU÷Ql_´)8PÄ€"ÎD|p` p  …A  &FCá@m°ým{Ï”jt9¶5˜¤S’¶•¿ªšÃ•Ú`•<•SNߣúÎâ¨`Ì9`2²µnj€ÝzÛT·’6èGÚè_”è•&#OÔ-£6Ø#¯{¬’Ý?…S·æ1 ÷ ƒ¿(gc0˜S ‰¶8ßY·›µà²Ë.{Æ*¹«nE½ÒëÙº/GBéÓ§—ùZŸOe)Òòâ‹Ò”wÝÉb“¡=Ì'.\¸¼nþÚ@Æè¥u+j‹^)!Ì+·ˆFñäñùS¿«ü4¯häŠ.ÜàÀ08`2yíW\Qû€¾X?kv /³{ƒ½ð)Ýlj®Ìõô©?¯LÑ䥕ÕiÁ>ràE»þÉ&å7€%K–¬7¸²I…Mó ž±N¹*ËçQœ/OqÐ)>u}ãì÷}ç~LѶ/ý¾pw“¾7*2Äù 9ÛšTÚ$¯J^?™å—«ü¾¼4 ʼnN®OKý„ÃÌgí VÖ´ÎÆð®w½ëq«ô¿6­¸I> a*œ”¥4•+¥åÅû4Ÿ_yå*o}§p Ÿ°½ÿ»úê«jZGc ÂÅ‹_eεM+¯›Ï []?uù8оð¹Ï}îã½”ÓP±}Êêw͹½—FTÍë…<ÒÔß­<å«ê¦åùv¨Œ”&ÂÁ>sà;öEëß鵎žà-oyËÛƒ\` á‚P_6ùåR±ürË#š*.4Þ¦u©Œ²ú"-8ÐLíÿ͹ >ýéOïèµÌž€œwÞyí¢Î[ÍÛ× BeBØ+#ÊòKÀó\Å•å‡4›TãÐÌhc§óÿlåÿÕk®¹fKÌhhÈù矿É>aõ&ˆÚhX^^ØäoêR~Y^ÒdËh}þ0Á>ràû"ô¹ŸúÔ§^úÿú*j hË\`¤úôo˜à|¤…¶íV„HŸH|žIã–KùS·( ºÔB+(\Ó'=/¾jœ/;¯Lçi}ùãæWŸÆ­ÝS ½Ëmqyƒ _ÕÖ@òö·¿ýzó¿ÊìW׫›'lš¸©[§.å%÷« ÅáùEnp %ðo°ÿËþxöÌÏ|æ3µßò«Ú†¾~ømo{ÛZkȯûÛß¾ØP ›]µaet!*wêú¹lÙ²ÿ`Œú/þ5³»l˜¤X/øi˜2•Ž¿ÈÏ•­8…=]QœòŒ«ëû8®}Ñvßg¼ý¸Ù«®¼òÊm£ÖÆ‘1Æ©üvùòå3Ì]bö2³o0&îÁD•µ¸]x/ø„Eãód‘?¢IãÒxå÷ñyq¾œðOY¬´žsféÇ>ö±ïŽ2F<³N>ùdnòé±+z衣̽оDt‘ Þ"„Ï3r ½\"I÷áŒp"^~¹E‚ìãñˤñ>M4ãæÂ«ÉÐ!ò}µñïËf—þÓ?ýÓ÷¬/O˜!6ª[Õ# ¾ñÇüj ÿ=vÕªU§Ú„E38×þ;PÙÓ ;ÀàþüLtlžQZ^ºO“?¯ŒqŒËëï8öc€mf±—¿ÉæÛuùÈG¾oþüI5ÀFÕ­jlÀwlþüù÷ZûkÖ¬™aß#x«Mà_µð¯›+áÔ¤NÃF“™¢ø¼ô"Ú¢x•1.nh•FŠÅú¦ñêÓD¿öÑ~tM¥\#L4–àù9oÞ<¶ üOÁRÆ=7oÞ|¦¹~»Ùט}…ÙÆ ¬ü$ÊïÝ™§‘?!» ý³žµ˜˜½ÙøsÓôéÓÔäÛû»•:Bcž—†Ìü1Â'ì_Ú ím/SðBÒ¯Xçg›–Ù] “¿W»Kc ´õö{§ñâ»¶­üž=–þ¡­ò?Ãá¬ÜäIi¯m ùCÞ¤Âþ½ ùvÝò$SßYøW̾Îì fwyÔháÌ”‚häB;ÎfÜÛ߀÷ÏYž{mŽ|ßú~ûÞ{ïýÝ~ðƒœ3M)3© Il¤”ˆØ&ÝßÇü;È9ÓügZ­á ³…ñ¶pLŒ7YƤ¹u›Éç³î3{§·ð–í·ß~÷˜:?Ð{÷u=ú)y µ‰Ï$X6a¯‚Æ&ÉžëÖ­;Á&Ê«,ýt‹:Ñ,šî~fÃŒ&Pá´1š÷r®IDAT{ÐÆn¹:§ôw™ å/íG“E»¶jÊÀ®ìx)dˆ³„&ì=ÍÊ•+ݱcÇ/HœbtÇš{¬¥c¹¾àà™Õÿãû#Æw^*ò²/³ðƒ&èOõ§ÊÉ[j| ¶Å±ýÉO~r¨}0˜k+гDæ(,<ßܽÍÍÔíª®åÉZ‰ëýD¦q>ÝûÛ¤ícYÜ—_g|yÄ„œÕ|§Ÿx ?ò|u>LKh‰‘UŠù⿸—=¶<ÂN—çýL{l†Mô™6ágØŸi‡“‡›;Cá w‹ËŠÇõ~"Ó8ŸîýÝh»¥×)k‚ÖœQ½7[?6ã7•?q-Lp7Y¿7Ú!Üš÷¿ÿýÌ… Èì&U]ýõÓL@ö7a9Èè`sñhvº•·¿ Ô"‡Lø÷§Kƒnç“ £!~?‹#³—ÅAívËÿ3 ¿”bûnqψÖ\2m%Ýèž·¶Š$„„‘ÑH‘d‡93™äœdâ3™‰ãd2ög<>'çHŽ7‘pÈh·%!ÉR4R$[`Ä¾Ó tM M’¦~þš¢¸÷½ûî­»¼÷¾:§^Õ­½¾{oý¿úWÝz£‘0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#0—ì7—­v£Àœ#ðÎw¾ó¨C9ä 'Ÿ|råþûïðpÄOúÓ#öÛo¿ƒC×V{ðÏ~ö³#ƒ{@pWÐ]â‚=H{XðŠŸtÁþ½†÷š2šš=¡€'ãBB]»B]Ïì {4øCS~ú³p½“°pýlpé~üûT¸ÞMXH÷L°;C¿ŸÞ³gÏ›6mÚõ±}Le…$6FÀt‰€ @—h»®…@àâ‹/>ú©§žZ„Ûš èV¾*¸G‡Î­ .Âú¨¶b¯ŸëUÁâŽã‚{x°6Ï#ðd!àõXÂ>¾×…T<ŠŸø@ˆÛü;BÚ‡:è »wïÞñÅ/~¢bcŒÀŒ˜Ì˜“/o{ÛÛ9ì°ÃÖ=ûì³ëCÏŽ ‚e]Þëƒ{l¸^ìš pV‡kü²¿Ípx"4e‡ì^‚Àõ¶à0Ü»íÁÞîëƒÁnûô§?ýðpšî–þ0è{×Ü"\pÁáað?> üëqCUƒSðo~„û1{]fç6Ë…ËÛ±ƒ½$aK ÷‡ë{÷†m}Õ«^õÀå—_þÓ傯½]&L–én/H_ƒ þà°†¼9 Ü'µð ÁÅîò¡››‚ͱ¾ ˆ¹5`?ö`ï ¢°e/A¸;…»ƒÿ®Ï}îsÄÛ¹DÀ`.oÛb7ú oxÃ+W®<á'?ùÉÉ{…û‰a°=!ôúÄ`_,³x?»›ÞØ ÏéÝ¡%cwïõ$Üæå†Þï0¢ÀqT{ìÅ#ÌOIìÉáúÄ`ã]íáÒÆÌ%ld¼­ÈZ{0—÷s¡m°P·sx¹è¢‹Ö5ýaVtzhöŒ`O vs°ÞL@°YZøÚáÖðnÜ´7„÷ä¦<ð†uëÖÝæÏ#—ö™è´ã&½¸•þùë÷ì¯=DÀŸT¢û3ƒ]¬0Õ`“âÁÞìM¸$ܾTù±?y hØdCÀ ”ËQÐe—]vÐý÷ßj˜±œzÌÌ!Ÿuy#`ÚC€M‰÷ 1øA°?†|þóŸçšÃ˜lŒÀL˜Ì×r%~ûÛß¾*Ìê_fóç†æœÐ{fø/ ÖªûåzÜÛa#À>ƒë°á=ýA ç?xôÑGoüÆ7¾a°1¥˜”B³\á@œaýñû½ŸYýË‚õ3²\‚{»°Œpkx—)Àzè¡}ÕUW=½Ýs/r àÁ=ŠsVjüíÛ·Ÿ…×bCó_,»ïmæp$î(hjöµ<½Þy>øàQøÌrl£àyÃy ü×À¾ðôz_„=ó€À“¡‘×ûÝ@ ¾ž™ï~êSŸÚ2 wÛAÀ \Ujøã™¡Aú×íu™ÝÿH&¸6-!þôf„ E ãmжŒÃ‰ *ÛQ˜…8×àä%Ž|ü„aø¤ëÓ„ÿCWv¯ž~ú¹‰%þgžyfl!Âp¹&Ž´ Ó5ñ„ãÊOz›Ö€|Bðþn°?ôFÃÖ1L&ƒ¹ù>ŸÙýB°?ìß–Oîlj € ÿ0Ðiüé5ᲤG`smÓ °ë}L D ÂÿŒ XüXÈBQx¬µhÖŠ¥Ë½'†^°ÿV - KÒa€ù¿Ñû…sïùôn,ðÃË‹»~þ»Õ^˜Eyä‘£Ã?|Ÿ‹PWXìï{–Ý ‹[2ÂRþjylŸxâ‰}þ]»vãÃO´6¥ †ùQ°ß cË7)ûÖŸÿùŸ?RšÚs…€ À\Ý®çû®w½ëä0hýðB¾) vÌò×Ía7²79à1:âˆ#Æ‚a¾bÅŠñõQG5†k¡žú¹-² xüñÇÇ„@.ä@~\´6c`K|mðõà~%h`¾yõÕWóoŒ6sˆ€ ÀÜ´plî‘ab Ap™ñ/¥Aµ~ôÑGÂŒ­ü~üîKùX´Þi–# áóºÑÎ;÷¹ø G£°¤†O ¯ äû«ÁýjÀçÁøóÃ9yLx£Â_îÿýïÿ¼°éëüм¿쫃}~›÷Ûœ«IlŽ[µjÕX˜ã"èå2{g#œh ØGydŸ‹r€¦aIÌáŸ_ ý½:l(üó¿ø‹¿x`Iú=—Ý4Èm ÷Ž /Í›ƒ€{GpüÇ ¤iÙ›ªžÙúš5kÆvõêÕû>jzâmŒÀ¢ €ö &;vìa~øáñ†ÆEégA?`=ßïó’剅ì%X&T€Çà‚<ÒöxKÂæ½—„êß^Ôú¿ìsßxõئœUó©ÂAŸºñwë9ëtYF`ž`ÿD@VÄ€} h¶†ÉÍB¿¾–ò¾%Ú½€}œ«.™t|»úAà¿3T{q°|—¿÷€5øµk׎…ýúõëÇ~®-è;~À\ÝB Àç,'<ôÐC£x`LÂá]ã/¢ƒ£Âÿka,¼*,Ÿ|ÆŸösWBøô]õZ/¼ð³ó}OxØßÜ—WÏ9¼”ôcŽ9fŸEÈs­j†×b·È,aìo>|ðÁÇÄ`Û¶m#ìcÍýgú»ÃØøåпÿÎÐøBÐ <ºwlø½0hé…™>‰ûþP<3}æ™;ƒ°ÿM>:öØcGÌê5³÷F¼¹»•nð#À2‚ÈÚì/!ì ·ê+Á^|úŒ?1l÷Á5ȈoØÈwl(î}Á"øÿVÆ¢[/*•ñnû7Ž6lØ0¶ ûÖ¡wF ;ˆ@øëî±½ï¾ûƧ&f¯¨Ýw…qéÓaáŸîÝ3ೡ3ãmÐÐ7¼á ‡†gØÄ÷Á`ßl¿´WìßË£º?î¸ãF›6m |NƳ1F`1`OÁÖ­[ÇÄ—=,+̉áóÂÿ7´÷ÿ _|kNÚ<øfšÔ¼Eá4¾sÃw®/0ÔKCGÕ,¦³llÒ;þøãÇ—ùÌúmŒ€XN8»"°eË–Ñ=÷Ü3&sr,òuaìúX°W|æ3ŸÙ¹œw/O¯-fÀ‘oõCò_ö²`ùG½Á¾f÷¸Ìö-ð{»Ü0#Ð;ü3#{ wß}÷Øå ƒþŽòóÏ~ö³_ þ¹Qg S€ w"lèû[á!ûïBRÖ÷¨¥ó$‘»yóæÑ‰'ž8v9=ÏÆ#P„?{îºë®1!`OÁ€— ~ _#ý‰¿"¨~ÇMJ°â8ÞýèGoü? IÞT’¬·`fóÌêø'œpÂX½ï {½ÝWl– î½÷ÞÑí·ß>ºóÎ;‡úùá®p#>¾`úÝOúÓ7.üMiØA€ÀðÇ;G‡C8~5Ø„ÿ It¯—œ…ÒI'N>ùäñ,ß|ÓëípåF`©àxcˆ„böD þµS÷sŸûÜׇ԰!µÅ`ïÝ8ÿüóO¬ñÁÿá4ˆM}Ìòùö^BßëøCzuÜ#`„Ú– wÜqÇø/–7—+üðO…Ÿð?¾ðn,=ûN ü/Á~ ØÞ?áãðÔú§œrÊx¦Ïf>#`ŒÀ¼ À>ö@n¹å–ñ ¤íw†vüV8mðÃ>§Ò¦^›±´ Ï{F@þŸ†‡•]ýöyø \ÖñO;í´ÑK_úR«ÛçÍpÝFÀdE€ÿ3€ `ùÂ`f[÷ÿ¯ÐŽÎxríé­ KGÂŽþ3Ãf¹€‹ê½ý¹<ë÷¬å#ðq½žßÛ;àŠ€èþõðÖ[oÝ|óÍト:ª¶¬šBÄo‡ÿRø½°4À'…Kg–†¼ãïØÿo„;ü‘`{™ñ³¦ÏQ»gžyæèe/{™gúK÷º¹ÃFÀþúøÆoÝpà ã>Txî–Pç¿K–µ“±m,ž„]ýG†?•øûAøþ³f/›û8uõþYg5 Ç·}O]¾0F`n`ÏKh »wóOÁ½˜B­—‡¯®ê¥ö*]XÎè?ðè£þÂÃõÏ®k»Æ–ƒy˜é#ôùS#`Œ€˜Œ‡ÝvÛm£k¯½vüi!ä k&‹_ öŸ„c†¯éºî®ë[Hvö¿:ù‚ÅíÔð×¹gŸ}öèŒ3Îðº~§È»2#` Î`yàoþæoúø{cÎøáxä_ûâ¿øØ"á÷e¡@Øà·60·ÿ#tðÃÁvÖ7fûÌô±¨ûmŒ€0F üAZk®¹fü§Ekî ½øŸÂ²À•yz3¬R:’-w{¿0ëÿÕPÇoÛ™^½zõèÜsÏ«ú½‹¿å;ìâ€Xz|ðÁÑ~ðƒñ^Žÿ¨è«áŒ–¿Ž¾e‘nÂÜ€p‚ßúpcþ ÌüÏïêÆlÚ´i,øO=õTÿÃ^W »#`ŒÀ^ž|òÉñÒÀøÃÑ®]»ºÂå© }¸®·Íz\¶0FÀ´ŸrŽÀ·¿ýíÑO<Ñf…l|_Ð|¶ÍJr—=xðîw¿û¸ð¹ÇgBÇÏÍÝy•Çç|þ“N:IAv€0F`Axúé§Ç¿ÿýïØ8؆ àgAð¿…}üçÌ\˜A€·¿ýí'…µø¯$[‘Ìü ïk^óšÑk_ûÚkþ6FÀ#°¸ð¥ÀW¿úÕÑ]wÝÕZ'ƒ,ùÏá4ØKæáSÁÁ€°ÓÿÜ ¾ù‹p—ŽiãNñ¼ozÓ›üçtîÐŒËxéK_:þ‡~xl¿0FÀ,)h¾üå/·²I0h9ì°ÃNýä'?ùÐá3þ½ï/ƒ=*'X|ð(ü=ðø_úr–벌€0F`þàh᫯¾z|†@îÞ„½f;9äÓ Ø–»ì¦å †\tÑE§†Ý™ß Z×´Sqþµk׎Â~‚ѪU«â`û€0FÀ¼þ[àë_ÿúˆÏsšðû#á_c_qÅWlÉYnÓ²AÂÌŸSý¾ì‰M;ççìþ·¾õ­#ÿS_ŒŠýFÀ#P†ÀÖ­[GáœÿìKAýHÐ ŠôN.»ì²ƒ¶mÛö_ºÿSvCf ë.c•?ÕkcŒ€0F`ø‡AHÀ}÷Ý7K¶©iؽ⪫®Ú15q zÿøý¸ãŽû߃ð_®¾ò=ÿ\0:묳rérŒ€0F`‰`ߨ™gž9zøá‡Ç6W×Ã2÷Š@Þúº×½îã?øÁžÉUnÝrz%|î„ÿÇÂéIY4¨úÃ^‚ßøÛ#`Œ€¨‹šäÓN;m„6 h©ëó¢|¬rïì°DýŸn¸á†Ÿ½(A‡½€óÏ?}˜­=ôõˆý ŸZŒ.¹ä’QÐ(ä(Îe#`ŒÀ’#ÀÜ” %gäZÂTO š€ÂÿðÕ[o¦7ØÏGC¯ÏËÑsfþï}ï{G6lÈQœË0FÀ#0Fpâ‰'ŽO ܾ}{Tø?‚ðyàÏ…¥êo]ýõwf)´F!½€pØ‚ÿwƒm¬úGMÃg~›7o®Ñ}g1FÀ#0izè¡l{§†ûð¦W½êUríµ×îžÜ‚vb÷o§Ø‰¥Òé……?µ¼å-oñ¿øM„Û‘FÀ#ÐH@øƒºlšf´Ánzæ™g~¿iÛêæïœ„Ùÿ/‡¿¢nƒã|ìôùË_ÙoŒ€0F Âäu6¯Â¡>YÊgoA0]zé¥çg)pÆB:'À5c “s²ß/þâ/Æ9Ð#`Œ@¬X±b6±Ð45œ8øì³ÏŽÂÆÀû†7¼áÀ¦åÍš¿Sfÿ¯ ³ÿÆßè<ßúó­¦0FÀ.àËÎ Èa‚L¤˜—­_¿þÃ9Ê›¥ŒN ÀQGõ›³4®,-ªÿc=¶,ÚáFÀ#`ZEà~áFáS¾Æu À†‰í¿üЇ>”gm¡b«:S9\|ñÅ«Ÿz꩟㤾&Àîç~®IÎkŒ€0F ü­üyç7úö·ù›f† á‹¶ {öì¹(”ôÉf¥UÏÝX¹råvîܹ?›(š˜sÎ9gtÄYÎjÒ ç5FÀ%G€ÿ›¹æškFAp7BBû ‚û+¡ Î@gKaæþfÿM,äáŒ3Îh´3#`Œ€È2‰½Mäy9Ï6þbЖŸ’£mUÊh6¯RÃÞ4a£ÃYMgÿÇü(hf¨ÕI€0FÀ´‡ œéðnT ûBœ“óPпhTXÅÌ€Ë/¿üô»ï¾ûà¦à%/yIÅn9™0FÀöà“ôÕ«W}ôÑF•±`ï'o uB:Ygõ_‚Š£©šÄgý7z¾œÙ#`Z@`ãÆå[4A>÷ýïÿŠšù¢";ÑÁnÔ¹5¢J»ÿ>úè*IÆ#`Œ@g09½ãŽ;ÕÇBøRŽ2Ëç÷¿4*°BæN@ØÙx*³ÿ&&œ!åä¥&mp^#`Œ€0)|™ÖTÆQ&_@‚=;\.YÕTÀ7—6FÀ#`††ÿ ÐTÆÅ} 2³“¿·íJpXSprœ¸l¿0FÀp,}SG;Ð"ð5@Ø3·)G»¦•Ñ àÚT=ÂI#`Œ€0CC€óü›Ê8ú„ðßëvrÚ]ëà£ýèAáÓ†ƒš²#€ñsá#`Œ€ü­oSG—DÂ^€NÖ¼['áðžý·lÙÒ˜0›#Ø$acŒ€0F`(ppS @2ÉíDеN¸A¹ÖGžxâ‰Ñ‘G9”{îv#`Œ€ÔT€NPí„°C²); NZ2èä¹p%FÀ#PÇ{¬±ŒcAצ€ðç;ɦÿ˜ôÈ#Œ6mêdsd×÷Áõ#`ŒÀ"ðä“OŽÞM5»wïî¼÷zÅwüMU»vퟔ„FÁÆ#`Œ@ßlÛ¶­±ð§,qwm:#‡vئÔÔlß¾}´ys'g$4mªó#`ŒÀ#À¤ÍtÓ%n4M5äu`î”°PŸ9Ôi,y{ýúõã…uËp>#`Œ€0M`BÊ—iMÕÿ=ôPÓ¦ÔÊßàßÙC ðÀX Pëv;“0FÀä@€YûÃ?ÜxöO[ }˜Îcßó75ì`ÃË 6FÀ#`ºF€µ&¶Ø&†¯ÛúXÿ§ÍÔ$œéßt3 G p '4Ÿ²lŒ€0FÀTEàñÇk³›ªþ©YÖ—é”ÐI´9–ØKðàƒŽŽ=öؾ°s½FÀ#°d ÅFö4ÝølÌüÑ$ôe:'0&6†ÿhÜgˆ0¬X±¢qY.À#`ŒÀ$4ñdã_Žcéo½õÖñ÷“êl3®ÙâEÍ–åükß;vô¶~R³ûÎfŒ€0s†ÿEÃf½ûØè:ûÚü'è{!lš@ ÃpSPÇôqŠRŽö» #`Œ€6¹å åÝtÓM½wº@¯ÑäP¡P–˜ÙSO=Å¥0FÀl0[ϹSÿÎ;ﱑ°oÓ@ø³!0—am†Ý”9oR®¶¹#`Œ€˜?4¹Ì)¬ùìï¶Ûn½zÏ.ÊœûÚ¸Yƒ¸Kn„0FÀtŠ€äIÎI%‡]{íµ½nü‹Aìü+€¸rüü±çäø*@es¬"å­\¹2Û2ƒÊ¶kŒ€0‹òƒÏórmø-Åõ×_?¨ýj½€9òÈ#ÇÚ€;wf9$ˆ2)‹›·nÝ: 6FÀ#06”³±<Çuqe¨ýûÞõ·¯KicN9å”Ñ1Ç“mÖÎ9[·nÍÊâÒ6ûÚ#`&Žì%Ë-üï¾ûîÿ†fCØÄÇ?ýAN?ýôÑÚµk³T9÷Ýw߈¨`lŒ€0FÀÄ ðüȠ܆ro¾ùæÜÅf)o0€Þ ¬9Øç ƒmܸqtê©§Ž×ñ›öÁO¹Üê°1FÀ#ü¹Ü–-[ZY›g?ëþC5ƒ"€´gÏž±°ÆÏ›7oΦàœ–r~ÒA;mŒ€0F`¾`ÖÏš<ëýh sʾæškZ);W[± 0í ›0ÒœñÏìSѰ¡›Ål¾î #¬ Ö·fÍšl'¦}ðµ0FÀ d Ÿöq¸O]92­W,;ßxãƒ_v$\çqÄû@ÔÒÿÈZ «®Jm7騣Ž­ZµÊ_ L{¢oŒ€˜sø2Œ šæ¶ ›ýn¿ýö}r«­zr”;X@çØ¸ àÄÀxW&al\½zõX€V€f50AþM¯( ²acŒ€0‹…òƒþL,÷Û0hn¹å–ѽ÷ÞÛFñ­”9h@™é‹¤‡2ð§B,‚\ªýY‘B‹€6¥ˆÀa‡6kNoŒ€0C@“<„[ê~ºÌôºë®kå+‚6!< ó¬Õˆ”ýëû°¨ö!un8ƒ/ \ÿXØæ tÙFÀ#ðBüìóbk_˜*ÏZŽ÷Ç?£› ÀmBÍÏLŸSºŒÍq´ðqÇ7Ú°aÃøæCRÍÁ´ÛÉ`K'l"0 1Ç#`úGÁÏ?Ýýa³ô‚Ïo½õÖÖIÆ,mš%íÜ:…&sôÑG7qLìÚ'i`/ya„U$&œ\TµNgŒ€0“Ðxæ·Î~°É¥¿8ÙsÓM7'¦/ŽŸ¹"ÀŠ çf³sÿÀÞÀõ$ai€òá,ìM‚Xˆå e°1FÀ~@ÌÄÁß¶ª_=EðŸ4UÚ¡»sG!ŽðKUn3øõë×øŒuÊA;PÕˆ°$À~–#öÛo¿ªÙÎ#`2 ÀŽßÿ®?uòy‡É-Š™Kø0>fþÚµ_U@^„¶6 ¢.‚ Y¨ª:‚l°·€|h !|‘`cŒ€0í!ÀdÁÏÒl—†Y?kýó¸ÑoNsKè* Nä ,<Ìr“ÈÃaa“ʶ¬@ý0O– œ!©ð>±1FÀäA€1ϸ\EÓ›§ÖçJaC8‚¹°ˆf® 7„a `Îú<*zÔõ³¬óS*},š4 ö*d‚ú!XêV9lD´1FÀÙ`2ÇR-c|ÙW_³—Z-c:úÜu×]-1TkYÞTsO€–¶mÛ¶ñ,¡‹E-[$nÖ‡­„K~ˆ„  ¡ NiD¼i0ïCëÒŒ€XL«™H!ø»žíƒ(‚ŸåÝ;î¸c<ö/&ÊÏ÷j!Ý-rˆüàÔñÌÈyÐpsg5 „åψ`¢"ÓHuñcÙŸÀÚccŒ€0Ï!ÀXÉD‹ñ•qzÚØÚn,1 øÙ^GV´Õ®6Ë]HÌÐ!ÌÜ5ëfÃDËC†­kXçÇBìÜi íâáÂBN h¼DP÷N8Ÿ0óŽ“6fûþ®vòa†Là|Øè·lf¡7öÈä¯~ã?÷0 g6ˬ²¶_ö0°×@g h¿KUÈéY"ÀÒY“2´nŒÀ¢ €ÐGàc«,©¶ÙodÀ=÷Ü3^>îKëÐfÿª”½p€N3#g×&‚:6ofßÞ¦Ê÷ ðp£>‚ T!¬´Ò0˜ ÄwÌ~#`æ–`%ô«~jÝf÷ù–ÿþû½m³C({! €€Eå·6!›""0M•ç/ò³Ì O y詟e‚išê…0`!.,_H3 ý Eõ9Ì#044ž1¹é[½cC[ØÙ/UÓñ>.{^ý M¸)_¾à?Š„iÈ¡b³ubìÒ  %˜fDX& –- Ú×0-¿ã€0]"À>_ZÕch®ö3ãO{˜Œ ©]¹úפœ…'€ÃR€ö” QÔð`æ\kTÔ‰å Êf‰BP…  IÀ’ž6Š àz© É£ï¼FÀ4A€ñKBŸ1jH3j=Ÿó¡æg£¶M1KAèºvà§ûbhX*eùµB;—ðXÊ…ò€RÏ4CH§´|^H[e!6FÀ6`–Ï ¡ÏØÕçÎý²þ1iCã‹à¯2Á*+gY—†è†òÙ ‚]ÿ&¨ð"—%ÒI½ÅƒŸS…$ÍûhD@„  ›æa'âBy\ö#Ø#`ê"À¸‡ ÇæÔˆÖmϤ|Œ|Î*Æè*ãç¤ò–%né7uKw„å4ƒªÍVÉ <7»„lðÇFX^<ˆ d[…ióÀkýþˆ@D4ÒÓúíx#`–ÆÆ5 ý¡©õÓ;Áà‡ Xè§M¿^J,°D6ÙñI âSE8J¨2Ëæe‘:>§V€¶A8tÎeópCØ€¦ Š)#"l.ô’A$Æ,&P„=BŸÉCÕ±¥O4טíoß¾}ßl¿ÏöÌ{ÝKKtãâU—”WBòSFH·ÁBµ9¢¢ãˆ¥ö祭jRB@>´Òàú˜âªh:˜/xÿ§öšåCæÅÐffûhn5îÑ'›f,=>³î*K1äh$DYRàá„TÀ¬Û0:,ˆM„´[d€%ƒ*Kq›È%/R£¾ˆXK#f¿>F„»„=îÐÕùE¨26¡¥Eè3¦b,ô‹ªf°;Tí|ž`V0œÕ@$ ÆÒ ð¶aâ}”ùо±äYêÛ¬|ÔfB`R Tìa  {Íðqs/KvÕ[ˆ KLÈp韅~{è›$Ø2s‡yBfÕÄEA ( Ö¶4Ô­Ï9o€ í„ Žv@}‘–@ œp‘ˆ,Ÿ$Ú#ÐB„;–÷R3ûyöBJBŸÙ¾…¾PéÆõ¨]€3/"/;ÿ›ªÁŽ–xØ¥¨3K/hnau²$eà@€‹ 4%!E¤@K!‚˜ 4Å®°s4 Žã„„½>î¢ú‡Æ•Óù—<ÓïçΚLÀ=Ö Ør˜˜ @4 t[LáÌ&B,†—­€lŽ…¼RrˆIäkAާÉeÌ;¼‹"Ô± ok,è/4L¬üŒ=ú}Þçê6˜r¤ @ˆ¡ ¨³7 ¬ „c,˜c2À Ð–Aø®\¹rl©ƒA¢ …9ë¿iÄ &ø!,6F`Q` w*öúÁE5ô AÐÇB¹¿óxM*Þ5Ø9ê*ýK_n!Ey*{ݺucõŸ– pÛ|q :w8è+/.„—,·)#ÔÉ’–@Ú…yI!÷py9@¸KÀË•Ð_ÄÙ|fŒÚ{„jŸ¾·9v•µÃáÕ0¨†Ó82˜‡mBª-ƒàc×=køس– pÛ4Ô­S ÕgˆZên{@ƒp”‘ˆ’ÈÄED0®±6F '¼<óòðñõ² 9ÞS4—úÚ×´¬xä|îº(Ë£e ”yèQi! ™µ#|Ú6:ÁoÍš5û¾*@†´e¸ú´‘:x±QéS7¶- AY¨_oQÚ !ˆ]ü†.îWQÛ6<ì¼Ï]€ ÷ ‹Ði{Y ¬©®˜0›ÑËŠJ.Ý™_VNÝðxÉ€2 Ô/Û&!©Óf- †*dEA$B19_éD0¸¶©‡÷ASd¹w —_.áJõ0'8Æ“ Æ0µYLL2ÝW •6÷Tm* B!Áð‹àbyÑÛ2¬ö/ˆP/ƒ vžÚªöV! 1®†˜à×5éE&â0å% £küÊ/—°. ϹlìŸ8\×Â-¾V¾8 |­²ºèÓ2×Áä@c„‰ŒîÏ2ã²,}7Èx§‡:h!8ô…Ý¥2½üÌбmµ Eü•mPÝ| mÕO}}„¦MÂ¥¾U!< EFí,Šã¾,â½)êë"‡ñ ê}“?—¾Ç‹|÷‹ûfPŒK­Ðyz˜¡£­–€¶C ç¶I65JK€Ò $—vØTG€{8íœ$è«×ä”CG€û¿Ëli¯¦=#Cï›Û—€|XN|3VÕJQRÝëÄ@ Ù6„3Óøk:˜.@³1Fà9xGy'x7EÜõžÄ‚>ö;# L„Dw_2ý `Ü7ˆvÛËŸÂQ´t@Ý pXk ^—/ˆ7ïÂ^ÄWjüø]p(ܽL˜dr™ŠaÃ{ âGƒ“HÜÜ3vHA||2¸ÇêN‘Ü64ËtŸÝ×~л„ ×{„ ç]â‹ß»ØßOk]ë<#`ñî-óËÈ4-!Ä8à× Æ†WƒYøY>ÐÙÚS@½ 𱦀kê·1C@€™»Þ „=ï„\Ú—¾GCh³Û°X˜d¼Ÿñ ›±Ø¹/JÇõª#ÂI3B?¹9È„D ùã#‘ƒ.®Ú¥´v@Sx–S+!Ïó–>séuÓúßLBÀ`:3Æùå 0fîh 01vø!‚"K\œ~–ZcbÀ§‰2”ÇlLdB ’@lŒ@ñó™’ØXÛ?¯±¿¨L‡®0Ȉ´_ì|`B°¬ùcblñCDä΀¬¸YZ/aè+åg ‡ `!²„3èÛ,&ñóT&èéyúl.&îÕ""`ñ®ÆAÆb]T"lHÄÄØË/" —ðÔ¯´Uì b ›Õ+͈AL¬=Øã`<<ñ³“Fq S£ãç$ö+Þ®˜GL2Þ5 ÁÌP$™=$!¾7©ŸkY ]¹qÓbÍA.?‚DÄ@D!]¶AhÕsÓ{¦k°×ý“`×5®L™_ñvÀ¢"`ùÎ2˜ læÝ/\HC‘@( #\–+\Êd#ýl2Ea¥%\®Zø®4iÞy½FE.arŒâ%ع–pã«úIgcŒÀhdù)`p’@É\´‹ºÏrÕ< ,]ÇnYZŠ¢ ‘i^ ?ÈB°È"(eO>ò`SSÖ&¥KãÓkÒÅaòË¥-`Äul‹ÊWž´Ìô:N§rì#0&³á55µ¦©9AE$á­Y¯üE‚=Ž“Ÿça¯üò«êô9¯›ø)¿(?aq¸Úa×þ0ÈŒ½¹Ì€°8 3 c Y„/—4q|ê— V¸òÈU·ãç)ö_Wñ«L»FÀ0ÈüÄqæ¢]\„‚Þøqc«x XÒ*„l|-¿ÒëZi¥:×µêÖý–«p\Lž^Çq±œÑ?FÀ–0È °òz€òéœÎïC àI~j"^¶‹ëz½s.#`ŒÀð0È|OF6³#€Àçs9 sá˜^Ï^²s#`Œ@û:¬>\õKXΜé&¸åDÁ½6FÀt‡€ @f¬MêjP7ç2FÀÔEÀ .r%ùLJ€q°0FÀ €AÝŽåmŒ5Ë{ïÝs#`úAÀ 3îÖÔÔ nÎeŒ€¨‹€ @]äJò™”3%Ø` @Ž6FÀdFÀ 3 &™uqFÀ#Ð ­€]»v-Õ‡ñ&õžSkêáæ\FÀº´N~é—~ééиÝu8oùLêÝ1€z¸9—0 ‰@'2³u°÷ÖìXÈ[TÐ)€PdŒ€0³ ðÄ,‰ë¦íŠ<\·ó–Ï Þ³ nÎeŒÀâ!äÈ}]ôª+ðPqó‹€ ÀüÞ;·ÜìÜ›½Ä‚»"×Ô½°AÖ¼ðÖÆxÈû_˜ÃWFÀåE`ÿý÷ÿ›.zßøNJlCiOíˆû(?n‘¿jýÖTEÊ錀X`ørîG]ô¯ðì³Ï~»‹Î ¥þÚ á´­¨q;c¿ÒÆaò+®ÈÓÈû•/3*v€XV˜xý'?ùÉN–Í;!¿ü˿̆†{–å†J¨¥ý%\qEnQXZF“ë¢úû*/w[šôÃy€0CA ¨ÿ¿ÒU[:!t& øWuÕ©¾ëiC¸Q&Fî,}¬“Gu)¯\…ÕO¥KýJ¯x]Ë%Ü¡a×eE Œ…ÚUß;#apÿ£®:Õw=EB.“?ugi7y•¿(ߤ¸ié«äÓÄþ¢² #ÒÉMÃMÊÐs¸0K‚ÀuW^ye'ëÿàÙxï{ßûãPß—á&JÀ¥n•¾7Í£üU몒^ipåOËÃËüqžIeÅéì7FÀ,í²¯:fxØeçúª«L¸ÅᱜÔÎ8Ϥt³Ä•Õ×U–&®'N‡§þ¸¬ØO:]ãZ"çk#`–]‡rÈ'ºìo§àÑGýƒ0ÈßÓeû¨KBºcQ[+Qº*e•å›–wZ½iþ²ôqb¿ò+Ÿ\µ7½V¸]#`ŒÀ² ÆÁûÇüÇ;»ìo§àÃþðS¡sÿªË¥®XÈÅþ¢ö5W™”SVVY¸òâVÍŸ–_Ç~•)7³dlŒ€XB¶~øá¿Óu¿;%tî™gžùãà܈Q[ê¦ýU|®ëiñJ—Û-«—ðIqeí(ËCzÅÉ-+ÃáFÀFà7þðÿðñ®û×9ü“ðã?íº£]Ö‡0+h“ÂÕ¾¢|ÄÍ>)í¤8µ!uÓ<ºÆ•_mÔõ´¸¸å± FÅ~#`–0þ]{ÿý÷ÿA}íœÐÉ /¼ðsÁùxî¢N 4êŠýqÝeáqš\þ²ºŸ×_–Ž4uâÒº'•·Ã~#`ŒÀ!À²ø¿ño<ÛGŸz!tôé§Ÿþ‡Á¹§N·]g‘0‹ÃÊüq»â4MÂã¼ÓüÔYVošwRº4.¾Žý”™^§õøÚ#°¨­ç? Çþ^×Wÿz#a)àѰðáÐñ玸ë ë•p“;©*Ò¥+ ŸTÖ´¸¢zŠò¤u§×qž´Ì4m|-¿òÈõ@Œ¨ýFÀ,2a¼ûÒW\ñ{}ö±7@§ßùÎwþepþMŸ´Q·\Zv.ÁW”. K¯Ó²ŠâÓ°²ë´Ó®UNÚ†ôšt³”¥rí#`[߯} ô±× p¯€HÀo§Óè·M ½Ø×‡Çþ²4„—¥‹ó”ùÓ¼Ó®ËÊ!|ZÞYâÓ´“êuœ0F`x(Œ{oïêÿ&áÕ;jŸ…³?º}ûöŸNjè¼Å!Øbáû'õ¥jºIeäˆKÛQç:΃¿ìZá^Èqç\†0CE Œq{ÂÌÿŸøÄ'nB{'\pÁÚ]»v}òꫯÞÿñÇ;ÿ ²µ{ ¡F±?½Nãª4(Í£k\ùUÏ,×UêŽÓL«OmHóÄ×òÇíT˜]#`ŒÀ"!6¿8à€CéSß ¢ýþccãîÝ»GŸÿüçGá¸à¡`Óz;b¡W$LãÄiãðœþ¢6Äõ¦ñ9ên£ÌírFÀœ ãžzê©C øú‡>ô¡õ9Ë®[V¯ ¬ÿÿ£Ðð Õø  }îsŸ=òÈ# š[W‚S.™a·YíŽoDîxÕá%€eû€X/Ÿ|òINÁwgÏž=‚ýòG>ò‘£úî_o ¨þ_üßJ(4;v FK’6±Òu*ì' Íiqi|¥D‰ÒüÓ®£¬•½EeÆaø‹®ã°Ê•9¡0F`N@¦=ûìóçü0æðŠ  èåô¿¶¾À~á €€8(nŒüZ4wn[‚--7½¨¢°YLË(º&,O¯‹Ú§W›ŠÂg×#0„Í~#´Ú?ùÉO^Ô|A°_zé¥|Qd‡½€ ú¿4 ú¯ÔOHÀg?ûÙÑ-·Ü2)Ù`ãb¡ûip|ûÓ¸6;W§^ò¤ùŠÚ˜¦™vÝe¿‹Úë0#`Œ@NðO<ñD¡ðW=l æ÷.¹ä’SÖµ{@×Õÿáxà—ƒP8|ZÝ0¨;ï¼s¬>9þøãGZ#ÆM-e¥a}¦;=Ùí9î¢Ú¥þÆ×ò«­q?äO]å)*Oa©› á4žë4Mz­8sÞ>2ÄB-ö«-qXì/Š'¬(ÒVu)£¨œ¢°´ÌªiŠÒ•…Åá±?­Û×FÀ!# õþ½jýÊMeÜc¹ hþõ>ð#*gÌ”°S°sçÎKBg®Ûv>¼êª«F×\sMÝ"‘oš°›_Ô‰:yŠÊQXQy„Åáéuœ7K¯ã´òÛ5FÀÌaGÿˆCìŠ6ûUéËÞeÏ!ÿ?®’>gšN ÀAô/š6Yë&M‹j5¿¥\*+‚q|QƒêäQ9EyÕ¥‘[ÔŽ²üÊ#wRº´Ü¢´ ã¾Ú#`æÃ;l<{¯²Þ?©?hkaüµ‹/¾¸öyReqIÑ÷¼ç=/ ß=žÒTp}ôÑ£sÏ=w–ÆD@£¬ƒ}†Ó¶IB­(¾(¬Ï>Õ]†9áE¦(¼(¬(¯ÃŒ€0CB€1=lÚ½úÕ¯±4ýå/¹qó aÀQa’|i(ì?4.°b€uëÖý÷9÷ôtw}™@ªˆA+ÉRÇuLŠ®iȤ4ħùâ°´Nâ0EáUÃÊòÏ^TŸÊPœ\ÂmŒ€0CC`õêգ׿þõ£cŽ9fÜ´—½ìe£¿þë¿/ähk%”³x í %¸ëØÑ˜y¥ù𨡠Ú5M°§}ê⺠¯¢pŠÂigQxQ˜ÒÅ…uë0FÀLCÍõ+_ùÊÑYgõ‚±œqýÌ3Ï}ï{ß›VDÕøsß÷¾÷6¼ÿ¨j†&é:Ñ\~ùåûoÙ²åĦêÿSO=utðÁ—ö7²¥‰:Š@ I¨©]鵚B¸Ò̦ôÓ\Õ=-â'¥/Š+ £,‹â&WõÚ5FÀ ÆåSN9eôªW½jtÄÅ›ôÏ8ãŒñÆô¦cÙÞ}Œ—ïý_@|[Øý¿S ÀæÍ›+?ÜŒT¨VÎÜB²ö……•5©(-a³˜²ôeá”]W¦v(N®ÂÓ²¸gEiâôö#`ÚF`ãÆãuþ5kÖL¬ b°víÚÆÿ_ÃØ·÷‹€7O¬0cd'€°aï-MgÿôyýúÙþA‘"r3b7±¨Xˆá/ª¿,¼¨àYÒå',nSš¦N\YÂËâÊÚ1)}ÚV_#`ÚB`åÊ•cÁÜqÇU®²ðØcUN_”y²âåüà×|üã¸(]ΰN@þ¯l:û?òÈ#G|v1«‰…QÓ6ÌZ7é©៦—`LË( W¯ëØ-‹+ 'ï´¸²x‹â&7nŸýFÀ®à ³³Ï>{ô’—¼¤pÌžÔžc=vtë­·NJ25Ž/ÛöšýxUðEm¹€ ¼Nhª€41°«½ŸZtv†Â-Üô¡(\‚°(}“~«Ü´Œ²pµ/M?)\i딩r'åUùv€0¹`ÆÏF¾“O>¹p¼®Rßᇞ[®œê] €s6Z`iOÓ6MkB-èrqe¤éTî¬áÊ'WõézwR^âêÆOË›b3K›Ö#PU«VÿI'ô‚qºjþ8Ý!‡’Ež Ø»°ú†·¸!3ú;Ñ„NÚTýÎ'€9 ç/ÇD mÁƒà+ªcÖð:” ë²pÕ¡x¹ —[®xܲ4 Ç•?Îg¿0F  ØKÆŒŸuû¢1¹NL&›Ê8êÚslvÌš§uÀ'€‡zè!MgÛëÜÁæ ,­Ã4®.nÑ—+¡—†I\Qø´¸qÁ5~Ô–IY'¥!®I¼ú5©~Ç#`ê"À¸~â‰'Žød™nƒ i*ãhËÔ˜0žæQyK+ÿiÀÿà·_SvÄŒ½M#"ÀMä¬7³¬½Ë:~Z¾²úŸ$ «ÄO*[qªC®Âc—¸IñqZû€0M`ã8›ú8º7×2rQ{Me\26ξ㽨aSÂZ'amd¿uïÿ&— Î)ý¬ ÑÀŠL:xhZ¡³:¥-#Óꪯ:ÊÒV']Õ´ÓêªRVY7FÀ¤0†rT/øpvLSÁœ–_tÍ54B"º6­:0MÁ¡þrqÅŠx[7"áŒÆ¦$&˜©'. K;8)ââ:Òüñõ´tÄOKCyUÓTM·Ñ~#`ŒÀ,0F#ðO;í´;û»4œÐTÆ-,@õ’ƒ…rW@k2,{Â~†;>«˜X– xÒ”ÅQ‡„ç¤4UÚ’¦Q¹ix|­4rã¸ØO|•4äQÚiéãòí7FÀ!À¸È7ø¨ù»ší§í`,crÚTÆ¡åîÚt¢`Ç%îÙ³§Qÿzè¡Ñ,§35ª¬ ³ö <ñÄcÀúR]Ö'8I°“fRfá»ví5=¨)ÈhvïÞ=¶Üt´EZ ¶Tˆž†¥mš–†xLY9ŠOË-º&m•ôJ#·¨,…ÅiðÇ×Jc×#PÆØM›6gúáïå«fk=ÝöíÛÏþ™Xvm:%9Z€¾ @|“ 5,K<¤hÌÜT>_„0p&W6.G~ JÒ”ÒLŠW>•¥ëiî,éI§ý“êQ¾ªé'•å8#`ÆT¾×?á„ÆûªŒ{]"‚V›±?Çì¿é¹N¿;#Ì’Ù¤¡ïë4–<¨[ÐPÞÐ –6Š @ôÐJøq7%J[Ö7å+‹/ ŸUتEe…©üÔ-J›†©.åMã}mŒÀr!€œØ°aÃXÅÏ¡=Œ‘C5<ð@ãÙ?}{ä‘GzébgÁÆÌ=‡šã¾ûîq|ãP ÂL¹±ö@@Ò‡9|øÁIÄ îaŠÃ«úãzfÍÓ4oüUÛètFÀÌ?hMöÌöþŒwC7h´Ù˜Þtó“âpVN/ÝíŒÐ;nrÓ€”C}|@ݳ„Ÿö ðPƒDB0Im” M-#4y1T¦ÜYúBå‹ýUËHó¦×UËq:#`æÆ1NäCècñ7ÛºF„ñ‹µÿIcxÕ6mÛ¶mÔÇ´¯SSb6œã{GÂ4÷T½iuÒñÐÀ±ìe@Õv J™œUÒNJC9MËRþœeMj³ãŒ€˜_ÿÙ¼Ç Ëø=¯†ñ¡ÝtöOÿï¿ÿþÞ`è”ÐKnºGÓ^ÃÀrþ¡CÓöÌšŸË2L"À2 ‚:ÌR¸J ãVaÕqúYû§Oë'.WÙq=ö#0|{ø\OBÍš5•Æ£¡÷Œ \Žôóá‡ïë«Ï³ö;ž;vìñ`Í»G}tlyqØD!ù°@IDAT¨"È‹0ˆ°tQº8,·çð§e§×9êpFÀôƒ“>c2Çñq³vd§µ^_wLVýŒ}7ß|³.{q;'ô’‡‚Í€ÐÔhF×G?6m÷¤üà¢M„¨šØ8(2À¡M_ªTè꺬MŠÇÅÈ-Kß$¼Í²›´Ëy€x1ŒEk×® }?ÚËE5|Òº¾é—lÂgË–-ãuÝ‡Û €9±þcC  I…Ž\DÃÑÁbXàE£¿Xw#á‹+[ÆrO½òãÆ×©é#`æ>öV¯^=žå£â/#æ¶“ glã“¿škŠgÜ­·ÞZPS·A½ºLXUƒZ†›Ô÷±9ú2­ pK 4¸M5qý±p|œ¦Š?Ϋ2É'¿â«”å4FÀ´‚ñJ¡?Ï÷ê"Æ áÏ’s.sã7f-¯n»z#<\èóÃ853ikpëT—i¿0õЗ@úˆÙ=ê|ÞS›z0Ûg3yÎ%iZ¸zýõ×ï[Ž­×ºvr ‚Ð5ÀçPÔö§žzêXãŒdÊE•€Xí5ûƒ„êJÿg ÜÌ(Dp! J&BÈ®hŽï–öîÄÂ>ç—>Í[9ÿ%0¾!üër>÷ʦ¿´oƒ!4 ðÙ´Æ Rì@…ÑrT"7†Ù|Æ8´  ¿Ÿò$/$ Sci îfAÊ£ 4”ÏÚ™M7€}™&GD@d€kÙnZçZŒ@} ³Ú<«´øzTù6Ã@@“ÌǼ•1ÎÝtÓM#¾÷º$4<_°€šFFŸ± À!uwUò Q ?ÄÂ/¨îÇ契栬" qee;|~@. ™ù·iÿŸ¯·ÙδìÁŒ` `Æ^4ÃÔׯ_?þ‚€ý"Â_3ØC"Ð& u€\xˆZ¿î«Üi=! ‚\âb|†O«gãy·±3î‡üq¸âp±x¹J·ŒØ¹ÏŰ×9€à/’Źê…Þ{ï½£[n¹¥õzêµnr®¹ tA*~Öëìe³|mäæ³Ë“¼³<<<,+ÀÑx£àä‡hbL" È fcê  Ì:ùÇb˜´1a“Œ(N•/’qà 7d?50_ «•4W€.qƒa[„%iBå 6Œ—Ð@fùz€‡‹<ÜtˆxVT j§2FÀœ°æÎ˜Þ…ªŸv#{î¸ãŽÑÝwßݺ†!'NeeÍ #Ülfæ„1Á4mù˜!À±Ú4ˆV_ňGŸ#BBlŒ€0F ;þ*ã~®V1idÖ?Ëä1WÝm•3·Ò‹€SýŽ=öØñ7¹ìîåaH?,N›Ù8È e†_u¯,mé9ä2€kcŒ€0í À>ÆjÆÞª“¶-¡^fü÷ÜsÏTmsŽúº,cn !ð9 €Jž5föe_ ”‹ y`½Ÿ>åL3Î*ÀB(Ø#à}ÓPs¼0F :hxYúEø3æviÐ4óg>óöy_UŒæšÐIn š–Ð ˆ±ƒYÕCä§,d¶ï¶. †ükDÀZ2´nŒ€(G€1Wjþ*“±ò’êÅ0‰ä,Æô®IG½×Ë5÷€n3s‡ ÎGˆ³Öðå¸NfçU—b¥Ø´iÓXÕ¨²Ã”‡…+­š î£k¿0Fà…0vj¶Ï¸]eâõš_±´€ªŸsüû¨¿yf+a!]æKþs™O™cºÌĹ© ÿÐ…(ãBá†vèíñŠ) €ÀG]{do²Š!Tø¼$<„¸¹ ÂzíÚµc‹ºMûp«>èˆ cBû.¹<#0Ÿ060nÉæÚøÜ6´õ>»5®µ]ç"—¿Ô€ ÛEPeI }4c‡}jC åå6ìI }X^\ö$@Ð̲—ÚÉ2– X#` §fö¸Uö ÆWZcœæ³êª ¡´ÈíXzÀÍác‡½ÖãgU“³W@yÈh°ÜÜ&Ö@P6Ä2€¥ÎY –üʇè‹Ï!˜U§7ý €pd BÈKèãŸ7¡I{Ù×ÄlŸ±™13oýèç)¨^« @„”—Ý™03j–°”%|d€¦K Á_ó’ @3€@¯Ãòi§Œ ¡OàaR DìþXa#Éø%¡¯ñËB?F(¯ß Áök’è™.¥Zç8b‘¶44Œ™ºÎàšõ=È/õÖ}‘¤%  –% 19@{0«öDåÙ5F Þ]ÆÞEÍìqë¾Óå5uCû™¬ âgܵÐv¼`hvMLüÁš5kÆ/2å£Ðߤü²¼" h 6l]í@\åacC?ÑÄ‚1°1F`:DÞ+ƞئïÚô’†›"úêÛ¼“™á"^Þ²f’­¼Ü…ˆáÁ„•êHß\Ò§yêÐ2ëùm½-MÐf"¸9–(h;åbcƒf" mmѵ51Rö/ ¼+Ò¬!èñ3àok è[úÆÄƒu}fûo±¯}âúQF `*R ×Z¡gw^@¸!ø$èSÿ¼ö«j»™Ð ð±Z>´À¯Š^7éL*âŒpæAFpBÚØУlÖñyQʼD¼<øÛ4Z.`¿‚ê þ6^\ˆÔœiß´œ BQ¹Ö¤ˆùºì¸ñ,^am¼7}ô³JôYKŒŒ•àY& ªà4¤4&3Þ ߢêyÚD”ËÄXféK- õrÍØüJÉ©;þº€Á:eÛ\ªP4Š´Ї @Dt A ¬­û¢úí.ä¸XÞ; {Ü6µtCG˜w”1‰–ñIÆB_H Û5¨qôà# й—Šškˆg âå)`pjËPwüuƒž4ÔO; »4Ô‡å44Ú.rº¤1Q(BoñÃx†õ ¥BžpÂHcAöü³zïµh™ ÐóÈ̯Ï Á½c €ù2ëD#€ÀéÊh§=§"ÄÐLHã¶©!@pÆ#X¢†·MBRc&0™fDpEp.?×X†iˆöÏ3(.áŽ+A®8][°O¿Oø{M6ÀÔØMÇn^Rt'±æ‘ídPá{û66 VmŽ› yA¥!€±cËfÊUËŸ”¡¨%þ¿“‚6 ɤ¶M‹«JTŽˆBì¦~ð ‹¡0•c÷Å ¤yvåâçþÈJˆ+ ׊#̦à©ñ¡|m3\‡œÛ ãÝáeŠA+¡?-¢Mz¹µ±P/w[íÕ¦B}eÀlœ:™Ih^UqÀ©š>M'b r19_.ÄCZŒÂS¿â W¹ø‹L\ñ îÓxž™8}|ÿäW<®°ŠÃ^äª»Ý À¤€w!n¼Ñ˜ûc³ø˜d¼ÇC~i RÛÓN,B™—Ë`a% ¤D†úDD ·¨®„â¢öÏý&h)õ®Kèó,yÌ&’‹Õ*€ÅºŸ•{ÃLPBYŸ2 ª!€`Û$¤%`†I„RPe¿r§Ð,{Íîqy‡peÚzŸU¾ÝùAÀ 㽚÷K¤€åö3Ð,ˆùÖ¹M¬¥PÙ©(EàlŒÀ²#À»Éû yÈ;ïǼEË~o»ê¿ @F¤ñ¥ƒpøÚþòC?!" @ DØÜ¤{¨Ÿ5éxùbÀµXTâ÷÷NZº˜ˆç~÷K÷ëyLžÇ¢±o™^@fë:N8Ö œEp™0`åĆÍqÚÏ ›Fùi 䯤ÒÚ5CE€ç•÷Fä—w(&×9ߥ¡âàvuƒ€ @Fœ—ýÅD[ ÃwX߸" f±w˜7¹Ôî) <‘͘ps’&ívÞåC€÷AB=&Ëøã÷AïÅþåCÌ=n €ŒÈú%-á̬]ŸµÅ81ãaÐ)ˆý9fïÒRÄ-£~[È€ˆBŽ:ãºì_NxÆ$äõlKÀãÊÄï‚Âì®0Ȉ´_æÙÁŒµkŒpÄA€àg0ÝÙk|î{úø ˆ¸ ꉵ"h lŒ€àÙäYa•?ŸzŽÉûU†]#Ð7&ï€_òŒ`†¢ ì5ÀÆÇ,Ç8k†”ÙYZU´¿€üԣ͎ñú¬üq›f©Ïi‡‡€ž£øÙŠýòjy|ïc¿âí¡"`ñÎøåÏfÅ¢DbìS¿tÂc¿®åNªbÀ?•„ÈDA~„×q›ÊÊpx{€¿î³žØåþÏýÒ½’K«ÊüíµØ%ö0ȈqjÝÎY>€z7Ì nÎeŒÀâ!ÆÃþuK]l\pÁO†¶ïi©ýƒ+Ö`p·Ä 2FÀÌ»»hpë`o'vtÑ™!ÔaPï.XP7ç2F`!x¼‹^uB‚P|¸‹Î ¡€zwÁ nÎeŒÀâ!ÆÃ-]ôª:³­‹Î¸ŽùEÀ`~ï[nŒ@^ÂDòî¼%—Ö U¿¸úÅ µà…÷5ÆC~ÜØÿ¾2FÀ,/al¼¦‹ÞwE¾ÓEg†R‡ÛPÚ“³ê›\Ê–7öÏR/ù¬˜1§5F`Axú§?ýéõ]ô­pÀ,%H…¡®¹±òËíâf—Õ¡6àÆ~¥/ S\‘§/ó+Ÿâum׿˜L7ǰÇþëUW]µ8_¼ûÝïÞÀ¼¹G@;­ºŽP#ò¥n®ÆÕQµlµ‰ôò×)oR^ZUï†Ó#°À|©«¾u¢ØÛ™OtÕ©¾ë ê›IÚS$øfigœ–|qÝUóÅuÉ_%/i•^nQýEq„™TAÙiŒ€X`88¯3YÙƒûŸ„ŽurºQßG,à&µEéäNJ›Æ‘gR¾Iq*+.£JzåÃÓÇþ4âpåÓ¤e¥q¾6FÀ,_ºòÊ+ïíª¿€÷¼ç=|ÖðÿuÕ±>ë‘ KÝ*mjšGù'ÕU%Mœ_éqåãñÇ᱿,]QYÖ¤hùÚeB Œ‹Ðe;#t*tî£]v®ÏºŠ„`û'µ“tUÓN+gRöL—uwJ.¿üòŸ†ü.;ØG]E/ŸÂpcQû_GØ´xå‹ëR˜Ü*eÔͯ²‹ò—Å)\í³kŒ€X"®=ýôӯ躿:÷®w½ëóÁù¯]w´Ëú$ÌR·¬ J—Æ—…ÇéŠÒ…Åy¦ùËò>)®¬Ü4O|û­(CÐáFÀ,8¿Æ¹ë>vNövð÷Ù®;ÛU}µX°©Þ¢0ÅÉ-KS®|U\Ê(+§,œrÓ8]ãʯtº–«vÍ’Vyì#`–O}ò“ŸüJýì…\tÑEÂoõÑá.ꌅŸürUz­ðin|eyŸ·¥,iÊâŠÊŸ”Ö€qû€XtÂx¸õÀ¼¬¯~öBèìÊ•+ÿeèü÷úêx›õJÈÉë",ýiºøzš¿¬œ¢|ei /‹KË™”.›tÆ¥õøÚ#° °'îï~ü㸯þõFÞøÆ7>þ#àáãOõÕù®ê­"äHS”®,)M•9 šî7^rÉ%¿»üºåP7c®|áÏ~=”õÊ g!î¸ãŽÑ1Ç3 áãY2³ÂØ’.¾–hááÛÎQøÄƒfík¯ü©KdŠúS—–£tMÝT ·}M{©ƒûÿÌ3…Ý*ç7FÀLD€q á»×¼îÜsÏÝyÝu×ý•úr{%^xáßïBç÷i"éöÛo­]»–³ö Ï"Á¨0\L|-_áµ!m߸±Q{ÕÆÔU>…«<]ãbâp®› lÊHMÓ2ËòÇáøMRä}mŒÀ¼"ð“Ÿü$þc"Æì7¿ò•¯ü›`nê³oûo×xÛÛÞ¶"Ôyeô_DBíꫯÝrË-]7+[}©`SÁ„Çq ¯ê6É[µÒU©'íË´k•›–^ÏÒN§5FÀ °¬=zâ‰'â™ÿ¾f†¥€ýƒœûÓ°pê¾À<½€ƒ:è×ÃÀ¿±¬Ï€¯}ík£o}ë[eI.¡&·¬±i|z]–¯ixZOzMù„ÅáéuYâ½NÓOº®’—4UÓÅuå) #Ož^ÇåÚoŒ€˜'ÏvïÞ=¶ÓÚÍ$7h ^–‹/Ÿ–¶­ø^À¡‡ú{¨ÊŸ Þ}÷Ý£O}êS£Ç{¬-²—˃ ·Ø_TYÓôi™Óê#}Z§ÊHó¦×Ê«ôºNËK¯•>-/½V:»FÀyA€ýk»ví1û¯jH&Ãÿóûßÿþ×WÍ“3]çà‚ .ø¹°Ñë-³vâÁ…¿LÝ|óͳfí%},Ôb¿‡Å~ŧn•4ižôš2ŠÊ) +Ê[V”7 K¯)‡°8<ö§õøÚ#0dؼüøã˜ÕÏb A °p'ä{þs°Y i¶spØa‡ý³ºí…-±9;¯»Å«¾:°(OZ×,¸ÏR^YÚ¸¾²¶”…Çyí7FÀ Æ/6úa‹ÆÁ*mÞ«1xÍ¥—^zI•ô9ÓtJÂÎÿu¡³onÚ›nºi´cÇŽñçoMËj+¿¹Ôû«ÖKž4_z]µ,¥+Ê_V®²ä–¥KùNÃ(£(LeÛ5FÀ c=v,ø÷ ðÚÍC €æ Œ¿dä!µ ª‘±S°nݺ:¹¿¾[¯ëž|òÉ£ã?~¶S£ï­g‰…ZìWÅUÔ¾ ·j›ÊÒ•…Óö8¿lýrFÀrÈ!£×¿þõ£w¼ã£p Ï¾sXêÊ3òñÉ`0'†³o>”£U˨¼¯j“ÒµýÃg“’Lãt½7¾ñûÒé´=XÔL*ì¸É±!>Sú4,¾&š/Sq=Н¦|Ee…M«¯(OQ˜êµkŒ€ŒÅL>_ûÚ׎ ˜óÎ;otà 7ŒûiÚFÆÁPǯ†r>Ú´¬ªù;#úЇNÇ!ͬ½‰9餓F«V­zQ! ’½7u_{ÕÆT°ïKСGmI«ÌN³”S–6m›¯€0]#°zõêÑë^÷ºñ1õqÝ|ðèì³Ï}ï{ß‹ƒ›ø_ý¾÷½ïœ+¯¼òGM ©š·™4®ZKHÖKþÇ{ï½w†ÅIÏ:ë¬âˆ:¡ªÆIÆm",¾ŽÓ¦áEi‹ÂTÆ4—¼e¦(®(Lù‹â+ 'OQ¸Âäªl»FÀ¡ 6­Â‘½£ÓN;­pì¦/ùËG×\sMá87k?öއ ùþÁ¬yë¤ïl@Xãx+êÿ&–?bí¿ŠÈ! —²¶……•õ¹(mQù /‹+*RúIåÅ©¬²8ÕŸ!…Û5FÀt…šj&›ï~÷»G§Ÿ~z©ð§=Gyäè„Nh$Û‹ZÎE^ryø—Ü.úÚ™ œŽ´¹©úóæÍoD ˜„MBEuÓ&üEm( / ›TFÚg]Çõ+l’;)}Y\Y8õÌ7)ý¤v;Î# Æé—¾ô¥£sÎ9gÄ쿪abzÿý÷WM^šnï9ëÂÿà¼"$º¦4a¦ˆNÀïÿþïûWõW5ݸaÆ™»`TØUÓúg­\B­Šð/K;kx•6ªÌ4mY8éˆ+‹/‹Sz¹q} +˧µß#Ð&ŒÑlð{Å+^1þ+úYëZ¿~}ù‚œB^…Mí?Ú° €û榳n\×ð•€iK‘P®[vÕ|z¤ï¢þ¸¾´uã(§,oYxœ§,MYxÚn_#`r!€’C›K+ÊÑ ƒúʦ€¶ë-Ú#À7MÛß ·¢¶Kè•Å…Çeçö«=eåNŠW?Ëò>)•øIe;Î#0 £Ž:jü)Â?ç×ÉD²iÙX—Ý–¿˜Ö!QÇj÷v…nà@}£¥œÚ†¸½„ežøºqq=©_õ¦áéõ¤t“â(GñrÓ²•†øIiŠò9Ì#0 Œ£lÎãþM›6•Ž«³”9)-Çù6•sѸxàÅ_|ðUW]Uý¿…'5®$®XÑM™ío“- °O²¨{S£›9.žëIÂD“âËâÔöinÚž4½âå¦ñº&>GÊ«R–êµkŒ€˜†ªøOTüÌöëNÚÒr«^#›ÐG›øªf}Aº˜¼ ¢¥‹N4áæüº÷jweçÎ/:‹¹va3dDó€ ‡ø[å“à«"¼‹šCþIy‹òT «"p•FnYÙÄË–¥‰ÃgIç³ß##ÀF>>ã;å”S:›ÆõËÿè£V’ J_æ²­KÓ  C¨büñF}kš¿Qå!3ì,ü¡ÑØ¢¨#¤%TËò_÷£(ÊŽÓù«¦#ï¬iI_%ÒUI[Ô‡#°\0ö2ËçdØ7V'ÛFè±Çk¬þgÙ¹é$yÖ~vF`jÏ&†Mz].Lj«´»víï`Ý)=§¡iZ.A7I¸“fR<íšVŽâ'õAq¤­’^iª¦Ÿµ|¥·kŒ€ˆ` eCGî"ø«h`ãümú™µ?òÈ#Û„†¹kÓ@@6Ý 8>ø`¯ªžô! !&XJú ÙÑžiè1ˆIA\¦ÒÆa©¿JònS7=ùªæUZ¥×õ,ítZ#`ÆLÖõ;àgyˆ™Äx®1½n›NëÔÛ`7=7!ØÄ°5I2ѤEya‚h°1ˆ5|àÀÎ5®¹Eå¦ôeñE᪳(®(Œô²EñeaªGnYº¢ð:yŠÊq˜0ó‹ãߺuëFüï 3ýxìj¯~øáÆòˆñ¹ÑµéŒÐ1þ6~S³mÛ¶ñPÓrÚÌŸ’´|Á€† ÈHŠ@ bb <„Õ1*¿nÞYó“^yR680‹‰“¥cŽ9f<Ógmí鼘‡zh¼A¼é’[¾8ëÚtNrt’õþ|aØ!72ÀF¬4HÁ´GB4}0ê• ä´ÜI×Mó«ì¸þدx»FÀ,6Œ}¬é#øq‡¨Ñv˜¬Ar´e„>L§a‡Ðf]SƒQAØ´î&ùcÍmG#@;2 ó•0ŽÛBØ,x¨ ¹qYUüʇ+K>…W)CiêäQ^»FÀ Æ¥Õ«WUûýU«V »ÁZ·}ûöñX7m7­(vÿC$ú0:ˆÀË1ØÚŽ;Æš€>€ËQ'8è³B ä2 íÀ,Â\í¡ÌØ*|š«<ÓÒUË‹ýUó;0ó“„=kú¸³Lp†ÞsÖëÑèæ˜ýßsÏ=YdbÌ:'ldŒmj¸ËyY ˜Ö_}MÀ¦„?j2^"‚iùËâ%€q1r«¦/KW'¼¨- «Sžó#0 Øè½víÚ±°Gà3~-¢a:“ÏŸ‰, /Ó9 £€ß<"8PÃpDŽ›Ñ×M(ª—¾±aR›&aÏT‚4ý³¢XèÊ[¤uˆãikz]Ôþºa”mcŒÀð`LB­/¡ÏØT4~ ¿'Õ[Ⱥ?2'Ç–Zo½õÖÎÿ‰{Û @XóðäØ ÀxàÆkKM×bb`†æ+6?b1àà¥Ã–}]0k?bá^UÇy¨¯èZíHãn×a#À¤cåÊ•c¡Zÿè£^x߯.„Žì”Ë2ÂÖ­[ã*:÷÷Bè%Z€€²(G$`Úwô¤_CŸùt‹O4Z2hª!ˆ1J…¶®ã4Óüä)2*«,¾(ÃŒ€hfòL0˜áËr½ÌáŸCs †Œw7ÞxcãsqšÞÞ‚šYk.@YKprÔ"kÊn¸6E²6…¾¼´¬Åun\$´-ÄËîŠÃÀ| €V–=—]úL*lžÖlÒÎyRëþìõêÛôFè8jl6TäÒ š X´=³>(¬UÅ{ÈV@d?¶5»”èš6È[dÊ‹Ò:ÌÙ`"À²!‚•>vÙg÷e(2ñÉy®‰*õ°yý–[n)«²Óð^ =efÊ:>+‡a&|ÿý÷—€`Ø< «}X>_QˆtýEÅ4Bð|ëí3F`V˜iŸ_‰—e©tV¼âôÈ%„®5ÊfÂ{Í5×d“wq{ëø{'Zkb¶š‹ò}÷Ý7þþtQ?E©s³Ó<_‘ʼnˆ@¢ mh T§]#`š!Àû yGØ#äW¬X1ö{ü«‡+ã"kþÈ’\†ñöÇ?þqÖ¥„¦mëÐTR|J+e­%Ç' ؛ֵšµ,ù‹H}çÞ@ ¸ú’ÃÄ`Yž ÷s(ðþ¡²GÐ#à%ì—}Ù3×ýaw>'ó1æ4|òÇõÌ €°€‡úôÓO“ˆ@Žð裎Xೕܛà†t#Ûn „*ÕP§Èƒ¬qnûn¸üEGb ÙFÀ#èY*•ß›óÚ¹ûÈ6Q?öØcÙ+¸ë®»FØ¡™Á€a—%3Mþ‚?ûaÏzuS"À¾·¤LovÉûBÜŠ6qB°\î+~k òâïÒæ4Â]!/Ë;cÓ Ln˜õ3YÌmØ“6”MißEh꩸Ž;î¸ñÌ"ÀL¾ `Y5Ø4DÀ/Wú(ä½olÑ %BÀ=…nc ˆ/ëó±Eà3ñl¾ÿ»Í$Sç©än ²ëúë¯Ï]l¶òGèÂÀËŒýC°,€Š¦ €`pæ>{x mºG@ä ¨fdûIkíAbëžQÆ*mšÅEÐkìbŒñsÛç*¯›Y?ßâã¶aÐ:sØOyÕF»â2IŒú=ìà µiÓ¦ñA?Ä¡®AÔ1ììd3ª6´ª£NYΓ*_‚ˆ P3~½`hóÞ‹e/ áŽ@g|À• —K˜gðó÷”0Æ0ëoc­_hpÐjM š;HH‡ç_¥xex9ír€6­@Ñ´ÒOrÙsÀþN½b'­È$´†dzQõÅštO«–1œž»%Mày` Á"¼qYz¯kù½$ÕíáåGŒÜ¨;yœÖ#Æ”Ûn»mt×7üµ}°€Æ&$€MøãR€Ÿ£+Y¿!ªýY eò@p:DÀ›gEpøéôˈ€ž+=[ºf– ?.× ~—£…Œi¬y|-AÏŒ]~ õåx6Ò^¢ægœ¯##Ҳʮ!|çÏ^³y1ƒ&€È   6lûSæÆ  ?«à0!ˆª èUoZêA­Gy¬ãÙ,>“ÈAYïSb_‹,(L¤!¾¦Ü8]Y=‹ÎûŠK¸„¸üÄ&a®ô‹ˆ‘û”öŽ1AÔߪç+ù…%¡M¾öÚk[¯ç…µ6¿< ‹}Öì7nÜ8Šv–“ŽÙ;–xö ÔQõÀùlƒýþC PµIð"<ÇŒRä“®_ä'­ŒÒ©…Ë%•=Â}šA½ªMƒú$„¨*k`I@ÿ¼¥5Ïiu;Þ#`š#€ÀgÜn럢2ö³ÖO½‹bæ’¾Hç  `vÏN~nRUažjX" £†¬7A8GÀk·Us#`ŒÀì0æ£rgwÒÒïì%OÎA½¬ó3ó¯2Éœ\Ú°bç–#‚žO÷8aάœo~Y˜…ÆZ4 |=€`çÆO3<¤…òé dÀg LCÍñFÀj0–#ø»ØØ—¶ˆ±ýæ›oÿQ]·×sM¸Öó֬ͳñd ê²@|#É‹åk:>%Á¦U ^Ë ˆ–o–mŒ€0F :L¬Pó3Û¯{ÒkõÚ^œÒÁ‰~|A6mìqîù Yé„ †°SƒàE-ª"0ëMd]BEÝDùØ*¥€=B&t>¿ƒžŸÃ-5F {˜D1ÓGøÏ:fçh-cý–-[F÷Þ{ï©û‹ðY@ç`‹ßøï~õ‡0ºYöÄ`A&øï,u?dr1Í@>°ì/Àµ1FÀÑxEèc¿û0 6–s†?ãzä£~/@©ýÖÚ”ÇÌ›ÏöX£'¾Ê,¾ìfP–?$‚¥Bªì@;¡‡œvi¢*CÚáFÀ,*Ì´?Y^íCÅ/\ô,!ßyç•7€+ï"¸ G¸)0¸mÛ¶gì±€… Ž‡ @ªîø/»ÑRí³_íD Ê~X.Z,Úi 6FÀED¡Ï Áßd–?“7vö3f/«YHÀÍäaã –ÒC{˜#¼¼Ú¸×DåÃ~Ž Æ"Ü!÷*d€v’k2°¬¯¡ûm! }!ÌW^~4²MÆ}•7ÏîÂn jwÔ;lÔñÍBp‹ÀLëîˆË„\èøá¦dâIÁõÂeû€*Ìî5žVÙ'ÕE?ôLÙÜ×TóÛE{»ªc¡ €@d&EP$H!¬ÉCxxQQAšš¦d€vci3ËZ* \#`ŒÀ`¬”&Áß×F¾",h ËÁ÷Ýwßxl_öŠÑR:`ç›NŽæ° "ƒ EÈbùj€‡9ƒÉ€Ôþì€lL{(‰× Æ×ìk ÚXDjŠúç0#`Œ@ôUãRßëùEý¡]üq³~Æ[›b–†Ð}v›ò@ ¢G€N2®ä‘:kRúYâXë×ÿèëö °  {†”ˆ˜ üY"ÀÒæxÓã,mrZ#`Œ@QMBøUÆ©²²Ú g¢ÄºuëÖñ†ìi«¶Ú1Oå.àÆðPè~6íM›=#P±ì#à`Æžóágù²±´ ²¡/ª|£<äài€”i;ƉýcŒ€(@€1Aelò,šÉÚ]TýÒFXøÜÔ‚ ¥#€‡;iI@iqµO€½Ò PFÎ 2Zá€ÑBô`Çm*òóâê¼â!Òfp(ÖÆ## |ÔûØ¡ÆE„>»ú‡sŽÅCï{®ö--@X-_ ð…À´%ðX+ ™ˆÓäðKµÏ¡C¼Z& ¾ª†­!€P6ýÀ?M Rµ.§3F`>`Ö̘¢Yþgø1¢ší³”Kû-ôctf÷/5. +S•%b´úÓ­‘!hÛx™Ôüõ1–ò©í@Õ}j7„@¤Ea,HK r£8»FÀÌ7ì3’°G€"ôs|åÔ*Œwl˜FÍÏxg¡Ÿù¥'‚’—m$!8«AˆbYËçeCÈ"¤ÛxXÙD¨?*¢|êÒ'ƒ,ÌjXÒÀRFËi ;6FÀ ;B^3|Æ"Þíy3Œk}¾zbÏÖ<–yÂÚ º[ÌŽYOb9A^G5NͦùÚb¡wd Þ7°~ýúFÚA‘.逘%»F _RaÐGØ·1ÎtÑSÚÍ àgÂÌkºÀ¬i&2‹æEb–]G "™5C&ØØÇC @+Жf€zcí×ÚHÈ‹UG;@ÔpZzx.乑Z2€ áºqR™v€x1CÍæ5»ç}œwáHûÑ<² ‹–>aæ½_/¾ƒÃ 1(¹/¼p0QíÊo*ÔÈÏÆ;ÁÚµk÷‘´bº%Mio$dàиzÙêVÀ Rƒ•¡Ÿ‘¹#`&#ÀXÀäƒw5¶‹$é#BŸñÁ¯qh‘ú8ù.'Ö£ò”{€†y³$ÐDWƒ„`1¼èZ&ˆ…iœ'‡Ÿöë"Ê£®˜äXgã%/llè3$€6È9 ÎÆ,AÞ{ {„ ×mNúÄ—¾¡…Dàc%ìåöÙ¶e®Û ÂÝç¥dC ³i4l’Ëe~Z[G83@X&ÀmóÑ^4–`æ‚ÜËôƒÁ›ˆb ¢Î&)Z¾žxÞ7$Øqyöå¶ù^úÇø…°Gðã—Yô¾«ŸóàšÌp—˜1Ãd!6 B0ÞáPæåÁ¦³êÜõk¹€O ÑP'dRÐdÿÀ´v–òI[€›ÚœDlZoRxGxv%è%Ü%è—MÐ162V ðqU›‘>ó|m0ãÝã¥fv,"ÀŒµ-Ãì7ÞƒÀ#2@¸nËÄ'Æ_P/2ÔÅGËú >"ܮ巡­'d±ËåÙF€ÅÂ]Ï¢„~Ž%³yFl öØxù²‹±až±JÛMjÞ Ô[¨ïs/ ”5 á&íi !1!h“q§u3ø¡`hcÉ  ƒ8œAFÚƒ2 D2AÀ/‚€«k\…ÙÅöK°ÇÂ]a¼×ò/6 ³÷Žw^ï»Æe'A³£8¬& ïB!Äz:›úº$ñÞºÁ/&/)nÙ̹a—ÇÙšÒN°d€0f@Ý$Hû6 PXîÑ$“ƒ,á±_×ÿ{×|WU%"$R¡RË › ZÚêŒ( uA”W‹âØNã?´c[-¶Õ±Ö¦©dì@)Q ))-§€B’"4„Lšy‘wBè÷Ýü¾de÷œsϽ÷ÜsϽ÷Û3û®µ×^{í½¿sÎ^ëì{î¹uç¢q{Ï;_žk:Örà’ñ:NÎÉa9fÄJ×3©vý|w?,G°ý8´Ç¨”†¾ŸçŸ *) àÛ ™´CÀ»cf±ã£CÔ3ñ¡Â¸€ô3 éuNtÄ«lb À9+8å”±¬œ–Ëö5ÊzÄ…Y[Ž<Êc}ª7ÊøÔ97­ äã®ñw=TxL›v‘ðIzn}ókŽ «‚^ää)ëWJܙРë™pëeü DšòÒãqRx–S¾%À¼¤vEç,ëÒzÍ›vÅ“JOmRJé©NíóÆhyÿ öZtM¶Û%ëßhlyP8¨y-‚š¬Ô·íõþŽ—Q?fî0÷küÞïS`VÒ"Ä €é¸$;Âq9Òƒ§®s^[¼¾IyÝéüìèÜû pP!úýrœñS¼ ä.3ÿÕI‹…‚Ñ~ÍMï"àÿ&0ñ΄ ”2ƒ‚N¶æ[FüaÆxý*°'»-ýº–Çò¡ž¶€ ß(\XiPÀ9iQ¡#޹—íï<صKÁ %nMj›R;Þ®:¦ãН?^ ÒEugOLFa=×c[×¼Tˆô¨^p1( \š§ tÊ̪¯ Z=ÇÀg”Ø·‚R.‚ ªî[ý™A" kL;r,ë¡ÚxÎG~ãußÀ€ Ó¸]||^[øqî ¸@1 å‚·!{…}ëgˆ²Å1pÔw h¡”ž©h*¼NxÍÈá+¨Ž×N¼Öš:k8pPñqâÅ©'¬+6=4æ¸ÏÀ€).V Ð)+Sõº(qW@mp1Aî¢â¢õÍ~!Àó\×®žŸºâuù~ÇvÇ^´ãäAÊÀ€ï*àC‡JÄ‹™ÎX‹ Hf–«ô £ú¥}îp&ϲ“èžÏ:wéäS‡O»ÔQмd¦F TŒ²/æÎeÀÄ-}tÖCò ”°L^òÎ{ÝûGCY/n¢]Ú- e€àdxNòѹ¨óP,)Sz9#Ð4T|DâE_±é±5ÇÀ€™ØòÀˆ1yf- RÛ´’Áˆ^buiƒwt Hų¬õÍ:oäàYÖ¹EÇ®úx>åñÃ7{xÜpPñ‹AŦm.î ð%CÂ^”êâIãâ­r¤âsºi}µ“÷u‚úJƒî08 ó`Sý踊ʡ§e!ëcJ˱μFT|Ô¼HT hEæ$Ä™ÇKŠ:q«XeQÕÑžÓÄãCg-ì#O™Êrè±,JÆräUojÆe/&: stæÌñxŠåÐÊðtDLüj_a(¥mc Dˆê.–eòMLšiœ˪㸅䑪^2Í3¶Ïã©ëÔÖÔ½8¨øLð‚S1 CH)>6IDATdŽN.+Ññ+åQN>¶Q[ÒTOu ´ÃÀ !‹Wð®ÚGš×GžœmUG*>ÊËòEz¬s2F :T‡eËR\ü*6ms#„Ï:bR:kòÌâ%Uë£,¶cë•"ŸÖI'•Ç6eø´}´kÞæ"à âcÌŠMÛ\ ȉÊÑÊÁò¸Š'eY:¢’KOmX/™(§Ï•<¾¬^l_LîÂ@ÀÀÄQ™‚(™²dœ£xÕ‘F™xR&ÖË9³,^”z1G»j/YQYu¤Jl§”Ç«ÞÔ#0TŒz\ì+6=Òæè”×®]»Ïñs²r¾Â´ß周“3FÀ$LJÊ.öˆ€œUfÆ®yÞtc„'lŒ€¨ í ;@t‡›[#`ºEÀ@·Èå´sL±€6¹Ú#P1*Ô@Å€Úœ0FÀôÃê {@½ Ð=vniŒ€è"ÖFß@€ ª€ã*#`Œ@Å8¨PšsÐPmÒ#`*EÀ@¥pî5æ ;P½ÐnneŒ€èZ,ìcõGèº9÷þnw-ÝÊ#0ZÀôýo>ë ÖÖ¡)ž€b|òj½‡ŒåFÀŒ¯ÜyçÛú=çZ8Äû=‘&ÙwФ£á±#`†—0âý(Ò§á×`ìëú4þFšuÐÝañ@w¸¹•0#‡À³ų– ûsuL¦)}8èîH8è7·2F`äXYÇŒj &MšôP“iJ<ÄC˜ˆRC|¬?°¥KFÀñC7C߯cÖµ?þø˜ÌÆ:&Ô„>äØš0–nÇrœøNêÓ1äµõ@Š”ËFÀŒ)×1ïZ€™3gîÁ¢?6»ÑIò ªyÉHÅ×qÀ³úˆýG>K·Œ,ÚÈãËØ±Ž0F` Ø´ Žy×p"øà¿ê˜PúˆN¯“ñ¨(ÛŠíÄ^–®ìŠÏÒKeQ?¶ë»më€9—€7°>0oÞ¼ZvÌk poAîû‹ šp²Dg˜å %ëf¬ÑvÙööõ#_¦?铊OÛź<´ËFÀq@kâMuͳ¶à²Ë.û&u]†~¢ó/ZfüEº¬+ª—}é”Õíb[ÉSuÄgé°Î;)2.#0flܲeËu͹¶€Â?§®‰ ²9º”v2&¶Uûví¢^äóڕщm£~ä©£2iäcûÈK'¶õæ€0ãŠÖÇ[ñÀ­uÍ¿ÖàCù7LlU]“T?ѦcŒT|ª«r»zéQÚ(cG:EúÒ)Û_‘~¬ó@¢®3F`ÄxkàµuαÖࢋ.ÚŠ þ}D_Ñ©‰'Ÿ7¦^ëóì¶“õ«:Rñ©½(|Ô‹íÅKWå¨oÞ#0fÜôõ¯}Is®5àÄV¯^}=ÈŠ:'Yw_ѱeõ]¶>«­d²¡rÍÓ£¼¨.ÏžäeÛ§zy}Ê®©0F` ؆µñoëžwíÀW\± »S÷Dëì/uri9k,y:yrÙȪϒI?²M™vy:iû´ûuÑž¿ˆ(™7F`Œ¸ú¶Ûn«åýÿÓÚvþè£þ Èq £ÆGÇç–'—N^}ž\íÊÒnì¤mb9òCZÖ¸(OëTΪS;S#`ŒÀˆ#°/þ¹jsHÀ7Nž<ù÷0aþåáH¦èÜ8ÁÔÉ©>oò©¾ôòäªÏ¢E}åÕ¥ý¤åØOj#–#Ï6i9Úñ@Dü0c€Àî={öü^ü³ysHÀ‰^|ñÅ+á þl“®£O:º‡­ÿï j® 8áK/½ô+ ßÔäûÙotl‘}æÉ£ù²z±Û”mW¤—Öµ+k Ô‹ºi9Î+«NvL€0£ˆÖ½ûÞüæ7ÏäÜ úyïø-ð£A‚о£ó‹öËÈót¢òeõ¤[V?ÕkWŽãj§Û®>Ú2oŒ@1éõT¬íÚ¦ ß÷“ƒ>øÃü:|chÀ‰¿ÿýïßr1òj–G%éÂŒT<çù¢9G½Èµ)SG[Ñ^»r‘Íh‡zeÊQ'í»¨/×#°?7³‹!âÖâ{ÿ n¹å–û¼0ß_vhŸ  s‹.«O†T·¨®H—íb}7娷ø¬ñÇ~òê£N™±¨?S#`ŒÀ °zÒ¤IgÃù/jâ\¨ .¸à?Ø?)Ùëkç{µ_Eû<ÞÎv™¹eéDYìÛ¶CÜõFÀ XË~øòË/¿kîܹ?hêx°óÏ?1~+ù.°µþEbKN4Ïft~ÔIõÓržvò¬~ÊØNuÒrÙ1§ý—m×n^®7FÀ4ùpþgâ;ÿFÿóm£ÔsÏ=wÅöíÛÜÙÀƒœ;¤,GIå(|Z—e8ÕÏÒ‘ŒºèÇvâóh–Ý´¿´,[iÛ´,=S#`ŒÀ"ð Æ<뤓NºÛþ|ÇM£ÓÁÝÄàðÁ—n¿ýöߘ6mÚ?@ôçÈ øéÜ´¥-GËâ³æ’êçéÙÈj“ÊÔO”§²´LÝ,Y–ûì‹üŸ¢¸-TÊthYN-KÖn¼Ý´)²™e²O× ZŠ–ËFÀ4‡&Ožü«xÊÿ‹¿ûº4”Q†£xåœsÎù'|%ðVïi:òtx©ÓKËœC–¬sËO^ÿYcê´}–~–¬sµM#`Œ@…l„­Olݺõݸë_V¡ÝÚM ÅC€E¨ðW¨?ï¾ûîûè—‘__¤_gïhEcßÝÊØŽ)Þ)G[ªOûŠånø,»´“%§,•«,Ç%‹õæ€0M@kÕ|ü…ý~õ«_ýYÆÓë†v ø{Þóžy»víânÀmiÝ ËYέŒŒ:YzÝÎ%Ï^VY2õ›U—%k§ŸÕ&K&;¦FÀ"ðnºÎÇwýŠó'–#p2Ø XuÖYg}Šï x²A¦,‡–ÊXNeyc®ZOýdÙ-W‘~^úŠT}ˆ².îlD]óFÀ °ëÓ§‘߆íþƽ˿W<†þ+€,Î<óÌqÀÞ½pá¡|:Çgéõ[FǦ$>:8Êb9êfÉUiž¨y#ÊŠø<ý<9meÕI&šÕgQ]–¾eF`Üð5Ó·3`',ÿ3ž1ûë›o¾yCßz°á‘ ˆ)(½ï¼‡~ø[;vìøc”ÿå#XWwâEÚ«Cϲ‘%ÓÜ:]¤/*;¤Y2ÕçÕ¥rÎ_²”Ê–©0!¯«ÎZZ;=ßÿ¡ù¶úWæèŒŒxd¡w¼ã[ÁÏZ°`ÁS¦Lù$œÏŸ |˜êûIé蘳œ–wýõ×/¯©ÏÆu3v€Ž€|ðþ®ò?Bþ9ÕWIéèòœ»œ`Zß©¼h¼²•§STϺAÖçÙr#`Œ@lÄz6wüÿxÓM7=ÛEû‘j2¶€Žâé§Ÿ¾ üÌÇ{ì »wïþm8bî LW}/TÎ3uî´)§šW—%ïu,Eí5ž<ªê‹ìÕåËr#0Îøš)}ô ¬¾Œuõ+H|.Ì Œ} ³à´ÓNÛ~6þvø†éÓ§_ þ“È|Ÿ@å‰mžƒï¥®Š¶[PÊÔgép¾’§´ŠqÛ†Gâu5Žóo3g>Ñÿm`ôElóß ¾ó§ŸÛt0ìÕ’#È¿†èæ%K–¼¿½üG‘§"÷œèüªvþ Jη¨M;ÖKG4µ'yJ³ô¤“Ö¹lŒ€èÐf.~Ê7ûºë®ã«ârp ŧžzê òÉ'?‹ïŒ>žÏ ð¯ˆK%96Q6JQ:¡NÚNu¤±>Ú‹:‘¯JG6ÛÙc½tDÕ6Ò¢º¨gÞ# À»ýïbœµú³gÏæC~NmpÐ VϘ1ã%ÙÌK—.}7(w.C~ ra¢SËsÞEu2ZFGº¢eiÚ£ž²ìgQÙÍÒ‘L:¢’›#`:D`%Ö‘9¸Û¿wûcÿP_‡Øù€N;å”S£ÍâgŸ}ö¶lÙr!øßE~ré`JŽ//0€­}wÌE:Òk§C½¼¤±äÕ§ò2úÔ‘ž(Ç(>ÚÌÒõæ€0 ë±ṅl.œþw@ýÝ~PÙbi§UÖà¸èwÜqÛ0×yÌË–-{#è…þ>辯èܰõ*È[u­ÔÎa³];*Òc]ÙDÝ~ëk¼ôSvüÖ3F`äØŽÞ‹uqîêÕ«¿9oÞ<¾«ß©Gô ›ãWÏ|‘ù©§žz;þ‡ÁùMtxxpŸƒ¥cg@ œ=õ{uþ´©Ô©Ã¥~'m¤ß®M¬_¶­æbjŒÀX!À›¬ÿÄzxÇÖ­[¿‰7õñ«X§ pP!˜4uòÉ'?ÂüO?ýô©pþ øÅ¿ÚJr€ äìIPIò½-öªm^ý~ÍýœÚì—´çÔF´}‹½ÔW¦¤“öè–õŒ€*¶amã¶>wW¿ñ¥/}iÓP~Èë ìøã_óÌ3 pg€Á<ùÿ¥è0)0r'Ž_mHe[4ÖµãÙ¦›v²«¶eìHWmM€yÖẟ|ÇæÍ›ïÆßïr»ß©Ô2»@0 O#8¯¾b>Døëȇ ç¦<§ØK0g3wl§LQY;QO¼ì¨Ü®o×#02ð÷ùtúwâïÚï÷Ïös\ w<ù[Ï à×Gáß ÏÁ…p:‚וR–ãÌ’Ù£~§mR{ÑFäS½vå^ÇÑξë€|ýîb¬qó±úïW_}µ²7°C±¿cû±‡_¬CÇ­_À¼víÚ3p‘¼2æ·#OFî(E'ù"#r¾¢Eºeêd'ö/™Ú§eÉM€zøFÕ ó¼ßÁ¯¡À÷ù;†~V#6 : pü»1œû'ògñs—©ˆ–OG™»üÊàä®’œ­²ÊYƤÃ:ñEúY6òd²§úX޼êM€VàæOõîݹsçw¯½öÚ‡fäc:P >ðÇsÌf 4óÇ7nÜx2.°÷âãsÌo@î)Éé’2‰æíT_vÚÙ•ž©0CƒÀJ¬EàåûñLÓ½³fÍzfhFî¶p0D'‘Gù†Ë|‡½aÆñüÀ™`Ï@æW]ï í¾$'OAä÷)$LÔOÊ”WV]KÉFÀt…€®³®wÞˆwø‹Âáß}ÕUWý´snÑ$4éht8–iÓ¦ñaBæ¹lºmÛ¶Ÿ–™_Ì@ž„ÜsÒBCªÜ³Qˆ¶"_…mÛ0£ŽîÀ[×PæÉ‡ö¾kòAÞåïÞ½{á5×\Ã畜F#t0;ì°•˜óNkÍš5GL™2å4\Äg Ÿ‰ ™AÁëYWU’Ó&eR¹*û¶cŒ@-ð/t"/B~oÞû?´W îíÄÀ@áïoçG}4_É‹šyœóA/¾øâŒÉ“'¿;ïD@À_¼ ùÕÈ•¦4 HËìL2uÌr*S©0•!ÀŸàñ ýGp½}ëÀCØÎ__™u Í¡ê} ¸Ðy›¾t"ßL‹X^·nÝtlñ½}" `PÀ?4jûWÇl_6Áv¦s·Ó/‹ õŒ@WðÎþf\ƒtø}þóŸ_Õ•%79ŒÜ!ílBXv£…^YÜz–€AÁªU«f€þ2w~™ôXä®ìtÕÎŒ€(…À&\ËOà:û!´úÔ{tæÌ™~—~)øÆSÉÀx÷ÂYO?‚ó¾´råÊix/Á[!x ò©ÈÜ-8 y*ra‚ÍÌ€ÂF®4Fàpí‚sù ð¼³gðþ¾Ö[ g¿çeŒ@´ÈÕû8á„6 ´p"·*°Mzæ™gÞ:oû:‹ÒtTp÷àУ[Jø@Y¬©0íà÷Ë—âšú1y|M·/[á÷æ·ÏåpP'kå €Å‰w+&ò·£Ú’%KŽÂ¯f`áb0ÀÀ€‰|ÒD> ÔÉŒ3ü©¯Ÿ /G^†ëiÞíñäg>ó™5(;¾"pP_­Û¸ÈAàñǾ£<¿F8;'â«…õS!k=kÀ]eš¯Ý„¦”56R%‘å^ø^ÛǾ«´Õ/»Uޱ!¶øt=_ ÓÊ8ÏWàü^sžŽÿ§Þ¶çQr…¼ûÍE`ñâŇM:õX윈…³•qgô hp,ÈŽ?™NH™ÆÄ“ÖYV_­N'>4†´®Sy¯ícUÚê—Ý*ÇXƒ­]èc-°x´µ †óó8ùVsû8x~mæd‰€€FªåË—OÙ´iÓq»ví:z¿ˆøXdoÄÌ݃7"S6y߸xR¦ªÊ²Õ2:ñ¡>ÒºNå½¶ýUi«_v«c¶6bŽÏÁÆ >éПǹբ?àôiä|O”†Ãzä<î¶,X°àh,Öüä㰈ƒüð?ʇeuX>t_P€ò>žò¢²êZJj“Öu*ïµ}ì¯J[ý²[å3lñnœ¿ç];¿c'¿çÁZRÈèðÿoÁ{ŽßÏ;‘FÀÀH^O®,÷ÜsÏ‘¸£{~Nõz8¾.ù(8„×!…òQ XÞ—Y†üHÈZ]ˆª¿Xî…§½^ÚǶUÚê—Ý’cÜŽþù”<óúÈã˜´äØ†_c´»D«@×bÇh œúNÚw2F`/|&.¸ýöÛ'~øá¯…Ó™'tˆ#@LEùµ09 ™ïG8å#à„(;ü¡àY~5xþ‚:‡ =õù«œ×‚ÙŸb¹ž{iŸ×¶Ým¨ßŽüÚïÆ¼é°w#¿D9ÊÛð@ÜKpØ,ožóÁ9ñ›¡³ Øn^›‘7]yå•´édŒ@8è@77U#p×]wMY¿~ýáøs'S·oßþ*8ÁCñó°×àŽ¶Å#Ðx œâ«à8§À)Ç€6‡@¿õr&ÔŪ}<äAïÀHc_m‹á]öŽeÞAoa-ÚïD¹Å£¯Gk˲íxømè®}ìc›[–üaŒ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ@üÚxÍ3žÄIEND®B`‚ic09™ì‰PNG  IHDRôxÔúsRGB®ÎéDeXIfMM*‡i    øµ…@IDATxì½ eÅ}ÞùØ÷¦Wè!„"4’cK>Š$„„‘ÑH‘d‡93™äœdâ3™‰ãd2ög<>'çHŽ7‘pÈh·%!ÉR4R$[`Ä¾Ó tM M’¦~þš¢¸÷½ûî­»¼÷¾:§^Õ­½¾{oý¿úWÝz£‘0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#0—ì7—­v£Àœ#ðÎw¾ó¨C9ä 'Ÿ|råþûïðpÄOúÓ#öÛo¿ƒC×V{ðÏ~ö³#ƒ{@pWÐ]â‚=H{XðŠŸtÁþ½†÷š2šš=¡€'ãBB]»B]Ïì {4øCS~ú³p½“°pýlpé~üûT¸ÞMXH÷L°;C¿ŸÞ³gÏ›6mÚõ±}Le…$6FÀt‰€ @—h»®…@àâ‹/>ú©§žZ„Ûš èV¾*¸G‡Î­ .Âú¨¶b¯ŸëUÁâŽã‚{x°6Ï#ðd!àõXÂ>¾×…T<ŠŸø@ˆÛü;BÚ‡:è »wïÞñÅ/~¢bcŒÀŒ˜Ì˜“/o{ÛÛ9ì°ÃÖ=ûì³ëCÏŽ ‚e]Þëƒ{l¸^ìš pV‡kü²¿Ípx"4e‡ì^‚Àõ¶à0Ü»íÁÞîëƒÁnûô§?ýðpšî–þ0è{×Ü"\pÁáað?> üëqCUƒSðo~„û1{]fç6Ë…ËÛ±ƒ½$aK ÷‡ë{÷†m}Õ«^õÀå—_þÓ傯½]&L–én/H_ƒ þà°†¼9 Ü'µð ÁÅîò¡››‚ͱ¾ ˆ¹5`?ö`ï ¢°e/A¸;…»ƒÿ®Ï}îsÄÛ¹DÀ`.oÛb7ú oxÃ+W®<á'?ùÉÉ{…û‰a°=!ôúÄ`_,³x?»›ÞØ ÏéÝ¡%cwïõ$Üæå†Þï0¢ÀqT{ìÅ#ÌOIìÉáúÄ`ã]íáÒÆÌ%ld¼­ÈZ{0—÷s¡m°P·sx¹è¢‹Ö5ýaVtzhöŒ`O vs°ÞL@°YZøÚáÖðnÜ´7„÷ä¦<ð†uëÖÝæÏ#—ö™è´ã&½¸•þùë÷ì¯=DÀŸT¢û3ƒ]¬0Õ`“âÁÞìM¸$ܾTù±?y hØdCÀ ”ËQÐe—]vÐý÷ßj˜±œzÌÌ!Ÿuy#`ÚC€M‰÷ 1øA°?†|þóŸçšÃ˜lŒÀL˜Ì×r%~ûÛß¾*Ìê_fóç†æœÐ{fø/ ÖªûåzÜÛa#À>ƒë°á=ýA ç?xôÑGoüÆ7¾a°1¥˜”B³\á@œaýñû½ŸYýË‚õ3²\‚{»°Œpkx—)Àzè¡}ÕUW=½Ýs/r àÁ=ŠsVjüíÛ·Ÿ…×bCó_,»ïmæp$î(hjöµ<½Þy>øàQøÌrl£àyÃy ü×À¾ðôz_„=ó€À“¡‘×ûÝ@ ¾ž™ï~êSŸÚ2 wÛAÀ \Ujøã™¡Aú×íu™ÝÿH&¸6-!þôf„ E ãmжŒÃ‰ *ÛQ˜…8×àä%Ž|ü„aø¤ëÓ„ÿCWv¯ž~ú¹‰%þgžyfl!Âp¹&Ž´ Ó5ñ„ãÊOz›Ö€|Bðþn°?ôFÃÖ1L&ƒ¹ù>ŸÙýB°?ìß–Oîlj € ÿ0Ðiüé5ᲤG`smÓ °ë}L D ÂÿŒ XüXÈBQx¬µhÖŠ¥Ë½'†^°ÿV - KÒa€ù¿Ñû…sïùôn,ðÃË‹»~þ»Õ^˜Eyä‘£Ã?|Ÿ‹PWXìï{–Ý ‹[2ÂRþjylŸxâ‰}þ]»vãÃO´6¥ †ùQ°ß cË7)ûÖŸÿùŸ?RšÚs…€ À\Ý®çû®w½ëä0hýðB¾) vÌò×Ía7²79à1:âˆ#Æ‚a¾bÅŠñõQG5†k¡žú¹-² xüñÇÇ„@.ä@~\´6c`K|mðõà~%h`¾yõÕWóoŒ6sˆ€ ÀÜ´plî‘ab Ap™ñ/¥Aµ~ôÑGÂŒ­ü~üîKùX´Þi–# áóºÑÎ;÷¹ø G£°¤†O ¯ äû«ÁýjÀçÁøóÃ9yLx£Â_îÿýïÿ¼°éëüм¿쫃}~›÷Ûœ«IlŽ[µjÕX˜ã"èå2{g#œh ØGydŸ‹r€¦aIÌáŸ_ ý½:l(üó¿ø‹¿x`Iú=—Ý4Èm ÷Ž /Í›ƒ€{GpüÇ ¤iÙ›ªžÙúš5kÆvõêÕû>jzâmŒÀ¢ €ö &;vìa~øáñ†ÆEégA?`=ßïó’剅ì%X&T€Çà‚<ÒöxKÂæ½—„êß^Ôú¿ìsßxõئœUó©ÂAŸºñwë9ëtYF`ž`ÿD@VÄ€} h¶†ÉÍB¿¾–ò¾%Ú½€}œ«.™t|»úAà¿3T{q°|—¿÷€5øµk׎…ýúõëÇ~®-è;~À\ÝB Àç,'<ôÐC£x`LÂá]ã/¢ƒ£Âÿka,¼*,Ÿ|ÆŸösWBøô]õZ/¼ð³ó}OxØßÜ—WÏ9¼”ôcŽ9fŸEÈs­j†×b·È,aìo>|ðÁÇÄ`Û¶m#ìcÍýgú»ÃØøåпÿÎÐøBÐ <ºwlø½0hé…™>‰ûþP<3}æ™;ƒ°ÿM>:öØcGÌê5³÷F¼¹»•nð#À2‚ÈÚì/!ì ·ê+Á^|úŒ?1l÷Á5ȈoØÈwl(î}Á"øÿVÆ¢[/*•ñnû7Ž6lØ0¶ ûÖ¡wF ;ˆ@øëî±½ï¾ûƧ&f¯¨Ýw…qéÓaáŸîÝ3ೡ3ãmÐÐ7¼á ‡†gØÄ÷Á`ßl¿´WìßË£º?î¸ãF›6m |NƳ1F`1`OÁÖ­[ÇÄ—=,+̉áóÂÿ7´÷ÿ _|kNÚ<øfšÔ¼Eá4¾sÃw®/0ÔKCGÕ,¦³llÒ;þøãÇ—ùÌúmŒ€XN8»"°eË–Ñ=÷Ü3&sr,òuaìúX°W|æ3ŸÙ¹œw/O¯-fÀ‘oõCò_ö²`ùG½Á¾f÷¸Ìö-ð{»Ü0#Ð;ü3#{ wß}÷Øå ƒþŽòóÏ~ö³_ þ¹Qg S€ w"lèû[á!ûïBRÖ÷¨¥ó$‘»yóæÑ‰'ž8v9=ÏÆ#P„?{îºë®1!`OÁ€— ~ _#ý‰¿"¨~ÇMJ°â8ÞýèGoü? IÞT’¬·`fóÌêø'œpÂX½ï {½ÝWl– î½÷ÞÑí·ß>ºóÎ;‡úùá®p#>¾`úÝOúÓ7.üMiØA€ÀðÇ;G‡C8~5Ø„ÿ It¯—œ…ÒI'N>ùäñ,ß|ÓëípåF`©àxcˆ„böD þµS÷sŸûÜׇ԰!µÅ`ïÝ8ÿüóO¬ñÁÿá4ˆM}Ìòùö^BßëøCzuÜ#`„Ú– wÜqÇø/–7—+üðO…Ÿð?¾ðn,=ûN ü/Á~ ØÞ?áãðÔú§œrÊx¦Ïf>#`ŒÀ¼ À>ö@n¹å–ñ ¤íw†vüV8mðÃ>§Ò¦^›±´ Ï{F@þŸ†‡•]ýöyø \ÖñO;í´ÑK_úR«ÛçÍpÝFÀdE€ÿ3€ `ùÂ`f[÷ÿ¯ÐŽÎxríé­ KGÂŽþ3Ãf¹€‹ê½ý¹<ë÷¬å#ðq½žßÛ;àŠ€èþõðÖ[oÝ|óÍト:ª¶¬šBÄo‡ÿRø½°4À'…Kg–†¼ãïØÿo„;ü‘`{™ñ³¦ÏQ»gžyæèe/{™gúK÷º¹ÃFÀþúøÆoÝpà ã>Txî–Pç¿K–µ“±m,ž„]ýG†?•øûAøþ³f/›û8uõþYg5 Ç·}O]¾0F`n`ÏKh »wóOÁ½˜B­—‡¯®ê¥ö*]XÎè?ðè£þÂÃõÏ®k»Æ–ƒy˜é#ôùS#`Œ€˜Œ‡ÝvÛm£k¯½vüi!ä k&‹_ öŸ„c†¯éºî®ë[Hvö¿:ù‚ÅíÔð×¹gŸ}öèŒ3Îðº~§È»2#` Î`yàoþæoúø{cÎøáxä_ûâ¿øØ"á÷e¡@Øà·60·ÿ#tðÃÁvÖ7fûÌô±¨ûmŒ€0F üAZk®¹fü§Ekî ½øŸÂ²À•yz3¬R:’-w{¿0ëÿÕPÇoÛ™^½zõèÜsÏ«ú½‹¿å;ìâ€Xz|ðÁÑ~ðƒñ^Žÿ¨è«áŒ–¿Ž¾e‘nÂÜ€p‚ßúpcþ ÌüÏïêÆlÚ´i,øO=õTÿÃ^W »#`ŒÀ^ž|òÉñÒÀøÃÑ®]»ºÂå© }¸®·Íz\¶0FÀ´ŸrŽÀ·¿ýíÑO<Ñf…l|_Ð|¶ÍJr—=xðîw¿û¸ð¹ÇgBÇÏÍÝy•Çç|þ“N:IAv€0F`Axúé§Ç¿ÿýïØ8؆ àgAð¿…}üçÌ\˜A€·¿ýí'…µø¯$[‘Ìü ïk^óšÑk_ûÚkþ6FÀ#°¸ð¥ÀW¿úÕÑ]wÝÕZ'ƒ,ùÏá4ØKæáSÁÁ€°ÓÿÜ ¾ù‹p—ŽiãNñ¼ozÓ›üçtîÐŒËxéK_:þ‡~xl¿0FÀ,)h¾üå/·²I0h9ì°ÃNýä'?ùÐá3þ½ï/ƒ=*'X|ð(ü=ðø_úr–벌€0F`þàh᫯¾z|†@îÞ„½f;9äÓ Ø–»ì¦å †\tÑE§†Ý™ß Z×´Sqþµk׎Â~‚ѪU«â`û€0FÀ¼þ[àë_ÿúˆÏsšðû#á_c_qÅWlÉYnÓ²AÂÌŸSý¾ì‰M;ççìþ·¾õ­#ÿS_ŒŠýFÀ#P†ÀÖ­[GáœÿìKAýHÐ ŠôN.»ì²ƒ¶mÛö_ºÿSvCf ë.c•?ÕkcŒ€0F`ø‡AHÀ}÷Ý7K¶©iؽ⪫®Ú15q zÿøý¸ãŽû߃ð_®¾ò=ÿ\0:묳rérŒ€0F`‰`ߨ™gž9zøá‡Ç6W×Ã2÷Š@Þúº×½îã?øÁžÉUnÝrz%|î„ÿÇÂéIY4¨úÃ^‚ßøÛ#`Œ€¨‹šäÓN;m„6 h©ëó¢|¬rïì°DýŸn¸á†Ÿ½(A‡½€óÏ?}˜­=ôõˆý ŸZŒ.¹ä’QÐ(ä(Îe#`ŒÀ’#ÀÜ” %gäZÂTO š€ÂÿðÕ[o¦7ØÏGC¯ÏËÑsfþï}ï{G6lÈQœË0FÀ#0Fpâ‰'ŽO ܾ}{Tø?‚ðyàÏ…¥êo]ýõwf)´F!½€pØ‚ÿwƒm¬úGMÃg~›7o®Ñ}g1FÀ#0izè¡l{§†ûð¦W½êUríµ×îžÜ‚vb÷o§Ø‰¥Òé……?µ¼å-oñ¿øM„Û‘FÀ#ÐH@øƒºlšf´Ánzæ™g~¿iÛêæïœ„Ùÿ/‡¿¢nƒã|ìôùË_ÙoŒ€0F Âäu6¯Â¡>YÊgoA0]zé¥çg)pÆB:'À5c “s²ß/þâ/Æ9Ð#`Œ@¬X±b6±Ð45œ8øì³ÏŽÂÆÀû†7¼áÀ¦åÍš¿Sfÿ¯ ³ÿÆßè<ßúó­¦0FÀ.àËÎ Èa‚L¤˜—­_¿þÃ9Ê›¥ŒN ÀQGõ›³4®,-ªÿc=¶,ÚáFÀ#`ZEà~áFáS¾Æu À†‰í¿üЇ>”gm¡b«:S9\|ñÅ«Ÿz꩟㤾&Àîç~®IÎkŒ€0F ü­üyç7úö·ù›f† á‹¶ {öì¹(”ôÉf¥UÏÝX¹råvîܹ?›(š˜sÎ9gtÄYÎjÒ ç5FÀ%G€ÿ›¹æškFAp7BBû ‚û+¡ Î@gKaæþfÿM,äáŒ3Îh´3#`Œ€È2‰½Mäy9Ï6þbЖŸ’£mUÊh6¯RÃÞ4a£ÃYMgÿÇü(hf¨ÕI€0FÀ´‡ œéðnT ûBœ“óPпhTXÅÌ€Ë/¿üô»ï¾ûà¦à%/yIÅn9™0FÀöà“ôÕ«W}ôÑF•±`ï'o uB:Ygõ_‚Š£©šÄgý7z¾œÙ#`Z@`ãÆå[4A>÷ýïÿŠšù¢";ÑÁnÔ¹5¢J»ÿ>úè*IÆ#`Œ@g09½ãŽ;ÕÇBøRŽ2Ëç÷¿4*°BæN@ØÙx*³ÿ&&œ!åä¥&mp^#`Œ€0)|™ÖTÆQ&_@‚=;\.YÕTÀ7—6FÀ#`††ÿ ÐTÆÅ} 2³“¿·íJpXSprœ¸l¿0FÀp,}SG;Ð"ð5@Ø3·)G»¦•Ñ àÚT=ÂI#`Œ€0CC€óü›Ê8ú„ðßëvrÚ]ëà£ýèAáÓ†ƒš²#€ñsá#`Œ€ü­oSG—DÂ^€NÖ¼['áðžý·lÙÒ˜0›#Ø$acŒ€0F`(ppS @2ÉíDеN¸A¹ÖGžxâ‰Ñ‘G9”{îv#`Œ€ÔT€NPí„°C²); NZ2èä¹p%FÀ#PÇ{¬±ŒcAצ€ðç;ɦÿ˜ôÈ#Œ6mêdsd×÷Áõ#`ŒÀ"ðä“OŽÞM5»wïî¼÷zÅwüMU»vퟔ„FÁÆ#`Œ@ßlÛ¶­±ð§,qwm:#‡vئÔÔlß¾}´ys'g$4mªó#`ŒÀ#À¤ÍtÓ%n4M5äu`î”°PŸ9Ôi,y{ýúõã…uËp>#`Œ€0M`BÊ—iMÕÿ=ôPÓ¦ÔÊßàßÙC ðÀX Pëv;“0FÀä@€YûÃ?ÜxöO[ }˜Îcßó75ì`ÃË 6FÀ#`ºF€µ&¶Ø&†¯ÛúXÿ§ÍÔ$œéßt3 G p '4Ÿ²lŒ€0FÀTEàñÇk³›ªþ©YÖ—é”ÐI´9–ØKðàƒŽŽ=öؾ°s½FÀ#°d ÅFö4ÝølÌüÑ$ôe:'0&6†ÿhÜgˆ0¬X±¢qY.À#`ŒÀ$4ñdã_Žcéo½õÖñ÷“êl3®ÙâEÍ–åükß;vô¶~R³ûÎfŒ€0s†ÿEÃf½ûØè:ûÚü'è{!lš@ ÃpSPÇôqŠRŽö» #`Œ€6¹å åÝtÓM½wº@¯ÑäP¡P–˜ÙSO=Å¥0FÀl0[ϹSÿÎ;ﱑ°oÓ@ø³!0—am†Ý”9oR®¶¹#`Œ€˜?4¹Ì)¬ùìï¶Ûn½zÏ.ÊœûÚ¸Yƒ¸Kn„0FÀtŠ€äIÎI%‡]{íµ½nü‹Aìü+€¸rüü±çäø*@es¬"å­\¹2Û2ƒÊ¶kŒ€0‹òƒÏórmø-Åõ×_?¨ýj½€9òÈ#ÇÚ€;wf9$ˆ2)‹›·nÝ: 6FÀ#06”³±<Çuqe¨ýûÞõ·¯KicN9å”Ñ1Ç“mÖÎ9[·nÍÊâÒ6ûÚ#`&Žì%Ë-üï¾ûîÿ†fCØÄÇ?ýAN?ýôÑÚµk³T9÷Ýw߈¨`lŒ€0FÀÄ ðüȠ܆ro¾ùæÜÅf)o0€Þ ¬9Øç ƒmܸqtê©§Ž×ñ›öÁO¹Üê°1FÀ#ü¹Ü–-[ZY›g?ëþC5ƒ"€´gÏž±°ÆÏ›7oΦàœ–r~ÒA;mŒ€0F`¾`ÖÏš<ëýh sʾæškZ);W[± 0í ›0ÒœñÏìSѰ¡›Ål¾î #¬ Ö·fÍšl'¦}ðµ0FÀ d Ÿöq¸O]92­W,;ßxãƒ_v$\çqÄû@ÔÒÿÈZ «®Jm7騣Ž­ZµÊ_ L{¢oŒ€˜sø2Œ šæ¶ ›ýn¿ýö}r«­zr”;X@çØ¸ àÄÀxW&al\½zõX€V€f50AþM¯( ²acŒ€0‹…òƒþL,÷Û0hn¹å–ѽ÷ÞÛFñ­”9h@™é‹¤‡2ð§B,‚\ªýY‘B‹€6¥ˆÀa‡6kNoŒ€0C@“<„[ê~ºÌôºë®kå+‚6!< ó¬Õˆ”ýëû°¨ö!un8ƒ/ \ÿXØæ tÙFÀ#ðBüìóbk_˜*ÏZŽ÷Ç?£› ÀmBÍÏLŸSºŒÍq´ðqÇ7Ú°aÃøæCRÍÁ´ÛÉ`K'l"0 1Ç#`úGÁÏ?Ýýa³ô‚Ïo½õÖÖIÆ,mš%íÜ:…&sôÑG7qLìÚ'i`/ya„U$&œ\TµNgŒ€0“Ðxæ·Î~°É¥¿8ÙsÓM7'¦/ŽŸ¹"ÀŠ çf³sÿÀÞÀõ$ai€òá,ìM‚Xˆå e°1FÀ~@ÌÄÁß¶ª_=EðŸ4UÚ¡»sG!ŽðKUn3øõë×øŒuÊA;PÕˆ°$À~–#öÛo¿ªÙÎ#`2 ÀŽßÿ®?uòy‡É-Š™Kø0>fþÚµ_U@^„¶6 ¢.‚ Y¨ª:‚l°·€|h !|‘`cŒ€0í!ÀdÁÏÒl—†Y?kýó¸ÑoNsKè* Nä ,<Ìr“ÈÃaa“ʶ¬@ý0O– œ!©ð>±1FÀäA€1ϸ\EÓ›§ÖçJaC8‚¹°ˆf® 7„a `Îú<*zÔõ³¬óS*},š4 ö*d‚ú!XêV9lD´1FÀÙ`2ÇR-c|ÙW_³—Z-c:úÜu×]-1TkYÞTsO€–¶mÛ¶ñ,¡‹E-[$nÖ‡­„K~ˆ„  ¡ NiD¼i0ïCëÒŒ€XL«™H!ø»žíƒ(‚ŸåÝ;î¸c<ö/&ÊÏ÷j!Ý-rˆüàÔñÌÈyÐpsg5 „åψ`¢"ÓHuñcÙŸÀÚccŒ€0Ï!ÀXÉD‹ñ•qzÚØÚn,1 øÙ^GV´Õ®6Ë]HÌÐ!ÌÜ5ëfÃDËC†­kXçÇBìÜi íâáÂBN h¼DP÷N8Ÿ0óŽ“6fûþ®vòa†Là|Øè·lf¡7öÈä¯~ã?÷0 g6ˬ²¶_ö0°×@g h¿KUÈéY"ÀÒY“2´nŒÀ¢ €ÐGàc«,©¶ÙodÀ=÷Ü3^>îKëÐfÿª”½p€N3#g×&‚:6ofßÞ¦Ê÷ ðp£>‚ T!¬´Ò0˜ ÄwÌ~#`æ–`%ô«~jÝf÷ù–ÿþû½m³C({! €€Eå·6!›""0M•ç/ò³Ì O y詟e‚išê…0`!.,_H3 ý Eõ9Ì#044ž1¹é[½cC[ØÙ/UÓñ>.{^ý M¸)_¾à?Š„iÈ¡b³ubìÒ  %˜fDX& –- Ú×0-¿ã€0]"À>_ZÕch®ö3ãO{˜Œ ©]¹úפœ…'€ÃR€ö” QÔð`æ\kTÔ‰å Êf‰BP…  IÀ’ž6Š àz© É£ï¼FÀ4A€ñKBŸ1jH3j=Ÿó¡æg£¶M1KAèºvà§ûbhX*eùµB;—ðXÊ…ò€RÏ4CH§´|^H[e!6FÀ6`–Ï ¡ÏØÕçÎý²þ1iCã‹à¯2Á*+gY—†è†òÙ ‚]ÿ&¨ð"—%ÒI½ÅƒŸS…$ÍûhD@„  ›æa'âBy\ö#Ø#`ê"À¸‡ ÇæÔˆÖmϤ|Œ|Î*Æè*ãç¤ò–%né7uKw„å4ƒªÍVÉ <7»„lðÇFX^<ˆ d[…ióÀkýþˆ@D4ÒÓúíx#`–ÆÆ5 ý¡©õÓ;Áà‡ Xè§M¿^J,°D6ÙñI âSE8J¨2Ëæe‘:>§V€¶A8tÎeópCØ€¦ Š)#"l.ô’A$Æ,&P„=BŸÉCÕ±¥O4טíoß¾}ßl¿ÏöÌ{ÝKKtãâU—”WBòSFH·ÁBµ9¢¢ãˆ¥ö祭jRB@>´Òàú˜âªh:˜/xÿ§öšåCæÅÐffûhn5îÑ'›f,=>³î*K1äh$DYRàá„TÀ¬Û0:,ˆM„´[d€%ƒ*Kq›È%/R£¾ˆXK#f¿>F„»„=îÐÕùE¨26¡¥Eè3¦b,ô‹ªf°;Tí|ž`V0œÕ@$ ÆÒ ð¶aâ}”ùо±äYêÛ¬|ÔfB`R Tìa  {Íðqs/KvÕ[ˆ KLÈp韅~{è›$Ø2s‡yBfÕÄEA ( Ö¶4Ô­Ï9o€ í„ Žv@}‘–@ œp‘ˆ,Ÿ$Ú#ÐB„;–÷R3ûyöBJBŸÙ¾…¾PéÆõ¨]€3/"/;ÿ›ªÁŽ–xØ¥¨3K/hnau²$eà@€‹ 4%!E¤@K!‚˜ 4Å®°s4 Žã„„½>î¢ú‡Æ•Óù—<ÓïçΚLÀ=Ö Ør˜˜ @4 t[LáÌ&B,†—­€lŽ…¼RrˆIäkAާÉeÌ;¼‹"Ô± ok,è/4L¬üŒ=ú}Þçê6˜r¤ @ˆ¡ ¨³7 ¬ „c,˜c2À Ð–Aø®\¹rl©ƒA¢ …9ë¿iÄ &ø!,6F`Q` w*öúÁE5ô AÐÇB¹¿óxM*Þ5Ø9ê*ýK_n!Ey*{ݺucõŸ– pÛ|q :w8è+/.„—,·)#ÔÉ’–@Ú…yI!÷py9@¸KÀË•Ð_ÄÙ|fŒÚ{„jŸ¾·9v•µÃáÕ0¨†Ó82˜‡mBª-ƒàc×=køس– pÛ4Ô­S ÕgˆZên{@ƒp”‘ˆ’ÈÄED0®±6F '¼<óòðñõ² 9ÞS4—úÚ×´¬xä|îº(Ë£e ”yèQi! ™µ#|Ú6:ÁoÍš5û¾*@†´e¸ú´‘:x±QéS7¶- AY¨_oQÚ !ˆ]ü†.îWQÛ6<ì¼Ï]€ ÷ ‹Ði{Y ¬©®˜0›ÑËŠJ.Ý™_VNÝðxÉ€2 Ô/Û&!©Óf- †*dEA$B19_éD0¸¶©‡÷ASd¹w —_.áJõ0'8Æ“ Æ0µYLL2ÝW •6÷Tm* B!Áð‹àbyÑÛ2¬ö/ˆP/ƒ vžÚªöV! 1®†˜à×5éE&â0å% £küÊ/—°. ϹlìŸ8\×Â-¾V¾8 |­²ºèÓ2×Áä@c„‰ŒîÏ2ã²,}7Èx§‡:h!8ô…Ý¥2½üÌбmµ Eü•mPÝ| mÕO}}„¦MÂ¥¾U!< EFí,Šã¾,â½)êë"‡ñ ê}“?—¾Ç‹|÷‹ûfPŒK­Ðyz˜¡£­–€¶C ç¶I65JK€Ò $—vØTG€{8íœ$è«×ä”CG€û¿Ëli¯¦=#Cï›Û—€|XN|3VÕJQRÝëÄ@ Ù6„3Óøk:˜.@³1Fà9xGy'x7EÜõžÄ‚>ö;# L„Dw_2ý `Ü7ˆvÛËŸÂQ´t@Ý pXk ^—/ˆ7ïÂ^ÄWjüø]p(ܽL˜dr™ŠaÃ{ âGƒ“HÜÜ3vHA||2¸ÇêN‘Ü64ËtŸÝ×~л„ ×{„ ç]â‹ß»ØßOk]ë<#`ñî-óËÈ4-!Ä8à× Æ†WƒYøY>ÐÙÚS@½ 𱦀kê·1C@€™»Þ „=ï„\Ú—¾GCh³Û°X˜d¼Ÿñ ›±Ø¹/JÇõª#ÂI3B?¹9È„D ùã#‘ƒ.®Ú¥´v@Sx–S+!Ïó–>séuÓúßLBÀ`:3Æùå 0fîh 01vø!‚"K\œ~–ZcbÀ§‰2”ÇlLdB ’@lŒ@ñó™’ØXÛ?¯±¿¨L‡®0Ȉ´_ì|`B°¬ùcblñCDä΀¬¸YZ/aè+åg ‡ `!²„3èÛ,&ñóT&èéyúl.&îÕ""`ñ®ÆAÆb]T"lHÄÄØË/" —ðÔ¯´Uì b ›Õ+͈AL¬=Øã`<<ñ³“Fq S£ãç$ö+Þ®˜GL2Þ5 ÁÌP$™=$!¾7©ŸkY ]¹qÓbÍA.?‚DÄ@D!]¶AhÕsÓ{¦k°×ý“`×5®L™_ñvÀ¢"`ùÎ2˜ læÝ/\HC‘@( #\–+\Êd#ýl2Ea¥%\®Zø®4iÞy½FE.arŒâ%ع–pã«úIgcŒÀhdù)`p’@É\´‹ºÏrÕ< ,]ÇnYZŠ¢ ‘i^ ?ÈB°È"(eO>ò`SSÖ&¥KãÓkÒÅaòË¥-`Äul‹ÊWž´Ìô:N§rì#0&³á55µ¦©9AE$á­Y¯üE‚=Ž“Ÿça¯üò«êô9¯›ø)¿(?aq¸Úa×þ0ÈŒ½¹Ì€°8 3 c Y„/—4q|ê— V¸òÈU·ãç)ö_Wñ«L»FÀ0ÈüÄqæ¢]\„‚Þøqc«x XÒ*„l|-¿ÒëZi¥:×µêÖý–«p\Lž^Çq±œÑ?FÀ–0È °òz€òéœÎïC àI~j"^¶‹ëz½s.#`ŒÀð0È|OF6³#€Àçs9 sá˜^Ï^²s#`Œ@û:¬>\õKXΜé&¸åDÁ½6FÀt‡€ @f¬MêjP7ç2FÀÔEÀ .r%ùLJ€q°0FÀ €AÝŽåmŒ5Ë{ïÝs#`úAÀ 3îÖÔÔ nÎeŒ€¨‹€ @]äJò™”3%Ø` @Ž6FÀdFÀ 3 &™uqFÀ#Ð ­€]»v-Õ‡ñ&õžSkêáæ\FÀº´N~é—~ééиÝu8oùLêÝ1€z¸9—0 ‰@'2³u°÷ÖìXÈ[TÐ)€PdŒ€0³ ðÄ,‰ë¦íŠ<\·ó–Ï Þ³ nÎeŒÀâ!äÈ}]ôª+ðPqó‹€ ÀüÞ;·ÜìÜ›½Ä‚»"×Ô½°AÖ¼ðÖÆxÈû_˜ÃWFÀåE`ÿý÷ÿ›.zßøNJlCiOíˆû(?n‘¿jýÖTEÊ錀X`ørîG]ô¯ðì³Ï~»‹Î ¥þÚ á´­¨q;c¿ÒÆaò+®ÈÓÈû•/3*v€XV˜xý'?ùÉN–Í;!¿ü˿̆†{–å†J¨¥ý%\qEnQXZF“ë¢úû*/w[šôÃy€0CA ¨ÿ¿ÒU[:!t& øWuÕ©¾ëiC¸Q&Fî,}¬“Gu)¯\…ÕO¥KýJ¯x]Ë%Ü¡a×eE Œ…ÚUß;#apÿ£®:Õw=EB.“?ugi7y•¿(ߤ¸ié«äÓÄþ¢² #ÒÉMÃMÊÐs¸0K‚ÀuW^ye'ëÿàÙxï{ßûãPß—á&JÀ¥n•¾7Í£üU몒^ipåOËÃËüqžIeÅéì7FÀ,í²¯:fxØeçúª«L¸ÅᱜÔÎ8Ϥt³Ä•Õ×U–&®'N‡§þ¸¬ØO:]ãZ"çk#`–]‡rÈ'ºìo§àÑGýƒ0ÈßÓeû¨KBºcQ[+Qº*e•å›–wZ½iþ²ôqb¿ò+Ÿ\µ7½V¸]#`ŒÀ² ÆÁûÇüÇ;»ìo§àÃþðS¡sÿªË¥®XÈÅþ¢ö5W™”SVVY¸òâVÍŸ–_Ç~•)7³dlŒ€XB¶~øá¿Óu¿;%tî™gžùãà܈Q[ê¦ýU|®ëiñJ—Û-«—ðIqeí(ËCzÅÉ-+ÃáFÀFà7þðÿðñ®û×9ü“ðã?íº£]Ö‡0+h“ÂÕ¾¢|ÄÍ>)í¤8µ!uÓ<ºÆ•_mÔõ´¸¸å± FÅ~#`–0þ]{ÿý÷ÿA}íœÐÉ /¼ðsÁùxî¢N 4êŠýqÝeáqš\þ²ºŸ×_–Ž4uâÒº'•·Ã~#`ŒÀ!À²ø¿ño<ÛGŸz!tôé§Ÿþ‡Á¹§N·]g‘0‹ÃÊüq»â4MÂã¼ÓüÔYVošwRº4.¾Žý”™^§õøÚ#°¨­ç? Çþ^×Wÿz#a)àѰðáÐñ玸ë ë•p“;©*Ò¥+ ŸTÖ´¸¢zŠò¤u§×qž´Ì4m|-¿òÈõ@Œ¨ýFÀ,2a¼ûÒW\ñ{}ö±7@§ßùÎwþepþMŸ´Q·\Zv.ÁW”. K¯Ó²ŠâÓ°²ë´Ó®UNÚ†ôšt³”¥rí#`[߯} ô±× p¯€HÀo§Óè·M ½Ø×‡Çþ²4„—¥‹ó”ùÓ¼Ó®ËÊ!|ZÞYâÓ´“êuœ0F`x(Œ{oïêÿ&áÕ;jŸ…³?º}ûöŸNjè¼Å!Øbáû'õ¥jºIeäˆKÛQç:΃¿ìZá^Èqç\†0CE Œq{ÂÌÿŸøÄ'nB{'\pÁÚ]»v}òꫯÞÿñÇ;ÿ ²µ{ ¡F±?½Nãª4(Í£k\ùUÏ,×UêŽÓL«OmHóÄ×òÇíT˜]#`ŒÀ"!6¿8à€CéSß ¢ýþccãîÝ»GŸÿüçGá¸à¡`Óz;b¡W$LãÄiãðœþ¢6Äõ¦ñ9ên£ÌírFÀœ ãžzê©C øú‡>ô¡õ9Ë®[V¯ ¬ÿÿ£Ðð Õø  }îsŸ=òÈ# š[W‚S.™a·YíŽoDîxÕá%€eû€X/Ÿ|òINÁwgÏž=‚ýòG>ò‘£úî_o ¨þ_üßJ(4;v FK’6±Òu*ì' Íiqi|¥D‰ÒüÓ®£¬•½EeÆaø‹®ã°Ê•9¡0F`N@¦=ûìóçü0æðŠ  èåô¿¶¾À~á €€8(nŒüZ4wn[‚--7½¨¢°YLË(º&,O¯‹Ú§W›ŠÂg×#0„Í~#´Ú?ùÉO^Ô|A°_zé¥|Qd‡½€ ú¿4 ú¯ÔOHÀg?ûÙÑ-·Ü2)Ù`ãb¡ûip|ûÓ¸6;W§^ò¤ùŠÚ˜¦™vÝe¿‹Úë0#`Œ@NðO<ñD¡ðW=l æ÷.¹ä’SÖµ{@×Õÿáxà—ƒP8|ZÝ0¨;ï¼s¬>9þøãGZ#ÆM-e¥a}¦;=Ùí9î¢Ú¥þÆ×ò«­q?äO]å)*Oa©› á4žë4Mz­8sÞ>2ÄB-ö«-qXì/Š'¬(ÒVu)£¨œ¢°´ÌªiŠÒ•…Åá±?­Û×FÀ!# õþ½jýÊMeÜc¹ hþõ>ð#*gÌ”°S°sçÎKBg®Ûv>¼êª«F×\sMÝ"‘oš°›_Ô‰:yŠÊQXQy„Åáéuœ7K¯ã´òÛ5FÀÌaGÿˆCìŠ6ûUéËÞeÏ!ÿ?®’>gšN ÀAô/š6Yë&M‹j5¿¥\*+‚q|QƒêäQ9EyÕ¥‘[ÔŽ²üÊ#wRº´Ü¢´ ã¾Ú#`æÃ;l<{¯²Þ?©?hkaüµ‹/¾¸öyReqIÑ÷¼ç=/ ß=žÒTp}ôÑ£sÏ=w–ÆD@£¬ƒ}†Ó¶IB­(¾(¬Ï>Õ]†9áE¦(¼(¬(¯ÃŒ€0CB€1=lÚ½úÕ¯±4ýå/¹qó aÀQa’|i(ì?4.°b€uëÖý÷9÷ôtw}™@ªˆA+ÉRÇuLŠ®iȤ4ħùâ°´Nâ0EáUÃÊòÏ^TŸÊPœ\ÂmŒ€0CC`õêգ׿þõ£cŽ9fÜ´—½ìe£¿þë¿/ähk%”³x í %¸ëØÑ˜y¥ù𨡠Ú5M°§}ê⺠¯¢pŠÂigQxQ˜ÒÅ…uë0FÀLCÍõ+_ùÊÑYgõ‚±œqýÌ3Ï}ï{ß›VDÕøsß÷¾÷6¼ÿ¨j†&é:Ñ\~ùåûoÙ²åĦêÿSO=utðÁ—ö7²¥‰:Š@ I¨©]鵚B¸Ò̦ôÓ\Õ=-â'¥/Š+ £,‹â&WõÚ5FÀ ÆåSN9eôªW½jtÄÅ›ôÏ8ãŒñÆô¦cÙÞ}Œ—ïý_@|[Øý¿S ÀæÍ›+?ÜŒT¨VÎÜB²ö……•5©(-a³˜²ôeá”]W¦v(N®ÂÓ²¸gEiâôö#`ÚF`ãÆãuþ5kÖL¬ b°víÚÆÿ_ÃØ·÷‹€7O¬0cd'€°aï-MgÿôyýúÙþA‘"r3b7±¨Xˆá/ª¿,¼¨àYÒå',nSš¦N\YÂËâÊÚ1)}ÚV_#`ÚB`åÊ•cÁÜqÇU®²ðØcUN_”y²âåüà×|üã¸(]ΰN@þ¯l:û?òÈ#G|v1«‰…QÓ6ÌZ7é©៦—`LË( W¯ëØ-‹+ 'ï´¸²x‹â&7nŸýFÀ®à ³³Ï>{ô’—¼¤pÌžÔžc=vtë­·NJ25Ž/ÛöšýxUðEm¹€ ¼Nhª€41°«½ŸZtv†Â-Üô¡(\‚°(}“~«Ü´Œ²pµ/M?)\i딩r'åUùv€0¹`ÆÏF¾“O>¹p¼®Rßᇞ[®œê] €s6Z`iOÓ6MkB-èrqe¤éTî¬áÊ'WõézwR^âêÆOË›b3K›Ö#PU«VÿI'ô‚qºjþ8Ý!‡’Ež Ø»°ú†·¸!3ú;Ñ„NÚTýÎ'€9 ç/ÇD mÁƒà+ªcÖð:” ë²pÕ¡x¹ —[®xܲ4 Ç•?Îg¿0F  ØKÆŒŸuû¢1¹NL&›Ê8êÚslvÌš§uÀ'€‡zè!MgÛëÜÁæ ,­Ã4®.nÑ—+¡—†I\Qø´¸qÁ5~Ô–IY'¥!®I¼ú5©~Ç#`ê"À¸~â‰'Žød™nƒ i*ãhËÔ˜0žæQyK+ÿiÀÿà·_SvÄŒ½M#"ÀMä¬7³¬½Ë:~Z¾²úŸ$ «ÄO*[qªC®Âc—¸IñqZû€0M`ã8›ú8º7×2rQ{Me\26ξ㽨aSÂZ'amd¿uïÿ&— Î)ý¬ ÑÀŠL:xhZ¡³:¥-#Óꪯ:ÊÒV']Õ´ÓêªRVY7FÀ¤0†rT/øpvLSÁœ–_tÍ54B"º6­:0MÁ¡þrqÅŠx[7"áŒÆ¦$&˜©'. K;8)ââ:Òüñõ´tÄOKCyUÓTM·Ñ~#`ŒÀ,0F#ðO;í´;û»4œÐTÆ-,@õ’ƒ…rW@k2,{Â~†;>«˜X– xÒ”ÅQ‡„ç¤4UÚ’¦Q¹ix|­4rã¸ØO|•4äQÚiéãòí7FÀ!À¸È7ø¨ù»ší§í`,crÚTÆ¡åîÚt¢`Ç%îÙ³§Qÿzè¡Ñ,§35ª¬ ³ö <ñÄcÀúR]Ö'8I°“fRfá»ví5=¨)ÈhvïÞ=¶Üt´EZ ¶Tˆž†¥mš–†xLY9ŠOË-º&m•ôJ#·¨,…ÅiðÇ×Jc×#PÆØM›6gúáïå«fk=ÝöíÛÏþ™Xvm:%9Z€¾ @|“ 5,K<¤hÌÜT>_„0p&W6.G~ JÒ”ÒLŠW>•¥ëiî,éI§ý“êQ¾ªé'•å8#`ÆT¾×?á„ÆûªŒ{]"‚V›±?Çì¿é¹N¿;#Ì’Ù¤¡ïë4–<¨[ÐPÞÐ –6Š @ôÐJøq7%J[Ö7å+‹/ ŸUتEe…©üÔ-J›†©.åMã}mŒÀr!€œØ°aÃXÅÏ¡=Œ‘C5<ð@ãÙ?}{ä‘GzébgÁÆÌ=‡šã¾ûîq|ãP ÂL¹±ö@@Ò‡9|øÁIÄ îaŠÃ«úãzfÍÓ4oüUÛètFÀÌ?hMöÌöþŒwC7h´Ù˜Þtó“âpVN/ÝíŒÐ;nrÓ€”C}|@ݳ„Ÿö ðPƒDB0Im” M-#4y1T¦ÜYúBå‹ýUËHó¦×UËq:#`æÆ1NäCècñ7ÛºF„ñ‹µÿIcxÕ6mÛ¶mÔÇ´¯SSb6œã{GÂ4÷T½iuÒñÐÀ±ìe@Õv J™œUÒNJC9MËRþœeMj³ãŒ€˜_ÿÙ¼Ç Ëø=¯†ñ¡ÝtöOÿï¿ÿþÞ`è”ÐKnºGÓ^ÃÀrþ¡CÓöÌšŸË2L"À2 ‚:ÌR¸J ãVaÕqúYû§Oë'.WÙq=ö#0|{ø\OBÍš5•Æ£¡÷Œ \Žôóá‡ïë«Ï³ö;ž;vìñ`Í»G}tlyqØD!ù°@IDAT¨"È‹0ˆ°tQº8,·çð§e§×9êpFÀôƒ“>c2Çñq³vd§µ^_wLVýŒ}7ß|³.{q;'ô’‡‚Í€ÐÔhF×G?6m÷¤üà¢M„¨šØ8(2À¡M_ªTè꺬MŠÇÅÈ-Kß$¼Í²›´Ëy€x1ŒEk×® }?ÚËE5|Òº¾é—lÂgË–-ãuÝ‡Û €9±þcC  I…Ž\DÃÑÁbXàE£¿Xw#á‹+[ÆrO½òãÆ×©é#`æ>öV¯^=žå£â/#æ¶“ glã“¿škŠgÜ­·ÞZPS·A½ºLXUƒZ†›Ô÷±9ú2­ pK 4¸M5qý±p|œ¦Š?Ϋ2É'¿â«”å4FÀ´‚ñJ¡?Ï÷ê"Æ áÏ’s.sã7f-¯n»z#<\èóÃ853ikpëT—i¿0õЗ@úˆÙ=ê|ÞS›z0Ûg3yÎ%iZ¸zýõ×ï[Ž­×ºvr ‚Ð5ÀçPÔö§žzêXãŒdÊE•€Xí5ûƒ„êJÿg ÜÌ(Dp! J&BÈ®hŽï–öîÄÂ>ç—>Í[9ÿ%0¾!üër>÷ʦ¿´oƒ!4 ðÙ´Æ Rì@…ÑrT"7†Ù|Æ8´  ¿Ÿò$/$ Sci îfAÊ£ 4”ÏÚ™M7€}™&GD@d€kÙnZçZŒ@} ³Ú<«´øzTù6Ã@@“ÌǼ•1ÎÝtÓM#¾÷º$4<_°€šFFŸ± À!uwUò Q ?ÄÂ/¨îÇ契栬" qee;|~@. ™ù·iÿŸ¯·ÙδìÁŒ` `Æ^4ÃÔׯ_?þ‚€ý"Â_3ØC"Ð& u€\xˆZ¿î«Üi=! ‚\âb|†O«gãy·±3î‡üq¸âp±x¹J·ŒØ¹ÏŰ×9€à/’Źê…Þ{ï½£[n¹¥õzêµnr®¹ tA*~Öëìe³|mäæ³Ë“¼³<<<,+ÀÑx£àä‡hbL" È fcê  Ì:ùÇb˜´1a“Œ(N•/’qà 7d?50_ «•4W€.qƒa[„%iBå 6Œ—Ð@fùz€‡‹<ÜtˆxVT j§2FÀœ°æÎ˜Þ…ªŸv#{î¸ãŽÑÝwßݺ†!'NeeÍ #Ülfæ„1Á4mù˜!À±Ú4ˆV_ňGŸ#BBlŒ€0F ;þ*ã~®V1idÖ?Ëä1WÝm•3·Ò‹€SýŽ=öØñ7¹ìîåaH?,N›Ù8È e†_u¯,mé9ä2€kcŒ€0í À>ÆjÆÞª“¶-¡^fü÷ÜsÏTmsŽúº,cn !ð9 €Jž5föe_ ”‹ y`½Ÿ>åL3Î*ÀB(Ø#à}ÓPs¼0F :hxYúEø3æviÐ4óg>óöy_UŒæšÐIn š–Ð ˆ±ƒYÕCä§,d¶ï¶. †ükDÀZ2´nŒ€(G€1Wjþ*“±ò’êÅ0‰ä,Æô®IG½×Ë5÷€n3s‡ ÎGˆ³Öðå¸NfçU—b¥Ø´iÓXÕ¨²Ã”‡…+­š î£k¿0Fà…0vj¶Ï¸]eâõš_±´€ªŸsüû¨¿yf+a!]æKþs™O™cºÌĹ© ÿÐ…(ãBá†vèíñŠ) €ÀG]{do²Š!Tø¼$<„¸¹ ÂzíÚµc‹ºMûp«>èˆ cBû.¹<#0Ÿ060nÉæÚøÜ6´õ>»5®µ]ç"—¿Ô€ ÛEPeI }4c‡}jC åå6ìI }X^\ö$@Ð̲—ÚÉ2– X#` §fö¸Uö ÆWZcœæ³êª ¡´ÈíXzÀÍác‡½ÖãgU“³W@yÈh°ÜÜ&Ö@P6Ä2€¥ÎY –üʇè‹Ï!˜U§7ý €pd BÈKèãŸ7¡I{Ù×ÄlŸ±™13oýèç)¨^« @„”—Ý™03j–°”%|d€¦K Á_ó’ @3€@¯Ãòi§Œ ¡OàaR DìþXa#Éø%¡¯ñËB?F(¯ß Áök’è™.¥Zç8b‘¶44Œ™ºÎàšõ=È/õÖ}‘¤%  –% 19@{0«öDåÙ5F Þ]ÆÞEÍìqë¾Óå5uCû™¬ âgܵÐv¼`hvMLüÁš5kÆ/2å£Ðߤü²¼" h 6l]í@\åacC?ÑÄ‚1°1F`:DÞ+ƞئïÚô’†›"úêÛ¼“™á"^Þ²f’­¼Ü…ˆáÁ„•êHß\Ò§yêÐ2ëùm½-MÐf"¸9–(h;åbcƒf" mmѵ51Rö/ ¼+Ò¬!èñ3àok è[úÆÄƒu}fûo±¯}âúQF `*R ×Z¡gw^@¸!ø$èSÿ¼ö«j»™Ð ð±Z>´À¯Š^7éL*âŒpæAFpBÚØУlÖñyQʼD¼<øÛ4Z.`¿‚ê þ6^\ˆÔœiß´œ BQ¹Ö¤ˆùºì¸ñ,^am¼7}ô³JôYKŒŒ•àY& ªà4¤4&3Þ ߢêyÚD”ËÄXféK- õrÍØüJÉ©;þº€Á:eÛ\ªP4Š´Ї @Dt A ¬­û¢úí.ä¸XÞ; {Ü6µtCG˜w”1‰–ñIÆB_H Û5¨qôà# й—Šškˆg âå)`pjËPwüuƒž4ÔO; »4Ô‡å44Ú.rº¤1Q(BoñÃx†õ ¥BžpÂHcAöü³zïµh™ ÐóÈ̯Ï Á½c €ù2ëD#€ÀéÊh§=§"ÄÐLHã¶©!@pÆ#X¢†·MBRc&0™fDpEp.?×X†iˆöÏ3(.áŽ+A®8][°O¿Oø{M6ÀÔØMÇn^Rt'±æ‘ídPá{û66 VmŽ› yA¥!€±cËfÊUËŸ”¡¨%þ¿“‚6 ɤ¶M‹«JTŽˆBì¦~ð ‹¡0•c÷Å ¤yvåâçþÈJˆ+ ׊#̦à©ñ¡|m3\‡œÛ ãÝáeŠA+¡?-¢Mz¹µ±P/w[íÕ¦B}eÀlœ:™Ih^UqÀ©š>M'b r19_.ÄCZŒÂS¿â W¹ø‹L\ñ îÓxž™8}|ÿäW<®°ŠÃ^äª»Ý À¤€w!n¼Ñ˜ûc³ø˜d¼ÇC~i RÛÓN,B™—Ë`a% ¤D†úDD ·¨®„â¢öÏý&h)õ®Kèó,yÌ&’‹Õ*€ÅºŸ•{ÃLPBYŸ2 ª!€`Û$¤%`†I„RPe¿r§Ð,{Íîqy‡peÚzŸU¾ÝùAÀ 㽚÷K¤€åö3Ð,ˆùÖ¹M¬¥PÙ©(EàlŒÀ²#À»Éû yÈ;ïǼEË~o»ê¿ @F¤ñ¥ƒpøÚþòC?!" @ DØÜ¤{¨Ÿ5éxùbÀµXTâ÷÷NZº˜ˆç~÷K÷ëyLžÇ¢±o™^@fë:N8Ö œEp™0`åĆÍqÚÏ ›Fùi 䯤ÒÚ5CE€ç•÷Fä—w(&×9ߥ¡âàvuƒ€ @Fœ—ýÅD[ ÃwX߸" f±w˜7¹Ôî) <‘͘ps’&ívÞåC€÷AB=&Ëøã÷AïÅþåCÌ=n €ŒÈú%-á̬]ŸµÅ81ãaÐ)ˆý9fïÒRÄ-£~[È€ˆBŽ:ãºì_NxÆ$äõlKÀãÊÄï‚Âì®0Ȉ´_æÙÁŒµkŒpÄA€àg0ÝÙk|î{úø ˆ¸ ꉵ"h lŒ€àÙäYa•?ŸzŽÉûU†]#Ð7&ï€_òŒ`†¢ ì5ÀÆÇ,Ç8k†”ÙYZU´¿€üԣ͎ñú¬üq›f©Ïi‡‡€ž£øÙŠýòjy|ïc¿âí¡"`ñÎøåÏfÅ¢DbìS¿tÂc¿®åNªbÀ?•„ÈDA~„×q›ÊÊpx{€¿î³žØåþÏýÒ½’K«ÊüíµØ%ö0ȈqjÝÎY>€z7Ì nÎeŒÀâ!ÆÃþuK]l\pÁO†¶ïi©ýƒ+Ö`p·Ä 2FÀÌ»»hpë`o'vtÑ™!ÔaPï.XP7ç2F`!x¼‹^uB‚P|¸‹Î ¡€zwÁ nÎeŒÀâ!ÆÃ-]ôª:³­‹Î¸ŽùEÀ`~ï[nŒ@^ÂDòî¼%—Ö U¿¸úÅ µà…÷5ÆC~ÜØÿ¾2FÀ,/al¼¦‹ÞwE¾ÓEg†R‡ÛPÚ“³ê›\Ê–7öÏR/ù¬˜1§5F`Axú§?ýéõ]ô­pÀ,%H…¡®¹±òËíâf—Õ¡6àÆ~¥/ S\‘§/ó+Ÿâum׿˜L7ǰÇþëUW]µ8_¼ûÝïÞÀ¼¹G@;­ºŽP#ò¥n®ÆÕQµlµ‰ôò×)oR^ZUï†Ó#°À|©«¾u¢ØÛ™OtÕ©¾ë ê›IÚS$øfigœ–|qÝUóÅuÉ_%/i•^nQýEq„™TAÙiŒ€X`88¯3YÙƒûŸ„ŽurºQßG,à&µEéäNJ›Æ‘gR¾Iq*+.£JzåÃÓÇþ4âpåÓ¤e¥q¾6FÀ,_ºòÊ+ïíª¿€÷¼ç=|ÖðÿuÕ±>ë‘ KÝ*mjšGù'ÕU%Mœ_éqåãñÇ᱿,]QYÖ¤hùÚeB Œ‹Ðe;#t*tî£]v®ÏºŠ„`û'µ“tUÓN+gRöL—uwJ.¿üòŸ†ü.;ØG]E/ŸÂpcQû_GØ´xå‹ëR˜Ü*eÔͯ²‹ò—Å)\í³kŒ€X"®=ýôӯ躿:÷®w½ëóÁù¯]w´Ëú$ÌR·¬ J—Æ—…ÇéŠÒ…Åy¦ùËò>)®¬Ü4O|û­(CÐáFÀ,8¿Æ¹ë>vNövð÷Ù®;ÛU}µX°©Þ¢0ÅÉ-KS®|U\Ê(+§,œrÓ8]ãʯtº–«vÍ’Vyì#`–O}ò“ŸüJýì…\tÑEÂoõÑá.ꌅŸürUz­ðin|eyŸ·¥,iÊâŠÊŸ”Ö€qû€XtÂx¸õÀ¼¬¯~öBèìÊ•+ÿeèü÷úêx›õJÈÉë",ýiºøzš¿¬œ¢|ei /‹KË™”.›tÆ¥õøÚ#° °'îï~ü㸯þõFÞøÆ7>þ#àáãOõÕù®ê­"äHS”®,)M•9 šî7^rÉ%¿»üºåP7c®|áÏ~=”õÊ g!î¸ãŽÑ1Ç3 áãY2³ÂØ’.¾–hááÛÎQøÄƒfík¯ü©KdŠúS—–£tMÝT ·}M{©ƒûÿÌ3…Ý*ç7FÀLD€q á»×¼îÜsÏÝyÝu×ý•úr{%^xáßïBç÷i"éöÛo­]»–³ö Ï"Á¨0\L|-_áµ!m߸±Q{ÕÆÔU>…«<]ãbâp®› lÊHMÓ2ËòÇáøMRä}mŒÀ¼"ð“Ÿü$þc"Æì7¿ò•¯ü›`nê³oûo×xÛÛÞ¶"Ôyeô_DBíꫯÝrË-]7+[}©`SÁ„Çq ¯ê6É[µÒU©'íË´k•›–^ÏÒN§5FÀ °¬=zâ‰'â™ÿ¾f†¥€ýƒœûÓ°pê¾À<½€ƒ:è×ÃÀ¿±¬Ï€¯}ík£o}ë[eI.¡&·¬±i|z]–¯ixZOzMù„ÅáéuYâ½NÓOº®’—4UÓÅuå) #Ož^ÇåÚoŒ€˜'ÏvïÞ=¶ÓÚÍ$7h ^–‹/Ÿ–¶­ø^À¡‡ú{¨ÊŸ Þ}÷Ý£O}êS£Ç{¬-²—˃ ·Ø_TYÓôi™Óê#}Z§ÊHó¦×Ê«ôºNËK¯•>-/½V:»FÀyA€ýk»ví1û¯jH&Ãÿóûßÿþ×WÍ“3]çà‚ .ø¹°Ñë-³vâÁ…¿LÝ|óͳfí%},Ôb¿‡Å~ŧn•4ižôš2ŠÊ) +Ê[V”7 K¯)‡°8<ö§õøÚ#0dؼüøã˜ÕÏb A °p'ä{þs°Y i¶spØa‡ý³ºí…-±9;¯»Å«¾:°(OZ×,¸ÏR^YÚ¸¾²¶”…Çyí7FÀ Æ/6úa‹ÆÁ*mÞ«1xÍ¥—^zI•ô9ÓtJÂÎÿu¡³onÚ›nºi´cÇŽñçoMËj+¿¹Ôû«ÖKž4_z]µ,¥+Ê_V®²ä–¥KùNÃ(£(LeÛ5FÀ c=v,ø÷ ðÚÍC €æ Œ¿dä!µ ª‘±S°nݺ:¹¿¾[¯ëž|òÉ£ã?~¶S£ï­g‰…ZìWÅUÔ¾ ·j›ÊÒ•…Óö8¿lýrFÀrÈ!£×¿þõ£w¼ã£p Ï¾sXêÊ3òñÉ`0'†³o>”£U˨¼¯j“ÒµýÃg“’Lãt½7¾ñûÒé´=XÔL*ì¸É±!>Sú4,¾&š/Sq=Н¦|Ee…M«¯(OQ˜êµkŒ€ŒÅL>_ûÚ׎ ˜óÎ;otà 7ŒûiÚFÆÁPǯ†r>Ú´¬ªù;#úЇNÇ!ͬ½‰9餓F«V­zQ! ’½7u_{ÕÆT°ïKСGmI«ÌN³”S–6m›¯€0]#°zõêÑë^÷ºñ1õqÝ|ðèì³Ï}ï{ß‹ƒ›ø_ý¾÷½ïœ+¯¼òGM ©š·™4®ZKHÖKþÇ{ï½w†ÅIÏ:ë¬âˆ:¡ªÆIÆm",¾ŽÓ¦áEi‹ÂTÆ4—¼e¦(®(Lù‹â+ 'OQ¸Âäªl»FÀ¡ 6­Â‘½£ÓN;­pì¦/ùËG×\sMá87k?öއ ùþÁ¬yë¤ïl@Xãx+êÿ&–?bí¿ŠÈ! —²¶……•õ¹(mQù /‹+*RúIåÅ©¬²8ÕŸ!…Û5FÀt…šj&›ï~÷»G§Ÿ~z©ð§=Gyäè„Nh$Û‹ZÎE^ryø—Ü.úÚ™ œŽ´¹©úóæÍoD ˜„MBEuÓ&üEm( / ›TFÚg]Çõ+l’;)}Y\Y8õÌ7)ý¤v;Î# Æé—¾ô¥£sÎ9gÄ쿪abzÿý÷WM^šnï9ëÂÿà¼"$º¦4a¦ˆNÀïÿþïûWõW5ݸaÆ™»`TØUÓúg­\B­Šð/K;kx•6ªÌ4mY8éˆ+‹/‹Sz¹q} +˧µß#Ð&ŒÑlð{Å+^1þ+úYëZ¿~}ù‚œB^…Mí?Ú° €û榳n\×ð•€iK‘P®[vÕ|z¤ï¢þ¸¾´uã(§,oYxœ§,MYxÚn_#`r!€’C›K+ÊÑ ƒúʦ€¶ë-Ú#À7MÛß ·¢¶Kè•Å…Çeçö«=eåNŠW?Ëò>)•øIe;Î#0 £Ž:jü)Â?ç×ÉD²iÙX—Ý–¿˜Ö!QÇj÷v…nà@}£¥œÚ†¸½„ežøºqq=©_õ¦áéõ¤t“â(GñrÓ²•†øIiŠò9Ì#0 Œ£lÎãþM›6•Ž«³”9)-Çù6•sѸxàÅ_|ðUW]Uý¿…'5®$®XÑM™ío“- °O²¨{S£›9.žëIÂD“âËâÔöinÚž4½âå¦ñº&>GÊ«R–êµkŒ€˜†ªøOTüÌöëNÚÒr«^#›ÐG›øªf}Aº˜¼ ¢¥‹N4áæüº÷jweçÎ/:‹¹va3dDó€ ‡ø[å“à«"¼‹šCþIy‹òT «"p•FnYÙÄË–¥‰ÃgIç³ß##ÀF>>ã;å”S:›ÆõËÿè£V’ J_æ²­KÓ  C¨büñF}kš¿Qå!3ì,ü¡ÑØ¢¨#¤%TËò_÷£(ÊŽÓù«¦#ï¬iI_%ÒUI[Ô‡#°\0ö2ËçdØ7V'ÛFè±Çk¬þgÙ¹é$yÖ~vF`jÏ&†Mz].Lj«´»víï`Ý)=§¡iZ.A7I¸“fR<íšVŽâ'õAq¤­’^iª¦Ÿµ|¥·kŒ€ˆ` eCGî"ø«h`ãümú™µ?òÈ#Û„†¹kÓ@@6Ý 8>ø`¯ªžô! !&XJú ÙÑžiè1ˆIA\¦ÒÆa©¿JònS7=ùªæUZ¥×õ,ítZ#`ÆLÖõ;àgyˆ™Äx®1½n›NëÔÛ`7=7!ØÄ°5I2ѤEya‚h°1ˆ5|àÀÎ5®¹Eå¦ôeñE᪳(®(Œô²EñeaªGnYº¢ð:yŠÊq˜0ó‹ãߺuëFüï 3ýxìj¯~øáÆòˆñ¹ÑµéŒÐ1þ6~S³mÛ¶ñPÓrÚÌŸ’´|Á€† ÈHŠ@ bb <„Õ1*¿nÞYó“^yR680‹‰“¥cŽ9f<Ógmí鼘‡zh¼A¼é’[¾8ëÚtNrt’õþ|aØ!72ÀF¬4HÁ´GB4}0ê• ä´ÜI×Mó«ì¸þدx»FÀ,6Œ}¬é#øq‡¨Ñv˜¬Ar´e„>L§a‡Ðf]SƒQAØ´î&ùcÍmG#@;2 ó•0ŽÛBØ,x¨ ¹qYUüʇ+K>…W)CiêäQ^»FÀ Æ¥Õ«WUûýU«V »ÁZ·}ûöñX7m7­(vÿC$ú0:ˆÀË1ØÚŽ;Æš€>€ËQ'8è³B ä2 íÀ,Â\í¡ÌØ*|š«<ÓÒUË‹ýUó;0ó“„=kú¸³Lp†ÞsÖëÑèæ˜ýßsÏ=YdbÌ:'ldŒmj¸ËyY ˜Ö_}MÀ¦„?j2^"‚iùËâ%€q1r«¦/KW'¼¨- «Sžó#0 Øè½víÚ±°Gà3~-¢a:“ÏŸ‰, /Ó9 £€ß<"8PÃpDŽ›Ñ×M(ª—¾±aR›&aÏT‚4ý³¢XèÊ[¤uˆãikz]Ôþºa”mcŒÀð`LB­/¡ÏØT4~ ¿'Õ[Ⱥ?2'Ç–Zo½õÖÎÿ‰{Û @XóðäØ ÀxàÆkKM×bb`†æ+6?b1àà¥Ã–}]0k?bá^UÇy¨¯èZíHãn×a#À¤cåÊ•c¡Zÿè£^x߯.„Žì”Ë2ÂÖ­[ã*:÷÷Bè%Z€€²(G$`Úwô¤_CŸùt‹O4Z2hª!ˆ1J…¶®ã4Óüä)2*«,¾(ÃŒ€hfòL0˜áËr½ÌáŸCs †Œw7ÞxcãsqšÞÞ‚šYk.@YKprÔ"kÊn¸6E²6…¾¼´¬Åun\$´-ÄËîŠÃÀ| €V–=—]úL*lžÖlÒÎyRëþìõêÛôFè8jl6TäÒ š X´=³>(¬UÅ{ÈV@d?¶5»”èš6È[dÊ‹Ò:ÌÙ`"À²!‚•>vÙg÷e(2ñÉy®‰*õ°yý–[n)«²Óð^ =efÊ:>+‡a&|ÿý÷—€`Ø< «}X>_QˆtýEÅ4Bð|ëí3F`V˜iŸ_‰—e©tV¼âôÈ%„®5ÊfÂ{Í5×d“wq{ëø{'Zkb¶š‹ò}÷Ý7þþtQ?E©s³Ó<_‘ʼnˆ@¢ mh T§]#`š!Àû yGØ#äW¬X1ö{ü«‡+ã"kþÈ’\†ñöÇ?þqÖ¥„¦mëÐTR|J+e­%Ç' ؛ֵšµ,ù‹H}çÞ@ ¸ú’ÃÄ`Yž ÷s(ðþ¡²GÐ#à%ì—}Ù3×ýaw>'ó1æ4|òÇõÌ €°€‡úôÓO“ˆ@Žð裎Xೕܛà†t#Ûn „*ÕP§Èƒ¬qnûn¸üEGb ÙFÀ#èY*•ß›óÚ¹ûÈ6Q?öØcÙ+¸ë®»FØ¡™Á€a—%3Mþ‚?ûaÏzuS"À¾·¤LovÉûBÜŠ6qB°\î+~k òâïÒæ4Â]!/Ë;cÓ Ln˜õ3YÌmØ“6”MißEh꩸Ž;î¸ñÌ"ÀL¾ `Y5Ø4DÀ/Wú(ä½olÑ %BÀ=…nc ˆ/ëó±Eà3ñl¾ÿ»Í$Sç©än ²ëúë¯Ï]l¶òGèÂÀËŒýC°,€Š¦ €`pæ>{x mºG@ä ¨fdûIkíAbëžQÆ*mšÅEÐkìbŒñsÛç*¯›Y?ßâã¶aÐ:sØOyÕF»â2IŒú=ìà µiÓ¦ñA?Ä¡®AÔ1ììd3ª6´ª£NYΓ*_‚ˆ P3~½`hóÞ‹e/ áŽ@g|À• —K˜gðó÷”0Æ0ëoc­_hpÐjM š;HH‡ç_¥xex9ír€6­@Ñ´ÒOrÙsÀþN½b'­È$´†dzQõÅštO«–1œž»%Mày` Á"¼qYz¯kù½$ÕíáåGŒÜ¨;yœÖ#Æ”Ûn»mt×7üµ}°€Æ&$€MøãR€Ÿ£+Y¿!ªýY eò@p:DÀ›gEpøéôˈ€ž+=[ºf– ?.× ~—£…Œi¬y|-AÏŒ]~ õåx6Ò^¢ægœ¯##Ҳʮ!|çÏ^³y1ƒ&€È   6lûSæÆ  ?«à0!ˆª èUoZêA­Gy¬ãÙ,>“ÈAYïSb_‹,(L¤!¾¦Ü8]Y=‹ÎûŠK¸„¸üÄ&a®ô‹ˆ‘û”öŽ1AÔߪç+ù…%¡M¾öÚk[¯ç…µ6¿< ‹}Öì7nÜ8Šv–“ŽÙ;–xö ÔQõÀùlƒýþC PµIð"<ÇŒRä“®_ä'­ŒÒ©…Ë%•=Â}šA½ªMƒú$„¨*k`I@ÿ¼¥5Ïiu;Þ#`š#€ÀgÜn럢2ö³ÖO½‹bæ’¾Hç  `vÏN~nRUažjX" £†¬7A8GÀk·Us#`ŒÀì0æ£rgwÒÒïì%OÎA½¬ó3ó¯2Éœ\Ú°bç–#‚žO÷8aάœo~Y˜…ÆZ4 |=€`çÆO3<¤…òé dÀg LCÍñFÀj0–#ø»ØØ—¶ˆ±ýæ›oÿQ]·×sM¸Öó֬ͳñd ê²@|#É‹åk:>%Á¦U ^Ë ˆ–o–mŒ€0F :L¬Pó3Û¯{ÒkõÚ^œÒÁ‰~|A6mìqîù Yé„ †°SƒàE-ª"0ëMd]BEÝDùØ*¥€=B&t>¿ƒžŸÃ-5F {˜D1ÓGøÏ:fçh-cý–-[F÷Þ{ï©û‹ðY@ç`‹ßøï~õ‡0ºYöÄ`A&øï,u?dr1Í@>°ì/Àµ1FÀÑxEèc¿û0 6–s†?ãzä£~/@©ýÖÚ”ÇÌ›ÏöX£'¾Ê,¾ìfP–?$‚¥Bªì@;¡‡œvi¢*CÚáFÀ,*Ì´?Y^íCÅ/\ô,!ßyç•7€+ï"¸ G¸)0¸mÛ¶gì±€… Ž‡ @ªîø/»ÑRí³_íD Ê~X.Z,Úi 6FÀED¡Ï Áßd–?“7vö3f/«YHÀÍäaã –ÒC{˜#¼¼Ú¸×DåÃ~Ž Æ"Ü!÷*d€v’k2°¬¯¡ûm! }!ÌW^~4²MÆ}•7ÏîÂn jwÔ;lÔñÍBp‹ÀLëîˆË„\èøá¦dâIÁõÂeû€*Ìî5žVÙ'ÕE?ôLÙÜ×TóÛE{»ªc¡ €@d&EP$H!¬ÉCxxQQAšš¦d€vci3ËZ* \#`ŒÀ`¬”&Áß×F¾",h ËÁ÷Ýwßxl_öŠÑR:`ç›NŽæ° "ƒ EÈbùj€‡9ƒÉ€Ôþì€lL{(‰× Æ×ìk ÚXDjŠúç0#`Œ@ôUãRßëùEý¡]üq³~Æ[›b–†Ð}v›ò@ ¢G€N2®ä‘:kRúYâXë×ÿèëö °  {†”ˆ˜ üY"ÀÒæxÓã,mrZ#`Œ@QMBøUÆ©²²Ú g¢ÄºuëÖñ†ìi«¶Ú1Oå.àÆðPè~6íM›=#P±ì#à`Æžóágù²±´ ²¡/ª|£<äài€”i;ƉýcŒ€(@€1Aelò,šÉÚ]TýÒFXøÜÔ‚ ¥#€‡;iI@iqµO€½Ò PFÎ 2Zá€ÑBô`Çm*òóâê¼â!Òfp(ÖÆ## |ÔûØ¡ÆE„>»ú‡sŽÅCï{®ö--@X-_ ð…À´%ðX+ ™ˆÓäðKµÏ¡C¼Z& ¾ª†­!€P6ýÀ?M Rµ.§3F`>`Ö̘¢Yþgø1¢ší³”Kû-ôctf÷/5. +S•%b´úÓ­‘!hÛx™Ôüõ1–ò©í@Õ}j7„@¤Ea,HK r£8»FÀÌ7ì3’°G€"ôs|åÔ*Œwl˜FÍÏxg¡Ÿù¥'‚’—m$!8«AˆbYËçeCÈ"¤ÛxXÙD¨?*¢|êÒ'ƒ,ÌjXÒÀRFËi ;6FÀ ;B^3|Æ"Þíy3Œk}¾zbÏÖ<–yÂÚ º[ÌŽYOb9A^G5NͦùÚb¡wd Þ7°~ýúFÚA‘.逘%»F _RaÐGØ·1ÎtÑSÚÍ àgÂÌkºÀ¬i&2‹æEb–]G "™5C&ØØÇC @+Жf€zcí×ÚHÈ‹UG;@ÔpZzx.乑Z2€ áºqR™v€x1CÍæ5»ç}œwáHûÑ<² ‹–>aæ½_/¾ƒÃ 1(¹/¼p0QíÊo*ÔÈÏÆ;ÁÚµk÷‘´bº%Mio$dàиzÙêVÀ Rƒ•¡Ÿ‘¹#`&#ÀXÀäƒw5¶‹$é#BŸñÁ¯qh‘ú8ù.'Ö£ò”{€†y³$ÐDWƒ„`1¼èZ&ˆ…iœ'‡Ÿöë"Ê£®˜äXgã%/llè3$€6È9 ÎÆ,AÞ{ {„ ×mNúÄ—¾¡…Dàc%ìåöÙ¶e®Û ÂÝç¥dC ³i4l’Ëe~Z[G83@X&ÀmóÑ^4–`æ‚ÜËôƒÁ›ˆb ¢Î&)Z¾žxÞ7$Øqyöå¶ù^úÇø…°Gðã—Yô¾«ŸóàšÌp—˜1Ãd!6 B0ÞáPæåÁ¦³êÜõk¹€O ÑP'dRÐdÿÀ´v–òI[€›ÚœDlZoRxGxv%è%Ü%è—MÐ162V ðqU›‘>ó|m0ãÝã¥fv,"ÀŒµ-Ãì7ÞƒÀ#2@¸nËÄ'Æ_P/2ÔÅGËú >"ܮ巡­'d±ËåÙF€ÅÂ]Ï¢„~Ž%³yFl öØxù²‹±až±JÛMjÞ Ô[¨ïs/ ”5 á&íi !1!h“q§u3ø¡`hcÉ  ƒ8œAFÚƒ2 D2AÀ/‚€«k\…ÙÅöK°ÇÂ]a¼×ò/6 ³÷Žw^ï»Æe'A³£8¬& ïB!Äz:›úº$ñÞºÁ/&/)nÙ̹a—ÇÙšÒN°d€0f@Ý$Hû6 PXîÑ$“ƒ,á±_×ÿ{×|WU%"$R¡RË › ZÚêŒ( uA”W‹âØNã?´c[-¶Õ±Ö¦©dì@)Q ))-§€B’"4„Lšy‘wBè÷Ýü¾de÷œsϽ÷ÜsϽ÷Û3û®µ×^{í½¿sÎ^ëì{î¹uç¢q{Ï;_žk:Örà’ñ:NÎÉa9fÄJ×3©vý|w?,G°ý8´Ç¨”†¾ŸçŸ *) àÛ ™´CÀ»cf±ã£CÔ3ñ¡Â¸€ô3 éuNtÄ«lb À9+8å”±¬œ–Ëö5ÊzÄ…Y[Ž<Êc}ª7ÊøÔ97­ äã®ñw=TxL›v‘ðIzn}ókŽ «‚^ää)ëWJܙРë™pëeü DšòÒãqRx–S¾%À¼¤vEç,ëÒzÍ›vÅ“JOmRJé©NíóÆhyÿ öZtM¶Û%ëßhlyP8¨y-‚š¬Ô·íõþŽ—Q?fî0÷küÞïS`VÒ"Ä €é¸$;Âq9Òƒ§®s^[¼¾IyÝéüìèÜû pP!úýrœñS¼ ä.3ÿÕI‹…‚Ñ~ÍMï"àÿ&0ñ΄ ”2ƒ‚N¶æ[FüaÆxý*°'»-ýº–Çò¡ž¶€ ß(\XiPÀ9iQ¡#޹—íï<صKÁ %nMj›R;Þ®:¦ãН?^ ÒEugOLFa=×c[×¼Tˆô¨^p1( \š§ tÊ̪¯ Z=ÇÀg”Ø·‚R.‚ ªî[ý™A" kL;r,ë¡ÚxÎG~ãußÀ€ Ó¸]||^[øqî ¸@1 å‚·!{…}ëgˆ²Å1pÔw h¡”ž©h*¼NxÍÈá+¨Ž×N¼Öš:k8pPñqâÅ©'¬+6=4æ¸ÏÀ€).V Ð)+Sõº(qW@mp1Aî¢â¢õÍ~!Àó\×®žŸºâuù~ÇvÇ^´ãäAÊÀ€ï*àC‡JÄ‹™ÎX‹ Hf–«ô £ú¥}îp&ϲ“èžÏ:wéäS‡O»ÔQмd¦F TŒ²/æÎeÀÄ-}tÖCò ”°L^òÎ{ÝûGCY/n¢]Ú- e€àdxNòѹ¨óP,)Sz9#Ð4T|DâE_±é±5ÇÀ€™ØòÀˆ1yf- RÛ´’Áˆ^buiƒwt Hų¬õÍ:oäàYÖ¹EÇ®úx>åñÃ7{xÜpPñ‹AŦm.î ð%CÂ^”êâIãâ­r¤âsºi}µ“÷u‚úJƒî08 ó`Sý踊ʡ§e!ëcJ˱μFT|Ô¼HT hEæ$Ä™ÇKŠ:q«XeQÕÑžÓÄãCg-ì#O™Êrè±,JÆräUojÆe/&: stæÌñxŠåÐÊðtDLüj_a(¥mc Dˆê.–eòMLšiœ˪㸅䑪^2Í3¶Ïã©ëÔÖÔ½8¨øLð‚S1 CH)>6IDATdŽN.+Ññ+åQN>¶Q[ÒTOu ´ÃÀ !‹Wð®ÚGš×GžœmUG*>ÊËòEz¬s2F :T‡eËR\ü*6ms#„Ï:bR:kòÌâ%Uë£,¶cë•"ŸÖI'•Ç6eø´}´kÞæ"à âcÌŠMÛ\ ȉÊÑÊÁò¸Š'eY:¢’KOmX/™(§Ï•<¾¬^l_LîÂ@ÀÀÄQ™‚(™²dœ£xÕ‘F™xR&ÖË9³,^”z1G»j/YQYu¤Jl§”Ç«ÞÔ#0TŒz\ì+6=Òæè”×®]»Ïñs²r¾Â´ß周“3FÀ$LJÊ.öˆ€œUfÆ®yÞtc„'lŒ€¨ í ;@t‡›[#`ºEÀ@·Èå´sL±€6¹Ú#P1*Ô@Å€Úœ0FÀôÃê {@½ Ð=vniŒ€è"ÖFß@€ ª€ã*#`Œ@Å8¨PšsÐPmÒ#`*EÀ@¥pî5æ ;P½ÐnneŒ€èZ,ìcõGèº9÷þnw-ÝÊ#0ZÀôýo>ë ÖÖ¡)ž€b|òj½‡ŒåFÀŒ¯ÜyçÛú=çZ8Äû=‘&ÙwФ£á±#`†—0âý(Ò§á×`ìëú4þFšuÐÝañ@w¸¹•0#‡À³ų– ûsuL¦)}8èîH8è7·2F`äXYÇŒj &MšôP“iJ<ÄC˜ˆRC|¬?°¥KFÀñC7C߯cÖµ?þø˜ÌÆ:&Ô„>äØš0–nÇrœøNêÓ1äµõ@Š”ËFÀŒ)×1ïZ€™3gîÁ¢?6»ÑIò ªyÉHÅ×qÀ³úˆýG>K·Œ,ÚÈãËØ±Ž0F` Ø´ Žy×p"øà¿ê˜PúˆN¯“ñ¨(ÛŠíÄ^–®ìŠÏÒKeQ?¶ë»më€9—€7°>0oÞ¼ZvÌk poAîû‹ šp²Dg˜å %ëf¬ÑvÙööõ#_¦?铊OÛź<´ËFÀq@kâMuͳ¶à²Ë.û&u]†~¢ó/ZfüEº¬+ª—}é”Õíb[ÉSuÄgé°Î;)2.#0flܲeËu͹¶€Â?§®‰ ²9º”v2&¶Uûví¢^äóڕщm£~ä©£2iäcûÈK'¶õæ€0ãŠÖÇ[ñÀ­uÍ¿ÖàCù7LlU]“T?ѦcŒT|ª«r»zéQÚ(cG:EúÒ)Û_‘~¬ó@¢®3F`ÄxkàµuαÖࢋ.ÚŠ þ}D_Ñ©‰'Ÿ7¦^ëóì¶“õ«:Rñ©½(|Ô‹íÅKWå¨oÞ#0fÜôõ¯}Is®5àÄV¯^}=ÈŠ:'Yw_ѱeõ]¶>«­d²¡rÍÓ£¼¨.ÏžäeÛ§zy}Ê®©0F` ؆µñoëžwíÀW\± »S÷Dëì/uri9k,y:yrÙȪϒI?²M™vy:iû´ûuÑž¿ˆ(™7F`Œ¸ú¶Ûn«åýÿÓÚvþè£þ Èq £ÆGÇç–'—N^}ž\íÊÒnì¤mb9òCZÖ¸(OëTΪS;S#`ŒÀˆ#°/þ¹jsHÀ7Nž<ù÷0aþåáH¦èÜ8ÁÔÉ©>oò©¾ôòäªÏ¢E}åÕ¥ý¤åØOj#–#Ï6i9Úñ@Dü0c€Àî={öü^ü³ysHÀ‰^|ñÅ+á þl“®£O:º‡­ÿï j® 8áK/½ô+ ßÔäûÙotl‘}æÉ£ù²z±Û”mW¤—Öµ+k Ô‹ºi9Î+«NvL€0£ˆÖ½ûÞüæ7ÏäÜ úyïø-ð£A‚о£ó‹öËÈót¢òeõ¤[V?ÕkWŽãj§Û®>Ú2oŒ@1éõT¬íÚ¦ ß÷“ƒ>øÃü:|chÀ‰¿ÿýïßr1òj–G%éÂŒT<çù¢9G½Èµ)SG[Ñ^»r‘Íh‡zeÊQ'í»¨/×#°?7³‹!âÖâ{ÿ n¹å–û¼0ß_vhŸ  s‹.«O†T·¨®H—íb}7娷ø¬ñÇ~òê£N™±¨?S#`ŒÀ °zÒ¤IgÃù/jâ\¨ .¸à?Ø?)Ùëkç{µ_Eû<ÞÎv™¹eéDYìÛ¶CÜõFÀ XË~øòË/¿kîܹ?hêx°óÏ?1~+ù.°µþEbKN4Ïft~ÔIõÓržvò¬~ÊØNuÒrÙ1§ý—m×n^®7FÀ4ùpþgâ;ÿFÿóm£ÔsÏ=wÅöíÛÜÙÀƒœ;¤,GIå(|Z—e8ÕÏÒ‘ŒºèÇvâóh–Ý´¿´,[iÛ´,=S#`ŒÀ"ð Æ<뤓NºÛþ|ÇM£ÓÁÝÄàðÁ—n¿ýöߘ6mÚ?@ôçÈ øéÜ´¥-GËâ³æ’êçéÙÈj“ÊÔO”§²´LÝ,Y–ûì‹üŸ¢¸-TÊthYN-KÖn¼Ý´)²™e²O× ZŠ–ËFÀ4‡&Ožü«xÊÿ‹¿ûº4”Q†£xåœsÎù'|%ðVïi:òtx©ÓKËœC–¬sËO^ÿYcê´}–~–¬sµM#`Œ@…l„­Olݺõݸë_V¡ÝÚM ÅC€E¨ðW¨?ï¾ûîûè—‘__¤_gïhEcßÝÊØŽ)Þ)G[ªOûŠånø,»´“%§,•«,Ç%‹õæ€0M@kÕ|ü…ý~õ«_ýYÆÓë†v ø{Þóžy»víânÀmiÝ ËYέŒŒ:YzÝÎ%Ï^VY2õ›U—%k§ŸÕ&K&;¦FÀ"ðnºÎÇwýŠó'–#p2Ø XuÖYg}Šï x²A¦,‡–ÊXNeyc®ZOýdÙ-W‘~^úŠT}ˆ².îlD]óFÀ °ëÓ§‘߆íþƽ˿W<†þ+€,Î<óÌqÀÞ½pá¡|:Çgéõ[FǦ$>:8Êb9êfÉUiž¨y#ÊŠø<ý<9meÕI&šÕgQ]–¾eF`Üð5Ó·3`',ÿ3ž1ûë›o¾yCßz°á‘ ˆ)(½ï¼‡~ø[;vìøc”ÿå#XWwâEÚ«Cϲ‘%ÓÜ:]¤/*;¤Y2ÕçÕ¥rÎ_²”Ê–©0!¯«ÎZZ;=ßÿ¡ù¶úWæèŒŒxd¡w¼ã[ÁÏZ°`ÁS¦Lù$œÏŸ |˜êûIé蘳œ–wýõ×/¯©ÏÆu3v€Ž€|ðþ®ò?Bþ9ÕWIéèòœ»œ`Zß©¼h¼²•§STϺAÖçÙr#`Œ@lÄz6wüÿxÓM7=ÛEû‘j2¶€Žâé§Ÿ¾ üÌÇ{ì »wïþm8bî LW}/TÎ3uî´)§šW—%ïu,Eí5ž<ªê‹ìÕåËr#0Îøš)}ô ¬¾Œuõ+H|.Ì Œ} ³à´ÓNÛ~6þvø†éÓ§_ þ“È|Ÿ@å‰mžƒï¥®Š¶[PÊÔgép¾’§´ŠqÛ†Gâu5Žóo3g>Ñÿm`ôElóß ¾ó§ŸÛt0ìÕ’#È¿†èæ%K–¼¿½üG‘§"÷œèüªvþ Jη¨M;ÖKG4µ'yJ³ô¤“Ö¹lŒ€èÐf.~Ê7ûºë®ã«ârp ŧžzê òÉ'?‹ïŒ>žÏ ð¯ˆK%96Q6JQ:¡NÚNu¤±>Ú‹:‘¯JG6ÛÙc½tDÕ6Ò¢º¨gÞ# À»ýïbœµú³gÏæC~NmpÐ VϘ1ã%ÙÌK—.}7(w.C~ ra¢SËsÞEu2ZFGº¢eiÚ£ž²ìgQÙÍÒ‘L:¢’›#`:D`%Ö‘9¸Û¿wûcÿP_‡Øù€N;å”S£ÍâgŸ}ö¶lÙr!øßE~ré`JŽ//0€­}wÌE:Òk§C½¼¤±äÕ§ò2úÔ‘ž(Ç(>ÚÌÒõæ€0 ë±ṅl.œþw@ýÝ~PÙbi§UÖà¸èwÜqÛ0×yÌË–-{#è…þ>辯èܰõ*È[u­ÔÎa³];*Òc]ÙDÝ~ëk¼ôSvüÖ3F`äØŽÞ‹uqîêÕ«¿9oÞ<¾«ß©Gô ›ãWÏ|‘ù©§žz;þ‡ÁùMtxxpŸƒ¥cg@ œ=õ{uþ´©Ô©Ã¥~'m¤ß®M¬_¶­æbjŒÀX!À›¬ÿÄzxÇÖ­[¿‰7õñ«X§ pP!˜4uòÉ'?ÂüO?ýô©pþ øÅ¿ÚJr€ äìIPIò½-öªm^ý~ÍýœÚì—´çÔF´}‹½ÔW¦¤“öè–õŒ€*¶amã¶>wW¿ñ¥/}iÓP~Èë ìøã_óÌ3 pg€Á<ùÿ¥è0)0r'Ž_mHe[4ÖµãÙ¦›v²«¶eìHWmM€yÖẟ|ÇæÍ›ïÆßïr»ß©Ô2»@0 O#8¯¾b>Døëȇ ç¦<§ØK0g3wl§LQY;QO¼ì¨Ü®o×#02ð÷ùtúwâïÚï÷Ïös\ w<ù[Ï à×Gáß ÏÁ…p:‚וR–ãÌ’Ù£~§mR{ÑFäS½vå^ÇÑξë€|ýîb¬qó±úïW_}µ²7°C±¿cû±‡_¬CÇ­_À¼víÚ3p‘¼2æ·#OFî(E'ù"#r¾¢Eºeêd'ö/™Ú§eÉM€zøFÕ ó¼ßÁ¯¡À÷ù;†~V#6 : pü»1œû'ògñs—©ˆ–OG™»üÊàä®’œ­²ÊYƤÃ:ñEúY6òd²§úX޼êM€VàæOõîݹsçw¯½öÚ‡fäc:P >ðÇsÌf 4óÇ7nÜx2.°÷âãsÌo@î)Éé’2‰æíT_vÚÙ•ž©0CƒÀJ¬EàåûñLÓ½³fÍzfhFî¶p0D'‘Gù†Ë|‡½aÆñüÀ™`Ï@æW]ï í¾$'OAä÷)$LÔOÊ”WV]KÉFÀt…€®³®wÞˆwø‹Âáß}ÕUWý´snÑ$4éht8–iÓ¦ñaBæ¹lºmÛ¶Ÿ–™_Ì@ž„ÜsÒBCªÜ³Qˆ¶"_…mÛ0£ŽîÀ[×PæÉ‡ö¾kòAÞåïÞ½{á5×\Ã畜F#t0;ì°•˜óNkÍš5GL™2å4\Äg Ÿ‰ ™AÁëYWU’Ó&eR¹*û¶cŒ@-ð/t"/B~oÞû?´W îíÄÀ@áïoçG}4_É‹šyœóA/¾øâŒÉ“'¿;ïD@À_¼ ùÕÈ•¦4 HËìL2uÌr*S©0•!ÀŸàñ ýGp½}ëÀCØÎ__™u Í¡ê} ¸Ðy›¾t"ßL‹X^·nÝtlñ½}" `PÀ?4jûWÇl_6Áv¦s·Ó/‹ õŒ@WðÎþf\ƒtø}þóŸ_Õ•%79ŒÜ!ílBXv£…^YÜz–€AÁªU«f€þ2w~™ôXä®ìtÕÎŒ€(…À&\ËOà:û!´úÔ{tæÌ™~—~)øÆSÉÀx÷ÂYO?‚ó¾´råÊix/Á[!x ò©ÈÜ-8 y*ra‚ÍÌ€ÂF®4Fàpí‚sù ð¼³gðþ¾Ö[ g¿çeŒ@´ÈÕû8á„6 ´p"·*°Mzæ™gÞ:oû:‹ÒtTp÷àУ[Jø@Y¬©0íà÷Ë—âšú1y|M·/[á÷æ·ÏåpP'kå €Å‰w+&ò·£Ú’%KŽÂ¯f`áb0ÀÀ€‰|ÒD> ÔÉŒ3ü©¯Ÿ /G^†ëiÞíñäg>ó™5(;¾"pP_­Û¸ÈAàñǾ£<¿F8;'â«…õS!k=kÀ]eš¯Ý„¦”56R%‘å^ø^ÛǾ«´Õ/»Uޱ!¶øt=_ ÓÊ8ÏWàü^sžŽÿ§Þ¶çQr…¼ûÍE`ñâŇM:õX윈…³•qgô hp,ÈŽ?™NH™ÆÄ“ÖYV_­N'>4†´®Sy¯ícUÚê—Ý*ÇXƒ­]èc-°x´µ †óó8ùVsû8x~mæd‰€€FªåË—OÙ´iÓq»ví:z¿ˆøXdoÄÌ݃7"S6y߸xR¦ªÊ²Õ2:ñ¡>ÒºNå½¶ýUi«_v«c¶6bŽÏÁÆ >éПǹբ?àôiä|O”†Ãzä<î¶,X°àh,Öüä㰈ƒüð?ʇeuX>t_P€ò>žò¢²êZJj“Öu*ïµ}ì¯J[ý²[å3lñnœ¿ç];¿c'¿çÁZRÈèðÿoÁ{ŽßÏ;‘FÀÀH^O®,÷ÜsÏ‘¸£{~Nõz8¾.ù(8„×!…òQ XÞ—Y†üHÈZ]ˆª¿Xî…§½^ÚǶUÚê—Ý’cÜŽþù”<óúÈã˜´äØ†_c´»D«@×bÇh œúNÚw2F`/|&.¸ýöÛ'~øá¯…Ó™'tˆ#@LEùµ09 ™ïG8å#à„(;ü¡àY~5xþ‚:‡ =õù«œ×‚ÙŸb¹ž{iŸ×¶Ým¨ßŽüÚïÆ¼é°w#¿D9ÊÛð@ÜKpØ,ožóÁ9ñ›¡³ Øn^›‘7]yå•´édŒ@8è@77U#p×]wMY¿~ýáøs'S·oßþ*8ÁCñó°×àŽ¶Å#Ðx œâ«à8§À)Ç€6‡@¿õr&ÔŪ}<äAïÀHc_m‹á]öŽeÞAoa-ÚïD¹Å£¯Gk˲íxømè®}ìc›[–üaŒ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ€0FÀ#`Œ@üÚxÍ3žÄIEND®B`‚ic05 5ARGB…,[†­ÃÌÕÕȦS$ŠB´ïùý‰ÿüùê¦/…uôþ‘ÿþîXЗÿ³€m™ÿQ•™ÿ|q™ÿlp™ÿlp™ÿlp™ÿlh™ÿg!û—ÿ÷!T™ÿ9š™ÿu™ÿlq™ÿlq™ÿlq™ÿln™ÿj1þ—ÿü1.þ—ÿþ!‘™ÿˆv™ÿsl™ÿql™ÿql™ÿql™ÿpB™ÿN˜—ÿ”OΓÿÆG…2~¿ñ‹ÿê³t(‹ B\rˆˆ—“ˆ„nW<†…UKZcgeecbcaaZSNUŠhsffz™¥¬²³³°¬¢—‡p^\^Q…tbvž¼Ã¸—fZW‚in´“ë^W€zcÀ•ûVU•–ÃÀe©³±À“à ¾¤‚W«¹Îļ¼ÂÃÁ¸¦œt]W«¸ÅÚæÝɾ¸¶¹¼¿ÀÁÁÀ¾¼¹³©£žwgb]W«¸ÅÒìöøðæÛË¿¶¯§¤£¡ž˜‡}vqlgb]W¬¸ÅÒëöøòìÒ¶®©¤ž™”Š…€{vqlgb]YªµÅÒèô÷ðéÒ¶®©¤ž™”Š…€{nvqlgb]UsqÄÒåòöíäѶ®©¤ž™”Š…€{vqlgoTU—ÃÉÜïôéßж®©¤ž™”Š…€{vrƒ¢À„d¬®²ÂÃÇÓÖÓ̶®©¤ž™”— ­¿Ã©W¬ºÌ¼¹À‚ÃÂÀÀ¾¾½¿Â‚ÿ¯ €^W¬¸ÆÝáÐÁ»¶»¿ÂƒÃ¾º³©¢šjb]W¬¸ÅÒìö÷ëáÒĺµ®¨¥¥¤¢ž˜ƒwqlgb]W¬¸ÅÒëöøòìÕĸ®©¤ž™”Š…€{vqlgb]Y¬¸ÅÒéõøñêÒ¶®©¤ž™”Š…€{vqlgb]Xz}ÄÒæòöíåѶ®©¤ž™”RŠ…€{vqlgeVUކÃËáðôêàж®©¤ž™”Š…€{vqv“ºzc©§¹ÃÄÍÚÛØÎ¶®©¤ž™”І‹“ ±Âô›[ªºÃ·¼Ã ÄÃÀ½»¹··¶º¾Â€Ã»¥•cXª·ÉÛÕý¹½Â‡Ã½¶¨¡”tb]Xª·ÅÒìõîáÑ·±­«ªª©§¥£¡šŽrlgb]Xª·ÅÒêöøòìÙÍÁ·°¦ š•Š…€{vqlgb]Yª·ÅÒéõøñëÓ÷®©¤Ÿ™”Š…€{vqlgb]Xÿ·ÅÒåóöîæÒ÷®©¤Ÿ™”Š…€{vqlgb]‚ÅÒãñõëáÐ÷®©¤Ÿ™”Š…€{vqlga…àíòçÜÏ÷®©¤Ÿ™”Š…€{vpl‹ ÛÍ·®©¤ š•Š„††…UKZcgeecbcaaZSNUŠhsffz™¥¬²³³°¬¢—‡p^\^Q…tbvž¼Ã¸—fZW‚in´“ë^W€zcÀ•ûVU•–ÃÀe©³±À“à ¾¤‚W«¹Îļ¼ÂÃÁ¸¦œt]W«¸ÅÚæÝɾ¸¶¹¼¿ÀÁÁÀ¾¼¹³©£žwgb]W«¸ÅÒìöøðæÛË¿¶¯§¤£¡ž˜‡}vqlgb]W¬¸ÅÒëöøòìÒ¶®©¤ž™”Š…€{vqlgb]YªµÅÒèô÷ðéÒ¶®©¤ž™”Š…€{nvqlgb]UsqÄÒåòöíäѶ®©¤ž™”Š…€{vqlgoTU—ÃÉÜïôéßж®©¤ž™”Š…€{vrƒ¢À„d¬®²ÂÃÇÓÖÓ̶®©¤ž™”— ­¿Ã©W¬ºÌ¼¹À‚ÃÂÀÀ¾¾½¿Â‚ÿ¯ €^W¬¸ÆÝáÐÁ»¶»¿ÂƒÃ¾º³©¢šjb]W¬¸ÅÒìö÷ëáÒĺµ®¨¥¥¤¢ž˜ƒwqlgb]W¬¸ÅÒëöøòìÕĸ®©¤ž™”Š…€{vqlgb]Y¬¸ÅÒéõøñêÒ¶®©¤ž™”Š…€{vqlgb]Xz}ÄÒæòöíåѶ®©¤ž™”RŠ…€{vqlgeVUކÃËáðôêàж®©¤ž™”Š…€{vqv“ºzc©§¹ÃÄÍÚÛØÎ¶®©¤ž™”І‹“ ±Âô›[ªºÃ·¼Ã ÄÃÀ½»¹··¶º¾Â€Ã»¥•cXª·ÉÛÕý¹½Â‡Ã½¶¨¡”tb]Xª·ÅÒìõîáÑ·±­«ªª©§¥£¡šŽrlgb]Xª·ÅÒêöøòìÙÍÁ·°¦ š•Š…€{vqlgb]Yª·ÅÒéõøñëÓ÷®©¤Ÿ™”Š…€{vqlgb]Xÿ·ÅÒåóöîæÒ÷®©¤Ÿ™”Š…€{vqlgb]‚ÅÒãñõëáÐ÷®©¤Ÿ™”Š…€{vqlga…àíòçÜÏ÷®©¤Ÿ™”Š…€{vpl‹ ÛÍ·®©¤ š•Š„††…UKZcgeecbcaaZSNUŠhsffz™¥¬²³³°¬¢—‡p^\^Q…tbvž¼Ã¸—fZW‚in´“ë^W€zcÀ•ûVU•–ÃÀe©³±À“à ¾¤‚W«¹Îļ¼ÂÃÁ¸¦œt]W«¸ÅÚæÝɾ¸¶¹¼¿ÀÁÁÀ¾¼¹³©£žwgb]W«¸ÅÒìöøðæÛË¿¶¯§¤£¡ž˜‡}vqlgb]W¬¸ÅÒëöøòìÒ¶®©¤ž™”Š…€{vqlgb]YªµÅÒèô÷ðéÒ¶®©¤ž™”Š…€{nvqlgb]UsqÄÒåòöíäѶ®©¤ž™”Š…€{vqlgoTU—ÃÉÜïôéßж®©¤ž™”Š…€{vrƒ¢À„d¬®²ÂÃÇÓÖÓ̶®©¤ž™”— ­¿Ã©W¬ºÌ¼¹À‚ÃÂÀÀ¾¾½¿Â‚ÿ¯ €^W¬¸ÆÝáÐÁ»¶»¿ÂƒÃ¾º³©¢šjb]W¬¸ÅÒìö÷ëáÒĺµ®¨¥¥¤¢ž˜ƒwqlgb]W¬¸ÅÒëöøòìÕĸ®©¤ž™”Š…€{vqlgb]Y¬¸ÅÒéõøñêÒ¶®©¤ž™”Š…€{vqlgb]Xz}ÄÒæòöíåѶ®©¤ž™”RŠ…€{vqlgeVUކÃËáðôêàж®©¤ž™”Š…€{vqv“ºzc©§¹ÃÄÍÚÛØÎ¶®©¤ž™”І‹“ ±Âô›[ªºÃ·¼Ã ÄÃÀ½»¹··¶º¾Â€Ã»¥•cXª·ÉÛÕý¹½Â‡Ã½¶¨¡”tb]Xª·ÅÒìõîáÑ·±­«ªª©§¥£¡šŽrlgb]Xª·ÅÒêöøòìÙÍÁ·°¦ š•Š…€{vqlgb]Yª·ÅÒéõøñëÓ÷®©¤Ÿ™”Š…€{vqlgb]Xÿ·ÅÒåóöîæÒ÷®©¤Ÿ™”Š…€{vqlgb]‚ÅÒãñõëáÐ÷®©¤Ÿ™”Š…€{vqlga…àíòçÜÏ÷®©¤Ÿ™”Š…€{vpl‹ ÛÍ·®©¤ š•Š„††ic10c‰PNG  IHDR+ƒsRGB®ÎéDeXIfMM*‡i   ÓÝê@IDATx콸%Wuç[s¸·s·Z…V"H 6j¢¬¬D° ÆolfülŸŸ'x‚=ý˜÷ÍûÙóñÙóÞx4öð3Ø4 $! ›$L0„r+¶Ô’:ªsέ·þ¥^W¥ÓçÜ{B…]»~ûûö­:v­ýÛuÏ©õßkïJ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @ &ãbª u „DàÆoœuâĉ‰²iÒ¤IsŽ;6þÔú–¶o¼¥9ZñÅuÜ,­ŸJZOÏõ -ËñvNznËö‘ãÆ›jyÚȆ–•“'O±M[6·~ÜgeoÝèŸmßI³c¶åAÛ¦r+ÿ„ Žiýøñã{í¸Z·´K¦OŸ~rÍš5Ùsµ™@€@A K±€ [n¹eŽ9¡=:gòäÉSÌnøLsÀ'™¥sÍYdŽ«œîi¶oª-gÙçtŸ-'Û¶¶mºå)–åxkßlËJr²uŽ’Ž›œ®ñ§ö:á¨-œZßoK‰ ü˜C¶~ØÚe¯µ›¶í¶vk9ïÔzêà[mçœÊê]W/; !а†½–wg–;m=Ívoï´û|§–vßï´!;M8Ø9uêÔ6üAÑ $@€@iJCÍ… ÔžÀ¸U«V-0G~91 ̉YxÊqÏ:óÃVKõƧν­ë³‡Æ×€@Î4ÔA" F„ ´´ýÚ·Ýò›CbÛÁƒ·ßsÏ=çdÈÙ>Šƒ È DÖ T€@/V®\9uöìÙÞ3¿ÄÎ]jN‡ø‘uÛ¦žy}^n™yƒ@‚@Å4ta“åÍ–5$adÝþwÓÏm°YëwÜq‡ŽyÑ2 € p@ˆŒÀÇ?þñI[·n]lÕZnÎübsÎ0g@½õ‹íóB ÁŸ¯í¶¡eMXG‚â% ±`›ýÏKئlŸ·ÚwÂû.ØlËöyã¾}û6[dŽ%A€@Ä"n\ªÄGàºë®Óú¥–Óz{xO—öPŸ.­ÆZžeyB|µ§F€@Á$x4Á&û^yZ¶iiß7›8ðC nЇ P €áR4 n ¨×~óæÍgØñgžÊKm)G™=xË©×>õÚóz9ƒ@‚*# ù¶Ú÷ÒF$R™…\€:@舆€ò#pÍ5×L‘3?qâij­Ô¥ê¹·‡e­{–ã?1¿+R J h.‚§-{ÁÓö÷´}>m“>}×]wi? €J&€P2p.ÄI šo=ag˹×Òj«ž|õà¿Ú2ß¹@Àøp‰j q  ìM#O_~ùåëW¯^}R€ /FóåIi€@¤¢¿eË–³Ì±?ÇzïÏÑÒªª|®åWYf2=ƒ@‚  ÏZ–@°Î‚u¶|Ê¢¨Ö>|øi†  > ôS 8 dÃô[zñ/¶¯°Lˆ~œMO­ úð!éÐ3­ ³Lš4é©5kÖì©_u°€@9ÊáÌU @œ Õ?W=ø§zñÏ5gß{ó®O‚ zЫ109`à ÖY~ê¶Ûn{¡ÞUÃz@ƒ@ŒgC¸ñÆ—šƒ‘zò-_¬u3Õ'Ü ÔjÌ‚ ‚ (:à)ËZ°Öò#š˜p÷îÝØë 5ì€@ jQ7/•ƒ@Ün¹å–É<ÃÆ„^lãò/²‡¸‹ÍÙ—£¾å™qמÚA€@ŽŽYYÏ[N‡Øo‰&&\k>hó ìÍñ:@ R•âçâ€@7¶oã:Óž|;>íÕ·¥ÆåËÑŸ`™@(Š€æH£$ ˜Ø,aà{•á3¶ýÅ¢.J¹€Š €PUÊ„ú" }›Ýù<{¸ºÌ £/'ÿ–÷U 'A€Š# È€'mˆÙZû½º×–=zô‹Ð$@A@²Y0 ñ85Fÿ²L辜þ ,¿öÔ€"&°Ùêöˆ†˜  Ì1qkS5ÔŒ@Í s!P7§fÝ×$|i¯¾Ù¯^ýK,Ϩ[]°€ Ð'ãvÞs–5”à^Ë©@pçwê3à  (‡@9œ¹ ¢'`áû,|_=øo0gÿ ¶|Ý©Y¿ª`1 P€"¨R&$pÍ5×Ìž0aÂåÊ/G_¿ò‚MÅ$4ŠÀ”)S{`Oëlã|Ó¥>Ožü½=|džì|û®»îzÄìbŒM ƒè–@·¤8%¸îºëζqÃï2åý§ì²o³ܳJ¼<—j89ër굜9sæ+ÖõYN¼öÍž=; ¹o8.ª H Ø¿*8p`d]Û³Ÿ÷íÛ—[(Ü .—ì³…Þ6ðu[~oÉ’%?¼õÖ[_šÔB€@°‚m k [n¹e‚=ĽÞêû6sø=¤~SêO=Ë! ‡^Y¼gõÚ{ï½BðÝé/Ç"®A@óHPA6k› ÊúlŽ[&Pfs ìµ{껊0¿hÑ¢!4÷f æá@·m°,^ã,¤ÿuöù.«âÛ-«—Ÿ ûâmïBk¦‰ìÜ¡Ÿ5kÖȺoÓR޽ÏD_¨1Ô†€œ Ð*øgE Ð'M,¨W~Ë:8¾f¿W?^³fÍèïíóBœtO {V ¾ ˜Ã¿Ì~üÞmYN¿ò¢¾ ãÄÆP¯¼Âì•åÜg|9õÚ®ñI€Š" ×3J ð-í•qé6_j ]ØmÇ|Óò×,ýŽ;îxª‹s8È™@Î@)"pà 7L·þ·Øê»¬—Eÿ,óÿfH/Ð8ú9sæ$sçÎ Ï׺òÐÐãë_FÅ 0½ÝÀ#$ìÞ½;Ù³gÏÈRBÍ$p 0­"zÍàw­sä+öÌt—½e`GEvpY4ŠI£š›ÊE@ãøm¦æ+N…õ¿Û®ófËtͼå*äÞ{ï})gß{óµ´û¥5ÁD@ƒÐp 3( 1 ›}›" H& …è'–ð5{cÆ÷ï¾ûî#&Bå!P€‚ÀRlü|¦~«©‡õÅ_kj˜%`ïENÇÜÏ›7/™?þHo¾}eëÕÈÎ: t  ¹@(ŒÀhâ€DE¢'°Íž»¾jm}§Õô«6€^AH‚ú €Ð4NiU«V-´°ÄkíGç:«õÕ–g5§öÍ©©^‡§^üááátü½Ã×R³ì“ @ L:°k×®‘è­+ïܹ3— L«±j@z5Å·,ßi‚À]wÞyçs–Çéh€F57•톀Màw±w½9ý í_iy¢eR4s¾Bõ=d_¾>k; €â" É %ìØ±#Ù¾}{ºÔp}fΨÚúi4‘àr%&”ˆªy©LÞò&Jyµ#°råÊ©ÎýSÖƒ9ý7[ά]%0x„€&ßsÇ^KwöÕ»Ï+óF0±@ ±ôFMD¨áYa@ë¼Ò°ö·…Þ$ðM{žûŠå;lî&¨}“R¼ äM”òjAàÆo\j†^oбzúßiëÓka8FŽ˜2eJ²`Á‚‘}9øÊš]Ÿ@臀 P”€–¶mÛ–”`Ë–-iä€u8„f*ö¼’@:o€mZc“~÷•»ø¸ à Åݾ¬ÍÜ¿Â&÷y¿)¼ï3oh$„À+­™õ.\˜:øƯ¥ÂúI€ :PT€†hè€gE (Š€$'ì™ñ 67ÄM øIbr$€#LŠªŽÀu×]w¶MþvƒY žþ·Vg Wn% g_νÂ÷Õ«¯%áû­”ø @±ðhE h(–L:V«›ð¬ ·›UŠ øž- 嫉°&9@¤ˆjèu}öE-‡_ù¢j¬àªYêÁ×kõpö³TX‡ ´'€(ОK [Ÿ·¡·™-k.»ì²ï¯^½úd va"€0>N.›À{ßûÞ3,¼_¡ý³|IÙ×çz/ gÿe¬A€ò" Q@C|ÒAE è3©RM ø¢u<}ÊÞ&p_¥–pq H`@€œ^<›o¾yî‰'Þg_ºµ«ý´eîÛⱿ⠓&MJÃ÷—.]š,Y²$íáçu{¯@Ä@€@a4T@Ã6oÞœæM›6%GŽ)ìz<*Ÿ˜ðö\ú9¶Žz$;! ©“,¦ÿ–[&=zôíÆâ£ö%«W÷Í€Ky4ÿgœ‘,[¶,uöåôÛ åÀ• @•ÀîÝ»“7¦s øœÖa2ê9ìÌ•€†üƒåÏØÈÏ®Y³f®¥S "€PXŠí€ÆõÛ{ß?bNÿ/Z û+…³z!à¡üîð«—Ú´i½Á±€ TL@o ,a`Æ L2X^›²K}Å¢þbÏž=wßsÏ=ÇË»4W‚@ozãÅѸ馛–ÛŒ«?k_šÿ‹¿¢€KPä)Æ8™_N¿^ǧí$@€â"à“ º qÀæRŠ«’áÕf“ud}ÁÌú4¯ ¯q°ˆ±ÔܰžþéÖÓÿAû‚”Ó¯×öáÐ ÛWøþòåËÓp~…ô«ÇŸ@€@óÈùפ‚Ï?ÿüH”€"H…xÀJþsšñ™»îºkWaW¡`ô@§«X:8o¼ñuVÊÇ-ÿ¼å9ƒ—H Yš¬O!üêÙ?óÌ3Óžþ‰'fa€ ¤,32 A@C”™\°›ã°E[®±Ž¯ÿn~¯+P(º$€Ð%(ëŸÀÊ•+§ÚŒñ7X rüßÕIœÙJÀ~õìËéWf²¾VJ|† @ [š\ðÙgŸM#´Ô0R®7!àÏ­Ä?³!Ûs-™Â Ѐ. qH,Ìÿ óÿ˜}Éý’•0¯¿R8+KÀf™M{õÏ:ë¬4¤_½ýÆ8{ë€ @ 7þ¶Í#ðÌ3Ï${÷îͭ솤÷8Þa‘·Þ~ûíß°õ΃ê—D $ÐM¹ŒÆö[]?`NéÇÍñ¿²)õ.ªžêá×øýW½êU‰œþyóæ1a_Q°)€ 1 x„Àúõë“çž{.9|øð˜çpÀèLx؆cÜjQœñå/y÷èG³ƒ@ŒgŸ"@o>·‚fã׬üîðÒŸWJ @ ÖÙ“¼ð ‰Ä6À[✠øú@%q2:@è†ÍcX½zõøûî»ïöåÿvôu–¹ŸÆÆvÚsçÎM{÷Õïfª¢&ö[“ÎìU‡‰fé—ï<44Ôù`ö@€ tE@Ñ.hþÞ,0&¶Mvĵár×]wíóhh4€F7ÿË•Ï{Þ3ÃfŸÿ%Û¢‰ý–¼¼‡µ,ŸÀÏCû§L™’ÝÍ: @€@ŽüÍO=õTòä“O&ûöí˱ôèŠÚosuýOþ¯¿ù›¿Ù]í¨P.rÁXßBlb¿YÖÛÿ«öeñ¿[-Ô·&ÅY>sæÌä¼óÎKÎ?ÿü´Çßxw1J† @èH`Ë–-ÉO<‘<þøãÉîÝ»;×ðûíyõÿ9zôèÞ}÷ÝÛ΂ê·À“iÒ”·ÜrËÌ#GŽü«ï¿±¼¨)õî¶žrúW¬X‘Nà·|ùòDáþ$@€ phÞ =öX²sçÎp Ç’ÖÉ÷g&üÞwÜ¡a$0 `ÓîõøÛÁÿjõþWöeÀ«ü27ÀìÙ³S‡_=ýË–-ãU}6¬B€ d'ܸqcȦVaÛ»è§í­^Ÿ°W§ŠèšDÔEšâŽ¿9ýãÏlu§`ãôy×Q6 @(ŸÀž={Í èÞ(ð þGíÓ§&Nœø¿ô¥/mxÅ>4†@äM½jÕªy6yÊošãÿëVÕÙ‘W·«ê §ãùâ¿pá®Îá @€ úصk×Èœ[·n­_бø°ûg&üg„€b‡\*@È­3€m6Ʋñÿ+bµå¹Å©ö†ƒÔé¿è¢‹ï¢E© @èÀŽ;ÒùÖ®]Ë‚/¡;jCƒÿd„ ÿáË_þ23*öv;Õöh€Ú6]GÃÇY¸ÿûmï¶|vÇ£°ÃTÍ䬳ÎJ.¾øât&òk@£SE@€ 0szÍ !>úhrèС1Έ{·ñÐ Š¿oQß´·h¾RÄ"jÜ믿þJsrÿÀªô–ˆªÕSUl¨C²téÒ‘ÞþiÓ¦õt>C€ 4‡À‰'’õë×'<òH:o€>78=iuÿwöÆ€/ØòÅsˆºê4¯õøŸoÕø–o‰ :}UAãú/¸à‚´·îÜÆxè‹!'A€ &8|øp 1 á“þÐ:Õþåí·ßþ&ß±Ö Æ-kŽÿ"3µå_²<Ñr£ÒôéÓéW^´H(H€ @œÀÎ;ÓáôV&E|Á¢‹ÿͰ®õ¶Ê5lÚn¸aº™ýë¦Ìý[[6nf9û¯ýëÓÞ~ó'A€ @ š/à¹çžKxàäÉ'ŸLNžŸ³Kž]âe ¿”&ó{ík_ËŒþ…“æ€ @18vìXòàƒ&?üá“ÄVÕ=ýOo¿ýö¿Ž­buª@9­¥‰þþ¹]êÿ¶ÍÔ÷îø¿ùÍoNf̘QI®@€ È Ä,˜ðÖ)úÏ,à`äÍdõ n–U«V-´ü³1Môgï÷L.½ôÒôu~Ó¦M+˜ ÅC€ @ ™$hhÀ~ô£äàÁ¨üåmøð-·ÝvÛÍlÙêjP û믿þJ›å]bY—)­hõøëU~—_~yby”v].@€ &p!@C"š#`u’~Ì"¾Üä¶-»î·ÿ[ÑlyrA—(­X ÓIV¬X‘¬\¹2™={vi×åB€ @€ÀËäük¢@½5àøñã/ï¨ïši/þñ¾}û~ëž{B¡7@Î-d¯÷›nó­VìÏå\t%ŽêU¯J®ºêªdáÂ…•\Ÿ‹B€ @¯$°{÷îä;ßùNòøã'æ@¿rg ?™ÿô {‡ï¾ûîm54¿V&#äØ\Öë¿ÔŠ»Ýòs,¶’¢†‡‡“Ÿú©ŸJÎ?ÿüJ®ÏE!@€ Ñ lÞ¼9ùö·¿<ÿüó£X½ÌÌï¸ãŽûêan=­DÈ©Ýì—ØdwXqËs*²’bfΜ™¼å-oI^÷º×% ý'A€ @axöÙg“o}ë[ɶmõî@·h†6‡Ú‡íUw†M¼¾ÖááåÐv7ÝtÓûífý´5=‡â*)Bü]qÅéZ'A€ @õ!`‘É<|ÿû߯ûNšoõ[69à'ëC¿>–" ØVæüÿ¶Ý ÿÉŠ©-Ë .¸ yûÛßž¨÷Ÿ@€ Ô—€& üîw¿›ÜÿýuŸàOìõã¿¶fÍšõmð,¯­ÓÊqæüÿ¾9ÿÿ"[ú2ahh(yç;ß™¼úÕ¯îë|N‚ @€Â$ð /$_ûÚ×’M›6…i`VÙä¯Nž<ù½&êâpé‚@Z¹å–[&9räÓ¶ýC­ûêðY!þW^yeòÆ7¾1™0aBLÆF@€ @ GÖY™<ôÐCéDŠ ¨c2à~Vš°§Žö‡f3@-b3ýϲS¾dù]=žÄáguVòž÷¼'™;wnö` @€ P,$ßüæ7“Ç{¬Ø Tº‰­ãòò/}éK› ºDcŠEè¡©­ç޽ŸònSÒ®ìá´ µñ3ÉUW]ÅìþA´F@€ @ |O?ýt:,`ïÞ½å_|À+š°Ï"Þ`‘O XT£OGè²ùí5sOœ8ñ·vã]Ñå)ÁvÞyç%ï~÷»“3fc†@€ @å°¡Ìé€|°v“š/vxâĉoùâ¿x_ùäâ¸"@íXWçß²dåÊ•Éë_ÿú.jÉ!€ @€@S<óÌ3ÉW¿úÕdÿþýµª²‰ÇÍϹÚ"¾Y+Ã1`Œ†¸îºë†l¼É7ì°KÇ84¨ÝšÙÿg~ægxµ_P­‚1€ @‡€&üÆ7¾‘¬]»6£º°düøñ'MøÀç?ÿù/vq8‡d0|FëªM–7ÃÆÎÕ¶_Þº/ÔÏšÕÿïxGš5îŸ@€ @  §OV¬X‘Ì›7/Y¿~}bCžÛÜ6›“mœå÷_zé¥O?üðÃg`À!th½êÏÂK4ÛÿÛ;ÜæáááÄìNÎ=÷ÜÄlÎ> ‚ @€Â#0þü䢋.J¶nÝšÔe‚@‰&X¬zÃÞ°Ã^uøáQ Ó"€6íbNô›ãs¶ë¦6»ƒÜôš×¼&YµjU2{öì íÃ(@€ @ \оøâ‹Ó‰7nÜ®¡ËN‰×Z$ÀA‹ø~f« ´c³æÿWÛü mv·Ia;W_}uòÖ·¾5Qø? € @€@?E|ÖYg%K–,I4IàñãÇû)¦ÔsLhñîË.»ì€½Ù` úxŒ-€n¼ñÆß°M¿Ó²9ÈêíßûÞ—œsÎ9AÚ‡Q€ @€@ý %^xa²aÆZ¼%àäÉ“Þc‘/Úp€o×xy#dXßtÓM×ÚÇOYŸÙäêÙgŸŽ÷×?' € @€@ž|H€^øÂ /äYt!eiC{;ÀÛ/¹ä’#&|·‹DP(À©F4çÿµ¦Ým§†Þ®o|ã“k®¹&™4iRè¦b @€ PSæP'6<:‘ðì³Ï_ Y°aÑï2`‰?Þà D0è7ß|ó\sþ¿e«‹+hƒ®/©Àw¾óÉ•W^É,ÿ]Sã@@€ @`K—.M”Ÿzê©à_¨H›'íê׿þõÏ›pß õŽñ\€$gï¾ü+kÜ+Cn`©nïÁ„l&¶A€ @˜;wnúºñuëÖ%G º†6'À8‹–¾ÎÞ”v¿½à‰ -Ù¸Æ 6éß¿4æ¿^2÷ž.7cÆŒäø@ªºõt"C€ @ȉÀôéÓÓÉׯ_Ÿ|8ù⿘lÚ´©jSF½þ´iÓ4`³ xÓ_ýÕ_=?êÁ ÙÙØ€[n¹e¦ÝgíÛÝ™ñÕ¸!6^eµ5ãò›rhh(yÿûߟLž<9Dó° € @€Ài&L˜X”urÆgœ¶/” GޤÃÿ'š=ŸûÈG>²0»Ê¶£QÀu×]÷S}‚|å߬Y³Ò1ÿzå € @€@hbÀ÷¾÷½‰"šCLŠФ€––ÚòÏB´± ›š$Œ³ð”?6¨R}‚Jêñßûޗ𪿠šc @€ L™2%hVçfˆI¯/Ôœ–®·a׿¢EÛÔà†nøõþ¯,h¯å›M‰Ù–,X° ×S9€ @€@PѬH¹-ÉùW$€’ùaŸüèG?zfh6mO#€ü㓬?Q4Ì~ÊÇ;Þ‘œ}öÙýœÊ9€ @€‚# a×_½œìàl;5€ìšmbÀŸg`Á5â-Ë–-û%ãø ³ì¹ø .¸ Y¹reÏçq @€ ''OžL6lؤ™š¸ÐÒ9_|ñcöjÀG‚4²£¢ìµS¬q¿`ì‚zíŸþ!sêÆ+ i)€ @€@u–/_žlÞ¼9Ù½{wuF´¹²„‰S¯ÔÞ7_xá…ÿcíÚµGÛݦè‡XÃþ²µZP¯ýÓ ™7ß|3¯û‹î߉ A€ @N@C¬C6 íMgš àèÑÿ óÏþ­Ûû2j`õêÕªßo„Öˆo{ÛÛ’yóæ…fö@€ @È•€œÿ«¯¾:×2ó(Ì'묳’çž{.È*Z4ù/™aQ axÉ96ûG>ò‘ m"‡9_B¾ôÒKéýϱ}) € @¨?K.¹$Í}Æ¢¯ýà?øš–mQ|Œ.`Μ9¿¼cÇŽ gòäÉÉù矄-@€ @ gžyf244”ìÙæP{>l¬þ](¼ò²#:àäÉ“7…þî¹ç2ó^w*å@€ @ÑPÏû\üèG? ¦NæKfm‘ðï-¿â5Ùê¸Ý€£Gž) „¼bÅŠ:ÞØ @€ @ pŠ–Öìû!ønm:‘_ýs?÷sÑ ˆ*àŸøÄeö:‰‰m¯ð›·õS§NM–,YÒº™Ï€ @€ `ìímÉ‚ ’íÛ·ÁCQ 6¡üˆ-ðûðÐȆV¢¬>ªF !-[¶ŒÉÿBhl€ @€‚%pÆg$¡Ìá¦h„ãǰ2ÿòÝöáG6D°›pU½ÿº/–/_ÁíA @€ G@~ÓC…ÑÉžíýW­sù§¯¹æš)wß}÷‘â”[rlÀ«C-ZTnKr5@€ @5#0þüdâĉIË|•Ô¢U0#¦Û› ^oˬĠ.ðùÏ~Ú½÷Þ;+`Ò¤Iéx–Ú‹"!@€ DC@a÷zà®]»‚¬“‰—ša¶Îkí ãBæÍ›ÇøÿoL‚ @€Â# ÿiÏž=•ÖΗ´È Ѥh"Ô0GŽ Âñž5kV47 @€ P$ùO¡Læ. ;ÁìB(²ñû-ûĉê¦ áÆ™1cF¿Õà<@€ @" ÿ©]ï{Z°¢ ;ŠºfLg†rÓLŸ>½¨ö¢\@€ @Q˜6mZ0@k‡²}ž{ã7κãŽ;öÅ=À"ÎEÐD$@€ @›€&QÅ—kdý”)SôŽ÷µc×$ü#¢lœÆ’PnÝÀ$@€ @›€^Š/×ÎóïÆnÆr°†šÓN­)׊—®Öæý‘U˜Á5!@€ O@þS(¾\;Xfßp»íuÜM€…ÝOi§ÖTÑ(UP皀 @€@ Øpî`"Úùr¶-šIÞ¢V¯^=Þ€I¡Ç¯ãÿ6C€ @(@è€E' ”~WŒrÁË.»lêÁƒÇ…"=ztkÙ@€ @NàÈ‘#ÁD¸MÙ%Y¬:t(íý×ìûíB6Ê6ñðáÃe_’ëA€ @¨%ùO¡tæÚäòíNn·±ŽÛ¢ààíõ ‰Ô£ª“ U›Àõ!@€ Ô‚€ü§&Tg²†#Äœ¢Ž;Vy{8p Dá&®@€ @…À¾}û‚ˆÐ\n!D”‚jà]Ñ 6ÀÀP-@7D€™3gZçC€ @ˆ–€zÜC{ï¿n¢è€PÆŽìÙ³ Ú¯)*@€ äA`÷îÝiøÑÓMx›[TÀôéÓƒÑ?®]»’eË–åñ?A€ @€¢$ ¿)”NÜæ“+º‘£4 `Ê‘MJ–†„bOÑ7åC€ @è•€Gôz^Ç7ámnQ 'NL&Ožœ„º!ç_jÖððp÷&eB€ @¨5Íߦ7„ ÿ  †·“†ìß¿?Ë·mÛ†DK` @€ ùK!8ÿâ"!âäÉ“¡!ÊÝž¨"DG@o-šP3IN˜0AI€ @€ `Ôã¾}ûö`€P:‘‹¾9¢BQ‘tS¿ð ɒ%KŠnGʇ @€ P.­¡Û¡ønûöí« »A NÐ<“&M b5ÌÖ­[“Å‹3à w)çB€ @QزeK0>’Bÿ8ßN•‰NPEg̘‘„¢àHÕÚ¹sg2oÞ¼NmÀv@€ @! p{ Û¥÷ïÞ½ÿ¯,Z $góæÍÉÐÐP07xc¾Y¨( @€ ùG¡8ÿ‚³cÇŽàeP”€†„ò:@5œGÌŸ?¿¨v¤\@€ @ÁP¤¶:kC4i»æ#hJŠRPã…4 @öèŠà¢A‚ @€šH@cÿCqþÅ_~Z^ÿç÷Z´ÀÔ©S“^å (M¸téRgÏ€ @€@c(ÔþðáÃÁLþ'ðzk[“R´€zÚ§M›–9r$˜öܽ{w2<<œHœ A€ @h uˆÊÙ©÷_CöìÙÓ”&Hë­ ÚI8vìXP ª /^õªW¥zc @€ è(ô_)$`Ó¦MÑq«BQ ¡M¨Æ8zôh:Ë$Žuk²€ @ˆ€zÙCšøOLå—iˆvÓRÔ€SáözÇdHIC4I¡"H€ @€b% ˆìíÛ·Õó/ÖêýoÒä~E/èu€š ´Æ•Ú´|ùrÞ àw"K@€ @ */¾øb¢Ð-ÇLÝ4ÁóÏ?Œ=e½ ˜êi?tèP™\Ǽ– M‚±dÉ’1å@€ @u# žE„4î_ Ÿ}öÙàæŠ+«m!Lœ81Q>qâDY\»ºŽ^±sçÎôÍ]ÀA€ @€j@@¯dW©ç_Ø. ©i|S*®¡!&Mˆ¡  @€ ¨£S½ÿ!¦uëÖ×1\&§ÆP&Ün¯¥ý“ @€ Ô™€Bþ5ß™Æý‡–öíÛר±ÿÞTá)S¦‚"»ôÏ¡…£ @€ Ô‘€†\kÒ¿Ð&`Kù\k×® R˜(³­%hò‰P‡èŸD"€3 @€ :ó¿yóæD3쇘dÛ®]»B4­T›%ˆ¬€ &” ¹Û‹¹bê?M·õà8@€ @ 9BïÌuÓ4RP@¨CÔ.ˆ!}¥a  @€ ÐŽ€œu^†<¡¹ìÓ¼¤—4RPÕêPÙç"sˆ € @‰€Âþå\‡<‘¹lSï?ée„`Ú´iA¾À›ÇEY!A€ @€ü”M›6íü‹ÓC=Ä$ë-7L£EH9ib@ýs’ @€ ”NàСCµ˜°\ŽÿºuëJçS‡ 6^P#…>€l”°mÛ6Þ])$@€ @ TûöíK¶nÝšhìÈI>øàƒ!›X©m†ܸqÉŒ3‚žÀï’Ý»w§Ñ¡ÿã¹½,!@€ zعsg²}ûö´S2äšhøôý÷ߟ0‡ZçVšØyW³öŒ?>™;wn:û¾Ô­ÓR;.\˜LœH†ÜVØ@€ ºC­(d…þ×!©çÏž=u0µ2‰È W˜ýìÙ³“³Ï>;øÉõJ MX—Æ fV!@€ À ÔÍßxâ‰'ÒHéÀ±Vn@Kh¶}ÍhyÞyç%guVÐJ‘Ó8 A€ @ȃ€&×LÿzÝ_ÒÆ“õë××ÁÔÊm$~¼Mè†×ÛæÌ™“Ìš5+}}„fá—ÃZRÔ®]»ÒH Ы I€ @€z% ßBãý÷îÝÛë©•/?íÑG­ìúu»0ZL½êŠÐÜ ,H.¼ðÂdñâÅÁ:ØšíRÊ—l&A€ @è…€BþåOÔÉù—X¡qÿLÞ}K#ŒÂJ=ëúGP’ ö .¸ Y´hQB€ Ð?‚Ô; @€ ÑÈoÐÄy ù×Pèº$Ù|ß}÷áü÷Ø`£ó˜ìØ…ØK8ÿüóSA@¯ -éŸAòú‹ÐZ{ @€ ù9[¶lIÃþëÔ¨!ÛrþC¢Në¶· =—‘­º©vìØ1òÙWôú= PDÀ¼yó’Є9ÿˆðc @€ 8½Z\!ÿJ\§$çÿÇ?þ1}6@ऌmß¾½­“¯É—-[–ÎÚЀº†ótÑ$@€ ôA@œêõ×äyu;¯ù ~ô£áü÷Ñî~ €“c©¹41 æh—  Ä9|BÙ_§ÐžvœÙ@€ ôN@~À¾}û’ 6¤o뽄jÏÐ0ç{ï½·6¯&¬–Vç«óÀÎlNÛ£0 CCCo<Ÿ#`þüùéÐEdç8­Ð’6è^“ª²mÊ”)%]™Ë@€ @UÐä~Ö|èС*ÍèûÚòcî¿ÿþ üª¾+ȉ=6„T3‰sçÎu–L zk€œmÃß¶mÛ¨Ç÷hF߇knÍð9kÖ¬TÈèÑÐ÷8€ @‚€:¬ÞóºFoݺ5yøá‡k7\!ˆ m ŒµIÿ@rœçÌ™3æøá»D@IDAT'@jÌŠÆÚT­¼éŸ_¶(@B†Ä€Ð&1« Ø@€ t& ÉýÔë_ç7ƒ=ÿüóÉc=Ö¹’ìé™@ÏÈ^:Áç˜={v¢1öc%9Ø ”åx+"@Nx•Éßp {$PLž<¹Js¸6 @€ 0  ?–ãðàÁKªîtuX®[·.yæ™gª3"Ò+# а íW¿D)l݆Õ̘1#QV$€æ¨zr>Ù®W€¨ŠÐð @€ PšÑ_‘Êu÷mÕC!ÿŠœ&åO`@¦R×Ô»/çY}·"€.;mÚ´dùòåéÛ É-ª|‡"4Ç Ì0àÍÁé€ @(˜€üýû÷§¾„"|ëœYýÀT)]g†cÙŽ0¡.ö«_βÆÒ«7½×<…Þ/[¶,Y¼xqú«òª«£/©†úÑÛT' @€ u@**¹*ß!O"ꈔó/ŠT€œØª_"ÀÌ™3ÓÀ~þ z¯ •Õ/!@ŽxI"†®/1@B€†, @€ ê ¨§\Ž,Îò–-[’µk×V ]}«–c@ŽœõŠ %‰ræõÙË€¬) Ã÷af áý–•-·×u½3Tão¦NÊD½Âãx@€ äH@üÉ/¨ª“0Ǫ¤EiøóÓO?¬_¿>ï¢)¯€`úÝ,gY‘Ó§OO³ÂrׯyÎ8ãŒtž Rúô_v’˜±iÓ¦4@Nš4©l¸ @€I@ѹš8\aòUt ]Q =ôPZ¯"ʧÌöÚsé{«þ! °páÂ4@B€nnõ¤’äpkŽ€E‹¥Ã$”­ü©nº¦²æ0q"·Ð íʹ€ @èD FÇ_uUƒfúïgØt'VlïŽÞ[wœz:ÊE¤á Ÿ—£¬h€A“Þ80gΜ4«< R‰2èÇ&©$pHÐD†$@€ @`prü5—æ‹¥Ç_Tä³(Ü_9¦z Þâå•€P k ЭÞr šHoÐ!Ys}xÀ’%KÒ/MD¨hƒ²’êvàÀäàÁƒé+ %L™2¥¬Ës@€ DE@C}åøÇêï ¤!ÅêõWýHÕ@(˜½œr%‰š@"€œô<Ã]4áàððpš¥**@_e% $n¨~ŠP " ,ú\€ @ îbvüÕ6"ýØcU2—YÝï¼íGÈ›h›òô:=9ÉšÕ_!ü>$@*XÞ¡ûþöÍ9 ±5 M•ÚnR5,@Q h‹ˆ€ @! Ç_Ãyõ ­g騒ê÷øã§@Œõ«c{!”ÔjrÄ•Ô;®¤!š@"@žÑiáöG“j"Be}¡èúe…ÛèŸ["€²ÄÕY‚ € @HÒˆ`Eîê9=Ö¤·—=ú裥QŽ•ežõBÈ“æeÉ —s¬±òž<@áóE©b”«ˆ À¡,ÁCB€ìÐP @€šD@ÏúzæW§œžcMŠp^·n]²aÆÂü›XÙ•Q/€2(g®¡°|ýó lUo½Æñç=7ÀÈN­d£¤8jhBYª£Â$€(ÄIÃ4'‚êL‚ @€@Ìôì¯goe=ÇœÔë¯ ¤0 TÐ.r‚•²"€zÅ5«¿œtM¨WT4€W×ç è QB¹Œ¹ôJ]K 4,@Q¼9À[…% @€@,äìËé×äÜyÏû#ùO?ýt²yóæèëû^íAè•XNÇ+ôGÎðüùó_Q¢Bååœ+,¨ŒWúÉù^¼xqš}®}Q-@¨üì<ª³Þ @‚ @€@ è^ÏÓeEÚVÍJ¯>òÉ' ™×¬êºÅx}€ [U_ R,XðŠqñzS€G(|FBAÉç Ðõ$Phˆ@ã“t eE?hh€ì`x@-Î5 @€ò  gzunÉñ/b‚ï$‚¨€"‰S6 @€@·ô¬ªN<íWgY“’|…ûí4‰iÙuE(›x‡ëI=” H9ü­I“ªW\ûô…S¶Ú¦ë{T€lÕ?¿rÑóhò Њ ЫI€ @(“€¢råôû0Þ2¯]õµÔùÔSO¥C„«¶…ëF`0~¹ž-gW"À¢E‹:ÎŒï=ârÂ%Tj”} TOŠ%¤´êËV™¹r½í( € @ &÷ö ‰ü“çž{.Ù°aC%~G‡faó€WÄ©rè5'€&mü»œ`½BÏ'ÐÓ—SI6*ëMÿ$1@Êh‘IâG6*@‘²A“'’ @€ 0=W+ÊUO u¯¢Ãmûó8WuÞ´iS²~ýúTÈ£Lʃ@íð +ô¥£×iÌ›7/ÿ;3üm ‰WO¼Ä€ª’†Ì;7Í>D`÷îÝ…Ú$N ëKÐ\ ¨ê.຀ @ ¾â/‡_Ï—êùnjRG›Âýå_TÕÉØTöeÔ  Ê}^C³ïË™µ š@ޝ†Týê‘ì‰z¥ "Š´K*¥"”u}´N‚ @€@;ªçg9ýUv¦µ³­ìmŠæ}úé§Óg÷²¯ÍõÊ#€Pë¾®$‡V_LŠP/÷hIû5IžK©—!(—%”5¯lr1 Èù$š(ú@yÊ”)iT€"Æâ7[öA€ ÄA@½ÚêÝ–Ó/ç¿é½ÜbñÌ3Ϥü5Ewøèµ@O{õÅ$‡Yó´{M`«‘š(PóxS(ã–Ô+¯¼dÉ’´§^QR‹ü¢Ñø-e…2iž Š–`¾€Ö»†Ï€ @ ^zÞlú¸þÖÖU§™&÷c‚¿V2qF¨IûÊ™×$´{M`»jè8e}ÙIDEó={öì4KØðɥ•ô¥/ÊQ$(3y`QÄ)€ TKÀ~E¡ê0„èØj‰¼tuwü5É_‘Q¹!ÔN'€p:“`·èT“Ο?¿§‰î‚¯Px‰úò é]θæ8P–} Û×0…"•TŸ/@òbÊ¢N¹€ @ xY§_ŽHϽÅ×~ô+Èñ—Ó¿qãFÄÑQE½ fÍ«^ümÛ¶¥³Æûw›Ôë.@Ù#BûBT´ÂÂ… Óìb€† ÈÞ¢’x*ò@YοĪÀ0¢¨S. @È—€&ð“ÃÓ:WÿÓ™4y @M[_ޱxõïÕQÍF„ú%™ô…î“úI(*I ðaÛ·oO‡H P„‘EQ§\@€ МþѹÉñWo¿²žsA‚@ï…±Ë!Ö€^ÔÖˆ€P…5‹Å‹§Y_ôþ&"Å€ìœb«¹|¨@¯¬k|‹a: @†€žÏ4LTÏ­ê´‘SK:€ž‘Ÿþùtþ0Χé[j~(<^óè5ý¾óÞ‡èËB_¦R CM”ýµ‚>g@‘“ºè‹S?4ÊJº¾O ¨H @€@1ñ*§_ϨZâÐvæ¬gyõökœ?œ:sjú€î9¿4‘žBÖûI ‡V_ú‚Õ2ääcõ—-[–:çŠ P.ZÀP‚²’D 0@‚ @Œ€:¸Üé/r.¨Á¬ çluRÉñ×V9þ„ú‡Ó6!Z‚b«ôa“þÑõ®{9ísçÎíy^¿¤ Š ° /_9»¡‘¸°téÒRʼn .<øP. 7 @€F' çL=oª—_ÎlhUn}5{ÅLÏ êí×Ü`¡?«WC‰«¶#€ÐŽJ·ù—æððpÏó´V[½ÛÊ3gÎL…•]‡/—V1@s%h¨@Ñ ­C$¢¸ u @€ÀK¼£ÉCûëðŒBÛ‰“zú7lØ02<5»°¡>êÓV][*U¯ Ô¼'ÞÄêÙ–S­Pw•í"C×Ux ‹šDPv{o}ÑÃTe…¬)K|P;ø¼*ÀD‚Þ\€ Ò ÈqÕs¤¢Kë0Ô´t@c\PY[¶lI6oÞœFéŽq8»!БÀàÞaÇ¢ÙQ%Ÿ@Ãäç‘4<ÀX9ÐRlõE^—äb€† ÈnʨƒÚcïÞ½i/EHP„€–bK‚ @1ð^~wú™˜®÷ÖU–Í÷¿ÞùqÆéNgÍ)­4è¼­@ä¬j²@e}±ë‹I_ìuJrº•õ6ñ‘s.A@u)#yt€®)ž<÷û6‡2ìæ€ @ ¬Ã¯Æòw"5övÍí¥Þ~E’’ '€ŒýSU@€@‰4æ\Ï rúÝá׳ ipÞÛ¯ )pœ)%tG ;NQ%‡\_:rn‹t W*ëÇC×­cT€_œ=¡¬/hÕÅ'õSÝÊL>€®¯¤2 e‘mZf=¹ @åÐ3ŽœQeïéÇ1Í· Ô¡£ñ‡m¾l)­;ÝqŠî(9­R%Èi,:y¯µ”d Ð8û²zÑó®›"'\Øð7 xd€„²“ÄeE&(iƒxûÊn®@¨=—¹ÃïN=,¯—•zNÓP\={×µ3¬^ıv4£Ñ‰|ŸTG £¨ží¢†d1f£¤,ËaÖNPÅ_¸paúV„ìP*^×"qGÙEHp;õ™@€@ó¨óE¨÷î—ÅØ$âz¶Uo¿=oWñLØ$ÞÔµ{ݳŠöHýhæ~‰e:‡îê R6x®3h½eÁç Ð}V ¨êí! ¨ % =bïQZ%Pç»Û!@§Ðó•|:¨—ªžEN·.Þ-zžÝ¾}{ÚÛ¯g0B#€Z‹Td~vìØ1Ú^¦rHý ršõũȀº«ÒŠvÐDˆÊJª—å*† x›fßæQ. hA!~}–€  F@½ûÞ³ïN¿~óIÅÐ3«Æô«·_C]á^úq÷¹$ ¨Î!$ÈÚ"À‰EˆY:¬C€z#Ðêì»ãʳ@oµ‰çhEkÊéWf…xÚµ©5AhjËwYoõ¸Ëñ“ ç®ê”u–¥ºJ  KòqøóçÏOgŒUÝôÃ#Å9„è€,g0ñ µOÑ ­ÂòÔX‡ $©À¯g,ïÙ÷%Î~w‡žÞ¯¬ub!€KKX9Ú!ExUåTΘ1#Í>y`lb@öµ‰‹/Nälûd‚ªwhIʸrV”Q[y„€–J º‘ @M à=ûrø%æãì‡ÙêzvÑ3¯zúCët “VÕ‘@[­"›¥~ʱS4@™¯ 즺r0=Œ^N± Y'´›rB?F=ëÃÃÃiV=5DÀÅ€¨$"y›8ãl¤€G „v_¹­,!@Ý£¯g%9øÞ»ïëÝœÏ1åÐs”œ~eµ ±@ˆ½…s®Ÿ~Ô å=ï!¾*Î{ÍgÍš•†ÐK¸óÒxú<šEõT••ô£åÑZ†>1î%å¬H£ûÉ…‰5 m$@€@H$Ä»s¯¥²ÄxBøCj¥ö¶è9©Õé§ÝÚ³bk|xªŽ¯MK©‘œ6ýÈ…27@§JËIv±Bcê5g€„}ñÇöEŸPÝTW©Úªk]ÄÙ­ålR;ª~òáØÈRÔì÷žj†~…߇ m9‹Ó§OO³Ä€ld@è½åÙzt³®¶ð7',\¸ð“ J¨Ûd6êe‘ ¡œMÙh$ d)±@ÝÈ:ú„ïwC,ìcôl§ ”=û³žÚ™&@hrëçTw9“RŠ.'¬I²ÄE,X° µ_ʰrÝœãnxË!ö9|2A¨ÃpNuôa­ûU_ 1àKͺPÕZ>C€@¾²¡ûu¦ç9ˆ8‡ù².»4E§ºÃ¯çÚ³ìàzu €P‡Vª®²J G«NIv+Ï;w¤·\aóô [R]çÍ›—fÕM¢‡ u.0Z›¨Íô œMrþ=jÀ—. dI±@ þ$g|}vG¿þµ£" _ÏjrúÞŸýÝÇùç@{í¹°µOúaÕ°zÖõª·::U/|r=ýxÈ9Ö‹ãXÇŒµP] SD„ÚÓ[oq´ôèÝ Z¯ã}ÜZ?>Cˆ€¾Ó=Ì¿ÛÝé×0¶©>jë½{÷¦Yjk Ð=€îYqd—ôƒ+ÇQãµåHË¡ªk’ã×:T@αrLŽq¶}>«7]ˆÚT?´±ÖÛ"³,´®{@B@V(àŸZ‰ñ€@~\¸Í:ö¾«(Ÿ½8JÒ= gwúõ F‚ú'P_Ϭÿ:sfIô­Iõ*7?ab6*044”:ÆúA’s¬¬è‡SëüjWAbB¼-õà¡:+·NB¨c@ Lú-Ñw;òí–îô‡Y¬ª3=Ïùo¹Dþ˜ŸeêÜNØîÊ èaEʰœ Ý´¤ºgÇÑ‹‰ÄqÑR9Vµ¼µîz`õ=Hh]èF!á$ÈÁhj’CåCüÐâØµ»O¦¨öWýUgÀÐC†îR±äd(U +4´À…Ý»ÊþÙ÷e·û:CŠmCJ‹€8ÿ¿ê´žuîýذj5M% ßbEèùo±–þ[ŒðÔÔ»‚zו@][.b»åpÈáÓ+öH/Ô}å  Ý)Ö°Öcý–“(AHyþüù)=tHð¬ú“ª# {OmâƒÝZâB€/;‰¾_KÝþ¹Ûëpò ๖ºç³K­»S¯¥öké9Öïç<¸RF˜tÏús†~kõ¬¡û™ÔŸ@ýÛ0Êð°4z³Êr§XGŠ—Bïô-…^9æ±w­Ãäxªîþ¢uî¡Ñï¡öºCÕ¯-­‚€ Y‘À·ùRû|ëz¿vp^˜ô œuÔ[?û=èKߟ=Ç÷…YK¬‚@>Ôù¢ßNwúõ¡ÿ €øÚ4Šñ£Ó[3Ê‘Ñ+³)J©×¸~Ì}©Ù“줊º$€¸(à b¬{“ëä÷s^½RYA@\‘ äBC'áÀÏócµÌnË®{Y££}uOúôïñìº;Öª_ëv¯³o÷¥ŸÓî³ß~Œ/u, hO@ÿ'z.p‡_¿‘ÁÅÿN{fl…@Lbj͈êÂÐà)çEó(RÀ“¢\ Ð2Ö(9\zŤòððpZ}9‰zÈQ”€/ór/ËzÈ:˜ª‰?—]«¬`à×–p0ZÊ ŽË–áŽs§cÅb¬cÚío·­Ó5Ø”C@¿ýúÝó¬ß~þWËaÏU "€[›FzŽ@‘/E(«·Üð%ds¬N±‘ì< "ëbˆÐgª&àBDÖÖ³4X‡:Ðo¸ÿ¦ËáW/¬¿ë°Àè|Ø[=“Š' ÁÖ¹ô  ÞPOÖcL%044”VÏœ¼—DKD[ž:A¨? ƒúÎ:üËŸ}†Ê®×¿ÆÔȃ@)£úÑR(,©\ê)Ÿ6mZšçÌ™“^ÜE=hxŽQða:áÉ'tQ@½)U…†»M,!@ YüwXξ~‡õ›äÎ>N~³îj A Jó #ÀZah{.X‘Þ[î'ûÈ„€˜EÖ UÿVQ@Că@”€~cô»*gßcµä¹hP²œˆ÷A°ø¡ ¶iRÃFôࢇõNÄøÐÒNЃšG ø’qÛaßÃX@ JzÎñßIwøµ$ʬÊVáÚˆŸ@üm\Û"Ô¯éÚ‰jG=Ìè!G6þ°£eLÉ#$|>Õ­5R€á1µ8u Ð=E‰éwOb±ÿjgîr$ €|8RJøQ,jEjõ˜+knOê×C?i©h˜zÍÛE ´Šâé\XB€@} èÙ%û»&á»]¯>Ï8õmc,‡@Ý Ô½±5% aÀ_Kè“îéÈçpqÀ—±<,& ø0-õÀH‚ p ´:ú±%òf¯²ëáÖË &@hRk׬®ühÖ¬Ár27û/R÷‚"üáJ]zÈŠ%b ( :KÐ|ZJ`ß,!”C@¿=ú½ÑïŽ~s”Û Ó<³”Ó\œÀà )¡ ü˜¶¦Åúün¾ßþpæhZúº[Ç¥"$|^¬ýŠðH‰ZWvÙcY‡ îè·Ä|ý†d}/ïY'Á¨3€:·^ä¶óCyçT= >” {Ïh=+øº–Ùãr2£´b!¡!>lBV}\ð¥¢ôK‚ — è{Q¿îìk©Ï<Õù7ÂëÀ€@'Ȱ½rüWÞµ6@=è“&MJ³zÒ³I½èzàk·Ì>fÏ y]uÕ‹ÙIe¯þ‡$ø‰¾r}° €@¿ô½ç~v©uålâ9#Kƒu@ )šÒÒ5¬'?Ì5l´š˜¬^tE´K>¤@â€g=4úz»sBÝ–F0gΜ3FP°Ô€¾§õì½÷Ùuœü6(&C¥@(7ë…@/´86/ÙÈ/ÓïE-õ ™\Щçç…ºì$ ¨1кÔ> ²øw­¾oý;×þvßGuùþ-‹× Љ@'2l¯œ?æ•7´ã¬û•ÛÝŸz(ÕC«–¾žÚ=´¶\¢ÒŠŠh7”@F©;ëòA;•V„‹CÁp§Þ¿#µômZvú^é´=ø c  @ Ò˜q:~äOg–° È–HК²÷²?ìº@ BÚ½žQõTÝ\ÐÒ…­«·Ž4€¯i™uêõýçÛD%ûݘ¥Ôi{öÖ!@ ?ýqã¬ðPd.Q:9ÒÊíîomóg=(g?ûv-CJ<¦L™’æV»d¿D‰ž%¸PZ]Zíç3 ðJúŸVÎ:òþÝ$G_ëþÝ•=Sç @ a´V´!ÀC(lŠš€œiE(k˜§Öÿ×RܾôqÿìçWµT}üíl8à‚@«@ '‚”GÀ¿7ü{Äzwê}»–í’Î'A€@ø^~ ßV,l&ÖàT·kr¬EÐ.eÿoô îõÙev½ÓÃ|»²óÞæ¯ilW®ì’â€Ăl4Ö³umWÛ ÐtÙÿuïµ÷múSÎnÏòâÿ+Kƒu@ñ@ˆ§-£« Ñ5)*™€" ”|Ùzyÿ󥜭·fmWòý­åñY6= ³¢€‹Ù¥Û]„}” ªèÞ÷ÿE-=Ëwæ}›ŽUòeú¡åÏhûZå# D@ ‚FŒ¹ z0Qo' (Ž€ÿ67Aöêú¿lÍÚ?Ú¶ìùy¬g‡̘1£m‘r‚E Q uéÛa ãH(›@öÿE÷ öûQËÖu£äËV›;mo=ŽÏ€ Ð\ÍmûZÔ\3îœÔÂ`Œ„@èR¹³1Ö6í÷c|=ûYøüsëz¯hÇŠ"ðò$øpƒ¬PàÛ}ɼNŒ¥ð{XŸ}Ýv}ήûý“ÝîçyyÙ¥Ž#A€ò&€7QÊË•@¹â¤0TNÀÅÒËÿwöX_×Ò×[ËËnoݧÏÙ¤ •§NšÝÜv]Nœ¢´t±@ë¾]Û²ŸÛÂÆJ ø½Ñi™uÚý˜ì6¯6n—üø^÷µ;žm€ " A•2s#0ÚÃTn¡ @ V<*È—íŒïö»Cǵ;Úg üš:6kGë¹r•³Â€ £-%24!µòR³L³û}]K_{ñÕÒ·¹³îü:moÝK?7»u@€@ Ô¹õ`;_ hdª ÈqtÞ¿oü³›åÛýs7K?Ç'`Ô„†­IÇøµüx?FŸ%È™õ¥Ö;e?Fçi^Rhu†U~öºÙëùzvÙj—ïë´]û;íóí¾ô²º9'{ìhǵ¯µ>C€šF i-^³ú¶{P¬Y0€@[Yçß#ôçN¿œzÿ¬ýZWÖº£ÏYçß÷µ½ mÔñJ¾L?´ù<Övío-c¬s:ï籄 @ xÅ3æ € ï}—#ëN·oË.³û²N¼ŽqG^ëÚçi4ç¸Ó¾NÛ½L–€ @ •@+>E€Ü šc <wÄÝñÖwˆ²;åÝ®«œì±YgÝ!h§Ôi_§íÊa; @È“@ž4)+w<,玔!P:9ÓJî”»s]f×õßzŽ;àÚîǶ:õÙŠöÝÑi_¯Û³×c€ Ô@Z©Á6vz o0ª\èËéìÒ×ÛíÏnË:ß~Ž–¾®c³Ç¸ÑÚî)»®m­Ÿý¸ÑövNö|Ö!@€’€» h<ÜÝ<×9ÈJ¾Ô=îë¾l·Í÷i©ý­Çè³R¶§Üi]¦Ú?Ç—ÚÞn½Ý¶ì±cí×±$@€ ê TßX0 ¬c1Êaì‚@n:4Ò‹­Buºó­Ï¾®í~fÉ:è¾ß·yyÙe§u?·ßýÙó²ei; € @ ™šÙ5ŽKmš*C%øLí^©ì}èë¾Ô1íÖÛmóòXB€ @  㫸(ׄ@·²NT·çp @€ œNàt&l ˆ@@ÑSÆךRM@€ ¦@hZ‹×¬¾5k°ÌEˆ © @€@[m±°1¡´v@€ @u'€P÷ŒÜ~€È8Àê`£` @€@.rÁH!E@(’.e·@h%Âg@€ X ÄÒ’× âÆ¥j€ @€@iJCÍ…ú%€Ð/9Îë‡ýPã@€ :@¨C+5ÜF€†ß%W dà\€ @ 4¥¡æB€@ Ô¡•°€ @ ýPãœR P*n.@€ DJ Ò†©Z1µføu! ü6ÂB@€ þ ôdzJ$€P"l.• p@€ ÄJ Ö–¨^5f ª‚PƒFÂD@€ ¾ ô…“Ê$€P&m®@€ ÄJ Ö–¨^5f ªB@  !@€ú"€Ð6N*“@™´¹÷ @€@¬bNÄÚ@Ô+I¸ @€ DãoF!,X°àp…7—.˜@Á€)þˆx>@€ ưçñ@ˆBxûÛß~ÜD™!€5à*!Ü8˜@€* `þ@ÜǺ䡱`= Ô³Ýêj5@][»!@€@1ˆ(†ë ¥î´Î“@˜í‚U€ @hóGöÆRÏ(†œjŒ±4 õ€ª#@@uì¹2 @”ÀóÚÕ³YѦÊlè¹öœP Š  M…‘Q4#•€ @¹˜u8¶ZE'ìß¿ÿo¬‘öÆÖPM¯œ²nR;§Ô·us>Ç´'PC¿¦–žÚmó}£-ý¼ì1¾-[¾ïGp,!@€@c |.ÆšG'üâ/þ¢Tš»bl¬&ש“6wþ)£ßs¹¶Ÿ›7¯KÑåûuZ—~ÝÖí½~örŠâÓ«=@€ PKÛgÍšõZZ>†ÑÑ §ê¥Z3F[F½» ‡ÎǨAf*WE}ýšy´g‘e¹QX… @Í#ð¹[o½õXŒÕŽRxøá‡°>Ækj²cžŽßh<Û]§Ý¶ÑÊèvŸ—›=¾Ý¶ìþÐ×Ý~-{I~^öœvÛ²û»]÷rzµ©Ûò9€ @ öôðúÿÖ¾*¥°zõê“ö€ÿ§êÌæËasÇ®†U+Üdg3ÃA ñk R†ÎÍÓF·©Ÿ2‰´%9€ Ô–Àß~îsŸ{¬¶Öax”€ê|òäÉ[mqdŒú³;bî]Ų®St=º)ßëÚSÝZ~eµ^£ŸÏyÔ­Ÿër @€@õ¬#è«·¢8 ¢>ðl3l]:J.“@Îb§2|{™õ)êZ^-My–%[B³i´ú0èÝÃù€ @ –Ö®X±â«µ´¼K££T{Àÿ?mq¢K8v¤;qýš^D™²eP»ú­O¨çµã<–­Î°Ÿs[Ëö²Z·ó€ @ÿ‡†“g>G·µðþ÷¿ÿIëÉûBt­ÖÐ åá6ݨÕvç8¾ý–åçjh;½œ^ëÒz]Àæ@€ GÎ?ÿüè}ǨÝö ÿ [D­âÄõ7XmZ9•æÛ)92¹~»s«¶É¯¯e·©Ÿs:•ÝOYýœÓéúl‡ @ˆ‡€ù¿{ï¿Z+zàæ›o^kõü\<·fskÒ‹£9%wÇ:.ÏýU\³Õ~·!O–­×(â³ÛÝKÙ~N¯uÕñDôBšc!@€@í |ÿ³Ÿýìmµ¯Eˆ^ƒãÇÿk[肇LÀ¹vŽo+Óü*®Yfý²×ê§®~Ž–Ý¦~ÎQÙ~^·×ÉžÓ‹}½”ϱ€ @µ `/;ù¿™¥Ý?´Ö¢Zíl„`oØhÕÿ/í°µ.ŠvÔúq"aç׫^Ý7ˆ-±Ÿë »­'Ý’â8@€ Poöœø§ý×ý£z×¢{ë!ÇôéÓÏWB©¦zuâz=¾¦X:šÝOýý-{I~^?çôr-¿N§sÆÚßɾ~ÏëTÛ!@€jA`׉'þ}-,ÍÉÈÆW_}õñãÇÿJNÜ(¦œ¾¢LéÕ)ìõø¢ì±\gÓ‹m~Ž–y¥"ÊÌË6Ê @(—€E}þæš5k¶•{Õj¯Ö@˜mBÀ;mñÅj‘sõ~ ´sÝ¡ë¦L?¶]9ÝœÛ1Σ—zù9!0,ʕÀڨ—{‹c!@€@ɾò—ù—Ÿ.ùš•_®Q€h;vì×l±«ròP¢œÂ~-Þ2®ÑmýûµÅÏët±ö·;ÏÏÑ’@€ ÝÖáÓÈèðÆ 6!àkøßÊ4>«5!P„#׫“Øëñ½¢-ºü^ì É–±ìv[Ç:.»ßÏѲ5ÅÐZ'>C€ ¼DÀžõ~Õzÿ74‘Gã5² øskôÏ5±Áë\gwÔFsÜÚÕÏo·¯ Û¼þίÊ:eËXûûµÝËí÷|΃ @ˆ†ÀŸ™óÿÙhjÓcE)ˆÑ‘#GòñL¼8¼Be9°½:‹½_!Â\/íõ.«]d|Q×l-—€\o ƒ @A°g¾‡gΜùσ0¦"#+ØP€ÿŸ½7¾ä¸ïû° ,ö¾ïÅI\$€¡ˆd(3!(ÛJ‚8,‚HÖaÓQ%)ÙQÅ.GŽ –”Ä.ljÙ¥Ž** ‚”J¢DH‰å’TU Q$ EÀâZ,öÀîbX, Ìw°¿Eïì¼7W÷LOϧ«æßófºýëOÏÿ½þýú˜—Þxãʸ¿6{ŠõHÀ 8"'#ÊØ)öªäVÝo£K•̪ûmÊ$ @€À(Íì¿|âŸ86 m)9Y€xÞ~ûí–E?ˆ-b=0ã͇ئ²š¦_¤cY–WqŸÁÊ¢Ìyu5æÝo««oymõ  @€€7Yï¯~âþûïÿº7‰#4i€ÚìÖ[oý—YÄ~#x€›fJß$OÓô1"³:4©·zX¹ódUÝŸ—¯Ëu+³o]t&/ @€@÷|êSŸútÉ#:y€Ú+Ûà'²è?ެíP7#`F^–¶ƒÐʪ£WŸiL¯>4©—é5/OÕýyù]7™óX°À"z܃ @£!ð™lÓ¿Ÿ¶ÅÎö8¾dÉ’g§ûóF|ó µ2‘MÒ–å¯sÍ È:iÇ’ÆêÔ?ŸLLïy2ëÞ[½çÕ—ë€ @9/ž8qâG²³~×ÏF À©Æùà?øäË/¿ü'Ož|#âöš¼jUZ•¡× Éª*³‰Ì±§­bÒõ~h>Uú¹å3À¥Á9 @¿Ì6ý»õ8>:Í*¼$ ì±‰>çµ×^û—¸ö²Ë.›{î[¾3,VÅì¼7½7öôVÿ²z”]ëšþ¼óÎ;;L¾®Y°²,¶ëŠ] q¯¬ÌEå(ýUuîz_\«‚•‘- šdTñá> @ˆ@ÖŸ{63þo¸ï¾ûž‰]×¾õ{ËÊí»äÈÊ»å–[þY¦ÒO=õÔìÿø#ÓuªÈh3í˜vѽbÚŸ}ëá[^Ⱥ!Ûø(nÊ4mä€ @ ?êûeý¸=\pÁóý•:ž’˜µUö&€›²è³ã5ÝþýûÍvìØ‘ÇfX¬‹v^Œ›Þ{z«Y=Ê®uM¿téÒÒÙ*K¡Lþ›wßsóº2ŠyÛÞ39uËqÓ·=¯2|S¿_Å­ªþÙz±¹N¥*Ù܇ @蟀úwÇ—M°++}÷Æ?óÄO°ÄÛiŠÉϸ馛.Φ‡üjÆä =ôÐìË_þ²ƒŠÓTm¡uTùv˲ëCëXÔ‹ÏÕÊÚ®ÌÙS-‰€ @Cñÿúë¯Ï^yå•YfãݲsçÎ¥K¬åNzÀÇ>ö±óŽ;ö¹¬£eY=ûì³³ìí³íÛ·ç·]ƒÀ΋±¯Ùç²{eׯ”¾o]‹3ÄOÁô°øÍ«oþµk—ÝÓµâ}÷³{nùíšÅvÝ•Õöž+‹óah@öÃ1Lá” @€ Ј@¶¡{nü[&9²ýî߽{÷«?ü0k¼O9cÔÛ`M%~î¹çþEV×ï]Tß/}éK³¯}ík‹’p¯GŒ®÷»AQ6‚>/Kì÷]½M×2盎s@€ á ¨ïvôèÑ3Œi¥m꜅ÿùî»ïþ¨N…iïS’mú÷ײþOUÕYÔ¾ð…Yæ5ªJÊý¨=ý0£¸ÿ’ý–hõà9òËi€ @`êÓe3ºçÎÚÌÞò&ÇÀ9Yº_ºóÎ;ß=„ޱ•9Éßÿýß¿2kˆ_ÎŽZõ׃%'À¿øÅØÚorúTnºoGŽ]Ÿ'Ãîóý³Õ«ªÞóî÷Yÿ®ºVåwGõ«ÒöYïe¹u !™€ @`Há/Nû/ÓGûdayv|öŽ;îØ\–fJ×jÀ©É^ ñ¿fuº¼i½´) ¯lJÍú! 7+³¬6‹î•¥·k–Oñ¢P•®êþ"Ù¾ïUéRuß§>]Ë€öÙÈ‚ @þ˜ñ_g¿&õ O9ve{Ü—9&½Þä·ÝvÛ Ù£÷÷Ú>~ÚàÿðçN3i+—|õèxL¡«[]cªO]|ÊŠ­ÍЀ ¤DàäÉ“ùÈ¿úouƒòèÈÂ÷eN€R7_Šé&åý¸á†–žþù¿‘5ä¶.ùâ‹/Î^xá…Ù%—\2Ó®ô îh¡c7Ý+»¶è^léûÖUås—…ÎÊôyóNù=7}1Ý¢{Å²ŠŸåmzÏôê#nòEÚUŸª²ªî»åW¥­ºïʲsí«ƒ@€ ­éךÿ6A³dGd}ñÿüÚk¯ýãl`÷;mäŒ=Ϥf¬Y³F›þíöÑh{öì™ýÆoüF¾ã¤yȆ€ C;†Ñ ÝRkã{H*¦÷:P6 @€À™^yå•ÖÆ¿$É BdÿJ¶)àz}˜Z˜ŒছnÒ¨ÿÿè³80ûìg?;ÓŒB?ŠÆdHcÍdË´šÚ}û<†ØtžW§&uð)«ª\+«nºyõ39óîWÉç> @€@ÿ´Ùß©Wúu*üĉ¹# ›°3ô¯: iæÉ8²éÿSÖFk}·“FÍøÎw&9ƒÄ7N¯òÌØó*´¦°¡Ê¶r}¸>eUa³²ê¦ë£~eK5ªôã> @€€?ZŽyäÈ[¿ïE°œ§Âe³þ–}˜J< Àí·ß~eÖ ?ªQ5•äÁœýéŸþi¨"{Š€ÃO¢êœ€÷C .oKç£}ÊòC)€ @u ÈÆ:zô¨÷Í×µ óö€_øñÿñÕuuJ!Ý$Y#ÿlÖXoîÖ¨ÕdlüùŸÿùì·û·gŽW)PiÓÚ°3ù¡(w‘oyw &««å÷)«®>V¦O>dÕÕŸt€ @å´Þ_3­Cg9Áެ¬ªœå&ïøà?xm6•÷޾à?ù䓳Ï|æ3³ƒöUä¤Ê©2Ð|…e`CË/+3†kV﮺˜ÅU¡IÚº²ªÒq€ @`8êÿiÔ_€Á}ÛSVæß¿ë®»® Y^L²“w,Y²äÈ€÷ZOmxÿý÷Ï}ôјÚzòºT”v?P©ÕgQ»ø¬«Éb€EĹ@€üДßëýièÌÚ^š- øß¥MéÞ’”*S¬ËÍ7ß¼3ëÄÿ»ìz¯é¡u%Úððáó‹.ºh–9"rǫ̃°Xí¼—Ý+»fùÊî•]ó™Þ§¬ººžz§’Ÿf—(|6Ý,¶4ŠíšÅU÷ê¦39–Þb·Ìb÷ž›ÞÒ…Žeðú Md…J»¨.MÊÔÿ°Öˆ @€ÂPÿL#þÇÏ—•†+éLÉ*×±+.»îºë¾øµ¯}í/ÏL•Þ§Þ ã>fÆÔ“•tíU}{ì±Ù§?ýi–T x_ÿÜM ¿2U|È(“[¼fåtÕ·(××ç&ú5I;ý|Õ9€ @ pÑ”gM~¯ÕÒ¬'ü|v~Žó9ÉÓdg|èCZ‘ºß—! Ýròfi9Àºuëf7nÌÕqGzí¼+ak–fˆôC”íxêNóÉ¡:¼\uî¹é­N[~7{¾({Ï=wóÏõ¹NˆÕIPG÷bšºu©›®(¿ês™\fTQã> @hO@F¿6úSŸk¨ ²Ï?ÿ|+~ û{â@IDATÇîÝ»¿üðÃ?nRŒSžðYƒ®¥Ñ´ÑÄúõëÝi&±¨6:=\cMçîg·2‹î¹éú:J+w§¶õ%·­>Å|®~v^LSöÙÒ6ei¹@€ ÐŒ€Œn­õ?vìØÜ~|3‰ÝR»K>³~àÏfÒ’ž¬`Ù²eWøXŽk¯½v¶sçÎÙ¹çž;;ï¼óιîöØN3· µ‚Œ1èÒU«‹o¶&·J?KW§ü&i«Êå> @€@x—_~ùìÒK/ip4;ÍudvßyçßžÄp% º>>Tµo¿ýö-™qð×dlÇ´à÷~ï÷ž¡Š¦±Ë€)svἆš•`¶cÖ_üo3…~op¥)¤ aÿ‘Ì«”µa€ïú®ïšé¡/ŸrèÃ0)Òi÷Ùå¸È¸o'}Z¹\–U5¯›¶n:•×&m› @€@;ê¿ãï˜}Ï÷|On÷HÊòåËg×_ýìK_úR;¡rú7Ý}÷ÝWÝ{ï½Iî¤à‚ .ø;ò,Å4úÿ®w½k®*ú§P=trª þA«3 ˜ÂÕu‘CÂÒ¹iìZ•úuÓIN“´Uår?n´uÜíƒv€ Ô hóó÷½ï}³M›6UU9¾úկΠ»ðŸ•n  çdƒÉÿUVö?¨ü ÅÆ1D·ÜrËêì=’WÊŠá¸êª«f+W®¬¬¡t•#À5+3‘à4;U¥©›î´ð9'&oÎíI^6&UŒ§mZËWØÒµÕ…ÿÅ*Â܇ @gЮúïyÏ{f·Þzk©ñ¯Ù~mùÌ€ìµ9}¾»n¸á†$Ë“«Ô–-[nÏÞ%ÍÎï|ç;Ïþ¯XpÅ–-0`>¤:ÝüÜÜ1M86IkòcŠ›èß$mLuD@€ 04 /¼0_ë_gTvÒ#e5i2+·Iž&ic•_W¯ºéš0!- @˜*Må×H¾6úkÓ‡–½ôÜsÏEƒO¯'tÂíwÜqÇÇxàεџ&5à§ú§7½øâ‹+cpèà²Ë.óò€´ùgòRpÄBÌ[ĦNšˆ«Ø›jÆ)dmÊh“§IBËo¢ i!@€À˜ÈÞºâŠ+fßýÝßïêßVwÙK_øÂfû­¸Îù z¬ÉÞØöÞLèv‘€¤ëÖ­»+s´ò>ùnMÿ_±b…o±¹<.‹ ß …F$Ô§áæÊZÄÔÒ-JÓ‘ÉT¾ErÝtMË™¾^mò4©C[ùmó5Ñ´€ @ šæÿîw¿{¶~ýúÎÕц۷of€…½ØþfVI[:€“'OÞÃ迪§õ,„þ ¸†\£zQšþµ÷[¢Ë¯äþ¥µ©K›OÆpÏ=÷œ{üøñM1<<úÇØ°aCðç MSQ™!þ!ƒW¢EVo7«]óÉÀdªŸr]½›ž»:5Í2}¬zYc×Ïô$† @±ÈÞ®6»æškò#¤¥¥Z P0¼cÁù–\Ÿ)ó±(ÔUdW_}õåög¶$äÃYv¶Á,Û0¢nòÎédÜ葪úÇb¬v®˜g®8$#Ó£/¬¼¦8Ûäk“GzµÉ×&[Vü}µQÓ¶©“^º×©cY¤ @`:´³ÿµ×^;{ûÛßÞ‹M£>‹–ìÛ·/VÈ8bl™ìÁyç+¯¼…ñëcCŒ6ŒÕÙ×Εú'êÓÑF×®yTW×Àѹ¯`FS]™MÓûÒ3v9Æ¥‰žmòH~Û|¦[×ü&‡€ Œ•€ ýz¥ŸFäû k×®i3÷¡ƒ–¸6Æ)}äH&ô7LÙ«¯¾úŸ¨ˆf¬\¹2pm‹—1óÚk¯å,ô§TÏ:FºwuҦʪk½ŒaW9¡óWéYu_úÕIºȇ @}ÐTÿ«®ºjÃßê¸zõê(ì8éSâØmz¦'ãÈÖÁ_ƒñ¯‡bh€=˜Ú@‡¸˜7Ëî=–‘VeЛ!W•®/¾õ1yMôo“§‰üyiÛ”Û&[þÐù]]8‡ @±X¾|ynôkÔèACÙO±Ør%¶Ã%±µ]}RrìŠå¡Ñô™˜‚9ôš#À'g3KþéK‹iš¾TÈÈ.ZûV»k¹]ó÷]_ʃ @¡hWMó×®þCþVG-9ˆÅ–“ZV턵wÝuךO~ò“‡k£=MƵÀöXšX×ßëAÖ¡ôóÎ;o´­—AWf¨»†^ÙýQWÚ³ò.+Ï¢çŠëZfßùy†æ6%7 @3ü5Ý?»ÉÊ6‰E§²þ_6 za¦ë#¦ï˜ãd™a°¹¬±†hœXdÔÕ·,]×ò»æ/Ó‰k€ @`H[¶l™]sÍ5³]»vÕê·©«í[6¤e¯ª¸?šÛIÌøüç?¿lÿþý™ýznà kF¢Ði‘6#@ü4ý&Ö% eu0íŽ1îæoš¯iz·,Ϋ _‹«s”§èš_R}È(׎«€ @ ,õç/¾øâ|Ä_#ÿc 19Êú‚×caY¥g€ì€ËeÆâШúƒþñ2–ù+åèûýŸ¡™¹ÿÌM¡uó%ß­c™Cço£ó¼<)Õe^¹@€D@;ú_qų«¯¾zÛ†äuZHöS,¶\™¾Y¿@˜¡®e_@ÓØcyh^yå•¡Px)WŽ€'NäŽÍˆñKDÆŽ†¼k@6-Çò¶Íç¥!G.Äú¨†OY>ôA @ðA`ãÆ¹ÑÉ%—Dc µ©—ì§Xl9ÙBÅõéq¡ ù9›Â~®:ʬoÝÆî0^2šÌ`3ÄxlÁŒ¿¦ÆøØêé[_ãÖVn×ün¹¾dù’ãêëù”êk  @ õiwìØ‘Oóß¼ysˆ"z—yüøñ {M*T¶œ;³1ãXkÞ¤"sÒ&±@uÓ?‚¦¬Ë`:¼üòËC«àµ|Ù,‹Ó34+@u ø6F}È«#§QÝ& @¡ \pÁ³Ë/¿|vå•WÎV¬Hf@:Ç&û)†ZŠP§º­CÊOÆ Hú§ˆaýý±cÇfòq´¼êa3G€þAåpÑò€!Œ¤:ÿ˜–¦©~]ó‰aÓ2«¸·¹oõh“·˜Ç—¬®rÜüîyQߦŸ}ÊjZ6é!@€À<êSnÛ¶-7ü/¼ðÂ(Œäyº¶½®~X,€f“·åX7_R¤1xŽ_ñš5kê¶ÃèÒéŸCK´i –Èì׋Á¯Û°¦·«³]«+cQ:_²|É‘®±Ëò©ß¢¶á @(Ц~—^zi¾±ßªUɼ®XÍü³OÕïŠÁŽ+›þ_ªôˆ/&åÐ?ÊáÇ£hŽƒ&í0ÈúgµYšñ 'Œfb¸†¬¥ ›±Ö¥Ü¶2Úæ ÉÕmú¹×R=wëêž§Z_ê@€@:Ôݺuknôk´¿K¿vLTd7Å`ü‹Y ËÉC·]r€XþQô ëœS ò˜iÍ °å¡f˜qgqÛv·üj§¶2ÆÔÆn}»êB–O™nýBÉuËà€ ´! õü²´¶åÊ•mDŒ:ì¦XúášÝœzHÊ ‘çX¼GGŽ9½i^êQ±~2¶ôÏã.bV@Q/ߟͨŒå ËwýšÈ3MòT¥ !Se†’[UŸ¾ï빜J]ûfKy€ ®ô;­Ñ~mê7¥Ñþ"7-+Ö îXl8 f¦’rèÁ‘¡ËÔýû÷ç›v¤þ-ªŸ6eÔ¡µ=Ú'@íãkV€Œ›¶Æ·Fmó/ªsÝ{¦ƒÒ/ÒÃMWWvt!䆩º„Bfî¤ @`ºôÚ¾‹.ºhvÉ%—ä}ãé’x³æ²—Ô'‹Á eÍ1l(ú™HÊ XÚ –†{ñÅ'ï°XÿØZ C{È ¶êóM ®Á·Èà6Ëb2Êä¦zÍå壎®<÷¼®ìyyÜëvnq]Ù¤ƒ @e4­_Sü/»ì²ÙêÕ«Ë’LöÚ¾}û¢0þÕSýW=“sèL;ðÇŽ=š?H2t oÐ^š CoŸË7Ìkkô¿¥ùðgVŸš„)ý\¹î¹OÝMVhùV1 @¨C@ƒ]šÚ¯‘þM›6-œíYG^Ši´\8¦éÿ±l&º­“sȘÔ’X ‚çŸ>…G膫|ÍÖÐ~ r–hã@sÔ© 6]HqÑÀ·g x½ŽìbšXeõìúÙêÙUμüc—?¯^\‡ @šÙºcÇŽÜèß¾}ûé~*dÊ ÈNòÑO/—Þìªú¨²I¦’sÈÔhr,;88p ÷þi¤›0Ÿ€þélã@kC9ä=”G‡(˜ai}™Ø1/Õu“©t±|9¹:»ú¹×ÇrZÿ2ùe×ÆÂ =!@ˆ€úˆ[¶lÉ~øÓç¯×FÈÓúë»×Ë.•¦ÿk€)„$­R½J#¦”wk×®]Sxž¼ÔQF½-ІrèÈPgó@3ð›ÑnŽ‹¥¤Ýó¢pM!¦Ûe×TñŒd¦ï}°²,ö]L™\÷š{î»läA€ õådô«/£Ñ€UZ5÷W›^x!šÍÿT«C‡ù«\ä’’uÄ4…CÞ-}IhŠ;¡9rt¨=Ýýš~ÑšWŒåut r[÷z3­ûMmú†,Õʰ8dY&»Ï²¬LÅC•ëêÀ9 @qPŸQ;økŠ¿vñסþÇ´ùŸj¡ÍÛ§’thýFŒcY ‡I^.ftû·²ýÌ /^Íöhê pµ±gŸüîT$»ææirn²•§«¬&åö‘Ö­[èòú,Ëê2D™V61 @ÃM±uëÖ¼¿sçÎZ³Q‡×:~ bý×^dzSÙTB’5ž'Nœˆ¦µÀÆs½¢QjÄŠÈ V63@ÎÞX×ð³sï®ïž—ató•ÝuÍÊ %žÜ¾ÊuË™w>OÇ©]wùL­îÔ€ Ж€ú•6½_ƒw¬éoK²<Ÿh5Ú^Õ—.ÏæªS É:dÊ8Œ©üÜsÏåïÿœÒÖG]‹3äüÑë }8\ýÝgIçöÅåsÆ€[ÞÏ]FCèï–ïžwÑEíìKV=È @€@Z¦»mÛ¶|=¿b·o¦ÄéJ•=¤¾•õ£‡&¡½Ç¦4ý_¼“uè¡Òˆ°vtŒ%hj‰6˜X·n],*%§‡ë Цzl™@¨/×8´ó~8L—¡yèòÝz›.»÷8‡ @`zV­Z•¯ç×ëú´¶?T?qzdç×øðáÃùFß1ô“MKmÖÓæñ¦WÈ8Y€ Å¶€tÚ»won²! h„ úg~饗òC_4zä Ðì­é æšCü¸¸º¸ç!ë_”måZ\¼?ÄgW÷|](€ °ÔÛ°aÃL¿6ò[³fMØ‘~ ÒÉŠÉøWÿïÙgŸ=CÏ)|HÚ LÄÅ´€*yšôÊ!ŒÁ)<ÔeuÔôž—_~9?4ÍGÏ…:útÆÌ34‡xæéRÆ/ĵbùú\¼¢Ü*™¦ƒÅUé¹@€@œÔßÓ”~ýŠYÏ?\;ÉþQ|ˆ>ï¼Zû#à²ö'I€ îÔ'×ÚýM›6åF¿ú¿¾ûݵDB‡Žvs=ÍHøö·¿Ý¦ZIå™”@_,z¨ µƒí¹zõêÕC§äd²Í•Íš! cÅŠ£ø¡3#ÒCü@»ò ³]³ÏÄ€ Œ“€úßÕ×´~þíW߈—_~9ßñ?ÖZ=öØcQîIÐ7¯I9WSŒl&@ß°ë”g›ÍiÔ˜y[. §ÀX~Í0·X­¤óŽ{¬,‹­Ì.÷-/1 @~ h棌|û2úá÷Ë7FiZÒ¬Y°n_-&=µ×óÏ?“Jƒé29€Hk'wíÀãRé§Tk dÒ$PæЬµ¹f€(iP‡ ª/|÷K_ç1ס¨«1±ëÛub@€Ê ¨cƾÖð«¯M˜ÿ²_bí;iÏ®Gyd: RQÓI:ÄDžI=¬±yÐpÄÚB~õ’CàèÑ£ù!碌d@³tŒe†€KÆ~ŠñPŽ•kº¸z¦x>¥º¦Ø~Ô €@¬Ôш¾ ~;´Ñ6aš4í?摵Ê׿þõ|ãîi¶ÐÙµž¬@Kôe%P¬AËdj#9´gȘÓú9yØÍ! Ïc 2Â]C\ç}8Ü2Çʽ!@}°õû6¥_Æÿ’%KúT²"% Á+´ŒTÅÙ³Ï>ËÔÿBãLÖ š ¥:b 2VôÍ“'OæÖuD§~èYÐÎ¥:´Y¤‚ÍS@SíÆ:KÀªŽ®nç}8Lb@€À” Ȱ×À“6ì³Ñý18L¹-C×]»ýËN‰9hv‚Fÿ g˜´@†…Œ'y¯ÌØ8OŸ^zé¥|&€^•B€€(ÎÐuÍj1‡€Å–~¬±ëpÿOuŽs`¬­ŠÞ€ 04ý†jð@#ú6¥_Æ?¿­C·LÜå«ÿ¥Á(9bê'å+_a×ÿ’Fš´@<4ŠªÑÓ˜÷žz¥œf*hc¾˜E„PF@KZt:t(¿-O¾žoshÖKJÓöÌ!PŒUy»æž»×r@5þ´ÉSC,I @½P@†¾F÷íH©OÐ+̉¦>‘¦ükd=öðè£æöSìz¡ßä‚®×jzÓ«¯¾:DÔ.SN ­cÙºukþ:ÃÚI8YrÙæ‚Aû_È) gÞb]›Zp û²s÷ÚÙŒ]ÿ12Gg@±Ðo¼Œ}èÛ?Sùciqê¡>¥6ªŽyÿ4#»gÏžÙ3Ï n à‹€ì£½{÷F»oš[O-O`Ý¿Käìs­ƒ’a­©-Úl-Ö ÜsÏ=—o΢/zºS 8S@Óµ§€œæ CÑ•4ù!@íhÙª–ôÙ¨¾bLãoÇ“\õ¨¨7“afáñãÇóuÿcеý0©p8\µY„œK/½4Õ4F±y¸ä‘Û¼y3ûÄÚH#ÖKŽ&ý?è° N†9Ë!0&§€FJ¦ò£0¥ºÚóI @ úÕˆþêÕ«OcÛO*m3•z¨¿¤]þÝ£1×ýµ×^›=ôÐC£X¢04G…Ñ#/—ÖÙkƒ¿ð ù.ü…¤Q|Ô&Z }ÇdˆE%Ðÿ‡ö¢p7Í”¡iŽÅê´hæ@Œ#S1þ7, @`Zn§Q}÷6_£úú-%@`(•ýûÒhã£þé_üÅ_œÑ?µ{ÄgÀp6“|Ô_/¬kI€ÖRéŸ@#î1òxi£ ½¯U?ôI@ÿrB7…ÑTE9ä pºN€ L‰€~ûdÔËÐW_MƾÎuÈ‘N€@,4È£åК=† ~èW¿úÕÙÁƒÇ n:â˜Ó òxÉà—Q-ãeçιC@Ž=`±9¤œš®-ÇFÖœ†åroôáÿ£¢÷X£r (6ÇöÖ,@ È˜×ÆÒ6¢o±Fùé›èÎdKÈö9|øpgY} Î<òHî°è«ÌÊÁ° åÓ4fÛhOFË®]»òY6#`AöAnIgÍ€· ÒZA@ÓÊÊöÖ@ÿor ¸çt˜*€Î¹›“rŽš\† 0Jú½’Q/cß ~Ñq Ü(!£to4X£QÍ*Sxì±Çò·£IçtÅPÑ ÚøB‰¾ä-˜#@F¶Í°{1Ä2®ô–m£ P1´ :T0Ç@qÆ€ž_u¦äpžë*¢Ü‡ ®ÔçÓt} ª˜oFWÙä‡@ ^zé¥(g7/b£AŽo|ã³={ö,Jƽ9pÌã^>tèPnxèGÀ ZËuá…æ£íz7¦þb r^èu†rT°™LL-ƒ.Mh)Ž¢WZÓ,m¦€Åæ,`=e¤… 0mú ±Q|ÕW,ƒŸß“i?)×^{7iÔ¿¸‡Sìu6ãÿÉ'ŸŒ]ÕhõÃP£iô émÛ¶m+M—Wøâ‹/ÎÿlF@,Óoe4i6€6œÑf†üÕhp’Œ‚€þÇô|R^Ϲf èSÀú<•ÿÕ3–ï¡Q¶Qµ›úv_ÿú×ó½Î¦ÞŽ]ë A½cRSý·oß>Óù¼ G€Þ°uëÖ|æ€fÄð* › ÀÞóZŽëS `βºªYtèš{”åã „' =™ÔDzÑ{רg©cxþ”0^²Cô3-V?hlAúëU`%t'€ !C*š@ç‹þ‰4ÝL34ê.o›‹ Ui\ÿüš   µ± x“€þŸõ?:ïÿÔr((¶k¿)iø¿‹¾›†× œI@ß§ê7ÉÀ—1oF¾Œ~ÙgÿLf|‚@êóË‘Ý2Æ ½eü«?p´àh#é;vìÈ×Wu´õƒ¦ÙZ õ6Ú' ¸Óy 5:e‘#/šœrPè–,& ÿu‹fô˜#À%Õ>/.»€Ò$`ƽà˨׹}–ÁO€üá¬ÁÇãÇûÚ³$-Ux衇fGí¹ä´‹Ãв}‹N€E!@ñé8|øpîWnÈ µ@ÚHÃ6 ´‘Í!u¢lŒ™€9 æÕAß »çîµßPÞí¦»jê³:$GÓtôO[×0è¨úYÙõe¡7È Y ìp".@ wö}`±)àv¸í¼˜ÆÒ*^tÏMÇ9 .}WȨ7Ã^Æ»}.ŽâëMó—Ѭɱ‡={ö̾ñoÐo Ø8<ÀÕ?œÚðONóMƒÖ¾íÚµ+—!#|ÈbÍd°ý´Q ¼ý@ ~êÜ›3 L[9\G€-]²ëî=÷¼L× 8¨ßa#ñÚ$O‡ó:w}]'@éОb²ÚرQP¿ã±Çã5=4 OåÐæ~ÚìOï›Õ?¢u®›¡jm¸yóæ|$^†øPû¨Ï>ûl^Ÿ7æˆ&u!- ¢ƒ`Ñš\×)P}oî¡/m,"g„m`¨ €€K`Ѭ7]Ù¹9Êbs ¸÷Š×ÜÏeò¹2úÍÖs«Ø5Ê›^Ó¨¼d ø& ß7ý Ôy A¿çO=õÔì[ßúV2uK»àÐR6GË´ÞN  ëAï$kûöíù>úЬä}}é˜çQŽÍPèÒáïSwÊ‚â& ãÉ—e$×a`ßÁºç^}.^/¦we*¥×9Á=îïŠ}.Æ*Q¿¯îu;W~3àí\éíÜb¥'@ˆ•€~gdô«ßo¿A±êÚD/mVøõ¯=ßs¬I>Òú!€Àdz¤È0×+åPE£ørø¹W‡Å–H¦fÈ(ïó‹Ae©L})­^½z¶nݺ¼žgà ÈÀë3˜CÁÊt¿›ž›Œ¢L»n±9-ì³Åæ¸p?Û5ý~”½î}—]7YŠ•_iŠ÷Üëvné­Lå³sÅvî^wËâ€À èwC3oûîß÷ÁZo<{ä‘Gf]gH÷¡kªeàزZ;oNur´9 <^>wêÔ2½=@3ô¥Y}®¡QP^I}Iáø0!ˆš€kÌJQ׈ŽZq”ƒ hh PýêÔFüX6Ãw¾óÙOšÏh°kÄÃÀÐ{=ôÏ?ÿ|¾v_£D2Öe$k&@ˆÑzÛ¤O³ 4+@Î÷äÔpgh©‚6F"@€ @oÐÛÂlÄ?EÃ_uÒ+Åÿò/ÿÒË2è·ÈqÖ…–Yz òÊØ7'€M ½à‚ fçw^¾7€ÏÙ¦–dëm:42/G€¼‹}› YZ¦ §„b @€¦L@€ê“kϰ µ­ê¨þdâ"€ Çöà¹çžËgh€BèÙV=Í8ÐÑ÷¬}©i„ŽeË–å›j/ÛøÉô#† @€@ÊdðËðO}< z~ãߘi†!>8znyÃôO¡Mûl&€Œaއœ `Õ´Y›7oΧÉ+§Ù}}Ù½ð ¹ÓCjV€9Bú(Ÿ2 @€ Ð'Íò5ÿ¯%¹}ÖÏ-K}}þûöís/s4ˆœZ³mÛ¶3ÖÇk­¼ cýóø|S@Yåt°W Ú¬€Ù“ X¾6:±WjV‚Ú‘@€ ¤¼£Yû°Ö¿ŒJœ×p Ô.š£å[·nͧƻjØÞš6¯/ÐÁfØ^Ú8PÓ“BìKàÖEË´G€f °O€K†s@€ 1Ð ž6öÓ¨ÿ‚úñ?þx^ç)Ô7…:â°eÜk9€œ2úÝ ©ñš  Ùrôl¯€;väN-Ð[ BwŸ9#To¶D"dÙȆ @€@4“!¬-õݧdÇ<ñij={ö$»‘aªíˆ`à–ÕÆÞ½{g›6mš­\¹ò,m45Þöèó Eˆ 6ä‡<™š²/g@è ZŽ ¥š… Íåàíg=\€ @˜€–íÚlÖTwó/C,›@kýC/Y.+›kÝ àèΰ³}a¼øâ‹¹œ2'€ÖëëºvÑïkY€[)ÍNÐ~Z" )M2Îõe2ˆ‰¦Né°YšÀ¦!©#€ @`ÛÔO}â>çéÔ×=Í þæ7¿™ÖMÉáÑß¾ÊÁÐéŠrÌ  ½Ö­[WšÚ6 Ô—þûþÇÓ”|é¦CzjV€œ¡—¸³äѬ€â’‰R`\„ @€€íÖ˜ãBï“åA]¯"Ôïê©§˜îï•êpÂp Ǿ´dÕúRY¿~ýL#ÿÅ kš  ¥ú"jêœZ¶ C:HoMÝ×D¨ ‡‡ÖWé°YìŠ6r!@€À´ ¨O®~§FûS…_YK«ïýÌ3ÏÌž|òÉIÖ¿ŒI ×pDØŠò.ê gãÆ¥N©,G€ÖÈk$\#ðZƒ4T°%ÚÌÐ]"r†‚Í ÓA{hy€f”9M†âB¹€ @ã" þ«úÖZ†:ÅÑ~k-õ±¿õ­oMæmVï)Ä8"me}éhý͛7/Ü _ÓòeøÊ×—ÔÞIßk×®Í[" ™Ò+dЗ´í£ rˆ΀ԑ @€Ò! Á4ö[<š5«‰"eøë•à„4 àˆ¸]5µ^¯ Ôæ{šò¾(ØkexÇðÅå.О¶_@È™ îñ0g€–L @€ à°~³f°†\Æê–ë¹úèOd¯õÓÛÉBÎâµþSÒ @ä­­/#94@£ÚUAŽmÒ§âX¦-i¿91tôµ_€fOèË\‡íÀ[ªžîC€ ´ h™­úÈí× Ò©Ù{öìaƒ¿ =8FÐØú¢Ú·oßlÆ ù¨v•Ýõå‹'Ïö Ðk5SAo°ëÔ«Mw¿í› G€b–´¡I@€ 0.êK«?lF,ýâ!)j°ìÙgŸÍ 9`2dkô[6€~y·.Mÿ”û÷ïϧ'i} WäéÐÈ»¼1ýskоŽ;vœÞÕO‡9äЗ{È Ï±œ!)#€ ´# ~«üÀ‰m@«]­üær Í&@Àà0#Œõý /äËdÐ7 6#À]£#@õrZ¯¤Ýýµ ¾ôC× ‡‰8ëÐk € @ý+£ßfmbô—s'ö?÷Üs“µa9!®bÅŒüЗßòòº›«ìÎЗª¾\cuHwÍx°™2еD@34+"d°Í æ…@€ à€ú¸öZkõÁذn1[ñ‘ѯýñ_Ìjêwq$òhà àè“và²dôjI€œš2ß%,[¶,7jeäê‹%´AÝEWË+#\ÇÖ­[s}µL@Ž‘Ð{èÇIeX9bgÎ @€Ê h´ÚŒ~ÅLí/çT¼ª>®^å§%±0+Òáó"8Ñá=}‰Ú¾2B»Mu×±jÕªÓë®Æð%c΀-[¶ä#õrh´ÞŒô®\å×ì Zš ½Ì X³,€ @`Ê4°¤~Åê3êP\¯¯ÖñCŸ¼^ÍHÕ'}Òî©,}h_€Õ«WÏÖ¬Yã¥TMk—<òÎÊË´,wÏýÈØ2Õ#tCFZZša³ä `v@húȇ @ 6ʯ¾—¦ª7k-ÉÕMõ}yn³š‘z8† ÞS™2:5…Æ ù:uźûÈk+GÀ˜¾ˆdtkV€;3@³TÐ^TýØÙŸÚÂÝ;@³x³€'€  M@ƒDê'Z¿GBså—á¯Ù½8Mšó#G9å\’¹ªo[à{ÄY£Ø2\åd­/ú1wf€~¨l™€'¡âTÜ;@û6ˆ§,ÓÓ„®€ éP¿Iƾú‚:˜ÖßþYK­ë×h¿–“öÑ'm¯-9ÇHÀ[­¡Îòj½–h ¿ï`ûØ÷˜– Ư_¿>?T£GæKäèk©ƒfRèP™ rؘ“E1k-b@€†& Q}PÛZ~ Õn-¢µ}ûöå†?”n,ɽ˜€Å|’º«‘m˜2tÛ¾*pÉ\¹re~ŒuV€ê§zÈY¢c(g€ôЗ¿{Õ š g€f à% @}PßÎFøYÇœ&åß»wo¾—©HÀb8óI¸å]”@#÷!‚ S«:d@Ë3<ÆYbã:ôY?x¡×—uŸÞYÍB0/»ôc9l–3D…@€€/2øÕ×±uüêÓü°Ñ~þ}ö'ýh”±À0öl¡¿ŒÉýû÷ç#ܱd@ë‚:lV€~HÆl}þÖ­[s/¸œ:dœ÷ä1¶d•ë:]l–3úlÊ‚ Œ›€ Q,Rƒß{jV§ö³dÂ?_$Ö#€ §äRéKG_Bú¢_·n··Ìå¨úAÑŒ€±Î °:jÔ]‡Þ(`¯û“3@K-úþÑT{Ú´<µ«ñ–3Àf à°–#† L›€ú)fì›áßwße*- 0mÈ­CçþSiùxë‰ Þ¶éE3}ékI€œ2fûš Íuè‹Ð¦¶ù Q¯ðs7Tä 1>Äk]‡€µ©9,ÖÆ‡@€Ò' ÙŸ(0c_ñ˜û]±·˜œ)È7áV_Ö±·Ø´ôÃ0­ö.­­¾¤ôº-ÐÆw}¥–A*„~ŒÌЗ!Êq—=ìØ±#Ÿé YrèÇw¨`?úV¾b¯½ l6³Œ1 @`¼4À¢ß}3ú‡Œ/½öšë-RXÓÛ·úz‹T{mÉ9U8¦Úò%õÖ”|ý@ô±$ X¼ O¡š²®‘t­=“>úñ{°7#lÛ¶mð¥.ËâÆ‚º§· ˜3À^ïèæá€ ¸è÷Ü5öuΈsm¤>«öÖ’ÑoýVø÷ÇŸ’šÀМYÒ9äИf¬X±bºjÝŒf{Ǭ<ª)xR‹Kää°}ä­:¨ýuhÆ‚‚9f4SÀ–¨}€ ôO@†¥ŒLw„_}%B¿Ä_³g5Ú¯¾c"€`L­Õ“®úq± år­¸F¤×®]›;$ôe«/Y)xVݽÔ´ªŸœ:b©£8»ožjsh–€ÎY: 2@€€?Z¢)§¼üfôû+IMh JF¿FûÕWS)…þh¤Mƒ€4Ú1H-ôƒ£/9à2ò† 20ÍèܰaÃé½dœ¦òå+czÓ¦Mù¡ÂÛ“wßf hV†…¢S@ua¦€Ñ!† ,& ¾ŒúËà' K@NûêËø×gÆNÀØ[0°þú¢;tèP¾.\³bé•¶D@?˜ÚàF›Æ2jî£I4ëB{1èPˆqv€[Ï2§€»É 9o†œMâêË9 @`(ê[éwÝFôeðëw”3úeð«¬A˜T›â ŒCÀ0t Œ¤|Ùú¡Ša6€‹LÎm¨ý 43@zÊ ™)yiÝÙª×ЯtÛ`Þ¹f1ßê ™ª‹9ã˜Gë€ 0vú-4c_±ú)1Íê;__ú«o%c_F¿–ÁªÝH•€T[6@½ìËQ÷êÕ«£˜ àVSSÎåÐa3ä Hif€ê«z®Zµ*?ôšAu&l©@ìuµ™ÒÓ‚ê#G€ëÐg–!b@ˆ€úú3c_çÙÇŒ·åÔ¯UÿéÀ§GúãÕÍ à,'#I£ëúa“`è½æA×ÌslÞ¼ùô2TÞ&àÖÛ^Û§zêÇLuÔšbu>bÒYN nÐÌs è93A ËP\=9‡ iQoÓöeðëœiâãx\£Ÿ5ýãh3´ôO€¦“¨?Û@Ž€ØGke$kæ‚– Èa{¤æ™W;h¯ êh´ÝfÈq3– ¶Q[é° ãß®s€eFˆ€|Ðïè+¶~Öƒû"Üõ…4­_¿6ô“€)À0åÖ÷Pwó€kJºŒì؃;3@;îëÇÜœÅèØëRG¿¥K—æû6hïu`43@?€r Œ­#}­3æÖ_í*‡€êkë3\RœC€@‘€ DõÌÀ×gýÖ¤6HP¬wÊŸ5x £_ýõ{ÆÖßI¹m¨Ûðp ߣ×@žT}ÁêÇRŽ€1ÆÊ@Ô¡ÝöõCo›Ö)NÑC¬ºj„ÕO³ôèÃiÛC©v9£tƒ9ŠŽ1=§Å:ñ€šÐï„käëÜ }ŒÃf,cLm}éWûÒ®1¶:Å@@ ­ˆ2¾Ì  Ùcy•A¨å š>¯ Ä2å ÐIjAËT_ ê™3@³R©³ê¥£èàP{Ë)`Ž;×õ±=»©=›Ô€@[ú¾×ï—ê—Øï@[™ä‹“€ÚX¿õ[R¸‰“§dðjï€âþrÈÉ“j½Õy´ÎdY»š#@Ï„9´´BNœeĸ@ }»¾{®ïgÂt¨½ÕïѯƒöŸNÛSÓpp„c‹äŒ€- @»ð§dèÙRÕGut÷HuôÁÝ?@õÖȹêºC@uuƒ9ŠK ”fÞÌs¸r8‡ 0eö]êÆfècäM÷ɰµü6ûÐ~kSí[M·¥©ùp I"eëK[#å2”e8ËHJ)èõ:´±žê:‡€öyÐaõ–3@í¬ÙS–§Y‹fFh†€;s@Žý?جf¤ôÍ@] 0]ú-Ôw¡ zû^4ãÞâéÒ¡æEê7ÙDšÚÏZþ"!>CÀ/~y"myômY€Ö×§¸ÑšêäÆú3ÃXƱ:>)Õ[³éŸGëðG€?–HªI@SÇeÉ 0Æ·Ô¬fžL›»Ó¾~ô\Ã8ÕN’ë0^S]2`õ¯[§zžƒ@\5KÀf˜SÀý¬Ì$¨C›4€@‘€Œ/9kͰw z÷‡n‘Ÿ°Áû2üÕàZDŒ{K@X¾HŸC@ ÂæÐúò)w3AÕ׌b±Ð‘ªC@uugF¸uWg@3ÜÝ'œMÀ¦ÕV='r¸Î×A ëæ$CLƒ€Ì›!_ö™Ñ×i< ¡k©gL}üú}OõíI¡9"¡àE¹µèGB?2P4}\ñ”‚Å7nÌ«­ú±Ô§b}N5Xݵ‡€‚œ!ª³)×=t›jdEGC9äÐÿœæ8°ÏæDP¬{8 B·ò!PŸ€;Z¯ßRû¿7Ã^ŸÍØWL€@(zædäë÷[}:6î E¹ðC`ZÖ–fH @@?ÚøE›éém28¦Š34CÂf(®2èÆÌÌEgˆ9ä ø% Bÿ{:ªBÙòs˜£À>+ÖA€êpgø˜ñ.ÃÝŒ{ýŸº×­¯Ï–”~ ¨/b¿Íê›ðûì—/Ò š€Ð„‘߈À‰'f:l€F™L,‡ˆ–G¬[·.¯:€ú±•w=õÝ¢3D`ÕÙ:b Î0¡®qR·DsrØ,s¸i˜iP—0éb$ ÿ3Ô»‡¾ÃÍ /¦Á ±5ÑI¬ïaSúçíS-@`pŒ£&§¥~lgÑ´fÍšüPgQœdÛ!/|ªHª§Í°i‡)Ï8ûiˆÿŠÚÈF0›´ë 0ëLÐ5÷³{ÆD@Ï«Œr{ní³ðîg÷Üî›ASÐM èÙV_Âl°ïoÝ#@ã'€`üm˜d ø‘©×¬r¸F±: 2ŠíÇ[±ýpד8žT2úlÙ€í#`u\l†ÏÒxÚÔ45ƒÊ>·‰Í) XÎ#ÅvÍöÙ-‹u0 ý?ëÐ3¢ “‚>Û=»oŸÝ{ölY»gq.Œ?˜Ý·ßLÅúÿ @éÀnÛŽºfüø´k>&f»Ë4C@Î:O•¯–LèX¿~}Pz›¡XÓSuˆ´{bÒÍ¥gÜŒÃ3Š\g€þïôÙ‚›A×Ýs»¯ë&ÇÎ+¸iÞ¼òæßy×-[Ž]këÿfQ˜wß½nçj;—L;×uûZt®ôvßò.Ò{€À|ú²¾€9Ê‹ßö9_ w ±À0öLT~€ü5¬F?W­Z•’*¶ÚgA£åfësŠAÆ’Þ.¡Ã‚;Ú¡¥Œvâ&0F›Ð"- 0ýÞ™ã_¿uîý¬!Z„2!q´ZðÃTâñ£FmsA-PÐH© È1 £8*àQ…AE¹û(Hræ‘C@ç©:DOဠŒ€ûö[®ß2ý¶Øq&†@IDATÓŸ †Á-£mº´ç«ßöÕ,’ëí Ôq°™æHÑ0vg lÚ´)¯¾9DÔ²·¤ê±ö&† qÐï‘ÍⳘߨq´ZB 8bht€@„äX¾|y¾§€©§Ñò)8Ì!"§ˆ9Ô¹²)”检@EÀŒýâȾ[ƒ&. Î!*8ªq0úAÓtuB<4Zn› Z‡£èƒ řťj¼˜SÀbãO«¡  Œ€kìÛȾëhæ÷e ­ˆŽˆŸ€øÛh²òC7ަ_äÐŽûæPœÚÆiÅ·虵N›bØh ÛG«¢% „" ßBýFèp#í·‚þO(òÈ…DÏA´øŒ¶i*sJlmi³Ôá‘s@‡:@v¿Rpä 4cÅfH¸ª—h¶€® @ ]úmÓw½~ëä6c_ŸSsˆ§ÛŠÔ éÀ^›&S£TŒÂdÄCE\Ç€Û¾ÖA’3ÀŠS eË\§€:†ª»b Œ€ýŽ™‘o±ê¯Fh ¤J@ª-›@½\1êP…d ëÐè¹ޏÎ;O¥35Ï) '€6Tlÿ öTC–€úúM2#_q*¿MÃÒ¥t@ 8ú L­`ô´Â–L&Ͱ5öî³ së€)¶suÆÜtc!§ÀªU«òÃôWT7s ˜s@N „!`Ng}×ÚïŒfj1u? o¤BýÀÐkJjH`ìÆ\Ãê’¼&­³?ï¼óòÅ,Q§ÍbëÀ¹Ã¦úžþùù±fÍšÓUVå°¥r ès]OWŽ@=Ð÷¥÷ö{¡XFY¤ìZjR ¯pxʼn0Ÿø¡õIs²lÖ@±¶2–m¶€Åvm¬ÏÙ’%Kf+W®Ì·¾æ(Æc­§[7Î!´! £Þ5ôí\qYàû²Œ × TàH¥%¬?À 6ê@U’cÀFÑM{¾lHAs Xli,Ïb[6QÔUõ³=læ3Š”ø Œ‘€û=®ï:fôëœ@oÀð Î"#0Fã+2„¨Sƒ€ë(>sêTÊ`‡:’v®xL¡l鯩®æpg ¨î@±°ïc3ìõlƾââ÷w,z£ Øàˆ­EÐç4~ÌO£àd rèñ\ Öuîµ±<¿63ÂÝ_@uU½Ì9 Ç€{Œ¥nÅ6ã3 /÷ûÓœ­n¬û |ÿÄÛ†hŒƒÀÙ½Úqè– ÀüyÄUÔæ|r öÜ*v;´:·CZëÌÆŠ@{ ,_¾C`Êì;GßC:wcûn²x'ýÿ @ 8âh´(!@‡¡ —&E@£ív+îþ¨S®ÏÖQwÏíž›¾(«Ïî̲òÌ)àÆæ0PL€üÐw‚ófØ›!¯Ï6U¿XêÐß%E}ø @ÍàhÆ‹Ô= “Ñ#lŠ5Í$PX´Ü@÷õ?¥Ž½{®kvÝÎ-ÎöôÇ6#,+NúÈ01‡€Í¢kúlõ*ËÏ5L€ýßêAçŠÝs׸·ëJ7/,º7/×!@ ~8âo£ÉjHçc²MOÅÐ(¼œÊþÇÜk®‘ ëv躂}vó˜lŸ±ô¶ µ1aY3@³ä0Gbsè<´žezq m ØÿWñÿ°ÌwÓ”•dz_F…k€¦IÀ4Û}4µV§E Ð?›Y0Ïxp¯Û¹ââyñšjâ^óQ3s,’%#Énl›šóÀô_$‹{hBÀ tåÑóeŸíÿ ìš ý²ÀóYF…k€ P—€º¤H7utp ‚žB!Ј€ûêžKÈ<ƒÅ½®óyŸ‹×M1÷º][Ë¡±h©å5ç€2ÂôyÞÑT+ƒx¬}ÝXçv¨vn±Œ{‹u]ÁâüƒógÞu' §€ opxC‰ è… ŠLÄG@Nƒ¢ãÀղ껠xߌ/Épï¹ç®|7Í&˜·ÜÀͧræ9ä<(J»HW6çÍW‹-·}¶gÂ>Ûýâu÷s1­åizÝòC€†&€`è ü…æu²fâ& 09Eç-_hbÞ÷{Ý=—l•#‡A1ÓÙ}]×Qt ¸Ÿå$Ðg¢ëÜýEF`^G225Q€@)}‡é°Ñ{3ÊuMçvÏFýí³¥³|î +Hi˼ëei¹@€À´à˜V{®¶tdG×d( Ñq­ï3ºí\±àv^Lk†¹›]+É) ó®+í¢{e²¸@€æÀ0 ×£ @Ç7Šf@  J@ß6Z®sרÖyñ¾k€Ûýb»®´æ}ß4½.yóòXYÄ€ @`8† N™µ Љ®Š„è•€Ðú5ãZçöÙÍ w¯ó螥+ÊÖ=eÁ×õ2Ù\ƒ @©ÀZ‹&VŸyûĪIu Љ€ fý¿˜ñl±{MçîgKc£àöÙÝsåµ´VžÏ;W> ó΋y-=1 @€€?8ü±DR®±@<"!Ј€žG{&ç›ìÞ—­ kvîÆ–vQ\–Þ®)Ÿ;·ØÊ-Þw¯W¥uï›b@€ ñÀ0¾6›”Æ“jî(*{ðàÁüÕjöì)¶s)hç»×Üó>ï«\ @€ªà¨"ÄýA ¸FÔ ŠPødhT]ÏÏÞdšœŠB€ É8w25¥¢£$€6ÊfµÒçœsΨõGy@€ Ì#€`®GA@Í€€ @€@p$ЈTðG€þX" € @ .8âj´)`@ƒÀ1@€  DÀ@à)¶õ8‘ÊþX" € @ .8âj´)ÀPÂG@€ @- àh ŽlýÀ ÐkJšÍ˜ÀS@€ *©¶lBõÂPcŽ *8FÐH¨@€ Њ€VØÈÔ'}Ò¦,@€ @ U8RmÙ„ê… ¡ÆAU˜0‚FBE@€ Vp´ÂF¦> àè“6eáà€ @H•€T[6¡záH¨1©  @€ 0ƒ¡§àºpÔ%E:˜àƒ"2 @€b$€ ÆVA§3à8À0â!@€#€`0ô\—€º¤H烑@€ #1¶ :AÀ8ø@€ @ ­°‘©O8ú¤MYÌà€ @p dýÿr?ù< @f žs# ûb8óá®_8üòD @H€@2öf€“'OOà¡¢ € @€ l@òXd*µV' À·¿ým­ø32 þ6JICf¤ÔšÔ€ t'õqtÇèOÂ=÷ÜóF&íU‘1µFúºàH¿©! @hB@Zý¥}±¿¢(©O8ú¤MY8x @€\™=ò‚ûyÌçI,8ÕO¹!Ð}>óÙp€ @K`éÒ¥O…-¡?é)9öô‡’ú$€ OڔŠž@€ ‡Àk—_~ù^çó¨OSr0`Ôâbåq,æÃ]pøc‰$@€ §Oí9—@Uf³d™ø$Z„J”ÀPŠ…‹€ @€@X‡߯ô¥ý®´lÔî+á¤#yh8†nñ•_öÌ”]SÍÜëÌ_[£1 @HàËe÷.:¥_Íèéu€„ ¸Z‚Õ£J èùðùŒàèØ d‡ @‰Èú˜8blË|ä#G3½¾£nèÔ€Oã®»6HhKÀ õb{ÚuW®]sÓ–]sóp@€ ŸÞxã >z–õ§žå!.®‰J“Tcžn×](v-†¶3]ªô³tÌpIq@€&Kà…xà[)Õ>™%j”¬óþRjêò׈4#í­»o®ávÓ¸÷8_LÀxùÙõŹû¹[¦‹]sõ.»ÖFCm¨‘€ $Gàßg5ú«”j•Ì&€j”¬óÿûtÜSz<ߪ‹kä½uuñ™å±gÂ>+×¢k‹¥Žû®Ë 暌EϘ¢ @€@gÿ_g ‘ Hj@¶ÀSߤ¦hDö¼ ¦NŸ¡Ê*–W÷Ú`€J .Ó¹$Ù`—L?—µ] ¥”ÉwËTYvÝÊ5‘}&† @˜$ßO­ÖI9Ô8YGþs©5õyÓ@‹ƒ‘Eã²/½‡*×­ß<vÝMëó¼L¾]SÜ4àhJŒô€ @ 9ÿñ¾ûîÛ“Z­’sd ô@jD}Þ¡u¹.^_LûÐÑÊè«NVŽ•«8D(“_vÍgÙ&ß§LdA€ Œ@Ö/üÔø´®Ö89À‡?üa½ @K aV'˜禷kÅünšâ½˜?Ï«O(­¼¼¬ŒÐupå[™eõb€KŠs@€ 09ÙÛÿÞ¸?ÅZ'çÈ:î²?›bcM¹NeFZeòÌ ì"·NÞ.å”é]§ÌºiL·PåŒ]~]ޤƒ @5?Ê^ÿ÷̨k0Gùäªgæ­ù¿³¨Þñ0\Ž‹@(ƒtQ-C«‹ÊÖ=+¿*]Ûû}ÉÕv¦¿ù&ËX2ÀHC€ IøDªµNÒ½ àѬÁþ$ÕF›z½ŠÆZŸ<¬lF§«·Éu¯éÜ—þ&§È×®webrŠò»Ê%? @€@2ž;yòd²3Ê“tœzô~1™GŠœõZ¾"3ìÜëe×ÜûS97>^²Bèå¶iù–‡.IÎ!@€ÀtdýÁgÓÿO¤ZãdË—/—׿…Tnjõ’aÖ5˜qçC–«‹Éu¯¥zk]Ûèey€">C€ I8±téÒd§ÿ«“uÜtÓM¯fõûדxL'PÉ2c­ìZS>d4-3dzŸõ1Y>ôõ%Ëä(n,_“<¤… @˜¬ÏøK÷Þ{ïs)×:Y€íøñãÿ6‹¤Ü€ÔÍ?Æ¢þk^¢Õ[q×ÐFV›<ÒÓò™ÎÌ0Ä€ @`24€ü¿¤^Û¤wß}÷á¬cÿ ©7âTê'#­*˜!W'm•¬©Üoˬm¾2®&«ìÞ¼k–GqÝÐ&O]Ù¤ƒ @5OÜwß}{F]ƒÊ'íPý—-[ödÑ¡,H9&†ž[3úÜkMÏc‘áêÝE§¶,ÝòÛœ›ÎmÊoš§KYÌhÓºä @ã$õýŽe}Ç>Ní›i¼àæ›o>˜5æÏ7ÃBê ˜h†]c‘Ñ¥mò¶©·åQRÆH ‰!ÙF3Ûäm“ÇÊ«ªWÝtE,_ñú¢Ï–§J§E2BÞk«Ÿå ©²!@€ÆGà7ÞøûŸûÜçŽOóvO 4·ÝvÛodÑ¿o‡‰\1hjÄ5M_¬£åW\'4M_GæXÒXÝ›èkyæñ­º_VV›<’cùL&3Œ1 @H—@ÖçûÝlê¿ìÄÉ„É8NµèßÍ⣓i]* H ì¡Ô2= @€&Mà¥%K–ü½©˜”àöÛo"kà{¦ÖȩԷh´55暦 ·¶õ²|Mêiyû &·‰LËãS“ÙDÒB€ Œ@Öïû¿ò+¿òÔø4ï¦ñ¤Bõ•¯|åÏ¢?í†ÜC¨cè™W'­ê[ú!¸ú,³)Ϻe›Üºé•Îò(nXДé!@€Àxd}½ßùÔ§>õÿŒGcšNÎpÏ=÷¼qî¹çj)Àq‘Ô6†œô2C°»–aº¶­k×òÝü¦‹{­ë¹Éô]?“ÛD?Ëã[—&:€ @ w{3€ìÁI†É9ÔÊ·ÜrË#Y£ÿw“lñWÚ 53ÜBU%´üPzÏ“kõ1~óÒ5½Bn™ª—ÉWÇâ}fÌ#Åu@€ 0jodý¼¹÷Þ{Ÿu-:(?I€xÝzë­ÿWÖø÷w`GÖˆ ¸>U²ì>ëÙ´,ã¢ØWè*³k~_õ@ @€À ~üäÿ;HÉ‘:Y€øgK~2‹žŠ¤-P£‚@C²¢È ·Ím#Üò†`1Ofˆ2U÷r»Ê´ümÚ†<€ @Qø¯½öÚÏE­aÊMÚpóÍ7Ìß–Çz`M 45Κ¦_¤žOY‹Êë½|L¦â²Ðõ~™L»Æ#A @€’ ðDöÊ¿>ðÀ¯'Q›•˜´@ܲ¥_΢ɽÿ±Ã3MÖ*°©¢&¯i¾²ô>e•ÉŸwÍÊUS0½bÔ)6V11B@€ #ÙÌïýê¯þê Ô¥s&ïÁÌ poéõ€„ˆ t5ÔÌí*'bD•ªU1¨º_Y@ËVî¼ì¡ïÏ+—ë€ @£& ÿ;3ãÿk£®…Gåqœ‚¹zõê˜NzCÏUQ2«‚ŠuÒVɪºoeU¥Ké¾Õ¹¾}r³z¹e² À¥Á9 @%ŸÊ6ýûíQjHi§À~à8™Î>þy Öˆõ@À µ> Ð>Ëò€& U̪îWU¢*×ûUå§t_¬€ @ UÙ`Î?ËŒÿ›jýÚÖ €C.[ p$Ûâ¿|å•W9—9M˜@•ÁØWÕM·¼²kîýϭΊ‡nùÌ¢(€ t'õã~ñÞ{ï½§»¤ô$à(´éÇ?þñ[ó7sÝñãÇ wøy†¡ne:.ºW–>Ô5ßzTÉëz?Wî"ížâ²Ðõ~™L®A€ ŒžÀþóÏ?ÿ¾*€À›Íø/2£â><ûÝßýÝÙ‰'œ»œÆ@`ž1Ø—n‹ŒÎE÷úÒÏg9VŸy2í¾â²Pç~Y¾¾®UéÇ €¾Z‚r @€€¯½öÚ,›Í½ñÕW_ýõo¼q™©iIÁpª=o¾ùæ+2ƒàþìãR]Ú·oßìÁœé!"ÄC`ž±éSC3 }ÊDVÜhó¸Ûí @€@SÆn¿e¹cýúõ÷Ýpà ¹mW•wJ÷qd­}Çw,ÏÞ ù@vºÖmü½{÷Î>ÿùÏŸåèÃuõ༜€móÚÃî—å^t¯,=×â&PÕžU÷Ëj—ú €ÔëWÖ¦\ƒ @ M'Ožœ¹K¸³³7Þxã¶;wþ»¬Æç¤YëvµÂq˦‰hwÈï*C('€–0 ŒNÿ×dÈú%`Æó"ö–fžf¡ïÏ+·Íõ*]ÛÈ$ @€@²ÓŽ;v–p9²~ÝÞu×]?wÖÍ _˜¼à–[nùñl$ìÇ=Ï>ûììsŸûÜLž$°dœšXdÔÚ½1°­Òµë}—,#ä. Î!@€@|´g›;òïj¨~a6ЫK?sçw~̽7åóI;´î?kü_¨óhO9ô€aÔ!.ye%Ø=ÅŰèžÒÚýb¾.÷Êdõ}­ŒEß:Ô-ÏÚ û,«nýI@€ P€gOøs3hi€œ™ýöo²™}n ݘ¬àž{îÉ–ýŸûKY[¯¨ÛÞ/¾øâ,{EàìÈ‘#u³Î3> CŸ*/22Ýsu¨JWuß•ú¼J—ªûMô«’Uu¿IY¤… @ˆ‡€ ÿº³³Oíp^Ö7üôÝwß}y<µF“É:zè¡ÿ>CþŸ5Å~èÐ¡Ü pàÀ¦YI:Âp|ÕU²ªîû¤PV3}|F @èN@}6­÷oúºöSË6dþúÇ>ö±ÚÀÝ5ŽOÂ$úЇ®É:÷÷´mÍøõ_ÿõÙSO=ÕVù<0®Lì¢{J_u¿Lfª×Œ…â1Ó{žÎU÷çåã: @€@ÔŸ{ùå—[mΞþæ4¸îèÑ£ÿg5F‹):2ÛÿíúAäÚmòÁœ=òÈ#]Ä·!߆é"yf4.JÓPýÁ“÷Y'Ÿe™¬>öYVõ¡ @€ 0v¯¿þú,3ÜgŠÛÍ# ?ñÑ~tá&ðmËC¾É9²]ÿ$k˜÷ûh=@ôG4ûÒ—¾”"û‰ŒÅdœY0Cͽf÷úˆ­ü>ʪ[†éÔŸe™¬ºõœ—ÎäÌ«Õ}W.K\œC€ ahàUÆÿ)㽓¶o@ÖÏû7Ù~Wu6ÒÌKFªw+µo»í¶u™ð›YæU­Ìɤ×ê-—\rÉlÉ’%§ß`„ÅÊnç—][t/tú!Ë®S7éwÞyç)éÁô¶Ø½i×,.»§kvßâ²tmïu‘ïêÑçù<#º¾dù’£:TÉ’‡¹‹—¹ 'ò@€ ¼E@›ýUíôÿVêê3õÿ²àuhSÀï¹úê«ùÑG}k„±ZÄèSLj@ÖÈ?›µØÖ­öÄOÌxàÙÁƒCˆGæ)UF›P*£rÚèjºÅ¦ŸéÕ¦Nn“ã£~Md•¥-sö¸ºr@€ †€FûµÞßFì}–"™§úšÿéùçŸÿ}ʃ¬ÉÌÈFÿ/Éú—³F Vgy§üñÙÆgëÖ­+Q6£Âb=$v^ŒËî•]³|e÷Ê®-J¿è^SY!ÒK¿¥K—JôinÅóü¦sßêd±Ý/æ+Þw?Û¹Åe2Ý+–Uüly-vå‡:?õÅJ|©\Ÿe6‘Õ$­)®Ñ½;–@€ Ðõ¿dü‡œ‰©Yš¹…÷íÞ½û7~øáú«á°%Mf@fhôÿüиµ¹ÄïüÎïäû„.kŠòÛrÆIyí°kMcËßE¦e~¨:]îÐÜ)€ L€Fç}­÷_ÄN6Û©þü²,þx–öœEéSºl4<&HÙÆÚàá³£7‡Ç3Ï<3ÓÞ_|ñ,›Zr‡ðZ¬v^ŒËî•]³|e÷Ê®-J¿è^SY¡ÒÛ®®*KÁ½fç¿™âÍ¿vÍâª{uÒ-J#ùÅûîg;·ØÕ§íù©/µ¶Ù[å¢L)Z·Üªtî}M=c@«Ç€L€ @ õÁŽ;dÊÿ"ENÍ,¾ðºë®{"›ð‹Ò¦r¯7ƒx``?Ÿ•ÿæ¼ñyúé§g¿ök¿6{òÉ'{,5ý¢\#-¦ÚJ/;Úêeùû¬c“2›¤­bÐD–¥ !S² € @ÃЀˑ#GfÚí¿Ï r­˜ÅÿâGôG×õYþPe%ïøÐ‡>ti÷o øøñã³ßú­ßš}ñ‹_ôòꊡê1ærë‹êèCÆ"ù)Þ3fŠ}…2çéæs6Ƽ2¸@€¦J@ý:ÙJ}Lù/c¬ò§Ã–lYÀ?-K—ÚµäY'þ§²F´žz¸äÐ[:”Ú3Ô{}ÄSA±m•°ü&³­œ:ù¬¬:ië¤ñ-¯N™¡Ò„¨‹ÉT\,mU:îC€ t'  þ4êïóm´r²+þëú¡º¤œ1åÔ0 êÆo\“9þNèrêÊß»wo¾A`Ýô¤+'PÇ SξŒº¾Ê)§Q}Õô«Ã-TÚj-ÏLJ×3K9ûS“úŸ›+€ @‹h†¥ŒþÇÝå‘î=õýœ=Ÿ´qÛ?vï§xž´ Û,îDzF]SýÿýïÏ7Ôk'˜bܾeêˆí¥Ÿ™³Ï²Î,9ObX‡cÝt}áÿ³Ê”@€ÀTèUéÙòìÓ¯ôŽ¥Þî,€¬ÿ÷c?øƒ?ø¶Xt ¡Gꀟ ­­ÌË/¿|vÙe—åÙõîIí:©˜ÐŒ@C²JbC³Nšªr¸ßž€ñ¯ÓÞ–¶ª4KWGf•,îC€ TÍsýõ×ϲ7³Í¶lÙ2ûÀ>P©ÇZŽ ·? çeöÙÏØ‡ãÞwÆï bæ]º&kÌ«b1°5âÿ}ß÷}gU_×õÀ9ÝYi¸PŸ€kØMe×­s©¡Ó6)¿ª.e÷›Èo’¶¬,®A€ ,&°mÛ¶ÙûÞ÷¾ÙÚµkO'¼êª«òW¥ïÙ³çôµ¡OäpìÆ;?úÑþãO}êS{‡Ö+DùÉ:–/_þÎzŽìÉÌÞ-yƃïfÖæCNŒ—LùyhF&¿ÊP'¥QMɳtn»VNaüW›Ô¯IÚñ“¡€ @`Ü–-[6{Ï{Þ3»âŠ+J+"§Àý÷ß_zoˆ‹…ÁØeYŸüc™?7„.¡ËLuþù9™Aý·eLÅpd{äÿU)'€fšXe$ZšªtÍK'‡͸‰ü¶i-ŸÕ‰€ @ Ù^Zöüáx®ñ/I;vìÈ—FÇ`«™® ëþäwÜ¡M“ IÎÈ6nØMãØ ƒ:†pÍ5×ÌV­ZU[é2—Ø4 –^ÿÜ„·—·®”ŸÕMWÌÝ$_“´Årê|-¿Ž¤ @)Ð&ï}ï{óuþuêùîw¿{öä“OÖI:DšíÙÀì-YÁŸ¢ðe&éX³fÍßÖ«%b2:ßùÎw6VÅò|0[°á8ÐGa}•‘Ü €þá^yüøñKbqèŸ‚àŸ€Œ2†½kÜùפ¦uËvÓ5‘_7m[ùmó…Ö«®|7]躸eÅr>Å:ÇÂ= @c' 5üÚä¯Ë@§¼ímo›ýÉŸüÉìĉQ q÷È:?[p{ÿRÊyR"9ÀÖ­[oþùç3[nøõÞçŸ~þŠ Om…˜\£Æç3`r}ʬQä’ÇPså»ç¡ÊC. @˜uëÖÍÞõ®wÍvíÚå¥ÚK—.Í7|üñǽÈë*DƒÈ'Àd2qt2¶ãþ­±Œþ_zé¥3=Ô¾ƒ6S5F­þ]¸šŒ”Z›pj“§‰ü¶iûÒ«¯rÚr  @‚€64¿þúëó{ßýg½5à›ßüæÕ:«Lõ €÷ßxãË|ðÁWÏJ<Ò þ­ÓAœÓ&}Ù ë Õ” #»iÏž=AË©+\}ôBŸñofyÿ nþØÓ%åȼS×þÞïýÞ’ a­i»f›‡F©¼Uª»Ú6Æe›r‡ÌãþcÖ©oÓôuëfrëèPW¦Ït¦ŸO™ódµ-«m>Ó£Mþ6y¬E½“qd÷.Ûô®Xɾ?Ëø/{púÖ£ª<ú_l+=rèîúçC\c­Ž¡Ö4½ËÉòÖ)ÇÍ7µsãÔ¶ÞCço«7ù @€ÀÐd]rÉ%ùTÿõë×­Nãò¥ ¶Üœþþ¶ÆŠ4C23²†Z!£5†‡&Ò¶®¥–í ŽÚsÌûÔªpd‰†6€»–ïgW]†Î @€À<Zßå•Wæëû‡|•ß<ýê^Wß-[NöPIX^rm”—’qdô—Ë0ÇcÓkãèáe9BÛŠKÿW^y%ÿ'ÔŒ€XÖäX}šw–¶é³aùTfÛ¼MóYýˆÏ$à¶Å™wê}êš¿^)¤‚ @ýظqcnôkÔ?ùkÍexGÜw^rã7.{ðÁ‡OaGÐÉ9byøOœ8‘¿Ë²cû ž]޽S‡f舅ñàpW «ÑÜ5¼1ꢞȄ @ M2wìØ‘þÛ·oOª’²Ÿb¶3²ezÍ€ˆžºó5]=–‡æøñãI8ÜöÕ?¥ÞÍ)Κ^4†}\ýëž›‘±²VU¬µNdºXܶ¸®ùÝr}Êrår@€|Ð+ò´“ÿÛÞö¶Y¬¯ïZçØ™yA×:Æ?™ÙHõ91Nkú|ŠAF“œ:äl‘#@Üû6–ëo–¦/ݬ<µ{_eöñŒ¹õòY^W¹]ó»u1Yëž{î¦å€ ôA@ýÉmÛ¶å†ÿE]”Tÿ²ÈOý.Í8Ža0W3 ËB¶aú9e×Çv-€ÀÇä8zôèØž…ÆúêŸC3äì°YÚ+`ÈàmMpËÛ4Ÿú–•m׺Ê÷%Gzø”Õµ^nþPz ñ,¸õ yŠYH‘ @˜ðk]ÿUW]•ìh±_~ùåüR €9›Uíçä±tØ92Ú‡¢©â2$lV€9úž`ÆLÓö·|ªsÓ¼ÆÉd´ÍorÆ[Ý»êBŽ/™]ëF~@€ PE@KkwîÜ9»âŠ+f[·nmÝ/­*'Öû‡ަÎz5zÊ!)€gt5Ò,ÇAW–_´H7Ý` Z³`Ÿºú”U¦~hùeer € hÆì…^˜þ[¶lHFàСCÑ8dä’š †Òˆ³Ö¥Ç<8Y€Ëß–ÈÈ•Àœnš>Î]ƒo‘Á݇.1”áòˆAŸE:„ÖÕ•ïž/Ò‰{€ @ .õ=5µÿ’lm¿Œ9oÐ~b:b˜ »…#{25@¤Âþýûg_|q ªD¡ƒ +› p½A g€t>Œ~“% >äEÑ0”pYù*•9ïú¯:&çz’Q‹a¦uð:R}W§ ¶ÁÞ  Ùò€ê QGo¨ ÀXÚº 3\Ûèny›”W•Ö•éžWåkr?”Ü¢}•S,—Ï€ @À¬\¹2Ôº~­ñ',& @›~ñb©íîÆ2“¼öõr%çÐzs94}#† Zïí$Ì' i6zm¢önPûi‡Žª/ÛìQéì°©CúlÆ`•œùš½uǧ¬·¤NïÌ8öQó6eµÉÓG](€ ¸ ÈþصkW>Ú¿iÓ¦Ê~lܵéO;0µ>|%——Ã^råšù»šœ@h4âË.üûöíË¿ by¨ý=:þ%Éø:qâD~¨ý4#@m©}3ÚÛ¹Ò‹¹ÿ/’S¼çÊj“ž<²$ÛÕ¯X–Ïc—ï2°ºXìÞ〠´! +ýìÛ¶mÛé~gYSͳwïÞh¦ÿkpQ‰ÔC²€X¼7z´ÀæÍ›S–¼ÖOKÌ#¨÷¢Öu¸JÈØÓa·b;7‡Œ}vóq~&>Œf+ÃbiàžŸ©‘ŸO®|÷Üt¤@€ " LíØ±ãô¡~*¡Í–dýòvRüåúÿÛ{¨=ŽòÎSÑÅWI–,[²1b°3ÄL.a„0°ÃÁÉÌ„lÎÙ™awÎfg†…3“ ÞÃda @¸£€™‹í&!™œ‰ÁŒX°±‰llcÙ’¬‹å‹,[²uµ÷ù·ôÈõ½î~ßî·oUÝ¿:§¾ê·ººê©_õ×]ÏS—Þ»woëýÏæ¤?§AüÛó±têwïÞ½ˆ©@óߤ2¢È #¯„VUàýžAλq Ì/<žWzÏ_×7‘_žay盌벬Pî®Êíªœ°nC€ 7Mï?÷Üs³Ýû5Ò‹Â7µÙÒi¦´\,›\½ƒ4HÑŠés€ú¬…¾L°zõêz­ÅÕ‹òf”Ý3`>Wüº¢®0<žv},ç¼]ÈÓeY^Ÿ°ÌðØÏ7¶“²’ @ÍPÿRJ¿FûzŸ°ÙRÆ››ø4H Wõûzè¡Q4È j9í¾ÓgvîܹhÕªUÑÜäC¸»Ã™¾L@í>ÏÌ€"®úŒÐ( kŠZ~]Ñù¢òR÷úö%ßå÷UoÊ… @ 9Ú{ê¼óÎËFú׬YSØÏk®Äñæ$å_ýëXFÿ¥ükIÂÜ` R¥Æ¢è«º±ô0Á5O`Ò ¸Œm|2¼§tìJ~øó¸ækZ>ÇPÎòW==¥êR6¯Ét“¿Ÿž{³1ayáqÙRªÔµlž¤ƒ Ð$žSMÒ$/,Z´råÊl#?)þ¬ÃµO@z‘¾”öÛ/uz Ú‹`,n°½ ¥Æô-Gír© ›…´ûï%c€ÖðÈëÁ¢)\nhóAS¤pê^ìÓÉUV¦y¯¯ócË–ÝT:/×ÃÉ|‹â•ŽÎö$-~C€Ò% ~¸öæZ»vm6Ú¿bÅŠt+“¨ä»víÊ$o³_^FþÇ2ý_\kPå¤ôÅ´ @J†ŒZK„놀¦ù‚²4jF€f}^°) ó”˾Œy²4UϪùô-KQùïaÕz‘€@›x6µI—¼‡J@3ƒ×­[—­åW¨Ï÷áú! ¯|=òÈ#Qþk3B_îÛ•nK´`éÒ¥Ù7ä5Í$§Í5Õhùò屈49ÔiÒ†Œò²òéá¯e2h–@—Jù´\WrL“¡ë›Âeñ°ëò)€ áP_J³nµyŸ<ûpÅѶR²wìØÑiŸ»LÍ·oß^&Ù`Ò Ú V’b§)á19M{¹à‚ ¢²|Åħ+Yd’AF^S|f€Œ3}.Óp%8 Û4 x9]q/[N(Wx\özÒA€ 0šåyöÙggSû¥ôkÔ´kº},SÿEG3„588&7x€Fy5 ¦i’Eÿš‚„‹ƒ€Údß¾}™×®¤ziÈà ö-¥+À¶%OÛùו;”/<žÌwڹɴü† @ =>ʯþô9眳èÌ3ÏŒnd9=ªíI¬©ÿ{÷îJùWm·mÛÖ^¥#Íyð=4 ¦Íu/hƒ:8³ñH|ÿRu¿ÈËP£Ù>;@í%ƒR Ε\%“Ž›š-àùzC‹dp=tžÞã=ôxB@€Ò! mÞ'¯ü4ꋟ€Fý5ÀÓÈ¿¨ùLàø 6+ašL³uzZnÚìMÓ½cš !}Sº®6£{"J¿* å¾w€Œš%ДÂ]J˜‰\É Ã¦dô<%Fx\B¬è’„òû±‡Ñ ‹@€ ‚/E_Sû5Ò¯\z|“½Ø wÝuWz0xqÒ$Æõ²†é«±ýC4po 6‹pï)ÖzÉ ¯Ù&1:Wl=lZFÏ׿óï#¿!Õ¥~” @¨J@³,5•ß×òŸqÆÑ ´T­ÓØÓkãmé`M F5ÅS±cúô_Èm4=P¤dÇ6 @ʤŒZ»„K€”DÿÌ >ñ¨ûLÓÓd Ð ˜gw¸‚ë¡è븩ôd¾éµ.C€ Ð&õ9¤ä»Â¿fÍÅÚÞqÞÚ_KëþctwÜqGŒbu"Óh ¢©Ý´ElNkÍe…Ò'\Ú´ÆI:Øéžsƒ€Œ±ì0²+îaصQ@e{ùÓdå @éÐ`œ>ɧQ~õ{¥ð§Ð7J‡p<’jÔ_úMŒNÿ=òÈ#1ŠÖ‰L£2h37=d¤¤Åæ´) Ö–Ë Š=üä|ðÁ¬Rš C€Œš!Âæ5Rþ]÷P•ÑqÓ†0ÿð.ðx½|OÆ{Ü?µÜdÝÈ«˜À¡C‡²ÎMõÏŠKª~F³¯ï¼óÎêèŠQÔn‘Õ”íoH­CÑCQ "n˜ô@T;ûš#ßPpåÊ•Ñî!0íÅÏ…aSFyî—C׿‡qóäÏ5€ P¿F#üRöW¯^yö¹*æ5Ä3hÕ²Xm¢£“ò¯þø˜Ýè RN4 {ðàÁ(Û]»dêAÉ.§Q6OãB… *s½8eòY)Þ®d{¨zé¸OÀd˜t“òùy÷Ðã !Ä@€gS ­€ N@35ªïžMûœÌ8C)ýúbVŒ³­Õ"šö¯éÿcw£3¨Áõ°Ò«eJ›êû¦)*cÿ‡ª[öìÙ“yå¥%+nÐý ¯ ĦH—­³:­aÇUǩ֥lI@  Più¢Fö]áõëGCažR=¤Wíܹ3ûôzŒrk#ø[n¹eA_4F9»i”•2¥u÷1:)F2hú”ÖŠãÆK@†ª‡~8ó¢ …Y/[Ý åSØG ¨Ý 0b("F< @ ê_h:¿Fõ¥ðKñgý~7ìS+ÅGþ5«ûñ¼H_%ÀÙãX!HÁÐ~Ú -F'…HËä0ÄØBýȤûB_²¿f¡en aK÷Kê ´êéF‘Û$ßU9mÖ¼!@U H±×~DRö}Ó>õ-p˜E@ÊÿŽ;¢ö/ù5˜vÏ=÷̪ÊhÎÖ Ö^auŠ”ÍÐΩz(ã G@ÖVyÿœ‰”ÝÛ2È CWʳÂ:‡ zx¦)s\åÚ*iË”M@€@ßÔ?Ј¾+üég³¾¾[%½òµ™ž6ü‹U—QÉöÃþ°³Á¤ZqÔ5€š¢u!±:}BN7¯¦_á 0‹€Vmr)ï_Ð^n A@Vý!½è]I÷PŒòŽóâ´Eçg1ç< @ FÐ;_о“|J¿ú8Ô! ~fÌ»ý{Ý6mÚ´`æ¬Ç9ý¿?õiÀ˜ÝÞ½{3…F³p¨J@$ÍðYº^/BÏÚ¾ªdI@ˆƒ€ú´šý'eß7–¯Y84I@KQ5K98i2ÿ¦òÚ²eKöU‚¦òJ>£7¨!]Šu?¿Ù¤¼I‘Óæ€C½õúvK@÷’f¿„¢È Ž‚/P¨=ÆâÔyŠýe6–¶ ž€@>žSù\Æ«~ föiTß×î+Ä?¶;¡ûújõx û‚+–¨ÁÓ;âUãHŽàx;KÑÑ&1ï^)QeqÓFçœsNf¸ÇmJ-»" ÿÇ<ó^¦´€{Fœ! n `¤ì–w ¥é=¬Ïïù¨¾+ü ÅÐ:ã‘AÏ-- g“ÆZ{-OøÁ~õï>ÙaèkÚ” ±/ŒÛ·o_´nݺl¤6¨‡hœ@žQ@4;@¡ :ÖÈ€ êôÕ¨¾+ú®ôk ?ï×ê<¹¢9Ú+MëýcŸ-­KÖ›nº) Y›k¡j9a˜à¥™šb¯©-áÔè‰d½ÿÔͽsçÎl3í⊃@—tÿMÎPù>[@ÆÜ0Ð¥l”@ˆ€ŒçRô5øä!SøcoµqÊ—ÂNÿÞ2š¥ Mÿ4ýWLÀvjÀsžóœÓíc¶vé»–úÇd_€‰†äg/òf HÜ»Q ÆuŠL­íå¶¡P@ƒ% }¦|Dß•}ì눃@ì´Þ__#K¥t×]we¤±sí[> 9- ÍÑî¿ÿþEk×®]tÑE-Ú³gOv3)>FçûÈ ‹2±в•Éý5´ŒÀê ÉË(£a 6žÈ@qÐûL ¾|8_ñ8¤F@ 쳡'™nÛ¶mÑæÍ›'£ùC@EiT]]è³{šb¯OªèA†rÆæ¤\iIÀ™gž™í›|ÈIZF Ù5“3ldÀnPˆƒ ôE@ëðµTÔ}­Í—×?Š~_­B¹M$}Ga*N:Ðm·Ý–Џ½ËIzJh³¦ØëªRJ4#ଳΊÖ k¦éHnÉÉHê”ÆåT´dŸœ1 }†€ÜPÐÔæHÊ'•inÑ6 ‚A­à9Õ*Þ,s½c¤Ø‡Š¾·_:%@ ?Úá_ )õ…¤ûhÝ?®< 3Xi#@½dÝ•KÁ %úJ€Œš††ƒÀPhöü¤UZÿ—ú?uÏ"PØ”q`( © 6”:æ1“Ö;C£ù>Нþ’{ÃA’{P@IDAT`LÔ·ÒLgé)9-ÓæsÕ[Œ'\ fÚIÒ_žÜ šr¯i2²>iÔ2§d}®Ck$/C% ÿ½I£€×UÜ(àÇœ! að¾›+ú“á0kM­ P€6?—#Ý!%'åÿÆoLNîc(Ù š£%“Vaý>÷Üs³]øõÏ#ëYLÿ@ú§>xð`&Ÿ^|8Œ€FËŠ6ð”q@†÷2x3Æv§P_@ 5zvkí½Fñµ ²Bõuä5š¯g:È' }Eº‹t…Ôœô²›nº)*+%†J¶–”ôŸsÎ9¹SŠeX·n]¦hǶY ”mŽ¡e š±À ±d£“lðô­`žÑNy7 ¸a@Pøü­A!HÁ—b//¥Þ]Ù—ò±6‚†B„äHé—¾Óìå²e´¸ù曓”½lÛN‡ aý“¸ èF/+ß,P7¨Ò>V(º‘¤ÚÏÀ7do€F’É€ È8 _ô¿îNýÏëxÒ Uƒz$ gžMCp<‘/ï#÷ =Nо?k‡P_ê¾ H'‘â/} E·{÷îE?üá ûf)Ö©™1T¤®­­×L€¼QCÏNJÁÙgŸ}FPÓTdÈÛÕÜÓwJfÉ/€>q8¹¤¡+9(©ðø´ç@hP}½#ëxÿ: 䇺#àÏžîJœ¯$½•ùp_ÇJƒƒº! =Íôu³¢n¤˜¿mp®Oý¥ò œ¿¦í_‰`ÆRäe’`–R¯—›6ᓲ­Ok躬nÚåSß__¹reö™C‘9n.À zI•yQùÿŸ‡ÊV×éw™ëgˆÁi@Ðs)¹—‚¿lÙ²lÔÞCWú+”Œ ¹ ¨¿¯QÿY:ËÜtpáÝw߽讻î¢OÔk s‚ÔŽãI×€:žÕI× óŒ3ÎȼÖÝhF€ }:Ye ”1@ M»ÃAÝð燇.Áäo'„ Ð4 XhWèCeÞ=lºlòƒš' Šš…¬%À©:õƒn¿ýöEÛ¶mKµ QÊ F³hwý]»v0”R£OóÉk&€,rRÂûìèË€¡M%“6 dY@›‚K!Ðp¶@x¬âýy2+ìHTŠz" ¥^J»Þë>j¯ßRôõÛzýÖñ䳤'±)¨A@ï~ 2ê3yÞ¨‘]o—Ê€¡õþ4Å5K@MžšVã{hjM• ÿô¹šóÏ??ûz€nný£–5"Ô;÷rÍLÐlÿZkór1 è x'ÞÃ"½c>wç¿ê·§+ʇx@ }ú–ÒîÊ»+ð®¼ûo…~ܾT”ÄD@}yé)O÷OéW·ÜrKï³¥cjÛ&eÁÐMäûr½ˆ53 ŠÓt»óÎ;/ÛS@ÿ´}n¨Žþ£>š´dA{ÌR"ªÔ•´€@<ü[Ï­2Î nÈ e±÷x7 ”É›4 P‘×ÿ^襸çýv¥ÞÿgÇŠzBåH÷Ðt)Ω;mV(忪>•z½»”@C´5r.#Àºuë2…yž@½ôµa ¼¦îhy@_ëv|ÝŒ«W¯Î–4„Šl D ¸òáaÙj¸A@a8» 4ø¹0mW¶,ÒA MzOkvœþ\Q×ïÐKY×o?ï¡+÷UÿÚ¬yCiÐ2^ J‚Û±cÇ¢ýèG'ú C¨SŒuÀÐ`«hÚvù—À×ø{g·j1y—ï{ŸM!Rô¹íÀFU[’ô€€Wz¤ Íã& þÛþÛCözÆû±BÜ0 ¸’î¡ßwþ[áä±Ò(ÎüãaÒ¢V€@j4P§‘r á]¦:Üyç‹¶nÝšZS$)/€†›M#öꮨOã;«i²s€@ªôìVÿ_ŠmqÓò)ÿ©oZØŸ¶òÅÐY­×?ëÚµk3%Y+MçŸÖù*#ŠF9¤xË+?Í Ð?OÝ|Ë”¦ÑLdàÐŒ !Ž!4G@Ï}ùiÅ|ÎAH“€ú÷Ò)4:>$Å_Fë{î¹'ó]ë0iÞ ÍJ Yž ró üd@£æÚ°)+—”ïg>ó™ÙÌíü)¯Ù]9ýÃjÓ"0tEr @€†L@}ì!Žø«Í¤ mÚ´‰)ÿ=ÞÀZ†¯QòðëR”µ°”榜ò“‘A^F}=@®œd о«V­Ê6 ìª|Ê @€@ê42®ÿ¡Mõ÷vѧÎo»í¶ÆC=_Âj0Tã5Wj)ÆÚI_ º¦qj=¿/ hz:fÈkÏ_ÐtÓ ¨®n`iÀ4Rœƒ @€À±e¥ôk¯ìž.)qÓ†èÚå_Š3å¿ÿ–ÃÐQH)ÖLmä'#€ÖkêSRÔën˜W}¶ïÏxÆ¢sÏ=7{˜ÈàKòÒ7ô9CÍ|ÀA€ @ÇH1–Ò¯Qÿ!*þª¥–(ÿèG?ʦþÓîqÀÐa;hÚÿ®]»²ü}Ã&)êš …¹||Ó@´a þë|š° 27¨Ž2¬X±bæfVUò'- @€R" >¹ÿ.çºæ£È÷ØF[¶léºhÊ›AÀ @MŸÖƾ'€|ƒÀ¶fxdl?%Øå¬m|¨ò´‹©To @€Æ@@{ƒIñ—>0d§å Zë¯@\|0ôÐ&ú§×L)ãnÐHý)§œ’}NOÿ,m®ÛgHÍÐÌ€6ËtÌ*CeÉ %šÀ'! @€Àh†¯Fú¥w5·/~ªŸFý·nÝÚ—”[‚€ÚH¢Ñ~m„±nݺl €—!ƒ€6ñÓçüšüR€ç?Êèà{hý‘”sY&ÛÞ Cùëa(/dÐp€ @HÀÖ÷‡m¤™¾·ß~{+{›…åp\Ÿ€ú çÎAÓâeÐL€ÉQðpo€.¬…š ©ùò’Ë÷ !¢m§Yòb ò53ÀgF´]6ùC€ @ )ÀÓ`ÚX¦¿KW¸ãŽ;é¸4`è¹4%^Ëô‰@„‡ÎgH!×äMÃòüXöIy­Uò)ûm—¯È<í ÙÚ0¯x«B€ ÄH@}dõ™5Í_ýö18ÍæÝ¾}û¢»ï¾{ðK†Öž"hQ=4´1àÙgŸ; ^ ¹¼”w)²Fãåõ9A­Û×~m/MÐEQyÕ[†yftÙò”@€ 0€–ôj ­–´¶½|vš]ŸÓ ‡;ï¼3›éÐuÙ”WŸ€ú ÉAÝ»w/:묳²=ò2Õh¸¦ÉKïÚº¨û׬Y“y"ÜÐöòÕÓ7)dV@Þ]A @€@W|´_JpKe»ªW™r|“¿{ï½·LrÒDJ@d £ 4ô`ѦxyÎ?(ÅXk‹”¶k§¥ Ú·@^O-Д§6eaV@×­Ly€ @N`¬£ýª¿úø;vìÈvøo{ðÏy¶G@{lçÎY µöX½zõ"mΗç45^F=Œ4# ¯iGúb¼¾$ K¨d—Q Mç³üS‚*rÿ„6Ë'o@€ áP\ýZMóïzöm,tµLyóæÍìîKƒ4 € ¶‘…4²¶iÚ}‘@åJñÕ4-¿íµùÓê©™ 2XÈË(!C€|›Kñ'ù¥K—f{h¯Gp€ @¨J@ƒjše+Å,;ùç1Ò@›õ³ûhÌ“‹¸ú0ÔgØZÚO–Gm8m<´?€d èÓIŽp‰€ Z" º´å4IeÈ«|Í Ðæ…2Là @€ 0€Ò¤ô«ÿ=f…W´³?Ÿõ›v·¤}@äí§Ñt}&PFm8ÍÉH ¥W °,–m޾O“#<çKÎ;ï¼Ì‚èJz›ûˆ™¼öSaD2hÁiF”PfŽ!@€†O@›øIé—os *’Ò¶nÝš}ÚoÌÚª®Œêìàznûgˬu×tø•+WfŸEИS‹Ð,É$ïûÈ }Út²bÊ«|Gd Q@€ 0>RôÕ?–Ò¯£±; Êmß¾=SþÙàow€DÚYÿœšŠsæ™gfŠl±µ~ÕªUÙí¯/äÉî k£ Ú/@Šz[N–L·ðÊ@âKfͪhKò… @膀+ýRü¥ô3Â}lgÿ;w.Ú¶m[ö9C˜ts/ÆP €Z¡¤ úÇÔ´vYçŠ>˜—•o¨iN2Ä4ÅIFгÎ:+óÚ»@†íÐæòñSò2hy€f”™]‘Ç—8@€ ¸hðLý^)ý qÇHŸÐòâ-[¶dŠ?\ÆG@‚m®ióRb5`Úª)ö—! –¥¡ŒRÀÏ=÷ÜÌË ½í/ ˆ£xʇÆq*Ë6¬Ç€ @ýð‘~)ümÎ,í§võJ-)Öˆ?Kê±Lýj ‰¶ äkô¼êN÷šö.«!@M"c@ø%ß

-Xñ†%9 @¨H@£Ö¾—•FûuŒË' Ý`ÇŽ‹î½÷ÞVËòK'6Rh¥2ê¡øÐCeëyV¯^=÷µÖ½ûÒ=\c¶j^!Ê»‚îÆ=øÚrÊÛ’AF^䵇€ @ >õï4¥_³?µž¿Íþ]}iûÏAýv)þÚÙ_3$˜êß›Ä*K¬-3‡\¾±Ÿ6¬º/€. ðéU±¯§Ò(üÊ•+3ߥ1@V½äõußDPÆX*àw! @˜M@}Oõ«4¥%v63õÿ¥ôkF°úÁ8Ì"€`¡ÄÎk_=Ö¬YSy_€ÉªJ¡ÕûŠ+N<Œc°ôe ;½´ü‹’CûÈË 0¯Af²Mø @€†D@}WWøÙ¾\ËÊ0¢™¯ñ׳0””ãFªc0 ðNЩûï¿‘–Hù¬ë¤Ìúnø>+…iX¡1@ÆG}ôÄžmË/C‰,²òráReË–Õm®‡ @IP,å}p)&Èb¥>þöíÛ™!SÃ$& €Ä¬¬¸RxeÔz â71]yÈ  Qm߈%K­d÷en ðÑzÜ·íd8‘×^ š ƒ€Ï`é“? @}P¿K} )ý ù]õ–³]»ve>æ=ºª×Œ+ú € ê–© ëô ¨³/À¤¸R¦µa ¼”grë¡žŠ ’Yòûì€. ²|‡³dpc€ ,’@€R% þ¡¦õËKé—W€ú‹RüYß_WÀPÌf0gd5ÔƒCK4òܤ“òºjÕªûèA•ÚT.ÿ´à9眓½¤´¦J^/¬.œ^’2@È»qÅ 2²à @€@ÌÔ—ñQ~)ý©õcb+cÉ<°è¾ûîËö–’lPbj¡ôeÁ~–ªÄÚ©^úi*|ÓNÓÚ—/_žy¢kF@J³œ‡ $òë֭˦¨i™€Œ2ltá|šœ^¢ZÂ!ƒ€/PˆA ‹V  @€¦ðþŠOëïbå4y†pN,5`'Å_Ú"€ -²‘æ. Ð&ym8)©RVehÐÃLÊsÛ›îµQ“N:iÑYg•yÍ¢ð=TŸ®,±*G åå|ÿ7`h£åÉ€ €’|€G¡|W}¡PŽ¡‹«||´Ÿ™Cká8ëƒ ÎviU*=´ý+RrÛr“³ü/m•×f¾¡1@Æ RÜ Ð¥qcrÿ1vƒ‹Œ’“=ڼȀ 0|êo¨¿¨‰òlÜ×l›‹©FûåÙÔ¯Y¶ä6›€ÙŒ™Bv­/Ò(½¦î·í\IõMaRÜ+ÀIéÖ—äeý]?ÄÕŽ¾ÉŽä›40CÀ[€ "á~)þ]÷gŠäRüäh?3(†ÔºiÕ@ZíÕ¸´ÚxNzmä×ÅçèT†ŽOÖO¦ê4Ú®}äÏ;L.š ®ª[×nÒ  e2hSA…òÌèºU(€ )øê¹gÍy{í£eœtóÑ~ÿöX“s9Êqt*MëÒƒIFM#ïÊùN÷RZ}¯€Ô-Îâ'¿víÚlºœ ¾‰`|Y›Ã=¤ü»!À— taøéꞢ@€PÿCƒ=>¥_¡ú^¸öÈ ¢Í·µäV3Eqˆ‰€˜Z£GY|Z’”rMmïr”8Ü+ \"úËIëñ׬Y“yñõ¥2 ôeèP'À­ý2LÈù²ÉëŒ.Û¿ÇÛž¢!@ƒ# þ“¿ë5È#…¿AˆÁQ!1VßJJ¿6öSß `ˆ±Uz”I£ÅR»Z0YÕeË–e-ÐKKëÛ»ÜuRž¦~k*¾/}Pžz1÷¹T ¬—: á>:§vpc€ ò8@€â" %Ó•|õ-Ýï¾}ÔOÕLZø÷5ÀÓ}­)1eRn½–d÷iKZ×~úé§·TÊôléê2FÈ0‘òW&këʵ– ˆ·4K †™zÉk¶‚œÏÐò_:ÐÖg$'Yñ€ cônö©üRøÕ‡`t¿û»Cì¥ôË«=pH‰€”Z«CYõ2‘Rªœp)€}9)š2DÈËÒí£Õ’mNkðÏ<óÌÌ«>²$Kñ–—á#—7KÀšàû ôyŸÄÀ  @MÐȾî{ˆ²ßÝêùÈØòÐCe#ý°¡-ª3äŠ8`ˆ£¢•B–fY75}]ûôíd Ðg 5;A²¹1@/Æ¡87vœsÎ9™UÙ÷a ¦õdyF-pƒ€/À(0”;“z@€@¤Hº²ïоBÌ6hWËSJÿÃ?œ)ý£Mªñ#uœ0ÄÙ.QI¥‡zšâ$C@, ï M õ€öeC™ ›ÀGÖµ™ ÚAØf„7«Œ2ò2V¸c¦€“ „ ±л\ïÉPÑWÿ Å2ž;CRú5Ú¯MýÔ6´O<íƒ$õ `¨Ïp49è¥ NdÐ:𘜦Ñû&{2H•²<¤uYÚ!œ zÊ ãL,{äÝy3B£€f øÌ¼ë‰ƒ ¤H@ï?Ù—Ò¯ …¸ø¨]´s¿¼úV(üñµ5G@s,G‘“ˆ²†J±Ö4ü7‚“1@³´w”ddÒÌÝlªçêÕ«3¯v‰}v@ø’gCurƒ€f?èXq8@€@¬ôöQ})ü:V?Iï:\¼ÔGTŸVJ?#ýñ¶’5O€žuóLG‘£[±µ?†½Š Ky gHI–es½"¹«ÆÍ[³ô’‹ÝyjrtDF&7 (”—q@uÆA€º$ ¥^ʽ+ü~Ü¥ ”5?µ›~MïWÿ1À0ÆVo¨ÎÚÎ÷Ðl€Xö(ªžŒš ¯¸/1@Êçœêê³T/HèEç”F%tŸÉàÎàg ¸q@Ëä1 éN¦.€ú! ù+ù>ª¯phý…~èv[ªúyá׺~ © iÇnÛ€Òâ"€ ®öHR½eI• ¶½Š€ÊXá3”Æ7Œy-}Q]ÊÄKIöO ê¥'eÚ2„¤ö"”¼ê˜ÉKþЩmU_ABã€~ã @N@ïÄ]Á÷÷ŠFõS{/zem§þœ©4Ú¯öÄAO Gü ŽjЋR ¥KRR¶4b|Úi§eþ¬³ÎÊ:C]* &V}µlC~íÚµYç'œ ŽPÊN¹¼%ZJ º7}ÓAS®/²C€ÀtšIæÊ½ÞqÝw¥ú•œM…€ÚT ¿FúåÕæqRi=ä욀®‰¼<½`5@»ÕK©Nq:¶FµÆ\SèÃ¥)Ž”—¹Ý4bîK#”^–räUçö(SOuT·É‘Ý£2Lz b_ÖR¦Þ¤ 0Rö\É÷éûú-E_ÏÜð¨âJÿ—s¯Å¨Q,0ÄÒ“C#èš  M¥L§ê|©€du.T'½päS)/jµ—üš5k²$ªg8C ¥ýŠêÆ«]UǼö”q@÷€Œ2°¤ $Ç1 n øH¾|Wò=Ô»‰ßnÛ£ëÒÔþêø(¿ pe_¡îwcé_x} !Ð m‘%ßôЖr쳤 ÉI™“b,#‡œêë#å¾bHõõºx½}CAuÜ|v€Â!ÏŒpE¡wl‹Î‡›††ôÿ¡ó8@)лOïþ)tÅ^ʽŒ¦(q)µhû²ê~Q_Á•~ ¦`jŸ;%Œ›€q·çµW@¶hZ¹6 L}Y@@)Æþe«ä ±Bq¢“Òª¯@ÈËù‹=4 Ðù;Öòb“·)á±³‹2€ÏCýϸÁ@÷€@Bå^ï0)÷ ]Á÷ß<ã»htËÐýNëó@Aº­ˆä©Àz &*¿FÔi8å”S’ýZ@ôÑ]µjUæu/p£ÀP;L2hÿy9ÕSu—¥_/ý!C² ×ø#þO|™A^Vn ðÐgÈ`àFµ†‚ ï¿õ?8y¬g!ÊTzí<4‰uNêu¯ro­¥©Ï `rë&Z7ur´F\ÉÙàÍ'e*4(Þ z }”\¡3Î8#óª»:Æ2¸1D!‘éÖ‰¹þWå¦íSJ¥{Ù n$˜ü=i4ðßa>C &ú_peÝCŹ1M¡ÿÏëØ è>Tøu?ã t `H·í/9/˜â&–A@K%´± œ¦Éë­uw•Ÿ•+Wf^uW=e ®˜ê<.j+WŠªJåÆŸIþöcÝ~¦óx?WµlÒ“€›I…\¿uŸzèÊ»§õÐïe…8 ‰€ º>¸ ÷ªü>÷pHõ¥.# clõDêÌ‹¦|Ci¦„¼cq“×KÛ ‡º–^J>))öÙggÐdðeÞ‘á~*?ŘRí7¯ñ`²>2辑—q@Nqú9Oç¡â§¥óëz:Æ•' [Οc =NaïçÂЕG˜^÷Îd\ÁŒ˜€þGôŽô÷¤B7z U‡Àà `|§[Auäpóò¡¯*ø—ÄR/u½Ü5KÀg •ñä²ÕSuö=–¶>_ pUÌ\¡”Œ]Ìq£Ê Ýø øÐ`¦ •nÒÍ:-&¯õßúÿ™x|Î:¯<üy¦ ] W¾EéÃ29†š%àa_Àÿo›-‰Ü ˜ `ˆ¹uF./¥fo)Ë—/ϼr_)Áa‡`¨J±” ß\ЩJñ›\:À=çt›$*ÁáqƇ&ëA^€@:ô¬ÑûÝ ß>ºÖ€w^HƒcŒ‡€ñ´ur5åÅÔ~“iym¸(§:u4Z®P~¨K4K`r/uÜ( cÕ@ˆ™€ÞÝþÞöw—ÞÝêGÑ—Š¹å ýÀÐwJ-A€—V H 'Ñ,É‘rEpƒ€Â!ÎÐ,ÓN;-óŽUuWg*ôêdá @}²¯wp¨ðKÙgõ!eBéÀN[NR q4¹Ö‡û H*u4|ù€†8Z®ºûƒÞ¾tÀš1ÀTn§C@M²/åÞGõ¥ôëÝKÿ¨)ÂäqÀ0ÎvO¢Ö¼àâm&7 ès„îB£€:(n ðóC '—¨^ª« nP¨Ž€ P†€}7¨KÑ—Ï3.Ó7*C“4€À4¦Ñá\¯xÉõŠ¿ráyFµ¡OWTÇF)Ë ‡ä|/…U«V¨3N à€Ž±Üß…z/ºÆô¸] 6 `h“.y×"À °¾(.Öºz˜ûÞ.”w€¼ä3?—7S@FÙñÙúƒ aPFÏ|½çôœ÷÷œ~{ÿÆÃaÕœÚ@±À{ X>^ŒÃm|ÍÐòœk½;Ÿ-à†…agÉÓ¥Ê(~ŠQõp£€/!PGQ#B8@Hƒ€¿»¤äëùí3ÝܨM&vDJŒ…€±´t‚õä…™`£ÕY3&7Ô} #€¤„ÇC¸GòŒª—:‘áÆOl6Xóæâr@5 ¸QZ¡+ù ¥èá}T—C‰ÀHC!&ÆJ@Ë–-[–y}¢0tuqÀByuÆÂµ”aúTŽUçICˆdWýÂ%~LÇ3•–EN@ ®Ü»Âï¿õ¬åy›B "# 0€it8×;½h¥ á G@K |>?ï47øŒtœrç-o¶€Fž|¶€ªþ8@È' g§äëyéʾB¹”ßù5&€À1¸¢&À 8êæ‰V¸ÉYá}䆟=þ޶BS“D3#òfGhÔJÆÜ8 8 1ðç¼”zÖû1ÓöÇpPG@ €<*ÄEC TÜ¢ A’& Qty¹ÉûËg ¨c¨Î¢wuœšó//`H­å¨BÀ{~ë·”|ýÖ³\nòY_%ÒB CkÑÕ‡—öÀ4òêHiÖˆzž êXºWG3¥ûtša œ-à;YkÆ@JõËk;â ´ Ld]ÉW>ŸÂã´kŒô€Ú#€ =¶äÜ^æ @$‹F„Ë s ïžU\h$ðc7èw¬N†ßhqùòå Ä”ünÐŒßk@aÌuZP ~@­ðçB)õêù¡có\Þ³4/q€ P€j¼HÝ1:§¸VH‰^Hx‡dOþÓúõ}‡EË $פqÀ ö-;åCõ ø³ÊŸWnÔ C=»b|~Õ¯=9@H“€4Ûm4RÓiMS¾¢n (ºç½ínýöã0,º¾kÀÓŒ’W#á— Ü0Úž ]s¥<tEÀŸ+>R†~¬4¡‹åùÊÄ1 ,$€`!~EF€ÎDd ‚8½ÐL)ÖòryÿŠS§ÜücË»¶«ÊÉØáË V®\¹ XÉtì{(Ä@°? P‰€þ¿¤¼û3@ÏŸ–¯ãÐO{FL;WI C€@ç0tŽœ« “Q…i!pŒ€ïGà†Åæý/)NÞ“Çþ»èúc¥5ûWFŽ“O>9óE9K R`¯è<c!àÿ§ }d^Ç*õ:žtJ‡ƒ ñÀ0ž¶N²¦tL’l6„Nˆ€Ï*EÎû¿S\‘w¥Â¯ótažMO[^ rÜ@ Ù2øÌð·âqˆ€þwÜ 'Ùܘåq Cïÿs^É߯pÚ¹0Ç€ 0l†Ý¾É׎KòMHD@ÆywEÿŸa¼ŽÝë:?'%&üíÇ~>;9çŸY/kšqÀ®€Í) —˜€+íBàJ»ÿ/„¡§ó¸YÑÿCQ|x-Ç€ <ò¨ :9Ñ4‚@`.n4˜ü_–’>7Y€Î‡iüx2ôë&Ó{|^(¹–-[–ù¼óaœŒ2(”wÃÇë·ŸS:\ÚÂûÈÃPµ û±×Z÷BžSº"7í\Ñ5ÄC€æ!€`j\Ó:E¡¦ DGÀLÏ‚pöAaýùá׆¿Ãë‹â=ÍÒ¥KÉ{:Ï 5š ÂߊŸüí†Åãfð6P¨û!ü­«'çÅM¦{›” (>Ìwò~C€b&€ æÖA¶ÂNh ”%à†ƒÉpòú&”=ÍlÐ̂ɼ&O–­ßáL‚Ð0à†7(/?Ï)Î}^þ³âÊÈæQ6½§óPy„Çy¿'Ë™L?íš¼´žß´sž†€ 0d†Üº¨µ4"U€JÍ^ð™ŽË•yWö'ëù ÂóúJ‚ ò¡›öL-:W5^åU½¦(ý´¼Âzq @€@9Êq"UO¦u {‰b!äÐójR!Gèý¼+êžVñŠ“²®cy?VAú]äŠÎÅåC< @ã €`íœt-Õ‘õ©»IWá!^ ¸âí¡ž-RÂÊ»ÒíçzšÉ¸ð·ò˜tº®È+Š/ʇx@€ P•€ªÄHß9uŠ1tŽ!Ð)PÙÖÿ¼¼Çy芶+ßJ£8?ï¡+õú{…t]ž+ŠWÚ¢sEñyù@€ú&€ ï |@‘mW®¥ðú±‡ç¿C¥{òœ~‡çu¼;ÏsUã•GÑ5yù@€Æ@ÀZ9ñ:J9X¼xqâµ@|T'àŠ±Y?CWp§ãI/E[ÎÏO ý\X–ç¯<òŽóâ´UÎë: @€@»0´Ë—Ü!ÄHi gßäðwxìÊ®ÒÉyzWÆé·{¥Ë ¯Ñ9¹iqMžÏ ã @€À `d³«R®ø «VÔ&VÚnÏž=™xá½çÇ*AÞq^\˜¶ÊùLþ@€ @ !Ì«n$Ù´G T˜Ú+…œ!pŒNr'@€  •€¡¶ì€ê…`@IU @€ Þ`è =—%€ ,)Ò5A€MP$@€  `ˆ±Ui pð£eZLö€ @½ÀÐz .K@YR¤ƒ @€ PL@1ÎDB@$ 11˜0’†¦š€ @`„0Œ°ÑS«2€ÔZ,my1¤Ý~H@€ PL@1ÎDB@$ € @€@Ò0$Ý|ãÀ8Ú9¦Z2 ¦Ö@@€ ¦`hŠ$ù@ƒ!€`0MIE @€ÆI€q¶Ë¥Â0äÖ¥n€ @`¼0Œ·í“©9€dš A!@€ ˆ `ˆ¸qí Ü ]`@×Ä)€ @  º Lµ `¨ *ÀPI!@€’!€ ™¦· ÆÝþÔ€ @¨O@}†äÐ @¦ˆ˜p€ @"€`@9äª`rëÆW7 ñµ A€ Ô'0ÀâÅ‹Ÿ¬ƒb%€ Ö–¦\†Ù®Ô € ÌK`éÒ¥ƒÐ7cxâ‰'ÌÛ˜\? ñ·B€ @`¨Ìðøê6€5Æ d7UuÀÐUò,"À €"2ÄC€ qØ¿ÿcC¨9€!´âê€`Q1DÔˆ@€ú'pdãÆ‡ú£¾ƒ1؃°ÈÔoÒaæ€`˜íJ­ @€ ý ÈXJÄÁ¬¶;KÕ˜DIÀd³%+43’m:‡ @mØÑF¦}ä9€mxo)³ºáL)Ç`àN€ @l Ž“>Œà-oyË}Ö“n „/$€  'Z € ¨d @€%`ºÈÖDEšØƒ1X‡]ßeÌÔŒ§µ€ @€ ÐfôA½D™›J¤!I‚˜`£%,23nC€ ŒšÀMC©ýÒ¡TDõ°ÎûÍŒÜ ©EŸª ŠÙS,Æt”×îyqM3á9Ò4Qòƒ @ÉØsÍ5×lIVú Á5àèѣ̘hà¡üìBé «Øë¡¶tï²úïXÚ€· ! @=þk¿¹A¸A~ý×ýNk•ƒh*±€@,Šá¡Fú#OYÏ‹ï•Ë¡0t?þæ€ @`Ô¾>¤ÚÊ`£vêÝ_7¤¢.O•·"Å-LóÔ•Óòòš~ÅðÎ:ƒ_^\_5/’ÅãC¹M(|ŽÀ¿&óô¼Ë†ó–í²—-§‰t^æ¼2Ï’!õügÕó€ @i°þé—6nܸ/-©gK;HÀ›ßüæÍVõïÏ®>)R"Жòé ÚVB½…m×%,«ê±s¨z]Ùôž[ æÉòf”mMÒA€ a°½å¾0Äš Òp¼¡þdˆ 6æ:… £+lmó躜¼:†qMÖ×ëÖVþ’ÕËhRî0¯yò÷kÚ¬w(#Ç€ @ÉØrèСÿ’œÔ%¬ओNúœÕO $I„À,…Í»¶«ÓU9m×£Éüɬ6*Sf^^yqUò*“v2 ³&‰ð€ Œƒ€õ=?jÓÿùi¹Á.¿üòÇìöüü8nÑqÔ²ªr9¯Ò8/ͪòÍ[Î<×5É¢¼æ©SxMŒ2…òq @€ Çm0ùÓÉH[QÐÁÄÁFð>nÁ™©\ïõm‚q¼ú*¿ŽÌ©´1rB€ L'`}ÂO^}õÕwOO•öÙÁÞøÆ7þÀšè¯Ón&¤²Ê¡+sMRó<ËÊÐdÙ1çå\êÊ8o>ó\ç×(œæ˜0ç @€Àà´ýáàj5Q¡ÁT_ëÈ_i{FÂn–Â6­j®ôMKÓö9—¡N=BçÍϯ óêòØË¯ÂažkT'¿nžúa˜‡×@€ 4 Xßïã×\sͶ4¥//õ( 6 àû†DŸÄ „@ÅNüz…óº&ò˜·ì®¯ë²®ó”5Ï5E =¯¢óÄC€  ŽÀnÛùÿÿ\­r*4 €ê}äÈ‘gÁþD%B@ŠÙ4WWqóëg•3M†¶ÎÅ,Û´:»ÜÓÒôy.vùúdCÙ€ ® ÄØëšåõCÀFÿÿÝg>ó™‡û)½ÛRGc¸âŠ+¶ÛCå}Ý⥴& QYk³Nž·Â*ί«r§í¢,—¯JY³®É;ÏoUB@€ 0h7^tÑEŸt ƒÊÆ :Û,€ÿdÁƒús˜ ²Š_žRWµºžGÙ몦/›oìéfÕÛÏ+¬âüºy®™UÖ¬óªP'- @H’À“ú_]yå•£Ù/nT›ð¸uúÿ…5r5-$É{y˜BÏRÚfÕZ××ÍcVc8Ÿ2ÇY²Ï:?†ö¥Ž€ @` lÀç?~á _Ð~q£q£2¨Ußô¦7}ÂO¦…VÑIåÝ•µ0ÞãVõ©Õñ:‡¦^`'ç¹FyÎ*cž|ç¹Æe™&ç«´U3ª#= @H‡€õo>tèÐ{Ò‘¸IGg6kìwX°£„äÒ%iÊÞ¼rTUcK?o½Ë\Wµ®eòœ'Ë¡°Içù6™'yA€ DOà° öüöÆE/iÃŽÒ`Ÿ|Ø:þÿÜXŽf­GÃ÷MoÙ¹XUq«š¾· FT°³nZ$o‹&óŸ•ç¬óMבü @€â%`}ÃwÙÔÿÄ+a{’Ò œføºY}ÞßZrN™€+Œ)×!”Ý룰Içù¶‘ç,Yg¯"“×#Ì“%U’€ $Cà+_üâ?˜Œ´ :Z€8®\¹òß[‡ÿÛ 3%» „ Úd1®ÄMÆwñ»Ï²›¨ŸË?ï<åx¾ó\[tͬ<ý|Q]f/*—x@€ ä l]ºtéo[-šK˨ —\rÉSÞjíõpBm6jQ]y« ÁóQ؇óòç)»Îµó”§k¼Ì¦yy¾ErÕ=_”ï´x/“Ó(q€ $Gà€Iü– 6<˜œä V>.WÊl‘€ @ 6ë>ù/mÝÿwkç”x£7¨ý.¿üòÿj£}¿Ÿx[ŽR|WðÖu±æUµ^^¢ëf/º®N¼—©0ÏÕ=Ÿ—g™8/7/-3ò¨@€’$ð[÷ÿ¹$%oXh Ç^vÙeïµÿ5 ó%»† )e‹™¦ð•ÍÃÓy^ueòüb ½^±ÈSF—¹¨-f/Si @€’$ðç^xồ”¼¡1‡jÊÿ“'tÒ¿°Ÿ£ŸÒÂ}ÖX–E ^X€+{aܼÇMæ5¯ ±]çLÊ´Ežìu¯Ï˳n\Œ2Õ­×C€ ,úöé§ŸþÖ+¯¼’Ï¿¿0ÿ¯yÍkö›!àõu{ÍaD\ét…­ њ̫ yRÏÃyz[U­Ï¬ëÛ>/yUKª¶é!@€@TþþСC—­_¿þ±¨¤êY  `û<`ÿbÑ»&Nñ3qRêbuyJm^\(ÿ¬óaZŽËˆù>)_ RB€ QØvôèÑ×mܸñ¡QSÈ©<€(¿ú«¿z·}àr;µ/ç4Q=˜¦œ¹Bœ'Þ´ëòÒ·çòu%ˬòfo‚—Q”Wìç‹ä&€ @ Z»l&ç+¯¹æšmÑJØ£` à¿þõ¯ÿž^k§10ê#z–ÂØ…LÓd˜v® Ùš,Ã뢰Èyš¢ó©Ä{=º² •ÖCN@€ p‚À}¦Ã½úsŸûÜOÄp°€€8þxÝë^÷-Sþ{‹}|á~ÅF TÜ\¶<¥®Ì9¥ñk==! @€ 5û–,Yòª«¯¾ú²gá0ÌhÛà«–ä æÌHÊéL*ú(ê@/(b²- ’•Šöv,ʳíó¥„$ @€@¬vYñ•Ÿýìg7Å*`,ra(Ѷàoí†ú5KŠ ¯¶“)‰m—;æüǤ€{]Y0æ;žºC€ ë»Ýc²¾üóŸÿü­©ÈܧœJÒ¿ì²ËþÚí ðHÉKH–WüÍͪ۬ó]ò˜%KÛ绬+eA€ ÌOÀú…ñ9kþË3ÄPžÕ"ÛàO<ñÄ+í’*\FÒ† ”UóŠõkóÎM‹óëæ9?Ÿw®‰8ÏVùE盡jE²ÌªKÕrê¤wYêäÁµ€ @½øo¶æÿ6òo/¥'Z(€Š g3¾oF€Kì²/%yCŠˆ²o<›iJæ´s ÒQ†]ÖiVY³Î;O§0t,ip @€â `}´¿:xðà+7lØð`¥#€9ÚÊŒäÈ‘d—Þ<Çå\ÒWðz(zpE6ÉrV^³Î.‚ @˜E`ýÖ­[ß¼qãF¾Ô6‹TÎy 9PÊDÙ×¶:tèå–öoʤ'Ms¤æ¹y•Åy¯Ë“aqMòh2¯il½…ynÖùðš*iÃë8† @h•Àë§ýŽ}æïm_ÿú×´ZÒ€3ÇP£qßð†7 ÛvM–U%/–´Ý²ä@€JØc˰_k›ý}´TjÀPˆ¦Ü‰+®¸âÐk^óšß¶Ô`¾}M¨œX¤Rc˜bê¾ ž·Â˜œËUW&ϧ‹ú5YV•¼ó×sçÀ…s`À\Øæ¿è•¯|å¦C‡ý¢å ]-Ÿ˜?'®œE@/÷³ÒÖ=ßU9uå,s}•º”MëéÎró¤m#Ï2²Î*—ó€ @O#°qéÒ¥/øìg?‹òÿ44íG0 }ÆO+áu¯{–¼ë«_ýê5Kç§ìø9OKDD!W•`Þ‘ôP¹›–‡§›–¦PPN$O€vO¾ © @ñØn}«ÿÙFý¿Hã“„=¶¹møµýû÷_l"¼×þ˜ Ðc[Pt=n”qƒÉ´ÜæI;-?›'Ï*×Ì*Ÿó€ Ô'P¦Q¿rè€Öú¯?|øðO£ü÷@¢HfLéúçå—_þ˜•©ÙeŸ ¼ÊŽªkR,O/ˆ¢ÑYy±¾.³ds¹Ã¸Y2·‘¶Jž³äëò|ªrwɈ² @€@Gî´ýÏÞf›ü]×Qy3ƒ3fêê´Í¸aß¾}/4ååVæ‘®ÊR9Rüf)eÒˆI™tž¦©2‡Òe¹”妛Åz^†Udž· ®ƒ @#"pÀêú6Ûù(ÿqµ:3"jã³~Ͼpõ’%K>a¢½$"ñ¢E ›”G%Ø@…iKñžWY<­‡eÊ Ór•!F@€ ðëK]k}¨ß±éþ?z*–£X`ˆ¥%9ìK7Û?ÎËþîïþî­ýGæ×§9 ”UÖ< ÝSðœÉS1Í•-£lºæ%$G@€ †l¶|þíîÿ•†ò#›° ¨MdiŠê“¯xÅ+6Ø'µIàçÍÏþ~Z'’G £òt? C•4mÈ9M6+#߬<¦÷üû¨Û¤\¡,~<™fò·§‹AþIÙø @€$ð¸õ«®4ñ§?ýi”ÿÈ‘7Ð¥—^zŸ‰ø›6à-ü°ù_Œ\äÎÄ“7mD?Tð¦¥ëLàˆ Yµ!f•ü«¤­+k—eÕ••ë!@€@d´»ÿÿc™¿ó“ŸüäݑɆ80€‰-ú—ù—¿kÊÊË®¿þúß4ÙÞg~]l2v)O“Š›çÕ‡‘ lÙž®KÆeÊj[®yòoòš>î‰2ÜI@€z&ð]ÛÝÿí6Ýÿ[=ËAñ `¨¬Ï䦌]?Ïuó\ÊÊ1 @CÖgúŒmð÷ŸúÔ§´)9n 0 ¤!U—¼ä%×~ï{ß{¡}:ð­¦Xþ¾Eý䀪· *®Äy¨“e”iO?+mÙt.TÕô~ÝCg1oÝæ¹~žk$ß¼×Í[7®ƒ @‘8`ò}Ò¦ú¿Ï>é§õþ¸À0°ý…_ø…ÃV¥«ÌpµíðOMÁù?ì÷óVMª“>ìyÊ ¯ ÁŒ˜€ @ .ýÖúÔ‘#GÞ·aÆíu3ãúx `ˆ·mjIvܰÁ _”!À2”!@Jšü¬‘|‡èJ]Ùô~]̡שªŒó\7Ï5¡\ó^?ïuaÙC€ Ðÿ«–,Yò¯_¿~ga*N †€Á4e~Er `)Ÿ›ŸzX±¡òXFñ-ý°Z£^m¶©’Ó¼×U)ƒ´€ @ AZ?éã&÷ûlÿC ÊÈsÀ0'¸Ô.›4˜Bün«Ã©Õ£Œ¼®ô•QúËäGš…œïÂØò¿ú¸>,3<./5)!@€À ü‰O|bÏ jD%*ÀP Wú‰Ý°iÓ¦k{ì±ß°%ihR‰ó¼Æf0ðzÏ{W×½^å6‘Ǽò—-_÷EßrÖ©#×B€ #p¿õi>nþƒ6Õ/DÆKÀHÛþâ‹/>dUßpçwþéÃ?üÏíaðvû}qÊ8\I“Â֦몜*up™ª\ÓdÚ¾ÊoªÜ¦òi’)yA€ Üjýœ¯X±âê~ðƒ7Y$N@â XWü /¼ð åq•¼møK¦<¿ÓŽ_o¾]-Ú ¨ë&•¶*Šxm•ëæ‘ÙËj»œydók\Fÿ]&T}æ¹./ïºù„ׇÇyeÍŠ«{ý¬ü9@€@>&ûù%Œ&öI«éWíS~lëû¿bÇúƒ@F7 ¶<àzûqý7Þø³öþצý–ý>åD‚¸rWU÷넠굩a ë:ì}_?ÌE×Ô­KQ¾ÄC€ h`ïϬÿòÞ?ù“?ÙÔBþd9ЈMWá…/|áÍ–çÛ¾ûÝï¾Û6ùŸìøwÌŸÙt9CÎ/T« ÂkçaT÷úyÊl뚺u©{}[õ"_@€ Ð }¾o½õÛ?ò±}L›üá PH@!N¼øÅ/Þe®´ ßøðáfÇÿ›ù‹b!#宬ríŠ`Ùô^Çy¯óëÇ:¿ºêæSçzÝ3u®¯[w®‡ Œ…ïÛj-m}”ïÛlܾhû®v5©ÇJÀX[¾B½mÃÀ}–|ýu×]wÕêÕ«ßlmøâ Y4AM¾„›Ì«.ÊP–ð¸n¾\@€: pÈú/nå|È”þïtPE Œ€5h›Õ¹ä’KŽXþ*Ë-·¼ÈÂe^3–›ïÜÍRÞÂócùëßTã4‘gÝ<ê^ŸÇ¢<óÊ!€ ÌIàN»îSGýÌ'?ùÉûæÌƒË °7Á\~æg~FSŽÞfŸ|Çã?þ¦`ÿkûý³seÖðE®ÌUUú›cÞ²ý:Éàr‡qMÈV'P–ð¸Nžº¶n^u¯Ï“?Ì3<ÎKK @h‘€6õû+Ûͽmê÷U;f7ÿa%k cié–êiŸ|IJ^/¯Y‹/Ö¬€ß4šùN+k®@W-ܯ×uóæQµÌ®Ò‡uëªÌ.Ë ëWtÜ¥<”@€j¸Ýú¢Ÿ^ºtéUùÈG—Bài0< óðY7ÝtÓ;O:é¤+,ŸÿÕüÅóæ7ë:)z¡²7¯ÒîyÌ{½äl"Yõñ¼×»®lMåS$GÛù•K< @(Ià€¥û²õG×âŸ`´¿$4’U'€ :3®˜Aàçþç¶$Ù¬€Ûn»íE¦|ýûýæ—͸”ÓhJó ëV¡É¼òd©šÃP^ùÄA€ €À­v¼ÁfÑ~’OøT8l€ÖÐ’±<ÿùÏ×^¿eŸüß-üL™ú- Ú|¯.TçUðšÌc– aYMk#OÉÖd¾ž—‡MÕÝói+_ÏŸ€ ä¸ßú~ÚX{ÃÇ?þñÿ/ç%¸Ë~¿WÞŒ/Y²ä­vüÛæ×™ŸËÍ£¼ù5³îi5‘Ç´ü97€óWªðxúUÓφù„ÇÓ¯â, @(Mà€õ1®µÔl'ÿ¿´Oø.}% !Ð  Â$«r̰ÉR¾Ë‚ÿÞ¾"p‰…šð&ó§—Ë¡z*Wêê(þÕKMç çÓ´Ämå;)g[å´•ï¤üü† @`ŽZ_â¿YÍ6aÝ»’³2»ªå@€ ÐLé·>Ý?üáßÞY© `è6EµKÀÖO›`#÷¿fño°’ŸÓFé¡â©cÜ·Q^•dËôcU·ð¸Éº’ @É8lý¶oZßà/Íÿ…ôß›\  `¨Œäi°‡ù c€Iüo·lÙr.·øËÌ¿Ââ–µU“"ÓÊm«È™ùÉ4ó†„å‡Ç e?w6.‹‡sgÄ…€ ¤Bà~ôëÖ/ûŠù¿úЇ>ôp*‚#'š €  Šä=g?ûÙ›MÈËß{ï½k–,YòJSú.·ß¿jþ ó­»"%³kÃ@‘U4‘OyT•{VúP¦ðxÖuœ‡ @ JºÉüµæ¿²zõjvî²™ª+º"M9Ñxæ3Ÿù  £M]6š‚·dçÎ/1%ü2û­¥ÿÀ|§®/%3,7<î´òÇ Ëû…2!@HžÀ~«ÁuÖ§ø²mý•~ô£;’¯€@C04’lÒ$`ŠÿQ“üúãþ]÷Ýwßö²ÐÌZ]*`ùOu¡"ìÇ]Ì𲦠×ÑI—ÅC[tÜ‘H@€@œ6[?é+&Ú—Ï8㌿»òÊ+Å)&RA _úåOé‘X·nÝ‚¥Ë–-û'¶wÀkLÌKÍŸÓ·¸R~]ö°-£€çßw˔ʗ¹–4€ $I`I}õƒþÖújÿåøÀ–$kÐ蘀ŽS\:Ž/øœI,¿H³ì#C€ükͯ0ß»“Â*½áqSµ‘gS²MËÇåöPiÃãi×r€ ¨1in6¯µü×îß¿ÿëׯ?•„,M@FD„@ŽÏXo¬7%ré<ð³fȾ,`q?o~q‚"Ttý¸‰Ùž—‡1Õ¹ª,^u}x\5?ÒC€ Ðß¼ï[–ãõ6+óoÞ÷¾÷=ÚXîd‘À0Ò†§Úõ˜"-+ô÷û+y䑳>|‰ý¾ÔÎiÉÀ³ÍGç¤Üº‚ëá¼F]çyx¨ ‡ÇѨ(ÐêR±ê$‡ ôA`³½{¯µ>ƵüÚÇ>ö1mÜŒƒ$€ A˜d5^+W®|ÀjŸ}Y@}ôÑçÛ®³¯6ÿ+öÓf‚Ë£“’*ºáq]y=/•_Ñqݲ¸€ äì6‰¿&…ßú×þÑýëø“kBN€ÔZ y“ °bÅŠÛLPù?¶Ú’½{÷þœÿ’½à^fá«ÌŸi>j—§¨›ü­ÈœW– ã[)˜L!@è’ÀN+ìzóÙ´~Û¸ïF;~²K( c'€`ìwõo€)ÍúÔ /ø°)µ‹÷íÛ÷|‹{™»Ô~ÿc;>Û|ôN y¨”‡Çm –“wƵ)yC€ Pž€õs4¥ÿ[毷ã¿}ÿûßwù«I ´A@TÉSØ P›Úl:à¢\pôèQíðKöó—ÍG¹‡€dÍs¡îÇV—¼¤­Çyù*È= ãÂãYç•@€ÀTð¸Ý¼Fø¯µe×Ù¿–Hâ ˆ`ˆ¨1e¼N9å”ÍVûì ¢ ƒÀ‘#G|ÉÀ¥uâcr¡Òœ'—Î{óÒ@€@’3©o2½½ç¿eý–o~èCz8Éš 4FDÀˆ›ª¦Cà¸A@F ’úñÇ–½X_j£ê¿(o/Z}vð$KÍ…Æ€ð8µz / @`dî²÷öw¬òÝÿŽ}éÆõëת ä `H¾ ©Àœzê©[­žòר¾ö^f þŒ½„5KàE%ÿÓ:—¢ áqŠuAf@€À/2«ü‹ì¼¾6 jv2Ñ?n ðPÕбÕ/Ñ!6 @ :¾vÿûöŽý¾½c¯·™ˆ7]yå•Ú³ Œ€5(Õ/ÓO?}‡Õ^þË¢`/ñ¥=ôÐO-Y²äev¬Í5K@_hD{–.e¼çåN†’ÅãÂ㼸>ä¦L@€@ô)¾lÁÞß·Y†ß4eŸµû4 "@  º Lè€)èG¬Ø_ؽ{÷9K—.}‘½ð_hçdPx¾ùQ:7 x(EÇ£D¥!@ u[­?p“½Ûn´éüÚ°ïÆ÷¼ç=ÛS¯òCóÀ0?;®„@rÖ®]»Ë„þëã>“Ïž=«>üû¡¥2(ll¦@V @h›ÀN{û4~…ßýÃ?üÃûÚ.”ü!´`H«½X½zµ¦ý]ÜgùÛÒ3lßx|?Íÿæg ø@€@_4ÃïóRò7™Ò«…7˜²ÿ`_Q.  é´’B 3gžyæ^+lQ@38 ÏfK¬Ãñsv|¡yž#@hÀ>ËóVó7Ù{÷Fó7ÙÞ>?´5ûZ(‹,! ã>‚F¦Šh‚Àñ™×Y^ò™³‡e»víºÈf ü´uJ.¶HÍÐç/Èð€ 24ª¯ÏýJÙÏFömÍþ­¦ì߯nüeð‘(K@YR¤ƒžFÀ”~}ŽÐ7Üè î¾ûîU'Ÿ|ò d0#~ÖÎ/÷4„€ ‘Ø©©ûV÷LÙ·pÓ¾}ûnýà?øøHyPm@ C:„MQ ŸüÉŸ|Ú¾ªûÖ­[ŸaÏpÃÀOYÜÇA€†BÀŒä{¬.Rò7™Â«èKéÿè?0”:R@ =Òk3$†@²žõ¬gí0áå¿ì•ضmÛ©G}¾uŽ~Ê:K µÙ Œò'{:B@€@„ž0™î1‡½Ãn³™o·ëXʾ)ú»í@ *¢j„Àøœþùšòxãq¿€f Ø' }OÍðcöX@Š€ Ð2ƒ–ÿ]æ5Š¿Ù|6¢ê©§þèïxÇ~ûƒ  I4BB`œ‚ lÙ²eµ.°‘–‹mÄE^`3d Ь–, Å@¨@`§¥Õ”ýÍönÉ};Þôîw¿ûnûýd…|H @ J?¥T@`wÞyçÉG޹È.½Ð:jϵNÛsíXáó,<ßü;¶à˜óc;ëxèçC]ÖõX‹,äïq¡LaÜ´øiçÂz…ùÅ“×Sÿ3ðzŠ@ÑýR5¾Éû«¨ì&Ë@^Úm›ù»Ìˆ|—”|ã¦ðÇš¾ÏçõÔÂ8@`Ș0äÖ¥n /¼PS4xÜ/¨ý÷¾÷½e+W®<ß š-puöÂPûœ¾à~@€@ªô.Øn^#ø™—¢o þæåË—ßúö·¿ÝöSmYä†j`@m„d À-·Ü²Ú꡽2oFßs@3VyíØsg ¤~^•ó:xÆ…ÇMžW¾ražÇbŽý­O^Oݧe8Âk¼ŠþOÚ¾Úa?›¦oõΔ|)øK—.Ý|ðàÁ{l$ÿ‰ðÞ瀎ÀÀ@`ï|ç;kN>ùägY'óY–ô9æŸm£IϲΦ~˯󎷇·@™õxc=ÊÕ¥¬*W.,óX̱¿UãÉk -íX­‹þOäxØêr¯ùmö¬Ýbòo±PÓö·ZÜÖeË–maã=µ*€@uª3ã @ lÚ´é¤Ç{ì™ÖA}†8×|¶¼@¡â¬Ãúó§é" d.ï8/N‰=ÞÃ0.<®{¾É¼ªÈ¢råÂkŽÅû[5ž¼žºÏÊp„×0xýŸDؾL&}Vëï7[¨÷²ßŠ{îsŸ»åŠ+®8jÇ8@h˜€†’ IÖÁ]|ÓM7cû*Ã^ÃàUôÒqû>`åí2¯|5’¿Íž[:´Õ¦çï“L8@èž›vÏœ!‘°ŽïVenÉßPTýo~ó›«5c`É’%çZÇÙgL†2ðì.‚H< Ðö\ÚaϨl´Þ޳P¿Íï8zô¨Â­ï|ç;mKò… ú˜PŸ!9@èŒÀu×]·Ôö#XgmÍ8Ç >ß:ÝëldMŸ9\{›Q`ûÕÖ¡õå-AÐ>g[˜Í,°ã,;õ#ï8/.L[å|VàD9æÆM‹Ÿv.”+̯(ž¼0„÷‰Ý/U㛼¿Ž—íë른k§ü=ö¿ï#ô:ÞcÃì÷ã?¾Û¦ãñ:B€Àð `~SC@3 üÙŸýÙ’³ÍÙúܳ,ñÚÅ‹ŸcÊ„fè·B Ö˜—áL Ï´p¥…™³c?›´ÛâØ»wïý(ôºkp€ PD@â!@`&3œºjÕªÕ¦˜È0ySFd,Ðñ¹¦”hƒ,^¡ýVZlxh¿3WUA,J¯ÌŠÎU'¯§Œ;Y#ÿSÄ^¹¼²Qyc¶Ó|6 oœöèØŒm{ì& õ[Çö™»='tÒýo{ÛÛ‡Ì9† Ô%€ .A®‡ ʾô¥/­0ÅG†vñŠãá*S~V˜‘Àã–Ë`œWüróYÜñøS,Ìu–g#ñÊ„¼žŽ²ˆÉ€x=juÔ†vÚ±^¡¦Óï³{2‹×9;~ØÓ(ÞîßG§t¶ôæQ)÷¦Ä?f¿q€ (`ˆ¢€æ! M÷ïß¿âàÁƒš]l†Áé¦x­4ÅLÆS-\n~™_e¿µÏÁ‰sv|✥ÉÎYÜÉæOÓ9óËÌc„ g¼&bžúYt®j¼rœrsKáV(…ü€)á[xâœ]Ä~?bçÚ½ñ˜ï·¸CvìÕ9ó{u^רµÚ2˜G÷wWyâ @ƒ#€`pMJ… @ Iñ±Ê6KÓ×V>|ødSeXdÊâ‰cS"3cÃñrOµÐg&È‘[xš)™2.Èn>ûJƒ)¥Ë-Ïef'Âsаë<þDhù¬²øŸÈ;w<Ñ;wb†vþýÜïQyiôú § C—×d‘"}Bxûýˆ;ª´:¶ ;¶¸½vìé4ržUÌê~âØÒh”=svmvlqOÚ”ø‡ý)è̱#½S"„ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ 9ÿP0p^*òÄ»IEND®B`‚ic11Ò‰PNG  IHDR szzôsRGB®ÎéDeXIfMM*‡i     ¬†bó4IDATX µ—ÉKäWÇ_·íÒí¾µ¢Áe"Œ t<%‡&ÂÁ£§¢aNÁ\¼äœ? Ï^28—!„(âÅf $ƒ :¸Æ}·ÛžúTº:¿îÌd¶öÁû½µ¾õ­zUïuûÜkJÁÅÅŃòòò®`0ø0|xww± ´Ád2é|>ß©ôodnóúúúO©¿ÝÞÞ>+,,\œœLüŸ ßË?)..þæôô´GÖC555êêjII‰£ °+((@±Š' ÇuçççîèèÈíìì$BìØï÷ÏÖ÷SSSϲõeþV„¾…¡ŽŽ_SS“*Ëz›1„VWW],Kž Ù¯'&&Æ Ãø†††bùùù]ÑhÔ‰»m=§íöö¶›žžvrDO…Äg€ûùŒŒŒ<¾¹¹éêëë»7å詯¯wNâæ‘ÄÖÌ)¶¶¶ŽH$âòòò˜»×"^vÝÝÝ®¢¢â!Š”€Ö_œ·œ¿# î«Hf¸ÍÍM Ô“““#ôøH”&‰êÚÚZä««+¦3"]'Þá#Yà.//Õ8²dii‰ I#)Fä3Ãá°¦ýýý}e+ñá∬’‚–†È²NŃìG-V‹µnkkKÓ“±·¤ Ø$ÖWUUqF®±±Ñ1öæ·¤’•HÖ5Sy“cJ³›>% –üãóÔ,€Växô(ðÀ )4Ù-yU\u…¡lüQÀâ¶`„½–ÙZŽÚ+¹9K ,,,|4330˽èc™­½/ÒÒR¼X$8õ`é´··G9+”˜›C¡Ù¡wüû Xëêê\ss³#ÝgggÝÚÚZTôÏ+I¿e”jð±{{{š D=^à±y“ÂECJó`Éëé°˜ –WT ›yyœþϲ Î+ÇF^2­K؇w(dx k©©Rpâããc,w+++ée# `ämkk«²ÅX.cVØ=}oÇ…BŽ”ôµtÅr. ÒÓOi±ÀóÙÐР·"Ö÷A† …>J†Þ2Y<‚ræÁa/òf„íUÔÇd<Æ…A%(7K œñ˪ay•Ò—#ÓKBÓPÆ¿JMß>v°ư§¥æ $w%°¸¸˜˜››KŸ ÊL!.ŲWYò¶dˆñ _ðõ5TòìKI J̽f-DrA€ÌéììtòCÄɽã+++û òòèls7ÖÛyHåhP@ °[›}Qç|eo~÷."`BÖ…T¼„ó‚íñb¼®/2ú hJjü,£&d.FA®ÒаSíãããÓô•îèíí”ñçRc(6ëŒã”y±üÓ±±±Ç‚•qŠÝÓÓóD:OäÉŒˆ ±¥ˆ»Ëpó;r}Ad‘öéèèèR6ƿɚ½â/// éô@^¸©a‰p*ÐÊ…`\âã\Æq©»Òß‘ú\›?ä/Ÿþèð@ý§ûÛÊSaé\$IEND®B`‚info>bplist00Ô X$versionY$archiverT$topX$objects† _NSKeyedArchiverÑ Troot€§ U$nullÓ WNS.keysZNS.objectsV$class¢€€¢€€€Tname_assetcatalog-referenceTiconÓ   €Ò !"Z$classnameX$classes\NSDictionary¢!#XNSObject$)27ILQS[ahp{‚…‡‰ŒŽ’—°µ¼½¾ÀÅÐÙæé$òsqlitebrowser-sqlitebrowser-5733cb7/src/main.cpp000066400000000000000000000043371463772530400221220ustar00rootroot00000000000000 #include "Application.h" #include "sqlite.h" #include static QString message = QString(); void db4sMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QByteArray localMsg = msg.toLocal8Bit(); // Emulate the default Qt treatment. This might not work in some OS, like Windows. fprintf(stderr, "%s\n", localMsg.constData()); const char *file = context.file ? context.file : ""; const char *function = context.function ? context.function : ""; localMsg = QString("%1 (%2, %3:%4)\n").arg(msg, function, file).arg(context.line).toLocal8Bit(); // Log using the SQLite log mechanism, so it gets the same treatment than messages // reported by SQLite itself. This will allow these messages to be seen in our Log window. // Error code will be the type sqlite3_log(static_cast(type), localMsg.constData()); } void boxMessageOutput(QtMsgType, const QMessageLogContext &, const QString &msg) { message += msg + "\n"; } int main( int argc, char ** argv ) { #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif #endif QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); #ifdef Q_OS_WIN // In Windows, there is no output to terminal for a graphical application, so we install // the output to message box, until the main window is shown or the application exits. qInstallMessageHandler(boxMessageOutput); #endif // Create application object. All the initialisation stuff happens in there Application a(argc, argv); // If there has been invocations to the message handler, show it to user in a message box. if(!message.isEmpty()) { QMessageBox messageBox; messageBox.setTextFormat(Qt::RichText); messageBox.setText("

" + message.toHtmlEscaped() + "
"); messageBox.exec(); } // Quit application now if user doesn't want to see the UI if(!a.showMainWindow()) return 0; qInstallMessageHandler(db4sMessageOutput); // Run application return a.exec(); } sqlitebrowser-sqlitebrowser-5733cb7/src/os2app.rc000066400000000000000000000000461463772530400222150ustar00rootroot00000000000000ICON 1 DISCARDABLE "iconos2.ico"sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/000077500000000000000000000000001463772530400226465ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/LICENSE.rst000066400000000000000000000453471463772530400244770ustar00rootroot00000000000000License ======= The MIT License (MIT) - Code ---------------------------- Copyright (c) 2013-2019 Colin Duquesnoy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Creative Commons Attribution International 4.0 - Images ------------------------------------------------------- QDarkStyle (c) 2013-2019 Colin Duquesnoy QDarkStyle (c) 2019-2019 Daniel Cosmo Pizetta Creative Commons Corporation (“Creative Commonsâ€) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is†basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. Using Creative Commons Public Licenses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. - **Considerations for licensors:** Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. `More considerations for licensors `__. - **Considerations for the public:** By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. `More considerations for the public `__. Creative Commons Attribution 4.0 International Public License ------------------------------------------------------------- By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. Section 1 – Definitions ~~~~~~~~~~~~~~~~~~~~~~~ a. **Adapted Material** means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. **Adapter's License** means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. c. **Copyright and Similar Rights** means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. d. **Effective Technological Measures** means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. e. **Exceptions and Limitations** means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. f. **Licensed Material** means the artistic or literary work, database, or other material to which the Licensor applied this Public License. g. **Licensed Rights** means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. h. **Licensor** means the individual(s) or entity(ies) granting rights under this Public License. i. **Share** means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. j. **Sui Generis Database Rights** means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. k. **You** means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. Section 2 – Scope ~~~~~~~~~~~~~~~~~ a. **License grant.** 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: A. reproduce and Share the Licensed Material, in whole or in part; and B. produce, reproduce, and Share Adapted Material. 2. **Exceptions and Limitations.** For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. **Term.** The term of this Public License is specified in Section 6(a). 4. **Media and formats; technical modifications allowed.** The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 5. **Downstream recipients.** A. **Offer from the Licensor – Licensed Material.** Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. B. **No downstream restrictions.** You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. **No endorsement.** Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. **Other rights.** 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. Section 3 – License Conditions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. **Attribution.** 1. If You Share the Licensed Material (including in modified form), You must: A. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. Section 4 – Sui Generis Database Rights ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. Section 5 – Disclaimer of Warranties and Limitation of Liability ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. Section 6 – Term and Termination ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. Section 7 – Other Terms and Conditions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. Section 8 – Interpretation ~~~~~~~~~~~~~~~~~~~~~~~~~~ a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.†Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at `creativecommons.org/policies `__, Creative Commons does not authorize the use of the trademark “Creative Commons†or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/000077500000000000000000000000001463772530400235675ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/_variables.scss000066400000000000000000000021251463772530400265730ustar00rootroot00000000000000// --------------------------------------------------------------------------- // // WARNING! File created programmatically. All changes made in this file will be lost! // // Created by the qtsass compiler v0.3.0 // // The definitions are in the "qdarkstyle.palette" module // //---------------------------------------------------------------------------- $ID: 'dark'; $COLOR_BACKGROUND_6: #60798B; $COLOR_BACKGROUND_5: #54687A; $COLOR_BACKGROUND_4: #455364; $COLOR_BACKGROUND_2: #293544; $COLOR_BACKGROUND_3: #37414F; $COLOR_BACKGROUND_1: #19232D; $COLOR_TEXT_1: #E0E1E3; $COLOR_TEXT_2: #C9CDD0; $COLOR_TEXT_3: #ACB1B6; $COLOR_TEXT_4: #9DA9B5; $COLOR_ACCENT_1: #26486B; $COLOR_ACCENT_2: #346792; $COLOR_ACCENT_3: #1A72BB; $COLOR_ACCENT_4: #259AE9; $OPACITY_TOOLTIP: 230; $SIZE_BORDER_RADIUS: 4px; $BORDER_1: 1px solid $COLOR_BACKGROUND_1; $BORDER_2: 1px solid $COLOR_BACKGROUND_4; $BORDER_3: 1px solid $COLOR_BACKGROUND_6; $BORDER_SELECTION_3: 1px solid $COLOR_ACCENT_3; $BORDER_SELECTION_2: 1px solid $COLOR_ACCENT_2; $BORDER_SELECTION_1: 1px solid $COLOR_ACCENT_1; $PATH_RESOURCES: ':/qss_icons'; sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/darkstyle.qrc000066400000000000000000000233541463772530400263070ustar00rootroot00000000000000 rc/arrow_down.png rc/arrow_down@2x.png rc/arrow_down_disabled.png rc/arrow_down_disabled@2x.png rc/arrow_down_focus.png rc/arrow_down_focus@2x.png rc/arrow_down_pressed.png rc/arrow_down_pressed@2x.png rc/arrow_left.png rc/arrow_left@2x.png rc/arrow_left_disabled.png rc/arrow_left_disabled@2x.png rc/arrow_left_focus.png rc/arrow_left_focus@2x.png rc/arrow_left_pressed.png rc/arrow_left_pressed@2x.png rc/arrow_right.png rc/arrow_right@2x.png rc/arrow_right_disabled.png rc/arrow_right_disabled@2x.png rc/arrow_right_focus.png rc/arrow_right_focus@2x.png rc/arrow_right_pressed.png rc/arrow_right_pressed@2x.png rc/arrow_up.png rc/arrow_up@2x.png rc/arrow_up_disabled.png rc/arrow_up_disabled@2x.png rc/arrow_up_focus.png rc/arrow_up_focus@2x.png rc/arrow_up_pressed.png rc/arrow_up_pressed@2x.png rc/base_icon.png rc/base_icon@2x.png rc/base_icon_disabled.png rc/base_icon_disabled@2x.png rc/base_icon_focus.png rc/base_icon_focus@2x.png rc/base_icon_pressed.png rc/base_icon_pressed@2x.png rc/branch_closed.png rc/branch_closed@2x.png rc/branch_closed_disabled.png rc/branch_closed_disabled@2x.png rc/branch_closed_focus.png rc/branch_closed_focus@2x.png rc/branch_closed_pressed.png rc/branch_closed_pressed@2x.png rc/branch_end.png rc/branch_end@2x.png rc/branch_end_disabled.png rc/branch_end_disabled@2x.png rc/branch_end_focus.png rc/branch_end_focus@2x.png rc/branch_end_pressed.png rc/branch_end_pressed@2x.png rc/branch_line.png rc/branch_line@2x.png rc/branch_line_disabled.png rc/branch_line_disabled@2x.png rc/branch_line_focus.png rc/branch_line_focus@2x.png rc/branch_line_pressed.png rc/branch_line_pressed@2x.png rc/branch_more.png rc/branch_more@2x.png rc/branch_more_disabled.png rc/branch_more_disabled@2x.png rc/branch_more_focus.png rc/branch_more_focus@2x.png rc/branch_more_pressed.png rc/branch_more_pressed@2x.png rc/branch_open.png rc/branch_open@2x.png rc/branch_open_disabled.png rc/branch_open_disabled@2x.png rc/branch_open_focus.png rc/branch_open_focus@2x.png rc/branch_open_pressed.png rc/branch_open_pressed@2x.png rc/checkbox_checked.png rc/checkbox_checked@2x.png rc/checkbox_checked_disabled.png rc/checkbox_checked_disabled@2x.png rc/checkbox_checked_focus.png rc/checkbox_checked_focus@2x.png rc/checkbox_checked_pressed.png rc/checkbox_checked_pressed@2x.png rc/checkbox_indeterminate.png rc/checkbox_indeterminate@2x.png rc/checkbox_indeterminate_disabled.png rc/checkbox_indeterminate_disabled@2x.png rc/checkbox_indeterminate_focus.png rc/checkbox_indeterminate_focus@2x.png rc/checkbox_indeterminate_pressed.png rc/checkbox_indeterminate_pressed@2x.png rc/checkbox_unchecked.png rc/checkbox_unchecked@2x.png rc/checkbox_unchecked_disabled.png rc/checkbox_unchecked_disabled@2x.png rc/checkbox_unchecked_focus.png rc/checkbox_unchecked_focus@2x.png rc/checkbox_unchecked_pressed.png rc/checkbox_unchecked_pressed@2x.png rc/line_horizontal.png rc/line_horizontal@2x.png rc/line_horizontal_disabled.png rc/line_horizontal_disabled@2x.png rc/line_horizontal_focus.png rc/line_horizontal_focus@2x.png rc/line_horizontal_pressed.png rc/line_horizontal_pressed@2x.png rc/line_vertical.png rc/line_vertical@2x.png rc/line_vertical_disabled.png rc/line_vertical_disabled@2x.png rc/line_vertical_focus.png rc/line_vertical_focus@2x.png rc/line_vertical_pressed.png rc/line_vertical_pressed@2x.png rc/radio_checked.png rc/radio_checked@2x.png rc/radio_checked_disabled.png rc/radio_checked_disabled@2x.png rc/radio_checked_focus.png rc/radio_checked_focus@2x.png rc/radio_checked_pressed.png rc/radio_checked_pressed@2x.png rc/radio_unchecked.png rc/radio_unchecked@2x.png rc/radio_unchecked_disabled.png rc/radio_unchecked_disabled@2x.png rc/radio_unchecked_focus.png rc/radio_unchecked_focus@2x.png rc/radio_unchecked_pressed.png rc/radio_unchecked_pressed@2x.png rc/toolbar_move_horizontal.png rc/toolbar_move_horizontal@2x.png rc/toolbar_move_horizontal_disabled.png rc/toolbar_move_horizontal_disabled@2x.png rc/toolbar_move_horizontal_focus.png rc/toolbar_move_horizontal_focus@2x.png rc/toolbar_move_horizontal_pressed.png rc/toolbar_move_horizontal_pressed@2x.png rc/toolbar_move_vertical.png rc/toolbar_move_vertical@2x.png rc/toolbar_move_vertical_disabled.png rc/toolbar_move_vertical_disabled@2x.png rc/toolbar_move_vertical_focus.png rc/toolbar_move_vertical_focus@2x.png rc/toolbar_move_vertical_pressed.png rc/toolbar_move_vertical_pressed@2x.png rc/toolbar_separator_horizontal.png rc/toolbar_separator_horizontal@2x.png rc/toolbar_separator_horizontal_disabled.png rc/toolbar_separator_horizontal_disabled@2x.png rc/toolbar_separator_horizontal_focus.png rc/toolbar_separator_horizontal_focus@2x.png rc/toolbar_separator_horizontal_pressed.png rc/toolbar_separator_horizontal_pressed@2x.png rc/toolbar_separator_vertical.png rc/toolbar_separator_vertical@2x.png rc/toolbar_separator_vertical_disabled.png rc/toolbar_separator_vertical_disabled@2x.png rc/toolbar_separator_vertical_focus.png rc/toolbar_separator_vertical_focus@2x.png rc/toolbar_separator_vertical_pressed.png rc/toolbar_separator_vertical_pressed@2x.png rc/transparent.png rc/transparent@2x.png rc/transparent_disabled.png rc/transparent_disabled@2x.png rc/transparent_focus.png rc/transparent_focus@2x.png rc/transparent_pressed.png rc/transparent_pressed@2x.png rc/window_close.png rc/window_close@2x.png rc/window_close_disabled.png rc/window_close_disabled@2x.png rc/window_close_focus.png rc/window_close_focus@2x.png rc/window_close_pressed.png rc/window_close_pressed@2x.png rc/window_grip.png rc/window_grip@2x.png rc/window_grip_disabled.png rc/window_grip_disabled@2x.png rc/window_grip_focus.png rc/window_grip_focus@2x.png rc/window_grip_pressed.png rc/window_grip_pressed@2x.png rc/window_minimize.png rc/window_minimize@2x.png rc/window_minimize_disabled.png rc/window_minimize_disabled@2x.png rc/window_minimize_focus.png rc/window_minimize_focus@2x.png rc/window_minimize_pressed.png rc/window_minimize_pressed@2x.png rc/window_undock.png rc/window_undock@2x.png rc/window_undock_disabled.png rc/window_undock_disabled@2x.png rc/window_undock_focus.png rc/window_undock_focus@2x.png rc/window_undock_pressed.png rc/window_undock_pressed@2x.png darkstyle.qss sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/darkstyle.qss000066400000000000000000001517321463772530400263320ustar00rootroot00000000000000/* --------------------------------------------------------------------------- WARNING! File created programmatically. All changes made in this file will be lost! Created by the qtsass compiler v0.4.0 The definitions are in the "qdarkstyle.qss._styles.scss" module --------------------------------------------------------------------------- */ /* Light Style - QDarkStyleSheet ------------------------------------------ */ /* See Qt documentation: - https://doc.qt.io/qt-5/stylesheet.html - https://doc.qt.io/qt-5/stylesheet-reference.html - https://doc.qt.io/qt-5/stylesheet-examples.html --------------------------------------------------------------------------- */ /* Reset elements ------------------------------------------------------------ Resetting everything helps to unify styles across different operating systems --------------------------------------------------------------------------- */ * { padding: 0px; margin: 0px; border: 0px; border-style: none; border-image: none; outline: 0; } /* specific reset for elements inside QToolBar */ QToolBar * { margin: 0px; padding: 0px; } /* QWidget ---------------------------------------------------------------- --------------------------------------------------------------------------- */ QWidget { background-color: #19232D; border: 0px solid #455364; padding: 0px; color: #DFE1E2; selection-background-color: #346792; selection-color: #DFE1E2; } QWidget:disabled { background-color: #19232D; color: #788D9C; selection-background-color: #26486B; selection-color: #788D9C; } QWidget::item:selected { background-color: #346792; } QWidget::item:hover:!selected { background-color: #1A72BB; } /* QMainWindow ------------------------------------------------------------ This adjusts the splitter in the dock widget, not qsplitter https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow --------------------------------------------------------------------------- */ QMainWindow::separator { background-color: #455364; border: 0px solid #19232D; spacing: 0px; padding: 2px; } QMainWindow::separator:hover { background-color: #60798B; border: 0px solid #1A72BB; } QMainWindow::separator:horizontal { width: 5px; margin-top: 2px; margin-bottom: 2px; image: url(":/qss_icons/dark/rc/toolbar_separator_vertical.png"); } QMainWindow::separator:vertical { height: 5px; margin-left: 2px; margin-right: 2px; image: url(":/qss_icons/dark/rc/toolbar_separator_horizontal.png"); } /* QToolTip --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip --------------------------------------------------------------------------- */ QToolTip { background-color: #346792; color: #DFE1E2; /* If you remove the border property, background stops working on Windows */ border: none; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Remove opacity, fix #174 - may need to use RGBA */ } /* QStatusBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar --------------------------------------------------------------------------- */ QStatusBar { border: 1px solid #455364; /* Fixes Spyder #9120, #9121 */ background: #455364; /* Fixes #205, white vertical borders separating items */ } QStatusBar::item { border: none; } QStatusBar QToolTip { background-color: #1A72BB; border: 1px solid #19232D; color: #19232D; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Reducing transparency to read better */ opacity: 230; } QStatusBar QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; } /* QCheckBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox --------------------------------------------------------------------------- */ QCheckBox { background-color: #19232D; color: #DFE1E2; spacing: 4px; outline: none; padding-top: 4px; padding-bottom: 4px; } QCheckBox:focus { border: none; } QCheckBox QWidget:disabled { background-color: #19232D; color: #788D9C; } QCheckBox::indicator { margin-left: 2px; height: 14px; width: 14px; } QCheckBox::indicator:unchecked { image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QCheckBox::indicator:unchecked:disabled { image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); } QCheckBox::indicator:checked { image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QCheckBox::indicator:checked:disabled { image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); } QCheckBox::indicator:indeterminate { image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); } QCheckBox::indicator:indeterminate:disabled { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_disabled.png"); } QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); } /* QGroupBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { font-weight: bold; border: 1px solid #455364; border-radius: 4px; padding: 2px; margin-top: 6px; margin-bottom: 4px; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left: 4px; padding-left: 2px; padding-right: 4px; padding-top: -4px; } QGroupBox::indicator { margin-left: 2px; margin-top: 2px; padding: 0; height: 14px; width: 14px; } QGroupBox::indicator:unchecked { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QGroupBox::indicator:unchecked:disabled { image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); } QGroupBox::indicator:checked { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QGroupBox::indicator:checked:disabled { image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); } /* QRadioButton ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton --------------------------------------------------------------------------- */ QRadioButton { background-color: #19232D; color: #DFE1E2; spacing: 4px; padding-top: 4px; padding-bottom: 4px; border: none; outline: none; } QRadioButton:focus { border: none; } QRadioButton:disabled { background-color: #19232D; color: #788D9C; border: none; outline: none; } QRadioButton QWidget { background-color: #19232D; color: #DFE1E2; spacing: 0px; padding: 0px; outline: none; border: none; } QRadioButton::indicator { border: none; outline: none; margin-left: 2px; height: 14px; width: 14px; } QRadioButton::indicator:unchecked { image: url(":/qss_icons/dark/rc/radio_unchecked.png"); } QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_unchecked_focus.png"); } QRadioButton::indicator:unchecked:disabled { image: url(":/qss_icons/dark/rc/radio_unchecked_disabled.png"); } QRadioButton::indicator:checked { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked.png"); } QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked_focus.png"); } QRadioButton::indicator:checked:disabled { outline: none; image: url(":/qss_icons/dark/rc/radio_checked_disabled.png"); } /* QMenuBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar --------------------------------------------------------------------------- */ QMenuBar { background-color: #455364; padding: 2px; border: 1px solid #19232D; color: #DFE1E2; selection-background-color: #1A72BB; } QMenuBar:focus { border: 1px solid #346792; } QMenuBar::item { background: transparent; padding: 4px; } QMenuBar::item:selected { padding: 4px; background: transparent; border: 0px solid #455364; background-color: #1A72BB; } QMenuBar::item:pressed { padding: 4px; border: 0px solid #455364; background-color: #1A72BB; color: #DFE1E2; margin-bottom: 0px; padding-bottom: 0px; } /* QMenu ------------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu --------------------------------------------------------------------------- */ QMenu { border: 0px solid #455364; color: #DFE1E2; margin: 0px; background-color: #37414F; selection-background-color: #1A72BB; } QMenu::separator { height: 1px; background-color: #60798B; color: #DFE1E2; } QMenu::item { background-color: #37414F; padding: 4px 24px 4px 28px; /* Reserve space for selection border */ border: 1px transparent #455364; } QMenu::item:selected { color: #DFE1E2; background-color: #1A72BB; } QMenu::item:pressed { background-color: #1A72BB; } QMenu::icon { padding-left: 10px; width: 14px; height: 14px; } QMenu::indicator { padding-left: 8px; width: 12px; height: 12px; /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ } QMenu::indicator:non-exclusive:unchecked { image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QMenu::indicator:non-exclusive:unchecked:hover, QMenu::indicator:non-exclusive:unchecked:focus, QMenu::indicator:non-exclusive:unchecked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QMenu::indicator:non-exclusive:unchecked:disabled { image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); } QMenu::indicator:non-exclusive:checked { image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QMenu::indicator:non-exclusive:checked:hover, QMenu::indicator:non-exclusive:checked:focus, QMenu::indicator:non-exclusive:checked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QMenu::indicator:non-exclusive:checked:disabled { image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate { image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); } QMenu::indicator:non-exclusive:indeterminate:disabled { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate:focus, QMenu::indicator:non-exclusive:indeterminate:hover, QMenu::indicator:non-exclusive:indeterminate:pressed { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); } QMenu::indicator:exclusive:unchecked { image: url(":/qss_icons/dark/rc/radio_unchecked.png"); } QMenu::indicator:exclusive:unchecked:hover, QMenu::indicator:exclusive:unchecked:focus, QMenu::indicator:exclusive:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_unchecked_focus.png"); } QMenu::indicator:exclusive:unchecked:disabled { image: url(":/qss_icons/dark/rc/radio_unchecked_disabled.png"); } QMenu::indicator:exclusive:checked { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked.png"); } QMenu::indicator:exclusive:checked:hover, QMenu::indicator:exclusive:checked:focus, QMenu::indicator:exclusive:checked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked_focus.png"); } QMenu::indicator:exclusive:checked:disabled { outline: none; image: url(":/qss_icons/dark/rc/radio_checked_disabled.png"); } QMenu::right-arrow { margin: 5px; padding-left: 12px; image: url(":/qss_icons/dark/rc/arrow_right.png"); height: 12px; width: 12px; } /* QAbstractItemView ------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QAbstractItemView { alternate-background-color: #19232D; color: #DFE1E2; border: 1px solid #455364; border-radius: 4px; } QAbstractItemView QLineEdit { padding: 2px; } /* QAbstractScrollArea ---------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QAbstractScrollArea { background-color: #19232D; border: 1px solid #455364; border-radius: 4px; /* fix #159 */ padding: 2px; /* remove min-height to fix #244 */ color: #DFE1E2; } QAbstractScrollArea:disabled { color: #788D9C; } /* QScrollArea ------------------------------------------------------------ --------------------------------------------------------------------------- */ QScrollArea QWidget QWidget:disabled { background-color: #19232D; } /* QScrollBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar --------------------------------------------------------------------------- */ QScrollBar:horizontal { height: 16px; margin: 2px 16px 2px 16px; border: 1px solid #455364; border-radius: 4px; background-color: #19232D; } QScrollBar:vertical { background-color: #19232D; width: 16px; margin: 16px 2px 16px 2px; border: 1px solid #455364; border-radius: 4px; } QScrollBar::handle:horizontal { background-color: #60798B; border: 1px solid #455364; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:hover { background-color: #346792; border: #346792; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:focus { border: 1px solid #1A72BB; } QScrollBar::handle:vertical { background-color: #60798B; border: 1px solid #455364; min-height: 8px; border-radius: 4px; } QScrollBar::handle:vertical:hover { background-color: #346792; border: #346792; border-radius: 4px; min-height: 8px; } QScrollBar::handle:vertical:focus { border: 1px solid #1A72BB; } QScrollBar::add-line:horizontal { margin: 0px 0px 0px 0px; border-image: url(":/qss_icons/dark/rc/arrow_right_disabled.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { border-image: url(":/qss_icons/dark/rc/arrow_right.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { border-image: url(":/qss_icons/dark/rc/arrow_down.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { margin: 0px 3px 0px 3px; border-image: url(":/qss_icons/dark/rc/arrow_left_disabled.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { border-image: url(":/qss_icons/dark/rc/arrow_left.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/dark/rc/arrow_up_disabled.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { border-image: url(":/qss_icons/dark/rc/arrow_up.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { background: none; } QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { background: none; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } /* QTextEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets --------------------------------------------------------------------------- */ QTextEdit { background-color: #19232D; color: #DFE1E2; border-radius: 4px; border: 1px solid #455364; } QTextEdit:focus { border: 1px solid #1A72BB; } QTextEdit:selected { background: #346792; color: #455364; } /* QPlainTextEdit --------------------------------------------------------- --------------------------------------------------------------------------- */ QPlainTextEdit { background-color: #19232D; color: #DFE1E2; border-radius: 4px; border: 1px solid #455364; } QPlainTextEdit:focus { border: 1px solid #1A72BB; } QPlainTextEdit:selected { background: #346792; color: #455364; } /* QSizeGrip -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip --------------------------------------------------------------------------- */ QSizeGrip { background: transparent; width: 12px; height: 12px; image: url(":/qss_icons/dark/rc/window_grip.png"); } /* QStackedWidget --------------------------------------------------------- --------------------------------------------------------------------------- */ QStackedWidget { padding: 2px; border: 1px solid #455364; border: 1px solid #19232D; } /* QToolBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar --------------------------------------------------------------------------- */ QToolBar { background-color: #455364; border-bottom: 1px solid #19232D; padding: 1px; font-weight: bold; spacing: 2px; } QToolBar:disabled { /* Fixes #272 */ background-color: #455364; } QToolBar::handle:horizontal { width: 16px; image: url(":/qss_icons/dark/rc/toolbar_move_horizontal.png"); } QToolBar::handle:vertical { height: 16px; image: url(":/qss_icons/dark/rc/toolbar_move_vertical.png"); } QToolBar::separator:horizontal { width: 16px; image: url(":/qss_icons/dark/rc/toolbar_separator_horizontal.png"); } QToolBar::separator:vertical { height: 16px; image: url(":/qss_icons/dark/rc/toolbar_separator_vertical.png"); } QToolButton#qt_toolbar_ext_button { background: #455364; border: 0px; color: #DFE1E2; image: url(":/qss_icons/dark/rc/arrow_right.png"); } /* QAbstractSpinBox ------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractSpinBox { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; border-radius: 4px; /* min-width: 5px; removed to fix 109 */ } QAbstractSpinBox:up-button { background-color: transparent #19232D; subcontrol-origin: border; subcontrol-position: top right; border-left: 1px solid #455364; border-bottom: 1px solid #455364; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-bottom: -1px; } QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { image: url(":/qss_icons/dark/rc/arrow_up_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::up-arrow:hover { image: url(":/qss_icons/dark/rc/arrow_up.png"); } QAbstractSpinBox:down-button { background-color: transparent #19232D; subcontrol-origin: border; subcontrol-position: bottom right; border-left: 1px solid #455364; border-top: 1px solid #455364; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-top: -1px; } QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::down-arrow:hover { image: url(":/qss_icons/dark/rc/arrow_down.png"); } QAbstractSpinBox:hover { border: 1px solid #346792; color: #DFE1E2; } QAbstractSpinBox:focus { border: 1px solid #1A72BB; } QAbstractSpinBox:selected { background: #346792; color: #455364; } /* ------------------------------------------------------------------------ */ /* DISPLAYS --------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QLabel ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe --------------------------------------------------------------------------- */ QLabel { background-color: #19232D; border: 0px solid #455364; padding: 2px; margin: 0px; color: #DFE1E2; } QLabel:disabled { background-color: #19232D; border: 0px solid #455364; color: #788D9C; } /* QTextBrowser ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QTextBrowser { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; } QTextBrowser:disabled { background-color: #19232D; border: 1px solid #455364; color: #788D9C; border-radius: 4px; } QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { border: 1px solid #455364; } /* QGraphicsView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QGraphicsView { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; } QGraphicsView:disabled { background-color: #19232D; border: 1px solid #455364; color: #788D9C; border-radius: 4px; } QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { border: 1px solid #455364; } /* QCalendarWidget -------------------------------------------------------- --------------------------------------------------------------------------- */ QCalendarWidget { border: 1px solid #455364; border-radius: 4px; } QCalendarWidget:disabled { background-color: #19232D; color: #788D9C; } /* QLCDNumber ------------------------------------------------------------- --------------------------------------------------------------------------- */ QLCDNumber { background-color: #19232D; color: #DFE1E2; } QLCDNumber:disabled { background-color: #19232D; color: #788D9C; } /* QProgressBar ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar --------------------------------------------------------------------------- */ QProgressBar { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; text-align: center; } QProgressBar:disabled { background-color: #19232D; border: 1px solid #455364; color: #788D9C; border-radius: 4px; text-align: center; } QProgressBar::chunk { background-color: #346792; color: #19232D; border-radius: 4px; } QProgressBar::chunk:disabled { background-color: #26486B; color: #788D9C; border-radius: 4px; } /* ------------------------------------------------------------------------ */ /* BUTTONS ---------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QPushButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton --------------------------------------------------------------------------- */ QPushButton { background-color: #455364; color: #DFE1E2; border-radius: 4px; padding: 2px; outline: none; border: none; } QPushButton:disabled { background-color: #455364; color: #788D9C; border-radius: 4px; padding: 2px; } QPushButton:checked { background-color: #60798B; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:disabled { background-color: #60798B; color: #788D9C; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:selected { background: #60798B; } QPushButton:hover { background-color: #54687A; color: #DFE1E2; } QPushButton:pressed { background-color: #60798B; } QPushButton:selected { background: #60798B; color: #DFE1E2; } QPushButton::menu-indicator { subcontrol-origin: padding; subcontrol-position: bottom right; bottom: 4px; } QDialogButtonBox QPushButton { /* Issue #194 #248 - Special case of QPushButton inside dialogs, for better UI */ min-width: 80px; } /* QToolButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton --------------------------------------------------------------------------- */ QToolButton { background-color: #455364; color: #DFE1E2; border-radius: 4px; padding: 2px; outline: none; border: none; /* The subcontrols below are used only in the DelayedPopup mode */ /* The subcontrols below are used only in the MenuButtonPopup mode */ /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ } QToolButton:disabled { background-color: #455364; color: #788D9C; border-radius: 4px; padding: 2px; } QToolButton:checked { background-color: #60798B; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:disabled { background-color: #60798B; color: #788D9C; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:hover { background-color: #54687A; color: #DFE1E2; } QToolButton:checked:pressed { background-color: #60798B; } QToolButton:checked:selected { background: #60798B; color: #DFE1E2; } QToolButton:hover { background-color: #54687A; color: #DFE1E2; } QToolButton:pressed { background-color: #60798B; } QToolButton:selected { background: #60798B; color: #DFE1E2; } QToolButton[popupMode="0"] { /* Only for DelayedPopup */ padding-right: 2px; } QToolButton[popupMode="1"] { /* Only for MenuButtonPopup */ padding-right: 20px; } QToolButton[popupMode="1"]::menu-button { border: none; } QToolButton[popupMode="1"]::menu-button:hover { border: none; border-left: 1px solid #455364; border-radius: 0; } QToolButton[popupMode="2"] { /* Only for InstantPopup */ padding-right: 2px; } QToolButton::menu-button { padding: 2px; border-radius: 4px; width: 12px; border: none; outline: none; } QToolButton::menu-button:hover { border: 1px solid #346792; } QToolButton::menu-button:checked:hover { border: 1px solid #346792; } QToolButton::menu-indicator { image: url(":/qss_icons/dark/rc/arrow_down.png"); height: 8px; width: 8px; top: 0; /* Exclude a shift for better image */ left: -2px; /* Shift it a bit */ } QToolButton::menu-arrow { image: url(":/qss_icons/dark/rc/arrow_down.png"); height: 8px; width: 8px; } QToolButton::menu-arrow:hover { image: url(":/qss_icons/dark/rc/arrow_down_focus.png"); } /* QCommandLinkButton ----------------------------------------------------- --------------------------------------------------------------------------- */ QCommandLinkButton { background-color: transparent; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; padding: 0px; margin: 0px; } QCommandLinkButton:disabled { background-color: transparent; color: #788D9C; } /* ------------------------------------------------------------------------ */ /* INPUTS - NO FIELDS ----------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QComboBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QComboBox { border: 1px solid #455364; border-radius: 4px; selection-background-color: #346792; padding-left: 4px; padding-right: 4px; /* padding-right = 36; 4 + 16*2 See scrollbar size */ /* changed to 4px to fix #239 */ /* Fixes #103, #111 */ min-height: 1.5em; /* padding-top: 2px; removed to fix #132 */ /* padding-bottom: 2px; removed to fix #132 */ /* min-width: 75px; removed to fix #109 */ /* Needed to remove indicator - fix #132 */ } QComboBox QAbstractItemView { border: 1px solid #455364; border-radius: 0; background-color: #19232D; selection-background-color: #346792; } QComboBox QAbstractItemView:hover { background-color: #19232D; color: #DFE1E2; } QComboBox QAbstractItemView:selected { background: #346792; color: #455364; } QComboBox QAbstractItemView:alternate { background: #19232D; } QComboBox:disabled { background-color: #19232D; color: #788D9C; } QComboBox:hover { border: 1px solid #346792; } QComboBox:focus { border: 1px solid #1A72BB; } QComboBox:on { selection-background-color: #346792; } QComboBox::indicator { border: none; border-radius: 0; background-color: transparent; selection-background-color: transparent; color: transparent; selection-color: transparent; /* Needed to remove indicator - fix #132 */ } QComboBox::indicator:alternate { background: #19232D; } QComboBox::item { /* Remove to fix #282, #285 and MR #288*/ /*&:checked { font-weight: bold; } &:selected { border: 0px solid transparent; } */ } QComboBox::item:alternate { background: #19232D; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #455364; } QComboBox::down-arrow { image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { image: url(":/qss_icons/dark/rc/arrow_down.png"); } /* QSlider ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider --------------------------------------------------------------------------- */ QSlider:disabled { background: #19232D; } QSlider:focus { border: none; } QSlider::groove:horizontal { background: #455364; border: 1px solid #455364; height: 4px; margin: 0px; border-radius: 4px; } QSlider::groove:vertical { background: #455364; border: 1px solid #455364; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical { background: #346792; border: 1px solid #455364; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical :disabled { background: #26486B; } QSlider::sub-page:horizontal { background: #346792; border: 1px solid #455364; height: 4px; margin: 0px; border-radius: 4px; } QSlider::sub-page:horizontal:disabled { background: #26486B; } QSlider::handle:horizontal { background: #9DA9B5; border: 1px solid #455364; width: 8px; height: 8px; margin: -8px 0px; border-radius: 4px; } QSlider::handle:horizontal:hover { background: #346792; border: 1px solid #346792; } QSlider::handle:horizontal:focus { border: 1px solid #1A72BB; } QSlider::handle:vertical { background: #9DA9B5; border: 1px solid #455364; width: 8px; height: 8px; margin: 0 -8px; border-radius: 4px; } QSlider::handle:vertical:hover { background: #346792; border: 1px solid #346792; } QSlider::handle:vertical:focus { border: 1px solid #1A72BB; } /* QLineEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit --------------------------------------------------------------------------- */ QLineEdit { background-color: #19232D; padding-top: 2px; /* This QLineEdit fix 103, 111 */ padding-bottom: 2px; /* This QLineEdit fix 103, 111 */ padding-left: 4px; padding-right: 4px; border-style: solid; border: 1px solid #455364; border-radius: 4px; color: #DFE1E2; } QLineEdit:disabled { background-color: #19232D; color: #788D9C; } QLineEdit:hover { border: 1px solid #346792; color: #DFE1E2; } QLineEdit:focus { border: 1px solid #1A72BB; } QLineEdit:selected { background-color: #346792; color: #455364; } /* QTabWiget -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabWidget { padding: 2px; selection-background-color: #455364; } QTabWidget QWidget { /* Fixes #189 */ border-radius: 4px; } QTabWidget::pane { border: 1px solid #455364; border-radius: 4px; margin: 0px; /* Fixes double border inside pane with pyqt5 */ padding: 0px; } QTabWidget::pane:selected { background-color: #455364; border: 1px solid #346792; } /* QTabBar ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabBar, QDockWidget QTabBar { qproperty-drawBase: 0; border-radius: 4px; margin: 0px; padding: 2px; border: 0; /* left: 5px; move to the right by 5px - removed for fix */ } QTabBar::close-button, QDockWidget QTabBar::close-button { border: 0; margin: 0; padding: 4px; image: url(":/qss_icons/dark/rc/window_close.png"); } QTabBar::close-button:hover, QDockWidget QTabBar::close-button:hover { image: url(":/qss_icons/dark/rc/window_close_focus.png"); } QTabBar::close-button:pressed, QDockWidget QTabBar::close-button:pressed { image: url(":/qss_icons/dark/rc/window_close_pressed.png"); } QTabBar::tab, QDockWidget QTabBar::tab { /* !selected and disabled ----------------------------------------- */ /* selected ------------------------------------------------------- */ } QTabBar::tab:top:selected:disabled, QDockWidget QTabBar::tab:top:selected:disabled { border-bottom: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:bottom:selected:disabled, QDockWidget QTabBar::tab:bottom:selected:disabled { border-top: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:left:selected:disabled, QDockWidget QTabBar::tab:left:selected:disabled { border-right: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:disabled { border-left: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled { border-bottom: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled { border-top: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled { border-right: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled { border-left: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected { border-bottom: 2px solid #19232D; margin-top: 2px; } QTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected { border-top: 2px solid #19232D; margin-bottom: 2px; } QTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected { border-left: 2px solid #19232D; margin-right: 2px; } QTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected { border-right: 2px solid #19232D; margin-left: 2px; } QTabBar::tab:top, QDockWidget QTabBar::tab:top { background-color: #455364; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; min-width: 5px; border-bottom: 3px solid #455364; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:selected, QDockWidget QTabBar::tab:top:selected { background-color: #54687A; border-bottom: 3px solid #259AE9; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:!selected:hover, QDockWidget QTabBar::tab:top:!selected:hover { border: 1px solid #1A72BB; border-bottom: 3px solid #1A72BB; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom { border-top: 3px solid #455364; background-color: #455364; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; min-width: 5px; } QTabBar::tab:bottom:selected, QDockWidget QTabBar::tab:bottom:selected { background-color: #54687A; border-top: 3px solid #259AE9; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } QTabBar::tab:bottom:!selected:hover, QDockWidget QTabBar::tab:bottom:!selected:hover { border: 1px solid #1A72BB; border-top: 3px solid #1A72BB; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:left, QDockWidget QTabBar::tab:left { background-color: #455364; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-left-radius: 4px; border-bottom-left-radius: 4px; min-height: 5px; } QTabBar::tab:left:selected, QDockWidget QTabBar::tab:left:selected { background-color: #54687A; border-right: 3px solid #259AE9; } QTabBar::tab:left:!selected:hover, QDockWidget QTabBar::tab:left:!selected:hover { border: 1px solid #1A72BB; border-right: 3px solid #1A72BB; /* Fixes different behavior #271 */ margin-right: 0px; padding-right: -1px; } QTabBar::tab:right, QDockWidget QTabBar::tab:right { background-color: #455364; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; min-height: 5px; } QTabBar::tab:right:selected, QDockWidget QTabBar::tab:right:selected { background-color: #54687A; border-left: 3px solid #259AE9; } QTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hover { border: 1px solid #1A72BB; border-left: 3px solid #1A72BB; /* Fixes different behavior #271 */ margin-left: 0px; padding-left: 0px; } QTabBar QToolButton, QDockWidget QTabBar QToolButton { /* Fixes #136 */ background-color: #455364; height: 12px; width: 12px; } QTabBar QToolButton:pressed, QDockWidget QTabBar QToolButton:pressed { background-color: #455364; } QTabBar QToolButton:pressed:hover, QDockWidget QTabBar QToolButton:pressed:hover { border: 1px solid #346792; } QTabBar QToolButton::left-arrow:enabled, QDockWidget QTabBar QToolButton::left-arrow:enabled { image: url(":/qss_icons/dark/rc/arrow_left.png"); } QTabBar QToolButton::left-arrow:disabled, QDockWidget QTabBar QToolButton::left-arrow:disabled { image: url(":/qss_icons/dark/rc/arrow_left_disabled.png"); } QTabBar QToolButton::right-arrow:enabled, QDockWidget QTabBar QToolButton::right-arrow:enabled { image: url(":/qss_icons/dark/rc/arrow_right.png"); } QTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::right-arrow:disabled { image: url(":/qss_icons/dark/rc/arrow_right_disabled.png"); } /* QDockWiget ------------------------------------------------------------- --------------------------------------------------------------------------- */ QDockWidget { outline: 1px solid #455364; background-color: #19232D; border: 1px solid #455364; border-radius: 4px; titlebar-close-icon: url(":/qss_icons/dark/rc/transparent.png"); titlebar-normal-icon: url(":/qss_icons/dark/rc/transparent.png"); } QDockWidget::title { /* Better size for title bar */ padding: 3px; spacing: 4px; border: none; background-color: #455364; } QDockWidget::close-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/dark/rc/window_close.png"); } QDockWidget::close-button:hover { image: url(":/qss_icons/dark/rc/window_close_focus.png"); } QDockWidget::close-button:pressed { image: url(":/qss_icons/dark/rc/window_close_pressed.png"); } QDockWidget::float-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/dark/rc/window_undock.png"); } QDockWidget::float-button:hover { image: url(":/qss_icons/dark/rc/window_undock_focus.png"); } QDockWidget::float-button:pressed { image: url(":/qss_icons/dark/rc/window_undock_pressed.png"); } /* QTreeView QListView QTableView ----------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview --------------------------------------------------------------------------- */ QTreeView:branch:selected, QTreeView:branch:hover { background: url(":/qss_icons/dark/rc/transparent.png"); } QTreeView:branch:has-siblings:!adjoins-item { border-image: url(":/qss_icons/dark/rc/branch_line.png") 0; } QTreeView:branch:has-siblings:adjoins-item { border-image: url(":/qss_icons/dark/rc/branch_more.png") 0; } QTreeView:branch:!has-children:!has-siblings:adjoins-item { border-image: url(":/qss_icons/dark/rc/branch_end.png") 0; } QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { border-image: none; image: url(":/qss_icons/dark/rc/branch_closed.png"); } QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { border-image: none; image: url(":/qss_icons/dark/rc/branch_open.png"); } QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { image: url(":/qss_icons/dark/rc/branch_closed_focus.png"); } QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { image: url(":/qss_icons/dark/rc/branch_open_focus.png"); } QTreeView::indicator:checked, QListView::indicator:checked, QTableView::indicator:checked, QColumnView::indicator:checked { image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, QListView::indicator:checked:hover, QListView::indicator:checked:focus, QListView::indicator:checked:pressed, QTableView::indicator:checked:hover, QTableView::indicator:checked:focus, QTableView::indicator:checked:pressed, QColumnView::indicator:checked:hover, QColumnView::indicator:checked:focus, QColumnView::indicator:checked:pressed { image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QTreeView::indicator:unchecked, QListView::indicator:unchecked, QTableView::indicator:unchecked, QColumnView::indicator:unchecked { image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, QListView::indicator:unchecked:hover, QListView::indicator:unchecked:focus, QListView::indicator:unchecked:pressed, QTableView::indicator:unchecked:hover, QTableView::indicator:unchecked:focus, QTableView::indicator:unchecked:pressed, QColumnView::indicator:unchecked:hover, QColumnView::indicator:unchecked:focus, QColumnView::indicator:unchecked:pressed { image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QTreeView::indicator:indeterminate, QListView::indicator:indeterminate, QTableView::indicator:indeterminate, QColumnView::indicator:indeterminate { image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); } QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, QListView::indicator:indeterminate:hover, QListView::indicator:indeterminate:focus, QListView::indicator:indeterminate:pressed, QTableView::indicator:indeterminate:hover, QTableView::indicator:indeterminate:focus, QTableView::indicator:indeterminate:pressed, QColumnView::indicator:indeterminate:hover, QColumnView::indicator:indeterminate:focus, QColumnView::indicator:indeterminate:pressed { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); } QTreeView, QListView, QTableView, QColumnView { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; gridline-color: #455364; border-radius: 4px; } QTreeView:disabled, QListView:disabled, QTableView:disabled, QColumnView:disabled { background-color: #19232D; color: #788D9C; } QTreeView:selected, QListView:selected, QTableView:selected, QColumnView:selected { background-color: #346792; color: #455364; } QTreeView:focus, QListView:focus, QTableView:focus, QColumnView:focus { border: 1px solid #1A72BB; } QTreeView::item:pressed, QListView::item:pressed, QTableView::item:pressed, QColumnView::item:pressed { background-color: #346792; } QTreeView::item:selected:active, QListView::item:selected:active, QTableView::item:selected:active, QColumnView::item:selected:active { background-color: #346792; } QTreeView::item:selected:!active, QListView::item:selected:!active, QTableView::item:selected:!active, QColumnView::item:selected:!active { color: #DFE1E2; background-color: #37414F; } QTreeView::item:!selected:hover, QListView::item:!selected:hover, QTableView::item:!selected:hover, QColumnView::item:!selected:hover { outline: 0; color: #DFE1E2; background-color: #37414F; } QTableCornerButton::section { background-color: #19232D; border: 1px transparent #455364; border-radius: 0px; } /* QHeaderView ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview --------------------------------------------------------------------------- */ QHeaderView { background-color: #455364; border: 0px transparent #455364; padding: 0; margin: 0; border-radius: 0; } QHeaderView:disabled { background-color: #455364; border: 1px transparent #455364; } QHeaderView::section { background-color: #455364; color: #DFE1E2; border-radius: 0; text-align: left; font-size: 13px; } QHeaderView::section::horizontal { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-left: 1px solid #19232D; } QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { border-left: 1px solid #455364; } QHeaderView::section::horizontal:disabled { color: #788D9C; } QHeaderView::section::vertical { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-top: 1px solid #19232D; } QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { border-top: 1px solid #455364; } QHeaderView::section::vertical:disabled { color: #788D9C; } QHeaderView::down-arrow { /* Those settings (border/width/height/background-color) solve bug */ /* transparent arrow background and size */ background-color: #455364; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/dark/rc/arrow_down.png"); } QHeaderView::up-arrow { background-color: #455364; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/dark/rc/arrow_up.png"); } /* QToolBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox --------------------------------------------------------------------------- */ QToolBox { padding: 0px; border: 0px; border: 1px solid #455364; } QToolBox:selected { padding: 0px; border: 2px solid #346792; } QToolBox::tab { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-top-left-radius: 4px; border-top-right-radius: 4px; } QToolBox::tab:disabled { color: #788D9C; } QToolBox::tab:selected { background-color: #60798B; border-bottom: 2px solid #346792; } QToolBox::tab:selected:disabled { background-color: #455364; border-bottom: 2px solid #26486B; } QToolBox::tab:!selected { background-color: #455364; border-bottom: 2px solid #455364; } QToolBox::tab:!selected:disabled { background-color: #19232D; } QToolBox::tab:hover { border-color: #1A72BB; border-bottom: 2px solid #1A72BB; } QToolBox QScrollArea { padding: 0px; border: 0px; background-color: #19232D; } /* QFrame ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe https://doc.qt.io/qt-5/qframe.html#-prop https://doc.qt.io/qt-5/qframe.html#details https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color --------------------------------------------------------------------------- */ /* (dot) .QFrame fix #141, #126, #123 */ .QFrame { border-radius: 4px; border: 1px solid #455364; /* No frame */ /* HLine */ /* HLine */ } .QFrame[frameShape="0"] { border-radius: 4px; border: 1px transparent #455364; } .QFrame[frameShape="4"] { max-height: 2px; border: none; background-color: #455364; } .QFrame[frameShape="5"] { max-width: 2px; border: none; background-color: #455364; } /* QSplitter -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter --------------------------------------------------------------------------- */ QSplitter { background-color: #455364; spacing: 0px; padding: 0px; margin: 0px; } QSplitter::handle { background-color: #455364; border: 0px solid #19232D; spacing: 0px; padding: 1px; margin: 0px; } QSplitter::handle:hover { background-color: #9DA9B5; } QSplitter::handle:horizontal { width: 5px; image: url(":/qss_icons/dark/rc/line_vertical.png"); } QSplitter::handle:vertical { height: 5px; image: url(":/qss_icons/dark/rc/line_horizontal.png"); } /* QDateEdit, QDateTimeEdit ----------------------------------------------- --------------------------------------------------------------------------- */ QDateEdit, QDateTimeEdit { selection-background-color: #346792; border-style: solid; border: 1px solid #455364; border-radius: 4px; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; min-width: 10px; } QDateEdit:on, QDateTimeEdit:on { selection-background-color: #346792; } QDateEdit::drop-down, QDateTimeEdit::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #455364; } QDateEdit::down-arrow, QDateTimeEdit::down-arrow { image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus { image: url(":/qss_icons/dark/rc/arrow_down.png"); } QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { background-color: #19232D; border-radius: 4px; border: 1px solid #455364; selection-background-color: #346792; } /* QAbstractView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractView:hover { border: 1px solid #346792; color: #DFE1E2; } QAbstractView:selected { background: #346792; color: #455364; } /* PlotWidget ------------------------------------------------------------- --------------------------------------------------------------------------- */ PlotWidget { /* Fix cut labels in plots #134 */ padding: 0px; } sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/main.scss000066400000000000000000000002001463772530400254000ustar00rootroot00000000000000/* Light Style - QDarkStyleSheet ------------------------------------------ */ @import '_variables'; @import '../qss/_styles'; sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/000077500000000000000000000000001463772530400241735ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/.keep000066400000000000000000000000021463772530400251100ustar00rootroot00000000000000 sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_down.png000066400000000000000000000010061463772530400270570ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¸IDATX…í”=‹Q†Ÿ÷†•A´‘AÌL÷ø ìD‘E-[Ùÿ @´°´±PÄJ ÅÒBKí×dg¢+%ü€™×"‰F7™ø±Í<0Ì3gÞ÷pν5555;ŒÊE7ÍÞ öýSÃûNïSñð›üA˜Y¬µϰÁ.€ü¯\v=qòÓ• véû}ƒÁ`ϧ/_ïÇ'¡0†Àa|ãáîÕ]g¢(Ít Š¢ÑèÃðpgêýEV7§4¿=ú8<=m^&Ì`»±•ö¯#.ØFÒ2í ÌVÒ¼$)ÿ9é—ORÞJš%®H*óªtBÀØ_kÍš—‰ÛÒKÓ ÐÕñ“ *¶ÿÂ4ÑõF;I®Í«t.Ý4='th¬ñ朵6AB@nt¾“4oÍÓ^¸­/Ót= »À*Æh¦ˆrLŸ |öp’ðâK>šîËsd\§.`Œ/8IVFx}ûyø¸å¹gú¿IÔÎØ>‹“L}Ï}ƒÄÙ­géÝ–ç¾9®äñ¾áïÒ ÃÓ/ IЫӞ÷鸵Læc€N.<(ðÚ´ç}5)-ƒÁ`0 ƒÁ`0 †{‰§0—Ó·ØIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_down_disabled.png000066400000000000000000000010421463772530400307060ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÔIDATX…í”±kQÇ?ß„  qÐÁI‰J%¸:yµHéP Ž‚mfÿAÝü ’¸V¼¡uðzCuí-. .µd±¡æ~—3§mc’»ÜÞÝû¾ï÷û~ï÷2dÈအdà]Ÿûþ“ïFجpý(r»Ò÷)¯þ@ÑiàuŠÝýx„¢ßÞÆ«ž×Ÿ¿±®Ã+@€áHÑv«sñéxßXO¦siî§ÕÕ­r©øô‡åÏJ”0´·˜€Ù“‚kß\šŸßL3r/iµZÝr©ø¬cùãˆKŒ[ÅæÄ ¹vÕ÷ýŸÛhƒ$¼™¹ûˆ»½×̆uOÌAÂfí°ãÚmHcíÃÛ•âùò0Ù «Ý„˜á$’ß ›õ‡ƒøôB¼)ž»¸†4 ¸^_ìÂÌœ$wÿ­°Y¯ýKèó¸Q23ÈW!JϧÌ7%U–jχÑ©Á&ff/›ÜØQ33)¾ß}sµl*X¨¿Vsä÷*Õ D' L‰†ø†4úµw£èuÅ®VfÏD!èTüÅ>;‡ø£jý›ñ¦oŸäûzÏV÷Z¸øøë¸Z2dÈp ø¤ñ¤ŽDÆQ^IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_down_disabled@2x.png000066400000000000000000000020541463772530400312640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÞIDATxœí˜Ïk\UÇ?ç¾44‘Š`q“¶.²Ð"ÆB­YĦi Z51 "Mð@‘ ‚ºP .4i‰3t„š23)#âª6éª1]m+ˆ¦ ›Ò@fæIcß›7ÉdfÞ4ÚûY¾óîyßsï¹ç¾{Àb±X,‹Åb±X,‹Åò`!þ=ýï‰1ÇQÀ´ö²ªŠ!¯®û~:~jè^c]ÁÛ²<€©…š 8"æ8à™€ÿO€eR0ªî ÿõ´@u96/5àPOG^LB`›Ç¨,×…Í‹ªAė‘t,’ñ¿8]}{4Ïy„íþ/€q7_m@ þ˜”yqèNŽE.U”î¾þ'ò®I;½NUÙl™P<\sŒÛu~ìÔl±AkN@׋Gwj“žô™”ͳ‚‚ÿErù®dbäúz×$™¹ž­7íÀÏ>“€:Acj‡°¢ÁüÅl½i_/x(ñÌœžoȺÏ!\(" æ¸N@O6dÝ™ÓÃó¥ø)YüììôÒ®½O}ëdM+Ð⑦„ÝTEDŠ|3^w§¡÷ܹ/ï”êiC«÷ëå˹]½pÆi\hž R6r÷×¶è#æï׉‘ìý•§£³wàc7ºÖ)¼È'©ØÉ·)ã»eïß¹™©TsKÛ""ýrÂÈ…¢+¯úVêLd¨pDiTTÀæf¦jnmûäy¼ÙTÕ- Þe0~^¡ïÊéììô Þgªø_AQRK*¼šŽEâ•ø†*®ÔžÁN#zxÈkQ…òþŒj¼èK©Xt²<¥^ªšª‡úŽíu]ùxÔcPÙ`&()ÐwÓU9<?y±2¥ÿRõjÕùò@‹R@“ÏTúv¸Ñ7Ô¥+=™©‚ÌUªÞIGfòªû«>SðæC þª³¿ÚÁCH¡ ñèoâÖµ+Ly Ë)½ÖÉãø žÂTÉ?›¾‚ÔðZbÉñ/þܲu±å¿M'!ðN‘Ù²u±cblä¯$!÷'FGoeÎu#úݽÏW–ØAd5+¼Y/ÈnËž½¦ÆÐorË÷‡#1§qáqàiŸY,ÄúUöæŽ×2gO,…­¯&]áLf(·owS¿"Ÿ­ÿ¶~ºo÷Žc™ÌP.|eµ½ÃÈÁWÞAù0Шún2ýˆ6kÞ̘»2õcskÛ+÷‡»¨(o$ãѵÖs_º9sW¦/5·îid¹Ïx[”£Éxäëû¡Åb±X,‹Åb±X,‹Åò ñdv7oÔaIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_down_focus.png000066400000000000000000000010131463772530400302540ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+½IDATX…í”=kQ…Ÿs×B ˆ6AÁZl’E;Y‘຋¦QÁ_ ¨¿@lRÚX(²‰A CJ‘$k£)RYØ(X%¨‘ݽÇbfÝe£›™õ#Í<0ð2Ü9çÜû¾w    `ŸQ·˜œ‹‚#ÿÃÔ°Ù¬‡£ágõêM¿W¯hé$°’&Îßxl¢{þË©W¦?ÙéEúQ”0†À„áåö˜®®U´µëÖ*ÚúÚÒeä'HHƒ!ó`#CH$üø[[Õ~ó]Ö§µ3Þ ×mϦÞÁΠ‰ Àöìx;ÜXŸÖÎàºß Û*?‹w±n'‚ŠÂ™Úa$áts¾·Z w~ùíž;+Ï{û~7(7wR"®™•º [ŸéhË ßD~”†…è3ï ÝZ­éÑ^Ú™{;9ç)á§ÀA’›:¢;°ÛFךu½È¢›k¸&>äçÀaƒ•†0%Z_4Õ¼¢WY5sO÷ļÏ{8†0ÑÝ–ŽÒÅ75½Í£7Ò?»àS±ã%àDúêC(éÂrUïójü“9·àãíŽ?ï”téuUŸFÕ*(((ØW~¤ø±x‹Ç¸IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_down_focus@2x.png000066400000000000000000000017401463772530400306350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+’IDATxœí˜Mh\U†Ÿ÷ÞPE¡ÚèV\·d"©hTJ›BÒI àJ´þkAD¬`ºÐ­ŠW®šŒÉ¢J5›ÊLÒtÓŸÅeDÒ¸ˆ:s_¡2¹÷&™™Ü™Dzžåùî9ç}¿ósÏ9@ @ ¸·Pº`pÆJþˆ ‰À{ «0 D@ÃÖÇ‹“ú¨9žI@i6©q¯ö˜Fm"êk.ˆöJÉ~!“[gÐÿ{Úç"lëL¶8‡ÒŒGç€R!IäIDÖך¤±jY ésPªø0ö÷À¡T ãý™C¤¬§¤ãµ²–óêl™€#s~éÃë oOû±{_Òß6‚e“ ‹iD`V±ÙOm=cùJ}Ü2ª²l®t^²³µHm†¡jqÁ…©‘¹¥FÙ°­lï@ŸP?€ªõ¤8®DßÔh±´¼×tæ.w#»¸7!áXuVžaG'G 7iGlGn°Ë‘?¬D½ ™ƒÉ€yßœÃå«ùQtcí¬loÿ^áÜÖ×™~ûWß¡«<\|U3öËö\Ú‰ã>lTÛí3æ{&¯zG¯©CÞqbh«yÞ¸ÁÁ[¹î¾ò•“oâj5}ËìÊlvôNðÒOÙÁ烅÷Íj%$$$¬*¿¯8¬‚âQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_down_pressed@2x.png000066400000000000000000000020561463772530400311640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+àIDATxœí˜Mh\UÇç½2©š¸±”´RÄÖ`2º(4~„ˆR”JQWÍ¢é¤i&ê' V°]¨ÍÔ|Œ”D„‚›b]i©L®æM nüÀEi5 ›H!¦SçÉhæ½—Nfæ½IJïoyÏ»çþϹïÞ{îƒÁ`0 ƒÁ`0 ý…xâ]©PÁVpt=„……‚X¢ùÐI÷®´oòõP°¬:錌⠫`ƒ% ¸ë¬T+rWÿöA(¢¨÷¶ûö€Ö®Sm"rhò|® n$ ÃÃÂ×<"ûœÑÞŒ÷ãÀ´tŸjµ\ùØRbPaC&AÁL³®¥Ó#}¹ >«& ÞýÙã¸ÖE`‡§›îÆ9 d9xõÆsËmwFú]½gž>òù-.;=]7HÀÂü/bÛíÙážkwê]öÈ÷\SÍïœR‹Š¢vùF‡ŠÚ¾à…¬j~O¹àaÇ`.}l¶áöÍg~ð PìõÈ‚¸Ž}©!óÙ\úØìZüT¤}ïÁñÍó g}Å/H]©Óñ©¨4yçnÄxã÷TòÖZ}UTe&:›šg€žñÚ±´Â„VÃRi¼žyôïæ•U V‰NÞ Ùý¡X×û zÒI'ߥŠ?°¦‹'Ro£z"À«‹†‚f^äg´÷dµ^íZ$Í8“?nkíøSD^¢4™¢„¸„ à]CÎXïéÚ\‡@<‘ÚêY æ1-× 5TÚæ^ÏŽ%ÏÕè;¼IŠz‹o€V¶ëÒ–]e$¨ÀYôåìXߥê|zFÃI‘xbhÊwÀCžaª¸D?'®ûBö‹þl-:KF ËQ‘–#Ÿ>!…M}Øcª`9ÿ‡kÚ§‡ßü9™ÿ¦³"Oõœ~Äþǽ:3`!ŠÞ2ñ`‘3 '1ë‚ÓU × _Û[ä @òÖçï½pû>C/–H30ó⺠çA™™¢0|Xèõ’ æÇ1|µdfù‰{„½]„O×2j{"ËËË£³;ÁW$CþTB­ÌÏÏŸT>¹ãóŠdòĄڃˆãøG&“~‘7ÃÌÚ <…8Ž¿3å×ßù3UЪ •a¯×K&Æ ÀSbhÍ„FÇáb~a nNN‰£Ÿˆz½íŸ`ÜŒ¶Ä¢æMhe&ŽÃð=Œ»¨nžŒÔ¨ ­-Eq¾ z Ê‹f_™[]‹ã(:`Æ“E®éÍSë/#Q·û,â…i†5´ohÝ3S/ê> ¼Vä%̈¯u`só4»÷+E~ó‚t½s‚ì0“OîD|TVdàîvxÞÇñ©ñè—ÝÀge¥ž[¢à™KKK?MF§w!¾j¢?ï X\\ü^ùx'p¬î¾¼4`aa! ÐNàÄÙÙðÖ€(оT`»€Ÿ‹¼Ë_f¼6`¡Ûý4G·PØ7ü/~™)â²(ú´˜€Md<ÓvL3Ì0ÿ€¥N˜ÿYIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_left_disabled.png000066400000000000000000000010551463772530400306750ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ßIDATX…å–±kQ‡¿ß»C‚‚G,l¬í-­,$·%ÍÅÕdÓùÄBìETâ!x•®wM°ð6XXYŠ­ ÚØè Aro,VÅJ÷í>"èt;3ßüvæ1ð¿›b'\L³#Þë-`ÅèþüŸ¾oÇ,žôû‡üŽžª1.Vñ4MØÎÜ8 MÓÖ'ßy–„ÆÆÐgß¹-8à÷`á\vXÃ'ß1*Z£!\è]\—qÉcT(Ðíe}‰›?‹^¼6@²œ-!=(½z×HzÙ)C–aV·óZÝôÒ “Ûæ03¡ ‰oÐ]¾|oÏÀXùß›[%€ÓéÚ1˜ÀQÀ¸ë¿³JkØò{ïq£‡Š ^Cà `ϵπ½S@LT€çùÝÐN€€,"DåDÅèÞœAÛ*™(AIŠ|ã•Ì/»€ÌšC'˜Œ/„­3 uµ:˜Œ›˜](=s4¸-kKXŒCÐú<¥ûPŒ6n™ì€yœj(Ñxˆ¶ž ® î 0èDŒU²Ž›^1x„€À͈²ËyžÏæÝt4 ö¢åyþUw{ÀË¿0¿8gg‘¶iÌÜÿ®}hG• ˆIàIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_left_disabled@2x.png000066400000000000000000000021651463772530400312520ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœí›Oh\UÆçÍ´ZŒ¶º0¨+QÔP„"Hl'‰A vÆÑ•Øü™P¢EðãЊ"¶I¦ÆEŠš& ¡;Id Š (Å… â¢A­m “¹ÇEyófÀß½ïbæ[~ÜsîwÎý÷˜:è`3C’N`£ÈdG‹"ò2QÕCËsÇ^cÜ ŽAl£?;üB4 ’ ^‰kìt\ÙBonx§!Xæn­p^w@_nì4Xº"’‰+†·dòc·(¦‚°£¬qÅñÒ€üÐ Sn¶Ë;‡¯]3©OnwÏ+zöí»úÒÖ`Ø‘bkù(¼1 §§˜ÞòGú8ÊĸéEá‹’Þ¾zeo«juòà‰™Üè‚GhEÄêäÁz-¼ ð|Éúä!a2¹BÕÃm¤º«3 “+ä=ÒD®ïõN*ß@"ìÉ2‚o‰`°x䵃súó#÷¢óÀÖˆdP·“ÇìÉÝiŒ,ׄyÁ}åpöÞ¹50R®HFš<8ꀾ½ûoL K@w˜$±Ê7`½2ù±ëÔ¬} r[³¢šdå°Ú»ò¶‰1 À=IÁþ-o#°f@OO1Ý¥>îHÖï÷W+‹Å`Ëös“¨ F$o*߀ 䋳«oO6±Ú¨|â˾ ±ɾ(èAüiû0b5 7WØ/p¨Ug›+ElôfGƒ¾åÅö#¾‰~Ð$Ñ[ÞF›Òö ïõÜ 0È3´Î8ñ/Nÿ†Ø\žøxºUÑT\1l Ö -ÍN¾ZlfÀ[boÑ¥ÙòAÞŽòŠz¹l$¥»îê~V•é0)ˆXŠ÷Ÿ`%¡R©dÎï†ù8" žu‚µd¾¯]uYCõófED=꫉œ:5~±fêƒ|æÄ—=ÁzÕù©ßkAíA¼ "üHËIª3S?Ћ°æ‘dMpÖ†•™É¥®ý(çü*ë'D"pº+'ËgMÊ<\lV4 ¡åà|#Z™9ö¥"Y Ö&ç&$²/ÏNœå ¢'%p½1&vUæ&?Dô©&RÖ7F—$z/(Ex©Uq÷‚Lü2²tbòuEÞj#9É-q½ïÞðN®Ì>@©T2µ_»G]óoˆVsô€jµ´Vëª?Žr&"Y5ÁªSS—ÓÛ. *|‘¬ ^°8=}!0éà{ñ¼3 ròÈ/uÕ>àœíX^ðÙ\ù'Ôû€ßÚȱ- o X™yï» Ðàψ´9þ2pz¦ü•QyôŸwƒl†¿Ì„±27± ­#ÔEx-éœ:è ƒÿþì5-Œ›ãmIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_left_focus.png000066400000000000000000000010471463772530400302460ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÙIDATX…å–1kTA…¿3YE *ZØXXÙXˆMؤ±L@ ¸‰®•;!?@,BzK!©|º‰,¢YÓH AMcgdQ’ì‹eÁJß¼7(è©çžûÝ;÷Î{ð¿K¹ ' Ÿˆ ¿·ðëV8þ»óœÉÏ­{4öü 8&—‹ ¹’Ÿ-|ðpÏ+ÀxJ\€«…GŽˆKÀdÉÂ3Øú؈÷±®a#ÿ(@s%.݃IM¨Ðìxé6€­iÉk4;¾Ž|—AÖ¨ÄÊkŒ?õ4òCT® ••üŒu|ÁÑ0b쪕•Ô±UŸòpl¡¤‰¯Ð|â3Á^ŽZ˜ ÉKL>Eð à$©»þ+•šØð'cr´ýg•½‚-€²˜ìa_H¥c²¼jk›¨Ià3FV>ˆÒFÝ+z¥)`GFÆY ’L6[z­ià»PˆdƒÍY½TPè Të·®R—µ†u@ƒ.T†¨ÜÂ‘æ‡>®Që»-ÝÃ^PEˆÚCÔ wl? Q•$Ÿî‡[ÈÓ6#Ë.?n«ÿu/ÌÏS—"Û‹ö¶­Ýo£š6þ ÀÖ”za_—wl¾äôþwõ‹Ê­IsBïIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_left_focus@2x.png000066400000000000000000000021371463772530400306210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›MhUÅgò•¢¨QW¢¸iÉGEIE«U Í{¥®D*Šv!*(‚ ±´bÁ…ˆqaÑ/ZJ+H›]¯Ï7zzò¸v”ÇEŠT߸×#ÏüÝy)·ºƒ08î«y?p^Ò7Äyµ,€uc¾<Ž< \”ÍΫ Ü0æ‹k5Ï—ÝV­èV«ëßñùÆ~sUí5†^wïRËÓ˜õIß9Nù¬‚0tÀµÅµÞÜ” „•㢗Ulý¾ï5Œd\\ç!ýSñó {S¦0Žü²*00é'@'=·ïúÂ;˜ôýÆ{²¾µÊª¡2ýSn¿š2 61.lÑïP%Æ}3ö¾lû±TÜ#ïL*Àà”û,Oç$}›8Ï-îJU*€þi_Ûû禗?òË* À† _AìYàÂt¢˜Š:%6Lú’þ¸4(¦Ìï *|¬óÚ%ù}àÊT »êÎCÁ3`pÌkâšg0×¥a¬R6:ÿ¤ÂfÀÐ×âšßnLú.a¿`ÔÑâBü0œò >ÙýåÀÖÀµñ F÷d“F~Y¹˜âI£GSf{­ ®ó3€¾I?h¼»#J;ܬV¹è›lí~%ë;ÀiŸTŽ3 óBƒöûûª¶¸+UnÓ<è®·•éa2]–ˆBÿü˜€¹êLœËGÌ¢”ëS`¾®—A£I¸rß̰ËòKiW ¢ï†üw‚’›Ç¢GŒßLùF¸ú·ÐYSÐNÅ­£íÀ»™D(,…säZªiði*hÿÐ!…rdX'ÿîŽg"¡ð"ŽèçxI·¾JúB2ª|Y,e>Û¦ï©é໤/U ¡´iØÖ×-t+°ôÕ¾*ƒPê}øy]_ÝœÌÖአ”¾5ë:ìXuàTÒDvù*Y‰›[õ¬»Éž*€PÙ£h®¡·míH™Z>A–§JŸÅ͆öÚzª#py‡§Ê7#Í:Ï ¿˜2uúðT‚*€ä¹ãÑcÂo¤ü’¶ÌÕØ©¸÷‚è>`&“~x pp£–Öü¢» Ÿ¤#Xg0n×¢z5 Mú*p“€ùÛõkÚ œ(£½àªë‡kðmÑm àPCßiðS6ËóÜ,€ù-ú2’6c~Kúʱî QSÖ–Ì©Îþ¿Ì$5·Uaí¢ýù­…ôlÕ5uÕUWg‡þ°QVìÍIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_left_pressed.png000066400000000000000000000010761463772530400305760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ðIDATX…å–1hSQ†¿?}­RA1‚...âР]+Tº©SM–´©à&Šâ&´M+؇ƒ`'p)êæ¢ò:HAA¨`¡EÛ䇤N‚ïÞ\"èÙÜóÿß=ïÜs/üï¡Ð‚ƒ¦ò[Qï;0[ŽÇ÷þi}ÒüèØí](z ¶'kN.”ù‘âõ¾¾þ N¸ä({úóûC®¹LïóŸïg10,í*@¡4wTÃd©u `àÒlÕà*€IÎæ ”kcˆiƒT†³¹7@¡4;‚é~û3~æ^…ÒÌIƒE ‡–±·¹3@áâô1#·ìl;uüï"ó$<^ªNÑ`·)€9d¬À`yê`ÓôÌ`?Î2V`Ë¢¿®-…3‡¬=`¬„4uèÍ5† >´a‚]`™^Ì_þaC‚/´Æ]0ˆÌB¯â‰·¤ÍSÀšZ™ N"ɽÉ×"¾ÂY ‰«Ï£@êìY絃$_BvØnJoï.ÏO,U·u̳ýÃ$®Ô·dæÑq%qåšÄ]Jɵ&u@vhõ@xˆ@ÈI3ÈY®×G›_WÏO]sƒM´7õ››?Î^þ€•…+ëQ£qX} ©ýïÆO2” ok ÞIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_left_pressed@2x.png000066400000000000000000000022031463772530400311410ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+5IDATxœí›KˆU†¿SÝ“1$Aˆñ…¨+Q\C·d1ø]‰N0Ó’žv@|Ð6‰˜€øè6¦{ u4:ºH@Ìtâq!ˆ¸Ð¨„(š ffº~m ªƒÑz\LÿËÿ@Ýs¿:}ï=UÕÐW_}Ͳ¬ø§*Ž6kfzJ`H[;Õg⸮ÇE’Vaôå›0j‚<Ãì鸮í<€Õ¥fÑÌ&AÁj-o§F›Wùh°<è ü¸Æp@aô¥ËÌ4¬ŠÆ ×8ù¸.§†Fç›1\šôXÎUÀ ë·¯È-á=àÊ4Æs ÀðC¯Ÿ37°t/P úбä£rÀp­–ÿ}ðøÁÍ‘,ÆE/*GÈŽ9¯mèî°o"ÁɃ#Š¥ævŒõAO˜@‰NP(5‹ú–Âä!c×– ¶-ꦕCfŠåæ½­¨¯”îü)e ¸¡q ÒžEÆ÷­·ð¥¦ÔËÕxì–}> î÷§T\Wj\Ø,‹„|Sú“‡ mzåòl Xôÿêì2™<¤àšòÎ ¼ÿCC—}gg÷o”x7XmŸk:ù>pEÐWéä!á ¸~ü…¥fs“ÀP( Kô|&J Àp­–ŸŸÍ¿º1è«wÊubò€ZÍ›ýiÕ.ŒuA[¸sçO)²â‘•ÏKz0ì»7yH`,–O ™˜{“‡˜+ Pj–‘m ™3K­¹9SÅ Xjl3´3êËð3ßëN£ø* ò@z {ýé¥×Ãǩؘ©Jänæ¹þú563­ê;H•¨/‘sB¬»@g¢ºÃ ô @ʹú&>öƒÐL»²¬v Pæ`SI™:}Dðf4ÌxÿMÉ$T¯ûhpx71ä„Ä’94Qš—ï> sB¢‰š(X8Ù½Sðy8"g~‰'ñÙîñ_½\îvà›HÈzÕ­R¹ 3¯núÑëÚ­ˆBá)c©•áô®Ê·xº ø%è›ðz ²Qª¿ÃN«ú¥‡wp"y"©/DÓíÍŸøf÷óAß0OTB&+ñáVåà Ú<É<¥|fÎl+šiWÞÆØõMxiÈt/î´ÆÚˆ'C¦¤\Z9d~éLTžCz1dš¡”N‹™SçâcšÙ!¥Ò78¨×ýe}1ò-ùÒ Àþz}aùÜŠû1DB¦ótÀþÝ#äXú–àÖè€ƒÍ±ßæl`-ðuã9à‹ÖÆŸ»yo°ï“ËIŸîØü]­ŽEcqžp°=öÆZ`6èÛÙò—€NklŸ»ø~0Î)Ðymì#உ.æ=›uN}õÕ×ÿC—v>ƒb‰ŽƒIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_right.png000066400000000000000000000010241463772530400272250ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÆIDATX…í×=kQÆñÿ¹£F F;uf’5¥ ­…¥¤‰•ˆ ­…䈈_@¬E,±[D±´°¶ŒÙÌŒÈÚ(ƒÜûXÌ,¦sç…›BOu‹9÷ùÍ™[ܽl–‡FYþÅÀ"gý8Ž?w p3>wTpä—÷ƒñx<¿€ªìÜ÷Ÿ;χÃá½H+ó‡KŠÂÀ›!àÊfV<4Óê`& •kndEq', ,^·FY¶ 3óåÒîmdÅÕЀ 0ôè}–­† 1=‘Þmäùù €j šŒFÎT5E,àüËõ¢X Ø8y½Îóüxh¾4°8Á@•ˆ3Á‡Àfdœ p”÷‹Og’$ù0 ßÒÄ­,ÇñzÆ–¥iøûý“ïêt·åGŸxt¹Ÿ$oên°¯]xù®ŸJ“A“MšNÀ$U½Zë§ñ“†û4š€ÎÌ0ãîb’Þoµï„»Æ.¦q|»Mx}€UcO—Òø¦™é/Êÿ˜WÛß¾^ûs#jW5Ï€Þš›»´”žÞé"¼@[’ÙþÈ­öz½í®ÂÿÀo§ë—6“=v„IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_right@2x.png000066400000000000000000000021531463772530400276030ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›MˆEÇÿ¯f“‰„x1xÉv÷ôÌ®šk\¼Š!‰DÈ‹ˆ!à ž ! ‡DЀ"x0`¢(xCrJBHÂIÀ‹ ‚Ñgº¦A× ·»ž‡™„¥«Wv´ªºóƒ9Lêÿê_¯«êõ0a„ R¾Ù“ý,é§KR¦‡«Žgµ©Žz²Ÿ£N™mãàŠ©þm!LuÄÌ÷úb€ ÔY)壦ú·…1ˆHZ60èb·;xØ”† Œ€K6R-¿Ô ƒ:F1iÀJµL-ü0lt 56. ÀÔ³üµk‹Üè­›páÏ\ý¾Û§ÛívÝ¢æØØ4@TXxëT½þÅeæ)‹ºcaù`EÅÅ‘1¥éqf6vù?X_ÐL Æ I¿ÿŽmíÕàdd@±¶IÒÁžLºÐÿ7í€ äz+¿ÛMÒ]ÅP†3xøSÅv"þ(IÒyWqqf0,’À𠂉Oü$å6—±Üw®H`è™°V€NwÓô1×á¸7`H™ ëIñù$I6» ¤*€Aš 0‰KÝn7rD• WËhl"1µÐéttBµx´A,ƒðPmÍÚ ívû~ÛêP##–³ejMýl¯×[gSØ^7‡¨´YmJÀkV(žˆ@GMixm”-{Û½¹9YÆhìÚ$1èSS^ €Z1ˆðj# >4¥áï%À¬ ž‡ahlð€¯@T21ôAM¿mZÊÇ (œøüy#œ~¨ø Å„˜/ ‡,Pxiƒ@ç~_\|^ün `}𾪠<377·dKÖ ¸lð„ïT¶´+‚¿ljW¾ ¥=:*ËžlµZØÖ¯:h4ûËù…U¾½Ùlþê"€*3€ OÀ ÞÅqâ*ˆª (üŸPâ©(ž¾ê2÷——~‰ óq<ýµëpœÀ4MfðsÍ0\pË]œ]+WvüJ3ŠN¹Š£ˆ³ PŒšÞÊo4£ècW1”áÄ"*œñ˜ñ~# +MƺfíˆûYl7ãbÙ¬ŸïÏ$að’ƒì ´;z„+Pù³OeuǦÅ™ÿ6»sgOÇ·-jŽ›mñcžý½svvö¦½1p±þ¬òÚö™™™ßlkýLPöàò:Xíhµ6õ êÅÊ'3@À-EØÙh4¾7¥a[ŸÌ0÷¶ÂðSýÛÂ\Ž”È~+Š¢/Mõ=a„ ¶ø‚¢HE˜ÚIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_right_disabled.png000066400000000000000000000010411463772530400310530ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÓIDATX…íÕ;‹QÆñÿ3ñ†‚ÙNP [ÑVÄr6Íjav°qQ4),d?H𠈂٠îB6.È"ÎÆÎÂÚÞÂJ°q‰ x!籘 Ø™Ë0)ô­Nñ^~œsæ üë¡q’âzcPùdÚ]û\$ 3o¨z¨íÅ••Có`qÎßö÷’$Ù7@µÝP}š$I¥t€P0Xpeªó0¶$gknÅ—­R™ÂĸÞ\-+!_ßë«%À`i„àÉârs©T€3 ÛÝÚrãB©€uÙ<ùdˆH³ÑAÒøÈØ¹J±Xt’«W ê ÁšðÔ·§Ï¾ ¤g\Á¼2ƒ^Hå /ÙòÕd6OŒ£©\þ›*À ÍÀô~:[ÈÙRñؽ¢Ü»¶|7Rö˜aíXôÞæ°¹j+¾7ÿ ‡cÁ“ˆžmÔ*ïÙRðx˜“áµÆ\ÙÚä P!wžã͹ÊB>A³‚9û¸wÛóûvƒxV´]]÷øò˜š,•J!·ÃãÍ àÞ²Nþ›Kjô±gfV\éza3™ïg(µç»Ïµ]jG¿ˆˆÀÁ=ÿ›^áÝK å\ËG»ˆhµèõáÏX7žZZ¨ü%‘BdôR&ϸ ˜Ò§æ§—Ê#*ˆMíK <òu­|F2y¢»ÒÙV½ò½t:Ò´¡É z²9÷aC8ò(ã°cjÕÊŸ çqÉc0 æ—õêŒ`R+ ¬§§Q¯FþLƽ¡Í Ï6kÕá ¹×Í _¬œ¿} LpûP2¬­]¾<Úy|y¹Ôq¥;(.J;»Ÿâ›Û{—ggÿs¥y=HÁ_•ŽgOœøWHoÝHp–•J5NNÿ- 506ïa?\žgt«6ó‡E«8ùdf•‹š)Ó:YùÅ¢†uì}4…þW_Ì ~t©^þÁV|WXüjŒ‚и àæ\uÉVì!C† qÅÿ¡2½)ÒIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_right_focus.png000066400000000000000000000010351463772530400304260ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÏIDATX…íÖ=‹SAÅñÿ™Dñ_:A+ µ1aKI³²Ye×FÐÖBöˆ,~Q°±Í.q±‰I¥Vk#Ø(‹ø‚&s,æF,s“0ú—[ÌÌùÍÜgà¿^eP­?É(ôu¨³¨Ó„QÉìöĪÛG×½3;àšÙþÕ¬xë_8=»¶Ä» +®d`"ÂXçßUâ-ì‘zhj clƒ¤ËõÕ¸œP”˜ÞtµÞòRnöo„oÔ[¾ °Ñq§öȳY a¨?¨­úTV@B(’ÛÝ>Ñòñ¬€‚šsw°ŸÌ¬ùpf(5¥}qà§'×¼?+ PÄô58Øøq~@B ëX~€ …`£ZѬ‹@Jÿ*:ý|Nï3dl5:sz;êÌêÄÑ8 øî 3½¦^•™?Ñ ØR>0Zè5õ¬ìcŸ€$§ H—zój³Î¸' ¥¦Ch©;¯{c®S`#îÜ×_œÕÍqÃKœ~Ò]—ow›áÚ$á¥Â!õœïw_†+HÎ H;gýs?\d¹ø™°Êނη:÷¦¡Ó/ØDVøf_7ôeZáÿ àž¤@—ñœêIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_right_focus@2x.png000066400000000000000000000021301463772530400307750ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœí›Kˆ\E…Ï©4A¢ ! î|¬{Ú¸0™€&Ý‚àƒ® $ˆL@\(øBÑ…(ŠÝó@&2Adzš²A\Aƒ % é[ÇEϨÜ*5TUØßò.êüÿ¹UÕÀˆ#þÏ0Ô@•¦ž5´O‰”,,7x8ÔØ1 fÀD³(@šÕQEpÇR‹¡Æ… 6ÒZò PÒÜÄ´¶?Á `K—6@útë¬n¥ƒ`çòƱBÇoÑæP:¡ ·þ™ÍÆjaËœ6&ИÀã…ŽÝ>« ‰ô.˜h¨¼$„­½B3“óº<–æÅÍtêÂŽÓ]½¿ýsÇÒ”¸K@°p‹c½{Ú¾)ØäRHQœ™ ò¡jË>Ÿ@û?IS«rI T¦u ‰þ¿ji çšôBµ©‡SÅà#™|§Eˆz£ÚR=Y%Ò€þiÑc‚ôAõcÝ•2–?ÅS Ðêîðw.5sÛ´*©ãIn€ž™@\a¥ùjK7¥ e8`­yby&\#èø¶¦®KÇÐ è#Ÿ ×Ô¶–6¥ˆ`È}T>-^_@Ç&æuelõ Z§ynQWsÛßѺ˜Ê™°Ú<•L pǹ«ôaÌæ)Vñ5O÷vÏØ·ðŒ¢Ä𛀝y¨Ül_ŒÑAæh@¿.ÕE‚OTZ8Z*O€t›'êh¥©ý!eò5€[®¤^›hj_(¬  ïÈ Ô+¡4²6è/{Á¶Å¼ ègïÄ(èíPÙ<õ"¹×øØrüJ"ãàMþévƒÁ’r4€€ã¾¹×Ëí:Ž„–ËÎ †*g¯÷Ú'Ìã }/`/‰¼ K·žÀ'½SæAvž!' œ;/ØãÔÊ~ž%šÉ. ãÙñOôz¼geŠçb*Ý,O{ßaœw¯Ôy6¶þP—@?y§Ïÿ‘†;Û{øSІg€àKþŒµÜµTãÉTa Å KÚÂïwwöñë”±$¯ÈròÀyÖÛ5.¥Ž'é @ÊÑÉûÛ5.¤Œet3€„gÍä£K5~”,ŽÉf€dÝæ†<Ô®ñÍT1øHcaèlõz©½CÿL&…îWzw¹fžŒÑÜ J\úÕ¾|Ä]µy$‡ä¸Júš›ÅõgyßâìÅÒ”h»€s¾¾Â:îY¬³KóbHµ |;N¶wó×DzL ~èõ¸óË:N 50!˜ð=Áÿ…க)~J'4Áj]3³âd§ÁoBiÄ äøë™!Kîí4Ø 8~Bþ4u@ €ø\§ÆÏ‚=bĈ‘ønþN~àÆ%SIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_right_pressed.png000066400000000000000000000010761463772530400307610ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ðIDATX…íÖ?haÇñïó^b¥‚Š]DœüÌàà(]ê$ÁEÑEÒÚ4ÁQJptP’Zk@u‹[ÅÑ¡ mÄÅÉ¡“(HK‡Š5Éýî²8Ý]ŽË ÜvÏûûðÜûÞüëeQn:]®o€Y¾Û9²üèÆzšñ¾½ =\®uüò]ÃôëÌÈèÈËc¥¹Ã Ý7ö¤Tzáeø`.®}k€"í¡Ô¾$¦Š“õZ¦€a’á»U,7f3˜P€@÷ŠåÆ¥Lð×$ÐãÂäüD¦&à9ùK…©úÙL?Dìt>­âµ»'³„Éì–ó^®ß?š-0Sÿ±ßz½·§*ƒ™‚ N†Áa×Ñ«!Dˆ81€90k½¼ŠÒ‘K+Zà,ø6|—çû8?ý5J_ZpüÜl:o/L‰Ü˜F8Aø/ßqþýÃê§8̓> ¯žo®Ô~PywÄÉúý†]m/VZIÖI:3™˜]iÎ,Vç 0p {¾z`}&|÷T1÷€aðfkãÇš5Ðpˆ¿–·n_ø¼TûF8Dœ€`ÓÀòÝîÄÊÓ›[i…ÿ/€?”¢cÅû‰IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_right_pressed@2x.png000066400000000000000000000022121463772530400313240ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+a YÀþ¡GÞZaSÛ @…t&·Í•~}ÏæåÉ’a‚àžÇú÷ Ñ°«_€ˆbêIòáðèÊ—lÜ ý3„€ Ô^1>–›O™VóЀED$ÑÊ¢`{X*&u¼5€2ºE€˜ +Ñý¦t¼5$»eMS^àLuÏØcÑ›—“Y,-=k“Þ4¥á¯(¢Þlj·jo˜’ñÔImñ¤<7›[<ào ´Dxó6ÓBf€zåãÛí+~Ü’ñá¼ñ+mñ~H®Xñq½'0€GHAjñ8T¼0y Wl©úqˆrúÎøœ\~÷§;ë¿Ù”ö!$½ó ¾.&êÎN\ùÙ¶x®p±× RƒßƒdÍg{ÆŽ¹ˆ!Ï# ¢oÀOÂ`íá]õo\‘KP2v8¡ÜÕÞ½ù —±äa€5Ýó“õîƒqüq”Y;O>Ô‰ëS.cù §5@ ºádµÝ}ße§â2 韞‰Gc‡1h81€Y;¼ÒnÕsÿ™Œƒ# @ëòövZµ'm\nºÅvdÜìðAß•Ç7ø°xÀb$ÝâÓÿÑ÷àôxý¤-Ýn±ùCÉôâg %Ü;½÷Ñßmiž ®ƒ_Í˲uGš#¿8Ò;k\ð©Öiüà@«kLþa"ëþqUHÖvâ±oMé˜ÆXdÜìæD©u³­-_šÒ°Á øç!ð¾öî±¶©ùmað_cÁv!@€/´[£Ÿ›»G=,ñ'¯C¯^ÎÃIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_up.png000066400000000000000000000010051463772530400265330ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+·IDATX…í”±jQ†¿sGBˆ’h½dÌŠÖk±•âˆIg# >€¨¯ `ð …ˆÖÍlifææfSˆ‚6š½¿ÅìĈ»1;.±™¦™{ïù¿9sf ¡¡¡á?cu†ZûÒ[D'1ZišîÕ©ãêÚáÒ~TÑŠ­!\<<ß½ìbì+ Ê‹•$ª—e»iëMõ ²k&6€E@‘RÁj}•±v!Mß·æ±;°íýª‰Í*ˆÏ_ŠX2±YÅ™ d>ÜqØk`¾ ³­’˜—¹7EnÏD ÷þ¡ç@š~ !! ‘éEæÃýÚ’,÷þ1Ø“ª8ØQá˜ÍJICë¹÷$Mœµ± ’\º‰{’0³ª½Ó`’œ™aÆÓóËËGuŽè÷ûs§Ï,>ø5ºU'üpý²ËâåçOïv»ÝƒÁÂ÷áðâú ÂeÈñn.In¶Z­oxïÏEÜèJ9kDÌþ5¼¤œ‡‚-‹ÃÕv»ýàTµ'ÊrLK¥–AÍßôXìW£ ®šK àìo!“çtöüõSjhhh8I~Dë±fh›?IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_up@2x.png000066400000000000000000000017471463772530400271220ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+™IDATxœí™ÁoEÆ¿7»„Z. ‡ÊñÚX-gʽ¥"ªz"9öUPq¨BBPÎHU›rC¨è©µ”CýPÎ8 ÉÎîÖê!åNZï~ì¤öîàØÎî&¨ó»ùß¼ï½y3žI‹Åb±X,‹Åb±X,Ë«…U`­£  Dp§îy7ŽBÇ‘`;ˆ® x €Ú³‘rm©^]+[‹:ø+ùâÁuo§c‹ðŽD_”­§´ )AÝ$ñÙxAü¡æy×E„eè*¥mÒ­Ñm>šÈAð“®V?¹ Ò+XZñð}âüÁ‡ÃöÁò&ƒ*#Dpq|¥ÑhüS¤¾BÏ€ÍÍÍ7 ÔÃtò ¡€X @Ä™~'V ÜÎÎÉ"5Ö›OŸ¾é<ÑàÝ‘ï÷À蘕$Àãs¯]nž>½S„ÎB °µÕõ”Û[äÌh4!€s¾‰()]܈]÷ƒ·+•(o­¹@kýD­XLE"¸¿çB´EHâåF£ÑÉCçKY9²†ï)¢àTj¨¿òÓa*Â߉àÒ[ž÷xV¦ ¹ÁE‡xSò2uòø¤÷Ê)‡hk­ßŸQf†\  u´š@81l'+?Ë•¦ï“ æ6Ÿ ¨–ÖÑÊÌ‚‡8t´Ž®Rø+€¹a»™eåSüÇë;nÐ÷ý³PÎ:€jÊÉÜ‚GˆŠé|!{ÎòÒRecŒŸ™­0<ç- )‡c—üKDõÿÄ0dž x©V«ýaò0‚Z?¹àítòqòÀ©·6…hû~tÞä‘é†7@|i§ÿ9Òÿñüªîyߤì£è ìpÊ“VÄõšçÛJÿ¿Àq#S€Dð- ÇxŸÏŠ$ýÜ,‹Åb±X,‹Åb±X,¯6ÿ–S^ÀihAIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_up_disabled.png000066400000000000000000000010451463772530400303660ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+×IDATX…í•=hQÀÿwýÂÁ(-:t)Úê±›¥PÄ$”ÆÁæNð Á&Ö.Ýœƒ›{· ÒÍÅ¡JD¬‹é"ØQ'?&ÇÒI8Ï{‡\lBªM«î·w÷ÿø½{ïÞƒ””””ÿŒ$M¼äÝulô4KhG_?ü5I“$)WZœplØÍÐ/oaüŸä¼Êyˆ c (2fU…«w³*PpËÓX|à ‘@(ÊIkŒ_pËÓ"w+E«¬ƒÕæÀmÛk ª@Æ*ë—çæþª@®T¾¥ªkÀª*ÍcĪ¢Àˆ<Ë»•›½Ôvö È—ÊË@ 0ŠªˆìÒ}Ø|›T@r¥ÊCàQ|k¥µæþŒŠÄ>Âìø¹ òñý¦¿/jµjF&V€q©Ö÷Œì\fNŸ¾}íÊ+ß÷»jtmDžç lÛÌ*p=Ùwó¶òÚZgO¶†ÍwµZø[bñÞ‘`0z 2‹F,š´ù/QUÓl¤/Ç­×kߺæn,ÿ„uàbüÈÒÛœï퀈î|‰0úQ|³¶º Ð× ‚ð³@¦-/Ñ6½Ú9Ž©~§ï p¬£IâS)%%%å°óÿšXð7Ÿ IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_up_disabled@2x.png000066400000000000000000000020621463772530400307400ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+äIDATxœí™Ëo[UÆ¿9¶K¡B$l© AjÓvã´¬Kì‹ÚEZ?²€,ÈÃüˆUØTB¬BB¡$,²0¶ Œ¬¶‰ha(ÞÕT*F¢Í XTUÕ¨±Ï°H×÷;~Ük1?É›™ó˜ù “o¨ÔÚžö*00A)A)`à¨ðj­íé¿b ÖòŒ¢W€CÆDœKCt¶WôJ­é‹#5P_ôMá60¶LÜ#ˆd3“¼ÔhùÆH 4Z¾‡ý¨Ô'¾ÅFÌb¨?k4}·¸[õV:kü(ÿŒú­xnEçq–çÍô!ö®—}ðƇz5Îî¢6¦½Gœ½ ûñÛá>³ýô81ï}“øtÝY¦( '¾iÂ2?ï} ·Önk}W§^ø@Òóp!·"CV>C.õª—èÚÚ%ýè3pnÙG~v½,qÆ€L¤`å;ÙÞ :]iæý}H6‚Ö»þ$1¾éJÅ~ÓƒÐöAŸÝoÖWàÑ»'ì§URRRòG~Qãºr”/rÅIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_up_focus@2x.png000066400000000000000000000017361463772530400303170ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí˜ÏoTUÅϹóÒÔ1J݉.uÛ™1Ædª˜.´ÓìýTâ‚bBü±6!P`EL ó¦¸`’&2$ØÈˆ¬Õ5î$ã¢UÚ{\Ì€Ówo;¿Þ›©x?Ëûîý~Ï÷¼ïÜwï@ @ ÿUâ|EeR_0.4r§G¡c$ct€y,D”s$?Œ=äìí£ü5 ™0yU/F‘VHd»ãîFÈÑõ³5<|wŽ÷S–š¾ÅX‡­x!ñH ,:íí$ºÚîË#߽͟ÒS›ò9`º¢iA·á+]ßšIÀ‚ÎìýÖèÛü’¦RÛ"5¦«zÝP7ìkÔ,¾W 8&ì£Q=ëµ¾…&HÅ€b¬y#ݰ§}\ö^ü¿X4 lg¡Z¾¢òq3°ùªNº`¬}\ °ø´r㌑Z*ÄzgÐèõ¥ÅdœfñΛëBò˜`],Äêp´î»$cû©Hçò"ÀÒýí¦áyi‚>û¾l>êçþг¥º¢õßì9‘'\!™ßÌ!ôš°øÒ†yïÚÑíY~z2 tYãkÏè €ùDöfñî§+$€ñ¨Ÿç±Ú,ÿê6V×¼r]Oolj€ó j]j†R|[No'ø&—c¹ÛûCWL~­‰hS5[!ÀÞZ.UHÀÚ¸µ wFœ½÷&t ÑiÂô²ö«ú;àdÿþð#Ä#þ²ÓÒ?ƒ//é ±ZÅn.ØîÔxˆF«S×uÀ·äÛv@~IS4ª˜pÒí¦âÛñwÂo4ʼç[âí€BE34ª#Q¼vsñмj';aR½XUÉ·Äé€BE§atÆãäp·ùqÄ‚åÇ~²ã¼bl7øþžúÏC`óμ‰ÚÇ<'ª'_mî@žmíªO‚yvÔ2@ @ £æq©^ÍýØ&p²ðøPÂ/0Î{.Þ–@jŸ¸¥ÆZsúÝüÝïñ_‹¾ñj›)Ôoºû|.žˆBÈ»`ïô¥±ýá'h꘠^nCÞIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/arrow_up_pressed@2x.png000066400000000000000000000020351463772530400306360ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÏIDATxœí˜OlTUÅÏyO‰…ÔDª%îÀ¥}oêÂÄ t¡”… VÂ̈±ºÀ°Â±1!!ÈÌ ŠHÀ˜5ʪ%P¨‰iG—†Ä•ª‰’˜©ßý\0•y:o¦â÷[¾oî½çœ¹÷Î÷PEQEQEQEQþ_°S ÷ç ÃFx €Eà£ÙGtB‡Ý‰EÓ¹â~`€.Ïmvvþòkéâ·íÖÒöœlñ0€B»ä‹=é¡…ù¹É™vêicB'Û}œÀÛU>´£ÇÝõÈ|iâ+`¬-ªÚr äóÝúmã€#5 œëÚ|#{elìï„¥%ÀÀ+ç¾µöægv‡k1AÀŠÖøåú;]{¯|<òW’ú à™×‹üE\°=fer_…ì°—SwvÏœ;|3)‰ðôHñQ{ &A8ÁŠ «DÄŽ‘4ç/bè»ó£¿'¡3‘œÌÉ-¤5`k¨$Lu9bÅèºNÛÞ1ûþk?µR'söš¥ïà{O‘Ö ê6¿ô€*lߟq2Þ¶Vé\¢¥¤œL[¾}ÀÁ k0_‰Â!ô’r­?ë¹MÊ Ð²ÒÙ bY—lª|.¤óe»6Èt_Î{¾ ©Z@:[Ü#àîµµ•YÏ7&v'tY"“ý¹ÂpãóÞ§éܬ·_€q©@ážñ&ÌW'e„Ÿ»¹â¾f§oªv3Å·@xˆÜÚ·}›B0¸¼ô¸»óö|éâ×ÎÛ`B7³ñÈw"À°Åæ²s †Âæ`»kÝ|iâR#ïu÷å¾þ4Àýáš@1Xƒ %ztIœ}òÆc¹ññ—£MVê  Ü× `OT˜J²æ+Ö"…q÷צ°÷oôN­sÕÀ³ûŽ­_\³î‚ÁŸ „0Dä¶Nˆ áÒÚ» õ¾?Ô€“9ÑM¦&›ôÛê<Œˆ½0+fq¨tæÐ+ _1€ôÁS½âûSBm(kp@@‹ á÷¶‘ÁoÎŽþ\mlÕœŒ·”)½¡¤ió®_Z‡üË Î}ðæõåF-Ûõg=—”«ˆ5Uf(ïÆ°¨-0Öµ¾W NÜ`™œLa»Lè,%ó«#Ѻ-Ãi7ç Ä ˆt®pDÄ‹ÙNÿq(¤ÉÏž~ãÝʧÑÿâ óžy Ü©äÃO£Gà´þ/1Þ¢;€<*­x‹[e`„<ÚiŠ¢(Š¢(Š¢(Š¢(J§ùîs?õ¢WIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/base_icon.png000066400000000000000000000023501463772530400266230ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿr1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDYØ !ŒqÏ¥¬¬•Q¹ Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý ÌÕ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ— ´/Imеá–]ÃtåH½I±Î¿ ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ º ¦®œfÚ×â=åï1ChLûc @P× Þ¹‚2Û ‚ú»56î{½ýÊŽ|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>kÏ–¼¿Ú…í QW Ömõ°gÀ0}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þo2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕìËiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/base_icon@2x.png000066400000000000000000000063261463772530400272040ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{ý£}*P´A6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w¾ÑþÜ©*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾£ 4Šï?÷4Tý÷%p—§P9òmS¨ ŸÿÄÿŸòmh§¾})è{îq1o…R’- @V1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö ?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r ΛB}oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™~‘ ßx+¶ŠQ@ɘµ¯² ®]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=záê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§.Hxfû:VîGèÊ­c ¨/’Ñgîä§ñcXy .*PFÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ òÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'Y 1a5rIH™GƒeOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàKª'à%¸C4Ós–ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·ºôHe H .åã( ¾óGF{e%´òœ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 1œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! Ñ$ À£ý2b…»}4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌòš¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa([9ÆHrç9my"è“Þ')ƒóIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ùæ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡ÁÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœá%^œ(Ιew1,S|¼’…œYµp†*—rA†8î»÷O·ýWÐ8Ósúc¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ×í+rJØîí°õKU\²8ž¯/Î]I#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— —¤ NÑøü=/„a‰!­5 ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N÷óÖJ>dŒ¡C #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf"NT€ì£µ?÷Æ— hÝF›%à¹î°œŸ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿFfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­À}LÁÑ÷Ùë9qž¶øÌ“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­äŸ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/base_icon_disabled.png000066400000000000000000000023501463772530400304520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿr1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDYØ !ŒqÏ¥¬¬•Q¹ Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý ÌÕ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ— ´/Imеá–]ÃtåH½I±Î¿ ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ º ¦®œfÚ×â=åï1ChLûc @P× Þ¹‚2Û ‚ú»56î{½ýÊŽ|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>kÏ–¼¿Ú…í QW Ömõ°gÀ0}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þo2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕìËiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/base_icon_disabled@2x.png000066400000000000000000000063261463772530400310330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{ý£}*P´A6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w¾ÑþÜ©*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾£ 4Šï?÷4Tý÷%p—§P9òmS¨ ŸÿÄÿŸòmh§¾})è{îq1o…R’- @V1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö ?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r ΛB}oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™~‘ ßx+¶ŠQ@ɘµ¯² ®]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=záê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§.Hxfû:VîGèÊ­c ¨/’Ñgîä§ñcXy .*PFÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ òÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'Y 1a5rIH™GƒeOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàKª'à%¸C4Ós–ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·ºôHe H .åã( ¾óGF{e%´òœ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 1œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! Ñ$ À£ý2b…»}4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌòš¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa([9ÆHrç9my"è“Þ')ƒóIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ùæ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡ÁÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœá%^œ(Ιew1,S|¼’…œYµp†*—rA†8î»÷O·ýWÐ8Ósúc¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ×í+rJØîí°õKU\²8ž¯/Î]I#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— —¤ NÑøü=/„a‰!­5 ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N÷óÖJ>dŒ¡C #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf"NT€ì£µ?÷Æ— hÝF›%à¹î°œŸ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿFfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­À}LÁÑ÷Ùë9qž¶øÌ“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­äŸ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/base_icon_focus.png000066400000000000000000000023501463772530400300220ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿr1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDYØ !ŒqÏ¥¬¬•Q¹ Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý ÌÕ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ— ´/Imеá–]ÃtåH½I±Î¿ ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ º ¦®œfÚ×â=åï1ChLûc @P× Þ¹‚2Û ‚ú»56î{½ýÊŽ|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>kÏ–¼¿Ú…í QW Ömõ°gÀ0}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þo2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕìËiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/base_icon_focus@2x.png000066400000000000000000000063261463772530400304030ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{ý£}*P´A6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w¾ÑþÜ©*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾£ 4Šï?÷4Tý÷%p—§P9òmS¨ ŸÿÄÿŸòmh§¾})è{îq1o…R’- @V1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö ?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r ΛB}oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™~‘ ßx+¶ŠQ@ɘµ¯² ®]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=záê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§.Hxfû:VîGèÊ­c ¨/’Ñgîä§ñcXy .*PFÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ òÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'Y 1a5rIH™GƒeOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàKª'à%¸C4Ós–ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·ºôHe H .åã( ¾óGF{e%´òœ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 1œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! Ñ$ À£ý2b…»}4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌòš¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa([9ÆHrç9my"è“Þ')ƒóIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ùæ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡ÁÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœá%^œ(Ιew1,S|¼’…œYµp†*—rA†8î»÷O·ýWÐ8Ósúc¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ×í+rJØîí°õKU\²8ž¯/Î]I#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— —¤ NÑøü=/„a‰!­5 ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N÷óÖJ>dŒ¡C #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf"NT€ì£µ?÷Æ— hÝF›%à¹î°œŸ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿFfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­À}LÁÑ÷Ùë9qž¶øÌ“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­äŸ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/base_icon_pressed.png000066400000000000000000000023501463772530400303500ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿr1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDYØ !ŒqÏ¥¬¬•Q¹ Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý ÌÕ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ— ´/Imеá–]ÃtåH½I±Î¿ ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ º ¦®œfÚ×â=åï1ChLûc @P× Þ¹‚2Û ‚ú»56î{½ýÊŽ|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>kÏ–¼¿Ú…í QW Ömõ°gÀ0}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þo2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕìËiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/base_icon_pressed@2x.png000066400000000000000000000063261463772530400307310ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{ý£}*P´A6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w¾ÑþÜ©*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾£ 4Šï?÷4Tý÷%p—§P9òmS¨ ŸÿÄÿŸòmh§¾})è{îq1o…R’- @V1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö ?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r ΛB}oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™~‘ ßx+¶ŠQ@ɘµ¯² ®]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=záê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§.Hxfû:VîGèÊ­c ¨/’Ñgîä§ñcXy .*PFÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ òÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'Y 1a5rIH™GƒeOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàKª'à%¸C4Ós–ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·ºôHe H .åã( ¾óGF{e%´òœ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 1œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! Ñ$ À£ý2b…»}4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌòš¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa([9ÆHrç9my"è“Þ')ƒóIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ùæ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡ÁÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœá%^œ(Ιew1,S|¼’…œYµp†*—rA†8î»÷O·ýWÐ8Ósúc¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ×í+rJØîí°õKU\²8ž¯/Î]I#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— —¤ NÑøü=/„a‰!­5 ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N÷óÖJ>dŒ¡C #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf"NT€ì£µ?÷Æ— hÝF›%à¹î°œŸ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿFfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­À}LÁÑ÷Ùë9qž¶øÌ“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­äŸ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_closed.png000066400000000000000000000006121463772530400274660ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+"ô™¦ùYUŽÄ Ö¾#¤ êBÔâfM¢çð—Ù™Ž8=ˆø3+ù8‰®˜ªTvtál̨š·Ìm²ý¿‰ ôõÍ…„Ý1£ÛõÈöO¼è7Í÷ ‹’í½) „áT¶›¢€r¹¼Fjbõ„^ËöN¼€J¥ÒE©ôcùF7ò–‘íŸhÌœªá8€=:ïXB\W‘!Ñoú6€£M"ã©mš—ˆ(ö’´Ñ$V€íº£6‰„·‹?³'ªr$rrÿ8?lô'`:eÐ^!DEeåؾ?Œˆ'dWT^`ÃØWâêŸwdzj4F£Ñh4F£Ñ´ãoÜíz5ïõIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_closed_disabled.png000066400000000000000000000006521463772530400313210ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+\IDATX…í”?KBQ‡ŸW­M¬!ŠZ ·lrtp mhºÚAß IÎÐÒ'¨Tp 2†Z¤¾€Ðä”ÔÑSCê=MZ÷\¸K÷Ù^8ç÷>¼çøøøüwÄéú´U°£áìýMµïV àdq±XœOC¹\.è©€RÊFôö¸îÛ‘¡§­zåJàx\g¬Â££>u;íX<‘–ùØJb¡×íÜ™d9½„H[= Ò4¯ËçN3Áo’«K“ já,³•Oy* ”²éð„I)ßj6ójúcBÚ쎆G@x•ɨ¢Zkº(+‡›L³wCÏß»·ï' 5†Ñ¾-e»GF‡ž½’™° ˜áÕô6'Œ:¥¼¼;~*3‹%€WÓGÌ?dÙ†T"òIVË >#ü¤+]O¢—3f³¥ÆÒ}øÛZZl¦¯`é)Hº9–0 f³ÅtÙÌ«éßed°ü$Öw3ø•0¾Ãd´ªJÓo‰ö·¼Hv†9AQ'À1ÑÞË¢ œ[âk…©Ïa}=ë2õ‹ö¶¼€ÚÚfµ#`óœÇùT,T!ÚßÒü~¿mÚÁ:@°'_'à­©x( #ƒ¥L°ÒK8’¯‚ÓãO0=$-5…›ÎüÊ\•¼pfs•2ßYó0Tßt„Ç þsÔ¾·'zmLféTkÍ嬀sVã@šûÅB/eç‘úà©ots°»È»x3”A³ââ‰òŸ\Cˆ­ Àœ³??•ì ¥då0"¥Ÿ¯Å‘cä¶åëœð ÉX8"#ÃB/ ÐWæ:* £o‡Ï‰ö/„ðú_Åìƒé³O9uHÚëÿ…Ð]Àçkq̸2Jòä7ÅŽ¢Š{W¥<ïBè ø²é7ã@6_²åì5ËåâÁ¯Å? 0wÙ®aÂáá%uÉxð­HO…B¡P( …B¡P(ŠBüêÝSçIòIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_closed_focus.png000066400000000000000000000006131463772530400306660ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+=IDATX…í“?/Ca‡Ÿs[ÁЈoÐ]b»ÚÉb4H+lÂfð $:X|ÒÁªôv1K,¢Ô,¢“„Ôû3PMl÷½É]Üg;É{~çÉÉy!##ã¿c±^KVjɼ›MÞT¬—T ˆõzg(<*½.5”KW fNØò |Ì«Ÿ®Ð©Ú©Ðî .E®›ªÀ·Dn ¸ø)§ËÑ羯@¼#üC)r&Ùz»bGq3¼60 ÝµáJ‡aS³© P37Þ·Âo˜é2]à>€{ßþd’F\(Ï9Y1Urä¶‘­o˜Í_-ÚCÜ ï_0iÕÐ1à„-tªvî“ãµ°¥9Cua¾Ã½Â3MRÈ›´×©Úïðø’À¦“ëÛ`3Ép€|܃'àn¬¬Q3—T ###ã Fpb¡›SjIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_closed_focus@2x.png000066400000000000000000000014521463772530400312420ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÜIDATxœí™OHTQÅÏyóÒÑ IˆAP­ªEá›0!"%g,#ZTA´iä¢v´ÒEHXŽæb"m¡ÏrQ!Dÿ% )øÞýZ„1ž ‚÷¾ û[~æœ9ï>î;€Åb±X,‹Åb±X,–ÿ ê6ðraÀS@òÜD†½º=WƒÖöHr¡AJ†ÂC~Guú®G맯‡[1£Œì{ Ûµú®¯€’¨¹›à†ñ4çuûWCï °5`å*„2‡nÑî_ íîw2D’ Qš·GBÝþÕ0òü6Î9 îˆÒ¼œ3‘a%Œ-ÁBšoy8Björá S9Ê1ú>Ïð‰+^Nåä´É,œã0MåÂ^Ï”ÏÒ+d8i2K,€—SïTœÜ·Œ§ùÅTŽØ V>#8ë \ˆÒÖšX÷áàk¢æÊ•Ÿ1òpb-`ª‹KËMQš7(ßMdˆý$6uŒ3!¸+BjðÃ{ºýc/^dù`{… <©ÛûŸ(…éX|ã0-Ç{(›%_>Á3ÝÞ±°wXêÊ0ˆm%åÚd‡Ó¬Û?ÖNôK ¤@S©"·ýv§ÛD†X øàª›ÒÅ3Õmt.€Œ<$­5ñ…åDn•_º ¶˜¼)Š¥€¦É2PæÿÉ ˜*tò³É,Æ H ‰'JFÔç¡xÀ?ÎW¦ó$Lšý¾ –ÅWdÀ´ßÁ‚É,ËD^Xê`¿4*GòÊÎþìò³|l*G9FvÖ¼Ô*W†ì,D®ûYÞ1‘a%ôÐ-Îì¢êÐR*È]?ë\Õî_íx»qeù¿Á"ž6&ó¦öú¿¡uhÍKíì¢ü,¿YWÃæ±£4ò{¿ZWÀ×P–ŠG$Ûþ•/h.`ª‹KϘ0­È#¾×éi±X,‹Åb±X,‹ÅR_D”̾Äù «IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_closed_pressed.png000066400000000000000000000006371463772530400312220ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+QIDATX…í”-HCQ€¿ó6gÑf,¾U‹˜M³jqOÐMŒ‚à^°˜ÜÝÆÂª›Y°Ï¿dS›ø“Š»Ç´‰ñݯø¾vàü|Ü{î…˜˜˜ÿŽKWq½]ðýÙºª¯}„peoºÂÉžÄ{&ÓHD+àûFUæ:á]êñ;Z༚;Be«»ÙÒu¤ÍjnCàaÂõж—ð/®WÒn ê5««Õ =¬N Csäõw E*iog*R|ß´‰þN¨8gÑ ¼<)ÜÛ–‡Pé® ŒOí¤3´C¨Ä]J@ò@Ë8:s¹Ÿ¿ ÚÃúLf‹ó"RŒgö¢¼rbÓ'iS”öŠÓŠÔY¶;^ÜWäH¢º}^É•m‡[¨Ç4€Aà°9ú¶f8X\Àƒ ·}Ÿ øyV &&&æž5a7 meåIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_closed_pressed@2x.png000066400000000000000000000015431463772530400315710ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí™_HSaÆŸïœÍé +’¼RŒ®ºÚ™V&D¡7aÑUFâQk³$è"hu™m‘szI&ÙEeåf”Aöç¢4DK4ûûvc1·cCðûŽÐ÷»Ûûžç{λwg€D"‘H$‰D"‘H$’ÿ Æ[@Ó½½Žc81ìw÷ðÖ\ \ØS×ûË6N­ÑÞP e§îJPx¾ù”}Á’^cŒ=ÑšÚJyê®2ªÛbáõÏ»ÎÏóÖÏ× €’ESkÞ<îúÙàn ¯ïHBÍA¾QOû¾!Á[?B®À+Ÿ{.©ª[zšî}&ÂÃrÁ‘›§ÆhŸA«Ò¡û®ˆò‘Ž*Rl"4ðy‹³z@Mj»ŠÕãÁG£"ý,j‹ÇÙèë!¢ã †Š ßýZ¤SM÷}(cHXYñ›® Q>L X~G°Úãö¡k­a£Þjcê}˜È–cT-XrqL ÐcDÑMF=M÷ýáÁôM,87 FÛ Zùšî½Ã[ßô èoyÐAƒÖQÞÚk" RÆÌÐ]TÔ·ofŒú3 /xk›€£¡ÓžP•JRëŒÑ¥ ß]É[ßÔjk戴Ez”§Ö ¸5ìw{Dx05€O…“WH+¬+ši˜á’´Ú˜¶ :u_ ÚSk¼Í…«D>)2%€òÆë‡’Äî¥éµ²øŽ!ë7‘^„àhh¯`L—RžO*ÉÝ#gÞ‰öcø¼ŽZS[)HyZrø8 ép ?< ðKpçɶB$-ý ,Ýýô`çéÇ¢|¤#dÊ\^[<Šû¶¥ÖpyØïîáa9øO€Ç£DÑM@ÕÒÝît]䮟î8&7^Àâƒ)<Íaõ¢îõÿ‚ë] ÌåµD1 ÷o‘؇ˆªVŽv4 ù½Ÿ ®±%Äþ¼fÀ”E‰×¬•ÜôêLC2±ÿ¥ÿìžš‰D"‘H$‰D"‘H$Ùø Y›Ú ñ"OIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_end.png000066400000000000000000000002231463772530400267610ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+EIDATX…íα A‚Øfb¡È“„!ŒÅ_oë[3¤´RZÎGwÆ7@@Àó€á_ÄLéM@Tí ç|àל 9™¥®IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_end@2x.png000066400000000000000000000003131463772530400273330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+}IDATxœíÙÁ € A´ÿÊl‚`#XÆš0ÓÀÙpcŒÐ\ïžëÝ冻<þÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjǸÊãõ×øý xâûp‚üà ·&ú*dIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_end_focus.png000066400000000000000000000002251463772530400301620ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+GIDATX…íα A‚*ÛÁBiØ/ÀFJó×ÛúÖ¹FÿÞø>œàÚ¯Ž ¯IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_line.png000066400000000000000000000002041463772530400271410ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+6IDATX…íÎÁ 01ÔÉÙe“Oß?‘«MÒ“ôæãmÆ|_§–iXïIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_line@2x.png000066400000000000000000000003561463772530400275230ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœíÐA 1‚Œ€Œò¸Øec@kŸ»ö¹²aÊñt€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@{×€Á|³OIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_line_disabled.png000066400000000000000000000002071463772530400307730ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÎ10A&âP€„ =" Üëÿg#eõdõl>Þf|Àe#;X{¯ IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_line_disabled@2x.png000066400000000000000000000003601463772530400313450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¢IDATxœíÐA Ã0o(Àþ-€Œðh ¬·1 µÏ]û\Ù0åø:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë =úu +“ÐIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_line_focus.png000066400000000000000000000002061463772530400303420ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íÎA @Arª‡!$’œxÎþÛLÄ¢ì©ì©ÍÇÛŒ/ø¬yßV1ÉIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_line_focus@2x.png000066400000000000000000000003561463772530400307220ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœíÐA Ã0S¸F" #<ëm hís×>W6L9þƒÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h¯çC—’Y¼IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_line_pressed.png000066400000000000000000000002071463772530400306710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÎ10A&š… ,à8" Üëÿg#eMgMo>Þf|À9?™9;&IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_line_pressed@2x.png000066400000000000000000000003571463772530400312510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¡IDATxœíÐA Ã0Mx†AFx4ÖÛÐÚç®}®l˜rü ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ðs×(˜ÍgIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_more.png000066400000000000000000000002421463772530400271560ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+TIDATX…íÕÁ CQ÷7q´Žæ&ÒIt#äçžòÈ¥) Yî¶ÜM¹Q”ò‹á€*_Ø{(/ùƒrž½5»­‡/„òí …IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_more@2x.png000066400000000000000000000004041463772530400275300ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¶IDATxœíÙÑ ƒP ÅÐuŽ"ö Á"tŒƒôìbY÷/3óºŸóºé°Éão Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4Кå|äqýŸióÕ33ÇþcK\~КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð,àÄ… ”™¼WIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_more_disabled.png000066400000000000000000000002471463772530400310120ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+YIDATX…c` ¸…¤4¸…¤4Pb%š©F0ê€QŒ:`Ô£p°PjÀJªä¡Œ v­™Ó@®þQŒ:`Ô£uÀ¨Üž ?¶mĽIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_more_disabled@2x.png000066400000000000000000000004071463772530400313620ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¹IDATxœíÙQ ƒPÑ¥Á °€¬Z¨ÄŒÓäÍØÉäþí ä8¯ç8¯G:|äñ Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4Кålò¸~Ï´€ÙµÀÌÌýû²%.¿€hM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h–ð.VvbñIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_more_focus.png000066400000000000000000000002441463772530400303570ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+VIDATX…c` X¬ýÛ`±öo%f0Q¢™`Ô£uÀ¨F0ê€w åFüw ¤J!ÀxàD0s¹º<F0ê€QŒ:`Ô£p0Ë ‰(GGIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_more_focus@2x.png000066400000000000000000000004041463772530400307270ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¶IDATxœíÙA Ã@ÅÐiNáQ áR›Âx•Ö&0–õo3¹îõ^÷z¥Ã!ÿКhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ðlà#ë×øL ˜S ÌÌ<߃-qû@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@³}€g DøîëLIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_more_pressed.png000066400000000000000000000002411463772530400307020ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+SIDATX…c` ˜dLl0ɘØ@‰L”h¦uÀ¨F0ê€QŒ:`ÀÀB3(©’‡E83#¿\Í£uÀ¨F0ê€Q ¸¹“G-ÍÊIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_more_pressed@2x.png000066400000000000000000000004061463772530400312570ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¸IDATxœíÙÁ ƒPÄÐ ¢$zâF1Üè)=‘2^¤o7°–5·çýçýJ‡Mÿ  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- Y>ÀGׯñ™0»˜™ù>[âò (€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€fù?úªØçj,äIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_open.png000066400000000000000000000006271463772530400271640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…íÑ¿JAðù6¤I!‚ M²Þ@ˆUPÓ V±Uðll,| ),¬AlE°H#Øzûç^ÀpˆçXˆ…Br¹T‚û+—a˜å‚ ‚ÿNЉ÷'B¶r‘î’ÖO“”c"ªJ_Àa¤õ¦ˆpTV¶‘³€,Wˆ{kíZQÜ9ׂª<° Ê\Q¾p@U©®@ÎÌPÔUâÜΨ¬µvãr `à ˜·Çý~¢FãmQ×·Ep  *SãÒ’?Îg¼ß£¨ 5û¯YÖŽãø¥¨¿ký¾q>7ÎÓXß U’ʸôÈ8Oã<­÷‡¿Ç3qð[â\G gjîf€¬xWÄné^™¾ÒàÙûE^2ÿõÂŒ"[M­¯ËvM5¬µ1E%RæªÓlÖ§íšI)sï ‚àOúo‡>NxÓEIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_open@2x.png000066400000000000000000000014431463772530400275330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÕIDATxœí×AHaðÿûf•ÀŒ.A²;;³l¤—ÂCE&]ìCD:Du :FàEˆºT‡ #*»„$lØ¥Óž2w¾™5Sa1LÝu_‡”ÖQÜÙ5ðýŽßûæÍÿ{;ð€B!„B!„B!¶ ÚÀuÝ}  ÇD™é^ŠÝ%"#Üj´Îžaân ¦+¶méxŽë½pøOCzòc:w±¡¡a>hïRÌLÚó®ÔU²œ›ü>¾«±±1¿Ñ¾*h0òõ`ð¹šÚÚ·Žãì Ú{É sD{Ù^ßáoLà/_¥#PF*“ÉXAû§ÇÇ·[ÞØ —}¥9·ùõ&Zë ´×WúF\lµmûÓûÖ1©WøJS |ʲ¬Ô†—ü€mÛND©fC¾Òn&5¤µnýמ®ëÖ³RÃXyøLÑPMai`šæTa~î8O}¥&õÒñ¼ŽõöÒZ-‚R`Ä— ÕU“±Øç02!½¥˜Yi/{ÀÍ•7ãn+¿ADŵ®Ï¸n;¨ò]Ü_mmÑht&̼¡`IÆu/¨€á+=Cqá|"‘˜-]üý™»ðíUböØñØ5"Z;gÙZg[˜ø9€šÒuRÕ†:‹Å& NW×Ôî¸à‚¯|5aY=åÊXÖ€Öz?“z  ÎW1-ù|~ˆTõ1pÌWŸ%¦³¶mö—3_Ù££_ã*²ð@ýzö0ÁEu2‘ˆ —9Zx_¿I&£^±?Ä wëØ>RPÔT‰Ã$“ÉÜÌtî€Gkï¢ó£yi~©T®Š¼¥ÿÔtÔ¹<õ í¦iþ¬t¦M¡]÷ãz…Œëå7ÛÅÌ{ÿƒÌÇq¶mv!„B!„B!„b‹ø%'óùƒ3F¡IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_open_disabled.png000066400000000000000000000006461463772530400310140ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+XIDATX…íÒ1/CQÆñÿ9‰Bº›‰°‰E´iÐDµµÕÀÀfÀ¬µ4bh™­DBH7ÂÖE'ƒDÊäÞûZ8Ú.ç7?yÎó&,˲¬ÿN™¡¸³ +_R…ƒôÝoJ#3+½^ÀÍ/Åüö4 ßeµy¡´ƒ¢õe8挛òá¤3ì5¹%`¤Ó”7¨ê¶ŠH›hŽ'ÎüwÙ‰ÙÅ)ñ9GèÔÙ»çEøáz€€i@å¾ä¦’Ñ|åéµSë’òÃõùç\(¾´¢Y Èvè—¹£ýÝ7S¿ñ|}ÄY¶°óÜ¥—§ƒAïê¶²‰Rk¢dã4—^Çpy]ÂñŨ ö€ U`p²\ȧ3µôÕ< _}tT•òÅ\¦PkW]ÂI§O|ÊÀ£öýèÉAæ¦Þ®F(8²,Ëú>w…k0Ô ågIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_open_disabled@2x.png000066400000000000000000000015501463772530400313610ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÖOleÇñï3Û­DÄ4£‚JÄQë ˆd…Ý%¤©Èn—b±¦ÛFL<o¦ñF‚‘piBÿ$MT¦8(è–&”¤ˆFÊ­€š!FÁÐRö}¼pØE°3»„ð|ŽóÌüö÷¾³³³`Œ1ÆcŒ1ÆcŒ1ƘDž„ ؘ{·Î+Æаø¼Ðßó á«Í.•iÛ*¢{ù Ð×}4L^è Heó#Àú’È/j¼kyß÷o…ÍTSÛǨî.9výêBï™Ó]]Ós õB×R dhóß®æûÄ[-5¡³ïH$:ªRÙ|g`ñ€„¾¡7@”]ÀŸ3Ž¡oÄcñÑ ™ÖçÃæ'rï?_té0ð^`4%¸·ÃÜ}ˆàHçò/:ÇQð?D½†ºÆæ’»)Ó¾¸(î[úÀè*ªo ôŽÎ¹ôá à÷üót-p¢ô¸ÂsN܉d¦µáÿfnʶ­tâNͲø çdM‹ˆEp~üÌÍ/¬ûÊÅo׫KFÕ"²}y]ýå‰_Ç~y¬ôÖü À³3'úS•ç6ú{/DÕ;² 8wîçbó¶ÆÁ —oT¯—ŒD ay]ýüæmÃ###÷|M&›ò;O΃OLŶ9Ü{=ÊΑüÌ&É·«ÐÉÝ›|hzÁíwŽ80ì’ʶ~òéÝiº¯Æûç#ß÷‹Q÷,Û¤›Ú6«ªÌŒF»µexðà_¹\®úš{z?HKà<ùp¨¿{_¹:–u’ÙÖWùX…dàÒITv t–³_Ù7 ™k_&ÎV>ÐÊ…Æc=§ÊÛ,¢×àýó»~WÏ[ ßÿl=ëÅtM%¿þËÄøé©×VÕ~=©ó–¯Üã´“ÓÕ±Ôð7=+Õ«"@ð3ÓMùU:MúnÈ‚?ú{oV²Lž¥Î¯}©~)ÂË€CuÏÚUKw}Ù¹;ÔÿúGN"ÑQ•hi™÷°{cŒ1ÆcŒ1ÆcŒ1‰vCô=PÃpIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_open_focus.png000066400000000000000000000006141463772530400303570ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+>IDATX…íÒ¿+…QÆñïóÊbR¬ü½÷–Í$?Š›˜X)€Í$“É,R/)%‹"ñŠ¢Ìe±Ð¤î½ÅëÞMÎg<===§s ‚ øï”Èo•—-u•ÑÄEA7¿)Ío»Íö:â)Ö ’¿ËFYeFM@g>‰÷fåsÛî²}ôP¡9+Ÿ9 *kØ…÷ãÄ“ßeã-`­ÀáK¤¾Ÿnÿ«§czN¯5^ê…×r‰ç°?=_œxZò.Ð^/–Ôw5¢Ç¬þÌ?ðQ.ñ xém¸WKÑÔå=帣² 4 €=Ÿ¢¹¬›×4 ¿ã!W¼4Lj"¦(¦Ò‚Vªé«z@¼énEÞZÞŠH£éˆªíªi@¼ëv•| Ü t]kWíl}ýŒAÁŸó +rôï‚IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_open_focus@2x.png000066400000000000000000000014271463772530400307340ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÉIDATxœíÖMHTQà÷½^K² ‚ ŒVAATÒ8„E&)&Ì"Ê¢ŸE‹¢‚ E`n‚(ˆjø3W¤¿Môæ80›­¢¬° 5¯÷m#ä\+̹3A}Ïò|ç¼|ç»fcŒ1ÆcŒ1ÆcŒ1Æü/˜k@E·V!Ð Ë^L7àû"üøL‚o|Ÿ <˜ÁöA§ˆ•…¸·ºþ«=žú.«úêù²P}ä d‘O-"[B•NÇgS_‚#…l§ð˜KN\!Ø @‚.¤œS¿ûðOª~(·úšJþvÆcŒ1ÆcŒ1ÆcÌâ;_zòê±nМIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_open_pressed.png000066400000000000000000000006451463772530400307110ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+WIDATX…íÒÍ+DQÆñ﹓Ò()åeÇ ÷’²³š0;e5Vš;ˆݬd¥¦¹w3#y©YXX)%E"®¢¬m”lˆ©;ó³0 Ô¸3c%ç³<===§s@Ó4MûïTPÀ²3+`˜¨bÌËÎ\URÚ—HwøʃzòrSà¤\Ölš@ºuÔp‚âÝÓ—Ð Ð4åÔ5bÀÐhˆìZ¶3V.kÆ!£¨€V`ßó#?ݾ¢Çé¹W¯í~TPK@°Ñc;)/ÏgÚnB)¶0Hþåá>r±>ûÔø>³â™I”r>†ËšH½}Þ~[°îšùRáÂYn:tóšôØNT`+8Ô3È à£°½lrµš¾ªôÚ®%ÈŽ@KéèY„‘óåä^µ]5 èw;‹!¹n ˆžæ’—µvý‚¨ïŸQÓ4MûsÞW+iEÄtL…IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/branch_open_pressed@2x.png000066400000000000000000000015341463772530400312610ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÕKlTuÇñï¹S¦ÚÐИPMJdcR6ÀLÇG¢©Ï¤$,pAK3í€bâÂÄLº3ñQ;¥‰ )1`ݘX’RÚY²¢ƒ„Ð IƒÚÎqQ£Ók%Ø{gºà|–ÿsïo~÷Ì Œ1ÆcŒ1ÆcŒ1Æó¨¯ÏÆÓõ³Êq„§P¾íM~¢~”[H4ѹµ ò)IŽö%½äy^@$ž}éïåÄý߯w_íoŸöš=ŸJ8žùPà“¢Ã{ª•OŒõÆÿXlªãC±ùÂŽªU5߯oé¨öž=§1•ªˆÄÓ]®‡Ÿ{5¼/@t¯Àm×éËÊÀð†ÖCk¼Æ×ï;¼|òVÍY„k”xÇË»>l º;ót! ƒÀ3®Ñ-U§y¬·-·˜Üp¬£V$pØèM òÖhwrx1¹Å|ø @ö«äÏËff^¹à­)\ÇÒÍÿ7³aÏ¡u"Küëáå'§à<ïÇÃO 9zpânPßNºF!¾ ÇÒ{6kc"óŠ:…a nþD.ÏNësÙ¾¶kž ÿ%àWÀDvpöæ¦è@íd((ðbÑHDh~2Òº¹)úCCÿù7‰§w œªŠÏ@ƒ[rG[ïùÙٗ߀…Db1Dºp-YáÔŠüŠw<¶kjþ* ñÌÇ íî,E;×NÔ~Ðßÿö¬ß=K¶€ÈžLŽö!×hØ©p¶d·ÔoK_UÓ#ÐâºNyÿJO²³TKº€H"½åÎ`„õ—¢º)"QÚó©—0íV°~+ðƒú$/ê@\|X1ȵ¶”¬ÍbýÄ}ZR‘Ϫjfµ>Qúw@ØAÙï <±aøB@f±>Qªm;õ¨'¨ì«ò¾73›õˆH$ª›À嘴ÌÖO A]„í‘ ÂVd³>€ïyŽ˜ÖúÌ#Žbjë3@û(0²XÀbdcZëeþ—<ïPJMœPÝ-Ù´ȼ6ïW³Ù\Ž‹'×QTžÀU«ï-§I¬s­DȺ {5çd±P¨þéáfS³Ù\¾jµÊ‚¼"ƒV’µaƒI…•>LuF3tµ»{Mzr:l4û¯ßþ1ó‰teIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_checked@2x.png000066400000000000000000000023261463772530400305120ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ˆIDATxœí›OoÜDÆŸ×6EâÖSTu×ΚͨR‘š[O‘€KK/ ¢­ú¸P‘H$!´” |‚Vjª(—*½¤•ÚkzA°\6ÎÚÞ«Û/‡î¯×®½ñøOšýI{ðÌØóúÙç­`Ê”)ÇÊҨìµìÁ%&þÀ€Ó^/4²ÉÙðÀ61ÝÛ5‰¼´“R°lû]ýà- A–I—ÁŸ™†ñëË)IÌL}ÇY&ÐŽÞÍÀ<¶vm{‰™ÿèDl×]bÆ×ÅÄV&ôMßq¾H¬+Ú~+RüŒ™Vø ÃpˆÈ—gN˜Yµm[ ^ âu'GêÁïťØfmÖqGÈöüøÞeÓ4÷Š^6–eÍ(ª¶ÁÀ;¡ân_ožŒc)в—0šóÿxÿ|zTnLÓÜ |ï2€g¡âùá½0&ÀðQ÷ÿ1Ój»Ýþ[~˜ÅbšæƒVÃeÑ{âÁ…ÑþCɱ•†Âþf¤èÜX›˜óN‡ ÃpdU&1±7¢mâ™áÕm´Ÿ„˜ØÇf¯‰ó€ã‚VuYè¹n[ °Âà†E÷Uº®ë;y¯]{ì¸îœð#_ðÆðwÕg<î¹n;ïõk-@‡Y£€p*¦ú”ð—yû¨µ-×½N1®æí£¶ôç 3ÖŠî§–t˜5…qÀk)MÎÛW-È`}8PÀ·òöU;²[Ÿ× Ãèæí¯Vdµ>Û}]ÿNFŸµ «õ |-ËÏ,ÔF€ ­ÿ§¬~k!@ÖHypçMŸ±‚áÄ„@¿x ÖÛÍf/Ëù-×½Î%[_Û=×mûŒÇ®b8Wgð5àG;®;—z~EÖä@ °‚ä¹úæD—Ui}AnB¯¨1uX˜uœÏ“ê«õ£”0ÒZÏqÎDK«¶¾@†÷SêOhŒÛáT¨ƒõ¹PÀß8xY›h*ÔÁú‚܆Ñ%ÂWé-_¤B]¬/2ì6›·x’Òì„Ê|W6Pë ¤°Hä„kHI€ÞãlÊåJ±¾@ÚS ­ëdK…4ʱ¾@êc0c*$R¦õRÈž ±”j}ô‰ÐáS¡\ë ™ Nš UX_Pˆ¦B%Öö.=ª±¾ Ð—¡´T¨Òú‚BX$ò…>a|‘Áñú¤*ë n7›=OQÎhÀsÏ ´é)Êù¬ŸÌФ”õsÆÀûeô5)µø*\%q쇘Y-)éÄľm'ÀÓðmۺ̠Ê$&öA´MœÛáƒê™A•I@êÅHÑØ#yLbº7rL¼nYÖŒäØ Ç²¬LÄ¢÷İk4ø+TtRQµ£$‚X,ÑãÝá½0ÙryЪÂþf­—Ë“zqøÏn¹¼ ï8˯Ɔ àå–a܈«IœÍæ €—‹ ªà¥Y]¿™Ô 릩ïÌK ­x2mš:̶¹sx±êºŽÛæžL²mnÊ”)Ç›ÿæ2ùÓŽª@ IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_checked_disabled.png000066400000000000000000000013331463772530400317640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…å—OHTQÆç¸‚u5¸ÉMm2Œ(œ¦…o¶Ìd­\©-‡ÁÕ-’,'(ƸI(ÿ´©ÕNÝØB)háF˜{ZøÞôš?o|¶¨oõÞ¹çžï{ß¹—w/üïâÀÕñnDî]@S@<»Àªé\6³ìy_"v|X@;Ð9N­vDn¶uœÛÛøúqÕ(8‰ ^cÞ?Q²BÌ¿Íü‚ýZ,~ÊäéEd8ê%׉º‚cFAu(—ÍLAìÂùéˆQž9-¾`yòº¬óA’{¡ù}·öy7æÐäQ{,Xœ{þÝy<íÆêJäÖŒ¨}«OUˆÈà«'¯Ëå* K„Õè Îr„´”›c•ôƒd2i©á)>·o`V?»\öÆÆþŠ€h,VÕ{‡Ée©»³uòØ”°~ϲ4žJ¥L¥ùa¥U]Âú‘ÜìÔf5Pч¼hVÕ™h,.ˆ;‚õ.ünÃc$“L&#+ëÛ5[_µ…1 ÷]Ð+ËëÛ·-áÖ»¨Ø‚îÎÖIE–¼1 U}x˜ÜŸõU H¥RƲ4ì•Ióm}Õf§6Ed´Ô¸ÂÈ‚Oë} ¸p¦åQq+Èk³Þ·€­¨Ùzßà ƨ ººeŒÚµZïÂ÷ïxq.óWL¬^váàTñbôô4:;°`òô— Õ»µ?¸±ß-PM#Ò‡ÈxÄNˆæ÷ç=g¸#¡§ QBõ½¢< ªé‚(obÄŽ‹Jš*E0(£¹ìÔ}7pèf´ñåÓJ[ÇÙEDš€“w;ÚÞ¡šÈe3/ªù௠¨ããpáIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_checked_disabled@2x.png000066400000000000000000000024661463772530400323460ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+èIDATxœí›OLUÇ¿¿™YLz!URizq›ˆ!©Ho½l\C+‘ÀFÐ4Ù½z±Y 1¦õäÍè%šf[0„Æb6-z¢’].ÅaléYØ™ŸöÉìììÎ,ógÙÏíÍüfÞo¾ùþÞ{3y4hÐà$Cv‚"‘¤¢´äúˆñ.€KÚ¼àifµ“°Ê„»…¶¹Lf¼`u‘¥=ý‰n–ð€v’ôÊ’Æ-Φ–ªEÉÕîÐ=˜á€3®ææg@·wîm¬¯ýR)¨¢Ýƒ‰0>õ&7!ІÛ;óëk+¦§Ím¿XrñŒ‰G%‰4cw3N«¤{db±˜¼‹æóšÆWˆi„Óúó¤¡Ç¬ÊˆD’Jè¥ÜïÐÕ<?©ûZžKm{’½ËDû­rÓ ¼ux”²ûÿ¼|Ñ80JÆ‹•–\J¼§Ð”ŽËÃÀò\j[ÝÇÏòkÅg+¡L€âTwx8¹8ûåß^$ê%Ës©m%õnjϘ€ƒyþ0@¢.çæ’Ìóú6]e1&×µéÍØÝt9/ß0æÎÀ9cŒ™%+¼ öµ`’{ÙêÕL€…RïìЋ‡5Mxˆq¯ I?ÿðÕ†Ó{ÞÝ7.h=xÀ)§˜pM–µG½±xØéý-@$’TÀê÷Κœ>Ë*}â´@ jÉÝ•O]& :í#°ôôÇ;ÀóºŸ@ ‰$&º dšvÚW °²~‘=MRo;í+pص>1-§§²Nû ”5Xuïé¹ÏÝè3Pص¾ºn烧³ìéw°Më/̤þt«ß@8 Ö¸â€7ßùðEÒF&t_’´‰…ôä;ׇZr7ÁþZ_àØ½±xX–µGL¸†âZàaM£‡Ý7.X]_˨¿pÿk׬/p,ÀÁ[šùZP¿‹D’]VOë \^Q+p©éÅ­+¬Ç¨oÄóA‰ÆzúãÆãõ¶¾À±Ä¸gÒÄMéK!Ö8@•Õ[ö,ÂJJ!Ö8`9=•aÜ*N”BP¬/pe Øßi» Æc‹°&–è[–¤iÀúWÈdÆ Ä|Ö¥ð:À-b|±¾ÀµY`qvò;¥`…_Ö¸: Ú,…jøf}«ÔP føj}ë ¡£–‚ßÖx²Q—˜ðÀsæÆe»ŸÌ¼Ä—¯Â?Τ¶¼íG_µˆ¯ÂõÄL€¼¾‹Åªí'4&¹ç1fäô]4Ÿw3)?1æNÀ–1ÆL€U}CÓøŠËyù†¦ÒU}›Q>%— À„»ú61MDû­î§ç-ѾD+KbÆgL(ì´ÍXÿïá´ÂôqAl–.Ý1NÙⳕPÛvyPR’y>ÐÛåUºJàñ#o—üo~˜@Ì#‹3“Ÿ™«8Åý•ým%ÜÞ™QÔ»Ô<‡Yš™¼U) ê¿±¾¶~õ_AÔ…c÷ßeIÃÐÒLꛪQvn¥ÿmŽ€®â®ëÀý6GÀkùm®Aƒ'› ™ž‚ß’IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_checked_focus.png000066400000000000000000000012171463772530400313350ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+AIDATX…í—1kQ…¿3Y«€…b vùbµ»¢ˆ‚]BŠ$øj•Ê$e©V°0`PAAÒÁ-‚ vA²»•ø’:AÁ"•É‹·¬›ÙìNv´Ñ¯zÜwgî™sß̼ÿ:ê”ßûfŒ—eÁ•<Š1õUê³úÜS@©êÇà'iÂr"ÆZjÌêé)¥ªo??°¢j»÷õ=ª7ÞùR<Â$ò:pQÖíàD!$Ù^’ÖBcV›y$²Y¬ZÂoc¼ LDí,QˆN¨åY¼‹€D)Ú‚ËËö4š3ú– ÇB¬Ð#÷Ü«ž~`ô 9£gåç* ¸í ýôb rõ¬k¢³&3±âHÇ~ŠJnJ×xÜéŒIZû+ŠÛžH>`ìÔ¿ðòÏ H³Þ¹ yV÷»¼ï"ì·ªS­´Ø˜ÖÞ úû:ÆeoµìNÄ a} Ûk(Fuì׬ø@ªõ³~`’Ölot„î–¯óÐ1bë}[عÓ³½ü¼+5“õ `U± šÇõÌÉ°ê³ šÓÚ-õšW¤ÅfFë3 h|å]­H8—õ™¤¶bë³  ÕŠHšöýHš;¯õÌ¿ãÝ}&ú&HÛÃ!´6yݼ›bÕ—“áÁ)˜:@<Â䟭{Û4B Ý‚UŒ§×‹U ¨uìá†"yòIág@¡J˜K;˜TÈs§ô;½&p4K¶ÎcÝóçäÀ¦‘v4ûÏ/¦Në­¹mËIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_checked_focus@2x.png000066400000000000000000000023651463772530400317140ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+§IDATxœí›ÏoUÇ¿g¦…ÂÊç¦!XX6M0ñ¥/•M›¨–¢‚‰mb[›(Šý 4±Ñmñ‘²©&m <-£uƒ 𲍋Ö-й_}SfæÍtæ1w~Ô¾Oòsîyïž{Þ÷ܹ3¹hРÁNF¢8uϰim'ÔY ì`wÒÁÕ'<"8gÀ¸ÚRÀÍÙYû^hJ“| à7^ÕizÌòa¥_~ÞÊÉl!¥s‚ƒ§±ýí§K782ðL@ç$DøY2±¥ùyé'|Ôì›™ªì§=æŠ ÁÄ­CkX¸þ®XZÉ™k4¶à ,r@Áí!oû•CMºgØ´ºÂßᔽàr®Ò+KÚ#O€R™­Pñ¦Ã<¿§ G¼cM ¬­àÜ5¿lR>Ø.ƒ€J¯,ÁsVæöêØ\Ô$@Au^Sdøn¿ü£?Ìd©ôÊ’P†6ïØŸ¤è2˜¸¥=º”P͘r[äu¯OMìw^ZÂîÀÒÂ'ö^¸Wxy›íëÁ»ßê5x!´ChÊ:€(t•Ù¦”åÔ†…㦣wOÊßq;÷ (ó°²x”óön|ä‚EÞé*³-îïç:Ý3l‚ÁìóiÞ§,õIÜ>r€Ç˸ æÖõ9·ÜÎÅIv8’t?¹T@÷ ›Lð;Í[ù x=n_¹L@¸ôOiWâö•»ˆ,}‘‘JŸÌÇí/W ˆ*}æö¼„¯tô™«D•¾²äb”žQÈM Ô#ýßNËŸºúÍ…²¾¼qƒ¯XTC› á„a£÷zåA”ï?^Æ%‘t¥o[]e¶Yä@.À^«SÎ+‹·Kã<öýâ$;DÒ—¾Mì(¥†°V‡Éºg¨²,¥oØ|DõkCqõ_|ԜŬï%ùI)N²ÃkÎZú6Àñ‡]¦ð[g)äAú6ñ`_xº¥§ò }›Ø ¨ôÉ<)Ÿ†:VK!/Ò·Ñ2ì}WÜqÛe‚ß›àr }- ˜í‘u ra¥¼àHˆO*Ò·Ñv˜ë—?"•B)IßFëm0b)“¢ôm´& ŽRð#UéÛh_½p)¤,}›DV‚u—BÒ·I$u–B&Ò·IìY r)d$}›D†BK!CéÛ$š€ÙY7LyO¤v“… CÞÏJú6‰?ßë•TrT€)«V˜¢’£Q_™%I*o…+§dÀ;iôU/¹x+œ%~›¤ž8¯Ï\£™^8zñÆîà¿Iê‘óúa ê-|b_ôúø(€s.ƒ…czÃJ㎻-¬¹%×$À€qÕy-äh©ÌVÝÁ%M©ÌV ] 1ïØ6lZ ¸ à/‡©Å±í”„ÍÍÒîãóÕ±¹¨k»¼P†U3¦ò¼]Þx†ãÕþŶËÛtNpðq`D+'å²_Sà:à×~\†È`rQ¥¨ôá‹ ‡¨‡¦¾Ю5´ä‰thªîcsÕ-çòxlÀ"Àûõ›kРÁÎæ?·7é‹ù]VIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_checked_pressed.png000066400000000000000000000013001463772530400316540ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+rIDATX…å—ÏNaÅ÷k»"1QÀ»¾‚ЊÑL\ qÅÐÐ&@IŒÂ²iX•D#-BÀİÁ½MØ(‰‰Š@}X)1qÁªv®‹ÎÔ±Ð?Sz–çÞ™sæÜo2wà‡Ôý‰Ü-TgPº}R9BÙF$³—Ÿ|W×@$>ÿH‘¹³ŒùK•éâJòÉ)}cÏn‹˜·ÀD“¡R¹ðaíáw?ToŽ>½R †PÉ—¹ã$¬:3 ¢É½üÔºÂìYïgxê ðÀT»„€P©\ðSÜ 4…Š7ª\µj8¿b? ;‹Ç)®:\°~{{¸žX6j­XbÆ>å'^5ê÷Õ@4– [jm¶‘ÞFטFEOH¥ŒÐçŽx«ðÍ@ä°+ º9UfÿŠh,Vt®†Þ*ö/_¼³£?1e%¶š]Þô6;Ցî„¢ƒnN•Ç;«“û­øoš€-Þôµ6¢±\Ø©'z^_Ã+ k¤R÷¬Ãö£oÙ€*³",¹¨»}_:ãFD탦#°ãÜrs",)ºXÓê)ú– N[¦,£ÀIƒ.ÏÑ·nØYÜdº^½è=ؽö-OÍ(l´½guFÑvôÞ àŒBGi7zž?Ç»ËS›@¸ic‹p¯dGPY ýºy-¢ã )¾ž6 l”B¡‹2`ý´†*R|t¸ß#É :ŒJ¶?ž4g‡;/¢ã ¶ø<`!’©Êºí“ ~nJâÔIÀ]ý\Ü|ß¹ÿ踌Çõª왿A$V\N¾ôãžÿ~)r/NÀ¢ÊIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_checked_pressed@2x.png000066400000000000000000000024471463772530400322430ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÙIDATxœí›OhWÇ¿¿™ÑBÓ"v…Ý¢‡ÆCE°$[öàe¡µm.mjKU<„¬6æÒ‚f²bk/Ù`ĵZ4ö"”´‡ ½,Ùxº½Øƒ!Ö¬E0HÂÎüzH^;»;»;›ù›f?°‡yó›y¿ùî÷7ófxhРÁV†¬ÅUUY^ uèÀQEnð‚˹ÕË @œ•€«M‘¥É™d²Pë šD9â×ÉÓȤ¾lú̯Õâ¤*§ h÷H? Oo¶‹öúô›‰Ô9€+þÑr¥ÑîP?_º“ž—Ð[-ÑÌÊßs¿ünº×¬1š¸xЧKšŸ€0 èÆž§áù‰‰4ÇsµAgç5ùþŽün]áÃ` ØY!½cVeÄUUyöp×"Û~“ ú±ÌX_ÞùÔ'Ö5ÖiŒ·E¹—#KJoŒe÷€åÅPGIÍ?^Ŷ7ËÅ@f¬//ôcžˆ6ö-/†:JcËУE õÎåO¹‘¨›dÆúò Vme×Öžó†€Ýp>=o5iʸM@{iŒÉc[Œ[{ž†çNÌ+Lrµ4ÆlP4 ÚݾLr/½Vm ¿°B[Ïh«TÐ@xo½é:3†æ®ôþe÷Üw@,‘Ú+iÚMŽxqýw‚·ÚzF[íž?ÐÄUUј~Ðl²»YÒ´/ìöhž= }*txßn z*µ„A·û ¤qUU Ó÷¶U‹#¢ »}R Ö€U‰ù‚ݾ'€Uëx0“îÍÙí/PXµ>€lSäñ7Nô(¬ZŸt餕žVŒõXöÛ3wê7øa}#ïíÝ#¯ab`ÂøYWä¡Û—Nß³r¼ÖØv@[Ïh+n81V'—4íf,‘Ú[ëx¿¬/°-€TÐPa¬®~Œ«jE—ùi}ý{À¯¨fD—_ù¬ÒN?­/pý&È Áè©ÔþÒv¿­/pB€ë5öoÓwÆR‚õ¶¯¬Ö+*… X_`[€Lº7F²Vœ(… X_àÈ=à¥æ¥ `ÌÕÛ–~`¦qÀúG˜I& ø$j–¿AÀ§óÄúÇžÙËgÿ°R µðÊúGƒK¡žY_à¨ÖKÁO­/p| ´ÑRðÚúWF‚(Ï­/pE€:KÁë \{°Z ~Y_àêË…RðÍúW˜I& º"Àl’ż.Ëùe}ë¯Ã·/¾'k8Hà)Ï<'ð”¬á ÕOfnâÉü€ÌXï€w½è«^ñUØOÌX1ntv^«86è˜ä¾Rc"=0nÝß‘ßíhVb’ûBiL™ ηu…;œ—gh²~ĸÍ($— W‹C±®á°ãÙ¹L¬k8L ¢XÙµÁD€¦ÈÒ$˜þ44íÔi|3‰ðïdiÃŒqrM‘¥ÉÒØº¦Ë3X•5i*ÈÓå5Y?²þÏolº¼ Ú=ò?Y0¸6}ö¼Ù¾Šã€ì•Oϸ߽´<™éÜlº÷«J–M1ôáµ58›«‹¦6°líX›uÀesX``®žes 4ØÚüø­òûI6ÖIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_indeterminate.png000066400000000000000000000007411463772530400314010ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+“IDATX…í—ONÂPÆ¿yv¸(þ¥—€Dãð zYõÖÄ…˜x.`b‡ð•Wº¢‰aiÇ… -%H &ö[¾7™ï—™ÉËà¿‹æ”R‡.èŒ*û‘¸0† ´Ø(•J/ d׺$Â]XDr‰qU.ï}¯J Ð3€×SB´ …Â{®½^ooâº55ì ðñ|%`*«i*‹¥R§Q˜I*uf*‹Me5§gbv˨@JˆV\iMórsÅà \TeR>ŸóÌü[Rl`gY@ײΙù Ìj©yDD7åbñ),*´RÊ3W7Ê0£!¥Ìý` Ðu½O„ €G«§æ꺮÷â–΀×ÃÐ>®£¿Ý‚ Ø,c|} ã2³m;ë™ ü„6L\·ÀØq¼ÜÔ™žÍ"6\Ð R)JkZëû·žlÛÎŽ§F ®Ó» ÅÄ@|³±x1™j¶š+?¯ë‰u‚V³DŸäÊ''Ý-IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_indeterminate@2x.png000066400000000000000000000016271463772530400317570ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IIDATxœí›?OA‡ïí%V©(€vC#…˜@ci¢P@h-$á;å ‰$бòÏ' ¡¡5P€&”6ˆv»7ËQ`!†½»×⎸»·'w;»7àÍÓÍìÜÜ3¿ÛÀ `0zj§ÑsÞ–åY&~`À€k™šu΀#»Ä´î‰Á÷ˆ*}èÂ\)è-€[)Hv“?v„øø¯F¹V˜™J¾_$Ð6®Þà`”@Ûž”‹ÌÜò‡n€<<\dÆ‹lܺ ½,ùþÓ–Wã*·ýv¤ú„™žåPÝBøDTMÕSf¶¤”…¬i"^кžŒ{šØaÎû‡_¸í øT«VæÇ9ÎB>m\×íÏYù5îªJ…¡±èÄØôز<‹ð3ÿ£òû×£«2xpç¸V­Ì8 T6Æ¢)€Æ«îo™iiddä{úšÙâ8Î1ƒ–‚uѱñ“àD¸Au3e·®‘ãêF¤j¼©MÌç‚!„Ÿ¦T7‰qŒ¶‰ ´Â»l³}'ĸ7­^[®z€nݘt èÆ [@7&ݺ1èÐ @·€nòitâúþ$¯Á¸6ÿ× ¼ÏDOœB!úwËŽQ¾<)牱Ʋ<êßAwˆ±åI9¯Ú™RžçÝð^U"9ô®á¥ˆòwº®Ò‡"7êÉéùIP)æÊg§)¹$á´á¥lÛþ ð‚JjðBÝ!9Ê€-Ä*¦þ€UûkaŸ S¶«ª¥²h¼•ßÉ:0“ nݘt èÆ [@7&ݺ1èÐ @·€nL1ugÁ3[]rI÷³h›¸Ž‚)e!M©nã^޶‰ `7X¨ÁšNSª›ÔÈš‰TíEÛ4@Lë¡2ñ²ëºý)»eŽëºý~¬‹Ž ˆ Àƒ| Tõå¬üÚU á|³4Â;Æc ÑÙvyÐRŽ«—z»ÙvùsJ¾_ü?Lm!Vâ®´\ˆ¡¡€‹ÙIuxq¸PxÕªA»‡¦ÞMU-{Ú:4•äØÜ8ê»®/ã±¹2€½NŽÍ †Þæu„G3\oXIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_indeterminate_disabled.png000066400000000000000000000010411463772530400332220ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÓIDATX…í—±kSQÆ_^é"´ÄþJG],(.yê T^×"äé ˜©Tÿ38ÁÅdÐE”… â ¨uÑM·îmQàRÈ=¾ŸR^‰}iEóM÷{8ßïÞsyÜ ÿ»ô{àüåò¤›ÀÏÈgXǬÚn6^''¼ä‡”—„VàHFæDµf®LÏžú¶ñéýÛx¢¿þµ³rîð³JΣõüIãKîÊÇ]"R 8ŠÙ¹x'Æú$Î-¬Òn6V²0Ž-dÅBÉxµ¸KäÍäZzßã¶rÛ=ïÜÃw¿¼wïM¸P(í ­%)Hèú®B„gà°ÕUeÍSP0Ë„ÇK_ýélvxiµN«> ±†ÛºÙB(G_ÎL$§eyU Äâ ŒØí¨¶Ö°„s]Ý=¿çós/ë%Õ5 4‹ƒqÝm-„(ØÕÝSšÏÏÍØ>¶ V^ûLUñƒ‰¯j=ó¡øitt´ì‚ÜuF=EøöŸ$¦k t˜Ÿ“°ÝçPc@ н; `úæ xQ^Äàt:¹àŠz‡ Fb/1p|%J¹Åo{Y'FÍÚYßUˆ zÂûC?»YÓéäByƒ`üX‰òÊØª¨1 ²Ô­t'2÷¾¸!ÔM¦ÓÉ%Ì1ëØ°¼Î¯$hôÌam-CóðSs›€Þš›~~sÇâ'‡uµ «vöZsì ¨Úám´Ù¾l´×ì^í h+”²ÈF [€l”²ÈF [€l”²ÈF [€lt'Š„.„Áž[Äÿk€¼W¦žÜϬš½ Âo@¸ÿây°öàCpð¨üÆa°ö<Üñ¼h1!}C; Ð]Që…¡Ý ô í©!dÀÝ{Œ€m"5Äàí[tï1‘ m? ð{iñ5@¿œÓ<ôkYÃú2 ;9ò“`\©!Á¸”ù)RCøÈŒ¥€ŒÞay‰rè=È8‘K=-æÈ> ² ¯É2P“ l²QÈ e€l²QÈ e€l²QÈ e€M¬dnD£ÑFç‰746ÚKÖ; æF¾}NŠj%Ví|¶æØ0knŸtXWË0ÊtÊÜfà5§Æ&<6·‰éZ0ët^ž»#±N›cÖ±6,}õ§äÿ/m&þ–®>1N¹Êتhî¸<(¡yøé†>._¦S^÷qù¿ü7&s<3žºa÷¬î÷1÷v¦«»§¢ {Ò\‡ˆO§nÖKh¸ÆÏççfºöy¢^lº{C”#ƒSãɇ ³ÖRÊ|mŽ€ÞÊ©ë wmŽ€Ï ¼iæÚœB¡hoþAXIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_indeterminate_focus.png000066400000000000000000000007221463772530400325770ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+„IDATX…í—ÍJ#A…¿ÓºÕ…2ú&é Š/a>„`Vbæ&‚ #¸Ü Øà"/0 ¦}$kûÌ® Il1vtÀ>«âÖ¥ÎW?÷Âg—Fõ3¯e¸¨ ¾”ab¸Åô#Ôé7uñ,@œx|0 ¬$eXûiS‡cqâuðà«=лÜÖß2\¿þöR6G¹ ,ÊÚ'1’lïK«•6uZ†qP¾‘ÓZb ÿÊpø ³D z W¦ùˆzq ƒ+ëØ'éjKwùpe à£TT0ÿRB|æäŸÀÂ+×`ýH›:)J*<øÜ«ÈÇS˜, wãs¯N ð*H7uµ ¦X{€ÕJ7u]”ôâÈï°ðߢÿû *€ à] ·ðX@Îʬ–x9ÞŒ`úÙYÀãÚ6i ?¢uŒ¿!wk‰ôžÔpoR¾ó†ðE¨æ&5&f÷6žoL‚Bk–—Î+£óSêÆ&ÔšUúñ䄆ê WùIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_indeterminate_focus@2x.png000066400000000000000000000016421463772530400331530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+TIDATxœí›½OSQ‡Ÿ·…X$:Ë $’6n˜( ‘&È ÿqS$šø'?þ1‚Dœ4%˜ Îp°ÄŤ¯ƒsïí­Òž{{@γ÷žžþÞß=_iχñ“‘ÍTêžÕ–r‰3*ƒ‚t)ìØ•´¸zPø!ðYÑù©‡™,O_—ŸÿúÜ? ÈOêIлÀ¡X”6E‹Å‚¼ü[¥TÍ'ª’{¬£ 3l¿ä:@gòS:‚jÍ]Ó€Ü$#"z=mMDõFþ —k=ŽtÆëö3¡pIE®æùÁ2KÎÉz¬B ˜Ðô§ X用^²ÁÒ5ª èžÕ–ï%ý€¿Û ¯HÉP±OVbWžùim£¢PNøÂ‹»³r$<1V r‰3Çü×´Êùí’<@±OVHÉPò…;¼ÜTP¡2è/«ÈØ›‚|‰_f²ûdETÆü±pna€ ]@šç±«k•Vž#r4\§Ê…ýþòÁ2Kq kÚÛÃu"z@p‡·ÕfûzkÚ½ÖÞíœ¶ØÆ`[€mœ¶ØÆ`[€mœ¶ØÆ`[€mZâh$?¥=¨Þ³Éÿ Pà="—ŠýþݲnŒ{@nR‡Q}!ùäñ¾£Õ¹I6mÌÈ€Î)Ý'è}S"è½Î)ÝgÒ†‘8ì1iýž††Ùñ“ ‘ex |‹IK#|ó44Œ‘ ý²ªÈ“6LPäÂB¿¬š´a<æ 2ŽH/°Àï%*i6–ÁÞ¹‚Œ›6Ë>À[×d¸IжÛ8l °3À¶Û8l °3À¶Û8l °3 Pøá/Lhºyrâ%¬=œD’úì/Êp ~iÍ!Bûr¸NDÐù@`SñÊj©5N#ú®ªNu õÐ_Õkùim‹[\Òä§µME¯úcáÜ~ÇBd²<>úBY*ú`;™ðç°tðÄø¢—[€ºŽË‹ÊX¥•g[ù¸|jÓÞ›oì¸ü¹Ç:ú_\˜-öËͨG5÷sn"2šœª¦  #ųܪUa³—¦î±JKžM]šªûÚœwä¼}+^›–AßÕsmÎápìl~C‡»æ?šIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_indeterminate_pressed.png000066400000000000000000000010061463772530400331210ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¸IDATX…í—ÏJQ‡¿3IV%B+©àk4ÿŠÅhJ_¢Á”jF)%ö¡%™Ø¢E’•pÓ.«i“×4(”,cr\Ìd ÆŽ˜Lbió[Þ{¸ß7÷\†{á\ˆ¾.Í¡ºŠD‰øDi !’¯mdþ(Ëß)²v“˜O騒«5?ö ˜Çñ=ÊÐÜŠ< 0EÝzÞÛÙ€EUy6 *•èE¯@ -ÂðÆóžæËeŸ½¾ ¼ï¶éÀ÷ýU%òcL·Ùr& wý×h|ÝØklêø¾¿ÚmÓ¢„‡óFáN4ªC^Œ@ˆ2×q€[Ù?¿Äžèœ øl€ °6ÀØ`ŠI6½Öntõ©€)H`ŒéÖå6ÆtQ‚ÌUF@»Ùr&uDÌf³ëfË™Âø[[`Ç/ª<)B”¿§›¿¹sv19¯f!ÙèÜ)?ÿ!k²Õl\^Í,Ÿðf8-Y¨dIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_unchecked@2x.png000066400000000000000000000015171463772530400310560ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›OOQÅÏ­XCXbaø#S»puÅR¾`$wMD—ð t­&âRI$¾.YQX™ØiJY’ÆJz\PÊËÌio+ï·êÜw§9÷ô½é,î,ËuFêI*‹]¥ryä8DFHô ÐÑhq#@n@d¥3ÿê8ÎáE÷kIñòùi@^è»2µÍa‡àÜÝ¡¡EáYIg°¶¶v³;ÑóÀLCä5û{/FGGG-Fnãã_~ë=À§¥ ˆo)’¬\¹Ô@Db HK3݉|µ"wÀ\nZ ŸŒÐPf]wpé¼íÔ ”\në…ot×âà“”ë~æ‡ (‹]¥_å羽y~‚•ûÉdr§‘¯Ïóú ±u·«¡Bç­ø½àƒ1¼±T.OÂ|àQ^¶[ñL&w@ye„úKåòD0/dÈqã*㺃K Ð×\wð €L-@Öa€ÈÈi>V[ýÌŸ‡ˆÄêi$6Ì @¢ßø‚ÝF‰kf ‚ë!Ì7¼Vû«» f Qo¯á#pͰh ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h Ð&Ü$|‘¶7ȬÁ¬í„p“” P»ìmœ´æ`Ö íàzT£äFíÁɺf Z’"‚±ÓHe3˜Õ(¹b\¥=ߟl„¸fàùþC˜ã"ËÁœ ›¥Aì³r”N¥RmÕ4™ÍfÈuÕP}ÍҎ㜫 ‰ud<ÏŸj‡ã@R<ÏŸ ‚óQ#4‘LøžÉTû‡w[­‹TDb${«g>X^HÝy^÷Àð_Ì,ìïÍž52sáÐT6Ÿ,7h¿¡©ÁùKM™TÇæ&ŽûícÃZrl² T6!²Ü/×36g±X®7p°v€–è‹IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_unchecked_disabled.png000066400000000000000000000006071463772530400323320ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…í׿NÂPÇñï¹!0Z|†¾@_€ŠL&¨#˜°ÖYd‡•DWFe4"OÐè;°PGá8”*]lãàý77ý}Ò»œÿ=²}à_^Ÿ Ü€z€“QO *tÇÏoþU³#*·À ˆP>2©Ž(¡tÞ_žîw•z³fŒ¼ ŒY£a’Iù*Õz»ŒY |EjéŸ0écLÌò( û–…04øêý¾¢åQ¾@"o'³7ÿ)ª1Âñ>ÀŸÄ,À,À,À,`¯¦×|#â L÷$Üj½]Ϋ;ù¶ºá@¡ ”0‹AˆÊyë³EEzéùÆbrzÑz@¸æÉôªq&í"¨ .&i’ÕLo}zýU”)B¨Ho{5³ùÃ%f/å+=IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_unchecked_disabled@2x.png000066400000000000000000000015441463772530400327050ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›¿OSQÇ¿ßNò#î.XWML¬us¨#IѤ¥DÐþÁD¬8hM ²ƒl¸ºP˜œ)’¶ DòŽ}MsûjiOîgº=÷¾ö{¾½÷ÝåÀb±\dxšEáX,àtŒPp À €¶º*ûwŽäl ‘qºŽWÓéB­‡jÀðƒø˜€/ œ‡Ê²#ÄôZf! @ª-ªjÀd²½;/s LÔE^£¾Ýïåä÷Tê·ßtµmÌK{îkI#ž%ðM ?)Ž{¾Jÿ¡ëìà&€`i‚2Ñ<…ÏNðÝ¡hbŒ‚e¡=™Z[~ÿÙïKš †"ñG$gôxA!¯e>V,6áX, ¿:~À;ó‚¼çúÊrj§Ž¢Ï{‘ä€ wD/€È±ëèªùbtÌ݃Ž”½ðò¼Õ’€•åÔ¾(ƒRè6×UP¼ê<²Åmß’¬fÞ}-(µ ÀÉ=‘u4ÿ™ÿRÌÁcÈ\àgÀ 7 ±[UÄÈáŠ9ïg@éjl¶«î,9T\û~\(¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´ñ3àØÝ–7ÈÈáØœ÷K0WzXp¹¢‰‘ö9ïgÀ¦7 y §ì)hRXÌÁcË\Pa€™²Áp$1Re ˆòÊqá’¹¦Â§ëh@©6Xˆ¹;÷-wn?é‘ÙR€È1pXÛ€Õtº ÄtY¨ÏiG6‰¢5ŽC‘øh»Û¶ Ï 0ã×BS-!ÞŒ¿ñéÉŠÈ:‰Ýf«"ºŽ.Ï|Иžÿúeá|êž«uŒÈ~/'»ó€aBdðä›­†š ÿß9¿ßãL¡JÑwͦ©P4£àZ­iŠÈ 0s榩r±X@ ÃÅzû!œT]7cÛÜ6€-—8\:MÛœÅb¹ØüßsáµÏ3¦ÑIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_unchecked_focus.png000066400000000000000000000006031463772530400316760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+5IDATX…í—1NQEÏe(‘×0"µ ´;VµZH/« SŒ•1±6q6ÀhÀR“™k“ ‚…™‰…ÿ–ï¿ü{òþ/Þ…ÿ.m’[÷Tó9%ù,Ô¹nÒ3=íèÜe#¤ û`fx+Ã]Ð4Ä‚òèõ$ºúp4u?Ljçȼœj^†y¡îÔíLž`Ž«_L¢V4äxhx¯ÂàåTóÈŠ<,굞D0«Â|˜a’]e½ùOòêC¶vü‰@ €6–‚fÕ†Z­ú‹]©!îNÝ®Ê|}wŒH¿8× ‘É“* :>Ìä Pw¦qQÿLî³k¬KàƒU0Y–a¾{ Ô÷“BÉ­{Š<\¯Î­íó_jHi¼Í‚>h±o/|A'>IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_unchecked_focus@2x.png000066400000000000000000000015221463772530400322510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›½OQÅÏ™¬l©¾zYâb!55ŸF±“hZÂ_ 5˜¥šHÂg,©± $4,TÖ,´Ü¥`cá²;Ì "»w7¼_µ÷Ý;Éy'ïÍlq/àp8n3¼JQ׺’MyŒ€"Ð)¡@¢ÊÚþ•"‰œ€]ˆËÇI,îô1ÙC 1³†1Bo´Ý”Òq pj«ŸAê¼¢s èž×DÊŸ8^}µBóÅ#ob{œ'qÙøc,1±ê¿ø"”ÉJúFz?Hø7-õàI~+ÉÇÒ• Ç)^Æ„ØYÕ¡¥_'·°pÑqª $fVñ”Ô €»åeðùÖ?…Ë#ü}áé;*wþgQìÚäAÕDWîµ%¨÷JK¹ã$ï‡_Œ^øÁ¦ÌšÛì÷^Åõ=ÇOŒ*Îk"‘ò2! 1 ªÇê˜JhîäÈ›<¯éû*CSϽCã MåN_{h*H׺’Í .µœw ÇæìƒØ#¸ThÆÒUÆæÇíæý[ö<ÿÚGIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_unchecked_pressed.png000066400000000000000000000006231463772530400322260ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+EIDATX…í×±NÂPÆñÿ)¡Œ–Ÿ¡  ø&ð¬&”ÁœÕAvè ð ÆÄ'¨‰Kß)ã5XÀAÛ8x¿ñ´É÷Ko‡{à¿G’ƒŠ7¬[ª×@ pRê™ÁZ¤÷æ_>T[]…`"úžJ½Ê ¨ D´ûê_Ýíª­AC‘'„—ˆ|sâ·§©”oSöF%›åå|-Òˆ¿„õ‰D:À"‹r€‰ßžFä›@”SíÄskçH˜Eù.B!ÔÍÿµpR;óo"Â(üI À À À ÀvóÍí5Û¨â³C€Ô-{£RVåeoTp‚=ÀZ¤l–ã,g§6Ë1`¯Dúñüëbâ îUåˆÂíò×QÅpûèb§â ë9ÕÎöê\L>ÿafÁJ¤Ÿ\ÍL>§|n2Û½dEIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/checkbox_unchecked_pressed@2x.png000066400000000000000000000015361463772530400326040ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›MOQ†ßSÑ!t©„÷n°Ý´Äþ ÁHRܘV‰­²0_  M[#íNI4þî¤ +×It 2 }]´”afJ+2=m¸Ïj:çNòÞ'÷önî ÃeFÚM,„­þI÷Þ0  /ØhÿÌ!€ ›¬ÚûËK/÷Z}ÔB%–ÌN‹È+#“³cì˜[/¤—a³AMÄ’…«;A*x‚(VºTLýñ+7YÆ‘|@ÒU(‹à ˆïU z±Iÿ‚`˜Ä]‘FAÚøÔo%ø®€x*; àƒãÕOR2¥â³Ïg-§î€KæŠ0 ຣðh½ùèíM,„¯ Xßp²çGÑRqv'˜ÀÁK¾¹²à€¨üþeßrÿ1†ÜZý“püá‘ò¼×&¥âìŽ^4^F­°5áçP;ê”k˾7ùº˜þ |ü›”Öêç|í \ëþ=ÂÚêcî>0zR”Ý`‚uŽSsÜôÖ½4ŽÆn;ê΃kžcßOÀ¥ÂР @#@;€6F€vmŒíÚÚ´1´hchÐÆÐ  @#@;€6F€vmŒíÚÚ´1´hchÐÆÐ Ÿ€CG±ç¹æpèS÷P9~¨‚CA„ê$§æ@l»ë>d³ñ¹°­ž‚î„R›C‘-÷V?#ã©üd0á‚'þ$ûŽ›ã"\qñ°÷–Qk6P˜»óømÏm…ñ™wÀd/ˆŠ½g·P¿M=çøpð¨/TŽ%sS½±(±dnŠÕ£ ƒ×‚y¿š&¢Ä“¹÷>Ý"e‚k!Èn·Ý" ¡*8Tßó‘ÓU.®23~÷ž›tŒ‰BZhÃ%!"Ñf·U©eòKÅE²?ÓìÒw˦©x*—ð½Ö4ET ˜?wÓ”“hb!l…­ R&@ŽÕo]w_Û± ‘-®Ø{öJ;msƒáróô°å&aEIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_horizontal.png000066400000000000000000000001701463772530400300770ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+*IDATX…íÎA ±ÿ™bdÄÀnÖ{ÎM¬døÂ7¥±ô'¡IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_horizontal@2x.png000066400000000000000000000002111463772530400304450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+;IDATxœíÐ Á×þE‹ø)ä@f,[ÀÿÆÚç¦#’f: Í€t¼×þ…©@ ¬!IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_horizontal_disabled.png000066400000000000000000000001711463772530400317270ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•++IDATX…íÎA İ o(˜ü[Ç#1ÐVa½çÜäÀJÆ€/<èÿ÷Ík%IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_horizontal_disabled@2x.png000066400000000000000000000002131463772530400322760ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+=IDATxœíÐ Á×n&°‚ý+ø)ä@f,[ÀÿÆÚç¦#’f: Í€t¼×ºaY¯ŒoIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_horizontal_focus.png000066400000000000000000000001671463772530400313040ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+)IDATX…íÎA İ S¸žD@ÆñH ´U@Xï979°’qà Ó²æj„F˜IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_horizontal_focus@2x.png000066400000000000000000000002111463772530400316440ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+;IDATxœíÐ Á×R¶6¢~ 9™ËVð¿±ö¹éˆ¤™H3 ï5†jêÑC3bIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_horizontal_pressed.png000066400000000000000000000001701463772530400316240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+*IDATX…íÎA İ Mxš ƒŒã‘h«€°Þsnr`%ãÀ¾0í¹[–IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_horizontal_pressed@2x.png000066400000000000000000000002121463772530400321730ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+™éÎ ¥IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_vertical@2x.png000066400000000000000000000003661463772530400301000ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœíб €0Ä@ Aì?‚EBËGaw_½å±!®ûYß}s]œþ‰hM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4/p1€2UÄIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_vertical_disabled.png000066400000000000000000000002071463772530400313470ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÎ10A&ÞP€ü[ " Üëÿg#eõdõl>Þf|ÀäÆ5‰•.IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_vertical_disabled@2x.png000066400000000000000000000003711463772530400317230ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+«IDATxœíÐ1€0ÄPŠ·*À²°€Ä•Ÿ!Ùnº¼Œ 1s}÷s_CxìâôO@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- yUÑ€;ºêIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_vertical_focus.png000066400000000000000000000002051463772530400307150ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+7IDATX…íα01.K±5#B†€RßÛ§ˆEY=Y=›·_ð‹i‡|áÍIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_vertical_focus@2x.png000066400000000000000000000003661463772530400312770ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœíÐ1€0ÄPZSõP|` ºâà3$ÛM——q Öõ¼ß}Ÿs)NÿD´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4К dA€Éä’­IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_vertical_pressed.png000066400000000000000000000002061463772530400312440ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íÎ10A&šð„ Pîõÿ³‹²z²z6o3¾àøb—_;ÃkIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/line_vertical_pressed@2x.png000066400000000000000000000003701463772530400316200ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ªIDATxœíÐ1€0ÄPЦzbC žðTV|†d»éò26Ä<®õÝÏ}᱋Ó?Q- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€æXá€\†C¼IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_checked.png000066400000000000000000000023541463772530400274510ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+žIDATX…å–]ˆ”eÇç}÷+¶Õ(Y,wfÞuÁdëj¼°ÒDAó£ BŠS’.º,-É kÛnK´BˆÀ» E7µ„L¯J\a evwfÞ™u«ÅÀJ«uæýw13ë;;û]wþ¯žç<çœÿÿù<Üé°Ù8÷ Eœ|°ÙÐj°R †ƒ”ç\àÐÓ‰$ÿWƒÙì2 ‚n°•3Ì{ÁA{b±Ø·ÿIÀÀÀÀ|Ç­=Œ±¥dëÅtJfƒ…ššá» … P(,”äÉÜ5À&P¬è®“*¶Åãñ_f- ?›]ì:< Û—‰¶|¶Ò,?•hIN:›}ñÇð•w6Æã-—f, “ÉÄ…,ŽåGÿy±½½ý÷©ˆÇ#™LÖ×Ô×Bln˜‚žç]œV@2™œWSWÿ=°ì€myÍ̂ٗ!ÉÒ¾¿¬Ë ‡‚ežç ‡}jÆÕÖ5Z ôNDÞ?4qóù톭Š‚ˆŒà„Cp$L`f’Ôñý¸°í˜{TÒj3Ó„+0àûޏ€ ·ÚÛÚÚ®‡fã¤}ÿ °·†I&}ô¦~&I$uMó/–˜l½çEN–Çœp´+ÞÙþñäßÿ¬k r€F°i?{HÒØä:::FM¼UÌ­îðØ˜€t:}¿à à·›\ÿ$œ5íçö {A3Äδï¿6Äb-=`—‡R©¡‡«f3ìDGGÇhÙžÉdâ ½f³y8í]ß÷ë™ ‚ãæžª`²Ç_‡ÓÌ^jgÁ\FcA¶£B’ôM©µªZ€)µR•A¶~äÅXôd¸/i°Ôl© ’Qº5 0P|®$bá~>Ÿ/ç^T>ˆNUT%LÓûL;å(•+0TlÕ.ó0 2s€üpÏuÝrî«å.tɽ‚ÖJ™:É!YE¬ãÔÅ‹9ÉÙn3él1е•ø˜K-uŽT2­)RèL•׬·D¸¾¯¯oìÚÅb±Ÿ€gÎ[~¬¬Ëó¼±U:ÐÜž*Ñhô*ØÁ‚ûš›·‡S^ùõuf¼ð…mÙ¶¦²Ù ÀRàGÏ[4ö7¨8áiwiû’Éä¼²½³³óÖµ‘‘Í`˜b;y‰./Ù®¢‰D¢ÎÊuí™´ f2G {8æE#OW•cßïp`§‰u@T âM±¯TpÇã‹®Tˆ’,íg/cœõ"‘US ˜ïÔÔýZ"ñAk,²k²‰$ÀÌ “Œ[ÚÏí½\uGŠ[}V—Òð

­9Ð9‚ §µµõòlòÞÙøýg÷/EqúIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_checked@2x.png000066400000000000000000000052361463772530400300250ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ PIDATxœí[kUþN÷îd7d^I¤2==½›ÅP$”JP âjP Ä@¨’Gñ Š( U@DPRTa2) ¤ÄB‹Gª¡¢BA ˆƒ„ÚÍL÷ôL²„ðÈØ™¾Ÿ?vÝ=3Ý3»³)Kóýës¿{î×gîÜî{îi`?öc?þŸ!ûbþmÛ¦·Wú(j st8ÀTt»î$È„ú·FnH§Ó¹‰Ö6aÈçó= ¸ ‹!8jŒnr$ž¢†û» c£ˆ°¥"Ñâ»P8J]ÈÂVú CÁ²w¶ohþüùåúm l»°¢n'0¿U>ë pi:•z°3bÜÈf³3¡ëw äÜšð7¬‡’ÍÔ±Eïj•ÊîJG‡—(•ºHNt‹¢ä8_Ðásƒ.1MóõñèW²®ûyQ|ÀaÕ­Ü È“By¢­MžN&“ï4ãÛuÝNÏóN h§X\{ Ap‘•Jý~,úqÀ¶Ýs(\`R•(ðn ¸Õ4Í÷ÆêßL&“˜2eêw(¼áv·X¦qƒˆ¨f}7’šwopm¨I ¸ª¬ë?ïM& Íúm›7¿Ý5©sè*B`JPÿ`rÇysgÌØÓŒÏ¦@R³w g…š¶R“Ó» ã¥füý…B²ÝSU/¸òJ¥4ôåÞÞÞ]úÒšØqÝ¥U7/xQ¨æï«›€Þd² kÒGpM°…ŸmOt¬!©7ê«áËç¿âáù(ï2˲†õÓJ;_¸à­Ü o·Ló§øh([òùù±@Ç'ù™J?ogÍ"ç8?ä.¿àݦù`\ߨ …CÊžú'€Y>óKPÞ—šýåmÛ>šv:‰£$’è(@P…M€z´Ù=I±w%ßö™KBu\:ÞÕ76¹|~%ˆ‹|¦­ºà˜T*µµq™L&q@W×@» àœFúò „w§ cµˆxôèïïŸÔ–èXðxŸy“2¾°P¤Rw¤(§[gÙà3J;Þ²’/6"*—ÏŸ&Äf7¯_òÇétz]#ìl6;SÓÛ2õù¸Ò2Í»ëõ©û ):äW~›€k¹ù7¶gíü= ûÍ€|†¢=›sœ¥$cŸXÝÝÝo¼%¨Y®< ^ŸºNíB¡ÀŸ©,Àq"Ç9èàé3ŸÁåqÜÆ!7:ùŠÅâäXªR÷Bß{IàСRé»õèõg€ÂÕ ‚ßš¦™;“É$äq¿+´IÓ,Ûu¿Z‹[3¢ëçðGl]ww÷[Qƒæò…s ¹$NÜø!7lqœš7ó1CÄ#ñHÀ¨pA-nÍ8%莰X,N–‘·±} ²,îuWt jœ\«OUá–Â+ë‰l¸ì]…à‹ÒDcžã.Œ"¤“É—øgí´\¡pt˜W€ááác$>±ðÕžžYù0ïãVRàñš[ ¯ŒjEAà‡¥ªò”UPÀÜ@'`C˜ã‡m¾Áôh¹‚y[\·7Š d@»@;2Ì©±Èþ+­¿šó ¨ǫ́ö‰„¦ÔQíB†´óˆ0§Ö"˜èE>ûEMx¸þØÐªþÓ~ h'`…9µf@WàJäýH²O¿(LÆPÂڻ„`€äyzÝIµ³µûBD Nðï™L&áçT@Â;ÄvÖMx¬éßTZ­• Ð>^Uâ îö_ëJUM›½ÝgG¾!N$DfŸmÛž$@›ÏTš;wnÉÏ©µ2ª$ŒQŒU:A˜Œœ6°;̩ǥ W­œ!™¨ö‰=¶¦%º|À®âTwSoø¯Dù²AÁ£Qí *rl%^H;7Wû@è°‘ Â?ÄóÖ ÐÔiLk Žiš¯D1´`B§æl­ À‡/🿮¿P¨û¸±,k‚ûcõ¶"¼/*%?òˆ–E£ÒׇyU=[{ÁokSjQ˜çG¹½ý&;£%·®.Ás€0²®{4‚ï(»ìô¬a^í|%¼ý]5Xïa‡½M"2cÔJraEqôjÍO×J× @›Æ5)jØ;â ýÛ¶EîøÓXà™(N+ ÕV*¹&ŠCR#%°Iʵ¸5J¥¶‚Xë3Mj.‡ÃX(RòÎøf„´(ñ¼HU¹4î8Îq g‡asfrm-nÝ×XMøëÐàßËf³fÔÀ–e½¯'×ÂØ RØÈJå´¸ã¸L&“ ð¡ÞwÕ;ª€T*µ 1LˆÞ¶4N¨išY(u,€šˆ‡uMúâ³0yÊ´KÜö¾;üQÇŠzüºBi×…Ìç;޹Ff‚2¾ðgí-š; X’6sâ=x³XŒV2£9NáTŽ,RÇ´Ò7€¬ËHoe+Ks'ì£)ÇqޤÈÞ¦£›Až$ð€eË÷qØ'ŸÍ ‹†V©,àÈÑÏæ,¦˜*@Gò‰»¸€l†p³F>ŸJ¥Þøo¨EÞýØÿ]ükul ­IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_checked_disabled.png000066400000000000000000000024701463772530400312770ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+êIDATX…å—[lTU†¿µg: $å"F*Ѐ)L%‚¢ÐÖŠ@)9R"ö!&ú`‚‚' õÅE”ÚòÂô¢m(ÐÒ¾€kCÀBb,K«10Š´Ùˇ™)gzoñõtöÚëüÿ¿×Ùk¯}àA7JpÚêœ$ëñfбËQI¦FàºB ªõˆ·2X¾ÿ—ÿU@º“· lM¡ Ï÷,¢Û‚e%'îKÀrgÓ±ös`]ÔÕ¦PmÐ#a¤ÙgÂm¡°õšÃj§‰H°˜¯±äž¨*þcÈÒ¼ÖJ0+B,þÐIêê Bý‰öûýæÔ…ë¯ÉÀ5cíªc•¥ç-`YVN²Ása‚À÷ž‘ÿ¾väàÁ¿ú#înoŽèuwŸ ¹À?Š.9^^Ò8 €ŒììÄÐÝQ§AgƒîY4gÊÛv(änü´¬¼­*² h1j«(jsx»¿º;jo„œêÞÈÓVç$©×›úð¸€Uô*"‡5ÅÝ´¶¢¤05+?!ßû-°Ð^3º6÷i0g?Õ˜™ÇE·cs~¿ßœ>ßò®Š¼ŒìcÅÿ¼W[^ü©›Äqß-;欖×ÄæL\¾0»TegwòS®Me_ä£ö¤®Íßç^\ èPa{tXèžëžµé1…eÀÍqž[ûݨ§.´ìÖß[S?‰Ùœºvã[n÷ñ²âJà07}Mî“=(veD™1ÿ²¬œdÀàŽ­®ý0uUî¤8i"Uê1kz –¨Ú£nw ‘Ól¸6Õ=ö„öä(v|t7¿ß/Å `ž°Ýàr dBcž‚‚+põ>\sÚºÅÖÖØçÞ¿ˆ0=B¨a¸¦ñï& ÉQKÌwO€¡.ú”î~),á/€áô‚ñP§GLbNöСÕQu+æoÚÔUv'šDø$:7 ÅBTÙU(vW”(²*ÊZÙC@°ª´á$„q7l¾ôÆxóP3˜ƒH"*‹çNÞéö§fm\mr?_vÝ âv¸µ²@FvvbÌßPTÔyóa“ º‡þ?Ge×XÏíuî.ê8ŽawD nÕ˸2¹|ñ§ÖäYóf ,ÔPÂìõ¯¬Hz5Çq|·mâ^E6wÀ>,/ý±{\¯'Õ¯M7§§Ìÿ!M`‰GÃfÌšw;éÑ•ç¯\©ï·$ý~¿I˜ð„Ó®¾2T"W±´ÚŠâ†ÞâûÝ×K3_›`¼ENÔÕ"P zD0ÍÛÖÞ¶>o¢E§é‚®¦«Hm§éÜPøê÷¾8õc²ÌÉ]h¬)žL<ЈحÁ²ÒÚ‡ôköbææi!Ê#ËE5I#mÕ´-¢Zx*kË‹. ÷Á¶ÿ÷€Ú°€ÝBIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_checked_disabled@2x.png000066400000000000000000000054671463772530400316620ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ éIDATxœí[}pTÕÿ»›M"æCÁ¯?0È@C¬´ÆÒÈG²…`6¼V±h ›ZÛâ´Ne¦®±Ú±#£hØ@D£m—¬1_vS…Ð"5DÅÔVIB@ ûvßé!ðöíÛ·o“]¦Óò›Ù?Þ¹¿{ÎyçÝwß½çžÎã<Îãÿt.ŒJ‹.‘kž ÎV ¸àt¥B„~ý þ ö³ AØÖäqŠ·oq ÀÌ»*2…5P*˜Š¸~˜j1sCÔ´Ö¯Ý €cé#ûЬâ²Ù$Ä£žcÝ{™°¢÷bñꮪ*9VJc€ÙŽÅ3¿05V:õÁ]<ÑTW½1#À¬"çedųD¸×€¦0ð.1¼ > Èò ƒzd1p,ðB$Ò@4Œ Dœ ¦Éá2°ÍZÚX·vßHüQfKe7+ mp…¶cÞD[·Z7m8î\iYò¨@ÿL‚˜ â"=NXÜ\ç~}X7€ ßQ¶€ˆÖH qŠè9›ÍúÌ_^[Ó;\ýjH’dëSÒÊ<àRm;OçNÎx¼²²R‰VwÔp¹\bû¾î§Àü˜¦Ic¨l¨wŽV¯-N9aáç.T·1h³_$,ôz^8Ψàr¹Äöׂèn–nA\Üè©~?}ÃE¡Ã9ÖO؄Рw·5éäô†ÚÚ~³º,Ѷ¾®DiÄï ³ëÜ£Ñ5|¼¿½ÿ²É·½š ø®! Zc\ð'dçLÎüsGG‡©/„éØÎ‚°Z#~YNñK­¯W÷™Õ+îxÏß¹¿}Sæ¤O€(§G3N!9©³£½ÅŒS¯@AÉâ©€Ø I%~µ¹Î}â°:‹ùçψ°R-cÂý-Ý"õ€YÅ÷Âögµã}9Õ›·¦æTTŽ;'‘Å̸ž€±ü&à03ÚÉ‚úaì¨Àá¬a‘Jæ,rë«Ú ;Ftº¤¼šÀ‹U=ºáSnjÞ²®ÛŒgƒŸ°ô¥/0ÑL»Áô\º¥ïÇ0Ó¡°ðáDÿ'ßpëŒvÿ‘Œïz½•þpý„‘Ò|©bZÐÍÌ JÌÞ¼½¤ì®>%mÀ«`þæàF¯ïSÒvÚ‹3ÍthhX= Èp€ñõŒ€)¶Ñ_’µ¾Órô¾)AF€{}:—“_0c ÛG…øž¢¥D €`›c;½*ÓËÖž+À[S3@½´I’¤žàu´Eö vÒÖFǹ!a¤*Bœ'Ʊ sȰ‚×[é'Àp…W(0Ì>O/-M`U‰|ǧ愮OjÏ^éFF˜ñEdOã"ãXz¬iÑ1-'4À§ÁVBgNMû^ÃöøÂØv¢rmÐ5£KKÑ[ìW_Èp±¦zÃö8‚XÚ&A¾3p@Ë €`620MËQCN•›Du#|ÚX_µÛˆ ˜ƒ}×­!ðYm;œI0¥Ðá û¹Ì S ‡c B Rò.—K0hNáÕòBpúlm‡Zæ'" ¬Âÿ$€£†ÇŸ§”•F„w>ìÎAÐ…úý=;µ<Ýo8ší¯Rdd¬Á³þ+¦ˆ£XbùÏÊ“FZŸù-½ô¸nXVj¨Žšif¡´ÈpÇçÿzì*FœØ€^i®s×1\.— &í&íe=®nš·¬ë&B“J”(+Víqx¼ÞJ¿ðßÍ@<Iß“Sä D8ŽÛ±¯û¨Î!øR>’Ñ¤Ç »ŒeðÔ×~h¦£ìj#ÃÞÍ5}Ì;ℊŒ»"ÇI’dcæ_«e̼2ÜéPØ4o¬~›8h2´YODò²µ~}§?à¿ ݈ Ì<.Rò"%f WI­@ð¶·'ÙÏkÂñ62¬,Ñ}vÉi¸G‚|ä[w‚è—¬³ü4 Æ×-m®¯^iÒ€é÷TŒ!Я4:~³e˺°>fV;;Ú»2¿“ à;§EFá¸ë¦¼vè`û7F}»ºÚ”ÎŽöwÇO¼¹šH¹@`z÷v”€Ul?hÙ¸ö]3$I²ÉrâVÐÙ´{zƈ²îÚ¶v(âé°½xÉ¥lñïã2•x»õDò̆†ÕfœSç§’”Û£„l f‘‡Î ¿¨Ìí$È“F}­Ú][$”8×X¢ÉBð´He;¦ $òÎ[ˆà…ª"ŒAëZêÖ:1‚‰\iYrúq¿M õ`Ÿ_þ 3?¯–ÃÙTﮎÔ×t‘T£l!ˆ‚*.¨ºH}8Ú§C½Äù0+¡šÏˆ°ªi£{™¦k„:÷ïÞ“™•s€ï1äœR’ò®ºaê]{wˆÆó‘B’$[Ƥ[_°Á²Q>’±¨««ÍTÍ`Té¬tê[ŽÁò´³ Ü–à |/UdG£k$°/¹´/Ú  LÓ´Oøï6ªÑ"êBII’,½Júï ¬b2€5¤XŸnÚôâ¿£Õk¹Ò²ä娙ñ·r Ë=-žª¨6eÃ.•µ;œeLXƒÐOÛq"Ùm0$I²õÒóñ\óè-Ãeb,53ۇÈËåíó]ÉVË*šL@þÊL-JàcV¸'aTÒq…ú¾”Â@Ä8A˜ÀL¹ š pªÎH`i“ǽk$þÇìöùå…Ìü[ .râB7ÀO¦S¿{8C>T] 1XLÝ=ĸ)–ºtX!§ø«£-Ð4BÜþ45»¤<‹R˜0|©€Þ¬¼œ›=öáüÀ„øÃ>oÑ•J‚e²e"˜ÆHŠÁ“›£úúà `hkõ¬ßÿ‚Zäó8óøßÅ€ꀲ·úIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_checked_focus.png000066400000000000000000000023201463772530400306410ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+‚IDATX…å—]ˆÔeÅçñ+©4$¬\«%ûX*uV‰>4QÒtwkÛˆ"A¥‹.‚JKÚ¢2» ¬ÐŠ ¯ÌvVÍí ½]Í6HŠÀÐV· %Ólæ=]Ìì8ãή;Öçfø?ÿç=ç¼_ÿç¸Ô¡j’§·»&‘£Ñò‹ÌAŽ zŒv)G:Ó¬ŸÿW3ÓNE{-0kˆ¤]9iUW“¾úO¦nö•ÉdÜz¬êÅÞî>SŽƒÃ#½'‰ŽŒ—¸AŠsA Àõö‚–dô{ÕfnõM1çmÀm@¯Pëȱ|´s–²ƒN©Õ!5…Ge¿ÔJŽÖ¢Î‡Ô=dÓ¶¸6œÆ[©'3óurPáóð@‡G?׃–`NëîÝÍÚAõ¾‚3Þ Ô×eºÃ3¼¢Xx¶êÛY‰½èÉZ©}«·4%ÙoÐßñ]PÍöÎïû‹OowMˆq)Ò|ÌD bvdáÃ2É{m*íZ¡¥Iyö$W\ÔOSp—á\V“öµèDñe«CýžÇ~ YyÆœ’ôž&Þ)©Ûìá—'Ý ÜJÔ‚L³:úÞ…ÒñJø €`½ÚO|rÜXXÊÊâùéŒ6^7#×c'w Eg…^Ì+zm黢©ŸøÌýÀñ“9Þ/å­ŸÌjИ!ÁhE};O—Æö4‘~îH¥¹³Ÿd`! äZt¶/>m‹kÁ« 3:¢_¿k«¯->K–½ 86õ3€ã}ùŸðy)O"Ÿ†U!]dô?‘eež¾°4»¿TSøK‘µ jñ¢?XúÄÁ<'*ȃ8wò‡¥öb Ø…OrcG¸Åu}1Tw/£ æ AâÜeäG_Œ¼¢h8t±€Ã¥'N¹ö}àJ øWn,£;¸Hˆò±¹sÛÙÓ+°ÃN€à8¯ŒDá=àbjÁÙ˜ –;Šs j_÷30,Év£SßwñÚeuùíjÕ-­é\¤s7Êh@TH÷3ðMƒŽ_ã†]ÍÒR²ì±ð¢Š­ðÇßñjidF :à‡®FнAÙ ÖʼY·ÖwøŠ¾ø¾åú'{Làu ¾Yá5³á±Ò*Z·Ùí|QЪ«!@ª-·Ièq`k¦[_ާµùöqÖ|ÄDÀ†CŸæaÃÞýT¾V}:n-vfš4{Pù>Ð{€[ßêìÏÔ<²Ù €[”«¸¶Rí<+ûMàh2¡é…­.¢by)ôƒà* mTV‹w¶èÏŠ" ßÄwAË€¿uog³öžŸ7`}KµùfámÀ-ÀK­—aãPšÒShv¾)ôÈjØó°¾­”>h’ö˜Ž€)„zlo‰ðY.ËÁd¤÷ô0â¨ãsp}qžómyßç˘Õâ®ý6Æ*|ªÍ3…×÷ %ßb¿ÐÊL“¾¼PnUÍf¤}ƒ#Ès€ò4ô z@»BŽôîfýX ï¥SëÛx¸øà6IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_checked_focus@2x.png000066400000000000000000000051401463772530400312160ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœí[kÕ=çÎÌ®ƒ,ˆøHJ(ƒ1–®Lp™]‚+˜¤T‚,»‹¥â#*&ÆÄ$&Z¥‹FÆ–Uµ‚¥"•d`w-Q«ÄµÙ]^jùÀ2QB4*ÊCyÌô=ù± Ý=3Ý3;3”•pªæG÷ÜïžûM÷íûø8€8€ÿgp4rJR‡ï‰¡‘ÖŽ”Áñp€A"¶íý½'è À¼Ž(–÷Ná;•ÖV±ŒK雎µÓAN0ª_N„w`´ÔZó𪬩òª,w$6¤pº…®0±œ® ¼*pVæC<¶æ ¦Ëè·V74c;5”ÐËŽr™{ã[yj×ÅÜUŒÐúN`…f; â0Ã86‘Ú$kÖ*†Î¢×);àÅ.ëŠ Ý­\T54‰Ng.ÀK\¦ÍÑëV4qs!Új“ªª‰a¤+_Hë xïð4æ-h£SH3ŸTõÇ;µŒÄ8—ym|]™ÉW/0‰N´Ü­ ⸞Vv"jlJSiuˆc áçÀKÕÛÂe…‹u$½ à°}6‚×t·ðÞ|uò‚ýÁgœ_HçÇ< X"åÜG)UBçà$BÏÖw83Ѯ막@¼Í£ºqÔÓ:8_¼NRh0ÞeJ;Ö´‡‰ÿ„†Ä×RˆW…q …ÈöÄhý}Ì ãÆ·á~ï¹L‡ ø Wäãç €…~㾦ôÀêi|;¨ñÚ¤ªÒ{´HÀ÷ÄöÓ¢i=v'ô ÌôüQ‚®Í77Èé¬.©¯8ÃeJ+jn ”'q`ÔÞ 1W ˆÖÄhzOc€·\¦£6ü 7g"Qœ‡¾­ª} /ëiâA&á|‚—…‰+¼©~¡rvf´Ñ!´ÀSËØ‹rqs@ÐYƒå’ Ç,ÑHwqÊ Í îãÓÌI¹êd`ïˆé~—"ãà‰ ¶b®…w¢TiŒÜÃô B÷:¬à¾koŠaŒŸ—€êÏQ ÊeziMßóóöáì¤"Vúy¨ä2ƒÒ5„›i)yþ8){Ÿ2+ø¶§=¡,lŒá‡Š© F&ê[AKãÑ.Úýœì1@öÁš·²8nºì´@™•„AkPqÄÀ§'ø9Ù ¿á¾´@à»b¥wƒÏz¦ÝÈìñiFø9YEði î×ÁÏaA…–¥½ÆÏÉ é%Y"ÿ[߬,×níþB`º¦c7÷J°ª6)÷Ÿ#¾"-ònxL˜“ËÇ~D¬TÙ°Ý}í¿#ÜØ»Îœ!V»ÏF5€¨Ë´çõ6îqsr ‚ðì¨Ú¾SÜ ü+¤¼’ ÀÎC1ØgÚîçdÀjƒ‘5rºAèÕ òJB!mËÁ1>Ó»~NŽç׼ᾢlàd2å„ oÛ£]Ðú,YUßa#Çgq\8hžÞ•Æî¬ "v¼÷ÚdÝ1Yˆg°€ûüý»‰å}Ýt]Ì]”•[fH|0pK¾]àdo%tùiYØ{¶¶ÒS˜ìç¹sÌ-¶*./6FÌ"ÔÂxç(Ûâ‡bµŸ—g?€žU¡)A-o㇃wŒÊ ò†•mÜD1°Í‚žÊµ=ž3±æ£/©aoeœvJR+¾øÜâé@áå5¯g*ærÚe@zi´æ‘\ÔœXÑÄÍžù¢2PŽZÿq¸]™ÙÝwpúf ¸ÒÐÿÔ\vW?çÂ{ó~|è—ýq#ï4VäŸ<×àOÇuèè †_jæ§Žå$T"ÄjD85ì8®6©*I¿wÛDÎÎw:”7«¦b¼ƒa•;3Lçêi|{7YäŽxÿ ¿™4Ã6f`` —ƒžÉÛ–˜Áœ|üü R$oðÙ.L¤‚×à@ßÂürL?‹ÀGgô4›óÂ=³D‡QòáC¼}Eój\Éu7³ Ô<_J%ëÈ01]™énáðXIs|VÇ…­€îÈdxlo ï/ä¾6©ªHF áÍ!z%óòž œëÔô €/:-áÅ¡qž¶tw‡Õ߇1K4 –Á m•8}»È‡€€ l´–4 ¶¥ñ¬Õ†úNgŽÀ+]¦´!LJe®” ‘èP½¨.oF˜êi6—•’ ÑTü°Å2¾«@Ý綉¼¬·™sÃêœ$•èР¼ÒƒÛsu±ÿVÙ ±>…«͆ûq¦îéiŽü²Ee‰Õw8wŠ¼Î£xÞ‰rÚš)ü¨_¥¢6©ªAûg‘—z ˆ§ã‡prPR„Emg wÌ RÞöpj4£U ‹4²_¥`\§Ž¨‰ê٬ίíÏ)´ó@?%ÏN*²1jïè¿ÅÒ€æD`n{±…ÿ)Öo!hH*îDñ3B×â+^šÉðÜ5m,jQÖÿTÙ”.eßëÍ¿1¹ƒÒÝŠ›YÅ$,aÂsŠîÚ‚é¢f"Ǥ YGgÌu…æ¹QR²t]‡ Õ `hŽâO=™ÇÇ3Å£6©ªA2ö,€MrMÃÓ"g2ÚçCÉéòu‹4ÜXÝ %€–ñ¼,Ÿ£Á›þ!ƒ-ÕQìH8fjlËÁǶàéèû¤&ŸðU"gô4sM)úËöÁD}JgJº@¥ÃÍo9ÚÁ_úsËûQÞOfÚeÆŽB“¡®PWVßÀÛgÅ·bn± šA¨ØGSu u¢1vúÞŽë§›÷=ieYõ ^èÏ÷aØ/ŸÍÕ-ÒpZL4²'Š<Àƒ% BßÉÍVô}6·ÐzÒ¬ñ|OÞø*ä"ÀÀÿ.þ ‘ZÀ‹yåmIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_checked_pressed.png000066400000000000000000000024101463772530400311670ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ºIDATX…å—[l”EÇg¾Ò*x!-‰‹rm@±Q£t·èƒ7$€\4VC4btKa š  Äµ±¾@º]ZvmbHx²‰ T@I4𤥻6<Ø`L `iK„&»ìÎña»Ë×ûEßø¿}gÎ9ÿÿÌ73ç Üéñ8û*Ì´©äQY‚0aŠA¹ŒHÂiGmSKdëoÿ«oy¨¥xqŒY[Eugkdë÷ÿI@qYä~‘Þz`mŸ© ¤Y•ê¤Îë?¦kÒdc5ÇŠc KÕ²av_úãN*µ¾¥aÛ•q XXq`žIÚ£ˆ> t‰œòÀµ/OUU%GœR0h¼Ýo€ì-.Xu&Ryv̼›öbsZ€iÀ'—·[j+ÿ‘xæByS{©CX\Gx6v°²mT‹¡û’ ~(R´&îéyª*;òÛPñùC;Ù t¨¦JâÑw»Ü9CR½„E(š‡"OŸ„Ôå³,ÈEUŽA²¡?hkD«}åµ…ªl0â]¢C®@‰¿ÖkÑV„?ÔæÍGýfƒAãëÎÿ@‘»†™òuU>ŒGµn’¢Ò`îäü‚³ÀбÈÖã™1㎶¢Ÿ¨êîäÞîüC}K99Àj¼þPhvríU úæ\íË (.Û?å% çfOOÄÕ×]° ä­ˆ]P@Ê}þp¥ÛÚ 4ç€ÇKüµO  ˜•€ ko¬JdìÞMû v<)-C?}jKíƒ.»¢zÀо2H"/¤åÛ~é4§˜4vYLqlt¬1ߥsÊâÁ`&€#rÁ¤ÊŠ §!ú²û3—äy…ƒdŒFn¹Ž‘ P8q™+9«“œLî‡2Ñ r#ø‰Œê3g”ÜîMÈe€„8ž¬Súº8aÈ%÷×½ÖxÒºèÌ\p·g§ò;€±Ìä8…h¿Xs+U БµÝÕS"²Ìä ‰Ô‚„IJC?†¥ ? Ê‘fU]Q\É»–He;7½ÊÞ3 nƒUY`lªi€¶p SÒʦAï†~¹4ïýñý mŒM¿ºÛmñn ¯(~iýb[¶7è¿Ã­Ý BpQ t_Æúo©æ®Q´†‘GaïÜžékÝU´¨4˜«6]gv[ Šý¡ÃoGbžk¯,ÇÞòšÇP)–³H_þýFŒÖÇê·ý:`5Ä[V[àNÅ"Å# H÷? €}1ϵíÃ5$¥¥_9¯§†^oyx;ªŸ£t¦rÅ×tº=†lÉV˜gR© øú†ã¬k¯Ûü÷Ð$C£¨4˜{w~AX`#pà ϟ‰bý†mJK6†¶ÆQä²@ðÏÕCciJ}Wò_³*{æªfu<ºåç¡ÜGlËŸ|gÿÔœ<)í3uˆÐŒrkÎçØD×Í”X'7Ç£†ÙÆÚeˆYÝ× œÇY×Z·¹{8Ž1=LJüág,Z úÜXü6UvÄ£•'Gs×Óìéòýs’ÖYƒ°í{št¤¯W=mÕ4Å£sãÉ{gã_^ï×= ²_BIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_checked_pressed@2x.png000066400000000000000000000053641463772530400315540ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ¦IDATxœí[{pTÕÿ}÷în`“dƒÒ‘Ø–ÑX˜!» R5"ÚÑZÅ®õ1(QØM€,ÂT[©K¬v´j»`ÜA¦­™Q§:ŠLµ¡Ô"d–úÀñ4JÂ#²ÙÝóõ Ü{÷î½w“]¦Óòûo¿ó;ßùïž=÷<¾ œÆiœÆÿ3èT42µ*|¦\@•€˜ ¦óA8£ 8€ ÐGÀüøPJÑÖkj;ò­-opûÃß—ó˜1„)CtÓÁà7$ÁÍmÏ.‰Ä9‰œ€É_Å û\ž[ßxŸ@õ‚/´7¹rš³¸ý+/'¢ßðäʧøÌËÛ›‚ës1"†€éóÎJÊÒSÜa@¼âV!¤=@ê3Qm½Éc©”<"Y ¶"F™`šDà üÀHá[!¤š¶g0ýà €§:< ŒWŒ×)îð:^%YÚ´cõâîl|ÏXZ?rà¨m×0;CýîŽEƒ¿Ï^ý †·?r;¯P&Š9—íý³qáÁ¡úW¢Ür8Ç”, ¢‡—F`z46þÀC¨«ÙúÎ>¡äÞ?ö? )DX'%Q·}MpoÖ~-àâ»/ŽÛœË@ü EšâWúdyî‡O/ú6ŸÙ ’<ûÆnñ­*;£nŒ=Ü‘•¿!búüð„”Œ—‘>áî’˜¹=7j¼ÜrˆÔ+®0:ÜLè_PÈðoÛÚ\ÕO̓’–eZè:ó.\] àj…)! ñˆ±>¦B—k5À•Ƽa€hŽ{¿ËtNì.ÝÀÀ''ªÏùÌÕu¥W7"•¼ŠEoo_so—Q£ÞÀª;˜1ßLÜpAÀCžaÝÎ|‡––[RDhQÚ$æ»ô¸º ÐuËŸŒtû£Nþ`å¨ÕáÚïÖòÒPàt\ÀqÒBïµ7Ýû•–÷|¾e"Í5ç¼Ä°¸®N¬zpÌéç”:éGÃV£v:\]—‚q¦¡˜ü`òôÀʘÕÚ‰q¡–“f¾@õâ-GSáfÃò<"ÉÒ£r‰¡ÖN¸ £5a¢ÊÀdøî(¯§À†-§ý§U°Û´ÚË´”ô@(V5"‘É^ÿ”N~*0Á¨¼°Ï©Õ^¬å¤Ï¬&IÌ™ÏØWez§µ§l€ÖæyqÊ £Ür(9zëÕ))‰Œ3ëgu¬–c؇ë@O|¯ŠÀrÚ°ùÇ÷Ù†+ļ‚axú ªU<ÚDÄ¿L…æ d€c¶Ã£4¦^-'}}©jCJŸ9Õåô¾Qy^ÁÆm³l;OmÀZŽÎ$È)`¼Ø ¼dTžO0Ȱm¡Ò΄=ZNzHR]62«EÒPt¬h3€¬ncrÆ—íM‹vS4ÚuFLZúdÚ@yÿ^1}~8ã릵¹ªŒf3½y@“á‘|($p­ÒÄ2·jii¼[£mJ[R¦kµ<%R < à°‰à\âk{aR{ ‚·sŒê5Ê‘3ÆuÇ´<ýw8«wQD<Û¨±]Ï¿!°É‰Qî@ ·­XvÌ$I*Í lÒ;× @ÊAœ”ݯªó`}U4Þ@`v0þì4¿‚³æVŸ¨÷7Löh¨Ê׆ÿÇÐ7µÖþV#^kå·J@ÒL­kP­SºYa‹Â÷ýzíõ‰Ø²ü±\@0¶º·Šèºn½ö|}iš„”¬ ¹UŽM”}§¦‹ˆC[% ÓÁ¡ -®ÙDÍîñÉÉÉ®ŽÃ% pÇ[<Ï›» ØvïÀÀ‹È—J‡ ¹‰»Á²U˜FC]Nçr¹þNÁ³ÙlÔêç :¤=ïŠÐ§À}‘h÷Ç’Ú^¦’¬·¯ÿ]`ÆÅ¤ç}Ñü¼ ߯Œä‹¥·Û‘¨@¯/ó.<×YIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_unchecked@2x.png000066400000000000000000000041671463772530400303720ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+)IDATxœí›ŒeÇ¿ÏÌÞÞ]Û»b EÓÝÙ½»ZÒbb9¦Zƒš¶P$Q0)©R5F Ô`ÖU¨R~˜P ‚i0A¡±†ýƒ¶©J.öÈ]wgv÷Ú£–"mÕîy¿þÑÖÎÌÎîíÞÎ.W½Ïó¼ÏûÌwž}÷™÷}˜a†þŸ‘Nœdôðáy]ÅÊrŠºER.Ð/€Nà8Àã€ä9@¨¿iä¾d2™m·¶¶% —Ë (àf*¬†àS “%ñ<5ü<¿&" U$BNI± …« Ô@V„[€4[Þ:räÉááárˆqÃÁ² + j3á°bÖ:ÀIÃx"ŒÑr2™ÌÅÐõûò¹:n ÀïE°JF¨ã Ži•ʉJO-•úHÎt“¢r9€è­sŸ®O$¯·¢¿¥dòù‹âï«nå @žÊÎHD^ˆÅbo5;ŸÏ÷:Žs%E[`uð9p ‚µ¦a<5ý@ °¬ü > »JøÜ“H$Þžj|7ét::gNÿ: ïd¾¿Ä&3¿[DT³±›NIÍÊå¿àN_“ðñ²®{(+4·FFþÞ×Ý{ê6o'0Ç+ ;þ9«çóKæÏ?ÙL̦@R³ìüv>ëk:DMÖ¤âñWš‰7UF …X—£ž­žpåO•Ò© o4–Ö̉í|~cÕÅ ö Õp§.†b±‚®Ér‚Û½-ü`W´g;I½ÑX €l.÷¿ô™·A9·š¦yªÑ8aBR¬\á€÷Às-Ül&ßh$FC 8˜Ë kÄ>=ç:òÉ„aܨާ³fÉÚö×¹ßm#xS*‘xb²¾“þ …Â…±®‹ð •Z7.’†ñ ˆŸ¹myÔ²¬¥“õ4e¥6Xà2ÒkÞ­a„ˆ°R.®ä.s”¢=º›ŒÔë[7m{ˆµ.¡´O†q¨Áí`hh¨H§|­G]æ¥É\îKõúÕLIÑ!?pÛÜnš±ý-jm©TêM‚›Ü6Ü5111»VŸš ° …å–¹Le¾‚Îö¢Ô#äθèT©ôÅZîµG€Âîcü$‘HdÂQÙ>ÎÌMžŠÄmµž oƒÙlö½Ðô€³Êt*ñT*õf¨jÛIÝÊåú¯Qð Ó0^ôûŽÑõpîâà¥óåâ@DO{Œ 7ù&€À*o@ü&4uBtñj|*èoP•€‰‰‰Ù ®pÛœ²þÛж™d,ö*÷¨›-.óûU% X,~@ôœ…XóûMwDDQàùáD©ªuʪ(`‰§°/|yAHv¶Øï0È%î#m4laBHŸv^â÷ š“:ÓþÞ_ ’íL¿OÐèó‰ü#laį½ÏïzœGojm:‘L&‹*.S4NGÝ>U ÿÓa§Å;»¨JÁîc]©ªas¾`YV·îõ€Ò’%KJnŸ 9À³¢Jò‚¶¨ë§w›<œðû%Àv)èU3çù‚¦ESîcV•Ou7uÀ}$âz£:ÏPâø´sÄï0À·ÙÈe~ŸóÍ» Ò>^þÕÛû2÷þûÒÑB!¾¼öBR#d¥Ç¨ô=~¿ªœÙ[{Ùm‹(µÒï7ÝÉäó—Á»£|ÜJ.xÍï¼@ñ¿þ®Q[GЫ5¿°B¤â÷ L@Dãvœ.j8 qåèáÃóBUØFHj¤\ç¶ e[o` Ã8b—ËÔ)–ýÛáÓÛ.\p‘Ë4‘MÄvùÖ\Ö„?ò_Îd2‰p$¶t:¥ð»^«Ü4ü: 0 ã%€îÉ0*zdcÛʬ9s¿ïkï±â¿{¶Öò¯™!”öMŸùFÛ¶«ÖÕ¦ oŒ_$¢îrÛ„øþ¢EóªÏRwoÐ4ã{ò ·¿‚<›Éd.nQkè¤Óéh´ìüÊSCDüåèÑ#Õë7éîp¥\¼ÞÕÕ¸è]ÏŒŽŽú‹£ÞUf÷õ?ÁG]¦2uY7YQå¤ <¥] xÎÊ+"ÝÝ“ìH­ñdX§w€ouÛ„²¾‘²†j„L3¶Ÿà:‘Xkå øWX: IÉÚöWIüØ×ô@2¬‘Mý‚YÛ¾ ^Ø[êÒ¯{ÿ‚Gktk ét::«¿ÿa!nñ5½hñ•µn{~š-“Ó­|þik|M–Òdõ@<þ×fâM•±±±ù‘®è¯}Û÷ð:”³Ì4͆r§R(©[vþ‡|Ý×Td«S.n<ÒlÜFÈçó½e_áÞãi<¯ÊåëÞi&f+¥²·P¸@—/àI‚÷UJ¥-Í,Öc7IØ…›E¸Þz%‰-f"¾ADœfc·V,Ë-â4¿ `'ÁN©´«Ùd¤Óého_ßr Ú*W z / e}£^-ßÆÆÆÇãºã<âÚ:neöB°JÞPJÆT·ëªTN–J%§§§§O)5—¤IM[ârWè¯óÕ3åòlEˆLä?Iá½. +f üNÒ0~:•!ï'ìOf4Û.\ÍӓԇŒ #ÄÒy,ÌŶ=ÉÙ¶½˜"g?šZ8Å0›3!˜ ¢_€wdÂÜkÆéRŽ;à 3üoòK` Âd½Í»IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_unchecked_disabled.png000066400000000000000000000020251463772530400316360ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÇIDATX…å—QH]eÀÿïê]óÁm!ÌJÙ&+¶¨Z V+õš §3B6mD/Aàèá Ez*ÆbN-"Ÿ®WKk¶{u\_ÃBF+„ÈF]µˆ Zê½÷û÷p¯v½×9/^{Ùÿéœïü¿ÿï÷Î9ßÿÀ’M²¯öx©õäÕ‰±¨”%€˜Rˆ :Šäõ‡gÌ©@•Ó|0nM» O¯³î¢'C½]#¨pZ¶‰µ/$‡f :G&½&>³‹Û<³¥8®v·ˆø€Z`W2ÿ¼Ò42Ðù{ÖUNó^keØŸ‹»~ïGáp[l-i×uÍ¥«SÏïeÀ/ÆÚ£ú»¯¬[ ¼þx™Ás¡HàsÏ]ÿ¼8ÔÓóçZàô¨®~}K´`þŒ MÀߊtßV º¡¡06_ð5胠ï?ñPÉmmm6xj}_}s«Š¼ DŒšƒú:fRLúŒØ|ÁéœÁ Â4Ø×ÕŽÒ ”Xc?%mÑ+N*Ÿkz Ìð‡sÿ°¿cnðåpÇ;k·]öGBÎóK×VÜÁœP•·sðûý‹*¼•Ä\ÌXÔÁ¤Ý‘--ù›ÀEŽ&©ý¡îi„‹E;®Û—sM¯¬?Q“Üä¾ùÏ-÷+Þk¥@·º¡¡0WpÇq¼§= èª#}çÆTéAÙŸßú‰ëº¹xMe6¾ýƒäêÃÁ@ש3ó0¡P{éjä½ JHe}󛈾‚0MÔ6²z¸EK–ì/w}Qãm ûÏü• Ùqïœ-<­È à&اBîoÒó<«Mþé‡ñ{öø Á'pÈ£ñƽû+ÝYóݵk£kvH®ëšü¢œõö‚T’hÅ|Á¾ÎoWË_³-?\÷Òö|“×à$‡"ƒ C‚™ÄØ™…hÜz=Þb‹îª­%Ñ ŒšhcØÿño·b¬ëǤÜizÜXÓ<¹ž|`±­¡Þîàí³ú5{¶îÕÝ1«#¢Zª‰mÕD€ˆ¨Ž"žþ` c"›ºwvü ë2dÔTÂCIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_unchecked_disabled@2x.png000066400000000000000000000043451463772530400322170ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+—IDATxœí[mlÇ~Þ¹Û¡þh!¡ÈЬ (¦*˜V5E`Àœëª˜ø`Õ bㆤ­J”F)9܆~¤ ‰œ!ÐH=l#“Æál§F¤€B U6QR‡Pj%Q±í»›·?øÚÝ[Ÿï|»®iýü›gÞ}÷Ùçfgfgæ€1Œa ÿÏ ‘¸I¡RzwPÚ âÙ’1ƒ€ig€( 6 ¾‰Ô.Gý>ïÇVk³Ì€%÷Wf {¸D01ðÍa¦ù˜™›¢¶µ~×;ØL€ùÐÒâ²â /69÷&líùŠØwjçΠYIM3 À½n±$ñ €yfå4Ÿ'`³¿®z/Lh °´¨|"Ùñ,~%L2ð7b´1øœ Û?Ôý—S@á0R‰D:ˆ¦‚1ˆsÁ´ @Ê` 8j­?\·ël"ú2 @)ûŽ”tÀ$}—¼.ˆ…Ãýo´6ì½Oî\eCʸp` A,q‘Ñ=ôX×\ç}uX€ Èw—=HD5’"D½àtÚ÷—?mïn~5EqöÊô O¸G_OÀ–Üì̧ªªªd¼¹ã6Àãñˆcg»žóF]•£ÆT5Õ{/Æ›7­K½jáq_R×1è`H8Ö´ù^ºOθ ðx<âØû÷ƒè]–.A\|ØWýv<ù†‹Bwùä¡‘î»öäkyMû÷bÍe‹çÆÎñ÷UèQ}B°Xz¸ÎûA<¹ÁG§³ísÈ{‰4sŒIácvNvÖŸÛÛÛc!b6Àå.ÿ/êè=ÁÔÒújuo¬yÌÂÅö¡ÎŽÓ Y3ç\Q>n´f¦÷!%¹³ýtK,ybz–­\7G$«è}ÍuÞµ°`v/òÝå¿ ÂsjŽ µðîêZ1TÀÒâµãqê‡g¼L U`<<´Ô{·±[ÍcW»rîP×i‰¤gdÞ&Ð…,n«­íŽX‹Àök)ëSqÎ0É]yy{´ £¯T. ð:õXbescMWb-ASÓ‹ý27ÿ¾É0×9þ_D».šDáðouÜþ–zï‰D„Z‰ÖFïg lQsÌxÒµf͸Á®Ô€eJÅB-PQAÉa :-E(-´À…[a_MþÉ`ñƒ·Æ/µ½ÜZ¿»3a…£­¶¶LºŠSÅpÈ74 O)ù*˜¿¯¢‚2ÈO›¦ÒbdØz_øC•Ù#3òb pHǃÐN’Þlmô~f¢FKáóùÂ`ò©9?d;È+ÀË55š%n¤@$ôš`ôDp£Çœ¯æ$ÑkæÊ³¹Ù“N‚ nµé¤åèã" àkÎïpª¨¿·øv^ÐÇvTUUI04?œd±Nù °ÈV‰pÔtu#kµ3féc ÀLuQJú0"æN vž©‰4€ø^-!GýØ?(¨×>Uc4 ¤ª Œø·¾i¡=U2¤‚9®5¶Ñ„¶ÚÚ~!åTEÝÁ Y$ 1*¾ù­B„ĸ¬ `Žh6w òJJ’¨×|>߀:&rp}§övȰFžõ°uÛÓuÔe}L¤À'‚"{Î;Irš¦Ì8¯1št¨‹ºÏdY#b¡ÑÎÀ9}L„‚¡Ùld`>æN`Öj'œ‰ˆÑvçq·öß ˜[è.Ÿl…@+áñxƒ~¨!mú¸nì­Ws!Ò%ºðÖû]9Ðì(S ÔùŽ>Îp=€Ýç¯,2UÝ€„^3¿ÑÖVÒÇÀA¹€j«™–*¥w›ªÐBx<AL«tô£XCškºˆàWQIAi×o‡Z?ÛµÀŒ›e> ^Êôź*Ìà?ªË~t‰»ì릩´Š¢8™ù×jŽ™Ÿ3jþ@šT¿I¬é 6ÂfsdZ‡™V ígowJˆ·mgˆ¥À&-Ek]JyĺÚhAÞêÊ zRC2~ÓØX1¾‰¨{ƒ-¼m½¢Žg‰†¥EåRjEq:úå¨Îð^÷ñB´ë†Þ–¶Çu««S„õ……?ÓŽú¯¢W¦oa‘Š ’àŠ¡Ui€¿aÇç,q?€~=?xWßK¡³ÆCÁµªâ«9b¬åÌRLGd:;N_Ìš9çߺ0gÚ7æNÊÉÎò···‡ãVmȵ²üç lƒêÇ Âóþ:¯~gÛ1Ÿêìx÷½¬Y9wøÞ­9}2yá×¾5ïµógN]Gy¢PÅ™9sþË6AÛ/e–ž?$¦3ƒC¾jdPï&\?žv„EŽðÉ|¥rv<¹«øá{zÃi­ÊtUgƒáЃùFˆûVÅÖ#3þ@à ºª €í$í[ü ;>7o,ÈU6¤¤ÊË?eÆF¾¬­å&¶Õ-¾_Ä“sؘË]^Æ„íºª+DxÖ–tmk<£!/ÏcwL¸X¦ÍPŸWºÞš!Oø|¾¸û¢„zq—»l!Õ© =pÈ–rÍ¯Š¢8»Ã ñr+MÃÄXï¯÷VG?`Â0æZQ:…í¶ç¸£„ 8„¿2Ó6þˆ%w;Æ%_‘÷¤¦úÓ),¦ ÂtfÊQÀiQrž$õ~Ÿ÷T"úMÇ]«* ™ù÷¬í ]ÿ*ƒÞá4ùÈt&âúaê® ÞàÛfæÐ `k05TmæEËfr++f1PÂà"Ó‡“ƒ€O%èuÁrOîìÉo çÿ1ÜÃz¸V”N‘ÛbÍä 0M ×wn¾蟟cà‹ð‘Vßã¸cÃþ7ñ8ñàç^bIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_unchecked_focus.png000066400000000000000000000017231463772530400312120ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+…IDATX…å—MhœU†Ÿ÷fÒ¡µ•¢)6´­šÔI²ð§¥´Ti“š©…¢¸p').¢(p¥EDÑMh3i¢©,éBÚi¬¥ CAˆ “F”jµ?Ìw_3I“N’&dâ¦gs?Îw¾ó>÷~÷ç\¸ÙMó ~°×Õ -–·ZTcÖ 0ŠÈWB&Û¦Ë Ð”q:Ú]Àæ9&J¤ýC»õÍ‚ê»}k*ß=]ta÷;„#JY»’":R%±AŠÛ@ÍÀúbö‚öe›õÛ¼šû¸ê\¶š7+?k—:Òu<%û  Fâçhí:õ„ÎÎ`ÓA×Tg5Àa–éÙìcúkVáëlÇ€—þq9¾Ú‡ù'XhÓ™4 x%—}¨¿“=^â5ÅùˆO˜­†^:°ßry+}ºUc“CBÉGWâ Ö¦Aâ’³-t¬KÉŸaOéô€ôAoÂÚcø=I´gAâ“ .æÃ‹À9`KÃ!vÌ  ¿¬×O·ë‚ŋ6Ü®«B¯Ý5y&êymJþü;¯µÃíºZ. 02î3ª_# ì„üeÙÅ$ËÇÝ×~㣅&|Uvñ¢E…¯,m)@Õ…†Ÿ ˆ̺i Î ÆX$[½´˜[Ü9>K÷ÿË^¥`À‘ªÅÒ¼pi"÷ùñ=f€pà®ÅH ¦ø˜÷MØa 8n_,·ÕŽ•T¦è0z¼þW–]Üh@TÈ”|Û¬óÀ1`Måíà^`ÔRç-«ød.Eicm.¥÷9YÍ'[õýtá³–åu¯Zêø!èÉ¢+g»?T„#Iž‘TdìR%qyBUëCˆÛ](ËÇ7œ£1¯½Cíúu&9]LÒ=nîžK¼Å¡Žìn½Qì¼®fop¤y+PMá­rˆèxHÈœhÓ¹ùä½¹í?‰Gc¦‘&ÐIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_unchecked_focus@2x.png000066400000000000000000000041171463772530400315640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí[}pTÕ=çî&a« ~´£ŠN [ lBÁiÇÊqLÕJu¨ÅÖ™Ö±tpF­Øj+¨H[?**Ó™…Íé€:S ƒ|lBÆÖQ¡cë0©Z åÃØÝ{úGPß{»›ìf߯¤Í™Ù?Þïžû{çž÷ö¾ûî½Æ0†ñÿ ÄI®ˆê¼Óe˜Ik/“ÁŠ 8ÀHÇÎüö Ú ˜7Äööù|§ÔÚJfÀô¸.I[»ä|“ú•DxF[¬5Ow4`Hù«Òo$ÖÅqµ…–˜ígj¯ \•ú'žë¼IóúƒpL³aô „©~åÌw.oà? oÔJÛ‡~§š°T›¬Ùgø»R8l-ŽÒ' *Ë€Q2'`< :ßê%çvk¹¤cß(FQÔÅ5ÍJ­¾˜¥ø8¨Í”ÙdÚø¯‚rGJpi真ãÝ"oiðýÑaÀ´˜nõ ¯(J+Ì/_™Ë#ýÍïDuTå•A,t/€ó½å‚V¶ÿÅÜ‹´…æ.Ü€f™ð${Èež+è)ʬH4ò`ÁyóÀ×7ª2iq'¥»œí*ZCi.lkâ‰Brf@³Lør»àõž’.CFvEØ^P¾~"ÓE0Š{;\¯²‚³sx,ß\¦ Õ.ÏÒøÝ)qê@5 ìƒ.t„º‚FÚ¾ËîÂ¥–¤F0K$ìtDËE=>k«‚½UíÕ€p‹f¼ÅÄÆõì*Fo)°eO1ȇáÉÝGp{oõr Ð/<Áu‰Fî.BgI‘¨çW:c‚î™ô¢ÎÊU'§uqÌ0ÃJ¦­i.^fi:†ßØïû¹p[.~N,ôç1¥ßîYÀ·}ÐXRôôMt](Awæd5 &ª/ø–#”TÐÜçŸÌÒ¢*‰g¼å]øžÁ7²q³âFôLUõ€x9QÏüYJ¬obšÐzgŒÆÞœ›ÕAó\Ëç}S7P0Æ£™s²ý 2 8ÓcNwÆRiüÑgy%ÇîWÑÀy׎:X†)^^†ÿA-€rGèÏMÜïå z¬ ¥äºpRæ=^^ŽùºÞ¢Í÷W^éa`]š½Ð6›©L^”°=›ÎTÆUWDužï*K…f œ!Z³65«;êÙ%à¥O*É õ.‡ZÔ^ŽLp„Þù´=Näœùk×1øƒé1õGbéPU¹¤Ÿ;c"Wg»ý^ è¸/ÃÝ–§a—û¢²„8» ß]ƒ·Ãekrñs¯ ‘"y·'vS8®ŒyµÁ‚)Ïë\J®%|ˆ÷ï¨gÆøcôº6¸;Â6PϺøR<¼Q'ÕTGUHiÜ{ˆ^K£½Õësu8 sܳ«UJ©åšÍònŽúL12h!p¥#”4äâ¾6UöiÀÎ~ñZ§>Ž‘˜~¸Û>Ö³€úÙ#Óí¿ïŒ‰\’϶¼Ži!(÷Ž éwÇÓæï;ö€AbmwZ çŤND?Î'EAW°6–~@äR—`[:Èóy(W½R :ªò‘û˜È[]Ä‹¡s87×cÏ‹‚v‰U¥ÍÝâîóáÊ`Ju­º¬\Å`z‹Î¯ êOÞ8^Ÿoã~l”¼.ªÀ ý•@ï-–´&³rg?,4o>¨‹*”⇄–ø¼§xK*Å:›x´œýß*×­”Ö(ó ôBfU!{ì­ vÆ"QËáÞ¯´jlÊ,]ßÄt¡¹‹êÅkbši¨c²´ 2›ÂK…šQUùHƒ™2vÀzÙ†áI‘KÚ#|²?ú¶Ë×´ªÊX=  ¡ZÄ6Yn¥Á_%üM‡+‚8‘4H›¨´å¥4ÆOØ:€W£ç“š\Â;D.IDØYŒ~ßžãµq]#é¥î »$þllOôç–÷ÂßL³Ì´I¨7Ô25¾æÞ¸*tOú¹G±d#¹š šhŒ]tæc‡ñýLó> ÍVfmÇkx¥?ßô…ÊÖ´ªŠ³ìD‘Œ#1JÂHô¬ÜEÏgsí#Í>ÛõØ;X¶ãcÃøßÄÔS’/ˆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/radio_unchecked_pressed.png000066400000000000000000000020031463772530400315300ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+µIDATX…å—]h›UÇÏyûSçl‹Ø²YªbA‘5Íô¯96D¶N°ˆÈœ ×t­éª txƒC ‚Å4­&ˆ¢W‹ít:Pº+é²X¼°„ š6®Åm6Ë{/’~fíZšz³ÿåó>çüÏá=ç<nvÉj’ëš»+­›Ù/*»**P Ê"I„sŽÚÞÁèÑ_ àm ûP:€§V8k\TÅ£G¿_@mcô‘é€s¡H¿*gÔqGõ_“*Þ`¬¦ñX±ÛŒa·Zê¶æ¦ÿÆqÝCƒ'Û.®`{swµÉØ>DR"oÝ2ùÉ@(”Y¶¤`Ðx'Ê_9Zün`ßùhëÏ+ðù  [4l¾rJxy°«õïe©:.Ý4MÂ!à2Âc>nº!ÀŽ@xc&Í5Š~˜ðL½A(dWc>'•:¸]‘w¤ªëKÄ^OÍÏ0‹‡¸ÓDj€þµ™ˆÆ£­"œ*Œ8Ÿƒ.(z€ÏßåE8€ð§jéµ™ÏA\žœlFvzýág–°¢ï¨ê;‰˜ÿ¯µ›g5|*”x+Ô1fj;ïBy˜º:5-”ùŒâÑ@/0<èów=” ˜½€ |=|*”.4ˆ¢Ú`EŸË@äIE¾-¼yVÖ˜ï²(²3*‘ßÖ  „Ì(€BEÀLÐȵTþÐÂèR±33÷Ý3?bÞ9ð¿)øöB1€´8žõò¼Ý€ÂøÌ3·*Ë=ë`®¹UÉÙØÜW‘=ë`Ø  ðC€[$ýªúlmc´¸ðö*Ve€±noÀP$0.Y²Í0ýj¡í½G"{s—Ü/ñm³½ÁÂ]`m;€ÁðÆB™×4KÔfïc z]€ø‰¶¸ÂÀ7Ígƒئ*î,窈G§çÍ7ÐÒ²—F½w¢üýµA¨x›"o"øQÆÝbyi~õ°DK¶½¹»Ú¸î P|yÅq÷´ü³뚆`É-eåÃÀƒ¸°8oɦÔw8rŸ5¶¸_‘1àmžKŸ®¤)­»Xö¼U9.p/T5õ‰Øk?]/}Ù¶üáW:7•šHC.”¡å ÖŒÙtêª+Ö))ò¨a«±vbêsÝ0ÀYqœƒñž–‰¥Kàå†I„ "Šò†ÚÀqËqSÀmóžÏêp¸—ø ™†æ­íŠòðÁW·ÓZTU´ŒÜ ât<£³Ãkû-Åë!¦Ì^S°æ ÷Å…i ¡À¹Tc +ìkÍ^a¼yö1b}uóÐP8îtG Ølhš(;y³ßÿ¦’j¬”…¾’ÐÏi9"Ú4¤#Ë¿w}é™TãØ…ãûÞ‰¶4mß2Úרà.\Í4öÌ ¶AÍM;ÿœJœ”É%¡ Þ`Ðe–ß×IÇêÌ* ŠƒK@xÅ@?® ¼Ö]ßnÉ‹VybÀVènû3;†õ‡›€ðÚ²*€o ×y‹WMê®o· ù¯¹D0šcNš]¿qîëVÓâ3.*áïÒE$×MSUG²žIà-®¼„yŠ¥‚Ÿ~°ª¬¹7vÓOB%*ï𥆞ÔÖâY˜¬_’0‰ç Üæ÷«ûzn3½h¨]Ò ÆJ-G„§'<üâD}&ÀW*p»†Š@ÄÔÞÛL/2;³Ö8¦¡F:Ý®’Dú„ `_ê Ô„«—}Ök‡iFýƹˆ`ø¢Ä²Dkƒ¸ ð-\`††Š(R>k—Ét㆓9¯3ðñ7×¾æSOë]ñ´q cч Y$ðnCí’VÛ¦ uu÷LjP§åó£ñ´q@ ™æOv™ë+°”FÏ?Ž÷˜pqƼUËI޽m¯½ô£)÷t#í¨vÄsÂkÔ™áv}€ë2CÿhZ»ä˜Q×ïQ^.Ö}qÌæ}Ê8€ø®Øc«±>³Þ;1Æ5¦0óͺkÈš+‚¡÷N¸Ù¤1D¸AG0õûßþ„p:ŒÞóŒó di¯IPŸ¿ëÛ…!ín£÷,£Æ<°^$˜-í±õ'ÔoœÓ ª¡\ù~Õ¥ÕÄ[è6I¢Bö‹wþt!^ÚtVLÃæJÁ´93h÷:Ö•wj5æIÐí¨²äáé±—~|í8;Ì@µ5æIô¹öš„yæ¼RÀŠcŒžÀQ£&Î$ȇ´—|Çf_} ©ó΄ÃF9$t‡ÌºM‘+ ƒw¦SÚÚ @{þ>iÊü൶»K7TUp–b…ë2SºÎÖh¯–‹*tQ×ßáká…þDùÜÐQ'ÃF]ü-1Ö¿Eñ,[Ýõ„Ðyf`g}yyÔ$‹×7æ¢Í.53îœ87x•ÝÓU üLKxS `€mŠ »¬&#߯ºÜÃ=…¤`&KÜ B¼ex ÒpMÙúØ`C¹¼oáêë8«p_Y„Ýø+ýK0ŠrêÓy·#‘h–dǰ(#˩ݮ¿Ô$rÞ(‰K߯~¼©7þmû/( ý‚ŸÞɰ«.ù×y'sj{2ä°w!£ªbrkö½´ Ÿ­±AŸeEfçÐõvÖ(¦m%ç+Z5^ žCàYÆö0Ì 0¶ÉM9§ÿÖ“ÿt‡>YÊ^œ'¦ƒy<@ã@È0 ]ϸƒAg‰qÄÿ&Âa)qØAØÝPSv¨¿”ã`øßÄ3AÇÎavêIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_horizontal.png000066400000000000000000000002321463772530400316370ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+LIDATX…í×Á ÁS,ÌÂKÒˆ–O|î>óDf+b®ˆy»g5[°Õ­=©¾ý ìϨHÃÙ)ëÄr»½,«ŒIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_horizontal@2x.png000066400000000000000000000004631463772530400322170ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+åIDATxœíб Â@Ñý.‚ É5ÑÑ5Y&¡ L`‘Atgó"_°7‰¤V[ÿÁ4ÝOK=¯IRËpÇã­ç}«aËO’õ1uHêð~XÏûV›Xóé»×}›ü6Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh{x|ùîußdóµÔ9•9•¹–:÷¾—¤/ó½(8¶I:ÖIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_horizontal_disabled.png000066400000000000000000000002331463772530400334670ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+MIDATX…í×± Q4fîÀ˜&¬æ"Äò®ü Ék¡dºÌu™¿îQ£`˜ÉýZ¯ý ÒŸQÙ™¢Ø !{ˆÑIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_horizontal_disabled@2x.png000066400000000000000000000004651463772530400340500ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+çIDATxœí›±Â0Åž"1ÇÐ0 #pLÀ4©²…)]:Ûˆ;¤êÿ}õNDäŸ)£°?ž¥æš$µäò¼ß=÷[Ùüx’¬ÇLI¦Ïa=÷[ ïc¶æ^ûM|#ÀOcZ€Æ´hÐ4 h @ Ѐ 1-@cZ€Æ´hÐ4 h @ Ѐ 1-@cZ€Æ´hÐ4 h @ Ѐ 1-@cZ€fü£©dÙš{í·2<@MNIæ$ó:wÝiá,'"0žBóIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_horizontal_focus.png000066400000000000000000000002321463772530400330360ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+LIDATX…í×Á Fa‹vòÚÄM¸™´A¦t|ïøƒð]¡dºÜt¹½îQ£`˜ÉýZ¯ý òŸQ“Ú)è× ½÷y9IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_horizontal_focus@2x.png000066400000000000000000000004611463772530400334140ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ãIDATxœíб‚@á÷[µX-Y‘]P‡uY ™Fw°Î¸_tÁ ¼ÛDÒ?«½pžÖqÍzÛ~V×ûXSÏû­N{~IDATX…íÓ¡ ÁƒB€R0tMB)$ß(,òßì¨s«NKol³¥£î­–!IÙ#üðÂ]k  Ÿ£IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_vertical@2x.png000066400000000000000000000003241463772530400316330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+†IDATxœí×± Â@ P;C ¤ÌÄ T™(›0O$šˆ!r´èBʽW~¹øvçú‘u°,¯{ÉmŽÈK‹BZ³äcoÏïp¨§Nº|Dĵ e®ÃÝz³;@–aŠ(ïe¶æ–SëÀÿð ÔS']>Â/ð›_€N|áû(âª×IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_vertical_disabled.png000066400000000000000000000002141463772530400331060ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+>IDATX…íÓ±Á£2‰ ´ ,-hÀ˜ÑšH*$¹>»èA’ôY8#—º€ô(:Go ¾J7¾@’¤ï6ñ) {¾iÌIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_vertical_disabled@2x.png000066400000000000000000000003261463772530400334640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ˆIDATxœí×± Â@À}Š@Dˆ qENh”Ä Y4ñ¤È/Bë‘=®.Ø»ìö£,ƒóõ~)5c’c‡>«)É\“Ûô|¼¾óC3¸Á哤&§$ã2o°7ÍjÉäݡ˪J2'z÷þ‡_ Üàò‰_à'¿;ñ×Sü¯IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_vertical_focus.png000066400000000000000000000002131463772530400324550ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+=IDATX…íÓ!ÑåRªâ.êfd—2’*Rö¥ß6}$}ÎHm ?ªöYcˆO‚Ò…/$é» »X ƒ2eIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_vertical_focus@2x.png000066400000000000000000000003231463772530400330310ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+…IDATxœí×± Â@À}èQ u : rEî‚èÄ¢xRô&µÙ3áꂽË.`;Jœnõ\SÇ$‡}–4å]®K¹‡»vj¥Ë'ɱìëØ†³lÍì%eHòìÐeiS}•¡w àøÚ©•.Ÿø~ó °]¼$lŸƒAIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_vertical_pressed.png000066400000000000000000000002171463772530400330070ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+AIDATX…íÓ¡À Ñ…š(“ZpƒJ1™¡…Â"ùfŸ:·ê@’,íQÚ˜@½Týþ·?ùJP:ð’$…[ Ô é IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_move_vertical_pressed@2x.png000066400000000000000000000003211463772530400333550ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ƒIDATxœí×± Â@À}Š@4B#´@€Ñ ‰E#TáB,šxRd}jŒü3áꂽË. eœoK’±&Ç ú¬iNêuzÞ_ßá¡1¸Çå“ä””q¶ЕÖ†’¼Þd}sR‡­KÿÃ/ÐÜãò‰_ Í/@'>ìý:W˜ÉIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_horizontal.png000066400000000000000000000002271463772530400326750ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…í×± AƒŒÁ‘%’!LÇëÚHTö.{'#Íè^RO -úŒš´^AþíT(ûö£‰|IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_horizontal@2x.png000066400000000000000000000004441463772530400332500ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÖIDATxœíб ÂPDÁ;Šp†äšhÁÑ5Y&¡ L`‘AêAòNô³¿÷ª"âÈZ}<ÏËÚ¯[UU¯§ë8žïbÇI|ZUµßCUŸ °ÿí½/à?$€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ ÉÏï]±½öT]Ku-½ö¤vDı½mTº– IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled.png000066400000000000000000000002271463772530400345240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…í×± AƒŒ&d…Œ‰”ÕÂtü÷±®DF‘Õ‘ÕÎÆ2 Û¼×tÀÍúŒ†t^AþíÝ뮢IvßIEND®B`‚toolbar_separator_horizontal_disabled@2x.png000066400000000000000000000004431463772530400350170ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÕIDATxœíÛ1Â@Ñ "¢  A  &.BAèRg™a_uÝýÛþ É?¬‹÷Çóa˜¹Ì—çýö0vìŒK–ÇÀø aÐðyüÚySf€ŸP{€­ö[ì¶Øl°Ø `°À`+€=ÀV{€­ö[ì¶Øl°Ø `°À`+€=ÀV{€­ö[ì¶Øl°Ø `°À`+€=ÀV{€Íû4¯µóÖ´3œ€ ˜–s’lî »“Pçç·yIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus.png000066400000000000000000000002251463772530400340720ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+GIDATX…í×± AƒØ)-g¤l1„éøïc]‰Œ"»"»œe¶y¯é€›÷ GŽ»²Ó|c…~IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus@2x.png000066400000000000000000000004401463772530400344430ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÒIDATxœíб‚PDÑ]‹ ë "+² ê°"«4Ó”ë9Ì~ög_UDœY«¯ó6nµÝ÷}{Œ=‹ñiUÕûø¡ª†O¨ýøoïCÉ!ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ôMxþxÊX{ꮥ»–Z{b;"âÔ^hN;FäÒIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_horizontal_pressed.png000066400000000000000000000002271463772530400344220ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…í×A Áƒ ©pS?ÕCRkˆ8~ìþ{™o%2Ьެv6–iØæ½¦;nÞg4t9>îŽÂa¾‘IEND®B`‚toolbar_separator_horizontal_pressed@2x.png000066400000000000000000000004461463772530400347200ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ØIDATxœíÒ±MÃPFцð&,’R †¡‰²Da‹Tla ,¥ˆh}"åÉÒsõ>_y&É3{Q¿½fæ´½~|Ÿ?/bÇ«¸tsZg–uf™[ˆÝ±Û‡ß÷&ÿ€‡P=@+€ @Ð  hдèZô­z€V=@+€ @Ð  hдèZô­z€V=@+€ @Ð  hдèZô­z€V=@“~þ9ï X3sý{Ö£Û‘ä™ýÉnJ" IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_vertical.png000066400000000000000000000002111463772530400323060ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+;IDATX…íÍ¡ À уA€Q0lMÒQšüE@Õ"1½§ÎH’ôwé‹7âaÑ/Mg«eäCI’¤“ ½×%!U"IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_vertical@2x.png000066400000000000000000000003051463772530400326640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+wIDATxœíб ÂP P;C ¤ÌÄ T™(›0O$šˆ!bZôS‡/‘÷Ê“‹óEgm°,¯{å6Gä¥G¡­YùÇÛó;Ú«?}>"âZCÍm¸àlvd SD½{”9Øš[N½K¿÷%~SÇ IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled.png000066400000000000000000000002101463772530400341340ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+:IDATX…íͱÀÀ0™ÆV0–,àÜYM¥Ujä«tI’~NäRMçè-ÄCI’¤› ¬~ˆcIEND®B`‚toolbar_separator_vertical_disabled@2x.png000066400000000000000000000003101463772530400344300ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+zIDATxœíбmÂ`…Ñïgˆˆ2bƒÐx"š¬6 Y,á´‘]ƒ%8§¼zÅ}·€w0ÖÁçùrK×êc‡>3j^êëöóýû??l_ðùª¥ŽÕuox7›–ÑTÝwèòP£æjÚ»ð| Ñ Ÿ[ÇIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_vertical_focus.png000066400000000000000000000002071463772530400335120ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÍ¡Ñc)U1€EMà=ÙRž¤ŠŠûéÚ$I¿ 'R[È®}ÖXâ“¡$IÒÅe¼É9ŽøIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_vertical_focus@2x.png000066400000000000000000000003051463772530400340630ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+wIDATxœíб Â@À=èQ u : rEî‚èÄ¢xRôŽ%<®.ØÛØ‚êƒÓ­[Ú˜ä°BŸ%My×õq©ûw¸ë¯þôù$9Ö¾}8`kfTjHò\¡ËÒ¦öªaíÀï}Nþ*?çIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/toolbar_separator_vertical_pressed.png000066400000000000000000000002121463772530400340340ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+Ÿ$·¤ ë°5À©´èKòÙ½Éö–¤öG—ö÷¦p„™IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/transparent.png000066400000000000000000000001501463772530400272360ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/transparent@2x.png000066400000000000000000000001651463772530400276160ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@òÉQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/transparent_disabled.png000066400000000000000000000001501463772530400310650ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/transparent_disabled@2x.png000066400000000000000000000001651463772530400314450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@òÉQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/transparent_focus.png000066400000000000000000000001501463772530400304350ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/transparent_focus@2x.png000066400000000000000000000001651463772530400310150ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@òÉQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/transparent_pressed.png000066400000000000000000000001501463772530400307630ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/transparent_pressed@2x.png000066400000000000000000000001651463772530400313430ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@òÉQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_close.png000066400000000000000000000013351463772530400273770ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…å—InA@ßïdÜÁ]m¯à \à@Bˆ3Iá‘8ËìX@æy@Hœ3ÀÊ=Ip`Aú³ðÔi÷hõñVõWÕÏ¿ª»møßC†ÏóªXïî¢òÆqëy^ØFô-ð[Ðׯ˜/·\?ü zp!,6mû¼¸ (Ç€ÕÏÈ·¦i<`œÐ;±5ʉúá€è½1h”“- ªS ‚Î"UÝšpœÆ5ÂRŠÄñ4øÉé¶Œ¹œhÚöiŠÄLU‰ÌoŽt[¦qŸk‘ˆ¦mŸŠÊ«4‰žïÏÁ{¾??€ÏÁ!v$ÃóÂE=LHÞ(ºØ2æ" .ÈI®Š,§Ás/Uô ŒDÏ÷Ÿ rZ^(P ñbx˜¦…—èÂ%A÷Ó$úEÒàÚmsXT»”@ŽÄð Æs¥á•b9ë*Á!å6Ì‹–i)²,ˆfÀWªÀ+ XÊ/ES€Ÿ•ëU™ìyá\$z–±Îä¬çûϪÔ,}Cl T¬í$\”iáŽcAb;Ù^§½ZGpDZw¦…HÜLˆZ›@ø¡h·x\B‘eà;à¢Ñf]µÿýø –ï€QvéŸIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_close@2x.png000066400000000000000000000031241463772530400277470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíšÉsE‡¿×YXœ @E£Iä!„Ä ±C6þNp€•ŽðwP@¨Ä+{ XеŠ*bkFãC ˆCˆ²úqˆ”2’lõX3¶(ü{^÷¼ßçni$ ÖXcÿ3Ònðܹs7ý={õŽ@ΈÖ^ ‚ ²Âý-‹0 ‹*}/‚îfAN^Þ¸þõ[·þÕ\Û"à§ŸÎß²~ãì »š.]ÄÈ`Ñó>Ϫñ4˜¬V1ʰé_„oççæžÚ¾}ûÌÂaÓ¼Àº W^l`V‡+q¼'ÕŽSdÑðʹu^jn`„cKÜ£¿W%,þ:z¼y¤E€ÂÆ÷êÇêðT?š´É¬˜¬VwwÀ†æÀ'÷ì«#½ ¡~”Îá´%[‹käpÑáÞ«.!Ix`¦f̫̓-Êž÷³9ˆ»„U9 ¶=À Ö –=ïçæ mŸ¦âøQ±:ô;Ü࢞- _8ÔvME[dØÜ¹Z/aû‹ùÏÚ]]Tô¦„4ÃCÐ[Ò*q¼«Ã¸K8P.¾tYÛ•0 R1£À­«õ’hß`äÏtªt«+!«ðÐþ9 -EÏûk™ŽÅ°É(£“Õên×õ#yxr  v@ƒJeú1Lmä‡ò?ë¯ ËÚ I ü…ÚÁ >MrÄ ¹ƒð}ÿ«$÷X‰ðõ¹Ë#K aîR1cd¾>ù„áô^•Úé4%$ /èïû.Ÿ_[£;Ò”°Òá!Á»ÀbAþŒ¨^r(ßl‘‘0 j¾Pï|ækè¡nÃ××J‡0 GÌi…›Êÿµ‚ ø R™~cÇ€-s/[t¨ìûwÕpÔÀò$¨æìj…‡”@B ÊŒ¢ˆˆËÓeêá!Q=¡È)ÇàÂe• …RZï:™€T%dRxX ß÷?©¡‡Zþ‘€Ë*<—UxÈp4˜Œ¢' r ¸)áÔFø³è«Aæ .Aeéø•{ƒY³…ˆ13WL¹*5ãò±»k20Ç;Åê8nßÞ6èÇØ±JeúÁ¬újéXþ¶e.qkö‹ùoÒìk!™í€©8Þi¬Ž±üð[0vljjú´új&“0Ç÷÷YW¸=¥%/hÍ ”JùoSZï:©ï€„áçT™s¨Û"}Ùì„T$ +C;Ôß–…„ÔŽÀÙjuGN™p /jA~ ÇOcõ=àF‡¹¿«‘’ç}×UÃuRÐMø«%¡ë#<¼=Ò èy`å0®ÇÁêøTïLÜp] 8[­îè³8ŸùkáƒñÅ ŠEïý$ŒÕ±n%,û4Â#ÜáP~Å G}ßsY»R‰ŸÁè{tþ¹¿ÕŒ ”=ï{—µÛÌONE÷Y• Çð³=â¾ÁJIH,`%Â7Ãé}*ö$JH$ Š¢û,Œƒlu(ï*|ƒ¤æ…}÷ ?¸®ïü"˜4¼Mpæ—"ò¢öp¥S­Âí9eâlµºÃu}§Eѽ&’„/ûþ¨k.„a8 bÞ%åÐQ@ÒðŠ+ùþˆCmb¢(Úo‘wp€r¾fè$aI½~AOû-ò.m~õÙ‚ƒ„E\ /ãÀ}ͪp¼T( ;ÔvMR FtŸïû?¶»ÜV@Âðs*[©ð Ò’Ð" ŽãmóV¿îrècUÂ7˜Œ¢æÚkBg 诵\n÷=Û¶Å G[Þç­¾Ì <@Ù÷G-z˜í\-[sóó¯4¶yÐgî=Ç žù¥(ûþ¨¢Çp È¾æ±6¤Öa9„ãÅBá´k“YSòý' JK¶vO‚KýUç0ò|/…oPòý޳”‘SÍC-nè3'€É6Ó¯…÷¼–Ez…R¡0¼„„ÊüºÜ‰æÁù|þ÷«¹¾ÇTx$ýx[Ô>ÞËá” …a¬Ù‹òð H¤Ê›óënسýî»Ï¯vk¬±FoñeCªìù'fIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_close_disabled.png000066400000000000000000000014641463772530400312310ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+æIDATX…å–ËnÓ@@Ï ,€ÏH³i ‹$;Öi6H´µÃKB-[ðH|KvH$@åÕ&ÐvË6)Ú¼b^ü°i.‹ÔÁŽíÄ)Ù îjlÏÜsæÎèÊð¿‡øƒJÕ>©ª·£*ÜØÞ¨·¦ *W-C”›À/T¯mµÏ2þUm'€œ(ëÃ:7-x¥jŸeÈÇ©ûß2¦é‘ÀšŒ ¦!Q©ÚçUu-ÌâXD@É\zÓ”¨Ö¹xÑëþÃ!à¹mw&_|,ñçnÂRn¶ø¶ë¶w'† "pXÙj6žDö%^ÇHd&•؇¯ å߇×ç†|‰ìl჈D$²ùÒoŒDÙ´ÏÒßùXx¬@_¢ó*NBÀ%Q6í³‚Ã5 ž(àKäæJ]`1Ä|µvFàq |9 >R ë´%fæ ®çtŽÊÄpIGƼi]V ßè=D/ôQ1pÕ•­VãÁ¸Ü©’$zÚÅRÃaÌÃsÛ/gòEá>ÞÄDð‰Ý!‰\…KÛÍôp—.U(ò“þ ‡ˆfzü˜4ßD(›¶)è“„u‚`æf‹N×m;S(W-Cà)p8ðÚ¯D°cšÙ|i×sÛnš¼©Ž`ÿg"ô² —É!AŸ–MÛL“{læ {IàY|³ÙXõœö‹\¾ð dp³JU‰‘󆽄hŽÊ•­V}ÕÑu;IF6_rFI$ Œ†ß¹?<¿ëv^ÌÌ–>#L$+P1k‹ëiá~xn{'Qb®¸ë9Q‰ˆ@Ŭ-*«PÛnÖáA‰ì\ñ‹Ài†ïDŒDH \µ@6báõ{ãà '½Ä@ lÔN Òú[xP"—/|‰Häò…®Ûy>¹5 Ô:ÜÍfã® á>qX‘[ÉUPk³Ù¸{Pø‰½ˆ@Fõ*àßQ]™<(,#|>J«ÓÊýïÇoÏ †Áýß¹IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_close_disabled@2x.png000066400000000000000000000032651463772530400316040ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+gIDATxœí›Mp[WÇç*…”ФM?g »4I“6´h¬/§íÚŠvmgbÙÖ¬ÊLlØ2S[vWíF¶4 M?éÉ壄å£-0ÌtJÝQ Äij;ÝÃÂ’1ú¼OzÏ6ƒÿË{Ï;çü¾÷>=éöµ¯}ý?KÚ ¦ž}ö®}ö;(#ÀA…«ÆðC¯ÿ`‡ûëK©ìÔ—¬åyÇuU.ߊ}æG¯~üIsl €ÑÑÉ;Ön3?N7M]LÚ[š}3¢¾CQ|bú+F´ ùïyûÀÁO¿ùÚK/­n5Í Ö˜çi5pDQ/•™y,Ä~CUgóúPmýöï6¶@í\BïUÝÍoJa¬y¬€ÀíÝKmBHgsöÑg$Jf&Ïô2_×ÁæÖ ¼Ñ»¤¶Ö”÷„dfò ˜ ½Í­ÞZ¨Ä.×zçÚ}ÁÌË*Ä~Ð<Ú ¼ôÂ{Æh g²+Û¡nÞeÙ²ªªéòÒ ïµÌtº$Í=j­)ƒvèçšUIúŹß8ĬTvêµT€;{Å*\GIUŠù_·›ïö&„0ÍC°· „m¤23)ê¹B›(/-¼å’ÛU鉙‡-¶‚pW¯X…ëjlÚ/,\íëvBTæ¡Ýç€ò–fßTÕôæí¤§Ž€©lžÔƒ)¨y#2ìj¬€†S_EðîpÿØd¿+!ˆyàI{‹s¿ R#0A ¯ÿm;aúÑBHdr§EÅÚ< ž|\¬YBPó¨—‹óÏ/í5ÂN›‡wNò WȰÂu‡ð;µF9=1ópóD"“;-ˆóžWcÎ jBX ¥.LMU—Ï÷ Vþi0‰åâìï’ÙéSXõ£¥n¨1ÕÂì/ëxS¡€þ ؘÚÝ2!€€DWQqùtºyˆ@r"÷uD®àÁM7Œpny1ÿ‹òm)*„ÈÌCwN*çßPcÎ-?FÐ Q}2*óá h(‘ù†X{8ðÒ¢ú¤Wœÿy}59¨C¨Yéõ•{]ºXMGm"ÜÛ¥Ö®"rÓý½©1ãòØ=°"ÏL4PuùÞ¾.9ŒU?™>]gõJQ&ÿyîî3Å?0/æþf_ÛÙ ˆg¦NŧóG±ê§Ç' «¯fE ‘9aážÒµÆT£‚:€Dvæ„ÔlÕżÀ†Â†CÚ£Ö˜HVB¨‚˜Ö¬0lTSÀ§ñwG!¼ÇáñÜqYq5oÔ>µ\\XHf§¿…ÕWÏ9\û±…!)ÿÎ@ × €AÌ7´[Ô¼XÎ{¥|µÝdâÂÔ¢\f! t¤ÆsÇÕˆóžïf ²˜]…§p<ŒâÇ3S'n£¾l™‡{Â×éf¾¡mÖzfî1ŠŸÈΜpè¡CŠ>”ÎL?hÑÜ̯#z¾¼8ï©Q߯Òó%@ù»ÆÌP¥0ûnЀ0¿Ukbò¬s™!P7_îsÈüVÍ€Dõ¬Wšÿ£k~gAÍ[•¿8WqÍßM©ñ©!5¼BœÁxöâ±Ý2à•òU±œÇñ`T‘•Ôxî¸KîžâÙ‹ÇŒ­àh^,£ašoÈ+嫈Žà ÁHÕB×-Ðy¯”/;Äö­ä…\•WhóÖg}$V‡ºm‡Ž+ ž½xÌh,ÀgÇ¢6P^œ÷=¬;„ß«FªéÌôƒÚ®€-óÊýE6;Z^\ðbCSЕ`³ËKsjžh0”ýöØ[o)<àxWÌ7Ÿ˜NÑŸâáor«vÆûÉ‹nlÙ±Zí{ÿ æüâ\ŪŒà¶îÓXìû̓m^–Ö'’m(2¶›æò‹s±ŒâA„³Ícmþ_@j=òl(2VYš[vo3Zy¥|Ù‚B‹·V¢ÝþªÖêÓ{É|C^)_FìÝ!\ihP«Ý¼$ð~›‹7¬Õ§ýÒ|K’½¢òâ‚×ÂLíRó`¬%ê/o¯}ñÔ™—c5=ÜÜDÔ7{®\ŠîWÚ°ô×?ÿþý/䲪< ›ï}¬ª/߳ϼVxñ£Ýîo_ûÚ×ÞÒ¿îƒDRôœš;IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_close_focus.png000066400000000000000000000013301463772530400305710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ŠIDATX…å–=rÓ@†ß×IœƒZKp ¢5Ä!$qþfÂ2Ã(ÓQ$;ä×HÎ g`ÆÖ! ƒÖKá(È+É’w%Ïÿ{1¾xt­ÇQ¤·î’|=4 까¤7$~A|5lñ34â†(Ò€‡ î 껾ÚuÁ@+‚ú“l<u?k$úî$®¢Îêp­:M²HÜK û¢:%&s§á¢HÜO Œ<ú"×2$Nç‘p}µEÙpаŸ€Ðãy†ÄBU‰xê—ƒìŒ<~Hö6`Uèñ\âz¦Ä@Ë…ð–oà Ep ñÚÕôµJêÄ’“\z¼Ê…Kg\ 7²à3À ôRP¯ŒD3ÐsBçUà…³$¾ˆ_¦yá¥Àh R7Kb’;£OвK äIHˆ@€Ób¥á•½ó*Á+ ÜJ=Hö\ Ü {UòRÿ%ê§$ÙƒDáGÕ°JÎ@-H̘G êÂñõ¬Jfé-pA—à k;Æ Û#~™ÜR+¸%a@rK ]:µjhúòòà¡a74ì ÜšWb¦@Ó—Gêʆ“Ü »ñ@hØÍ‘¸(’Șz|o÷‡†]’Û–Äb‘DæKØh‰R¿,2|W·²¶¡`%n6}=!u]÷|¿:çõë§'8Ðôÿ,õZèÜèyŸ·Œ7[F¸íM¯Ô‹ªÄ¬ì¼=Ù2ðx@øLçªEUzmî†B’æ! „¤ÍC€Ü‚eÍÛ"ÌëlmV·Br‡*7gÏ™løF@øCµ‚Ö£ƒÀþBHË<ô¼ì­Ê´ª˜&€È`8*gË™’†æßIqÍ;§ÉPó£ZÊÎYÙ"ðX@ø?Íë•~;!¦ù»Îib}Z¿sFlÒÙêŒ~猽01F ]Õ¢*˜ÎwÂÇl9;oχæÏ—ìô^˜‡>@‚¡ †/Ùiïl…@ó2MökúveÊ–vƒÆ¡ó•¢B~¼í¨¾; ¥ZAëÎi’ðNXÊÍÙsMóÁm:?¨yH ZÊ/Ø ÞÛ àëáÿél¥¨ßŒÍÛ³Îl8ùIãÒdµ _VqC‰€þ l;ü~™‡„@<&6d@ÈÝe æ!¹9{Ñd× ë„h÷ìÎצõ^"ùÚ” HBŠæ!oÔ¸Bë<ÐõLj`÷<º–yH±ZÊ–í{˜]G<ëƒMóõ¢ÞM©4`À!,¢ÈGî ›M¤mR/ɳø"8Þé \ÐÏî•:€lÉNál•°§· ™8³•±y{6½ÊJuÚÌ?ÑgŠÏ½ôr}FH²®v¥ i~xrÀTŸ¯ô~uu*•È/ØÉ„̶š)Û3 äêRâò vÒ{[%À¼Á–`+ í1a+i@H@óÀ}'Mn7ž,ý+ þ‰4 $`´l'â˜Çt±2£›õ¢Þuè1 dKvj°jÿ§D.‚£e;q[#†ùjQkí‹ù²ýÀcïäø ¯ñê¬þØO½í@\ó†.Õ Zíµ™›·—Ìì{a -Û GxÛïf 2£›’.8¸ÁÇ¡ïh™<~ßK—ë3Z ÉÝì„wˆ~]àSç4¾>­?…äîT_ÆJv\ÎÖÍozéR¨ù–ö BìØ óÐLûáOzo«ù;÷œX0V²ã®qoÿt@xßæÛ•³3騯 ÛèÌ­‚þš?¸âš—ŸùÝT-jÍÐ%;á¶6Z¶¡ùƒ: »`ßÅÛ1ÌWfµZDˆ2eö6 wB$€¸æASÕ‚–bcklÞ^vfoÁàÆ£ ì `˜Ì·Ô„ð6t¿õÙ©;^šæƒgéJÚæê3ZñÒ%`3*Vð”ÃVÇJv|—˜nµ™ÿfÔ![’¦ª3ZŒŠMRq;Á¼ÎÔgõ—ν.ù7ìÛþ°Ý¾x_Ì·”+ÙYsö€½Óh}Zk_ì~[ü°ÿ1_ó•Y-Ëë2ã<-ïÒ¹Øëÿ^ŠÊd°…וý4ßRãëVSAЙΕ^ÁíÝR´Ì×fu#´È´Õ¸øFCPoÝoõ”ÁÖ!4=Læ[ª´„t…]!ØõΕ.fîªÁ_»Ö›æ× êJ2,ªÎhqGƇýÛ]í\îP+è³íÃÊýøøxÓ™^fó-Ug´è¥<Æðwà#d¿xh[Ù÷^Õ'û]ßt áÒrÒI0.é­:IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_close_pressed.png000066400000000000000000000013501463772530400311210ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…å–»rÓ@†¿ã¤ž#%T±Rð „Ä!dr#Dj,7™á(e5’' Ø!ÎÅÀ0Ã3PY~èà €ûPÄJd]lËqÃp*iµûŸV«Ù…ÿ½$¼0^:µ Ê]^µ}ûã4A†Y]Rå5ÂoD¬À+(„´ GÀ„9…–aº¥iÁ‹–³¦ÐB˜î£z>»€;‘1E›Ó(ZÎ*§Qp/! "@oš†é–Rà=U9H^ù°‘"q:‰„aº%E›q¸ [Z¹•|û,Eb&¯DžxsA¶Ú~ù]´¯RóûžÄº"ºÞö*—Cá–³ª*M`fPZ¹)Â&ñÏ¡Ò4,g5Ex%/†Ì@X†U}®J#&ÛU•gábšßwWDô,/|,Ãt7­§I¤ÁÝ ¼Êɨì±²$´ÿydPllx.ˆDcȸ\ðÜ74@ãcØ|»‘'/ó/È*~)ª‰ö+Ÿyór -wÕsI×o;/šÕ§y2s,Âê’Â0ig"šÓE¤Ôß[FÖX3WÕ`;"0ƒêEÑr—§"°`9‹YðN­R|»Ñ™Hb¨À‚å,öT.ãpv;µJ=lèÔ*õ ‰óQ™ÃàmÏ~ïß©Uê"ìÆ$fGIdmÇOD´5.ÿZ­°·Á^í"f.98ѰÆÈèÈ%‰@t©žo8ìÙŽ2¿LèÈ%-º@#ñh¶bèàŠÃÞÛnB0ñ¬ÅàÇþÅ–óÙ÷ºp7a[ÆaC|㶯°f ÝËùìûþ õF€âtfeĵz×}ìG™K¥ÇR±¡Olˆ¿Û!üª5t—¦2—ë]¬ûAÈ#98Ñ2´;ltE¬}¦0;ZpˆmšøÐxÂXYÀ]|×fâ¡°³L[<8è;,bæp4Á ÇWò#E—Ü®$ú'ã"v8à~Õ`ºWò×:P)`ûLˆJ4v(h½~Z2 98þ(ˆóÌ[‘S¥é‘¥ÍŠÓ#¿ hÂb«&4=·Å+÷;„_´·Ï.ºåÎ=ê9ÿ]àïªÒ¹:3òG—Ü~šê€Tzò`ñ7‚ˆ‡Ûp¸î~Ÿˆ.%ús¹æ¯&p¤Ò“5f/*ˆøjýãGEä,vB RéɃ»¤ð€CxKâ=‚š€èÑâtöO®ù *Koq6³àš+⃹N£ú˜àdÀá‰G,\ÜñQ™Ðð ,s:lñ¥é‘%A{q<A–*ïT[³e4%>?<ïÛ4©ñcмÔüë³ácÐέ:aÓ8<0ñÈ:8ϼ*}Q‹(䳋‚žn4 VîYª¼m×§nxâj*«rzu&3çA;AÖÍÑÂìðŸk/ù82ø‹‡oi[xÈ¡Žmï‘LOÇðkLø±X²ðÊ‹U¯×ŒÀ-ÛöCþÄg3 Xzq…°ë?ò¯×žÂÓ{—­HßvŠ÷¨¼ã˜Ó¸˜ õ¯Õ °Þ OÙŠô•¦G.¸—-•Ã×É„m5lõª–}n'‰÷(æ‡çUéc D8ï_«1À´™3Àuî/ ú\!Ÿ­I²SXÉÌma‡ÿ*sÆ¿ó/ü¥pîúWÇ^‰íCyP„›(‹ŠùNq&º_iÃ⯫¿ùàáx×YÄ<@ùDE_µ7åù·~•ùx»ëÛe—]vÿ^ì ö^&­IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_grip.png000066400000000000000000000006341463772530400272340ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+NIDATX…åÖ½N„@†áï ÈÞ&»YB£VVÖ‹`¢WjlLL–‹XBg¡•5ÇÂ-ÍÌ™ÁBJ8äyäà¿4%VUÕ ©ø ïËùüÔ¤x \¡Ç©>?IÀμqßÞèkÁ_Á/¼kWiš~L`ƒØàÁlñ Ü{€÷à‚{ °Å˲<ŽŽf@ÿµ\,rÀÃ"’áÉàK%úüAr<÷M}«¯9¿W¼mêë,Ë> ð…;ñÀ9€—®©ó!.ð‹BàÖ¶øvnm‹[„ÄŽøk×Ô«1\´ Ãà–›0^Àf q=·7}42,ƹksדþqãRÀÌŠ¢øÉ„33Q?˜ðáÜ>|ðsf6†?!ÙÎâcs6û̬˜Ù¸˜˜™|Îýùñ VdÖ}ˤ„TIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_grip@2x.png000066400000000000000000000013101463772530400275760ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+zIDATxœíš¿nÓP‡¿¨ÊKT6;6</ÁBÕР++o+J ˆ÷ðÆ©®Ó!UbAHä0 !רicß{}¯“ßhÿt¿OŠ6Ùd“uŽô}ÛÉçó»(ÏAÎ#ߎ¢¯åûWû:˜‹äóùÊ!0e´WÀǫ̀Ÿ£ÙÏyø¿ôFunêàß*<«ÎN@#<:MãøKu~P/Áeð·&“OuÏ F@xˆ€¶ð0]à!p]á!`&à!P¦à!@&á!0¦á! 6à!¶à!6áÁs¶áÁc.àÁS®àÁC¦á‹âž¨¼äQ’DŸË÷½`þ¿>å[šÄ7Ë3Þl„¬Ã7Ä Žà*ú¤:ÛûZܼ¨Áƒc¾ÁƒC>ƒ#á$Iô~•.ë|†Ë|‡‹B€KB B‚ÃBƒƒB„CB…ûWðÉ$:Zµï¸(vEåXØ º„Oã¸üé ¯ÿõ™Ü ßV|‡?99ݯ7³ ^EßTûŒìC†ï¼ þ¾Š¾­ö]ôÕy)C…‡Kp¿ŸÆñ‡UûºÀÆKøŸÏçS”w5}+}Œj¬ <Ô8.Š]AŽ0ßÐ×~I_«è9Y–mwv¾ƒ\/]n ßÐ×ÞtT~ Çã+ Û¥Kþ–RÓ×é°¦û " MÓŸ O_ ?ÝëòŸœš¾i—ÚîkÌl6ÛβlË×¾<ϯ™ìÛd“5Î[štaŸ›½IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_grip_disabled.png000066400000000000000000000006621463772530400310640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+dIDATX…åÖ1NÃ0Æñÿs“r:p‚–‰‰¹ÄX\¡·ð5è*,ˆB{ œ€&öÒ˜†¢¦!vâ„ö“Ÿlç)ð߇ԉEýAK…æäe<ž¨zq¦ û`v’ùZ¬pÚÀs<—Ãd­ò+Hãt﯆¯µÈÃ+ `ƒWÀ¯$€ î=€+î5@Ü[[üàètÛ¨ƒ¼ßÎ{à¡9â`O0Íd¾T€ø.ð(qpœ¬¾‚xt{qöV*€/¼P7|1Óž$zë¸s߸S€*p°ü lñ¨?h¹à`q.¸ eâ‚ç(†ËLâFwîÔ +ÂS0¨_Lk°Qg¹i6õ- Ìχ™Ý àmY<7½¢S6oê _ÕeÐZ+2ÎÃQ!×yøz]þ`9¶€‡ßþd´ÖÒüªËÄSu6ý­µÂ®5‹çº¿Ÿù¾¦•…ÿ¼ŽIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_grip_disabled@2x.png000066400000000000000000000013741463772530400314370ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+®IDATxœíš?nA‡¿Ù…&H¹%)iˆ-¥CØ „$ɱ¡€ÐrÇ‚±h³>D$.À"! ŠühpÆÞïÎÌÎlüÊõÛŸæû´ž=-ÌjV³:Ï¥ò^€í*Wj·„èÈw‰¢Gýƒ×_‡¿×Â\T¹Z_‘=@ /ëÃ=Q.+sPÿàO1^Òû ) þ·(žê½…û $Á£d½ßi}Ñû µ žwZãî)Œ€4ðPiᡲÀCà²ÂCÀLÀC LÁC€LÂC`LÃC@lÀC lÁClƒçlÃÇ\Àƒ§\Áƒ‡Lתµ;ˆz€¨‡q¯ùyøw¯&B¦áËÕú¢ö%` %¯ôoØ€“7R^p?Ôc½7w®à•R÷ûÝæ'½?×MÐ%üa§¹7îžÜø9 ðrà<8à<8à#<8àì=/²Õïµ>L“e]€Ïð`Y€ïð`Q@ð`I@(ð`A@Hð`X@hð`P@ˆð`H@¨ð`à!WðÀf¿×jO›·R©ßUÈsÀüLÐ%|ÜݾTÙÙTH3Áà7L`L%Àwørµ¾Á(¼™™`ð"òVÏ32 >óLÐwø•Ûµ{J©wzÞ¤Wç (*<À\ÊÅÚ˜älÄÝÝýió²ÀÄ'À%üa§éÎ8 ú_ªì¬#ðLybûÿ^Ï#Å2"àïÙ¹!ø„¼ô}B)7ÐS–ùËǃc‹C—SÃ'䥆7ÚIpñädNÁÂÐ¥LŸ¥ŒÉË´XÓy ½¿ýºrõÚà¦ÀÏHØŠ»­NÚp=Ôƒ¸ÛüèK^b­®>YXn4æ}Í»±½}ÑdÞ¬fuŽë}ê¿ YIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_grip_focus.png000066400000000000000000000006301463772530400304270ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+JIDATX…åÖ?JÄ@ÇñïK½[x×Ê*`·ñ ñ@z"!ØÂn'¤^ÿœÀB+°áY„(ÄÄ™—‰…SÎ<øü˜y<þû’)±¬Ô9;-^«"¹H&ÅkÝ d(Çíþ$¾p8^˜Éª=‹þ?ðT–ÕJÞ& à£ðÁ£ðÅ£°àÁXñ ÆàÁøâç7z´½å£*’ " ^£kQ΀ƒv6%œ <&HÑž~‚=ð‹‡BÞ÷  Àˆo€ð”"y7›ÄÀÒxVê\Õ°àÔº¶àÎ#ñçYöá¦I÷ž„‘ð °pNB#ÞÖ â®Þžb3N*ùØÆ”NqhÜyCM^iB­÷.U‘Zo]x·nÿЬC`ûëOæѦƒ·ƒxOÏ „d6ë8Þ™Yû–³w?Í9Ú][WËZÖ²¹¬î ø®N¦-“žHüh·íÁç-û6y}¥®…¨îP}¤# e㱞×'{ZõlÍu‡êÃ_øk-ãZ¾¯‘Šà±°ÇùÞÆ½ÀïvìC¾¿QÁðïŠîiŒ€2ðÐeᡪÀCâªÂCÂ\ÀC¢\ÁC‚\ÂCb\ÃCB|ÀC"|ÁC|ÂCä|ÃCÄBÀC¤BÁC„\Ãw†ºz€ìþhײÉëQM„\Ãw‡ê:5Ø0ØÀ4È÷D#À|AÞ¹ŠB@ ø³–ÙÃ|oíBÁv÷˶½Í÷×ú ¿cGE÷Ô& x¨I@,ðPƒ€˜à!°€Øà! €á!€Pð’ÝíÚñÏÉL0iøª3ÁØá;ïuÛL¯ÏåÍøé¼”€¦ÂÃ%Î ‡‚;mÛé¼yUàaÆþëNxx¸@@ôð™öMz“Ï›÷5*°(ðíüB/ÓèGðSòJÃ÷2í¡óye? ÿ=›­®lè;°>±\~J^ix×yû'¸~…6°6±TéXJA^¥ÍºÎƒœ€O÷ì—a€ßÀOdý*gròyf¶_e³®ó¦ÖÍZÛh5Ö¼/tÕeÞ²–µÀõÖAL+lÞIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_grip_pressed.png000066400000000000000000000007071463772530400307620ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+yIDATX…åÖ1NÃ0Æñÿ³›r:p‚‚„ÄÔ¹åHp…°TÜ ¡T∠©™‘:Q('`€‰¹!5C¡¶ic§Nðh?ù÷ɶž ÿ}H•X«Ûo$Zßy zgªR\éL d/¯UŠ‹ibäMÏ’“t­ô+ÈÀÛO·—•ÈÃK `ƒ—À/%€ î=€+î5@Ü[[üðüz·nâàk4èuÀC'tćÀPOç· P?^¦œ¦k…¯` üøùæâs«¾ðB\ðÀÄ‘À>ð:• ³Œ;ð;(Ð>ñV·ß1Ö8Xœ€ þ­ÕÐÏ P70‰%hgáN°$|¥fþ ËÀG̯g¡®Cs_gðrÿ¯”ëf_!¤ÂÃÐ'foá^EðªÒ˜Œ;ÍþB-‚ç÷ߧ=SëÀCA¬ ""`"` "`"`"à"à "àààà `¾ÜÜ‘’>(¡­ÏÃî‡ÙûAíÙ†¯$½ºˆž ì¡ìM‘‘ÙŒð)ys„OðSA™½¹ ð/Üÿ2ì¾3ûs]ýÂwÓžÉM@ð“€Pà!!Áƒg¡ÁƒG!ƒ'¾àUåÞdÜ>Z%˹€áÁ±€ÐáÁ¡€àÁ‘€XàÁ€˜àÁ²€ØàÁ¢€áÁ’€XáÁÂ!_ðÀÁdÜ>^5¯šôjŠ<{‚>῎:«Ã·ªrìdO0 xôK×<|ÒßO·³'¼òÚ̳²'7|Æ=ÁÐáËÍÁ]}cæ-ût^H@Qáák€7xÑ}ßð°dx…vOVÍË çü †_iõ0ÏŠŒ©3 xÞÎå­±†l™ªI¯†Ê–àä­ _Mz5HÉ[sýo”›£m‘ßßÝ™Ë'¤æexçíæñØ=½ºìÌ\Êt,%%/Ó`mç!àÓˇ¿Ty œ?z–39fžˆ6² ÖvÞºÑîï”›£íPón=xqÍfÞ¦6u‰ë/W>ž4a¼´IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_minimize.png000066400000000000000000000003131463772530400301060ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+}IDATX…íÒ!ƒ@…á†;4©@ô&ÜQÑ*Ð=²7A H¸Cwª MHê&kÞçfÍÿÄ‚ˆˆHeö{D„½ É vð6³8 ˜ç¥Ãã \3@l¸÷·¶üx÷òÈØ…ã‘Íþ÷P|Öüdl÷ýªþ EDDªûW(õ1IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_minimize@2x.png000066400000000000000000000005151463772530400304640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÿIDATxœíÖ!NÄP…áóúJ'A À6¤I% ‚à`¬Ã ˜Mà‘$àØ’Ô`†„ŒC´½XòZp½$ôÿä¹§Ç´0 á·£™…):u™Ä±Ô‡úŸî£<­V»EÛ-%IÚž¨›—ÉnóÎ˲|Iƒš¦Ùɋţ¤}vnLkëÛƒªª^¿ÇYú\^,®ôß^^’‚öã2H:q¨ó'‚Âiš 0+cÜ»·pb²»4 Ð~~\Jzö(äÊ´V×]¤ñ`€º®ß¶bv$éZÒ»G·‰mLv3¦_‰!`.¾~³7oߊñIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_minimize_disabled.png000066400000000000000000000003171463772530400317410ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÒ1‚P„áŸw á6¯àöZp Â-(°µµµ1á6&Ü– ˆ˜Øñhæëv³ÉL± ""r0ÛÎ1V§=»®ÿ)PœoÑœïYèÇÑ/ïçý–µÓ$ÈB°v¿ËÖF |döŽ]רoÉŸPDDäpjYÎû>üIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_minimize_disabled@2x.png000066400000000000000000000005201463772530400323070ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÖ-NQÅñs)áK À³’ |Ç<†Ô#1, ™tMI%¦ †°v€"!u˜fÊ»Xò5„ùÿä¹#Î3#­`¿Ý‹bØÉÒ¤!½žBY–á§û·gç{Ë0rÓ©¤ÆÚåQ™üÆk¿¸ŸMžãc2ÀÉ`°»ª¶%;ÈP.§E¨uø0¿| ×â§>–Ûå?|yIÚ·uâ0À]ý<}ò3Óqœ%´M2€™æQ$wÝÅY2@gó}(ùS–Fy-|¥Ë8L¸N_C¨Ìu%é-KµfU&¿Vºñ@âGh‹OÆåB‰±í—†IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_minimize_focus.png000066400000000000000000000003161463772530400313100ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+€IDATX…íÒ!Â@„á–;päž 0 ÆÖ"ë8 Iï@Õ& ®[3Ÿ{o7™"""6¦Åd«öìÖ ì+$ÿ8v®¶ÀaÍÀPÐùuÒ L[Û·áûß§¡üûÙÂ\@Òx7È<ê2ç.ž68ˆˆˆÍ}^“ 7ä™ìIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_minimize_focus@2x.png000066400000000000000000000005151463772530400316630ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÿIDATxœíÖ¡JQÆñïÌŒÓÚ}AP°Ú\¶lñ9,>€ììKØ-ж)†¾iAlAï1Xä^µÍYpþ¿x΄ï~áΕ€A°?·îvܪÊÒ‹¶UÒÌÒoû 8¸öQóžæ’JÚê-]ŒN®EÓØÙýÔVù²(àèÆ·Õùƒ¤ÝˆtQ\z¶Úö–S{ú>¯Š/ßÒLÿìð’dÒŽ¤y>/ p; I´&ç³²€) 0¿[CŽ.¿Íge›Õ…¤Ç€<¡¾.Áê<Ÿ,'öâ²CÉ/%½†¤ëW'×ÕFmûù@â! Å'¶;Á |PŸIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_minimize_pressed.png000066400000000000000000000003221463772530400316330ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+„IDATX…íÒ± ‚PÄñÿ÷ÜÄ=€M,lèA˜kg°´wvгR!$všûu—÷%wÅ33³•Å4*ªc³ÉYxk›'„fʺ«.À6瀀´»ŸW€ô}‘úÜå‚âE:rúw¼„߀ˆxä. ìGylùOhff¶º7•y À²g/IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_minimize_pressed@2x.png000066400000000000000000000005211463772530400322060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÖ!NÄP…ásûš  < !‹ƒ°ÜLHXÀPÏ@¢ðHpØQ„ HÈ8™LÚ^,yp}“Ðÿ“çVœÓJÀ Øßg·ƒÉyÈS¥OR§ºî~»ÿ8ÀîÉņY5•t,i­§n¹,ä~ßVÅøùzô“öG—ëÍR/&me©—‹išn{vsúþ=.âçÚ¥ê÷ò’äÚlB1ãd¹f)´&ÅY:ÀÀ¤˜?® G.=ÄY2@¨4qé5K£œLó²íÎâ8`v5þe±'éVÒgŽn=[Èý®-m'þHüCñ­ñ<56PŽiIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_undock.png000066400000000000000000000010111463772530400275440ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+»IDATX…í–¿JÃPÅÏ—D ¾@ â^pA|ÑA\|]§¢Kñ œú.‚Žöú'·ˆ\t°ZkŽCMÛT“&¤µƒ=Ó½ÉwïùåËÉ%À—DÝt]7Óxkæ!²0›ÒÊ!Yœ™ÒLÓ|àºn¦ÑlÞ‚È¥3îç@iZ×—}-¬®ñÖÌ݈ÜûÇgÞŸ†´Û>‰È†?6ÂË‚ï|.kEæeªŽâo{‡wà4ø‘rùÁ£µÚ½R«ï†m¢iô„,Y–u'"ŸIÁªÔÔ>ÇÎHݽMÛ¶ûoCØ uçT•ÚÁI sX¡h—$õ¸ º R ”RKq‹{žV§çq7b €Ù]+9· ‚y˜·¬ÐÐõ«¢„Øñçž'±¿®±†€ ÀØÒœz¡a¡ê¨BD…ãÆÒ’E<’DJPš1ô#ú‡‡ÄYïq›ç[UG=˜†Áíùlö"Nm§¯†cŽ–g×që;žaì ð”@#L³ž`Á4ë-C_$Xð’Зï!زmë4áÚ®/XˆÄ=\IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_undock@2x.png000066400000000000000000000015601463772530400301270ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+"IDATxœíš½kAÆŸw/’;"6bŒxw{{æ !`kïÄÂ.ì•t6!±D‹¤³‰‰ v¶B !ñön³ F,”„Kˆ·¯EBÀÛ½»ìÇ›ÉeçWÎνï3ÏÍ3h4š4Cq¬nnžh4¦4FÀ€þtÅa—U/mçró#ƒƒ[*Ç2 Z¯ß2@ äãÄ‘‚×O–Mó}»:FÔ൚3I w'µñÀ@ž@+¶ãL´«©Tç61VÃÀc¦ÉàÑ žÚ€ý1¿óÀåD¤¸[¹ìÕÖ9!ô?8ÐhL¡Çì‡íÿÚ%#éø ÒÚ€ƒ¥®' ÒÞ!NÇuÞ2‹±÷q°ëwøìÓÞ+³¸ÚÕT£ P-@5ÚÕT“zºn„jµÚ%Æ#fºðÅnõíº³U Ì—=Znîí¼¨T*¢Æ ‘³=UǹKŒ祅`Ã3îYVþs¨uÞ úvªm‡€]ߘ%ƨi<X0¼O¶ã<”Lh€í8ãOK&>"0ælÛ½.•Àg€mÛ%0^J%Œ@†÷jmmíœDp0úfˆ$‹•9“} ØgïH$Š 2º|œÔS^b]¡DšU$„d€ax¼Òî;'p‰Dh† …ÈN¬ol #¸ ©ß kT P6@µÕhT P6@µÕhT P6@µÕDy Š+ÝN|ÀnkAªz«­e©2€ÀK­e©1€w;—›o-O‹M<ôn¸—&Á¨4A¸_.¿>Õ=€—Á£V±¸Ø®Îiì‡Ïå³ýýsCCCÛ*ûŽšXk¥øf™Åᤃú‡ãgÒI’~HD š>H$Š ”ˆë¿óŒ§ö$’Åà<ï¹D`Ÿårþ 'ámÀ! ž(•Jß%b.ƒ¥Bá^K$ Í–Mó­Tô@ˆÈ3‹ùqCÝpøÍàqË,ÌH&ézãZ­º×Èð¦ÜႤ˜A.ƒ–áý}bYVM:ŸF£I7ÿnÓ\ؘ<IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_undock_disabled.png000066400000000000000000000010301463772530400313740ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÊIDATX…í–?HÃ@Æ¿— )Õ]©‹¸vA\Œ®ÒXÄ!.­.ºD\œ:8.Å¥V\”’‚ÐE³"8ÚÑÁ¡8¸þ …æž‹©55iÒ¿ƒý¦wÉË}¿¼»{ðßEn/4mX”ƒ)GL´éUX—+½B!Sn ° iÃ\ÞiÓØ&*Êš± $§4Q¦:o©ÈfÊ9|—½K"ÕŠ†\²~­¹¡g]÷K3)j‚ÿšÛ±½Ò aÌÇ6Âdšs ÏÕø–Ó$I‚…(Ž>ïs¹œÙ2Àür|›„ØQÒN“03@„71r»ÝX¹Êg^¼Ô–@Q«Ät`‡ò#fM±X,àÀN«Ævˆw34í5¿þoí]ïȇ„$EÜùøÕh =ë¸éìRÔlZcÁÂóéêû1 úÐr×sÒŠšplÝJVЧ °nE]©€»¨(W¤=kÔË ”>¬¿uíWQ×?uÄŠyÍÈŸœyI­U€ ŒŽ˜U2Å×äŸ%¨Š$¯mÛ3v¯/OŸ½¦×.OŸ“S‘s’( Hãd_¶@‘ˆ’†ž=öñÝ@øgÛ€¥ÉrZÉIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_undock_disabled@2x.png000066400000000000000000000016341463772530400317600ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+NIDATxœí›ÍkAÆŸwÓ¨…R""ö`m<¨ѓފ6‰›”ÒTûñÿëQiý"í¥Ôƒ1UZM*´àÁ‹‡"=XÌ¥Š‡–Š©If<³›M³»“1Íü޳Ãó>ûd23ìÎ …¢–!»m¡7Ï ‚ñ­¶:àËëàX€F± ¹Gçb·×Ì:Û À×ñr ãšìè$E áÄãh²X—Ue_°'̉ØnU£4‚еïÐÑ/Ÿ>¼}oÔÁÒðžûÀµš-{•#G F#¡ìÚB nökÀG¬UŽTFÛr pN(ûtóÌ ªïæ )ïýÊÂŒ‡±#ïåðg©«N ¼×Y1]ç“ñ¨í½…¼Á7¹¬ó^-³¸0T² ÈF Û€lT² Ȧæ(¹ò®ìf`ý œ$`—Ù.|ÁÈG«f8À¤˜vmûyofrrÕªÖF1 Àè=ˈØ‘7X´Øôäá@[6]ß߈tÍNE_ÛÔ3¥è_Àèñ§Èß¼š‰ðÊìíYÄ0_ rDC" oÀGÚ‘c¢ è8u®o/'º/ª \DxÐÑÝÝ(B\@Ö•½p!ÅlМK×_!¬ €€Ó" Ù… òe4ü¯¸…ø*ûˆ¦ñý"Œd³ðhÍ»N¼Ä1¢ì^ÄÆ,otÌð‡zÀ˜esj~+¬m@6*Ùd£m@6*Ùd£m@6*Ùdcå|€8ÐRâÝÿFX/l¨­À±PØT[hÓ5Éð!‰T†Ü£…U3Ø$G ṸþÜp-ã„Þd‘ó›=€1„‹Ý<°9ø{\žêÓ#‰‰‰fušXk…@ÀR"õ8­k´ |sºˆp`Y„®Q³" Ù†ã¥Y]c7dD³Áw Úº/F–ß-{YÈ/¢ übb*úF„¶áNðxkÓM‰(X. 'âcÏDé~34??Ï/…ÎÄS_WW:Q¬Ÿ`V8èr2½%²HÉ7®þÎða¦iCÚìi&OŠÓu¹ºëÏŸÜý\z …¢†ù )ÐôÆlëIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_undock_focus.png000066400000000000000000000007671463772530400307640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+©IDATX…í–±JÃP†ÿ“d±_@Ô7¨`¡A|) *]|]—ND—â8YI:A †R°P;¸¸(Ô©¹Ç¡&6µ·MLk†öŸn’sÏÿåÜ{˜uѨ©*'QdPÀjD¯ƒMGS ú ªrr¡Ã5kÕìj´éB(²¨DG§`kjWÝ)ÀwÙ§"îXç[s;§ŒÜ/ã¤[‚‡å–Và¿4øµÒe^ÑTlì{Ÿ©ð‘, šËžîöÈù3€nñ ÀçÃÀˆ¹$ÍB=Ü i“÷½ð– Sá<ÀÃÌChK#¾Ý-³€˜O#û Ú*6‚÷ÿí@×ãëàž”°äÍì媅ð5;§J7Ý tË@‡€ütÅ~ çs€Ø¢t=©ˆ¹¤[BÞº–;ˆ¥ 6ãh:šRˆ Åà«þ1Ð×~uK¼XœˆÓmÐMП 0î'bt…Ї Á€PéÀ[d{¦³z–Ú¡êYj …ÖÁ0|„µð PÞ6è2äÜב{2båkIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_undock_focus@2x.png000066400000000000000000000015421463772530400313260ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíš;hQ…Ï™]0b°1…ÁX awí¾0… 1`—€¨¤³ )­Œ¥ ZXZ$î† $‚ ‚Ù€E$……¢Å‚ˆX(>ÜcDwfw33{÷&Î|å›óŸ9™Ç¿w.gU oZ«iŒ ÐK`[+Œ…EÀ‚3L=»ÀoæG [Ô @÷tEÑ1HàH)ÏÇõ&8a•³Ez„Í{òÐh![Ôp½ ¡®€ì¬NBZ@„ÛLài¿+!p}Óêü™ÖkûZb­}”·Wx¨ö™ø?¸šÆ(¶ÞÉ@׺÷€ ÁÖøi?~ÞC€ÞÖØi?~ÞÓAEš½çKy'ro…lÑU½c~Þ·ÊSÜI¶ Ø& À¶Û$Ø6`›Øд:RÐÞ´ã^•Ëc ö4›Ÿ)ºoš¡ eóìÀR?¿†ÕÚpÍFsuÀ.ÓF<ï^, p1ÈŸ5êo§Z÷È«¢æ`ãä€èõ5n²HÓ/®™¢î˜Àãv›4³NÒ<çÆây¾oC½„„„óé ÑìË IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_undock_pressed.png000066400000000000000000000010331463772530400312750ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÍIDATX…í–±J#Q†¿“dT°p‹-Å0 #,‚ì+,ŠŠ…–މ"6V)¶»«#+›´V*yAÁô T,TÐB AP…NL¢3Î$Ñæ¯î9sÿoÎ=sæÂg—¸ÝìM6… ~„öŠœ”#„Œjd>—6¯ßèM6}iŒl D+2~ÁÁ>éµ!Ná†p¢ÚæQ‘›„=w鯶y^Ê€= 9ûïy6w­—·d˜–¾¶¶K>Fu€5Ð=¾Ð&ù_7&¬I§EDå^…ýŽ‹o;ëëCweô˜‹3ŠüB_)NeÉiEAá°åt«{üïp.=}â ¿†i(’,…ò#…¾€Wׂ¾@fË5.…8øzöÝk|ÁÛji×ûçÝT~ ÚjÏE‰Û>Šÿ ÙTܱèJe˜@,$êùëªùgX¨Ô ì®ç*eÉ0-ÇÖrdk“!cß'.z:”ÎÛóËÀcÚÿžˆ¡ ý¦u 4WÅLt,ûjÅKèsT7ªb·mz ÎH(4 œWê®ÊÜîrìØ7ÀîrìX‚Á.T3À•__=DGréøoŸÏ~r='™y‘öwYÙIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/dark/rc/window_undock_pressed@2x.png000066400000000000000000000016111463772530400316510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+;IDATxœíš½kAÆŸÙ „ Øˆc Cb¡BrÑ”â'± Šx`6—ÓS þÆ*¸—Kr)Ò6ÑB„œ ‹H.)$ˆ…‚Å)µˆäƒ3™}-"·{{·s“sçWÎ ÏûìsóÅî …"ʰ G3»›8O2BŽh ÁWŠ ,Ãô†®g>Œ%WÝ: fŒž¬)­AtR´x>{óU¹š_娀¬—ع­€•ë6Ò×Ëuð5ºúÍsŒ!‡ÖhœF‚ç¶ç¼õ‘„ã­fÖuýpéšàùlâqðÞàCÆuŸÏgSÏAˆ&¹üló^/«¸0T² ÈF Û€lT² È&òT<uõì×4-A`§Ah®Ô?f˜Ÿ|»! ÌèȾK§~ùÖª×b‰ô%X4E„½4Û}»Ù>Cv€á$ÿDg¼º8žšó­We§@Ì0‡aÑsÀÓÇI›fám—‘YÄ1€n#}ÀÈÂU¢3ÐhgÂìUÀ@ÏÀÈAMŠ*è]³ðäÄ-sq[[Ôp€bhãE"„¦õŠ(!¾œÖ€ù–—ÄøòüBÄÒõC"Œè|«ƒÀre;°àqœðÀâXÒÿAÇ…ÎÁ 4ÎEH»ù£° @¶Ù¨d @¶Ù¨d @¶Ù¨dŸû²h¯ðí¿Š¥ Ñ„¥Ò¦H@ Ó¥mQ  °¡ë™ÒƨÀ-îto8 pv£Ü}ázÚüP´ø¼Ëeéÿ1€×å7׋£ïß[sël{ÕÂ^+ŠÏùlª#lQûÀð=ì"¡À°,BÖᵈBAa 7"tmhÀC›"Šà§eYã"„õÒ†¯ ¹å–îÞUçEô®ä'ï,ˆÐv<ä›<ðTDA¯0FÃóÙÔ Qú¶˜¥o?kYÛµàTÙ~bYaŒ®ÍOÜ6E©øÅõ¸a³€!0œaŸH3)l¦m=˜›¸û¥õ E„ù:ÞÐ1K4jIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/000077500000000000000000000000001463772530400237555ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/_variables.scss000066400000000000000000000021261463772530400267620ustar00rootroot00000000000000// --------------------------------------------------------------------------- // // WARNING! File created programmatically. All changes made in this file will be lost! // // Created by the qtsass compiler v0.3.0 // // The definitions are in the "qdarkstyle.palette" module // //---------------------------------------------------------------------------- $ID: 'light'; $COLOR_BACKGROUND_6: #ACB1B6; $COLOR_BACKGROUND_5: #B9BDC1; $COLOR_BACKGROUND_4: #C9CDD0; $COLOR_BACKGROUND_2: #E0E1E3; $COLOR_BACKGROUND_3: #CED1D4; $COLOR_BACKGROUND_1: #FAFAFA; $COLOR_TEXT_1: #19232D; $COLOR_TEXT_2: #293544; $COLOR_TEXT_3: #54687A; $COLOR_TEXT_4: #788D9C; $COLOR_ACCENT_1: #DAEDFF; $COLOR_ACCENT_2: #9FCBFF; $COLOR_ACCENT_3: #73C7FF; $COLOR_ACCENT_4: #37AEFE; $OPACITY_TOOLTIP: 230; $SIZE_BORDER_RADIUS: 4px; $BORDER_1: 1px solid $COLOR_BACKGROUND_1; $BORDER_2: 1px solid $COLOR_BACKGROUND_4; $BORDER_3: 1px solid $COLOR_BACKGROUND_6; $BORDER_SELECTION_3: 1px solid $COLOR_ACCENT_3; $BORDER_SELECTION_2: 1px solid $COLOR_ACCENT_2; $BORDER_SELECTION_1: 1px solid $COLOR_ACCENT_1; $PATH_RESOURCES: ':/qss_icons'; sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/lightstyle.qrc000066400000000000000000000233571463772530400266660ustar00rootroot00000000000000 rc/arrow_down.png rc/arrow_down@2x.png rc/arrow_down_disabled.png rc/arrow_down_disabled@2x.png rc/arrow_down_focus.png rc/arrow_down_focus@2x.png rc/arrow_down_pressed.png rc/arrow_down_pressed@2x.png rc/arrow_left.png rc/arrow_left@2x.png rc/arrow_left_disabled.png rc/arrow_left_disabled@2x.png rc/arrow_left_focus.png rc/arrow_left_focus@2x.png rc/arrow_left_pressed.png rc/arrow_left_pressed@2x.png rc/arrow_right.png rc/arrow_right@2x.png rc/arrow_right_disabled.png rc/arrow_right_disabled@2x.png rc/arrow_right_focus.png rc/arrow_right_focus@2x.png rc/arrow_right_pressed.png rc/arrow_right_pressed@2x.png rc/arrow_up.png rc/arrow_up@2x.png rc/arrow_up_disabled.png rc/arrow_up_disabled@2x.png rc/arrow_up_focus.png rc/arrow_up_focus@2x.png rc/arrow_up_pressed.png rc/arrow_up_pressed@2x.png rc/base_icon.png rc/base_icon@2x.png rc/base_icon_disabled.png rc/base_icon_disabled@2x.png rc/base_icon_focus.png rc/base_icon_focus@2x.png rc/base_icon_pressed.png rc/base_icon_pressed@2x.png rc/branch_closed.png rc/branch_closed@2x.png rc/branch_closed_disabled.png rc/branch_closed_disabled@2x.png rc/branch_closed_focus.png rc/branch_closed_focus@2x.png rc/branch_closed_pressed.png rc/branch_closed_pressed@2x.png rc/branch_end.png rc/branch_end@2x.png rc/branch_end_disabled.png rc/branch_end_disabled@2x.png rc/branch_end_focus.png rc/branch_end_focus@2x.png rc/branch_end_pressed.png rc/branch_end_pressed@2x.png rc/branch_line.png rc/branch_line@2x.png rc/branch_line_disabled.png rc/branch_line_disabled@2x.png rc/branch_line_focus.png rc/branch_line_focus@2x.png rc/branch_line_pressed.png rc/branch_line_pressed@2x.png rc/branch_more.png rc/branch_more@2x.png rc/branch_more_disabled.png rc/branch_more_disabled@2x.png rc/branch_more_focus.png rc/branch_more_focus@2x.png rc/branch_more_pressed.png rc/branch_more_pressed@2x.png rc/branch_open.png rc/branch_open@2x.png rc/branch_open_disabled.png rc/branch_open_disabled@2x.png rc/branch_open_focus.png rc/branch_open_focus@2x.png rc/branch_open_pressed.png rc/branch_open_pressed@2x.png rc/checkbox_checked.png rc/checkbox_checked@2x.png rc/checkbox_checked_disabled.png rc/checkbox_checked_disabled@2x.png rc/checkbox_checked_focus.png rc/checkbox_checked_focus@2x.png rc/checkbox_checked_pressed.png rc/checkbox_checked_pressed@2x.png rc/checkbox_indeterminate.png rc/checkbox_indeterminate@2x.png rc/checkbox_indeterminate_disabled.png rc/checkbox_indeterminate_disabled@2x.png rc/checkbox_indeterminate_focus.png rc/checkbox_indeterminate_focus@2x.png rc/checkbox_indeterminate_pressed.png rc/checkbox_indeterminate_pressed@2x.png rc/checkbox_unchecked.png rc/checkbox_unchecked@2x.png rc/checkbox_unchecked_disabled.png rc/checkbox_unchecked_disabled@2x.png rc/checkbox_unchecked_focus.png rc/checkbox_unchecked_focus@2x.png rc/checkbox_unchecked_pressed.png rc/checkbox_unchecked_pressed@2x.png rc/line_horizontal.png rc/line_horizontal@2x.png rc/line_horizontal_disabled.png rc/line_horizontal_disabled@2x.png rc/line_horizontal_focus.png rc/line_horizontal_focus@2x.png rc/line_horizontal_pressed.png rc/line_horizontal_pressed@2x.png rc/line_vertical.png rc/line_vertical@2x.png rc/line_vertical_disabled.png rc/line_vertical_disabled@2x.png rc/line_vertical_focus.png rc/line_vertical_focus@2x.png rc/line_vertical_pressed.png rc/line_vertical_pressed@2x.png rc/radio_checked.png rc/radio_checked@2x.png rc/radio_checked_disabled.png rc/radio_checked_disabled@2x.png rc/radio_checked_focus.png rc/radio_checked_focus@2x.png rc/radio_checked_pressed.png rc/radio_checked_pressed@2x.png rc/radio_unchecked.png rc/radio_unchecked@2x.png rc/radio_unchecked_disabled.png rc/radio_unchecked_disabled@2x.png rc/radio_unchecked_focus.png rc/radio_unchecked_focus@2x.png rc/radio_unchecked_pressed.png rc/radio_unchecked_pressed@2x.png rc/toolbar_move_horizontal.png rc/toolbar_move_horizontal@2x.png rc/toolbar_move_horizontal_disabled.png rc/toolbar_move_horizontal_disabled@2x.png rc/toolbar_move_horizontal_focus.png rc/toolbar_move_horizontal_focus@2x.png rc/toolbar_move_horizontal_pressed.png rc/toolbar_move_horizontal_pressed@2x.png rc/toolbar_move_vertical.png rc/toolbar_move_vertical@2x.png rc/toolbar_move_vertical_disabled.png rc/toolbar_move_vertical_disabled@2x.png rc/toolbar_move_vertical_focus.png rc/toolbar_move_vertical_focus@2x.png rc/toolbar_move_vertical_pressed.png rc/toolbar_move_vertical_pressed@2x.png rc/toolbar_separator_horizontal.png rc/toolbar_separator_horizontal@2x.png rc/toolbar_separator_horizontal_disabled.png rc/toolbar_separator_horizontal_disabled@2x.png rc/toolbar_separator_horizontal_focus.png rc/toolbar_separator_horizontal_focus@2x.png rc/toolbar_separator_horizontal_pressed.png rc/toolbar_separator_horizontal_pressed@2x.png rc/toolbar_separator_vertical.png rc/toolbar_separator_vertical@2x.png rc/toolbar_separator_vertical_disabled.png rc/toolbar_separator_vertical_disabled@2x.png rc/toolbar_separator_vertical_focus.png rc/toolbar_separator_vertical_focus@2x.png rc/toolbar_separator_vertical_pressed.png rc/toolbar_separator_vertical_pressed@2x.png rc/transparent.png rc/transparent@2x.png rc/transparent_disabled.png rc/transparent_disabled@2x.png rc/transparent_focus.png rc/transparent_focus@2x.png rc/transparent_pressed.png rc/transparent_pressed@2x.png rc/window_close.png rc/window_close@2x.png rc/window_close_disabled.png rc/window_close_disabled@2x.png rc/window_close_focus.png rc/window_close_focus@2x.png rc/window_close_pressed.png rc/window_close_pressed@2x.png rc/window_grip.png rc/window_grip@2x.png rc/window_grip_disabled.png rc/window_grip_disabled@2x.png rc/window_grip_focus.png rc/window_grip_focus@2x.png rc/window_grip_pressed.png rc/window_grip_pressed@2x.png rc/window_minimize.png rc/window_minimize@2x.png rc/window_minimize_disabled.png rc/window_minimize_disabled@2x.png rc/window_minimize_focus.png rc/window_minimize_focus@2x.png rc/window_minimize_pressed.png rc/window_minimize_pressed@2x.png rc/window_undock.png rc/window_undock@2x.png rc/window_undock_disabled.png rc/window_undock_disabled@2x.png rc/window_undock_focus.png rc/window_undock_focus@2x.png rc/window_undock_pressed.png rc/window_undock_pressed@2x.png lightstyle.qss sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/lightstyle.qss000066400000000000000000001520721463772530400267040ustar00rootroot00000000000000/* --------------------------------------------------------------------------- WARNING! File created programmatically. All changes made in this file will be lost! Created by the qtsass compiler v0.4.0 The definitions are in the "qdarkstyle.qss._styles.scss" module --------------------------------------------------------------------------- */ /* Dark Style - QDarkStyleSheet ------------------------------------------ */ /* See Qt documentation: - https://doc.qt.io/qt-5/stylesheet.html - https://doc.qt.io/qt-5/stylesheet-reference.html - https://doc.qt.io/qt-5/stylesheet-examples.html --------------------------------------------------------------------------- */ /* Reset elements ------------------------------------------------------------ Resetting everything helps to unify styles across different operating systems --------------------------------------------------------------------------- */ * { padding: 0px; margin: 0px; border: 0px; border-style: none; border-image: none; outline: 0; } /* specific reset for elements inside QToolBar */ QToolBar * { margin: 0px; padding: 0px; } /* QWidget ---------------------------------------------------------------- --------------------------------------------------------------------------- */ QWidget { background-color: #FAFAFA; border: 0px solid #C0C4C8; padding: 0px; color: #19232D; selection-background-color: #9FCBFF; selection-color: #19232D; } QWidget:disabled { background-color: #FAFAFA; color: #9DA9B5; selection-background-color: #DAEDFF; selection-color: #9DA9B5; } QWidget::item:selected { background-color: #9FCBFF; } QWidget::item:hover:!selected { background-color: #73C7FF; } /* QMainWindow ------------------------------------------------------------ This adjusts the splitter in the dock widget, not qsplitter https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow --------------------------------------------------------------------------- */ QMainWindow::separator { background-color: #C0C4C8; border: 0px solid #FAFAFA; spacing: 0px; padding: 2px; } QMainWindow::separator:hover { background-color: #ACB1B6; border: 0px solid #73C7FF; } QMainWindow::separator:horizontal { width: 5px; margin-top: 2px; margin-bottom: 2px; image: url(":/qss_icons/light/rc/toolbar_separator_vertical.png"); } QMainWindow::separator:vertical { height: 5px; margin-left: 2px; margin-right: 2px; image: url(":/qss_icons/light/rc/toolbar_separator_horizontal.png"); } /* QToolTip --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip --------------------------------------------------------------------------- */ QToolTip { background-color: #9FCBFF; color: #19232D; /* If you remove the border property, background stops working on Windows */ border: none; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Remove opacity, fix #174 - may need to use RGBA */ } /* QStatusBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar --------------------------------------------------------------------------- */ QStatusBar { border: 1px solid #C0C4C8; /* Fixes Spyder #9120, #9121 */ background: #C0C4C8; /* Fixes #205, white vertical borders separating items */ } QStatusBar::item { border: none; } QStatusBar QToolTip { background-color: #73C7FF; border: 1px solid #FAFAFA; color: #FAFAFA; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Reducing transparency to read better */ opacity: 230; } QStatusBar QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; } /* QCheckBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox --------------------------------------------------------------------------- */ QCheckBox { background-color: #FAFAFA; color: #19232D; spacing: 4px; outline: none; padding-top: 4px; padding-bottom: 4px; } QCheckBox:focus { border: none; } QCheckBox QWidget:disabled { background-color: #FAFAFA; color: #9DA9B5; } QCheckBox::indicator { margin-left: 2px; height: 14px; width: 14px; } QCheckBox::indicator:unchecked { image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QCheckBox::indicator:unchecked:disabled { image: url(":/qss_icons/light/rc/checkbox_unchecked_disabled.png"); } QCheckBox::indicator:checked { image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QCheckBox::indicator:checked:disabled { image: url(":/qss_icons/light/rc/checkbox_checked_disabled.png"); } QCheckBox::indicator:indeterminate { image: url(":/qss_icons/light/rc/checkbox_indeterminate.png"); } QCheckBox::indicator:indeterminate:disabled { image: url(":/qss_icons/light/rc/checkbox_indeterminate_disabled.png"); } QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { image: url(":/qss_icons/light/rc/checkbox_indeterminate_focus.png"); } /* QGroupBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { font-weight: bold; border: 1px solid #C0C4C8; border-radius: 4px; padding: 2px; margin-top: 6px; margin-bottom: 4px; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left: 4px; padding-left: 2px; padding-right: 4px; padding-top: -4px; } QGroupBox::indicator { margin-left: 2px; margin-top: 2px; padding: 0; height: 14px; width: 14px; } QGroupBox::indicator:unchecked { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QGroupBox::indicator:unchecked:disabled { image: url(":/qss_icons/light/rc/checkbox_unchecked_disabled.png"); } QGroupBox::indicator:checked { border: none; image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QGroupBox::indicator:checked:disabled { image: url(":/qss_icons/light/rc/checkbox_checked_disabled.png"); } /* QRadioButton ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton --------------------------------------------------------------------------- */ QRadioButton { background-color: #FAFAFA; color: #19232D; spacing: 4px; padding-top: 4px; padding-bottom: 4px; border: none; outline: none; } QRadioButton:focus { border: none; } QRadioButton:disabled { background-color: #FAFAFA; color: #9DA9B5; border: none; outline: none; } QRadioButton QWidget { background-color: #FAFAFA; color: #19232D; spacing: 0px; padding: 0px; outline: none; border: none; } QRadioButton::indicator { border: none; outline: none; margin-left: 2px; height: 14px; width: 14px; } QRadioButton::indicator:unchecked { image: url(":/qss_icons/light/rc/radio_unchecked.png"); } QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_unchecked_focus.png"); } QRadioButton::indicator:unchecked:disabled { image: url(":/qss_icons/light/rc/radio_unchecked_disabled.png"); } QRadioButton::indicator:checked { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked.png"); } QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked_focus.png"); } QRadioButton::indicator:checked:disabled { outline: none; image: url(":/qss_icons/light/rc/radio_checked_disabled.png"); } /* QMenuBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar --------------------------------------------------------------------------- */ QMenuBar { background-color: #C0C4C8; padding: 2px; border: 1px solid #FAFAFA; color: #19232D; selection-background-color: #73C7FF; } QMenuBar:focus { border: 1px solid #9FCBFF; } QMenuBar::item { background: transparent; padding: 4px; } QMenuBar::item:selected { padding: 4px; background: transparent; border: 0px solid #C0C4C8; background-color: #73C7FF; } QMenuBar::item:pressed { padding: 4px; border: 0px solid #C0C4C8; background-color: #73C7FF; color: #19232D; margin-bottom: 0px; padding-bottom: 0px; } /* QMenu ------------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu --------------------------------------------------------------------------- */ QMenu { border: 0px solid #C0C4C8; color: #19232D; margin: 0px; background-color: #D2D5D8; selection-background-color: #73C7FF; } QMenu::separator { height: 1px; background-color: #ACB1B6; color: #19232D; } QMenu::item { background-color: #D2D5D8; padding: 4px 24px 4px 28px; /* Reserve space for selection border */ border: 1px transparent #C0C4C8; } QMenu::item:selected { color: #19232D; background-color: #73C7FF; } QMenu::item:pressed { background-color: #73C7FF; } QMenu::icon { padding-left: 10px; width: 14px; height: 14px; } QMenu::indicator { padding-left: 8px; width: 12px; height: 12px; /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ } QMenu::indicator:non-exclusive:unchecked { image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QMenu::indicator:non-exclusive:unchecked:hover, QMenu::indicator:non-exclusive:unchecked:focus, QMenu::indicator:non-exclusive:unchecked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QMenu::indicator:non-exclusive:unchecked:disabled { image: url(":/qss_icons/light/rc/checkbox_unchecked_disabled.png"); } QMenu::indicator:non-exclusive:checked { image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QMenu::indicator:non-exclusive:checked:hover, QMenu::indicator:non-exclusive:checked:focus, QMenu::indicator:non-exclusive:checked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QMenu::indicator:non-exclusive:checked:disabled { image: url(":/qss_icons/light/rc/checkbox_checked_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate { image: url(":/qss_icons/light/rc/checkbox_indeterminate.png"); } QMenu::indicator:non-exclusive:indeterminate:disabled { image: url(":/qss_icons/light/rc/checkbox_indeterminate_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate:focus, QMenu::indicator:non-exclusive:indeterminate:hover, QMenu::indicator:non-exclusive:indeterminate:pressed { image: url(":/qss_icons/light/rc/checkbox_indeterminate_focus.png"); } QMenu::indicator:exclusive:unchecked { image: url(":/qss_icons/light/rc/radio_unchecked.png"); } QMenu::indicator:exclusive:unchecked:hover, QMenu::indicator:exclusive:unchecked:focus, QMenu::indicator:exclusive:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_unchecked_focus.png"); } QMenu::indicator:exclusive:unchecked:disabled { image: url(":/qss_icons/light/rc/radio_unchecked_disabled.png"); } QMenu::indicator:exclusive:checked { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked.png"); } QMenu::indicator:exclusive:checked:hover, QMenu::indicator:exclusive:checked:focus, QMenu::indicator:exclusive:checked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked_focus.png"); } QMenu::indicator:exclusive:checked:disabled { outline: none; image: url(":/qss_icons/light/rc/radio_checked_disabled.png"); } QMenu::right-arrow { margin: 5px; padding-left: 12px; image: url(":/qss_icons/light/rc/arrow_right.png"); height: 12px; width: 12px; } /* QAbstractItemView ------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QAbstractItemView { alternate-background-color: #FAFAFA; color: #19232D; border: 1px solid #C0C4C8; border-radius: 4px; } QAbstractItemView QLineEdit { padding: 2px; } /* QAbstractScrollArea ---------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QAbstractScrollArea { background-color: #FAFAFA; border: 1px solid #C0C4C8; border-radius: 4px; /* fix #159 */ padding: 2px; /* remove min-height to fix #244 */ color: #19232D; } QAbstractScrollArea:disabled { color: #9DA9B5; } /* QScrollArea ------------------------------------------------------------ --------------------------------------------------------------------------- */ QScrollArea QWidget QWidget:disabled { background-color: #FAFAFA; } /* QScrollBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar --------------------------------------------------------------------------- */ QScrollBar:horizontal { height: 16px; margin: 2px 16px 2px 16px; border: 1px solid #C0C4C8; border-radius: 4px; background-color: #FAFAFA; } QScrollBar:vertical { background-color: #FAFAFA; width: 16px; margin: 16px 2px 16px 2px; border: 1px solid #C0C4C8; border-radius: 4px; } QScrollBar::handle:horizontal { background-color: #ACB1B6; border: 1px solid #C0C4C8; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:hover { background-color: #9FCBFF; border: #9FCBFF; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:focus { border: 1px solid #73C7FF; } QScrollBar::handle:vertical { background-color: #ACB1B6; border: 1px solid #C0C4C8; min-height: 8px; border-radius: 4px; } QScrollBar::handle:vertical:hover { background-color: #9FCBFF; border: #9FCBFF; border-radius: 4px; min-height: 8px; } QScrollBar::handle:vertical:focus { border: 1px solid #73C7FF; } QScrollBar::add-line:horizontal { margin: 0px 0px 0px 0px; border-image: url(":/qss_icons/light/rc/arrow_right_disabled.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { border-image: url(":/qss_icons/light/rc/arrow_right.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { border-image: url(":/qss_icons/light/rc/arrow_down.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { margin: 0px 3px 0px 3px; border-image: url(":/qss_icons/light/rc/arrow_left_disabled.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { border-image: url(":/qss_icons/light/rc/arrow_left.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/light/rc/arrow_up_disabled.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { border-image: url(":/qss_icons/light/rc/arrow_up.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { background: none; } QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { background: none; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } /* QTextEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets --------------------------------------------------------------------------- */ QTextEdit { background-color: #FAFAFA; color: #19232D; border-radius: 4px; border: 1px solid #C0C4C8; } QTextEdit:focus { border: 1px solid #73C7FF; } QTextEdit:selected { background: #9FCBFF; color: #C0C4C8; } /* QPlainTextEdit --------------------------------------------------------- --------------------------------------------------------------------------- */ QPlainTextEdit { background-color: #FAFAFA; color: #19232D; border-radius: 4px; border: 1px solid #C0C4C8; } QPlainTextEdit:focus { border: 1px solid #73C7FF; } QPlainTextEdit:selected { background: #9FCBFF; color: #C0C4C8; } /* QSizeGrip -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip --------------------------------------------------------------------------- */ QSizeGrip { background: transparent; width: 12px; height: 12px; image: url(":/qss_icons/light/rc/window_grip.png"); } /* QStackedWidget --------------------------------------------------------- --------------------------------------------------------------------------- */ QStackedWidget { padding: 2px; border: 1px solid #C0C4C8; border: 1px solid #FAFAFA; } /* QToolBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar --------------------------------------------------------------------------- */ QToolBar { background-color: #C0C4C8; border-bottom: 1px solid #FAFAFA; padding: 1px; font-weight: bold; spacing: 2px; } QToolBar:disabled { /* Fixes #272 */ background-color: #C0C4C8; } QToolBar::handle:horizontal { width: 16px; image: url(":/qss_icons/light/rc/toolbar_move_horizontal.png"); } QToolBar::handle:vertical { height: 16px; image: url(":/qss_icons/light/rc/toolbar_move_vertical.png"); } QToolBar::separator:horizontal { width: 16px; image: url(":/qss_icons/light/rc/toolbar_separator_horizontal.png"); } QToolBar::separator:vertical { height: 16px; image: url(":/qss_icons/light/rc/toolbar_separator_vertical.png"); } QToolButton#qt_toolbar_ext_button { background: #C0C4C8; border: 0px; color: #19232D; image: url(":/qss_icons/light/rc/arrow_right.png"); } /* QAbstractSpinBox ------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractSpinBox { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; border-radius: 4px; /* min-width: 5px; removed to fix 109 */ } QAbstractSpinBox:up-button { background-color: transparent #FAFAFA; subcontrol-origin: border; subcontrol-position: top right; border-left: 1px solid #C0C4C8; border-bottom: 1px solid #C0C4C8; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-bottom: -1px; } QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { image: url(":/qss_icons/light/rc/arrow_up_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::up-arrow:hover { image: url(":/qss_icons/light/rc/arrow_up.png"); } QAbstractSpinBox:down-button { background-color: transparent #FAFAFA; subcontrol-origin: border; subcontrol-position: bottom right; border-left: 1px solid #C0C4C8; border-top: 1px solid #C0C4C8; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-top: -1px; } QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::down-arrow:hover { image: url(":/qss_icons/light/rc/arrow_down.png"); } QAbstractSpinBox:hover { border: 1px solid #9FCBFF; color: #19232D; } QAbstractSpinBox:focus { border: 1px solid #73C7FF; } QAbstractSpinBox:selected { background: #9FCBFF; color: #C0C4C8; } /* ------------------------------------------------------------------------ */ /* DISPLAYS --------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QLabel ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe --------------------------------------------------------------------------- */ QLabel { background-color: #FAFAFA; border: 0px solid #C0C4C8; padding: 2px; margin: 0px; color: #19232D; } QLabel:disabled { background-color: #FAFAFA; border: 0px solid #C0C4C8; color: #9DA9B5; } /* QTextBrowser ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QTextBrowser { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; } QTextBrowser:disabled { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #9DA9B5; border-radius: 4px; } QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { border: 1px solid #C0C4C8; } /* QGraphicsView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QGraphicsView { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; } QGraphicsView:disabled { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #9DA9B5; border-radius: 4px; } QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { border: 1px solid #C0C4C8; } /* QCalendarWidget -------------------------------------------------------- --------------------------------------------------------------------------- */ QCalendarWidget { border: 1px solid #C0C4C8; border-radius: 4px; } QCalendarWidget:disabled { background-color: #FAFAFA; color: #9DA9B5; } /* QLCDNumber ------------------------------------------------------------- --------------------------------------------------------------------------- */ QLCDNumber { background-color: #FAFAFA; color: #19232D; } QLCDNumber:disabled { background-color: #FAFAFA; color: #9DA9B5; } /* QProgressBar ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar --------------------------------------------------------------------------- */ QProgressBar { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; text-align: center; } QProgressBar:disabled { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #9DA9B5; border-radius: 4px; text-align: center; } QProgressBar::chunk { background-color: #9FCBFF; color: #FAFAFA; border-radius: 4px; } QProgressBar::chunk:disabled { background-color: #DAEDFF; color: #9DA9B5; border-radius: 4px; } /* ------------------------------------------------------------------------ */ /* BUTTONS ---------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QPushButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton --------------------------------------------------------------------------- */ QPushButton { background-color: #C0C4C8; color: #19232D; border-radius: 4px; padding: 2px; outline: none; border: none; } QPushButton:disabled { background-color: #C0C4C8; color: #9DA9B5; border-radius: 4px; padding: 2px; } QPushButton:checked { background-color: #ACB1B6; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:disabled { background-color: #ACB1B6; color: #9DA9B5; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:selected { background: #ACB1B6; } QPushButton:hover { background-color: #B4B8BC; color: #19232D; } QPushButton:pressed { background-color: #ACB1B6; } QPushButton:selected { background: #ACB1B6; color: #19232D; } QPushButton::menu-indicator { subcontrol-origin: padding; subcontrol-position: bottom right; bottom: 4px; } QDialogButtonBox QPushButton { /* Issue #194 #248 - Special case of QPushButton inside dialogs, for better UI */ min-width: 80px; } /* QToolButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton --------------------------------------------------------------------------- */ QToolButton { background-color: #C0C4C8; color: #19232D; border-radius: 4px; padding: 2px; outline: none; border: none; /* The subcontrols below are used only in the DelayedPopup mode */ /* The subcontrols below are used only in the MenuButtonPopup mode */ /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ } QToolButton:disabled { background-color: #C0C4C8; color: #9DA9B5; border-radius: 4px; padding: 2px; } QToolButton:checked { background-color: #ACB1B6; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:disabled { background-color: #ACB1B6; color: #9DA9B5; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:hover { background-color: #B4B8BC; color: #19232D; } QToolButton:checked:pressed { background-color: #ACB1B6; } QToolButton:checked:selected { background: #ACB1B6; color: #19232D; } QToolButton:hover { background-color: #B4B8BC; color: #19232D; } QToolButton:pressed { background-color: #ACB1B6; } QToolButton:selected { background: #ACB1B6; color: #19232D; } QToolButton[popupMode="0"] { /* Only for DelayedPopup */ padding-right: 2px; } QToolButton[popupMode="1"] { /* Only for MenuButtonPopup */ padding-right: 20px; } QToolButton[popupMode="1"]::menu-button { border: none; } QToolButton[popupMode="1"]::menu-button:hover { border: none; border-left: 1px solid #C0C4C8; border-radius: 0; } QToolButton[popupMode="2"] { /* Only for InstantPopup */ padding-right: 2px; } QToolButton::menu-button { padding: 2px; border-radius: 4px; width: 12px; border: none; outline: none; } QToolButton::menu-button:hover { border: 1px solid #9FCBFF; } QToolButton::menu-button:checked:hover { border: 1px solid #9FCBFF; } QToolButton::menu-indicator { image: url(":/qss_icons/light/rc/arrow_down.png"); height: 8px; width: 8px; top: 0; /* Exclude a shift for better image */ left: -2px; /* Shift it a bit */ } QToolButton::menu-arrow { image: url(":/qss_icons/light/rc/arrow_down.png"); height: 8px; width: 8px; } QToolButton::menu-arrow:hover { image: url(":/qss_icons/light/rc/arrow_down_focus.png"); } /* QCommandLinkButton ----------------------------------------------------- --------------------------------------------------------------------------- */ QCommandLinkButton { background-color: transparent; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; padding: 0px; margin: 0px; } QCommandLinkButton:disabled { background-color: transparent; color: #9DA9B5; } /* ------------------------------------------------------------------------ */ /* INPUTS - NO FIELDS ----------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QComboBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QComboBox { border: 1px solid #C0C4C8; border-radius: 4px; selection-background-color: #9FCBFF; padding-left: 4px; padding-right: 4px; /* padding-right = 36; 4 + 16*2 See scrollbar size */ /* changed to 4px to fix #239 */ /* Fixes #103, #111 */ min-height: 1.5em; /* padding-top: 2px; removed to fix #132 */ /* padding-bottom: 2px; removed to fix #132 */ /* min-width: 75px; removed to fix #109 */ /* Needed to remove indicator - fix #132 */ } QComboBox QAbstractItemView { border: 1px solid #C0C4C8; border-radius: 0; background-color: #FAFAFA; selection-background-color: #9FCBFF; } QComboBox QAbstractItemView:hover { background-color: #FAFAFA; color: #19232D; } QComboBox QAbstractItemView:selected { background: #9FCBFF; color: #C0C4C8; } QComboBox QAbstractItemView:alternate { background: #FAFAFA; } QComboBox:disabled { background-color: #FAFAFA; color: #9DA9B5; } QComboBox:hover { border: 1px solid #9FCBFF; } QComboBox:focus { border: 1px solid #73C7FF; } QComboBox:on { selection-background-color: #9FCBFF; } QComboBox::indicator { border: none; border-radius: 0; background-color: transparent; selection-background-color: transparent; color: transparent; selection-color: transparent; /* Needed to remove indicator - fix #132 */ } QComboBox::indicator:alternate { background: #FAFAFA; } QComboBox::item { /* Remove to fix #282, #285 and MR #288*/ /*&:checked { font-weight: bold; } &:selected { border: 0px solid transparent; } */ } QComboBox::item:alternate { background: #FAFAFA; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #C0C4C8; } QComboBox::down-arrow { image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { image: url(":/qss_icons/light/rc/arrow_down.png"); } /* QSlider ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider --------------------------------------------------------------------------- */ QSlider:disabled { background: #FAFAFA; } QSlider:focus { border: none; } QSlider::groove:horizontal { background: #C0C4C8; border: 1px solid #C0C4C8; height: 4px; margin: 0px; border-radius: 4px; } QSlider::groove:vertical { background: #C0C4C8; border: 1px solid #C0C4C8; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical { background: #9FCBFF; border: 1px solid #C0C4C8; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical :disabled { background: #DAEDFF; } QSlider::sub-page:horizontal { background: #9FCBFF; border: 1px solid #C0C4C8; height: 4px; margin: 0px; border-radius: 4px; } QSlider::sub-page:horizontal:disabled { background: #DAEDFF; } QSlider::handle:horizontal { background: #788D9C; border: 1px solid #C0C4C8; width: 8px; height: 8px; margin: -8px 0px; border-radius: 4px; } QSlider::handle:horizontal:hover { background: #9FCBFF; border: 1px solid #9FCBFF; } QSlider::handle:horizontal:focus { border: 1px solid #73C7FF; } QSlider::handle:vertical { background: #788D9C; border: 1px solid #C0C4C8; width: 8px; height: 8px; margin: 0 -8px; border-radius: 4px; } QSlider::handle:vertical:hover { background: #9FCBFF; border: 1px solid #9FCBFF; } QSlider::handle:vertical:focus { border: 1px solid #73C7FF; } /* QLineEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit --------------------------------------------------------------------------- */ QLineEdit { background-color: #FAFAFA; padding-top: 2px; /* This QLineEdit fix 103, 111 */ padding-bottom: 2px; /* This QLineEdit fix 103, 111 */ padding-left: 4px; padding-right: 4px; border-style: solid; border: 1px solid #C0C4C8; border-radius: 4px; color: #19232D; } QLineEdit:disabled { background-color: #FAFAFA; color: #9DA9B5; } QLineEdit:hover { border: 1px solid #9FCBFF; color: #19232D; } QLineEdit:focus { border: 1px solid #73C7FF; } QLineEdit:selected { background-color: #9FCBFF; color: #C0C4C8; } /* QTabWiget -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabWidget { padding: 2px; selection-background-color: #C0C4C8; } QTabWidget QWidget { /* Fixes #189 */ border-radius: 4px; } QTabWidget::pane { border: 1px solid #C0C4C8; border-radius: 4px; margin: 0px; /* Fixes double border inside pane with pyqt5 */ padding: 0px; } QTabWidget::pane:selected { background-color: #C0C4C8; border: 1px solid #9FCBFF; } /* QTabBar ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabBar, QDockWidget QTabBar { qproperty-drawBase: 0; border-radius: 4px; margin: 0px; padding: 2px; border: 0; /* left: 5px; move to the right by 5px - removed for fix */ } QTabBar::close-button, QDockWidget QTabBar::close-button { border: 0; margin: 0; padding: 4px; image: url(":/qss_icons/light/rc/window_close.png"); } QTabBar::close-button:hover, QDockWidget QTabBar::close-button:hover { image: url(":/qss_icons/light/rc/window_close_focus.png"); } QTabBar::close-button:pressed, QDockWidget QTabBar::close-button:pressed { image: url(":/qss_icons/light/rc/window_close_pressed.png"); } QTabBar::tab, QDockWidget QTabBar::tab { /* !selected and disabled ----------------------------------------- */ /* selected ------------------------------------------------------- */ } QTabBar::tab:top:selected:disabled, QDockWidget QTabBar::tab:top:selected:disabled { border-bottom: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:bottom:selected:disabled, QDockWidget QTabBar::tab:bottom:selected:disabled { border-top: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:left:selected:disabled, QDockWidget QTabBar::tab:left:selected:disabled { border-right: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:disabled { border-left: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled { border-bottom: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled { border-top: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled { border-right: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled { border-left: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected { border-bottom: 2px solid #FAFAFA; margin-top: 2px; } QTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected { border-top: 2px solid #FAFAFA; margin-bottom: 2px; } QTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected { border-left: 2px solid #FAFAFA; margin-right: 2px; } QTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected { border-right: 2px solid #FAFAFA; margin-left: 2px; } QTabBar::tab:top, QDockWidget QTabBar::tab:top { background-color: #C0C4C8; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; min-width: 5px; border-bottom: 3px solid #C0C4C8; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:selected, QDockWidget QTabBar::tab:top:selected { background-color: #B4B8BC; border-bottom: 3px solid #37AEFE; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:!selected:hover, QDockWidget QTabBar::tab:top:!selected:hover { border: 1px solid #73C7FF; border-bottom: 3px solid #73C7FF; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom { border-top: 3px solid #C0C4C8; background-color: #C0C4C8; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; min-width: 5px; } QTabBar::tab:bottom:selected, QDockWidget QTabBar::tab:bottom:selected { background-color: #B4B8BC; border-top: 3px solid #37AEFE; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } QTabBar::tab:bottom:!selected:hover, QDockWidget QTabBar::tab:bottom:!selected:hover { border: 1px solid #73C7FF; border-top: 3px solid #73C7FF; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:left, QDockWidget QTabBar::tab:left { background-color: #C0C4C8; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-left-radius: 4px; border-bottom-left-radius: 4px; min-height: 5px; } QTabBar::tab:left:selected, QDockWidget QTabBar::tab:left:selected { background-color: #B4B8BC; border-right: 3px solid #37AEFE; } QTabBar::tab:left:!selected:hover, QDockWidget QTabBar::tab:left:!selected:hover { border: 1px solid #73C7FF; border-right: 3px solid #73C7FF; /* Fixes different behavior #271 */ margin-right: 0px; padding-right: -1px; } QTabBar::tab:right, QDockWidget QTabBar::tab:right { background-color: #C0C4C8; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; min-height: 5px; } QTabBar::tab:right:selected, QDockWidget QTabBar::tab:right:selected { background-color: #B4B8BC; border-left: 3px solid #37AEFE; } QTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hover { border: 1px solid #73C7FF; border-left: 3px solid #73C7FF; /* Fixes different behavior #271 */ margin-left: 0px; padding-left: 0px; } QTabBar QToolButton, QDockWidget QTabBar QToolButton { /* Fixes #136 */ background-color: #C0C4C8; height: 12px; width: 12px; } QTabBar QToolButton:pressed, QDockWidget QTabBar QToolButton:pressed { background-color: #C0C4C8; } QTabBar QToolButton:pressed:hover, QDockWidget QTabBar QToolButton:pressed:hover { border: 1px solid #9FCBFF; } QTabBar QToolButton::left-arrow:enabled, QDockWidget QTabBar QToolButton::left-arrow:enabled { image: url(":/qss_icons/light/rc/arrow_left.png"); } QTabBar QToolButton::left-arrow:disabled, QDockWidget QTabBar QToolButton::left-arrow:disabled { image: url(":/qss_icons/light/rc/arrow_left_disabled.png"); } QTabBar QToolButton::right-arrow:enabled, QDockWidget QTabBar QToolButton::right-arrow:enabled { image: url(":/qss_icons/light/rc/arrow_right.png"); } QTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::right-arrow:disabled { image: url(":/qss_icons/light/rc/arrow_right_disabled.png"); } /* QDockWiget ------------------------------------------------------------- --------------------------------------------------------------------------- */ QDockWidget { outline: 1px solid #C0C4C8; background-color: #FAFAFA; border: 1px solid #C0C4C8; border-radius: 4px; titlebar-close-icon: url(":/qss_icons/light/rc/transparent.png"); titlebar-normal-icon: url(":/qss_icons/light/rc/transparent.png"); } QDockWidget::title { /* Better size for title bar */ padding: 3px; spacing: 4px; border: none; background-color: #C0C4C8; } QDockWidget::close-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/light/rc/window_close.png"); } QDockWidget::close-button:hover { image: url(":/qss_icons/light/rc/window_close_focus.png"); } QDockWidget::close-button:pressed { image: url(":/qss_icons/light/rc/window_close_pressed.png"); } QDockWidget::float-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/light/rc/window_undock.png"); } QDockWidget::float-button:hover { image: url(":/qss_icons/light/rc/window_undock_focus.png"); } QDockWidget::float-button:pressed { image: url(":/qss_icons/light/rc/window_undock_pressed.png"); } /* QTreeView QListView QTableView ----------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview --------------------------------------------------------------------------- */ QTreeView:branch:selected, QTreeView:branch:hover { background: url(":/qss_icons/light/rc/transparent.png"); } QTreeView:branch:has-siblings:!adjoins-item { border-image: url(":/qss_icons/light/rc/branch_line.png") 0; } QTreeView:branch:has-siblings:adjoins-item { border-image: url(":/qss_icons/light/rc/branch_more.png") 0; } QTreeView:branch:!has-children:!has-siblings:adjoins-item { border-image: url(":/qss_icons/light/rc/branch_end.png") 0; } QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { border-image: none; image: url(":/qss_icons/light/rc/branch_closed.png"); } QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { border-image: none; image: url(":/qss_icons/light/rc/branch_open.png"); } QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { image: url(":/qss_icons/light/rc/branch_closed_focus.png"); } QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { image: url(":/qss_icons/light/rc/branch_open_focus.png"); } QTreeView::indicator:checked, QListView::indicator:checked, QTableView::indicator:checked, QColumnView::indicator:checked { image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, QListView::indicator:checked:hover, QListView::indicator:checked:focus, QListView::indicator:checked:pressed, QTableView::indicator:checked:hover, QTableView::indicator:checked:focus, QTableView::indicator:checked:pressed, QColumnView::indicator:checked:hover, QColumnView::indicator:checked:focus, QColumnView::indicator:checked:pressed { image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QTreeView::indicator:unchecked, QListView::indicator:unchecked, QTableView::indicator:unchecked, QColumnView::indicator:unchecked { image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, QListView::indicator:unchecked:hover, QListView::indicator:unchecked:focus, QListView::indicator:unchecked:pressed, QTableView::indicator:unchecked:hover, QTableView::indicator:unchecked:focus, QTableView::indicator:unchecked:pressed, QColumnView::indicator:unchecked:hover, QColumnView::indicator:unchecked:focus, QColumnView::indicator:unchecked:pressed { image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QTreeView::indicator:indeterminate, QListView::indicator:indeterminate, QTableView::indicator:indeterminate, QColumnView::indicator:indeterminate { image: url(":/qss_icons/light/rc/checkbox_indeterminate.png"); } QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, QListView::indicator:indeterminate:hover, QListView::indicator:indeterminate:focus, QListView::indicator:indeterminate:pressed, QTableView::indicator:indeterminate:hover, QTableView::indicator:indeterminate:focus, QTableView::indicator:indeterminate:pressed, QColumnView::indicator:indeterminate:hover, QColumnView::indicator:indeterminate:focus, QColumnView::indicator:indeterminate:pressed { image: url(":/qss_icons/light/rc/checkbox_indeterminate_focus.png"); } QTreeView, QListView, QTableView, QColumnView { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; gridline-color: #C0C4C8; border-radius: 4px; } QTreeView:disabled, QListView:disabled, QTableView:disabled, QColumnView:disabled { background-color: #FAFAFA; color: #9DA9B5; } QTreeView:selected, QListView:selected, QTableView:selected, QColumnView:selected { background-color: #9FCBFF; color: #C0C4C8; } QTreeView:focus, QListView:focus, QTableView:focus, QColumnView:focus { border: 1px solid #73C7FF; } QTreeView::item:pressed, QListView::item:pressed, QTableView::item:pressed, QColumnView::item:pressed { background-color: #9FCBFF; } QTreeView::item:selected:active, QListView::item:selected:active, QTableView::item:selected:active, QColumnView::item:selected:active { background-color: #9FCBFF; } QTreeView::item:selected:!active, QListView::item:selected:!active, QTableView::item:selected:!active, QColumnView::item:selected:!active { color: #19232D; background-color: #D2D5D8; } QTreeView::item:!selected:hover, QListView::item:!selected:hover, QTableView::item:!selected:hover, QColumnView::item:!selected:hover { outline: 0; color: #19232D; background-color: #D2D5D8; } QTableCornerButton::section { background-color: #FAFAFA; border: 1px transparent #C0C4C8; border-radius: 0px; } /* QHeaderView ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview --------------------------------------------------------------------------- */ QHeaderView { background-color: #C0C4C8; border: 0px transparent #C0C4C8; padding: 0; margin: 0; border-radius: 0; } QHeaderView:disabled { background-color: #C0C4C8; border: 1px transparent #C0C4C8; } QHeaderView::section { background-color: #C0C4C8; color: #19232D; border-radius: 0; text-align: left; font-size: 13px; } QHeaderView::section::horizontal { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-left: 1px solid #FAFAFA; } QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { border-left: 1px solid #C0C4C8; } QHeaderView::section::horizontal:disabled { color: #9DA9B5; } QHeaderView::section::vertical { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-top: 1px solid #FAFAFA; } QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { border-top: 1px solid #C0C4C8; } QHeaderView::section::vertical:disabled { color: #9DA9B5; } QHeaderView::down-arrow { /* Those settings (border/width/height/background-color) solve bug */ /* transparent arrow background and size */ background-color: #C0C4C8; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/light/rc/arrow_down.png"); } QHeaderView::up-arrow { background-color: #C0C4C8; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/light/rc/arrow_up.png"); } /* QToolBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox --------------------------------------------------------------------------- */ QToolBox { padding: 0px; border: 0px; border: 1px solid #C0C4C8; } QToolBox:selected { padding: 0px; border: 2px solid #9FCBFF; } QToolBox::tab { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-top-left-radius: 4px; border-top-right-radius: 4px; } QToolBox::tab:disabled { color: #9DA9B5; } QToolBox::tab:selected { background-color: #ACB1B6; border-bottom: 2px solid #9FCBFF; } QToolBox::tab:selected:disabled { background-color: #C0C4C8; border-bottom: 2px solid #DAEDFF; } QToolBox::tab:!selected { background-color: #C0C4C8; border-bottom: 2px solid #C0C4C8; } QToolBox::tab:!selected:disabled { background-color: #FAFAFA; } QToolBox::tab:hover { border-color: #73C7FF; border-bottom: 2px solid #73C7FF; } QToolBox QScrollArea { padding: 0px; border: 0px; background-color: #FAFAFA; } /* QFrame ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe https://doc.qt.io/qt-5/qframe.html#-prop https://doc.qt.io/qt-5/qframe.html#details https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color --------------------------------------------------------------------------- */ /* (dot) .QFrame fix #141, #126, #123 */ .QFrame { border-radius: 4px; border: 1px solid #C0C4C8; /* No frame */ /* HLine */ /* HLine */ } .QFrame[frameShape="0"] { border-radius: 4px; border: 1px transparent #C0C4C8; } .QFrame[frameShape="4"] { max-height: 2px; border: none; background-color: #C0C4C8; } .QFrame[frameShape="5"] { max-width: 2px; border: none; background-color: #C0C4C8; } /* QSplitter -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter --------------------------------------------------------------------------- */ QSplitter { background-color: #C0C4C8; spacing: 0px; padding: 0px; margin: 0px; } QSplitter::handle { background-color: #C0C4C8; border: 0px solid #FAFAFA; spacing: 0px; padding: 1px; margin: 0px; } QSplitter::handle:hover { background-color: #788D9C; } QSplitter::handle:horizontal { width: 5px; image: url(":/qss_icons/light/rc/line_vertical.png"); } QSplitter::handle:vertical { height: 5px; image: url(":/qss_icons/light/rc/line_horizontal.png"); } /* QDateEdit, QDateTimeEdit ----------------------------------------------- --------------------------------------------------------------------------- */ QDateEdit, QDateTimeEdit { selection-background-color: #9FCBFF; border-style: solid; border: 1px solid #C0C4C8; border-radius: 4px; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; min-width: 10px; } QDateEdit:on, QDateTimeEdit:on { selection-background-color: #9FCBFF; } QDateEdit::drop-down, QDateTimeEdit::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #C0C4C8; } QDateEdit::down-arrow, QDateTimeEdit::down-arrow { image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus { image: url(":/qss_icons/light/rc/arrow_down.png"); } QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { background-color: #FAFAFA; border-radius: 4px; border: 1px solid #C0C4C8; selection-background-color: #9FCBFF; } /* QAbstractView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractView:hover { border: 1px solid #9FCBFF; color: #19232D; } QAbstractView:selected { background: #9FCBFF; color: #C0C4C8; } /* PlotWidget ------------------------------------------------------------- --------------------------------------------------------------------------- */ PlotWidget { /* Fix cut labels in plots #134 */ padding: 0px; } sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/main.scss000066400000000000000000000001771463772530400256030ustar00rootroot00000000000000/* Dark Style - QDarkStyleSheet ------------------------------------------ */ @import '_variables'; @import '../qss/_styles'; sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/000077500000000000000000000000001463772530400243615ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/.keep000066400000000000000000000000021463772530400252760ustar00rootroot00000000000000 sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_down.png000066400000000000000000000010501463772530400272440ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÚIDATX…í”=kQ†Ÿsg!BXq &Æ0Æ -lcc Hˆ•µ•µ?ÀÎ_`áP,,1XˆX¨•:,b& N²NvƒlÀÀ΋ùØe×MvÖ`šyàÂåιïûιw öI'“Ó ‡þ“íf͵+&]RÔôß°·tze“Òv8%ð¾£.½µÍyWÚ§zxžSGåèrû™fGôï+ ©ÏK•yÏsê=|ÛÞªŒDKŠ<ŽWÄÐqO† 3WôQe$¼áÛöVgÕ½#‚°Ù˜{Z Ž€\iw!w5q}ðÓ=w;Þ´º‹zÄ8Ú¬o¼(ž0 WAòº `@á^m¥zœèo…}Ä4¯Ë•£› ‰¨º‹¹I‚ÞYw«÷w*Þ1@ÂÿP_Y"»˜Ò'„š¤[!¢·jnõánú·vâôùE#ò8ª ]-ÍÌGª7ýÕêóAtsíäÌ…9"ž‰" ‘~-¿ˆd±öÍ~;¨fî«}|föRYËÀxÒ‰TÃ7&\Xûê|Ê£7Ô7~bzöLˆõ 8•,}·ç=×YÉ«5ôOæäÙËÇZ­ÖÂç’UºþãËÇõaµ ö•?åf©¬˜ÕIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_down@2x.png000066400000000000000000000017661463772530400276340ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœí˜Mh\UÇç%L°v"d ™I ’¤c“ÜØ ~´´ ~7®Ä…àÖE©*¥ÝTDÜ ŠàB°´]ˆ4 ꪶ‹Ìh33û1o Í$í MŒ™9.ÒÀäÍÍ8™yo2Òû[¾ÿ»çžÿ¹÷¾wï‹Åb±X,‹Åb±X,˃…xDG?ùPD;€2ˆnC^>¢8ªR=‘K'ŽWª†Œ­ŠÐѲüZˆ*¥\:ÞYùÌÙ®dÚCô$ð?ŸöFô¾· T-€èÐÞçç,öÄPr éù†: ^_}%—L\ô¾m,@lhìiÐAvy:hã"˜ÌëmÃn*~ÙÔbÓô ìVG'~oO@»Á¡ÚÏu)Ë¡ììÔt­F›’šôY„kIÖªÝ.hµyáš j™‡:þÙTâNhøu£"Ú¿Kí0¬ùK8¡ñl*qã¿Z×\•ì‡VCg^0È¥zãøˆ`@… «+¯ßžž.Ô¤î¼7?¿ydÇw%§k/0â‘[½ŒæAN‰›33÷ê ´¥)¼¸¸¸ZÜÿä÷á;Ë»žªNJÙ¤jjó*_ºéá·òùŸÿÙJ´F³•¾¡ÑSŠ5heÛH™Í+|’KÅßo¤ß†?b……¹ÉîžÞ%à G h ˜Í sSñã¦õÐÔW¼°0÷Kw$z x™Æ}^Fóe}'›J|ÑLd_2Œ î›@ô[ ä‘üØ0™68+¨¾é¦§›Œíßtí{Iá Âé‰"÷õEGåµ[é© Å܈¯ë5:°ÿqÊ?ÔHL#?¯Z>’Kÿv©Ñ½øþÁŠ=6:BY&Ýi+E0™¿‰£‡Ü™ÄÕfs¬$/vl`äQœÎóÀ㩞"˜Ìÿ–ºé߯û•ceg¾ãÎ^ý³ŒŒW<’PûÏÓAµù+*‚0¿žP`ôìÙÓÝ¥ž3ÈÞóƒ©0ÿ–¥WóÉä]ÿ³[#Ð=|>™¼ÛU*V8g×G{³Yq¶«T8¤yhÁ!&“É,çú#À×›ôoÚÝ}åöGÞÈd2ËAçôÉ¥'68ö)Â{5ßR>sÓñ£´èÆ©•Z\˜;ŽDW€oˆ~à¦ÑÂ[é–ßèóýîéͱv~XGwÝTâóVç³-WZÅ…¹Ë;{zw<Uäí\*þÍväb±X,‹Åb±X,‹ÅbyÐø‡h(×®²ƒÑIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_down_disabled.png000066400000000000000000000010351463772530400310760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÏIDATX…í”?kSQÆϵŠ âà¤à˜ÁÉèMÔ,ˆtýý‚ú Ä¥£ ‚£‡4$©I'…ŒR°¢…ZÄ‚-íyr›¤ÿÌ‹]î.¼Þ÷yÞsÎ{¤¤¤¤0Ú fªàÿÉv¹ÏŽDNí]°Ïö]^íàpÎõ®¬lìÇ']þﯭ Äq¼´º2zMfÀH’øwÚ>z»º2:ÇñRgŸÛh6›G—=ÜJ‚ÁC9 Ù‰¹yyrìØ½L&³Ö³ãÞ3™ÌÚâÂüm¬©V‘ü$„ºÌ5õýëüíæ­¼=°­r­ñxÐÚ‚í¾NB’ìö =¾šË>”´kmÏ•+õI‹'›}±u v#jëÊ“…Ü¥§m¶W3•ú]Ä3ààd.vYD÷‹¹‹/zi÷}·¥JcBò+à(¸s‰HäVøÛÖÍâåì›~t®rmîŠ^Ç‘,;XаüMòÙJ¿šOw©6w^ÓÀ) ·‘oVt½˜»ða½¡šÒìì9…èp&Yúì(ŒãøÓ ZC¿tÕjõô:#_€#¬ßÈçó Ãj¥¤¤¤(¹Ä«-@DX·IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_down_disabled@2x.png000066400000000000000000000020251463772530400314500ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÇIDATxœí˜Oh\U‡¿sgAt£;éZ]'3Ì_^*¡MA…JÁµ¢‚+Ѫ("b7)âZ…€n\Iµ]ˆXšÎ˜¤™í¶Ú©¸ˆÐ¨I3÷s1‰ÌÌ{™L’y“ÒÞoyÏ=ïwÏðx<Çãñx<ÇãñÜYX÷Bm~ñ=Iï93‹%éâff’Ð4³Âòèûòn…êlý&FnhÑ«óíK.m×íK2·DäÜ)Ãn»*&9w*¹žBu®gûºDâÁ‡7@ ‡y­Jz*ª”ªÉíÛ03[Ìßv©tkÁÌ!uç´‹#ã•âO©*½ìÍÌ-=ìhžuú1 Å·ÌçÂáHä£å˜üÄxðø/½T{R«ýpH¹ø;à‘NÅÖM8è´0''ÿ³5ÝD®õÒOy: ÃÂ55òàÇöu!ü\rÉ䵤F¾²SòÐG¢hd%ÏÍq`&EœÛñe‚J€Iò4GÑÈJ?Vú*@«j¬}Õ-‹[7a˜u0¡´ØÏü³ú×± Vû5Ôw¢(ZWcý„ÐtG4›¶Ì²/¦×íHhúß—OLNNÞØ•½½!Éjó‹SÀÉ”c2š K?yétß2Û}·¯«Î/¾4•0šÁµmòfoŽ•GOïÝî>¹8·ð‚aŸÐõsdÚ&ºvbÃ^ ƒÑéT¥~mïGy‹™ùúq'¾îîí«unõ7æH¾ñ†ž ƒÒ™½Ún÷1.Î. ÂRéJÓšeàjûº$ì§?”–<\Í‘/:yÈ ‡Ëå_ï²fãrûºÔš¶ë—bÈ%ÆY㲋7‚Jed9‹X3íÜêõúý7švNRØ!àhnÓ­¯}ê`U½'ÏÓÅbñzV1fr¶(‹×ãç:ÄäÌ03,NIÞà¬kG³L2.lÍkÇ…>ï´ž'%ûz೸±ölEëYÇ7´ N’«Í×?{µ÷Fû( 'Íl(»e~¶0³8,_{§Ç¶·Ã ðú°’‡áÎðÿS›[|Ièã¶%!^«?v,ógP]˜Âìy )㕨\üò bñx<Çãñx<ÇãñÜIüzÉ[Gy.fIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_down_focus.png000066400000000000000000000010131463772530400304420ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+½IDATX…í”ÍKTQÆÏ™>t“¶è:BÑ\Úö¸JˆZÙ. š™hþBú„.’‹Ò¦EK]$-[ز\9´)œ;` „0÷má½3ŠcwfÝÜ\8¼œó<Ï9ç=2222N%ƒBPû)< Sƒ_ÕòÐE·§ê]qü š^ÍÁ¹ÜÎUàcˆ€Æ±|Fk‚X½öX/oõ÷ÙM`e÷bÌa­+:Ân…Ì!x×ÞF׋Ã[¬Mä·ÏÖï˜é5„ƒ#…Ю†½:3P¿»6‘ßÞ?¡o,çÿç0Ç•š‡Ø¹y²Añ¼2à=áží&µÇLþB81ÕCˆ¦¹`f£ä=Ej»6õxý`sô,‰ùŸu«wL“•GÞlZÒT Aí¾àK ‘ôLÃăjièešvÇ æ›c ·@ß!!ó¿`ã•r~¹Ý®:ÜŸGp¶\@‡hûIc%ïC§š]?1?o€­’a–hÔ@·*eïS7z=½ñk aÁEö¸—¾EN£_‹^µ[­ž2×ë—£Fôøìrîö—‡—~ôª•‘‘‘qªü!‘Ê‹k*IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_down_focus@2x.png000066400000000000000000000017551463772530400310310ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ŸIDATxœí˜OhTWÆ¿sߤ›"Ò™üJ a¦íºÐUM±¢¥E\šøKAèÂþ R FŠkg’ˆÝtU¬v!¢vmuÛ:Z«Mt2í&ikм÷u¡sߙ̼7ñüàmî÷î¹ß9÷μ{/ (Š¢(Š¢(Š¢(Š¢<_ˆÝŸ®O†  è`|ʼn4„FÌ—%?}ÄW“+ÖVxm³×^‚òxOêÉÓ)'›…H„æ(ä™_öQš£Ñfƒ…;#FÌ9[ì ÂdƆA4¯%Jø^Åï»b¿ì, N×ß4 /xÙ’lÚ"¸’ÿ3³½ê§¯­ÕÁIÕO_3žyÛ’² ÿ;Ä™ü-㙡µ’‡£C„ÁSs¯˜ï" ¯[ÒfZ ŽäùK˜ ¶UG³öF:>•êhö¶0¦ð'K€Þú%Lzˆ$/W…ÁðzÉ#Úqm^›­o ‚ð¬ïXHÐhœØ ýíÜqÙóÁ±ôR#aþ-ßK/­tý»À÷öˆ<í[ ¤@$š»ð5Ÿö•¹Ì!‘¶\¶´÷:ƒ”üLísR¾r›‘/J~úX3‡šféÈ}N®P›€àäM„ð@Ùï-¶ÛKÇ.´rÅÚc Š|Tñ3ßuÊ‹¢(Š¢(Š¢(Š¢(Šò<ñ²#,;lŽgìIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_down_pressed.png000066400000000000000000000007741463772530400310050ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+®IDATX…í“1kQ…¿ó‚² ÚXX° (Ù˜ÒNI©±ˆÆl´Ï/Œ¿@lÒ¨‚…(VZ()Sv‰$2…TŠ4 3'ÅÎl‚›lf5Í|0ðxïÎ9çÎ}%%%%ÇŒ²EÔôwàôòýQ¿¬3aßf8¤ø_:ñý˜E @Äã±HRM Ÿâú3ßöæV\·x‹¸æÖaÒŽÓ#i¯Ñ•>nŽ_Ôæ^¯ºoósÀít«÷B$„ÔåUõ$÷F´½¿¤cî£Ú®®3&3Ó®QgÐ\æn™ËÌT×¹ó§y«ìlk¶É4âaZ™àœ_"3,×k<’tà»Gv5<…x’å¢5’n„LWbjbHO»gÍAÔô] *]Cˆ€ÛLLëåQÚ¹gûbÉ#JxœØ!²Î;pk²¦÷yt ]®Ù†¯X¼N!ŒÓ{ÿ$0R¯i!¯fáÛ5| øˆ8›†È460×ëÃZ.¢Wü÷ž-ùBÅÌcΧ*_bqõAMkEµz ðü³Ï…˜¯ˆ•$pãþ ¾õªURRRr¬ìoÉ“TniFÃIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_down_pressed@2x.png000066400000000000000000000017041463772530400313510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+vIDATxœí˜MˆE†Ÿ·Çx ‚ x= ™!ÍaT†€‘€–™]qAðÿ@B0‚ij »ÎæàI¢ñ ¢Dâ53#xŠäbb<ézÉŒ°»Øýå0+ÌT×8?Û=£¦žc}]UïûuWu}@ @ ; ¹ ·ì´Þ2(  ›…°Ìˆ±E¼]+êLءް¿ ÓS8=qµ¤»zÛ"÷¡ÿöëþg|ÞR ΢ÿaºžÎ¦›=l4­’{œIöê2%"í« <]+é²û°7õ–IøÚà~'ôïM‚ˆ°~O‚M"ªEµ|]|K€jQ­æ›î4Òà~3Ãcø%†ùAæ»Ý†°~Å’øxÔéÙýf½[tøÌÿdÆ‘¥²ÜØÇÐ7¹TÖÍqXÐì Â( OaÎùÆŽ8<Ì<Œ€•9mÆÛ<ñWÀlþóÊ¥d›'Wæ´9Ê #¯ååyµù“c&>ó„ ¦é} »sù´_hß˱åyµGk¬Í¬VÑÖ6'€57&#bI’yu¯íÿ™/?¢íñ†›3S½É*p*‰òªvÏõ©9á\mŽ×%=ïžÞX½a¯¬zB YŸª˜¼V-éÜäÃî‘õ¦=/ãCÜå”e%é7Ÿ^¨–”ZŽã õ†7ø¸Û eqjômw0ž«•uacg·i­]±§"ñ9°ß™Á°‰“2/è`õ’uDoŽ{heˆÊ¦½íg¨¬¹B8Í0í'ûÅ$*A8o¢toë.¢óÌÂÇQÒ´wî¶"ÏÇG ¼Ì¦&o lØVzû£u:Ÿæ„¬¼ÿ+Ÿ“dŒ²%…E¾ùìýïÆ/s‚ùü SüIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_left@2x.png000066400000000000000000000020711463772530400276050ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ëIDATxœí›Mh\UÇg2¤-E[u^l5‰DãÌH±n$ŠV‹X´‚®Š( ºAªXAp!¢7.,ꪴ*‚1™Qf’mÞDi?¢53ï¸ òî šâ½÷]uþËó‡{ÎýÝwÞ¼úꫯ¾þ*Ëû£ÑêjTª¶ Åò“¶Æ[¹T¡tÙ5Bîþ¬7‰µcçm âRQ±¼d’ÔbiÎÖøÖr¡h¤r ÂQà,ÃJlåvDÅñ ¦@¶t»¢¶ò¹ £;ÎE¦€m®s`ËØØFÑöÛÀ˜|Alv–µ-o*ùS+\k8ŠÅKÏT(¤ð͉CÀ­é°:<`¸T~V”»°‚8<ð.VSx´‡å|ò1€¨T¹Wá`«ã«†ÌŽ@T¬Þ¼Üí¨—•_S&†‹•ë=Ü_›]Þzä@aûåW* ËûäÁóP’£(g¦ÿ+¿&o¢í—^„LçVf“OÎ/Uσä=àÃJpØæ®GÎ‹WlÊ¡ï€\œvTÉxòàÀÖ­W1Äï“ÀÃòÒå­GîLLäÛ~~áê´á¾¿?¹ºrÑ×'^öñ`V~M.v€DÅÊsÀF<¨•_“uQ©ú8ÂÃ=¬à&–DÅò} O¥£ _nNWÖF+y©Û ëÌ›² Ç@£ów²yzló çX ¢Ò5c â'·¿’µ[õ¹7Ux ‡eå#¦+Y]¡V½ö¢*û{XÁB°¾E[ µ /øÈeC.ŠÒV£öÂkF\åûGrUPo¼Kà-#.6¿íÛ»b¦§WueðvÐÒ†Ái!q<½²¡“¿a&íH0ÇÁyÍæg?´Û†% ™ÿ’—Uø®9ßêäåz…¥´#¹¬!xÛ†Ë_Ì.*rð}ÚÉ‚×s¸Ü˜Ë 7+i';Þ/¢ãõÚÇHn¯ÀjÚÉB&7q\Ÿyt½_ž¼BÈìQ´Ô˜{¸¿ÛñÛ#dú,޵Cˆ<‘Ž x|yʼ‰ë³Ï <ßÃòR[æj¯q/Ýb’xÛæ{&¸s¡€cÇÚCŸî>4§Â4›ÍßNɯ{€O ËÙ£1('ëõd7ð¥|ÁXnÌ~KÒÞw+Hñâç_©tv!œìvíµÌÁhÕç絓Ûò‹aý?þe µ8ó‰À-¤Þì}o ÀÒBí}¨ÒQ¥òk ¯± IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_left_disabled.png000066400000000000000000000011001463772530400310520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+òIDATX…å—¿kSQÇ?ß©JÅ_ ‚âèЩ©i*BJ‡8)¸¹ýÄAÜE;™Á¥tHEÚ´ö;©dDAê¢ÅR ä‡W\ûî»— z¶ ïœïçžïá\üï¡ØÓ4=Ü·Ò{V?7zh»ïwÅo·ß ÷ÝæØË™“ÄïõzC»‡7ŸŸ¼(­V«ôõÛÇÀ¤on0€™éØñ“WÌáv`)}uÇÐ ‡‘×þp€…Ýi3nýÇO<`q¹{Up@È™ç̓—_N!Hr†/ÐYYGj%ÀÌŠ‹{,¬¬ž1s³À2¿½&> Óéž’¹6°Er®âçizÂÏ€£sA}÷(¹äI{.ší"¯o­ÎÇ\ƒÄ]>€$1ßð\ªÕÏ0 ¬ÈP´W4w¡z½òΔ4€u0 «Èù±‘×R2üÌ Â3ïõ±‘%ÌšÀ¤ ‘(tƒ‰ÚÙYŒëf–Q¸…µÊŒŒi2ŠŠAyX¯UîKÜÍN–±#xˆÆ«£·1=pοÁ’líËÇ›O$¶ìØA€f³98rpß5`Þ÷W'ÚF+—Ëý_{/Ý¿ÐhœÞJÜ%ÁºßcÖþwã7ØÅ¥þõ³!IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_left_disabled@2x.png000066400000000000000000000022231463772530400314330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+EIDATxœí›OˆEƯg6Ùƒ êEÔ“(ÞãîìÎf'5ÄàГˆ¢ QATˆˆ"ðâÁ žÂ‚F7ÆÎÎÎÌîJññ ˆÁ¸8;ýy˜ÕÔt0l°º»4ó¿ý^}õªÞ«®na„.dXÙl •}Hϧ’EâÆä >žûŸàD{968®3ñ¦;gêÏŽ|<$O$í•0§áÉòwÐ$Ýîu†Ž¹¼™¥¾|+ÀââÉ«,æK³6Iòå'HZ­Öe}[›®ÌÛW5oç‹v»½mê‡ÀµEø *’$_£z¨¹¼·”Ï"’$©ÚØøa`—ËHàmÓË"$™mÚrìN—73‘ãà!=`¡³ò2ð Ë™!)ßÁC°°¸ô ðt– >·¥ÿ7JàDgéa™fÐ/*†Òø´³|7²7Ï2X”{Ú»(E€dqé¦Hvý‹õ×c—·.@«Û0³#À&—7³Ôg‹»QZZ­åëÓ”£ÀV—7£”ÁCït®Nň43FÅ‹úTZ ‚ ("8™ˆNs“*¢¡0½|0‘ì“)˜°Ï>[3ÿãúá¬u¾};ëÌhª©¦6³$ëþ­º_[FõEEÔ.n{ÖÇuÿvgo0b>e¹^[È·ø¸¶ñq‘4Õ3º¸ÇˆgÕ` ê­î¨t¹Ú{Øê:b}åˆÀ®bõ åÌpi[}å‰@׳ÛZh@äò´sE çõÅó©Ë=!òEàª7§Ï©×íqQÙ“°¼Mù¤¢°wX[Ûjç¸Ñ1¼mzIÅ@UªóEàN'.(šÞÍC$ ¥…@p‚‚¢þŽ»³)s]¥…'žXc(6Å¥ÿ2Ð]šëôH«ª†ÖP‰’*”æïVu£ `C¶(™Ì€Biî&àØšü*$ýy¿JÁtÍ^rhOXvùÈ ª ºFg¯QkNç%,Kˆ¯‚Ø9vòJ1f¸Ø14»›‡@›àî£s9cåc 3ae2íW+õ°«xêBcäC °” G~E©ØñÒO[ZLmáÚ„•êóýz”€½ÃÚºekû;(×'¬hnÒ0¬¦ºca 8àÄSîì6"ÿT¥»sáE”ûx€În#ò PšJá1'¨JŒ7žÁBi~8ìUA$Xs³^y›…ÒÜàh+Ê‘_‘Ç%x¡ j‘°ÍÍzå €H¸Þ§¼°*|²1±ÿúè @e ÷žˆ<´ÆPm‰‚×c°ÜŸ{UaØÊß"•÷ç€Jîè+nT@²ÛHþ‹ÑÉjþQàm'®HtÒ)hDìšë}ß5TR˹A¥VÌ׃RûCë÷_$,‰i9¤ZÈì`çR­­ývà[ÇP¢™ ©1Ó{ÑoµšÜ L%,Éü€ 2 3ææŒèÍÀI×QCÆj›†?ôwL[£·úkƒ2ƒtNõu|g­Ü,­©C³|#ª å¿T¸ ¨9†`–É Êd'® ä?ÑûXûZÜ a!dv•û;ÞE9èF×”éY<9˜/ŠèÓNPÂ6O™?Œ”ûòÏ ¼ìe¥yJ5d-Ws#¼åÄÁã7ÁgSöFÄvþœëÆNê}C€ÏFäL­mé^ÐÏ#å¾!3½;Oëé¶À7 +µÍ *•‡/ùÝÖu¿B9D¾èLìX¨›ú> šv®(L÷]ö£Z»8ÕÀö¶$¢PÚþ½»øÓu6É_fÊ}Û¿½Ãý–hüefµ&:>å u…:bŸËº¦¦šjêÿ¡¿êj3¬°ñ¶IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_left_pressed.png000066400000000000000000000010211463772530400307520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÃIDATX…å–¿kTA…¿³Ï5 h‘Æ*… Í.ÁÂ2‚’&ŦJâëlùÄBÒ‹ ØÏÄÊ-l‚…±³a·IBº€¤ÐÆÎÀ¢‰y{,6[ûæÍ  ·š¹÷|sïü¸ð¿›R|¹å«ÙŸçM]ùÝús)Å×w=Qó¸\Õ§‘J¼³ïñò„·ˆé¿$޳þwÖæ `[ý)žóƒ? °Öã ððl:€°D=¯X<@ (Pô¼<‰ãpñÚE׳@+^ àU×w # Pt}Ëb8ϰÞA'>  Øöuà=pIJ#^`mË×Èø€˜ØN#ÿ‚ÁŸGc'ÚùȪ–`/¥h0@ã'÷‡JøUXº­/œ2ƒùj”¢r |ZÀ]àÈF©2$oiGføáa7 àAK1m „âÚºZ;È[ÚrLýeíæM½Æ¬Àðf¸f&¢j˜·ôLf@®}ˆ–š<–yÔ*G4€$_¯hŒÏzÀë9„¸%²nÑË+ ¶µa2÷¤}¡¸ÎC$vxh¥= »àÎCÚ?<÷‹œöiU  =ç˜}iÏ€ [V•8xÜ÷!ÞL{î­õIaKþyTI)<9ç[ ‡È €z%n™ý/L÷PMÓ¾+è<” àÀ¾>£ÀÚ´oH°¾_J°ÞWi€àâ´o‘¨‚‘_R)Þ:áËê a.ÏTÝÈ/©p_´¸À˜kr!‡<ÖþS àðg¾pÐL 6æB…—¸+UaÆg=pz ï7gЧóP€q»¶a-ûÛ2aJ*qWªàlëê¯ FÒ¾"ì<P NuxÖðdÆto¯ÝVíŽ1ì͘½ÓMi‡›Õ*€öœ÷aÞXø »…›Ê~ЀêêûÕ(ä+°|šGÝõž‚yœ\—5E~û Àè Ëû6õ˜¯`ƒî£M½.3ž÷c†¼i²x-í «ÿ{>OJ’O5xñvÚÿëz;:…$´[J` x/ŠBaÉìjèÜ‚¸_p,Š B¡‰ìj謸 q"ŠBáIŒmÔo$Ü|— U¿7”2 cCú©žpðc&`jUC(mnߤ“]¸ók&ÐÛ+ƒPê{¸£©¯kæNàì²<*š ¥/D#›ô¹kÜ œË*z*Y‰[7éC›‡Èžœ”ÿ:T¶µ†ô®áÑ´'±´&”¦J÷âVSÀs³!ÈÏ`W¢Ê‹‘Ñ/ ^͘©œÜ* É'<…™Jû6 ù›à¿Så wx:u††é´_Æ 2 »‡µ¨Ó<|š ©È×!cÃúcM—mÀ|Ú_úŸ@Š Àƒ›õ{}­À·e´€í7èçn-ˆŠn+J;nÔ÷^d ð˲`À’9Z­Íú¦[3™@Àj1j#MÍ%ænR?™yÓ=€‡‡ô±`½ë·®Ä‹UçÔW_}ý7ô'-ÙR¾OTIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_right.png000066400000000000000000000010241463772530400274130ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÆIDATX…íÖ±kÔ`Çñï“+T\ŽX½;Butp”.u*ÅEÐÕAúˆˆÿ€(8‹8âvˆÅÑÁY#B{Wð¼rK¥CÁ“Ëû8$isIx3è3¿ïóû¼ïóÿzI‘E~'ü©¨x“¤=Æ{uœbËô”ÀÉéœÛk…á|€´®9æmÇdŒå½‰÷ÖÜjô–ßýúŒ‚o¨F€(¨¦¹çw.?² ÈP€~;\· @ALæyâwoÛdR„Ê‹V{qÅ6 C¨®#òÆ¿^· …Çq´·p1X² ÒQ(pÂ÷ýÙNе øÑJp?œ»tõŒm@Ž8?M¦ïš•r¥ @ÞoÇó¼…"¼šÃ»$7¾ÛÙäáûŽ1ËÃA¼5ËÆŠ¥yø/ŒÜü1øòy–ÝUo@@HŒêÚx°ùqÖn@åp¿èÝq?ê•éRp.èúîVôªdŸ2€üäðx´=-3¿ôäªÏGýèa•ð€4\Ñ×»ýè>ÙoQ•*3‚ÓsæGß}{…OfÞYãøwáPp û€x“de¸Ôþ¿þ+ƒŽi‰ZP IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_right@2x.png000066400000000000000000000021131463772530400277650ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ýIDATxœí›_hWÆ¿3‘M[IA íÎJh²;š »+hékEªEÁVBA-|j)‚}PAK¡-ô-ôAZôÉJQ‰>(HKM6 :YƒµîDÐ`UL›ÌTÔ¹7˜Å{Ï\ao;„û}÷›sÏÜ;›Z´hÑÂùby·_ªNùAu2_,ïÊÚÏL!Sù¥J À{ð‘™xyÖLo ïé2Søñ±ˆ˜Žø¥ÊRsãÛÁ`HRŸ;>^è©öÔ0ŽÁˆ5×:Ùã…R¹ËœŽYLVÀtt1Q¿¿pi§€VÓH0^Güÿ±ÎÞÞ½&°@zI¼‘›Ê‚ Ý¢fÓØ A*–ßá—~Ʋe³,ê6…í%œªîó/ßø÷ Ï‚@ ¥@¼9_ªì·¯ýtdš ºGÛ ¥Êv!ýi‘ âô>+Õ-‚$ÀJ%0ów~±Ü'ëãÂkBð@ôK¡Xy[ÖËCqqˆ¡ö„‡ó=‹ß”v“Aî?ž 0›¼ä¨¿ ¼HÒHVº€yHè„ß³è5)Yºž0Þ¬þWKÕW$ d4Æô¹a¡>67^¶­î@€v·,içtww¿`SÙ‘hOÞšhë8hóðäR€&Þõÿ¾þ,yu-@_ ýbåsX8Aº 9<ð±Tw˜r5ˆ•B`Þç—*šq9@W À7ù ú¾)ÇОˆ˜¿2¥àx€¾ï±±Çâs€ê‘‰~45¸3og§¡-}‰¶Eáàצ®V'ì49yÀÙØS×>} í5­äâðzröŒúàGPwˆ&Ä\‚=¤n=ýÖ˜“Ûýžà™q¨X½óÀIobö:„§&m©:€fò„³InÍø•Swm*»¥'Ï@˜ÄüÎø¥?nÚϸ0¥=0pqÛŠk—jc2 €  ´þ8È[þ5*å"«ÔÉ3î$D«£ðì°¤‘ PËž€IxÜ7ž–v#ܵeÏ ñ†(¬õËz¹ô—£:½­QX;$ëã’(‡Úú^Ѓ‚ÔPƒf|Ñ©eþo2 Ùß?5êCŸÀÂá¦Yl ÛßÿzµkÞp`ò€Ý% Üyíñ­õš²¨Û6HOþÏÿèî{ÑÑ ‹šM#õ¸€VÝÃ…ôfŒÄSà 8^1V?wM@«iLþbD÷ÿ:<^Ù¨Ÿ»lNÇ,&+ æmædUtqø¼A ã˜üÅÈãïìØcZՇϘß&›à>fÄ̈‰°çŸúàïÇnÑ¢E +ÜéØälIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_right_disabled.png000066400000000000000000000010661463772530400312500ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+èIDATX…íÖ=kQàsnÖMðA‰ Ár!vcfG²+„m’*Á´)B~ˆøDÁZÄBVìq±X—Y»À–VB~„Üc1³YË™ÙáZèÛÌ÷½ï3g.Ãÿz1É¢VØÝÁQÏø¾ÿ5O€I²HÐyHç­©7ÛãÎÔÜØ™_¯{½Þèß@Du÷Û÷çµZmÄ9€€)·/MN=‘”è å HŠ4Zkuºœú6¾¿×jom¸@‚HÚHƒGÍÎÖ§€¡…gÍvwÑ) (#¤^½»7b† c€êÍÎÇëŽ'q–²o›››×\ÀA—iÍ»0 ¯8DØønú…7NÈÉÇqÖ) kâë玮&é+ähÀŽŒ]üàK’¾¼ˆ† ûV¬V|ÿSÒÆ<0ˆÞÀÈ¥[·¶9s‘d<üXâJ9ðÚi÷ÈœAJ2 bµxõ,ûdJ€…h8¨J鯋,ûd¤}Ë¥¹ÇY‡gÖöŸOçKÞýa†§2$áå¼ï­Ga W©!Ph\¼0q·ÿ32l¥=~ž^.‹‡y ’& ì“à)cËÕÙy ÿ_ðl ¢BtI]ºIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_right_disabled@2x.png000066400000000000000000000022001463772530400316110ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+2IDATxœíšMˆ[U†ß÷ޤƟv¡Åwþl5$7$c&C§RÁ‚à ])RPD[P þ¡àB]Õ"S™ÒÞ‰“4™©.D""(ˆX,£dr_“‘ñž[™ØsN.˜g‘Å œ÷;ïýÎ9ßwï¦L™ò†¶Š»«Ï"IžH<Ò¬WŸ³5¶K¬°Üé£A•Hs­™Ú²­ñ]¸KI?½Ò¿ÙâøN°fÉ$uiw@|zºsöz[.°f€$e\Þ`x²Ý^ÛgKÇ66—À…ا0YŠãÏ÷zÐÀ ,nœèt:»=éí‡0½$Ê([\\¼Äæø84@ ´ s—í¹òý8Ž îtÇÃõHH#P,½!ÉZ r185@$$H™@ðÁv§ÿ‚Kíâa ¥k€<¼Ü]=ì^ÿßñu ÀÐØ¤ãNï!1ø4 “´ ßlwz ^ãØ†_‘A’ʃ@àñJo¿×X¶Ä} jsûOï »HûìÌ™Šïx¼0B0›§Ë“$Xl÷z7ú dR’H#®Ò'Ou»×ú cr Œ6úšPáR·Û½ÚG 5ø»NW‹× žè÷û{\ëOÜ `ö ÂMy<Žã’Kí\0J„ü§ ’š,^ú¡Ëæ)l!!¹î@±ô¶$'±æÊÍL x»³ö’‹2h” é< owמ´-—?¶04Ÿ²êh»³úˆ]™¼¢ÌGíôzÜíßmK&¿€$À0^µ%‘o€ôä-¬‹¹6€™1Š|Ç–FnžÎf! 4Î=áP«Q}Í–F.3`4é0ã¯gfg"k“rhÀæäiÆ%¼Ò¬WØÖË Á¨øÞk6ªe¼c¸hrf£Ü¥>¹¢Tx «&°A. Í8€yçWvQ÷”Ëå+í\œÚ¼éÉ9(nŸ-—×]jO<Hæä¿Ý(àÖùrù7×ú5€$3úüj~ýä#†‰-Y“ÿ5Ap`®VùÎW“É’2KÜón›kT¾òŠw.ö ­FÔ÷ï—£”¤v<º¯Y–¼Æ2ÂóËÑ$«Ä}´Ù¨}ä5Žmø4 Ìø2÷©Ù™è-1x0€ 3tÄ—›õêÄ?“qz ró'Œ[ÿn³QyÂEs3.®3Àhn|¬ÁúÃy˜<àöCÉ@æ¢_Në÷¶Z­ wºãáp ¤ÛZ|Q qgÔhýáNs||ß1<EÑ9Oz;Æ}/ ü¢0_oD?;×úX3`Tâ¦/ÿ‚ÌÔÊßÛÒ±52êûßÁà`³VùÚ–† ìíÛ>x"¨$ îš­WÎZßö â(€!„¡=?wK唵±§L™2ÅÍSž"sßIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_right_focus.png000066400000000000000000000010361463772530400306150ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÐIDATX…í–¿kQ…¿;k–ˆ i2% º£ ¢¶)%M¬DmDwýQHþñ‹M )$b·ˆbia­HŠÝl”͆-İ’w,f²l93;< =ðºwïùÞáòÞƒ]–eS­ošÉ&lpx½>û£L€ Ë&CSˆ}¿Um\éíñ0”8ókË^_ûTý[óƒÍp…5Uü€Ã™.Eýø1R¦*À.ÍAÜŽ–ãû~v À@Üš½E¿‰„Ì¥DkK—}Œ$&žEÍÞ‚_€DJWìÅÑ¥xÎ7$)˜”ÔŠšñiߣ{A¯,Ç5ß D23ÓÛcO¿ð @rKàÛv¯üÀèûzÊ?€¤_‚Jp0KÉ®í„.°³ëÓß²•ež½oŽùÏõ°›µ°ŒvÌ·Ìì\ûVø!oñ8²tmƒ.´Ỽ ÆIÀH ãZ·±¿U¤IцæÈ»™Õ‚} hÄÜxй>*jž@¦ ñæI§ÞÇòÎÀð¢±çí¯Ów0“_€Do&¦â«ÜݸæÿSú~÷¤Î¯_<1(ò'З°j0XøxeögYæÿð+0SÀã§IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_right_focus@2x.png000066400000000000000000000021611463772530400311670ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+#IDATxœí›_hUÆ¿3cÚ¢¤¶Ùݸ-ÙÝÔW_•b+üCñAµ³m )(b ¶ >D°n6QDѧZÄJŠðE¤²;5E’˜Ý¥ˆRm5;÷óaSmfFÍÚ{ïÞâþÞvXîwη÷Ï93³@Ÿ>}þψ®J•Ö‹õ¼@‘#µ`hBר&Ñf@aª à­~$Eí ƒá9]ã›Âû÷¯¬/K„Þ‰‘jë6]ã›B›€¨Ø…AêÓљ֨> ýh4L¹¶Uµ£S#o-nÓ¨£¤#²Íkû³¥ÊâVãZÿód‡òü“£3­A;zëǤk–„Pn"u¼0YßhP³kL  1€²qó{wæ5u»Âì`ÒÆ–ò­7Aj«A®ó{E!¶>Y¬6_6®½,l‚€x‡Š•Æ!óúÿŒ¥S%®^)U–÷ZŒ!MRÅë%ŠTŠÕƘÕ8.î"\ÝÖÆ@¼_œZ¾Ûj,ŠÛF@0±'läxiú‡;l‡cß«GcÜ„ëHï“bu雡ôƀə@lýSÛ§—n²D/ ø»å÷•?;rl9c#„Þ\Zñ’¹äùr²0yn³iùÞÐ!Q-¸U6­œ¸ùíùM&…]1 1äΕk?0Ù<¹d¦Í„ûolNã0Äê˜RÚhòÍWMt.Ði£ï¢1^šn<«[ÊM@$Š›@ÊÑb¥±O§Œ»€ ѤKÂm:§B¼P|]—‚ã¤CBÛ±x )1rF×èÎÜM H?þü–ÀSa9÷†.wg@Jò ^ËYmÉîà%’NÖË™#„Cà!–½ïÖ²OCâ½Â•ãÚà‰ŸþãA =‰Ä½D-¸c€¤%Ï/œÿíáú¸¬˜’uÅ€´ä¿Ž8pßÂxö‚Ia $ßU Û‚{æË×ÿdZ¼×› ¤Ä°äGj×|mØ —$’ðGBíþöÀðY[Aôj ¤ýò¿(Á½a0üÍ@ìϦ&¿Bb, r_ØÇò  t 5{ y4Ü—™µKˤtvÂýaýÐnas øñ y®ä¦,ÆÀ‚r©¾_×jÁPÏ_“±ð¢$Óª¼wÂ óŒ‰æ¦[ÌRß ðQ~1¸<`Ö€´Înî÷_™›¶AÝ®0i@|ÚÅ‹þgß~Ñ f×X9 ÔqÏ™ƒ[~¶¡× 6ŽÁÅö®3rM Z]£s$\ ÎÑîïÊùï5êhEã H<¾>/T{êÁ §õièÇÌ_fÅkåá/õo}ˆ:J ¢ â¥ÚþÜgÚÆîÓ§OCü›°8Ýê‚oVIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_right_pressed.png000066400000000000000000000010211463772530400311350ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÃIDATX…íÖ½kAÆñï3ë+µbÄRP<¯P°”4±µ½˜4’¿@$øˆ‚•æBH!'éQ,-„ ',-R 6JŠøn‹]ÏNn7Ë\¡¿jæ7Ïggg–…½4Ê öº¿ìp|þ¼>× #Ž;{é®lxbç?Xë¼÷¾±0 ¦·¿±Òé8Kp J¸öuŠG¶GÚCµd1XÜ^^g1)@`±¸¹Ûîy!)c4DéûDjx¸G3óúé;O¦ä ÌTˆ¼ÿ¹85@€ØŒÇ’$ùÿŧ¸8wFS‚€­™žoèè{ê'òï.Í5µQ¶¹z á®Ì6ô¦ìÕB8ï·iÝj¨[ešª¯`.±0ÛÔjÅy*­€†}æ~ë¬V / 0È¿{ÄãV“{» / ÀŇžm6¸#Éo¨ æÕÄAn.Jq·á¥†·Ù~._=©Ÿu„ȧÀbKFq‡™Mm×þ¿~ÁQQ=†ÈfIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_right_pressed@2x.png000066400000000000000000000021121463772530400315110ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+üIDATxœí›Oh\EÇ?ß·šŠm¼X¼H1§ª§‚›,Ú‹´ØJ­)B|«– ž)(b ¶ *¨•fKiÑS-b%EZÐCÉn =ˆ ªˆ  þ«¨Í¾ýyHKͼHÒ™yÜÏñæû›oæÍÌÎBŸ>}þÏÈWCSm{ãE ³„½Íº&|µoZmË €„™±¹9¢Ó¾ÚEâ«!ý§-3Ÿ>ku_í‡Â›DÏy2HO&Ûv»·Œø`Xþk8ÙšµuÞr<ãOÀ⬓˜9бµ²–M w¬2NL~nƒ‘ò–L8Z8$ †“ŽíÿÚVË\á=pæ±yðWŽì9e×Ë]&¡‡@O®ZÃ;fæm r-ŸŒ‚7ž˜êðjèì¥kt×vO·mw¤üE‰%A澯µ:öd¬Šˆ&À hµˆŒS³6«—h4¿Zt%$ˆ£“³v_ÌZ®†Ç§HÂ@"޽׶FìbÊ`Ãau>>tÖîŒYHYÀ0ËK¸93N¨ÒàÞX1>»±ËŽt£æB†–ŽŠ:/Î_JxpÇFý2»|BFnÌÓírÿ®aý:¾\BX®†¬Ë–wëÇ%”6Hnç_[Ó{t!V¥0tþ¤Æi]_Ĭ¥ EŸ“Më:»˜¨s€,ßy“1–k&f-Wˆùó8@"çTOÆSiCĪÃ%æÏã5÷Dӌ҆ÞUCQH…9o4GÊ¿&|TÁú1Öy.Äæf¹„~w•|xávV¡óö¢d~}§¹È£›Ô –»L ÷µ‡s×glÛ¤¿ƒe®€X ¡¯jlÛ ß#å-™“à÷[Æ7è§ÐY+ÁŸ¹×£ø9IØ:^×wÞr<ãó Ú\ÄØ6^×—Þ2àó+põÌNÆÃ͆ÚÛ‚Ïÿ í2 ¼’6ô©·¶ûôéÓ'ÿ "óv~«QIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_up.png000066400000000000000000000010211463772530400267170ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÃIDATX…í•ÏkA€¿7›D(šþ‚¦›”Ò¤©‡mÒ¼Y ^‹=‰ ‚ààÍ?À›wožz«Š´·@z‚‚'¥ÁС¥¨ÉÌxÈDVkº¡ö²ìagß¼÷ÍÛabbbb®‰:qîf%§y‹¥’H$r_>ø%ŠT¼°º¤µ©a©t»Ý½¹Å ø_rKÁª]Bà ¯–Ë/W.UÀϯ¬ãU°Ðî±@Æ(Uõó+ë—")”6QvH÷ Š }6Nbewg ¥»Ãæõ† ò‹¥G‚¼R®fém꤈<¸1™Ù?i·>,],=y ¨^ÛePñ„…p/=5stÜn½* Ùbù™Ež»wbÿ%Šôô¬V/* ²…ò O]gûÿø‚Xî\ŸÊLŸ´[;ƒrœ9ˆ‚ Hµx[ÀC7±øïüý¾ÝœH=¦^ïüUÀ÷o1öó5°áV0dÛÏÃí‰ï8MÝo6ë§gæçË“$o€Ûnh”•Ÿ#!{×´Úl4>~HôC:I€ñЬHÇô`¶kß=Ý&þ(b£ßK# ÅÄÄÄ\1¿vR~Ì*[Ü6IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_up@2x.png000066400000000000000000000017461463772530400273070ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+˜IDATxœí™KhQ†ÿ“„ÖG0©ÍL´3Ѷ: ˆºR4*ЏP[pãÆ…¸—âJq%ˆ+7*ЏSW-ˆZPãÆ¨(•>ª±˜Eâ«´s]$ÕdæÖ¤“™´êù ɹÿüÜ{ç\0 Ã0 Ã0 Ã0 Ã0ÿ4S«šÞK ³ð8?2üüèLèðÎĤª–8Ð%~!å]áóÇ'ÍÖÒt"±ÄNúúv‚áo…|.ÝL=Í4€"Zò” ûC›­`ÇüB>w«Y¢šc@*åS|m¬Ý˜ÖùCáÎbrE?²YÃmi®‚ÑhtÎoÛU»­Qa”%x$]¯·Nöf³ÙïnêsÕ€`<hónb“$dž~rNÝo\1@­XòÞÐe µöµG¢kˆ ¶¾~ñÆ)•“9ŠºLïyÓ°—<Êm„é·.J«ÑD·+qÔ%¶r- º`±)Toò“€0›Ð /î«1}MC"M8fÀ¢Xr ‘ç€)4ÝäËÌ„ˆÃZr³=•V1@é}‰~”ÊÚJl&?‰Ô¿b@Õô^ûãþ¦áB(×÷t€¯:" €ÌâmðkŒÊƒÑ ОÀ‚Ž·…|îi#£7d€¢%8Ë©íTòUc ÊyD»üÁŽ/Å|îÝQí@Š–8IÀqkÈä’Ç@ mþPxnñsî¶Q§o@*åS=sD8d º•ü$dùR~XßìXTÌoì^NkþiB¥º>p}Ö¨ÛÉWÍEIpº6Ÿ¾îÍd2?ê©nÚ»ºÚZÆ[nÀô (Ö–âÅeä&àö¸o¬·ÞûC]¨ËW·cbl€¬™ª®o²müÞ–#¯Öê\Ó€ˆ¦w ¢›0—¡ ¾ãEvxå!Úö.óìm­ŽS¢FÝ”žåÉòÒ¹Ç"Yš4ßIª˜r¨1} µ›B³-ùJ$+AŒ´}døùã©:XP´•›@4ø—%Ho’Ô`P‰ë)YË¢h‰£º UÒžP2m6d«º•@ûüÁ°QÌçBՒ〘‘ÿ ܇&F†ŸUÝY¬ïQËYòï ËÍbN`vïs»å܆a†a†a†a˜ÿšŸæ6÷ì‡Ñq(IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_up_disabled.png000066400000000000000000000010221463772530400305470ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÄIDATX…픿jQÆgvÜ,Œ6Z¤I¡õ*L!f#¤SÚˆ‚ ê+è#|AÁÆBAff™™ÝÙr{­¬,‚ˆÙ½ŸÅÌÆÅì&:lb3\8pþ|¿{á\¨T©R¥ÿ,+Ûø¾ÓY®9ï-Ðô.·Z­ÏeæxešÚíÞ…šó  0ÄOÃNçü±„釋ª‘+ òÊ9/ÙŽ³æ‘DI¶frmà¬ÀFùAÀ9µ£$[;€0Î6@[À)0nœ3p`ÂXmm§Ùõ¹„iï¶™^ @ §‰|ËaÓ^·“î­¹Di÷¾‰g@­0p”»âujžGi÷^iI%½GȘ™;Ä|ÜéŠZm†q÷¡¤™ë>5!É‹ÒlÓàn^dNHÓjg63I^Þ¯'WW/?Ø;`0Ô¿|ÛyЏ™ÂIü“ùoL*^Ùx±¸àß ‚`w&@¿ß?¹ócø¸&åæPÎ|ÒCàFïþ ¾ïˆãøÌˆúLWŠŒ£äÍ÷EœºÝ…õõK_üqш1-íu©Ü7=M¬ìªÕ~NÃÄÌåª äŽÓ­R¥J•Ñ/{°%âú»UIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_up_disabled@2x.png000066400000000000000000000020151463772530400311240ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¿IDATxœí˜¿o›EÆŸçâD‰TX6ÊJ™IÛš$oQå©é¡Tü@ÅPE©âÇŒTµ 1€ –"‘³ã7µ ¡ˆ HZû»ÂïĉóÚå>ãÝ}¿÷|Ÿ»÷|gÀãñx<Çãñx<Çóÿ‚Ú¸T©/ú€!qsîìôÕa芥Íêeˆ×˜‡m‚.ùçV­Åt’-åJõ Äñ¹ Þ,mÖß´žíIÜØ¬¿'àµ.Cߟ;{æ I B×@ °Ö昛¸â¥}éþ_¯AÐè³´þ`­çØÄ'ÎG:ÐЂLR‰¾Ðƒ‹AìôS__ ¨Õjï4p @éƒ&nrFRR¬çÐ8ŸÏçÿè—Æ¾°±±ñ„3cEÏv¶·jgSH~âFRmw¿0;;ûK?töÅ€Jeû©&kžŽÎFAr{‰i ÅuÝaÓ¼87wúnÖZ37 \­>£×@<™¨]|·£­ÁFIîʸÅ`fæ»,õfj@isë䊎Ç&‘€]W> a¯Ïù3Û‡Sú/™]„Ö7¶^€Ü:ų‡â@HÇ Ùòf}¡g¡121 V/ã¾p,ÚCµ é ¶Œ‹›pLR±T©/õš·“CPë—~ `¬³¤ºó{ÑŽu­\Æ@}V®Ô^>Dz‡4 Ö_´ÏCÐIÊì*+I)&Ú°Öíj½'=‚’Xkï€L<^:!»â#¹[JbÑD¾;?súÍ^Þ6ÀZ›Ãèøu‚—""f»ò©”d’¹úóOß¿º¼¼Ü1TÈ´jNd¶? Û´ý¦÷ÅöÜ^è©ý\Nv·IJJJÊqå&Ñ—°4Ñ IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_up_focus@2x.png000066400000000000000000000017541463772530400305050ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+žIDATxœí—?lSWÆ¿sŸƒ"íJCmül˜¡{ "aèÀF¢àNÚ2¡UB-lH•ì÷B˜ª­ S#E*©ìmþTT¥&vL—VªJãw¿6`?ߨ®ýüàþFŸwîýÎçóÞ=°X,‹Åb±X,‹Åb±¼^ÈvmœöJ“¾ ñW/ì»´:¶Å€´Wœ!$@=Bάdßš‹[‹jÿH´¤¼‹„xá½)â»ùÒ§q뉯Hqý«>ný®­^Øw"ŒCV,ŒÏ2Qx»äAä|gœ)ìÏþxY*ýUƒ‡o>LlîþZ€3MARWˆéU¼µ9ð÷¹_Ï¿óO?õõÕ€Ôõ?ÞPƒÁm‚'#D :‹†¶"ÀÖÅ¿Pe0‰‰•ìðÏIñöÖßœ»h*_}ZWsê¥ îeråã= ­#2Ò¹âû„ºb("ЦíÍhHÈbH+½”ñ‹'»Õ&\¿t–J¾°'ê¶øgÙÍìÑ”…´WšìzÝ:z6 å§A|`WcD4z)þ¦uvø6åmLõºxO¸~é¡ÌÖÑ£eM¤¼áz¥Ö£uº3€×+}âjsÌØ¶Q°ÕëtÍõŠŸƒìêDûßIã³L<)çN7iøpEÀðÇQdníÍ䇸À0dµY¬cß|88ðïî¯ 8Útõ¬ÖLÉ'¾ãÓ?Ï­}ä>ít¥Ž ÈÜ(ï }[€Æ#ˆµâcº¾Öm,ÆK”à¥Ôd§÷‡Ž Hç ÃZ9 BiBX»Ôl'¤ —!÷…›§W²#OÚ¥·5`l¾0ª*Î" GB™íçú¸0Ο(ÎÄÚÌÐï­S[Î?9BT!2 õ6àDŽBƒ øM9jby:¹¼Uæ–Ç`&W>N î6/;¬x zÕ0ž@‡t ïùåcÆ4laÀX~ý„Vz À°a§V|ædXQ/¥üõqSJÓ+àæË— ú²)ö’CPÍ®f“ŸÕÿhè€`¯^ñ µÚ0œ£¯bí5 µ ÐW°ã>r‘ kµY,‹Åb±X,‹Åb±X^kþ0+>%†óIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/arrow_up_pressed.png000066400000000000000000000007731463772530400304610ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+­IDATX…픿kA†Ÿw/ÁÂh‹4¦ŽÊ ¤bJ›  ’"…¨‚æO0Ør{!J@,P$éFäÜ+"ö±ì¬"—óZÜÞ¹z z›“ئٙùÞg¾Ù]((((8b”wãü{„2o0c¡ÄÈô%}ÍS'ʳ)þàÑPæf ¬?kø|žZ=w ®û°‚þcê[LL_ÖF/õzê@Üð8b 1,0°—g£ˆµ¸áñÿ"Pmx’À*pJ†™CVk‰¯÷U Z÷-–€AÀöoá-ZÏ Ú,×ê¾ÙZâû @) èÿE[¢dñ]ಙiºb@±¢GóÜÌt9¤ôì.]´™ c„½Nž;À¹hŸÀ5Ķ¢ŒŸm‹3“öo–ú25àû'zs#Ç=ƒÉØÄFCÚþD.@T—,®è`0Â=Œö#Hl}ð“üËi øÅ=gªÛûCW|[×èkbYÐ^„l&¿§%—&FóÏ¢¶aœ½T°¿»‰Ñ‘RUcf<ÚÊP3¤þÎøÔ0#ÚsüÖhpfþû³ãØNa]ÇÙ¼ÔŒEõZÝe†‘x‰úÝÁ™¹q{ºÓ¸ë€ÅUL–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý ÌÕ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ— ´/Imеá–]ÃtåH½I±Î¿ ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ º ¦®œfÚ×â=åï1ChLûc @P× Þ¹‚2Û ‚ú»56î{½ýÊŽ|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>kÏ–¼¿Ú…í QW Ömõ°gÀ0}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þo2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕìËiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/base_icon@2x.png000066400000000000000000000063261463772530400273720ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{ý£}*P´A6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w¾ÑþÜ©*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾£ 4Šï?÷4Tý÷%p—§P9òmS¨ ŸÿÄÿŸòmh§¾})è{îq1o…R’- @V1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö ?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r ΛB}oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™~‘ ßx+¶ŠQ@ɘµ¯² ®]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=záê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§.Hxfû:VîGèÊ­c ¨/’Ñgîä§ñcXy .*PFÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ òÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'Y 1a5rIH™GƒeOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàKª'à%¸C4Ós–ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·ºôHe H .åã( ¾óGF{e%´òœ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 1œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! Ñ$ À£ý2b…»}4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌòš¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa([9ÆHrç9my"è“Þ')ƒóIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ùæ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡ÁÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœá%^œ(Ιew1,S|¼’…œYµp†*—rA†8î»÷O·ýWÐ8Ósúc¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ×í+rJØîí°õKU\²8ž¯/Î]I#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— —¤ NÑøü=/„a‰!­5 ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N÷óÖJ>dŒ¡C #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf"NT€ì£µ?÷Æ— hÝF›%à¹î°œŸ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿFfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­À}LÁÑ÷Ùë9qž¶øÌ“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­äŸ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/base_icon_disabled.png000066400000000000000000000023501463772530400306400ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿr1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDYØ !ŒqÏ¥¬¬•Q¹ Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý ÌÕ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ— ´/Imеá–]ÃtåH½I±Î¿ ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ º ¦®œfÚ×â=åï1ChLûc @P× Þ¹‚2Û ‚ú»56î{½ýÊŽ|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>kÏ–¼¿Ú…í QW Ömõ°gÀ0}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þo2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕìËiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/base_icon_disabled@2x.png000066400000000000000000000063261463772530400312210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{ý£}*P´A6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w¾ÑþÜ©*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾£ 4Šï?÷4Tý÷%p—§P9òmS¨ ŸÿÄÿŸòmh§¾})è{îq1o…R’- @V1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö ?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r ΛB}oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™~‘ ßx+¶ŠQ@ɘµ¯² ®]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=záê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§.Hxfû:VîGèÊ­c ¨/’Ñgîä§ñcXy .*PFÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ òÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'Y 1a5rIH™GƒeOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàKª'à%¸C4Ós–ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·ºôHe H .åã( ¾óGF{e%´òœ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 1œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! Ñ$ À£ý2b…»}4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌòš¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa([9ÆHrç9my"è“Þ')ƒóIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ùæ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡ÁÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœá%^œ(Ιew1,S|¼’…œYµp†*—rA†8î»÷O·ýWÐ8Ósúc¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ×í+rJØîí°õKU\²8ž¯/Î]I#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— —¤ NÑøü=/„a‰!­5 ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N÷óÖJ>dŒ¡C #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf"NT€ì£µ?÷Æ— hÝF›%à¹î°œŸ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿFfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­À}LÁÑ÷Ùë9qž¶øÌ“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­äŸ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/base_icon_focus.png000066400000000000000000000023501463772530400302100ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿr1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDYØ !ŒqÏ¥¬¬•Q¹ Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý ÌÕ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ— ´/Imеá–]ÃtåH½I±Î¿ ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ º ¦®œfÚ×â=åï1ChLûc @P× Þ¹‚2Û ‚ú»56î{½ýÊŽ|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>kÏ–¼¿Ú…í QW Ömõ°gÀ0}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þo2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕìËiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/base_icon_focus@2x.png000066400000000000000000000063261463772530400305710ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{ý£}*P´A6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w¾ÑþÜ©*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾£ 4Šï?÷4Tý÷%p—§P9òmS¨ ŸÿÄÿŸòmh§¾})è{îq1o…R’- @V1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö ?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r ΛB}oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™~‘ ßx+¶ŠQ@ɘµ¯² ®]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=záê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§.Hxfû:VîGèÊ­c ¨/’Ñgîä§ñcXy .*PFÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ òÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'Y 1a5rIH™GƒeOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàKª'à%¸C4Ós–ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·ºôHe H .åã( ¾óGF{e%´òœ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 1œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! Ñ$ À£ý2b…»}4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌòš¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa([9ÆHrç9my"è“Þ')ƒóIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ùæ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡ÁÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœá%^œ(Ιew1,S|¼’…œYµp†*—rA†8î»÷O·ýWÐ8Ósúc¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ×í+rJØîí°õKU\²8ž¯/Î]I#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— —¤ NÑøü=/„a‰!­5 ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N÷óÖJ>dŒ¡C #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf"NT€ì£µ?÷Æ— hÝF›%à¹î°œŸ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿFfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­À}LÁÑ÷Ùë9qž¶øÌ“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­äŸ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/base_icon_pressed.png000066400000000000000000000023501463772530400305360ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿr1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDYØ !ŒqÏ¥¬¬•Q¹ Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý ÌÕ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ— ´/Imеá–]ÃtåH½I±Î¿ ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ º ¦®œfÚ×â=åï1ChLûc @P× Þ¹‚2Û ‚ú»56î{½ýÊŽ|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>kÏ–¼¿Ú…í QW Ömõ°gÀ0}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þo2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕìËiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/base_icon_pressed@2x.png000066400000000000000000000063261463772530400311170ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{ý£}*P´A6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w¾ÑþÜ©*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾£ 4Šï?÷4Tý÷%p—§P9òmS¨ ŸÿÄÿŸòmh§¾})è{îq1o…R’- @V1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö ?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r ΛB}oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™~‘ ßx+¶ŠQ@ɘµ¯² ®]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=záê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§.Hxfû:VîGèÊ­c ¨/’Ñgîä§ñcXy .*PFÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ òÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'Y 1a5rIH™GƒeOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàKª'à%¸C4Ós–ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·ºôHe H .åã( ¾óGF{e%´òœ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 1œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! Ñ$ À£ý2b…»}4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌòš¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa([9ÆHrç9my"è“Þ')ƒóIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ùæ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡ÁÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœá%^œ(Ιew1,S|¼’…œYµp†*—rA†8î»÷O·ýWÐ8Ósúc¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ×í+rJØîí°õKU\²8ž¯/Î]I#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— —¤ NÑøü=/„a‰!­5 ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N÷óÖJ>dŒ¡C #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf"NT€ì£µ?÷Æ— hÝF›%à¹î°œŸ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿFfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­À}LÁÑ÷Ùë9qž¶øÌ“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­äŸ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_closed.png000066400000000000000000000006211463772530400276540ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+CIDATX…í’±JAEÏ$T*$»ÚD7lü-,-¬´í,ü++¿@$…­Š¶‚~²MŒÕ&6+„Èî<«-w¶qO5fî;<rrrþ;*í}×ó5@9)Nw»÷¶…´£Ã°˜D°QÌZ@‹bs\ï)ÎZ€ÞKpr8ÊŽç?Ø­p½ßLVªËÀ¼‚êDÅqQÿÚ¤+í'üƒëùò+î†íà$S àz~2N¬„ÏÁ]ªK—“‰qâ6m­3ð tMßÛ ¨hXj5 Žk™ ÌÖ [À°¾>¾¥í0þ„Ž×ØVÈ) µÈz¿Óº2é1ÚÀÜBcU!MDöL‡ 8õ¥E­ä( …Ö±ép¥DŸS‚:뵃}›á¥´‚Rrü¹h[œœœœË×`ƵÄ|IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_closed@2x.png000066400000000000000000000015061463772530400302310ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+øIDATxœí™ÏKaÇ¿ï¼ë®né¦Ñ®SêìR„³— #óR¼dDD§¡K@P‡ºEÐ=(!AQ A¢ Ðݲ•tsT,Ã-ºî¼]:쎣‹àûŽÐó9~Øï÷}æÝ}Ÿw ‚ ‚ ‚ âƒÉ6Ð sÀÀµ+Õ/Ûs;Hm@kkkí*¯/”kΙëëLßí Éüð•p8àÖ´wÑ„Ù.Ów;¨ø /½Xk˜Ïd–dûWCêÛ:ºa@ÍzpQ…5x^Ze…ˆWE7Ì’|ÿ­Qò~e³‹¥„WM7’TdØ e[0o}Ëj‚ÛX]ä}U9Üp•fK ³¹†¦ØO=®Ò©úÆXvya.¥2 àðB7Ì~Wݺp´Î™ÜÈg•Y|iè†iØ0CS™/ÓªrøÖ`ó¯î çóŸ ^µÆ×sØÞ zé¥Ðò(z8þ"ÃÃEð௒n˜ *"ø>‰ÙãÃó˜éQŠ4Ég²ý}oÌZ£iÆÐëÖÄeÙÞ»¢ Ö‘ñÃ×󢢚h[G ƒ¥²½}ߺ~<Ì9^¡ÍUºk[©.Ùþ>7àGxm‚pÙVꎊ¾6@7Æ8ï’ߨ‡÷ßà9$í4þÂíÉ›`âa…È0RäkÝ*ßùt기.ÿ<çÚÉüøÈ•Y”7 –HvjŽPW&/qGœÎçÒ£ªó(ý ˆ&ÌvͯQ¹øu戋~,PØ€––cMÜÁ €ŠÙŸ Ñ7K¿U•Ã’ÄãñP)Ä_8â*Ý›žH?V‘a3TL‚ÚŠ¨{ »BxjO¤n+ðßé; Ù0oá߃e¼ß£®CÑY¿ROx<Zu¿Ô–Éc5EtMN¦”Ü÷«!ud#@±Lš%Þ³[È~-nÛN}c4†³›Ò´R¯=‘ú.Õ“ ‚ ‚ ‚ ¢ ›'ËÐwœIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_closed_disabled.png000066400000000000000000000006341463772530400315070ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+NIDATX…í’½JQFÏ¬Š•ˆE,,Ä^lL †¸XZØÙ‰v> XÙøФ°5bg²²bbç ˆV"*ˆ?ÑÜÏF#Øí]ØÆ=ÝÀÌ7‡{rrrþ;–¤Y’Egm Á‘0œ~L+$ìï ÛÀûC½^ïËTÀ̲¥Ÿztlü3S€¹JñH²íŸº·.3+ÅM ñ]NEñù®¯@¢#üK3n©Wˆµ¹Ji?SIAtÖîöÂ,¨VË3§I2¼¾àw¡9}¼ý ¹(iF*€B¡Ð®}çS H²û§ç0Üu­;‘©@3nm!–'æË囤ÞGÅí¡ÀI¶VŠ'>9^/Ð8½˜ª[÷]î%Ј/&sÇ@?ÒN8[Üó]žX@’¸:ưà°:[ÚH³ ?é€I· ¸¢ó¶jf.­@NNNÎjõq¯†ô«“IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_closed_disabled@2x.png000066400000000000000000000015031463772530400320550ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+õIDATxœí™MhQ…ÏŒý ÒB¡uQ,ˆ+wc3LÒ¤ ‚›êJÄ… ‚ ˆw‚.t'‚{A»"A\ ‚Ú$dšLK7Š í¢ZlK3ëB*Étb,ô½)ø¾å¹srçýÜL…B¡P( …B¡P(ÿ$Ú 8åƒq˜øB>=4&Ús;m@¡Pè =«!y$g›‘¾ÛAüùz„6Y.Ï öýgÄo×ã(]‡ßeÛö²hÿVˆ^X˜ÿµ àC_bfáþ­¾Àó¼®5?¢j9Û”’¡Rž€išK¬£j%×sedh†´%˜·¬÷A  ë ¤K®wGVŽ0R÷àHvðƒ®„u®•ÜêY™Y6‰eÿÜêÎ…uM RYËš‘™%¶¨èzl™tøý¶mÏËÊë ÜlFhÓ‚¤eYá R±ÞÃ{;ô¶(}=ÐV˜YÊɵ†aÔ¸¦÷FÕJîô7bŸÄòyc‘)qxKÐ]p½Ç¢ýcoäÓGÞ„“a€Ó¢½wE€(˜‹ÃwW4à¥çí£@s¶˜*¢½coÀììlR¯á€¡Ò­\&•ík&&&?×üq ŒûÃéÔMbm@oÿþ» Œ6ªôœýÕËD9$í4±M‚¥²w• ÷Bòk~F曢XP,OŸñ“ÆçD`µ¬/2³HoÀd¹šÒˆ :ëäe-€ÍšodçIÈ4+—g@4  »NöŒg̪Ì,›H;+•JÏÀ ³?1.åló…¬a"ߨî4Žã´¯ÚS‡êu"ܶÍ224Cø `f-ÙÝó@&Tz”µR7Dû·Bø (MM_~ÿ7XGqeéëEYwýßz 8ŽÓžìêù ãÈx—@-Éd¤üÞo…Ð-Ð×רÕI ¬ó‰ÝòåÁ 0 £FàóÌ1iÇóCCEz* …B¡P( …B¡P´âª¹Òqšær;IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_closed_focus.png000066400000000000000000000006261463772530400310600ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+HIDATX…í“¡NÃP†¿SØ!ë&'è €A"p8$l< L`x¶2e‡&áÐ%0IJµ†[éÁl4Áõ6©¡Ÿ;ɽÿùr“óß‘D§UŹ"€Y¡X–&i¬D§ÏcáÂlúA_—²hK¤*»‹Ò™a¶ÀK˾CäâWÂõŸ3ðö©Âã¼Üp\ÿÊT ÙþÁq}“´å5ªnÒ £ ,ð†v¼„*]§lf*@[¢ÂLVâ4}ÊV LéõtªNÊ= ø¡õ]K±œ¦Ý ÎTؾ"±¶ßŽ*ïI3ŒA½ì«è îxÍêƒIŽÑÔ;ã-íÍËcÓæ`ðkîh]‘ûùÝK¯Yé˜6‡¤PÁꫪrë í“4ÍÁd …*¯añó€¶¥ÈÉÉÉùae¨ÚŠ|IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_closed_focus@2x.png000066400000000000000000000015111463772530400314240ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ûIDATxœí™QHSQÆ¿ÿÝšsÕ”j›Ë‚”Ý‚ × Ì—‚^*‚"z¨pº*ˆÞ‚|¨··m™>„DDQö=>Ams¥±;…DC³m÷ô’±Ý]‚ç\¡ÿïñûþï~÷ܳ;€a†a†a†a˜ÿ ’m 'Œa§þØËt‡d{®©ìüä]Wð-”k¦0dcáQ™¾+A“ùá¾ùõî*CÒ^è¹V™¾+AÅ# ìtÍ¥ùS9Ùþµº Ó¬Z`–ÌYô éþµà•ÄOwƒÝHoΗ¤û×@É¿¸yÖÔH·›EÆ+–CÙÌFƒãdŠƒV€v=aÜT•ÊÒg0}¾é9 º`3ºI§UfYBú.`‡ž4† p¦*Œf¶¥£á7*³8Rèq# BÕy@siÍ©ÎÀ7U9+XþŒ°ðã—oâòö»Ùjãè>ìA^¿Á3!”ÜG ‹QD1`7Ó“ùï*28~KÇš§MMì±5Dâùû²ý/²Ñ¦÷‚ÄQ«N$NÊö^€fºSŽø:aj¥%i„•F¬:¯e{;^@8>és <ÐR1 \Ow‡Úeû;[ÀáÚHîa{Ëe$3Ñ`ŸŠŽ ÏLÝÀ‘rO·M{Ad{HZmœ; 'r—ºm‘ßj.­Cå›"G Ø™0Ž à¡Å‚J®}éž-“*³(/@çÚ@4  ¾LžÓûS]¡wªó(ýÐr­ z‚Ê‹/‚p܉‹°ûÎ×M(Ò€Š³¿Å2]¡gªrXQR@¤?SW0=@ØU9¡ãÝÁ»*2,‡üú„F^ÿ €Žr™îeºפû×@zúÖüUüýop zi.ÎFUíõÿBê.éÏÔ‘×?À[fùa±èiÿÒÛ¨ä÷~-¤®€†ºˆ  P&å]¥Òáµrñ€äÆbTá,€i¤:ô±'üY¦'Ã0 Ã0 Ã0 Ã0L-~Çd¯bIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_closed_pressed.png000066400000000000000000000006051463772530400314030ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+7IDATX…퓽JQFÏl¶±±°µ ¨«¥¥…˜!…O šÂÆð‡ànkÄÎZ°MÒø’Tb¥M"HÜÏÆ„`·waïéæçpg.x<žÿŽeI–dI—€ùêŠ}ä²$ŸN xoµT*T a–bìŽãÁ"£Bª‘Ý ÎÆqÜÑs¡µu;F<þ†ËqG®™Žð/qGš4õʆ]gíáôcz“#”q•´µY¨@Ã,Î0;%ñT¨À|aô\ës H²Á'MDxû.Q.T érìC Ø>Xµ~Öοফ} *`§¶f.}B—¢¤­-DSÆ¡ëppXAÒÖ’Œ{A(8¯Fvé:<³€$S@ ˜nûGy†ƒË Ä«‰ ¨4ÌÒ¼Çó¦|`’R?IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_closed_pressed@2x.png000066400000000000000000000014441463772530400317570ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÖIDATxœí™MHTQ†Ÿïú3¦¥H‹6&D«Z¤£æÏ&‚ ME`„Á8(A´iä¢v„»0 BB¢@‚([„ÔÌ´(‚‹\T‹2E-Ç™¯•63^„ιBçY¾ÌûÞ÷ž;çÌp8‡Ãáp8‡Ãñ¿!¦ âIQ8 €6IÜ´çf0Z@l\+ØÎR®æ G"2nÒw3x&?|±–ÒB-«<Jh½IßÍ`üˆ%Uýôì/ª{ÚeÞ´1Œ®€ªOëW€b®_Õ¸1Œèì”LY†¿Y]ŠŒiÿbX¹çZd.ã±ÏoKê 6ÂÚìm¢õµÅSzÝVŽB¬>ƒÝMòTáB¡®Ê¥xB»lfYÅø.àG,¡q„H¡îAs$, ›Y) –ÔÀºó@¶„==‡ä«­ŸªÒTv¶Ê’ßì_è>¼,”ûé e,ªª•›h}’^jýfñßmdü$Ö×(38à3ª‰%õžiÿÀ è Ë;…“>£3¦½·D"Lá»% |©»QÆ|F¦½/àVJ+KKxìÍ(W£ai3íh££ZR®ŒMya°;L¿ °PÏ àDüxzžó"â{Hú×wNèE„›y¢ð&û“›oŠ)àÎ+=•õ¸Ÿë/ðYÒ´DZå‹Í,Ö Ni³(ãÀ¶yÞóh4È[Ûy¬~ %´^”Gä\¼À p:ˆ‹‹ÜžÐ]ž0ùg…¾hXžØÊQˆ•¦4TRÊ`®.ʵhX†mdØãô«zÕ³Ä:ru»‘0WLûÃxu¯¹¼ößàžÏí¤×Ö^ÿ7ŒîSÚ1Ë,P±ª)¼…hë:(V~ïÃè ý ¤×囬p|«\<. ¯QÒ(Ý3À$p,zX¦Mz:‡Ãáp8‡Ãápã7/œ¾l1`IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_end.png000066400000000000000000000002241463772530400271500ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+FIDATX…íα A‚˜"uê¬3±`ÂHiþz[?†À#Gåc*ã €  =`©Uµ=²-àš™xš=ëšqqO4IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_end@2x.png000066400000000000000000000003161463772530400275240ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+€IDATxœíÙÁ € A° Μí¿›Â2ÖÄ™þˆc„Ö¾ÏÚ÷)7\åñ/ P P P P P P P P P P P P P Pû}€Y¯¿ÆÇ¨_À†2¾ €Ú^õÀÝ¿Èê x¶­ß¶rúÜ 2Ú U…IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_end_disabled@2x.png000066400000000000000000000003151463772530400313520ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÙ± €0Á‡þ‹r@€hÊ”±HÌ4ð§•3Ï„ÖuïuÝ»Üp–Ç¿@€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@í÷Žòxý5>S¿€=Ozþáñ© êŒ)%uIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_end_focus.png000066400000000000000000000002301463772530400303440ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+JIDATX…íÎA ! DÑÒ ¥6µ«šDÌ&½üwŸÉ7DÖŠ¬¥|¸2þ@´Lõàû"«'à˜o¿G¹ý$˜ Mòo;¯IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_end_focus@2x.png000066400000000000000000000003141463772530400307210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+~IDATxœíÙA À AZ/˜FRT•±M˜1ð_6Ü#4×»çzw¹á.ÿõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€Úñ®òxý5>Fÿžø>œàÎÑÿ.ÚOhIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_end_pressed.png000066400000000000000000000002231463772530400306740ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+EIDATX…íÎA Qpì-Mè` BaaFûî|V¤À#Í#­²1*Ç € àyÀlØXù& U¶Þÿ8A­ ‘uËwIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_end_pressed@2x.png000066400000000000000000000003121463772530400312450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+|IDATxœíÙQ €0ÁÿêDKÒ÷²é_gBëÝ{½{—îòøP¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨à*×_ã3ý xâûp‚‘w BdâæsIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_line.png000066400000000000000000000002061463772530400273310ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íα01.cPS3#£g(õ½}ŠX”Õ“Õ³ùx›ñEH©Ó+/˜IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_line@2x.png000066400000000000000000000003601463772530400277040ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¢IDATxœíÐ1 Ä@‚ ffüËÇÐ3ðÍ­}îÚçʆ)ÇÐ:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZèícIO7}LIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_line_disabled.png000066400000000000000000000002061463772530400311600ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íα01.“³ke(õ½}ŠXT=Y=¹ùx›ñEtöÑGTIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_line_disabled@2x.png000066400000000000000000000003601463772530400315330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¢IDATxœíÐ1 Ä@‚Q ¸ÇÐ3ðÍ­}îÚçʆ)ÇÐ:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZèíêHŠOIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_line_focus.png000066400000000000000000000002071463772530400305310ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÎ10A&bЉ $â"" Üëÿg#eOeOm>Þf|Àz”ä¢?IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_line_focus@2x.png000066400000000000000000000003571463772530400311110ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¡IDATxœíÐA Ã0/˜Æ!*@Fx4ÖÛÐÚç®}®l˜rü ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€ÐKºÍ¼ê® IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_line_pressed.png000066400000000000000000000002061463772530400310560ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íÎ10A&Êq‚ DPîõÿ³‹ª'«'7o3¾àl‚†I#…IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_line_pressed@2x.png000066400000000000000000000003571463772530400314370ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¡IDATxœíÐA Ä@‚BÔ!cxt l³kAçΜ;#¶ÿAè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´q¢Oz2T‡IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_more.png000066400000000000000000000002471463772530400273510ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+YIDATX…c` H©è5H©è5Pb%š©F0ê€QŒ:`Ô£p°PjÀ†ÿ”TÉC?<»s©\ý£uÀ¨F0ê€Q ¸£g è¥ñ\IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_more@2x.png000066400000000000000000000004071463772530400277210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¹IDATxœíÙ± ƒ`Åà#b jjö$ujÆ€1¾H¿½ÀYÖënrœ×sœ×#>òø?P- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhÍò6y\¿ÆgZÀìZ`fæþ}Ù—_@´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4ËxÇÉP+ igIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_more_disabled.png000066400000000000000000000002401463772530400311710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+RIDATX…íÕ± DQ—²t³l¦"k¹ƒ ä_áqMJqd«ÉVÏê)GH´€Óó’¿Xà¬Ñ嵜¾¸  ÕëÁ9êIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_more_disabled@2x.png000066400000000000000000000004051463772530400315460ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+·IDATxœíÙ± ƒ`Åà ÊP)(‚‚­ÈÒo/p–õº›œ×ýœ×ýH‡MКhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð,à#ë×øL ˜¯˜™9ö[âò (€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€fù=š ¨P„¿IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_more_focus.png000066400000000000000000000002501463772530400305420ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ZIDATX…c` ¨Í|Ù 6óe%f0Q¢™`Ô£uÀ¨F0ê€w ¥ügøï@I•<ôC€‘ñÀ­tñrõxŒ:`Ô£uÀ¨F0àè “ ‹pøIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_more_focus@2x.png000066400000000000000000000004071463772530400311200ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¹IDATxœíÙQ ƒPÑ-ÁC` QXC*¨ŒÓäÍØÉäþí 丞÷¸žW:lòø?P- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhÍò>ò¸~Ï´€ÙµÀÌÌ}~Ù—_@´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4Ëø:Ý ÎuñIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_more_pressed.png000066400000000000000000000002421463772530400310710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+TIDATX…c` Ì?ý¿aþéÿ ”˜ÁD‰fj€QŒ:`Ô£uÀ¨Ü,T0Ã’*yX„ÀDSÆr5xŒ:`Ô£uÀ¨F0à+l «­þIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_more_pressed@2x.png000066400000000000000000000004031463772530400314420ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+µIDATxœíÙA Ã@ÅÐIJTd´ 60^¥µ ŒeýÛÌ@žµ÷³ö–yü(€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€æø—<®_ã3-`n-03óû^l‰Ç/ Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4Кã¼ê^ P\û•IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_open.png000066400000000000000000000006701463772530400273500ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+jIDATX…íÒ1K[QÆñÿ{/ˆ´©¨Þ›‚bn„.ñÐM\2‰ÖA(ÝâÚN~ !_Bœ2thGEÚAH)tÕ¤“&ª½h ¡&‚CrßÍ B<‰.BÏo<<<¼s8щœžhe1ÞKs¹Ÿ§6Ö¸1*$n¬µ'šß€á7ƒ9TÌ_<óoòœ¡Ñ=b¼³Àß(okìzþ§_VÀ# Z-Ývúz>Z¥#¤ÿQy¹«×)Õ*ó?¬'+žyÎÂ|Ä‹á;cEž/ä~¼VïÐP.—ëµÊÂDw¯Exºa$"ìï‰mßr«²0É}>“Njä°ùØìMp;z xåüR˜C]ÀL­2?Ù‹€}4½heoO,>Ü÷ÐæÓ‹‹‹k¾ëÄL¿-Âø_{™ñBnøh­öeØŸÖðÞ÷â¤Òcbøa‹ïg§¬Ž•×/]º àºntqÙ~ÏÀ_„ÁÈ›…üÌx«:¶týC£c¼3Ís¹.Œ­z76ÉÊ)àߥwÀ¼RÈ]œhe¿–/ 1èî@ì³Àžõ]anxb½8?;ómK‹Æ?Áu(ä³Wî˜è^“ÿ|¶¹lã=ÙŽ›‡6- ’Ÿ^ŠuÖ÷ïßç´o°;Ÿº–Ëζ«W+¾«T*Õk•…Ïzú€LÓÐpÊ^é:8÷ë÷ÕvvjëîºUžÿª;¶}dðŒp¼˜»p¬Z½èýÿO&I&“›þëJ)¥”RJ)¥”RJ)¥Ôâwöômá…IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_open_disabled.png000066400000000000000000000006311463772530400311740ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+KIDATX…í‘¡Ka‡Ÿ÷¦ˆ2d hÕ¾ œ²á1‡K¢®Yg1L° 6 Š`l¢eÁ`Äàív;·³ f‹¬©Ûk™`™·]üžøòãù~?>0 ÃG¢n½q.ˆ­’(-; ÏýHÝFcÆjKEá-ïdÖED{e­(™…¤€9Ñvàa!*ï7miKSÁ˜ˆöG0luJ(×À¸ªÞz~¸Ùóñ \³„0 ¸‘•ßÖC_ ªV-Ov»§ƒ¼“9ü)wëá¶ gÝQ•ÉTr+N¿G¹û*ðç7wT8,”ËäèPÙ¶ívõáñXT÷D8ZZÌìG-U ê7Šˆ\c€´€UàS”r>—½Ä7p·Î zLuO-6òNönPW¬žÎjB_€×ŽJ±Ë<ÅuÅFUEUc0 ßà ÖÊk%§!ôIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_open_disabled@2x.png000066400000000000000000000014751463772530400315550ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ïIDATxœíÖOH“qðïónóЍƒF§ ½Ã鿦 $Jº„iAD:D„+ð"ôçT‡ #R»Ø»ïÜBê²SB!ˆ\be¦n{ŸSÚ^ÌÌ÷Ý‚|>·½Ïû~ÏïyÙo„B!„B!„B±UÙ€p8¾_WðÀn€î4{ëo[ÐÛš‚‘Ä1úsŸôó-McfòL ‡øóíÜæ`ÁWB¡Ä^¶ñ€}†ÒGEçÃ~ã›Íä†Ã“Õº-󌃆Ҭ®óÑV£¶©†óX2ˆÅb;–ueùçAÎwèx«×=ò7y¯¢¯kdGª1”ÞÛ˜Ú}>÷;S ¯°â x<žÙ…¯³‡@xl(U)ÌσÚDïF³BZ¢Ua]3nž€„¢/7Xµù•Lk1³Ò7\Y£Üßìu_&"ýwχ"‰n&~ÀaHvV8º\.ׂ•ýZ>€UÁHü,ƒl†%Ÿpz¡',æ_ef i‰k®³˜00óaúbgggÖê>‹6F'Úz  Ê°¨–vPG›Ûý’ÉdYjnþ.€S†&Æ…f_Ã@±z,ê ‹`]PmXy*‹l»^^žr,f†´]Ó‰Ÿ{¸˜ý}‰LÖd)3  vƒ¤8hjˆ³/ÀÂ_õø|®ét…ÝKÌã¼™0ÅŠÞXŠÍç–+¡d2Y63÷ízÖ¼)Æ[G àJ•ª§’ÈöÁh¼ˆú *³éÝçG)û)ùV£‰ûŸÀLt»ÅSu½ÿÿ%UUíªªVüë>„B!„B!„Bˆ-â'éù˜S®F IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_open_focus.png000066400000000000000000000006521463772530400305470ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+\IDATX…íÒ=(…QÇñïÿ¹ "¹’"÷ŨØl&yÙ”‰R¸·l›I&“÷)ƒÁ¤”,ДŠLî%åí¾,tÕ-/ço1 xÜ»ÉùŒ§_¿~§sÀ²,ËúïÄ/Id—m7ŽÖŸþ¦´uá®é%ଠúsûÑﲎ_™¢Õ@›cä0ꥻüò-^®ý5à t‚Ôúå}Ÿ†€M Ê¨ìD¼ÌðwÙðR®×Q³¸‚ì=—Wtÿtû_ ¸žl,$o‚ƒÀP®ÊZ(‘™FõÓó…™8b¶€JQÖ˪³Ý—#5÷~ý¾ࣈ—PÕyÀAuµ 7v|Ëk¸!3 2õ^9“«›ö»yIBËé~1²T yàE‘Xj<¸RL_Ñ¢‹¹ã˜m ø~”We sw‹í*i@ÔK7• T¯D¥ÿ,îž”ÚU:Uùú-˲¬?ç †þuhR÷ôIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_open_focus@2x.png000066400000000000000000000015051463772530400311170ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+÷IDATxœíÖMˆwÇñï3IŠ èRHveÕº’ÝÅÕ‹žÔƒø† bK/ŠõbVÁT$ ZÁƒbvÄz¬b)míµÂ{Гˆn¶êÁu7‰]_W“8WH¦ZíÎ$}>Çÿ3ÿg~ÿg˜IÀcŒ1ÆcŒ1ÆcŒ1 Ú yb¨Kù^DZŽäR‰ÃˆháÞ¤£'ÿ¥Â!A¾éO'.éxínþw”ÅU OG›Š©ëëæ–‚ö®¡*I·¸[Ðo«VMÖDüJ·”ÇÛÖ ¬¶‡Âו‡‰ßfž|и÷˜%¶»…ã¾ÃC0ð^ œñ•&"ÞOÉl~Ûûöêt‡— N0ÃWúScÞ‚éxм¯…ò ÔȨ“lÍdï?jʡܽĈ÷¶ín~ƒ*½@ÌWºðD+뇺[Ÿ†7üŒiw‡Ó¨"µ7Ô³¥ØèÆ;›ÛžÕlP•¤[Ø/pà 1æšâ»X'/ÂÎY·tôV)ú0±z]¡/Z*qcû´¿ºÎ^û¤ü0ž6ùZ(èŽ\ºåh½2ÖuÉÞÂ<ñô`ª¯”Se•Gì~DÊ瀾ú3¯úÓÍ꙯œ‘è¯Àœ÷Ür_E×li¹\Ï\РÌÊŽL‰8åó(ËßqiÎsdõ_©Ä@#r…ö3ø.·º?}›R\pêm×ü!ZYÔ¨ÃݳÁT¥£§Q!㫜}RÚpwçôÑFÆiüÆ$Ý‚+ª›yõ¥ÿ.7ؼïßþ|–d4:óäí ÿwcŒ1ÆcŒ1ÆcŒ1æ#ñ¨³ônö©¬IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_open_pressed.png000066400000000000000000000006171463772530400310760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+AIDATX…íÒ1/CQÆñÿ{Õ D$Öú¤·‘°™t¦Ò†¤ÀÖIL&3½—t0˜$±HˆÐÞv˜$fÒA„Þ×b@R§½›8¿ñäÍsž“ó‚eY–õ߉iÀ tH6!»’’ÛvB½+M£ <ç\fED[Í:mä £]pYªë”iدk’×À$0hš7è}#+pôKȉèbËËk:£!çÀ°Â1Ò¿½¾­óòrï² ÂЭ°çWµ¨ªß¾Ï«éª*G@\ Ü×C:?&O¦|ã|度° 8Þ«PxLÒLl"¬ˆ²±”¢hzy¤^U3@å¡L ¼+ò))u’×q€ÝŠºŽpŒ0ôyÔa.çÊi§Y‘ ìWt¤ép<„!™åq¹‰š™ªÊÏe´,˲þœÿObÅXÓúÕIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/branch_open_pressed@2x.png000066400000000000000000000014121463772530400314420ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¼IDATxœíÖKHTqÇñï¹ÙsZ¸ Š rT›jlr‚Àˆ ¢¢‹(GC²-"ˆ bZ=ÀEBzÇEôÚ„ꌶi•aÑ*„èeó:mn7³òÞ™ Ïgù?ÿ{îïî½Ì€1ÆcŒ1ÆcŒ1Æc¦ Ú ½WWˆC'ÂbàBC”s"¢!d›PªOwÎ8p8Q-÷ƒô <€Ž´>6z–®FæÒT·J²A{{©ª¸C9ãY~Ÿ4G%7Õ¾NÐ`òs}¿ð ã©Ví=.Ù­n†6ßá¿ß>˜ÀÈÃ!”·Þ5Z ô\Ô¥Aû_|¦ó—ÍçpÐWúв7ÈÓ‡&ÐÙ§U‡ûÀr_é Û÷Gep*}¯ftQ^¹¬ñ•Fv6TKÏTúz~êcò²#<ö•ŠòØÍèö¿íéöëʼÒËχvŠÔ„qxiMqýPÉk¾RD•Ûí=ô§½Út“ =À_©Og°>“çÊ'à•Tuª8­Ê‰ Êg_E9Þ"RüÕõnZë®3½ë*ÜÌÁÞæ¨|3oèçöëÚ€Þuºä‰ÆZûa]URiN©Ð2AÊÖÈ0Gëê¤vÎ’ •Ö­E¸D|¥§È®DLÞt=ÓYŸÆ¸„ÒàÛ§(G×Ik©2–t©´®.Â]`‘ïÎC[¿ÂÈlå†ÂfߥcN‘=‰˜Ü,e¾’ •Ñ%Eå°òOö Œ¨ÃŽÆµÒ[âháý L&•×Yaðð·›…¡¼CM9e@sTÞGæ² %5ɶ'Yˆ7­•åÊU–OÀKUÅÍ’¾ 7æå¨¯‹Ë—ræ)ûƹýzY…FUåü«jNNöÿà¿”ìÖŠŽnó¯scŒ1ÆcŒ1ÆcŒ1ÓÄ7‘ŸßYy·ØÇIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_checked.png000066400000000000000000000013171463772530400303250ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…å—ÍkAÆŸw6–B$¥)1›´—|@‚¦ëQA‘ê5ëQAZ´'OZÿ€žZð `Ñ‚žëµð¢A©×ÐJ¦)ÍWµH-ÛÌë!»šïÍ&Ûô9 ï¼3ÏgvøßEõèÔ9Ét—ˆÎðØäSbæA<û%½ö¦%€ŠÝ&Ð\30›$o×o+€7¢Ä>/2àÄßnh7iQBðSPżãEv¹«am ÀXuM2Í €7¢Hò\m•–óÉÇGÐ=cW:0@š-6½„f·Z kS`«®1èN!•ÌtDoÖ -0àcÀ'@‹Þˆø×CôÔî §8À}]OÑ2=É4CÄó+|Q j7!@½DoÈ4Jœ´\]#âyb~XÛi-úŽHéÀ»-;ºˆÞ ©d†M·ö·½%ÈH>ª?ŠŠº‹Þ2šEÑw€B*™Ñ8€M› ï6zC–?ǹtò€€ic‡ªN Tvm^¯áhtH˜yÊý"~Xåý¾¸îõΨ)ÆÀåö|è:@—Ž»ÕÜ€w0»³µõÓãáhtÈ9à¿BàûúñäÎvéÐüÇdö¾”ªÕðc¢TÏþØ.¾u¹=/™á!¢AÀÚóªŠÌüJOæÒkÏlÚóÑo^]þJPÖU÷IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_checked@2x.png000066400000000000000000000024611463772530400307000ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ãIDATxœí›MoU†ß33©RBÚ$6‘ØUD°ÒH鮲T`S袂šT•øl`‰4DB¨eÅ/ ‚T5lªt,¬6°@©‘1 ²•*8¸6©»hÚ*‘g‹xÒñÌØ3î|†ø‘¼˜{ÏÌ=÷è=÷úèСÃA†lY¥ÓRl}ó eà€<ë©gí³ `ƒ€ef¾Z軎L¦fõ’e^L½Á} à7¼ô‘)üá?kÙ[‰-ê(–á €~W]ó‡~MuõFv¶ª•Ÿ›5 @,9: æÏ¼ñÍOèTWod{«ZY2­5+¬Ëþ]ñ}fd‰n”W‡×k²ë¾:bBŒ¯ˆ5>ÍÀ€#ÚZRøM³t0 –bß[AcÎÿ$+4vÌêý ¤¯â82¤™¦ku’¿E:Ý\eJ_Å…1@Ý¢šr"VÜü¨YeÒWñ~dš&FSúâ ¥¯â†,  à¯R!ÒWq&å€ ³†TƒôUàn>—ѧ–†õT‹ôU\Jñ£—ܶ0;$0¾ˆçà }wÁL¦¦€.À*ˆÇÀ8nñ5_¤¯âÚ,P.¬dm¥‚>I_ÅÕiÐf*´Â7髸»°› æø*}×BO >K_Å“•àS¤‚ïÒWñf)Ü^*"}Ïö¶S! é«xº²‘ I_ÅÛÝ`&S!¿Àìźùý ¤¯âùv¸XÈ墓D´à1€ÇD´(´û—™—ør>`#¿Rð¶mµK8þ³l7>N´:Or ¾oë-̰¡}ˆ¯¸é’Ÿè}' ¨·1”–µÏbO»ïš?ˆ5å-]‘aJ6”d¾Úð ÌESQ—}óœÈ`*Êh\ˆéû˜ 4ÐwÀŸš¢#¢@óû)šÃÒÚã¹zß0pwî(Ý=‘¿@4¥)ˆ>è>yt8òü¿ï½öȱû®;aBŒK/?×Ó?ED ^ÕÖ’Âçüö«aÝÑôÊÌÿçÂâéR>û¹YUÓ)n«Z^êêltÊ;Ï<‡Á˜.²—š´œã·ª•¥îžÈ/ Çþ»7”#…'KkÙ¯[µ}mÀxýÔuè®ÍÕçùÛí\›ëСÃÁæ?0 òr.Ê™ÑIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_checked_disabled.png000066400000000000000000000012321463772530400321500ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+LIDATX…í—±nÓP†¿ã´Y*1PT¶<…Chê±µbêT‚Nhx€N©Ä@%*@ u鉡"rBîS´s+º¤Ê= ±ƒë&qœ¸,ðMWÇçÞóû?Wö½ð¯#ñÀדïÇy AïeTæèXkkW~) Ñê¼Ø&,#¬(U¯\|uC@£ÙYáø…²ÏÙz©Tú™EÕv»}·ÛsÖö;ÖêJèÄÜ@‰HTP¶WËÅÃ, ‡/rè7¨è§ ÅOœH^ Ÿ³õ,‹G¹Ê¬­n‹èo¸¬lÆ×ý ¹¹SÓhšu} *Ï*e÷ó¸üLø¾)¨è°y0nŽ3îaTÕÑœ~ ‹OJfü–ÙV¯EwÿŠß7„½X¸á•Šïn]Àë/¥'›"b“æ'n¤]í·ÌrÃúÏ+žNò‰Å—€%=ò}SŸÁú‰ÄXМ~PUgVëC’¿¢»¨D"¿ÝyŽ™ÅúD;ׂ*ob©©¬ŸX€ˆXéÉ&p9&-µõ ð<÷¥:2AtÇóÜTÖ§à-»o‰·¢ÏTÖ§0¢S[ŸZô[¡j7€3àLÕnLk}Hêßq¥\ú'$â€\@ÿ™ÕâqŽY †çCÐèöœµÛ0ß%X[L´ÀZ[sYGØ÷›F®òÔ#g¸™86fq¾ËšŠ¾î—²µðÙ°‹I *1F_LBþ\ÍÔ%rz‘s3ìjöŸß ãðöMY0ºIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_checked_disabled@2x.png000066400000000000000000000023661463772530400325330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœí›OoÜDÆŸ±½mÚ[O«ªU{ =PU*RC±â¨­KÊ¥%PÑVý\@$IˆT åŸ$"P—r‰ÒKšl›]¹4½ —rh”–½5iwí—Ãf„×kÇv<þ²?i¿»óúÙç­ G»%ˆs®)¥¾‚ò@;ÐÞ´“‹{Ѐ-38·œæÆ¬iš­Ðo…,.Y@ø /ËI43V|pnHÿy« %è±Å¥ûãæwàÅÀqó‹KÖþÑTk¿Žt=•Ô²å³jíþÇA'}•Y\².˜÷4?%° ÅÆFãñêèè¨-3ˤT*µ\>zÄQq‘¦ð„¼áW]pÎ5¦íûÍcû…–†Ëúޜw*,XVYkaÀ°«y…šë'½cW (¥¾ÏÅÿSböû;åâ`X×- — +¯=8ÐTÚýRιÆÈþ@i«8ý˜´¯B ÁúðBuØÍ¤}N€ÖŸ:sF_IÚ_¡ˆj}ËÔ\ÿRFŸ… ªõ(×¢¼ðŒBaˆcýóC§ÿÕo!ÈÃú)Ï¿Ôj/©¤N@LL~"æL›ƒƒ¢|¿m}Šdýó’¬/Hì^¯÷«¤Þpb®N¸Âånµj ý~NÖ$€‘2€¹:©øžsè²<­/H>ü÷ˆêÇ+íû0èd£¾—,Á©¶Í;ÉÛúÜ9¿‡‘ý»Š`}Ab_xÖQ E°¾ ±íù8û4Bè¯=8Që ¤ŒÔ|vÀð=ŒìïÙ3(€õR0M³EL½†ðRxÀɘL¬/v0WX adb}ÔÛ`ÄR؊̬/*@ŒRð#Së ¤O„”B¦Ö¤2ÜF)dn}A*Ä,…\¬/HíY F)äb}AªCJ!7ë RÀ4Í)λù,² URœ÷ò²¾ õÇaspðiÌ£9ëÖÁhŽ4fD}e–&™¬0u} À›Yô—B¼Î¿ERÏÝG•JEÍ*ÙtçÞym€ÿ"©'î£rùè¹ie‡OîkÞ?,»¥f•!¤9—8ÍYþt5ÐZ˜ÙI"¸K»WŒ¯8ÍYol¬åò`4ÉZÊ\‘—Ë“æ\Úüç··\^ÐÞ-ò¿Ø0ãç†ô~'çgÓ7Œ§–R6ÆÎ¯}mÓðÚ{pv‘6MmcÛN8\ÌmsXð0ζ¹=zìnþã4ê”ZÂ×ÛIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_checked_focus.png000066400000000000000000000012701463772530400315220ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+jIDATX…í—ÏJQ‡¿sÕ¸º¨­m5Ò°ÐRZè.Ò•o FÅUÕ¥ˆ«º¨X©‰Š î„BA_ 4mŠB­$‘ºpaÄ{º˜L:jþM2®ÚfÎ=wÎo~g˜¹þuäb ºž¿gÏdÑ»@O@uŽPÙ1mšÈLô~¬*`0™<¯$, ¬(s_¦z_\0´V¸¯¢€ß 3!SLš¸ý+ˆªwÖ¿_/ÚPL`¸f \'ÚÝ$…9@f²ñÞÍ »”ds(•UÞÚ3™ž˜r–ÓsB¦˜²¸srš.Õ)Ç<ã=µWÂç§·~–NÃn¬½JnÓ &s£ IçJã_ã}ïjå* šÊE¬ÊÐåD$ ôךcj úbAU³ñ·xcæÀÀÍÂ4ðÐSe©Þ¼@ˆ¦rq>`eÙΆ׮^@eëEì8‹bëM¯Û‚zouëg3ñ¾½úêr@’À ç­h*qGZ±ÞÅïKØ¥jÞ° ¬m€6e}ÃTYaµ|>è/L!-XïR·ÙÃðš ÛÞ˜«¯ÎÅ|Zß°ÅŠØqà¸F–oëd&ûöJ¿ëЍ2›™ôg½/Ùá×[Í[ï[@•V4m½8­°VÆ€}`ßZkÖzß?£oÓá÷@¤nbƒx8gÔÍ/2¼rÐ]:-\ ²P´¡ØU °±R­]7VniÓ„µŒ ,¥òbNNÓž5\K ¯tÛÎŽ˜*/kÚ4áŽUÚ˜$r¥tžêÏÖlÏêµE ¨ìVÚšýç²§ôût8IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_checked_focus@2x.png000066400000000000000000000023761463772530400321040ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+°IDATxœí›OlEÆ¿76EꥪP½umUJ¸"ªT$rëÅàÒÒ ˆ‚h«âRn\¨H$â$Ên[‰ÔR.Uz ªöš^5ØŠÙQÖ‘Zõ„R%ó8¸Syÿe×Ý¿!þI9ìÎ[Ï›/ßÛµg€ìfÈKP©Âév¾sš˜Ï0Ó9/†œ[¿l€Ñ&âE&ºžkenÝ™¡M·‹\©ê¯ƒé€_&ÏȨƒðÑ?eí·í‚„c 3«k“`,ìÀÁÀ( Åï:`vüG; P¬éÌôY8¹Eƒ?/V×?qj·U¦k{,ùXL‘·ìÓVðm¬/npêècý0Kq$g´ßÐNxî,”*œnçÖÿ0Ùþ÷MÂÙ岦Ÿyð Uu-͘ðZÏéz®9n¾1ZJ ïœ6 þ¡Üâ÷wÊà`¹¬é›„³~Ôsz´;6#ˆùŒñ˜*ÍvBÈ3T–˚ΕÞsæ±60Ó˜á"!oŸ^4’ó½Ç zÕc¹ª;Éyƃ}ÚJà™E„MîysŒÝcÐ8ÃKÚݾ¬¹[f¯Î¡]B:î¼P¨u†S’§x ¸ Ælã­é÷³ï€#×:#Bò]ÎØ `/ç‰p¯Pë ûýüD Pªp:%äϲ6ÍY’ü©ß>-Àj^¿ ›G—‚€·ýö‘X µµcÌ4v?‰ Tá´øÀ Û~ñÛW"p³þSžð–¼ê·¯Ä àÕúšn\ÊÖýö—(¼ZŸ‰µ|DŸ‰À«õÁ|ÁËž^HŒ}Yÿbö¯ úM„qX_È»Àð·z„)51!à×-A³ÍñLÃËõ«yý28Zë+|; Pë áçñt®ÎÀ9!ùî‘k÷ë㱾·)ÉSp˜«‹”ü©TaG—Åi}…oÔ+ªÄ4¶š[ÿØ©=Ž»¾™Ðo‚ ž.ÔÖŽ™ÏÇm}E¸é²‡ß÷–B¬¯ðï)¿ðd»s)$Áú ß4.eëD<ã§J!)ÖWr8ÔÒ®|ß%lô£4‡X_ˆwfhS \€K)xÀq—˜H¬¯ì)Ð?ø§—Rp#*ë+} z,G¢´¾"Pú(;"µ¾"ð‰Ðó–BÔÖW„2ì·â°¾"ú,…X¬¯í]Àk)Äe}E¨/Cn¥§õ¡ Ð-ñ.»E+L⽸¬¯ýu¸9ži0¥O4àßîÍ3¥OxýÊ,L"YÐ(¿Ôðf}õK"¾Ž;6 G78M*!`Í}Ãb€Ñî=<úX?lVÑa“{Ëc](I¼Ø{ÌRœ 8¯È,Nõ“Í#ÙºP’èºáÉÙ¡ª®ž]È Uu 1ËØ`#@®•¹ÐßÏ.íO3æv’j±´iÅx½;6#}-—gˆŠ 9Ÿäåò’Å)‚œyîåòŠbumòÿ°a4¹t1sÅ®Íq°4®]!ÐdxiE3ÓÄRùÀN7Mák£¦>ž6Mõ¿m®ûƒFIÜ6´|¿Ÿms ØÝü×Òóy(IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_checked_pressed.png000066400000000000000000000012151463772530400320470ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+?IDATX…í—MOQ†Ÿ3Ö‰ &¸‘þ†ZKÔMÜAX±F£¬X). aU’HÄHÓ– ?À&îHH0Œ¿²…hâ‚ö[ÆÒv>:u£ÏnΜ¹ç÷Ìǹð¯#í²§÷^ãÀHJuN}âl^öº (}Ó—"¼é$,%ŒK³·åí%›zßQvŸÀbãœÚ³»ò#ªŸ¾êõ+W™Ö€k¬›ä(K¾ Å¹¼l¥QØâßÈVÙSQ¨ø-žpyãsji"Æ_[)ØXPÀH@í@xRïM%ܰ±L×ì„”uR ÔáùÓœ|ª€ª«Ù†að…ÜìuÓëd–U†CÉJjÆ<€‡Á˜ «E@ÕÕ,ÍØEqØ9α1p]¬?ËæWDLØõ¡aØS=æ±€\²þÕLAŽ¢Ü@¨~ñQ`T ÛUW³ö\?Ö[⾆C¿6—U4’[Y€ «¢¬ÛcG·y!éÇzKh Žsl(ìc¢¬#¼ÿ£xLë# X1Ã^ÍÎI…´Hß!”gÀú?ÜEY­bÖhÂ7¦0C ¤ïJÆ{%o TIàM”Ž*6±Hß!´U`°[~ÅG*T#.é;„º úLO┾C¨¨!܈Uú¡BM…¸¥ïI%Xk*$!}‡HPc*$"}‡ÈÞü¦BRÒwˆôe¨Z*$)}‡H0Þ+yËä=pÝd±™7x?)é;Dþ:<Ø)óçE™žÏD™Ï[œ÷ûÉ,Jbù,>Ô#[À;qÌU+©ø*œ$nØ-nÌΪ“/¡ãâûn¹[ž7ž·r:L§âÄÅ÷­r›Ê’ÂJq;op1d¿bÃ2¹TÜV©\’+7JÚÜ+i+“KÚ¾{Ñ2¹¤-Ø¥…Xù½KÖw˜Søýÿ«8Ñ`2s˜‚àl–.Ù1.¬­ï0Wn[Óvy ²¦Å|š·Ë[&—°?ðvy‡Âi‘C`@•‘›çäŽÛ˜g0ÐÅUF¢s+aøF7Ÿyø:4…ðeá ÎáÁç¡©ƒ›ëä¿]×i<6·¥Âj-ÇæêÔ©s´ùWÄÔðÿPIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_indeterminate.png000066400000000000000000000010141463772530400315610ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¾IDATX…í—¿KqÆŸ÷®"°ŒõÌ–¼©³Æ‚¢¡Õ¹± p jŠêO¨ !ƒþ‡VÁ±† ¨5,¡,õìqAQxoC'D^ÙiQ>ÓË{/ïóá}ßá¾À½OtÉý#:Ó" ðØäSdæxå2}¼÷!€$+óZ5³I:ƒòéäZ€?88 ÒwÜxN|ÔÙìÉ®ÝÝ}®R«S €“ ½Ÿ¤ ÷Ëaö÷*“v˜šI’¦ür˜¥ /ç„r`ì⣞¨€Øü”0¼†*`œ]c7ÓE*um„^3€Q ðãMŸH½3ļ  ý‹½5&ZÊŸmZYNÀÛ£øˆy£ sh'昷GñU PY¨™d‰fhUôÖ˜hNÍ$ VEŸÞ€±CË=~G¿{ €@½ŠÀëd­Ì¡ÛÕ f>€R«©@é¹%bx–sb9pºŠtƇA¸ ÕWi¡DCM-æïù|îq¹¤²D:ãÃ`¾Pm„4µ˜…ù|n³×+hßö÷…ð΃t7;Ý5Ü*ú®UŠ~#Ü5Ýn,ðQÎØàì%‹{=nz{ƒ‘7Ÿ§PúÌ?,Z<˜K%²~Ë®fG,lè&€ƒŽp2³­e81Ä‹#sŸúài©…o¶†š‘2 žüÊ S25d`Щtzò«L éGàÃìÔ(ˆ€iËÖ[ ÂKù0;5*[Ì—÷{=–^“U 'AÕT£ P-@5ÚÕT£ P-@5ÚÕT£ P-@5ÚX¡´Ù_i?ñ2Ç¥½ fxðÎÙwM·û)©‘ˆÚ x+æ¸7JÏmcú/­1 Ö1!ôBÌqo”d+içÍŽXØgmuÇ숅tÎÇxiß4à•#´ÁÐÍ•d‚c³´sÇxÒ[ î .¶šCæk 9¢ÛD'›7š?×™m|ÞÿH6âû_ôá®`t}¨uˆˆnØíì%‹Ÿ|6#^UöWÖÿs`ñpf&qÑ««ì7ŸÏN4µ˜€ÔOYÝa0†3³‰Kå*®ñóùÜDsÈ|¢¬¼sCI²x0“Jܨ”Tõ±9=ö®ëewlÎ^ç_TslN£Ñ¬nþhwzFIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_indeterminate_disabled.png000066400000000000000000000007351463772530400334210ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…í—Á.Q†¿3è®Ò«”Fº«x‰®¤<‚J,Tb/ž¡»FQêΣhC"Ýô^‹Î0aŒh§HÌ¿º¹srþïžs3¹þ»äýÆÅõÝŠã8{€»MÐÆ˜ÚÆÚòí§­½+p–ŒXªëuô ÕÖ«"\OX*™)ÓÈçóI¸v:9oà”êÀ¬1v-¨Äô+‰H¬`© ê< ã@þAίڮX±g~‹·œPœÈL™F’æa=gðsÛ\°^¸¤Ê¥R.÷à/#~G)@ ðëÓ_\¶õ6Âýfî>–ýbAÆÅV ©õÂÉæY„zS륑~B±%¥î±ìýr÷±TJJÝÇ}yüÆöqýí¤)ÀH†ÈI™5]wÞ_v#ÐÞÀ)O `ÆÃÏ-n°÷ú#2ÆÔG6êWmWž34Bo¸±ÔtÝù²{<´2µà[Ô`RcrwãóÁ$ÐÛhfs„^¯cª âFf©^fµ„Mz{3IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_indeterminate_disabled@2x.png000066400000000000000000000016651463772530400337760ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+gIDATxœí›?OÛ@ÆŸs5ZÁ”¡æ2”"Pq•H!R€ÄH‡"ñ P·†¢"µTúç ±ÁäD ªSh;ÐC:ÄÒ $~;$HŽã”$çøHs¿í^¿¹<÷ؾ;%÷‰¤“aõ$麮*þÀ4AyÐ0Àît«Õâƒ]t °=sÝÌç6¢ÑháÚO]—Lc |Ã}w„zÆ!€g£aíó¿’”Zˆˆ%Ó™E;m8xè°“L DTóF×4 µûu ×-‘æ-oR»™µ.::“Lcvlá3{©±•ÍÏÌÌÝTÉK<÷ƒ}½¦“ ´  Û–2îô:T ëºÊÔÛ?l}¢ b6¦iY—u·„„aÕÖÄ,áCÊÿ°OŒU¯€âLÛÿÛÏŠOÛeðÓ´lAÅ,€3K¸_ñ¦í¹U”–:k›-…B¡_îËl-1M˂ђ5fà8 ÒpEB[n‹ó VP6m¡!{Žƒìžµ•Í»ªÊC´÷Øsœž€ŠÞM›í¡Z{õîµæ> Sˆ i€h¢‘ˆ i€h¢‘ˆ i€h¢QÝè$µkŒá€¨ó¿ÀwÆð<Òì¿[6 ÷Jg戰 `­<ÊßñÛ©tfŽ·3.tý ‹@ŸxE4 >êúAO\0î1€;<}pr·¬¡i:~ä2€ò/.\ÒÒ e MÃe@4:xÎÀæyúàÍG£ƒç<}p¿‘ðÈ*c˜ð ¥%ªÕ\-ƒ‘ðÈ*og®ìÊë1÷š,9 Š i€h¢‘ˆ i€h¢‘ˆ i€h¢‘T‡Ø¥µÇ}^‰q›jí•cœIZ[Á`_¯»²¼ÃAû‰=Çé Ø³¶L&]Uå!¤šS¶Ð¾=§Ês½²MË Ãº¬­å$ #b¯¬1ûØÌ|n„Ÿ–P·ZÀZ;™`9,m=1~hæsö܆ŽËƒÑ+(›7ù¸<©æTùÎ7w\þŠRµÈQ0‹£amÅéBÍ}@$ôhÀbË$ya!y[+¡¾¢)à=J58íD]ESM”Ía@ÏÍ,›Ã €ýFÊæ$Igóé| ì6åÎIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_indeterminate_focus.png000066400000000000000000000007651463772530400327740ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+§IDATX…í—ÏJ#A‡¿êÄxÒƒâÎE‚ÅPPö²ìSødÍi1>‚ö`AãE|†¼€° /°¨ôÒ‘]Xr2b—‡Ì„ÁÄ‘M&*8¿SS]ôï›®f¨‚.y˜<°sîA ˆÎ#1ùÜ¢rbRZ<_ð~= ðyßþ6ÛÅ$'ÊÚŲ÷³ »WWÑcàŸB>cê•ß cãp>¸ª»LN  ×à&ÒA’ ùË%ï(ã@þ‡eËVT9tR¾˜fV£ædL½§yXæî¾â{Í4c¡ý‘mOtö}ô¿üÔàM”$o~)abß®lÿyvMaýrÉÛJмñ²õ¶;0(—­×1Àk(àjѳ «@­ƒ³k ù«EÏF%½øüFÖ±½ï$ ÀkÜB£ì•ÙÔÎͰ¿¬¶¨œÔ]&×+×ß—ó½NƒXóGdRZtޝ¥lÙŠ¹»¯„z¸®4µs3ìúûrªlΤ´ìµLŠôîmaèÆ8€ÛyÝ át¨Éþat¼éšL§-ùßæ>ß;-ÉÀRT7öÝÞÈënÌæfÅa1wYÛÿõðrƾ²Õ †Ïï³ç¸ÀLÍ–Iš9ã½¼ò ‘9ßfÐMGŒcVösÈb•¾â¹²2ᢽÆã¶ ZOx'ík_ NíŽÓkáƒÐA [€l”²ÈF [€l”²ÈF [€l”²È&àÅ"WFŒV"¼pÇü_ƒ à+3ÿìÓ“GFðÉôa@üO¹ß¸A„ÙÈH¦Gt1!êF7ª™ø­¨ˆRaâ7u£Õ"kpnw÷€ "kr1§¡dÎüGPÈ€?••Ÿl{¤¥¶sJFÈ€åÞà&1õ‹¬!1õ/÷7EÖ~R}¡1f´ø‚ìå7Û`[ª/4&º˜'ç€Ü~,¼'Ë@}e 2@¶Ù(d 2@¶Ù(d 2@¶Ù(\úv,­I®(pjß±‡8 `¤ó› [F­·ªÊ‡‹öU{Œ³P’x.¿Í¦Öî±®²a²Ö‘ß&ð¼=ÆY(I4aé s¨>aèž«ó™ú„¡ÌÁü>Gnp1 ¼šèûá$P0À?M&KÛ*Ʋ¹Y)ª\ž¡Å52§Or¹¼ÉZÁ,¹\þ€Hb-ö?\˜ÅRBÃncÏ©ûú0bþÉ* ÌL©è¥…Žyi ¯4z*ÍŽuiªøksÙ’óœÄksÀ*狹6§P(Î6Ð~(MS‹%IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_indeterminate_pressed.png000066400000000000000000000007141463772530400333140ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+~IDATX…í—ÍJQ€¿3ÙÒ‰ù"™RÑ ½B ¹ rÖ#dÐ"ƒ6ö£ø ¾@PøÓ‹¨„KqN gl(Ig4h¾ååpÎ7÷\†sà¿#ßÊ-ÝQ8’@Ô£:] .PHÇåy¢ÀCSOE¸'æ¦ùô¦\ý¸Õ]Cy>€Ü Oíh[Þ½¨z÷¢ë+«¤€"°&°gßDÈ2”¼%”ËÄ¥êEaëCªå–ŠBÅjñ€áˆK úÔ¼,îDL+·’°ÏœQ‡­/&ämhÂÆ8¥KM xlê1ÂþeîÊyfKnÝ‚\o T×ÂÍ ÅÂÅR]c3 ,WlRÚ('@o†Ü=”\6)m· ©oÀê¡kçáo· -Ð…áéW±JC#(qukzõ5¬ÜBÃ>ýˆ û@±ÜR“Úh†›“JC#jR¸L‚£îÖbRÀ¿·1y1±­fJÂ9½Î…ÒAhŒ[Í>Dr ´PéIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_indeterminate_pressed@2x.png000066400000000000000000000016571463772530400336750ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+aIDATxœí›=LSQÇçµ~$¨Ñ‰¬:ˆÆjp4$Œ8hHX›Â`‰bœüI($.2@G‰Ôø1à FÔhH$Ò ¾¾¾ ô¾×KÃým÷¾ónÿ÷ßÞ¤ç€ÃáØÉÈf‚Ò/4Ù\G‡z\%4{â•¶eV€Ï*d%ÏÓ…e&ÎÊêF/mh@fNÛ ‰DfµæQntŸ’gÿ óÊ=PUÉÌi?0Ss“PŽ3#¯´OUË~Ñe ÍÒ܉C[5ánfŽ[eŸ‡ufæ´ ˜)êT¾©p;™gjï";;%­T3ÆÇ5ñ«‰ÆU‹¢ " „œ[%¤_h²iïý?{ç¿s\ém•¥´GÎð¬ÖïJðDáÜz§0¿ð“–àÆX²šëè¬ù¯Þn.×Êäz[eéwŽ+(ßÖ;•£ÍutcK PKEmH_m‘/±(‘ÞVYÂ#íï Î B (œóë$óLE/¯:$rLúÛ¢œ Æ„ þÆÞE>F¬«j„h?Œ 3 è†·Ývû­¢½äöZö°SpØ`g€m¶qØ`g€m¶qØ`g€m¶IF1ÈhVÏ+ÜG9Æ&ÿk0@w"ÜìJÉ̆Ñ`ü Éê5U¦QZˆò>ã¸*Ó#Y½f:˜‘™7zP”Ǧ"*E”G™7zÐd #¼UÎûMÆ0ä@ACÅìøMÐÈ€|’—Àˆ´T‚†Š12 û„|WáºÉ&¨p½û„|7Ãx ô¤dL„ À[þQq£ïD¸Ð“’1ÓÁ"¹Îcã3Ùn´-À6ÎÛlã °-À6ÎÛlã °-À6ÎÛlã é[ñ7ÆÇ5Q%-‘¢}%fÀgãWQŠª&!Ú?cJ%…¬¿½êq1b]U#— ÝßVáu0¦4Q2ÏÓ¢¶28<«õÑË‹—áY­'Ï€¿/871`a™ …ÿÞâЮOjÉ„µd颌qa~a™‰`ì–ÒåñH'rLnçtù\‚vò Tœ.¿F¡Z¤æ &Téï9-CaÏÊÞºR ©ÒŸ¬ª }ݧ¸W.`SES 58µÃ&‹¦*)›;É߬ëíX6÷I…×[)›s8;›?ÀW ÀT‰IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_unchecked.png000066400000000000000000000006011463772530400306630ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+3IDATX…í×±NÂPÆñÿ¹$0R—6Œ¦,M´l}xžguž‚g0&>A7qèbg 8Bb ¤Ú8x¿ñ,ßï¶Ë9ðß#ùA«Ýé’e·à”Ô³B‰1f4{}> hù×CàX£’ úQJ½JÑhÃYúöP´ü°ú¼dHžN¥”ïâù¡kÐ pƒ˜ÞþK˜ƒRÀºŠr€y:]dHØ Ÿƒýü"T’*Ê HT€SÚ?ÿ-Ê ¸ø ð'± ° ° ° 8¬PiVÞ(8À²PbDÏݪº=?tQи0f4 :©á^^y»µ¼ŽÔÆûyþ0yî B²[ Ïàl_NS‡É7¢Ýén÷v‰8Ú^ÏÌ4Fjãüifó‚f1§ ×IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_unchecked@2x.png000066400000000000000000000015271463772530400312450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœí›±NÛP†ÿcK"šØÚ©R öÂÚ¾E¡*RéVÔJÐŽðí •JÇ©•€· +‹ b¨@b &R*e K9°Á±’R’ãˆûM¾÷\[ÿùsoîr P(n3ÔÉ¢œmgôžfÂsL]UöïÔìcól˜ÖKŽSm÷R;(_°g5ðGŒ‘Ù#ð Åã}g _±®““ƒF¥¶`® úzÉW/;4ííÓ¤`«mLF¥öÀ›È¼ â_Ü c"4nTæ 4΃é)+š3*5xÀ[$ì„Ä/سþšúCŒ…âû3é#)ƒÌ1ë%–Ü &ôúxßù[ÈÙvF¯òïË3ÏåÓú™]>Üóº(úƹÿØÐ€F€"gèQôQ‹¾¨Ÿðtø˜Þ÷[òP>ÜóÀô!`R•§¢ëbøW]€ëoû¾Ä;ppƒ1í Àù=þóÒ毂ý|h<º É3xh€J]‘ÕCšsà{Ñx’WcÚ®ºëÉ!ví'p«PH F -@e€´i”Ò¤QH F -@e€´i”Ò¤QH F -@e€´i”Ò¤QH F -@e€´i”Ò¤QH &É€zðÀÜÿEr¨GãI /ƒœë†¨^ÒœÅãqv‚&z†{ R ù9øðntAÌbl††–Y˜˜îŠ´`ìUŽ3°]3àl˜Ö ¸¨ fÐÊ݇}wF<É3x9ûÅÒí (9NµZ K×È5ǬôÇq sÌšÐuÀhhz)©…¦UBd¬/ˆw‹¸Ä¼Õ•ÒVEÊ Mçü3o5GiÕÛwÞ!¡î¹UÇ{Ù¡y£RšM°˜ÈJã6 8ñ÷¤U/;¸€Eß4M½ÒÀŸú­iŠ"@K×oš ‘³í Uyê¼ÞžÆýªë¶ÍÑÀ» lp†6:i›S(·›¿ÄÅàºC–8eIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_unchecked_disabled.png000066400000000000000000000006161463772530400325200ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+@IDATX…í—?NQ‡¿y <Ã^kaŒ ÜS`­ÒÃ)8ƒ1!¨Ñ%Ë^`ï@–@vÇÂ]‚ü±ÐÝXø¾rÞËû}™×ÌÀG¶ £ñ¤i½@5§œ9&Fz—g'^ü «Ê È4‘÷<ÒUõÄ­Ý‹óÓ»§×qKÄ<Ã’ÄmÏó¦y„gø¾__©3®#­¬fm"¦²("Àó¼iIâ6°tbídu³q§¾)D*4ö Tóúóï‘9PÛ'ð'X+`¬€°VÀ l Ì?§×bQÕ*0Û'‚¸¾ï׋ OßvE w#=ÐÊJAà 8NÇòrìH?«YLžß‚{àXQ:@þš´í.PæÐb’1OšN¬tt®mŸÿ™(aìH{5³|=§q6!¶ÈVIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_unchecked_disabled@2x.png000066400000000000000000000015721463772530400330740ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+,IDATxœí›½OQÅÏÙð!,Vjìmi6h²2–ü‚ÑDí$š€–úh &j©&’ˆÿÀ&&ÊgX² •µ‹$Zñ›= Ë0;|Hœ½»áýª—ûîLÎ;óÞ¼æ^Àápœfxœ¤Tj.^ß´Ñá& v€­j"Öö¯äe.€ø´µÚð±§§sí¨‡5@ǧfï z å¿I-KŸz×»Þ“ÔAIÉdjW6sÃú£ÑW¼9{¦f ‘Hü ›ÝÆ’86~IàAàmó'Aý””@ï‰!ƒxÐuÅ8п²™ƒ¤‡a;!tŒM¤ï‰zë ý&8è%»FÛN•Àα½-hÀ¹Ý8Åû7º¯¾ æ—JÍÅëãß±wæÅò5Wø~xWÛâÀóK„žøB­uMë½Á¼ W]q<ï%»F"QX¼äµ…ÿVŠÇ0j÷ÍNTú™? ’B ¾P[0'͇ÂrÂÊÊþ5\ N‡°w5VÚUwk(¹öà 8U8¬Xã °`3ÀZ€5ÎkÖ8¬Xã °`3ÀZ€5ÎkÖ8¬Xã °`3ÀZ€5ÎkÖ8¬Xã °`3ÀZ€5ÎkÖ8¬Xf@nw@²ê ¬!œ+“Ëî=æ(D••ýkøœ+“[(óè–t¬ž‚JD‘G·/´Ì)5€øäwŒOÍôE¢® |NßòWŽ‹ æ”°µÚð@±6Xˆ ž™©º£ðåËìEŠC¾Pv{µñhzz:×(>Ý‹èBMŽóc“é;Õp$ql2}‡µúèÂnœâ³°šÐIâשô«’na1L@X®´*R’1ÍÈ£Û¿í€Ðk/yíQXÝshÇIe2™•Íö™@t@…—“¸„’OJèuüLíàAEßG7MMÎÞõÕ×4•¥øìÄMS~R©¹x]ÓzïN½} Uר6‡En¯6ާmÎápœnþÅ傸½4IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_unchecked_focus.png000066400000000000000000000006001463772530400320610ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+2IDATX…í—±NÂP†¿sI`´.”Õ C_ O`"ïÀ¬ #Îê ;Œ˜ycâô:(;íB!ã@k*Û8xÿñææ|_î]Îÿ=²p>‰®npJâ$@ 0|¿q_Ž \Lâè°BÐrørx@aðví>´ŸâŽ1ú ¼n7Ú÷Zq9ðtþxÑ45™— ì%LvÁí«*àó^+Þn´ ¬ú_ÜÜ«€ç%€PP¿HÀ)ïÏŠ&Šœ üI¬€°VÀ X+`òIº½Vq] €×/šU¡ÓÙž"Á€Âh˜šÌª8›Fnº–×FÙù÷b2Qî5»b’”ƒ‡]1©-&YÒjÖÔÏo¯¿Â£KE…Ñ~5³ùÀe9xê¥IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/checkbox_unchecked_focus@2x.png000066400000000000000000000015511463772530400324410ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›OOA‡Ÿw†„‹Ò"^ôÐ&áâU¾…`$/B£‰è>žA#/b¢‰ð-ðê…bH¨WJ[ôBb€Höõ-Ëvù#ayÛ0Ïivf6ùÍ“Ù˼àp8®2r–Iýó¥Ží]oõ€Üz€–x£ý7{@tñmþ×å‘î?§½t²UÉÌnލèkàÆ½,6D˜X{šü„ˆ7éX÷rÚº%•i K¼Ë#שÉß³ò7j0z«ÊÖlå-0v¤ò"|S¥$¨ñYÏ"žݪÜè e·¤ªÏ¢vBäÈÌ•GTù˜õ_Ç c©/'m§†@UÒ³åGx2…r­Ú-“µÑÔ|xz€þùRÇöŽ8ü浨׿šíÚˆ/õÅs'·ycOüeàúAW1Ñ®™ðÑ ¿¸½ë ü᩾l¶Å¬f»6^ºz¶w¼Áð¼:ûGÝAò…±Ô—x"ÆÏÏÑäg…üaûç|up©á¿ù“Q–jHoxJ„zª Ê1E»4‚kP¸P;í¨;¡5ÔûQ®N€ukœëÖ8Ö¬q¬XãX°Æ °``À'À:€5N€ukœëÖ8Ö¬q¬XãX°Æ °``À'À:€5N€uk¢ìUŠ4½ ÐöÂãQ ,Sq„ºL‚kX£+Õ–¨ž©¦ !Qjèð”zâ-֚ЗùPŠ-`ÌdæÊÞ÷Âsê$Úü¯@ín°ªLßž+7ݧpë]¥[‘©@W1ÑîŸ.`y¤û®®%ŸÎ•†›âsP•t®4ÜÚªË@Wµ[„ɨšè©Jz®òžPµˆBÞƒ%Êv‹Tσ”¡‚ €™ÂhòyÔ½çèŠíÌé‹-©@@‚@ŸBŸTŸ”ÈT3š?îÒ÷éES*UyCóME˜l~奼IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/line_horizontal_pressed@2x.png000066400000000000000000000002121463772530400323610ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/line_vertical_disabled@2x.png000066400000000000000000000003671463772530400321160ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+©IDATxœíС€0ÄPÊTFG تX6øˆÄº¼Œ qÝÏúîó˜CxìâôO@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- yjÑ€1‹^ºIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/line_vertical_focus.png000066400000000000000000000002061463772530400311040ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íÎ10A&^0CTPîõÿ³‹²z²z6o3¾à9Æ“ÊÐÒIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/line_vertical_focus@2x.png000066400000000000000000000003711463772530400314610ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+«IDATxœíÐ1€0ÄPЉ*À¢°†T”Ÿ!Ùnº¼Œ q\ÏúîûœCxìâôO@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- y`‘€¢fA$IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/line_vertical_pressed.png000066400000000000000000000002051463772530400314310ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+7IDATX…íÎA@1æü{@¢z"à™ý·“ªE=IO²ùx›ñE+¶ÜuqÍIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/line_vertical_pressed@2x.png000066400000000000000000000003661463772530400320130ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœíÐ1€@ÄPOB‚u×âàS$ÝT“—9Ï»Öwß׌ð8ÅéŸ(€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@³l¡€‘Þk:IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_checked.png000066400000000000000000000024151463772530400276350ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¿IDATX…å–MlTUÇç½×)ˆòQ§¥µe:0N+¦JÂE%E>4ACb$AHŒ &(‘Šuc‚"~„Ä]AB# ’HÊJ ’ FÚ)m_¡†FS„¶3÷¸˜×ñ 3¥ê޳{÷ûÿÿνï¾sán)$¹¬:Z¬6ÈR  °ººNXj7v%~»ð¿ç>²P,m}jœº§,•-݉³?ý'€¡úi“dè `­—ì*4Gl£‰¤]äÚÎM“J1©*ëY`h¥'q8etýµÎØÕ‚Ê«#áöA`¾g¼Ý­˜ù ÍÍÉ1вÊBu¯¨è@¸l³²»óÜ™qÌ®© ÙFO‚Ì~”›¯]ooÿk 㬇ÃÅLÞ#Êz”bY‹{ÚÏ´Œ PO-ÖÉ?Ð]nGìmÀbî×/ G7£²èN&þqéwןàÜ>£XïÙ QÕ¦ÞD®yYu´‘ ª<<Q.áP2™Ü{›ºí±†ÒêhdCÀq¾–šwJCÑÇ9ôÝÒ@MâôŸ¾×Vi8ú.*ï“òÖ«ÜÑ÷z:bŸùM"‘H È>ƒ2O•彉ÖÃÑì“ÒTº#DŽѭi üï2³*ç—Ï \Ÿ^l¾òëCµÛ^ý·¦±Bß( Õ½åq±F„ó@휹×å9Ίtñr(ŒÏ®© YÂ6¯ÂB?¬xèÑ2ÿ€*Ô¶_Ì–ˆêQ¿ŒmäM…¢B¬=Ø)ÃÃó=’§óh€Xtf éò‚ÍG¦Š¼õœ²Iy)H%mÿ1”ÐD€Jÿý΀ë©ÎÁÛP+wNVÈ8rî4ÛC;kºÔ1A_’¸4a#—ý7RE#Ú=x?¸ €b®Ø†¹Yp˜‰†˜¬¹jYÞvj×ÈX@f]–-’ú’‰õ‚!ãX{³¤Òí9žà8N“G·œúú̱ëmÇ>-Ô]Uw^m;ë?Q‚²2 j̸ÒÖÒ#pdV°xƒ_Ìx‡B¶BÙß›ˆíð•…ëVà\÷…xænõ…5›Ó„º½$žšyqúô°;=°twÞŽ$èN71o­?/‰T5ÝgD¶àkTYÇd ¿¯ç¾™Ô‹Š"ý×öe’]× ô_;:¥$xÀR¸a*é“Ò úk½›hÝq×gjðsà9 ÙíhÝê÷Ìù»ÏÕO›d ý‚2å7Ѻiôª×xìO²"RV]»Iác…ž"ÇyüJ[KÏÀ»Š}¥ä@²8¹®/Å$oD"‘@ÿ ½Øüê“n"öëíyyÿr]ñvËX‹€6ЗœAû|Y8ú:K–äÜ ò„ G_î´bžy—ˆ,Îgc4تªÓ­Ô×kFØm¬#I8·†]Ç ˜ARA«c–!¬¯(Ç’&µ®ïb¼w4quø9áÚEÆÐ€ðÄxòD7»í±cc%tÅV-¨ˬÑ¥*D(G±.Ð.„$¥Ñ½Øz¾Ý»;þ_eÍCýcòIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_checked@2x.png000066400000000000000000000053501463772530400302100ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ šIDATxœí[kpÕþΕ,ůν Ì`3ø"ƒNG#.ï9óI&›H õ®x.@³¶4¦!&>Â>0µ±;z÷‡æ[[Þ°Àë÷ؘÖ0°Š€`VN ü¦?íüø#œ[•¹¹=ÁKÜð…9öÝJŒÝó/`çÎx®œæ,.ÏÒ â÷–åÊgD´>ÚÚŒôˆi`A­¿Òf£‡Á¸Á€&¼  ™íIu$Eÿ˜¶ÙII‰R;‹9,“µ-aB#ßPhàs“X ïýx:ú§WíÙ_B¾Â€[§x˜AoókÂëH{ûg™ø®®n,L8†/"¢+X•¦Qbº¥»3ô×ìÞ`¨ª \Ï„g8µ¢xÌdžC‡Z²õ¯„ÏçsôÛ~HŒû,Heðoz:ZïÇDOËÙ@¸ë‚ø^]üŒ ñ«#áPW~MQq晥öxÁÝDô3%šâWÎäGÛÚb™øÌ4Âåño!ÐuJ#ÝâêèÁ½dè/+,ô«%óËHpwщ•ýáðU_"“†ÝžÀzíËð~"‘Xvº^Ž„C]¶±’&¶hŠÎ™…¢-Àj›U_–‰Uÿwz\c~Ι^ÝýixЪŸ\ah¨+ëï{yvY個1Õ›—””›èû§?–à®ó/ѫ짌Œz:[Ö &2ÔžS ô½[:Ïõ9—ž´p~I™ë`l w¯Y}Ó1`a}}¹Œì°pªàLÄ.ˆD"£™ˆuŸá? ,®fF€jÕ'Áè‚@3ïb»x)‹=¹¼§‰q³Â6NDÝáÐ.Êfž'ßrò™î»}ùáý»»­(óù|ŽQû:¾ Œz+uìfà±hGýóÀÖ¤• ^¯×yœ ·8OaÞÕSSþ547§í¥†p×½$w(L,‰Îë ‡Þ·"Êí \ÅÀðZá§€i$ü´·#´Ý }A­¿Ò&Ð PÅIïìîh},]£1€JËæohÑ” l‰v´hÂT44T–?¢‡ (³"^_\Ü4»ÜEÃý½ÿÉÚÿø`ßñÒy®¸r<°¼¸Æõ§ã½½º¨´Ó ËhhŔē6<`¦yÑ¢À<×àø›Lt»×*˜ùw]àE·»¡ÈŒë”CphÊBb„”ŽŸ6‚ñs峞ì;ÐÒiÔ¸ÏçsÄíx…€o˜ Í„kQ<¶&k—H$2ÊÐüPŒ»Ó­ tÍ_ìs1TÓJ\J~ÈLâÀ˜x„&^ö`º¦Ê0í…ƒ'P˜º½Ÿ\¬ÇÕ €Ýn»ŠñÁÛû¶ö5êöúoh­™¸é‚÷WÕt_f [“¶ª+Ê›ô˜ú݉q…ê‘Ä«FÍ¹Ý E`Ú`,*w`ÂF³å®)š/Ó«“€Ê`°ê¹$¯**¿Ê…Rþ¨òî[cDè=ú€²×ÎqÕ~Ò å¥Àù§ L{z:ÛiySXmð3Ź3ÝiB‘`Rýp‚dJž2%ð«"Þ¡å(áòîû:€ù&bò@uÝ—Ï0"0a‡ú™–j9©cñYj‚j4Mt­¡Ì<"‰ä5FåR£]ýnœðbå“dÎýÈØ)ÿi%âI©Õ^«åè€JUbý>ÓiüT BµQy1F´ÚKµ½iPE" £›€~¶ö´€a€H$2@¹tø|>‡’£R?Pú ÈÊ•"Ó…‚é:HÏÀ°òY Né6§0±Ï6\!æ†ÙçÅ‹;¡ÌbãmmmãJNJ¬Ê¨J¦¹&"Ž˜”熡’9Ó°–£7~ª"¥Œœ´š”çlØvê4¦ˆ–“¦}ªGábƒˆ^2*Ï'ˆ„aÛIÖh'´k9©–šÃF^¡å(áH m gŠ<>í‡v2´ÚejoM @¼P¾G€2}ô•…Þ`Úéf2ñ¬©Þ\ƒðŒSd‚€Ë•)¨9…¤5mk‹1ã=UE)/×òÔbìøÜ“[¶?bDpÕ-mМ(õV—}¤åéÎáLê]ˆV5 ï>Ê0ÍåÄ÷uu½wÂBB¥™€·ôÒãº(°Û¶@}Ô|‘Ë{ŽáŽ/ZSñ(Àoqrz¾'ܪ=ÔB€ Ú¤IÆsúDLzlS˜œ$Úãp5š›Τý:ûMÄe Þw&‡n…IzÜ]øžæ&]T¾Mk¦?jZÿ±»ö¬/5‰ìL \†üᣄä«ÌŽã&×ú¿VÚx$ÝéPÚé mg¨C ûz3•}Z:IÛ¹`èF<0øo¶±’&³Ä, ŽÙn)¶½„þqûø¦t|£ ƒø>µßw{†{p`¢'ô,*ÿ61~å§uð10¯‹v´^o6è€{IC¿Ty`þí±ýûÓj0=u{‚›¾Qa:œ”¼Üʯ•žàAr=˜n`z²3‰ÏAØ4*:wZš^}>Ÿc`̶ À'm „¢sˌÒ\ À!• óÿŠéÄEápxÌŠ8`2u^8v)]F„…àSç†GAèf`[ËœÉiwm¦þ=ÁMßvòyâ0G¬0»¹béŽP¥7x®`n†âFž‰†[Öb—«« gÍ:*3 ¤\ÞàíÄü„ÒFÄk»Ã­O›Õµ|IÊíõߦÍóSóœÉ;2ýµrªòøï`Ð#PŽg„G{Â-wYq`ùŽP¬¿/TRVYDÀù sÃhR4•ίy=öYψeÙ9€ÏçsØKÝO‚pT?$¿ÝSSq3"Kw3¼&·Úæö´opµ¦ "«z;[Z2ó—&Æ%ùåñý$>v&m+"‘=–/mYîhãØÀ/w¬„FEÁ\AX[Ræª(.«Üu| ÷xf~­¡ºº±°h~Ù]ü"@gjŠßeÇeу»3Ú”eUÖëÿ˜6qjb2FDbdc& ±r¥½ª« 3¯‡Þ$ccOgý=Vï)1­ËÒî3Mx @¹NñÀ¯1‰×Æ1²-Ó`ø|>Çਭ‰‰®p%À)Ëpâ ^ge´O‡i_—¯òøkâQ€¿cÐHœw@ôoHìœ ³ ~{œb1ljd‘(.MÈøHQK‚–@¢„KÌ6húCëz:ZvNG?˜|‹€ßäʧè&àÁžŽú¿dÓåµÈõ'3Âíñ_ н–çØw'6ÎJ ?éM#äí£)—÷쥂y ƒWX’¥›(Þ Âs=Zþ‹,¾0Ãiùl®Ê㯑¼@=MœÒÎÁÄÜŽ‰|â‡AÔÎŒvˆÄ;ÑpÛ>äáK±Ì`38‰ÿÐðÁÑëpkIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_checked_disabled.png000066400000000000000000000024131463772530400314620ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+½IDATX…å—]l“eÇçmǦ(3„ T&¸€"©^­t£]ç„DäC£¢‘„@$^xa‚‚¹ç¼1A ¨!1$\aâ“¡íºµ£-„¤Œ ›DÔ ØÖö9^¼m÷nÝF‹Þq®žç<çüÏÿùzÿÏ wºI9Ááp¢FÝÙu¨´‚Ôó@-à ÐHX2Úxþ_ ôôõÕcµÁÒ`õŒ1®-þúoÿSÉduÅHæÊ†œk¡S³rÂ…^€ÑÁÑÊJc¥e.¢ ,£+Öósñ]7›Z½ÞßÊ&êë[(YëÂcvaÝ¥£ÃŸƒÁÌt¤UÕ G/"º¨½dÔZÓ²¼á\Éz{µY1q`ŽÀÑJ7¯x½Þ¦+<Ѻºº*ﮞ½ep],³<àó½%X,6k8Ãi`‰ {›} oˆˆ)§xÞTUÂÑøv  ¥ßRw½ß_7èŒqOLβXÒÙì«/*'jÔe6OFà¢Âq˸: ˆˆªj{8š¨Et³‘ÌaUmtB‘x g@þHW¹=UW÷·c6V8 x¨šbÒ×};àó~ì,’J¥f\ýkè°X`U ÉÛ•³œÙ‚¾o7ÌîIŠÚ¦)0•½=ÑØ~U-LÎãñŒ úŽE»s¬@ §'y?ð$ðçœê{?u¢†£ñÀË ”bŠlí‰Ä_wúüÞà<Âã¡Hâ‰"F2«A8îñxFóþÞÞD-°Óî•þáTá½H$ò@¾/"Šê1Å<[D‹fQùÚ ”±Ìk@EÉ•ÇlfV*¶8bYßäÈ´PjrÌ—¤¬ºâ6¤ê3ξ±Ì…\s^1œS-S¸F¹ÃR{»@æ;{7¯]Ëc?˜?ˆVQ΄b¦1uÝ{ \lI…¬Ì-øD ÈÅÛ'À%g§²º:=ÿÀ¨r@TžÒE¹V¸­:.×¥®üvöç}c+ Ò  bV:“,£Ÿåi}[G%kœà^‘k~WDÀEºÓ’UÉd²píü~ï•E‘¶@ ¡p£TUÖ¨XEšššrÌæ ¤7;ÁfV¹ß¤¬­Ð/ü¾úÝNOO4¶XüÐì[ZxŒ?ábm·óeW,›•w×ÕÕ¥ï©r¯Sa/ÓoG´í÷Ëœ*šJ¥f(bëŒêŽ)Õ ‰ô%£þƆç&Êq(zƃf·Ê˜+ÈEýJÕu ¥iéOãÖBUº£ñ¯ÝƆ–i œJ&«+†31`1*šê·Mõ 9räˆ `ýúõÙÉÆUUÂ}‰m¨~ ¸É,ÍmuÁ&U—P_ßB1V˜ |©é›ƒÁàÐd±SY*•šqõÚÐ>„-À EÁ¦†äĸ)å­·7þHVôð(pE]&}ãP)ÒžhìyÙƒ²È~ŠéZ¿Ù÷“ÅO«¯¡ÐÙû¤bø3ltúA:Áœ0âºPeeGFî2TÞœ«¸æ[ƬY˘~œÔ´µ1¬ÿuª% |w4¾ ÕvÀ_J<ÈYÝhôž¼edi€¶…NŸ^@VÖYЪ`ÿš).„~QúU«e:‚>ßùrpïlû5o쯳…ØŸIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_checked_disabled@2x.png000066400000000000000000000052741463772530400320440ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ nIDATxœí[{l[åÿ{m'a …QZ©XÙ†@´hŒ´qÛÉíŠ`Ï::`Œ²166Ø@:[ÑVH¬Zª± S¡­íø'ÍÊCf±¥¥<ÒÒ´ipÛßo$¥÷^Û÷Ú‰]M[’ÿ¸çû}çœïÜÏßó\à0ã0þŸ!‡ÂHWW×±9ÝÅY9UÀ“!rˆ#èöŽý> È[šÂ?¡kooy¯Ö¾Õ,‰¯z /"q€3Æ©æ=^´'Ú[g÷‰«è"€*€¤DâÝçˆh·0ª©`"Ë&ÕyžnnnÎVKkÕ‰§ h®–Îx_ KBmsVW£GL8¯¤RÓôœ<,à•4  "-yªëJ>SJÔõá¼H}£Òs“¡d†¢œ"‚¹ÎÐà 3¦ -ž˜óæDüŸPº’É9Ji/8¾Hñ µøbÖ«½<¿¥eW%º“ÉdÃ0õyBž/À%l ƒrmG°å/ãñ˜@¢ñž+<°®Ð)>¢#·4 î¯~3Òé´o×î}? ànSíå¤Üߘs·ˆ¨JuW’Z4Ñs€;lE Çéᯠ¿{¥zËA<oÌ‹÷V’¿0ÉR(x#™« ÃØW‰ÎŠ@R‹Æ{Ö@p™­h‡¦©‹C­­½•è/©T“äð< \yµÞÿ߿·\]Z%†£‰ž%EŸÒ”§ùP5 ¿»OS!BÖXKxæpžk:;;õru•Ý¢ñîïòŒÅø$²Ã7†1\®žj‚¤D“½·\ s[È;‚sYŽŽ²Ž÷4 Po?ÝÞÖru-Vg•"OýT€åf™P®i¶¬v«ë€WzzŽñdù:€¿½ÌeÚ+}óÑîîÓ˜×.&x†4h°àv¡l†’ç*Ý”h¼gß7‰G4Ź¡ÐÜÍNu]I¤V¸Ö$ÚáAnv ØQŽscSØb npj9uy•¢éÿpÛS .Ì—ScíÚµuG4³ÂÖƒj°™#™Ã0r%-9) ÇRÄL"h5þT9N…»z.øZ9ü"xMD~ÞÞÖ²±ò+©Ô4OiS¾ oéh›ûH©:%g’"‚ßÙÄkÊi|__Ÿ7’H=*ŸÇøß ¹!ë^BÒuÆšï÷Bà~‹r׺u¯©T’JñI”Õ©ÝãæD,;z(“} ÄMnÜr!"÷Dã=íëë;•œÍüà&É”ºIŸÿ°½dtM»Íâø§`pλN¶Óé´//Þ(ò-WGK¡Ôœ"¸th8·Ú­'†1LõEQn-µ6(ª,î=ŽÀ¹&Q6ë‘ûœ “”C9ñ\á0*¸$šèqí…ýn{ ‚wL¢§44¿·hÄ—¿£GU£ÏÄÆù~ÿ'NF#Éž+^ïæ\pw8Ö]´1°páÂ<ÈgÍ2¼¦·xw¢œoyþæd°¯¯ï!–:qª ,s[î*Ú|VXP¬NAÆFÌV³L‡çïNÆ3Ù[a^(Õ‚YÓN8i‘Åø78Øk“kj:ËÎ+€·a¿€Ï$z-lþÀÎ;€ÎÎN]DûInW$oq*EÐò☗‚sÊ‚è¢fÚTÅì3Ž=~zà±Nœš@0+M}݉¢A³øNMN/䨠§Y ©wìk¹\êX^C( —8´¼ÕwÚÚ†"Ј¯XŒ@sœûµÚŸ—„ÿi3Ô~Ý÷vNAi´òjÀÉy?;M΄!»ïvF‘iV’h%ÏØHj¢§µ‡t@GGÇ~æ /N›ø"ZÖb²äG$ÑŠê8Tx'ª¢ˆó2h~ÊÙ{„ cûlÇbáxú‰DêxL¢‘™3gŽ˜9Âz¢ªkG¹8ñ¡KyÍ .È74L¶‰íœÂAPÃV‹Žœ>˜v*¯%ÅѶ'/'ÛDïÛ9… Þ2? 鲨ÀsN嵄Nåh[,¾²ÅÎ)ü oÚ;Ç •^ ¢Û˜*ak0èÕ‰@Ðê; {kaÈfº¼'¾N¥JN7†a ø„»¿Õ†<æt$?6EŸg­‚ˆW€±»µn‹0'çÙy½*{/ˆ=ÎWÛ|Z~¹!šÜt¬7Ê{‘ÍôÙy%æp±ì¢¼ÀÉX(ê§ÀñĨš àÎÖÖÖŒG l>ËËÅŽÇ‹ÀƒìŒ&5¨<¯««ËyǗͬb#§<ÕÑڲƉBR#aÙ¤ ød1nÑŒ^zÈz“Ê:¥yí×ᆑS¹ºË¼íÄ› RÉÜàvוH]ë%ÌÇ*›Y_Œ[r«”üÞ*‘mH$Nr2lgèÔ 6AèËyp‘Ûu\:öò‹Pdy©Û¡’0‚³7Â:útêKܼ ç¼Ël@ш Ä3>M…Üf `èX·½Ÿy˜]YŠ_2"B’wÚÄWoŒ¥÷àÀhO`6ó!…"ËÏ °“Åí–+Ü=‡û¦x—Y&Äo@Iʹ] â*“h[΃Ùå¼ H$S³Ê³Âk¸ßì±G+Gê=KÏnn.kzM§Ó¾]{†Ö“l7‰ß˜TïivÊ+t @"‘˜š¥þ€i”ä烻æ-X°`9ΣGçCÃÙs \Ê,Nðå17úî±Âg§Õ¸Á¾ksC4Þ½’M¢¬¦©€[æJ™ )¿@"–Œ0Áãí­-×O$A"™L6 ¨JY ‘Xê&5Ër}{ e•[ݲSd"±ÔUX3.M™<éæJßVµ0š"“º”å0g¬høVŽŽŠ²Ä"±î r»EHTè—FóÎJtMétÚ×?0ø\gñ‡X§r™óœ’"̨è8ëÓ¶Ý ðy³Œd»xs›¢Éä¬JtM‰DbêÎ}ìð¦ÊÕ]Vnãq$JvvvêSO˜þ ö.–±Ò«åïokkû´R½å ™L6Œ(ýÇïp´­ø¥l½çòrg˜HªìuW“ûH>Üà•e•$,:!{à­_$%(vIYöéG[o/7ŸÈŒ %KG½!ŽžÊS¤x7€)x±AÇúJƒ‘N§}ý»C9‚ [†get¡ä:ڗ„Óå£ÑÞéÔÕ ßu eD +áÛPò/]Égš¶Ÿ×ëÍ)ÕèÍi“sºÌЈS5sYZ%7)ÊâyAÿ?&â?˜èþ6(@PëÁp‡@îýdÇÖ?§ËÛQíOf´h¼÷BˆºÙÕÔ à]!–©\fU5SsköÑÔÆxïé:Ô"Ž~ìpÊ8Õ| ÁZöd¨uv|<߸á|6öN‡FƒP§CäT3 œ È‘½¹Ùb/Û@lÆ-Z^¢Á`Ë[ÿ ¹È‡q‡ñ¿‹ÿ’K×íÒñ;IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_checked_focus.png000066400000000000000000000024141463772530400310330ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¾IDATX…å–[l“eÇÏÛn.¢“àÚ ¶ŽvŒ½QI¼ð„ƒF1D# ln‘„ ”8 ˆóÆ„I;!áj&.0%ÑÀ•TB‚“­Ëlwh‚¢k¿ïñâ뺯t‡nxÇsÓ¾Ï÷ÿÿÿ{~à~™ xÞÁH©Iä¬]‚RŠP‚`P" aTÎX*í½µþÐÿj ¼µ¶§^ѳ¤='¶½­»¶èû{2PÖtýÄuÉT?J‡ÀI1ôZ»ß{Dz¹ž"Qï\ŒµTTV+Ìqàz"!²áruáठÌkŒÍ1Ð@¿ u³"…‡NïĸCªS,|[v!”WÅfUwmá…¬  ”aÉY @à¨ý÷ížÍþ=®ð]h= yïÙÜV#ÏöTùÏOh Ðp-_ò?• {Bß{ì{2â©P•ò–ØVEwa¯šE¿×øúÝïÝ}L^b¯B%*¡¾Lñy#¥ž„·Ê].*³E°U¹‚rÜ‹iMÑnÕú@k¬LT«âbAu ":ê Ìß{Ê6ö9 fiN°·fÆÍÔÇ:5åűýÈcÌ·Qù0ôŽïK·HeÛÅÜø‚ "²¢»Ú"5`woÛØŸ%}íÌŸ=œœÊ±Ä¦!º'Ø݇jjpk!ò€­Zïþ–2° )6x ¸ž3=Úäf G·«ðJ¶QlÜìN„ªüí —/oŠ>‘a a¬•€ï\»ph8<0P&°˜ä½)ŸÎ?›5Ò9–äy%Ã*/¨ê·nµå] g2ÒɘfÙvµ;aD¿s¤XœiJr9mª+¦ ž }9+¡½É¿%£(ðª=rŒT¤lªò¢2ÇÝNÄo soD“ÑËŸ bÆÏÜ#ä €„WŠR çºr®ºÖƒÓ†¹û†/¸”Aþt~y,CO0ÅP•´¾ÆJ-g8•s¡O'­,K#±u?0•·`ÈcìVwÂcd)€ÀŒ×t8Ьx²ISÇ®§vf'* I;Y««°»«ºhäD©Šª¬rX¤=Ã@×F_Ÿ:Î n­r“åã{ßYŠlo"ýª'ìßéÎZW•Ào¡j_ª6HÛá{+€u†kùÃù_j$ž¯…k@ö0þr$Tewhzá:÷+ZÙv1WÏÔè¶1_C€`óààM£Ýÿ«ÏqëÀB±¤V„åÀlœu¹òñHc×F_Wúd¨[¢@ ÈéPµoñ¸œ:pè' …/z"þ-c$mêœóµbú]U‚ÍÑ-Ÿ}ÆcžîÚèësCF]T§Ô³À ”¯s²¾s“ÿÖ¨"cDeÛÅÜ¡¾½ÕÀc›ç»j}?ßsWU4ÇÊ-µ!Ì"*ZW.<œMQ(޽&è. „UÍêž߯£ÁÇÝÖsý5='þo3ÈëÉT¡CEObko®Iôßñ#êQžËr^akOMᩉ “*1*ûç&¼²F”% ¥8/¨çj r5íÝ5—&Ã{ÇÐ0ã×µæIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_checked_focus@2x.png000066400000000000000000000053241463772530400314100ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ †IDATxœí[kpÕþÎê‘8äáHvic,‰Ó–Г†GÛRPÊc€G6áÙ¦…fÀ  8L¦Á±œx )5S`J‡GfHä- @© ±%“ØŽ$óð#$Ž%íמÝÕjW²¤L§Í÷Oç~çܳŸ®îÞ{îpGqÿÏ#щ¿uŸGRÊB!æ©9"8`9€© !°àÇ"²CÀm¡Êݥέdø›ã5"²à"§Ž3Ìn^Ô';C•ïB„EL@± ¥¦¹ï|‡‚»ž[ÜØh‡"SUÏ3ïÕK²Xa‹&@Mó¾sE‘G„2¿X1³ K(+:ë<‹1"  º%^á$p­Mð¶BåNŸ¤©|¡¦1ä,K§…2…T¦ YMU‚"<À”YÄÜF¨Ë¢u³>*$ÿ‚®ß÷]ªÊ‹f™4‘ò2„/9G’¯î¼µêó|bW5î-+;fâyõb‹²ô1 á‘PåÇ‘>€4Ç®H+€ Ik¥&¬Ússù—ã¯ÅܶvwjÀ"yoAäÁH·ç>¬5ߨù Ð@Åï‹? » -*EZÇÊhhFwÞqsÀ‰ú¦¤Uu¹¿0YÛFàEwR®Ûq‹w>1ó JÀ×· àU†–^QÔË:—Îz;¯xã„¿åó* ùBÆ„K¼ÏCÎs¢·ÏÌ5–’OÇªÄ “‡ËIeþ‘zxˆ†ft%ؤk|[&¦7¡Ž\cå<‚-±Ÿ‘ò¬Áû©¤óÀM]Kª‡sST'î„`ôÏòH¤®â×¹„ÈI€×õÍWu€‰cŽÄ3uÞëK±:Ëþ–ØÏ…²ZkÁ ¡Šv¾¶ÌùC÷Œ´Ûõ/>ùí¤ëÀÙù~ó–Þ“Êeªªœ a•T‘HCA7€nQ±]>Ÿ÷€”@8¾"K4ÖR93ZïÙnåj+@ ÛÈS¯âPNï¨õôæ’Ûܶvw²æ272'ïCdM¤Üó4®”t..þ5‘ ÊÄ©[œ¥1o÷õx¿·u¥¤²ùY lN, p›65 ÏŠ†*ßÊ%©`süR àÏ…o‚á/;B•[r!^•¶˜9f¤Ü©÷®Éæ“ý-@ …¿Óš„Ø”ËßÖLW0_KÁ ÿÃÀ·TÊëÁæø 4Ðöµ;T§ðAQxï©cÇdóÉÔßòÙB 4¦$l°KâOôOT¯¸ÙŽ›+(høšÕÜ3ÉŽ›r\`Æ4sxXê³ñ³ Hß©KlŽÔVî²ê|n[»{‚ëЋ ~`—è8pÅdqn´ £³è¾(˳­ LƒÍ^›¨ä)™yÀ2=RF¼kA,´ä†Ëƒ¾„í(Œ”{žј|þþÄ͸¦¸]¼€V±-»Cq«Nýë× ¹Ô.¹BAà¾@8fú0c¸RÒ¤<§5 pƒÕTB.6tú«þf5÷Lb•eRE!vË]jÌùB3Ÿ FgLjߥP™ú«Ug“űú…RI!À<ÿ@|±'Ò[ñí¨Œfäe0|gpkLìª÷í1òÆÐF ·Û%]tPî°l_)ª@t_œª:2ê”PÁ)Ë6#G ÿ@ìû<–É”Ì;a]"`I"t¹+àÉFŠÉ '(‘LŽªr…e{ ¡.·jO u¹«Â“Œ³Ip¶îÅòÝ/‚RW-úfÆoZ‹tRŸ»@ªœ ˜¢#8Ô~›<ŽØäg‚*ËÖI_és§þÙTƒL!{mtUfV­=R° kñìC´;A÷ܶvío2¨ß!ŠY çŒúçUV+2\…ÈL^Áî³d›¯±u¥¤D`¹B,-hY}žýd×NidÇ•§Œh9™ºŠªšVÊ-S {ló,b)€¤&M38 9f|ª÷aÆÌ©*í–í%múv¤q‚Þ]FŽÉBˆë?«–‹ ’Ï[µ—TŲoÅCî²3ƒc4DØHY`äh‘rÜ X¼)J>ÖÍ|ߊ£RWЙ9b2pÈ›´çïß=‰1G×’êa‚Of¶”¸Z. [–ä¨p‘Φ¨[´ vÜâÝÁ›ú¾Ry:8y?€C†–.Ü{`(¹ÚŠôÅNƒ~2XÕ]ñ®‘—í®ÛEqôx:+¢7Îê`]1*"¨È=ÝË?hÉC—³€¯š•ÇMPeF/5vÆyþÖ}–;>_÷q¯YqŠžŽ.õn²$5PTý&M”§Ì¨¦tÔzzE°Ycš ¤ãq¸[WJ*ér_¢Ã29[XÎo¸ÔÙÇù}‰«µ‡0"ˆ×íÙlÆÍ¾ŒMó÷†´n©^ßûM«Ž»–L&‚ùÜAá»)Á¥vÇqsÛÚÝüVç«bu¶Ó¡¬tÖWl1L†n§êXaÕ9Dj+w%Ýî3˜*>>ȳÃCÉ…v…YH}é­ ]¼}¡8•¦lüì#@„„zÁz}MKŸå ¾ïOù ¹üÌŸX y®±›ô ØÜ3“Â{µ6!ê¨õdÍÁö] Ç7¸nÌ@îM)rz.ßÔ4żŠSV€¸€íÉÎa ˆ°)¥ºWíª?vÀž>v»³5æ§Ò;ßê^¡­5M1¯âThœþ©ž½=p(—ä€ÑÒùdÅy€ËIÌ“ÑBʱ‡›ûô‚Ü.¢<ç,O¼nܵÙ!Ž7¸IcJŠ¢.°»¹’ÓjÅß;C([¡»ÆÖH¨bi!$ª÷–Mt«ùiš_8~³kµ6 —FC•ì|s^®ùÃñëÐ߸ ®é}·åûm ¤Â}·A¸ÚùŒòx¤Þû‹\Bäµ^ „ã¸ËÅÂôõ¾Ïò‰U(æ¶µ»SýÞ'Öš^óõx/²º¡E~ ö6:ý‰ç\fhér‹vÖWþ;¯xãÄáyéÏÐßÀGI—{A×’év…Ü1ä¿ci£#ØŸx”€qˆ%!lRSxð“e•‰¼ã怪ƽeeSÜ· y7!Óµm^Qéº:×·Æ×÷–Íß«J2 “û…xL=älÌç¢Îi ³÷¸øbЬ€Iž@c´Ü{W®÷‰´(hÏX—XŸ1#30¿T!/Aä%tlÎWŒÃïõ…\,”K˜-Ó.Ëe¶Ï†‚7í5­=Ç+IçãüÔ‚–ð†ÿFJ‡¨ˆ¦Ý©/’ÃÇìw§ÒiÅÅ)ª$§‰8«‰tPgr>FÿR“-õwT‘eŸ„<ï’ѪÁpâÇ*ø°óŠ3 zAÜ™î]?ž!oDqË6 T‚¾Ä%„Ü ðô¢Æ&v‰"#ί6ójnéþ4Þw²@YL`‘ÁñÄAŒäËP•§"û<Ïÿlû(v@3Ô´öïH;Ï%q2€9ª˜†Ñ߸À ƒ÷B¸“ªìÕ7¢õ•ÿ7ÜE>Š£8Šÿ]ü0úÝk¨–æIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_checked_pressed.png000066400000000000000000000022721463772530400313630ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+lIDATX…å—Kl”U†ŸïŸ¶€` TJi^HuÓR^@ T£5D¤7D&((±°Ö HÀš–2±«šØ@¥(‰VÐÎ!Aƒ!‚¥Õ˜Цíœ×Å\˜K/3ÅïæÏù®ï9çûÏwÜë°lŒö¨À<*$–³¸ôœR˜Žšr»ü¿U†Fƒ%Æ šØ^]f?ܦfL뢢A§Ç<ãJØð ãdÌÂc®s,7c-Pµï S»©Ü~Ëš@óYÍóG žõ½ƒ´î\b#ã‘®—¼Â¯ìŠëα¦n±]Ș@KŠ}F·`&p87̆õåö÷x‰S±÷²¦Üÿ'ûZ`ЃgªJíü„ÚÎhúp§ 0öô.âf.›ä1H²Ö ÛÌh0èóeoøm Ñ&'ÕiØÇ>Ä s´ä{T€ÇFO¬”˜ƒá€kGs 91™IRc H±Œ#Ž6IËÌL£®@K·üžGø}Ș¿ÙoÅtõ’Wä=3>¦Ž1éA3Þ¯ZÄç‰IÚ/*oð.«jJ­+¦ó½}ŸDiíJM^"`FÃ8Éò%ö ±_R|r•%6„ø :lLÔÅ |ÒC‚€?ò§Ò”µ(ÈÁzD¦Ør(ÈÛ‰‚êR:€KÀ“{x*@رšÈ–­,±¡˜¼¥GÅ2vÙ›ÆÇ-çôp|h&ÁÏã¥4ÏG¿ß%ÇáM 7‹Ô1ä{a6%I<¾@,M'^˜«IŒU“Hñ…“ÆC\‰*f§PTèñß(Z,Å“% ;G27gÆc?+D/Í+Ù6À7^ìdâyÌŠ‰vš9Áµ» p=qpßÍhl£?vÀ%Îî9ŠR‚t1y$ùæºÈvšè‹ÉîÔœŒ*W$:)ÌÀdzÁÏÑœ(pŽåÎ8‘NÀG'Dª¾)¤øoW[n?{c,³@ÆÅÿ£$kÌÑ‘F n¡õ#NfæÂƤ©ï]Dâë^?»E«£MîÇêRâwƒÔ ß`¢¾íŒ¦Ç„›ý6JëZʪ¥£ù¬æùÝÀƒÀ7·§QõV‰ÝÍv,´_TÞà¿ìCln;Çsu‹-”j7fYºõ¨ó8<†qÃDýÕ[2¹”yE»ó úœ±¶ÖoçF³·®[Ïë†ùãÕ¨q¢SpÌàÊȾi8ÂÌ’Qè9VÖr§GTÕ”Ù¯cåÈìaÒ­§G#ðl&ö‚óž±­ÚoÇ'²ÍêiÖzZsÉ¡"O3"O3‘•éœ2Ž¿]Ê&î½ÿ5…¯’Q*JqIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_checked_pressed@2x.png000066400000000000000000000050241463772530400317330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ÆIDATxœí›}pTÕÆïÍfc€ˆVÄvÔ‘hetÍ.D†FcÛÑZ?‹“*²QѪ­mmu¦¬:V+RfŠ˜O`Ú®3ÊÔNQfD,cvʼnÇV‚Rj«õ6‰d³÷íðÞ»wï½›ì2Ê3“?î{žóžç¾{r>Þs.ÆaÆr(iíÕc u 3€Ó€“ŽB9R La/°Wá]QÞᯆÉÖ³dg©µ•,íI=“˜ —gÑÍN„˜´Ç¢$ED‹©ŠU•ö©p§@}1} ô™Êò´Áº#’.¢ßâ #©õª<¤)–OWý K›jè,FwÖtéq¡ \çA3QþlÁ`‡Âße„0ا!2:BUH˜l*ÕLWåa30ÛbîíO1kY½Œä«ç€–¤Î1”­6m³›j¤+ˆ¨¶¤^)Êà _ ÂwÁkjð£…5²9yM—W^FŸÂ”6nEde¾:y0Ú­þ¬0ÇB^‹Ê|?!«“Z†(7Ëú#Üd¡ã>4ÂL[p¶ ¸ñóÎm ê¬/¤3J³Ÿ€õ¯ëÑaec_ ¹:ÉïW'u‚/3Åo€w<*Lɤ¹1=oDø‰íV/š)ïxµïÓðð~6_÷Z ®+ͪžSwS½|FîuG¾µ«³¶ný2p±Å”Ng¸ÏS ª òPçÅ'æžÔãß 'ö³áíÏÅq|ê¾áÆu¦Á<àóˆ)›×Ê¿¼mKp ×û‰/D¹§¥[]_æ$ƒò¤Õf˜4ºqÝÝ‚Zñ¯W'u‚<èÅ)& a¹ßrWÅ®Yá·:9èÜ®±Ï¥ôj¬îp,”JƒÕļ»jHÖ^;y¨š'/'æ~j°ÅôZcDÞuò ×2Qnó•\d(ÜîU>:eÚ~8Sró”9P8ÓaÚêäX1PÍ×€c½8%ÂŒ¶.=Õ‹ âЮœáääŽÂéŽç·s8v\íS^:„˜ëYnÚµ ŽwÃ-Ê4G%ϹŸRg= šû?m+whW¨vrÜz@•íYùħ‘C9øÙ Ê ž„íUNŠÛ4h#eLòæØšU uÏÖˆx vû¬;Áp¼O­|nıA …ÈŸðØ‚áæãPA¡|¼>r§Ál>ÿóFÌÜns£ûlÏbI¡xfŸÛ·P¡²˜†Δa+'·(öŒªp”ˆø -Ä;#•Lv˜ö99¹ëa—õÙÔÜ‘Ó>Ÿò’A}Ú ';*ô;9ncÀ›ŽJž‹ žò*/)|ÚVáÝ`‡“ã6€ÙElI‘ÜFRlòÏ%Ä®¦^õ"h®öœ“€ÁJ^¬çïç®éÒ¼ÓÍhf¸ÝSjið¸WJ¾YÕ@¹Ôf¶8y9=[{Ùj …Ž0˸øÔ[oQñÞÄ´ýÀ‰i j°¯Qööï%éäå›Ãm»(U.÷jlá¹òªwƨ˜Påî†Ù2äÅìšUxÖ-=õÀÁ ¬À…­½ê¹ãÛ5À ”ç<•k›¢ö3A'šU û&M”7®kF=6YLF&ç8܆eõ2B9×oyñÆ¥‹7øÇU'¸û!Ìûý)ÛûDþ¬°ò+{ÛÜòD¯žäÕpÓ9ò‰©\B ‚ 1¹Òï8.Þ§a~á¨ûh¾Ó¡¼hŒ²Yíƒa¸Ìd©ŸÐE3åBÔ‚{ÄLjßMHSç—˜H qömïG™ý¬ÊÇ÷8¸ÛfT´÷¨ç²=¡?Å·~†Ëò3(>DX‹0ÏoÐXÔ)¢ö#|X4Gòjr8Ú XÃÞÉ òktnשæ~–ªÐøŸìdñ)ʪaƒoŒH é5Þ§á!6ç[̯ ¯{…¾èÜ®S3üg1oÛwÞvªì"²©ó°ÉÅÀ\„d)_-þa(½OVVò¼s׿‡¶„®n²˜ÒÌñ»¹è‚D[Öb²û°ÖX„ëÇsA"¾M+ß?³@ºêëÖ›³Ú®E¥Å¯nàKRm Øn\(<>©’[ ýµŠU•ŽnUåQìãÙŠ¦¨ü0ˆÀÙœ¦¨¬UxÈj¸a`ˆM«“:%_½R!Þ§áö$kTù5Ö÷PžëOÙv½PP:kÒNîVái‡ùü0$Ú’:£_ãAçv:8ÄóÀ"GÑ”s×' ¾(kÙ`5+8»XZ•U¡ î_p¶ü»P¿ÚÞ¦•å|å.„£­e ÓµAgóUÙö„.RX…#1)Rx¤<ÃòB.,z¡ù TEL`iž3ÈåwrgÐûDVŒë²t{·Öi6+sLN¡ò± ÏÏ„3l*4ñ> ï¤Nà2®Ü–ái%AFû|÷uùÖn=Q„Àwª8‚”’ɘTe &!ªMeº(ç!\éá3!Kb5Ò3ýÅû`"¡ß2á—d¿ *%ö(Ü;i'OŒ¥Ë;QÔOfšU“»¹Â4¸ ˆÓ7ðŽÀrMÑRèM/”n=ƒØh6iúݼOö£‹ŽQ^Ë÷~84ŸÍu뉆PoÂÀi’Ý®NŽ©ð©*{ÞSe;áŦY¼ù¿pù0ã0þñ_³tæ9Ê=÷IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_unchecked.png000066400000000000000000000017601463772530400302020ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¢IDATX…å—OheÀof’5"µA7Ɇ$›ñÐ1 ‘BÕX‹E¤MTDj¡*z„=(ð¤EÑ«ÁF­,éIJ•غSºÝT»ÉT#]”Ôv“ïyØIH² Éš]/}§a¾7ï÷{ÃÌ÷nõJ’[ººÛ€ýÙ-Ð$KaR 'pÚR{(—ýébUâ÷oKA^gݳ–Ê‘Éìùï6$°%Ù{çm2û>ðl”( 'l£Ù¢]ØÎ cqLØ!b= ôƒ¶G%¾úc"ý{ʼn.Ï ±[#ðÑ í®)®Ñ”Õ’ìyFEß’Ào–1û&'ÆÎ­[àî{SIÛè&à‹‚ÜxþZ&ó÷à%áºnl††÷D9„r],kçTæÜèš®»)¦ ßè;Á¥ô+€©¾¸~³Û=€Ê›@n®XÜþ篿‹¬åOÄôöc€§ªÃ„hI‚~$êçS–5½D 9Ùýè`º@ìÀá [bæ0¸®x2õتˆ¼ èëùìU€ïû³}­„`EoaA ©}k3ðµÍ1óAµàódÓCã@ªµó¾ž2:ÇÙ *_ù¾?[m@U9 ¶ýD™Ð ªßÔ^2@¾Lv­  mb1Q+ ­ld’XA@aѨQÜáÌ”j ­DbÙ<ð?Ær™PÇÄkE¼ÖÍמ"šcsÀ6tÖJ@-+]åæï-2 ¢{j%-׈ȩ2Çq†#»Çéí­«e_I *¸ratJàHS À6e`z?ÔéïÖûÍ$˜4?œ iX§4$@^u™‰š¯mf`ÂQm™Öê}ŒcñµZÍh:§:íÚ{»âc€«Õ%ɘõïþdÄ©×^£÷I²kˆgü[ß,cT¯Ý®÷IôÔ8‘DFkl³‰`08@ýÉnóx<6µO¢¶@¦oGÍ& ``D]–‚ Ýf®P]]]õ*0á÷û'Ô>†X³¢*™–æG^þ¥¢biDï“h<«q 2Œœs… ÕêLA½1L§4EÐ5¦ªšAÖi'´ë}ŒKÝf#oÖûÌH¯]¢MïcH@l¡|‹õþûu+Ü UæËË;‚€ÛÔ)è°ÁIoèóû£ÌxKÓPÊÛô~³GíÚ ºåáHUÉ{z¿„ëLÚ¯(5›+/ÿ f^ÇáÆ}Œ„ (°ZZ Ýj¾Éá^¿Ü\‰yE€ð%µA2ö&vLÀÕuÿC*S!ɸ~;|Ö⬭ÿ*u*S8¼ªôP"ß«Âôkðg͵Ÿ0Gbþ¸:×ÿ¹ÚFÀou E.túÞ`hC ën3Dæ“¡qËwAªÏ^ÂÀ„uâédþ©v†Äh ø†ÓUoXW›-8Wo(càAµ™Ñú´a VÇ­O¸q²L@ RÜ5Ý¡ÊiéðõJ¢/W™¯báï0Cg§Ãán¸àïkŒÄ»Ò9¶“Ö ‘K‘óöÒò³m›Š¬·—T8W9Ëõõõ)«6ªtyàI¨ ¡@Û£I[©HûŒPt ×WTR±ˆ€Tæ cŠh´/_ùjôÃÐhº±ÌÀãñجvç3 <MO俇V–} Á`Zg3ìÂ;,NWû>ÛtAÉhŽt¶¶f/;*\ åòoêíû«œ,T,›ƒÁ÷Ó^ÈM»\ÁÏÑÁ_´/ë·ƒ°IU±T¾STâ([\RñßKƒ‘K™ÅMªªM -/ù‘ÿ 5ºêׯØvk¸ëøÅLbfTÖíý6˜žf @W%¢ÇÇ0º'“‹)ij²VžØÉÌ»¡:¯4cO¨³î¾«»Â‘Ó(¾/(MP=ð&q`£‡2M†Çã± Y™h+€Û6Là ˆxWO íÙ,o!÷×X¥Ë»’!žx{Š‹Ä8¢Bâ´`%À‚¬1ŠFm—•Eb±=.cÅ¢†­†Ä&n°$ť߰+ÔÑz,ý&þa¢þsü @½Y1Á@? uÔý1›.¯Ç쉌pº¼·t?€O𻓠{ÄGž5óŒbÞfr÷ºµ‚y'ƒ›¬Î2L˜ ‰°7t¦õ_ÈâÿÓ1#SÙJ—w¥„ØðZute—¶Wžq+€‹†Á8¢vf´CÄ„þSÈÃ?Åæ™gžy&ù—4ÚÏm¬ikIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_unchecked_disabled.png000066400000000000000000000017771463772530400320410ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+±IDATX…å—_hÛUÇ?ç¦]ªâ:FÁŠ-›e*–èSm³´KšZ7D¶n ˆÈ Ň½ B‡}phÁ'e(РоZlµÓ‰¦IÛ4É‚EˆP*hÖ*«R×?ùå~Im›µKIê˾O‡û;¿óýÜËïÞß¹p«Kv’¦šµ&•^f  ÔW,"Qqt(òÿXU€X<Þn­Âå•Õ+ÖzÎ÷Û¿©àëtº¾vÅyå™ÂÐ<ˆæå’…ÕùU¯×šœ4"zÐX=ŠÐ(ä:5œíõûÛ1@$?$y3Œð k¬ººüA8v¶ƒVUH=è ôg«æDÏ‘ŽïËOµäÅ&ϼ5<ç÷ûÿÞÎx³FGG½·×ïå,ð{$Lß ‘Hì]v˜ZUx³;Ðñ’ˆØ˜¥ªLö¯¡dÖ´ƒmóësÌæ—–ó\ZAF*1 uv ‚¼Ðdó±ªn˜ô€ÈD² å4ȵ\çt%æë!öÝq˜zb“ÉÇ·ôu7°¯>ÖÖöW¥æEù|¾UA_Pepý*¬Äbé»G?êï|·ZæE;ýCÀ ÂC‘‰ÔÃ%Vœã€ |áóùV« "Šê0€`O•`è•/«m¾aÌW˜žR¥@…Ÿv À;[›J ƒjì†}ZM--,kßSüKÎÿQÄý¥B^wËÑ[__¬=Wÿ;H‘}JãÐèliix«ÜÚÊfÀÎXì KI,ðåQ¦y ‚×õ›–ƹ{D„.Jà²$%íºND­`º™`"k'Ty^©««K¹•Õ5ÂÑ„ ` €:·ræÁÛYÕÜTÿ’#¢dv$—iyBÀo¦Ä„²?CýoCË ­UŸa dDª'j#] -Ó5e†æ¸@Í09;5Ôòùú½¥è/É€Žx¼^kµÀgs4÷تÀ-)¯z}ACÃñbrÇãñšó…\,À’<Çå®Ö`ÃoG£(Á€H´û6/¬Êŧ ¤ ƒ'G›ßŠd2é;~òÌ2 0ÅÙNÊêÖ@ý#"¢‹Í]´$U$Öý(€•Ž& È‹ôðG¦ßÿN±y A4˜ïý$0ÁÖ(ØÌsý·›¦y¦˜œE@RE¢Ý!¸ÅÑÔ«”¾±¹±±§˜|£E(‘˜*ilBÖ„+©ö°Õï÷Ÿ.4—*æÀ‘X÷ªO(í©«TçÀôûßñ)ÝLÈF{ ¿2áÆööv£Ð\€H´ë„üÎv8pR÷˜¦9Ph7AR"ñžA>k_È5­Áy?($GA„¢Ýuv¨¶Ð¯´45ÜQŽ»³bŠ&¾'À:+'”;[‚ /´ïˆ—ÀŽîîKÜ k牦ú—…Î@kSÃS ~må(|®££kÎHûŽh€'Í5®°P½IßøI û\~Ðwb9(q íÓ†< …<Ãí;¬¡ÎDÄ]оzK\,\¸p0íåMŽ}DsÄW}ïpûå5€¤ˆàgz£ð'JRZF,ðûXm#)oÛö·‹òí“×€PgW3€€…JT?,Ye¹‘êàA 3¹jÂßΞ×C©­Ûþ2¬Ó‰e…išØOåþ|÷9 …z.'ðU •JyäQ÷d–GÿsèeÞ°PWLžzå‚\±9 _æ6 -U m»øý‡Ý•Y>´µµe@þÞÊ)òÎ\±¹/ÊbÛ&ðG×ÔUšÍ s]YœŸ1­œÏŸÜXn˜ÿnZAíåS§^ãŒË2À[3èà³P ë:ãÆ:DD´8f$k2ËCôlGªN·ÅU ʦJfeÇ8 _²¢ßpÆ\0P»v:ú†(âóÖm 5æÿûóAzœÚ§;c² d¢ÈèSîʪ$Î:µOtFäø¤=HTQklc ­­­ƒÒÊ—L&­|„¶E9&žùË…#@ú¬[i爸€‡«X×ÎÍž=ûœ5&Ë!ì+ª†º¸,ê*€LMM­ƒêsÆdO‚ ¬ÛÂì™óB'#W9¨·1Ùû¬ÛB~Ñ]Y•ƒhØ´²ß“} {gÌ…‚vídÒ“=Rý]>~ÿNÌ %SË ¯¬ © Xd#ag\–çß­uÙÈ´,rÆuD⻯ýòi¤ú÷8ãò,‰‰í)JÀ%nŠ«Ú¡Y^7M3íŒËi€©*jøpçù—ºª°Œ ©HÜlåÜ+6§Cëþ²Ý’²J+¯óuø˜EG,q+€™ê=êßž+6練Öò ;#ßÙ‹]é†Àr"™Lúù‰Y—køÃ`çî‚}2ô4V¹!²œ8zêì·`ì=áaj}¾ø¼ˆI>ä ïØÕ™ÈZW+…öLða+'ÄO@Ö-ð‡öÝ œ†àek¼lÚ‘H\V¢VבL&}Ê—ùì5D¿¨Æóôpûøv؋̰®®Ó<)yuëÖ­Îâ¨OÇOõ=E²ÅB¥”ÒËF*ªÑ€¦¦¦#¾ÈàG¤°ñSµŸy†dEjGB¸3q/!÷X9,/¤l§à„;·C`¯¸üjrí„ûœÏØ•ÂP‰Lâ>PÖÁr2x²%àÿ~!9Š:ƒáήÇ!²Â–@$¢Ï7›fݱ|û•ÉdÒwôTß3¹Û¦‡Ø¦Óý‹òýí9QT•Ø‘w=p“•#Ù"ÞôîH<~u1¹JA,›rìÔ™ÎÎØ«ÓU·Úy`…’íííÆ”ÏMû9 Î!–±Þ«2«›ššŽ›·ÄãñšsÚø.À•>íh~-Uí¹õÚºº÷‹ÉYJ©ìÝ×ð:šÎ|¢Æ+k‹)X¡PÈoõR¬‚½^i”µGÞ=°¢­­-Slî’fñH¬§™Ô¯¸$GóI[(ØRc`{±f$“IßÑ“}ÍY Á r݆§²¼%ÐðÂ(äp¡\>é™FC? à¦aÂR"€„´ðŸÐò/CË ¥Ïx½ÞÌY­'zÓª6mÈtEÌô<@®0)JîÖ”åóƒþ?—¢ßÅ&º®åqÊ=ö äLJ{T¥ñdºCÑw¸_ÍÖ_c¡äì3ÿSášP,  ¢£­¡.é"±Ÿ¢:gÒs6žH?ª°H»ø÷•Ÿ%\jØÖØ—~vQkìÑìSïLÄÖÞ,žá½[fy ÀªvÍ~ yÍ=éuÀ3ÀõÀšTO¹à¹k©êϾ…‡{R8ÆÝˆÀWÃ{·Ì”[ðÚ<_ €ÊSªúMÙá9˜è·Šm…Pë È••G'²ÍÈB¿Ú9ë´œádn寮É}ˆûÀÿo3W@!àø¥z¥˜îÝ÷äÆžÌí1yAþð®<¸RÆ•úl3žïËßUʪì\)Ÿ‘ß¿ôDxî‘ ”®*ª²ÛCHÀ僡IõÌ*o’j)7?zrjÐü2ÖÊ×sVÁvˆÐí¾¶ª\ð¦Ó—‚‚P£‡¼]qÑ×Ö]>¦Âù„N-}™ªJæF¨¯¾?þrö퀫vÐ…æhMê½’$T¥¡7õ&&O^™={X¤$óêA=¬Eù<àÈþáöª[Ű›N_ ÎÜh¦5O^n ý8?oÑ¢tSoºÑU;€°H¨hg$þx9Ei´&ý‚ G€ ®jšÇc¡ŸJ_²,¯;õçš@æß^³]q„A=ƒÕ‰ q’Ó¾{mpÆ­¶â®7°S•æl5 p6“‘ý¿µW]]Œ±¬ƒIôÄÔc⣠å‰åä£\Tè…ÏÞ.µ¨£Ù¦ãÉ:Ç/{DÙR‹÷õám­qAΡ¦4V9R̸wvüw¦c?êz,3IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_unchecked_focus@2x.png000066400000000000000000000042471463772530400317560ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+YIDATxœí[opTÕ=çíf!Ò(ìf!aJÌfÅ Îi§: §mPZ‡V;*—P§u”Ñ@+­Ò”i…$eÚ‰­2¥£–†¶:þ™vÚIvBþlB‚˜d÷Ý_?¤tÞ{û6Ù;I›óíû»¿wîy÷Ýw÷Þ»À$&1‰ÿgp,n¨ïð2®-¡à:Î'q Ó\ ÀA/ˆ^§9Fò(!GšCþ“ÙÖ–55]%$ײÀõ£Ls’À›€z©%äÿ¤8(€Óˆ°¤¦û—† Yæln4Bcõ•ÊûʇŒ9•Ö1Jj:–QãV 9•3 Z)ÜԲֻ׉‘±Åu]nÁ³¾7L˜ð‡ ¤ Àq]´sJGŸ;W×)ÌÑò)R,ŠARnðu¹Ãä<"P•‘µ³?ÊDFwu|Y”¶Àl›â>¾Ê÷`ì­¦‡Š>N'wQõéÜÜiSoÕ +“Ü£”ûÃ!ÿ¯G!@”ÖtÞ²À”QÀöø”§O­›~~´ù(khôÄ/øB"ò$_B¹%Üæ}›©Ò;U¢ »ž"¸ÑR¢„¬\›#¡™miçMWïîÎÓ•z”‚Ç|ÎX&À~OŒw]ﻘNÎô ¨­´°{ ßµ”´SS«Z˜ý^ZùF‰@ÝÇE@ìõ„Wð7p/<2³7Õ\Z:7.-Šn²iü»nÑUã šÙÖß[`Ÿ©€ø"§êûÐ ®Ts¥Ü‚ußáo,µ÷ÄÜ—l½¯¸?Õ<ŽB„¥µÑÇA< s[¶†×ü0•)põÎîEJSGLýoEÁ+-k}÷dcv–.uß§p›‘#qoK¨`ïHuG|æÿ²m¦ÒÔ~à½AÏ¥Ðxh<D(x"/9ÔjºŽTwDt{+€BÕ®¹´UŸY··)2ÐWIà¯ÖCªº¥Uâ®ê°k¢‹Þo D(ßn.÷¶g¢7ˆ©„þ¸ñZ 5árÿ‰Ì%fCcMJ€G“Í l ˜÷«¨à­*¦“O9¨3«O÷¾ l  =ѯÙÅÚàÉ‘»{ûd¨ Ë9‰YÆjê"|ÕH¸×.ÔÖW˜¯ñ{çÔ eÕüM»× Á€¡Sn2rJâpX_Ön/x€±×æ{;o°Æ%Ð _à1P?QQxÊ7î±™Š éÁ)åJX§L0@4\kaŽ8­mÌ 0i× ¬!6c¯±„„c&tŠI»¢\c±ç™®„ãþÛŸ z̬`±5&Áy¦—êq^ÚáŠOÌÚÅÜ6ÀÆe1@âHkm<¡uͼqå)kh4ð6=@Ì‹$ta\üæÏÇ }¦k&v›‰‚y/µN`\<ºúÚAcL¢ÓŠªÒµéYQ7`üŠ|3ay¸°7à_æ:’0rN¸t\e"DZ­16!9f¾V¥N +h.X´³)!ÆJ4o6 [c& ”˜t ÂFkL‚9ƒ|€qÿ}áÐNÌC•h–›8M²†%pt½ï"ˆwŒ%¾Ü7Þ,ì¼æåÞ¢¶‚¬qÉ–ÄL¿¢dh{zBAà2i&ä­C›·ÆÙ iÚ> jøOeܨïð:®2[¨ Pw˜8j{ìBm h.÷¶“8h ¦hqͺ>n(ŒÞ pþåksÚ¼íb“ï èò ã¥ë‹wµÁ1•YBYC£‡ÀOŒœ(l³ëþÀ0´T¼m =nåÚäŒÌì!~Þ·€qòvNsk;’Å'ï¤Ô,ì=%uÝ ëjãÁš3³„ò„‘£à§ÍåÞ„)ðe »7 Í>Dàec¼¦ô×‹ëº 2Ôê8Ê=B×oa>Cô<ø¶WoäÝa]ƒqu•œ›#x-°=l=õ™"Öã}àW5éP刯ôG…r;€Ëœ7qjÞ “³Æ#!PÛµÀƒFN(•©ÛI¹Ú®» ˜O\jsft?lý=faim÷àlƒña Ÿ Wø~JŠ´ž`im×36XT¦èw´Tžµ­”%”54zâ=¾Rn)úcáßòdŸ=+Òë â*퉾 `•¥¤Õ%²²©ÂÿÏ´ò%;:}š‹¿ƒyû>Šåx·Þ7#å…Üôßáq{¢?ÀÚÅb ìPql9^é¦7UŸÎÍÍó°Ñ~X6À‘sjóIAðEM–W_é´¿—^h/iõòÐÌyðDO‡MÝ`ô¬Ö¤Wq±ãý+ñú~3WŽxÞ$ÙHŒA3Þ1HøF¸;dÉboa£´Ï!Ä`¢q3S_C&†MǨ¤}À‘I…€nà÷”Ñ]‰x1D}={‹›ÆyvQßãÝ\+ÞÞ²¿*ÏÛÎvK!Þ >‡Šg¡ðòi\k3bøãŽ:Öîl·Tµ ·ŽÆù xÈ9ÉGEa²ŽmÐWՇܯŒxÏçËçñtðü¦Úâóø±¹š¼,—WJßRLç^h*PPèÉ’–U²« …¾ïË/Ä’}àÿ²·‚˜ÈEÔÒ¸R¢õWƒ¾ÙüS<¿È±n¥jm&ù²ù5§‚Ê­+à[œq²ÀgÀŒçÇUSmqI†ÇvsŒ• ¯õ¾c¸øüz={ÛíZ9âÇ.¨vî_!v×ã©_è·hRÔÎcxcÆDäò5¢ËIJ×ÅxA÷$œÑÕ²ïoæ¿dZ>2¥»IóÆ‹s1!8n0Éôëpdi”Ñâ9¶ ºÈeÃ'=}aûu1å]L&õ¸óž\Ž¿`Ê3{CvâV¾e]ÍFΨ•Uì€ÜÕŒÜÕÌ'73 Áióë ÙÅrú½½í?!ÍJïõÔƒ¼IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/radio_unchecked_pressed@2x.png000066400000000000000000000040371463772530400323010ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÑIDATxœí›lUåÇ?ÏéåÖ ,¢nQ"ÅH\@Íh •´f‹Û¢8ÝÒùcÐR:—Í8L´°‰ÛØá1Vé,é!c™Žd‚Áaí-l.u°°Ù S³¡–ÒRoïùî;çܽ·=·+ŸÿÎó>ïs¾ïsÞóžsÞ÷=p‘‹\äÿ‹“4ÒeN‚E‚ë뀙S“ =@ฉÃfüÙqÙ¿t¾uå[[ÞÐÜ¡kp©‘±¸a„aº0^Ä¥¹¦œ3S˜!äH²æ·ÉxÌ 2ÌØ®Xwx~E™ÅCŒ-ª”X'( +fJŒnÁêÚR¶…Ñ#F€†6]‰ð âþ n.â÷À>ŽþfƒœÄá”"$4HqĘâŠfIÜdðY (mD±ß`eÍ<{s4úG•€–˜æ¹° ødŠâSÀoLì6ñRõ|ûW.±[¨¨/Ê­w‹ÓœãŒ`Ù²rûyîê‡qš:t¢(L!jSa!?¸ÿ{¤ñ½´v*Ú×OÄ“—Ëk•ñä37ר9' ^rJò”Ī@‘k¢1®ÂÞÎ5n6l}UÅN!<*˜(ÞÕWÄ’‡æXo.1sJ@½äÌè`pO è„wU—[{.ñFJC›®šPÀÎà€+øC4Á-_­°žlc9¹œxFŒÕ/Ú"FÙX5 ®ÂÞþXœE;¼vƒO:ìhmUA¶±²N@c»¾‚ñ„Ï(Z8Må’2ûG¶q¢jõ×”²Äà;ÀùÇ¡ŒÛ{Kx:Û8YÝ[_W™ã°¸ÄSñùê2–æãí,Wšbú&°Ák3¨®)·mÃÕ¶´¼®Kvái<Ю^êÆCãjÊØhÐäµ ;4w¸ºÃ&ÀuX‡¸Òc:ápWm¥Ö¼`fê™ÊJà€Ç5ÑP¿W‘Lu3&`k‡Ë<&áð¥åsíÄÈ忇o\kƒ î6ø§Ç<·¤˜3ÕK›IV ¾ïµì¨-µ¶QjÍuö®`­Ï(žØö†&¦«“6M1 zLñ„¨½Ì<ÓËOãçÓqV¤sO›3¾í;†-ËçÙ[¡ˆÌ#µ•v†ä õHºwƒ” hj×'€ÏyLñx‚§BÒ˜w&v³ãèyƒ¸²÷>“Ê7up¸øOÆÄËuön¸2óGU•%¿ðÚ—êT¾©0ô êåWáH;d~Í‚/¤º ’pvÄ\àsrøuè ó̱Rb€·×Né/¡4è—”w€ ê1ý±ºÌŽýÆ;gç|εäyʤæLûÕ6vÈÚÅì Oò`|*p|4ÉçBÁõk7m#UÄŒ@¥qÿìOGP» $蓪ûŽÅa 3N'i/º¤z úœ.9ͱ'jnaÀ`ÐcжvÊ;À''À“$‘ãâ›?_$?‡æóÏ#7¹Û\(4ï£Pàø¨jŽ}äõIîÂ?£jLͼü3XÄ”€éTÐ'ù=À8æ=v•ƒèú¤*]²®1CN@»Ã‘ Oª§€o±ÑÌ7)rA¡díAŸ¤ôñà]ŸÛЦ«BÖ–wê%q»Ïhì ú%%àìÚÚk^[$t0#F)þåžî:‚~é¦Ä|_Q‹CÔ6&~Í2^ZSiƒA¿” p Øœ_j6¸µñ. ]ež¨—_öÚL´¤òM™€³óþ{<¦B'‘´>n)‰q/C»ÑÎñNw¯¯=çI?+,~ì=<ôÜ!]ŽÄüÑÚ©¨ŒïymRuÈ€êr^–0Œ¸¬GfþèíçüŸ½'lNçŸa]Àdð¸Ï(–6TÒ¼ÚxaK‡¦™üKøf<½|¡%½Ÿ#ãÚ`m¹í¶{ýå²³¡MWŒJihíT4*~ØCô§Ø”©Þ°«ÃQÅ?»:=RÀ ›Ž*¸9ê¿Êé~67{Lqê†ÛT9l–ÞhïáðE`Àc^Pü?‘4&{‡£©]_óÚ Vf³m'ë4Å´ðí¸ülR¿±Ç IÖr‡%6࿘ÏÖ–Û·²‰‘õ¡ÚrÛ.X絇ÇËvÜ‹\ä"ÿ›ü™•< ¶7IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_horizontal.png000066400000000000000000000002311463772530400320240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+KIDATX…í×± 0Q YÂÚÚ2xÀÕ²‰’ò®ü ¼V*¦æ¡æñºßš Ã*îi£sô3è|F»¸SÚ­ÁÓsƒo€IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_horizontal@2x.png000066400000000000000000000004621463772530400324040ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+äIDATxœíб Â0Ño†ˆDKÍ4¬@ÅDlÁ4Ôi` SQAe;‡Ä½Ê…•|_"韕Ñ?Øîö‡”rN’Ôzºß®—ž÷[mF~Àë1ŸÎ½î7Y#ÀO3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€¶F€Ç—s¯ûM†¨5Ç$s’y9w½/I-žÎŸ"0íªIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_horizontal_disabled.png000066400000000000000000000002301463772530400336520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+JIDATX…í×± 0Q ,ƒ´°p¬l`¢¤¼+?¯U„Š™‡š‡¾î·fðŠ{Úèý :ŸÑ.î”vçé_Ï~ß/IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_horizontal_disabled@2x.png000066400000000000000000000004641463772530400342350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+æIDATxœí± 1Å^âvABbV b"¶`$$ö¸Š-BqÐA•䌄]ýâ+ñw""ÿLýÁõv?Ô”óòY=íwÛKÏýV6#O’×1S’é}XÏýV†Èŗ¹×~køi @ Ѐ 1-@cZ€Æ´hÐ4 h @ Ѐ 1-@cZ€Æ´hÐ4 h @ Ѐ 1-@cZ€Æ´hÐ4 h @ ЬàñeîµßÄð%9&uNê¼Ì}÷EDZxL"0W)IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_horizontal_focus.png000066400000000000000000000002331463772530400332250ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+MIDATX…í×Á Fa‰Vqæt– }\¢6°”Žï¾«"”LÍ—š¯×ýVÏöÈíq­rô3(|F2“;…¦J ÑLZ´IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_horizontal_focus@2x.png000066400000000000000000000004631463772530400336040ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+åIDATxœí’± Â0Ÿ"LÀB¬Q0;°U˜ŠDT©°CâNŠäâ+¾r""ÿLé}Ááú<æ•ËrÛù~ÚßZÎײëùó$Y–’ ŸÅZÎWÒ?À¼ÌÚ¹Õ|[øi @ Ѐ 1-@cZ€Æ´hÐ4 h @ Ѐ 1-@cZ€Æ´hÐ4 h @ Ѐ 1-@cZ€Æ´hÐ4 h @ ÐtPJ¦µs«ùZ6xeLò˜¿2¶Ÿùž7ñ8>‡±IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_horizontal_pressed.png000066400000000000000000000002321463772530400335520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+LIDATX…í×Á Fa‹kS À¡lƒLéøÞñá»*BÉÔ|«ù~Ý£FÁ0“ûµ^9ú¤?£&²2;E¦Õ5ŽIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_horizontal_pressed@2x.png000066400000000000000000000004611463772530400341300ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ãIDATxœíÒÁ Â@Ñ¿‘R,Ä$'+ÊÑ,Ä2<ÙE<¸àA¼¸»ÁyH`ÑŸ!‰¤VFÿÁùº’,õñtÜ—KÏó­v#¼ZR2¥dÊëÅzžo2>ÀóEÞï{o´ÅðÓ @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ màþá¾×ù&[˜“Üê58/I_{½8¬ÞÜIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_vertical.png000066400000000000000000000002161463772530400314470ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+@IDATX…íÓ¡À Ñ….Ðèô€¡kfRD4:m X¾Ù§Î­:$K{”ú¼@»Ôÿü:@¾”Ž|$Iáp  –ÇIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_vertical@2x.png000066400000000000000000000003211463772530400320160ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ƒIDATxœí×± Â@À}Š@S -¹"wB#äÄ/7ñ¤ÈOjŒì™puÁÞe—°eœ/×[J“W賤ÚZîõõ||†‡nl›Ë'É©”Œó°?ÀÎôhmH2ý¾ÊâjkÖ.ü¿@7¶Íå¿Àw~vâ ) fšŒ¥IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_vertical_disabled.png000066400000000000000000000002111463772530400332710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+;IDATX…íÓ!ÑáT‚ ¸µ÷‚cI¢J™Ÿ¶MZ$}Îsu <ê¶’Sˆ‚Ò•/$é» ? ÿ!û–IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_vertical_disabled@2x.png000066400000000000000000000003231463772530400336470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+…IDATxœí×± Â@À}Š@”B€D´@äŠÜ 9’[±hâIÑ›ÔzdÏ„« ö.»€ý(mð|M·š2&9v賦¹$÷ëåüøíÔF—O’SMÛpq€½Y ¤IÞº¬m.)CïÀÿð ´S]>ñ üæ`'>^“8ÎIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_vertical_focus.png000066400000000000000000000002201463772530400326410ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+BIDATX…c`£`Œ‚Q0À€ÆPõj?Ã:Ù»çvš¸+,£'Í£`Œ‚Q0 FÁ€ŽÆ ºµIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_vertical_focus@2x.png000066400000000000000000000003251463772530400332210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+‡IDATxœí×± ÂP Ð3CD,ÀB¬€(2Q ö`&,ñiQ"Ê”¼Wž\œÝ9`?jœnÏsZ†$Ý }S•1©ËãÚÝ?óÃlrƒË'Ik9¶Ö†i>?ÀÎÌP铼~_eYU«ª_»ð?ü³É .Ÿø¾ò °oŒ"œ›Ñ-IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_vertical_pressed.png000066400000000000000000000002131463772530400331710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+=IDATX…íÓ¡EÑÇNºb›YÄ90I)ï¦ß^ú Iú,œÑæ@~í5…_¥_ IÒw0§ ùFƪIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_move_vertical_pressed@2x.png000066400000000000000000000003161463772530400335470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+€IDATxœí×± ÂP Ðû X„EØQe¢”lÁLe‰Ð¢Èmʯ<¹8»s@?Ú:x¾—[’1-çúliJò¸_Ûë;<ƒG\>I.IÆuX +Õ†,™Þd{S’aïÀÿð ƒG\>ñ Ôütâ#¹6+ÐIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_horizontal.png000066400000000000000000000002241463772530400330600ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+FIDATX…í×± Qb\‚šÚÜ„Õâì¼ëùy-ÊZµšlLhØð> @€ @€ýŒÎÅ×]Èȇ̜ÚIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_horizontal@2x.png000066400000000000000000000004401463772530400334320ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÒIDATxœíСÂPDÑ Ed‹¦Z@Q]P ]A6‡ö¨çþþ›TÕ?ÔÃÛÝþa8'Iæùt¿]/bÇF<š$ËçÇ$ã;à¼>ÿé^• ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ðd€Ç—{U,À<ç˜dJ2-wUÕêž ÞP{3‡ÖIEND®B`‚toolbar_separator_horizontal_disabled.png000066400000000000000000000002231463772530400346270ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc‰PNG  IHDR szzô pHYsÄÄ•+EIDATX…í×± QbÌÁM° `,‡8;ïz~^K„Nužê$¼A @€ €F?£ýDñuåÜM p°IEND®B`‚toolbar_separator_horizontal_disabled@2x.png000066400000000000000000000004421463772530400352040ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÔIDATxœíб ÂP…чÈ.‚à®`åDná‚à©Ü"ÑNÛÁ{ª¿{÷}IUý³A=|½Ýs†ó2b>íwۋر&Éëóc’ñB`²|þÓ½*à'4€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ É/÷ªX€!9&ó”ÌÓrWU­ï ËPìôðIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_horizontal_focus.png000066400000000000000000000002271463772530400342620ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…í×A Á ÁJ} ³ZHê§&@Äñc÷ßË|+‘QdWd—³1=ÂYÞ½4Üp3?#í'Н»EcÅæIEND®B`‚toolbar_separator_horizontal_focus@2x.png000066400000000000000000000004421463772530400345540ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÔIDATxœíÒ± Â0DÑ3CÀ,Ä ˆ‚‰(Ø…è¨` (Q¥ÎCâžÉÏ_IªêŸ uñþú:ä˼â|?ínbÇF\š$óã·I¶ß€ 0=~é¼*à'4€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ ±cä¹t^üÆ1ÉcúÆÑí¨ªö¦øTºIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_horizontal_pressed.png000066400000000000000000000002261463772530400346070ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+HIDATX…í×± AƒŒM³RÈPaÓñßǺ6EuFu:Ë4ló^Ó7ë3Òyù· DúˆÿýáIEND®B`‚toolbar_separator_horizontal_pressed@2x.png000066400000000000000000000004421463772530400351020ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÔIDATxœíÒ±mÂPFÑß Á(„ +&¢Ì„1¨Ø‚±D¥õ‰Ä=’¥çê}¾òL’w¶¨‹?oÏÓÌ\·×Ëùcù;âÒÍu–9Î2Çy…Ø ðóá¿Ï;“À¿P=@+€ @Ð  hдèZô­z€V=@+€ @Ð  hдèZô­z€V=@+€ @Ð  hдèZô­z€V=@“œw%¬3sßžîHòƾ³Þ T {IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_vertical.png000066400000000000000000000002111463772530400324740ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+;IDATX…íÍ!Ñá²ìÊÞzßsYv ITóÓ´I’^v¤\P/}ÿ9ú/ %I’ŽÀIªv žIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_vertical@2x.png000066400000000000000000000003021463772530400330470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+tIDATxœíб Â@À}Š@S -¹"wB#äÄ–›8RämKx&\]°· pm\o÷GZ“œw賦©*Ïéó~ý†§îì?ŸO’Kk—a?ÀÁôT Iæí«¬nªÊ°w `{_ç­úbìòIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_vertical_disabled.png000066400000000000000000000002051463772530400343260ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+7IDATX…íÍ!ÀÐq*APÜÚ{Á±$QUì§µ$I¿ 'Æ\(¾­äT⣡$IÒÕ“¨‚!ãIEND®B`‚toolbar_separator_vertical_disabled@2x.png000066400000000000000000000003051463772530400346220ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+wIDATxœíÐÁ ÂPÐY‹Kñ ؃-xJEéÄ» ¤•`ß«üœcÀ¼wö0; °ÕÏ×tk©1Éqƒ>kš+¹_/çÇwxè¯þôù$9µ´±ìÍb€J’¼7è²¶¹RÃÖ%€ßû(Ï |lMIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_vertical_focus.png000066400000000000000000000002151463772530400336770ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+?IDATX…c`£`Œ‚Q0 F:`„1Tg½ÚÏÀðßNöî¹&îÊÀÀÀÀD' GÁ(£`Œ‚Q0 pOsÐÃïÉIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_vertical_focus@2x.png000066400000000000000000000003071463772530400342530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+yIDATxœíб Â@À=аh€†h¸"ôA1T`hâI‘?¶-á™puÁÞ&ÀÔ2¸<Þ×´LI†ú¬¦*sR·×}xþæ§îòŸO’Örn­M˼à`ú*c’ÏöUÖU•¹ªÆ½{Ûû-fÏ5ÔIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/toolbar_separator_vertical_pressed.png000066400000000000000000000002071463772530400342260ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÍ¡Ñc']±‡Í,â=Š¤ŠŠûéÚ$I¿ 'Ú\Ȧ½¦Pâ‹¡$IÒÍ \˜ª¶QIEND®B`‚toolbar_separator_vertical_pressed@2x.png000066400000000000000000000003001463772530400345130ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+rIDATxœíб ƒ@À}аÜÐ刊é‚"¨¹ HúÌL¸º`oà Ê1çµK2¤äuCŸ3-I¾Ÿ¶Lû°©þãóIòN2ÃÚR ÏšßåMη$éï.\o±õ D-ÚQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/transparent.png000066400000000000000000000001501463772530400274240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/transparent@2x.png000066400000000000000000000001651463772530400300040ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@òÉQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/transparent_disabled.png000066400000000000000000000001501463772530400312530ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/transparent_disabled@2x.png000066400000000000000000000001651463772530400316330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@òÉQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/transparent_focus.png000066400000000000000000000001501463772530400306230ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/transparent_focus@2x.png000066400000000000000000000001651463772530400312030ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@òÉQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/transparent_pressed.png000066400000000000000000000001501463772530400311510ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/transparent_pressed@2x.png000066400000000000000000000001651463772530400315310ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@òÉQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_close.png000066400000000000000000000014561463772530400275710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+àIDATX…åÖOoÚvÇñ÷‡ä°UI$ Gàèäì)LZ› &©T%é){•övìm‡­[´õß2õYôž&$i·@ÛM bm»”ïÔÄ`cìŽË´ßÉØæ÷~ùg0Àÿ}Èß(–ÝO }cð±Ì¾j6jϦ*”ÜU“¾ü-z_ž×ŸdüLúXTö‹ew}Zñbyyi_P\Sæ[ÿØ€ñQà=C¦(–—7 {8ÒºÐ= 7MD±ì®‡âÐ3qÏ1ãoxÝÖéBÖù ±ÂÕgC •…ë¹W—Ýöqú¸Æ‘m]œÕž„—ÝV-‘I‹x82ÙVó¬öSðÜFF‘?‹BÌ-æ^zx„Sq×è_ùÄx$ hE!„VãNÅ]“…â6.>à#æ³ù:âf„SYº%Óãˆøæ¸x,À‹EäO½Nûä*Nê8IcG¡âÞÁ´Çð'ú‰Ûcâ[ͳړæNˆAôÀ÷%ŽÃ„[^§}8¿˜k€FŸÁ‹HO ê#ˆAÜÐöEý(q†—3Ùèeþ³ˆ#†ø3ít©V PZ®"{ŠzŸÕ¹EçÄë´N¦(”ÜUÄS`6°Û_‰ÀW”ê|Ö9öº­Ó$ó&ºý¸BqCw m 3ÈžJËÕ$sO\BÙ]Aú9*~Q?Üóº­s×7‚;”l%b…²»Qq>¿¨íù;b«óYç$10!þÃèù}DþmZD$ P^º ÚO¿B´Æ#rÇ^·B„ý8¡¸Œ/šññ b!›ÿñÙ0BÕ(Ä XYºü?o}?)îˈÀ)¹Ÿ‚žýÛø0"÷R±°è\vZ¿öwøG¤ûá¸í|HÜçÚ™í0üœ˜µžÝt5,ø—ü}¼öàCãq@CÐD¶5xlÓà㵡ÝiÍýßÿ$±‹¥N~5íIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_close@2x.png000066400000000000000000000032771463772530400301460ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+qIDATxœíš]s[W†Ÿµ•Д´N?œJ¶Ã…e¥™‰e©iCKÆIã„Ú ?€áGpU.à‚ÉEoú7úh:‰eÙ()P –äÌ0ÖDZl7'©ãíÅ…­ÔÖç>Ò9¶™ú½Ügµ×ój-££{ÚÓž¾É’F‹áDâ <Ô_L€kvŸ|°üÏLi{ËëLác‰AóDßÞ©êåÊûá­7ÔÆÖÐ{ìØóûŸ|ëSàDÍ¡{ÖÈØò|æÏÁ”í"ÑáphËavÕÝÍçW6/›ÚûŸìŸzx€CÆêdøhâ-? öSMá”ä3<ûËÚå:@.´Ø£g·šÐ¾*åbíR϶٫ÇXŒ &ßô\e@ê‹ÆO¶…PÔ.Õ èg{öˆ±©Ý`B_4~‘)ÚÁ¯«Ž­Î€î»ÜsH¶ã&x„_ úMíb7‹×çÕš³¸›°#ã°ß¾í×µbEÆn¯Ï×hxL¾)Ʀ€‡ î©Úw—ŠsuˆíZ}C#oSÀ á÷­ÈÙå|æóF›»Ó?á¡°»LðÞlÕRiö/ÖÈY`¥],pHĤú¢ñ“±žÔK¼¤p„7ÂX;xp耪ÂGo«“8vªg‹¹/\ó·R,ñºªN/:„ß7ÂØB>{Í%·³áXâ{Fõ*Ûh‚WxAÏ• ¹?¹æ÷d<5axÞ!ü?¨¾Û© á:æ:0:0Î,²ó²ÇvÀC‡@°&ôÇ’'Tmš€áÁá*ÐLËùÌçFî;„¿Lm\ÆZÊ;¼õ4óµê¸ªˆ¼m•«øÐ ÁϹüxkªŽ; ª…|öš çpï„ÔÆ5}‹úcÉŠužyÔœï|耪ú‡âßWä*ðœCø¿EäL9Ÿù;ÀÀÑã¯Y ¥Q^j{¦ò̹Åâì»,ðÑèÌ‘'v§àÁgÀ£ ¢+ª‚¸ÜXÐ?4üÅ\Á­ÚKyˆÊùÅRæ¾äÛ¤@ M|¸ 4S¹0÷jÎuF8KyHˆŸv@U}ÑäÁ^A8èéÄ*ü|ö÷•lƒ°n‚`'UÚ>rß>ÂÈXÐðàlVH++Vä±k¼Š<6T\Àt­À 82OTŒL êòôQz¬†ÒG¿dmðTá—;J Ü5R9½0㺿•}­À:`ž4Â(/Y ¥‡“þU¶Ut@8:2bD§Az}I(Ü5;ºPš›õ%ß–Ô>˼®m”ñŒCê;ÆÚÓ~›àëxüäWU8Çú#÷¯â_¶Æø>¾u@x(7Øgxì{K…¹€HläÇ¢||ÛáÜ;!«£7K¹LWoȺ¯j§Lèz¼Â[d¼`)ŸýTEßÃq*F¦ Æž ®QW¬Ã»Ï¼EÆ— ™éfKùÜï¼™@º[:6àkx;„¯•‰VðUm2aµ}Zé­ÒáèȈC 3trR$–µ3¸Á?2*ã ÅLÚÛñwDåÚ¿³èm«2º\Ìf½ì°ðO÷>%˜Ëh‚'6à§W»‚º§W0§– ™œk~çï¯ð¢Lt °T˜›±È8Žß ;JÄ]ó;u@$vü¸hhðåbvʵ…‡£ýŸ;¡mx†·zÁox€åBfÚ¨LàÜ :íÒ ­_’ê¾”K9Äv¬hâ´ýêßúl [mÕ M;`Þyæ½4<ÀB1“6*ãÀ#‡ðÃŽÄ’ÃÍvÀ&ø°Ã&kˆ^XÌç&b}“×NP1§–ò³sµê 8òjr R±_‡Ä;_UtäŒ ¿ÅÍ„/=Y.äþµy±n*û+þàÊÅì”(¸Ã+ ¿®]lôðŽC²5Ä\ÜIøªÊÅì”X½€ƒ ‚œª]kd@¥Mž øÙ«Ž5®r)—r1A°Õ ´úT×@~º›à«*—r)D/ÒÒ¹R»Rg€Ù÷ßK…g¯Ã2uIv‹ó¹É¦&(%•Ð¥ÚåPíÂýÛ·WŸ;üÄV"+¤ÈÏ ÁýKë—Üý²p¨·÷²ª‰/‚ÜÕÔìÿÙRþ·vº¾=íiO»KÿŠö)ve]6IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_close_disabled.png000066400000000000000000000013741463772530400314170ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+®IDATX…å–ÍRÓ`†ŸX¨×áR×mmk [*Œ†2ƒÀŒ×à’ ~ùÓqÆ=ÛÐö&t§w .l^ÐNHš6ÁnÏ*“œï}žœïë4ð¿—u/¼ÓÓ[ê8¯0®zá– F òÍ)a/A¿‚€ç“· >€ÓmPà¬aÜ® ;ðÍê¨àÇ~kFØpì†ãØj÷™ê»ºv„íŒBâØo͘x{‘¥k1ÀX‚QJxf5'@ÎrL`²˜ìi‰·—‘ðͪ°(\F­RÎÄ*åÜ»>cY%Îá±7—Q›(æß„{>å5Ú…¶#CÝRaüáù› ƒ' \V".³ýàDÂ/”[Êíš%¾;^£ù0ÚRo?È ‡è–×h>¶‘í {Ô=L'õöLï²ÂS û­§&6ûIœ¥ÄáˆZ¥œß–J QÂ,0@RX,5<“@HbkÀºLðÌ= ØB±µ2Ùœ[ÎmeÉKü$•à§aŠÞ7L£Yó2MàÈoM;bOhéȘ™(æG.pþ¾Ë0„Â9À¨NóïÓä¦Ú‚ðyÄÞ’1Gìù­é4ÙC'pRoßÇ´ßî–r›g‚íšÐF$/Õ$N .ÓBà–r›†ÍŸÄî°I$ ‚O ¯£ýn)·)ÓBDb|˜Dß-8þܾgŽÒÂ/¬õ›s&[dÿ6Tí÷¡H‚c<«óƒàÝ:ñ[óˆµ4ŽüÖ]Gþ <«Dïá‘ß¾ãHGï–Wo-ÈXJ MUÊ…O:„ŽX‰ÂM,^à–óë&‰LÌVzÜÞmSøËG&Ýr~ý²ð!¸€X¾ßµQÀÃ2foÀW3[Uö¿_¬3vÔl=ØXIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_close_disabled@2x.png000066400000000000000000000031741463772530400317710ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+.IDATxœíšËsÕ‡¿s*&2BR•U¶‰y1ÓóìéAXæ!›¿%+² Ê‹l²LþŽTÀÄzÍH=o™¤âß§{»{F §9Íi¾Í‘aƒËË7Ï~çìÝŸƒ.¡rC[î˯|?óñ¬œ$››ÝŸè#ú6–,¢÷DÌ5»ûÕ¯ƒ ø²F£ñø}Ý}ñÊ-‹.VŠÙn‚½OæÖËX»Šp®ïÐÍ3PòS1•Q+áá¯ÉíÃW:ôuO„+~Þ[q˜;u¢J°HP)¤ÿ>ôè°Áhð²#¢—gßK\¬·Z?NYó!ð#‡ÂÇßK­Þ^‘÷p’À§²gæ}?ýÏ£ƒAcÍ/ùÀÅ욪.±ý—g4¥ïô¾, åñµdÇšÙíùQ9¸ã\ÆMBÐ?0ì6¸7ºÆ>|%—Yvip9¸ó8Hжa+`Ä_UvT÷Þ:Ið½” ÞªW%A¹Þ?4 àëGå*È??½sENJü¼·2BÂÇFw¯öXÈd>ׯSžÂo€O€Oßks'¾?ï­¨˜,Â üÖØÝL©Túì¸û;ÍiNs²ò?c/ø/IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_close_focus.png000066400000000000000000000013141463772530400307610ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+~IDATX…å–IrÓ@†¿ggÀÊY+¸W` ƒ¤â$xà©â ,³ÃR2&UœC«`’Ø ¢Ç‘ñ É’ã Å[I­îÿû¤V«ÿ{ItpÓöXŽð²S7ÞMTvüy”W(¿ E^|ª Q‡º)p0QÚ–ãU¦·lo¥ ˜·ÂP7þr{%×úÆTåp–í-(r0ĺ#ÀNSÂr¼Ê(œPUÖF: ã ÑʼnƒI$,Ç«¨Êá\¨ºÍR{D SŸ=Š‘(數„Þ¹PuëÆ~_!¦Ê-ï)"{CŠFâbD Ô°‰òøÖÝR¯èî¢_/Ñæ´²ÿýúDf€r¬.IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_close_focus@2x.png000066400000000000000000000032551463772530400313410ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+_IDATxœí›Ës[E‡¿ÓÎP<&‰%¹˜Í”+ÅäA Ô !N Nò7¤"ÛUP,XÁTlXÎ`YžÍü¯JlKÞoŠç¶d¨Ô,,[¼bl« Y H²ÔWº×öÔø[ö=:Ý¿ÏÝÒÕðÁü?#µwÿ+wÃü¼<ŽH¯¢×ŠòŽ1úìD<òÍj/°bÉÜŸ­•'T8 È‚Š¾rÍyî?„.UÖV ˆý3“]²¯!ì­¸tÕžLä½ÀVîÝCÓw*fØ\qéS]Øô×ìc[çÊMeƒÂ’>Q#<ÀfDF¶'rû}\¯¯Ô °Ç\÷Ë“•ƒU=QgŽöõ*¡AxTÍÉʱ*×5˜«‘‘îáé»<¯2 bƒù}ÂÑk+Gª(¼å0g»Z3º$Äóû¬±c4 ¢ÕÙªX+g‹s¯¹/á¹%•g*«|=ʈ±Gp—°&Ça9¼Ã¶`NE{¾e*/Լ螾K­Ú&¸(Ø'û:?p¨m™®dþ£v ¸Ù¡ü'=’GÞ­uqE°>%ø€õ%ÁïðPëe°‚É3ï£z˜kT lVÌhl0¿Ï¡ÖÑDþö6-ŒâÞÒÓ(<8ì€Û¹ýˆŒà¸Œ5‡':>tí_h"»‘˜"t(/†¿ãÒÛY@4™»[TγŠ¼†·ptª/ü¶kOà7 #ÀMå?klV‚Çð—,ôx M﬘ÃSñŽ<ͱ á¡I¬„èðì^cm*èðàð*°Ùxä]µô?9”ßlÔŽu%ów4*ôÞog¾’¦w@‰èàÌ1œÇ‡ÐLø‰3a—7o+Ò²€®¡™{ œÃA‚ ?Xm;œíïø¸|<:<»W¬Ž[¦¼$*Ç&ûCo6¹ä²õøÄ²„óÀ'½ZÂö¡ÙÛ@S¸…¿,*Gý_\‹4#ADíZ…/®Ãg¼HæTAÄéÆÊ÷ð€€Øð̽Ör7 .\‘c“ñÐ>õû@€¯ -Ü4bâLø-Q9T}áËXy(¨ðà(ј½OEÏ7x|èe¬<”½ĺJ.–% #¹—XÀJOÐá!À#PŽÃÈç¨\Á8}Ó2 ˆ%gv[H£êòémÑvÐTñ)X=¿‡gk“-¾y ÓúÄ×…•؈%gv[%ÕBx€- ©îÁ™=¾-¬‚@ìHävY%ló¡Ý5¤ƒ’ເ‰Ü®‚H·ð‹ ‹u[´@v‚¯<†ŸW±G±æðsÃjekü{;<œÛi¬ŒãÞª}xª¿s :”ÿ›`_®oøHá;‡&âáÏZ[q©´¾ÄZIhùx oDW†Èöu¼¦bÆñ8XHÇ’3»½¯øjZ°ÞùÌÑãñHz¥‚l¼óßž$(©V%4- ,|‡Cù¼Xí­¾D™„y‡¾Û¬’Ú‘Èír¨­Is_Œ MÿE0㸅_«Ç'")Os$§ï5¯‚Ó¨oÛT}ÕùÜËÐÄXðPÜ VÝwBA$ÝÌNðöåh1|9”7¾œ®ÄôA#æw‚5zpêLä ×þμ†íÍôEÆ\û×#–̲*/€§#œ¾u­ÂLÄ#i#zÇã`¬Œw çvºôn( :8}«3ŽkxᄟáKLÄ#i±Ú‹»„´‹„ºG ©ðñð¨CmÓtæP#/U¿ú¬AÞ=Tï8¬(`9|;L´ ÊÉlxÄ¡¶e¼JPìÁl_ç—µ.Öà1ü¢*'V+| ¿$T è~þÛ[ØTøP•ˆCã5 _bûPî0ÈK¸I˜µ›–öM¾å¿åƒÕ?–n+<õ¿ ød«½À‚CyH xºr°úU@¹ß¡Ù¢²zg¾™¾È $ˆêÁʱZÿ/PhЧ¾/|Þy•“‰‡G]$(ÕÙjì©÷W]´VN­§ð%2ñð¨*'©#AŠ_Ñ]E•€¶_®œ¦j<~ÑZ955ªj²^Èö‡GêHøFÛôlå`•€¯ýÓw¢Kw«òw À,𢪹g=‡/Q|^’ /3þ¡›ìþìéÎüZ¯oƒ 6X_ü LF ëÓÝIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_close_pressed.png000066400000000000000000000013121463772530400313050ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+|IDATX…å—;rÓP†¿#SëH ­‚-P@Â#!dbIÉLX@fXe: í<fXEä¬:ØPÿ–3zY²S0œÊ²î=ß§s¯|á›|#Ý3ãµÁ-‰—¾k êDZ1ãð xáµì3€seb¼î –0a¤Õ…Á‡ZÖwo&÷®0n&æ8f/B¢3Ôp”bÁ휀‰]`´H‰xn>ÂØÍ x-{/Ø(8šG"Œ´jÆq.Ñö›6È -;)hÔ•ˆá¹'—h®&ÇѹÐ:â “àÒĺçÚY¼驯OÞ¨‚O˜Wb \›EðR8ásû³Ht.ôqR^)P&ñl²™æ…Ï$FÚ0£W$1Fåá@ÛoÙAUIÈÙ—›^K !±_2¯2¿U¸v(±icPnàÕ×pŒŸ²C#øQ;_ÁÝ¡ýÌšC8ýp¨ÇE iè n¤°éj4 ú±èââfâ4 —á›ðHàtV‰JÞ¹–§Áƒ¦õ¼–íËðç•(èkYg¹²‹ hZoòEд^‘3,ÇT2¸ïZ7;>hZ$%â¹¥ÓŽã‡&³ÂSs#ya2·Áo‰Õ¢F7Wip‰­*8€ïZWb‹L%Ì8ߤT¤*õÀwEðÀµN<•+’wÚ¥•¸ºÙ½Ð}ÄÇEÀ'Ñ*`Ü‚g%V|×>Aòd{¹5‡íyá~ËB`›ìÆ4ö&×ÉÿÉFTÀvœàZQ$ap™p`ø|g|¤^ž”ؾ_G;‹ÊýïÇiàeÕæ÷IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_close_pressed@2x.png000066400000000000000000000031541463772530400316650ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›ËsSuÇ?çG@¤ :ãÊ-T^yt”w ”ÂàØ$uçÎ.tá°pãRWôþG…>y´I눕ã0Œ+EPÊ«ò;.štJ’öþnroÇ~—¿{î9çûéùýn’&°¤%-éÿ,©´x憮Î?åC”cÀJ…ë –ÏÞKÈÍî¯*ÕןN ì&³VñùMò 4¶ @×]#+¸$°£äÒ=ZÒQ ©ï@Ô“ÕB?°ö¹ ÂåÏxûÝf™˜½lJ˜œ¬``­(}Ýcš´ã5§yeÛSÃG¥ËeÚç©ÑX¯æ5_ ÇK×Ê(¬ò¨Õ(J_&§qÿm†£®Qz™XYºV ÀU‡šúëBרFaóRÁ[ùÈs ¸çP{Ñ!ø1LhžOKˤšåW‡p‡°(Û¡`Þsì šÀÐ’j–_K/T|ÉiÜB?ÐèPàÊÁT\r±5«w\#jÖ9„ßÇp(‘‘Jçõ !Hóàê BÐæ¡ÂPªŽ˜dU8LxÅkú»F5êëKÝcºSóôãhÞXZ¼ÌƒÃÌj !JŽ“`-:2æšß£öN± ¼ä~ßXZ:rÝ%·ç•ŽÊ(†'Á‚˜¿æUiu5>& ¨žqmÆÒ¬qÿÇZV; ~Ì <°JK:.×üÔð üCÃdDÆýÔXó…{«S˜29Ýa•Á°Íƒ3 T©ˆŒK pß!|ZzÇ5âè×<ÐZ­ùBŽÚ”Õ]Öp&¡óɘ¸¼y›SUO@Q ¹®J+®“§¿{Lw–^Èät‡Å}Ïç…õš/ä FÝYÝm„ /z+«á@:*ßôdu; °Þ¡ÔC+´vFåJ-€ê ˆÅ.–yø†0QèÀåÕeàæ!½9}8ïÁM1NE什òÍ((„ÐÌCO¹”ŒÉÕ¼p¸ð¸ªVE9–yqŠêÓ·ŒrXíóÖ‡¢IÆår}:(@°ô!ž¹OK™h Û<„¸f«A˜ÀðÄ5^„'êö¶»f… 3®[­euúô…F„Áž¬n³7y ̘‡ U¦¸‹²?—‚ìk¶B›€Ì¸nUË Õ›X0Ø5ªÛ‚ê«T¡L@Ϙ¾!ÊÂÆ€RÞµ–} ¹P¾>~Ì«0L9¤]oL8“(ŸùÇ¢´Šrxä¿! 8Ó&?æp4“‹É¸\Vå> dÆukíÎ(3àtN›`Øùލ Ï^ìÎê;"œ^pÈqÇöuDäǪž¥š'À¯y5´•šHÇåpÇI°–¡ &¡&§sÚ´ ÷±WC[:"Cs¤brÔÖ¾ªÞEóÀËáE9–ŒË KîžœîÎáýuþRa_**?¹ä®p¿õfu‹ ø™Ÿ¥ÍÕ|Q Á7€…0_TfL÷Zå,!Bðuôfu‹º}Mæ:¢2l„£Àc¯X…¢ Îi“ŸÎfÌ ›Â'­=?Ÿ:¢2¬†6!4À°NºGt³_óqpmÂKéˆ …Áó èÑÍbv5´§bÒïRܯz³º_…op8€ÛyØ÷~L~ž/h^õd¾¨„o©ð­Ï ò„0'€îÝ,Ë^q(4)ÂñdTúbk–_¢ìMÆå—J+ði~J„ö…2_TPÊd®ékv9cÀ«‰Å|Q]Y=`¦ÏoÊŸ Ñt\~Ÿ½\ö°Ëù˜ÿ€y€Î¸ Øé_µLz › |Rº\é1¸Ç¡ö”š…Ûóó©ð¸mÇ‚ {K×Êy¤O,M²È½y۔ŀêO”,´p%ZŸšù^ë­oÌZô#¨ãûJÏv¯Ëm/ºð¨lðhlñ(\ðà\ñ |ð`lñìlš*ô#Èû¦,rЈñ9p ÍüQ<ð `YÁ­Yó>\®·e±;*@(Ü+€#¾Î— Éë¸s€Ð¸S€8X¾[<M2,vÀO”Ì]ðΞøªBf‡p§N otÂA¸¹¿:acqóÑVüÀÅlï„øXí+û^L©‡Æ¿ëÚvÈJ”¾Ð› Mø~ž$S˜à¡ ®ÀC\‚Ë\ƒ‹\„ØÈúÇyʼ(ŽûQxš%ËxØ„ïe„Ã\‡ƒ|€C||‚Í|ƒ|„M|… ìÁK»]œeÍ+õ=Qòr¼¥yMÐuø Þ%g˜Xô%o™Ã˜kIÌyøÝÆŠ8¼ž5A/à…wñ<-k‚>ç½"/ü:ì:|e·qˆð~:oö+òBà¼JŸ÷Ü0·¬Á#G½èâ§÷»áGWòR+‚-Z­MWóªÕêMyëZ×5®¿pˆÊn2ÄIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_grip_disabled.png000066400000000000000000000006551463772530400312540ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+_IDATX…åÖ±NÃ0Æñÿ¥Ny:ð…‰‰HíÐv$xRÄ‚DÕN•²Ê0ÀÄž´Ç@ƒÔ4%v°Ã€Gû¤ß'ût2ü÷%mbÓ4íÅ9w ¯£ar µ‰›Œ¹Â…ÀI±ßJ€G裼d†ëâ,ø”ñMӛȋpÁMÎ̯ Ð_ŲWáN“0 n9 áÛÞØ„{Mè„Õýˆï7æî0ŠÊÅŽxXå†Ê†³iLÙ)nˆÛÔº¡@U#“ñX‡«ª˜\ïëðrÝ!ü;Àö.ŽP–5?é¢,áUu6óUTµv0©ªø¬ûóõ ßoÔŠcÃW5IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_grip_disabled@2x.png000066400000000000000000000013331463772530400316200ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíš½nÓP†Ÿ/¡* l½–”¦Q®€”Р++wŒü”T0 –¬ni£&’7® ) "ù*¤`œ¦±Ï9>ÇÉ;ÚŸ_ç‘ãXG†uÖYg•#E/Àv¢¯£;RÑç¨üêäqsgçÛìùkE-ÌE¢Á°#ª@QtR}Ôgg*Å,Í~.เÿ™ÞLΕR@* ;ˆ‚nn!¼NÎx#À|JßñB€#ø©0}’œ-\€;x}ØÜ½õ19_èCÐ1üAÚ5… ð à < À'xp,À7xp(ÀGxp$À¼,Óe]€Ïð`Y€ïð`Q@ð`I@(ð`A@Hð`X@hð`P@ˆð`H@¨ð`à39Wð¨ì7µÞ²}ǧg÷”Ê Àüž KøVøh0ÜW¤geO0xQÞ°€1“ßáOÏöRàÍì †¯ÈÛdŸ‘=ÁÀáóí ú?º¯è»dߢ¿Î+ (+<\A€+xöÚõíÃeûòÀÃe‡‡Køt2ê"ú>Ù·ìÏ(UÀªÀCŠ€‹wgéa~N_ŽÛ>½/ëôqoü<ÿý¸1s83üœ¾Ìð¦û ñ&8«ÀæÌ¡\Ÿ¥¤ôåZ¬é>Hh·Ûçˆ>~c:y¾ÉIö ÚͳXÓ}sÓï÷7ã8Þðµ/Š¢ë&ûÖYg…ó¾UïºIæ{IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_grip_focus.png000066400000000000000000000006531463772530400306220ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+]IDATX…åÖOJÃ@ðïMC½A#¸*®ÔUW® èTx°¶øîõGO)¹‘¯çó^DNxGf 4Ø-÷“VqàÄ=5OÊoÞWà‹kÍ£×ËíÏ_…{pÄçö<è%³*î 4î Xþ¶xœ§Š˜Ùâ€Å ¸à‰#n à‰?ê%‡ëp§I·„‘ð¢1+“°À /ëšñZcnš„¾øBù6¦ü,›O¨hÂU‡˜¤$”^­kÂWеEànãKæ °[Ô5àkêlæ0¢iͤ­ûëõ ³:õ†¡ùDIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_grip_focus@2x.png000066400000000000000000000013501463772530400311670ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+šIDATxœíš½nAFÏu¡.‰KŒ_ %/ACd“€D›‚–Ž–@ ±NøqAxG"¥m)‚!‘K‘fY¯cïîÌìÌÚ·œ½ûiÎÑìßhaYËZÖ"—”=ÛÕŒFwUx.ð£¦úø[·þ5~üJYsQÍÞ°¥Ðj œ‹¼îÄ{j¥ÌÌA]ÀKŸ£*7’}•üÕš>KöVNÀTx•öÉ^ýK²¿R7ÁKởÒΩŒ€<ðPyᡊÀCàŠÂCÀLÀC LÁC€LÂC`LÃC@lÀC lÁClƒçlÃÇ\Àƒ§\Áƒ‡LÃ7¢ñ=} Ð=îl~Ž÷jCÄ4|³7l‰è°¬+DÉoØ€OÉ›(/8‚?WäI²·tîàyxÒÙø˜ì/õ&è~³ŸvNi|€‡’ø%ð  ð  ð=]Á£ú <8X.áÝúAÖ<«|‡‹B€KB B‚ÃBƒƒB„CB…œÁ‹îöê‡Yó½ñ¶ /Áž ÷ðû£]A±±'¼ò–Œ¹xßí¤À›Ù Þ%óŒì † Ÿþ•8÷ ðþv4¼Ÿ?ëy®<"ï'òæxo˜¹\Á ºãf¬—ðÇúQÖ¼¢ðp‰ïá÷‡mT>$ó²^F©`%9Ðè· ÁOÉË ñn?™—÷úß ØŠtõ§ŒÏ€ë±áÜðSòrÛ΃ÄSàìêé °*ô[JJ^¡ÉšÎƒ„€ÓG·~£òøüR‘V‘r&òv‘ɚΛZƒµ­HW}Í»ùæû5“yËZÖ×?ø¢‰<$ã……IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_grip_pressed.png000066400000000000000000000006701463772530400311470ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+jIDATX…åÖ1NÃ0Æñÿ‹C¸8Aa@ ¬-@‚ $ÎQîÑ $¤víŠ å 01—V‰â4vj‡ö“Ÿlç)ð߇4‰ ÆÚJ 7ÀËyGN’&qcÀv1Ÿ6‰ ´ž Ž‹µèW`Á»—‡òÚH€*>ýë´ ˆN7IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_grip_pressed@2x.png000066400000000000000000000013071463772530400315170ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+yIDATxœíš½nÔ@FÏ]HB]ÞÄ‚Š7 í’ðã4PÐÒÑò$¶‰ÃOØ ÄÐﺣäÒ $öR@a&v6¶gÆ3^ßÒ¾þ4çH® C 5Ô:—t½×•åzx†òáQšÈ×âý‹­ËKe £#”WÀõbϨƒuy©l¡c(ÀW̾^ (ƒ~/á©ÙÛ»W  a²ŸÈg³¿W›àYði"Ëžé€&ðÐMá¡ÚÀCäÚÂCÄlÀC¤lÁC„lÂCdlÃCD\ÀC$\ÁC\ÂCà\ÃCÀ|ÀC |ÁC€lÃg¹ÞBy 0Zòðþ5ùT¼ÔDÈ:üß™à1° l/GLÍž`8?wª‚à ~)Êc³·sáï=¸*ÌþN7AÏðGeÏt& xèH@(ðЀàÁ³€ÐàÁ£€áÁ“_ðwÓDÞ×Ér. dxp, txp( xp$ xp &x°, 6x°( Fx°$ Vx°ð/x…½ýDfuóçz[…à`&è~§>üÁ\÷T˜áb&¼¯YÁØH@èð‡sÝ-·3Œ^…7fž•™`äðíf‚¡Ãg¹ÞAykæ­útžK@_áá¼r`7Ý‘ãÚy-àa…€¾ÃÃB‡?XèDà™W÷5*°.ðP"àßÙy†%øŠ¼ÆðUyM7ÐÿLsÝØT¾— —ÃWä5†·ÆIpó„ ÀVáR«ßRJòZ-ÖvÒòS„'À/àDaÜæŸ3O”I›ÅÚΫ¬çßtkšëF¨yÙ½d3o¨¡Ö¸þÿ0¬ôwVj÷IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_minimize.png000066400000000000000000000003101463772530400302710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+zIDATX…íÒ!1„áÿuï@ÜCô&Ì æ È=ݤw Õš&¸¶f>7ÉKfÄ‘ɬÉ1.]ã x3`½l1¸=Î]@»¦Ïûê·û€r€ø£„ðïr„:ÀÍwƒ4 3cáVÂô'™î¬ š7^IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_minimize@2x.png000066400000000000000000000005161463772530400306530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÖ1JQEáó2B,,D ;‹`'º€tº×aãÄdö)í²l„€‚ hÀÂBdòlåb•pÎWÞŠ;·™I’$I’$I’$©Ÿ÷~¿ÈÒdQF£90ÿíüã›Û{ëT³„#`eQÝ2™âEY´ﮟÒcm€µ^oµ»7ÀVŽvMªyÜy¹¿}þ¶Ò§:tÏø/°Qa†µˆd©³ ‘Ã4ªÐ0õWKè‘Gà2jÌø8rôÉlRUñ$ k¼ŽÇo­öç>Äsà=KµÅšâ°,ËÝô þI’$I’$I’$IMñ›§6ÝÌ®aIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_minimize_disabled.png000066400000000000000000000003161463772530400321260ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+€IDATX…íÒ1 Â@„á6w¼Š lNbaã‘,¬=ƒ )r!w0Ï*Aì²ÛÌ× <˜)˜™™5¦ï*¥t[æœß’âgÀs³¤;°ßr0Ȩþxx¤u‰t­P°“Òm éße 뀈¸¯ Óœt^Bó'433kî„ì!'¹¯IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_minimize_disabled@2x.png000066400000000000000000000005151463772530400325010ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÿIDATxœíÖ!NÄP…ási'$x6@‚@˜Å߀Ǵµ>Í€=%{¾ûzðsIò1C9@í¯#øÕeç€ðÔ[†Î= ;Bñ')î GQ UøD|IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_minimize_focus@2x.png000066400000000000000000000005151463772530400320510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÿIDATxœíÖ±.Q…ñïÎlB6Z…è$  ã¼h·ñìl³V¯”Ðy¥DBC"Bc®Vî ›»‰ù~åùOqæ43 I’$I’$I’$uBøócØ>¦ÌÔ¥WP3 õo÷X?yX®Co`Xh«\&Sà¼(‹ÁÍ~ÿ1=6X?/†ùêXÍP.§Iظ;XyúéSaîsÈÿ{y€~/2JÃÆv²Ô™…Àn5è˜æ‘ËôÈ#r‘Fâ[yÜçè“Ù¤ ¦ac€ÛÁÒKùþ±áxÍR­]Sà¬(‹Íô þI’$I’$I’$I]ñ|ô4Cå꿤IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_minimize_pressed.png000066400000000000000000000003121463772530400320200ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+|IDATX…íÒ± Ã0„áÿ);¼ˆkobBá1RÜe†”î3H@;„K%Ò)jîë=¸+fffE$ÅzpjY¸N¼#B_ö§&à - 20_Æx¤êéÖ¼ 8“ØJL¿nÿ¡°¯æ"+¸–Øýš™™u÷T ¹„µ²IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_minimize_pressed@2x.png000066400000000000000000000005071463772530400324000ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ùIDATxœíÖ!NÄ@…ño¶]ƒ@ç$„ VâàHÁb8ìöX‚E’€C"0ÜEBÖ!È&Ûv°dpMè÷“ï_ñúL ’$I’$I’$IÒ „¿Ž1ÆpùHUªL/öé¦!t¿àê9nŒ#³GÀZoåÊXw]ÅÙÉnxKÙ7Oq}YóBd«D»‚æMËöé$¼GéSËŠé?|y€Íºf–†ÙÊôYÈae M6@€‡U)"pŸFÙã– ¯E •5oÎÓ0àx>F-{®Ï"Õúµn»Šô þI’$I’$I’$ICñ̓7¿ YQIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_undock.png000066400000000000000000000010121463772530400277330ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¼IDATX…í–1KÃ@Çÿ/­)¸ÖTPh¶bRpAü RéâÐEqéÔÁAt)~'‘~A .‚¥E#„BãÐE©-hÛç iMlÚ„3´ÿé.÷îý¹{w0î¢aƒ1E‰ Î( ð‚G+ Ì´"Y]¿kŽˆ)JThrŒ”7c+Jx¬‚]œÐàœïæÀHaú#×ó± $JûnÞϽa4ÃöQæ=×ÕòÐz%Q’yPnûø'MþÔ€˜HÎCÖÀæïqIÞµKÒ%ê Ü)ÕÔä-pÙq`*¬YiqŸ@GƒÀêæ³ÝÞªkºuÀ\„ý¢îmA<¡dtìÁV§Âá `3ätB€Æ&ˆ¸ô°ì4¸ÿ·Ä¦[gN“0aÀœÑïR( èÀRµç²mÑYOÈ`ŽјŸ®Àá`8€—[ÏV äEIÎÛGf´‚YæBp„Z‘l¤qúûEüÍó#Q’_ÌøãÅÛúSåÜIhˆ¯|1ÚĸvÜ ÆÀu¯î >¬©•ªk€šZ©°â€7÷¾tO Ì‹Z9q9wÌõ¬DÙÓ_Ä:IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_undock@2x.png000066400000000000000000000016131463772530400303140ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+=IDATxœíšÁOAÆ¿·[„h)"’ÒJ"Ðõ@-Ä£g=x3bbBbÔðþ¼Ðè£1zƒzÓ„˜˜Z‰‡V6@K‘jÀ²û¼»Û-ÝÝéXwÇÙé{ß|}™ ÀÏÛÝÉd¸eKcÂ%)­îe¹b@†3å6}jua¡d×Ù•ñþÔVh@¯›8É“Á£K‹™—Õ:¨N#ÇR£¬ÐNc4€ˆF"Ñ/›ëÅVÍ€˜–: ¦YŠ+yC'ƒÏ[Í„º èN&ámõ€#žHkùV}°rM¨ûlÙRÇÐ|ƒ€Þ]íQ·»«}Sb¥ÝÉ;œò@‹,LÚC‚Ø~ç—si×µ…b‰!¶ylÒÞ,«¸0d M`€l² -@6¾7 f!tøè`¬%ºà4Q»*≡¬S1Àäôâý|°–Í~wk¯ØVmqmø"3Oè-ÄcÑPh¤Ÿ«çg5*AS¥Zõèц&˜ùd ý ó›Ø@ê¦È4–Ä©Ëĸ-2ñQA4Õ†OŠJ`2 §ïDƒŠJèU1øÑ!M‹ˆn2€T}€dŽ!ôïãý7D„¶z.ˆHä ÑeeÀ?¹ÅÍ‚tÕ½!¢B?&BˆŽðlµçЇ8VÔm@>·à¸Ð±£7‘„îü˜Â1¾/…d M`€l² -@6²È&0@¶ÙÈ '÷¤À@¢ÖŽïØ®lðÛ ÈT6øÊbÌT¶ùÉ€|¹MŸªlô‹:Ï¿m@¾€€óxõØúá`©IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_undock_disabled.png000066400000000000000000000010031463772530400315620ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+µIDATX…íV±NÂP=·(89˜õHLCÿÀh‚añt11Æ…‰ÁÁèBü'Iøâ@JRù ‹ÆÀB{°@+-mŠv€3½×wß;çÝ{ÞME¹-Öj­øJ¼WèÀN@®6˜ª‰X¤(Šbo¦€!y¿ ØŽVb5ºgŠœ¢†7Ÿ;9$¿úzÉœ8 øIû߀øÈF]Â,5Ï¥%W¿Ì‚¢j<íl— ü–~y ÑxÙÖ1íßëêó™Ó!ÄlÌ­î{GËçóºcÕUí‚€ëiÂ<¢!ÑãlV|³/ØL82õ¨Jã¹@ÀMrÈÂà±R©D¼n{€ø2±EÄúÆ–ä5xò¶–®ÇÀ½×C8°i΢$€¦_?ì§%GÓÙQW5pjΙÈóë ý.,„. H×sËŠª•]BÚæ œ 0UÃÐJÄ"Å0´Át7ùG L´_EÕ>¬Í…Šq’ËH^BG ài.äÀ€ Añ<..œèe'Æ•,§:¾ÈrªCº°K@À§O^ðÊ„‚œ‘n}î]p|x0pÝþçóIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_undock_disabled@2x.png000066400000000000000000000015611463772530400321450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+#IDATxœíšËkQÆ¿3X¥¸± ‹u!º;mÓ6ñUtáN îZ•îÜ”þ¶K¡EtÑ¥›º¡|LÒN› ¸ºp¡è" ".)&s\´RÌL’ÎLNoÓ¹¿åÍÍ9ßý2÷æpç&ÎPÔ–eµ‰Öq&ºPÀû!,<´ð1Ï»¥âl:þQsv”TÛ¹ÆíQâˆÁ(€0–JšÏ«M1ÂÆÎ.;cžíÚÅØÔ¶˜YqF«O AvŹČED0p‡)¸ì÷$6À²¬6Úwà-€ãP¶c0 \ú}ºòLü ‰Öq4Ûâ€Ð¾©ý?°qÚ7'~ÚCìaêj„5xµ'‚©ý?ŸJš‘k‹(dl‡«êÕÞ,§¸ÚÕT£ P-@5ÚÕT{êBKK¯¹Fé6˜Îƒp¨QgÈØùwáå0(´Ðšà¦i~k{Ô¬Ú²vî*ƒæ–âî§“¦äKµ+Ao¥Zu X+ù)=šÅ@¶eçoI&ñ5 kçFˆyB2ñ6i!ðŒe;¦TV.w‚A¥† …€GŽã’î1€\š ’,ÅÝ”ìÝ.®H$Š‹èò°{oyEt¾aÃ=%!et‹Õ'ÈEK`Ò}} êX««€+¹6±/…µª¨F Z€j´ª¨F Z€j´ª¨F Z€jBô¨‚OÖ»ñ­­WŽÄì àµÊ‘X@Ìó•cñ1€QpKÅÙÊá¸Pa̯o¸‰ÁДA¸‘ê÷ïÞÛük–®²x`O°Õ._üupfx¸ûgÍÙ•Ñÿk¥ ÷©dOg££ú‚ô¥ÑIã³DXŸ7CüB"Qdˆ_J„õàº4 àD²|5ÜÄ}‰ÀÎ ô¼h7ôlÁ<:8xæ“DhßBh¨ÿì=0K$ S©Þ§Rñ} "w(Ù3ШڌoJš“’iê¾q}µœï6 žÓ€HаQ¼X`ƒï¦{{?ŠçÓh4±æ/b#Ô½Gœ¤IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_undock_focus.png000066400000000000000000000010231463772530400311340ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÅIDATX…í–±KQÇ?¿ä¶@6›!P¡ôì–@'Jÿ…¢`qqp0ƒ.…".NŠ.âtK'…ü.B tl&iÕ!ˆ˜K;´¢6Ãù~z’¤¹x׋É|§÷Þýî÷ý¼÷~÷ã`Ø%ÝfеD£!ëÀ´ÂxD£ªÒ¥ºkg¹ôÕƒ™b-ñ·!e Ÿƒ*êNy1¿¨»÷Ú ›kÝ›øÓ`î™ÎxcË/¨ýÎS]ëå!ÙG;åîv}ÑàŸx–?}ëuûúD¾¾ì—ĈšxŒÊ÷䓯ÌÊõØç=𡘊nù%À°׿XùŸorcgAî¯ÀþT›>v2¡W®˜v5••Æ-/Îë“Aƒ›wÛÒõTÙšD„7@Ú›_²@9,@K£9Ê¥|‹®]Ïó",yó˜Jà¯kàŸá`0p€(]ÏW*ºeœn­»êrJƒ¨\ª»ÖwªÂfóñÝú­ì‚óHöÂLaþh1õ9Hló ìõÂpÕr÷ƒßË}üŠê.ÊêñBú$4ÀñBúÄXîKn+ô<¤¯ßû‘Km„|wÈu´Ô‚Ô¹ÓËIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_undock_focus@2x.png000066400000000000000000000015541463772530400315170ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíš=LAÇÿoáü ±!Ü‘BÂ.BbkïG¢…!±0p|„ĆPZ‰¥† ²g(m°1&`¢v¶¢„;¢Å)·G(4Çí³x»·Ç~ ñó+çÞ½÷ŸÿíÌ¾Ì  P(â …MП-·í$0I°o4àdºÂ° ð C[“z]/@ šY7ËÃ`¼ÂÑ<t±läÊCõ=ú¼uËaà!SáºÛ“àÛ€þl¹­’àUç"‘vxê«Ý|ÿ‚; L¢ù&]{Úÿ÷ÿvûæÄM{€5LQˆ‘ƒS{k€,žïùüh*toôØãc‡öfÙÅ…¡ -@6ÊÙd£ -@6±7 a#Ô7¿Ù¹«ÙĸÌ@ªQ¼aZ…z "ˆ—øOë|ánûϹ„gצ›¥›D´F»h!.|aâÛ…Lú½Ÿ/5èjÝ%`˜¥½4yè&¦w†i‹,âj@o®4ДȤÀ¬ž+]UÀaÀ…¹óÌdŠ*€bz¦?Þ:+"¹Ã€ª¦MR,ÝtzwLDbç ÜQ(4LBt¹íGô”—…èò} bkdˆ‚]èšÆËBZ|°>’ ÓèÔ¥çi°Edö&ö­°2@¶Ù(d 2@¶Ù(d 2@¶Ù(d Mû²èitâ{¶kböðJíH¬ `h‹µcq2 x¢‚lí`\ ¨‚0ìvo¸™6Á TA”Ég’®÷…»{—¥Ý'Oö¯ËŸ9eÏ~¼“þíì8jŽà]+ŠõühJ:©Û&¸u‘( À‘×Í€7" …… oEäu@6¨ˆ(ÂV«­Í‰Hí0`m<õ™ÂÝ€}˜xèóXdžˆÜ®Pá{ê€ç" ú…ˆg #é—¢ò»w‚÷ÉÎK2ó=È[?4¸–IO‹,Òð×Þ'ÖEÖ0à €‘bö(‚±ÔbÛV':¿B=…BcþŒÑÊÊË hIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_undock_pressed.png000066400000000000000000000007631463772530400314740ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¥IDATX…í–¿JÃP‡¿£â à þyAÚ"‚ø ¢ 8(¶‹ƒ.‚ˆ‹SÑ¥¸¶¨“‚Oà"ˆ ¦ƒy)\\tˆ5Ç!¦´Ñ¤IMÛÁþ¦{““ûûr ÿ]ôòÔÔAÛ"«0ŒþÑ«\ZÂÞzBÞœš:øùÁ-ÊÄë%˜L»=~q¶E6vse¢_ɺS_€ï´·J î / ¨nÏÓI ¬—F*ª¿­í›v© ð£NŠ:b+³ÞçyC7ýÅÁxänqQ>›Èßë¶*û¿ ä|WPàmŒ›³¢.­$ä),@u ò†.‹p Á'#XÂLÅæüâB{#ì4mìxg*lxíßz»ÞqÓ9”awªN½ P×hÒIñ-:¯ †lT$üéêø1ìt:Ð|× @®`¨ëvî‡@ç2péZ’@9—Ò=wÚÎ ”€£Ú±Ãó­‚¡/ÀPLf«é¤œ… ¬ÍÀUÎU®ÃÆWTÙxŽ`7“’rd€LJʶ2‰S¡¯mx–×rñÛ®/!`t×vzôIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/light/rc/window_undock_pressed@2x.png000066400000000000000000000015271463772530400320450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœíš=hAÇo/ÁÄFDD ƒ±)òa¬ý-ìB@Tب¨¤³ )­Œ¥ ŠÞ›Øˆj'sI!¤°P¢p "Š Éí³HT¸Ý»ËÞîdrîþÊÙ¹÷þó¿™aöAJJJ’‘¨FçtGóxô"´ÛbÐ…e”9Æ›h“_•:G2 —×Y…ýQâ˜B  ÐïvÉ‹r}œZƒçòÚ<ߪƒX×6™V·\ŸšfÀØŒžTe’n2EàTÐLmÀúš²/i›„@aa;‡Kß ¡ÿÁæ%êmð°¶š—(m?…=zcQdƒíá XÛêê“í 5„©¸Ï»]ùl…\^µÂcŸözy‹#5À¶Û¤Ø`›ÔÛl“xª„ÎèÞUkÇ€=Õúçòú¡V1ªP&‹Ü=×#?k"gyÆòzF! ì2-$€yκ2æGUN‚¾“jÙ%›Öa…§Ø<@ ¯s3zÕd’@²ÓÚ‡0h2ñÉ ŒäfµÇTŸ¹7z@„{¦Ö@Ǧt§‰à>´!ÀH²´¬d¸b"°ÏN›HFtùgÀ½åCºB_ˆ™’)ÒŠ0Yî¹Æð'ˆÐ\êš:•¸?«d<‘+“ø£pj€m¶I °-À6©¶Ø&5À¶Û¤Ø`›ÔÛlSK}€-V»ñÝË¥ ÉšÊ\iS² p÷7%Âb£¥íI1 ¨ÐT7œŠª\.W/\O»@hþK÷w—/–þ ø[.ï42r¡]*uö]5ǰךâ£Û%­q z|‹;IL|5Ôg€ÀK‰"£¼2Ög@Ñã°b"Y¾78Ü1ØgÀÅ#òNÙµÿPÜóòÅDèÀsÀçNn <1‘04ʰÛ-ÏL…4à†ˆ7ßIŸÂuì-‡¢ô¹Ý2d2IÕ/®Þj{ÆaPá8°Û¤˜uA&d•›îQùd:_JJJ²ù N¶laXIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/qss/000077500000000000000000000000001463772530400234545ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/qdarkstyle/qss/_styles.scss000066400000000000000000001713251463772530400260440ustar00rootroot00000000000000/* See Qt documentation: - https://doc.qt.io/qt-5/stylesheet.html - https://doc.qt.io/qt-5/stylesheet-reference.html - https://doc.qt.io/qt-5/stylesheet-examples.html --------------------------------------------------------------------------- */ /* Reset elements ------------------------------------------------------------ Resetting everything helps to unify styles across different operating systems --------------------------------------------------------------------------- */ * { padding: 0px; margin: 0px; border: 0px; border-style: none; border-image: none; outline: 0; } /* specific reset for elements inside QToolBar */ QToolBar * { margin: 0px; padding: 0px; } /* QWidget ---------------------------------------------------------------- --------------------------------------------------------------------------- */ QWidget { background-color: $COLOR_BACKGROUND_1; border: 0px solid $COLOR_BACKGROUND_4; padding: 0px; color: $COLOR_TEXT_1; selection-background-color: $COLOR_ACCENT_2; selection-color: $COLOR_TEXT_1; &:disabled { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; selection-background-color: $COLOR_ACCENT_1; selection-color: $COLOR_TEXT_4; } &::item { &:selected { background-color: $COLOR_ACCENT_2; } &:hover:!selected { background-color: $COLOR_ACCENT_3; } } } /* QMainWindow ------------------------------------------------------------ This adjusts the splitter in the dock widget, not qsplitter https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow --------------------------------------------------------------------------- */ QMainWindow { &::separator { background-color: $COLOR_BACKGROUND_4; border: 0px solid $COLOR_BACKGROUND_1; spacing: 0px; padding: 2px; &:hover { background-color: $COLOR_BACKGROUND_6; border: 0px solid $COLOR_ACCENT_3; } &:horizontal { width: 5px; margin-top: 2px; margin-bottom: 2px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/toolbar_separator_vertical.png'); } &:vertical { height: 5px; margin-left: 2px; margin-right: 2px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/toolbar_separator_horizontal.png'); } } } /* QToolTip --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip --------------------------------------------------------------------------- */ QToolTip { background-color: $COLOR_ACCENT_2; color: $COLOR_TEXT_1; /* If you remove the border property, background stops working on Windows */ border: none; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Remove opacity, fix #174 - may need to use RGBA */ } /* QStatusBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar --------------------------------------------------------------------------- */ QStatusBar { border: $BORDER_2; /* Fixes Spyder #9120, #9121 */ background: $COLOR_BACKGROUND_4; /* Fixes #205, white vertical borders separating items */ &::item { border: none; } QToolTip { background-color: $COLOR_ACCENT_3; border: $BORDER_1; color: $COLOR_BACKGROUND_1; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Reducing transparency to read better */ opacity: $OPACITY_TOOLTIP; } QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; } } /* QCheckBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox --------------------------------------------------------------------------- */ QCheckBox { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_1; spacing: 4px; outline: none; padding-top: 4px; padding-bottom: 4px; &:focus { border: none; } QWidget:disabled { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; } &::indicator { margin-left: 2px; height: 14px; width: 14px; &:unchecked { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked.png'); &:hover, &:focus, &:pressed { border: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked_focus.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked_disabled.png'); } } &:checked { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked.png'); &:hover, &:focus, &:pressed { border: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked_focus.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked_disabled.png'); } } &:indeterminate { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_indeterminate.png'); &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_indeterminate_disabled.png'); } &:focus, &:hover, &:pressed { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_indeterminate_focus.png'); } } } } /* QGroupBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { font-weight: bold; border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; padding: 2px; margin-top: 6px; margin-bottom: 4px; &::title { subcontrol-origin: margin; subcontrol-position: top left; left: 4px; padding-left: 2px; padding-right: 4px; padding-top: -4px; } &::indicator { margin-left: 2px; margin-top: 2px; padding: 0; height: 14px; width: 14px; &:unchecked { border: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked.png'); &:hover, &:focus, &:pressed { border: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked_focus.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked_disabled.png'); } } &:checked { border: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked.png'); &:hover, &:focus, &:pressed { border: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked_focus.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked_disabled.png'); } } } } /* QRadioButton ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton --------------------------------------------------------------------------- */ QRadioButton { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_1; spacing: 4px; padding-top: 4px; padding-bottom: 4px; border: none; outline: none; &:focus { border: none; } &:disabled { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; border: none; outline: none; } QWidget { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_1; spacing: 0px; padding: 0px; outline: none; border: none; } &::indicator { border: none; outline: none; margin-left: 2px; height: 14px; width: 14px; &:unchecked { image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_unchecked.png'); &:hover, &:focus, &:pressed { border: none; outline: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_unchecked_focus.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_unchecked_disabled.png'); } } &:checked { border: none; outline: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_checked.png'); &:hover, &:focus, &:pressed { border: none; outline: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_checked_focus.png'); } &:disabled { outline: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_checked_disabled.png'); } } } } /* QMenuBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar --------------------------------------------------------------------------- */ QMenuBar { background-color: $COLOR_BACKGROUND_4; padding: 2px; border: $BORDER_1; color: $COLOR_TEXT_1; selection-background-color: $COLOR_ACCENT_3; &:focus { border: $BORDER_SELECTION_2; } &::item { background: transparent; padding: 4px; &:selected { padding: 4px; background: transparent; border: 0px solid $COLOR_BACKGROUND_4; background-color: $COLOR_ACCENT_3; } &:pressed { padding: 4px; border: 0px solid $COLOR_BACKGROUND_4; background-color: $COLOR_ACCENT_3; color: $COLOR_TEXT_1; margin-bottom: 0px; padding-bottom: 0px; } } } /* QMenu ------------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu --------------------------------------------------------------------------- */ QMenu { border: 0px solid $COLOR_BACKGROUND_4; color: $COLOR_TEXT_1; margin: 0px; background-color: $COLOR_BACKGROUND_3; selection-background-color: $COLOR_ACCENT_3; &::separator { height: 1px; background-color: $COLOR_BACKGROUND_6; color: $COLOR_TEXT_1; } &::icon { margin: 0px; padding-left: 8px; } &::item { background-color: $COLOR_BACKGROUND_3; padding: 4px 24px 4px 8px; /* Reserve space for selection border */ border: 1px transparent $COLOR_BACKGROUND_4; &:selected { color: $COLOR_TEXT_1; background-color: $COLOR_ACCENT_3; } &:pressed { background-color: $COLOR_ACCENT_3; } } &::indicator { width: 14px; height: 14px; padding-left: 6px; /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ &:non-exclusive { &:unchecked { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked.png'); &:hover, &:focus, &:pressed { border: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked_focus.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked_disabled.png'); } } &:checked { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked.png'); &:hover, &:focus, &:pressed { border: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked_focus.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked_disabled.png'); } } &:indeterminate { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_indeterminate.png'); &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_indeterminate_disabled.png'); } &:focus, &:hover, &:pressed { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_indeterminate_focus.png'); } } } /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ &:exclusive { &:unchecked { image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_unchecked.png'); &:hover, &:focus, &:pressed { border: none; outline: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_unchecked_focus.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_unchecked_disabled.png'); } } &:checked { border: none; outline: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_checked.png'); &:hover, &:focus, &:pressed { border: none; outline: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_checked_focus.png'); } &:disabled { outline: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_checked_disabled.png'); } } } } &::right-arrow { margin: 5px; padding-left:12px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_right.png'); height: 12px; width: 12px; } } /* QAbstractItemView ------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QAbstractItemView { alternate-background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_1; border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; QLineEdit { padding: 2px; } } /* QAbstractScrollArea ---------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QAbstractScrollArea { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; /* fix #159 */ padding: 2px; /* remove min-height to fix #244 */ color: $COLOR_TEXT_1; &:disabled { color: $COLOR_TEXT_4; } } /* QScrollArea ------------------------------------------------------------ --------------------------------------------------------------------------- */ QScrollArea QWidget QWidget:disabled { background-color: $COLOR_BACKGROUND_1; } /* QScrollBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar --------------------------------------------------------------------------- */ QScrollBar { &:horizontal { height: 16px; margin: 2px 16px 2px 16px; border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; background-color: $COLOR_BACKGROUND_1; } &:vertical { background-color: $COLOR_BACKGROUND_1; width: 16px; margin: 16px 2px 16px 2px; border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; } &::handle { &:horizontal { background-color: $COLOR_BACKGROUND_6; border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; min-width: 8px; &:hover { background-color: $COLOR_ACCENT_2; border: $COLOR_ACCENT_2; border-radius: $SIZE_BORDER_RADIUS; min-width: 8px; } &:focus { border: $BORDER_SELECTION_3; } } &:vertical { background-color: $COLOR_BACKGROUND_6; border: $BORDER_2; min-height: 8px; border-radius: $SIZE_BORDER_RADIUS; &:hover { background-color: $COLOR_ACCENT_2; border: $COLOR_ACCENT_2; border-radius: $SIZE_BORDER_RADIUS; min-height: 8px; } &:focus { border: $BORDER_SELECTION_3; } } } &::add-line { &:horizontal { margin: 0px 0px 0px 0px; border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_right_disabled.png'); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; &:hover, &:on { border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_right.png'); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } } &:vertical { margin: 3px 0px 3px 0px; border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down_disabled.png'); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; &:hover, &:on { border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down.png'); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } } } &::sub-line { &:horizontal { margin: 0px 3px 0px 3px; border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_left_disabled.png'); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; &:hover, &:on { border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_left.png'); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } } &:vertical { margin: 3px 0px 3px 0px; border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_up_disabled.png'); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; &:hover, &:on { border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_up.png'); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } } } &::up-arrow:horizontal, &::down-arrow:horizontal { background: none; } &::up-arrow:vertical, &::down-arrow:vertical { background: none; } &::add-page:horizontal, &::sub-page:horizontal { background: none; } &::add-page:vertical, &::sub-page:vertical { background: none; } } /* QTextEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets --------------------------------------------------------------------------- */ QTextEdit { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_1; border-radius: $SIZE_BORDER_RADIUS; border: $BORDER_2; &:focus { border: $BORDER_SELECTION_3; } &:selected { background: $COLOR_ACCENT_2; color: $COLOR_BACKGROUND_4; } } /* QPlainTextEdit --------------------------------------------------------- --------------------------------------------------------------------------- */ QPlainTextEdit { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_1; border-radius: $SIZE_BORDER_RADIUS; border: $BORDER_2; &:focus { border: $BORDER_SELECTION_3; } &:selected { background: $COLOR_ACCENT_2; color: $COLOR_BACKGROUND_4; } } /* QSizeGrip -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip --------------------------------------------------------------------------- */ QSizeGrip { background: transparent; width: 12px; height: 12px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_grip.png'); } /* QStackedWidget --------------------------------------------------------- --------------------------------------------------------------------------- */ QStackedWidget { padding: 2px; border: $BORDER_2; border: $BORDER_1; } /* QToolBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar --------------------------------------------------------------------------- */ QToolBar { background-color: $COLOR_BACKGROUND_4; border-bottom: $BORDER_1; padding: 1px; font-weight: bold; spacing: 2px; QToolButton { background-color: $COLOR_BACKGROUND_4; border: $BORDER_2; &:hover { background-color: $COLOR_BACKGROUND_5; border: $COLOR_BACKGROUND_5; } &:checked { border: $COLOR_BACKGROUND_6; background-color: $COLOR_BACKGROUND_6; &:hover { background-color: $COLOR_BACKGROUND_6; border: $COLOR_BACKGROUND_6; } } &:pressed { border: $COLOR_BACKGROUND_6; background-color: $COLOR_BACKGROUND_6; &:hover { background-color: $COLOR_BACKGROUND_6; border: $COLOR_BACKGROUND_6; } } /* This fixes 202 */ &:disabled { border: $COLOR_BACKGROUND_4; background-color: $COLOR_BACKGROUND_4; } } &::handle { &:horizontal { width: 16px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/toolbar_move_horizontal.png'); } &:vertical { height: 16px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/toolbar_move_vertical.png'); } } &::separator { &:horizontal { width: 16px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/toolbar_separator_horizontal.png'); } &:vertical { height: 16px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/toolbar_separator_vertical.png'); } } } QToolButton#qt_toolbar_ext_button { background: $COLOR_BACKGROUND_4; border: 0px; color: $COLOR_TEXT_1; image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_right.png'); } /* QAbstractSpinBox ------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractSpinBox { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; color: $COLOR_TEXT_1; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; border-radius: $SIZE_BORDER_RADIUS; /* min-width: 5px; removed to fix 109 */ &:up-button { background-color: transparent $COLOR_BACKGROUND_1; subcontrol-origin: border; subcontrol-position: top right; border-left: $BORDER_2; border-bottom: $BORDER_2; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-bottom: -1px; } &::up-arrow, &::up-arrow:disabled, &::up-arrow:off { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_up_disabled.png'); height: 8px; width: 8px; } &::up-arrow:hover { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_up.png'); } &:down-button { background-color: transparent $COLOR_BACKGROUND_1; subcontrol-origin: border; subcontrol-position: bottom right; border-left: $BORDER_2; border-top: $BORDER_2; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-top: -1px; } &::down-arrow, &::down-arrow:disabled, &::down-arrow:off { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down_disabled.png'); height: 8px; width: 8px; } &::down-arrow:hover { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down.png'); } &:hover { border: $BORDER_SELECTION_2; color: $COLOR_TEXT_1; } &:focus { border: $BORDER_SELECTION_3; } &:selected { background: $COLOR_ACCENT_2; color: $COLOR_BACKGROUND_4; } } /* ------------------------------------------------------------------------ */ /* DISPLAYS --------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QLabel ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe --------------------------------------------------------------------------- */ QLabel { background-color: $COLOR_BACKGROUND_1; border: 0px solid $COLOR_BACKGROUND_4; padding: 2px; margin: 0px; color: $COLOR_TEXT_1; &:disabled { background-color: $COLOR_BACKGROUND_1; border: 0px solid $COLOR_BACKGROUND_4; color: $COLOR_TEXT_4; } } /* QTextBrowser ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QTextBrowser { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; color: $COLOR_TEXT_1; border-radius: $SIZE_BORDER_RADIUS; &:disabled { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; color: $COLOR_TEXT_4; border-radius: $SIZE_BORDER_RADIUS; } &:hover, &:!hover, &:selected, &:pressed { border: $BORDER_2; } } /* QGraphicsView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QGraphicsView { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; color: $COLOR_TEXT_1; border-radius: $SIZE_BORDER_RADIUS; &:disabled { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; color: $COLOR_TEXT_4; border-radius: $SIZE_BORDER_RADIUS; } &:hover, &:!hover, &:selected, &:pressed { border: $BORDER_2; } } /* QCalendarWidget -------------------------------------------------------- --------------------------------------------------------------------------- */ QCalendarWidget { border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; &:disabled { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; } } /* QLCDNumber ------------------------------------------------------------- --------------------------------------------------------------------------- */ QLCDNumber { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_1; &:disabled { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; } } /* QProgressBar ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar --------------------------------------------------------------------------- */ QProgressBar { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; color: $COLOR_TEXT_1; border-radius: $SIZE_BORDER_RADIUS; text-align: center; &:disabled { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; color: $COLOR_TEXT_4; border-radius: $SIZE_BORDER_RADIUS; text-align: center; } &::chunk { background-color: $COLOR_ACCENT_2; color: $COLOR_BACKGROUND_1; border-radius: $SIZE_BORDER_RADIUS; &:disabled { background-color: $COLOR_ACCENT_1; color: $COLOR_TEXT_4; border-radius: $SIZE_BORDER_RADIUS; } } } /* ------------------------------------------------------------------------ */ /* BUTTONS ---------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QPushButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton --------------------------------------------------------------------------- */ QPushButton { background-color: $COLOR_BACKGROUND_4; border: $BORDER_2; color: $COLOR_TEXT_1; border-radius: $SIZE_BORDER_RADIUS; padding: 3px; outline: none; &:disabled { background-color: $COLOR_BACKGROUND_4; border: $BORDER_2; color: $COLOR_TEXT_4; border-radius: $SIZE_BORDER_RADIUS; padding: 3px; } &:checked { background-color: $COLOR_BACKGROUND_6; border: $COLOR_BACKGROUND_6; border-radius: $SIZE_BORDER_RADIUS; padding: 3px; outline: none; &:disabled { background-color: $COLOR_BACKGROUND_6; border: $COLOR_BACKGROUND_6; color: $COLOR_TEXT_4; border-radius: $SIZE_BORDER_RADIUS; padding: 3px; outline: none; } &:selected { background: $COLOR_BACKGROUND_6; } } &::menu-indicator { subcontrol-origin: padding; subcontrol-position: bottom right; bottom: 4px; } &:hover { background-color: $COLOR_BACKGROUND_5; border: $COLOR_BACKGROUND_5; color: $COLOR_TEXT_1; } &:pressed { background-color: $COLOR_BACKGROUND_6; border: $COLOR_BACKGROUND_6; } &:selected { background: $COLOR_BACKGROUND_6; color: $COLOR_TEXT_1; } } QDialogButtonBox QPushButton { /* Issue #194 #248 - Special case of QPushButton inside dialogs, for better UI */ min-width: 80px; } /* QToolButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton --------------------------------------------------------------------------- */ QToolButton { background-color: transparent; border: 1px solid transparent; border-radius: $SIZE_BORDER_RADIUS; margin: 0px; padding: 2px; &:checked { background-color: $COLOR_BACKGROUND_3; border: $COLOR_BACKGROUND_3; &:disabled { background-color: $COLOR_BACKGROUND_4; border: $COLOR_BACKGROUND_4; } &:hover { background-color: $COLOR_BACKGROUND_3; border: $COLOR_BACKGROUND_3; } } &:pressed { margin: 1px; background-color: $COLOR_BACKGROUND_3; border: $COLOR_BACKGROUND_3; &:hover { background-color: $COLOR_BACKGROUND_3; border: $COLOR_BACKGROUND_3; } } &:disabled { border: none; } &:hover { background-color: $COLOR_BACKGROUND_2; border: $COLOR_BACKGROUND_2; } /* The subcontrols below are used only in the DelayedPopup mode */ &[popupMode="0"] { /* Only for DelayedPopup */ padding-right: 2px; } /* The subcontrols below are used only in the MenuButtonPopup mode */ &[popupMode="1"] { /* Only for MenuButtonPopup */ padding-right: 20px; &::menu-button { border: none; &:hover { border: none; border-left: 1px solid $COLOR_ACCENT_3; border-radius: 0; } } } /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ &[popupMode="2"] { /* Only for InstantPopup */ padding-right: 2px; } &::menu-button { padding: 2px; border-radius: $SIZE_BORDER_RADIUS; border: $BORDER_2; width: 12px; outline: none; &:hover { border: $BORDER_SELECTION_2; } &:checked { &:hover { border: $BORDER_SELECTION_2; } } } &::menu-indicator { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down.png'); height: 8px; width: 8px; top: 0; /* Exclude a shift for better image */ left: -2px; /* Shift it a bit */ } &::menu-arrow { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down.png'); height: 8px; width: 8px; &:hover { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down_focus.png'); } } } /* QCommandLinkButton ----------------------------------------------------- --------------------------------------------------------------------------- */ QCommandLinkButton { background-color: transparent; border: $BORDER_2; color: $COLOR_TEXT_1; border-radius: $SIZE_BORDER_RADIUS; padding: 0px; margin: 0px; &:disabled { background-color: transparent; color: $COLOR_TEXT_4; } } /* ------------------------------------------------------------------------ */ /* INPUTS - NO FIELDS ----------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QComboBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QComboBox { border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; selection-background-color: $COLOR_ACCENT_2; padding-left: 4px; padding-right: 4px; /* padding-right = 36; 4 + 16*2 See scrollbar size */ /* changed to 4px to fix #239 */ /* Fixes #103, #111 */ min-height: 1.5em; /* padding-top: 2px; removed to fix #132 */ /* padding-bottom: 2px; removed to fix #132 */ /* min-width: 75px; removed to fix #109 */ QAbstractItemView { border: $BORDER_2; border-radius: 0; background-color: $COLOR_BACKGROUND_1; selection-background-color: $COLOR_ACCENT_2; &:hover { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_1; } &:selected { background: $COLOR_ACCENT_2; color: $COLOR_BACKGROUND_4; } &:alternate { background: $COLOR_BACKGROUND_1; } } &:disabled { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; } &:hover { border: $BORDER_SELECTION_2; } &:focus { border: $BORDER_SELECTION_3; } &:on { selection-background-color: $COLOR_ACCENT_2; } /* Needed to remove indicator - fix #132 */ &::indicator { border: none; border-radius: 0; background-color: transparent; selection-background-color: transparent; color: transparent; selection-color: transparent; /* Needed to remove indicator - fix #132 */ &:alternate { background: $COLOR_BACKGROUND_1; } } &::item { &:alternate { background: $COLOR_BACKGROUND_1; } &:checked { font-weight: bold; } &:selected { border: 0px solid transparent; } } &::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid $COLOR_BACKGROUND_4; } &::down-arrow { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down_disabled.png'); height: 8px; width: 8px; &:on, &:hover, &:focus { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down.png'); } } } /* QSlider ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider --------------------------------------------------------------------------- */ QSlider { &:disabled { background: $COLOR_BACKGROUND_1; } &:focus { border: none; } &::groove { &:horizontal { background: $COLOR_BACKGROUND_4; border: $BORDER_2; height: 4px; margin: 0px; border-radius: $SIZE_BORDER_RADIUS; } &:vertical { background: $COLOR_BACKGROUND_4; border: $BORDER_2; width: 4px; margin: 0px; border-radius: $SIZE_BORDER_RADIUS; } } &::add-page { &:vertical { background: $COLOR_ACCENT_2; border: $BORDER_2; width: 4px; margin: 0px; border-radius: $SIZE_BORDER_RADIUS; :disabled { background: $COLOR_ACCENT_1; } } } &::sub-page { &:horizontal { background: $COLOR_ACCENT_2; border: $BORDER_2; height: 4px; margin: 0px; border-radius: $SIZE_BORDER_RADIUS; &:disabled { background: $COLOR_ACCENT_1; } } } &::handle { &:horizontal { background: $COLOR_TEXT_4; border: $BORDER_2; width: 8px; height: 8px; margin: -8px 0px; border-radius: $SIZE_BORDER_RADIUS; &:hover { background: $COLOR_ACCENT_2; border: $BORDER_SELECTION_2; } &:focus { border: $BORDER_SELECTION_3; } } &:vertical { background: $COLOR_TEXT_4; border: $BORDER_2; width: 8px; height: 8px; margin: 0 -8px; border-radius: $SIZE_BORDER_RADIUS; &:hover { background: $COLOR_ACCENT_2; border: $BORDER_SELECTION_2; } &:focus { border: $BORDER_SELECTION_3; } } } } /* QLineEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit --------------------------------------------------------------------------- */ QLineEdit { background-color: $COLOR_BACKGROUND_1; padding-top: 2px; /* This QLineEdit fix 103, 111 */ padding-bottom: 2px; /* This QLineEdit fix 103, 111 */ padding-left: 4px; padding-right: 4px; border-style: solid; border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; color: $COLOR_TEXT_1; &:disabled { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; } &:hover { border: $BORDER_SELECTION_2; color: $COLOR_TEXT_1; } &:focus { border: $BORDER_SELECTION_3; } &:selected { background-color: $COLOR_ACCENT_2; color: $COLOR_BACKGROUND_4; } } /* QTabWiget -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabWidget { padding: 2px; selection-background-color: $COLOR_BACKGROUND_4; QWidget { /* Fixes #189 */ border-radius: $SIZE_BORDER_RADIUS; } &::pane { border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; margin: 0px; /* Fixes double border inside pane with pyqt5 */ padding: 0px; &:selected { background-color: $COLOR_BACKGROUND_4; border: 1px solid $COLOR_ACCENT_2; } } } /* QTabBar ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabBar { qproperty-drawBase: 0; border-radius: $SIZE_BORDER_RADIUS; margin: 0px; padding: 2px; border: 0; /* left: 5px; move to the right by 5px - removed for fix */ &::close-button { border: 0; margin: 0; padding: 4px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_close.png'); &:hover { image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_close_focus.png'); } &:pressed { image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_close_pressed.png'); } } &::tab { &:top:selected:disabled { border-bottom: 3px solid $COLOR_ACCENT_1; color: $COLOR_TEXT_4; background-color: $COLOR_BACKGROUND_4; } &:bottom:selected:disabled { border-top: 3px solid $COLOR_ACCENT_1; color: $COLOR_TEXT_4; background-color: $COLOR_BACKGROUND_4; } &:left:selected:disabled { border-right: 3px solid $COLOR_ACCENT_1; color: $COLOR_TEXT_4; background-color: $COLOR_BACKGROUND_4; } &:right:selected:disabled { border-left: 3px solid $COLOR_ACCENT_1; color: $COLOR_TEXT_4; background-color: $COLOR_BACKGROUND_4; } /* !selected and disabled ----------------------------------------- */ &:top:!selected:disabled { border-bottom: 3px solid $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; background-color: $COLOR_BACKGROUND_1; } &:bottom:!selected:disabled { border-top: 3px solid $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; background-color: $COLOR_BACKGROUND_1; } &:left:!selected:disabled { border-right: 3px solid $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; background-color: $COLOR_BACKGROUND_1; } &:right:!selected:disabled { border-left: 3px solid $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; background-color: $COLOR_BACKGROUND_1; } /* selected ------------------------------------------------------- */ &:top:!selected { border-bottom: 2px solid $COLOR_BACKGROUND_1; margin-top: 2px; } &:bottom:!selected { border-top: 2px solid $COLOR_BACKGROUND_1; margin-bottom: 3px; } &:left:!selected { border-left: 2px solid $COLOR_BACKGROUND_1; margin-right: 2px; } &:right:!selected { border-right: 2px solid $COLOR_BACKGROUND_1; margin-left: 2px; } &:top { background-color: $COLOR_BACKGROUND_4; color: $COLOR_TEXT_1; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; min-width: 5px; border-bottom: 3px solid $COLOR_BACKGROUND_4; border-top-left-radius: 3px; border-top-right-radius: 3px; &:selected { background-color: $COLOR_BACKGROUND_5; color: $COLOR_TEXT_1; border-bottom: 3px solid $COLOR_ACCENT_4; border-top-left-radius: 3px; border-top-right-radius: 3px; } &:!selected:hover { border: $BORDER_SELECTION_3; border-bottom: 3px solid $COLOR_ACCENT_3; /* Fixes spyder-ide/spyder#9766 */ padding-left: 4px; padding-right: 4px; } } &:bottom { color: $COLOR_TEXT_1; border-top: 3px solid $COLOR_BACKGROUND_4; background-color: $COLOR_BACKGROUND_4; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; min-width: 5px; &:selected { color: $COLOR_TEXT_1; background-color: $COLOR_BACKGROUND_5; border-top: 3px solid $COLOR_ACCENT_4; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; } &:!selected:hover { border: $BORDER_SELECTION_3; border-top: 3px solid $COLOR_ACCENT_3; /* Fixes spyder-ide/spyder#9766 */ padding-left: 4px; padding-right: 4px; } } &:left { color: $COLOR_TEXT_1; background-color: $COLOR_BACKGROUND_4; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-left-radius: 3px; border-bottom-left-radius: 3px; min-height: 5px; &:selected { color: $COLOR_TEXT_1; background-color: $COLOR_BACKGROUND_5; border-right: 3px solid $COLOR_ACCENT_4; } &:!selected:hover { border: $BORDER_SELECTION_3; border-right: 3px solid $COLOR_ACCENT_3; padding: 0px; } } &:right { color: $COLOR_TEXT_1; background-color: $COLOR_BACKGROUND_4; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; min-height: 5px; &:selected { color: $COLOR_TEXT_1; background-color: $COLOR_BACKGROUND_5; border-left: 3px solid $COLOR_ACCENT_4; } &:!selected:hover { border: $BORDER_SELECTION_3; border-left: 3px solid $COLOR_ACCENT_3; padding: 0px; } } } QToolButton { /* Fixes #136 */ background-color: $COLOR_BACKGROUND_4; height: 12px; width: 12px; &:pressed { background-color: $COLOR_BACKGROUND_4; &:hover { border: $BORDER_SELECTION_2; } } &::left-arrow { &:enabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_left.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_left_disabled.png'); } } &::right-arrow { &:enabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_right.png'); } &:disabled { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_right_disabled.png'); } } } } /* QDockWiget ------------------------------------------------------------- --------------------------------------------------------------------------- */ QDockWidget { outline: $BORDER_2; background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; // See discussion here: https://stackoverflow.com/questions/32145080/qdockwidget-float-close-button-hover-images titlebar-close-icon: url($PATH_RESOURCES + '/' + $ID + '/rc/transparent.png'); titlebar-normal-icon: url($PATH_RESOURCES + '/' + $ID + '/rc/transparent.png'); &::title { /* Better size for title bar */ padding: 3px; spacing: 4px; border: none; background-color: $COLOR_BACKGROUND_4; } &::close-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_close.png'); &:hover { image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_close_focus.png'); } &:pressed { image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_close_pressed.png'); } } &::float-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; // float button has an issue that if you change any of those // parameters bellow there will be a duplication in the icon // actually it seems that they are always there (duplication) border: 0; margin: 0; padding: 0; image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_undock.png'); &:hover { image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_undock_focus.png'); } &:pressed { image: url($PATH_RESOURCES + '/' + $ID + '/rc/window_undock_pressed.png'); } } } /* QTreeView QListView QTableView ----------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview --------------------------------------------------------------------------- */ QTreeView { &:branch { &:selected, &:hover { background: url($PATH_RESOURCES + '/' + $ID + '/rc/transparent.png'); } &:has-siblings:!adjoins-item { border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/branch_line.png') 0; } &:has-siblings:adjoins-item { border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/branch_more.png') 0; } &:!has-children:!has-siblings:adjoins-item { border-image: url($PATH_RESOURCES + '/' + $ID + '/rc/branch_end.png') 0; } &:has-children:!has-siblings:closed, &:closed:has-children:has-siblings { border-image: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/branch_closed.png'); } &:open:has-children:!has-siblings, &:open:has-children:has-siblings { border-image: none; image: url($PATH_RESOURCES + '/' + $ID + '/rc/branch_open.png'); } &:has-children:!has-siblings:closed:hover, &:closed:has-children:has-siblings:hover { image: url($PATH_RESOURCES + '/' + $ID + '/rc/branch_closed_focus.png'); } &:open:has-children:!has-siblings:hover, &:open:has-children:has-siblings:hover { image: url($PATH_RESOURCES + '/' + $ID + '/rc/branch_open_focus.png'); } } } QTreeView, QListView, QTableView, QColumnView { &::indicator { &:checked { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked.png'); &:hover, &:focus, &:pressed { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_checked_focus.png'); } } &:unchecked { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked.png'); &:hover, &:focus, &:pressed { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_unchecked_focus.png'); } } &:indeterminate { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_indeterminate.png'); &:hover, &:focus, &:pressed { image: url($PATH_RESOURCES + '/' + $ID + '/rc/checkbox_indeterminate_focus.png'); } } } } QTreeView, QListView, QTableView, QColumnView { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; color: $COLOR_TEXT_1; gridline-color: $COLOR_BACKGROUND_4; border-radius: $SIZE_BORDER_RADIUS; &:disabled { background-color: $COLOR_BACKGROUND_1; color: $COLOR_TEXT_4; } &:selected { background-color: $COLOR_ACCENT_2; color: $COLOR_BACKGROUND_4; } &:focus { border: $BORDER_SELECTION_3; } &::item { &:pressed { background-color: $COLOR_ACCENT_2; } &:selected { &:active { background-color: $COLOR_ACCENT_2; } } &:!selected { &:hover { outline: 0; color: $COLOR_TEXT_1; background-color: $COLOR_BACKGROUND_3; } } } } QTableCornerButton { &::section { background-color: $COLOR_BACKGROUND_1; border: 1px transparent $COLOR_BACKGROUND_4; border-radius: 0px; } } /* QHeaderView ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview --------------------------------------------------------------------------- */ QHeaderView { background-color: $COLOR_BACKGROUND_4; border: 0px transparent $COLOR_BACKGROUND_4; padding: 0; margin: 0; border-radius: 0; &:disabled { background-color: $COLOR_BACKGROUND_4; border: 1px transparent $COLOR_BACKGROUND_4; } &::section { background-color: $COLOR_BACKGROUND_4; color: $COLOR_TEXT_1; border-radius: 0; text-align: left; font-size: 13px; &:checked { color: $COLOR_TEXT_1; background-color: $COLOR_ACCENT_2; &:disabled { color: $COLOR_TEXT_4; background-color: $COLOR_ACCENT_1; } } &::horizontal { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-left: $BORDER_1; &::first, &::only-one { border-left: $BORDER_2; } &:disabled { color: $COLOR_TEXT_4; } } &::vertical { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-top: $BORDER_1; &::first, &::only-one { border-top: $BORDER_2; } &:disabled { color: $COLOR_TEXT_4; } } } &::down-arrow { /* Those settings (border/width/height/background-color) solve bug */ /* transparent arrow background and size */ background-color: $COLOR_BACKGROUND_4; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down.png'); } &::up-arrow { background-color: $COLOR_BACKGROUND_4; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_up.png'); } } /* QToolBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox --------------------------------------------------------------------------- */ QToolBox { padding: 0px; border: 0px; border: $BORDER_2; &:selected { padding: 0px; border: 2px solid $COLOR_ACCENT_2; } &::tab { background-color: $COLOR_BACKGROUND_1; border: $BORDER_2; color: $COLOR_TEXT_1; border-top-left-radius: 4px; border-top-right-radius: 4px; &:disabled { color: $COLOR_TEXT_4; } &:selected { background-color: $COLOR_BACKGROUND_6; border-bottom: 2px solid $COLOR_ACCENT_2; &:disabled { background-color: $COLOR_BACKGROUND_4; border-bottom: 2px solid $COLOR_ACCENT_1; } } &:!selected { background-color: $COLOR_BACKGROUND_4; border-bottom: 2px solid $COLOR_BACKGROUND_4; &:disabled { background-color: $COLOR_BACKGROUND_1; } } &:hover { border-color: $COLOR_ACCENT_3; border-bottom: 2px solid $COLOR_ACCENT_3; } } QScrollArea QWidget QWidget { padding: 0px; border: 0px; background-color: $COLOR_BACKGROUND_1; } } /* QFrame ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe https://doc.qt.io/qt-5/qframe.html#-prop https://doc.qt.io/qt-5/qframe.html#details https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color --------------------------------------------------------------------------- */ /* (dot) .QFrame fix #141, #126, #123 */ .QFrame { border-radius: $SIZE_BORDER_RADIUS; border: $BORDER_2; /* No frame */ &[frameShape="0"] { border-radius: $SIZE_BORDER_RADIUS; border: 1px transparent $COLOR_BACKGROUND_4; } /* HLine */ &[frameShape="4"] { max-height: 2px; border: none; background-color: $COLOR_BACKGROUND_4; } /* HLine */ &[frameShape="5"] { max-width: 2px; border: none; background-color: $COLOR_BACKGROUND_4; } } /* QSplitter -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter --------------------------------------------------------------------------- */ QSplitter { background-color: $COLOR_BACKGROUND_4; spacing: 0px; padding: 0px; margin: 0px; &::handle { background-color: $COLOR_BACKGROUND_4; border: 0px solid $COLOR_BACKGROUND_1; spacing: 0px; padding: 1px; margin: 0px; &:hover { background-color: $COLOR_TEXT_4; } &:horizontal { width: 5px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/line_vertical.png'); } &:vertical { height: 5px; image: url($PATH_RESOURCES + '/' + $ID + '/rc/line_horizontal.png'); } } } /* QDateEdit, QDateTimeEdit ----------------------------------------------- --------------------------------------------------------------------------- */ QDateEdit, QDateTimeEdit { selection-background-color: $COLOR_ACCENT_2; border-style: solid; border: $BORDER_2; border-radius: $SIZE_BORDER_RADIUS; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; min-width: 10px; &:on { selection-background-color: $COLOR_ACCENT_2; } &::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid $COLOR_BACKGROUND_4; } &::down-arrow { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down_disabled.png'); height: 8px; width: 8px; &:on, &:hover, &:focus { image: url($PATH_RESOURCES + '/' + $ID + '/rc/arrow_down.png'); } } QAbstractItemView { background-color: $COLOR_BACKGROUND_1; border-radius: $SIZE_BORDER_RADIUS; border: $BORDER_2; selection-background-color: $COLOR_ACCENT_2; } } /* QAbstractView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractView { &:hover { border: $BORDER_SELECTION_2; color: $COLOR_TEXT_1; } &:selected { background: $COLOR_ACCENT_2; color: $COLOR_BACKGROUND_4; } } /* PlotWidget ------------------------------------------------------------- --------------------------------------------------------------------------- */ PlotWidget { /* Fix cut labels in plots #134 */ padding: 0px; } sqlitebrowser-sqlitebrowser-5733cb7/src/sql/000077500000000000000000000000001463772530400212625ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/sql/ObjectIdentifier.cpp000066400000000000000000000043251463772530400252030ustar00rootroot00000000000000#include "ObjectIdentifier.h" static std::string duplicate_char(std::string str, char to_replace) { size_t pos = 0; while((pos = str.find(to_replace, pos)) != std::string::npos) { str.insert(pos, 1, to_replace); pos += 2; // Advance by two characters in order to avoid escaping a character multiple times } return str; } namespace sqlb { static escapeQuoting customQuoting = DoubleQuotes; void setIdentifierQuoting(escapeQuoting toQuoting) { customQuoting = toQuoting; } char getIdentifierQuoteChar() { switch(customQuoting) { case GraveAccents: return '`'; case SquareBrackets: return '['; case DoubleQuotes: return '"'; } return '"'; } std::string escapeIdentifier(const std::string& id) { switch(customQuoting) { case GraveAccents: return '`' + duplicate_char(id, '`') + '`'; case SquareBrackets: // There aren't any escaping possibilities for square brackets inside the identifier, // so we rely on the user to not enter these characters when this kind of quoting is // selected. return '[' + id + ']'; case DoubleQuotes: // This may produce a 'control reaches end of non-void function' warning if the // default branch is removed, even though we have covered all possibilities in the // switch statement. return '"' + duplicate_char(id, '"') + '"'; } } std::string escapeString(const std::string& literal) { return '\'' + duplicate_char(literal, '\'') + '\''; } bool ObjectIdentifier::fromSerialised(const std::string& serialised) { auto pos_comma = serialised.find(","); auto pos_colon = serialised.find(":"); if(pos_comma == serialised.npos || pos_colon == serialised.npos) return false; size_t size_schema, size_name; size_schema = std::stoul(serialised.substr(0, pos_comma)); size_name = std::stoul(serialised.substr(pos_comma+1, pos_colon-pos_comma)); if(pos_colon + size_schema + size_name + 1 != serialised.size()) return false; m_schema = serialised.substr(pos_colon + 1, size_schema); m_name = serialised.substr(pos_colon + size_schema + 1, size_name); return true; } } sqlitebrowser-sqlitebrowser-5733cb7/src/sql/ObjectIdentifier.h000066400000000000000000000051101463772530400246410ustar00rootroot00000000000000#ifndef OBJECTIDENTIFIER_H #define OBJECTIDENTIFIER_H #include namespace sqlb { enum escapeQuoting { DoubleQuotes, GraveAccents, SquareBrackets }; // Set quoting style for escapeIdentifier void setIdentifierQuoting(escapeQuoting toQuoting); // Get currently configured quote char char getIdentifierQuoteChar(); // Add quotes to an identifier std::string escapeIdentifier(const std::string& id); // Add SQL quotes to a string literal and escape any single quote character std::string escapeString(const std::string& literal); // Object identifier consisting of schema name and object name class ObjectIdentifier { public: ObjectIdentifier(const std::string& schema, const std::string& name) : m_schema(schema), m_name(name) { } ObjectIdentifier() : m_schema("main") { } explicit ObjectIdentifier(const std::string& variant) { // Try to unserialise the parameter first. If that does not work, just assume it's an object name for the main schema clear(); if(!fromSerialised(variant)) m_name = variant; } bool operator==(const ObjectIdentifier& rhs) const { return (rhs.m_schema == m_schema && rhs.m_name == m_name); } bool operator<(const ObjectIdentifier& rhs) const { return toDisplayString() < rhs.toDisplayString(); } const std::string& schema() const { return m_schema; } const std::string& name() const { return m_name; } void setSchema(const std::string& schema) { m_schema = schema; } void setName(const std::string& name) { m_name = name; } void clear() { m_schema = "main"; m_name.clear(); } bool isEmpty() const { return m_name.empty(); } // This returns a string which can be used in SQL statements std::string toString(bool shortName = false) const { if(shortName && m_schema == "main") return sqlb::escapeIdentifier(m_name); else return sqlb::escapeIdentifier(m_schema) + "." + sqlb::escapeIdentifier(m_name); } // This returns a string which can be used in the user interface std::string toDisplayString() const { if(m_schema == "main") return m_name; else return m_schema + "." + m_name; } std::string toSerialised() const { return std::to_string(m_schema.size()) + "," + std::to_string(m_name.size()) + ":" + m_schema + m_name; } bool fromSerialised(const std::string& serialised); private: std::string m_schema; std::string m_name; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/src/sql/Query.cpp000066400000000000000000000107111463772530400230730ustar00rootroot00000000000000#include "Query.h" #include namespace sqlb { void Query::clear() { m_table.clear(); m_rowid_columns = {"_rowid_"}; m_selected_columns.clear(); m_where.clear(); m_sort.clear(); } std::string Query::buildWherePart() const { if(m_where.empty() && m_global_where.empty()) return std::string(); std::string where = "WHERE "; if(m_where.size()) { for(auto i=m_where.cbegin();i!=m_where.cend();++i) { const auto it = findSelectedColumnByName(i->first); std::string column = sqlb::escapeIdentifier(i->first); if(it != m_selected_columns.cend() && it->selector != i->first) column = it->selector; where += column + " " + i->second + " AND "; } // Remove last ' AND ' where.erase(where.size() - 5); } if(m_global_where.size()) { // Connect to previous conditions if there are any if(m_where.size()) where += " AND "; // For each condition for(const auto& w : m_global_where) { where += "("; // For each selected column for(const auto& c : m_column_names) { const auto it = findSelectedColumnByName(c); std::string column = sqlb::escapeIdentifier(c); if(it != m_selected_columns.cend() && it->selector != column) column = it->selector; where += column + " " + w + " OR "; } // Remove last ' OR ' where.erase(where.size() - 4); where += ") AND "; } // Remove last ' AND ' where.erase(where.size() - 5); } return where; } std::string Query::buildQuery(bool withRowid) const { // Selector and display formats std::string selector; if (withRowid) { // We select the rowid data into a JSON array in case there are multiple rowid columns in order to have all values at hand. // If there is only one rowid column, we leave it as is. if(m_rowid_columns.size() == 1) { // As of SQLite 3.36 when selecting rowid from a view SQLite does not return NULL anymore but instead returns "rowid" and throws // an error. To avoid that error (we don't actually care for the value of this column, so the value is not the issue here) we // explicitly select NULL (without any quotes) here. if(m_is_view && !hasCustomRowIdColumn()) selector = "NULL,"; else selector = sqlb::escapeIdentifier(m_rowid_columns.at(0)) + ","; } else { selector += "sqlb_make_single_value("; for(size_t i=0;i::iterator Query::findSelectedColumnByName(const std::string& name) { return std::find_if(m_selected_columns.begin(), m_selected_columns.end(), [name](const SelectedColumn& c) { return name == c.original_column; }); } std::vector::const_iterator Query::findSelectedColumnByName(const std::string& name) const { return std::find_if(m_selected_columns.cbegin(), m_selected_columns.cend(), [name](const SelectedColumn& c) { return name == c.original_column; }); } } sqlitebrowser-sqlitebrowser-5733cb7/src/sql/Query.h000066400000000000000000000072411463772530400225440ustar00rootroot00000000000000#ifndef QUERY_H #define QUERY_H #include "ObjectIdentifier.h" #include #include #include namespace sqlb { struct OrderBy { enum SortDirection { Ascending, Descending }; OrderBy(const std::string& expr_, SortDirection direction_) : expr(expr_), is_expression(false), direction(direction_) {} bool operator==(const OrderBy& rhs) const { return direction == rhs.direction && is_expression == rhs.is_expression && expr == rhs.expr; } std::string toSql() const { if(is_expression) return expr + (direction == Ascending ? " ASC" : " DESC"); else return sqlb::escapeIdentifier(expr) + (direction == Ascending ? " ASC" : " DESC"); } std::string expr; bool is_expression; SortDirection direction; }; struct SelectedColumn { SelectedColumn(const std::string& original_column_, const std::string& selector_) : original_column(original_column_), selector(selector_) {} std::string original_column; std::string selector; }; class Query { public: Query() : m_is_view(false) {} explicit Query(const sqlb::ObjectIdentifier& table, bool is_view = false) : m_table(table), m_is_view(is_view) {} void clear(); std::string buildQuery(bool withRowid) const; std::string buildCountQuery() const; void setColumnNames(const std::vector& column_names) { m_column_names = column_names; } std::vector columnNames() const { return m_column_names; } void setTable(const sqlb::ObjectIdentifier& table) { m_table = table; } sqlb::ObjectIdentifier table() const { return m_table; } void setRowIdColumns(const std::vector& rowids) { m_rowid_columns = rowids; } std::vector rowIdColumns() const { return m_rowid_columns; } void setRowIdColumn(const std::string& rowid) { m_rowid_columns = {rowid}; } bool hasCustomRowIdColumn() const { return m_rowid_columns.size() != 1 || (m_rowid_columns.at(0) != "rowid" && m_rowid_columns.at(0) != "_rowid_"); } const std::vector& selectedColumns() const { return m_selected_columns; } std::vector& selectedColumns() { return m_selected_columns; } const std::unordered_map& where() const { return m_where; } std::unordered_map& where() { return m_where; } const std::vector& globalWhere() const { return m_global_where; } std::vector& globalWhere() { return m_global_where; } void setGlobalWhere(const std::vector& w) { m_global_where = w; } const std::vector& orderBy() const { return m_sort; } std::vector& orderBy() { return m_sort; } void setOrderBy(const std::vector& columns) { m_sort = columns; } private: std::vector m_column_names; sqlb::ObjectIdentifier m_table; std::vector m_rowid_columns; std::vector m_selected_columns; std::unordered_map m_where; // TODO The two where variables should be merged into a single variable which ... std::vector m_global_where; // ... holds some sort of general tree structure for all sorts of where conditions. std::vector m_sort; bool m_is_view; std::vector::iterator findSelectedColumnByName(const std::string& name); std::vector::const_iterator findSelectedColumnByName(const std::string& name) const; std::string buildWherePart() const; }; } #endif sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/000077500000000000000000000000001463772530400225565ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/ParserDriver.cpp000066400000000000000000000007011463772530400256700ustar00rootroot00000000000000#include "ParserDriver.h" namespace sqlb { namespace parser { ParserDriver::ParserDriver() : result(nullptr), trace_scanner(false), trace_parser(false), scanner(nullptr), buffer(nullptr) { } int ParserDriver::parse(const std::string& s) { source = s; begin_scan(); sqlb::parser::parser parse(scanner, *this); parse.set_debug_level(trace_parser); int res = parse(); end_scan(); return res; } } } sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/ParserDriver.h000066400000000000000000000030521463772530400253370ustar00rootroot00000000000000#ifndef PARSER_DRIVER_H #define PARSER_DRIVER_H #include #include "sqlite3_parser.hpp" #include "../sqlitetypes.h" // Give Flex the prototype of yylex we want and declare it for the parser typedef void* yyscan_t; namespace sqlb { namespace parser { class ParserDriver; } } #define YY_DECL sqlb::parser::parser::symbol_type yylex(yyscan_t yyscanner, sqlb::parser::ParserDriver& drv) YY_DECL; namespace sqlb { namespace parser { class ParserDriver { friend parser; public: ParserDriver(); void setScannerDebug(bool on) { trace_scanner = on; } void setParserDebug(bool on) { trace_parser = on; } // Run the parser on string s. Returns 0 on success int parse(const std::string& s); // Result returned by the parsing process sqlb::ObjectPtr result; // The token's location used by the scanner sqlb::parser::location location; private: // The string to be parsed std::string source; // Handling the scanner void begin_scan(); void end_scan(); // Debug flags for both scanner and parser bool trace_scanner; bool trace_parser; // Scanner state yyscan_t scanner; // Scanner buffer typedef struct yy_buffer_state* YY_BUFFER_STATE; YY_BUFFER_STATE buffer; // This is a purely internal variable used for parsing CREATE TABLE statements. It stores a pointer to the table column which // is currently being parsed. This allows us to modify the column and add additional constraints when we see them. std::shared_ptr last_table_column; }; } } #endif sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/README000066400000000000000000000005661463772530400234450ustar00rootroot00000000000000This directory contains the SQLite lexer and parser files. For convenience and to not have extra dependencies in the build process, the generated C++ files are included here. Please don't edit them by hand. To modify the lexer or parser, edit the sqlite3_lexer.ll or sqlite3_parser.yy files and rerun flex or bison like this: flex sqlite3_lexer.ll bison sqlite3_parser.yy sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/sqlite3_lexer.cpp000066400000000000000000003414201463772530400260510ustar00rootroot00000000000000#line 2 "sqlite3_lexer.cpp" #line 4 "sqlite3_lexer.cpp" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ /* %not-for-header */ /* %if-c-only */ /* %if-not-reentrant */ /* %endif */ /* %endif */ /* %ok-for-header */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* %if-c++-only */ /* %endif */ /* %if-c-only */ /* %endif */ /* %if-c-only */ /* %endif */ /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ /* %if-c-only */ #include #include #include #include /* %endif */ /* %if-tables-serialization */ /* %endif */ /* end standard C headers. */ /* %if-c-or-c++ */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* %endif */ /* begin standard C++ headers. */ /* %if-c++-only */ /* %endif */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* %not-for-header */ /* Returned upon end-of-file. */ #define YY_NULL 0 /* %ok-for-header */ /* %not-for-header */ /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* %ok-for-header */ /* %if-reentrant */ /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r /* %endif */ /* %if-not-reentrant */ /* %endif */ /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yyg->yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yyg->yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin , yyscanner ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif /* %if-not-reentrant */ /* %endif */ /* %if-c-only */ /* %if-not-reentrant */ /* %endif */ /* %endif */ #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = yyg->yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { /* %if-c-only */ FILE *yy_input_file; /* %endif */ /* %if-c++-only */ /* %endif */ char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* %if-c-only Standard (non-C++) definition */ /* %not-for-header */ /* %if-not-reentrant */ /* %endif */ /* %ok-for-header */ /* %endif */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] /* %if-c-only Standard (non-C++) definition */ /* %if-not-reentrant */ /* %not-for-header */ /* %ok-for-header */ /* %endif */ void yyrestart ( FILE *input_file , yyscan_t yyscanner ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); void yypop_buffer_state ( yyscan_t yyscanner ); static void yyensure_buffer_stack ( yyscan_t yyscanner ); static void yy_load_buffer_state ( yyscan_t yyscanner ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); /* %endif */ void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); void yyfree ( void * , yyscan_t yyscanner ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */ /* Begin user sect3 */ #define yywrap(yyscanner) (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP #define FLEX_DEBUG typedef flex_uint8_t YY_CHAR; typedef int yy_state_type; #define yytext_ptr yytext_r /* %% [1.5] DFA */ /* %if-c-only Standard (non-C++) definition */ static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); static int yy_get_next_buffer ( yyscan_t yyscanner ); static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); /* %endif */ /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ /* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\ yyleng = (int) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ /* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\ yyg->yy_c_buf_p = yy_cp; /* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */ #define YY_NUM_RULES 126 #define YY_END_OF_BUFFER 127 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[481] = { 0, 0, 0, 0, 0, 127, 125, 1, 2, 2, 125, 125, 112, 111, 125, 101, 102, 108, 106, 104, 107, 103, 109, 97, 97, 125, 105, 119, 115, 117, 99, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 125, 125, 113, 110, 125, 125, 125, 92, 1, 2, 121, 0, 95, 0, 96, 3, 97, 4, 97, 97, 0, 0, 100, 123, 120, 122, 116, 118, 124, 99, 92, 92, 92, 92, 92, 11, 92, 0, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 43, 92, 92, 46, 50, 92, 92, 92, 55, 92, 59, 60, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0, 0, 94, 0, 93, 114, 92, 0, 0, 92, 97, 0, 97, 97, 99, 92, 92, 92, 6, 12, 92, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 32, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 52, 92, 92, 56, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 76, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 98, 0, 0, 5, 92, 92, 92, 92, 0, 92, 92, 15, 16, 92, 92, 92, 92, 92, 92, 92, 92, 92, 29, 92, 31, 92, 92, 35, 92, 92, 92, 92, 40, 92, 42, 92, 92, 92, 92, 92, 92, 53, 92, 92, 58, 61, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 74, 92, 92, 92, 92, 80, 82, 83, 92, 92, 92, 92, 92, 89, 92, 92, 8, 92, 92, 92, 92, 92, 17, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 36, 92, 92, 92, 92, 92, 92, 47, 92, 92, 92, 54, 92, 92, 92, 92, 65, 66, 92, 92, 92, 92, 92, 92, 73, 92, 92, 92, 79, 92, 92, 92, 92, 87, 92, 90, 92, 9, 10, 92, 92, 92, 92, 92, 92, 21, 92, 92, 92, 28, 92, 33, 34, 37, 92, 92, 92, 44, 92, 92, 49, 51, 92, 92, 92, 92, 92, 68, 92, 92, 92, 92, 75, 77, 78, 92, 92, 85, 86, 92, 92, 92, 7, 14, 18, 92, 92, 92, 25, 92, 92, 92, 92, 39, 92, 92, 92, 57, 92, 92, 64, 92, 69, 92, 92, 92, 92, 92, 88, 91, 92, 19, 92, 92, 92, 27, 30, 92, 92, 92, 92, 92, 92, 92, 70, 92, 72, 92, 92, 92, 92, 92, 92, 92, 38, 41, 45, 48, 62, 63, 92, 71, 81, 84, 92, 20, 92, 92, 26, 67, 92, 92, 92, 92, 22, 23, 13, 92, 92, 92, 92, 24, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6, 1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 21, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 36, 52, 1, 53, 1, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 36, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 36, 1, 80, 1, 81, 1, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 1, 1, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const YY_CHAR yy_meta[86] = { 0, 1, 1, 2, 1, 1, 1, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 3, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 3, 3, 3 } ; static const flex_int16_t yy_base[489] = { 0, 0, 0, 59, 60, 299, 2446, 293, 85, 87, 270, 285, 2446, 2446, 278, 2446, 2446, 2446, 2446, 2446, 271, 73, 270, 77, 81, 0, 2446, 79, 255, 81, 244, 128, 64, 187, 76, 124, 154, 191, 34, 245, 68, 94, 87, 183, 225, 161, 255, 271, 315, 280, 99, 298, 157, 210, 206, 156, 2446, 153, 150, 145, 373, 223, 106, 2446, 214, 210, 205, 196, 2446, 229, 2446, 261, 349, 106, 0, 0, 2446, 2446, 2446, 2446, 2446, 2446, 111, 61, 310, 252, 170, 344, 331, 338, 122, 111, 109, 350, 359, 366, 370, 406, 396, 427, 400, 419, 437, 440, 322, 470, 433, 463, 378, 447, 473, 220, 493, 498, 515, 501, 487, 307, 506, 518, 521, 391, 443, 536, 550, 576, 573, 630, 600, 604, 610, 540, 613, 584, 624, 677, 643, 646, 667, 659, 671, 177, 127, 2446, 121, 110, 2446, 533, 72, 68, 688, 357, 113, 119, 0, 180, 681, 685, 711, 543, 546, 694, 60, 53, 697, 754, 746, 749, 774, 757, 714, 761, 789, 778, 781, 792, 562, 795, 798, 818, 815, 821, 830, 856, 850, 859, 863, 853, 866, 892, 847, 896, 878, 638, 914, 899, 918, 921, 924, 939, 931, 927, 945, 955, 960, 988, 983, 979, 994, 999, 1012, 1015, 706, 1008, 741, 1004, 1032, 1041, 1059, 1045, 1051, 1076, 1065, 1072, 1097, 1089, 2446, 113, 39, 718, 1092, 1110, 975, 1104, 31, 1123, 1135, 725, 824, 1127, 1140, 1120, 1152, 1155, 1168, 1174, 1158, 1171, 827, 1149, 886, 1180, 1198, 948, 1215, 1229, 1207, 1232, 951, 1222, 1023, 1225, 1243, 1251, 1239, 1260, 1255, 1027, 1284, 1273, 1131, 1194, 1290, 1299, 1304, 1310, 1318, 1307, 1321, 1325, 1328, 1342, 1379, 1385, 1201, 1388, 1391, 1394, 1397, 1355, 1278, 1281, 1408, 1411, 1414, 1423, 1437, 1335, 1430, 1418, 1346, 1449, 1455, 1469, 1485, 1488, 1349, 1477, 1491, 1505, 1496, 1510, 1519, 1514, 1499, 1523, 1536, 1542, 1358, 1556, 1552, 1572, 1582, 1585, 1578, 1364, 1590, 1597, 1593, 1382, 1606, 1612, 1620, 1616, 1458, 1481, 1623, 1642, 1635, 1650, 1647, 1665, 1527, 1670, 1679, 1682, 1539, 1685, 1703, 1691, 1721, 1564, 1733, 1568, 1725, 1656, 1662, 1744, 1739, 1730, 1751, 1754, 1764, 1709, 1757, 1779, 1799, 1712, 1792, 1760, 1773, 1782, 1816, 1806, 1786, 1802, 1825, 1830, 1809, 1819, 1840, 1853, 1862, 1856, 1865, 1835, 1891, 1869, 1894, 1899, 1847, 1859, 1876, 1907, 1926, 1881, 1884, 1932, 1940, 1936, 1888, 1904, 1910, 1953, 1962, 1946, 1918, 1976, 1982, 1988, 1967, 1959, 1997, 1994, 2010, 1970, 2015, 2018, 2004, 2034, 2021, 2037, 2029, 2059, 2063, 2077, 2042, 2045, 2085, 2048, 2070, 2093, 2098, 2066, 2073, 2101, 2129, 2134, 2120, 2139, 2147, 2142, 2106, 2154, 2112, 2150, 2162, 2169, 2174, 2184, 2180, 2210, 2166, 2177, 2188, 2191, 2194, 2197, 2238, 2201, 2204, 2207, 2265, 2214, 2254, 2262, 2219, 2222, 2268, 2281, 2284, 2287, 2233, 2290, 2247, 2308, 2300, 2275, 2320, 2293, 2446, 2405, 2412, 2414, 2419, 2426, 2433, 2436, 2439 } ; static const flex_int16_t yy_def[489] = { 0, 480, 1, 1, 1, 480, 480, 480, 480, 480, 480, 481, 480, 480, 482, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 483, 480, 480, 480, 480, 480, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 485, 486, 480, 480, 480, 480, 480, 484, 480, 480, 480, 481, 480, 482, 480, 480, 480, 480, 480, 480, 480, 487, 483, 480, 480, 480, 480, 480, 480, 480, 484, 484, 484, 484, 484, 484, 484, 480, 480, 480, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 488, 485, 480, 486, 480, 480, 484, 480, 480, 484, 480, 480, 480, 487, 480, 484, 484, 484, 484, 484, 484, 480, 480, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 480, 488, 480, 484, 484, 484, 484, 484, 480, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 484, 0, 480, 480, 480, 480, 480, 480, 480, 480 } ; static const flex_int16_t yy_nxt[2532] = { 0, 6, 7, 8, 9, 10, 11, 6, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 38, 40, 41, 42, 43, 44, 45, 38, 46, 47, 48, 49, 50, 51, 52, 38, 53, 6, 38, 54, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 38, 46, 47, 48, 49, 50, 51, 52, 38, 55, 56, 6, 57, 58, 59, 60, 60, 62, 62, 62, 62, 69, 69, 71, 93, 72, 72, 71, 116, 72, 72, 76, 77, 78, 80, 81, 99, 73, 62, 62, 100, 73, 83, 118, 60, 60, 90, 91, 92, 152, 147, 152, 226, 93, 153, 153, 74, 116, 117, 155, 155, 153, 153, 138, 234, 99, 73, 153, 153, 100, 73, 83, 118, 90, 91, 92, 90, 91, 92, 228, 90, 91, 92, 147, 74, 84, 85, 117, 90, 91, 92, 101, 138, 102, 144, 86, 141, 87, 103, 90, 91, 92, 88, 104, 89, 145, 90, 91, 92, 143, 105, 90, 91, 92, 84, 85, 226, 124, 106, 101, 163, 102, 162, 86, 107, 87, 103, 108, 155, 155, 88, 104, 89, 83, 125, 66, 90, 91, 92, 105, 90, 91, 92, 94, 67, 64, 124, 106, 158, 65, 95, 109, 107, 119, 61, 108, 149, 96, 110, 120, 97, 148, 125, 98, 147, 146, 90, 91, 92, 90, 91, 92, 94, 90, 91, 92, 158, 69, 69, 95, 109, 119, 90, 91, 92, 96, 110, 120, 97, 73, 145, 98, 143, 82, 121, 90, 91, 92, 122, 90, 91, 92, 123, 90, 91, 92, 111, 112, 79, 151, 151, 126, 70, 113, 114, 127, 68, 67, 73, 115, 65, 73, 121, 63, 61, 128, 122, 157, 480, 480, 123, 129, 90, 91, 92, 111, 112, 90, 91, 92, 126, 113, 114, 480, 127, 480, 130, 115, 480, 135, 73, 136, 480, 128, 137, 157, 480, 90, 91, 92, 129, 139, 140, 480, 90, 91, 92, 90, 91, 92, 480, 131, 480, 194, 130, 132, 480, 135, 133, 136, 156, 480, 137, 90, 91, 92, 178, 480, 134, 160, 139, 140, 90, 91, 92, 71, 480, 72, 72, 480, 131, 194, 480, 159, 132, 151, 151, 133, 156, 73, 90, 91, 92, 161, 480, 178, 134, 73, 160, 90, 91, 92, 90, 91, 92, 164, 166, 90, 91, 92, 84, 85, 159, 165, 90, 91, 92, 167, 73, 168, 86, 161, 150, 90, 91, 92, 73, 88, 184, 89, 90, 91, 92, 164, 480, 166, 90, 91, 92, 84, 85, 165, 90, 91, 92, 167, 169, 168, 86, 170, 150, 90, 91, 92, 174, 88, 184, 89, 90, 91, 92, 480, 90, 91, 92, 90, 91, 92, 171, 480, 90, 91, 92, 175, 172, 169, 176, 170, 177, 480, 181, 173, 174, 90, 91, 92, 480, 480, 90, 91, 92, 480, 90, 91, 92, 480, 185, 171, 90, 91, 92, 175, 172, 480, 480, 176, 480, 177, 181, 173, 182, 90, 91, 92, 179, 480, 183, 180, 480, 90, 91, 92, 480, 186, 185, 90, 91, 92, 480, 90, 91, 92, 90, 91, 92, 90, 91, 92, 182, 90, 91, 92, 187, 179, 183, 180, 188, 193, 480, 480, 192, 186, 480, 480, 189, 90, 91, 92, 480, 190, 480, 195, 90, 91, 92, 90, 91, 92, 197, 191, 187, 480, 480, 196, 188, 193, 198, 215, 192, 90, 91, 92, 480, 189, 480, 90, 91, 92, 190, 195, 90, 91, 92, 90, 91, 92, 197, 191, 90, 91, 92, 196, 480, 199, 480, 198, 215, 90, 91, 92, 90, 91, 92, 90, 91, 92, 200, 202, 480, 480, 201, 480, 203, 480, 217, 90, 91, 92, 90, 91, 92, 199, 90, 91, 92, 90, 91, 92, 90, 91, 92, 480, 90, 91, 92, 200, 202, 209, 480, 201, 203, 211, 480, 217, 90, 91, 92, 480, 210, 212, 213, 216, 480, 214, 480, 90, 91, 92, 90, 91, 92, 204, 205, 480, 480, 209, 90, 91, 92, 211, 218, 206, 221, 480, 207, 208, 210, 212, 213, 216, 222, 214, 90, 91, 92, 480, 90, 91, 92, 224, 204, 205, 90, 91, 92, 90, 91, 92, 218, 206, 480, 221, 207, 208, 219, 480, 90, 91, 92, 222, 223, 220, 90, 91, 92, 480, 225, 229, 224, 231, 90, 91, 92, 480, 230, 90, 91, 92, 90, 91, 92, 480, 480, 219, 233, 480, 480, 232, 223, 480, 220, 90, 91, 92, 225, 235, 229, 480, 231, 90, 91, 92, 230, 90, 91, 92, 480, 244, 480, 90, 91, 92, 233, 90, 91, 92, 232, 90, 91, 92, 90, 91, 92, 235, 239, 287, 90, 91, 92, 90, 91, 92, 236, 243, 237, 244, 240, 245, 90, 91, 92, 246, 480, 90, 91, 92, 90, 91, 92, 238, 90, 91, 92, 239, 287, 241, 248, 90, 91, 92, 480, 236, 243, 237, 240, 480, 245, 480, 242, 247, 246, 251, 250, 90, 91, 92, 249, 238, 90, 91, 92, 90, 91, 92, 241, 248, 90, 91, 92, 90, 91, 92, 252, 90, 91, 92, 242, 480, 247, 480, 251, 250, 480, 480, 249, 253, 90, 91, 92, 254, 90, 91, 92, 90, 91, 92, 255, 256, 480, 480, 252, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 253, 480, 480, 257, 254, 258, 259, 260, 480, 264, 261, 255, 256, 262, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 257, 258, 480, 259, 260, 264, 261, 263, 480, 266, 262, 265, 268, 480, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 267, 90, 91, 92, 90, 91, 92, 263, 266, 480, 480, 265, 268, 269, 270, 273, 90, 91, 92, 480, 480, 274, 480, 271, 90, 91, 92, 480, 480, 267, 90, 91, 92, 480, 90, 91, 92, 90, 91, 92, 272, 269, 270, 276, 273, 275, 277, 480, 480, 274, 480, 271, 90, 91, 92, 480, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 272, 90, 91, 92, 276, 275, 278, 277, 279, 90, 91, 92, 280, 302, 480, 90, 91, 92, 90, 91, 92, 90, 91, 92, 282, 90, 91, 92, 281, 288, 90, 91, 92, 285, 283, 278, 279, 480, 480, 286, 280, 302, 480, 480, 284, 90, 91, 92, 480, 90, 91, 92, 282, 90, 91, 92, 281, 288, 90, 91, 92, 289, 285, 283, 90, 91, 92, 286, 290, 90, 91, 92, 284, 292, 90, 91, 92, 291, 90, 91, 92, 293, 90, 91, 92, 90, 91, 92, 480, 289, 294, 480, 295, 90, 91, 92, 290, 90, 91, 92, 480, 292, 90, 91, 92, 296, 291, 480, 480, 293, 299, 90, 91, 92, 480, 90, 91, 92, 480, 294, 295, 90, 91, 92, 297, 300, 303, 480, 298, 90, 91, 92, 480, 296, 480, 90, 91, 92, 301, 299, 480, 304, 90, 91, 92, 308, 90, 91, 92, 305, 480, 306, 297, 300, 307, 303, 298, 480, 480, 90, 91, 92, 90, 91, 92, 480, 301, 90, 91, 92, 304, 315, 480, 308, 90, 91, 92, 480, 305, 306, 90, 91, 92, 307, 480, 309, 311, 480, 310, 313, 90, 91, 92, 90, 91, 92, 480, 90, 91, 92, 315, 90, 91, 92, 314, 90, 91, 92, 312, 316, 90, 91, 92, 309, 480, 311, 310, 313, 480, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 317, 314, 318, 480, 320, 312, 316, 90, 91, 92, 90, 91, 92, 90, 91, 92, 319, 480, 480, 90, 91, 92, 322, 321, 480, 323, 480, 480, 317, 324, 326, 318, 320, 90, 91, 92, 480, 90, 91, 92, 90, 91, 92, 480, 480, 319, 90, 91, 92, 328, 322, 480, 321, 323, 90, 91, 92, 325, 324, 326, 327, 90, 91, 92, 90, 91, 92, 480, 90, 91, 92, 90, 91, 92, 329, 480, 330, 328, 90, 91, 92, 331, 90, 91, 92, 325, 332, 333, 327, 480, 90, 91, 92, 480, 90, 91, 92, 334, 480, 90, 91, 92, 480, 329, 330, 335, 480, 336, 338, 480, 331, 480, 90, 91, 92, 332, 333, 90, 91, 92, 90, 91, 92, 90, 91, 92, 334, 337, 339, 90, 91, 92, 480, 480, 335, 336, 480, 338, 90, 91, 92, 480, 340, 90, 91, 92, 90, 91, 92, 90, 91, 92, 347, 480, 480, 337, 339, 90, 91, 92, 90, 91, 92, 341, 90, 91, 92, 90, 91, 92, 340, 342, 480, 343, 90, 91, 92, 480, 344, 345, 347, 90, 91, 92, 346, 90, 91, 92, 90, 91, 92, 480, 341, 480, 90, 91, 92, 90, 91, 92, 342, 480, 343, 90, 91, 92, 480, 344, 345, 480, 480, 348, 351, 346, 349, 354, 350, 353, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 348, 352, 351, 349, 354, 350, 355, 353, 90, 91, 92, 90, 91, 92, 90, 91, 92, 356, 90, 91, 92, 480, 480, 90, 91, 92, 357, 480, 480, 352, 90, 91, 92, 358, 355, 359, 480, 90, 91, 92, 360, 480, 480, 361, 363, 356, 480, 367, 480, 90, 91, 92, 480, 480, 357, 90, 91, 92, 90, 91, 92, 480, 358, 480, 359, 480, 362, 364, 360, 90, 91, 92, 361, 363, 365, 366, 367, 90, 91, 92, 368, 90, 91, 92, 369, 90, 91, 92, 90, 91, 92, 90, 91, 92, 362, 364, 90, 91, 92, 90, 91, 92, 365, 366, 370, 90, 91, 92, 368, 480, 90, 91, 92, 369, 90, 91, 92, 371, 372, 90, 91, 92, 373, 90, 91, 92, 374, 90, 91, 92, 376, 480, 370, 375, 377, 480, 90, 91, 92, 90, 91, 92, 90, 91, 92, 371, 372, 480, 379, 480, 480, 373, 90, 91, 92, 374, 90, 91, 92, 376, 378, 380, 375, 377, 90, 91, 92, 382, 90, 91, 92, 384, 90, 91, 92, 381, 379, 383, 90, 91, 92, 386, 90, 91, 92, 90, 91, 92, 378, 380, 90, 91, 92, 90, 91, 92, 382, 90, 91, 92, 384, 385, 387, 381, 388, 383, 90, 91, 92, 389, 386, 480, 90, 91, 92, 480, 90, 91, 92, 480, 90, 91, 92, 90, 91, 92, 391, 480, 480, 385, 480, 387, 388, 390, 480, 90, 91, 92, 389, 395, 480, 480, 90, 91, 92, 392, 393, 90, 91, 92, 90, 91, 92, 480, 480, 391, 90, 91, 92, 480, 394, 390, 90, 91, 92, 90, 91, 92, 395, 396, 90, 91, 92, 392, 393, 480, 480, 397, 401, 90, 91, 92, 90, 91, 92, 90, 91, 92, 394, 398, 399, 90, 91, 92, 480, 480, 400, 480, 396, 402, 403, 480, 480, 90, 91, 92, 397, 401, 404, 90, 91, 92, 90, 91, 92, 480, 480, 398, 480, 399, 405, 90, 91, 92, 400, 90, 91, 92, 402, 403, 90, 91, 92, 90, 91, 92, 480, 404, 409, 90, 91, 92, 406, 407, 90, 91, 92, 408, 405, 412, 480, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 411, 90, 91, 92, 409, 410, 413, 406, 480, 407, 90, 91, 92, 408, 412, 480, 90, 91, 92, 90, 91, 92, 414, 90, 91, 92, 480, 480, 411, 90, 91, 92, 415, 480, 410, 413, 90, 91, 92, 90, 91, 92, 416, 90, 91, 92, 90, 91, 92, 480, 414, 417, 421, 90, 91, 92, 90, 91, 92, 419, 415, 418, 90, 91, 92, 480, 480, 90, 91, 92, 480, 416, 90, 91, 92, 480, 420, 90, 91, 92, 417, 421, 423, 422, 90, 91, 92, 419, 424, 418, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 420, 90, 91, 92, 480, 425, 423, 422, 90, 91, 92, 480, 424, 90, 91, 92, 90, 91, 92, 426, 90, 91, 92, 90, 91, 92, 90, 91, 92, 428, 480, 90, 91, 92, 425, 427, 90, 91, 92, 90, 91, 92, 90, 91, 92, 480, 430, 426, 429, 431, 90, 91, 92, 432, 480, 480, 435, 428, 90, 91, 92, 433, 480, 427, 90, 91, 92, 480, 90, 91, 92, 480, 90, 91, 92, 430, 429, 436, 90, 91, 92, 480, 432, 434, 435, 90, 91, 92, 480, 437, 433, 90, 91, 92, 90, 91, 92, 438, 480, 90, 91, 92, 90, 91, 92, 439, 436, 440, 90, 91, 92, 434, 441, 480, 90, 91, 92, 437, 443, 480, 90, 91, 92, 480, 480, 438, 90, 91, 92, 90, 91, 92, 442, 439, 480, 440, 90, 91, 92, 480, 480, 441, 90, 91, 92, 444, 443, 90, 91, 92, 90, 91, 92, 90, 91, 92, 445, 446, 480, 448, 442, 90, 91, 92, 480, 447, 90, 91, 92, 90, 91, 92, 449, 444, 90, 91, 92, 90, 91, 92, 90, 91, 92, 452, 445, 451, 446, 448, 450, 480, 480, 90, 91, 92, 447, 90, 91, 92, 90, 91, 92, 449, 90, 91, 92, 90, 91, 92, 453, 90, 91, 92, 452, 451, 454, 480, 450, 90, 91, 92, 455, 480, 458, 480, 480, 90, 91, 92, 456, 457, 90, 91, 92, 90, 91, 92, 459, 453, 90, 91, 92, 461, 480, 454, 90, 91, 92, 480, 455, 480, 460, 458, 90, 91, 92, 480, 456, 462, 457, 480, 464, 90, 91, 92, 465, 459, 90, 91, 92, 463, 461, 90, 91, 92, 90, 91, 92, 480, 460, 90, 91, 92, 90, 91, 92, 462, 90, 91, 92, 464, 466, 480, 480, 465, 90, 91, 92, 463, 90, 91, 92, 90, 91, 92, 480, 480, 90, 91, 92, 90, 91, 92, 90, 91, 92, 480, 90, 91, 92, 466, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 467, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 468, 90, 91, 92, 469, 470, 90, 91, 92, 90, 91, 92, 471, 480, 480, 467, 472, 480, 478, 473, 90, 91, 92, 480, 480, 90, 91, 92, 480, 468, 480, 477, 469, 470, 90, 91, 92, 474, 480, 475, 471, 90, 91, 92, 480, 472, 478, 480, 473, 90, 91, 92, 90, 91, 92, 90, 91, 92, 476, 480, 477, 480, 90, 91, 92, 474, 479, 475, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, 480, 480, 480, 476, 90, 91, 92, 480, 480, 480, 480, 479, 90, 91, 92, 480, 480, 480, 480, 480, 480, 480, 480, 480, 90, 91, 92, 64, 480, 64, 64, 64, 64, 64, 66, 480, 66, 66, 66, 66, 66, 75, 75, 83, 480, 83, 83, 83, 142, 480, 142, 142, 142, 142, 142, 144, 480, 144, 144, 144, 144, 144, 154, 154, 227, 227, 227, 5, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480 } ; static const flex_int16_t yy_chk[2532] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 8, 8, 9, 9, 21, 21, 23, 32, 23, 23, 24, 40, 24, 24, 27, 27, 27, 29, 29, 34, 23, 62, 62, 34, 24, 234, 42, 3, 4, 38, 38, 38, 73, 228, 73, 227, 32, 73, 73, 23, 40, 41, 82, 82, 152, 152, 50, 163, 34, 23, 153, 153, 34, 24, 162, 42, 83, 83, 83, 32, 32, 32, 149, 40, 40, 40, 148, 23, 31, 31, 41, 34, 34, 34, 35, 50, 35, 145, 31, 52, 31, 35, 42, 42, 42, 31, 35, 31, 144, 41, 41, 41, 142, 36, 50, 50, 50, 31, 31, 141, 45, 36, 35, 92, 35, 91, 31, 36, 31, 35, 36, 155, 155, 31, 35, 31, 90, 45, 67, 35, 35, 35, 36, 31, 31, 31, 33, 66, 65, 45, 36, 86, 64, 33, 37, 36, 43, 61, 36, 59, 33, 37, 43, 33, 58, 45, 33, 57, 55, 36, 36, 36, 52, 52, 52, 33, 45, 45, 45, 86, 69, 69, 33, 37, 43, 86, 86, 86, 33, 37, 43, 33, 69, 54, 33, 53, 30, 44, 43, 43, 43, 44, 33, 33, 33, 44, 37, 37, 37, 39, 39, 28, 71, 71, 46, 22, 39, 39, 46, 20, 14, 69, 39, 11, 71, 44, 10, 7, 46, 44, 85, 5, 0, 44, 47, 111, 111, 111, 39, 39, 44, 44, 44, 46, 39, 39, 0, 46, 0, 47, 39, 0, 49, 71, 49, 0, 46, 49, 85, 0, 39, 39, 39, 47, 51, 51, 0, 85, 85, 85, 46, 46, 46, 0, 48, 0, 117, 47, 48, 0, 49, 48, 49, 84, 0, 49, 47, 47, 47, 104, 0, 48, 88, 51, 51, 49, 49, 49, 72, 0, 72, 72, 0, 48, 117, 0, 87, 48, 151, 151, 48, 84, 72, 51, 51, 51, 89, 0, 104, 48, 151, 88, 117, 117, 117, 84, 84, 84, 93, 95, 48, 48, 48, 60, 60, 87, 94, 104, 104, 104, 96, 72, 96, 60, 89, 60, 88, 88, 88, 151, 60, 108, 60, 89, 89, 89, 93, 0, 95, 87, 87, 87, 60, 60, 94, 93, 93, 93, 96, 97, 96, 60, 98, 60, 94, 94, 94, 100, 60, 108, 60, 95, 95, 95, 0, 96, 96, 96, 60, 60, 60, 99, 0, 108, 108, 108, 101, 99, 97, 102, 98, 103, 0, 106, 99, 100, 121, 121, 121, 0, 0, 98, 98, 98, 0, 100, 100, 100, 0, 109, 99, 97, 97, 97, 101, 99, 0, 0, 102, 0, 103, 106, 99, 107, 101, 101, 101, 105, 0, 107, 105, 0, 99, 99, 99, 0, 110, 109, 106, 106, 106, 0, 102, 102, 102, 103, 103, 103, 122, 122, 122, 107, 109, 109, 109, 112, 105, 107, 105, 113, 116, 0, 0, 115, 110, 0, 0, 114, 107, 107, 107, 0, 114, 0, 118, 105, 105, 105, 110, 110, 110, 120, 114, 112, 0, 0, 119, 113, 116, 123, 131, 115, 116, 116, 116, 0, 114, 0, 112, 112, 112, 114, 118, 113, 113, 113, 115, 115, 115, 120, 114, 118, 118, 118, 119, 0, 124, 0, 123, 131, 114, 114, 114, 119, 119, 119, 120, 120, 120, 125, 126, 0, 0, 125, 0, 126, 0, 133, 147, 147, 147, 123, 123, 123, 124, 131, 131, 131, 159, 159, 159, 160, 160, 160, 0, 124, 124, 124, 125, 126, 128, 0, 125, 126, 129, 0, 133, 176, 176, 176, 0, 128, 129, 130, 132, 0, 130, 0, 126, 126, 126, 125, 125, 125, 127, 127, 0, 0, 128, 133, 133, 133, 129, 134, 127, 136, 0, 127, 127, 128, 129, 130, 132, 137, 130, 128, 128, 128, 0, 129, 129, 129, 139, 127, 127, 130, 130, 130, 132, 132, 132, 134, 127, 0, 136, 127, 127, 135, 0, 134, 134, 134, 137, 138, 135, 127, 127, 127, 0, 140, 150, 139, 157, 193, 193, 193, 0, 156, 136, 136, 136, 137, 137, 137, 0, 0, 135, 161, 0, 0, 158, 138, 0, 135, 139, 139, 139, 140, 164, 150, 0, 157, 138, 138, 138, 156, 140, 140, 140, 0, 170, 0, 135, 135, 135, 161, 156, 156, 156, 158, 157, 157, 157, 150, 150, 150, 164, 166, 214, 161, 161, 161, 164, 164, 164, 165, 169, 165, 170, 167, 171, 212, 212, 212, 171, 0, 158, 158, 158, 170, 170, 170, 165, 229, 229, 229, 166, 214, 168, 173, 237, 237, 237, 0, 165, 169, 165, 167, 0, 171, 0, 168, 172, 171, 177, 175, 214, 214, 214, 174, 165, 166, 166, 166, 167, 167, 167, 168, 173, 165, 165, 165, 169, 169, 169, 178, 171, 171, 171, 168, 0, 172, 0, 177, 175, 0, 0, 174, 179, 168, 168, 168, 180, 173, 173, 173, 174, 174, 174, 181, 182, 0, 0, 178, 172, 172, 172, 175, 175, 175, 177, 177, 177, 178, 178, 178, 179, 0, 0, 183, 180, 184, 185, 186, 0, 190, 187, 181, 182, 188, 180, 180, 180, 179, 179, 179, 181, 181, 181, 238, 238, 238, 248, 248, 248, 182, 182, 182, 183, 184, 0, 185, 186, 190, 187, 189, 0, 192, 188, 191, 195, 0, 190, 190, 190, 184, 184, 184, 187, 187, 187, 183, 183, 183, 185, 185, 185, 194, 186, 186, 186, 188, 188, 188, 189, 192, 0, 0, 191, 195, 196, 197, 200, 192, 192, 192, 0, 0, 201, 0, 198, 250, 250, 250, 0, 0, 194, 189, 189, 189, 0, 191, 191, 191, 195, 195, 195, 199, 196, 197, 203, 200, 202, 204, 0, 0, 201, 0, 198, 194, 194, 194, 0, 196, 196, 196, 197, 197, 197, 198, 198, 198, 201, 201, 201, 199, 200, 200, 200, 203, 202, 205, 204, 206, 199, 199, 199, 207, 232, 0, 202, 202, 202, 253, 253, 253, 258, 258, 258, 209, 203, 203, 203, 208, 215, 204, 204, 204, 211, 210, 205, 206, 0, 0, 213, 207, 232, 0, 0, 210, 232, 232, 232, 0, 207, 207, 207, 209, 206, 206, 206, 208, 215, 205, 205, 205, 216, 211, 210, 208, 208, 208, 213, 217, 209, 209, 209, 210, 219, 215, 215, 215, 218, 213, 213, 213, 220, 210, 210, 210, 211, 211, 211, 0, 216, 221, 0, 222, 260, 260, 260, 217, 267, 267, 267, 0, 219, 216, 216, 216, 223, 218, 0, 0, 220, 225, 217, 217, 217, 0, 219, 219, 219, 0, 221, 222, 220, 220, 220, 224, 230, 233, 0, 224, 218, 218, 218, 0, 223, 0, 222, 222, 222, 231, 225, 0, 235, 223, 223, 223, 241, 221, 221, 221, 236, 0, 239, 224, 230, 240, 233, 224, 0, 0, 225, 225, 225, 230, 230, 230, 0, 231, 224, 224, 224, 235, 249, 0, 241, 233, 233, 233, 0, 236, 239, 231, 231, 231, 240, 0, 242, 244, 0, 243, 246, 241, 241, 241, 235, 235, 235, 0, 239, 239, 239, 249, 270, 270, 270, 247, 236, 236, 236, 245, 251, 240, 240, 240, 242, 0, 244, 243, 246, 0, 249, 249, 249, 242, 242, 242, 243, 243, 243, 246, 246, 246, 252, 247, 254, 0, 256, 245, 251, 244, 244, 244, 247, 247, 247, 245, 245, 245, 255, 0, 0, 251, 251, 251, 259, 257, 0, 261, 0, 0, 252, 262, 264, 254, 256, 271, 271, 271, 0, 252, 252, 252, 284, 284, 284, 0, 0, 255, 256, 256, 256, 266, 259, 0, 257, 261, 254, 254, 254, 263, 262, 264, 265, 259, 259, 259, 261, 261, 261, 0, 255, 255, 255, 257, 257, 257, 268, 0, 269, 266, 264, 264, 264, 272, 262, 262, 262, 263, 273, 274, 265, 0, 263, 263, 263, 0, 266, 266, 266, 275, 0, 265, 265, 265, 0, 268, 269, 276, 0, 277, 279, 0, 272, 0, 269, 269, 269, 273, 274, 290, 290, 290, 291, 291, 291, 268, 268, 268, 275, 278, 280, 272, 272, 272, 0, 0, 276, 277, 0, 279, 273, 273, 273, 0, 281, 274, 274, 274, 277, 277, 277, 275, 275, 275, 289, 0, 0, 278, 280, 276, 276, 276, 278, 278, 278, 282, 279, 279, 279, 280, 280, 280, 281, 283, 0, 285, 297, 297, 297, 0, 286, 287, 289, 281, 281, 281, 288, 300, 300, 300, 306, 306, 306, 0, 282, 0, 289, 289, 289, 318, 318, 318, 283, 0, 285, 325, 325, 325, 0, 286, 287, 0, 0, 292, 295, 288, 293, 299, 294, 298, 282, 282, 282, 329, 329, 329, 283, 283, 283, 285, 285, 285, 286, 286, 286, 287, 287, 287, 288, 288, 288, 292, 296, 295, 293, 299, 294, 301, 298, 292, 292, 292, 293, 293, 293, 294, 294, 294, 302, 299, 299, 299, 0, 0, 295, 295, 295, 303, 0, 0, 296, 298, 298, 298, 304, 301, 305, 0, 296, 296, 296, 307, 0, 0, 308, 310, 302, 0, 314, 0, 301, 301, 301, 0, 0, 303, 302, 302, 302, 334, 334, 334, 0, 304, 0, 305, 0, 309, 311, 307, 303, 303, 303, 308, 310, 312, 313, 314, 307, 307, 307, 315, 335, 335, 335, 316, 304, 304, 304, 305, 305, 305, 308, 308, 308, 309, 311, 310, 310, 310, 314, 314, 314, 312, 313, 317, 309, 309, 309, 315, 0, 311, 311, 311, 316, 313, 313, 313, 319, 320, 312, 312, 312, 321, 315, 315, 315, 322, 342, 342, 342, 324, 0, 317, 323, 326, 0, 316, 316, 316, 346, 346, 346, 317, 317, 317, 319, 320, 0, 328, 0, 0, 321, 320, 320, 320, 322, 319, 319, 319, 324, 327, 330, 323, 326, 351, 351, 351, 332, 353, 353, 353, 336, 321, 321, 321, 331, 328, 333, 324, 324, 324, 338, 322, 322, 322, 323, 323, 323, 327, 330, 326, 326, 326, 328, 328, 328, 332, 327, 327, 327, 336, 337, 339, 331, 340, 333, 330, 330, 330, 341, 338, 0, 331, 331, 331, 0, 333, 333, 333, 0, 332, 332, 332, 336, 336, 336, 344, 0, 0, 337, 0, 339, 340, 343, 0, 338, 338, 338, 341, 349, 0, 0, 337, 337, 337, 345, 347, 340, 340, 340, 339, 339, 339, 0, 0, 344, 355, 355, 355, 0, 348, 343, 356, 356, 356, 341, 341, 341, 349, 350, 343, 343, 343, 345, 347, 0, 0, 352, 359, 344, 344, 344, 345, 345, 345, 347, 347, 347, 348, 354, 357, 349, 349, 349, 0, 0, 358, 0, 350, 360, 361, 0, 0, 348, 348, 348, 352, 359, 362, 363, 363, 363, 367, 367, 367, 0, 0, 354, 0, 357, 364, 350, 350, 350, 358, 354, 354, 354, 360, 361, 359, 359, 359, 352, 352, 352, 0, 362, 368, 358, 358, 358, 365, 366, 357, 357, 357, 366, 364, 374, 0, 360, 360, 360, 361, 361, 361, 364, 364, 364, 369, 369, 369, 373, 362, 362, 362, 368, 372, 376, 365, 0, 366, 370, 370, 370, 366, 374, 0, 365, 365, 365, 371, 371, 371, 377, 374, 374, 374, 0, 0, 373, 368, 368, 368, 380, 0, 372, 376, 366, 366, 366, 375, 375, 375, 381, 373, 373, 373, 378, 378, 378, 0, 377, 382, 387, 372, 372, 372, 379, 379, 379, 384, 380, 383, 376, 376, 376, 0, 0, 377, 377, 377, 0, 381, 385, 385, 385, 0, 386, 380, 380, 380, 382, 387, 389, 388, 390, 390, 390, 384, 393, 383, 381, 381, 381, 383, 383, 383, 391, 391, 391, 382, 382, 382, 384, 384, 384, 386, 387, 387, 387, 0, 394, 389, 388, 392, 392, 392, 0, 393, 395, 395, 395, 396, 396, 396, 397, 400, 400, 400, 386, 386, 386, 388, 388, 388, 399, 0, 389, 389, 389, 394, 398, 401, 401, 401, 393, 393, 393, 402, 402, 402, 0, 404, 397, 403, 405, 406, 406, 406, 407, 0, 0, 410, 399, 394, 394, 394, 408, 0, 398, 397, 397, 397, 0, 399, 399, 399, 0, 398, 398, 398, 404, 403, 412, 405, 405, 405, 0, 407, 409, 410, 403, 403, 403, 0, 413, 408, 411, 411, 411, 404, 404, 404, 414, 0, 410, 410, 410, 415, 415, 415, 416, 412, 417, 407, 407, 407, 409, 419, 0, 408, 408, 408, 413, 422, 0, 409, 409, 409, 0, 0, 414, 413, 413, 413, 412, 412, 412, 421, 416, 0, 417, 418, 418, 418, 0, 0, 419, 414, 414, 414, 423, 422, 416, 416, 416, 417, 417, 417, 420, 420, 420, 424, 425, 0, 430, 421, 422, 422, 422, 0, 428, 419, 419, 419, 421, 421, 421, 431, 423, 426, 426, 426, 427, 427, 427, 429, 429, 429, 435, 424, 432, 425, 430, 431, 0, 0, 423, 423, 423, 428, 424, 424, 424, 433, 433, 433, 431, 430, 430, 430, 434, 434, 434, 436, 425, 425, 425, 435, 432, 437, 0, 431, 428, 428, 428, 438, 0, 441, 0, 0, 431, 431, 431, 439, 440, 432, 432, 432, 435, 435, 435, 443, 436, 442, 442, 442, 446, 0, 437, 444, 444, 444, 0, 438, 0, 445, 441, 438, 438, 438, 0, 439, 447, 440, 0, 449, 436, 436, 436, 450, 443, 437, 437, 437, 448, 446, 439, 439, 439, 441, 441, 441, 0, 445, 440, 440, 440, 445, 445, 445, 447, 443, 443, 443, 449, 451, 0, 0, 450, 446, 446, 446, 448, 452, 452, 452, 447, 447, 447, 0, 0, 448, 448, 448, 453, 453, 453, 450, 450, 450, 0, 449, 449, 449, 451, 454, 454, 454, 455, 455, 455, 456, 456, 456, 457, 457, 457, 458, 459, 459, 459, 460, 460, 460, 461, 461, 461, 451, 451, 451, 462, 463, 463, 463, 464, 465, 466, 466, 466, 467, 467, 467, 468, 0, 0, 458, 469, 0, 477, 470, 472, 472, 472, 0, 0, 458, 458, 458, 0, 462, 0, 476, 464, 465, 474, 474, 474, 471, 0, 473, 468, 464, 464, 464, 0, 469, 477, 0, 470, 465, 465, 465, 462, 462, 462, 468, 468, 468, 475, 0, 476, 0, 477, 477, 477, 471, 478, 473, 469, 469, 469, 470, 470, 470, 471, 471, 471, 473, 473, 473, 479, 479, 479, 0, 0, 0, 475, 476, 476, 476, 0, 0, 0, 0, 478, 475, 475, 475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 478, 478, 478, 481, 0, 481, 481, 481, 481, 481, 482, 0, 482, 482, 482, 482, 482, 483, 483, 484, 0, 484, 484, 484, 485, 0, 485, 485, 485, 485, 485, 486, 0, 486, 486, 486, 486, 486, 487, 487, 488, 488, 488, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480 } ; static const flex_int16_t yy_rule_linenum[126] = { 0, 80, 81, 83, 89, 113, 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 202, 203, 204, 205, 206, 207, 208, 209, 210, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237 } ; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET #line 1 "sqlite3_lexer.ll" #line 2 "sqlite3_lexer.ll" #include #include "ParserDriver.h" #include "sqlite3_parser.hpp" #line 1244 "sqlite3_lexer.cpp" #define YY_NO_UNISTD_H 1 #line 12 "sqlite3_lexer.ll" #define TOKEN(n) sqlb::parser::parser::symbol_type(sqlb::parser::parser::token::TOK_##n, yytext, loc) std::string unquote_string(std::string s, char quote_char) { if(s.size() < 2) return s; if(quote_char == '[') { if(s.front() == '[' && s.back() == ']') s = s.substr(1, s.size()-2); } else { if(s.front() == quote_char && s.back() == quote_char) { s = s.substr(1, s.size()-2); auto pos = s.npos; while((pos = s.find(std::string(2, quote_char))) != s.npos) s = s.replace(pos, 2, std::string(1, quote_char)); } } return s; } #line 1270 "sqlite3_lexer.cpp" #line 55 "sqlite3_lexer.ll" /* TODO Add $ bind parameters */ // Code run each time a pattern is matched. #define YY_USER_ACTION loc.columns(yyleng); #line 1275 "sqlite3_lexer.cpp" #line 1277 "sqlite3_lexer.cpp" #define INITIAL 0 #define BETWEEN_MODE 1 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ /* %if-c-only */ #include /* %endif */ /* %if-c++-only */ /* %endif */ #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* %if-c-only Reentrant structure and macros (non-C++). */ /* %if-reentrant */ /* Holds the entire state of the reentrant scanner. */ struct yyguts_t { /* User-defined. Not touched by flex. */ YY_EXTRA_TYPE yyextra_r; /* The rest are the same as the globals declared in the non-reentrant scanner. */ FILE *yyin_r, *yyout_r; size_t yy_buffer_stack_top; /**< index of top of stack. */ size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; int yy_n_chars; int yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; int yy_did_buffer_switch_on_eof; int yy_start_stack_ptr; int yy_start_stack_depth; int *yy_start_stack; yy_state_type yy_last_accepting_state; char* yy_last_accepting_cpos; int yylineno_r; int yy_flex_debug_r; char *yytext_r; int yy_more_flag; int yy_more_len; }; /* end struct yyguts_t */ /* %if-c-only */ static int yy_init_globals ( yyscan_t yyscanner ); /* %endif */ /* %if-reentrant */ int yylex_init (yyscan_t* scanner); int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); /* %endif */ /* %endif End reentrant structures and macros. */ /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( yyscan_t yyscanner ); int yyget_debug ( yyscan_t yyscanner ); void yyset_debug ( int debug_flag , yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); FILE *yyget_in ( yyscan_t yyscanner ); void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); int yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); int yyget_lineno ( yyscan_t yyscanner ); void yyset_lineno ( int _line_number , yyscan_t yyscanner ); int yyget_column ( yyscan_t yyscanner ); void yyset_column ( int _column_no , yyscan_t yyscanner ); /* %if-bison-bridge */ /* %endif */ /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( yyscan_t yyscanner ); #else extern int yywrap ( yyscan_t yyscanner ); #endif #endif /* %not-for-header */ #ifndef YY_NO_UNPUT #endif /* %ok-for-header */ /* %endif */ #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * , yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT /* %if-c-only Standard (non-C++) definition */ /* %not-for-header */ #ifdef __cplusplus static int yyinput ( yyscan_t yyscanner ); #else static int input ( yyscan_t yyscanner ); #endif /* %ok-for-header */ /* %endif */ #endif /* %if-c-only */ /* %endif */ /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* %if-c-only Standard (non-C++) definition */ /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) /* %endif */ /* %if-c++-only C++ definition */ /* %endif */ #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ /* %% [5.0] fread()/read() definition of YY_INPUT goes here unless we're doing C++ \ */\ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ /* %if-c++-only C++ definition \ */\ /* %endif */ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR /* %if-c-only */ #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ #endif /* %if-tables-serialization structures and prototypes */ /* %not-for-header */ /* %ok-for-header */ /* %not-for-header */ /* %tables-yydmap generated elements */ /* %endif */ /* end tables serialization structures and prototypes */ /* %ok-for-header */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 /* %if-c-only Standard (non-C++) definition */ extern int yylex (yyscan_t yyscanner); #define YY_DECL int yylex (yyscan_t yyscanner) /* %endif */ /* %if-c++-only C++ definition */ /* %endif */ #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif /* %% [6.0] YY_RULE_SETUP definition goes here */ #define YY_RULE_SETUP \ YY_USER_ACTION /* %not-for-header */ /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( !yyg->yy_init ) { yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yyg->yy_start ) yyg->yy_start = 1; /* first start state */ if ( ! yyin ) /* %if-c-only */ yyin = stdin; /* %endif */ /* %if-c++-only */ /* %endif */ if ( ! yyout ) /* %if-c-only */ yyout = stdout; /* %endif */ /* %if-c++-only */ /* %endif */ if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_load_buffer_state( yyscanner ); } { /* %% [7.0] user's declarations go here */ #line 69 "sqlite3_lexer.ll" #line 73 "sqlite3_lexer.ll" // Shortcut to the location held by the driver sqlb::parser::location& loc = drv.location; // Code run each time yylex is called. loc.step(); #line 1615 "sqlite3_lexer.cpp" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { /* %% [8.0] yymore()-related code goes here */ yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ *yy_cp = yyg->yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; /* %% [9.0] code to set up and find next match goes here */ yy_current_state = yyg->yy_start; yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 481 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_current_state != 480 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; yy_find_action: /* %% [10.0] code to find the action number goes here */ yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; /* %% [11.0] code for yylineno update goes here */ do_action: /* This label is used only to access EOF actions. */ /* %% [12.0] debug code goes here */ if ( yy_flex_debug ) { if ( yy_act == 0 ) fprintf( stderr, "--scanner backing up\n" ); else if ( yy_act < 126 ) fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n", (long)yy_rule_linenum[yy_act], yytext ); else if ( yy_act == 126 ) fprintf( stderr, "--accepting default rule (\"%s\")\n", yytext ); else if ( yy_act == 127 ) fprintf( stderr, "--(end of buffer or a NUL)\n" ); else fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); } switch ( yy_act ) { /* beginning of action switch */ /* %% [13.0] actions go here */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yyg->yy_hold_char; yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP #line 80 "sqlite3_lexer.ll" loc.step(); YY_BREAK case 2: /* rule 2 can match eol */ YY_RULE_SETUP #line 81 "sqlite3_lexer.ll" loc.lines(yyleng); loc.step(); YY_BREAK case 3: YY_RULE_SETUP #line 83 "sqlite3_lexer.ll" { int c; while((c = yyinput(yyscanner)) != '\n' && c != EOF) ; /* eat up text of comment */ } YY_BREAK case 4: YY_RULE_SETUP #line 89 "sqlite3_lexer.ll" { int c; for(;;) { while((c = yyinput(yyscanner)) != '*' && c != EOF) ; /* eat up text of comment */ if(c == '*') { while((c = yyinput(yyscanner)) == '*') ; if(c == '/') break; /* found the end */ } if(c == EOF) throw sqlb::parser::parser::syntax_error(loc, "EOF in comment"); } } YY_BREAK /* For lack of a better idea, we need this hack to avoid reduce/reduce conflicts in the rules for parsing BETWEEN expressions. * What we do here is distinguish two types of AND operators: the regular one and the special case when the AND follows a BETWEEN keyword. */ case 5: YY_RULE_SETUP #line 113 "sqlite3_lexer.ll" { BEGIN INITIAL; return TOKEN(AND_BETWEEN); } YY_BREAK case 6: YY_RULE_SETUP #line 114 "sqlite3_lexer.ll" return TOKEN(AND); YY_BREAK case 7: YY_RULE_SETUP #line 115 "sqlite3_lexer.ll" { BEGIN BETWEEN_MODE; return TOKEN(BETWEEN); } YY_BREAK case 8: YY_RULE_SETUP #line 117 "sqlite3_lexer.ll" return TOKEN(ABORT); YY_BREAK case 9: YY_RULE_SETUP #line 118 "sqlite3_lexer.ll" return TOKEN(ACTION); YY_BREAK case 10: YY_RULE_SETUP #line 119 "sqlite3_lexer.ll" return TOKEN(ALWAYS); YY_BREAK case 11: YY_RULE_SETUP #line 120 "sqlite3_lexer.ll" return TOKEN(AS); YY_BREAK case 12: YY_RULE_SETUP #line 121 "sqlite3_lexer.ll" return TOKEN(ASC); YY_BREAK case 13: YY_RULE_SETUP #line 122 "sqlite3_lexer.ll" return TOKEN(AUTOINCREMENT); YY_BREAK case 14: YY_RULE_SETUP #line 123 "sqlite3_lexer.ll" return TOKEN(CASCADE); YY_BREAK case 15: YY_RULE_SETUP #line 124 "sqlite3_lexer.ll" return TOKEN(CASE); YY_BREAK case 16: YY_RULE_SETUP #line 125 "sqlite3_lexer.ll" return TOKEN(CAST); YY_BREAK case 17: YY_RULE_SETUP #line 126 "sqlite3_lexer.ll" return TOKEN(CHECK); YY_BREAK case 18: YY_RULE_SETUP #line 127 "sqlite3_lexer.ll" return TOKEN(COLLATE); YY_BREAK case 19: YY_RULE_SETUP #line 128 "sqlite3_lexer.ll" return TOKEN(CONFLICT); YY_BREAK case 20: YY_RULE_SETUP #line 129 "sqlite3_lexer.ll" return TOKEN(CONSTRAINT); YY_BREAK case 21: YY_RULE_SETUP #line 130 "sqlite3_lexer.ll" return TOKEN(CREATE); YY_BREAK case 22: YY_RULE_SETUP #line 131 "sqlite3_lexer.ll" return TOKEN(CURRENT_DATE); YY_BREAK case 23: YY_RULE_SETUP #line 132 "sqlite3_lexer.ll" return TOKEN(CURRENT_TIME); YY_BREAK case 24: YY_RULE_SETUP #line 133 "sqlite3_lexer.ll" return TOKEN(CURRENT_TIMESTAMP); YY_BREAK case 25: YY_RULE_SETUP #line 134 "sqlite3_lexer.ll" return TOKEN(DEFAULT); YY_BREAK case 26: YY_RULE_SETUP #line 135 "sqlite3_lexer.ll" return TOKEN(DEFERRABLE); YY_BREAK case 27: YY_RULE_SETUP #line 136 "sqlite3_lexer.ll" return TOKEN(DEFERRED); YY_BREAK case 28: YY_RULE_SETUP #line 137 "sqlite3_lexer.ll" return TOKEN(DELETE); YY_BREAK case 29: YY_RULE_SETUP #line 138 "sqlite3_lexer.ll" return TOKEN(DESC); YY_BREAK case 30: YY_RULE_SETUP #line 139 "sqlite3_lexer.ll" return TOKEN(DISTINCT); YY_BREAK case 31: YY_RULE_SETUP #line 140 "sqlite3_lexer.ll" return TOKEN(ELSE); YY_BREAK case 32: YY_RULE_SETUP #line 141 "sqlite3_lexer.ll" return TOKEN(END); YY_BREAK case 33: YY_RULE_SETUP #line 142 "sqlite3_lexer.ll" return TOKEN(ESCAPE); YY_BREAK case 34: YY_RULE_SETUP #line 143 "sqlite3_lexer.ll" return TOKEN(EXISTS); YY_BREAK case 35: YY_RULE_SETUP #line 144 "sqlite3_lexer.ll" return TOKEN(FAIL); YY_BREAK case 36: YY_RULE_SETUP #line 145 "sqlite3_lexer.ll" return TOKEN(FALSE); YY_BREAK case 37: YY_RULE_SETUP #line 146 "sqlite3_lexer.ll" return TOKEN(FILTER); YY_BREAK case 38: YY_RULE_SETUP #line 147 "sqlite3_lexer.ll" return TOKEN(FOLLOWING); YY_BREAK case 39: YY_RULE_SETUP #line 148 "sqlite3_lexer.ll" return TOKEN(FOREIGN); YY_BREAK case 40: YY_RULE_SETUP #line 149 "sqlite3_lexer.ll" return TOKEN(FROM); YY_BREAK case 41: YY_RULE_SETUP #line 150 "sqlite3_lexer.ll" return TOKEN(GENERATED); YY_BREAK case 42: YY_RULE_SETUP #line 151 "sqlite3_lexer.ll" return TOKEN(GLOB); YY_BREAK case 43: YY_RULE_SETUP #line 152 "sqlite3_lexer.ll" return TOKEN(IF); YY_BREAK case 44: YY_RULE_SETUP #line 153 "sqlite3_lexer.ll" return TOKEN(IGNORE); YY_BREAK case 45: YY_RULE_SETUP #line 154 "sqlite3_lexer.ll" return TOKEN(IMMEDIATE); YY_BREAK case 46: YY_RULE_SETUP #line 155 "sqlite3_lexer.ll" return TOKEN(IN); YY_BREAK case 47: YY_RULE_SETUP #line 156 "sqlite3_lexer.ll" return TOKEN(INDEX); YY_BREAK case 48: YY_RULE_SETUP #line 157 "sqlite3_lexer.ll" return TOKEN(INITIALLY); YY_BREAK case 49: YY_RULE_SETUP #line 158 "sqlite3_lexer.ll" return TOKEN(INSERT); YY_BREAK case 50: YY_RULE_SETUP #line 159 "sqlite3_lexer.ll" return TOKEN(IS); YY_BREAK case 51: YY_RULE_SETUP #line 160 "sqlite3_lexer.ll" return TOKEN(ISNULL); YY_BREAK case 52: YY_RULE_SETUP #line 161 "sqlite3_lexer.ll" return TOKEN(KEY); YY_BREAK case 53: YY_RULE_SETUP #line 162 "sqlite3_lexer.ll" return TOKEN(LIKE); YY_BREAK case 54: YY_RULE_SETUP #line 163 "sqlite3_lexer.ll" return TOKEN(MATCH); YY_BREAK case 55: YY_RULE_SETUP #line 164 "sqlite3_lexer.ll" return TOKEN(NO); YY_BREAK case 56: YY_RULE_SETUP #line 165 "sqlite3_lexer.ll" return TOKEN(NOT); YY_BREAK case 57: YY_RULE_SETUP #line 166 "sqlite3_lexer.ll" return TOKEN(NOTNULL); YY_BREAK case 58: YY_RULE_SETUP #line 167 "sqlite3_lexer.ll" return TOKEN(NULL); YY_BREAK case 59: YY_RULE_SETUP #line 168 "sqlite3_lexer.ll" return TOKEN(ON); YY_BREAK case 60: YY_RULE_SETUP #line 169 "sqlite3_lexer.ll" return TOKEN(OR); YY_BREAK case 61: YY_RULE_SETUP #line 170 "sqlite3_lexer.ll" return TOKEN(OVER); YY_BREAK case 62: YY_RULE_SETUP #line 171 "sqlite3_lexer.ll" return TOKEN(PARTITION); YY_BREAK case 63: YY_RULE_SETUP #line 172 "sqlite3_lexer.ll" return TOKEN(PRECEDING); YY_BREAK case 64: YY_RULE_SETUP #line 173 "sqlite3_lexer.ll" return TOKEN(PRIMARY); YY_BREAK case 65: YY_RULE_SETUP #line 174 "sqlite3_lexer.ll" return TOKEN(RAISE); YY_BREAK case 66: YY_RULE_SETUP #line 175 "sqlite3_lexer.ll" return TOKEN(RANGE); YY_BREAK case 67: YY_RULE_SETUP #line 176 "sqlite3_lexer.ll" return TOKEN(REFERENCES); YY_BREAK case 68: YY_RULE_SETUP #line 177 "sqlite3_lexer.ll" return TOKEN(REGEXP); YY_BREAK case 69: YY_RULE_SETUP #line 178 "sqlite3_lexer.ll" return TOKEN(REPLACE); YY_BREAK case 70: YY_RULE_SETUP #line 179 "sqlite3_lexer.ll" return TOKEN(RESTRICT); YY_BREAK case 71: YY_RULE_SETUP #line 180 "sqlite3_lexer.ll" return TOKEN(RETURNING); YY_BREAK case 72: YY_RULE_SETUP #line 181 "sqlite3_lexer.ll" return TOKEN(ROLLBACK); YY_BREAK case 73: YY_RULE_SETUP #line 182 "sqlite3_lexer.ll" return TOKEN(ROWID); YY_BREAK case 74: YY_RULE_SETUP #line 183 "sqlite3_lexer.ll" return TOKEN(ROWS); YY_BREAK case 75: YY_RULE_SETUP #line 184 "sqlite3_lexer.ll" return TOKEN(SELECT); YY_BREAK case 76: YY_RULE_SETUP #line 185 "sqlite3_lexer.ll" return TOKEN(SET); YY_BREAK case 77: YY_RULE_SETUP #line 186 "sqlite3_lexer.ll" return TOKEN(STORED); YY_BREAK case 78: YY_RULE_SETUP #line 187 "sqlite3_lexer.ll" return TOKEN(STRICT); YY_BREAK case 79: YY_RULE_SETUP #line 188 "sqlite3_lexer.ll" return TOKEN(TABLE); YY_BREAK case 80: YY_RULE_SETUP #line 189 "sqlite3_lexer.ll" return TOKEN(TEMP); YY_BREAK case 81: YY_RULE_SETUP #line 190 "sqlite3_lexer.ll" return TOKEN(TEMPORARY); YY_BREAK case 82: YY_RULE_SETUP #line 191 "sqlite3_lexer.ll" return TOKEN(THEN); YY_BREAK case 83: YY_RULE_SETUP #line 192 "sqlite3_lexer.ll" return TOKEN(TRUE); YY_BREAK case 84: YY_RULE_SETUP #line 193 "sqlite3_lexer.ll" return TOKEN(UNBOUNDED); YY_BREAK case 85: YY_RULE_SETUP #line 194 "sqlite3_lexer.ll" return TOKEN(UNIQUE); YY_BREAK case 86: YY_RULE_SETUP #line 195 "sqlite3_lexer.ll" return TOKEN(UPDATE); YY_BREAK case 87: YY_RULE_SETUP #line 196 "sqlite3_lexer.ll" return TOKEN(USING); YY_BREAK case 88: YY_RULE_SETUP #line 197 "sqlite3_lexer.ll" return TOKEN(VIRTUAL); YY_BREAK case 89: YY_RULE_SETUP #line 198 "sqlite3_lexer.ll" return TOKEN(WHEN); YY_BREAK case 90: YY_RULE_SETUP #line 199 "sqlite3_lexer.ll" return TOKEN(WHERE); YY_BREAK case 91: YY_RULE_SETUP #line 200 "sqlite3_lexer.ll" return TOKEN(WITHOUT); YY_BREAK case 92: YY_RULE_SETUP #line 202 "sqlite3_lexer.ll" return sqlb::parser::parser::make_IDENTIFIER(yytext, loc); YY_BREAK case 93: YY_RULE_SETUP #line 203 "sqlite3_lexer.ll" return sqlb::parser::parser::make_IDENTIFIER(unquote_string(yytext, '`'), loc); YY_BREAK case 94: YY_RULE_SETUP #line 204 "sqlite3_lexer.ll" return sqlb::parser::parser::make_IDENTIFIER(unquote_string(yytext, '['), loc); YY_BREAK case 95: YY_RULE_SETUP #line 205 "sqlite3_lexer.ll" return sqlb::parser::parser::make_QUOTEDLITERAL(unquote_string(yytext, '"'), loc); YY_BREAK case 96: YY_RULE_SETUP #line 206 "sqlite3_lexer.ll" return sqlb::parser::parser::make_STRINGLITERAL(yytext, loc); YY_BREAK case 97: YY_RULE_SETUP #line 207 "sqlite3_lexer.ll" return sqlb::parser::parser::make_NUMERIC(yytext, loc); YY_BREAK case 98: YY_RULE_SETUP #line 208 "sqlite3_lexer.ll" return sqlb::parser::parser::make_BLOBLITERAL(yytext, loc); YY_BREAK case 99: YY_RULE_SETUP #line 209 "sqlite3_lexer.ll" return sqlb::parser::parser::make_BINDPARAMETER(yytext, loc); YY_BREAK case 100: YY_RULE_SETUP #line 210 "sqlite3_lexer.ll" return sqlb::parser::parser::make_BINDPARAMETER(yytext, loc); YY_BREAK case 101: YY_RULE_SETUP #line 212 "sqlite3_lexer.ll" return sqlb::parser::parser::make_LPAREN(loc); YY_BREAK case 102: YY_RULE_SETUP #line 213 "sqlite3_lexer.ll" return sqlb::parser::parser::make_RPAREN(loc); YY_BREAK case 103: YY_RULE_SETUP #line 214 "sqlite3_lexer.ll" return sqlb::parser::parser::make_DOT(loc); YY_BREAK case 104: YY_RULE_SETUP #line 215 "sqlite3_lexer.ll" return sqlb::parser::parser::make_COMMA(loc); YY_BREAK case 105: YY_RULE_SETUP #line 216 "sqlite3_lexer.ll" return sqlb::parser::parser::make_SEMI(loc); YY_BREAK case 106: YY_RULE_SETUP #line 217 "sqlite3_lexer.ll" return sqlb::parser::parser::make_PLUS(loc); YY_BREAK case 107: YY_RULE_SETUP #line 218 "sqlite3_lexer.ll" return sqlb::parser::parser::make_MINUS(loc); YY_BREAK case 108: YY_RULE_SETUP #line 219 "sqlite3_lexer.ll" return sqlb::parser::parser::make_STAR(loc); YY_BREAK case 109: YY_RULE_SETUP #line 220 "sqlite3_lexer.ll" return sqlb::parser::parser::make_SLASH(loc); YY_BREAK case 110: YY_RULE_SETUP #line 221 "sqlite3_lexer.ll" return sqlb::parser::parser::make_TILDE(loc); YY_BREAK case 111: YY_RULE_SETUP #line 222 "sqlite3_lexer.ll" return sqlb::parser::parser::make_AMPERSAND(loc); YY_BREAK case 112: YY_RULE_SETUP #line 223 "sqlite3_lexer.ll" return sqlb::parser::parser::make_PERCENT(loc); YY_BREAK case 113: YY_RULE_SETUP #line 224 "sqlite3_lexer.ll" return sqlb::parser::parser::make_BITOR(loc); YY_BREAK case 114: YY_RULE_SETUP #line 225 "sqlite3_lexer.ll" return sqlb::parser::parser::make_OROP(loc); YY_BREAK case 115: YY_RULE_SETUP #line 226 "sqlite3_lexer.ll" return sqlb::parser::parser::make_EQUAL(loc); YY_BREAK case 116: YY_RULE_SETUP #line 227 "sqlite3_lexer.ll" return sqlb::parser::parser::make_EQUAL2(loc); YY_BREAK case 117: YY_RULE_SETUP #line 228 "sqlite3_lexer.ll" return sqlb::parser::parser::make_GREATER(loc); YY_BREAK case 118: YY_RULE_SETUP #line 229 "sqlite3_lexer.ll" return sqlb::parser::parser::make_GREATEREQUAL(loc); YY_BREAK case 119: YY_RULE_SETUP #line 230 "sqlite3_lexer.ll" return sqlb::parser::parser::make_LOWER(loc); YY_BREAK case 120: YY_RULE_SETUP #line 231 "sqlite3_lexer.ll" return sqlb::parser::parser::make_LOWEREQUAL(loc); YY_BREAK case 121: YY_RULE_SETUP #line 232 "sqlite3_lexer.ll" return sqlb::parser::parser::make_UNEQUAL(loc); YY_BREAK case 122: YY_RULE_SETUP #line 233 "sqlite3_lexer.ll" return sqlb::parser::parser::make_UNEQUAL2(loc); YY_BREAK case 123: YY_RULE_SETUP #line 234 "sqlite3_lexer.ll" return sqlb::parser::parser::make_BITWISELEFT(loc); YY_BREAK case 124: YY_RULE_SETUP #line 235 "sqlite3_lexer.ll" return sqlb::parser::parser::make_BITWISERIGHT(loc); YY_BREAK case 125: YY_RULE_SETUP #line 237 "sqlite3_lexer.ll" throw sqlb::parser::parser::syntax_error(loc, "Invalid character: " + std::string(yytext)); YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(BETWEEN_MODE): #line 239 "sqlite3_lexer.ll" return sqlb::parser::parser::make_EOF(loc); YY_BREAK case 126: YY_RULE_SETUP #line 241 "sqlite3_lexer.ll" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK #line 2353 "sqlite3_lexer.cpp" case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yyg->yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; /* %if-c-only */ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; /* %endif */ /* %if-c++-only */ /* %endif */ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yyg->yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { /* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */ yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; } } else switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_END_OF_FILE: { yyg->yy_did_buffer_switch_on_eof = 0; if ( yywrap( yyscanner ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yyg->yy_c_buf_p = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* %ok-for-header */ /* %if-c++-only */ /* %not-for-header */ /* %ok-for-header */ /* %endif */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ /* %if-c-only */ static int yy_get_next_buffer (yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = yyg->yytext_ptr; int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) (yyg->yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), yyg->yy_n_chars, num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } if ( yyg->yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin , yyscanner); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } yyg->yy_n_chars += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ /* %if-c-only */ /* %not-for-header */ static yy_state_type yy_get_previous_state (yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { yy_state_type yy_current_state; char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* %% [15.0] code to get the start state into yy_current_state goes here */ yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { /* %% [16.0] code to find the next state goes here */ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 481 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ /* %if-c-only */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ /* %% [17.0] code to find the next state, and perhaps do backing up, goes here */ char *yy_cp = yyg->yy_c_buf_p; YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 481 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 480); (void)yyg; return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT /* %if-c-only */ /* %endif */ #endif /* %if-c-only */ #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) #else static int input (yyscan_t yyscanner) #endif /* %endif */ /* %if-c++-only */ /* %endif */ { int c; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; *yyg->yy_c_buf_p = yyg->yy_hold_char; if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) /* This was really a NUL. */ *yyg->yy_c_buf_p = '\0'; else { /* need more input */ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin , yyscanner); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( yyscanner ) ) return 0; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(yyscanner); #else return input(yyscanner); #endif } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + offset; break; } } } c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ yyg->yy_hold_char = *++yyg->yy_c_buf_p; /* %% [19.0] update BOL and yylineno */ return c; } /* %if-c-only */ #endif /* ifndef YY_NO_INPUT */ /* %endif */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * @param yyscanner The scanner object. * @note This function does not reset the start condition to @c INITIAL . */ /* %if-c-only */ void yyrestart (FILE * input_file , yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); yy_load_buffer_state( yyscanner ); } /* %if-c++-only */ /* %endif */ /** Switch to a different input buffer. * @param new_buffer The new input buffer. * @param yyscanner The scanner object. */ /* %if-c-only */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (yyscanner); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( yyscanner ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yyg->yy_did_buffer_switch_on_eof = 1; } /* %if-c-only */ static void yy_load_buffer_state (yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; /* %if-c-only */ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; /* %endif */ /* %if-c++-only */ /* %endif */ yyg->yy_hold_char = *yyg->yy_c_buf_p; } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * @param yyscanner The scanner object. * @return the allocated buffer state. */ /* %if-c-only */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file , yyscanner); return b; } /* %if-c++-only */ /* %endif */ /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * @param yyscanner The scanner object. */ /* %if-c-only */ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf , yyscanner ); yyfree( (void *) b , yyscanner ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ /* %if-c-only */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { int oerrno = errno; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flush_buffer( b , yyscanner); /* %if-c-only */ b->yy_input_file = file; /* %endif */ /* %if-c++-only */ /* %endif */ b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } /* %if-c-only */ b->yy_is_interactive = 0; /* %endif */ /* %if-c++-only */ /* %endif */ errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * @param yyscanner The scanner object. */ /* %if-c-only */ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( yyscanner ); } /* %if-c-or-c++ */ /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * @param yyscanner The scanner object. */ /* %if-c-only */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (new_buffer == NULL) return; yyensure_buffer_stack(yyscanner); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } /* %endif */ /* %if-c-or-c++ */ /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * @param yyscanner The scanner object. */ /* %if-c-only */ void yypop_buffer_state (yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; if (yyg->yy_buffer_stack_top > 0) --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } } /* %endif */ /* %if-c-or-c++ */ /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ /* %if-c-only */ static void yyensure_buffer_stack (yyscan_t yyscanner) /* %endif */ /* %if-c++-only */ /* %endif */ { yy_size_t num_to_alloc; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!yyg->yy_buffer_stack) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; } if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc (yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; } } /* %endif */ /* %if-c-only */ /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b , yyscanner ); return b; } /* %endif */ /* %if-c-only */ /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * @param yyscanner The scanner object. * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) { return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); } /* %endif */ /* %if-c-only */ /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n , yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n , yyscanner); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } /* %endif */ #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif /* %if-c-only */ static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* %endif */ /* %if-c++-only */ /* %endif */ /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ yyg->yy_hold_char = *yyg->yy_c_buf_p; \ *yyg->yy_c_buf_p = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /* %if-c-only */ /* %if-reentrant */ /** Get the user-defined data for this scanner. * @param yyscanner The scanner object. */ YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyextra; } /* %endif */ /** Get the current line number. * @param yyscanner The scanner object. */ int yyget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yylineno; } /** Get the current column number. * @param yyscanner The scanner object. */ int yyget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yycolumn; } /** Get the input stream. * @param yyscanner The scanner object. */ FILE *yyget_in (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyin; } /** Get the output stream. * @param yyscanner The scanner object. */ FILE *yyget_out (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyout; } /** Get the length of the current token. * @param yyscanner The scanner object. */ int yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; } /** Get the current token. * @param yyscanner The scanner object. */ char *yyget_text (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yytext; } /* %if-reentrant */ /** Set the user-defined data. This data is never touched by the scanner. * @param user_defined The data to be associated with this scanner. * @param yyscanner The scanner object. */ void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyextra = user_defined ; } /* %endif */ /** Set the current line number. * @param _line_number line number * @param yyscanner The scanner object. */ void yyset_lineno (int _line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); yylineno = _line_number; } /** Set the current column. * @param _column_no column number * @param yyscanner The scanner object. */ void yyset_column (int _column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_column called with no buffer" ); yycolumn = _column_no; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * @param yyscanner The scanner object. * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyin = _in_str ; } void yyset_out (FILE * _out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyout = _out_str ; } int yyget_debug (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yy_flex_debug; } void yyset_debug (int _bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flex_debug = _bdebug ; } /* %endif */ /* %if-reentrant */ /* Accessor methods for yylval and yylloc */ /* %if-bison-bridge */ /* %endif */ /* User-visible API */ /* yylex_init is special because it creates the scanner itself, so it is * the ONLY reentrant function that doesn't take the scanner as the last argument. * That's why we explicitly handle the declaration, instead of using our macros. */ int yylex_init(yyscan_t* ptr_yy_globals) { if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); return yy_init_globals ( *ptr_yy_globals ); } /* yylex_init_extra has the same functionality as yylex_init, but follows the * convention of taking the scanner as the last argument. Note however, that * this is a *pointer* to a scanner, as it will be allocated by this call (and * is the reason, too, why this function also must handle its own declaration). * The user defined value in the first argument will be available to yyalloc in * the yyextra field. */ int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) { struct yyguts_t dummy_yyguts; yyset_extra (yy_user_defined, &dummy_yyguts); if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); yyset_extra (yy_user_defined, *ptr_yy_globals); return yy_init_globals ( *ptr_yy_globals ); } /* %endif if-c-only */ /* %if-c-only */ static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ yyg->yy_buffer_stack = NULL; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = NULL; yyg->yy_init = 0; yyg->yy_start = 0; yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* %endif */ /* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */ /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(yyscanner); } /* Destroy the stack itself. */ yyfree(yyg->yy_buffer_stack , yyscanner); yyg->yy_buffer_stack = NULL; /* Destroy the start condition stack. */ yyfree( yyg->yy_start_stack , yyscanner ); yyg->yy_start_stack = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( yyscanner); /* %if-reentrant */ /* Destroy the main struct (reentrant only). */ yyfree ( yyscanner , yyscanner ); yyscanner = NULL; /* %endif */ return 0; } /* %endif */ /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s , yyscan_t yyscanner) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } /* %if-tables-serialization definitions */ /* %define-yytables The name for this specific scanner's tables. */ #define YYTABLES_NAME "yytables" /* %endif */ /* %ok-for-header */ #line 241 "sqlite3_lexer.ll" namespace sqlb { namespace parser { void ParserDriver::begin_scan() { yylex_init(&scanner); location.initialize(); yyset_debug(trace_scanner, scanner); buffer = yy_scan_string(source.c_str(), scanner); } void ParserDriver::end_scan() { yy_delete_buffer(buffer, scanner); yylex_destroy(scanner); } } } sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/sqlite3_lexer.h000066400000000000000000000317311463772530400255170ustar00rootroot00000000000000#ifndef yyHEADER_H #define yyHEADER_H 1 #define yyIN_HEADER 1 #line 6 "sqlite3_lexer.h" #line 8 "sqlite3_lexer.h" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ /* %not-for-header */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* %if-c++-only */ /* %endif */ /* %if-c-only */ /* %endif */ /* %if-c-only */ /* %endif */ /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ /* %if-c-only */ #include #include #include #include /* %endif */ /* %if-tables-serialization */ /* %endif */ /* end standard C headers. */ /* %if-c-or-c++ */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* %endif */ /* begin standard C++ headers. */ /* %if-c++-only */ /* %endif */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* %not-for-header */ /* %not-for-header */ /* %if-reentrant */ /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r /* %endif */ /* %if-not-reentrant */ /* %endif */ /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif /* %if-not-reentrant */ /* %endif */ /* %if-c-only */ /* %if-not-reentrant */ /* %endif */ /* %endif */ #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { /* %if-c-only */ FILE *yy_input_file; /* %endif */ /* %if-c++-only */ /* %endif */ char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* %if-c-only Standard (non-C++) definition */ /* %not-for-header */ /* %endif */ /* %if-c-only Standard (non-C++) definition */ /* %if-not-reentrant */ /* %not-for-header */ /* %endif */ void yyrestart ( FILE *input_file , yyscan_t yyscanner ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); void yypop_buffer_state ( yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); /* %endif */ void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); void yyfree ( void * , yyscan_t yyscanner ); /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */ /* Begin user sect3 */ #define yywrap(yyscanner) (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP #define FLEX_DEBUG #define yytext_ptr yytext_r /* %if-c-only Standard (non-C++) definition */ /* %endif */ #ifdef YY_HEADER_EXPORT_START_CONDITIONS #define INITIAL 0 #define BETWEEN_MODE 1 #endif #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ /* %if-c-only */ #include /* %endif */ /* %if-c++-only */ /* %endif */ #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* %if-c-only Reentrant structure and macros (non-C++). */ /* %if-reentrant */ /* %if-c-only */ /* %endif */ /* %if-reentrant */ int yylex_init (yyscan_t* scanner); int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); /* %endif */ /* %endif End reentrant structures and macros. */ /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( yyscan_t yyscanner ); int yyget_debug ( yyscan_t yyscanner ); void yyset_debug ( int debug_flag , yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); FILE *yyget_in ( yyscan_t yyscanner ); void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); int yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); int yyget_lineno ( yyscan_t yyscanner ); void yyset_lineno ( int _line_number , yyscan_t yyscanner ); int yyget_column ( yyscan_t yyscanner ); void yyset_column ( int _column_no , yyscan_t yyscanner ); /* %if-bison-bridge */ /* %endif */ /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( yyscan_t yyscanner ); #else extern int yywrap ( yyscan_t yyscanner ); #endif #endif /* %not-for-header */ /* %endif */ #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * , yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT /* %if-c-only Standard (non-C++) definition */ /* %not-for-header */ /* %endif */ #endif /* %if-c-only */ /* %endif */ /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* %if-tables-serialization structures and prototypes */ /* %not-for-header */ /* %not-for-header */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 /* %if-c-only Standard (non-C++) definition */ extern int yylex (yyscan_t yyscanner); #define YY_DECL int yylex (yyscan_t yyscanner) /* %endif */ /* %if-c++-only C++ definition */ /* %endif */ #endif /* !YY_DECL */ /* %not-for-header */ /* %if-c++-only */ /* %not-for-header */ /* %endif */ /* yy_get_previous_state - get the state just before the EOB char was reached */ /* %if-c-only */ /* %not-for-header */ #undef YY_NEW_FILE #undef YY_FLUSH_BUFFER #undef yy_set_bol #undef yy_new_buffer #undef yy_set_interactive #undef YY_DO_BEFORE_ACTION #ifdef YY_DECL_IS_OURS #undef YY_DECL_IS_OURS #undef YY_DECL #endif #ifndef yy_create_buffer_ALREADY_DEFINED #undef yy_create_buffer #endif #ifndef yy_delete_buffer_ALREADY_DEFINED #undef yy_delete_buffer #endif #ifndef yy_scan_buffer_ALREADY_DEFINED #undef yy_scan_buffer #endif #ifndef yy_scan_string_ALREADY_DEFINED #undef yy_scan_string #endif #ifndef yy_scan_bytes_ALREADY_DEFINED #undef yy_scan_bytes #endif #ifndef yy_init_buffer_ALREADY_DEFINED #undef yy_init_buffer #endif #ifndef yy_flush_buffer_ALREADY_DEFINED #undef yy_flush_buffer #endif #ifndef yy_load_buffer_state_ALREADY_DEFINED #undef yy_load_buffer_state #endif #ifndef yy_switch_to_buffer_ALREADY_DEFINED #undef yy_switch_to_buffer #endif #ifndef yypush_buffer_state_ALREADY_DEFINED #undef yypush_buffer_state #endif #ifndef yypop_buffer_state_ALREADY_DEFINED #undef yypop_buffer_state #endif #ifndef yyensure_buffer_stack_ALREADY_DEFINED #undef yyensure_buffer_stack #endif #ifndef yylex_ALREADY_DEFINED #undef yylex #endif #ifndef yyrestart_ALREADY_DEFINED #undef yyrestart #endif #ifndef yylex_init_ALREADY_DEFINED #undef yylex_init #endif #ifndef yylex_init_extra_ALREADY_DEFINED #undef yylex_init_extra #endif #ifndef yylex_destroy_ALREADY_DEFINED #undef yylex_destroy #endif #ifndef yyget_debug_ALREADY_DEFINED #undef yyget_debug #endif #ifndef yyset_debug_ALREADY_DEFINED #undef yyset_debug #endif #ifndef yyget_extra_ALREADY_DEFINED #undef yyget_extra #endif #ifndef yyset_extra_ALREADY_DEFINED #undef yyset_extra #endif #ifndef yyget_in_ALREADY_DEFINED #undef yyget_in #endif #ifndef yyset_in_ALREADY_DEFINED #undef yyset_in #endif #ifndef yyget_out_ALREADY_DEFINED #undef yyget_out #endif #ifndef yyset_out_ALREADY_DEFINED #undef yyset_out #endif #ifndef yyget_leng_ALREADY_DEFINED #undef yyget_leng #endif #ifndef yyget_text_ALREADY_DEFINED #undef yyget_text #endif #ifndef yyget_lineno_ALREADY_DEFINED #undef yyget_lineno #endif #ifndef yyset_lineno_ALREADY_DEFINED #undef yyset_lineno #endif #ifndef yyget_column_ALREADY_DEFINED #undef yyget_column #endif #ifndef yyset_column_ALREADY_DEFINED #undef yyset_column #endif #ifndef yywrap_ALREADY_DEFINED #undef yywrap #endif #ifndef yyget_lval_ALREADY_DEFINED #undef yyget_lval #endif #ifndef yyset_lval_ALREADY_DEFINED #undef yyset_lval #endif #ifndef yyget_lloc_ALREADY_DEFINED #undef yyget_lloc #endif #ifndef yyset_lloc_ALREADY_DEFINED #undef yyset_lloc #endif #ifndef yyalloc_ALREADY_DEFINED #undef yyalloc #endif #ifndef yyrealloc_ALREADY_DEFINED #undef yyrealloc #endif #ifndef yyfree_ALREADY_DEFINED #undef yyfree #endif #ifndef yytext_ALREADY_DEFINED #undef yytext #endif #ifndef yyleng_ALREADY_DEFINED #undef yyleng #endif #ifndef yyin_ALREADY_DEFINED #undef yyin #endif #ifndef yyout_ALREADY_DEFINED #undef yyout #endif #ifndef yy_flex_debug_ALREADY_DEFINED #undef yy_flex_debug #endif #ifndef yylineno_ALREADY_DEFINED #undef yylineno #endif #ifndef yytables_fload_ALREADY_DEFINED #undef yytables_fload #endif #ifndef yytables_destroy_ALREADY_DEFINED #undef yytables_destroy #endif #ifndef yyTABLES_NAME_ALREADY_DEFINED #undef yyTABLES_NAME #endif #line 241 "sqlite3_lexer.ll" #line 609 "sqlite3_lexer.h" #undef yyIN_HEADER #endif /* yyHEADER_H */ sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/sqlite3_lexer.ll000066400000000000000000000172401463772530400256760ustar00rootroot00000000000000%{ #include #include "ParserDriver.h" #include "sqlite3_parser.hpp" %} %option noyywrap nounput batch debug case-insensitive 8bit never-interactive nodefault nounistd reentrant warn %option header-file="sqlite3_lexer.h" %option outfile="sqlite3_lexer.cpp" %{ #define TOKEN(n) sqlb::parser::parser::symbol_type(sqlb::parser::parser::token::TOK_##n, yytext, loc) std::string unquote_string(std::string s, char quote_char) { if(s.size() < 2) return s; if(quote_char == '[') { if(s.front() == '[' && s.back() == ']') s = s.substr(1, s.size()-2); } else { if(s.front() == quote_char && s.back() == quote_char) { s = s.substr(1, s.size()-2); auto pos = s.npos; while((pos = s.find(std::string(2, quote_char))) != s.npos) s = s.replace(pos, 2, std::string(1, quote_char)); } } return s; } %} U [\x80-\xbf] U2 [\xc2-\xdf] U3 [\xe0-\xef] U4 [\xf0-\xf4] UNICODE {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} ID ([a-z_]|{UNICODE})([a-z0-9_$]|{UNICODE})* GRAVEQUOTEDID `([^\n`]|(``))*` SQUAREBRACKETID \[([^\n\]])*\] QUOTEDLITERAL \"([^\n\"]|(\"\"))*\" STRINGLITERAL \'([^\n\']|(\'\'))*\' BLOBLITERAL X\'[0-9a-f]*\' BINDPARAMETER_NUM \?([1-9]{DIGIT}*)? BINDPARAMETER_STR [:@][a-z]+ /* TODO Add $ bind parameters */ DIGIT [0-9] NUMERIC (({DIGIT}+(\.{DIGIT}*)?|(\.{DIGIT}+))(e[\+\-]?{DIGIT}+)?)|(0x[0-9a-f]+) NL [\r\n] WS [ \t\f] %{ // Code run each time a pattern is matched. #define YY_USER_ACTION loc.columns(yyleng); %} %s BETWEEN_MODE %% %{ // Shortcut to the location held by the driver sqlb::parser::location& loc = drv.location; // Code run each time yylex is called. loc.step(); %} {WS}+ loc.step(); {NL}+ loc.lines(yyleng); loc.step(); "--" { int c; while((c = yyinput(yyscanner)) != '\n' && c != EOF) ; /* eat up text of comment */ } "/*" { int c; for(;;) { while((c = yyinput(yyscanner)) != '*' && c != EOF) ; /* eat up text of comment */ if(c == '*') { while((c = yyinput(yyscanner)) == '*') ; if(c == '/') break; /* found the end */ } if(c == EOF) throw sqlb::parser::parser::syntax_error(loc, "EOF in comment"); } } /* For lack of a better idea, we need this hack to avoid reduce/reduce conflicts in the rules for parsing BETWEEN expressions. * What we do here is distinguish two types of AND operators: the regular one and the special case when the AND follows a BETWEEN keyword. */ "AND" { BEGIN INITIAL; return TOKEN(AND_BETWEEN); } "AND" return TOKEN(AND); "BETWEEN" { BEGIN BETWEEN_MODE; return TOKEN(BETWEEN); } "ABORT" return TOKEN(ABORT); "ACTION" return TOKEN(ACTION); "ALWAYS" return TOKEN(ALWAYS); "AS" return TOKEN(AS); "ASC" return TOKEN(ASC); "AUTOINCREMENT" return TOKEN(AUTOINCREMENT); "CASCADE" return TOKEN(CASCADE); "CASE" return TOKEN(CASE); "CAST" return TOKEN(CAST); "CHECK" return TOKEN(CHECK); "COLLATE" return TOKEN(COLLATE); "CONFLICT" return TOKEN(CONFLICT); "CONSTRAINT" return TOKEN(CONSTRAINT); "CREATE" return TOKEN(CREATE); "CURRENT_DATE" return TOKEN(CURRENT_DATE); "CURRENT_TIME" return TOKEN(CURRENT_TIME); "CURRENT_TIMESTAMP" return TOKEN(CURRENT_TIMESTAMP); "DEFAULT" return TOKEN(DEFAULT); "DEFERRABLE" return TOKEN(DEFERRABLE); "DEFERRED" return TOKEN(DEFERRED); "DELETE" return TOKEN(DELETE); "DESC" return TOKEN(DESC); "DISTINCT" return TOKEN(DISTINCT); "ELSE" return TOKEN(ELSE); "END" return TOKEN(END); "ESCAPE" return TOKEN(ESCAPE); "EXISTS" return TOKEN(EXISTS); "FAIL" return TOKEN(FAIL); "FALSE" return TOKEN(FALSE); "FILTER" return TOKEN(FILTER); "FOLLOWING" return TOKEN(FOLLOWING); "FOREIGN" return TOKEN(FOREIGN); "FROM" return TOKEN(FROM); "GENERATED" return TOKEN(GENERATED); "GLOB" return TOKEN(GLOB); "IF" return TOKEN(IF); "IGNORE" return TOKEN(IGNORE); "IMMEDIATE" return TOKEN(IMMEDIATE); "IN" return TOKEN(IN); "INDEX" return TOKEN(INDEX); "INITIALLY" return TOKEN(INITIALLY); "INSERT" return TOKEN(INSERT); "IS" return TOKEN(IS); "ISNULL" return TOKEN(ISNULL); "KEY" return TOKEN(KEY); "LIKE" return TOKEN(LIKE); "MATCH" return TOKEN(MATCH); "NO" return TOKEN(NO); "NOT" return TOKEN(NOT); "NOTNULL" return TOKEN(NOTNULL); "NULL" return TOKEN(NULL); "ON" return TOKEN(ON); "OR" return TOKEN(OR); "OVER" return TOKEN(OVER); "PARTITION" return TOKEN(PARTITION); "PRECEDING" return TOKEN(PRECEDING); "PRIMARY" return TOKEN(PRIMARY); "RAISE" return TOKEN(RAISE); "RANGE" return TOKEN(RANGE); "REFERENCES" return TOKEN(REFERENCES); "REGEXP" return TOKEN(REGEXP); "REPLACE" return TOKEN(REPLACE); "RESTRICT" return TOKEN(RESTRICT); "RETURNING" return TOKEN(RETURNING); "ROLLBACK" return TOKEN(ROLLBACK); "ROWID" return TOKEN(ROWID); "ROWS" return TOKEN(ROWS); "SELECT" return TOKEN(SELECT); "SET" return TOKEN(SET); "STORED" return TOKEN(STORED); "STRICT" return TOKEN(STRICT); "TABLE" return TOKEN(TABLE); "TEMP" return TOKEN(TEMP); "TEMPORARY" return TOKEN(TEMPORARY); "THEN" return TOKEN(THEN); "TRUE" return TOKEN(TRUE); "UNBOUNDED" return TOKEN(UNBOUNDED); "UNIQUE" return TOKEN(UNIQUE); "UPDATE" return TOKEN(UPDATE); "USING" return TOKEN(USING); "VIRTUAL" return TOKEN(VIRTUAL); "WHEN" return TOKEN(WHEN); "WHERE" return TOKEN(WHERE); "WITHOUT" return TOKEN(WITHOUT); {ID} return sqlb::parser::parser::make_IDENTIFIER(yytext, loc); {GRAVEQUOTEDID} return sqlb::parser::parser::make_IDENTIFIER(unquote_string(yytext, '`'), loc); {SQUAREBRACKETID} return sqlb::parser::parser::make_IDENTIFIER(unquote_string(yytext, '['), loc); {QUOTEDLITERAL} return sqlb::parser::parser::make_QUOTEDLITERAL(unquote_string(yytext, '"'), loc); {STRINGLITERAL} return sqlb::parser::parser::make_STRINGLITERAL(yytext, loc); {NUMERIC} return sqlb::parser::parser::make_NUMERIC(yytext, loc); {BLOBLITERAL} return sqlb::parser::parser::make_BLOBLITERAL(yytext, loc); {BINDPARAMETER_NUM} return sqlb::parser::parser::make_BINDPARAMETER(yytext, loc); {BINDPARAMETER_STR} return sqlb::parser::parser::make_BINDPARAMETER(yytext, loc); "(" return sqlb::parser::parser::make_LPAREN(loc); ")" return sqlb::parser::parser::make_RPAREN(loc); "." return sqlb::parser::parser::make_DOT(loc); "," return sqlb::parser::parser::make_COMMA(loc); ";" return sqlb::parser::parser::make_SEMI(loc); "+" return sqlb::parser::parser::make_PLUS(loc); "-" return sqlb::parser::parser::make_MINUS(loc); "*" return sqlb::parser::parser::make_STAR(loc); "/" return sqlb::parser::parser::make_SLASH(loc); "~" return sqlb::parser::parser::make_TILDE(loc); "&" return sqlb::parser::parser::make_AMPERSAND(loc); "%" return sqlb::parser::parser::make_PERCENT(loc); "|" return sqlb::parser::parser::make_BITOR(loc); "||" return sqlb::parser::parser::make_OROP(loc); "=" return sqlb::parser::parser::make_EQUAL(loc); "==" return sqlb::parser::parser::make_EQUAL2(loc); ">" return sqlb::parser::parser::make_GREATER(loc); ">=" return sqlb::parser::parser::make_GREATEREQUAL(loc); "<" return sqlb::parser::parser::make_LOWER(loc); "<=" return sqlb::parser::parser::make_LOWEREQUAL(loc); "!=" return sqlb::parser::parser::make_UNEQUAL(loc); "<>" return sqlb::parser::parser::make_UNEQUAL2(loc); "<<" return sqlb::parser::parser::make_BITWISELEFT(loc); ">>" return sqlb::parser::parser::make_BITWISERIGHT(loc); . throw sqlb::parser::parser::syntax_error(loc, "Invalid character: " + std::string(yytext)); <> return sqlb::parser::parser::make_EOF(loc); %% namespace sqlb { namespace parser { void ParserDriver::begin_scan() { yylex_init(&scanner); location.initialize(); yyset_debug(trace_scanner, scanner); buffer = yy_scan_string(source.c_str(), scanner); } void ParserDriver::end_scan() { yy_delete_buffer(buffer, scanner); yylex_destroy(scanner); } } } sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/sqlite3_location.h000066400000000000000000000175151463772530400262140ustar00rootroot00000000000000// A Bison parser, made by GNU Bison 3.8.2. // Locations for Bison parsers in C++ // Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc. // 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 . // As a special exception, you may create a larger work that contains // part or all of the Bison parser skeleton and distribute that work // under terms of your choice, so long as that work isn't itself a // parser generator using the skeleton or a modified version thereof // as a parser skeleton. Alternatively, if you modify or redistribute // the parser skeleton itself, you may (at your option) remove this // special exception, which will cause the skeleton and the resulting // Bison output files to be licensed under the GNU General Public // License without this special exception. // This special exception was added by the Free Software Foundation in // version 2.2 of Bison. /** ** \file sqlite3_location.h ** Define the sqlb::parser ::location class. */ #ifndef YY_YY_SQLITE3_LOCATION_H_INCLUDED # define YY_YY_SQLITE3_LOCATION_H_INCLUDED # include # include # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif #line 10 "sqlite3_parser.yy" namespace sqlb { namespace parser { #line 59 "sqlite3_location.h" /// A point in a source file. class position { public: /// Type for file name. typedef const std::string filename_type; /// Type for line and column numbers. typedef int counter_type; /// Construct a position. explicit position (filename_type* f = YY_NULLPTR, counter_type l = 1, counter_type c = 1) : filename (f) , line (l) , column (c) {} /// Initialization. void initialize (filename_type* fn = YY_NULLPTR, counter_type l = 1, counter_type c = 1) { filename = fn; line = l; column = c; } /** \name Line and Column related manipulators ** \{ */ /// (line related) Advance to the COUNT next lines. void lines (counter_type count = 1) { if (count) { column = 1; line = add_ (line, count, 1); } } /// (column related) Advance to the COUNT next columns. void columns (counter_type count = 1) { column = add_ (column, count, 1); } /** \} */ /// File name to which this position refers. filename_type* filename; /// Current line number. counter_type line; /// Current column number. counter_type column; private: /// Compute max (min, lhs+rhs). static counter_type add_ (counter_type lhs, counter_type rhs, counter_type min) { return lhs + rhs < min ? min : lhs + rhs; } }; /// Add \a width columns, in place. inline position& operator+= (position& res, position::counter_type width) { res.columns (width); return res; } /// Add \a width columns. inline position operator+ (position res, position::counter_type width) { return res += width; } /// Subtract \a width columns, in place. inline position& operator-= (position& res, position::counter_type width) { return res += -width; } /// Subtract \a width columns. inline position operator- (position res, position::counter_type width) { return res -= width; } /** \brief Intercept output stream redirection. ** \param ostr the destination output stream ** \param pos a reference to the position to redirect */ template std::basic_ostream& operator<< (std::basic_ostream& ostr, const position& pos) { if (pos.filename) ostr << *pos.filename << ':'; return ostr << pos.line << '.' << pos.column; } /// Two points in a source file. class location { public: /// Type for file name. typedef position::filename_type filename_type; /// Type for line and column numbers. typedef position::counter_type counter_type; /// Construct a location from \a b to \a e. location (const position& b, const position& e) : begin (b) , end (e) {} /// Construct a 0-width location in \a p. explicit location (const position& p = position ()) : begin (p) , end (p) {} /// Construct a 0-width location in \a f, \a l, \a c. explicit location (filename_type* f, counter_type l = 1, counter_type c = 1) : begin (f, l, c) , end (f, l, c) {} /// Initialization. void initialize (filename_type* f = YY_NULLPTR, counter_type l = 1, counter_type c = 1) { begin.initialize (f, l, c); end = begin; } /** \name Line and Column related manipulators ** \{ */ public: /// Reset initial location to final location. void step () { begin = end; } /// Extend the current location to the COUNT next columns. void columns (counter_type count = 1) { end += count; } /// Extend the current location to the COUNT next lines. void lines (counter_type count = 1) { end.lines (count); } /** \} */ public: /// Beginning of the located region. position begin; /// End of the located region. position end; }; /// Join two locations, in place. inline location& operator+= (location& res, const location& end) { res.end = end.end; return res; } /// Join two locations. inline location operator+ (location res, const location& end) { return res += end; } /// Add \a width columns to the end position, in place. inline location& operator+= (location& res, location::counter_type width) { res.columns (width); return res; } /// Add \a width columns to the end position. inline location operator+ (location res, location::counter_type width) { return res += width; } /// Subtract \a width columns to the end position, in place. inline location& operator-= (location& res, location::counter_type width) { return res += -width; } /// Subtract \a width columns to the end position. inline location operator- (location res, location::counter_type width) { return res -= width; } /** \brief Intercept output stream redirection. ** \param ostr the destination output stream ** \param loc a reference to the location to redirect ** ** Avoid duplicate information. */ template std::basic_ostream& operator<< (std::basic_ostream& ostr, const location& loc) { location::counter_type end_col = 0 < loc.end.column ? loc.end.column - 1 : 0; ostr << loc.begin; if (loc.end.filename && (!loc.begin.filename || *loc.begin.filename != *loc.end.filename)) ostr << '-' << loc.end.filename << ':' << loc.end.line << '.' << end_col; else if (loc.begin.line < loc.end.line) ostr << '-' << loc.end.line << '.' << end_col; else if (loc.begin.column < end_col) ostr << '-' << end_col; return ostr; } #line 10 "sqlite3_parser.yy" } } // sqlb::parser #line 305 "sqlite3_location.h" #endif // !YY_YY_SQLITE3_LOCATION_H_INCLUDED sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/sqlite3_parser.cpp000066400000000000000000007314171463772530400262370ustar00rootroot00000000000000// A Bison parser, made by GNU Bison 3.8.2. // Skeleton implementation for Bison LALR(1) parsers in C++ // Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc. // 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 . // As a special exception, you may create a larger work that contains // part or all of the Bison parser skeleton and distribute that work // under terms of your choice, so long as that work isn't itself a // parser generator using the skeleton or a modified version thereof // as a parser skeleton. Alternatively, if you modify or redistribute // the parser skeleton itself, you may (at your option) remove this // special exception, which will cause the skeleton and the resulting // Bison output files to be licensed under the GNU General Public // License without this special exception. // This special exception was added by the Free Software Foundation in // version 2.2 of Bison. // DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, // especially those whose name start with YY_ or yy_. They are // private implementation details that can be changed or removed. #include "sqlite3_parser.hpp" // Unqualified %code blocks. #line 39 "sqlite3_parser.yy" #include "ParserDriver.h" static std::string unquote_text(std::string str, char quote_char) { if(quote_char != '[') { if(str.front() != quote_char || str.back() != quote_char) return str; str = str.substr(1, str.size()-2); std::string quote(2, quote_char); size_t pos = 0; while((pos = str.find(quote, pos)) != std::string::npos) { str.erase(pos, 1); pos += 1; // Don't remove the other quote char too } return str; } else { if(str.front() != '[' || str.back() != ']') return str; return str.substr(1, str.size()-2); } } #line 76 "sqlite3_parser.cpp" #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include // FIXME: INFRINGES ON USER NAME SPACE. # define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ # define YY_(msgid) msgid # endif #endif // Whether we are compiled with exception support. #ifndef YY_EXCEPTIONS # if defined __GNUC__ && !defined __EXCEPTIONS # define YY_EXCEPTIONS 0 # else # define YY_EXCEPTIONS 1 # endif #endif #define YYRHSLOC(Rhs, K) ((Rhs)[K].location) /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ # ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (N) \ { \ (Current).begin = YYRHSLOC (Rhs, 1).begin; \ (Current).end = YYRHSLOC (Rhs, N).end; \ } \ else \ { \ (Current).begin = (Current).end = YYRHSLOC (Rhs, 0).end; \ } \ while (false) # endif // Enable debugging if requested. #if YYDEBUG // A pseudo ostream that takes yydebug_ into account. # define YYCDEBUG if (yydebug_) (*yycdebug_) # define YY_SYMBOL_PRINT(Title, Symbol) \ do { \ if (yydebug_) \ { \ *yycdebug_ << Title << ' '; \ yy_print_ (*yycdebug_, Symbol); \ *yycdebug_ << '\n'; \ } \ } while (false) # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug_) \ yy_reduce_print_ (Rule); \ } while (false) # define YY_STACK_PRINT() \ do { \ if (yydebug_) \ yy_stack_print_ (); \ } while (false) #else // !YYDEBUG # define YYCDEBUG if (false) std::cerr # define YY_SYMBOL_PRINT(Title, Symbol) YY_USE (Symbol) # define YY_REDUCE_PRINT(Rule) static_cast (0) # define YY_STACK_PRINT() static_cast (0) #endif // !YYDEBUG #define yyerrok (yyerrstatus_ = 0) #define yyclearin (yyla.clear ()) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYRECOVERING() (!!yyerrstatus_) #line 10 "sqlite3_parser.yy" namespace sqlb { namespace parser { #line 169 "sqlite3_parser.cpp" /// Build a parser object. parser::parser (yyscan_t yyscanner_yyarg, ParserDriver& drv_yyarg) #if YYDEBUG : yydebug_ (false), yycdebug_ (&std::cerr), #else : #endif yyscanner (yyscanner_yyarg), drv (drv_yyarg) {} parser::~parser () {} parser::syntax_error::~syntax_error () YY_NOEXCEPT YY_NOTHROW {} /*---------. | symbol. | `---------*/ // by_state. parser::by_state::by_state () YY_NOEXCEPT : state (empty_state) {} parser::by_state::by_state (const by_state& that) YY_NOEXCEPT : state (that.state) {} void parser::by_state::clear () YY_NOEXCEPT { state = empty_state; } void parser::by_state::move (by_state& that) { state = that.state; that.clear (); } parser::by_state::by_state (state_type s) YY_NOEXCEPT : state (s) {} parser::symbol_kind_type parser::by_state::kind () const YY_NOEXCEPT { if (state == empty_state) return symbol_kind::S_YYEMPTY; else return YY_CAST (symbol_kind_type, yystos_[+state]); } parser::stack_symbol_type::stack_symbol_type () {} parser::stack_symbol_type::stack_symbol_type (YY_RVREF (stack_symbol_type) that) : super_type (YY_MOVE (that.state), YY_MOVE (that.location)) { switch (that.kind ()) { case symbol_kind::S_columndef_list: // columndef_list value.YY_MOVE_OR_COPY< ColumnList > (YY_MOVE (that.value)); break; case symbol_kind::S_columnconstraint_list: // columnconstraint_list case symbol_kind::S_tableconstraint: // tableconstraint case symbol_kind::S_tableconstraint_list: // tableconstraint_list case symbol_kind::S_optional_tableconstraint_list: // optional_tableconstraint_list value.YY_MOVE_OR_COPY< TableConstraints > (YY_MOVE (that.value)); break; case symbol_kind::S_optional_if_not_exists: // optional_if_not_exists case symbol_kind::S_optional_unique: // optional_unique case symbol_kind::S_optional_temporary: // optional_temporary case symbol_kind::S_optional_always_generated: // optional_always_generated value.YY_MOVE_OR_COPY< bool > (YY_MOVE (that.value)); break; case symbol_kind::S_createindex_stmt: // createindex_stmt value.YY_MOVE_OR_COPY< sqlb::IndexPtr > (YY_MOVE (that.value)); break; case symbol_kind::S_indexed_column: // indexed_column value.YY_MOVE_OR_COPY< sqlb::IndexedColumn > (YY_MOVE (that.value)); break; case symbol_kind::S_indexed_column_list: // indexed_column_list value.YY_MOVE_OR_COPY< sqlb::IndexedColumnVector > (YY_MOVE (that.value)); break; case symbol_kind::S_columnid_list: // columnid_list case symbol_kind::S_optional_columnid_with_paren_list: // optional_columnid_with_paren_list value.YY_MOVE_OR_COPY< sqlb::StringVector > (YY_MOVE (that.value)); break; case symbol_kind::S_createvirtualtable_stmt: // createvirtualtable_stmt case symbol_kind::S_createtable_stmt: // createtable_stmt value.YY_MOVE_OR_COPY< sqlb::TablePtr > (YY_MOVE (that.value)); break; case symbol_kind::S_tableoption: // tableoption case symbol_kind::S_tableoptions_list: // tableoptions_list case symbol_kind::S_optional_tableoptions_list: // optional_tableoptions_list value.YY_MOVE_OR_COPY< std::bitset > (YY_MOVE (that.value)); break; case symbol_kind::S_columnconstraint: // columnconstraint value.YY_MOVE_OR_COPY< std::pair, std::shared_ptr> > (YY_MOVE (that.value)); break; case symbol_kind::S_columndef: // columndef value.YY_MOVE_OR_COPY< std::shared_ptr > (YY_MOVE (that.value)); break; case symbol_kind::S_ABORT: // "ABORT" case symbol_kind::S_ACTION: // "ACTION" case symbol_kind::S_ALWAYS: // "ALWAYS" case symbol_kind::S_AND: // "AND" case symbol_kind::S_AND_BETWEEN: // "AND BETWEEN" case symbol_kind::S_AS: // "AS" case symbol_kind::S_ASC: // "ASC" case symbol_kind::S_AUTOINCREMENT: // "AUTOINCREMENT" case symbol_kind::S_BETWEEN: // "BETWEEN" case symbol_kind::S_CASCADE: // "CASCADE" case symbol_kind::S_CASE: // "CASE" case symbol_kind::S_CAST: // "CAST" case symbol_kind::S_CHECK: // "CHECK" case symbol_kind::S_COLLATE: // "COLLATE" case symbol_kind::S_CONFLICT: // "CONFLICT" case symbol_kind::S_CONSTRAINT: // "CONSTRAINT" case symbol_kind::S_CREATE: // "CREATE" case symbol_kind::S_CURRENT_DATE: // "CURRENT_DATE" case symbol_kind::S_CURRENT_TIME: // "CURRENT_TIME" case symbol_kind::S_CURRENT_TIMESTAMP: // "CURRENT_TIMESTAMP" case symbol_kind::S_DEFAULT: // "DEFAULT" case symbol_kind::S_DEFERRABLE: // "DEFERRABLE" case symbol_kind::S_DEFERRED: // "DEFERRED" case symbol_kind::S_DELETE: // "DELETE" case symbol_kind::S_DESC: // "DESC" case symbol_kind::S_DISTINCT: // "DISTINCT" case symbol_kind::S_ELSE: // "ELSE" case symbol_kind::S_END: // "END" case symbol_kind::S_ESCAPE: // "ESCAPE" case symbol_kind::S_EXISTS: // "EXISTS" case symbol_kind::S_FAIL: // "FAIL" case symbol_kind::S_FALSE: // "FALSE" case symbol_kind::S_FILTER: // "FILTER" case symbol_kind::S_FOLLOWING: // "FOLLOWING" case symbol_kind::S_FOREIGN: // "FOREIGN" case symbol_kind::S_FROM: // "FROM" case symbol_kind::S_GENERATED: // "GENERATED" case symbol_kind::S_GLOB: // "GLOB" case symbol_kind::S_IF: // "IF" case symbol_kind::S_IGNORE: // "IGNORE" case symbol_kind::S_IMMEDIATE: // "IMMEDIATE" case symbol_kind::S_IN: // "IN" case symbol_kind::S_INDEX: // "INDEX" case symbol_kind::S_INITIALLY: // "INITIALLY" case symbol_kind::S_INSERT: // "INSERT" case symbol_kind::S_IS: // "IS" case symbol_kind::S_ISNULL: // "ISNULL" case symbol_kind::S_KEY: // "KEY" case symbol_kind::S_LIKE: // "LIKE" case symbol_kind::S_MATCH: // "MATCH" case symbol_kind::S_NO: // "NO" case symbol_kind::S_NOT: // "NOT" case symbol_kind::S_NOTNULL: // "NOTNULL" case symbol_kind::S_NULL: // "NULL" case symbol_kind::S_ON: // "ON" case symbol_kind::S_OR: // "OR" case symbol_kind::S_OVER: // "OVER" case symbol_kind::S_PARTITION: // "PARTITION" case symbol_kind::S_PRECEDING: // "PRECEDING" case symbol_kind::S_PRIMARY: // "PRIMARY" case symbol_kind::S_RAISE: // "RAISE" case symbol_kind::S_RANGE: // "RANGE" case symbol_kind::S_REFERENCES: // "REFERENCES" case symbol_kind::S_REGEXP: // "REGEXP" case symbol_kind::S_REPLACE: // "REPLACE" case symbol_kind::S_RESTRICT: // "RESTRICT" case symbol_kind::S_RETURNING: // "RETURNING" case symbol_kind::S_ROLLBACK: // "ROLLBACK" case symbol_kind::S_ROWID: // "ROWID" case symbol_kind::S_ROWS: // "ROWS" case symbol_kind::S_SELECT: // "SELECT" case symbol_kind::S_SET: // "SET" case symbol_kind::S_STORED: // "STORED" case symbol_kind::S_STRICT: // "STRICT" case symbol_kind::S_TABLE: // "TABLE" case symbol_kind::S_TEMP: // "TEMP" case symbol_kind::S_TEMPORARY: // "TEMPORARY" case symbol_kind::S_THEN: // "THEN" case symbol_kind::S_TRUE: // "TRUE" case symbol_kind::S_UNBOUNDED: // "UNBOUNDED" case symbol_kind::S_UNIQUE: // "UNIQUE" case symbol_kind::S_UPDATE: // "UPDATE" case symbol_kind::S_USING: // "USING" case symbol_kind::S_VIRTUAL: // "VIRTUAL" case symbol_kind::S_WHEN: // "WHEN" case symbol_kind::S_WHERE: // "WHERE" case symbol_kind::S_WITHOUT: // "WITHOUT" case symbol_kind::S_IDENTIFIER: // "identifier" case symbol_kind::S_NUMERIC: // "numeric" case symbol_kind::S_STRINGLITERAL: // "string literal" case symbol_kind::S_QUOTEDLITERAL: // "quoted literal" case symbol_kind::S_BLOBLITERAL: // "blob literal" case symbol_kind::S_BINDPARAMETER: // "bind parameter" case symbol_kind::S_literalvalue: // literalvalue case symbol_kind::S_id: // id case symbol_kind::S_allowed_keywords_as_identifier: // allowed_keywords_as_identifier case symbol_kind::S_tableid: // tableid case symbol_kind::S_columnid: // columnid case symbol_kind::S_signednumber: // signednumber case symbol_kind::S_signednumber_or_numeric: // signednumber_or_numeric case symbol_kind::S_typename_namelist: // typename_namelist case symbol_kind::S_type_name: // type_name case symbol_kind::S_unary_expr: // unary_expr case symbol_kind::S_binary_expr: // binary_expr case symbol_kind::S_like_expr: // like_expr case symbol_kind::S_exprlist_expr: // exprlist_expr case symbol_kind::S_function_expr: // function_expr case symbol_kind::S_isnull_expr: // isnull_expr case symbol_kind::S_between_expr: // between_expr case symbol_kind::S_in_expr: // in_expr case symbol_kind::S_whenthenlist_expr: // whenthenlist_expr case symbol_kind::S_case_expr: // case_expr case symbol_kind::S_raise_expr: // raise_expr case symbol_kind::S_expr: // expr case symbol_kind::S_select_stmt: // select_stmt case symbol_kind::S_optional_sort_order: // optional_sort_order case symbol_kind::S_optional_where: // optional_where case symbol_kind::S_tableid_with_uninteresting_schema: // tableid_with_uninteresting_schema case symbol_kind::S_optional_exprlist_with_paren: // optional_exprlist_with_paren case symbol_kind::S_optional_conflictclause: // optional_conflictclause case symbol_kind::S_optional_typename: // optional_typename case symbol_kind::S_optional_storage_identifier: // optional_storage_identifier case symbol_kind::S_optional_constraintname: // optional_constraintname case symbol_kind::S_fk_clause_part: // fk_clause_part case symbol_kind::S_fk_clause_part_list: // fk_clause_part_list case symbol_kind::S_optional_fk_clause: // optional_fk_clause value.YY_MOVE_OR_COPY< std::string > (YY_MOVE (that.value)); break; default: break; } #if 201103L <= YY_CPLUSPLUS // that is emptied. that.state = empty_state; #endif } parser::stack_symbol_type::stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) that) : super_type (s, YY_MOVE (that.location)) { switch (that.kind ()) { case symbol_kind::S_columndef_list: // columndef_list value.move< ColumnList > (YY_MOVE (that.value)); break; case symbol_kind::S_columnconstraint_list: // columnconstraint_list case symbol_kind::S_tableconstraint: // tableconstraint case symbol_kind::S_tableconstraint_list: // tableconstraint_list case symbol_kind::S_optional_tableconstraint_list: // optional_tableconstraint_list value.move< TableConstraints > (YY_MOVE (that.value)); break; case symbol_kind::S_optional_if_not_exists: // optional_if_not_exists case symbol_kind::S_optional_unique: // optional_unique case symbol_kind::S_optional_temporary: // optional_temporary case symbol_kind::S_optional_always_generated: // optional_always_generated value.move< bool > (YY_MOVE (that.value)); break; case symbol_kind::S_createindex_stmt: // createindex_stmt value.move< sqlb::IndexPtr > (YY_MOVE (that.value)); break; case symbol_kind::S_indexed_column: // indexed_column value.move< sqlb::IndexedColumn > (YY_MOVE (that.value)); break; case symbol_kind::S_indexed_column_list: // indexed_column_list value.move< sqlb::IndexedColumnVector > (YY_MOVE (that.value)); break; case symbol_kind::S_columnid_list: // columnid_list case symbol_kind::S_optional_columnid_with_paren_list: // optional_columnid_with_paren_list value.move< sqlb::StringVector > (YY_MOVE (that.value)); break; case symbol_kind::S_createvirtualtable_stmt: // createvirtualtable_stmt case symbol_kind::S_createtable_stmt: // createtable_stmt value.move< sqlb::TablePtr > (YY_MOVE (that.value)); break; case symbol_kind::S_tableoption: // tableoption case symbol_kind::S_tableoptions_list: // tableoptions_list case symbol_kind::S_optional_tableoptions_list: // optional_tableoptions_list value.move< std::bitset > (YY_MOVE (that.value)); break; case symbol_kind::S_columnconstraint: // columnconstraint value.move< std::pair, std::shared_ptr> > (YY_MOVE (that.value)); break; case symbol_kind::S_columndef: // columndef value.move< std::shared_ptr > (YY_MOVE (that.value)); break; case symbol_kind::S_ABORT: // "ABORT" case symbol_kind::S_ACTION: // "ACTION" case symbol_kind::S_ALWAYS: // "ALWAYS" case symbol_kind::S_AND: // "AND" case symbol_kind::S_AND_BETWEEN: // "AND BETWEEN" case symbol_kind::S_AS: // "AS" case symbol_kind::S_ASC: // "ASC" case symbol_kind::S_AUTOINCREMENT: // "AUTOINCREMENT" case symbol_kind::S_BETWEEN: // "BETWEEN" case symbol_kind::S_CASCADE: // "CASCADE" case symbol_kind::S_CASE: // "CASE" case symbol_kind::S_CAST: // "CAST" case symbol_kind::S_CHECK: // "CHECK" case symbol_kind::S_COLLATE: // "COLLATE" case symbol_kind::S_CONFLICT: // "CONFLICT" case symbol_kind::S_CONSTRAINT: // "CONSTRAINT" case symbol_kind::S_CREATE: // "CREATE" case symbol_kind::S_CURRENT_DATE: // "CURRENT_DATE" case symbol_kind::S_CURRENT_TIME: // "CURRENT_TIME" case symbol_kind::S_CURRENT_TIMESTAMP: // "CURRENT_TIMESTAMP" case symbol_kind::S_DEFAULT: // "DEFAULT" case symbol_kind::S_DEFERRABLE: // "DEFERRABLE" case symbol_kind::S_DEFERRED: // "DEFERRED" case symbol_kind::S_DELETE: // "DELETE" case symbol_kind::S_DESC: // "DESC" case symbol_kind::S_DISTINCT: // "DISTINCT" case symbol_kind::S_ELSE: // "ELSE" case symbol_kind::S_END: // "END" case symbol_kind::S_ESCAPE: // "ESCAPE" case symbol_kind::S_EXISTS: // "EXISTS" case symbol_kind::S_FAIL: // "FAIL" case symbol_kind::S_FALSE: // "FALSE" case symbol_kind::S_FILTER: // "FILTER" case symbol_kind::S_FOLLOWING: // "FOLLOWING" case symbol_kind::S_FOREIGN: // "FOREIGN" case symbol_kind::S_FROM: // "FROM" case symbol_kind::S_GENERATED: // "GENERATED" case symbol_kind::S_GLOB: // "GLOB" case symbol_kind::S_IF: // "IF" case symbol_kind::S_IGNORE: // "IGNORE" case symbol_kind::S_IMMEDIATE: // "IMMEDIATE" case symbol_kind::S_IN: // "IN" case symbol_kind::S_INDEX: // "INDEX" case symbol_kind::S_INITIALLY: // "INITIALLY" case symbol_kind::S_INSERT: // "INSERT" case symbol_kind::S_IS: // "IS" case symbol_kind::S_ISNULL: // "ISNULL" case symbol_kind::S_KEY: // "KEY" case symbol_kind::S_LIKE: // "LIKE" case symbol_kind::S_MATCH: // "MATCH" case symbol_kind::S_NO: // "NO" case symbol_kind::S_NOT: // "NOT" case symbol_kind::S_NOTNULL: // "NOTNULL" case symbol_kind::S_NULL: // "NULL" case symbol_kind::S_ON: // "ON" case symbol_kind::S_OR: // "OR" case symbol_kind::S_OVER: // "OVER" case symbol_kind::S_PARTITION: // "PARTITION" case symbol_kind::S_PRECEDING: // "PRECEDING" case symbol_kind::S_PRIMARY: // "PRIMARY" case symbol_kind::S_RAISE: // "RAISE" case symbol_kind::S_RANGE: // "RANGE" case symbol_kind::S_REFERENCES: // "REFERENCES" case symbol_kind::S_REGEXP: // "REGEXP" case symbol_kind::S_REPLACE: // "REPLACE" case symbol_kind::S_RESTRICT: // "RESTRICT" case symbol_kind::S_RETURNING: // "RETURNING" case symbol_kind::S_ROLLBACK: // "ROLLBACK" case symbol_kind::S_ROWID: // "ROWID" case symbol_kind::S_ROWS: // "ROWS" case symbol_kind::S_SELECT: // "SELECT" case symbol_kind::S_SET: // "SET" case symbol_kind::S_STORED: // "STORED" case symbol_kind::S_STRICT: // "STRICT" case symbol_kind::S_TABLE: // "TABLE" case symbol_kind::S_TEMP: // "TEMP" case symbol_kind::S_TEMPORARY: // "TEMPORARY" case symbol_kind::S_THEN: // "THEN" case symbol_kind::S_TRUE: // "TRUE" case symbol_kind::S_UNBOUNDED: // "UNBOUNDED" case symbol_kind::S_UNIQUE: // "UNIQUE" case symbol_kind::S_UPDATE: // "UPDATE" case symbol_kind::S_USING: // "USING" case symbol_kind::S_VIRTUAL: // "VIRTUAL" case symbol_kind::S_WHEN: // "WHEN" case symbol_kind::S_WHERE: // "WHERE" case symbol_kind::S_WITHOUT: // "WITHOUT" case symbol_kind::S_IDENTIFIER: // "identifier" case symbol_kind::S_NUMERIC: // "numeric" case symbol_kind::S_STRINGLITERAL: // "string literal" case symbol_kind::S_QUOTEDLITERAL: // "quoted literal" case symbol_kind::S_BLOBLITERAL: // "blob literal" case symbol_kind::S_BINDPARAMETER: // "bind parameter" case symbol_kind::S_literalvalue: // literalvalue case symbol_kind::S_id: // id case symbol_kind::S_allowed_keywords_as_identifier: // allowed_keywords_as_identifier case symbol_kind::S_tableid: // tableid case symbol_kind::S_columnid: // columnid case symbol_kind::S_signednumber: // signednumber case symbol_kind::S_signednumber_or_numeric: // signednumber_or_numeric case symbol_kind::S_typename_namelist: // typename_namelist case symbol_kind::S_type_name: // type_name case symbol_kind::S_unary_expr: // unary_expr case symbol_kind::S_binary_expr: // binary_expr case symbol_kind::S_like_expr: // like_expr case symbol_kind::S_exprlist_expr: // exprlist_expr case symbol_kind::S_function_expr: // function_expr case symbol_kind::S_isnull_expr: // isnull_expr case symbol_kind::S_between_expr: // between_expr case symbol_kind::S_in_expr: // in_expr case symbol_kind::S_whenthenlist_expr: // whenthenlist_expr case symbol_kind::S_case_expr: // case_expr case symbol_kind::S_raise_expr: // raise_expr case symbol_kind::S_expr: // expr case symbol_kind::S_select_stmt: // select_stmt case symbol_kind::S_optional_sort_order: // optional_sort_order case symbol_kind::S_optional_where: // optional_where case symbol_kind::S_tableid_with_uninteresting_schema: // tableid_with_uninteresting_schema case symbol_kind::S_optional_exprlist_with_paren: // optional_exprlist_with_paren case symbol_kind::S_optional_conflictclause: // optional_conflictclause case symbol_kind::S_optional_typename: // optional_typename case symbol_kind::S_optional_storage_identifier: // optional_storage_identifier case symbol_kind::S_optional_constraintname: // optional_constraintname case symbol_kind::S_fk_clause_part: // fk_clause_part case symbol_kind::S_fk_clause_part_list: // fk_clause_part_list case symbol_kind::S_optional_fk_clause: // optional_fk_clause value.move< std::string > (YY_MOVE (that.value)); break; default: break; } // that is emptied. that.kind_ = symbol_kind::S_YYEMPTY; } #if YY_CPLUSPLUS < 201103L parser::stack_symbol_type& parser::stack_symbol_type::operator= (const stack_symbol_type& that) { state = that.state; switch (that.kind ()) { case symbol_kind::S_columndef_list: // columndef_list value.copy< ColumnList > (that.value); break; case symbol_kind::S_columnconstraint_list: // columnconstraint_list case symbol_kind::S_tableconstraint: // tableconstraint case symbol_kind::S_tableconstraint_list: // tableconstraint_list case symbol_kind::S_optional_tableconstraint_list: // optional_tableconstraint_list value.copy< TableConstraints > (that.value); break; case symbol_kind::S_optional_if_not_exists: // optional_if_not_exists case symbol_kind::S_optional_unique: // optional_unique case symbol_kind::S_optional_temporary: // optional_temporary case symbol_kind::S_optional_always_generated: // optional_always_generated value.copy< bool > (that.value); break; case symbol_kind::S_createindex_stmt: // createindex_stmt value.copy< sqlb::IndexPtr > (that.value); break; case symbol_kind::S_indexed_column: // indexed_column value.copy< sqlb::IndexedColumn > (that.value); break; case symbol_kind::S_indexed_column_list: // indexed_column_list value.copy< sqlb::IndexedColumnVector > (that.value); break; case symbol_kind::S_columnid_list: // columnid_list case symbol_kind::S_optional_columnid_with_paren_list: // optional_columnid_with_paren_list value.copy< sqlb::StringVector > (that.value); break; case symbol_kind::S_createvirtualtable_stmt: // createvirtualtable_stmt case symbol_kind::S_createtable_stmt: // createtable_stmt value.copy< sqlb::TablePtr > (that.value); break; case symbol_kind::S_tableoption: // tableoption case symbol_kind::S_tableoptions_list: // tableoptions_list case symbol_kind::S_optional_tableoptions_list: // optional_tableoptions_list value.copy< std::bitset > (that.value); break; case symbol_kind::S_columnconstraint: // columnconstraint value.copy< std::pair, std::shared_ptr> > (that.value); break; case symbol_kind::S_columndef: // columndef value.copy< std::shared_ptr > (that.value); break; case symbol_kind::S_ABORT: // "ABORT" case symbol_kind::S_ACTION: // "ACTION" case symbol_kind::S_ALWAYS: // "ALWAYS" case symbol_kind::S_AND: // "AND" case symbol_kind::S_AND_BETWEEN: // "AND BETWEEN" case symbol_kind::S_AS: // "AS" case symbol_kind::S_ASC: // "ASC" case symbol_kind::S_AUTOINCREMENT: // "AUTOINCREMENT" case symbol_kind::S_BETWEEN: // "BETWEEN" case symbol_kind::S_CASCADE: // "CASCADE" case symbol_kind::S_CASE: // "CASE" case symbol_kind::S_CAST: // "CAST" case symbol_kind::S_CHECK: // "CHECK" case symbol_kind::S_COLLATE: // "COLLATE" case symbol_kind::S_CONFLICT: // "CONFLICT" case symbol_kind::S_CONSTRAINT: // "CONSTRAINT" case symbol_kind::S_CREATE: // "CREATE" case symbol_kind::S_CURRENT_DATE: // "CURRENT_DATE" case symbol_kind::S_CURRENT_TIME: // "CURRENT_TIME" case symbol_kind::S_CURRENT_TIMESTAMP: // "CURRENT_TIMESTAMP" case symbol_kind::S_DEFAULT: // "DEFAULT" case symbol_kind::S_DEFERRABLE: // "DEFERRABLE" case symbol_kind::S_DEFERRED: // "DEFERRED" case symbol_kind::S_DELETE: // "DELETE" case symbol_kind::S_DESC: // "DESC" case symbol_kind::S_DISTINCT: // "DISTINCT" case symbol_kind::S_ELSE: // "ELSE" case symbol_kind::S_END: // "END" case symbol_kind::S_ESCAPE: // "ESCAPE" case symbol_kind::S_EXISTS: // "EXISTS" case symbol_kind::S_FAIL: // "FAIL" case symbol_kind::S_FALSE: // "FALSE" case symbol_kind::S_FILTER: // "FILTER" case symbol_kind::S_FOLLOWING: // "FOLLOWING" case symbol_kind::S_FOREIGN: // "FOREIGN" case symbol_kind::S_FROM: // "FROM" case symbol_kind::S_GENERATED: // "GENERATED" case symbol_kind::S_GLOB: // "GLOB" case symbol_kind::S_IF: // "IF" case symbol_kind::S_IGNORE: // "IGNORE" case symbol_kind::S_IMMEDIATE: // "IMMEDIATE" case symbol_kind::S_IN: // "IN" case symbol_kind::S_INDEX: // "INDEX" case symbol_kind::S_INITIALLY: // "INITIALLY" case symbol_kind::S_INSERT: // "INSERT" case symbol_kind::S_IS: // "IS" case symbol_kind::S_ISNULL: // "ISNULL" case symbol_kind::S_KEY: // "KEY" case symbol_kind::S_LIKE: // "LIKE" case symbol_kind::S_MATCH: // "MATCH" case symbol_kind::S_NO: // "NO" case symbol_kind::S_NOT: // "NOT" case symbol_kind::S_NOTNULL: // "NOTNULL" case symbol_kind::S_NULL: // "NULL" case symbol_kind::S_ON: // "ON" case symbol_kind::S_OR: // "OR" case symbol_kind::S_OVER: // "OVER" case symbol_kind::S_PARTITION: // "PARTITION" case symbol_kind::S_PRECEDING: // "PRECEDING" case symbol_kind::S_PRIMARY: // "PRIMARY" case symbol_kind::S_RAISE: // "RAISE" case symbol_kind::S_RANGE: // "RANGE" case symbol_kind::S_REFERENCES: // "REFERENCES" case symbol_kind::S_REGEXP: // "REGEXP" case symbol_kind::S_REPLACE: // "REPLACE" case symbol_kind::S_RESTRICT: // "RESTRICT" case symbol_kind::S_RETURNING: // "RETURNING" case symbol_kind::S_ROLLBACK: // "ROLLBACK" case symbol_kind::S_ROWID: // "ROWID" case symbol_kind::S_ROWS: // "ROWS" case symbol_kind::S_SELECT: // "SELECT" case symbol_kind::S_SET: // "SET" case symbol_kind::S_STORED: // "STORED" case symbol_kind::S_STRICT: // "STRICT" case symbol_kind::S_TABLE: // "TABLE" case symbol_kind::S_TEMP: // "TEMP" case symbol_kind::S_TEMPORARY: // "TEMPORARY" case symbol_kind::S_THEN: // "THEN" case symbol_kind::S_TRUE: // "TRUE" case symbol_kind::S_UNBOUNDED: // "UNBOUNDED" case symbol_kind::S_UNIQUE: // "UNIQUE" case symbol_kind::S_UPDATE: // "UPDATE" case symbol_kind::S_USING: // "USING" case symbol_kind::S_VIRTUAL: // "VIRTUAL" case symbol_kind::S_WHEN: // "WHEN" case symbol_kind::S_WHERE: // "WHERE" case symbol_kind::S_WITHOUT: // "WITHOUT" case symbol_kind::S_IDENTIFIER: // "identifier" case symbol_kind::S_NUMERIC: // "numeric" case symbol_kind::S_STRINGLITERAL: // "string literal" case symbol_kind::S_QUOTEDLITERAL: // "quoted literal" case symbol_kind::S_BLOBLITERAL: // "blob literal" case symbol_kind::S_BINDPARAMETER: // "bind parameter" case symbol_kind::S_literalvalue: // literalvalue case symbol_kind::S_id: // id case symbol_kind::S_allowed_keywords_as_identifier: // allowed_keywords_as_identifier case symbol_kind::S_tableid: // tableid case symbol_kind::S_columnid: // columnid case symbol_kind::S_signednumber: // signednumber case symbol_kind::S_signednumber_or_numeric: // signednumber_or_numeric case symbol_kind::S_typename_namelist: // typename_namelist case symbol_kind::S_type_name: // type_name case symbol_kind::S_unary_expr: // unary_expr case symbol_kind::S_binary_expr: // binary_expr case symbol_kind::S_like_expr: // like_expr case symbol_kind::S_exprlist_expr: // exprlist_expr case symbol_kind::S_function_expr: // function_expr case symbol_kind::S_isnull_expr: // isnull_expr case symbol_kind::S_between_expr: // between_expr case symbol_kind::S_in_expr: // in_expr case symbol_kind::S_whenthenlist_expr: // whenthenlist_expr case symbol_kind::S_case_expr: // case_expr case symbol_kind::S_raise_expr: // raise_expr case symbol_kind::S_expr: // expr case symbol_kind::S_select_stmt: // select_stmt case symbol_kind::S_optional_sort_order: // optional_sort_order case symbol_kind::S_optional_where: // optional_where case symbol_kind::S_tableid_with_uninteresting_schema: // tableid_with_uninteresting_schema case symbol_kind::S_optional_exprlist_with_paren: // optional_exprlist_with_paren case symbol_kind::S_optional_conflictclause: // optional_conflictclause case symbol_kind::S_optional_typename: // optional_typename case symbol_kind::S_optional_storage_identifier: // optional_storage_identifier case symbol_kind::S_optional_constraintname: // optional_constraintname case symbol_kind::S_fk_clause_part: // fk_clause_part case symbol_kind::S_fk_clause_part_list: // fk_clause_part_list case symbol_kind::S_optional_fk_clause: // optional_fk_clause value.copy< std::string > (that.value); break; default: break; } location = that.location; return *this; } parser::stack_symbol_type& parser::stack_symbol_type::operator= (stack_symbol_type& that) { state = that.state; switch (that.kind ()) { case symbol_kind::S_columndef_list: // columndef_list value.move< ColumnList > (that.value); break; case symbol_kind::S_columnconstraint_list: // columnconstraint_list case symbol_kind::S_tableconstraint: // tableconstraint case symbol_kind::S_tableconstraint_list: // tableconstraint_list case symbol_kind::S_optional_tableconstraint_list: // optional_tableconstraint_list value.move< TableConstraints > (that.value); break; case symbol_kind::S_optional_if_not_exists: // optional_if_not_exists case symbol_kind::S_optional_unique: // optional_unique case symbol_kind::S_optional_temporary: // optional_temporary case symbol_kind::S_optional_always_generated: // optional_always_generated value.move< bool > (that.value); break; case symbol_kind::S_createindex_stmt: // createindex_stmt value.move< sqlb::IndexPtr > (that.value); break; case symbol_kind::S_indexed_column: // indexed_column value.move< sqlb::IndexedColumn > (that.value); break; case symbol_kind::S_indexed_column_list: // indexed_column_list value.move< sqlb::IndexedColumnVector > (that.value); break; case symbol_kind::S_columnid_list: // columnid_list case symbol_kind::S_optional_columnid_with_paren_list: // optional_columnid_with_paren_list value.move< sqlb::StringVector > (that.value); break; case symbol_kind::S_createvirtualtable_stmt: // createvirtualtable_stmt case symbol_kind::S_createtable_stmt: // createtable_stmt value.move< sqlb::TablePtr > (that.value); break; case symbol_kind::S_tableoption: // tableoption case symbol_kind::S_tableoptions_list: // tableoptions_list case symbol_kind::S_optional_tableoptions_list: // optional_tableoptions_list value.move< std::bitset > (that.value); break; case symbol_kind::S_columnconstraint: // columnconstraint value.move< std::pair, std::shared_ptr> > (that.value); break; case symbol_kind::S_columndef: // columndef value.move< std::shared_ptr > (that.value); break; case symbol_kind::S_ABORT: // "ABORT" case symbol_kind::S_ACTION: // "ACTION" case symbol_kind::S_ALWAYS: // "ALWAYS" case symbol_kind::S_AND: // "AND" case symbol_kind::S_AND_BETWEEN: // "AND BETWEEN" case symbol_kind::S_AS: // "AS" case symbol_kind::S_ASC: // "ASC" case symbol_kind::S_AUTOINCREMENT: // "AUTOINCREMENT" case symbol_kind::S_BETWEEN: // "BETWEEN" case symbol_kind::S_CASCADE: // "CASCADE" case symbol_kind::S_CASE: // "CASE" case symbol_kind::S_CAST: // "CAST" case symbol_kind::S_CHECK: // "CHECK" case symbol_kind::S_COLLATE: // "COLLATE" case symbol_kind::S_CONFLICT: // "CONFLICT" case symbol_kind::S_CONSTRAINT: // "CONSTRAINT" case symbol_kind::S_CREATE: // "CREATE" case symbol_kind::S_CURRENT_DATE: // "CURRENT_DATE" case symbol_kind::S_CURRENT_TIME: // "CURRENT_TIME" case symbol_kind::S_CURRENT_TIMESTAMP: // "CURRENT_TIMESTAMP" case symbol_kind::S_DEFAULT: // "DEFAULT" case symbol_kind::S_DEFERRABLE: // "DEFERRABLE" case symbol_kind::S_DEFERRED: // "DEFERRED" case symbol_kind::S_DELETE: // "DELETE" case symbol_kind::S_DESC: // "DESC" case symbol_kind::S_DISTINCT: // "DISTINCT" case symbol_kind::S_ELSE: // "ELSE" case symbol_kind::S_END: // "END" case symbol_kind::S_ESCAPE: // "ESCAPE" case symbol_kind::S_EXISTS: // "EXISTS" case symbol_kind::S_FAIL: // "FAIL" case symbol_kind::S_FALSE: // "FALSE" case symbol_kind::S_FILTER: // "FILTER" case symbol_kind::S_FOLLOWING: // "FOLLOWING" case symbol_kind::S_FOREIGN: // "FOREIGN" case symbol_kind::S_FROM: // "FROM" case symbol_kind::S_GENERATED: // "GENERATED" case symbol_kind::S_GLOB: // "GLOB" case symbol_kind::S_IF: // "IF" case symbol_kind::S_IGNORE: // "IGNORE" case symbol_kind::S_IMMEDIATE: // "IMMEDIATE" case symbol_kind::S_IN: // "IN" case symbol_kind::S_INDEX: // "INDEX" case symbol_kind::S_INITIALLY: // "INITIALLY" case symbol_kind::S_INSERT: // "INSERT" case symbol_kind::S_IS: // "IS" case symbol_kind::S_ISNULL: // "ISNULL" case symbol_kind::S_KEY: // "KEY" case symbol_kind::S_LIKE: // "LIKE" case symbol_kind::S_MATCH: // "MATCH" case symbol_kind::S_NO: // "NO" case symbol_kind::S_NOT: // "NOT" case symbol_kind::S_NOTNULL: // "NOTNULL" case symbol_kind::S_NULL: // "NULL" case symbol_kind::S_ON: // "ON" case symbol_kind::S_OR: // "OR" case symbol_kind::S_OVER: // "OVER" case symbol_kind::S_PARTITION: // "PARTITION" case symbol_kind::S_PRECEDING: // "PRECEDING" case symbol_kind::S_PRIMARY: // "PRIMARY" case symbol_kind::S_RAISE: // "RAISE" case symbol_kind::S_RANGE: // "RANGE" case symbol_kind::S_REFERENCES: // "REFERENCES" case symbol_kind::S_REGEXP: // "REGEXP" case symbol_kind::S_REPLACE: // "REPLACE" case symbol_kind::S_RESTRICT: // "RESTRICT" case symbol_kind::S_RETURNING: // "RETURNING" case symbol_kind::S_ROLLBACK: // "ROLLBACK" case symbol_kind::S_ROWID: // "ROWID" case symbol_kind::S_ROWS: // "ROWS" case symbol_kind::S_SELECT: // "SELECT" case symbol_kind::S_SET: // "SET" case symbol_kind::S_STORED: // "STORED" case symbol_kind::S_STRICT: // "STRICT" case symbol_kind::S_TABLE: // "TABLE" case symbol_kind::S_TEMP: // "TEMP" case symbol_kind::S_TEMPORARY: // "TEMPORARY" case symbol_kind::S_THEN: // "THEN" case symbol_kind::S_TRUE: // "TRUE" case symbol_kind::S_UNBOUNDED: // "UNBOUNDED" case symbol_kind::S_UNIQUE: // "UNIQUE" case symbol_kind::S_UPDATE: // "UPDATE" case symbol_kind::S_USING: // "USING" case symbol_kind::S_VIRTUAL: // "VIRTUAL" case symbol_kind::S_WHEN: // "WHEN" case symbol_kind::S_WHERE: // "WHERE" case symbol_kind::S_WITHOUT: // "WITHOUT" case symbol_kind::S_IDENTIFIER: // "identifier" case symbol_kind::S_NUMERIC: // "numeric" case symbol_kind::S_STRINGLITERAL: // "string literal" case symbol_kind::S_QUOTEDLITERAL: // "quoted literal" case symbol_kind::S_BLOBLITERAL: // "blob literal" case symbol_kind::S_BINDPARAMETER: // "bind parameter" case symbol_kind::S_literalvalue: // literalvalue case symbol_kind::S_id: // id case symbol_kind::S_allowed_keywords_as_identifier: // allowed_keywords_as_identifier case symbol_kind::S_tableid: // tableid case symbol_kind::S_columnid: // columnid case symbol_kind::S_signednumber: // signednumber case symbol_kind::S_signednumber_or_numeric: // signednumber_or_numeric case symbol_kind::S_typename_namelist: // typename_namelist case symbol_kind::S_type_name: // type_name case symbol_kind::S_unary_expr: // unary_expr case symbol_kind::S_binary_expr: // binary_expr case symbol_kind::S_like_expr: // like_expr case symbol_kind::S_exprlist_expr: // exprlist_expr case symbol_kind::S_function_expr: // function_expr case symbol_kind::S_isnull_expr: // isnull_expr case symbol_kind::S_between_expr: // between_expr case symbol_kind::S_in_expr: // in_expr case symbol_kind::S_whenthenlist_expr: // whenthenlist_expr case symbol_kind::S_case_expr: // case_expr case symbol_kind::S_raise_expr: // raise_expr case symbol_kind::S_expr: // expr case symbol_kind::S_select_stmt: // select_stmt case symbol_kind::S_optional_sort_order: // optional_sort_order case symbol_kind::S_optional_where: // optional_where case symbol_kind::S_tableid_with_uninteresting_schema: // tableid_with_uninteresting_schema case symbol_kind::S_optional_exprlist_with_paren: // optional_exprlist_with_paren case symbol_kind::S_optional_conflictclause: // optional_conflictclause case symbol_kind::S_optional_typename: // optional_typename case symbol_kind::S_optional_storage_identifier: // optional_storage_identifier case symbol_kind::S_optional_constraintname: // optional_constraintname case symbol_kind::S_fk_clause_part: // fk_clause_part case symbol_kind::S_fk_clause_part_list: // fk_clause_part_list case symbol_kind::S_optional_fk_clause: // optional_fk_clause value.move< std::string > (that.value); break; default: break; } location = that.location; // that is emptied. that.state = empty_state; return *this; } #endif template void parser::yy_destroy_ (const char* yymsg, basic_symbol& yysym) const { if (yymsg) YY_SYMBOL_PRINT (yymsg, yysym); } #if YYDEBUG template void parser::yy_print_ (std::ostream& yyo, const basic_symbol& yysym) const { std::ostream& yyoutput = yyo; YY_USE (yyoutput); if (yysym.empty ()) yyo << "empty symbol"; else { symbol_kind_type yykind = yysym.kind (); yyo << (yykind < YYNTOKENS ? "token" : "nterm") << ' ' << yysym.name () << " (" << yysym.location << ": "; YY_USE (yykind); yyo << ')'; } } #endif void parser::yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym) { if (m) YY_SYMBOL_PRINT (m, sym); yystack_.push (YY_MOVE (sym)); } void parser::yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym) { #if 201103L <= YY_CPLUSPLUS yypush_ (m, stack_symbol_type (s, std::move (sym))); #else stack_symbol_type ss (s, sym); yypush_ (m, ss); #endif } void parser::yypop_ (int n) YY_NOEXCEPT { yystack_.pop (n); } #if YYDEBUG std::ostream& parser::debug_stream () const { return *yycdebug_; } void parser::set_debug_stream (std::ostream& o) { yycdebug_ = &o; } parser::debug_level_type parser::debug_level () const { return yydebug_; } void parser::set_debug_level (debug_level_type l) { yydebug_ = l; } #endif // YYDEBUG parser::state_type parser::yy_lr_goto_state_ (state_type yystate, int yysym) { int yyr = yypgoto_[yysym - YYNTOKENS] + yystate; if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate) return yytable_[yyr]; else return yydefgoto_[yysym - YYNTOKENS]; } bool parser::yy_pact_value_is_default_ (int yyvalue) YY_NOEXCEPT { return yyvalue == yypact_ninf_; } bool parser::yy_table_value_is_error_ (int yyvalue) YY_NOEXCEPT { return yyvalue == yytable_ninf_; } int parser::operator() () { return parse (); } int parser::parse () { int yyn; /// Length of the RHS of the rule being reduced. int yylen = 0; // Error handling. int yynerrs_ = 0; int yyerrstatus_ = 0; /// The lookahead symbol. symbol_type yyla; /// The locations where the error started and ended. stack_symbol_type yyerror_range[3]; /// The return value of parse (). int yyresult; #if YY_EXCEPTIONS try #endif // YY_EXCEPTIONS { YYCDEBUG << "Starting parse\n"; /* Initialize the stack. The initial state will be set in yynewstate, since the latter expects the semantical and the location values to have been already stored, initialize these stacks with a primary value. */ yystack_.clear (); yypush_ (YY_NULLPTR, 0, YY_MOVE (yyla)); /*-----------------------------------------------. | yynewstate -- push a new symbol on the stack. | `-----------------------------------------------*/ yynewstate: YYCDEBUG << "Entering state " << int (yystack_[0].state) << '\n'; YY_STACK_PRINT (); // Accept? if (yystack_[0].state == yyfinal_) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: // Try to take a decision without lookahead. yyn = yypact_[+yystack_[0].state]; if (yy_pact_value_is_default_ (yyn)) goto yydefault; // Read a lookahead token. if (yyla.empty ()) { YYCDEBUG << "Reading a token\n"; #if YY_EXCEPTIONS try #endif // YY_EXCEPTIONS { symbol_type yylookahead (yylex (yyscanner, drv)); yyla.move (yylookahead); } #if YY_EXCEPTIONS catch (const syntax_error& yyexc) { YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; error (yyexc); goto yyerrlab1; } #endif // YY_EXCEPTIONS } YY_SYMBOL_PRINT ("Next token is", yyla); if (yyla.kind () == symbol_kind::S_YYerror) { // The scanner already issued an error message, process directly // to error recovery. But do not keep the error token as // lookahead, it is too special and may lead us to an endless // loop in error recovery. */ yyla.kind_ = symbol_kind::S_YYUNDEF; goto yyerrlab1; } /* If the proper action on seeing token YYLA.TYPE is to reduce or to detect an error, take that action. */ yyn += yyla.kind (); if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.kind ()) { goto yydefault; } // Reduce or error. yyn = yytable_[yyn]; if (yyn <= 0) { if (yy_table_value_is_error_ (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } // Count tokens shifted since error; after three, turn off error status. if (yyerrstatus_) --yyerrstatus_; // Shift the lookahead token. yypush_ ("Shifting", state_type (yyn), YY_MOVE (yyla)); goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact_[+yystack_[0].state]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: yylen = yyr2_[yyn]; { stack_symbol_type yylhs; yylhs.state = yy_lr_goto_state_ (yystack_[yylen].state, yyr1_[yyn]); /* Variants are always initialized to an empty instance of the correct type. The default '$$ = $1' action is NOT applied when using variants. */ switch (yyr1_[yyn]) { case symbol_kind::S_columndef_list: // columndef_list yylhs.value.emplace< ColumnList > (); break; case symbol_kind::S_columnconstraint_list: // columnconstraint_list case symbol_kind::S_tableconstraint: // tableconstraint case symbol_kind::S_tableconstraint_list: // tableconstraint_list case symbol_kind::S_optional_tableconstraint_list: // optional_tableconstraint_list yylhs.value.emplace< TableConstraints > (); break; case symbol_kind::S_optional_if_not_exists: // optional_if_not_exists case symbol_kind::S_optional_unique: // optional_unique case symbol_kind::S_optional_temporary: // optional_temporary case symbol_kind::S_optional_always_generated: // optional_always_generated yylhs.value.emplace< bool > (); break; case symbol_kind::S_createindex_stmt: // createindex_stmt yylhs.value.emplace< sqlb::IndexPtr > (); break; case symbol_kind::S_indexed_column: // indexed_column yylhs.value.emplace< sqlb::IndexedColumn > (); break; case symbol_kind::S_indexed_column_list: // indexed_column_list yylhs.value.emplace< sqlb::IndexedColumnVector > (); break; case symbol_kind::S_columnid_list: // columnid_list case symbol_kind::S_optional_columnid_with_paren_list: // optional_columnid_with_paren_list yylhs.value.emplace< sqlb::StringVector > (); break; case symbol_kind::S_createvirtualtable_stmt: // createvirtualtable_stmt case symbol_kind::S_createtable_stmt: // createtable_stmt yylhs.value.emplace< sqlb::TablePtr > (); break; case symbol_kind::S_tableoption: // tableoption case symbol_kind::S_tableoptions_list: // tableoptions_list case symbol_kind::S_optional_tableoptions_list: // optional_tableoptions_list yylhs.value.emplace< std::bitset > (); break; case symbol_kind::S_columnconstraint: // columnconstraint yylhs.value.emplace< std::pair, std::shared_ptr> > (); break; case symbol_kind::S_columndef: // columndef yylhs.value.emplace< std::shared_ptr > (); break; case symbol_kind::S_ABORT: // "ABORT" case symbol_kind::S_ACTION: // "ACTION" case symbol_kind::S_ALWAYS: // "ALWAYS" case symbol_kind::S_AND: // "AND" case symbol_kind::S_AND_BETWEEN: // "AND BETWEEN" case symbol_kind::S_AS: // "AS" case symbol_kind::S_ASC: // "ASC" case symbol_kind::S_AUTOINCREMENT: // "AUTOINCREMENT" case symbol_kind::S_BETWEEN: // "BETWEEN" case symbol_kind::S_CASCADE: // "CASCADE" case symbol_kind::S_CASE: // "CASE" case symbol_kind::S_CAST: // "CAST" case symbol_kind::S_CHECK: // "CHECK" case symbol_kind::S_COLLATE: // "COLLATE" case symbol_kind::S_CONFLICT: // "CONFLICT" case symbol_kind::S_CONSTRAINT: // "CONSTRAINT" case symbol_kind::S_CREATE: // "CREATE" case symbol_kind::S_CURRENT_DATE: // "CURRENT_DATE" case symbol_kind::S_CURRENT_TIME: // "CURRENT_TIME" case symbol_kind::S_CURRENT_TIMESTAMP: // "CURRENT_TIMESTAMP" case symbol_kind::S_DEFAULT: // "DEFAULT" case symbol_kind::S_DEFERRABLE: // "DEFERRABLE" case symbol_kind::S_DEFERRED: // "DEFERRED" case symbol_kind::S_DELETE: // "DELETE" case symbol_kind::S_DESC: // "DESC" case symbol_kind::S_DISTINCT: // "DISTINCT" case symbol_kind::S_ELSE: // "ELSE" case symbol_kind::S_END: // "END" case symbol_kind::S_ESCAPE: // "ESCAPE" case symbol_kind::S_EXISTS: // "EXISTS" case symbol_kind::S_FAIL: // "FAIL" case symbol_kind::S_FALSE: // "FALSE" case symbol_kind::S_FILTER: // "FILTER" case symbol_kind::S_FOLLOWING: // "FOLLOWING" case symbol_kind::S_FOREIGN: // "FOREIGN" case symbol_kind::S_FROM: // "FROM" case symbol_kind::S_GENERATED: // "GENERATED" case symbol_kind::S_GLOB: // "GLOB" case symbol_kind::S_IF: // "IF" case symbol_kind::S_IGNORE: // "IGNORE" case symbol_kind::S_IMMEDIATE: // "IMMEDIATE" case symbol_kind::S_IN: // "IN" case symbol_kind::S_INDEX: // "INDEX" case symbol_kind::S_INITIALLY: // "INITIALLY" case symbol_kind::S_INSERT: // "INSERT" case symbol_kind::S_IS: // "IS" case symbol_kind::S_ISNULL: // "ISNULL" case symbol_kind::S_KEY: // "KEY" case symbol_kind::S_LIKE: // "LIKE" case symbol_kind::S_MATCH: // "MATCH" case symbol_kind::S_NO: // "NO" case symbol_kind::S_NOT: // "NOT" case symbol_kind::S_NOTNULL: // "NOTNULL" case symbol_kind::S_NULL: // "NULL" case symbol_kind::S_ON: // "ON" case symbol_kind::S_OR: // "OR" case symbol_kind::S_OVER: // "OVER" case symbol_kind::S_PARTITION: // "PARTITION" case symbol_kind::S_PRECEDING: // "PRECEDING" case symbol_kind::S_PRIMARY: // "PRIMARY" case symbol_kind::S_RAISE: // "RAISE" case symbol_kind::S_RANGE: // "RANGE" case symbol_kind::S_REFERENCES: // "REFERENCES" case symbol_kind::S_REGEXP: // "REGEXP" case symbol_kind::S_REPLACE: // "REPLACE" case symbol_kind::S_RESTRICT: // "RESTRICT" case symbol_kind::S_RETURNING: // "RETURNING" case symbol_kind::S_ROLLBACK: // "ROLLBACK" case symbol_kind::S_ROWID: // "ROWID" case symbol_kind::S_ROWS: // "ROWS" case symbol_kind::S_SELECT: // "SELECT" case symbol_kind::S_SET: // "SET" case symbol_kind::S_STORED: // "STORED" case symbol_kind::S_STRICT: // "STRICT" case symbol_kind::S_TABLE: // "TABLE" case symbol_kind::S_TEMP: // "TEMP" case symbol_kind::S_TEMPORARY: // "TEMPORARY" case symbol_kind::S_THEN: // "THEN" case symbol_kind::S_TRUE: // "TRUE" case symbol_kind::S_UNBOUNDED: // "UNBOUNDED" case symbol_kind::S_UNIQUE: // "UNIQUE" case symbol_kind::S_UPDATE: // "UPDATE" case symbol_kind::S_USING: // "USING" case symbol_kind::S_VIRTUAL: // "VIRTUAL" case symbol_kind::S_WHEN: // "WHEN" case symbol_kind::S_WHERE: // "WHERE" case symbol_kind::S_WITHOUT: // "WITHOUT" case symbol_kind::S_IDENTIFIER: // "identifier" case symbol_kind::S_NUMERIC: // "numeric" case symbol_kind::S_STRINGLITERAL: // "string literal" case symbol_kind::S_QUOTEDLITERAL: // "quoted literal" case symbol_kind::S_BLOBLITERAL: // "blob literal" case symbol_kind::S_BINDPARAMETER: // "bind parameter" case symbol_kind::S_literalvalue: // literalvalue case symbol_kind::S_id: // id case symbol_kind::S_allowed_keywords_as_identifier: // allowed_keywords_as_identifier case symbol_kind::S_tableid: // tableid case symbol_kind::S_columnid: // columnid case symbol_kind::S_signednumber: // signednumber case symbol_kind::S_signednumber_or_numeric: // signednumber_or_numeric case symbol_kind::S_typename_namelist: // typename_namelist case symbol_kind::S_type_name: // type_name case symbol_kind::S_unary_expr: // unary_expr case symbol_kind::S_binary_expr: // binary_expr case symbol_kind::S_like_expr: // like_expr case symbol_kind::S_exprlist_expr: // exprlist_expr case symbol_kind::S_function_expr: // function_expr case symbol_kind::S_isnull_expr: // isnull_expr case symbol_kind::S_between_expr: // between_expr case symbol_kind::S_in_expr: // in_expr case symbol_kind::S_whenthenlist_expr: // whenthenlist_expr case symbol_kind::S_case_expr: // case_expr case symbol_kind::S_raise_expr: // raise_expr case symbol_kind::S_expr: // expr case symbol_kind::S_select_stmt: // select_stmt case symbol_kind::S_optional_sort_order: // optional_sort_order case symbol_kind::S_optional_where: // optional_where case symbol_kind::S_tableid_with_uninteresting_schema: // tableid_with_uninteresting_schema case symbol_kind::S_optional_exprlist_with_paren: // optional_exprlist_with_paren case symbol_kind::S_optional_conflictclause: // optional_conflictclause case symbol_kind::S_optional_typename: // optional_typename case symbol_kind::S_optional_storage_identifier: // optional_storage_identifier case symbol_kind::S_optional_constraintname: // optional_constraintname case symbol_kind::S_fk_clause_part: // fk_clause_part case symbol_kind::S_fk_clause_part_list: // fk_clause_part_list case symbol_kind::S_optional_fk_clause: // optional_fk_clause yylhs.value.emplace< std::string > (); break; default: break; } // Default location. { stack_type::slice range (yystack_, yylen); YYLLOC_DEFAULT (yylhs.location, range, yylen); yyerror_range[1].location = yylhs.location; } // Perform the reduction. YY_REDUCE_PRINT (yyn); #if YY_EXCEPTIONS try #endif // YY_EXCEPTIONS { switch (yyn) { case 4: // statement: createindex_stmt #line 278 "sqlite3_parser.yy" { drv.result = yystack_[0].value.as < sqlb::IndexPtr > (); } #line 1479 "sqlite3_parser.cpp" break; case 5: // statement: createvirtualtable_stmt #line 279 "sqlite3_parser.yy" { drv.result = yystack_[0].value.as < sqlb::TablePtr > (); } #line 1485 "sqlite3_parser.cpp" break; case 6: // statement: createtable_stmt #line 280 "sqlite3_parser.yy" { drv.result = yystack_[0].value.as < sqlb::TablePtr > (); } #line 1491 "sqlite3_parser.cpp" break; case 7: // literalvalue: "numeric" #line 288 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1497 "sqlite3_parser.cpp" break; case 8: // literalvalue: "string literal" #line 289 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1503 "sqlite3_parser.cpp" break; case 9: // literalvalue: "blob literal" #line 290 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1509 "sqlite3_parser.cpp" break; case 10: // literalvalue: "NULL" #line 291 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1515 "sqlite3_parser.cpp" break; case 11: // literalvalue: "TRUE" #line 292 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1521 "sqlite3_parser.cpp" break; case 12: // literalvalue: "FALSE" #line 293 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1527 "sqlite3_parser.cpp" break; case 13: // literalvalue: "CURRENT_TIME" #line 294 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1533 "sqlite3_parser.cpp" break; case 14: // literalvalue: "CURRENT_DATE" #line 295 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1539 "sqlite3_parser.cpp" break; case 15: // literalvalue: "CURRENT_TIMESTAMP" #line 296 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1545 "sqlite3_parser.cpp" break; case 16: // id: "identifier" #line 300 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1551 "sqlite3_parser.cpp" break; case 17: // id: "quoted literal" #line 301 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1557 "sqlite3_parser.cpp" break; case 18: // allowed_keywords_as_identifier: "ABORT" #line 306 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1563 "sqlite3_parser.cpp" break; case 19: // allowed_keywords_as_identifier: "ACTION" #line 307 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1569 "sqlite3_parser.cpp" break; case 20: // allowed_keywords_as_identifier: "ALWAYS" #line 308 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1575 "sqlite3_parser.cpp" break; case 21: // allowed_keywords_as_identifier: "ASC" #line 309 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1581 "sqlite3_parser.cpp" break; case 22: // allowed_keywords_as_identifier: "CASCADE" #line 310 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1587 "sqlite3_parser.cpp" break; case 23: // allowed_keywords_as_identifier: "CAST" #line 311 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1593 "sqlite3_parser.cpp" break; case 24: // allowed_keywords_as_identifier: "CONFLICT" #line 312 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1599 "sqlite3_parser.cpp" break; case 25: // allowed_keywords_as_identifier: "DEFERRED" #line 313 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1605 "sqlite3_parser.cpp" break; case 26: // allowed_keywords_as_identifier: "DESC" #line 314 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1611 "sqlite3_parser.cpp" break; case 27: // allowed_keywords_as_identifier: "END" #line 315 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1617 "sqlite3_parser.cpp" break; case 28: // allowed_keywords_as_identifier: "FAIL" #line 316 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1623 "sqlite3_parser.cpp" break; case 29: // allowed_keywords_as_identifier: "FILTER" #line 317 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1629 "sqlite3_parser.cpp" break; case 30: // allowed_keywords_as_identifier: "FOLLOWING" #line 318 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1635 "sqlite3_parser.cpp" break; case 31: // allowed_keywords_as_identifier: "GENERATED" #line 319 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1641 "sqlite3_parser.cpp" break; case 32: // allowed_keywords_as_identifier: "GLOB" #line 320 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1647 "sqlite3_parser.cpp" break; case 33: // allowed_keywords_as_identifier: "KEY" #line 321 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1653 "sqlite3_parser.cpp" break; case 34: // allowed_keywords_as_identifier: "LIKE" #line 322 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1659 "sqlite3_parser.cpp" break; case 35: // allowed_keywords_as_identifier: "IGNORE" #line 323 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1665 "sqlite3_parser.cpp" break; case 36: // allowed_keywords_as_identifier: "INITIALLY" #line 324 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1671 "sqlite3_parser.cpp" break; case 37: // allowed_keywords_as_identifier: "IMMEDIATE" #line 325 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1677 "sqlite3_parser.cpp" break; case 38: // allowed_keywords_as_identifier: "MATCH" #line 326 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1683 "sqlite3_parser.cpp" break; case 39: // allowed_keywords_as_identifier: "NO" #line 327 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1689 "sqlite3_parser.cpp" break; case 40: // allowed_keywords_as_identifier: "OVER" #line 328 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1695 "sqlite3_parser.cpp" break; case 41: // allowed_keywords_as_identifier: "PARTITION" #line 329 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1701 "sqlite3_parser.cpp" break; case 42: // allowed_keywords_as_identifier: "PRECEDING" #line 330 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1707 "sqlite3_parser.cpp" break; case 43: // allowed_keywords_as_identifier: "RAISE" #line 331 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1713 "sqlite3_parser.cpp" break; case 44: // allowed_keywords_as_identifier: "RANGE" #line 332 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1719 "sqlite3_parser.cpp" break; case 45: // allowed_keywords_as_identifier: "REGEXP" #line 333 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1725 "sqlite3_parser.cpp" break; case 46: // allowed_keywords_as_identifier: "REPLACE" #line 334 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1731 "sqlite3_parser.cpp" break; case 47: // allowed_keywords_as_identifier: "RESTRICT" #line 335 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1737 "sqlite3_parser.cpp" break; case 48: // allowed_keywords_as_identifier: "RETURNING" #line 336 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1743 "sqlite3_parser.cpp" break; case 49: // allowed_keywords_as_identifier: "ROLLBACK" #line 337 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1749 "sqlite3_parser.cpp" break; case 50: // allowed_keywords_as_identifier: "ROWID" #line 338 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1755 "sqlite3_parser.cpp" break; case 51: // allowed_keywords_as_identifier: "ROWS" #line 339 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1761 "sqlite3_parser.cpp" break; case 52: // allowed_keywords_as_identifier: "STORED" #line 340 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1767 "sqlite3_parser.cpp" break; case 53: // allowed_keywords_as_identifier: "STRICT" #line 341 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1773 "sqlite3_parser.cpp" break; case 54: // allowed_keywords_as_identifier: "TEMPORARY" #line 342 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1779 "sqlite3_parser.cpp" break; case 55: // allowed_keywords_as_identifier: "TEMP" #line 343 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1785 "sqlite3_parser.cpp" break; case 56: // allowed_keywords_as_identifier: "UNBOUNDED" #line 344 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1791 "sqlite3_parser.cpp" break; case 57: // allowed_keywords_as_identifier: "VIRTUAL" #line 345 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1797 "sqlite3_parser.cpp" break; case 58: // allowed_keywords_as_identifier: "WITHOUT" #line 346 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1803 "sqlite3_parser.cpp" break; case 59: // tableid: allowed_keywords_as_identifier #line 350 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1809 "sqlite3_parser.cpp" break; case 60: // tableid: "CURRENT_TIME" #line 351 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1815 "sqlite3_parser.cpp" break; case 61: // tableid: "CURRENT_DATE" #line 352 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1821 "sqlite3_parser.cpp" break; case 62: // tableid: "CURRENT_TIMESTAMP" #line 353 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1827 "sqlite3_parser.cpp" break; case 63: // tableid: id #line 354 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1833 "sqlite3_parser.cpp" break; case 64: // tableid: "string literal" #line 355 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = unquote_text(yystack_[0].value.as < std::string > (), '\''); } #line 1839 "sqlite3_parser.cpp" break; case 65: // columnid: allowed_keywords_as_identifier #line 359 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1845 "sqlite3_parser.cpp" break; case 66: // columnid: "CURRENT_TIME" #line 360 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1851 "sqlite3_parser.cpp" break; case 67: // columnid: "CURRENT_DATE" #line 361 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1857 "sqlite3_parser.cpp" break; case 68: // columnid: "CURRENT_TIMESTAMP" #line 362 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1863 "sqlite3_parser.cpp" break; case 69: // columnid: "IF" #line 363 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1869 "sqlite3_parser.cpp" break; case 70: // columnid: id #line 364 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1875 "sqlite3_parser.cpp" break; case 71: // columnid: "string literal" #line 365 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = unquote_text(yystack_[0].value.as < std::string > (), '\''); } #line 1881 "sqlite3_parser.cpp" break; case 72: // signednumber: "+" "numeric" #line 369 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "+" + yystack_[0].value.as < std::string > (); } #line 1887 "sqlite3_parser.cpp" break; case 73: // signednumber: "-" "numeric" #line 370 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "-" + yystack_[0].value.as < std::string > (); } #line 1893 "sqlite3_parser.cpp" break; case 74: // signednumber_or_numeric: signednumber #line 374 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1899 "sqlite3_parser.cpp" break; case 75: // signednumber_or_numeric: "numeric" #line 375 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1905 "sqlite3_parser.cpp" break; case 76: // typename_namelist: tableid #line 379 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1911 "sqlite3_parser.cpp" break; case 77: // typename_namelist: typename_namelist tableid #line 380 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 1917 "sqlite3_parser.cpp" break; case 78: // type_name: typename_namelist #line 384 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 1923 "sqlite3_parser.cpp" break; case 79: // type_name: typename_namelist "(" signednumber_or_numeric ")" #line 385 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } #line 1929 "sqlite3_parser.cpp" break; case 80: // type_name: typename_namelist "(" signednumber_or_numeric "," signednumber_or_numeric ")" #line 386 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + "(" + yystack_[3].value.as < std::string > () + ", " + yystack_[1].value.as < std::string > () + ")"; } #line 1935 "sqlite3_parser.cpp" break; case 81: // unary_expr: "-" expr #line 390 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "-" + yystack_[0].value.as < std::string > (); } #line 1941 "sqlite3_parser.cpp" break; case 82: // unary_expr: "+" expr #line 391 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "+" + yystack_[0].value.as < std::string > (); } #line 1947 "sqlite3_parser.cpp" break; case 83: // unary_expr: "~" expr #line 392 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "~" + yystack_[0].value.as < std::string > (); } #line 1953 "sqlite3_parser.cpp" break; case 84: // unary_expr: "NOT" expr #line 393 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "NOT " + yystack_[0].value.as < std::string > (); } #line 1959 "sqlite3_parser.cpp" break; case 85: // binary_expr: expr "||" expr #line 397 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " || " + yystack_[0].value.as < std::string > (); } #line 1965 "sqlite3_parser.cpp" break; case 86: // binary_expr: expr "*" expr #line 398 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " * " + yystack_[0].value.as < std::string > (); } #line 1971 "sqlite3_parser.cpp" break; case 87: // binary_expr: expr "/" expr #line 399 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " / " + yystack_[0].value.as < std::string > (); } #line 1977 "sqlite3_parser.cpp" break; case 88: // binary_expr: expr "%" expr #line 400 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " % " + yystack_[0].value.as < std::string > (); } #line 1983 "sqlite3_parser.cpp" break; case 89: // binary_expr: expr "+" expr #line 401 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " + " + yystack_[0].value.as < std::string > (); } #line 1989 "sqlite3_parser.cpp" break; case 90: // binary_expr: expr "-" expr #line 402 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " - " + yystack_[0].value.as < std::string > (); } #line 1995 "sqlite3_parser.cpp" break; case 91: // binary_expr: expr "<<" expr #line 403 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " << " + yystack_[0].value.as < std::string > (); } #line 2001 "sqlite3_parser.cpp" break; case 92: // binary_expr: expr ">>" expr #line 404 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " >> " + yystack_[0].value.as < std::string > (); } #line 2007 "sqlite3_parser.cpp" break; case 93: // binary_expr: expr "&" expr #line 405 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " & " + yystack_[0].value.as < std::string > (); } #line 2013 "sqlite3_parser.cpp" break; case 94: // binary_expr: expr "|" expr #line 406 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " | " + yystack_[0].value.as < std::string > (); } #line 2019 "sqlite3_parser.cpp" break; case 95: // binary_expr: expr "<" expr #line 407 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " < " + yystack_[0].value.as < std::string > (); } #line 2025 "sqlite3_parser.cpp" break; case 96: // binary_expr: expr "<=" expr #line 408 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " <= " + yystack_[0].value.as < std::string > (); } #line 2031 "sqlite3_parser.cpp" break; case 97: // binary_expr: expr ">" expr #line 409 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " > " + yystack_[0].value.as < std::string > (); } #line 2037 "sqlite3_parser.cpp" break; case 98: // binary_expr: expr ">=" expr #line 410 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " >= " + yystack_[0].value.as < std::string > (); } #line 2043 "sqlite3_parser.cpp" break; case 99: // binary_expr: expr "=" expr #line 411 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " = " + yystack_[0].value.as < std::string > (); } #line 2049 "sqlite3_parser.cpp" break; case 100: // binary_expr: expr "==" expr #line 412 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " == " + yystack_[0].value.as < std::string > (); } #line 2055 "sqlite3_parser.cpp" break; case 101: // binary_expr: expr "!=" expr #line 413 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " != " + yystack_[0].value.as < std::string > (); } #line 2061 "sqlite3_parser.cpp" break; case 102: // binary_expr: expr "<>" expr #line 414 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " <> " + yystack_[0].value.as < std::string > (); } #line 2067 "sqlite3_parser.cpp" break; case 103: // binary_expr: expr "IS" expr #line 415 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " IS " + yystack_[0].value.as < std::string > (); } #line 2073 "sqlite3_parser.cpp" break; case 104: // binary_expr: expr "IS" "DISTINCT" "FROM" expr #line 416 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " IS DISTINCT FROM " + yystack_[0].value.as < std::string > (); } #line 2079 "sqlite3_parser.cpp" break; case 105: // binary_expr: expr "IS" "NOT" "DISTINCT" "FROM" expr #line 417 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " IS NOT DISTINCT FROM " + yystack_[0].value.as < std::string > (); } #line 2085 "sqlite3_parser.cpp" break; case 106: // binary_expr: expr "AND" expr #line 418 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " AND " + yystack_[0].value.as < std::string > (); } #line 2091 "sqlite3_parser.cpp" break; case 107: // binary_expr: expr "OR" expr #line 419 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " OR " + yystack_[0].value.as < std::string > (); } #line 2097 "sqlite3_parser.cpp" break; case 108: // like_expr: expr "LIKE" expr #line 423 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " LIKE " + yystack_[0].value.as < std::string > (); } #line 2103 "sqlite3_parser.cpp" break; case 109: // like_expr: expr "GLOB" expr #line 424 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " GLOB " + yystack_[0].value.as < std::string > (); } #line 2109 "sqlite3_parser.cpp" break; case 110: // like_expr: expr "MATCH" expr #line 425 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " MATCH " + yystack_[0].value.as < std::string > (); } #line 2115 "sqlite3_parser.cpp" break; case 111: // like_expr: expr "REGEXP" expr #line 426 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " REGEXP " + yystack_[0].value.as < std::string > (); } #line 2121 "sqlite3_parser.cpp" break; case 112: // like_expr: expr "NOT" "LIKE" expr #line 427 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT LIKE " + yystack_[0].value.as < std::string > (); } #line 2127 "sqlite3_parser.cpp" break; case 113: // like_expr: expr "NOT" "GLOB" expr #line 428 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT GLOB " + yystack_[0].value.as < std::string > (); } #line 2133 "sqlite3_parser.cpp" break; case 114: // like_expr: expr "NOT" "MATCH" expr #line 429 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT MATCH " + yystack_[0].value.as < std::string > (); } #line 2139 "sqlite3_parser.cpp" break; case 115: // like_expr: expr "NOT" "REGEXP" expr #line 430 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT REGEXP " + yystack_[0].value.as < std::string > (); } #line 2145 "sqlite3_parser.cpp" break; case 116: // like_expr: expr "LIKE" expr "ESCAPE" expr #line 431 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " LIKE " + yystack_[2].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } #line 2151 "sqlite3_parser.cpp" break; case 117: // like_expr: expr "GLOB" expr "ESCAPE" expr #line 432 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " GLOB " + yystack_[2].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } #line 2157 "sqlite3_parser.cpp" break; case 118: // like_expr: expr "MATCH" expr "ESCAPE" expr #line 433 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " MATCH " + yystack_[2].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } #line 2163 "sqlite3_parser.cpp" break; case 119: // like_expr: expr "REGEXP" expr "ESCAPE" expr #line 434 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " REGEXP " + yystack_[2].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } #line 2169 "sqlite3_parser.cpp" break; case 120: // like_expr: expr "NOT" "LIKE" expr "ESCAPE" expr #line 435 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT LIKE " + yystack_[3].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } #line 2175 "sqlite3_parser.cpp" break; case 121: // like_expr: expr "NOT" "GLOB" expr "ESCAPE" expr #line 436 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT GLOB " + yystack_[3].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } #line 2181 "sqlite3_parser.cpp" break; case 122: // like_expr: expr "NOT" "MATCH" expr "ESCAPE" expr #line 437 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT MATCH " + yystack_[3].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } #line 2187 "sqlite3_parser.cpp" break; case 123: // like_expr: expr "NOT" "REGEXP" expr "ESCAPE" expr #line 438 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT REGEXP " + yystack_[3].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } #line 2193 "sqlite3_parser.cpp" break; case 124: // exprlist_expr: expr #line 442 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2199 "sqlite3_parser.cpp" break; case 125: // exprlist_expr: exprlist_expr "," expr #line 443 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + ", " + yystack_[0].value.as < std::string > (); } #line 2205 "sqlite3_parser.cpp" break; case 126: // function_expr: id "(" exprlist_expr ")" #line 447 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } #line 2211 "sqlite3_parser.cpp" break; case 127: // function_expr: id "(" "DISTINCT" exprlist_expr ")" #line 448 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + "(DISTINCT " + yystack_[1].value.as < std::string > () + ")"; } #line 2217 "sqlite3_parser.cpp" break; case 128: // function_expr: id "(" ")" #line 449 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + "()"; } #line 2223 "sqlite3_parser.cpp" break; case 129: // function_expr: id "(" "*" ")" #line 450 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + "(*)"; } #line 2229 "sqlite3_parser.cpp" break; case 130: // isnull_expr: expr "ISNULL" #line 454 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " ISNULL"; } #line 2235 "sqlite3_parser.cpp" break; case 131: // isnull_expr: expr "NOTNULL" #line 455 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " NOTNULL"; } #line 2241 "sqlite3_parser.cpp" break; case 132: // isnull_expr: expr "NOT" "NULL" #line 456 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " NOT NULL"; } #line 2247 "sqlite3_parser.cpp" break; case 133: // between_expr: expr "BETWEEN" expr "AND BETWEEN" expr #line 460 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " BETWEEN " + yystack_[2].value.as < std::string > () + " AND " + yystack_[0].value.as < std::string > (); } #line 2253 "sqlite3_parser.cpp" break; case 134: // between_expr: expr "NOT" "BETWEEN" expr "AND BETWEEN" expr #line 461 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT BETWEEN " + yystack_[2].value.as < std::string > () + " AND " + yystack_[0].value.as < std::string > (); } #line 2259 "sqlite3_parser.cpp" break; case 135: // in_expr: expr "IN" "(" ")" #line 465 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " IN ()"; } #line 2265 "sqlite3_parser.cpp" break; case 136: // in_expr: expr "IN" "(" select_stmt ")" #line 466 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " IN (" + yystack_[1].value.as < std::string > () + ")"; } #line 2271 "sqlite3_parser.cpp" break; case 137: // in_expr: expr "IN" "(" exprlist_expr ")" #line 467 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " IN (" + yystack_[1].value.as < std::string > () + ")"; } #line 2277 "sqlite3_parser.cpp" break; case 138: // in_expr: expr "IN" id "." tableid #line 468 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " IN " + sqlb::escapeIdentifier(yystack_[2].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } #line 2283 "sqlite3_parser.cpp" break; case 139: // in_expr: expr "IN" tableid #line 469 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " IN " + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } #line 2289 "sqlite3_parser.cpp" break; case 140: // in_expr: expr "IN" id "." id "(" ")" #line 470 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[6].value.as < std::string > () + " IN " + sqlb::escapeIdentifier(yystack_[4].value.as < std::string > ()) + "." + yystack_[2].value.as < std::string > () + "()"; } #line 2295 "sqlite3_parser.cpp" break; case 141: // in_expr: expr "IN" id "." id "(" exprlist_expr ")" #line 471 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[7].value.as < std::string > () + " IN " + sqlb::escapeIdentifier(yystack_[5].value.as < std::string > ()) + "." + yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } #line 2301 "sqlite3_parser.cpp" break; case 142: // in_expr: expr "IN" id "(" exprlist_expr ")" #line 472 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " IN " + yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } #line 2307 "sqlite3_parser.cpp" break; case 143: // in_expr: expr "NOT" "IN" "(" ")" #line 473 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " NOT IN ()"; } #line 2313 "sqlite3_parser.cpp" break; case 144: // in_expr: expr "NOT" "IN" "(" select_stmt ")" #line 474 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT IN (" + yystack_[1].value.as < std::string > () + ")"; } #line 2319 "sqlite3_parser.cpp" break; case 145: // in_expr: expr "NOT" "IN" "(" exprlist_expr ")" #line 475 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT IN (" + yystack_[1].value.as < std::string > () + ")"; } #line 2325 "sqlite3_parser.cpp" break; case 146: // in_expr: expr "NOT" "IN" id "." tableid #line 476 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT IN " + sqlb::escapeIdentifier(yystack_[2].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } #line 2331 "sqlite3_parser.cpp" break; case 147: // in_expr: expr "NOT" "IN" tableid #line 477 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT IN " + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } #line 2337 "sqlite3_parser.cpp" break; case 148: // in_expr: expr "NOT" "IN" id "." id "(" ")" #line 478 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[7].value.as < std::string > () + " NOT IN " + sqlb::escapeIdentifier(yystack_[4].value.as < std::string > ()) + "." + yystack_[2].value.as < std::string > () + "()"; } #line 2343 "sqlite3_parser.cpp" break; case 149: // in_expr: expr "NOT" "IN" id "." id "(" exprlist_expr ")" #line 479 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[8].value.as < std::string > () + " NOT IN " + sqlb::escapeIdentifier(yystack_[5].value.as < std::string > ()) + "." + yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } #line 2349 "sqlite3_parser.cpp" break; case 150: // in_expr: expr "NOT" "IN" id "(" exprlist_expr ")" #line 480 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[6].value.as < std::string > () + " NOT IN " + yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } #line 2355 "sqlite3_parser.cpp" break; case 151: // whenthenlist_expr: "WHEN" expr "THEN" expr #line 484 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "WHEN " + yystack_[2].value.as < std::string > () + " THEN " + yystack_[0].value.as < std::string > (); } #line 2361 "sqlite3_parser.cpp" break; case 152: // whenthenlist_expr: whenthenlist_expr "WHEN" expr "THEN" expr #line 485 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " WHEN" + yystack_[2].value.as < std::string > () + " THEN " + yystack_[0].value.as < std::string > (); } #line 2367 "sqlite3_parser.cpp" break; case 153: // case_expr: "CASE" expr whenthenlist_expr "ELSE" expr "END" #line 489 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "CASE " + yystack_[4].value.as < std::string > () + " " + yystack_[3].value.as < std::string > () + " ELSE " + yystack_[1].value.as < std::string > () + " END"; } #line 2373 "sqlite3_parser.cpp" break; case 154: // case_expr: "CASE" expr whenthenlist_expr "END" #line 490 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "CASE " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " END"; } #line 2379 "sqlite3_parser.cpp" break; case 155: // case_expr: "CASE" whenthenlist_expr "ELSE" expr "END" #line 491 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "CASE " + yystack_[3].value.as < std::string > () + " ELSE " + yystack_[1].value.as < std::string > () + " END"; } #line 2385 "sqlite3_parser.cpp" break; case 156: // case_expr: "CASE" whenthenlist_expr "END" #line 492 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "CASE " + yystack_[1].value.as < std::string > () + " END"; } #line 2391 "sqlite3_parser.cpp" break; case 157: // raise_expr: "RAISE" "(" "IGNORE" ")" #line 496 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "RAISE(IGNORE)"; } #line 2397 "sqlite3_parser.cpp" break; case 158: // raise_expr: "RAISE" "(" "ROLLBACK" "," "string literal" ")" #line 497 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "RAISE(ROLLBACK, " + yystack_[1].value.as < std::string > () + ")"; } #line 2403 "sqlite3_parser.cpp" break; case 159: // raise_expr: "RAISE" "(" "ABORT" "," "string literal" ")" #line 498 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "RAISE(ABORT, " + yystack_[1].value.as < std::string > () + ")"; } #line 2409 "sqlite3_parser.cpp" break; case 160: // raise_expr: "RAISE" "(" "FAIL" "," "string literal" ")" #line 499 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "RAISE(FAIL, " + yystack_[1].value.as < std::string > () + ")"; } #line 2415 "sqlite3_parser.cpp" break; case 161: // expr: literalvalue #line 503 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2421 "sqlite3_parser.cpp" break; case 162: // expr: allowed_keywords_as_identifier #line 504 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } #line 2427 "sqlite3_parser.cpp" break; case 163: // expr: "bind parameter" #line 505 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2433 "sqlite3_parser.cpp" break; case 164: // expr: id "." id "." id #line 506 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = sqlb::escapeIdentifier(yystack_[4].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[2].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } #line 2439 "sqlite3_parser.cpp" break; case 165: // expr: id "." id #line 507 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = sqlb::escapeIdentifier(yystack_[2].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } #line 2445 "sqlite3_parser.cpp" break; case 166: // expr: id #line 508 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } #line 2451 "sqlite3_parser.cpp" break; case 167: // expr: unary_expr #line 509 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2457 "sqlite3_parser.cpp" break; case 168: // expr: binary_expr #line 510 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2463 "sqlite3_parser.cpp" break; case 169: // expr: function_expr #line 511 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2469 "sqlite3_parser.cpp" break; case 170: // expr: "(" exprlist_expr ")" #line 512 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "(" + yystack_[1].value.as < std::string > () + ")"; } #line 2475 "sqlite3_parser.cpp" break; case 171: // expr: "CAST" "(" expr "AS" type_name ")" #line 513 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "CAST(" + yystack_[3].value.as < std::string > () + " AS " + yystack_[1].value.as < std::string > () + ")"; } #line 2481 "sqlite3_parser.cpp" break; case 172: // expr: expr "COLLATE" id #line 514 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " COLLATE " + yystack_[0].value.as < std::string > (); } #line 2487 "sqlite3_parser.cpp" break; case 173: // expr: like_expr #line 515 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2493 "sqlite3_parser.cpp" break; case 174: // expr: isnull_expr #line 516 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2499 "sqlite3_parser.cpp" break; case 175: // expr: between_expr #line 517 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2505 "sqlite3_parser.cpp" break; case 176: // expr: in_expr #line 518 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2511 "sqlite3_parser.cpp" break; case 177: // expr: case_expr #line 519 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2517 "sqlite3_parser.cpp" break; case 178: // expr: raise_expr #line 520 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2523 "sqlite3_parser.cpp" break; case 179: // select_stmt: "SELECT" #line 529 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "SELECT"; } #line 2529 "sqlite3_parser.cpp" break; case 180: // optional_if_not_exists: %empty #line 537 "sqlite3_parser.yy" { yylhs.value.as < bool > () = false; } #line 2535 "sqlite3_parser.cpp" break; case 181: // optional_if_not_exists: "IF" "NOT" "EXISTS" #line 538 "sqlite3_parser.yy" { yylhs.value.as < bool > () = true; } #line 2541 "sqlite3_parser.cpp" break; case 182: // optional_sort_order: %empty #line 542 "sqlite3_parser.yy" { } #line 2547 "sqlite3_parser.cpp" break; case 183: // optional_sort_order: "ASC" #line 543 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "ASC"; } #line 2553 "sqlite3_parser.cpp" break; case 184: // optional_sort_order: "DESC" #line 544 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "DESC"; } #line 2559 "sqlite3_parser.cpp" break; case 185: // optional_unique: %empty #line 552 "sqlite3_parser.yy" { yylhs.value.as < bool > () = false; } #line 2565 "sqlite3_parser.cpp" break; case 186: // optional_unique: "UNIQUE" #line 553 "sqlite3_parser.yy" { yylhs.value.as < bool > () = true; } #line 2571 "sqlite3_parser.cpp" break; case 187: // optional_where: %empty #line 557 "sqlite3_parser.yy" { } #line 2577 "sqlite3_parser.cpp" break; case 188: // optional_where: "WHERE" expr #line 558 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2583 "sqlite3_parser.cpp" break; case 189: // tableid_with_uninteresting_schema: id "." tableid #line 562 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2589 "sqlite3_parser.cpp" break; case 190: // tableid_with_uninteresting_schema: "TEMP" "." tableid #line 563 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2595 "sqlite3_parser.cpp" break; case 191: // tableid_with_uninteresting_schema: tableid #line 564 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2601 "sqlite3_parser.cpp" break; case 192: // indexed_column: expr optional_sort_order #line 568 "sqlite3_parser.yy" { // If the expression is only one column name and nothing else, treat it as a column name; otherwise as an expression. char quote = getIdentifierQuoteChar(); if((quote == '[' && std::count(yystack_[1].value.as < std::string > ().begin(), yystack_[1].value.as < std::string > ().end(), quote) == 1 && yystack_[1].value.as < std::string > ().front() == '[' && yystack_[1].value.as < std::string > ().back() == ']') || (quote != '[' && std::count(yystack_[1].value.as < std::string > ().begin(), yystack_[1].value.as < std::string > ().end(), quote) == 2 && yystack_[1].value.as < std::string > ().front() == quote && yystack_[1].value.as < std::string > ().back() == quote)) { yylhs.value.as < sqlb::IndexedColumn > () = sqlb::IndexedColumn(unquote_text(yystack_[1].value.as < std::string > (), quote), false, yystack_[0].value.as < std::string > ()); } else if(std::count(yystack_[1].value.as < std::string > ().begin(), yystack_[1].value.as < std::string > ().end(), '\'') == 2 && yystack_[1].value.as < std::string > ().front() == '\'' && yystack_[1].value.as < std::string > ().back() == '\'') { // Also remove single quotes when this actually is a string literal but looks like a columnid yylhs.value.as < sqlb::IndexedColumn > () = sqlb::IndexedColumn(unquote_text(yystack_[1].value.as < std::string > (), '\''), false, yystack_[0].value.as < std::string > ()); } else { yylhs.value.as < sqlb::IndexedColumn > () = sqlb::IndexedColumn(yystack_[1].value.as < std::string > (), true, yystack_[0].value.as < std::string > ()); } } #line 2620 "sqlite3_parser.cpp" break; case 193: // indexed_column_list: indexed_column #line 585 "sqlite3_parser.yy" { yylhs.value.as < sqlb::IndexedColumnVector > () = sqlb::IndexedColumnVector(1, yystack_[0].value.as < sqlb::IndexedColumn > ()); } #line 2626 "sqlite3_parser.cpp" break; case 194: // indexed_column_list: indexed_column_list "," indexed_column #line 586 "sqlite3_parser.yy" { yylhs.value.as < sqlb::IndexedColumnVector > () = yystack_[2].value.as < sqlb::IndexedColumnVector > (); yylhs.value.as < sqlb::IndexedColumnVector > ().push_back(yystack_[0].value.as < sqlb::IndexedColumn > ()); } #line 2632 "sqlite3_parser.cpp" break; case 195: // createindex_stmt: "CREATE" optional_unique "INDEX" optional_if_not_exists tableid_with_uninteresting_schema "ON" tableid "(" indexed_column_list ")" optional_where #line 590 "sqlite3_parser.yy" { yylhs.value.as < sqlb::IndexPtr > () = std::make_shared(yystack_[6].value.as < std::string > ()); yylhs.value.as < sqlb::IndexPtr > ()->setTable(yystack_[4].value.as < std::string > ()); yylhs.value.as < sqlb::IndexPtr > ()->setUnique(yystack_[9].value.as < bool > ()); yylhs.value.as < sqlb::IndexPtr > ()->setWhereExpr(yystack_[0].value.as < std::string > ()); yylhs.value.as < sqlb::IndexPtr > ()->fields = yystack_[2].value.as < sqlb::IndexedColumnVector > (); yylhs.value.as < sqlb::IndexPtr > ()->setFullyParsed(true); } #line 2645 "sqlite3_parser.cpp" break; case 196: // optional_exprlist_with_paren: %empty #line 605 "sqlite3_parser.yy" { } #line 2651 "sqlite3_parser.cpp" break; case 197: // optional_exprlist_with_paren: "(" ")" #line 606 "sqlite3_parser.yy" { } #line 2657 "sqlite3_parser.cpp" break; case 198: // optional_exprlist_with_paren: "(" exprlist_expr ")" #line 607 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > (); } #line 2663 "sqlite3_parser.cpp" break; case 199: // createvirtualtable_stmt: "CREATE" "VIRTUAL" "TABLE" optional_if_not_exists tableid_with_uninteresting_schema "USING" id optional_exprlist_with_paren #line 611 "sqlite3_parser.yy" { yylhs.value.as < sqlb::TablePtr > () = std::make_shared(yystack_[3].value.as < std::string > ()); yylhs.value.as < sqlb::TablePtr > ()->setVirtualUsing(yystack_[1].value.as < std::string > ()); yylhs.value.as < sqlb::TablePtr > ()->setFullyParsed(false); } #line 2673 "sqlite3_parser.cpp" break; case 200: // optional_temporary: %empty #line 623 "sqlite3_parser.yy" { yylhs.value.as < bool > () = false; } #line 2679 "sqlite3_parser.cpp" break; case 201: // optional_temporary: "TEMP" #line 624 "sqlite3_parser.yy" { yylhs.value.as < bool > () = true; } #line 2685 "sqlite3_parser.cpp" break; case 202: // optional_temporary: "TEMPORARY" #line 625 "sqlite3_parser.yy" { yylhs.value.as < bool > () = true; } #line 2691 "sqlite3_parser.cpp" break; case 203: // tableoption: "WITHOUT" "ROWID" #line 629 "sqlite3_parser.yy" { yylhs.value.as < std::bitset > ().set(sqlb::Table::WithoutRowid, true); } #line 2697 "sqlite3_parser.cpp" break; case 204: // tableoption: "STRICT" #line 630 "sqlite3_parser.yy" { yylhs.value.as < std::bitset > ().set(sqlb::Table::Strict, true); } #line 2703 "sqlite3_parser.cpp" break; case 205: // tableoptions_list: tableoption #line 634 "sqlite3_parser.yy" { yylhs.value.as < std::bitset > () = yystack_[0].value.as < std::bitset > (); } #line 2709 "sqlite3_parser.cpp" break; case 206: // tableoptions_list: tableoptions_list "," tableoption #line 635 "sqlite3_parser.yy" { yylhs.value.as < std::bitset > () = yystack_[2].value.as < std::bitset > () | yystack_[0].value.as < std::bitset > (); } #line 2715 "sqlite3_parser.cpp" break; case 207: // tableoptions_list: tableoptions_list tableoption #line 636 "sqlite3_parser.yy" { yylhs.value.as < std::bitset > () = yystack_[1].value.as < std::bitset > () | yystack_[0].value.as < std::bitset > (); } #line 2721 "sqlite3_parser.cpp" break; case 208: // optional_tableoptions_list: %empty #line 640 "sqlite3_parser.yy" { } #line 2727 "sqlite3_parser.cpp" break; case 209: // optional_tableoptions_list: tableoptions_list #line 641 "sqlite3_parser.yy" { yylhs.value.as < std::bitset > () = yystack_[0].value.as < std::bitset > (); } #line 2733 "sqlite3_parser.cpp" break; case 210: // optional_conflictclause: %empty #line 645 "sqlite3_parser.yy" { } #line 2739 "sqlite3_parser.cpp" break; case 211: // optional_conflictclause: "ON" "CONFLICT" "ROLLBACK" #line 646 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2745 "sqlite3_parser.cpp" break; case 212: // optional_conflictclause: "ON" "CONFLICT" "ABORT" #line 647 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2751 "sqlite3_parser.cpp" break; case 213: // optional_conflictclause: "ON" "CONFLICT" "FAIL" #line 648 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2757 "sqlite3_parser.cpp" break; case 214: // optional_conflictclause: "ON" "CONFLICT" "IGNORE" #line 649 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2763 "sqlite3_parser.cpp" break; case 215: // optional_conflictclause: "ON" "CONFLICT" "REPLACE" #line 650 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2769 "sqlite3_parser.cpp" break; case 216: // optional_typename: %empty #line 654 "sqlite3_parser.yy" { } #line 2775 "sqlite3_parser.cpp" break; case 217: // optional_typename: type_name #line 655 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 2781 "sqlite3_parser.cpp" break; case 218: // optional_storage_identifier: %empty #line 659 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "VIRTUAL"; } #line 2787 "sqlite3_parser.cpp" break; case 219: // optional_storage_identifier: "STORED" #line 660 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "STORED"; } #line 2793 "sqlite3_parser.cpp" break; case 220: // optional_storage_identifier: "VIRTUAL" #line 661 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = "VIRTUAL"; } #line 2799 "sqlite3_parser.cpp" break; case 221: // optional_always_generated: %empty #line 665 "sqlite3_parser.yy" { yylhs.value.as < bool > () = false; } #line 2805 "sqlite3_parser.cpp" break; case 222: // optional_always_generated: "GENERATED" "ALWAYS" #line 666 "sqlite3_parser.yy" { yylhs.value.as < bool > () = true; } #line 2811 "sqlite3_parser.cpp" break; case 223: // columnconstraint: optional_constraintname "PRIMARY" "KEY" optional_sort_order optional_conflictclause #line 670 "sqlite3_parser.yy" { auto pk = std::make_shared(); pk->setName(yystack_[4].value.as < std::string > ()); pk->setConflictAction(yystack_[0].value.as < std::string > ()); yylhs.value.as < std::pair, std::shared_ptr> > ().first = pk; } #line 2822 "sqlite3_parser.cpp" break; case 224: // columnconstraint: optional_constraintname "PRIMARY" "KEY" optional_sort_order optional_conflictclause "AUTOINCREMENT" #line 676 "sqlite3_parser.yy" { auto pk = std::make_shared(); pk->setName(yystack_[5].value.as < std::string > ()); pk->setConflictAction(yystack_[1].value.as < std::string > ()); pk->setAutoIncrement(true); yylhs.value.as < std::pair, std::shared_ptr> > ().first = pk; } #line 2834 "sqlite3_parser.cpp" break; case 225: // columnconstraint: optional_constraintname "NOT" "NULL" optional_conflictclause #line 683 "sqlite3_parser.yy" { auto nn = std::make_shared(); nn->setName(yystack_[3].value.as < std::string > ()); nn->setConflictAction(yystack_[0].value.as < std::string > ()); drv.last_table_column->setNotNull(nn); } #line 2845 "sqlite3_parser.cpp" break; case 226: // columnconstraint: optional_constraintname "NULL" #line 689 "sqlite3_parser.yy" { } #line 2852 "sqlite3_parser.cpp" break; case 227: // columnconstraint: optional_constraintname "UNIQUE" optional_conflictclause #line 691 "sqlite3_parser.yy" { auto u = std::make_shared(); u->setName(yystack_[2].value.as < std::string > ()); u->setConflictAction(yystack_[0].value.as < std::string > ()); drv.last_table_column->setUnique(u); } #line 2863 "sqlite3_parser.cpp" break; case 228: // columnconstraint: optional_constraintname "CHECK" "(" expr ")" #line 697 "sqlite3_parser.yy" { auto c = std::make_shared(yystack_[1].value.as < std::string > ()); c->setName(yystack_[4].value.as < std::string > ()); drv.last_table_column->setCheck(c); } #line 2873 "sqlite3_parser.cpp" break; case 229: // columnconstraint: optional_constraintname "DEFAULT" signednumber #line 702 "sqlite3_parser.yy" { auto d = std::make_shared(yystack_[0].value.as < std::string > ()); d->setName(yystack_[2].value.as < std::string > ()); drv.last_table_column->setDefaultValue(d); } #line 2883 "sqlite3_parser.cpp" break; case 230: // columnconstraint: optional_constraintname "DEFAULT" literalvalue #line 707 "sqlite3_parser.yy" { auto d = std::make_shared(yystack_[0].value.as < std::string > ()); d->setName(yystack_[2].value.as < std::string > ()); drv.last_table_column->setDefaultValue(d); } #line 2893 "sqlite3_parser.cpp" break; case 231: // columnconstraint: optional_constraintname "DEFAULT" id #line 712 "sqlite3_parser.yy" { auto d = std::make_shared(yystack_[0].value.as < std::string > ()); d->setName(yystack_[2].value.as < std::string > ()); drv.last_table_column->setDefaultValue(d); } #line 2903 "sqlite3_parser.cpp" break; case 232: // columnconstraint: optional_constraintname "DEFAULT" allowed_keywords_as_identifier #line 717 "sqlite3_parser.yy" { // We must allow the same keywords as unquoted default values as in the columnid context. // But we do not use columnid here in order to avoid reduce/reduce conflicts. auto d = std::make_shared(yystack_[0].value.as < std::string > ()); d->setName(yystack_[2].value.as < std::string > ()); drv.last_table_column->setDefaultValue(d); } #line 2914 "sqlite3_parser.cpp" break; case 233: // columnconstraint: optional_constraintname "DEFAULT" "IF" #line 723 "sqlite3_parser.yy" { // Same as above. auto d = std::make_shared(yystack_[0].value.as < std::string > ()); d->setName(yystack_[2].value.as < std::string > ()); drv.last_table_column->setDefaultValue(d); } #line 2924 "sqlite3_parser.cpp" break; case 234: // columnconstraint: optional_constraintname "DEFAULT" "(" expr ")" #line 728 "sqlite3_parser.yy" { auto d = std::make_shared("(" + yystack_[1].value.as < std::string > () + ")"); d->setName(yystack_[4].value.as < std::string > ()); drv.last_table_column->setDefaultValue(d); } #line 2934 "sqlite3_parser.cpp" break; case 235: // columnconstraint: optional_constraintname "COLLATE" id #line 733 "sqlite3_parser.yy" { auto c = std::make_shared(yystack_[0].value.as < std::string > ()); c->setName(yystack_[2].value.as < std::string > ()); drv.last_table_column->setCollation(c); } #line 2944 "sqlite3_parser.cpp" break; case 236: // columnconstraint: optional_constraintname "REFERENCES" tableid optional_columnid_with_paren_list optional_fk_clause #line 738 "sqlite3_parser.yy" { // TODO Solve shift/reduce conflict. It is not super important though as shifting seems to be right here. auto fk = std::make_shared(); fk->setName(yystack_[4].value.as < std::string > ()); fk->setTable(yystack_[2].value.as < std::string > ()); fk->setColumns(yystack_[1].value.as < sqlb::StringVector > ()); fk->setConstraint(yystack_[0].value.as < std::string > ()); yylhs.value.as < std::pair, std::shared_ptr> > ().second = fk; } #line 2957 "sqlite3_parser.cpp" break; case 237: // columnconstraint: optional_constraintname optional_always_generated "AS" "(" expr ")" optional_storage_identifier #line 746 "sqlite3_parser.yy" { // TODO Solve shift/reduce conflict. auto g = std::make_shared(yystack_[2].value.as < std::string > (), yystack_[0].value.as < std::string > ()); g->setName(yystack_[6].value.as < std::string > ()); drv.last_table_column->setGenerated(g); // This is a hack which removes any "GENERATED ALWAYS" from the end of the type name. // As of now these are shifted to the type instead of reducing the type when seeing the GENERATED identifier. // TODO Remove this once the grammar is conflict free const std::string generated_always = "GENERATED ALWAYS"; if(drv.last_table_column->type().size() >= generated_always.size() && drv.last_table_column->type().compare(drv.last_table_column->type().size() - generated_always.size(), generated_always.size(), generated_always) == 0) { std::string type = drv.last_table_column->type().substr(0, drv.last_table_column->type().size()-generated_always.size()); if(type.back() == ' ') type.pop_back(); drv.last_table_column->setType(type); } } #line 2980 "sqlite3_parser.cpp" break; case 238: // columnconstraint_list: %empty #line 767 "sqlite3_parser.yy" { } #line 2986 "sqlite3_parser.cpp" break; case 239: // columnconstraint_list: columnconstraint_list columnconstraint #line 768 "sqlite3_parser.yy" { yylhs.value.as < TableConstraints > () = yystack_[1].value.as < TableConstraints > (); // Primary key and foreign key constraints are converted to table constraints // because we cannot store them as column constraints at the moment. if(yystack_[0].value.as < std::pair, std::shared_ptr> > ().first) yylhs.value.as < TableConstraints > ().index.insert(std::make_pair(sqlb::IndexedColumnVector{sqlb::IndexedColumn(drv.last_table_column->name(), false)}, yystack_[0].value.as < std::pair, std::shared_ptr> > ().first)); if(yystack_[0].value.as < std::pair, std::shared_ptr> > ().second) yylhs.value.as < TableConstraints > ().fk.insert(std::make_pair(sqlb::StringVector{drv.last_table_column->name()}, yystack_[0].value.as < std::pair, std::shared_ptr> > ().second)); } #line 3001 "sqlite3_parser.cpp" break; case 240: // columndef: columnid optional_typename #line 781 "sqlite3_parser.yy" { yylhs.value.as < std::shared_ptr > () = std::make_shared(yystack_[1].value.as < std::string > (), yystack_[0].value.as < std::string > ()); drv.last_table_column = yylhs.value.as < std::shared_ptr > (); } #line 3007 "sqlite3_parser.cpp" break; case 241: // columndef_list: columndef columnconstraint_list #line 785 "sqlite3_parser.yy" { yylhs.value.as < ColumnList > ().first.push_back(yystack_[1].value.as < std::shared_ptr > ()); yylhs.value.as < ColumnList > ().second = yystack_[0].value.as < TableConstraints > (); } #line 3013 "sqlite3_parser.cpp" break; case 242: // columndef_list: columndef_list "," columndef columnconstraint_list #line 786 "sqlite3_parser.yy" { yylhs.value.as < ColumnList > () = yystack_[3].value.as < ColumnList > (); yylhs.value.as < ColumnList > ().first.push_back(yystack_[1].value.as < std::shared_ptr > ()); yylhs.value.as < ColumnList > ().second.index.insert(yystack_[0].value.as < TableConstraints > ().index.begin(), yystack_[0].value.as < TableConstraints > ().index.end()); yylhs.value.as < ColumnList > ().second.fk.insert(yystack_[0].value.as < TableConstraints > ().fk.begin(), yystack_[0].value.as < TableConstraints > ().fk.end()); } #line 3019 "sqlite3_parser.cpp" break; case 243: // optional_constraintname: %empty #line 790 "sqlite3_parser.yy" { } #line 3025 "sqlite3_parser.cpp" break; case 244: // optional_constraintname: "CONSTRAINT" id #line 791 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 3031 "sqlite3_parser.cpp" break; case 245: // optional_constraintname: "CONSTRAINT" "string literal" #line 792 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 3037 "sqlite3_parser.cpp" break; case 246: // columnid_list: columnid #line 796 "sqlite3_parser.yy" { yylhs.value.as < sqlb::StringVector > () = sqlb::StringVector(1, yystack_[0].value.as < std::string > ()); } #line 3043 "sqlite3_parser.cpp" break; case 247: // columnid_list: columnid_list "," columnid #line 797 "sqlite3_parser.yy" { yylhs.value.as < sqlb::StringVector > () = yystack_[2].value.as < sqlb::StringVector > (); yylhs.value.as < sqlb::StringVector > ().push_back(yystack_[0].value.as < std::string > ()); } #line 3049 "sqlite3_parser.cpp" break; case 248: // optional_columnid_with_paren_list: %empty #line 801 "sqlite3_parser.yy" { } #line 3055 "sqlite3_parser.cpp" break; case 249: // optional_columnid_with_paren_list: "(" columnid_list ")" #line 802 "sqlite3_parser.yy" { yylhs.value.as < sqlb::StringVector > () = yystack_[1].value.as < sqlb::StringVector > (); } #line 3061 "sqlite3_parser.cpp" break; case 250: // fk_clause_part: "ON" "DELETE" "SET" "NULL" #line 806 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3067 "sqlite3_parser.cpp" break; case 251: // fk_clause_part: "ON" "DELETE" "SET" "DEFAULT" #line 807 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3073 "sqlite3_parser.cpp" break; case 252: // fk_clause_part: "ON" "DELETE" "CASCADE" #line 808 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3079 "sqlite3_parser.cpp" break; case 253: // fk_clause_part: "ON" "DELETE" "RESTRICT" #line 809 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3085 "sqlite3_parser.cpp" break; case 254: // fk_clause_part: "ON" "DELETE" "NO" "ACTION" #line 810 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3091 "sqlite3_parser.cpp" break; case 255: // fk_clause_part: "ON" "UPDATE" "SET" "NULL" #line 811 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3097 "sqlite3_parser.cpp" break; case 256: // fk_clause_part: "ON" "UPDATE" "SET" "DEFAULT" #line 812 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3103 "sqlite3_parser.cpp" break; case 257: // fk_clause_part: "ON" "UPDATE" "CASCADE" #line 813 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3109 "sqlite3_parser.cpp" break; case 258: // fk_clause_part: "ON" "UPDATE" "RESTRICT" #line 814 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3115 "sqlite3_parser.cpp" break; case 259: // fk_clause_part: "ON" "UPDATE" "NO" "ACTION" #line 815 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3121 "sqlite3_parser.cpp" break; case 260: // fk_clause_part: "ON" "INSERT" "SET" "NULL" #line 816 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3127 "sqlite3_parser.cpp" break; case 261: // fk_clause_part: "ON" "INSERT" "SET" "DEFAULT" #line 817 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3133 "sqlite3_parser.cpp" break; case 262: // fk_clause_part: "ON" "INSERT" "CASCADE" #line 818 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3139 "sqlite3_parser.cpp" break; case 263: // fk_clause_part: "ON" "INSERT" "RESTRICT" #line 819 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3145 "sqlite3_parser.cpp" break; case 264: // fk_clause_part: "ON" "INSERT" "NO" "ACTION" #line 820 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3151 "sqlite3_parser.cpp" break; case 265: // fk_clause_part: "MATCH" id #line 821 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3157 "sqlite3_parser.cpp" break; case 266: // fk_clause_part_list: fk_clause_part #line 825 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 3163 "sqlite3_parser.cpp" break; case 267: // fk_clause_part_list: fk_clause_part_list fk_clause_part #line 826 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3169 "sqlite3_parser.cpp" break; case 268: // optional_fk_clause: %empty #line 830 "sqlite3_parser.yy" { } #line 3175 "sqlite3_parser.cpp" break; case 269: // optional_fk_clause: fk_clause_part_list #line 831 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 3181 "sqlite3_parser.cpp" break; case 270: // optional_fk_clause: fk_clause_part_list "DEFERRABLE" "INITIALLY" "DEFERRED" #line 832 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3187 "sqlite3_parser.cpp" break; case 271: // optional_fk_clause: fk_clause_part_list "DEFERRABLE" "INITIALLY" "IMMEDIATE" #line 833 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3193 "sqlite3_parser.cpp" break; case 272: // optional_fk_clause: fk_clause_part_list "DEFERRABLE" #line 834 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3199 "sqlite3_parser.cpp" break; case 273: // optional_fk_clause: fk_clause_part_list "NOT" "DEFERRABLE" "INITIALLY" "DEFERRED" #line 835 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " " + yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3205 "sqlite3_parser.cpp" break; case 274: // optional_fk_clause: fk_clause_part_list "NOT" "DEFERRABLE" "INITIALLY" "IMMEDIATE" #line 836 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " " + yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3211 "sqlite3_parser.cpp" break; case 275: // optional_fk_clause: fk_clause_part_list "NOT" "DEFERRABLE" #line 837 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3217 "sqlite3_parser.cpp" break; case 276: // optional_fk_clause: "DEFERRABLE" "INITIALLY" "DEFERRED" #line 838 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3223 "sqlite3_parser.cpp" break; case 277: // optional_fk_clause: "DEFERRABLE" "INITIALLY" "IMMEDIATE" #line 839 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3229 "sqlite3_parser.cpp" break; case 278: // optional_fk_clause: "DEFERRABLE" #line 840 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } #line 3235 "sqlite3_parser.cpp" break; case 279: // optional_fk_clause: "NOT" "DEFERRABLE" "INITIALLY" "DEFERRED" #line 841 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3241 "sqlite3_parser.cpp" break; case 280: // optional_fk_clause: "NOT" "DEFERRABLE" "INITIALLY" "IMMEDIATE" #line 842 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3247 "sqlite3_parser.cpp" break; case 281: // optional_fk_clause: "NOT" "DEFERRABLE" #line 843 "sqlite3_parser.yy" { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } #line 3253 "sqlite3_parser.cpp" break; case 282: // tableconstraint: optional_constraintname "PRIMARY" "KEY" "(" indexed_column_list ")" optional_conflictclause #line 847 "sqlite3_parser.yy" { auto pk = std::make_shared(); pk->setName(yystack_[6].value.as < std::string > ()); pk->setConflictAction(yystack_[0].value.as < std::string > ()); yylhs.value.as < TableConstraints > ().index.insert(std::make_pair(yystack_[2].value.as < sqlb::IndexedColumnVector > (), pk)); } #line 3264 "sqlite3_parser.cpp" break; case 283: // tableconstraint: optional_constraintname "PRIMARY" "KEY" "(" indexed_column_list "AUTOINCREMENT" ")" optional_conflictclause #line 853 "sqlite3_parser.yy" { auto pk = std::make_shared(); pk->setName(yystack_[7].value.as < std::string > ()); pk->setConflictAction(yystack_[0].value.as < std::string > ()); pk->setAutoIncrement(true); yylhs.value.as < TableConstraints > ().index.insert(std::make_pair(yystack_[3].value.as < sqlb::IndexedColumnVector > (), pk)); } #line 3276 "sqlite3_parser.cpp" break; case 284: // tableconstraint: optional_constraintname "UNIQUE" "(" indexed_column_list ")" optional_conflictclause #line 860 "sqlite3_parser.yy" { auto u = std::make_shared(); u->setName(yystack_[5].value.as < std::string > ()); u->setConflictAction(yystack_[0].value.as < std::string > ()); sqlb::StringVector columns; yylhs.value.as < TableConstraints > ().index.insert(std::make_pair(yystack_[2].value.as < sqlb::IndexedColumnVector > (), u)); } #line 3288 "sqlite3_parser.cpp" break; case 285: // tableconstraint: optional_constraintname "CHECK" "(" expr ")" #line 867 "sqlite3_parser.yy" { auto c = std::make_shared(yystack_[1].value.as < std::string > ()); c->setName(yystack_[4].value.as < std::string > ()); yylhs.value.as < TableConstraints > ().check.push_back(c); } #line 3298 "sqlite3_parser.cpp" break; case 286: // tableconstraint: optional_constraintname "FOREIGN" "KEY" "(" columnid_list ")" "REFERENCES" tableid optional_columnid_with_paren_list optional_fk_clause #line 872 "sqlite3_parser.yy" { auto f = std::make_shared(yystack_[2].value.as < std::string > (), yystack_[1].value.as < sqlb::StringVector > (), yystack_[0].value.as < std::string > ()); f->setName(yystack_[9].value.as < std::string > ()); yylhs.value.as < TableConstraints > ().fk.insert(std::make_pair(yystack_[5].value.as < sqlb::StringVector > (), f)); } #line 3308 "sqlite3_parser.cpp" break; case 287: // tableconstraint_list: tableconstraint #line 880 "sqlite3_parser.yy" { yylhs.value.as < TableConstraints > () = yystack_[0].value.as < TableConstraints > (); } #line 3314 "sqlite3_parser.cpp" break; case 288: // tableconstraint_list: tableconstraint_list "," tableconstraint #line 881 "sqlite3_parser.yy" { yylhs.value.as < TableConstraints > () = yystack_[2].value.as < TableConstraints > (); yylhs.value.as < TableConstraints > ().index.insert(yystack_[0].value.as < TableConstraints > ().index.begin(), yystack_[0].value.as < TableConstraints > ().index.end()); yylhs.value.as < TableConstraints > ().fk.insert(yystack_[0].value.as < TableConstraints > ().fk.begin(), yystack_[0].value.as < TableConstraints > ().fk.end()); std::copy(yystack_[0].value.as < TableConstraints > ().check.begin(), yystack_[0].value.as < TableConstraints > ().check.end(), std::back_inserter(yylhs.value.as < TableConstraints > ().check)); } #line 3320 "sqlite3_parser.cpp" break; case 289: // tableconstraint_list: tableconstraint_list tableconstraint #line 882 "sqlite3_parser.yy" { yylhs.value.as < TableConstraints > () = yystack_[1].value.as < TableConstraints > (); yylhs.value.as < TableConstraints > ().index.insert(yystack_[0].value.as < TableConstraints > ().index.begin(), yystack_[0].value.as < TableConstraints > ().index.end()); yylhs.value.as < TableConstraints > ().fk.insert(yystack_[0].value.as < TableConstraints > ().fk.begin(), yystack_[0].value.as < TableConstraints > ().fk.end()); std::copy(yystack_[0].value.as < TableConstraints > ().check.begin(), yystack_[0].value.as < TableConstraints > ().check.end(), std::back_inserter(yylhs.value.as < TableConstraints > ().check)); } #line 3326 "sqlite3_parser.cpp" break; case 290: // optional_tableconstraint_list: %empty #line 886 "sqlite3_parser.yy" { } #line 3332 "sqlite3_parser.cpp" break; case 291: // optional_tableconstraint_list: "," tableconstraint_list #line 887 "sqlite3_parser.yy" { yylhs.value.as < TableConstraints > () = yystack_[0].value.as < TableConstraints > (); } #line 3338 "sqlite3_parser.cpp" break; case 292: // createtable_stmt: "CREATE" optional_temporary "TABLE" optional_if_not_exists tableid_with_uninteresting_schema "AS" select_stmt #line 891 "sqlite3_parser.yy" { yylhs.value.as < sqlb::TablePtr > () = std::make_shared(yystack_[2].value.as < std::string > ()); yylhs.value.as < sqlb::TablePtr > ()->setFullyParsed(false); } #line 3347 "sqlite3_parser.cpp" break; case 293: // createtable_stmt: "CREATE" optional_temporary "TABLE" optional_if_not_exists tableid_with_uninteresting_schema "(" columndef_list optional_tableconstraint_list ")" optional_tableoptions_list #line 895 "sqlite3_parser.yy" { yylhs.value.as < sqlb::TablePtr > () = std::make_shared(yystack_[5].value.as < std::string > ()); yylhs.value.as < sqlb::TablePtr > ()->setWithoutRowidTable(yystack_[0].value.as < std::bitset > ().test(sqlb::Table::WithoutRowid)); yylhs.value.as < sqlb::TablePtr > ()->setStrict(yystack_[0].value.as < std::bitset > ().test(sqlb::Table::Strict)); for(const auto& i : yystack_[2].value.as < TableConstraints > ().index) yylhs.value.as < sqlb::TablePtr > ()->addConstraint(i.first, i.second); for(const auto& i : yystack_[2].value.as < TableConstraints > ().fk) yylhs.value.as < sqlb::TablePtr > ()->addConstraint(i.first, i.second); for(const auto& i : yystack_[2].value.as < TableConstraints > ().check) yylhs.value.as < sqlb::TablePtr > ()->addConstraint(i); yylhs.value.as < sqlb::TablePtr > ()->setFullyParsed(true); for(const auto& f : yystack_[3].value.as < ColumnList > ().first) yylhs.value.as < sqlb::TablePtr > ()->fields.push_back(*f); for(const auto& pk : yystack_[3].value.as < ColumnList > ().second.index) yylhs.value.as < sqlb::TablePtr > ()->addConstraint(pk.first, pk.second); for(const auto& fk : yystack_[3].value.as < ColumnList > ().second.fk) yylhs.value.as < sqlb::TablePtr > ()->addConstraint(fk.first, fk.second); } #line 3371 "sqlite3_parser.cpp" break; #line 3375 "sqlite3_parser.cpp" default: break; } } #if YY_EXCEPTIONS catch (const syntax_error& yyexc) { YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; error (yyexc); YYERROR; } #endif // YY_EXCEPTIONS YY_SYMBOL_PRINT ("-> $$ =", yylhs); yypop_ (yylen); yylen = 0; // Shift the result of the reduction. yypush_ (YY_NULLPTR, YY_MOVE (yylhs)); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: // If not already recovering from an error, report this error. if (!yyerrstatus_) { ++yynerrs_; context yyctx (*this, yyla); std::string msg = yysyntax_error_ (yyctx); error (yyla.location, YY_MOVE (msg)); } yyerror_range[1].location = yyla.location; if (yyerrstatus_ == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ // Return failure if at end of input. if (yyla.kind () == symbol_kind::S_YYEOF) YYABORT; else if (!yyla.empty ()) { yy_destroy_ ("Error: discarding", yyla); yyla.clear (); } } // Else will try to reuse lookahead token after shifting the error token. goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (false) YYERROR; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ yypop_ (yylen); yylen = 0; YY_STACK_PRINT (); goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus_ = 3; // Each real token shifted decrements this. // Pop stack until we find a state that shifts the error token. for (;;) { yyn = yypact_[+yystack_[0].state]; if (!yy_pact_value_is_default_ (yyn)) { yyn += symbol_kind::S_YYerror; if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == symbol_kind::S_YYerror) { yyn = yytable_[yyn]; if (0 < yyn) break; } } // Pop the current state because it cannot handle the error token. if (yystack_.size () == 1) YYABORT; yyerror_range[1].location = yystack_[0].location; yy_destroy_ ("Error: popping", yystack_[0]); yypop_ (); YY_STACK_PRINT (); } { stack_symbol_type error_token; yyerror_range[2].location = yyla.location; YYLLOC_DEFAULT (error_token.location, yyerror_range, 2); // Shift the error token. error_token.state = state_type (yyn); yypush_ ("Shifting", YY_MOVE (error_token)); } goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; /*-----------------------------------------------------. | yyreturn -- parsing is finished, return the result. | `-----------------------------------------------------*/ yyreturn: if (!yyla.empty ()) yy_destroy_ ("Cleanup: discarding lookahead", yyla); /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ yypop_ (yylen); YY_STACK_PRINT (); while (1 < yystack_.size ()) { yy_destroy_ ("Cleanup: popping", yystack_[0]); yypop_ (); } return yyresult; } #if YY_EXCEPTIONS catch (...) { YYCDEBUG << "Exception caught: cleaning lookahead and stack\n"; // Do not try to display the values of the reclaimed symbols, // as their printers might throw an exception. if (!yyla.empty ()) yy_destroy_ (YY_NULLPTR, yyla); while (1 < yystack_.size ()) { yy_destroy_ (YY_NULLPTR, yystack_[0]); yypop_ (); } throw; } #endif // YY_EXCEPTIONS } void parser::error (const syntax_error& yyexc) { error (yyexc.location, yyexc.what ()); } /* Return YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. */ std::string parser::yytnamerr_ (const char *yystr) { if (*yystr == '"') { std::string yyr; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; else goto append; append: default: yyr += *yyp; break; case '"': return yyr; } do_not_strip_quotes: ; } return yystr; } std::string parser::symbol_name (symbol_kind_type yysymbol) { return yytnamerr_ (yytname_[yysymbol]); } // parser::context. parser::context::context (const parser& yyparser, const symbol_type& yyla) : yyparser_ (yyparser) , yyla_ (yyla) {} int parser::context::expected_tokens (symbol_kind_type yyarg[], int yyargn) const { // Actual number of expected tokens int yycount = 0; const int yyn = yypact_[+yyparser_.yystack_[0].state]; if (!yy_pact_value_is_default_ (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ const int yyxbegin = yyn < 0 ? -yyn : 0; // Stay within bounds of both yycheck and yytname. const int yychecklim = yylast_ - yyn + 1; const int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; for (int yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck_[yyx + yyn] == yyx && yyx != symbol_kind::S_YYerror && !yy_table_value_is_error_ (yytable_[yyx + yyn])) { if (!yyarg) ++yycount; else if (yycount == yyargn) return 0; else yyarg[yycount++] = YY_CAST (symbol_kind_type, yyx); } } if (yyarg && yycount == 0 && 0 < yyargn) yyarg[0] = symbol_kind::S_YYEMPTY; return yycount; } int parser::yy_syntax_error_arguments_ (const context& yyctx, symbol_kind_type yyarg[], int yyargn) const { /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yyla) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yyla. (However, yyla is currently not documented for users.) - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (!yyctx.lookahead ().empty ()) { if (yyarg) yyarg[0] = yyctx.token (); int yyn = yyctx.expected_tokens (yyarg ? yyarg + 1 : yyarg, yyargn - 1); return yyn + 1; } return 0; } // Generate an error message. std::string parser::yysyntax_error_ (const context& yyctx) const { // Its maximum. enum { YYARGS_MAX = 5 }; // Arguments of yyformat. symbol_kind_type yyarg[YYARGS_MAX]; int yycount = yy_syntax_error_arguments_ (yyctx, yyarg, YYARGS_MAX); char const* yyformat = YY_NULLPTR; switch (yycount) { #define YYCASE_(N, S) \ case N: \ yyformat = S; \ break default: // Avoid compiler warnings. YYCASE_ (0, YY_("syntax error")); YYCASE_ (1, YY_("syntax error, unexpected %s")); YYCASE_ (2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_ (3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_ (4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_ (5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); #undef YYCASE_ } std::string yyres; // Argument number. std::ptrdiff_t yyi = 0; for (char const* yyp = yyformat; *yyp; ++yyp) if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount) { yyres += symbol_name (yyarg[yyi++]); ++yyp; } else yyres += *yyp; return yyres; } const short parser::yypact_ninf_ = -349; const short parser::yytable_ninf_ = -292; const short parser::yypact_[] = { 11, 145, 123, 106, -349, -349, -349, -349, -349, -349, 51, 67, 58, -349, -349, 117, 117, 117, 86, 2483, 2483, 2483, 130, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, 168, -349, -349, -349, -349, -349, -349, -349, 173, -349, -349, 97, 160, 99, -349, 2574, 2574, -8, 2574, 2392, 129, -349, -349, -349, -349, 242, 247, -349, -349, -349, -349, -349, -349, -349, 2574, -349, 251, -349, -349, 1034, -349, 1736, -349, 1947, -349, -349, 28, 2301, 249, 1736, -349, 1736, 1736, 1736, 1151, 257, -349, -349, -349, -349, 1736, -349, 258, -349, -349, -349, -349, -349, -349, 102, -349, -349, -349, -349, 113, -349, -349, -349, -349, -349, -349, 3480, 3012, -349, 122, 7, -349, -71, -349, 61, -349, -14, -349, 34, -74, 165, -349, -349, -349, 1736, -32, 214, 1736, 3592, 9, 683, -8, -349, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, -8, 1736, 2041, 1268, -349, 1736, 1736, 80, -349, 1736, 1736, -349, -349, -349, 164, 1736, 169, 170, -349, -349, 175, -349, -349, 285, -8, 1853, 262, 222, -349, 232, 2574, 236, 286, 38, 316, 246, 248, 318, 282, -349, -349, 231, -349, -2, -349, -349, 542, 1736, -349, 1736, -30, 3090, 321, 322, 327, 326, -349, 329, 1736, 203, 332, 3480, 151, 151, 126, 126, 202, 126, 202, 296, 179, 179, 254, 254, 254, 254, 179, 179, 202, 202, 3592, 3168, -349, 331, 800, 180, -349, 276, 1385, 179, 387, 514, 1736, 1736, 2135, 1736, 1736, -349, 1736, 3558, 2285, 1736, -349, -349, -349, -349, -349, 7, 1736, -349, 1736, -349, -349, -349, -349, -349, -349, 236, 2, 352, 293, -349, 355, 1736, 356, 357, 1736, -349, -349, -74, -349, 1736, 3246, 2245, 1736, -349, 2574, 245, 250, -349, 253, -349, 252, -349, -8, 1736, 1736, -349, 267, 358, 1736, 2574, 1736, 302, 1736, 1736, 3324, 2719, 917, 272, -349, 2802, 2885, 3664, 1736, 3480, 359, 2685, 2768, -349, 236, 2392, 56, -9, 1736, 2851, 2392, 1736, 277, -349, 3480, -349, 1736, 3402, 361, 364, 366, 368, -349, -349, 179, 179, -349, -349, 291, 370, -349, -349, 1736, 179, 179, 1736, 1736, -349, 294, 371, 1736, 2574, 1736, 1736, 1736, 179, -349, -349, -349, 340, -349, 297, 307, -8, 328, -21, -349, 62, -349, -349, -349, -349, -349, -349, 2934, -349, 301, 112, 236, 3480, -349, -349, -349, -349, -349, -349, 1502, -349, 179, 179, -349, -349, 305, 375, -349, 179, 179, 179, -349, -349, 2392, -18, -349, 310, -3, 35, 37, 311, 334, -349, -58, 295, 236, 379, -349, -349, 306, -349, 1619, -349, -349, -349, 96, -349, 360, -349, -17, -349, 362, -349, 4, -349, 365, -349, 8, 108, 317, -349, -349, -349, 2574, -349, 236, -349, -349, 309, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, -349, 109, 352, -349, -349, -349, -349, 56, -349 }; const short parser::yydefact_[] = { 0, 185, 0, 2, 4, 5, 6, 201, 202, 186, 0, 0, 0, 1, 3, 180, 180, 180, 0, 0, 0, 0, 0, 18, 19, 20, 21, 22, 23, 24, 61, 60, 62, 25, 26, 27, 28, 29, 30, 31, 32, 35, 37, 36, 33, 34, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 54, 56, 57, 58, 16, 64, 17, 63, 59, 191, 0, 0, 0, 181, 0, 0, 0, 0, 0, 0, 55, 63, 190, 189, 196, 0, 67, 66, 68, 69, 71, 70, 65, 216, 238, 290, 179, 292, 0, 199, 0, 76, 78, 217, 240, 243, 243, 0, 0, 197, 0, 0, 0, 0, 23, 14, 13, 15, 12, 0, 10, 43, 11, 7, 8, 9, 163, 161, 166, 162, 167, 168, 173, 0, 169, 174, 175, 176, 177, 178, 124, 182, 193, 0, 0, 77, 0, 239, 221, 238, 0, 287, 243, 208, 0, 82, 81, 83, 0, 0, 0, 0, 84, 0, 0, 0, 198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 131, 0, 0, 183, 184, 192, 187, 0, 0, 0, 75, 74, 0, 245, 244, 0, 0, 0, 0, 0, 226, 0, 0, 210, 0, 243, 0, 0, 0, 0, 243, 289, 204, 0, 205, 209, 293, 170, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 165, 125, 89, 90, 86, 87, 93, 88, 94, 85, 99, 100, 97, 98, 95, 96, 101, 102, 91, 92, 106, 0, 172, 109, 0, 63, 139, 0, 0, 103, 108, 110, 0, 0, 0, 0, 0, 132, 0, 107, 111, 0, 195, 194, 72, 73, 79, 0, 0, 235, 0, 233, 230, 231, 232, 229, 222, 210, 182, 248, 0, 227, 0, 0, 0, 0, 0, 288, 203, 0, 207, 0, 0, 0, 0, 154, 0, 0, 0, 157, 0, 129, 0, 126, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 63, 147, 112, 114, 115, 0, 188, 0, 0, 0, 225, 210, 0, 268, 0, 0, 0, 0, 0, 0, 206, 151, 155, 0, 0, 0, 0, 0, 0, 127, 164, 133, 117, 137, 136, 0, 63, 138, 104, 0, 116, 118, 0, 0, 143, 0, 0, 0, 0, 0, 0, 0, 119, 80, 228, 234, 223, 246, 0, 278, 0, 0, 0, 266, 269, 236, 212, 213, 214, 215, 211, 0, 285, 0, 0, 210, 152, 153, 171, 159, 160, 158, 142, 0, 105, 134, 121, 145, 144, 0, 63, 146, 120, 122, 123, 224, 249, 0, 0, 265, 281, 0, 0, 0, 272, 0, 267, 218, 0, 210, 0, 284, 140, 0, 150, 0, 247, 276, 277, 0, 252, 0, 253, 0, 262, 0, 263, 0, 257, 0, 258, 0, 0, 275, 219, 220, 237, 0, 282, 210, 141, 148, 0, 279, 280, 254, 251, 250, 264, 261, 260, 259, 256, 255, 270, 271, 0, 248, 283, 149, 273, 274, 268, 286 }; const short parser::yypgoto_[] = { -349, -349, -349, 176, -19, -13, -68, -348, 178, 91, -349, 72, -349, -349, -349, -98, -349, -349, -349, -349, 241, -349, -349, 308, -258, 198, 101, -349, -349, 200, 199, -290, -349, -349, -349, -349, -223, -349, -349, -305, -349, -349, -349, -349, 263, 320, -349, -103, 47, -91, 3, -349, -94, -135, -349, -349, -349 }; const short parser::yydefgoto_[] = { 0, 2, 3, 130, 131, 132, 72, 96, 210, 211, 105, 106, 133, 134, 135, 136, 137, 138, 139, 140, 162, 141, 142, 143, 100, 19, 204, 11, 293, 73, 145, 146, 4, 102, 5, 12, 233, 234, 235, 312, 107, 486, 223, 150, 108, 97, 98, 153, 408, 363, 413, 414, 415, 154, 155, 110, 6 }; const short parser::yytable_[] = { 70, 70, 70, 360, 320, 151, 71, 71, 71, 85, 86, 321, 88, 157, 407, 207, 208, 340, 416, 407, 230, 238, 239, 325, 326, 225, 231, 369, 104, 451, 496, 467, -241, 470, -241, 202, 243, 148, -291, 232, 229, 484, -242, 67, -242, 212, 69, 226, 417, 468, 452, 499, 485, 203, 1, 502, 406, 418, 84, 84, 87, 84, 94, 497, 71, 71, 244, 71, 95, 250, 149, 474, 227, 478, 471, 245, 149, 84, 424, 240, 149, 240, 419, 71, 500, 420, 84, 453, 503, 472, 94, 396, 71, 228, 318, 473, 95, 370, 231, 466, 214, 215, 81, 246, 409, 167, 67, 168, 216, 69, 454, 232, 475, 14, 479, 283, 459, 169, 206, 170, 461, 151, 209, 13, 217, 277, 205, 476, 206, 480, 213, 82, 410, 477, 411, 481, 16, 412, 410, 218, 455, 219, 178, 412, 284, 493, 460, 220, 285, 251, 221, 333, 15, 310, 488, 286, 287, 504, 510, 17, 288, 173, 174, 494, 22, 176, 191, 178, 222, 236, 289, 170, 273, 77, 276, 505, 511, 339, 78, 297, 71, 298, 18, 341, 508, 342, 76, 171, 172, 173, 174, 191, 175, 176, 177, 178, 300, 304, 181, 182, 183, 184, 84, 305, 187, 188, 79, 334, 71, 170, 171, 172, 173, 174, 20, 21, 176, 351, 178, 191, 74, 75, 171, 172, 173, 174, 99, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 80, 191, 385, 189, 101, -200, 7, 8, 190, 103, 395, 9, 156, 191, 10, 379, 109, 170, 104, 164, 166, 171, 172, 173, 174, 350, 175, 176, 177, 178, 383, 71, 170, 387, 397, 292, 398, 192, 187, 188, 425, 193, 206, 295, 296, 194, 195, 299, 196, 197, 307, 198, 199, 191, 432, 200, 170, 437, 439, 170, 446, 308, 447, 201, 458, 309, 447, 84, 464, 490, 170, 170, 509, 71, 170, 380, 311, 313, 314, 315, 317, 316, 386, 149, 161, 319, 328, 329, 71, 441, 330, 331, 332, 364, 463, 191, 335, 343, 171, 172, 173, 174, 94, 175, 176, 177, 178, 94, 95, 181, 182, 183, 184, 95, 362, 187, 188, 365, 367, 368, 376, 384, 403, 389, 428, 377, 492, 429, 378, 430, 191, 431, 433, 445, 438, 450, 448, 465, 440, 469, 482, 483, 489, 487, 71, 337, 506, 495, 357, 498, 449, 303, 501, 306, 171, 172, 173, 174, 375, 175, 176, 177, 178, 241, 294, 181, 182, 183, 184, 361, 144, 187, 188, 423, 224, 512, 456, 513, 507, 0, 158, 159, 160, 163, 0, 0, 191, 94, 152, 165, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 237, 0, 0, 242, 0, 71, 0, 0, 0, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 0, 274, 0, 280, 0, 281, 282, 0, 0, 290, 291, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 0, 171, 172, 173, 174, 0, 175, 176, 177, 178, 0, 0, 181, 182, 183, 184, 0, 0, 187, 188, 0, 0, 0, 0, 0, 323, 0, 324, 0, 171, 172, 173, 174, 191, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 346, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 165, 0, 0, 0, 347, 348, 0, 352, 353, 0, 354, 0, 0, 356, 0, 0, 0, 0, 0, 192, 358, 0, 359, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 366, 0, 200, 144, 0, 0, 0, 0, 371, 0, 201, 374, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 381, 382, 322, 0, 0, 0, 0, 388, 0, 390, 391, 0, 0, 0, 0, 0, 0, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 421, 0, 0, 144, 0, 0, 0, 0, 426, 0, 0, 0, 0, 111, 247, 0, 0, 0, 113, 114, 248, 0, 115, 0, 434, 0, 0, 435, 436, 0, 0, 0, 0, 0, 442, 443, 444, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 249, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 122, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 129, 111, 338, 0, 0, 0, 113, 114, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 122, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 99, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 129, 111, 394, 0, 0, 0, 113, 114, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 122, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 99, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 129, 111, 112, 0, 0, 0, 113, 114, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 122, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 129, 111, 0, 0, 0, 0, 113, 114, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 122, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 161, 0, 66, 67, 126, 127, 69, 128, 129, 111, 0, 0, 0, 0, 113, 114, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 278, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 279, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 129, 111, 0, 0, 0, 0, 113, 114, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 344, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 122, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 129, 111, 462, 0, 0, 0, 113, 114, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 122, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 129, 111, 491, 0, 0, 0, 113, 114, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 122, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 129, 111, 0, 0, 0, 0, 113, 114, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 116, 117, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 122, 0, 123, 0, 0, 48, 49, 50, 0, 124, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 129, 301, 0, 0, 0, 0, 207, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 0, 28, 0, 0, 29, 0, 0, 118, 119, 120, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 121, 37, 38, 0, 0, 39, 40, 302, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, 123, 0, 0, 48, 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 59, 147, 0, 60, 61, 0, 83, 63, 0, 125, 64, 0, 0, 0, 65, 0, 0, 66, 67, 126, 127, 69, 128, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 0, 28, 0, 0, 29, 0, 0, 30, 31, 32, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, 0, 0, 0, 48, 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 59, 275, 0, 60, 61, 0, 83, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 66, 67, 0, 68, 69, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 0, 28, 0, 0, 29, 0, 0, 30, 31, 32, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, 0, 0, 0, 48, 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 59, 349, 0, 60, 61, 0, 83, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 66, 67, 0, 68, 69, 0, 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 0, 28, 0, 0, 29, 0, 0, 30, 31, 32, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, 0, 0, 0, 48, 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 66, 67, 0, 68, 69, 171, 172, 173, 174, 0, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 171, 172, 173, 174, 0, 175, 176, 177, 178, 0, 0, 181, 182, 183, 184, 0, 192, 187, 188, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 191, 0, 200, 23, 24, 25, 0, 0, 0, 26, 201, 0, 27, 0, 28, 355, 0, 29, 149, 0, 89, 90, 91, 0, 373, 33, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 38, 0, 0, 39, 40, 92, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, 0, 0, 0, 48, 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 66, 67, 0, 93, 69, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 0, 28, 0, 0, 29, 0, 0, 89, 90, 91, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 38, 0, 0, 39, 40, 92, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, 0, 0, 0, 48, 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 66, 67, 0, 93, 69, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 0, 28, 0, 0, 29, 0, 0, 30, 31, 32, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, 0, 0, 0, 48, 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 66, 67, 0, 68, 69, 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, 0, 28, 0, 0, 29, 0, 0, 30, 31, 32, 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 38, 0, 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, 0, 0, 0, 48, 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 59, 0, 0, 60, 61, 0, 83, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 66, 67, 404, 68, 69, 0, 171, 172, 173, 174, 0, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 171, 172, 173, 174, 0, 175, 176, 177, 178, 0, 0, 181, 182, 183, 184, 0, 0, 187, 188, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 191, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 0, 405, 0, 393, 201, 171, 172, 173, 174, 0, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 171, 172, 173, 174, 0, 175, 176, 177, 178, 0, 0, 181, 182, 183, 184, 0, 0, 187, 188, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 191, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 0, 422, 0, 399, 201, 171, 172, 173, 174, 0, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 171, 172, 173, 174, 0, 175, 176, 177, 178, 0, 0, 181, 182, 183, 184, 0, 0, 187, 188, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 191, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 0, 457, 0, 400, 201, 171, 172, 173, 174, 0, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 171, 172, 173, 174, 201, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 202, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 171, 172, 173, 174, 201, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 327, 0, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 171, 172, 173, 174, 201, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 336, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 171, 172, 173, 174, 201, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 372, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 171, 172, 173, 174, 201, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 392, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 171, 172, 173, 174, 201, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 171, 172, 173, 174, 201, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 0, 0, 200, 0, 0, 0, 171, 172, 173, 174, 201, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 189, 0, 0, 0, 0, 190, 0, 0, 0, 0, 191, 0, 171, 172, 173, 174, 0, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 0, 0, 0, 192, 0, 0, 0, 193, 190, 0, 0, 194, 195, 191, 196, 197, 0, 198, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 193, 0, 0, 0, 194, 195, 0, 196, 197, 0, 198, 199, 171, 172, 173, 174, 0, 175, 176, 177, 178, 0, 201, 181, 182, 183, 184, 0, 0, 187, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 401 }; const short parser::yycheck_[] = { 19, 20, 21, 308, 6, 108, 19, 20, 21, 77, 78, 234, 80, 111, 362, 8, 9, 275, 27, 367, 155, 53, 54, 53, 54, 39, 100, 317, 96, 50, 47, 49, 4, 36, 6, 33, 27, 105, 4, 113, 6, 99, 4, 114, 6, 116, 117, 61, 57, 67, 71, 47, 110, 51, 43, 47, 361, 66, 77, 78, 79, 80, 81, 80, 77, 78, 57, 80, 81, 167, 42, 36, 86, 36, 77, 66, 42, 96, 368, 111, 42, 111, 91, 96, 80, 94, 105, 108, 80, 92, 109, 349, 105, 107, 229, 98, 109, 320, 100, 447, 39, 40, 3, 94, 48, 3, 114, 5, 47, 117, 48, 113, 77, 7, 77, 35, 4, 4, 6, 6, 425, 224, 115, 0, 63, 193, 4, 92, 6, 92, 149, 32, 76, 98, 78, 98, 69, 81, 76, 78, 78, 80, 16, 81, 64, 49, 34, 86, 68, 168, 89, 249, 101, 221, 459, 75, 76, 49, 49, 101, 80, 10, 11, 67, 78, 14, 40, 16, 107, 4, 90, 6, 191, 5, 193, 67, 67, 275, 5, 4, 193, 6, 65, 3, 489, 5, 56, 8, 9, 10, 11, 40, 13, 14, 15, 16, 215, 216, 19, 20, 21, 22, 221, 216, 25, 26, 109, 4, 221, 6, 8, 9, 10, 11, 16, 17, 14, 285, 16, 40, 20, 21, 8, 9, 10, 11, 97, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 81, 40, 341, 30, 3, 101, 102, 103, 35, 3, 349, 107, 4, 40, 110, 4, 6, 6, 327, 3, 3, 8, 9, 10, 11, 285, 13, 14, 15, 16, 4, 285, 6, 342, 3, 112, 5, 64, 25, 26, 4, 68, 6, 115, 115, 72, 73, 3, 75, 76, 29, 78, 79, 40, 4, 82, 6, 4, 397, 6, 4, 80, 6, 90, 4, 74, 6, 327, 4, 4, 6, 6, 4, 327, 6, 335, 81, 32, 3, 74, 3, 74, 342, 42, 111, 95, 6, 6, 342, 398, 4, 6, 4, 41, 433, 40, 5, 62, 8, 9, 10, 11, 362, 13, 14, 15, 16, 367, 362, 19, 20, 21, 22, 367, 3, 25, 26, 3, 3, 3, 116, 4, 4, 62, 4, 116, 465, 4, 116, 4, 40, 4, 3, 34, 4, 48, 70, 3, 398, 70, 70, 48, 4, 89, 398, 55, 70, 28, 298, 28, 410, 216, 28, 216, 8, 9, 10, 11, 327, 13, 14, 15, 16, 163, 206, 19, 20, 21, 22, 309, 103, 25, 26, 367, 152, 507, 414, 512, 487, -1, 113, 114, 115, 116, -1, -1, 40, 447, 109, 122, -1, -1, -1, 447, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 487, 161, -1, -1, 164, -1, 487, -1, -1, -1, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, -1, 192, -1, 194, -1, 196, 197, -1, -1, 200, 201, -1, -1, -1, -1, 206, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, -1, 13, 14, 15, 16, -1, -1, 19, 20, 21, 22, -1, -1, 25, 26, -1, -1, -1, -1, -1, 238, -1, 240, -1, 8, 9, 10, 11, 40, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 55, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, 279, -1, -1, -1, 283, 284, -1, 286, 287, -1, 289, -1, -1, 292, -1, -1, -1, -1, -1, 64, 299, -1, 301, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, 314, -1, 82, 317, -1, -1, -1, -1, 322, -1, 90, 325, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 336, 337, 104, -1, -1, -1, -1, 343, -1, 345, 346, -1, -1, -1, -1, -1, -1, -1, -1, 355, -1, -1, -1, -1, -1, -1, -1, -1, -1, 365, -1, -1, 368, -1, -1, -1, -1, 373, -1, -1, -1, -1, 3, 4, -1, -1, -1, 8, 9, 10, -1, 12, -1, 389, -1, -1, 392, 393, -1, -1, -1, -1, -1, 399, 400, 401, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, 52, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, 119, 3, 4, -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, 119, 3, 4, -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, 119, 3, 4, -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, 119, 3, -1, -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, 111, -1, 113, 114, 115, 116, 117, 118, 119, 3, -1, -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, 52, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, 119, 3, -1, -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, 52, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, 119, 3, 4, -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, 119, 3, 4, -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, 119, 3, -1, -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, 78, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, 119, 3, -1, -1, -1, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, -1, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, -1, -1, 80, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, 3, -1, 99, 100, -1, 102, 103, -1, 105, 106, -1, -1, -1, 110, -1, -1, 113, 114, 115, 116, 117, 118, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, -1, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, -1, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, -1, -1, -1, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, 3, -1, 99, 100, -1, 102, 103, -1, -1, 106, -1, -1, -1, 110, -1, -1, 113, 114, -1, 116, 117, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, -1, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, -1, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, -1, -1, -1, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, 3, -1, 99, 100, -1, 102, 103, -1, -1, 106, -1, -1, -1, 110, -1, -1, 113, 114, -1, 116, 117, -1, -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, -1, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, -1, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, -1, -1, -1, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, -1, 106, -1, -1, -1, 110, -1, -1, 113, 114, -1, 116, 117, 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, -1, 13, 14, 15, 16, -1, -1, 19, 20, 21, 22, -1, 64, 25, 26, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, 40, -1, 82, 27, 28, 29, -1, -1, -1, 33, 90, -1, 36, -1, 38, 55, -1, 41, 42, -1, 44, 45, 46, -1, 104, 49, -1, 51, -1, -1, 54, -1, -1, 57, -1, 59, 60, -1, -1, 63, 64, 65, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, -1, -1, -1, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, -1, 106, -1, -1, -1, 110, -1, -1, 113, 114, -1, 116, 117, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, -1, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, -1, 59, 60, -1, -1, 63, 64, 65, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, -1, -1, -1, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, -1, 106, -1, -1, -1, 110, -1, -1, 113, 114, -1, 116, 117, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, -1, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, -1, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, -1, -1, -1, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, -1, 106, -1, -1, -1, 110, -1, -1, 113, 114, -1, 116, 117, 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, -1, 38, -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, 57, -1, 59, 60, -1, -1, 63, 64, -1, 66, 67, -1, -1, 70, -1, -1, -1, 74, 75, 76, 77, -1, -1, -1, -1, -1, 83, 84, 85, -1, 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, -1, -1, 99, 100, -1, 102, 103, -1, -1, 106, -1, -1, -1, 110, -1, -1, 113, 114, 4, 116, 117, -1, 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, 8, 9, 10, 11, -1, 13, 14, 15, 16, -1, -1, 19, 20, 21, 22, -1, -1, 25, 26, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, 40, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, -1, 4, -1, 55, 90, 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, 8, 9, 10, 11, -1, 13, 14, 15, 16, -1, -1, 19, 20, 21, 22, -1, -1, 25, 26, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, 40, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, -1, 4, -1, 55, 90, 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, 8, 9, 10, 11, -1, 13, 14, 15, 16, -1, -1, 19, 20, 21, 22, -1, -1, 25, 26, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, 40, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, -1, 4, -1, 55, 90, 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, 8, 9, 10, 11, 90, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, 33, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, 8, 9, 10, 11, 90, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, 32, -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, 8, 9, 10, 11, 90, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, 31, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, 8, 9, 10, 11, 90, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, 8, 9, 10, 11, 90, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, 31, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, 8, 9, 10, 11, 90, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, 8, 9, 10, 11, 90, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, -1, -1, 82, -1, -1, -1, 8, 9, 10, 11, 90, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, 64, -1, -1, -1, 68, 35, -1, -1, 72, 73, 40, 75, 76, -1, 78, 79, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, -1, 72, 73, -1, 75, 76, -1, 78, 79, 8, 9, 10, 11, -1, 13, 14, 15, 16, -1, 90, 19, 20, 21, 22, -1, -1, 25, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 55 }; const unsigned char parser::yystos_[] = { 0, 43, 121, 122, 152, 154, 176, 102, 103, 107, 110, 147, 155, 0, 7, 101, 69, 101, 65, 145, 145, 145, 78, 27, 28, 29, 33, 36, 38, 41, 44, 45, 46, 49, 51, 54, 57, 59, 60, 63, 64, 66, 67, 70, 74, 75, 76, 77, 83, 84, 85, 87, 88, 90, 91, 92, 93, 94, 95, 96, 99, 100, 102, 103, 106, 110, 113, 114, 116, 117, 124, 125, 126, 149, 149, 149, 56, 5, 5, 109, 81, 3, 32, 102, 124, 126, 126, 124, 126, 44, 45, 46, 65, 116, 124, 125, 127, 165, 166, 97, 144, 3, 153, 3, 126, 130, 131, 160, 164, 6, 175, 3, 4, 8, 9, 12, 37, 38, 44, 45, 46, 58, 78, 80, 87, 105, 115, 116, 118, 119, 123, 124, 125, 132, 133, 134, 135, 136, 137, 138, 139, 141, 142, 143, 143, 150, 151, 3, 126, 42, 163, 167, 165, 167, 173, 174, 4, 135, 143, 143, 143, 111, 140, 143, 3, 143, 3, 3, 5, 4, 6, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 30, 35, 40, 64, 68, 72, 73, 75, 76, 78, 79, 82, 90, 33, 51, 146, 4, 6, 8, 9, 115, 128, 129, 116, 124, 39, 40, 47, 63, 78, 80, 86, 89, 107, 162, 164, 39, 61, 86, 107, 6, 173, 100, 113, 156, 157, 158, 4, 143, 53, 54, 111, 140, 143, 27, 57, 66, 94, 4, 10, 52, 135, 124, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 124, 143, 3, 124, 126, 52, 78, 143, 143, 143, 35, 64, 68, 75, 76, 80, 90, 143, 143, 112, 148, 150, 115, 115, 4, 6, 3, 124, 3, 65, 123, 124, 125, 128, 29, 80, 74, 126, 81, 159, 32, 3, 74, 74, 3, 173, 95, 6, 156, 104, 143, 143, 53, 54, 32, 6, 6, 4, 6, 4, 135, 4, 5, 31, 55, 4, 135, 144, 3, 5, 62, 52, 55, 55, 143, 143, 3, 124, 126, 143, 143, 143, 55, 143, 129, 143, 143, 159, 146, 3, 169, 41, 3, 143, 3, 3, 151, 156, 143, 54, 104, 143, 131, 116, 116, 116, 4, 124, 143, 143, 4, 4, 135, 124, 126, 143, 62, 143, 143, 31, 55, 4, 135, 144, 3, 5, 55, 55, 55, 143, 4, 4, 4, 159, 127, 168, 48, 76, 78, 81, 170, 171, 172, 27, 57, 66, 91, 94, 143, 4, 168, 151, 4, 143, 54, 4, 4, 4, 4, 4, 3, 143, 143, 143, 4, 4, 135, 124, 126, 143, 143, 143, 34, 4, 6, 70, 124, 48, 50, 71, 108, 48, 78, 170, 4, 4, 4, 34, 159, 4, 135, 4, 3, 127, 49, 67, 70, 36, 77, 92, 98, 36, 77, 92, 98, 36, 77, 92, 98, 70, 48, 99, 110, 161, 89, 159, 4, 4, 4, 135, 49, 67, 28, 47, 80, 28, 47, 80, 28, 47, 80, 49, 67, 70, 126, 159, 4, 49, 67, 169, 172 }; const unsigned char parser::yyr1_[] = { 0, 120, 121, 121, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 123, 123, 124, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 135, 135, 136, 136, 136, 136, 137, 137, 137, 138, 138, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 144, 145, 145, 146, 146, 146, 147, 147, 148, 148, 149, 149, 149, 150, 151, 151, 152, 153, 153, 153, 154, 155, 155, 155, 156, 156, 157, 157, 157, 158, 158, 159, 159, 159, 159, 159, 159, 160, 160, 161, 161, 161, 162, 162, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 164, 164, 165, 166, 166, 167, 167, 167, 168, 168, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 171, 171, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 173, 173, 173, 173, 173, 174, 174, 174, 175, 175, 176, 176 }; const signed char parser::yyr2_[] = { 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 4, 6, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 1, 3, 4, 5, 3, 4, 2, 2, 3, 5, 6, 4, 5, 5, 5, 3, 7, 8, 6, 5, 6, 6, 6, 4, 8, 9, 7, 4, 5, 6, 4, 5, 3, 4, 6, 6, 6, 1, 1, 1, 5, 3, 1, 1, 1, 1, 3, 6, 3, 1, 1, 1, 1, 1, 1, 1, 0, 3, 0, 1, 1, 0, 1, 0, 2, 3, 3, 1, 2, 1, 3, 11, 0, 2, 3, 8, 0, 1, 1, 2, 1, 1, 3, 2, 0, 1, 0, 3, 3, 3, 3, 3, 0, 1, 0, 1, 1, 0, 2, 5, 6, 4, 2, 3, 5, 3, 3, 3, 3, 3, 5, 3, 5, 7, 0, 2, 2, 2, 4, 0, 2, 2, 1, 3, 0, 3, 4, 4, 3, 3, 4, 4, 4, 3, 3, 4, 4, 4, 3, 3, 4, 2, 1, 2, 0, 1, 4, 4, 2, 5, 5, 3, 3, 3, 1, 4, 4, 2, 7, 8, 6, 5, 10, 1, 3, 2, 0, 2, 7, 10 }; #if YYDEBUG || 1 // YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. // First, the terminals, then, starting at \a YYNTOKENS, nonterminals. const char* const parser::yytname_[] = { "\"end of file\"", "error", "\"invalid token\"", "\"(\"", "\")\"", "\".\"", "\",\"", "\";\"", "\"+\"", "\"-\"", "\"*\"", "\"/\"", "\"~\"", "\"&\"", "\"%\"", "\"|\"", "\"||\"", "\"=\"", "\"==\"", "\">\"", "\">=\"", "\"<\"", "\"<=\"", "\"!=\"", "\"<>\"", "\"<<\"", "\">>\"", "\"ABORT\"", "\"ACTION\"", "\"ALWAYS\"", "\"AND\"", "\"AND BETWEEN\"", "\"AS\"", "\"ASC\"", "\"AUTOINCREMENT\"", "\"BETWEEN\"", "\"CASCADE\"", "\"CASE\"", "\"CAST\"", "\"CHECK\"", "\"COLLATE\"", "\"CONFLICT\"", "\"CONSTRAINT\"", "\"CREATE\"", "\"CURRENT_DATE\"", "\"CURRENT_TIME\"", "\"CURRENT_TIMESTAMP\"", "\"DEFAULT\"", "\"DEFERRABLE\"", "\"DEFERRED\"", "\"DELETE\"", "\"DESC\"", "\"DISTINCT\"", "\"ELSE\"", "\"END\"", "\"ESCAPE\"", "\"EXISTS\"", "\"FAIL\"", "\"FALSE\"", "\"FILTER\"", "\"FOLLOWING\"", "\"FOREIGN\"", "\"FROM\"", "\"GENERATED\"", "\"GLOB\"", "\"IF\"", "\"IGNORE\"", "\"IMMEDIATE\"", "\"IN\"", "\"INDEX\"", "\"INITIALLY\"", "\"INSERT\"", "\"IS\"", "\"ISNULL\"", "\"KEY\"", "\"LIKE\"", "\"MATCH\"", "\"NO\"", "\"NOT\"", "\"NOTNULL\"", "\"NULL\"", "\"ON\"", "\"OR\"", "\"OVER\"", "\"PARTITION\"", "\"PRECEDING\"", "\"PRIMARY\"", "\"RAISE\"", "\"RANGE\"", "\"REFERENCES\"", "\"REGEXP\"", "\"REPLACE\"", "\"RESTRICT\"", "\"RETURNING\"", "\"ROLLBACK\"", "\"ROWID\"", "\"ROWS\"", "\"SELECT\"", "\"SET\"", "\"STORED\"", "\"STRICT\"", "\"TABLE\"", "\"TEMP\"", "\"TEMPORARY\"", "\"THEN\"", "\"TRUE\"", "\"UNBOUNDED\"", "\"UNIQUE\"", "\"UPDATE\"", "\"USING\"", "\"VIRTUAL\"", "\"WHEN\"", "\"WHERE\"", "\"WITHOUT\"", "\"identifier\"", "\"numeric\"", "\"string literal\"", "\"quoted literal\"", "\"blob literal\"", "\"bind parameter\"", "$accept", "sql", "statement", "literalvalue", "id", "allowed_keywords_as_identifier", "tableid", "columnid", "signednumber", "signednumber_or_numeric", "typename_namelist", "type_name", "unary_expr", "binary_expr", "like_expr", "exprlist_expr", "function_expr", "isnull_expr", "between_expr", "in_expr", "whenthenlist_expr", "case_expr", "raise_expr", "expr", "select_stmt", "optional_if_not_exists", "optional_sort_order", "optional_unique", "optional_where", "tableid_with_uninteresting_schema", "indexed_column", "indexed_column_list", "createindex_stmt", "optional_exprlist_with_paren", "createvirtualtable_stmt", "optional_temporary", "tableoption", "tableoptions_list", "optional_tableoptions_list", "optional_conflictclause", "optional_typename", "optional_storage_identifier", "optional_always_generated", "columnconstraint", "columnconstraint_list", "columndef", "columndef_list", "optional_constraintname", "columnid_list", "optional_columnid_with_paren_list", "fk_clause_part", "fk_clause_part_list", "optional_fk_clause", "tableconstraint", "tableconstraint_list", "optional_tableconstraint_list", "createtable_stmt", YY_NULLPTR }; #endif #if YYDEBUG const short parser::yyrline_[] = { 0, 273, 273, 274, 278, 279, 280, 288, 289, 290, 291, 292, 293, 294, 295, 296, 300, 301, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 350, 351, 352, 353, 354, 355, 359, 360, 361, 362, 363, 364, 365, 369, 370, 374, 375, 379, 380, 384, 385, 386, 390, 391, 392, 393, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 442, 443, 447, 448, 449, 450, 454, 455, 456, 460, 461, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 484, 485, 489, 490, 491, 492, 496, 497, 498, 499, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 529, 537, 538, 542, 543, 544, 552, 553, 557, 558, 562, 563, 564, 568, 585, 586, 590, 605, 606, 607, 611, 623, 624, 625, 629, 630, 634, 635, 636, 640, 641, 645, 646, 647, 648, 649, 650, 654, 655, 659, 660, 661, 665, 666, 670, 676, 683, 689, 691, 697, 702, 707, 712, 717, 723, 728, 733, 738, 746, 767, 768, 781, 785, 786, 790, 791, 792, 796, 797, 801, 802, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 825, 826, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 847, 853, 860, 867, 872, 880, 881, 882, 886, 887, 891, 895 }; void parser::yy_stack_print_ () const { *yycdebug_ << "Stack now"; for (stack_type::const_iterator i = yystack_.begin (), i_end = yystack_.end (); i != i_end; ++i) *yycdebug_ << ' ' << int (i->state); *yycdebug_ << '\n'; } void parser::yy_reduce_print_ (int yyrule) const { int yylno = yyrline_[yyrule]; int yynrhs = yyr2_[yyrule]; // Print the symbols being reduced, and their result. *yycdebug_ << "Reducing stack by rule " << yyrule - 1 << " (line " << yylno << "):\n"; // The symbols being reduced. for (int yyi = 0; yyi < yynrhs; yyi++) YY_SYMBOL_PRINT (" $" << yyi + 1 << " =", yystack_[(yynrhs) - (yyi + 1)]); } #endif // YYDEBUG #line 10 "sqlite3_parser.yy" } } // sqlb::parser #line 4868 "sqlite3_parser.cpp" #line 916 "sqlite3_parser.yy" void sqlb::parser::parser::error(const location_type& l, const std::string& m) { std::cerr << l << ": " << m << std::endl; } sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/sqlite3_parser.hpp000066400000000000000000004217331463772530400262410ustar00rootroot00000000000000// A Bison parser, made by GNU Bison 3.8.2. // Skeleton interface for Bison LALR(1) parsers in C++ // Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc. // 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 . // As a special exception, you may create a larger work that contains // part or all of the Bison parser skeleton and distribute that work // under terms of your choice, so long as that work isn't itself a // parser generator using the skeleton or a modified version thereof // as a parser skeleton. Alternatively, if you modify or redistribute // the parser skeleton itself, you may (at your option) remove this // special exception, which will cause the skeleton and the resulting // Bison output files to be licensed under the GNU General Public // License without this special exception. // This special exception was added by the Free Software Foundation in // version 2.2 of Bison. /** ** \file sqlite3_parser.hpp ** Define the sqlb::parser ::parser class. */ // C++ LALR(1) parser skeleton written by Akim Demaille. // DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, // especially those whose name start with YY_ or yy_. They are // private implementation details that can be changed or removed. #ifndef YY_YY_SQLITE3_PARSER_HPP_INCLUDED # define YY_YY_SQLITE3_PARSER_HPP_INCLUDED // "%code requires" blocks. #line 12 "sqlite3_parser.yy" #include #include #include "../sqlitetypes.h" #include "../ObjectIdentifier.h" namespace sqlb { namespace parser { class ParserDriver; } } typedef void* yyscan_t; struct TableConstraints { std::multimap> index; std::multimap> fk; std::vector> check; }; using ColumnList = std::pair>, TableConstraints>; #line 67 "sqlite3_parser.hpp" # include # include // std::abort # include # include # include # include #if defined __cplusplus # define YY_CPLUSPLUS __cplusplus #else # define YY_CPLUSPLUS 199711L #endif // Support move semantics when possible. #if 201103L <= YY_CPLUSPLUS # define YY_MOVE std::move # define YY_MOVE_OR_COPY move # define YY_MOVE_REF(Type) Type&& # define YY_RVREF(Type) Type&& # define YY_COPY(Type) Type #else # define YY_MOVE # define YY_MOVE_OR_COPY copy # define YY_MOVE_REF(Type) Type& # define YY_RVREF(Type) const Type& # define YY_COPY(Type) const Type& #endif // Support noexcept when possible. #if 201103L <= YY_CPLUSPLUS # define YY_NOEXCEPT noexcept # define YY_NOTHROW #else # define YY_NOEXCEPT # define YY_NOTHROW throw () #endif // Support constexpr when possible. #if 201703 <= YY_CPLUSPLUS # define YY_CONSTEXPR constexpr #else # define YY_CONSTEXPR #endif # include "sqlite3_location.h" #include #ifndef YY_ASSERT # include # define YY_ASSERT assert #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 1 #endif #line 10 "sqlite3_parser.yy" namespace sqlb { namespace parser { #line 208 "sqlite3_parser.hpp" /// A Bison parser. class parser { public: #ifdef YYSTYPE # ifdef __GNUC__ # pragma GCC message "bison: do not #define YYSTYPE in C++, use %define api.value.type" # endif typedef YYSTYPE value_type; #else /// A buffer to store and retrieve objects. /// /// Sort of a variant, but does not keep track of the nature /// of the stored data, since that knowledge is available /// via the current parser state. class value_type { public: /// Type of *this. typedef value_type self_type; /// Empty construction. value_type () YY_NOEXCEPT : yyraw_ () , yytypeid_ (YY_NULLPTR) {} /// Construct and fill. template value_type (YY_RVREF (T) t) : yytypeid_ (&typeid (T)) { YY_ASSERT (sizeof (T) <= size); new (yyas_ ()) T (YY_MOVE (t)); } #if 201103L <= YY_CPLUSPLUS /// Non copyable. value_type (const self_type&) = delete; /// Non copyable. self_type& operator= (const self_type&) = delete; #endif /// Destruction, allowed only if empty. ~value_type () YY_NOEXCEPT { YY_ASSERT (!yytypeid_); } # if 201103L <= YY_CPLUSPLUS /// Instantiate a \a T in here from \a t. template T& emplace (U&&... u) { YY_ASSERT (!yytypeid_); YY_ASSERT (sizeof (T) <= size); yytypeid_ = & typeid (T); return *new (yyas_ ()) T (std::forward (u)...); } # else /// Instantiate an empty \a T in here. template T& emplace () { YY_ASSERT (!yytypeid_); YY_ASSERT (sizeof (T) <= size); yytypeid_ = & typeid (T); return *new (yyas_ ()) T (); } /// Instantiate a \a T in here from \a t. template T& emplace (const T& t) { YY_ASSERT (!yytypeid_); YY_ASSERT (sizeof (T) <= size); yytypeid_ = & typeid (T); return *new (yyas_ ()) T (t); } # endif /// Instantiate an empty \a T in here. /// Obsolete, use emplace. template T& build () { return emplace (); } /// Instantiate a \a T in here from \a t. /// Obsolete, use emplace. template T& build (const T& t) { return emplace (t); } /// Accessor to a built \a T. template T& as () YY_NOEXCEPT { YY_ASSERT (yytypeid_); YY_ASSERT (*yytypeid_ == typeid (T)); YY_ASSERT (sizeof (T) <= size); return *yyas_ (); } /// Const accessor to a built \a T (for %printer). template const T& as () const YY_NOEXCEPT { YY_ASSERT (yytypeid_); YY_ASSERT (*yytypeid_ == typeid (T)); YY_ASSERT (sizeof (T) <= size); return *yyas_ (); } /// Swap the content with \a that, of same type. /// /// Both variants must be built beforehand, because swapping the actual /// data requires reading it (with as()), and this is not possible on /// unconstructed variants: it would require some dynamic testing, which /// should not be the variant's responsibility. /// Swapping between built and (possibly) non-built is done with /// self_type::move (). template void swap (self_type& that) YY_NOEXCEPT { YY_ASSERT (yytypeid_); YY_ASSERT (*yytypeid_ == *that.yytypeid_); std::swap (as (), that.as ()); } /// Move the content of \a that to this. /// /// Destroys \a that. template void move (self_type& that) { # if 201103L <= YY_CPLUSPLUS emplace (std::move (that.as ())); # else emplace (); swap (that); # endif that.destroy (); } # if 201103L <= YY_CPLUSPLUS /// Move the content of \a that to this. template void move (self_type&& that) { emplace (std::move (that.as ())); that.destroy (); } #endif /// Copy the content of \a that to this. template void copy (const self_type& that) { emplace (that.as ()); } /// Destroy the stored \a T. template void destroy () { as ().~T (); yytypeid_ = YY_NULLPTR; } private: #if YY_CPLUSPLUS < 201103L /// Non copyable. value_type (const self_type&); /// Non copyable. self_type& operator= (const self_type&); #endif /// Accessor to raw memory as \a T. template T* yyas_ () YY_NOEXCEPT { void *yyp = yyraw_; return static_cast (yyp); } /// Const accessor to raw memory as \a T. template const T* yyas_ () const YY_NOEXCEPT { const void *yyp = yyraw_; return static_cast (yyp); } /// An auxiliary type to compute the largest semantic type. union union_type { // columndef_list char dummy1[sizeof (ColumnList)]; // columnconstraint_list // tableconstraint // tableconstraint_list // optional_tableconstraint_list char dummy2[sizeof (TableConstraints)]; // optional_if_not_exists // optional_unique // optional_temporary // optional_always_generated char dummy3[sizeof (bool)]; // createindex_stmt char dummy4[sizeof (sqlb::IndexPtr)]; // indexed_column char dummy5[sizeof (sqlb::IndexedColumn)]; // indexed_column_list char dummy6[sizeof (sqlb::IndexedColumnVector)]; // columnid_list // optional_columnid_with_paren_list char dummy7[sizeof (sqlb::StringVector)]; // createvirtualtable_stmt // createtable_stmt char dummy8[sizeof (sqlb::TablePtr)]; // tableoption // tableoptions_list // optional_tableoptions_list char dummy9[sizeof (std::bitset)]; // columnconstraint char dummy10[sizeof (std::pair, std::shared_ptr>)]; // columndef char dummy11[sizeof (std::shared_ptr)]; // "ABORT" // "ACTION" // "ALWAYS" // "AND" // "AND BETWEEN" // "AS" // "ASC" // "AUTOINCREMENT" // "BETWEEN" // "CASCADE" // "CASE" // "CAST" // "CHECK" // "COLLATE" // "CONFLICT" // "CONSTRAINT" // "CREATE" // "CURRENT_DATE" // "CURRENT_TIME" // "CURRENT_TIMESTAMP" // "DEFAULT" // "DEFERRABLE" // "DEFERRED" // "DELETE" // "DESC" // "DISTINCT" // "ELSE" // "END" // "ESCAPE" // "EXISTS" // "FAIL" // "FALSE" // "FILTER" // "FOLLOWING" // "FOREIGN" // "FROM" // "GENERATED" // "GLOB" // "IF" // "IGNORE" // "IMMEDIATE" // "IN" // "INDEX" // "INITIALLY" // "INSERT" // "IS" // "ISNULL" // "KEY" // "LIKE" // "MATCH" // "NO" // "NOT" // "NOTNULL" // "NULL" // "ON" // "OR" // "OVER" // "PARTITION" // "PRECEDING" // "PRIMARY" // "RAISE" // "RANGE" // "REFERENCES" // "REGEXP" // "REPLACE" // "RESTRICT" // "RETURNING" // "ROLLBACK" // "ROWID" // "ROWS" // "SELECT" // "SET" // "STORED" // "STRICT" // "TABLE" // "TEMP" // "TEMPORARY" // "THEN" // "TRUE" // "UNBOUNDED" // "UNIQUE" // "UPDATE" // "USING" // "VIRTUAL" // "WHEN" // "WHERE" // "WITHOUT" // "identifier" // "numeric" // "string literal" // "quoted literal" // "blob literal" // "bind parameter" // literalvalue // id // allowed_keywords_as_identifier // tableid // columnid // signednumber // signednumber_or_numeric // typename_namelist // type_name // unary_expr // binary_expr // like_expr // exprlist_expr // function_expr // isnull_expr // between_expr // in_expr // whenthenlist_expr // case_expr // raise_expr // expr // select_stmt // optional_sort_order // optional_where // tableid_with_uninteresting_schema // optional_exprlist_with_paren // optional_conflictclause // optional_typename // optional_storage_identifier // optional_constraintname // fk_clause_part // fk_clause_part_list // optional_fk_clause char dummy12[sizeof (std::string)]; }; /// The size of the largest semantic type. enum { size = sizeof (union_type) }; /// A buffer to store semantic values. union { /// Strongest alignment constraints. long double yyalign_me_; /// A buffer large enough to store any of the semantic values. char yyraw_[size]; }; /// Whether the content is built: if defined, the name of the stored type. const std::type_info *yytypeid_; }; #endif /// Backward compatibility (Bison 3.8). typedef value_type semantic_type; /// Symbol locations. typedef location location_type; /// Syntax errors thrown from user actions. struct syntax_error : std::runtime_error { syntax_error (const location_type& l, const std::string& m) : std::runtime_error (m) , location (l) {} syntax_error (const syntax_error& s) : std::runtime_error (s.what ()) , location (s.location) {} ~syntax_error () YY_NOEXCEPT YY_NOTHROW; location_type location; }; /// Token kinds. struct token { enum token_kind_type { TOK_YYEMPTY = -2, TOK_EOF = 0, // "end of file" TOK_YYerror = 256, // error TOK_YYUNDEF = 257, // "invalid token" TOK_LPAREN = 258, // "(" TOK_RPAREN = 259, // ")" TOK_DOT = 260, // "." TOK_COMMA = 261, // "," TOK_SEMI = 262, // ";" TOK_PLUS = 263, // "+" TOK_MINUS = 264, // "-" TOK_STAR = 265, // "*" TOK_SLASH = 266, // "/" TOK_TILDE = 267, // "~" TOK_AMPERSAND = 268, // "&" TOK_PERCENT = 269, // "%" TOK_BITOR = 270, // "|" TOK_OROP = 271, // "||" TOK_EQUAL = 272, // "=" TOK_EQUAL2 = 273, // "==" TOK_GREATER = 274, // ">" TOK_GREATEREQUAL = 275, // ">=" TOK_LOWER = 276, // "<" TOK_LOWEREQUAL = 277, // "<=" TOK_UNEQUAL = 278, // "!=" TOK_UNEQUAL2 = 279, // "<>" TOK_BITWISELEFT = 280, // "<<" TOK_BITWISERIGHT = 281, // ">>" TOK_ABORT = 282, // "ABORT" TOK_ACTION = 283, // "ACTION" TOK_ALWAYS = 284, // "ALWAYS" TOK_AND = 285, // "AND" TOK_AND_BETWEEN = 286, // "AND BETWEEN" TOK_AS = 287, // "AS" TOK_ASC = 288, // "ASC" TOK_AUTOINCREMENT = 289, // "AUTOINCREMENT" TOK_BETWEEN = 290, // "BETWEEN" TOK_CASCADE = 291, // "CASCADE" TOK_CASE = 292, // "CASE" TOK_CAST = 293, // "CAST" TOK_CHECK = 294, // "CHECK" TOK_COLLATE = 295, // "COLLATE" TOK_CONFLICT = 296, // "CONFLICT" TOK_CONSTRAINT = 297, // "CONSTRAINT" TOK_CREATE = 298, // "CREATE" TOK_CURRENT_DATE = 299, // "CURRENT_DATE" TOK_CURRENT_TIME = 300, // "CURRENT_TIME" TOK_CURRENT_TIMESTAMP = 301, // "CURRENT_TIMESTAMP" TOK_DEFAULT = 302, // "DEFAULT" TOK_DEFERRABLE = 303, // "DEFERRABLE" TOK_DEFERRED = 304, // "DEFERRED" TOK_DELETE = 305, // "DELETE" TOK_DESC = 306, // "DESC" TOK_DISTINCT = 307, // "DISTINCT" TOK_ELSE = 308, // "ELSE" TOK_END = 309, // "END" TOK_ESCAPE = 310, // "ESCAPE" TOK_EXISTS = 311, // "EXISTS" TOK_FAIL = 312, // "FAIL" TOK_FALSE = 313, // "FALSE" TOK_FILTER = 314, // "FILTER" TOK_FOLLOWING = 315, // "FOLLOWING" TOK_FOREIGN = 316, // "FOREIGN" TOK_FROM = 317, // "FROM" TOK_GENERATED = 318, // "GENERATED" TOK_GLOB = 319, // "GLOB" TOK_IF = 320, // "IF" TOK_IGNORE = 321, // "IGNORE" TOK_IMMEDIATE = 322, // "IMMEDIATE" TOK_IN = 323, // "IN" TOK_INDEX = 324, // "INDEX" TOK_INITIALLY = 325, // "INITIALLY" TOK_INSERT = 326, // "INSERT" TOK_IS = 327, // "IS" TOK_ISNULL = 328, // "ISNULL" TOK_KEY = 329, // "KEY" TOK_LIKE = 330, // "LIKE" TOK_MATCH = 331, // "MATCH" TOK_NO = 332, // "NO" TOK_NOT = 333, // "NOT" TOK_NOTNULL = 334, // "NOTNULL" TOK_NULL = 335, // "NULL" TOK_ON = 336, // "ON" TOK_OR = 337, // "OR" TOK_OVER = 338, // "OVER" TOK_PARTITION = 339, // "PARTITION" TOK_PRECEDING = 340, // "PRECEDING" TOK_PRIMARY = 341, // "PRIMARY" TOK_RAISE = 342, // "RAISE" TOK_RANGE = 343, // "RANGE" TOK_REFERENCES = 344, // "REFERENCES" TOK_REGEXP = 345, // "REGEXP" TOK_REPLACE = 346, // "REPLACE" TOK_RESTRICT = 347, // "RESTRICT" TOK_RETURNING = 348, // "RETURNING" TOK_ROLLBACK = 349, // "ROLLBACK" TOK_ROWID = 350, // "ROWID" TOK_ROWS = 351, // "ROWS" TOK_SELECT = 352, // "SELECT" TOK_SET = 353, // "SET" TOK_STORED = 354, // "STORED" TOK_STRICT = 355, // "STRICT" TOK_TABLE = 356, // "TABLE" TOK_TEMP = 357, // "TEMP" TOK_TEMPORARY = 358, // "TEMPORARY" TOK_THEN = 359, // "THEN" TOK_TRUE = 360, // "TRUE" TOK_UNBOUNDED = 361, // "UNBOUNDED" TOK_UNIQUE = 362, // "UNIQUE" TOK_UPDATE = 363, // "UPDATE" TOK_USING = 364, // "USING" TOK_VIRTUAL = 365, // "VIRTUAL" TOK_WHEN = 366, // "WHEN" TOK_WHERE = 367, // "WHERE" TOK_WITHOUT = 368, // "WITHOUT" TOK_IDENTIFIER = 369, // "identifier" TOK_NUMERIC = 370, // "numeric" TOK_STRINGLITERAL = 371, // "string literal" TOK_QUOTEDLITERAL = 372, // "quoted literal" TOK_BLOBLITERAL = 373, // "blob literal" TOK_BINDPARAMETER = 374 // "bind parameter" }; /// Backward compatibility alias (Bison 3.6). typedef token_kind_type yytokentype; }; /// Token kind, as returned by yylex. typedef token::token_kind_type token_kind_type; /// Backward compatibility alias (Bison 3.6). typedef token_kind_type token_type; /// Symbol kinds. struct symbol_kind { enum symbol_kind_type { YYNTOKENS = 120, ///< Number of tokens. S_YYEMPTY = -2, S_YYEOF = 0, // "end of file" S_YYerror = 1, // error S_YYUNDEF = 2, // "invalid token" S_LPAREN = 3, // "(" S_RPAREN = 4, // ")" S_DOT = 5, // "." S_COMMA = 6, // "," S_SEMI = 7, // ";" S_PLUS = 8, // "+" S_MINUS = 9, // "-" S_STAR = 10, // "*" S_SLASH = 11, // "/" S_TILDE = 12, // "~" S_AMPERSAND = 13, // "&" S_PERCENT = 14, // "%" S_BITOR = 15, // "|" S_OROP = 16, // "||" S_EQUAL = 17, // "=" S_EQUAL2 = 18, // "==" S_GREATER = 19, // ">" S_GREATEREQUAL = 20, // ">=" S_LOWER = 21, // "<" S_LOWEREQUAL = 22, // "<=" S_UNEQUAL = 23, // "!=" S_UNEQUAL2 = 24, // "<>" S_BITWISELEFT = 25, // "<<" S_BITWISERIGHT = 26, // ">>" S_ABORT = 27, // "ABORT" S_ACTION = 28, // "ACTION" S_ALWAYS = 29, // "ALWAYS" S_AND = 30, // "AND" S_AND_BETWEEN = 31, // "AND BETWEEN" S_AS = 32, // "AS" S_ASC = 33, // "ASC" S_AUTOINCREMENT = 34, // "AUTOINCREMENT" S_BETWEEN = 35, // "BETWEEN" S_CASCADE = 36, // "CASCADE" S_CASE = 37, // "CASE" S_CAST = 38, // "CAST" S_CHECK = 39, // "CHECK" S_COLLATE = 40, // "COLLATE" S_CONFLICT = 41, // "CONFLICT" S_CONSTRAINT = 42, // "CONSTRAINT" S_CREATE = 43, // "CREATE" S_CURRENT_DATE = 44, // "CURRENT_DATE" S_CURRENT_TIME = 45, // "CURRENT_TIME" S_CURRENT_TIMESTAMP = 46, // "CURRENT_TIMESTAMP" S_DEFAULT = 47, // "DEFAULT" S_DEFERRABLE = 48, // "DEFERRABLE" S_DEFERRED = 49, // "DEFERRED" S_DELETE = 50, // "DELETE" S_DESC = 51, // "DESC" S_DISTINCT = 52, // "DISTINCT" S_ELSE = 53, // "ELSE" S_END = 54, // "END" S_ESCAPE = 55, // "ESCAPE" S_EXISTS = 56, // "EXISTS" S_FAIL = 57, // "FAIL" S_FALSE = 58, // "FALSE" S_FILTER = 59, // "FILTER" S_FOLLOWING = 60, // "FOLLOWING" S_FOREIGN = 61, // "FOREIGN" S_FROM = 62, // "FROM" S_GENERATED = 63, // "GENERATED" S_GLOB = 64, // "GLOB" S_IF = 65, // "IF" S_IGNORE = 66, // "IGNORE" S_IMMEDIATE = 67, // "IMMEDIATE" S_IN = 68, // "IN" S_INDEX = 69, // "INDEX" S_INITIALLY = 70, // "INITIALLY" S_INSERT = 71, // "INSERT" S_IS = 72, // "IS" S_ISNULL = 73, // "ISNULL" S_KEY = 74, // "KEY" S_LIKE = 75, // "LIKE" S_MATCH = 76, // "MATCH" S_NO = 77, // "NO" S_NOT = 78, // "NOT" S_NOTNULL = 79, // "NOTNULL" S_NULL = 80, // "NULL" S_ON = 81, // "ON" S_OR = 82, // "OR" S_OVER = 83, // "OVER" S_PARTITION = 84, // "PARTITION" S_PRECEDING = 85, // "PRECEDING" S_PRIMARY = 86, // "PRIMARY" S_RAISE = 87, // "RAISE" S_RANGE = 88, // "RANGE" S_REFERENCES = 89, // "REFERENCES" S_REGEXP = 90, // "REGEXP" S_REPLACE = 91, // "REPLACE" S_RESTRICT = 92, // "RESTRICT" S_RETURNING = 93, // "RETURNING" S_ROLLBACK = 94, // "ROLLBACK" S_ROWID = 95, // "ROWID" S_ROWS = 96, // "ROWS" S_SELECT = 97, // "SELECT" S_SET = 98, // "SET" S_STORED = 99, // "STORED" S_STRICT = 100, // "STRICT" S_TABLE = 101, // "TABLE" S_TEMP = 102, // "TEMP" S_TEMPORARY = 103, // "TEMPORARY" S_THEN = 104, // "THEN" S_TRUE = 105, // "TRUE" S_UNBOUNDED = 106, // "UNBOUNDED" S_UNIQUE = 107, // "UNIQUE" S_UPDATE = 108, // "UPDATE" S_USING = 109, // "USING" S_VIRTUAL = 110, // "VIRTUAL" S_WHEN = 111, // "WHEN" S_WHERE = 112, // "WHERE" S_WITHOUT = 113, // "WITHOUT" S_IDENTIFIER = 114, // "identifier" S_NUMERIC = 115, // "numeric" S_STRINGLITERAL = 116, // "string literal" S_QUOTEDLITERAL = 117, // "quoted literal" S_BLOBLITERAL = 118, // "blob literal" S_BINDPARAMETER = 119, // "bind parameter" S_YYACCEPT = 120, // $accept S_sql = 121, // sql S_statement = 122, // statement S_literalvalue = 123, // literalvalue S_id = 124, // id S_allowed_keywords_as_identifier = 125, // allowed_keywords_as_identifier S_tableid = 126, // tableid S_columnid = 127, // columnid S_signednumber = 128, // signednumber S_signednumber_or_numeric = 129, // signednumber_or_numeric S_typename_namelist = 130, // typename_namelist S_type_name = 131, // type_name S_unary_expr = 132, // unary_expr S_binary_expr = 133, // binary_expr S_like_expr = 134, // like_expr S_exprlist_expr = 135, // exprlist_expr S_function_expr = 136, // function_expr S_isnull_expr = 137, // isnull_expr S_between_expr = 138, // between_expr S_in_expr = 139, // in_expr S_whenthenlist_expr = 140, // whenthenlist_expr S_case_expr = 141, // case_expr S_raise_expr = 142, // raise_expr S_expr = 143, // expr S_select_stmt = 144, // select_stmt S_optional_if_not_exists = 145, // optional_if_not_exists S_optional_sort_order = 146, // optional_sort_order S_optional_unique = 147, // optional_unique S_optional_where = 148, // optional_where S_tableid_with_uninteresting_schema = 149, // tableid_with_uninteresting_schema S_indexed_column = 150, // indexed_column S_indexed_column_list = 151, // indexed_column_list S_createindex_stmt = 152, // createindex_stmt S_optional_exprlist_with_paren = 153, // optional_exprlist_with_paren S_createvirtualtable_stmt = 154, // createvirtualtable_stmt S_optional_temporary = 155, // optional_temporary S_tableoption = 156, // tableoption S_tableoptions_list = 157, // tableoptions_list S_optional_tableoptions_list = 158, // optional_tableoptions_list S_optional_conflictclause = 159, // optional_conflictclause S_optional_typename = 160, // optional_typename S_optional_storage_identifier = 161, // optional_storage_identifier S_optional_always_generated = 162, // optional_always_generated S_columnconstraint = 163, // columnconstraint S_columnconstraint_list = 164, // columnconstraint_list S_columndef = 165, // columndef S_columndef_list = 166, // columndef_list S_optional_constraintname = 167, // optional_constraintname S_columnid_list = 168, // columnid_list S_optional_columnid_with_paren_list = 169, // optional_columnid_with_paren_list S_fk_clause_part = 170, // fk_clause_part S_fk_clause_part_list = 171, // fk_clause_part_list S_optional_fk_clause = 172, // optional_fk_clause S_tableconstraint = 173, // tableconstraint S_tableconstraint_list = 174, // tableconstraint_list S_optional_tableconstraint_list = 175, // optional_tableconstraint_list S_createtable_stmt = 176 // createtable_stmt }; }; /// (Internal) symbol kind. typedef symbol_kind::symbol_kind_type symbol_kind_type; /// The number of tokens. static const symbol_kind_type YYNTOKENS = symbol_kind::YYNTOKENS; /// A complete symbol. /// /// Expects its Base type to provide access to the symbol kind /// via kind (). /// /// Provide access to semantic value and location. template struct basic_symbol : Base { /// Alias to Base. typedef Base super_type; /// Default constructor. basic_symbol () YY_NOEXCEPT : value () , location () {} #if 201103L <= YY_CPLUSPLUS /// Move constructor. basic_symbol (basic_symbol&& that) : Base (std::move (that)) , value () , location (std::move (that.location)) { switch (this->kind ()) { case symbol_kind::S_columndef_list: // columndef_list value.move< ColumnList > (std::move (that.value)); break; case symbol_kind::S_columnconstraint_list: // columnconstraint_list case symbol_kind::S_tableconstraint: // tableconstraint case symbol_kind::S_tableconstraint_list: // tableconstraint_list case symbol_kind::S_optional_tableconstraint_list: // optional_tableconstraint_list value.move< TableConstraints > (std::move (that.value)); break; case symbol_kind::S_optional_if_not_exists: // optional_if_not_exists case symbol_kind::S_optional_unique: // optional_unique case symbol_kind::S_optional_temporary: // optional_temporary case symbol_kind::S_optional_always_generated: // optional_always_generated value.move< bool > (std::move (that.value)); break; case symbol_kind::S_createindex_stmt: // createindex_stmt value.move< sqlb::IndexPtr > (std::move (that.value)); break; case symbol_kind::S_indexed_column: // indexed_column value.move< sqlb::IndexedColumn > (std::move (that.value)); break; case symbol_kind::S_indexed_column_list: // indexed_column_list value.move< sqlb::IndexedColumnVector > (std::move (that.value)); break; case symbol_kind::S_columnid_list: // columnid_list case symbol_kind::S_optional_columnid_with_paren_list: // optional_columnid_with_paren_list value.move< sqlb::StringVector > (std::move (that.value)); break; case symbol_kind::S_createvirtualtable_stmt: // createvirtualtable_stmt case symbol_kind::S_createtable_stmt: // createtable_stmt value.move< sqlb::TablePtr > (std::move (that.value)); break; case symbol_kind::S_tableoption: // tableoption case symbol_kind::S_tableoptions_list: // tableoptions_list case symbol_kind::S_optional_tableoptions_list: // optional_tableoptions_list value.move< std::bitset > (std::move (that.value)); break; case symbol_kind::S_columnconstraint: // columnconstraint value.move< std::pair, std::shared_ptr> > (std::move (that.value)); break; case symbol_kind::S_columndef: // columndef value.move< std::shared_ptr > (std::move (that.value)); break; case symbol_kind::S_ABORT: // "ABORT" case symbol_kind::S_ACTION: // "ACTION" case symbol_kind::S_ALWAYS: // "ALWAYS" case symbol_kind::S_AND: // "AND" case symbol_kind::S_AND_BETWEEN: // "AND BETWEEN" case symbol_kind::S_AS: // "AS" case symbol_kind::S_ASC: // "ASC" case symbol_kind::S_AUTOINCREMENT: // "AUTOINCREMENT" case symbol_kind::S_BETWEEN: // "BETWEEN" case symbol_kind::S_CASCADE: // "CASCADE" case symbol_kind::S_CASE: // "CASE" case symbol_kind::S_CAST: // "CAST" case symbol_kind::S_CHECK: // "CHECK" case symbol_kind::S_COLLATE: // "COLLATE" case symbol_kind::S_CONFLICT: // "CONFLICT" case symbol_kind::S_CONSTRAINT: // "CONSTRAINT" case symbol_kind::S_CREATE: // "CREATE" case symbol_kind::S_CURRENT_DATE: // "CURRENT_DATE" case symbol_kind::S_CURRENT_TIME: // "CURRENT_TIME" case symbol_kind::S_CURRENT_TIMESTAMP: // "CURRENT_TIMESTAMP" case symbol_kind::S_DEFAULT: // "DEFAULT" case symbol_kind::S_DEFERRABLE: // "DEFERRABLE" case symbol_kind::S_DEFERRED: // "DEFERRED" case symbol_kind::S_DELETE: // "DELETE" case symbol_kind::S_DESC: // "DESC" case symbol_kind::S_DISTINCT: // "DISTINCT" case symbol_kind::S_ELSE: // "ELSE" case symbol_kind::S_END: // "END" case symbol_kind::S_ESCAPE: // "ESCAPE" case symbol_kind::S_EXISTS: // "EXISTS" case symbol_kind::S_FAIL: // "FAIL" case symbol_kind::S_FALSE: // "FALSE" case symbol_kind::S_FILTER: // "FILTER" case symbol_kind::S_FOLLOWING: // "FOLLOWING" case symbol_kind::S_FOREIGN: // "FOREIGN" case symbol_kind::S_FROM: // "FROM" case symbol_kind::S_GENERATED: // "GENERATED" case symbol_kind::S_GLOB: // "GLOB" case symbol_kind::S_IF: // "IF" case symbol_kind::S_IGNORE: // "IGNORE" case symbol_kind::S_IMMEDIATE: // "IMMEDIATE" case symbol_kind::S_IN: // "IN" case symbol_kind::S_INDEX: // "INDEX" case symbol_kind::S_INITIALLY: // "INITIALLY" case symbol_kind::S_INSERT: // "INSERT" case symbol_kind::S_IS: // "IS" case symbol_kind::S_ISNULL: // "ISNULL" case symbol_kind::S_KEY: // "KEY" case symbol_kind::S_LIKE: // "LIKE" case symbol_kind::S_MATCH: // "MATCH" case symbol_kind::S_NO: // "NO" case symbol_kind::S_NOT: // "NOT" case symbol_kind::S_NOTNULL: // "NOTNULL" case symbol_kind::S_NULL: // "NULL" case symbol_kind::S_ON: // "ON" case symbol_kind::S_OR: // "OR" case symbol_kind::S_OVER: // "OVER" case symbol_kind::S_PARTITION: // "PARTITION" case symbol_kind::S_PRECEDING: // "PRECEDING" case symbol_kind::S_PRIMARY: // "PRIMARY" case symbol_kind::S_RAISE: // "RAISE" case symbol_kind::S_RANGE: // "RANGE" case symbol_kind::S_REFERENCES: // "REFERENCES" case symbol_kind::S_REGEXP: // "REGEXP" case symbol_kind::S_REPLACE: // "REPLACE" case symbol_kind::S_RESTRICT: // "RESTRICT" case symbol_kind::S_RETURNING: // "RETURNING" case symbol_kind::S_ROLLBACK: // "ROLLBACK" case symbol_kind::S_ROWID: // "ROWID" case symbol_kind::S_ROWS: // "ROWS" case symbol_kind::S_SELECT: // "SELECT" case symbol_kind::S_SET: // "SET" case symbol_kind::S_STORED: // "STORED" case symbol_kind::S_STRICT: // "STRICT" case symbol_kind::S_TABLE: // "TABLE" case symbol_kind::S_TEMP: // "TEMP" case symbol_kind::S_TEMPORARY: // "TEMPORARY" case symbol_kind::S_THEN: // "THEN" case symbol_kind::S_TRUE: // "TRUE" case symbol_kind::S_UNBOUNDED: // "UNBOUNDED" case symbol_kind::S_UNIQUE: // "UNIQUE" case symbol_kind::S_UPDATE: // "UPDATE" case symbol_kind::S_USING: // "USING" case symbol_kind::S_VIRTUAL: // "VIRTUAL" case symbol_kind::S_WHEN: // "WHEN" case symbol_kind::S_WHERE: // "WHERE" case symbol_kind::S_WITHOUT: // "WITHOUT" case symbol_kind::S_IDENTIFIER: // "identifier" case symbol_kind::S_NUMERIC: // "numeric" case symbol_kind::S_STRINGLITERAL: // "string literal" case symbol_kind::S_QUOTEDLITERAL: // "quoted literal" case symbol_kind::S_BLOBLITERAL: // "blob literal" case symbol_kind::S_BINDPARAMETER: // "bind parameter" case symbol_kind::S_literalvalue: // literalvalue case symbol_kind::S_id: // id case symbol_kind::S_allowed_keywords_as_identifier: // allowed_keywords_as_identifier case symbol_kind::S_tableid: // tableid case symbol_kind::S_columnid: // columnid case symbol_kind::S_signednumber: // signednumber case symbol_kind::S_signednumber_or_numeric: // signednumber_or_numeric case symbol_kind::S_typename_namelist: // typename_namelist case symbol_kind::S_type_name: // type_name case symbol_kind::S_unary_expr: // unary_expr case symbol_kind::S_binary_expr: // binary_expr case symbol_kind::S_like_expr: // like_expr case symbol_kind::S_exprlist_expr: // exprlist_expr case symbol_kind::S_function_expr: // function_expr case symbol_kind::S_isnull_expr: // isnull_expr case symbol_kind::S_between_expr: // between_expr case symbol_kind::S_in_expr: // in_expr case symbol_kind::S_whenthenlist_expr: // whenthenlist_expr case symbol_kind::S_case_expr: // case_expr case symbol_kind::S_raise_expr: // raise_expr case symbol_kind::S_expr: // expr case symbol_kind::S_select_stmt: // select_stmt case symbol_kind::S_optional_sort_order: // optional_sort_order case symbol_kind::S_optional_where: // optional_where case symbol_kind::S_tableid_with_uninteresting_schema: // tableid_with_uninteresting_schema case symbol_kind::S_optional_exprlist_with_paren: // optional_exprlist_with_paren case symbol_kind::S_optional_conflictclause: // optional_conflictclause case symbol_kind::S_optional_typename: // optional_typename case symbol_kind::S_optional_storage_identifier: // optional_storage_identifier case symbol_kind::S_optional_constraintname: // optional_constraintname case symbol_kind::S_fk_clause_part: // fk_clause_part case symbol_kind::S_fk_clause_part_list: // fk_clause_part_list case symbol_kind::S_optional_fk_clause: // optional_fk_clause value.move< std::string > (std::move (that.value)); break; default: break; } } #endif /// Copy constructor. basic_symbol (const basic_symbol& that); /// Constructors for typed symbols. #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, location_type&& l) : Base (t) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const location_type& l) : Base (t) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, ColumnList&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const ColumnList& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, TableConstraints&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const TableConstraints& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, bool&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const bool& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, sqlb::IndexPtr&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const sqlb::IndexPtr& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, sqlb::IndexedColumn&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const sqlb::IndexedColumn& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, sqlb::IndexedColumnVector&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const sqlb::IndexedColumnVector& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, sqlb::StringVector&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const sqlb::StringVector& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, sqlb::TablePtr&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const sqlb::TablePtr& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, std::bitset&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const std::bitset& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, std::pair, std::shared_ptr>&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const std::pair, std::shared_ptr>& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, std::shared_ptr&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const std::shared_ptr& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif #if 201103L <= YY_CPLUSPLUS basic_symbol (typename Base::kind_type t, std::string&& v, location_type&& l) : Base (t) , value (std::move (v)) , location (std::move (l)) {} #else basic_symbol (typename Base::kind_type t, const std::string& v, const location_type& l) : Base (t) , value (v) , location (l) {} #endif /// Destroy the symbol. ~basic_symbol () { clear (); } /// Destroy contents, and record that is empty. void clear () YY_NOEXCEPT { // User destructor. symbol_kind_type yykind = this->kind (); basic_symbol& yysym = *this; (void) yysym; switch (yykind) { default: break; } // Value type destructor. switch (yykind) { case symbol_kind::S_columndef_list: // columndef_list value.template destroy< ColumnList > (); break; case symbol_kind::S_columnconstraint_list: // columnconstraint_list case symbol_kind::S_tableconstraint: // tableconstraint case symbol_kind::S_tableconstraint_list: // tableconstraint_list case symbol_kind::S_optional_tableconstraint_list: // optional_tableconstraint_list value.template destroy< TableConstraints > (); break; case symbol_kind::S_optional_if_not_exists: // optional_if_not_exists case symbol_kind::S_optional_unique: // optional_unique case symbol_kind::S_optional_temporary: // optional_temporary case symbol_kind::S_optional_always_generated: // optional_always_generated value.template destroy< bool > (); break; case symbol_kind::S_createindex_stmt: // createindex_stmt value.template destroy< sqlb::IndexPtr > (); break; case symbol_kind::S_indexed_column: // indexed_column value.template destroy< sqlb::IndexedColumn > (); break; case symbol_kind::S_indexed_column_list: // indexed_column_list value.template destroy< sqlb::IndexedColumnVector > (); break; case symbol_kind::S_columnid_list: // columnid_list case symbol_kind::S_optional_columnid_with_paren_list: // optional_columnid_with_paren_list value.template destroy< sqlb::StringVector > (); break; case symbol_kind::S_createvirtualtable_stmt: // createvirtualtable_stmt case symbol_kind::S_createtable_stmt: // createtable_stmt value.template destroy< sqlb::TablePtr > (); break; case symbol_kind::S_tableoption: // tableoption case symbol_kind::S_tableoptions_list: // tableoptions_list case symbol_kind::S_optional_tableoptions_list: // optional_tableoptions_list value.template destroy< std::bitset > (); break; case symbol_kind::S_columnconstraint: // columnconstraint value.template destroy< std::pair, std::shared_ptr> > (); break; case symbol_kind::S_columndef: // columndef value.template destroy< std::shared_ptr > (); break; case symbol_kind::S_ABORT: // "ABORT" case symbol_kind::S_ACTION: // "ACTION" case symbol_kind::S_ALWAYS: // "ALWAYS" case symbol_kind::S_AND: // "AND" case symbol_kind::S_AND_BETWEEN: // "AND BETWEEN" case symbol_kind::S_AS: // "AS" case symbol_kind::S_ASC: // "ASC" case symbol_kind::S_AUTOINCREMENT: // "AUTOINCREMENT" case symbol_kind::S_BETWEEN: // "BETWEEN" case symbol_kind::S_CASCADE: // "CASCADE" case symbol_kind::S_CASE: // "CASE" case symbol_kind::S_CAST: // "CAST" case symbol_kind::S_CHECK: // "CHECK" case symbol_kind::S_COLLATE: // "COLLATE" case symbol_kind::S_CONFLICT: // "CONFLICT" case symbol_kind::S_CONSTRAINT: // "CONSTRAINT" case symbol_kind::S_CREATE: // "CREATE" case symbol_kind::S_CURRENT_DATE: // "CURRENT_DATE" case symbol_kind::S_CURRENT_TIME: // "CURRENT_TIME" case symbol_kind::S_CURRENT_TIMESTAMP: // "CURRENT_TIMESTAMP" case symbol_kind::S_DEFAULT: // "DEFAULT" case symbol_kind::S_DEFERRABLE: // "DEFERRABLE" case symbol_kind::S_DEFERRED: // "DEFERRED" case symbol_kind::S_DELETE: // "DELETE" case symbol_kind::S_DESC: // "DESC" case symbol_kind::S_DISTINCT: // "DISTINCT" case symbol_kind::S_ELSE: // "ELSE" case symbol_kind::S_END: // "END" case symbol_kind::S_ESCAPE: // "ESCAPE" case symbol_kind::S_EXISTS: // "EXISTS" case symbol_kind::S_FAIL: // "FAIL" case symbol_kind::S_FALSE: // "FALSE" case symbol_kind::S_FILTER: // "FILTER" case symbol_kind::S_FOLLOWING: // "FOLLOWING" case symbol_kind::S_FOREIGN: // "FOREIGN" case symbol_kind::S_FROM: // "FROM" case symbol_kind::S_GENERATED: // "GENERATED" case symbol_kind::S_GLOB: // "GLOB" case symbol_kind::S_IF: // "IF" case symbol_kind::S_IGNORE: // "IGNORE" case symbol_kind::S_IMMEDIATE: // "IMMEDIATE" case symbol_kind::S_IN: // "IN" case symbol_kind::S_INDEX: // "INDEX" case symbol_kind::S_INITIALLY: // "INITIALLY" case symbol_kind::S_INSERT: // "INSERT" case symbol_kind::S_IS: // "IS" case symbol_kind::S_ISNULL: // "ISNULL" case symbol_kind::S_KEY: // "KEY" case symbol_kind::S_LIKE: // "LIKE" case symbol_kind::S_MATCH: // "MATCH" case symbol_kind::S_NO: // "NO" case symbol_kind::S_NOT: // "NOT" case symbol_kind::S_NOTNULL: // "NOTNULL" case symbol_kind::S_NULL: // "NULL" case symbol_kind::S_ON: // "ON" case symbol_kind::S_OR: // "OR" case symbol_kind::S_OVER: // "OVER" case symbol_kind::S_PARTITION: // "PARTITION" case symbol_kind::S_PRECEDING: // "PRECEDING" case symbol_kind::S_PRIMARY: // "PRIMARY" case symbol_kind::S_RAISE: // "RAISE" case symbol_kind::S_RANGE: // "RANGE" case symbol_kind::S_REFERENCES: // "REFERENCES" case symbol_kind::S_REGEXP: // "REGEXP" case symbol_kind::S_REPLACE: // "REPLACE" case symbol_kind::S_RESTRICT: // "RESTRICT" case symbol_kind::S_RETURNING: // "RETURNING" case symbol_kind::S_ROLLBACK: // "ROLLBACK" case symbol_kind::S_ROWID: // "ROWID" case symbol_kind::S_ROWS: // "ROWS" case symbol_kind::S_SELECT: // "SELECT" case symbol_kind::S_SET: // "SET" case symbol_kind::S_STORED: // "STORED" case symbol_kind::S_STRICT: // "STRICT" case symbol_kind::S_TABLE: // "TABLE" case symbol_kind::S_TEMP: // "TEMP" case symbol_kind::S_TEMPORARY: // "TEMPORARY" case symbol_kind::S_THEN: // "THEN" case symbol_kind::S_TRUE: // "TRUE" case symbol_kind::S_UNBOUNDED: // "UNBOUNDED" case symbol_kind::S_UNIQUE: // "UNIQUE" case symbol_kind::S_UPDATE: // "UPDATE" case symbol_kind::S_USING: // "USING" case symbol_kind::S_VIRTUAL: // "VIRTUAL" case symbol_kind::S_WHEN: // "WHEN" case symbol_kind::S_WHERE: // "WHERE" case symbol_kind::S_WITHOUT: // "WITHOUT" case symbol_kind::S_IDENTIFIER: // "identifier" case symbol_kind::S_NUMERIC: // "numeric" case symbol_kind::S_STRINGLITERAL: // "string literal" case symbol_kind::S_QUOTEDLITERAL: // "quoted literal" case symbol_kind::S_BLOBLITERAL: // "blob literal" case symbol_kind::S_BINDPARAMETER: // "bind parameter" case symbol_kind::S_literalvalue: // literalvalue case symbol_kind::S_id: // id case symbol_kind::S_allowed_keywords_as_identifier: // allowed_keywords_as_identifier case symbol_kind::S_tableid: // tableid case symbol_kind::S_columnid: // columnid case symbol_kind::S_signednumber: // signednumber case symbol_kind::S_signednumber_or_numeric: // signednumber_or_numeric case symbol_kind::S_typename_namelist: // typename_namelist case symbol_kind::S_type_name: // type_name case symbol_kind::S_unary_expr: // unary_expr case symbol_kind::S_binary_expr: // binary_expr case symbol_kind::S_like_expr: // like_expr case symbol_kind::S_exprlist_expr: // exprlist_expr case symbol_kind::S_function_expr: // function_expr case symbol_kind::S_isnull_expr: // isnull_expr case symbol_kind::S_between_expr: // between_expr case symbol_kind::S_in_expr: // in_expr case symbol_kind::S_whenthenlist_expr: // whenthenlist_expr case symbol_kind::S_case_expr: // case_expr case symbol_kind::S_raise_expr: // raise_expr case symbol_kind::S_expr: // expr case symbol_kind::S_select_stmt: // select_stmt case symbol_kind::S_optional_sort_order: // optional_sort_order case symbol_kind::S_optional_where: // optional_where case symbol_kind::S_tableid_with_uninteresting_schema: // tableid_with_uninteresting_schema case symbol_kind::S_optional_exprlist_with_paren: // optional_exprlist_with_paren case symbol_kind::S_optional_conflictclause: // optional_conflictclause case symbol_kind::S_optional_typename: // optional_typename case symbol_kind::S_optional_storage_identifier: // optional_storage_identifier case symbol_kind::S_optional_constraintname: // optional_constraintname case symbol_kind::S_fk_clause_part: // fk_clause_part case symbol_kind::S_fk_clause_part_list: // fk_clause_part_list case symbol_kind::S_optional_fk_clause: // optional_fk_clause value.template destroy< std::string > (); break; default: break; } Base::clear (); } /// The user-facing name of this symbol. std::string name () const YY_NOEXCEPT { return parser::symbol_name (this->kind ()); } /// Backward compatibility (Bison 3.6). symbol_kind_type type_get () const YY_NOEXCEPT; /// Whether empty. bool empty () const YY_NOEXCEPT; /// Destructive move, \a s is emptied into this. void move (basic_symbol& s); /// The semantic value. value_type value; /// The location. location_type location; private: #if YY_CPLUSPLUS < 201103L /// Assignment operator. basic_symbol& operator= (const basic_symbol& that); #endif }; /// Type access provider for token (enum) based symbols. struct by_kind { /// The symbol kind as needed by the constructor. typedef token_kind_type kind_type; /// Default constructor. by_kind () YY_NOEXCEPT; #if 201103L <= YY_CPLUSPLUS /// Move constructor. by_kind (by_kind&& that) YY_NOEXCEPT; #endif /// Copy constructor. by_kind (const by_kind& that) YY_NOEXCEPT; /// Constructor from (external) token numbers. by_kind (kind_type t) YY_NOEXCEPT; /// Record that this symbol is empty. void clear () YY_NOEXCEPT; /// Steal the symbol kind from \a that. void move (by_kind& that); /// The (internal) type number (corresponding to \a type). /// \a empty when empty. symbol_kind_type kind () const YY_NOEXCEPT; /// Backward compatibility (Bison 3.6). symbol_kind_type type_get () const YY_NOEXCEPT; /// The symbol kind. /// \a S_YYEMPTY when empty. symbol_kind_type kind_; }; /// Backward compatibility for a private implementation detail (Bison 3.6). typedef by_kind by_type; /// "External" symbols: returned by the scanner. struct symbol_type : basic_symbol { /// Superclass. typedef basic_symbol super_type; /// Empty symbol. symbol_type () YY_NOEXCEPT {} /// Constructor for valueless symbols, and symbols from each type. #if 201103L <= YY_CPLUSPLUS symbol_type (int tok, location_type l) : super_type (token_kind_type (tok), std::move (l)) #else symbol_type (int tok, const location_type& l) : super_type (token_kind_type (tok), l) #endif { #if !defined _MSC_VER || defined __clang__ YY_ASSERT (tok == token::TOK_EOF || (token::TOK_YYerror <= tok && tok <= token::TOK_BITWISERIGHT)); #endif } #if 201103L <= YY_CPLUSPLUS symbol_type (int tok, std::string v, location_type l) : super_type (token_kind_type (tok), std::move (v), std::move (l)) #else symbol_type (int tok, const std::string& v, const location_type& l) : super_type (token_kind_type (tok), v, l) #endif { #if !defined _MSC_VER || defined __clang__ YY_ASSERT ((token::TOK_ABORT <= tok && tok <= token::TOK_BINDPARAMETER)); #endif } }; /// Build a parser object. parser (yyscan_t yyscanner_yyarg, ParserDriver& drv_yyarg); virtual ~parser (); #if 201103L <= YY_CPLUSPLUS /// Non copyable. parser (const parser&) = delete; /// Non copyable. parser& operator= (const parser&) = delete; #endif /// Parse. An alias for parse (). /// \returns 0 iff parsing succeeded. int operator() (); /// Parse. /// \returns 0 iff parsing succeeded. virtual int parse (); #if YYDEBUG /// The current debugging stream. std::ostream& debug_stream () const YY_ATTRIBUTE_PURE; /// Set the current debugging stream. void set_debug_stream (std::ostream &); /// Type for debugging levels. typedef int debug_level_type; /// The current debugging level. debug_level_type debug_level () const YY_ATTRIBUTE_PURE; /// Set the current debugging level. void set_debug_level (debug_level_type l); #endif /// Report a syntax error. /// \param loc where the syntax error is found. /// \param msg a description of the syntax error. virtual void error (const location_type& loc, const std::string& msg); /// Report a syntax error. void error (const syntax_error& err); /// The user-facing name of the symbol whose (internal) number is /// YYSYMBOL. No bounds checking. static std::string symbol_name (symbol_kind_type yysymbol); // Implementation of make_symbol for each token kind. #if 201103L <= YY_CPLUSPLUS static symbol_type make_EOF (location_type l) { return symbol_type (token::TOK_EOF, std::move (l)); } #else static symbol_type make_EOF (const location_type& l) { return symbol_type (token::TOK_EOF, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_YYerror (location_type l) { return symbol_type (token::TOK_YYerror, std::move (l)); } #else static symbol_type make_YYerror (const location_type& l) { return symbol_type (token::TOK_YYerror, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_YYUNDEF (location_type l) { return symbol_type (token::TOK_YYUNDEF, std::move (l)); } #else static symbol_type make_YYUNDEF (const location_type& l) { return symbol_type (token::TOK_YYUNDEF, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_LPAREN (location_type l) { return symbol_type (token::TOK_LPAREN, std::move (l)); } #else static symbol_type make_LPAREN (const location_type& l) { return symbol_type (token::TOK_LPAREN, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_RPAREN (location_type l) { return symbol_type (token::TOK_RPAREN, std::move (l)); } #else static symbol_type make_RPAREN (const location_type& l) { return symbol_type (token::TOK_RPAREN, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_DOT (location_type l) { return symbol_type (token::TOK_DOT, std::move (l)); } #else static symbol_type make_DOT (const location_type& l) { return symbol_type (token::TOK_DOT, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_COMMA (location_type l) { return symbol_type (token::TOK_COMMA, std::move (l)); } #else static symbol_type make_COMMA (const location_type& l) { return symbol_type (token::TOK_COMMA, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_SEMI (location_type l) { return symbol_type (token::TOK_SEMI, std::move (l)); } #else static symbol_type make_SEMI (const location_type& l) { return symbol_type (token::TOK_SEMI, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_PLUS (location_type l) { return symbol_type (token::TOK_PLUS, std::move (l)); } #else static symbol_type make_PLUS (const location_type& l) { return symbol_type (token::TOK_PLUS, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_MINUS (location_type l) { return symbol_type (token::TOK_MINUS, std::move (l)); } #else static symbol_type make_MINUS (const location_type& l) { return symbol_type (token::TOK_MINUS, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_STAR (location_type l) { return symbol_type (token::TOK_STAR, std::move (l)); } #else static symbol_type make_STAR (const location_type& l) { return symbol_type (token::TOK_STAR, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_SLASH (location_type l) { return symbol_type (token::TOK_SLASH, std::move (l)); } #else static symbol_type make_SLASH (const location_type& l) { return symbol_type (token::TOK_SLASH, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_TILDE (location_type l) { return symbol_type (token::TOK_TILDE, std::move (l)); } #else static symbol_type make_TILDE (const location_type& l) { return symbol_type (token::TOK_TILDE, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_AMPERSAND (location_type l) { return symbol_type (token::TOK_AMPERSAND, std::move (l)); } #else static symbol_type make_AMPERSAND (const location_type& l) { return symbol_type (token::TOK_AMPERSAND, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_PERCENT (location_type l) { return symbol_type (token::TOK_PERCENT, std::move (l)); } #else static symbol_type make_PERCENT (const location_type& l) { return symbol_type (token::TOK_PERCENT, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_BITOR (location_type l) { return symbol_type (token::TOK_BITOR, std::move (l)); } #else static symbol_type make_BITOR (const location_type& l) { return symbol_type (token::TOK_BITOR, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_OROP (location_type l) { return symbol_type (token::TOK_OROP, std::move (l)); } #else static symbol_type make_OROP (const location_type& l) { return symbol_type (token::TOK_OROP, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_EQUAL (location_type l) { return symbol_type (token::TOK_EQUAL, std::move (l)); } #else static symbol_type make_EQUAL (const location_type& l) { return symbol_type (token::TOK_EQUAL, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_EQUAL2 (location_type l) { return symbol_type (token::TOK_EQUAL2, std::move (l)); } #else static symbol_type make_EQUAL2 (const location_type& l) { return symbol_type (token::TOK_EQUAL2, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_GREATER (location_type l) { return symbol_type (token::TOK_GREATER, std::move (l)); } #else static symbol_type make_GREATER (const location_type& l) { return symbol_type (token::TOK_GREATER, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_GREATEREQUAL (location_type l) { return symbol_type (token::TOK_GREATEREQUAL, std::move (l)); } #else static symbol_type make_GREATEREQUAL (const location_type& l) { return symbol_type (token::TOK_GREATEREQUAL, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_LOWER (location_type l) { return symbol_type (token::TOK_LOWER, std::move (l)); } #else static symbol_type make_LOWER (const location_type& l) { return symbol_type (token::TOK_LOWER, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_LOWEREQUAL (location_type l) { return symbol_type (token::TOK_LOWEREQUAL, std::move (l)); } #else static symbol_type make_LOWEREQUAL (const location_type& l) { return symbol_type (token::TOK_LOWEREQUAL, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_UNEQUAL (location_type l) { return symbol_type (token::TOK_UNEQUAL, std::move (l)); } #else static symbol_type make_UNEQUAL (const location_type& l) { return symbol_type (token::TOK_UNEQUAL, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_UNEQUAL2 (location_type l) { return symbol_type (token::TOK_UNEQUAL2, std::move (l)); } #else static symbol_type make_UNEQUAL2 (const location_type& l) { return symbol_type (token::TOK_UNEQUAL2, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_BITWISELEFT (location_type l) { return symbol_type (token::TOK_BITWISELEFT, std::move (l)); } #else static symbol_type make_BITWISELEFT (const location_type& l) { return symbol_type (token::TOK_BITWISELEFT, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_BITWISERIGHT (location_type l) { return symbol_type (token::TOK_BITWISERIGHT, std::move (l)); } #else static symbol_type make_BITWISERIGHT (const location_type& l) { return symbol_type (token::TOK_BITWISERIGHT, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ABORT (std::string v, location_type l) { return symbol_type (token::TOK_ABORT, std::move (v), std::move (l)); } #else static symbol_type make_ABORT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ABORT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ACTION (std::string v, location_type l) { return symbol_type (token::TOK_ACTION, std::move (v), std::move (l)); } #else static symbol_type make_ACTION (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ACTION, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ALWAYS (std::string v, location_type l) { return symbol_type (token::TOK_ALWAYS, std::move (v), std::move (l)); } #else static symbol_type make_ALWAYS (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ALWAYS, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_AND (std::string v, location_type l) { return symbol_type (token::TOK_AND, std::move (v), std::move (l)); } #else static symbol_type make_AND (const std::string& v, const location_type& l) { return symbol_type (token::TOK_AND, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_AND_BETWEEN (std::string v, location_type l) { return symbol_type (token::TOK_AND_BETWEEN, std::move (v), std::move (l)); } #else static symbol_type make_AND_BETWEEN (const std::string& v, const location_type& l) { return symbol_type (token::TOK_AND_BETWEEN, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_AS (std::string v, location_type l) { return symbol_type (token::TOK_AS, std::move (v), std::move (l)); } #else static symbol_type make_AS (const std::string& v, const location_type& l) { return symbol_type (token::TOK_AS, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ASC (std::string v, location_type l) { return symbol_type (token::TOK_ASC, std::move (v), std::move (l)); } #else static symbol_type make_ASC (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ASC, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_AUTOINCREMENT (std::string v, location_type l) { return symbol_type (token::TOK_AUTOINCREMENT, std::move (v), std::move (l)); } #else static symbol_type make_AUTOINCREMENT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_AUTOINCREMENT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_BETWEEN (std::string v, location_type l) { return symbol_type (token::TOK_BETWEEN, std::move (v), std::move (l)); } #else static symbol_type make_BETWEEN (const std::string& v, const location_type& l) { return symbol_type (token::TOK_BETWEEN, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CASCADE (std::string v, location_type l) { return symbol_type (token::TOK_CASCADE, std::move (v), std::move (l)); } #else static symbol_type make_CASCADE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CASCADE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CASE (std::string v, location_type l) { return symbol_type (token::TOK_CASE, std::move (v), std::move (l)); } #else static symbol_type make_CASE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CASE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CAST (std::string v, location_type l) { return symbol_type (token::TOK_CAST, std::move (v), std::move (l)); } #else static symbol_type make_CAST (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CAST, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CHECK (std::string v, location_type l) { return symbol_type (token::TOK_CHECK, std::move (v), std::move (l)); } #else static symbol_type make_CHECK (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CHECK, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_COLLATE (std::string v, location_type l) { return symbol_type (token::TOK_COLLATE, std::move (v), std::move (l)); } #else static symbol_type make_COLLATE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_COLLATE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CONFLICT (std::string v, location_type l) { return symbol_type (token::TOK_CONFLICT, std::move (v), std::move (l)); } #else static symbol_type make_CONFLICT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CONFLICT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CONSTRAINT (std::string v, location_type l) { return symbol_type (token::TOK_CONSTRAINT, std::move (v), std::move (l)); } #else static symbol_type make_CONSTRAINT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CONSTRAINT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CREATE (std::string v, location_type l) { return symbol_type (token::TOK_CREATE, std::move (v), std::move (l)); } #else static symbol_type make_CREATE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CREATE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CURRENT_DATE (std::string v, location_type l) { return symbol_type (token::TOK_CURRENT_DATE, std::move (v), std::move (l)); } #else static symbol_type make_CURRENT_DATE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CURRENT_DATE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CURRENT_TIME (std::string v, location_type l) { return symbol_type (token::TOK_CURRENT_TIME, std::move (v), std::move (l)); } #else static symbol_type make_CURRENT_TIME (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CURRENT_TIME, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_CURRENT_TIMESTAMP (std::string v, location_type l) { return symbol_type (token::TOK_CURRENT_TIMESTAMP, std::move (v), std::move (l)); } #else static symbol_type make_CURRENT_TIMESTAMP (const std::string& v, const location_type& l) { return symbol_type (token::TOK_CURRENT_TIMESTAMP, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_DEFAULT (std::string v, location_type l) { return symbol_type (token::TOK_DEFAULT, std::move (v), std::move (l)); } #else static symbol_type make_DEFAULT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_DEFAULT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_DEFERRABLE (std::string v, location_type l) { return symbol_type (token::TOK_DEFERRABLE, std::move (v), std::move (l)); } #else static symbol_type make_DEFERRABLE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_DEFERRABLE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_DEFERRED (std::string v, location_type l) { return symbol_type (token::TOK_DEFERRED, std::move (v), std::move (l)); } #else static symbol_type make_DEFERRED (const std::string& v, const location_type& l) { return symbol_type (token::TOK_DEFERRED, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_DELETE (std::string v, location_type l) { return symbol_type (token::TOK_DELETE, std::move (v), std::move (l)); } #else static symbol_type make_DELETE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_DELETE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_DESC (std::string v, location_type l) { return symbol_type (token::TOK_DESC, std::move (v), std::move (l)); } #else static symbol_type make_DESC (const std::string& v, const location_type& l) { return symbol_type (token::TOK_DESC, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_DISTINCT (std::string v, location_type l) { return symbol_type (token::TOK_DISTINCT, std::move (v), std::move (l)); } #else static symbol_type make_DISTINCT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_DISTINCT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ELSE (std::string v, location_type l) { return symbol_type (token::TOK_ELSE, std::move (v), std::move (l)); } #else static symbol_type make_ELSE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ELSE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_END (std::string v, location_type l) { return symbol_type (token::TOK_END, std::move (v), std::move (l)); } #else static symbol_type make_END (const std::string& v, const location_type& l) { return symbol_type (token::TOK_END, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ESCAPE (std::string v, location_type l) { return symbol_type (token::TOK_ESCAPE, std::move (v), std::move (l)); } #else static symbol_type make_ESCAPE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ESCAPE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_EXISTS (std::string v, location_type l) { return symbol_type (token::TOK_EXISTS, std::move (v), std::move (l)); } #else static symbol_type make_EXISTS (const std::string& v, const location_type& l) { return symbol_type (token::TOK_EXISTS, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_FAIL (std::string v, location_type l) { return symbol_type (token::TOK_FAIL, std::move (v), std::move (l)); } #else static symbol_type make_FAIL (const std::string& v, const location_type& l) { return symbol_type (token::TOK_FAIL, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_FALSE (std::string v, location_type l) { return symbol_type (token::TOK_FALSE, std::move (v), std::move (l)); } #else static symbol_type make_FALSE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_FALSE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_FILTER (std::string v, location_type l) { return symbol_type (token::TOK_FILTER, std::move (v), std::move (l)); } #else static symbol_type make_FILTER (const std::string& v, const location_type& l) { return symbol_type (token::TOK_FILTER, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_FOLLOWING (std::string v, location_type l) { return symbol_type (token::TOK_FOLLOWING, std::move (v), std::move (l)); } #else static symbol_type make_FOLLOWING (const std::string& v, const location_type& l) { return symbol_type (token::TOK_FOLLOWING, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_FOREIGN (std::string v, location_type l) { return symbol_type (token::TOK_FOREIGN, std::move (v), std::move (l)); } #else static symbol_type make_FOREIGN (const std::string& v, const location_type& l) { return symbol_type (token::TOK_FOREIGN, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_FROM (std::string v, location_type l) { return symbol_type (token::TOK_FROM, std::move (v), std::move (l)); } #else static symbol_type make_FROM (const std::string& v, const location_type& l) { return symbol_type (token::TOK_FROM, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_GENERATED (std::string v, location_type l) { return symbol_type (token::TOK_GENERATED, std::move (v), std::move (l)); } #else static symbol_type make_GENERATED (const std::string& v, const location_type& l) { return symbol_type (token::TOK_GENERATED, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_GLOB (std::string v, location_type l) { return symbol_type (token::TOK_GLOB, std::move (v), std::move (l)); } #else static symbol_type make_GLOB (const std::string& v, const location_type& l) { return symbol_type (token::TOK_GLOB, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_IF (std::string v, location_type l) { return symbol_type (token::TOK_IF, std::move (v), std::move (l)); } #else static symbol_type make_IF (const std::string& v, const location_type& l) { return symbol_type (token::TOK_IF, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_IGNORE (std::string v, location_type l) { return symbol_type (token::TOK_IGNORE, std::move (v), std::move (l)); } #else static symbol_type make_IGNORE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_IGNORE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_IMMEDIATE (std::string v, location_type l) { return symbol_type (token::TOK_IMMEDIATE, std::move (v), std::move (l)); } #else static symbol_type make_IMMEDIATE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_IMMEDIATE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_IN (std::string v, location_type l) { return symbol_type (token::TOK_IN, std::move (v), std::move (l)); } #else static symbol_type make_IN (const std::string& v, const location_type& l) { return symbol_type (token::TOK_IN, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_INDEX (std::string v, location_type l) { return symbol_type (token::TOK_INDEX, std::move (v), std::move (l)); } #else static symbol_type make_INDEX (const std::string& v, const location_type& l) { return symbol_type (token::TOK_INDEX, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_INITIALLY (std::string v, location_type l) { return symbol_type (token::TOK_INITIALLY, std::move (v), std::move (l)); } #else static symbol_type make_INITIALLY (const std::string& v, const location_type& l) { return symbol_type (token::TOK_INITIALLY, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_INSERT (std::string v, location_type l) { return symbol_type (token::TOK_INSERT, std::move (v), std::move (l)); } #else static symbol_type make_INSERT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_INSERT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_IS (std::string v, location_type l) { return symbol_type (token::TOK_IS, std::move (v), std::move (l)); } #else static symbol_type make_IS (const std::string& v, const location_type& l) { return symbol_type (token::TOK_IS, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ISNULL (std::string v, location_type l) { return symbol_type (token::TOK_ISNULL, std::move (v), std::move (l)); } #else static symbol_type make_ISNULL (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ISNULL, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_KEY (std::string v, location_type l) { return symbol_type (token::TOK_KEY, std::move (v), std::move (l)); } #else static symbol_type make_KEY (const std::string& v, const location_type& l) { return symbol_type (token::TOK_KEY, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_LIKE (std::string v, location_type l) { return symbol_type (token::TOK_LIKE, std::move (v), std::move (l)); } #else static symbol_type make_LIKE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_LIKE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_MATCH (std::string v, location_type l) { return symbol_type (token::TOK_MATCH, std::move (v), std::move (l)); } #else static symbol_type make_MATCH (const std::string& v, const location_type& l) { return symbol_type (token::TOK_MATCH, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_NO (std::string v, location_type l) { return symbol_type (token::TOK_NO, std::move (v), std::move (l)); } #else static symbol_type make_NO (const std::string& v, const location_type& l) { return symbol_type (token::TOK_NO, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_NOT (std::string v, location_type l) { return symbol_type (token::TOK_NOT, std::move (v), std::move (l)); } #else static symbol_type make_NOT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_NOT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_NOTNULL (std::string v, location_type l) { return symbol_type (token::TOK_NOTNULL, std::move (v), std::move (l)); } #else static symbol_type make_NOTNULL (const std::string& v, const location_type& l) { return symbol_type (token::TOK_NOTNULL, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_NULL (std::string v, location_type l) { return symbol_type (token::TOK_NULL, std::move (v), std::move (l)); } #else static symbol_type make_NULL (const std::string& v, const location_type& l) { return symbol_type (token::TOK_NULL, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ON (std::string v, location_type l) { return symbol_type (token::TOK_ON, std::move (v), std::move (l)); } #else static symbol_type make_ON (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ON, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_OR (std::string v, location_type l) { return symbol_type (token::TOK_OR, std::move (v), std::move (l)); } #else static symbol_type make_OR (const std::string& v, const location_type& l) { return symbol_type (token::TOK_OR, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_OVER (std::string v, location_type l) { return symbol_type (token::TOK_OVER, std::move (v), std::move (l)); } #else static symbol_type make_OVER (const std::string& v, const location_type& l) { return symbol_type (token::TOK_OVER, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_PARTITION (std::string v, location_type l) { return symbol_type (token::TOK_PARTITION, std::move (v), std::move (l)); } #else static symbol_type make_PARTITION (const std::string& v, const location_type& l) { return symbol_type (token::TOK_PARTITION, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_PRECEDING (std::string v, location_type l) { return symbol_type (token::TOK_PRECEDING, std::move (v), std::move (l)); } #else static symbol_type make_PRECEDING (const std::string& v, const location_type& l) { return symbol_type (token::TOK_PRECEDING, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_PRIMARY (std::string v, location_type l) { return symbol_type (token::TOK_PRIMARY, std::move (v), std::move (l)); } #else static symbol_type make_PRIMARY (const std::string& v, const location_type& l) { return symbol_type (token::TOK_PRIMARY, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_RAISE (std::string v, location_type l) { return symbol_type (token::TOK_RAISE, std::move (v), std::move (l)); } #else static symbol_type make_RAISE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_RAISE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_RANGE (std::string v, location_type l) { return symbol_type (token::TOK_RANGE, std::move (v), std::move (l)); } #else static symbol_type make_RANGE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_RANGE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_REFERENCES (std::string v, location_type l) { return symbol_type (token::TOK_REFERENCES, std::move (v), std::move (l)); } #else static symbol_type make_REFERENCES (const std::string& v, const location_type& l) { return symbol_type (token::TOK_REFERENCES, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_REGEXP (std::string v, location_type l) { return symbol_type (token::TOK_REGEXP, std::move (v), std::move (l)); } #else static symbol_type make_REGEXP (const std::string& v, const location_type& l) { return symbol_type (token::TOK_REGEXP, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_REPLACE (std::string v, location_type l) { return symbol_type (token::TOK_REPLACE, std::move (v), std::move (l)); } #else static symbol_type make_REPLACE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_REPLACE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_RESTRICT (std::string v, location_type l) { return symbol_type (token::TOK_RESTRICT, std::move (v), std::move (l)); } #else static symbol_type make_RESTRICT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_RESTRICT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_RETURNING (std::string v, location_type l) { return symbol_type (token::TOK_RETURNING, std::move (v), std::move (l)); } #else static symbol_type make_RETURNING (const std::string& v, const location_type& l) { return symbol_type (token::TOK_RETURNING, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ROLLBACK (std::string v, location_type l) { return symbol_type (token::TOK_ROLLBACK, std::move (v), std::move (l)); } #else static symbol_type make_ROLLBACK (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ROLLBACK, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ROWID (std::string v, location_type l) { return symbol_type (token::TOK_ROWID, std::move (v), std::move (l)); } #else static symbol_type make_ROWID (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ROWID, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_ROWS (std::string v, location_type l) { return symbol_type (token::TOK_ROWS, std::move (v), std::move (l)); } #else static symbol_type make_ROWS (const std::string& v, const location_type& l) { return symbol_type (token::TOK_ROWS, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_SELECT (std::string v, location_type l) { return symbol_type (token::TOK_SELECT, std::move (v), std::move (l)); } #else static symbol_type make_SELECT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_SELECT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_SET (std::string v, location_type l) { return symbol_type (token::TOK_SET, std::move (v), std::move (l)); } #else static symbol_type make_SET (const std::string& v, const location_type& l) { return symbol_type (token::TOK_SET, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_STORED (std::string v, location_type l) { return symbol_type (token::TOK_STORED, std::move (v), std::move (l)); } #else static symbol_type make_STORED (const std::string& v, const location_type& l) { return symbol_type (token::TOK_STORED, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_STRICT (std::string v, location_type l) { return symbol_type (token::TOK_STRICT, std::move (v), std::move (l)); } #else static symbol_type make_STRICT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_STRICT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_TABLE (std::string v, location_type l) { return symbol_type (token::TOK_TABLE, std::move (v), std::move (l)); } #else static symbol_type make_TABLE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_TABLE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_TEMP (std::string v, location_type l) { return symbol_type (token::TOK_TEMP, std::move (v), std::move (l)); } #else static symbol_type make_TEMP (const std::string& v, const location_type& l) { return symbol_type (token::TOK_TEMP, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_TEMPORARY (std::string v, location_type l) { return symbol_type (token::TOK_TEMPORARY, std::move (v), std::move (l)); } #else static symbol_type make_TEMPORARY (const std::string& v, const location_type& l) { return symbol_type (token::TOK_TEMPORARY, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_THEN (std::string v, location_type l) { return symbol_type (token::TOK_THEN, std::move (v), std::move (l)); } #else static symbol_type make_THEN (const std::string& v, const location_type& l) { return symbol_type (token::TOK_THEN, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_TRUE (std::string v, location_type l) { return symbol_type (token::TOK_TRUE, std::move (v), std::move (l)); } #else static symbol_type make_TRUE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_TRUE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_UNBOUNDED (std::string v, location_type l) { return symbol_type (token::TOK_UNBOUNDED, std::move (v), std::move (l)); } #else static symbol_type make_UNBOUNDED (const std::string& v, const location_type& l) { return symbol_type (token::TOK_UNBOUNDED, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_UNIQUE (std::string v, location_type l) { return symbol_type (token::TOK_UNIQUE, std::move (v), std::move (l)); } #else static symbol_type make_UNIQUE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_UNIQUE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_UPDATE (std::string v, location_type l) { return symbol_type (token::TOK_UPDATE, std::move (v), std::move (l)); } #else static symbol_type make_UPDATE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_UPDATE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_USING (std::string v, location_type l) { return symbol_type (token::TOK_USING, std::move (v), std::move (l)); } #else static symbol_type make_USING (const std::string& v, const location_type& l) { return symbol_type (token::TOK_USING, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_VIRTUAL (std::string v, location_type l) { return symbol_type (token::TOK_VIRTUAL, std::move (v), std::move (l)); } #else static symbol_type make_VIRTUAL (const std::string& v, const location_type& l) { return symbol_type (token::TOK_VIRTUAL, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_WHEN (std::string v, location_type l) { return symbol_type (token::TOK_WHEN, std::move (v), std::move (l)); } #else static symbol_type make_WHEN (const std::string& v, const location_type& l) { return symbol_type (token::TOK_WHEN, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_WHERE (std::string v, location_type l) { return symbol_type (token::TOK_WHERE, std::move (v), std::move (l)); } #else static symbol_type make_WHERE (const std::string& v, const location_type& l) { return symbol_type (token::TOK_WHERE, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_WITHOUT (std::string v, location_type l) { return symbol_type (token::TOK_WITHOUT, std::move (v), std::move (l)); } #else static symbol_type make_WITHOUT (const std::string& v, const location_type& l) { return symbol_type (token::TOK_WITHOUT, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_IDENTIFIER (std::string v, location_type l) { return symbol_type (token::TOK_IDENTIFIER, std::move (v), std::move (l)); } #else static symbol_type make_IDENTIFIER (const std::string& v, const location_type& l) { return symbol_type (token::TOK_IDENTIFIER, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_NUMERIC (std::string v, location_type l) { return symbol_type (token::TOK_NUMERIC, std::move (v), std::move (l)); } #else static symbol_type make_NUMERIC (const std::string& v, const location_type& l) { return symbol_type (token::TOK_NUMERIC, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_STRINGLITERAL (std::string v, location_type l) { return symbol_type (token::TOK_STRINGLITERAL, std::move (v), std::move (l)); } #else static symbol_type make_STRINGLITERAL (const std::string& v, const location_type& l) { return symbol_type (token::TOK_STRINGLITERAL, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_QUOTEDLITERAL (std::string v, location_type l) { return symbol_type (token::TOK_QUOTEDLITERAL, std::move (v), std::move (l)); } #else static symbol_type make_QUOTEDLITERAL (const std::string& v, const location_type& l) { return symbol_type (token::TOK_QUOTEDLITERAL, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_BLOBLITERAL (std::string v, location_type l) { return symbol_type (token::TOK_BLOBLITERAL, std::move (v), std::move (l)); } #else static symbol_type make_BLOBLITERAL (const std::string& v, const location_type& l) { return symbol_type (token::TOK_BLOBLITERAL, v, l); } #endif #if 201103L <= YY_CPLUSPLUS static symbol_type make_BINDPARAMETER (std::string v, location_type l) { return symbol_type (token::TOK_BINDPARAMETER, std::move (v), std::move (l)); } #else static symbol_type make_BINDPARAMETER (const std::string& v, const location_type& l) { return symbol_type (token::TOK_BINDPARAMETER, v, l); } #endif class context { public: context (const parser& yyparser, const symbol_type& yyla); const symbol_type& lookahead () const YY_NOEXCEPT { return yyla_; } symbol_kind_type token () const YY_NOEXCEPT { return yyla_.kind (); } const location_type& location () const YY_NOEXCEPT { return yyla_.location; } /// Put in YYARG at most YYARGN of the expected tokens, and return the /// number of tokens stored in YYARG. If YYARG is null, return the /// number of expected tokens (guaranteed to be less than YYNTOKENS). int expected_tokens (symbol_kind_type yyarg[], int yyargn) const; private: const parser& yyparser_; const symbol_type& yyla_; }; private: #if YY_CPLUSPLUS < 201103L /// Non copyable. parser (const parser&); /// Non copyable. parser& operator= (const parser&); #endif /// Stored state numbers (used for stacks). typedef short state_type; /// The arguments of the error message. int yy_syntax_error_arguments_ (const context& yyctx, symbol_kind_type yyarg[], int yyargn) const; /// Generate an error message. /// \param yyctx the context in which the error occurred. virtual std::string yysyntax_error_ (const context& yyctx) const; /// Compute post-reduction state. /// \param yystate the current state /// \param yysym the nonterminal to push on the stack static state_type yy_lr_goto_state_ (state_type yystate, int yysym); /// Whether the given \c yypact_ value indicates a defaulted state. /// \param yyvalue the value to check static bool yy_pact_value_is_default_ (int yyvalue) YY_NOEXCEPT; /// Whether the given \c yytable_ value indicates a syntax error. /// \param yyvalue the value to check static bool yy_table_value_is_error_ (int yyvalue) YY_NOEXCEPT; static const short yypact_ninf_; static const short yytable_ninf_; /// Convert a scanner token kind \a t to a symbol kind. /// In theory \a t should be a token_kind_type, but character literals /// are valid, yet not members of the token_kind_type enum. static symbol_kind_type yytranslate_ (int t) YY_NOEXCEPT; /// Convert the symbol name \a n to a form suitable for a diagnostic. static std::string yytnamerr_ (const char *yystr); /// For a symbol, its name in clear. static const char* const yytname_[]; // Tables. // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing // STATE-NUM. static const short yypact_[]; // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. // Performed when YYTABLE does not specify something else to do. Zero // means the default is an error. static const short yydefact_[]; // YYPGOTO[NTERM-NUM]. static const short yypgoto_[]; // YYDEFGOTO[NTERM-NUM]. static const short yydefgoto_[]; // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If // positive, shift that token. If negative, reduce the rule whose // number is the opposite. If YYTABLE_NINF, syntax error. static const short yytable_[]; static const short yycheck_[]; // YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of // state STATE-NUM. static const unsigned char yystos_[]; // YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. static const unsigned char yyr1_[]; // YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. static const signed char yyr2_[]; #if YYDEBUG // YYRLINE[YYN] -- Source line where rule number YYN was defined. static const short yyrline_[]; /// Report on the debug stream that the rule \a r is going to be reduced. virtual void yy_reduce_print_ (int r) const; /// Print the state stack on the debug stream. virtual void yy_stack_print_ () const; /// Debugging level. int yydebug_; /// Debug stream. std::ostream* yycdebug_; /// \brief Display a symbol kind, value and location. /// \param yyo The output stream. /// \param yysym The symbol. template void yy_print_ (std::ostream& yyo, const basic_symbol& yysym) const; #endif /// \brief Reclaim the memory associated to a symbol. /// \param yymsg Why this token is reclaimed. /// If null, print nothing. /// \param yysym The symbol. template void yy_destroy_ (const char* yymsg, basic_symbol& yysym) const; private: /// Type access provider for state based symbols. struct by_state { /// Default constructor. by_state () YY_NOEXCEPT; /// The symbol kind as needed by the constructor. typedef state_type kind_type; /// Constructor. by_state (kind_type s) YY_NOEXCEPT; /// Copy constructor. by_state (const by_state& that) YY_NOEXCEPT; /// Record that this symbol is empty. void clear () YY_NOEXCEPT; /// Steal the symbol kind from \a that. void move (by_state& that); /// The symbol kind (corresponding to \a state). /// \a symbol_kind::S_YYEMPTY when empty. symbol_kind_type kind () const YY_NOEXCEPT; /// The state number used to denote an empty symbol. /// We use the initial state, as it does not have a value. enum { empty_state = 0 }; /// The state. /// \a empty when empty. state_type state; }; /// "Internal" symbol: element of the stack. struct stack_symbol_type : basic_symbol { /// Superclass. typedef basic_symbol super_type; /// Construct an empty symbol. stack_symbol_type (); /// Move or copy construction. stack_symbol_type (YY_RVREF (stack_symbol_type) that); /// Steal the contents from \a sym to build this. stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) sym); #if YY_CPLUSPLUS < 201103L /// Assignment, needed by push_back by some old implementations. /// Moves the contents of that. stack_symbol_type& operator= (stack_symbol_type& that); /// Assignment, needed by push_back by other implementations. /// Needed by some other old implementations. stack_symbol_type& operator= (const stack_symbol_type& that); #endif }; /// A stack with random access from its top. template > class stack { public: // Hide our reversed order. typedef typename S::iterator iterator; typedef typename S::const_iterator const_iterator; typedef typename S::size_type size_type; typedef typename std::ptrdiff_t index_type; stack (size_type n = 200) YY_NOEXCEPT : seq_ (n) {} #if 201103L <= YY_CPLUSPLUS /// Non copyable. stack (const stack&) = delete; /// Non copyable. stack& operator= (const stack&) = delete; #endif /// Random access. /// /// Index 0 returns the topmost element. const T& operator[] (index_type i) const { return seq_[size_type (size () - 1 - i)]; } /// Random access. /// /// Index 0 returns the topmost element. T& operator[] (index_type i) { return seq_[size_type (size () - 1 - i)]; } /// Steal the contents of \a t. /// /// Close to move-semantics. void push (YY_MOVE_REF (T) t) { seq_.push_back (T ()); operator[] (0).move (t); } /// Pop elements from the stack. void pop (std::ptrdiff_t n = 1) YY_NOEXCEPT { for (; 0 < n; --n) seq_.pop_back (); } /// Pop all elements from the stack. void clear () YY_NOEXCEPT { seq_.clear (); } /// Number of elements on the stack. index_type size () const YY_NOEXCEPT { return index_type (seq_.size ()); } /// Iterator on top of the stack (going downwards). const_iterator begin () const YY_NOEXCEPT { return seq_.begin (); } /// Bottom of the stack. const_iterator end () const YY_NOEXCEPT { return seq_.end (); } /// Present a slice of the top of a stack. class slice { public: slice (const stack& stack, index_type range) YY_NOEXCEPT : stack_ (stack) , range_ (range) {} const T& operator[] (index_type i) const { return stack_[range_ - i]; } private: const stack& stack_; index_type range_; }; private: #if YY_CPLUSPLUS < 201103L /// Non copyable. stack (const stack&); /// Non copyable. stack& operator= (const stack&); #endif /// The wrapped container. S seq_; }; /// Stack type. typedef stack stack_type; /// The stack. stack_type yystack_; /// Push a new state on the stack. /// \param m a debug message to display /// if null, no trace is output. /// \param sym the symbol /// \warning the contents of \a s.value is stolen. void yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym); /// Push a new look ahead token on the state on the stack. /// \param m a debug message to display /// if null, no trace is output. /// \param s the state /// \param sym the symbol (for its value and location). /// \warning the contents of \a sym.value is stolen. void yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym); /// Pop \a n symbols from the stack. void yypop_ (int n = 1) YY_NOEXCEPT; /// Constants. enum { yylast_ = 3719, ///< Last index in yytable_. yynnts_ = 57, ///< Number of nonterminal symbols. yyfinal_ = 13 ///< Termination state number. }; // User arguments. yyscan_t yyscanner; ParserDriver& drv; }; inline parser::symbol_kind_type parser::yytranslate_ (int t) YY_NOEXCEPT { // YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to // TOKEN-NUM as returned by yylex. static const signed char translate_table[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 }; // Last valid token kind. const int code_max = 374; if (t <= 0) return symbol_kind::S_YYEOF; else if (t <= code_max) return static_cast (translate_table[t]); else return symbol_kind::S_YYUNDEF; } // basic_symbol. template parser::basic_symbol::basic_symbol (const basic_symbol& that) : Base (that) , value () , location (that.location) { switch (this->kind ()) { case symbol_kind::S_columndef_list: // columndef_list value.copy< ColumnList > (YY_MOVE (that.value)); break; case symbol_kind::S_columnconstraint_list: // columnconstraint_list case symbol_kind::S_tableconstraint: // tableconstraint case symbol_kind::S_tableconstraint_list: // tableconstraint_list case symbol_kind::S_optional_tableconstraint_list: // optional_tableconstraint_list value.copy< TableConstraints > (YY_MOVE (that.value)); break; case symbol_kind::S_optional_if_not_exists: // optional_if_not_exists case symbol_kind::S_optional_unique: // optional_unique case symbol_kind::S_optional_temporary: // optional_temporary case symbol_kind::S_optional_always_generated: // optional_always_generated value.copy< bool > (YY_MOVE (that.value)); break; case symbol_kind::S_createindex_stmt: // createindex_stmt value.copy< sqlb::IndexPtr > (YY_MOVE (that.value)); break; case symbol_kind::S_indexed_column: // indexed_column value.copy< sqlb::IndexedColumn > (YY_MOVE (that.value)); break; case symbol_kind::S_indexed_column_list: // indexed_column_list value.copy< sqlb::IndexedColumnVector > (YY_MOVE (that.value)); break; case symbol_kind::S_columnid_list: // columnid_list case symbol_kind::S_optional_columnid_with_paren_list: // optional_columnid_with_paren_list value.copy< sqlb::StringVector > (YY_MOVE (that.value)); break; case symbol_kind::S_createvirtualtable_stmt: // createvirtualtable_stmt case symbol_kind::S_createtable_stmt: // createtable_stmt value.copy< sqlb::TablePtr > (YY_MOVE (that.value)); break; case symbol_kind::S_tableoption: // tableoption case symbol_kind::S_tableoptions_list: // tableoptions_list case symbol_kind::S_optional_tableoptions_list: // optional_tableoptions_list value.copy< std::bitset > (YY_MOVE (that.value)); break; case symbol_kind::S_columnconstraint: // columnconstraint value.copy< std::pair, std::shared_ptr> > (YY_MOVE (that.value)); break; case symbol_kind::S_columndef: // columndef value.copy< std::shared_ptr > (YY_MOVE (that.value)); break; case symbol_kind::S_ABORT: // "ABORT" case symbol_kind::S_ACTION: // "ACTION" case symbol_kind::S_ALWAYS: // "ALWAYS" case symbol_kind::S_AND: // "AND" case symbol_kind::S_AND_BETWEEN: // "AND BETWEEN" case symbol_kind::S_AS: // "AS" case symbol_kind::S_ASC: // "ASC" case symbol_kind::S_AUTOINCREMENT: // "AUTOINCREMENT" case symbol_kind::S_BETWEEN: // "BETWEEN" case symbol_kind::S_CASCADE: // "CASCADE" case symbol_kind::S_CASE: // "CASE" case symbol_kind::S_CAST: // "CAST" case symbol_kind::S_CHECK: // "CHECK" case symbol_kind::S_COLLATE: // "COLLATE" case symbol_kind::S_CONFLICT: // "CONFLICT" case symbol_kind::S_CONSTRAINT: // "CONSTRAINT" case symbol_kind::S_CREATE: // "CREATE" case symbol_kind::S_CURRENT_DATE: // "CURRENT_DATE" case symbol_kind::S_CURRENT_TIME: // "CURRENT_TIME" case symbol_kind::S_CURRENT_TIMESTAMP: // "CURRENT_TIMESTAMP" case symbol_kind::S_DEFAULT: // "DEFAULT" case symbol_kind::S_DEFERRABLE: // "DEFERRABLE" case symbol_kind::S_DEFERRED: // "DEFERRED" case symbol_kind::S_DELETE: // "DELETE" case symbol_kind::S_DESC: // "DESC" case symbol_kind::S_DISTINCT: // "DISTINCT" case symbol_kind::S_ELSE: // "ELSE" case symbol_kind::S_END: // "END" case symbol_kind::S_ESCAPE: // "ESCAPE" case symbol_kind::S_EXISTS: // "EXISTS" case symbol_kind::S_FAIL: // "FAIL" case symbol_kind::S_FALSE: // "FALSE" case symbol_kind::S_FILTER: // "FILTER" case symbol_kind::S_FOLLOWING: // "FOLLOWING" case symbol_kind::S_FOREIGN: // "FOREIGN" case symbol_kind::S_FROM: // "FROM" case symbol_kind::S_GENERATED: // "GENERATED" case symbol_kind::S_GLOB: // "GLOB" case symbol_kind::S_IF: // "IF" case symbol_kind::S_IGNORE: // "IGNORE" case symbol_kind::S_IMMEDIATE: // "IMMEDIATE" case symbol_kind::S_IN: // "IN" case symbol_kind::S_INDEX: // "INDEX" case symbol_kind::S_INITIALLY: // "INITIALLY" case symbol_kind::S_INSERT: // "INSERT" case symbol_kind::S_IS: // "IS" case symbol_kind::S_ISNULL: // "ISNULL" case symbol_kind::S_KEY: // "KEY" case symbol_kind::S_LIKE: // "LIKE" case symbol_kind::S_MATCH: // "MATCH" case symbol_kind::S_NO: // "NO" case symbol_kind::S_NOT: // "NOT" case symbol_kind::S_NOTNULL: // "NOTNULL" case symbol_kind::S_NULL: // "NULL" case symbol_kind::S_ON: // "ON" case symbol_kind::S_OR: // "OR" case symbol_kind::S_OVER: // "OVER" case symbol_kind::S_PARTITION: // "PARTITION" case symbol_kind::S_PRECEDING: // "PRECEDING" case symbol_kind::S_PRIMARY: // "PRIMARY" case symbol_kind::S_RAISE: // "RAISE" case symbol_kind::S_RANGE: // "RANGE" case symbol_kind::S_REFERENCES: // "REFERENCES" case symbol_kind::S_REGEXP: // "REGEXP" case symbol_kind::S_REPLACE: // "REPLACE" case symbol_kind::S_RESTRICT: // "RESTRICT" case symbol_kind::S_RETURNING: // "RETURNING" case symbol_kind::S_ROLLBACK: // "ROLLBACK" case symbol_kind::S_ROWID: // "ROWID" case symbol_kind::S_ROWS: // "ROWS" case symbol_kind::S_SELECT: // "SELECT" case symbol_kind::S_SET: // "SET" case symbol_kind::S_STORED: // "STORED" case symbol_kind::S_STRICT: // "STRICT" case symbol_kind::S_TABLE: // "TABLE" case symbol_kind::S_TEMP: // "TEMP" case symbol_kind::S_TEMPORARY: // "TEMPORARY" case symbol_kind::S_THEN: // "THEN" case symbol_kind::S_TRUE: // "TRUE" case symbol_kind::S_UNBOUNDED: // "UNBOUNDED" case symbol_kind::S_UNIQUE: // "UNIQUE" case symbol_kind::S_UPDATE: // "UPDATE" case symbol_kind::S_USING: // "USING" case symbol_kind::S_VIRTUAL: // "VIRTUAL" case symbol_kind::S_WHEN: // "WHEN" case symbol_kind::S_WHERE: // "WHERE" case symbol_kind::S_WITHOUT: // "WITHOUT" case symbol_kind::S_IDENTIFIER: // "identifier" case symbol_kind::S_NUMERIC: // "numeric" case symbol_kind::S_STRINGLITERAL: // "string literal" case symbol_kind::S_QUOTEDLITERAL: // "quoted literal" case symbol_kind::S_BLOBLITERAL: // "blob literal" case symbol_kind::S_BINDPARAMETER: // "bind parameter" case symbol_kind::S_literalvalue: // literalvalue case symbol_kind::S_id: // id case symbol_kind::S_allowed_keywords_as_identifier: // allowed_keywords_as_identifier case symbol_kind::S_tableid: // tableid case symbol_kind::S_columnid: // columnid case symbol_kind::S_signednumber: // signednumber case symbol_kind::S_signednumber_or_numeric: // signednumber_or_numeric case symbol_kind::S_typename_namelist: // typename_namelist case symbol_kind::S_type_name: // type_name case symbol_kind::S_unary_expr: // unary_expr case symbol_kind::S_binary_expr: // binary_expr case symbol_kind::S_like_expr: // like_expr case symbol_kind::S_exprlist_expr: // exprlist_expr case symbol_kind::S_function_expr: // function_expr case symbol_kind::S_isnull_expr: // isnull_expr case symbol_kind::S_between_expr: // between_expr case symbol_kind::S_in_expr: // in_expr case symbol_kind::S_whenthenlist_expr: // whenthenlist_expr case symbol_kind::S_case_expr: // case_expr case symbol_kind::S_raise_expr: // raise_expr case symbol_kind::S_expr: // expr case symbol_kind::S_select_stmt: // select_stmt case symbol_kind::S_optional_sort_order: // optional_sort_order case symbol_kind::S_optional_where: // optional_where case symbol_kind::S_tableid_with_uninteresting_schema: // tableid_with_uninteresting_schema case symbol_kind::S_optional_exprlist_with_paren: // optional_exprlist_with_paren case symbol_kind::S_optional_conflictclause: // optional_conflictclause case symbol_kind::S_optional_typename: // optional_typename case symbol_kind::S_optional_storage_identifier: // optional_storage_identifier case symbol_kind::S_optional_constraintname: // optional_constraintname case symbol_kind::S_fk_clause_part: // fk_clause_part case symbol_kind::S_fk_clause_part_list: // fk_clause_part_list case symbol_kind::S_optional_fk_clause: // optional_fk_clause value.copy< std::string > (YY_MOVE (that.value)); break; default: break; } } template parser::symbol_kind_type parser::basic_symbol::type_get () const YY_NOEXCEPT { return this->kind (); } template bool parser::basic_symbol::empty () const YY_NOEXCEPT { return this->kind () == symbol_kind::S_YYEMPTY; } template void parser::basic_symbol::move (basic_symbol& s) { super_type::move (s); switch (this->kind ()) { case symbol_kind::S_columndef_list: // columndef_list value.move< ColumnList > (YY_MOVE (s.value)); break; case symbol_kind::S_columnconstraint_list: // columnconstraint_list case symbol_kind::S_tableconstraint: // tableconstraint case symbol_kind::S_tableconstraint_list: // tableconstraint_list case symbol_kind::S_optional_tableconstraint_list: // optional_tableconstraint_list value.move< TableConstraints > (YY_MOVE (s.value)); break; case symbol_kind::S_optional_if_not_exists: // optional_if_not_exists case symbol_kind::S_optional_unique: // optional_unique case symbol_kind::S_optional_temporary: // optional_temporary case symbol_kind::S_optional_always_generated: // optional_always_generated value.move< bool > (YY_MOVE (s.value)); break; case symbol_kind::S_createindex_stmt: // createindex_stmt value.move< sqlb::IndexPtr > (YY_MOVE (s.value)); break; case symbol_kind::S_indexed_column: // indexed_column value.move< sqlb::IndexedColumn > (YY_MOVE (s.value)); break; case symbol_kind::S_indexed_column_list: // indexed_column_list value.move< sqlb::IndexedColumnVector > (YY_MOVE (s.value)); break; case symbol_kind::S_columnid_list: // columnid_list case symbol_kind::S_optional_columnid_with_paren_list: // optional_columnid_with_paren_list value.move< sqlb::StringVector > (YY_MOVE (s.value)); break; case symbol_kind::S_createvirtualtable_stmt: // createvirtualtable_stmt case symbol_kind::S_createtable_stmt: // createtable_stmt value.move< sqlb::TablePtr > (YY_MOVE (s.value)); break; case symbol_kind::S_tableoption: // tableoption case symbol_kind::S_tableoptions_list: // tableoptions_list case symbol_kind::S_optional_tableoptions_list: // optional_tableoptions_list value.move< std::bitset > (YY_MOVE (s.value)); break; case symbol_kind::S_columnconstraint: // columnconstraint value.move< std::pair, std::shared_ptr> > (YY_MOVE (s.value)); break; case symbol_kind::S_columndef: // columndef value.move< std::shared_ptr > (YY_MOVE (s.value)); break; case symbol_kind::S_ABORT: // "ABORT" case symbol_kind::S_ACTION: // "ACTION" case symbol_kind::S_ALWAYS: // "ALWAYS" case symbol_kind::S_AND: // "AND" case symbol_kind::S_AND_BETWEEN: // "AND BETWEEN" case symbol_kind::S_AS: // "AS" case symbol_kind::S_ASC: // "ASC" case symbol_kind::S_AUTOINCREMENT: // "AUTOINCREMENT" case symbol_kind::S_BETWEEN: // "BETWEEN" case symbol_kind::S_CASCADE: // "CASCADE" case symbol_kind::S_CASE: // "CASE" case symbol_kind::S_CAST: // "CAST" case symbol_kind::S_CHECK: // "CHECK" case symbol_kind::S_COLLATE: // "COLLATE" case symbol_kind::S_CONFLICT: // "CONFLICT" case symbol_kind::S_CONSTRAINT: // "CONSTRAINT" case symbol_kind::S_CREATE: // "CREATE" case symbol_kind::S_CURRENT_DATE: // "CURRENT_DATE" case symbol_kind::S_CURRENT_TIME: // "CURRENT_TIME" case symbol_kind::S_CURRENT_TIMESTAMP: // "CURRENT_TIMESTAMP" case symbol_kind::S_DEFAULT: // "DEFAULT" case symbol_kind::S_DEFERRABLE: // "DEFERRABLE" case symbol_kind::S_DEFERRED: // "DEFERRED" case symbol_kind::S_DELETE: // "DELETE" case symbol_kind::S_DESC: // "DESC" case symbol_kind::S_DISTINCT: // "DISTINCT" case symbol_kind::S_ELSE: // "ELSE" case symbol_kind::S_END: // "END" case symbol_kind::S_ESCAPE: // "ESCAPE" case symbol_kind::S_EXISTS: // "EXISTS" case symbol_kind::S_FAIL: // "FAIL" case symbol_kind::S_FALSE: // "FALSE" case symbol_kind::S_FILTER: // "FILTER" case symbol_kind::S_FOLLOWING: // "FOLLOWING" case symbol_kind::S_FOREIGN: // "FOREIGN" case symbol_kind::S_FROM: // "FROM" case symbol_kind::S_GENERATED: // "GENERATED" case symbol_kind::S_GLOB: // "GLOB" case symbol_kind::S_IF: // "IF" case symbol_kind::S_IGNORE: // "IGNORE" case symbol_kind::S_IMMEDIATE: // "IMMEDIATE" case symbol_kind::S_IN: // "IN" case symbol_kind::S_INDEX: // "INDEX" case symbol_kind::S_INITIALLY: // "INITIALLY" case symbol_kind::S_INSERT: // "INSERT" case symbol_kind::S_IS: // "IS" case symbol_kind::S_ISNULL: // "ISNULL" case symbol_kind::S_KEY: // "KEY" case symbol_kind::S_LIKE: // "LIKE" case symbol_kind::S_MATCH: // "MATCH" case symbol_kind::S_NO: // "NO" case symbol_kind::S_NOT: // "NOT" case symbol_kind::S_NOTNULL: // "NOTNULL" case symbol_kind::S_NULL: // "NULL" case symbol_kind::S_ON: // "ON" case symbol_kind::S_OR: // "OR" case symbol_kind::S_OVER: // "OVER" case symbol_kind::S_PARTITION: // "PARTITION" case symbol_kind::S_PRECEDING: // "PRECEDING" case symbol_kind::S_PRIMARY: // "PRIMARY" case symbol_kind::S_RAISE: // "RAISE" case symbol_kind::S_RANGE: // "RANGE" case symbol_kind::S_REFERENCES: // "REFERENCES" case symbol_kind::S_REGEXP: // "REGEXP" case symbol_kind::S_REPLACE: // "REPLACE" case symbol_kind::S_RESTRICT: // "RESTRICT" case symbol_kind::S_RETURNING: // "RETURNING" case symbol_kind::S_ROLLBACK: // "ROLLBACK" case symbol_kind::S_ROWID: // "ROWID" case symbol_kind::S_ROWS: // "ROWS" case symbol_kind::S_SELECT: // "SELECT" case symbol_kind::S_SET: // "SET" case symbol_kind::S_STORED: // "STORED" case symbol_kind::S_STRICT: // "STRICT" case symbol_kind::S_TABLE: // "TABLE" case symbol_kind::S_TEMP: // "TEMP" case symbol_kind::S_TEMPORARY: // "TEMPORARY" case symbol_kind::S_THEN: // "THEN" case symbol_kind::S_TRUE: // "TRUE" case symbol_kind::S_UNBOUNDED: // "UNBOUNDED" case symbol_kind::S_UNIQUE: // "UNIQUE" case symbol_kind::S_UPDATE: // "UPDATE" case symbol_kind::S_USING: // "USING" case symbol_kind::S_VIRTUAL: // "VIRTUAL" case symbol_kind::S_WHEN: // "WHEN" case symbol_kind::S_WHERE: // "WHERE" case symbol_kind::S_WITHOUT: // "WITHOUT" case symbol_kind::S_IDENTIFIER: // "identifier" case symbol_kind::S_NUMERIC: // "numeric" case symbol_kind::S_STRINGLITERAL: // "string literal" case symbol_kind::S_QUOTEDLITERAL: // "quoted literal" case symbol_kind::S_BLOBLITERAL: // "blob literal" case symbol_kind::S_BINDPARAMETER: // "bind parameter" case symbol_kind::S_literalvalue: // literalvalue case symbol_kind::S_id: // id case symbol_kind::S_allowed_keywords_as_identifier: // allowed_keywords_as_identifier case symbol_kind::S_tableid: // tableid case symbol_kind::S_columnid: // columnid case symbol_kind::S_signednumber: // signednumber case symbol_kind::S_signednumber_or_numeric: // signednumber_or_numeric case symbol_kind::S_typename_namelist: // typename_namelist case symbol_kind::S_type_name: // type_name case symbol_kind::S_unary_expr: // unary_expr case symbol_kind::S_binary_expr: // binary_expr case symbol_kind::S_like_expr: // like_expr case symbol_kind::S_exprlist_expr: // exprlist_expr case symbol_kind::S_function_expr: // function_expr case symbol_kind::S_isnull_expr: // isnull_expr case symbol_kind::S_between_expr: // between_expr case symbol_kind::S_in_expr: // in_expr case symbol_kind::S_whenthenlist_expr: // whenthenlist_expr case symbol_kind::S_case_expr: // case_expr case symbol_kind::S_raise_expr: // raise_expr case symbol_kind::S_expr: // expr case symbol_kind::S_select_stmt: // select_stmt case symbol_kind::S_optional_sort_order: // optional_sort_order case symbol_kind::S_optional_where: // optional_where case symbol_kind::S_tableid_with_uninteresting_schema: // tableid_with_uninteresting_schema case symbol_kind::S_optional_exprlist_with_paren: // optional_exprlist_with_paren case symbol_kind::S_optional_conflictclause: // optional_conflictclause case symbol_kind::S_optional_typename: // optional_typename case symbol_kind::S_optional_storage_identifier: // optional_storage_identifier case symbol_kind::S_optional_constraintname: // optional_constraintname case symbol_kind::S_fk_clause_part: // fk_clause_part case symbol_kind::S_fk_clause_part_list: // fk_clause_part_list case symbol_kind::S_optional_fk_clause: // optional_fk_clause value.move< std::string > (YY_MOVE (s.value)); break; default: break; } location = YY_MOVE (s.location); } // by_kind. inline parser::by_kind::by_kind () YY_NOEXCEPT : kind_ (symbol_kind::S_YYEMPTY) {} #if 201103L <= YY_CPLUSPLUS inline parser::by_kind::by_kind (by_kind&& that) YY_NOEXCEPT : kind_ (that.kind_) { that.clear (); } #endif inline parser::by_kind::by_kind (const by_kind& that) YY_NOEXCEPT : kind_ (that.kind_) {} inline parser::by_kind::by_kind (token_kind_type t) YY_NOEXCEPT : kind_ (yytranslate_ (t)) {} inline void parser::by_kind::clear () YY_NOEXCEPT { kind_ = symbol_kind::S_YYEMPTY; } inline void parser::by_kind::move (by_kind& that) { kind_ = that.kind_; that.clear (); } inline parser::symbol_kind_type parser::by_kind::kind () const YY_NOEXCEPT { return kind_; } inline parser::symbol_kind_type parser::by_kind::type_get () const YY_NOEXCEPT { return this->kind (); } #line 10 "sqlite3_parser.yy" } } // sqlb::parser #line 4414 "sqlite3_parser.hpp" #endif // !YY_YY_SQLITE3_PARSER_HPP_INCLUDED sqlitebrowser-sqlitebrowser-5733cb7/src/sql/parser/sqlite3_parser.yy000066400000000000000000000751471463772530400261170ustar00rootroot00000000000000%skeleton "lalr1.cc" %require "3.4.1" %defines %define api.token.constructor %define api.value.type variant %define parse.assert %output "sqlite3_parser.cpp" %define api.location.file "sqlite3_location.h" %define api.namespace { sqlb::parser } %code requires { #include #include #include "../sqlitetypes.h" #include "../ObjectIdentifier.h" namespace sqlb { namespace parser { class ParserDriver; } } typedef void* yyscan_t; struct TableConstraints { std::multimap> index; std::multimap> fk; std::vector> check; }; using ColumnList = std::pair>, TableConstraints>; } // The parsing context %param { yyscan_t yyscanner } %param { ParserDriver& drv } %locations %define parse.trace %define parse.error verbose %code { #include "ParserDriver.h" static std::string unquote_text(std::string str, char quote_char) { if(quote_char != '[') { if(str.front() != quote_char || str.back() != quote_char) return str; str = str.substr(1, str.size()-2); std::string quote(2, quote_char); size_t pos = 0; while((pos = str.find(quote, pos)) != std::string::npos) { str.erase(pos, 1); pos += 1; // Don't remove the other quote char too } return str; } else { if(str.front() != '[' || str.back() != ']') return str; return str.substr(1, str.size()-2); } } } %define api.token.prefix {TOK_} %token EOF 0 "end of file" LPAREN "(" RPAREN ")" DOT "." COMMA "," SEMI ";" PLUS "+" MINUS "-" STAR "*" SLASH "/" TILDE "~" AMPERSAND "&" PERCENT "%" BITOR "|" OROP "||" EQUAL "=" EQUAL2 "==" GREATER ">" GREATEREQUAL ">=" LOWER "<" LOWEREQUAL "<=" UNEQUAL "!=" UNEQUAL2 "<>" BITWISELEFT "<<" BITWISERIGHT ">>" ; %token ABORT "ABORT" %token ACTION "ACTION" %token ALWAYS "ALWAYS" %token AND "AND" %token AND_BETWEEN "AND BETWEEN" %token AS "AS" %token ASC "ASC" %token AUTOINCREMENT "AUTOINCREMENT" %token BETWEEN "BETWEEN" %token CASCADE "CASCADE" %token CASE "CASE" %token CAST "CAST" %token CHECK "CHECK" %token COLLATE "COLLATE" %token CONFLICT "CONFLICT" %token CONSTRAINT "CONSTRAINT" %token CREATE "CREATE" %token CURRENT_DATE "CURRENT_DATE" %token CURRENT_TIME "CURRENT_TIME" %token CURRENT_TIMESTAMP "CURRENT_TIMESTAMP" %token DEFAULT "DEFAULT" %token DEFERRABLE "DEFERRABLE" %token DEFERRED "DEFERRED" %token DELETE "DELETE" %token DESC "DESC" %token DISTINCT "DISTINCT" %token ELSE "ELSE" %token END "END" %token ESCAPE "ESCAPE" %token EXISTS "EXISTS" %token FAIL "FAIL" %token FALSE "FALSE" %token FILTER "FILTER" %token FOLLOWING "FOLLOWING" %token FOREIGN "FOREIGN" %token FROM "FROM" %token GENERATED "GENERATED" %token GLOB "GLOB" %token IF "IF" %token IGNORE "IGNORE" %token IMMEDIATE "IMMEDIATE" %token IN "IN" %token INDEX "INDEX" %token INITIALLY "INITIALLY" %token INSERT "INSERT" %token IS "IS" %token ISNULL "ISNULL" %token KEY "KEY" %token LIKE "LIKE" %token MATCH "MATCH" %token NO "NO" %token NOT "NOT" %token NOTNULL "NOTNULL" %token NULL "NULL" %token ON "ON" %token OR "OR" %token OVER "OVER" %token PARTITION "PARTITION" %token PRECEDING "PRECEDING" %token PRIMARY "PRIMARY" %token RAISE "RAISE" %token RANGE "RANGE" %token REFERENCES "REFERENCES" %token REGEXP "REGEXP" %token REPLACE "REPLACE" %token RESTRICT "RESTRICT" %token RETURNING "RETURNING" %token ROLLBACK "ROLLBACK" %token ROWID "ROWID" %token ROWS "ROWS" %token SELECT "SELECT" %token SET "SET" %token STORED "STORED" %token STRICT "STRICT" %token TABLE "TABLE" %token TEMP "TEMP" %token TEMPORARY "TEMPORARY" %token THEN "THEN" %token TRUE "TRUE" %token UNBOUNDED "UNBOUNDED" %token UNIQUE "UNIQUE" %token UPDATE "UPDATE" %token USING "USING" %token VIRTUAL "VIRTUAL" %token WHEN "WHEN" %token WHERE "WHERE" %token WITHOUT "WITHOUT" %token IDENTIFIER "identifier" %token NUMERIC "numeric" %token STRINGLITERAL "string literal" %token QUOTEDLITERAL "quoted literal" %token BLOBLITERAL "blob literal" %token BINDPARAMETER "bind parameter" %type literalvalue %type signednumber %type signednumber_or_numeric %type id %type allowed_keywords_as_identifier %type tableid %type columnid %type typename_namelist %type type_name %type unary_expr %type binary_expr %type like_expr %type exprlist_expr %type function_expr %type isnull_expr %type between_expr %type in_expr %type whenthenlist_expr %type case_expr %type raise_expr %type expr %type optional_if_not_exists %type optional_unique %type optional_temporary %type optional_sort_order %type optional_where %type optional_constraintname %type optional_conflictclause %type tableid_with_uninteresting_schema %type optional_exprlist_with_paren %type select_stmt %type indexed_column %type indexed_column_list %type createindex_stmt %type createvirtualtable_stmt %type optional_typename %type optional_storage_identifier %type optional_always_generated %type columnconstraint_list %type , std::shared_ptr>> columnconstraint %type > columndef %type columndef_list %type columnid_list %type optional_columnid_with_paren_list %type fk_clause_part %type fk_clause_part_list %type optional_fk_clause %type tableconstraint %type tableconstraint_list %type optional_tableconstraint_list %type > tableoption %type > tableoptions_list %type > optional_tableoptions_list %type createtable_stmt %% %left OR; %left AND; %right NOT; %left IS MATCH LIKE BETWEEN IN UNEQUAL UNEQUAL2 EQUAL EQUAL2 GLOB REGEXP ISNULL NOTNULL; %left GREATER LOWEREQUAL LOWER GREATEREQUAL; %right ESCAPE; %left AMPERSAND BITOR BITWISELEFT BITWISERIGHT; %left PLUS MINUS; %left STAR SLASH PERCENT; %left OROP; %left COLLATE; %right TILDE; %nonassoc ON; /* * Statements */ %start sql; sql: statement | statement ";" ; statement: createindex_stmt { drv.result = $1; } | createvirtualtable_stmt { drv.result = $1; } | createtable_stmt { drv.result = $1; } ; /* * Expressions */ literalvalue: NUMERIC | STRINGLITERAL | BLOBLITERAL | NULL | TRUE | FALSE | CURRENT_TIME | CURRENT_DATE | CURRENT_TIMESTAMP ; id: IDENTIFIER | QUOTEDLITERAL //| STRINGLITERAL ; allowed_keywords_as_identifier: ABORT | ACTION | ALWAYS | ASC | CASCADE | CAST | CONFLICT | DEFERRED | DESC | END | FAIL | FILTER | FOLLOWING | GENERATED | GLOB | KEY | LIKE | IGNORE | INITIALLY | IMMEDIATE | MATCH | NO | OVER | PARTITION | PRECEDING | RAISE | RANGE | REGEXP | REPLACE | RESTRICT | RETURNING | ROLLBACK | ROWID | ROWS | STORED | STRICT | TEMPORARY | TEMP | UNBOUNDED | VIRTUAL | WITHOUT ; tableid: allowed_keywords_as_identifier | CURRENT_TIME | CURRENT_DATE | CURRENT_TIMESTAMP | id | STRINGLITERAL { $$ = unquote_text($1, '\''); } ; columnid: allowed_keywords_as_identifier | CURRENT_TIME | CURRENT_DATE | CURRENT_TIMESTAMP | IF | id | STRINGLITERAL { $$ = unquote_text($1, '\''); } ; signednumber: "+" NUMERIC { $$ = "+" + $2; } // No NUMERIC without "+" or "-" here because that is just a literalvalue | "-" NUMERIC { $$ = "-" + $2; } ; signednumber_or_numeric: signednumber | NUMERIC ; typename_namelist: tableid { $$ = $1; } | typename_namelist tableid { $$ = $1 + " " + $2; } ; type_name: typename_namelist { $$ = $1; } | typename_namelist "(" signednumber_or_numeric ")" { $$ = $1 + "(" + $3 + ")"; } | typename_namelist "(" signednumber_or_numeric "," signednumber_or_numeric ")" { $$ = $1 + "(" + $3 + ", " + $5 + ")"; } ; unary_expr: "-" expr %prec TILDE { $$ = "-" + $2; } | "+" expr %prec TILDE { $$ = "+" + $2; } | "~" expr { $$ = "~" + $2; } | NOT expr { $$ = "NOT " + $2; } ; binary_expr: expr "||" expr { $$ = $1 + " || " + $3; } | expr "*" expr { $$ = $1 + " * " + $3; } | expr "/" expr { $$ = $1 + " / " + $3; } | expr "%" expr { $$ = $1 + " % " + $3; } | expr "+" expr { $$ = $1 + " + " + $3; } | expr "-" expr { $$ = $1 + " - " + $3; } | expr "<<" expr { $$ = $1 + " << " + $3; } | expr ">>" expr { $$ = $1 + " >> " + $3; } | expr "&" expr { $$ = $1 + " & " + $3; } | expr "|" expr { $$ = $1 + " | " + $3; } | expr "<" expr { $$ = $1 + " < " + $3; } | expr "<=" expr { $$ = $1 + " <= " + $3; } | expr ">" expr { $$ = $1 + " > " + $3; } | expr ">=" expr { $$ = $1 + " >= " + $3; } | expr "=" expr { $$ = $1 + " = " + $3; } | expr "==" expr { $$ = $1 + " == " + $3; } | expr "!=" expr { $$ = $1 + " != " + $3; } | expr "<>" expr { $$ = $1 + " <> " + $3; } | expr IS expr { $$ = $1 + " IS " + $3; } | expr IS DISTINCT FROM expr %prec TILDE { $$ = $1 + " IS DISTINCT FROM " + $5; } | expr IS NOT DISTINCT FROM expr %prec TILDE { $$ = $1 + " IS NOT DISTINCT FROM " + $6; } | expr AND expr { $$ = $1 + " AND " + $3; } | expr OR expr { $$ = $1 + " OR " + $3; } ; like_expr: expr LIKE expr { $$ = $1 + " LIKE " + $3; } | expr GLOB expr { $$ = $1 + " GLOB " + $3; } | expr MATCH expr { $$ = $1 + " MATCH " + $3; } | expr REGEXP expr { $$ = $1 + " REGEXP " + $3; } | expr NOT LIKE expr { $$ = $1 + " NOT LIKE " + $4; } | expr NOT GLOB expr { $$ = $1 + " NOT GLOB " + $4; } | expr NOT MATCH expr { $$ = $1 + " NOT MATCH " + $4; } | expr NOT REGEXP expr { $$ = $1 + " NOT REGEXP " + $4; } | expr LIKE expr ESCAPE expr %prec LIKE { $$ = $1 + " LIKE " + $3 + " ESCAPE " + $5; } | expr GLOB expr ESCAPE expr %prec GLOB { $$ = $1 + " GLOB " + $3 + " ESCAPE " + $5; } | expr MATCH expr ESCAPE expr %prec MATCH { $$ = $1 + " MATCH " + $3 + " ESCAPE " + $5; } | expr REGEXP expr ESCAPE expr %prec REGEXP { $$ = $1 + " REGEXP " + $3 + " ESCAPE " + $5; } | expr NOT LIKE expr ESCAPE expr %prec LIKE { $$ = $1 + " NOT LIKE " + $3 + " ESCAPE " + $6; } | expr NOT GLOB expr ESCAPE expr %prec GLOB { $$ = $1 + " NOT GLOB " + $3 + " ESCAPE " + $6; } | expr NOT MATCH expr ESCAPE expr %prec MATCH { $$ = $1 + " NOT MATCH " + $3 + " ESCAPE " + $6; } | expr NOT REGEXP expr ESCAPE expr %prec REGEXP { $$ = $1 + " NOT REGEXP " + $3 + " ESCAPE " + $6; } ; exprlist_expr: expr { $$ = $1; } | exprlist_expr "," expr { $$ = $1 + ", " + $3; } ; function_expr: id "(" exprlist_expr ")" { $$ = $1 + "(" + $3 + ")"; } | id "(" DISTINCT exprlist_expr ")" { $$ = $1 + "(DISTINCT " + $4 + ")"; } | id "(" ")" { $$ = $1 + "()"; } | id "(" "*" ")" { $$ = $1 + "(*)"; } ; isnull_expr: expr ISNULL { $$ = $1 + " ISNULL"; } | expr NOTNULL { $$ = $1 + " NOTNULL"; } | expr NOT NULL %prec NOTNULL { $$ = $1 + " NOT NULL"; } ; between_expr: expr BETWEEN expr AND_BETWEEN expr %prec BETWEEN { $$ = $1 + " BETWEEN " + $3 + " AND " + $5; } | expr NOT BETWEEN expr AND_BETWEEN expr %prec BETWEEN { $$ = $1 + " NOT BETWEEN " + $4 + " AND " + $6; } ; in_expr: expr IN "(" ")" { $$ = $1 + " IN ()"; } | expr IN "(" select_stmt ")" { $$ = $1 + " IN (" + $4 + ")"; } | expr IN "(" exprlist_expr ")" { $$ = $1 + " IN (" + $4 + ")"; } | expr IN id "." tableid { $$ = $1 + " IN " + sqlb::escapeIdentifier($3) + "." + sqlb::escapeIdentifier($5); } | expr IN tableid { $$ = $1 + " IN " + sqlb::escapeIdentifier($3); } | expr IN id "." id "(" ")" { $$ = $1 + " IN " + sqlb::escapeIdentifier($3) + "." + $5 + "()"; } | expr IN id "." id "(" exprlist_expr ")" { $$ = $1 + " IN " + sqlb::escapeIdentifier($3) + "." + $5 + "(" + $7 + ")"; } | expr IN id "(" exprlist_expr ")" { $$ = $1 + " IN " + $3 + "(" + $5 + ")"; } | expr NOT IN "(" ")" { $$ = $1 + " NOT IN ()"; } | expr NOT IN "(" select_stmt ")" { $$ = $1 + " NOT IN (" + $5 + ")"; } | expr NOT IN "(" exprlist_expr ")" { $$ = $1 + " NOT IN (" + $5 + ")"; } | expr NOT IN id "." tableid { $$ = $1 + " NOT IN " + sqlb::escapeIdentifier($4) + "." + sqlb::escapeIdentifier($6); } | expr NOT IN tableid { $$ = $1 + " NOT IN " + sqlb::escapeIdentifier($4); } | expr NOT IN id "." id "(" ")" { $$ = $1 + " NOT IN " + sqlb::escapeIdentifier($4) + "." + $6 + "()"; } | expr NOT IN id "." id "(" exprlist_expr ")" { $$ = $1 + " NOT IN " + sqlb::escapeIdentifier($4) + "." + $6 + "(" + $8 + ")"; } | expr NOT IN id "(" exprlist_expr ")" { $$ = $1 + " NOT IN " + $4 + "(" + $6 + ")"; } ; whenthenlist_expr: WHEN expr THEN expr { $$ = "WHEN " + $2 + " THEN " + $4; } | whenthenlist_expr WHEN expr THEN expr { $$ = $1 + " WHEN" + $3 + " THEN " + $5; } ; case_expr: CASE expr whenthenlist_expr ELSE expr END { $$ = "CASE " + $2 + " " + $3 + " ELSE " + $5 + " END"; } | CASE expr whenthenlist_expr END { $$ = "CASE " + $2 + " " + $3 + " END"; } | CASE whenthenlist_expr ELSE expr END { $$ = "CASE " + $2 + " ELSE " + $4 + " END"; } | CASE whenthenlist_expr END { $$ = "CASE " + $2 + " END"; } ; raise_expr: RAISE "(" IGNORE ")" { $$ = "RAISE(IGNORE)"; } | RAISE "(" ROLLBACK "," STRINGLITERAL ")" { $$ = "RAISE(ROLLBACK, " + $5 + ")"; } | RAISE "(" ABORT "," STRINGLITERAL ")" { $$ = "RAISE(ABORT, " + $5 + ")"; } | RAISE "(" FAIL "," STRINGLITERAL ")" { $$ = "RAISE(FAIL, " + $5 + ")"; } ; expr: literalvalue | allowed_keywords_as_identifier { $$ = sqlb::escapeIdentifier($1); } | BINDPARAMETER | id "." id "." id { $$ = sqlb::escapeIdentifier($1) + "." + sqlb::escapeIdentifier($3) + "." + sqlb::escapeIdentifier($5); } | id "." id { $$ = sqlb::escapeIdentifier($1) + "." + sqlb::escapeIdentifier($3); } | id { $$ = sqlb::escapeIdentifier($1); } | unary_expr | binary_expr | function_expr | "(" exprlist_expr ")" { $$ = "(" + $2 + ")"; } | CAST "(" expr AS type_name ")" { $$ = "CAST(" + $3 + " AS " + $5 + ")"; } | expr COLLATE id { $$ = $1 + " COLLATE " + $3; } | like_expr | isnull_expr | between_expr | in_expr | case_expr | raise_expr // TODO Window functions ; /* * SELECT */ select_stmt: SELECT { $$ = "SELECT"; } // TODO ; /* * Helper rules for CREATE statements */ optional_if_not_exists: %empty { $$ = false; } | IF NOT EXISTS { $$ = true; } ; optional_sort_order: %empty { } | ASC { $$ = "ASC"; } | DESC { $$ = "DESC"; } ; /* * CREATE INDEX */ optional_unique: %empty { $$ = false; } | UNIQUE { $$ = true; } ; optional_where: %empty { } | WHERE expr { $$ = $2; } ; tableid_with_uninteresting_schema: id "." tableid { $$ = $3; } | TEMP "." tableid { $$ = $3; } | tableid { $$ = $1; } ; indexed_column: expr optional_sort_order { // If the expression is only one column name and nothing else, treat it as a column name; otherwise as an expression. char quote = getIdentifierQuoteChar(); if((quote == '[' && std::count($1.begin(), $1.end(), quote) == 1 && $1.front() == '[' && $1.back() == ']') || (quote != '[' && std::count($1.begin(), $1.end(), quote) == 2 && $1.front() == quote && $1.back() == quote)) { $$ = sqlb::IndexedColumn(unquote_text($1, quote), false, $2); } else if(std::count($1.begin(), $1.end(), '\'') == 2 && $1.front() == '\'' && $1.back() == '\'') { // Also remove single quotes when this actually is a string literal but looks like a columnid $$ = sqlb::IndexedColumn(unquote_text($1, '\''), false, $2); } else { $$ = sqlb::IndexedColumn($1, true, $2); } } ; indexed_column_list: indexed_column { $$ = sqlb::IndexedColumnVector(1, $1); } | indexed_column_list "," indexed_column { $$ = $1; $$.push_back($3); } ; createindex_stmt: CREATE optional_unique INDEX optional_if_not_exists tableid_with_uninteresting_schema ON tableid "(" indexed_column_list ")" optional_where { $$ = std::make_shared($5); $$->setTable($7); $$->setUnique($2); $$->setWhereExpr($11); $$->fields = $9; $$->setFullyParsed(true); } ; /* * CREATE VIRTUAL TABLE */ optional_exprlist_with_paren: %empty { } | "(" ")" { } | "(" exprlist_expr ")" { $$ = $2; } ; createvirtualtable_stmt: CREATE VIRTUAL TABLE optional_if_not_exists tableid_with_uninteresting_schema USING id optional_exprlist_with_paren { $$ = std::make_shared($5); $$->setVirtualUsing($7); $$->setFullyParsed(false); } ; /* * CREATE TABLE */ optional_temporary: %empty { $$ = false; } | TEMP { $$ = true; } | TEMPORARY { $$ = true; } ; tableoption: WITHOUT ROWID { $$.set(sqlb::Table::WithoutRowid, true); } | STRICT { $$.set(sqlb::Table::Strict, true); } ; tableoptions_list: tableoption { $$ = $1; } | tableoptions_list "," tableoption { $$ = $1 | $3; } | tableoptions_list tableoption { $$ = $1 | $2; } ; optional_tableoptions_list: %empty { } | tableoptions_list { $$ = $1; } ; optional_conflictclause: %empty { } | ON CONFLICT ROLLBACK { $$ = $3; } | ON CONFLICT ABORT { $$ = $3; } | ON CONFLICT FAIL { $$ = $3; } | ON CONFLICT IGNORE { $$ = $3; } | ON CONFLICT REPLACE { $$ = $3; } ; optional_typename: %empty { } | type_name { $$ = $1; } ; optional_storage_identifier: %empty { $$ = "VIRTUAL"; } | STORED { $$ = "STORED"; } | VIRTUAL { $$ = "VIRTUAL"; } ; optional_always_generated: %empty { $$ = false; } | GENERATED ALWAYS { $$ = true; } ; columnconstraint: optional_constraintname PRIMARY KEY optional_sort_order optional_conflictclause { auto pk = std::make_shared(); pk->setName($1); pk->setConflictAction($5); $$.first = pk; } | optional_constraintname PRIMARY KEY optional_sort_order optional_conflictclause AUTOINCREMENT { auto pk = std::make_shared(); pk->setName($1); pk->setConflictAction($5); pk->setAutoIncrement(true); $$.first = pk; } | optional_constraintname NOT NULL optional_conflictclause { auto nn = std::make_shared(); nn->setName($1); nn->setConflictAction($4); drv.last_table_column->setNotNull(nn); } | optional_constraintname NULL { } | optional_constraintname UNIQUE optional_conflictclause { auto u = std::make_shared(); u->setName($1); u->setConflictAction($3); drv.last_table_column->setUnique(u); } | optional_constraintname CHECK "(" expr ")" { auto c = std::make_shared($4); c->setName($1); drv.last_table_column->setCheck(c); } | optional_constraintname DEFAULT signednumber { auto d = std::make_shared($3); d->setName($1); drv.last_table_column->setDefaultValue(d); } | optional_constraintname DEFAULT literalvalue { auto d = std::make_shared($3); d->setName($1); drv.last_table_column->setDefaultValue(d); } | optional_constraintname DEFAULT id { auto d = std::make_shared($3); d->setName($1); drv.last_table_column->setDefaultValue(d); } | optional_constraintname DEFAULT allowed_keywords_as_identifier { // We must allow the same keywords as unquoted default values as in the columnid context. // But we do not use columnid here in order to avoid reduce/reduce conflicts. auto d = std::make_shared($3); d->setName($1); drv.last_table_column->setDefaultValue(d); } | optional_constraintname DEFAULT IF { // Same as above. auto d = std::make_shared($3); d->setName($1); drv.last_table_column->setDefaultValue(d); } | optional_constraintname DEFAULT "(" expr ")" { auto d = std::make_shared("(" + $4 + ")"); d->setName($1); drv.last_table_column->setDefaultValue(d); } | optional_constraintname COLLATE id { auto c = std::make_shared($3); c->setName($1); drv.last_table_column->setCollation(c); } | optional_constraintname REFERENCES tableid optional_columnid_with_paren_list optional_fk_clause { // TODO Solve shift/reduce conflict. It is not super important though as shifting seems to be right here. auto fk = std::make_shared(); fk->setName($1); fk->setTable($3); fk->setColumns($4); fk->setConstraint($5); $$.second = fk; } | optional_constraintname optional_always_generated AS "(" expr ")" optional_storage_identifier { // TODO Solve shift/reduce conflict. auto g = std::make_shared($5, $7); g->setName($1); drv.last_table_column->setGenerated(g); // This is a hack which removes any "GENERATED ALWAYS" from the end of the type name. // As of now these are shifted to the type instead of reducing the type when seeing the GENERATED identifier. // TODO Remove this once the grammar is conflict free const std::string generated_always = "GENERATED ALWAYS"; if(drv.last_table_column->type().size() >= generated_always.size() && drv.last_table_column->type().compare(drv.last_table_column->type().size() - generated_always.size(), generated_always.size(), generated_always) == 0) { std::string type = drv.last_table_column->type().substr(0, drv.last_table_column->type().size()-generated_always.size()); if(type.back() == ' ') type.pop_back(); drv.last_table_column->setType(type); } } ; columnconstraint_list: %empty { } | columnconstraint_list columnconstraint { $$ = $1; // Primary key and foreign key constraints are converted to table constraints // because we cannot store them as column constraints at the moment. if($2.first) $$.index.insert(std::make_pair(sqlb::IndexedColumnVector{sqlb::IndexedColumn(drv.last_table_column->name(), false)}, $2.first)); if($2.second) $$.fk.insert(std::make_pair(sqlb::StringVector{drv.last_table_column->name()}, $2.second)); } ; columndef: columnid optional_typename { $$ = std::make_shared($1, $2); drv.last_table_column = $$; } ; columndef_list: columndef columnconstraint_list { $$.first.push_back($1); $$.second = $2; } | columndef_list "," columndef columnconstraint_list { $$ = $1; $$.first.push_back($3); $$.second.index.insert($4.index.begin(), $4.index.end()); $$.second.fk.insert($4.fk.begin(), $4.fk.end()); } ; optional_constraintname: %empty { } | CONSTRAINT id { $$ = $2; } | CONSTRAINT STRINGLITERAL { $$ = $2; } ; columnid_list: columnid { $$ = sqlb::StringVector(1, $1); } | columnid_list "," columnid { $$ = $1; $$.push_back($3); } ; optional_columnid_with_paren_list: %empty { } | "(" columnid_list ")" { $$ = $2; } ; fk_clause_part: ON DELETE SET NULL { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | ON DELETE SET DEFAULT { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | ON DELETE CASCADE { $$ = $1 + " " + $2 + " " + $3; } | ON DELETE RESTRICT { $$ = $1 + " " + $2 + " " + $3; } | ON DELETE NO ACTION { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | ON UPDATE SET NULL { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | ON UPDATE SET DEFAULT { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | ON UPDATE CASCADE { $$ = $1 + " " + $2 + " " + $3; } | ON UPDATE RESTRICT { $$ = $1 + " " + $2 + " " + $3; } | ON UPDATE NO ACTION { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | ON INSERT SET NULL { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | ON INSERT SET DEFAULT { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | ON INSERT CASCADE { $$ = $1 + " " + $2 + " " + $3; } | ON INSERT RESTRICT { $$ = $1 + " " + $2 + " " + $3; } | ON INSERT NO ACTION { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | MATCH id { $$ = $1 + " " + $2; } ; fk_clause_part_list: fk_clause_part { $$ = $1; } | fk_clause_part_list fk_clause_part { $$ = $1 + " " + $2; } ; optional_fk_clause: %empty { } | fk_clause_part_list { $$ = $1; } | fk_clause_part_list DEFERRABLE INITIALLY DEFERRED { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | fk_clause_part_list DEFERRABLE INITIALLY IMMEDIATE { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | fk_clause_part_list DEFERRABLE { $$ = $1 + " " + $2; } | fk_clause_part_list NOT DEFERRABLE INITIALLY DEFERRED { $$ = $1 + " " + $2 + " " + $3 + " " + $4 + " " + $5; } | fk_clause_part_list NOT DEFERRABLE INITIALLY IMMEDIATE { $$ = $1 + " " + $2 + " " + $3 + " " + $4 + " " + $5; } | fk_clause_part_list NOT DEFERRABLE { $$ = $1 + " " + $2 + " " + $3; } | DEFERRABLE INITIALLY DEFERRED { $$ = $1 + " " + $2 + " " + $3; } | DEFERRABLE INITIALLY IMMEDIATE { $$ = $1 + " " + $2 + " " + $3; } | DEFERRABLE { $$ = $1; } | NOT DEFERRABLE INITIALLY DEFERRED { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | NOT DEFERRABLE INITIALLY IMMEDIATE { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } | NOT DEFERRABLE { $$ = $1 + " " + $2; } ; tableconstraint: optional_constraintname PRIMARY KEY "(" indexed_column_list ")" optional_conflictclause { auto pk = std::make_shared(); pk->setName($1); pk->setConflictAction($7); $$.index.insert(std::make_pair($5, pk)); } | optional_constraintname PRIMARY KEY "(" indexed_column_list AUTOINCREMENT ")" optional_conflictclause { auto pk = std::make_shared(); pk->setName($1); pk->setConflictAction($8); pk->setAutoIncrement(true); $$.index.insert(std::make_pair($5, pk)); } | optional_constraintname UNIQUE "(" indexed_column_list ")" optional_conflictclause { auto u = std::make_shared(); u->setName($1); u->setConflictAction($6); sqlb::StringVector columns; $$.index.insert(std::make_pair($4, u)); } | optional_constraintname CHECK "(" expr ")" { auto c = std::make_shared($4); c->setName($1); $$.check.push_back(c); } | optional_constraintname FOREIGN KEY "(" columnid_list ")" REFERENCES tableid optional_columnid_with_paren_list optional_fk_clause { auto f = std::make_shared($8, $9, $10); f->setName($1); $$.fk.insert(std::make_pair($5, f)); } ; tableconstraint_list: tableconstraint { $$ = $1; } | tableconstraint_list "," tableconstraint { $$ = $1; $$.index.insert($3.index.begin(), $3.index.end()); $$.fk.insert($3.fk.begin(), $3.fk.end()); std::copy($3.check.begin(), $3.check.end(), std::back_inserter($$.check)); } | tableconstraint_list tableconstraint { $$ = $1; $$.index.insert($2.index.begin(), $2.index.end()); $$.fk.insert($2.fk.begin(), $2.fk.end()); std::copy($2.check.begin(), $2.check.end(), std::back_inserter($$.check)); } ; optional_tableconstraint_list: %empty { } | "," tableconstraint_list { $$ = $2; } ; createtable_stmt: CREATE optional_temporary TABLE optional_if_not_exists tableid_with_uninteresting_schema AS select_stmt { $$ = std::make_shared($5); $$->setFullyParsed(false); } | CREATE optional_temporary TABLE optional_if_not_exists tableid_with_uninteresting_schema "(" columndef_list optional_tableconstraint_list ")" optional_tableoptions_list { $$ = std::make_shared($5); $$->setWithoutRowidTable($10.test(sqlb::Table::WithoutRowid)); $$->setStrict($10.test(sqlb::Table::Strict)); for(const auto& i : $8.index) $$->addConstraint(i.first, i.second); for(const auto& i : $8.fk) $$->addConstraint(i.first, i.second); for(const auto& i : $8.check) $$->addConstraint(i); $$->setFullyParsed(true); for(const auto& f : $7.first) $$->fields.push_back(*f); for(const auto& pk : $7.second.index) $$->addConstraint(pk.first, pk.second); for(const auto& fk : $7.second.fk) $$->addConstraint(fk.first, fk.second); } ; %% void sqlb::parser::parser::error(const location_type& l, const std::string& m) { std::cerr << l << ": " << m << std::endl; } sqlitebrowser-sqlitebrowser-5733cb7/src/sql/sqlitetypes.cpp000066400000000000000000000511441463772530400243610ustar00rootroot00000000000000#include "sqlitetypes.h" #include "ObjectIdentifier.h" #include "parser/ParserDriver.h" #include #include #include namespace sqlb { StringVector escapeIdentifier(StringVector ids) { std::transform(ids.begin(), ids.end(), ids.begin(), [](const std::string& id) { return escapeIdentifier(id); }); return ids; } std::string joinStringVector(const StringVector& vec, const std::string& delim) { return std::accumulate(vec.begin(), vec.end(), std::string(), [delim](const std::string& so_far, const std::string& s) { return so_far.empty() ? s : so_far + delim + s; }); } std::string joinStringVector(const IndexedColumnVector& vec, const std::string& delim) { return std::accumulate(vec.begin(), vec.end(), std::string(), [delim](const std::string& so_far, const IndexedColumn& c) { return so_far.empty() ? c.toString("", " ") : so_far + delim + c.toString("", ""); }); } bool Object::operator==(const Object& rhs) const { if(m_name != rhs.m_name) return false; if(m_fullyParsed != rhs.m_fullyParsed) // We check for the fully parsed flag to make sure not to lose anything in some corner cases return false; // We don't care about the original SQL text return true; } std::string ForeignKeyClause::toString() const { std::string result = escapeIdentifier(m_table); if(m_columns.size()) result += "(" + joinStringVector(escapeIdentifier(m_columns), ",") + ")"; if(m_constraint.size()) result += " " + m_constraint; return result; } std::string ForeignKeyClause::toSql(const StringVector& columns) const { std::string result; if(!m_name.empty()) result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; result += "FOREIGN KEY(" + joinStringVector(escapeIdentifier(columns), ",") + ") REFERENCES " + this->toString(); return result; } std::string UniqueConstraint::toSql(const IndexedColumnVector& columns) const { std::string result; if(!m_name.empty()) result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; result += "UNIQUE"; if(columns.size()) result += "(" + joinStringVector(columns, ",") + ")"; if(!m_conflictAction.empty()) result += " ON CONFLICT " + m_conflictAction; return result; } std::string NotNullConstraint::toSql() const { std::string result; if(!m_name.empty()) result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; result += "NOT NULL"; if(!m_conflictAction.empty()) result += " ON CONFLICT " + m_conflictAction; return result; } std::string PrimaryKeyConstraint::toSql(const IndexedColumnVector& columns) const { std::string result; if(!m_name.empty()) result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; result += "PRIMARY KEY(" + joinStringVector(columns, ",") + (m_auto_increment ? " AUTOINCREMENT" : "") + ")"; if(!m_conflictAction.empty()) result += " ON CONFLICT " + m_conflictAction; return result; } std::string CheckConstraint::toSql() const { std::string result; if(!m_name.empty()) result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; result += "CHECK(" + m_expression + ")"; return result; } std::string DefaultConstraint::toSql() const { std::string result; if(!m_name.empty()) result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; result += "DEFAULT " + m_value; return result; } std::string CollateConstraint::toSql() const { std::string result; if(!m_name.empty()) result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; result += "COLLATE " + m_collation; return result; } std::string GeneratedColumnConstraint::toSql() const { std::string result; if(!m_name.empty()) result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; result += "GENERATED ALWAYS AS (" + m_expression + ")" + " " + storage(); return result; } bool Field::operator==(const Field& rhs) const { if(m_name != rhs.m_name) return false; if(m_type != rhs.m_type) return false; if(m_notnull != rhs.m_notnull) return false; if(m_check != rhs.m_check) return false; if(m_defaultvalue != rhs.m_defaultvalue) return false; if(m_unique != rhs.m_unique) return false; if(m_collation != rhs.m_collation) return false; return true; } std::string Field::toString(const std::string& indent, const std::string& sep) const { std::string str = indent + escapeIdentifier(m_name) + sep + m_type; if(m_notnull) str += " " + m_notnull->toSql(); if(m_defaultvalue) str += " " + m_defaultvalue->toSql(); if(m_check) str += " " + m_check->toSql(); if(m_unique) str += " " + m_unique->toSql({}); if(m_collation) str += " " + m_collation->toSql(); if(m_generated) str += " " + m_generated->toSql(); return str; } bool Field::isText() const { if(starts_with_ci(m_type, "character")) return true; if(starts_with_ci(m_type, "varchar")) return true; if(starts_with_ci(m_type, "varying character")) return true; if(starts_with_ci(m_type, "nchar")) return true; if(starts_with_ci(m_type, "native character")) return true; if(starts_with_ci(m_type, "nvarchar")) return true; if(compare_ci(m_type, "text")) return true; if(compare_ci(m_type, "clob")) return true; return false; } bool Field::isInteger() const { if(compare_ci(m_type, "int")) return true; if(compare_ci(m_type, "integer")) return true; if(compare_ci(m_type, "tinyint")) return true; if(compare_ci(m_type, "smallint")) return true; if(compare_ci(m_type, "mediumint")) return true; if(compare_ci(m_type, "bigint")) return true; if(compare_ci(m_type, "unsigned big int")) return true; if(compare_ci(m_type, "int2")) return true; if(compare_ci(m_type, "int8")) return true; return false; } bool Field::isReal() const { if(compare_ci(m_type, "real")) return true; if(compare_ci(m_type, "double")) return true; if(compare_ci(m_type, "double precision")) return true; if(compare_ci(m_type, "float")) return true; return false; } bool Field::isNumeric() const { if(starts_with_ci(m_type, "decimal")) return true; if(compare_ci(m_type, "numeric")) return true; if(compare_ci(m_type, "boolean")) return true; if(compare_ci(m_type, "date")) return true; if(compare_ci(m_type, "datetime")) return true; return false; } bool Field::isBlob() const { if(m_type.empty()) return true; if(compare_ci(m_type, "blob")) return true; return false; } Field::Affinity Field::affinity() const { if (isInteger()) return IntegerAffinity; if (isText()) return TextAffinity; if (isBlob()) return BlobAffinity; if (isReal() || isNumeric()) return FloatAffinity; return BlobAffinity; } Table::Table(const Table& table) : Object(table.name()) { *this = table; } Table& Table::operator=(const Table& rhs) { // Base class Object::operator=(rhs); // Just assign the simple values m_options = rhs.m_options; m_virtual = rhs.m_virtual; // Clear the fields and the constraints first in order to avoid duplicates and/or old data in the next step fields.clear(); m_indexConstraints.clear(); m_foreignKeys.clear(); m_checkConstraints.clear(); // Make copies of the fields and the constraints. This is necessary in order to avoid any unwanted changes to the application's main database // schema representation just by modifying a reference to the fields or constraints and thinking it operates on a copy. std::copy(rhs.fields.begin(), rhs.fields.end(), std::back_inserter(fields)); for(const auto& e : rhs.m_indexConstraints) { if(e.second->isPrimaryKey()) m_indexConstraints.insert(std::make_pair(e.first, std::make_shared(*std::dynamic_pointer_cast(e.second)))); else m_indexConstraints.insert(std::make_pair(e.first, std::make_shared(*e.second))); } for(const auto& e : rhs.m_foreignKeys) m_foreignKeys.insert(std::make_pair(e.first, std::make_shared(*e.second))); std::transform(rhs.m_checkConstraints.begin(), rhs.m_checkConstraints.end(), std::back_inserter(m_checkConstraints), [](const auto& e) { return std::make_shared(*e); }); return *this; } bool Table::operator==(const Table& rhs) const { if(!Object::operator==(rhs)) return false; if(m_options != rhs.m_options) return false; if(m_virtual != rhs.m_virtual) return false; if(fields != rhs.fields) return false; if(m_indexConstraints != rhs.m_indexConstraints) return false; if(m_foreignKeys != rhs.m_foreignKeys) return false; if(m_checkConstraints != rhs.m_checkConstraints) return false; return true; } StringVector Table::fieldList() const { StringVector sl; std::transform(fields.begin(), fields.end(), std::back_inserter(sl), [](const auto& f) { return f.toString(); }); return sl; } StringVector Table::fieldNames() const { StringVector sl; std::transform(fields.begin(), fields.end(), std::back_inserter(sl), [](const auto& f) { return f.name(); }); return sl; } StringVector Table::rowidColumns() const { // For WITHOUT ROWID tables this function returns the names of the primary key column. For ordinary tables with a rowid column, it returns "_rowid_" if(withoutRowidTable()) { auto columns = primaryKeyColumns(); StringVector result; std::transform(columns.begin(), columns.end(), std::back_inserter(result), [](const auto& e) { return e.name(); }); return result; } else return {"_rowid_"}; } TablePtr Table::parseSQL(const std::string& sSQL) { parser::ParserDriver drv; if(!drv.parse(sSQL)) { TablePtr t = std::dynamic_pointer_cast(drv.result); t->setOriginalSql(sSQL); return t; } else { std::cerr << "Sqlite parse error: " << sSQL << std::endl; TablePtr t = std::make_shared
(""); t->setOriginalSql(sSQL); return t; } } std::string Table::sql(const std::string& schema, bool ifNotExists) const { // Special handling for virtual tables: just build an easy create statement and copy the using part in there if(isVirtual()) return "CREATE VIRTUAL TABLE " + ObjectIdentifier(schema, m_name).toString(true) + " USING " + m_virtual + ";"; // This is a normal table, not a virtual one std::string sql = "CREATE TABLE "; if(ifNotExists) sql += "IF NOT EXISTS "; sql += ObjectIdentifier(schema, m_name).toString(true); sql += " (\n"; sql += joinStringVector(fieldList(), ",\n"); // Constraints for(const auto& it : m_indexConstraints) sql += ",\n\t" + it.second->toSql(it.first); for(const auto& it : m_foreignKeys) sql += ",\n\t" + it.second->toSql(it.first); for(const auto& it : m_checkConstraints) sql += ",\n\t" + it->toSql(); sql += "\n)"; // Table options bool first_option = true; for(size_t i=0;i constraint) { IndexedColumnVector c; std::transform(columns.begin(), columns.end(), std::back_inserter(c), [](const auto& e) { return IndexedColumn(e, false); }); m_indexConstraints.insert(std::make_pair(c, constraint)); } void Table::addConstraint(const StringVector& columns, std::shared_ptr constraint) { IndexedColumnVector c; std::transform(columns.begin(), columns.end(), std::back_inserter(c), [](const auto& e) { return IndexedColumn(e, false); }); m_indexConstraints.insert(std::make_pair(c, constraint)); } void Table::addConstraint(const IndexedColumnVector& columns, std::shared_ptr constraint) { StringVector c; std::transform(columns.begin(), columns.end(), std::back_inserter(c), [](const auto& e) { return e.name(); }); m_foreignKeys.insert(std::make_pair(c, constraint)); } void Table::removeConstraint(std::shared_ptr constraint) { auto c = std::find_if(m_indexConstraints.begin(), m_indexConstraints.end(), [constraint](const auto& e) { return e.second == constraint; }); if(c != m_indexConstraints.end()) m_indexConstraints.erase(c); } void Table::removeConstraint(std::shared_ptr constraint) { auto c = std::find_if(m_foreignKeys.begin(), m_foreignKeys.end(), [constraint](const auto& e) { return e.second == constraint; }); if(c != m_foreignKeys.end()) m_foreignKeys.erase(c); } void Table::removeConstraint(std::shared_ptr constraint) { m_checkConstraints.erase(std::remove_if(m_checkConstraints.begin(), m_checkConstraints.end(), [constraint](const auto& e) { return e == constraint; })); } void Table::addKeyToConstraint(std::shared_ptr constraint, const std::string& key) { // Search for matching constraint for(auto it=m_indexConstraints.begin();it!=m_indexConstraints.end();++it) { if(it->second == constraint) { // Add key to the column list auto new_columns = it->first; new_columns.emplace_back(key, false); m_indexConstraints.insert(std::make_pair(new_columns, it->second)); it = m_indexConstraints.erase(it); } } } void Table::removeKeyFromConstraint(std::shared_ptr constraint, const std::string& key) { for(auto it=m_indexConstraints.begin();it!=m_indexConstraints.end();++it) { if(it->second == constraint) { // Remove key from the column list std::remove_const_tfirst)> new_columns; std::copy_if(it->first.begin(), it->first.end(), std::back_inserter(new_columns), [key](const auto& c) { return c != key; }); // If the column list is empty now, remove the entire constraint. Otherwise save the updated column list if(new_columns.empty()) { it = m_indexConstraints.erase(it); } else { m_indexConstraints.insert(std::make_pair(new_columns, it->second)); it = m_indexConstraints.erase(it); } // If container is empty now, return here instead of advancing the iterator if(m_indexConstraints.empty()) return; } } } void Table::removeKeyFromAllConstraints(const std::string& key) { auto match_and_remove = [key](auto& container, auto& it) { // Check if they contain the old key name if(contains(it->first, key)) { // If so, remove it from the column list std::remove_const_tfirst)> new_columns; std::copy_if(it->first.begin(), it->first.end(), std::back_inserter(new_columns), [key](const auto& c) { return c != key; }); // If the column list is empty now, remove the entire constraint. Otherwise save the updated column list if(new_columns.empty()) { it = container.erase(it); } else { container.insert(std::make_pair(new_columns, it->second)); it = container.erase(it); } // If container is empty now, return here instead of advancing the iterator if(container.empty()) return; } }; for(auto it=m_indexConstraints.begin();it!=m_indexConstraints.end();++it) match_and_remove(m_indexConstraints, it); for(auto it=m_foreignKeys.begin();it!=m_foreignKeys.end();++it) match_and_remove(m_foreignKeys, it); } void Table::renameKeyInAllConstraints(const std::string& key, const std::string& to) { // Do nothing if the key hasn't really changed if(key == to) return; const auto match_and_rename = [key, to](auto& container, auto& it, const auto& rename) { // Check if they contain the old key name if(contains(it->first, key)) { // If so, update it in the column list std::remove_const_tfirst)> new_columns; std::transform(it->first.begin(), it->first.end(), std::back_inserter(new_columns), [rename](auto c) { return rename(c); }); container.insert(std::make_pair(new_columns, it->second)); it = container.erase(it); } }; // Update all constraints for(auto it=m_indexConstraints.begin();it!=m_indexConstraints.end();++it) { match_and_rename(m_indexConstraints, it, [key, to](IndexedColumn c) { if(c == key) c.setName(to); return c; }); } for(auto it=m_foreignKeys.begin();it!=m_foreignKeys.end();++it) match_and_rename(m_foreignKeys, it, [key, to](const std::string& c) { return c == key ? to : c; }); } std::shared_ptr Table::primaryKey() const { const auto it = std::find_if(m_indexConstraints.begin(), m_indexConstraints.end(), [](const auto& e) { return e.second->isPrimaryKey(); }); if(it != m_indexConstraints.end()) return std::dynamic_pointer_cast(it->second); return nullptr; } IndexedColumnVector Table::primaryKeyColumns() const { const auto it = std::find_if(m_indexConstraints.begin(), m_indexConstraints.end(), [](const auto& e) { return e.second->isPrimaryKey(); }); if(it != m_indexConstraints.end()) return it->first; return {}; } std::shared_ptr Table::foreignKey(const StringVector& columns) const { const auto it = std::find_if(m_foreignKeys.begin(), m_foreignKeys.end(), [columns](const auto& e) { return e.first == columns; }); if(it != m_foreignKeys.end()) return it->second; return nullptr; } std::string IndexedColumn::toString(const std::string& indent, const std::string& sep) const { std::string name = m_isExpression ? m_name : escapeIdentifier(m_name); std::string order = (m_order.empty() ? "" : (sep + m_order)); return indent + name + order; } Index& Index::operator=(const Index& rhs) { // Base class Object::operator=(rhs); // Just assign the easy stuff m_unique = rhs.m_unique; m_table = rhs.m_table; m_whereExpr = rhs.m_whereExpr; // Make copies of the column std::copy(rhs.fields.begin(), rhs.fields.end(), std::back_inserter(fields)); return *this; } StringVector Index::columnSqlList() const { StringVector sl; std::transform(fields.begin(), fields.end(), std::back_inserter(sl), [](const auto& c) { return c.toString(); }); return sl; } std::string Index::sql(const std::string& schema, bool ifNotExists) const { // Start CREATE (UNIQUE) INDEX statement std::string sql; if(m_unique) sql = "CREATE UNIQUE INDEX "; else sql = "CREATE INDEX "; if(ifNotExists) sql += "IF NOT EXISTS "; sql += ObjectIdentifier(schema, m_name).toString(true); sql += " ON "; sql += sqlb::escapeIdentifier(m_table); sql += " (\n"; // Add column list sql += joinStringVector(columnSqlList(), ",\n"); // Add partial index bit sql += "\n)"; if(!m_whereExpr.empty()) sql += " WHERE " + m_whereExpr; return sql + ";"; } IndexPtr Index::parseSQL(const std::string& sSQL) { parser::ParserDriver drv; if(!drv.parse(sSQL)) { IndexPtr i = std::dynamic_pointer_cast(drv.result); i->setOriginalSql(sSQL); return i; } else { std::cerr << "Sqlite parse error: " << sSQL << std::endl; IndexPtr i = std::make_shared(""); i->setOriginalSql(sSQL); return i; } } template<> std::string getBaseTable(IndexPtr object) { return object->table(); } ViewPtr View::parseSQL(const std::string& sSQL) { // TODO auto v = std::make_shared(""); v->setOriginalSql(sSQL); return v; } TriggerPtr Trigger::parseSQL(const std::string& sSQL) { // TODO auto t = std::make_shared(""); t->setOriginalSql(sSQL); return t; } template<> std::string getBaseTable(TriggerPtr object) { return object->table(); } } //namespace sqlb sqlitebrowser-sqlitebrowser-5733cb7/src/sql/sqlitetypes.h000066400000000000000000000527421463772530400240330ustar00rootroot00000000000000#pragma once #ifndef SQLITETYPES_H #define SQLITETYPES_H #include #include #include #include #include #include #include #include template bool contains(const C& container, E element) { return std::find(container.begin(), container.end(), element) != container.end(); } template bool contains(const std::map& container, E element) { return container.find(element) != container.end(); } template bool compare_ci(const T& a, const T& b) { // Note: This function does not have to be (actually it must not be) fully UTF-8 aware because SQLite itself is not either. return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](unsigned char c1, unsigned char c2) { return std::tolower(c1) == std::tolower(c2); }); } template bool compare_ci(const T& a, const char* b) { return compare_ci(a, std::string(b)); } inline bool starts_with_ci(const std::string& str, const std::string& with) { if(str.size() < with.size()) return false; else return compare_ci(str.substr(0, with.size()), with); } namespace sqlb { using StringVector = std::vector; class Object; class Table; class Index; class View; class Trigger; class Field; class Constraint; class IndexedColumn; using ObjectPtr = std::shared_ptr; using TablePtr = std::shared_ptr
; using IndexPtr = std::shared_ptr; using ViewPtr = std::shared_ptr; using TriggerPtr = std::shared_ptr; using FieldVector = std::vector; using IndexedColumnVector = std::vector; StringVector escapeIdentifier(StringVector ids); std::string joinStringVector(const StringVector& vec, const std::string& delim); std::string joinStringVector(const IndexedColumnVector& vec, const std::string& delim); class Object { public: explicit Object(const std::string& name): m_name(name), m_fullyParsed(false) {} virtual ~Object() = default; bool operator==(const Object& rhs) const; void setName(const std::string& name) { m_name = name; } const std::string& name() const { return m_name; } void setOriginalSql(const std::string& original_sql) { m_originalSql = original_sql; } std::string originalSql() const { return m_originalSql; } void setFullyParsed(bool fully_parsed) { m_fullyParsed = fully_parsed; } bool fullyParsed() const { return m_fullyParsed; } /** * @brief Returns the CREATE statement for this object * @param schema The schema name of the object * @param ifNotExists If set to true the "IF NOT EXISTS" qualifier will be added to the create statement * @return A std::string with the CREATE statement. */ virtual std::string sql(const std::string& schema = std::string("main"), bool ifNotExists = false) const = 0; protected: std::string m_name; std::string m_originalSql; bool m_fullyParsed; }; class Constraint { public: void setName(const std::string& name) { m_name = name; } const std::string& name() const { return m_name; } protected: std::string m_name; }; class ForeignKeyClause : public Constraint { public: explicit ForeignKeyClause(const std::string& table = std::string(), const StringVector& columns = {}, const std::string& constraint = std::string()) : m_table(table), m_columns(columns), m_constraint(constraint) { } std::string toString() const; void setTable(const std::string& table) { m_table = table; } const std::string& table() const { return m_table; } void setColumns(const StringVector& columns) { m_columns = columns; } const StringVector& columns() const { return m_columns; } void setConstraint(const std::string& constraint) { m_constraint = constraint; } const std::string& constraint() const { return m_constraint; } std::string toSql(const StringVector& columns) const; private: std::string m_table; StringVector m_columns; std::string m_constraint; }; class UniqueConstraint : public Constraint { public: virtual ~UniqueConstraint() = default; void setConflictAction(const std::string& conflict) { m_conflictAction = conflict; } const std::string& conflictAction() const { return m_conflictAction; } virtual std::string toSql(const IndexedColumnVector& columns) const; virtual bool isPrimaryKey() const { return false; } protected: std::string m_conflictAction; }; class NotNullConstraint : public Constraint { public: void setConflictAction(const std::string& conflict) { m_conflictAction = conflict; } const std::string& conflictAction() const { return m_conflictAction; } std::string toSql() const; protected: std::string m_conflictAction; }; class PrimaryKeyConstraint : public UniqueConstraint { // Primary keys are a sort of unique constraint for us. This matches quite nicely as both can have a conflict action // and both need to maintain a copy of the column list with sort order information etc. public: PrimaryKeyConstraint() : m_auto_increment(false) {} void setAutoIncrement(bool ai) { m_auto_increment = ai; } bool autoIncrement() const { return m_auto_increment; } bool isPrimaryKey() const override { return true; } std::string toSql(const IndexedColumnVector& columns) const override; private: bool m_auto_increment; }; class CheckConstraint : public Constraint { public: explicit CheckConstraint(const std::string& expr = std::string()) : m_expression(expr) { } void setExpression(const std::string& expr) { m_expression = expr; } const std::string& expression() const { return m_expression; } std::string toSql() const; private: std::string m_expression; }; class DefaultConstraint : public Constraint { public: explicit DefaultConstraint(const std::string& value = std::string()) : m_value(value) { } void setValue(const std::string& value) { m_value = value; } const std::string& value() const { return m_value; } std::string toSql() const; private: std::string m_value; }; class CollateConstraint : public Constraint { public: explicit CollateConstraint(const std::string& collation) : m_collation(collation) { } void setCollation(const std::string& collation) { m_collation = collation; } const std::string& collation() const { return m_collation; } std::string toSql() const; private: std::string m_collation; }; class GeneratedColumnConstraint : public Constraint { public: explicit GeneratedColumnConstraint(const std::string& expr = std::string(), const std::string& storage = "VIRTUAL") : m_expression(expr), m_storage(storage) { } void setExpression(const std::string& expr) { m_expression = expr; } const std::string& expression() const { return m_expression; } void setStorage(const std::string& storage) { m_storage = storage; } std::string storage() const { return m_storage.empty() ? "VIRTUAL" : m_storage; } std::string toSql() const; private: std::string m_expression; std::string m_storage; }; class Field { public: Field() {} Field(const std::string& name, const std::string& type, bool notnull = false, const std::string& defaultvalue = std::string(), const std::string& check = std::string(), bool unique = false, const std::string& collation = std::string()) : m_name(name) , m_type(type) , m_notnull(notnull ? std::make_shared() : nullptr) , m_check(check.empty() ? nullptr : std::make_shared(check)) , m_defaultvalue(defaultvalue.empty() ? nullptr : std::make_shared(defaultvalue)) , m_unique(unique ? std::make_shared() : nullptr) , m_collation(collation.empty() ? nullptr : std::make_shared(collation)) {} bool operator==(const Field& rhs) const; std::string toString(const std::string& indent = "\t", const std::string& sep = "\t") const; void setName(const std::string& name) { m_name = name; } void setType(const std::string& type) { m_type = type; } void setNotNull(std::shared_ptr notnull) { m_notnull = notnull; } void setNotNull(bool notnull = true) { if(notnull) m_notnull = std::make_shared(); else m_notnull.reset(); } void setCheck(std::shared_ptr check) { m_check = check; } void setCheck(const std::string& check) { if(!check.empty()) m_check = std::make_shared(check); else m_check.reset(); } void setDefaultValue(std::shared_ptr defaultvalue) { m_defaultvalue = defaultvalue; } void setDefaultValue(const std::string& value) { if(!value.empty()) m_defaultvalue = std::make_shared(value); else m_defaultvalue.reset(); } void setUnique(std::shared_ptr u) { m_unique = u; } void setUnique(bool u) { if(u) m_unique = std::make_shared(); else m_unique.reset(); } void setCollation(std::shared_ptr c) { m_collation = c; } void setCollation(const std::string& collation) { if(!collation.empty()) m_collation = std::make_shared(collation); else m_collation.reset(); } bool isText() const; bool isInteger() const; bool isBlob() const; bool isReal() const; bool isNumeric() const; // Type affinity of the column according to SQLite3 rules. // The Affinity enum values match the SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_BLOB, and SQLITE_TEXT constants enum Affinity { IntegerAffinity = 1, FloatAffinity = 2, TextAffinity = 3, BlobAffinity = 4, }; Affinity affinity() const; const std::string& name() const { return m_name; } const std::string& type() const { return m_type; } bool notnull() const { return m_notnull ? true : false; } std::string check() const { return m_check ? m_check->expression() : std::string{}; } std::string defaultValue() const { return m_defaultvalue ? m_defaultvalue->value() : std::string{}; } bool unique() const { return m_unique ? true : false; } std::string collation() const { return m_collation ? m_collation->collation() : std::string{}; } const std::shared_ptr generated() const { return m_generated; } std::shared_ptr generated() { return m_generated; } void setGenerated(std::shared_ptr gen) { m_generated = gen; } private: std::string m_name; std::string m_type; std::shared_ptr m_notnull; std::shared_ptr m_check; std::shared_ptr m_defaultvalue; std::shared_ptr m_unique; std::shared_ptr m_collation; std::shared_ptr m_generated; }; class Table : public Object { public: explicit Table(const std::string& name): Object(name) {} explicit Table(const Table& table); Table& operator=(const Table& rhs); bool operator==(const Table& rhs) const; virtual bool isView() const { return false; } FieldVector fields; using field_type = Field; using field_iterator = FieldVector::iterator; enum Options { WithoutRowid, Strict, NumOptions }; /** * @brief Returns the CREATE TABLE statement for this table object * @return A std::string with the CREATE TABLE object. */ std::string sql(const std::string& schema = "main", bool ifNotExists = false) const override; StringVector fieldNames() const; StringVector rowidColumns() const; void setWithoutRowidTable(bool without_rowid) { m_options.set(WithoutRowid, without_rowid); } bool withoutRowidTable() const { return m_options.test(WithoutRowid); } void setStrict(bool strict) { m_options.set(Strict, strict); } bool isStrict() const { return m_options.test(Strict); } void setVirtualUsing(const std::string& virt_using) { m_virtual = virt_using; } const std::string& virtualUsing() const { return m_virtual; } bool isVirtual() const { return !m_virtual.empty(); } void addConstraint(const IndexedColumnVector& columns, std::shared_ptr constraint) { m_indexConstraints.insert(std::make_pair(columns, constraint)); } void addConstraint(const IndexedColumnVector& columns, std::shared_ptr constraint) { m_indexConstraints.insert(std::make_pair(columns, constraint)); } void addConstraint(const StringVector& columns, std::shared_ptr constraint) { m_foreignKeys.insert(std::make_pair(columns, constraint)); } void addConstraint(std::shared_ptr constraint) { m_checkConstraints.push_back(constraint); } void removeConstraint(std::shared_ptr constraint); void removeConstraint(std::shared_ptr constraint); void removeConstraint(std::shared_ptr constraint); void addKeyToConstraint(std::shared_ptr constraint, const std::string& key); void removeKeyFromConstraint(std::shared_ptr constraint, const std::string& key); void removeKeyFromAllConstraints(const std::string& key); void renameKeyInAllConstraints(const std::string& key, const std::string& to); // These three functions are helper functions which we need for some templated code. As soon as we // switch to C++17 we should be able to rewrite that code so we can get rid of these. void addConstraint(const StringVector& columns, std::shared_ptr constraint); void addConstraint(const StringVector& columns, std::shared_ptr constraint); void addConstraint(const IndexedColumnVector& columns, std::shared_ptr constraint); std::shared_ptr primaryKey() const; IndexedColumnVector primaryKeyColumns() const; std::multimap> indexConstraints() const { return m_indexConstraints; } std::multimap> foreignKeys() const { return m_foreignKeys; } std::shared_ptr foreignKey(const StringVector& columns) const; //! Only returns the first foreign key, if any std::vector> checkConstraints() const { return m_checkConstraints; } /** * @brief parseSQL Parses the create Table statement in sSQL. * @param sSQL The create table statement. * @return The table object. The table object may be empty if parsing failed. */ static TablePtr parseSQL(const std::string& sSQL); private: StringVector fieldList() const; private: std::multimap> m_indexConstraints; // This stores both UNIQUE and PRIMARY KEY constraints std::multimap> m_foreignKeys; std::vector> m_checkConstraints; std::string m_virtual; std::bitset m_options; }; class IndexedColumn { public: IndexedColumn() : m_isExpression(false) { } IndexedColumn(const std::string& name, bool expr, const std::string& order = std::string()) : m_name(name), m_isExpression(expr), m_order(order) { } bool operator==(const std::string& name) const { return !m_isExpression && m_name == name; } bool operator!=(const std::string& name) const { return !m_isExpression && m_name != name; } bool operator==(const IndexedColumn& other) const { return m_name == other.m_name && m_isExpression == other.m_isExpression && m_order == other.m_order; } bool operator<(const IndexedColumn& other) const { return m_name < other.m_name; } void setName(const std::string& name) { m_name = name; } const std::string& name() const { return m_name; } void setExpression(bool expr) { m_isExpression = expr; } bool expression() const { return m_isExpression; } void setOrder(const std::string& order) { m_order = order; } std::string order() const { return m_order; } std::string toString(const std::string& indent = "\t", const std::string& sep = "\t") const; private: std::string m_name; bool m_isExpression; std::string m_order; }; class Index : public Object { public: explicit Index(const std::string& name): Object(name), m_unique(false) {} Index& operator=(const Index& rhs); IndexedColumnVector fields; using field_type = IndexedColumn; using field_iterator = IndexedColumnVector::iterator; void setUnique(bool unique) { m_unique = unique; } bool unique() const { return m_unique; } void setTable(const std::string& table) { m_table = table; } const std::string& table() const { return m_table; } void setWhereExpr(const std::string& expr) { m_whereExpr = expr; } const std::string& whereExpr() const { return m_whereExpr; } /** * @brief Returns the CREATE INDEX statement for this index object * @return A std::string with the CREATE INDEX object. */ std::string sql(const std::string& schema = "main", bool ifNotExists = false) const override; /** * @brief parseSQL Parses the CREATE INDEX statement in sSQL. * @param sSQL The create index statement. * @return The index object. The index object may be empty if the parsing failed. */ static IndexPtr parseSQL(const std::string& sSQL); private: StringVector columnSqlList() const; bool m_unique; std::string m_table; std::string m_whereExpr; }; class View : public Table { public: explicit View(const std::string& name): Table(name) {} virtual bool isView() const override { return true; } std::string sql(const std::string& /*schema*/ = "main", bool /*ifNotExists*/ = false) const override { /* TODO */ return m_originalSql; } static ViewPtr parseSQL(const std::string& sSQL); }; class Trigger : public Object { public: explicit Trigger(const std::string& name): Object(name) {} std::string sql(const std::string& /*schema*/ = "main", bool /*ifNotExists*/ = false) const override { /* TODO */ return m_originalSql; } static TriggerPtr parseSQL(const std::string& sSQL); void setTable(const std::string& table) { m_table = table; } std::string table() const { return m_table; } private: std::string m_table; }; /** * @brief Return the name of the base table of the given object. For indices and triggers that is the table which the object is related to. */ template std::string getBaseTable(std::shared_ptr /*object*/) { return std::string{}; } template<> std::string getBaseTable(IndexPtr object); template<> std::string getBaseTable(TriggerPtr object); /** * @brief findField Finds a field in the database object and returns an iterator to it. * @param object * @param name * @return The iterator pointing to the field in the field container of the object if the field was found. * object.fields.end() if the field couldn't be found. */ template typename T::field_iterator findField(T* object, const std::string& name) { return std::find_if(object->fields.begin(), object->fields.end(), [&name](const typename T::field_type& f) { return compare_ci(name, f.name()); }); } template typename T::field_iterator findField(const T* object, const std::string& name) { return findField(const_cast(object), name); } template typename std::remove_reference::type::field_iterator findField(std::shared_ptr object, const std::string& name) { return findField(object.get(), name); } template typename std::remove_reference::type::field_iterator findField(T& object, const std::string& name) { return findField(&object, name); } template struct is_shared_ptr : std::false_type {}; template struct is_shared_ptr> : std::true_type {}; /** * @brief removeField Finds and removes a field in the database object * @param object * @param name * @return true if sucessful, otherwise false */ template bool removeField(T* object, const std::string& name) { auto index = findField(object, name); if(index != object->fields.end()) { object->fields.erase(index); return true; } return false; } template::value>::type> bool removeField(T object, const std::string& name) { return removeField(object.get(), name); } template::value>::type> bool removeField(T& object, const std::string& name) { return removeField(&object, name); } /** * @brief getFieldNumber returns the number of the field with the given name in an object. This is supposed to be a temporary helper function only. * @param object * @param name * @return number of the field * * TODO Remove this function. Whereever it is used we make the assumption that the queried columns are exactly equal to the columns of the table or view. * For more complex queries this is not true and in fact it already is a dubious assumption because we also select the rowid column. */ inline size_t getFieldNumber(TablePtr object, const std::string& name) { for(size_t i=0;ifields.size();i++) { if(object->fields[i].name() == name) return i; } return 0; } } //namespace sqlb #endif sqlitebrowser-sqlitebrowser-5733cb7/src/sqlite.h000066400000000000000000000012521463772530400221350ustar00rootroot00000000000000#ifndef SQLITE_H #define SQLITE_H #ifdef ENABLE_SQLCIPHER #define SQLITE_TEMP_STORE 2 #ifndef SQLITE_HAS_CODEC #define SQLITE_HAS_CODEC #endif #ifdef Q_OS_WIN32 #include #else #include #endif #else #include #endif // For older versions of the SQLite library which do not have the SQLITE_DETERMINISTIC flag // yet (which introduced in this commit: https://www.sqlite.org/src/info/5716fc2341ddd8cf), we // define it here with a value of 0. Because it is ORed with other constants a value of 0 is a no-op. #ifndef SQLITE_DETERMINISTIC #define SQLITE_DETERMINISTIC 0 #endif #endif sqlitebrowser-sqlitebrowser-5733cb7/src/sqlitedb.cpp000066400000000000000000002572501463772530400230110ustar00rootroot00000000000000#include "sqlitedb.h" #include "sqlite.h" #include "sqlitetablemodel.h" #include "CipherDialog.h" #include "CipherSettings.h" #include "Settings.h" #include "Data.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QStringList DBBrowserDB::Datatypes = {"INTEGER", "TEXT", "BLOB", "REAL", "NUMERIC"}; QStringList DBBrowserDB::DatatypesStrict = {"INT", "INTEGER", "TEXT", "BLOB", "REAL", "ANY"}; // Helper template to allow turning member functions into a C-style function pointer // See https://stackoverflow.com/questions/19808054/convert-c-function-pointer-to-c-function-pointer/19809787 template struct Callback; template struct Callback { template static Ret callback(Args... args) { return func(args...); } static std::function func; }; template std::function Callback::func; namespace sqlb { QString escapeIdentifier(const QString& id) { return QString::fromStdString(escapeIdentifier(id.toStdString())); } QString escapeString(const QString& literal) { return QString::fromStdString(escapeString(literal.toStdString())); } QString escapeByteArray(const QByteArray& literal) { if(isTextOnly(literal)) return sqlb::escapeString(literal); else return QString("X'%1'").arg(QString(literal.toHex())); }} // collation callbacks int collCompare(void* /*pArg*/, int sizeA, const void* sA, int sizeB, const void* sB) { if(sizeA == sizeB) return memcmp(sA, sB, static_cast(sizeA)); return sizeA - sizeB; } static int sqlite_compare_utf16( void* /*arg*/,int size1, const void *str1, int size2, const void* str2) { const QString string1 = QString::fromRawData(reinterpret_cast(str1), static_cast(static_cast(size1) / sizeof(QChar))); const QString string2 = QString::fromRawData(reinterpret_cast(str2), static_cast(static_cast(size2) / sizeof(QChar))); return QString::compare(string1, string2, Qt::CaseSensitive); } static int sqlite_compare_utf16ci( void* /*arg*/,int size1, const void *str1, int size2, const void* str2) { const QString string1 = QString::fromRawData(reinterpret_cast(str1), static_cast(static_cast(size1) / sizeof(QChar))); const QString string2 = QString::fromRawData(reinterpret_cast(str2), static_cast(static_cast(size2) / sizeof(QChar))); return QString::compare(string1, string2, Qt::CaseInsensitive); } static void sqlite_make_single_value(sqlite3_context* ctx, int num_arguments, sqlite3_value* arguments[]) { QByteArray output; for(int i=0;i(sqlite3_value_text(arguments[i])); char* output_str = new char[static_cast(output.size()) + 1]; std::strcpy(output_str, output); sqlite3_result_text(ctx, output_str, output.size(), [](void* ptr) { char* cptr = static_cast(ptr); delete cptr; }); } DBBrowserDB::DBBrowserDB() : _db(nullptr), db_used(false), isEncrypted(false), isReadOnly(false), disableStructureUpdateChecks(false) { // Register error log callback. This needs to be done before SQLite is first used Callback::func = std::bind(&DBBrowserDB::errorLogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); void (*log_callback)(void*, int, const char*) = static_cast(Callback::callback); sqlite3_config(SQLITE_CONFIG_LOG, log_callback, nullptr); // Enable URI filenames sqlite3_config(SQLITE_CONFIG_URI, 1); } void DBBrowserDB::collationNeeded(void* /*pData*/, sqlite3* /*db*/, int eTextRep, const char* sCollationName) { QString name(sCollationName); // Don't request built-in collations. SQLite requests these collations even though they are built into // the library. Since we have no need for overriding them, we just silently ignore these requests. if(name.compare("BINARY", Qt::CaseInsensitive) && name.compare("NOCASE", Qt::CaseInsensitive) && name.compare("RTRIM", Qt::CaseInsensitive)) { emit requestCollation(name, eTextRep); } } void DBBrowserDB::errorLogCallback(void* /*user_data*/, int error_code, const char* message) { QString msg = QString("(%1) %2").arg(error_code).arg(message); logSQL(msg, kLogMsg_ErrorLog); } static void regexp(sqlite3_context* ctx, int /*argc*/, sqlite3_value* argv[]) { // This is a cache for the last 50 regular expressions. Compiling them takes some time, so we want to cache the compiled // regular expressions for performance purposes. static std::array, 50> regex_cache; // Check if pattern is in cache QString pattern{reinterpret_cast(sqlite3_value_text(argv[0]))}; QRegularExpression regex; const auto it = std::find_if(regex_cache.begin(), regex_cache.end(), [pattern](const std::pair& val) { return val.first == pattern; }); if(it == regex_cache.end()) { // Pattern is not in cache. Create a new regular expressions object, compile it, and insert it into the cache regex.setPattern(pattern); regex.setPatternOptions(QRegularExpression::UseUnicodePropertiesOption); if(!regex.isValid()) return sqlite3_result_error(ctx, "invalid operand", -1); regex.optimize(); static size_t regex_cache_size; regex_cache_size = (regex_cache_size + 1) % regex_cache.size(); regex_cache[regex_cache_size] = {pattern, regex}; } else { // Pattern is in the cache. Just retrieve it regex = it->second; } // Get arguments and check their values QString arg2{reinterpret_cast(sqlite3_value_text(argv[1]))}; // Perform the actual matching and return the result. // SQLite expects a 0 for not found and a 1 for found. sqlite3_result_int(ctx, regex.match(arg2).hasMatch()); } bool DBBrowserDB::isOpen ( ) const { return _db != nullptr; } bool DBBrowserDB::getDirty() const { return !savepointList.empty(); } bool DBBrowserDB::open(const QString& db, bool readOnly) { if (isOpen()) close(); isEncrypted = false; disableStructureUpdateChecks = false; // Get encryption settings for database file CipherSettings cipherSettings; if(tryEncryptionSettings(db, &isEncrypted, &cipherSettings) == false) return false; // Open database file if(sqlite3_open_v2(db.toUtf8(), &_db, readOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE, nullptr) != SQLITE_OK) { lastErrorMessage = QString::fromUtf8(sqlite3_errmsg(_db)); return false; } // Set encryption details if database is encrypted #ifdef ENABLE_SQLCIPHER if(isEncrypted) { executeSQL("PRAGMA key = " + cipherSettings.getPassword(), false, false); executeSQL("PRAGMA cipher_page_size = " + std::to_string(cipherSettings.getPageSize()), false, false); executeSQL("PRAGMA kdf_iter = " + std::to_string(cipherSettings.getKdfIterations()), false, false); executeSQL("PRAGMA cipher_hmac_algorithm = " + cipherSettings.getHmacAlgorithm(), false, false); executeSQL("PRAGMA cipher_kdf_algorithm = " + cipherSettings.getKdfAlgorithm(), false, false); executeSQL("PRAGMA cipher_plaintext_header_size = " + std::to_string(cipherSettings.getPlaintextHeaderSize()), false, false); } #endif if (_db) { // add UTF16 collation (comparison is performed by QString functions) sqlite3_create_collation(_db, "UTF16", SQLITE_UTF16, nullptr, sqlite_compare_utf16); // add UTF16CI (case insensitive) collation (comparison is performed by QString functions) sqlite3_create_collation(_db, "UTF16CI", SQLITE_UTF16, nullptr, sqlite_compare_utf16ci); // register collation callback Callback::func = std::bind(&DBBrowserDB::collationNeeded, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); void (*c_callback)(void*, sqlite3*, int, const char*) = static_cast(Callback::callback); sqlite3_collation_needed(_db, nullptr, c_callback); // Set foreign key settings as requested in the preferences bool foreignkeys = Settings::getValue("db", "foreignkeys").toBool(); setPragma("foreign_keys", foreignkeys ? "1" : "0"); // Register REGEXP function if(Settings::getValue("extensions", "disableregex").toBool() == false) sqlite3_create_function(_db, "REGEXP", 2, SQLITE_UTF8, nullptr, regexp, nullptr, nullptr); // Register our internal helper function for putting multiple values into a single column sqlite3_create_function_v2( _db, "sqlb_make_single_value", -1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr, sqlite_make_single_value, nullptr, nullptr, nullptr ); // Check if file is read only. In-memory databases are never read only if(db == ":memory:") { isReadOnly = false; } else { QFileInfo fi(db); QFileInfo fid(fi.absoluteDir().absolutePath()); isReadOnly = readOnly || !fi.isWritable() || !fid.isWritable(); } // Load extensions loadExtensionsFromSettings(); // Execute default SQL if(!isReadOnly) { QByteArray default_sql = Settings::getValue("db", "defaultsqltext").toByteArray(); if(!default_sql.isEmpty()) executeMultiSQL(default_sql, false, true); } curDBFilename = db; updateSchema(); return true; } else { return false; } } /** detaches a previously attached database identified with its alias-name **/ bool DBBrowserDB::detach(const std::string& attached_as) { if(!_db) { return false; } waitForDbRelease(); // detach database if(!executeSQL("DETACH " + sqlb::escapeIdentifier(attached_as) + ";", false)) { QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); return false; } // Update schema to load database schema of the newly attached database updateSchema(); return true; } bool DBBrowserDB::attach(const QString& filePath, QString attach_as) { if(!_db) return false; waitForDbRelease(); // In shared cache mode, attempting to attach the same database file more than once results in an error. // So no need for a check if this file has already been attached and abort if this is the case // Ask for name to be given to the attached database if none was provided if(attach_as.isEmpty()) { attach_as = QInputDialog::getText(nullptr, qApp->applicationName(), tr("Please specify the database name under which you want to access the attached database"), QLineEdit::Normal, QFileInfo(filePath).baseName() ).trimmed(); } if(attach_as.isNull()) return false; #ifdef ENABLE_SQLCIPHER // Try encryption settings CipherSettings cipherSettings; bool is_encrypted; if(tryEncryptionSettings(filePath, &is_encrypted, &cipherSettings) == false) return false; // Attach database std::string key; if(is_encrypted) key = "KEY " + cipherSettings.getPassword(); else key = "KEY ''"; // Only apply cipher settings if the database is encrypted if(is_encrypted) { if(!executeSQL("PRAGMA cipher_default_page_size = " + std::to_string(cipherSettings.getPageSize()), false)) { QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); return false; } if(!executeSQL("PRAGMA cipher_default_kdf_iter = " + std::to_string(cipherSettings.getKdfIterations()), false)) { QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); return false; } if(!executeSQL("PRAGMA cipher_hmac_algorithm = " + cipherSettings.getHmacAlgorithm(), false)) { QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); return false; } if(!executeSQL("PRAGMA cipher_kdf_algorithm = " + cipherSettings.getKdfAlgorithm(), false)) { QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); return false; } if(!executeSQL("PRAGMA cipher_plaintext_header_size = " + std::to_string(cipherSettings.getPlaintextHeaderSize()), false)) { QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); return false; } } if(!executeSQL("ATTACH " + sqlb::escapeString(filePath.toStdString()) + " AS " + sqlb::escapeIdentifier(attach_as.toStdString()) + " " + key, false)) { QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); return false; } // Clean up cipher settings #else // Attach database if(!executeSQL("ATTACH " + sqlb::escapeString(filePath.toStdString()) + " AS " + sqlb::escapeIdentifier(attach_as.toStdString()), false)) { QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); return false; } #endif // Update schema to load database schema of the newly attached database updateSchema(); return true; } bool DBBrowserDB::tryEncryptionSettings(const QString& filePath, bool* encrypted, CipherSettings* cipherSettings) const { lastErrorMessage = tr("Invalid file format"); // Open database file sqlite3* dbHandle; if(sqlite3_open_v2(filePath.toUtf8(), &dbHandle, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) return false; // Try reading from database #ifdef ENABLE_SQLCIPHER bool isDotenvChecked = false; // Determine default encryption settings depending on the SQLCipher version we use QString sqlite_version, sqlcipher_version; getSqliteVersion(sqlite_version, sqlcipher_version); int enc_default_page_size, enc_default_kdf_iter; int enc_default_plaintext_header_size = 0; std::string enc_default_hmac_algorithm, enc_default_kdf_algorithm; if(sqlcipher_version.startsWith('4')) { enc_default_page_size = 4096; enc_default_kdf_iter = 256000; enc_default_hmac_algorithm = "SHA512"; enc_default_kdf_algorithm = "SHA512"; } else { enc_default_page_size = 1024; enc_default_kdf_iter = 64000; enc_default_hmac_algorithm = "SHA1"; enc_default_kdf_algorithm = "SHA1"; } #endif *encrypted = false; while(true) { const std::string statement = "SELECT COUNT(*) FROM sqlite_master;"; sqlite3_stmt* vm; const char* tail; int err = sqlite3_prepare_v2(dbHandle, statement.c_str(), static_cast(statement.size()), &vm, &tail); if(err == SQLITE_BUSY || err == SQLITE_PERM || err == SQLITE_NOMEM || err == SQLITE_IOERR || err == SQLITE_CORRUPT || err == SQLITE_CANTOPEN) { lastErrorMessage = QString::fromUtf8(sqlite3_errmsg(dbHandle)); sqlite3_close_v2(dbHandle); return false; } if(sqlite3_step(vm) != SQLITE_ROW) { sqlite3_finalize(vm); #ifdef ENABLE_SQLCIPHER bool foundDotenvPassword = false; // Being in a while loop, we don't want to check the same file multiple times if (!isDotenvChecked) { QFile databaseFile(filePath); QFileInfo databaseFileInfo(databaseFile); QString databaseDirectoryPath = databaseFileInfo.dir().path(); QString databaseFileName(databaseFileInfo.fileName()); QString dotenvFilePath = databaseDirectoryPath + "/.env"; QSettings dotenv(dotenvFilePath, QSettings::IniFormat); QVariant passwordValue = dotenv.value(databaseFileName); foundDotenvPassword = !passwordValue.isNull(); isDotenvChecked = true; if (foundDotenvPassword) { std::string password = passwordValue.toString().toStdString(); QVariant keyFormatValue = dotenv.value(databaseFileName + "_keyFormat", QVariant(CipherSettings::KeyFormats::Passphrase)); CipherSettings::KeyFormats keyFormat = CipherSettings::getKeyFormat(keyFormatValue.toInt()); int pageSize = dotenv.value(databaseFileName + "_pageSize", enc_default_page_size).toInt(); int kdfIterations = dotenv.value(databaseFileName + "_kdfIter", enc_default_kdf_iter).toInt(); int plaintextHeaderSize = dotenv.value(databaseFileName + "_plaintextHeaderSize", enc_default_plaintext_header_size).toInt(); std::string hmacAlgorithm = dotenv.value(databaseFileName + "_hmacAlgorithm", QString::fromStdString(enc_default_hmac_algorithm)).toString().toStdString(); std::string kdfAlgorithm = dotenv.value(databaseFileName + "_kdfAlgorithm", QString::fromStdString(enc_default_kdf_algorithm)).toString().toStdString(); cipherSettings->setKeyFormat(keyFormat); cipherSettings->setPassword(password); cipherSettings->setPageSize(pageSize); cipherSettings->setKdfIterations(kdfIterations); cipherSettings->setHmacAlgorithm("HMAC_" + hmacAlgorithm); cipherSettings->setKdfAlgorithm("PBKDF2_HMAC_" + kdfAlgorithm); cipherSettings->setPlaintextHeaderSize(plaintextHeaderSize); } } if(foundDotenvPassword) { // Skip the CipherDialog prompt for now to test if the dotenv settings are correct } else { CipherDialog *cipherDialog = new CipherDialog(nullptr, false); if(cipherDialog->exec()) { *cipherSettings = cipherDialog->getCipherSettings(); } else { sqlite3_close_v2(dbHandle); *encrypted = false; return false; } } // Close and reopen database first to be in a clean state after the failed read attempt from above sqlite3_close_v2(dbHandle); if(sqlite3_open_v2(filePath.toUtf8(), &dbHandle, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) return false; // Set the key sqlite3_exec(dbHandle, ("PRAGMA key = " + cipherSettings->getPassword()).c_str(), nullptr, nullptr, nullptr); // Set the settings if they differ from the default values if(cipherSettings->getPageSize() != enc_default_page_size) sqlite3_exec(dbHandle, ("PRAGMA cipher_page_size = " + std::to_string(cipherSettings->getPageSize())).c_str(), nullptr, nullptr, nullptr); if(cipherSettings->getKdfIterations() != enc_default_kdf_iter) sqlite3_exec(dbHandle, ("PRAGMA kdf_iter = " + std::to_string(cipherSettings->getKdfIterations())).c_str(), nullptr, nullptr, nullptr); if(cipherSettings->getHmacAlgorithm() != enc_default_hmac_algorithm) sqlite3_exec(dbHandle, ("PRAGMA cipher_hmac_algorithm = " + cipherSettings->getHmacAlgorithm()).c_str(), nullptr, nullptr, nullptr); if(cipherSettings->getKdfAlgorithm() != enc_default_kdf_algorithm) sqlite3_exec(dbHandle, ("PRAGMA cipher_kdf_algorithm = " + cipherSettings->getKdfAlgorithm()).c_str(), nullptr, nullptr, nullptr); if(cipherSettings->getPlaintextHeaderSize() != enc_default_plaintext_header_size) sqlite3_exec(dbHandle, ("PRAGMA cipher_plaintext_header_size = " + std::to_string(cipherSettings->getPlaintextHeaderSize())).c_str(), nullptr, nullptr, nullptr); *encrypted = true; #else lastErrorMessage = QString::fromUtf8(sqlite3_errmsg(dbHandle)); sqlite3_close_v2(dbHandle); return false; #endif } else { sqlite3_finalize(vm); sqlite3_close_v2(dbHandle); return true; } } } void DBBrowserDB::getSqliteVersion(QString& sqlite, QString& sqlcipher) { sqlite = QString(SQLITE_VERSION); // The SQLCipher version must be queried via a pragma and for a pragma we need a database connection. // Because we want to be able to query the SQLCipher version without opening a database file first, we // open a separate connection to an in-memory database here. sqlcipher = QString(); #ifdef ENABLE_SQLCIPHER sqlite3* dummy; if(sqlite3_open(":memory:", &dummy) == SQLITE_OK) { sqlite3_stmt* stmt; if(sqlite3_prepare_v2(dummy, "PRAGMA cipher_version", -1, &stmt, nullptr) == SQLITE_OK) { if(sqlite3_step(stmt) == SQLITE_ROW) sqlcipher = QByteArray(static_cast(sqlite3_column_blob(stmt, 0)), sqlite3_column_bytes(stmt, 0)); sqlite3_finalize(stmt); } sqlite3_close_v2(dummy); } #endif } bool DBBrowserDB::setSavepoint(const std::string& pointname, bool unique) { if(!isOpen()) return false; if(isReadOnly) { qWarning() << "setSavepoint: not done. DB is read-only"; return false; } if(unique && contains(savepointList, pointname)) return true; executeSQL("SAVEPOINT " + sqlb::escapeIdentifier(pointname) + ";", false, true); savepointList.push_back(pointname); emit dbChanged(getDirty()); return true; } bool DBBrowserDB::releaseSavepoint(const std::string& pointname) { if(!isOpen()) return false; if(contains(savepointList, pointname) == false) // If there is no such savepoint in the list, // we have already released it, so in this case // the operation should be successfull return true; if(!executeSQL("RELEASE " + sqlb::escapeIdentifier(pointname) + ";", false, true)) return false; // SQLite releases all savepoints that were created between // creation of given savepoint and releasing of it, // so we should too auto it = std::find(savepointList.rbegin(), savepointList.rend(), pointname).base() - 1; savepointList.erase(it, savepointList.end()); emit dbChanged(getDirty()); return true; } bool DBBrowserDB::revertToSavepoint(const std::string& pointname) { if(!isOpen() || contains(savepointList, pointname) == false) return false; executeSQL("ROLLBACK TO SAVEPOINT " + sqlb::escapeIdentifier(pointname) + ";", false, true); executeSQL("RELEASE " + sqlb::escapeIdentifier(pointname) + ";", false, true); // SQLite releases all savepoints that were created between // creation of given savepoint and releasing of it, // so we should too auto it = std::find(savepointList.rbegin(), savepointList.rend(), pointname).base() - 1; savepointList.erase(it, savepointList.end()); emit dbChanged(getDirty()); return true; } bool DBBrowserDB::releaseAllSavepoints() { if(!_db) return false; waitForDbRelease(); while(!savepointList.empty()) { if(!releaseSavepoint(savepointList.front())) return false; } // When still in a transaction, commit that too if(sqlite3_get_autocommit(_db) == 0) executeSQL("COMMIT;", false, true); return true; } bool DBBrowserDB::revertAll() { while(!savepointList.empty()) { if(!revertToSavepoint(savepointList.front())) return false; } return true; } bool DBBrowserDB::create ( const QString & db) { if (isOpen()) close(); // read encoding from settings and open with sqlite3_open for utf8 and sqlite3_open16 for utf16 QString sEncoding = Settings::getValue("db", "defaultencoding").toString(); int openresult = SQLITE_OK; if(sEncoding == "UTF-8" || sEncoding == "UTF8" || sEncoding == "Latin1") openresult = sqlite3_open(db.toUtf8(), &_db); else openresult = sqlite3_open16(db.utf16(), &_db); if( openresult != SQLITE_OK ){ lastErrorMessage = QString::fromUtf8(sqlite3_errmsg(_db)); sqlite3_close_v2(_db); _db = nullptr; return false; } if (_db) { // force sqlite3 do write proper file header // if we don't create and drop the table we might end up // with a 0 byte file, if the user cancels the create table dialog { NoStructureUpdateChecks nup(*this); executeSQL("CREATE TABLE notempty (id integer primary key);", false, false); executeSQL("DROP TABLE notempty;", false, false); } // Close database and open it through the code for opening existing database files. This is slightly less efficient but saves us some duplicate // code. sqlite3_close_v2(_db); return open(db); } else { return false; } } bool DBBrowserDB::close() { // Do nothing if no file is opened if(!_db) return true; waitForDbRelease(); if (getDirty()) { // In-memory databases can't be saved to disk. So the need another text than regular databases. // Note that the QMessageBox::Yes option in the :memory: case and the QMessageBox::No option in the regular case are // doing the same job: proceeding but not saving anything. QMessageBox::StandardButton reply; if(curDBFilename == ":memory:") { reply = QMessageBox::question(nullptr, QApplication::applicationName(), tr("Do you really want to close this temporary database? All data will be lost."), QMessageBox::Yes | QMessageBox::Cancel); } else { reply = QMessageBox::question(nullptr, QApplication::applicationName(), tr("Do you want to save the changes made to the database file %1?").arg(curDBFilename), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); } // If the user clicked the cancel button stop here and return false if(reply == QMessageBox::Cancel) return false; // If he didn't it was either yes or no if(reply == QMessageBox::Save) releaseAllSavepoints(); else revertAll(); //not really necessary, I think... but will not hurt. } if(sqlite3_close_v2(_db) != SQLITE_OK) qWarning() << tr("Database didn't close correctly, probably still busy"); _db = nullptr; curDBFilename.clear(); schemata.clear(); savepointList.clear(); emit dbChanged(getDirty()); emit structureUpdated(); // Return true to tell the calling function that the closing wasn't cancelled by the user return true; } bool DBBrowserDB::saveAs(const std::string& filename) { if(!_db) return false; waitForDbRelease(); // Open the database file identified by filename. Exit early if this fails // for any reason. sqlite3* pTo; int rc = sqlite3_open(filename.c_str(), &pTo); if(rc!=SQLITE_OK) { qWarning() << tr("Cannot open destination file: '%1'").arg(filename.c_str()); return false; } else { // Set up the backup procedure to copy from the "main" database of // connection _db to the main database of connection pTo. // If something goes wrong, pBackup will be set to nullptr and an error // code and message left in connection pTo. // // If the backup object is successfully created, call backup_step() // to copy data from _db to pTo. Then call backup_finish() // to release resources associated with the pBackup object. If an // error occurred, then an error code and message will be left in // connection pTo. If no error occurred, then the error code belonging // to pTo is set to SQLITE_OK. // sqlite3_backup* pBackup = sqlite3_backup_init(pTo, "main", _db, "main"); if(pBackup == nullptr) { qWarning() << tr("Cannot backup to file: '%1'. Message: %2").arg(filename.c_str(), sqlite3_errmsg(pTo)); sqlite3_close_v2(pTo); return false; } else { sqlite3_backup_step(pBackup, -1); sqlite3_backup_finish(pBackup); } rc = sqlite3_errcode(pTo); } if(rc == SQLITE_OK) { // Close current database and set backup as current sqlite3_close_v2(_db); _db = pTo; curDBFilename = QString::fromStdString(filename); return true; } else { qWarning() << tr("Cannot backup to file: '%1'. Message: %2").arg(filename.c_str(), sqlite3_errmsg(pTo)); // Close failed database connection. sqlite3_close_v2(pTo); return false; } } DBBrowserDB::db_pointer_type DBBrowserDB::get(const QString& user, bool force_wait) { if(!_db) return nullptr; waitForDbRelease(force_wait ? Wait : Ask); db_user = user; db_used = true; emit databaseInUseChanged(true, user); return db_pointer_type(_db, DatabaseReleaser(this)); } void DBBrowserDB::waitForDbRelease(ChoiceOnUse choice) const { if(!_db) return; // We can't show a message box from another thread than the main thread. So instead of crashing we // just decide that we don't interrupt any running query in this case. if(choice == Ask && QThread::currentThread() != QApplication::instance()->thread()) choice = Wait; std::unique_lock lk(m); while(db_used) { // notify user, give him the opportunity to cancel that auto str = db_user; lk.unlock(); bool cancel = choice == CancelOther; if(choice == Ask) { QMessageBox msgBox; msgBox.setText(tr("The database is currently busy: ") + str); msgBox.setInformativeText(tr("Do you want to abort that other operation?")); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); int ret = msgBox.exec(); cancel = ret == QMessageBox::Yes; } if(cancel) sqlite3_interrupt(_db); lk.lock(); cv.wait(lk, [this](){ return !db_used; }); } } bool DBBrowserDB::dump(const QString& filePath, const std::vector& tablesToDump, bool insertColNames, bool insertNewSyntx, bool keepOriginal, bool exportSchema, bool exportData, bool keepOldSchema) const { waitForDbRelease(); // Open file QFile file(filePath); if(file.open(QIODevice::WriteOnly|QIODevice::Text)) { QApplication::setOverrideCursor(Qt::WaitCursor); // Count the total number of all records in all tables for the progress dialog size_t numRecordsTotal = 0; objectMap objMap = schemata.at("main"); // We only always export the main database, not the attached databases std::vector tables; for(const auto& it : objMap.tables) { // Never export the sqlite_stat1 and the sqlite_sequence tables if they exist. Also only export any tables which are selected for export. if(!it.second->isView() && it.first != "sqlite_stat1" && it.first != "sqlite_sequence" && contains(tablesToDump, it.first)) { // Get the number of records in this table and remember to export it tables.push_back(it.second); numRecordsTotal += querySingleValueFromDb("SELECT COUNT(*) FROM " + sqlb::ObjectIdentifier("main", it.first).toString()).toUInt(); } } QProgressDialog progress(tr("Exporting database to SQL file..."), tr("Cancel"), 0, static_cast(numRecordsTotal)); // Disable context help button on Windows progress.setWindowFlags(progress.windowFlags() & ~Qt::WindowContextHelpButtonHint); progress.setWindowModality(Qt::ApplicationModal); progress.show(); qApp->processEvents(); // Open text stream to the file QTextStream stream(&file); // Put the SQL commands in a transaction block stream << "BEGIN TRANSACTION;\n"; // First export the schema of all selected tables. We need to export the schema of all tables before we export the first INSERT statement to // make sure foreign keys are working properly. if(exportSchema) { for(const auto& it : tables) { // Write the SQL string used to create this table to the output file if(!keepOldSchema) stream << QString("DROP TABLE IF EXISTS %1;\n").arg(QString::fromStdString(sqlb::escapeIdentifier(it->name()))); if(it->fullyParsed() && !keepOriginal) stream << QString::fromStdString(it->sql("main", keepOldSchema)) << "\n"; else { QString statement = QString::fromStdString(it->originalSql()); if(keepOldSchema) { // The statement is guaranteed by SQLite to start with "CREATE TABLE" const int createTableLength = 12; statement.replace(0, createTableLength, "CREATE TABLE IF NOT EXISTS"); } stream << statement << ";\n"; } } } // Now export the data as well if(exportData) { for(const auto& it : tables) { // get columns sqlb::StringVector cols = it->fieldNames(); std::string sQuery = "SELECT * FROM " + sqlb::escapeIdentifier(it->name()); sqlite3_stmt *stmt; QString lineSep(QString(")%1\n").arg(insertNewSyntx?',':';')); int status = sqlite3_prepare_v2(_db, sQuery.c_str(), static_cast(sQuery.size()), &stmt, nullptr); if(SQLITE_OK == status) { int columns = sqlite3_column_count(stmt); size_t counter = 0; size_t numRecordsCurrent = 0; qApp->processEvents(); while(sqlite3_step(stmt) == SQLITE_ROW) { if (counter) stream << lineSep; if (!insertNewSyntx || !counter) { stream << "INSERT INTO " << QString::fromStdString(sqlb::escapeIdentifier(it->name())); if (insertColNames) stream << " (" << QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(cols), ",")) << ")"; stream << " VALUES ("; } else { stream << " ("; } for (int i = 0; i < columns; ++i) { int fieldsize = sqlite3_column_bytes(stmt, i); int fieldtype = sqlite3_column_type(stmt, i); QByteArray bcontent( reinterpret_cast(sqlite3_column_blob(stmt, i)), fieldsize); switch(fieldtype) { case SQLITE_BLOB: stream << QString("X'%1'").arg(QString(bcontent.toHex())); break; case SQLITE_TEXT: stream << sqlb::escapeByteArray(bcontent); break; case SQLITE_NULL: stream << "NULL"; break; case SQLITE_FLOAT: if(bcontent.indexOf("Inf") != -1) stream << "'" << bcontent << "'"; else stream << bcontent; break; default: stream << bcontent; } if(i != columns - 1) stream << ','; } progress.setValue(static_cast(++numRecordsCurrent)); if(counter % 5000 == 0) qApp->processEvents(); counter++; if(progress.wasCanceled()) { sqlite3_finalize(stmt); file.close(); file.remove(); QApplication::restoreOverrideCursor(); return false; } } if (counter > 0) stream << ");\n"; } sqlite3_finalize(stmt); } } // Finally export all objects other than tables if(exportSchema) { auto writeSchema = [&stream, &tablesToDump, keepOldSchema, keepOriginal](const QString& type, auto objects) { for(const auto& obj : objects) { const auto& it = obj.second; // If this object is based on a table (e.g. is an index for that table) it depends on the existence of this table. // So if we didn't export the base table this depends on, don't export this object either. if(!sqlb::getBaseTable(it).empty() && !contains(tablesToDump, sqlb::getBaseTable(it))) continue; // Write the SQL string used to create this object to the output file if(!it->originalSql().empty()) { if(!keepOldSchema) stream << QString("DROP %1 IF EXISTS %2;\n").arg( type.toUpper(), QString::fromStdString(sqlb::escapeIdentifier(it->name()))); if(it->fullyParsed() && !keepOriginal) stream << QString::fromStdString(it->sql("main", keepOldSchema)) << "\n"; else stream << QString::fromStdString(it->originalSql()) << ";\n"; } } }; std::map views; std::copy_if(objMap.tables.begin(), objMap.tables.end(), std::inserter(views, views.end()), [](const auto& t) { return t.second->isView(); }); writeSchema("view", views); writeSchema("index", objMap.indices); writeSchema("trigger", objMap.triggers); } // Done stream << "COMMIT;\n"; file.close(); QApplication::restoreOverrideCursor(); qApp->processEvents(); return stream.status() == QTextStream::Ok && file.error() == QFileDevice::NoError; } return false; } // Callback for sqlite3_exec. It receives the user callback in the first parameter. Converts parameters // to C++ classes and calls user callback. int DBBrowserDB::callbackWrapper (void* callback, int numberColumns, char** values, char** columnNames) { std::vector valuesList; std::vector namesList; for (int i=0; i(callback)); return userCallback(numberColumns, valuesList, namesList); } bool DBBrowserDB::executeSQL(const std::string& statement, bool dirtyDB, bool logsql, execCallback callback) { waitForDbRelease(); if(!_db) { lastErrorMessage = tr("No database file opened"); return false; } if (dirtyDB) setSavepoint(); if (logsql) logSQL(QString::fromStdString(statement), kLogMsg_App); char* errmsg; if (SQLITE_OK == sqlite3_exec(_db, statement.c_str(), callback ? callbackWrapper : nullptr, &callback, &errmsg)) { // Update DB structure after executing an SQL statement. But try to avoid doing unnecessary updates. if(!disableStructureUpdateChecks && (starts_with_ci(statement, "ALTER") || starts_with_ci(statement, "CREATE") || starts_with_ci(statement, "DROP") || starts_with_ci(statement, "ROLLBACK"))) updateSchema(); return true; } else { lastErrorMessage = QString("%1 (%2)").arg(QString::fromUtf8(errmsg), QString::fromStdString(statement)); qWarning() << "executeSQL: " << lastErrorMessage; sqlite3_free(errmsg); return false; } } bool DBBrowserDB::executeMultiSQL(QByteArray query, bool dirty, bool log) { waitForDbRelease(); if(!_db) { lastErrorMessage = tr("No database file opened"); return false; } // Log the statement if needed if(log) logSQL(query, kLogMsg_App); // Show progress dialog QProgressDialog progress(tr("Executing SQL..."), tr("Cancel"), 0, 100); progress.setWindowModality(Qt::ApplicationModal); // Disable context help button on Windows progress.setWindowFlags(progress.windowFlags() & ~Qt::WindowContextHelpButtonHint); progress.show(); // Execute the statement by looping until SQLite stops giving back a tail string sqlite3_stmt* vm; const char *tail = query.constData(); const char * const tail_start = tail; const char * const tail_end = tail + query.size() + 1; size_t total_tail_length = static_cast(tail_end - tail_start); unsigned int line = 0; bool structure_updated = false; int last_progress_value = -1; std::string savepoint_name; while(tail && *tail != 0) { line++; // Update progress dialog, keep UI responsive. Make sure to not spend too much time updating the progress dialog in case there are many small statements. int progress_value = static_cast(static_cast(tail - tail_start) / static_cast(total_tail_length) * 100.0f); if(progress_value > last_progress_value) { progress.setValue(progress_value); qApp->processEvents(); if(progress.wasCanceled()) { lastErrorMessage = tr("Action cancelled."); return false; } last_progress_value = progress_value; } // Check next statement { // Ignore all whitespace at the start of the current tail const char* tail_ptr = tail; while(std::isspace(*tail_ptr)) tail_ptr++; // Convert the first couple of bytes of the tail to a C++ string for easier handling. We only need the first 8 bytes (in cae it's a ROLLBACK // statement), so no need to convert the entire tail. If the tail is less than 8 bytes long, make sure not to read past its end. size_t length = std::min(static_cast(tail_end - tail + 1), static_cast(8)); std::string next_statement(tail_ptr, length); std::transform(next_statement.begin(), next_statement.end(), next_statement.begin(), ::toupper); // Check for transaction statements and skip until the next semicolon if(next_statement.compare(0, 6, "COMMIT") == 0 || next_statement.compare(0, 4, "END ") == 0 || next_statement.compare(0, 6, "BEGIN ") == 0) { while(tail != tail_end) { if(*tail++ == ';') break; } // Set DB to dirty and create a restore point if we haven't done that yet if(savepoint_name.empty()) { savepoint_name = generateSavepointName("execmultisql"); setSavepoint(savepoint_name); dirty = true; } // Don't just execute next statement. Start next statement with the same checks continue; } // Check whether the DB structure is changed by this statement if(!disableStructureUpdateChecks && !structure_updated) { // Check if it's a modifying statement if(next_statement.compare(0, 5, "ALTER") == 0 || next_statement.compare(0, 6, "CREATE") == 0 || next_statement.compare(0, 4, "DROP") == 0 || next_statement.compare(0, 8, "ROLLBACK") == 0) structure_updated = true; } } // Execute next statement if(sqlite3_prepare_v2(_db, tail, static_cast(tail_end - tail + 1), &vm, &tail) == SQLITE_OK) { switch(sqlite3_step(vm)) { case SQLITE_OK: case SQLITE_ROW: case SQLITE_DONE: case SQLITE_MISUSE: // This is a workaround around problematic user scripts. If they lead to empty commands, // SQLite will return a misuse error which we hereby ignore. sqlite3_finalize(vm); break; default: // In case of *any* error abort the execution and roll back the transaction // Make sure to save the error message first before any other function can mess around with it lastErrorMessage = tr("Error in statement #%1: %2.\nAborting execution%3.").arg( QString::number(line), sqlite3_errmsg(_db), dirty ? tr(" and rolling back") : ""); qWarning() << lastErrorMessage; // Clean up sqlite3_finalize(vm); if(dirty) revertToSavepoint(savepoint_name); return false; } } else { lastErrorMessage = tr("Error in statement #%1: %2.\nAborting execution%3.").arg( QString::number(line), sqlite3_errmsg(_db), dirty ? tr(" and rolling back") : ""); qWarning() << lastErrorMessage; if(dirty) revertToSavepoint(savepoint_name); return false; } } // If the DB structure was changed by some command in this SQL script, update our schema representations if(structure_updated) updateSchema(); // Exit return true; } QByteArray DBBrowserDB::querySingleValueFromDb(const std::string& sql, bool log, ChoiceOnUse choice) const { waitForDbRelease(choice); if(!_db) return QByteArray(); if(log) logSQL(QString::fromStdString(sql), kLogMsg_App); QByteArray retval; sqlite3_stmt* stmt; if(sqlite3_prepare_v2(_db, sql.c_str(), static_cast(sql.size()), &stmt, nullptr) == SQLITE_OK) { // Execute the statement. We distinguish three types of results: // SQLITE_ROW in case some data was returned from the database. This data is then used as a return value. // SQLITE_DONE in case the statement executed successfully but did not return any data. We do nothing in this case, leaving the return value empty. // Any other case is an error, so we need to prepare an error message. int result = sqlite3_step(stmt); if(result == SQLITE_ROW) { if(sqlite3_column_count(stmt) > 0 && sqlite3_column_type(stmt, 0) != SQLITE_NULL) { int bytes = sqlite3_column_bytes(stmt, 0); if(bytes) retval = QByteArray(static_cast(sqlite3_column_blob(stmt, 0)), bytes); else retval = ""; } } else if(result != SQLITE_DONE) { lastErrorMessage = tr("didn't receive any output from %1").arg(QString::fromStdString(sql)); qWarning() << lastErrorMessage; } sqlite3_finalize(stmt); } else { lastErrorMessage = tr("could not execute command: %1").arg(sqlite3_errmsg(_db)); qWarning() << lastErrorMessage; } return retval; } bool DBBrowserDB::getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, std::vector& rowdata) const { waitForDbRelease(); if(!_db) return false; std::string query = "SELECT * FROM " + table.toString() + " WHERE "; // For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values. sqlb::StringVector pks = getTableByName(table)->rowidColumns(); if(pks.size() == 1) query += sqlb::escapeIdentifier(pks.front()) + "='" + rowid.toStdString() + "'"; else query += "sqlb_make_single_value(" + sqlb::joinStringVector(sqlb::escapeIdentifier(pks), ",") + ")=" + sqlb::escapeString(rowid.toStdString()); sqlite3_stmt *stmt; bool ret = false; if(sqlite3_prepare_v2(_db, query.c_str(), static_cast(query.size()), &stmt, nullptr) == SQLITE_OK) { // even this is a while loop, the statement should always only return 1 row while(sqlite3_step(stmt) == SQLITE_ROW) { for (int i = 0; i < sqlite3_column_count(stmt); ++i) { if(sqlite3_column_type(stmt, i) == SQLITE_NULL) { rowdata.emplace_back(); } else { int bytes = sqlite3_column_bytes(stmt, i); if(bytes) rowdata.emplace_back(static_cast(sqlite3_column_blob(stmt, i)), bytes); else rowdata.emplace_back(""); } } ret = true; } } sqlite3_finalize(stmt); return ret; } unsigned long DBBrowserDB::max(const sqlb::ObjectIdentifier& tableName, const std::string& field) const { // This query returns the maximum value of the given table and column std::string query = "SELECT MAX(CAST(" + sqlb::escapeIdentifier(field) + " AS INTEGER)) FROM " + tableName.toString() + ")"; // If, however, there is a sequence table in this database and the given column is the primary key of the table, we try to look up a value in the sequence table if(schemata.at(tableName.schema()).tables.count("sqlite_sequence")) { auto pk = getTableByName(tableName)->primaryKeyColumns(); if(pk.size() == 1 && pk.front().name() == field) { // This SQL statement tries to do two things in one statement: get the current sequence number for this table from the sqlite_sequence table or, if there is no record for the table, return the highest integer value in the given column. // This works by querying the sqlite_sequence table and using an aggregate function (SUM in this case) to make sure to always get exactly one result row, no matter if there is a sequence record or not. We then let COALESCE decide // whether to return that sequence value if there is one or fall back to the SELECT MAX statement from avove if there is no sequence value. query = "SELECT COALESCE(SUM(seq), (" + query + ") FROM sqlite_sequence WHERE name=" + sqlb::escapeString(tableName.name()); } } return querySingleValueFromDb(query).toULong(); } std::string DBBrowserDB::emptyInsertStmt(const std::string& schemaName, const sqlb::Table& t, const QString& pk_value) const { std::string stmt = "INSERT INTO " + sqlb::escapeIdentifier(schemaName) + "." + sqlb::escapeIdentifier(t.name()); const auto pk = t.primaryKeyColumns(); sqlb::StringVector vals; sqlb::StringVector fields; for(const sqlb::Field& f : t.fields) { // Never insert into a generated column if(f.generated()) continue; if(pk.size() == 1 && pk.at(0) == f.name()) { fields.push_back(f.name()); if(!pk_value.isNull()) { vals.push_back(f.isText()? "'" + pk_value.toStdString() + "'" : pk_value.toStdString()); } else { if(f.notnull()) { unsigned long maxval = this->max(sqlb::ObjectIdentifier(schemaName, t.name()), f.name()); std::string newval = std::to_string(maxval + 1); vals.push_back(f.isText()? "'" + newval + "'" : newval); } else { vals.push_back("NULL"); } } } else if(f.notnull() && f.defaultValue().length() == 0) { fields.push_back(f.name()); if(f.isInteger()) vals.push_back("0"); else vals.push_back("''"); } else { // don't insert into fields with a default value // or we will never see it. if(f.defaultValue().length() == 0) { fields.push_back(f.name()); vals.push_back("NULL"); } } } if(fields.empty()) { stmt.append(" DEFAULT VALUES;"); } else { stmt.append("("); stmt.append(sqlb::joinStringVector(sqlb::escapeIdentifier(fields), ",")); stmt.append(") VALUES ("); stmt.append(sqlb::joinStringVector(vals, ",")); stmt.append(");"); } return stmt; } QString DBBrowserDB::addRecord(const sqlb::ObjectIdentifier& tablename) { waitForDbRelease(); if(!_db) return QString(); sqlb::TablePtr table = getTableByName(tablename); if(!table) return QString(); // For tables without rowid we have to set the primary key by ourselves. We do so by querying for the largest value in the PK column // and adding one to it. std::string sInsertstmt; QString pk_value; if(table->withoutRowidTable()) { // For multiple rowid columns we just use the value of the last one and increase that one by one. If this doesn't yield a valid combination // the insert record dialog should pop up automatically. pk_value = QString::number(max(tablename, table->rowidColumns().back()) + 1); sInsertstmt = emptyInsertStmt(tablename.schema(), *table, pk_value); } else { sInsertstmt = emptyInsertStmt(tablename.schema(), *table); } if(!executeSQL(sInsertstmt)) { qWarning() << "addRecord: " << lastErrorMessage; return QString(); } else { if(table->withoutRowidTable()) return pk_value; else return QString::number(sqlite3_last_insert_rowid(_db)); } } bool DBBrowserDB::deleteRecords(const sqlb::ObjectIdentifier& table, const std::vector& rowids, const sqlb::StringVector& pseudo_pk) { if (!isOpen()) return false; // Get primary key of the object to edit. sqlb::StringVector pks = primaryKeyForEditing(table, pseudo_pk); if(pks.empty()) { lastErrorMessage = tr("Cannot delete this object"); return false; } // Quote all values in advance std::vector quoted_rowids; std::transform(rowids.begin(), rowids.end(), std::back_inserter(quoted_rowids), [](const auto& rowid) { return sqlb::escapeByteArray(rowid).toStdString(); }); // For a single rowid column we can use a SELECT ... IN(...) statement which is faster. // For multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values. std::string statement; if(pks.size() == 1) { statement = "DELETE FROM " + table.toString() + " WHERE " + pks.at(0) + " IN ("+ sqlb::joinStringVector(quoted_rowids, ", ") + ");"; } else { statement = "DELETE FROM " + table.toString() + " WHERE "; statement += "sqlb_make_single_value("; for(const auto& pk : pks) statement += sqlb::escapeIdentifier(pk) + ","; statement.erase(statement.end()-1); statement += ") IN (" + sqlb::joinStringVector(quoted_rowids, ", ") + ")"; } if(executeSQL(statement)) { return true; } else { qWarning() << "deleteRecord: " << lastErrorMessage; return false; } } bool DBBrowserDB::updateRecord(const sqlb::ObjectIdentifier& table, const std::string& column, const QByteArray& rowid, const QByteArray& value, int force_type, const sqlb::StringVector& pseudo_pk) { waitForDbRelease(); if (!isOpen()) return false; // Get primary key of the object to edit. sqlb::StringVector pks = primaryKeyForEditing(table, pseudo_pk); if(pks.empty()) { lastErrorMessage = tr("Cannot set data on this object"); return false; } std::string sql = "UPDATE " + table.toString() + " SET " + sqlb::escapeIdentifier(column) + "=? WHERE "; // For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values. if(pks.size() == 1) sql += sqlb::escapeIdentifier(pks.front()) + "=" + sqlb::escapeByteArray(rowid).toStdString(); else sql += "sqlb_make_single_value(" + sqlb::joinStringVector(sqlb::escapeIdentifier(pks), ",") + ")=" + sqlb::escapeString(rowid.toStdString()); setSavepoint(); logSQL(QString::fromStdString(sql), kLogMsg_App); // If we get a NULL QByteArray we insert a NULL value, and for that // we can pass NULL to sqlite3_bind_text() so that it behaves like sqlite3_bind_null() const char *rawValue = value.isNull() ? nullptr : value.constData(); sqlite3_stmt* stmt; int success = 1; if(sqlite3_prepare_v2(_db, sql.c_str(), static_cast(sql.size()), &stmt, nullptr) != SQLITE_OK) success = 0; if(success == 1) { if(force_type == SQLITE_BLOB) { if(sqlite3_bind_blob(stmt, 1, rawValue, value.length(), SQLITE_STATIC)) success = -1; } else if(force_type == SQLITE_INTEGER) { if(sqlite3_bind_int64(stmt, 1, value.toLongLong())) success = -1; } else if(force_type == SQLITE_FLOAT) { if(sqlite3_bind_double(stmt, 1, value.toDouble())) success = -1; } else { if(sqlite3_bind_text(stmt, 1, rawValue, value.length(), SQLITE_STATIC)) success = -1; } } if(success == 1 && sqlite3_step(stmt) != SQLITE_DONE) success = -1; if(success != 0 && sqlite3_finalize(stmt) != SQLITE_OK) success = -1; if(success == 1) { return true; } else { lastErrorMessage = sqlite3_errmsg(_db); qWarning() << "updateRecord: " << lastErrorMessage; return false; } } sqlb::StringVector DBBrowserDB::primaryKeyForEditing(const sqlb::ObjectIdentifier& table, const sqlb::StringVector& pseudo_pk) const { // This function returns the primary key of the object to edit. For views we support 'pseudo' primary keys which must be specified manually. // If no pseudo pk is specified we'll take the rowid column of the table instead. If this neither a table nor was a pseudo-PK specified, // it is most likely a view that hasn't been configured for editing yet. In this case we return a null string to abort. if(pseudo_pk.empty()) { sqlb::TablePtr tbl = getTableByName(table); if(tbl) return tbl->rowidColumns(); } else { return pseudo_pk; } return sqlb::StringVector(); } bool DBBrowserDB::createTable(const sqlb::ObjectIdentifier& name, const sqlb::FieldVector& structure) { // Build SQL statement sqlb::Table table(name.name()); for(size_t i=0;i& p) { return p.first.isNull() && p.second.toStdString() == field.name(); })) { if(!addColumn(sqlb::ObjectIdentifier(tablename.schema(), new_table.name()), field)) { revertToSavepoint(savepointName); return false; } } changed_something = true; } // Newer versions of SQLite add a better ALTER TABLE support which we can use #if SQLITE_VERSION_NUMBER >= 3025000 // If the name of a field should be changed do that by using SQLite's ALTER TABLE feature. We build a new // map for tracking column names here which uses the update column names as the old names too. This is to // make sure we are using the new table layout for later updates. AlterTableTrackColumns new_track_columns; for(const auto& old_name_it : track_columns) { QString old_name = old_name_it.first; QString new_name = track_columns[old_name]; if(!old_name.isNull() && !new_name.isNull() && new_name != old_name) { if(!executeSQL("ALTER TABLE " + sqlb::ObjectIdentifier(tablename.schema(), new_table.name()).toString() + " RENAME COLUMN " + sqlb::escapeIdentifier(old_name.toStdString()) + " TO " + sqlb::escapeIdentifier(new_name.toStdString()))) { QString error(tr("Renaming the column failed. DB says:\n%1").arg(lastErrorMessage)); revertToSavepoint(savepointName); lastErrorMessage = error; return false; } changed_something = true; new_track_columns.insert({new_name, new_name}); } else { new_track_columns.insert({old_name, new_name}); } } track_columns.swap(new_track_columns); #endif // Update our schema representation to get the new table and all the changed triggers, views and indices if(changed_something) { updateSchema(); old_table = *getTableByName(sqlb::ObjectIdentifier(tablename.schema(), new_table.name())); } // Check if there's still more work to be done or if we are finished now if(tablename.schema() == newSchemaName && old_table == new_table) { // Release the savepoint - everything went fine if(!releaseSavepoint(savepointName)) { lastErrorMessage = tr("Releasing savepoint failed. DB says: %1").arg(lastErrorMessage); return false; } // Success, update the DB schema before returning updateSchema(); return true; } // // P A R T 3 // // Create a new table with the desired schema and a name that doesn't exist yet std::string new_table_name = new_table.name(); sqlb::Table new_table_with_random_name(new_table); new_table_with_random_name.setName(generateTemporaryTableName(newSchemaName)); if(!executeSQL(new_table_with_random_name.sql(newSchemaName), true, true)) { QString error(tr("Creating new table failed. DB says: %1").arg(lastErrorMessage)); revertToSavepoint(savepointName); lastErrorMessage = error; return false; } // Assemble list of column names to copy from in the old table and list of column names to into into in the new table sqlb::StringVector copy_values_from; sqlb::StringVector copy_values_to; for(const auto& from_it : track_columns) { const auto& from = from_it.first; // Ignore new fields if(from.isNull()) continue; // Ignore deleted fields QString to = track_columns[from]; if(to.isNull()) continue; // Ignore generated columns auto it = sqlb::findField(new_table, to.toStdString()); if(it->generated()) continue; copy_values_from.push_back(from.toStdString()); copy_values_to.push_back(to.toStdString()); } // Copy the data from the old table to the new one if(!executeSQL("INSERT INTO " + sqlb::escapeIdentifier(newSchemaName) + "." + sqlb::escapeIdentifier(new_table_with_random_name.name()) + " (" + sqlb::joinStringVector(sqlb::escapeIdentifier(copy_values_to), ",") + ") SELECT " + sqlb::joinStringVector(sqlb::escapeIdentifier(copy_values_from), ",") + " FROM " + sqlb::escapeIdentifier(tablename.schema()) + "." + sqlb::escapeIdentifier(old_table.name()))) { QString error(tr("Copying data to new table failed. DB says:\n%1").arg(lastErrorMessage)); revertToSavepoint(savepointName); lastErrorMessage = error; return false; } // Save all indices, triggers and views associated with this table because SQLite deletes them when we drop the table in the next step std::vector otherObjectsSql; auto saveRelatedObjects = [old_table, track_columns, &otherObjectsSql, newSchemaName](const auto& objects) { for(const auto& obj : objects) { const auto& it = obj.second; // If this object references the table save its SQL string if(sqlb::getBaseTable(it) == old_table.name()) { // If this is an index, update the fields first. This highly increases the chance that the SQL statement won't throw an // error later on when we try to recreate it. if(std::is_same::value) { sqlb::IndexPtr idx = std::dynamic_pointer_cast(it); // Loop through all changes to the table schema. For indices only the column names are relevant, so it suffices to look at the // list of tracked columns for(const auto& from_it : track_columns) { const auto& from = from_it.first; const auto& to = from_it.second; // Are we updating the field name or are we removing the field entirely? if(!to.isNull()) { // We're updating the field name. So search for it in the index and replace it wherever it is found for(size_t i=0;ifields.size();i++) { if(idx->fields[i].name() == from.toStdString()) idx->fields[i].setName(to.toStdString()); } } else { // We're removing a field. So remove it from any indices, too. while(sqlb::removeField(idx, from.toStdString())) ; } } // Only try to add the index later if it has any columns remaining. Also use the new schema name here, too, to basically move // any index that references the table to the same new schema as the table. if(idx->fields.size()) otherObjectsSql.push_back(idx->sql(newSchemaName)); } else { // If it's a view or a trigger we don't have any chance to corrections yet. Just store the statement as is and // hope for the best. otherObjectsSql.push_back(it->originalSql() + ";"); } } } }; saveRelatedObjects(schemata[tablename.schema()].tables); // We can safely pass the tables along with the views here since they never have a base table set saveRelatedObjects(schemata[tablename.schema()].indices); saveRelatedObjects(schemata[tablename.schema()].triggers); // We need to disable foreign keys here. The reason is that in the next step the entire table will be dropped and there might be foreign keys // in other tables that reference this table. These foreign keys would then cause the drop command in the next step to fail. However, we can't // simply disable foreign keys here since that is not allowed from inside a transaction and we definitely are inside a transaction at that point. // So what we do instead is defer foreign key enforcement until the end of the transaction which effectively disables foreign keys for us here. // But because we don't really want to defer foreign keys, the former value of that pragma is saved here in order to restore the old value later. QString foreignKeysOldSettings = getPragma("defer_foreign_keys"); setPragma("defer_foreign_keys", "1"); // Delete the old table if(!executeSQL("DROP TABLE " + sqlb::escapeIdentifier(tablename.schema()) + "." + sqlb::escapeIdentifier(old_table.name()), true, true)) { QString error(tr("Deleting old table failed. DB says: %1").arg(lastErrorMessage)); revertToSavepoint(savepointName); lastErrorMessage = error; return false; } // Rename the temporary table if(!renameTable(newSchemaName, new_table_with_random_name.name(), new_table.name())) { revertToSavepoint(savepointName); return false; } // Restore the former foreign key settings setPragma("defer_foreign_keys", foreignKeysOldSettings); // Restore the saved triggers, views and indices std::string errored_sqls; for(const std::string& sql : otherObjectsSql) { if(!executeSQL(sql, true, true)) errored_sqls += sql + "\n"; } if(!errored_sqls.empty()) { QMessageBox::information(nullptr, qApp->applicationName(), tr("Restoring some of the objects associated with this table failed. " "This is most likely because some column names changed. " "Here's the SQL statement which you might want to fix and execute manually:\n\n") + QString::fromStdString(errored_sqls)); } // Release the savepoint - everything went fine if(!releaseSavepoint(savepointName)) { lastErrorMessage = tr("Releasing savepoint failed. DB says: %1").arg(lastErrorMessage); return false; } // Success, update the DB schema before returning updateSchema(); return true; } bool DBBrowserDB::renameTable(const std::string& schema, const std::string& from_table, const std::string& to_table) { // Do nothing if table names are the same if(from_table == to_table) return true; // Check if table names only differ in case. If they do, we have to rename the table twice because SQLite can't rename 'table' to 'Table'. // To solve this we rename 'table' to 'some temp name' and then 'some temp name' to 'Table'. if(compare_ci(from_table, to_table)) { // Generate a temporary table name and rename the table via that by recusrively calling this function std::string temp_name = generateTemporaryTableName(schema); if(!renameTable(schema, from_table, temp_name)) return false; if(!renameTable(schema, temp_name, to_table)) return false; // Exit here return true; } // The old and the new table names differ (and that not only in case) // Rename the table std::string sql = "ALTER TABLE " + sqlb::escapeIdentifier(schema) + "." + sqlb::escapeIdentifier(from_table) + " RENAME TO " + sqlb::escapeIdentifier(to_table); if(!executeSQL(sql)) { QString error = tr("Error renaming table '%1' to '%2'.\n" "Message from database engine:\n%3").arg(QString::fromStdString(from_table), QString::fromStdString(to_table), lastErrorMessage); lastErrorMessage = error; qWarning() << lastErrorMessage; return false; } else { return true; } } void DBBrowserDB::logSQL(const QString& statement, LogMessageType msgtype) const { // Remove any leading and trailing spaces, tabs, or line breaks first emit sqlExecuted(statement.trimmed(), msgtype); } void DBBrowserDB::updateSchema() { waitForDbRelease(); schemata.clear(); // Exit here is no DB is opened if(!isOpen()) return; // Get a list of all databases. This list always includes the main and the temp database but can include more items if there are attached databases if(!executeSQL("PRAGMA database_list;", false, true, [this](int, std::vector db_values, std::vector) -> bool { // Get the schema name which is in column 1 (counting starts with 0). 0 contains an ID and 2 the file path. const std::string schema_name = db_values.at(1).toStdString(); // Always add the schema to the map. This makes sure it's even then added when there are no objects in the database objectMap& object_map = schemata[schema_name]; // Get a list of all the tables for the current database schema. We need to do this differently for normal databases and the temporary schema // because SQLite doesn't understand the "temp.sqlite_master" notation. std::string statement; if(schema_name == "temp") statement = "SELECT type,name,sql,tbl_name FROM sqlite_temp_master;"; else statement = "SELECT type,name,sql,tbl_name FROM " + sqlb::escapeIdentifier(schema_name) + ".sqlite_master;"; if(!executeSQL(statement, false, true, [this, schema_name, &object_map](int, std::vector values, std::vector) -> bool { const std::string val_type = values.at(0).toStdString(); const std::string val_name = values.at(1).toStdString(); std::string val_sql = values.at(2).toStdString(); const std::string val_tblname = values.at(3).toStdString(); if(!val_sql.empty()) { val_sql.erase(std::remove(val_sql.begin(), val_sql.end(), '\r'), val_sql.end()); if(val_type == "table" || val_type == "view") { sqlb::TablePtr table; if(val_type == "table") table = sqlb::Table::parseSQL(val_sql); else table = sqlb::View::parseSQL(val_sql); if(!table->fullyParsed()) table->setName(val_name); // For virtual tables, views, and tables we could not parse at all, // query the column list using the SQLite pragma to at least get // some information on them when our parser does not. if((!table->fullyParsed() && table->fields.empty()) || table->isVirtual()) { const auto columns = queryColumnInformation(schema_name, val_name); for(const auto& column : columns) table->fields.emplace_back(column.first, column.second); } object_map.tables.insert({val_name, table}); } else if(val_type == "index") { sqlb::IndexPtr index = sqlb::Index::parseSQL(val_sql); if(!index->fullyParsed()) index->setName(val_name); object_map.indices.insert({val_name, index}); } else if(val_type == "trigger") { sqlb::TriggerPtr trigger = sqlb::Trigger::parseSQL(val_sql); trigger->setName(val_name); trigger->setOriginalSql(val_sql); // For triggers set the name of the table the trigger operates on here because we don't have a parser for trigger statements yet. trigger->setTable(val_tblname); object_map.triggers.insert({val_name, trigger}); } } return false; })) { qWarning() << tr("could not get list of db objects: %1").arg(sqlite3_errmsg(_db)); } return false; })) { qWarning() << tr("could not get list of databases: %1").arg(sqlite3_errmsg(_db)); } emit structureUpdated(); } QString DBBrowserDB::getPragma(const std::string& pragma) const { if (pragma=="case_sensitive_like") return querySingleValueFromDb("SELECT 'x' NOT LIKE 'X';"); else return querySingleValueFromDb("PRAGMA " + pragma + ";"); } bool DBBrowserDB::setPragma(const std::string& pragma, const QString& value) { // Set the pragma value std::string sql = "PRAGMA " + pragma + " = '" + value.toStdString() + "';"; // In general, we want to commit changes before running pragmas because most of them can't be rolled back and some of them // even fail when run in a transaction. However, the defer_foreign_keys pragma has neither problem and we need it to be settable // inside transactions (see the renameColumn() function where it is set and reset at some point and where we don't want the changes // to be committed just because of this pragma). if(pragma != "defer_foreign_keys") releaseSavepoint(); bool res = executeSQL(sql, false, true); // PRAGMA statements are usually not transaction bound, so we can't revert if( !res ) qWarning() << tr("Error setting pragma %1 to %2: %3").arg(QString::fromStdString(pragma), value, lastErrorMessage); // If this is the page_size or the auto_vacuum pragma being set, we need to execute the vacuum command right after the pragma statement or the new // settings won't be saved. if(res && (pragma == "page_size" || pragma == "auto_vacuum")) res = executeSQL("VACUUM;", false, true); return res; } bool DBBrowserDB::setPragma(const std::string& pragma, const QString& value, QString& originalvalue) { if( originalvalue != value ) { if( setPragma(pragma, value)) { originalvalue = value; return true; } } return false; } bool DBBrowserDB::setPragma(const std::string& pragma, int value, int& originalvalue) { if( originalvalue != value ) { QString val = QString::number(value); QString origval = QString::number(originalvalue); if( setPragma(pragma, val, origval)) { originalvalue = value; } } return false; } bool DBBrowserDB::loadExtension(const QString& filePath) { waitForDbRelease(); if(!_db) return false; // Check if file exists if(!QFile::exists(filePath)) { lastErrorMessage = tr("File not found."); return false; } // Enable extension loading sqlite3_enable_load_extension(_db, 1); // Try to load extension char* error; int result = sqlite3_load_extension(_db, filePath.toUtf8(), nullptr, &error); // Disable extension loading if so configured // (we don't want to leave the possibility of calling load_extension() from SQL without user informed permission) if (!Settings::getValue("extensions", "enable_load_extension").toBool()) sqlite3_enable_load_extension(_db, 0); if (result == SQLITE_OK) { return true; } else { lastErrorMessage = QString::fromUtf8(error); sqlite3_free(error); return false; } } void DBBrowserDB::loadExtensionsFromSettings() { if(!_db) return; sqlite3_enable_load_extension(_db, Settings::getValue("extensions", "enable_load_extension").toBool()); const QStringList list = Settings::getValue("extensions", "list").toStringList(); for(const QString& ext : list) { if(loadExtension(ext) == false) QMessageBox::warning(nullptr, QApplication::applicationName(), tr("Error loading extension: %1").arg(lastError())); } const QVariantMap builtinList = Settings::getValue("extensions", "builtin").toMap(); for(const QString& ext : builtinList.keys()) { if(builtinList.value(ext).toBool()) { if(loadExtension(ext) == false) QMessageBox::warning(nullptr, QApplication::applicationName(), tr("Error loading built-in extension: %1").arg(lastError())); } } } std::vector> DBBrowserDB::queryColumnInformation(const std::string& schema_name, const std::string& object_name) const { waitForDbRelease(); std::vector> result; std::string statement = "PRAGMA " + sqlb::escapeIdentifier(schema_name) + ".TABLE_INFO(" + sqlb::escapeIdentifier(object_name) + ");"; logSQL(QString::fromStdString(statement), kLogMsg_App); sqlite3_stmt* vm; const char* tail; if(sqlite3_prepare_v2(_db, statement.c_str(), static_cast(statement.size()), &vm, &tail) == SQLITE_OK) { while(sqlite3_step(vm) == SQLITE_ROW) { std::string name = reinterpret_cast(sqlite3_column_text(vm, 1)); std::string type = reinterpret_cast(sqlite3_column_text(vm, 2)); result.push_back(std::make_pair(name, type)); } sqlite3_finalize(vm); } else{ lastErrorMessage = tr("could not get column information"); } return result; } std::string DBBrowserDB::generateSavepointName(const std::string& identifier) const { // Generate some sort of unique name for a savepoint for internal use. return "db4s_" + identifier + "_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count()); } std::string DBBrowserDB::generateTemporaryTableName(const std::string& schema) const { // We're using a static variable as a counter here instead of checking from the beginning onwards every time. This has // two reasons: 1) It makes the function thread-safe, and 2) it saves us some time because in case older temporary tables // are still in use. Both reasons don't matter too much for now, but just in case... static std::atomic_uint counter; while(true) { std::string table_name = "sqlb_temp_table_" + std::to_string(++counter); if(!getTableByName(sqlb::ObjectIdentifier(schema, table_name))) return table_name; } } void DBBrowserDB::interruptQuery() { if(!_db) return; sqlite3_interrupt(_db); } sqlitebrowser-sqlitebrowser-5733cb7/src/sqlitedb.h000066400000000000000000000324551463772530400224540ustar00rootroot00000000000000#ifndef SQLITEDB_H #define SQLITEDB_H #include "sql/ObjectIdentifier.h" #include "sql/sqlitetypes.h" #include #include #include #include #include #include #include #include #include struct sqlite3; class CipherSettings; enum LogMessageType { kLogMsg_User, kLogMsg_App, kLogMsg_ErrorLog }; struct objectMap { // These map from object name to object pointer std::map tables; // This stores tables AND views std::map indices; std::map triggers; bool empty() const { return tables.empty() && indices.empty() && triggers.empty(); } }; using schemaMap = std::map; // Maps from the schema name (main, temp, attached schemas) to the object map for that schema int collCompare(void* pArg, int sizeA, const void* sA, int sizeB, const void* sB); namespace sqlb { QString escapeIdentifier(const QString& id); QString escapeString(const QString& literal); QString escapeByteArray(const QByteArray& literal); } /// represents a single SQLite database. except when noted otherwise, /// all member functions are to be called from the main UI thread /// only. class DBBrowserDB : public QObject { Q_OBJECT private: /// custom unique_ptr deleter releases database for further use by others struct DatabaseReleaser { explicit DatabaseReleaser(DBBrowserDB * pParent_ = nullptr) : pParent(pParent_) {} DBBrowserDB * pParent; void operator() (const sqlite3* db) const { if(!db || !pParent) return; std::unique_lock lk(pParent->m); pParent->db_used = false; lk.unlock(); emit pParent->databaseInUseChanged(false, QString()); pParent->cv.notify_one(); } }; public: explicit DBBrowserDB(); ~DBBrowserDB () override = default; bool open(const QString& db, bool readOnly = false); bool attach(const QString& filename, QString attach_as = QString()); /** detaches a previously attached database identified with its alias-name \param attached_as the alias-name as witch a additional database file has been attached to the connection **/ bool detach(const std::string& attached_as); bool create ( const QString & db); bool close(); bool saveAs(const std::string& filename); // This returns the SQLite version as well as the SQLCipher if DB4S is compiled with encryption support static void getSqliteVersion(QString& sqlite, QString& sqlcipher); using db_pointer_type = std::unique_ptr; /** borrow exclusive address to the currently open database, until releasing the returned unique_ptr. the intended use case is that the main UI thread can call this any time, and then optionally pass the obtained pointer to a background worker, or release it after doing work immediately. if database is currently used by somebody else, opens a dialog box and gives user the opportunity to sqlite3_interrupt() the operation of the current owner, then tries again. \param user a string that identifies the new user, and which can be displayed in the dialog box. \param force_wait if set to true we won't ask the user to cancel the running query but just wait until it is done. \returns a unique_ptr containing the SQLite database handle, or nullptr in case no database is open. **/ db_pointer_type get (const QString& user, bool force_wait = false); bool setSavepoint(const std::string& pointname = "RESTOREPOINT", bool unique = true); bool releaseSavepoint(const std::string& pointname = "RESTOREPOINT"); bool revertToSavepoint(const std::string& pointname = "RESTOREPOINT"); bool releaseAllSavepoints(); bool revertAll(); // Set a non-unique savepoint for the general undoing mechanism (undoing only last write). bool setUndoSavepoint() { return setSavepoint("UNDOPOINT", /* unique */ false); }; bool revertToUndoSavepoint() { return revertToSavepoint("UNDOPOINT"); }; bool releaseUndoSavepoint() { return releaseSavepoint("UNDOPOINT"); }; bool dump(const QString& filename, const std::vector& tablesToDump, bool insertColNames, bool insertNew, bool keepOriginal, bool exportSchema, bool exportData, bool keepOldSchema) const; enum ChoiceOnUse { Ask, Wait, CancelOther }; // Callback to get results from executeSQL(). It is invoked for // each result row coming out of the evaluated SQL statements. If // a callback returns true (abort), the executeSQL() method // returns false (error) without invoking the callback again and // without running any subsequent SQL statements. The 1st argument // is the number of columns in the result. The 2nd argument to the // callback is the text representation of the values, one for each // column. The 3rd argument is a list of strings where each entry // represents the name of corresponding result column. using execCallback = std::function, std::vector)>; bool executeSQL(const std::string& statement, bool dirtyDB = true, bool logsql = true, execCallback callback = nullptr); bool executeMultiSQL(QByteArray query, bool dirty = true, bool log = false); QByteArray querySingleValueFromDb(const std::string& sql, bool log = true, ChoiceOnUse choice = Ask) const; const QString& lastError() const { return lastErrorMessage; } /** * @brief getRow Executes a sqlite statement to get the rowdata(columns) * for the given rowid. * @param schemaName Name of the database schema. * @param sTableName Table to query. * @param rowid The rowid to fetch. * @param rowdata A list of QByteArray containing the row data. * @return true if statement execution was ok, else false. */ bool getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, std::vector& rowdata) const; /** * @brief Interrupts the currently running statement as soon as possible. */ void interruptQuery(); private: /** * @brief max Queries the table t for the max value of field. * @param tableName Table to query * @param field Name of the field to get the max value * @return the max value of the field or 0 on error */ unsigned long max(const sqlb::ObjectIdentifier& tableName, const std::string& field) const; static int callbackWrapper (void* callback, int numberColumns, char** values, char** columnNames); public: void updateSchema(); // Please don't call this from threads other than the main thread. private: /** * @brief Creates an empty insert statement. * @param schemaName The name of the database schema in which to find the table * @param pk_value This optional parameter can be used to manually set a specific value for the primary key column * @return An sqlite conform INSERT INTO statement with empty values. (NULL,'',0) */ std::string emptyInsertStmt(const std::string& schemaName, const sqlb::Table& t, const QString& pk_value = QString()) const; public: QString addRecord(const sqlb::ObjectIdentifier& tablename); bool deleteRecords(const sqlb::ObjectIdentifier& table, const std::vector& rowids, const sqlb::StringVector& pseudo_pk = {}); bool updateRecord(const sqlb::ObjectIdentifier& table, const std::string& column, const QByteArray& rowid, const QByteArray& value, int force_type = 0, const sqlb::StringVector& pseudo_pk = {}); bool createTable(const sqlb::ObjectIdentifier& name, const sqlb::FieldVector& structure); bool renameTable(const std::string& schema, const std::string& from_table, const std::string& to_table); bool addColumn(const sqlb::ObjectIdentifier& tablename, const sqlb::Field& field); /** * @brief This type maps from old column names to new column names. Given the old and the new table definition, this suffices to * track fields between the two. * USE CASES: * 1) Don't specify a column at all or specify equal column names: Keep its name as-is. * 2) Specify different column names: Rename the field. * 3) Map from an existing column name to a Null string: Delete the column. * 4) Map from a Null column name to a new column name: Add the column. */ using AlterTableTrackColumns = std::map; /** * @brief alterTable Can be used to rename, modify or drop existing columns of a given table * @param tablename Specifies the schema and name of the table to edit * @param new_table Specifies the new table schema. This is exactly how the new table is going to look like. * @param track_columns Maps old column names to new column names. This is used to copy the data from the old table to the new one. * @param newSchema Set this to a non-empty string to move the table to a new schema * @return true if renaming was successful, false if not. In the latter case also lastErrorMessage is set */ bool alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb::Table& new_table, AlterTableTrackColumns track_columns, std::string newSchemaName = std::string()); const sqlb::TablePtr getTableByName(const sqlb::ObjectIdentifier& name) const { if(schemata.empty() || name.schema().empty() || !schemata.count(name.schema())) return sqlb::TablePtr{}; const auto& schema = schemata.at(name.schema()); if(schema.tables.count(name.name())) return schema.tables.at(name.name()); return sqlb::TablePtr{}; } const sqlb::IndexPtr getIndexByName(const sqlb::ObjectIdentifier& name) const { if(schemata.empty() || name.schema().empty()) return sqlb::IndexPtr{}; const auto& schema = schemata.at(name.schema()); if(schema.indices.count(name.name())) return schema.indices.at(name.name()); return sqlb::IndexPtr{}; } const sqlb::TriggerPtr getTriggerByName(const sqlb::ObjectIdentifier& name) const { if(schemata.empty() || name.schema().empty()) return sqlb::TriggerPtr{}; const auto& schema = schemata.at(name.schema()); if(schema.triggers.count(name.name())) return schema.triggers.at(name.name()); return sqlb::TriggerPtr{}; } bool isOpen() const; bool encrypted() const { return isEncrypted; } bool readOnly() const { return isReadOnly; } bool getDirty() const; QString currentFile() const { return curDBFilename; } /// log an SQL statement [thread-safe] void logSQL(const QString& statement, LogMessageType msgtype) const; QString getPragma(const std::string& pragma) const; bool setPragma(const std::string& pragma, const QString& value); bool setPragma(const std::string& pragma, const QString& value, QString& originalvalue); bool setPragma(const std::string& pragma, int value, int& originalvalue); bool loadExtension(const QString& filename); void loadExtensionsFromSettings(); static QStringList Datatypes; static QStringList DatatypesStrict; private: std::vector > queryColumnInformation(const std::string& schema_name, const std::string& object_name) const; public: std::string generateSavepointName(const std::string& identifier = std::string()) const; // This function generates the name for a temporary table. It guarantees that there is no table with this name yet std::string generateTemporaryTableName(const std::string& schema) const; schemaMap schemata; signals: void sqlExecuted(QString sql, int msgtype) const; void dbChanged(bool dirty); void structureUpdated(); void requestCollation(QString name, int eTextRep); void databaseInUseChanged(bool busy, QString user); private: /// external code needs to go through get() to obtain access to the database sqlite3 * _db; mutable std::mutex m; mutable std::condition_variable cv; bool db_used; QString db_user; /// wait for release of the DB locked through a previous get(), /// giving users the option to discard running task through a /// message box. void waitForDbRelease(ChoiceOnUse choice = Ask) const; QString curDBFilename; mutable QString lastErrorMessage; std::vector savepointList; bool isEncrypted; bool isReadOnly; sqlb::StringVector primaryKeyForEditing(const sqlb::ObjectIdentifier& table, const sqlb::StringVector& pseudo_pk) const; // SQLite Callbacks void collationNeeded(void* pData, sqlite3* db, int eTextRep, const char* sCollationName); void errorLogCallback(void* user_data, int error_code, const char* message); bool tryEncryptionSettings(const QString& filename, bool* encrypted, CipherSettings* cipherSettings) const; bool disableStructureUpdateChecks; class NoStructureUpdateChecks { public: explicit NoStructureUpdateChecks(DBBrowserDB& db) : m_db(db) { m_db.disableStructureUpdateChecks = true; } ~NoStructureUpdateChecks() { m_db.disableStructureUpdateChecks = false; } private: DBBrowserDB& m_db; }; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/sqlitetablemodel.cpp000066400000000000000000001172211463772530400245250ustar00rootroot00000000000000#include "sqlitetablemodel.h" #include "sqlitedb.h" #include "sqlite.h" #include "Settings.h" #include "Data.h" #include "CondFormat.h" #include "RowLoader.h" #include #include #include #include #include #include #include #include #include #include #include SqliteTableModel::SqliteTableModel(DBBrowserDB& db, QObject* parent, const QString& encoding, bool force_wait) : QAbstractTableModel(parent) , m_db(db) , m_lifeCounter(0) , m_currentRowCount(0) , m_realRowCount(0) , m_encoding(encoding) { // Load initial settings first reloadSettings(); worker = new RowLoader( [this, force_wait](){ return m_db.get(tr("reading rows"), force_wait); }, [this](QString stmt){ return m_db.logSQL(stmt, kLogMsg_App); }, m_headers, m_mutexDataCache, m_cache ); worker->start(); // any UI updates must be performed in the UI thread, not in the worker thread: connect(worker, &RowLoader::fetched, this, &SqliteTableModel::handleFinishedFetch, Qt::QueuedConnection); connect(worker, &RowLoader::rowCountComplete, this, &SqliteTableModel::handleRowCountComplete, Qt::QueuedConnection); reset(); } SqliteTableModel::~SqliteTableModel() { worker->stop(); worker->wait(); worker->disconnect(); delete worker; } SqliteTableModel::RowCount SqliteTableModel::rowCountAvailable () const { return m_rowCountAvailable; } void SqliteTableModel::handleFinishedFetch (int life_id, unsigned int fetched_row_begin, unsigned int fetched_row_end) { if(life_id < m_lifeCounter) return; Q_ASSERT(fetched_row_end >= fetched_row_begin); auto old_row_count = m_currentRowCount; auto new_row_count = std::max(old_row_count, fetched_row_begin); new_row_count = std::max(new_row_count, fetched_row_end); Q_ASSERT(new_row_count >= old_row_count); if(new_row_count != old_row_count) { beginInsertRows(QModelIndex(), static_cast(old_row_count), static_cast(new_row_count - 1)); m_currentRowCount = new_row_count; endInsertRows(); } if(fetched_row_end != fetched_row_begin) { // TODO optimize size_t num_columns = m_headers.size(); emit dataChanged(createIndex(static_cast(fetched_row_begin), 0), createIndex(static_cast(fetched_row_end) - 1, static_cast(num_columns) - 1)); } if(m_rowCountAvailable != RowCount::Complete) m_rowCountAvailable = RowCount::Partial; emit finishedFetch(static_cast(fetched_row_begin), static_cast(fetched_row_end)); } void SqliteTableModel::handleRowCountComplete (int life_id, int num_rows) { if(life_id < m_lifeCounter) return; m_realRowCount = static_cast(num_rows); if (num_rows > m_rowsLimit) { num_rows = m_rowsLimit; } m_rowCountAvailable = RowCount::Complete; handleFinishedFetch(life_id, static_cast(num_rows), static_cast(num_rows)); emit finishedRowCount(); } void SqliteTableModel::reset() { beginResetModel(); clearCache(); m_sQuery.clear(); m_query.clear(); m_table_of_query.reset(); m_headers.clear(); m_vDataTypes.clear(); m_mCondFormats.clear(); m_mRowIdFormats.clear(); endResetModel(); } void SqliteTableModel::setQuery(const sqlb::Query& query) { // Unset all previous settings. When setting a table all information on the previously browsed data set is removed first. reset(); // Save the query m_query = query; // Set the row id columns m_table_of_query = m_db.getTableByName(query.table()); if(!m_table_of_query->isView()) { // It is a table m_query.setRowIdColumns(m_table_of_query->rowidColumns()); } else { // It is a view if(m_query.rowIdColumns().empty()) m_query.setRowIdColumn("_rowid_"); } m_vDataTypes.emplace_back(SQLITE_INTEGER); // TODO This is not necessarily true for tables without ROWID or with multiple PKs m_headers.push_back(sqlb::joinStringVector(m_query.rowIdColumns(), ",")); // Store field names and affinity data types for(const auto& fld : m_table_of_query->fields) { m_headers.push_back(fld.name()); m_vDataTypes.push_back(fld.affinity()); } // Tell the query object about the column names m_query.setColumnNames(m_headers); // Apply new query and update view updateAndRunQuery(); } void SqliteTableModel::setQuery(const QString& sQuery) { // Reset reset(); m_sQuery = sQuery.trimmed(); removeCommentsFromQuery(m_sQuery); getColumnNames(sQuery.toStdString()); worker->setQuery(m_sQuery, QString()); // now fetch the first entries triggerCacheLoad(static_cast(m_chunkSize / 2) - 1); emit layoutChanged(); } int SqliteTableModel::rowCount(const QModelIndex&) const { return static_cast(m_currentRowCount); } int SqliteTableModel::realRowCount() const { return static_cast(m_realRowCount); } int SqliteTableModel::columnCount(const QModelIndex&) const { return static_cast(m_headers.size()); } size_t SqliteTableModel::filterCount() const { return m_query.where().size(); } // Convert a number to string using the Unicode superscript characters template static QString toSuperScript(T number) { QString superScript = QString::number(number); superScript.replace("0", "â°"); superScript.replace("1", "¹"); superScript.replace("2", "²"); superScript.replace("3", "³"); superScript.replace("4", "â´"); superScript.replace("5", "âµ"); superScript.replace("6", "â¶"); superScript.replace("7", "â·"); superScript.replace("8", "â¸"); superScript.replace("9", "â¹"); return superScript; } QVariant SqliteTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::FontRole) return QVariant(); if (orientation == Qt::Vertical && role == Qt::FontRole) return QVariant(); if (orientation == Qt::Horizontal) { size_t column = static_cast(section); // if we have a VIRTUAL table the model will not be valid, with no header data if(column < m_headers.size()) { const std::string plainHeader = m_headers.at(static_cast(section)); // In the edit role, return a plain column name, but in the display role, add the sort indicator. switch (role) { case Qt::EditRole: return QString::fromStdString(plainHeader); case Qt::FontRole: { bool is_pk = false; bool is_fk = getForeignKeyClause(column-1) != nullptr; if (contains(m_query.rowIdColumns(), m_headers.at(column))) { is_pk = true; } else if (m_table_of_query) { auto field = sqlb::findField(m_table_of_query, m_headers.at(column)); const auto pk = m_table_of_query->primaryKeyColumns(); is_pk = field != m_table_of_query->fields.end() && contains(pk, field->name()); } QFont font; font.setUnderline(is_pk); font.setItalic(is_fk); return font; } default: QString sortIndicator; for(size_t i = 0; i < m_query.orderBy().size(); i++) { const sqlb::OrderBy sortedColumn = m_query.orderBy()[i]; // Append sort indicator with direction and ordinal number in superscript style if (sortedColumn.expr == plainHeader) { sortIndicator = sortedColumn.direction == sqlb::OrderBy::Ascending ? " â–´" : " â–¾"; if(m_query.orderBy().size() > 1) sortIndicator.append(toSuperScript(i+1)); break; } } return QString::fromStdString(plainHeader) + sortIndicator; } } return QString::number(section + 1); } else return QString::number(section + 1); } QVariant SqliteTableModel::getMatchingCondFormat(const std::map>& mCondFormats, size_t column, const QString& value, int role) const { if (!mCondFormats.count(column)) return QVariant(); bool isNumber; value.toDouble(&isNumber); std::string sql; // For each conditional format for this column, // if the condition matches the current data, return the associated format. for (const CondFormat& eachCondFormat : mCondFormats.at(column)) { if (isNumber && !contains(eachCondFormat.sqlCondition(), '\'')) sql = "SELECT " + value.toStdString() + " " + eachCondFormat.sqlCondition(); else sql = "SELECT " + sqlb::escapeString(value.toStdString()) + " " + eachCondFormat.sqlCondition(); // Empty filter means: apply format to any row. // Query the DB for the condition, waiting in case there is a loading in progress. if (eachCondFormat.filter().isEmpty() || m_db.querySingleValueFromDb(sql, false, DBBrowserDB::Wait) == "1") switch (role) { case Qt::ForegroundRole: return eachCondFormat.foregroundColor(); case Qt::BackgroundRole: return eachCondFormat.backgroundColor(); case Qt::FontRole: return eachCondFormat.font(); case Qt::TextAlignmentRole: return static_cast(eachCondFormat.alignmentFlag() | Qt::AlignVCenter); } } return QVariant(); } QVariant SqliteTableModel::getMatchingCondFormat(size_t row, size_t column, const QString& value, int role) const { QVariant format; // Check first for a row-id format and when there is none, for a conditional format. if (m_mRowIdFormats.count(column)) { std::unique_lock lock(m_mutexDataCache); const bool row_available = m_cache.count(row); const QByteArray blank_data(""); const QByteArray& row_id_data = row_available ? m_cache.at(row).at(0) : blank_data; lock.unlock(); format = getMatchingCondFormat(m_mRowIdFormats, column, row_id_data, role); if (format.isValid()) return format; } if (m_mCondFormats.count(column)) return getMatchingCondFormat(m_mCondFormats, column, value, role); else return QVariant(); } QVariant SqliteTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= rowCount()) return QVariant(); std::unique_lock lock(m_mutexDataCache); const size_t row = static_cast(index.row()); const size_t column = static_cast(index.column()); const bool row_available = m_cache.count(row); const QByteArray blank_data(""); const QByteArray& data = row_available ? m_cache.at(row).at(column) : blank_data; if(role == Qt::DisplayRole) { if(!row_available) return tr("loading..."); if(data.isNull()) { return m_nullText; } else if(isBinary(data)) { return m_blobText; } else { if (data.length() > m_symbolLimit) { // Add "..." to the end of truncated strings return decode(data.left(m_symbolLimit).append(" ...")); } else { return decode(data); } } } else if(role == Qt::EditRole) { if(!row_available) return QVariant(); return decode(data); } else if(role == Qt::FontRole) { QFont font = m_font; if(!row_available || data.isNull() || isBinary(data)) font.setItalic(true); else { // Unlock before querying from DB lock.unlock(); QVariant condFormatFont = getMatchingCondFormat(row, column, data, role); if (condFormatFont.isValid()) return condFormatFont; } return font; } else if(role == Qt::ForegroundRole) { if(!row_available) return QColor(100, 100, 100); if(data.isNull()) return m_nullFgColour; else if (isBinary(data)) return m_binFgColour; else { // Unlock before querying from DB lock.unlock(); QVariant condFormatColor = getMatchingCondFormat(row, column, data, role); if (condFormatColor.isValid()) return condFormatColor; if (hasDisplayFormat(index)) return m_formattedFgColour; } // Regular case (not null, not binary, no matching conditional format and no display format) return m_regFgColour; } else if (role == Qt::BackgroundRole) { if(!row_available) return QColor(255, 200, 200); if(data.isNull()) return m_nullBgColour; else if (isBinary(data)) return m_binBgColour; else { // Unlock before querying from DB lock.unlock(); QVariant condFormatColor = getMatchingCondFormat(row, column, data, role); if (condFormatColor.isValid()) return condFormatColor; if (hasDisplayFormat(index)) return m_formattedBgColour; } // Regular case (not null, not binary, no matching conditional format and no display format) return m_regBgColour; } else if(role == Qt::ToolTipRole) { auto fk = getForeignKeyClause(column-1); if(fk) return tr("References %1(%2)\nHold %3Shift and click to jump there").arg( QString::fromStdString(fk->table()), QString::fromStdString(sqlb::joinStringVector(fk->columns(), ",")), QKeySequence(Qt::CTRL).toString(QKeySequence::NativeText)); } else if (role == Qt::TextAlignmentRole) { // Align horizontally according to conditional format or default (left for text and right for numbers) // Align vertically to the center, which displays better. lock.unlock(); QVariant condFormat = getMatchingCondFormat(row, column, data, role); if (condFormat.isValid()) return condFormat; bool isNumber = m_vDataTypes.at(column) == SQLITE_INTEGER || m_vDataTypes.at(column) == SQLITE_FLOAT; return static_cast((isNumber ? Qt::AlignRight : Qt::AlignLeft) | Qt::AlignVCenter); } else if(role == Qt::DecorationRole) { if(!row_available) return QVariant(); if(m_imagePreviewEnabled && !isImageData(data).isNull()) { QImage img; if(img.loadFromData(data)) return QPixmap::fromImage(img); } } return QVariant(); } std::shared_ptr SqliteTableModel::getForeignKeyClause(size_t column) const { // No foreign keys when not browsing a table. This usually happens when executing custom SQL statements // and browsing the result set instead of browsing an entire table. if(m_query.table().isEmpty()) return nullptr; // Check if database object is a table. If it isn't stop here and don't return a foreign key. // This happens for views which don't have foreign keys (though we might want to think about // how we can check for foreign keys in the underlying tables for some purposes like tool tips). // If it is a table, heck if the column number is in the valid range. if(m_table_of_query && m_table_of_query->name().size() && column < m_table_of_query->fields.size()) { // Note that the rowid column has number -1 here, it can safely be excluded since there will never be a // foreign key on that column. return m_table_of_query->foreignKey({m_table_of_query->fields.at(column).name()}); } return nullptr; } bool SqliteTableModel::setData(const QModelIndex& index, const QVariant& value, int role) { // Don't even try setting any data if we're not browsing a table, i.e. the model data comes from a custom query if(!isEditable(index)) return false; // This function is for in-place editing. // So, BLOB flag is false every times. return setTypedData(index, false, value, role); } bool SqliteTableModel::setTypedData(const QModelIndex& index, bool isBlob, const QVariant& value, int role) { if(readingData()) { // can't insert rows while reading data in background return false; } m_db.setUndoSavepoint(); if(index.isValid() && role == Qt::EditRole) { std::unique_lock lock(m_mutexDataCache); auto & cached_row = m_cache.at(static_cast(index.row())); const size_t column = static_cast(index.column()); QByteArray newValue = encode(value.toByteArray()); QByteArray oldValue = cached_row.at(column); // Special handling for integer columns: instead of setting an integer column to an empty string, set it to '0' when it is also // used in a primary key. Otherwise SQLite will always output an 'datatype mismatch' error. if(newValue == "" && !newValue.isNull()) { if(m_table_of_query) { auto field = sqlb::findField(m_table_of_query, m_headers.at(column)); const auto pk = m_table_of_query->primaryKeyColumns(); if(contains(pk, field->name()) && field->isInteger()) newValue = "0"; } } // Don't do anything if the data hasn't changed // To differentiate NULL and empty byte arrays, we also compare the NULL flag if(oldValue == newValue && oldValue.isNull() == newValue.isNull()) return true; // Determine type. If the BLOB flag is set, it's always BLOB. If the affinity data type of the modified column is something numeric, // we check if the new value is also numeric. In that case we can safely set the data type to INTEGER or FLOAT. In all other cases we // default to TEXT. int type = SQLITE_TEXT; if(isBlob) { type = SQLITE_BLOB; } else if(m_vDataTypes.at(column) == SQLITE_INTEGER) { bool ok; newValue.toLongLong(&ok); if(ok) type = SQLITE_INTEGER; } else if(m_vDataTypes.at(column) == SQLITE_FLOAT) { bool ok; newValue.toDouble(&ok); if(ok) type = SQLITE_FLOAT; } if(m_db.updateRecord(m_query.table(), m_headers.at(column), cached_row.at(0), newValue, type, m_query.rowIdColumns())) { cached_row[column] = newValue; // After updating the value itself in the cache, we need to check if we need to update the rowid too. if(contains(m_query.rowIdColumns(), m_headers.at(column))) { // When the cached rowid column needs to be updated as well, we need to distinguish between single-column and multi-column primary keys. // For the former ones, we can just overwrite the existing value with the new value. // For the latter ones, we need to make a new JSON object of the values of all primary key columns, not just the updated one. if(m_query.rowIdColumns().size() == 1) { cached_row[0] = newValue; } else { assert(m_headers.size() == cached_row.size()); QByteArray output; for(size_t i=0;i(std::distance(m_headers.begin(), it))]; output += QByteArray::number(v.size()) + ":" + v; } cached_row[0] = output; } const QModelIndex& rowidIndex = index.sibling(index.row(), 0); lock.unlock(); emit dataChanged(rowidIndex, rowidIndex); } else { lock.unlock(); } emit dataChanged(index, index); return true; } else { lock.unlock(); QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error changing data:\n%1").arg(m_db.lastError())); return false; } } return false; } // Custom display format set? bool SqliteTableModel::hasDisplayFormat (const QModelIndex& index) const { bool custom_display_format = false; if(m_query.selectedColumns().size()) { if(index.column() > 0) custom_display_format = m_query.selectedColumns().at(static_cast(index.column())-1).selector != m_query.selectedColumns().at(static_cast(index.column())-1).original_column; } return custom_display_format; } Qt::ItemFlags SqliteTableModel::flags(const QModelIndex& index) const { if(!index.isValid()) return Qt::ItemIsEnabled; Qt::ItemFlags ret = QAbstractTableModel::flags(index) | Qt::ItemIsDropEnabled; if(!isBinary(index) && !hasDisplayFormat(index) && isEditable(index)) ret |= Qt::ItemIsEditable; return ret; } void SqliteTableModel::sort(int column, Qt::SortOrder order) { // Construct a sort order list from this item and forward it to the function to sort by lists std::vector list; list.emplace_back(m_headers.at(static_cast(column)), order == Qt::AscendingOrder ? sqlb::OrderBy::Ascending : sqlb::OrderBy::Descending); sort(list); } void SqliteTableModel::sort(const std::vector& columns) { // Don't do anything when the sort order hasn't changed if(m_query.orderBy() == columns) return; // Save sort order m_query.orderBy() = columns; // Set the new query (but only if a table has already been set if(!m_query.table().isEmpty()) updateAndRunQuery(); } SqliteTableModel::Row SqliteTableModel::makeDefaultCacheEntry () const { Row blank_data; for(size_t i=0; i < m_headers.size(); ++i) blank_data.emplace_back(""); return blank_data; } bool SqliteTableModel::readingData() const { return worker->readingData(); } bool SqliteTableModel::insertRows(int row, int count, const QModelIndex& parent) { if(!isEditable()) return false; if(readingData()) { // can't insert rows while reading data in background return false; } const auto blank_data = makeDefaultCacheEntry(); std::vector tempList; for(int i=row; i < row + count; ++i) { QString rowid = m_db.addRecord(m_query.table()); if(rowid.isNull()) { return false; } tempList.emplace_back(blank_data); tempList.back()[0] = rowid.toUtf8(); // update column with default values Row rowdata; if(m_db.getRow(m_query.table(), rowid, rowdata)) { for(size_t j=1; j < m_headers.size(); ++j) { tempList.back()[j] = rowdata[j - 1]; } } } beginInsertRows(parent, row, row + count - 1); for(size_t i = 0; i < tempList.size(); ++i) { m_cache.insert(i + static_cast(row), std::move(tempList.at(i))); m_currentRowCount++; m_realRowCount++; } endInsertRows(); return true; } bool SqliteTableModel::removeRows(int row, int count, const QModelIndex& parent) { if(!isEditable()) return false; if(readingData()) { // can't delete rows while reading data in background return false; } std::vector rowids; for(int i=count-1;i>=0;i--) { if(m_cache.count(static_cast(row+i))) { rowids.push_back(m_cache.at(static_cast(row + i)).at(0)); } } bool ok = m_db.deleteRecords(m_query.table(), rowids, m_query.rowIdColumns()); if (ok) { beginRemoveRows(parent, row, row + count - 1); for(int i=count-1;i>=0;i--) { m_cache.erase(static_cast(row + i)); m_currentRowCount--; m_realRowCount--; } endRemoveRows(); } return ok; } QModelIndex SqliteTableModel::dittoRecord(int old_row) { if(!isEditable()) return QModelIndex(); if (!insertRow(rowCount())) return QModelIndex(); size_t firstEditedColumn = 0; int new_row = rowCount() - 1; const auto pk = m_table_of_query->primaryKeyColumns(); for (size_t col = 0; col < m_table_of_query->fields.size(); ++col) { if(pk.empty() || !contains(pk, m_table_of_query->fields.at(col).name())) { if (!firstEditedColumn) firstEditedColumn = col + 1; QVariant value = data(index(old_row, static_cast(col + 1)), Qt::EditRole); setData(index(new_row, static_cast(col + 1)), value); } } return index(new_row, static_cast(firstEditedColumn)); } void SqliteTableModel::updateAndRunQuery() { clearCache(); // Update the query m_sQuery = QString::fromStdString(m_query.buildQuery(true)); QString sCountQuery = QString::fromStdString(m_query.buildCountQuery()); worker->setQuery(m_sQuery, sCountQuery); // now fetch the first entries triggerCacheLoad(static_cast(m_chunkSize / 2) - 1); emit layoutChanged(); } void SqliteTableModel::getColumnNames(const std::string& sQuery) { auto pDb = m_db.get(tr("retrieving list of columns")); sqlite3_stmt* stmt; if(sqlite3_prepare_v2(pDb.get(), sQuery.c_str(), static_cast(sQuery.size()), &stmt, nullptr) == SQLITE_OK) { int columns = sqlite3_column_count(stmt); for(int i = 0; i < columns; ++i) { m_headers.push_back(sqlite3_column_name(stmt, i)); m_vDataTypes.push_back(sqlite3_column_type(stmt, i)); } } sqlite3_finalize(stmt); } static void addCondFormatToMap(std::map>& mCondFormats, size_t column, const CondFormat& condFormat) { // If the condition is already present in the vector, update that entry and respect the order, since two entries with the same // condition do not make sense. auto it = std::find_if(mCondFormats[column].begin(), mCondFormats[column].end(), [condFormat](const CondFormat& format) { return format.sqlCondition() == condFormat.sqlCondition(); }); // Replace cond-format if present. push it back if it's a conditionless format (apply to every cell in column) or insert // as first element otherwise. if(it != mCondFormats[column].end()) { *it = condFormat; } else if (condFormat.filter().isEmpty()) mCondFormats[column].push_back(condFormat); else mCondFormats[column].insert(mCondFormats[column].begin(), condFormat); } void SqliteTableModel::addCondFormat(const bool isRowIdFormat, size_t column, const CondFormat& condFormat) { if(isRowIdFormat) addCondFormatToMap(m_mRowIdFormats, column, condFormat); else addCondFormatToMap(m_mCondFormats, column, condFormat); emit layoutChanged(); } void SqliteTableModel::setCondFormats(const bool isRowIdFormat, size_t column, const std::vector& condFormats) { if(isRowIdFormat) m_mRowIdFormats[column] = condFormats; else m_mCondFormats[column] = condFormats; emit layoutChanged(); } void SqliteTableModel::updateFilter(const std::string& column, const QString& value) { std::string whereClause = CondFormat::filterToSqlCondition(value, m_encoding); // If the value was set to an empty string remove any filter for this column. Otherwise insert a new filter rule or replace the old one if there is already one if(whereClause.empty()) m_query.where().erase(column); else m_query.where()[column] = whereClause; // Build the new query updateAndRunQuery(); } void SqliteTableModel::updateGlobalFilter(const std::vector& values) { std::vector filters; for(auto& v : values) filters.push_back(CondFormat::filterToSqlCondition(v, m_encoding)); m_query.setGlobalWhere(filters); // Build the new query updateAndRunQuery(); } void SqliteTableModel::clearCache() { m_lifeCounter++; if(m_db.isOpen()) { worker->cancel(); worker->waitUntilIdle(); } if(m_currentRowCount > 0) { beginRemoveRows(QModelIndex(), 0, static_cast(m_currentRowCount - 1)); endRemoveRows(); } m_cache.clear(); m_currentRowCount = 0; m_realRowCount = 0; m_rowCountAvailable = RowCount::Unknown; } bool SqliteTableModel::isBinary(const QModelIndex& index) const { std::lock_guard lock(m_mutexDataCache); const size_t row = static_cast(index.row()); if(!m_cache.count(row)) return false; const auto & cached_row = m_cache.at(row); return isBinary(cached_row.at(static_cast(index.column()))); } bool SqliteTableModel::isBinary(const QByteArray& data) const { return !isTextOnly(data, m_encoding, true); } QByteArray SqliteTableModel::encode(const QByteArray& str) const { return encodeString(str, m_encoding); } QByteArray SqliteTableModel::decode(const QByteArray& str) const { return decodeString(str, m_encoding); } Qt::DropActions SqliteTableModel::supportedDropActions() const { return Qt::CopyAction; } bool SqliteTableModel::dropMimeData(const QMimeData* data, Qt::DropAction, int row, int column, const QModelIndex& parent) { // What has been dropped on the widget? if(data->hasUrls()) { // If it's a URL, open the file and paste the content in the current cell QList urls = data->urls(); QFile file(urls.first().toLocalFile()); if(file.exists() && file.open(QFile::ReadOnly)) { setData(index(row, column, parent), file.readAll()); return true; } } else if(data->hasText()) { // If it's just text we can set the cell data directly setData(index(row, column, parent), data->text()); } return false; } void SqliteTableModel::setPseudoPk(std::vector pseudoPk) { if(!m_table_of_query->isView()) return; if(pseudoPk.empty()) pseudoPk.emplace_back("_rowid_"); // Do nothing if the value didn't change if(m_query.rowIdColumns() == pseudoPk) return; m_query.setRowIdColumns(pseudoPk); if(m_headers.size()) m_headers[0] = sqlb::joinStringVector(pseudoPk, ","); updateAndRunQuery(); } bool SqliteTableModel::hasPseudoPk() const { return m_query.hasCustomRowIdColumn(); } bool SqliteTableModel::isEditable(const QModelIndex& index) const { if(m_query.table().isEmpty()) return false; if(!m_db.isOpen()) return false; if((!m_table_of_query || m_table_of_query->isView()) && !m_query.hasCustomRowIdColumn()) return false; // Extra check when the index parameter is set and pointing to a generated column in a table if(index.isValid() && m_table_of_query) { const auto field = sqlb::findField(m_table_of_query, m_headers.at(static_cast(index.column()))); if(field != m_table_of_query->fields.cend() && field->generated()) return false; } return true; } void SqliteTableModel::triggerCacheLoad (int row) const { int halfChunk = static_cast( m_chunkSize / 2); size_t row_begin = static_cast(std::max(0, row - halfChunk)); size_t row_end = static_cast(row + halfChunk); if(rowCountAvailable() == RowCount::Complete) { row_end = std::min(row_end, static_cast(rowCount())); } else { // will be truncated by reader } // avoid re-fetching data std::lock_guard lk(m_mutexDataCache); m_cache.smallestNonAvailableRange(row_begin, row_end); if(row_end != row_begin) worker->triggerFetch(m_lifeCounter, row_begin, row_end); } void SqliteTableModel::triggerCacheLoad (int row_begin, int row_end) const { if(row_end == row_begin) return; triggerCacheLoad((row_begin + row_end) / 2); } bool SqliteTableModel::completeCache () const { // Show progress dialog because fetching all data might take some time but only show // cancel button if we allow cancellation here. This isn't QProgressDialog progress(tr("Fetching data..."), tr("Cancel"), 0, rowCount()); QPushButton* cancelButton = new QPushButton(tr("Cancel")); // This is to prevent distracted cancellation of the fetching and avoid the // Snap-To Windows optional feature. cancelButton->setDefault(false); cancelButton->setAutoDefault(false); progress.setCancelButton(cancelButton); progress.setWindowModality(Qt::ApplicationModal); // Disable context help button on Windows progress.setWindowFlags(progress.windowFlags() & ~Qt::WindowContextHelpButtonHint); progress.show(); waitUntilIdle(); // This loop fetches all data by loading it block by block into the cache for(int i = 0; i < (rowCount() + static_cast( m_chunkSize / 2)); i += static_cast(m_chunkSize)) { progress.setValue(i); qApp->processEvents(); if(progress.wasCanceled()) return false; triggerCacheLoad(i); worker->waitUntilIdle(); } return true; } bool SqliteTableModel::isCacheComplete () const { if(readingData()) return false; std::lock_guard lock(m_mutexDataCache); return m_cache.numSet() == m_currentRowCount; } void SqliteTableModel::waitUntilIdle () const { worker->waitUntilIdle(); } QModelIndex SqliteTableModel::nextMatch(const QModelIndex& start, const std::vector& column_list, const QString& value, Qt::MatchFlags flags, bool reverse, bool dont_skip_to_next_field) const { // Extract flags bool whole_cell = !(flags & Qt::MatchContains); bool regex = flags & Qt::MatchRegExp; Qt::CaseSensitivity case_sensitive = ((flags & Qt::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive); bool wrap = flags & Qt::MatchWrap; int increment = (reverse ? -1 : 1); // Prepare the regular expression for regex mode QRegularExpression reg_exp; if(regex) { reg_exp = QRegularExpression(value, (case_sensitive ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption)); if(!reg_exp.isValid()) return QModelIndex(); if(whole_cell) { #if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) reg_exp.setPattern("\\A(" + reg_exp.pattern() + ")\\Z"); #else reg_exp.setPattern(QRegularExpression::anchoredPattern(reg_exp.pattern())); #endif } } // Wait until the row count is there waitUntilIdle(); // Stop right away if there is no data in the table if(rowCount() == 0) return QModelIndex(); // Make sure the start position starts in a column from the list of columns to search in QModelIndex pos = start; if(std::find(column_list.begin(), column_list.end(), pos.column()) == column_list.end()) { // If for some weird reason the start index is not in the column list, we simply use the first column of the column list instead pos = pos.sibling(pos.row(), reverse ? column_list.back() : column_list.front()); } // Get the last cell to search in. If wrapping is enabled, we search until we hit the start cell again. If wrapping is not enabled, we start at the last // cell of the table. QModelIndex end = (wrap ? pos : index(rowCount(), column_list.back())); // Loop through all cells for the search while(true) { // Go to the next cell and skip all columns in between which we do not care about. This is done as the first step in order // to skip the start index when matching the first cell is disabled. if(dont_skip_to_next_field == false) { while(true) { // Next cell position int next_row = pos.row(); int next_column = pos.column() + increment; // Have we reached the end of the row? Then go to the next one if(next_column < 0 || next_column >= static_cast(m_headers.size())) { next_row += increment; next_column = (reverse ? column_list.back() : column_list.front()); } // Have we reached the last row? Then wrap around to the first one if(wrap && (next_row < 0 || next_row >= rowCount())) next_row = (reverse ? rowCount()-1 : 0); // Set next index for search pos = pos.sibling(next_row, next_column); // Have we hit the last column? We have not found anything then if(pos == end) return QModelIndex(); // Is this a column which we are supposed to search in? If so, stop looking for the next cell and start comparing if(std::find(column_list.begin(), column_list.end(), next_column) != column_list.end()) break; } } // Make sure the next time we hit the above check, we actuall move on to the next cell and do not skip the loop again. dont_skip_to_next_field = false; // Get row from cache. If it is not in the cache, load the next chunk from the database const size_t row = static_cast(pos.row()); if(!m_cache.count(row)) { triggerCacheLoad(static_cast(row)); waitUntilIdle(); } const Row* row_data = &m_cache.at(row); // Get cell data const size_t column = static_cast(pos.column()); QString data = row_data->at(column); // Perform comparison if(whole_cell && !regex && data.compare(value, case_sensitive) == 0) return pos; else if(!whole_cell && !regex && data.contains(value, case_sensitive)) return pos; else if(regex && reg_exp.match(data).hasMatch()) return pos; } } void SqliteTableModel::reloadSettings() { m_nullText = Settings::getValue("databrowser", "null_text").toString(); m_blobText = Settings::getValue("databrowser", "blob_text").toString(); m_regFgColour = QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()); m_regBgColour = QColor(Settings::getValue("databrowser", "reg_bg_colour").toString()); m_formattedFgColour = QColor(Settings::getValue("databrowser", "formatted_fg_colour").toString()); m_formattedBgColour = QColor(Settings::getValue("databrowser", "formatted_bg_colour").toString()); m_nullFgColour = QColor(Settings::getValue("databrowser", "null_fg_colour").toString()); m_nullBgColour = QColor(Settings::getValue("databrowser", "null_bg_colour").toString()); m_binFgColour = QColor(Settings::getValue("databrowser", "bin_fg_colour").toString()); m_binBgColour = QColor(Settings::getValue("databrowser", "bin_bg_colour").toString()); m_font = QFont(Settings::getValue("databrowser", "font").toString()); m_font.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); m_symbolLimit = Settings::getValue("databrowser", "symbol_limit").toInt(); m_rowsLimit = Settings::getValue("databrowser", "rows_limit").toInt(); m_imagePreviewEnabled = Settings::getValue("databrowser", "image_preview").toBool(); m_chunkSize = static_cast(Settings::getValue("db", "prefetchsize").toUInt()); } sqlitebrowser-sqlitebrowser-5733cb7/src/sqlitetablemodel.h000066400000000000000000000251651463772530400241770ustar00rootroot00000000000000#ifndef SQLITETABLEMODEL_H #define SQLITETABLEMODEL_H #include #include #include #include #include #include #include #include "RowCache.h" #include "sql/Query.h" #include "sql/sqlitetypes.h" struct sqlite3; class DBBrowserDB; class CondFormat; class SqliteTableModel : public QAbstractTableModel { Q_OBJECT #ifdef REGEX_UNIT_TEST friend class TestRegex; #endif public: explicit SqliteTableModel(DBBrowserDB& db, QObject *parent = nullptr, const QString& encoding = QString(), bool force_wait = false); ~SqliteTableModel() override; /// reset to state after construction void reset(); /// returns logical amount of rows, whether currently cached or not int rowCount(const QModelIndex &parent = QModelIndex()) const override; int realRowCount() const; int columnCount(const QModelIndex &parent = QModelIndex()) const override; size_t filterCount() const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; bool setTypedData(const QModelIndex& index, bool isBlob, const QVariant& value, int role = Qt::EditRole); enum class RowCount { Unknown, //< still finding out in background... Partial, //< some chunk was read and at least a lower bound is thus known Complete //< total row count of table known }; /// what kind of information is available through rowCount()? RowCount rowCountAvailable () const; /// trigger asynchronous loading of (at least) the specified row /// into cache. void triggerCacheLoad (int single_row) const; /// trigger asynchronous loading of (at least) the specified rows /// into cache. \param row_end is exclusive. void triggerCacheLoad (int row_begin, int row_end) const; /// wait until not reading any data (that does not mean data is /// complete, just that the background reader is idle) void waitUntilIdle () const; /// load all rows into cache, return when done. Returns true if all data was loaded, false if the loading was cancelled. bool completeCache() const; /// returns true if all rows are currently available in cache /// [NOTE: potentially unsafe in case we have a limited-size /// cache, where entries can vanish again -- however we can't do /// this for the current implementation of the PlotDock] bool isCacheComplete () const; bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; QModelIndex dittoRecord(int old_row); /// configure for browsing results of specified query void setQuery(const QString& sQuery); std::string query() const { return m_sQuery.toStdString(); } std::string customQuery(bool withRowid) const { return m_query.buildQuery(withRowid); } /// configure for browsing specified table void setQuery(const sqlb::Query& query); void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; void sort(const std::vector& columns); sqlb::ObjectIdentifier currentTableName() const { return m_query.table(); } Qt::ItemFlags flags(const QModelIndex& index) const override; bool isBinary(const QModelIndex& index) const; void setEncoding(const QString& encoding) { m_encoding = encoding; } QString encoding() const { return m_encoding; } // The pseudo-primary key is exclusively for editing views void setPseudoPk(std::vector pseudoPk); bool hasPseudoPk() const; std::vector pseudoPk() const { return m_query.rowIdColumns(); } std::shared_ptr getForeignKeyClause(size_t column) const; // This returns true if the model and, if set, the index can be edited. Not specifying the index parameter asks whether the model can // be edited in general (i.e. inserting and deleting rows as well as updating some cells). Specifying the index parameter asks whether // this specific index can be edited. // The model is able to operate in more or less two different modes, table browsing and query browsing. We only support editing data // in the table browsing mode but not for the query mode. This function returns true if the model is currently editable, i.e. it's // running in the table mode and isn't browsing a view, unless this view is set up for editing by specifying a pseudo PK. // When the index parameter is set, the same checks are performed but additionally the function checks whether this specific index // can be edited. This makes a difference for generated columns which are in (editable) tables but cannot be modified anyway. bool isEditable(const QModelIndex& index = QModelIndex()) const; // Custom display format set? bool hasDisplayFormat (const QModelIndex& index) const; // Conditional formats are of two kinds: regular conditional formats (including condition-free formats applying to any value in the // column) and formats applying to a particular row-id and which have always precedence over the first kind and whose filter apply // to the row-id column. void addCondFormat(const bool isRowIdFormat, size_t column, const CondFormat& condFormat); void setCondFormats(const bool isRowIdFormat, size_t column, const std::vector& condFormats); // Search for the specified expression in the given cells. This intended as a replacement for QAbstractItemModel::match() even though // it does not override it, which - because of the different parameters - is not possible. // start contains the index to start with, column_list contains the ordered list of the columns to look in, value is the value to search for, // flags allows to modify the search process (Qt::MatchContains, Qt::MatchRegExp, Qt::MatchCaseSensitive, and Qt::MatchWrap are understood), // reverse can be set to true to progress through the cells in backwards direction, and dont_skip_to_next_field can be set to true if the current // cell can be matched as well. QModelIndex nextMatch(const QModelIndex& start, const std::vector& column_list, const QString& value, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchContains), bool reverse = false, bool dont_skip_to_next_field = false) const; DBBrowserDB& db() { return m_db; } void reloadSettings(); public slots: void updateFilter(const std::string& column, const QString& value); void updateGlobalFilter(const std::vector& values); signals: void finishedFetch(int fetched_row_begin, int fetched_row_end); void finishedRowCount(); protected: Qt::DropActions supportedDropActions() const override; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; private: friend class RowLoader; class RowLoader * worker; /// clears the cache, resets row-count to unknown (but keeps table /// & query info), increase life_counter void clearCache(); void handleFinishedFetch(int life_id, unsigned int fetched_row_begin, unsigned int fetched_row_end); void handleRowCountComplete(int life_id, int num_rows); void updateAndRunQuery(); void getColumnNames(const std::string& sQuery); QByteArray encode(const QByteArray& str) const; QByteArray decode(const QByteArray& str) const; // Return matching conditional format color/font or invalid value, otherwise. // Only format roles are expected in role (Qt::ItemDataRole) QVariant getMatchingCondFormat(size_t row, size_t column, const QString& value, int role) const; QVariant getMatchingCondFormat(const std::map>& mCondFormats, size_t column, const QString& value, int role) const; DBBrowserDB& m_db; /// counts numbers of clearCache() since instantiation; using this /// to avoid processing of queued signals originating in an era /// before the most recent reset(). int m_lifeCounter; /// note: the row count can be determined by the row-count query /// (which yields the "final" row count"), or, if it is faster, by /// the first chunk reading actual data (in which case the row /// count will be set to that chunk's size and later updated to /// the full row count, when the row-count query returns) RowCount m_rowCountAvailable; unsigned int m_currentRowCount; unsigned int m_realRowCount; std::vector m_headers; /// reading something in background right now? (either counting /// rows or actually loading data, doesn't matter) bool readingData() const; using Row = std::vector; mutable RowCache m_cache; Row makeDefaultCacheEntry () const; bool isBinary(const QByteArray& index) const; QString m_sQuery; std::vector m_vDataTypes; std::map> m_mCondFormats; std::map> m_mRowIdFormats; sqlb::Query m_query; std::shared_ptr m_table_of_query; // This holds a pointer to the table object which is queried in the m_query object QString m_encoding; /** * These are used for multi-threaded population of the table */ mutable std::mutex m_mutexDataCache; private: /** * Settings. These are stored here to avoid fetching and converting them every time we need them. Because this class * uses a lot of settings and because some of its functions are called very often, this should speed things up noticeable. * Call reloadSettings() to update these. */ QString m_nullText; QString m_blobText; QColor m_regFgColour; QColor m_regBgColour; QColor m_formattedFgColour; QColor m_formattedBgColour; QColor m_nullFgColour; QColor m_nullBgColour; QColor m_binFgColour; QColor m_binBgColour; QFont m_font; int m_symbolLimit; int m_rowsLimit; bool m_imagePreviewEnabled; /** * @brief m_chunkSize Size of the next chunk fetch more will try to fetch. * This value should be rather high, because our query * uses LIMIT and sqlite3 will still execute the whole query and * just skip the not wanted rows, but the execution will * still take nearly the same time as doing the query at all up * to that row count. */ size_t m_chunkSize; }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/sqltextedit.cpp000066400000000000000000000131001463772530400235340ustar00rootroot00000000000000#include "sql/ObjectIdentifier.h" #include "sqltextedit.h" #include "Settings.h" #include "SqlUiLexer.h" #include #include #include #include SqlUiLexer* SqlTextEdit::sqlLexer = nullptr; SqlTextEdit::SqlTextEdit(QWidget* parent) : ExtendedScintilla(parent) { // Create lexer object if not done yet if(sqlLexer == nullptr) sqlLexer = new SqlUiLexer(this); // Set the SQL lexer setLexer(sqlLexer); // Set icons for auto completion registerImage(SqlUiLexer::ApiCompleterIconIdKeyword, QImage(":/icons/keyword")); registerImage(SqlUiLexer::ApiCompleterIconIdFunction, QImage(":/icons/function")); registerImage(SqlUiLexer::ApiCompleterIconIdTable, QImage(":/icons/table")); registerImage(SqlUiLexer::ApiCompleterIconIdColumn, QImage(":/icons/field")); registerImage(SqlUiLexer::ApiCompleterIconIdSchema, QImage(":/icons/database")); // Remove command bindings that would interfere with our shortcutToggleComment QsciCommand * command = standardCommands()->boundTo(Qt::ControlModifier+Qt::Key_Slash); command->setKey(0); command = standardCommands()->boundTo(Qt::ControlModifier+Qt::ShiftModifier+Qt::Key_Slash); command->setKey(0); // Change command binding for Ctrl+T so it doesn't interfere with "Open tab" command = standardCommands()->boundTo(Qt::ControlModifier+Qt::Key_T); command->setKey(Qt::ControlModifier+Qt::ShiftModifier+Qt::Key_Up); // Change command binding for Ctrl+Shift+T so it doesn't interfere with "Open SQL file" command = standardCommands()->boundTo(Qt::ControlModifier+Qt::ShiftModifier+Qt::Key_T); command->setKey(Qt::ControlModifier+Qt::ShiftModifier+Qt::Key_Insert); QShortcut* shortcutToggleComment = new QShortcut(QKeySequence(tr("Ctrl+/")), this, nullptr, nullptr, Qt::WidgetShortcut); connect(shortcutToggleComment, &QShortcut::activated, this, &SqlTextEdit::toggleBlockComment); // Do rest of initialisation reloadSettings(); } void SqlTextEdit::reloadSettings() { // Enable auto completion if it hasn't been disabled if(Settings::getValue("editor", "auto_completion").toBool()) { setAutoCompletionThreshold(3); setAutoCompletionCaseSensitivity(true); setAutoCompletionShowSingle(true); setAutoCompletionSource(QsciScintilla::AcsAPIs); } else { setAutoCompletionThreshold(0); } // Set wrap lines setWrapMode(static_cast(Settings::getValue("editor", "wrap_lines").toInt())); ExtendedScintilla::reloadSettings(); setupSyntaxHighlightingFormat(sqlLexer, "comment", QsciLexerSQL::Comment); setupSyntaxHighlightingFormat(sqlLexer, "comment", QsciLexerSQL::CommentLine); setupSyntaxHighlightingFormat(sqlLexer, "comment", QsciLexerSQL::CommentDoc); setupSyntaxHighlightingFormat(sqlLexer, "keyword", QsciLexerSQL::Keyword); setupSyntaxHighlightingFormat(sqlLexer, "table", QsciLexerSQL::KeywordSet6); setupSyntaxHighlightingFormat(sqlLexer, "function", QsciLexerSQL::KeywordSet7); setupSyntaxHighlightingFormat(sqlLexer, "string", QsciLexerSQL::SingleQuotedString); // Highlight double quote strings as identifier or as literal string depending on user preference switch(static_cast(Settings::getValue("editor", "identifier_quotes").toInt())) { case sqlb::DoubleQuotes: setupSyntaxHighlightingFormat(sqlLexer, "identifier", QsciLexerSQL::DoubleQuotedString); sqlLexer->setQuotedIdentifiers(false); break; case sqlb::GraveAccents: sqlLexer->setQuotedIdentifiers(true); setupSyntaxHighlightingFormat(sqlLexer, "string", QsciLexerSQL::DoubleQuotedString); // treat quoted string as literal string break; case sqlb::SquareBrackets: setupSyntaxHighlightingFormat(sqlLexer, "string", QsciLexerSQL::DoubleQuotedString); break; } setupSyntaxHighlightingFormat(sqlLexer, "identifier", QsciLexerSQL::Identifier); setupSyntaxHighlightingFormat(sqlLexer, "identifier", QsciLexerSQL::QuotedIdentifier); } void SqlTextEdit::toggleBlockComment() { int lineFrom, indexFrom, lineTo, indexTo; // If there is no selection, select the current line if (!hasSelectedText()) { getCursorPosition(&lineFrom, &indexFrom); indexTo = text(lineFrom).length(); // Windows lines requires an adjustment, otherwise the selection would // end in the next line. if (text(lineFrom).endsWith("\r\n")) indexTo--; setSelection(lineFrom, 0, lineFrom, indexTo); } getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo); bool uncomment = text(lineFrom).contains(QRegularExpression("^[ \t]*--")); // If the selection ends before the first character of a line, don't // take this line into account for un/commenting. if (indexTo==0) lineTo--; beginUndoAction(); // Iterate over the selected lines, get line text, make // replacement depending on whether the first line was commented // or uncommented, and replace the line text. All in a single undo action. for (int line=lineFrom; line<=lineTo; line++) { QString lineText = text(line); if (uncomment) lineText.replace(QRegularExpression("^([ \t]*)-- ?"), "\\1"); else lineText.replace(QRegularExpression("^"), "-- "); indexTo = text(line).length(); if (lineText.endsWith("\r\n")) indexTo--; setSelection(line, 0, line, indexTo); replaceSelectedText(lineText); } endUndoAction(); } sqlitebrowser-sqlitebrowser-5733cb7/src/sqltextedit.h000066400000000000000000000006511463772530400232100ustar00rootroot00000000000000#ifndef SQLTEXTEDIT_H #define SQLTEXTEDIT_H #include "ExtendedScintilla.h" class SqlUiLexer; /** * @brief The SqlTextEdit class * This class is based on the QScintilla widget */ class SqlTextEdit : public ExtendedScintilla { Q_OBJECT public: explicit SqlTextEdit(QWidget *parent = nullptr); static SqlUiLexer* sqlLexer; public slots: void reloadSettings(); void toggleBlockComment(); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/tests/000077500000000000000000000000001463772530400216255ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/tests/CMakeLists.txt000066400000000000000000000030351463772530400243660ustar00rootroot00000000000000include_directories("${CMAKE_CURRENT_BINARY_DIR}" ..) find_package(Qt5 REQUIRED COMPONENTS Test Widgets) # test-sqlobjects set(TESTSQLOBJECTS_SRC ../sql/sqlitetypes.cpp ../sql/Query.cpp ../sql/ObjectIdentifier.cpp testsqlobjects.cpp ../sql/parser/ParserDriver.cpp ../sql/parser/sqlite3_lexer.cpp ../sql/parser/sqlite3_parser.cpp ) set(TESTSQLOBJECTS_HDR ../sql/sqlitetypes.h ../sql/Query.h ../sql/ObjectIdentifier.h ../sql/parser/ParserDriver.h ../sql/parser/sqlite3_lexer.h ../sql/parser/sqlite3_location.h ../sql/parser/sqlite3_parser.hpp testsqlobjects.h ) add_executable(test-sqlobjects ${TESTSQLOBJECTS_HDR} ${TESTSQLOBJECTS_SRC}) target_link_libraries(test-sqlobjects Qt5::Test) add_test(test-sqlobjects test-sqlobjects) # test-import set(TESTIMPORT_SRC ../csvparser.cpp TestImport.cpp ) set(TESTIMPORT_MOC_HDR TestImport.h ) add_executable(test-import ${TESTIMPORT_MOC_HDR} ${TESTIMPORT_SRC}) target_link_libraries(test-import Qt5::Test) add_test(test-import test-import) # test regex set(TESTREGEX_SRC TestRegex.cpp ../Data.cpp ) set(TESTREGEX_HDR ../Data.h TestRegex.h ) add_executable(test-regex ${TESTREGEX_HDR} ${TESTREGEX_SRC}) target_link_libraries(test-regex Qt5::Test Qt5::Widgets) add_test(test-regex test-regex) # test cache set(TESTCACHE_SRC TestRowCache.cpp ) set(TESTCACHE_HDR TestRowCache.h ) add_executable(test-cache ${TESTCACHE_HDR} ${TESTCACHE_SRC}) target_link_libraries(test-cache Qt5::Test) add_test(test-cache test-cache) sqlitebrowser-sqlitebrowser-5733cb7/src/tests/TestImport.cpp000066400000000000000000000142711463772530400244500ustar00rootroot00000000000000// force QtCore-only main application by QTEST_MAIN #undef QT_GUI_LIB #include #include #include #include #include #include "csvparser.h" #include "TestImport.h" QTEST_MAIN(TestImport) TestImport::TestImport() { } TestImport::~TestImport() { } void TestImport::csvImport() { // Fetch data QFETCH(QString, csv); QFETCH(char, separator); QFETCH(char, quote); QFETCH(QString, encoding); QFETCH(int, numfields); QFETCH(std::vector>, result); // Create temporary CSV file QTemporaryFile file; QVERIFY(file.open()); { QTextStream out(&file); out.setCodec(encoding.toUtf8()); out << csv; } file.flush(); CSVParser csvparser(true, separator, quote); file.seek(0); QTextStream tstream(&file); tstream.setCodec(encoding.toUtf8()); std::vector> parsedCsv; int parsedCsvColumns = 0; csvparser.parse([&parsedCsv, &parsedCsvColumns](size_t /*rowNum*/, const CSVRow& data) -> bool { std::vector row; for(size_t i=0;i parsedCsvColumns) parsedCsvColumns = row.size(); return true; }, tstream); // Check return values QCOMPARE(parsedCsvColumns, numfields); QCOMPARE(parsedCsv.size(), result.size()); for(int i=0;i("csv"); QTest::addColumn("separator"); QTest::addColumn("quote"); QTest::addColumn("encoding"); QTest::addColumn("numfields"); QTest::addColumn>>("result"); std::vector> result{ {"a", "b", "c"}, {"d", "e", "f"}, {"g", "h", "i"} }; QTest::newRow("commas_noquotes") << "a,b,c\nd,e,f\ng,h,i\n" << ',' << static_cast(0) << "UTF-8" << 3 << result; QTest::newRow("semicolons_noquotes") << "a;b;c\nd;e;f\ng;h;i\n" << ';' << static_cast(0) << "UTF-8" << 3 << result; QTest::newRow("commas_doublequotes") << "\"a\",\"b\",\"c\"\n\"d\",\"e\",\"f\"\n\"g\",\"h\",\"i\"\n" << ',' << '"' << "UTF-8" << 3 << result; QTest::newRow("noquotes_butquotesset") << "a,b,c\nd,e,f\ng,h,i\n" << ',' << '"' << "UTF-8" << 3 << result; QTest::newRow("windowslinebreaks") << "a,b,c\r\nd,e,f\r\ng,h,i\r\n" << ',' << static_cast(0) << "UTF-8" << 3 << result; QTest::newRow("oldmaclinebreaks") << "a,b,c\rd,e,f\rg,h,i\r" << ',' << static_cast(0) << "UTF-8" << 3 << result; result.clear(); result = { {"a", "b", ""}, {"c", ""}, {"d", "", "e"}, {""}, {"", "", "f"} }; QTest::newRow("emptyvalues") << "a,b,\nc,\nd,,e\n\n,,f" << ',' << static_cast(0) << "UTF-8" << 3 << result; result.clear(); result = {{"a", "b", "c"}}; QTest::newRow("oneline") << "a,b,c" << ',' << static_cast(0) << "UTF-8" << 3 << result; result.clear(); result = { {"a,a\"", "b", "c"}, {"d", "e", "\"\"f,f"} }; QTest::newRow("manyquotes") << "\"a,a\"\"\",\"b\",\"c\"\n\"d\",\"e\",\"\"\"\"\"f,f\"\n" << ',' << '"' << "UTF-8" << 3 << result; result.clear(); result = {{QByteArray("\xC2\xAE"), QByteArray("\xC9\x85"), QByteArray("\xC6\x89")}}; QString csv = QString::fromUtf8("\xC2\xAE") + "," + QString::fromUtf8("\xC9\x85") + "," + QString::fromUtf8("\xC6\x89") + "\n"; QTest::newRow("utf8chars") << csv << ',' << static_cast(0) << "UTF-8" << 3 << result; result.clear(); result = {{QByteArray("\u4E18"), QByteArray("\u4E26"), QByteArray("\u4E4B")}}; QString csv2 = QString::fromUtf8("\u4E18") + "," + QString::fromUtf8("\u4E26") + "," + QString::fromUtf8("\u4E4B") + "\n"; QTest::newRow("utf16chars") << csv2 << ',' << static_cast(0) << "UTF-16" << 3 << result; } sqlitebrowser-sqlitebrowser-5733cb7/src/tests/TestImport.h000066400000000000000000000003521463772530400241100ustar00rootroot00000000000000#ifndef TESTIMPORT_H #define TESTIMPORT_H #include class TestImport : public QObject { Q_OBJECT public: TestImport(); ~TestImport(); private slots: void csvImport(); void csvImport_data(); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/tests/TestRegex.cpp000066400000000000000000000042171463772530400242470ustar00rootroot00000000000000#include "TestRegex.h" #include "../Data.h" #include QTEST_APPLESS_MAIN(TestRegex) void TestRegex::sqlQueryComments_data() { QTest::addColumn("dirtyQuery"); QTest::addColumn("clearQuery"); QTest::newRow("test1") << // dirtyQuery "SELECT * -- asd ffdsf\n" "-- saf ewf sf\n" "-- dsaf fd\n" "FROM \t-- sfsdf\n" "qwfwqf -- asdasd" << // clearQuery "SELECT *\nFROM\nqwfwqf"; QTest::newRow("test2") << // dirtyQuery "SELECT *-- comment\n" "FROM\n\n" "-- something\n" "qwfqwf" << // cleanQuery "SELECT *\nFROM\nqwfqwf"; QTest::newRow("test3") << // dirtyQuery "-- Comment before the query\n" "SELECT * FROM test" << // cleanQuery "SELECT * FROM test"; QTest::newRow("test4") << // dirtyQuery "SELECT * FROM test\n" "-- Comment after the query" << // cleanQuery "SELECT * FROM test"; QTest::newRow("test5") << // dirtyQuery "SELECT 40+2 -- get the answer\n" "AS answer" << // cleanQuery "SELECT 40+2\n" "AS answer"; QTest::newRow("test6") << // dirtyQuery "SELECT '-- comment inside quotes'" << // cleanQuery "SELECT '-- comment inside quotes'"; QTest::newRow("single_quote_comment") << // dirtyQuery "SELECT 'something--something' -- comment" << // cleanQuery "SELECT 'something--something'"; /* This still needs to be fixed in our code before activating the test QTest::newRow("double_quote_comment") << // dirtyQuery "SELECT \"something--something\" -- comment" << // cleanQuery "SELECT \"something--something\"";*/ } void TestRegex::sqlQueryComments() { QFETCH(QString, dirtyQuery); QFETCH(QString, clearQuery); removeCommentsFromQuery(dirtyQuery); QCOMPARE(dirtyQuery, clearQuery); } sqlitebrowser-sqlitebrowser-5733cb7/src/tests/TestRegex.h000066400000000000000000000003401463772530400237050ustar00rootroot00000000000000#ifndef TESTREGEX_H #define TESTREGEX_H #define REGEX_UNIT_TEST #include class TestRegex : public QObject { Q_OBJECT private slots: void sqlQueryComments(); void sqlQueryComments_data(); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/tests/TestRowCache.cpp000066400000000000000000000114371463772530400246720ustar00rootroot00000000000000#include #include "TestRowCache.h" #include "../RowCache.h" QTEST_APPLESS_MAIN(TestRowCache) TestRowCache::TestRowCache() { } TestRowCache::~TestRowCache() { } using C = RowCache; void TestRowCache::construction() { C c; QCOMPARE(c.numSet(), static_cast(0)); QVERIFY(c.count(0) == false); QVERIFY(c.count(1) == false); QVERIFY(c.count(2) == false); QVERIFY_EXCEPTION_THROWN(c.at(0), std::out_of_range); } void TestRowCache::setGet() { C c; c.set(1, 10); c.set(5, 50); c.set(0, 0); c.set(6, 60); c.set(100, 1000); QCOMPARE(c.numSet(), static_cast(5)); QCOMPARE(c.numSegments(), static_cast(4)); // the '0' set after the '1' position does not merge currently int cnt = 0; const C & cc = c; for(size_t i = 0; i < 200; i++) { if(c.count(i)) { QCOMPARE(c.at(i), static_cast(10*i)); QCOMPARE(cc.at(i), static_cast(10*i)); cnt++; } else { QVERIFY_EXCEPTION_THROWN(c.at(i), std::out_of_range); QVERIFY_EXCEPTION_THROWN(cc.at(i), std::out_of_range); } } QCOMPARE(cnt, 5); } void TestRowCache::insert() { C c; c.insert(3, 30); QCOMPARE(c.numSet(), static_cast(1)); QCOMPARE(c.numSegments(), static_cast(1)); QCOMPARE(c.at(3), 30); c.insert(3, 31); QCOMPARE(c.numSet(), static_cast(2)); QCOMPARE(c.numSegments(), static_cast(1)); QCOMPARE(c.at(3), 31); QCOMPARE(c.at(4), 30); c.insert(0, 0); QCOMPARE(c.numSet(), static_cast(3)); QCOMPARE(c.numSegments(), static_cast(2)); QCOMPARE(c.at(0), 0); QVERIFY_EXCEPTION_THROWN(c.at(3), std::out_of_range); QCOMPARE(c.at(4), 31); QCOMPARE(c.at(5), 30); QVERIFY_EXCEPTION_THROWN(c.at(6), std::out_of_range); c.insert(1, 100); QCOMPARE(c.numSet(), static_cast(4)); QCOMPARE(c.numSegments(), static_cast(2)); QCOMPARE(c.at(0), 0); QCOMPARE(c.at(1), 100); QCOMPARE(c.at(5), 31); QCOMPARE(c.at(6), 30); c.insert(8, 1); QCOMPARE(c.numSet(), static_cast(5)); QCOMPARE(c.numSegments(), static_cast(3)); QCOMPARE(c.at(0), 0); QCOMPARE(c.at(1), 100); QCOMPARE(c.at(5), 31); QCOMPARE(c.at(6), 30); QCOMPARE(c.at(8), 1); } void TestRowCache::erase() { C c; c.insert(3, 30); c.insert(3, 31); c.insert(0, 0); c.insert(8, 1); QCOMPARE(c.numSet(), static_cast(4)); QCOMPARE(c.numSegments(), static_cast(3)); QCOMPARE(c.at(0), 0); QCOMPARE(c.at(4), 31); QCOMPARE(c.at(5), 30); QCOMPARE(c.at(8), 1); // erase entire segment c.erase(0); QCOMPARE(c.numSet(), static_cast(3)); QCOMPARE(c.numSegments(), static_cast(2)); QCOMPARE(c.at(3), 31); QCOMPARE(c.at(4), 30); QCOMPARE(c.at(7), 1); // erase inside segment c.erase(4); QCOMPARE(c.numSet(), static_cast(2)); QCOMPARE(c.numSegments(), static_cast(2)); QCOMPARE(c.at(3), 31); QCOMPARE(c.at(6), 1); // erase non-filled row c.erase(5); QCOMPARE(c.numSet(), static_cast(2)); QCOMPARE(c.numSegments(), static_cast(2)); QCOMPARE(c.at(3), 31); QCOMPARE(c.at(5), 1); c.erase(5); QCOMPARE(c.numSet(), static_cast(1)); QCOMPARE(c.numSegments(), static_cast(1)); QCOMPARE(c.at(3), 31); c.erase(3); QCOMPARE(c.numSet(), static_cast(0)); QCOMPARE(c.numSegments(), static_cast(0)); } void TestRowCache::smallestNonAvailableRange() { C c; c.insert(3, 0); c.insert(3, 0); c.insert(0, 0); c.insert(8, 0); QCOMPARE(c.numSet(), static_cast(4)); QVERIFY(c.count(0)); QVERIFY(c.count(4)); QVERIFY(c.count(5)); QVERIFY(c.count(8)); using P = std::pair; auto test = [&](size_t begin, size_t end) { P p{ begin, end }; c.smallestNonAvailableRange(p.first, p.second); return p; }; QCOMPARE(test( 0, 0), P( 0, 0)); QCOMPARE(test( 0, 1), P( 1, 1)); QCOMPARE(test( 0, 2), P( 1, 2)); QCOMPARE(test( 0, 3), P( 1, 3)); QCOMPARE(test( 0, 4), P( 1, 4)); QCOMPARE(test( 0, 5), P( 1, 4)); QCOMPARE(test( 0, 6), P( 1, 4)); QCOMPARE(test( 0, 7), P( 1, 7)); QCOMPARE(test( 0, 8), P( 1, 8)); QCOMPARE(test( 0, 9), P( 1, 8)); QCOMPARE(test( 0,10), P( 1,10)); QCOMPARE(test( 1,10), P( 1,10)); QCOMPARE(test( 2,10), P( 2,10)); QCOMPARE(test( 3,10), P( 3,10)); QCOMPARE(test( 4,10), P( 6,10)); QCOMPARE(test( 5,10), P( 6,10)); QCOMPARE(test( 6,10), P( 6,10)); QCOMPARE(test( 7,10), P( 7,10)); QCOMPARE(test( 8,10), P( 9,10)); QCOMPARE(test( 9,10), P( 9,10)); QCOMPARE(test(10,10), P(10,10)); } sqlitebrowser-sqlitebrowser-5733cb7/src/tests/TestRowCache.h000066400000000000000000000004721463772530400243340ustar00rootroot00000000000000#ifndef TESTROWCACHE_H #define TESTROWCACHE_H #include class TestRowCache : public QObject { Q_OBJECT public: TestRowCache(); ~TestRowCache(); private slots: void construction(); void setGet(); void insert(); void erase(); void smallestNonAvailableRange(); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/tests/testsqlobjects.cpp000066400000000000000000001174531463772530400254150ustar00rootroot00000000000000#include "testsqlobjects.h" #include "../sql/ObjectIdentifier.h" #include "../sql/sqlitetypes.h" #include QTEST_APPLESS_MAIN(TestTable) Q_DECLARE_METATYPE(std::string) using namespace sqlb; #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) namespace QTest { template inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected, const char *file, int line) { return compare_helper(t1 == t2, "Compared values are not the same", toString(t1), toString(t2), actual, expected, file, line); } } #endif void TestTable::sqlOutput() { Table tt("testtable"); Field f("id", "integer"); Field fkm("km", "integer", false, "", "km > 1000"); tt.fields.push_back(f); tt.fields.emplace_back("car", "text"); tt.fields.push_back(fkm); tt.addConstraint({f.name(), fkm.name()}, std::make_shared()); QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" "\t\"id\"\tinteger,\n" "\t\"car\"\ttext,\n" "\t\"km\"\tinteger CHECK(km > 1000),\n" "\tPRIMARY KEY(\"id\",\"km\")\n" ");"); } void TestTable::sqlGraveAccentOutput() { Table tt("testtable"); Field f("id", "integer"); Field fkm("km", "integer", false, "", "km > 1000"); tt.fields.push_back(f); tt.fields.emplace_back("car", "text"); tt.fields.push_back(fkm); tt.addConstraint({f.name(), fkm.name()}, std::make_shared()); sqlb::setIdentifierQuoting(sqlb::GraveAccents); QCOMPARE(tt.sql(), "CREATE TABLE `testtable` (\n" "\t`id`\tinteger,\n" "\t`car`\ttext,\n" "\t`km`\tinteger CHECK(km > 1000),\n" "\tPRIMARY KEY(`id`,`km`)\n" ");"); sqlb::setIdentifierQuoting(sqlb::DoubleQuotes); } void TestTable::sqlSquareBracketsOutput() { Table tt("testtable"); Field f("id", "integer"); Field fkm("km", "integer", false, "", "km > 1000"); tt.fields.push_back(f); tt.fields.emplace_back("car", "text"); tt.fields.push_back(fkm); tt.addConstraint({f.name(), fkm.name()}, std::make_shared()); sqlb::setIdentifierQuoting(sqlb::SquareBrackets); QCOMPARE(tt.sql(), "CREATE TABLE [testtable] (\n" "\t[id]\tinteger,\n" "\t[car]\ttext,\n" "\t[km]\tinteger CHECK(km > 1000),\n" "\tPRIMARY KEY([id],[km])\n" ");"); sqlb::setIdentifierQuoting(sqlb::DoubleQuotes); } void TestTable::autoincrement() { Table tt("testtable"); Field f("id", "integer"); Field fkm("km", "integer"); tt.fields.push_back(f); tt.fields.emplace_back("car", "text"); tt.fields.push_back(fkm); PrimaryKeyConstraint pk; pk.setAutoIncrement(true); tt.addConstraint({f.name()}, std::make_shared(pk)); QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" "\t\"id\"\tinteger,\n" "\t\"car\"\ttext,\n" "\t\"km\"\tinteger,\n" "\tPRIMARY KEY(\"id\" AUTOINCREMENT)\n" ");"); } void TestTable::notnull() { Table tt("testtable"); Field f("id", "integer"); Field fkm("km", "integer"); tt.fields.push_back(f); tt.fields.emplace_back("car", "text", true); tt.fields.push_back(fkm); PrimaryKeyConstraint pk; pk.setAutoIncrement(true); tt.addConstraint({f.name()}, std::make_shared(pk)); QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" "\t\"id\"\tinteger,\n" "\t\"car\"\ttext NOT NULL,\n" "\t\"km\"\tinteger,\n" "\tPRIMARY KEY(\"id\" AUTOINCREMENT)\n" ");"); } void TestTable::withoutRowid() { Table tt("testtable"); Field f("a", "integer"); tt.fields.push_back(f); tt.fields.emplace_back("b", "integer"); tt.setWithoutRowidTable(true); tt.addConstraint({f.name()}, std::make_shared()); QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" "\t\"a\"\tinteger,\n" "\t\"b\"\tinteger,\n" "\tPRIMARY KEY(\"a\")\n" ") WITHOUT ROWID;"); } void TestTable::strict() { Table tt("testtable"); tt.fields.emplace_back("a", "integer"); tt.fields.emplace_back("b", "integer"); tt.setStrict(true); QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" "\t\"a\"\tinteger,\n" "\t\"b\"\tinteger\n" ") STRICT;"); } void TestTable::strictAndWithoutRowid() { Table tt("testtable"); Field f("a", "integer"); tt.fields.push_back(f); tt.fields.emplace_back("b", "integer"); tt.setStrict(true); tt.setWithoutRowidTable(true); tt.addConstraint({f.name()}, std::make_shared()); QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" "\t\"a\"\tinteger,\n" "\t\"b\"\tinteger,\n" "\tPRIMARY KEY(\"a\")\n" ") WITHOUT ROWID,STRICT;"); } void TestTable::foreignKeys() { Table tt("testtable"); Field f("a", "integer"); tt.fields.push_back(f); auto fk = std::make_shared("b", sqlb::StringVector{"c"}); tt.addConstraint({f.name()}, fk); QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" "\t\"a\"\tinteger,\n" "\tFOREIGN KEY(\"a\") REFERENCES \"b\"(\"c\")\n" ");"); } void TestTable::uniqueConstraint() { Table tt("testtable"); Field f1("a", "integer"); Field f2("b", "integer"); Field f3("c", "integer"); f1.setUnique(true); tt.fields.push_back(f1); tt.fields.push_back(f2); tt.fields.push_back(f3); tt.addConstraint({f2.name(), f3.name()}, std::make_shared()); QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" "\t\"a\"\tinteger UNIQUE,\n" "\t\"b\"\tinteger,\n" "\t\"c\"\tinteger,\n" "\tUNIQUE(\"b\",\"c\")\n" ");"); } void TestTable::parseSQL() { std::string sSQL = "create TABLE hero (\n" "\tid integer PRIMARY KEY AUTOINCREMENT,\n" "\tname text NOT NULL DEFAULT 'xxxx',\n" "\tinfo VARCHAR(255) CHECK (info == 'x')\n" ");"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "hero"); QCOMPARE(tab.rowidColumns(), {"_rowid_"}); QCOMPARE(tab.fields.at(0).name(), "id"); QCOMPARE(tab.fields.at(1).name(), "name"); QCOMPARE(tab.fields.at(2).name(), "info"); QCOMPARE(tab.fields.at(0).type(), "integer"); QCOMPARE(tab.fields.at(1).type(), "text"); QCOMPARE(tab.fields.at(2).type(), "VARCHAR(255)"); auto pk = tab.primaryKey(); auto pkColumns = tab.primaryKeyColumns(); QVERIFY(pk->autoIncrement()); QCOMPARE(pkColumns.size(), 1); QCOMPARE(pkColumns.at(0).name(), tab.fields.at(0).name()); QVERIFY(tab.fields.at(1).notnull()); QCOMPARE(tab.fields.at(1).defaultValue(), "'xxxx'"); QCOMPARE(tab.fields.at(1).check(), ""); QCOMPARE(tab.fields.at(2).check(), "\"info\" == 'x'"); } void TestTable::parseSQLdefaultexpr() { std::string sSQL = "CREATE TABLE chtest(\n" "id integer primary key,\n" "dumpytext text default('axa') CHECK(dumpytext == \"aa\"),\n" "date datetime default CURRENT_TIMESTAMP," "zoi integer)"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "chtest"); QCOMPARE(tab.fields.at(0).name(), "id"); QCOMPARE(tab.fields.at(1).name(), "dumpytext"); QCOMPARE(tab.fields.at(2).name(), "date"); QCOMPARE(tab.fields.at(3).name(), "zoi"); QCOMPARE(tab.fields.at(0).type(), "integer"); QCOMPARE(tab.fields.at(1).type(), "text"); QCOMPARE(tab.fields.at(2).type(), "datetime"); QCOMPARE(tab.fields.at(3).type(), "integer"); QCOMPARE(tab.fields.at(1).defaultValue(), "('axa')"); QCOMPARE(tab.fields.at(1).check(), "\"dumpytext\" == \"aa\""); QCOMPARE(tab.fields.at(2).defaultValue(), "CURRENT_TIMESTAMP"); QCOMPARE(tab.fields.at(2).check(), ""); QCOMPARE(tab.fields.at(3).defaultValue(), ""); QCOMPARE(tab.fields.at(3).check(), ""); auto pk = tab.primaryKeyColumns(); QCOMPARE(pk.size(), 1); QCOMPARE(pk.at(0).name(), tab.fields.at(0).name()); } void TestTable::parseSQLMultiPk() { std::string sSQL = "CREATE TABLE hero (\n" "\tid1 integer,\n" "\tid2 integer,\n" "\tnonpkfield blob,\n" "PRIMARY KEY(\"id1\",\"id2\")\n" ");"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "hero"); QCOMPARE(tab.fields.at(0).name(), "id1"); QCOMPARE(tab.fields.at(1).name(), "id2"); QCOMPARE(tab.fields.at(0).type(), "integer"); QCOMPARE(tab.fields.at(1).type(), "integer"); auto pk = tab.primaryKeyColumns(); QCOMPARE(pk.size(), 2); QCOMPARE(pk.at(0).name(), tab.fields.at(0).name()); QCOMPARE(pk.at(1).name(), tab.fields.at(1).name()); } void TestTable::parseSQLForeignKey() { std::string sSQL = "CREATE TABLE grammar_test(id, test, FOREIGN KEY(test) REFERENCES other_table);"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "grammar_test"); QCOMPARE(tab.fields.at(0).name(), "id"); QCOMPARE(tab.fields.at(1).name(), "test"); } void TestTable::parseSQLSingleQuotes() { std::string sSQL = "CREATE TABLE 'test'('id','test');"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).name(), "id"); QCOMPARE(tab.fields.at(1).name(), "test"); } void TestTable::parseSQLSquareBrackets() { std::string sSQL = "CREATE TABLE [test]([id],[test]);"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).name(), "id"); QCOMPARE(tab.fields.at(1).name(), "test"); } void TestTable::parseSQLKeywordInIdentifier() { std::string sSQL = "CREATE TABLE deffered(key integer primary key, if text);"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "deffered"); QCOMPARE(tab.fields.at(0).name(), "key"); QCOMPARE(tab.fields.at(1).name(), "if"); } void TestTable::parseSQLSomeKeywordsInIdentifier() { std::string sSQL = "CREATE TABLE \"Average Number of Volunteers by Area of Work\" (" "`Area of Work` TEXT," "`Average Number of Volunteers` INTEGER);"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "Average Number of Volunteers by Area of Work"); QCOMPARE(tab.fields.at(0).name(), "Area of Work"); QCOMPARE(tab.fields.at(1).name(), "Average Number of Volunteers"); } void TestTable::parseSQLWithoutRowid() { std::string sSQL = "CREATE TABLE test(a integer primary key, b integer) WITHOUT ROWID;"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.primaryKeyColumns().at(0).name(), "a"); QCOMPARE(tab.rowidColumns(), {"a"}); QCOMPARE(tab.withoutRowidTable(), true); QCOMPARE(tab.isStrict(), false); } void TestTable::parseSQLStrictTable() { Table tab(*Table::parseSQL("CREATE TABLE test(a integer, b any) STRICT")); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).name(), "a"); QCOMPARE(tab.fields.at(1).name(), "b"); QCOMPARE(tab.isStrict(), true); QCOMPARE(tab.withoutRowidTable(), false); } void TestTable::parseSQLStrictAndWithoutRowidTable() { Table tab(*Table::parseSQL("CREATE TABLE test(a integer, b any) STRICT, WITHOUT ROWID")); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).name(), "a"); QCOMPARE(tab.fields.at(1).name(), "b"); QCOMPARE(tab.isStrict(), true); QCOMPARE(tab.withoutRowidTable(), true); } void TestTable::parseNonASCIIChars() { std::string sSQL = "CREATE TABLE `lösung` (" "`Fieldöäüß` INTEGER," "PRIMARY KEY(`Fieldöäüß`)" ");"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "lösung"); QCOMPARE(tab.fields.at(0).name(), "Fieldöäüß"); } void TestTable::parseNonASCIICharsEs() { std::string sSQL = "CREATE TABLE \"Cigüeñas de Alcalá\" (" "\"Field áéíóúÃÉÃÓÚñÑçÇ\" INTEGER," "PRIMARY KEY(\"Field áéíóúÃÉÃÓÚñÑçÇ\")" ");"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "Cigüeñas de Alcalá"); QCOMPARE(tab.fields.at(0).name(), "Field áéíóúÃÉÃÓÚñÑçÇ"); } void TestTable::parseSQLEscapedQuotes() { std::string sSql = "CREATE TABLE double_quotes(a text default 'a''a');"; Table tab(*Table::parseSQL(sSql)); QCOMPARE(tab.name(), "double_quotes"); QCOMPARE(tab.fields.at(0).name(), "a"); QCOMPARE(tab.fields.at(0).defaultValue(), "'a''a'"); } void TestTable::parseSQLForeignKeys() { std::string sql = "CREATE TABLE foreign_key_test(a int, b int, foreign key (a) references x, foreign key (b) references w(y,z) on delete set null);"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "foreign_key_test"); QCOMPARE(tab.fields.at(0).name(), "a"); QCOMPARE(tab.fields.at(0).type(), "int"); QCOMPARE(tab.foreignKey({tab.fields.at(0).name()})->table(), "x"); QCOMPARE(tab.fields.at(1).name(), "b"); QCOMPARE(tab.fields.at(1).type(), "int"); QCOMPARE(tab.foreignKey({tab.fields.at(1).name()})->toString(), "\"w\"(\"y\",\"z\") on delete set null"); } void TestTable::parseSQLCheckConstraint() { std::string sql = "CREATE TABLE a (\"b\" text CHECK(\"b\"='A' or \"b\"='B'));"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "a"); QCOMPARE(tab.fields.at(0).name(), "b"); QCOMPARE(tab.fields.at(0).type(), "text"); QCOMPARE(tab.fields.at(0).check(), "\"b\" = 'A' OR \"b\" = 'B'"); } void TestTable::parseDefaultValues() { std::string sql = "CREATE TABLE test(a int DEFAULT 0, b int DEFAULT -1, c text DEFAULT 'hello', d text DEFAULT '0');"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).name(), "a"); QCOMPARE(tab.fields.at(0).type(), "int"); QCOMPARE(tab.fields.at(0).defaultValue(), "0"); QCOMPARE(tab.fields.at(1).name(), "b"); QCOMPARE(tab.fields.at(1).type(), "int"); QCOMPARE(tab.fields.at(1).defaultValue(), "-1"); QCOMPARE(tab.fields.at(2).name(), "c"); QCOMPARE(tab.fields.at(2).type(), "text"); QCOMPARE(tab.fields.at(2).defaultValue(), "'hello'"); QCOMPARE(tab.fields.at(3).name(), "d"); QCOMPARE(tab.fields.at(3).type(), "text"); QCOMPARE(tab.fields.at(3).defaultValue(), "'0'"); } void TestTable::createTableWithIn() { std::string sSQL = "CREATE TABLE not_working(" "_id PRIMARY KEY NOT NULL," "value NVARCHAR(5) CHECK (value IN ('a', 'b', 'c'))" ");"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "not_working"); QCOMPARE(tab.fields.at(1).check(), "\"value\" IN ('a', 'b', 'c')"); } void TestTable::createTableWithNotLikeConstraint() { std::string sSQL = "CREATE TABLE hopefully_working(\n" "value TEXT CHECK(value NOT LIKE 'prefix%'),\n" "value2 TEXT CHECK(value2 NOT MATCH 'prefix%'),\n" "value3 TEXT CHECK(value3 NOT REGEXP 'prefix%'),\n" "value4 TEXT CHECK(value4 NOT GLOB 'prefix%'),\n" "value5 INTEGER CHECK(value5 BETWEEN 1+4 AND 100 OR 200),\n" "value6 INTEGER CHECK(value6 NOT BETWEEN 1 AND 100)\n" ");"; Table tab(*Table::parseSQL(sSQL)); QCOMPARE(tab.name(), "hopefully_working"); QCOMPARE(tab.fields.at(0).check(), "\"value\" NOT LIKE 'prefix%'"); QCOMPARE(tab.fields.at(1).check(), "\"value2\" NOT MATCH 'prefix%'"); QCOMPARE(tab.fields.at(2).check(), "\"value3\" NOT REGEXP 'prefix%'"); QCOMPARE(tab.fields.at(3).check(), "\"value4\" NOT GLOB 'prefix%'"); QCOMPARE(tab.fields.at(4).check(), "\"value5\" BETWEEN 1 + 4 AND 100 OR 200"); QCOMPARE(tab.fields.at(5).check(), "\"value6\" NOT BETWEEN 1 AND 100"); } void TestTable::rowValues() { std::string sql = "CREATE TABLE test(\n" "a INTEGER,\n" "b INTEGER,\n" "CHECK((a, b) = (1, 2))\n" ");"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "test"); auto c = tab.checkConstraints(); QCOMPARE(c.size(), 1); QCOMPARE(c.at(0)->expression(), "(\"a\", \"b\") = (1, 2)"); } void TestTable::complexExpressions() { std::string sql = "CREATE TABLE test(\n" "a INTEGER CHECK((a > 0)),\n" "b INTEGER CHECK((b > 0 and b > 1)),\n" "c INTEGER CHECK((c = -1) or (c > 0 and c > 1) or (c = 0)),\n" "d INTEGER CHECK((((d > 0))))\n" ");"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).check(), "(\"a\" > 0)"); QCOMPARE(tab.fields.at(1).check(), "(\"b\" > 0 AND \"b\" > 1)"); QCOMPARE(tab.fields.at(2).check(), "(\"c\" = -1) OR (\"c\" > 0 AND \"c\" > 1) OR (\"c\" = 0)"); QCOMPARE(tab.fields.at(3).check(), "(((\"d\" > 0)))"); } void TestTable::datetimeExpression() { std::string sql = "CREATE TABLE test(\n" "entry INTEGER DEFAULT (DATETIME(CURRENT_TIMESTAMP, 'LOCALTIME'))\n" ");"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).name(), "entry"); QCOMPARE(tab.fields.at(0).type(), "INTEGER"); QCOMPARE(tab.fields.at(0).defaultValue(), "(DATETIME(CURRENT_TIMESTAMP, 'LOCALTIME'))"); } void TestTable::extraParentheses() { std::string sql = "CREATE TABLE test(\n" "xy INTEGER DEFAULT (1 + (5) - 4)\n" ");"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).name(), "xy"); QCOMPARE(tab.fields.at(0).type(), "INTEGER"); QCOMPARE(tab.fields.at(0).defaultValue(), "(1 + (5) - 4)"); } void TestTable::moduloOperator() { std::string sql = "CREATE TABLE test(\n" "xy INTEGER DEFAULT (7 % 2)\n" ");"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).name(), "xy"); QCOMPARE(tab.fields.at(0).type(), "INTEGER"); QCOMPARE(tab.fields.at(0).defaultValue(), "(7 % 2)"); } void TestTable::complexExpression() { std::string sql = "CREATE TABLE test(\n" "uuid INTEGER DEFAULT (hex(randomblob(4))||'-'||hex(randomblob(2))||'-'||'4'||substr(hex(randomblob(2)),2)||'-'||substr('AB89',1+(abs(random())%4),1)||substr(hex(randomblob(2)),2)||'-'||hex(randomblob(6))),\n" "a INTEGER,\n" "b INTEGER,\n" "CHECK((a = 'S' AND b IS NOT NULL) OR (a IN ('A', 'P')))" ");"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "test"); QCOMPARE(tab.fields.at(0).name(), "uuid"); QCOMPARE(tab.fields.at(0).type(), "INTEGER"); QCOMPARE(tab.fields.at(0).defaultValue(), "(hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' || substr(hex(randomblob(2)), 2) || '-' || substr('AB89', 1 + (abs(random()) % 4), 1) || substr(hex(randomblob(2)), 2) || '-' || hex(randomblob(6)))"); auto c = tab.checkConstraints(); QCOMPARE(c.size(), 1); QCOMPARE(c.at(0)->expression(), "(\"a\" = 'S' AND \"b\" IS NOT NULL) OR (\"a\" IN ('A', 'P'))"); } void TestTable::parseIdentifierWithDollar() { std::string sql = "CREATE TABLE te$st(te$st$ INTEGER);"; Table tab(*Table::parseSQL(sql)); QCOMPARE(tab.name(), "te$st"); QCOMPARE(tab.fields.at(0).name(), "te$st$"); QCOMPARE(tab.fields.at(0).type(), "INTEGER"); } void TestTable::parseTest() { QFETCH(std::string, sql); Table tab(*Table::parseSQL(sql)); QVERIFY(tab.fullyParsed()); } void TestTable::parseTest_data() { // These are some rather unspecific queries but we include them here to test some basic parser features. They are // extracted from this file: https://www.sqlite.org/cgi/src/artifact/1c602347e73ab80b QTest::addColumn("sql"); QTest::newRow("1") << std::string("CREATE TABLE t1(c1 one)"); QTest::newRow("2") << std::string("CREATE TABLE t1(c1 one two)"); QTest::newRow("3") << std::string("CREATE TABLE t1(c1 one two three)"); QTest::newRow("4") << std::string("CREATE TABLE t1(c1 one two three four)"); QTest::newRow("5") << std::string("CREATE TABLE t1(c1 one two three four(14))"); QTest::newRow("6") << std::string("CREATE TABLE t1(c1 one two three four(14, 22))"); QTest::newRow("7") << std::string("CREATE TABLE t1(c1 var(+14, -22.3))"); QTest::newRow("8") << std::string("CREATE TABLE t1(c1 var(1.0e10))"); QTest::newRow("9") << std::string("CREATE TABLE t1(c1 text PRIMARY KEY)"); QTest::newRow("10") << std::string("CREATE TABLE t1(c1 text PRIMARY KEY ASC)"); QTest::newRow("11") << std::string("CREATE TABLE t1(c1 text PRIMARY KEY DESC)"); QTest::newRow("12") << std::string("CREATE TABLE t1(c1 text CONSTRAINT cons PRIMARY KEY DESC)"); QTest::newRow("13") << std::string("CREATE TABLE t1(c1 text NOT NULL)"); QTest::newRow("14") << std::string("CREATE TABLE t1(c1 text CONSTRAINT nm NOT NULL)"); QTest::newRow("15") << std::string("CREATE TABLE t1(c1 text NULL)"); QTest::newRow("16") << std::string("CREATE TABLE t1(c1 text CONSTRAINT nm NULL)"); QTest::newRow("17") << std::string("CREATE TABLE t1(c1 text UNIQUE)"); QTest::newRow("18") << std::string("CREATE TABLE t1(c1 text CONSTRAINT un UNIQUE)"); QTest::newRow("19") << std::string("CREATE TABLE t1(c1 text CHECK(c1!=0))"); QTest::newRow("20") << std::string("CREATE TABLE t1(c1 text CONSTRAINT chk CHECK(c1!=0))"); QTest::newRow("21") << std::string("CREATE TABLE t1(c1 text DEFAULT 1)"); QTest::newRow("22") << std::string("CREATE TABLE t1(c1 text DEFAULT -1)"); QTest::newRow("23") << std::string("CREATE TABLE t1(c1 text DEFAULT +1)"); QTest::newRow("24") << std::string("CREATE TABLE t1(c1 text DEFAULT -45.8e22)"); QTest::newRow("25") << std::string("CREATE TABLE t1(c1 text DEFAULT (1+1))"); QTest::newRow("26") << std::string("CREATE TABLE t1(c1 text CONSTRAINT \"1 2\" DEFAULT (1+1))"); QTest::newRow("27") << std::string("CREATE TABLE t1(c1 text COLLATE nocase)"); QTest::newRow("28") << std::string("CREATE TABLE t1(c1 text CONSTRAINT 'a x' COLLATE nocase)"); QTest::newRow("29") << std::string("CREATE TABLE t1(c1 REFERENCES t2)"); QTest::newRow("30") << std::string("CREATE TABLE t1(c1 CONSTRAINT abc REFERENCES t2)"); QTest::newRow("31") << std::string("CREATE TABLE t1(c1 PRIMARY KEY NOT NULL UNIQUE CHECK(c1 IS 'ten') DEFAULT 123 REFERENCES t1);"); QTest::newRow("32") << std::string("CREATE TABLE t1(c1 REFERENCES t1 DEFAULT 123 CHECK(c1 IS 'ten') UNIQUE NOT NULL PRIMARY KEY);"); QTest::newRow("33") << std::string("CREATE TABLE t1(c1, c2, PRIMARY KEY(c1))"); QTest::newRow("34") << std::string("CREATE TABLE t1(c1, c2, PRIMARY KEY(c1, c2))"); QTest::newRow("35") << std::string("CREATE TABLE t1(c1, c2, PRIMARY KEY(c1, c2) ON CONFLICT IGNORE)"); QTest::newRow("36") << std::string("CREATE TABLE t1(c1, c2, UNIQUE(c1))"); QTest::newRow("37") << std::string("CREATE TABLE t1(c1, c2, UNIQUE(c1, c2))"); QTest::newRow("38") << std::string("CREATE TABLE t1(c1, c2, UNIQUE(c1, c2) ON CONFLICT IGNORE)"); QTest::newRow("39") << std::string("CREATE TABLE t1(c1, c2, CHECK(c1 IS NOT c2))"); QTest::newRow("40") << std::string("CREATE TABLE t1(c1, c2, FOREIGN KEY(c1) REFERENCES t2)"); QTest::newRow("41") << std::string("CREATE TABLE t1(col1, col2 TEXT, col3 INTEGER UNIQUE, col4 VARCHAR(10, 10) PRIMARY KEY, \"name with spaces\" REFERENCES t1);"); QTest::newRow("42") << std::string("CREATE TABLE t1(a, b, c)"); QTest::newRow("43") << std::string("CREATE TEMP TABLE t1(a, b, c)"); QTest::newRow("44") << std::string("CREATE TEMPORARY TABLE t1(a, b, c)"); QTest::newRow("45") << std::string("CREATE TABLE IF NOT EXISTS t1(a, b, c)"); QTest::newRow("46") << std::string("CREATE TEMP TABLE IF NOT EXISTS t1(a, b, c)"); QTest::newRow("47") << std::string("CREATE TEMPORARY TABLE IF NOT EXISTS t1(a, b, c)"); QTest::newRow("48") << std::string("CREATE TABLE main.t1(a, b, c)"); QTest::newRow("49") << std::string("CREATE TEMP TABLE temp.t1(a, b, c)"); QTest::newRow("50") << std::string("CREATE TEMPORARY TABLE temp.t1(a, b, c)"); QTest::newRow("51") << std::string("CREATE TABLE IF NOT EXISTS main.t1(a, b, c)"); QTest::newRow("52") << std::string("CREATE TEMP TABLE IF NOT EXISTS temp.t1(a, b, c)"); QTest::newRow("53") << std::string("CREATE TEMPORARY TABLE IF NOT EXISTS temp.t1(a, b, c)"); QTest::newRow("54") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH FULL ON DELETE SET NULL ON UPDATE RESTRICT DEFERRABLE)"); QTest::newRow("55") << std::string("CREATE TABLE t1(a REFERENCES t2(x) ON DELETE RESTRICT ON UPDATE SET NULL MATCH FULL NOT DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("56") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH PARTIAL ON DELETE SET NULL ON UPDATE CASCADE DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("57") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH PARTIAL ON DELETE RESTRICT ON UPDATE SET DEFAULT )"); QTest::newRow("58") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH PARTIAL ON DELETE RESTRICT ON UPDATE RESTRICT DEFERRABLE)"); QTest::newRow("59") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH PARTIAL ON DELETE NO ACTION ON UPDATE SET DEFAULT NOT DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("60") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE SET NULL ON UPDATE CASCADE NOT DEFERRABLE)"); QTest::newRow("61") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE SET DEFAULT ON UPDATE SET NULL DEFERRABLE)"); QTest::newRow("62") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE SET DEFAULT NOT DEFERRABLE)"); QTest::newRow("63") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE RESTRICT ON UPDATE SET DEFAULT NOT DEFERRABLE INITIALLY DEFERRED)"); QTest::newRow("64") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE RESTRICT ON UPDATE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("65") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE NO ACTION ON UPDATE SET DEFAULT NOT DEFERRABLE)"); QTest::newRow("66") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH STICK ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE)"); QTest::newRow("67") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH STICK ON UPDATE SET NULL NOT DEFERRABLE INITIALLY DEFERRED)"); QTest::newRow("68") << std::string("CREATE TABLE t1(a REFERENCES t2(x) ON DELETE SET NULL ON UPDATE NO ACTION DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("69") << std::string("CREATE TABLE t1(a REFERENCES t2(x) ON DELETE RESTRICT ON UPDATE NO ACTION NOT DEFERRABLE)"); QTest::newRow("70") << std::string("CREATE TABLE t1(a REFERENCES t2(x) NOT DEFERRABLE INITIALLY DEFERRED)"); QTest::newRow("71") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH FULL ON DELETE SET NULL ON UPDATE SET NULL DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("72") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH FULL ON DELETE SET NULL ON UPDATE SET DEFAULT NOT DEFERRABLE)"); QTest::newRow("73") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH FULL ON DELETE SET DEFAULT ON UPDATE SET NULL )"); QTest::newRow("74") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH FULL ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("75") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH PARTIAL ON DELETE SET NULL ON UPDATE RESTRICT NOT DEFERRABLE)"); QTest::newRow("76") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH PARTIAL ON DELETE SET NULL ON UPDATE NO ACTION DEFERRABLE)"); QTest::newRow("77") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH PARTIAL ON DELETE CASCADE ON UPDATE SET DEFAULT )"); QTest::newRow("78") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH PARTIAL NOT DEFERRABLE)"); QTest::newRow("79") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH SIMPLE ON DELETE SET DEFAULT ON UPDATE CASCADE DEFERRABLE)"); QTest::newRow("80") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH STICK ON DELETE SET NULL ON UPDATE NO ACTION DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("81") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH STICK ON DELETE NO ACTION ON UPDATE SET DEFAULT NOT DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("82") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH STICK ON UPDATE SET DEFAULT DEFERRABLE INITIALLY IMMEDIATE)"); QTest::newRow("83") << std::string("CREATE TABLE t1(a REFERENCES t2 ON DELETE RESTRICT ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED)"); QTest::newRow("84") << std::string("CREATE TABLE sqlit_abc(a, b, c)"); QTest::newRow("85") << std::string("CREATE TABLE temp.sqlitehelloworld(x)"); QTest::newRow("86") << std::string("CREATE TABLE auxa.\"sqlite\"(x, y)"); QTest::newRow("87") << std::string("CREATE TABLE auxb.\"sqlite-\"(z)"); QTest::newRow("88") << std::string("CREATE TABLE \"SQLITE-TBL\"(z)"); QTest::newRow("89") << std::string("CREATE TABLE main.abc(a, b, c)"); QTest::newRow("90") << std::string("CREATE TABLE temp.helloworld(x)"); QTest::newRow("91") << std::string("CREATE TABLE auxa.\"t 1\"(x, y)"); QTest::newRow("92") << std::string("CREATE TABLE auxb.xyz(z)"); QTest::newRow("93") << std::string("CREATE TABLE main.abc(a, b, c)"); QTest::newRow("94") << std::string("CREATE TABLE main.t1(a, b, c)"); QTest::newRow("95") << std::string("CREATE TABLE temp.tmp(a, b, c)"); QTest::newRow("96") << std::string("CREATE TABLE auxb.tbl(x, y)"); QTest::newRow("97") << std::string("CREATE TABLE auxb.t1(k, v)"); QTest::newRow("98") << std::string("CREATE TABLE auxa.next(c, d)"); QTest::newRow("99") << std::string("CREATE TEMP TABLE t1(a, b)"); QTest::newRow("100") << std::string("CREATE TEMPORARY TABLE t2(a, b)"); QTest::newRow("101") << std::string("CREATE TEMP TABLE temp.t1(a, b)"); QTest::newRow("102") << std::string("CREATE TEMPORARY TABLE temp.t2(a, b)"); QTest::newRow("103") << std::string("CREATE TEMP TABLE TEMP.t3(a, b)"); QTest::newRow("104") << std::string("CREATE TEMPORARY TABLE TEMP.xxx(x)"); QTest::newRow("105") << std::string("CREATE TABLE t1(a, b)"); QTest::newRow("106") << std::string("CREATE TABLE t2(a, b)"); QTest::newRow("107") << std::string("CREATE TABLE t3(a, b)"); QTest::newRow("108") << std::string("CREATE TABLE xxx(x)"); QTest::newRow("109") << std::string("CREATE TABLE auxa.t1(a, b)"); QTest::newRow("110") << std::string("CREATE TABLE auxa.i1(a, b)"); QTest::newRow("111") << std::string("CREATE TABLE auxa.v1(a, b)"); QTest::newRow("112") << std::string("CREATE TABLE tbl1(a, b)"); QTest::newRow("113") << std::string("CREATE TABLE idx1(a, b)"); QTest::newRow("114") << std::string("CREATE TABLE view1(a, b)"); QTest::newRow("115") << std::string("CREATE TABLE IF NOT EXISTS t1(a, b)"); QTest::newRow("116") << std::string("CREATE TABLE IF NOT EXISTS auxa.tbl1(a, b)"); QTest::newRow("117") << std::string("CREATE TABLE IF NOT EXISTS v1(a, b)"); QTest::newRow("118") << std::string("CREATE TABLE IF NOT EXISTS auxa.view1(a, b)"); QTest::newRow("119") << std::string("CREATE TABLE t1(a, b, c);"); QTest::newRow("120") << std::string("CREATE TABLE t2(d, e, f);"); QTest::newRow("121") << std::string("CREATE TABLE t3(g BIGINT, h VARCHAR(10));"); QTest::newRow("122") << std::string("CREATE TABLE t4(i BLOB, j ANYOLDATA);"); QTest::newRow("123") << std::string("CREATE TABLE t5(k FLOAT, l INTEGER);"); QTest::newRow("124") << std::string("CREATE TABLE t6(m DEFAULT 10, n DEFAULT 5, PRIMARY KEY(m, n));"); QTest::newRow("125") << std::string("CREATE TABLE t7(x INTEGER PRIMARY KEY);"); QTest::newRow("126") << std::string("CREATE TABLE t8(o COLLATE nocase DEFAULT 'abc');"); QTest::newRow("127") << std::string("CREATE TABLE t9(p NOT NULL, q DOUBLE CHECK (q!=0), r STRING UNIQUE);"); QTest::newRow("128") << std::string("CREATE TABLE t1(x VARCHAR(10), y INTEGER, z DOUBLE);"); QTest::newRow("129") << std::string("CREATE TABLE t2(a DATETIME, b STRING, c REAL);"); QTest::newRow("130") << std::string("CREATE TABLE t3(o, t);"); QTest::newRow("131") << std::string("CREATE TABLE t4(a DEFAULT NULL,b DEFAULT 'string constant',c DEFAULT X'424C4F42',d DEFAULT 1,e DEFAULT -1,f DEFAULT 3.14,g DEFAULT -3.14,h DEFAULT ( substr('abcd', 0, 2) || 'cd' ),i DEFAULT CURRENT_TIME,j DEFAULT CURRENT_DATE,k DEFAULT CURRENT_TIMESTAMP);"); QTest::newRow("132") << std::string("CREATE TABLE t5(x DEFAULT ( 'abc' ))"); QTest::newRow("133") << std::string("CREATE TABLE t5(x DEFAULT ( 1 IN (1, 2, 3) ))"); QTest::newRow("134") << std::string("CREATE TABLE t5(a DEFAULT NULL, b DEFAULT 'text value', c DEFAULT X'424C4F42',d DEFAULT -45678.6,e DEFAULT 394507);"); QTest::newRow("135") << std::string("CREATE TABLE t6(a DEFAULT ( nextint() ), b DEFAULT ( nextint() ));"); QTest::newRow("136") << std::string("CREATE TABLE t7(a DEFAULT CURRENT_TIME, b DEFAULT CURRENT_DATE, c DEFAULT CURRENT_TIMESTAMP);"); QTest::newRow("137") << std::string("CREATE TABLE t8(a COLLATE nocase, b COLLATE rtrim, c COLLATE binary, d);"); QTest::newRow("138") << std::string("CREATE TABLE t1(a, b, c)"); QTest::newRow("139") << std::string("CREATE TABLE t2(a PRIMARY KEY, b, c)"); QTest::newRow("140") << std::string("CREATE TABLE t3(a, b, c, PRIMARY KEY(a))"); QTest::newRow("141") << std::string("CREATE TABLE t4(a, b, c, PRIMARY KEY(c,b,a))"); QTest::newRow("142") << std::string("CREATE TABLE t5(a, b INTEGER PRIMARY KEY, c)"); QTest::newRow("143") << std::string("CREATE TABLE t5(a PRIMARY KEY, b, c)"); QTest::newRow("144") << std::string("CREATE TABLE t5(a, b, c, PRIMARY KEY(a))"); QTest::newRow("145") << std::string("CREATE TABLE t5(a, b, c, PRIMARY KEY(c,b,a))"); QTest::newRow("146") << std::string("CREATE TABLE t5(a, b INTEGER PRIMARY KEY, c)"); QTest::newRow("147") << std::string("CREATE TABLE t1(a UNIQUE, b UNIQUE)"); QTest::newRow("148") << std::string("CREATE TABLE t2(a UNIQUE, b, c, UNIQUE(c, b))"); QTest::newRow("149") << std::string("CREATE TABLE t3(a, b, c, UNIQUE(a), UNIQUE(b), UNIQUE(c))"); QTest::newRow("150") << std::string("CREATE TABLE t4(a, b, c, UNIQUE(a, b, c))"); QTest::newRow("151") << std::string("CREATE TABLE t1(a TEXT PRIMARY KEY, b)"); QTest::newRow("152") << std::string("CREATE TABLE t1(a INTEGER PRIMARY KEY, b)"); QTest::newRow("153") << std::string("CREATE TABLE t1(a TEXT UNIQUE, b)"); QTest::newRow("154") << std::string("CREATE TABLE t1(a PRIMARY KEY, b TEXT UNIQUE)"); QTest::newRow("155") << std::string("CREATE TABLE t1(a PRIMARY KEY, b, c, UNIQUE(c, b))"); QTest::newRow("156") << std::string("CREATE TABLE t1(a, b PRIMARY KEY);"); QTest::newRow("157") << std::string("CREATE TABLE t2(a, b, c, UNIQUE(b, c));"); QTest::newRow("158") << std::string("CREATE TABLE x1(a TEXT, b INTEGER CHECK( b>0 ));"); QTest::newRow("159") << std::string("CREATE TABLE t1(a TEXT, b INTEGER, CHECK( b>0 ));"); QTest::newRow("160") << std::string("CREATE TABLE x2(a CHECK( a||b ), b);"); QTest::newRow("161") << std::string("CREATE TABLE t2(a, b, CHECK( a||b ));"); QTest::newRow("162") << std::string("CREATE TABLE t1(a NOT NULL, b)"); QTest::newRow("163") << std::string("CREATE TABLE t2(a PRIMARY KEY NOT NULL, b)"); QTest::newRow("164") << std::string("CREATE TABLE t3(a NOT NULL, b NOT NULL, c NOT NULL UNIQUE)"); QTest::newRow("165") << std::string("CREATE TABLE t1_ab(a PRIMARY KEY ON CONFLICT ABORT, b);"); QTest::newRow("166") << std::string("CREATE TABLE t1_ro(a PRIMARY KEY ON CONFLICT ROLLBACK, b);"); QTest::newRow("167") << std::string("CREATE TABLE t1_ig(a PRIMARY KEY ON CONFLICT IGNORE, b);"); QTest::newRow("168") << std::string("CREATE TABLE t1_fa(a PRIMARY KEY ON CONFLICT FAIL, b);"); QTest::newRow("169") << std::string("CREATE TABLE t1_re(a PRIMARY KEY ON CONFLICT REPLACE, b);"); QTest::newRow("170") << std::string("CREATE TABLE t1_xx(a PRIMARY KEY, b);"); QTest::newRow("171") << std::string("CREATE TABLE t2_ab(a, b NOT NULL ON CONFLICT ABORT);"); QTest::newRow("172") << std::string("CREATE TABLE t2_ro(a, b NOT NULL ON CONFLICT ROLLBACK);"); QTest::newRow("173") << std::string("CREATE TABLE t2_ig(a, b NOT NULL ON CONFLICT IGNORE);"); QTest::newRow("174") << std::string("CREATE TABLE t2_fa(a, b NOT NULL ON CONFLICT FAIL);"); QTest::newRow("175") << std::string("CREATE TABLE t2_re(a, b NOT NULL ON CONFLICT REPLACE);"); QTest::newRow("176") << std::string("CREATE TABLE t2_xx(a, b NOT NULL);"); QTest::newRow("177") << std::string("CREATE TABLE t3_ab(a, b, UNIQUE(a, b) ON CONFLICT ABORT);"); QTest::newRow("178") << std::string("CREATE TABLE t3_ro(a, b, UNIQUE(a, b) ON CONFLICT ROLLBACK);"); QTest::newRow("179") << std::string("CREATE TABLE t3_ig(a, b, UNIQUE(a, b) ON CONFLICT IGNORE);"); QTest::newRow("180") << std::string("CREATE TABLE t3_fa(a, b, UNIQUE(a, b) ON CONFLICT FAIL);"); QTest::newRow("181") << std::string("CREATE TABLE t3_re(a, b, UNIQUE(a, b) ON CONFLICT REPLACE);"); QTest::newRow("182") << std::string("CREATE TABLE t3_xx(a, b, UNIQUE(a, b));"); QTest::newRow("183") << std::string("CREATE TABLE t4(a, b CHECK (b!=10));"); QTest::newRow("184") << std::string("CREATE TABLE t2(oid, b);"); QTest::newRow("185") << std::string("CREATE TABLE t3(a, _rowid_);"); QTest::newRow("186") << std::string("CREATE TABLE t4(a, b, rowid);"); QTest::newRow("187") << std::string("CREATE TABLE t5(pk integer primary key)"); QTest::newRow("188") << std::string("CREATE TABLE t5(pk integer, primary key(pk))"); QTest::newRow("189") << std::string("CREATE TABLE t5(pk integer, v integer, primary key(pk))"); QTest::newRow("190") << std::string("CREATE TABLE t5(pk integer, v integer, primary key(pk, v))"); QTest::newRow("191") << std::string("CREATE TABLE t5(pk int, v integer, primary key(pk, v))"); QTest::newRow("192") << std::string("CREATE TABLE t5(pk int, v integer, primary key(pk))"); QTest::newRow("193") << std::string("CREATE TABLE t5(pk int primary key, v integer)"); QTest::newRow("194") << std::string("CREATE TABLE t5(pk inTEger primary key)"); QTest::newRow("195") << std::string("CREATE TABLE t5(pk inteGEr, primary key(pk))"); QTest::newRow("196") << std::string("CREATE TABLE t5(pk INTEGER, v integer, primary key(pk))"); QTest::newRow("197") << std::string("CREATE TABLE t6(pk INT primary key);"); QTest::newRow("198") << std::string("CREATE TABLE t7(pk BIGINT primary key);"); QTest::newRow("199") << std::string("CREATE TABLE t8(pk SHORT INTEGER primary key);"); QTest::newRow("200") << std::string("CREATE TABLE t9(pk UNSIGNED INTEGER primary key);"); QTest::newRow("201") << std::string("CREATE TABLE t(x INTEGER PRIMARY KEY ASC, y, z)"); QTest::newRow("202") << std::string("CREATE TABLE t(x INTEGER, y, z, PRIMARY KEY(x ASC))"); QTest::newRow("203") << std::string("CREATE TABLE t(x INTEGER, y, z, PRIMARY KEY(x DESC))"); QTest::newRow("204") << std::string("CREATE TABLE t(x INTEGER PRIMARY KEY DESC, y, z)"); } sqlitebrowser-sqlitebrowser-5733cb7/src/tests/testsqlobjects.h000066400000000000000000000024501463772530400250500ustar00rootroot00000000000000#ifndef TESTSQLOBJECTS_H #define TESTSQLOBJECTS_H #include class TestTable: public QObject { Q_OBJECT private slots: void sqlOutput(); void sqlGraveAccentOutput(); void sqlSquareBracketsOutput(); void autoincrement(); void notnull(); void withoutRowid(); void strict(); void strictAndWithoutRowid(); void foreignKeys(); void uniqueConstraint(); void parseSQL(); void parseSQLSquareBrackets(); void parseSQLdefaultexpr(); void parseSQLMultiPk(); void parseSQLForeignKey(); void parseSQLSingleQuotes(); void parseSQLKeywordInIdentifier(); void parseSQLSomeKeywordsInIdentifier(); void parseSQLWithoutRowid(); void parseSQLStrictTable(); void parseSQLStrictAndWithoutRowidTable(); void parseNonASCIIChars(); void parseNonASCIICharsEs(); void parseSQLEscapedQuotes(); void parseSQLForeignKeys(); void parseSQLCheckConstraint(); void parseDefaultValues(); void createTableWithIn(); void createTableWithNotLikeConstraint(); void rowValues(); void complexExpressions(); void datetimeExpression(); void extraParentheses(); void moduloOperator(); void complexExpression(); void parseIdentifierWithDollar(); void parseTest(); void parseTest_data(); }; #endif sqlitebrowser-sqlitebrowser-5733cb7/src/tools/000077500000000000000000000000001463772530400216235ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/tools/create_windows_icon.sh000077500000000000000000000012711463772530400262100ustar00rootroot00000000000000#!/usr/bin/env sh # This script depends on ImageMagick being installed FILES=() # array accumulating names of converted images # commands to give to convert for each iteration MAGICK_CMDS="+antialias -units PixelsPerInch -alpha set -background transparent" SRC_FILE="../../images/logo.svg" # conversion source ICO_FILE="../iconwin.ico" # output icon file for imgsize in 16 32 64 128 do RESIZE="${imgsize}x${imgsize}" DEST_FILE="icon${imgsize}.png" # NOTE: explicitly not using quotes - outpput raw contents to convert command convert ${MAGICK_CMDS} ${SRC_FILE} -resize ${RESIZE} ${DEST_FILE} FILES+=("${DEST_FILE}") done convert "${FILES[@]}" "${ICO_FILE}" rm "${FILES[@]}" sqlitebrowser-sqlitebrowser-5733cb7/src/translations/000077500000000000000000000000001463772530400232045ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/translations/README000066400000000000000000000002101463772530400240550ustar00rootroot00000000000000TS files for the application should be all named according to a convention such as _, e.g. sqlb_de, sqlb_ru etc. sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/000077500000000000000000000000001463772530400243005ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/ar.png000066400000000000000000000011201463772530400254020ustar00rootroot00000000000000‰PNG  IHDRÓFggAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<¢PLTEQ Q PNPO%d$I}HRƒQ4n3;s9V†UT„REzD@w@\Š[Ax@| z£~LKa_p˜ok•ji“gQƒP®Že‘d S 9q8ƒ¥n–lsšqwœu¤€\‹ZaŽ`?v>W‡VM€K=u<0k/YT U[W2m1F{F_(f(3m2 Q %€%stRNS@æØfbKGDˆHtIMEà ºçÚžIDATÓm‹‚0 EÙ“©à ‡  ¢"àÛÿÿ6¥#('Y–ž­i¯ãôAèÄ¡ìNQ )˜”²>ò[ZéªÁÐyþx2µR̓…Ãe¯ÖÐHaüM’nwÞ^Eðæç!ÉŽ:Ñ&>åç¶eU2`ÕÇ[É®7crcîA( >š§÷²šëmñBÉù» ùm‡.4ÌÞÇ„ ¨DJŠB%tEXtdate:create2016-07-11T02:24:19+02:00©˜õà%tEXtdate:modify2016-07-11T02:24:19+02:00ØÅM\IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/br.png000066400000000000000000000010601463772530400254060ustar00rootroot00000000000000‰PNG  IHDRä˜ïUsRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEß/ÝkÞ"°IDAT8ËÍ“?H[AÆ÷|/êÐ6y'Š¡ í µC]$Ö%RqëÒŽE ­S¡¤ÅÁ–VÁÙIÅÚ‚JF±â`—4$ôÏâËKR‚”ã]‡$mIŸ‰B‡~ÓÝñÝï,À*º¦Qƒ5LóDúà~Gq>÷RùêàªÀ „'WLz.H@pKºLÆ l¥@h[0ÞwZ›Xú6ÁÓý¡– ^^›båÀåUÂ;í_ÀÂ]0h,~}Äfò É#Í›x7ϯ>&h+^|‚HEÚ_ÀvÂD'HËàlj$v¢­A -E}D "n稙`Àaù†b6ÓqÈ)„Ç NJïSšHªÀǬ¿ÏàúEè—õX¥c* ùŠ~åANÁLF?Àº«°­4C-o1EqGöX³—Õ\n\Ão9l¦·w`*ö;çngà+îµ½FiÁ;g€‘Ö÷ôf Gó_ “?c±Ë%îóó.¸y© €ÝìwÂÑÛ™¢O‹ŠÂ#ª…†€ÆÚ‹ë ¥T§û4 ×ùSÕ€ü÷ú Æ—Ÿ'mÚ_IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/cn.png000066400000000000000000000010731463772530400254070ustar00rootroot00000000000000‰PNG  IHDRÓFgPLTEô-ÿ1ÿ2ÿ0ÿ:Á$ Å%Å'Ä$Ä#À à Å$Å$¿$ ÿ>  ˜ ÿ9ÿJ ‹ ÿSÿJ Š ÿRÿIŽ ÿQÿGŽ ‰ ÿS { sÿNVaaSgQTRbá)ß,â<Þ'ëj äAß)á*à&ç[ ö®æT â@Ý&à4ìu Þ*Þ)á+ß+ÿðõ§Ý#Ý%ÜäHìx Ý!Þ+à3í{ Þ&Þ,çY Ý#è+ã*â*é+Ī%3tRNSCSTTTTTTSAOMlmnonmocc‰ž‰ ”;wÉ©IDATÓc```bfaaaecf&`çàäâæáåâ~  ±‰©™‰¹…%X ‹0ˆŠYÛØÚÙ;8:9»€•¸ƒ¤”«›»‡§‹—· TPZ†AVÎÕÞÇ×Ï? Ð&(4òw ±uA1M &¢ÂÅ] *(¢ *É0(«„…G ðHU5u M-$ ©­ÃÀÀÈ «§ „Œ:Ì¢.½üIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/cs.png000066400000000000000000000003741463772530400254170ustar00rootroot00000000000000‰PNG  IHDRä˜ïUÃIDAT8Ë­¡‚`FH°0Áé#|Ÿ€Jr‘p³˜ úX &2‘âܬÝ@aƒ9ÔMËoÕ©ÈàÿÚÝwwîÙÅqV"M¯BVOÆHÁN PH’ ¶½Ä²Äñ™:Q_‡0<`šS|+e7\7¨l«þ*ªÚªEe[€gHó”IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/flags.qrc000066400000000000000000000017331463772530400261070ustar00rootroot00000000000000 ar.png cs.png de.png es.png us.png fr.png it.png ru.png cn.png br.png gb.png roc.png kr.png tr.png ua.png eg.png pl.png jp.png nl.png sv.png id.png ro.png sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/fr.png000066400000000000000000000011501463772530400254120ustar00rootroot00000000000000‰PNG  IHDRÓFg,PLTE*Œ-˜.› “ÿÿÿÿ/ÿ;ÿ:ÿ5!o"q!qkÀÄÐßßàááááßßà¾ÂÕ "Ö+Ö+Ò*:Â]§"ÿ!CIäU˜ÿ0`HãU—ÿ0aFÝT–NÿH~ ÿ-[188 5_bhoopppppooo_akk j Z ;/0 .RTY```aaaa```RS\\ Z k &&yÚàíýþÿÿÿÿÿýþþÙÝó &ô0÷1&€xÙßìüýþÿüýýØÜò &ó0ö1(…'zÞãñÿÜà÷ 'ø1ÿ2üc—HtRNSCSTTTTTTTTTSAPMnmpooodc‰žžžžžžžžž‰ Y4>£IDATÓc```bfaaevN.àæáååã IHzxzzzyûøúúùII3ÈÈCBÃ|}Ã#"£¢¢¢åäÑ•”± ÊÓOPE]PMžA]#&666.Þ“’’’5µ´utõôô ŒŒMLÍÌÌ-,¬¬mllíìœ]\\ÝÜ}˜HQDƒ%þIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/gb.png000066400000000000000000000013371463772530400254020ustar00rootroot00000000000000‰PNG  IHDRä˜ïUbKGDÿÿÿ ½§“”IDAT8­“YH”Q†GǦPk¤qÆqÀMid\#1,¤šò*ìBŠ$Jó")Á‚Â…¤ ë¢P°tH)†ÒÜ—Á…1ÓqÅíGýÝé"û]Æ¢÷êƒóžç¼çœïƒÿ,‡íòf,8xì\T«ÝäÏoëÎënòÂâ‡ïš[ai}7fsÊZ%`IIý½€MA^Þ':;­’M£q£¿üý œjnÆÿòGff%OLÌIòS<íz’öúñC€¦·C±2HG{6mmÙ$'‡xµää:^ÆñFn§£– µV uTŽÍ¼¯¢/2’`ÁBmí-L¦;èt¾v ðð4ž¥`шG]%ÞÅÅxUT2è¤psÑ –‹Y(–ؘbe`€¤¤ ’’‚°54ìÖ”]a¡½EQÎÁ§±Z§ùQoAW×$`Ôpk˜f«ÀØžD›¢(ÕVƒ™Ba—ÚX¸&eË¢|Åjµ3îÕÚØÞã¶% ]r–€ëž6ejê¾ÆõÉIlÍ͸ÆÅá¤RíëûyTk“€Æ_³p>áZbb ~>J„êjÄž\¯^‡‰Ql[m£ÍËãPT r¹#‹]]̈!4.§©©Ï [¿¬×ûjÒoDãÖÕˆE¯Gøò“s±iUvIôú§”–¶ =ƒ»Á€Ã‡·ÄVäï>(5C=ž–ðpf?›¨KÌ$¢ÆôÜÆÇçì€##åx{çPbG[þ»u;:($ ¸´<Ú™rŸøo*2Ÿµ3=½ð×Çÿ£©)99FñÎ<Ϥ_h7ìžåhàÈÎM*•‹S~†.Ò½÷»À\hôȃfó쬸g–e‹ðªóÀÿ¢_¨»ít ñÉIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/id.png000066400000000000000000000005271463772530400254060ustar00rootroot00000000000000‰PNG  IHDR™öÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ< PLTEÿÿÿÿÿþþþº*NbKGD LòtIMEæ ïyo‹IDAT×c` „‚Ã* †3CèYÉFl%tEXtdate:create2022-11-25T01:08:05+00:00¢Uïk%tEXtdate:modify2022-11-25T01:08:05+00:00ÓW×(tEXtdate:timestamp2022-11-25T01:07:28+00:00VäK8IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/it.png000066400000000000000000000012221463772530400254170ustar00rootroot00000000000000‰PNG  IHDRkúxýzTXtRaw profile type exifxÚTi®Ü þÏ)z¼æ8€ÔôøýLȼ™Ñ{£ª¶Ž÷- ãÏï~9d‹AS±\sŽ­Z¹°xÓã9/–åxźÎôÁ~ĹÙüÆß7µ7Gº£SÜ|¶7G|]â@߉„º °¿‰œ«•¨_ïm˜»Ä\’f+)ä33G’ñÐM¢˜4œŒ3ŠADZὬÓ5—3D/È(îŒÄÍ]L•\¿zç>®Î?ñW( Yî+¼—ù<šz;”Wþ=ŒÂJO –'¥üýd> &|šÌ*ë©Ñª›âW~:#…çôæ‡F"¥¤µèCG.Û¼,yµ oƺæv›t¢µ5ÞÚŸÁ]büETRÌÃcÇŽäu{ÑQÐct•~t«Úšœ˜úè9×Q™­ðŒu6 çH‡¶”hX3uÑ©•Tj1KÉôŒ­—Ôs+»?3«&ÙÛ:OÿXÿä4,¿[ãxøsBITÛáOàAIDAT(‘í˱À ÁØ,;ÈYK×K &U:[®þo8›‰Åýêã¹RE2Q]î±{á@Í5×üãßuÄŸ¿ÜIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/jp.png000066400000000000000000000006441463772530400254230ustar00rootroot00000000000000‰PNG  IHDR ù€šngAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<6IDATxÚbüúõ+ø÷ï„DfÀÁŸÿˆ(ÊÅÅ$ÿÿÿѦÿÿ‡SHàÅ‹ÄSôÁØ·ïÿá#ÿÿúofößË ®š‘‘h @± «^»öÿÂ…ÿÿüùÿë÷ÿÇÿ?}ò?9¢âB€b‚»$ôöíÿÕ«ÿÿþýÿ×/(Z¼äÿãÇpKþüù@LÏÁÝøÿãG¨Òß`òË—ÿþ‡YT @,@ ãÿgýÏÄV ¶hÐ,))¨þÿ* &¸ñ@õÿ……ÿûûÿÿù ªHÿ—“ƒ‡ ¸“ :þsqýßµ ¤ÚÎîL ÜÇ@ô@1¾}û–. e@ÜÉÈøÿ?BˆïÞ½ @ Þ½{‹HÄ –&“lŸäº‰=IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/kr.png000066400000000000000000000015751463772530400254320ustar00rootroot00000000000000‰PNG  IHDRkúxtRNSÖÝÛüC W pHYs  šœIDATxœU“Kh\eÅÏ÷Íwï¼îŒuÒ<Ccó˜6u°[hˆÔ4H-íJ %.\„XÁ…níB¡ R¥ Ø*bÛØRÅ&Ô¡3ÐÄš2­6™8™orçqïïÿw‘"xö¿Åùްkü?D€&€ˆAÄ`13ifMÄ @Ä0U@X]Í;•Í;Leúµª™`Öu7·ê¾ÿûÂoÁ Ùѹ3dš¶½Qrl @ À¶íkW¯œÿâü[·áˆRJF0fXÊfÏœž¼2ý½^…4‘@`ÙlöÒôt&“É;› °ÖîÜœ—ÉxŽàA¥ús&óå×~º>ó°³ ¥cyyÙ÷ýCƒûˆBÑã‰7ªcc¸÷Ç³Ï {µX(ÜœûÅÙØPJ‘ÀÌBˆt:ÇSO§£¦>ó¸5È,=ˆÌÝÄcVøÔäËǤړì¶âqÏõ˜HØ5Ç2CRþ³ýçìBâÝ·£‹?¢§?Ýuÿîß;±Þqâ˜÷Úë ˜‚!Äf¥²¼ò—$b@p]o ¾áµÎ‡vüš|g×ÄÈè7ï·Ù…ªR±ì{4³"i-¥ Í-XµmŸìxå«z²¥¯k¥¥«±Ô¸ñHêv’÷¦”Û¶'$ày.˜ˆ…sw–ö=•:´»sfxèT¾½© ÝZýâÀ‘'ú޶­ºÐÕ“zitDˆ$˜€öýÙÙÙ>üèÌÙsêo=‡#)¿©VˆÔRƉÃÍaèÏÏN<ùÞå‹Ë岡”fV4´V†ÑÖÚ àêµïúGFòfûLöbÞßimãK—¿ýøô§ÍÍ-OöõšÊ¨yž&R̼%:½wïóÃùÜÝp¤ À£±ð¡Ax¸B,’Hvöôöî>øâÁhÌjø"_*E ò,×us¹œ½iww&ƒ‘X­^ ›‚5;®¶¢–ã”çç æžþþ–Db%¿¶ZX«Å"3m=Fk&ÍÄÄh&&™†˜@ÿ¢:¦*H(¹IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/nl.png000066400000000000000000000001671463772530400254230ustar00rootroot00000000000000‰PNG  IHDRä˜ïU pHYsôô€­¬U)IDAT8Ëc\'£ñŸŠ€‰Ê`ÈøÿÿÿÑHl‘¢èÖ=)ƒÌ@zú£o;IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/pl.png000066400000000000000000000002131463772530400254150ustar00rootroot00000000000000‰PNG  IHDRä˜ïUbKGDÿÿÿ ½§“ pHYs × ×B(›x+IDAT8Ëcüÿÿÿ*&*ƒQ¡Œïë멚lï30Œ¦ÃQI£ÒâÀž™IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/ro.png000066400000000000000000000001521463772530400254240ustar00rootroot00000000000000‰PNG  IHDR [~SmPLTE+Tb[Î&ÝP üѬ6JIDAT×c```qqqVRRbL‡‚cÞÆIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/roc.png000066400000000000000000000005111463772530400255660ustar00rootroot00000000000000‰PNG  IHDRkúxsRGB®ÎégAMA± üa pHYsÃÃÇo¨dÞIDAT8Oc``˜ CS&10L“‘…u Þÿþá@PÍŒŒS¹¸fZ[¯óôÜ,/¿ˆ‰ hÑš™™'{zn9pàé½{;:ÎÉÊÎ;(ÍSxx¦çåþGŽ<30Xv< 6oÚ|÷îÇÎÎsÒÒÄÚ<„g0sÍ5±Þèä¹]R~ãt°øÒj_|šº!H€¡‹‹¡ƒ‡¡“‡¡&2­Á Ÿæ× ÜÈè ›ç šdÄ4?BÓ€ŒÐù$!t>IOBç“„Ðù$!H’$üÿwÔK…ÖäIEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/ru.png000066400000000000000000000007671463772530400254460ustar00rootroot00000000000000‰PNG  IHDRÓFgêPLTEÿÿÿÞÞÞááááááÝÝÝÿÿÿ¸¸¸¯¯¯¦¦¦   ©©§¢¢ ŒŒÿ44l11gœœÿ åUP ÿáTNûÜRLõÞvR,N(ü€ÿ  šÿÿ£ÿÿ„ÿaop_v]`^pÿÿÿOO§NN¥PP¨€‚~€|{}€A~A€Bûøÿþ’0*˜:tRNSCSTAPMmmoooopopopopopopodc‰ž‰ ¼R7H‚IDATÓ]ÈÇÁ@Ћ0zï]ô½w‚ÿÿ;b7ïåàdðçÒÜ Íc—ðnŸ€ðó ØäGv{â!ž8žˆs2…tær%nÙò…ûƒ0‹%”+Ïñ®Ö ×­a5šhµå—.z}É †ÀhlLÆt80_,«õ?è99Kvl^’IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/flags/sv.png000066400000000000000000000007401463772530400254370ustar00rootroot00000000000000‰PNG  IHDRä˜ïUgAMA± üa$tEXtSoftwareBy Embellish, from Dadaware›Š®gIDATxœ­“±JÃP…¿4!^šmA)]lGGDêæìû8øÝDÁA(:ö}”¢ƒR‹¶ÒD¯õæ:Ø&jm¡Ø3îø8??×ði%:eWf‰FïòõÿÿÿDW|J[€Qa„ATz2FoXh‰Te‡1Dm9V~¶*2WgŠ 5b1DnZj‹JPa…Rc…JGW|õÿÿ4GqRb…CU{L]€BTz+Ju¯! "TSd†N_‚OWhŠ-Bk)=hGP^‚¾@G¼?FüõõøññÈW\ÆV[ÈW]øÚÜóÙÚóÙÛÜsOWatRNSCSTTTTTTTTTTSAPMmþþþmnonþþþnnonþþþþþþþþþþonþomþomomocbŠžž‰ ièNèIDATÓc```bfaecçàäâæáåååãgA!aQ1q I)iiiY œ|bRrJjZzFfV6((2()çäæå—¨¨ªA©ºƒ¦VYyEeUuMm]=D¥¶"ƒŽnCceqSsnK«ž¾´1›´wtvu÷ô¦öAUš*2˜™÷[XZYÛØÚÙ;8‚ÍtrfPtÉv…¨€RÙnŠ î<'"Ï ^Þ Š>“&£€I¾Š ~þS¦¢€i ŠAÓgÌDÓƒBBÑ@Dd#CtL,ˆ‹O`ñgÊ¢IEND®B`‚sqlitebrowser-sqlitebrowser-5733cb7/src/translations/place_translations_here000066400000000000000000000000001463772530400300050ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_ar_SA.ts000066400000000000000000014272401463772530400255740ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite عن «متصÙّح قواعد بيانات SQLite» Version الإصدارة <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record أضÙ٠سجلًا جديدًا Enter values for the new record considering constraints. Fields in bold are mandatory. أدخÙÙ„ قيم السجلّ الجديد بأخذ القيود بعين الاعتبار. الحقول الثخينة ضرورية. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. يمكنك تحديد قيمة الحقل المحدّد ÙÙŠ عمود â€Ø§Ù„اسم“ وذلك ÙÙŠ عمود â€Ø§Ù„قيمة“. ÙŠÙØ´ÙŠØ± عمود â€Ø§Ù„نوع“ إلى نوع الحقل. ØªÙØ¹Ø±Ø¶ القيم المبدئية Ø¨Ù†ÙØ³ نمط قيم NULL. Name الاسم Type النوع Value القيمة Values to insert. Pre-filled default values are inserted automatically unless they are changed. القيم التي Ø³ØªÙØ¯Ø±Ø¬. لو لم تتغيّر ÙØ³Ùتدرج آليًا القيم المبدئية المعبّأة مسبقًا. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. عندما تحرّر القيم ÙÙŠ الإطار أعلاه، ستظهر هنا Ø¥ÙØ§Ø¯Ø© SQL لإدراج هذا السجلّ. يمكنك تحرير Ø§Ù„Ø¥ÙØ§Ø¯Ø© يدويًا قبل Ø§Ù„Ø­ÙØ¸. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <p>Ø³ÙŠÙØ±Ø³Ù„ زر <span style=" font-weight:600;">Ø§Ø­ÙØ¸</span> Ø¥ÙØ§Ø¯Ø© SQL الظاهرة إلى قاعدة البيانات لإدراج السجلّ الجديد.</p><p>سيستعيد زر <span style=" font-weight:600;">استعد المبدئيات</span> القيمة الأولية ÙÙŠ عمود â€<span style=" font-weight:600;">القيمة</span>“.</p><p>Ø³ÙŠÙØºÙ„Ù‚ زر <span style=" font-weight:600;">ألغÙ</span> مربّع الحوار هذا دون تنÙيذ الاستعلام.</p> Auto-increment زيادة آليّة Unique constraint قيد â€Ùريد“ Check constraint: %1 قيد Ø§Ù„ÙØ­Øµ: %L1 Foreign key: %1 Ø§Ù„Ù…ÙØªØ§Ø­ الأجنبي: %L1 Default value: %1 القيمة المبدئية: %L1 Error adding record. Message from database engine: %1 خطأ أثناء Ø¥Ø¶Ø§ÙØ© السجلّ. الرسالة من محرّك قواعد البيانات: %L1 Are you sure you want to restore all the entered values to their defaults? أمتأكّد من استعادة كلّ القيم Ø§Ù„Ù…ÙØ¯Ø®Ù„Ø© إلى مبدئياتها؟ Application Possible command line arguments: معطيات سطر الأوامر الممكنة: The -o/--option and -O/--save-option options require an argument in the form group/setting=value يطلب الخياران ‎-o/--option Ùˆ ‎-O/--save-option معطًى بهذا النحو: group/setting=value The user settings file location is replaced with the argument value instead of the environment variable value. Ignored environment variable (DB4S_SETTINGS_FILE) value: The file %1 does not exist المل٠%L1 غير موجود Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Browse this table, or use it as target of a data import Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The -S/--settings option requires an argument. The option is ignored. Invalid option/non-existent file: %1 خيار غير صالح/مل٠غير موجود: %L1 SQLite Version إصدارة SQLite: †SQLCipher Version %1 (based on SQLite %2) إصدارة SQLCipher:†%L1 (مبنيّة على SQLite %L2) DB Browser for SQLite Version %1. «متصÙّح قواعد بيانات SQLite» الإصدارة %L1. Last commit hash when built: %1 Built for %1, running on %2 مبنيّة للمعماريّة %L1ØŒ وتعمل على المعماريّة %L2 Qt Version %1 إصدارة كيوت: %L1 CipherDialog SQLCipher encryption تعمية SQLCipher &Password &كلمة السر &Reenter password Ø£&Ø¹ÙØ¯ إدخال كلمة السر Encr&yption settings إعدادات التع&مية SQLCipher &3 defaults مبدئيّات SQLCipher &3 SQLCipher &4 defaults مبدئيّات SQLCipher &4 Custo&m Ù…&خصّص Page si&ze Ù…&قاس Ø§Ù„ØµÙØ­Ø© &KDF iterations ت&كرارات KDF HMAC algorithm خوارزميّة HMAC KDF algorithm خوارزميّة KDF Plaintext Header Size حجم ترويسة النص البائن Passphrase عبارة سر Raw key Ù…ÙØªØ§Ø­ خام Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. من ÙØ¶Ù„Ùƒ اضبط Ù…ÙØªØ§Ø­Ù‹Ø§ لتعمية قاعدة البيانات. لو غيّرت أيًا من الإعدادات الأخرى (الاختيارية)ØŒ ÙØ³ÙŠÙƒÙˆÙ† عليك إعادة إدخالها أيضًا ÙÙŠ كلّ مرّة ØªÙØªØ­ Ùيها مل٠قاعدة البيانات. اترك حقول كلمة السر ÙØ§Ø±ØºØ© لتعطيل التعمية. قد تأخذ عملية التعمية وقتًا وعليك Ø§Ù„Ø§Ø­ØªÙØ§Ø¸ بنسخة من قاعدة البيانات احتياطًا! Ø³ØªÙØ·Ø¨Ù‘Ù‚ التعديلات غير المحÙوظة قبل تعديل التعمية. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. من ÙØ¶Ù„Ùƒ أدخÙÙ„ Ø§Ù„Ù…ÙØªØ§Ø­ المستعمل لتعمية قاعدة البيانات. إن كانت هناك إعدادات أخرى قد تغيّرت ÙÙŠ مل٠قاعدة البيانات هذا، ÙØ¹Ù„يك ذكر ذلك أيضًا. ColumnDisplayFormatDialog Choose display format اختر تنسيق العرض Display format تنسيق العرض Choose a display format for the column '%1' which is applied to each value prior to showing it. اختر تنسيق عرض العمود â€%L1“ Ù„ÙŠÙØ·Ø¨Ù‘Ù‚ على كلّ قيمة قبل عرضها. Default المبدئي Decimal number عدد عشري Exponent notation تدوين Ø£ÙØ³Ù‘ÙŠ Hex blob â€BLOB ستّ‌عشري Hex number عدد ستّ‌عشري Apple NSDate to date â€ØªØ§Ø±ÙŠØ® آبل/Apple NSDate“ إلى تاريخ Java epoch (milliseconds) to date عَصر جاڤا (ملّي‌ثانية) إلى تاريخ .NET DateTime.Ticks to date â€DateTime.Ticks من ‎.NET إلى تاريح Julian day to date يوم جولياني إلى تاريخ Unix epoch to local time عَصر لينكس إلى الوقت المحلي WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy التاريخ بتنسيق dd/mm/yyyy Lower case حالة الأحر٠صغيرة Binary GUID to text SpatiaLite Geometry to SVG Custom display format must contain a function call applied to %1 على تنسيق العرض المخصّص أن يحتوي على نداء دالة مطبّق على %L1 Error in custom display format. Message from database engine: %1 خطأ ÙÙŠ تنسيق العرض المخصّص. الرسالة من محرّك قواعد البيانات: %L1 Custom display format must return only one column but it returned %1. على تنسيق العرض المخصّص إعادة عمود واحد Ùقط، لكنّه أعاد %L1. Octal number عدد ثماني Round number عدد تقريبي Unix epoch to date عَصر لينكس إلى تاريخ Upper case حالة الأحر٠كبيرة Windows DATE to date â€ØªØ§Ø±ÙŠØ® وندوز/Windows DATE“ إلى تاريخ Custom مخصّص CondFormatManager Conditional Format Manager مدير التنسيقات الشرطيّة This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. ÙŠÙØªÙŠØ­ لك مربّع الحوار هذا إنشاء التنسيقات الشرطيّة وتحريرها. ستختار البرمجيّة كلّ نمط خلايا حسب أوّل شرط متواÙÙ‚ مع بيانات الخليّة. يمكنك نقل التنسيقات الشرطيّة إلى أعلى وأسÙÙ„ØŒ حيث تعبّر أعلاها أكثرها أولويّة، والعكس. صياغة الشروط هي Ù†ÙØ³Ù‡Ø§ صياغة المرشّحات، والشروط Ø§Ù„ÙØ§Ø±ØºØ© تنطبق على كلّ القيم. Add new conditional format أضÙ٠تنسيقًا شرطيًا جديدًا &Add Ø£&ضÙÙ Remove selected conditional format أزÙÙ„ التنسيق الشرطيّ المحدّد &Remove Ø£&زÙÙ„ Move selected conditional format up انقل التنسيق الشرطيّ المحدّد لأعلى Move &up انقل لأ&على Move selected conditional format down انقل التنسيق الشرطيّ المحدّد لأسÙÙ„ Move &down انقل لأ&سÙÙ„ Foreground الأمامية Text color لون النص Background الخلÙية Background color لون الخلÙية Font الخط Size الحجم Bold ثخين Italic مائل Underline مسطّر Alignment المحاذاة Condition الشرط Click to select color انقر لاختيار لون Are you sure you want to clear all the conditional formats of this field? أمتأكّد من مسح كلّ التنسيقات الشرطيّة لهذا الحقل؟ DBBrowserDB Please specify the database name under which you want to access the attached database من ÙØ¶Ù„Ùƒ اختر اسم قاعدة البيانات الذي تريد استعماله للوصول إلى قاعدة البيانات المرÙقة Invalid file format تنسيق المل٠غير صالح Do you want to save the changes made to the database file %1? أتريد Ø­ÙØ¸ التعديلات Ø§Ù„Ù…ÙØ¬Ø±Ø§Ø© على مل٠قاعدة البيانات %L1ØŸ Exporting database to SQL file... يصدّر قاعدة البيانات إلى مل٠SQL... Cancel ألغ٠Executing SQL... ينÙّذ SQL... Action cancelled. Ø£Ùلغي الإجراء. Do you really want to close this temporary database? All data will be lost. أمتأكّد من إغلاق قاعدة البيانات المؤقّتة هذه؟ ستÙقد كلّ البيانات. Database didn't close correctly, probably still busy لم ØªÙØºÙ„Ù‚ قاعدة البيانات كما ينبغي، ربّما هي مشغولة Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: قاعدة البيانات مشغولة حاليًا: Do you want to abort that other operation? أتريد إجهاض العملية الأخرى؟ No database file opened لم ÙŠÙÙØªØ­ مل٠قاعدة بيانات Error in statement #%1: %2. Aborting execution%3. خطأ ÙÙŠ Ø§Ù„Ø¥ÙØ§Ø¯Ø© رقم %L1:†%L2. Ø³Ø£ÙØ¬Ù‡Ø¶ التنÙيذ%L3. and rolling back ÙˆØ£ÙØ±Ø¬Ø¹ ما كان موجودًا. didn't receive any output from %1 لم أستلم أيّ ناتج من %L1 could not execute command: %1 تعذّر تنÙيذ الأمر: %L1 Cannot delete this object تعذّر حذ٠هذا الكائن Cannot set data on this object تعذّر ضبط البيانات على هذا الكائن A table with the name '%1' already exists in schema '%2'. هناك جدول Ø¨Ù†ÙØ³ الاسم â€%L1“ Ø¨Ø§Ù„ÙØ¹Ù„ ÙÙŠ المخطّط â€%L2“. No table with name '%1' exists in schema '%2'. ما من جدول له الاسم â€%L1“ ÙÙŠ المخطّط â€%L2“. Cannot find column %1. تعذّر العثور على العمود %L1 Creating savepoint failed. DB says: %1 ÙØ´Ù„ إنشاء نقطة Ø§Ù„Ø­ÙØ¸. تقول قاعدة البيانات: %L1 Renaming the column failed. DB says: %1 ÙØ´Ù„ تغيير اسم العمود. تقول قاعدة البيانات: %L1 Releasing savepoint failed. DB says: %1 ÙØ´Ù„ت استعداة نقطة Ø§Ù„Ø­ÙØ¸. تقول قاعدة البيانات: %L1 Creating new table failed. DB says: %1 ÙØ´Ù„ إنشاء جدول جديد. تقول قاعدة البيانات: %L1 Copying data to new table failed. DB says: %1 ÙØ´Ù„ نسخ البيانات إلى جدول جديد. تقول قاعدة البيانات: %L1 Deleting old table failed. DB says: %1 ÙØ´Ù„ حذ٠الجدول القديم. تقول قاعدة البيانات: %L1 Error renaming table '%1' to '%2'. Message from database engine: %3 خطأ ÙÙŠ تغيير اسم الجدول â€%L1“ إلى â€%L2“. الرسالة من محرّك قواعد البيانات: %L3 could not get list of db objects: %1 تعذّر جلب قائمة كائنات قواعد البيانات: %L1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: ÙØ´Ù„ت استعادة بعض الكائنات المرتبطة بهذا الجدول. غالبًا ما يحدث هذا بسبب تغيّر اسم الأعمدة. هذه Ø¥ÙØ§Ø¯Ø© SQL التي قد ترغب بتنÙيذها لإصلاح ذلك يدويًا: could not get list of databases: %1 تعذّر جلب قائمة قواعد البيانات: %L1 Error loading extension: %1 خطأ أثناء تحميل الامتداد: %L1 Error loading built-in extension: %1 could not get column information تعذّر جلب معلومات العمود Error setting pragma %1 to %2: %3 تعذّر ضبط pragma %L1 إلى %L2:†%L3 File not found. تعذّر العثور على الملÙ. DbStructureModel Name الاسم Object الكائن Type النوع Schema المخطّط Database قاعدة البيانات Browsables ما يمكنك تصÙّحه All الكلّ Temporary مؤقّتة Tables (%1) الجداول (%L1) Indices (%1) الÙهارس (%L1) Views (%1) المناظير (%L1) Triggers (%1) المحÙّزات (%L1) EditDialog Edit database cell تحرير خليّة قاعدة البيانات Mode: الوضع: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. هذه قائمة بالأوضاع المتوÙّرة ÙÙŠ محرّر الخلايا. اختر وضعًا لعرض أو تحرير البيانات ÙÙŠ الخليّة الحالية. Text نصوص RTL Text نصوص من اليمين إلى اليسار Binary بيانات ثنائيّة Image صور JSON JSON XML XML Evaluation Automatically adjust the editor mode to the loaded data type اضبط وضع المحرّر آليًا على نوع البيانات المحمّل This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. ÙŠÙÙØ¹Ù‘Ù„/ÙŠÙØ¹Ø·Ù‘Ù„ هذا الزر التبديل التلقائي لوضع المحرّر. متى حدّدت خليّة جديدة أو استوردت بيانات جديدة ويÙÙØ¹Ù‘Ù„ التبديل الآلي سترى بأنّ الوضع Ø³ÙŠÙØ¶Ø¨Ø· على نوع البيانات المكتشÙ. يمكنك بعدها تغيير وضع المحرّر يدويًا. لو أردت أن يكون التبديل يدويًا عند الانتقال بين الخلايا، ÙØ¹Ø·Ù‘Ù„ هذا الزر. Auto-switch التبديل الآلي This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. ÙŠÙØ³ØªØ¹Ù…Ù„ محرّر «كيوت» هذا للغات المكتوبة من اليمين إلى اليسار (مثل العربيّة) إذ لا يدعمها محرّر النصوص المبدئي. لو كتبت حرو٠لغة تÙكتب من اليمين إلى اليسار، ÙØ³ØªÙƒØªØ´Ù البرمجيّة ذلك وتحدّد وضع الخليّة هذا تلقائيًا. Identification of the cell currently in the editor Type and size of data currently in table Open preview dialog for printing the data currently stored in the cell Ø§ÙØªØ­ مربّع حوار معاينة طباعة البيانات المخزّنة ÙÙŠ الخليّة حاليًا Auto-format: pretty print on loading, compact on saving. التنسيق الآلي: طباعة جميلة (pretty print) عند التحميل، رصّ عند Ø§Ù„Ø­ÙØ¸. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. إن ÙØ¹Ù‘لت الخيار ÙØ³ØªÙنسّق ميزة التنسيق الآلي البياناتَ متى تحمّلت، ÙØªÙƒØ³Ø± النصوص إلى أسطر ÙˆØªÙØ²ÙŠØ­Ù‡Ø§ لزيادة مقروؤيتها. وعند Ø­ÙØ¸ البيانات ترصّ ميزة التنسيق الآلي البياناتَ بإزالة نهايات الأسطر ÙˆØ§Ù„Ù…Ø³Ø§ÙØ§Øª غير اللازمة. Word Wrap Ù„ÙÙ‘ الأسطر Wrap lines on word boundaries Ù„ÙÙÙ‘ الأسطر عند حدود الكلمات Open in default application or browser Ø§ÙØªØ­ ÙÙŠ التطبيق المبدئي أو المتصÙّح Open in application Ø§ÙØªØ­ ÙÙŠ التطبيق The value is interpreted as a file or URL and opened in the default application or web browser. ØªÙØ­Ù„ّل البرمجيّة القيمة على أنّها مل٠أو مسار ÙˆØªÙØªØ­Ù‡ ÙÙŠ التطبيق المبدئي أو ÙÙŠ متصÙّح الوب. Save file reference... Ø§Ø­ÙØ¸ إشارة إلى الملÙ... Save reference to file Ø§Ø­ÙØ¸ إشارة إلى الملÙ... Open in external application Ø§ÙØªØ­ ÙÙŠ تطبيق خارجي Autoformat التنسيق الآلي &Export... &صدّر... &Import... ا&Ø³ØªÙˆØ±ÙØ¯... Import from file Ø§Ø³ØªÙˆØ±ÙØ¯ من مل٠Opens a file dialog used to import any kind of data to this database cell. ÙŠÙØªØ­ مربّع حوار Ù…Ù„ÙØ§Øª ÙŠÙØ³ØªØ¹Ù…Ù„ لاستيراد أيّ نوع من البيانات ÙÙŠ خليّة قاعدة البيانات هذه. Export to file صدّر إلى مل٠Opens a file dialog used to export the contents of this database cell to a file. ÙŠÙØªØ­ مربّع حوار Ù…Ù„ÙØ§Øª ÙŠÙØ³ØªØ¹Ù…Ù„ لتصدير محتويات خليّة قاعدة البيانات هذه إلى ملÙ. Print... اطبع... Ctrl+P Ctrl+P Open preview dialog for printing displayed text ÙŠÙØªØ­ مربّع حوار المعاينة لطباعة النص المعروض Copy Hex and ASCII انسخ Hex وآسكي Copy selected hexadecimal and ASCII columns to the clipboard انسخ الأعمدة الستّ‌عشرية وآسكي المحدّدة إلى Ø§Ù„Ø­Ø§ÙØ¸Ø© Ctrl+Shift+C Ctrl+Shift+C Erases the contents of the cell يمسح محتويات هذه الخليّة Set as &NULL ا&ضبط على NULL This area displays information about the data present in this database cell تعرض هذه المنطقة معلومات عن البيانات الموجودة ÙÙŠ خليّة قاعدة البيانات هذه Apply data to cell طبّق البيانات على الخليّة This button saves the changes performed in the cell editor to the database cell. ÙŠØ­ÙØ¸ هذا الزر التغييرات Ø§Ù„Ù…ÙØ¬Ø±Ø§Ø© داخل محرّر الخلايا ÙÙŠ خليّة قاعدة البيانات. Apply طبّق Choose a filename to export data اختر اسمًا للمل٠لتصدير البيانات Image data can't be viewed in this mode. لا يمكن عرض بيانات الصور ÙÙŠ هذا الوضع. Try switching to Image or Binary mode. جرّب الانتقال إلى وضع â€ØµÙˆØ±â€œ أو â€Ø¨ÙŠØ§Ù†Ø§Øª ثنائيّة“. Binary data can't be viewed in this mode. لا يمكن عرض البيانات الثنائيّة ÙÙŠ هذا الوضع. Try switching to Binary mode. جربّ الانتقال إلى وضع â€Ø¨ÙŠØ§Ù†Ø§Øª ثنائيّة“. Image files (%1) Ù…Ù„ÙØ§Øª الصور (%L1) Binary files (*.bin) Ø§Ù„Ù…Ù„ÙØ§Øª الثنائيّة (*.bin) Choose a file to import اختر ملÙًا لاستيراده The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Unsaved data in the cell editor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. %1 Image صورة %L1 Invalid data for this mode بيانات غير صالحة ÙÙŠ هذا الوضع The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? تحتوي الخليّة بيانات %L1 غير صالحة. السبب: %L2. أمتأكّد من تطبيقها على الخليّة؟ Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) Couldn't save file: %1. تعذّر Ø­ÙØ¸ الملÙ: %L1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. EditIndexDialog &Name الا&سم Order الترتيب &Table الج&دول Edit Index Schema تحرير مخطّط الÙهرس &Unique &ÙØ±ÙŠØ¯ For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed إن أردت حصر الÙهرس على جزء من الجدول ÙØ­Ø³Ø¨ØŒ يمكنك هنا تحديد بند WHERE Ù„ÙŠÙØ­Ø¯Ù‘د جزء الجدول الذي يجب Ùهرسته Partial inde&x clause بند Ù&هرس جزئي Colu&mns الأ&عمدة Table column عمود الجدول Type النوع Add a new expression column to the index. Expression columns contain SQL expression rather than column names. أضÙ٠عمود تعبير جديد إلى الÙهرس. تحتوي أعمدة التعابير على تعابير SQL بدل أسماء الأعمدة. Index column عمود الÙهرس Deleting the old index failed: %1 ÙØ´Ù„ حذ٠الÙهرس القديم: %L1 Creating the index failed: %1 ÙØ´Ù„ إنشاء الÙهرس: %L1 EditTableDialog Edit table definition تحرير تعري٠الجدول Table الجدول Advanced متقدّم Without Rowid بلا معرّ٠للصÙÙˆÙ Fields الحقول Database sche&ma مخ&طّط قاعدة البيانات Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Add أضÙÙ Remove أزÙÙ„ Move to top انقل للأعلى Move up انقل لأعلى Move down انقل لأسÙÙ„ Move to bottom انقل للأسÙÙ„ Name الاسم Type النوع NN NN Not null ليس NULL PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> AI AI Autoincrement زيادة آليّة Auto Increment U U Unique ÙØ±ÙŠØ¯ Unique Default المبدئي Default value القيمة المبدئية Check Ø§Ù„ÙØ­Øµ Check constraint قيد Ø§Ù„ÙØ­Øµ Check constraint Collation قواعد مقارنة المحار٠Foreign Key Ù…ÙØªØ§Ø­ أجنبي <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Index Constraints Add constraint أضÙ٠قيدًا Remove constraint أزÙÙ„ القيد Columns الأعمدة SQL SQL Foreign Keys References Check Constraints <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <span style=" font-weight:600; color:#ff0000;">تحذير: </span>ثمّة خطب بتعري٠هذا الجدول تعذّر على المحلّل Ùهمه تمامًا. يمكن أن يؤدّي تعديل ÙˆØ­ÙØ¸ هذا الجدول إلى بعض المشاكل. Primary Key Ù…ÙØªØ§Ø­ أساسي Add a primary key constraint أضÙ٠قيد ÙØ±Ø¶ Ù…ÙØªØ§Ø­ أساسي Add a unique constraint أضÙ٠قيد ÙØ±Ø¶ â€Ùريد“ Error creating table. Message from database engine: %1 خطأ أثناء إنشاء الجدول. الرسالة من محرّك قواعد البيانات: %L1 There already is a field with that name. Please rename it first or choose a different name for this field. هناك حقل بهذا الاسم Ø¨Ø§Ù„ÙØ¹Ù„. من ÙØ¶Ù„Ùƒ غيّر اسمه أو اختر اسمًا مختلÙًا لهذا الحقل. There can only be one primary key for each table. Please modify the existing primary key instead. لكلّ جدول Ù…ÙØªØ§Ø­ أساسي واحد Ùقط. من ÙØ¶Ù„Ùƒ عدّل Ø§Ù„Ù…ÙØªØ§Ø­ الموجود بدل هذا الأمر. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. هذا العمود مذكور ÙÙŠ Ù…ÙØªØ§Ø­ أجنبي ÙÙŠ الجدول %L1 ولا يمكن تغيير اسمه. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. ثمّة صÙÙ‘ واحد على الأقل Ø¶ÙØ¨Ø· هذا الحقل Ùيه على NULL. لهذا السبب يستحيل ضبط هذه الراية. من ÙØ¶Ù„Ùƒ غيّر بيانات الجدول أوّلًا. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. ثمّة صÙÙ‘ واحد على الأقل Ø¶ÙØ¨Ø· هذا الحقل Ùيه على قيمة ليست بنوع â€Ø¹Ø¯Ø¯ صحيح“. لهذا السبب يستحيل ضبط راية الزيادة الآليّة. من ÙØ¶Ù„Ùƒ غيّر بيانات الجدول أوّلًا. Column '%1' has duplicate data. ÙÙŠ العمود â€%L1“ بيانات متكرّرة. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. يمنع هذا ØªÙØ¹ÙŠÙ„ راية â€Ùريد“. من ÙØ¶Ù„Ùƒ أزÙÙ„ البيانات المتكرّرة كي تقدر على ØªÙØ¹ÙŠÙ„ هذه الراية. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. أمتأكّد من حذ٠الحقل â€%L1“؟ ستÙقد كل البيانات المخزّنة Ùيه حاليًا. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled من ÙØ¶Ù„Ùƒ أضÙ٠حقلًا ÙŠÙØ·Ø§Ø¨Ù‚ المعايير الآتية قبل ضبط راية â€Ø¨Ù„ا معرّ٠صÙÙˆÙ/rowid“: - راية â€Ù…ÙØªØ§Ø­ أساسي“ مضبوطة - الزيادة الآلية معطّلة Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set ExportDataDialog Export data as CSV تصدير البيانات بنسق CSV Tab&le(s) الج&داول Colu&mn names in first line أسماء الأ&عمدة ÙÙŠ أوّل سطر Fie&ld separator ÙØ§ØµÙ„ الح&قول , , ; ; Tab جدولات | | Other شيء آخر &Quote character محر٠ال&تنصيص " " ' ' New line characters محر٠الأسطر الجديدة Windows: CR+LF (\r\n) وندوز: CR+LF â€(‎\r\n) Unix: LF (\n) ÙŠÙنكس: LF â€(‎\n) Pretty print طباعة جميلة Could not open output file: %1 تعذّر ÙØªØ­ مل٠الخرج: %L1 Choose a filename to export data اختر اسمًا للمل٠لتصدير البيانات Export data as JSON تصدير البيانات بنسق JSON exporting CSV يصدّر CSV Error while writing the file '%1': %2 exporting JSON يصدّر JSON Please select at least 1 table. من ÙØ¶Ù„Ùƒ حدّد جدولًا واحدًا على الأقل. Choose a directory اختر دليلًا Export completed. اكتمل التصدير. Export finished with errors. ExportSqlDialog Export SQL... تصدير SQL... Tab&le(s) الج&دول Select All حدّد الكلّ Deselect All ألغ٠تحديد الكلّ &Options &خيارات Keep column names in INSERT INTO أبق٠أسماء الأعمدة ÙÙŠ INSERT INTO Multiple rows (VALUES) per INSERT statement أكثر من صÙÙ‘ واحد (VALUES) لكلّ Ø¥ÙØ§Ø¯Ø© INSERT Export everything صدّر كل شيء Export schema only صدّر المخطّط Ùقط Export data only صدّر البيانات Ùقط Keep original CREATE statements Keep old schema (CREATE TABLE IF NOT EXISTS) أبق٠المخطّط القديم (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) اكتب على المخطّط القديم (DROP TABLEØŒ وبعدها CREATE TABLE) Please select at least one table. من ÙØ¶Ù„Ùƒ حدّد جدولًا واحدًا على الأقل. Choose a filename to export اختر اسمًا للمل٠لتصديره Export completed. اكتمل التصدير. Export cancelled or failed. إمّا أنّ التصدير Ø£Ùلغي أو أنّه ÙØ´Ù„. ExtendedScintilla Ctrl+H Ctrl+H Ctrl+F Ctrl+F Ctrl+P Ctrl+P Find... ابحث... Find and Replace... ابحث واستبدل... Print... اطبع... ExtendedTableWidget Use as Exact Filter استعملها كمرشّح كما هي Containing تحتوي على Not containing لا تحتوي على Not equal to لا تساوي Greater than أكبر من Less than أصغر من Greater or equal أكبر من أو تساوي Less or equal أصغر من أو تساوي Between this and... بين هذه Ùˆ... Regular expression تعبير نمطي Edit Conditional Formats... حرّر التنسيقات الشرطيّة... Set to NULL اضبطها على NULL Cut Copy انسخ Copy with Headers انسخ مع الترويسات Copy as SQL انسخ كَ†SQL Paste ألصÙÙ‚ Print... اطبع... Use in Filter Expression استعملها ÙÙŠ تعبير الترشيح Alt+Del Alt+Del Ctrl+Shift+C Ctrl+Shift+C Ctrl+Alt+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? محتوى Ø§Ù„Ø­Ø§ÙØ¸Ø© أكبر من المدى المحدّد. أتريد إدراجه رغم ذلك؟ <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>لم ØªÙØ­Ù…ّل كلّ البيانات. <b>أتريد تحميل كلّ البيانات قبل تحديد كلّ الصÙÙˆÙØŸ</b><p><p>لو اخترت <b>لا</b> Ùلن ØªÙØ­Ù…ّل أيّة بيانات أخرى ولن ÙŠÙØ¬Ø±Ù‰ هذا التحديد.<br/>لو اخترت <b>نعم</b> ÙØ¹Ù„يك الانتظار وقتًا حتّى ØªÙØ­Ù…ّل البيانات، ولكن التحديد هنا سيحدث</p>تحذير: قد يطلب تحميل كلّ البيانات ذاكرة كثيرة لو كانت الجداول ضخمة. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. تعذّر ضبط التحديد على NULL. على العمود %L1 قيد â€Ù„يس NULL“. FileExtensionManager File Extension Manager مدير امتدادات Ø§Ù„Ù…Ù„ÙØ§Øª &Up لأ&على &Down لأ&سÙÙ„ &Add Ø£&ضÙÙ &Remove Ø£&زÙÙ„ Description الوص٠Extensions الامتدادات *.extension يمكن للمستخدم تحرير هذه، ÙØ§Ù„Ø£ÙØ¶Ù„ أن تكون إنكليزية بدون محار٠يونيكود كي لا يتركها من غير قصد *.extension FilterLineEdit Filter رشّح These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression تتيح لك مربّعات الإدخال هذه إجراء ترشيح سريع على الجدول المحدّد حاليًا. مبدئيًا ØªÙØ±Ø´Ù‘Ø­ الصÙو٠التي تحتوي على نص الإدخال. كما ويدعم البحث Ø§Ù„Ù…ÙØ¹Ø§Ù…لات الآتية: % حر٠البدل > أكبر من < أصغر من >= أكبر من أو يساوي >= أصغر من أو يساوي = يساوي (Ù…ÙØ·Ø§Ø¨Ù‚Ø© تامّة) <> لا يساوي (Ù…ÙØ·Ø§Ø¨Ù‚Ø© عكسية تامّة) س~ص مدى: القيم بين â€Ø³â€œ Ùˆâ€Øµâ€œ /ريجÙكس/ القيم التي ØªÙØ·Ø§Ø¨Ù‚ التعبير النمطي Clear All Conditional Formats امسح كلّ التنسيقات الشرطيّة Use for Conditional Format استعمله تنسيقًا شرطيًا Edit Conditional Formats... حرّر التنسيقات الشرطيّة... Set Filter Expression اضبط تعبير الترشيح What's This? ما هذا؟ Is NULL تساوي NULL Is not NULL لا تساوي NULL Is empty ÙØ§Ø±ØºØ© Is not empty ليست ÙØ§Ø±ØºØ© Not containing... لا تحتوي على... Equal to... تساوي... Not equal to... لا تساوي... Greater than... أكبر من... Less than... أصغر من... Greater or equal... أكبر من أو تساوي... Less or equal... أصغر من أو تساوي... In range... ÙÙŠ المدى... Regular expression... تعبير نمطي... FindReplaceDialog Find and Replace البحث والاستبدال Fi&nd text: ابح&Ø« عن النص: Re&place with: ا&ستبدله بÙâ€: Match &exact case طابÙÙ‚ &حالة الأحر٠Match &only whole words طابÙÙ‚ الكلمات الكاملة &ÙØ­Ø³Ø¨ When enabled, the search continues from the other end when it reaches one end of the page إن ÙØ¹Ù‘لته ÙØ³ÙŠÙواصل البحث من الطر٠التالي عندما يصل إلى نهاية Ø§Ù„ØµÙØ­Ø© &Wrap around البحث يلت&ÙÙ‘ When set, the search goes backwards from cursor position, otherwise it goes forward إن ÙØ¹Ù‘لته ÙØ³ÙŠØ¬Ø±ÙŠ Ø§Ù„Ø¨Ø­Ø« إلى خل٠مكان المؤشّر، وإلّا ÙØ¥Ù„Ù‰ أمامه Search &backwards ابحث لل&خل٠<html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> إن ÙØ¹Ù‘لته Ùلن يجري البحث على النمط Ø§Ù„Ù…ÙØ±Ø§Ø¯ إلّا ÙÙŠ التحديد الحالي. &Selection only الت&حديد Ùقط <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> إن ÙØ¹Ù‘لته ÙØ³ÙŠÙتعامل مع نمط البحث على أنّه تعبير يونكس نمطي. طالع <a href="https://en.wikibooks.org/wiki/Regular_Expressions">التعابير النمطية ÙÙŠ ويكي‌كتب (بالإنجليزية)</a>. Use regular e&xpressions استعمل الت&عابير النمطية Find the next occurrence from the cursor position and in the direction set by "Search backwards" ابحث عن الحدوث التالي من موقع المؤشّر حسب الاتجاه الذي حدّده â€Ø§Ù„بحث للخلÙ“ &Find Next ابحث عن ال&تالي F3 &Replace ا&ستبدل Highlight all the occurrences of the text in the page Ø£Ø¨Ø±ÙØ² كلّ الحدوثات ÙÙŠ نص Ø§Ù„ØµÙØ­Ø© F&ind All ابحث عن ال&كلّ Replace all the occurrences of the text in the page استبدل كلّ الحدوثات ÙÙŠ نص Ø§Ù„ØµÙØ­Ø© Replace &All اس&تبدل الكلّ The searched text was not found لم ÙŠÙØ¹Ø«Ø± على نص البحث The searched text was not found. لم ÙŠÙØ¹Ø«Ø± على نص البحث. The searched text was found one time. Ø¹ÙØ«Ø± على نص البحث مرّة واحدة. The searched text was found %1 times. Ø¹ÙØ«Ø± على نص البحث %L1 من المرّات. The searched text was replaced one time. Ø§Ø³ØªÙØ¨Ø¯Ù„ نص البحث مرّة واحدة. The searched text was replaced %1 times. Ø§Ø³ØªÙØ¨Ø¯Ù„ نص البحث %L1 من المرّات. ForeignKeyEditor &Reset &صÙّر Foreign key clauses (ON UPDATE, ON DELETE etc.) بنود Ø§Ù„Ù…ÙØ§ØªÙŠØ­ الأجنبية (ON UPDATEØŒ أو ON DELETEØŒ إلخ.) ImageViewer Image Viewer Reset the scaling to match the original size of the image. Set the scaling to match the size of the viewport. Print... اطبع... Open preview dialog for printing displayed image ÙŠÙØªØ­ مربّع حوار المعاينة لطباعة الصورة المعروضة Ctrl+P Ctrl+P ImportCsvDialog Import CSV file استيراد مل٠CSV Table na&me ا&سم الجدول &Column names in first line أسماء الأ&عمدة ÙÙŠ أوّل سطر Field &separator &ÙØ§ØµÙ„ الحقول , , ; ; Tab جدولات | | Other شيء آخر &Quote character محر٠الت&نصيص Other (printable) شيء آخر (مطبوع) Other (code) شيء آخر (كود) " " ' ' &Encoding ال&ترميز UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? أأقلّم الحقول؟ Separate tables Ø§ÙØµÙ„ الجداول Advanced متقدّم When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. عند استيراد قيمة ÙØ§Ø±ØºØ© من مل٠CSV إلى جدول موجود يحمل قيمة مبدئية لهذا العمود، ØªÙØ¶Ø§Ù تلك القيمة المبدئية. ÙØ¹Ù‘Ù„ هذا الخيار لإدراج قيمة ÙØ§Ø±ØºØ© عوضًا عن ذلك. Ignore default &values تجاهَل ال&قيم المبدئية Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. ÙØ¹Ù‘Ù„ هذا الخيار لإيقا٠الاستيراد عند محاولة استيراد قيمة ÙØ§Ø±ØºØ© ÙÙŠ عمود â€Ù„يس NULL“ ليس له قيمة مبدئية. Fail on missing values ÙŠÙØ´Ù„ الاستيراد إن كانت القيم ناقصة Disable data type detection عطّل اكتشا٠نوع البيانات Disable the automatic data type detection when creating a new table. عطّل الاكتشا٠الآلي لنوع البيانات عند إنشاء جدول جديد. Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. حين تستورد القيم إلى جدول موجود وله Ù…ÙØªØ§Ø­ أساسي أو قيود â€Ùريد“ أو Ùهرس â€Ùريد“، Ùهناك احتمال بحدوث تعارض. يتيح لك هذا الخيار تحديد الطريقة التي ستتّبعها البرمجيّة ÙÙŠ تلك الحالة. مبدئيًا تجهض البرمجيّة الاستيراد وترجع إلى ما كانت عليه قاعدة البيانات، ولكن يمكنك أيضًا تجاهل الصÙو٠المتعارضة وعدم استيرادها، أو حتّى استبدال الصÙÙ‘ الموجود ÙÙŠ الجدول كلّه. Abort import Ø£Ø¬Ù‡ÙØ¶ الاستيراد Ignore row تجاهَل الصÙÙ‘ Replace existing row استبدل الصÙÙ‘ الموجود Conflict strategy استراتيجيّة التعارضات Deselect All ألغ٠تحديد الكلّ Match Similar طابÙÙ‚ المتشابهات Select All حدّد الكلّ There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. هناك جدول Ø¨Ù†ÙØ³ الاسم â€%L1“ Ø¨Ø§Ù„ÙØ¹Ù„ ولا يمكن الاستيراد داخل أحد الجداول الموجودة إلّا إن تطابق عدد الأعمدة. There is already a table named '%1'. Do you want to import the data into it? هناك جدول Ø¨Ù†ÙØ³ الاسم â€%L1“ Ø¨Ø§Ù„ÙØ¹Ù„. أتريد استيراد البيانات داخله؟ Creating restore point failed: %1 ÙØ´Ù„ إنشاء نقطة استعادة: %L1 Creating the table failed: %1 ÙØ´Ù„ إنشاء الجدول: %L1 importing CSV يستورد CSV Could not prepare INSERT statement: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. أخذ استيراد المل٠â€%L1“ â€%L2 م‌ث. منها %L3 م‌ث على دالة الصÙÙ‘. Inserting row failed: %1 ÙØ´Ù„ إدراج الصÙÙ‘: %L1 MainWindow DB Browser for SQLite متصÙّح قواعد بيانات SQLite This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. هذه بنية قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø©. يمكنك سحب Ø¥ÙØ§Ø¯Ø§Øª SQL من صÙÙ‘ ÙÙŠ الكائن وإسقاطها ÙÙŠ التطبيقات الأخرى أو إلى سيرورة أخرى من â€Ù…تصÙّح قواعد بيانات SQLite“. Un/comment block of SQL code اجعل/لا تجعل كتلة كود SQL تعليقًا Un/comment block اجعل/لا تجعل الكتلة تعليقًا Comment or uncomment current line or selected block of code حوّل السطر الحالي (أو كتلة الكود المحدّدة) إلى تعليق، أو ألغ٠التحويل Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. اجعل الأسطر المحدّدة (أو الحالي Ùقط لو لم يكن هناك تحديد) تعليقًا، أو ألغ٠ذلك. يتغيّر تحويل كتلة الكود كاملةً حسب أوّل سطر Ùيها. Ctrl+/ Ctrl+/ Stop SQL execution أوقÙ٠تنÙيذ SQL Stop execution أوقÙ٠التنÙيذ Stop the currently running SQL script أوقÙ٠تنÙيذ سكربت SQL الذي يعمل حاليًا Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. تحذير: لا يمكن قراءة pragma هذه، ولهذا استÙنتجت هذه القيمة. قد تؤدّي كتابة pragma على تعويض Ø¥ÙØ§Ø¯Ø© LIKE Ù…ÙØ¹Ø§Ø¯ تعريÙها ÙˆÙّرها امتداد SQLite. toolBar1 شريط الأدوات1 Export one or more table(s) to a JSON file صدّر جدولًا أو أكثر إلى مل٠JSON Edit Database &Cell تحرير &خليّة قاعدة البيانات DB Sche&ma Ù…&خطّط قاعدة البيانات This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. هذه بنية قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø©. يمكنك سحب عدد من أسماء الكائنات من عمود â€Ø§Ù„اسم“ وإسقاطها ÙÙŠ محرّر SQL ويمكنك ضبط خصائص تلك الأسماء Ø§Ù„Ù…ÙØ³Ù‚طة مستعملًا قائمة السياق. سيساعد هذا ÙÙŠ كتابة Ø¥ÙØ§Ø¯Ø§Øª SQL. يمكنك سحب Ø¥ÙØ§Ø¯Ø§Øª SQL من عمود â€Ø§Ù„مخطّط“ وإسقاطها ÙÙŠ محرّر SQL أو ÙÙŠ أيّ تطبيق آخر. &Remote الب&عيد Execute current line Ù†Ùّذ السطر الحالي This button executes the SQL statement present in the current editor line ÙŠÙÙ†Ùّذ هذا الزر Ø¥ÙØ§Ø¯Ø© SQL الظاهرة ÙÙŠ سطر المحرّر الحالي Shift+F5 Shift+F5 Open an existing database file in read only mode Ø§ÙØªØ­ مل٠قاعدة بيانات موجود ÙÙŠ وضع القراءة Ùقط Opens the SQLCipher FAQ in a browser window ÙŠÙØªØ­ الأسئلة الشائعة عن SQLCipher ÙÙŠ Ù†Ø§ÙØ°Ø© المتصÙّح &File مل&Ù &Import ا&Ø³ØªÙˆØ±ÙØ¯ &Export &صدّر &Edit ت&حرير &View من&ظور &Help Ù…&ساعدة Too&ls Ø£&دوات DB Toolbar شريط قاعدة البيانات SQL &Log س&جلّ SQL Show S&QL submitted by اعرض SQL الذي Ù†&Ùّذه User المستخدم Application التطبيق Error Log سجلّ الأخطاء This button clears the contents of the SQL logs يمسح هذا الزر محتويات سجلّات SQL &Clear ا&مسح This panel lets you examine a log of all SQL commands issued by the application or by yourself تتيح لك هذه اللوحة ÙØ­Øµ كلّ أوامر SQL التي Ù†Ùّذها التطبيق أو المستخدم &Plot الر&سم البياني &New Database... قاعدة بيانات &جديدة... Create a new database file Ø£Ù†Ø´ÙØ¦ مل٠قاعدة بيانات جديد This option is used to create a new database file. ÙŠÙØ³ØªØ®Ø¯Ù… هذا الخيار لإنشاء مل٠قاعدة بيانات جديد. Ctrl+N Ctrl+N &Open Database... ا&ÙØªØ­ قاعدة بيانات... Open an existing database file Ø§ÙØªØ­ مل٠قاعدة بيانات موجود This option is used to open an existing database file. ÙŠÙØ³ØªØ®Ø¯Ù… هذا الخيار Ù„ÙØªØ­ مل٠قاعدة بيانات موجود. Ctrl+O Ctrl+O &Close Database Ø£&غلÙÙ‚ قاعدة البيانات This button closes the connection to the currently open database file ÙŠÙØºÙ„Ù‚ هذا الزر الاتصال بمل٠قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­ حاليًا Ctrl+W Ctrl+W &Revert Changes أرجÙ&ع التعديلات Revert database to last saved state Ø£Ø±Ø¬ÙØ¹ قاعدة البيانات إلى آخر حالة محÙوظة This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. ÙŠÙØ³ØªØ¹Ù…Ù„ هذا الخيار لإرجاع مل٠قاعدة البيانات إلى آخر حالة محÙوظة له. ستÙقد كلّ التعديلات عليه منذ آخر عملية Ø­ÙØ¸ أجريتها. &Write Changes ا&كتب التعديلات Write changes to the database file اكتب التعديلات ÙÙŠ مل٠قاعدة البيانات This option is used to save changes to the database file. ÙŠÙØ³ØªØ¹Ù…Ù„ هذا الخيار لكتابة التعديلات ÙÙŠ مل٠قاعدة البيانات. Ctrl+S Ctrl+S Compact &Database... Ø±ÙØµÙ‘ &قاعدة البيانات Compact the database file, removing space wasted by deleted records Ø±ÙØµÙ‘ مل٠قاعدة البيانات، Ù…ÙØ²ÙŠÙ„ًا المساحة الضائعة بسبب حذ٠السجلّات Compact the database file, removing space wasted by deleted records. Ø±ÙØµÙ‘ مل٠قاعدة البيانات، Ù…ÙØ²ÙŠÙ„ًا المساحة الضائعة بسبب حذ٠السجلّات. E&xit ا&خرج Ctrl+Q Ctrl+Q &Database from SQL file... &قاعدة بيانات من مل٠SQL... Import data from an .sql dump text file into a new or existing database. Ø§Ø³ØªÙˆØ±ÙØ¯ بيانات من مل٠‎.sql نصي Ù…ÙØ±Ù‘غ إلى قاعدة بيانات جديدة أو موجودة. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. يتيح لك هذا الخيار استيراد البيانات من مل٠‎.sql نصي Ù…ÙØ±Ù‘غ إلى قاعدة بيانات جديدة أو موجودة. يمكن إنشاء Ù…Ù„ÙØ§Øª SQL Ø§Ù„Ù…ÙØ±Ù‘غة ÙÙŠ أغلب محرّكات قواعد البيانات، بما Ùيها MySQL ÙˆPostgreSQL. &Table from CSV file... ج&دولًا من مل٠CSV... Open a wizard that lets you import data from a comma separated text file into a database table. Ø§ÙØªØ­ مرشدًا يساعدك ÙÙŠ استيراد البيانات من مل٠نصي مقسوم بÙواصل إلى جدول قاعدة البيانات. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Ø§ÙØªØ­ مرشدًا يساعدك ÙÙŠ استيراد البيانات من مل٠نصي مقسوم بÙواصل إلى جدول قاعدة البيانات. يمكن إنشاء Ù…Ù„ÙØ§Øª CSV ÙÙŠ أغلب تطبيقات قواعد البيانات والجداول الممتدّة. &Database to SQL file... &قاعدة بيانات إلى مل٠SQL... Export a database to a .sql dump text file. صدّر قاعدة بيانات إلى مل٠‎.sql نصي Ù…ÙØ±Ù‘غ. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. يتيح لك هذا الخيار تصدير قاعدة بيانات إلى مل٠‎.sql نصي Ù…ÙØ±Ù‘غ. يمكن Ù„Ù…Ù„ÙØ§Øª SQL Ø§Ù„Ù…ÙØ±Ù‘غة احتواء كلّ البيانات الضرورية لإعادة إنشاء قاعدة البيانات ÙÙŠ أغلب محرّكات قواعد البيانات، Ùما Ùيها MySQL ÙˆPostgreSQL. &Table(s) as CSV file... الج&داول كمل٠CSV... Export a database table as a comma separated text file. صدّر جدول قاعدة بيانات كمل٠نصي مقسوم بÙواصل. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. صدّر جدول قاعدة بيانات كمل٠نصي مقسوم بÙواصل، جاهز Ù„ÙŠÙØ³ØªÙˆØ±Ø¯ إلى تطبيقات قواعد البيانات أو الجداول الممتدّة الأخرى. &Create Table... Ø£&Ù†Ø´ÙØ¦ جدولًا... Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Ø§ÙØªØ­ مرشد إنشاء الجدول، حيث تستطيع تحديد اسم وحقول للجدول الجديد ÙÙŠ قاعدة البيانات &Delete Table... ا&حذ٠الجدول... Delete Table احذ٠الجدول Open the Delete Table wizard, where you can select a database table to be dropped. Ø§ÙØªØ­ مرشد حذ٠الجدول، حيث يمكنك تحديد جدول قاعدة البيانات الذي Ø³ÙŠÙØ­Ø°Ù. &Modify Table... &عدّل الجدول... Create &Index... Ø£Ù†Ø´ÙØ¦ &Ùهرسًا... Open the Create Index wizard, where it is possible to define a new index on an existing database table. Ø§ÙØªØ­ جدول إنشاء الÙهارس، حيث يمكنك تحديد Ùهرس جديد ÙÙŠ جدول قاعدة بيانات موجود. &Preferences... التÙ&ضيلات... Open the preferences window. Ø§ÙØªØ­ Ù†Ø§ÙØ°Ø© Ø§Ù„ØªÙØ¶ÙŠÙ„ات. &DB Toolbar شريط &قاعدة البيانات Shows or hides the Database toolbar. يعرض أو ÙŠÙØ®ÙÙŠ شريط قاعدة البيانات.. New &tab Ctrl+T Ctrl+T Open SQL file(s) Ø§ÙØªØ­ Ù…Ù„ÙØ§Øª SQL This button opens files containing SQL statements and loads them in new editor tabs ÙŠÙØªØ­ هذا الزر Ù…Ù„ÙØ§Øª تحتوي Ø¥ÙØ§Ø¯Ø§Øª SQL ويحمّلها ÙÙŠ ألسنة محرّر جديدة This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file يتيح لك هذا الزر Ø­ÙØ¸ كلّ الإعدادات المرتبطة بقاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© ÙÙŠ مل٠مشروع «متصÙّح قواعد بيانات SQLite» This button lets you open a DB Browser for SQLite project file يتيح لك هذا الزر ÙØªØ­ مل٠مشروع «متصÙّح قواعد بيانات SQLite» Browse Table تصÙّح الجدول W&hat's This? ما Ù‡&ذا؟ &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs E&xecute SQL This has to be equal to the tab title in all the main tabs &Recent Files &New Database Ctrl+F4 Ctrl+F4 &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Shift+F1 Shift+F1 Execute all/selected SQL Ù†Ùّذ كلّ Ø¥ÙØ§Ø¯Ø§Øª SQL أو المحدّدة Ùقط This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. ÙŠÙÙ†Ùّذ هذا الزر Ø¥ÙØ§Ø¯Ø§Øª SQL المحدّدة حاليًا. إن لم تحدّد شيئًا ÙØ³ØªÙÙ†Ùّذ كلّ Ø¥ÙØ§Ø¯Ø§Øª SQL. Ctrl+Shift+T &Load Extension... &حمّل امتدادًا... Execute line Ù†Ùّذ السطر &Wiki الوي&كي F1 Bug &Report... Ø£Ø¨Ù„ÙØº عن علّ&Ø©... Feature Re&quest... ا&طلب ميزة... Web&site موقع الو&ب &Donate on Patreon... تبرّع &عبر باتريون... &Save Project Open &Project... Ø§ÙØªØ­ Ù…&شروعًا... Open &Project &Attach Database... أر&ÙÙÙ‚ قاعدة بيانات... Add another database file to the current database connection أضÙ٠مل٠قاعدة بيانات آخر إلى اتصال قاعدة البيانات الحالي This button lets you add another database file to the current database connection يتيح لك هذا الزر Ø¥Ø¶Ø§ÙØ© مل٠قاعدة بيانات آخر إلى اتصال قاعدة البيانات الحالي &Set Encryption... ا&ضبط التعمية... SQLCipher &FAQ Ø£&سئلة شائعة عن SQLCipher Table(&s) to JSON... الج&دول/الجداول إلى JSON... Open Data&base Read Only... Ø§ÙØªØ­ قاع&دة بيانات للقراءة Ùقط... Ctrl+Shift+O Ctrl+Shift+O Save results Ø§Ø­ÙØ¸ النتائج Save the results view Ø§Ø­ÙØ¸ منظور النتائج This button lets you save the results of the last executed query يتيح لك هذا الزر Ø­ÙØ¸ نتائج آخر استعلام Ù†ÙÙّذ Find text in SQL editor ابحث عن النصوص ÙÙŠ محرّر SQL Find ابحث This button opens the search bar of the editor ÙŠÙØªØ­ هذا الزر شريط البحث للمحرّر Ctrl+F Ctrl+F Find or replace text in SQL editor ابحث أو استبدل النصوص ÙÙŠ محرّر SQL Find or replace ابحث أو استبدل This button opens the find/replace dialog for the current editor tab ÙŠÙØªØ­ هذا الزر مربّع حوار البحث والاستبدال للسان المحرّر الحالي Ctrl+H Ctrl+H Export to &CSV &صدّر بنسق CSV Export to &JSON Save as &view Ø§Ø­ÙØ¸ كمن&ظور Save as view Ø§Ø­ÙØ¸ كمنظور Shows or hides the Project toolbar. اعرض أو أخÙ٠شريط أدوات المشروع. Extra DB Toolbar شريط أدوات قواعد البيانات الإضاÙÙŠ &Open Database New In-&Memory Database قاعدة بيانات جديدة ÙÙŠ ال&ذاكرة Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Drag && Drop Qualified Names اسحب ÙˆØ£Ø³Ù‚ÙØ· الأسماء المؤهّلة Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor استخدم الأسماء المؤهّلة (مثل ‎"Table"."Field"‎) عند سحب الكائنات وإسقاطها ÙÙŠ المحرّر. Drag && Drop Enquoted Names اسحب ÙˆØ£Ø³Ù‚ÙØ· الأسماء مقتبسةً Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor استخدم Ø§Ù„Ù…ÙØ¹Ø±Ù‘ÙØ§Øª مهرّبة (مثلًا "Table1") عند سحب الكائنات وإسقاطها ÙÙŠ المحرّر &Integrity Check ÙØ­Øµ ال&سلامة Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. ÙŠÙØ´ØºÙ‘Ù„ integrity_check pragma على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© ÙˆÙŠÙØ¹ÙŠØ¯ النتائج ÙÙŠ لسان â€Ù†Ùّذ SQL“. ÙŠÙØ¬Ø±ÙŠ pragma ÙØ­Øµ سلامة على قاعدة البيانات كاملةً. &Foreign-Key Check ÙØ­Øµ الم&ÙØªØ§Ø­ الأجنبي Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab ÙŠÙØ´ØºÙ‘Ù„ foreign_key_check pragma على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© ÙˆÙŠÙØ¹ÙŠØ¯ النتائج ÙÙŠ لسان â€Ù†Ùّذ SQL“ &Quick Integrity Check ÙØ­Øµ سلام&Ø© سريع Run a quick integrity check over the open DB ÙŠÙØ´ØºÙ‘Ù„ ÙØ­Øµ سلامة سريع على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. ÙŠÙØ´ØºÙ‘Ù„ quick_check pragma على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© ÙˆÙŠÙØ¹ÙŠØ¯ النتائج ÙÙŠ لسان â€Ù†Ùّذ SQL“. ÙŠÙØ¬Ø±ÙŠ Ù‡Ø°Ø§ الأمر أغلب ما ØªÙØ¬Ø±ÙŠÙ‡ PRAGMA integrity_check إلّا أنّه أسرع. &Optimize Ø­&سّن Attempt to optimize the database حاوÙÙ„ تحسين قاعدة البيانات Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. ÙŠÙØ´ØºÙ‘Ù„ optimize pragma على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø©. قد تؤدّي pragma إلى إجراء بعض التحسينات لها أن ØªÙØ­Ø³Ù‘Ù† من أداء الاستعلامات مستقبلًا. Print اطبع Print text from current SQL editor tab اطبع النص من لسان محرّر SQL الحالي Open a dialog for printing the text in the current SQL editor tab Ø§ÙØªØ­ مربّع حوار طباعة النص ÙÙŠ لسان محرّر SQL الحالي Print the structure of the opened database اطبع بنية قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© Open a dialog for printing the structure of the opened database Ø§ÙØªØ­ مربّع حوار طباعة بنية قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© &Save Project As... احÙ&ظ المشروع ÙƒÙŽâ€... Save the project in a file selected in a dialog Ø§Ø­ÙØ¸ المشروع ÙÙŠ مل٠تحدّده من مربّع حوار Save A&ll Ø§Ø­ÙØ¸ ال&كلّ Save DB file, project file and opened SQL files Ø§Ø­ÙØ¸ مل٠قاعدة البيانات ومل٠المشروع ÙˆÙ…Ù„ÙØ§Øª SQL Ø§Ù„Ù…ÙØªÙˆØ­Ø© Ctrl+Shift+S Ctrl+Shift+S Close Pro&ject Close project and database files and return to the initial state Ctrl+Shift+W Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Refresh Ø£Ù†Ø¹ÙØ´ Reload the database structure Ctrl+Shift+F4 Detach Database Detach database file attached to the current database connection &Recently opened Ø§Ù„Ù…ÙØªÙˆØ­Ø© حدي&ثًا Project Toolbar شريط أدوات المشروع Extra DB toolbar شريط أدوات قواعد البيانات الإضاÙÙŠ Close the current database file أغلÙÙ‚ مل٠قاعدة البيانات الحالي &About &عن This button opens a new tab for the SQL editor ÙŠÙØªØ­ هذا الزر لسانًا جديدًا لمحرّر SQL &Execute SQL Ù†&Ùّذ SQL Save SQL file Ø§Ø­ÙØ¸ مل٠SQL Ctrl+E Ctrl+E Export as CSV file صدّر كمل٠بنسق CSV Export table as comma separated values file صدّر الجدول كمل٠نصي مقسوم بÙواصل Sa&ve Project احÙ&ظ المشروع Save the current session to a file Ø§Ø­ÙØ¸ الجلسة الحالية ÙÙŠ مل٠Load a working session from a file حمّل جلسة عمل من مل٠Save SQL file as Ø§Ø­ÙØ¸ مل٠SQL كَ†This button saves the content of the current SQL editor tab to a file ÙŠØ­ÙØ¸ هذا الزر محتويات لسان محرّر SQL الحالي ÙÙŠ مل٠&Browse Table ت&صÙّح الجدول Copy Create statement انسخ Ø¥ÙØ§Ø¯Ø© الإنشاء Copy the CREATE statement of the item to the clipboard انسخ Ø¥ÙØ§Ø¯Ø© CREATE للعنصر إلى Ø§Ù„Ø­Ø§ÙØ¸Ø© Ctrl+Return Ctrl+Return Ctrl+L Ctrl+L Ctrl+P Ctrl+P Ctrl+D Ctrl+D Ctrl+I Ctrl+I Encrypted معمّاة Database is encrypted using SQLCipher قاعدة البيانات معمّاة بامتداد SQLCipher Read only للقراءة Ùقط Database file is read only. Editing the database is disabled. مل٠قاعدة البيانات للقراءة Ùقط. تحرير قاعدة البيانات معطّل. Database encoding ترميز قاعدة البيانات Choose a database file اختر مل٠قاعدة بيانات Choose a filename to save under اختر اسمًا Ù„Ù„Ù…Ù„Ù Ù„Ø­ÙØ¸Ù‡ به Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 خطأ أثناء Ø­ÙØ¸ مل٠قاعدة البيانات. هذا يعني أنّه تعذّر Ø­ÙØ¸ كلّ التغييرات ÙÙŠ قاعدة البيانات. عليك حلّ الخطأ الآتي أوّلًا: %L1 Are you sure you want to undo all changes made to the database file '%1' since the last save? أمتأكّد من التراجع عن كلّ التعديلات التي أجريتها على مل٠قاعدة البيانات â€%L1“ منذ آخر Ø­ÙØ¸ØŸ Choose a file to import اختر ملÙًا لاستيراده Text files(*.sql *.txt);;All files(*) Ø§Ù„Ù…Ù„ÙØ§Øª النصية(*.sql *.txt);;كلّ Ø§Ù„Ù…Ù„ÙØ§Øª(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. أتريد إنشاء مل٠قاعدة بيانات جديد Ù„ÙŠØ­ØªÙØ¸ بالبيانات المستوردة؟ إن كانت إجابتك â€Ù„ا“ ÙØ³Ù†Ø­Ø§ÙˆÙ„ استيراد البيانات من مل٠SQL إلى قاعدة البيانات الحالية. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? ما زلت تنÙّذ Ø¥ÙØ§Ø¯Ø§Øª SQL. بإغلاق قاعدة البيانات الآن تكون Ø£ÙˆÙ‚ÙØª التنÙيذ وقد يترك ذلك قاعدة البيانات ÙÙŠ حال غير مستقرّة. أمتأكّد من إغلاق قاعدة البيانات؟ Do you want to save the changes made to the project file '%1'? أتريد Ø­ÙØ¸ التعديلات التي أجريتها ÙÙŠ مل٠المشروع â€%L1“؟ File %1 already exists. Please choose a different name. المل٠%L1 موجود Ø¨Ø§Ù„ÙØ¹Ù„. من ÙØ¶Ù„Ùƒ اختر اسمًا آخر. Error importing data: %1 خطأ أثناء استيراد البيانات: %L1 Import completed. اكتمل الاستيراد. Delete View احذ٠المنظور Modify View عدّل المنظور Delete Trigger احذ٠المحÙّز Modify Trigger عدّل المحÙّز Delete Index احذ٠الÙهرس Modify Index عدّل الÙهرس Modify Table عدّل الجدول Do you want to save the changes made to SQL tabs in a new project file? أتريد Ø­ÙØ¸ التعديلات التي أجريتها على ألسنة SQL ÙÙŠ مل٠مشروع جديد؟ Do you want to save the changes made to the SQL file %1? أتريد Ø­ÙØ¸ التعديلات التي أجريتها على مل٠SQL بالاسم â€%L1“؟ Could not find resource file: %1 تعذّر العثور على مل٠الموارد: %L1 Choose a project file to open اختر مل٠مشروع Ù„ÙØªØ­Ù‡ Could not open project file for writing. Reason: %1 تعذّر ÙØªØ­ مل٠المشروع للكتابة. السبب: %L1 Setting PRAGMA values will commit your current transaction. Are you sure? سيؤّدي ضبط قيم PRAGMA إلى إيداع المعاملة الحالية. أمتأكّد؟ Ctrl+Tab Ctrl+Shift+Tab Clear List Window Layout تخطيط Ø§Ù„Ù†Ø§ÙØ°Ø© Reset Window Layout صÙّر تخطيط Ø§Ù„Ù†Ø§ÙØ°Ø© Simplify Window Layout بسّط تخطيط Ø§Ù„Ù†Ø§ÙØ°Ø© Alt+Shift+0 Alt+Shift+0 Dock Windows at Bottom Ø§Ø±ØµÙ Ø§Ù„Ù†ÙˆØ§ÙØ° بالأسÙÙ„ Dock Windows at Left Side Ø§Ø±ØµÙ Ø§Ù„Ù†ÙˆØ§ÙØ° على اليسار Dock Windows at Top Ø§Ø±ØµÙ Ø§Ù„Ù†ÙˆØ§ÙØ° بالأعلى The database is currently busy. قاعدة البيانات مشغولة حاليًا. Click here to interrupt the currently running query. انقر هنا لمقاطعة الاستعلام الذي يعمل حاليًا. Ctrl+Alt+W Could not open database file. Reason: %1 تعذّر ÙØªØ­ مل٠قاعدة البيانات. السبب: %L1 In-Memory database قاعدة بيانات ÙÙŠ الذاكرة Choose a database file to save under Error while saving the database to the new file. Are you sure you want to delete the table '%1'? All data associated with the table will be lost. أمتأكّد من حذ٠الجدول â€%L1“؟ ستÙقد كلّ البيانات المرتبطة بالجدول. Are you sure you want to delete the view '%1'? أمتأكّد من حذ٠المنظور â€%L1“؟ Are you sure you want to delete the trigger '%1'? أمتأكّد من حذ٠المحÙّز â€%L1“؟ Are you sure you want to delete the index '%1'? أمتأكّد من حذ٠الÙهرس â€%L1“؟ Error: could not delete the table. خطأ: تعذّر حذ٠الجدول. Error: could not delete the view. خطأ: تعذّر حذ٠المنظور. Error: could not delete the trigger. خطأ: تعذّر حذ٠المحÙّز. Error: could not delete the index. خطأ: تعذّر حذ٠الÙهرس. Message from database engine: %1 الرسالة من محرّك قواعد البيانات: %L1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? تحرير الجدول يطلب Ø­ÙØ¸ كلّ التغييرات المرجأة الآن. أمتأكّد من Ø­ÙØ¸ قاعدة البيانات؟ Error checking foreign keys after table modification. The changes will be reverted. خطأ أثناء ÙØ­Øµ Ø§Ù„Ù…ÙØ§ØªÙŠØ­ الأجنبية بعد تعديل الجدول. Ø³ØªÙØ±Ø¬ÙŽØ¹ التغييرات. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. لم يمرّ الجدول ÙØ­Øµ Ø§Ù„Ù…ÙØªØ§Ø­ الأجنبي.<br/>عليك تشغيل â€Ø£Ø¯ÙˆØ§Øª -> ÙØ­Øµ Ø§Ù„Ù…ÙØªØ§Ø­ الأجنبي“ وإصلاح المشاكل المذكورة. Edit View %1 حرّر المنظور %L1 Edit Trigger %1 حرّر المحÙّز %L1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. أنت تنÙّذ حقًا Ø¥ÙØ§Ø¯Ø§Øª SQL. أتريد إيقاÙها لتنÙيذ Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª الحالية بدلها؟ وقد يترك ذلك قاعدة البيانات ÙÙŠ حال غير مستقرّة. -- EXECUTING SELECTION IN '%1' -- -- ينÙّذ التحديد ÙÙŠ â€%L1“ -- -- EXECUTING LINE IN '%1' -- -- ينÙّذ السطر ÙÙŠ â€%L1“ -- -- EXECUTING ALL IN '%1' -- -- ينÙّذ الكلّ ÙÙŠ â€%L1“ -- At line %1: عند السطر %L1: Result: %1 النتيجة: %L1 Result: %2 النتيجة: %L2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? سيؤّدي ضبط قيم PRAGMA أو التنظي٠إلى إيداع المعاملة الحالية. أمتأكّد؟ Opened '%1' in read-only mode from recent file list ÙÙØªØ­ â€%L1“ بوضع القراءة Ùقط من قائمة Ø§Ù„Ù…Ù„ÙØ§Øª Ø§Ù„Ù…ÙØªÙˆØ­Ø© حديثًا Opened '%1' from recent file list ÙÙØªØ­ â€%L1“ من قائمة Ø§Ù„Ù…Ù„ÙØ§Øª Ø§Ù„Ù…ÙØªÙˆØ­Ø© حديثًا &%1 %2%3 â€&%L1 â€â€Ž%L2‎â€%L3 (read only) (للقراءة Ùقط) Open Database or Project Ø§ÙØªØ­ قاعدة بيانات أو مشروع Attach Database... أرÙÙÙ‚ قاعدة بيانات... Import CSV file(s)... Ø§Ø³ØªÙˆØ±ÙØ¯ Ù…Ù„ÙØ§Øª CSV... Do you want to save the changes made to SQL tabs in the project file '%1'? أتريد Ø­ÙØ¸ التعديلات التي أجريتها على ألسنة SQL ÙÙŠ مل٠المشروع â€%L1“؟ The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? DB file '%1' could not be opened This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Table '%1' not found; settings ignored -- Reference to file "%1" (not supported by this version) -- Project saved to file '%1' Ø­ÙÙØ¸ المشروع ÙÙŠ المل٠â€%L1“ Yes. Don't ask again This action will open a new SQL tab with the following statements for you to edit and run: ÙŠÙØªØ­ هذا الإجراء لسان SQL جديد يحتوي Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª الآتية لتحرّرها وتنÙّذها: Busy (%1) مشغولة (%L1) Rename Tab غيّر اسم اللسان Duplicate Tab كرّر اللسان Close Tab أغلÙÙ‚ اللسان Opening '%1'... ÙŠÙØªØ­ â€%L1“... There was an error opening '%1'... خطأ أثناء ÙØªØ­ â€%L1“... Value is not a valid URL or filename: %1 القيمة ليست عنوانًا ولا اسم مل٠صالح: %L1 %1 rows returned in %2ms Ø£ÙØ¹ÙŠØ¯ من الصÙÙˆÙ %L1 خلال %L2 م‌ث Automatically load the last opened DB file at startup Ctrl+Alt+0 Choose text files اختر Ù…Ù„ÙØ§Øª نصية Import completed. Some foreign key constraints are violated. Please fix them before saving. اكتمل الاستيراد. انتÙهكت بعض قيود Ø§Ù„Ù…ÙØªØ§Ø­ الأجنبي. من ÙØ¶Ù„Ùƒ Ø£ØµÙ„ÙØ­Ù‡Ø§ قبل Ø§Ù„Ø­ÙØ¸. Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. اختر الإجراء الذي تريد تطبيقه على Ø§Ù„Ù…Ù„ÙØ§Øª التي Ø£Ùلتّها. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. اختر الإجراء الذي تريد تطبيقه على المل٠الذي Ø£Ùلتّه. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. اختر الإجراء الذي تريد تطبيقه على الملÙين الذين Ø£Ùلتّهما. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. اختر الإجراء الذي تريد تطبيقه على Ø§Ù„Ù…Ù„ÙØ§Øª التي Ø£Ùلتّها. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. اختر الإجراء الذي تريد تطبيقه على Ø§Ù„Ù…Ù„ÙØ§Øª التي Ø£Ùلتّها. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. اختر الإجراء الذي تريد تطبيقه على Ø§Ù„Ù…Ù„ÙØ§Øª التي Ø£Ùلتّها. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. Select SQL file to open اختر مل٠SQL Ù„ÙØªØ­Ù‡ Select file name اختر اسم المل٠Select extension file اختر مل٠الامتداد Extension successfully loaded. نجح تحميل الامتداد. Error loading extension: %1 خطأ أثناء تحميل الامتداد: %L1 Don't show again لا تعرض ثانيةً New version available. تتوÙّر إصدارة جديدة. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. تتوÙّر إصدارة جديدة من «متصÙّح قواعد بيانات SQLite» â€(%L1Ù«â€%L2Ù«â€%L3).<br/><br/>من ÙØ¶Ù„Ùƒ نزّلها من <a href='%4'>%L4</a>. Collation needed! Proceed? قواعد مقارنة المحار٠مطلوبة! أنتابع؟ A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! يحتاج أحد الجداول ÙÙŠ قاعدة البيانات هذه دالة قواعد مقارنة المحار٠Collation الخاصّة â€%L1“ والتي لا يستطيع البرنامج توÙيرها دون معلومات أخرى. احذر إن اخترت المتابعة، Ùقد تحدث أمور غير حسنة لقاعدة البيانات. Ø®ÙØ° نسخة احتياطيّة! creating collation ÙŠÙنشئ قواعد مقارنة المحار٠Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. ضع اسمًا جديدًا للسان SQL. استخدم محر٠â€&&“ Ù„ÙŠÙØªØ§Ø­ استخدام المحر٠الذي يليه كاختصار لوحة Ù…ÙØ§ØªÙŠØ­. Please specify the view name من ÙØ¶Ù„Ùƒ اختر اسم المنظور There is already an object with that name. Please choose a different name. هناك كائن Ø¨Ù†ÙØ³ الاسم. من ÙØ¶Ù„Ùƒ اختر اسمًا آخر. View successfully created. نجح إنشاء المنظور. Error creating view: %1 خطأ أثناء إنشاء المنظور: %L1 This action will open a new SQL tab for running: Ø³ÙŠÙØªØ­ هذا الإجراء لسان SQL جديد لتشغيل: Press Help for opening the corresponding SQLite reference page. انقر â€Ù…ساعدة“ Ù„ÙØªØ­ ØµÙØ­Ø© SQLite المرجعية المناسبة. DB Browser for SQLite project file (*.sqbpro) مل٠مشروع «متصÙّح قواعد بيانات SQLite» â€(*.sqbpro) Execution finished with errors. اكتمل التنÙيذ وحدثت أخطاء. Execution finished without errors. اكتمل التنÙيذ دون أخطاء. NullLineEdit Set to NULL اضبطه على NULL Alt+Del Alt+Del PlotDock Plot رسم بياني <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> تعرض هذه اللوحة قائمة الأعمدة للمجدول الذي تتصÙّحه حاليًا أو للاستعلام الذي Ù†ÙÙّذ حديثًا. يمكنك تحديد الأعمدة التي تريد استخدامها كمحاور س أو ص للوحة الرسم البياني أدناه. يعرض الجدول نوع المحور المكتش٠والذي سيؤثّر على الرسم البياني الناتج. يمكنك تحديد الأعمدة العددية Ùقط لمحور ص، عكس محور س حيث يمكنك تحديد:<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">تاريخ/وقت</span>: السلاسل النصية التي لها التنسيق â€yyyy-MM-dd hh:mm:ss“ أو â€yyyy-MM-ddThh:mm:ss“</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">تاريخ</span>: السلاسل النصية التي لها التنسيق â€yyyy-MM-dd“</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">وقت</span>: السلاسل النصّية التي لها التنسيق â€hh:mm:ss“</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">لصيقة</span>: السلاسل النصية التي لها تنسيقات أخرى. تحديد هذا العمود كمحور x سيÙنتج رسم بياني بأشرطة حيث قيم الأعمدة ستكون لصيقات للأشرطة</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">عدد</span>: قيم عددية صحيحة أو حقيقية</li></ul>بنقر خلايا ص مزدوجًا يمكنك تغيير اللون المستخدم لذلك الرسم. Columns الأعمدة X س Y1 ص1 Y2 ص2 Axis Type نوع المحور Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. هنا تجد الرسم البياني المرسوم عند تحديد قيم x Ùˆ y أعلاه. انقر النقاط لتحديدها ÙÙŠ الرسم البياني والجدول. انقر مع Ctrl لتحديد مدًى من النقاط. استخدم عجلة Ø§Ù„ÙØ£Ø±Ø© للتقريب والإبعاد، وحرّك Ø§Ù„ÙØ£Ø±Ø© لتغيير مدى المحور. اختر المحاور أو لصيقات المحاور لتحريكها أو قرّب/بعّد بذاك الاتجاه ÙØ­Ø³Ø¨. Line type: نوع الخطوط: None بلا Line خط StepLeft عتبة يسرى StepRight عتبة يمنى StepCenter عتبة وسطى Impulse نبض Point shape: شكل النقط: Cross علامة ضرب Plus علامة جمع Circle دائرة Disc قرص Square مربّع Diamond معيّن Star نجمة Triangle مثلّث TriangleInverted مثلّث مقلوب CrossSquare علامة ضرب ÙÙŠ مربّع PlusSquare علامة جمع ÙÙŠ مربّع CrossCircle علامة ضرب ÙÙŠ دائرة PlusCircle علامة جمع ÙÙŠ دائرة Peace رمز السلام <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <p>Ø§Ø­ÙØ¸ الرسم البياني الحالي...</p><p>نسق المل٠يحدّده الامتداد (png Ùˆjpg Ùˆpdf Ùˆbmp)</p> Save current plot... Ø§Ø­ÙØ¸ الرسم البياني الحالي... Load all data and redraw plot حمّل كلّ البيانات ÙˆØ£Ø¹ÙØ¯ رسم الرسم البياني Row # رقم الص٠Copy انسخ Print... اطبع... Show legend اعرض Ù…ÙØªØ§Ø­ الرسم Stacked bars أشرطة مرصوصة Fixed number format Date/Time تاريخ/وقت Date تاريخ Time وقت Numeric عدد Label لصيقة Invalid غير صالح Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. حمّل كلّ البيانات ÙˆØ£Ø¹ÙØ¯ رسم الرسم البياني. تحذير: لم ØªÙØ¬Ù„ب كلّ البيانات من الجدول بسبب استعمال آليّة جلب جزئية. Choose an axis color اختر لونًا للمحور Choose a filename to save under اختر اسمًا Ù„Ù„Ù…Ù„Ù Ù„Ø­ÙØ¸Ù‡ PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;كلّ Ø§Ù„Ù…Ù„ÙØ§Øª(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. توجد منحنيات ÙÙŠ هذا الرسم البياني ولا يمكن تطبيق نمط الخطوط المحدّد إلّا على الرسوم البيانية Ø§Ù„Ù…ÙØ±ÙˆØ²Ø© حسب س. إمّا أن ØªÙØ±Ø² الجدول أو الاستعلام حسب س لإزالة المنحنيات أو تحديد أحد الأنماط التي تدعمها المنحنيات: â€Ø¨Ù„ا“ أو â€Ø®Ø·â€œ. Loading all remaining data for this table took %1ms. أخذ تحميل كلّ البيانات الباقية لهذا الجدول %L1 م‎ث. PreferencesDialog Preferences Ø§Ù„ØªÙØ¶ÙŠÙ„ات &General &عام Remember last location تذكّر آخر مكان Always use this location استخدم هذا المكان دائمًا Remember last location for session only تذكّر آخر مكان لهذه الجلسة Ùقط ... ... Default &location الم&كان المبدئي Lan&guage الل&غة Automatic &updates الت&حديثات الآلية enabled Ù…ÙØ¹Ù‘لة Show remote options اعرض خيارات البعيد &Database &قاعدة البيانات Database &encoding &ترميز قاعدة البيانات Open databases with foreign keys enabled. Ø§ÙØªØ­ قواعد البيانات ÙˆØ§Ù„Ù…ÙØ§ØªÙŠØ­ الأجنبية Ù…ÙØ¹Ù‘لة. &Foreign keys الم&ÙØ§ØªÙŠØ­ الأجنبية Remove line breaks in schema &view أزÙÙ„ كاسرات الأسطر ÙÙŠ من&ظور المخطّط Prefetch block si&ze &حجم الكتلة لجلبها مسبقًا SQ&L to execute after opening database Ø¥&ÙØ§Ø¯Ø© SQL لتÙÙ†Ùّذ بعد ÙØªØ­ قاعدة البيانات Default field type نوع الحقول المبدئي Data &Browser مت&صÙّح البيانات Font الخط &Font ال&خط Content المحتوى Symbol limit in cell أقصى عدد من الرموز ÙÙŠ كلّ خليّة NULL NULL Regular العادية Binary البيانات الثنائيّة Background الخلÙية Filters المرشّحات Threshold for completion and calculation on selection عتبة إكمال النصوص والحساب Show images in cell اعرض الصور ÙÙŠ الخلايا Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. ÙØ¹Ù‘Ù„ هذا الخيار لعرض معاينة كائنات BLOB التي Ùيها بيانات صور داخل الخلايا. ولكن يمكن أن يؤثّر هذا على أداء متصÙّح البيانات. Escape character محر٠الهروب Delay time (&ms) وقت التأخير (&م‌ث) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. اضبط وقت انتظار قبل تطبيق قيمة المرشّح الجديدة. يمكن ضبطه إلى القيمة صÙÙØ± لتعطيل الانتظار. &SQL Ù…&حرّر SQL Context السياق Colour اللون Bold ثخين Italic مائل Underline مسطّر Keyword الكلمات Ø§Ù„Ù…ÙØªØ§Ø­ÙŠØ© Function الدوال Table الجداول Comment التعليقات Identifier Ø§Ù„Ù…Ø¹Ø±Ù‘ÙØ§Øª String السلاسل النصية Current line السطر الحالي SQL &editor font size حجم الخط ÙÙŠ Ù…&حرّر SQL Tab size حجم التبويبات SQL editor &font &خط محرّر SQL Error indicators مؤشّرات الأخطاء Hori&zontal tiling التراتب Ø£Ù&قيًا If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. إن ÙØ¹Ù‘لته ÙØ³ØªØ±Ù‰ محرّر أكواد SQL ومنظور جدول النتائج جنبًا إلى جنب بدلًا من أن يكونان Ùوق بعض. Code co&mpletion Ø¥&كمال الكود Toolbar style نمط شريط الأدوات Only display the icon اعرض الأيقونة ÙØ­Ø³Ø¨ Only display the text اعرض النص ÙØ­Ø³Ø¨ The text appears beside the icon يظهر النص بجانب الأيقونة The text appears under the icon يظهر النص أسÙÙ„ الأيقونة Follow the style اتبع النمط DB file extensions امتدادات Ù…Ù„ÙØ§Øª قواعد البيانات Manage Ø£Ø¯ÙØ± Main Window Ø§Ù„Ù†Ø§ÙØ°Ø© الرئيسية Database Structure بنية قاعدة البيانات Browse Data تصÙّح البيانات Execute SQL Ù†Ùّذ SQL Edit Database Cell حرّر خليّة قاعدة البيانات When this value is changed, all the other color preferences are also set to matching colors. ØªÙØ¶Ø¨Ø· كلّ ØªÙØ¶ÙŠÙ„ات الألوان الأخرى (متى تغيّر هذا الخيار) إلى الألوان Ø§Ù„Ù…ÙØ·Ø§Ø¨Ù‚Ø© للنمط. Follow the desktop style اتبع نمط سطح المكتب Dark style النمط الداكن Application style نمط البرمجيّة This sets the font size for all UI elements which do not have their own font size option. يضبط هذا حجم خط كلّ عناصر الواجهة التي لا تحدّد Ù„Ù†ÙØ³Ù‡Ø§ حجم خط. Font size حجم الخط Max Recent Files Prompt to save SQL tabs in new project file If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. إن ÙØ¹Ù‘لته ÙØ³ØªÙزال ÙƒØ§Ø³ÙØ±Ø§Øª الأسطر ÙÙŠ عمود â€Ø§Ù„مخطّط“ ÙÙŠ لسان â€Ø¨Ù†ÙŠØ© قاعدة البيانات“ كما والرصي٠والخرج المطبوع. Database structure font size حجم خط بنية قاعدة البيانات Font si&ze &حجم الخط This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. هذا أقصى عدد من العناصر المسموحة لإجراء مزايا الحساب الثقيلة من عدم ذلك. أي أقصى عدد من الصÙÙˆÙ ÙÙŠ الجدول Ù„ØªÙØ¹ÙŠÙ„ إكمال القيم حسب القيم الموجودة ÙÙŠ العمود. وأقصى عدد من الÙهارس ÙÙŠ التحديد لحساب المجموع والمتوسّط. يمكنك ضبطه على صÙÙØ± لتعطيل الميزة. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. هذا أقصى عدد من الصÙÙˆÙ ÙÙŠ كلّ جدول Ù„ØªÙØ¹ÙŠÙ„ إكمال القيمة حسب البيانات الحالية ÙÙŠ العمود. يمكن ضبطه على ØµÙØ± لتعطيل الإكمال. Field display عرض الحقول Light style Displayed &text ال&نص المعروض Formatted Click to set this color انقر لضبط هذا اللون Text color لون النص Background color لون الخلÙية Preview only (N/A) معاينة Ùقط (غير متوÙّر) Foreground الأمامية Selection background Selection foreground Highlight SQL &results font size حجم خط Ù†&تائج SQL Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. &Wrap lines Ù„Ù&ÙÙ‘ الأسطر Never أبدًا At word boundaries عند حدود الكلمات At character boundaries عند حدود المحار٠At whitespace boundaries عند حدود Ø§Ù„Ù…Ø³Ø§ÙØ§Øª &Quotes for identifiers &علامات التنصيص Ù„Ù„Ù…ÙØ¹Ø±Ù‘ÙØ§Øª Choose the quoting mechanism used by the application for identifiers in SQL code. اختر آليّة التنصيص التي سيستخدمها التطبيق Ù„Ù„Ù…ÙØ¹Ø±Ù‘ÙØ§Øª ÙÙŠ كود SQL. "Double quotes" - Standard SQL (recommended) "علامات تنصيص مزدوجة" - SQL القياسية (مستحسن) `Grave accents` - Traditional MySQL quotes `نبر الإطالة` - علامات اقتباس MySQL التقليدية [Square brackets] - Traditional MS SQL Server quotes [أقواس مربّعة] - علامات تنصيص خادوم SQL Ù„ÙÙ…Ø§ÙŠÙƒØ±ÙˆØ³ÙˆÙØª التقليدي Keywords in &UPPER CASE الكلمات Ø§Ù„Ù…ÙØªØ§Ø­ÙŠØ© &كبيرة الحالة When set, the SQL keywords are completed in UPPER CASE letters. إن ÙØ¹Ù‘لته ÙØ³ÙŠØ¬Ø±ÙŠ Ø¥ÙƒÙ…Ø§Ù„ كلمات SQL Ø§Ù„Ù…ÙØªØ§Ø­ÙŠÙ‘Ø© بالأحر٠وحالتها كبيرة. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background إن ÙØ¹Ù‘لته ÙØ³ØªÙبرز الأسطر ÙÙŠ كود SQL التي تسبّبت بأخطاء أثناء آخر تنÙيذ ÙˆØ³ÙŠÙØ´ÙŠØ± إطار النتائج إلى الخطأ ÙÙŠ الخلÙية Close button on tabs أزرار إغلاق على الألسنة If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. إن ÙØ¹Ù‘لته ÙØ³ØªØ¹Ø±Ø¶ ألسنة محرّر SQL زرّ إغلاق. وبغضّ النظر عن هذا الخيار، يمكنك استعمال قائمة السياق أو اختصار لوحة Ø§Ù„Ù…ÙØ§ØªÙŠØ­ لإغلاق تلك الألسنة. &Extensions الامت&دادات Select extensions to load for every database: حدّد الامتدادات Ù„ØªÙØ­Ù…ّل لكلّ قاعدة بيانات: Add extension أضÙ٠امتدادًا Remove extension أزÙÙ„ الامتداد Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> مع أنّ معامل REGEX مدعوم، إلّا أنّ SQLITE ليس Ùيها أية خوارزمية تعابير نمطية Ù…Ùنجزة،<br/>بل تنادي التطبيق الجاري. ينÙّذ «متصÙّح قواعد بيانات SQLite» هذه الخوارزمية لك<br/>لتستعمل REGEXP دون عناء. مع ذلك، يختل٠تنÙيذ هذه الميزة ولربّما تحتاج استعمال<br/>واحدة أخرى، لذا ÙØ£Ù†Øª حرّ ÙÙŠ تعطيل طريقة التطبيق ÙÙŠ التنÙيذ وتحميل أيّ من تلك باستعمال<br/>إحدى الامتدادات. إعادة تشغيل التطبيق مطلوبة. Disable Regular Expression extension عطّل ملحقة العبارات النمطية <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> توÙّر SQLite دالة SQL لتحميل الامتدادات من مل٠مكتبة مشتركة. ÙØ¹Ù‘Ù„ هذا إن أردت استعمال دالة <span style=" font-style:italic;">load_extension()‎</span> من كود SQL.</p><p>لأسباب أمنية، تحميل الامتداد معطّل مبدئيًا ويجب ØªÙØ¹ÙŠÙ„Ù‡ بهذا الإعداد. يمكنك دائمًا تحميل الامتدادات عبر الواجهة الرسومية، حتى لو كان هذا الخيار معطّلًا. Allow loading extensions from SQL code اسمح بتحميل الامتدادات من كود SQL Remote البعيد CA certificates شهادات سلطة الشهادات Proxy الوسيط Configure اضبط Export Settings Import Settings Subject CN اش موضوع التعمية Common Name الاسم الشائع Subject O المنظّمة موضوع التعمية Organization المنظّمة Valid from صالحة من Valid to صالحة حتى Serial number الرقم التسلسلي Your certificates شهاداتك File المل٠Subject Common Name الاسم الشائع لموضوع التعمية Issuer CN اش Ø§Ù„Ù…ÙØµØ¯Ùر Issuer Common Name الاسم الشائع Ù„Ù„Ù…ÙØµØ¯Ùر Clone databases into استنسخ قواعد البيانات إلى Choose a directory اختر دليلًا The language will change after you restart the application. ستتغيّر اللغة بعد إعادة تشغيل التطبيق. Select extension file اختر مل٠الامتداد Extensions(*.so *.dylib *.dll);;All files(*) الامتدادات(*.so *.dylib *.dll);;كلّ Ø§Ù„Ù…Ù„ÙØ§Øª(*) Import certificate file Ø§Ø³ØªÙˆØ±ÙØ¯ مل٠شهادة No certificates found in this file. لم ØªÙØ¹Ø«Ø± على شهادات ÙÙŠ هذا الملÙ. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! أمتأكّد من إزالة هذه الشهادة؟ Ø³ØªÙØ­Ø°Ù كلّ بيانات الشهادة من إعدادات التطبيق! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. أمتأكّد من مسح كلّ الإعدادات المحÙوظة؟ ستÙقد كلّ Ø§Ù„ØªÙØ¶ÙŠÙ„ات لديك ÙˆØ³ØªÙØ³ØªØ¹Ù…Ù„ القيم المبدئية. Save Settings File Initialization File (*.ini) The settings file has been saved in location : Open Settings File The settings file was loaded properly. The selected settings file is not a normal settings file. Please check again. ProxyDialog Proxy Configuration ضبط الوسيط Pro&xy Type &نوع الوسيط Host Na&me ا&سم Ø§Ù„Ù…ÙØ¶ÙŠÙ Port Ø§Ù„Ù…Ù†ÙØ° Authentication Re&quired الاستيثاق Ù…&طلوب &User Name اسم المست&خدم Password كلمة السر None بلا وسيط System settings إعدادات النظام HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data خطأ ÙÙŠ استيراد البيانات from record number %1 من السجلّ رقم %L1 . %1 . %L1 Importing CSV file... يستورد مل٠CSV... Cancel ألغ٠All files (*) كلّ Ø§Ù„Ù…Ù„ÙØ§Øª (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Ù…Ù„ÙØ§Øª قواعد بيانات SQLite â€(*.db *.sqlite *.sqlite3 *.db3) Left يسار Right يمين Center وسط Justify ضبط SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) Ù…Ù„ÙØ§Øª قواعد بيانات SQLite â€(*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) Ù…Ù„ÙØ§Øª مشاريع «متصÙّح قواعد بيانات SQLite» â€(*.sqbpro) SQL Files (*.sql) Ù…Ù„ÙØ§Øª SQL â€(*.sql) All Files (*) كلّ Ø§Ù„Ù…Ù„ÙØ§Øª (*) Text Files (*.txt) Ù…Ù„ÙØ§Øª النصوص (*.txt) Comma-Separated Values Files (*.csv) Ù…Ù„ÙØ§Øª القيم المقسومة بÙواصل (*.csv) Tab-Separated Values Files (*.tsv) Ù…Ù„ÙØ§Øª القيم المقسومة بجدولات (*.tsv) Delimiter-Separated Values Files (*.dsv) Ù…Ù„ÙØ§Øª القيم المقسومة Ø¨Ø­Ø±ÙˆÙ ÙØµÙ„ (*.dsv) Concordance DAT files (*.dat) â€Concordance DAT files â€(*.dat) JSON Files (*.json *.js) Ù…Ù„ÙØ§Øª JSON â€(*.json *.js) XML Files (*.xml) Ù…Ù„ÙØ§Øª XML â€(*.xml) Binary Files (*.bin *.dat) Ø§Ù„Ù…Ù„ÙØ§Øª الثنائيّة (*.bin *.dat) SVG Files (*.svg) Ù…Ù„ÙØ§Øª SVG â€(*.svg) Hex Dump Files (*.dat *.bin) Ù…Ù„ÙØ§Øª ستّ‌عشرية Ù…ÙØ±Ù‘غة (*.dat *.bin) Extensions (*.so *.dylib *.dll) الامتدادات (*.so *.dylib *.dll) Initialization File (*.ini) QsciCommand Paste ألصÙÙ‚ Cancel ألغ٠QsciLexerCPP Default المبدئي Keyword الكلمات Ø§Ù„Ù…ÙØªØ§Ø­ÙŠØ© Identifier Ø§Ù„Ù…Ø¹Ø±Ù‘ÙØ§Øª QsciLexerJSON Default المبدئي String السلاسل النصية QsciLexerJavaScript Regular expression تعبير نمطي QsciLexerPython Default المبدئي Comment التعليقات Keyword الكلمات Ø§Ù„Ù…ÙØªØ§Ø­ÙŠØ© Identifier Ø§Ù„Ù…Ø¹Ø±Ù‘ÙØ§Øª QsciLexerSQL Default المبدئي Comment التعليقات Keyword الكلمات Ø§Ù„Ù…ÙØªØ§Ø­ÙŠØ© Identifier Ø§Ù„Ù…Ø¹Ø±Ù‘ÙØ§Øª QsciScintilla Select All حدّد الكلّ RemoteCommitsModel Commit ID معرّ٠الإيداع Message الرسالة Date التاريخ Author المؤلّ٠Size الحجم Authored and committed by %1 ألّÙÙ‡ وأودعه: %L1 Authored by %1, committed by %2 ألّÙÙ‡ %L1ØŒ وأودعه %L2 RemoteDatabase Error opening local databases list. %1 خطأ أثناء ÙØªØ­ قائمة قواعد البيانات المحليّة. %L1 Error creating local databases list. %1 خطأ أثناء إنشاء قائمة قواعد البيانات المحليّة. %L1 RemoteDock Remote البعيد Identity الهويّة Push currently opened database to server Ø§Ø¯ÙØ¹ قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© حاليًا إلى الخادوم Upload DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html dir="rtl"> <p>يمكنك ÙÙŠ هذه اللوحة Ø¥Ø¶Ø§ÙØ© قواعد البيانات البعيدة من موقع dbhub.io إلى «متصÙّح قواعد بيانات SQLite». تحتاج أولًا إلى هويّة:</p> <ol> <li>Ù„ÙØ¬ إلى موقع dbhub.io (استعمل معلومات ولوج ØºÙØªâ€ŒÙ‡ÙŽØ¨ أو غيرها، كما ترغب)</li> <li>انقر الزر â€Ù„توليد شهادة العميل“ (وهذه هي الهويّة). هكذا تحصل على مل٠شهادة ØªØ­ÙØ¸Ù‡ على القرص المحلي لديك.</li> <li>انتقل إلى لسان â€Ø§Ù„بعيد“ ÙÙŠ ØªÙØ¶ÙŠÙ„ات «متصÙّح قواعد بيانات SQLite». انقر الزر Ù„Ø¥Ø¶Ø§ÙØ© شهادة جديدة إلى التطبيق واختر مل٠الشهادة الذي نزّلته للتو.</li> </ol> <p>سترى الآن ÙÙŠ لوحة â€Ø§Ù„بعيد“ هويّتك ويمكنك Ø¥Ø¶Ø§ÙØ© قواعد البيانات لتصير بعيدة.</p> </html> Local المحلي Current Database قاعدة البيانات الحالية Clone استنسخ Branch Ø§Ù„ÙØ±Ø¹ Commits الإيداعات Commits for إيداعات Ø§Ù„ÙØ±Ø¹ Delete Database احذ٠قاعدة البيانات Delete the local clone of this database احذ٠النسخة المحلية من قاعدة البيانات هذه Open in Web Browser Ø§ÙØªØ­ ÙÙŠ متصÙّح Ø§Ù„ÙˆÙØ¨ Open the web page for the current database in your browser Ø§ÙØªØ­ ØµÙØ­Ø© Ø§Ù„ÙˆÙØ¨ لقاعدة البيانات الحالية ÙÙŠ المتصÙّح لديك Clone from Link استنسخ من رابط Use this to download a remote database for local editing using a URL as provided on the web page of the database. استعمل هذا لتنزيل قاعدة بيانات بعيدة للتعديل عليها محليًا باستعمال المسار الموجود ÙÙŠ ØµÙØ­Ø© Ø§Ù„ÙˆÙØ¨ لقاعدة البيانات تلك. Refresh Ø£Ù†Ø¹ÙØ´ Reload all data and update the views Ø£Ø¹ÙØ¯ تحميل كلّ البيانات وحدّث المناظير Clone Database استنسخ قاعدة بيانات Open Database Ø§ÙØªØ­ قاعدة بيانات Open the local copy of this database Ø§ÙØªØ­ النسخة المحلية من قاعدة البيانات هذه Check out Commit اسحب الإيداع (Check out) Download and open this specific commit نزّل هذا الإيداع بعينه ÙˆØ§ÙØªØ­Ù‡ Check out Latest Commit اسحب الإيداع الأخير (Check out) Check out the latest commit of the current branch اسحب الإيداع الأخير (Check out) ÙÙŠ Ø§Ù„ÙØ±Ø¹ الحالي Save Revision to File Ø§Ø­ÙØ¸ المراجعة ÙÙŠ مل٠Saves the selected revision of the database to another file ÙŠØ­ÙØ¸ المراجعة المحدّدة لقاعدة البيانات ÙÙŠ مل٠آخر Upload Database Ø§Ø±ÙØ¹ قاعدة البيانات Upload this database as a new commit ÙŠØ±ÙØ¹ قاعدة البيانات هذه كإيداع جديد <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> تستعمل حاليًا هويّة مضمّنة ÙÙŠ البرمجيّة وللقراءة Ùقط. لو أردت Ø±ÙØ¹ قاعدة البيانات ÙØ¹Ù„يك ضبط حسابك على DBHub.io واستعماله.<br/>أليس لديك واحد بعد؟ <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Ø£Ù†Ø´ÙØ¦Ù‡ الآن</span></a> ÙˆØ§Ø³ØªÙˆØ±ÙØ¯ الشهادة <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">هنا</span></a> Ù„ØªÙØ´Ø§Ø±Ùƒ قواعد بياناتك.<br/>Ø²ÙØ± <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">الموقع</span></a> للمساعدة ÙˆØ§Ù„ØªÙØ§ØµÙŠÙ„. &User &Database &قاعدة البيانات Back Ø¹ÙØ¯ Select an identity to connect اختر هويّة للاتصال Public عامّة This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. بهذا تÙنزّل قاعدة بيانات من خادوم بعيد للتعديل عليها محليًا. من ÙØ¶Ù„Ùƒ أدخÙÙ„ المسار الذي ستستنسخ القاعدة منه. يمكنك توليده بنقر â€Ø§Ø³ØªÙ†Ø³Ø® قاعدة البيانات ÙÙŠ DB4S“ ÙÙŠ ØµÙØ­Ø© Ø§Ù„ÙˆÙØ¨ لقاعدة البيانات التي تريد. Invalid URL: The host name does not match the host name of the current identity. مسار غير صالح: لا يتطابق اسم المضي٠مع اسم مضي٠الهويّة الحالية. Invalid URL: No branch name specified. مسار غير صالح: لم تحدّد اسم Ø§Ù„ÙØ±Ø¹. Invalid URL: No commit ID specified. مسار غير صالح: لم تحدّد معرّ٠الإيداع. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? عدّلت النسخة المحلية من قاعدة البيانات. بجلب الإيداع ÙØ£Ù†Øª تÙلغي هذه التعديلات المحلية. أمتأكّد من المواصلة؟ The database has unsaved changes. Are you sure you want to push it before saving? ÙÙŠ قاعدة البيانات تعديلات غير محÙوظة. أمتأكّد من Ø¯ÙØ¹ القاعدة قبل Ø­ÙØ¸ التعديلات؟ The database you are trying to delete is currently opened. Please close it before deleting. قاعدة البيانات التي تحاول حذÙها Ù…ÙØªÙˆØ­Ø© حاليًا. من ÙØ¶Ù„Ùƒ أغلÙقها قبل حذÙها. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? بهذا تحذ٠النسخة المحلية من قاعدة البيانات هذه مع كلّ التعديلات التي لم تودعها بعد. أمتأكّد من حذ٠قاعدة البيانات هذه؟ RemoteLocalFilesModel Name الاسم Branch Ø§Ù„ÙØ±Ø¹ Last modified آخر تعديل Size الحجم Commit الإيداع File المل٠RemoteModel Name الاسم Commit الإيداع Last modified آخر تعديل Size الحجم Size: الحجم: Last Modified: آخر تعديل: Licence: الرخصة: Default Branch: Ø§Ù„ÙØ±Ø¹ المبدئي: RemoteNetwork Choose a location to save the file اختر مكانًا Ù„Ø­ÙØ¸ المل٠Ùيه Error opening remote file at %1. %2 خطأ أثناء ÙØªØ­ المل٠البعيد ÙÙŠ %L1. %L2 Error: Invalid client certificate specified. خطأ: Ø­ÙØ¯Ù‘دت شهادة عميل غير صالحة. Please enter the passphrase for this client certificate in order to authenticate. من ÙØ¶Ù„Ùƒ أدخÙÙ„ عبارة السر لشهادة العميل لإجراء الاستيثاق. Cancel ألغ٠Uploading remote database to %1 ÙŠØ±ÙØ¹ قاعدة البيانات البعيدة إلى %L1 Downloading remote database from %1 ينزّل قاعدة البيانات البعيدة من %L1 Error: Cannot open the file for sending. خطأ: تعذّر ÙØªØ­ المل٠لإرساله. RemotePushDialog Push database Ø¯ÙØ¹ قاعدة البيانات Database na&me to push to ا&سم قاعدة البيانات الذي Ø³ÙŠÙØ¯Ùع إليها Commit message رسالة الإيداع Database licence رخصة قاعدة البيانات Public عامّة Branch Ø§Ù„ÙØ±Ø¹ Force push Ø£Ø¬Ø¨ÙØ± Ø§Ù„Ø¯ÙØ¹ Username اسم المستخدم Database will be public. Everyone has read access to it. ستكون قاعدة البيانات عامّة. يملك الجميع تصريح القراءة منها. Database will be private. Only you have access to it. ستكون قاعدة البيانات خاصّة. أنت من لديك حقّ الوصول إليها لا غير. Use with care. This can cause remote commits to be deleted. استعمله بحذر. يمكن أن يتسبّب هذا بحذ٠الإيداعات البعيدة. RunSql Execution aborted by user أجهض المستخدم التنÙيذ , %1 rows affected ØŒ عدد الصÙو٠المتأثّرة هو %L1 query executed successfully. Took %1ms%2 Ù†ÙÙّذ الاستعلام بنجاح: أخذ %L1 م‌ث%L2 executing query ينÙّذ الاستعلام SelectItemsPopup A&vailable ال&Ù…ÙØªØ§Ø­ Sele&cted الم&حدّد SqlExecutionArea Form استمارة Find previous match [Shift+F3] ابحث عن المطابقة السابقة [Shift+F3] Find previous match with wrapping ابحث عن المطابقة السابقة مع Ø§Ù„Ø§Ù„ØªÙØ§Ù Shift+F3 Shift+F3 The found pattern must be a whole word يجب أن يكون النمط محور البحث كلمة كاملة Whole Words الكلمات الكاملة Text pattern to find considering the checks in this frame النمط محور البحث بأخذ Ø§Ù„ÙØ­ÙˆØµ ÙÙŠ هذا الإطار بعين الاعتبار Find in editor ابحث ÙÙŠ المحرّر The found pattern must match in letter case يجب أن يطابق النمط محور البحث حالة الأحر٠Case Sensitive حسّاس لحالة الأحر٠Find next match [Enter, F3] ابحث عن المطابقة التالية [Enter, F3] Find next match with wrapping ابحث عن المطابقة التالية مع Ø§Ù„Ø§Ù„ØªÙØ§Ù F3 Interpret search pattern as a regular expression تعامَل مع نمط البحث كتعبير نمطي <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> إن ÙØ¹Ù‘لته ÙØ³ØªØªØ¹Ø§Ù…Ù„ البرمجيّة مع نمط البحث على أنّه تعبير يونكس نمطي. Ø·Ø§Ù„ÙØ¹ <a href="https://en.wikibooks.org/wiki/Regular_Expressions">التعابير النمطية ÙÙŠ ويكي‌كتب (بالإنجليزية)</a>. Regular Expression تعبير نمطي Close Find Bar أغلÙÙ‚ شريط البحث <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> نتائج آخر Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª المنÙّذة.<br/>يمكنك طيّ هذه اللوحة واستعمال لوحة <span style=" font-style:italic;">سجلّ SQL</span> باختيار <span style=" font-style:italic;">المستخدم</span> بدل هذا. Results of the last executed statements نتائج آخر Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª المنÙّذة This field shows the results and status codes of the last executed statements. يعرض هذا الحقل نتائج ورموز حالة آخر Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª المنÙّذة. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Couldn't save file: %1. تعذّر Ø­ÙØ¸ الملÙ: %L1. Your changes will be lost when reloading it! ستÙقد تغييراتك لو ÙØ¹Ù„ت! The file "%1" was modified by another program. Do you want to reload it?%2 عدّل برنامج آخر الملÙÙ‘ â€%L1“. أتريد إعادة تحميله؟%L2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. SqlTextEdit Ctrl+/ Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة abs(X) القيمة Ø§Ù„Ù…ÙØ·Ù„قة للمعطى العددي X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. ‎() â€«ØªÙØ¹ÙŠØ¯ الدالة changes()‎ عدد الصÙÙˆÙ ÙÙŠ قاعدة البيانات التي تغيّرت أو Ø£ÙØ¯Ø±Ø¬Øª أو Ø­ÙØ°Ùت باستخدام أحدث Ø¥ÙØ§Ø¯Ø© INSERT أو DELETE أو UPDATE Ø£ÙØ¬Ø±ÙŠØª بنجاح. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) â€«ØªÙØ¹ÙŠØ¯ الدالة char(X1,X2,...,XN) سلسلة نصية Ù…Ø¤Ù„Ù‘ÙØ© من محارÙÙŽ قيم٠نقاط رموزها اليونيكودية هي الأعداد الصحيحة بدءًا من X1 وحتّى XN بالترتيب. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) â€«ØªÙØ¹ÙŠØ¯ الدالة coalesce()‎ نسخة من أوّل معطًى ليس NULØŒ أو NULL إن كانت كلّ المعطيات تساوي NULL. (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) ‫الدالة glob(X,Y) تعادل التعبير â€Y GLOB X“. (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) ØªÙØ¹ÙŠØ¯ الدالة‫ ifnull()‎ نسخة من أوّل معطًى ليس NULØŒ أو NULL إن كان ÙƒÙلا المعطيين يساويان NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) ‫تبحث الدالة instr(X,Y) عن أوّل حدوث للسلسلة النصية Y داخل السلسلة النصية X ÙˆØªÙØ¹ÙŠØ¯ عدد المحار٠قبلها زائدًا Ù¡ØŒ أو ØªÙØ¹ÙŠØ¯ القيمة صÙÙØ± إن لم توجد Y ÙÙŠ أيّ مكان ÙÙŠ X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) â€«ØªÙØ³Ù‘ر الدالة hex()‎ المطى على أنّه BLOB ÙˆØªÙØ¹ÙŠØ¯ سلسلة نصية تمثّل عرضًا ستّ‌عشري بحالة أحر٠كبيرة لمحتوى كائن BLOB ذاك. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. ‎() â€«ØªÙØ¹ÙŠØ¯ الدالة last_insert_rowid()‎ معرّ٠الصÙ/ROWID لآخر عملية إدراج صÙÙ‘ من اتصال قاعدة البيانات والتي Ù†Ùّذت الدالة. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) ‫باعتبار X سلسلة نصية، ØªÙØ¹ÙŠØ¯ الدالة length(X) عدد المحار٠(وليس البايتات) داخل X والموجودة قبل أوّل محر٠NUL Ùيها. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) ØªÙØ³ØªØ¹Ù…Ù„ الدالة‫ like()‎ لتنÙيذ التعبير â€Y LIKE X“. (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) ØªÙØ³ØªØ¹Ù…Ù„ الدالة‫ like()‎ لتنÙيذ التعبير â€Y LIKE X ESCAPE Z“. (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) â€«ØªÙØ­Ù…ّل الدالة load_extension(X) امتدادات SQLite من مل٠مكتبة مشتركة اسمه X. عليك السماح باستعمال هذه الدالة من Ø§Ù„ØªÙØ¶ÙŠÙ„ات. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) â€«ØªÙØ­Ù…ّل الدالة load_extension(X) امتدادات SQLite من مل٠مكتبة مشتركة اسمه X باستخدام نقطة الإدخال Y. عليك السماح باستعمال هذه الدالة من Ø§Ù„ØªÙØ¶ÙŠÙ„ات. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة lower(X) نسخة من السلسلة النصية X حيث محار٠آسكي كلّها محوّلة إلى حالة الأحر٠الصغيرة. (X) ltrim(X) removes spaces from the left side of X. (X) â€«ØªÙØ²ÙŠÙ„ ltrim(X) Ø§Ù„Ù…Ø³Ø§ÙØ§Øª من الجانب الأيسر للسلسلة النصية X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة ltrim(X,Y) سلسلة نصية بإزالة كلّ المحار٠التي قد تظهر ÙÙŠ Y من الجانب الأيسر للسلسلة X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) â€«ØªÙØ¹ÙŠØ¯ الدالة متعدّدة المعطيات max()‎ المعطى الذي له أكبر قيمة، أو NULL إن كان أحد المعطيات هو NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) â€«ØªÙØ¹ÙŠØ¯ الدالة متعدّدة المعطيات min()‎ المعطى الذي له أصغر قيمة. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة nullif(X,Y) أوّل معطًى إن كانت المعطيات Ù…Ø®ØªÙ„ÙØ©ØŒ ÙˆØªÙØ¹ÙŠØ¯ NULL إن كانت المعطيات متطابقة. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) ‫تعمل دالة SQL هذه printf(FORMAT,...) تمامًا مثل دالة لغة سي sqlite3_mprintf()‎ ودالة printf()‎ من مكتبة سي القياسية. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة quote(X) نص SQL حرÙيّ تكون قيمة معامله مناسبة لتوضع ÙÙŠ عبارة SQL. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. ‎() â€«ØªÙØ¹ÙŠØ¯ الدالة random()‎ عددًا صحيحًا عشوائيًا زائÙًا بين -٩٢٢٣٣٧٢٠٣٦٨٥٤٧٧٥٨٠٨ Ùˆ +٩٢٢٣٣٧٢٠٣٦٨٥٤٧٧٥٨٠٧. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) â€«ØªÙØ¹ÙŠØ¯ الدالة randomblob(N) كائن BLOB بحجم N بايت يحتوي على بايتات عشوائية Ø²Ø§Ø¦ÙØ©. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) â€«ØªÙØ¹ÙŠØ¯ الدالة replace(X,Y,Z) سلسلة نصية باستبدال كلّ ظهور للسلسة النصية Y ÙÙŠ السلسلة النصية X بالسلسلة النصية Z. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) ØªÙØ¹ÙŠØ¯ الدالة‫ round(X) قيمة X عشرية عائمة Ù…Ùقرّبة إلى خانات الصÙÙØ± يمين Ø§Ù„ÙØ§ØµÙ„Ø© العشرية. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) ØªÙØ¹ÙŠØ¯ الدالة‫ round(X,Y) قيمة X عشرية عائمة Ù…Ùقرّبة إلى خانات Y يمين Ø§Ù„ÙØ§ØµÙ„Ø© العشرية. (X) rtrim(X) removes spaces from the right side of X. (X) â€«ØªÙØ²ÙŠÙ„ rtrim(X) Ø§Ù„Ù…Ø³Ø§ÙØ§Øª من الجانب الأيمن للسلسلة النصية X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة rtrim(X,Y) سلسلة نصية بإزالة كلّ المحار٠التي قد تظهر ÙÙŠ Y من الجانب الأيمن للسلسلة X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة soundex(X) سلسلة نصية بترميز Soundex من السلسلة النصية X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) â€«ØªÙØ¹ÙŠØ¯ substr(X,Y) كلّ المحار٠حتّى نهاية السلسلة النصية X بدايةً من المحر٠رقم Y. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) â€«ØªÙØ¹ÙŠØ¯ الدالة substr(X,Y,Z) سلسلة نصية جزئية من السلسلة الدخل X والتي تبدأ بالمحر٠رقم Y وبطول Z من المحارÙ. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. ‎() â€«ØªÙØ¹ÙŠØ¯ الدالة total_changes()‎ عدد الصÙو٠المتأثّرة Ø¨Ø¥ÙØ§Ø¯Ø© INSERT أو UPDATE أو DELETE مذ ÙÙØªØ­ اتصال قاعدة البيانات الحالية. (X) trim(X) removes spaces from both ends of X. (X) â€«ØªÙØ²ÙŠÙ„ trim(X) Ø§Ù„Ù…Ø³Ø§ÙØ§Øª من جانبي للسلسلة النصية X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة trim(X,Y) سلسلة نصية بإزالة كلّ المحار٠التي قد تظهر ÙÙŠ Y من ÙƒÙلا جانبي X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة typeof(X) سلسلة نصية توضّح نوع بيانات التعبير X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) â€«ØªÙØ¹ÙŠØ¯ دالة unicode(X) النقطة الرمزية اليونيكودية العددية لأوّل محر٠من السلسلة النصية X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة upper(X) نسخة من السلسلة النصية الدخل X حيث محار٠آسكي بحالة الأحر٠الكبيرة محوّلة كلّها إلى حالة الأحر٠الكبيرة. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) â€«ØªÙØ¹ÙŠØ¯ الدالة zeroblob(N) كائن BLOB يحتوي N بايت بالمحتوى 0x00. (timestring,modifier,modifier,...) (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) ØªÙØ¹ÙŠØ¯ الدالة‫ avg()‎ القيمة المتوسّطة لكلّ X لا تساوي NULL داخل مجموعة ما. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة count(X) عدد المرات التي لا يكون Ùيها X يساوي NULL ÙÙŠ مجموعة ما. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة group_concat()‎ سلسلة نصية تجمع كلّ قيم X التي لا تساوي NULL. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة group_concat()‎ سلسلة نصية تجمع كلّ قيم X التي لا تساوي NULL. إن كان المعطى Y موجودًا، ÙØ³ÙŠÙستخدم ÙƒÙØ§ØµÙ„ بين سيرورات X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة الجامعة max()‎ أكبر قيمة لكلّ القيم ÙÙŠ المجموعة. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) â€«ØªÙØ¹ÙŠØ¯ الدالة الجامعة min()‎ أدنى قيمة لا تساوي NULL لكلّ القيم ÙÙŠ المجموعة. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) â€«ØªÙØ¹ÙŠØ¯ الدالتان الجامعتان sum()‎ Ùˆ total()‎ مجموع كل القيم التي لا تساوي NULL ÙÙŠ المجموعة. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. ‎() ‫رقم الصÙÙ‘ داخل القسم الحالي. ØªÙØ±Ù‚ّم الصÙو٠بدءًا من Ù¡ بالترتيب الذي حدّده بند ORDER BY ÙÙŠ ØªØ¹Ø±ÙŠÙ Ø§Ù„Ù†Ø§ÙØ°Ø©ØŒ أو بترتيب اعتباطي إن لم يكن كذلك.†() The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. ‎() ‫ناتج row_number()‎ لأوّل ÙØ±Ø¯ ÙÙŠ كلّ مجموعة - رتبة الصÙÙ‘ الحالي مع Ø§Ù„ÙØ±Ø§ØºØ§Øª. إن لم يكن هناك بند ORDER BYØŒ ÙØ³ØªÙعتبر كلّ الصÙÙˆÙ Ø£ÙØ±Ø§Ø¯ ÙˆØ³ØªÙØ¹ÙŠØ¯ هذه الدالة Ù¡ دومًا. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. ‎() ‫رقم مجموعة Ø§Ù„Ø£ÙØ±Ø§Ø¯ للصÙÙ‘ الحالي داخل القسم - رتبة الصÙÙ‘ الحالي مع Ø§Ù„ÙØ±Ø§ØºØ§Øª. ØªÙØ±Ù‚ّم الأقسام بدءًا من 1 الترتيب الذي حدّده بند ORDER BY ÙÙŠ ØªØ¹Ø±ÙŠÙ Ø§Ù„Ù†Ø§ÙØ°Ø©. إن لم يوجد بند ORDER BYØŒ ÙØ³ØªÙعتبر كلّ الصÙÙˆÙ Ø£ÙØ±Ø§Ø¯ ÙˆØ³ØªÙØ¹ÙŠØ¯ هذه الدالة Ù¡ دومًا. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. ‎() ب‫غضّ النظر عن الاسم، ØªÙØ¹ÙŠØ¯ هذه الدالة دومًا قيمة بين ٠٫٠ و١٫٠ مساويةً لن(الرتبة - Ù¡)/(صÙو٠القسم - Ù¡)ØŒ حيث â€Ø§Ù„رتبة“ هي القيمة التي ØªÙØ¹ÙŠØ¯Ù‡Ø§ دالة Ø§Ù„Ù†Ø§ÙØ°Ø© المضمّنة rank()‎ Ùˆâ€ØµÙو٠القسم“ هو إجمال عدد الصÙÙˆÙ ÙÙŠ القسم. إن احتوى القسم صÙًا واحدًا ÙØ­Ø³Ø¨ØŒ ÙØ³ØªÙعيد هذه الدالة ٠٫٠. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. ‎() التوزيع التصاعدي. ÙŠÙØ­Ø³Ø¨ بالمعادلة رقم الصÙ/صÙو٠القسم، حيث â€Ø±Ù‚Ù… الصÙ“ هي القيمة التي أرجعتها‫ row_number()‎ لآخر ÙØ±Ø¯ ÙÙŠ المجموعة، Ùˆâ€ØµÙو٠القسم“ هي عدد الصÙÙˆÙ ÙÙŠ القسم. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) â€«ÙŠÙØªØ¹Ø§Ù…Ù„ مع المعطى N على أنّه عدد صحيح. تقسم هذه الدالة القسم إلى N مجموعة إلى حد الإمكان من المساواة، ÙˆØªÙØ³Ù†Ø¯ عددًا صحيحًا بين 1 ÙˆN لكل مجموعة، بالترتيب الذي حدّده بند ORDER BYØŒ أو بترتيب اعتباطي إن كان عكس ذلك. إن كان ضروريا، ÙØ³ØªØ­Ø¯Ø« المجموعات الأكبر أولا. ØªÙØ¹ÙŠØ¯ هذه الدالة قيمة العدد الصحيح Ø§Ù„Ù…ÙØ³Ù†Ø­Ø¯Ø© إلى المجموعة التي هي جزء من الص٠الحالي. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) â€«ØªÙØ¹ÙŠØ¯ ناتج تقدير التعبير expr على الصÙÙ‘ السابق ÙÙŠ القسم. أو NULL إن لم يكن هناك صÙÙ‘ سابق (لأنّ الص٠الحالي هو الأوّل). (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) ‫لو ÙˆÙØ¬Ø¯ وسيط الإزاحة offset Ùيجب أن يكون عددًا صحيحًا غير سالب. ÙÙŠ هذه الحالة تكون القيمة Ø§Ù„Ù…ÙØ¹Ø§Ø¯Ø© هي ناتج تقدير العبارة expr للصÙÙˆÙ Ø§Ù„Ù…ÙØ²Ø§Ø­Ø© حسب الإزاحة قبل الصÙÙ‘ الحالي ÙÙŠ القسم. لو كانت الإزاحة صÙÙØ±Ù‹Ø§ ÙØ³ÙŠÙقدّر التعبير حسب الص٠الحالي. لو لم تكن هناك صÙو٠بالإزاحة تلك قبل الصÙÙ‘ الحالي، ÙØ³ÙŠÙعاد NULL. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) ‫وإن ÙˆÙØ¬Ø¯Øª قيمة default ÙØ³ØªÙعاد بدل NULL لو لم يوجد الصÙÙ‘ الذي حدّدته الإزاحة تلك. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) â€«ØªÙØ¹ÙŠØ¯ ناتج تقدير التعبير حسب الصÙÙ‘ التالي ÙÙŠ القسم. أو NLL لو لم يكن هناك واحد (إذ الصÙÙ‘ الحالي هو آخر صÙÙ‘). (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) ‫لو ÙˆÙØ¬Ø¯ وسيط الإزاحة offset Ùيجب أن يكون عددًا صحيحًا غير سالب. ÙÙŠ هذه الحالة تكون القيمة Ø§Ù„Ù…ÙØ¹Ø§Ø¯Ø© هي ناتج تقدير العبارة expr للصÙÙˆÙ Ø§Ù„Ù…ÙØ²Ø§Ø­Ø© حسب الإزاحة بعد الصÙÙ‘ الحالي ÙÙŠ القسم. لو كانت الإزاحة صÙÙØ±Ù‹Ø§ ÙØ³ÙŠÙقدّر التعبير حسب الص٠الحالي. لو لم تكن هناك صÙو٠بالإزاحة تلك بعد الصÙÙ‘ الحالي، ÙØ³ÙŠÙعاد NULL. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) ‫تحسب دالة Ø§Ù„Ù†ÙˆØ§ÙØ° (window) المضمّنة هذه إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ ص٠كما تحسبها دوال الجامعة. ØªÙØ¹ÙŠØ¯ الدالة قيمة التعبير expr محسوبًا حسب الص٠الأوّل ÙÙŠ إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ صÙ. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) ‫تحسب دالة Ø§Ù„Ù†ÙˆØ§ÙØ° (window) المضمّنة هذه إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ ص٠كما تحسبها دوال الجامعة. ØªÙØ¹ÙŠØ¯ الدالة قيمة التعبير expr محسوبًا حسب الص٠الأخير ÙÙŠ إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ صÙ. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr, N) ‫تحسب دالة Ø§Ù„Ù†ÙˆØ§ÙØ° (window) المضمّنة هذه إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ ص٠كما تحسبها دوال الجامعة. ØªÙØ¹ÙŠØ¯ الدالة قيمة التعبير expr محسوبًا حسب الص٠رقم N ÙÙŠ إطار Ø§Ù„Ù†Ø§ÙØ°Ø©. ØªÙØ±Ù‚ّم الصÙÙˆÙ ÙÙŠ إطارات Ø§Ù„Ù†ÙˆØ§ÙØ° بدءًا بالعدد Ù¡ حسب الترتيب الذي حدّده بند ORDER BY لو ÙˆÙØ¬Ø¯ØŒ أو بترتيب اعتباطي لو لم يوجد. ولو لم يكن هناك ص٠برقم N ÙÙŠ القسم ÙØ³ÙŠÙعاد NULL. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. SqliteTableModel reading rows يقرأ الصÙÙˆÙ loading... يحمّل... References %1(%2) Hold %3Shift and click to jump there Ø§Ù„ØªÙØ¶ÙŠÙ„ات %L1â€(%L2) اضغط %L3Shift وانقر للانتقال إلى هناك Error changing data: %1 خطأ أثناء تغيير البيانات: %L1 retrieving list of columns يجلب قائمة الأعمدة Fetching data... يجلب البيانات... Cancel ألغ٠TableBrowser Browse Data تصÙّح البيانات &Table: الج&دول: Select a table to browse data اختر جدولًا لتصÙّح بياناته Use this list to select a table to be displayed in the database view استعمل هذه القائمة لاختيار الجدول الذي Ø³ÙŠÙØ¹Ø±Ø¶ ÙÙŠ منظور قاعدة البيانات This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. هذا هو منظور جدول قاعدة البيانات. يمكنك إجراء الآتي Ùيه: - البدء بالكتابة لتحرير القيمة داخل الخط. - النقر مزدوجًا على أيّ سجلّ لتحرير محتوياته ÙÙŠ Ù†Ø§ÙØ°Ø© محرّر الخلايا. - ضغط Alt+Del لحذ٠محتوى الخليّة وضبطه على NULL. - ضغط Ctrl+"‎ لتكرار السجلّ الحالي. - ضغط Ctrl+'‎ لنسخ القيمة من الخلية أعلاه. - التحديد العادي وعمليات النسخ واللصق. Text pattern to find considering the checks in this frame النمط محور البحث بأخذ Ø§Ù„ÙØ­ÙˆØµ ÙÙŠ هذا الإطار بعين الاعتبار Find in table ابحث ÙÙŠ الجدول Find previous match [Shift+F3] ابحث عن المطابقة السابقة [Shift+F3] Find previous match with wrapping ابحث عن المطابقة السابقة مع Ø§Ù„Ø§Ù„ØªÙØ§Ù Shift+F3 Shift+F3 Find next match [Enter, F3] ابحث عن المطابقة التالية [Enter, F3] Find next match with wrapping ابحث عن المطابقة التالية مع Ø§Ù„Ø§Ù„ØªÙØ§Ù F3 The found pattern must match in letter case يجب أن يطابق النمط محور البحث حالة الأحر٠Case Sensitive حسّاس لحالة الأحر٠The found pattern must be a whole word يجب أن يكون النمط محور البحث كلمة كاملة Whole Cell الخلية كاملة Interpret search pattern as a regular expression تعامَل مع نمط البحث كتعبير نمطي <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> إن ÙØ¹Ù‘لته ÙØ³ÙŠÙتعامل مع نمط البحث على أنّه تعبير يونكس نمطي. طالع <a href="https://en.wikibooks.org/wiki/Regular_Expressions">التعابير النمطية ÙÙŠ ويكي‌كتب (بالإنجليزية)</a>. Regular Expression تعبير نمطي Close Find Bar أغلÙÙ‚ شريط البحث Text to replace with نص الاستبدال Replace with استبدله بÙ†Replace next match استبدÙÙ„ المطابقة التالية Replace استبدل Replace all matches استبدل كلّ المطابقات Replace all استبدل الكلّ Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Copy column name Copy the database table column name to your clipboard New Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. <html><head/><body><p>Scroll to the beginning</p></body></html> مرّر إلى البداية <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> ينقلك هذا الزر إلى بداية منظور الجدول أعلاه. |< |< Scroll one page upwards مرّر ØµÙØ­Ø© واحدة للأمام <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> ينقلك هذا الزر ØµÙØ­Ø© واحدة من السجلّات لأعلى ÙÙŠ منظور الجدول أعلاه. < < 0 - 0 of 0 Ù  - Ù  من أصل Ù  Scroll one page downwards مرّر ØµÙØ­Ø© واحدة للأسÙÙ„ <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> ينقلك هذا الزر ØµÙØ­Ø© واحدة من السجلّات لأسÙÙ„ ÙÙŠ منظور الجدول أعلاه. > > Scroll to the end مرّر إلى النهاية <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> ينقلك هذا الزر إلى نهاية منظور الجدول أعلاه. >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> انقر هنا للانتقال إلى السجلّ المحدّد <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> ÙŠÙØ³ØªØ¹Ù…Ù„ هذا الزر ÙÙŠ التنقّل إلى رقم السطر المحدّد ÙÙŠ منطقة â€Ø§Ù†ØªÙ‚Ù„ إلى“. Go to: انتقل إلى: Enter record number to browse أدخÙÙ„ رقم السجلّ لتصÙّحه Type a record number in this area and click the Go to: button to display the record in the database view اكتب رقم السجلّ ÙÙŠ هذا المربّع وانقر زر â€Ø§Ù†ØªÙ‚Ù„ إلى:“ لعرض السجلّ ÙÙŠ منظور قاعدة البيانات 1 Ù¡ Show rowid column اعرض عمود معرّ٠الصÙÙˆÙ Toggle the visibility of the rowid column بدّل ظهور عمود معرّ٠الصÙÙˆÙ/rowid Unlock view editing اسمح بتحرير المنظور This unlocks the current view for editing. However, you will need appropriate triggers for editing. يتيح هذا تحرير المنظور الحالي. مع ذلك ستحتاج إلى المحÙّزات المناسبة لإجراء التحرير. Edit display format حرّر تنسيق العرض Edit the display format of the data in this column حرّر تنسيق عرض البيانات ÙÙŠ هذا العمود New Record سجلّ جديد Insert a new record in the current table Ø£Ø¯Ø±ÙØ¬ سجلًا جديدًا ÙÙŠ الجدول الحالي <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> ÙŠÙنشئ هذا الزر سجلًا جديدًا ÙÙŠ قاعدة البيانات. أبق٠زر Ø§Ù„ÙØ£Ø±Ø© مضغوطًا Ù„ÙØªØ­ قائمة منبثقة Ùيها عدّة خيارات:<ul><li><span style=" font-weight:600;">سجلّ جديد</span>: لإدراج سجلّ جديد يحمل القيم المبدئية ÙÙŠ قاعدة البيانات.</li><li><span style=" font-weight:600;">Ø£Ø¯Ø±ÙØ¬ قيم...</span>: Ù„ÙØªØ­ مربّع حوار لإدخال القيم قبل إدراجها ÙÙŠ جدول البيانات. يتيح هذا إدخال القيم حسب القيود Ø§Ù„Ù…Ø®ØªÙ„ÙØ©. ÙŠÙÙØªØ­ مربّع الحوار هذا أيضًا إن ÙØ´Ù„ الخيار <span style=" font-weight:600;">سجلّ جديد</span> بسبب هذه القيود.</li></ul> Delete Record احذ٠السجلّ Delete the current record احذ٠السجلّ الحالي This button deletes the record or records currently selected in the table يحذ٠هذا الزر السجلّ أو السجلّات المحدّدة حاليًا ÙÙŠ الجدول Insert new record using default values in browsed table Ø£Ø¯Ø±ÙØ¬ سجلًا جديدًا مستخدمًا القيم المبدئية ÙÙŠ الجدول الذي تتصÙّحه Insert Values... Ø£Ø¯Ø±ÙØ¬ قيم... Open a dialog for inserting values in a new record Ø§ÙØªØ­ مربّع حوار لإدراج القيم ÙÙŠ سجلّ جديد Export to &CSV &صدّر بنسق CSV Export the filtered data to CSV صدّر البيانات المرشّحة إلى CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. ÙŠÙØµØ¯Ù‘ر هذا الزر بيانات الجدول الذي تتصÙّحه كما هي معروضة حاليًا (بعد المرشّحات وتنسيقات العرض وعمود Ø§Ù„ÙØ±Ø²) كمل٠CSV. Save as &view Ø§Ø­ÙØ¸ كمن&ظور Save the current filter, sort column and display formats as a view Ø§Ø­ÙØ¸ المرشّح الحالي وعمود Ø§Ù„ÙØ±Ø² وتنسيقات العرض كمنظور This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. ÙŠØ­ÙØ¸ هذا الزر الإعداد الحالي للجدول الذي تتصÙّحه (المرشّحات وتنسيقات العرض وعمود Ø§Ù„ÙØ±Ø²) ÙÙŠ منظور SQL يمكنك تصÙّحه لاحقًا أو استخدامه ÙÙŠ Ø¥ÙØ§Ø¯Ø§Øª SQL. Save Table As... Ø§Ø­ÙØ¸ الجدول ÙƒÙŽâ€... Save the table as currently displayed Ø§Ø­ÙØ¸ الجدول كما هو معروض حاليًا <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> توÙّر القائمة المنبثقة هذه الخيارات الآتية والتي تنطبق على الجدول الذي تتصÙّحه والمرشّح حاليًا:<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">صدّر بنسق CSV: ÙŠÙØµØ¯Ù‘ر هذا الخيار البيانات ÙÙŠ الجدول الذي تتصÙّحه كما هي معروضة حاليًا (بعد المرشّحات وتنسيقات العرض وعمود Ø§Ù„ÙØ±Ø²) إلى مل٠بنسق CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ø§Ø­ÙØ¸ كمنظور: ÙŠØ­ÙØ¸ هذا الخيار الإعداد الحالي للجدول الذي تتصÙّحه (المرشّحات وتنسيقات العرض وعمود Ø§Ù„ÙØ±Ø²) ÙÙŠ منظور SQL يمكنك تصÙّحه لاحقًا أو استعماله ÙÙŠ Ø¥ÙØ§Ø¯Ø§Øª SQL.</li></ul> Hide column(s) أخÙ٠العمود/الأعمدة Hide selected column(s) أخÙ٠العمود/الأعمدة المحدّدة Show all columns اعرض كلّ الأعمدة Show all columns that were hidden اعرض كلّ الأعمدة التي Ø£ÙØ®Ùيت Set encoding اضبط الترميز Change the encoding of the text in the table cells غيّر ترميز النصوص ÙÙŠ خلايا الجدول Set encoding for all tables اضبط ترميز كلّ الجداول Change the default encoding assumed for all tables in the database غيّر الترميز المبدئي Ø§Ù„Ù…ÙØªØ±Ø¶ ÙÙŠ كلّ جداول قاعدة البيانات Clear Filters امسح المرشّحات Clear all filters امسح كلّ المرشّحات This button clears all the filters set in the header input fields for the currently browsed table. يمسح هذا الزر كلّ المرشّحات المضبوطة ÙÙŠ حقول الدخل ÙÙŠ الترويسة للجدول الذي تتصÙّحه حاليًا. Clear Sorting امسح Ø§Ù„ÙØ±Ø² Reset the order of rows to the default صÙّر ترتيب الصÙو٠إلى المبدئيات This button clears the sorting columns specified for the currently browsed table and returns to the default order. يمسح هذا الزر تريتب الأعمدة المحدّد للجدول الذي تتصÙّحه حاليًا ÙˆÙŠÙØ¹ÙŠØ¯Ù‡ إلى التريب المبدئي. Print اطبع Print currently browsed table data اطبع بيانات الجدول الذي تتصÙّحه حاليًا Print currently browsed table data. Print selection if more than one cell is selected. اطبع بيانات الجدول الذي تتصÙّحه حاليًا. اطبع التحديد إن كانت هناك أكثر من خليّة واحدة محدّدة. Ctrl+P Ctrl+P Refresh Ø£Ù†Ø¹ÙØ´ Refresh the data in the selected table Ø£Ù†Ø¹ÙØ´ البيانات ÙÙŠ الجدول المحدّد This button refreshes the data in the currently selected table. ÙŠÙنعش هذا الزر البيانات ÙÙŠ الجدول المحدّد حاليًا. F5 Find in cells ابحث ÙÙŠ الخلايا Open the find tool bar which allows you to search for values in the table view below. Ø§ÙØªØ­ شريط أدوات البحث لتبحث عن القيم التي تريد ÙÙŠ منظور الجدول أسÙله. Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally Bold ثخين Ctrl+B Ctrl+B Italic مائل Underline مسطّر Ctrl+U Ctrl+U Align Right حاذ٠يمينًا Align Left حاذ٠يسارًا Center Horizontally الوسط الأÙقي Justify ضبط Edit Conditional Formats... حرّر التنسيقات الشرطيّة... Edit conditional formats for the current column حرّر تنسيقات العمود الحالي الشرطيّة Clear Format امسح التنسيق Clear All Formats امسح كلّ التنسيقات Clear all cell formatting from selected cells and all conditional formats from selected columns امسح كلّ تنسيق الخلايا ÙÙŠ الخلايا المحدّدة وكلّ التنسيقات الشرطيّة ÙÙŠ الأعمدة المحدّدة Font Color لون النص Background Color لون الخلÙية Toggle Format Toolbar اعرض/أخÙ٠شريط أدوات التنسيق Show/hide format toolbar اعرض/أخÙ٠شريط التنسيق This button shows or hides the formatting toolbar of the Data Browser يعرض هذا الزر (أو ÙŠÙØ®ÙÙŠ) شريط التنسيق لمتصÙّح البيانات Select column اختر عمودًا Ctrl+Space Ctrl+Space Replace text in cells استبدل النصوص ÙÙŠ الخلايا Filter in any column رشّح أيّ عمود Ctrl+R Ctrl+R %n row(s) لا صÙو٠صÙÙ‘ واحد صÙّان اثنان %Ln صÙÙˆÙ %Ln صÙًا %Ln صÙÙ‘ , %n column(s) ولا أعمدة وعمود واحد وعمودين اثنين Ùˆ%Ln أعمدة Ùˆ%Ln عمودًا Ùˆ%Ln عمود . Sum: %1; Average: %2; Min: %3; Max: %4 . المجموع: %L1ØŒ المتوسّط: %L2ØŒ الأدنى: %L3ØŒ الأقصى: %L4 Conditional formats for "%1" تنسيقات â€%L1“ الشرطيّة determining row count... يحدّد عدد الصÙÙˆÙ... %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. من ÙØ¶Ù„Ùƒ أدخÙÙ„ Ù…ÙØªØ§Ø­Ù‹Ø§ أساسيًا زائÙًا (pseudo) Ù„ØªÙØ¹ÙŠÙ„ التحرير ÙÙŠ هذا المنظور. يجب أن يكون Ø§Ù„Ù…ÙØªØ§Ø­ اسمًا لأحد الأعمدة Ø§Ù„ÙØ±ÙŠØ¯Ø© ÙÙŠ المنظور. Delete Records احذ٠السجلّات Duplicate records كرّر السجلّات Duplicate record كرّر السجلّ Ctrl+" Ctrl+" Adjust rows to contents اضبط الصÙو٠إلى محتواها Error deleting record: %1 خطأ أثناء حذ٠السجلّ: %L1 Please select a record first من ÙØ¶Ù„Ùƒ اختر سجلًا أوّلًا Please choose a new encoding for all tables. من ÙØ¶Ù„Ùƒ اختر ترميزًا جديدًا لكلّ الجداول. Please choose a new encoding for this table. من ÙØ¶Ù„Ùƒ اختر ترميزًا جديدًا لهذا الجدول. %1 Leave the field empty for using the database encoding. %L1 اترك الحقل ÙØ§Ø±ØºÙ‹Ø§ لاستعمال ترميز قاعدة البيانات. This encoding is either not valid or not supported. إمّا أنّ هذا الترميز غير صالح أو أنّه غير مدعوم. %1 replacement(s) made. عدد الاستبدالات Ø§Ù„Ù…ÙØ¬Ø±Ø§Ø©: %L1 TableBrowserDock New Data Browser Rename Data Browser Close Data Browser Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. VacuumDialog Compact Database رصّ قاعدة البيانات Warning: Compacting the database will commit all of your changes. تحذير: برصّ قاعدة البيانات ستÙودع كلّ التعديلات التي أجريتها. Please select the databases to co&mpact: من ÙØ¶Ù„Ùƒ اختر قواعد البيانات لر&صّها: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_cs.ts000066400000000000000000012421151463772530400252100ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite O DB Browser pro SQLite Version Verze <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Enter values for the new record considering constraints. Fields in bold are mandatory. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Name Název Type Typ Value Values to insert. Pre-filled default values are inserted automatically unless they are changed. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> Auto-increment Unique constraint Check constraint: %1 Foreign key: %1 Default value: %1 Error adding record. Message from database engine: %1 Are you sure you want to restore all the entered values to their defaults? Application Possible command line arguments: Možné parametry pro příkazový řádek: The user settings file location is replaced with the argument value instead of the environment variable value. Ignored environment variable (DB4S_SETTINGS_FILE) value: The file %1 does not exist Soubor %1 neexistuje Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Browse this table, or use it as target of a data import Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The -S/--settings option requires an argument. The option is ignored. The -o/--option and -O/--save-option options require an argument in the form group/setting=value Invalid option/non-existent file: %1 Neplatná volba/neexistující soubor: %1 SQLite Version verze SQLite SQLCipher Version %1 (based on SQLite %2) DB Browser for SQLite Version %1. Last commit hash when built: %1 Built for %1, running on %2 Qt Version %1 CipherDialog SQLCipher encryption Å¡ifrování SQLCipher &Password &Heslo &Reenter password &Zadejte heslo znovu Encr&yption settings SQLCipher &3 defaults SQLCipher &4 defaults Custo&m Page si&ze Velikost strany &KDF iterations HMAC algorithm KDF algorithm Plaintext Header Size Passphrase Raw key Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. ColumnDisplayFormatDialog Choose display format Vyberte formát zobrazení Display format Formát zobrazení Choose a display format for the column '%1' which is applied to each value prior to showing it. Vyberte formát zobrazení pro sloupec '%1' který je použit na každou hodnotu pÅ™ed zobrazením. Default Výchozí Decimal number Desetinné Äíslo Exponent notation Notace exponentu Hex blob Å estnáctkový blob Hex number Å estnáctkové Äíslo Apple NSDate to date Apple NSDate na datum Java epoch (milliseconds) to date .NET DateTime.Ticks to date Julian day to date Juliánský den na datum Unix epoch to local time WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy Datum jako dd/mm/yyyy Lower case Malá písmena Binary GUID to text SpatiaLite Geometry to SVG Custom display format must contain a function call applied to %1 Error in custom display format. Message from database engine: %1 Custom display format must return only one column but it returned %1. Octal number OsmiÄkové Äíslo Round number Zaokrouhlit Äíslo Unix epoch to date Unix epoch na datum Upper case Velká písmena Windows DATE to date Windows DATE na datum Custom Vlastní CondFormatManager Conditional Format Manager This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Add new conditional format &Add PÅ™idat Remove selected conditional format &Remove Odstranit Move selected conditional format up Move &up Move selected conditional format down Move &down Foreground PopÅ™edí Text color Barva textu Background Pozadí Background color Barva pozadí Font Font Size Velikost Bold TuÄný Italic Kurzíva Underline Podtržený Alignment Condition Click to select color Are you sure you want to clear all the conditional formats of this field? DBBrowserDB Please specify the database name under which you want to access the attached database Prosím specifikujte jméno databáze, pod kterým chcete pÅ™istupovat k pÅ™ipojené databázi Invalid file format Neplatný formát souboru Do you want to save the changes made to the database file %1? Chcete uložit zmÄ›ny provedené do databázového souboru %1? Exporting database to SQL file... Exportuji databázi do souboru SQL... Cancel ZruÅ¡it Executing SQL... Provádím SQL... Action cancelled. Akce zruÅ¡ena. Do you really want to close this temporary database? All data will be lost. Database didn't close correctly, probably still busy Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: Databáze je právÄ› zaneprázdnÄ›ná: Do you want to abort that other operation? No database file opened Error in statement #%1: %2. Aborting execution%3. and rolling back didn't receive any output from %1 could not execute command: %1 Cannot delete this object Nemohu smazat tento objekt Cannot set data on this object A table with the name '%1' already exists in schema '%2'. No table with name '%1' exists in schema '%2'. Cannot find column %1. Creating savepoint failed. DB says: %1 Renaming the column failed. DB says: %1 Releasing savepoint failed. DB says: %1 Creating new table failed. DB says: %1 Copying data to new table failed. DB says: %1 Deleting old table failed. DB says: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 could not get list of db objects: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: could not get list of databases: %1 Error loading extension: %1 Chyba pÅ™i naÄítání přípony: %1 Error loading built-in extension: %1 could not get column information Error setting pragma %1 to %2: %3 Chyba pÅ™i nastavování pragma %1 na %2: %3 File not found. Soubor nebyl nalezen. DbStructureModel Name Název Object Objekt Type Typ Schema Schéma Database Databáze Browsables All VÅ¡echny Temporary DoÄasný Tables (%1) Tabulky (%1) Indices (%1) Indexy (%1) Views (%1) Pohledy (%1) Triggers (%1) Triggery (%1) EditDialog Edit database cell Upravit buňku databáze Mode: Mód: Image Obrázek Set as &NULL Nastavit na &NULL Apply data to cell This button saves the changes performed in the cell editor to the database cell. Apply Provést Text Text This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. RTL Text Binary Binární JSON XML XML Evaluation Automatically adjust the editor mode to the loaded data type This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Auto-switch This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Identification of the cell currently in the editor Type and size of data currently in table Open preview dialog for printing the data currently stored in the cell Auto-format: pretty print on loading, compact on saving. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Word Wrap Wrap lines on word boundaries Open in default application or browser Open in application The value is interpreted as a file or URL and opened in the default application or web browser. Save file reference... Save reference to file Open in external application Autoformat &Export... &Import... Import from file Importovat ze souboru Opens a file dialog used to import any kind of data to this database cell. Export to file Exportovat do souboru Opens a file dialog used to export the contents of this database cell to a file. Erases the contents of the cell Vymazat obsah buňky This area displays information about the data present in this database cell Tato oblast zobrazuje informace o aktuálních datech v této databázové buňce Print... Tisk... Ctrl+P Open preview dialog for printing displayed text Copy Hex and ASCII Copy selected hexadecimal and ASCII columns to the clipboard Ctrl+Shift+C Choose a filename to export data Vyberte název souboru pro export dat Image data can't be viewed in this mode. Try switching to Image or Binary mode. Binary data can't be viewed in this mode. Try switching to Binary mode. Zkuste pÅ™epnout do binárního režimu. Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) Couldn't save file: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Image files (%1) Soubory obrázků (%1) Binary files (*.bin) Binární soubory (*.bin) Choose a file to import Vyberte soubor pro import The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Unsaved data in the cell editor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. %1 Image %1 Obrázek Invalid data for this mode Neplatná data pro tento režim The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? EditIndexDialog &Name Název Order Řadit &Table Tabulka Edit Index Schema Upravit schéma indexů &Unique Unikátní For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Partial inde&x clause Colu&mns Sloupce Table column Sloupec tabulky Type Typ Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Index column Index sloupce Deleting the old index failed: %1 Creating the index failed: %1 Vytváření indexu se nezdaÅ™ilo: %1 EditTableDialog Edit table definition Upravit definici tabulky Table Tabulka Advanced PokroÄilé Without Rowid Bez id řádku Database sche&ma Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Fields Pole Add Remove Move to top Move up Move down Move to bottom Name Název Type Typ NN NN Not null Není null PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> AI AI Autoincrement Autoincrement U U Unique Unikátní Default Výchozí Default value Výchozí hodnota Check Zkontrolovat Check constraint Zkontrolovat omezení Collation Foreign Key Cizí klÃ­Ä <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Index Constraints Add constraint Remove constraint Columns Sloupce SQL Foreign Keys References Check Constraints <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> Primary Key Add a primary key constraint Add a unique constraint There can only be one primary key for each table. Please modify the existing primary key instead. Error creating table. Message from database engine: %1 Chyba pÅ™i vytváření tabulky. Zpráva z databáze: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Pole s tímto názvem již existuje. Nejdříve jej pÅ™ejmenujte, nebo vyberte pro toto pole jiný název, prosím. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Tento sloupec je použit jako cizí klÃ­Ä v tabulce %1 a jeho název nemůže být zmÄ›nÄ›n. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Existuje alespoň jeden řádek, který je nastaven na NULL. Z tohoto důvodu je nemožné nastavit tento flag. Nejprve změňte data v tabulce, prosím. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Existuje alespoň jeden řádek, který neobsahuje hodnotu typu integer. Z tohoto důvodu je nemožné nastavit AI flag. Nejprve změňte data v tabulce, prosím. Column '%1' has duplicate data. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set ExportDataDialog Export data as CSV Exportovat data do CSV Tab&le(s) Tabulka/ky Colu&mn names in first line Názvy sloupců v prvním řádku Fie&ld separator OddÄ›lovaÄ pole , , ; ; Tab Karta | | Other Ostatní &Quote character &Uvozovka " " ' ' New line characters Znaky nového řádku Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print Pretty print Could not open output file: %1 Nemohu otevřít výstupní soubor: %1 Choose a filename to export data Vyberte název souboru pro export dat Export data as JSON Exportovat data jako JSON exporting CSV exportování CSV Error while writing the file '%1': %2 exporting JSON exportování JSONu Please select at least 1 table. Vyberte alespoň jednu tabulku, prosím. Choose a directory Vybrat složku Export completed. Export byl dokonÄen. Export finished with errors. ExportSqlDialog Export SQL... Exportovat SQL... Tab&le(s) Tabulka/ky Select All Vybrat vÅ¡e Deselect All ZruÅ¡it výbÄ›r &Options Volby Keep column names in INSERT INTO Zachovat názvy sloupců v INSERT INTO Multiple rows (VALUES) per INSERT statement Více řádků (VALUES) pro příkaz INSERT Export everything Exportovat vÅ¡e Export data only Exportovat pouze data Keep original CREATE statements Keep old schema (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) PÅ™epsat staré schéma (DROP TABLE, then CREATE TABLE) Export schema only Exportovat pouze schéma Please select at least one table. Vyberte prosím aspoň jednu tabulku. Choose a filename to export Vyberte název souboru pro export Export completed. Export dokonÄen. Export cancelled or failed. Export byl zruÅ¡en nebo selhal. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Find and Replace... Najít a nahradit... Print... Tisk... ExtendedTableWidget Use as Exact Filter Containing Not containing Not equal to Greater than VÄ›tší než Less than Menší než Greater or equal VÄ›tší nebo rovno Less or equal Menší nebo rovno Between this and... Mezi tímto a... Regular expression Edit Conditional Formats... Set to NULL Nastavit na NULL Cut Copy Kopírovat Copy with Headers Kopírovat s hlaviÄkami Copy as SQL Kopírovat jako SQL Paste Vložit Print... Tisk... Use in Filter Expression Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. FileExtensionManager File Extension Manager &Up Nahoru &Down Dolů &Add PÅ™idat &Remove Odstranit Description Popis Extensions Rozšíření *.extension *.extension FilterLineEdit Filter Filtr These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Clear All Conditional Formats Use for Conditional Format Edit Conditional Formats... Set Filter Expression What's This? Co je toto? Is NULL je NULL Is not NULL Není NULL Is empty Je prázdný Is not empty Není prázdný Not containing... Equal to... Rovný k... Not equal to... Není rovný k... Greater than... VÄ›tší než... Less than... Menší než... Greater or equal... VÄ›tší nebo rovno... Less or equal... Menší nebo rovno... In range... V rozmezí... Regular expression... FindReplaceDialog Find and Replace Najít a nahradit Fi&nd text: Najít text Re&place with: Nahradit s: Match &exact case Match &only whole words When enabled, the search continues from the other end when it reaches one end of the page &Wrap around When set, the search goes backwards from cursor position, otherwise it goes forward Search &backwards <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> &Selection only <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Use regular e&xpressions Find the next occurrence from the cursor position and in the direction set by "Search backwards" &Find Next Najít další F3 &Replace Nahradit Highlight all the occurrences of the text in the page F&ind All Najít vÅ¡e Replace all the occurrences of the text in the page Replace &All Nahradit vÅ¡e The searched text was not found Hledaný text nebyl nalezen The searched text was not found. Hledaný text nebyl nalezen. The searched text was found one time. Hledaný text byl nalezen jednou. The searched text was found %1 times. Hledaný text byl nalezen %1 krát. The searched text was replaced one time. Hledaný text byl nahrazen jednou. The searched text was replaced %1 times. Hledaný text byl nahrazen %1 krát. ForeignKeyEditor &Reset Foreign key clauses (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Reset the scaling to match the original size of the image. Set the scaling to match the size of the viewport. Print... Tisk... Open preview dialog for printing displayed image Ctrl+P ImportCsvDialog Import CSV file Importovat soubor CSV Table na&me Název tabulky &Column names in first line &Názvy sloupců v prvním řádku Field &separator OddÄ›lovaÄ pole , , ; ; Tab Karta | | Other Ostatní &Quote character &Uvozovka Other (printable) Other (code) " " ' ' &Encoding Kódování UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? OÅ™ezat pole? Separate tables OddÄ›lit tabulky Advanced PokroÄilé When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Ignore default &values Ignorovat výchozí hodnoty Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Fail on missing values Disable data type detection Disable the automatic data type detection when creating a new table. Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Abort import Ignore row Replace existing row Conflict strategy Deselect All ZruÅ¡it celý výbÄ›r Match Similar Select All Vybrat vÅ¡e There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. There is already a table named '%1'. Do you want to import the data into it? Creating restore point failed: %1 Vytváření bodu obnovy selhalo: %1 Creating the table failed: %1 Vytváření tabulky selhalo: %1 importing CSV importování CSV Could not prepare INSERT statement: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Inserting row failed: %1 Vkládání řádku selhalo: %1 MainWindow DB Browser for SQLite DB Browser pro SQLite toolBar1 toolBar1 Opens the SQLCipher FAQ in a browser window OtevÅ™e SQLCipher FAQ v oknÄ› prohlížeÄe Export one or more table(s) to a JSON file Export jedné nebo více tabulek do souboru JSON &File &Soubor &Import &Import &Export &Export Open an existing database file in read only mode &Edit Upravit &View Pohled &Help Pomoc DB Toolbar Panel nástrojů DB Edit Database &Cell Upravit databázovou buňku DB Sche&ma DB Schéma Execute current line Provést aktuální řádek This button executes the SQL statement present in the current editor line Shift+F5 Sa&ve Project Ulo&žit Projekt User Uživatel Application Aplikace &Clear &VyÄistit &New Database... Nová databáze... Create a new database file VytvoÅ™it nový databázový soubor This option is used to create a new database file. Tato volba slouží k vytvoÅ™ení nového souboru databáze. Ctrl+N &Open Database... Otevřít databázi... Open an existing database file Otevřít existující soubor databáze This option is used to open an existing database file. Tato volba slouží k otevÅ™ení existujícího souboru databáze. Ctrl+O &Close Database &Zavřít databázi This button closes the connection to the currently open database file Ctrl+W Revert database to last saved state Vrátit databázi do posledního uloženého stavu This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Write changes to the database file Zapsat zmÄ›ny do souboru databáze This option is used to save changes to the database file. Tato volba slouží k uložení provedených zmÄ›n do souboru databáze. Ctrl+S Compact &Database... Compact the database file, removing space wasted by deleted records Compact the database file, removing space wasted by deleted records. E&xit Exit Ctrl+Q Import data from an .sql dump text file into a new or existing database. Importovat data z textového souboru .sql do nové nebo již existující databáze. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Open a wizard that lets you import data from a comma separated text file into a database table. OtevÅ™e průzkumníka, kde můžete importovat data z textového souboru, kde jsou data oddÄ›lena Äárkami, do databázové tabulky. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Export a database to a .sql dump text file. Exportovat databázi do textového souboru .sql This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Export a database table as a comma separated text file. Exportovat databázovou tabulku jako textový soubor oddÄ›lený Äárkami. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Delete Table Smazat Tabulku Open the Delete Table wizard, where you can select a database table to be dropped. Open the Create Index wizard, where it is possible to define a new index on an existing database table. &Preferences... &Možnosti... Open the preferences window. Otevřít okno s možnostmi. &DB Toolbar Panel nástrojů DB Shows or hides the Database toolbar. Zobrazí nebo skryje liÅ¡tu Databáze. Shift+F1 New &tab Open SQL file(s) This button opens files containing SQL statements and loads them in new editor tabs Execute line &Wiki Wiki F1 Bug &Report... Nahlásit chybu... Feature Re&quest... Požadavek na funkci... Web&site Webová stránka &Donate on Patreon... PÅ™ispÄ›t na Patreon... This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file This button lets you open a DB Browser for SQLite project file Browse Table Close Pro&ject Close project and database files and return to the initial state Ctrl+Shift+F4 Detach Database Detach database file attached to the current database connection &Attach Database... PÅ™iložit databázi... &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs E&xecute SQL This has to be equal to the tab title in all the main tabs &Recent Files &New Database &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Ctrl+Shift+T &Save Project Open &Project Add another database file to the current database connection This button lets you add another database file to the current database connection &Set Encryption... Nastavit Å¡ifrování... SQLCipher &FAQ SQLCipher FAQ Table(&s) to JSON... Tabulka(ky) do JSONu... Open Data&base Read Only... Ctrl+Shift+O Save results Uložit výsledky Save the results view This button lets you save the results of the last executed query Find text in SQL editor Najít text v SQL editoru Find This button opens the search bar of the editor Ctrl+F Find or replace text in SQL editor Najít a nahradit text v SQL editoru Find or replace This button opens the find/replace dialog for the current editor tab Ctrl+H Export to &CSV Export do CSV Export to &JSON Save as &view Uložit jako pohled Save as view Uložit jako pohled Shows or hides the Project toolbar. Zobrazit nebo skrýt liÅ¡tu projektu Extra DB Toolbar Extra DB Toolbar &Open Database New In-&Memory Database Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Drag && Drop Qualified Names Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Drag && Drop Enquoted Names Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor &Integrity Check Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. &Foreign-Key Check Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab &Quick Integrity Check Run a quick integrity check over the open DB Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. &Optimize Attempt to optimize the database Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Print Tisk Print text from current SQL editor tab Open a dialog for printing the text in the current SQL editor tab Print the structure of the opened database Open a dialog for printing the structure of the opened database &Save Project As... Save the project in a file selected in a dialog Save A&ll Save DB file, project file and opened SQL files Ctrl+Shift+S Ctrl+Shift+W Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Refresh Obnovit Reload the database structure &Recently opened &Nedávno otevÅ™ené Ctrl+T This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Un/comment block of SQL code Un/comment block Comment or uncomment current line or selected block of code Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Ctrl+/ Stop SQL execution Stop execution Stop the currently running SQL script Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Too&ls Nástroje SQL &Log SQL &Log Show S&QL submitted by Error Log This button clears the contents of the SQL logs This panel lets you examine a log of all SQL commands issued by the application or by yourself &Plot This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. &Remote Vzdálené Project Toolbar Extra DB toolbar Extra DB toolbar Close the current database file Ctrl+F4 &Revert Changes Vrátit ZmÄ›ny &Write Changes Zapsat ZmÄ›ny &Database from SQL file... Databáze z SQL souboru... &Table from CSV file... Tabulka ze souboru CSV... &Database to SQL file... Databáze do souboru SQL... &Table(s) as CSV file... Tabulka/ky jako soubor CSV... &Create Table... VytvoÅ™it Tabulku... &Delete Table... Smazat Tabulku... &Modify Table... Upravit Tabulku... Create &Index... VytvoÅ™it Index... W&hat's This? Co je toto? &About O This button opens a new tab for the SQL editor &Execute SQL &Provést příkaz SQL Execute all/selected SQL Provést vÅ¡echny/vybrané SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Save SQL file Uložit SQL soubor &Load Extension... NaÄíst rozšíření... Ctrl+E Export as CSV file Exportovat jako soubor CSV Export table as comma separated values file Exportovat tabulku do souboru jako hodnoty oddÄ›lené Äárkami Save the current session to a file Uložit aktuální session do souboru Open &Project... Otevřít projekt... Load a working session from a file Save SQL file as Uložit soubor SQL jako This button saves the content of the current SQL editor tab to a file &Browse Table &Prohlížet Tabulku Copy Create statement Kopírovat příkaz Create Copy the CREATE statement of the item to the clipboard Zkopírovat do schránky příkaz CREATE Ctrl+Return Ctrl+L Ctrl+P Ctrl+D Ctrl+I Encrypted Å ifrováno Read only Pouze pro Ätení Database file is read only. Editing the database is disabled. Soubor databáze je urÄen pouze pro Ätení. Úprava databáze je zakázána. Database encoding Kódování databáze Database is encrypted using SQLCipher Databáze je Å¡ifrována pÅ™es SQLCipher Choose a database file Vyberte soubor databáze Choose a filename to save under Vyberte název souboru pro uložení Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? Jste si jisti, že chcete vrátit zpÄ›t vÅ¡echny provedené zmÄ›ny v databázi '%1' od posledního uložení? Choose a file to import Vyberte soubor pro import &%1 %2%3 &%1 %2%3 (read only) Open Database or Project Attach Database... Import CSV file(s)... Do you want to save the changes made to SQL tabs in the project file '%1'? Text files(*.sql *.txt);;All files(*) Textové soubory(*.sql *.txt);;VÅ¡echny soubory(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Do you want to save the changes made to the project file '%1'? File %1 already exists. Please choose a different name. Soubor %1 již existuje. Vyberte jiný název, prosím. Error importing data: %1 Chyba pÅ™i importu dat: %1 Import completed. Import dokonÄen. Delete View Smazat Pohled Modify View Delete Trigger Smazat Spoušť Modify Trigger Delete Index Smazat Index Modify Index ZmÄ›nit Index Modify Table ZmÄ›nit tabulku Do you want to save the changes made to SQL tabs in a new project file? Do you want to save the changes made to the SQL file %1? Could not find resource file: %1 Choose a project file to open Vybrat soubor projektu k otevÅ™ení Could not open project file for writing. Reason: %1 Busy (%1) Setting PRAGMA values will commit your current transaction. Are you sure? Ctrl+Tab Ctrl+Shift+Tab Clear List Window Layout Reset Window Layout Simplify Window Layout Alt+Shift+0 Dock Windows at Bottom Dock Windows at Left Side Dock Windows at Top The database is currently busy. Click here to interrupt the currently running query. Ctrl+Alt+W Could not open database file. Reason: %1 In-Memory database Choose a database file to save under Error while saving the database to the new file. Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Are you sure you want to delete the view '%1'? Are you sure you want to delete the trigger '%1'? Are you sure you want to delete the index '%1'? Error: could not delete the table. Error: could not delete the view. Error: could not delete the trigger. Error: could not delete the index. Message from database engine: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Edit View %1 Edit Trigger %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. -- EXECUTING SELECTION IN '%1' -- -- EXECUTING LINE IN '%1' -- -- EXECUTING ALL IN '%1' -- At line %1: Result: %1 Result: %2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Opened '%1' in read-only mode from recent file list Opened '%1' from recent file list Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? DB file '%1' could not be opened This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Table '%1' not found; settings ignored -- Reference to file "%1" (not supported by this version) -- Yes. Don't ask again This action will open a new SQL tab with the following statements for you to edit and run: Rename Tab Duplicate Tab Close Tab Opening '%1'... There was an error opening '%1'... Value is not a valid URL or filename: %1 %1 rows returned in %2ms Automatically load the last opened DB file at startup Ctrl+Alt+0 Choose text files Vybrat textové soubory Import completed. Some foreign key constraints are violated. Please fix them before saving. Select SQL file to open Vyberte soubor SQL k otevÅ™ení Select file name Vyberte název souboru Select extension file Vyberte soubor s rozšířením Extension successfully loaded. Rozšíření bylo úspěšnÄ› naÄteno. Error loading extension: %1 Chyba pÅ™i naÄítání přípony: %1 Don't show again Znovu nezobrazovat New version available. Dostupná nová verze. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Nová verze DB Browseru pro SQLite je nyní dostupná (%1.%2.%3).<br/><br/>StáhnÄ›te ji prosím na <a href='%4'>%4</a>. Project saved to file '%1' Collation needed! Proceed? Je potÅ™eba provést collation! Potvrdit? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! creating collation Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Please specify the view name Specifikujte název pohledu, prosím There is already an object with that name. Please choose a different name. Objekt s tímto názvem již existuje. Vyberte jiný název, prosím. View successfully created. Pohled byl úspěšnÄ› vytvoÅ™en. Error creating view: %1 Chyba pÅ™i vytváření pohledu: %1 This action will open a new SQL tab for running: Press Help for opening the corresponding SQLite reference page. DB Browser for SQLite project file (*.sqbpro) DB Browser pro SQLite project file (*.sqbpro) Error checking foreign keys after table modification. The changes will be reverted. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Execution finished with errors. Execution finished without errors. NullLineEdit Set to NULL Nastavit na NULL Alt+Del PlotDock Plot <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> Columns Sloupce X X Y1 Y2 Axis Type Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Line type: Typ řádku: None Žádná Line Řádek StepLeft KrokVlevo StepRight KrokVpravo StepCenter KrokDoprostÅ™ed Impulse Impuls Point shape: Cross Kříž Plus Plus Circle Kruh Disc Disk Square ÄŒtverec Diamond Diamand Star HvÄ›zda Triangle Trojúhelník TriangleInverted ObrácenýTrojúhelník CrossSquare PlusSquare PlusÄŒtverec CrossCircle PlusCircle Peace <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> Save current plot... Load all data and redraw plot Row # Řádek # Copy Kopírovat Print... Tisk... Show legend Zobrazit legendu Stacked bars Fixed number format Date/Time Datum/Äas Date Datum Time ÄŒas Numeric Label Å títek Invalid Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Choose an axis color Vyberte barvu osy Choose a filename to save under Vyberte název souboru pro uložení PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;VÅ¡echny Soubory(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Loading all remaining data for this table took %1ms. PreferencesDialog Preferences Možnosti &General &Obecné Remember last location Zapamatovat poslední umístÄ›ní Always use this location Vždy použít toto umístÄ›ní Remember last location for session only Pamatovat poslední umístÄ›ní pouze po dobu trvání session ... ... Default &location Výchozí &umístÄ›ní Lan&guage Jazyk Automatic &updates Automatické &aktualizace enabled povoleno Show remote options Zobrazit vzdálené možnosti &Database &Databáze Database &encoding Kódování &databáze Open databases with foreign keys enabled. OtevÅ™e databázi s povolenými cizími klíÄi. &Foreign keys &Cizí klíÄe SQ&L to execute after opening database SQ&L k vykonání po otevÅ™ení databáze Data &Browser ProhlížeÄ Dat Remove line breaks in schema &view Prefetch block si&ze Default field type Výchozí typ pole Font Font &Font &Font Content Obsah Symbol limit in cell Maximální poÄet znaků v buňce NULL NULL Regular Regulární Binary Binární Background Pozadí Filters Filtry Threshold for completion and calculation on selection Show images in cell Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Escape character Delay time (&ms) ZpoždÄ›ní (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. &SQL &SQL Context Kontext Colour Barva Bold TuÄný Italic Kurzíva Underline Podtržený Keyword KlíÄové slovo Function Funkce Table Tabulka Comment Komentář Identifier Identifikátor String String Current line Aktuální řádek SQL &editor font size velikost fontu SQL &editoru Tab size SQL editor &font &font SQL editoru Error indicators Hori&zontal tiling If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Code co&mpletion Toolbar style Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style DB file extensions Manage Main Window Database Structure Databázová Struktura Browse Data Prohlížet data Execute SQL ProveÄte SQL Edit Database Cell When this value is changed, all the other color preferences are also set to matching colors. Follow the desktop style Dark style Application style This sets the font size for all UI elements which do not have their own font size option. Font size Max Recent Files Prompt to save SQL tabs in new project file If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Database structure font size Font si&ze Velikost písma This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Field display Light style Displayed &text Formatted Click to set this color Text color Barva textu Background color Barva pozadí Preview only (N/A) Foreground PopÅ™edí Selection background Selection foreground Highlight SQL &results font size Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. &Wrap lines Never Nikdy At word boundaries At character boundaries At whitespace boundaries &Quotes for identifiers Choose the quoting mechanism used by the application for identifiers in SQL code. "Double quotes" - Standard SQL (recommended) `Grave accents` - Traditional MySQL quotes [Square brackets] - Traditional MS SQL Server quotes Keywords in &UPPER CASE When set, the SQL keywords are completed in UPPER CASE letters. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Close button on tabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. &Extensions &Rozšíření Select extensions to load for every database: Vyberte rozšíření k naÄtení pro každou databázi: Add extension PÅ™idat rozšíření Remove extension Odebrat rozšíření Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> Disable Regular Expression extension Zakázat rozšíření pro regulární výrazy <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> Allow loading extensions from SQL code Remote Vzdálený CA certificates certifikáty CA Proxy Configure Export Settings Import Settings Subject CN pÅ™edmÄ›t CN Common Name Subject O pÅ™edmÄ›t O Organization Organizace Valid from Platné od Valid to Platné do Serial number Sériové Äíslo Your certificates VaÅ¡e certifikáty File Soubor Subject Common Name Issuer CN Issuer Common Name Clone databases into Choose a directory Vyberte složku The language will change after you restart the application. Jazyk bude zmÄ›nÄ›n po restartu aplikace. Select extension file Vybrat soubor rozšíření Extensions(*.so *.dylib *.dll);;All files(*) Import certificate file Importovat soubor certifikátu No certificates found in this file. V tomto souboru nebyly nalezeny žádné certifikáty. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Opravdu chcete smazat tento certifikát? VÅ¡echny data certifikátu budou smazány z nastavení aplikace! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Save Settings File Initialization File (*.ini) The settings file has been saved in location : Open Settings File The settings file was loaded properly. The selected settings file is not a normal settings file. Please check again. ProxyDialog Proxy Configuration Pro&xy Type Host Na&me Port Authentication Re&quired &User Name Password None Žádná System settings HTTP SOCKS5 QObject Error importing data Chyba pÅ™i importu dat from record number %1 ze záznamu Äíslo %1 . %1 . %1 Importing CSV file... Cancel ZruÅ¡it All files (*) VÅ¡echny soubory (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Left Right Center Justify SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) SQL Files (*.sql) All Files (*) Text Files (*.txt) Comma-Separated Values Files (*.csv) Tab-Separated Values Files (*.tsv) Delimiter-Separated Values Files (*.dsv) Concordance DAT files (*.dat) JSON Files (*.json *.js) XML Files (*.xml) Binary Files (*.bin *.dat) SVG Files (*.svg) Hex Dump Files (*.dat *.bin) Extensions (*.so *.dylib *.dll) Initialization File (*.ini) QsciCommand Paste Vložit Cancel ZruÅ¡it QsciLexerCPP Default Výchozí Keyword KlíÄové slovo Identifier Identifikátor QsciLexerJSON Default Výchozí String String QsciLexerPython Default Výchozí Comment Komentář Keyword KlíÄové slovo Identifier Identifikátor QsciLexerSQL Default Výchozí Comment Komentář Keyword KlíÄové slovo Identifier Identifikátor QsciScintilla Select All Vybrat vÅ¡e RemoteCommitsModel Commit ID Message Date Datum Author Size Velikost Authored and committed by %1 Authored by %1, committed by %2 RemoteDatabase Error opening local databases list. %1 Error creating local databases list. %1 RemoteDock Remote Vzdálený Identity Push currently opened database to server Upload DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> Local Current Database Clone &User &Database &Databáze Branch VÄ›tev Commits Commits for <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> Back Delete Database Delete the local clone of this database Open in Web Browser Open the web page for the current database in your browser Clone from Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. Refresh Obnovit Reload all data and update the views Clone Database Open Database Open the local copy of this database Check out Commit Download and open this specific commit Check out Latest Commit Check out the latest commit of the current branch Save Revision to File Saves the selected revision of the database to another file Upload Database Upload this database as a new commit Select an identity to connect Public VeÅ™ejný This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Invalid URL: The host name does not match the host name of the current identity. Invalid URL: No branch name specified. Invalid URL: No commit ID specified. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? The database has unsaved changes. Are you sure you want to push it before saving? The database you are trying to delete is currently opened. Please close it before deleting. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? RemoteLocalFilesModel Name Název Branch VÄ›tev Last modified Poslední zmÄ›nÄ›né Size Velikost Commit File Soubor RemoteModel Name Název Last modified Poslední zmÄ›nÄ›né Size Velikost Commit Size: Last Modified: Licence: Default Branch: RemoteNetwork Choose a location to save the file Error opening remote file at %1. %2 Error: Invalid client certificate specified. Please enter the passphrase for this client certificate in order to authenticate. Cancel ZruÅ¡it Uploading remote database to %1 Nahrávám vzdálenou databázi do %1. {1?} Downloading remote database from %1 Stahuji vzdálenou databázi z %1. {1?} Error: Cannot open the file for sending. Chyba: Nemohu otevřít soubor k odeslání. RemotePushDialog Push database Database na&me to push to Commit message Database licence Public VeÅ™ejný Branch VÄ›tev Force push Username Database will be public. Everyone has read access to it. Database will be private. Only you have access to it. Use with care. This can cause remote commits to be deleted. RunSql Execution aborted by user , %1 rows affected , %1 řádků bylo ovlivnÄ›no query executed successfully. Took %1ms%2 executing query SelectItemsPopup A&vailable Sele&cted SqlExecutionArea Form Formulář Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 The found pattern must be a whole word Whole Words Celá slova Text pattern to find considering the checks in this frame Find in editor Najít v editoru The found pattern must match in letter case Case Sensitive Find next match [Enter, F3] Find next match with wrapping F3 Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Regulární výraz Close Find Bar Zavřít liÅ¡tu pro hledání <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> Results of the last executed statements Výsledky naposledy provedených příkazů This field shows the results and status codes of the last executed statements. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Couldn't save file: %1. Your changes will be lost when reloading it! The file "%1" was modified by another program. Do you want to reload it?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) odstraní mezery z levé strany X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) Funkce s více parametry min() vrací parametr s minimální hodnotou. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) Funkce nullif(X,Y) vrací první parametr, pokud jsou parametry odliÅ¡né. NULL vrací, pokud jsou parametry stejné. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () Funkce random() vrací pseudo-náhodný integer v rozmezí -9223372036854775808 a +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X) rtrim(X) removes spaces from the right side of X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. (X) trim(X) removes spaces from both ends of X. (X) trim(X) odstraní mezery z obou stran X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) AgregaÄní funkce max() vrací maximální hodnotu ze vÅ¡ech hodnot ve skupinÄ›. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) AgregaÄní funkce min() vrací minimální hodnotu ze vÅ¡ech hodnot ve skupinÄ›, která není NULL. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) AgregaÄní funkce sum() a total() vrací souÄet vÅ¡ech hodnot ve skupinÄ›, které nejsou NULL. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. SqliteTableModel reading rows Ätení sloupců loading... naÄítání... References %1(%2) Hold %3Shift and click to jump there Error changing data: %1 Chyba pÅ™i zmÄ›nÄ› dat: %1 retrieving list of columns Fetching data... NaÄítám data... Cancel ZruÅ¡it TableBrowser Browse Data Prohlížet data &Table: &Tabulka: Select a table to browse data Vyberte tabulku pro prohlížení dat Use this list to select a table to be displayed in the database view Pro zobrazení v databázovém pohledu použijte pro výbÄ›r tabulky tento seznam This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Text pattern to find considering the checks in this frame Find in table Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 Find next match [Enter, F3] Find next match with wrapping F3 The found pattern must match in letter case Case Sensitive The found pattern must be a whole word Whole Cell Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Regulární výraz Close Find Bar Zavřít liÅ¡tu pro hledání Text to replace with Replace with Replace next match Replace Replace all matches Replace all Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Copy column name Copy the database table column name to your clipboard New Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Posune na úplný zaÄátek</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Kliknutím na toto tlaÄítko se pÅ™esunete na zaÄátek pohledu tabulky výše.</p></body></html> |< |< Scroll one page upwards <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> < < 0 - 0 of 0 0 - 0 z 0 Scroll one page downwards <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> > > Scroll to the end Posunout na konec <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>Kliknutím zde pÅ™eskoÄíte na urÄený záznam</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Toto tlaÄítko je urÄeno k navigaci k záznamu, jehož Äíslo je nastaveno v poli Jít na.</p></body></html> Go to: Jít na: Enter record number to browse Vložte Äíslo záznamu pro jeho procházení Type a record number in this area and click the Go to: button to display the record in the database view NapiÅ¡tÄ› Äíslo záznamu do tohoto pole a kliknÄ›te na Jít na: tlaÄítko k zobrazení záznamu v pohledu databáze 1 1 Show rowid column Zobrazit rowid sloupce Toggle the visibility of the rowid column PÅ™epnout viditelnost rowid sloupců Unlock view editing This unlocks the current view for editing. However, you will need appropriate triggers for editing. Edit display format Upravit formát zobrazení Edit the display format of the data in this column Upravit formát zobrazení dat v tomto sloupci New Record Nový záznam Insert a new record in the current table Vložit nový záznam do souÄasné tabulky <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> Delete Record Smazat záznam Delete the current record Smazat aktuální záznam This button deletes the record or records currently selected in the table Insert new record using default values in browsed table Insert Values... Vložit hodnoty... Open a dialog for inserting values in a new record Export to &CSV Export do CSV Export the filtered data to CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Save as &view Uložit jako pohled Save the current filter, sort column and display formats as a view This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Save Table As... Save the table as currently displayed <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> Hide column(s) Skrýt sloupec(ce) Hide selected column(s) Skrýt vybraný sloupec(ce) Show all columns Zobrazit vÅ¡echny sloupce Show all columns that were hidden Set encoding Nastavit kódování Change the encoding of the text in the table cells ZmÄ›nit kódování textu v buňkách tabulky Set encoding for all tables Nastavit kódování pro vÅ¡echny tabulky Change the default encoding assumed for all tables in the database Clear Filters Clear all filters Vymazat vÅ¡echny filtry This button clears all the filters set in the header input fields for the currently browsed table. Clear Sorting Reset the order of rows to the default This button clears the sorting columns specified for the currently browsed table and returns to the default order. Print Tisk Print currently browsed table data Tisk právÄ› prohlížených dat tabulky Print currently browsed table data. Print selection if more than one cell is selected. Ctrl+P Refresh Obnovit Refresh the data in the selected table This button refreshes the data in the currently selected table. Toto tlaÄítko obnoví data v aktuálnÄ› vybrané tabulce. F5 Find in cells Open the find tool bar which allows you to search for values in the table view below. Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally Bold TuÄný Ctrl+B Italic Kurzíva Underline Podtržený Ctrl+U Align Right Align Left Center Horizontally Justify Edit Conditional Formats... Edit conditional formats for the current column Clear Format Clear All Formats Clear all cell formatting from selected cells and all conditional formats from selected columns Font Color Background Color Toggle Format Toolbar Show/hide format toolbar This button shows or hides the formatting toolbar of the Data Browser Select column Ctrl+Space Replace text in cells Filter in any column Ctrl+R %n row(s) , %n column(s) . Sum: %1; Average: %2; Min: %3; Max: %4 Conditional formats for "%1" determining row count... %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Delete Records Duplicate records Duplicate record Ctrl+" Adjust rows to contents Error deleting record: %1 Chyba pÅ™i mazání záznamu: %1 Please select a record first Prosím vyberte záznam jako první Please choose a new encoding for all tables. Vyberte nové kódování pro vÅ¡echny tabulky, prosím. Please choose a new encoding for this table. Vyberte nové kódování pro tuto tabulku, prosím. %1 Leave the field empty for using the database encoding. %1 Pro použití kódování databáze ponechte pole prázdné. This encoding is either not valid or not supported. Toto kódování není buÄ platné, nebo podporováno. %1 replacement(s) made. TableBrowserDock New Data Browser Rename Data Browser Close Data Browser Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. VacuumDialog Compact Database Compact Database Warning: Compacting the database will commit all of your changes. Varování: Procesem 'compact the database' budou aplikovány vÅ¡echny vaÅ¡e provedené zmÄ›ny. Please select the databases to co&mpact: Prosím vyberte databázi pro proces 'compact': sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_de.ts000066400000000000000000014033701463772530400251750ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Über DB-Browser für SQLite Version Version <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> <html><head/><body><p>DB-Browser für SQLite ist eine freie Open-Source-Anwendung mit GUI zum Erstellen, Entwerfen und Bearbeiten von SQLite-Datenbanken.</p><p>Die Anwendung ist sowohl unter der Mozilla Public License Version 2 als auch der GNU General Public License Version 3 or later verfügbar. Modifikationen oder Weitergabe sind unter Beachtung der Bedingungen dieser Lizenzen möglich.</p><p>Siehe <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> und <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> für Details.</p><p>Weitere Informationen über diese Anwendung gibt es auf unserer Webseite: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Diese Software verwendet das Qt-Toolkit unter der GPL/LGPL Qt Toolkit, welches unter </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a> verfügbar ist. <span style=" font-size:small;"><br/>Zugehörige Lizenzbedingungen und Informationen gibt es unter </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"></span></p><p><span style=" font-size:8pt;">Wir verwenden die nalgeon/sqlean-Bibliothek für die Unterstützung von SQLite-Erweiterungen.<br/>Diese Bibliothek ist unter der MIT license verfügbar; mehr Informationen gibt es unter:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">Zudem wird das Pastel SVG Iconset von Michael Buckley verwendet, das unter der Creative Commons Attribution Share Alike 4.0 Lizenz steht.<br/>Siehe </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> für weitere Details.</span></p></body></html> AddRecordDialog Add New Record Neue Zeile hinzufügen Enter values for the new record considering constraints. Fields in bold are mandatory. Geben Sie Werte für die neue Zeile unter Beachtung der Beschränkungen ein. Fette Felder sind Pflichtfelder. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. In der Wertspalte können Sie den Wert für das durch die Namensspalte identifizierte Feld angeben. Die Typspalte zeigt den Feldtyp an. Standardwerte werden im Stil von NULL-Werten angezeigt. Name Name Type Typ Value Wert Values to insert. Pre-filled default values are inserted automatically unless they are changed. Einzufügende Werte. Vorausgefüllte Standardwerte werden automatisch eingefügt, sofern sie nicht geändert wurden. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Wenn Sie die Werte im oberen Teil ändern, wird hier die SQL-Abfrage für das Einfügen der neuen Zeile angezeigt. Sie können die Abfrage vor dem Speichern manuell bearbeiten. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Speichern</span> wird die dargestellte SQL-Anweisung zum Einfügen des neuen Eintrags an die Datenbank übermitteln.</p><p><span style=" font-weight:600;">Voreinstellungen</span> wird die ursprünglichen Werte der Spalte <span style=" font-weight:600;">Wert</span> wiederherstellen.</p><p><span style=" font-weight:600;">Abbrechen</span> schließt diesen Dialog, ohne die Abfrage auszuführen.</p></body></html> Auto-increment Auto-Inkrement Unique constraint Unique-Beschränkungen Check constraint: %1 Prüfungsbeschränkung: %1 Foreign key: %1 Fremdschlüssel: %1 Default value: %1 Standardwert: %1 Error adding record. Message from database engine: %1 Fehler beim Hinzufügen der Zeile. Mitteilung der Datenbank-Engine: %1 Are you sure you want to restore all the entered values to their defaults? Sind Sie sicher, dass Sie alle eingegebenen Werte auf ihre Standardwerte zurücksetzen möchten? Application Possible command line arguments: Mögliche Kommandozeilen-Argumente: The -o/--option and -O/--save-option options require an argument in the form group/setting=value Die Optionen -o/--option und -O/--save-option benötigen ein Argument der Form Gruppe/Einstellung=Wert The user settings file location is replaced with the argument value instead of the environment variable value. Der Dateipfad der Benutzereinstellungen wird mit dem übergebenen Argument statt der Umgebungsvariable ersetzt. Ignored environment variable (DB4S_SETTINGS_FILE) value: Wert der Umgebungsvariable (DB4S_SETTINGS_FILE) ignoriert: The file %1 does not exist Die Datei %1 existiert nicht Usage Verwendung options Optionen database Datenbank project Projekt csv-file CSV-Datei Show command line options Terminaloptionen anzeigen Exit application after running scripts Anwendung nach der Ausführung der Skripte beenden file Datei Execute this SQL file after opening the DB Nach dem Öffnen der Datenbank diese SQL-Datei ausführen Import this CSV file into the passed DB or into a new DB Diese CSV-Datei in die übergebene oder in eine neue Datenbank importieren table Tabelle Browse this table, or use it as target of a data import Diese Tabelle durchsuchen oder als Ziel für einen Datenimport verwenden Open database in read-only mode Datenbank nur für den Lesezugriff öffnen settings_file datei_mit_einstellungen Run application based on this settings file Anwendung mit dieser Einstellungsdatei ausführen group Gruppe settings Einstellungen value Wert Run application with this setting temporarily set to value Anwendung mit dem temporär angepassten Einstellungswert ausführen Run application saving this value for this setting Anwendung mit dem angepassten Einstellungswert ausführen und die Einstellung dauerhaft speichern Display the current version Die aktuelle Version anzeigen Open this SQLite database Diese SQLite-Datenbank öffnen Open this project file (*.sqbpro) Diese Projektdatei öffnen (*.sqbpro) Import this CSV file into an in-memory database Diese CSV-Datei in eine In-Memory-Datenbank importieren The %1 option requires an argument Die Option %1 benötigt ein Argument The -S/--settings option requires an argument. The option is ignored. Die Option -S/--settings benötigt ein Argument. Diese Option wird ignoriert. SQLite Version SQLite-Version SQLCipher Version %1 (based on SQLite %2) SQLCipher Version %1 (basierend auf SQLite %2) DB Browser for SQLite Version %1. DB-Browser für SQLite Version %1. Last commit hash when built: %1 Letzter Commit-Hash des Builds: %1 Built for %1, running on %2 Erstellt für %1, laufend unter %2 Qt Version %1 Qt Version %1 Invalid option/non-existent file: %1 Ungültige Option/nicht vorhandene Datei: %1 CipherDialog SQLCipher encryption SQLCipher-Verschlüsselung &Password &Passwort &Reenter password Passwort wiede&rholen Encr&yption settings &Verschlüsselungs-Einstellungen SQLCipher &3 defaults SQLCipher &3-Standardwerte SQLCipher &4 defaults SQLCipher &4-Standardwerte Custo&m &Benutzerdefiniert Page si&ze Seiten&größe &KDF iterations &KDF-Iterationen HMAC algorithm HMAC-Algorithmus KDF algorithm KDF-Algorithmus Plaintext Header Size Reintext-Headergröße Passphrase Passphrase Raw key Originalschlüssel Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Setzen Sie bitte einen Schlüssel zum Verschlüsseln der Datenbank. Beachten Sie, dass bei Änderung der optionalen Einstellungen diese bei jedem Öffnen der Datenbankdatei eingegeben werden müssen. Lassen Sie die Passwortfelder leer, um die Verschlüsselung zu deaktivieren. Der Verschlüsselungsprozess benötigt unter Umständen ein bisschen Zeit und Sie sollten ein Backup-Kopie Ihrer Datenbank haben! Ungespeicherte Änderungen werden vor der Änderung der Verschlüsselung übernommen. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Geben Sie bitte den zur Verschlüsselung der Datenbank genutzten Schlüssel ein. Wenn weitere Einstellungen für diese Datenbankdatei vorgenommen worden sind, müssen Sie diese Informationen zusätzlich angeben. ColumnDisplayFormatDialog Choose display format Anzeigeformat auswählen Display format Anzeigeformat Choose a display format for the column '%1' which is applied to each value prior to showing it. Wählen Sie ein Anzeigeformat für die Spalte '%1', das bei der Anzeige eines jeden Wertes angewendet wird. Default Voreinstellung Decimal number Dezimalzahl Exponent notation Exponentennotation Hex blob Hex-Blob Hex number Hexwert Apple NSDate to date Apple NSDate zu Datum Java epoch (milliseconds) to date Java-Epoche (Millisekunden) zu Datum .NET DateTime.Ticks to date .NET DateTime.Ticks zu Datum Julian day to date Julianischer Tag zu Datum Unix epoch to local time Unix-Epoche zu lokaler Zeit WebKit / Chromium epoch to date WebKit-/Chromium-Epoche zu Datum WebKit / Chromium epoch to local time WebKit-/Chromium-Epoche zu lokaler Zeit Date as dd/mm/yyyy Datum als dd/mm/yyyy Lower case Kleinschreibung Binary GUID to text Binäre GUID zu Text SpatiaLite Geometry to SVG SpatiaLite-Geometrie zu SVG Custom display format must contain a function call applied to %1 Benutzerdefinierte Darstellungsformate benötigen einen Funktionsaufruf, der auf %1 angewendet wird Error in custom display format. Message from database engine: %1 Fehler im benutzerdefinierten Anzeigeformat. Meldung von Datenbank: %1 Custom display format must return only one column but it returned %1. Das benutzerdefinierte Anzeigeformat darf nur eine Spalte zurückgeben, es wurde aber %1 zurückgegeben. Octal number Oktalwert Round number Gerundeter Wert Unix epoch to date Unix-Epoche zu Datum Upper case Großschreibung Windows DATE to date Windows DATUM zu Datum Custom Benutzerdefiniert CondFormatManager Conditional Format Manager Verwaltung für bedingte Formatierung This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Dieser Dialog erlaubt das Erstellen und Bearbeiten bedingter Formatierungen. Jeder Zellenstil wird anhand der ersten erfüllten Bedingung für diese Zelldaten ausgewählt. Bedingte Formatierungen können nach oben und unten bewegt werden, wobei jene weiter oben Vorrang vor jenen weiter unten haben. Die Syntax für Bedingungen ist die gleiche wie bei Filtern und eine leere Bedingung trifft auf alle Werte zu. Add new conditional format Neue bedingte Formatierung hinzufügen &Add &Hinzufügen Remove selected conditional format Ausgewählte bedingte Formatierung entfernen &Remove &Entfernen Move selected conditional format up Ausgewählte bedingte Formatierung nach oben bewegen Move &up Nach &oben Move selected conditional format down Ausgewählte bedingte Formatierung nach unten bewegen Move &down Nach &unten Foreground Vordergrund Text color Textfarbe Background Hintergrund Background color Hintergrundfarbe Font Schrift Size Größe Bold Fett Italic Kursiv Underline Unterstreichung Alignment Ausrichtung Condition Bedingung Click to select color Zur Auswahl der Farbe klicken Are you sure you want to clear all the conditional formats of this field? Sollen wirklich alle bedingten Formatierungen dieses Felds gelöscht werden? DBBrowserDB Please specify the database name under which you want to access the attached database Geben Sie bitte einen Datenbanknamen an, mit dem Sie auf die anhängte Datenbank zugreifen möchten Invalid file format Ungültiges Dateiformat Do you want to save the changes made to the database file %1? Sollen die getätigten Änderungen an der Datenbankdatei %1 gespeichert werden? Exporting database to SQL file... Datenbank in SQL-Datei exportieren... Cancel Abbrechen Executing SQL... SQL ausführen... Action cancelled. Vorgang abgebrochen. Do you really want to close this temporary database? All data will be lost. Möchten Sie diese temporäre Datenbank wirklich schließen? Alle Daten gehen damit verloren. Database didn't close correctly, probably still busy Datenbank wurde nicht richtig geschlossen, vermutlich noch in Bearbeitung Cannot open destination file: '%1' Zieldatei kann nicht geöffnet werden: '%1' Cannot backup to file: '%1'. Message: %2 Erstellung des Backups in Datei '%1' nicht möglich. Mitteilung: %2 The database is currently busy: Die Datenbank ist zur Zeit beschäftigt: Do you want to abort that other operation? Möchten Sie die andere Operation abbrechen? No database file opened Keine Datenbankdatei geöffnet Error in statement #%1: %2. Aborting execution%3. Fehler in der Anweisung #%1: %2. Ausführung wird abgebrochen %3. and rolling back und der Zustand zurückgesetzt didn't receive any output from %1 keine Ausgabe von %1 erhalten could not execute command: %1 Befehl konnte nicht ausgeführt werden: %1 Cannot delete this object Dieses Objekt kann nicht gelöscht werden Cannot set data on this object Daten können für dieses Objekt nicht gesetzt werden A table with the name '%1' already exists in schema '%2'. Es existiert eine Tabelle mit dem Namen '%1' im Schema '%2'. No table with name '%1' exists in schema '%2'. Im Schema '%2' existiert keine Tabelle mit dem Namen '%1'. Cannot find column %1. Spalte %1 kann nicht gefunden werden. Creating savepoint failed. DB says: %1 Erstellung des Sicherungspunktes fehlgeschlagen. DB meldet: %1 Renaming the column failed. DB says: %1 Umbenennung der Spalte fehlgeschlagen. DB meldet: %1 Releasing savepoint failed. DB says: %1 Entsperren des Sicherungspunktes fehlgeschlagen. DB meldet: %1 Creating new table failed. DB says: %1 Erstellen der neuen Tabelle ist fehlgeschlagen. DB meldet: %1 Copying data to new table failed. DB says: %1 Kopieren der Daten zur neuen Tabelle ist fehlgeschlagen. DB meldet: %1 Deleting old table failed. DB says: %1 Löschen der alten Tabelle ist fehlgeschlagen. DB meldet: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 Fehler beim Umbenennen der Tabelle '%1' zu '%2'. Meldung von Datenbank: %3 could not get list of db objects: %1 Liste der DB-Objekte konnte nicht abgefragt werden: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Wiederherstellung einiger mit dieser Tabelle verbundener Objekte fehlgeschlagen. Dies passiert häufig durch geänderte Spaltennamen. SQL-Anweisung zum manuellen Reparieren und Ausführen: could not get list of databases: %1 konnte keine Datenbankliste abrufen: %1 Error loading extension: %1 Fehler beim Laden der Erweiterung: %1 Error loading built-in extension: %1 Fehler beim Laden der eingebauten Erweiterung: %1 could not get column information Spalteninformationen konnten nicht ermittelt werden Error setting pragma %1 to %2: %3 Fehler beim Setzen des Pragmas %1 auf %2: %3 File not found. Datei nicht gefunden. DbStructureModel Name Name Object Objekt Type Typ Schema Schema Database Datenbank Browsables Durchsuchbar All Alle Temporary Temporär Tables (%1) Tabellen (%1) Indices (%1) Indizes (%1) Views (%1) Ansichten (%1) Triggers (%1) Trigger (%1) EditDialog Edit database cell Datenbankzelle bearbeiten Mode: Modus: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Dies ist die Liste der unterstützten Modi des Zelleneditors. Wählen Sie einen Modus für die Anzeige oder Bearbeitung der Daten der aktuellen Zelle aus. RTL Text RTL-Text Image Bild JSON JSON XML XML Evaluation Auswertung Automatically adjust the editor mode to the loaded data type Den Editormodus automatisch dem geladenen Datentyp anpassen This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Dieser Button aktiviert oder deaktiviert den automatischen Wechsel des Editormodus. Wenn eine neue Zelle ausgewählt wird oder neue Daten importiert werden und der automatische Wechsel aktiviert ist, passt sich der Modus dem erkannten Datentyp an. Sie können den Editormodus danach manuell ändern. Wenn Sie dies bei der Bewegung durch die Zellen im manuell eingestellten Modus behalten möchten, deaktivieren Sie den Button. Auto-switch Auto-Wechsel This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Dieser Qt-Editor wird für Rechts-nach-Links-Skripte verwendet, die vom Standard-Texteditor nicht unterstützt werden. Das Vorhandensein von Rechts-nach-Links-Zeichen wird erkannt und dieser Editormodus wird automatisch ausgewählt. Identification of the cell currently in the editor Zuordnung der aktuell im Editor angezeigten Zelle Type and size of data currently in table Typ und Größe der aktuellen Tabellendaten Open preview dialog for printing the data currently stored in the cell Vorschau-Dialog öffnen, um die aktuell in der Zelle gespeicherten Daten auszugeben Auto-format: pretty print on loading, compact on saving. Auto-Format: Druckoptimierung (Pretty Print) beim Laden, kompakt beim Speichern. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Wenn aktiviert, formatiert die Auto-Format-Funktion die Daten beim Laden, bricht den Text in Zeilen und rückt ihn für maximale Lesbarkeit ein. Beim Speichern der Daten verdichtet die Auto-Format-Funktion die Daten durch das Entfernen der Zeilenumbrüche und unnötigen Leerzeichen. Word Wrap Wortumbrüche Wrap lines on word boundaries Zeilen an Wortgrenzen umbrechen Open in default application or browser Mit der Standardanwendung oder dem Browser öffnen Open in application Mit Anwendung öffnen The value is interpreted as a file or URL and opened in the default application or web browser. Der Wert wird als Datei oder URL interpretiert und mit der Standardanwendung oder dem Webbrowser geöffnet. Save file reference... Dateireferenz speichern... Save reference to file Referenz in Datei speichern Open in external application Mit externer Anwendung öffnen Autoformat Auto-Format &Export... &Exportieren... &Import... &Importieren... Import from file Aus Datei importieren Opens a file dialog used to import any kind of data to this database cell. Öffnet einen Dateidialog, um beliebige Daten in diese Datenbankzelle zu importieren. Export to file In Datei exportieren Opens a file dialog used to export the contents of this database cell to a file. Öffnet einen Dateidialog, um den Inhalt dieser Datenbankzelle in eine Datei zu exportieren. Print... Drucken... Ctrl+P Open preview dialog for printing displayed text Vorschaudialog zum Drucken des angezeigten Textes öffnen Copy Hex and ASCII Hex und ASCII kopieren Copy selected hexadecimal and ASCII columns to the clipboard Ausgewählte hexadezimale und ASCII-Spalten in die Zwischenablage kopieren Ctrl+Shift+C Set as &NULL Auf &NULL setzen Apply data to cell Daten auf Zelle anwenden This button saves the changes performed in the cell editor to the database cell. Dieser Button speichert die im Zelleneditor für die Datenbankzelle durchgeführten Änderungen. Apply Übernehmen Text Text Binary Binär Erases the contents of the cell Löscht den Inhalt der Zelle This area displays information about the data present in this database cell Dieser Bereich stellt Informationen über die Daten in dieser Datenbankzelle dar Choose a filename to export data Dateinamen für den Datenexport wählen Image data can't be viewed in this mode. In diesem Modus können keine Bilddaten angezeigt werden. Try switching to Image or Binary mode. Versuchen Sie, in den Bild- oder Binärmodus zu wechseln. Binary data can't be viewed in this mode. Binärdaten können in diesem Modus nicht angezeigt werden. Try switching to Binary mode. Versuchen Sie, in den Binärmodus zu wechseln. Type: NULL; Size: 0 bytes Typ: NULL; Größe: 0 Bytes Type: Text / Numeric; Size: %n character(s) Typ: Text / Numerisch; Größe: %n Zeichen Typ: Text / Numerisch; Größe: %n Zeichen Type: %1 Image; Size: %2x%3 pixel(s) Typ: %1-Bild; Größe: %2x%3 Pixel Type: Valid JSON; Size: %n character(s) Typ: Gültiges JSON; Größe: %n Zeichen Typ: Gültiges JSON; Größe: %n Zeichen Type: Binary; Size: %n byte(s) Typ: Binär; Größe: %n Byte Typ: Binär: Größe: %n Bytes Couldn't save file: %1. Datei konnte nicht gespeichert werden: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Die Daten wurden in einer temporären Datei gespeichert und mit der Standardanwendung geöffnet. Diese kann nun bearbeitet werden und am Ende entweder durch Speichern in die Zelle übernommen oder der Vorgang abgebrochen werden. Image files (%1) Bilddateien (%1) Binary files (*.bin) Binärdateien (*.bin) Choose a file to import Datei für Import auswählen The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Die Texteditor-Modi erlauben das Bearbeiten von Reintext sowie JSON- und XML-Daten mit Syntaxhervorhebung, automatischer Formatierung und Validierung vor dem Speichern. Fehler werden mittels einer roten Wellenlinie markiert. Im Auswertungsmodus werden eingegebene SQLite-Ausdrücke ausgewertet und das Ergebnis auf die Zelle angewendet. Unsaved data in the cell editor Ungespeicherte Änderungen im Zelleneditor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Der Zelleneditor enthält Daten, die noch nicht auf die Datenbank angewendet wurden. Sollen die bearbeiteten Daten auf Zeile=%1, Spalte=%2 angewendet werden? Editing row=%1, column=%2 Bearbeite Zeile=%1, Spalte=%2 No cell active. Keine Zelle aktiv. %1 Image %1 Bild Invalid data for this mode Ungültige Daten für diesen Modus The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? Die Zelle enthält ungültige %1-Daten. Grund: %2. Möchten Sie diese wirklich auf die Zelle anwenden? EditIndexDialog &Name &Name Order Sortierung &Table &Tabelle Edit Index Schema Index-Schema bearbeiten &Unique Einde&utig For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Zum Einschränken des Index auf einen Teil der Tabelle kann hier eine WHERE-Klausel angegeben werden, die den Teil der Tabelle auswählt, der indexiert werden soll Partial inde&x clause Teilinde&x-Klausel Colu&mns &Spalten Table column Tabellenspalte Type Typ Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Fügt eine neue Ausdrucksspalte zum Index hinzu. Ausdrucksspalten enthalten SQL-Ausdrücke statt Spaltennamen. Index column Indexspalte Deleting the old index failed: %1 Löschen des alten Index fehlgeschlagen: %1 Creating the index failed: %1 Erstellen des Index fehlgeschlagen: %1 EditTableDialog Edit table definition Tabellen-Definition bearbeiten Table Tabelle Advanced Erweitert Without Rowid Ohne Rowid Fields Felder Database sche&ma Datenbanksche&ma Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. Diese Tabelle zu "WITHOUT ROWID" umwandeln. Das Setzen dieses Flags erfordert die Angabe eines Primärschlüssels (welcher jeglichen Typ haben und auch zusammengesetzt sein darf), schließt aber das AUTOINCREMENT-Flag aus. On Conflict ON CONFLICT Strict Strikt When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Wenn die Strikt-Option aktiviert ist, erzwingt SQLite den jeweiligen Datentyp der Spalte beim Aktualisieren oder Einfügen von Daten. Add Hinzufügen Remove Entfernen Move to top Zum Beginn Move up Nach oben Move down Nach unten Move to bottom Zum Ende Name Name Type Typ NN NN Not null Nicht Null PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> Primärschlüssel</p></body></html> AI AI Autoincrement Autoinkrement U Unique Eindeutig Default Voreinstellung Default value Voreingestellter Wert Check Prüfen Check constraint Beschränkung prüfen Collation Kollation Foreign Key Fremdschlüssel <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> Fremdschlüssel</p></body></html> Index Constraints Index-Beschränkungen Add constraint Beschränkung hinzufügen Remove constraint Beschränkung entfernen Columns Spalten SQL SQL Foreign Keys Fremdschlüssel References Referenzen Check Constraints CHECK-Beschränkungen <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style="font-weight:600; color:#ff0000;">Warnung: </span>Diese Tabellendefinition enthält Elemente, die unser Parser nicht vollständig versteht. Das Ändern und Speichern der Tabelle kann zu Problemen führen.</p></body></html> Primary Key Primärschlüssel Add a primary key constraint Eine Beschränkung für den Primärschlüssel hinzufügen Add a unique constraint Eine Unique-Beschränkung hinzufügen Error creating table. Message from database engine: %1 Fehler beim Erstellen der Tabelle. Meldung der Datenbank: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Es existiert bereits ein Feld mit diesem Namen. Bitte benennen Sie es zunächst um oder wählen Sie einen anderen Namen für dieses Feld. There can only be one primary key for each table. Please modify the existing primary key instead. Es kann nur einen Primärschlüssel für jede Tabelle geben. Bitte stattdessen den existierenden Primärschlüssel bearbeiten. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Diese Spalte wird in einem Fremdschlüssel in Tabelle %1 referenziert und kann aus diesem Grund nicht geändert werden. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Mindestens eine Reihe enthält ein Feld mit dem Wert NULL. Dies verhindert das Setzen dieser Markierung. Bitte zunächst die Tabellendaten ändern. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Mindestens eine Reihe enthält ein Feld mit einem nicht ganzzahligen Wert. Dies verhindert das Setzen der AI-Markierung. Bitte zunächst die Tabellendaten ändern. Column '%1' has duplicate data. Spalte '%1' hat doppelte Daten. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Dies macht das Aktivieren des Flags 'Unique' unmöglich. Bitte die doppelten Daten entfernen, damit das Flag 'Unique' dann aktiviert werden kann. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Soll das Feld '%1' wirklich gelöscht werden? Alle aktuell in diesem Feld gespeicherten Daten gehen verloren. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Bitte fügen Sie vor dem Setzen des Flags "Without rowid" ein Feld hinzu, das folgenden Kriterien entspricht: - Primärschlüssel-Flag gesetzt - Autoinkrement deaktiviert Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set Bitte vor dem Setzen der Konfliktaktion ein Feld hinzufügen, das den folgenden Bedingungen genügt: - Primärschlüssel ist aktiviert ExportDataDialog Export data as CSV Daten als CSV exportieren Tab&le(s) Tabe&lle(n) Colu&mn names in first line &Spaltennamen in der ersten Zeile Fie&ld separator Fe&ld-Separator , , ; ; Tab Tab | | Other Anderer &Quote character &String-Zeichen " " ' ' New line characters Zeilenumbruchs-Zeichen Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print Pretty Print Could not open output file: %1 Ausgabedatei konnte nicht geöffnet werden: %1 Choose a filename to export data Dateinamen für den Datenexport wählen Export data as JSON Daten als JSON exportieren exporting CSV exportiere CSV Error while writing the file '%1': %2 Fehler beim Schreiben in Datei '%1': %2 exporting JSON exportiere JSON Please select at least 1 table. Bitte mindestens eine Tabelle auswählen. Choose a directory Verzeichnis wählen Export completed. Export abgeschlossen. Export finished with errors. Export wurde mit Fehlern beendet. ExportSqlDialog Export SQL... SQL exportieren... Tab&le(s) Tabe&lle(n) Select All Alle auswählen Deselect All Alle abwählen &Options &Optionen Keep column names in INSERT INTO Spaltennamen in INSERT INTO belassen Multiple rows (VALUES) per INSERT statement Mehrere Reihen (VALUES) je INSERT-Anweisung Export everything Alles exportieren Export schema only Nur Schema exportieren Export data only Nur Daten exportieren Keep original CREATE statements Originale CREATE-Anweisungen behalten Keep old schema (CREATE TABLE IF NOT EXISTS) Altes Schema behalten (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Altes Schema überschreiben (DROP TABLE, dann CREATE TABLE) Please select at least one table. Bitte wählen Sie mindestens eine Tabelle aus. Choose a filename to export Dateinamen zum Export auswählen Export completed. Export abgeschlossen. Export cancelled or failed. Export abgebrochen oder fehlgeschlagen. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Suchen... Find and Replace... Suchen und ersetzen... Print... Drucken... ExtendedTableWidget Use as Exact Filter Als exakten Filter verwenden Containing Enthält Not containing Enthält nicht Not equal to Ungleich zu Greater than Größer als Less than Kleiner als Greater or equal Größer oder gleich Less or equal Kleiner oder gleich Between this and... Zwischen diesem und... Regular expression Regulärer Ausdruck Edit Conditional Formats... Bedingte Formatierungen bearbeiten... Set to NULL Auf NULL setzen Cut Ausschneiden Copy Kopieren Copy with Headers Mit Headern kopieren Copy as SQL Als SQL kopieren Paste Einfügen Print... Drucken... Use in Filter Expression Im Filterausdruck verwenden Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? Der Inhalt der Zwischenablage ist größer als der ausgewählte Bereich. Soll er dennoch eingefügt werden? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>Es wurden nicht alle Daten geladen. <b>Sollen vor dem Auswählen aller Zeilen alle Daten geladen werden?</b><p><p>Das Antworten von <b>Nein</b> wird keine weiteren Daten laden und die Auswahl nicht durchführen.</br>Das Antworten von <b>Ja</b> benötigt möglicherweise einige Zeit, während die Daten geladen werden, aber die Auswahl wird vollständig sein.</p>Warnung: Das Laden aller Daten benötigt bei großen Tabellen möglicherweise eine große Menge an Speicher. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. Auswahl kann nicht auf NULL gesetzt. Die Spalte %1 hat eine NOT NULL Beschränkung. FileExtensionManager File Extension Manager Dateierweiterungs-Manager &Up H&och &Down &Runter &Add &Hinzufügen &Remove &Entfernen Description Beschreibung Extensions Erweiterungen *.extension *.erweiterung FilterLineEdit Filter Filtern These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Diese Eingabefelder erlauben Ihnen das Anwenden von schnellen Filtern in der aktuell ausgewählten Tabelle. Standardmäßig werden Zeilen, die den Eingabetext beinhalten, herausgefiltert. Zudem werden die folgenden Operatoren unterstützt: % Wildcard > Größer als < Kleiner als >= Größer oder gleich <= Kleiner oder gleich = Gleich: exakte Übereinstimmung <> Ungleich:exakte inverse Übereinstimmung x~y Bereich: Werte zwischen x und y /regexp/ Werte, die dem regulären Ausdruck genügen Clear All Conditional Formats Alle bedingten Formatierungen löschen Use for Conditional Format Als bedingte Formatierung verwenden Edit Conditional Formats... Bedingte Formatierungen bearbeiten... Set Filter Expression Filterausdruck setzen What's This? Was ist das? Is NULL Ist NULL Is not NULL Ist nicht NULL Is empty Ist leer Is not empty Ist nicht leer Not containing... Enthält nicht... Equal to... Gleich zu... Not equal to... Ungleich zu... Greater than... Größer als... Less than... Kleiner als... Greater or equal... Größer oder gleich... Less or equal... Kleiner oder gleich... In range... Im Bereich... Regular expression... Regulärer Ausdruck... FindReplaceDialog Find and Replace Suchen und Ersetzen Fi&nd text: Text fi&nden: Re&place with: Er&setzen mit: Match &exact case &Exakte Schreibung Match &only whole words Nur &ganze Wörter When enabled, the search continues from the other end when it reaches one end of the page Wenn aktiviert, fährt die Suche am anderen Ende fort, wenn sie das Ende der Seite erreicht hat &Wrap around &Umbrechen When set, the search goes backwards from cursor position, otherwise it goes forward Wenn gesetzt, erfolgt die Suche rückwärts von der Cursorposition, anderenfalls erfolgt sie vorwärts Search &backwards Rück&wärts suchen <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>Wenn ausgewählt, wird das gesuchte Muster nur in der aktuellen Auswahl gesucht.</p></body></html> &Selection only Nur Au&swahl <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Wenn aktiviert, wird das Suchmuster als regulärer Ausdruck (UNIX-Stil) interpretiert. Siehe <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks (englisch)</a>.</p></body></html> Use regular e&xpressions Reguläre A&usdrücke verwenden Find the next occurrence from the cursor position and in the direction set by "Search backwards" Das nächste Auftreten ausgehend von der Cursorposition und in der durch "Rückwärts suchen" gesetzten Richtung finden &Find Next Nächste &finden F3 &Replace &Ersetzen Highlight all the occurrences of the text in the page Alle Auftreten des Textes auf der Seite hervorheben F&ind All Alle f&inden Replace all the occurrences of the text in the page Alle Auftreten des Textes auf der Seite ersetzen Replace &All &Alle ersetzen The searched text was not found Der gesuchte Text wurde nicht gefunden The searched text was not found. Der gesuchte Text wurde nicht gefunden. The searched text was found one time. Der gesuchte Text wurde ein Mal gefunden. The searched text was found %1 times. Der gesuchte Text wurde %1-mal gefunden. The searched text was replaced one time. Der gesuchte Text wurde ein Mal ersetzt. The searched text was replaced %1 times. Der gesuchte Text wurde %1-mal ersetzt. ForeignKeyEditor &Reset Zu&rücksetzen Foreign key clauses (ON UPDATE, ON DELETE etc.) Fremdschlüssel-Klauseln (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Bildanzeige Reset the scaling to match the original size of the image. Skalierung auf Originalgröße des Bildes zurücksetzen. Set the scaling to match the size of the viewport. Skalierung auf Fenstergröße setzen. Print... Drucken... Open preview dialog for printing displayed image Vorschaudialog zum Drucken des angezeigten Bildes öffnen Ctrl+P ImportCsvDialog Import CSV file CSV-Datei importieren Table na&me Tabellenna&me &Column names in first line &Spaltennamen in erster Zeile Field &separator Feld-&Separator , , ; ; Tab Tab | | Other Anderer &Quote character &String-Zeichen Other (printable) Anderer (darstellbar) Other (code) Anderer (Code) " " ' ' &Encoding &Codierung UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? Felder trimmen? Separate tables Tabellen trennen Advanced Erweitert When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Beim Import eines leeren Wertes aus einer CSV-Datei in eine existierende Tabelle mit einem Standardwert für diese Spalte wird dieser Standardwert eingefügt. Aktivieren Sie diese Option, um stattdessen einen leeren Wert einzufügen. Ignore default &values Standard&werte ignorieren Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Aktivieren Sie diese Option, um den Import zu stoppen, wenn ein leerer Wert in eine NOT-NULL-Spalte ohne Standardwert importiert werden soll. Fail on missing values Fehler bei fehlenden Werten Disable data type detection Datentyp-Erkennung deaktivieren Disable the automatic data type detection when creating a new table. Die automatische Datentyperkennung bei der Erstellung einer neuen Tabelle deaktivieren. Use local number conventions Lokale Nummern-Konventionen verwenden Use decimal and thousands separators according to the system locale. Dezimal- und Tausender-Trennzeichen entsprechend der Systemeinstellungen verwenden. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Beim Import von Daten in eine existierende Tabelle mit einem Primärschlüssel, Unique-Beschränkungen oder einem eindeutigen Index besteht die Möglichkeit von Konflikten. Diese Option erlaubt die Auswahl einer Strategie für diesen Fall: Standardmäßig wird der Import abgebrochen und zurückgerollt, aber es besteht auch die Option des Ignorierens und somit Nicht-Importierens in Konflikt stehender Zeilen oder des Ersetzens existierender Zeilen der Tabelle. Abort import Import abbrechen Ignore row Zeile ignorieren Replace existing row Existierende Zeile ersetzen Conflict strategy Konflikt-Strategie Deselect All Alle abwählen Match Similar Ähnliche suchen Select All Alle auswählen There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Es gibt bereits eine Tabelle namens '%1' und ein Import in eine existierende Tabelle ist nur bei übereinstimmender Spaltenanzahl möglich. There is already a table named '%1'. Do you want to import the data into it? Es gibt bereits eine Tabelle namens '%1'. Möchten Sie die Daten in diese importieren? Creating restore point failed: %1 Erstellung des Wiederherstellungspunktes fehlgeschlagen: %1 Creating the table failed: %1 Erstellung der Tabelle fehlgeschlagen: %1 importing CSV importierte CSV Could not prepare INSERT statement: %1 INSERT-Anweisung konnte nicht vorbereitet werden: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Unerwartetes Dateiende. Bitte sicherstellen, dass die korrekten Anführungszeichen gesetzt sind und die Datei wohlgeformt ist. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Import der Datei '%1' benötigte %2 ms. Davon wurden %3 ms in der Zeilenfunktion verbracht. Inserting row failed: %1 Einfügen der Zeile fehlgeschlagen: %1 MainWindow toolBar1 Werkzeugleiste1 Opens the SQLCipher FAQ in a browser window Öffnet die SQLCipher-FAQ in einem Browserfenster Export one or more table(s) to a JSON file Exportiert eine oder mehrere Tabelle(n) in eine JSON-Datei DB Browser for SQLite DB-Browser für SQLite This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Dies ist die Struktur der geöffneten Datenbank. Sie können SQL-Anweisungen aus einer Objektzeile fassen und in anderen Anwendungen oder einer anderen 'DB-Browser für SQLite'-Instanz ablegen. Un/comment block of SQL code Kommentieren/Unkommentieren eines Block von SQL-Code Un/comment block Block kommentieren/unkommentieren Comment or uncomment current line or selected block of code Aktuelle Zeilen oder ausgewählten Codeblock kommentieren oder unkommentieren Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Aktuelle Zeilen oder aktuelle Zeile kommentieren oder unkommentieren, wenn es keine Auswahl gibt. Der gesamte Block wird entsprechend der ersten Zeile invertiert. Ctrl+/ Stop SQL execution SQL-Ausführung abbrechen Stop execution Ausführung abbrechen Stop the currently running SQL script Das aktuelle laufende SQL-Skript stoppen Error Log Fehlerprotokoll &Database Structure This has to be equal to the tab title in all the main tabs &Datenbankstruktur &Browse Data This has to be equal to the tab title in all the main tabs Daten d&urchsuchen Edit P&ragmas This has to be equal to the tab title in all the main tabs P&ragmas bearbeiten E&xecute SQL This has to be equal to the tab title in all the main tabs SQL aus&führen &Recent Files &Kürzliche Dateien &New Database &Neue Datenbank Ctrl+F4 &Undo &Zurücksetzen Undo last change to the database Letzte Datenbankänderung rückgängig machen This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Diese Aktion macht die letzte Änderung an der Datenbank aus "Daten durchsuchen" oder "SQL ausführen" rückgängig. Wiederherstellen ist nicht möglich. Compact &Database... &Datenbank komprimieren... Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Den Dialog zum Ändern der Tabelle öffnen, wo eine existierende Tabelle umbenannt werden kann. Zudem ist das Hinzufügen oder Löschen von Tabellenfeldern möglich, genauso wie das Ändern von Feldnamen und -typen. Execute all/selected SQL Komplettes/ausgewähltes SQL ausführen This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Dieser Button führt die aktuell ausgewählte SQL-Anweisung aus. Wenn kein Text ausgewählt ist, werden alle SQL-Anweisungen ausgeführt. Ctrl+Shift+T &Load Extension... Erweiterung &laden... Execute line Zeile ausführen &Wiki &Wiki F1 Bug &Report... Fehle&rmeldung... Feature Re&quest... Funktions&anfrage... Web&site Web&seite &Donate on Patreon... Über &Patreon spenden... &Save Project Projekt &speichern Open &Project... &Projekt öffnen... Open &Project &Projekt öffnen &Attach Database... Datenbank &anhängen... Add another database file to the current database connection Eine andere Datenbankdatei zur aktuellen Datenbankverbindung hinzufügen This button lets you add another database file to the current database connection Dieser Button erlaubt Ihnen das Hinzufügen einer anderen Datenbankdatei zur aktuellen Datenbankverbindung &Set Encryption... Verschlüsselung &setzen... SQLCipher &FAQ SQLCiper &FAQ Table(&s) to JSON... Tabelle(&n) zu JSON... Open Data&base Read Only... Daten&bank im Lesemodus öffnen... Ctrl+Shift+O Save results Ergebnisse speichern Save the results view Ergebnisansicht speichern This button lets you save the results of the last executed query Dieser Button erlaubt Ihnen das Speichern der Ergebnisse der zuletzt ausgeführten Abfrage Find text in SQL editor Text im SQL-Editor finden Find Suchen This button opens the search bar of the editor Dieser Button öffnet die Suchleiste des Editors Ctrl+F Find or replace text in SQL editor Text im SQL-Editor suchen oder ersetzen Find or replace Suchen oder ersetzen This button opens the find/replace dialog for the current editor tab Dieser Button öffnet den Suchen-/Ersetzen-Dialog für den aktuellen Editortab Ctrl+H Export to &CSV Nach &CSV exportieren Export to &JSON Nach &JSON exportieren Save as &view Als &View speichern Save as view Als Ansicht speichern &Open Database Datenbank &öffnen Drag && Drop SELECT Query Drag-and-drop für SELECT-Abfrage When dragging fields from the same table or a single table, drop a SELECT query into the editor Wenn Felder aus der gleichen Tabelle oder einen einzelnen Tabelle ausgewählt und gezogen werden, soll eine SELECT-Abfrage in den Editor geschrieben werden Browse Table Tabelle durchsuchen Ctrl+Shift+W Table from CSV data in Clipboard... Tabelle aus CSV-Daten in der Zwischenablage... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Dies behandelt den aktuellen Inhalt der Zwischenablage als CSV-Datei und öffnet den gleichen Import-Dialog wie für den Import von CSV-Daten aus einer Datei. Show &Row Counts Zeilena&nzahl anzeigen This shows the number of rows for each table and view in the database. Dies zeigt die Anzahl der Zeilen für jede Tabelle und Ansicht in der Datenbank. Save Database &As... D&atenbank speichern unter... Save the current database as a different file Die aktuelle Datenbank in einer anderen Datei speichern Refresh Aktualisieren Reload the database structure Die Datenbankstruktur neu laden Shows or hides the Project toolbar. Zeigt oder versteckt die Projekt-Werkzeugleiste. Extra DB Toolbar Extra DB-Werkzeugleiste This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Dieser Button erlaubt Ihnen das Speichern aller mit der geöffneten DB verbundenen Einstellungen in einer DB-Browser für SQLite-Projektdatei This button lets you open a DB Browser for SQLite project file Dieser Button erlaubt Ihnen das Öffnen einer DB-Browser für SQLite-Projektdatei New In-&Memory Database Neue In-&Memory-Datenbank Drag && Drop Qualified Names Drag-and-drop qualifizierter Namen Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Qualifizierte Namen (z. B. "Tabelle."Feld") verwenden, wenn die Objekte gefasst und im Editor abgelegt werden Drag && Drop Enquoted Names Drag-and-drop zitierter Namen Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Geschützte Identifier (z. B. "Tabelle1") verwenden, wenn die Objekte gefasst und im Editor abgelegt werden &Integrity Check &Integritätsprüfung Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. Führt das Pragma integrity_check auf der geöffneten Datenbank aus und gibt die Ergebnisse im SQL-Tab zurück. Dieses Pragma führt eine Integritätsprüfung der gesamten Datenbank durch. &Foreign-Key Check &Fremdschlüssel-Prüfung Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Führt das Pragma foreign_key_check auf der geöffneten Datenbank aus und gibt die Ergebnisse im SQL-Tab zurück &Quick Integrity Check &Schnelle Integritätsprüfung Run a quick integrity check over the open DB Führt eine schnelle Integritätsprüfung der geöffneten DB aus Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. Führt das Pragma quick_check auf der geöffneten Datenbank aus und gibt die Ergebnisse im SQL-Tab zurück. Dieser Befehl führt einen Großteil der Prüfung des Pragmas integrity_check aus, ist aber deutlich schneller. &Optimize &Optimieren Attempt to optimize the database Versuchen, die Datenbank zu optimieren Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Führt das Pragma optimize auf der geöffneten Datenbank aus. Dieses Pragma führt möglicherweise Optimierungen durch, die die Performanz zukünftiger Queries verbessern. Print Drucken Print text from current SQL editor tab Den Text aus dem aktuellen SQL-Editortab drucken Open a dialog for printing the text in the current SQL editor tab Einen Dialog zum Drucken des Textes im aktuellen SQL-Editortab öffnen Print the structure of the opened database Die Struktur der geöffneten Datenbank drucken Open a dialog for printing the structure of the opened database Einen Dialog zum Drucken der Struktur der geöffneten Datenbank öffnen &Save Project As... Projekt &speichern als... Save the project in a file selected in a dialog Das Projekt in einer in einem Dialog ausgewählten Datei speichern Save A&ll &Alle speichern Save DB file, project file and opened SQL files DB-Datei, Projektdatei und geöffnete SQL-Dateien speichern Ctrl+Shift+S Close Pro&ject Pro&jekt schließen Close project and database files and return to the initial state Projekt und Datenbankdateien schließen und zum initialen Zustand zurückkehren Ctrl+Shift+F4 Detach Database Datenbank ablösen Detach database file attached to the current database connection Die mit der aktuellen Datenbankverbindung verwendete Datenbankdatei ablösen Open an existing database file in read only mode Eine existierende Datenbank schreibgeschützt öffnen &File &Datei &Import &Import &Export &Export &Edit &Bearbeiten &View &Ansicht &Help &Hilfe Edit Database &Cell Datenbank&zelle bearbeiten This button clears the contents of the SQL logs Dieser Button löscht den Inhalt der SQL-Protokolle This panel lets you examine a log of all SQL commands issued by the application or by yourself Dieses Panel erlaubt Ihnen das Betrachten eines Protokolls aller SQL-Kommandos, die von der Anwendung oder von Ihnen selbst ausgegangen sind DB Sche&ma DB-Sche&ma This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Dies ist die Struktur der geöffneten Datenbank. Sie können mehrere Objektnamen aus der Namensspalte nehmen und in den SQL-Editor ziehen und Sie können die Eigenschaften der abgelegten Namen über das Kontextmenü anpassen. Dies kann Sie bei der Erstellung von SQL-Anweisungen unterstützen. Sie können SQL-Anweisungen aus der Schemaspalte nehmen und in den SQL-Editor oder in anderen Anwendungen ablegen. &Remote Entfe&rnt Open SQL file(s) SQL-Datei(en) öffnen This button opens files containing SQL statements and loads them in new editor tabs Dieser Button öffnet Dateien mit SQL-Anweisungen und lädt diese in neue Editortabs Execute current line Aktuelle Zeile ausführen This button executes the SQL statement present in the current editor line Dieser Button führt die SQL-Anweisung in der aktuellen Editorzeile aus Shift+F5 Sa&ve Project &Projekt speichern Save SQL file as SQL-Datei speichern als This button saves the content of the current SQL editor tab to a file Dieser Button speichert den Inhalt des aktuellen SQL-Editortabs in einer Datei &Browse Table Tabelle &durchsuchen Copy Create statement CREATE-Anweisung kopieren Copy the CREATE statement of the item to the clipboard CREATE-Anweisung des Elements in die Zwischenablage kopieren User Benutzer Application Anwendung &Clear &Leeren &New Database... &Neue Datenbank... Create a new database file Neue Datenbankdatei erstellen This option is used to create a new database file. Diese Option wird zum Erstellen einer neuen Datenbankdatei verwendet. Ctrl+N &Open Database... Datenbank &öffnen... Open an existing database file Existierende Datenbankdatei öffnen This option is used to open an existing database file. Diese Option wird zum Öffnen einer existierenden Datenbankdatei verwendet. Ctrl+O &Close Database Datenbank &schließen This button closes the connection to the currently open database file Dieser Button schließt die Verbindung zu der aktuell geöffneten Datenbankdatei Ctrl+W Revert database to last saved state Datenbank auf zuletzt gespeicherten Zustand zurücksetzen This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Diese Option wird zum Zurücksetzen der aktuellen Datenbankdatei auf den zuletzt gespeicherten Zustand verwendet. Alle getätigten Änderungen gehen verloren. Write changes to the database file Änderungen in Datenbankdatei schreiben This option is used to save changes to the database file. Diese Option wird zum Speichern von Änderungen in der Datenbankdatei verwendet. Ctrl+S Compact the database file, removing space wasted by deleted records Datenbankdatei komprimieren, löscht Speicherplatz von gelöschten Zeilen Compact the database file, removing space wasted by deleted records. Datenbankdatei komprimieren, löscht Speicherplatz von gelöschten Zeilen. E&xit &Beenden Ctrl+Q Import data from an .sql dump text file into a new or existing database. Daten von einer .sql-Dump-Textdatei in eine neue oder existierende Datenbank importieren. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Diese Option wird zum Importieren von Daten von einer .sql-Dump-Textdatei in eine neue oder existierende Datenbank verwendet. SQL-Dumpdateien können von den meisten Datenbankanwendungen erstellt werden, inklusive MySQL und PostgreSQL. Open a wizard that lets you import data from a comma separated text file into a database table. Öffnet einen Assistenten zum Importieren von Daten aus einer kommaseparierten Textdatei in eine Datenbanktabelle. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Öffnet einen Assistenten zum Importieren von Daten aus einer kommaseparierten Textdatei in eine Datenbanktabelle. CSV-Dateien können von den meisten Datenbank- und Tabellenkalkulationsanwendungen erstellt werden. Export a database to a .sql dump text file. Daten in eine .sql-Dump-Textdatei exportieren. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Diese Option ermöglicht den Export einer Datenbank in eine .sql-Dump-Textdatei. SQL-Dumpdateien enthalten alle notwendigen Daten, um die Datenbank mit den meisten Datenbankanwendungen neu erstellen zu können, inklusive MySQL und PostgreSQL. Export a database table as a comma separated text file. Datenbank als kommaseparierte Textdatei exportieren. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Exportiert die Datenbank als kommaseparierte Textdatei, fertig zum Import in andere Datenbank- oder Tabellenkalkulationsanwendungen. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Den Assistenten zum Erstellen einer Tabelle öffnen, wo der Name und die Felder für eine neue Tabelle in der Datenbank festgelegt werden können Open the Delete Table wizard, where you can select a database table to be dropped. Den Assistenten zum Löschen einer Tabelle öffnen, wo eine zu entfernende Datenbanktabelle ausgewählt werden kann. Open the Create Index wizard, where it is possible to define a new index on an existing database table. Den Assistenten zum Erstellen des Index öffnen, wo ein neuer Index für eine existierende Datenbanktabelle gewählt werden kann. &Preferences... &Einstellungen... Open the preferences window. Das Einstellungsfenster öffnen. &DB Toolbar &DB-Werkzeugleiste Shows or hides the Database toolbar. Zeigt oder versteckt die Datenbank-Werkzeugleiste. Shift+F1 &Recently opened &Kürzlich geöffnet Ctrl+T Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Warnung: dieses Pragma ist nicht lesbar und dieser Wert wurde abgeleitet. Das Schreiben des Pragmas überschreibt möglicherweise ein geändertes LIKE, das von einer SQLite-Erweiterung zur Verfügung gestellt wird. Too&ls &Werkzeuge DB Toolbar DB-Werkzeugleiste SQL &Log SQL-&Protokoll Show S&QL submitted by Anzeige des übergebenen S&QL von &Plot &Diagramm Project Toolbar Projekt-Werkzeugleiste Extra DB toolbar Extra DB-Werkzeugleiste Close the current database file Die aktuelle Datenbankdatei schließen &Revert Changes Änderungen &rückgängig machen &Write Changes Änderungen &schreiben &Database from SQL file... &Datenbank aus SQL-Datei... &Table from CSV file... &Tabelle aus CSV-Datei... &Database to SQL file... &Datenbank als SQL-Datei... &Table(s) as CSV file... &Tabelle(n) als CSV-Datei... &Create Table... Tabelle &erstellen... &Delete Table... Tabelle &löschen... &Modify Table... Tabelle &ändern... Create &Index... &Index erstellen... W&hat's This? &Was ist das? &About &Über New &tab Neuer &Tab This button opens a new tab for the SQL editor Dieser Button öffnet einen neuen Tab im SQL-Editor &Execute SQL SQL &ausführen Save the current session to a file Aktuelle Sitzung in einer Datei speichern Load a working session from a file Sitzung aus einer Datei laden Save SQL file SQL-Datei speichern Ctrl+E Export as CSV file Als CSV-Datei exportieren Export table as comma separated values file Tabelle als kommaseparierte Wertedatei exportieren Ctrl+L Ctrl+P Database encoding Datenbank-Codierung Choose a database file Eine Datenbankdatei auswählen Ctrl+Return Ctrl+D Ctrl+I Reset Window Layout Fensteranordnung zurücksetzen The database is currently busy. Die Datenbank ist aktuell beschäftigt. Click here to interrupt the currently running query. Hier klicken, um die aktuell laufende Abfrage zu unterbrechen. Encrypted Verschlüsselt Database is encrypted using SQLCipher Datenbank ist mittels SQLCipher verschlüsselt Read only Nur lesen Database file is read only. Editing the database is disabled. Zugriff auf Datenbank nur lesend. Bearbeiten der Datenbank ist deaktiviert. Could not open database file. Reason: %1 Datenbankdatei konnte nicht geöffnet werden. Grund: %1 Choose a filename to save under Dateinamen zum Speichern auswählen Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Fehler beim Speichern der Datenbankdatei. Dies bedeutet, dass nicht alle Änderungen an der Datenbank gespeichert wurden. Der folgende Fehler muss zuvor gelöst werden: %1 Do you want to save the changes made to SQL tabs in the project file '%1'? Sollen die in den SQL-Tabs getätigten Änderungen in der Projektdatei '%1' gespeichert werden? A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Eine neue Version des DB-Browsers für SQLite ist verfügbar (%1.%2.%3).<br/><br/>Bitte laden Sie diese von <a href='%4'>%4</a> herunter. DB Browser for SQLite project file (*.sqbpro) DB-Browser für SQLite-Projektdatei (*.sqbpro) Error checking foreign keys after table modification. The changes will be reverted. Fehler beim Prüfen von Fremdschlüsseln nach der Änderung an der Tabelle. Die Änderungen werden rückgängig gemacht. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Diese Tabelle hat die Fremdschlüssel-Prüfung nicht bestanden.<br/>Sie sollten 'Werkzeuge | Fremdschlüssel-Prüfung' ausführen und die gemeldeten Probleme beheben. Execution finished with errors. Ausführung wurde mit Fehlern beendet. Execution finished without errors. Ausführung wurde ohne Fehler beendet. Are you sure you want to undo all changes made to the database file '%1' since the last save? Sollen wirklich alle Änderungen an der Datenbankdatei '%1' seit dem letzten Speichern rückgängig gemacht werden? Choose a file to import Datei für Import auswählen Text files(*.sql *.txt);;All files(*) Textdateien(*.sql *.txt);;Alle Dateien(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Soll für die importierten Daten eine neue Datenbank erstellt werden? Bei der Antwort NEIN werden die Daten in die SQL-Datei der aktuellen Datenbank importiert. Ctrl+Tab Ctrl+Shift+Tab Clear List Liste leeren Window Layout Fensterlayout Simplify Window Layout Fensterlayout vereinfachen Alt+Shift+0 Dock Windows at Bottom Fenster unten anheften Dock Windows at Left Side Fenster links anheften Dock Windows at Top Fenster oben anheften You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Es werden aktuell SQL-Anweisungen ausgeführt. Das Schließen der Datenbank wird deren Ausführung stoppen, was die Datenbank möglicherweise in einem inkonsistenten Zustand belässt. Soll die Datenbank wirklich geschlossen werden? Do you want to save the changes made to the project file '%1'? Sollen die an der Projektdatei '%1' getätigten Änderungen gespeichert werden? File %1 already exists. Please choose a different name. Datei %1 existiert bereits. Bitte einen anderen Namen auswählen. Error importing data: %1 Fehler beim Datenimport: %1 Import completed. Import abgeschlossen. Delete View Ansicht löschen Delete Trigger Trigger löschen Delete Index Index löschen Delete Table Tabelle löschen Setting PRAGMA values will commit your current transaction. Are you sure? Das Setzen von PRAGMA-Werten übermittelt den aktuellen Vorgang. Sind Sie sicher? In-Memory database In-Memory-Datenbank Automatically load the last opened DB file at startup Beim Starten automatisch die zuletzt geöffnete Datenbank öffnen Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Möchten Sie die Tabelle '%1' wirklich löschen? Alle mit dieser Tabelle verbundenen Daten gehen verloren. Are you sure you want to delete the view '%1'? Möchten Sie die Ansicht '%1' wirklich löschen? Are you sure you want to delete the trigger '%1'? Möchten Sie den Trigger '%1' wirklich löschen? Are you sure you want to delete the index '%1'? Möchten Sie den Index '%1' wirklich löschen? Error: could not delete the table. Fehler: Tabelle konnte nicht gelöscht werden. Error: could not delete the view. Fehler: Ansicht konnte nicht gelöscht werden. Error: could not delete the trigger. Fehler: Trigger konnte nicht gelöscht werden. Error: could not delete the index. Fehler: Index konnte nicht gelöscht werden. Message from database engine: %1 Nachricht von Datenbank-Engine: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Das Bearbeiten der Tabelle setzt das Speichern aller ausstehenden Änderungen voraus. Möchten Sie die Datenbank wirklich speichern? Edit View %1 Ansicht %1 bearbeiten Edit Trigger %1 Trigger %1 bearbeiten You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. Es werden bereits SQL-Anweisungen ausgeführt. Sollen diese gestoppt werden, um stattdessen die aktuellen Anweisungen auszuführen? Dies führt möglicherweise zu einem inkonsistenten Zustand der Datenbank. -- EXECUTING SELECTION IN '%1' -- -- FÜHRE AUSWAHL IN '%1' AUS -- -- EXECUTING LINE IN '%1' -- -- FÜHRE ZEILE IN '%1' AUS -- -- EXECUTING ALL IN '%1' -- -- FÜHRE ALLES IN '%1' AUS -- At line %1: In Zeile %1: Result: %1 Ergebnis: %1 Result: %2 Ergebnis: %2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Das Setzen von PRAGMA-Werten oder das Komprimieren wird Ihre aktuelle Transaktion übermitteln. Sind Sie sich sicher? Opened '%1' in read-only mode from recent file list '%1' aus der Liste zuletzt geöffneter Dateien im Lesemodus geöffnet Opened '%1' from recent file list '%1' aus der Liste zuletzt geöffneter Dateien geöffnet Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Auf die Datei anzuwendende Aktion auswählen. <br/>Hinweis: Nur 'Import' kann mehr als eine Datei verarbeiten. Auf die Dateien anzuwendende Aktion auswählen. <br/>Hinweis: Nur 'Import' kann mehr als eine Datei verarbeiten. The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? Die Anweisungen im Tab '%1' werden noch ausgeführt. Das Schließen des Tabs stoppt die Ausführung. Dies hinterlässt die Datenbank möglicherweise in einem inkonsistenten Zustand. Soll der Tab wirklich geschlossen werden? This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Diese Projektdatei verwendet ein altes Dateiformat, da es mit DB-Browser für SQLite Version 3.10 oder älter erstellt wurde. Das Laden dieser Dateien wird nicht mehr vollständig unterstützt. Um es komplett zu laden, bitte DB-Browser für SQLite Version 3.12 verwenden und in das neue Format konvertieren. Project saved to file '%1' Projekt in Datei '%1' gespeichert Yes. Don't ask again Ja. Nicht erneut fragen This action will open a new SQL tab with the following statements for you to edit and run: Diese Aktion öffnet einen neuen SQL-Tab mit den folgenden Anweisungen zum Bearbeiten und Ausführen: Rename Tab Tab umbenennen Duplicate Tab Tab duplizieren Close Tab Tab schließen Opening '%1'... '%1' öffnen... There was an error opening '%1'... Fehler beim Öffnen von '%1'... Value is not a valid URL or filename: %1 Wert ist keine gültige URL bzw. kein gültiger Dateiname: %1 %1 rows returned in %2ms %1 Zeilen in %2 ms zurückgegeben Ctrl+Alt+0 Ctrl+Alt+W Choose a database file to save under Datenbankdatei zum Speichern auswählen Error while saving the database to the new file. Fehler beim Speichern der Datenbank in einer neuen Datei. Choose text files Textdateien auswählen Import completed. Some foreign key constraints are violated. Please fix them before saving. Import vollständig. Ein paar Fremdschlüssel-Beschränkungen wurden verletzt. Bitte beheben Sie diese vor dem Speichern. Modify View Ansicht verändern Modify Trigger Trigger verändern Modify Index Index verändern Modify Table Tabelle verändern &%1 %2%3 &%1 %2%3 (read only) (nur lesend) Open Database or Project Datenbank oder Projekt öffnen Attach Database... Datenbank anhängen... Import CSV file(s)... CSV-Datei(en) importieren... Do you want to save the changes made to SQL tabs in a new project file? Sollen die an den SQL-Tabs getätigten Änderungen in einer neuen Projektdatei gespeichert werden? Do you want to save the changes made to the SQL file %1? Sollen die getätigten Änderungen in der SQL-Datei %1 gespeichert werden? Select SQL file to open SQL-Datei zum Öffnen auswählen Select file name Dateinamen auswählen Select extension file Erweiterungsdatei auswählen Extension successfully loaded. Erweiterung erfolgreich geladen. Error loading extension: %1 Fehler beim Laden der Erweiterung: %1 Could not find resource file: %1 Ressourcen-Datei konnte nicht gefunden werden: %1 Don't show again Nicht wieder anzeigen New version available. Neue Version verfügbar. Choose a project file to open Wählen Sie die zu öffnende Projektdatei DB file '%1' could not be opened Datenbankdatei '%1' konnte nicht geöffnet werden Table '%1' not found; settings ignored Tabelle '%1' nicht gefunden; Einstellungen werden ignoriert Could not open project file for writing. Reason: %1 Projekt-Datei konnte nicht schreibend geöffnet werden. Grund: %1 -- Reference to file "%1" (not supported by this version) -- -- Referenz zu Datei "%1" (von dieser Version nicht unterstützt) -- Collation needed! Proceed? Kollation notwendig! Fortführen? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Eine Tabelle in dieser Datenbank benötigt eine spezielle Kollationsfunktion '%1', die diese Anwendung ohne weitere Kenntnisse nicht bereitstellen kann. Wenn Sie fortfahren, sollten Sie im Hinterkopf behalten, dass mit Ihrer Datenbank unerwartete Dinge geschehen können. Erstellen Sie ein Backup! creating collation erstelle Kollation Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Vergeben Sie einen Namen für den SQL-Tab. Verwenden Sie das Zeichen '&&', um das folgende Zeichen als Tastaturkürzel zu verwenden. Please specify the view name Geben Sie bitte einen Namen für Ansicht an There is already an object with that name. Please choose a different name. Es gibt bereits ein Objekt mit diesem Namen. Bitte wählen Sie einen anderen aus. View successfully created. Ansicht erfolgreich erstellt. Error creating view: %1 Fehler beim Erstellen der Ansicht: %1 This action will open a new SQL tab for running: Diese Aktion öffnet einen neuen SQL-Tab zur Ausführung: Press Help for opening the corresponding SQLite reference page. Drücken Sie auf 'Hilfe', um die entsprechende SQLite-Referenzseite zu öffnen. Busy (%1) Beschäftigt (%1) NullLineEdit Set to NULL Auf NULL setzen Alt+Del PlotDock Plot Diagramm <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Dieses Pane zeigt die Liste der Spalten der aktuell ausgewählten Tabelle oder der soeben ausgeführten Abfrage. Sie können die für die X- und Y-Achse gewünschten Spalten für das Plot-Pane unten auswählen. Die Tabelle zeigt den erkannten Achsentyp, der den entstehenden Plot beeinflusst. Für die Y-Achse sind nur numerische Spalten zulässig, während Sie für die X-Achse aus folgenden Optionen auswählen können:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Datum/Zeit</span>: Strings im Format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Datum</span>: Strings im Format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Zeit</span>: Strings im Format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Beschriftung</span>: andere Stringformate. Die Auswahl dieser Spalte als X-Achse erzeugt einen Balkendiagramm mit den Spaltenwerten als Beschriftung für die Balken.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numerisch</span>: Integer- oder Real-Werte</li></ul><p>Ein Doppelklick auf die Y-Zellen ermöglicht Ihnen das Ändern der für den Graph verwendeten Farbe.</p></body></html> Columns Spalten X X Y1 Y1 Y2 Y2 Axis Type Achsentyp Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Hier wird ein Plot angezeigt, wenn Sie oben die x- und y-Werte auswählen. Klicken Sie auf Punkte, um diese im Plot und in der Tabelle auszuwählen. Strg+Klick zur Auswahl eines Punktebereichs. Verwenden Sie das Mausrad zum Zoomen und ziehen Sie mit der Maus, um den Achsenbereich zu ändern. Wählen Sie die Achsen oder Achsenbeschriftungen aus, um nur in diese Richtung zu zoomen oder zu verschieben. Line type: Linientyp: None Keine Line Linie StepLeft Linksschritt StepRight Rechtsschritt StepCenter Mittelschritt Impulse Impuls Point shape: Punktform: Cross Kreuz Plus Plus Circle Kreis Disc Scheibe Square Quadrat Diamond Diamant Star Stern Triangle Dreieck TriangleInverted Invertiertes Dreieck CrossSquare Quadrat mit Kreuz PlusSquare Quadrat mit Plus CrossCircle Kreis mit Kreuz PlusCircle Kreis mit Plus Peace Peace <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Aktuelles Diagramm speichern...</p><p>Dateiformat durch Endung auswählen (png, jpg, pdf, bmp)</p></body></html> Save current plot... Aktuelles Diagramm speichern... Load all data and redraw plot Alle Daten laden und Plot neu zeichnen Row # Zeile # Copy Kopieren Print... Drucken... Show legend Legende anzeigen Stacked bars Gestapelte Bars Fixed number format Festes Zahlenformat Date/Time Datum/Zeit Date Datum Time Zeit Numeric Numerisch Label Beschriftung Invalid Ungültig Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Alle Daten laden und Plot neu zeichnen. Warnung: es wurden aufgrund der partiellen Abrufmechanismus noch nicht alle Daten aus der Tabelle abgerufen. Choose an axis color Eine Achsenfarbe wählen Choose a filename to save under Dateinamen zum Speichern auswählen PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Alle Dateien(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Dieser Plot enthält Kurven und der ausgewählte Linienstil kann nur auf nach X sortierte Graphen angewendet werden. Sortieren Sie entweder die Tabelle oder Abfrage nach X oder entfernen Sie die Kurven oder wählen Sie eine der Stile, die von Kurven unterstützt werden: Keiner oder Linie. Loading all remaining data for this table took %1ms. Das Laden aller verbleibender Daten dieser Tabelle benötigte %1 ms. PreferencesDialog Preferences Einstellungen &General All&gemeines Remember last location Letztes Verzeichnis merken Always use this location Immer dieses Verzeichnis verwenden Remember last location for session only Letztes Verzeichnis nur innerhalb der Sitzung merken Lan&guage &Sprache Show remote options Fernzugriffs-Optionen anzeigen Automatic &updates Automatische &Updates &Database &Datenbank Database &encoding Datenbank-&Codierung Open databases with foreign keys enabled. Öffnen von Datenbanken mit Fremdschlüsseln aktiviert. &Foreign keys &Fremdschlüssel enabled aktiviert Default &location Voreingestellter &Speicherort ... ... Remove line breaks in schema &view Zeilenumbrüche in der Schema&ansicht entfernen Prefetch block si&ze Block&größe für Prefetch SQ&L to execute after opening database Nach dem Öffnen einer Datenbank auszuführendes SQ&L Default field type Voreingestellter Feldtyp Data &Browser Daten&auswahl Font Schrift &Font Schri&ft Content Inhalt Symbol limit in cell Symbolbegrenzung in Zelle NULL NULL Regular Normal Binary Binär Background Hintergrund Filters Filter Threshold for completion and calculation on selection Schwellwert für die Vervollständigung und Berechnung bei Auswahl Show images in cell Bilder in Zelle anzeigen Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Diese Option aktivieren, um eine Vorschau von BLOBs mit Bilddaten in den Zellen anzuzeigen. Dies kann allerdings die Performanz der Anwendung beeinflussen. Escape character Escape-Zeichen Delay time (&ms) Verzögerung (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Verzögerung vor der Anwendung eines neuen Filters setzen. Kann auf 0 gesetzt werden, um dies zu deaktivieren. &SQL &SQL Context Kontext Colour Farbe Bold Fett Italic Kursiv Underline Unterstreichung Keyword Schlüsselwort Function Funktion Table Tabelle Comment Kommentar Identifier Bezeichner String String Current line Aktuelle Zeile SQL &editor font size SQL-&Editor-Schriftgröße Tab size Tab-Größe SQL editor &font SQL-Editor-&Schrift Error indicators Fehleranzeige Hori&zontal tiling Hori&zontale Anordnung If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Im aktivierten Zustand werden der SQL-Codeeditor und die Ergebnistabelle neben- statt untereinander angezeigt. Code co&mpletion &Codevervollständigung Toolbar style Werkzeugleisten-Stil Only display the icon Nur das Symbol anzeigen Only display the text Nur den Text anzeigen The text appears beside the icon Der Text erscheint neben dem Symbol The text appears under the icon Der Text erscheint unter dem Symbol Follow the style Dem Stil folgen DB file extensions DB-Dateierweiterungen Manage Verwalten Main Window Hauptfenster Database Structure Datenbankstruktur Browse Data Daten durchsuchen Execute SQL SQL ausführen Edit Database Cell Datenbankzelle bearbeiten When this value is changed, all the other color preferences are also set to matching colors. Wenn dieser Wert geändert wird, werden alle anderen Farbeinstellungen auch auf die entsprechenden Farben gesetzt. Follow the desktop style Dem Desktop-Stil folgen Dark style Dunkler Stil Application style Anwendungsstil This sets the font size for all UI elements which do not have their own font size option. Dies setzt die Schriftgröße für alle GUI-Elemente, die keine eigene Einstellung für die Schriftgröße besitzen. Font size Schriftgröße Max Recent Files Maximale Anzahl zuletzt geöffneter Dateien Prompt to save SQL tabs in new project file Dialog zum Speichern von SQL-Tabs in einer neuen Projektdatei If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Wenn dies aktiviert ist, dann erzeugen Änderungen am SQL-Editor-Tab beim Schließen des Tabs einen Bestätigungsdialog zum Speichern als Projekt. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Wenn aktiviert, werden die Zeilenumbrüche in der Schemaspalte des DB-Strukturtabs, Docks und der gedruckten Ausgabe entfernt. Database structure font size Schriftgröße in Datenbankstruktur Font si&ze Schrift&größe This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Dies ist die maximale Elementanzahl, die für die Aktivierung einiger rechenintensiver Funktionalitäten erlaubt ist: Maximale Zeilenanzahl in einer Tabelle für die Wertvervollständigung basierend auf den aktuellen Werten in dieser Spalte. Maximale Indexanzahl in einer Auswahl für die Berechnung von Summe und Durchschnitt. Kann auf 0 gesetzt werden, um diese Funktionalitäten zu deaktivieren. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Dies ist die maximale Anzahl an Zeilen in einer Tabelle, die zur Wertvervollständigung basierend auf aktuellen Werten in dieser Spalte erlaubt ist. Kann auf 0 gesetzt werden, um die Vervollständigung zu deaktivieren. Field display Feldanzeige Light style Heller Stil Displayed &text Angezeigter &Text Formatted Formatiert Click to set this color Zur Auswahl der Farbe klicken Text color Textfarbe Background color Hintergrundfarbe Preview only (N/A) Nur Vorschau (N/A) Foreground Vordergrund Selection background Hintergrund einer Auswahl Selection foreground Vordergrund einer Auswahl Highlight Hervorhebung SQL &results font size Schriftgröße der SQL-&Ergebnisse Use tabs for indentation Tabulatoren zur Einrückung verwenden When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. Wenn aktiviert, dann wird die Tabulator-Taste Tabulatoren und Leerzeichen zur Einrückung einfügen. Ansonsten werden lediglich Leerzeichen verwendet. &Wrap lines Zeilen &umbrechen Never Nie At word boundaries An Wortgrenzen At character boundaries An Zeichengrenzen At whitespace boundaries An Leerzeichengrenzen &Quotes for identifiers &Anführungszeichen für Identifiers Choose the quoting mechanism used by the application for identifiers in SQL code. Wählen Sie den Zitiermechanismus aus, der von der Anwendung für Identifier im SQL-Code verwendet wird. "Double quotes" - Standard SQL (recommended) "Doppelte Anführungszeichen" - Standard-SQL (empfohlen) `Grave accents` - Traditional MySQL quotes `Akzente` - Traditionelle MySQL-Anführungszeichen [Square brackets] - Traditional MS SQL Server quotes [Eckige Klammern] - Traditionelle MS-SQL-Server-Anführungszeichen Keywords in &UPPER CASE Schlüsselwörter in &GROẞSCHREIBUNG When set, the SQL keywords are completed in UPPER CASE letters. Wenn gesetzt, werden die SQL-Schlüsselwörter in GROẞSCHREIBUNG vervollständigt. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Wenn gesetzt, werden die SQL-Codezeilen, die während der letzten Ausführung Fehler verursacht haben, hervorgehoben und das Ergebnisfenster zeigt den Fehler im Hintergrund an Close button on tabs Schließen-Button für Tabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Wenn aktiviert, werden die SQL-Editor-Tabs einen Schließen-Button haben. In jedem Fall können Sie zum Schließen auch das Kontextmenü oder die Tastenkombination verwenden. &Extensions &Erweiterungen Select extensions to load for every database: Bei jeder Datenbank zu ladende Erweiterungen auswählen: Add extension Erweiterung hinzufügen Remove extension Erweiterung entfernen Select built-in extensions to load for every database: Bei jeder Datenbank zu ladende eingebaute Erweiterungen auswählen: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>Auch wenn der REGEXP-Operator unterstützt wird, implementiert SQLite keinerlei Algorithmus für reguläre<br/>Ausdrücke, sondern leitet diese an die laufende Anwendung weiter. DB-Browser für SQLite implementierte diesen<br/>Algorithmus für Sie, um REGEXP ohne Zusätze verwenden zu können. Allerdings gibt es viele mögliche<br/>Implementierungen und Sie möchten unter Umständen eine andere wählen, dann können Sie die<br/>Implementierung der Anwendung deaktivieren und Ihre eigene durch Laden einer Erweiterung verwenden. Ein Neustart der Anwendung ist notwendig.</p></body></html> Disable Regular Expression extension Erweiterung für reguläre Ausdrücke deaktivieren <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite bietet eine SQL-Funktion an, um Erweiterungen aus einer Shared-Library-Datei zu laden. Aktivieren Sie dies, wenn Sie die Funktion <span style=" font-style:italic;">load_extension()</span> aus SQL-Code heraus benutzen möchten.</p><p>Aus Sicherheitsgründen ist das Laden von Erweiterungen standardmäßig deaktiviert und muss durch diese Einstellung aktiviert werden. Sie können alternativ immer die gewünschten Erweiterungen über die GUI laden, auch wenn diese Option deaktiviert ist.</p></body></html> Allow loading extensions from SQL code Laden von Erweiterungen aus SQL-Code erlauben Remote Entfernt CA certificates CA-Zertifikate Proxy Proxy Configure Konfigurieren Export Settings Einstellungen exportieren Import Settings Einstellungen importieren Subject CN Subject CN Common Name Common Name Subject O Subject O Organization Organisation Valid from Gültig ab Valid to Gültig bis Serial number Seriennummer Your certificates Ihre Zertifikate File Datei Subject Common Name Subject Common Name Issuer CN CN des Ausstellers Issuer Common Name Common Name des Ausstellers Clone databases into Datenbank klonen nach Choose a directory Verzeichnis wählen The language will change after you restart the application. Die Sprache wird nach einem Neustart der Anwendung geändert. Select extension file Erweiterungsdatei wählen Extensions(*.so *.dylib *.dll);;All files(*) Erweiterungen(*.so *.dylib *.dll);;Alle Dateien(*) Import certificate file Zertifikatsdatei importieren No certificates found in this file. In dieser Datei wurden keine Zertifikate gefunden. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Soll dieses Zertifikat wirklich entfernt werden? Alle Zertifikatsdaten werden aus den Anwendungseinstellungen gelöscht! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Möchten Sie wirklich alle gespeicherten Einstellungen löschen? Alle Ihre Einstellungen gehen dadurch verloren und die Standardwerte werden verwendet. Save Settings File Einstellungsdatei speichern Initialization File (*.ini) Initialisierungsdatei (*.ini) The settings file has been saved in location : Die Einstellungsdatei wurde gespeichert unter: Open Settings File Einstellungsdatei öffnen The settings file was loaded properly. Die Einstellungsdatei wurde korrekt geladen. The selected settings file is not a normal settings file. Please check again. Die ausgewählte Einstellungsdatei ist keine normale Einstellungsdatei. Bitte erneut prüfen. ProxyDialog Proxy Configuration Proxy-Konfiguration Pro&xy Type Pro&xy-Typ Host Na&me Hostna&me Port Port Authentication Re&quired Anmeldung not&wendig &User Name &Benutzername Password Passwort None Keiner System settings Systemeinstellungen HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data Fehler beim Datenimport from record number %1 von Zeilennummer %1 . %1 . %1 Importing CSV file... CSV-Datei importieren... Cancel Abbrechen All files (*) Alle Dateien (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) SQLite Datenbankdateien (*.db *.sqlite *.sqlite3 *.db3) Left Links Right Rechts Center Zentriert Justify Blocksatz SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) SQLite-Datenbankdateien (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) DB-Browser für SQLite-Projektdateien (*.sqbpro) SQL Files (*.sql) SQL-Dateien (*.sql) All Files (*) Alle Dateien (*) Text Files (*.txt) Text-Dateien (*.txt) Comma-Separated Values Files (*.csv) Kommaseparierte Datendateien (*.csv) Tab-Separated Values Files (*.tsv) Tabulator-separierte Datendateien (*.tsv) Delimiter-Separated Values Files (*.dsv) Trennzeichen-separierte Datendateien (*.dsv) Concordance DAT files (*.dat) Konkordanz DAT-Dateien (*.dat) JSON Files (*.json *.js) JSON-Dateien (*.json *.js) XML Files (*.xml) XML-Dateien (*.xml) Binary Files (*.bin *.dat) Binärdateien (*.bin *.dat) SVG Files (*.svg) SVG-Dateien (*.svg) Hex Dump Files (*.dat *.bin) Hex-Dump-Dateien (*.dat *.bin) Extensions (*.so *.dylib *.dll) Erweiterungen (*.so *.dylib *.dll) Initialization File (*.ini) Initialisierungsdatei (*.ini) QsciCommand Paste Einfügen Cancel Abbrechen QsciLexerCPP Default Voreinstellung Keyword Schlüsselwort Identifier Bezeichner QsciLexerJSON Default Voreinstellung String String QsciLexerJavaScript Regular expression Regulärer Ausdruck QsciLexerPython Default Voreinstellung Comment Kommentar Keyword Schlüsselwort Identifier Bezeichner QsciLexerSQL Default Voreinstellung Comment Kommentar Keyword Schlüsselwort Identifier Bezeichner QsciScintilla &Undo &Zurücksetzen Select All Alle auswählen RemoteCommitsModel Commit ID Commit-ID Message Mitteilung Date Datum Author Autor Size Größe Authored and committed by %1 Erstellt und übermittelt von %1 Authored by %1, committed by %2 Erstellt von %1, übermittelt von %2 RemoteDatabase Error opening local databases list. %1 Fehler beim Öffnen der lokalen Datenbankliste. %1 Error creating local databases list. %1 Fehler beim Erstellen der lokalen Datenbankliste. %1 RemoteDock Remote Entfernt Local Lokal Identity Identität Push currently opened database to server Aktuell geöffnete Datenbank an den Server übertragen Upload Hochladen DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>In diesem Fensterbereich können entfernte Datenbanken von der Webseite dbhub.io zu DB-Browser für SQLite hinzugefügt werden. Zunächst benötigen Sie eine Identität:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Melden Sie sich auf der Webseite dbhub.io an (unter Verwendung Ihrer GitHub-Daten oder wie gewünscht)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Klicken Sie auf den Button &quot;Generate client certificate&quot;, um ein Zertifikat zu erstellen (das ist Ihre Identität). Speichern Sie die erzeugte Zertifikatsdatei auf ihrer lokalen Festplatte.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Öffnen Sie den Entfernt-Tab in den DB-Browser für SQLite-Einstellungen. Klicken Sie auf den Button, um ein neues Zertifikat hinzuzufügen und wählen Sie die soeben heruntergeladene Zertifikatsdatei aus.</li></ol><p>Jetzt zeigt der Entfernt-Fensterbereich Ihre Identität und Sie können entfernte Datenbanken hinzufügen.</p></body></html> Current Database Aktuelle Datenbank Clone Klonen Branch Branch Commits Commits Commits for Commits für Delete Database Datenbank löschen Delete the local clone of this database Den lokalen Klon der Datenbank löschen Open in Web Browser Im Webbrowser öffnen Open the web page for the current database in your browser Die Webseite der aktuellen Datenbank im Webbrowser öffnen Clone from Link Über Link klonen Use this to download a remote database for local editing using a URL as provided on the web page of the database. Diese Option verwenden, um eine entfernte Datenbank für die lokale Bearbeitung mittels einer URL herunterzuladen, wie sie auf der Webseite der Datenbank angegeben ist. Refresh Aktualisieren Reload all data and update the views Alle Daten erneut laden und die Ansichten aktualisieren Clone Database Datenbank klonen Open Database Datenbank öffnen Open the local copy of this database Die lokale Kopie dieser Datenbank öffnen Check out Commit Commit auschecken Download and open this specific commit Diesen spezifischen Commit herunterladen und öffnen Check out Latest Commit Letzten Commit auschecken Check out the latest commit of the current branch Den letzten Commit des aktuellen Branchs auschecken Save Revision to File Revision in Datei speichern Saves the selected revision of the database to another file Speichert die ausgewählte Revision der Datenbank in einer anderen Datei Upload Database Datenbank hochladen Upload this database as a new commit Diese Datenbank als neuen Commit hochladen <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>Aktuell wird eine eingebaute, nur lesend verwendbare Identität verwendet. Zum Hochladen einer Datenbank muss ein DBHub.io-Konto konfiguriert und verwendet werden.</p><p>Noch kein DBHub.io-Konto vorhanden? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Jetzt ein Konto erstellen</span></a> und das Zertifikat <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">hier</span></a> hochladen, um Datenbanken zu teilen.</p><p>Eine englische Online-Hilfe ist <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">hier</span></a> verfügbar.</p></body></html> &User Ben&utzer &Database &Datenbank Back Zurück Select an identity to connect Eine Identität zum Verbinden auswählen Public Öffentlich This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Dies lädt eine Datenbank zur lokalen Bearbeitung von einem entfernten Server herunter. Bitte die URL zum Klonen eingeben. Die URL kann durch Klicken des Buttons 'Clone Database in DB4S' auf der Webseite der Datenbank generiert werden. Invalid URL: The host name does not match the host name of the current identity. Ungültige URL: Der Hostname entspricht nicht dem Hostnamen der aktuellen Identität. Invalid URL: No branch name specified. Ungültige URL: Kein Branch-Name gesetzt. Invalid URL: No commit ID specified. Ungültige URL: Keine Commit-ID gesetzt. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? Der lokale Klon der Datenbank enthält Änderungen. Das Holen dieses Commits überschreibt die lokalen Änderungen. Soll wirklich fortgefahren werden? The database has unsaved changes. Are you sure you want to push it before saving? Die Datenbank besitzt ungespeicherte Änderungen. Soll diese wirklich vor dem Speicher hochgeladen werden? The database you are trying to delete is currently opened. Please close it before deleting. Die zu löschende Datenbank ist aktuell geöffnet. Bitte vor dem Löschen schließen. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? Dies löscht die lokale Version der Datenbank mit allen Änderungen, die noch nicht übermittelt wurden. Soll diese Datenbank wirklich gelöscht werden? RemoteLocalFilesModel Name Name Branch Branch Last modified Letzte Änderung Size Größe Commit Commit File Datei RemoteModel Name Name Last modified Letzte Änderung Size Größe Commit Commit Size: Größe: Last Modified: Letzte Änderung: Licence: Lizenz: Default Branch: Standard-Branch: RemoteNetwork Choose a location to save the file Ort zum Speichern der Datei wählen Error opening remote file at %1. %2 Fehler beim Öffnen der entfernten Datei unter %1. %2 Error: Invalid client certificate specified. Fehler: Ungültiges Benutzerzertifikat angegeben. Please enter the passphrase for this client certificate in order to authenticate. Bitte die Passphrase für dieses Benutzerzertifikat eingeben, um die Authentifizierung durchzuführen. Cancel Abbrechen Uploading remote database to %1 Entfernte Datenbank wird hochgeladen zu %1 Downloading remote database from %1 Entfernte Datenbank wird heruntergeladen von %1 Error: Cannot open the file for sending. Fehler: Öffnen der Datei zum Senden nicht möglich. RemotePushDialog Push database Datenbank übertragen Database na&me to push to Datenbankna&me am Zielort Commit message Commit-Nachricht Database licence Datenbanklizenz Public Öffentlich Branch Branch Force push Push erzwingen Username Benutzername Database will be public. Everyone has read access to it. Datenbank wird öffentlich sein. Jeder hat Lesezugriff darauf. Database will be private. Only you have access to it. Datenbank wird privat sein. Nur Sie haben Zugriff darauf. Use with care. This can cause remote commits to be deleted. Verwenden Sie dies mit Vorsicht. Dadurch können entfernte Commits gelöscht werden. RunSql Execution aborted by user Ausführung durch Benutzer abgebrochen , %1 rows affected , %1 Zeilen betroffen query executed successfully. Took %1ms%2 Abfrage erfolgreich ausgeführt. Benötigte %1 ms %2 executing query führe Abfrage aus SelectItemsPopup A&vailable &Verfügbar Sele&cted &Ausgewählt SqlExecutionArea Form Formular Find previous match [Shift+F3] Vorherige Übereinstimmung finden [Umschalt+F3] Find previous match with wrapping Vorherige Übereinstimmung mit Mapping finden Shift+F3 The found pattern must be a whole word Das Muster muss ein ganzes Wort sein Whole Words Ganze Wörter Text pattern to find considering the checks in this frame Zu findendes Textmuster unter Einbeziehung der Prüfungen in diesem Fenster Find in editor Im Editor finden The found pattern must match in letter case Das gefundene Muster muss in Groß-/Kleinschreibung übereinstimmen Case Sensitive Schreibungsabhängig Find next match [Enter, F3] Nächste Übereinstimmung finden [Enter, F3] Find next match with wrapping Nächste Übereinstimmung mit Umbruch finden F3 Interpret search pattern as a regular expression Suchmuster als regulären Ausdruck interpretieren <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Wenn aktiviert, wird das Suchmuster als regulärer Ausdruck (UNIX-Stil) interpretiert. Siehe <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks (englisch)</a>.</p></body></html> Regular Expression Regulärer Ausdruck Close Find Bar Suchbar schließen <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>Ergebnisse der zuletzt ausgeführten Anweisungen.</p><p>Dieses Panel kann zusammengeklappt und stattdessen der Dock <span style=" font-style:italic;">SQL-Protokoll</span> mit der Auswahl <span style=" font-style:italic;">Benutzer</span> verwendet werden.</p></body></html> Results of the last executed statements Ergebnisse der zuletzt ausgeführten Anweisungen This field shows the results and status codes of the last executed statements. Dieses Feld zeigt die Ergebnisse und Statuscodes der zuletzt ausgeführten Anweisungen. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Datei "%1" konnte nicht gelesen werden: %2. Couldn't save file: %1. Datei konnte nicht gespeichert werden: %1. Your changes will be lost when reloading it! Beim Neuladen gehen die Änderungen verloren! The file "%1" was modified by another program. Do you want to reload it?%2 Die Datei "%1" wurde durch ein anderes Programm geändert. Soll es neu geladen werden?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Mit "Ja für Alle" antworten, um die Datei für jedes externe Update ohne weiteren Dialog neu zu laden. Answer "No to All" to ignore any external update without further prompting. Mit "Nein für Alle" antworten, um alle externen Updates ohne weitere Dialoge zu ignorieren. Modifying and saving the file will restore prompting. Das Ändern und Speichern der Datei wird die Dialoge reaktivieren. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) Die Funktion abs(X) gibt einen absoluten Wert des numerischen Arguments X zurück. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () Die Funktion changes() gibt die Anzahl der Datenbankzeilen zurück, die mit der zuletzt abgeschlossenen INSERT-, DELETE- oder UPDATE-Anweisung geändert, eingefügt oder gelöscht worden sind. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) Die Funktion char(X1,X2,...,XN) gibt eine Zeichenkette zurück, die aus den Zeichen der Unicode-Werte der Ganzzahlen X1 bis XN zusammengesetzt ist. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) Die Funktion coalesce() gibt eine Kopie des ersten Nicht-NULL-Arguments zurück, oder NULL wenn alle Argumente NULL sind (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) Die Funktion glob(X,Y) ist äquivalent zum Ausdruck "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) Die Funktion ifnull() gibt eine Kopie des ersten Nicht-NULL-Arguments zurück, oder NULL, wenn beide Argumente NULL sind. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) Die Funktion instr(X,Y) sucht das erste Auftreten von Zeichenkette Y innerhalb der Zeichenkette X und gibt die Anzahl vorhergehender Charakter plus 1 zurück, oder 0, wenn Y in X nicht gefunden werden konnte. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) Die Funktion hex() interpretiert ihr Argument als BLOB und gibt eine Zeichenkette zurück, die die Hexadezimaldarstellung des Blob-Inhaltes in Großbuchstaben enthält. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) Die Funktion iif(X,Y,Z) gibt den Wert Y zurück, wenn X true ist, ansonsten Z. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () Die Funktion last_insert_rowid() gibt die ROWID der letzte Zeile zurück, die von der Datenbankverbindung eingefügt wurde und die dann die Funktion aufrief. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) Für eine Zeichenkette X gibt die Funktion length(X) die Anzahl der Zeichen (nicht Bytes) von X zurück, die sich vor dem ersten NUL-Zeichen befinden. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) Die Funktion like() wird als Implementierung des Ausdrucks "Y LIKE X" verwendet. (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) Die Funktion like() wird als Implementierung des Ausdrucks "Y LIKE X ESCAPE Z" verwendet. (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) Die Funktion load_extension(X) lädt SQLite-Erweiterungen aus der Shared-Library-Datei namens X. Die Verwendung dieser Funktion muss in den Einstellungen autorisiert werden. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) Die Funktion load_extension(X,Y) lädt SQLite-Erweiterungen aus der Shared-Library-Datei namens X unter Verwendung des Eintrittspunktes Y. Die Verwendung dieser Funktion muss in den Einstellungen autorisiert werden. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) Die Funktion lower(X) gibt eine Kopie der Zeichenkette X mit allen ASCII-Zeichen in Kleinschreibung zurück. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) entfernt Leerzeichen aus der linken Seite von X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) Die Funktion ltrim(X,Y) gibt eine Zeichenkette zurück, die durch Entfernen aller Zeichen innerhalb von Y aus der linken Seite von X gebildet wird. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) Die Funktion max() mit mehreren Argumenten gibt das Argument mit dem größten Wert zurück, oder NULL, wenn ein Argument NULL ist. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) Die Funktion max() mit mehreren Argumenten gibt das Argument mit dem kleinsten Wert zurück. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) Die Funktion nullif(X,Y) gibt ihr erstes Argument zurück, wenn die Argumente verschieden sind und NULL, wenn die Argumente gleich sind. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) Die printf(FORMAT,...) SQL-Funktion arbeitet wie die C-Funktion sqlite3_mprintf() und die Funktion printf() aus der C-Standardbibliothek. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) Die Funktion quote(X) gibt den Text eines SQL-Literals zurück, wobei der Wert des Arguments zum Einfügen in eine SQL-Anweisung geeignet ist. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () Die Funktion random() gibt eine pseudozufällige Ganzzahl zwischen -9223372036854775808 und +9223372036854775807 zurück. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) Die Funktion randomblob(N) gibt einen N-Byte Blob aus pseudozufälligen Bytes zurück. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) Die Funktion replace(X,Y,Z) gibt einen String zurück, der durch Ersetzen der Zeichenkette Z bei jedem Auftreten von Zeichenkette Y in Zeichenkette X gebildet wird. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) Die Funktion round(X) gibt einen Gleitkommawert X auf null Nachkommastellen gerundet zurück. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) Die Funktion round(X,Y) gibt eine Gleitkommazahl X auf Y Nachkommastellen gerundet zurück. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) entfernt Leerzeichen aus der rechten Seite von X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) Die Funktion rtrim(X,Y) gibt eine Zeichenkette zurück, die durch Entfernen aller Zeichen innerhalb von Y aus der rechten Seite von X gebildet wird. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) Die Funktion soundex(X) gibt eine Zeichenkette zurück, die aus der Soundex-Codierung von Zeichenkette X besteht. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) gibt alle Zeichen bis zum Ende der Zeichenkette X zurück, beginnend mit dem Y-ten. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) Die Funktion substr(X,Y) gibt einen Teil der Zeichenkette X zurück, die mit dem Y-ten Zeichen beginnt und Z Zeichen lang ist. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () Die Funktion changes() gibt die Anzahl der geänderten Datenbankzeilen zurück, die seit dem Öffnen der aktuellen Datenbankverbindung mit INSERT-, DELETE- oder UPDATE-Anweisung geändert, eingefügt oder gelöscht worden sind. (X) trim(X) removes spaces from both ends of X. (X) trim(X) entfernt Leerzeichen an beiden Enden von X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) Die Funktion ltrim(X,Y) gibt eine Zeichenkette zurück, die durch Entfernen aller Zeichen innerhalb von Y aus der von beiden Seiten von X gebildet wird. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) Die Funktion typeof(X) gibt einen String zurück, der den Datentyp des Ausdrucks X angibt. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) Die Funktion unicode(X) gibt einen numerischen Unicode-Wert zurück, der dem ersten Zeichen der Zeichenkette X entspricht. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) Die Funktion lower(X) gibt eine Kopie der Zeichenkette X mit allen ASCII-Zeichen in Großschreibung zurück. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) Die Funktion zeroblob(N) gibt einen BLOB aus N Bytes mit 0x00 zurück. (timestring,modifier,modifier,...) (Zeitstring,Modifikation,Modifikation,...) (format,timestring,modifier,modifier,...) (Format,Zeitstring,Modifikation,Modifikation,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) Die Funktion avg() gibt den Durchschnittswert alle Nicht-NULL-X in einer Gruppe zurück. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) Die Funktion count(X) gibt die Anzahl der Nicht-NULL-Elemente von X in einer Gruppe zurück. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) Die Funktion group_conact() gibt eine Zeichenkette zurück, die eine Verkettung aller Nicht-NULL-Werte von X ist. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) Die Funktion group_conact() gibt eine Zeichenkette zurück, die eine Verkettung aller Nicht-NULL-Werte von X ist. Wenn der Parameter Y aktiv ist, wird dieser als Trennzeichen zwischen Instanzen von X behandelt. (X) The max() aggregate function returns the maximum value of all values in the group. (X) Die Sammelfunktion max() gibt den Maximalwert aller Werte in der Gruppe zurück. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) Die Sammelfunktion min() gibt den Minimalwert aller Nicht-NULL-Werte in der Gruppe zurück. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) Die Sammelfunktionen sum() und total() geben die Summe aller Nicht-NULL-Werte in der Gruppe zurück. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () Die Anzahl der Zeilen in der aktuellen Partition. Zeilen werden beginnend bei 1 in der durch den Befehl ORDER BY in der Fensterdefinition nummeriert, ansonsten in willkürlicher Reihenfolge. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Die row_number() des ersten Peer in jeder Gruppe - der Rang der aktuellen Zeile mit Lücken. Wenn es keinen Befehl ORDER BY gibt, dann werden alle Zeilen als Peers angesehen und diese Funktion gibt immer 1 zurück. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Die Nummer der Peer-Gruppe der aktuellen Zeile in der Partition - der Rang der aktuellen Reihe ohne Lücken. Partitionen werden mit 1 startend nummeriert in der Reihenfolge, wie sie durch den Befehl ORDER BY in der Fensterdefinition festgelegt ist. Wenn es keinen Befehl ORDER BY gibt, werden alle Zeilen als Peers angesehen und diese Funktion gibt immer 1 zurück. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () Ungeachtet des Namens gibt diese Funktion immer einen Wert zwischen 0.0 und 1.0 identisch zu (Rang - 1)/(Partitionszeilen - 1) zurück, wobei Rang der Wert der eingebauten Fensterfunktion rank() und Partitionszeilen die Gesamtanzahl der Zeilen in der Partition ist. Wenn die Partition nur eine Zeile enthält, gibt diese Funktion 0.0 zurück. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () Die kumulative Verteilung. Berechnet als Zeilenanzahl/Partitionszeilen, wobei Zeilenanzahl der durch row_number() zurückgegebene Wert für den letzten Peer in der Gruppe ist und Partitionszeilen die Anzahl der Zeilen in der Partition. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) Das Argument N wird als Integer behandelt. Diese Funktion teilt die Partition in N Gruppen so gleichmäßig wie möglich auf und weist jeder Gruppe einen Integer zwischen 1 und N zu, in der Reihenfolge, die durch den Befehl ORDER BY definiert ist, ansonsten in beliebiger Reihenfolge. Wenn notwendig, tauchen größere Gruppen als erstes auf. Diese Funktion gibt einen Integerwert zurück, der der Gruppe zugewiesen ist, zu der die aktuelle Zeile gehört. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Gibt das Ergebnis der Evaluation des Ausdrucks expr gegen die vorherige Zeile in der Partition zurück. Wenn es keine vorhergehende Zeile gibt (weil die aktuelle Zeile die erste ist), wird NULL zurückgegeben. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) Wenn das Argument offset angegeben ist, dann muss dieses ein nichtnegativer Integerwert sein. In diesem Fall ist der Rückgabewert das Ergebnis der Evaluation von expr gegen die Zeile, die innerhalb der Partition offset Zeilen weiter oben liegt. Wenn offset 0 ist, wird expr gegen die aktuelle Zeile evaluiert. Wenn vor der aktuellen Zeile nicht genügend Zeilen vorhanden sind, wird NULL zurückgegeben. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) Wenn auch default angegeben ist, dann wird dieser Wert anstatt NULL zurückgegeben, wenn die durch offset angegebene Zeile nicht existiert. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Gibt das Ergebnis der Evaluation des Ausdrucks expr gegen die nächste Zeile in der Partition zurück. Wenn es keine nächste Zeile gibt (weil die aktuelle Zeile die letzte ist), wird NULL zurückgegeben. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) Wenn das Argument offset angegeben ist, dann muss dieses ein nichtnegativer Integerwert sein. In diesem Fall ist der Rückgabewert das Ergebnis der Evaluation von expr gegen die Zeile, die innerhalb der Partition offset Zeilen weiter unten liegt. Wenn offset 0 ist, wird expr gegen die aktuelle Zeile evaluiert. Wenn nach der aktuellen Zeile nicht genügend Zeilen vorhanden sind, wird NULL zurückgegeben. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Diese eingebaute Fensterfunktion berechnet den Fensterrahmen für jede Zeile auf die gleiche Art wie ein aggregierte Fensterfunktion. Sie gibt den Wert von expr evaluiert gegen die erste Zeile im Fensterrahmen für jede Zeile zurück. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Diese eingebaute Fensterfunktion berechnet den Fensterrahmen für jede Zeile auf die gleiche Art wie ein aggregierte Fensterfunktion. Sie gibt den Wert von expr evaluiert gegen die letzte Zeile im Fensterrahmen für jede Zeile zurück. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) Diese eingebaute Fensterfunktion berechnet den Fensterrahmen für jede Zeile auf die gleiche Art wie ein aggregierte Fensterfunktion. Sie gibt den Wert von expr evaluiert gegen die N-te Zeile im Fensterrahmen zurück. Die Zeilen werden beginnend bei 1 in der durch den Befehl ORDER BY definierten Reihenfolge nummeriert, falls dieser vorhanden ist, ansonsten in beliebiger Reihenfolge. Wenn es keine N-te Zeile in der Partition gibt, dann wird NULL zurückgegeben. (X) Return the arccosine of X. The result is in radians. (X) Gibt den Arkuskosinus von X zurück. Das Ergebnis ist im Bogenmaß. (X) Return the hyperbolic arccosine of X. (X) Gibt den Areakosinus hyperbolicus von X zurück. (X) Return the arcsine of X. The result is in radians. (X) Gibt den Arkussinus von X zurück. Das Ergebnis ist im Bogenmaß. (X) Return the hyperbolic arcsine of X. (X) Gibt den Areasinus hyperbolicus von X zurück. (X) Return the arctangent of X. The result is in radians. (X) Gibt den Arkustangens von X zurück. Das Ergebnis ist im Bogenmaß. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X,Y) Den Arkustangens von Y/X ermitteln. Das Ergebnis ist im Bogenmaß. Das Ergebnis wird abhängig von den Vorzeichen von X und Y im korrekten Quadranten platziert. (X) Return the hyperbolic arctangent of X. (X) Gibt den Areatangens hyperbolicus von X zurück. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Gibt die erste darstellbare Ganzzahl größer oder gleich X zurück. Für positive X-Werte wird immer von Null weg gerundet. Für negative X-Werte wird immer in Richtung Null gerundet. (X) Return the cosine of X. X is in radians. (X) Gibt den Kosinus von X zurück. X ist im Bogenmaß. (X) Return the hyperbolic cosine of X. (X) Gibt den Kosinus hyperbolicus von X zurück. (X) Convert value X from radians into degrees. (X) Umwandlung des Wertes X von Bogenmaß in Grad. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Ermittelt e (Eulersche Zahl, ungefähr 2.71828182845905) hoch X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Gibt die erste darstellbare Ganzzahl kleiner oder gleich X zurück. Für positive X-Werte wird immer in Richtung Null gerundet. Für negative X-Werte wird immer von Null weg gerundet. (X) Return the natural logarithm of X. (X) Gibt den natürlichen Logarithmus von X zurück. (B,X) Return the base-B logarithm of X. (B,X) Den Logarithmus von X zur Basis B zurückgeben. (X) Return the base-10 logarithm for X. (X) Gibt den Logarithmus von X zur Basis 10 zurück. (X) Return the logarithm base-2 for the number X. (X) Gibt den Logarithmus von X zur Basis 2 zurück. (X,Y) Return the remainder after dividing X by Y. (X,Y) Den Rest der Division von X durch Y ermitteln. () Return an approximation for Ï€. () Eine Näherung von Ï€ zurückgeben. (X,Y) Compute X raised to the power Y. (X,Y) Berechnung von X hoch Y. (X) Convert X from degrees into radians. (X) Umwandlung des Wertes X von Grad zu Bogenmaß. (X) Return the sine of X. X is in radians. (X) Gibt den Sinus von X zurück. X ist im Bogenmaß. (X) Return the hyperbolic sine of X. (X) Gibt den Sinus hyperbolicus von X zurück. (X) Return the square root of X. NULL is returned if X is negative. (X) Gibt die Quadratwurzel von X zurück. Wenn X negativ ist, wird NULL zurückgegeben. (X) Return the tangent of X. X is in radians. (X) Gibt den Tangens von X zurück. X ist im Bogenmaß. (X) Return the hyperbolic tangent of X. (X) Gibt den Tangens hyperbolicus von X zurück. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) Gibt die darstellbare Ganzzahl zwischen X und 0 (inklusiv) zurück, die am weitesten von Null entfernt ist. Oder, anders formuliert, gibt den Ganzzahl-Teil von X bei Rundung gegen Null zurück. SqliteTableModel reading rows lese Zeilen loading... laden... References %1(%2) Hold %3Shift and click to jump there Referenzen %1(%2) Halten Sie %3Umschalt und klicken Sie, um hierher zu springen Error changing data: %1 Fehler beim Ändern der Daten: %1 retrieving list of columns Liste der Spalten ermitteln Fetching data... Daten abrufen... Cancel Abbrechen TableBrowser Browse Data Daten durchsuchen &Table: &Tabelle: Select a table to browse data Anzuzeigende Tabelle auswählen Use this list to select a table to be displayed in the database view Diese Liste zur Auswahl der in der Datenbankansicht anzuzeigenden Tabelle verwenden This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Dies ist die Datenbanktabellen-Ansicht. Sie können die folgenden Aktionen durchführen: - Mit dem Schreiben beginnen, um die Werte Inline zu bearbeiten. - Doppelt auf einen Eintrag klicken, um dessen Inhalte im Zelleneditor-Fenster zu bearbeiten. - Alt+Entf zum Löschen des Zellinhaltes zu NULL. - Strg+" zur Duplizierung des aktuellen Eintrags. - Strg+' zum Kopieren des Wertes der darüberliegenden Zelle. - Standardmäßige Auswahl- und Kopieren/Einfügen-Operationen. Text pattern to find considering the checks in this frame Zu findendes Textmuster unter Einbeziehung der Prüfungen in diesem Fenster Find in table In Tabelle suchen Find previous match [Shift+F3] Vorherige Übereinstimmung finden [Umschalt+F3] Find previous match with wrapping Vorherige Übereinstimmung mit Umbruch finden Shift+F3 Find next match [Enter, F3] Nächste Übereinstimmung finden [Enter, F3] Find next match with wrapping Nächste Übereinstimmung mit Umbruch finden F3 The found pattern must match in letter case Das Suchmuster muss in Groß-/Kleinschreibung übereinstimmen Case Sensitive Schreibungsabhängig The found pattern must be a whole word Das Muster muss ein ganzes Wort sein Whole Cell Gesamte Zelle Interpret search pattern as a regular expression Suchmuster als regulären Ausdruck interpretieren <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Wenn aktiviert, wird das Suchmuster als regulärer Ausdruck (UNIX-Stil) interpretiert. Siehe <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks (englisch)</a>.</p></body></html> Regular Expression Regulärer Ausdruck Close Find Bar Suchbar schließen Text to replace with Ersetzungstext Replace with Ersetzen mit Replace next match Nächste Übereinstimmung ersetzen Replace Ersetzen Replace all matches Alle Übereinstimmungen ersetzen Replace all Alle ersetzen Export to &JSON Nach &JSON exportieren Export the filtered data to JSON Die gefilterten Daten nach JSON exportieren This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Dieser Button exportiert die Daten der angezeigten Tabelle wie aktuell dargestellt (inklusive Filtern, Anzeigeformaten und Spaltenreihenfolge) als eine JSON-Datei. Copy column name Spaltenname kopieren Copy the database table column name to your clipboard Den Spaltennamen in die Zwischenablage kopieren New Data Browser Neuer Datenbrowser Add a new docked Data Browser Einen neuen angedockten Datenbrowser hinzufügen This button adds a new docked Data Browser, which you can detach and arrange in different layouts. Dieser Button fügt einen neuen angedockten Datenbrowser hinzu, der abgedockt und in verschiedenen Layouts angeordnet werden kann. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Zum Anfang scrollen</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Ein Klick auf diesen Button navigiert zum Anfang der oben angezeigten Tabelle.</p></body></html> |< |< Scroll one page upwards Eine Seite nach oben scrollen <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Ein Klick auf diesen Button navigiert in den Einträgen der Tabellenansicht oben eine Seite nach oben.</p></body></html> < < 0 - 0 of 0 0 - 0 von 0 Scroll one page downwards Eine Seite nach unten scrollen <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Ein Klick auf diesen Button navigiert in den Einträgen der Tabellenansicht oben eine Seite nach unten.</p></body></html> > > Scroll to the end Zum Ende scrollen <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>Ein Klick auf diesen Button navigiert zum Ende der oben angezeigten Tabelle.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html></head><body><p>Klicken Sie hier, um zu einer bestimmten Zeile zu springen</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html></head><body><p>Dieser Button kann zum Navigieren zu einer im Bereich "Springe zu" festgelegten Zeile verwendet werden.</p></body></html> Go to: Springe zu: Enter record number to browse Zeilennummer zum Suchen auswählen Type a record number in this area and click the Go to: button to display the record in the database view Geben Sie eine Zeilennummer in diesem Bereich ein und klicken Sie auf den Button "Springe zu:", um die Zeile in der Datenbankansicht anzuzeigen 1 1 Show rowid column Rowid-Spalte anzeigen Toggle the visibility of the rowid column Sichtbarkeit der Rowid-Spalte umschalten Unlock view editing Ansicht zur Bearbeitung entsperren This unlocks the current view for editing. However, you will need appropriate triggers for editing. Dies entsperrt die aktuelle Ansicht zur Bearbeitung. Allerdings werden zur Bearbeitung passende Trigger benötigt. Edit display format Anzeigeformat bearbeiten Edit the display format of the data in this column Anzeigeformat der Daten in dieser Spalte bearbeiten New Record Neue Zeile Insert a new record in the current table Fügt eine neue Zeile zur aktuellen Tabelle hinzu <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Dieser Button erstellt eine neue Zeile in der Datenbank. Halten sie die Maustaste gedrückt, um ein Popup-Menü mit verschiedenen Optionen zu öffnen:</p><ul><li><span style=" font-weight:600;">Neuer Eintrag</span>: eine neue Zeile mit Standardwerten in die Datenbank einfügen.</li><li><span style=" font-weight:600;">Werte einfügen...</span>: einen Dialog zur Eingabe von Werten öffnen, bevor diese in die Datenbank eingefügt werden. Dies erlaubt die Eingabe von Werten, die den Beschränkungen Genüge tun. Dieser Dialog wird auch geöffnet, wenn die Option <span style=" font-weight:600;">Neuer Eintrag</span> aufgrund dieser Beschränkungen fehlschlägt.</li></ul></body></html> Delete Record Zeile löschen Delete the current record Aktuelle Zeile löschen This button deletes the record or records currently selected in the table Dieser Button löscht die Zeile oder Zeilen, die aktuell in der Tabelle ausgewählt sind Insert new record using default values in browsed table Eine neue Zeile mit den Standardwerten in den ausgewählte Tabelle einfügen Insert Values... Werte einfügen... Open a dialog for inserting values in a new record Einen Dialog zum Einfügen von Werten in eine neue Zeile öffnen Export to &CSV Nach &CSV exportieren Export the filtered data to CSV Die gefilterten Daten als CSV exportieren This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Dieser Button exportiert die Daten der ausgewählten Tabelle wie aktuell angezeigt (gefiltert, Anzeigeformate und Spaltenreihenfolge) als CSV-Datei. Save as &view Als &View speichern Save the current filter, sort column and display formats as a view Den aktuellen Filter, die Spaltenreihenfolge und Anzeigeformate als Ansicht speichern This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Dieser Button speichert die aktuellen Einstellungen der ausgewählten Tabelle (Filter, Anzeigeformate und Spaltenreihenfolge) als SQL-Ansicht, die Sie später durchsuchen oder in SQL-Anweisungen verwenden können. Save Table As... Tabelle speichern als... Save the table as currently displayed Tabelle wie aktuell angezeigt speichern <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>Dieses Popup-Menü bietet die folgenden Optionen zur Anwendung auf die aktuell ausgewählte und gefilterte Tabelle:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CSV exportieren: diese Option exportiert die Daten der ausgewählten Tabelle wie aktuell angezeigt (gefiltert, Anzeigeformat und Spaltenreihenfolge) in eine CSV-Datei.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Als Ansicht speichern: diese Option speichert die aktuelle Einstellung der ausgewählten Tabelle (Filter, Anzeigeformat und Spaltenreihenfolge) als eine SQL-Ansicht, die Sie später durchsuchen oder in SQL-Anweisungen verwenden können.</li></ul></body></html> Hide column(s) Spalte(n) verbergen Hide selected column(s) Ausgewählte Spalte(n) verbergen Show all columns Alle Spalten anzeigen Show all columns that were hidden Alle versteckten Spalten anzeigen Set encoding Codierung setzen Change the encoding of the text in the table cells Codierung des Textes in den Tabellenzellen ändern Set encoding for all tables Codierung für alle Tabellen setzen Change the default encoding assumed for all tables in the database Voreingestellte Codierung für alle Tabellen in der Datenbank ändern Clear Filters Filter löschen Clear all filters Alle Filter löschen This button clears all the filters set in the header input fields for the currently browsed table. Dieser Button löscht alle gesetzten Filter in den Header-Eingabefeldern der aktuell angezeigten Tabelle. Clear Sorting Sortierung löschen Reset the order of rows to the default Die Zeilenreihenfolge auf den Standardzustand zurücksetzen This button clears the sorting columns specified for the currently browsed table and returns to the default order. Dieser Button setzt die angegebene Spaltensortierung für die aktuell angezeigte Tabelle zurück und verwendet die Standardreihenfolge. Print Drucken Print currently browsed table data Aktuell angezeigte Tabellendaten drucken Print currently browsed table data. Print selection if more than one cell is selected. Die aktuell angezeigten Tabellendaten drucken. Auswahl drucken, wenn mehr als eine Zelle ausgewählt ist. Ctrl+P Refresh Aktualisieren Refresh the data in the selected table Die Daten in der ausgewählten Tabelle aktualisieren This button refreshes the data in the currently selected table. Dieser Button aktualisiert die Daten der aktuellen Tabellenansicht. F5 Find in cells In Zellen suchen Open the find tool bar which allows you to search for values in the table view below. Die Such-Werkzeugleiste öffnen, die das Suchen nach Werten in der Tabellenansicht unten erlaubt. Bold Fett Ctrl+B Italic Kursiv Underline Unterstreichung Ctrl+U Align Right Rechts ausrichten Align Left Links ausrichten Center Horizontally Horizontal zentrieren Justify Blocksatz Edit Conditional Formats... Bedingte Formatierungen bearbeiten... Edit conditional formats for the current column Bedingte Formatierungen der aktuellen Spalte bearbeiten Clear Format Formatierung löschen Clear All Formats Alle Formatierungen löschen Clear all cell formatting from selected cells and all conditional formats from selected columns Alle Zellenformatierungen aus den ausgewählten Zellen und alle bedingten Formatierungen aus den ausgewählten Spalten löschen Font Color Schriftfarbe Background Color Hintergrundfarbe Toggle Format Toolbar Formatierungs-Werkzeugleiste umschalten Show/hide format toolbar Formatierungs-Werkzeugleiste anzeigen/verstecken This button shows or hides the formatting toolbar of the Data Browser Dieser Button zeigt oder versteckt die Formatierungs-Werkzeugleiste im Datenbrowser Select column Spalte auswählen Ctrl+Space Replace text in cells Text in Zellen ersetzen Freeze columns Spalten sperren Make all columns from the first column up to this column not move when scrolling horizontally Blockiert die Bewegung aller Spalten von der ersten Spalte bis zu dieser Spalte beim horizontalen Scrollen Filter in any column In allen Spalten filtern Ctrl+R %n row(s) %n Zeile %n Zeilen , %n column(s) , %n Spalte , %n Spalten . Sum: %1; Average: %2; Min: %3; Max: %4 . Summe: %1; Durchschnitt: %2; Minimum: %3; Maximum: %4 Conditional formats for "%1" Bedingte Formatierung für "%1" determining row count... Zeilenanzahl bestimmen... %L1 - %L2 of >= %L3 %L1 - %L2 von >= %L3 %L1 - %L2 of %L3 %L1 - %L2 von %L3 (clipped at %L1 rows) (abgeschnitten bei %L1 Zeilen) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Bitte einen Pseudo-Primärschlüssel eingeben, um die Bearbeitung dieser Ansicht zu ermöglichen. Dies sollte der Name der eindeutigen Spalte dieser Ansicht sein. Delete Records Einträge löschen Duplicate records Einträge duplizieren Duplicate record Eintrag duplizieren Ctrl+" Adjust rows to contents Zeilen an Inhalte anpassen Error deleting record: %1 Fehler beim Löschen des Eintrags: %1 Please select a record first Bitte zuerst einen Eintrag auswählen Please choose a new encoding for all tables. Bitte wählen Sie eine neue Codierung für alle Tabellen. Please choose a new encoding for this table. Bitte wählen Sie eine neue Codierung für diese Tabelle. %1 Leave the field empty for using the database encoding. %1 Lassen Sie das Feld leer, um die Datenbank-Codierung zu verwenden. This encoding is either not valid or not supported. Diese Codierung ist entweder nicht gültig oder nicht unterstützt. %1 replacement(s) made. %1 Ersetzung(en) durchgeführt. TableBrowserDock New Data Browser Neuer Datenbrowser Rename Data Browser Datenbrowser umbenennen Close Data Browser Datenbrowser schließen Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. Einen neuen Namen für den Datenbrowser setzen. Das Zeichen '&&' verwenden, um das folgende Zeichen als Shortcut zu verwenden. VacuumDialog Compact Database Datenbank komprimieren Warning: Compacting the database will commit all of your changes. Warnung: Das Verdichten der Datenbank wird alle Ihre Änderungen übermitteln. Please select the databases to co&mpact: Bitte wählen Sie die zu ver&dichtenden Datenbanken aus: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_en_GB.ts000066400000000000000000012100741463772530400255540ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Version <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Enter values for the new record considering constraints. Fields in bold are mandatory. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Name Type Value Values to insert. Pre-filled default values are inserted automatically unless they are changed. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> Auto-increment Unique constraint Check constraint: %1 Foreign key: %1 Default value: %1 Error adding record. Message from database engine: %1 Are you sure you want to restore all the entered values to their defaults? Application Possible command line arguments: The user settings file location is replaced with the argument value instead of the environment variable value. Ignored environment variable (DB4S_SETTINGS_FILE) value: The file %1 does not exist Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Browse this table, or use it as target of a data import Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The -S/--settings option requires an argument. The option is ignored. The -o/--option and -O/--save-option options require an argument in the form group/setting=value Invalid option/non-existent file: %1 SQLite Version SQLCipher Version %1 (based on SQLite %2) DB Browser for SQLite Version %1. Last commit hash when built: %1 Built for %1, running on %2 Qt Version %1 CipherDialog SQLCipher encryption &Password &Reenter password Encr&yption settings SQLCipher &3 defaults SQLCipher &4 defaults Custo&m Page si&ze &KDF iterations HMAC algorithm KDF algorithm Plaintext Header Size Passphrase Raw key Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. ColumnDisplayFormatDialog Choose display format Display format Choose a display format for the column '%1' which is applied to each value prior to showing it. Default Decimal number Exponent notation Hex blob Hex number Apple NSDate to date Java epoch (milliseconds) to date .NET DateTime.Ticks to date Julian day to date Unix epoch to local time WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy Lower case Binary GUID to text SpatiaLite Geometry to SVG Custom display format must contain a function call applied to %1 Error in custom display format. Message from database engine: %1 Custom display format must return only one column but it returned %1. Octal number Round number Unix epoch to date Upper case Windows DATE to date Custom CondFormatManager Conditional Format Manager This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Add new conditional format &Add Remove selected conditional format &Remove Move selected conditional format up Move &up Move selected conditional format down Move &down Foreground Text color Text colour Background Background color Background colour Font Size Bold Italic Underline Alignment Condition Click to select color Are you sure you want to clear all the conditional formats of this field? DBBrowserDB Please specify the database name under which you want to access the attached database Invalid file format Do you really want to close this temporary database? All data will be lost. Do you want to save the changes made to the database file %1? Database didn't close correctly, probably still busy Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: Do you want to abort that other operation? Exporting database to SQL file... Cancel No database file opened Executing SQL... Action cancelled. Error in statement #%1: %2. Aborting execution%3. and rolling back didn't receive any output from %1 could not execute command: %1 Cannot delete this object Cannot set data on this object A table with the name '%1' already exists in schema '%2'. No table with name '%1' exists in schema '%2'. Cannot find column %1. Renaming the column failed. DB says: %1 Creating new table failed. DB says: %1 Copying data to new table failed. DB says: %1 Deleting old table failed. DB says: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: could not get list of databases: %1 Error loading extension: %1 Error loading built-in extension: %1 could not get column information Error renaming table '%1' to '%2'. Message from database engine: %3 Creating savepoint failed. DB says: %1 Releasing savepoint failed. DB says: %1 could not get list of db objects: %1 Error setting pragma %1 to %2: %3 File not found. DbStructureModel Name Object Type Schema Database Browsables All Temporary Tables (%1) Indices (%1) Views (%1) Triggers (%1) EditDialog Edit database cell Mode: Image Set as &NULL Apply data to cell This button saves the changes performed in the cell editor to the database cell. Apply Text This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. RTL Text Binary JSON XML Evaluation Automatically adjust the editor mode to the loaded data type This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Auto-switch This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Identification of the cell currently in the editor Type and size of data currently in table Open preview dialog for printing the data currently stored in the cell Auto-format: pretty print on loading, compact on saving. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Word Wrap Wrap lines on word boundaries Open in default application or browser Open in application The value is interpreted as a file or URL and opened in the default application or web browser. Save file reference... Save reference to file Open in external application Autoformat &Export... &Import... Import from file Opens a file dialog used to import any kind of data to this database cell. Export to file Opens a file dialog used to export the contents of this database cell to a file. Erases the contents of the cell This area displays information about the data present in this database cell Print... Ctrl+P Open preview dialog for printing displayed text Copy Hex and ASCII Copy selected hexadecimal and ASCII columns to the clipboard Ctrl+Shift+C Choose a filename to export data Image data can't be viewed in this mode. Try switching to Image or Binary mode. Binary data can't be viewed in this mode. Try switching to Binary mode. Image files (%1) Binary files (*.bin) Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) Couldn't save file: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Choose a file to import The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Unsaved data in the cell editor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. %1 Image Invalid data for this mode The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? EditIndexDialog &Name Order &Table Edit Index Schema &Unique For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Partial inde&x clause Colu&mns Table column Type Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Index column Deleting the old index failed: %1 Creating the index failed: %1 EditTableDialog Edit table definition Table Advanced Without Rowid Database sche&ma Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Fields Add Remove Move to top Move up Move down Move to bottom Name Type NN Not null PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> AI Autoincrement U Unique Default Default value Check Check constraint Collation Foreign Key <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Index Constraints Add constraint Remove constraint Columns SQL Foreign Keys References Check Constraints <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> Primary Key Add a primary key constraint Add a unique constraint There can only be one primary key for each table. Please modify the existing primary key instead. Error creating table. Message from database engine: %1 There already is a field with that name. Please rename it first or choose a different name for this field. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Column '%1' has duplicate data. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set ExportDataDialog Export data as CSV Tab&le(s) Colu&mn names in first line Fie&ld separator , ; Tab | Other &Quote character " ' New line characters Windows: CR+LF (\r\n) Unix: LF (\n) Pretty print Could not open output file: %1 Choose a filename to export data Export data as JSON exporting CSV Error while writing the file '%1': %2 exporting JSON Please select at least 1 table. Choose a directory Export completed. Export finished with errors. ExportSqlDialog Export SQL... Tab&le(s) Select All Deselect All &Options Keep column names in INSERT INTO Multiple rows (VALUES) per INSERT statement Export everything Export data only Keep original CREATE statements Keep old schema (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Export schema only Please select at least one table. Choose a filename to export Export completed. Export cancelled or failed. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Find and Replace... Print... ExtendedTableWidget Use as Exact Filter Containing Not containing Not equal to Greater than Less than Greater or equal Less or equal Between this and... Regular expression Edit Conditional Formats... Set to NULL Cut Copy Copy with Headers Copy as SQL Paste Print... Use in Filter Expression Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. FileExtensionManager File Extension Manager &Up &Down &Add &Remove Description Extensions *.extension FilterLineEdit Filter These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Clear All Conditional Formats Use for Conditional Format Edit Conditional Formats... Set Filter Expression What's This? Is NULL Is not NULL Is empty Is not empty Not containing... Equal to... Not equal to... Greater than... Less than... Greater or equal... Less or equal... In range... Regular expression... FindReplaceDialog Find and Replace Fi&nd text: Re&place with: Match &exact case Match &only whole words When enabled, the search continues from the other end when it reaches one end of the page &Wrap around When set, the search goes backwards from cursor position, otherwise it goes forward Search &backwards <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> &Selection only <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Use regular e&xpressions Find the next occurrence from the cursor position and in the direction set by "Search backwards" &Find Next F3 &Replace Highlight all the occurrences of the text in the page F&ind All Replace all the occurrences of the text in the page Replace &All The searched text was not found The searched text was not found. The searched text was found one time. The searched text was found %1 times. The searched text was replaced one time. The searched text was replaced %1 times. ForeignKeyEditor &Reset Foreign key clauses (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Reset the scaling to match the original size of the image. Set the scaling to match the size of the viewport. Print... Open preview dialog for printing displayed image Ctrl+P ImportCsvDialog Import CSV file Table na&me &Column names in first line Field &separator , ; Tab | Other &Quote character Other (printable) Other (code) " ' &Encoding UTF-8 UTF-16 ISO-8859-1 Trim fields? Separate tables Advanced When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Ignore default &values Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Fail on missing values Disable data type detection Disable the automatic data type detection when creating a new table. Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Abort import Ignore row Replace existing row Conflict strategy Deselect All Match Similar Select All There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. There is already a table named '%1'. Do you want to import the data into it? Creating restore point failed: %1 Creating the table failed: %1 importing CSV Could not prepare INSERT statement: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Inserting row failed: %1 MainWindow DB Browser for SQLite toolBar1 Opens the SQLCipher FAQ in a browser window Export one or more table(s) to a JSON file &File &Import &Export &Edit &View &Help DB Toolbar Edit Database &Cell DB Sche&ma &Remote Execute current line This button executes the SQL statement present in the current editor line Shift+F5 Sa&ve Project Open an existing database file in read only mode User This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Un/comment block of SQL code Un/comment block Comment or uncomment current line or selected block of code Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Ctrl+/ Stop SQL execution Stop execution Stop the currently running SQL script Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Too&ls Application Error Log This button clears the contents of the SQL logs &Clear This panel lets you examine a log of all SQL commands issued by the application or by yourself This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Project Toolbar Extra DB toolbar Close the current database file &New Database... Create a new database file This option is used to create a new database file. Ctrl+N &Open Database... Open an existing database file This option is used to open an existing database file. Ctrl+O &Close Database This button closes the connection to the currently open database file Ctrl+W Revert database to last saved state This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Write changes to the database file This option is used to save changes to the database file. Ctrl+S Compact &Database... Compact the database file, removing space wasted by deleted records Compact the database file, removing space wasted by deleted records. E&xit Ctrl+Q Import data from an .sql dump text file into a new or existing database. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Open a wizard that lets you import data from a comma separated text file into a database table. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Export a database to a .sql dump text file. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Export a database table as a comma separated text file. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Delete Table Open the Delete Table wizard, where you can select a database table to be dropped. Open the Create Index wizard, where it is possible to define a new index on an existing database table. &Preferences... Open the preferences window. &DB Toolbar Shows or hides the Database toolbar. Shift+F1 New &tab Open SQL file(s) This button opens files containing SQL statements and loads them in new editor tabs Execute line &Wiki F1 Bug &Report... Feature Re&quest... Web&site &Donate on Patreon... &Save Project This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Open &Project This button lets you open a DB Browser for SQLite project file Ctrl+Shift+O &Save Project As... Save the project in a file selected in a dialog Save A&ll Save DB file, project file and opened SQL files Ctrl+Shift+S Browse Table Close Pro&ject Close project and database files and return to the initial state Ctrl+Shift+F4 Detach Database Detach database file attached to the current database connection &Attach Database... Add another database file to the current database connection This button lets you add another database file to the current database connection &Set Encryption... SQLCipher &FAQ Table(&s) to JSON... Open Data&base Read Only... Save results Save the results view This button lets you save the results of the last executed query Find text in SQL editor Find This button opens the search bar of the editor Ctrl+F Find or replace text in SQL editor Find or replace This button opens the find/replace dialog for the current editor tab Ctrl+H Export to &CSV Export to &JSON Save as &view Save as view Shows or hides the Project toolbar. Extra DB Toolbar &Open Database New In-&Memory Database Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Drag && Drop Qualified Names Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Drag && Drop Enquoted Names Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor &Integrity Check Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. &Foreign-Key Check Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab &Quick Integrity Check Run a quick integrity check over the open DB Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. &Optimize Attempt to optimize the database Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Print Print text from current SQL editor tab Open a dialog for printing the text in the current SQL editor tab Print the structure of the opened database Open a dialog for printing the structure of the opened database Ctrl+Shift+W Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Refresh Reload the database structure &Recently opened Ctrl+T SQL &Log &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs E&xecute SQL This has to be equal to the tab title in all the main tabs &Recent Files Show S&QL submitted by &Plot &New Database Ctrl+F4 &Revert Changes &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. &Write Changes &Database from SQL file... &Table from CSV file... &Database to SQL file... &Table(s) as CSV file... &Create Table... &Delete Table... &Modify Table... Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Create &Index... W&hat's This? &About This button opens a new tab for the SQL editor &Execute SQL Execute all/selected SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Ctrl+Shift+T Save SQL file &Load Extension... Ctrl+E Export as CSV file Export table as comma separated values file Save the current session to a file Open &Project... Load a working session from a file Save SQL file as This button saves the content of the current SQL editor tab to a file &Browse Table Copy Create statement Copy the CREATE statement of the item to the clipboard Ctrl+Return Ctrl+L Ctrl+P Ctrl+D Ctrl+I Encrypted Read only Database file is read only. Editing the database is disabled. Database encoding Database is encrypted using SQLCipher Choose a database file Choose a filename to save under Error checking foreign keys after table modification. The changes will be reverted. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. At line %1: Result: %2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? Choose a file to import Text files(*.sql *.txt);;All files(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Automatically load the last opened DB file at startup Alt+Shift+0 The database is currently busy. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Do you want to save the changes made to the project file '%1'? File %1 already exists. Please choose a different name. Error importing data: %1 Import completed. Delete View Modify View Delete Trigger Modify Trigger Delete Index Modify Index Modify Table Do you want to save the changes made to SQL tabs in a new project file? Do you want to save the changes made to the SQL file %1? Could not find resource file: %1 Choose a project file to open Could not open project file for writing. Reason: %1 Busy (%1) Setting PRAGMA values will commit your current transaction. Are you sure? Reset Window Layout Click here to interrupt the currently running query. Ctrl+Alt+W Could not open database file. Reason: %1 In-Memory database Choose a database file to save under Error while saving the database to the new file. Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Are you sure you want to delete the view '%1'? Are you sure you want to delete the trigger '%1'? Are you sure you want to delete the index '%1'? Error: could not delete the table. Error: could not delete the view. Error: could not delete the trigger. Error: could not delete the index. Message from database engine: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Edit View %1 Edit Trigger %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. -- EXECUTING SELECTION IN '%1' -- -- EXECUTING LINE IN '%1' -- -- EXECUTING ALL IN '%1' -- Result: %1 %1 rows returned in %2ms Choose text files Import completed. Some foreign key constraints are violated. Please fix them before saving. Opened '%1' in read-only mode from recent file list Opened '%1' from recent file list &%1 %2%3 (read only) Open Database or Project Attach Database... Import CSV file(s)... Do you want to save the changes made to SQL tabs in the project file '%1'? The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? Select SQL file to open DB file '%1' could not be opened This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Table '%1' not found; settings ignored -- Reference to file "%1" (not supported by this version) -- Yes. Don't ask again This action will open a new SQL tab with the following statements for you to edit and run: Rename Tab Duplicate Tab Close Tab Opening '%1'... There was an error opening '%1'... Value is not a valid URL or filename: %1 Select file name Ctrl+Tab Ctrl+Shift+Tab Clear List Window Layout Ctrl+Alt+0 Simplify Window Layout Dock Windows at Bottom Dock Windows at Left Side Dock Windows at Top Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Select extension file Extension successfully loaded. Error loading extension: %1 Don't show again New version available. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Project saved to file '%1' Collation needed! Proceed? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! creating collation Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Please specify the view name There is already an object with that name. Please choose a different name. View successfully created. Error creating view: %1 This action will open a new SQL tab for running: Press Help for opening the corresponding SQLite reference page. DB Browser for SQLite project file (*.sqbpro) Execution finished with errors. Execution finished without errors. NullLineEdit Set to NULL Alt+Del PlotDock Plot <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used colour for that graph.</p></body></html> Columns X Y1 Y2 Axis Type Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Line type: None Line StepLeft StepRight StepCenter Impulse Point shape: Cross Plus Circle Disc Square Diamond Star Triangle TriangleInverted CrossSquare PlusSquare CrossCircle PlusCircle Peace <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> Save current plot... Load all data and redraw plot Row # Copy Print... Show legend Stacked bars Fixed number format Date/Time Date Time Numeric Label Invalid Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Choose an axis color Choose an axis colour Choose a filename to save under PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Loading all remaining data for this table took %1ms. PreferencesDialog Preferences &General Remember last location Always use this location Remember last location for session only ... Default &location Lan&guage Automatic &updates enabled Show remote options &Database Database &encoding Open databases with foreign keys enabled. &Foreign keys SQ&L to execute after opening database Data &Browser Remove line breaks in schema &view Prefetch block si&ze Default field type Font &Font Content Symbol limit in cell NULL Regular Binary Background Filters Threshold for completion and calculation on selection Escape character Delay time (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. &SQL Context Colour Bold Italic Underline Keyword Function Table Comment Identifier String Current line SQL &editor font size Tab size SQL editor &font Error indicators Hori&zontal tiling If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Code co&mpletion Toolbar style Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style DB file extensions Manage Main Window Database Structure Browse Data Execute SQL Edit Database Cell When this value is changed, all the other color preferences are also set to matching colors. Follow the desktop style Dark style Application style This sets the font size for all UI elements which do not have their own font size option. Font size Max Recent Files Prompt to save SQL tabs in new project file If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Database structure font size Font si&ze This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Show images in cell Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Field display Light style Displayed &text Formatted Click to set this color Text color Text colour Background color Background colour Preview only (N/A) Foreground Selection background Selection foreground Highlight SQL &results font size Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. &Wrap lines Never At word boundaries At character boundaries At whitespace boundaries &Quotes for identifiers Choose the quoting mechanism used by the application for identifiers in SQL code. "Double quotes" - Standard SQL (recommended) `Grave accents` - Traditional MySQL quotes [Square brackets] - Traditional MS SQL Server quotes Keywords in &UPPER CASE When set, the SQL keywords are completed in UPPER CASE letters. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Close button on tabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. &Extensions Select extensions to load for every database: Add extension Remove extension Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> Disable Regular Expression extension <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> Allow loading extensions from SQL code Remote CA certificates Proxy Configure Export Settings Import Settings Subject CN Common Name Subject O Organization Valid from Valid to Serial number Your certificates File Subject Common Name Issuer CN Issuer Common Name Clone databases into Choose a directory The language will change after you restart the application. Select extension file Extensions(*.so *.dylib *.dll);;All files(*) Import certificate file No certificates found in this file. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Save Settings File Initialization File (*.ini) The settings file has been saved in location : Open Settings File The settings file was loaded properly. The selected settings file is not a normal settings file. Please check again. ProxyDialog Proxy Configuration Pro&xy Type Host Na&me Port Authentication Re&quired &User Name Password None System settings HTTP SOCKS5 QObject Error importing data from record number %1 . %1 Importing CSV file... Cancel All files (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Left Right Center Justify SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) SQL Files (*.sql) All Files (*) Text Files (*.txt) Comma-Separated Values Files (*.csv) Tab-Separated Values Files (*.tsv) Delimiter-Separated Values Files (*.dsv) Concordance DAT files (*.dat) JSON Files (*.json *.js) XML Files (*.xml) Binary Files (*.bin *.dat) SVG Files (*.svg) Hex Dump Files (*.dat *.bin) Extensions (*.so *.dylib *.dll) Initialization File (*.ini) RemoteCommitsModel Commit ID Message Date Author Size Authored and committed by %1 Authored by %1, committed by %2 RemoteDatabase Error opening local databases list. %1 Error creating local databases list. %1 RemoteDock Remote Identity Push currently opened database to server Upload DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> Local Current Database Clone &User &Database Branch Commits Commits for <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> Back Delete Database Delete the local clone of this database Open in Web Browser Open the web page for the current database in your browser Clone from Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. Refresh Reload all data and update the views Clone Database Open Database Open the local copy of this database Check out Commit Download and open this specific commit Check out Latest Commit Check out the latest commit of the current branch Save Revision to File Saves the selected revision of the database to another file Upload Database Upload this database as a new commit Select an identity to connect Public This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Invalid URL: The host name does not match the host name of the current identity. Invalid URL: No branch name specified. Invalid URL: No commit ID specified. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? The database has unsaved changes. Are you sure you want to push it before saving? The database you are trying to delete is currently opened. Please close it before deleting. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? RemoteLocalFilesModel Name Branch Last modified Size Commit File RemoteModel Name Commit Last modified Size Size: Last Modified: Licence: Default Branch: RemoteNetwork Choose a location to save the file Error opening remote file at %1. %2 Error: Invalid client certificate specified. Please enter the passphrase for this client certificate in order to authenticate. Cancel Uploading remote database to %1 Downloading remote database from %1 Error: Cannot open the file for sending. RemotePushDialog Push database Database na&me to push to Commit message Database licence Public Branch Force push Username Database will be public. Everyone has read access to it. Database will be private. Only you have access to it. Use with care. This can cause remote commits to be deleted. RunSql Execution aborted by user , %1 rows affected query executed successfully. Took %1ms%2 executing query SelectItemsPopup A&vailable Sele&cted SqlExecutionArea Form Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 The found pattern must be a whole word Whole Words Text pattern to find considering the checks in this frame Find in editor The found pattern must match in letter case Case Sensitive Find next match [Enter, F3] Find next match with wrapping F3 Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Close Find Bar <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> Results of the last executed statements This field shows the results and status codes of the last executed statements. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Couldn't save file: %1. Your changes will be lost when reloading it! The file "%1" was modified by another program. Do you want to reload it?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) ltrim(X) removes spaces from the left side of X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X) rtrim(X) removes spaces from the right side of X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. (X) trim(X) removes spaces from both ends of X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. SqliteTableModel reading rows loading... References %1(%2) Hold %3Shift and click to jump there Error changing data: %1 retrieving list of columns Fetching data... Cancel TableBrowser Browse Data &Table: Select a table to browse data Use this list to select a table to be displayed in the database view This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Text pattern to find considering the checks in this frame Find in table Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 Find next match [Enter, F3] Find next match with wrapping F3 The found pattern must match in letter case Case Sensitive The found pattern must be a whole word Whole Cell Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Close Find Bar Text to replace with Replace with Replace next match Replace Replace all matches Replace all <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> Copy column name Copy the database table column name to your clipboard New Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> |< Scroll one page upwards <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> < 0 - 0 of 0 Scroll one page downwards <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> > Scroll to the end <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> Go to: Enter record number to browse Type a record number in this area and click the Go to: button to display the record in the database view 1 Show rowid column Toggle the visibility of the rowid column Unlock view editing This unlocks the current view for editing. However, you will need appropriate triggers for editing. Edit display format Edit the display format of the data in this column New Record Insert a new record in the current table Delete Record Delete the current record This button deletes the record or records currently selected in the table Insert new record using default values in browsed table Insert Values... Open a dialog for inserting values in a new record Export to &CSV Export the filtered data to CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Save as &view Save the current filter, sort column and display formats as a view This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Save Table As... Save the table as currently displayed Hide column(s) Hide selected column(s) Show all columns Show all columns that were hidden Set encoding Change the encoding of the text in the table cells Set encoding for all tables Change the default encoding assumed for all tables in the database Clear Filters Clear all filters This button clears all the filters set in the header input fields for the currently browsed table. Clear Sorting Reset the order of rows to the default This button clears the sorting columns specified for the currently browsed table and returns to the default order. Print Print currently browsed table data Print currently browsed table data. Print selection if more than one cell is selected. Ctrl+P Refresh Refresh the data in the selected table This button refreshes the data in the currently selected table. F5 Find in cells Open the find tool bar which allows you to search for values in the table view below. Bold Ctrl+B Italic Underline Ctrl+U Align Right Align Left Center Horizontally Justify Edit Conditional Formats... Edit conditional formats for the current column Clear Format Clear All Formats Clear all cell formatting from selected cells and all conditional formats from selected columns Font Color Background Color Toggle Format Toolbar Show/hide format toolbar This button shows or hides the formatting toolbar of the Data Browser Select column Ctrl+Space Replace text in cells Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally Filter in any column Ctrl+R %n row(s) %n row %n rows , %n column(s) , %n column , %n columns . Sum: %1; Average: %2; Min: %3; Max: %4 Conditional formats for "%1" determining row count... %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Delete Records Duplicate records Duplicate record Ctrl+" Adjust rows to contents Error deleting record: %1 Please select a record first Please choose a new encoding for all tables. Please choose a new encoding for this table. %1 Leave the field empty for using the database encoding. This encoding is either not valid or not supported. %1 replacement(s) made. TableBrowserDock New Data Browser Rename Data Browser Close Data Browser Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. VacuumDialog Compact Database Warning: Compacting the database will commit all of your changes. Please select the databases to co&mpact: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_es_ES.ts000066400000000000000000014016741463772530400256100ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Acerca de «DB Browser for SQLite» Version Versión <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> <html><head/><body><p><em>DB Browser for SQLite</em> es una herramienta visual gratuita y de código abierto que se utiliza para crear, diseñar y editar archivos de bases de datos SQLite.</p><p>Tiene licencia doble bajo la Licencia Pública de Mozilla versión 2, así como la Licencia Pública General de GNU versión 3 o posterior. Puede modificarlo o redistribuirlo bajo las condiciones de estas licencias.</p><p>Vea <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> y <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> para los detalles.</p><p>Para obtener más información sobre este programa, visite nuestra página en: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Esta aplicación usa el Qt Toolkit GPL/LGPL de </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>Vea </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> para los detalles y los términos de licencia.</span></p><p><span style=" font-size:8pt;">Utilizamos la biblioteca nalgeon/sqlen para el soporte de extensiones SQLite.<br/>Esta biblioteca se distribuye bajo la licencia MIT, vea lo siguiente para más información:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">También utiliza el conjunto de iconos SVG de Michael Buckley bajo licencia Creative Commons Attribution Share Alike 4.0.<br/>Vea </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> para los detalles.</span></p></body></html> AddRecordDialog Add New Record Añadir nuevo registro Enter values for the new record considering constraints. Fields in bold are mandatory. Introduzca valores para el nuevo registro teniendo en cuenta las restricciones. Los campos en negrita son obligatorios. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. En la columna Valor puede especificar el valor del campo identificado en la columna Nombre. La columna Tipo indica el tipo de campo. Los valores por defecto se muestran en la misma tipografía que los valores NULL. Name Nombre Type Tipo Value Valor Values to insert. Pre-filled default values are inserted automatically unless they are changed. Valores a insertar. Los valores mostrados por defecto son insertados automáticamente a menos que se cambien. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Cuando se editan los valores en el cuadro superior, aquí se muestra la consulta SQL para insertar este nuevo registro. Puede editarla antes de guardar. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Guardar</span> enviará a la base de datos la sentencia SQL mostrada para insertar el nuevo registro.</p><p><span style=" font-weight:600;">Restituir valores por Defecto</span> restituirá los valores iniciales en la columna <span style=" font-weight:600;">Valor</span></p><p><span style=" font-weight:600;">Cancelar</span> cierra este diálogo sin ejecutar la consulta.</p></body></html> Auto-increment Auto-incremento Unique constraint Restricción UNIQUE Check constraint: %1 Restricción CHECK: %1 Foreign key: %1 Clave foránea: %1 Default value: %1 Valor por defecto: %1 Error adding record. Message from database engine: %1 Error añadiendo registro. Mensaje de la base de datos: %1 Are you sure you want to restore all the entered values to their defaults? ¿Está seguro de que quiere restaurar todos los valores introducidos a sus valores por defecto? Application Possible command line arguments: Argumentos de línea de comandos disponibles: The -o/--option and -O/--save-option options require an argument in the form group/setting=value Las opciones -o/--option y -O/--save-option requieren un argumento de la forma grupo/ajuste=valor The user settings file location is replaced with the argument value instead of the environment variable value. La ubicación del archivo de ajustes de usuario es reemplazada por el valor del argumento, en vez del valor de la variable de entorno. Ignored environment variable (DB4S_SETTINGS_FILE) value: Valor ignorado de la variable de entorno (DB4S_SETTINGS_FILE): The file %1 does not exist El archivo %1 no existe Usage Uso options opciones database base-de-datos project proyecto csv-file archivo-csv Show command line options Mostrar opciones de línea de comandos Exit application after running scripts Salir de la aplicación tras ejecutar los scripts file archivo Execute this SQL file after opening the DB Ejecutar este archivo de SQL tras abrir la base de datos Import this CSV file into the passed DB or into a new DB Importar este archivo CSV a la base de datos pasada o en una nueva base de datos table tabla Browse this table, or use it as target of a data import Mostrar esta tabla en la hoja de datos tras abrir la base de datos Open database in read-only mode Abrir base de datos en modo de solo-lectura settings_file The other command-line placeholders are using "-" so this is more consistent than the original. archivo-ajustes Run application based on this settings file Ejecutar la aplicación basándose en este archivo de ajustes group grupo settings ajustes value valor Run application with this setting temporarily set to value Ejecutar la aplicación con este ajuste establecido temporalmente a este valor Run application saving this value for this setting Ejecutar la aplicación guardando este valor para este ajuste Display the current version Mostrar la versión actual Open this SQLite database Abrir esta base de datos SQLite Open this project file (*.sqbpro) Abrir este archivo de proyecto (*.sqbpro) Import this CSV file into an in-memory database Importar este archivo CSV a una base de datos en memoria The %1 option requires an argument La opción %1 necesita un argumento The -S/--settings option requires an argument. The option is ignored. La opción -S/--settings necesita un argumento. La opción es ignorada. SQLite Version Versión de SQLite SQLCipher Version %1 (based on SQLite %2) Versión de SQLCipher %1 (basado en SQLite %2) DB Browser for SQLite Version %1. «DB Browser for SQLite» Versión %1. Last commit hash when built: %1 Último «commit hash» cuando fue compilado: %1 Built for %1, running on %2 Compilado para %1, ejecutándose en %2 Qt Version %1 Versión de Qt %1 Invalid option/non-existent file: %1 Opción inválida o archivo inexistente: %1 CipherDialog SQLCipher encryption Cifrado con SQLCipher &Password &Clave &Reenter password &Reintroducir clave Encr&yption settings Ajustes de &cifrado SQLCipher &3 defaults Predeterminados de SQLCipher &3 SQLCipher &4 defaults Predeterminados de SQLCipher &4 Custo&m &Personalizado Page si&ze &Tamaño de página &KDF iterations Iteraciones &KDF HMAC algorithm Algoritmo HMAC KDF algorithm Algoritmo KDF Plaintext Header Size Tamaño de la cabecera del texto en claro Passphrase Frase de contraseña Raw key Clave en bruto Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Por favor, elija una clave para cifrar la base de datos. Tenga en cuenta que: - Si modifica cualquiera de los otros ajustes opcionales necesitará reintroducirlos también cada vez que abra la base de datos. - Puede dejar los campos de clave en blanco para no usar cifrado. - El proceso de cifrado puede llevar algún tiempo. - ¡Debería hacer una copia de respaldo de la base de datos! - Los cambios no guardados son aplicados antes de modificar el cifrado. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Por favor, introduzca la clave a usar en el cifrado de la base de datos. Si se modificaron cualquiera de los otros ajustes para este archivo de base de datos, también tendrá que proporcionar esta información. ColumnDisplayFormatDialog Choose display format Elija el formato de presentación Display format Formato de presentación Choose a display format for the column '%1' which is applied to each value prior to showing it. Elija el formato para la columna «%1» el cual se aplicará a cada valor antes de mostrarlo. Default Por defecto Decimal number Número decimal Exponent notation Notación exponencial Hex blob Secuencia hexadecimal Hex number Número hexadecimal Apple NSDate to date Fecha de Apple NSDate a fecha Java epoch (milliseconds) to date Tiempo Java (milisegundos) a fecha .NET DateTime.Ticks to date DateTime.Ticks de .NET a fecha Julian day to date Fecha juliana a fecha Unix epoch to local time Tiempo Unix a hora local WebKit / Chromium epoch to date WebKit / Chromium epoch a fecha WebKit / Chromium epoch to local time WebKit / Chromium epoch a hora local Date as dd/mm/yyyy Fecha dd/mm/aaaa Lower case Minúsculas Binary GUID to text GUID binario a texto SpatiaLite Geometry to SVG Geometría SpatiaLite a SVG Custom display format must contain a function call applied to %1 El formato de presentación a medida tiene que contener una llamada de función aplicada a %1 Error in custom display format. Message from database engine: %1 Error en el formato de presentación a medida. Mensaje del motor de la base de datos: %1 Custom display format must return only one column but it returned %1. El formato de presentación a medida debe devolver sólo una columna pero ha devuelto %1. Octal number Número octal Round number Número redondeado Unix epoch to date Tiempo Unix a fecha Upper case Mayúsculas Windows DATE to date Fecha Windows a fecha Custom A medida CondFormatManager Conditional Format Manager Gestor de Formato Condicional This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Este diálogo permite crear y editar formatos condicionales. Cada estilo de celda será seleccionado por la primera condición que se cumpla para los datos de esa celda. Los formatos condicionales se pueden mover arriba y abajo, teniendo precedencia aquellos en líneas superiores sobre los inferiores. La sintaxis es la misma que para los filtros y se aplica una condición vacía a todos los valores. Add new conditional format Añadir un nuevo formato condicional &Add &Añadir Remove selected conditional format Elimina el formato condicional seleccionado &Remove &Eliminar Move selected conditional format up Mueve arriba el formato condicional seleccionado Move &up Mueve a&rriba Move selected conditional format down Mueve abajo el formato condicional seleccionado Move &down Mueve a&bajo Foreground Texto Text color Color del texto Background Fondo Background color Color del fondo Font Tipo de letra Size Tamaño Bold Negrita Italic Cursiva Underline Subrayado Alignment Justificado Condition Condición Click to select color Haga clic para seleccionar el color Are you sure you want to clear all the conditional formats of this field? ¿Está seguro de que quiere borrar todos los formatos condicionales de este campo? DBBrowserDB Please specify the database name under which you want to access the attached database Por favor, especifique el nombre con el que acceder a la base de datos anexada Invalid file format Formato de archivo inválido Do you want to save the changes made to the database file %1? ¿Guardar los cambios hechos al archivo de base de datos «%1»? Exporting database to SQL file... Exportando base de datos a un archivo SQL... Cancel Cancelar Executing SQL... Ejecutando SQL... Action cancelled. Acción cancelada. Do you really want to close this temporary database? All data will be lost. ¿Está seguro de que quiere cerrar esta base de datos temporal? Todos los datos se perderán. Database didn't close correctly, probably still busy La base de datos no se ha cerrado correctamente, probablemente todavía está ocupada Cannot open destination file: '%1' No se puede abrir el archivo de destino: «%1» Cannot backup to file: '%1'. Message: %2 No se puede guardar copia de seguridad en el archivo: «%1». Mensaje: %2 The database is currently busy: La base de datos está actualmente ocupada: Do you want to abort that other operation? ¿Desea abortar la otra operación? No database file opened No hay una base de datos abierta Error in statement #%1: %2. Aborting execution%3. Error en la sentencia #%1: %2. Abortando ejecución%3. and rolling back y deshaciendo cambios didn't receive any output from %1 no se recibió ninguna salida de «%1» could not execute command: %1 no se pudo ejecutar el comando: «%1» Cannot delete this object No se puede borrar este objeto Cannot set data on this object No se pueden poner datos en este objeto A table with the name '%1' already exists in schema '%2'. Una tabla con el nombre «%1» ya existe en el esquema «%2». No table with name '%1' exists in schema '%2'. No existe una tabla con el nombre «%1» en el esquema «%2». Cannot find column %1. No se puede encontrar la columna %1. Creating savepoint failed. DB says: %1 Creación del punto de guardado fallido. La base de datos dice: %1 Renaming the column failed. DB says: %1 Renombrado de la columna fallido. La base de datos dice: %1 Releasing savepoint failed. DB says: %1 Liberación del punto de guardado fallido. La base de datos dice: %1 Creating new table failed. DB says: %1 Creación de la nueva tabla fallida. La base de datos dice: %1 Copying data to new table failed. DB says: %1 Copia de datos a la nueva tabla fallida. La base de datos dice: %1 Deleting old table failed. DB says: %1 Borrado de tabla fallido. La base de datos dice: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 Error renombrando la tabla «%1» a «%2». Mensaje de la base de datos: %3 could not get list of db objects: %1 No se pudo obtener la lista de objetos de la base de datos: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: La restitución de algunos de los objetos asociados con esta tabla ha fallado. Lo más probable es que esto suceda porque los nombres de algunas columnas han cambiado. Esta es la sentencia SQL que puede que quiera corregir y ejecutar manualmente: could not get list of databases: %1 no se pudo obtener lista de bases de datos: %1 Error loading extension: %1 Error cargando la extensión: %1 Error loading built-in extension: %1 Error cargando extensión incorporada: %1 could not get column information No se pudo obtener información de la columna Error setting pragma %1 to %2: %3 Error definiendo pragma %1 como %2: %3 File not found. Archivo no encontrado. DbStructureModel Name Nombre Object Objeto Type Tipo Schema Esquema Database Base de datos Browsables Navegables All Todos Temporary Temporal Tables (%1) Tablas (%1) Indices (%1) Ãndices (%1) Views (%1) Vistas (%1) Triggers (%1) Disparadores (%1) EditDialog Edit database cell Editar celda de la base de datos Mode: Modo: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Esta es la lista de modos admitidos en el editor de celdas. Elija un modo para visualizar o editar los datos de la celda actual. RTL Text Texto RTL Image Imagen JSON JSON XML XML Evaluation Evaluación Automatically adjust the editor mode to the loaded data type Ajustar automáticamente el modo de edición al tipo de datos cargados This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Esta casilla activa o desactiva el cambio automático del modo de edición. Cuando se selecciona una nueva celda o se importan nuevos datos y la selección automática está activada, el modo de edición se ajusta al tipo de datos detectados. El modo de edición para la celda se puede cambiar manualmente. Si prefiere mantener el modo de edición seleccionado manualmente mientras se mueve por las celdas, desmarque la casilla. Auto-switch Auto-selección This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Este editor Qt se usa para scripts de derecha-a-izquierda, que no están soportados por el editor de Texto por defecto. Al detectar la presencia de caracteres de derecha-a-izquierda este modo de edición se activa automáticamente. Identification of the cell currently in the editor Identificación de la celda actualmente en el editor Type and size of data currently in table Tipo y tamaño de la celda actualmente en la tabla Open preview dialog for printing the data currently stored in the cell Abrir diálogo de previsualización para imprimir los datos actualmente almacenados en la celda Auto-format: pretty print on loading, compact on saving. Auto-formato: dar formato al cargar, compactar al guardar. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Si se habilita, la opción de auto-formato da formato a los datos al cargarlos, rompiendo y sangrando las líneas de texto para una legibilidad máxima. Al guardar los datos, esta opción los compacta, eliminando fines de línea y espacio en blanco innecesario. Word Wrap Ajuste del Texto Wrap lines on word boundaries Ajustar las líneas en palabras completas Open in default application or browser Abrir en la aplicacion por defecto o navegador Open in application Abrir en una aplicacion The value is interpreted as a file or URL and opened in the default application or web browser. El valor es interpretado como un nombre de archivo o URL y abierto en la aplicación por defecto del sistema o el navegador de internet. Save file reference... Guardar referencia de archivo... Save reference to file Guardar referencia a archivo Open in external application Abrir en una aplicación externa Autoformat Auto-formato &Export... &Exportar... &Import... &Importar... Import from file Importar desde archivo Opens a file dialog used to import any kind of data to this database cell. Abre un diálogo para elegir el archivo para importar cualquier tipo de datos a esta celda. Export to file Exportar a archivo Opens a file dialog used to export the contents of this database cell to a file. Abre un diálogo para elegir el archivo al que exportar el contenido de esta celda de la base de datos. Print... Imprimir... Ctrl+P Open preview dialog for printing displayed text Abre un diálogo de previsualización para imprimir el texto mostrado Copy Hex and ASCII Copiar hex. y ASCII Copy selected hexadecimal and ASCII columns to the clipboard Copia las columnas seleccionadas en hexadecimal y ASCII al portapapeles Ctrl+Shift+C Set as &NULL Borrar a &NULL Apply data to cell Aplicar los datos a la celda This button saves the changes performed in the cell editor to the database cell. Este botón guarda los cambios realizados en el editor a la celda de la base de datos. Apply Aplicar Text Texto Binary Binario Erases the contents of the cell Borra el contenido de la celda This area displays information about the data present in this database cell Esta zona muestra información acerca de los datos presentes en esta celda de la base de datos Choose a filename to export data Seleccione un nombre de archivo para exportar los datos Image data can't be viewed in this mode. Datos de imagen no se pueden visualizar en este modo. The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Los modos de edición de texto permiten editar texto plano, y también JSON o XML con resaltado de sintaxis, formato automático y validación previa a guardar. Los errores se indican con un subrayado ondulado en rojo. En el modo de Evaluación, las expresiones de SQLite se evalúan y el resultado se aplica a la celda. Unsaved data in the cell editor Datos sin guardar en el editor de celdas The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? El editor de celdas contiene datos aún no aplicados a la base de datos. ¿Desea aplicar los datos editados a la fila=%1, columna=%2? Editing row=%1, column=%2 Editando fila=%1, columna=%2 No cell active. No hay celda activa. Try switching to Image or Binary mode. Intente cambiando al modo «Imagen» o «Binario». Binary data can't be viewed in this mode. Datos binarios no se pueden visualizar en este modo. Try switching to Binary mode. Intente cambiando al modo «Binario». Image files (%1) Archivos de imagen (%1) Binary files (*.bin) Archivos binarios (*.bin) Type: NULL; Size: 0 bytes Tipo: NULL; Tamaño: 0 bytes Type: Text / Numeric; Size: %n character(s) Tipo: Texto / Numérico; Tamaño: %n carácter Tipo: Texto / Numérico; Tamaño: %n caracteres Type: %1 Image; Size: %2x%3 pixel(s) Tipo: Imagen %1; Tamaño: %2×%3 píxeles Type: Valid JSON; Size: %n character(s) Tipo: JSON válido; Tamaño: %n carácter Tipo: JSON válido; Tamaño: %n caracteres Type: Binary; Size: %n byte(s) Tipo: Binario; Tamaño: %n byte Tipo: Binario; Tamaño: %n bytes Choose a file to import Seleccione el archivo a importar %1 Image Imagen %1 Invalid data for this mode Datos inválidos para este modo The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? La celda contiene datos de tipo %1 inválidos. Razón: «%2». ¿Realmente desea aplicarlos a la celda? Couldn't save file: %1. No se pudo guardar el archivo: «%1». The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Los datos se han guardado en un archivo temporal y se han abierto con la aplicación predeterminada. Ahora puede editar el archivo y, cuando haya terminado, podrá aplicar los nuevos datos a la celda o cancelar los cambios. EditIndexDialog &Name &Nombre Order Orden &Table &Tabla Edit Index Schema Editar índice del esquema &Unique Ú&nico For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Para restringir el índice exclusivamente a una parte de la tabla hay que especificar aquí una cláusula WHERE que seleccione la parte de la tabla que será indexada Partial inde&x clause Cláusula para inde&xado parcial Colu&mns Colu&mnas Table column Columna de la tabla Type Tipo Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Añade una nueva columna computada al índice. Las columnas computadas contienen una expresión SQL en lugar de nombres de columna. Index column Columna de índice Deleting the old index failed: %1 Borrado del índice previo fallido: %1 Creating the index failed: %1 Creación de índice fallida: %1 EditTableDialog Edit table definition Editar la definición de la tabla Table Tabla Advanced Avanzado Without Rowid Sin Rowid Fields Campos Database sche&ma Esque&ma de la base de datos Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. Establecer la propiedad «WITHOUT ROWID» a la tabla. Establecer esta opción requiere especificar una clave primaria (que puede ser de cualquier tipo y puede ser compuesta), y prohibe el uso de la propiedad AUTOINCREMENT. On Conflict En caso de conflicto Strict Opción STRICT When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Cuando la opción «STRICT» está habilitada, SQLite hace cumplir los tipos de datos de cada columna cuando se actualizan o insertan datos. Add Añadir Remove Eliminar Move to top Mover al principio Move up Mover hacia arriba Move down Mover hacia abajo Move to bottom Mover al final Name Nombre Type Tipo NN NN Not null No nulo PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> Clave primaria</p></body></html> AI AI Autoincrement Autoincremento U U Unique Único Default Por defecto Default value Valor por defecto Check Check Check constraint Restricción de «check» Collation Comparación Foreign Key Clave foránea <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> Clave foránea</p></body></html> Index Constraints Restricciones de índice Add constraint Añadir restricción Remove constraint Eliminar restricción Columns Columnas SQL SQL Foreign Keys Claves foráneas References Referencias Check Constraints Restricciones «CHECK» <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Aviso: </span>algo ocurre con la definición de esta tabla que nuestro intérprete no entiende completamente. Modificar y guardar esta tabla podría traer problemas.</p></body></html> Primary Key Clave Primaria Add a primary key constraint Añadir una restricción de clave primaria Add a unique constraint Añadir una restricción de único" Error creating table. Message from database engine: %1 Error creando la tabla. Mensaje de la base de datos: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Ya hay un campo con este nombre. Por favor, renómbrelo antes o elija un nombre diferente para este campo. There can only be one primary key for each table. Please modify the existing primary key instead. Sólo puede existir una clave primaria en cada tabla. Por favor, modifique la clave primaria existente. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Esta columna está referenciada en una clave foránea en la tabla %1 y por tanto no se le puede cambiar el nombre. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Hay al menos una línea con este campo NULO. Esto hace imposible activar este flag. Por favor, modifique antes los datos de la tabla. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Hay al menos una línea con un valor no entero en este campo. Esto hace imposible activar el flag AI. Por favor, modifique antes los datos de la tabla. Column '%1' has duplicate data. La columna «%1» tiene datos duplicados. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Como en otros textos, pasamos los términos estándar de SQL a mayúsculas para evitar traducirlos, lo que podría ser más confuso para el usuario experto y no tener beneficio para el inexperto. Esto imposibilita la habilitación de la restricción UNIQUE. Por favor, elimine primero los datos duplicados, lo cual permitirá habilitar la restricción UNIQUE. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. ¿Está seguro de que quiere borrar este campo «%1»? Todos los datos actualmente almacenados en este campo se perderán. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Por favor añada un campo que cumpla las siguientes condiciones antes de activar el indicador «sin rowid»: - Indicador de clave primaria activado - Indicador de autoincremento desactivado Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set Por favor añada un campo que cumpla las siguientes condiciones antes de activar la acción «ON CONFLICT»: - Indicador de clave primaria activado ExportDataDialog Export data as CSV Exportar datos como CSV Tab&le(s) Tab&la(s) Colu&mn names in first line Nombres de las &columnas en la primera línea Fie&ld separator &Separador de campos , , ; ; Tab Tab | | Other Otro &Quote character &Entrecomillado " " ' ' New line characters Caracteres de nueva línea Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print Impresión formateada Could not open output file: %1 No se puede abrir el archivo de salida: %1 Choose a filename to export data Seleccione un nombre de archivo para exportar los datos Export data as JSON Exportar datos como JSON exporting CSV exportando CSV Error while writing the file '%1': %2 Error al guardar el archivo «%1»: %2 exporting JSON exportando JSON Please select at least 1 table. Por favor, seleccione al menos 1 tabla. Choose a directory Seleccione una carpeta Export completed. Exportación completada. Export finished with errors. Exportación terminada con errores. ExportSqlDialog Export SQL... Exportar SQL... Tab&le(s) Tab&la(s) Select All Seleccionar Todo Deselect All Deseleccionar Todo &Options &Opciones Keep column names in INSERT INTO Mantener el nombre de la columna en INSERT INTO Multiple rows (VALUES) per INSERT statement Múltiples líneas (VALUES) en cada sentencia INSERT Export everything Exportar todo Export data only Exportar solo los datos Keep original CREATE statements Mantener las sentencias «CREATE» originales Keep old schema (CREATE TABLE IF NOT EXISTS) Mantener esquema previo (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Sobrescribir esquema previo (DROP TABLE, después CREATE TABLE) Export schema only Exportar solo el esquema Please select at least one table. Por favor, seleccione al menos una tabla. Choose a filename to export Seleccione un nombre de archivo al que exportar Export completed. Exportación completada. Export cancelled or failed. Exportación cancelada o fallida. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Buscar... Find and Replace... Buscar y reemplazar... Print... Imprimir... ExtendedTableWidget Use as Exact Filter Usar como filtro exacto Containing Conteniendo Not containing Que no contenga Not equal to No igual a Greater than Mayor que Less than Menor que Greater or equal Mayor o igual Less or equal Menor o igual Between this and... Entre esto y... Regular expression Expresión regular Edit Conditional Formats... Editar formatos condicionales... Set to NULL Poner a NULL Cut Cortar Copy Copiar Copy with Headers Copiar con cabeceras Copy as SQL Copiar como SQL Paste Pegar Print... Imprimir... Use in Filter Expression Usar en expresión de filtro Alt+Del Ctrl+Shift+C Ctrl+Alt+C <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>No se han cargado todos los datos. <b>¿Quiere cargar todos los datos antes de seleccionar todas las filas?</b><p><p>Responder <b>No</b> significa que no se cargarán mas datos y la selección no se se realizará.<br/>Responder <b>Sí</b> puede tardar un tiempo mientras los datos se cargan pero la selección se realizará en su totalidad.</p>Precaución: Cargar todos los datos puede necesitar una gran cantidad de memoria para tablas grandes. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. No se puede ajustar la selección a NULL. La columna %1 tiene una restricción NOT NULL. The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? El contenido del portapapeles es mayor que el rango seleccionado. ¿Quiere insertarlo de todos modos? FileExtensionManager File Extension Manager Gestor de extensiones de archivos &Up &Subir &Down &Bajar &Add &Añadir &Remove &Eliminar Description Descripción Extensions Extensiones *.extension *.extensión FilterLineEdit Filter Filtro These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Estos campos de texto permiten realizar filtros rápidos sobre la tabla actualmente seleccionada. Por defecto, las filas que contengan el texto introducido se muestran. Los siguientes operadores también se admiten: % Comodín > Mayor que < Menor que >= Igual o mayor que <= Igual o menor que = Igual a: correspondencia exacta <> Distinto: correspondencia inversa exacta x~y Rango: valores entre x e y Clear All Conditional Formats Eliminar todos los formatos condicionales Use for Conditional Format Usar para formato condicional Edit Conditional Formats... Editar formatos condicionales... Set Filter Expression Establecer expresión de filtro What's This? ¿Qué es esto? Is NULL Es nulo Is not NULL No es nulo Is empty Es vacío Is not empty No es vacío Not containing... No contiene... Equal to... Igual a... Not equal to... No igual a... Greater than... Mayor que... Less than... Menor que... Greater or equal... Mayor o igual... Less or equal... Menor o igual... In range... En el rango... Regular expression... Expresión regular... FindReplaceDialog Find and Replace Buscar y reemplazar Fi&nd text: &Buscar texto: Re&place with: &Reemplazar con: Match &exact case Distinguir &mayús. y minús. Match &only whole words &Solo palabras completas When enabled, the search continues from the other end when it reaches one end of the page Si se habilita, la búsqueda continua desde el otro extremo cuando llega a un extremo de la página &Wrap around &Dar la vuelta When set, the search goes backwards from cursor position, otherwise it goes forward Si se marca, la búsqueda va hacia atrás desde la posición del cursor. De lo contrario va hacia adelante Search &backwards Buscar hacia &atrás <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>Si se marca, el patrón de búsqueda se limita a buscar sólo en la selección.</p></body></html> &Selection only En la &selección <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Si se marca, el patrón de búsqueda se interpreta como una expresión regular UNIX. Véase <a href="https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular">«Expresión regular» en Wikipedia</a>.</p></body></html> Use regular e&xpressions Usar e&xpresiones regulares Find the next occurrence from the cursor position and in the direction set by "Search backwards" Encontrar la siguiente ocurrencia desde la posición del cursor y en la dirección definida por «Buscar hacia atrás» &Find Next Buscar &siguiente F3 &Replace R&eemplazar Highlight all the occurrences of the text in the page Resaltar todas las ocurrencias del texto en la página F&ind All Encontrar &todo Replace all the occurrences of the text in the page Reemplazar todas las ocurrencias del texto en la página Replace &All Reem&plazar todo The searched text was not found El texto buscado no fue encontrado The searched text was not found. El texto buscado no fue encontrado. The searched text was found one time. El texto buscado fue encontrado una vez. The searched text was found %1 times. El texto buscado fue encontrado %1 veces. The searched text was replaced one time. El texto buscado fue reemplazado una vez. The searched text was replaced %1 times. El texto buscado fue reemplazado %1 veces. ForeignKeyEditor &Reset &Reiniciar Foreign key clauses (ON UPDATE, ON DELETE etc.) Cláusulas de clave foránea (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Visor de imágenes Reset the scaling to match the original size of the image. Restablecer el escalado según el tamaño original de la imagen. Set the scaling to match the size of the viewport. Establecer el escalado según el tamaño del área de visualización. Print... Imprimir... Open preview dialog for printing displayed image Abre un diálogo de previsualización para imprimir la imagen mostrada Ctrl+P ImportCsvDialog Import CSV file Importar archivo CSV Table na&me &Nombre de la tabla &Column names in first line Nombres de &columna en la primera línea Field &separator &Separador de campos , , ; ; Tab Tab | | Other Otro &Quote character &Entrecomillado Other (printable) Otro (imprimible) Other (code) Otro (código) " " ' ' &Encoding &Codificación UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? ¿Recortar campos? Separate tables Tablas separadas Advanced Avanzado When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Cuando se importe un valor vacío desde el archivo CSV a una tabla existente con un valor por defecto para la columna, ese valor por defecto es insertado. Active esta opción si, por el contrario, desea insertar un valor vacío para esta columna. Ignore default &values Ignorar &valores por defecto Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Active esta opción para para la importación cuando se intente importar un valor vacío a una columna NOT NULL sin un valor por defecto. Fail on missing values Fallar cuando falten valores Disable data type detection Deshabilitar detección de tipo Disable the automatic data type detection when creating a new table. Deshabilitar la detección automática de tipo cuando se esté creando una nueva tabla. Use local number conventions Usar convenios numéricos locales Use decimal and thousands separators according to the system locale. Usar separadores de decimales y de miles según la configuración regional. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Cuando se importa a una tabla existente con una clave primaria, restricciones de único o un índice de único, existe la posibilidad de que se genere un conflicto. Esta opción le permite elegir la estrategia en esos casos: Por defecto la importación se aborta y se deshacen los cambios pero también puede elegir ignorar y no importar las filas conflictivas o reemplazar las filas existentes en la tabla. Abort import Abortar importación Ignore row Ignorar fila Replace existing row Reemplazar la fila existente Conflict strategy Estrategia para conflictos Deselect All Deseleccionar Todo Match Similar Emparejar Similares Select All Seleccionar Todo There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Ya existe una tabla con nombre «%1» y una importación a una tabla existente solo es posible si el número de columnas coincide. There is already a table named '%1'. Do you want to import the data into it? Ya existe una tabla con nombre «%1». ¿Desea importar los datos cargándolos en ella? Creating restore point failed: %1 Creación del punto de restauración fallido: %1 Creating the table failed: %1 Creación de la tabla fallido: %1 importing CSV importando CSV Could not prepare INSERT statement: %1 No se pudo preparar la sentencia «INSERT»: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Fin de archivo inesperado. Por favor, asegúrese de haber configurado correctamente el entrecomillado y de que el archivo no esté mal formado. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Importar el archivo «%1» tardó %2ms. De ellos, %3ms se gastaron en la función fila. Inserting row failed: %1 Inserción de línea fallido: %1 MainWindow DB Browser for SQLite DB Browser for SQLite &Database Structure This has to be equal to the tab title in all the main tabs Estru&ctura &Browse Data This has to be equal to the tab title in all the main tabs Hoja de &datos Edit P&ragmas This has to be equal to the tab title in all the main tabs Editar p&ragmas E&xecute SQL This has to be equal to the tab title in all the main tabs E&jecutar SQL toolBar1 toolBar1 &Recent Files Archivos &recientes This button clears the contents of the SQL logs Este botón limpia el contenido del historial SQL This panel lets you examine a log of all SQL commands issued by the application or by yourself Este panel le permite examinar el histórico de todos los comandos SQL ordenados por la aplicación o por usted mismo Project Toolbar Barra de herramientas de proyectos Extra DB toolbar Barra de herramientas extra Close the current database file Cierra el archivo de base de datos actual &New Database &Nueva base de datos This button closes the connection to the currently open database file Este botón cierra la conexión con el archivo de base de datos actualmente abierto Ctrl+F4 &Undo &Deshacer Undo last change to the database Deshace el último cambio realizado a la base de datos This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Esta acción deshace el último cambio realizado a la base de datos en «Hoja de datos» «Ejecutar SQL». Volver a realizarlo no es posible. Compact &Database... Compactar base de &datos... Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Abre el asistente «Modificar tabla», donde se puede renombrar una tabla existente. También se pueden añadir o borrar campos de la tabla, así como modificar los nombres de los campos y sus tipos. &About &Acerca de This button opens a new tab for the SQL editor Este botón abre una nueva pestaña para el editor SQL Execute all/selected SQL Ejecuta todo el SQL (o la selección) This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Este botón ejecuta las sentencias SQL actualmente seleccionadas. Si no hay ningún texto seleccionado, se ejecutan todas las sentencias. Ctrl+Shift+T &Load Extension... &Cargar extensión... Execute line Ejecutar línea This button executes the SQL statement present in the current editor line Este botón ejecuta la sentencia SQL presente en la línea actual del editor &Wiki &Wiki F1 Bug &Report... &Informar de fallos... Feature Re&quest... Solicitud de &mejoras... Web&site &Sitio web &Donate on Patreon... &Donar en Patreon... &Save Project &Guardar proyecto Open &Project... Abrir &proyecto... Open &Project Abrir &proyecto &Attach Database... Ane&xar base de datos... Add another database file to the current database connection Añade un archivo de base de datos adicional a la conexión actual This button lets you add another database file to the current database connection Este botón le permite añadir otro archivo de base de datos a la conexión de base de datos actual &Set Encryption... &Establecer cifrado... This button saves the content of the current SQL editor tab to a file Este botón guarda el contenido de la pestaña actual del editor SQL a un archivo SQLCipher &FAQ SQLCipher &FAQ Find Buscar Find or replace Buscar o reemplazar Ctrl+H Ctrl+Shift+W Table from CSV data in Clipboard... Tabla desde CSV en el portapapeles... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Esta opción interpreta el contenido del portapapeles como un archivo CSV y abre el mismo asistente usado para importar datos CSV desde un archivo. Show &Row Counts &Contar filas This shows the number of rows for each table and view in the database. Muestra el número de filas de cada una de las tablas y vistas de la base de datos. Save Database &As... G&uardar base de datos como... Save the current database as a different file Guardar la base de datos actual como un archivo diferente Refresh Refrescar Reload the database structure Recargar la estructura de la base de datos New &tab Nueva pesta&ña Open SQL file(s) Abrir archivo(s) SQL This button opens files containing SQL statements and loads them in new editor tabs Este botón abre archivos que contengan sentencias SQL y los carga en pestañas nuevas del editor This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Este botón le permite guardar todos los ajustes asociados a la base de datos abierta a un archivo de proyecto de «DB Browser for SQLite» This button lets you open a DB Browser for SQLite project file Este botón le permite abrir un archivo de proyecto «DB Browser for SQLite» Export to &JSON Exportar a &JSON &Open Database &Abrir base de datos New In-&Memory Database Nueva base de datos en &memoria Drag && Drop SELECT Query Arrastrar y soltar consulta SELECT When dragging fields from the same table or a single table, drop a SELECT query into the editor Cuando se arrastran campos de la misma tabla o de una única tabla, pone una consulta SELECT en el editor Drag && Drop Qualified Names Arrastrar y soltar nombres calificados Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Usa nombres calificados (p.ej. "Tabla"."Campo") al arrastrar los objetos y soltarlos en el editor Drag && Drop Enquoted Names Arrastrar y soltar nombres entrecomillados Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Usa identificadores escapados (p.ej. "Tabla1") al arrastrar los objetos y soltarlos en el editor &Integrity Check Comprobar &integridad Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. Ejecuta el pragma integrity_check en la base de datos abierta y devuelve los resultados en la pestaña Ejecutar SQL. Este pragma realiza una comprobación de integridad de toda la base de datos. &Foreign-Key Check Comprobar clave &foránea Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Ejecuta el pragma foreign_key_check con la base de datos abierta y devuelve los resultados en la pestaña Ejecutar SQL. &Quick Integrity Check Comprobar integridad &rápido Run a quick integrity check over the open DB Ejecuta una comprobación de integridad rápida en la base de datos abierta Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. Ejecuta el pragma quick_check en la base de datos abierta y devuelve los resultados en la pestaña Executar SQL. Este comando hace la mayoría de comprobaciones de PRAGMA integrity_check pero se ejecuta mucho más rápido. &Optimize &Optimizar Attempt to optimize the database Intenta optimizar la base de datos Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Ejecuta el pragma optimize en la base de datos abierta. Este pragma realiza optimizaciones que pueden mejorar el rendimiento de consultas futuras. Print Imprimir Print text from current SQL editor tab Imprime el texto de la pestaña actual del editor SQL Open a dialog for printing the text in the current SQL editor tab Abre un diálogo para imprimir el texto de la pestaña actual del editor SQL Print the structure of the opened database Imprime la estructura de la base de datos abierta Open a dialog for printing the structure of the opened database Abre un diálogo para imprimir la estructura de la base de datos abierta Un/comment block of SQL code Des/comentar bloque de código SQL Un/comment block Des/comentar bloque de código Comment or uncomment current line or selected block of code Comenta o descomenta la línea actual o el bloque de código seleccionado Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Comenta o descomenta las líneas seleccionadas o la línea actual cuando no hay selección. El estado de todo el bloque es intercambiado en función de la primera línea. Ctrl+/ Stop SQL execution Detener ejecución de SQL Stop execution Detener ejecución Stop the currently running SQL script Detener el script SQL que está ejecutándose &Save Project As... &Guardar proyecto como... Save the project in a file selected in a dialog Guarda el proyecto en un archivo seleccionado en una ventana de diálogo Save A&ll Guardar &todo Save DB file, project file and opened SQL files Guarda los archivos de la base de datos, el proyecto y los archivos SQL abiertos Ctrl+Shift+S Browse Table Navegar Tabla Close Pro&ject Cerrar pro&yecto Close project and database files and return to the initial state Cierra el proyecto y los archivos de la base de datos y vuelve al estado inicial Ctrl+Shift+F4 Detach Database Desanclar base de datos Detach database file attached to the current database connection Desanclar el archivo de base de datos anclado a la conexión actual de la base de datos Shows or hides the Project toolbar. Muestra u oculta la barra de herramientas de proyecto. Extra DB Toolbar Barra de herramientas extra Export one or more table(s) to a JSON file Exportar una o más tablas a un archivo JSON This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Esta es la estructura de la base de datos abierta. Puede arrastrar sentencias SQL desde una fila de objeto y soltarlas en otras aplicaciones o en otra instancia de «DB Browser for SQLite». Table(&s) to JSON... Tabla(&s) a JSON... Open Data&base Read Only... Abrir &base de datos como solo lectura... Ctrl+Shift+O Save results Guardar resultados Save the results view Guarda la vista de resultados This button lets you save the results of the last executed query Este botón le permite guardar los resultados de la última consulta ejecutada Find text in SQL editor Buscar texto en el editor SQL This button opens the search bar of the editor Este botón abre la barra de búsqueda del editor Ctrl+F Find or replace text in SQL editor Buscar o reemplazar texto en el editor SQL This button opens the find/replace dialog for the current editor tab Este botón abre el diálogo de buscar/reemplazar para la pestaña actual del editor Export to &CSV Exportar a &CSV Save as &view Guardar como &vista Save as view Guardar como vista Open an existing database file in read only mode Abre una base de datos existente en modo de solo lectura &File &Archivo &Import &Importar &Export E&xportar &Edit &Editar &View &Ver &Help Ay&uda Too&ls &Herramientas DB Toolbar DB Toolbar Edit Database &Cell Editar &celda Error Log Registro de errores DB Sche&ma Esque&ma This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Esta es la estructura de la base de datos abierta. Puede arrastrar múltiples objetos de la columna Nombre, soltarlos en el editor SQL y ajustar sus propiedades usando el menú contextual. Esto le ayudará a componer sentencias SQL. Puede arrastrar sentencias SQL desde la columna Esquema y soltarlas en el editor SQL o en otras aplicaciones. &Remote &Remoto Execute current line Ejecuta la línea actual Shift+F5 Sa&ve Project &Guardar proyecto User Usuario Application Aplicación &Clear &Limpiar &New Database... &Nueva base de datos... Create a new database file Crea un nuevo archivo de base de datos This option is used to create a new database file. Esta opción se usa para crear un nuevo archivo de base de datos. Ctrl+N &Open Database... &Abrir base de datos... Open an existing database file Abre un archivo de base de datos This option is used to open an existing database file. Esta opción se usa para abrir un archivo de base de datos. Ctrl+O &Close Database &Cerrar base de datos Ctrl+W Opens the SQLCipher FAQ in a browser window Abre la FAQ de SQLCipher en una ventana del navegador Revert database to last saved state Revierte el estado de la base de datos al último guardado This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Esta opción se usa para revertir el estado de la base de datos actual al último guardado. Todos los cambios hechos desde la última vez que se guardó se perderán. Write changes to the database file Escribe los cambios al archivo de la base de datos This option is used to save changes to the database file. Esta opción se usa para guardar los cambios en el archivo de la base de datos. Ctrl+S Compact the database file, removing space wasted by deleted records Compacta el archivo de la base de datos eliminando el espacio malgastado por los registros borrados Compact the database file, removing space wasted by deleted records. Compacta el archivo de la base de datos, eliminando el espacio malgastado por los registros borrados. E&xit &Salir Ctrl+Q Import data from an .sql dump text file into a new or existing database. Importa datos de un archivo de texto con un volcado .sql en una base de datos nueva o existente. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Esta opción se usa para importar datos de un archivo de texto con un volcado .sql en una base de datos nueva o existente. Los archivos de volcado SQL se pueden crear en la mayoría de los motores de base de datos, incluyendo MySQL y PostgreSQL. Open a wizard that lets you import data from a comma separated text file into a database table. Abre un asistente que le permite importar datos desde un archivo de texto con valores separado por comas a una tabla de una base de datos. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Abre un asistente que le permite importar datos desde un archivo de texto con valores separado por comas a una tabla de una base de datos. Los archivos CSV se pueden crear en la mayoría de las aplicaciones de bases de datos y hojas de cálculo. Export a database to a .sql dump text file. Exporta la base de datos como un volcado .sql a un archivo de texto. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Esta opción le permite exportar la base de datos como un volcado .sql a un archivo de texto. Los archivos de volcado SQL contienen todos los datos necesarios para recrear la base de datos en la mayoría de los motores de base de datos, incluyendo MySQL y PostgreSQL. Export a database table as a comma separated text file. Exporta la base de datos como un archivo de texto con valores separados por comas. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Exporta la base de datos como un archivo de texto con valores separados por comas, listo para ser importado en otra base de datos o aplicaciones de hoja de cálculo. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Abre el asistente para Crear una Tabla, donde se puede definir el nombre y los campos de una nueva tabla en la base de datos Delete Table Borrar tabla Open the Delete Table wizard, where you can select a database table to be dropped. Abre el asistente para «Borrar tabla», donde se puede seleccionar una tabla de la base de datos para borrar. Open the Create Index wizard, where it is possible to define a new index on an existing database table. Abre el asistente «Crear índice», donde se puede definir un nuevo índice de una tabla existente de la base de datos. &Preferences... &Preferencias... Open the preferences window. Abrir la ventana de preferencias. &DB Toolbar &Barra de herramientas Shows or hides the Database toolbar. Muestra u oculta la barra de herramientas de la base de datos. Shift+F1 &Recently opened Archivos &recientes Ctrl+T Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Aviso: este pragma no es legible y este valor se ha supuesto. Escribir el pragma puede sobreescribir un LIKE redefinido que proporcione una extensión de SQLite. SQL &Log Historial de &SQL Show S&QL submitted by Mostrar S&QL ejecutado por &Plot &Gráfica &Revert Changes &Revertir cambios &Write Changes &Guardar cambios &Database from SQL file... Base de datos de &archivo SQL... &Table from CSV file... &Tabla de archivo CSV... &Database to SQL file... &Base de datos a archivo SQL... &Table(s) as CSV file... &Tabla(s) a archivo CSV... &Create Table... &Crear tabla... &Delete Table... &Borrar tabla... &Modify Table... &Modificar tabla... Create &Index... Crear í&ndice... W&hat's This? ¿&Qué es esto? &Execute SQL &Ejecutar SQL Save SQL file Guardar archivo SQL Ctrl+E Export as CSV file Exportar como archivo CSV Export table as comma separated values file Exportar tabla como archivo de valores separados por comas Save the current session to a file Guarda la sesión actual en un archivo Load a working session from a file Carga una sesión de trabajo de un archivo Save SQL file as Guardar archivo SQL como &Browse Table &Mostrar datos Copy Create statement Copiar sentencia CREATE Copy the CREATE statement of the item to the clipboard Copia la sentencia CREATE del ítem al portapapeles Ctrl+Return Ctrl+L Ctrl+P Ctrl+D Ctrl+I Encrypted Cifrado Read only Solo lectura Database file is read only. Editing the database is disabled. El archivo de la base de datos es de solo lectura. La edición de la base de datos está desactivada. Database encoding Codificación de la base de datos Database is encrypted using SQLCipher La base de datos está cifrada usando SQLCipher Choose a database file Seleccione un archivo de base de datos Choose a filename to save under Seleccione un nombre de archivo en el que guardar Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Error mientras se guardaba el archivo de la base de datos. Esto significa que no todos lo cambios hechos a la base de datos se han guardado. Antes tiene que solucionar el siguiente error. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? ¿Está seguro de que quiere deshacer todos los cambios hechos al archivo de la base de datos «%1» desde la última vez que se guardó? Choose a file to import Seleccione el archivo a importar &%1 %2%3 &%1 %2%3 (read only) (sólo lectura) Open Database or Project Abrir base de datos o proyecto Attach Database... Anexar base de datos... Import CSV file(s)... Importar archivo(s) CSV... Do you want to save the changes made to SQL tabs in the project file '%1'? ¿Quiere guardar los cambios hechos a las pestañas SQL en el archivo de proyecto «%1»? Text files(*.sql *.txt);;All files(*) Archivos de texto(*.sql *.txt);;Todos los archivos(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. ¿Quiere crear un nuevo archivo de base de datos donde poner los datos importados? Si responde no se intentarán importar los datos del archivo SQL en la base de datos actual. Automatically load the last opened DB file at startup Cargar automáticamente al inicio el último archivo abierto Ctrl+Alt+0 Ctrl+Alt+W Choose a database file to save under Elija un archivo de base de datos en el que guardar Error while saving the database to the new file. Error mientras se guardaba la base de datos en el nuevo archivo. Do you want to save the changes made to the project file '%1'? ¿Quiere guardar los cambios hechos al archivo de proyecto «%1»? Edit View %1 Editar vista %1 Edit Trigger %1 Editar disparador %1 Result: %1 Resultado: %1 File %1 already exists. Please choose a different name. El archivo %1 ya existe. Por favor elija un nombre diferente. Error importing data: %1 Error importando datos: %1 Import completed. Importación completada. Delete View Borrar vista Modify View Modificar vista Delete Trigger Borrar disparador Modify Trigger Modificar disparador Delete Index Borrar índice Modify Index Modificar índice Modify Table Modificar tabla Opened '%1' in read-only mode from recent file list Se ha abierto «%1» en modo de sólo lectura desde la lista de archivos recientes Opened '%1' from recent file list Se ha abierto «%1» desde la lista de archivos recientes Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Seleccione la acción a aplicar al archivo. Seleccione la acción a aplicar a los archivos <br/>Nota: sólo «Importar» procesará más de un archivo. The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? Las sentencias en la pestaña «%1»; todavía se están ejecutando. Al cerrar la pestaña se detendrá la ejecución. Esto puede dejar la base de datos en un estado inconsistente. ¿Está seguro de que quiere cerrar la pestaña? DB file '%1' could not be opened El archivo de base de datos «%1»; no se pudo abrir This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Este proyecto está usando un formato de archivo antiguo porque fue creado usando «DB Browser for SQLite» versión 3.10 o menor. La carga de este formato de archivo no está soportado en su totalidad. Si quiere cargarlo completamente, por favor, use «DB Browser for SQLite» versión 3.12 para convertirlo al nuevo formato. Table '%1' not found; settings ignored No se ha encontrado la tabla «%1»;; ajustes ignorados -- Reference to file "%1" (not supported by this version) -- -- Vínculo al archivo "%1" (no soportado en esta versión) -- Yes. Don't ask again Sí. No pregunte otra vez This action will open a new SQL tab with the following statements for you to edit and run: Esta acción abrirá una nueva pestaña SQL con las siguientes sentencias para que usted las pueda modificar y ejecutar: Rename Tab Renombrar Pestaña Duplicate Tab Duplicar Pestaña Close Tab Cerrar Pestaña Opening '%1'... Abriendo «%1»... There was an error opening '%1'... Hubo un error abriendo «%1»... Value is not a valid URL or filename: %1 Valor no es un nombre de archivo o URL válido: %1 Do you want to save the changes made to SQL tabs in a new project file? ¿Quiere guardar los cambios hechos a las pestañas SQL en un nuevo archivo de proyecto? Do you want to save the changes made to the SQL file %1? ¿Quiere guardar los cambios hechos al archivo SQL %1? Could not find resource file: %1 No se pudo encontrar el archivo de recursos: %1 Choose a project file to open Seleccione un archivo de proyecto para abrir Could not open project file for writing. Reason: %1 No se pudo abrir el archivo de proyecto para escritura. Motivo: %1 Collation needed! Proceed? ¡Es necesaria una función de comparación! ¿Proceder? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Una tabla en esta base de datos necesita una función de comparación especial «%1» que esta aplicación no puede proporcionar sin más información. Si decide continuar, está avisado de que la base de datos se puede dañar. ¡Cree una copia de respaldo! Setting PRAGMA values will commit your current transaction. Are you sure? Al definir los valores de PRAGMA se consolidará la transacción actual. ¿Está seguro? Ctrl+Tab Ctrl+Shift+Tab Clear List Limpiar lista Window Layout Disposición de la ventana Reset Window Layout Reiniciar disposición Simplify Window Layout Simplificar disposición Alt+Shift+0 Dock Windows at Bottom Acoplar ventanas en la parte inferior Dock Windows at Left Side Acoplar ventanas en la parte izquierda Dock Windows at Top Acoplar ventanas en la parte superior The database is currently busy. La base de datos está ocupada Click here to interrupt the currently running query. Haga clic aquí para interrumpir la consulta que se está ejecutando Could not open database file. Reason: %1 No se pudo abrir el archivo de base de datos. Razón: %1 In-Memory database Base de datos en memoria You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Todavía se están ejecutando sentencias SQL. Al cerrar la base de datos se detendrá la ejecución. Esto puede dejar la base de datos en un estado inconsistente. ¿Está seguro de que quiere cerrar la base de datos? Are you sure you want to delete the table '%1'? All data associated with the table will be lost. ¿Está seguro de que quiere borrar la tabla «%1»? Se perderán todos los datos asociados con la tabla. Are you sure you want to delete the view '%1'? ¿Está seguro de que quiere borrar la vista «%1»? Are you sure you want to delete the trigger '%1'? ¿Está seguro de que quiere borrar el disparador «%1»? Are you sure you want to delete the index '%1'? ¿Está seguro de que quiere borrar el índice «%1»? Error: could not delete the table. Error: no se pudo borrar la tabla. Error: could not delete the view. Error: no se pudo borrar la vista. Error: could not delete the trigger. Error: no se pudo borrar el disparador. Error: could not delete the index. Error: no se pudo borrar el índice. Message from database engine: %1 Mensaje de la base de datos: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Para editar la tabla es necesario guardar antes todos los cambios pendientes. ¿Está seguro de que quiere guardar la base de datos? You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. Ya se están ejecutando sentencias SQL. ¿Quiere detenerlas para en su lugar ejecutar las sentencias actuales?. Esto puede dejar la base de datos en un estado inconsistente. -- EXECUTING SELECTION IN '%1' -- -- EJECUTANDO SELECCIÓN DE «%1» -- -- EXECUTING LINE IN '%1' -- -- EJECUTANDO LÃNEA DE «%1» -- -- EXECUTING ALL IN '%1' -- -- EJECUTANDO TODO «%1» -- Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Establecer valores PRAGMA o realizar una limpieza consolidará la transacción actual. ¿Está seguro? Busy (%1) Ocupado (%1) %1 rows returned in %2ms %1 filas devueltas en %2ms Choose text files Elija archivos de texto Import completed. Some foreign key constraints are violated. Please fix them before saving. Importación completada. Algunas restricciones de las claves foráneas se han infringido. Por favor arréglelas antes de guardar. Select SQL file to open Seleccione el archivo SQL a abrir Select file name Seleccione el nombre del archivo Select extension file Seleccione el archivo de extensión Extension successfully loaded. Extensiones cargadas con éxito. Error loading extension: %1 Error cargando la extensión: %1 Don't show again No volver a mostrar New version available. Hay una nueva versión disponible. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Hay disponible una nueva versión de «DB Browser for SQLite» (%1.%2.%3).<br/><br/>Por favor, descárguela de <a href='%4'>%4</a>. Project saved to file '%1' Proyecto guardado en el archivo «%1» creating collation creando comparación Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Establezca el nuevo nombre para la pestaña SQL. Use el carácter «&&» para permitir usar el carácter siguiente como un atajo de teclado. Please specify the view name Por favor, especifique el nombre de la vista There is already an object with that name. Please choose a different name. Ya hay un objeto con ese nombre. Por favor, elija un nombre diferente. View successfully created. Vista creada con éxito. Error creating view: %1 Error creando la vista: %1 This action will open a new SQL tab for running: Esta acción abrirá una nueva pestaña SQL para ejecutar: Press Help for opening the corresponding SQLite reference page. Pulse Ayuda para abrir la página correspondiente de la referencia de SQLite. DB Browser for SQLite project file (*.sqbpro) Archivo de proyecto de «DB Browser for SQLite» (*.sqbpro) Error checking foreign keys after table modification. The changes will be reverted. Error comprobando las claves foráneas tras la modificación de la tabla. Los cambios se desharán. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Esta tabla no ha pasado la comprobación de claves foráneas.<br/>Debería ejecutar 'Herramientas | Comprobar Claves foráneas' y arreglar los problemas mostrados. At line %1: En la línea %1: Result: %2 Resultado: %2 Execution finished with errors. Ejecución terminada con errores. Execution finished without errors. Ejecución terminada sin errores. NullLineEdit Set to NULL Poner a NULL Alt+Del PlotDock Plot Gráfica <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Esta tabla muestra la lista de columnas de la tabla actualmente visualizada o de la consulta recién ejecutada. Puede seleccionar las columnas que desea usar como ejes X o Y en el gráfico del panel inferior. La tabla muestra el tipo de eje detectado, el cual afectará al gráfico resultante. Para los ejes Y solo se pueden seleccionar columnas numéricas, pero para el eje X se pueden seleccionar :</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fecha/Hora</span>: texto con formato &quot;aaaa-MM-dd hh:mm:ss&quot; o &quot;aaaa-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fecha</span>: texto con formato &quot;aaaa-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: texto con formato &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Etiqueta</span>: texto con otros formatos. Seleccionado esta columna como eje X se dibuja un gráfico de barras con los valores de la columna usados como etiquetas de las barras.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numérico</span>: valores reales o enteros</li></ul><p>Haciendo doble clic sobre las celdas Y se puede cambiar el color usado para la gráfica correspondiente.</p></body></html> Columns Columnas X X Y1 Y2 Axis Type Tipo de eje Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Aquí se dibuja un gráfico cuando se seleccionan los valores de X e Y en la parte superior. Con un clic sobre los puntos se seleccionan en el gráfico y en la tabla. Con Ctrl+Clic se pueden seleccionar rangos de puntos. Use la rueda del ratón para aumentar y disminuir el gráfico y arrastre con el ratón para cambiar el rango del eje. Seleccione los ejes o sus etiquetas para arrastrar y aumentar/disminuir solo en esa orientación. Line type: Tipo de línea: None Ninguno Line Línea StepLeft EscalónIzquierda StepRight EscalónDerecha StepCenter EscalónCentrado Impulse Impulso Point shape: Forma de punto: Cross Aspa es más específico que cruz. El signo más también es una cruz (una cruz griega). Aspa Plus Más Circle Circunferencia Disc Círculo Square Cuadrado Diamond Diamante Star Estrella Triangle Triángulo TriangleInverted TriánguloInvertido CrossSquare AspaCuadrado PlusSquare MásCuadrado CrossCircle AspaCircunferencia PlusCircle MásCircunferencia Peace Paz <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Guarda la gráfica actual...</p><p>El formato del archivo es elegido por la extensión (png, jpg, pdf, bmp)</p></body></html> Save current plot... Guarda la gráfica actual... Load all data and redraw plot Cargar todos los datos y redibujar el gráfico Row # Nº de línea Copy Copiar Print... Imprimir... Show legend Mostrar leyenda Stacked bars Barras apiladas Fixed number format Formato de números fijos Date/Time Fecha/hora Date Fecha Time Tiempo Numeric Numérico Label Etiqueta Invalid Inválido Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Cargar todos los datos y redibujar el gráfico. Aviso: aún no se han cargado todos los datos desde la tabla debido al mecanismo de lectura parcial. Choose an axis color Elija un color para el eje Choose a filename to save under Seleccione un nombre de archivo en el que guardar PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Todos los archivos(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Existen lazos en este gráfico y el estilo de línea seleccionado solo se puede aplicar a gráficos ordenados por X. Debe ordenar la tabla o consulta por X para eliminar los lazos o seleccionar uno de los estilos soportados por los lazos: Ninguno o Línea. Loading all remaining data for this table took %1ms. Cargar todos los datos restantes para esta tabla tardó %1ms. PreferencesDialog Preferences Preferencias &General &General Remember last location Recordar la última ubicación Always use this location Usar siempre esta ubicación Remember last location for session only Recordar la última ubicación solamente para esta sesión ... ... Default &location &Posición por defecto Lan&guage &Idioma Automatic &updates &Actualizaciones automáticas enabled activado Show remote options Mostrar opciones del remoto &Database &Base de datos Database &encoding Co&dificación de la base de datos Open databases with foreign keys enabled. Abrir base de datos con claves foráneas activadas. &Foreign keys Claves &foráneas Data &Browser &Hoja de datos Remove line breaks in schema &view Elimina los saltos de línea en la &vista del esquema Prefetch block si&ze &Tamaño del bloque de precarga SQ&L to execute after opening database SQ&L a ejecutar tras abrir la base de datos Default field type Tipo de campo por defecto Font Tipo de letra &Font &Tipo de letra Content Contenido Symbol limit in cell Límite de símbolos en la celda NULL NULL Regular Normal Binary Binario Background Fondo Filters Filtros Toolbar style Estilo de barra de herramientas Only display the icon Solo mostrar el icono Only display the text Solo mostrar el texto The text appears beside the icon El texto aparece junto al icono The text appears under the icon El texto aparece bajo el icono Follow the style Seguir el estilo predefinido DB file extensions Extensiones de archivos de BB.DD. Manage Gestionar Main Window Ventana principal Database Structure Estructura Browse Data Hoja de datos Execute SQL Ejecutar SQL Edit Database Cell Editar celda When this value is changed, all the other color preferences are also set to matching colors. Cuando se cambia este valor, también se ajustan con colores a juego todas las otras prefencias de color. Follow the desktop style Usa el estilo del escritorio Dark style Estilo oscuro Light style Estilo claro Application style Estilo de la aplicación This sets the font size for all UI elements which do not have their own font size option. Esto establece el tamaño de tipografía para todos los elementos de la interfaz de usuario que no tienen su propia opción. Font size Tamaño de fuente Max Recent Files Máximo de archivos recientes Prompt to save SQL tabs in new project file Preguntar si guardar pestañas SQL en un nuevo archivo de proyecto If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Cuando está activado, los cambios hechos en el editor SQL hacen que al cerrar la pestaña del editor SQL se muestre un diálogo de confirmación para guardar el proyecto. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Cuando está activado, se omiten los saltos de línea en la columna Esquema, tanto en la pestaña Estructura en pantalla, como al imprimir. Database structure font size Tamaño de fuente de la estructura de base de datos Font si&ze &Tamaño de fuente Formatted Formateado This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Este es el máximo número ocurrencias permitidos para que algunas funcionalidades computacionalmente costosas sean activadas: Máximo número de filas en una tabla para activar el autocompletado basado en los valores actuales en la columna. Máximo número de índices en una selección para calcular la suma y la media. Pueden ajustarse a 0 parar desactivar las funcionalidades. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Este el el número máximo de filas en una tabla para activar el autocompletado basado en los valores actuales en la columna. Se puede poner a 0 para desactivar el autocompletado. Selection background Fondo de la selección Selection foreground Texto de la selección Highlight Resaltado Use tabs for indentation Usar tabuladores para indentar When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. Cuando está activado, la tecla Tab insertará tabuladores y espacios para indentar. En caso contrario, para la indentación sólo se insertarán espacios. Close button on tabs Botón de cerrar en pestañas If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Si se habilita, las pestañas del editor SQL tendrán un botón para cerrarlas. En cualquier caso, usted siempre podrá usar el menú contextual o el atajo de teclado para cerrarlas. Select built-in extensions to load for every database: Seleccione extensiones incorporadas a cargar para cualquier base de datos: Proxy Proxy Configure Configurar Export Settings Exportar ajustes Import Settings Importar ajustes Field display Estilo de las celdas Displayed &text &Texto presentado Click to set this color Haga clic para ajustar este color Text color Color del texto Background color Color del fondo Preview only (N/A) Solo vista previa (N/A) Escape character Carácter de escape Delay time (&ms) Tiempo de retardo (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Define el tiempo de espera antes de que se aplique un nuevo valor de filtro. Se puede poner a 0 para desactivar la espera. &SQL &SQL Context Contexto Colour Color Bold Negrita Italic Cursiva Underline Subrayado Keyword Palabra clave Function Función Table Tabla Comment Comentario Identifier Identificador String Cadena Current line Línea actual SQL &editor font size Tamaño de letra del &editor SQL Tab size Tamaño del tabulador &Wrap lines Ajuste de líneas Never Nunca At word boundaries En los límites de palabra At character boundaries En los límites de caracteres At whitespace boundaries En los límites de espacios en blanco &Quotes for identifiers &Comillas para identificadores Choose the quoting mechanism used by the application for identifiers in SQL code. Elija el mecanismo de entrecomillado usado por la aplicación para los identificadores en el código SQL. "Double quotes" - Standard SQL (recommended) "Dobles comillas" - SQL estándar (recomendado) `Grave accents` - Traditional MySQL quotes `Acentos graves` - Entrecomillado tradicional de MySQL [Square brackets] - Traditional MS SQL Server quotes [Corchetes] - Entrecomillado tradicional de MS SQL Server Keywords in &UPPER CASE Palabras claves en &MAYÚSCULAS When set, the SQL keywords are completed in UPPER CASE letters. Si se activa, las palabras claves de SQL se completan en letras MAYÚSCULAS. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Si se activa, las líneas de código SQL que causaron errores durante la última ejecución se destacan y el marco de resultados indica el error mediante el color del fondo <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite proporciona una función SQL para cargar extensiones desde un archivo de biblioteca compartida. Active esta opción si desea usar la función <span style=" font-style:italic;">load_extension()</span> desde código SQL.</p><p>Por razónes de seguridad, la carga de extensiones está desactivada por defecto y debe ser habilitada usando esta configuración. Siempre puede cargar extensiones a través de la interfaz de usuario, incluso aunque esta opción esté deshabilitada.</p></body></html> Allow loading extensions from SQL code Permitir cargar extensiones desde código SQL Remote Remoto CA certificates Certificados CA Subject CN Sujeto CN Common Name Nombre común Subject O Sujeto O Organization Organización Valid from Válido desde Valid to Válido hasta Serial number Número de serie Your certificates Sus certificados File Archivo Subject Common Name Nombre común del sujeto Issuer CN Emisor CN Issuer Common Name Nombre común del emisor Clone databases into Clonar las bases de datos en SQL editor &font &Tipo de letra del editor SQL Error indicators Indicadores de error Hori&zontal tiling Mosaico hori&zontal If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Si se activa, el editor de código SQL y la vista de la tabla de resultados se muestran de lado a lado en lugar de una sobre la otra. Code co&mpletion Co&mpletar código Threshold for completion and calculation on selection Umbral para cálculos al seleccionar y completación Show images in cell Mostrar imágenes en la celda Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Active esta opción para mostrar una previsualización de los BLOBs que contengan datos de imagen en las celdas. Tenga en cuenta que esto puede afectar el desempeño del navegador de la hoja de datos. Foreground Texto SQL &results font size Tamaño de letra de &resultados &Extensions E&xtensiones Select extensions to load for every database: Seleccione extensiones a cargar para cualquier base de datos: Add extension Añadir extensión Remove extension Eliminar extensión <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p> Aunque SQLite admite el operador REGEXP, no implementa en sí ningún algoritmo de expresiones<br/> regulares sino que llama a los de la aplicación en ejecución. «DB Browser for SQLite» implementa este<br/> método para permitirle usar REGEXP de fábrica. Sin embargo, como hay múltiples posibles<br/> implementaciones y puede querer usar otra, puede desactivar este método y cargar el suyo propio<br/> usando una extensión. Necesitará reiniciar la aplicación.</p> </body></html> Disable Regular Expression extension Desactivar extensión de expresiones regulares Choose a directory Seleccione una carpeta The language will change after you restart the application. El idioma cambiará al reiniciar la aplicación. Select extension file Seleccione archivo de extensión Extensions(*.so *.dylib *.dll);;All files(*) Extensiones (*.so *.dll);;Todos los archivos (*) Import certificate file Importar archivo de certificado No certificates found in this file. No hay certificados en este archivo. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! ¿Está seguro de que quiere eliminar este certificado? ¡Todos los datos del certificado se borrarán de los ajustes de la aplicación! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. ¿Está seguro de que desea borrar todos los ajustes guardadas? Todas sus preferencias se perderán y se usarán valores predeterminados. Save Settings File Guardar archivo de ajustes Initialization File (*.ini) Archivos de inicialización (*.ini) The settings file has been saved in location : Los ajustes se han guardado en la ubicación: Open Settings File Abrir archivo de ajustes The settings file was loaded properly. El archivo de ajustes se ha cargado correctamente. The selected settings file is not a normal settings file. Please check again. El archivo de ajustes seleccionado no parece tener el formato esperado. Por favor compruebe que es correcto. ProxyDialog Proxy Configuration Configuración del proxy Pro&xy Type Tipo de pro&xy Host Na&me No&mbre del host Port Puerto Authentication Re&quired Autentificación re&querida &User Name Nombre de &usuario Password Contraseña None Ninguno System settings Ajustes del sistema HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data Error importando datos from record number %1 del registro número %1 . %1 . %1 Importing CSV file... Importando archivo CSV... Cancel Cancelar All files (*) Todos los archivos (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Archivos de BB.DD. SQLite (*.db *.sqlite *.sqlite3 *.db3) Left Izquierda Right Derecha Center Centrado Justify Justificado SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) Archivos de BB.DD. SQLite (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) Archivos de proyecto de DB Browser for SQLite (*.sqbpro) SQL Files (*.sql) Archivos SQL (*.sql) All Files (*) Todos los archivos (*) Text Files (*.txt) Archivos de texto (*.txt) Comma-Separated Values Files (*.csv) Archivos de valores separados por comas (*.csv) Tab-Separated Values Files (*.tsv) Archivos de valores separados por tabuladores (*.tsv) Delimiter-Separated Values Files (*.dsv) Archivos de Valores Separados por Delimitador (*.dsv) Concordance DAT files (*.dat) Archivos DAT de Concordance (*.dat) JSON Files (*.json *.js) Archivos JSON (*.json *.js) XML Files (*.xml) Archivos XML (*.xml) Binary Files (*.bin *.dat) Archivos binarios (*.bin *.dat) SVG Files (*.svg) Archivos SVG (*.svg) Hex Dump Files (*.dat *.bin) Archivos de volcado Hex (*.dat *.bin) Extensions (*.so *.dylib *.dll) Extensiones (*.so *.dylib *.dll) Initialization File (*.ini) Archivos de inicialización (*.ini) QsciCommand Paste Pegar Cancel Cancelar QsciLexerCPP Default Por defecto Keyword Palabra clave Identifier Identificador QsciLexerJSON Default Por defecto String Cadena QsciLexerJavaScript Regular expression Expresión regular QsciLexerPython Default Por defecto Comment Comentario Keyword Palabra clave Identifier Identificador QsciLexerSQL Default Por defecto Comment Comentario Keyword Palabra clave Identifier Identificador QsciScintilla &Undo &Deshacer Select All Seleccionar Todo RemoteCommitsModel Commit ID ID versión Message Mensaje Date Fecha Author Autor Size Tamaño Authored and committed by %1 Escrito y registrado por %1 Authored by %1, committed by %2 Escrito por %1, registrado por %2 RemoteDatabase Error opening local databases list. %1 Error abriendo la lista de bases de datos locales. %1 Error creating local databases list. %1 Error creando la lista de bases de datos locales. %1 RemoteDock Remote Remoto Local Local Identity Identidad Push currently opened database to server Cargar la base de datos actualmente abierta al servidor Upload Cargar al servidor DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>En este panel, las BB.DD. remotas del sitio web dbhub.io se pueden añadir a «DB Browser for SQLite». En primer lugar necesita una identidad:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ingrese en el sitio web dbhub.io (use sus credenciales de GitHub o las que desee)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Haga clic en el botón de crear un certificado de cliente (esa es su identidad). Eso le proporcionará un archivo de certificado (guárdelo en su disco local).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vaya a la pestaña «Remoto» de las preferencias de «DB Browser for SQLite». Haga clic en el botón para añadir el nuevo certificado a la aplicación y elija el archivo de certificado recién descargado.</li></ol><p>Ahora el panel «Remoto» le mostrará su identidad y podrá añadir BB.DD. remotas.</p></body></html> Current Database Base de datos actual Clone Clonar Branch Rama Commits Versiones Commits for Versiones para Delete Database Borrar base de datos Delete the local clone of this database Borrar el clon local de la base de datos Open in Web Browser Abrir en el navegador web Open the web page for the current database in your browser Abrir la página web de la base de datos actual en su navegador Clone from Link Clonar desde enlace Use this to download a remote database for local editing using a URL as provided on the web page of the database. Use esto para descargar una base de datos remota y editarla localmente usando una URL provista por la página web de la base de datos. Refresh Refrescar Reload all data and update the views Recargar todos los datos y actualizar las vistas Clone Database Clonar base de datos Open Database Abrir base de datos Open the local copy of this database Abrir la copia local de esta base de datos Check out Commit Obtener versión Download and open this specific commit Descargar y abrir esta versión específica Check out Latest Commit Obtener la última versión Check out the latest commit of the current branch Obtener la última versión de la rama actual Save Revision to File Guardar versión en un archivo Saves the selected revision of the database to another file Guarda la versión seleccionada de la base de datos a otro archivo Upload Database Cargar base de datos Upload this database as a new commit Cargar en el servidor esta base de datos como una nueva versión <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>Está usando una identidad integrada de sólo lectura. Para subir su base de datos necesita configurar y usar su cuenta DBHub.io.</p><p>¿Todavía no tiene una cuenta en DBHub.io? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Cree una ahora</span></a> e importe su certificado <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">aquí</span></a> para compartir sus bases de datos.</p><p>Tiene ayuda en línea <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">aquí</span></a>.</p></body></html> &User &Usuario &Database &Base de datos Back Retroceder Select an identity to connect Seleccione una identidad para conectar Public Pública This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Esto descarga una base de datos desde un servidor remoto para edición local. Por favor, introduzca la URL desde la que clonar. Puede obtener esta URL haciendo clic en el botón «Clonar base de datos en DB4S» de la página web de la base de datos. Invalid URL: The host name does not match the host name of the current identity. URL inválida: El nombre de «host» no encaja con el de la identidad actual. Invalid URL: No branch name specified. URL inválida: No se ha especificado el nombre de rama. Invalid URL: No commit ID specified. URL inválida: No se ha especificado el ID de versión. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? Ha realizado cambios en el clon local de la base de datos. Al obtener esta versión sobreescribiría los cambios locales. ¿Está seguro de querer proceder? The database has unsaved changes. Are you sure you want to push it before saving? La base de datos tiene cambios sin guardar. ¿Está seguro de enviarlos sin guardar? The database you are trying to delete is currently opened. Please close it before deleting. La base de datos que pretende borrar está actualmente abierta. Por favor, ciérrela antes de borrarla. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? Esto borra la versión local de esta base de datos con todos los cambios que aún no ha registrado. ¿Está seguro de querer borrarla? RemoteLocalFilesModel Name Nombre Branch Rama Last modified Última modificación Size Tamaño Commit Versión File Archivo RemoteModel Name Nombre Last modified Última modificación Size Tamaño Commit Versión Size: Tamaño: Last Modified: Última modificación: Licence: Licencia: Default Branch: Rama por defecto: RemoteNetwork Choose a location to save the file Seleccione una ubicación para guardar el archivo Error opening remote file at %1. %2 Error abriendo el archivo remoto en %1. %2 Error: Invalid client certificate specified. Error: El certificado del cliente es inválido. Please enter the passphrase for this client certificate in order to authenticate. Por favor, introduzca la frase de contraseña de este certificado de cliente para autenticarse. Cancel Cancelar Uploading remote database to %1 Subiendo base de datos remota a %1 Downloading remote database from %1 Descargando base de datos remota desde %1 Error: Cannot open the file for sending. Error: No se puede abrir el archivo para enviar. RemotePushDialog Push database Remitir base de datos Database na&me to push to No&mbre de la base de datos de destino Commit message Mensaje de versión Database licence Licencia de la base de datos Public Pública Branch Rama Force push Forzar remisión Username Nombre de usuario Database will be public. Everyone has read access to it. La base de datos será pública. Todo el mundo podrá leerla. Database will be private. Only you have access to it. La base de datos será privada. Sólo usted tendrá acceso. Use with care. This can cause remote commits to be deleted. Usar con cuidado. Esto puede provocar borrados de versiones remotas. RunSql Execution aborted by user Ejecución abortada por el usuario , %1 rows affected , %1 filas afectadas query executed successfully. Took %1ms%2 consulta ejecutada con éxito. Tardó %1ms%2 executing query ejecutando consulta SelectItemsPopup A&vailable &Disponible Sele&cted &Seleccionado SqlExecutionArea Form Formulario Find previous match [Shift+F3] Buscar la siguiente ocurrencia [Shift+F3] Find previous match with wrapping Buscar la siguiente ocurrencia Shift+F3 The found pattern must be a whole word El patrón de búsqueda debe ser una palabra completa Whole Words Palabras completas Text pattern to find considering the checks in this frame El patrón de texto buscado considerando las opciones de este marco Find in editor Buscar en el editor The found pattern must match in letter case El patrón de búsqueda debe coincidir en mayúsculas y minúsculas Case Sensitive Distinguir mayús./minús. Find next match [Enter, F3] Buscar la siguiente ocurrencia [Enter, F3] Find next match with wrapping Encontrar la siguiente ocurrencia volviendo al principio si es necesario F3 Interpret search pattern as a regular expression Interpretar el patrón de búsqueda como una expresión regular <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Si se activa, el patrón de búsqueda se interpreta como una expresión regular UNIX. Véase <a href="https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular">«Expresión regular» en Wikipedia</a>.</p></body></html> Regular Expression Expresión regular Close Find Bar Cerrar la barra de búsqueda <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>Resultados de las útimas sentencias ejecutadas.</p><p>Puede que prefiera colapsar este panel y en su lugar usar el <span style=" font-style:italic;">Registro SQL</span> con selección de <span style=" font-style:italic;">Usuario</span>.</p></body></html> Results of the last executed statements Resultados de las últimas sentencias ejecutadas This field shows the results and status codes of the last executed statements. Este campo muestra los resultados y códigos de estado de las últimas sentencias ejecutadas. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. No se pudo leer el archivo "%1": %2. Couldn't save file: %1. No se pudo guardar el archivo: %1. Your changes will be lost when reloading it! ¡Los cambios se perderán al recargarlo! The file "%1" was modified by another program. Do you want to reload it?%2 El archivo "%1" ha sido modificado por otro programa. ¿Quiere recargarlo?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Responda "Sí a todo" para recargar el archivo sin pedir confirmación ante cualquier actualizacion externa. Answer "No to All" to ignore any external update without further prompting. Responda "No a todo" para ignorar cualquier actualizacion externa sin antes pedir confirmación. Modifying and saving the file will restore prompting. Modificando y guardando el archivo se restaurarán los avisos de petición de confirmacións. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) La función abs(X) devuelve el valor absoluto del argumento numérico X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () La función changes() devuelve el número de líneas de la base de datos que se modificaron, insertaron o borraron por la consulta INSERT, DELETE, o UPDATE más reciente. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) La función char(X1,X2,...,XN) devuelve una cadena compuesta por caracteres que tienen el valor numérico del código de punto unicode los enteros X1 hasta XN, respectivamente. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) La función coalesce() devuelve una copia de su primer argumento no nulo, o NULL si todos los argumentos son NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) La función glob(X,Y) es equivalente a la expresión "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) La función ifnull() devuelve una copia de su primer argumento no nulo, o NULL si ambos argumentos son NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) La función instr(X,Y) busca la primera coincidencia de la cadena Y en la cadena X y devuelve el número de caracteres precedentes más 1, ó 0 si Y no se encuentra en X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) La función hex() interpreta su argumento como un BLOB y devuelve una cadena que es el equivalente codificado en hexadecimal en mayúsculas del contenido del BLOB. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) La función iif(X,Y,Z) devuelve el valor Y si X es verdadero, y Z en caso contrario. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () La función last_insert_rowid() devuelve el ROWID del la última línea insertada desde la conexión de la base de datos que invocó la función. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) La función length(X) devuelve el número de caracteres (no bytes) en X anteriores al primer carácter NUL. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) La función like() se usa para implementar la expresión "Y LIKE X". (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) La función like() se usa para implementar la expresión "Y LIKE X ESCAPE Z". (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) La función load_extension(X) carga extensiones SQLite del archivo de la biblioteca compartida llamada X usando el punto de entrada Y. El uso de esta función tiene que ser autorizado desde las Preferencias. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) La función load_extension(X,Y) carga extensiones SQLite del archivo de la biblioteca compartida llamado X usando el punto de entrada Y. El uso de esta función tiene que ser autorizado desde las Preferencias. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) La función lower(X) devuelve una copia de la cadena X con todos los caracteres ASCII convertidos a minúsculas. (X) ltrim(X) removes spaces from the left side of X. (X) La función ltrim(X) quita los espacios a la izquierda de X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) La función ltrim(X,Y) devuelve una cadena formada quitando todos los caracteres que aparecen en Y de la izquierda de X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) La función multi-argumento max() devuelve el argumento con el valor máximo, o NULL si cualquier argumento es NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) La función multi-argumento max() devuelve el argumento con el valor mínimo. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) La función nullif(X,Y) devuelve su primer argumento si los argumentos son diferentes y NULL si los argumentos son el mismo. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) La función SQL printf(FORMAT,...) funciona como la función de lenguaje C sqlite3_mprintf() y la función printf() de la biblioteca C estándar. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) La función quote(X) devuelve el texto de un literal SQL, que es el valor de su argumento, apropiado para la inclusión en una sentencia SQL. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () La función random() devuelve un entero pseudo-aleatorio entre -9223372036854775808 y +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) La función randomblob(N) devuelve un BLOB de N bytes que contiene bytes pseudo-aleatorios. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) La función replace(X,Y,Z) devuelve una cadena formada substituyendo en la cadena Z cada coincidencia con la subcadena Y por la subcadena X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) La función round(X) devuelve un valor en coma flotante X redondeado a cero dígitos a la derecha de la coma decimal. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) La función round(X,Y) devuelve un valor en coma flotante X redondeado a Y dígitos a la derecha de la coma decimal. (X) rtrim(X) removes spaces from the right side of X. (X) La función rtrim(X) quita los espacios a la derecha de X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) La función rtrim(X,Y) devuelve una cadena formada quitando todos los caracteres que aparecen en Y de la derecha de X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) La función soundex(X) devuelve una cadena que es la codificación soundex de la cadena X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) La función substr(X,Y) devuelve una subcadena con todos los caracteres de la cadena X desde el Y-ésimo hasta el último. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) La función substr(X,Y,Z) devuelve una subcadena de la cadena X desde el Y-ésimo carácter y que es Z caracteres de largo. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () La función total_changes() devuelve el número de cambios en las líneas causadas por sentencias INSERT, UPDATE o DELETE desde que la conexión con la base de datos actual se abrió. (X) trim(X) removes spaces from both ends of X. (X) La función trim(X) quita los espacios de ambos lados de X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) La función trim(X,Y) devuelve una cadena formada quitando todos los caracteres que aparecen en Y de ambos lados de X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) La función typeof(X) devuelve una cadena que indica el tipo de datos de la expresión X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) La función unicode(X) devuelve el valor numérico del código de punto unicode correspondiente al primer carácter de la cadena X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) La función upper(X) devuelve una copia de la cadena X con todos los caracteres ASCII convertidos a mayúsculas. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) La función zeroblob(N) devuelve un BLOB consistente en N bytes de 0x00. (timestring,modifier,modifier,...) (timestring,modificador,modificador,...) (format,timestring,modifier,modifier,...) (formato,timestring,modificador,modificador,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) La función avg() devuelve el valor medio de todos los valores no nulos del grupo X. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) La función count(X) devuelve el conteo del número de veces que X no es nulo en un grupo. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) La función group_concat() devuelve una cadena que es la concatenación de todos los valores no nulos X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) La función group_concat() devuelve una cadena que es la concatenación de todos los valores no nulos X, usando el parámetro Y como separador entre las instancias de X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) La función agregada max() devuelve el máximo valor de entre todos los valores en el grupo. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) La función agregada min() devuelve el mínimo valor no NULO de entre todos los valores en el grupo. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) Las funciones agregadas sum() y total() devuelven la suma de todos los valores no NULOS en el grupo. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () El número de fila dentro de la partición actual. Las filas se numeran empezando por 1 en el orden definido por la cláusula ORDER BY en la ventana de definición, o sino en un orden arbitrario. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () El row_number() del primer par (igual) en cada grupo - el rango de la fila actual con huecos. Si no hay una cláusula ORDER BY, entonces todas las filas son consideradas pares y esta función siempre devuelve 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () El número del grupo de pares de la fila actual dentro de su partición - el rango de la fila actual sin huecos. Las particiones se numeran empezando por 1 en el orden definido por la cláusula ORDER BY en la ventana de definición. Si no hay una cláusula ORDER BY, entonces todas las filas son consideradas pares y esta función siempre devuelve 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () A pesar del nombre, esta función siempre devuelve un valor entre 0.0 y 1.0 igual a (rank - 1)/(partition-rows - 1), donde rank es el valor devuelto por la función de ventana incorporada rank() y partition-rows es el número total de filas en la partición. Si la partición contiene sólo una fila, esta función devuelve 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () La distribución acumulada. Calculada como row-number/partition-rows, donde row-number es el valor devuelto por row_number() para el último par (igual) en el grupo y partition-rows el número de filas en la partición. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) El argumento N es tratado como un entero. Esta función divide la partición en N grupos tan equitativamente como sea posible y asigna un entero entre 1 y N a cada grupo, en el orden definido por la cláusula ORDER BY, o sino en un orden arbitrario. Si es necesario, los grupos mayores aparecen primero. Esta función devuelve un valor entero asignado al grupo del que la fila actual es parte. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Devuelve el resultado de evaluar la expresión expr con la fila anterior en la partición. Si no hay fila anterior (porque la fila actual es la primera) devuelve NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) Si se proporciona un offset, éste debe ser un entero no negativo. En este caso el valor devuelto es el resultado de evaluar expr con la fila offset veces anterior a la fila actual dentro de la partición. Si offset es 0, entonces expr se evalua con la fila actual. Si no hay fila offset veces anterior devuelve NULL. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) Si también se proporciona un default, entonces éste es devuelto en lugar de NULL si no existe la fila identificada por offet. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Devuelve el resultado de evaluar la expresión expr con la siguiente fila en la partición. Si no hay fila siguiente (porque la fila actual es la última) devuelve NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) Si se proporciona un offset, éste debe ser un entero no negativo. En este caso el valor devuelto es el resultado de evaluar expr con la fila offset veces posterior a la fila actual dentro de la partición. Si offset es 0, entonces expr se evalua con la fila actual. Si no hay fila offset veces siguiente devuelve NULL. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Esta función de ventana incorporada calcula el marco de la ventana para cada fila de la misma forma que una función agregada de ventana. Devuelve el valor de expr evaluada con la primera fila en el marco de la ventana para cada fila. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Esta función de ventana incorporada calcula el marco de la ventana para cada fila de la misma forma que una función agregada de ventana. Devuelve el valor de expr evaluada con la última fila en el marco de la ventana para cada fila. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) Esta función de ventana incorporada calcula el marco de la ventana para cada fila de la misma forma que una función agregada de ventana. Devuelve el valor de expr evaluada con la fila N del marco de la ventana. Las columnas se numeran dentro del marco de la ventana empezando por 1 en el orden definico por la cláusula ORDER BY, o sino en orden arbitrario. Si no hay fila N-ava en la partición, entonces devuelve NULL. (X) Return the arccosine of X. The result is in radians. (X) Devuelve el arcocoseno de X. El resultado es en radianes. (X) Return the hyperbolic arccosine of X. (X) Devuelve el arcocoseno hiperbólico de X. (X) Return the arcsine of X. The result is in radians. (X) Devuelve el arcoseno de X. El resultado es en radianes. (X) Return the hyperbolic arcsine of X. (X) Devuelve el arcoseno hiperbólico de X. (X) Return the arctangent of X. The result is in radians. (X) Devuelve la arcotangente de X. El resultado es en radianes. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X,Y) Devuelve la arcotangente de Y/X. El resultado es en radianes. El resultado se coloca en el cuadrante correcto en función de los signos de X e Y. (X) Return the hyperbolic arctangent of X. (X) Devuelve la arcotangente hiperbólica de X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Devuelve el valor del primer entero representable mayor o igual que X. Para números positivos esta función redondea en sentido contrario a 0. Para números negativos esta función redondea hacia 0. (X) Return the cosine of X. X is in radians. (X) Devuelve el coseno de X. X es en radianes. (X) Return the hyperbolic cosine of X. (X) Devuelve el coseno hiperbólico de X. (X) Convert value X from radians into degrees. (X) Convierte el valor de X de radianes a grados sexagesimales. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Calcula e (número de Euler, aproximadamente 2.71828182845905) elevado a X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Devuelve el valor del primer entero representable menor o igual que X. Para números positivos esta función redondea hacia 0. Para números negativos esta función redondea en sentido contrario a 0. (X) Return the natural logarithm of X. (X) Devuelve el logaritmo natural de X. (B,X) Return the base-B logarithm of X. (B,X) Devuelve el logaritmo en base B de X. (X) Return the base-10 logarithm for X. (X) Devuelve el logaritmo en base 10 de X. (X) Return the logarithm base-2 for the number X. (X) Devuelve el logaritmo en base 2 de X. (X,Y) Return the remainder after dividing X by Y. (X,Y) Devuelve el resto de dividir X entre Y. () Return an approximation for Ï€. () Devuelve una aproximación para Ï€. (X,Y) Compute X raised to the power Y. (X,Y) Devuelve X elevado a Y. (X) Convert X from degrees into radians. (X) Convierte X de grados sexagesimales a radianes (X) Return the sine of X. X is in radians. (X) Devuelve el seno de X. X es en radianes. (X) Return the hyperbolic sine of X. (X) Devuelve el seno hiperbólico de X. (X) Return the square root of X. NULL is returned if X is negative. (X) Devuelve la raiz cuadrada de X. Devuelve NULL si X es negativo. (X) Return the tangent of X. X is in radians. (X) Devuelve la tangente de X. X es en radianes. (X) Return the hyperbolic tangent of X. (X) Devuelve la tangente hiperbólica de X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) Devuelve el entero representable entre X y 0 (incluído) que está más lejos de 0. En otras palabras, devuelve la parte entera de X, redondeando hacia 0. SqliteTableModel reading rows leyendo filas loading... cargando... References %1(%2) Hold %3Shift and click to jump there Referencia %1(%2) Mantenga pulsado %3Mayús. y haga clic para ir ahí Error changing data: %1 Error modificando datos: %1 retrieving list of columns obteniendo lista de columnas Fetching data... Obteniendo datos... Cancel Cancelar TableBrowser Browse Data Hoja de datos &Table: &Tabla: Select a table to browse data Seleccione una tabla para ver sus datos Use this list to select a table to be displayed in the database view Use esta lista para seleccionar la tabla a mostrar en la vista de la base de datos This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Este es el visor de la tabla de la base de datos. Puede realizar lo siguiente: - Escribir y editar valores. - Doble-clic en cualquier registro para editar su contenido en la ventana del editor de celdas. - Alt+Supr para borrar el contenido de la celda a NULL. - Ctrl+" para duplicar el registro actual. - Ctrl+' para copiar el valor de la celda de arriba. - Las operaciones de copiar y pegar usuales. Text pattern to find considering the checks in this frame El patrón de texto a buscar según las opciones seleccionadas en este marco Find in table Buscar en la tabla Find previous match [Shift+F3] Buscar la anterior ocurrencia [Mayús.+F3] Find previous match with wrapping Buscar la anterior ocurrencia volviendo al final si es necesario Shift+F3 Find next match [Enter, F3] Buscar la siguiente ocurrencia [Intro, F3] Find next match with wrapping Buscar la siguiente ocurrencia volviendo al principio si es necesario F3 The found pattern must match in letter case El patrón de búsqueda tiene que coincidir en mayúsculas y minúsculas Case Sensitive Distinguir mayús./minús. The found pattern must be a whole word El patrón de búsqueda tiene que ser una palabra completa Whole Cell Toda la celda Interpret search pattern as a regular expression Interpretar el patrón de búsqueda como una expresión regular <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Si se marca, el patrón de búsqueda se interpreta como una expresión regular UNIX. Véase <a href="https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular">«Expresión regular» en Wikipedia</a>.</p></body></html> Regular Expression Expresión regular Close Find Bar Cerrar la barra de búsqueda Text to replace with Texto con el que reemplazar Replace with Reemplazar con Replace next match Reemplazar la siguiente coincidencia Replace Reemplazar Replace all matches Reemplazar todas las coincidencias Replace all Reemplazar todo Export to &JSON Exportar a &JSON Export the filtered data to JSON Exportar los datos filtrados a JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Este botón exporta los datos de la tabla que está navegando tal y como se muestran (tras aplicar filtros, formatos de visualización y orden de las columnas) como un archivo JSON. Copy column name Copiar el nombre de la columna Copy the database table column name to your clipboard Copia el nombre de la columna de la base de datos al portapapeles New Data Browser Nueva hoja de datos Add a new docked Data Browser Añadir una nueva hoja de datos anclada This button adds a new docked Data Browser, which you can detach and arrange in different layouts. Este botón añade una nueva hoja de datos anclada, que se puede desanclar y mostrar una presentación diferente. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Desplazarse hasta el principio</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Pulsando este botón se mueve hasta el principio en la vista de tabla de arriba.</p></body></html> |< |< Scroll one page upwards Retroceder una página <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Pulsando este botón se retrocede una página de registros en la vista de tabla de arriba.</p></body></html> < < 0 - 0 of 0 0 - 0 de 0 Scroll one page downwards Avanzar una página <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Pulsando este botón se avanza una página de registros en la vista de tabla de arriba.</p></body></html> > > Scroll to the end Desplazarse hasta el final <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>Pulsando este botón se mueve al final de la vista de tabla de arriba.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>Pulse aquí para saltar al registro especificado</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Este botón se usa para moverse al número de registro especificado en la casilla Ir a.</p></body></html> Go to: Ir a: Enter record number to browse Introduzca el número de registro al que navegar Type a record number in this area and click the Go to: button to display the record in the database view Escriba un número de registro en esta casilla y haga clic en el botón «Ir a:» para mostrar el registro en la vista de la base de datos 1 1 Show rowid column Mostrar la columna rowid Toggle the visibility of the rowid column Cambia la visibilidad de la columna rowid Unlock view editing Desbloquear edición de vistas This unlocks the current view for editing. However, you will need appropriate triggers for editing. Esto desbloquea la vista actual para edición. Aunque para la edición se necesitarán los disparadores adecuados. Edit display format Editar el formato de presentación Edit the display format of the data in this column Editar el formato de presentación de los datos en esta columna New Record Nuevo registro Insert a new record in the current table Inserta un nuevo registro en la tabla actual <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Este botón crea un nuevo registro en la base de datos. Mantenga pulsado el botón del ratón para abrir un menú emergente con varias opciones:</p><ul><li><span style=" font-weight:600;">Nuevo Registro</span>: inserta en la base de datos un nuevo registro con valores por defecto.</li><li><span style=" font-weight:600;">Introduce Valores...</span>: abre un diálogo para introducir valores antes de insertarlos en la base de datos. Esto permite introducir valores que cumplan con las restricciones. Este diálogo también se abre si la opción de <span style=" font-weight:600;">Nuevo Registro</span> falla debido a esas restricciones.</li></ul></body></html> Delete Record Borrar registro Delete the current record Borra el registro actual This button deletes the record or records currently selected in the table Este botón borra el registro seleccionado (o los registros seleccionados) actualmente en la base de datos Insert new record using default values in browsed table Inserta un nuevo registro usando valores por defecto en la tabla visualizada Insert Values... Introducir valores... Open a dialog for inserting values in a new record Abre un diálogo para introducir valores en un nuevo registro Export to &CSV Exportar a &CSV Export the filtered data to CSV Exportar los datos filtrados a CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Este botón exporta los datos de la tabla mostrada tal como se presentan (después de filtros, formatos de presentación y columna de orden) como un archivo CSV. Save as &view Guardar como &vista Save the current filter, sort column and display formats as a view Guardar el filtro actual, la columna de orden y los formatos de presentación como una vista This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Este botón guarda los ajustes actuales de la tabla visualizada (filtros, formatos de presentación y la columna de orden) como una vista SQL que más tarde puede visualizar o usar en sentencias SQL. Save Table As... Guardar tabla como... Save the table as currently displayed Guarda la tabla tal como se presenta <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>Este menú contextual provee las siguientes opciones que se aplican a la tabla actualmente visualizada y filtrada:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exportar a CSV: esta opción exporta los datas de la tabla tal cual se presentan actualmente (después de filtros, formatos de presentación y columna de orden) a un archivo CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Guardar como vista: esta opción guarda la configuración actual de la tabla visualizada (filtros, formatos de presentación y columna de orden) como una vista SQL que luego puede visualizar o usar en sentencias SQL.</li></ul></body></html> Hide column(s) Ocultar columna(s) Hide selected column(s) Ocultar columna(s) seleccionada(s) Show all columns Mostrar todas las columnas Show all columns that were hidden Mostrar todas las columnas que están ocultas Set encoding Definir codificación Change the encoding of the text in the table cells Cambia la codificación del texto de las celdas de la tabla Set encoding for all tables Definir la codificación para todas las tablas Change the default encoding assumed for all tables in the database Cambia la codificación por defecto para todas las tablas en la base de datos Clear Filters Borrar Filtros Clear all filters Borra todos los filtros This button clears all the filters set in the header input fields for the currently browsed table. Este botón elimina todos los filtros establecidos en la cabecera para la tabla mostrada actualmente. Clear Sorting Eliminar ordenación Reset the order of rows to the default Reinicia el orden de las filas al orden por defecto This button clears the sorting columns specified for the currently browsed table and returns to the default order. Este botón elimina la ordenación de las columnas especificadas para la tabla mostrada actualmente y vuelve al orden por defecto. Print Imprimir Print currently browsed table data Imprime los datos de la tabla mostrada actualmente Print currently browsed table data. Print selection if more than one cell is selected. Imprime los datos de la tabla mostrada actualmente. Imprime la selección si se ha seleccionado más de una celda. Ctrl+P Refresh Refrescar Refresh the data in the selected table Refresca los datos en la tabla seleccionada This button refreshes the data in the currently selected table. Este botón refresca los datos de la tabla seleccionada actualmente. F5 Find in cells Buscar en celdas Open the find tool bar which allows you to search for values in the table view below. Abre la barra de búsqueda que permite buscar valores en la vista de la tabla de abajo. Freeze columns Congelar las columnas Make all columns from the first column up to this column not move when scrolling horizontally Hace que no se muevan las columnas, desde la primera hasta esta, cuando se hace scroll horizontal Bold Negrita Ctrl+B Italic Cursiva Underline Subrayado Ctrl+U Align Right Alineado derecha Align Left Alineado izquierda Center Horizontally Centrado horizontal Justify Justificar Edit Conditional Formats... Editar formatos condicionales... Edit conditional formats for the current column Edita formatos condicionales para la columna actual Clear Format Eliminar formato Clear All Formats Eliminar todos los formatos Clear all cell formatting from selected cells and all conditional formats from selected columns Elimina todo el formato de las celdas seleccionadas y los formatos condicionales de las columnas seleccionadas Font Color Color del texto Background Color Color del fondo Toggle Format Toolbar Conmutar barra de formato Show/hide format toolbar Mostrar/ocultar la barra de formato This button shows or hides the formatting toolbar of the Data Browser Este botón muestra u oculta la barra de formato de la Hoja de Datos Select column Seleccionar columna Ctrl+Space Replace text in cells Reemplazar texto en las celdas Filter in any column Filtrar en cualquier columna Ctrl+R %n row(s) %n fila %n filas , %n column(s) , %n columna , %n columnas . Sum: %1; Average: %2; Min: %3; Max: %4 . Suma: %1; Media: %2; Mín: %3; Máx: %4 Conditional formats for "%1" Formatos condicionales para "%1" determining row count... determinando nº de filas... %L1 - %L2 of >= %L3 %L1 - %L2 de >= %L3 %L1 - %L2 of %L3 %L1 - %L2 de %L3 (clipped at %L1 rows) (truncado a %L1 filas) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Introduzca una clave pseudo-primaria para activar la edición en esta vista. Esta debería ser el nombre de una columna única en la vista. Delete Records Borrar registros Duplicate records Duplicar registros Duplicate record Duplicar registro Ctrl+" Adjust rows to contents Ajustar las filas al contenido Error deleting record: %1 Error borrando registro: %1 Please select a record first Por favor, antes seleccione un registro Please choose a new encoding for all tables. Por favor, elija una nueva codificación para todas las tablas. Please choose a new encoding for this table. Por favor, elija una nueva codificación para esta tabla. %1 Leave the field empty for using the database encoding. %1 Deje este campo vacío para usar la codificación de la base de datos. This encoding is either not valid or not supported. Esta codificación no es válida o no está soportada. %1 replacement(s) made. Se realizaron %1 sustitucion(es). TableBrowserDock New Data Browser Nueva hoja de datos Rename Data Browser Renombrar hoja de datos Close Data Browser Cerrar hoja de datos Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. Pone un nuevo nombre a la hoja de datos. Use el carácter «&&» para que el carácter siguiente se use como atajo de teclado. VacuumDialog Compact Database Compactar base de datos Warning: Compacting the database will commit all of your changes. Aviso: compactar la base de datos provocará la consolidación de todos sus cambios. Please select the databases to co&mpact: Seleccione las bases de datos que desea co&mpactar: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_fa.ts000066400000000000000000012153351463772530400251750ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Version <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Enter values for the new record considering constraints. Fields in bold are mandatory. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Name Type Value Values to insert. Pre-filled default values are inserted automatically unless they are changed. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> Auto-increment Unique constraint Check constraint: %1 Foreign key: %1 Default value: %1 Error adding record. Message from database engine: %1 Are you sure you want to restore all the entered values to their defaults? Application Possible command line arguments: The user settings file location is replaced with the argument value instead of the environment variable value. Ignored environment variable (DB4S_SETTINGS_FILE) value: The file %1 does not exist Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Browse this table, or use it as target of a data import Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The -S/--settings option requires an argument. The option is ignored. The -o/--option and -O/--save-option options require an argument in the form group/setting=value SQLite Version SQLCipher Version %1 (based on SQLite %2) DB Browser for SQLite Version %1. Last commit hash when built: %1 Built for %1, running on %2 Qt Version %1 Invalid option/non-existent file: %1 CipherDialog SQLCipher encryption &Password &Reenter password Passphrase Raw key Encr&yption settings SQLCipher &3 defaults SQLCipher &4 defaults Custo&m Page si&ze &KDF iterations HMAC algorithm KDF algorithm Plaintext Header Size Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. ColumnDisplayFormatDialog Choose display format Display format Choose a display format for the column '%1' which is applied to each value prior to showing it. Default Decimal number Exponent notation Hex blob Hex number Octal number Round number Apple NSDate to date Java epoch (milliseconds) to date .NET DateTime.Ticks to date Julian day to date Unix epoch to date Unix epoch to local time WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Windows DATE to date Date as dd/mm/yyyy Lower case Upper case Binary GUID to text SpatiaLite Geometry to SVG Custom Custom display format must contain a function call applied to %1 Error in custom display format. Message from database engine: %1 Custom display format must return only one column but it returned %1. CondFormatManager Conditional Format Manager This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Add new conditional format &Add Remove selected conditional format &Remove Move selected conditional format up Move &up Move selected conditional format down Move &down Foreground Text color Background Background color Font Size Bold Italic Underline Alignment Condition Click to select color Are you sure you want to clear all the conditional formats of this field? DBBrowserDB Please specify the database name under which you want to access the attached database Invalid file format Do you really want to close this temporary database? All data will be lost. Do you want to save the changes made to the database file %1? Database didn't close correctly, probably still busy Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: Do you want to abort that other operation? Exporting database to SQL file... Cancel No database file opened Executing SQL... Action cancelled. Error in statement #%1: %2. Aborting execution%3. and rolling back didn't receive any output from %1 could not execute command: %1 Cannot delete this object Cannot set data on this object A table with the name '%1' already exists in schema '%2'. No table with name '%1' exists in schema '%2'. Cannot find column %1. Creating savepoint failed. DB says: %1 Renaming the column failed. DB says: %1 Releasing savepoint failed. DB says: %1 Creating new table failed. DB says: %1 Copying data to new table failed. DB says: %1 Deleting old table failed. DB says: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Error renaming table '%1' to '%2'. Message from database engine: %3 could not get list of db objects: %1 could not get list of databases: %1 Error setting pragma %1 to %2: %3 File not found. Error loading extension: %1 Error loading built-in extension: %1 could not get column information DbStructureModel Name Object Type Schema Database Browsables All Temporary Tables (%1) Indices (%1) Views (%1) Triggers (%1) EditDialog Edit database cell Mode: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Text RTL Text Binary Image JSON XML Evaluation Automatically adjust the editor mode to the loaded data type This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Auto-switch This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Identification of the cell currently in the editor Type and size of data currently in table Open preview dialog for printing the data currently stored in the cell Auto-format: pretty print on loading, compact on saving. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Word Wrap Wrap lines on word boundaries Open in default application or browser Open in application The value is interpreted as a file or URL and opened in the default application or web browser. Save file reference... Save reference to file Open in external application Autoformat &Export... &Import... Import from file Opens a file dialog used to import any kind of data to this database cell. Export to file Opens a file dialog used to export the contents of this database cell to a file. Erases the contents of the cell Set as &NULL This area displays information about the data present in this database cell Apply data to cell This button saves the changes performed in the cell editor to the database cell. Apply Print... Ctrl+P Open preview dialog for printing displayed text Copy Hex and ASCII Copy selected hexadecimal and ASCII columns to the clipboard Ctrl+Shift+C Image data can't be viewed in this mode. Try switching to Image or Binary mode. Binary data can't be viewed in this mode. Try switching to Binary mode. Image files (%1) Binary files (*.bin) Choose a file to import The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Unsaved data in the cell editor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. %1 Image Choose a filename to export data Invalid data for this mode The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) Couldn't save file: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. EditIndexDialog Edit Index Schema &Name &Table &Unique For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Partial inde&x clause Colu&mns Table column Type Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Index column Order Deleting the old index failed: %1 Creating the index failed: %1 EditTableDialog Edit table definition Table Advanced Without Rowid Fields Name Type NN Not null PK Database sche&ma Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Add Remove Move to top Move up Move down Move to bottom <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> AI Autoincrement U Unique Default Default value Check Check constraint Collation Foreign Key <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Index Constraints Add constraint Remove constraint Columns SQL Foreign Keys References Check Constraints <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> Primary Key Add a primary key constraint Add a unique constraint There can only be one primary key for each table. Please modify the existing primary key instead. Error creating table. Message from database engine: %1 There already is a field with that name. Please rename it first or choose a different name for this field. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Column '%1' has duplicate data. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set ExportDataDialog Export data as CSV Tab&le(s) Colu&mn names in first line Fie&ld separator , ; Tab | Other &Quote character " ' New line characters Windows: CR+LF (\r\n) Unix: LF (\n) Pretty print Export data as JSON exporting CSV Error while writing the file '%1': %2 Could not open output file: %1 exporting JSON Choose a filename to export data Please select at least 1 table. Choose a directory Export completed. Export finished with errors. ExportSqlDialog Export SQL... Tab&le(s) Select All Deselect All &Options Keep column names in INSERT INTO Multiple rows (VALUES) per INSERT statement Export everything Export schema only Export data only Keep original CREATE statements Keep old schema (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Please select at least one table. Choose a filename to export Export completed. Export cancelled or failed. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Find and Replace... Print... ExtendedTableWidget Use as Exact Filter Containing Not containing Not equal to Greater than Less than Greater or equal Less or equal Between this and... Regular expression Edit Conditional Formats... Set to NULL Cut Copy Copy with Headers Copy as SQL Paste Print... Use in Filter Expression Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. FileExtensionManager File Extension Manager &Up &Down &Add &Remove Description Extensions *.extension FilterLineEdit Filter These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Clear All Conditional Formats Use for Conditional Format Set Filter Expression What's This? Is NULL Is not NULL Is empty Is not empty Not containing... Equal to... Not equal to... Greater than... Less than... Greater or equal... Less or equal... In range... Regular expression... Edit Conditional Formats... FindReplaceDialog Find and Replace Fi&nd text: Re&place with: Match &exact case Match &only whole words When enabled, the search continues from the other end when it reaches one end of the page &Wrap around When set, the search goes backwards from cursor position, otherwise it goes forward Search &backwards <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> &Selection only <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Use regular e&xpressions Find the next occurrence from the cursor position and in the direction set by "Search backwards" &Find Next F3 &Replace Highlight all the occurrences of the text in the page F&ind All Replace all the occurrences of the text in the page Replace &All The searched text was not found The searched text was not found. The searched text was replaced one time. The searched text was found one time. The searched text was replaced %1 times. The searched text was found %1 times. ForeignKeyEditor &Reset Foreign key clauses (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Reset the scaling to match the original size of the image. Set the scaling to match the size of the viewport. Print... Open preview dialog for printing displayed image Ctrl+P ImportCsvDialog Import CSV file Table na&me &Column names in first line Field &separator , ; Tab | Other &Quote character Other (printable) Other (code) " ' &Encoding UTF-8 UTF-16 ISO-8859-1 Trim fields? Separate tables Advanced When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Ignore default &values Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Fail on missing values Disable data type detection Disable the automatic data type detection when creating a new table. Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Abort import Ignore row Replace existing row Conflict strategy Deselect All Match Similar Select All There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. There is already a table named '%1'. Do you want to import the data into it? Creating restore point failed: %1 Creating the table failed: %1 importing CSV Could not prepare INSERT statement: %1 Inserting row failed: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. MainWindow DB Browser for SQLite This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. toolBar1 &File &Import &Export &Edit &View &Help Too&ls DB Toolbar Edit Database &Cell SQL &Log Show S&QL submitted by User Application Error Log This button clears the contents of the SQL logs &Clear This panel lets you examine a log of all SQL commands issued by the application or by yourself &Plot DB Sche&ma This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. &Remote Project Toolbar Extra DB toolbar Close the current database file &New Database... Create a new database file This option is used to create a new database file. Ctrl+N &Open Database... Open an existing database file This option is used to open an existing database file. Ctrl+O &Close Database This button closes the connection to the currently open database file Ctrl+W &Revert Changes Revert database to last saved state This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. &Write Changes Write changes to the database file This option is used to save changes to the database file. Ctrl+S Compact &Database... Compact the database file, removing space wasted by deleted records Compact the database file, removing space wasted by deleted records. E&xit Ctrl+Q &Database from SQL file... Import data from an .sql dump text file into a new or existing database. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. &Table from CSV file... Open a wizard that lets you import data from a comma separated text file into a database table. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. &Database to SQL file... Export a database to a .sql dump text file. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. &Table(s) as CSV file... Export a database table as a comma separated text file. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. &Create Table... Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database &Delete Table... Delete Table Open the Delete Table wizard, where you can select a database table to be dropped. &Modify Table... Create &Index... Open the Create Index wizard, where it is possible to define a new index on an existing database table. &Preferences... Open the preferences window. &DB Toolbar Shows or hides the Database toolbar. New &tab Ctrl+T Open SQL file(s) This button opens files containing SQL statements and loads them in new editor tabs Sa&ve Project This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file This button lets you open a DB Browser for SQLite project file Ctrl+Shift+O &Save Project As... Save the project in a file selected in a dialog Save A&ll Save DB file, project file and opened SQL files Ctrl+Shift+S Browse Table Close Pro&ject Close project and database files and return to the initial state Ctrl+Shift+F4 Detach Database Detach database file attached to the current database connection W&hat's This? &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs E&xecute SQL This has to be equal to the tab title in all the main tabs &Recent Files &New Database Ctrl+F4 &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Shift+F1 &About &Recently opened This button opens a new tab for the SQL editor &Execute SQL Execute all/selected SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Ctrl+Return Ctrl+Shift+T Save SQL file &Load Extension... Execute current line Execute line This button executes the SQL statement present in the current editor line Shift+F5 Export as CSV file Export table as comma separated values file &Wiki F1 Bug &Report... Feature Re&quest... Web&site &Donate on Patreon... &Save Project Save the current session to a file Open &Project... Open &Project Load a working session from a file &Attach Database... Add another database file to the current database connection This button lets you add another database file to the current database connection &Set Encryption... Save SQL file as This button saves the content of the current SQL editor tab to a file &Browse Table Copy Create statement Copy the CREATE statement of the item to the clipboard SQLCipher &FAQ Opens the SQLCipher FAQ in a browser window Table(&s) to JSON... Export one or more table(s) to a JSON file Open Data&base Read Only... Open an existing database file in read only mode Save results Save the results view This button lets you save the results of the last executed query Find text in SQL editor Find This button opens the search bar of the editor Ctrl+F Find or replace text in SQL editor Find or replace This button opens the find/replace dialog for the current editor tab Ctrl+H Export to &CSV Export to &JSON Save as &view Save as view Shows or hides the Project toolbar. Extra DB Toolbar &Open Database New In-&Memory Database Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Drag && Drop Qualified Names Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Drag && Drop Enquoted Names Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor &Integrity Check Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. &Foreign-Key Check Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab &Quick Integrity Check Run a quick integrity check over the open DB Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. &Optimize Attempt to optimize the database Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Print Print text from current SQL editor tab Open a dialog for printing the text in the current SQL editor tab Ctrl+P Print the structure of the opened database Open a dialog for printing the structure of the opened database Un/comment block of SQL code Un/comment block Comment or uncomment current line or selected block of code Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Ctrl+/ Stop SQL execution Stop execution Stop the currently running SQL script Ctrl+Shift+W Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Refresh Reload the database structure Ctrl+L Ctrl+D Ctrl+I Ctrl+E Ctrl+Alt+0 The database is currently busy. Click here to interrupt the currently running query. Encrypted Database is encrypted using SQLCipher Read only Database file is read only. Editing the database is disabled. Database encoding Ctrl+Alt+W Choose a database file Could not open database file. Reason: %1 Choose a filename to save under In-Memory database Choose a database file to save under Error while saving the database to the new file. Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Are you sure you want to delete the view '%1'? Are you sure you want to delete the trigger '%1'? Are you sure you want to delete the index '%1'? Error: could not delete the table. Error: could not delete the view. Error: could not delete the trigger. Error: could not delete the index. Message from database engine: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Error checking foreign keys after table modification. The changes will be reverted. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. -- EXECUTING SELECTION IN '%1' -- -- EXECUTING LINE IN '%1' -- -- EXECUTING ALL IN '%1' -- %1 rows returned in %2ms Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Execution finished with errors. Execution finished without errors. Choose text files Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? Choose a file to import Opened '%1' in read-only mode from recent file list Opened '%1' from recent file list &%1 %2%3 (read only) Open Database or Project Attach Database... Import CSV file(s)... Do you want to save the changes made to SQL tabs in a new project file? Do you want to save the changes made to SQL tabs in the project file '%1'? Do you want to save the changes made to the SQL file %1? The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? Text files(*.sql *.txt);;All files(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Ctrl+Tab Ctrl+Shift+Tab Clear List Window Layout Reset Window Layout Simplify Window Layout Alt+Shift+0 Dock Windows at Bottom Dock Windows at Left Side Dock Windows at Top You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Do you want to save the changes made to the project file '%1'? Edit View %1 Edit Trigger %1 At line %1: Result: %1 Result: %2 File %1 already exists. Please choose a different name. Error importing data: %1 Import completed. Some foreign key constraints are violated. Please fix them before saving. Import completed. Delete View Modify View Delete Trigger Modify Trigger Delete Index Modify Index Modify Table Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. DB file '%1' could not be opened This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Table '%1' not found; settings ignored Could not open project file for writing. Reason: %1 -- Reference to file "%1" (not supported by this version) -- Project saved to file '%1' Yes. Don't ask again Rename Tab Duplicate Tab Close Tab Opening '%1'... There was an error opening '%1'... Value is not a valid URL or filename: %1 Setting PRAGMA values will commit your current transaction. Are you sure? Automatically load the last opened DB file at startup Select SQL file to open Select file name Select extension file Extension successfully loaded. Error loading extension: %1 Could not find resource file: %1 Don't show again New version available. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Choose a project file to open DB Browser for SQLite project file (*.sqbpro) Collation needed! Proceed? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! creating collation Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Please specify the view name There is already an object with that name. Please choose a different name. View successfully created. Error creating view: %1 This action will open a new SQL tab for running: This action will open a new SQL tab with the following statements for you to edit and run: Press Help for opening the corresponding SQLite reference page. Busy (%1) NullLineEdit Set to NULL Alt+Del PlotDock Plot <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> Columns X Y1 Y2 Axis Type Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Line type: None Line StepLeft StepRight StepCenter Impulse Point shape: Cross Plus Circle Disc Square Diamond Star Triangle TriangleInverted CrossSquare PlusSquare CrossCircle PlusCircle Peace <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> Save current plot... Load all data and redraw plot Copy Print... Show legend Stacked bars Fixed number format Date/Time Date Time Numeric Label Invalid Row # Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Choose an axis color Choose a filename to save under PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Loading all remaining data for this table took %1ms. PreferencesDialog Preferences &General Default &location Remember last location Always use this location Remember last location for session only ... Lan&guage Toolbar style Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style enabled Automatic &updates DB file extensions Manage Show remote options &Database Database &encoding Open databases with foreign keys enabled. &Foreign keys Remove line breaks in schema &view When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Prefetch block si&ze SQ&L to execute after opening database Default field type Main Window Database Structure Browse Data Execute SQL Edit Database Cell When this value is changed, all the other color preferences are also set to matching colors. Follow the desktop style Dark style Application style This sets the font size for all UI elements which do not have their own font size option. Font size Max Recent Files Prompt to save SQL tabs in new project file If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Database structure font size Data &Browser Font &Font Font si&ze Content Symbol limit in cell This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Threshold for completion and calculation on selection Show images in cell Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Field display Displayed &text Binary NULL Regular Click to set this color Text color Background color Preview only (N/A) Filters Escape character Delay time (&ms) Light style Formatted Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. &SQL Context Colour Bold Italic Underline Keyword Function Table Comment Identifier String Current line Background Foreground Selection background Selection foreground Highlight SQL editor &font SQL &editor font size SQL &results font size Tab size Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. &Wrap lines Never At word boundaries At character boundaries At whitespace boundaries &Quotes for identifiers Choose the quoting mechanism used by the application for identifiers in SQL code. "Double quotes" - Standard SQL (recommended) `Grave accents` - Traditional MySQL quotes [Square brackets] - Traditional MS SQL Server quotes Code co&mpletion Keywords in &UPPER CASE When set, the SQL keywords are completed in UPPER CASE letters. Error indicators When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Hori&zontal tiling If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Close button on tabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. &Extensions Select extensions to load for every database: Add extension Remove extension Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> Disable Regular Expression extension <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> Allow loading extensions from SQL code Remote Your certificates File Subject CN Subject Common Name Issuer CN Issuer Common Name Valid from Valid to Serial number CA certificates Common Name Subject O Organization Clone databases into Proxy Configure Export Settings Import Settings Choose a directory The language will change after you restart the application. Select extension file Extensions(*.so *.dylib *.dll);;All files(*) Import certificate file No certificates found in this file. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Save Settings File Initialization File (*.ini) The settings file has been saved in location : Open Settings File The settings file was loaded properly. The selected settings file is not a normal settings file. Please check again. ProxyDialog Proxy Configuration Pro&xy Type Host Na&me Port Authentication Re&quired &User Name Password None System settings HTTP SOCKS5 QObject All files (*) Error importing data from record number %1 . %1 Importing CSV file... Cancel SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Left Right Center Justify SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) SQL Files (*.sql) All Files (*) Text Files (*.txt) Comma-Separated Values Files (*.csv) Tab-Separated Values Files (*.tsv) Delimiter-Separated Values Files (*.dsv) Concordance DAT files (*.dat) JSON Files (*.json *.js) XML Files (*.xml) Binary Files (*.bin *.dat) SVG Files (*.svg) Hex Dump Files (*.dat *.bin) Extensions (*.so *.dylib *.dll) Initialization File (*.ini) RemoteCommitsModel Commit ID Message Date Author Size Authored and committed by %1 Authored by %1, committed by %2 RemoteDatabase Error opening local databases list. %1 Error creating local databases list. %1 RemoteDock Remote Identity Upload DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> Local Current Database Clone &User &Database Branch Commits Commits for <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> Back Delete Database Delete the local clone of this database Open in Web Browser Open the web page for the current database in your browser Clone from Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. Refresh Reload all data and update the views Clone Database Open Database Open the local copy of this database Check out Commit Download and open this specific commit Check out Latest Commit Check out the latest commit of the current branch Save Revision to File Saves the selected revision of the database to another file Upload Database Upload this database as a new commit Push currently opened database to server Select an identity to connect Public This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Invalid URL: The host name does not match the host name of the current identity. Invalid URL: No branch name specified. Invalid URL: No commit ID specified. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? The database has unsaved changes. Are you sure you want to push it before saving? The database you are trying to delete is currently opened. Please close it before deleting. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? RemoteLocalFilesModel Name Branch Last modified Size Commit File RemoteModel Name Commit Last modified Size Size: Last Modified: Licence: Default Branch: RemoteNetwork Choose a location to save the file Error opening remote file at %1. %2 Error: Invalid client certificate specified. Please enter the passphrase for this client certificate in order to authenticate. Cancel Uploading remote database to %1 Downloading remote database from %1 Error: Cannot open the file for sending. RemotePushDialog Push database Database na&me to push to Commit message Database licence Public Branch Force push Username Database will be public. Everyone has read access to it. Database will be private. Only you have access to it. Use with care. This can cause remote commits to be deleted. RunSql Execution aborted by user , %1 rows affected query executed successfully. Took %1ms%2 executing query SelectItemsPopup A&vailable Sele&cted SqlExecutionArea Form Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 The found pattern must be a whole word Whole Words Text pattern to find considering the checks in this frame Find in editor The found pattern must match in letter case Case Sensitive Find next match [Enter, F3] Find next match with wrapping F3 Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Close Find Bar <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> Results of the last executed statements This field shows the results and status codes of the last executed statements. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Couldn't save file: %1. Your changes will be lost when reloading it! The file "%1" was modified by another program. Do you want to reload it?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) ltrim(X) removes spaces from the left side of X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X) rtrim(X) removes spaces from the right side of X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. (X) trim(X) removes spaces from both ends of X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. SqliteTableModel reading rows loading... References %1(%2) Hold %3Shift and click to jump there Error changing data: %1 retrieving list of columns Fetching data... Cancel TableBrowser Browse Data &Table: Select a table to browse data Use this list to select a table to be displayed in the database view This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Text pattern to find considering the checks in this frame Find in table Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 Find next match [Enter, F3] Find next match with wrapping F3 The found pattern must match in letter case Case Sensitive The found pattern must be a whole word Whole Cell Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Close Find Bar Text to replace with Replace with Replace next match Replace Replace all matches Replace all Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Copy column name Copy the database table column name to your clipboard New Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> |< Scroll one page upwards <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> < 0 - 0 of 0 Scroll one page downwards <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> > Scroll to the end <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> Go to: Enter record number to browse Type a record number in this area and click the Go to: button to display the record in the database view 1 Show rowid column Toggle the visibility of the rowid column Unlock view editing This unlocks the current view for editing. However, you will need appropriate triggers for editing. Edit display format Edit the display format of the data in this column New Record Insert a new record in the current table <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> Delete Record Delete the current record This button deletes the record or records currently selected in the table Insert new record using default values in browsed table Insert Values... Open a dialog for inserting values in a new record Export to &CSV Export the filtered data to CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Save as &view Save the current filter, sort column and display formats as a view This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Save Table As... Save the table as currently displayed <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> Hide column(s) Hide selected column(s) Show all columns Show all columns that were hidden Set encoding Change the encoding of the text in the table cells Set encoding for all tables Change the default encoding assumed for all tables in the database Clear Filters Clear all filters This button clears all the filters set in the header input fields for the currently browsed table. Clear Sorting Reset the order of rows to the default This button clears the sorting columns specified for the currently browsed table and returns to the default order. Print Print currently browsed table data Print currently browsed table data. Print selection if more than one cell is selected. Ctrl+P Refresh Refresh the data in the selected table This button refreshes the data in the currently selected table. F5 Find in cells Open the find tool bar which allows you to search for values in the table view below. Bold Ctrl+B Italic Underline Ctrl+U Align Right Align Left Center Horizontally Justify Edit Conditional Formats... Edit conditional formats for the current column Clear Format Clear All Formats Clear all cell formatting from selected cells and all conditional formats from selected columns Font Color Background Color Toggle Format Toolbar Show/hide format toolbar This button shows or hides the formatting toolbar of the Data Browser Select column Ctrl+Space Replace text in cells Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally Filter in any column Ctrl+R %n row(s) , %n column(s) . Sum: %1; Average: %2; Min: %3; Max: %4 Conditional formats for "%1" determining row count... %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Delete Records Duplicate records Duplicate record Ctrl+" Adjust rows to contents Error deleting record: %1 Please select a record first Please choose a new encoding for all tables. Please choose a new encoding for this table. %1 Leave the field empty for using the database encoding. This encoding is either not valid or not supported. %1 replacement(s) made. TableBrowserDock New Data Browser Rename Data Browser Close Data Browser Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. VacuumDialog Compact Database Warning: Compacting the database will commit all of your changes. Please select the databases to co&mpact: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_fr.ts000066400000000000000000014217651463772530400252240ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite À propos de DB-Browser pour SQLite Version Version <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Ajouter un nouvel enregistrement Enter values for the new record considering constraints. Fields in bold are mandatory. Saisissez les valeurs en tenant compte des contraintes. Les champs en gras sont obligatoires. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Dans la colonne Valeur, vous pouvez spécifier la valeur du champ identifié dans la colonne Nom. La colonne Type indique le type du champ. Les valeurs par défaut sont affichées dans le même style que les valeurs NULL. Name Nom Type Type Value Valeur Values to insert. Pre-filled default values are inserted automatically unless they are changed. Valeurs à insérer. Les valeurs par défaut pré-remplies sont insérées automatiquement à moins qu'elles ne soient modifiées. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Lorsque vous éditez les valeurs dans le cadre supérieur, la requête SQL d'insertion du nouvel enregistrement est affichée ici. Vous pouvez l'éditer manuellement avant de l'enregistrer. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Enregistrer</span> soumettra l'instruction SQL affichée à la base de données pour créer le nouvel enregistrement.</p><p><span style=" font-weight:600;">Restaurer les valeurs par défaut</span> restaurera les valeurs par défaut dans la <span style=" font-weight:600;">colonne</span> Valeur.</p><p><span style=" font-weight:600;">Annuler</span> fermera cette boîte de dialogue sans exécuter la requête.</p></body></html> Auto-increment Incrément automatique Unique constraint Contrainte unique Check constraint: %1 Vérifier les contraintes : %1 Foreign key: %1 Clé étrangère : %1 Default value: %1 Valeur par défaut : %1 Error adding record. Message from database engine: %1 Erreur lors de l'ajout d'un enregistrement. Message du moteur de base de données : %1 Are you sure you want to restore all the entered values to their defaults? Êtes-vous sûr de vouloir restaurer toutes les valeurs saisies à leurs valeurs par défaut ? Application Possible command line arguments: Arguments utilisables en ligne de commande : The -o/--option and -O/--save-option options require an argument in the form group/setting=value Les options de commande -o/--option et -O/--save-option nécessitent un argument sous la forme groupe/paramètre=valeur The user settings file location is replaced with the argument value instead of the environment variable value. L'emplacement du fichier de configuration de l'utilisateur est remplacé par la valeur de l'argument au lieu de la valeur de la variable d'environnement. Ignored environment variable (DB4S_SETTINGS_FILE) value: Valeur ignorée de la variable d'environnement (DB4S_SETTINGS_FILE) : The file %1 does not exist Le fichier %1 n'existe pas Usage Utilisation options options database base de données project projet csv-file fichier-csv Show command line options Afficher les options de la ligne de commande Exit application after running scripts Quitter l'application après l'exécution des scripts file fichier Execute this SQL file after opening the DB Exécuter ce fichier SQL après avoir ouvert la base de données Import this CSV file into the passed DB or into a new DB Importer ce fichier CSV dans la base de données existante ou dans une nouvelle base de données table table Browse this table, or use it as target of a data import Parcourir cette table ou l'utiliser comme cible d'une importation de données Open database in read-only mode Ouvrir la base de données en Lecture seule settings_file fichier paramètres Run application based on this settings file Lancer l'application avec ce fichier de paramètres group groupe settings paramètres value valeur Run application with this setting temporarily set to value Lancer l'application en utilisant temporairement la valeur de ce paramètre Run application saving this value for this setting Lancer l'application en sauvegardant la valeur de ce paramètre Display the current version Afficher la version en cours Open this SQLite database Ouvrir cette base de données SQLite Open this project file (*.sqbpro) Ouvrir ce fichier projet (*.sqbpro) Import this CSV file into an in-memory database Importer ce fichier CSV dans une base de données en mémoire The %1 option requires an argument L'option %1 nécessite un argument The -S/--settings option requires an argument. The option is ignored. L'option -S/--settings nécessite un argument. L'option est ignorée. Invalid option/non-existent file: %1 Option invalide ou fichier %1 inexistant SQLite Version Version de SQLite SQLCipher Version %1 (based on SQLite %2) SQLCipher Version %1 (basé sur SQLite %2) DB Browser for SQLite Version %1. DB Browser pour SQLite Version %1. Last commit hash when built: %1 Corriger cette phrase. A voir en fonction du contexte MVT Dernier hachage du commit lors de la construction : %1 Built for %1, running on %2 Compilé pour %1, fonctionnant sur %2 Qt Version %1 Version de Qt %1 CipherDialog SQLCipher encryption Chiffrement par SQLCipher &Password Mot de &Passe &Reenter password &Retaper le mot de passe Encr&yption settings Para&mètre de chiffrement SQLCipher &3 defaults SQLCipher &3 par défaut SQLCipher &4 defaults SQLCipher &4 par défaut Custo&m Pers&onnalisé Page si&ze &Taille de page &KDF iterations Itérations &KDF HMAC algorithm Algorithme HMAC KDF algorithm Algorithme KDF Plaintext Header Size Taille En-tête texte en clair Passphrase The button size is not large enought to handle the whole "french text", if #Passphrase must be translate Phrase secrète Raw key Same comment as for Passphrase Clé de chiffrement Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Veuillez définir une clé pour chiffrer la base de données. Notez que si vous modifiez les autres paramètres, optionnels, vous devrez les ressaisir chaque fois que vous ouvrirez la base de données. Laisser les champs Mot de passe vides pour désactiver le chiffrement. Le processus de chiffrement peut prendre un certain temps. Vous devriez avoir une copie de sauvegarde de votre base de données ! Les modifications non enregistrées seront appliquées avant la modification du chiffrement. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Veuillez entrer la clé utilisée pour le chiffrement de la base de données. Si d'autres paramètres ont été modifiés pour cette base de données, vous devrez aussi fournir ces informations. ColumnDisplayFormatDialog Choose display format Choisir un format d'affichage Display format Format d'affichage Choose a display format for the column '%1' which is applied to each value prior to showing it. Choisissez le format d'affichage pour la colonne '%1'. Il sera appliqué à chaque valeur avant son affichage. Default Défaut Decimal number Nombre décimal Exponent notation Notation scientifique Hex blob Blob hexadécimal Hex number Nombre hexadécimal Apple NSDate to date Apple NSDate vers date Java epoch (milliseconds) to date Java epoch (milliseconds) en date .NET DateTime.Ticks to date .NET DateTime.Ticks en date Julian day to date Date julienne vers Date Unix epoch to local time Heure Unix epoch vers heure locale WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy Date au format DD/MM/AAAA Lower case Minuscule Binary GUID to text GUID binaire en texte SpatiaLite Geometry to SVG SpatiaLite Geometry vers SVG Custom display format must contain a function call applied to %1 Le format d'affichage personnalisé doit contenir un appel de fonction appliqué à %1 Error in custom display format. Message from database engine: %1 Erreur dans le format d'affichage personnalisé. Message du moteur de base de données : %1 Custom display format must return only one column but it returned %1. Le format d'affichage personnalisé ne doit renvoyer qu'une seule colonne, mais il a renvoyé %1. Octal number Nombre octal Round number Nombre arrondi Unix epoch to date Date Unix epoch en Date Upper case Majuscule Windows DATE to date Date Windows en Date Custom Personnalisé CondFormatManager Conditional Format Manager Gestion des formats conditionnels This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Cette fenêtre de dialogue permet de créer et de modifier des formats conditionnels. Chaque style de cellule sera sélectionné par la première condition remplie pour les données de cette cellule. Les formats conditionnels peuvent être déplacés vers le haut et vers le bas. Ceux des rangées supérieures ont la priorité sur ceux des rangées inférieures. La syntaxe des conditions est la même que celle des filtres et une condition vide s'applique à toutes les valeurs. Add new conditional format Ajouter un nouveau format conditionnel &Add &Ajouter Remove selected conditional format Supprime le format conditionnel sélectionné &Remove &Supprimer Move selected conditional format up Déplace le format conditionnel vers le haut Move &up &Monter Move selected conditional format down Déplace le format conditionnel vers le bas Move &down &Descendre Foreground Avant-plan Text color Couleur de texte Background Arrière-plan Background color Couleur d'arrière-plan Font Police Size Taille Bold Gras Italic Italique Underline Souligné Alignment Alignement Condition Condition Click to select color Cliquer pour sélectionner une couleur Are you sure you want to clear all the conditional formats of this field? Êtes-vous sûr de vouloir effacer tous les formats conditionnels de ce champ ? DBBrowserDB Please specify the database name under which you want to access the attached database Veuillez spécifier le nom de la base de données sous laquelle vous voulez accéder à la base de données attachée Invalid file format Format de fichier invalide Do you want to save the changes made to the database file %1? Voulez-vous enregistrer les changements effectués dans la base de données %1 ? Exporting database to SQL file... Exporter la base de données dans un fichier SQL... Cancel Annuler Executing SQL... Exécution du SQL... Action cancelled. Action annulée. Do you really want to close this temporary database? All data will be lost. Voulez-vous vraiment fermer cette base de données temporaire ? Toutes les données seront perdues. Database didn't close correctly, probably still busy La base de données ne s'est pas fermée correctement; Elle est probablement encore occupée Cannot open destination file: '%1' Le fichier de destination %1 ne peut être ouvert Cannot backup to file: '%1'. Message: %2 Impossible de sauvegarder dans le fichier : '%1'. Message : %2 The database is currently busy: La base de données est actuellement occupée : Do you want to abort that other operation? Voulez-vous annuler cette autre opération ? No database file opened Aucun fichier de base de données ouvert Error in statement #%1: %2. Aborting execution%3. Erreur dans le traitement #%1 : %2. Exécution de %3 abandonnée. and rolling back et annulation des changements didn't receive any output from %1 n'a pas reçu toutes les sorties de %1 could not execute command: %1 ne peut pas exécuter les commandes : %1 Cannot delete this object Impossible de supprimer cet objet Cannot set data on this object 170726 MVT Has to be checked in real context Définition des données impossible pour cet objet A table with the name '%1' already exists in schema '%2'. Une table portant le nom " %1 " existe déjà dans le schéma " %2 ". No table with name '%1' exists in schema '%2'. Il n'existe pas de table nommée " %1 " dans le schéma " %2 ". Cannot find column %1. La colonne %1 n'a pas été trouvée. Creating savepoint failed. DB says: %1 La création du point de restauration a échoué. DB indique : %1 Renaming the column failed. DB says: %1 Le changement de nom de la colonne a échoué. DB indique : %1 Releasing savepoint failed. DB says: %1 La libération du point de sauvegarde a échoué. DB indique : %1 Creating new table failed. DB says: %1 La création d'une nouvelle table a échoué. DB indique : %1 Copying data to new table failed. DB says: %1 La copie des données dans une nouvelle table a échoué. DB indique : %1 Deleting old table failed. DB says: %1 La suppression d'une ancienne table a échoué. DB indique : %1 Error renaming table '%1' to '%2'. Message from database engine: %3 Erreur lors du changement de nom de la table %1 vers %2. Message du moteur de base de données : %3 could not get list of db objects: %1 La liste des objets de la base de données ne peut être obtenue : %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: La restauration de certains des objets associés à cette table a échoué. Cela est le plus souvent dû au changement du nom de certaines colonnes. Voici l'instruction SQL que vous pourrez corriger et exécuter manuellement : could not get list of databases: %1 n'a pas pu obtenir la liste des bases de données : %1 Error loading extension: %1 Erreur lors du chargement de l'extension %1 Error loading built-in extension: %1 could not get column information 170726 MVT Has to be checked in real context ne peut obtenir les informations sur la colonne Error setting pragma %1 to %2: %3 Erreur dans les paramètres des pragma %1 à %2 : %3 File not found. Fichier non trouvé. DbStructureModel Name Nom Object Objet Type Type Schema Schéma Database Base de données Browsables Consultables All Tout Temporary Temporaire Tables (%1) Tables (%1) Indices (%1) Index (%1) Views (%1) Vues (%1) Triggers (%1) Déclencheurs (%1) EditDialog Edit database cell Éditer le contenu d'une cellule Mode: Mode : This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Voici la liste des modes pris en charge par l'éditeur de cellules. Choisissez un mode d'affichage ou d'édition des données de la cellule courante. RTL Text Remark : there is not acronym in french for Right to Left Text (DàG : Droite à Gauche ?). If DçG is not correct, we should use the HTML dir parameter RTL Texte DàG Image Image JSON JSON XML XML Evaluation Évaluation Automatically adjust the editor mode to the loaded data type Ajuster automatiquement le mode éditeur au type de données chargé This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Ce bouton à cocher active ou désactive le changement automatique du mode éditeur. Lorsqu'une nouvelle cellule est sélectionnée ou de nouvelles données sont importées et que la commutation automatique est activée, le mode s'adapte au type de données détecté. Vous pouvez ensuite changer le mode éditeur manuellement. Si vous souhaitez conserver ce mode de commutation manuelle pendant que vous vous déplacez dans les cellules, éteignez le bouton. Auto-switch Auto-switch This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Cet éditeur Qt est utilisé pour les scripts écrits de droite à gauche. Ils ne sont pas pris en charge par l'éditeur de texte par défaut. La présence de caractères de droite à gauche est détectée et ce mode d'édition est automatiquement sélectionné. Identification of the cell currently in the editor Identification de la cellule dans l'éditeur Type and size of data currently in table Type et taille des données figurant actuellement dans la table Open preview dialog for printing the data currently stored in the cell Ouvrir la fenêtre de prévisualisation pour imprimer les données actuellement stockées dans la cellule Auto-format: pretty print on loading, compact on saving. Auto-format : formater au chargement, compacter à l'enregistrement. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Lorsqu'elle est activée, la fonction de formatage automatique met en forme les données lors du chargement, transforme le texte en lignes et ajoute des retraits pour une lisibilité maximale. Lors de la sauvegarde des données, la fonction de formatage automatique compacte les données en supprimant les fins des lignes et les espaces inutiles. Word Wrap Coupure des mots Wrap lines on word boundaries Coupe les lignes aux limites des mots Open in default application or browser Ouvrir dans l'application ou le navigateur par défaut Open in application Ouvrir dans l'application The value is interpreted as a file or URL and opened in the default application or web browser. La valeur est interprétée comme étant un fichier ou une URL. Elle sera ouverte dans l'application ou le navigateur web par défaut. Save file reference... Enregistrer la référence du fichier... Save reference to file Enregistre la référence au fichier Open in external application Ouvrir dans une application externe Autoformat Format automatique &Export... &Exporter... &Import... &Importer... Import from file Importer depuis un fichier Opens a file dialog used to import any kind of data to this database cell. Ouvre une boîte de dialogue pour importer n'importe quel type de données dans cette cellule de base de données. Export to file Exporter vers un fichier Opens a file dialog used to export the contents of this database cell to a file. Ouvrir la boîte de dialogue pour exporter le contenu de cette cellule de la base de données vers un fichier. Print... Imprimer... Ctrl+P Open preview dialog for printing displayed text Ouvrir un aperçu du texte avant son impression Copy Hex and ASCII Copier l'Hex et l'ASCII Copy selected hexadecimal and ASCII columns to the clipboard Copier les colonnes hexadécimales et ASCII sélectionnées dans le presse-papiers Ctrl+Shift+C Set as &NULL Définir comme &NULL Apply data to cell Appliquer les données à la cellule This button saves the changes performed in the cell editor to the database cell. Ce bouton permet d'enregistrer les modifications effectuées dans l'éditeur de cellule dans la cellule de base de données. Apply Appliquer Text Texte Binary Binaire Erases the contents of the cell Effacer le contenu de la cellule This area displays information about the data present in this database cell Cette zone affiche des informations à propos des données contenues dans la cellule de la base de données Choose a filename to export data Choisir un nom de fichier pour exporter les données Image data can't be viewed in this mode. L'image ne peut être affichée dans ce mode. Try switching to Image or Binary mode. Essayez de basculer vers le mode Image ou le mode Binaire. Binary data can't be viewed in this mode. Les données Binaires ne peuvent être affichées dans ce mode. Try switching to Binary mode. Essayez de basculer vers le mode Binaire. Type: NULL; Size: 0 bytes Type : NULL ; Taille : 0 octet Type: Text / Numeric; Size: %n character(s) Type : Texte / Numérique ; Taille : %n caractère Type : Texte / Numérique ; Taille : %n caractères Type: %1 Image; Size: %2x%3 pixel(s) Type : %1 Image ; Taille : %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type : JSON valide ; Taille : %n caractère Type : JSON valide ; Taille : %n caractères Type: Binary; Size: %n byte(s) Type : Binaire ; Taille : %n octet Type : Binaire ; Taille : %n octets Couldn't save file: %1. Le fichier %1 ne peut être sauvegardé. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Les données ont été enregistrées dans un fichier temporaire et ont été ouvertes avec l'application par défaut. Vous pouvez maintenant modifier le fichier et, lorsque vous êtes prêt, appliquer les nouvelles données enregistrées à la cellule ou annuler les modifications. Image files (%1) Fichiers image (%1) Binary files (*.bin) Fichiers Binaires (*.bin) Choose a file to import Choisir un fichier à importer The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Les modes de l'éditeur de texte vous permettent de modifier du texte brut, ainsi que des données JSON ou XML, avec mise en évidence de la syntaxe, formatage automatique et validation avant enregistrement. Les erreurs sont signalées par un trait de soulignement rouge. Dans le mode Évaluation, les expressions SQLite saisies sont évaluées et le résultat est appliqué à la cellule. Unsaved data in the cell editor Données non enregistrées dans l'éditeur de cellules The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? L'éditeur de cellules contient des données qui n'ont pas encore été appliquées à la base de données. Voulez-vous appliquer les données modifiées à la ligne=%1, colonne=%2 ? Editing row=%1, column=%2 Modification de la ligne=%1, colonne=%2 No cell active. Pas de cellule active. %1 Image %1 Image Invalid data for this mode Les données sont invalides pour ce mode The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? La cellule contient des données %1 invalides. Raison : %2. Voulez-vous vraiment l'appliquer à la cellule ? EditIndexDialog &Name &Nom Order Ordre &Table &Table Edit Index Schema Éditer le schéma d'index &Unique &Unique For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Pour restreindre l'index à un sous-ensemble de la table, vous pouvez spécifier une clause WHERE ici. Elle sélectionnera le sous-ensemble de la table qui sera indexé Partial inde&x clause Clause d'inde&x partiel Colu&mns &Colonnes Table column Colonne de table Type Type Add a new expression column to the index. Expression columns contain SQL expression rather than column names. 170726 MVT Has to be checked in real context Ajouter une nouvelle expression de colonne à l'index. Les expressions de colonnes contiennent des expressions SQL plutôt que des noms de colonnes. Index column Colonne d'index Deleting the old index failed: %1 La suppression de l'ancien index a échoué : %1 Creating the index failed: %1 La création de l'index a échoué : %1 EditTableDialog Edit table definition Éditer la définition de la table Table Table Advanced Avancé Without Rowid Sans RowId Fields Champs Database sche&ma Sché&ma de la base de données Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Sur le conflit Strict Stricte When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Lorsque l'option strict est activée, SQLite respecte les types de données de chaque colonne lors de la mise à jour ou de l'insertion de données. Add Ajouter Remove Supprimer Move to top Monter au début Move up Monter Move down Descendre Move to bottom Descendre à la fin Name Nom Type Type NN NN Not null Non-Null PK CP <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> Clé primaire</p></body></html> AI IA Autoincrement Incrément automatique U U Unique Unique Default Défaut Default value Valeur par défaut Check Vérifier Check constraint Vérifier les contraintes Collation Séquence Foreign Key Clé étrangère <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> Clé étrangère</p></body></html> Index Constraints Contraintes d'index Add constraint Ajouter une contrainte Remove constraint Supprimer une contrainte Columns Colonnes SQL SQL Foreign Keys Clés étrangères References Références Check Constraints Vérifier les contraintes <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Attention : </span>Il y a quelque chose dans la définition de cette table que notre analyseur syntaxique n'a pas complètement compris. La modification et l'enregistrement de cette table peuvent créer des problèmes.</p></body></html> Primary Key Clé primaire Add a primary key constraint Ajoute une clé primaire à la contrainte Add a unique constraint Ajoute une contrainte unique Error creating table. Message from database engine: %1 Erreur lors de la création de la table. Message du moteur de la base de données : %1 There already is a field with that name. Please rename it first or choose a different name for this field. Il existe déjà un champ avec ce nom. Veuillez le renommer avant ou choisir un autre nom pour ce champ. There can only be one primary key for each table. Please modify the existing primary key instead. Une table ne peut avoir qu'une seule clé primaire. Veuillez modifier la clé primaire existante à la place. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Cette colonne est référencée dans une clé étrangère dans la table %1. Son nom ne peut être changé. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Il existe au moins un enregistrement avec ce champ autorisant des valeurs nulles (NULL). Il est donc impossible de définir cet indicateur. Veuillez modifier les données de la table au préalable. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Il existe au moins un enregistrement avec une valeur qui n'est pas un nombre entier dans ce champ. Il est donc impossible de définir l'indicateur AI (Incrément automatique) sur ce champ. Veuillez modifier les données de la table au préalable. Column '%1' has duplicate data. La colonne %1 a des des données en double. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Il est donc impossible d'activer l'indicateur "Unique". Veuillez supprimer les données en double, cela vous permettra d'activer l'indicateur "Unique". Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Êtes-vous sûr de vouloir supprimer le champ "%1" ? Toutes les données contenues dans ce champ seront perdues. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Veuillez ajouter un champ ayant les caractéristiques suivant avant de positionner l'option Sans RowId : - Défini comme clé primaire ; - Incrément automatique désactivé Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set Veuillez ajouter un champ qui répond aux critères suivants avant de définir l'action sur le conflit : - Indicateur de clé primaire activé ExportDataDialog Export data as CSV Exporter au format CSV Tab&le(s) &Table(s) Colu&mn names in first line Nom des &col. en 1ère ligne Fie&ld separator &Séparateur de champ , , ; ; Tab Tabulation | | Other Autre &Quote character T&ype de guillemet " " ' ' New line characters Saut de ligne Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print "Indenter" is more clear to me than the previous "Formater" Indenter Could not open output file: %1 Le fichier de destination %1 ne peut être ouvert Choose a filename to export data Choisir un nom de fichier pour exporter les données Export data as JSON Exporter au format JSON exporting CSV Exporter au format CSV Error while writing the file '%1': %2 Erreur lors de l'écriture du fichier %1 : %2 exporting JSON Exporter au format JSON Please select at least 1 table. Veuillez sélectionner au moins une table. Choose a directory Choisir un répertoire Export completed. Export terminé. Export finished with errors. L'export s'est terminé avec des erreurs. ExportSqlDialog Export SQL... Same as defined in English... But converted to uniformize with other dialog boxes. Exporter au format SQL... Tab&le(s) Tab&le(s) Select All Sélectionner tout Deselect All Désélectionner tout &Options &Options Keep column names in INSERT INTO Conserver les noms des colonnes dans INSERT INTO Multiple rows (VALUES) per INSERT statement Plusieurs enregistrements (VALUES) par INSERT Export everything Exporter tout Export schema only Exporter uniquement le schéma Export data only Exporter uniquement les données Keep original CREATE statements Conserver les déclarations CREATE d'origine Keep old schema (CREATE TABLE IF NOT EXISTS) Conserver l'ancien schéma (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Écraser l'ancien schéma (DROP TABLE, puis CREATE TABLE) Please select at least one table. Veuillez sélectionner au moins une table. Choose a filename to export Choisir un nom de fichier pour l'export Export completed. Export terminé. Export cancelled or failed. L'export a été annulé ou a échoué. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Rechercher... Find and Replace... Chercher et remplacer... Print... Imprimer... ExtendedTableWidget Use as Exact Filter Utiliser comme filtre exact Containing Contenant Not containing Ne contenant pas Not equal to Différent de Greater than Plus grand que Less than Plus petit que Greater or equal Plus grand ou égal à Less or equal Plus petit ou égal à Between this and... Entre ceci et... Regular expression Expression régulière Edit Conditional Formats... Éditer les formats conditionnels... Set to NULL Définir comme NULL Cut Couper Copy Copier Copy with Headers Copier avec les entêtes Copy as SQL Copier comme du SQL Paste Coller Print... Imprimer... Use in Filter Expression Utiliser dans l'expression du filtre Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? Le contenu du presse-papier est plus grand que la plage sélectionnée. Voulez-vous poursuivre l'insertion malgré tout ? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>Toutes les données n'ont pas été chargées. <b>Voulez-vous charger toutes les données avant de sélectionner toutes les lignes ? </b><p><p>Répondre <b>Non</b> signifie qu'aucune autre donnée ne sera chargée et que la sélection ne sera pas effectuée.<br/>Répondre <b>Oui</b> peut prendre un certain temps pendant le chargement des données mais la sélection sera complète.</p>Avertissement : Le chargement de toutes les données peut nécessiter une grande quantité de mémoire pour les grandes tables. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. La sélection ne peut être à NULL. La colonne %1 à une contrainte NOT NULL. FileExtensionManager File Extension Manager Gestionnaire d'extension de fichier &Up &Monter &Down &Descendre &Add &Ajouter &Remove &Supprimer Description Description Extensions Extensions *.extension *.extension FilterLineEdit Filter Filtre These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Ces champs de saisie vous permettent d'effectuer des filtres rapides dans le tableau actuellement sélectionné. Par défaut, les lignes contenant le texte de saisie sont filtrées. Les opérateurs suivants sont également pris en charge : % Joker (métacaractère) > Supérieur à < Inférieur à >= Supérieur ou égal à <= Inférieur ou égal à = Égal à : correspondance exacte <> Différent de: correspondance inverse exacte x~y Fourchette : valeurs entre x et y /regexp/ Valeurs correspondant à l'expression régulière Clear All Conditional Formats Effacer tous les formats conditionnels Use for Conditional Format Utiliser pour le format conditionnel Edit Conditional Formats... Éditer un format conditionnel... Set Filter Expression Définir l'expression du filtre What's This? Qu'est-ce que c'est ? Is NULL Est NULL Is not NULL Est non NULL Is empty Est vide Is not empty Est non vide Not containing... Ne contenant pas... Equal to... Égal à... Not equal to... Différent de... Greater than... Plus grand que... Less than... Plus petit que... Greater or equal... Plus grand ou égal à... Less or equal... Plus petit ou égal à... In range... Peut être aussi traduit par "dans la plage..." ou "Entre..." Entre les valeurs... Regular expression... Expression régulière... FindReplaceDialog Find and Replace Chercher et remplacer Fi&nd text: &Rechercher : Re&place with: Re&mplacer avec : Match &exact case &Expression exacte Match &only whole words M&ots entiers uniquement When enabled, the search continues from the other end when it reaches one end of the page Lorsque la Recherche circulaire est activée, la recherche recommence au début une fois la fin de la page atteinte &Wrap around Recherche &circulaire When set, the search goes backwards from cursor position, otherwise it goes forward Lorsqu'elle est activée, la recherche s'effectue en remontant à partir de la position du curseur, sinon elle se fait en descendant Search &backwards Rechercher vers le &haut <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>Lorsque cette case est cochée, la recherche ne se fait que dans la sélection actuelle.</p></body></html> &Selection only &Sélection uniquement <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> La version française de https://en.wikibooks.org/wiki/Regular_Expressions n'existe pas <html><head/><body><p>Lorsqu'elle est cochée, le motif à trouver est interprété comme une expression régulière UNIX. Voir <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Use regular e&xpressions Utiliser les e&xpressions régulières Find the next occurrence from the cursor position and in the direction set by "Search backwards" Trouver l'occurrence suivante à partir de la position du curseur et dans la direction définie par "Rechercher vers le haut" &Find Next &Suivant F3 &Replace Rem&placer Highlight all the occurrences of the text in the page Surligner toutes les occurrences du texte dans la page F&ind All Rechercher &tout Replace all the occurrences of the text in the page Remplace toutes les occurrences du texte dans la page Replace &All Remplacer to&ut The searched text was not found Le texte recherché n'a pas été trouvé The searched text was not found. Le texte recherché n'a pas été trouvé. The searched text was found one time. Le texte recherché a été trouvé une fois. The searched text was found %1 times. Le texte recherché a été trouvé %1 fois. The searched text was replaced one time. Le texte recherché a été remplacé une fois. The searched text was replaced %1 times. Le texte recherché a été remplacé %1 fois. ForeignKeyEditor &Reset &Réinitialiser Foreign key clauses (ON UPDATE, ON DELETE etc.) Clauses de clé étrangère (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Visionneuse d'images Reset the scaling to match the original size of the image. Réinitialise la mise à l'échelle pour qu'elle corresponde à la taille originale de l'image. Set the scaling to match the size of the viewport. Régler l'échelle pour qu'elle corresponde à la taille de la fenêtre de visualisation. Print... Imprimer... Open preview dialog for printing displayed image Ouvrir un aperçu de l'image pour son impression Ctrl+P Ctrl+P ImportCsvDialog Import CSV file Importer un fichier CSV Table na&me No&m de la table &Column names in first line Nom des &col. en 1ère ligne Field &separator &Séparateur de champ , , ; ; Tab Tabulation | | Other Autre &Quote character T&ype de guillemet Other (printable) Autre (imprimable) Other (code) Autre (code) " " ' ' &Encoding &Encodage UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? Réduire les champs ? Separate tables Tables distinctes Advanced Avancé When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Lorsque vous importez une valeur vide du fichier CSV dans une table existante avec une valeur par défaut pour cette colonne, cette valeur par défaut est insérée. Activez cette option pour insérer une valeur vide à la place. Ignore default &values Ignorer les &valeurs par défaut Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Activez cette option pour arrêter l'importation lorsque vous essayez d'importer une valeur vide dans une colonne NON NULL sans valeur par défaut. Fail on missing values Erreur sur les valeurs manquantes Disable data type detection Désactiver la détection du type de données Disable the automatic data type detection when creating a new table. Désactive la détection automatique du type de données lors de la création d'une nouvelle table. Use local number conventions Utiliser les conventions locales pour les nombres Use decimal and thousands separators according to the system locale. Utiliser les séparateurs décimaux et de milliers en fonction des paramètres locaux du système. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Lors de l'importation dans une table existante possédant une clé primaire, des contraintes uniques ou un index unique, il y a un risque de conflit. Cette option vous permet de sélectionner une stratégie pour ce cas : Par défaut, l'importation est interrompue et annulée, mais vous pouvez également choisir d'ignorer et de ne pas importer les lignes en conflit ou de remplacer la ligne existante dans la table. Abort import Abandonner l'import Ignore row Ignorer l'enregistrement Replace existing row Remplacer l'enregistrement existant Conflict strategy En conflit avec la stratégie Deselect All Désélectionner tout Match Similar 170726 MVT Has to be checked in real context or after explanation of this function. I suppose this function permits, with data names on the first line to "prefill a corresponding names" in an existing object ? Appairer Select All Sélectionner tout There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Il existe déjà une table nommée '%1' et une importation dans une table existante n'est possible que si le nombre de colonnes correspond. There is already a table named '%1'. Do you want to import the data into it? Il existe déjà une table appelée "%1". Voulez-vous y importer les données ? Creating restore point failed: %1 La création du point de restauration a échoué : %1 Creating the table failed: %1 La création de la table a échoué %1 importing CSV Importer au format CSV Could not prepare INSERT statement: %1 Impossible de préparer l'instruction INSERT : %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Fin de fichier inattendue. Veuillez vous assurer que vous avez configuré les bons guillemets et que le fichier n'est pas défectueux. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. L'importation du fichier'%1' a pris %2 ms. %3 ms ont été utilisés par la fonction enregistrement. Inserting row failed: %1 L'insertion de l'enregistrement a échoué : %1 MainWindow toolBar1 Barre d'outils1 Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Attention : ce pragma n'est pas lisible et cette valeur a été déduite. Écrire le pragma pourrait écraser un LIKE redéfini fourni par une extension SQLite. Too&ls &Outils Edit Database &Cell Éditer le contenu d'une &cellule Opens the SQLCipher FAQ in a browser window Ouvre la FAQ de SQLCipher dans la fenêtre d'un navigateur Export one or more table(s) to a JSON file Exporter une ou plusieurs tables vers un fichier JSON DB Browser for SQLite DB Browser pour SQLite &File &Fichier &Import &Importer &Export &Exporter &Edit É&dition &View &Vue &Help &Aide User Utilisateur Application Application This button clears the contents of the SQL logs Ce bouton supprime le contenu des logs SQL &Clear &Effacer &New Database... &Nouvelle base de données... Create a new database file Créer une nouvelle base de données This option is used to create a new database file. Cette option est utilisée pour créer un nouveau fichier de base de données. Ctrl+N &Open Database... &Ouvrir une base de données... Open an existing database file Ouvre une base de données existante This option is used to open an existing database file. Cette option est utilisée pour ouvrir une base de données existante. Ctrl+O &Close Database &Fermer la base de données This button closes the connection to the currently open database file Ce bouton ferme la connexion à la base de données actuellement ouverte Ctrl+W &Revert Changes &Annuler les modifications Revert database to last saved state Revenir à la dernière version sauvegardée de la base de données This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Cette option permet de restaurer la base de données dans l'état de sa dernière sauvegarde. Tous les changements effectués depuis cette dernière sauvegarde seront perdus. &Undo Ann&uler Undo last change to the database Annuler la dernière modification apportée à la base de données This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Cette action annule la dernière modification apportée à la base de données dans le navigateur de bases de données ou dans l'onglet Exécuter le SQL. Il n'est pas possible d'annuler à nouveau. &Write Changes Enregistrer les &modifications Write changes to the database file Enregistrer les modifications dans la base de données This option is used to save changes to the database file. Cette option est utilisée pour enregistrer les modifications dans la base de données. Ctrl+S Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Ouvrir l'assistant de modification d'une table où il sera possible de renommer une table existante. Il est aussi possible d'ajouter ou de supprimer des champs de la table, tout comme modifier le nom des champs et leur type. Execute all/selected SQL Exécuter tout ou seulement le SQL sélectionné This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Ce bouton lance l'exécution des commandes SQL actuellement sélectionnées. Si aucun texte n'est sélectionné, toutes les commandes SQL seront exécutées. Ctrl+Shift+T Ctrl+Maj+T Execute line Exécuter la ligne &Wiki &Wiki F1 Bug &Report... &Rapport d'erreur... Feature Re&quest... &Demande de fonctionnalités... Web&site &Site Internet &Donate on Patreon... Faire une &donation sur Patreon... &Save Project Enre&gistrer le projet Open &Project... Ouvrir un &projet... Open &Project Ouvrir un &projet &Attach Database... Attac&her une base de données... Add another database file to the current database connection Ajouter un autre fichier de base de données à la connexion de la base de données en cours This button lets you add another database file to the current database connection Ce bouton vous permet d'ajouter un autre fichier de base de données à la connexion de la base de données en cours &Set Encryption... Chi&ffrer... SQLCipher &FAQ &FAQ SQLCipher Table(&s) to JSON... Table(&s) vers JSON... Open Data&base Read Only... Ouvrir une base de données en &lecture seule... Ctrl+Shift+O Save results Enregistrer les résultats Save the results view Enregistrer la vue des résultats This button lets you save the results of the last executed query Ce bouton vous permet d'enregistrer les résultats de la dernière requête exécutée Find text in SQL editor Rechercher du texte dans l'éditeur SQL Find Rechercher This button opens the search bar of the editor Ce bouton ouvre la barre de recherche dans l'éditeur Ctrl+F Find or replace text in SQL editor Rechercher ou remplacer du texte dans l'éditeur SQL Find or replace Chercher et remplacer This button opens the find/replace dialog for the current editor tab Ce bouton ouvre la boîte de dialogue Rechercher/Remplacer pour l'onglet en cours de l'éditeur Ctrl+H Export to &CSV Exporter au format &CSV Export to &JSON Exporter au format &JSON Save as &view Enregistrer comme une &vue Save as view Enregistrer comme une vue &Open Database &Ouvrir une base de données Drag && Drop SELECT Query Glisser && Déposer la requête SELECT When dragging fields from the same table or a single table, drop a SELECT query into the editor Lorsque vous faites glisser des champs d'une même table ou d'une table unique, déposez une requête SELECT dans l'éditeur Browse Table Parcourir la table Ctrl+Shift+W Ctrl+Maj+W Table from CSV data in Clipboard... Table depuis les données CSV du Presse-papiers... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Cette opération traite le contenu actuel du presse-papiers comme un fichier CSV et ouvre le même assistant d'importation que celui utilisé pour importer des données CSV à partir d'un fichier. Show &Row Counts Afficher le nomb&re de lignes This shows the number of rows for each table and view in the database. Indique le nombre de lignes pour chaque table et vue de la base de données. Save Database &As... Enregistrer la b&ase de données sous... Save the current database as a different file Enregistrer la base de données en cours dans un autre fichier Refresh Rafraîchir Reload the database structure Recharger la structure de la base de données Shows or hides the Project toolbar. Afficher ou masquer la barre d'outil Projet. Extra DB Toolbar Extra DB Toolbar This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Ce bouton vous permet d'enregistrer tous les paramètres associés à la base de données ouverte dans un fichier de projet DB Browser pour SQLite &Database Structure This has to be equal to the tab title in all the main tabs Structure de la base de &données &Browse Data This has to be equal to the tab title in all the main tabs &Parcourir les données Edit P&ragmas This has to be equal to the tab title in all the main tabs Éditer les p&ragmas E&xecute SQL This has to be equal to the tab title in all the main tabs E&xécuter le SQL &Recent Files Fichiers &récents &New Database &Nouvelle base de données This button lets you open a DB Browser for SQLite project file Ce bouton vous permet d'ouvrir un fichier de projet DB Browser pour SQLite New In-&Memory Database Nouvelle base de données en &mémoire Drag && Drop Qualified Names Glisser && Déposer les noms qualifiés Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Utilisez des noms qualifiés (par ex. "Table", "Champ") lorsque vous faites glisser les objets et pour les déposez dans l'éditeur Drag && Drop Enquoted Names Glisser && Déposer les noms indiqués Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Utiliser les identificateurs par défaut (par ex. "Table1") lors du glisser-déposer des objets dans l'éditeur &Integrity Check Vérifier l'&intégrité Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. Exécute le pragma integrity_check sur la base de données ouverte et retourne les résultats dans l'onglet Exécuter le SQL. Ce pragma effectue un contrôle d'intégrité de l'ensemble de la base de données. &Foreign-Key Check Vérifier les clés &étrangères Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Exécute le pragma foreign_key_check_check sur la base de données ouverte et retourne les résultats dans l'onglet Exécuter SQL &Quick Integrity Check Vérification &rapide de l'intégrité Run a quick integrity check over the open DB Effectuer un rapide contrôle d'intégrité sur la base de données ouverte Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. Exécute le pragma quick_check sur la base de données ouverte et retourne les résultats dans l'onglet Exécuter SQL. Cette commande effectue la plupart des vérifications de PRAGMA integrity_check mais s'exécute beaucoup plus rapidement. &Optimize &Optimiser Attempt to optimize the database Tente d'optimiser la base de données Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Exécute le pragma d'optimisation sur la base de données ouverte. Ce pragma pourrait effectuer des optimisations qui amélioreront la performance des requêtes futures. Print Imprimer Print text from current SQL editor tab Imprime le contenu de l'onglet en cours de l'éditeur SQL [Ctrl+P] Open a dialog for printing the text in the current SQL editor tab Ouvre une boite de dialogue pour imprimer le contenu de l'onglet en cours de l'éditeur SQL Print the structure of the opened database Imprime la structure de la base de données ouverte Open a dialog for printing the structure of the opened database Ouvre une boite de dialogue pour imprimer la structure de la base de données ouverte &Save Project As... Enr&egistrer le projet sous... Save the project in a file selected in a dialog Enregistrer le projet dans un fichier sélectionné dans une boite de dialogue Save A&ll Enregistrer &tout Save DB file, project file and opened SQL files Enregistre la base de données, le fichier projet et les fichiers SQL ouverts Ctrl+Shift+S Close Pro&ject Fermer le pro&jet Close project and database files and return to the initial state Fermer les fichiers du projet et de la base de données et revenir à l'état initial Ctrl+Shift+F4 Ctrl+Maj+F4 Detach Database Détacher une base de données Detach database file attached to the current database connection Détacher le fichier de base de données attaché à la connexion actuelle à la base de données Compact the database file, removing space wasted by deleted records Compacter la base de donnée, récupérer l'espace perdu par les enregistrements supprimés Compact the database file, removing space wasted by deleted records. Compacter la base de donnée, récupérer l'espace perdu par les enregistrements supprimés. E&xit &Quitter Ctrl+Q Import data from an .sql dump text file into a new or existing database. Importer les données depuis un fichier SQL résultant d'un vidage (sql dump) dans une nouvelle base de données ou une base existante. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Cette option vous permet d'importer un fichier SQL de vidage d'une base de données (SQL dump) dans une nouvelle base de données ou une base existante. Ce fichier peut être créé par la plupart des moteurs de base de données, y compris MySQL et PostgreSQL. Open a wizard that lets you import data from a comma separated text file into a database table. Ouvrir un assistant vous permettant d'importer des données dans une table de la base de données à partir d'un fichier texte séparé par des virgules (csv). Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Ouvre un assistant vous permettant d'importer des données dans une table de la base de données à partir d'un fichier texte séparé par des virgules (csv). Les fichiers CSV peuvent être créés par la plupart des outils de gestion de base de données et les tableurs. Export a database to a .sql dump text file. Exporter la base de données vers un fichier de vidage SQL (SQL dump) au format texte. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Exporter la base de données vers un fichier de vidage SQL (SQL dump) au format texte. Ce fichier (SQL dump) contient toutes les informations nécessaires pour recréer une base de données par la plupart des moteurs de base de données, y compris MySQL et PostgreSQL. Export a database table as a comma separated text file. Exporter la table vers un fichier texte séparé par des virgules (CSV). Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Exporter la table vers un fichier texte séparé par des virgules (CSV), prêt à être importé dans une autre base de données ou un tableur. &Create Table... &Créer une table... Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Ouvrir l'assistant de création d'une table dans lequel il sera possible de définir les noms et les champs d'une nouvelle table dans la base de données &Delete Table... &Supprimer la table... Open the Delete Table wizard, where you can select a database table to be dropped. Ouvrir l'assistant de suppression d'une table avec lequel vous pourrez sélectionner la table à supprimer. &Modify Table... &Modifier la table... Open the Create Index wizard, where it is possible to define a new index on an existing database table. Ouvrir l'assistant de création d'un index avec lequel il sera possible de définir un nouvel index dans une table préexistante de la base de données. &Preferences... &Préférences... Open the preferences window. Ouvrir la fenêtre des préférences. &DB Toolbar &Barre d'outils BDD Shows or hides the Database toolbar. Affiche ou masque la barre d'outils Base de données. Shift+F1 &Recently opened Ouvert &récemment Ctrl+T This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Ceci est la structure de la base de données ouverte. Vous pouvez faire glisser plusieurs noms d'objets de la colonne Nom et les déposer dans l'éditeur SQL et vous pouvez ajuster les propriétés des noms déposés en utilisant le menu contextuel. Cela pourrait vous aider à composer des instructions SQL. Vous pouvez faire glisser les instructions SQL de la colonne Schéma et les déposer dans l'éditeur SQL ou dans d'autres applications. Project Toolbar Barre d'outil Projet Extra DB toolbar Extra DB Toolbar Close the current database file Fermer la base de données en cours Ctrl+F4 Compact &Database... Compacter la base de &données... &About À &propos This button opens a new tab for the SQL editor Ce bouton ouvre un nouvel onglet dans l'éditeur SQL &Execute SQL &Exécuter le SQL Save the current session to a file Enregistrer la session courante dans un fichier Load a working session from a file Charger une session de travail depuis un fichier This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Ceci est la structure de la base de données ouverte. Vous pouvez faire glisser les instructions SQL d'une ligne d'objet et les déposer dans d'autres applications ou dans une autre instance de 'DB Browser pour SQLite'. Error Log Journal des erreurs Un/comment block of SQL code Dé/commenter un bloc de code SQL Un/comment block Dé/commenter un bloc Comment or uncomment current line or selected block of code Commenter ou décommenter la ligne actuelle ou le bloc de code sélectionné Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Commenter ou décommenter les lignes sélectionnées ou la ligne en cours, lorsqu'il n'y a pas de sélection. Tout le bloc est basculé en fonction de la première ligne. Ctrl+/ Stop SQL execution Arrête l'exécution du SQL Stop execution Arrêter l'exécution Stop the currently running SQL script Arrête le script SQL en cours d'exécution DB Toolbar Barre d'outils BDD SQL &Log &Journal SQL Show S&QL submitted by A&fficher le SQL soumis par This panel lets you examine a log of all SQL commands issued by the application or by yourself Ce panneau vous permet d'examiner un journal de toutes les commandes SQL émises par l'application ou par vous-même &Plot Gra&phique DB Sche&ma DB Sche&ma &Remote Serveur &distant &Database from SQL file... &Base de données à partir du fichier SQL... &Table from CSV file... &Table depuis un fichier CSV... &Database to SQL file... Base de &données vers un fichier SQL... &Table(s) as CSV file... &Table vers un fichier CSV... Create &Index... Créer un &index... W&hat's This? &Qu'est-ce que c'est ? New &tab Nouvel ongle&t Open SQL file(s) Ouvrir un fichier SQL This button opens files containing SQL statements and loads them in new editor tabs Ce bouton ouvre un fichier contenant des instructions SQL et le charge dans un nouvel onglet de l'éditeur Save SQL file Enregistrer le fichier SQL &Load Extension... Charger l'&extension... Execute current line Exécuter la ligne courante (Maj+F5) This button executes the SQL statement present in the current editor line Ce bouton exécute l'instruction SQL présente dans la ligne courante de l'éditeur Shift+F5 Sa&ve Project Enre&gistrer le projet Save SQL file as Enregistrer le fichier SQL comme This button saves the content of the current SQL editor tab to a file Ce bouton enregistre le contenu de l'onglet actuel de l'éditeur SQL dans un fichier &Browse Table &Parcourir la table Copy Create statement Copier l'instruction CREATE Copy the CREATE statement of the item to the clipboard Copie l'instruction CREATE de cet item dans le presse-papier Open an existing database file in read only mode Ouvrir une base de données existante en lecture seule Ctrl+E Export as CSV file Exporter les données au format CSV Export table as comma separated values file Exporter la table vers un fichier texte séparé par des virgules (CSV) Ctrl+L Ctrl+P Database encoding Encodage de la base de données Choose a database file Choisir une base de données Ctrl+Return Ctrl+D Ctrl+I Reset Window Layout Rétablir la disposition des fenêtres The database is currently busy. La base de données est actuellement occupée. Click here to interrupt the currently running query. Cliquez ici pour interrompre la requête en cours. Encrypted Chiffré Database is encrypted using SQLCipher La base de données a été chiffrée avec SQLCipher Read only Lecture seule Database file is read only. Editing the database is disabled. La base de données est ouverte en lecture seule. Il n'est pas possible de la modifier. Could not open database file. Reason: %1 La base de données ne peut être ouverte. Motif : %1 Choose a filename to save under Choisir un nom de fichier pour enregistrer sous Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Erreur lors de l'enregistrement de la base de données. Les changements n'ont pas tous été sauvegardés. Vous devez corriger au préalable l'erreur suivante : %1 Do you want to save the changes made to SQL tabs in the project file '%1'? Voulez-vous enregistrer les modifications apportées aux onglets SQL dans le fichier du projet '%1' ? A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Une nouvelle version de DB Browser pour SQLite est disponible (%1.%2.%3).<br/><br/>Vous pouvez la télécharger sur <a href='%4'>%4</a>. DB Browser for SQLite project file (*.sqbpro) Fichier de projet DB Browser pour SQLite (*.sqbpro) Error checking foreign keys after table modification. The changes will be reverted. Erreur de vérification des clés étrangères après modification de la table. Les modifications seront annulées. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Cette table n'a pas passé avec succès un contrôle de clé étrangère.<br/>Vous devez exécuter l'Outil | Contrôle des clés étrangères' et corriger les problèmes rapportés. Execution finished with errors. L'exécution s'est terminée avec des erreurs. Execution finished without errors. L'exécution s'est terminée sans erreur. Are you sure you want to undo all changes made to the database file '%1' since the last save? Êtes-vous sûr de vouloir annuler tous les changements effectués dans la base de données %1 depuis la dernière sauvegarde ? Choose a file to import Choisir un fichier à importer Text files(*.sql *.txt);;All files(*) Fichiers texte (*.sql *.txt);;Tous les fichiers(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Voulez vous créer une nouvelle base de donnée pour gérer les données importées ? Si vous répondez non, nous essaierons d'importer les données du fichier SQL dans la base de données courante. Ctrl+Tab Ctrl+Tab Ctrl+Shift+Tab Ctrl+Maj+Tab Clear List Effacer la liste Window Layout Disposition des fenêtres Simplify Window Layout Simplifier la disposition des fenêtres Alt+Shift+0 Maj+Alt+0 Dock Windows at Bottom Ancrer les fenêtres en bas Dock Windows at Left Side Ancrer les fenêtres à gauche Dock Windows at Top Ancrer les fenêtres en haut You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Des traitements SQL sont en cours d'exécution. Fermer la base de données maintenant arrêtera ces traitements. Cela risque de laisser la base de données dans un état incohérent. Êtes-vous sûr de vouloir fermer la base de données ? Do you want to save the changes made to the project file '%1'? Voulez-vous enregistrer les changements effectués dans le fichier projet '%1' ? File %1 already exists. Please choose a different name. Le fichier %1 existe déjà. Veuillez choisir un nom de fichier différent. Error importing data: %1 Erreur lors de l'import des données : %1 Import completed. Import terminé. Delete View Supprimer la vue Delete Trigger Supprimer le déclencheur Delete Index Supprimer l'index Delete Table Supprimer la table Setting PRAGMA values will commit your current transaction. Are you sure? Paramétrer les valeurs du PRAGMA enregistrera les actions de votre transaction courante. Êtes-vous sûr ? In-Memory database Base de données en mémoire Automatically load the last opened DB file at startup Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Êtes-vous sûr de vouloir supprimer la table %1 ? Toutes les données de la table seront perdues. Are you sure you want to delete the view '%1'? Êtes-vous sûr de vouloir supprimer la vue %1 ? Are you sure you want to delete the trigger '%1'? Êtes-vous sûr de vouloir supprimer le déclencheur %1 ? Are you sure you want to delete the index '%1'? Êtes-vous sûr de vouloir supprimer l'index %1 ? Error: could not delete the table. Erreur : suppression de la table impossible. Error: could not delete the view. Erreur : suppression de la vue impossible. Error: could not delete the trigger. Erreur : suppression du déclencheur impossible. Error: could not delete the index. Erreur : suppression de l'index impossible. Message from database engine: %1 Message depuis le moteur de la base de données : %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? La modification de la table nécessite d'enregistrer toutes les modifications en attente maintenant. Êtes-vous sûr de vouloir enregistrer la base de données ? Edit View %1 Éditer la vue %1 Edit Trigger %1 Éditer le déclencheur %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. Vous avez des instructions SQL en cours d'exécution. Voulez-vous les arrêter afin d'exécuter les instructions en cours à la place ? Cela pourrait laisser la base de données dans un état incohérent. -- EXECUTING SELECTION IN '%1' -- -- EXÉCUTION DE LA SELECTION DANS '%1' -- -- EXECUTING LINE IN '%1' -- -- EXÉCUTION DE LA LIGNE DANS '%1' -- -- EXECUTING ALL IN '%1' -- -- EXÉCUTER TOUT DANS '%1' -- At line %1: À la ligne %1 : Result: %1 Résultat : %1 Result: %2 Résultat : %2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Le réglage des valeurs PRAGMA ou du "vacuuming" validera votre transaction en cours. Êtes-vous sûr ? Opened '%1' in read-only mode from recent file list Ouverture de '%1' en lecture seule depuis la liste des fichiers récents Opened '%1' from recent file list Ouverture de '%1' depuis la liste des fichiers récents Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Sélectionnez l'action à appliquer au fichier déposé.<br>Note : seule l'action "Importer" permet de traiter plus d'un fichier. Sélectionnez l'action à appliquer aux fichiers déposés.<br>Note : seule l'action "Importer" permet de traiter plus d'un fichier. The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? Les traitements de l'onglet '%1' sont toujours en cours d'exécution. La fermeture de l'onglet arrêtera l'exécution. Cela pourrait laisser la base de données dans un état incohérent. Êtes-vous sûr de vouloir fermer l'onglet ? This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Ce fichier de projet utilise un ancien format de fichier car il a été créé à l'aide de DB Browser for SQLite version 3.10 ou inférieure. Le chargement de ce format de fichier n'est plus entièrement pris en charge. Si vous souhaitez le charger complètement, veuillez utiliser DB Browser for SQLite version 3.12 pour le convertir au nouveau format de fichier. Project saved to file '%1' Projet enregistré dans le fichier '%1' Yes. Don't ask again Oui. Ne plus demander This action will open a new SQL tab with the following statements for you to edit and run: Need to verify if following statements ore shown bellow ou above or on the open action Cette action ouvrira un nouvel onglet SQL avec les instructions suivantes que vous pourrez modifier et exécuter : Rename Tab Renommer l'onglet Duplicate Tab Dupliquer l'onglet Close Tab Fermer l'onglet Opening '%1'... Ouverture de '%1'... There was an error opening '%1'... Il y a eu une erreur lors de l'ouverture de '%1'... Value is not a valid URL or filename: %1 Le valeur n'est pas une URL valide ou un nom de fichier : %1 %1 rows returned in %2ms %1 enregistrements ramenés en %2ms Ctrl+Alt+0 Ctrl+Alt+0 Ctrl+Alt+W Ctrl+Alt+W Choose a database file to save under Choisissez un fichier de base de donnés pour enregistrer sous Error while saving the database to the new file. Erreur lors de l'enregistrement de la base de données dans le nouveau fichier. Choose text files Choisir des fichiers texte Import completed. Some foreign key constraints are violated. Please fix them before saving. Importation terminée. Certaines contraintes clés étrangères sont violées. Veuillez les corriger avant de les enregistrer. Modify View Modifier la vue Modify Trigger Modifier le déclencheur Modify Index Modifier l'index Modify Table Modifier la table &%1 %2%3 &%1 %2%3 (read only) (lecture seule) Open Database or Project Ouvrir une base de données ou un projet Attach Database... Attacher une base de données... Import CSV file(s)... Importer un ou des fichiers CSV... Do you want to save the changes made to SQL tabs in a new project file? Voulez-vous enregistrer les changements effectués dans l'onglet SQL dans un nouveau fichier projet ? Do you want to save the changes made to the SQL file %1? Voulez-vous enregistrer les changements effectués dans le fichier SQL %1 ? Select SQL file to open Sélectionner un fichier SQL à ouvrir Select file name Sélectionner un nom de fichier Select extension file Sélectionner une extension de fichier Extension successfully loaded. L'extension a été chargée avec succès. Error loading extension: %1 Erreur lors du chargement de l'extension %1 Could not find resource file: %1 Le fichier de ressources %1 ne peut être ouvert Don't show again Ne plus afficher New version available. Une nouvelle version est disponible. Choose a project file to open Choisir un fichier de projet à ouvrir DB file '%1' could not be opened Le fichier DB '%1' n'a pu être ouvert Table '%1' not found; settings ignored Table "%1" introuvable ; paramètres ignorés Could not open project file for writing. Reason: %1 Le fichier projet ne peut être ouvert en écriture. Raison : %1 -- Reference to file "%1" (not supported by this version) -- -- Référence au fichier "%1" (non supporté par cette version) -- Collation needed! Proceed? Classement nécessaire ! Continuer ? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Une table de cette base de données nécessite la fonction spéciale de classement '%1' que cette application ne peut fournir sans connaissances complémentaires. Si vous choisissez de continuer, ayez à l'esprit que des choses non souhaitées peuvent survenir dans votre base de données. Faites une sauvegarde ! creating collation Créer un classement Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Définissez un nouveau nom pour l'onglet SQL. Utilisez le caractère '&&' pour permettre d'utiliser le caractère suivant comme raccourci clavier. Please specify the view name Veuillez spécifier le nom de la vue There is already an object with that name. Please choose a different name. Il existe déjà un objet avec ce nom. Veuillez choisir un autre nom. View successfully created. La vue a été crée avec succès. Error creating view: %1 Erreur lors de la création de la vue : %1 This action will open a new SQL tab for running: Cette action ouvrira un nouvel onglet SQL pour son exécution : Press Help for opening the corresponding SQLite reference page. Cliquez sur Aide pour ouvrir la page de référence correspondante de SQLite. Busy (%1) Occupé (%1) NullLineEdit Set to NULL Définir comme NULL Alt+Del PlotDock Plot Graphique <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Ce volet affiche la liste des colonnes de la table actuellement parcourue ou de la requête qui vient d'être exécutée. Vous pouvez sélectionner les colonnes que vous voulez utiliser comme axe X ou Y pour le volet de tracé ci-dessous. Le tableau montre le type d'axe détecté qui affectera le tracé résultant. Pour l'axe Y, vous ne pouvez sélectionner que des colonnes numériques, mais pour l'axe X, vous pourrez sélectionner :</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Heure</span> : chaînes au format &quot;aaaa-MM-jj hh:mm:ss&quot; ou &quot;aaaa-MM-jjThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span> : chaînes au format &quot;aaaa-MM-jj&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Heures</span> : chaînes au format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span> : autres formats de chaînes. Sélectionner cette colonne comme axe X produira un diagramme en barres avec les valeurs de la colonne comme étiquettes pour les barres</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numerique</span> : Nombres entiers ou Réels</li></ul><p>En double-cliquant sur une cellule Y, vous pouvez changer la couleur utilisée dans le graphique.</p></body></html> Columns Colonnes X X Y1 Y1 Y2 Y2 Axis Type Type d'axe Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Voici le graphique qui sera dessiné lorsque vous sélectionnerez les valeurs x et y ci-dessus. Cliquez sur les points pour les sélectionner dans le graphique et dans le tableau. Ctrl+Clic pour sélectionner une plage de points. Utilisez la molette de la souris pour zoomer et faites glisser la souris pour modifier la plage des axes. Sélectionnez les axes ou les étiquettes d'axes à faire glisser et à zoomer uniquement dans cette orientation. Line type: Type de ligne : None Aucun Line Ligne StepLeft À gauche StepRight À droite StepCenter Centré Impulse Impulsion Point shape: Forme du point : Cross Croix Plus Plus Circle Cercle Disc Disque Square Carré Diamond Diamant Star Étoile Triangle Triangle TriangleInverted Triangle inversé CrossSquare Carré et Croix PlusSquare Carré et Plus CrossCircle Cercle et Croix PlusCircle Cercle et Plus Peace Paix <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Enregistrer le graphique actuel...</p><p>Choisir le format de fichier parmi ces extensions (png, jpg, pdf, bmp)</p></body></html> Save current plot... Enregistrer le tracé actuel... Load all data and redraw plot Charger toutes les données et redessiner le graphique Row # # Ligne Copy Copier Print... Imprimer... Show legend Afficher la légende Stacked bars Diagramme à barres empilées Fixed number format Format des nombres fixes Date/Time Date/Heure Date Date Time Heure Numeric Numérique Label Label Invalid Invalide Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Charger toutes les données et redessiner le tracé. Attention : toutes les données n'ont pas encore été extraites du tableau en raison du mécanisme d'extraction partielle. Choose an axis color Choisir une couleur d'axe Choose a filename to save under Choisir un nom de fichier pour enregistrer sous PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Il y a des courbes dans ce graphique et le style de ligne sélectionné ne peut être appliqué qu'aux graphiques triés par X. Triez la table ou la requête par X pour supprimer les courbes ou sélectionnez un des styles pris en charge par les courbes : Aucun ou Ligne. Loading all remaining data for this table took %1ms. Le chargement de toutes les données restantes pour ce tableau a pris %1 ms. PreferencesDialog Preferences Préférences &General &Général Remember last location Se souvenir du dernier emplacement Always use this location Toujours utiliser cet emplacement Remember last location for session only Dernier emplac. pour cette session uniquement Lan&guage Lan&gue Show remote options Afficher options serv. distant Automatic &updates Mises à jour a&utomatiques &Database Base de &Données Database &encoding &Encodage de la base de données Open databases with foreign keys enabled. Ouvrir une base de données en activant les clés étrangères. &Foreign keys &Clés étrangères enabled Autoriser Default &location Emp&lacement par défaut ... ... Remove line breaks in schema &view Suppr. les sauts de ligne dans la &vue du schéma Prefetch block si&ze &Taille du bloc de préfetch SQ&L to execute after opening database Fichier SQ&L à exécuter à l'ouverture de la base de données Default field type Type de champ par défaut Data &Browser &Navigateur des données Font Police &Font &Police Content Contenu Symbol limit in cell Texte : Nb. max. de caractères NULL NULL Regular Standard Binary Binaire Background Arrière plan Filters Filtres Threshold for completion and calculation on selection Seuil d'achèvement et calcul lors de la sélection Show images in cell Afficher les images dans la cellule Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Activez cette option pour afficher un aperçu des BLOBs contenant des images dans les cellules. Cela peut toutefois affecter les performances du navigateur de données. Escape character Caractère d'échappement Delay time (&ms) Délai (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Définit le temps d'attente avant qu'une nouvelle valeur de filtre est appliquée. Peut être renseigné à 0 pour supprimer le temps d'attente. &SQL &SQL Context Contexte Colour Couleur Bold Gras Italic Italique Underline Souligné Keyword Mot clé Function Fonction Table Table Comment Commentaire Identifier Identifiant String Chaîne de caractère Current line Ligne courante SQL &editor font size &Taille de la police : Éditeur SQL Tab size Largeur de tabulation SQL editor &font &Police de l'éditeur SQL Error indicators Indicateur d'erreur Hori&zontal tiling Division hori&zontale If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Si elle est activée, l'éditeur de code SQL et l'affichage du tableau de résultats sont présentés côte à côte au lieu d'être l'un sur l'autre. Code co&mpletion Co&mplétion de code Toolbar style Style de la barre d'outil Only display the icon Afficher uniquement les icones Only display the text Afficher uniquement le texte The text appears beside the icon Le texte sera affiché à côté des icones The text appears under the icon Le texte sera affiché sous les icones Follow the style Suivre le style DB file extensions Extensions de fichiers DB Manage Gestion Main Window Fenêtre principale Database Structure Structure de la base de données Browse Data Parcourir les données Execute SQL Exécuter le SQL Edit Database Cell Éditer le contenu d'une cellule de la BDD When this value is changed, all the other color preferences are also set to matching colors. Lorsque cette valeur est modifiée, toutes les autres préférences de couleur sont également réglées sur les couleurs correspondantes. Follow the desktop style Suit le style du bureau Dark style Style sombre Application style Style de l'application This sets the font size for all UI elements which do not have their own font size option. Définit la taille de la police pour tous les éléments de l'interface utilisateur qui n'ont pas leur propre option de taille de police. Font size Taille de police Max Recent Files Nb. max. fichiers récents Prompt to save SQL tabs in new project file Invite à sauvegarder les onglets SQL dans un nouveau fichier de projet If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Si cette option est activée, les modifications apportées à l'éditeur SQL génèrent une boîte de dialogue de confirmation de l'enregistrement du projet lors de la fermeture de l'onglet de l'éditeur SQL. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Lorsque cette option est activée, les sauts de ligne de la colonne Schéma de l'onglet Structure de la base de données, du dock et de la sortie imprimée sont supprimés. Database structure font size Taille de la police pour la structure de la base de données Font si&ze T&aille de police This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Il s'agit du nombre maximum d'éléments autorisés pour l'activation de certaines fonctionnalités coûteuses en termes de calcul : Nombre maximal de lignes dans un tableau pour permettre la complétion des valeurs sur la base des valeurs actuelles de la colonne. Nombre maximum d'index dans une sélection pour le calcul de la somme et de la moyenne. Peut être fixé à 0 pour la désactivation des fonctionnalités. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Il s'agit du nombre maximum de lignes dans une table pour permettre la complétion de la valeur en fonction des valeurs actuelles dans la colonne. Peut être mis à 0 pour désactiver la complétion. Field display Affichage des champs Light style Style clair Displayed &text &Texte affiché Formatted Formaté Click to set this color Cliquez pour définir cette couleur Text color Couleur de texte Background color Couleur d'arrière plan Preview only (N/A) Préaffichage uniquement (N/A) Foreground Avant-plan Selection background Sélection de l'arrière-plan Selection foreground Sélection de l'avant-plan Highlight Souligner SQL &results font size Taille police &résultats SQL Use tabs for indentation Utiliser les tabulations pour l'indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. Lorsqu'elle est activée, la touche Tab insère des caractères de tabulation et d'espacement pour l'indentation. Dans le cas contraire, seuls les espaces seront utilisés. &Wrap lines &Retour à la ligne Never Jamais At word boundaries Aux limites des mots At character boundaries Aux limites des caractères At whitespace boundaries Aux limites des espaces &Quotes for identifiers &Guillemets pour les identifiants Choose the quoting mechanism used by the application for identifiers in SQL code. Choisissez le système de guillemets utilisés par l'application pour les identificateurs dans le code SQL. "Double quotes" - Standard SQL (recommended) "Double guillemet" - Standard SQL (recommandé) `Grave accents` - Traditional MySQL quotes `Accent Grave` - Guillemets standards MySQL [Square brackets] - Traditional MS SQL Server quotes [Crochets] - Guillemets traditionnels de MS SQL Server Keywords in &UPPER CASE Mots clé en &MAJUSCULES When set, the SQL keywords are completed in UPPER CASE letters. Si cette case est cochée, les mots clé SQL sont transformés en MAJUSCULES. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Si cette option est activée, les lignes de code SQL qui ont causé des erreurs lors de la dernière exécution sont mises en surbrillance et le cadre des résultats indique l'erreur en arrière-plan Close button on tabs Bouton de fermeture des onglets If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Si cette option est activée, les onglets de l'éditeur SQL comporteront un bouton de fermeture. Dans tous les cas, vous pouvez utiliser le menu contextuel ou le raccourci clavier pour les fermer. &Extensions E&xtensions Select extensions to load for every database: Sélectionner une extension à charger pour toutes les bases de données : Add extension Ajouter une extension Remove extension Enlever une extension Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>Bien que SQLite supporte l'opérateur REGEXP, aucun algorithme<br>d'expression régulière n'est implémenté : l'application doit fournir le sien. DB Browser pour SQLite implémente<br/>cet algorithme pour vous permettre d'utiliser REGEXP. Cependant, comme il existe plusieurs implémentations possibles<br/>et que vous souhaitez peut-être utiliser autre chose, vous êtes libre de désactiver cette implémentation dans l'application<br/>pour utiliser la vôtre en utilisant une extension. Cela nécessite le redémarrage de l'application.</p></body></html> Disable Regular Expression extension Désactiver l'extension "Expression Régulière" <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite fournit une fonction SQL pour charger des extensions à partir d'un fichier de bibliothèque partagé. Activez cette option si vous souhaitez utiliser la fonction <span style=" font-style:italic;">load_extension()</span> depuis le code SQL.</p><p>Pour des raisons de sécurité, le chargement des extensions est désactivé par défaut et doit être activé par ce paramètre. Vous pouvez toujours charger des extensions via l'interface graphique, même si cette option est désactivée.</p></body></html> Allow loading extensions from SQL code Autoriser le chargement des extensions depuis le code SQL Remote Serveur distant CA certificates Certificats CA Proxy Proxy Configure Configurer Export Settings Exporter les paramètres Import Settings Importer les paramètres Subject CN Sujet CN Common Name Nom Commun - CN Subject O Sujet O Organization Organisation Valid from Valide de Valid to Valide jusqu'à Serial number Numéro de série Your certificates Vos certificats File Fichier Subject Common Name Sujet Common Name Issuer CN Émetteur CN Issuer Common Name Clone databases into Cloner la base de données dans Choose a directory Choisir un répertoire The language will change after you restart the application. La langue ne changera qu'après le redémarrage de l'application. Select extension file Sélectionner un fichier d'extension Extensions(*.so *.dylib *.dll);;All files(*) Extensions (*.so *.dylib *.dll);;Tous les fichiers (*) Import certificate file Importer un fichier de certificat No certificates found in this file. Aucun certificat n'a été trouvé dans ce fichier. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Êtes-vous sûr de vouloir supprimer ce certificat ? Toutes les données de ce certificat seront supprimées des paramètres de l'application! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Êtes-vous sûr de vouloir effacer tous les réglages sauvegardés ? Toutes vos préférences seront perdues et les valeurs par défaut seront utilisées. Save Settings File Enregistrer le fichier de paramètres Initialization File (*.ini) Fichier d'initialisation (*.ini) The settings file has been saved in location : Le fichier de paramètres a été enregistré à l'emplacement : Open Settings File Ouvrir le fichier de paramètres The settings file was loaded properly. Le fichier de configuration a été chargé correctement. The selected settings file is not a normal settings file. Please check again. Le fichier de paramètres sélectionné n'est pas un fichier de paramètres normal. Veuillez vérifier à nouveau. ProxyDialog Proxy Configuration Configuration du proxy Pro&xy Type Type de pro&xy Host Na&me No&m de l'hôte Port Port Authentication Re&quired Authentification re&quise &User Name Nom d'&utilisateur Password Mot de passe None Aucun System settings Paramètres système HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data Erreur lors de l'import des données from record number %1 pour l'enregistrement numéro %1 . %1 . %1 Importing CSV file... Import du fichier CSV... Cancel Annuler All files (*) Tous les fichiers (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Base de données SQLite (*.db *.sqlite *.sqlite3 *.db3) Left Gauche Right Droite Center Centré Justify Justifié SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) Fichier de BDD SQLite (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) Fichiers projet DB Browser pour SQLite (*.sqbpro) SQL Files (*.sql) Fichiers SQL (*.sql) All Files (*) Tous les fichiers (*) Text Files (*.txt) Fichiers texte (*.txt) Comma-Separated Values Files (*.csv) Valeurs séparées par des virgules (*.csv) Tab-Separated Values Files (*.tsv) Valeurs séparées par des tabulations (*.tsv) Delimiter-Separated Values Files (*.dsv) Valeurs séparées par des délimiteurs (*.dsv) Concordance DAT files (*.dat) Fichiers de concordance (*.dat) JSON Files (*.json *.js) Fichiers JSON (*.json *.js) XML Files (*.xml) Fichiers XML (*.xml) Binary Files (*.bin *.dat) Fichiers binaires (*.bin *.dat) SVG Files (*.svg) Fichiers SVG (*.svg) Hex Dump Files (*.dat *.bin) Fichiers de dump hexadécimal (*.dat *.bin) Extensions (*.so *.dylib *.dll) Extensions (*.so *.dylib *.dll) Initialization File (*.ini) Fichier d'initialisation (*.ini) QsciCommand Paste Coller Cancel Annuler QsciLexerCPP Default Défaut Keyword Mot clé Identifier Identifiant QsciLexerJSON Default Défaut String Chaîne de caractère QsciLexerJavaScript Regular expression Expression régulière QsciLexerPython Default Défaut Comment Commentaire Keyword Mot clé Identifier Identifiant QsciLexerSQL Default Défaut Comment Commentaire Keyword Mot clé Identifier Identifiant QsciScintilla &Undo Ann&uler Select All Sélectionner tout RemoteCommitsModel Commit ID ID de commit Message Message Date Date Author Auteur Size Taille Authored and committed by %1 Need to see the context Authored can be translated by "Publié" (published) too as the main author Créé et validé par %1 Authored by %1, committed by %2 Créé par %1, validé par %2 RemoteDatabase Error opening local databases list. %1 Erreur lors de l'ouverture de la liste des bases de données locales. %1 Error creating local databases list. %1 Erreur lors de la création de la liste des bases de données locales. %1 RemoteDock Remote Serveur distant Local Local Identity Identité Push currently opened database to server Déplacer la base de données en cours sur le serveur Upload Télécharger DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>Dans ce volet, les bases de données distantes du site Web dbhub.io peuvent être ajoutées à DB Browser pour SQLite. Il faut d'abord vous identifier :</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connectez-vous sur le site dbhub.io (utilisez vos identifiants GitHub ou ce que vous voulez)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cliquez sur le bouton &quot;Generate client certificate&quot; (c'est votre identité). Cela vous fournira un fichier de certificat (enregistrez-le sur votre disque local).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Allez dans l'onglet Serveur distant des Préférences DB Browser pour SQLite. Cliquez sur le bouton pour ajouter un nouveau certificat à DB Browser pour SQLite et choisissez le fichier de certificat que vous venez de télécharger.</li></ol><p>Maintenant, le panneau Serveur distant affiche votre identité et vous pouvez ajouter des bases de données distantes..</p></body></html> Current Database Base de données en cours Clone Cloner Branch Branche Commits Commits Commits for Commits pour Delete Database Supprime la base de données Delete the local clone of this database Supprime le clone local de la base de données Open in Web Browser Ouvre dans un navigateur Internet Open the web page for the current database in your browser Ouvre la page web de la base de données en cours dans votre navigateur Clone from Link Cloner depuis un lien Use this to download a remote database for local editing using a URL as provided on the web page of the database. Utilisez ceci pour télécharger une base de données distante pour l'éditer localement en utilisant une URL telle que fournie sur la page web de la base de données. Refresh Rafraîchir Reload all data and update the views Recharge toutes les données et met à jour les vues Clone Database Cloner une base de données Open Database Ouvrir une base de données Open the local copy of this database Ouvrir la copie locale de la base de données Check out Commit Vérifier le commit Download and open this specific commit Télécharger et ouvrir ce commit particulier Check out Latest Commit Vérifier le dernier commit Check out the latest commit of the current branch Vérifie le dernier commit de la branche en cours Save Revision to File Enregistrer la révision dans un fichier Saves the selected revision of the database to another file Enregistre la révision sélectionnée de la base de données dans un autre fichier Upload Database Télécharger la base de données Upload this database as a new commit Téléchargez cette base de données en tant que nouveau commit <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>Vous utilisez actuellement une identité intégrée, en lecture seule. Pour télécharger votre base de données, vous devez configurer et utiliser votre compte DBHub.io. </p><p>Vous n'avez pas encore de compte DBHub.io ? <a href="https://dbhub.io/"><span style=" text-decoration : underline ; color:#007af4 ;">Créez-en un maintenant</span></a> et importez votre certificat <a href="#preferences"><span style=" text-decoration : underline ; color:#007af4 ;">ici</span></a> pour partager vos bases de données.</p><p>Pour l'aide en ligne, visitez <a href="https://dbhub.io/about"><span style=" text-decoration : underline ; color:#007af4 ;">ici</span></a>.</p></body></html> &User &Utilisateur &Database Base de &données Back Retour Select an identity to connect Sélectionner une identité pour se connecter Public Public This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Cela télécharge une base de données à partir d'un serveur distant pour l'éditer localement. Veuillez entrer l'URL à partir de laquelle vous souhaitez la cloner. Vous pouvez générer cette URL en cliquant sur le bouton "Cloner la base de données dans DB4S" sur la page web de la base de données. Invalid URL: The host name does not match the host name of the current identity. URL invalide : Le nom de l'hôte ne correspond pas au nom de l'hôte de l'identité actuelle. Invalid URL: No branch name specified. URL invalide : Nom de branche non spécifié. Invalid URL: No commit ID specified. URL invalide : Commit ID non spécifié. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? Vous avez modifié le clone local de la base de données. La récupération de ce commit annule ces modifications locales. Êtes-vous sûr de vouloir continuer ? The database has unsaved changes. Are you sure you want to push it before saving? La base de données contient des modifications non sauvegardées. Êtes-vous sûr de vouloir la pousser avant de la sauvegarder ? The database you are trying to delete is currently opened. Please close it before deleting. La base de données que vous essayez de supprimer est actuellement ouverte. Veuillez la fermer avant de la supprimer. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? Cela va supprimer la version locale de cette base de données avec tous les changements pour lesquels vous n'avez pas fait de commit. Êtes-vous sûr de vouloir supprimer cette base de données ? RemoteLocalFilesModel Name Nom Branch Branche Last modified Dernière modification Size Taille Commit Commit File Fichier RemoteModel Name Nom Last modified Dernière modification Size Taille Commit Commit Size: Taille : Last Modified: Dernière modification : Licence: Licence : Default Branch: Branche par défaut : RemoteNetwork Choose a location to save the file Choisissez un emplacement pour enregistrer le fichier Error opening remote file at %1. %2 Erreur lors de l'ouverture du fichier distant %1. %2 Error: Invalid client certificate specified. Erreur : Le certificat du client spécifié est invalide. Please enter the passphrase for this client certificate in order to authenticate. Pour vous authentifier, veuillez entrer la phrase secrète pour ce certificat client. Cancel Annuler Uploading remote database to %1 Téléchargement de la base distante dans %1 Downloading remote database from %1 Télécharger une base de données distante depuis %1 Error: Cannot open the file for sending. Erreur : le fichier à envoyer ne peut être ouvert. RemotePushDialog Push database Je ne pense pas que Push soir le bon terme. Est-ce que cela fonctionne comme un serveur de version ? Pousser une base de données Database na&me to push to &Nom de la base de données à pousser vers Commit message Message de commit Database licence Licence de la base de données Public Publique Branch Branche Force push Forcer le "push" Username Nom d'utilisateur Database will be public. Everyone has read access to it. La base de données sera publique. Tout le monde a un accès en lecture. Database will be private. Only you have access to it. La base de données sera privée. Vous seul y avez accès. Use with care. This can cause remote commits to be deleted. À utiliser avec précaution. Cela peut entraîner la suppression des commit distants. RunSql Execution aborted by user Exécution annulée par l'utilisateur , %1 rows affected , %1 enregistrements affectés query executed successfully. Took %1ms%2 Requête exécutée avec succès. Elle a pris %1 ms %2 executing query Exécution de la requête SelectItemsPopup A&vailable &Disponible Sele&cted Séle&ctionné SqlExecutionArea Form Formulaire Find previous match [Shift+F3] Trouver la correspondance précédente [Maj+F3] Find previous match with wrapping Trouver la correspondance précédente avec le modèle Shift+F3 The found pattern must be a whole word Le motif trouvé doit être un mot entier Whole Words Mots entiers Text pattern to find considering the checks in this frame Modèle de texte à trouver en tenant compte des contrôles de ce cadre Find in editor Chercher dans l'éditeur The found pattern must match in letter case Le motif recherché doit respecter la casse des lettres Case Sensitive Sensible à la casse Find next match [Enter, F3] Trouver la correspondance suivante [Entrée, F3] Find next match with wrapping Trouver la correspondance suivante avec le modèle F3 F3 Interpret search pattern as a regular expression Interpréter le modèle de recherche comme une expression régulière <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Lorsqu'elle est cochée, le motif à trouver est interprété comme une expression régulière UNIX. Voir <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Expression régulière Close Find Bar Fermer la barre de recherche <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>Résultats des derniers traitements exécutées.</p><p>Vous pouvez réduire ce panneau et utiliser le <span style=" font-style:italic ;">dock SQL Log</span> avec la sélection de l'<span style=" font-style:italic ;">utilisateur</span> à la place.</p></body></html> Results of the last executed statements Résultats du dernier traitement exécuté This field shows the results and status codes of the last executed statements. Ce champ affiche les résultats et les codes de statut du dernier traitement exécuté. Ctrl+PgUp Ctrl+Page Haut Ctrl+PgDown Ctrl+Page Bas Couldn't read file "%1": %2. Le fichier %1 ne peut être lu : %2. Couldn't save file: %1. Le fichier %1 ne peut être sauvegardé. Your changes will be lost when reloading it! Vos modifications seront perdues lors du rechargement ! The file "%1" was modified by another program. Do you want to reload it?%2 Le fichier "%1" a été modifié par un autre programme. Voulez-vous le recharger ? %2 Answer "Yes to All" to reload the file on any external update without further prompting. Répondez "Oui pour tous" pour recharger le fichier lors de toute mise à jour externe sans autre question. Answer "No to All" to ignore any external update without further prompting. Répondez "Non à tous" pour ignorer toute mise à jour externe sans autre question. Modifying and saving the file will restore prompting. A voir selon le contexte MVT La modification et l'enregistrement du fichier rétabliront la demande d'information. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) La fonction abs(X) renvoie la valeur absolue de l'argument numérique X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () La fonction changes() renvoie le nombre de lignes de la base de données qui ont été modifiées, insérées ou supprimées par les instructions UPDATE, INSERT ou DELETE terminées dernièrement. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1, X2,...) La fonction char(X1,X2,...,XN) renvoie une chaîne composée des caractères ayant les valeurs des points de code unicode des entiers allant de X1 à XN, respectivement. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X, Y, ...) La fonction coalesce () renvoie une copie de son premier argument non-NULL, ou NULL si tous les arguments sont NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X, Y) La fonction glob(X, Y) est équivalente à l'expression « Y GLOB X ». (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X, Y) La fonction ifnull() renvoie une copie de son premier argument non-NULL, ou NULL si les deux arguments sont NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X, Y) La fonction instr(X, Y) trouve la première occurrence de la chaîne Y dans la chaîne X. Elle renvoie le nombre de caractères précédents plus 1 ou 0 si Y n'est pas dans X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) La fonction hex() interprète son argument comme un BLOB et renvoie une chaîne qui est le rendu hexadécimal en majuscules du contenu de ce blob. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) La fonction iif(X,Y,Z) renvoie la valeur Y si X est vrai, Z sinon. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () La fonction last_insert_rowid () renvoie le ROWID de la dernière ligne insérée par la connexion de la base de données qui a invoqué la fonction. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) Pour une valeur de chaîne X, la fonction length(X) renvoie le nombre de caractères (pas d'octets) dans X avant le premier caractère NULL. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X, Y) La fonction like() est utilisée pour mettre en Å“uvre de l’expression « Y LIKE X ». (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X, Y, Z) La fonction like() est utilisée pour mettre en Å“uvre de l’expression « Y LIKE X ESCAPE Z ». (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) La fonction load_extension(X) charge les extensions SQLite à partir du fichier de bibliothèque partagé nommé X. L'utilisation de cette fonction doit être autorisée à partir des Préférences. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) La fonction load_extension(X) charge les extensions SQLite à partir du fichier de bibliothèque partagée nommé X en utilisant le point d'entrée Y. L'utilisation de cette fonction doit être autorisée à partir des Préférences. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) La fonction lower(X) renvoie une copie de la chaîne X avec tous ses caractères ASCII convertis en minuscules. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) supprime les espaces gauche de X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X, Y) La fonction ltrim(X,Y) renvoie une chaîne résultant de la suppression de tous les caractères qui apparaissent en Y à gauche de X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) La fonction à arguments multiples max() renvoie l'argument ayant la plus grande valeur ou renvoie NULL si tous les arguments sont NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) La fonction à arguments multiples min() renvoie l'argument ayant la plus petite valeur. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X, Y) La fonction nullif(X,Y) renvoie le premier argument, si les arguments sont différents et NULL si les X et Y sont les mêmes. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) La fonction SQL printf(FORMAT,...) fonctionne comme la fonction de sqlite3_mprintf() en langage C et la fonction printf() de la bibliothèque C standard. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) La fonction quote(X) renvoie le texte d'un litéral SQL qui est la valeur appropriée de l'argument pour son inclusion dans une requête SQL. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () La fonction random() renvoie un nombre entier pseudo-aléatoire entre -9223372036854775808 et +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) La fonction randomblob(N) renvoie un blob de N octets contenant des octets pseudo-aléatoires. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X, Y, Z) La fonction replace(X,Y,Z) renvoie une chaîne formée en substituant par la chaîne Z chaque occurrence de la chaîne Y présente dans la chaîne X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) La fonction round(X) renvoie une valeur à virgule flottante X arrondie à zéro chiffres à droite de la virgule décimale. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X, Y) La fonction round(X,Y) renvoie une valeur à virgule flottante X arrondie à Y chiffres à droite de la virgule décimale. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) supprime les espaces droite de X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X, Y) La fonction rtrim(X,Y) renvoie une chaîne formée en supprimant tous les caractères qui apparaissent en Y, à droite de X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) La fonction soundex(X) renvoie une chaîne qui est l'encodage soundex de la chaîne X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X, Y) substr(X,Y) renvoie tous les caractères à partir du n-ième Y jusqu'à la fin de la chaîne X. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X, Y, Z) La fonction substr(X,Y,Z) renvoie une sous-chaîne de la chaîne X à partie du n-ième caractère Y, de longueur Z. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () La fonction total_changes() renvoie le nombre d'enregistrements altérés par les instructions INSERT, UPDATE ou DELETE depuis l'ouverture de la connexion de base de données courante. (X) trim(X) removes spaces from both ends of X. (X) trim(X) supprime les espaces aux deux extrémités de X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X, Y) La fonction trim(X,Y) renvoie une chaîne formée en supprimant tous les caractères de Y présents aux deux extrémités de X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) La fonction typeof(X) renvoie une chaîne qui indique le type de données de l'expression X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) La fonction unicode(X) renvoie le point de code unicode numérique correspondant au premier caractère de la chaîne X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) La fonction upper(X) renvoie une copie de la chaîne X dans laquelle tous les caractères ASCII en minuscules sont convertis en leurs équivalents en majuscules. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) La fonction zeroblob(N) renvoie un BLOB composé de N octets de valeur 0x00. (timestring,modifier,modifier,...) (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) La fonction avg() renvoie la valeur moyenne de tous les X non-NULL dans d'un groupe. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) La fonction count(X) renvoie le nombre de fois où X n'est pas NULL dans un groupe. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) la fonction group_concat() renvoie une chaîne qui est la concaténation de toutes les valeurs non-NULL de X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X, Y) La fonction group_concat() renvoie une chaîne qui est la concaténation de toutes les valeurs non-NULL de X. Si le paramètre Y est présent, il est utilisé comme séparateur entre chaque instances de X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) La fonction d'agrégat max() renvoie la valeur maximale de toutes les valeurs du groupe. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) La fonction d'agrégation min() renvoie la valeur non-NULL minimale de toutes les valeurs du groupe. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) Les fonctions d'agrégation sum() et total() renvoient la somme de toutes les valeurs non-NULL du groupe. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () Le numéro de l'enregistrement dans la partition courante. Les lignes sont numérotées à partir de 1 dans l'ordre défini par la clause ORDER BY dans la définition de la fenêtre, ou, sinon, dans un ordre arbitraire. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Le row_number() enregistrement homologue de chaque groupe - le rang de l'enregistrement courant avec les écarts. S'il n'y a pas de clause ORDER BY, alors tous les enregistrements sont considérées comme homologues et cette fonction renvoie toujours 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Le numéro du groupe d'enregistrements homologues de la rangée courante dans sa partition - le rang de la rangée courante sans espaces. Les partitions sont numérotées à partir de 1 dans l'ordre défini par la clause ORDER BY dans la définition de la fenêtre. S'il n'y a pas de clause ORDER BY, alors toutes les lignes sont considérées comme homologues et cette fonction renvoie toujours 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () Malgré le nom, cette fonction retourne toujours une valeur comprise entre 0.0 et 1.0 égale à (rang - 1)/(rangées de partitions - 1), où rang est la valeur retournée par la fonction de fenêtre intégrée rank() et rangées de partitions est le nombre total de rangées dans la partition. Si la partition ne contient qu'une seule ligne, cette fonction renvoie 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () Répartition cumulée. Calculée en tant que ligne-numéro/rangées-partition, où ligne-numéro est la valeur retournée par row_number() pour le dernier homologue dans le groupe et ligne-partition le nombre de lignes dans la partition. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) L'argument N est traité comme un entier. Cette fonction divise la partition en N groupes le plus uniformément possible et attribue un entier compris entre 1 et N à chaque groupe, dans l'ordre défini par la clause ORDER BY, ou, sinon, dans un ordre arbitraire. Si nécessaire, les plus grands groupes se forment en premier. Cette fonction retourne la valeur entière assignée au groupe dont la ligne courante fait partie. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Retourne le résultat de l'évaluation de l'expression expr par rapport à la ligne précédente de la partition. Ou NULL s'il n'y a pas de ligne précédente (parce que la ligne courante est la première). (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) Si l'argument offset est fourni, alors il doit être un entier non négatif. Dans ce cas, la valeur retournée est le résultat de l'évaluation de expr par rapport au décalage des lignes avant la ligne courante dans la partition. Si l'offset est égal à 0, alors expr est évalué par rapport à la ligne courante. S'il n'y a pas de lignes de décalage de ligne avant la ligne courante, NULL est retourné. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) Si la valeur par défaut est aussi renseignée, cette valeur sera retournée au lieu de NULL si la ligne identifiée par offset n'existe pas. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Retourne le résultat de l'évaluation de l'expression expr par rapport à la ligne suivante de la partition. Ou NULL s'il n'y a pas de ligne suivante (parce que la ligne courante est la dernière). (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) Si l'argument offset est fourni, alors il doit être un entier non négatif. Dans ce cas, la valeur retournée est le résultat de l'évaluation de expr par rapport par rapport au décalage des lignes après la ligne courante dans la partition. Si l'offset est égal à 0, alors expr est évalué par rapport à la ligne courante. S'il n'y a pas de lignes de décalage de ligne après la ligne courante, NULL est retourné. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Cette fonction de fenêtrage intégrée calcule le cadre de la fenêtre pour chaque rangée de la même manière qu'une fonction de fenêtrage agrégée. Elle retourne la valeur de expr évaluée par rapport à la première ligne du cadre de la fenêtre pour chaque ligne. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Cette fonction de fenêtrage intégrée calcule le cadre de la fenêtre pour chaque rangée de la même manière qu'une fonction de fenêtrage agrégée. Elle retourne la valeur de expr évaluée par rapport à la dernière ligne du cadre de la fenêtre pour chaque ligne. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) Cette fonction de fenêtrage intégrée calcule le cadre de la fenêtre pour chaque rangée de la même manière qu'une fonction de fenêtrage agrégée. Elle retourne la valeur de expr évaluée par rapport à la ligne N du cadre de la fenêtre. Les rangées sont numérotées à l'intérieur du cadre de la fenêtre à partir de 1 dans l'ordre défini par la clause ORDER BY si elle est présente, ou dans un ordre arbitraire sinon. S'il n'y a pas de n-ième ligne dans la partition, alors NULL est retourné. (X) Return the arccosine of X. The result is in radians. (X) Retourne l'arc cosinus de X. Le résultat est en radians. (X) Return the hyperbolic arccosine of X. (X) Renvoie le cosinus de l'arc hyperbolique de X. (X) Return the arcsine of X. The result is in radians. (X) Renvoie l'arcsinus de X. Le résultat est en radians. (X) Return the hyperbolic arcsine of X. (X) Renvoie l'arcsinus hyperbolique de X. (X) Return the arctangent of X. The result is in radians. (X) Renvoie l'arctangente de X. Le résultat est en radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X,Y) Renvoie l'arctangente de Y/X. Le résultat est en radians. Le résultat est placé dans le bon quadrant en fonction des signes de X et Y. (X) Return the hyperbolic arctangent of X. (X) Renvoie l'arctangente hyperbolique de X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Renvoie la première valeur entière représentable supérieure ou égale à X. Pour les valeurs positives de X, cette routine arrondit à l'écart de zéro. Pour les valeurs négatives de X, cette routine arrondit vers zéro. (X) Return the cosine of X. X is in radians. (X) Renvoie le cosinus de X. X est exprimé en radians. (X) Return the hyperbolic cosine of X. (X) Renvoie le cosinus hyperbolique de X. (X) Convert value X from radians into degrees. (X) Convertit la valeur X de radians en degrés. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Calculer le (le nombre d'Euler, environ 2,71828182845905) élevé à la puissance X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Renvoie la première valeur entière représentable inférieure ou égale à X. Pour les nombres positifs, cette fonction arrondit vers zéro. Pour les nombres négatifs, cette fonction arrondit à l'opposé de zéro. (X) Return the natural logarithm of X. (X) Renvoie le logarithme naturel de X. (B,X) Return the base-B logarithm of X. (B,X) Renvoie le logarithme en base B de X. (X) Return the base-10 logarithm for X. (X) Renvoie le logarithme en base 10 de X. (X) Return the logarithm base-2 for the number X. (X) Renvoie le logarithme en base 2 de X. (X,Y) Return the remainder after dividing X by Y. (X,Y) Renvoie le reste après avoir divisé X par Y. () Return an approximation for Ï€. () Renvoie une approximation de Ï€. (X,Y) Compute X raised to the power Y. (X,Y) Calculer X élevé à la puissance Y. (X) Convert X from degrees into radians. (X) Convertir X de degrés en radians. (X) Return the sine of X. X is in radians. (X) Renvoie le sinus de X. X est en radians. (X) Return the hyperbolic sine of X. (X) Renvoie le sinus hyperbolique de X. (X) Return the square root of X. NULL is returned if X is negative. (X) Renvoie la racine carrée de X. NULL est renvoyé si X est négatif. (X) Return the tangent of X. X is in radians. (X) Renvoie la tangente de X. X est en radians. (X) Return the hyperbolic tangent of X. (X) Renvoie la tangente hyperbolique de X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) Renvoie l'entier représentable compris entre X et 0 (inclus) qui est le plus éloigné de zéro. Ou, en d'autres termes, retourner la partie entière de X, en l'arrondissant vers zéro. SqliteTableModel reading rows Lecture des enregistrements loading... chargement... References %1(%2) Hold %3Shift and click to jump there Références %1(%2) Appuyez simultanément sur %3+Maj et cliquez pour arriver ici Error changing data: %1 Erreur lors du changement des données : %1 retrieving list of columns récupération de la liste des colonnes Fetching data... Récupération des données... Cancel Annuler TableBrowser Browse Data Parcourir les données &Table: &Table : Select a table to browse data Sélectionner une table pour parcourir son contenu Use this list to select a table to be displayed in the database view Utiliser cette liste pour sélectionner la table à afficher dans la vue Base de données This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Ceci est la vue des tables de la base de données. Vous pouvez effectuer les actions suivantes : - Commencez à écrire pour éditer en ligne la valeur. - Double-cliquez sur n'importe quel enregistrement pour éditer son contenu dans la fenêtre de l'éditeur de cellule. - Alt+Supp pour supprimer le contenu de la cellule et la met à NULL. - Ctrl+" pour dupliquer l'enregistrement en cours. - Ctrl+' pour copier la valeur de la cellule ci-dessus. - Sélection standard et opérations de copier/coller. Text pattern to find considering the checks in this frame Modèle de texte à trouver en tenant compte des contrôles de ce cadre Find in table Chercher dans la table Find previous match [Shift+F3] Trouver la correspondance précédente [Maj+F3] Find previous match with wrapping Trouver la correspondance précédente avec le modèle Shift+F3 Find next match [Enter, F3] Trouver la correspondance suivante [Entrée, F3] Find next match with wrapping Trouver la correspondance suivante avec le modèle F3 The found pattern must match in letter case Le motif recherché doit respecter la casse des lettres Case Sensitive Sensible à la casse The found pattern must be a whole word Le motif trouvé doit être un mot entier Whole Cell Ensemble de la cellule Interpret search pattern as a regular expression Interpréter le modèle de recherche comme une expression régulière <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Lorsque cette case est cochée, le motif à trouver est interprété comme une expression régulière UNIX. Voir <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Expression régulière Close Find Bar Fermer la barre de recherche Text to replace with Texte à remplacer par Replace with Remplacer par Replace next match Remplacer la prochaine correspondance Replace Remplacer Replace all matches Remplacer toutes les correspondances Replace all Remplacer tout Export to &JSON Exporter au format &JSON Export the filtered data to JSON Exporte les données filtrées au format JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Ce bouton exporte les données de la table parcourue telles qu'elles sont actuellement affichées (après les filtres, les formats d'affichage et la colonne d'ordre) dans un fichier JSON. Copy column name Copier le nom de la colonne Copy the database table column name to your clipboard Copie le nom de la colonne de la table de la base de données dans le presse-papiers New Data Browser Nouveau navigateur de données Add a new docked Data Browser Ajouter un nouveau navigateur de données ancré This button adds a new docked Data Browser, which you can detach and arrange in different layouts. Ce bouton ajoute un nouveau navigateur de données ancré, que vous pouvez détacher et organiser selon différentes dispositions. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Aller au début</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Cliquer sur ce bouton permet d'aller au début de la table ci-dessus.</p></body></html> |< |< Scroll one page upwards Remonter d'une page <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Cliquer sur ce bouton permet d'afficher la page précédente des enregistrements de la table ci dessus.</p></body></html> < < 0 - 0 of 0 0 - 0 de 0 Scroll one page downwards Descendre d'une page <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Cliquer sur ce bouton permet d'afficher la page suivante des enregistrements de la table ci dessus.</p></body></html> > > Scroll to the end Aller à la fin <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>Cliquer sur ce bouton permet d'aller à la fin de la table ci-dessus.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>Cliquer ici pour vous déplacer sur l'enregistrement indiqué</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Ce bouton est utilisé pour aller directement à l'enregistrement indiqué dans le champ Aller à.</p></body></html> Go to: Aller à : Enter record number to browse Entrez le nombre d'enregistrements à parcourir Type a record number in this area and click the Go to: button to display the record in the database view Entrez un numéro d'enregistrement dans ce champ et cliquez sur le bouton "Aller à" pour afficher l'enregistrement dans la vue base de données 1 1 Show rowid column Afficher la colonne RowId Toggle the visibility of the rowid column Permet d'afficher ou non la colonne RowId Unlock view editing Déverrouiller l'éditeur de vues This unlocks the current view for editing. However, you will need appropriate triggers for editing. Permet de déverrouiller la vue courante pour l'éditer. Cependant, vous aurez besoin de déclencheurs appropriés pour faire cela. Edit display format Modifier le format d'affichage Edit the display format of the data in this column Modifie le format d'affichage des données contenues dans cette colonne New Record Nouvel enregistrement Insert a new record in the current table Insérer un nouvel enregistrement dans la table en cours <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Ce bouton crée un nouvel enregistrement dans la base de données. Maintenez le bouton de la souris enfoncé pour ouvrir un menu contextuel de différentes options :</p><ul><li><span style=" font-weight:600;">Nouvel enregistrement</span> : Insère un nouvel enregistrement avec les valeurs par défaut dans la base de données.</li><li><span style=" font-weight:600;">Insérer des valeurs...</span> : ouvre une boite de dialogue pour saisir des valeurs avant leur insertion dans la base de données. Ceci permet de saisir des valeurs correspondant aux différentes contraintes. Cette boîte de dialogue est également ouverte si l'option <span style=" font-weight:600;">Nouvel enregistrement </span> est en erreur à cause de ces contraintes.</li></ul></body></html> Delete Record Supprimer l'enregistrement Delete the current record Supprimer l'enregistrement courant This button deletes the record or records currently selected in the table Ce bouton permet de supprimer l'enregistrement sélectionné dans la table Insert new record using default values in browsed table Insérer un nouvel enregistrement en utilisant les valeurs par défaut de la table parcourue Insert Values... Ajouter des valeurs... Open a dialog for inserting values in a new record Ouvre une fenêtre de dialogue permettant l'insertion de valeurs dans un nouvel enregistrement Export to &CSV Exporter au format &CSV Export the filtered data to CSV Exporte les données filtrées au format CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Ce bouton exporte les données de la table parcourue telles qu'elles sont actuellement affichées (après les filtres, les formats d'affichage et la colonne d'ordre) dans un fichier CSV. Save as &view Enregistrer comme une &vue Save the current filter, sort column and display formats as a view Enregistrer le filtre, la colonne de tri et les formats d'affichage actuels sous la forme d'une vue This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Ce bouton permet d'enregistrer les paramètres actuels de la table parcourue (filtres, formats d'affichage et colonne d'ordre) sous forme de vue SQL que vous pourrez ensuite parcourir ou utiliser dans les instructions SQL. Save Table As... Enregistrer la table sous... Save the table as currently displayed Enregistrer la table comme affichée actuellement <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>Ce menu déroulant fournit les options suivantes s'appliquant à la table actuellement parcourue et filtrée:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exporter au format CSV : cette option exporte les données de la table parcourue telles qu'elles sont actuellement affichées (après filtres, formats d'affichage et colonne d'ordre) vers un fichier CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enregistrer comme vue : cette option permet d'enregistrer les paramètres actuels de la table parcourue (filtres, formats d'affichage et colonne d'ordre) dans une vue SQL que vous pourrez ensuite parcourir ou utiliser dans les instructions SQL.</li></ul></body></html> Hide column(s) Masquer une/des colonnes Hide selected column(s) Maquer la/les colonnes sélectionnées Show all columns Afficher toutes les colonnes Show all columns that were hidden Permet d'afficher toutes les colonnes qui ont été masquées Set encoding Définir l'encodage Change the encoding of the text in the table cells Change l'encodage du texte des cellules de la table Set encoding for all tables Définir l'encodage pour toutes les tables Change the default encoding assumed for all tables in the database Change l'encodage par défaut choisi pour l'ensemble des tables de la base de données Clear Filters Effacer les filtres Clear all filters Effacer tous les filtres This button clears all the filters set in the header input fields for the currently browsed table. Ce bouton efface tous les filtres définis dans les champs de saisie de l'en-tête de la table actuellement parcourue. Clear Sorting Effacer le tri Reset the order of rows to the default Rétablit l'ordre des lignes aux valeurs par défaut This button clears the sorting columns specified for the currently browsed table and returns to the default order. Ce bouton efface les critères de tri définis pour les colonnes de la table actuellement parcourue et revient à l'ordre par défaut. Print Imprimer Print currently browsed table data Imprimer les données de la table actuelle Print currently browsed table data. Print selection if more than one cell is selected. Imprime les données de la table actuelle. Imprime la sélection si plus d'une cellule est sélectionnée. Ctrl+P Refresh Rafraîchir Refresh the data in the selected table Rafraîchir les données de la table sélectionnée This button refreshes the data in the currently selected table. Ce bouton permet de rafraîchir les données de la table actuellement sélectionnée. F5 Find in cells Rechercher dans les cellules Open the find tool bar which allows you to search for values in the table view below. Ouvre la barre d'outils de recherche qui vous permet de rechercher des valeurs dans la table ci-dessous. Freeze columns Figer les colonnes Make all columns from the first column up to this column not move when scrolling horizontally Fige toutes les colonnes de la première colonne jusqu'à cette colonne lors d'un défilement horizontal Bold Gras Ctrl+B Italic Italique Underline Souligné Ctrl+U Align Right Aligner à droite Align Left Aligner à gauche Center Horizontally Centrer horizontalement Justify Justifié Edit Conditional Formats... Éditer les formats conditionnels... Edit conditional formats for the current column Éditer les formats conditionnels de la colonne en cours Clear Format Effacer les formats Clear All Formats Effacer tous les formats Clear all cell formatting from selected cells and all conditional formats from selected columns Effacer tous les formats de cellule des cellules sélectionnées et tous les formats conditionnels des colonnes sélectionnées Font Color Couleur de police Background Color Couleur d'arrière-plan Toggle Format Toolbar Changer le format de la barre d'outils Show/hide format toolbar Afficher/Cacher la barre des formats This button shows or hides the formatting toolbar of the Data Browser Ce bouton permet d'afficher ou de masquer la barre d'outils de formatage du navigateur de données Select column Sélectionner une colonne Ctrl+Space Replace text in cells Remplace du texte dans les cellules Filter in any column Filtrer dans n'importe quelle colonne Ctrl+R %n row(s) %n ligne %n lignes , %n column(s) , %n colonne , %n colonnes . Sum: %1; Average: %2; Min: %3; Max: %4 . Somme: %1; Moyenne: %2; Min: %3; Max: %4 Conditional formats for "%1" Format conditionnel pour "%1" determining row count... Détermination du nombre d'enregistrements... %L1 - %L2 of >= %L3 %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) (coupé à %L1 lignes) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Veuillez entrer une pseudo clé primaire pour permettre l'édition de la vue. Ce devrait être le nom d'une colonne unique dans la vue. Delete Records Supprimer les enregistrements Duplicate records Enregistrement en double Duplicate record Dupliquer l'enregistrement Ctrl+" Adjust rows to contents Ajuster les lignes au contenu Error deleting record: %1 Erreur dans la suppression d'un enregistrement : %1 Please select a record first Veuillez sélectionner au préalable un enregistrement Please choose a new encoding for all tables. Veuillez choisir un nouvel encodage pour toutes les tables. Please choose a new encoding for this table. Veuillez choisir un nouvel encodage pour cette table. %1 Leave the field empty for using the database encoding. %1 Laissez le champ vide pour utiliser l'encodage de la base de données. This encoding is either not valid or not supported. Cet encodage est invalide ou non supporté. %1 replacement(s) made. %1 remplacement(s) effectué(s). TableBrowserDock New Data Browser Nouveau navigateur de données Rename Data Browser Renommer le navigateur de données Close Data Browser Fermer le navigateur de données Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. Donnez un nouveau nom à l'explorateur de données. Utilisez le caractère "&&" pour permettre l'utilisation du caractère suivant comme raccourci clavier. VacuumDialog Compact Database Compacter la base de données Warning: Compacting the database will commit all of your changes. Attention : compacter la base de donnée entraînera l'enregistrement de tous les changements effectués. Please select the databases to co&mpact: Veuillez saisir le nom de la base de données à co&mpacter : sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_id.ts000066400000000000000000013610641463772530400252040ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Tentang Peramban DB untuk SQLite Version Versi <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Menambah Record Baru Enter values for the new record considering constraints. Fields in bold are mandatory. Masukkan nilai bagi record baru dengan mempertimbangkan batasan. Ruas yang dicetak tebal adalah wajib. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Dalam kolom Nilai Anda dapat menyatakan nilai bagi ruas yang diidentifikasi dalam kolom Nama. Kolom Tipe mengindikasikan tipe ruas. Nilai baku ditampilkan dengan gaya yang sama dengan nilai NULL. Name Nama Type Tipe Value Nilai Values to insert. Pre-filled default values are inserted automatically unless they are changed. Nilai yang akan disisipkan. Nilai baku yang terpraisi disisipkan secara otomatis kecuali bila mereka diubah. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Ketika Anda menyunting nilai-nilai dalam kerangka atas, query SQL untuk menyisipkan record baru ini ditampilkan di sini. Anda dapat menyunting query secara manual sebelum menyimpan. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Simpan</span> akan mengirim pernyataan SQL yang ditunjukkan ke basis data untuk menyisipkan record baru.</p><p><span style=" font-weight:600;">Pulihkan Baku</span> akan memulihkan nilai-nilai awal dalam kolom <span style=" font-weight:600;">Nilai</span>.</p><p><span style=" font-weight:600;">Batal</span> akan menutup dialog ini tanpa mengeksekusi query.</p></body></html> Auto-increment Inkremen otomatis Unique constraint Batasan unik Check constraint: %1 Periksa konstrain: %1 Foreign key: %1 Foreign key: %1 Default value: %1 Nilai baku: %1 Error adding record. Message from database engine: %1 Kesalahan saat menambah record. Pesan dari mesin basis data: %1 Are you sure you want to restore all the entered values to their defaults? Anda yakin hendak memulihkan semua nilai yang dimasukkan ke nilai baku mereka? Application Possible command line arguments: Argumen baris perintah yang mungkin: The user settings file location is replaced with the argument value instead of the environment variable value. Lokasi berkas pengaturan pengguna digantikan dengan nilai argumen bukan nilai variabel lingkungan. Ignored environment variable (DB4S_SETTINGS_FILE) value: Nilai variabel lingkungan (DB4S_SETTINGS_FILE) yang diabaikan: The file %1 does not exist Berkas %1 tidak ada Usage Cara pakai options opsi database basis_data project proyek csv-file berkas-csv Show command line options Tampilkan opsi baris perintah Exit application after running scripts Keluar aplikasi setelah menjalankan skrip file berkas Execute this SQL file after opening the DB Jalankan berkas SQL ini setelah membuka DB Import this CSV file into the passed DB or into a new DB Impor berkas CSV ini ke dalam DB yang diberikan atau ke dalam suatu DB baru table tabel Browse this table, or use it as target of a data import Ramban tabel ini, atau gunakan itu sebagai target dari suatu impor data Open database in read-only mode Buka basis data dalam mode hanya baca settings_file berkas_pengaturan Run application based on this settings file Jalankan aplikasi berbasis pada berkas pengaturan ini group grup settings pengaturan value nilai Run application with this setting temporarily set to value Menjalankan aplikasi dengan pengaturan ini sementara ditata ke nilai Run application saving this value for this setting Menjalankan aplikasi dengan menyimpan nilai bagi pengaturan ini Display the current version Menampilkan versi saat ini Open this SQLite database Buka basis data SQLite ini Open this project file (*.sqbpro) Buka berkas proyek ini (*.sqbpro) Import this CSV file into an in-memory database Impor berkas CSV ini ke dalam suatu basis data dalam memori The %1 option requires an argument Opsi %1 memerlukan sebuah argumen The -S/--settings option requires an argument. The option is ignored. Opsi -S/--settings memerlukan sebuah argumen. Opsi diabaikan. The -o/--option and -O/--save-option options require an argument in the form group/setting=value Opsi -o/--option dan -O/--save-option memerlukan sebuah argumen dalam bentuk grup/pengaturan=nilai Invalid option/non-existent file: %1 Opsi tidak valid/berkas tidak ada: %1 SQLite Version Versi SQLite SQLCipher Version %1 (based on SQLite %2) SQLCipher Versi %1 (berbasis SQLite %2) DB Browser for SQLite Version %1. Peramban DB untuk SQLite Versi %1. Last commit hash when built: %1 Hash commit terakhir ketika dibangun: %1 Built for %1, running on %2 Dibangun untuk %1, dijalankan pada %2 Qt Version %1 Qt Versi %1 CipherDialog SQLCipher encryption Enkripsi SQLCipher &Password Kata &Sandi &Reenter password Masu&kkan lagi kata sandi Encr&yption settings Pengaturan enkr&ipsi SQLCipher &3 defaults Baku SQLCipher &3 SQLCipher &4 defaults Baku SQLCipher &4 Custo&m Ubaha&n Page si&ze Uk&uran halaman &KDF iterations Iterasi &KDF HMAC algorithm Algoritme HMAC KDF algorithm Algoritme KDF Plaintext Header Size Ukuran Header Teks Polos Passphrase Frasa Sandi Raw key Kunci mentah Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Harap atur kunci untuk mengenkripsi basis data. Catat bahwa bila Anda mengubah sebarang pengaturan opsional lain, Anda akan perlu memasukkan ulang mereka juga setiap kali Anda membuka berkas basis data. Biarkan ruas kata sandi kosong untuk menonaktifkan enkripsi. Proses enkripsi mungkin perlu beberapa waktu dan Anda mesti memiliki salinan cadangan dari basis data Anda! Perubahan yang belum tersimpan diterapkan sebelum mengubah enkripsi. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Harap masukkan kunci yang dipakai untuk mengenkripsi basis data. Bila sebarang pengaturan lain diubah untuk berkas basis data ini, Anda perlu menyediakan informasi ini juga. ColumnDisplayFormatDialog Choose display format Pilih format tampilan Display format Format tampilan Choose a display format for the column '%1' which is applied to each value prior to showing it. Pilih suatu format tampilan bagi kolom '%1' yang diterapkan ke setiap nilai sebelum menunjukkannya. Default Baku Decimal number Bilangan desimal Exponent notation Notasi eksponensial Hex blob Blob heksa Hex number Bilangan heksa Apple NSDate to date NSDate Apple ke tanggal Java epoch (milliseconds) to date Epos Java (milidetik) ke tanggal .NET DateTime.Ticks to date DateTime.Ticks .NET ke tanggal Julian day to date Hari Julian ke tanggal Unix epoch to local time Epos Unix ke waktu lokal WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy Tanggal sebagai dd/mm/yyyy Lower case Huruf kecil Binary GUID to text GUID biner ke teks SpatiaLite Geometry to SVG SpatiaLite Geometry ke SVG Custom display format must contain a function call applied to %1 Format tampilan ubahan mesti memuat suatu pemanggilan fungsi yang diterapkan ke %1 Error in custom display format. Message from database engine: %1 Kesalahan dalam format tampilan ubahan. Pesan dari mesin basis data: %1 Custom display format must return only one column but it returned %1. Format tampilan ubahan mesti mengembalikan hanya satu kolom tapi itu mengembalikan %1. Octal number Bilangan oktal Round number Bilangan bulat Unix epoch to date Epos Unix ke tanggal Upper case Huruf besar Windows DATE to date DATE Windows ke tanggal Custom Ubahan CondFormatManager Conditional Format Manager Manajer Format Bersyarat This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Dialog ini memungkinkan pembuatan dan penyuntingan format bersyarat. Setiap gaya sel akan dipilih berdasarkan syarat yang pertama terpenuhi untuk data sel itu. Format bersyarat dapat dipindah naik dan turun, yang ada pada baris lebih tinggi lebih diutamakan dari pada yang lebih rendah. Sintaks untuk syarat sama dengan bagi filter dan suatu syarat kosong berlaku untuk semua nilai. Add new conditional format Tambahkan format bersyarat yang baru &Add T&ambah Remove selected conditional format Hapus format bersyarat yang dipilih &Remove &Hapus Move selected conditional format up Pindahkan ke atas format bersyarat yang dipilih Move &up &Naikkan Move selected conditional format down Pindahkan ke bawah format bersyarat yang dipilih Move &down &Turunkan Foreground Latar depan Text color Warna teks Background Latar belakang Background color Warna latar belakang Font Fonta Size Ukuran Bold Tebal Italic Miring Underline Garis bawah Alignment Perataan Condition Syarat Click to select color Klik untuk memilih warna Are you sure you want to clear all the conditional formats of this field? Anda yakin hendak membersihkan semua format bersyarat atas ruas ini? DBBrowserDB Please specify the database name under which you want to access the attached database Harap nyatakan nama basis data yang akan dipakai untuk mengakses basis data yang dicantol Invalid file format Format berkas tidak valid Do you really want to close this temporary database? All data will be lost. Anda yakin hendak menutup basis data temporer ini? Semua data akan hilang. Do you want to save the changes made to the database file %1? Apakah Anda ingin menyimpan perubahan yang dibuat ke berkas basis data %1? Database didn't close correctly, probably still busy Basis data tidak ditutup secara benar, mungkin masih sibuk Cannot open destination file: '%1' Tidak bisa membuka berkas tujuan: '%1' Cannot backup to file: '%1'. Message: %2 Tidak bisa mencadangkan ke berkas: '%1'. Pesan %2 The database is currently busy: Basis data saat ini sibuk: Do you want to abort that other operation? Apakah Anda ingin menggugurkan operasi lain itu? Exporting database to SQL file... Mengekspor basis data ke berkas SQL... Cancel Batal No database file opened Tidak ada berkas basis data yang dibuka Executing SQL... Mengeksekusi SQL... Action cancelled. Aksi dibatalkan. Error in statement #%1: %2. Aborting execution%3. Kesalahan dalam pernyataan #%1: %2. Menggugurkan eksekusi %3. and rolling back dan me-roll back didn't receive any output from %1 tak menerima keluaran apa pun dari %1 could not execute command: %1 tidak bisa mengeksekusi perintah: %1 Cannot delete this object Tidak bisa menghapus objek ini Cannot set data on this object Tidak bisa menata data pada objek ini A table with the name '%1' already exists in schema '%2'. Sebuah tabel dengan nama '%1' sudah ada dalam skema '%2'. No table with name '%1' exists in schema '%2'. Tidak ada tabel dengan nama '%1' ada dalam skema '%2'. Cannot find column %1. Tidak bisa temukan kolom %1. Creating savepoint failed. DB says: %1 Gagal membuat savepoint. Pesan DB: %1 Renaming the column failed. DB says: %1 Gagal mengubah nama kolom. Pesan DB: %1 Releasing savepoint failed. DB says: %1 Gagal melepas savepoint. Pesan DB: %1 Creating new table failed. DB says: %1 Gagal membuat tabel baru. Pesan DB: %1 Copying data to new table failed. DB says: %1 Gagal menyalin data ke tabel baru. Pesan DB: %1 Deleting old table failed. DB says: %1 Gagal menghapus tabel lama. Pesan DB: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Gagal memulihkan beberapa objek yang terkait dengan tabel ini. Ini sangat boleh jadi karena beberapa nama kolom berubah. Ini pernyataan SQL yang mungkin ingin Anda perbaiki dan eksekusi secara manual: could not get list of databases: %1 tidak bisa memperoleh daftar basis data: %1 Error loading extension: %1 Kesalahan saat memuat ekstensi: %1 Error loading built-in extension: %1 could not get column information tidak bisa memperoleh informasi kolom Error renaming table '%1' to '%2'. Message from database engine: %3 Kesalahan saat mengubah nama tabel '%1' menjadi '%2'. Pesan dari mesin basis data: %3 could not get list of db objects: %1 tidak bisa memperoleh daftar obyek db: %1 Error setting pragma %1 to %2: %3 Kesalahan saat mengatur pragma %1 ke %2: %3 File not found. Berkas tidak ditemukan. DbStructureModel Name Nama Object Objek Type Tipe Schema Skema Database Basis data Browsables Dapat diramban All Semua Temporary Sementara Tables (%1) Tabel (%1) Indices (%1) Indeks (%1) Views (%1) View (%1) Triggers (%1) Trigger (%1) EditDialog Edit database cell Sunting sel basis data Mode: Mode: Image Gambar Set as &NULL Atur sebagai &NULL Apply data to cell Terapkan data ke sel This button saves the changes performed in the cell editor to the database cell. Tombol ini menyimpan perubahan yang dilakukan dalam penyunting sel ke sel basis data. Apply Terapkan Text Teks This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Ini adalah daftar mode yang didukung untuk penyunting sel. Pilih suatu mode untuk menilik atau menyunting data dari sel saat ini. RTL Text Teks RTL Binary Biner JSON JSON XML XML Evaluation Evaluasi Automatically adjust the editor mode to the loaded data type Secara otomatis menyetel mode penyunting ke tipe data yang dimuat This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Tombol yang dapat dicentang ini memfungsikan atau menonaktifkan pemindahan otomatis mode penyunting. Ketika sebuah sel baru dipilih atau data baru diimpor dan pemindahan otomatis difungsikan, mode disesuaikan ke tipe data yang terdeteksi. Anda kemudian dapat mengubah mode penyunting secara manual. Bila Anda ingin mempertahankan mode yang berpindah manual ini ketika bergerak melalui sel, matikan tombol. Auto-switch Berpindah otomatis This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Penyunting Qt ini dipakai untuk skrip kanan ke kiri, yang tidak didukung oleh penyunting Teks baku. Keberadaan karakter kanan ke kiri terdeteksi dan mode penyunting ini dipilih secara otomatis. Identification of the cell currently in the editor Identifikasi dari sel yang saat ini dalam penyunting Type and size of data currently in table Tipe dan ukuran data yang saat ini dalam tabel Open preview dialog for printing the data currently stored in the cell Buka dialog pratinjau untuk mencetak data yang saat ini disimpan dalam sel Auto-format: pretty print on loading, compact on saving. Format otomatis: cetak cantik saat memuat, padatkan saat menyimpan. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Ketika difungsikan, fitur format otomatis memformat data saat memuat, memecah teks dalam baris-baris, dan mengindentasi untuk keterbacaan maksimal. Saat menyimpan data, fitur format otomatis memampatkan data menghapus akhir baris, dan ruang spasi yang tak perlu. Word Wrap Lipat Kata Wrap lines on word boundaries Lipat baris pada perbatasan kata Open in default application or browser Buka dalam aplikasi baku atau peramban Open in application Buka dalam aplikasi The value is interpreted as a file or URL and opened in the default application or web browser. Nilai diinterpretasi sebagai suatu berkas atau URL dan dibuka dalam aplikasi baku atau peramban web. Save file reference... Simpan acuan berkas... Save reference to file Simpan acuan ke berkas Open in external application Buka dalam aplikasi eksternal Autoformat Format otomatis &Export... &Ekspor... &Import... &Impor... Import from file Impor dari berkas Opens a file dialog used to import any kind of data to this database cell. Membuka sebuah dialog berkas yang dipakai untuk mengimpor sebarang jenis data ke sel basis data ini. Export to file Ekspor ke berkas Opens a file dialog used to export the contents of this database cell to a file. Membuka sebuah dialog berkas yang dipakai untuk mengekspor ini sel basis data ini ke suatu berkas. Erases the contents of the cell Menghapus isi sel This area displays information about the data present in this database cell Wilayah ini menampilkan informasi tentang data yang ada dalam sel basis data ini Print... Cetak... Ctrl+P Ctrl+P Open preview dialog for printing displayed text Membuka dialog pratinjau untuk mencetak teks yang ditampilkan Copy Hex and ASCII Salin Heksa dan ASCII Copy selected hexadecimal and ASCII columns to the clipboard Menyalin kolom-kolom ASCII dan heksadesimal yang dipilih ke papan klip Ctrl+Shift+C Ctrl+Shift+C Choose a filename to export data Pilih suatu nama berkas untuk mengekspor data Image data can't be viewed in this mode. Data gambar tak bisa dilihat dalam mode ini. Try switching to Image or Binary mode. Cobalah beralih ke mode Gambar atau Biner. Binary data can't be viewed in this mode. Data biner tak dapat dilihat dalam mode ini. Try switching to Binary mode. Cobalah beralih ke mode Biner. Image files (%1) Berkas gambar (%1) Binary files (*.bin) Berkas biner (*.bin) Type: NULL; Size: 0 bytes Tipe: NULL; Ukuran: 0 byte Type: Text / Numeric; Size: %n character(s) Tipe: Teks/Numerik; Ukuran: %n karakter Type: %1 Image; Size: %2x%3 pixel(s) Tipe: Citra %1; Ukuran: %2x%3 piksel Type: Valid JSON; Size: %n character(s) Tipe: JSON yang Valid; Ukuran: %n karakter Type: Binary; Size: %n byte(s) Tipe: Biner; Ukuran: %n byte Couldn't save file: %1. Tak bisa menyimpan berkas: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Data telah disimpan ke suatu berkas temporer dan telah dibuka dengan aplikasi baku. Kini Anda dapat menyunting berkas, dan ketika Anda siap, menerapkan data baru yang disimpanke sel atau membatalkan perubahan apa pun. Choose a file to import Pilih suatu berkas untuk diimpor The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Mode penyunting teks memungkinkan Anda menyunting berkas polos, maupun data XML atau JSON dengan penyorotan sintaks, pemformatan otomatis, dan validasi sebelum menyimpan. Kesalahan diindikasikan dengan garis bawah cacing merah. Dalam mode Evaluasi, ekspresi SQLite yang dimasukkan dievaluasi dan hasilnya diterapkan ke sel. Unsaved data in the cell editor Data belum disimpan dalam penyunting sel The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Penyunting sel memuat data yang belum diterapkan ke basis data. Apakah Anda hendak menerapkan data yang disunting ke baris=%1, kolom=%2? Editing row=%1, column=%2 Menyunting baris=%1, kolom=%2 No cell active. Tidak ada sel yang aktif. %1 Image Gambar %1 Invalid data for this mode Data tidak valid bagi mode ini The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? Sel memuat data %1 yang tidak valid. Alasan: %2. Anda yakin ingin menerapkannya ke sel? EditIndexDialog &Name &Nama Order Urutan &Table &Tabel Edit Index Schema Sunting Skema Indeks &Unique &Unik For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Untuk membatasi indeks hanya ke suatu bagian dari tabel Anda dapat menyatakan suatu klausa WHERE di sini yang memilih bagian dari tabel yang mesti diindeks Partial inde&x clause &Klausa indeks parsial Colu&mns Kolo&m Table column Kolom tabel Type Tipe Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Menambah sebuah kolom ekspresi baru ke indeks. Kolom ekspresi memuat pernyataan SQL, bukan nama-nama kolom. Index column Kolom indeks Deleting the old index failed: %1 Menghapus indeks lama gagal: %1 Creating the index failed: %1 Membuat indeks gagal: %1 EditTableDialog Edit table definition Sunting definisi tabel Table Tabel Advanced Tingkat lanjut Without Rowid Tanpa Rowid Database sche&ma Ske&ma basis data Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Saat Konflik Strict Ketat When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Ketika opsi ketat difungsikan, SQLite memaksakan tipe data dari setiap kolom ketika memperbarui atau menyisipkan data. Fields Ruas Add Tambah Remove Hapus Move to top Pindah ke puncak Move up Naikkan Move down Turunkan Move to bottom Pindah ke dasar Name Nama Type Tipe NN NN Not null Tidak null PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> Kunci primer</p></body></html> AI AI Autoincrement Inkremen otomatis U U Unique Unik Default Baku Default value Nilai baku Check Periksa Check constraint Periksa konstrain Collation Kolasi Foreign Key Foreign Key <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Index Constraints Konstrain Indeks Add constraint Tambah konstrain Remove constraint Hapus konstrain Columns Kolom SQL SQL Foreign Keys Foreign Key References Referensi Check Constraints Periksa Konstrain <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Peringatan: </span>Ada sesuatu pada definisi tabel ini yang parser kami tidak sepenuhnya paham. Mengubah dan menyimpan tabel ini dapat menyebabkan masalah.</p></body></html> Primary Key Kunci Primer Add a primary key constraint Tambahkan konstrain kunci primer Add a unique constraint Tambahkan konstrain unik There can only be one primary key for each table. Please modify the existing primary key instead. Hanya boleh ada satu kunci primer bagi setiap tabel. Harap ubah kunci primer yang ada sebagai pengganti. Error creating table. Message from database engine: %1 Kesalahan saat membuat tabel. Pesan dari mesin basis data: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Sudah ada ruas dengan nama itu. Harap terlebih dahulu ubah namanya atau pilih suatu nama lain untuk ruas ini. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Kolom ini diacu dalam suatu foreign key dalam tabel %1 sehingga namanya tidak dapat diubah. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Ada paling tidak satu baris dengan ruas ini diatur ke NULL. Menjadi tidak mungkin menata flag ini. Harap ubah data tabel terlebih dahulu. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Ada paling tidak satu baris dengan nilai non integer dalam ruas ini. Menjadi tidak mungkin menata flag AI. Harap ubah data tabel terlebih dahulu. Column '%1' has duplicate data. Kolom '%1' punya data duplikat. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Menjadi tidak mungkin memfungsikan flag 'Unik'. Harap hapus data duplikat, yang akan mengizinkan flag 'Unik' untuk difungsikan. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Anda yakin ingin menghapus ruas '%1'? Semua data yang saat ini disimpan dalam ruas ini akan hilang. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Harap tambahkan suatu ruas yang memenuhi kriteria berikut sebelum menata flag tanpa rowid: - Flag kunci primer ditata - Inkremen otomatis dinonaktifkan Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set Harap tambahkan suatu ruas yang memenuhi kriteria berikut sebelum menata aksi saat konflik: - Flag kunci primer ditata ExportDataDialog Export data as CSV Ekspor data sebagai CSV Tab&le(s) Tabe&l Colu&mn names in first line Nama-nama kolo&m dalam baris pertama Fie&ld separator Pemisah rua&s , , ; ; Tab Tab | | Other Lainnya &Quote character Karakter &kutip " " ' ' New line characters Karakter baris baru Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print Cetak cantik Could not open output file: %1 Tidak bisa membuka berkas keluaran: %1 Choose a filename to export data Pilih suatu nama berkas untuk mengekspor data Export data as JSON Ekspor data sebagai JSON exporting CSV mengekspor CSV Error while writing the file '%1': %2 Kesalahan saat menulis berkas '%1': %2 exporting JSON mengekspor JSON Please select at least 1 table. Harap pilih setidaknya 1 tabel. Choose a directory Pilih suatu direktori Export completed. Ekspor selesai. Export finished with errors. Ekspor selesai dengan kesalahan. ExportSqlDialog Export SQL... Ekspor SQL... Tab&le(s) Tabe&l Select All Pilih Semua Deselect All Pilih Tak Satu Pun &Options &Opsi Keep column names in INSERT INTO Pertahankan nama-nama kolom dalam INSERT INTO Multiple rows (VALUES) per INSERT statement Beberapa baris (VALUES) per pernyataan INSERT Export everything Ekspor semuanya Export data only Hanya ekspor data Keep original CREATE statements Pertahankan pernyataan CREATE asli Keep old schema (CREATE TABLE IF NOT EXISTS) Pertahankan skema lama (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Timpa skema lama (DROP TABLE, lalu CREATE TABLE) Export schema only Ekspor skema saja Please select at least one table. Harap pilih paling tidak satu tabel. Choose a filename to export Pilih suatu nama berkas untuk ekspor Export completed. Ekspor selesai. Export cancelled or failed. Ekspor dibatalkan atau gagal. ExtendedScintilla Ctrl+H Ctrl+H Ctrl+F Ctrl+F Ctrl+P Ctrl+P Find... Cari... Find and Replace... Cari dan Ganti... Print... Cetak... ExtendedTableWidget Use as Exact Filter Gunakan sebagai Filter Eksak Containing Memuat Not containing Tidak memuat Not equal to Tidak sama dengan Greater than Lebih dari Less than Kurang dari Greater or equal Lebih dari atau sama dengan Less or equal Kurang dari atau sama dengan Between this and... Antara ini dan... Regular expression Ekspresi reguler Edit Conditional Formats... Sunting Format Bersyarat... Set to NULL Atur ke NULL Cut Potong Copy Salin Copy with Headers Salin dengan Header Copy as SQL Salin sebagai SQL Paste Tempel Print... Cetak... Use in Filter Expression Pakai dalam Ekspresi Filter Alt+Del Alt+Del Ctrl+Shift+C Ctrl+Shift+C Ctrl+Alt+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? Konten papan klip lebih besar daripada rentang yang dipilih. Tetap disisipkan? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>Belum semua data dimuat. <b>Apakah Anda ingin memuat semua data sebelum memilih semua baris?</b><p><p>Menjawab <b>Tidak</b> berarti tidak ada lagi data yang akan dimuat dan pemilihan tidak akan dilaksanakan.<br/>Menjawab <b>Ya</b> mungkin akan makan waktu ketika data dimuat tapi pemilihan akan lengkap.</p>Peringatan: Memuat semua data mungkin memerlukan sejumlah besar memori untuk tabel-tabel besar. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. Tidak bisa menata pilihan ke NULL. Kolom %1 memiliki konstrain NOT NULL. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. FileExtensionManager File Extension Manager Manajer Ekstensi Berkas &Up &Naik &Down &Turun &Add T&ambah &Remove &Hapus Description Deskripsi Extensions Ekstensi *.extension *.extension FilterLineEdit Filter Filter These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Ruas masukan ini memungkinkan Anda melakukan penyaringan cepat dalam tabel yang saat ini sedang dipilih. Secara baku, baris yang memuat teks masukan disaring. Operator berikut juga didukung: % Wildcard > Lebih dari < Kurang dari >= Sama dengan atau lebih dari <= Sama dengan atau kurang dari = Sama dengan: cocok eksak <> Tidak sama dengan: ketidakcocokan eksak x~y Rentang: nilai antara x dan y /regexp/ Nilai yang cocok dengan ekspresi reguler Clear All Conditional Formats Bersihkan Semua Format Bersyarat Use for Conditional Format Gunakan untuk Format Bersyarat Edit Conditional Formats... Sunting Format Bersyarat... Set Filter Expression Atur Ekspresi Filter What's This? Apa Ini? Is NULL NULL Is not NULL Bukan NULL Is empty Kosong Is not empty Tidak kosong Not containing... Tidak memuat... Equal to... Sama dengan... Not equal to... Tidak sama dengan... Greater than... Lebih dari... Less than... Kurang dari... Greater or equal... Lebih dari atau sama dengan... Less or equal... Kurang dari atau sama dengan... In range... Dalam rentang... Regular expression... Ekspresi reguler... FindReplaceDialog Find and Replace Cari dan Ganti Fi&nd text: &Cari teks: Re&place with: &Ganti dengan: Match &exact case Cocok b&esar kecil huruf Match &only whole words C&ocok hanya ke kata lengkap When enabled, the search continues from the other end when it reaches one end of the page Saat difungsikan, pencarian berlanjut dari ujung lain ketika itu mencapai suatu ujung dari halaman &Wrap around Putar &balik When set, the search goes backwards from cursor position, otherwise it goes forward Saat ditata, pencarian dilakukan ke arah mundur dari posisi kursor, bila tidak itu ke arah maju Search &backwards Cari &mundur <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>Saat dicentang, pola yang akan dicari hanya dicari pada pilihan saat ini.</p></body></html> &Selection only &Hanya pilihan <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Saat dicentang, pola yang akan dicari diinterpretasikan sebagai suatu ekspresi reguler UNIX. Lihat <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Ekspresi Reguler dalam Wikibook</a>.</p></body></html> Use regular e&xpressions Pakai e&kspresi reguler Find the next occurrence from the cursor position and in the direction set by "Search backwards" Cari kemunculan berikutnya dari posisi kursor dan dalam arah yang diatur oleh "Cari mundur" &Find Next &Cari Selanjutnya F3 F3 &Replace &Ganti Highlight all the occurrences of the text in the page Soroti semua kemunculan teks dalam halaman F&ind All Car&i Semua Replace all the occurrences of the text in the page Ganti semua kemunculan teks dalam halaman Replace &All Ganti Semu&a The searched text was not found Teks yang dicari tidak ditemukan The searched text was not found. Teks yang dicari tidak ditemukan. The searched text was found one time. Teks yang dicari ditemukan satu kali. The searched text was found %1 times. Teks yang dicari ditemukan %1 kali. The searched text was replaced one time. Teks yang dicari diganti satu kali. The searched text was replaced %1 times. Teks yang dicari diganti %1 kali. ForeignKeyEditor &Reset &Reset Foreign key clauses (ON UPDATE, ON DELETE etc.) Klausa foreign key (ON UPDATE, ON DELETE dsb.) ImageViewer Image Viewer Penampil Citra Reset the scaling to match the original size of the image. Reset skala agar cocok dengan ukuran asli citra. Set the scaling to match the size of the viewport. Tata skala agar cocok dengan ukuran viewport. Print... Cetak... Open preview dialog for printing displayed image Buka dialog pratinjau untuk mencetak citra yang ditampilkan Ctrl+P Ctrl+P ImportCsvDialog Import CSV file Impor berkas CSV Table na&me Na&ma tabel &Column names in first line Nama &kolom pada baris pertama Field &separator Pemi&sah ruas , , ; ; Tab Tab | | Other Lainnya &Quote character Karakter kuti&p Other (printable) Lainnya (dapat dicetak) Other (code) Lainnya (kode) " " ' ' &Encoding P&engkodean UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? Pangkas ruas? Separate tables Pisahkan tabel-tabel Advanced Tingkat lanjut When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Ketika mengimpor suatu nilai kosong dari berkas CSV ke dalam tabel yang telah ada dengan suatu nilai baku bagi kolom ini, nilai baku tersebut disisipkan. Aktifkan opsi ini untuk menyisipkan nilai kosong sebagai pengganti. Ignore default &values Abaikan nilai-nilai &baku Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Aktifkan opsi ini untuk menghentikan impor ketika mencoba mengimpor suatu nilai kosong ke dalam kolom NOT NULL tanpa suatu nilai baku. Fail on missing values Gagal saat ada nilai yang hilang Disable data type detection Nonaktifkan deteksi tipe data Disable the automatic data type detection when creating a new table. Nonaktifkan deteksi tipe data otomatis ketika membuat sebuah tabel baru. Use local number conventions Gunakan konvensi bilangan lokal Use decimal and thousands separators according to the system locale. Gunakan pemisah desimal dan ribuan sesuai dengan lokal sistem. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Ketika mengimpor ke dalam suatu tabel yang telah ada dengan sebuah kunci primer, konstrain unik, atau suatu indeks unik, ada kemungkinan konflik. Opsi ini memungkinkan Anda memilih suatu strategi untuk kasus tersebut. Secara baku impor digugurkan dan di-roll back tapi Anda bisa juga memilih untuk mengabaikan dan tidak mengimpor baris-baris yang konflik atau untuk menggantikan baris yang ada dalam tabel. Abort import Tentang impor Ignore row Abaikan baris Replace existing row Gantikan baris saat ini Conflict strategy Strategi konflik Deselect All Hapus Semua Pilihan Match Similar Cocok Serupa Select All Pilih Semua There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Sudah ada tabel bernama '%1' dan suatu impor ke tabel yang telah ada hanya mungkin bila cacah kolom cocok. There is already a table named '%1'. Do you want to import the data into it? Sudah ada tabel bernama '%1'. Apakah Anda ingin mengimpor data ke dalamnya? Creating restore point failed: %1 Gagal membuat titik pemulihan: %1 Creating the table failed: %1 Gagal membuat tabel: %1 importing CSV mengimpor CSV Could not prepare INSERT statement: %1 Tidak bisa mempersiapkan pernyataan INSERT: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Akhir berkas yang tak diduga. Harap pastikan bahwa Anda telah mengonfigurasi karakter kutip yang benar dan berkas tidak salah bentuk. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Mengimpor berkas '%1' makan waktu %2 ms. %3 ms dari total itu dihabiskan dalam fungsi baris. Inserting row failed: %1 Gagal menyisipkan baris: %1 MainWindow DB Browser for SQLite Peramban DB untuk SQLite toolBar1 bilahAlat1 Opens the SQLCipher FAQ in a browser window Membuka FAQ SQL Cipher dalam sebuah jendela peramban Export one or more table(s) to a JSON file Ekspor satu tabel atau lebih ke berkas JSON &File &Berkas &Import &Impor &Export &Ekspor &Edit &Sunting &View &Tilik &Help B&antuan DB Toolbar Bilah Alat DB Edit Database &Cell &Sunting Sel Basis Data DB Sche&ma Ske&ma DB &Remote &Remote Execute current line Eksekusi baris kini This button executes the SQL statement present in the current editor line Tombol ini mengeksekusi pernyataan SQL yang ada dalam baris penyunting saat ini Shift+F5 Shift+F5 Sa&ve Project Simpan Pro&yek Open an existing database file in read only mode Buka berkas basis data yang ada dalam mode hanya baca User Pengguna This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Ini adalah struktur dari basis data yang dibuka. Anda dapat menyeret pernyataan SQL dari suatu baris objek dan menjatuhkan mereka ke dalam aplikasi lain atau ke dalam instansi lain dari 'Peramban DB untuk SQLite'. Un/comment block of SQL code Jadikan komentar/bukan komentar blok kode SQL Un/comment block Jadikan komentar/bukan komentar blok Comment or uncomment current line or selected block of code Jadikan komentar/bukan komentar baris saat ini atau blok kode yang dipilih Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Jadikan komentar/bukan komentar baris yang dipilih atau baris saat ini, bila tidak ada yang dipilih. Seluruh blok dijungkitkan menurut baris pertama. Ctrl+/ Ctrl+/ Stop SQL execution Hentikan eksekusi SQL Stop execution Hentikan eksekusi Stop the currently running SQL script Hentikan skrip SQL yang saat ini sedang berjalan Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Peringatan: pragma ini tidak dapat dibaca dan nilai ini telah disimpulkan. Menulis pragma mungkin menimpa suatu LIKE yang didefinisikan ulang yang disediakan oleh sebuah ekstensi SQLite. Too&ls Pera&latan Application Aplikasi Error Log Log Kesalahan This button clears the contents of the SQL logs Tombol ini membersihkan isi log SQL &Clear &Bersihkan This panel lets you examine a log of all SQL commands issued by the application or by yourself Panel ini memungkinkan Anda memeriksa log dari semua perintah SQL yang diberikan oleh aplikasi atau oleh Anda sendiri This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Ini adalah struktur dari basis data yang dibuka. Anda dapat menyeret beberapa nama obyek dari kolom Nama dan menjatuhkan mereka ke dalam penyunting SQL dan Anda dapat menyetel properti dari nama-nama yang dijatuhkan memakai menu konteks. Ini akan membantu Anda dalam menyusun pernyataan SQL. Anda dapat menyeret pernyataan SQL dari kolom Skema dan menjatuhkan mereka ke dalam penyunting SQL atau ke dalam aplikasi lain. Project Toolbar Bilah Alat Proyek Extra DB toolbar Bilah alat DB ekstra Close the current database file Tutup berkas basis data saat ini &New Database... &Basis Data Baru... Create a new database file Buat suatu berkas basis data baru This option is used to create a new database file. Opsi ini dipakai untuk membuat sebuah berkas basis data baru. Ctrl+N Ctrl+N &Open Database... Buk&a Basis Data... Open an existing database file Buka sebuah berkas basis data yang ada This option is used to open an existing database file. Opsi ini dipakai untuk membuka sebuah berkas basis data yang ada. Ctrl+O Ctrl+O &Close Database &Tutup Basis Data This button closes the connection to the currently open database file Tombol ini menutup koneksi ke berkas basis data yang saat ini terbuka Ctrl+W Ctrl+W Revert database to last saved state Pulihkan basis data ke keadaan tersimpan terakhir This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Opsi ini dipakai untuk memulihkan berkas basis data saat ini ke keadaan tersimpan terakhir. Semua perubahan yang dibuat sejak operasi simpan terakhir hilang. Write changes to the database file Tulis perubahan ke berkas basis data This option is used to save changes to the database file. Opsi ini dipakai untuk menyimpan perubahan ke berkas basis data. Ctrl+S Ctrl+S Compact &Database... Mampatkan Basis &Data... Compact the database file, removing space wasted by deleted records Memampatkan berkas basis data, menghapus ruang yang terbuang oleh record yang dihapus Compact the database file, removing space wasted by deleted records. Memampatkan berkas basis data, menghapus ruang yang terbuang oleh record yang dihapus. E&xit &Keluar Ctrl+Q Ctrl+Q Import data from an .sql dump text file into a new or existing database. Impor data dari sebuah berkas teks dump sql ke dalam basis data baru atau yang ada. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Opsi ini memungkinkan Anda mengimpor data dari berkas teks curah .sql ke dalam basis data baru atau yang ada. Berkas curah SQL dapat dibuat pada kebanyakan mesin basis data, termasuk MySQL dan PostgreSQL. Open a wizard that lets you import data from a comma separated text file into a database table. Membuka suatu wahana pandu yang mengizinkan Anda mengimpor data dari berkas teks dengan pemisah koma ke dalam tabel basis data. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Opsi ini membuka suatu wahana pandu yang memungkinkan Anda mengimpor data dari berkas teks dipisah koma ke dalam tabel basis data. Berkas CSV dapat dibuat pada kebanyakan aplikasi basis data dan lembar kerja. Export a database to a .sql dump text file. Ekspor suatu basis data ke sebuah berkas teks curah .sql. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Opsi ini memungkinkan Anda mengekspor sebuah basis data ke suatu berkas teks curah .sql. Berkas curah SQL memuat semua data yang diperlukan untuk mencipta ulang basis data pada kebanyakan mesin basis data, termasuk MySQL dan PostgreSQL. Export a database table as a comma separated text file. Ekspor suatu tabel basis data sebagai sebuah berkas teks yang dipisah koma. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Ekspor suatu tabel basis data sebagai berkas teks yang dipisah koma, siap untuk diimpor ke dalam aplikasi lembar kerja atau basis data lain. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Membuka wahana pandu Buat Tabel, dimana mungkin untuk mendefinisikan nama dan ruas bagi suatu tabel baru dalam basis data Delete Table Hapus Tabel Open the Delete Table wizard, where you can select a database table to be dropped. Membuka wahana pandu Hapus Tabel, dimana Anda dapat memilih sebuah tabel basis data yang akan di-drop. Open the Create Index wizard, where it is possible to define a new index on an existing database table. Membuka wahana pandu Buat Indeks, dimana mungkin untuk mendefinisikan sebuah indeks baru pada tabel basis data yang ada. &Preferences... &Preferensi... Open the preferences window. Buka jendela preferensi. &DB Toolbar Bilah Alat &DB Shows or hides the Database toolbar. Menampilkan atau menyembunyikan bilah alat Basis Data. Shift+F1 Shift+F1 New &tab &Tab baru Open SQL file(s) Buka berkas SQL This button opens files containing SQL statements and loads them in new editor tabs Tombol ini membuka berkas yang memuat pernyataan SQL dan memuat mereka dalam tab penyunting baru Execute line Eksekusi baris &Wiki &Wiki F1 F1 Bug &Report... Lapo&ran Bug... Feature Re&quest... Per&mintaan Fitur... Web&site &Situs Web &Donate on Patreon... &Donasi di Patreon... &Save Project &Simpan Proyek This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Tombol ini memungkinkan Anda menyimpan semua pengaturan terkait DB yang terbuka ke suatu berkas proyek Peramban DB untuk SQLite Open &Project Buka &Proyek This button lets you open a DB Browser for SQLite project file Tombol ini memungkinkan Anda membuka suatu berkas proyek Peramban DB untuk SQLite Ctrl+Shift+O Ctrl+Shift+O &Save Project As... &Simpan Proyek Sebagai... Save the project in a file selected in a dialog Simpan proyek dalam suatu berkas yang dipilih dalam sebuah dialog Save A&ll Simpan Se&mua Save DB file, project file and opened SQL files Simpan berkas DB, berkas proyek, dan berkas SQL yang dibuka Ctrl+Shift+S Ctrl+Shift+S Browse Table Ramban Tabel Close Pro&ject Tutup Pro&yek Close project and database files and return to the initial state Tutup berkas basis data dan proyek, dan kembali ke keadaan awal Ctrl+Shift+F4 Ctrl+Shift+F4 Detach Database Lepas Cantolan Basis Data Detach database file attached to the current database connection Lepas cantolan berkas basis data yang tercantol ke koneksi basis data saat ini &Attach Database... C&antol Basis Data... Add another database file to the current database connection Tambahkan berkas basis data lain ke koneksi basis data saat ini This button lets you add another database file to the current database connection Tombol ini memungkinkan Anda menambah berkas basis data lain ke koneksi basis data saat ini &Set Encryption... Atur Enkrip&si... SQLCipher &FAQ &FAQ SQLCipher Table(&s) to JSON... Tabel ke J&SON... Open Data&base Read Only... &Buka Basis Data Hanya-Baca... Save results Simpan hasil Save the results view Simpan view hasil This button lets you save the results of the last executed query Tombol ini memungkinkan Anda menyimpan hasil dari query yang terakhir dieksekusi Find text in SQL editor Cari teks dalam penyunting SQL Find Cari This button opens the search bar of the editor Tombol ini membuka bilah pencarian dari penyunting Ctrl+F Ctrl+F Find or replace text in SQL editor Cari atau ganti teks dalam penyunting SQL Find or replace Cari atau ganti This button opens the find/replace dialog for the current editor tab Tombol ini membuka dialog cari/ganti untuk tab penyunting saat ini Ctrl+H Ctrl+H Export to &CSV Ekspor ke &CSV Export to &JSON Ekspor ke &JSON Save as &view Simpan sebagai &view Save as view Simpan sebagai view Shows or hides the Project toolbar. Menampilkan atau menyembunyikan bilah alat Proyek. Extra DB Toolbar Bila Alat DB Ekstra &Open Database Buk&a Basis Data New In-&Memory Database Basis Data Dalam &Memori Baru Drag && Drop SELECT Query Seret && Jatuhkan Query SELECT When dragging fields from the same table or a single table, drop a SELECT query into the editor Ketika menyeret ruas dari tabel yang sama atau suatu tabel tunggal, menjatuhkan suatu query SELECT ke dalam penyunting Drag && Drop Qualified Names Seret && Jatuhkan Qualified Name Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Pakai qualified name (mis. "Table"."Field") ketika menyeret objek dan menjatuhkan mereka ke dalam penyunting Drag && Drop Enquoted Names Seret && Jatuhkan Nama Berkutip Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Pakai identifier berkutip (mis. "Table1") ketika menyeret objek dan menjatuhkan mereka ke dalam penyunting &Integrity Check Pemeriksaan &Integritas Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. Menjalankan pragma integrity_check atas basis data yang terbuka dan mengembalikan hasil dalam tab Jalankan SQL. Pragma ini melakukan pemeriksaan integritas dari seluruh basis data. &Foreign-Key Check Pemeriksaan &Foreign-Key Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Menjalankan pragma foreign_key_check atas basis data yang terbuka dan mengembalikan hasil dalam tab Jalankan SQL &Quick Integrity Check Pemeri&ksaan Cepat Integritas Run a quick integrity check over the open DB Menjalankan pemeriksaan cepat atas integritas pada DB yang terbuka Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. Menjalankan pragma quick_check atas basis data yang terbuka dan mengembalikan hasil dalam tab Jalankan SQL. Perintah ini melakukan hampir seluruh pemeriksaan dari PRAGMA integrity_check tapi berjalan jauh lebih cepat. &Optimize &Optimasikan Attempt to optimize the database Mencoba mengoptimasi basis data Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Menjalankan pragma optimasi atas basis data yang dibuka. Pragma ini mungkin melakukan optimasi yang akan memperbaiki kinerja dari query di masa mendatang. Print Cetak Print text from current SQL editor tab Cetak teks dari tab penyunting SQL saat ini Open a dialog for printing the text in the current SQL editor tab Membuka suatu dialog untuk mencetak teks dalam tab penyunting SQL saat ini Print the structure of the opened database Cetak struktur dari basis data yang dibuka Open a dialog for printing the structure of the opened database Membuka suatu dialog untuk mencetak struktur dari basis data yang dibuka Ctrl+Shift+W Ctrl+Shift+W Table from CSV data in Clipboard... Tabel dari data CSV dalam Papan Klip... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Ini memperlakukan konten papan klip saat ini sebagai suatu berkas CSV dan membuka wahana pandu impor yang sama dengan yang dipakai untuk mengimpor data CSV dari suatu berkas. Show &Row Counts Tampilkan Cacah Ba&ris This shows the number of rows for each table and view in the database. Ini menampilkan cacah baris bagi setiap tabel dan view dalam basis data. Save Database &As... Simpan Basis Data Seb&agai... Save the current database as a different file Menyimpan basis data saat ini sebagai suatu berkas yang berbeda Refresh Segarkan Reload the database structure Memuat ulang struktur basis data &Recently opened Ba&ru-baru ini dibuka Ctrl+T Ctrl+T SQL &Log &Log SQL &Database Structure This has to be equal to the tab title in all the main tabs Struktur Basis &Data &Browse Data This has to be equal to the tab title in all the main tabs Ram&ban Data Edit P&ragmas This has to be equal to the tab title in all the main tabs Sunting P&ragma E&xecute SQL This has to be equal to the tab title in all the main tabs Jalan&kan SQL &Recent Files Be&rkas Baru-baru Ini Show S&QL submitted by Tampilkan S&QL yang dikirim oleh &Plot &Plot &New Database &Basis Data Baru Ctrl+F4 Ctrl+F4 &Revert Changes Balikkan Pe&rubahan &Undo Tak Ja&di Undo last change to the database Batalkan perubahan terakhir ke basis data This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Aksi ini membatalkan perubahan terakhir yang dilakukan ke basis data dalam Peramban Basis Data atau dalam Jalankan SQL. Menjalankan ulang tidak mungkin. &Write Changes &Tulis Perubahan &Database from SQL file... Basis &data dari berkas SQL... &Table from CSV file... &Tabel dari berkas CSV... &Database to SQL file... Basis &data ke berkas SQL... &Table(s) as CSV file... &Tabel sebagai berkas CSV... &Create Table... &Buat Tabel... &Delete Table... &Hapus Tabel... &Modify Table... &Ubah Tabel... Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Membuka wahana pandu Ubah Tabel, dimana dimungkinkan mengubah nama suatu tabel yang ada. Juga mungkin untuk menambah atau menghapus ruas dari suatu tabel, maupun mengubah nama dan tipe ruas. Create &Index... Buat &Indeks... W&hat's This? Apa &Ini? &About Perih&al This button opens a new tab for the SQL editor Tombol ini membuka suatu tab baru bagi penyunting SQL &Execute SQL &Eksekusi SQL Execute all/selected SQL Eksekusi semua/SQL yang dipilih This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Tombol ini mengeksekusi pernyataan SQL yang saat ini dipilih. Bila tidak ada teks yang dipilih, semua pernyataan dieksekusi. Ctrl+Shift+T Ctrl+Shift+T Save SQL file Simpan berkas SQL &Load Extension... &Muat Ekstensi... Ctrl+E Ctrl+E Export as CSV file Ekspor sebagai berkas CSV Export table as comma separated values file Ekspor tabel sebagai berkas nilai yang dipisah koma Save the current session to a file Simpan sesi saat ini ke suatu berkas Open &Project... Buka &Proyek... Load a working session from a file Muat suatu sesi kerja dari sebuah berkas Save SQL file as Simpan berkas SQL sebagai This button saves the content of the current SQL editor tab to a file Tombol ini menyimpan isi dari tab penyunting SQL saat ini ke sebuah berkas &Browse Table Ram&ban Tabel Copy Create statement Salin pernyataan Create Copy the CREATE statement of the item to the clipboard Salin pernyataan CREATE dari butir ke papan klip Ctrl+Return Ctrl+Return Ctrl+L Ctrl+L Ctrl+P Ctrl+P Ctrl+D Ctrl+D Ctrl+I Ctrl+I Encrypted Terenkripsi Read only Hanya baca Database file is read only. Editing the database is disabled. Berkas basis data hanya baca. Menyunting basis data dinonaktifkan. Database encoding Pengkodean basis data Database is encrypted using SQLCipher Basis data terenkripsi memakai SQLCipher Choose a database file Pilh suatu berkas basis data Choose a filename to save under Pilih suatu nama berkas untuk tempat menyimpan Error checking foreign keys after table modification. The changes will be reverted. Kesalahan saat memeriksa foreign key setelah modifikasi tabel. Perubahan akan dibalikkan. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Tabel ini tidak lolos pemeriksaan foreign key.<br/>Anda mesti menjalankan 'Alat | Pemeriksaan Foreign Key' dan memperbaiki masalah-masalah yang dilaporkan. At line %1: Pada baris %1: Result: %2 Hasil: %2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Menata nilai PRAGMA atau mem-vacuum akan meng-commit transaksi Anda saat ini. Anda yakin? Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Kesalahan saat menyimpan berkas basis data. Ini berarti bahwa tidak semua perubahan ke basis data disimpan. Anda perlu terlebih dahulu menyelesaikan kesalahan berikut. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? Anda yakin ingin membatalkan semua perubahan yang dibuat ke berkas basis data '%1' sejak penyimpanan terakhir? Choose a file to import Pilih suatu berkas yang akan diimpor Text files(*.sql *.txt);;All files(*) Berkas teks(*.sql *.txt);;Semua berkas(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Apakah Anda ingin membuat suatu berkas basis data baru untuk menampung data yang diimpor? Bila Anda menjawab tidak kami akan mencoba mengimpor data dalam berkas SQL ke basis data saat ini. Automatically load the last opened DB file at startup You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Anda masih mengeksekusi pernyataan SQL. Menutup basis data sekarang akan menghentikan eksekusi mereka, kemungkinkan meninggalkan basis data dalam keadaan tidak konsisten. Anda yakin hendak menutup basis data? Do you want to save the changes made to the project file '%1'? Apakah Anda ingin menyimpan perubahan yang dibuat ke berkas proyek '%1'? File %1 already exists. Please choose a different name. Berkas %1 sudah ada. Harap pilih nama lain. Error importing data: %1 Kesalahan saat mengimpor data: %1 Import completed. Impor selesai. Delete View Hapus View Modify View Ubah View Delete Trigger Hapus Trigger Modify Trigger Ubah Trigger Delete Index Hapus Indeks Modify Index Ubah Indeks Modify Table Ubah Tabel Do you want to save the changes made to SQL tabs in a new project file? Apakah Anda ingin menyimpan perubahan yang dibuat ke tab SQL dalam suatu berkas proyek baru? Do you want to save the changes made to the SQL file %1? Apakah Anda ingin menyimpan perubahan yang dibuat ke berkas SQL %1? Could not find resource file: %1 Tidak bisa menemukan berkas sumber daya: %1 Choose a project file to open Pilih sebuah berkas proyek untuk dibuka Could not open project file for writing. Reason: %1 Tidak bisa membuka berkas proyek untuk ditulisi. Alasan: %1 Busy (%1) Sibuk (%1) Setting PRAGMA values will commit your current transaction. Are you sure? Menata nilai PRAGMA akan meng-commit transaksi Anda saat ini. Anda yakin? Reset Window Layout Reset Tata Letak Jendela The database is currently busy. Basis data saat ini sibuk. Click here to interrupt the currently running query. Klik di sini untuk mengiterupsi query yang sedang berjalan. Ctrl+Alt+W Ctrl+Alt+W Could not open database file. Reason: %1 Tidak bisa membuka berkas basis data. Alasan: %1 In-Memory database Basis data dalam memori Choose a database file to save under Pilih suatu berkas basis data tempat menyimpan Error while saving the database to the new file. Kesalahan saat menyimpan basis data ke berkas baru. Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Anda yakin ingin menghapus tabel '%1'? Semua data terkait dengan tabel akan hilang. Are you sure you want to delete the view '%1'? Anda yakin ingin menghapus view '%1'? Are you sure you want to delete the trigger '%1'? Anda yakin ingin menghapus trigger '%1'? Are you sure you want to delete the index '%1'? Anda yakin ingin menghapus indeks '%1'? Error: could not delete the table. Kesalahan: tidak bisa menghapus tabel. Error: could not delete the view. Kesalahan: tidak bisa menghapus view. Error: could not delete the trigger. Kesalahan: tidak bisa menghapus trigger. Error: could not delete the index. Kesalahan: tidak bisa menghapus indeks. Message from database engine: %1 Pesan dari mesin basis data: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Menyunting tabel memerlukan menyimpan semua perubahan tertunda sekarang. Anda yakin ingin menyimpan basis data? Edit View %1 Sunting View %1 Edit Trigger %1 Sunting Trigger %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. Anda telah sedang mengeksekusi pernyataan SQL. Apakah Anda ingin menghentikan mereka untuk mengeksekusi pernyataan saat ini sebagai pengganti? Perhatikan bahwa ini mungkin meninggalkan basis data dalam keadaan yang tidak konsisten. -- EXECUTING SELECTION IN '%1' -- -- MENGEKSEKUSI PILIHAN DALAM '%1' -- -- EXECUTING LINE IN '%1' -- -- MENGEKSEKUSI BARIS DALAM '%1' -- -- EXECUTING ALL IN '%1' -- -- MENGEKSEKUSI SEMUA DALAM '%1' -- Result: %1 Hasil: %1 %1 rows returned in %2ms %1 baris dikembalikan dalam %2 ms Choose text files Pilih berkas teks Import completed. Some foreign key constraints are violated. Please fix them before saving. Impor selesai. Beberapa konstrain foreign key dilanggar. Harap perbaiki mereka sebelum menyimpan. Opened '%1' in read-only mode from recent file list Membuka '%1' dalam mode hanya baca dari daftar berkas terkini Opened '%1' from recent file list Membuka '%1' dari daftar berkas terkini &%1 %2%3 &%1 %2%3 (read only) (hanya baca) Open Database or Project Buka Basis Data atau Proyek Attach Database... Cantol Basis Data... Import CSV file(s)... Impor berkas CSV... Do you want to save the changes made to SQL tabs in the project file '%1'? Apakah Anda ingin menyimpan perubahan yang dibuat ke tab SQL dalam berkas proyek '%1'? The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? Pernyataan dalam tab '%1' masih sedang dieksekusi. Menutup tab akan menghentikan eksekusi. Ini mungkin membuat basis data dalam keadaan tidak konsisten. Anda yakin ingin menutup tab? Select SQL file to open Pilih berkas SQL yang akan dibuka DB file '%1' could not be opened Berkas DB '%1' tidak dapat dibuka This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Berkas proyek ini memakai format berkas lama karena itu dibuat memakai Peramban DB untuk SQLite versi 3.10 atau sebelumnya. Memuat format berkas ini tidak lagi didukung sepenuhnya. Bila Anda ingin memuatnya secara lengkap, harap gunakan Peramban DB untuk SQLite versi 3.12 untuk mengubahnya ke format berkas baru. Table '%1' not found; settings ignored Tabel '%1' tidak ditemukan, pengaturan diabaikan -- Reference to file "%1" (not supported by this version) -- -- Referensi ke berkas "%1" (tidak didukung oleh versi ini) -- Yes. Don't ask again Ya. Jangan tanyakan lagi This action will open a new SQL tab with the following statements for you to edit and run: Aksi ini akan membuka sebuah tab SQL baru dengan pernyataan berikut untuk Anda sunting dan jalankan: Rename Tab Ubah Nama Tab Duplicate Tab Duplikatkan Tab Close Tab Tutup Tab Opening '%1'... Membuka '%1'... There was an error opening '%1'... Ada kesalahan saat membuka '%1'... Value is not a valid URL or filename: %1 Nilai bukanlah URL atau nama berkas yang valid: %1 Select file name Pilih nama berkas Ctrl+Tab Ctrl+Tab Ctrl+Shift+Tab Ctrl+Shift+Tab Clear List Bersihkan Daftar Window Layout Tata Letak Jendela Ctrl+Alt+0 Ctrl+Alt+0 Simplify Window Layout Sederhanakan Tata Letak Jendela Alt+Shift+0 Alt+Shift+0 Dock Windows at Bottom Tambatkan Jendela ke Bawah Dock Windows at Left Side Tambatkan Jendela ke Sisi Kiri Dock Windows at Top Tambatkan Jendela ke Atas Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Pilih aksi yang akan diterapkan ke berkas yang dijatuhkan. <br/>Catatan: hanya 'Impor' yang akan memroses lebih dari %n berkas. Select extension file Pilih berkas ekstensi Extension successfully loaded. Ekstensi sukses dimuat. Error loading extension: %1 Kesalahan saat memuat ekstensi: %1 Don't show again Jangan tampilkan lagi New version available. Tersedia versi baru. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Tersedia sebuah versi baru Peramban DB bagi SQLite (%1.%2.%3).<br/><br/>Harap unduh di <a href='%4'>%4</a>. Project saved to file '%1' Proyek disimpan ke berkas '%1' Collation needed! Proceed? Perlu kolasi! Lanjutkan? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Sebuah tabel dalam basis data ini memerlukan suatu fungsi kolasi khusus '%1' yang aplikasi ini tak bisa sediakan tanpa pengetahuan lebih jauh. Bila Anda memilih melanjutkan, sadari bahwa hal-hal buruk dapat terjadi ke basis data Anda. Buat suatu cadangan! creating collation membuat kolasi Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Menata sebuah nama baru bagi tab SQL. Gunakan karakter '&&' untuk mengizinkan memakai karakter berikut sebagai suatu pintasan papan ketik. Please specify the view name Harap tentukan nama view There is already an object with that name. Please choose a different name. Sudah ada objek dengan nama itu. Harap pilih nama lain. View successfully created. View sukses dibuat. Error creating view: %1 Kesalahan saat membuat view: %1 This action will open a new SQL tab for running: Aksi ini akan membuka sebuah tab SQL baru untuk menjalankan: Press Help for opening the corresponding SQLite reference page. Tekan Bantuan untuk membuka halaman referensi SQLite yang terkait. DB Browser for SQLite project file (*.sqbpro) Berkas proyek Peramban DB bagi SQLite (*.sqbpro) Execution finished with errors. Eksekusi selesai dengan kesalahan. Execution finished without errors. Eksekusi selesai tanpa kesalahan. NullLineEdit Set to NULL Tata ke NULL Alt+Del Alt+Del PlotDock Plot Plot <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Panel ini menunjukkan daftar kolom dari tabel yang saat ini diramban atau query yang baru saja dieksekusi. Anda dapat memilih kolom yang ingin Anda pakai sebagai sumbu X atau Y bagi panel plot di bawah. Tabel menunjukkan tipe sumbu yang terdeteksi yang akan memengaruhi plot yang dihasilkan. Untuk sumbu Y Anda hanya dapat memilih kolom-kolom numerik, tapi untuk sumbu X Anda akan dapat memilih:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Tanggal/Waktu</span>: string dengan format &quot;yyyy-MM-dd hh:mm:ss&quot; atau &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Tanggal</span>: string dengan format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Waktu</span>: string dengan format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: format string lain. Memilih kolom ini sebagai sumbu X akan menghasilkan plot Batang dengan nilai-nilai kolom sebagai label batang.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numerik</span>: nilai bilangan bulat atau riil</li></ul><p>Mengklik ganda sel Y Anda dapat mengubah warna yang dipakai untuk grafik itu.</p></body></html> Columns Kolom X X Y1 Y1 Y2 Y2 Axis Type Tipe Sumbu Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Di sini suatu plot digambar ketika Anda memilih nilai-nilai x dan y di atas. Klik pada titik-titik untuk memilih mereka dalam plot dan dalam tabel. Ctrl+Klik untuk memilih suatu rentang titik. Gunakan roda tetikus untuk mengubah pembesaran dan penyeretan tetikus untuk mengubah rentang sumbu. Pilih sumbu atau label sumbu untuk menyeret dan memperbesar hanya dalam orientasi itu. Line type: Tipe garis: None Nihil Line Garis StepLeft LangkahKiri StepRight LangkahKanan StepCenter LangkahPusat Impulse Impuls Point shape: Bentuk titik: Cross Silang Plus Plus Circle Lingkaran Disc Cakram Square Bujur Sangkar Diamond Permata Star Bintang Triangle Segi Tiga TriangleInverted SegiTigaTerbalik CrossSquare SilangKotak PlusSquare PlusKotak CrossCircle SilangLingkar PlusCircle PlusLingkar Peace Damai <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Simpan plot saat ini...</p><p>Format berkas dipilih oleh ekstensi (png, jpg, pdf, bmp)</p></body></html> Save current plot... Simpan plot saat ini... Load all data and redraw plot Muat semua data dan gambar ulang plot Row # Baris # Copy Salin Print... Cetak... Show legend Tampilkan legenda Stacked bars Batang bertumpuk Fixed number format Format bilangan tetap Date/Time Tanggal/Waktu Date Tanggal Time Waktu Numeric Numerik Label Label Invalid Tidak valid Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Muat semua data dan gambar ulang plot. Peringatan: belum semua data diambil dari tabel karena mekanisme pengambilan parsial. Choose an axis color Pilih suatu warna sumbu Choose a filename to save under Pilih suatu nama berkas untuk tempat menyimpan PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Semua Berkas(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Ada kurva dalam plot ini dan gaya garis yang dipilih hanya bisa diterapkan ke grafik yang diurut berdasarkan X. Urutkan tabel atau query berdasarkan X untuk menghapus kurva atau pilih satu dari gaya yang didukung oleh kurva: Nihil atau Garis. Loading all remaining data for this table took %1ms. Memuat semua sisa data dari tabel ini makan waktu %1 ms. PreferencesDialog Preferences Preferensi &General &Umum Remember last location Ingat lokasi terakhir Always use this location Selalu pakai lokasi ini Remember last location for session only Ingat lokasi terakhir hanya untuk sesi ... ... Default &location &Lokasi baku Lan&guage &Bahasa Automatic &updates Pembar&uan otomatis enabled difungsikan Show remote options Tampilkan opsi remote &Database Basis &data Database &encoding P&engodean basis data Open databases with foreign keys enabled. Membuka basis data dengan foreign key difungsikan. &Foreign keys &Foreign key SQ&L to execute after opening database SQ&L yang akan dieksekusi setelah membuka basis data Data &Browser Peram&ban Data Remove line breaks in schema &view Buang putus baris dalam &tampilan skema Prefetch block si&ze &Ukuran blok prefetch Default field type Tipe ruas baku Font Fonta &Font &Fonta Content Isi Symbol limit in cell Batas simbol dalam sel NULL NULL Regular Biasa Binary Biner Background Latar belakang Filters Filter Threshold for completion and calculation on selection Ambang batas bagi penyelesaian dan kalkulasi saat dipilih Escape character Karakter escape Delay time (&ms) Waktu tunda (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Mengatur waktu tunggu sebelum suatu nilai filter baru diterapkan. Dapat diatur ke 0 untuk menonaktifkan menunggu. &SQL &SQL Context Konteks Colour Warna Bold Tebal Italic Miring Underline Garis bawah Keyword Kata kunci Function Fungsi Table Tabel Comment Komentar Identifier Identifier String String Current line Baris saat ini SQL &editor font size Ukuran fonta p&enyunting SQL Tab size Ukuran tab SQL editor &font &Fonta penyunting SQL Error indicators Indikator kesalahan Hori&zontal tiling Pengubinan hori&zontal If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Bila difungsikan penyunting kode SQL dan view tabel hasilnya ditampilkan bersisian sebagai ganti satu di atas yang lain. Code co&mpletion Pele&ngkapan kode Toolbar style Gaya bilah alat Only display the icon Hanya tampilkan ikon Only display the text Hanya tampilkan teks The text appears beside the icon Teks muncul di sebelah ikon The text appears under the icon Teks muncul di bawah ikon Follow the style Ikuti gaya DB file extensions Ekstensi berkas DB Manage Kelola Main Window Jendela Utama Database Structure Struktur Basis Data Browse Data Ramban Data Execute SQL Jalankan SQL Edit Database Cell Sunting Sel Basis Data When this value is changed, all the other color preferences are also set to matching colors. Saat nilai ini diubah, semua preferensi warna lain juga diatur ke warna yang cocok. Follow the desktop style Ikuti gaya desktop Dark style Gaya gelap Application style Gaya aplikasi This sets the font size for all UI elements which do not have their own font size option. Ini menata ukuran fonta bagi semua elemen UI yang tidak punya opsi ukuran fonta sendiri. Font size Ukuran fonta Max Recent Files Maks Berkas Baru-baru Ini Prompt to save SQL tabs in new project file Tanyakan untuk menyimpan tab SQL dalam berkas proyek baru If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Bila ini dinyalakan, maka perubahan ke penyunting SQL membangkitkan sebuah dialog konfirmasi simpan proyek ketika menutup tab penyunting SQL. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Ketika difungsikan, putus baris dalam kolom Skema dari tab Struktur DB, dok, dan keluaran tercetak dihapus. Database structure font size Ukuran fonta struktur basis data Font si&ze &Ukuran fonta This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Ini adalah cacah maksimum butir yang diizinkan bagi beberapa fungsionalitas yang mahal secara komputasi untuk difungsikan: Banyaknya baris maksimum dalam suatu tabel untuk memfungsikan pelengkapan nilai berdasarkan nilai saat ini dalam kolom. Banyaknya indeks maksimum dalam suatu seleksi untuk menghitung jumlah dan rerata. Dapat diatur ke 0 untuk menonaktifkan fungsionalitas. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Ini adalah cacah baris maksimum dalam suatu tabel untuk memfungsikan pelengkapan nilai berbasis nilai saat ini dalam kolom. Dapat diatur ke 0 untuk menonaktifkan pelengkapan. Show images in cell Tampilkan gambar dalam sel Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Fungsikan opsi ini untuk menampilkan suatu pratinjau dari BLOB yang memuat data citra dalam sel. Namun ini dapat mempengaruhi kinerja peramban data. Field display Tampilan ruas Light style Gaya terang Displayed &text &Teks yang ditampilkan Formatted Diformat Click to set this color Klik untuk menata warna ini Text color Warna teks Background color Warna latar belakang Preview only (N/A) Hanya pratinjau (T/T) Foreground Latar depan Selection background Latar belakang pilihan Selection foreground Latar depan pilihan Highlight Penyorotan SQL &results font size Ukuran fonta &hasil SQL Use tabs for indentation Gunakan tab untuk indentasi When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. Ketika ditata, tombol Tab akan menyisipkan karakter tab dan spasi untuk indentasi. Bila tidak, hanya spasi yang akan dipakai. &Wrap lines &Lipat baris Never Tak Pernah At word boundaries Di perbatasan kata At character boundaries Di perbatasan karakter At whitespace boundaries Di perbatasan ruang putih &Quotes for identifiers &Kutip untuk identifier Choose the quoting mechanism used by the application for identifiers in SQL code. Pilih mekanisme pengutipan yang dipakai oleh aplikasi bagi identifier dalam kode SQL. "Double quotes" - Standard SQL (recommended) "Kutip ganda" - SQL Standar (disarankan) `Grave accents` - Traditional MySQL quotes `Aksen grave` - Kutip tradisional MySQL [Square brackets] - Traditional MS SQL Server quotes [Kurung siku] - Kutip tradisional MS SQL Server Keywords in &UPPER CASE Kata kunci dalam H&URUF BESAR When set, the SQL keywords are completed in UPPER CASE letters. Saat ditata, kata kunci SQL dilengkapkan dalam HURUF BESAR. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Ketika ditata, baris kode SQL yang menyebabkan kesalahan saat eksekusi terakhir disorot dan bingkai hasil mengindikasikan kesalahan dalam latar belakang Close button on tabs Tutup tombol pada tab If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Bila difungsikan, tab penyunting SQL akan memiliki tombol tutup. Apapun keadaannya, Anda dapat memakai menu kontekstual atau pintasan papan ketik untuk menutup mereka. &Extensions &Ekstensi Select extensions to load for every database: Pilih ekstensi yang akan dimuat untuk setiap basis data: Add extension Tambah ekstensi Remove extension Hapus ekstensi Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>Walaupun mendukung operator REGEXP SQLite tidak mengimplementasikan algoritma<br/>ekspresi reguler apa pun tapi memanggil balik aplikasi yang berjalan. Peramban DB bagi SQLite<br/>mengimplementasi algoritma ini bagi Anda agar memungkinkan Anda langsung memakai REGEXP.<br/>Namun, karena ada beberapa implementasi yang mungkin<br/> dan Anda mungkin ingin memakai yang lain,<br/>Anda bebas untuk menonaktifkan implementasi aplikasi dan memuat milik Anda sendiri memakai ekstensi.<br/>Memerlukan memulai ulang aplikasi.</p></body></html> Disable Regular Expression extension Nonaktifkan ekstensi Ekspresi Reguler <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite menyediakan sebuah fungsi SQL untul memuat ekstensi dari suatu berkas pustaka bersama. Aktifkan ini bila Anda ingin memakai fungsi <span style=" font-style:italic;">load_extension()</span> dari kode SQL.</p><p>Untuk alasan keamanan, pemuatan ekstensi dimatikan secara baku dan harus difungsikan melalui pengaturan ini. Anda selalu dapat memuat ekstensi melalui GUI, walaupun opsi ini dinonaktifkan.</p></body></html> Allow loading extensions from SQL code Izinkan memuat ekstensi dari kode SQL Remote Remote CA certificates Sertifikat CA Proxy Proksi Configure Konfigurasikan Export Settings Ekspor Pengaturan Import Settings Impor Pengaturan Subject CN CN Subjek Common Name Common Name Subject O O Subjek Organization Organisasi Valid from Valid sejak Valid to Valid sampai Serial number Nomor seri Your certificates Sertifikat Anda File Berkas Subject Common Name Common Name Subjek Issuer CN CN Penerbit Issuer Common Name Common Name Penerbit Clone databases into Klon basis data ke Choose a directory Pilih suatu direktori The language will change after you restart the application. Bahasa akan berubah setelah Anda menjalankan ulang aplikasi. Select extension file Pilih berkas ekstensi Extensions(*.so *.dylib *.dll);;All files(*) Ekstensi(*.so *.dylib *.dll);;Semua berkas(*) Import certificate file Impor berkas sertifikat No certificates found in this file. Tidak ditemukan sertifikat dalam berkas ini. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Anda yakin hendak menghapus sertifikat ini? Semua data sertifikat akan dihapus dari pengaturan aplikasi! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Anda yakin hendak membersihkan semua pengaturan yang disimpan? Semua preferensi Anda akan hilang dan nilai-nilai baku akan dipakai. Save Settings File Simpan Berkas Pengaturan Initialization File (*.ini) Berkas Inisialisasi (*.ini) The settings file has been saved in location : Berkas pengaturan telah disimpan di lokasi : Open Settings File Buka Berkas Pengaturan The settings file was loaded properly. Berkas pengaturan dimuat secara benar. The selected settings file is not a normal settings file. Please check again. Berkas pengaturan yang dipilih bukanlah berkas pengaturan yang normal. Harap periksa lagi. ProxyDialog Proxy Configuration Konfigurasi Proksi Pro&xy Type Tipe Pro&ksi Host Na&me Na&ma Host Port Port Authentication Re&quired &Perlu Autentikasi &User Name Nama Pengg&una Password Kata Sandi None Nihil System settings Pengaturan sistem HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data Kesalahan saat mengimpor data from record number %1 dari record nomor %1 . %1 . %1 Importing CSV file... Mengimpor berkas CSV... Cancel Batal All files (*) Semua berkas (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Berkas basis data SQLite (*.db *.sqlite *.sqlite3 *.db3) Left Kiri Right Kanan Center Tengah Justify Rata Kiri Kanan SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) Berkas Basis Data SQLite (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) Berkas proyek Peramban DB bagi SQLite (*.sqbpro) SQL Files (*.sql) Berkas SQL (*.sql) All Files (*) Semua Berkas (*) Text Files (*.txt) Berkas Teks (*.txt) Comma-Separated Values Files (*.csv) Berkas Nilai yang Dipisah Koma (*.csv) Tab-Separated Values Files (*.tsv) Berkas Nilai yang Dipisah Tab (*.tsv) Delimiter-Separated Values Files (*.dsv) Berkas Nilai yang Dipisah Pembatas (*.dsv) Concordance DAT files (*.dat) Berkas DAT Concordance (*.dat) JSON Files (*.json *.js) Berkas JSON (*.json *.js) XML Files (*.xml) Berkas XML (*.xml) Binary Files (*.bin *.dat) Berkas Biner (*.bin *.dat) SVG Files (*.svg) Berkas SVG (*.svg) Hex Dump Files (*.dat *.bin) Berkas Hex Dump (*.dat *.bin) Extensions (*.so *.dylib *.dll) Ekstensi (*.so *.dylib *.dll) Initialization File (*.ini) Berkas Inisialisasi (*.ini) QsciCommand Paste Tempel Cancel Batal QsciLexerCPP Default Baku Keyword Kata kunci Identifier Identifier QsciLexerJSON Default Baku String String QsciLexerJavaScript Regular expression Ekspresi reguler QsciLexerPython Default Baku Comment Komentar Keyword Kata kunci Identifier Identifier QsciLexerSQL Default Baku Comment Komentar Keyword Kata kunci Identifier Identifier QsciScintilla &Undo Tak Ja&di Select All Pilih Semua RemoteCommitsModel Commit ID ID Commit Message Pesan Date Tanggal Author Penulis Size Ukuran Authored and committed by %1 Dibuat dan di-commit oleh %1 Authored by %1, committed by %2 Dibuat oleh %1, di-commit oleh %2 RemoteDatabase Error opening local databases list. %1 Kesalahan saat membuka daftar basis data lokal. %1 Error creating local databases list. %1 Kesalahan saat membuat daftar basis data lokal. %1 RemoteDock Remote Remote Identity Identitas Push currently opened database to server Push basis data yang saat ini dibuka ke server Upload Unggah DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>Dalam panel ini, basis data remote dari situs web dbhub.io dapat ditambahkan ke Peramban DB untuk SQLite. Pertama Anda perlu suatu identitas:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Log masuk ke situs web dbhub.io (gunakan kredensial GitHub Anda atau apa pun yang Anda inginkan)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Klik tombol untuk &quot;Membuat sertifikat klien&quot; (itu adalah identitas Anda). Itu Akan memberi Anda suatu berkas sertifikat (simpan itu ke disk lokal Anda).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pergi ke tab Remote dalam Preferensi Peramban DB untuk SQLite. Klik tombol untuk menambahkan sertifikat baru ke Peramban DB untuk SQLite dan pilih berkas sertifikat yang baru saja diunduh.</li></ol><p>Kini panel Remote menampilkan identitas Anda dan Anda dapat menambah basis data remote.</p></body></html> Local Lokal Current Database Basis Data Saat Ini Clone Klon &User Pengg&una &Database Basis &data Branch Branch Commits Commit Commits for Commit untuk <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>Anda kini sedang memakai identitas bawaan, hanya-baca. Untuk mengunggah basis data Anda, Anda perlu mengonfigurasi dan memakai akun DBHub.io milik Anda.</p><p>Belum punya akun DBHub.io? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Buat baru sekarang</span></a> dan impor sertifikat Anda <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">di sini</span></a> untuk berbagi basis data Anda.</p><p>Untuk bantuan daring kunjungi <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">ini</span></a>.</p></body></html> Back Mundur Delete Database Hapus Basis Data Delete the local clone of this database Menghapus klon lokal dari basis data ini Open in Web Browser Buka dalam Peramban Web Open the web page for the current database in your browser Membuka halaman web bagi basis data saat ini dalam peramban Anda Clone from Link Klon dari Tautan Use this to download a remote database for local editing using a URL as provided on the web page of the database. Gunakan ini untuk mengunduh suatu basis data remote untuk penyuntingan lokal memakai suatu URL yang diberikan pada halaman web dari basis data. Refresh Segarkan Reload all data and update the views Muat ulang semua data dan perbarui view Clone Database Klon Basis Data Open Database Buka Basis Data Open the local copy of this database Membuka salinan lokal dari basis data ini Check out Commit Check out Commit Download and open this specific commit Unduh dan buka commit spesifik ini Check out Latest Commit Check out Commit Terakhir Check out the latest commit of the current branch Check out commit terakhir dari branch saat ini Save Revision to File Simpan Revisi ke Berkas Saves the selected revision of the database to another file Menyimpan revisi basis data yang dipilih ke berkas lain Upload Database Unggah Basis Data Upload this database as a new commit Unggah basis data ini sebagi suatu commit baru Select an identity to connect Pilih sebuah identitas untuk menyambung Public Publik This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Ini mengunduh sebuah basis data dari suatu server remote untuk penyuntingan lokal. Harap masukkan URL sumber klon. Anda dapat membangkitkan URL ini dengan mengklik tombol 'Klon Basis Data dalam DB4S' pada halaman web dari basis data. Invalid URL: The host name does not match the host name of the current identity. URL tidak valid: Nama host tidak cocok dengan nama host dari identitas saat ini. Invalid URL: No branch name specified. URL tidak valid: Tidak ada nama branch yang dinyatakan. Invalid URL: No commit ID specified. URL tidak valid: Tidak ada ID commit yang dinyatakan. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? Anda telah mengubah klon lokal dari basis data. Mengambil commit ini menimpa perubahan lokal ini. Anda yakin ingin melanjutkan? The database has unsaved changes. Are you sure you want to push it before saving? Basis data memiliki perubahan yang belum disimpan. Anda yakin ingin mem-push itu sebelum menyimpan? The database you are trying to delete is currently opened. Please close it before deleting. Basis data yang Anda coba hapus saat ini sedang dibuka. Harap tutup itu sebelum menghapus. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? Ini menghapus versi lokal dari basis data ini dengan semua perubahan yang belum Anda commit. Anda yakin ingin menghapus basis data ini? RemoteLocalFilesModel Name Nama Branch Branch Last modified Terakhir diubah Size Ukuran Commit Commit File Berkas RemoteModel Name Nama Commit Commit Last modified Terakhir diubah Size Ukuran Size: Ukuran: Last Modified: Terakhir Diubah: Licence: Lisensi: Default Branch: Branch Baku: RemoteNetwork Choose a location to save the file Pilih suatu lokasi untuk menyimpan berkas Error opening remote file at %1. %2 Kesalahan saat membuka berkas remote pada %1. %2 Error: Invalid client certificate specified. Kesalahan: Sertifikat klien yang ditentukan tidak valid. Please enter the passphrase for this client certificate in order to authenticate. Harap masukkan frasa sandi bagi sertifikat klien ini untuk mengautentikasi. Cancel Batal Uploading remote database to %1 Mengunggah basis data remote ke %1 Downloading remote database from %1 Mengunduh basis data remote dari %1 Error: Cannot open the file for sending. Kesalahan: Tidak bisa membuka berkas untuk pengiriman. RemotePushDialog Push database Push basis data Database na&me to push to Na&ma basis data tujuan push Commit message Pesan commit Database licence Lisensi basis data Public Publik Branch Branch Force push Paksa push Username Nama pengguna Database will be public. Everyone has read access to it. Basis data akan menjadi publik. Semua orang punya akses baca ke sana. Database will be private. Only you have access to it. Basis data akan menjadi privat. Hanya Anda yang punya akses ke sana. Use with care. This can cause remote commits to be deleted. Gunakan dengan hati-hati. Ini bisa menyebabkan commit remote terhapus. RunSql Execution aborted by user Eksekusi digugurkan oleh pengguna , %1 rows affected , %1 baris tedampak query executed successfully. Took %1ms%2 query sukses dieksekusi. Makan waktu %1ms%2 executing query mengeksekusi query SelectItemsPopup A&vailable &Tersedia Sele&cted &Dipilih SqlExecutionArea Form Bentuk Find previous match [Shift+F3] Cari kecocokan sebelumnya [Shift+F3] Find previous match with wrapping Cari kecocokan sebelumnya dan teruskan dari akhir setelah mencapai awal Shift+F3 Shift+F3 The found pattern must be a whole word Pola yang ditemukan mesti berupa kata utuh Whole Words Kata Lengkap Text pattern to find considering the checks in this frame Pola teks yang akan dicari dengan mempertimbangkan pemeriksaan dalam bingkai ini Find in editor Cari dalam penyunting The found pattern must match in letter case Pola yang ditemukan mesti cocok besar kecil hurufnya Case Sensitive Peka Huruf Besar Kecil Find next match [Enter, F3] Cari kecocokan selanjutnya [Enter, F3] Find next match with wrapping Cari kecocokan selanjutnya dan putar balik F3 F3 Interpret search pattern as a regular expression Interpretasikan pola pencarian sebagai ekspresi reguler <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Bila dicentang, pola yang akan dicari diinterpretasikan sebagi suatu ekspresi reguler UNIX. Lihat <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Ekspresi Reguler dalam Wikibook</a>.</p></body></html> Regular Expression Ekspresi Reguler Close Find Bar Tutup Bilah Pencarian <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>Hasil dari pernyataan yang terakhir dieksekusi.</p><p>Anda mungkin ingin melipat panel ini dan memakai dok <span style=" font-style:italic;">Log SQL</span> dengan pilihan <span style=" font-style:italic;">Pengguna</span> sebagai pengganti.</p></body></html> Results of the last executed statements Hasil dari pernyataan yang terakhir dieksekusi This field shows the results and status codes of the last executed statements. Ruas ini menunjukkan hasil dan kode status dari pernyataan yang terakhir dieksekusi. Ctrl+PgUp Ctrl+PgUp Ctrl+PgDown Ctrl+PgDown Couldn't read file "%1": %2. Tak bisa membaca berkas "%1": %2. Couldn't save file: %1. Tak bisa menyimpan berkas: %1. Your changes will be lost when reloading it! Perubahan Anda akan hilang ketika dimuat ulang! The file "%1" was modified by another program. Do you want to reload it?%2 Berkas "%1" diubah oleh program lain. Apakah Anda hendak memuat ulang itu?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Jawab "Ya ke Semua" untuk memuat ulang berkas saat pembaruan eksternal apa pun tanpa bertanya lebih jauh. Answer "No to All" to ignore any external update without further prompting. Jawab "Tidak ke Semua" untuk mengabaikan pembaruan eksternal apa pun tanpa bertanya lebih jauh. Modifying and saving the file will restore prompting. Mengubah dan menyimpan berkas akan memulihkan bertanya. SqlTextEdit Ctrl+/ Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) Fungsi abs(X) mengembalikan nilai absolut dari argumen numerik X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () Fungsi changes() mengembalikan banyaknya baris basis data yang diubah atau disisipkan atau dihapus oleh pernyataan INSERT, DELETE, atau UPDATE yang terakhir selesai. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) Fungsi char(X1,X2,...,XN) mengembalikan suatu string yang tersusun dari karakter yang memiliki nilai-nilai titik kode unicode dari bilangan bulat X1 sampai XN. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) Fungsi coalesce() mengembalikan suatu salinan dari argumen bukan NULL pertamanya, atau NULL bila semua argumen adalah NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) Fungsi glob(X,Y) ekuivalen dengan ekspresi "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) Fungsi ifnull() mengembalikan suatu salinan dari argumen bukan NULL pertama, atau NULL bila kedua argumen adalah NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) Fungsi instr(X,Y) mencari kemunculan pertama dari string Y di dalam string X dan mengembalikan banyaknya karakter sebelumnya tambah 1, atau 0 bila Y tidak ditemukan dalam X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) Fungsi hex() menginterpretasi argumennya sebagai sebuah BLOB dan mengembalikan suatu string yang merupakan perenderan heksadesimal huruf besar dari konten blob tersebut. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) Fungsi iif(X,Y,Z) mengembalikan nilai Y bila X benar, dan Z bila tidak. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () Fungsi last_insert_rowid() mengembalikan ROWID dari baris terakhir sisip dari koneksi basis data yang memanggil fungsi. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) Untuk suatu nilai string X, fungsi length(X) mengembalikan banyaknya karakter (bukan byte) dalam X sebelum karakter NUL pertama. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) Fungsi like() dipakai untuk mengimplementasikan ekspresi "Y LIKE X". (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) Fungsi like() dipakai untuk mengimplementasikan ekspresi "Y LIKE X ESCAPE Z". (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) Fungsi load_extension(X) memuat ekstensi SQLite dari berkas pustaka bersama bernama X. Penggunaan fungsi ini mesti diotorisasi dari Preferensi. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) Fungsi load_extension(X) memuat ekstensi SQLite dari berkas pustaka bersama bernama X memakai titik masuk Y. Penggunaan fungsi ini mesti diotorisasi dari Preferensi. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) Fungsi lower(X) mengembalikan suatu salinan dari string X dengan semua karakter ASCII dikonversi ke huruf kecil. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) menghapus spasi dari sisi kiri X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) Fungsi ltrim(X,Y) mengembalikan suatu string yang dibentuk dengan menghapus sebarang dan semua karakter yang muncul dalam Y di sisi kiri X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) Fungsi multi-argumen max() mengembalikan argumen dengan nilai maksimum, atau mengembalikan NULL bila sebarang argumen adalah NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) Fungsi multi-argumen min() mengembalikan argumen dengan nilai minimum. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) Fungsi nullif(X,Y) mengembalikan argumen pertamanya bila argumen-argumen berbeda dan NULL bila argumen-argumen adalah sama. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) Fungsi SQL printf(FORMAT,...) bekerja seperti fungsi bahasa C sqlite3_mprintf() dan fungsi printf() dari pustaka standar C. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) Fungsi quote(X) mengembalikan teks dari suatu literal SQL yang merupakan nilai dari argumennya, cocok untuk disertakan ke dalam suatu pernyataan SQL. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () Fungsi random() mengembalikan suatu bilang bulat pseudo-random antara -9223372036854775808 dan +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) Fungsi randomblob(N) mengembalikan suatu blob N byte yang memuat byte pseudo random. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) Fungsi replace(X,Y,Z) mengembalikan sebuah string yang dibentuk dengan memasang pengganti string Z bagi setiap kemunculan string Y dalam string X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) Fungsi round(X) mengembalikan suatu nilai floating point X yang dibulatkan ke nol digit di sisi kanan titik desimal. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) Fungsi round(X,Y) mengembalikan suatu nilai floating point X yang dibulatkan ke Y digit di sisi kanan titik desimal. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) menghapus spasi dari sisi kanan X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) Fungsi rtrim(X,Y) mengembalikan suatu string yang dibentuk dengan menghapus sebarang dan semua karakter yang muncul dalam Y di sisi kanan X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) Fungsi soundex(X) mengembalikan suatu string yang berupa enkoding soundex dari string X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) mengembalikan semua karakter sampai di akhir string X dimulai dari yang ke Y. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) Fungsi substr(X,Y,Z) mengembalikan sebuah sub string dari string masukan X yang dimulai dengan karakter ke-Y sepanjang Z karakter. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () Fungsi total_changes() mengembalikan banyaknya baris yang berubah karena pernyataan INSERT, UPDATE, atau DELETE sejak koneksi basis data saat ini dibuka. (X) trim(X) removes spaces from both ends of X. (X) trim(X) menghapus spasi di kedua ujung X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) Fungsi trim(X,Y) mengembalikan suatu string yang dibentuk dengan menghapus sebarang dan semua karakter yang muncul dalam Y di kedua ujung X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) Fungsi typeof(X) mengembalikan sebuah string yang mengindikasikan tipe data dari ekspresi X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) Fungsi unicode(X) mengembalikan titik kode unicode numerik yang bersesuaian dengan karakter pertama dari string X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) Fungsi upper(X) mengembalikan suatu salinan dari string masukan X dimana semua karakter ASCII huruf kecil dikonversi ke ekuivalen huruf besar mereka. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) Fungsi zeroblob(N) mengembalikan suatu BLOB yang terdiri dari N byte 0x00. (timestring,modifier,modifier,...) (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) Fungsi avg() mengembalikan nilai rerata dari semua X bukan NULL dalam suatu grup. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) Fungsi count(X) mengembalikan suatu cacah dari banyaknya X adalah bukan NULL dalam sebuah grup. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) Fungsi group_concat() mengembalikan suatu string yang merupakan konkatenasi dari semua nilai bukan NULL dari X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) Fungsi group_concat() mengembalikan suatu string yang merupakan konkatenasi dari semua nilai bukan NULL dari X. Bila parameter Y ada maka itu dipakai sebagai pemisah antara instansi-instansi X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) Fungsi agregasi max() mengembalikan nilai maksimum dari semua nilai dalam grup. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) Fungsi agregasi min() mengembalikan nilai bukan NULL minimum dari semua nilai dalam grup. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) Fungsi agregat sum() dan total() mengembalikan jumlah dari semua nilai bukan NULL dalam grup. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () Banyaknya baris di dalam partisi saat ini. Baris dinomori mulai dari 1 dalam urutan yang ditentukan oleh klausul ORDER BY dalam definisi jendela, atau dalam urutan sebarang bila tidak. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () row_number() dari peer pertama dalam setiap grup - ranking dari baris saat ini dengan celah. Bila tidak ada klausul ORDER BY, maka semua baris dianggap peer dan fungsi ini selalu mengembalikan 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Banyaknya grup peer dari baris saat ini di dalam partisinya - ranking dari baris saat ini tanpa celah. Partisi dinomori mulai dari 1 dalam urutan yang ditentukan oleh klausul ORDER BY dalam definisi jendela. Bila tidak ada klausul ORDER BY, maka semua baris dianggap peer dan fungsi ini selalu mengembalikan 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () Walaupaun namanya begitu, fungsi ini selalu mengembalikan suatu nilai antara 0,0 dan 1,0 sama dengan (ranking - 1)/(baris partisi - 1), dimana ranking adalah nilai yang dikembalikan oleh fungsi jendela bawaan rank() dan baris-partisi adalah cacah total baris dalam partisi. Bila partisi hanya memuat satu baris, fungsi ini mengembalikan 0,0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () Distribusi kumulatif. Dihitung sebagai nomor-baris/baris-partisi, dimana nomor-baris adalah nilai yang dikembalikan oleh row_number() bagi peer terakhir dalam grup dan baris-partisi adalah banyaknya baris dalam partisi. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) Argumen N ditangani sebagai sebuah bilangan bulat. Fungsi ini membagi partisi ke dalam N grup serata mungkin dan menugaskan suatu bilangan bulat antara 1 dan N ke setiap grup, dalam urutan yang ditentukan oleh klausul ORDER BY, atau dalam urutan sebarang bila tidak. Kalau perlu, grup-grup yang lebih besar muncul pertama. Fungsi ini mengembalikan nilai bilangan bulat yang ditugaskan ke ke grup dimana baris saat ini adalah bagian darinya. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Mengembalikan hasil mengevaluasi ekspresi expr terhadap baris sebelumnya dalam partisi. Atau bila tidak ada baris sebelumnya (karena baris saat ini adalah yg pertama), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) Bila argumen offset diberikan, maka itu mesti berupa bilangan bulat tidak negatif. Dalam kasus ini nilai yang dikembalikan adalah hasil dari mengevaluasi expr terhadap baris-baris ofset baris sebelum baris saat ini dalam partisi. Bila offset adalah 0, maka expr dievaluasi terhadap baris saat ini. Bila tidak ada baris-baris ofset baris sebelum baris saat ini, dikembalikan NULL. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) Bila default juga diberikan, maka itu dikembalikan sebagai pengganti dari NULL bila baris yang diidentifikasi oleh offset tidak ada. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Mengembalikan hasil dari mengevaluasi ekspresi expr terhadap baris selanjutnya dalam partisi. Atau bila tidak ada baris selanjutnya (karena baris saat ini adalah terakhir), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) Bila argumen offset diberikan, maka itu mesti berupa bilangan bulat tidak negatif. Dalam kasus ini nilai yang dikembalikan adalah hasil dari mengevaluasi expr terhadap baris-baris ofset baris setelah baris saat ini dalam partisi. Bila offset adalah 0, maka expr dievaluasi terhadap baris saat ini. Bila tidak ada baris-baris ofset baris setelah baris saat ini, dikembalikan NULL. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Fungsi jendela bawaan ini menghitung kerangka jendela bagi setiap baris dengan cara yang sama dengan fungsi jendela agregasi. Itu mengembalikan nilai expr yang dievaluasi terhadap baris pertama dalam kerangka jendela bagi setiap baris. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Fungsi jendela bawaan ini menghitung kerangka jendela bagi setiap baris dengan cara yang sama dengan fungsi jendela agregasi. Itu mengembalikan nilai expr yang dievaluasi terhadap baris terakhir dalam kerangka jendela bagi setiap baris. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) Fungsi jendela bawaan ini menghitung kerangka jendela bagi setiap baris dengan cara yang sama dengan fungsi jendela agregasi. Itu mengembalikan nilai expr yang dievaluasi terhadap baris N dari kerangka jendela. Baris-baris dinomori dalam kerangka jendela dimulai dari 1 dalam urutan yang ditentukan oleh klausul ORDER BY bila ada, atau dalam urutan sebarang bila tidak. Bila tidak adan baris ke N dalam partisi, maka NULL dikembalikan. (X) Return the arccosine of X. The result is in radians. (X) Mengembalikan arckosinus dari X. Hasil dalam radian. (X) Return the hyperbolic arccosine of X. (X) Mengembalikan arckosinus hiperbolik dari X. (X) Return the arcsine of X. The result is in radians. (X) Mengembalikan arcsinus dari X. Hasil dalam radian. (X) Return the hyperbolic arcsine of X. (X) Mengembalikan arcsinus hiperbolik dari X. (X) Return the arctangent of X. The result is in radians. (X) Mengembalikan arctangen dari X. Hasil dalam radian. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X, Y) Mengembalikan arctangen dari Y/X. Hasil dalam radian. Hasil ditempatkan ke dalam kuadran yang benar bergantung pada tanda dari X dan Y. (X) Return the hyperbolic arctangent of X. (X) Mengembalikan arctangen hiperbolik dari X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Mengembalikan nilai bilangan bulat pertama yang dapat direpresentasikan yang lebih dari atau sama dengan X. Untuk nilai X positif, rutin ini membulatkan menjauh dari nol. Untuk nilai negatif X, rutin ini membulatkan menuju nol. (X) Return the cosine of X. X is in radians. (X) Mengembalikan kosinus dari X. X dalam radian. (X) Return the hyperbolic cosine of X. (X) Mengembalikan kosinus hiperbolik dari X. (X) Convert value X from radians into degrees. (X) Mengonversi nilai X dari radian ke derajat. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Menghitung e (bilangan Euler, kurang lebih 2.71828182845905) pangkat X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Mengembalikan nilai bilangan bulat pertama yang dapat direpresentasikan yang kurang dari atau sama dengan X. Untuk nilai X positif, rutin ini membulatkan menuju nol. Untuk nilai negatif X, rutin ini membulatkan menjauhi nol. (X) Return the natural logarithm of X. (X) Mengembalikan logaritma alami dari X. (B,X) Return the base-B logarithm of X. (B, X) Mengembalikan logaritma basis-B dari X. (X) Return the base-10 logarithm for X. (X) Mengembalikan logaritma basis-10 untuk X. (X) Return the logarithm base-2 for the number X. (X) Mengembalikan logaritma basis-2 untuk bilangan X. (X,Y) Return the remainder after dividing X by Y. (X, Y) Mengembalikan sisa setelah X dibagi Y. () Return an approximation for Ï€. () Mengembalikan suatu aproksimasi untuk Ï€. (X,Y) Compute X raised to the power Y. (X,Y) Menghitung X pangkat Y. (X) Convert X from degrees into radians. (X) Mengonversi X dari derajat ke radian. (X) Return the sine of X. X is in radians. (X) Mengembalikan sinus X. X dalam radian. (X) Return the hyperbolic sine of X. (X) Mengembalikan sinus hiperbolik dari X. (X) Return the square root of X. NULL is returned if X is negative. (X) Mengembalikan akar kuadrat dari X. NULL dikembalikan bila X negatif. (X) Return the tangent of X. X is in radians. (X) Mengembalikan tangen dari X. X dalam radian. (X) Return the hyperbolic tangent of X. (X) Mengembalikan tangen hiperbolik dari X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) Mengembalikan bilangan bulat yang dapat direpresentasikan antara X dan 0 (inklusif) yang paling jauh dari nol. Atau, dengan perkataan lain, mengembalikan bagian bilangan bulat dari X, membulatkan menuju nol. SqliteTableModel reading rows membaca baris loading... memuat... References %1(%2) Hold %3Shift and click to jump there Mengacu %1(%2) Tahan Shift%3 dan klik untuk melompat ke sana Error changing data: %1 Kesalahan saat mengubah data: %1 retrieving list of columns mengambil daftar kolom Fetching data... Mengambil data... Cancel Batal TableBrowser Browse Data Ramban Data &Table: &Tabel: Select a table to browse data Pilih suatu tabel untuk diramban datanya Use this list to select a table to be displayed in the database view Gunakan daftar ini untuk memilih suatu tabel yang akan ditampilkan dalam view basis data This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Ini adalah view tabel basis data. Anda dapat melakukan aksi berikut: - Mulai menulis untuk menyunting nilai secara inline. - Klik ganda sebarang record untuk menyunting isinya dalam jendela penyunting sel. - Alt+Del untuk menghapus isi sel menjadi NULL. - Ctrl+" untuk menduplikasi record saat ini. - Ctrl+' untuk menyalin nilai dari sel di atas. - Operasi salin/tempel dan pemilihan standar. Text pattern to find considering the checks in this frame Pola teks yang akan dicari dengan mempertimbangkan pemeriksaan dalam bingkai ini Find in table Cari dalam tabel Find previous match [Shift+F3] Cari kecocokan sebelumnya [Shift+F3] Find previous match with wrapping Cari kecocokan sebelumnya dan teruskan dari akhir setelah mencapai awal Shift+F3 Shift+F3 Find next match [Enter, F3] Cari kecocokan selanjutnya [Enter, F3] Find next match with wrapping Cari kecocokan selanjutnya dan teruskan dari awal setelah mencapai akhir F3 F3 The found pattern must match in letter case Pola yang ditemukan mesti cocok besar kecil hurufnya Case Sensitive Peka Huruf Besar Kecil The found pattern must be a whole word Pola yang ditemukan mesti berupa kata utuh Whole Cell Seluruh Sel Interpret search pattern as a regular expression Interpretasikan pola pencarian sebagai suatu ekspresi reguler <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Saat dicentang, pola yang akan dicari diinterpretasikan sebagai suatu ekspresi reguler UNIX. Lihat <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Ekspresi Reguler dalam Wikibook</a>.</p></body></html> Regular Expression Ekspresi Reguler Close Find Bar Tutup Bilah Pencarian Text to replace with Teks pengganti Replace with Ganti dengan Replace next match Gantikan kecocokan selanjutnya Replace Ganti Replace all matches Ganti semua yang cocok Replace all Ganti semua Export to &JSON Ekspor ke &JSON Export the filtered data to JSON Mengekspor data yang difilter ke JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Tombol ini mengekspor data dari tabel yang diramban sebagaimana saat ini ditampilkan (setelah filter, format tampilan, dan kolom pengurutan) sebagai suatu berkas JSON. Copy column name Salin nama kolom Copy the database table column name to your clipboard Menyalin nama kolom tabel basis data ke papan klip Anda New Data Browser Peramban Data Baru Add a new docked Data Browser Menambahkan sebuah Peramban Data tertambat yang baru This button adds a new docked Data Browser, which you can detach and arrange in different layouts. Tombol ini menambahkan suatu Peramban Data tertambat yang baru, yang dapat Anda copot dan atur dalam tata letak yang berbeda-beda. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Menggulir ke awal</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Mengklik tombol ini menavigasi ke awal dalam view tabel di atas.</p></body></html> |< |< Scroll one page upwards Gulir satu halaman naik <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Mengklik tombol ini menavigasi naik satu halaman record dalam view tabel di atas.</p></body></html> < < 0 - 0 of 0 0 - 0 dari 0 Scroll one page downwards Gulir satu halaman turun <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Mengklik tombol ini menavigasi turun satu halaman record dalam view tabel di atas.</p></body></html> > > Scroll to the end Gulir ke akhir <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>Mengklik tombol ini menavigasi ke akhir dalam view tabel di atas.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>Klik di sini untuk melompat ke record tertentu</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Tombol ini dipakai untuk menavigasi ke nomor record yang dinyatakan dalam area Ke.</p></body></html> Go to: Ke: Enter record number to browse Masukkan nomor record yang akan diramban Type a record number in this area and click the Go to: button to display the record in the database view Ketikkan suatu nomor record dalam area ini klik tombol Ke: untuk menampilkan record dalam view basis data 1 1 Show rowid column Tampilkan kolom rowid Toggle the visibility of the rowid column Jungkitkan kenampakan kolom rowid Unlock view editing Buka kunci penyuntingan view This unlocks the current view for editing. However, you will need appropriate triggers for editing. Ini membuka view saat ini untuk disunting. Namun Anda akan perlu trigger yang sesuai untuk penyuntingan. Edit display format Sunting format tampilan Edit the display format of the data in this column Sunting format tampilan data dalam kolom ini New Record Record Baru Insert a new record in the current table Sisipkan suatu record baru dalam tabel saat ini <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Tombol ini membuat sebuah record baru dalam basis data. Tahan tombol tetikus untuk membuka sebuah menu pop-up dengan opsi-opsi berbeda:</p><ul><li><span style=" font-weight:600;">Record Baru</span>: menyisipkan sebuah record baru dengan nilai-nilai baku dalam basis data.</li><li><span style=" font-weight:600;">Sisipkan Nilai...</span>: membuka suatu dialog untuk memasukkan nilai-nilai sebelum mereka disisipkan dalam basis data. Ini memungkinkan memasukkan nilai-nilai yang memenuhi konstrain lain. Dialog ini juga dibuka bila opsi <span style=" font-weight:600;">Record Baru</span> gagal karena konstrain ini.</li></ul></body></html> Delete Record Hapus Record Delete the current record Hapus record saat ini This button deletes the record or records currently selected in the table Tombol ini menghapus record atau record yang saat ini dipilih dalam tabel Insert new record using default values in browsed table Sisipkan record baru memakai nilai-nilai baku dalam tabel yang diramban Insert Values... Sisipkan Nilai... Open a dialog for inserting values in a new record Membuka suatu dialog untuk menyisipkan nilai-nilai dalam sebuah record baru Export to &CSV Ekspor ke &CSV Export the filtered data to CSV Ekspor data yang difilter ke CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Tombol ini mengekspor data dari tabel yang diramban yang saat ini ditampilkan (setelah filter, format tampilan, dan kolom urutan) sebagai suatu berkas CSV. Save as &view Simpan sebagai &view Save the current filter, sort column and display formats as a view Simpan filter saat ini, kolom pengurutan, dan format tampilan sebagai suatu view This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Tombol ini menyimpan pengaturan saat ini dari tabel yang diramban (filter, format tampilan, dan kolom pengurutan) sebagai suatu view SQL yang nanti Anda dapat ramban atau pakai dalam pernyataan SQL. Save Table As... Simpan Tabel Sebagai... Save the table as currently displayed Menyimpan tabel sebagai yang saat ini ditampilkan <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>Menu pop-up ini menyediakan opsi-opsi berikut yang diterapkan ke tabel yang saat ini diramban dan disaring:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ekspor ke CSV: opsi ini mengekspor data dari tabel yang diramban sebagaimana saat ini ditampilkan (setelah penyaring, format tampilan, dan urutan kolom) ke sebuah berkas CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Simpan sebagai view: opsi ini menyimpan pengaturan saat ini dari tabel yang diramban (penyaring, format tampilan, dan urutan kolom) sebagai sebuah view SQL yang nanti akan dapat Anda ramban atau pakai dalam pernyataan SQL.</li></ul></body></html> Hide column(s) Sembunyikan kolom Hide selected column(s) Sembunyikan kolom yang dipilih Show all columns Tampilkan semua kolom Show all columns that were hidden Tampilkan semua kolom yang disembunyikan Set encoding Atur pengkodean Change the encoding of the text in the table cells Ubah pengkodean teks dalam sel tabel Set encoding for all tables Atur pengkodean untuk semua tabel Change the default encoding assumed for all tables in the database Ubah pengkodean baku yang diasumsikan bagi semua tabel dalam basis data Clear Filters Bersihkan Filter Clear all filters Bersihkan semua filter This button clears all the filters set in the header input fields for the currently browsed table. Tombol ini membersihkan semua filter yang diatur dalam ruas masukan header bagi tabel yang saat ini diramban. Clear Sorting Bersihkan Pengurutan Reset the order of rows to the default Reset urutan baris ke baku This button clears the sorting columns specified for the currently browsed table and returns to the default order. Tombol ini membersihkan kolom pengurutan yang dinyatakan bagi tabel yang saat ini diramban dan mengembalikan ke urutan baku. Print Cetak Print currently browsed table data Cetak data tabel yang saat ini diramban Print currently browsed table data. Print selection if more than one cell is selected. Mencetak data tabel yang saat ini diramban. Mencetak pilihan bila lebih dari satu sel yang dipilih. Ctrl+P Ctrl+P Refresh Segarkan Refresh the data in the selected table Segarkan data dalam tabel yang dipilih This button refreshes the data in the currently selected table. Tombol ini menyegarkan data dalam tabel yang saat ini dipilih. F5 F5 Find in cells Cari dalam sel Open the find tool bar which allows you to search for values in the table view below. Membuka bilah alat pencarian yang memungkinkan Anda mencari nilai dalam view tabel di bawah. Bold Tebal Ctrl+B Ctrl+B Italic Miring Underline Garis bawah Ctrl+U Ctrl+U Align Right Rata Kanan Align Left Rata Kiri Center Horizontally Tengahkan Arah Horizontal Justify Rata Kiri Kanan Edit Conditional Formats... Sunting Format Bersyarat... Edit conditional formats for the current column Sunting format bersyarat bagi kolom saat ini Clear Format Bersihkan Format Clear All Formats Bersihkan Semua Format Clear all cell formatting from selected cells and all conditional formats from selected columns Membersihkan semua pemformatan sel dari sel yang dipilih dan semua format bersyarat dari kolom-kolom yang dipilih Font Color Warna Fonta Background Color Warna Latar Toggle Format Toolbar Jungkitkan Bilah Alat Format Show/hide format toolbar Tampilkan/sembunyikan bilah alat format This button shows or hides the formatting toolbar of the Data Browser Tombol ini menampilkan atau menyembunyikan bilah alat pemformatan dari Peramban Data Select column Pilih kolom Ctrl+Space Ctrl+Space Replace text in cells Gantikan teks dalam sel Freeze columns Bekukan kolom Make all columns from the first column up to this column not move when scrolling horizontally Buat semua kolom dari kolom pertama sampai dengan kolom ini tidak bergerak ketika menggulir ke arah horizontal Filter in any column Filter dalam sebarang kolom Ctrl+R Ctrl+R %n row(s) %n baris , %n column(s) , %n kolom . Sum: %1; Average: %2; Min: %3; Max: %4 . Jumlah: %1; Rerata: %2; Min: %3; Maks: %4 Conditional formats for "%1" Format bersyarat bagi "%1" determining row count... menentukan cacah baris... %L1 - %L2 of >= %L3 %L1 - %L2 dari >= %L3 %L1 - %L2 of %L3 %L1 - %L2 dari %L3 (clipped at %L1 rows) (dipangkas pada %L1 baris) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Harap masukkan suatu kunci primer pseudo agar memungkinkan penyuntingan pada view ini. Ini mesti berupa nama dari sebuah kolom unik dalam view. Delete Records Hapus Record Duplicate records Duplikatkan record Duplicate record Duplikatkan record Ctrl+" Ctrl+" Adjust rows to contents Setel baris ke isi Error deleting record: %1 Kesalahan saat menghapus record: %1 Please select a record first Harap pilih suatu record terlebih dahulu Please choose a new encoding for all tables. Harap pilih suatu enkoding baru bagi semua tabel. Please choose a new encoding for this table. Harap pilih suatu enkoding baru bagi tabel ini. %1 Leave the field empty for using the database encoding. %1 Biarkan ruas kosong untuk memakai enkoding basis data. This encoding is either not valid or not supported. Enkoding ini tidak valid atau tidak didukung. %1 replacement(s) made. %1 penggantian dibuat. TableBrowserDock New Data Browser Peramban Data Baru Rename Data Browser Ubah Nama Peramban Data Close Data Browser Tutup Peramban Data Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. Mengatur sebuah nama baru bagi peramban data. Gunakan karakter '&&' untuk mengizinkan penggunaan karakter berikut sebagai pintasan papan ketik. VacuumDialog Compact Database Mampatkan Basis Data Warning: Compacting the database will commit all of your changes. Peringatan: Memampatkan basis data akan meng-commit semua perubahan Anda. Please select the databases to co&mpact: Harap pilih basis data yang akan di&mampatkan: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_it.ts000066400000000000000000015377451463772530400252370ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Informazioni su DB Browser for SQLite Version Versione <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> <html><head/><body><p>DB Browser for SQLite è uno strumento visuale open source e freeware utilizzato per creare, progettare ed editare files di database SQLite.</p><p>È licenziato sia sotto la Mozilla Public License Version 2, che la GNU General Public License Version 3 o successive. Puoi modificare o redistribuirlo rispettando le condizioni di queste licenze.</p><p>Visita <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> e <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> per i dettagli.</p><p>Per ulteriori informazioni su questo applicativo si prega di visitare il nostro sito: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Questo software utilizza la versione GPL/LGPL del Toolkit Qt da: </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>Visita: </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> per i termini della licenza ed informazioni.</span></p><p><span style=" font-size:8pt;">Utilizziamo la libreria nalgeon/sqlean per il supporto alle estensioni SQLite.<br/>Questa libreria è licenziata tramite la licenza MIT, per ulteriori informazioni visita:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">Utilizziamo anche il set di icone Pastel SVG di Michael Buckley tramite la licenza Creative Commons Attribution Share Alike 4.0.<br/>Visita: </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> per i dettagli.</span></p></body></html> AddRecordDialog Add New Record Aggiungi un nuovo record Enter values for the new record considering constraints. Fields in bold are mandatory. Inserisci i valori per il nuovo record considerando i vincoli. I campi in grassetto sono obbligatori. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Nella colonna Valore puoi specificare il valore per il campo identificato dalla colonna Nome. La colonna Tipo indica il tipo del campo. I valori di default sono mostrati nello stesso stile come valori NULL. Name Nome Type Tipo Value Valore Values to insert. Pre-filled default values are inserted automatically unless they are changed. Valori da inserire. Sono preinseriti dei valori di default automaticamente a meno che essi non vengano cambiati. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Quando modifichi i valori nel riquadro superiore, la query SQL per inserire questo nuovo record è mostrata qui. Puoi modificare manualmente la query prima di salvare. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Salva</span> invia la richiesta SQL mostrata al database per inserire un nuovo record.</p><p><span style=" font-weight:600;">Ripristina Defaults</span> ripristinerà i valori iniziali della colonna <span style=" font-weight:600;">Valore</span>.</p><p><span style=" font-weight:600;">Annulla</span> chiuderà questa finestra di dialogo senza eseguire la query.</p></body></html> Auto-increment Auto-incrementale Unique constraint Restrizione univoco Check constraint: %1 Controlla restrizioni: %1 Foreign key: %1 Chiave esterna: %1 Default value: %1 Valore di default: %1 Error adding record. Message from database engine: %1 Errore nell'aggiungere il record. Messaggio dal database engine: %1 Are you sure you want to restore all the entered values to their defaults? Sei sicuro di voler ripristinare tutti i valori inseriti ai loro valori di default? Application Possible command line arguments: Possibili argomenti da linea di comando: The user settings file location is replaced with the argument value instead of the environment variable value. La posizione del file di configurazione viene rimpiazzata col valore dell'argomento anziché il valore della variabile d'ambiente. Ignored environment variable (DB4S_SETTINGS_FILE) value: Ignorato valore variabile d'ambiente(DB4S_SETTINGS_FILE) : The file %1 does not exist Il file %1 non esiste Usage Uso options opzioni database database project progetto csv-file csv-file Show command line options Mostra le opzioni da riga di comando Exit application after running scripts Chiudi l'applicazione dopo aver eseguito gli scripts file file Execute this SQL file after opening the DB Esegui questo file SQL dopo aver aperto il DB Import this CSV file into the passed DB or into a new DB Importa questo file CSV nel DB fornito o in un nuovo DB table tabella Browse this table, or use it as target of a data import Scorri questa tabella o usala come destinazione per l'importazione di dati Open database in read-only mode Apri il database in sola lettura settings_file file_impostazioni Run application based on this settings file Esegue l'applicazione basandosi su questo file di configurazione group gruppo settings impostazione value valore Run application with this setting temporarily set to value Esegue l'applicazione con questa impostazione temporaneamente impostata al valore Run application saving this value for this setting Esegue l'applicazione salvando questo valore come impostazione Display the current version Mostra la versione corrente Open this SQLite database Apre questo database SQLite Open this project file (*.sqbpro) Apre questo file di progetto (*.sqbpro) Import this CSV file into an in-memory database Importa questo file CSV in un database in memoria The %1 option requires an argument L'opzione %1 richiede un argomento The -S/--settings option requires an argument. The option is ignored. L'opzione -S/--settings richiede un argomento. L'opzione viene ignorata. The -o/--option and -O/--save-option options require an argument in the form group/setting=value L'opzioni -o/--option e -O/--save-option richiedono un parametro nel formato gruppo/impostaizione=valore SQLite Version Versione SQLite SQLCipher Version %1 (based on SQLite %2) Versione SQLCipher %1 (basata su SQLite %2) DB Browser for SQLite Version %1. Versione DB Browser for SQLite %1. Last commit hash when built: %1 Ultimo hash del commit quando compilata: %1 Built for %1, running on %2 Compilato per %1, in esecuzione su %2 Qt Version %1 Versione Qt %1 Invalid option/non-existent file: %1 Opzione non valida/file inesistente: %1 CipherDialog SQLCipher encryption Criptatura SQLCipher &Password &Password &Reenter password &Reinserire password Encr&yption settings I&mpostazioni cifratura SQLCipher &3 defaults Predefiniti SQLCipher &3 SQLCipher &4 defaults Predefiniti SQLCipher &4 Custo&m Personalizzat&i Page si&ze Di&mensioni pagina &KDF iterations Integrazione &KDF HMAC algorithm Algoritmo HMAC KDF algorithm Algoritmo KDF Plaintext Header Size Dimensione header testuale Passphrase Chiave testuale Raw key Chiave grezza Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Perfavore inserisci una chiave per criptare il database. Nota che se cambi una qualsiasi delle altre impostazioni opzionali, dovrai reinserirle ogni volta che apri il file del database. Lascia i campi password vuoti per disabilitare la crittografia. Il processo di crittazione può richiedere del tempo e dovresti avere una copia di backup del database! Modifiche non salvate sono applicate prima di modificare la crittografia. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Si prega d'inserire la chiave utilizzata per criptare il database. Se una qualunque altra impostazione è stata modificata per l'inserimento della criptazione si prega d'impostarla in modo adeguato. ColumnDisplayFormatDialog Choose display format Seleziona il formato di visualizzazione Display format Formato di visualizzazione Choose a display format for the column '%1' which is applied to each value prior to showing it. Seleziona un formato di visualizzazione per la colonna '%1' che è applicato a ciascun valore prima di mostrarlo. Default Default Decimal number Numero decimale Exponent notation Notazione esponenziale Hex blob Blob esadecimale Hex number Numero esadecimale Octal number Numero ottale Round number Numero arrotondato Apple NSDate to date Apple NSDate ad oggi Java epoch (milliseconds) to date Java epoch (millisecondi) ad oggi .NET DateTime.Ticks to date .NET DateTime.Ticks ad oggi Julian day to date Giorno giuliano ad oggi Unix epoch to date Unix epoch ad oggi Unix epoch to local time Unix epoch a ora locale WebKit / Chromium epoch to date WebKit / Chromium epoch ad oggi WebKit / Chromium epoch to local time WebKit / Chromium epoch a ora locale Windows DATE to date Windows DATE ad oggi Date as dd/mm/yyyy Data come gg/mm/aaaa Lower case Minuscolo Upper case Maiuscolo Binary GUID to text GUID binario in testo SpatiaLite Geometry to SVG SpatiaLite Geometry in SVG Custom Personalizzato Custom display format must contain a function call applied to %1 I formati di visualizzazione personalizzati devono contenere una chiamata a funzione applicata a %1 Error in custom display format. Message from database engine: %1 Errore nel formato personalizzato di visualizzazione. Messaggio dal motore DB: %1 Custom display format must return only one column but it returned %1. Il formato di visualizzazione personalizzato deve restituire solo una colonna ma ha restituito %1. CondFormatManager Conditional Format Manager Gestore della formattazione condizionale This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Questa finestra permette la creazione e modifica della formattazione condizionale. Lo stile di ogni cella corrisponde alla prima condizione corrispondente. Le formattazioni condizionali possono essere spostate su e giù, quelle in posizione superiore avranno precedenza su quelle inferiori. La sintassi per le condizioni è la stessa utilizzata per i filtri e una condizione vuota corrisponde a tutti i valori. Add new conditional format Aggiunti nuova condizione &Add &Aggiungi Remove selected conditional format Rimuovi la condizione selezionata &Remove &Rimuovi Move selected conditional format up Sposta la condizione selezionata in su Move &up Sposta &su Move selected conditional format down Sposta la condizione selezionata giù Move &down Sposta &giù Foreground Primo piano Text color Colore del testo Background Sfondo Background color Colore dello sfondo Font Testo Size Dimensione Bold Grassetto Italic Corsivo Underline Sottolinea Alignment Allineamento Condition Condizione Click to select color Clicca per scegliere il colore Are you sure you want to clear all the conditional formats of this field? Sei sicuro di voler eliminare tutte le formattazioni condizionali di questo campo? DBBrowserDB Please specify the database name under which you want to access the attached database Si prega di specificare il nome del database con cui si vuol accedere al database collegato Invalid file format Formato file non valido Do you really want to close this temporary database? All data will be lost. Vuoi davvero chiudere questo database temporaneo? Tutti i dati andranno persi. Do you want to save the changes made to the database file %1? Vuoi salvare le modifiche effettuate al database %1? Database didn't close correctly, probably still busy Il database non è stato chiuso correttamente; probabilmente è ancora occupato Cannot open destination file: '%1' Impossibile aprire il file di destinazione: '%1' Cannot backup to file: '%1'. Message: %2 Impossibile creare file di backup: '%1'. Messaggio: %2 The database is currently busy: Il database è attualmente in uso: Do you want to abort that other operation? Vuoi annullare l'altra operazione? Exporting database to SQL file... Esportando il database in file SQL... Cancel Annulla No database file opened Nessun database aperto Executing SQL... Eseguendo SQL... Action cancelled. Azione annullata. Error in statement #%1: %2. Aborting execution%3. Errore nello statement #%1: %2. Annullo l'esecuzione %3. and rolling back e ripristino il db didn't receive any output from %1 non ho ricevuto alcun ouput da %1 could not execute command: %1 impossibile eseguire il comando: %1 Cannot delete this object Non posso cancellare questo oggetto Cannot set data on this object Non posso impostare i dati in questo oggetto A table with the name '%1' already exists in schema '%2'. Una tabella con il nome '%1' esiste già nello schema '%2'. No table with name '%1' exists in schema '%2'. Nessuna tabella col nome '%1' esiste nello schema '%2'. Cannot find column %1. Impossibile trovare la colonna %1. Creating savepoint failed. DB says: %1 Creazione del punto di salvataggio fallita. DB log: %1 Renaming the column failed. DB says: %1 Fallimento dell'operazione di rinomina. DB log: %1 Releasing savepoint failed. DB says: %1 Rilascio del salvataggio falitto. DB log: %1 Creating new table failed. DB says: %1 Creazione della nuova tabella fallita. DB log: %1 Copying data to new table failed. DB says: %1 Copia dei dati nella nuova tabella fallita. DB log: %1 Deleting old table failed. DB says: %1 Eliminazione della vecchia tabella fallita. DB log: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 Errore durante il rinomino della tabella '%1' in '%2. Messaggio dal DB: %3 could not get list of db objects: %1 non posso ottenere la listra degli oggetti db: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Ripristino di alcuni oggetti associati a questa tabella fallito. Questo è probabilmente dovuto al fatto che i nomi di alcune colonne sono cambiati . Qui c'è la richiesta SQL che potresti voler sistemare ed eseguire manualmente: could not get list of databases: %1 non è possibile ricavare la lista dei database: %1 Error setting pragma %1 to %2: %3 Errore nell'impostare pragma %1 in %2: %3 File not found. File non trovato. Error loading extension: %1 Errore nel caricamento dell'estensione: %1 Error loading built-in extension: %1 Errore nel caricamento dell'esensione inclusa: %1 could not get column information non è possibile ricavare informazioni sulla colonna DbStructureModel Name Nome Object Oggetto Type Tipo Schema Schema Database Database Browsables Navigabili All Tutti Temporary Temporaneo Tables (%1) Tabelle (%1) Indices (%1) Indici (%1) Views (%1) Viste (%1) Triggers (%1) Triggers (%1) EditDialog Edit database cell Modifica la cella del database Mode: Modalità: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Questa è la lista delle modalità supportate dall'editor della cella. Scegli una modalità per vedere o modificare i dati della cella corrente. Text Testo RTL Text Testo RTL Binary Binario Image Immagine JSON JSON XML XML Evaluation Valutazione Automatically adjust the editor mode to the loaded data type Seleziona automaticamente la modalità dell'editor in base al tipo di dato caricato This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Questo bottone spuntabile permette di abilitare o disabilitare l'adattamento automatico della modalità dell'editor. Quando una nuova cella è selezionata o sono importati nuovi dati e la modalità di adattamento automaitco è abilitata, la modalità si aggiusta al tipo di dato rilevato. Puoi cambiare in seguito la modalità dell'editor in modo manuale. Se vuoi mantenere la modalità selezionata manualmente mentre ti muovi tre le celle, togli la spunta a questo bottone. Auto-switch Auto-switch This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Questo editor Qt è utilizzato per le scritture da destra a sinistra, che non sono supportate dall'editor testuale standard. La presenza di caratteri da destra a sinistra è rilevata e la modalità dell'editor viene selezionata automaticamente. Identification of the cell currently in the editor Identificatore della cella attualmente nell'editor Type and size of data currently in table Tipo e dimensione del dato attualmente nella tabella Open preview dialog for printing the data currently stored in the cell Apre una finestra d'anteprima per la stampa dei dati attualmente memorizzati nella cella Auto-format: pretty print on loading, compact on saving. Auto-formato: migliore stampa al caricamento, compatta in salvataggio. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Quando abilitato, la feature dell'auto-formato formatta i dati al caricamento, rompe il testo in righe e lo indenta per una maggiore leggibilità. Al salvataggio dei dati, la feature dell'auto-formato compatta i dati rimuovendo i fine riga, e spazi bianchi non necessari. Word Wrap A capo automatico Wrap lines on word boundaries Porta a capo le line di testo al raggiungimento del bordo Open in default application or browser Apri nell'applicazione predefinita o nel browser Open in application Apri nell'applicazione The value is interpreted as a file or URL and opened in the default application or web browser. Il valore è interpretato come file o URL e aperto nell'applicazione predefinita o nel web browser. Save file reference... Salva riferimento file... Save reference to file Salva riferimento su file Open in external application Apri in un'applicazione esterna Autoformat Autoformato &Export... &Esporta... &Import... &Importa... Import from file Importa da file Opens a file dialog used to import any kind of data to this database cell. Apri una finestra di dialogo per importare qualsiasi tipo di dato in questa cella del database. Export to file Esporta in un file Opens a file dialog used to export the contents of this database cell to a file. Apri una finestra di dialogo utilizzata per esportare i contenuti di questa cella del database in un file. Apply data to cell Applica i dati alla cella Erases the contents of the cell Cancella i contenuti di questa cella Set as &NULL Imposta come &NULL This area displays information about the data present in this database cell Quest'area mostra informazioni riguardo i dati presenti in questa cella del database This button saves the changes performed in the cell editor to the database cell. Questo bottone salva le modifiche fatte alla cella dell'editor alla cella del database. Apply Applica Print... Stampa... Ctrl+P Open preview dialog for printing displayed text Apri la finestra di anteprima per stampare il testo mostrato Copy Hex and ASCII Copia HEX e ASCII Copy selected hexadecimal and ASCII columns to the clipboard Copia le colonne esadecimali e ASCII selezionate negli appunti Ctrl+Shift+C Image data can't be viewed in this mode. I dati immagine non possono essere visualizzati in questa modalità. Try switching to Image or Binary mode. Prova a passare alla modalità Immagine o Binario. Binary data can't be viewed in this mode. I dati binari non possono essere visualizzati in questa modalità. Try switching to Binary mode. Prova a passare alla modalità Binario. Image files (%1) File immagine (%1) Binary files (*.bin) File binario (*.bin) Choose a file to import Scegli un file da importare The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. La modalità di editor ti permette di modificare testo, JSON o XML con sintassi evidenziata, formattato automaticamente e validato prima del salvataggio. Gli errori sono indicati con una sottolineatura rossa ondeggiata. In modalità di Valutazione, le espressioni SQLite inserite sono valutate e il risultato applicato alla cella. Unsaved data in the cell editor Dati non salvati nell'editor di cella The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? L'editor di cella contiene dati non ancora applicati al database. Vuoi applicare i dati modificati alla riga=%1, colonna=%2? Editing row=%1, column=%2 Modifica riga=%1, colonna=%2 No cell active. Nessuna cella attiva. %1 Image %1 Immagine Choose a filename to export data Scegli un nome del file per esportare i dati Invalid data for this mode Dati non validi per questa modalità The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? La cella continete dati %1 non validi. Ragione: %2. Sei davvero sicuro di applicare quello alla cella? Type: NULL; Size: 0 bytes Tipo: NULL; Dimensione: 0 bytes Type: Text / Numeric; Size: %n character(s) Tipo: Testo / Numerico; Dimensione: %n carattere Tipo: Testo / Numerico; Dimensione: %n caratteri Type: %1 Image; Size: %2x%3 pixel(s) Tipo: %1 Immagine; Dimensione: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Tipo: JSON Valido; Dimensione: %n carattere Tipo: JSON Valido; Dimensione: %n caratteri Type: Binary; Size: %n byte(s) Tipo: Binario; Dimensione %n byte Tipo: Binario; Dimensione %n bytes Couldn't save file: %1. Impossibile salvare il file: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Il dato è stato salvato in un file temporaneo ed è stato aperto con l'applicazione di default. Ora puoi modificare il file e, quando sei pronto, applicare il nuovo dato salvato alla cella o annullare le modifiche. EditIndexDialog Edit Index Schema Modifica Indice Schema &Name &Nome &Table &Tabella &Unique &Univoco For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Per restringere l'indice a solo una parte della tabella puoi specificare una clausula WHERE qui che selezioni la parte della tabella che dovrà essere indicizzata Partial inde&x clause Clausola di &indice parziale Colu&mns &Colonne Table column Colonna della tabella Type Tipo Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Aggiungi una nuova espressione colonna all'indice. Le espressioni colonna contengono espressioni SQL piuttosto che i nomi delle colonne. Index column Indice di colonna Order Ordine Deleting the old index failed: %1 Cancellazione del vecchio indice fallita: %1 Creating the index failed: %1 Creazione del vecchio indice fallita: %1 EditTableDialog Edit table definition Modifica la definizione della tabella Table Tabella Advanced Avanzate Database sche&ma Sche&ma database Without Rowid Senza id riga Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. Rendi questa tavola 'WITHOUT ROWID'. Abilitare questo flag obbliga a specificare una PRIMARY KEY (che può essere di qualsiasi tipo, anche composita), e vieta il flag AUTOINCREMENT. On Conflict In caso di conflitto Strict Esatto When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Quando l'opzione "esatto" è abilitata SQLite forza il tipo di dato di ogni colonna quando si aggiorna o inserice un dato. Fields Campi Add Aggiungi Remove Rimuovi Move to top Muovi in cima Move up Muovi su Move down Muovi giù Move to bottom Muovi al fondo Name Nome Type Tipo NN NN Not null Non null PK CP <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> Chiave primaria</p></body></html> AI AI Autoincrement Autoincremento U U Unique Univoco Default Default Default value Valore di default Check Controlla Check constraint Controlla le restrizioni Collation Fascicola Foreign Key Chiave esterna <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> Chiave esterna</p></body></html> Index Constraints Vincoli Indice Add constraint Aggiungi vincolo Remove constraint Rimuovi vincolo Columns Colonne SQL SQL Foreign Keys Chiavi esterne References Riferimenti Check Constraints Vincoli di verifica <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Attenzione: </span>C'è qualcosa in questa definizione di tabella che il nostro parser non comprende. Modificare e salvare questa tabella potrebbe creare dei problemi.</p></body></html> Primary Key Chiave primaria Add a primary key constraint Aggiungi un vincolo di chiave primaria Add a unique constraint Aggiungi un vincolo di unicità There can only be one primary key for each table. Please modify the existing primary key instead. Puoi avere solo una chiave primaria per ogni tabella. Si prega di modificare la chiave primaria attuale. Error creating table. Message from database engine: %1 Error nella creazione della tabella. Messaggio dal database engine: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Esiste già un campo con quel nome. Si prega di rinominarlo prima o scegliere un nome differente per questo campo. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Questa colonna è referenziata in una chiave esterna nella tabella %1 e quindi il nome non può essere modificato. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Esiste almeno una riga con questo campo impostato a NULL. Questo rende impossibile impostare questa opzione. Si prega prima di modificare quel dato. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Esiste almeno un riga con un valore non intero in questo campo. Questo rende impossibile impostare l'AI. Si prega prima di cambiare il dato. Column '%1' has duplicate data. La colonna '%1' ha dei dati duplicati. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Questo rende impossibile abilitare l'opzionie 'Univoco'. Perfavore rimuovi i dati duplicati, il che permetterà l'abilitazione dell'opzione 'Univoco'. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Sei sicuro di voler eliminare il campo '%1'? Tutti i dati che sono attualmente memorizzati in questo campo andranno persi. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Perfavore agginugi un campo che rispetti i seguenti criteri prima di impostare l'opzione senza id di riga: - Opzione Chiave Primaria impostata - Autoincremento disabilitato Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set Si prega di aggiungere un campo che rispetti i seguenti criteri prima d'impostare l'azione "In caso di conflitto": - Impostare chiave primaria ExportDataDialog Export data as CSV Esporta i dati come CSV Tab&le(s) Tabe&lla(e) Colu&mn names in first line Nomi delle &Colonne sulla prima riga Fie&ld separator Separatore di ca&mpo , , ; ; Tab Tab | | Other Altro &Quote character &Carattere citazione " " ' ' New line characters Carattere di nuova riga Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print Visualizzazione piacevole Export data as JSON Esporta i dati come JSON exporting CSV esportando in CSV Error while writing the file '%1': %2 Errore nella scrittura del file '%1': %2 Could not open output file: %1 Impossibile aprire il file di output: %1 exporting JSON esportando in JSON Choose a filename to export data Scegliere un nome file per esportare i dati Please select at least 1 table. Perfavore seleziona almeno una tabella. Choose a directory Scegliere una cartella Export completed. Esportazione completata. Export finished with errors. Esportazione completata con errori. ExportSqlDialog Export SQL... Esporta SQL... Tab&le(s) Tabe&lla(e) Select All Seleziona tutto Deselect All Deseleziona tutto &Options &Opzioni Keep column names in INSERT INTO Tieni i nomi delle colonne in INSERT INTO Multiple rows (VALUES) per INSERT statement Righe multiple (VALUES) per lo statement INSERT Export everything Esporta tutto Export schema only Esporta solo lo schema Export data only Esporta solo i dati Keep original CREATE statements Mantieni le dichiarazioni CREATE originali Keep old schema (CREATE TABLE IF NOT EXISTS) Mantieni lo schema esistente (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Sovrascrivi schema precedente (DROP TABLE, poi CREATE TABLE) Please select at least one table. Perfavore seleziona almeno una tabella. Choose a filename to export Scegli un nome del file per esportare Export completed. Esportazione completata. Export cancelled or failed. Esportazione annullata o fallita. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Trova... Find and Replace... Trova e Sostituisci... Print... Stampa... ExtendedTableWidget Use as Exact Filter Usa come filtro esatto Containing Che contiene Not containing Non contenuto Not equal to Non uguale a Greater than Maggiore di Less than Minore di Greater or equal Maggiore o uguale Less or equal Minore o uguale Between this and... Tra questo e... Regular expression Espressione regolare Edit Conditional Formats... Modifica Formattazione Condizionale... Set to NULL Imposta a NULL Cut Taglia Copy Copia Copy with Headers Copia con gli Headers Copy as SQL Copia come SQL Paste Incolla Print... Stampa... Use in Filter Expression Usa nell'espressione del filtro Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? Il contenuto degli appunti è più grande del range selezionato. Vuoi inserirlo comunque? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>Non tutti i dati sono stati caricati. <b>Vuoi caricare tutti i dati prima di selezionare tutte le righe?</b><p><p>Rispondere <b>No</b> significa che non verranno caricati i restanti dati e la selezione non verrà effettuata.<br/>Rispondere <b>Si</b> potrebbe richiedere del tempo per caricare i dati, ma la selezione sarà completa.</p>Attenzione: Caricare tutti i dati potrebbe richiedere un grosso quantitativo di memoria in caso di grandi tabelle. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. Impossibile modificare la selezione in NULL. La colonna %1 ho un vincolo NOT NULL. FileExtensionManager File Extension Manager Gestore delle estensioni dei files &Up Porta &su &Down Porta &giù &Add &Aggiungi &Remove &Rimuovi Description Descrizione Extensions Estensioni *.extension *.estensione FilterLineEdit Filter Filtro These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Questi campi di input permettono di effettuare filtri rapidi nella tabella correntemente selezionata. er impostazione predefinita, le righe che contengono il testo immesso sono escluse. Sono inoltre supportati i seguenti operatori: % Wildcard > Maggiore di < Minore di >= Maggiore o uguale <= Minore o uguale = Uguale a: corrispondenza esatta <> Diverso: corrispondenza esatta invertita x~y Intervallo: valori tra x e y /regexp/ Valori che corrispondono all'espressione regolare Use for Conditional Format Usa per formattazioni condizionali Clear All Conditional Formats Elimina tutte le formattazioni condizionali Edit Conditional Formats... Modifica Formattazione Condizionale... Set Filter Expression Imposta l'espressione del filtro What's This? Cos'è questo? Is NULL È NULL Is not NULL Non è NULL Is empty È vuoto Is not empty Non è vuoto Not containing... Non contenente... Equal to... Uguale a... Not equal to... Non uguale a... Greater than... Maggiore di... Less than... Minore di... Greater or equal... Maggiore o uguale... Less or equal... Minore o uguale... In range... Nell'intervallo... Regular expression... Espressione regolare... FindReplaceDialog Find and Replace Trova e sostituisci Fi&nd text: Tr&ova testo: Re&place with: So&stituisci con: Match &exact case Corrispondenza &esatta Match &only whole words Trova solo &parole complete When enabled, the search continues from the other end when it reaches one end of the page Quando abilitato, la ricerca contninua dall'altro capo del documento quando si raggiunge una fine del documento &Wrap around Senza &limiti When set, the search goes backwards from cursor position, otherwise it goes forward Quando abilitato, la ricerca va all'indietro dalla corrente posizione del cursore, altrimenti va in avanti Search &backwards Cerca &indietro <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>Quando abilitato, la ricerca viene effettuata solo all'interno della selezione corrente.</p></body></html> &Selection only &Solo selezionati <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Quando selezionato, la stringa del testo viene interpretata come una espressione regolare Unix. Vedi <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Espressioni regolari su Wikibooks (in inglese)</a>.</p></body></html> Use regular e&xpressions Usa &espressioni regolari Find the next occurrence from the cursor position and in the direction set by "Search backwards" Trova la prossima occorrenza dalla corrente posizione del cursore nella direzione impostata da "Cerca indietro" &Find Next &Trova successivo F3 &Replace &Sostituisci Highlight all the occurrences of the text in the page Evidenzia tutte le occorrenze del testo nella pagina F&ind All T&rova tutti Replace all the occurrences of the text in the page Sostituisce tutte le occorrenze del testo nella pagina Replace &All Sostituisci &Tutti The searched text was not found Il testo cercato non è stato trovato The searched text was not found. Il testo cercato non è stato trovato. The searched text was found one time. Il testo cercato è stato trovato una volta. The searched text was found %1 times. Il testo cercato è stato trovato %1 volte. The searched text was replaced one time. Il testo cercato è stato sostituito una volta. The searched text was replaced %1 times. Il testo cercato è stato sostituito %1 volte. ForeignKeyEditor &Reset &Reimposta Foreign key clauses (ON UPDATE, ON DELETE etc.) Clausule per chiave esterna (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Visualizzatore immagine Reset the scaling to match the original size of the image. Reimposta il fattore di scala per rispettare la dimensione originale dell'immagine. Set the scaling to match the size of the viewport. Imposta il fattore di scala per adattare l'immagine all'area di visualizzazione. Print... Stampa... Open preview dialog for printing displayed image Apri la finestra di anteprima per stampare l'immagine mostrata Ctrl+P Ctrl+P ImportCsvDialog Import CSV file Imoprta file CSV Table na&me No&me tabella &Column names in first line Nomi &colonna nella prima riga Field &separator &Separatore di campo , , ; ; Tab Tab | | Other Altro &Quote character &Carattere citazione Other (printable) Altro (stampabile) Other (code) Altro (codice) " " ' ' &Encoding Codific&a UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? Pulizia campi? Separate tables Separa tabelle Advanced Avanzate When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Quando importo un campo vuoto dal file CSV dentro una tabella con un valore predefinito per quella colonna, quel valore viene inserito. Attivare quest'opzione per inserire invece un valore vuoto. Ignore default &values Ignora valori &predefiniti Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Attivare quest'opzione per fermare l'importazione quando si prova ad importare un valore vuoto in una colonna "NOT NULL" senza valore predefinito. Fail on missing values Fallisci su valori mancanti Disable data type detection Disabilita rilevamento tipo dati Disable the automatic data type detection when creating a new table. Disabilita il riconoscimento automatico della tipologia di dato quando crea una nuova tabella. Use local number conventions Usa convenzioni numeriche locali Use decimal and thousands separators according to the system locale. Usa i separatori decimali e di migliaia in accordo col sistema locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Quando si importano dati all'interno di una tabella esistente con una chiave primaria, potrebbero esserci conflitti. Questa opzione ti permette di selezionare una strategia per quei casi: Di base l'importazione è annullata e viene fatto un rollback, ma puoi anche scegliere d'ignorare e non importare le righe in conflitto o di rimpiazzare quelle presenti nella tabella. Abort import Annulla l'importazione Ignore row Ignora la riga Replace existing row Rimpiazza la riga esistente Conflict strategy Strategia di conflitto Deselect All Deseleziona tutte Match Similar Seleziona simili Select All Seleziona tutte There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Esiste già una tabella col nome '%1' e l'importazione in una tabella esistente non è possibile se il numero di colonne non corrisponde. There is already a table named '%1'. Do you want to import the data into it? Esiste già una tabella col nome '%1'. Vuoi importare i dati al suo interno? Creating restore point failed: %1 Creazione del punto di ripristino fallita: %1 Creating the table failed: %1 Creazione della tabella fallita: %1 importing CSV importo il CSV Could not prepare INSERT statement: %1 Non posso preparae la dichiarazione INSERT: %1 Inserting row failed: %1 Inserimento della riga fallito: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Fine del file inaspettata. Si prega di verificare l'impostazione corretta dei caratteri di citazione e che il file non sia malformato. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Importare il file '%1' ha richiesto %2ms. Di questi %3ms sono stati spesi in funzioni di riga. MainWindow DB Browser for SQLite DB Browser for SQLite This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Questa è la struttura del database aperto. Puoi trascinare SQL da una riga oggetto e rilasciarli dentro altri applicativi o in altre istanze di àDB Browser for SQLite'. Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Attenzione: questo pragma non è leggibile e questo valore è stato dedotto. Scrivere i pragma può sovrascrivere un LIKE ridefinito provvisto da un'estensione di SQLite. toolBar1 &File &File &Import &Importa &Export &Esporta &Edit &Modifica &View &Visualizza &Help &Aiuto Too&ls &Strumenti DB Toolbar Barra degli strumenti del DB Edit Database &Cell Modifica &cella SQL &Log &Log SQL Show S&QL submitted by Mostra l'S&QL inviato da User Utente Application Applicazione Error Log Registro errori This button clears the contents of the SQL logs Questo pulsante cancella il contenuto del log SQL &Clear &Pulisci This panel lets you examine a log of all SQL commands issued by the application or by yourself Questo pannello ti permette di esaminare il log di tutti i comandi SQL inviati dall'applicazione o da te stesso &Plot &Grafica DB Sche&ma Sche&ma DB This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Questa è la struttura del database aperto. Puoi trascinare nomi d'oggetto multipli dalla colonna "Nome" e rilasciarli all'interno dell'editor SQL e puoi modificare le proprietà dei nomi rilasciati utilizzando il menù contestuale. Questo può aiutarti nel comporre statement SQL. Puoi trascinare statement SQL dalla colonna Schema e rilasciarli dentro l'editor SQL o all'interno di altre applicazioni. &Remote &Remoto Project Toolbar Barra degli strumenti di progetto Extra DB toolbar Barra degli strumenti extra DB Close the current database file Chiudi il file di database corrente &New Database... &Nuovo Database... Create a new database file Crea un nuovo file di database This option is used to create a new database file. Questa opzione è utilizzata per creare un nuovo file di database. Ctrl+N &Open Database... &Apri Database... Open an existing database file Apre un file di database esistente This option is used to open an existing database file. Questa opzione è utilizzata per aprire un file esistente di database. Ctrl+O &Close Database &Chiudi Database This button closes the connection to the currently open database file Questo pulsnate chiude la connessione al file di database attualmente aperto Ctrl+W &Revert Changes &Ripristina le modifiche Revert database to last saved state Ripristina il database all'ultimo stato salvato This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Questa opzione è utilizzata per ripristinare il file di database al suo ultimo stato salvato. Tutte le modifiche fatte dall'ultima opzione di salvataggio sono perse. &Write Changes &Salva le modifiche Write changes to the database file Scrive le modifiche sul file di database This option is used to save changes to the database file. Questa opzione è utilizzata per salvare le modifiche sul file di database. Ctrl+S Compact &Database... &Compatta Database... Compact the database file, removing space wasted by deleted records Compatta il file di database, rimuovendo lo spazio sprecato dalle righe eliminate Compact the database file, removing space wasted by deleted records. Compatta il file di database rimuovendo lo spazio sprecato dalle righe eliminate. E&xit &Esci Ctrl+Q &Database from SQL file... &Database dal file SQL... Import data from an .sql dump text file into a new or existing database. Importa i dati da un file di testo di dump .sql all'interno di un database nuovo o esistente. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Questa opzione ti permette d'importare i dati da un file di testo di dump .sql all'interno di un database nuovo o esistente. I file di dump SQL possono essere creati dalla maggiorparte dei motori SQL, inclusi MySQL e PostgreSQL. &Table from CSV file... &Tabella da file CSV... Open a wizard that lets you import data from a comma separated text file into a database table. Apre un wizard che ti permette d'importare dati da un file CSV all'interno di una tabella del database. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Apre un wizard che ti permette d'importare dati da un file CSV all'interno di una tabella del database. I file CSV possono essere creati dalla maggiorparte delle applicazioni database o foglio di calcolo. &Database to SQL file... &Database in file SQL... Export a database to a .sql dump text file. Esporta un database in un file di testo di dump .sql. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Questa opzione ti permette di esportare un database in un file di testo di dump .sql. Il file di dump SQL contiene tutti i dati necessari per ricreare il database sulla maggiorparte di motori di database, inclusi MySQL e PostgreSQL. &Table(s) as CSV file... &Tabella(e) come file CSV... Export a database table as a comma separated text file. Esporta la tabella del database come un file di testo CSV. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Esporta la tabella del database come un file di testo CSV, pronto per essere importato in un altro database o foglio di calcolo. &Create Table... &Crea tabella... Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Apre un wizard per la creazione di una tabella, dov'è possibile definire il nome e i campi di una nuova tabella del database &Delete Table... &Elimina tabella... Delete Table Elimina Tabella Open the Delete Table wizard, where you can select a database table to be dropped. Apre un wizard per la cancellazione della tabella, da qui puoi selezionare la tabella del database da eliminare. &Modify Table... &Modifica Tabella... Create &Index... Crea &Indice... Open the Create Index wizard, where it is possible to define a new index on an existing database table. Apre un wizard per la crazione di un indice, da qui è possibile definire un nuovo indice s'una tabella di database pre-esistente. &Preferences... &Preferenze... Open the preferences window. Apre la finestra delle preferenze. &DB Toolbar &Barra degli strumenti Shows or hides the Database toolbar. Mostra o nasconde la barra degli strumenti del database. New &tab Nuovo &tab Ctrl+T Open SQL file(s) Apri file(s) SQL This button opens files containing SQL statements and loads them in new editor tabs Questo pulsante apre files contenenti dichiarazioni SQL e le carica in un nuova scheda dell'editor Execute line Esegui riga F1 Sa&ve Project Sal&va Progetto This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Questo pulsante ti permette di salvare tutte le impostazioni associate all'apertura di un DB in un nuovo file di progetto DB Browser for SQLite This button lets you open a DB Browser for SQLite project file Questo pulsante ti permette di aprire un file di progetto DB Browser for SQLite Ctrl+Shift+O Find Trova Find or replace Trova o sostituisci Print text from current SQL editor tab Stampa testo dalla scheda corrente dell'editor SQL Print the structure of the opened database Stampa la struttura del database aperto Un/comment block of SQL code De/Commenta il blocco di codice SQL Un/comment block De/Commenta il blocco Comment or uncomment current line or selected block of code Commenta o decommenta la riga corrente o il blocco selezionato di codice Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Commenta o decommenta le righe selezionate o la riga corrente, quando non c'è nessuna selezione. Tutti i blocchi sono modificati in accordo alla prima riga. Ctrl+/ Stop SQL execution Ferma esecuzione SQL Stop execution Ferma esecuzione Stop the currently running SQL script Ferma lo script SQL attualmente in esecuzione &Save Project As... Salva Progetto C&ome... Save the project in a file selected in a dialog Salva il progetto in un file selezionato tramite una finestra di dialogo Save A&ll Salva T&utto Save DB file, project file and opened SQL files Salva il file DB, file di progetto e tutti i file SQL aperti Ctrl+Shift+S Browse Table Naviga nei dati Close Pro&ject Chiudi Pro&getto Close project and database files and return to the initial state Chiude il progetto e i file di database e ritorna allo stato iniziale Ctrl+Shift+F4 Ctrl+Shift+F4 Detach Database Scollega Database Detach database file attached to the current database connection Scollega il file di database associato alla connessione corrente W&hat's This? Cos'è &questo? &Database Structure This has to be equal to the tab title in all the main tabs Struttura &Database &Browse Data This has to be equal to the tab title in all the main tabs &Visualizza Dati Edit P&ragmas This has to be equal to the tab title in all the main tabs Modifica P&ragmas E&xecute SQL This has to be equal to the tab title in all the main tabs &Esegui SQL &Recent Files F&iles Recenti &New Database &Nuovo Database &Undo A&nnulla Undo last change to the database Annulla l'ultima modifica al database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Questa azione annulla l'ultima modifica effettuata al database in "Visualizza Dati" o in "Esegui SQL". Riapplicarla non è possibile. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Apre il wizard per Modificare la Tabella, in cui è possibile rinominare una tabella esistente. Si può anche aggiungere o eliminare campi da una tabella così come modificarne nome e tipo. Shift+F1 &About &Informazioni &Recently opened &Aperti di recente This button opens a new tab for the SQL editor Questo pulsante apre una nuova schede dell'editor SQL &Execute SQL &Esegui SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Questo pulsante esegue gli statement SQL evidenziati. Se nessun testo è selezionato, tutti gli statement SQL vengono eseguiti. Ctrl+Shift+T Ctrl+Shift+T Save SQL file Salva file SQL &Load Extension... &Carica Estensioni... Execute current line Esegue la riga corrente This button executes the SQL statement present in the current editor line Questo pulsante esegue lo statement SQL presente nella riga corrente dell'editor Shift+F5 Export as CSV file Esporta come file CSV Export table as comma separated values file Esporta la tabella come file CSV &Wiki &Wiki Bug &Report... Bug &Report... Feature Re&quest... Richiesta &Funzionalità... Web&site Sito &Web &Donate on Patreon... &Dona su Patreon... &Save Project &Salva Progetto Save the current session to a file Salva la sessione correte in un file Open &Project... Apri &Progetto... Open &Project Apri &Progetto Load a working session from a file Carica una sessione di lavoro da file &Attach Database... Co&llega Database... Add another database file to the current database connection Aggiunge un altro file di database alla connessione corrente This button lets you add another database file to the current database connection Questo pulsante ti permette di aggiungere un altro file alla connessione corrente &Set Encryption... &Imposta cifratura... Save SQL file as Salva file SQL come This button saves the content of the current SQL editor tab to a file Questo pulsante salva il contenuto della scheda di editor SQL in un file &Browse Table &Naviga Tabella Copy Create statement Copia statement CREATE Copy the CREATE statement of the item to the clipboard Copia lo statement CREATE negli appunti SQLCipher &FAQ SLQCipher &FAQ Opens the SQLCipher FAQ in a browser window Apre le SQLCipher FAQ in una finestra del browser Table(&s) to JSON... Tabella(&e) in JSON... Export one or more table(s) to a JSON file Esporta una o più tabelle in un file JSON Open Data&base Read Only... Apri un Data&base in Sola Lettura... Open an existing database file in read only mode Apre un file databse esistente in modalità sola lettura Save results Salva risultati Save the results view Salva i risultati della vista This button lets you save the results of the last executed query Questo pulsante ti permette di salvare i risultati dell'ultima query eseguita Find text in SQL editor Trova testo nell'editor SQL This button opens the search bar of the editor Questo pulsante apre la barra di ricerca dell'editor Ctrl+F Find or replace text in SQL editor Trova e/o sostituisci testo nell'editor SQL This button opens the find/replace dialog for the current editor tab Questo pulsante apre la finestra di ricerca/sostituzione testo per la scheda corrente dell'editor Ctrl+H Export to &CSV Esporta in &CSV Export to &JSON Esporta in &JSON Save as &view Salva come &vista Save as view Salva come vista Shows or hides the Project toolbar. Mostra o nasconde la barra degli strumenti di progetto. Extra DB Toolbar Barra degli strumenti DB estesa &Open Database &Apri Database New In-&Memory Database Nuovo Database In M&emoria Drag && Drop SELECT Query Trascina && Rilascia Query SELECT When dragging fields from the same table or a single table, drop a SELECT query into the editor Quando si trascinano campi da una stessa tabella o una singola tabella, rilascia una query SELECT nell'editor Drag && Drop Qualified Names Trascina && Rilascia Nomi Qualificati Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Usa nomi qualificati (es. "Table"."Campo") quando trascini gli oggetti e li rilasci all'interno dell'editor Drag && Drop Enquoted Names Trascina && Rilascia Nomi Quotati Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Usa gl'identificatori di citazione (es. "Tabella1") quando trascini e rilasci gli oggetti nell'editor &Integrity Check Controllo &Integrità Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. Avvia il controllo integrità (integrity check pragma) sul database aperto e riporta il risultato nella scheda "Esegui SQL". Questa operazione esegue un controllo d'integrità sull'intero database. &Foreign-Key Check Controlla Chiave &Esterna Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Avvia il controllo chiavi esterne (foreign_key_check pragma) nel database aperto e riporta il risultato nella scheda "Esegui SQL" &Quick Integrity Check Controllo Integrità &Veloce Run a quick integrity check over the open DB Avvia un controllo veloce d'integrità sul DB aperto Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. Avvia un controllo veloce d'integrità (quick_check pragma) sul database e riporta il risultato nella scheda "Esegui SQL". Quest comando esegue la maggiorparte dei controlli d'integrità del controllo completo, ma in modo molto più veloce. &Optimize &Ottimizza Attempt to optimize the database Prova ad ottimizzare il database Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Avvia l'ottimizzazione del database aperto. Questa operazione potrebbe eseguire delle ottimizzazione che miglioreranno le performance delle query future. Print Stampa Open a dialog for printing the text in the current SQL editor tab Apre una finetra per la stampa del testo nella scheda dell'editor SQL Open a dialog for printing the structure of the opened database Apre una finestra per la stampa della struttura del database aperto Ctrl+Shift+W Ctrl+Shift+W Table from CSV data in Clipboard... Tabella da dati CSV negli Appunti... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Questo tratta il contenuto attuale degli Appunti come un file CSV e apre lo stesso wizard d'importazione che viene utilizzato per importare dati da un file CSV. Show &Row Counts Mostra Numero &Righe This shows the number of rows for each table and view in the database. Questo mostra il numero di righe per ogni tabella e vista del database. Save Database &As... Salva Database Co&me... Save the current database as a different file Salva il database corrente in un diverso file Refresh Aggiorna Reload the database structure Aggiorna la struttura del database Ctrl+P Ctrl+F4 Execute all/selected SQL Esegui tutti gli SQL o quelli selezionati Ctrl+Return Ctrl+L Ctrl+D Ctrl+I Ctrl+E Reset Window Layout Ripristina disposizione finestra The database is currently busy. Il database è occupato. Click here to interrupt the currently running query. Clicca qui per interrompere la query in esecuzione. Encrypted Criptato Database is encrypted using SQLCipher Il database è stato criptato utilizzando SQLCipher Read only Sola lettura Database file is read only. Editing the database is disabled. Il file di database è in sola lettura. Le modifiche al database sono disabilitate. Database encoding Codifica Database Choose a database file Seleziona un file di database Could not open database file. Reason: %1 Impossibile aprire il file di database. Motivo: %1 Choose a filename to save under Seleziona un nome file per il salvataggio In-Memory database Database In-Memoria Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Sei sicuro di voler eliminare la tabella '%1'? Tutti i dati associati alla tabella andranno perduti. Are you sure you want to delete the view '%1'? Sei sicuro di voler eliminare la vista '%1'? Are you sure you want to delete the trigger '%1'? Sei sicuro di voler eliminare il trigger '%1'? Are you sure you want to delete the index '%1'? Sei sicuro di voler eliminare l'indice '%1'? Error: could not delete the table. Errore: impssibile eliminare la tabella. Error: could not delete the view. Errore: impossibile eliminare la vista. Error: could not delete the trigger. Errore: impossibile eliminare il trigger. Error: could not delete the index. Errore: impossibile eliminare l'indice. Message from database engine: %1 Messaggio dal database: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Per modificare la tabella bisogna salvare tutte le modifiche pendenti. Sei sicuro di voler salvare il database? Error checking foreign keys after table modification. The changes will be reverted. Errore nel controllo delle chiavi esterne dopo le modifiche alla tabella. Le modifiche saranno eliminate. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Questa tabella non ha passato il controllo sulle chiavi esterne.<br/>Dovresti avviare 'Strumenti | Controllo Chiavi Esterne' e correggere i problemi riportati. Edit View %1 Modifica Vista %1 Edit Trigger %1 Modifica Trigger %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. Sto eseguendo degli SQL. Vuoi fermarli per poter eseguire invece l'SQL corrente? Nota che questo potrebbe lasciare il database in uno stato inconsistente. -- EXECUTING SELECTION IN '%1' -- -- ESEGUO LA SELEZIONE IN '%1' -- -- EXECUTING LINE IN '%1' -- -- ESEGUO LINEA IN '%1' -- -- EXECUTING ALL IN '%1' -- -- ESEGUO TUTTO IN '%1' -- At line %1: Alla riga %1: Result: %1 Risultato: %1 Result: %2 Risultato: %2 Opened '%1' in read-only mode from recent file list Aperto '%1' in modalità sola lettura dalla lista dei files recenti Opened '%1' from recent file list Aperto '%1' dalla lista dei files recenti The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? Le dichiarazioni nella scheda '%1' sono ancora in esecuzione. Chiudere la scheda fermerà l'esecuzione. Questo potrebbe lasciare il database in uno stato inconsistente. Sei sicuro di voler chiudere la scheda? This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Questo file di progetto utilizza un vecchio formato perché è stato creato con DB Browser for SQLite versione 3.10 o precedente. Il caricamento di questo formato non è più pienamente supportato. Se vuoi caricarlo completamente, si prega di utilizzare DB Browser for SQLite versione 3.12 per convertirlo al nuovo formato. Project saved to file '%1' Progetto salvato sul file '%1' Yes. Don't ask again Si, non chiedere di nuovo This action will open a new SQL tab with the following statements for you to edit and run: Questa azione apre una nuova scheda SQL con le seguenti dichiarazioni per te da editare ed eseguire: Rename Tab Rinomina il Tab Duplicate Tab Duplica il Tab Close Tab Chiudi il Tab Opening '%1'... Apro '%1'... There was an error opening '%1'... Errore durante l'apertura di '%1'... Value is not a valid URL or filename: %1 Il valore non è un URL valida o nome file: %1 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Impostare i valori PRAGMA o pulizia chiuderanno la transazione corrente. Sei sicuro? Execution finished with errors. Esecuzione completata con errori. Execution finished without errors. Esecuzione completata senza errori. %1 rows returned in %2ms %1 righe ritornate in %2ms Automatically load the last opened DB file at startup Carica automaticamente l'ultimo file DB aperto all'avvio Choose text files Seleziona i file di testo Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Errore nel salvataggio del database. Questo significa che non tutte le modifiche del database sono state salvate. Avrai bisogno di risolvere prima il seguente errore. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? Sei sicuro di voler annullare tutte le modifiche effettuate al database '%1' dall'ultimo salvataggio? Choose a file to import Seleziona un file da importare &%1 %2%3 &%1 %2%3 (read only) (sola lettura) Open Database or Project Apri Database o Progetto Attach Database... Collega Database... Import CSV file(s)... Importa file(s) CSV... Do you want to save the changes made to SQL tabs in the project file '%1'? Vuoi salvare le modifiche effettuate ai tabs SQL nel file di progetto '%1'? Text files(*.sql *.txt);;All files(*) File di testo(*.sql *.txt);;Tutti i files(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Vuoi creare un nuovo file di database per mantenere i dati importati? Se rispondi di no proveremo ad importare i dati del file SQL all'interno del database corrente. Ctrl+Tab Ctrl+Tab Ctrl+Shift+Tab Ctrl+Shift+Tab Clear List Pulisci la Lista Window Layout Disposizione finestra Ctrl+Alt+0 Ctrl+Alt+0 Simplify Window Layout Semplifica Disposizione Finestra Alt+Shift+0 Alt+Shift+0 Dock Windows at Bottom Posiziona Finestre nel Basso Dock Windows at Left Side Posiziona Finestre sul Lato Sinistro Dock Windows at Top Posiziona Finestre in Alto Ctrl+Alt+W Ctrl+Alt+W Choose a database file to save under Scegli il file database in cui salvare Error while saving the database to the new file. Errore nel salvataggio in un nuovo file di database. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Sto ancora eseguendo comandi SQL. Se chiudi il database ora non verrano eseguiti, il database potrebbe rimanere in uno stato inconsistente. Sei sicuro di voler chiudere il database? Do you want to save the changes made to the project file '%1'? Vuoi salvare le modifiche fatte al file di progetto '%1'? File %1 already exists. Please choose a different name. Il file %1 esiste già. Si prega di scegliere un nome differente. Error importing data: %1 Errore nell'importazione: %1 Import completed. Some foreign key constraints are violated. Please fix them before saving. Importaizone completata. Alcuni vincoli per le chiavi esterne non sono rispettati. Si prega di correggerli prima di salvare. Import completed. Import completato. Delete View Elimina Vista Modify View Modifica Vista Delete Trigger Elimina Trigger Modify Trigger Modifica Trigger Delete Index Elimina Indice Modify Index Modifica Indice Modify Table Modifica Tabella Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Seleziona l'azione da applicare al file scartato. <br/>Nota: solo 'Importa' processa più di un file. Seleziona l'azione da applicare ai files scartati. <br/>Nota: solo 'Importa' processa più di un file. Setting PRAGMA values will commit your current transaction. Are you sure? Impostare i valori di PRAGMA chiuderà la transaione corrente. Sei sicuro? Do you want to save the changes made to SQL tabs in a new project file? Vuoi salvare le modifiche effettuate alle schede SQL in un nuovo file di progetto? Do you want to save the changes made to the SQL file %1? Vuoi salvare le modifiche fatte al file SQL %1? Select SQL file to open Selezionare il file SQL da aprire Select file name Seleziona il nome del file Select extension file Seleziona l'estensione del file Extension successfully loaded. Estensione caricata con successo. Error loading extension: %1 Errore nel caricamento dell'estensione: %1 Could not find resource file: %1 Non posso aprire il file di risorse: %1 Don't show again Non mostrare di nuovo New version available. Nuova versione disponibile. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Una nuova versione di DB Browser for SQLite è disponibile (%1.%2.%3).<br/><br/>Si prega di scaricarla da <a href='%4'>%4</a>. Choose a project file to open Seleziona un file di progetto da aprire DB Browser for SQLite project file (*.sqbpro) File di progetto DB Browser for SQLite (*.sqbpro) DB file '%1' could not be opened Il file DB '%1' non può essere aperto Table '%1' not found; settings ignored Tabella '%1' non trovata; impostazioni ignorate Could not open project file for writing. Reason: %1 Non posso scrivere nel file di progetto. Motivo: %1 -- Reference to file "%1" (not supported by this version) -- -- Riferimento al file "%1" (non supportato in questa versione) -- Collation needed! Proceed? Necessario confronto! Procedo? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Una tabella di questo database richiede una funzione di confronto speciale '%1' che questa applicazione non può fornire senza ulteriori informazioni. Se scegli di proseguire, sappi che potrebbero generarsi problemi nel tuo database. Crea un backup! creating collation creo confronto Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Imposta un nuovo nome per la scheda SQL. Usa il carattere '&&' per utilizzare il carattere succesivo come scorciatoia da tastiera. Please specify the view name Si prega di specificare il nome della vista There is already an object with that name. Please choose a different name. Esiste già un oggetto con quel nome. Si prega di scegliere un nome diverso. View successfully created. Vista creata con successo. Error creating view: %1 Errore nella creazione della vista: %1 This action will open a new SQL tab for running: Questa azione aprirà una nuova scheda SQL per eseguire: Press Help for opening the corresponding SQLite reference page. Premi Aiuto per aprire la pagina di riferimento SQLite corrispondente. Busy (%1) Occupato (%1) NullLineEdit Set to NULL Imposta a NULL Alt+Del PlotDock Plot Grafico <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Questo pannello mostra la lista delle colonne della tabella corrente o della query eseguita. Puoi selezionare la colonna che vuoi utilizzare come asse X o Y per il grafico sottostante. La tabella mostra i tipi d'asse rilevati. Per l'asse Y puoi selezionare solo colonne numeriche, ma per l'asse X potrai selezionare:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data/Ora</span>: stringhe col formato &quot;aaaa-MM-gg hh:mm:ss&quot; o &quot;aaaa-MM-ggThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data</span>: stringhe col formato &quot;aaaa-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Orario</span>: stringhe col formato &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Etichette</span>: altri formati di stringa. Selezionando queste colonne come X verrà visualizzato un grafico a barre</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeri</span>: interi or valori reali</li></ul><p>Cliccando due volte sulle celle Y potrai cambiare il colore utilizzato per il grafico.</p></body></html> Columns Colonne X Y1 Y1 Y2 Y2 Axis Type Tipo asse Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Qui compare il grafico quando vengono selezionati i valori x e y. Clicca s'un punto per selezionarl sul grafico e nella tabella. Ctrl+Click per selezionare un intervallo di punti. Usa la rotella del mouse per ingrandire e trascina col mouse per cambiare l'intervallo degli assi. Seleziona le etichette dell'asse o degli assi per trascinare o ingrandire solo in quella direzione. Line type: Tipo linea: None Nessuna Line Linea StepLeft Salto sinistro StepRight Salto destro StepCenter Salto centrato Impulse Impulso Point shape: Tipo punta: Cross Croce Plus Più Circle Cerchio Disc Disco Square Quadrato Diamond Rombo Star Stella Triangle Triangolo TriangleInverted Triangolo inverso CrossSquare Croce quadrato PlusSquare Più quadrato CrossCircle Croce cerchio PlusCircle Più cerchio Peace Pace <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Salva il grafico corrente...</p><p>Formato file selezionato dall'estensione (png, jpg, pdf, bmp)</p></body></html> Save current plot... Salva il grafico corrente... Load all data and redraw plot Carica tutti i dati e ridisegna grafico Copy Copia Print... Stampa... Show legend Mostra legenda Stacked bars Barre impilate Fixed number format Formato numero fisso Date/Time Data/Ora Date Data Time Ora Numeric Numerico Label Etichetta Invalid Invalido Row # Riga # Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Carica tutti i dati e ridisegna grafico. Attenzione: non sono ancora stati recuperati tutti i dati dalla tabella a causa del meccanismo di recupero. Choose an axis color Scegli il colore per l'asse Choose a filename to save under Scegli il nome di salvataggio PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Ci sono delle curve in questo grafico e lo stile di line selezionato può essere applicato solo a grafici ordinati per X. Riordina la tabella o seleziona per X per rimuovere le curve o seleziona uno degli stili supportati dalle curve: Nessuno o Linea. Loading all remaining data for this table took %1ms. Caricare tutti i dati restanti per questa tabella ha richiesto %1ms. PreferencesDialog Preferences Preferenze &General &Generale Default &location &Posizione di default Remember last location Ricorda l'ultima posizione Always use this location Usa sempre questa posizione Remember last location for session only Ricorda l'ultima posizione solo per questa sessione ... Lan&guage Lin&gua Toolbar style Stile barra degli strumenti Only display the icon Mostra solo le icone Only display the text Mostra solo il testo The text appears beside the icon Mostra il testo a lato delle icone The text appears under the icon Mostra il testo sotto le icone Follow the style Segui lo stile Show remote options Mostra opzioni remote enabled abilitato Automatic &updates Aggiornamenti a&utomatici DB file extensions Estensioni file DB Manage Gestisci Main Window Finestra principale Database Structure Struttura database Browse Data Naviga nei dati Execute SQL Esegui SQL Edit Database Cell Modifica Cella Database When this value is changed, all the other color preferences are also set to matching colors. Quando questo valore viene modificato, tutte le altre preferenze di colore vengono impostate al colore corrispondente. Follow the desktop style Segui lo stile del desktop Dark style Stile scuro Application style Stile Applicazione This sets the font size for all UI elements which do not have their own font size option. Imposta la dimensione del carattere per tutti gli elementi dell'interfaccia che non hanno una loro opzione dedicata. Font size Dimensione testo Max Recent Files Numero di files recenti Prompt to save SQL tabs in new project file Chiedi di salvare schede SQL in un nuovo file di progetto If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Se questo è abilitato, quando ci sono modifiche nell'editor SQL genera una finestra per salvarle in un file di progetto quando si chiude la scheda dell'editor SQL. &Database Database &encoding &Codifica Database Open databases with foreign keys enabled. Apri database contenenti chiavi esterne. &Foreign keys Chiavi &Esterne Remove line breaks in schema &view Rimuovi a-capo nella &vista dello schema When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Quando abilitato, vengono rimossi gli a-capo nella colonna dello Schema del tab "Struttura DB", dock e stampa. Prefetch block si&ze &Dimensione blocco di prefetch SQ&L to execute after opening database SQ&L da eseguire dopo aver aperto il database Default field type Tipo di campo di default Database structure font size Dimensione carattere struttura DB Data &Browser Font &Font Font si&ze Dimensione te&sto Content Contenuto Symbol limit in cell Limite simboli nella cella This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Questo è il numero massimo di oggetti permessi per l'esecuzione di alcune funzioni computazionalmente intense: Massimo numero di righe in una tabella per abilitare l'autocompletamento basato sui valori correnti di una colonna. Massimo numero di indici in una selezione per calcolare somma e media. Può essere impostato a 0 per disabilitare le funzionalità. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Questo è il numero massimo di righe in una tabella per abilitare il completamento dei valori basandosi su quelli attualmente nella colonna. Può essere impostato a 0 per disabilitare il completamento. Field display Visualizzazione campi Displayed &text &Testo visualizzato Binary Binario NULL Regular Normale Click to set this color Clicca per impostare questo colore Text color Colore del testo Background color Colore dello sfondo Preview only (N/A) Solo anteprima (N/A) Filters Filtri Escape character Carattere di escape Delay time (&ms) Ritardo (&ms) Light style Stile chiaro Formatted Formattato Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Imposta il tempo d'attesa prima che un nuovo filtro venga applicato. Può essere impostato a 0 per disabilitare l'attesa. &SQL &SQL Context Contesto Colour Colore Bold Grassetto Italic Corsivo Underline Sottolinea Keyword Parola chiave Function Funzione Table Tabella Comment Commento Identifier Identificatore String Stringa Current line Linea corrente Background Sfondo Foreground Primo piano Selection background Sfondo selezione Selection foreground Primo piano selezione Highlight Evidenziato SQL editor &font &Font editor SQL SQL &editor font size Dimensione font &editor SQL SQL &results font size Dimensione font &risultati SQL Tab size Dimensione tabulazione Use tabs for indentation Utilizza tabulatura per l'indentazione When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. Quando impostato, il tasto Tab inserisce un carattere tab per l'indentazione. Altrimenti verrannu utilizzati gli spazi. &Wrap lines &A-capo automatico Never Mai At word boundaries Al limite della parola At character boundaries Al limite del carattere At whitespace boundaries Al limite del carattere vuoto &Quotes for identifiers Identificatori per &citazioni Choose the quoting mechanism used by the application for identifiers in SQL code. Scegli il tipo meccanismo di citazione utilizzato per il codice SQL. "Double quotes" - Standard SQL (recommended) "Doppie virgolette" - Standard SQL (raccomandato) `Grave accents` - Traditional MySQL quotes `Apice inverso` - Citazione tradizionale MySQL [Square brackets] - Traditional MS SQL Server quotes [Parentesi quadre] - Citazione tradizionale MS SQL Server Code co&mpletion Auto co&mpletamento Keywords in &UPPER CASE Parole chiave &MAIUSCOLE When set, the SQL keywords are completed in UPPER CASE letters. Quando impostato, le parole chiave vengono completate in MAIUSCOLO. Error indicators Indicatori d'errore When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Quando impostato, le righe di codice SQL che causano errori durante l'ultima esecuzione sono evidenziate e il campo del risultato indica l'errore sullo sfondo Hori&zontal tiling Affianca &orizzontalmente If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Se abilitato l'editor di codice SQL e la tabella del risultato sono mostrate una accanto all'altra anzichè una sopra l'altra. Close button on tabs Pulsante di chiusura sulle schede If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Se abilitato, le schede dell'editor SQL avranno un pulsante per la chiusura. In ogni caso, puoi utilizzare il menù contestuale o le scorciatoie da tastiera per chiuderle. &Extensions &Estensioni Select extensions to load for every database: Seleziona le estensioni da caricare per ogni database: Add extension Aggiungi estensione Remove extension Rimuovi estensione Select built-in extensions to load for every database: Seleziona quali estensioni incluse caricare per ogni database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>Anche se SQLite supporta l'operatore REGEXP non implementa alcun algoritmo<br/>di espressione regolare, ma richiama l'applicativo in esecuzione. DB Browser for SQLite implementa questo<br/>algoritmo per te per permetterti di usare le REGEXP immediatamente. Ci sono però multiple implementazioni<br/>possibili e potresti voler utilizzare una o l'altra, sei libero di disabilitare l'implementazione<br/>dell'applicativo e caricare la tua utilizzando un'estensione. Richiede il riavvio dell'applicativo.</p></body></html> Disable Regular Expression extension Disabilita l'estensione per l'Espressione regolare <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite fornisce una funzione SQL per il cariamento di estensioni da una libreria dinamica condivisa. Attiva questa opzione se vuoi utilizzare la funzione<span style=" font-style:italic;">load_extension()</span> dal codice SQL.</p><p>Per motivi di sicurezza, il caricamento delle estensioni è disabilitato di default e dev'essere abilitato tramite questa impostazione. Puoi sempre caricare le estensioni attraverso l'interfaccia grafica, anche se quest'opzione è disabilitata.</p></body></html> Allow loading extensions from SQL code Permetti il caricamento di estensioni dal codice SQL Remote Remoto CA certificates Certificati CA Proxy Proxy Configure Configura Export Settings Esporta Impostazioni Import Settings Importa Impostazioni Subject CN Soggetto CN Common Name Nome comune Subject O Soggetto O Organization Organizzazione Valid from Valido dal Valid to Valido al Serial number Numero di serie Your certificates Tuo certificato Threshold for completion and calculation on selection Soglia per l'autocompletamento e il calcolo sulla selezione Show images in cell Mostra immagini nella cella Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Abilita questa opzione per mostrare un'anteprima dei BLOBs contenti dati immagine nella cella. Questo potrebbe impattare sulle performance. File File Subject Common Name Nome comune del soggetto Issuer CN CN emittente Issuer Common Name Nome comune emittente Clone databases into Clona il database in Choose a directory Seleziona una cartella The language will change after you restart the application. La lingua verrà modificata dopo il riavvio dell'applicativo. Select extension file Seleziona il file d'estensione Extensions(*.so *.dylib *.dll);;All files(*) Estensioni(*.so *.dylib *.dll);;Tutti i files(*) Import certificate file Importa il file di certificato No certificates found in this file. Nessun certificato trovato in questo file. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Sei sicuro di voler rimuovere questo certificato? Tutti i dati del certificato saranno eliminati dalle impostazioni dell'applicativo! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Sei sicuro di voler pulire tutte le impostazioni salvate? Tutte le tue preferenze andranno perse e verranno utilizzati i valori predefiniti. Save Settings File Salva file Impostazioni Initialization File (*.ini) File Inizializzazione (*.ini) The settings file has been saved in location : Il file delle impostazioni è stato salvato in : Open Settings File Apri file impostazioni The settings file was loaded properly. Il file delle impostazioni è stato caricato correttamente. The selected settings file is not a normal settings file. Please check again. Il file delle impostazioni selezionato non è un file corretto. Si prega di ricontrollare. ProxyDialog Proxy Configuration Configurazione proxy Pro&xy Type Tipo Pro&xy Host Na&me No&me host Port Porta Authentication Re&quired Autenticazione ri&chiesta &User Name Nome &Utente Password Password None Nessuna System settings Impostazioni di sistema HTTP HTTP SOCKS5 SOCKS5 QObject All files (*) Tutti i files (*) Error importing data Errore nell'import dei dati from record number %1 dalla riga numero %1 . %1 . %1 Importing CSV file... Importa file CSV... Cancel Annulla SQLite database files (*.db *.sqlite *.sqlite3 *.db3) File database SQLite (*.db *.sqlite *.sqlite3 *.db3) SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) File di progetto DB Browser for SQLite (*.sqbpro) SQL Files (*.sql) SQL Files (*.sql) All Files (*) Tutti i files (*) Text Files (*.txt) File testuali (*.txt) Comma-Separated Values Files (*.csv) File con valori separati da virgola (*.csv) Tab-Separated Values Files (*.tsv) Files con valori separati da tabulazione (*.tsv) Delimiter-Separated Values Files (*.dsv) Files con valori separati da delimitatore (*.dsv) Concordance DAT files (*.dat) File DAT Concordance (*.dat) JSON Files (*.json *.js) JSON Files (*.json *.js) XML Files (*.xml) XML Files (*.xml) Binary Files (*.bin *.dat) Files binari (*.bin *.dat) SVG Files (*.svg) SVG Files (*.svg) Hex Dump Files (*.dat *.bin) Hex Dump Files (*.dat *.bin) Extensions (*.so *.dylib *.dll) Estensioni (*.so *.dylib *.dll) Initialization File (*.ini) File inizializzazione (*.ini) Left Sinistra Right Destra Center Centrato Justify Giustificato QsciCommand Move down one line Sposta in basso di una riga Extend selection down one line Estendi la selezione in basso di una riga Extend rectangular selection down one line Estendi la selezione rettangolare in basso di una riga Scroll view down one line Scorri la vista in basso di una riga Move up one line Muovi in alto di una riga Extend selection up one line Estendi la selezione in alto di una riga Extend rectangular selection up one line Estendi la selezione rettangolare in alto di una riga Scroll view up one line Scorri la vista in alto di una riga Scroll to start of document Scorri all'inizio del documento Scroll to end of document Scorri alla fine del documento Scroll vertically to centre current line Scorri verticalmente per centrare la riga corrente Move down one paragraph Muovi in basso di un paragrafo Extend selection down one paragraph Estendi la selezione in basso di un paragrafo Move up one paragraph Muovi in alto di un paragrafo Extend selection up one paragraph Estendi la selezione in alto di un paragrafo Move left one character Muovi a sinistra di un carattere Extend selection left one character Estendi la selezione a sinistra di un carattere Extend rectangular selection left one character Estendi la selezione rettangolare a sinistra di un carattere Move right one character Muovi a destra di un carattere Extend selection right one character Estendi la selezione a destra di un carattere Extend rectangular selection right one character Estendi la selezione rettangolare a destra di un carattere Move left one word Muovi a sinistra di una parola Extend selection left one word Estendi la selezione a sinistra di una parola Move right one word Muovi a destra di una parola Extend selection right one word Estendi la selezione a destra di una parola Move to end of previous word Muovi alla fine della parola precedente Extend selection to end of previous word Estendi la selezione alla fine della parola precedente Move to end of next word Muovi alla fine della prossima parola Extend selection to end of next word Estendi la selezione alla fine della prossima parola Move left one word part Muovi a sinistra di una parte di parola Extend selection left one word part Estendi la selezione a sinistra di una parte di parola Move right one word part Muovi a destra di una parte di parola Extend selection right one word part Estendi la selezione a destra di una parte di parola Move to start of document line Muovi all'inizio della riga Extend selection to start of document line Estendi la selezione all'inizio della riga Extend rectangular selection to start of document line Estendi la selezione rettangolare all'inizio della riga Move to start of display line Muovi all'inizio della riga mostrata Extend selection to start of display line Estendi la selezione all'inizio della riga mostrata Move to start of display or document line Muovi all'inizio della riga mostrata o del documento Extend selection to start of display or document line Estendi la selezione all'inizio della riga mostrata o del documento Move to first visible character in document line Muovi al primo carattere visibile nella riga Extend selection to first visible character in document line Estendi la selezione al primo carattere visibile della riga Extend rectangular selection to first visible character in document line Estendi la selezione rettangolare al primo carattere visibile nella riga Move to first visible character of display in document line Muovi al primo carattere visibile nella riga mostrata Extend selection to first visible character in display or document line Estendi la selezione al primo carattere visibile nella riga mostrata Move to end of document line Muovi alla fine della riga Extend selection to end of document line Estendi la selezione alla fine della riga Extend rectangular selection to end of document line Estendi la selezione rettangolare alla fine della riga Move to end of display line Muovi alla fine della riga mostrata Extend selection to end of display line Estendi la selezione alla fine della riga mostrata Move to end of display or document line Muovi alla fine della riga mostrata o del documento Extend selection to end of display or document line Estendi la selezione alla fine della riga mostrata o del documento Move to start of document Muovi all'inizio del documento Extend selection to start of document Estendi la selezione all'inizio del documento Move to end of document Muovi alla fine del documento Extend selection to end of document Estendi la selezione alla fine del documento Move up one page Muovi su di una pagina Extend selection up one page Estendi la selezione in su di una pagina Extend rectangular selection up one page Estendi la selezione rettangolare in su di una pagina Move down one page Muovi in basso di una pagina Extend selection down one page Estendi la selezione in basso di una pagina Extend rectangular selection down one page Estendi la selezione rettangolare in basso di una pagina Stuttered move up one page Muovi in alto a scatti di una pagina Stuttered extend selection up one page Estendi la selezione in alto a scatti di una pagina Stuttered move down one page Muovi in basso a scatti di una pagina Stuttered extend selection down one page Estendi la selezione in basso a scatti di una pagina Delete current character Elimina il carattere corrente Delete previous character Elimina il carattere precedente Delete previous character if not at start of line Elimina il carattere precedente se non corrisponde all'inizio di riga Delete word to left Elimina la parola a sinistra Delete word to right Elimina la parola a destra Delete right to end of next word Elimina da destra alla fine della prossima parola Delete line to left Elimina la riga a sinsitra Delete line to right Elimina la riga a destra Delete current line Elimina la riga corrente Cut current line Taglia la riga corrente Copy current line Copia la riga corrente Transpose current and previous lines Trasponi la riga corrente e quella precedente Duplicate the current line Duplica la riga corrente Select all Seleziona tutto Move selected lines up one line Muovi le righe selezionate in alto di una riga Move selected lines down one line Muovi le righe selezionate in basso di una riga Duplicate selection Duplica la selezione Convert selection to lower case Converti la selezione in minuscolo Convert selection to upper case Converti la selezione in maiuscolo Cut selection Taglia la selezione Copy selection Copia la selezione Paste Incolla Toggle insert/overtype Alterna inserisci/sovrascrivi Insert newline Inserisci una nuova riga Formfeed Separatore di pagina Indent one level Indenta di un livello De-indent one level Rimuovi l'indentazione di un livello Cancel Annulla Undo last command Annulla l'ultimo comando Redo last command Ripristina l'ultimo comando Zoom in Ingrandisci Zoom out Rimpicciolisci QsciLexerCPP Default Default Inactive default Default inattivo C comment Commento C Inactive C comment Commento C inattivo C++ comment Commento C++ Inactive C++ comment Commento C++ inattivo JavaDoc style C comment Commento JavaDoc in stile C Inactive JavaDoc style C comment Commento JavaDoc in stile C inattivo Number Numero Inactive number Numero inattivo Keyword Parola chiave Inactive keyword Parola chiave inattiva Double-quoted string Stringa tra virgolette Inactive double-quoted string Stringa tra virgolette inattiva Single-quoted string Stringa tra singoli apici Inactive single-quoted string Stringa tra singoli apici inattiva IDL UUID IDL UUID Inactive IDL UUID IDL UUID inattivo Pre-processor block Blocco di pre-processore Inactive pre-processor block Blocco di pre-processore inattivo Operator Operatore Inactive operator Operatore inattivo Identifier Identificatore Inactive identifier Identificatore inattivo Unclosed string Stringa non terminata Inactive unclosed string Stringa non terminata inattiva C# verbatim string Stringa verbatim in C# Inactive C# verbatim string Stringa verbatim in C# inattiva JavaScript regular expression Espressione regolare JavaScript Inactive JavaScript regular expression Espressione regolare JavaScript inattiva JavaDoc style C++ comment Commmento JavaDoc in stile C++ Inactive JavaDoc style C++ comment Commento JavaDoc in stile C++ inattivo Secondary keywords and identifiers Parole chiave e identificatori secondari Inactive secondary keywords and identifiers Parole chiave e identificatori secondari inattivi JavaDoc keyword Parola chiave JavaDoc Inactive JavaDoc keyword Parola chiave JavaDoc inattiva JavaDoc keyword error Parola chiave JavaDoc errata Inactive JavaDoc keyword error Parola chiava JavaDoc errata inattiva Global classes and typedefs Classi globali e typedefs Inactive global classes and typedefs Classi globali e typedefs inattive C++ raw string Stringa grezza C++ Inactive C++ raw string Stringa grezza C++ inattiva Vala triple-quoted verbatim string Stringa Vala tri-apicata verbatim Inactive Vala triple-quoted verbatim string Stringa Vala tri-apicata verbatim inattiva Pike hash-quoted string Stringa Pike tra hash Inactive Pike hash-quoted string Stringa Pike tra hash inattiva Pre-processor C comment Commento di pre-processore C Inactive pre-processor C comment Commento di pre-processore C inattivo JavaDoc style pre-processor comment Commento di pre-processore in stile JavaDoc Inactive JavaDoc style pre-processor comment Commento di pre-processore in stile JavaDoc inattivo User-defined literal Letterale definito dall'utente Inactive user-defined literal Letterale definito dall'utente inattivo Task marker Segno di Task Inactive task marker Segno di Task inattivo Escape sequence Sequenza di escape Inactive escape sequence Sequenza di escape inattiva QsciLexerHTML HTML default Default HTML Tag Tag Unknown tag Tag sconosciuto Attribute Attributo Unknown attribute Attributo sconosciuto HTML number Numero HTML HTML double-quoted string Stringa tra virgolette in HTML HTML single-quoted string Stringa tra apici in HTML Other text in a tag Altro test in un tag HTML comment Commento HTML Entity Entità End of a tag Fine di un tag Start of an XML fragment Inizio di un frammento XML End of an XML fragment Fine di un frammento XML Script tag Tag di script Start of an ASP fragment with @ Inizio di un frammento ASP con @ Start of an ASP fragment Inizio di un frammento ASP CDATA CDATA Start of a PHP fragment Inizio di un frammento PHP Unquoted HTML value Valore HTML senza apici ASP X-Code comment Commento di codice ASP X SGML default Default SGML SGML command Comando SGML First parameter of an SGML command Primo parametro di un comando SGML SGML double-quoted string Stringa tra virgolette SGML SGML single-quoted string Stringa tra apici SGML SGML error Errore SGML SGML special entity Entità speciale SGML SGML comment Commento SGML First parameter comment of an SGML command Primo parametro di un comando SGML SGML block default Blocco di default SGML Start of a JavaScript fragment Inizio di un frammento JavaScript JavaScript default Default JavaScript JavaScript comment Commento JavaScript JavaScript line comment Commento di riga JavaScript JavaDoc style JavaScript comment Commento JavaScript in stile JavaDoc JavaScript number Numero JavaScript JavaScript word Parola JavaScript JavaScript keyword Parola chiave JavaScript JavaScript double-quoted string Stringa tra virgolette JavaScript JavaScript single-quoted string Stringa tra apici JavaScript JavaScript symbol Simbolo JavaScript JavaScript unclosed string Stringa non delimitata JavaScript JavaScript regular expression Espressione regolare JavaScript Start of an ASP JavaScript fragment Inizio di un frammento ASP in JavaScript ASP JavaScript default Default ASP JavaScript ASP JavaScript comment Commento ASP JavaScript ASP JavaScript line comment Line di commento ASP JavaScript JavaDoc style ASP JavaScript comment Commento ASP JavaScript in stile JavaDoc ASP JavaScript number Numero ASP JavaScript ASP JavaScript word Parola ASP JavaScript ASP JavaScript keyword Parola chiave ASP JavaScript ASP JavaScript double-quoted string Stringa ASP JavaScript tra virgolette ASP JavaScript single-quoted string Stringa ASP JavaScript tra apici ASP JavaScript symbol Simbolo ASP JavaScript ASP JavaScript unclosed string Stringa non delimitata ASP JavaScript ASP JavaScript regular expression Espressione regolare ASP JavaScript Start of a VBScript fragment Inizio di un frammento VBScript VBScript default Default VBScript VBScript comment Commento VBScript VBScript number Numero VBScript VBScript keyword Parola chiave VBScript VBScript string Stringa VBScript VBScript identifier Identificatore VBScript VBScript unclosed string Stringa non delimitata VBScript Start of an ASP VBScript fragment Inizio di un frammento ASP VBScript ASP VBScript default Default ASP VBScript ASP VBScript comment Commento ASP VBScript ASP VBScript number Numero ASP VBScript ASP VBScript keyword Parola chiave ASP VBScript ASP VBScript string Stringa ASP VBScript ASP VBScript identifier Identificatore ASP VBScript ASP VBScript unclosed string Stringa non delimitata ASP VBScript Start of a Python fragment Inizio di un frammento Python Python default Default Python Python comment Commento Python Python number Numero Python Python double-quoted string Stringa tra virgolette Python Python single-quoted string Stringa tra apici Python Python keyword Parola chiave Python Python triple double-quoted string Stringa tra tripilci virgolette Python Python triple single-quoted string Stringa tra triplici apici Python Python class name Nome di classe Python Python function or method name Funzione o nome di metodo Python Python operator Operatore Python Python identifier Identificatore Python Start of an ASP Python fragment Inizio di un frammento ASP Python ASP Python default Default ASP Python ASP Python comment Commento ASP Python ASP Python number Numero ASP Python ASP Python double-quoted string Stringa tra virgolette ASP Python ASP Python single-quoted string Stringa tra apici ASP Python ASP Python keyword Parola chiave ASP Python ASP Python triple double-quoted string Stringa tra triplici virgolette ASP Python ASP Python triple single-quoted string Stringa tra triplici apici ASP Python ASP Python class name Nome di classe ASP Python ASP Python function or method name Nome di funzione o metodo ASP Python ASP Python operator Operatore ASP Python ASP Python identifier Identificatore ASP Python PHP default Default PHP PHP double-quoted string Stringa tra virgolette PHP PHP single-quoted string Stringa tra apici PHP PHP keyword Parola chiave PHP PHP number Numero PHP PHP variable Variabile PHP PHP comment Commento PHP PHP line comment Commento di linea PHP PHP double-quoted variable Variabile tra virgolette PHP PHP operator Operatore PHP QsciLexerJSON Default Default Number Numero String Stringa Unclosed string Stringa non delimitata Property Proprietà Escape sequence Sequenza di escape Line comment Commento di linea Block comment Commento in blocco Operator Operatore IRI IRI JSON-LD compact IRI JSON-LD IRI compatto JSON keyword Parola chiave JSON JSON-LD keyword Parola chiave JSON-LD Parsing error Errore di analisi QsciLexerJavaScript Regular expression Espressione regolare QsciLexerPython Default Default Comment Commento Number Numero Double-quoted string Stringa tra virgolette Single-quoted string Stringa tra apici Keyword Parola chiave Triple single-quoted string Stringa tra triplici apici Triple double-quoted string Stringa tra triplici virgolette Class name Nome di classe Function or method name Nome di funzione o metodo Operator Operatore Identifier Identificatore Comment block Commento in blocco Unclosed string Stringa non delimitata Highlighted identifier Identificatore evidenziato Decorator Decoratore Double-quoted f-string Stringa-f tra virgolette Single-quoted f-string Stringa-f tra singoli apici Triple single-quoted f-string Stringa-f tra triplici apici Triple double-quoted f-string Stringa-f tra triplici virgolette QsciLexerSQL Default Default Comment Commento Comment line Commento di linea JavaDoc style comment Commento in stile JavaDoc Number Numero Keyword Parola chiave Double-quoted string Stringa tra virgolette Single-quoted string Stringa tra apici SQL*Plus keyword Parola chiave SQL*Plus SQL*Plus prompt Richiesta SQL*Plus Operator Operatore Identifier Identificatore SQL*Plus comment Commento SQL*Plus # comment line # commento di linea JavaDoc keyword Parola chiave JavaDoc JavaDoc keyword error Errore parola chiave JavaDoc User defined 1 Definito dall'utente 1 User defined 2 Definito dall'utente 2 User defined 3 Definito dall'utente 3 User defined 4 Definito dall'utente 4 Quoted identifier Identificatore di citazione Quoted operator Operatore di citazione QsciScintilla &Undo A&nnulla &Redo &Ripristina Cu&t &Taglia &Copy &Copia &Paste &Incolla Delete Elimina Select All Seleziona tutto RemoteCommitsModel Commit ID ID Commit Message Messaggio Date Data Author Autore Size Dimensione Authored and committed by %1 Creato e inviato da %1 Authored by %1, committed by %2 Creato da %1, inviato da %2 RemoteDatabase Error opening local databases list. %1 Errore nell'apertura della lista di database locale. %1 Error creating local databases list. %1 Errore nella creazione della lista di database locale. %1 RemoteDock Remote Remoto Identity Identità Push currently opened database to server Invia il database corrente al server Upload Carica DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>In questo pannello, si possono aggiungere database dal sito web dbhub.io a DB Browser for SQLite. Prima hai bisogno di un'identità:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Collegati al sito web dbhub.io (usa le tue credenziali GitHub o quello che preferisci)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Clicca il pulsante per &quot;Generare certificato client&quot; (è la tua identità). Che ti fornirà un file di certificato (salvalo sul tuo disco locale).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vai alla scheda "Remoto" nelle preferenze di DB Browser for SQLite. Clicca il pulsante per aggiungere un nuovo certificato a DB Browser for SQLite e seleziona il file di certificato appena scaricato.</li></ol><p>Ora il pannello "Remoto" mostra la tua identità e tu puoi aggiungere database remoti.</p></body></html> Local Locale Current Database Database Corrente Clone Clona Branch Ramo Commits Commits Commits for Commits per Delete Database Elimina Database Delete the local clone of this database Elimina la copia locale di questo database Open in Web Browser Apri nel Browser Web Open the web page for the current database in your browser Apre una pagina web per il database corrente nel tuo browser Clone from Link Clona da Collegamento Use this to download a remote database for local editing using a URL as provided on the web page of the database. Usa questo per scaricare un database remoto per modificarlo localmente utilizzando una URL fornita dalla pagina web del database. Refresh Aggiorna Reload all data and update the views Ricarica tutti i dati e aggiornal le viste Clone Database Clona Database Open Database Apri Database Open the local copy of this database Apre una copia locale di questo database Check out Commit Passare a Commit Download and open this specific commit Scarica ed apre questo commit specifico Check out Latest Commit Passare all'ultimo Commit Check out the latest commit of the current branch Passa all'ultimo comit del ramo corrente Save Revision to File Salva revisione su File Saves the selected revision of the database to another file Salva la revisione selezionata del database in un altro file Upload Database Carica Database Paste Incolla Cancel Annulla Upload this database as a new commit Carica questo database come un nuovo commit <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>Stai attulamente utilizzando un profilo interno in sola lettura. Per caricare i tuoi database, devi configurare e usare un account DBHub.io.</p><p>Non hai ancora un account DBHub.io? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Creane uno adesso</span></a> e importa il tuo certificato <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">qui</span></a> per condividere i tuoi databases.</p><p>Per aiuto online clicca <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">qui</span></a>.</p></body></html> &User &Utente &Database &Database Back Indietro Select an identity to connect Seleziona una identità da connettere Public Pubblico This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Questo scarica un database da un server remoto per modifiche locali. Si prega d'inserire l'URL da cui effettuare il clone. Puoi generare l'URL cliccando il pulsante 'Clona Database in DB4S' sulla pagina web del database. Invalid URL: The host name does not match the host name of the current identity. URL Invalida: Il nome host non corrisponde a quello dell'identità corrente. Invalid URL: No branch name specified. URL Invalida: Nessun ramo specificato. Invalid URL: No commit ID specified. URL Invalida: Nessun commit ID specificato. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? Hai modificato la copia locale del database. Caricare questo commit sovrascriverà le modifiche locali. Sei sicuro di voler procedere? The database has unsaved changes. Are you sure you want to push it before saving? Il database ha modifiche non salvate. Sei sicuro di volerlo inviare prima di salvare? The database you are trying to delete is currently opened. Please close it before deleting. Il database che stai provando ad eliminare è attualmente aperto. Si prega di chiuderlo prima di eliminarlo. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? Questo elimina la versione locale di questo database con tutte le modifiche che non hai ancora committato. Sei sicuro di voler eliminare questo database? RemoteLocalFilesModel Name Nome Branch Ramo Last modified Ultima modifica Size Dimensione Commit Commit File File RemoteModel Name Nome Commit Commit Last modified Ultima modifica Size Dimensione Size: Dimensione: Last Modified: Ultima Modifica: Licence: Licenza: Default Branch: Ramo di Default: RemoteNetwork Choose a location to save the file Sceli dove salvare il file Error opening remote file at %1. %2 Errore aprendo il file remoto a %1. %2 Error: Invalid client certificate specified. Errore: specificato certificato invalido per il client. Please enter the passphrase for this client certificate in order to authenticate. Si prega d'inserire la passphrase per questo certificato di client in modo da permetterne l'autenticazione. Cancel Annulla Uploading remote database to %1 Carico il database remoto in %1 Downloading remote database from %1 Scarico il database remoto da %1 Error: Cannot open the file for sending. Errore: Impossibile aprire il file per l'invio. RemotePushDialog Push database Invia database Database na&me to push to No&me del database a cui inviare Commit message Messaggio di commit Database licence Licenza database Public Pubblico Branch Branch Force push Forza invio Username Nome utente Database will be public. Everyone has read access to it. Il database sarà pubblico. Chiunque potrà accedere in lettura. Database will be private. Only you have access to it. Il database sarà privato. Solo tu potrai accedervi. Use with care. This can cause remote commits to be deleted. Usa con cautela. Questo può eliminare dei commit remoti. RunSql Execution aborted by user Esecuzione terminata dall'utente , %1 rows affected , %1 righe modificate query executed successfully. Took %1ms%2 query eseguita con successo. Impiegati %1ms%2 executing query query in esecuzione SelectItemsPopup A&vailable &Disponibile Sele&cted Se&lezionato SqlExecutionArea Form Find previous match [Shift+F3] Trova corrispondenza precedente [Shift+F3] Find previous match with wrapping Trova la corrispondenza precedente con reinizio Shift+F3 The found pattern must be a whole word Il pattern trovato deve essere una parola intera Whole Words Parole intere Text pattern to find considering the checks in this frame Il pattern da cercare considerando le spunte in quest'area Find in editor Trova nell'editor The found pattern must match in letter case Il patter trovato deve corrispondere esattamente (maiuscole/minuscole) incluse Case Sensitive Case Sensitive Find next match [Enter, F3] Trova la prossima corrispondenza [Invio, F3] Find next match with wrapping Trova la prossima corrispondenza con reinizio F3 Interpret search pattern as a regular expression Interpreta il pattern di ricerca come un'espressione regolare <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Quando selezionato, la stringa del testo viene interpretata come una RegExp Unix. Vedi <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Espressioni regolari su Wikibooks (in inglese)</a>.</p></body></html> Regular Expression Espressione regolare Close Find Bar Chiudi la barra di ricerca <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>Risultati degli ultimi statements eseguiti.</p><p>Potresti voler rimpicciolire questo pannello e usare la casella <span style=" font-style:italic;">SQL Log</span> con la selezione dell'<span style=" font-style:italic;">Utente</span>.</p></body></html> Results of the last executed statements Risultato degli 'ultimi statement eseguiti This field shows the results and status codes of the last executed statements. Questo campo mostra i risultati e i codici di stato degli ultimi statements eseguiti. Ctrl+PgUp Ctrl+PgUp Ctrl+PgDown Ctrl+PgDown Couldn't read file "%1": %2. Impossibile leggere file "%1": %2. Couldn't save file: %1. Impossibile salvare il file: %1. Your changes will be lost when reloading it! Le tue modifiche andranno perse quando ricaricherai! The file "%1" was modified by another program. Do you want to reload it?%2 Il file "%1" è stato modificato da un altro programma. Vuoi ricaricarlo?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Rispondere "Si a Tutto" per ricaricare il file ad ogni aggiornamento esterno senza nuove richieste di conferma. Answer "No to All" to ignore any external update without further prompting. Rispondere "No a Tutto" per ignorare ogni aggiornamento esterno senza chiedere nuovamente. Modifying and saving the file will restore prompting. Modificare e salvare il file ripristinerà le richieste. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) La funzione abs(X) ritorna il valore assoluto dell'argomento numerico X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () La funzione changes() ritorna il numero delle righe di database che sono state modificate o inserite o eliminate dallo statement INSERT, DELETE o UPDATE più recente. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1, X2,...) La funzione char(X1,X2,...,XN) ritorna una stringa composta dai caratteri unicode rappresentati dai valori interi da X1 a XN. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) La funzione coalesce(X,Y,...) ritorna una copia del suo primo argomento non NULL oppure NULL se tutti gli argomenti sono NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) La funzione glob(X,Y) è equivalente all'espressione "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) La funzione ifnull(X,Y) ritorno una copia del suo primo argomento non NULL o NULL se entrambi gli argomenti sono NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) La funzione intstr(X,Y) trova la prima occorrenza della stringa Y all'interno della stringa X e ritorna il numero dei caratteri precedenti più 1 o 0 se Y non si trova all'interno di X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) La funzione hex() interpreta i suoi argomenti come un BLOB e ritorna una stringa corrispondente al rendering esadecimale maiuscolo del contenuto di quel blob. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) La funzione iif(X,Y,Z) restituisce il valore di Y se X è vera e Z altrimenti. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () La funzione last_insert_rowid() ritorna il ROWID dell'ultima riga inserita nella connessione database che ha invocato la funzione. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) La funzione lenght(X) ritorna per una stringa X, il numero di caratteri (non bytes) di X prima del primo carattere NUL. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) La funzione like(X,Y) è utilizzata per implementare l'espressione "Y LIKE X". (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) La funzione like(X,Y,Z) è utilizzata per implementare l'espressione "Y LIKE X ESCAPE Z". (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) La funzione load_extension(X) carica l'estensione SQLite da un file di libreria condivisa di nome X. L'utilizzo di questa funzione dev'essere permesso tramite le Preferenze. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) La funzione load_extension(X,Y) carica un'estensione SQLite da un file di libreria condivisa di nome X utilizzando il punto d'ingresso Y. L'utilizzo di questa funzione dev'essere permesso tramite le Preferenze. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) La funzione lower(X) ritorna una copia della stringa X con tutti i caratteri ASCII convertiti in minuscolo. (X) ltrim(X) removes spaces from the left side of X. (X) La funzione ltrim(X) rimuove gli spazi dal lato sinistro di X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) La funzione ltrim(X,Y) ritorna una stringa formata rimuovendo tutti i caratteri che compaiono in Y dal lato sinistro di X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) La funzione multi-argomento max(X,Y,...) ritorna l'argomento con valore massimo o ritorna NULL se tutti gli argomenti sono NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) La funzione multi-argomento min(X,Y,...) ritorna l'argomento con valore minore o NULL se tutti gli argomenti sono NULL. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) La funzione nullif(X,Y) ritorna il primo argomento se gli argomenti sono diversi e NULL se gli argomenti sono uguali. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) La funzione SQL printf(FORMAT,...) si comporta come la funzione del linguaggio C sqlite3_mprintf() e la funzione printf() della libreria standard C. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) La funzione quote(X) ritorna il testo di un literale SQL il cui valore può essere incluso in uno statement SQL. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () La funzione random() ritorna un numero intero pseudo-casuale tra -9223372036854775808 e +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) La funzione randomblob(N) ritorna un blob di N-bytes contenenti dati pseudo-casuali. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) La funzione replace(X,Y,Z) ritorna una striga formata sostituendo la stringa Z in ogni occorrenza della stringa Y nella stringa X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) La funzione round(X) ritorna un valore in virgola mobile X arrotondato a 0 cifre decimali. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) La funzione round(X,Y) ritorna un numero in virgola mobile X arrotondato a Y cifre decimali. (X) rtrim(X) removes spaces from the right side of X. (X) La funzione rtrim(X) rimuove gli spazi dalla destra di X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) La funzione rtrim(X,Y) ritorna una stringa formata rimuovendo tutti i caratteri che compaiono in Y dal lato destro di X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) La funzione soundex(X) ritorna una stringa che rappresenta la codifica soundex della stringa X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) La funzione substr(X,Y) ritorna tutti i caratteri dalla fine della stringa X iniziando dall'Y-esimo. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) La funzione substr(X,Y,Z) ritorna una sotto-stringa di X che inizia dal carattere Y-esimo e lunga Z caratteri. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () La funzione total_changes() ritorna il numero di righe modificate da INSERT, UPDATE o DELETE dall'apertura della connessione al database. (X) trim(X) removes spaces from both ends of X. (X) La funzione trim(X) rimuove gli spazi da entrambi i lati di X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) La funzione trim(X,Y) ritorna una stringa formata rimuovendo tutti i caratteri che compaiono in Y da entrambi i termini di X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) La funzione typeof(X) ritorna una stringa che indica il tipo di dato dell'espressione X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) La funzione unicode(X) ritorna il valore numerico in unicode corrispondente al primo carattere della stringa X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) La funzione upper(X) ritorna una copia della stringa X in cui tutti i caratteri minuscoli ASCII sono stati converiti in maiuscolo. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) La funizione zeroblob(N) ritorna un BLOB di N byte di 0x00. (timestring,modifier,modifier,...) (stringa data,modificatore,modificatore,...) (format,timestring,modifier,modifier,...) (formato,stringa data-ora,modificatore,modificatore,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) La funzione avg(X) ritorna il valore medio di tutti gli X non-NULL in un gruppo. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) La funzione count(X) ritorna il numero di volte che X non è NULL in un gruppo. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) La funzione group_concat(X) ritorna una stringa rappresentante la concatenazione di tutti i valori di X non-NULL. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) La funzione group_concat(X,Y) ritorna una stringa rappresentate la concatenazione di tutti i valori di X non-NULL. Se il parametro Y è presente allora è utilizzato come separatore tra le istanze di X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) La funzione aggregata max(X) ritorna il valore massimo di tutti i valori nel gruppo. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) La funzione aggregata min(X) ritorna il minore non-NULL tra tutti i valori del gruppo. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) Le funzioni aggregate sum(X) e total(X) ritornano la somma di tutti i valori non-NULL nel gruppo. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () Il numero di righe all'interno della partizione corrente. Le righe sono numerate partendo da 1 nell'ordine definito dalla clausula ORDER BY nella finestra definizione, o altrimenti in ordine arbitrario. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Il row_number() del primo peer in ogni gruppo - il rango della riga corrente con intervalli. Se non ci sono clausule ORDER BY, allora tutte le righe sono considerate peer e questa funzione ritorna 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Il numero di peer nel gruppo della riga corrente all'interno della sua partizione - il rango della riga corrente senza intervalli. Le partizioni sono numerate a partire da 1 nell'ordine definito dalla clausula ORDER BY nella finestra definizione. Se non ci sono clausule ORDER BY allora tutte le righe sono considerate peer e questa funzione ritorna 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () A dispetto del nome, questa funzione ritorna sempre un valore tra 0.0 e 1.0 uguale a (rango - 1)/(righe della partizione - 1), dove rango è il valore ritornato dalla funzione interna rank() e le "righe della partizione" sono il numero di righe nella partizione. Se la partizione contiene solo una riga, questa funzione ritorna 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () La distribuzione cumulativa. Calcolata come "numero di righe"/"righe della partizione", dove "numero di righe" è il valore ritornato dalla funzione row_number() per l'utimo peer nel gruppo. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) L'argomento N è gestito come valore intero. Questa funzione divide la partizione in N gruppi il più uniformemente possibile e assegna un'intero tra 1 e N ad ogni gruppo, nell'ordine definito dalla clausula ORDER BY o altrimenti in ordine arbitrario. Se necessario i gruppi più grandi compariranno per primi. Questa funzione ritorna il valore intero assegnato al gruppo di cui fa parte la riga corrente. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Ritorna il risultato della valutazione dell'espressione expr sulla riga precedente della partizione o, se non esiste una riga precedente (perché la riga è la prima), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr, offset) Se l'argomento offset viene fornito, allora dev'essere un intero non negativo. In questo caso il valore ritornato è il risultato della valutazione dell'espressione expr sulla riga "offset" posizioni antecedente nella partizione. Se offset è 0 allora expr viene valutata sulla riga corrente. Se non ci sono offset righe antecedenti viene ritornato NULL. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) Se viene fornito anche default, allora viene ritornato al posto di NULL se la riga identificata da offset non esiste. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Ritorna il risultato della valutazione dell'espressione expr con la riga successiva nella partizione o, se non c'è una riga successiva (perché la riga corrente è l'utlima) NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) Se viene fornito l'argomento offset, dev'essere un intero non negativo. In questo caso il valore ritornato è il risultato della valutazione dell'espressione expr sulla riga "offset" posizioni successiva a quella corrente nella partizione. Se offset è 0, allora expr viene valutata sulla riga corrente. Se non c'è una riga "offset" posizioni successive, NULL viene restituito. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Questa funzione interna calcola la cornice della finestra di ciascuna riga allo stesso modo di una funzione finestra aggregata. Ritorna il valore della valutazione di expr sulla prima riga nella cornice della finestra per ciascuna riga. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Questa funzione interna calcola la cornice della finestra per ciascuna riga allo stesso modo della funzione finestra aggregata. Ritorna il valore dell'espressione expr valutata sull'ultima riga della cornice della finestra per ciascuna riga. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) Questa funzione interna calcola la cornice della finestra per ciascuna riga allo stesso modo della funzione aggregata finestra. Ritorna il valore della valutazione dell'espressione expr sulla riga N della cornice della finestra. Le righe sono numerate dalla cornice della finestra partendo da 1 nell'ordine definito dalla clausula ORDER BY se presente o in modo arbitrario. Se non esiste la riga Nesima nella partizione, viene ritornato NULL. (X) Return the arccosine of X. The result is in radians. (X) Restituisce l'arcoseno di X. Il risultato è in radianti. (X) Return the hyperbolic arccosine of X. (X) Restituisce l'arcoseno iperbolico di X. (X) Return the arcsine of X. The result is in radians. (X) Restituisce l'arcoseno di X. Il risultato è in radianti. (X) Return the hyperbolic arcsine of X. (X) Restituisce l'arcoseno iperbolico di X. (X) Return the arctangent of X. The result is in radians. (X) Restituisce l'arcotangente di X. Il risultato è in radianti. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X,Y) Restituisce l'arcotangente di Y/X. Il risultato è in radianti. Il risultato è posizionato nel quadrante corretto a seconda dei segni di X e Y. (X) Return the hyperbolic arctangent of X. (X) Restituisce l'arcotangente iperbolico di X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Restituisce il primo valore intero rappresentabile maggiore o uguale ad X. Per valori positivi di X, questa funzione arrotonda per eccesso. Per valori negativi di X, arrotonda per difetto. (X) Return the cosine of X. X is in radians. (X) Restituisce il coseno di X. X è in radianti. (X) Return the hyperbolic cosine of X. (X) Restituisce il coseno iperbolico di X. (X) Convert value X from radians into degrees. (X) Converte il valore di X da radianti in gradi. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Calcola e (il numero di Eulero, approssimativamente 2.71828182845905) elevato alla potenza di X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Restituisce il primo valore intero rappresentabile minore o uguale ad X. Per numeri positivi, questa funzione arrotonda per difetto. Per numeri negativi arrotonda per eccesso. (X) Return the natural logarithm of X. (X) Restituisce il logaritmo naturale di X. (B,X) Return the base-B logarithm of X. (B,X) Restituisce il logaritmo in base B di X. (X) Return the base-10 logarithm for X. (X) Restituisce il logaritmo in base 10 di X. (X) Return the logarithm base-2 for the number X. (X) Restituisce il logaritmo in base 2 di X. (X,Y) Return the remainder after dividing X by Y. (X,Y) Restituise il resto della divisione di X per Y. () Return an approximation for Ï€. () Restituisce un'approssimazione di Ï€. (X,Y) Compute X raised to the power Y. (X,Y) Calcola X alla potenza di Y. (X) Convert X from degrees into radians. (X) Converte X da gradi in radianti. (X) Return the sine of X. X is in radians. (X) Restituisce il seno di X. X è in radianti. (X) Return the hyperbolic sine of X. (X) Restituisce il seno iperbolico di X. (X) Return the square root of X. NULL is returned if X is negative. (X) Restituisce la radice quadrata di X. NULL viene restituito se X è negativo. (X) Return the tangent of X. X is in radians. (X) Restituisce la tangente di X. X è in radianti. (X) Return the hyperbolic tangent of X. (X) Restituisce la tangente iperbolica di X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) Restituisce l'intero rappresentabile tra X e 0 (inclusivo) che dista maggiormente da zero. O, in altre parole, restituisce la parte intera di X arrotondando verso zero. SqliteTableModel reading rows leggo le righe loading... caricamento... References %1(%2) Hold %3Shift and click to jump there Riferimenti %1(%2) Tieni premuto %3Shift e clicca per saltare lì Error changing data: %1 Errore nella modifica dei dati: %1 retrieving list of columns recupero la lista delle colonne Fetching data... Recupero dati... Cancel Annulla TableBrowser Browse Data Naviga nei dati &Table: &Tabella: Select a table to browse data Seleziona una tabella per navigare tra i dati Use this list to select a table to be displayed in the database view Usa questa lista per selezionare una tabella da visualizzare nella vista del database This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Questa è la vista della tabella del database. Puoi eseguire le seguenti operazioni: - Inizia a scrivere per modificare i valori. - Doppio-click su qualsiasi valore per modificarne il contenuto nella finestra di editor della cella. - Alt+Del per eliminare il contenuto della cella e portarlo a NULL. - Ctrl+" per duplicare il valore corrente. - Ctrl+' per copiare il valore dalla cella soprastante. - Operazioni di selezione e copia/incolla. Text pattern to find considering the checks in this frame Il pattern da cercare considerando le spunte in quest'area Find in table Trova nella tabella Find previous match [Shift+F3] Trova corrispondenza precedente [Shift+F3] Find previous match with wrapping Trova la corrispondenza precedente con reinizio Shift+F3 Find next match [Enter, F3] Trova la prossima corrispondenza [Invio, F3] Find next match with wrapping Trova la prossima corrispondenza con reinizio F3 The found pattern must match in letter case Il pattern trovato deve corrispondere esattamente (maiuscole/minuscole) incluse Case Sensitive Case Sensitive The found pattern must be a whole word Il pattern trovato deve essere una parola intera Whole Cell Cella completa Interpret search pattern as a regular expression Interpreta il pattern di ricerca come un'espressione regolare <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Quando selezionata, il pattern da trovare viene interpretato come un'espressione regolare UNIX. Vedi: <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Espressione regolare Close Find Bar Chiudi la barra di ricerca Text to replace with Testo da usare per la sostituzione Replace with Sostituisci con Replace next match Sostituisci la prossima corrispondenza Replace Sostituisci Replace all matches Sostituisci tutte le corrispondenze Replace all Sostituisci tutto Export to &JSON Esporta in &JSON Export the filtered data to JSON Esporta i dati filtrati in JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Questo pulsante esporta i dati della tabella visualizzata così come mostrata correntemente (dopo i filtri, formati di visualizzazione e ordine colonne) in un file JSON. Copy column name Copia nome colonna Copy the database table column name to your clipboard COpia il nome della colonna del database negli appunti New Data Browser Nuovo Browser Dati Add a new docked Data Browser Aggiunge un nuovo Browser Dati This button adds a new docked Data Browser, which you can detach and arrange in different layouts. Questo pulasnte agggiunge un nuovo Browser Dati, che puoi scollegare e posizionare a piacimento. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Scorri all'ìinizio</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Cliccare questo pulsante scorre la vista all'inizio della tabella.</p></body></html> |< |< Scroll one page upwards Scorri di una pagina in su <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Cliccando questo pulsante la vista scorre le righe di una pagina verso l'inizio della tabella.</p></body></html> < < 0 - 0 of 0 0 - 0 di 0 Scroll one page downwards Scorri di una pagina in giù <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Cliccando questo pulsante la vista scorre le righe di una pagina verso il fondo della tabella.</p></body></html> > > Scroll to the end Scorri alla fine <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>Cliccando questo pulsante la vista scorre al fondo della tabella.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>Clicca qui per saltare alla riga specificata</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Questo pulsante è utilizzato per navigare alla riga impostata nell'area "Vai a".</p></body></html> Go to: Vai a: Enter record number to browse Inserisci il numero di riga a cui scorrere Type a record number in this area and click the Go to: button to display the record in the database view Inserisci un numero in quest'area e clicca sul pul pulsante "Vai a" per visualizzare la riga selezionata 1 1 Show rowid column Mostra colonna rowid Toggle the visibility of the rowid column Mostra/nasconde la colonna rowid Unlock view editing Sblocca la modifica della vista This unlocks the current view for editing. However, you will need appropriate triggers for editing. Sblocca la vista corrente per modificarla. Per poterla modificare avrai comunque bisogno degli appropriati trigger. Edit display format Modifica formato di visualizzazione Edit the display format of the data in this column Modifica il formato di visualizzazione dei dati in questa colonna New Record Nuova Riga Insert a new record in the current table Inserisci un nuovo valore nella tabella corrente <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Questo pulsante crea una nuova riga nel database. Mantieni premuto il tasto del mouse per ottenere più opzioni:</p><ul><li><span style=" font-weight:600;">Nuova Riga</span>: inserisce una nuova riga con i valori predefiniti.</li><li><span style=" font-weight:600;">Inserisci Valori...</span>: apre una finestra per inserire i valori prima che vengano immessi nel database. Questo permette che l'immissione dei valori rispetti diversi limiti (constraints). Questa finestra si apre anche se l'opzione <span style=" font-weight:600;">Nuova Riga</span> fallisce a causa di questi limiti (constraints).</li></ul></body></html> Delete Record Elimina Riga Delete the current record Elimina il valore corrente This button deletes the record or records currently selected in the table Questo pulsante elimina la/e righe selezionate nella tabella Insert new record using default values in browsed table Inserisce un nuovo record utilizzando i valori di default della tabella Insert Values... Inserisci Valori... Open a dialog for inserting values in a new record Apre una finestra per l'inermento di valori all'interno di un nuovo record Export to &CSV Esporta in &CSV Export the filtered data to CSV Esporta i dati filtrati in CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Questo pulsante esporta i dati della tabella così come visualizzati (applicando filtri, formati e ordine delle colonne) in un file CSV. Save as &view Salva come &vista Save the current filter, sort column and display formats as a view Salva il filtro corrente, ordine colonne e formati dati come vista This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Questo pulsante salva le impostazioni della tabella visualizzata (filtri, formati e ordine colonne) in una vista SQL che puoi successivamente navigare o utilizzare in statement SQL. Save Table As... Salva Tabella Come... Save the table as currently displayed Salva la tabella così come visualizzata <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>Questo menù fornisce le seguenti opzioni applicabili alla tabella filtrata e visualizzata correntemente:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Esporta in CSV: questa opzione esporta i dati della tabella così come visualizzati (con filtri, riordine delle colonne e formati) in un file CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Salva come vista: questa opzione salva le impostazioni correnti della tabella visualizzata (filtri, riordine delle colonne e formati) come vista SQL che puoi successivamente visualizzare o utilizzare come statement.</li></ul></body></html> Hide column(s) Nascondi colonna(e) Hide selected column(s) Nasconde la(e) colonna(e) selezionata(e) Show all columns Mostra tutte le colonne Show all columns that were hidden Mostra tutte le colonne nascoste Set encoding Imposta codifica Change the encoding of the text in the table cells Modifica la codifica del testo nelle celle della tabella Set encoding for all tables Imposta la codifica per tutte le tabelle Change the default encoding assumed for all tables in the database Modifica il valore predefinito di codifica per tutte le tabelle del database Clear Filters Pulisci Filtri Clear all filters Cancella tutti i filtri This button clears all the filters set in the header input fields for the currently browsed table. Questo pulsante pulisce tutti i filtri impostati nella riga d'intestazione per la tabella corrente. Clear Sorting Ripristina Ordinamento Reset the order of rows to the default Ripristina l'ordine delle righe predefinito This button clears the sorting columns specified for the currently browsed table and returns to the default order. Questo pulsante ripristina l'ordinamento delle colonne predefinito per la tabella corrente. Print Stampa Print currently browsed table data Stampa i dati della tabella attualmente in esplorazione Print currently browsed table data. Print selection if more than one cell is selected. Stampa i dati visualizzati. Stampa la selezione se più di una cella è selezionata. Ctrl+P Refresh Aggiorna Refresh the data in the selected table Aggiorna i dati della tabella selezionata This button refreshes the data in the currently selected table. Questo pulsante aggiorna i dati della tabella selezionata. F5 Find in cells Trova nelle celle Open the find tool bar which allows you to search for values in the table view below. Apre la barra di ricerca che ti permette di cercare valori nella tabella visualizzata qui sotto. Freeze columns Blocca colonne Make all columns from the first column up to this column not move when scrolling horizontally Blocca tutte le colonne dalla prima a quella attuale nello scorrimento orizzontale Bold Grassetto Ctrl+B Italic Corsivo Underline Sottolinea Ctrl+U Align Right Allinea a Destra Align Left Allinea a Sinistra Center Horizontally Centra Orizzontalmente Justify Giustifica Edit Conditional Formats... Modifica Formattazione Condizionale... Edit conditional formats for the current column Modifica formattazione condizionale per la colonna corrente Clear Format Ripristina formattazione Clear All Formats Ripristina Tutte le Formattazioni Clear all cell formatting from selected cells and all conditional formats from selected columns Ripristina la formattazione di tutte le celle selezionate e tutte le formattazioni condizionali delle colonne selezionate Font Color Colore Testo Background Color Colore Sfondo Toggle Format Toolbar Mostra/Nascondi barra dei formati Show/hide format toolbar Mostra/nascondi barra dei formati This button shows or hides the formatting toolbar of the Data Browser Questo pulsante mostra o nasconde la barra dei formati per il Browser dei dati Select column Seleziona colonna Ctrl+Space Replace text in cells Sostituisci testo nelle celle Filter in any column Filtra in ogni colonna Ctrl+R %n row(s) %n riga %n righe , %n column(s) , %n colonna , %n colonne . Sum: %1; Average: %2; Min: %3; Max: %4 . Somma: %1; Media: %2; Min: %3; Max: %4 Conditional formats for "%1" Formattazione condizionale per '%1' determining row count... determino il numero di righe... %L1 - %L2 of >= %L3 %L1 - %L2 di >= %L3 %L1 - %L2 of %L3 %L1 - %L2 di %L3 (clipped at %L1 rows) (troncato a %L1 righe) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Si prega d'inserire una pseudo-chiave primaria in modo da abilitare le modifiche su questa vista. Deve corrispondere al nome di una colonna univoca nella vista. Delete Records Elimina i Records Duplicate records Duplica i records Duplicate record Duplica il record Ctrl+" Adjust rows to contents Adatta le righe al contenuto Error deleting record: %1 Errore eliminando le righe: %1 Please select a record first Si prega di selezionare prima un record Please choose a new encoding for all tables. Si prega di scegliere una nuova codifica per tutte le tabelle. Please choose a new encoding for this table. Si prega di scegliere una nuova codifica per questa tabella. %1 Leave the field empty for using the database encoding. %1 Lasciare il campo vuoto per utilizzare la codifica del database. This encoding is either not valid or not supported. Questa codifica non è valida o non è supportata. %1 replacement(s) made. %1 sostituzione(i) effettuata(e). TableBrowserDock New Data Browser Nuovo Browser Dati Rename Data Browser Rinomina Browser Dati Close Data Browser Chiudi Browser Dati Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. Imposta un nuovo nome per il browser dati. Usa il carattere '&&' per utilizzare il carattere successivo come scorciatoia da tastiera. UndoStack Inserting %1 bytes Inserisco %1 bytes Delete %1 chars Elimino %1 caratteri Overwrite %1 chars Sovrascrivo %1 caratteri VacuumDialog Compact Database Compatta Database Warning: Compacting the database will commit all of your changes. Attenzione: Compattare il database salverà tutte le tue modifiche. Please select the databases to co&mpact: Si prega di selezionare il database da co&mpattare: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_ja.ts000066400000000000000000014240651463772530400252030ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite DB Browser for SQLite ã«ã¤ã„㦠Version ãƒãƒ¼ã‚¸ãƒ§ãƒ³ <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> <html><head/><body><p>DB Browser for SQLite ã¯ã€SQLite データベースファイルを作æˆã€è¨­è¨ˆã€ç·¨é›†ã™ã‚‹ãŸã‚ã®ã€ã‚ªãƒ¼ãƒ—ンソースã§ãƒ•リーウェアãªãƒ´ã‚£ã‚¸ãƒ¥ã‚¢ãƒ«ãƒ„ールã§ã™ã€‚</p><p>ã“れã¯ã€Mozilla Public License Version 2 ã¨ã€GNU General Public License Version 3 ã‹ãれ以é™ã®ã™ã¹ã¦ãƒãƒ¼ã‚¸ãƒ§ãƒ³ ã®ä¸¡æ–¹ã§ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã•れã¦ã„ã¾ã™ã€‚ã‚ãªãŸã¯ã“れらã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã®æ¡ä»¶ã®ä¸‹ã§å¤‰æ›´ã‚„å†é…布ãŒã§ãã¾ã™ã€‚</p><p>詳細ã¯<a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> 㨠<a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> ã‚’ã”覧ãã ã•ã„。</p><p>ã“ã®ãƒ—ãƒ­ã‚°ãƒ©ãƒ ã®æ›´ãªã‚‹æƒ…報を得るã«ã¯ã€ç§ãŸã¡ã®ã‚¦ã‚§ãƒ–サイトを訪れã¦ãã ã•ã„:<a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">ã“ã®ã‚½ãƒ•トウェア㯠GPL/LGPL Qt Toolkit を使用ã—ã¦ã„ã¾ã™ã€‚</span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>ライセンスæ¡é …や情報㯠</span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> ã‚’ã”覧ãã ã•ã„。</span></p><p><span style=" font-size:8pt;">ã“ã®ã‚½ãƒ•トウェアã¯SQLite拡張サãƒãƒ¼ãƒˆã®ãŸã‚ã€nalgeon/sqlean library を使用ã—ã¦ã„ã¾ã™ã€‚<br/>ã“ã®ãƒ©ã‚¤ãƒ–ラリã¯MITライセンスã§ã™ã€‚æ›´ãªã‚‹æƒ…å ±ã¯ä»¥ä¸‹ã‚’ã”覧ãã ã•ã„:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">ã¾ãŸã€Michael Buckley ã® Pastel SVG icon set ã‚’ Creative Commons Attribution Share Alike 4.0 license ã®å…ƒã«ä½¿ç”¨ã—ã¦ã„ã¾ã™ã€‚<br/>詳細㯠</span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> ã‚’ã”覧ãã ã•ã„。</span></p></body></html> AddRecordDialog Add New Record æ–°ã—ã„レコードを追加 Enter values for the new record considering constraints. Fields in bold are mandatory. 制約を考慮ã—ã¦æ–°ã—ã„レコードã«å€¤ã‚’入力ã—ã¾ã™ã€‚太字ã®ãƒ•ィールドã¯å¿…é ˆã§ã™ã€‚ In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. 「値ã€åˆ—ã§ã¯ã€ã€Œåå‰ã€åˆ—ã§è­˜åˆ¥ã•れãŸãƒ•ィールドã®å€¤ã‚’指定ã§ãã¾ã™ã€‚「データ型ã€åˆ—ã¯ãƒ•ィールドã®ãƒ‡ãƒ¼ã‚¿åž‹ã‚’示ã—ã¾ã™ã€‚ デフォルト値ã¯NULL値ã¨åŒã˜ã‚¹ã‚¿ã‚¤ãƒ«ã§è¡¨ç¤ºã•れã¾ã™ã€‚ Name åå‰ Type データ型 Value 値 Values to insert. Pre-filled default values are inserted automatically unless they are changed. 挿入ã™ã‚‹å€¤ã€‚変更ã•れãªã„é™ã‚Šã€äº‹å‰å…¥åŠ›ã•れãŸãƒ‡ãƒ•ォルト値ãŒè‡ªå‹•çš„ã«æŒ¿å…¥ã•れã¾ã™ã€‚ When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. 上ã®ãƒ•レームã§å€¤ã‚’編集ã™ã‚‹ã¨ã€ã“ã®æ–°ã—ã„レコードを挿入ã™ã‚‹ SQL クエリーãŒã“ã“ã«è¡¨ç¤ºã•れã¾ã™ã€‚ä¿å­˜ã™ã‚‹å‰ã«ã“ã®ã‚¯ã‚¨ãƒªãƒ¼ã‚’手動ã§ç·¨é›†ã§ãã¾ã™ã€‚ <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">ä¿å­˜</span>ã¯è¡¨ç¤ºã•れã¦ã„ã‚‹æ–°ã—ã„レコードを挿入ã™ã‚‹SQL文をデータベースã«é©ç”¨ã—ã¾ã™ã€‚</p><p><span style=" font-weight:600;">ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã«æˆ»ã™</span>ã¯<span style=" font-weight:600;">「値ã€</span>åˆ—ã‚’åˆæœŸå€¤ã«æˆ»ã—ã¾ã™ã€‚</p><p><span style=" font-weight:600;">キャンセル</span>ã¯ã‚¯ã‚¨ãƒªãƒ¼ã‚’実行ã›ãšã«ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‰ã˜ã¾ã™ã€‚</p></body></html> Auto-increment 自動増加 Unique constraint ä¸€æ„æ€§åˆ¶ç´„ Check constraint: %1 ãƒã‚§ãƒƒã‚¯åˆ¶ç´„: %1 Foreign key: %1 外部キー: %1 Default value: %1 デフォルト値: %1 Error adding record. Message from database engine: %1 レコード追加ã§ã‚¨ãƒ©ãƒ¼ã€‚データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸: %1 Are you sure you want to restore all the entered values to their defaults? 入力ã—ãŸå€¤ã‚’ã™ã¹ã¦ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã«æˆ»ã—ã¾ã™ã‹? Application Possible command line arguments: 使用å¯èƒ½ãªã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°: The user settings file location is replaced with the argument value instead of the environment variable value. ユーザー設定ファイルã®å ´æ‰€ã¯ç’°å¢ƒå¤‰æ•°ã®å€¤ã«ä»£ã‚ã£ã¦ã“ã®å¼•æ•°ã«ç½®ãæ›ãˆã‚‰ã‚Œã¾ã™ã€‚ Ignored environment variable (DB4S_SETTINGS_FILE) value: 環境変数(DB4S_SETTINGS_FILE)ã®å€¤ã¯ç„¡è¦–ã•れã¾ã™ : The file %1 does not exist ファイル %1 ãŒå­˜åœ¨ã—ã¾ã›ã‚“ Usage ä½¿ã„æ–¹ options オプション database データベース project プロジェクト csv-file csvファイル Show command line options コマンドラインã®ã‚ªãƒ—ションを表示ã™ã‚‹ Exit application after running scripts スクリプト実行後ã«ã‚¢ãƒ—リケーションを終了ã™ã‚‹ file ファイル Execute this SQL file after opening the DB DBã‚’é–‹ã„ãŸå¾Œã«ã“ã®SQLを実行ã™ã‚‹ Import this CSV file into the passed DB or into a new DB ã“ã®CSVファイルを渡ã•れãŸDBã‹æ–°ã—ã„DBã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ table テーブル Browse this table, or use it as target of a data import ã“ã®ãƒ†ãƒ¼ãƒ–ルを閲覧ã€ã‚‚ã—ãã¯ã‚¤ãƒ³ãƒãƒ¼ãƒˆã®å¯¾è±¡ã¨ã—ã¦ä½¿ç”¨ã™ã‚‹ Open database in read-only mode データベースを読ã¿å–り専用モードã§é–‹ã settings_file 設定ファイル Run application based on this settings file ã“ã®è¨­å®šãƒ•ァイルを基ã«ã‚¢ãƒ—リケーションを実行ã™ã‚‹ group グループ settings 設定 value 値 Run application with this setting temporarily set to value 一時的ã«ã“ã®å€¤ã‚’設定ã—ã¦ã‚¢ãƒ—リケーションを実行ã™ã‚‹ Run application saving this value for this setting ã“ã®å€¤ã®è¨­å®šã‚’ä¿å­˜ã—ã¦ã‚¢ãƒ—リケーションを実行ã™ã‚‹ Display the current version ç¾åœ¨ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’表示ã™ã‚‹ Open this SQLite database ã“ã® SQLite データベースを開ã Open this project file (*.sqbpro) ã“ã®ãƒ—ロジェクトファイル(*.sqbpro)ã‚’é–‹ã Import this CSV file into an in-memory database ã“ã®CSVファイルをインメモリーデータベースã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ The %1 option requires an argument %1 オプションã«ã¯å¼•æ•°ãŒå¿…è¦ã§ã™ The -S/--settings option requires an argument. The option is ignored. -S/--settings オプションã¯å¼•æ•°ãŒå¿…è¦ã§ã™ã€‚ã“ã®ã‚ªãƒ—ションã¯ç„¡è¦–ã•れã¾ã™ã€‚ The -o/--option and -O/--save-option options require an argument in the form group/setting=value -o/--option 㨠-O/--save-optionオプション㯠グループ/設定=値 ã®å½¢å¼ã§å¼•æ•°ãŒå¿…è¦ã§ã™ SQLite Version SQLite ãƒãƒ¼ã‚¸ãƒ§ãƒ³ SQLCipher Version %1 (based on SQLite %2) SQLCipher ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %1 (SQLite %2 ãŒãƒ™ãƒ¼ã‚¹) DB Browser for SQLite Version %1. DB Browser for SQLite ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %1. Last commit hash when built: %1 ビルド時最新コミットã®ãƒãƒƒã‚·ãƒ¥: %1 Built for %1, running on %2 %1 å‘ã‘ビルド, %2 ã§å‹•作中 Qt Version %1 Qt ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %1 Invalid option/non-existent file: %1 䏿­£ãªã‚ªãƒ—ション/存在ã—ãªã„ファイルã§ã™: %1 CipherDialog SQLCipher encryption SQLCipher æš—å·åŒ– &Password パスワード(&P) &Reenter password パスワードã®å†å…¥åŠ›(&R) Passphrase パスフレーズ Raw key 生ã®ã‚­ãƒ¼ Encr&yption settings æš—å·åŒ–設定(&Y) SQLCipher &3 defaults SQLCipher 3 デフォルト(&3) SQLCipher &4 defaults SQLCipher 4 デフォルト(&4) Custo&m カスタム(&M) Page si&ze ページサイズ(&Z) &KDF iterations KDFå復回数(&K) HMAC algorithm HMACアルゴリズム KDF algorithm KDFアルゴリズム Plaintext Header Size プレーンテキストヘッダーサイズ Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. データベースを暗å·åŒ–ã™ã‚‹ã‚­ãƒ¼ã‚’設定ã—ã¦ãã ã•ã„。 ãã®ã»ã‹ã®ä»»æ„ã®è¨­å®šã‚’変更ã™ã‚‹ã¨ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを開ãã¨ãã¯æ¯Žå›žå†å…¥åŠ›ãŒå¿…è¦ã«ãªã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。 æš—å·åŒ–を無効ã«ã™ã‚‹ã«ã¯ãƒ‘スワード欄を空白ã«ã—ã¾ã™ã€‚ æš—å·åŒ–工程ã«ã¯å°‘ã—æ™‚é–“ãŒã‹ã‹ã‚‹ã§ã—ょã†ã€‚データベースã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を作æˆã™ã‚‹ã¹ãã§ã™! ä¿å­˜ã—ã¦ã„ãªã„å¤‰æ›´ã¯æš—å·åŒ–ã®å‰ã«å映ã•れã¾ã™ã€‚ Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æš—å·åŒ–ã«ä½¿ç”¨ã™ã‚‹ã‚­ãƒ¼ã‚’入力ã—ã¦ãã ã•ã„。 ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルã®ä»–ã®è¨­å®šãŒå¤‰æ›´ã•れãŸå ´åˆã¯ã€ã“ã®æƒ…報も指定ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ ColumnDisplayFormatDialog Choose display format 表示書å¼ã‚’é¸æŠž Display format è¡¨ç¤ºæ›¸å¼ Choose a display format for the column '%1' which is applied to each value prior to showing it. カラム '%1' ã®è¡¨ç¤ºå½¢å¼ã‚’é¸æŠžã—ã¦ãã ã•ã„。ã“れã¯è¡¨ç¤ºå‰ã«å„値ã«é©ç”¨ã•れã¾ã™ã€‚ Default デフォルト Decimal number å進数 Exponent notation 指数表記 Hex blob å六進Blob Hex number å六進数 Octal number 八進数 Round number 概数 Apple NSDate to date Apple NSDate を日付㫠Java epoch (milliseconds) to date Java エãƒãƒƒã‚¯ (ミリ秒) を日付㫠.NET DateTime.Ticks to date .NET DateTime.Ticks を日付㫠Julian day to date ユリウス日を日付㫠Unix epoch to date Unix エãƒãƒƒã‚¯ã‚’日付㫠Unix epoch to local time Unix エãƒãƒƒã‚¯ã‚’地方時㫠WebKit / Chromium epoch to date WebKit / Chromium エãƒãƒƒã‚¯ã‚’日付㫠WebKit / Chromium epoch to local time WebKit / Chromium エãƒãƒƒã‚¯ã‚’地方時㫠Windows DATE to date Windows DATE を日付㫠Date as dd/mm/yyyy 日付(dd/mm/yyyy) Lower case å°æ–‡å­— Upper case 大文字 Binary GUID to text ãƒã‚¤ãƒŠãƒªGUIDをテキスト㫠SpatiaLite Geometry to SVG SpatiaLiteジオメトリーをSVGã« Custom カスタム Custom display format must contain a function call applied to %1 カスタム表示形å¼ã«ã¯ã€%1 ã«é©ç”¨ã•れる関数呼ã³å‡ºã—ãŒå«ã¾ã‚Œã¦ã„ã‚‹å¿…è¦ãŒã‚りã¾ã™ Error in custom display format. Message from database engine: %1 カスタム表示形å¼ã§ã‚¨ãƒ©ãƒ¼ã€‚データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸: %1 Custom display format must return only one column but it returned %1. カスタム表示形å¼ã¯ãŸã 1ã¤ã®ã‚«ãƒ©ãƒ ã‚’è¿”ã™å¿…è¦ãŒã‚りã¾ã™ãŒã€%1 ãŒè¿”ã£ã¦ãã¾ã—ãŸã€‚ CondFormatManager Conditional Format Manager æ¡ä»¶ä»˜ã書å¼ç®¡ç† This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§æ¡ä»¶ä»˜ã書å¼ã®ä½œæˆã¨ç·¨é›†ãŒã§ãã¾ã™ã€‚ãれãžã‚Œã®ã‚»ãƒ«ã‚¹ã‚¿ã‚¤ãƒ«ã¯ã‚»ãƒ«ã®ãƒ‡ãƒ¼ã‚¿ãŒæœ€åˆã«ä¸€è‡´ã—ãŸæ¡ä»¶ã®ã‚‚ã®ãŒé¸æŠžã•れã¾ã™ã€‚æ¡ä»¶ä»˜ã書å¼ã¯ä¸Šä¸‹ã«ç§»å‹•ã§ãã€ä¸Šã®è¡Œã¯ä¸‹ã®è¡Œã«å„ªå…ˆã—ã¾ã™ã€‚æ¡ä»¶ã®æ§‹æ–‡ã¯ãƒ•ィルターã¨åŒã˜ã§ã€ç©ºç™½ã®æ¡ä»¶ã¯å…¨ã¦ã®å€¤ã«é©ç”¨ã•れã¾ã™ã€‚ Add new conditional format æ–°ã—ã„æ¡ä»¶ä»˜ã書å¼ã‚’追加ã—ã¾ã™ &Add 追加(&A) Remove selected conditional format é¸æŠžã—ãŸæ¡ä»¶ä»˜ã書å¼ã‚’削除ã—ã¾ã™ &Remove 削除(&R) Move selected conditional format up é¸æŠžã—ãŸæ¡ä»¶ä»˜ã書å¼ã‚’上ã¸ç§»å‹•ã—ã¾ã™ Move &up 上ã¸(&U) Move selected conditional format down é¸æŠžã—ãŸæ¡ä»¶ä»˜ã書å¼ã‚’下ã¸ç§»å‹•ã—ã¾ã™ Move &down 下ã¸(&D) Foreground 剿™¯ Text color 文字色 Background 背景 Background color 背景色 Font フォント Size サイズ Bold 太字 Italic イタリック Underline 下線 Alignment é…ç½® Condition æ¡ä»¶ Click to select color クリックã§è‰²ã‚’é¸æŠž Are you sure you want to clear all the conditional formats of this field? 本当ã«ã“ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã®æ¡ä»¶ä»˜ã書å¼ã‚’ã™ã¹ã¦å‰Šé™¤ã—ã¾ã™ã‹? DBBrowserDB Please specify the database name under which you want to access the attached database 接続ã—ãŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹æ™‚ã«ä½¿ç”¨ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹åを指定ã—ã¦ãã ã•ã„ Invalid file format 䏿­£ãªãƒ•ァイルフォーマット Do you really want to close this temporary database? All data will be lost. 本当ã«ã“ã®ä¸€æ™‚データベースを閉ã˜ã¾ã™ã‹? ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã¯å–ªå¤±ã—ã¾ã™ã€‚ Do you want to save the changes made to the database file %1? データベースファイル '%1' ã¸ã®å¤‰æ›´ã‚’ä¿å­˜ã—ã¾ã™ã‹? Database didn't close correctly, probably still busy ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãŒæ­£å¸¸ã«é–‰ã˜ã‚‰ã‚Œã¾ã›ã‚“ã§ã—ãŸã€‚多分ã¾ã ãƒ“ジー状態ã§ã™ Cannot open destination file: '%1' 目的ã®ãƒ•ァイル: '%1' ã‚’é–‹ã‘ã¾ã›ã‚“ Cannot backup to file: '%1'. Message: %2 ファイル: '%1' ã‚’ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã§ãã¾ã›ã‚“。メッセージ: %2 The database is currently busy: データベースã¯ç¾åœ¨ãƒ“ジー状態ã§ã™: Do you want to abort that other operation? ä»–ã®æ“作を中断ã—ã¾ã™ã‹? Exporting database to SQL file... データベースをSQLファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ... Cancel キャンセル No database file opened データベースファイルを開ã„ã¦ã„ã¾ã›ã‚“ Executing SQL... SQLを実行... Action cancelled. æ“作をキャンセルã—ã¾ã—ãŸã€‚ Error in statement #%1: %2. Aborting execution%3. ã“ã®æ–‡ã§ã‚¨ãƒ©ãƒ¼ #%1: %2。 実行を中断%3。 and rolling back ロールãƒãƒƒã‚¯ã—ã¾ã—㟠didn't receive any output from %1 %1 ã‹ã‚‰å‡ºåŠ›ã‚’å¾—ã‚‰ã‚Œã¾ã›ã‚“ã§ã—㟠could not execute command: %1 コマンド: %1 を実行ã§ãã¾ã›ã‚“ã§ã—㟠Cannot delete this object ã“ã®ã‚ªãƒ–ジェクトã¯å‰Šé™¤ã§ãã¾ã›ã‚“ Cannot set data on this object ã“ã®ã‚ªãƒ–ジェクトã«ãƒ‡ãƒ¼ã‚¿è¨­å®šã¯ã§ãã¾ã›ã‚“ A table with the name '%1' already exists in schema '%2'. åå‰ãŒ '%1' ã®ãƒ†ãƒ¼ãƒ–ルã¯ã‚¹ã‚­ãƒ¼ãƒž '%2' ã«æ—¢ã«å­˜åœ¨ã—ã¾ã™ã€‚ No table with name '%1' exists in schema '%2'. スキーマ '%2' ã«åå‰ãŒ '%1' ã®ãƒ†ãƒ¼ãƒ–ルãŒã‚りã¾ã›ã‚“。 Cannot find column %1. カラム %1 ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。 Creating savepoint failed. DB says: %1 セーブãƒã‚¤ãƒ³ãƒˆã®ä½œæˆã«å¤±æ•—。DBã®å応: %1 Renaming the column failed. DB says: %1 カラムå変更ã«å¤±æ•—。DBã®å応: %1 Releasing savepoint failed. DB says: %1 セーブãƒã‚¤ãƒ³ãƒˆã®è§£æ”¾ã«å¤±æ•—。DBã®å応: %1 Creating new table failed. DB says: %1 æ–°ã—ã„テーブルã®ä½œæˆã«å¤±æ•—。DBã®å応: %1 Copying data to new table failed. DB says: %1 æ–°ã—ã„テーブルã¸ã®ãƒ‡ãƒ¼ã‚¿ã®ã‚³ãƒ”ーã«å¤±æ•—。DBã®å応: %1 Deleting old table failed. DB says: %1 å¤ã„テーブルã®å‰Šé™¤ã«å¤±æ•—。DBã®å応: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 テーブルåã® '%1' ã‹ã‚‰ '%2' ã¸ã®å¤‰æ›´ã§ã‚¨ãƒ©ãƒ¼ã€‚ データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸: %3 could not get list of db objects: %1 DBオブジェクトã®ä¸€è¦§ã‚’å–å¾—ã§ãã¾ã›ã‚“: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: ã“ã®ãƒ†ãƒ¼ãƒ–ルã«é–¢é€£ã™ã‚‹ã‚ªãƒ–ジェクトã®å¾©å…ƒã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã“れã¯ãŠãらã一部ã®ã‚«ãƒ©ãƒ åãŒå¤‰æ›´ã•れãŸãŸã‚ã§ã™ã€‚ã“ã®SQL文を手動ã§ä¿®æ­£ã—実行ã—ã¦ãã ã•ã„。 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: could not get list of databases: %1 データベースã®ä¸€è¦§ã‚’å–å¾—ã§ãã¾ã›ã‚“: %1 Error setting pragma %1 to %2: %3 プラグマ %1 ã‚’ %2 ã«è¨­å®šæ™‚ã«ã‚¨ãƒ©ãƒ¼: %3 File not found. ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。 Error loading extension: %1 æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã§ã‚¨ãƒ©ãƒ¼: %1 Error loading built-in extension: %1 ビルトイン拡張ã®èª­ã¿è¾¼ã¿ã§ã‚¨ãƒ©ãƒ¼: %1 could not get column information カラム情報ãŒå–å¾—ã§ãã¾ã›ã‚“ã§ã—㟠DbStructureModel Name åå‰ Object オブジェクト Type データ型 Schema スキーマ Database データベース Browsables 表示å¯èƒ½ All ã™ã¹ã¦ Temporary 一時 Tables (%1) テーブル (%1) Indices (%1) インデックス (%1) Views (%1) ビュー (%1) Triggers (%1) トリガー (%1) EditDialog Edit database cell データベースã®ã‚»ãƒ«ã‚’編集 Mode: モード: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. ã“れã¯ã‚µãƒãƒ¼ãƒˆã—ã¦ã„るセル編集モードã®ä¸€è¦§ã§ã™ã€‚ç¾åœ¨ã®ã‚»ãƒ«ãƒ‡ãƒ¼ã‚¿ã®è¡¨ç¤ºä¿®æ­£ã«ä½¿ç”¨ã™ã‚‹ãƒ¢ãƒ¼ãƒ‰ã‚’é¸ã‚“ã§ãã ã•ã„。 Text テキスト RTL Text RTL テキスト Binary ãƒã‚¤ãƒŠãƒªãƒ¼ Image ç”»åƒ JSON JSON XML XML Evaluation 評価 Automatically adjust the editor mode to the loaded data type 編集モードを読ã¿è¾¼ã‚“ã ãƒ‡ãƒ¼ã‚¿åž‹ã«è‡ªå‹•çš„ã«èª¿æ•´ This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. ã“ã®ãƒã‚§ãƒƒã‚¯ãƒœã‚¿ãƒ³ã¯ç·¨é›†ãƒ¢ãƒ¼ãƒ‰ã®è‡ªå‹•切り替ãˆã‚’有効/無効ã«ã—ã¾ã™ã€‚æ–°ã—ã„セルãŒé¸æŠžã•ã‚Œã‚‹ã‹æ–°ã—ã„データãŒã‚¤ãƒ³ãƒãƒ¼ãƒˆã•ã‚ŒãŸæ™‚ã«è‡ªå‹•切り替ãˆãŒæœ‰åйã ã¨ã€æ¤œå‡ºã—ãŸãƒ‡ãƒ¼ã‚¿åž‹ã«ãƒ¢ãƒ¼ãƒ‰ã‚’調整ã—ã¾ã™ã€‚ãã®å¾Œã€ç·¨é›†ãƒ¢ãƒ¼ãƒ‰ã¯æ‰‹å‹•ã§å¤‰æ›´ã§ãã¾ã™ã€‚セル間ã®ç§»å‹•æ™‚ã«æ‰‹å‹•ã§å¤‰æ›´ã—ãŸãƒ¢ãƒ¼ãƒ‰ã‚’ç¶­æŒã—ãŸã„ãªã‚‰ã°ã€ã“ã®ãƒœã‚¿ãƒ³ã‚’オフã«ã—ã¾ã™ã€‚ Auto-switch 自動切替 This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. ã“ã®Qtエディターã¯å³æ›¸ãã®æ–‡ç« ã«ä½¿ã‚れã¾ã™ã€‚ã“れã¯ãƒ‡ãƒ•ォルトã®ãƒ†ã‚­ã‚¹ãƒˆã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã§ã¯ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“ã€‚å³æ›¸ãã®æ–‡å­—ã®å­˜åœ¨ãŒæ¤œçŸ¥ã•れるã¨ã€ã“ã®ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ãƒ¢ãƒ¼ãƒ‰ãŒè‡ªå‹•çš„ã«é¸æŠžã•れã¾ã™ã€‚ Identification of the cell currently in the editor エディター内ã®ç¾åœ¨ã®ã‚»ãƒ«ã®è­˜åˆ¥å€¤ Type and size of data currently in table ç¾åœ¨ãƒ†ãƒ¼ãƒ–ルã«ã‚るデータ型ã¨ã‚µã‚¤ã‚º Apply data to cell セルã«ãƒ‡ãƒ¼ã‚¿ã‚’é©ç”¨ Open preview dialog for printing the data currently stored in the cell ç¾åœ¨ã‚»ãƒ«ã«ã‚るデータをå°åˆ·ã™ã‚‹ãƒ—レビューダイアログを開ã Auto-format: pretty print on loading, compact on saving. 自動整形: ãれã„ã«è¡¨ç¤ºã€åœ§ç¸®ã—ã¦ä¿å­˜ã€‚ When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. 有効ã«ã™ã‚‹ã¨ã€è‡ªå‹•整形機能ã¯èª­ã¿è¾¼ã¿æ™‚ã«ãƒ‡ãƒ¼ã‚¿ã®å¯èª­æ€§ã‚’高ã‚る改行ã¨ã‚¤ãƒ³ãƒ‡ãƒ³ãƒˆã‚’加ãˆã¾ã™ã€‚データã®ä¿å­˜æ™‚ã«ã¯ã€æ”¹è¡Œã¨ä¸è¦ãªç©ºç™½ã‚’å–り除ãデータを圧縮ã—ã¾ã™ã€‚ Word Wrap ワードラップ Wrap lines on word boundaries å˜èªžå˜ä½ã§ãƒ¯ãƒ¼ãƒ‰ãƒ©ãƒƒãƒ— Open in default application or browser デフォルトã®ã‚¢ãƒ—リケーションã‹ãƒ–ラウザーã§é–‹ã Open in application アプリケーションã§é–‹ã The value is interpreted as a file or URL and opened in the default application or web browser. 値ã¯ãƒ•ァイルã‹URLã¨è§£é‡ˆã•れã€ãƒ‡ãƒ•ォルトã®ã‚¢ãƒ—リケーションã‹ã‚¦ã‚§ãƒ–ブラウザã§é–‹ã‹ã‚Œã¾ã™ã€‚ Save file reference... ファイルå‚ç…§ã‚’ä¿å­˜... Save reference to file å‚照をファイルã«ä¿å­˜ Open in external application 外部ã®ã‚¢ãƒ—リケーションã§é–‹ã Autoformat 自動整形 &Export... エクスãƒãƒ¼ãƒˆ(&E)... &Import... インãƒãƒ¼ãƒˆ(&I)... Import from file ファイルã‹ã‚‰ã‚¤ãƒ³ãƒãƒ¼ãƒˆ Opens a file dialog used to import any kind of data to this database cell. ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ã‚»ãƒ«ã«ä»»æ„ã®ç¨®é¡žã®ãƒ‡ãƒ¼ã‚¿ã‚’インãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ァイルダイアログを開ãã¾ã™ã€‚ Export to file ファイルã¸ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ Opens a file dialog used to export the contents of this database cell to a file. ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ã‚»ãƒ«ã®å†…容をファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ァイルダイアログを開ãã¾ã™ã€‚ Erases the contents of the cell セルã®å†…容を削除 Set as &NULL NULLã«è¨­å®š(&N) This area displays information about the data present in this database cell ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ã‚»ãƒ«ã«å­˜åœ¨ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ã®æƒ…報をã“ã“ã«è¡¨ç¤º This button saves the changes performed in the cell editor to the database cell. ã“ã®ãƒœã‚¿ãƒ³ã¯ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã§è¡Œã‚れãŸå¤‰æ›´ã‚’データベースã®ã‚»ãƒ«ã«ä¿å­˜ã—ã¾ã™ã€‚ Apply é©ç”¨ Print... å°åˆ·... Ctrl+P Open preview dialog for printing displayed text 表示ã•れãŸãƒ†ã‚­ã‚¹ãƒˆã‚’å°åˆ·ã™ã‚‹ãƒ—レビューダイアログを開ã Copy Hex and ASCII å六進数ã¨ASCIIをコピー Copy selected hexadecimal and ASCII columns to the clipboard é¸æŠžã—ãŸå六進数ã¨ASCIIã®ã‚«ãƒ©ãƒ ã‚’クリップボードã«ã‚³ãƒ”ー Ctrl+Shift+C Image data can't be viewed in this mode. ç”»åƒãƒ‡ãƒ¼ã‚¿ã¯ã“ã®ãƒ¢ãƒ¼ãƒ‰ã§ã¯è¡¨ç¤ºã§ãã¾ã›ã‚“。 Try switching to Image or Binary mode. ç”»åƒ/ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ¢ãƒ¼ãƒ‰ã«åˆ‡ã‚Šæ›¿ãˆã¦ã¿ã¦ãã ã•ã„。 Binary data can't be viewed in this mode. ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ‡ãƒ¼ã‚¿ã¯ã“ã®ãƒ¢ãƒ¼ãƒ‰ã§ã¯è¡¨ç¤ºã§ãã¾ã›ã‚“。 Try switching to Binary mode. ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ¢ãƒ¼ãƒ‰ã«åˆ‡ã‚Šæ›¿ãˆã¦ã¿ã¦ãã ã•ã„。 Image files (%1) ç”»åƒãƒ•ァイル (%1) Binary files (*.bin) ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ•ァイル (*.bin) Choose a file to import インãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. テキストモードã§ã¯ãƒ—レーンテキストã¨ã—ã¦ç·¨é›†ã§ãã¾ã™ã€‚JSONã‚„XMLã§ã‚‚åŒæ§˜ã§ã™ãŒã€ã‚·ãƒ³ã‚¿ãƒƒã‚¯ã‚¹ãƒã‚¤ãƒ©ã‚¤ãƒˆã€è‡ªå‹•フォーマットã€ä¿å­˜å‰ã®ãƒãƒªãƒ‡ãƒ¼ã‚·ãƒ§ãƒ³ãŒè¡Œã‚れã¾ã™ã€‚ エラーã¯èµ¤ã„波下線ã§ç¤ºã•れã¾ã™ã€‚ 評価モードã§ã¯å…¥åŠ›ã•れãŸSQLiteå¼ãŒè©•価ã•れã€çµæžœãŒã‚»ãƒ«ã«é©ç”¨ã•れã¾ã™ã€‚ Unsaved data in the cell editor ã‚»ãƒ«ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼å†…ã®æœªä¿å­˜ãƒ‡ãƒ¼ã‚¿ The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? データベースã«ã¾ã é©ç”¨ã•れã¦ã„ãªã„データãŒã‚»ãƒ«ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã«ã‚りã¾ã™ã€‚ 編集中データを行=%1, 列=%2 ã«é©ç”¨ã—ã¾ã™ã‹? Editing row=%1, column=%2 編集中 行=%1, 列=%2 No cell active. アクティブãªã‚»ãƒ«ã¯ã‚りã¾ã›ã‚“。 %1 Image %1 ç”»åƒ Choose a filename to export data エクスãƒãƒ¼ãƒˆãƒ‡ãƒ¼ã‚¿ã®ãƒ•ァイルåã‚’é¸æŠž Invalid data for this mode ã“ã®ãƒ¢ãƒ¼ãƒ‰ã§ã¯ä¸æ­£ãªãƒ‡ãƒ¼ã‚¿ The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? セルã«ä¸æ­£ãªãƒ‡ãƒ¼ã‚¿ %1 ãŒã‚りã¾ã™ã€‚ç†ç”±: %2。本当ã«ã‚»ãƒ«ã«é©ç”¨ã—ã¾ã™ã‹? Type: NULL; Size: 0 bytes åž‹: NULL; サイズ: 0 ãƒã‚¤ãƒˆ Type: Text / Numeric; Size: %n character(s) åž‹: テキスト/数値; サイズ: %n 文字 Type: %1 Image; Size: %2x%3 pixel(s) åž‹: %1 ç”»åƒ; サイズ: %2x%3 ピクセル Type: Valid JSON; Size: %n character(s) åž‹: æ­£è¦ãªJSON; サイズ: %n 文字 Type: Binary; Size: %n byte(s) åž‹: ãƒã‚¤ãƒŠãƒªâ€•; サイズ: %n ãƒã‚¤ãƒˆ Couldn't save file: %1. ファイルをä¿å­˜ã§ãã¾ã›ã‚“: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. データã¯ä¸€æ™‚ファイルã«ä¿å­˜ã•れã€ãƒ‡ãƒ•ォルトã®ã‚¢ãƒ—リケーションã§é–‹ã‹ã‚Œã¾ã—ãŸã€‚ã‚ãªãŸã¯ã™ãã«ãƒ•ァイルを編集ã§ãã€æº–å‚™ãŒã§ããŸã‚‰ã€ä¿å­˜ã—ãŸæ–°ã—ã„データをセルã«é©ç”¨ã€ã‚‚ã—ãã¯ã™ã¹ã¦ã®å¤‰æ›´ã‚’キャンセルã§ãã¾ã™ã€‚ EditIndexDialog Edit Index Schema インデックスã®ã‚¹ã‚­ãƒ¼ãƒžã‚’編集 &Name åå‰(&N) &Table テーブル(&T) &Unique 一æ„(&U) For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed インデックスをテーブルã®ä¸€éƒ¨ã®ã¿ã«åˆ¶é™ã™ã‚‹å ´åˆã¯ã€ãã®éƒ¨åˆ†ã‚’é¸æŠžã™ã‚‹WHERE節をã“ã“ã«æŒ‡å®šã—ã¾ã™ Partial inde&x clause インデックス指定節(&X) Colu&mns カラム(&M) Table column テーブルã®ã‚«ãƒ©ãƒ  Type データ型 Add a new expression column to the index. Expression columns contain SQL expression rather than column names. æ–°ã—ã„å¼ã‚«ãƒ©ãƒ ã‚’インデックスã«åŠ ãˆã‚‹ã€‚å¼ã‚«ãƒ©ãƒ ã¯ã‚«ãƒ©ãƒ åã§ãªãSQLå¼ã‚’æŒã¡ã¾ã™ã€‚ Index column インデックスカラム Order 順番 Deleting the old index failed: %1 å¤ã„インデックスã®å‰Šé™¤ã«å¤±æ•—: %1 Creating the index failed: %1 インデックスã®ä½œæˆã«å¤±æ•—: %1 EditTableDialog Edit table definition テーブルã®å®šç¾©ã‚’編集 Table テーブル Advanced 高度ãªè¨­å®š Without Rowid Rowidãªã— Fields フィールド Database sche&ma データベーススキーマ(&M) Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. 「ROWIDãªã—ã€ã®ãƒ†ãƒ¼ãƒ–ルを作æˆã—ã¾ã™ã€‚ã“ã®ãƒ•ラグを設定ã™ã‚‹ã«ã¯ä¸»ã‚­ãƒ¼(ä»»æ„ã®åž‹ã€è¤‡åˆã§ã‚‚よã„)ã®è¨­å®šãŒå¿…è¦ã§ã™ã€‚ãã—ã¦ã€è‡ªå‹•増加フラグã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。 On Conflict é‡è¤‡æ™‚å‡¦ç† Strict åž‹ã«åŽ³æ ¼ When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. åž‹ã«åŽ³æ ¼ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’æœ‰åŠ¹ã«ã™ã‚‹ã¨ã€ãƒ‡ãƒ¼ã‚¿ã®æ›´æ–°è¿½åŠ æ™‚ã«SQLiteã¯ãれãžã‚Œã®ã‚«ãƒ©ãƒ ã®ãƒ‡ãƒ¼ã‚¿åž‹ã‚’強制ã—ã¾ã™ã€‚ Add 追加 Remove 削除 Move to top 先頭㸠Move up 上㸠Move down 下㸠Move to bottom 末尾㸠Name åå‰ Type データ型 NN NN Not null éžnull PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> 主キー</p></body></html> AI AI Autoincrement 自動増加 U U Unique ä¸€æ„ Default デフォルト Default value デフォルト値 Check 検査 Check constraint ãƒã‚§ãƒƒã‚¯åˆ¶ç´„ Collation ç…§åˆé †åº Foreign Key 外部キー <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> 外部キー</p></body></html> Index Constraints インデックス制約 Add constraint 制約を追加 Remove constraint 制約を削除 Columns カラム SQL SQL Foreign Keys 外部キー References å‚ç…§ Check Constraints ãƒã‚§ãƒƒã‚¯åˆ¶ç´„ <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">警告: </span>ãƒ†ãƒ¼ãƒ–ãƒ«å®šç¾©ã«æ§‹æ–‡è§£æžã§ããªã„ã‚‚ã®ãŒã‚りã¾ã™ã€‚ã“ã®ãƒ†ãƒ¼ãƒ–ルを変更ã—ä¿å­˜ã™ã‚‹ã¨å•題ãŒèµ·ãã‚‹ã‹ã‚‚ã—れã¾ã›ã‚“。.</p></body></html> Primary Key 主キー Add a primary key constraint 主キー制約を追加 Add a unique constraint ä¸€æ„æ€§åˆ¶ç´„を追加 There can only be one primary key for each table. Please modify the existing primary key instead. 主キーã¯å„テーブルã«ä¸€ã¤ã ã‘存在ã§ãã¾ã™ã€‚替ã‚ã‚Šã«æ—¢å­˜ã®ä¸»ã‚­ãƒ¼ã‚’変更ã—ã¦ãã ã•ã„。 Error creating table. Message from database engine: %1 テーブル作æˆã§ã‚¨ãƒ©ãƒ¼ã€‚データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸: %1 There already is a field with that name. Please rename it first or choose a different name for this field. ã“ã®åå‰ã¯æ—¢ã«åˆ¥ã®ãƒ•ィールドã«ä½¿ç”¨ã•れã¦ã„ã¾ã™ã€‚既存ã®ãƒ•ィールドåを変更ã™ã‚‹ã‹ã€åˆ¥ã®åå‰ã‚’付ã‘ã¦ãã ã•ã„。 This column is referenced in a foreign key in table %1 and thus its name cannot be changed. ã“ã®ã‚«ãƒ©ãƒ ã¯ãƒ†ãƒ¼ãƒ–ル %1 ã®å¤–部キーã«å‚ç…§ã•れã¦ã„ã‚‹ã®ã§ã€åå‰ã‚’変更ã§ãã¾ã›ã‚“。 There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. å°‘ãªãã¨ã‚‚1ã¤ã®è¡Œã§ã“ã®ãƒ•ィールドã«NULLãŒè¨­å®šã•れã¦ã„ã¾ã™ã€‚ãã®ãŸã‚ã€éžNULLを設定ã™ã‚‹ã®ã¯ä¸å¯èƒ½ã§ã™ã€‚å…ˆã«ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’変更ã—ã¦ãã ã•ã„。 There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. å°‘ãªãã¨ã‚‚1ã¤ã®è¡Œã§ã“ã®ãƒ•ィールドã«INTEGERã§ãªã„値ãŒè¨­å®šã•れã¦ã„ã¾ã™ã€‚ãã®ãŸã‚ã€è‡ªå‹•増加を設定ã™ã‚‹ã®ã¯ä¸å¯èƒ½ã§ã™ã€‚å…ˆã«ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’変更ã—ã¦ãã ã•ã„。 Column '%1' has duplicate data. カラム '%1' ã«é‡è¤‡ãƒ‡ãƒ¼ã‚¿ãŒã‚りã¾ã™ã€‚ This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. 一æ„ã«ã™ã‚‹ã®ã¯ä¸å¯èƒ½ã§ã™ã€‚é‡è¤‡ãƒ‡ãƒ¼ã‚¿ã‚’削除ã™ã‚‹ã¨ã€ä¸€æ„ã«ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚ Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. 本当ã«ãƒ•ィールド '%1' を削除ã—ã¾ã™ã‹? ç¾åœ¨ã“ã®ãƒ•ィールドã«ã‚ã‚‹ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã¯å¤±ã‚れã¾ã™ã€‚ Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled rowidãªã—ã«ã™ã‚‹å‰ã«ã€ä»¥ä¸‹ã®æ¡ä»¶ã«åˆã†ãƒ•ィールドを追加ã—ã¦ãã ã•ã„。 - 主キーã§ã‚ã‚‹ - 自動増加ãªã— Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set é‡è¤‡æ™‚処ç†ã‚’設定ã™ã‚‹å‰ã«ã€ä»¥ä¸‹ã®æ¡ä»¶ã«åˆã†ãƒ•ィールドを追加ã—ã¦ãã ã•ã„: - 主キーã§ã‚ã‚‹ ExportDataDialog Export data as CSV データをCSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ Tab&le(s) テーブル(&L) Colu&mn names in first line 先頭行をカラムåã«(&M) Fie&ld separator フィールド区切り(&L) , , ; ; Tab タブ | | Other ãã®ä»– &Quote character 引用符文字(&Q) " " ' ' New line characters 改行文字 Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print æ•´å½¢ Export data as JSON データをJSONã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ exporting CSV CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ Error while writing the file '%1': %2 ファイル '%1' を書ã込むã¨ãã«ã‚¨ãƒ©ãƒ¼ãŒã‚りã¾ã—ãŸ: %2 Could not open output file: %1 出力ファイルを開ã‘ã¾ã›ã‚“: %1 exporting JSON JSONã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ Choose a filename to export data エクスãƒãƒ¼ãƒˆãƒ‡ãƒ¼ã‚¿ã®ãƒ•ァイルåã‚’é¸æŠž Please select at least 1 table. å°‘ãªãã¨ã‚‚1ã¤ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠžã—ã¦ãã ã•ã„。 Choose a directory ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’é¸æŠž Export completed. エクスãƒãƒ¼ãƒˆå®Œäº†ã€‚ Export finished with errors. エラーãŒã‚りã¾ã™ãŒã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãŒçµ‚了ã—ã¾ã—ãŸã€‚ ExportSqlDialog Export SQL... SQLã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ... Tab&le(s) テーブル(&L) Select All ã™ã¹ã¦é¸æŠž Deselect All ã™ã¹ã¦éžé¸æŠž &Options オプション(&O) Keep column names in INSERT INTO INSERT INTOã«ã‚«ãƒ©ãƒ åã‚’ä¿æŒ Multiple rows (VALUES) per INSERT statement INSERTæ–‡ã«è¤‡æ•°è¡Œ(VALUES) Export everything ã™ã¹ã¦ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ Export schema only スキーマã®ã¿ã‚’エクスãƒãƒ¼ãƒˆ Export data only データã®ã¿ã‚’エクスãƒãƒ¼ãƒˆ Keep original CREATE statements å…ƒã®CREATEæ–‡ã‚’ä¿æŒ Keep old schema (CREATE TABLE IF NOT EXISTS) å¤ã„ã‚¹ã‚­ãƒ¼ãƒžã‚’ä¿æŒ (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) å¤ã„スキーマを上書ã (DROP TABLE ã—ãŸå¾Œã« CREATE TABLE) Please select at least one table. å°‘ãªãã¨ã‚‚1ã¤ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠžã—ã¦ãã ã•ã„。 Choose a filename to export エクスãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ァイルåã‚’é¸æŠž Export completed. エクスãƒãƒ¼ãƒˆå®Œäº†ã€‚ Export cancelled or failed. エクスãƒãƒ¼ãƒˆã‚’キャンセルã¾ãŸã¯å¤±æ•—ã—ã¾ã—ãŸã€‚ ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... 検索... Find and Replace... 検索ã¨ç½®æ›... Print... å°åˆ·... ExtendedTableWidget Use as Exact Filter 抽出フィルターã«ä½¿ã† Containing å«ã‚€ Not containing å«ã¾ãªã„ Not equal to ç­‰ã—ããªã„ Greater than より大ãã„ Less than 未満 Greater or equal 以上 Less or equal 以下 Between this and... ã“れã¨ã®é–“... Regular expression æ­£è¦è¡¨ç¾ Edit Conditional Formats... æ¡ä»¶ä»˜ã書å¼ã‚’編集... Set to NULL NULLã«è¨­å®š Cut 切りå–り Copy コピー Copy with Headers ヘッダーをå«ã‚ã¦ã‚³ãƒ”ー Copy as SQL SQLã¨ã—ã¦ã‚³ãƒ”ー Paste 貼り付㑠Print... å°åˆ·... Use in Filter Expression フィルターå¼ã‚’使用 Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? クリップボードã®å†…容ã¯é¸æŠžã•れãŸç¯„囲より大ãã„ã§ã™. ãれã§ã‚‚挿入ã—ã¾ã™ã‹? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>読ã¿è¾¼ã¾ã‚Œã¦ã„ãªã„データãŒã‚りã¾ã™ã€‚<b>ã™ã¹ã¦ã®è¡Œã‚’é¸æŠžã™ã‚‹å‰ã«ã€ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿ã¾ã™ã‹?</b><p><p>ç­”ãˆãŒ <b>ã„ã„ãˆ</b> ãªã‚‰ã°ã€ãƒ‡ãƒ¼ã‚¿ã¯èª­ã¿è¾¼ã¾ã‚Œãšã€é¸æŠžã¯å®Ÿè¡Œã•れã¾ã›ã‚“。<br/>ç­”ãˆãŒ <b>ã¯ã„</b> ãªã‚‰ã°ã€æ™‚é–“ãŒã‹ã‹ã‚Šã¾ã™ãŒã€ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿ã€é¸æŠžãŒå®Ÿè¡Œã•れã¾ã™ã€‚</p>警告: 大ãã„テーブルã«ã‚ã‚‹ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã®èª­ã¿è¾¼ã¿ã«ã¯ã‹ãªã‚Šã®è¨˜æ†¶é ˜åŸŸã‚’å¿…è¦ã¨ã—ã¾ã™ã€‚ Cannot set selection to NULL. Column %1 has a NOT NULL constraint. é¸æŠžç¯„å›²ã«NULLを設定ã§ãã¾ã›ã‚“。カラム %1 ã«ã¯éžNULL制約ãŒã‚りã¾ã™ã€‚ FileExtensionManager File Extension Manager ファイル拡張å­ç®¡ç† &Up 上ã¸(&U) &Down 下ã¸(&D) &Add 追加(&A) &Remove 削除(&R) Description 説明 Extensions æ‹¡å¼µå­ *.extension *.æ‹¡å¼µå­ FilterLineEdit Filter フィルター These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression ã“ã®å…¥åŠ›æ¬„ã¯ç¾åœ¨é¸æŠžã—ãŸãƒ†ãƒ¼ãƒ–ルã®å³å¸­ãƒ•ィルターã«ãªã‚Šã¾ã™ã€‚ デフォルトã§ã¯å…¥åŠ›ãƒ†ã‚­ã‚¹ãƒˆãŒå«ã¾ã‚Œã‚‹è¡ŒãŒæŠ½å‡ºã•れã¾ã™ã€‚ ä»¥ä¸‹ã®æ¼”ç®—å­ã«ã‚‚対応ã—ã¦ã„ã¾ã™ã€‚: % ワイルドカード > より大ãã„ < 未満 >= 以上 <= 以下 = ç­‰ã—ã„: 完全ã«ä¸€è‡´ <> ç­‰ã—ããªã„: ä¸ä¸€è‡´ x~y 範囲: xã¨yã®é–“ /regexp/ æ­£è¦è¡¨ç¾ã«ä¸€è‡´ã™ã‚‹å€¤ Set Filter Expression フィルターå¼ã‚’設定 What's This? ã“れã¯ä½•? Is NULL NULL Is not NULL NULLã§ãªã„ Is empty 空文字 Is not empty 空文字ã§ãªã„ Not containing... å«ã¾ãªã„... Equal to... ç­‰ã—ã„... Not equal to... ç­‰ã—ããªã„... Greater than... より大ãã„... Less than... 未満... Greater or equal... 以上... Less or equal... 以下... In range... 範囲内... Regular expression... æ­£è¦è¡¨ç¾... Clear All Conditional Formats ã™ã¹ã¦ã®æ¡ä»¶ä»˜ã書å¼ã‚’削除 Use for Conditional Format æ¡ä»¶ä»˜ã書å¼ã‚’使ㆠEdit Conditional Formats... æ¡ä»¶ä»˜ã書å¼ã‚’編集... FindReplaceDialog Find and Replace 検索ã¨ç½®æ› Fi&nd text: 検索文字列(&N): Re&place with: ç½®æ›æ–‡å­—列(&P): Match &exact case 大/å°æ–‡å­—を区別(&E) Match &only whole words å˜èªžä¸€è‡´ã®ã¿(&O) When enabled, the search continues from the other end when it reaches one end of the page 有効ã«ã™ã‚‹ã¨ã€ãƒšãƒ¼ã‚¸ã®æœ€å¾Œã«åˆ°é”ã™ã‚‹ã¨å…ˆé ­ã«æˆ»ã£ã¦æ¤œç´¢ã—ã¾ã™ &Wrap around 折り返ã—ã‚り(&W) When set, the search goes backwards from cursor position, otherwise it goes forward 設定ã™ã‚‹ã¨ã‚«ãƒ¼ã‚½ãƒ«ä½ç½®ã‹ã‚‰æˆ»ã£ã¦æ¤œç´¢ã—ã¾ã™ã€‚設定ã—ãªã„ã¨ã‚«ãƒ¼ã‚½ãƒ«ä½ç½®ã®å…ˆã‚’検索ã—ã¾ã™ Search &backwards 戻ã£ã¦æ¤œç´¢(&B) <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>設定ã™ã‚‹ã¨ã€ç¾åœ¨é¸æŠžã—ãŸç¯„囲ã®ã¿ã‚’検索ã—ã¾ã™ã€‚</p></body></html> &Selection only é¸æŠžç¯„å›²ã®ã¿(&S) <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> URLã®ãŸã‚%ã®æ•°ã¯ä¸€è‡´ã—ãªã„ <html><head/><body><p>設定ã™ã‚‹ã¨ã€æ¤œç´¢æ¡ä»¶ã¯UNIXæ­£è¦è¡¨ç¾ã¨è§£é‡ˆã•れã¾ã™ã€‚以下をå‚ç…§ <a href="https://ja.wikibooks.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE">Wikibooksã®æ­£è¦è¡¨ç¾</a>。</p></body></html> Use regular e&xpressions æ­£è¦è¡¨ç¾ã‚’使用(&X) Find the next occurrence from the cursor position and in the direction set by "Search backwards" カーソルä½ç½®ã‹ã‚‰"戻ã£ã¦æ¤œç´¢"ã§è¨­å®šã—ãŸæ–¹å‘ã«ã‚ã‚‹ã€æ¬¡ã«ä¸€è‡´ã™ã‚‹æ–‡å­—列を検索ã—ã¾ã™ &Find Next 次を検索(&F) F3 &Replace ç½®æ›(&R) Highlight all the occurrences of the text in the page ページ内ã®ã™ã¹ã¦ã®ä¸€è‡´ã™ã‚‹æ–‡å­—列を強調 F&ind All ã™ã¹ã¦æ¤œç´¢(&I) Replace all the occurrences of the text in the page ページ内ã®ã™ã¹ã¦ã®ä¸€è‡´ã™ã‚‹æ–‡å­—åˆ—ã‚’ç½®æ› Replace &All ã™ã¹ã¦ç½®æ›(&A) The searched text was not found 検索文字列ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—㟠The searched text was not found. 検索文字列ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚ The searched text was found one time. 検索文字列ãŒ1ã¤ã‚りã¾ã—ãŸã€‚ The searched text was found %1 times. 検索文字列ãŒ%1ã¤ã‚りã¾ã—ãŸã€‚ The searched text was replaced one time. 検索文字列を1ã¤ç½®ãæ›ãˆã¾ã—ãŸã€‚ The searched text was replaced %1 times. 検索文字列を%1ã¤ç½®ãæ›ãˆã¾ã—ãŸã€‚ ForeignKeyEditor &Reset リセット(&R) Foreign key clauses (ON UPDATE, ON DELETE etc.) 外部キー節 (ON UPDATE, ON DELETE ãªã©ã€‚) ImageViewer Image Viewer ç”»åƒãƒ“ューアー Reset the scaling to match the original size of the image. ç”»åƒã®å…ƒã®ã‚µã‚¤ã‚ºã«åˆã‚ã›ã¦æ‹¡å¤§çŽ‡ã‚’ãƒªã‚»ãƒƒãƒˆã™ã‚‹ã€‚ Set the scaling to match the size of the viewport. 拡大率を表示領域ã®ã‚µã‚¤ã‚ºã«åˆã‚ã›ã‚‹ã€‚ Print... å°åˆ·... Open preview dialog for printing displayed image 表示ã•れãŸç”»åƒã‚’å°åˆ·ã™ã‚‹ãƒ—レビューダイアログを開ã Ctrl+P ImportCsvDialog Import CSV file CSVファイルをインãƒãƒ¼ãƒˆ Table na&me テーブルå(&M) &Column names in first line 先頭行をカラムåã«(&C) Field &separator フィールド区切り(&S) , , ; ; Tab タブ | | Other ãã®ä»– &Quote character 引用符文字(&Q) Other (printable) ãã®ä»– (å°åˆ·å¯èƒ½) Other (code) ãã®ä»– (文字コード) " " ' ' &Encoding エンコード(&E) UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? フィールドをトリムã™ã‚‹? Separate tables テーブルを分ã‘ã‚‹ Advanced 高度ãªè¨­å®š When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. 空値をCSVファイルã‹ã‚‰æ—¢å­˜ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ•ォルト値ãŒã‚るカラムã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã¨ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ãŒæŒ¿å…¥ã•れã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ä»£ã‚りã«ç©ºå€¤ãŒæŒ¿å…¥ã•れã¾ã™ã€‚ Ignore default &values デフォルト値を無視(&V) Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ã€ãƒ‡ãƒ•ォルト値ãŒãªã NOT NULL ãªã‚«ãƒ©ãƒ ã«ç©ºå€¤ã‚’インãƒãƒ¼ãƒˆã—よã†ã¨ã—ãŸã¨ãã«ã€ã‚¤ãƒ³ãƒãƒ¼ãƒˆã‚’中止ã—ã¾ã™ã€‚ Fail on missing values 値ãŒãªã„å ´åˆä¸­æ­¢ Disable data type detection データ型検出を無効 Disable the automatic data type detection when creating a new table. æ–°ã—ã„テーブルを作るã¨ãã«è‡ªå‹•データ型検出を無効ã«ã—ã¾ã™ã€‚ Use local number conventions åœ°åŸŸã®æ•°å€¤å¤‰æ›ã‚’使用 Use decimal and thousands separators according to the system locale. システムã®åœ°åŸŸè¨­å®šã«å¾“ã„ã€å°æ•°ç‚¹ã¨æ¡åŒºåˆ‡ã‚Šã‚’使用ã™ã‚‹ã€‚ When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. 主キーã€ä¸€æ„性制約ã€ä¸€æ„ãªã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ãŒã‚る既存ã®ãƒ†ãƒ¼ãƒ–ルã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã¨ã€ç«¶åˆãŒç™ºç”Ÿã™ã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションã§ã€ç«¶åˆã®è§£æ±ºæ–¹æ³•ã‚’é¸æŠžã§ãã¾ã™ã€‚デフォルトã§ã¯ã‚¤ãƒ³ãƒãƒ¼ãƒˆã‚’中止ã—ロールãƒãƒƒã‚¯ã—ã¾ã™ãŒã€ç„¡è¦–ã‚’é¸æŠžã—ã¦ç«¶åˆã—ãŸè¡Œã‚’インãƒãƒ¼ãƒˆã—ãªã„ã€ã‚‚ã—ãã¯ã€ãƒ†ãƒ¼ãƒ–ãƒ«å†…ã®æ—¢å­˜ã®è¡Œã‚’ç½®ãæ›ãˆã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ Abort import インãƒãƒ¼ãƒˆã‚’中止 Ignore row 行を無視 Replace existing row 既存ã®è¡Œã‚’ç½®ãæ›ãˆ Conflict strategy ç«¶åˆã®è§£æ±ºæ–¹æ³• Deselect All ã™ã¹ã¦éžé¸æŠž Match Similar 類似ã«ä¸€è‡´ Select All ã™ã¹ã¦é¸æŠž There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. åå‰ãŒ '%1' ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã¯æ—¢ã«å­˜åœ¨ã—ã¦ã„ã¾ã™ã€‚既存ã®ãƒ†ãƒ¼ãƒ–ルã¸ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã¯ã‚«ãƒ©ãƒ ã®æ•°ãŒä¸€è‡´ã™ã‚‹å ´åˆã®ã¿å¯èƒ½ã§ã™ã€‚ There is already a table named '%1'. Do you want to import the data into it? åå‰ãŒ '%1' ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã¯æ—¢ã«å­˜åœ¨ã—ã¦ã„ã¾ã™ã€‚データをã“れã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã—ã¾ã™ã‹? Creating restore point failed: %1 復元ãƒã‚¤ãƒ³ãƒˆã®ä½œæˆã«å¤±æ•—: %1 Creating the table failed: %1 テーブルã®ä½œæˆã«å¤±æ•—: %1 importing CSV CSVã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ Could not prepare INSERT statement: %1 INSERT文を準備ã§ãã¾ã›ã‚“ã§ã—ãŸ: %1 Inserting row failed: %1 è¡Œã®æŒ¿å…¥ã«å¤±æ•—: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. 予想外ã®EoF。正ã—ãクォートã•れã¦ã„ã‚‹ã‹ã€ãƒ•ァイル形å¼ãŒä¸æ­£ã§ãªã„ã‹ç¢ºèªã—ã¦ãã ã•ã„。 Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. ファイル '%1' ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã« %2msã‹ã‹ã‚Šã¾ã—ãŸã€‚内 %3ms ã¯è¡Œé–¢æ•°ã«è²»ã‚„ã•れã¾ã—ãŸã€‚ MainWindow DB Browser for SQLite DB Browser for SQLite This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. ã“れã¯é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ§‹é€ ã§ã™ã€‚ SQL文をオブジェクト行ã‹ã‚‰ãƒ‰ãƒ©ãƒƒã‚°ã—ã»ã‹ã®ã‚¢ãƒ—リケーションや'DB Browser for SQLite'ã®ä»–ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã«ãƒ‰ãƒ­ãƒƒãƒ—ã§ãã¾ã™ã€‚ Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. 警告: ã“ã®ãƒ—ラグマã¯èª­ã¿å–りå¯èƒ½ã§ãªãã€ã“ã®å€¤ã¯æŽ¨å®šã§ã™ã€‚プラグマを書ã込んã§ã‚‚ã€SQLite æ‹¡å¼µãªã©ã§ä¸Šæ›¸ãã•れるã‹ã‚‚ã—れã¾ã›ã‚“。 toolBar1 ツールãƒãƒ¼1 &File ファイル(&F) &Import インãƒãƒ¼ãƒˆ(&I) &Export エクスãƒãƒ¼ãƒˆ(&E) &Edit 編集(&E) &View ビュー(&V) &Help ヘルプ(&H) Too&ls ツール(&L) DB Toolbar DBツールãƒãƒ¼ Edit Database &Cell データベースã®ã‚»ãƒ«ã‚’編集(&C) SQL &Log SQLログ(&L) Show S&QL submitted by 表示ã™ã‚‹SQLã®é€ä¿¡å…ƒã¯(&Q) User ユーザー Application アプリケーション Error Log エラーログ This button clears the contents of the SQL logs ã“ã®ãƒœã‚¿ãƒ³ã§SQLログã®å†…容を消去ã—ã¾ã™ &Clear 消去(&C) This panel lets you examine a log of all SQL commands issued by the application or by yourself ã“ã®ãƒ‘ãƒãƒ«ã§ã‚¢ãƒ—リケーションやã‚ãªãŸãŒç™ºè¡Œã—ãŸå…¨ã¦ã®SQLコマンドã®ãƒ­ã‚°ã‚’調査ã§ãã¾ã™ &Plot プロット(&P) DB Sche&ma DBスキーマ(&M) This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. ã“れã¯é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ§‹é€ ã§ã™ã€‚ 複数ã®ã‚ªãƒ–ジェクトåã‚’åå‰ã‚«ãƒ©ãƒ ã‹ã‚‰ãƒ‰ãƒ©ãƒƒã‚°ã—SQLエディターã«ãƒ‰ãƒ­ãƒƒãƒ—ã§ãã¾ã™ã€‚ドロップã—ãŸåå‰ã®ãƒ—ロパティã¯ã‚³ãƒ³ãƒ†ã‚­ã‚¹ãƒˆãƒ¡ãƒ‹ãƒ¥ãƒ¼ã§èª¿ç¯€ã§ãã¾ã™ã€‚ã“れã¯SQLæ–‡ã®ä½œæˆã«å½¹ç«‹ã¡ã¾ã™ã€‚ SQL文をスキーマカラムã‹ã‚‰SQLエディターや他ã®ã‚¢ãƒ—リケーションã«ãƒ‰ãƒ­ãƒƒãƒ—ã§ãã¾ã™ã€‚ &Remote リモート(&R) Project Toolbar プロジェクトツールãƒãƒ¼ Extra DB toolbar 追加DBツールãƒãƒ¼ Close the current database file ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを閉ã˜ã¾ã™ &New Database... æ–°ã—ã„データベース(&N)... Create a new database file æ–°ã—ã„データベースファイルを作æˆã—ã¾ã™ This option is used to create a new database file. ã“ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¯æ–°ã—ã„データベースファイルを作æˆã™ã‚‹ãŸã‚ã«ä½¿ã„ã¾ã™ã€‚ Ctrl+N &Open Database... データベースを開ã(&O)... Open an existing database file 既存ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを開ãã¾ã™ This option is used to open an existing database file. ã“ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¯æ—¢å­˜ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを開ããŸã‚ã«ä½¿ã„ã¾ã™ã€‚ Ctrl+O &Close Database データベースを閉ã˜ã‚‹(&C) This button closes the connection to the currently open database file ã“ã®ãƒœã‚¿ãƒ³ã§ç¾åœ¨é–‹ã„ã¦ã„るデータベースファイルã¨ã®æŽ¥ç¶šã‚’é–‰ã˜ã¾ã™ New &tab æ–°ã—ã„タブ(&T) Open SQL file(s) SQLファイルを開ã This button opens files containing SQL statements and loads them in new editor tabs ã“ã®ãƒœã‚¿ãƒ³ã¯SQL文をå«ã‚€ãƒ•ァイルを開ãã€æ–°ã—ã„編集タブã«èª­ã¿è¾¼ã¿ã¾ã™ Execute line 行を実行 Sa&ve Project プロジェクトをä¿å­˜(&V) This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file ã“ã®ãƒœã‚¿ãƒ³ã¯DBã‚’é–‹ãã“ã¨ã«é–¢ä¿‚ã™ã‚‹ã™ã¹ã¦ã®è¨­å®šã‚’DB Browser for SQLite プロジェクトファイルã«ä¿å­˜ã—ã¾ã™ This button lets you open a DB Browser for SQLite project file ã“ã®ãƒœã‚¿ãƒ³ã¯DB Browser for SQLite プロジェクトファイルを開ãã¾ã™ Ctrl+Shift+O Find 検索 Find or replace 検索ã¨ç½®æ› Print text from current SQL editor tab ç¾åœ¨ã®SQLエディタータブã®ãƒ†ã‚­ã‚¹ãƒˆã‚’å°åˆ·ã—ã¾ã™ Print the structure of the opened database é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ§‹é€ ã‚’å°åˆ·ã—ã¾ã™ Un/comment block of SQL code SQLコードã®ãƒ–ロックをコメント/éžã‚³ãƒ¡ãƒ³ãƒˆã« Un/comment block ブロックをコメント/éžã‚³ãƒ¡ãƒ³ãƒˆ Comment or uncomment current line or selected block of code ç¾åœ¨è¡Œã‹ã‚³ãƒ¼ãƒ‰ã®é¸æŠžã•れãŸãƒ–ロックをコメント/éžã‚³ãƒ¡ãƒ³ãƒˆã«ã—ã¾ã™ Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. é¸æŠžã•れãŸè¡Œã‹ã€é¸æŠžãŒãªã„ãªã‚‰ã°ç¾åœ¨è¡Œã‚’コメント/éžã‚³ãƒ¡ãƒ³ãƒˆã«ã—ã¾ã™ã€‚ブロック全体ã¯ãã®å…ˆé ­è¡Œã«å¾“ã„コメント/éžã‚³ãƒ¡ãƒ³ãƒˆã•れã¾ã™ã€‚ Ctrl+/ Stop SQL execution SQLã®å®Ÿè¡Œã‚’中止 Stop execution 実行を中止 Stop the currently running SQL script ç¾åœ¨å®Ÿè¡Œä¸­ã® SQL スクリプトを中止ã—ã¾ã™ &Save Project As... プロジェクトã«åå‰ã‚’付ã‘ã¦ä¿å­˜(&S)... Save the project in a file selected in a dialog ダイアログã§é¸æŠžã—ãŸãƒ•ァイルã«ãƒ—ロジェクトをä¿å­˜ã—ã¾ã™ Save A&ll ã™ã¹ã¦ä¿å­˜(&L) Save DB file, project file and opened SQL files DBファイルã€ãƒ—ロジェクトファイルã€é–‹ã„ã¦ã„ã‚‹SQLファイルをä¿å­˜ã—ã¾ã™ Ctrl+Shift+S Browse Table テーブルを閲覧 Close Pro&ject プロジェクトを閉ã˜ã‚‹(&J) Close project and database files and return to the initial state プロジェクトã¨ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é–‰ã˜ã¦åˆæœŸçŠ¶æ…‹ã«æˆ»ã—ã¾ã™ Ctrl+Shift+F4 Detach Database データベースを切断 Detach database file attached to the current database connection ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹æŽ¥ç¶šã‹ã‚‰ä½¿ç”¨ä¸­ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを切り離ã—ã¾ã™ Ctrl+W &Revert Changes 変更をå–り消ã—(&R) Revert database to last saved state 最後ã«ä¿å­˜ã—ãŸçŠ¶æ…‹ã¸ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’戻ã—ã¾ã™ This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. ã“ã®ã‚ªãƒ—ションã¯ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを最後ã«ä¿å­˜ã—ãŸçŠ¶æ…‹ã«æˆ»ã™ãŸã‚ã«ä½¿ã„ã¾ã™ã€‚最後ã®ä¿å­˜ã®å¾Œã«è¡Œã‚れãŸã™ã¹ã¦ã®å¤‰æ›´ã¯å¤±ã‚れã¾ã™ã€‚ &Write Changes 変更を書ãè¾¼ã¿(&W) Write changes to the database file データベースファイルã«å¤‰æ›´ã‚’書ãè¾¼ã¿ã¾ã™ This option is used to save changes to the database file. ã“ã®ã‚ªãƒ—ションã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルã«å¤‰æ›´ã‚’ä¿å­˜ã™ã‚‹ãŸã‚ã«ä½¿ã„ã¾ã™ã€‚ Ctrl+S Compact &Database... データベースを圧縮(&D)... Compact the database file, removing space wasted by deleted records 削除ã•れãŸãƒ¬ã‚³ãƒ¼ãƒ‰ãŒæ®‹ã£ã¦ã„るスペースをå–り除ãã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを圧縮ã—ã¾ã™ Compact the database file, removing space wasted by deleted records. 削除ã•れãŸãƒ¬ã‚³ãƒ¼ãƒ‰ãŒæ®‹ã£ã¦ã„るスペースをå–り除ãã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを圧縮ã—ã¾ã™ã€‚ E&xit 終了(&X) Ctrl+Q &Database from SQL file... SQLファイルã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¸(&D)... Import data from an .sql dump text file into a new or existing database. SQLダンプテキストファイルã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’ã€æ–°ã—ã„ã‚‚ã—ãã¯æ—¢å­˜ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. ã“ã®ã‚ªãƒ—ションã§SQLダンプテキストファイルã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’ã€æ–°ã—ã„ã‚‚ã—ãã¯æ—¢å­˜ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã§ãã¾ã™ã€‚SQLダンプファイルã¯ã€MySQLã‚„PostgreSQLãªã©ã€ã»ã¨ã‚“ã©ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚¨ãƒ³ã‚¸ãƒ³ã§ä½œæˆã§ãã¾ã™ã€‚ &Table from CSV file... CSVファイルã‹ã‚‰ãƒ†ãƒ¼ãƒ–ルã¸(&T)... Open a wizard that lets you import data from a comma separated text file into a database table. カンマ区切りã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã®ãƒ‡ãƒ¼ã‚¿ã‚’データベースã®ãƒ†ãƒ¼ãƒ–ルã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ã‚’é–‹ãã¾ã™ã€‚ Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. カンマ区切りã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã®ãƒ‡ãƒ¼ã‚¿ã‚’データベースã®ãƒ†ãƒ¼ãƒ–ルã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ã‚’é–‹ãã¾ã™ã€‚CSVファイルã¯ã»ã¨ã‚“ã©ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚„表計算アプリケーションã§ä½œæˆã§ãã¾ã™ã€‚ &Database to SQL file... データベースをSQLファイルã¸(&D)... Export a database to a .sql dump text file. データベースを .sql ダンプテキストファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. ã“ã®ã‚ªãƒ—ションã§ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ .sql ダンプテキストファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã™ã€‚SQLダンプファイルã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®å†ä½œæˆã«å¿…è¦ãªã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’å«ã¿ã€MySQLã‚„PostgreSQLãªã©ã€ã»ã¨ã‚“ã©ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚¨ãƒ³ã‚¸ãƒ³ã§åˆ©ç”¨ã§ãã¾ã™ã€‚ &Table(s) as CSV file... テーブルをCSVファイルã¸(&T)... Export a database table as a comma separated text file. データベースã®ãƒ†ãƒ¼ãƒ–ルをカンマ区切りã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. データベースã®ãƒ†ãƒ¼ãƒ–ルをカンマ区切りã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ä»–ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚„表計算アプリケーションã§ã‚¤ãƒ³ãƒãƒ¼ãƒˆã§ãã¾ã™ã€‚ &Create Table... テーブルを作æˆ(&C)... Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«æ–°ã—ã„テーブルã®åå‰ã¨ãƒ•ィールドを定義ã§ãã‚‹ã€ãƒ†ãƒ¼ãƒ–ル作æˆã‚¦ã‚¤ã‚¶ãƒ¼ãƒ‰ã‚’é–‹ãã¾ã™ &Delete Table... テーブルを削除(&D)... Delete Table テーブルを削除 Open the Delete Table wizard, where you can select a database table to be dropped. 削除ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠžã§ãã‚‹ã€ãƒ†ãƒ¼ãƒ–ル削除ウィザードをã²ã‚‰ãã¾ã™ã€‚ &Modify Table... テーブルを変更(&M)... Create &Index... インデックスã®ä½œæˆ(&I)... Open the Create Index wizard, where it is possible to define a new index on an existing database table. 既存ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ†ãƒ¼ãƒ–ãƒ«ã«æ–°ã—ã„インデックスを定義ã§ãã‚‹ã€ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ã‚’é–‹ãã¾ã™ã€‚ &Preferences... 設定(&P)... Open the preferences window. 設定ウィンドウを開ãã¾ã™ã€‚ &DB Toolbar DBツールãƒãƒ¼(&D) Shows or hides the Database toolbar. データベースツールãƒãƒ¼ã‚’表示/éžè¡¨ç¤ºã—ã¾ã™ã€‚ Ctrl+T W&hat's This? ã“れã¯ä½•(&H)? &Database Structure This has to be equal to the tab title in all the main tabs データベース構造(&D) &Browse Data This has to be equal to the tab title in all the main tabs データ閲覧(&B) Edit P&ragmas This has to be equal to the tab title in all the main tabs プラグマ編集(&R) E&xecute SQL This has to be equal to the tab title in all the main tabs SQL実行(&X) &Recent Files 最近使用ã—ãŸãƒ•ァイル(&R) &New Database æ–°ã—ã„データベース(&N) Ctrl+F4 &Undo å…ƒã«æˆ»ã™(&U) Undo last change to the database データベースã¸ã®æœ€å¾Œã®å¤‰æ›´ã‚’å…ƒã«æˆ»ã—ã¾ã™ This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. ã“ã®æ“作ã¯ãƒ‡ãƒ¼ã‚¿é–²è¦§ã‹SQLå®Ÿè¡Œã§æœ€å¾Œã«è¡Œã£ãŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¸ã®å¤‰æ›´ã‚’å…ƒã«æˆ»ã—ã¾ã™ã€‚やり直ã—ã¯ã§ãã¾ã›ã‚“。 Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. 既存ã®ãƒ†ãƒ¼ãƒ–ルåを変更ã§ãるテーブル変更ウィザードを開ãã¾ã™ã€‚ã“れã¯ãƒ†ãƒ¼ãƒ–ルã«å¯¾ã—フィ―ルドã®è¿½åŠ ã‚„å‰Šé™¤ã€ãƒ•ィールドåやデータ型ã®å¤‰æ›´ãŒã§ãã¾ã™ã€‚ Shift+F1 &About DB Browser for SQLite ã«ã¤ã„ã¦(&A) &Recently opened 最近開ã„ãŸãƒ•ァイル(&R) This button opens a new tab for the SQL editor ã“ã®ãƒœã‚¿ãƒ³ã§SQLã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®æ–°ã—ã„タブを開ãã¾ã™ &Execute SQL SQL実行(&E) This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. ã“ã®ãƒœã‚¿ãƒ³ã§ç¾åœ¨é¸æŠžã—ã¦ã„ã‚‹SQL文を実行ã—ã¾ã™ã€‚テキストãŒé¸æŠžã•れã¦ã„ãªã„å ´åˆã€ã™ã¹ã¦ã®SQLæ–‡ãŒå®Ÿè¡Œã•れã¾ã™ã€‚ Ctrl+Shift+T Save SQL file SQLファイルをä¿å­˜ &Load Extension... 拡張を読ã¿è¾¼ã¿(&L)... Execute current line ç¾åœ¨è¡Œã‚’実行 This button executes the SQL statement present in the current editor line ã“ã®ãƒœã‚¿ãƒ³ã¯ç¾åœ¨ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®è¡Œã«ã‚ã‚‹SQL文を実行ã—ã¾ã™ Shift+F5 Export as CSV file CSVファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ Export table as comma separated values file テーブルをカンマ区切りã®ãƒ•ァイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ &Wiki ウィキ(&W) F1 Bug &Report... ãƒã‚°ãƒ¬ãƒãƒ¼ãƒˆ(&R)... Feature Re&quest... æ©Ÿèƒ½ã‚’è¦æ±‚(&Q)... Web&site ウェブサイト(&S) &Donate on Patreon... Patreonã§å¯„付(&D)... &Save Project プロジェクトをä¿å­˜(&S) Save the current session to a file ç¾åœ¨ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚’ファイルã«ä¿å­˜ã—ã¾ã™ Open &Project... プロジェクトを開ã(&P)... Open &Project プロジェクトを開ã(&P) Load a working session from a file 作業中ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚’ファイルã‹ã‚‰èª­ã¿è¾¼ã¿ã¾ã™ &Attach Database... ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«æŽ¥ç¶š(&A)... Add another database file to the current database connection ä»–ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルをç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹æŽ¥ç¶šã«åŠ ãˆã¾ã™ This button lets you add another database file to the current database connection ã“ã®ãƒœã‚¿ãƒ³ã§ä»–ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルをç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹æŽ¥ç¶šã«åŠ ãˆã¾ã™ &Set Encryption... æš—å·åŒ–を設定(&S)... Save SQL file as åå‰ã‚’付ã‘ã¦SQLファイルをä¿å­˜ This button saves the content of the current SQL editor tab to a file ã“ã®ãƒœã‚¿ãƒ³ã¯ç¾åœ¨ã®SQLエディタータブã®å†…容をファイルã«ä¿å­˜ã—ã¾ã™ &Browse Table テーブルを閲覧(&B) Copy Create statement CREATE文をコピー Copy the CREATE statement of the item to the clipboard ã“ã®ã‚¢ã‚¤ãƒ†ãƒ ã®CREATE文をクリップボードã«ã‚³ãƒ”ーã—ã¾ã™ SQLCipher &FAQ SQLCipher FAQ(&F) Opens the SQLCipher FAQ in a browser window SQLCipher ã® FAQ をブラウザã§é–‹ãã¾ã™ Table(&s) to JSON... テーブルをJSONã¸(&S)... Export one or more table(s) to a JSON file 1ã¤ä»¥ä¸Šã®ãƒ†ãƒ¼ãƒ–ルをJSONファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ Open Data&base Read Only... データベースを読ã¿å–り専用ã§é–‹ã(&B)... Open an existing database file in read only mode 既存ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを読ã¿å–り専用モードã§é–‹ãã¾ã™ Save results çµæžœã‚’ä¿å­˜ Save the results view çµæžœã®ãƒ“ューをä¿å­˜ This button lets you save the results of the last executed query ã“ã®ãƒœã‚¿ãƒ³ã§æœ€å¾Œã«å®Ÿè¡Œã—ãŸã‚¯ã‚¨ãƒªãƒ¼ã®çµæžœã‚’ä¿å­˜ã—ã¾ã™ Find text in SQL editor SQLã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®æ–‡å­—列を検索 This button opens the search bar of the editor ã“ã®ãƒœã‚¿ãƒ³ã¯ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®æ¤œç´¢ãƒãƒ¼ã‚’é–‹ãã¾ã™ Ctrl+F Find or replace text in SQL editor SQLã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®æ–‡å­—列を検索/ç½®æ›ã—ã¾ã™ This button opens the find/replace dialog for the current editor tab ã“ã®ãƒœã‚¿ãƒ³ã¯ç¾åœ¨ã®ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã‚¿ãƒ–ã®æ¤œç´¢/ç½®æ›ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ Ctrl+H Export to &CSV CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ(&C) Export to &JSON JSONã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ(&J) Save as &view ビューã¨ã—ã¦ä¿å­˜(&V) Save as view ビューã¨ã—ã¦ä¿å­˜ Shows or hides the Project toolbar. プロジェクトツールãƒãƒ¼ã‚’表示/éžè¡¨ç¤ºã—ã¾ã™ã€‚ Extra DB Toolbar 追加DBツールãƒãƒ¼ &Open Database データベースを開ã(&O) New In-&Memory Database æ–°ã—ã„インメモリーデータベース(&M) Drag && Drop SELECT Query SELECT クエリーをドラッグ&&ドロップ When dragging fields from the same table or a single table, drop a SELECT query into the editor åŒã˜ãƒ†ãƒ¼ãƒ–ルã€ã‚‚ã—ãã¯ã€å˜ç‹¬ã®ãƒ†ãƒ¼ãƒ–ルã‹ã‚‰ãƒ•ィールドをドラッグã™ã‚‹ã¨ã€ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼å†…ã«SELECTクエリーãŒãƒ‰ãƒ­ãƒƒãƒ—ã—ã¾ã™ Drag && Drop Qualified Names æ­£è¦åŒ–åå‰ã‚’ドラッグ&&ドロップ Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor オブジェクトをドラッグã—エディターã«ãƒ‰ãƒ­ãƒƒãƒ—ã—ãŸã¨ãã«ã€æ­£è¦åŒ–åç§°(例 "Table"."Field")を使ã„ã¾ã™ Drag && Drop Enquoted Names クォートã•れãŸåå‰ã‚’ドラッグ&&ドロップ Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor オブジェクトをドラッグã—エディターã«ãƒ‰ãƒ­ãƒƒãƒ—ã—ãŸã¨ãã«ã€ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—ã•れãŸåå‰(例 "Table1")を使ã„ã¾ã™ &Integrity Check æ•´åˆæ€§æ¤œæŸ»(&I) Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ•´åˆæ€§æ¤œæŸ»ãƒ—ラグマを実行ã—ã€çµæžœã‚’SQL実行タブã«å‡ºåŠ›ã—ã¾ã™ã€‚ã“ã®ãƒ—ラグマã¯ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ•´åˆæ€§æ¤œæŸ»ã‚’行ã„ã¾ã™ã€‚ &Foreign-Key Check 外部キー検査(&F) Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab é–‹ã„ã¦ã„るデータベースã®å¤–部キー検査プラグマを実行ã—ã€çµæžœã‚’SQL実行タブã«å‡ºåŠ›ã—ã¾ã™ &Quick Integrity Check 峿™‚æ•´åˆæ€§æ¤œæŸ»(&Q) Run a quick integrity check over the open DB é–‹ã„ã¦ã„ã‚‹DBã®é«˜é€Ÿæ•´åˆæ€§æ¤œæŸ»ã‚’実行ã—ã¾ã™ Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. é–‹ã„ã¦ã„るデータベースã®é«˜é€Ÿæ•´åˆæ€§æ¤œæŸ»ãƒ—ラグマを実行ã—ã€çµæžœã‚’SQL実行タブã«å‡ºåŠ›ã—ã¾ã™ã€‚ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯(通常ã®)æ•´åˆæ€§æ¤œæŸ»PRAGMAã®å¤§éƒ¨åˆ†ã‚’行ã„ã¾ã™ãŒã€ã‚ˆã‚Šé«˜é€Ÿã«å‹•作ã—ã¾ã™ã€‚ &Optimize 最é©åŒ–(&O) Attempt to optimize the database ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æœ€é©åŒ–を試ã¿ã¾ã™ Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æœ€é©åŒ–プラグマを実行ã—ã¾ã™ã€‚ã“ã®ãƒ—ラグマã¯å°†æ¥ã®ã‚¯ã‚¨ãƒªãƒ¼ã®æ€§èƒ½ã‚’改善ã•ã›ã¾ã™ã€‚ Print å°åˆ· Open a dialog for printing the text in the current SQL editor tab ç¾åœ¨ã®SQLã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã‚¿ãƒ–ã®æ–‡å­—列をå°åˆ·ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ Open a dialog for printing the structure of the opened database é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ§‹é€ ã‚’å°åˆ·ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ Ctrl+Shift+W Table from CSV data in Clipboard... クリップボードã®CSVデータã‹ã‚‰ãƒ†ãƒ¼ãƒ–ル... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. ã“ã®å‡¦ç†ã¯ç¾åœ¨ã®ã‚¯ãƒªãƒƒãƒ—ボードã®å†…容をCSVファイルã¨ã¿ãªã—ã¦ã€å®Ÿéš›ã®CSVファイルã¨åŒã˜ã‚ˆã†ã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ã‚’é–‹ãã¾ã™ã€‚ Show &Row Counts 行数を表示(&R) This shows the number of rows for each table and view in the database. データベース内ã«ã‚るテーブルã¨ãƒ“ューãれãžã‚Œã®è¡Œæ•°ã‚’表示ã—ã¾ã™ã€‚ Save Database &As... åå‰ã‚’付ã‘ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ä¿å­˜(&A)... Save the current database as a different file ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’別ã®ãƒ•ァイルã«ä¿å­˜ã—ã¾ã™ Refresh æ›´æ–° Reload the database structure データベース構造をå†èª­ã¿è¾¼ã¿ Ctrl+P Execute all/selected SQL ã™ã¹ã¦/é¸æŠžã—ãŸSQLを実行 Ctrl+Return Ctrl+L Ctrl+D Ctrl+I Ctrl+E Reset Window Layout ウィンドウレイアウトをリセット Ctrl+Tab Ctrl+Shift+Tab Clear List リストを削除 Window Layout ウィンドウレイアウト Ctrl+Alt+0 Simplify Window Layout ウィンドウレイアウトをシンプル㫠Alt+Shift+0 Dock Windows at Bottom ウィンドウを下ã«ãƒ‰ãƒƒã‚­ãƒ³ã‚° Dock Windows at Left Side ウィンドウを左ã«ãƒ‰ãƒƒã‚­ãƒ³ã‚° Dock Windows at Top ウィンドウを上ã«ãƒ‰ãƒƒã‚­ãƒ³ã‚° The database is currently busy. データベースã¯ç¾åœ¨ãƒ“ジー状態ã§ã™ã€‚ Click here to interrupt the currently running query. ã“ã“をクリックã—ã¦ã€ç¾åœ¨å®Ÿè¡Œä¸­ã®ã‚¯ã‚¨ãƒªãƒ¼ã‚’中断ã—ã¾ã™ã€‚ Encrypted æš—å·åŒ– Database is encrypted using SQLCipher データベースã¯SQLCipherã§æš—å·åŒ–ã•れã¦ã„ã¾ã™ Read only 読ã¿å–り専用 Database file is read only. Editing the database is disabled. データベースã¯èª­ã¿å–り専用ã§ã™ã€‚データベースã®ç·¨é›†ã¯ã§ãã¾ã›ã‚“。 Database encoding データベースã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ Ctrl+Alt+W Choose a database file ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž Could not open database file. Reason: %1 データベースファイルを開ã‘ã¾ã›ã‚“。 ç†ç”±: %1 Choose a filename to save under ä¿å­˜ã™ã‚‹ãƒ•ァイルåを下ã‹ã‚‰é¸æŠž In-Memory database インメモリーデータベース Choose a database file to save under ä¿å­˜ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを下ã‹ã‚‰é¸æŠž Error while saving the database to the new file. データベースを新ã—ã„ファイルã¸ä¿å­˜æ™‚ã«ã‚¨ãƒ©ãƒ¼ã€‚ You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? ã¾ã SQL文を実行中ã§ã™ã€‚今ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é–‰ã˜ã‚‹ã¨ã€å®Ÿè¡ŒãŒä¸­æ­¢ã•れã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ä¸€è²«æ€§ãŒãªã„状態を残ã™ã‹ã‚‚ã—れã¾ã›ã‚“。本当ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é–‰ã˜ã¾ã™ã‹? Edit View %1 ビューを編集 %1 Edit Trigger %1 トリガーを編集 %1 Opened '%1' in read-only mode from recent file list 最近使ã£ãŸãƒ•ァイルリストã‹ã‚‰èª­ã¿å–り専用モード㧠'%1' ã‚’é–‹ãã¾ã—㟠Opened '%1' from recent file list 最近使ã£ãŸãƒ•ァイルリストã‹ã‚‰ '%1' ã‚’é–‹ãã¾ã—㟠Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. ドロップã•れãŸãƒ•ァイルã«å¯¾ã—ã¦è¡Œã†æ“ä½œã‚’é¸æŠžã—ã¦ãã ã•ã„。 <br/>注æ„: 'インãƒãƒ¼ãƒˆ' ã®ã¿ãŒè¤‡æ•°ãƒ•ァイルを処ç†ã§ãã¾ã™ã€‚ The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? タブ '%1' ã®æ–‡ã¯ã¾ã å®Ÿè¡Œä¸­ã§ã™ã€‚タブを閉ã˜ã‚‹ã¨å®Ÿè¡ŒãŒåœæ­¢ã—ã¾ã™ã€‚ã“れã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ä¸€è²«æ€§ãŒãªããªã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚本当ã«ã‚¿ãƒ–ã‚’é–‰ã˜ã¾ã™ã‹? Could not find resource file: %1 リソースファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“: %1 DB file '%1' could not be opened DBファイル '%1' ã‚’é–‹ã‘ã¾ã›ã‚“ã§ã—㟠This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. ã“ã®ãƒ—ロジェクトファイルã¯DB Browser for SQLite ãƒãƒ¼ã‚¸ãƒ§ãƒ³ 3.10 以å‰ã§ä½œã‚‰ã‚ŒãŸå¤ã„ファイルフォーマットを使用ã—ã¦ã„ã¾ã™ã€‚ã“ã®ãƒ•ァイルフォーマットã®èª­ã¿è¾¼ã¿ã¯æ—¢ã«å®Œå…¨ã«ã¯ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“。もã—完全ã«èª­ã¿è¾¼ã¿ãŸã„å ´åˆã¯ã€DB Browser for SQLite ãƒãƒ¼ã‚¸ãƒ§ãƒ³3.12 を使ã£ã¦æ–°ã—ã„ファイルフォーマットã«å¤‰æ›ã—ã¦ãã ã•ã„。 Table '%1' not found; settings ignored テーブル '%1' ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“; 設定ã¯ç„¡è¦–ã•れã¾ã™ Could not open project file for writing. Reason: %1 書ã込むプロジェクトファイルを開ãã“ã¨ãŒã§ãã¾ã›ã‚“。 ç†ç”±: %1 -- Reference to file "%1" (not supported by this version) -- -- ファイル "%1" ã¸ã®å‚ç…§ (ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“) -- Project saved to file '%1' プロジェクトをファイル '%1' ã«ä¿å­˜ã—ã¾ã—㟠Yes. Don't ask again ã¯ã„。もã†èžã‹ãªã„ã§ This action will open a new SQL tab with the following statements for you to edit and run: ã“ã®æ“作ã¯ä»¥ä¸‹ã®æ–‡ã‚’編集実行ã§ãã‚‹æ–°ã—ã„SQLタブを開ãã¾ã™: Busy (%1) ビジー (%1) Rename Tab タブåを変更 Duplicate Tab タブを複製 Close Tab タブを閉ã˜ã‚‹ Opening '%1'... '%1' ã‚’é–‹ã„ã¦ã„ã¾ã™... There was an error opening '%1'... '%1' ã‚’é–‹ãã¨ãã«ã‚¨ãƒ©ãƒ¼ãŒã‚りã¾ã—ãŸ... Value is not a valid URL or filename: %1 å€¤ã¯æ­£è¦ã®URLã‚‚ã—ãã¯ãƒ•ァイルåã§ã‚りã¾ã›ã‚“: %1 Are you sure you want to delete the table '%1'? All data associated with the table will be lost. 本当ã«ãƒ†ãƒ¼ãƒ–ル '%1' を削除ã—ã¾ã™ã‹? テーブルã«é–¢é€£ã™ã‚‹ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã¯å¤±ã‚れã¾ã™ã€‚ Are you sure you want to delete the view '%1'? 本当ã«ãƒ“ュー '%1' を削除ã—ã¾ã™ã‹? Are you sure you want to delete the trigger '%1'? 本当ã«ãƒˆãƒªã‚¬ãƒ¼ '%1' を削除ã—ã¾ã™ã‹? Are you sure you want to delete the index '%1'? 本当ã«ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ '%1' を削除ã—ã¾ã™ã‹? Error: could not delete the table. エラー: テーブルを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ Error: could not delete the view. エラー: ビューを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ Error: could not delete the trigger. エラー: トリガーを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ Error: could not delete the index. エラー: インデックスを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ Message from database engine: %1 データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã€‚ %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? テーブルã®ç·¨é›†ã«ã¯ä¿ç•™ä¸­ã®ã™ã¹ã¦ã®å¤‰æ›´ã‚’今ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ 本当ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ä¿å­˜ã—ã¾ã™ã‹? Error checking foreign keys after table modification. The changes will be reverted. デーブル変更後ã®å¤–部キー検査ã§ã‚¨ãƒ©ãƒ¼ã€‚変更ã¯å…ƒã«æˆ»ã‚Šã¾ã™ã€‚ This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. ã“ã®ãƒ†ãƒ¼ãƒ–ルã¯å¤–部キー検査ã«åˆæ ¼ã—ã¾ã›ã‚“ã§ã—ãŸã€‚<br/>'ツール | 外部キー検査' を実行ã—ã€å ±å‘Šã•れãŸå•題を解決ã—ã¾ã™ã€‚ You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. SQLæ–‡ã¯æ—¢ã«å®Ÿè¡Œä¸­ã§ã™ã€‚替ã‚りã«ç¾åœ¨ã®æ–‡ã‚’実行ã™ã‚‹ãŸã‚ã€ä¸­æ­¢ã—ã¾ã™ã‹? 注æ„: ã“れã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ä¸€è²«æ€§ãŒãªã„状態を残ã™ã‹ã‚‚ã—れã¾ã›ã‚“。 -- EXECUTING SELECTION IN '%1' -- -- '%1 内ã®é¸æŠžéƒ¨åˆ†ã‚’実行中' -- -- EXECUTING LINE IN '%1' -- -- '%1 内ã®è¡Œã‚’実行中' -- -- EXECUTING ALL IN '%1' -- -- '%1 内をã™ã¹ã¦å®Ÿè¡Œä¸­' -- Result: %1 çµæžœ: %1 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? PRAGMA 値ã®è¨­å®šã‚„ãƒã‚­ãƒ¥ãƒ¼ãƒ ã¯ç¾åœ¨ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã‚’コミットã—ã¾ã™ã€‚ 本当ã«è¡Œã„ã¾ã™ã‹? %1 rows returned in %2ms %1 行㌠%2ms ã§è¿”ã•れã¾ã—㟠At line %1: %1 行目: Result: %2 çµæžœ: %2 Choose text files ãƒ†ã‚­ã‚¹ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 データベースã®ä¿å­˜ä¸­ã«ã‚¨ãƒ©ãƒ¼ã€‚ã“れã¯å…¨ã¦ã®å¤‰æ›´ãŒãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ä¿å­˜ã•れã¦ã„ãªã‹ã£ãŸãŸã‚ã§ã™ã€‚ã¾ãšã€ä»¥ä¸‹ã®ã‚¨ãƒ©ãƒ¼ã‚’解決ã—ã¦ãã ã•ã„。 %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? 本当ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイル '%1' ã¸ã®æœ€å¾Œã®ä¿å­˜å¾Œã«è¡Œã‚れãŸã™ã¹ã¦ã®å¤‰æ›´ã‚’å…ƒã«æˆ»ã—ã¾ã™ã‹? Choose a file to import インãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž &%1 %2%3 &%1 %2%3 (read only) (読ã¿å–り専用) Open Database or Project データベース化プロジェクトを開ã Attach Database... ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«æŽ¥ç¶š... Import CSV file(s)... CSVファイルをインãƒãƒ¼ãƒˆ... Do you want to save the changes made to SQL tabs in a new project file? æ–°ã—ã„プロジェクトファイルã«SQLタブã§è¡Œã‚れãŸå¤‰æ›´ã‚’ä¿å­˜ã—ã¾ã™ã‹? Do you want to save the changes made to SQL tabs in the project file '%1'? プロジェクトファイル '%1' ã«SQLタブã§è¡Œã‚れãŸå¤‰æ›´ã‚’ä¿å­˜ã—ã¾ã™ã‹? Do you want to save the changes made to the SQL file %1? 変更をSQLファイル %1 ã«ä¿å­˜ã—ã¾ã™ã‹? Text files(*.sql *.txt);;All files(*) テキストファイル(*.sql *.txt);;ã™ã¹ã¦ã®ãƒ•ァイル(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. インãƒãƒ¼ãƒˆã—ãŸãƒ‡ãƒ¼ã‚¿ã‚’ä¿æŒã™ã‚‹æ–°ã—ã„データベースを作æˆã—ã¾ã™ã‹ ã„ã„ãˆã‚’é¸æŠžã™ã‚‹ã¨ã€SQLファイルã‹ã‚‰ã®ãƒ‡ãƒ¼ã‚¿ã‚’ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã—よã†ã¨ã—ã¾ã™ã€‚ Automatically load the last opened DB file at startup 最後ã«é–‹ã„ãŸDBファイルを起動時ã«è‡ªå‹•çš„ã«èª­ã¿è¾¼ã‚€ Do you want to save the changes made to the project file '%1'? プロジェクトファイル '%1' ã«å¤‰æ›´ã‚’ä¿å­˜ã—ã¾ã™ã‹? Execution finished with errors. エラーãŒã‚りã¾ã™ãŒã€å®Ÿè¡ŒãŒçµ‚了ã—ã¾ã—ãŸã€‚ Execution finished without errors. エラーãªã—ã§å®Ÿè¡ŒãŒçµ‚了ã—ã¾ã—ãŸã€‚ File %1 already exists. Please choose a different name. ファイル %1 ã¯æ—¢ã«å­˜åœ¨ã—ã¦ã„ã¾ã™ã€‚é•ã†åå‰ã‚’é¸ã‚“ã§ãã ã•ã„。 Error importing data: %1 データã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã§ã‚¨ãƒ©ãƒ¼: %1 Import completed. Some foreign key constraints are violated. Please fix them before saving. インãƒãƒ¼ãƒˆãŒçµ‚了ã—ã¾ã—ãŸã€‚ã„ãã¤ã‹ã®å¤–部キー制約ã«é•åãŒã‚りã¾ã™ã€‚ä¿å­˜å‰ã«ä¿®æ­£ã—ã¦ãã ã•ã„。 Import completed. インãƒãƒ¼ãƒˆå®Œäº†ã€‚ Delete View ビューを削除 Modify View ビューを変更 Delete Trigger トリガーを削除 Modify Trigger トリガーを変更 Delete Index インデックスを削除 Modify Index インデックスを変更 Modify Table テーブルを変更 Setting PRAGMA values will commit your current transaction. Are you sure? PRAGMA 値ã®è¨­å®šã¯ç¾åœ¨ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã‚’コミットã—ã¾ã™ã€‚ 本当ã«è¡Œã„ã¾ã™ã‹? Select SQL file to open é–‹ãSQLãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž Select file name ファイルåã‚’é¸æŠž Select extension file æ‹¡å¼µãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž Extension successfully loaded. æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã«æˆåŠŸã—ã¾ã—ãŸã€‚ Error loading extension: %1 æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã§ã‚¨ãƒ©ãƒ¼: %1 Don't show again 二度ã¨è¡¨ç¤ºã—ãªã„ New version available. æ–°ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒã‚りã¾ã™ã€‚ A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. æ–°ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã® DB Browser for SQLite (%1.%2.%3)ãŒã‚りã¾ã™ã€‚<br/><br/><a href='%4'>%4</a>ã‹ã‚‰ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ã¦ãã ã•ã„。 Choose a project file to open é–‹ããƒ—ãƒ­ã‚¸ã‚§ã‚¯ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž DB Browser for SQLite project file (*.sqbpro) DB Browser for SQLite プロジェクトファイル (*.sqbpro) Collation needed! Proceed? ç…§åˆé †åºãŒå¿…è¦ã§ã™!続行ã—ã¾ã™ã‹? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚るテーブルã¯ç‰¹åˆ¥ãªç…§åˆé †åºé–¢æ•° '%1' ãŒå¿…è¦ã§ã™ãŒã€ã“ã®ã‚¢ãƒ—ãƒªã‚±ãƒ¼ã‚·ãƒ§ãƒ³ã¯æ›´ãªã‚‹çŸ¥è­˜ãªã—ã§ã¯æä¾›ã§ãã¾ã›ã‚“。 続行ã™ã‚‹ã¨ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ä½•ã‹æ‚ªã„ã“ã¨ãŒã‚ã‚‹ã‹ã‚‚ã—れã¾ã›ã‚“。 ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を作æˆã—ã¦ãã ã•ã„! creating collation ç…§åˆé †åºã®ä½œæˆä¸­ Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. SQLã‚¿ãƒ–ã«æ–°ã—ã„åå‰ã‚’設定ã—ã¦ãã ã•ã„。'&&'ã®æ–‡å­—を使ã†ã¨ã€ãã®æ¬¡ã®æ–‡å­—をキーボードショートカットã«ã§ãã¾ã™ã€‚ Please specify the view name ビューã®åå‰ã‚’指定ã—ã¦ãã ã•ã„ There is already an object with that name. Please choose a different name. ãã®åå‰ã®ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™ã€‚別ã®åå‰ã‚’é¸ã‚“ã§ãã ã•ã„。 View successfully created. ビューã®ä½œæˆã«æˆåŠŸã—ã¾ã—ãŸã€‚ Error creating view: %1 ビューã®ä½œæˆã§ã‚¨ãƒ©ãƒ¼: %1 This action will open a new SQL tab for running: ã“ã®æ“作ã¯å®Ÿè¡Œã®ãŸã‚æ–°ã—ã„SQLタブを開ãã¾ã™: Press Help for opening the corresponding SQLite reference page. ヘルプを押ã™ã¨ã€å¯¾å¿œã™ã‚‹ SQLite ã®ãƒªãƒ•ァレンスページを開ãã¾ã™ã€‚ NullLineEdit Set to NULL NULL ã«è¨­å®š Alt+Del PlotDock Plot プロット <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>ã“ã®ãƒšã‚¤ãƒ³ã¯ç¾åœ¨é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã‹ç›´å‰ã«å®Ÿè¡Œã—ãŸã‚¯ã‚¨ãƒªãƒ¼ã®ã‚«ãƒ©ãƒ ã®ä¸€è¦§ã‚’表示ã—ã¾ã™ã€‚下ã®ãƒ—ロットペインã§Xã‚‚ã—ãã¯Y軸ã¨ã—ã¦ä½¿ç”¨ã•ã‚Œã‚‹ã‚«ãƒ©ãƒ ã‚’é¸æŠžã§ãã¾ã™ã€‚表ã¯çµæžœã®ãƒ—ロットã«ä½¿ç”¨ã§ãる軸ã®ç¨®é¡žã‚’表示ã—ã¾ã™ã€‚Y軸ã«ã¯æ•°å€¤ã®ã‚«ãƒ©ãƒ ã®ã¿é¸æŠžã§ãã¾ã™ãŒã€X軸ã«ã¯ã“れらãŒé¸æŠžã§ãã¾ã™:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日時</span>: &quot;yyyy-MM-dd hh:mm:ss&quot; ã‚‚ã—ã㯠&quot;yyyy-MM-ddThh:mm:ss&quot; å½¢å¼ã®æ–‡å­—列</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日付</span>: &quot;yyyy-MM-dd&quot; å½¢å¼ã®æ–‡å­—列</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">時刻</span>: &quot;hh:mm:ss&quot; å½¢å¼ã®æ–‡å­—列</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ラベル</span>: ãã®ä»–ã®å½¢å¼ã®æ–‡å­—列。ã“れをX軸ã«é¸æŠžã™ã‚‹ã¨ã€ã‚«ãƒ©ãƒ ã®å€¤ã‚’棒グラフã®ãƒ©ãƒ™ãƒ«ã¨ã—ã¦è¡¨ç¤ºã—ã¾ã™</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">数値</span>: INTEGER ã‹ REAL ã®å€¤</li></ul><p>Yã®ã‚»ãƒ«ã‚’ダブルクリックã™ã‚‹ã¨ã€ã‚°ãƒ©ãƒ•ã«ä½¿ç”¨ã™ã‚‹è‰²ã‚’変更ã§ãã¾ã™ã€‚</p></body></html> Columns カラム X X Y1 Y1 Y2 Y2 Axis Type 軸ã®ãƒ‡ãƒ¼ã‚¿åž‹ Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. 上ã§Xã¨Yè»¸ã‚’é¸æŠžã™ã‚‹ã¨ã€ã“ã“ã«ã‚°ãƒ©ãƒ•ãŒæç”»ã•れã¾ã™ã€‚ 点をクリックã™ã‚‹ã¨ã€ç‚¹ã¨è©²å½“ã™ã‚‹ãƒ†ãƒ¼ãƒ–ルã®å€¤ãŒé¸æŠžã§ãã¾ã™ã€‚Ctrl+クリックã§ç‚¹ã‚’ç¯„å›²é¸æŠžã§ãã¾ã™ã€‚ マウスホイールã§ã‚ºãƒ¼ãƒ ã€ãƒ‰ãƒ©ãƒƒã‚°ã§è»¸ã®ç¯„囲を変更ã§ãã¾ã™ã€‚ 軸ã‹è»¸ã®ãƒ©ãƒ™ãƒ«ã‚’é¸æŠžã™ã‚‹ã¨ã€ã‚ºãƒ¼ãƒ ã‚„ãƒ‰ãƒ©ãƒƒã‚°ã®æ–¹å‘ã‚’é™å®šã§ãã¾ã™ã€‚ Line type: ç·šã®ç¨®é¡ž: None ãªã— Line ç›´ç·š StepLeft 階段(左値) StepRight 階段(å³å€¤) StepCenter 階段(最近値) Impulse インパルス Point shape: 点ã®å½¢çж: Cross × Plus + Circle â—‹ Disc â— Square â–¡ Diamond â—‡ Star * Triangle â–³ TriangleInverted â–½ CrossSquare ×+â–¡ PlusSquare ++â–¡ CrossCircle ×+â—‹ PlusCircle ++â—‹ Peace é™è¬ <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>ç¾åœ¨ã®ãƒ—ロットをä¿å­˜...</p><p>ãƒ•ã‚¡ã‚¤ãƒ«ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã¯æ‹¡å¼µå­ (png, jpg, pdf, bmp) ã‹ã‚‰é¸æŠžã•れã¾ã™</p></body></html> Save current plot... ç¾åœ¨ã®ãƒ—ロットをä¿å­˜... Load all data and redraw plot ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿å†æç”» Copy コピー Print... å°åˆ·... Show legend 凡例を表示 Stacked bars 値をç©ã¿é‡ã­ã‚‹ Fixed number format å›ºå®šã®æ•°å€¤ãƒ•ォーマット Date/Time 日時 Date 日付 Time 時刻 Numeric 数値 Label ラベル Invalid 䏿­£ Row # 行 # Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿å†æç”»ã—ã¾ã™ã€‚ 警告: 部分的ãªãƒ•ã‚§ãƒƒãƒæ©Ÿæ§‹ã«ã‚ˆã‚Šã€ã¾ã ãƒ†ãƒ¼ãƒ–ルã‹ã‚‰ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãŒãƒ•ェッãƒã•れã¦ã„ã‚‹ã‚ã‘ã§ã¯ã‚りã¾ã›ã‚“。 Choose an axis color 軸ã®è‰²ã‚’é¸æŠž Choose a filename to save under ä¿å­˜ã™ã‚‹ãƒ•ァイルåを下ã‹ã‚‰é¸æŠž PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;ã™ã¹ã¦ã®ãƒ•ァイル(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. ã“ã®ãƒ—ロットã«ã¯æœªã‚½ãƒ¼ãƒˆãªãƒ‡ãƒ¼ã‚¿ãŒã‚りã¾ã™ã€‚é¸æŠžã—ãŸç·šã®ç¨®é¡žã¯X軸ã§ã‚½ãƒ¼ãƒˆã•れãŸãƒ‡ãƒ¼ã‚¿ã®ã¿ã«é©ç”¨ã§ãã¾ã™ã€‚テーブルやクエリーをX軸ã§ã‚½ãƒ¼ãƒˆã™ã‚‹ã‹ã€æœªã‚½ãƒ¼ãƒˆã®ãƒ‡ãƒ¼ã‚¿ã§ã‚‚使用ã§ãる〠ãªã— ã‚„ ç›´ç·š å½¢å¼ã‚’é¸æŠžã—ã¦ãã ã•ã„。 Loading all remaining data for this table took %1ms. ã“ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã®æ®‹ã£ã¦ã„るデータã™ã¹ã¦ã®èª­ã¿è¾¼ã¿ã« %1ms ã‹ã‹ã‚Šã¾ã—ãŸã€‚ PreferencesDialog Preferences 設定 &General 全般(&G) Default &location デフォルトã®ãƒ•ォルダー(&L) Remember last location 最後ã«ä½¿ç”¨ã—ãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’記憶 Always use this location 常ã«ã“ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’使用 Remember last location for session only セッションã ã‘ã§æœ€å¾Œã«ä½¿ç”¨ã—ãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’記憶 ... ... Lan&guage 言語(&L) Toolbar style ツールãƒãƒ¼å½¢å¼ Only display the icon アイコンã®ã¿è¡¨ç¤º Only display the text 文字ã®ã¿è¡¨ç¤º The text appears beside the icon ã‚¢ã‚¤ã‚³ãƒ³ã®æ¨ªã«æ–‡å­—を表示 The text appears under the icon アイコンã®ä¸‹ã«æ–‡å­—を表示 Follow the style スタイルã«å¾“ㆠShow remote options リモートオプションを表示ã™ã‚‹ enabled 有効 Automatic &updates 自動アップデート(&U) DB file extensions DBãƒ•ã‚¡ã‚¤ãƒ«æ‹¡å¼µå­ Manage ç®¡ç† Main Window メインウィンドウ Database Structure データベース構造 Browse Data データ閲覧 Execute SQL SQL実行 Edit Database Cell データベースセル編集 When this value is changed, all the other color preferences are also set to matching colors. ã“ã®å€¤ãŒå¤‰æ›´ã•れるã¨ã€ä»–ã®è‰²è¨­å®šã™ã¹ã¦ã‚‚一致ã™ã‚‹è‰²ã«è¨­å®šã•れã¾ã™ã€‚ Follow the desktop style デスクトップスタイルã«å¾“ㆠDark style ダークスタイル Application style アプリケーションスタイル This sets the font size for all UI elements which do not have their own font size option. ã“れã¯ç‹¬è‡ªã®ãƒ•ォントサイズオプションをæŒãŸãªã„å…¨ã¦ã®UIè¦ç´ ã®ãƒ•ォントサイズを設定ã—ã¾ã™ã€‚ Font size フォントサイズ Max Recent Files ファイル使用履歴最大数 Prompt to save SQL tabs in new project file æ–°ã—ã„プロジェクトファイル㫠SQLタブをä¿å­˜ã™ã‚‹ã¨ãã«å°‹ã­ã‚‹ If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. 有効ã«ã™ã‚‹ã¨ã€SQL編集タブを閉ã˜ã‚‹ã¨ãã«ã€å¤‰æ›´ãŒã‚ã‚‹ã¨ãƒ—ロジェクトä¿å­˜ç¢ºèªãƒ€ã‚¤ã‚¢ãƒ«å…·ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ &Database データベース(&D) Database &encoding データベースã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰(&E) Open databases with foreign keys enabled. 外部キーを有効ã«ã—ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é–‹ã。 &Foreign keys 外部キー(&F) Remove line breaks in schema &view スキーマビューã‹ã‚‰æ”¹è¡Œã‚’å–り除ã(&V) When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. 有効ã«ã™ã‚‹ã¨ã€DB構造タブã®ã‚«ãƒ©ãƒ ã‚¹ã‚­ãƒ¼ãƒžã€ãƒ‰ãƒƒã‚¯ã‚„å°åˆ·ã•れãŸå‡ºåŠ›ã«ã‚る改行ãŒå–り除ã‹ã‚Œã¾ã™ã€‚ Prefetch block si&ze 先読ã¿ãƒ–ロックサイズ(&Z) SQ&L to execute after opening database データベースを開ã„ãŸå¾Œã«å®Ÿè¡Œã™ã‚‹SQL(&L) Default field type デフォルトã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ãƒ‡ãƒ¼ã‚¿å½¢å¼ Database structure font size データベース構造ã®ãƒ•ォントサイズ Data &Browser データ閲覧(&B) Font フォント &Font フォント(&F) Font si&ze フォントサイズ(&Z) Content 内容 Symbol limit in cell セル内ã®ã‚·ãƒ³ãƒœãƒ«ä¸Šé™ This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. ã“れã¯ã„ãã¤ã‹ã®è¨ˆç®—è² è·ã®é«˜ã„機能を有効ã«ã§ãã‚‹é …ç›®ã®æœ€å¤§æ•°ã§ã™ã€‚ カラム内ã®ç¾åœ¨å€¤ã«åŸºã¥ã„ãŸå€¤è£œå®Œã‚’有効ã«ã™ã‚‹ã€ãƒ†ãƒ¼ãƒ–ル内ã®è¡Œã®æœ€å¤§æ•°ã€‚ é¸æŠžå†…ã®åˆè¨ˆã¨å¹³å‡ã‚’計算ã™ã‚‹ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã®æœ€å¤§æ•°ã€‚ 0ã«è¨­å®šã™ã‚‹ã¨ã“ã®æ©Ÿèƒ½ã‚’無効ã«ã§ãã¾ã™ã€‚ This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. ã“れã¯ç¾åœ¨ã®å€¤ã‚’基ã«ã—ãŸã‚«ãƒ©ãƒ ã®å€¤è£œå®Œã‚’有効ã«ã—ãŸã¨ãã®ãƒ†ãƒ¼ãƒ–ル内ã®è¡Œæ•°ã®æœ€å¤§å€¤ã§ã™ã€‚ Field display フィールド表示 Displayed &text 表示ã•れãŸãƒ†ã‚­ã‚¹ãƒˆ(&T) Binary ãƒã‚¤ãƒŠãƒªãƒ¼ NULL NULL Regular 通常 Click to set this color クリックã§ã“ã®è‰²ã‚’設定 Text color 文字色 Background color 背景色 Preview only (N/A) 閲覧ã®ã¿(設定ä¸å¯) Filters フィルター Escape character エスケープ文字 Delay time (&ms) é…延時間 (ms) (&M) Light style ライトスタイル Formatted 整形済㿠Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. æ–°ã—ã„フィルターã®å€¤ãŒé©ç”¨ã•れるå‰ã®å¾…機時間を設定ã—ã¾ã™ã€‚0ã«ã™ã‚‹ã¨å¾…機ã—ã¾ã›ã‚“。 &SQL SQL(&S) Context 内容 Colour 色 Bold 太字 Italic イタリック Underline 下線 Keyword キーワード Function 関数 Table テーブル Comment コメント Identifier è­˜åˆ¥å­ String 文字列 Current line ç¾åœ¨è¡Œ Background 背景 Foreground 剿™¯ Selection background é¸æŠžä¸­èƒŒæ™¯ Selection foreground é¸æŠžä¸­å‰æ™¯ Highlight 強調 SQL editor &font SQLエディターフォント(&F) SQL &editor font size SQLエディターフォントサイズ(&E) SQL &results font size SQLçµæžœãƒ•ォントサイズ(&R) Tab size タブサイズ Use tabs for indentation インデントã«ã‚¿ãƒ–を使ㆠWhen set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. 設定ã™ã‚‹ã¨ã€ã‚¿ãƒ–キーã¯ã‚¤ãƒ³ãƒ‡ãƒ³ãƒˆã«ã‚¿ãƒ–ã¨ç©ºç™½æ–‡å­—を挿入ã—ã¾ã™ã€‚ãã†ã§ãªã‘れã°ã€ç©ºç™½æ–‡å­—ã ã‘を使用ã—ã¾ã™ã€‚ &Wrap lines ワードラップ(&W) Never ã—ãªã„ At word boundaries å˜èªžã§ At character boundaries 文字㧠At whitespace boundaries 空白㧠&Quotes for identifiers 識別å­ã®ã‚¯ã‚©ãƒ¼ãƒˆ(&Q) Choose the quoting mechanism used by the application for identifiers in SQL code. アプリケーションãŒSQLコード内ã§è­˜åˆ¥å­ã‚’クォートã™ã‚‹ä»•組ã¿ã‚’é¸æŠžã—ã¾ã™ã€‚ "Double quotes" - Standard SQL (recommended) "ダブルクォート" - 一般的㪠SQL (推奨) `Grave accents` - Traditional MySQL quotes `グレイヴアクセント` - ä¼çµ±çš„㪠MySQL ã®ã‚¯ã‚©ãƒ¼ãƒˆ [Square brackets] - Traditional MS SQL Server quotes [角括弧] - ä¼çµ±çš„㪠MS SQL Server ã®ã‚¯ã‚©ãƒ¼ãƒˆ Code co&mpletion コード補完(&M) Keywords in &UPPER CASE キーワードを大文字ã«(&U) When set, the SQL keywords are completed in UPPER CASE letters. 設定ã™ã‚‹ã¨ã€SQLキーワードを大文字ã«è£œå®Œã—ã¾ã™ã€‚ Error indicators エラー指摘 When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background 設定ã™ã‚‹ã¨ã€æœ€å¾Œã®å®Ÿè¡Œã§ã‚¨ãƒ©ãƒ¼ãŒèµ·ããŸSQLコードã®è¡ŒãŒå¼·èª¿ã•れã€çµæžœãƒ•レームãŒãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã§ã‚¨ãƒ©ãƒ¼ã‚’指摘ã—ã¾ã™ Hori&zontal tiling 横ã«ä¸¦ã¹ã‚‹(&Z) If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. 有効ã«ã™ã‚‹ã¨ã€é‡ã­ã‚‹ä»£ã‚りã«ã€SQLコードエディターã¨çµæžœã‚¿ãƒ–ビューãŒä¸¦ã‚“ã§è¡¨ç¤ºã•れã¾ã™ã€‚ Close button on tabs タブã«é–‰ã˜ã‚‹ãƒœã‚¿ãƒ³ã‚’表示 If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. 有効ã«ã™ã‚‹ã¨SQL編集タブã«é–‰ã˜ã‚‹ãƒœã‚¿ãƒ³ã‚’表示ã—ã¾ã™ã€‚ã©ã®ã‚ˆã†ãªå ´åˆã§ã‚‚コンテキストメニューやキーボードショートカットã‹ã‚‰ã‚¿ãƒ–ã‚’é–‰ã˜ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ &Extensions æ‹¡å¼µ(&E) Select extensions to load for every database: ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã§èª­ã¿è¾¼ã‚€æ‹¡å¼µã‚’é¸æŠž: Add extension 拡張を追加 Remove extension 拡張を削除 Select built-in extensions to load for every database: ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã§èª­ã¿è¾¼ã‚€ãƒ“ãƒ«ãƒˆã‚¤ãƒ³æ‹¡å¼µã‚’é¸æŠž <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>REGEXP演算å­ãŒã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã‚‹é–“ã€SQLite ã¯æ­£è¦è¡¨ç¾ã‚’実装ã—ã¾ã›ã‚“ãŒã€å®Ÿè¡Œä¸­ã®ã‚¢ãƒ—リケーションをコールãƒãƒƒã‚¯ã—ã¾ã™ã€‚DB Browser for SQLite ã¯ã“れを実装ã—ã¦ã„ã‚‹ã®ã§ã€REGEXP ã‚’ã™ãã«ä½¿ãˆã¾ã™ã€‚ã—ã‹ã—ã€ã“れã«ã¯è¤‡æ•°ã®å®Ÿè£…ãŒã‚りã€ã‚¢ãƒ—リケーションã®å®Ÿè£…を無効ã«ã—拡張を使ã£ã¦ä»–ã®å®Ÿè£…を読ã¿è¾¼ã‚€ã“ã¨ãŒè‡ªç”±ã«ã§ãã¾ã™ã€‚アプリケーションã®å†èµ·å‹•ãŒå¿…è¦ã§ã™ã€‚</p></body></html> Disable Regular Expression extension æ­£è¦è¡¨ç¾æ‹¡å¼µã‚’無効 <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite ã¯å…±æœ‰ãƒ©ã‚¤ãƒ–ラリファイルã‹ã‚‰æ‹¡å¼µã‚’読ã¿è¾¼ã‚€SQL関数をæä¾›ã—ã¾ã™ã€‚SQLコードã‹ã‚‰<span style=" font-style:italic;">load_extension()</span>関数を使ã„ãŸã„ãªã‚‰ã°ã€.ã“れを有効ã«ã—ã¾ã™ã€‚</p><p>セキュリティー上ã®ç†ç”±ã‹ã‚‰ã€æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã¯ãƒ‡ãƒ•ォルトã§ç„¡åйã«ãªã£ã¦ãŠã‚Šã€ä½¿ç”¨ã™ã‚‹ã«ã¯ã“ã®è¨­å®šã‚’有効ã«ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションãŒç„¡åйã§ã‚‚ã€GUIを通ã˜ã¦æ‹¡å¼µã‚’読ã¿è¾¼ã‚€ã“ã¨ã¯å¸¸ã«ã§ãã¾ã™ã€‚</p></body></html> Allow loading extensions from SQL code SQLã‚³ãƒ¼ãƒ‰ã§æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã‚’許å¯ã™ã‚‹ Remote リモート CA certificates èªè¨¼å±€è¨¼æ˜Žæ›¸ Proxy プロキシ Configure 設定 Export Settings 設定をエクスãƒãƒ¼ãƒˆ Import Settings 設定をインãƒãƒ¼ãƒˆ Subject CN 対象CN Common Name Common Name Subject O 対象O Organization Organization Valid from 証明開始 Valid to 証明終了 Serial number ã‚·ãƒªã‚¢ãƒ«ç•ªå· Your certificates ã‚ãªãŸã®è¨¼æ˜Žæ›¸ Threshold for completion and calculation on selection 補完ã¨é¸æŠžç¯„囲内ã®è¨ˆç®—ã®é–¾å€¤ Show images in cell セル内ã«ç”»åƒã‚’表示 Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ã€ã‚»ãƒ«å†…ã®ç”»åƒãƒ‡ãƒ¼ã‚¿ã‚’å«ã‚€ BLOB ã®ãƒ—レビューãŒã§ãã¾ã™ã€‚ã—ã‹ã—ã€ã“れã¯ãƒ‡ãƒ¼ã‚¿é–²è¦§ã®æ€§èƒ½ã«å½±éŸ¿ã—ã¾ã™ã€‚ File ファイル Subject Common Name 対象Common Name Issuer CN 発行者CN Issuer Common Name 発行者Common Name Clone databases into ã“ã“ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’複製 Choose a directory ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’é¸æŠž The language will change after you restart the application. アプリケーションをå†èµ·å‹•ã™ã‚‹ã¨ã€è¨€èªžãŒå¤‰æ›´ã•れã¾ã™ã€‚ Select extension file æ‹¡å¼µãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž Extensions(*.so *.dylib *.dll);;All files(*) æ‹¡å¼µ(*.so *.dylib *.dll);;ã™ã¹ã¦ã®ãƒ•ァイル(*) Import certificate file 証明書ファイルをインãƒãƒ¼ãƒˆ No certificates found in this file. ã“ã®ãƒ•ァイルã«è¨¼æ˜Žæ›¸ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。 Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! 本当ã«ã“ã®è¨¼æ˜Žæ›¸ã‚’削除ã—ã¾ã™ã‹? ã™ã¹ã¦ã®è¨¼æ˜Žæ›¸ãƒ‡ãƒ¼ã‚¿ã¯ã“ã®ã‚¢ãƒ—リケーション設定ã‹ã‚‰å‰Šé™¤ã•れã¾ã™! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. 本当ã«ä¿å­˜ã•れãŸè¨­å®šã‚’削除ã—ã¾ã™ã‹? ã™ã¹ã¦ã®è¨­å®šã¯å¤±ã‚れã€ãƒ‡ãƒ•ォルト値ãŒä½¿ç”¨ã•れã¾ã™ã€‚ Save Settings File 設定ファイルをä¿å­˜ Initialization File (*.ini) INIファイル (*.ini) The settings file has been saved in location : 設定ファイルをã“ã“ã«ä¿å­˜ã—ã¾ã—ãŸ: Open Settings File 設定ファイルを開ã The settings file was loaded properly. è¨­å®šãƒ•ã‚¡ã‚¤ãƒ«ãŒæ­£ã—ã読ã¿è¾¼ã¾ã‚Œã¾ã—ãŸã€‚ The selected settings file is not a normal settings file. Please check again. é¸æŠžã•れãŸè¨­å®šãƒ•ァイルã«ç•°å¸¸ãŒã‚りã¾ã™ã€‚ å†åº¦ç¢ºèªã—ã¦ãã ã•ã„。 ProxyDialog Proxy Configuration プロキシ設定 Pro&xy Type プロキシタイプ(&X) Host Na&me ホストå(&M) Port ãƒãƒ¼ãƒˆ Authentication Re&quired èªè¨¼ãŒå¿…è¦(&Q) &User Name ユーザーå(&U) Password パスワード None ãªã— System settings システム設定 HTTP HTTP SOCKS5 SOCKS5 QObject All files (*) ã™ã¹ã¦ã®ãƒ•ァイル (*) Error importing data データã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã§ã‚¨ãƒ©ãƒ¼ from record number %1 ãƒ¬ã‚³ãƒ¼ãƒ‰ç•ªå· %1 ã§ . %1 . %1 Importing CSV file... CSVファイルをインãƒãƒ¼ãƒˆä¸­... Cancel キャンセル SQLite database files (*.db *.sqlite *.sqlite3 *.db3) SQLite データベースファイル (*.db *.sqlite *.sqlite3 *.db3) Left å·¦ Right å³ Center 中央 Justify å‡ç­‰ SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) SQLite データベースファイル (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) DB Browser for SQLite プロジェクトファイル (*.sqbpro) SQL Files (*.sql) SQL ファイル (*.sql) All Files (*) ã™ã¹ã¦ã®ãƒ•ァイル (*) Text Files (*.txt) テキストファイル (*.txt) Comma-Separated Values Files (*.csv) カンマ区切りファイル (*.csv) Tab-Separated Values Files (*.tsv) タブ区切りファイル (*.tsv) Delimiter-Separated Values Files (*.dsv) 区切りファイル (*.dsv) Concordance DAT files (*.dat) 用語索引 DAT ファイル (*.dat) JSON Files (*.json *.js) JSONファイル (*.json *.js) XML Files (*.xml) XMLファイル (*.xml) Binary Files (*.bin *.dat) ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ•ァイル (*.bin *.dat) SVG Files (*.svg) SVG ファイル (*.svg) Hex Dump Files (*.dat *.bin) å六進ダンプファイル (*.dat *.bin) Extensions (*.so *.dylib *.dll) æ‹¡å¼µ (*.so *.dylib *.dll) Initialization File (*.ini) INIファイル (*.ini) QsciCommand Paste 貼り付㑠Cancel キャンセル QsciLexerCPP Default デフォルト Keyword キーワード Identifier è­˜åˆ¥å­ QsciLexerJSON Default デフォルト String 文字列 QsciLexerJavaScript Regular expression æ­£è¦è¡¨ç¾ QsciLexerPython Default デフォルト Comment コメント Keyword キーワード Identifier è­˜åˆ¥å­ QsciLexerSQL Default デフォルト Comment コメント Keyword キーワード Identifier è­˜åˆ¥å­ QsciScintilla &Undo å…ƒã«æˆ»ã™(&U) Select All ã™ã¹ã¦é¸æŠž RemoteCommitsModel Commit ID コミットID Message メッセージ Date 日付 Author 作者 Size サイズ Authored and committed by %1 %1 ãŒä½œæˆã€ã‚³ãƒŸãƒƒãƒˆã—ã¾ã—㟠Authored by %1, committed by %2 %1 ãŒä½œæˆ, %2 ãŒã‚³ãƒŸãƒƒãƒˆã—ã¾ã—㟠RemoteDatabase Error opening local databases list. %1 ローカルデータベースã®ä¸€è¦§ã‚’é–‹ãã¨ãã«ã‚¨ãƒ©ãƒ¼ã€‚ %1 Error creating local databases list. %1 ローカルデータベースã®ä¸€è¦§ã®ä½œæˆã§ã‚¨ãƒ©ãƒ¼ã€‚ %1 RemoteDock Remote リモート Identity アイデンティティー Push currently opened database to server ç¾åœ¨é–‹ã„ã¦ã„るデータベースをサーãƒãƒ¼ã«ãƒ—ッシュã—ã¾ã™ Upload アップロード DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>ã“ã®ç”»é¢ã§ã¯ã€dbhub.io ウェブサイトã®ãƒªãƒ¢ãƒ¼ãƒˆãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ DB Browser for SQLite ã«è¿½åŠ ã§ãã¾ã™ã€‚最åˆã«èªè¨¼ãŒå¿…è¦ã§ã™:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dbhub.io ã«ãƒ­ã‚°ã‚¤ãƒ³ (GitHub èªè¨¼ã‹ã‚ãªãŸã®æœ›ã‚€ã‚‚ã®ã‚’使ã„ã¾ã™)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).&quot;Generate client certificate&quot ボタンをクリック; (ã“れãŒã‚ãªãŸã®èªè¨¼æƒ…å ±ã§ã™) ã“れã§è¨¼æ˜Žæ›¸ãƒ•ァイルãŒå…¥æ‰‹ã§ãã¾ã™(ã“れをã‚ãªãŸã®ãƒ­ãƒ¼ã‚«ãƒ«ãƒ‡ã‚£ã‚¹ã‚¯ã«ä¿å­˜ã—ã¾ã™)。</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DB Browser for SQLite ã®è¨­å®šã«ã‚るリモートタブã¸ç§»å‹•ã—ã¾ã™ã€‚ボタンをクリックã€ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ãŸè¨¼æ˜Žæ›¸ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠžã—〠DB Browser for SQLite ã«æ–°ã—ã„èªè¨¼æƒ…報を追加ã—ã¾ã™ã€‚</li></ol><p>ã“れã§ãƒªãƒ¢ãƒ¼ãƒˆãƒ‘ãƒãƒ«ã«ã‚ãªãŸã®èªè¨¼æƒ…å ±ãŒè¡¨ç¤ºã•れã€ã‚Šã‚‚ーã¨ã§ãƒ¼ãŸã¹ãƒ¼ã™ãŒã¤ã„ã‹ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚</p></body></html> Local ローカル Current Database ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ Clone クローン Branch ブランムCommits コミット Commits for ã“れã«ã‚³ãƒŸãƒƒãƒˆ Delete Database データベースを削除 Delete the local clone of this database ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚¯ãƒ­ãƒ¼ãƒ³ã‚’削除 Open in Web Browser ウェブブラウザーã§é–‹ã Open the web page for the current database in your browser ブラウザã§ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ã‚¦ã‚§ãƒ–ページを開ã Clone from Link リンクã‹ã‚‰ã‚¯ãƒ­ãƒ¼ãƒ³ Use this to download a remote database for local editing using a URL as provided on the web page of the database. データベースã®ã‚¦ã‚§ãƒ–ãƒšãƒ¼ã‚¸ã§æä¾›ã•れるURLを使ã£ã¦ã€ãƒ­ãƒ¼ã‚«ãƒ«ç·¨é›†ç”¨ã®ãƒªãƒ¢ãƒ¼ãƒˆãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ダウンロードã™ã‚‹ã«ã¯ã€ã“れを使ã„ã¾ã™ã€‚ Refresh æ›´æ–° Reload all data and update the views å…¨ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’å†èª­ã¿è¾¼ã¿ã—ビューを更新ã™ã‚‹ Clone Database データベースをクローン Open Database データベースを開ã Open the local copy of this database ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚³ãƒ”ーを開ã Check out Commit コミットをãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆ Download and open this specific commit ã“ã®ç‰¹å®šã®ã‚³ãƒŸãƒƒãƒˆã‚’ダウンロードã—é–‹ã Check out Latest Commit 最新ã®ã‚³ãƒŸãƒƒãƒˆã‚’ãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆ Check out the latest commit of the current branch ç¾åœ¨ã®ãƒ–ランãƒã®æœ€æ–°ã®ã‚³ãƒŸãƒƒãƒˆã‚’ãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆ Save Revision to File リヴィジョンをファイルã«ä¿å­˜ Saves the selected revision of the database to another file データベースã®é¸æŠžã—ãŸãƒªãƒ´ã‚£ã‚¸ãƒ§ãƒ³ã‚’ã»ã‹ã®ãƒ•ァイルã«ä¿å­˜ Upload Database データベースをアップロード Upload this database as a new commit ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’æ–°ã—ã„コミットã¨ã—ã¦ã‚¢ãƒƒãƒ—ロード <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>ã‚ãªãŸã¯ç¾åœ¨çµ„ã¿è¾¼ã¿ã®èª­ã¿è¾¼ã¿å°‚用ã®ã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãƒ¼ã‚’使用ã—ã¦ã„ã¾ã™ã€‚ã‚ãªãŸã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’アップロードã™ã‚‹ã«ã¯ã€ã‚ãªãŸã® DBHub.io アカウントを設定ã—使ã†å¿…è¦ãŒã‚りã¾ã™ã€‚</p><p>DBHub.io ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒã¾ã ãªã„? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">今ã™ãアカウントを作り</span></a>ã€ã‚ãªãŸã®è¨¼æ˜Žæ›¸ã‚’<a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">ã“ã“ã‹ã‚‰</span></a>インãƒãƒ¼ãƒˆã—ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’共有ã—ã¦ãã ã•ã„。</p><p>オンラインã®ãƒ˜ãƒ«ãƒ—ã¯<a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">ã“ã“</span></a>を見ã¦ãã ã•ã„。</p></body></html> &User ユーザー(&U) &Database データベース(&D) Back 戻る Select an identity to connect 接続ã™ã‚‹ã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãƒ¼ã‚’é¸æŠž Public 公開 This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. ã“れã¯ãƒ­ãƒ¼ã‚«ãƒ«ç·¨é›†ç”¨ã«ãƒªãƒ¢ãƒ¼ãƒˆã‚µãƒ¼ãƒãƒ¼ã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ダウンロードã—ã¾ã™ã€‚ クローン元ã®URLを入力ã—ã¦ãã ã•ã„。ã“ã®URLã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã® ウェブページã«ã‚ã‚‹ 'Clone Database in DB4S' ボタンを クリックã—ã¦ç”Ÿæˆã§ãã¾ã™ã€‚ Invalid URL: The host name does not match the host name of the current identity. 䏿­£ãªURL: ホストåãŒç¾åœ¨ã®ã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãƒ¼ã®ãƒ›ã‚¹ãƒˆåã¨ä¸€è‡´ã—ã¾ã›ã‚“。 Invalid URL: No branch name specified. 䏿­£ãªURL: ブランãƒåãŒæŒ‡å®šã•れã¦ã„ã¾ã›ã‚“。 Invalid URL: No commit ID specified. 䏿­£ãªURL: コミットIDãŒæŒ‡å®šã•れã¦ã„ã¾ã›ã‚“。 You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? データベースã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚¯ãƒ­ãƒ¼ãƒ³ãŒç·¨é›†ã•れã¦ã„ã¾ã™ã€‚ã“ã®ã‚³ãƒŸãƒƒãƒˆã‚’フェッãƒã™ã‚‹ã¨ãƒ­ãƒ¼ã‚«ãƒ«ã®å¤‰æ›´ãŒç„¡è¦–ã•れã¾ã™ã€‚ 本当ã«å®Ÿè¡Œã—ã¾ã™ã‹? The database has unsaved changes. Are you sure you want to push it before saving? データベースã«ä¿å­˜ã•れã¦ã„ãªã„変更ãŒã‚りã¾ã™ã€‚本当ã«ä¿å­˜å‰ã«ãƒ—ッシュã—ã¾ã™ã‹? The database you are trying to delete is currently opened. Please close it before deleting. 削除ã—よã†ã¨ã—ãŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¯ç¾åœ¨é–‹ã‹ã‚Œã¦ã„ã¾ã™ã€‚削除å‰ã«é–‰ã˜ã¦ãã ã•ã„。 This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? ã“れã¯ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ­ãƒ¼ã‚«ãƒ«ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ã¾ã ã‚³ãƒŸãƒƒãƒˆã—ã¦ã„ãªã„変更ã¨å…±ã«å‰Šé™¤ã—ã¾ã™ã€‚本当ã«ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’削除ã—ã¾ã™ã‹? RemoteLocalFilesModel Name åå‰ Branch ブランムLast modified 最終変更 Size サイズ Commit コミット File ファイル RemoteModel Name åå‰ Commit コミット Last modified 最終変更 Size サイズ Size: サイズ: Last Modified: 最終変更: Licence: ライセンス: Default Branch: デフォルトブランãƒ: RemoteNetwork Choose a location to save the file ファイルをä¿å­˜ã™ã‚‹å ´æ‰€ã‚’é¸æŠž Error opening remote file at %1. %2 %1 ã®ãƒªãƒ¢ãƒ¼ãƒˆãƒ•ァイルを開ãã¨ãã«ã‚¨ãƒ©ãƒ¼. %2 Error: Invalid client certificate specified. エラー: 䏿­£ãªã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆè¨¼æ˜Žæ›¸ãŒæŒ‡å®šã•れã¾ã—ãŸã€‚ Please enter the passphrase for this client certificate in order to authenticate. ã“ã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆè¨¼æ˜Žæ›¸ã‚’確èªã™ã‚‹ãŸã‚パスフレーズを入力ã—ã¦ãã ã•ã„。 Cancel キャンセル Uploading remote database to %1 リモートデータベースをã“ã“ã«ã‚¢ãƒƒãƒ—ロード中 %1 Downloading remote database from %1 リモートデータベースをã“ã“ã‹ã‚‰ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ä¸­ %1 Error: Cannot open the file for sending. エラー: é€ä¿¡ã™ã‚‹ãƒ•ァイルを開ã‘ã¾ã›ã‚“。 RemotePushDialog Push database データベースをプッシュ Database na&me to push to プッシュã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®åå‰(&M) Commit message コミットメッセージ Database licence データベースライセンス Public 公開 Branch ブランムForce push 強制プッシュ Username ユーザーå Database will be public. Everyone has read access to it. データベースを公開ã«ã—ã¾ã™ã€‚ã™ã¹ã¦ã®äººãŒã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚ Database will be private. Only you have access to it. データベースをéžå…¬é–‹ã«ã—ã¾ã™ã€‚ã‚ãªãŸã ã‘ãŒã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚ Use with care. This can cause remote commits to be deleted. 注æ„ã—ã¦ä½¿ç”¨ã—ã¦ãã ã•ã„。ã“れã¯ãƒªãƒ¢ãƒ¼ãƒˆã‚³ãƒŸãƒƒãƒˆãŒå‰Šé™¤ã•れるå¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ RunSql Execution aborted by user 実行ã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã‚ˆã‚Šä¸­æ­¢ã•れã¾ã—㟠, %1 rows affected , %1 行ã«å½±éŸ¿ã‚’与ãˆã¾ã—㟠query executed successfully. Took %1ms%2 クエリーã®å®Ÿè¡Œã«æˆåŠŸã—ã¾ã—ãŸã€‚ %1ms%2 ã‹ã‹ã‚Šã¾ã—㟠executing query 実行クエリー SelectItemsPopup A&vailable 使用å¯èƒ½(&V) Sele&cted é¸æŠžæ¸ˆ(&C) SqlExecutionArea Form フォーム Find previous match [Shift+F3] å‰ã‚’検索 [Shift+F3] Find previous match with wrapping ワードラップ込ã¿ã§å‰ã‚’検索 Shift+F3 The found pattern must be a whole word å˜èªžå˜ä½ã§æ¤œç´¢ã—ã¾ã™ Whole Words å˜èªžå˜ä½ Text pattern to find considering the checks in this frame ã“ã®ãƒ•レームã§ã®ãƒã‚§ãƒƒã‚¯ãƒœãƒƒã‚¯ã‚¹ã‚’考慮ã—ãŸæ¤œç´¢æ–‡å­—列 Find in editor エディター内を検索 The found pattern must match in letter case 大/å°æ–‡å­—を区別ã—ã¾ã™ Case Sensitive 大/å°æ–‡å­—を区別 Find next match [Enter, F3] 次を検索 [Enter, F3] Find next match with wrapping ãƒžãƒƒãƒ”ãƒ³ã‚°ã§æ¬¡ã‚’検索 F3 Interpret search pattern as a regular expression æ­£è¦è¡¨ç¾ã§æ¤œç´¢ <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> URLã®ãŸã‚%ã®æ•°ãŒä¸€è‡´ã—ãªã„。 <html><head/><body><p>設定ã™ã‚‹ã¨ã€æ¤œç´¢æ¡ä»¶ã¯UNIXæ­£è¦è¡¨ç¾ã¨è§£é‡ˆã•れã¾ã™ã€‚以下をå‚ç…§ <a href="https://ja.wikibooks.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE">Wikibooksã®æ­£è¦è¡¨ç¾</a>。</p></body></html> Regular Expression æ­£è¦è¡¨ç¾ Close Find Bar 検索ãƒãƒ¼ã‚’é–‰ã˜ã‚‹ <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>最後ã«å®Ÿè¡Œã—ãŸæ–‡ã®çµæžœã€‚</p><p>ã“ã®ãƒ‘ãƒãƒ«ã‚’折りãŸãŸã‚“ã§ã€<span style=" font-style:italic;">SQL Log</span>ドックã§<span style=" font-style:italic;">ユーザー</span>ã‚’é¸æŠžã—ã¦è¡¨ç¤ºã•ã›ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</p></body></html> This field shows the results and status codes of the last executed statements. ã“ã®ãƒ•ィールドã«ã¯æœ€å¾Œã«å®Ÿè¡Œã—ãŸæ–‡ã®çµæžœã¨ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã‚³ãƒ¼ãƒ‰ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ Results of the last executed statements 最後ã«å®Ÿè¡Œã—ãŸæ–‡ã®çµæžœ Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. ファイル "%1" を読ã‚ã¾ã›ã‚“: %2。 Couldn't save file: %1. ファイルをä¿å­˜ã§ãã¾ã›ã‚“: %1. Your changes will be lost when reloading it! å†èª­ã¿è¾¼ã¿ã™ã‚‹ã¨å¤‰æ›´ãŒå¤±ã‚れã¾ã™! The file "%1" was modified by another program. Do you want to reload it?%2 ファイル "%1" ã¯ä»–ã®ãƒ—ログラムã«ã‚ˆã£ã¦å¤‰æ›´ã•れã¾ã—ãŸã€‚å†èª­ã¿è¾¼ã¿ã—ã¾ã™ã‹?%2 Answer "Yes to All" to reload the file on any external update without further prompting. "ã™ã¹ã¦ã¯ã„"ã‚’é¸æŠžã™ã‚‹ã¨ã€å¤–部ã§è¡Œã‚ã‚ŒãŸæ›´æ–°ã‚’ã€ç¢ºèªã›ãšã«ã™ã¹ã¦å†èª­ã¿è¾¼ã¿ã—ã¾ã™ã€‚ Answer "No to All" to ignore any external update without further prompting. "ã™ã¹ã¦ã„ã„ãˆ"ã‚’é¸æŠžã™ã‚‹ã¨ã€å¤–部ã§è¡Œã‚れãŸå¤‰æ›´ã‚’確èªã›ãšã«ã™ã¹ã¦ç„¡è¦–ã—ã¾ã™ã€‚ Modifying and saving the file will restore prompting. ファイルを変更・ä¿å­˜ã™ã‚‹ã¨ã€ç¢ºèªãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã¯å¾©æ´»ã—ã¾ã™ã€‚ SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) abs(X) 関数ã¯ã€æ•°å€¤ã§ã‚る引数 X ã®çµ¶å¯¾å€¤ã‚’è¿”ã—ã¾ã™ã€‚ () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () changes() 関数ã¯ã€æœ€å¾Œã«æˆåŠŸã—㟠INSERT, DELETE, UPDATE æ–‡ã§ã€å¤‰æ›´ã€æŒ¿å…¥ã€å‰Šé™¤ã•れãŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®è¡Œæ•°ã‚’è¿”ã—ã¾ã™ã€‚ (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) char(X1,X2,...,XN) 関数ã¯ã€ãれãžã‚Œã®æ–‡å­—㌠Unicode 符å·ä½ç½®ã§æ•´æ•°å€¤ X1 ã‹ã‚‰ XN ã‚’æŒã¤æ–‡å­—列を返ã—ã¾ã™ã€‚ (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) coalesce() 関数㯠NULL ã§ãªã„引数ã®ã†ã¡ã€æœ€ã‚‚å·¦ã®å¼•æ•°ã®ã‚³ãƒ”ーを返ã—ã¾ã™ã€‚ã™ã¹ã¦ã®å¼•数㌠NULL ãªã‚‰ã°ã€NULL ã‚’è¿”ã—ã¾ã™ (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) glob(X,Y) é–¢æ•°ã¯æ¬¡ã®å¼ã¨åŒå€¤ã§ã™ã€‚ "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) ifnull() 関数㯠NULL ã§ãªã„引数ã®ã†ã¡ã€æœ€ã‚‚å·¦ã®å¼•æ•°ã®ã‚³ãƒ”ーを返ã—ã¾ã™ã€‚両方ã®å¼•数㌠NULL ãªã‚‰ã°ã€NULL ã‚’è¿”ã—ã¾ã™ã€‚ (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) instr(X,Y) é–¢æ•°ã¯æ–‡å­—列 X 内ã«ã‚る最åˆã®æ–‡å­—列 Y を検索ã—ã€ãã®å‰ã®æ–‡å­—æ•°ã«1を加ãˆãŸå€¤ã‚’è¿”ã—ã¾ã™ã€‚X ã« Y ãŒãªã„å ´åˆã¯0ã‚’è¿”ã—ã¾ã™ã€‚ (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) hex() 関数ã¯å¼•æ•°ã‚’ BLOB ã¨è§£é‡ˆã—ã€ãã®ä¸­èº«ã‚’大文字ã®åå…­é€²æ•°ã®æ–‡å­—列ã¨ã—ã¦è¿”ã—ã¾ã™ã€‚ (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) iif(X,Y,Z) 関数ã¯XãŒçœŸãªã‚‰ã°Yã‚’ã€ãã†ã§ãªã‘れã°Zã‚’è¿”ã—ã¾ã™ã€‚ () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () last_insert_rowid() 関数ã¯ã€ã“ã®é–¢æ•°ã‚’呼ã³å‡ºã—ãŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹æŽ¥ç¶šãŒæœ€å¾Œã« INSERT ã—ãŸè¡Œã® ROWID ã‚’è¿”ã—ã¾ã™ã€‚ (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) 文字列 X ã«å¯¾ã—ã€length(X) 関数ã¯ã€æœ€åˆã® NULL 文字ã®å‰ã«ã‚る文字数(ãƒã‚¤ãƒˆæ•°ã§ãªã)ã‚’è¿”ã—ã¾ã™ã€‚ (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) like() 関数㯠"Y LIKE X" å¼ã¨åŒå€¤ã§ã™ã€‚ (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) like() 関数㯠"Y LIKE X ESCAPE Z" å¼ã¨åŒå€¤ã§ã™ã€‚ (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) load_extension(X) 関数ã¯ã€åå‰ãŒ X ã®å…±æœ‰ãƒ©ã‚¤ãƒ–ラリã‹ã‚‰ã™ãã« SQLite 拡張を読ã¿è¾¼ã¿ã¾ã™ã€‚. ã“ã®é–¢æ•°ã®ä½¿ç”¨ã«ã¯ã€è¨­å®šãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‹ã‚‰ã®èªè¨¼ãŒå¿…è¦ã§ã™ã€‚ (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X) load_extension(X,Y) 関数ã¯ã€åå‰ãŒ X ã®å…±æœ‰ãƒ©ã‚¤ãƒ–ラリã®ã‚¨ãƒ³ãƒˆãƒªãƒ¼ãƒã‚¤ãƒ³ãƒˆ Y ã‹ã‚‰ã™ãã« SQLite 拡張を読ã¿è¾¼ã¿ã¾ã™ã€‚. ã“ã®é–¢æ•°ã®ä½¿ç”¨ã«ã¯ã€è¨­å®šãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‹ã‚‰ã®èªè¨¼ãŒå¿…è¦ã§ã™ã€‚ (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) lower(X) 関数ã¯ã€ã™ã¹ã¦ ASCII 文字ã§ã‚る文字列 X ã‚’ã€ã™ã¹ã¦å°æ–‡å­—ã«å¤‰æ›ã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) 関数ã¯ã€X ã®å·¦ç«¯ã«ã‚る空白をå–り除ãã¾ã™ã€‚ (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) ltrim(X,Y)関数ã¯ã€X ã®å·¦ç«¯ã‹ã‚‰ã€ Y ã«å«ã¾ã‚Œã‚‹æ–‡å­—ã‚’ã™ã¹ã¦å–り除ã„ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) 複数ã®å¼•æ•°ã‚’æŒã¤ max() 関数ã¯å¼•æ•°ã®æœ€å¤§å€¤ã‚’è¿”ã—ã¾ã™ã€‚引数㫠NULL ãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã¯ NULL ã‚’è¿”ã—ã¾ã™ã€‚ (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) 複数ã®å¼•æ•°ã‚’æŒã¤ min() 関数ã¯å¼•æ•°ã®æœ€å°å€¤ã‚’è¿”ã—ã¾ã™ã€‚引数㫠NULL ãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã¯ NULL ã‚’è¿”ã—ã¾ã™ã€‚ (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) nullif(X,Y) 関数ã¯ã€äºŒã¤ã®å¼•æ•°ãŒé•ã†å ´åˆç¬¬ä¸€å¼•æ•°ã‚’ã€åŒã˜å ´åˆã¯ NULL ã‚’è¿”ã—ã¾ã™ã€‚ (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) printf(FORMAT,...) SQL 関数ã¯ã€C言語㮠sqlite3_mprintf() é–¢æ•°ã‚„ã€æ¨™æº–Cライブラリー㮠printf() 関数ã®ã‚ˆã†ã«å‹•作ã—ã¾ã™ã€‚ (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) quote(X) 関数ã¯ã€å¼•æ•°ã‚’SQLæ–‡ã«å«ã‚ã‚‹ã®ã«é©ã—ãŸSQLãƒªãƒ†ãƒ©ãƒ«ã®æ–‡å­—ã«ã—ã¦è¿”ã—ã¾ã™ã€‚ () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () random() 関数ã¯ã€ç¯„囲㌠-9223372036854775808 ã‹ã‚‰ +9223372036854775807 ã®æ•´æ•°ã§ã‚る疑似乱数を返ã—ã¾ã™ã€‚ (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) randomblob(N) 関数ã¯ã€ç–‘ä¼¼ä¹±æ•°ã§æ§‹æˆã•れ㟠N ãƒã‚¤ãƒˆã® BLOB ã‚’è¿”ã—ã¾ã™ã€‚function return an N-byte blob containing pseudo-random bytes. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) replace(X,Y,Z) 関数ã¯ã€æ–‡å­—列 X ã«å«ã¾ã‚Œã‚‹æ–‡å­—列 Y ã‚’ã™ã¹ã¦æ–‡å­—列 Z ã«ç½®ãæ›ãˆã¦è¿”ã—ã¾ã™ã€‚ (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) round(X) 関数ã¯ã€æµ®å‹•å°æ•°ç‚¹æ•° X ã®å°æ•°ç‚¹ä»¥ä¸‹ã‚’å››æ¨äº”å…¥ã—ã¦è¿”ã—ã¾ã™ã€‚ (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) round(X,Y) 関数ã¯ã€æµ®å‹•å°æ•°ç‚¹æ•° X ã‚’å°æ•°ç‚¹ç¬¬ Y ä½ã¾ã§ã«ãªã‚‹ã‚ˆã†ã«å››æ¨äº”å…¥ã—ã¦è¿”ã—ã¾ã™ã€‚ (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) 関数ã¯ã€X ã®å³ç«¯ã«ã‚る空白をå–り除ãã¾ã™ã€‚ (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) rtrim(X,Y) 関数ã¯ã€X ã®å³ç«¯ã‹ã‚‰ã€ Y ã«å«ã¾ã‚Œã‚‹æ–‡å­—ã‚’ã™ã¹ã¦å–り除ã„ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) soundex(X) 関数ã¯ã€æ–‡å­—列 X ã‚’ soundex ã«ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) 関数ã¯ã€æ–‡å­—列 Xã®ã€å…ˆé ­ã‹ã‚‰ Y 番目ã‹ã‚‰æœ«å°¾ã¾ã§ã®æ–‡å­—列を返ã—ã¾ã™ã€‚ (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) substr(X,Y,Z) 関数ã¯ã€æ–‡å­—列 X ã®ã€å…ˆé ­ã‹ã‚‰ Y 番目ã‹ã‚‰ Z æ–‡å­—ã®æ–‡å­—列を返ã—ã¾ã™ã€‚ () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () total_changes() 関数ã¯ã€ç¾åœ¨é–‹ã‹ã‚ŒãŸæŽ¥ç¶šã®ã‚るデータベースã«ãŠã„ã¦ã€INSERTã€UPDATEã€DELETEã§å¤‰æ›´ã•れãŸè¡Œæ•°ã‚’è¿”ã—ã¾ã™ã€‚ returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. (X) trim(X) removes spaces from both ends of X. (X) trim(X) 関数ã¯ã€X ã®ä¸¡ç«¯ã«ã‚る空白をå–り除ãã¾ã™ã€‚ (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) trim(X,Y) 関数ã¯ã€X ã®ä¸¡ç«¯ã‹ã‚‰ã€ Y ã«å«ã¾ã‚Œã‚‹æ–‡å­—ã‚’ã™ã¹ã¦å–り除ã„ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) typeof(X) 関数ã¯ã€å¼ X ã®ãƒ‡ãƒ¼ã‚¿åž‹ã‚’ç¤ºã™æ–‡å­—列を返ã—ã¾ã™ã€‚ (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) unicode(X) 関数ã¯ã€æ–‡å­—列 X ã®æœ€åˆã®æ–‡å­—ã«å¯¾å¿œã™ã‚‹ Unicode 符å·ä½ç½®ã‚’è¿”ã—ã¾ã™ã€‚ (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) upper(X) 関数ã¯ã€ã™ã¹ã¦ ASCII 文字ã§ã‚る文字列 X ã‚’ã€ã™ã¹ã¦å¤§æ–‡å­—ã«å¤‰æ›ã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) zeroblob(N) 関数ã¯ã€ã™ã¹ã¦ 0x00 ã§åŸ‹ã‚られãŸã€N ãƒã‚¤ãƒˆã® BLOB ã‚’è¿”ã—ã¾ã™ã€‚ (timestring,modifier,modifier,...) (時刻文字列, 修飾å­, 修飾å­,...) (format,timestring,modifier,modifier,...) (フォーマット, 時刻文字列, 修飾å­, 修飾å­,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) avg() 関数ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®éžNULLãªå€¤ã®å¹³å‡ã‚’è¿”ã—ã¾ã™ã€‚ (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) count(X) 関数ã¯ã‚°ãƒ«ãƒ¼ãƒ—内ã«ã‚ã‚‹ã€NULLã§ãªã„ X ã®ä»¶æ•°ã‚’è¿”ã—ã¾ã™ã€‚ (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) group_concat() 関数ã¯ã€éžNULLãªã™ã¹ã¦ã® X を連çµã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) group_concat() 関数ã¯ã€éžNULLãªã™ã¹ã¦ã® X を連çµã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ã‚‚ã—ã€å¼•æ•° Y ãŒå­˜åœ¨ã™ã‚‹ãªã‚‰ã°ã€X を連çµã™ã‚‹ã¨ãã®åŒºåˆ‡ã‚Šæ–‡å­—ã¨ã—ã¦ä½¿ç”¨ã—ã¾ã™ã€‚ (X) The max() aggregate function returns the maximum value of all values in the group. (X) max() 集計関数ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®(éžNULLã§ã‚ã‚‹)最大値を返ã—ã¾ã™ã€‚ (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) min() 集計関数ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®(éžNULLã§ã‚ã‚‹)最å°å€¤ã‚’è¿”ã—ã¾ã™ã€‚ (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) sum() 㨠total() 集計関数ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®éžNULLãªå€¤ã®åˆè¨ˆã‚’è¿”ã—ã¾ã™ã€‚ () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () ç¾åœ¨ã®åˆ†å‰²å†…ã®è¡Œç•ªå·ã€‚行ã¯ã€ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦å®šç¾©ã® ORDER BY å¥ã‚„ãれ以外ã®ä»»æ„ã®é †åºã«å¾“ã„ã€1 ã‹ã‚‰é †ã«ç•ªå·ä»˜ã‘ã•れã¾ã™ã€‚ () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () å„グループã®é †ä½ - åŒå€¤ã¯åŒé †ä½ã§ã€æ¬¡ã®å€¤ã¯é‡è¤‡åˆ†ã ã‘é †ä½ãŒãšã‚Œã¾ã™ã€‚ã‚‚ã—ã€ORDER BY å¥ãŒãªã‘れã°ã€ã™ã¹ã¦ã®è¡Œã‚’åŒé †ä½ã¨ã¿ãªã—ã€å¸¸ã« 1 ã‚’è¿”ã—ã¾ã™ã€‚ () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () å„グループã®é †ä½ - åŒå€¤ã¯åŒé †ä½ã§ã€æ¬¡ã®å€¤ã¯é‡è¤‡ã«é–¢ã‚らãšå‰ã®é †ä½+1ã«ãªã‚Šã¾ã™ã€‚パーティションã¯ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦å®šç¾©ã® ORDER BY å¥ã‚„ãれ以外ã®ä»»æ„ã®é †åºã«å¾“ã„ã€1 ã‹ã‚‰é †ã«ç•ªå·ä»˜ã‘ã•れã¾ã™ã€‚ã‚‚ã—ã€ORDER BY å¥ãŒãªã‘れã°ã€ã™ã¹ã¦ã®è¡Œã‚’åŒé †ä½ã¨ã¿ãªã—ã€å¸¸ã« 1 ã‚’è¿”ã—ã¾ã™ã€‚ () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () ãã®åå‰ã«ã‚‚é–¢ã‚らãšã€ã“ã®é–¢æ•°ã¯å¸¸ã« 0.0 ã‹ã‚‰ 1.0 ã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚ã“ã®å€¤ã¯ã€(rank - 1)/(パーティション行数 - 1) ã§ã™ã€‚ã“ã“ã§ã€rank ã¯çµ„ã¿è¾¼ã¿ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã® rank()ã€ãƒ‘ーティション行数ã¯ãƒ‘ーティション内ã®è¡Œã®æ•°ã§ã™ã€‚ã‚‚ã—ã€ãƒ‘ーティションã«1行ã—ã‹å«ã¾ã‚Œã¦ã„ãªã‘れã°ã€ã“ã®é–¢æ•°ã¯ 0.0 ã‚’è¿”ã—ã¾ã™ã€‚ () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () ç´¯ç©åˆ†å¸ƒã€‚(行番å·)/(パーティション行数) ã§è¨ˆç®—ã•れã¾ã™ã€‚ã“ã“ã§è¡Œç•ªå·ã¯ã‚°ãƒ«ãƒ¼ãƒ—内㧠row_number() ã§è¿”ã•れãŸå€¤ã€ãƒ‘ーティション行数ã¯ãƒ‘ーティション内ã®è¡Œã®æ•°ã§ã™ã€‚ (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) 引数 N ã¯INTEGERã¨ã—ã¦æ‰±ã‚れã¾ã™ã€‚ã“ã®é–¢æ•°ã¯ãƒ‘ーティションを ORDER BY å¥ã‚„ãれ以外ã®ä»»æ„ã®é †åºã«å¾“ã„ N 個ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«å¯èƒ½ãªé™ã‚Šç­‰åˆ†ã—ã€ãれãžã‚Œã®ã‚°ãƒ«ãƒ¼ãƒ—ã« 1 ã‹ã‚‰ N ã®INTEGERã‚’ã¤ã‘ã¾ã™ã€‚å¿…è¦ãŒã‚れã°ã€å…ˆé ­ã®ã»ã†ã«ã‚るグループã®ä»¶æ•°ã‚’多ãã™ã‚‹ã‚ˆã†ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¾ã™ã€‚ã“ã®é–¢æ•°ã¯ç¾åœ¨ã®è¡ŒãŒå«ã¾ã‚Œã‚‹ã‚°ãƒ«ãƒ¼ãƒ—ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸINTEGERã‚’è¿”ã—ã¾ã™ã€‚ (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) パーティション内ã®å‰ã®è¡Œã«å¯¾ã—ã¦å¼ expr を評価ã—ãŸçµæžœã‚’è¿”ã—ã¾ã™ã€‚(先頭行ã®ãŸã‚)å‰ã®è¡ŒãŒãªã‘れã°ã€NULLã‚’è¿”ã—ã¾ã™ã€‚ (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) 引数 offset ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆã€éžè² ã®INTEGERã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ã“ã®å ´åˆã€ãƒ‘ーティション内㮠offset ã ã‘å‰ã®è¡Œã«å¯¾ã—ã¦å¼ expr を評価ã—ãŸçµæžœã‚’è¿”ã—ã¾ã™ã€‚offset ㌠0 ãªã‚‰ã°ã€ç¾åœ¨è¡Œã«å¯¾ã—ã¦è©•価ã—ã¾ã™ã€‚å‰ã®è¡ŒãŒãªã‘れã°ã€NULLã‚’è¿”ã—ã¾ã™ã€‚ (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) default ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆã€è©²å½“ã®è¡ŒãŒãªã‘れã°ã€NULL ã®ä»£ã‚り㫠defaul 値を返ã—ã¾ã™ã€‚ (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) ãƒ‘ãƒ¼ãƒ†ã‚£ã‚·ãƒ§ãƒ³å†…ã®æ¬¡ã®è¡Œã«å¯¾ã—ã¦å¼ expr を評価ã—ãŸçµæžœã‚’è¿”ã—ã¾ã™ã€‚(最終行ã®ãŸã‚)次ã®è¡ŒãŒãªã‘れã°ã€NULLã‚’è¿”ã—ã¾ã™ã€‚ (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) 引数 offset ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆã€éžè² ã®INTEGERã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ã“ã®å ´åˆã€ãƒ‘ーティション内㮠offset ã ã‘次ã®è¡Œã«å¯¾ã—ã¦å¼ expr を評価ã—ãŸçµæžœã‚’è¿”ã—ã¾ã™ã€‚offset ㌠0 ãªã‚‰ã°ã€ç¾åœ¨è¡Œã«å¯¾ã—ã¦è©•価ã—ã¾ã™ã€‚次ã®è¡ŒãŒãªã‘れã°ã€NULLã‚’è¿”ã—ã¾ã™ã€‚ (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) ã“ã®çµ„ã¿è¾¼ã¿ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã¯ã€åŒã˜é›†è¨ˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã‚’使ã£ã¦ãれãžã‚Œã®è¡Œã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•レームを計算ã—ã¾ã™ã€‚å„行ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•ãƒ¬ãƒ¼ãƒ ã®æœ€åˆã®è¡Œã«å¯¾ã—ã¦è©•価ã•れる expr ã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚ (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) ã“ã®çµ„ã¿è¾¼ã¿ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã¯ã€åŒã˜é›†è¨ˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã‚’使ã£ã¦ãれãžã‚Œã®è¡Œã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•レームを計算ã—ã¾ã™ã€‚å„行ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•ãƒ¬ãƒ¼ãƒ ã®æœ€å¾Œã®è¡Œã«å¯¾ã—ã¦è©•価ã•れる expr ã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚ (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) ã“ã®çµ„ã¿è¾¼ã¿ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã¯ã€åŒã˜é›†è¨ˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã‚’使ã£ã¦ãれãžã‚Œã®è¡Œã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•レームを計算ã—ã¾ã™ã€‚å„行ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•レーム㮠N 番目ã®è¡Œã«å¯¾ã—ã¦è©•価ã•れる expr ã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚行ã¯ã€ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦å®šç¾©ã® ORDER BY å¥ã‚„ãれ以外ã®ä»»æ„ã®é †åºã«å¾“ã„ã€1 ã‹ã‚‰é †ã«ç•ªå·ä»˜ã‘ã•れã¾ã™ã€‚ N 番目ã®è¡ŒãŒãƒ‘ーティションã«ãªã„å ´åˆã€NULL ãŒè¿”ã•れã¾ã™ã€‚ (X) Return the arccosine of X. The result is in radians. (X) Xã®é€†ä½™å¼¦(arccos)ã‚’è¿”ã—ã¾ã™ã€‚çµæžœã¯ãƒ©ã‚¸ã‚¢ãƒ³å˜ä½ã§ã™ã€‚ (X) Return the hyperbolic arccosine of X. (X) Xã®é€†åŒæ›²ç·šä½™å¼¦(arcosh)ã‚’è¿”ã—ã¾ã™ã€‚ (X) Return the arcsine of X. The result is in radians. (X) Xã®é€†æ­£å¼¦(arcsin)ã‚’è¿”ã—ã¾ã™ã€‚çµæžœã¯ãƒ©ã‚¸ã‚¢ãƒ³å˜ä½ã§ã™ã€‚ (X) Return the hyperbolic arcsine of X. (X) Xã®é€†åŒæ›²ç·šæ­£å¼¦(arsinh)ã‚’è¿”ã—ã¾ã™ã€‚ (X) Return the arctangent of X. The result is in radians. (X) Xã®é€†æ­£æŽ¥(arctan)ã‚’è¿”ã—ã¾ã™ã€‚çµæžœã¯ãƒ©ã‚¸ã‚¢ãƒ³å˜ä½ã§ã™ã€‚ (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X,Y) Y/Xã®é€†æ­£æŽ¥(arctan)ã‚’è¿”ã—ã¾ã™ã€‚ çµæžœã¯ãƒ©ã‚¸ã‚¢ãƒ³å˜ä½ã§ã™ã€‚çµæžœã¯Xã¨Yã®ç¬¦å·ã«ã‚ˆã‚Šæ­£ã—ã„象é™ã«é…ç½®ã•れã¾ã™ã€‚ (X) Return the hyperbolic arctangent of X. (X) Xã®é€†åŒæ›²ç·šæ­£æŽ¥(artanh)ã‚’è¿”ã—ã¾ã™ã€‚ (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Xä»¥ä¸Šã§æœ€å°ã®æ•´æ•°ã‚’è¿”ã—ã¾ã™ã€‚XãŒæ­£ãªã‚‰ã°0ã‹ã‚‰é ã–ã‹ã‚‹ã‚ˆã†ã«ä¸¸ã‚ã¾ã™ã€‚XãŒè² ãªã‚‰ã°0ã«è¿‘ã¥ãよã†ã«ä¸¸ã‚ã¾ã™ã€‚ (X) Return the cosine of X. X is in radians. (X) Xã®ä½™å¼¦ã‚’è¿”ã—ã¾ã™ã€‚Xã¯ãƒ©ã‚¸ã‚¢ãƒ³å˜ä½ã§ã™ã€‚ (X) Return the hyperbolic cosine of X. (X) Xã®åŒæ›²ç·šä½™å¼¦ã‚’è¿”ã—ã¾ã™ã€‚ (X) Convert value X from radians into degrees. (X) Xをラジアンã‹ã‚‰åº¦ã«å¤‰æ›ã—ã¾ã™ã€‚ (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) e (オイラー数ã€ç´„2.71828182845905) ã®X乗を計算ã—ã¾ã™ã€‚ (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Xä»¥ä¸‹ã§æœ€å¤§ã®æ•´æ•°ã‚’è¿”ã—ã¾ã™ã€‚XãŒæ­£ãªã‚‰ã°0ã«è¿‘ã¥ãよã†ã«ä¸¸ã‚ã¾ã™ã€‚XãŒè² ãªã‚‰ã°0ã‹ã‚‰é ã–ã‹ã‚‹ã‚ˆã†ã«ä¸¸ã‚ã¾ã™ã€‚ (X) Return the natural logarithm of X. (X) Xã®è‡ªç„¶å¯¾æ•°ã‚’è¿”ã—ã¾ã™ã€‚ (B,X) Return the base-B logarithm of X. (B,X) 底をBã¨ã—ã¦Xã®å¯¾æ•°ã‚’è¿”ã—ã¾ã™ã€‚ (X) Return the base-10 logarithm for X. (X) 底を10ã¨ã—ã¦Xã®å¯¾æ•°ã‚’è¿”ã—ã¾ã™ã€‚ (X) Return the logarithm base-2 for the number X. (X) 底を2ã¨ã—ã¦Xã®å¯¾æ•°ã‚’è¿”ã—ã¾ã™ã€‚ (X,Y) Return the remainder after dividing X by Y. (X,Y) Xã‚’Yã§å‰²ã£ãŸã¨ãã®å‰°ä½™ã‚’è¿”ã—ã¾ã™ã€‚ () Return an approximation for Ï€. () Ï€ã®è¿‘似値を返ã—ã¾ã™ã€‚ (X,Y) Compute X raised to the power Y. (X,Y) Xã®Y情を計算ã—ã¾ã™ã€‚ (X) Convert X from degrees into radians. (X) Xを度ã‹ã‚‰ãƒ©ã‚¸ã‚¢ãƒ³ã«å¤‰æ›ã—ã¾ã™ã€‚ (X) Return the sine of X. X is in radians. (X) Xã®æ­£å¼¦ã‚’è¿”ã—ã¾ã™ã€‚Xã¯ãƒ©ã‚¸ã‚¢ãƒ³å˜ä½ã§ã™ã€‚ (X) Return the hyperbolic sine of X. (X) Xã®åŒæ›²ç·šæ­£å¼¦ã‚’è¿”ã—ã¾ã™ã€‚ (X) Return the square root of X. NULL is returned if X is negative. (X) Xã®å¹³æ–¹æ ¹ã‚’è¿”ã—ã¾ã™ã€‚XãŒè² ãªã‚‰ã°NULLã‚’è¿”ã—ã¾ã™ã€‚ (X) Return the tangent of X. X is in radians. (X) Xã®æ­£æŽ¥ã‚’è¿”ã—ã¾ã™ã€‚Xã¯ãƒ©ã‚¸ã‚¢ãƒ³å˜ä½ã§ã™ã€‚ (X) Return the hyperbolic tangent of X. (X) Xã®åŒæ›²ç·šæ­£æŽ¥ã‚’è¿”ã—ã¾ã™ã€‚ (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) Xã¨0ã®é–“ã«ã‚ã‚‹ã€0ã‹ã‚‰æœ€ã‚‚é ã„æ•´æ•°ã‚’è¿”ã—ã¾ã™ã€‚è¨€ã„æ›ãˆã‚‹ã¨ã€Xã‚’0ã«è¿‘ã¥ãよã†ã«ä¸¸ã‚ã¾ã™ã€‚ SqliteTableModel reading rows 行を読ã¿è¾¼ã¿ä¸­ loading... 読ã¿è¾¼ã¿ä¸­... References %1(%2) Hold %3Shift and click to jump there ã“れをå‚ç…§ %1(%2) %3Shift ã‚’ä¿æŒã—クリックã§ã‚¸ãƒ£ãƒ³ãƒ— Error changing data: %1 データã®å¤‰æ›´ã§ã‚¨ãƒ©ãƒ¼: %1 retrieving list of columns カラムã®ä¸€è¦§ã‚’å–得中 Fetching data... データをå–得中... Cancel キャンセル TableBrowser Browse Data データ閲覧 &Table: テーブル(&T): Select a table to browse data 閲覧ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠž Use this list to select a table to be displayed in the database view ã“ã®ä¸€è¦§ã‚’使ã£ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ“ューã«è¡¨ç¤ºã™ã‚‹ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠž This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. ã“れã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ†ãƒ¼ãƒ–ルã®ãƒ“ューã§ã™ã€‚ä»¥ä¸‹ã®æ“作ãŒã§ãã¾ã™: - 値をインライン編集ã§ãã¾ã™ã€‚ - レコードをダブルクリックã™ã‚‹ã¨ã€ã‚»ãƒ«ç·¨é›†ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§å†…容を編集ã§ãã¾ã™ã€‚ - Alt+Del ã§ã‚»ãƒ«ã®å†…容をNULLã«ã§ãã¾ã™ã€‚ - Ctrl+" ã§ç¾åœ¨ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’複製ã§ãã¾ã™ã€‚ - Ctrl+' ã§ä¸Šã®ã‚»ãƒ«ã®å€¤ã‚’コピーã§ãã¾ã™ã€‚ - é€šå¸¸ã®æ“作ã§ã€é¸æŠž/コピー/貼り付ã‘ãŒã§ãã¾ã™ã€‚ Text pattern to find considering the checks in this frame ã“ã®ãƒ•レームã§ã®ãƒã‚§ãƒƒã‚¯ãƒœãƒƒã‚¯ã‚¹ã‚’考慮ã—ãŸæ¤œç´¢æ–‡å­—列 Find in table テーブルを検索 Find previous match [Shift+F3] å‰ã‚’検索 [Shift+F3] Find previous match with wrapping 折り返ã—ã¦å‰ã‚’検索 Shift+F3 Find next match [Enter, F3] 次を検索 [Enter, F3] Find next match with wrapping 折り返ã—ã¦æ¬¡ã‚’検索 F3 The found pattern must match in letter case 大/å°æ–‡å­—を区別ã—ã¾ã™ Case Sensitive 大/å°æ–‡å­—を区別 The found pattern must be a whole word å˜èªžå˜ä½ã§æ¤œç´¢ã—ã¾ã™ Whole Cell セル全体ã«ä¸€è‡´ Interpret search pattern as a regular expression æ­£è¦è¡¨ç¾ã§æ¤œç´¢ <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>設定ã™ã‚‹ã¨ã€æ¤œç´¢æ¡ä»¶ã¯UNIXæ­£è¦è¡¨ç¾ã¨è§£é‡ˆã•れã¾ã™ã€‚以下をå‚ç…§ <a href="https://ja.wikibooks.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE">Wikibooksã®æ­£è¦è¡¨ç¾</a>。</p></body></html> Regular Expression æ­£è¦è¡¨ç¾ Close Find Bar 検索ãƒãƒ¼ã‚’é–‰ã˜ã‚‹ Text to replace with ã“ã®æ–‡å­—列ã§ç½®ãæ›ãˆã‚‹ Replace with ç½®æ› Replace next match 次ã«ä¸€è‡´ã—ãŸã‚‚ã®ã‚’ç½®ãæ›ãˆ Replace ç½®æ› Replace all matches 一致ã—ãŸã‚‚ã®ã™ã¹ã¦ã‚’ç½®ãæ›ãˆ Replace all ã™ã¹ã¦ç½®æ› Export to &JSON JSONã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ(&J) Export the filtered data to JSON フィルターã•れãŸãƒ‡ãƒ¼ã‚¿ã‚’JSONã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. ã“ã®ãƒœã‚¿ãƒ³ã¯é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルデータをç¾åœ¨ã®è¡¨ç¤ºé€šã‚Šã«(フィルターã€è¡¨ç¤ºãƒ•ォーマットã€ã‚«ãƒ©ãƒ ã®é †ç•ªã‚’ç¶­æŒã—ã¦)JSONファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ Copy column name カラムåをコピー Copy the database table column name to your clipboard データベース テーブル カラムåをクリップボードã«ã‚³ãƒ”ー New Data Browser æ–°ã—ã„データ閲覧 Add a new docked Data Browser æ–°ã—ãドッキングã—ãŸãƒ‡ãƒ¼ã‚¿é–²è¦§ã‚’追加 This button adds a new docked Data Browser, which you can detach and arrange in different layouts. ã“ã®ãƒœã‚¿ãƒ³ã¯æ–°ã—ãドッキングã—ãŸãƒ‡ãƒ¼ã‚¿é–²è¦§ã‚’追加ã—ã¾ã™ã€‚ã“れã¯é•ã†ãƒ¬ã‚¤ã‚¢ã‚¦ãƒˆã§åˆ‡ã‚Šé›¢ã—ã¦é…ç½®ã§ãã¾ã™ã€‚ <html><head/><body><p>Scroll to the beginning</p></body></html> 先頭㸠<html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ä¸Šã®ãƒ†ãƒ¼ãƒ–ルビューを先頭ã¾ã§ç§»å‹•ã—ã¾ã™ã€‚</p></body></html> |< |< Scroll one page upwards 1ページå‰ã¸ <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ä¸Šã®ãƒ†ãƒ¼ãƒ–ルビューを1ページå‰ã¸ç§»å‹•ã—ã¾ã™ã€‚</p></body></html> < < 0 - 0 of 0 0 - 0 of 0 Scroll one page downwards 1ページ後㸠<html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ä¸Šã®ãƒ†ãƒ¼ãƒ–ルビューを1ページ後ã¸ç§»å‹•ã—ã¾ã™ã€‚</p></body></html> > > Scroll to the end 末尾㸠<html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ä¸Šã®ãƒ†ãƒ¼ãƒ–ãƒ«ãƒ“ãƒ¥ãƒ¼ã®æœ«å°¾ã¾ã§ç§»å‹•ã—ã¾ã™ã€‚</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>ã“ã“をクリックã—ã¦æŒ‡å®šã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã¾ã§ç§»å‹•</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã¯ ã“ã“ã¸ç§»å‹• ã®å…¥åŠ›æ¬„ã§æŒ‡å®šã•れãŸç•ªå·ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã¸ç§»å‹•ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã—ã¾ã™ã€‚</p></body></html> Go to: ã“ã“ã¸ç§»å‹•: Enter record number to browse 閲覧ã™ã‚‹ãƒ¬ã‚³ãƒ¼ãƒ‰ã®ç•ªå·ã‚’入力 Type a record number in this area and click the Go to: button to display the record in the database view ã“ã®æ¬„ã«ãƒ¬ã‚³ãƒ¼ãƒ‰ã®ç•ªå·ã‚’入力ã—ã€ã“ã“ã¸ç§»å‹•ボタンをクリックã™ã‚‹ã¨ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ“ューã«ãƒ¬ã‚³ãƒ¼ãƒ‰ãŒè¡¨ç¤ºã•れã¾ã™ 1 1 Show rowid column rowidカラムを表示 Toggle the visibility of the rowid column rowidカラムã®è¡¨ç¤ºã‚’切り替ãˆã¾ã™ Unlock view editing ビューã®ç·¨é›†ã‚’開放 This unlocks the current view for editing. However, you will need appropriate triggers for editing. ã“れã¯ç¾åœ¨ã®ãƒ“ューã§ç·¨é›†ã§ãるよã†ã«ã—ã¾ã™ã€‚ã—ã‹ã—ã€ç·¨é›†æ™‚ã®ãƒˆãƒªã‚¬ãƒ¼ã«å¯¾å¿œã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ Edit display format 表示書å¼ã‚’編集 Edit the display format of the data in this column ã“ã®ã‚«ãƒ©ãƒ ã®ãƒ‡ãƒ¼ã‚¿ã®è¡¨ç¤ºæ›¸å¼ã‚’編集ã—ã¾ã™ New Record æ–°ã—ã„レコード Insert a new record in the current table æ–°ã—ã„レコードをç¾åœ¨ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã«æŒ¿å…¥ <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã¯æ–°ã—ã„レコードをデータベースã«ä½œæˆã—ã¾ã™ã€‚マウスボタンを押ã—ãŸã¾ã¾ã«ã™ã‚‹ã¨ã€é•ã†ã‚ªãƒ—ションã®ãƒãƒƒãƒ—アップメニューãŒé–‹ãã¾ã™:</p><ul><li><span style=" font-weight:600;">æ–°ã—ã„レコード</span>: データベースã«ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã§æ–°ã—ã„レコードを挿入ã—ã¾ã™ã€‚</li><li><span style=" font-weight:600;">値を挿入...</span>: ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«æŒ¿å…¥ã™ã‚‹å‰ã«ãƒ‡ãƒ¼ã‚¿ã‚’入力ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ã€‚ã“れã§ä»–ã®åˆ¶ç´„を満ãŸã™å€¤ãŒå…¥åŠ›ã§ãã¾ã™ã€‚ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã¯<span style=" font-weight:600;">æ–°ã—ã„レコード</span>オプションãŒãれらã®åˆ¶ç´„ã®ã›ã„ã§å¤±æ•—ã—ãŸã¨ãã«ã‚‚é–‹ãã¾ã™ã€‚</li></ul></body></html> Delete Record レコードを削除 Delete the current record ç¾åœ¨ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’削除 This button deletes the record or records currently selected in the table ã“ã®ãƒœã‚¿ãƒ³ã¯ãƒ†ãƒ¼ãƒ–ルã«ã‚ã‚‹ç¾åœ¨é¸æŠžä¸­ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’削除ã—ã¾ã™ Insert new record using default values in browsed table 閲覧中ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã‚’ä½¿ã„æ–°ã—ã„レコードを挿入ã—ã¾ã™ Insert Values... 値を挿入... Open a dialog for inserting values in a new record æ–°ã—ã„レコードã«å€¤ã‚’挿入ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ Export to &CSV CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ(&C) Export the filtered data to CSV フィルターã•れãŸãƒ‡ãƒ¼ã‚¿ã‚’CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. ã“ã®ãƒœã‚¿ãƒ³ã¯é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’ç¾åœ¨ã®è¡¨ç¤ºé€šã‚Š(フィルターã€è¡¨ç¤ºå½¢å¼ã€ã‚«ãƒ©ãƒ é †ç•ª)ã«CSVファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ Save as &view ビューã¨ã—ã¦ä¿å­˜(&V) Save the current filter, sort column and display formats as a view ç¾åœ¨ã®ãƒ•ィルターã€ã‚«ãƒ©ãƒ é †ç•ªã€è¡¨ç¤ºå½¢å¼ã‚’ビューã«ä¿å­˜ This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. ã“ã®ãƒœã‚¿ãƒ³ã¯é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã®ç¾åœ¨ã®è¡¨ç¤ºè¨­å®š(フィルターã€è¡¨ç¤ºå½¢å¼ã€ã‚«ãƒ©ãƒ é †ç•ª)ã‚’SQLビューã¨ã—ã¦ä¿å­˜ã—ã€ã‚ã¨ã§é–²è¦§ã‚„SQLæ–‡ã¨ã—ã¦ä½¿ç”¨ã§ãるよã†ã«ã—ã¾ã™ã€‚ Save Table As... テーブルã«åå‰ã‚’付ã‘ã¦ä¿å­˜... Save the table as currently displayed ç¾åœ¨è¡¨ç¤ºã•れã¦ã„ã‚‹ã‚‚ã®ã‚’テーブルã«ä¿å­˜ <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>ã“ã®ãƒãƒƒãƒ—アップメニューã¯ç¾åœ¨é–²è¦§ã—ã¦ã„るテーブルã«é©ç”¨ã•れる以下ã®ã‚ªãƒ—ションをæä¾›ã—ã¾ã™ã€‚:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ: ã“ã®ã‚ªãƒ—ションã¯é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’ç¾åœ¨ã®è¡¨ç¤ºé€šã‚Š(フィルターã€è¡¨ç¤ºå½¢å¼ã€ã‚«ãƒ©ãƒ é †ç•ª)ã«CSVファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ビューã¨ã—ã¦ä¿å­˜: ã“ã®ã‚ªãƒ—ションã¯é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã®ç¾åœ¨ã®è¡¨ç¤ºè¨­å®š(フィルターã€è¡¨ç¤ºå½¢å¼ã€ã‚«ãƒ©ãƒ é †ç•ª)ã‚’SQLビューã¨ã—ã¦ä¿å­˜ã—ã€ã‚ã¨ã§é–²è¦§ã‚„SQLæ–‡ã¨ã—ã¦ä½¿ç”¨ã§ãるよã†ã«ã—ã¾ã™ã€‚</li></ul></body></html> Hide column(s) カラムを隠㙠Hide selected column(s) é¸æŠžã—ãŸã‚«ãƒ©ãƒ ã‚’éš ã™ Show all columns ã™ã¹ã¦ã®ã‚«ãƒ©ãƒ ã‚’表示 Show all columns that were hidden éš ã•れãŸã™ã¹ã¦ã®ã‚«ãƒ©ãƒ ã‚’表示 Set encoding エンコードã®è¨­å®š Change the encoding of the text in the table cells テーブルã®ã‚»ãƒ«ã«ã‚るテキストã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã‚’変更ã—ã¾ã™ Set encoding for all tables ã™ã¹ã¦ã®ãƒ†ãƒ¼ãƒ–ルã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã®è¨­å®š Change the default encoding assumed for all tables in the database データベース内ã®ã™ã¹ã¦ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ•ォルトエンコードを変更ã—ã¾ã™ Clear Filters フィルターを削除 Clear all filters ã™ã¹ã¦ã®ãƒ•ィルターを消去 This button clears all the filters set in the header input fields for the currently browsed table. ã“ã®ãƒœã‚¿ãƒ³ã§ç¾åœ¨é–²è¦§ã—ã¦ã„るテーブルã®ãƒ˜ãƒƒãƒ€ãƒ¼å…¥åŠ›æ¬„ã«è¨­å®šã•れãŸã™ã¹ã¦ã®ãƒ•ィルターを消去ã—ã¾ã™ã€‚ Clear Sorting ä¸¦ã¹æ›¿ãˆã‚’解除 Reset the order of rows to the default 行ã®é †ç•ªã‚’デフォルトã«ãƒªã‚»ãƒƒãƒˆã—ã¾ã™ This button clears the sorting columns specified for the currently browsed table and returns to the default order. ã“ã®ãƒœã‚¿ãƒ³ã¯ã€ç¾åœ¨é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã«ã‚ã‚‹ä¸¦ã³æ›¿ãˆãŸã‚«ãƒ©ãƒ ã‚’デフォルトã®é †ç•ªã«æˆ»ã—ã¾ã™ã€‚ Print å°åˆ· Print currently browsed table data ç¾åœ¨é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルデータをå°åˆ· Print currently browsed table data. Print selection if more than one cell is selected. ç¾åœ¨é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルデータをå°åˆ·ã—ã¾ã™ã€‚複数ã®ã‚»ãƒ«ã‚’é¸æŠžã—ã¦ã„ã‚‹å ´åˆã€é¸æŠžç¯„囲をå°åˆ·ã—ã¾ã™ã€‚ Ctrl+P Refresh æ›´æ–° Refresh the data in the selected table é¸æŠžã—ãŸãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’æ›´æ–° This button refreshes the data in the currently selected table. ã“ã®ãƒœã‚¿ãƒ³ã§ç¾åœ¨é¸æŠžã—ã¦ã„るテーブルã®ãƒ‡ãƒ¼ã‚¿ã‚’æ›´æ–°ã—ã¾ã™ã€‚ F5 Find in cells セル内を検索 Open the find tool bar which allows you to search for values in the table view below. テーブルビューã®ä¸‹ã«å€¤ã‚’検索ã™ã‚‹ãŸã‚ã®æ¤œç´¢ãƒ„ールãƒãƒ¼ã‚’é–‹ãã¾ã™ã€‚ Freeze columns カラムを固定ã™ã‚‹ Make all columns from the first column up to this column not move when scrolling horizontally 水平方å‘ã«ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã—ã¦ã‚‚ã€å…ˆé ­ã‹ã‚‰ã“ã®ã‚«ãƒ©ãƒ ã¾ã§ã‚’移動ã—ãªã„よã†ã«ã—ã¾ã™ Bold 太字 Ctrl+B Italic イタリック Underline 下線 Ctrl+U Align Right 峿ƒãˆ Align Left å·¦æƒãˆ Center Horizontally 中央æƒãˆ Justify å‡ç­‰å‰²ä»˜ Edit Conditional Formats... æ¡ä»¶ä»˜ã書å¼ã‚’編集... Edit conditional formats for the current column ç¾åœ¨ã®ã‚«ãƒ©ãƒ ã®æ¡ä»¶ä»˜ã書å¼ã‚’編集ã—ã¾ã™ Clear Format 書å¼ã‚’削除 Clear All Formats ã™ã¹ã¦ã®æ›¸å¼ã‚’削除 Clear all cell formatting from selected cells and all conditional formats from selected columns é¸æŠžã—ãŸã‚»ãƒ«ã®ã™ã¹ã¦ã®æ›¸å¼ã‚’削除ã—ã€é¸æŠžã—ãŸã‚«ãƒ©ãƒ ã®ã™ã¹ã¦ã®æ¡ä»¶ä»˜ã書å¼ã‚’削除ã—ã¾ã™ Font Color フォント色 Background Color 背景色 Toggle Format Toolbar フォーマットツールãƒãƒ¼ã‚’切り替㈠Show/hide format toolbar フォーマットツールãƒãƒ¼ã‚’表示/éžè¡¨ç¤ºã—ã¾ã™ This button shows or hides the formatting toolbar of the Data Browser ã“ã®ãƒœã‚¿ãƒ³ã§ãƒ‡ãƒ¼ã‚¿é–²è¦§ã®æ›¸å¼ãƒ„ールãƒãƒ¼ã‚’表示/éžè¡¨ç¤ºã—ã¾ã™ Select column ã‚«ãƒ©ãƒ ã‚’é¸æŠž Ctrl+Space Replace text in cells セル内ã®ãƒ†ã‚­ã‚¹ãƒˆã‚’ç½®ãæ›ãˆ Filter in any column ä»»æ„ã®ã‚«ãƒ©ãƒ ã‚’フィルター Ctrl+R %n row(s) %n 行 , %n column(s) , %n カラム . Sum: %1; Average: %2; Min: %3; Max: %4 . åˆè¨ˆ: %1; å¹³å‡: %2; 最低: %3; 最高: %4 Conditional formats for "%1" "%1" ã®æ¡ä»¶ä»˜ãæ›¸å¼ determining row count... 行数を計算中... %L1 - %L2 of >= %L3 %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) (%L1 行を抜ã出ã—) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. ã“ã®ãƒ“ューã§ã®ç·¨é›†ã‚’有効ã«ã™ã‚‹ãŸã‚ã€ç–‘似主キーを入力ã—ã¦ãã ã•ã„。ビューã«ä¸€æ„ãªã‚«ãƒ©ãƒ ã®åå‰ãŒå¿…è¦ã§ã™ã€‚ Delete Records レコードを削除 Duplicate records レコードを複製 Duplicate record レコードを複製 Ctrl+" Adjust rows to contents 行を内容ã«åˆã‚ã›èª¿æ•´ Error deleting record: %1 レコードã®å‰Šé™¤ã§ã‚¨ãƒ©ãƒ¼: %1 Please select a record first 最åˆã«ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’é¸æŠžã—ã¦ãã ã•ã„ Please choose a new encoding for all tables. ã™ã¹ã¦ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã®æ–°ã—ã„ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã‚’é¸æŠžã—ã¦ãã ã•ã„。 Please choose a new encoding for this table. ã™ã¹ã¦ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã®æ–°ã—ã„ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã‚’é¸æŠžã—ã¦ãã ã•ã„。 %1 Leave the field empty for using the database encoding. %1 データベースã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã‚’使ã†ãŸã‚ã€ãƒ•ィールドを空ã«ã—ã¾ã™ã€‚ This encoding is either not valid or not supported. ã“ã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã¯ä¸æ­£ã‹ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“。 %1 replacement(s) made. %1 ã¤ç½®ãæ›ãˆã¾ã—ãŸã€‚ TableBrowserDock New Data Browser æ–°ã—ã„データ閲覧 Rename Data Browser データ閲覧ã®åå‰ã‚’変ãˆã‚‹ Close Data Browser データ閲覧を閉ã˜ã‚‹ Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. ãƒ‡ãƒ¼ã‚¿é–²è¦§ã«æ–°ã—ã„åå‰ã‚’付ã‘ã¾ã™ã€‚'&&'を付ã‘ã‚‹ã¨ãã®æ¬¡ã®æ–‡å­—をキーボードã®ã‚·ãƒ§ãƒ¼ãƒˆã‚«ãƒƒãƒˆã«ã§ãã¾ã™ã€‚ VacuumDialog Compact Database データベースを圧縮 Warning: Compacting the database will commit all of your changes. 警告: データベースã®åœ§ç¸®ã¯ã‚ãªãŸã®å¤‰æ›´ã‚’ã™ã¹ã¦ã‚³ãƒŸãƒƒãƒˆã—ã¾ã™ã€‚ Please select the databases to co&mpact: 圧縮ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é¸æŠžã—ã¦ãã ã•ã„(&M): sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_ko_KR.ts000066400000000000000000014115251463772530400256130ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite ~ì— ëŒ€í•˜ì—¬.. 보다는 ~~ ì •ë³´ ë¼ëŠ” í‘œí˜„ì„ ìš”ì¦˜ì— ë§Žì´ ì‚¬ìš©í•¨. DB Browser for SQLite ì •ë³´ Version 버전 <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> <html><head/><body><p>DB Browser for SQLite는 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±, ë””ìžì¸ ë° íŽ¸ì§‘í•˜ëŠ” ë° ì‚¬ìš©ë˜ëŠ” 오픈 소스 프리웨어 ì‹œê° ë„구입니다.</p><p>Mozilla Public License 버전 2와 GNU General Public License 버전 3 ì´ìƒì— ë”°ë¼ ì´ì¤‘ ë¼ì´ì„ ìŠ¤ê°€ ì ìš©ë©ë‹ˆë‹¤. ì´ëŸ¬í•œ ë¼ì´ì„ ìФ ì¡°ê±´ì— ë”°ë¼ ìˆ˜ì •í•˜ê±°ë‚˜ 재배í¬í•  수 있습니다.</p><p>ìžì„¸í•œ ì‚¬í•­ì€ <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> ë° <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a>ì„ í™•ì¸í•˜ì„¸ìš”.</p><p>ì´ í”„ë¡œê·¸ëž¨ì— ëŒ€í•œ ìžì„¸í•œ ë‚´ìš©ì€ ì›¹ì‚¬ì´íЏì—서 확ì¸í•˜ì„¸ìš”: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">ì´ ì†Œí”„íŠ¸ì›¨ì–´ëŠ” 다ìŒì˜ GPL/LGPL Qt íˆ´í‚·ì„ ì‚¬ìš©í•©ë‹ˆë‹¤.</span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;"> https://qt-project.org/</span></a><span style=" font-size:small;"><br/>ìžì„¸í•œ ë¼ì´ì„¼ìФ 약관 ë° ì •ë³´ëŠ” </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;">를 확ì¸í•˜ì„¸ìš”.</span></p><p><span style=" font-size:8pt;">ì €í¬ëŠ” SQLite 확장 ì§€ì›ì„ 위해 nalgeon/sqlean ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 사용합니다.<br/>ì´ ë¼ì´ë¸ŒëŸ¬ë¦¬ëŠ” MIT ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ ë¼ì´ì„ ìŠ¤ê°€ 부여ë˜ë©°, ìžì„¸í•œ ë‚´ìš©ì€ ë‹¤ìŒì„ 참조하세요:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">ë˜í•œ í¬ë¦¬ì—ì´í‹°ë¸Œ 커먼즈 저작ìží‘œì‹œ ë™ì¼ì¡°ê±´ë³€ê²½í—ˆë½ 4.0 ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ Michael Buckleyê°€ 설정한 파스텔 SVG ì•„ì´ì½˜ì„ 사용합니다.<br/>ìžì„¸í•œ ì‚¬í•­ì€ </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> ì„ í™•ì¸í•˜ì„¸ìš”.</span></p></body></html> AddRecordDialog Add New Record 새 레코드 추가 Enter values for the new record considering constraints. Fields in bold are mandatory. 제약 ì¡°ê±´ì„ ê³ ë ¤í•˜ì—¬ 새 레코드를 위한 ê°’ì„ ìž…ë ¥í•˜ì„¸ìš”. 진하게 ì²˜ë¦¬ëœ í•„ë“œëŠ” 반드시 입력해야 합니다. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. ê°’ 필드ì—는 ì´ë¦„ í•„ë“œì— ëŒ€ì‘하는 ê°’ì„ ìž…ë ¥ í•  수 있습니다. 타입 필드는 í•„ë“œì˜ íƒ€ìž…ì„ ì˜ë¯¸í•©ë‹ˆë‹¤. 기본 ê°’ì€ NULLê°’ê³¼ ê°™ì€ ìŠ¤íƒ€ì¼ë¡œ 표시ë©ë‹ˆë‹¤. Name ì´ë¦„ Type 타입 Value ê°’ Values to insert. Pre-filled default values are inserted automatically unless they are changed. 추가할 값들입니다. 기본 ê°’ë“¤ì´ ë¯¸ë¦¬ ìž…ë ¥ë˜ì–´ 있어 수정하지 않는다면 ìžë™ì ìœ¼ë¡œ 들어갑니다. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. 위 í”„ë ˆìž„ì˜ ê°’ì„ ìˆ˜ì •í•˜ë©´, ìˆ˜ì •ì‚¬í•­ì´ ë°˜ì˜ëœ 레코드 추가 SQL쿼리가 ì—¬ê¸°ì— ë‚˜íƒ€ë‚©ë‹ˆë‹¤. 저장하기 ì „ì´ë¼ë©´ ì§ì ‘ 쿼리를 수정할 ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">저장하기</span>는 새 레코드를 ë°ì´í„°ë² ì´ìŠ¤ì— ì¶”ê°€í•˜ê¸° 위해 작성ë˜ì–´ 나타나 있는 SQL êµ¬ë¬¸ì„ ë°˜ì˜í•©ë‹ˆë‹¤.</p><p><span style=" font-weight:600;">초기값 ë³µì›í•˜ê¸°</span>는 <span style=" font-weight:600;">ê°’</span> 필드를 초기 값으로 ë³µì›í•©ë‹ˆë‹¤.</p><p><span style=" font-weight:600;">취소하기</span>는 ì¿¼ë¦¬ì˜ ì‹¤í–‰ ì—†ì´ ì´ ì°½ì„ ë‹«ìŠµë‹ˆë‹¤.</p></body></html> Auto-increment ìžë™ ì¦ê°€(Auto-increment) Unique constraint ìœ ë‹ˆí¬ ì œì•½ Check constraint: %1 제약 ì¡°ê±´: %1 Foreign key: %1 외래키: %1 Default value: %1 기본 ê°’: %1 Error adding record. Message from database engine: %1 레코드 추가 ë„중 ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë°ì´í„°ë² ì´ìФ 엔진 메시지: %1 Are you sure you want to restore all the entered values to their defaults? ì •ë§ë¡œ 모든 입력한 ê°’ë“¤ì„ ì´ˆê¸° 값으로 ë³µì›í•©ë‹ˆê¹Œ? Application Possible command line arguments: 사용할 수 있는 명령줄 매개변수: The user settings file location is replaced with the argument value instead of the environment variable value. ì‚¬ìš©ìž í™˜ê²½ì„¤ì • íŒŒì¼ ìœ„ì¹˜ëŠ” 환경 변수 ê°’ 대신 ì¸ìž 값으로 대체ë©ë‹ˆë‹¤. Ignored environment variable (DB4S_SETTINGS_FILE) value: 무시ë˜ëŠ” 환경변수(DB4S_SETTINGS_FILE) ê°’ : The file %1 does not exist %1 파ì¼ì´ 존재하지 않습니다 Usage 사용법 options 옵션 database ë°ì´í„°ë² ì´ìФ project 프로ì íЏ csv-file CSV íŒŒì¼ Show command line options 명령줄 옵션 출력 Exit application after running scripts 스í¬ë¦½íЏ 실행 후 ì‘ìš© 프로그램 종료 file íŒŒì¼ Execute this SQL file after opening the DB DB를 ì—° 후 ì´ SQL 파ì¼ì„ 실행합니다 Import this CSV file into the passed DB or into a new DB CSV 파ì¼ì„ 불러온 후 기존 DB ë˜ëŠ” 새 DBì— ë°˜ì˜í•©ë‹ˆë‹¤ table í…Œì´ë¸” Browse this table, or use it as target of a data import 해당 í…Œì´ë¸”ì„ íƒìƒ‰í•˜ê±°ë‚˜, ë°ì´í„°ë¥¼ 가져올 ëŒ€ìƒ í…Œì´ë¸”로 ì„ íƒí•©ë‹ˆë‹¤ Open database in read-only mode ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ì½ê¸° ì „ìš© 모드로 엽니다 settings_file 설정 íŒŒì¼ Run application based on this settings file ì´ ì„¤ì • 파ì¼ì„ 기반으로 ì‘ìš© í”„ë¡œê·¸ëž¨ì„ ì‹¤í–‰í•©ë‹ˆë‹¤ group 그룹 settings 설정 value ê°’ Run application with this setting temporarily set to value 임시ì ìœ¼ë¡œ 해당 설정 ê·¸ë£¹ì„ ì§€ì • 값으로 설정한 후, ì‘ìš© í”„ë¡œê·¸ëž¨ì„ ì‹¤í–‰í•©ë‹ˆë‹¤ Run application saving this value for this setting ì‘ìš© í”„ë¡œê·¸ëž¨ì„ ì‹¤í–‰í•˜ë©° ì´ ì„¤ì • ê°’ì„ ì €ìž¥í•©ë‹ˆë‹¤ Display the current version 현재 ë²„ì „ì„ ì¶œë ¥í•©ë‹ˆë‹¤ Open this SQLite database SQLite ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 엽니다 Open this project file (*.sqbpro) 프로ì íЏ íŒŒì¼ (*.sqbpro)를 엽니다 Import this CSV file into an in-memory database 메모리 ë°ì´í„°ë² ì´ìŠ¤ì— ì´ CSV 파ì¼ì„ 가져옵니다 The %1 option requires an argument %1 ì˜µì…˜ì€ ì¸ìž ê°’ì„ í•„ìš”ë¡œ 합니다 The -S/--settings option requires an argument. The option is ignored. -S/--settings ì˜µì…˜ì€ ì¸ìž ê°’ì´ í•„ìš”í•©ë‹ˆë‹¤. ë”°ë¼ì„œ ì´ ì˜µì…˜ì€ ë¬´ì‹œë©ë‹ˆë‹¤. The -o/--option and -O/--save-option options require an argument in the form group/setting=value -o/--option ë˜ëŠ” -O/--save-option ì˜µì…˜ì€ group/setting=value 형ì‹ì˜ ì¸ìˆ˜ê°€ 필요합니다 Invalid option/non-existent file: %1 ìž˜ëª»ëœ ì˜µì…˜ì„ ì‚¬ìš©í•˜ì˜€ê±°ë‚˜ 파ì¼ì´ 존재하지 않습니다: %1 SQLite Version SQLite 버전 SQLCipher Version %1 (based on SQLite %2) SQLCipher 버전 %1 (SQLite %2 기반) DB Browser for SQLite Version %1. DB Browser for SQLite 버전 %1. Last commit hash when built: %1 빌드 당시 최종 깃 해시 ê°’: %1 Built for %1, running on %2 %1 í™˜ê²½ì„ ìœ„í•´ 빌드ë¨, %2 환경ì—서 실행 중 Qt Version %1 Qt 버전 %1 CipherDialog SQLCipher encryption SQLCipher 암호화 &Password 암호(&P) &Reenter password 암호 재입력(&R) Encr&yption settings 암호화 설정(&Y) SQLCipher &3 defaults SQLCipher &3 기본값 SQLCipher &4 defaults SQLCipher &4 기본값 Custo&m 수ë™(&M) Page si&ze 페ì´ì§€ í¬ê¸°(&Z) &KDF iterations &KDF 반복 횟수 HMAC algorithm HMAC 알고리즘 KDF algorithm KDF 알고리즘 Plaintext Header Size í‰ë¬¸ í—¤ë” í¬ê¸° Passphrase 암호 Raw key Raw 키 Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 암호화할 때 사용할 키를 지정해주세요. [주ì˜] ì—¬ëŸ¬ë¶„ì´ ì¶”ê°€ì ì¸ ì„¤ì •ì„ ë³€ê²½í•œë‹¤ë©´, ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì—´ 때마다 암호를 매번 입력해야합니다. 그러한 ë¶ˆíŽ¸í•¨ì„ í”¼í•˜ê¸° 위해 암호화를 하지 않으려면 암호 필드를 비워ë‘세요 암호화 ìž‘ì—…ì€ ì‹œê°„ì´ ì¢€ 걸릴 수 있습니다. 그리고 ê¼­ ì—¬ëŸ¬ë¶„ì˜ ë°ì´í„°ë² ì´ìФ ë°±ì—…ë³¸ì„ ë°˜ë“œì‹œ 만들어ë‘세요! 암호화 작업 ì´ì „ì— í•œ 저장ë˜ì§€ ì•Šì€ ë³€ê²½ ì‚¬í•­ë„ ë°˜ì˜ë˜ë‹ˆ 주ì˜í•˜ì„¸ìš”. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 암호화기 위해 사용할 키를 다시 입력해주세요. ë°ì´í„°ë² ì´ìФ 파ì¼ì„ 변경하기 위해서는 ì´ ì •ë³´ë¥¼ 다시 입력해야만 합니다. ColumnDisplayFormatDialog Choose display format 표시 형ì‹ì„ ì„ íƒí•˜ì„¸ìš” Display format 표시 í˜•ì‹ Choose a display format for the column '%1' which is applied to each value prior to showing it. '%1' ì»¬ëŸ¼ì˜ í‘œì‹œ 형ì‹ì„ ì„ íƒí•˜ì„¸ìš”. Default ì¼ë°˜ Decimal number ìˆ«ìž Exponent notation 지수 Hex blob ì´ì§„ ë°ì´í„° Hex number 16진수 Apple NSDate to date Apple NSDate ë‚ ì§œ Java epoch (milliseconds) to date Java 시간(밀리초)ì„ ë‚ ì§œë¡œ .NET DateTime.Ticks to date .NET DateTime Ticks를 날짜로 Julian day to date ë‚ ì§œ Unix epoch to local time 유닉스 시간(타임스탬프)ì„ ì§€ì—­ 시간으로 WebKit / Chromium epoch to date WebKit / Chromiumì„ ë‚ ì§œë¡œ WebKit / Chromium epoch to local time 로WebKit / Chromium ì‹œê°„ì„ ì§€ì—­ 시간으로 Date as dd/mm/yyyy 날짜를 dd/mm/yyyy 형태로 Lower case ì†Œë¬¸ìž Binary GUID to text ë°”ì´ë„ˆë¦¬ GUID를 í…스트로 SpatiaLite Geometry to SVG SpatiaLite Geometry를 SVG로 Custom display format must contain a function call applied to %1 ì‚¬ìš©ìž ì •ì˜ í‘œì‹œ 형ì‹ì€ %1ì— ì ìš©ëœ 함수 í˜¸ì¶œì„ í¬í•¨í•´ì•¼ 합니다 Error in custom display format. Message from database engine: %1 ì‚¬ìš©ìž ì •ì˜ í‘œì‹œ 형ì‹ì—서 ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë°ì´í„°ë² ì´ìФ ì—”ì§„ì˜ ë©”ì‹œì§€: %1 Custom display format must return only one column but it returned %1. ì‚¬ìš©ìž ì§€ì • 표시 형ì‹ì€ í•˜ë‚˜ì˜ ì—´ë§Œ 반환해야 하지만 %1개를 반환했습니다. Octal number 8진수 Round number ë¼ìš´ë“œ 수 Unix epoch to date 유닉스 시간(타임스탬프)ì„ ë‚ ì§œë¡œ Upper case ëŒ€ë¬¸ìž Windows DATE to date Windows ë‚ ì§œ Custom ì‚¬ìš©ìž ì§€ì • CondFormatManager Conditional Format Manager ì¡°ê±´ë¶€ ì„œì‹ ê´€ë¦¬ìž This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. ì´ ëŒ€í™”ìƒìžì—서는 ì¡°ê±´ë¶€ 형ì‹ì„ 추가하고 수정할 수 있습니다. ê° ì…€ 스타ì¼ì€ 해당 ì…€ ë°ì´í„°ì˜ 첫번째 ì¡°ê±´ì— ì˜í•´ 지정ë©ë‹ˆë‹¤. ì¡°ê±´ë¶€ 서ì‹ì€ 위/아래로 ì´ë™í•  수 있으며, ìƒìœ„ í–‰ì— ìžˆëŠ” 형ì‹ì€ 하위 í–‰ì— ìžˆëŠ” 형ì‹ë³´ë‹¤ ìš°ì„ ë©ë‹ˆë‹¤. ì¡°ê±´ êµ¬ë¬¸ì€ í•„í„°ì™€ ë™ì¼í•˜ë©° 빈 ì¡°ê±´ì€ ëª¨ë“  ê°’ì— ëŒ€í•´ ì ìš©ë©ë‹ˆë‹¤. Add new conditional format 새 ì¡°ê±´ë¶€ 서ì‹ì„ 추가합니다 &Add 추가(&A) Remove selected conditional format ì„ íƒí•œ ì¡°ê±´ë¶€ 서ì‹ì„ 삭제합니다 &Remove ì‚­ì œ(&R) Move selected conditional format up ì„ íƒí•œ ì¡°ê±´ë¶€ 서ì‹ì„ 위로 ì´ë™í•©ë‹ˆë‹¤ Move &up 위로 올리기(&U) Move selected conditional format down ì„ íƒí•œ ì¡°ê±´ë¶€ 서ì‹ì„ 아래로 ì´ë™í•©ë‹ˆë‹¤ Move &down 아래로 내리기(&D) Foreground 전경색 Text color 글ìžìƒ‰ Background 배경색 Background color 배경색 Font 글꼴 Size í¬ê¸° Bold 진하게 Italic 기울임 Underline 밑줄 Alignment ì •ë ¬ Condition ì¡°ê±´ Click to select color 색ìƒì„ ì„ íƒí•˜ì„¸ìš” Are you sure you want to clear all the conditional formats of this field? ì´ í•„ë“œì˜ ëª¨ë“  ì¡°ê±´ë¶€ 서ì‹ì„ ì •ë§ë¡œ 삭제하시겠습니까? DBBrowserDB Please specify the database name under which you want to access the attached database ë°ì´í„°ë² ì´ìФ ì—°ê²°ì„ ìœ„í•´ 불러올 ë°ì´í„°ë² ì´ìŠ¤ì˜ ë³„ì¹­ì„ ì§€ì •í•´ì£¼ì„¸ìš” Invalid file format ìž˜ëª»ëœ íŒŒì¼ í¬ë§·ìž…니다 Do you want to save the changes made to the database file %1? %1 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ê² ìŠµë‹ˆê¹Œ? Exporting database to SQL file... ë°ì´í„°ë² ì´ìŠ¤ë¥¼ SQL 파ì¼ë¡œ 내보내는 중... Cancel 취소 Executing SQL... SQL 실행 중... Action cancelled. ì‹¤í–‰ì´ ì·¨ì†Œë˜ì—ˆìŠµë‹ˆë‹¤. Do you really want to close this temporary database? All data will be lost. ì´ ìž„ì‹œ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ë‹«ì„까요? 모든 ë°ì´í„°ê°€ 사ë¼ì§‘니다. Database didn't close correctly, probably still busy ë°ì´í„°ë² ì´ìŠ¤ê°€ 제대로 닫히지 않았습니다, ì•„ë§ˆë„ ì•„ì§ ì‚¬ìš© ì¤‘ì¼ ê²ƒìž…ë‹ˆë‹¤ Cannot open destination file: '%1' ëŒ€ìƒ íŒŒì¼ì„ ì—´ 수 없습니다.: '%1' Cannot backup to file: '%1'. Message: %2 파ì¼ë¡œ 백업할 수 없습니다.: '%1'. 메시지: %2 The database is currently busy: ì´ ë°ì´í„°ë² ì´ìŠ¤ëŠ” 현재 사용 중입니다: Do you want to abort that other operation? ì´ ëª…ë ¹ì„ ì·¨ì†Œí•˜ì‹œê² ìŠµë‹ˆê¹Œ? No database file opened 열린 ë°ì´í„°ë² ì´ìФ 파ì¼ì´ 없습니다 Error in statement #%1: %2. Aborting execution%3. #%1: %2 êµ¬ë¬¸ì— ì—러가 있어 ì‹¤í–‰ì´ ì¤‘ë‹¨ë˜ì—ˆìŠµë‹ˆë‹¤%3. and rolling back 그리고 롤백합니다 didn't receive any output from %1 %1ì—서 아무런 ì¶œë ¥ì„ ë°›ì§€ 못했습니다 could not execute command: %1 ëª…ë ¹ì„ ì‹¤í–‰í•  수 없습니다: %1 Cannot delete this object ì´ ê°ì²´ë¥¼ 삭제할 수 없습니다 Cannot set data on this object ì´ ê°ì²´ì—는 ë°ì´í„°ë¥¼ 저장할 수 없습니다 A table with the name '%1' already exists in schema '%2'. '%1' ì´ë¦„ì˜ í…Œì´ë¸”ì´ ì´ë¯¸ 스키마 '%2'ì— ì¡´ìž¬í•©ë‹ˆë‹¤. No table with name '%1' exists in schema '%2'. 스키마 '%2'ì— ì´ë¦„ì´ '%1'ì¸ í…Œì´ë¸”ì´ ì—†ìŠµë‹ˆë‹¤. Cannot find column %1. %1 ì»¬ëŸ¼ì„ ì°¾ì„ ìˆ˜ 없습니다. Creating savepoint failed. DB says: %1 세ì´ë¸Œ í¬ì¸íŠ¸ë¥¼ ìƒì„±í•˜ì§€ 못했습니다. DB 메시지: %1 Renaming the column failed. DB says: %1 ì—´ ì´ë¦„ì„ ë³€ê²½í•˜ì§€ 못했습니다. DB 메시지: %1 Releasing savepoint failed. DB says: %1 세ì´ë¸Œ í¬ì¸íŠ¸ë¥¼ 해제하지 못했습니다. DB 메시지: %1 Creating new table failed. DB says: %1 새 í…Œì´ë¸”ì„ ìƒì„±í•˜ì§€ 못했습니다. DB 메시지: %1 Copying data to new table failed. DB says: %1 새 í…Œì´ë¸”ì— ë°ì´í„°ë¥¼ 복사하지 못했습니다. DB 메시지: %1 Deleting old table failed. DB says: %1 ì´ì „ í…Œì´ë¸”ì„ ì‚­ì œí•˜ì§€ 못했습니다. DB 메시지: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 í…Œì´ë¸” '%1'ì˜ ì´ë¦„ì„ '%2'(으)로 변경하는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë°ì´í„°ë² ì´ìФ 엔진 메시지: %3 could not get list of db objects: %1 DB 개체 목ë¡ì„ 가져알 수 없습니다: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: ì´ í…Œì´ë¸”ì— ê´€ë ¨ëœ ëª‡ ê°œì˜ ê°ì²´ë¥¼ ë³µì›í•˜ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤. ì´ëŸ¬í•œ 경우는 대부분 몇 ê°œì˜ í•„ë“œëª…ì´ ë³€ê²½ë˜ì–´ì„œ ë°œìƒ í–ˆì„ ê°€ëŠ¥ì„±ì´ í½ë‹ˆë‹¤. 아래 SQL êµ¬ë¬¸ì„ ì°¸ê³ í•˜ë©´ ì§ì ‘ 수ë™ìœ¼ë¡œ ê³ ì³ì„œ 실행할 수 ìžˆì„ ê²ƒìž…ë‹ˆë‹¤: could not get list of databases: %1 ë°ì´í„°ë² ì´ìФ 목ë¡ì„ 가져올 수 없습니다: %1 Error loading extension: %1 í™•ìž¥ê¸°ëŠ¥ì„ ë¶ˆëŸ¬ì˜¤ê¸° ì—러: %1 Error loading built-in extension: %1 내장 í™•ìž¥ê¸°ëŠ¥ì„ ë¶ˆëŸ¬ì˜¤ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤: %1 could not get column information ì—´ 정보를 가져올 수 없습니다 Error setting pragma %1 to %2: %3 pragma ì„¤ì •ì„ %1ì—서 %2로 ë³€ê²½í•˜ëŠ”ë° ì—러: %3 File not found. 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다. DbStructureModel Name ì´ë¦„ Object ê°ì²´ Type 타입 Schema 스키마 Database ë°ì´í„°ë² ì´ìФ Browsables 열기 All ëª¨ë‘ ì„ íƒ Temporary 임시 Tables (%1) í…Œì´ë¸” (%1) Indices (%1) ì¸ë±ìФ (%1) Views (%1) ë·° (%1) Triggers (%1) 트리거 (%1) EditDialog Edit database cell ë°ì´í„°ë² ì´ìФ ë°ì´í„° ê°’ì„ ìˆ˜ì •í•˜ê¸° Mode: 모드: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. ì…€ ì—디터ì—서 ì§€ì›ë˜ëŠ” 모ë¸ë“¤ 목ë¡ìž…니다. 현재 ì…€ì˜ ë°ì´í„°ë¥¼ 보거나 수정하기 위한 모드를 ì„ íƒí•˜ì„¸ìš”. RTL Text RTL Text Image ì´ë¯¸ì§€ JSON JSON XML XML Evaluation í‰ê°€ Automatically adjust the editor mode to the loaded data type 불러온 ë°ì´í„° íƒ€ìž…ì„ ì—디터 ëª¨ë“œì— ìžë™ ì ìš© This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. ì´ ì²´í¬ ë²„íŠ¼ì€ ì—디터 모드를 ìžë™ìœ¼ë¡œ 변경하는 ê¸°ëŠ¥ì„ í‚¤ê±°ë‚˜ ë•니다. 새 ì…€ì´ ì„ íƒë˜ê±°ë‚˜ 새로운 ë°ì´í„°ê°€ 가져와지면 ìžë™ 변경 ê¸°ëŠ¥ì´ ì¼œì ¸ì„œ ë°ì´í„° íƒ€ìž…ì„ ì¸ì‹í•˜ì—¬ ì ì ˆí•œ 모드를 ì ìš©í•©ë‹ˆë‹¤. ê·¸ í›„ì— ì—¬ëŸ¬ë¶„ì€ ëª¨ë“œë¥¼ 수ë™ìœ¼ë¡œ 변경할 수 있습니다. 만약 ì…€ë“¤ì„ ì´ë™í•  때 모드를 ì§ì ‘ ë³€ê²½í•˜ê³ ìž í•œë‹¤ë©´, ì´ ë²„íŠ¼ì„ ë¹„í™œì„±í™”í•˜ì„¸ìš”. Auto-switch ìžë™ 전환 This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. ì´ Qt 편집기는 기본 í…스트 편집기ì—서 ì§€ì›í•˜ì§€ 않는 오른쪽ì—서 왼쪽으로 쓰는 스í¬ë¦½íŠ¸ì— ì‚¬ìš©ë©ë‹ˆë‹¤. 오른쪽ì—서 왼쪽으로 작성ë˜ëŠ” 문ìžê°€ ê°ì§€ë˜ë©´ ì´ íŽ¸ì§‘ê¸° 모드가 ìžë™ìœ¼ë¡œ ì„ íƒë©ë‹ˆë‹¤. Identification of the cell currently in the editor 현재 íŽ¸ì§‘ê¸°ì— ìžˆëŠ” ì…€ì˜ ì •ì˜ Type and size of data currently in table 현재 í…Œì´ë¸”ì— ìžˆëŠ” ë°ì´í„°ì˜ 유형 ë° í¬ê¸° Apply data to cell ì…€ì— ë°ì´í„° ì ìš© Open preview dialog for printing the data currently stored in the cell 현재 ì…€ì— ì €ìž¥ëœ ë°ì´í„°ì— 대한 ì¸ì‡„ 미리보기 대화ìƒìž 열기 Auto-format: pretty print on loading, compact on saving. ìžë™í¬ë§·: 불러올 때 예ì˜ê²Œ 프린트ë˜ê³ , 저장할 때 ìš©ëŸ‰ì„ ì¤„ìž…ë‹ˆë‹¤. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. 활성화ë˜ë©´, ìžë™í¬ë§· ê¸°ëŠ¥ì´ ë°ì´í„°ë¥¼ 불러올 때 í¬ë§·ì„ 지정하여 긴 ë¬¸ìž¥ì„ ì—¬ëŸ¬ 행으로 만들고 들여쓰기를 해서 ê°€ë…ì„±ì„ í–¥ìƒí•©ë‹ˆë‹¤. ë°ì´í„°ë¥¼ 저장할 때는 ìžë™í¬ë§· ê¸°ëŠ¥ì€ ê°œí–‰ 문ìžë¥¼ 제거하여 ë°ì´í„°ë¥¼ 줄ì´ê³  í•„ìš” 없는 ê³µë°±ì„ ì‚­ì œí•©ë‹ˆë‹¤. Word Wrap 개행 Wrap lines on word boundaries 단어 경계마다 개행 Open in default application or browser 기본 ì‘ìš© 프로그램 ë˜ëŠ” 브ë¼ìš°ì €ì—서 열기 Open in application ì‘ìš© 프로그램ì—서 열기 The value is interpreted as a file or URL and opened in the default application or web browser. ê°’ì€ íŒŒì¼ ë˜ëŠ” URL로 í•´ì„ë˜ë©° 기본 애플리케ì´ì…˜ ë˜ëŠ” 웹 브ë¼ìš°ì €ì—서 열립니다. Save file reference... 참조를 파ì¼ì— 저장... Save reference to file 파ì¼ì— 참조 저장 Open in external application 외부 프로그램ì—서 열기 Autoformat ìžë™í¬ë§· The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. í…스트 편집기 모드를 사용하면 저장하기 ì „ì— êµ¬ë¬¸ ê°•ì¡°, ìžë™ ì„œì‹ ë° ìœ íš¨ì„± 검사를 통해 ì¼ë°˜ í…스트는 물론 JSON ë˜ëŠ” XML ë°ì´í„°ë¥¼ 편집할 수 있습니다. 오류는 빨간색 물결선 밑줄로 표시ë©ë‹ˆë‹¤. í‰ê°€ 모드ì—서 입력한 SQLite 표현ì‹ì´ í‰ê°€ë˜ê³  결과가 ì…€ì— ì ìš©ë©ë‹ˆë‹¤. &Export... 내보내기(&E)... &Import... 가져오기(&I)... Import from file 파ì¼ì—서 가져오기 Opens a file dialog used to import any kind of data to this database cell. ì´ ë°ì´í„°ë² ì´ìФ 셀로 ë°ì´í„°ë¥¼ 가져오기 위하여 대화ìƒìžë¥¼ 엽니다. Export to file 파ì¼ë¡œ 내보내기 Opens a file dialog used to export the contents of this database cell to a file. ì´ ë°ì´í„°ë² ì´ìФ ì…€ì˜ ë‚´ìš©ì„ íŒŒì¼ë¡œ ë‚´ë³´ë‚´ëŠ”ë° ì‚¬ìš©ë˜ëŠ” 대화 ìƒìžë¥¼ 엽니다. Print... Ctrl+P Open preview dialog for printing displayed text ì¶œë ¥ëœ í…스트를 ì¸ì‡„하기 위한 ì¸ì‡„ 미리보기 ì°½ì„ ì—½ë‹ˆë‹¤ Copy Hex and ASCII Hex와 ASCII를 복사합니다 Copy selected hexadecimal and ASCII columns to the clipboard ì„ íƒëœ 16진수와 ASCII 필드를 í´ë¦½ë³´ë“œë¡œ 복사합니다 Ctrl+Shift+C Set as &NULL NULL로 만들기(&N) This button saves the changes performed in the cell editor to the database cell. ì´ ë²„íŠ¼ì€ ë°ì´í„° ì…€ì— ì…€ ì—ë””í„°ì˜ ë³€ê²½ ì‚¬í•­ì„ ì ìš©í•˜ì—¬ 저장하는 버튼입니다. Apply ì ìš© Text 문ìžì—´ Binary ë°”ì´ë„ˆë¦¬ Erases the contents of the cell ì…€ì˜ ë°ì´í„° ê°’ì„ ì‚­ì œí•©ë‹ˆë‹¤ This area displays information about the data present in this database cell ì´ ì˜ì—­ì€ ì´ ë°ì´í„°ë² ì´ìФ ë°ì´í„° ê°’ì— ëŒ€í•œ 정보를 ë³´ì—¬ì¤ë‹ˆë‹¤ Choose a filename to export data 내보내기 í•  ë°ì´í„°ì˜ íŒŒì¼ ì´ë¦„ì„ ì„ íƒí•˜ì„¸ìš” Image data can't be viewed in this mode. ì´ë¯¸ì§€ ë°ì´í„°ëŠ” ì´ ëª¨ë“œì—서는 ë³¼ 수 없습니다. The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? ì…€ íŽ¸ì§‘ê¸°ì— ì•„ì§ ë°ì´í„°ë² ì´ìŠ¤ì— ì ìš©ë˜ì§€ ì•Šì€ ë°ì´í„°ê°€ 있습니다. 편집한 ë°ì´í„°ë¥¼ row=%1, column=%2ì— ì ìš©í•˜ì‹œê² ìŠµë‹ˆê¹Œ? Editing row=%1, column=%2 í–‰=%1, ì—´=%2 편집 중 No cell active. í™œì„±í™”ëœ ì…€ì´ ì—†ìŒ. Try switching to Image or Binary mode. ì´ë¯¸ì§€ë‚˜ ë°”ì´ë„ˆë¦¬ 모드로 바꿔보세요. Binary data can't be viewed in this mode. ë°”ì´ë„ˆë¦¬ ë°ì´í„°ëŠ” ì´ ëª¨ë“œì—서 ë³¼ 수 없습니다. Try switching to Binary mode. ë°”ì´ë„ˆë¦¬ 모드로 바꿔보세요. Image files (%1) ì´ë¯¸ì§€ íŒŒì¼ (%1) Binary files (*.bin) ë°”ì´ë„ˆë¦¬ íŒŒì¼ (*.bin) Type: NULL; Size: 0 bytes 타입: NULL; í¬ê¸°: 0 ë°”ì´íЏ Type: Text / Numeric; Size: %n character(s) 타입: í…스트/숫ìž; í¬ê¸°: %nìž Type: %1 Image; Size: %2x%3 pixel(s) 타입: %1 ì´ë¯¸ì§€; í¬ê¸°: %2x%3픽셀 Type: Valid JSON; Size: %n character(s) 타입: 유효한 JSON; í¬ê¸°: %nìž Type: Binary; Size: %n byte(s) 타입: ë°”ì´ë„ˆë¦¬; í¬ê¸°: %n ë°”ì´íЏ Choose a file to import 가져올 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” Unsaved data in the cell editor ì…€ íŽ¸ì§‘ê¸°ì— ì €ìž¥ë˜ì§€ ì•Šì€ ë°ì´í„° %1 Image %1 ì´ë¯¸ì§€ Invalid data for this mode ì´ ëª¨ë“œì— ë§žì§€ 않는 ë°ì´í„° The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? ì´ ì…€ì—는 올바르지 ì•Šì€ %1 ë°ì´í„°ë¥¼ í¬í•¨í•˜ê³  있습니다. ì´ìœ : %2. ì´ ì…€ì„ ì •ë§ë¡œ ì ìš©í• ê¹Œìš”? Couldn't save file: %1. 파ì¼ì„ 저장할 수 없습니다: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. ë°ì´í„°ëŠ” 임시 파ì¼ì— 저장ë˜ì—ˆìœ¼ë©° 기본 ì‘ìš© 프로그램으로 열렸습니다. ì´ì œ 파ì¼ì„ 편집할 수 있으며 ìž‘ì—…ì´ ì™„ë£Œë˜ë©´ ì €ìž¥ëœ ìƒˆ ë°ì´í„°ë¥¼ ì…€ì— ì ìš©í•˜ê±°ë‚˜ ë³€ê²½ì‚¬í•­ì„ ì·¨ì†Œí•  수 있습니다. EditIndexDialog &Name ì´ë¦„(&N) Order ì •ë ¬ 순서 &Table í…Œì´ë¸”(&T) Edit Index Schema ì¸ë±ìФ 스키마 수정 &Unique 유니í¬(&U) For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed ì¸ë±ìŠ¤ë¥¼ í…Œì´ë¸”ì˜ ì¼ë¶€ë¡œë§Œ 제한하기 위해서 ì¸ë±ì‹± 해야하는 í…Œì´ë¸”ì˜ ì¼ë¶€ë¥¼ 지정하는 WHERE ì ˆì„ ì§€ì •í•  수 있습니다 Partial inde&x clause 부분(Partial) ì¸ë±ìŠ¤ì ˆ(&X) Colu&mns ì—´(&M) Table column í…Œì´ë¸” ì—´ Type 타입 Add a new expression column to the index. Expression columns contain SQL expression rather than column names. ì¸ë±ìŠ¤ì— ìƒˆ í‘œí˜„ì‹ ì»¬ëŸ¼ì„ ì¶”ê°€í•˜ì„¸ìš”. í‘œí˜„ì‹ ì»¬ëŸ¼ì€ ì»¬ëŸ¼ ì´ë¦„ 대신 SQL 표현ì‹ì´ 들어갑니다. Index column ì¸ë±ìФ 컬럼 Deleting the old index failed: %1 ì´ì „ ì¸ë±ìŠ¤ë¥¼ ì‚­ì œí•˜ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤: %1 Creating the index failed: %1 ì¸ë±ìФ ìƒì„±ì— 실패했습니다: %1 EditTableDialog Edit table definition í…Œì´ë¸” ì •ì˜ ë³€ê²½ Table í…Œì´ë¸” Advanced 고급 Without Rowid Rowid 필드 ì—†ìŒ Fields 필드 Database sche&ma ë°ì´í„°ë² ì´ìФ 스키마(&M) Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. ì´ í…Œì´ë¸”ì„ 'WITHOUT ROWID' í…Œì´ë¸”로 만듭니다. ì´ í”Œëž˜ê·¸ë¥¼ 설정하려면 PRIMARY KEY(모든 ìœ í˜•ì´ ë  ìˆ˜ 있으며 ë³µí•©í˜•ì¼ ìˆ˜ 있ìŒ)를 지정해야 하며 AUTOINCREMENT 플래그는 금지ë©ë‹ˆë‹¤. On Conflict ì¶©ëŒ ì‹œ Strict 엄격 모드 When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. 엄격 모드 ì˜µì…˜ì´ í™œì„±í™”ë˜ë©´ SQLite는 ë°ì´í„°ë¥¼ ì—…ë°ì´íŠ¸í•˜ê±°ë‚˜ 삽입할 때 ê° ì—´ì˜ ë°ì´í„° ìœ í˜•ì„ ì ìš©í•©ë‹ˆë‹¤. Add 추가 Remove ì‚­ì œ Move to top 최ìƒë‹¨ìœ¼ë¡œ 올리기 Move up 위로 올리기 Move down 아래로 내리기 Move to bottom 최하단으로 내리기 Name 필드명 Type 타입 NN NN Not null Not null PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> 기본 키</p></body></html> AI AI Autoincrement ìžë™ ì¦ê°€(Autoincrement) U U Unique 유니í¬(Unique) Default 기본값 Default value 기본값 Check ì²´í¬ Check constraint 제약조건(Check constraint) Collation 콜레ì´ì…˜ Foreign Key 외래키 <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> 외래 키</p></body></html> Index Constraints ì¸ë±ìФ 제약 Add constraint 제약 ì¡°ê±´ 추가 Remove constraint 제약 ì¡°ê±´ ì‚­ì œ Columns 필드 SQL SQL Foreign Keys 외래 키 제약 References 참조 Check Constraints ì²´í¬ ì œì•½ <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>ì´ í…Œì´ë¸” ì •ì˜ ì¤‘ì— íŒŒì„œê°€ í•´ì„í•  수 없는 ë¶€ë¶„ì´ ìžˆìŠµë‹ˆë‹¤. ì´ í…Œì´ë¸”ì„ ìˆ˜ì •í•˜ê±°ë‚˜ 저장하면 문제가 ë°œìƒí•  수 있습니다.</p></body></html> Primary Key 기본 키 Add a primary key constraint 기본 키 제약 ì¡°ê±´ 추가 Add a unique constraint ìœ ë‹ˆí¬ ì œì•½ ì¡°ê±´ 추가 Error creating table. Message from database engine: %1 í…Œì´ë¸” ìƒì„± ì—러. ë°ì´í„°ë² ì´ìФ 메시지: %1 There already is a field with that name. Please rename it first or choose a different name for this field. ì´ë¯¸ 다른 필드ì—서 ì‚¬ìš©ì¤‘ì¸ ì´ë¦„입니다. 다른 ì´ë¦„ì„ ì‚¬ìš©í•˜ê±°ë‚˜ 사용 ì¤‘ì¸ í•„ë“œ ì´ë¦„ì„ ë°”ê¾¸ì„¸ìš”. There can only be one primary key for each table. Please modify the existing primary key instead. ê° í…Œì´ë¸”마다 í•˜ë‚˜ì˜ ê¸°ë³¸ 키만 ìžˆì„ ìˆ˜ 있습니다. 기존 기본 키를 대신 수정하세요. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. ì´ í•„ë“œëŠ” í…Œì´ë¸” %1 ì— ìžˆëŠ” ì™¸ëž˜í‚¤ì— ì°¸ì¡°ë˜ì–´ 있기 ë•Œë¬¸ì— ì´ë¦„ì„ ë³€ê²½í•  수 없습니다. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. ì´ í•„ë“œ ê°’ì´ NULL로 ë˜ì–´ 있는 레코드가 최소한 하나 ì´ìƒ 존재합니다. ì´ëŸ¬í•œ ìƒíƒœì—서는 ë³€ê²½ì´ ë¶ˆê°€ëŠ¥í•˜ë‹ˆ í…Œì´ë¸”ì˜ ë°ì´í„°ë¥¼ 먼저 수정해서 NULL ê°’ì„ ì‚­ì œì£¼ì„¸ìš”. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. ì´ í•„ë“œ ê°’ì´ ìˆ«ìžê°€ 아닌 값으로 ë˜ì–´ 있는 레코드가 최소 하나 ì´ìƒ 존재합니다. ì´ëŸ¬í•œ ìƒíƒœì—서는 ë³€ê²½ì´ ë¶ˆê°€ëŠ¥í•˜ë‹ˆ í…Œì´ë¸”ì˜ ë°ì´í„° ê°’ì„ ë¨¼ì € 변경해주세요. Column '%1' has duplicate data. %1 ì—´ì— ì¤‘ë³µëœ ë°ì´í„°ê°€ 있습니다. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. ì´ë¡œ ì¸í•´ ìœ ë‹ˆí¬ í”Œëž˜ê·¸ë¥¼ 설정할 수 없습니다. 중복 ë°ì´í„°ë¥¼ 제거하여야 ìœ ë‹ˆí¬ í”Œëž˜ê·¸ë¥¼ 설정할 수 있습니다. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. ì •ë§ë¡œ '%1' 필드를 삭제하시겠습니까? ì´ í•„ë“œì— ì €ìž¥ëœ ëª¨ë“  ë°ì´í„°ê°€ ê°™ì´ ì‚­ì œë©ë‹ˆë‹¤. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled 'rowid 사용하지 않ìŒ'ì„ ì‚¬ìš©í•˜ê¸° 위해서는 아래 ë‘ ê°€ì§€ ì‚¬í•­ì„ ë§Œì¡±ì‹œí‚¤ëŠ” 필드를 추가해주세요: - 기본 키(Primary Key) 사용 - ìžë™ ì¦ê°€(Auto Increment) 사용하지 ì•ŠìŒ Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set ì¶©ëŒ ì‹œ 조치를 설정하기 ì „ì— ë‹¤ìŒ ê¸°ì¤€ì„ ì¶©ì¡±í•˜ëŠ” 필드를 추가하십시오. - 기본 키(Primary Key) 플래그 ExportDataDialog Export data as CSV ë°ì´í„°ë¥¼ CSV 파ì¼ë¡œ 내보내기 Tab&le(s) í…Œì´ë¸”(&l) Colu&mn names in first line 첫 í–‰ì´ í•„ë“œ ì´ë¦„(&M) Fie&ld separator 필드 구분ìž(&l) , , ; ; Tab 탭 | | Other 기타 &Quote character 문ìžì—´ ë¬¶ìŒ ê¸°í˜¸(&Q) " " ' ' New line characters ê°œí–‰ë¬¸ìž Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print ì¸ì‡„하기 ì¢‹ì€ ìŠ¤íƒ€ì¼ Could not open output file: %1 내보낸 파ì¼ì„ ì—´ 수 없습니다: %1 Choose a filename to export data ë°ì´í„°ë¥¼ 내보낼 íŒŒì¼ ì´ë¦„ì„ ì •í•˜ì„¸ìš” Export data as JSON JSON으로 내보내기 exporting CSV CSV로 내보내기 Error while writing the file '%1': %2 '%1' 파ì¼ì„ 쓰는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤: %2 exporting JSON JSON으로 내보내기 Please select at least 1 table. 최소한 í…Œì´ë¸” 1개는 ì„ íƒí•˜ì„¸ìš”. Choose a directory 디렉터리를 ì„ íƒí•˜ì„¸ìš” Export completed. 내보내기가 완료ë˜ì—ˆìŠµë‹ˆë‹¤. Export finished with errors. 내보내기가 오류와 함께 완료ë˜ì—ˆìŠµë‹ˆë‹¤. ExportSqlDialog Export SQL... SQL로 내보내기... Tab&le(s) í…Œì´ë¸”(&l) Select All ëª¨ë‘ ì„ íƒ Deselect All ëª¨ë‘ ì„ íƒ í•´ì œ &Options 옵션(&O) Keep column names in INSERT INTO INSERT INTOë¬¸ì— í•„ë“œëª… 넣기 Multiple rows (VALUES) per INSERT statement í•˜ë‚˜ì˜ INSERTë¬¸ì— ì—¬ëŸ¬ì¤„ (VALUES) 사용하기 Export everything ëª¨ë‘ ë‚´ë³´ë‚´ê¸° Export data only ë°ì´í„°ë§Œ 내보내기 Keep original CREATE statements ì›ë³¸ CREATE ë¬¸ì„ ìœ ì§€ Keep old schema (CREATE TABLE IF NOT EXISTS) ì´ì „ 스키마 유지하기 (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) ì´ì „ 스키마 ë®ì–´ì“°ê¸° (DROP TABLE, then CREATE TABLE) Export schema only 스키마만 내보내기 Please select at least one table. 최소한 한 ê°œì˜ í…Œì´ë¸”ì„ ì„ íƒí•´ì£¼ì„¸ìš”. Choose a filename to export 내보내기 í•  파ì¼ëª…ì„ ê³ ë¥´ì„¸ìš” Export completed. 내보내기가 완료ë˜ì—ˆìŠµë‹ˆë‹¤. Export cancelled or failed. 내보내기가 취소ë˜ì—ˆê±°ë‚˜ 실패했습니다. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... 찾기... Find and Replace... 검색과 바꾸기... Print... ì¸ì‡„하기... ExtendedTableWidget Use as Exact Filter 정확한 필터로 ì ìš©í•˜ê¸° Containing í¬í•¨í•˜ëŠ” Not containing í¬í•¨í•˜ì§€ 않는 Not equal to 같지 ì•Šì€ Greater than 초과 Less than 미만 Greater or equal ì´ìƒ Less or equal ì´í•˜ Between this and... ì´ ê°’ê³¼ 사ì´ì—... Regular expression ì •ê·œ í‘œí˜„ì‹ Edit Conditional Formats... ì¡°ê±´ë¶€ ì„œì‹ íŽ¸ì§‘... Set to NULL NULL로 변경하기 Cut 잘ë¼ë‚´ê¸° Copy 복사하기 Copy with Headers í—¤ë” í¬í•¨ 복사하기 Copy as SQL SQL로 복사하기 Paste 붙여넣기 Print... ì¸ì‡„하기... Use in Filter Expression í•„í„° í‘œí˜„ì‹ ì ìš©í•˜ê¸° Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? í´ë¦½ë³´ë“œì˜ ë‚´ìš©ì´ ì„ íƒí•œ 범위보다 í½ë‹ˆë‹¤. 어쨌든 추가할까요? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>모든 ë°ì´í„°ê°€ 로드ë˜ì§€ 않았습니다. <b>모든 í–‰ì„ ì„ íƒí•˜ê¸° ì „ì— ëª¨ë“  ë°ì´í„°ë¥¼ 로드하시겠습니까?</b><p><p><b> 아니요</b>를 ì„ íƒí•˜ë©´ ë” ì´ìƒ ë°ì´í„°ê°€ 로드ë˜ì§€ 않고 ì„ íƒì´ 수행ë˜ì§€ 않습니다.<br/><b>예</b> 를 ì„ íƒí•˜ë©´ ë°ì´í„°ê°€ 로드ë˜ëŠ” ë™ì•ˆ ì‹œê°„ì´ ë‹¤ì†Œ 걸릴 수 있지만 ì„ íƒì´ 완료ë©ë‹ˆë‹¤.</p>경고: 모든 ë°ì´í„°ë¥¼ 로드하려면 í° í…Œì´ë¸”ì„ ìœ„í•´ ë§Žì€ ì–‘ì˜ ë©”ëª¨ë¦¬ê°€ 필요할 수 있습니다. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. ì„ íƒ ì‚¬í•­ì„ NULL로 설정할 수 없습니다. ì—´ %1ì— NOT NULL 제약 ì¡°ê±´ì´ ìžˆìŠµë‹ˆë‹¤. FileExtensionManager File Extension Manager íŒŒì¼ í™•ìž¥ìž ê´€ë¦¬ìž &Up 위로(&U) &Down 아래로(&D) &Add 추가하기(&A) &Remove 삭제하기(&R) Description 설명 Extensions í™•ìž¥ìž *.extension *.í™•ìž¥ìž FilterLineEdit Filter í•„í„° These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression ì´ ìž…ë ¥ 필드는 현재 ì„ íƒëœ í…Œì´ë¸”ì— ë¹ ë¥´ê²Œ 필터를 ì ìš©í•  수 있게 í•´ì¤ë‹ˆë‹¤. 기본ì ìœ¼ë¡œ ìž…ë ¥ ë°•ìŠ¤ì— ë“¤ì–´ê°€ìžˆëŠ” ì¡°ê±´ì— ë§žëŠ” í–‰ë“¤ì´ í‘œì‹œë©ë‹ˆë‹¤. 아래와 ê°™ì€ ì—°ì‚°ìžë“¤ì„ 사용할 수 있습니다: % 와ì¼ë“œì¹´ë“œ > 초과 < 미만 >= ì´ìƒ <= ì´í•˜ = ê°™ìŒ: 정확히 ì¼ì¹˜ <> 같지않ìŒ: 정확히 불ì¼ì¹˜ x~y 범위: x와 yê°’ ì‚¬ì´ ê°’ /regexp/ ì •ê·œ 표현ì‹ì— ì¼ì¹˜í•˜ëŠ” ê°’ Clear All Conditional Formats 모든 ì¡°ê±´ë¶€ ì„œì‹ ì§€ìš°ê¸° Use for Conditional Format ì¡°ê±´ë¶€ ì„œì‹ ì‚¬ìš© Edit Conditional Formats... ì¡°ê±´ë¶€ ì„œì‹ íŽ¸ì§‘... Set Filter Expression í•„í„° í‘œí˜„ì‹ ì„¤ì •í•˜ê¸° What's This? ì´ê±´ 무엇ì¸ê°€ìš”? Is NULL NULLìž„ Is not NULL NULLì´ ì•„ë‹˜ Is empty ë¹„ì–´ìžˆìŒ Is not empty 비어있지 ì•ŠìŒ Not containing... í¬í•¨í•˜ì§€ 않는... Equal to... ê°™ì€... Not equal to... 같지 않ì€... Greater than... 초과... Less than... 미만... Greater or equal... ì´ìƒ... Less or equal... ì´í•˜... In range... 범위... Regular expression... ì •ê·œ 표현ì‹... FindReplaceDialog Find and Replace 찾기와 바꾸기 Fi&nd text: ì°¾ì„ í…스트(&N): Re&place with: 바꾸려는 í…스트(&P): Match &exact case ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ 시(&E) Match &only whole words ì „ì²´ 단어 ì¼ì¹˜ 시(&O) When enabled, the search continues from the other end when it reaches one end of the page 활성화ë˜ë©´ 페ì´ì§€ì˜ 한쪽 ëì— ë„ë‹¬í–ˆì„ ë•Œ 다른 쪽 ëì—서 ê²€ìƒ‰ì´ ê³„ì†ë©ë‹ˆë‹¤ &Wrap around ì „ì²´ 페ì´ì§€ 검색(&W) When set, the search goes backwards from cursor position, otherwise it goes forward 활성화ë˜ë©´ 커서 위치 뒤로 검색합니다. 그렇지 않으면 앞으로 검색합니다 Search &backwards 뒤로 찾기(&B) <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>할성화ë˜ë©´ 현재 ì„ íƒ í•­ëª©ì—서만 찾습니다.</p></body></html> &Selection only ì„ íƒ í•­ëª©ë§Œ(&S) <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>ì„ íƒí•˜ë©´ ì°¾ì„ íŒ¨í„´ì´ UNIX ì •ê·œ 표현ì‹ìœ¼ë¡œ í•´ì„ë©ë‹ˆë‹¤. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>를 참고하십시오.</p></body></html> Use regular e&xpressions ì •ê·œ í‘œí˜„ì‹ ì‚¬ìš©(&X) Find the next occurrence from the cursor position and in the direction set by "Search backwards" 커서 위치ì—서 "뒤로 찾기"ì—서 설정한 ë°©í–¥ì— ë”°ë¼ ë‹¤ìŒ í•­ëª©ì„ ì°¾ìŠµë‹ˆë‹¤ &Find Next ë‹¤ìŒ ì°¾ê¸°(&F) F3 &Replace 바꾸기(&R) Highlight all the occurrences of the text in the page 페ì´ì§€ ë‚´ 찾으려는 í…스트를 ëª¨ë‘ ê°•ì¡° 표시합니다 F&ind All ëª¨ë‘ ì°¾ê¸°(&I) Replace all the occurrences of the text in the page 페ì´ì§€ ë‚´ ì¼ì¹˜í•˜ëŠ” 모든 í…스트를 바꿉니다 Replace &All ëª¨ë‘ ë°”ê¾¸ê¸°(&A) The searched text was not found 찾으려는 í…스트를 ì°¾ì„ ìˆ˜ 없습니다 The searched text was not found. 찾으려는 í…스트를 ì°¾ì„ ìˆ˜ 없습니다. The searched text was found one time. 찾으려는 í…스트를 한 번 발견ë˜ì—ˆìŠµë‹ˆë‹¤. The searched text was found %1 times. 찾으려는 í…스트가 %1번 발견ë˜ì—ˆìŠµë‹ˆë‹¤. The searched text was replaced one time. í…스트가 한 번 바뀌었습니다. The searched text was replaced %1 times. %1ê°œì˜ í…스트가 바뀌었습니다. ForeignKeyEditor &Reset 초기화(&R) Foreign key clauses (ON UPDATE, ON DELETE etc.) 외부 키(ON UPDATE, ON DELETE 등.) ImageViewer Image Viewer ì´ë¯¸ì§€ ë·°ì–´ Reset the scaling to match the original size of the image. ì´ë¯¸ì§€ì˜ ì›ëž˜ í¬ê¸°ì™€ ì¼ì¹˜í•˜ë„ë¡ ë°°ìœ¨ì„ ìž¬ì„¤ì •í•©ë‹ˆë‹¤. Set the scaling to match the size of the viewport. ë·°í¬íЏ(Viewport)ì˜ í¬ê¸°ì™€ ì¼ì¹˜í•˜ë„ë¡ ë°°ì—´ì„ ì„¤ì •í•©ë‹ˆë‹¤. Print... ì¸ì‡„... Open preview dialog for printing displayed image í‘œì‹œëœ ì´ë¯¸ì§€ì— 대한 ì¸ì‡„ 미리보기 ì°½ì„ ì—½ë‹ˆë‹¤ Ctrl+P ImportCsvDialog Import CSV file CSV íŒŒì¼ ê°€ì ¸ì˜¤ê¸° Table na&me í…Œì´ë¸” ì´ë¦„(&M) &Column names in first line 첫 í–‰ì— í•„ë“œëª… í¬í•¨(&C) Field &separator 필드 구분ìž(&S) , , ; ; Tab 탭 | | Other 기타 &Quote character 문ìžì—´ ë¬¶ìŒ ê¸°í˜¸(&Q) Other (printable) 기타 (ì¸ì‡„ìš©) Other (code) 기타 (코드) " " ' ' &Encoding ì¸ì½”딩(&E) UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? 필드 앞뒤 공백 제거? Separate tables í…Œì´ë¸” 나누기 Advanced 고급 When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. CSV 파ì¼ì˜ 빈 ê°’ì„ ì´ ì—´ì˜ ê¸°ë³¸ ê°’ì´ ìžˆëŠ” 기존 í…Œì´ë¸”로 가져올 때 해당 ê¸°ë³¸ê°’ì´ ì‚½ìž…ë©ë‹ˆë‹¤. 대신 빈 ê°’ì„ ì‚½ìž…í•˜ë ¤ë©´ ì´ ì˜µì…˜ì„ í™œì„±í™”í•˜ì„¸ìš”. Ignore default &values 기본 ê°’ì„ ë¬´ì‹œ(&V) Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. 기본 ê°’ ì—†ì´ ë¹„ì–´ 있는 ê°’ì„ NOT NULL 열로 가져오려고 í•  때 가져오기를 중단하려면 ì´ ì˜µì…˜ì„ í™œì„±í™”í•˜ì„¸ìš”. Fail on missing values ê°’ ëˆ„ë½ ì‹œ 실패 Disable data type detection ë°ì´í„° 타입 ì¸ì‹ ë„기 Disable the automatic data type detection when creating a new table. 새 í…Œì´ë¸”ì„ ìƒì„±í•  때 ìžë™ ë°ì´í„° 타입 ì¸ì‹ ê¸°ëŠ¥ì„ ë•니다. Use local number conventions 시스템 로케ì¼ì— ë”°ë¼ ìˆ«ìž ê°’ 처리 Use decimal and thousands separators according to the system locale. 시스템 로케ì¼ì— ë”°ë¼ ì†Œìˆ˜ ë° ì²œ 단위 구분 기호를 사용합니다. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. 기본 키, 고유 제약 ì¡°ê±´ ë˜ëŠ” 고유 ì¸ë±ìŠ¤ë¥¼ 사용하여 기존 í…Œì´ë¸”로 가져올 때 ì¶©ëŒ ê°€ëŠ¥ì„±ì´ ìžˆìŠµë‹ˆë‹¤. ì´ ì˜µì…˜ì„ ì‚¬ìš©í•˜ë©´ 해당 ê²½ìš°ì— ëŒ€í•œ 대처 ë°©ì•ˆì„ ì„ íƒí•  수 있습니다. 기본ì ìœ¼ë¡œëŠ” 가져오기가 중단ë˜ê³  롤백ë˜ì§€ë§Œ ì¶©ëŒí•˜ëŠ” í–‰ì„ ë¬´ì‹œí•˜ê³  가져오지 않거나 í…Œì´ë¸”ì˜ ê¸°ì¡´ í–‰ì„ ë°”ê¾¸ë„ë¡ ì„ íƒí•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. Abort import 가져오기 취소 Ignore row ì—´ 무시 Replace existing row 기존 í–‰ 바꾸기 Conflict strategy ì¶©ëŒ ë°œìƒ ì‹œ Deselect All ëª¨ë‘ ì„ íƒ í•´ì œ Match Similar 비슷한거 찾기 Select All ëª¨ë‘ ì„ íƒ There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. ì´ë¯¸ '%1'ì´ë¼ëŠ” ì´ë¦„ì„ ê°€ì§„ í…Œì´ë¸”ì´ ì¡´ìž¬í•˜ë©° 기존 í…Œì´ë¸”로 ë°ì´í„°ë¥¼ 가져오는 ê²ƒì€ í•„ë“œì˜ ìˆ˜ê°€ ê°™ì„ ë•Œë§Œ 가능합니다. There is already a table named '%1'. Do you want to import the data into it? ì´ë¯¸ '%1'ë¼ëŠ” ì´ë¦„ì˜ í…Œì´ë¸”ì´ ì¡´ìž¬í•©ë‹ˆë‹¤. ë°ì´í„°ë¥¼ ì´ í…Œì´ë¸”로 가져올까요? Creating restore point failed: %1 ë³µì› í¬ì¸íŠ¸ë¥¼ ìƒì„±í•˜ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤: %1 Creating the table failed: %1 í…Œì´ë¸” ìƒì„±ì— 실패했습니다: %1 importing CSV CSV 가져오기 Could not prepare INSERT statement: %1 INSERT ë¬¸ì„ ì¤€ë¹„í•  수 없습니다: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. 예기치 ì•Šì€ íŒŒì¼ì˜ ë(EOF)입니다. 올바른 따옴표를 구성했는지, íŒŒì¼ í˜•ì‹ì´ 잘못ë˜ì§€ 않았는지 확ì¸í•˜ì„¸ìš”. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. íŒŒì¼ '%1' ê°€ì ¸ì˜¤ëŠ”ë° %2msê°€ 걸렸습니다. ì´ ì¤‘ì—서 í–‰ ê¸°ëŠ¥ì„ ì ìš©í•˜ëŠ”ë° %3msê°€ 걸렸습니다. Inserting row failed: %1 í–‰ ì¶”ê°€ì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤: %1 MainWindow DB Browser for SQLite DB Browser for SQLite toolBar1 toolBar1 Opens the SQLCipher FAQ in a browser window SQLCipher FAQ를 봅니다 Export one or more table(s) to a JSON file í…Œì´ë¸”ì„ JSON 파ì¼ë¡œ 내보냅니다 Find 찾기 Find or replace 검색과 바꾸기 Print text from current SQL editor tab 현재 SQL 편집기 íƒ­ì˜ í…스트 ì¸ì‡„ Print the structure of the opened database 현재 ì—´ë ¤ 있는 ë°ì´í„°ë² ì´ìŠ¤ì˜ êµ¬ì¡° ì¸ì‡„ Un/comment block of SQL code SQL 코드 블럭 ì£¼ì„ ì²˜ë¦¬/í•´ì œ Un/comment block 블럭 ì£¼ì„ ì²˜ë¦¬/í•´ì œ Comment or uncomment current line or selected block of code 현재 줄 ë˜ëŠ” ì„ íƒëœ ë¸”ëŸ­ì„ ì£¼ì„ ì²˜ë¦¬ ë˜ëŠ” 해제합니다 Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. ì„ íƒëœ ì¤„ì„ ì£¼ì„ ì²˜ë¦¬ ë˜ëŠ” 해제합니다. ì„ íƒ í•­ëª©ì´ ì—†ëŠ” 경우 현재 ì¤„ì„ ì²˜ë¦¬í•©ë‹ˆë‹¤. 모든 ë¸”ëŸ­ì€ ì²«ë²ˆì§¸ ì¤„ì„ í†µí•´ 토글 í•  수 있습니다. Ctrl+/ Stop SQL execution SQL 실행 중단 Stop execution 실행 중단 Stop the currently running SQL script 현재 실행 ì¤‘ì¸ SQL 스í¬ë¦½íЏ 중단 Execute all/selected SQL ì „ì²´ ë˜ëŠ” ì„ íƒí•œ SQL 실행 Open an existing database file in read only mode ì½ê¸° ì „ìš© 모드로 존재하는 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ 엽니다 &File 파ì¼(&F) &Import 가져오기(&I) &Export 내보내기(&E) &Edit 편집(&E) &View 보기(&V) &Help ë„움ë§(&H) Too&ls ë„구(&L) DB Toolbar DB 툴바 Edit Database &Cell ë°ì´í„°ë² ì´ìФ ì…€ 수정하기(&C) Error Log ì—러 로그 This button clears the contents of the SQL logs ì´ ë²„íŠ¼ì€ SQL 로그 ë‚´ìš©ì„ ì§€ì›ë‹ˆë‹¤ This panel lets you examine a log of all SQL commands issued by the application or by yourself ì´ íŒ¨ë„ì—서 ì‘ìš© 프로그램 ë˜ëŠ” 사용ìžê°€ 실행한 모든 SQL ëª…ë ¹ì˜ ê¸°ë¡ì„ 확ì¸í•  수 있습니다 DB Sche&ma DB 스키마(&M) This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. ì´ê²ƒì€ 열린 ë°ì´í„°ë² ì´ìŠ¤ì˜ êµ¬ì¡°ìž…ë‹ˆë‹¤. ì´ë¦„ ì—´ì—서 여러 개체 ì´ë¦„ì„ ëŒì–´ì„œ SQL íŽ¸ì§‘ê¸°ì— ë†“ì„ ìˆ˜ 있으며 컨í…스트 메뉴를 사용하여 ëŒì–´ì„œ ë†“ì€ ì´ë¦„ì˜ ì†ì„±ì„ 변경할 수 있습니다. ì´ê²ƒì€ SQL ë¬¸ì„ ìž‘ì„±í•˜ëŠ”ë° ë„ì›€ì´ ë©ë‹ˆë‹¤. 스키마 ì—´ì—서 SQL ë¬¸ì„ ëŒì–´ì„œ SQL 편집기나 다른 ì‘ìš© í”„ë¡œê·¸ëž¨ì— ë†“ì„ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. &Remote ì›ê²©(&R) This button executes the SQL statement present in the current editor line ì´ ë²„íŠ¼ì€ í˜„ìž¬ 편집기 í–‰ì— ìžˆëŠ” SQL ë¬¸ì„ ì‹¤í–‰í•©ë‹ˆë‹¤ Shift+F5 Sa&ve Project 프로ì íЏ 저장하기(&V) User ì‚¬ìš©ìž Application 애플리케ì´ì…˜ &Clear 지우기(&C) &New Database... 새 ë°ì´í„°ë² ì´ìФ(&N)... Create a new database file 새 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•©ë‹ˆë‹¤ This option is used to create a new database file. ì´ ì˜µì…˜ì€ ìƒˆ ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ë ¤ê³  í•  때 사용합니다. Ctrl+N &Open Database... ë°ì´í„°ë² ì´ìФ 열기(&O)... Open an existing database file 기존 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ 엽니다 This option is used to open an existing database file. ì´ ì˜µì…˜ì€ ê¸°ì¡´ ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì—´ 때 사용합니다. Ctrl+O &Close Database ë°ì´í„°ë² ì´ìФ 닫기(&C) This button closes the connection to the currently open database file ì´ ë²„íŠ¼ì€ í˜„ìž¬ ì—´ë ¤ 있는 ë°ì´í„°ë² ì´ìФ 파ì¼ì— 대한 ì—°ê²°ì„ ë‹«ìŠµë‹ˆë‹¤ Ctrl+W Revert database to last saved state 마지막 ì €ìž¥ëœ ìƒíƒœë¡œ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ë˜ëŒë¦½ë‹ˆë‹¤ This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. ì´ ì˜µì…˜ì€ í˜„ìž¬ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 마지막 ì €ìž¥ëœ ìƒíƒœë¡œ ë˜ëŒë¦´ 때 사용합니다. 저장 ì´í›„ì— ì´ë£¨ì–´ì§„ 모든 변경 ì‚¬í•­ì„ ë˜ëŒë¦½ë‹ˆë‹¤. Write changes to the database file 변경 ì‚¬í•­ì„ ë°ì´í„°ë² ì´ìФ 파ì¼ì— ë°˜ì˜í•©ë‹ˆë‹¤ This option is used to save changes to the database file. ì´ ì˜µì…˜ì€ ë°ì´í„°ë² ì´ìФ 파ì¼ì— 변경 ì‚¬í•­ì„ ì €ìž¥í•˜ê¸° 위해 사용ë©ë‹ˆë‹¤. Ctrl+S Compact the database file, removing space wasted by deleted records ì‚­ì œëœ ë ˆì½”ë“œë¡œ 낭비ë˜ëŠ” ê³µê°„ì„ ì œê±°í•˜ì—¬ ë°ì´í„°ë² ì´ìФ íŒŒì¼ ì••ì¶• Compact the database file, removing space wasted by deleted records. ì‚­ì œëœ ë ˆì½”ë“œë¡œ 낭비ë˜ëŠ” ê³µê°„ì„ ì œê±°í•˜ì—¬ ë°ì´í„°ë² ì´ìФ íŒŒì¼ ì••ì¶•. E&xit 종료(&X) Ctrl+Q Import data from an .sql dump text file into a new or existing database. .sql ë¤í”„ 문ìžì—´ 파ì¼ì—서 ë°ì´í„°ë¥¼ 새 ë°ì´í„°ë² ì´ìŠ¤ë‚˜ 기존 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 가져옵니다. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. ì´ ì˜µì…˜ì€ .sql ë¤í”„ 문ìžì—´ 파ì¼ì—서 ë°ì´í„°ë¥¼ 새 ë°ì´í„°ë² ì´ìŠ¤ë‚˜ 기존 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 가져옵니다. SQL ë¤í”„ 파ì¼ì€ MySQLì´ë‚˜ PostgreSQL 등 ëŒ€ë¶€ë¶„ì˜ ë°ì´í„°ë² ì´ìФ 엔진ì—서 ìƒì„±í•  수 있습니다. Open a wizard that lets you import data from a comma separated text file into a database table. 마법사를 사용하여 CSV 파ì¼(쉼로 필드가 나누어진 문ìžì—´ 파ì¼)ì—서 ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”로 ë°ì´í„°ë¥¼ 가져올 수 있습니다. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. 마법사를 사용하여 CSV 파ì¼(쉼표로 필드가 나누어진 문ìžì—´ 파ì¼)ì—서 ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”로 ë°ì´í„°ë¥¼ 가져올 수 있습니다. CSV 파ì¼ì€ ëŒ€ë¶€ë¶„ì˜ ë°ì´í„°ë² ì´ìŠ¤ì™€ 스프레드시트 애플리케ì´ì…˜ì—서 ìƒì„±í•  수 있습니다. Export a database to a .sql dump text file. ë°ì´í„°ë² ì´ìŠ¤ë¥¼ .sql ë¤í”„ 문ìžì—´ 파ì¼ë¡œ 내보내기. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. ì´ ì˜µì…˜ì€ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ .sql ë¤í”„ 문ìžì—´ 파ì¼ë¡œ 내보낼 수 있습니다. SQL ë¤í”„ 파ì¼ì€ MySQLê³¼ PostgreSQL 등 ëŒ€ë¶€ë¶„ì˜ ë°ì´í„°ë² ì´ìФ 엔진ì—서 ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 재ìƒì„±í•˜ê¸° 위한 모든 필요한 ë°ì´í„°ë¥¼ í¬í•¨í•˜ê³  있습니다. Export a database table as a comma separated text file. ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”ì„ CSV(쉼표로 ë¶„ë¦¬ëœ ë¬¸ìžì—´ 파ì¼)로 내보내기. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”ì„ CSV(쉼표로 ë¶„ë¦¬ëœ ë¬¸ìžì—´ 파ì¼)로 내보내기. 다른 ë°ì´í„°ë² ì´ìŠ¤ë‚˜ 스프레드시트 애플리케ì´ì…˜ì—서 가져와서 사용할 수 있습니다. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database í…Œì´ë¸” ìƒì„± 마법사를 사용하여 ë°ì´í„°ë² ì´ìФì—서 새 í…Œì´ë¸”ì„ ìœ„í•œ ì´ë¦„ê³¼ 필드를 ì •ì˜í•  수 있습니다 Delete Table í…Œì´ë¸” 삭제하기 Open the Delete Table wizard, where you can select a database table to be dropped. í…Œì´ë¸” ì‚­ì œ 마법사를 사용하여 ì„ íƒí•œ ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”ì„ ì‚­ì œí•  수 있습니다. Open the Create Index wizard, where it is possible to define a new index on an existing database table. ì¸ë±ìФ ìƒì„± 마법사를 사용하여 기존 ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”ì— ìƒˆ ì¸ë±ìŠ¤ë¥¼ ì •ì˜í•  수 있습니다. &Preferences... 환경설정(&P)... Open the preferences window. 환경설정 ì°½ì„ ì—½ë‹ˆë‹¤. &DB Toolbar DB 툴바(&D) Shows or hides the Database toolbar. ë°ì´í„°ë² ì´ìФ 툴바를 ë³´ì´ê±°ë‚˜ 숨ê¹ë‹ˆë‹¤. Shift+F1 &Recently opened 최근 ì—´ì—ˆë˜ íŒŒì¼ë“¤(&R) Ctrl+T This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. ì´ê²ƒì€ 열려있는 ë°ì´í„°ë² ì´ìŠ¤ì˜ êµ¬ì¡°ìž…ë‹ˆë‹¤. 개체 í–‰ì—서 SQL ë¬¸ì„ ëŒì–´ì„œ 다른 ì‘ìš© 프로그램ì´ë‚˜ 'DB Browser for SQLite'ì˜ ë‹¤ë¥¸ ì¸ìŠ¤í„´ìŠ¤ì— ë†“ì„ ìˆ˜ 있습니다. Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. 경고: ì´ pragma는 ì½ê¸° ì „ìš©ì´ ì•„ë‹ˆë©° ì´ ê°’ì€ ì¶”ì¸¡ëœ ê°’ìž…ë‹ˆë‹¤. pragma를 작성하면 SQLiteì—서 제공하는 ìž¬ì •ì˜ ëœ LIKE를 ë®ì–´ 쓸 수 있습니다. &Recent Files 최근 íŒŒì¼ ì—´ê¸°(&R) Ctrl+F4 Compact &Database... ë°ì´í„°ë² ì´ìФ ì••ì¶•(&D)... Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. 기존 í…Œì´ë¸”ì˜ ì´ë¦„ì„ ë°”ê¿€ 수 있는 í…Œì´ë¸” 수정 마법사를 엽니다. í…Œì´ë¸”ì—서 필드를 추가 ë˜ëŠ” 삭제하고 필드 ì´ë¦„ ë° ìœ í˜•ì„ ìˆ˜ì •í•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. ì´ ë²„íŠ¼ì€ í˜„ìž¬ ì„ íƒë˜ì–´ 있는 SQL ëª…ë ¹ë¬¸ì„ ì‹¤í–‰í•©ë‹ˆë‹¤. 만약 ì„ íƒ í•­ëª©ì´ ì—†ìœ¼ë©´ 모든 SQL ëª…ë ¹ë¬¸ì´ ì‹¤í–‰ë©ë‹ˆë‹¤. &Load Extension... 확장ë„구 불러오기(&L)... Execute line 줄 실행 &Wiki 위키(&W) F1 Bug &Report... 버그 ë³´ê³ (&R)... Feature Re&quest... 기능 제안(&Q)... Web&site 웹 사ì´íЏ(&S) &Donate on Patreon... 후ì›í•˜ê¸°(&D)... Open &Project... 프로ì íЏ 열기(&P)... &Attach Database... ë°ì´í„°ë² ì´ìФ ì—°ê²°(&A)... Add another database file to the current database connection 현재 ë°ì´í„°ë² ì´ìФ ì—°ê²°ì— ë‹¤ë¥¸ ë°ì´í„°ë² ì´ìФ ì—°ê²°ì„ ì¶”ê°€í•©ë‹ˆë‹¤ This button lets you add another database file to the current database connection ì´ ë²„íŠ¼ì„ ì‚¬ìš©í•˜ë©´ 현재 ë°ì´í„°ë² ì´ìФ ì—°ê²°ì— ë‹¤ë¥¸ ë°ì´í„°ë² ì´ìФ 파ì¼ì„ 추가할 수 있습니다 &Set Encryption... 암호화 설정(&S)... SQLCipher &FAQ SQLCipher FAQ(&F) Table(&s) to JSON... í…Œì´ë¸”ì„ JSON으로 내보내기(&S)... Browse Table í…Œì´ë¸” íƒìƒ‰ Open Data&base Read Only... ì½ê¸° 전용으로 ë°ì´í„°ë² ì´ìФ 열기(&B)... &Database Structure This has to be equal to the tab title in all the main tabs ë°ì´í„°ë² ì´ìФ 구조(&D) &Browse Data This has to be equal to the tab title in all the main tabs ë°ì´í„° íƒìƒ‰ (&B) Edit P&ragmas This has to be equal to the tab title in all the main tabs Pragma 수정(&R) E&xecute SQL This has to be equal to the tab title in all the main tabs SQL 실행(&E) &New Database 새 ë°ì´í„°ë² ì´ìФ(&N) &Undo 실행 취소(&U) Undo last change to the database ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•œ 마지막 변경 사항 실행 취소합니다 This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. ì´ ìž‘ì—…ì€ ë°ì´í„°ë² ì´ìФ 브ë¼ìš°ì € ë˜ëŠ” SQL 실행ì—서 ë°ì´í„°ë² ì´ìŠ¤ì— ë§ˆì§€ë§‰ìœ¼ë¡œ 수행한 변경 ì‚¬í•­ì„ ì‹¤í–‰ 취소합니다. 다시 실행할 수 없습니다. New &tab 새 탭(&T) Open SQL file(s) SQL íŒŒì¼ ì—´ê¸° This button opens files containing SQL statements and loads them in new editor tabs ì´ ë²„íŠ¼ì€ SQL ë¬¸ì´ í¬í•¨ëœ 파ì¼ì„ ì—´ê³  새 편집기 íƒ­ì— ë¡œë“œí•©ë‹ˆë‹¤ Ctrl+Shift+T &Save Project 프로ì íЏ 저장하기(&S) This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file ì´ ë²„íŠ¼ì„ ì‚¬ìš©í•˜ë©´ 열린 DB와 ê´€ë ¨ëœ ëª¨ë“  ì„¤ì •ì„ DB Browser for SQLite 프로ì íЏ 파ì¼ë¡œ 저장할 수 있습니다 Open &Project 프로ì íЏ 열기(&P) This button lets you open a DB Browser for SQLite project file ì´ ë²„íŠ¼ì„ ì‚¬ìš©í•˜ë©´ DB Browser for SQLite 프로ì íЏ 파ì¼ì„ ì—´ 수 있습니다 Ctrl+Shift+O Save results ê²°ê³¼ 저장 Save the results view ê²°ê³¼ ë·° 저장 This button lets you save the results of the last executed query ì´ ë²„íŠ¼ì€ ë§ˆì§€ë§‰ìœ¼ë¡œ 실행한 ì¿¼ë¦¬ì˜ ê²°ê³¼ê°’ì„ ì €ìž¥í•©ë‹ˆë‹¤ Find text in SQL editor SQL 편집기ì—서 í…스트 찾기 This button opens the search bar of the editor ì´ ë²„íŠ¼ì€ íŽ¸ì§‘ê¸°ì˜ ê²€ìƒ‰ì°½ì„ ì—½ë‹ˆë‹¤ Ctrl+F Find or replace text in SQL editor SQL 편집기ì—서 í…스트 찾아 바꾸기 This button opens the find/replace dialog for the current editor tab ì´ ë²„íŠ¼ì€ í˜„ìž¬ ì—´ë ¤ 있는 íŽ¸ì§‘ê¸°ì˜ ì°¾ê¸° 바꾸기 대화ìƒìžë¥¼ 엽니다 Ctrl+H Export to &CSV CSV로 내보내기(&C) Export to &JSON &JSON으로 내보내기 Save as &view 뷰로 저장하기(&V) Save as view 다른 ì´ë¦„ì˜ ë·°ë¡œ 저장하기 Shows or hides the Project toolbar. 프로ì íЏ 툴바를 표시하거나 숨ê¹ë‹ˆë‹¤. Extra DB Toolbar 확장 DB 툴바 &Open Database ë°ì´í„°ë² ì´ìФ 열기(&O) New In-&Memory Database In-Memory ë°ì´í„°ë² ì´ìФ ìƒì„±(&M) Drag && Drop SELECT Query 드래그 앤 드롭 SELECT 쿼리 When dragging fields from the same table or a single table, drop a SELECT query into the editor ë™ì¼í•œ í…Œì´ë¸” ë˜ëŠ” ë‹¨ì¼ í…Œì´ë¸”ì—서 필드를 드래그할 때 SELECT 쿼리를 íŽ¸ì§‘ê¸°ì— ë“œë¡­í•©ë‹ˆë‹¤ Drag && Drop Qualified Names ì •ê·œí™”ëœ ì´ë¦„ì„ ëŒì–´ì„œ 놓기 Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor 개체를 ëŒì–´ì„œ íŽ¸ì§‘ê¸°ì— ë†“ì„ ë•Œ ì •ê·œí™”ëœ ì´ë¦„(예: "Table", "Field")ì„ ì‚¬ìš©í•©ë‹ˆë‹¤ Drag && Drop Enquoted Names ì¸ìš©ëœ ì´ë¦„ì„ ëŒì–´ì„œ 놓기 Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor 개체를 ëŒì–´ì„œ íŽ¸ì§‘ê¸°ì— ë†“ì„ ë•Œ ì´ìŠ¤ì¼€ì´í”„ëœ ì‹ë³„ìž(예: "Table1")ì„ ì‚¬ìš©í•©ë‹ˆë‹¤ &Integrity Check 무결성 검사(&I) Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. 열린 ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•´ integrity_check pragma를 실행하고 SQL 실행 íƒ­ì— ê²°ê³¼ë¥¼ 반환합니다. ì´ pragma는 ì „ì²´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¬´ê²°ì„± 검사를 수행합니다. &Foreign-Key Check 외래키 검사(&F) Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab 열린 ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•´ foreign_key_check pragma를 실행하고 SQL 실행 íƒ­ì— ê²°ê³¼ë¥¼ 반환합니다 &Quick Integrity Check 빠른 무결성 검사(&Q) Run a quick integrity check over the open DB 열린 ë°ì´í„°ë² ì´ìФ 대해 빠른 무결성 검사 실행 Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. 열린 ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•´ quick_check pragma를 실행하고 SQL 실행 íƒ­ì— ê²°ê³¼ë¥¼ 반환합니다. ì´ ëª…ë ¹ì€ ëŒ€ë¶€ë¶„ì˜ PRAGMA integrity_check 검사를 수행하지만 훨씬 빠르게 실행ë©ë‹ˆë‹¤. &Optimize 최ì í™”(&O) Attempt to optimize the database ë°ì´í„°ë² ì´ìФ 최ì í™” Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. 열린 ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•´ 최ì í™” pragma를 실행합니다. ì´ pragma는 향후 ì¿¼ë¦¬ì˜ ì„±ëŠ¥ì„ í–¥ìƒì‹œí‚¤ëŠ” 최ì í™”를 수행할 수 있습니다. Print ì¸ì‡„하기 &Save Project As... 다른 ì´ë¦„으로 프로ì íЏ 저장(&S)... Save the project in a file selected in a dialog 대화ìƒìžì—서 ì„ íƒí•œ 파ì¼ì— 프로ì íЏ 저장 Save A&ll ëª¨ë‘ ì €ìž¥(&l) Save DB file, project file and opened SQL files DB 파ì¼, 프로ì íЏ íŒŒì¼ ë° ì—´ë¦° SQL íŒŒì¼ ì €ìž¥ Ctrl+Shift+S Close Pro&ject 프로ì íЏ 닫기(&J) Close project and database files and return to the initial state 프로ì íЏ ë° í”„ë¡œì íЏ 파ì¼ì„ ë‹«ê³  초기 ìƒíƒœë¡œ ëŒì•„갑니다 Ctrl+Shift+W Table from CSV data in Clipboard... í´ë¦½ë³´ë“œì— ì €ìž¥ëœ CSV ë°ì´í„°ì—서 í…Œì´ë¸” 가져오기... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. 현재 í´ë¦½ë³´ë“œì— ì €ìž¥ëœ ë‚´ìš©ì„ CSV파ì¼ë¡œ 간주하여 파ì¼ë¡œë¶€í„° CSVë°ì´í„°ë¥¼ 불러올때 사용ë˜ëŠ” 불러오기 마법사를 엽니다. Show &Row Counts í–‰ 개수 보기 (&R) This shows the number of rows for each table and view in the database. ë°ì´í„°ë² ì´ìŠ¤ì˜ ê° í…Œì´ë¸”ê³¼ ë·°ì— ì €ìž¥ëœ í–‰ì˜ ê°œìˆ˜ë¥¼ 표시합니다. Save Database &As... 다른 ì´ë¦„으로 저장하기...(&A) Save the current database as a different file 현재 ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 다른 파ì¼ë¡œ 저장하기 Refresh 새로고침 Reload the database structure ë°ì´í„°ë² ì´ìФ 구조를 다시 로드합니다 Ctrl+Shift+F4 Detach Database ë°ì´í„°ë² ì´ìФ 분리 Detach database file attached to the current database connection 현재 ë°ì´í„°ë² ì´ìФ ì—°ê²°ì— ì—°ê²°ë˜ì–´ 있는 ë°ì´í„°ë² ì´ìФ íŒŒì¼ ë¶„ë¦¬ Open a dialog for printing the text in the current SQL editor tab 현재 SQL 편집기 탭ì—서 í…스트를 ì¸ì‡„하기 위한 대화ìƒìžë¥¼ 엽니다 Open a dialog for printing the structure of the opened database 열린 ë°ì´í„°ë² ì´ìŠ¤ì˜ êµ¬ì¡°ë¥¼ ì¸ì‡„하기 위한 대화ìƒìžë¥¼ 엽니다 SQL &Log SQL 로그(&L) Show S&QL submitted by ~ì— ì˜í•´ ì‹¤í–‰ëœ SQL 보기(&Q) &Plot 플롯(&P) Project Toolbar 프로ì íЏ 툴바 Extra DB toolbar 확장 DB 툴바 Close the current database file 현재 ë°ì´í„°ë² ì´ìФ íŒŒì¼ ë‹«ê¸° &Revert Changes 변경사항 취소하기(&R) &Write Changes 변경사항 저장하기(&W) &Database from SQL file... SQL 파ì¼ë¡œë¶€í„° ë°ì´í„°ë² ì´ìФ 가져오기(&D)... &Table from CSV file... CSV 파ì¼ì—서 í…Œì´ë¸” 가져오기(&T)... &Database to SQL file... ë°ì´í„°ë² ì´ìŠ¤ë¥¼ SQL로 내보내기(&D)... &Table(s) as CSV file... í…Œì´ë¸”ì„ CSV 파ì¼ë¡œ 내보내기(&T)... &Create Table... í…Œì´ë¸” ìƒì„±í•˜ê¸°(&C)... &Delete Table... í…Œì´ë¸” 삭제하기(&D)... &Modify Table... í…Œì´ë¸” 수정하기(&M)... Create &Index... ì¸ë±ìФ ìƒì„±í•˜ê¸°(&I)... W&hat's This? ì´ê±´ 무엇ì¸ê°€ìš”?(&H) &About ì •ë³´(&A) This button opens a new tab for the SQL editor ì´ ë²„íŠ¼ì€ SQL íŽ¸ì§‘ê¸°ì˜ ìƒˆë¡œìš´ íƒ­ì„ ì—½ë‹ˆë‹¤ &Execute SQL SQL 실행하기(&E) Save SQL file SQL íŒŒì¼ ì €ìž¥í•˜ê¸° Execute current line 현재 í–‰ 실행하기 Ctrl+E Export as CSV file CSV 파ì¼ë¡œ 내보내기 Export table as comma separated values file í…Œì´ë¸”ì„ CSV 파ì¼ë¡œ 내보내기 Save the current session to a file 현재 ì„¸ì…˜ì„ íŒŒì¼ë¡œ 저장하기 Load a working session from a file 파ì¼ì—서 작업 세션 불러오기 Save SQL file as SQL íŒŒì¼ ë‹¤ë¦„ ì´ë¦„으로 저장하기 This button saves the content of the current SQL editor tab to a file ì´ ë²„íŠ¼ì€ í˜„ìž¬ SQL íŽ¸ì§‘ê¸°ì˜ ë‚´ìš©ì„ íŒŒì¼ë¡œ 저장합니다 &Browse Table í…Œì´ë¸” 보기(&B) Copy Create statement ìƒì„± 구문 복사하기 Copy the CREATE statement of the item to the clipboard í•­ëª©ì˜ ìƒì„± êµ¬ë¬¸ì„ í´ë¦½ë³´ë“œì— 복사합니다 Ctrl+Return Ctrl+L Ctrl+P Ctrl+D Ctrl+I Encrypted ì•”í˜¸í™”ë¨ Read only ì½ê¸° ì „ìš© Database file is read only. Editing the database is disabled. ë°ì´í„°ë² ì´ìФ 파ì¼ì´ ì½ê¸° 전용입니다. ë°ì´í„°ë² ì´ìФ 수정 ê¸°ëŠ¥ì´ ë¹„í™œì„±í™”ë©ë‹ˆë‹¤. Database encoding ë°ì´í„°ë² ì´ìФ ì¸ì½”딩 Database is encrypted using SQLCipher ë°ì´í„°ë² ì´ìŠ¤ëŠ” SQLCipher를 통해 암호화ë©ë‹ˆë‹¤ Choose a database file ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” Choose a filename to save under 저장하려는 파ì¼ëª…ì„ ì„ íƒí•˜ì„¸ìš” Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì €ìž¥í•˜ë˜ ì¤‘ ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ ë§ì€ 모든 ë³€ê²½ì‚¬í•­ë“¤ì´ ë°ì´í„°ë² ì´ìŠ¤ì— ì €ìž¥ë˜ì§€ 못했ìŒì„ ì˜ë¯¸í•©ë‹ˆë‹¤. 다ìŒì— 나오는 ì—러를 먼저 해결하세요. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? ì •ë§ë¡œ ë°ì´í„°ë² ì´ìФ íŒŒì¼ '%1'ì˜ ëª¨ë“  변경 ì‚¬í•­ì„ ë§ˆì§€ë§‰ ì €ìž¥ëœ ìƒíƒœë¡œ ë˜ëŒë¦½ë‹ˆê¹Œ? Choose a file to import 가져올 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” &%1 %2%3 &%1 %2%3 (read only) (ì½ê¸° ì „ìš©) Open Database or Project ë°ì´í„°ë² ì´ìФ ë˜ëŠ” 프로ì íЏ 열기 Attach Database... ë°ì´í„°ë² ì´ìФ ì—°ê²°... Import CSV file(s)... CSV íŒŒì¼ ê°€ì ¸ì˜¤ê¸°... Do you want to save the changes made to SQL tabs in the project file '%1'? '%1' 프로ì íЏ 파ì¼ì— SQL íƒ­ì„ ì¶”ê°€í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ? Text files(*.sql *.txt);;All files(*) 문ìžì—´ 파ì¼(*.sql *.txt);;모든 파ì¼(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. ë°ì´í„°ë¥¼ 가져와서 새 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ê³  ì‹¶ì€ì‹ ê°€ìš”? 아니ë¼ë©´ SQL 파ì¼ì˜ ë°ì´í„°ë¥¼ 현재 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 가져오기를 í•  것입니다. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? ì•„ì§ SQL ëª…ë ¹ë¬¸ì´ ì‹¤í–‰ë˜ëŠ” 중입니다. ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 닫으면 ì‹¤í–‰ì´ ì¤‘ë‹¨ë˜ì–´ ë°ì´í„°ë² ì´ìŠ¤ê°€ ì¼ê´€ì„±ì´ 없어질 수 있습니다. ì •ë§ë¡œ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 닫으시겠습니까? Do you want to save the changes made to the project file '%1'? %1 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ? File %1 already exists. Please choose a different name. íŒŒì¼ %1ì´ ì´ë¯¸ 존재합니다. 다른 파ì¼ëª…ì„ ì„ íƒí•˜ì„¸ìš”. Error importing data: %1 ë°ì´í„° 가져오기 ì—러: %1 Import completed. 가져오기가 완료ë˜ì—ˆìŠµë‹ˆë‹¤. Delete View ë·° 삭제하기 Modify View ë·° 수정하기 Delete Trigger 트리거 삭제하기 Modify Trigger 트리거 수정하기 Delete Index ì¸ë±ìФ 삭제하기 Modify Index ì¸ë±ìФ 수정하기 Modify Table í…Œì´ë¸” 수정하기 Do you want to save the changes made to SQL tabs in a new project file? 새 프로ì íЏ 파ì¼ì— SQL íƒ­ì„ ì¶”ê°€í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ? Do you want to save the changes made to the SQL file %1? %1 SQL 파ì¼ì„ ìƒì„±í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ? Could not find resource file: %1 리소스 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다: %1 Choose a project file to open 불러올 프로ì íЏ 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” Could not open project file for writing. Reason: %1 쓰기 모드로 프로ì íЏ 파ì¼ì„ ì—´ 수 없습니다. ì›ì¸: %1 Busy (%1) 사용 중 (%1) Setting PRAGMA values will commit your current transaction. Are you sure? PRAGMA ì„¤ì •ì„ ë³€ê²½í•˜ë ¤ë©´ ì—¬ëŸ¬ë¶„ì˜ í˜„ìž¬ íŠ¸ëžœìž­ì…˜ì„ ì»¤ë°‹í•´ì•¼í•©ë‹ˆë‹¤. ë™ì˜í•˜ì‹­ë‹ˆê¹Œ? Ctrl+Tab Ctrl+Shift+Tab Clear List ëª©ë¡ ì§€ìš°ê¸° Window Layout ì°½ ë ˆì´ì•„웃 Reset Window Layout ì°½ ë ˆì´ì•„웃 초기화 Simplify Window Layout ì°½ ë ˆì´ì•„웃 단순화 Alt+Shift+0 Dock Windows at Bottom í•˜ë‹¨ì— ì°½ ê³ ì • Dock Windows at Left Side ì¢Œì¸¡ì— ì°½ ê³ ì • Dock Windows at Top ìƒë‹¨ì— ì°½ ê³ ì • The database is currently busy. ì´ ë°ì´í„°ë² ì´ìŠ¤ëŠ” 현재 사용 중입니다. Click here to interrupt the currently running query. 여기를 눌러 현재 실행 ì¤‘ì¸ ì¿¼ë¦¬ë¥¼ ê°•ì œ 중단합니다. Ctrl+Alt+W Could not open database file. Reason: %1 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì—´ 수 없습니다. ì›ì¸: %1 In-Memory database In-Memory ë°ì´í„°ë² ì´ìФ Choose a database file to save under 저장하려는 파ì¼ëª…ì„ ì„ íƒí•˜ì„¸ìš” Error while saving the database to the new file. ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 새 파ì¼ì— 저장할 때 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. Are you sure you want to delete the table '%1'? All data associated with the table will be lost. ì •ë§ë¡œ í…Œì´ë¸” '%1'ì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ? í…Œì´ë¸”ì˜ ëª¨ë“  ë°ì´í„°ê°€ ì‚­ì œë©ë‹ˆë‹¤. Are you sure you want to delete the view '%1'? ì •ë§ë¡œ '%1' 뷰를 삭제할까요? Are you sure you want to delete the trigger '%1'? ì •ë§ë¡œ '%1' 트리거를 삭제할까요? Are you sure you want to delete the index '%1'? ì •ë§ë¡œ '%1' ì¸ë±ìŠ¤ë¥¼ 삭제할까요? Error: could not delete the table. ì—러: í…Œì´ë¸”ì„ ì‚­ì œí•  수 없습니다. Error: could not delete the view. ì—러: 뷰를 삭제할 수 없습니다. Error: could not delete the trigger. ì—러: 트리거를 삭제할 수 없습니다. Error: could not delete the index. ì—러: ì¸ë±ìŠ¤ë¥¼ 삭제할 수 없습니다. Message from database engine: %1 ë°ì´í„°ë² ì´ìФ 엔진 메시지: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? 'pending'ì˜ ëœ»ì´ ë³´ë¥˜ìž…ë‹ˆë‹¤ë§Œ, 여기서는 작업 중ì´ë˜ì´ ë” ë§žë‹¤ê³  íŒë‹¨í–ˆìŠµë‹ˆë‹¤. í…Œì´ë¸”ì„ íŽ¸ì§‘í•˜ë ¤ë©´ 작업 중ì´ë˜ 모든 변경 ì‚¬í•­ì„ ì €ìž¥í•´ì•¼í•©ë‹ˆë‹¤. ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 저장하시겠습니까? Edit View %1 ë·° 편집 %1 Edit Trigger %1 트리거 편집 %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. ì´ë¯¸ SQL ëª…ë ¹ë¬¸ì„ ì‹¤í–‰í•˜ì˜€ìŠµë‹ˆë‹¤. 현재 ëª…ë ¹ë¬¸ì„ ëŒ€ì‹  실행하기 위해 기존 ì‹¤í–‰ì„ ì¤‘ë‹¨í•˜ì‹œê² ìŠµë‹ˆê¹Œ? ì´ë¡œ ì¸í•´ ë°ì´í„°ë² ì´ìŠ¤ê°€ ì¼ê´€ì„±ì´ 없는 ìƒíƒœê°€ ë  ìˆ˜ 있습니다. -- EXECUTING SELECTION IN '%1' -- -- '%1ì˜ ì„ íƒ í•­ëª© 실행 -- -- EXECUTING LINE IN '%1' -- --'%1'ì—서 ë¼ì¸ 실행 중 -- -- EXECUTING ALL IN '%1' -- -- '%1'로부터 ì „ì²´ 실행 -- At line %1: %1번째 줄: Result: %1 ê²°ê³¼: %1 Result: %2 ê²°ê³¼: %2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? PRAGMA ê°’ì„ ì§€ì •í•˜ì§€ 않으면 현재 íŠ¸ëžœìž­ì…˜ì— DB íŒŒì¼ ì²­ì†Œ 작업(Vacuum)ì´ ì»¤ë°‹ë©ë‹ˆë‹¤. 진행할까요? Opened '%1' in read-only mode from recent file list 최근 íŒŒì¼ ëª©ë¡ì—서 ì½ê¸° ì „ìš© 모드로 '%1'ì„(를) 열었습니다 Opened '%1' from recent file list 최근 íŒŒì¼ ëª©ë¡ì—서 '%1'ì„(를) 열었습니다 Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. ë“œë¡­ëœ íŒŒì¼ì— ì ìš©í•  ìž‘ì—…ì„ ì„ íƒí•©ë‹ˆë‹¤. <br/>참고: '가져오기'ë§Œ ë‘ ê°œ ì´ìƒì˜ 파ì¼ì„ 처리합니다. The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? %1 íƒ­ì˜ ë¬¸ì´ ì—¬ì „ížˆ 실행 중입니다. íƒ­ì„ ë‹«ìœ¼ë©´ ì‹¤í–‰ì´ ì¤‘ë‹¨ë©ë‹ˆë‹¤. ì´ë¡œ ì¸í•´ ë°ì´í„°ë² ì´ìŠ¤ê°€ ì¼ê´€ì„±ì´ 없는 ìƒíƒœê°€ ë  ìˆ˜ 있습니다. ì •ë§ë¡œ íƒ­ì„ ë‹«ìœ¼ì‹œê² ìŠµë‹ˆê¹Œ? DB file '%1' could not be opened DB íŒŒì¼ '%1'ì„(를) ì—´ 수 없습니다 This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. ì´ í”„ë¡œì íЏ 파ì¼ì€ DB Browser for SQLite 버전 3.10 ì´í•˜ë¥¼ 사용하여 ìƒì„±ë˜ì—ˆê¸° ë•Œë¬¸ì— ì´ì „ íŒŒì¼ í˜•ì‹ì„ 사용하고 있습니다. ì´ íŒŒì¼ í˜•ì‹ì„ 로드하는 ê²ƒì€ ë” ì´ìƒ 완전히 ì§€ì›ë˜ì§€ 않습니다. 완벽하게 로드하려면 DB Browser for SQLite 버전 3.12를 사용하여 새 íŒŒì¼ í˜•ì‹ìœ¼ë¡œ 변환하세요. Table '%1' not found; settings ignored í…Œì´ë¸” '%1'ì„(를) ì°¾ì„ ìˆ˜ 없습니다. ì„¤ì •ì´ ë¬´ì‹œë©ë‹ˆë‹¤ -- Reference to file "%1" (not supported by this version) -- -- "%1" 파ì¼ì— 대한 참조(ì´ ë²„ì „ì—서는 ì§€ì›ë˜ì§€ 않ìŒ) -- Yes. Don't ask again 예. 다시 묻지 않습니다 This action will open a new SQL tab with the following statements for you to edit and run: ì´ ìž‘ì—…ì„ ìˆ˜í–‰í•˜ë©´ 편집하거나 실행할 수 있는 ë‹¤ìŒ ëª…ë ¹ë¬¸ì´ í¬í•¨ëœ 새 SQL íƒ­ì´ ì—´ë¦½ë‹ˆë‹¤: Rename Tab 탭 ì´ë¦„ 변경 Duplicate Tab 탭 복제 Close Tab 탭 닫기 Opening '%1'... '%1' 여는 중... There was an error opening '%1'... '%1'ì„ ì—¬ëŠ” 중 ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤... Value is not a valid URL or filename: %1 올바른 URL ë˜ëŠ” íŒŒì¼ ì´ë¦„ì´ ì•„ë‹™ë‹ˆë‹¤: %1 %1 rows returned in %2ms %2msì˜ ì‹œê°„ì´ ê±¸ë ¤ì„œ %1 í–‰ì´ ë°˜í™˜ë˜ì—ˆìŠµë‹ˆë‹¤ Automatically load the last opened DB file at startup 시작 시 마지막으로 ì—° DB íŒŒì¼ ìžë™ìœ¼ë¡œ 불러오기 Ctrl+Alt+0 Choose text files í…스트 íŒŒì¼ ì„ íƒ Import completed. Some foreign key constraints are violated. Please fix them before saving. 가져오기가 완료ë˜ì—ˆìŠµë‹ˆë‹¤. ì¼ë¶€ 외래 í‚¤ì˜ ì œì•½ ì¡°ê±´ì´ ìœ„ë°˜ë˜ì—ˆìŠµë‹ˆë‹¤. 저장 하기 ì „ì— ìˆ˜ì •í•˜ì‹­ì‹œì˜¤. Select SQL file to open ì—´ SQL 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” Select file name íŒŒì¼ ì´ë¦„ì„ ì„ íƒí•˜ì„¸ìš” Select extension file íŒŒì¼ í™•ìž¥ìžë¥¼ ì„ íƒí•˜ì„¸ìš” Extension successfully loaded. í™•ìž¥ê¸°ëŠ¥ì„ ì„±ê³µì ìœ¼ë¡œ 불러왔습니다. Error loading extension: %1 확장기능 불러오기 ì—러: %1 Don't show again 다시 ë³´ì§€ 않기 New version available. ì´ìš© 가능한 새 ë²„ì „ì´ ìžˆìŠµë‹ˆë‹¤. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. ì´ìš© 가능한 새 ë²„ì „ì´ ìžˆìŠµë‹ˆë‹¤ (%1.%2.%3).<br/><br/><a href='%4'>%4</a>ì—서 다운로드하세요. Project saved to file '%1' '%1' 파ì¼ë¡œ 프로ì íŠ¸ê°€ 저장ë˜ì—ˆìŠµë‹ˆë‹¤ Collation needed! Proceed? 콜레ì´ì…˜ì´ 필요합니다! 진행할까요? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! ì´ ë°ì´í„°ë² ì´ìŠ¤ì˜ í…Œì´ë¸”ì€ ì´ ì• í”Œë¦¬ì¼€ì´ì…˜ì—서 잘 알지 못하는 특별한 함수 '%1'ê°€ 필요합니다. ì´ëŒ€ë¡œ ê³„ì† ì§„í–‰í•  수는 있습니다만 ì—¬ëŸ¬ë¶„ì˜ ë°ì´í„°ë² ì´ìŠ¤ì— ë‚˜ìœ ì˜í–¥ì´ ê°ˆ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. ë°±ì—…ì„ ìƒì„±í•˜ì„¸ìš”! creating collation 콜레ì´ì…˜ ìƒì„± Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. SQL íƒ­ì˜ ìƒˆ ì´ë¦„ì„ ì„¤ì •í•˜ì„¸ìš”. '&&' 문ìžë¥¼ 사용하여 다ìŒì— ë”°ë¼ì˜¤ëŠ” 문ìžë¥¼ 키보드 단축키로서 사용할 수 있습니다. Please specify the view name ë·° ì´ë¦„ì„ ì§€ì •í•´ì£¼ì„¸ìš” There is already an object with that name. Please choose a different name. ì´ë¯¸ ê°™ì€ ì´ë¦„ì˜ ê°ì²´ê°€ 존재합니다. 다른 ì´ë¦„ì„ ê³ ë¥´ì„¸ìš”. View successfully created. ë·°ê°€ 성공ì ìœ¼ë¡œ ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤. Error creating view: %1 ë·° ìƒì„± ì—러: %1 This action will open a new SQL tab for running: ì´ ìž‘ì—…ì€ ë‹¤ìŒì„ 실행하는 새 SQL íƒ­ì„ ì—½ë‹ˆë‹¤: Press Help for opening the corresponding SQLite reference page. 해당 SQLite 참조 페ì´ì§€ë¥¼ 열려면 ë„움ë§ì„ 누르십시오. DB Browser for SQLite project file (*.sqbpro) DB Browser for SQLite 프로ì íЏ íŒŒì¼ (*.sqbpro) Error checking foreign keys after table modification. The changes will be reverted. í…Œì´ë¸” 수정 후 외래 키를 확ì¸í•˜ëŠ” 중 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤. 변경 ì‚¬í•­ì´ ë˜ëŒë ¤ì§‘니다. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. ì´ í…Œì´ë¸”ì€ ì™¸ëž˜ 키 검사를 통과하지 못했습니다.<br/>'ë„구 -> 외래 키 검사'를 실행하여 ë³´ê³ ëœ ë¬¸ì œë¥¼ 해결하십시오. Execution finished with errors. ì—러가 ë°œìƒí•˜ì—¬ 실행 중단ë¨. Execution finished without errors. ì—러 ì—†ì´ ì‹¤í–‰ 완료. NullLineEdit Set to NULL NULL로 변경하기 Alt+Del PlotDock Plot 플롯 <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>ì´ í™”ë©´ì€ í˜„ìž¬ ë³´ê³  있는 í…Œì´ë¸” ë˜ëŠ” 방금 실행한 ì¿¼ë¦¬ì˜ í•„ë“œ 목ë¡ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. 아래 플롯 í™”ë©´ì— Xì¶• ë˜ëŠ” Y축으로 사용할 필드를 ì„ íƒí•  수 있습니다. ì´ í‘œëŠ” ê²°ê³¼ í”Œë¡¯ì— ì˜í–¥ì„ 줄 수 있다고 ì¸ì‹ëœ ì¶•ì˜ ì¢…ë¥˜ë¥¼ ë³´ì—¬ì¤ë‹ˆë‹¤. Yì¶•ì€ ìˆ«ìž íƒ€ìž… 필드만 ì„ íƒí•  수 있지만 Xì¶•ì€ ë‹¤ìŒê³¼ ê°™ì€ í•„ë“œ íƒ€ìž…ì„ ì„ íƒí•  수 있습니다:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ë‚ ì§œ</span>: 문ìžì—´ í¬ë§· &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">시간</span>: 문ìžì—´ í¬ë§· &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ë¼ë²¨</span>: ì´ í•„ë“œë¥¼ X축으로 ì„ íƒí•˜ë©´ 필드 ê°’ì´ ë§‰ëŒ€ì˜ ë ˆì´ë¸”로 í‘œì‹œëœ ë§‰ëŒ€ 그래프가 ìƒì„±ë©ë‹ˆë‹¤.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">숫ìž</span>: 정수 ë˜ëŠ” 실수</li></ul><p>Y ì…€ì„ ë”블 í´ë¦­í•˜ë©´ ê·¸ëž˜í”„ì— ì‚¬ìš©ëœ ìƒ‰ì„ ë³€ê²½í•  수 있습니다.</p></body></html> Columns 필드 X X Y1 Y1 Y2 Y2 Axis Type ì¶• 타입 Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. 위ì—서 x와 y ê°’ì„ ì„ íƒí•˜ë©´ ì—¬ê¸°ì— í”Œë¡¯ì´ ê·¸ë ¤ì§‘ë‹ˆë‹¤. 플롯과 í…Œì´ë¸”ì—서 í•­ëª©ì„ í´ë¦­í•˜ë©´ ì„ íƒë©ë‹ˆë‹¤. 여러 ë²”ìœ„ì˜ í•­ëª©ì„ ì„ íƒí•˜ë ¤ë©´ Control+í´ë¦­ì„ 하세요. 확대/축소를 하려면 마우스 íœ ì„ ì´ìš©í•˜ê³  ì¶• 범위를 바꾸려면 마우스를 드래그하세요. 한 방향으로만 드래그 ë˜ëŠ” 확대/축소를 하고 싶다면 ì¶• ë˜ëŠ” ì¶• ë¼ë²¨ì„ ì„ íƒí•˜ì„¸ìš”. Line type: í–‰ 타입: None 사용하지 ì•ŠìŒ Line í–‰ StepLeft 왼쪽으로 StepRight 오른쪽으로 StepCenter 중앙으로 Impulse 임펄스(Impulse) Point shape: í¬ì¸íЏ 모양: Cross ì‹­ìžê°€ Plus ë”하기 Circle ì› Disc 디스í¬(Disc) Square 정사ê°í˜• Diamond 마름모 Star 별 Triangle 삼ê°í˜• TriangleInverted 역삼ê°í˜• CrossSquare CrossSquare PlusSquare PlusSquare CrossCircle CrossCircle PlusCircle PlusCircle Peace Peace <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>현재 플롯 저장하기...</p><p>íŒŒì¼ í¬ë§· 확장ìžë¥¼ ì„ íƒí•˜ì„¸ìš” (png, jpg, pdf, bmp)</p></body></html> Save current plot... 현재 플롯 저장하기... Load all data and redraw plot 모든 ë°ì´í„°ë¥¼ 불러와서 í”Œë¡¯ì„ ë‹¤ì‹œ 그립니다 Row # í–‰ # Copy 복사 Print... ì¸ì‡„하기... Show legend 범례 표시 Stacked bars ëˆ„ì  ë§‰ëŒ€ Fixed number format ê³ ì • ìˆ«ìž í˜•ì‹ Date/Time ë‚ ì§œ/시간 Date ë‚ ì§œ Time 시간 Numeric ìˆ«ìž Label ë ˆì´ë¸” Invalid 올바르지 ì•ŠìŒ Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. 모든 ë°ì´í„°ë¥¼ 불러와서 í”Œë¡¯ì„ ë‹¤ì‹œ 그립니다. 주ì˜: ì´ ê¸°ëŠ¥ì€ ë¶€ë¶„ë§Œ 가져오는 메커니즘으로 ì¸í•˜ì—¬ í…Œì´ë¸”ì—서 모든 ë°ì´í„°ê°€ 가져와지지는 않습니다. Choose an axis color ì¶• ìƒ‰ê¹”ì„ ì„ íƒí•˜ì„¸ìš” Choose a filename to save under 저장하려는 파ì¼ëª…ì„ ì„ íƒí•˜ì„¸ìš” PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;모든 파ì¼(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. í”Œë¡¯ì— ìžˆëŠ” 곡선들 ì¤‘ì— X축으로 ì •ë ¬ëœ ê·¸ëž˜í”„ë§Œ ì„ íƒí•œ ì„ ì˜ ìŠ¤íƒ€ì¼ì„ 변경할 수 있습니다. X로 표 ë˜ëŠ” 쿼리를 정렬하여 ê³¡ì„ ì„ ì œê±°í•˜ë ¤ë©´ '사용하지 않ìŒ'ì„, ê³¡ì„ ì´ ì§€ì›í•˜ëŠ” ìŠ¤íƒ€ì¼ ì¤‘ 하나를 ì„ íƒí•˜ë ¤ë©´ 'í–‰'ì„ ì„ íƒí•˜ì„¸ìš”. Loading all remaining data for this table took %1ms. í…Œì´ë¸”ì˜ ë‚˜ë¨¸ì§€ ë°ì´í„°ë¥¼ ë¶ˆëŸ¬ì˜¤ëŠ”ë° %1msê°€ 소요ë˜ì—ˆìŠµë‹ˆë‹¤. PreferencesDialog Preferences 환경설정 &General ì¼ë°˜(&G) Remember last location 마지막 위치를 기억 Always use this location í•­ìƒ ì´ ìœ„ì¹˜ë¥¼ 사용 Remember last location for session only ê°™ì€ ì„¸ì…˜ì—서만 마지막 위치를 기억 ... ... Default &location 기본 위치(&L) Lan&guage 언어(&G) Automatic &updates ìžë™ ì—…ë°ì´íЏ(&U) enabled 사용하기 Show remote options ì›ê²© 옵션 보기 &Database ë°ì´í„°ë² ì´ìФ(&D) Database &encoding ë°ì´í„°ë² ì´ìФ ì¸ì½”딩(&E) Open databases with foreign keys enabled. 외래키 ê¸°ëŠ¥ì„ ì‚¬ìš©í•˜ë©° ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 엽니다. &Foreign keys 외래키(&F) Data &Browser ë°ì´í„° 보기(&B) Remove line breaks in schema &view 스키마 ë·°ì—서 ê°œí–‰ì„ ì œê±°í•©ë‹ˆë‹¤(&V) Prefetch block si&ze 프리패치 í•  블럭 í¬ê¸°(&Z) SQ&L to execute after opening database ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ì—° 후 SQLì„ ì‹¤í–‰(&L) Default field type 기본 필드 타입 Font 글꼴 &Font 글꼴(&F) Content ë‚´ìš© Symbol limit in cell ì…€ 안 심볼 한계 NULL NULL Regular 보통 Binary ë°”ì´ë„ˆë¦¬ Background 배경색 Filters í•„í„° Toolbar style 툴바 ìŠ¤íƒ€ì¼ Only display the icon ì•„ì´ì½˜ë§Œ 표시 Only display the text í…스트만 표시 The text appears beside the icon í…스트를 ì•„ì´ì½˜ 옆으로 The text appears under the icon í…스트가 ì•„ì´ì½˜ 아래로 Follow the style 애플리케ì´ì…˜ ìŠ¤íƒ€ì¼ ì ìš© DB file extensions ë°ì´í„°ë² ì´ìФ íŒŒì¼ í™•ìž¥ìž Manage 관리 Main Window ë©”ì¸ ì°½ Database Structure ë°ì´í„°ë² ì´ìФ 구조 Browse Data ë°ì´í„° 보기 Execute SQL SQL 실행 Edit Database Cell ë°ì´í„°ë² ì´ìФ ì…€ 수정 When this value is changed, all the other color preferences are also set to matching colors. ì´ ê°’ì´ ë³€ê²½ë˜ë©´ 다른 모든 색ìƒë“¤ë„ ì´ì— ì¼ì¹˜í•˜ëŠ” 색ìƒìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. Follow the desktop style ë°ìФí¬í†± ìŠ¤íƒ€ì¼ ì ìš© Dark style 어둡게 Application style 애플리케ì´ì…˜ ìŠ¤íƒ€ì¼ This sets the font size for all UI elements which do not have their own font size option. 개별 글꼴 í¬ê¸° ì˜µì…˜ì´ ì—†ëŠ” 모든 UI ìš”ì†Œì˜ ê¸€ê¼´ í¬ê¸°ë¥¼ 설정합니다. Font size 글꼴 í¬ê¸° Prompt to save SQL tabs in new project file 새 프로ì íЏ 파ì¼ì—서 SQL íƒ­ì„ ì €ìž¥í•˜ë¼ëŠ” 메시지 출력 If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. ì´ ê¸°ëŠ¥ì„ ì¼œë©´ SQL편집기 íƒ­ì„ ë‹«ì„ ë•Œ 코드 ë³€ê²½ì‚¬í•­ì„ í”„ë¡œì íŠ¸ì— ì €ìž¥í•  ì§€ 물어봅니다. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. 활성화ë˜ë©´ DB 구조 íƒ­ì˜ ìŠ¤í‚¤ë§ˆ ì—´ì—서 줄 바꿈, ë… ë° ì¸ì‡„ëœ ì¶œë ¥ì´ ì œê±°ë©ë‹ˆë‹¤. Database structure font size ë°ì´í„°ë² ì´ìФ 구조 글꼴 í¬ê¸° Font si&ze 글꼴 í¬ê¸°(&Z) This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. ì—°ì‚°ì´ ë§Žì´ ê±¸ë¦¬ëŠ” ì¼ë¶€ ê¸°ëŠ¥ì„ í™œì„±í™”í•˜ëŠ”ë° í—ˆìš©ë˜ëŠ” 최대 항목 수입니다. ì—´ì˜ í˜„ìž¬ ê°’ì„ ê¸°ë°˜ìœ¼ë¡œ ê°’ ì™„ì„±ì„ í™œì„±í™”í•˜ê¸° 위한 í…Œì´ë¸”ì˜ ìµœëŒ€ í–‰ì˜ ê°¯ìˆ˜ìž…ë‹ˆë‹¤. 합계 ë° í‰ê· ì„ 계산하려는 ì„ íƒ í•­ëª©ì˜ ìµœëŒ€ ì¸ë±ìФ 수입니다. 기능 비활성화하려면 0으로 설정하세요. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. ì—´ì˜ í˜„ìž¬ ê°’ì„ ê¸°ë°˜ìœ¼ë¡œ ê°’ ì™„ì„±ì„ í™œì„±í™”í•˜ê¸° 위한 í…Œì´ë¸”ì˜ ìµœëŒ€ í–‰ 수입니다. 비활성화하려면 0으로 설정하세요. Close button on tabs íƒ­ì— ë‹«ê¸° 버튼 If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. 활성화ë˜ë©´ SQL 편집기 íƒ­ì— ë‹«ê¸° ë²„íŠ¼ì´ ìƒê¹ë‹ˆë‹¤. ì–´ë–¤ 경우든 컨í…스트 메뉴나 키보드 단축기를 사용하여 ë‹«ì„ ìˆ˜ 있습니다. Select built-in extensions to load for every database: 모든 ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•´ 불러 올 내장 확장기능: Proxy 프ë¡ì‹œ Configure 설정 Field display 필드 출력 Light style ë°ì€ 테마 Max Recent Files 최근 ì—° íŒŒì¼ ëª©ë¡ ìµœëŒ€ê°’ Displayed &text 출력 í…스트(&T) Click to set this color ì„ íƒí•˜ì—¬ ì´ ìƒ‰ìƒì„ ì„ íƒí•˜ì„¸ìš” Text color 글ìžìƒ‰ Background color 배경색 Preview only (N/A) 미리보기만 출력 (N/A) Escape character ì´ìŠ¤ì¼€ì´í”„ ë¬¸ìž Delay time (&ms) 대기 시간 (&ms) Formatted ì„œì‹ Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. 새로운 í•„í„° ê°’ì„ ì ìš©í•˜ê¸° ì „ì— ëŒ€ê¸°í•  ì‹œê°„ì„ ì„¤ì •í•˜ì„¸ìš”. 대기 ì‹œê°„ì„ 0으로 하면 대기하지 않습니다. &SQL SQL(&S) Context ë‚´ìš© Colour 색깔 Bold 진하게 Italic 기울게 Underline 밑줄 Keyword 키워드 Function 함수 Table í…Œì´ë¸” Comment ì£¼ì„ Identifier ì‹ë³„ìž String 문ìžì—´ Current line 현재 í–‰ Selection background ì„ íƒëœ 배경색 Selection foreground ì„ íƒëœ 전경색 Highlight ê°•ì¡° SQL &editor font size SQL ì—디터 글꼴 í¬ê¸°(&E) Tab size 탭 í¬ê¸° Use tabs for indentation ë“¤ì—¬ì“°ê¸°ì— íƒ­ 사용 When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. 설정하면 Tab 키는 들여쓰기를 위해 탭 ë° ê³µë°± 문ìžë¥¼ 삽입합니다. 그렇지 않으면 공백만 사용ë©ë‹ˆë‹¤. &Wrap lines 줄 바꿈(&W) Never 사용 안 함 At word boundaries 단어 경계ì—서 At character boundaries ë¬¸ìž ê²½ê³„ì—서 At whitespace boundaries 공백ì—서 &Quotes for identifiers ì‹ë³„ìž êµ¬ë¶„ 기호(&Q) Choose the quoting mechanism used by the application for identifiers in SQL code. SQL ì½”ë“œì˜ ì‹ë³„ìžì— 대해 ì‘ìš© 프로그램ì—서 사용하는 기호를 ì„ íƒí•©ë‹ˆë‹¤. "Double quotes" - Standard SQL (recommended) "í° ë”°ì˜´í‘œ" - SQL 표준 (권장ë¨) `Grave accents` - Traditional MySQL quotes 'ìž‘ì€ ë”°ì˜´í‘œ' - MySQL 전통 ì¸ìš© 부호 [Square brackets] - Traditional MS SQL Server quotes [대괄호] - MS SQL 전통 ì¸ìš© 부호 Keywords in &UPPER CASE í‚¤ì›Œë“œì— ëŒ€í•´ 대문ìž(&U) When set, the SQL keywords are completed in UPPER CASE letters. 활성화ë˜ë©´ SQL 키워드가 대문ìžë¡œ 완성ë©ë‹ˆë‹¤. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background 활성화ë˜ë©´ 마지막 실행 ì¤‘ì— ì˜¤ë¥˜ë¥¼ ì¼ìœ¼í‚¨ SQL 코드 ì¤„ì´ ê°•ì¡° 표시ë˜ê³  ê²°ê³¼ í”„ë ˆìž„ì€ ë°±ê·¸ë¼ìš´ë“œì— 오류를 나타냅니다 <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite는 공유 ë¼ì´ë¸ŒëŸ¬ë¦¬ 파ì¼ì—서 í™•ìž¥ì„ ë¡œë“œí•˜ê¸° 위한 SQL 함수를 제공합니다. SQL 코드ì—서 <span style=" font-style:italic;">load_extension()</span> 함수를 사용하려면 ì´ ê¸°ëŠ¥ì„ í™œì„±í™”í•˜ì‹­ì‹œì˜¤.</p><p>보안 ìƒì˜ ì´ìœ ë¡œ 확장 로드는 기본ì ìœ¼ë¡œ 비활성화ë˜ì–´ 있으며 ì„¤ì •ì„ í†µí•´ 활성화해야 합니다. ì´ ì˜µì…˜ì´ ë¹„í™œì„±í™”ë˜ì–´ 있ë”ë¼ë„ í•­ìƒ GUI를 통해 í™•ìž¥ì„ ë¡œë“œí•  수 있습니다.</p></body></html> Allow loading extensions from SQL code SQL 코드ì—서 í™•ìž¥ê¸°ëŠ¥ì„ ë¶ˆëŸ¬ì˜¤ëŠ” ê²ƒì„ í—ˆìš© Remote ì›ê²© CA certificates CA ì¸ì¦ì„œ Subject CN 제목 CN Common Name ì¼ë°˜ ì´ë¦„ Subject O 제목 O Organization 기관 Valid from 유효날짜(시작) Valid to 유효날짜(ë) Serial number 시리얼 넘버 Your certificates ë‹¹ì‹ ì˜ ì¸ì¦ì„œ File íŒŒì¼ Subject Common Name 주제 ì¼ë°˜ ì´ë¦„ Issuer CN ì´ìŠˆ 등ë¡ìž CN Issuer Common Name ì´ìŠˆ 등ë¡ìž ì¼ë°˜ ì´ë¦„ Clone databases into ë°ì´í„°ë² ì´ìФ 복제하기 SQL editor &font SQL 편집기 글꼴(&F) Error indicators ì—러 표시 Hori&zontal tiling 화면 ìˆ˜í‰ ë‚˜ëˆ„ê¸°(&Z) If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. 활성화ë˜ë©´ SQL 코드 편집기와 ê²°ê³¼ í…Œì´ë¸” ë·°ê°€ 나란히 표시ë©ë‹ˆë‹¤. Code co&mpletion 코드 완성(&M) Threshold for completion and calculation on selection ì„ íƒì— 대한 완료 ë° ì—°ì‚° 임계 ê°’ Show images in cell ì…€ì— ì´ë¯¸ì§€ 표시 Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. ì…€ì— ì´ë¯¸ì§€ ë°ì´í„°ê°€ í¬í•¨ëœ BLOBì˜ ë¯¸ë¦¬ë³´ê¸°ë¥¼ 표시하려면 ì´ ì˜µì…˜ì„ í™œì„±í™”í•©ë‹ˆë‹¤. 그러나 ì´ëŠ” ë°ì´í„° 브ë¼ìš°ì €ì˜ ì„±ëŠ¥ì— ì˜í–¥ì„ ë¼ì¹  수 있습니다. Foreground 전경색 SQL &results font size SQL ê²°ê³¼ 글꼴 í¬ê¸°(&R) &Extensions 확장기능(&E) Select extensions to load for every database: 불러올 í™•ìž¥ê¸°ëŠ¥ì„ ì„ íƒí•˜ì„¸ìš”(í™•ìž¥ê¸°ëŠ¥ì€ ëª¨ë“  ë°ì´í„°ë² ì´ìŠ¤ì— ë°˜ì˜ë©ë‹ˆë‹¤): Add extension 확장기능 추가 Remove extension 확장기능 제거 <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>SQLiteì—서는 기본ì ìœ¼ë¡œ ì •ê·œ í‘œí˜„ì‹ ê¸°ëŠ¥ì„ ì œê³µí•˜ì§€ 않습니다만 애플리케ì´ì…˜ì„ 실행하여 호출하는 ê²ƒì€ ê°€ëŠ¥í•©ë‹ˆë‹¤. DB Browser for SQLiteì—서는 ì´ ì•Œê³ ë¦¬ì¦˜ì„ ë°•ìŠ¤ ë°–ì—ì„œë„ ì •ê·œ 표현ì‹ì„ 사용할 수 있ë„ë¡ ì´ ì•Œê³ ë¦¬ì¦˜ì„ êµ¬í˜„í•´ì¤ë‹ˆë‹¤. 하지만 í™•ìž¥ê¸°ëŠ¥ì„ ì‚¬ìš©í•˜ì—¬ 외부ì—서 만든 알고리즘 êµ¬í˜„ì„ ì‚¬ìš©í•˜ê³ ìž í•œë‹¤ë©´ DB Browser for SQLiteì—서 제공하는 구현 ì‚¬ìš©ì„ ìžìœ ë¡­ê²Œ ëŒ ìˆ˜ 있습니다. ì´ ê¸°ëŠ¥ì€ ì• í”Œë¦¬ì¼€ì´ì…˜ì„ 재시작해야 합니다.</p></body></html> Disable Regular Expression extension ì •ê·œ í‘œí˜„ì‹ í™•ìž¥ê¸°ëŠ¥ 비활성화 Export Settings 환경설정 내보내기 Import Settings 환경설정 불러오기 Choose a directory 디렉터리를 ì„ íƒí•˜ì„¸ìš” The language will change after you restart the application. 언어 ë³€ê²½ì€ ì• í”Œë¦¬ì¼€ì´ì…˜ì„ 재시작해야 ë°˜ì˜ë©ë‹ˆë‹¤. Select extension file 확장기능 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” Extensions(*.so *.dylib *.dll);;All files(*) 확장기능(*.so *.dylib *dll);;모든 파ì¼(*) Import certificate file ì¸ì¦ì„œ íŒŒì¼ ê°€ì ¸ì˜¤ê¸° No certificates found in this file. ì´ íŒŒì¼ì—는 ì¸ì¦ì„œê°€ 없습니다. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! ì •ë§ë¡œ ì´ ì¸ì¦ì„œë¥¼ 삭제하겠습니까? 애플리케ì´ì…˜ 설정ì—서 모든 ì¦ëª… ë°ì´í„°ê°€ ì‚­ì œë  ê²ƒìž…ë‹ˆë‹¤! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. ì €ìž¥ëœ ëª¨ë“  ì„¤ì •ì„ ì •ë§ë¡œ 초기화하시겠습니까? 모든 ì„¤ì •ì´ ì´ˆê¸°í™”ë˜ê³  기본값으로 대체ë©ë‹ˆë‹¤. Save Settings File í™˜ê²½ì„¤ì •ì„ ë‚´ë³´ë‚¼ 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” Initialization File (*.ini) 환경설정 íŒŒì¼ (*.ini) The settings file has been saved in location : 환경설정 파ì¼ì´ ë‹¤ìŒ ê²½ë¡œì— ì €ìž¥ë˜ì—ˆìŠµë‹ˆë‹¤ : Open Settings File 가져오려는 환경설정 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” The settings file was loaded properly. 환경설정 파ì¼ì„ ì •ìƒì ìœ¼ë¡œ 불러 왔습니다. The selected settings file is not a normal settings file. Please check again. ì„ íƒí•˜ì‹  환경설정 파ì¼ì€ ì •ìƒì ì¸ 환경설정 파ì¼ì´ 아닙니다. 다시 확ì¸í•´ì£¼ì„¸ìš”. ProxyDialog Proxy Configuration 프ë¡ì‹œ 설정 Pro&xy Type 프ë¡ì‹œ 종류(&X) Host Na&me 서버 주소(&M) Port í¬íЏ Authentication Re&quired ì¸ì¦ ì •ë³´ í•„ìš”(&Q) &User Name 사용ìžëª…(&U) Password 암호 None 사용하지 ì•ŠìŒ System settings 시스템 설정 HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data ë°ì´í„° 가져오기 ì—러 from record number %1 레코드 넘버: %1 . %1 . %1 Importing CSV file... CSV íŒŒì¼ ê°€ì ¸ì˜¤ê¸°... Cancel 취소 All files (*) 모든 파ì¼(*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) SQLite ë°ì´í„°ë² ì´ìФ 파ì¼(*.db *.sqlite *.sqlite3 *.db3) Left 왼쪽 Right 오른쪽 Center 중앙 Justify ì •ë ¬ SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) SQLite ë°ì´í„°ë² ì´ìФ íŒŒì¼ (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) DB Browser for SQLite 프로ì íЏ íŒŒì¼ (*.sqbpro) SQL Files (*.sql) SQL íŒŒì¼ (*.sql) All Files (*) 모든 íŒŒì¼ (*) Text Files (*.txt) í…스트 íŒŒì¼ (*.txt) Comma-Separated Values Files (*.csv) 쉼표로 êµ¬ë¶„ëœ íŒŒì¼ (*.csv) Tab-Separated Values Files (*.tsv) 탭으로 ë¶„ë¦¬ëœ íŒŒì¼ (*.tsv) Delimiter-Separated Values Files (*.dsv) 구분ìžë¡œ êµ¬ë¶„ëœ íŒŒì¼ (*.dsv) Concordance DAT files (*.dat) Concordance DAT íŒŒì¼ (*.dat) JSON Files (*.json *.js) JSON íŒŒì¼ (*.json *.js) XML Files (*.xml) XML íŒŒì¼ (*.xml) Binary Files (*.bin *.dat) ë°”ì´ë„ˆë¦¬ íŒŒì¼ (*bin *.dat) SVG Files (*.svg) SVG íŒŒì¼ (*.svg) Hex Dump Files (*.dat *.bin) Hex ë¤í”„ íŒŒì¼ (*.dat *bin) Extensions (*.so *.dylib *.dll) 확장기능 (*.so *.dylib *.dll) Initialization File (*.ini) 환경설정 íŒŒì¼ (*.ini) QsciCommand Paste 붙여넣기 Cancel 취소 QsciLexerCPP Keyword 키워드 Identifier ì‹ë³„ìž QsciLexerJSON String 문ìžì—´ QsciLexerJavaScript Regular expression ì •ê·œ í‘œí˜„ì‹ QsciLexerPython Comment ì£¼ì„ Keyword 키워드 Identifier ì‹ë³„ìž QsciLexerSQL Comment ì£¼ì„ Keyword 키워드 Identifier ì‹ë³„ìž QsciScintilla &Undo 실행 취소(&U) Select All ëª¨ë‘ ì„ íƒ RemoteCommitsModel Commit ID 커밋 ID Message 메시지 Date ë‚ ì§œ Author ì €ìž Size í¬ê¸° Authored and committed by %1 %1ì— ì˜í•´ 작성ë˜ê³  ì»¤ë°‹ë¨ Authored by %1, committed by %2 %1ì— ì˜í•´ 작성ë˜ê³ , %2ì— ì˜í•´ ì»¤ë°‹ë¨ RemoteDatabase Error opening local databases list. %1 로컬 ë°ì´í„°ë² ì´ìФ 목ë¡ì„ ì—´ë˜ ì¤‘ ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. %1 Error creating local databases list. %1 로컬 ë°ì´í„°ë² ì´ìФ 목ë¡ì„ ìƒì„±í•˜ë˜ 중 ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. %1 RemoteDock Remote ì›ê²© Local 로컬 Identity ì‹ ì› Push currently opened database to server 현재 열린 ë°ì´ë² ì´ìŠ¤ë¥¼ 서버로 ë°˜ì˜í•©ë‹ˆë‹¤ Upload 업로드 DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>ì´ ì°½ì—서는 DBHub.io 웹 사ì´íŠ¸ì˜ ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ DB Browser for SQLiteì— ì¶”ê°€í•  수 있습니다.</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DBHub.io 웹 사ì´íŠ¸ì— ë¡œê·¸ì¸(ì›í•˜ì‹œë©´ GitHub ìžê²© ì¦ëª…ì„ ì‚¬ìš©í•  수 있습니다)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ &quot;í´ë¼ì´ì–¸íЏ ì¸ì¦ì„œ ìƒì„±&quot; (ë‹¹ì‹ ì˜ ì‹ ì› ì •ë³´). 그러면 ì¸ì¦ì„œ 파ì¼ì´ 제공ë©ë‹ˆë‹¤(로컬 디스í¬ì— 저장)</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DB Browser for SQLite ì„¤ì •ì˜ ì›ê²© 탭으로 ì´ë™í•©ë‹ˆë‹¤. ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ DB Browser for SQLiteì— ìƒˆ ì¸ì¦ì„œë¥¼ 추가하고 방금 다운로드한 ì¸ì¦ì„œ 파ì¼ì„ ì„ íƒí•©ë‹ˆë‹¤.</li></ol><p>ì´ì œ ì›ê²© 패ë„ì— IDê°€ 표시ë˜ê³  ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 추가할 수 있습니다.</p></body></html> Current Database 현재 ë°ì´í„°ë² ì´ìФ Clone 복제 Branch 브랜치 Commits 커밋 Commits for 커밋 조회할 브랜치 Delete Database ë°ì´í„°ë² ì´ìФ ì‚­ì œ Delete the local clone of this database ì´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¡œì»¬ 복제본 ì‚­ì œ Open in Web Browser 웹 브ë¼ìš°ì €ì—서 열기 Open the web page for the current database in your browser 브ë¼ìš°ì €ì—서 현재 ë°ì´í„°ë² ì´ìŠ¤ì˜ ì›¹ 페ì´ì§€ë¥¼ 엽니다 Clone from Link 주소로부터 복제 Use this to download a remote database for local editing using a URL as provided on the web page of the database. ì´ë¥¼ 사용하여 로컬 íŽ¸ì§‘ì„ ìœ„í•´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ì›¹ 페ì´ì§€ì—서 ì œê³µëœ URLì„ ì‚¬ìš©í•˜ì—¬ ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 다운로드 합니다. Refresh 새로고침 Reload all data and update the views 모든 ë°ì´í„°ë¥¼ 다시 로드하고 뷰를 ì—…ë°ì´íŠ¸í•©ë‹ˆë‹¤ Clone Database ë°ì´í„°ë² ì´ìФ 복제 Open Database ë°ì´í„°ë² ì´ìФ 열기 Open the local copy of this database ì´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¡œì»¬ ë³µì œë³¸ì„ ì—½ë‹ˆë‹¤ Check out Commit 커밋 ì²´í¬ì•„웃 Download and open this specific commit ì´ íŠ¹ì • ì»¤ë°‹ì„ ë‹¤ìš´ë¡œë“œí•˜ì—¬ 엽니다 Check out Latest Commit 최신 커밋 í™•ì¸ Check out the latest commit of the current branch ì´ ë¸Œëžœì¹˜ì˜ ìµœì‹  커밋 í™•ì¸ Save Revision to File ë¦¬ë¹„ì „ì„ íŒŒì¼ì— 저장 Saves the selected revision of the database to another file ë°ì´í„°ë² ì´ìŠ¤ì˜ ì„ íƒí•œ ë¦¬ë¹„ì „ì„ ë‹¤ë¥¸ 파ì¼ì— 저장합니다 Upload Database ë°ì´í„°ë² ì´ìФ 업로드 Upload this database as a new commit ì´ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 새 커밋으로 업로드 <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>현재 기본으로 제공ë˜ëŠ” ì½ê¸° ì „ìš© ID를 사용하고 있습니다. ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 업로드하려면 DBHub.io ê³„ì •ì„ êµ¬ì„±í•˜ê³  사용해야 합니다.</p><p>ì•„ì§ DBHub.io ê³„ì •ì´ ì—†ìœ¼ì‹­ë‹ˆê¹Œ? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">지금 만들어</span></a> ì¸ì¦ì„œë¥¼ 가져옵니다. <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">여기</span></a>ì—서 ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 공유하세요.</p><p>온ë¼ì¸ ë„움ë§ì„ 보려면 <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">여기</span></a>를 방문하세요.</p></body></html> &User 사용ìž(&U) &Database ë°ì´í„°ë² ì´ìФ(&D) Back 뒤로가기 Select an identity to connect ì—°ê²°í•  ID를 ì„ íƒí•˜ì„¸ìš” Public 공개 This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. 로컬 íŽ¸ì§‘ì„ ìœ„í•´ ì›ê²© 서버ì—서 ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 다운로드합니다. 복제하려는 URLì„ ìž…ë ¥í•˜ì„¸ìš”. ë°ì´í„°ë² ì´ìŠ¤ì˜ ì›¹ 페ì´ì§€ì—서 'DB4Sì—서 ë°ì´í„°ë² ì´ìФ 복제' ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ ì´ëŸ¬í•œ URLì„ ìƒì„±í•  수 있습니다. Invalid URL: The host name does not match the host name of the current identity. ìž˜ëª»ëœ URL: 호스트 ì´ë¦„ì´ í˜„ìž¬ IDì˜ í˜¸ìŠ¤íŠ¸ ì´ë¦„ê³¼ ì¼ì¹˜í•˜ì§€ 않습니다. Invalid URL: No branch name specified. ìž˜ëª»ëœ URL: ì§€ì •ëœ ë¸Œëžœì¹˜ ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤. Invalid URL: No commit ID specified. ìž˜ëª»ëœ URL: 커밋 IDê°€ 지정ë˜ì§€ 않았습니다. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¡œì»¬ ë³µì œë³¸ì„ ìˆ˜ì •í–ˆìŠµë‹ˆë‹¤. ì´ ì»¤ë°‹ì„ ê°€ì ¸ì˜¤ë©´ ì´ëŸ¬í•œ 로컬 변경 ì‚¬í•­ì´ ë¬´ì‹œë©ë‹ˆë‹¤. 계ì†í•˜ì‹œê² ìŠµë‹ˆê¹Œ? The database has unsaved changes. Are you sure you want to push it before saving? ë°ì´í„°ë² ì´ìŠ¤ì— ì €ìž¥ë˜ì§€ ì•Šì€ ë³€ê²½ ì‚¬í•­ì´ ìžˆìŠµë‹ˆë‹¤. 저장하기 ì „ì— í‘¸ì‹œí•˜ì‹œê² ìŠµë‹ˆê¹Œ? The database you are trying to delete is currently opened. Please close it before deleting. 삭제하려는 ë°ì´í„°ë² ì´ìŠ¤ê°€ 현재 열려있습니다. 삭제하기 ì „ì— ë‹«ìœ¼ì‹­ì‹œì˜¤. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? ì´ë ‡ê²Œí•˜ë©´ ì•„ì§ ì»¤ë°‹í•˜ì§€ ì•Šì€ ëª¨ë“  변경 사항과 함께 ì´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¡œì»¬ ë²„ì „ì´ ì‚­ì œë©ë‹ˆë‹¤. ì •ë§ë¡œ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 삭제하시겠습니까? RemoteLocalFilesModel Name ì´ë¦„ Branch 브랜치 Last modified 마지막 ìˆ˜ì •ì¼ Size í¬ê¸° Commit 커밋 File íŒŒì¼ RemoteModel Name ì´ë¦„ Last modified 마지막 수정 Size í¬ê¸° Commit 커밋 Size: í¬ê¸°: Last Modified: 마지막 수정: Licence: ë¼ì´ì„¼ìФ: Default Branch: 기본 브랜치: RemoteNetwork Choose a location to save the file 파ì¼ì„ 저장할 위치를 ì„ íƒí•˜ì„¸ìš” Error opening remote file at %1. %2 %1 ì— ìžˆëŠ” ì›ê²© 파ì¼ì„ ì—´ë˜ ì¤‘ ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. %2 Error: Invalid client certificate specified. ì—러: 올바르지 ì•Šì€ í´ë¼ì´ì–¸íЏ ì¸ì¦ì„œìž…니다. Please enter the passphrase for this client certificate in order to authenticate. ì¸ì¦ì„ 위한 í´ë¼ì´ì–¸íЏ ì¸ì¦ì„œ 암호를 입력해주세요. Cancel 취소 Uploading remote database to %1 %1로 ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 업로드 중입니다 Downloading remote database from %1 %1 ì—서 ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 다운로드 중입니다. {1?} Error: Cannot open the file for sending. ì—러: 보내려는 파ì¼ì„ ì—´ 수 없습니다. RemotePushDialog Push database ë°ì´í„°ë² ì´ìФ 푸시(Push) Database na&me to push to 푸시할 ë°ì´í„°ë² ì´ìФ ì´ë¦„(&M) Commit message 커밋 메시지 Database licence ë°ì´í„°ë² ì´ìФ ë¼ì´ì„¼ìФ Public 공개 Branch 브랜치 Force push ê°•ì œ 푸시 Username 사용ìžëª… Database will be public. Everyone has read access to it. 공개 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 지정합니다. 누구나 ì½ê¸° ì ‘ê·¼ì´ ê°€ëŠ¥í•©ë‹ˆë‹¤. Database will be private. Only you have access to it. 비공개 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 지정합니다. 당신만 접근할 수 있습니다. Use with care. This can cause remote commits to be deleted. 주ì˜í•´ì„œ 사용하세요. ì›ê²© ì»¤ë°‹ì„ ì‚­ì œí•˜ëŠ” 결과를 초래할 수 있습니다. RunSql Execution aborted by user 사용ìžì— ì˜í•´ì„œ ì‹¤í–‰ì´ ì·¨ì†Œë˜ì—ˆìŠµë‹ˆë‹¤ , %1 rows affected , %1 í–‰ì´ ì˜í–¥ 받았습니다 query executed successfully. Took %1ms%2 %2 ë°ì´í„°ë² ì´ìŠ¤ì— ì¿¼ë¦¬ê°€ 성공ì ìœ¼ë¡œ 실행ë˜ì—ˆìŠµë‹ˆë‹¤. %1ms 걸렸습니다 executing query 쿼리 실행 중 SelectItemsPopup A&vailable 사용 가능한(&V) Sele&cted ì„ íƒë¨(&C) SqlExecutionArea Form í¼ Find previous match [Shift+F3] ì´ì „ 찾기 [Shift+F3] Find previous match with wrapping 랩핑(Wrapping)ëœ ì´ì „ ì¼ì¹˜ë‚´ì—­ 검색하기 Shift+F3 The found pattern must be a whole word 온전한 ë‚±ë§ ì¼ì¹˜ 검색패턴 Whole Words 온전한 ë‚±ë§ ì¼ì¹˜ Text pattern to find considering the checks in this frame ì´ í”„ë ˆìž„ 안ì—서 확ì¸í•˜ê¸° 위해 ê²€ìƒ‰í•˜ê³ ìž í•˜ëŠ” 문ìžì—´ 패턴 Find in editor 편집기 ë‚´ì—서 찾기 The found pattern must match in letter case ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ 검색패턴 Case Sensitive ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ Find next match [Enter, F3] ë‹¤ìŒ ì°¾ê¸° [Enter,F3] Find next match with wrapping 랩핑(Wrapping)으로 ë‹¤ìŒ ì°¾ê¸° F3 Interpret search pattern as a regular expression 검색 패턴 ì •ê·œ í‘œí˜„ì‹ ì‚¬ìš© <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>ì„ íƒí•˜ë©´ ì°¾ì„ íŒ¨í„´ì´ UNIX ì •ê·œ 표현ì‹ìœ¼ë¡œ í•´ì„ë©ë‹ˆë‹¤. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>를 참고하십시오.</p></body></html> Regular Expression ì •ê·œ í‘œí˜„ì‹ Close Find Bar 검색바 닫기 <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>마지막으로 ì‹¤í–‰ëœ ëª…ë ¹ë¬¸ì˜ ê²°ê³¼ìž…ë‹ˆë‹¤.</p><p>ì´ íŒ¨ë„ì„ ì¶•ì†Œí•˜ê³  대신 <span style=" font-style:italic;">사용ìž</span> ì„ íƒê³¼ 함께 <span style=" font-style:italic;">SQL 로그</span> ë…ì„ ì‚¬ìš©í•  수 있습니다.</p></body></html> Results of the last executed statements 가장 최근 실행 구문 ê²°ê³¼ This field shows the results and status codes of the last executed statements. ì´ í•„ë“œëŠ” 가장 ìµœê·¼ì— ì‹¤í–‰ëœ êµ¬ë¬¸ì˜ ê²°ê³¼ì™€ ìƒíƒœ 코드를 ë³´ì—¬ì¤ë‹ˆë‹¤. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. "%1" 파ì¼ì„ ì—´ 수 없습니다: %2. Couldn't save file: %1. 파ì¼ì„ 저장할 수 없습니다: %1. Your changes will be lost when reloading it! 다시 불러오면 변경 ì‚¬í•­ì„ ìžƒìŠµë‹ˆë‹¤! The file "%1" was modified by another program. Do you want to reload it?%2 "%1" 파ì¼ì´ 다른 í”„ë¡œê·¸ëž¨ì— ì˜í•´ 수정ë˜ì—ˆìŠµë‹ˆë‹¤. 다시 불러오겠습니까?%2 Answer "Yes to All" to reload the file on any external update without further prompting. 외부 ê°±ì‹ ì´ ìžˆì„때 물어보지 않고 파ì¼ì„ 다시 불러게 하려면 "ëª¨ë‘ ì˜ˆ"를 누르세요. Answer "No to All" to ignore any external update without further prompting. 외부 ê°±ì‹ ì´ ìžˆì„ ë•Œ 물어보지 않고 무시하려면 "ëª¨ë‘ ì•„ë‹ˆìš”"로 ì‘답합니다. Modifying and saving the file will restore prompting. 파ì¼ì„ 수정하고 저장하면 프롬프트가 ë³µì›ë©ë‹ˆë‹¤. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) abs(X) 함수는 ìˆ«ìž ë§¤ê°œë³€ìˆ˜ Xì˜ ì ˆëŒ€ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () changes() 함수는 가장 ìµœê·¼ì— ì‹¤í–‰ëœ INSERT, DELETE, UPDATE 구문ì—서 ë°ì´í„°ë² ì´ìФì—서 변경ë˜ê±°ë‚˜ 추가ë˜ê±°ë‚˜ ì‚­ì œëœ í–‰ 수를 반환합니다. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) char(X1,X2,...,XN) 함수는 ê°ê°ì˜ X1ì—서 XN ìˆ«ìž ê°’ì˜ ìœ ë‹ˆì½”ë“œ í¬ì¸íЏ ê°’ì„ ê°€ì§„ 문ìžë“¤ë¡œ êµ¬ì„±ëœ ë¬¸ìžì—´ì„ 반환합니다. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) coalesce() 함수는 첫번째 NULLì´ ì•„ë‹Œ ì¸ìž ê°’ì˜ ì‚¬ë³¸ì„ ë°˜í™˜í•©ë‹ˆë‹¤. 만약 ì¸ìž ê°’ì´ ëª¨ë‘ NULLì´ë¼ë©´ NULLì„ ë°˜í™˜í•©ë‹ˆë‹¤ (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) glob(X,Y) 함수는 "Y GLOB X" 표현ì‹ê³¼ 같습니다. (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) ifnull() 함수는 첫번째 NULLì´ ì•„ë‹Œ ì¸ìž ê°’ì˜ ì‚¬ë³¸ì„ ë°˜í™˜í•©ë‹ˆë‹¤. 만약 ì¸ìžê°’ 둘 다 NULLì´ë¼ë©´ NULLì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) instr(X,Y) 함수는 문ìžì—´ Xì—서 문ìžì—´ Yê°€ 있다면 첫 ê¸€ìž ìœ„ì¹˜ + 1 ê°’ì„ ë¦¬í„´í•©ë‹ˆë‹¤. 만약 문ìžì—´ Xì—서 문ìžì—´ Yê°€ 발견ë˜ì§€ 않는다면 0ì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) hex() 함수는 매개변수를 BLOB으로 변환한 후 blobì˜ ë‚´ìš©ì„ ëŒ€ë¬¸ìž 16진수 문ìžì—´ë¡œ 변환하여 반환합니다. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) The iif(X,Y,Z) 함수는 Xê°€ ì°¸ì´ë©´ Y ê°’ì„ ë°˜í™˜í•˜ê³ , 그렇지 않으면 Z를 반환합니다. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () last_insert_rowid() 함수는 함수가 í˜¸ì¶œëœ ë°ì´í„°ë² ì´ìФ ì—°ê²°ì—서 가장 ìµœê·¼ì— ì¶”ê°€ëœ í–‰ì˜ ROWID를 반환합니다. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) 문ìžì—´ 변수 X를 위한 것으로 length(X) 함수는 첫 번째 NUL 문ìžë¥¼ 만날 ë•Œê¹Œì§€ì˜ (ë°”ì´íЏ 수가 아닌)ë¬¸ìž ìˆ˜ë¥¼ 반환합니다. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) like() 함수는 "Y LIKE X" 표현ì‹ì„ 구현하기위해 사용합니다. (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) like() 함수는 "Y LIKE X ESCAPE Z" 표현ì‹ì„ 구현하기 위해 사용합니다. (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) load_extension(X) 함수는 Xë¼ëŠ” 공유 ë¼ì´ë¸ŒëŸ¬ë¦¬ 파ì¼ì—서 SQLite í™•ìž¥ì„ ë¡œë“œí•©ë‹ˆë‹¤. ì´ ê¸°ëŠ¥ì˜ ì‚¬ìš©ì€ í™˜ê²½ì„¤ì •ì—서 승ì¸í•˜ì—¬ì•¼ 합니다. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) The load_extension(X) 함수는 ì§„ìž…ì  Y를 사용하여 Xë¼ëŠ” 공유 ë¼ì´ë¸ŒëŸ¬ë¦¬ 파ì¼ì—서 SQLite í™•ìž¥ì„ ë¡œë“œí•©ë‹ˆë‹¤. ì´ ê¸°ëŠ¥ì˜ ì‚¬ìš©ì€ í™˜ê²½ì„¤ì •ì—서 승ì¸ë˜ì–´ì•¼ 합니다. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) lower(X) 함수는 문ìžì—´ Xì—서 모든 ASCII 문ìžë¥¼ 소문ìžë¡œ 변경한 문ìžì—´ ì‚¬ë³¸ì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) 함수는 Xì˜ ì¢Œì¸¡ì˜ ê³µë°± ì—¬ë°±ì„ ì œê±°í•©ë‹ˆë‹¤. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) ltrim(X,Y) 함수는 Xì˜ ì¢Œì¸¡ì—서 Yì— ìžˆëŠ” 모든 문ìžë¥¼ 제거한 문ìžì—´ì„ 반환합니다. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) 다중 ì¸ìžë¥¼ 제공하는 max() 함수는 주어진 ì¸ìž ê°’ 중ì—서 가장 í° ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. 만약 주어진 ì¸ìž ì¤‘ì— NULL ê°’ì´ í•˜ë‚˜ë¼ë„ 있으면 NULLì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) 다중 ì¸ìžë¥¼ 제공하는 min() 함수는 주어진 ì¸ìž ê°’ 중ì—서 가장 ìž‘ì€ ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. Y) nullif(X,Y) 함수는 ë‘ ì¸ìž ê°’ì´ ì„œë¡œ 다르면 X를 반환하고 ë‘ ì¸ìž ê°’ì´ ê°™ìœ¼ë©´ NULLì„ ë°˜í™˜í•©ë‹ˆë‹¤. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) printf(FORMAT,...) SQL 함수는 sqlite3_mprintf() C-언어 함수와 표준 C ë¼ì´ë¸ŒëŸ¬ë¦¬ì—ì„œì˜ printf() 함수처럼 ë™ìž‘합니다. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) quote(X) 함수는 X를 SQL문 ì•ˆì— í¬í•¨ë˜ê¸°ì— ì ì ˆí•˜ë„ë¡ SQL 리터럴 문ìžì—´ë¡œ 반환합니다. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () random() 함수는 -9223372036854775808와 +9223372036854775807 사ì´ì˜ pseudo-ëžœë¤ ì •ìˆ˜ë¥¼ 반환합니다. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) randomblob(N) 함수는 psedo-ëžœë¤ ë°”ì´íŠ¸ë¥¼ í¬í•¨í•œ N-ë°”ì´íЏ blobì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) replace(X,Y,Z) 함수는 문ìžì—´ Xì— ìžˆëŠ” 모든 문ìžì—´ Y를 Z로 치환한 문ìžì—´ì„ 반환합니다. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) round(X) 함수는 ë¶€ë™ì†Œìˆ˜ì  ê°’ X를 0ì˜ ìžë¦¬ì—서 반올림한 ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) round(X,Y) 함수는 ë¶€ë™ì†Œìˆ˜ì  ê°’ X를 ì†Œìˆ˜ì  ìš°ì¸¡ì—서 Yìžë¦¬ì—서 반올림한 ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X)ì€ Xì˜ ìš°ì¸¡ ê³µë°±ì„ ì œê±°í•©ë‹ˆë‹¤. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) rtrim(X,Y) 함수는 Xì˜ ìš°ì¸¡ì—서 Yì— ìžˆëŠ” 모든 문ìžë¥¼ 삭제한 문ìžì—´ì„ 반환합니다. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) soundex(X) 함수는 문ìžì—´ Xì˜ ì‚¬ìš´ë±ìФ(Soundex) ì¸ì½”딩 문ìžì—´ì„ 반환합니다. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) 함수는 문ìžì—´ Xì—서 Y번째부터 ë까지 모든 문ìžì—´ì„ 반환합니다. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) substr(X,Y,Z) 함수는 문ìžì—´ Xì—서 Y번째 문ìžë¶€í„° Zë¬¸ìž ìˆ˜ë§Œí¼ ë°˜í™˜í•©ë‹ˆë‹¤. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () total_changes() 함수는 현재 ë°ì´í„°ë² ì´ìФ ì—°ê²°ì´ ì—´ë¦° 후 INSERT, UPDATE, DELETE êµ¬ë¬¸ì— ì˜í•´ì„œ ë³€ê²½ëœ ë ˆì½”ë“œ í–‰ 수를 반환합니다. (X) trim(X) removes spaces from both ends of X. (X) trim(X) 함수는 Xì˜ ì–‘ìª½ ê³µë°±ì„ ì œê±°í•©ë‹ˆë‹¤. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) trim(X,Y) 함수는 Xì˜ ì–‘ëì—서 Yì— í•´ë‹¹í•˜ëŠ” 문ìžë“¤ì„ 삭제한 문ìžì—´ì„ 반환합니다. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) typeof(X) 함수는 í‘œí˜„ì‹ Xì˜ ë°ì´í„° íƒ€ìž…ì„ ë‚˜íƒ€ë‚´ëŠ” 문ìžì—´ì„ 반환합니다. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) unicode(X) 함수는 문ìžì—´ Xì˜ ì²« 글ìžì— 해당하는 ìˆ«ìž ìœ ë‹ˆì½”ë“œ í¬ì¸íŠ¸ë¥¼ 반환합니다. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) upper(X) 함수는 ìž…ë ¥ 문ìžì—´ Xì—서 ASCII 문ìžì— 해당하는 글ìžë¥¼ 대문ìžë¡œ 변경한 문ìžì—´ ì‚¬ë³¸ì„ ë°˜í™˜í•©ë‹ˆë‹¤. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) zeroblob(N) 함수는 N ë°”ì´íŠ¸ì˜ 0x00으로 ì´ë£¨ì–´ì§„ BLOBì„ êµ¬ì„±í•˜ì—¬ 반환합니다. (timestring,modifier,modifier,...) (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) avg() 함수는 그룹ì—서 모든 NULLì´ ì•„ë‹Œ Xì˜ ê°’ì˜ í‰ê· ì„ 반환합니다. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) count(X) 함수는 그룹ì—서 NULLì´ ì•„ë‹Œ 개수를 세어 반환합니다. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) group_concat() 함수는 Xì˜ ëª¨ë“  NULLì´ ì•„ë‹Œ ê°’ë“¤ì˜ ë¬¸ìžì—´ë¡œ í•©ì³ì„œ 반환합니다. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) group_concat() 함수는 Xì˜ ëª¨ë“  NULLì´ ì•„ë‹Œ ê°’ë“¤ì˜ ë¬¸ìžì—´ë¡œ í•©ì³ì„œ 반환합니다. 만약 매개변수 Yê°€ 있다면 ê°’ë“¤ì„ ë¬¸ìžì—´ë¡œ í•©ì¹  때 구분ìžë¡œ 사용합니다. (X) The max() aggregate function returns the maximum value of all values in the group. (X) max() 집계 함수는 그룹ì—서 모든 값들 중 가장 í° ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) min() 집계 함수는 그룹ì—서 NULLì´ ì•„ë‹Œ 모든 값들 중 가장 ìž‘ì€ ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) sum(x)ê³¼ total() 집계 함수는 ê·¸ë£¹ì˜ ëª¨ë“  NULLì´ ì•„ë‹Œ ê°’ë“¤ì˜ í•©ì„ ë°˜í™˜í•©ë‹ˆë‹¤. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () 현재 파티션 ë‚´ì˜ í–‰ 번호입니다. í–‰ì€ ì°½ ì •ì˜ì˜ ORDER BY ì ˆì— ì •ì˜ëœ 순서대로 1부터 시작하거나 ìž„ì˜ì˜ 순서로 번호가 지정ë©ë‹ˆë‹¤. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () ê° ê·¸ë£¹ì˜ ì²« 번째 í”¼ì–´ì˜ row_number ()-ê°„ê²©ì´ ìžˆëŠ” 현재 í–‰ì˜ ìˆœìœ„. ORDER BY ì ˆì´ ì—†ìœ¼ë©´ 모든 í–‰ì´ í”¼ì–´ë¡œ 간주ë˜ê³  ì´ í•¨ìˆ˜ëŠ” í•­ìƒ 1ì„ ë°˜í™˜í•©ë‹ˆë‹¤. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () 파티션 ë‚´ 현재 í–‰ì˜ í”¼ì–´ 그룹 번호 - ê°„ê²©ì´ ì—†ëŠ” 현재 í–‰ì˜ ìˆœìœ„, íŒŒí‹°ì…˜ì€ ì°½ ì •ì˜ì˜ ORDER BYì ˆì— ì •ì˜ëœ 순서대로 1부터 시작ë©ë‹ˆë‹¤. ORDER BY ì ˆì´ ì—†ìœ¼ë©´ 모든 í–‰ì´ í”¼ì–´ë¡œ 간주ë˜ì–´ ì´ í•¨ìˆ˜ëŠ” í•­ìƒ 1ì„ ë°˜í™˜í•©ë‹ˆë‹¤. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () ì´ë¦„ì—ë„ ë¶ˆêµ¬í•˜ê³  ì´ í•¨ìˆ˜ëŠ” í•­ìƒ (rank - 1)/(partition-rows - 1)ê³¼ ê°™ì€ 0.0ì—서 1.0 사ì´ì˜ ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. 여기서 rank는 내장 ì°½ 함수 rank() ë° partitionì—서 반환한 값입니다. rows는 íŒŒí‹°ì…˜ì˜ ì´ í–‰ 수 입니다. íŒŒí‹°ì…˜ì— í–‰ì´ í•˜ë‚˜ë§Œ í¬í•¨ëœ 경우 ì´ í•¨ìˆ˜ëŠ” 0.0ì„ ë°˜í™˜í•©ë‹ˆë‹¤. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () ëˆ„ì  ë¶„í¬. row-number/partition-rows로 계산ë©ë‹ˆë‹¤. 여기서 row-number는 ê·¸ë£¹ì˜ ë§ˆì§€ë§‰ í”¼ì–´ì— ëŒ€í•´ row_number()ì—서 반환한 ê°’ì´ê³  partition-rows는 íŒŒí‹°ì…˜ì˜ í–‰ 수입니다. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) ì¸ìž Nì€ ì •ìˆ˜ë¡œ 취급ë©ë‹ˆë‹¤. ì´ í•¨ìˆ˜ëŠ” ORDER BY êµ¬ë¬¸ì´ ìžˆë‹¤ë©´ ê·¸ 순서대로, 없다면 ìž„ì˜ì˜ 순서로 가능하면 균등하게 Nê°œì˜ ê·¸ë£¹ìœ¼ë¡œ 나누고 ê° ê·¸ë£¹ì— 1부터 N 사ì´ì˜ 정수를 할당합니다. 필요한 경우 í° ê·¸ë£¹ì´ ë¨¼ì € 나옵니다. ì´ í•¨ìˆ˜ëŠ” 현재 í–‰ì´ ì†í•´ìžˆëŠ” ê·¸ë£¹ì´ í• ë‹¹ëœ ì •ìˆ˜ë¥¼ 반환합니다. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) íŒŒí‹°ì…˜ì˜ ì´ì „ í–‰ì— ëŒ€í•´ expr 표현ì‹ì„ í‰ê°€í•œ 결과를 반환합니다. ë˜ëŠ” ì´ì „ í–‰ì´ ì—†ëŠ” 경우(현재 í–‰ì´ ì²«ë²ˆì§¸ì¼ ë•Œ) NULL 반환ë©ë‹ˆë‹¤. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) offset ì¸ìˆ˜ê°€ 제공ë˜ë©´ ìŒì´ 아닌 정수여야합니다. ì´ ê²½ìš° ë°˜í™˜ëœ ê°’ì€ íŒŒí‹°ì…˜ ë‚´ì˜ í˜„ìž¬ í–‰ ì´ì „ì— í–‰ 오프셋 í–‰ì— ëŒ€í•´ expr를 í‰ê°€í•œ 결과입니다. ì˜¤í”„ì…‹ì´ 0ì´ë©´ exprì´ í˜„ìž¬ í–‰ì— ëŒ€í•´ í‰ê°€ë©ë‹ˆë‹¤. 현재 í–‰ ì•žì— í–‰ 오프셋 í–‰ì´ ì—†ìœ¼ë©´ NULLì´ ë°˜í™˜ë©ë‹ˆë‹¤. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) defaultë„ ì œê³µë˜ë©´ offset으로 ì‹ë³„ëœ í–‰ì´ ì¡´ìž¬í•˜ì§€ ì•Šì•˜ì„ ë•Œ NULL 대신 반환ë©ë‹ˆë‹¤. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) íŒŒí‹°ì…˜ì˜ ë‹¤ìŒ í–‰ì— ëŒ€í•´ expr 표현ì‹ì„ í‰ê°€í•œ 결과를 반환합니다. ë˜ëŠ” ë‹¤ìŒ í–‰ì´ ì—†ëŠ” 경우(현재 í–‰ì´ ë§ˆì§€ë§‰ í–‰ì¼ ë•Œ) NULLì´ ë°˜í™˜ë©ë‹ˆë‹¤. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) offset ì¸ìˆ˜ê°€ 제공ë˜ë©´ ìŒì´ 아닌 정수여야 합니다. ì´ ê²½ìš° ë°˜í™˜ëœ ê°’ì€ íŒŒí‹°ì…˜ ë‚´ì—서 현재 í–‰ ë’¤ì— ìžˆëŠ” í–‰ 오프셋 í–‰ì— ëŒ€í•´ exprì„ í‰ê°€í•œ 결과입니다. ì˜¤í”„ì…‹ì´ 0ì´ë©´ exprì´ í˜„ìž¬ í–‰ì— ëŒ€í•´ í‰ê°€ë©ë‹ˆë‹¤. 현재 í–‰ ë’¤ì— í–‰ 오프셋 í–‰ì´ ì—†ìœ¼ë©´ NULLì´ ë°˜í™˜ë©ë‹ˆë‹¤. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr)ì´ ë‚´ìž¥ ì°½ 함수는 집계 ì°½ 함수와 ë™ì¼í•œ ë°©ì‹ìœ¼ë¡œ ê° í–‰ì˜ ì°½ í”„ë ˆìž„ì„ ê³„ì‚°í•©ë‹ˆë‹¤. ê° í–‰ì˜ ì°½ 프레임ì—서 첫 번째 í–‰ì— ëŒ€í•´ í‰ê°€ëœ exprì˜ ê°’ì„ ë¦¬í„´í•©ë‹ˆë‹¤. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr)ì´ ë‚´ìž¥ ì°½ 함수는 집계 ì°½ 함수와 ë™ì¼í•œ ë°©ì‹ìœ¼ë¡œ ê° í–‰ì˜ ì°½ í”„ë ˆìž„ì„ ê³„ì‚°í•©ë‹ˆë‹¤. ê° í–‰ì˜ ì°½ 프레임ì—서 마지막 í–‰ì— ëŒ€í•´ í‰ê°€ ëœ exprì˜ ê°’ì„ ë¦¬í„´í•©ë‹ˆë‹¤. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N)ì´ ë‚´ìž¥ ì°½ 함수는 집계 ì°½ 함수와 ë™ì¼í•œ ë°©ì‹ìœ¼ë¡œ ê° í–‰ì˜ ì°½ í”„ë ˆìž„ì„ ê³„ì‚°í•©ë‹ˆë‹¤. ì°½ í”„ë ˆìž„ì˜ N í–‰ì— ëŒ€í•´ í‰ê°€ ëœ exprì˜ ê°’ì„ ë¦¬í„´í•©ë‹ˆë‹¤. í–‰ì€ ORDER BY ì ˆì— ì •ì˜ ëœ ìˆœì„œëŒ€ë¡œ 1부터 시작하여 ì°½ 프레임 ë‚´ì—서 번호가 매겨집니다. 그렇지 않으면 ìž„ì˜ì˜ 순서로 번호가 매겨집니다. íŒŒí‹°ì…˜ì— N 번째 í–‰ì´ ì—†ìœ¼ë©´ NULLì´ ë°˜í™˜ë©ë‹ˆë‹¤. (X) Return the arccosine of X. The result is in radians. (X) Xì˜ ì•„í¬ì½”사ì¸ì„ 반환합니다. 결과는 ë¼ë””안 단위입니다. (X) Return the hyperbolic arccosine of X. (X) Xì˜ ìŒê³¡ì„  ì•„í¬ì½”사ì¸ì„ 반환합니다. (X) Return the arcsine of X. The result is in radians. (X) Xì˜ ì•„í¬ì‚¬ì¸ì„ 반환합니다. 결과는 ë¼ë””안 단위입니다. (X) Return the hyperbolic arcsine of X. (X) Xì˜ ìŒê³¡ì„  ì•„í¬ì‚¬ì¸ì„ 반환합니다. (X) Return the arctangent of X. The result is in radians. (X) Xì˜ ì•„í¬íƒ„젠트를 반환합니다. 결과는 ë¼ë””안 단위입니다. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X,Y) Y/Xì˜ ì•„í¬íƒ„젠트를 반환합니다. 결과는 ë¼ë””안입니다. ê·¸ 결과는 X와 Yì˜ ë¶€í˜¸ì— ë”°ë¼ ì˜¬ë°”ë¥¸ ì‚¬ë¶„ë©´ì— ë°°ì¹˜ë©ë‹ˆë‹¤. (X) Return the hyperbolic arctangent of X. (X) Xì˜ ìŒê³¡ì„  ì•„í¬íƒ„젠트를 반환합니다. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) X보다 í¬ê±°ë‚˜ ê°™ì€ í‘œí˜„ 가능한 첫 번째 정수 ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. Xì˜ ì–‘ìˆ˜ ê°’ì˜ ê²½ìš° ì´ ë£¨í‹´ì€ 0ì—서 반올림합니다. ìŒìˆ˜ X ê°’ì˜ ê²½ìš° ì´ ë£¨í‹´ì€ 0으로 반올림합니다. (X) Return the cosine of X. X is in radians. (X) Xì˜ ì½”ì‚¬ì¸ ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. X는 ë¼ë””안 단위입니다. (X) Return the hyperbolic cosine of X. (X) Xì˜ ìŒê³¡ì„  코사ì¸ì„ 반환합니다. (X) Convert value X from radians into degrees. (X) ê°’ X를 ë¼ë””안ì—서 ê°ë„로 변환합니다. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) 계산 e(오ì¼ëŸ¬ 수, 약 2.71828182845905)를 X로 거듭제곱합니다. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) X보다 작거나 ê°™ì€ ì²« 번째 표현 가능한 정수 ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. ì–‘ìˆ˜ì˜ ê²½ìš° ì´ í•¨ìˆ˜ëŠ” 0으로 반올림합니다. ìŒìˆ˜ì˜ 경우 ì´ í•¨ìˆ˜ëŠ” 0ì—서 반올림합니다. (X) Return the natural logarithm of X. (X) Xì˜ ìžì—° 로그를 반환합니다. (B,X) Return the base-B logarithm of X. (B,X) Xì˜ ë°‘ì´ Bì¸ ë¡œê·¸ë¥¼ 반환합니다. (X) Return the base-10 logarithm for X. (X) Xì— ëŒ€í•œ ë°‘ì´ 10ì¸ ë¡œê·¸ë¥¼ 반환합니다. (X) Return the logarithm base-2 for the number X. (X) ìˆ«ìž Xì— ëŒ€í•´ ë°‘ì´ 2ì¸ ë¡œê·¸ë¥¼ 반환합니다. (X,Y) Return the remainder after dividing X by Y. (X,Y) X를 Y로 나눈 나머지를 반환합니다. () Return an approximation for Ï€. () Ï€ì— ëŒ€í•œ ê·¼ì‚¬ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. (X,Y) Compute X raised to the power Y. (X,Y) Xì˜ ê±°ë“­ì œê³±ì„ ê³„ì‚°í•©ë‹ˆë‹¤. (X) Convert X from degrees into radians. (X) X를 ë„ì—서 ë¼ë””안으로 변환합니다. (X) Return the sine of X. X is in radians. (X) Xì˜ ì‚¬ì¸ì„ 반환합니다. X는 ë¼ë””안 단위입니다. (X) Return the hyperbolic sine of X. (X) Xì˜ ìŒê³¡ì„  사ì¸ì„ 반환합니다. (X) Return the square root of X. NULL is returned if X is negative. (X) Xì˜ ì œê³±ê·¼ì„ ë°˜í™˜í•©ë‹ˆë‹¤. Xê°€ ìŒìˆ˜ì´ë©´ NULLì´ ë°˜í™˜ë©ë‹ˆë‹¤. (X) Return the tangent of X. X is in radians. (X) Xì˜ íƒ„ì  íŠ¸ë¥¼ 반환합니다. X는 ë¼ë””안 단위입니다. (X) Return the hyperbolic tangent of X. (X) Xì˜ ìŒê³¡íƒ„젠트를 반환합니다. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) 0ì—서 가장 멀리 떨어져 있는 X와 0(í¬í•¨) 사ì´ì˜ 표현 가능한 정수를 반환합니다. ë˜ëŠ” 다시 ë§í•´ì„œ Xì˜ ì •ìˆ˜ ë¶€ë¶„ì„ 0으로 반올림하여 반환합니다. SqliteTableModel reading rows í–‰ì„ ì½ëŠ” 중 loading... 로딩 중... References %1(%2) Hold %3Shift and click to jump there 참조 %1(%2) %3Shift를 누른 ìƒíƒœì—서 ì´ë™í•˜ê³ ìž 하는 ê³³ì„ í´ë¦­í•˜ì„¸ìš” Error changing data: %1 ë°ì´í„° 수정 ì—러: %1 retrieving list of columns ì»¬ëŸ¼ì€ í•„ë“œë¡œ 표현합니다. 필드 ëª©ë¡ ê°€ì ¸ì˜¤ê¸° Fetching data... ë°ì´í„°ë¥¼ 가져오는 중입니다... Cancel 취소 TableBrowser Browse Data ë°ì´í„° íƒìƒ‰ &Table: í…Œì´ë¸”(&T): Select a table to browse data íƒìƒ‰í•˜ë ¤ëŠ” ë°ì´í„°ê°€ 있는 í…Œì´ë¸”ì„ ì„ íƒí•˜ì„¸ìš” Use this list to select a table to be displayed in the database view 리스트ì—서 í…Œì´ë¸”ì„ ì„ íƒí•˜ë©´ ë°ì´í„°ë² ì´ìФ ë·°ì—서 ë³¼ 수 있습니다 This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. ì´ê²ƒì€ ë°ì´í„°ë² ì´ìŠ¤ì˜ í…Œì´ë¸” 뷰입니다. ë‹¤ìŒ ìž‘ì—…ì„ ìˆ˜í–‰í•  수 있습니다: - ê°’ì„ ì¸ë¼ì¸ìœ¼ë¡œ 편집하기 위한 ìž‘ì„±ì„ ì‹œìž‘í•©ë‹ˆë‹¤. - ì…€ 편집기 ì°½ì—서 ë‚´ìš©ì„ íŽ¸ì§‘í•˜ë ¤ë©´ 레코드를 ë”블 í´ë¦­í•©ë‹ˆë‹¤. - ì…€ ë‚´ìš©ì„ NULL 값으로 삭제하려면 Alt+Del - Ctrl + "는 현재 레코드를 복제합니다. - ìœ„ì˜ ì…€ì—서 ê°’ì„ ë³µì‚¬í•˜ë ¤ë©´ Ctrl + ' - 표준 ì„ íƒ ë° ë³µì‚¬ / 붙여넣기 작업. Text pattern to find considering the checks in this frame ì´ í”„ë ˆìž„ 안ì—서 확ì¸í•˜ê¸° 위해 ê²€ìƒ‰í•˜ê³ ìž í•˜ëŠ” 문ìžì—´ 패턴 Find in table í…Œì´ë¸”ì—서 찾기 Find previous match [Shift+F3] ì´ì „ 찾기 [Shift+F3] Find previous match with wrapping ëž©í•‘ëœ ì´ì „ ì¼ì¹˜ë‚´ì—­ 검색하기 Shift+F3 Find next match [Enter, F3] ë‹¤ìŒ ì°¾ê¸° [Enter, F3] Find next match with wrapping 랩핑(Wrapping)으로 ë‹¤ìŒ ì°¾ê¸° F3 The found pattern must match in letter case ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ 검색패턴 Case Sensitive ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ The found pattern must be a whole word 온전한 ë‚±ë§ ì¼ì¹˜ 검색패턴 Whole Cell ì „ì²´ ì…€ Interpret search pattern as a regular expression 검색 íŒ¨í„´ì„ ì •ê·œ 표현ì‹ìœ¼ë¡œ í•´ì„ <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>ì„ íƒí•˜ë©´ 찾으려는 íŒ¨í„´ì´ UNIX ì •ê·œì‹ìœ¼ë¡œ í•´ì„ë©ë‹ˆë‹¤. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>ì„ ì°¸ê³ í•˜ì„¸ìš”.</p></body></html> Regular Expression ì •ê·œ í‘œí˜„ì‹ Close Find Bar 검색바 닫기 Text to replace with 바꾸려는 í…스트 Replace with ~로 바꾸기 Replace next match ì¼ì¹˜í•˜ëŠ” ë‹¤ìŒ í…스트 바꾸기 Replace 바꾸기 Replace all matches ì¼ì¹˜í•˜ëŠ” 모든 í…스트 바꾸기 Replace all ëª¨ë‘ ë°”ê¾¸ê¸° <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>첫 페ì´ì§€ë¡œ 갑니다.</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>í…Œì´ë¸” ë·° 맨 위로 가기 위해서는 ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì„¸ìš”.</p></body></html> |< |< Scroll one page upwards 한 페ì´ì§€ 위로 스í¬ë¡¤í•©ë‹ˆë‹¤ <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>위 í…Œì´ë¸” ë·°ì—서 레코드를 한 페ì´ì§€ 앞으로 가려면 ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì„¸ìš”.</p></body></html> < < 0 - 0 of 0 0 - 0 of 0 Scroll one page downwards 한 페ì´ì§€ 아래로 스í¬ë¡¤í•©ë‹ˆë‹¤ <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>위 í…Œì´ë¸” ë·°ì—서 레코드를 한 페ì´ì§€ 뒤로 가려면 ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì„¸ìš”.</p></body></html> > > Scroll to the end 마지막 페ì´ì§€ë¡œ ì´ë™ <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>í…Œì´ë¸” ë·° 맨 아래로 가기 위해서는 ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì„¸ìš”.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>특정 레코드로 ì´ë™í•˜ë ¤ë©´ 여기를 í´ë¦­í•˜ì„¸ìš”</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>ì´ ë²„íŠ¼ì€ íŠ¹ì • ìœ„ì¹˜ì˜ ë ˆì½”ë“œ 넘버로 가기 위해서 사용합니다.</p></body></html> Go to: 특정 레코드 행으로 가기: Enter record number to browse ì°¾ì„ ë ˆì½”ë“œ í–‰ 번호를 입력하세요 Type a record number in this area and click the Go to: button to display the record in the database view 레코드 í–‰ 번호를 입력하고 '특정 레코드 행으로 가기:' ë²„íŠ¼ì„ í´ë¦­í•˜ë©´ ë°ì´í„°ë² ì´ìФ ë·°ì— ë ˆì½”ë“œê°€ 표시ë©ë‹ˆë‹¤ 1 1 Show rowid column ì»¬ëŸ¼ì˜ rowid 표시하기 Toggle the visibility of the rowid column rowid ì»¬ëŸ¼ì„ í‘œì‹œí•˜ê±°ë‚˜ 숨ê¹ë‹ˆë‹¤ Unlock view editing ë·° 수정 잠금 해제하기 This unlocks the current view for editing. However, you will need appropriate triggers for editing. ìˆ˜ì •ì„ ìœ„í•˜ì—¬ 현재 ë·°ì˜ ìž ê¸ˆì„ í•´ì œí•©ë‹ˆë‹¤. 하지만 ìˆ˜ì •ì„ ìœ„í•´ì„œëŠ” ì ì ˆí•œ 트리거가 필요할 것입니다. Edit display format 표시 í˜•ì‹ ë³€ê²½ Edit the display format of the data in this column ì´ ì»¬ëŸ¼ì— ìžˆëŠ” ë°ì´í„°ì˜ 표시 형ì‹ì„ 수정합니다 New Record 새 레코드 Insert a new record in the current table 현재 í…Œì´ë¸”ì— ìƒˆ 레코드를 추가합니다 <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>ì´ ë²„íŠ¼ì€ ë°ì´í„°ë² ì´ìŠ¤ì— ìƒˆ 레코드를 ìƒì„±í•©ë‹ˆë‹¤.</p><ul><li><span style=" font-weight:600;">새 레코드</span>: ë°ì´í„°ë² ì´ìŠ¤ì˜ ê¸°ë³¸ê°’ìœ¼ë¡œ 새 레코드를 ìƒì„±í•©ë‹ˆë‹¤.</li><li><span style=" font-weight:600;">ê°’ 삽입...</span>: ë°ì´í„°ë² ì´ìŠ¤ì— ê°’ì„ ì‚½ìž…í•˜ê¸° ì „ì— ê°’ì„ ìž…ë ¥í•  수 있는 대화ìƒìžë¥¼ 엽니다. ì´ë¥¼ 통해 다양한 제약 ì¡°ê±´ì— ì¶©ì¡±í•˜ëŠ” ê°’ì„ ìž…ë ¥í•  수 있습니다. ì´ëŸ¬í•œ 제약으로 ì¸í•´ <span style=" font-weight:600;">새 레코드</span> ì˜µì…˜ì´ ì‹¤íŒ¨í•œ 경우ì—ë„ ì´ ëŒ€í™”ìƒìžê°€ 열립니다.</li></ul></body></html> Delete Record 레코드 ì‚­ì œ Delete the current record 현재 레코드 삭제하기 This button deletes the record or records currently selected in the table ì´ ë²„íŠ¼ì€ í…Œì´ë¸”ì—서 현재 ì„ íƒëœ 레코드를 삭제합니다 Insert new record using default values in browsed table 현재 íƒìƒ‰í•œ í…Œì´ë¸”ì˜ ê¸°ë³¸ê°’ì„ ì‚¬ìš©í•˜ì—¬ 새 레코드 삽입 Insert Values... ê°’ 추가... Open a dialog for inserting values in a new record 새 ë ˆì½”ë“œì˜ ê°’ì„ ì‚½ìž…í•˜ê¸° 위한 대화ìƒìžë¥¼ 엽니다 Export to &CSV CSV로 내보내기(&C) Export the filtered data to CSV 필러ë§ëœ ë°ì´í„°ë¥¼ CSV로 내보내기 This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. ì´ ë²„íŠ¼ì€ í˜„ìž¬ 표시ëœëŒ€ë¡œ(í•„í„°, 표시 í˜•ì‹ ë° ì—´ 순서) íƒìƒ‰ëœ í…Œì´ë¸”ì˜ ë°ì´í„°ë¥¼ CSV 파ì¼ë¡œ 내보냅니다. Export to &JSON &JSON으로 내보내기 Export the filtered data to JSON í•„í„°ë§ëœ ë°ì´í„°ë¥¼ JSON으로 내보내기 This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. ì´ ë²„íŠ¼ì€ ê²€ìƒ‰ëœ í…Œì´ë¸”ì˜ ë°ì´í„°ë¥¼ 현재 í‘œì‹œëœ ëŒ€ë¡œ(í•„í„°, 표시 í˜•ì‹ ë° ìˆœì„œ ì—´ ì´í›„) JSON 파ì¼ë¡œ 내보냅니다. Save as &view 뷰로 저장하기(&V) Save the current filter, sort column and display formats as a view 현재 í•„í„°, ì—´ ì •ë ¬ ë° í‘œì‹œ 형ì‹ì„ 뷰로 저장 This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. ì´ ë²„íŠ¼ì€ ê²€ìƒ‰ëœ í…Œì´ë¸”ì˜ í˜„ìž¬ 설정(í•„í„°, 표시 í˜•ì‹ ë° ì—´ 순서)ì„ ë‚˜ì¤‘ì— SQL 문ì—서 검색하거나 사용할 수 있는 SQL 뷰로 저장합니다. Save Table As... 다른 ì´ë¦„으로 í…Œì´ë¸” 저장... Save the table as currently displayed 현재 ì¶œë ¥ëœ í˜•íƒœë¡œ í…Œì´ë¸” 저장 <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>ì´ íŒì—… 메뉴는 현재 íƒìƒ‰ ë° í•„í„°ë§ëœ í‘œì— ì ìš©ë˜ëŠ” ë‹¤ìŒ ì˜µì…˜ì„ ì œê³µí•©ë‹ˆë‹¤.</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CSV로 내보내기: ì´ ì˜µì…˜ì€ í˜„ìž¬ 표시ëœëŒ€ë¡œ(í•„í„°, 표시 í˜•ì‹ ë° ì—´ 순서) íƒìƒ‰ëœ í…Œì´ë¸”ì˜ ë°ì´í„°ë¥¼ CSV 파ì¼ë¡œ 내보냅니다.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">뷰로 저장: ì´ ì˜µì…˜ì€ ê²€ìƒ‰ëœ í…Œì´ë¸”ì˜ í˜„ìž¬ 설정(í•„í„°, 표시 í˜•ì‹ ë° ì—´ 순서)ì„ ë‚˜ì¤‘ì— SQL 문ì—서 검색하거나 사용할 수 있는 SQL 뷰로 저장합니다.</li></ul></body></html> Hide column(s) 컬럼(들) 숨기기 Hide selected column(s) ì„ íƒí•œ 컬럼(들)ì„ ìˆ¨ê¸°ê¸° Show all columns ì „ì²´ 컬럼 보기 Show all columns that were hidden 숨겨진 ì „ì²´ 컬럼 보기 Set encoding ì¸ì½”딩 지정하기 Change the encoding of the text in the table cells í…Œì´ë¸” ì…€ ì•ˆì˜ í…스트 ì¸ì½”ë”©ì„ ë³€ê²½í•©ë‹ˆë‹¤ Set encoding for all tables 모든 í…Œì´ë¸”ì˜ ì¸ì½”딩 지정하기 Change the default encoding assumed for all tables in the database ë°ì´í„°ë² ì´ìФ ì•ˆì— ìžˆëŠ” 모든 í…Œì´ë¸”ì˜ ê¸°ë³¸ ì¸ì½”ë”©ì„ ë³€ê²½í•©ë‹ˆë‹¤ Copy column name ì—´ ì´ë¦„ 복사 Copy the database table column name to your clipboard ë°ì´í„°ë² ì´ìФ í…Œì´ë¸” ì—´ ì´ë¦„ì„ í´ë¦½ë³´ë“œì— 복사 Clear Filters í•„í„° 지우기 Clear all filters 모든 í•„í„° 지우기 This button clears all the filters set in the header input fields for the currently browsed table. ì´ ë²„íŠ¼ì€ í˜„ìž¬ íƒìƒ‰ëœ í…Œì´ë¸”ì˜ í—¤ë” ìž…ë ¥ í•„ë“œì— ì„¤ì •ëœ ëª¨ë“  필터를 ì§€ì›ë‹ˆë‹¤. Clear Sorting ì •ë ¬ 초기화 Reset the order of rows to the default í–‰ 순서를 기본값으로 재설정 This button clears the sorting columns specified for the currently browsed table and returns to the default order. ì´ ë²„íŠ¼ì€ í˜„ìž¬ ê²€ìƒ‰ëœ í…Œì´ë¸”ì— ì§€ì •ëœ ì—´ ì •ë ¬ì„ ì§€ìš°ê³  기본 순서로 ëŒì•„갑니다. Print ì¸ì‡„하기 Print currently browsed table data 현재 íƒìƒ‰í•œ í…Œì´ë¸” ë°ì´í„°ë¥¼ ì¸ì‡„합니다 Print currently browsed table data. Print selection if more than one cell is selected. 현재 찾아본 í…Œì´ë¸” ë°ì´í„°ë¥¼ ì¸ì‡„합니다. 둘 ì´ìƒì˜ ì…€ì´ ì„ íƒëœ 경우 ì„ íƒ í•­ëª©ë§Œ ì¸ì‡„합니다. Ctrl+P New Data Browser 새 ë°ì´í„° íƒìƒ‰ê¸° Add a new docked Data Browser ë„í‚¹ëœ ìƒˆ ë°ì´í„° 브ë¼ìš°ì € 추가 This button adds a new docked Data Browser, which you can detach and arrange in different layouts. ì´ ë²„íŠ¼ì€ ë¶„ë¦¬í•˜ê³  다른 ë ˆì´ì•„웃으로 정렬할 수 있는 ë„í‚¹ëœ ìƒˆ ë°ì´í„° 브ë¼ìš°ì €ë¥¼ 추가합니다. Refresh 새로고침 Refresh the data in the selected table ì„ íƒí•œ í…Œì´ë¸”ì˜ ë°ì´í„° 새로고치기 This button refreshes the data in the currently selected table. ì´ ë²„íŠ¼ì€ í˜„ìž¬ ì„ íƒëœ í…Œì´ë¸”ì˜ ë°ì´í„°ë¥¼ 새로고칩니다. F5 Find in cells ì…€ì—서 찾기 Open the find tool bar which allows you to search for values in the table view below. 아래 표 보기ì—서 ê°’ì„ ê²€ìƒ‰í•  수 있는 ë„구 모ìŒì„ 엽니다. Bold 진하게 Ctrl+B Italic 기울임 Underline 밑줄 Ctrl+U Align Right 우측으로 ì •ë ¬ Align Left 좌측으로 ì •ë ¬ Center Horizontally ê°€ìš´ë° ì •ë ¬ Justify ì •ë ¬ Edit Conditional Formats... ì¡°ê±´ë¶€ ì„œì‹ íŽ¸ì§‘... Edit conditional formats for the current column ì´ ì»¬ëŸ¼ì˜ ì¡°ê±´ë¶€ ì„œì‹ íŽ¸ì§‘ Clear Format ì„œì‹ ì§€ìš°ê¸° Clear All Formats 모든 í•„í„° 지우기 Clear all cell formatting from selected cells and all conditional formats from selected columns ì„ íƒí•œ ì…€ì˜ ëª¨ë“  ì…€ 서ì‹ê³¼ ì„ íƒí•œ ì—´ì˜ ëª¨ë“  ì¡°ê±´ë¶€ ì„œì‹ ì§€ìš°ê¸° Font Color 글ìžìƒ‰ Background Color 배경색 Toggle Format Toolbar ì„œì‹ íˆ´ë°” 토글 Show/hide format toolbar ì„œì‹ íˆ´ë°” 표시/숨기기 This button shows or hides the formatting toolbar of the Data Browser ì´ ë²„íŠ¼ì€ ë°ì´í„° 브ë¼ìš°ì €ì˜ ì„œì‹ ë„구 모ìŒì„ 표시하거나 숨ê¹ë‹ˆë‹¤ Select column 컬럼 ì„ íƒ Ctrl+Space Replace text in cells ì…€ì˜ í…스트 바꾸기 Freeze columns 컬럼 잠그기(Freeze) Make all columns from the first column up to this column not move when scrolling horizontally 가로로 스í¬ë¡¤í•  때 첫번째 열부터 ì´ ì—´ê¹Œì§€ì˜ ëª¨ë“  ì—´ì´ ì´ë™í•˜ì§€ 않ë„ë¡ í•©ë‹ˆë‹¤ Filter in any column 모든 ì—´ì—서 í•„í„°ë§ Ctrl+R %n row(s) %n ì—´(들) , %n column(s) , %n 컬럼(들) . Sum: %1; Average: %2; Min: %3; Max: %4 . 합계: %1, í‰ê· : %2, 최소값: %3, 최대값: %4 Conditional formats for "%1" "%1"ì— ëŒ€í•œ ì¡°ê±´ë¶€ ì„œì‹ determining row count... í–‰ 개수 ê²°ì • 중... %L1 - %L2 of >= %L3 L1 - %L2ì˜ >= %L3 %L1 - %L2 of %L3 L1 - %L2ì˜ %L3 (clipped at %L1 rows) (%L1 í–‰ì—서 잘림) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. ì´ ë·°ì—서 ìˆ˜ì •ì„ í™œì„±í™”í•˜ê¸° 위하여 pseudo-primary key를 입력하시기 ë°”ëžë‹ˆë‹¤. ì´ê²ƒì€ ë·°ì—서 유ì¼í•œ ì´ë¦„ì´ì–´ì•¼ 합니다. Delete Records 레코드 ì‚­ì œ Duplicate records 레코드 복제하기 Duplicate record 레코드 복제하기 Ctrl+" Adjust rows to contents ë‚´ìš©ì— ë§žê²Œ í–‰ í¬ê¸° ì¡°ì ˆ Error deleting record: %1 레코드 추가 ì—러: %1 Please select a record first 레코드를 먼저 ì„ íƒí•˜ì„¸ìš” Please choose a new encoding for all tables. 모든 í…Œì´ë¸”ì— ì„¤ì •í•  새 ì¸ì½”ë”©ì„ ì„ íƒí•˜ì„¸ìš”. Please choose a new encoding for this table. ì´ í…Œì´ë¸”ì— ì ìš©í•  새 ì¸ì½”ë”©ì„ ì„ íƒí•˜ì„¸ìš”. %1 Leave the field empty for using the database encoding. %1 ë°ì´í„°ë² ì´ìФ ì¸ì½”ë”©ì„ ì‚¬ìš©í•˜ê¸° 위해 필드를 비워둡니다. This encoding is either not valid or not supported. ì´ ì¸ì½”ë”©ì€ ì˜¬ë°”ë¥´ì§€ 않거나 ì§€ì›ë˜ì§€ 않습니다. %1 replacement(s) made. %1ê°œì˜ êµì²´ê°€ ì´ë£¨ì–´ì¡ŒìŠµë‹ˆë‹¤. TableBrowserDock New Data Browser 새 ë°ì´í„° íƒìƒ‰ê¸° Rename Data Browser ë°ì´í„° íƒìƒ‰ê¸° ì´ë¦„ 변경 Close Data Browser ë°ì´í„° íƒìƒ‰ê¸° 닫기 Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. ë°ì´í„° 브ë¼ìš°ì €ì˜ 새 ì´ë¦„ì„ ì„¤ì •í•˜ì„¸ìš”. '&&' 문ìžë¥¼ 사용하여 다ìŒì— ë”°ë¼ì˜¤ëŠ” 문ìžë¥¼ 키보드 단축키로서 사용할 수 있습니다. VacuumDialog Compact Database ë°ì´í„°ë² ì´ìФ í¬ê¸° 줄ì´ê¸°(Vacuum) Warning: Compacting the database will commit all of your changes. 주ì˜: ë°ì´í„°ë² ì´ìФ í¬ê¸° 줄ì´ê¸°ë¥¼ 하면 저장ë˜ì§€ ì•Šì€ ëª¨ë“  ìˆ˜ì •ì‚¬í•­ì´ ë°˜ì˜ë©ë‹ˆë‹¤. Please select the databases to co&mpact: í¬ê¸°ë¥¼ ì¤„ì¼ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ì„ íƒí•˜ì„¸ìš”(&M): sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_nl.ts000066400000000000000000013605311463772530400252170ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Over DB-browser voor SQLite Version Versie <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Nieuw record toevoegen Enter values for the new record considering constraints. Fields in bold are mandatory. Voer waarden in voor het nieuwe record, rekening houdend met beperkingen. Vette velden zijn verplicht. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. In de Waarde-kolom kun je de waarde opgegeven voor het veld geïdentificeerd in de Naam-kolom. De Type-kolom geeft het type van het veld aan. Standaardwaarden worden in dezelfde stijl getoond als NULL-waarden. Name Naam Type Type Value Waarde Values to insert. Pre-filled default values are inserted automatically unless they are changed. In te voeren waarden. Vooringevulde standaardwaarden worden automatisch ingevoerd, tenzij ze aanpast worden. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Wanneer je waarden in het kader hierboven bewerkt, dan wordt de SQL-opdracht voor het invoegen van een nieuw record hier getoond. Je kunt de opdracht dan nog bewerken, voordat je deze opslaat. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Opslaan</span> verstuurt de SQL-instructie voor het invoeren van een nieuw record naar de database.</p><p><span style=" font-weight:600;">Standaardwaarden herstellen</span> herstelt de initiële waarden van de <span style=" font-weight:600;">Value</span>-kolom.</p><p><span style=" font-weight:600;">Annuleren</span> sluit dit venster zonder de opdracht uit te voeren.</p></body></html> Auto-increment Automatisch ophogen Unique constraint Uniciteitsbeperking Check constraint: %1 Controlebeperking: %1 Foreign key: %1 Vreemde sleutel: %1 Default value: %1 Standaardwaarde: %1 Error adding record. Message from database engine: %1 Fout bij toevoegen record. Melding van de database: %1 Are you sure you want to restore all the entered values to their defaults? Weet je zeker dat je alle ingevoerde waarden wilt herstellen naar hun standaardwaarden? Application The user settings file location is replaced with the argument value instead of the environment variable value. De bestandslocatie van de gebruikersinstellingen is vervangen door de argumentwaarde in plaats van door de waarde van de omgevingsvariabele. Ignored environment variable (DB4S_SETTINGS_FILE) value: Negeerde de waarde van de omgevingsvariabele(DB4S_SETTINGS_FILE): Possible command line arguments: Mogelijke opdrachtregelargumenten: The file %1 does not exist Het bestand %1 bestaat niet Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Browse this table, or use it as target of a data import Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The -S/--settings option requires an argument. The option is ignored. De -S/--settings optie vereist een argument. De optie wordt genegeerd. The -o/--option and -O/--save-option options require an argument in the form group/setting=value De -o/--option and -O/--save-option opties vereisen een argument in de vorm van groep/instelling=waarde Invalid option/non-existent file: %1 Ongeldige optie of niet bestaand bestand: %1 SQLite Version SQLite-versie SQLCipher Version %1 (based on SQLite %2) SQLCipher-versie %1 (gebaseerd op SQLite %2) DB Browser for SQLite Version %1. DB-browser voor SQLite versie %1. Last commit hash when built: %1 Built for %1, running on %2 Gebouwd voor %1, draaiend op %2 Qt Version %1 Qt-versie %1 CipherDialog SQLCipher encryption SQLCipher encryptie &Password &Wachtwoord &Reenter password Wa&chtwoord herhalen Passphrase Toegangsfrase Raw key Onbewerkte sleutel Encr&yption settings Encr&yptie-instellingen SQLCipher &3 defaults SQLCipher &3 standaardwaarden SQLCipher &4 defaults SQLCipher &4 standaardwaarden Custo&m &Aangepast Page si&ze &Paginagrootte &KDF iterations KDF &iteraties HMAC algorithm &HMAC-algoritme KDF algorithm &KDF-algoritme Plaintext Header Size Platte-&tekstheadergrootte Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Geef een sleutel op om de database mee te versleutelen. Wees je ervan bewust dat als je een van de andere, optionele, opties wijzigt, je die iedere keer opnieuw moet invoeren als je het databasebestand wilt openen. Laat wachtwoordvelden leeg om de versleuteling uit te schakelen. Versleuteling kan wat tijd in beslag nemen en je doet er tevens verstandig aan een backup van je database te hebben! Onopgeslagen wijzigingen worden toegepast voordat de versleuteling aangepast wordt. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Voer de sleutel in waarmee database is versleuteld. Indien enige andere opties voor dit databasebestand gewijzigd waren dan dien je die gegevens hier nu ook opnieuw in te voeren. ColumnDisplayFormatDialog Choose display format Kies een opmaak Display format Opmaak Choose a display format for the column '%1' which is applied to each value prior to showing it. Kies een opmaak voor de kolom '%1' die op iedere waarde wordt toegepast voordat deze getoond wordt. Default Standaard Decimal number Decimaal getal Exponent notation Wetenschappelijke E-notatie Hex blob Hexadecimale blob Hex number Hexadecimaal getal Octal number Octaal getal Round number Afgerond getal Apple NSDate to date Apple NSDate naar datum Java epoch (milliseconds) to date Java-epoch (milliseconden) naar datum .NET DateTime.Ticks to date .NET DateTime.Ticks naar datum Julian day to date Juliaanse dag naar datum Unix epoch to date Unix-epoch naar datum Unix epoch to local time Unix-epoch naar lokale tijd WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Windows DATE to date Windows DATE naar datum Date as dd/mm/yyyy Datum als dd/mm/jjjj Lower case onderkast Upper case BOVENKAST Binary GUID to text Binair GUID naar datum SpatiaLite Geometry to SVG Custom Aangepast Custom display format must contain a function call applied to %1 Aangepaste opmaak moet bestaan uit een functie-aanroep die toegepast wordt op %1 Error in custom display format. Message from database engine: %1 Fout in de aangepaste opmaak. Melding van de database: %1 Custom display format must return only one column but it returned %1. Aangepaste opmaak moet slechts één kolom retourneren, maar retourneerde er %1. CondFormatManager Conditional Format Manager Voorwaardelijke-opmaakbeheerder This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Dit dialoogvenster stelt je in staat om voorwaardelijke opmaakregels te creëren en te bewerken. Iedere celstijl zal worden geselecteerd op basis van de eerst vervulde voorwaarde voor diens celwaarde. De voorwaardelijke opmaakregels kunnen omhoog en omlaag verplaatst worden. Hoger geplaatste regels hebben hogere prioriteit. De syntaxis voor de voorwaarden in dezelfde als voor filters en een lege voorwaarde wordt toegepast op alle waarden. Add new conditional format Nieuwe voorwaardelijke-opmaakregel toevoegen &Add &Toevoegen Remove selected conditional format Verwijder de geselecteerde voorwaardelijke-opmaakregel &Remove &Verwijderen Move selected conditional format up Verplaats de geselecteerde voorwaardelijke-opmaakregel omhoog Move &up Om&hoog verplaatsen Move selected conditional format down Verplaats de geselecteerde voorwaardelijke-opmaakregel omlaag Move &down Om&laag verplaatsen Foreground Voorgrond Text color Tekstkleur Background Achtergrond Background color Achtergrondkleur Font Lettertype Size Grootte Bold Vet Italic Cursief Underline Onderstreept Alignment Uitlijning Condition Voorwaarde Click to select color Klik om een kleur te selecteren Are you sure you want to clear all the conditional formats of this field? Weet je zeker dat je alle voorwaardelijke-opmaakregels voor dit veld wilt verwijderen? DBBrowserDB Please specify the database name under which you want to access the attached database Geef de databasenaam zoals je de gekoppelde database wilt benaderen Invalid file format Ongeldig bestandsformaat Do you really want to close this temporary database? All data will be lost. Weet je zeker dat je deze tijdelijke database wilt sluiten? Alle gegevens zullen verloren gaan. Do you want to save the changes made to the database file %1? Wil je de wijzigingen opslaan die je de gemaakt hebt voor database %1? Database didn't close correctly, probably still busy Database is niet goed afgesloten; waarschijnlijk nog steeds bezig Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: De database is momenteel bezig: Do you want to abort that other operation? Wil je die andere handeling afbreken? Exporting database to SQL file... Database wordt geëxporteerd naar SQL-bestand... Cancel Annuleren No database file opened Er is geen databasebestand open Executing SQL... SQL wordt uitgevoerd... Action cancelled. Handeling geannuleerd. Error in statement #%1: %2. Aborting execution%3. Fout in instructie #%1: %2. Uitvoering wordt afgebroken%3. and rolling back en teruggedraaid didn't receive any output from %1 Geen uitvoer ontvangen van %1 could not execute command: %1 kon opdracht niet uitvoeren: %1 Cannot delete this object Kan dit object niet verwijderen Cannot set data on this object Kan de gegevens niet toepassen op dit object A table with the name '%1' already exists in schema '%2'. Er bestaat al een tabel met de naam '%1' in schema '%2'. No table with name '%1' exists in schema '%2'. Er bestaat geen tabel met de naam '%1' in schema '%2'. Cannot find column %1. Kan kolom %1 niet vinden. Creating savepoint failed. DB says: %1 Het maken van een herstelpunt is niet gelukt. Melding van de database: %1 Renaming the column failed. DB says: %1 Het hernoemen van de kolom is niet gelukt. Melding van de database: %1 Releasing savepoint failed. DB says: %1 Het opheffen van een herstelpunt is niet gelukt. Melding van de database: %1 Creating new table failed. DB says: %1 Het maken van de nieuwe tabel is niet gelukt. Melding van de database: %1 Copying data to new table failed. DB says: %1 Het kopiëren van de gegevens naar de nieuwe tabel is niet gelukt. Melding van de database: %1 Deleting old table failed. DB says: %1 Het verwijderen van de oude tabel is niet gelukt. Melding van de database: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Fout bij het het herstellen van sommige objecten die met deze tabel geassocieerd zijn. Dit gebeurde hoogstwaarschijnlijk omdat kolomnamen gewijzigd zijn. Dit is de SQL-instructie die je wellicht aan wilt passen om het nogmaals mee te proberen: Error renaming table '%1' to '%2'. Message from database engine: %3 Fout bij het hernoemen van tabel '%1' naar '%2'. Melding van de database: %3 could not get list of db objects: %1 Fout bij het verkrijgen van lijst met database-objecten: %1 could not get list of databases: %1 Fout bij het verkrijgen van lijst met databases: %1 Error setting pragma %1 to %2: %3 Fout bij het omzetten van pragma %1 naar %2: %3 File not found. Bestand niet gevonden. Error loading extension: %1 Fout bij het laden van extensie: %1 Error loading built-in extension: %1 could not get column information Fout bij het verkrijgen van kolominformatie DbStructureModel Name Naam Object Object Type Type Schema Schema Database Database Browsables Doorbladerbare All Alle Temporary Tijdelijke Tables (%1) Tabellen (%1) Indices (%1) Indices (%1) Views (%1) Views (%1) Triggers (%1) Triggers (%1) EditDialog Edit database cell Databasecel bewerken This area displays information about the data present in this database cell Dit gebied toont informatie over de aanwezige gegevens in de databasecel Mode: Modus: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Dit is de lijst van ondersteunde modi voor de celbewerker. Kies een modus om de gegevens van de huidige cel te bekijken of te bewerken. Text Tekst RTL Text Rechts-naar-linkstekst Binary Binair Image Afbeelding JSON JSON XML XML Evaluation Automatically adjust the editor mode to the loaded data type De bewerker automatisch aanpassen aan het geladen gegevenstype This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Deze aanvinkbare knop zet het automatisch wisselen van de bewerkingsmodus aan of uit. Wanneer een nieuwe cel wordt geselecteerd of nieuwe gegevens worden geïmporteerd en automatisch wisselen aangevinkt is, dan verandert de modus naar het gedetecteerde gegevenstype. Je kunt de bewerkingsmodus dan alsnog handmatig aanpassen. Vink de knop uit als je handmatig wisselen wilt gebruiken tijdens het navigeren door de cellen. Auto-switch Automatisch wisselen This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Deze Qt-bewerker wordt voor rechts-naar-linksteksten gebruikt, omdat dit niet ondersteund wordt door de standaard tekstbewerker. Er werden rechts-naar-linkstekens gedetecteerd en daarom is deze bewerkingsmodus automatisch geselecteerd. Identification of the cell currently in the editor Type and size of data currently in table Apply data to cell Gegevens toepassen op cel This button saves the changes performed in the cell editor to the database cell. Deze knop slaat de wijzigingen die aangebracht zijn in de celbewerker op in de cel. Apply Toepassen Print... Afdrukken... Open preview dialog for printing displayed text Open voorvertoningsdialoogvenster om getoonde tekst af te drukken Open preview dialog for printing the data currently stored in the cell Opent een voorvertoningsdialoogvenster voor het afdrukken van de de huidige gegevens in de cel Ctrl+P Copy Hex and ASCII HEX en ASCII kopiëren Copy selected hexadecimal and ASCII columns to the clipboard De geselecteerde hexadecimale en ASCII kolommen kopiëren naar het klembord Ctrl+Shift+C Autoformat Auto-opmaak Auto-format: pretty print on loading, compact on saving. Auto-opmaak: mooi opmaken bij het laden, comprimeren bij het opslaan. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Indien geselecteerd zal de auto-opmaakfunctie de gegevens bij het laden mooi opmaken, door de tekst op te delen in regels en deze dan in te laten springen. Bij het opslaan zal de auto-opmaakfunctie de gegevens comprimeren door regeleinden en onnodige witruimte te verwijderen. &Export... &Exporteren... Export to file Naar bestand exporteren Opens a file dialog used to export the contents of this database cell to a file. Opent een bestandsdialoogvenster om de inhoud van deze databasecel naar een bestand te exporteren. &Import... &Importeren... Import from file Uit bestand importeren Opens a file dialog used to import any kind of data to this database cell. Opent een bestandsdialoogvenster om gegevens van een willekeurig gegevenstype naar deze databasecel te importeren. Set as &NULL Omzetten naar &NULL Erases the contents of the cell Wist de inhoud van de cel Word Wrap Woordterugloop Wrap lines on word boundaries Past regelterugloop toe op woordbegrenzingen Open in default application or browser In standaard applicatie of browser openen Open in application In applicatie openen The value is interpreted as a file or URL and opened in the default application or web browser. De waarde wordt geïnterpreteerd als bestand of URL en wordt geopend in de standaard applicatie of webbrower. Save file reference... Bestandsreferentie opslaan... Save reference to file Referentie in bestand opslaan Open in external application In externe applicatie openen The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Unsaved data in the cell editor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. Image data can't be viewed in this mode. Afbeeldingsgegevens kunnen niet worden getoond in deze modus. Try switching to Image or Binary mode. Probeer te wisselen naar Afbeeldings- of Binaire modus. Binary data can't be viewed in this mode. Binaire gegevens kunnen niet worden getoond in deze modus. Try switching to Binary mode. Probeer te wisselen naar Binaire modus. Image files (%1) Afbeeldingbestanden (%1) Choose a file to import Kies een bestand om te importeren %1 Image %1 Afbeelding Binary files (*.bin) Binaire bestanden (*.bin) Choose a filename to export data Kies een bestandsnaam om naar te exporteren Invalid data for this mode Ongeldige gegevens voor deze modus The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? De cel bevat ongeldige %1 gegevens. Reden: %2. Weet je zeker dat je het op de cel wilt toepassen? Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) Couldn't save file: %1. Kon het bestand niet opslaan: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. De gegevens zijn in een tijdelijk bestand opgeslagen en is geopend in de standaard applicatie. Je kunt het bestand nu bewerken en, wanneer je klaar bent, de opgeslagen nieuwe gegevens toepassen op de cel of de wijzingen annuleren. EditIndexDialog Edit Index Schema Schema-index bewerken &Name &Naam &Table &Tabel &Unique &Uniek For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Om de index slechts op een gedeelte van de tabel toe te passen kun je hier een WHERE clausule opgeven die slechts dát gedeelte van de tabel selecteert dat geïndexeerd dient te worden Partial inde&x clause Gedeeltelijke inde&x-clausule Colu&mns &Kolommen Table column Tabelkolom Type Type Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Voeg een nieuwe expressiekolom toe aan de index. Expressiekolommen bevatten SQL-expressies in plaats van kolomnamen. Index column Indexkolom Order Sortering Deleting the old index failed: %1 Het verwijderen van de oude index is mislukt: %1 Creating the index failed: %1 Het maken van de index is mislukt: %1 EditTableDialog Edit table definition Tabeldefinitie bewerken Table Tabel Advanced Geavanceerd Database sche&ma Database&schema Without Rowid Zonder &rowid Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Fields Velden Add Toevoegen Remove Verwijderen Move to top Bovenaan plaatsen Move up Omhoog verplaatsen Move down Omlaag verplaatsen Move to bottom Onderaan plaatsen Name Naam Type Type NN NN Not null Niet NULL PK PS <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> Primaire sleutel</p></body></html> AI AO Autoincrement Automatisch ophogen U U Unique Uniek Default Standaard Default value Standaardwaarde Check Controle Check constraint Controlebeperking Collation Collatie Foreign Key Vreemde sleutel <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> Vreemde sleutel</p></body></html> Index Constraints Add constraint Beperking toevoegen Remove constraint Beperking verwijderen Columns Kolommen SQL SQL Foreign Keys References Check Constraints <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Waarschuwing: </span>Er is iets aan deze tabeldefinitie dat onze parser niet volledig begrijpt. Het aanpassen en opslaan van deze tabel kan problemen opleveren.</p></body></html> Primary Key Primaire sleutel Add a primary key constraint Voeg een primaire sleutelbeperking toe Add a unique constraint Voeg een uniciteitsbeperking toe There can only be one primary key for each table. Please modify the existing primary key instead. Er kan maar een primairesleutel per tabel bestaan. Pas in plaats daarvan de al bestaande primaire sleutel aan. Error creating table. Message from database engine: %1 Fout bij maken van de tabel. Melding van de database: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Er bestaat al een veld met die naam. Hernoem dat veld eerst of kies een andere naam voor dit veld. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Naar deze kolom wordt verwezen in een vreemde sleutel in tabel %1 en kan daarom niet aangepast worden. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Er is tenminste een record waarin de waarde van dit veld NULL is. Dit maakt het onmogelijk om deze optie toe te passen. Pas de tabelgegevens eerst aan. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Er is tenminste een record waarin de waarde van dit veld geen geheel getal is. Dit maakt het onmogelijk om de AO-optie toe te passen. Pas de tabelgegevens eerst aan. Column '%1' has duplicate data. Kolom '%1' heeft gedupliceerde waarden. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Dit maakt het onmogelijk om de Uniek-optie toe te passen. Verwijder eerst de gedupliceerde waarden, zodat de Uniek-optie toe kan worden gepast. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Weet je zeker dat je het veld '%1' wilt verwijderen? Alle waarden die momenteel opgeslagen zijn in dit veld zullen verloren gaan. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Voeg eerste een veld toe dat aan de volgende criteria voldoet, voordat je de 'Zonder rowid' optie toepast: - Primaire sleutel ingeschakeld - Automatisch ophogen uitgeschakeld Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set ExportDataDialog Export data as CSV Gegevens exporteren als CSV Tab&le(s) &Tabel(-len) Colu&mn names in first line &Kolomnamen op eerste regel Fie&ld separator &Veldscheidingsteken , , ; ; Tab Tab | | Other Anders &Quote character &Scheidingsteken tekenreeks " " ' ' New line characters Nieuwe-regeltekens Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print Mooi opmaken Export data as JSON Exporteer de gegevens als JSON exporting CSV CSV wordt geëxporteerd Error while writing the file '%1': %2 Could not open output file: %1 Kon het uitvoerbestand niet openen: %1 exporting JSON JSON wordt geëxporteerd Choose a filename to export data Kies een bestandsnaam om naar te exporteren Please select at least 1 table. Selecteerd tenminste één tabel. Choose a directory Kies een map Export completed. Het exporteren is voltooid. Export finished with errors. ExportSqlDialog Export SQL... SQL exporteren... Tab&le(s) &Tabel(-len) Select All Alles selecteren Deselect All Alles deselecteren &Options &Opties Keep column names in INSERT INTO Kolomnamen behouden in INSERT INTO Multiple rows (VALUES) per INSERT statement Meervoudige records (VALUES) per INSERT-instructie Export everything Alles exporteren Export schema only Alleen het schema exporteren Export data only Alleen de gegevens exporteren Keep original CREATE statements Keep old schema (CREATE TABLE IF NOT EXISTS) Ouder schema behouden (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Ouder schema overschrijven (DROP TABLE, daarna CREATE TABLE) Please select at least one table. Selecteer tenminste één tabel. Choose a filename to export Kies een bestandsnaam om naar te exporteren Export completed. Het exporteren is voltooid. Export cancelled or failed. Het exporteren is geannuleerd of niet gelukt. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Zoeken... Find and Replace... Zoeken en Vervangen... Print... Afdrukken... ExtendedTableWidget Use as Exact Filter Als exact filter gebruiken Containing Bevat Not containing Bevat niet Not equal to Niet gelijk aan Greater than Groter dan Less than Kleiner dan Greater or equal Groter dan of gelijk aan Less or equal Kleiner dan of gelijk aan Between this and... Binnen het bereik van dit en... Regular expression Als reguliere expressie Edit Conditional Formats... Voorwaardelijke opmaakregels bewerken... Set to NULL Omzetten naar NULL Cut Knippen Copy Kopiëren Copy with Headers Kopiëren met kolomnamen Copy as SQL Kopiëren als SQL Paste Plakken Print... Afdrukken... Use in Filter Expression Gebruiken in filterexpressie Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? De inhoud van het klembord is groter dan het geselecteerde bereik. Wil je het desondanks invoegen? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>Niet alle gegevens zijn geladen. <b>Wil je alle gegevens laden voordat alle records geselecteerd worden?</b><p><p> <b>Nee</b> betekent dat gegevens laden gestopt wordt en de selectie niet toegepast zal worden.<br/> <b>Ja</b> betekent dat het een tijd kan duren totdat alle gegevens geladen zijn, maar de selectie wel toegepast zal worden.</p>Waarschuwing: Alle gegevens laden kan een grote hoeveelheid werkgeheugen vereisen voor grote tabellen. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. Kan de selectie niet omzetten naar NULL. Kolom %1 heeft een NIET NULL-beperking. FileExtensionManager File Extension Manager Bestandsextensiebeheerder &Up Om&hoog &Down Om&laag &Add &Toevoegen &Remove &Verwijderen Description Omschrijving Extensions Extensies *.extension *.extensie FilterLineEdit Filter Filter These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Deze invoervelden stellen je in staat om snelfilters toe te passen op de huidig geselecteerde tabel. Gewoonlijk worden records die de ingevoerde tekst bevatten gefilterd. De volgende operatoren worden ook ondersteund: % Jokerteken > Groter dan < Kleiner dan >= Groter dan of gelijk aan <= Kleiner dan of gelijk aan = Gelijk aan: exacte overeenkomst <> Niet gelijk aan: inverse van exacte overeenkomst x~y Bereik: waarden tussen x en y /regexp/ Waarden die voldoen aan de reguliere expressie Set Filter Expression Filterexpressie toepassen What's This? Wat is dit? Is NULL Is NULL Is not NULL Is niet NULL Is empty Is leeg Is not empty Is niet leeg Not containing... Bevat niet... Equal to... Gelijk aan... Not equal to... Niet gelijk aan... Greater than... Groter dan... Less than... Kleiner dan... Greater or equal... Groter dan of gelijk aan... Less or equal... Kleiner dan of gelijk aan... In range... Binnen het bereik... Regular expression... Reguliere expressie... Clear All Conditional Formats Verwijder alle voorwaardelijke opmaakregels Use for Conditional Format Gebruiken voor voorwaardelijke opmaak Edit Conditional Formats... Voorwaardelijke opmaakregels bewerken... FindReplaceDialog Find and Replace Zoeken en vervangen Fi&nd text: Zoek &tekst: Re&place with: Vervang &door: Match &exact case Identieke onder-/boven&kast Match &only whole words Alleen &hele woorden When enabled, the search continues from the other end when it reaches one end of the page Indien geselecteerd zal het zoeken aan het andere einde doorgaan zodra een einde bereikt is &Wrap around Door&gaan na einde When set, the search goes backwards from cursor position, otherwise it goes forward Indien geselecteerd zal, ten opzichte van de cursorpositie, achteruit in plaats van vooruit gezocht worden Search &backwards &Omgekeerd zoeken <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>Indien geselecteerd wordt alleen gezocht in de huidige selectie.</p></body></html> &Selection only Alleen in &selectie <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Indien geselecteerd wordt de zoekterm geïnterpreteerd als een UNIX reguliere expressie. Zie hiervoor <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Reguliere Expressies in Wikibooks (Engels)</a>.</p></body></html> Use regular e&xpressions Gebruik reguliere e&xpressies Find the next occurrence from the cursor position and in the direction set by "Search backwards" Zoek de eerstvolgende overeenkomst vanaf de cursorpositie, in de richting aangegeven door de optie "Omgekeerd zoeken" &Find Next Volgende &zoeken F3 &Replace &Vervangen Highlight all the occurrences of the text in the page Markeer alle overeenkomsten met de tekst in de pagina F&ind All Alles z&oeken Replace all the occurrences of the text in the page Vervang alle overeenkomsten met de tekst in de pagina Replace &All Alles v&ervangen The searched text was not found De gezochte tekst is niet gevonden The searched text was not found. De gezochte tekst is niet gevonden. The searched text was replaced one time. De gezochte tekst is één keer vervangen. The searched text was found one time. De gezochte tekst is één keer gevonden. The searched text was replaced %1 times. De gezochte tekst is %1 keer vervangen. The searched text was found %1 times. De gezochte tekst is %1 keer gevonden. ForeignKeyEditor &Reset &Herstellen Foreign key clauses (ON UPDATE, ON DELETE etc.) Vreemde-sleutelclausules (ON UPDATE, ON DELETE, etc.) ImageViewer Image Viewer Afbeeldingenbekijker Reset the scaling to match the original size of the image. Schaal de afbeelding terug naar diens oorspronkelijke grootte. Set the scaling to match the size of the viewport. Schaal de afbeelding naar de grootte van het venster. Print... Afdrukken... Open preview dialog for printing displayed image Open voorvertoningsdialoogvenster om getoonde afbeelding af te drukken Ctrl+P ImportCsvDialog Import CSV file CSV-bestand importeren Table na&me &Tabelnaam &Column names in first line &Kolomnamen op eerste regel Field &separator &Veldscheidingsteken , , ; ; Tab Tab | | Other (printable) Anders (afdrukbaar) Other (code) Anders (code) &Quote character &Scheidingsteken tekenreeks " " ' ' &Encoding &Encodering UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Other Anders Trim fields? Velden trimmen? Separate tables Tabellen scheiden Advanced Geavanceerd When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Indien geselecteerd dan wordt een lege waarde in plaats van de standaardwaarde ingevoerd voor bestaande tabellen die een standaardwaarde hebben voor deze kolom. Ignore default &values &Negeer standaardwaarden Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Indien geselecteerd dan wordt het importeren afgebroken zodra een lege waarde wordt geprobeerd in te voeren in een NIET NULL veld die geen standaardwaarde kent. Fail on missing values Afbreken bij afwezige waarden Disable data type detection Gegevenstypedetectie uitschakelen Disable the automatic data type detection when creating a new table. Schakel automatische gegevenstypedetectie uit als een nieuwe tabel wordt gemaakt. Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Tijdens het importeren in bestaande tabellen kunnen er conflicten optreden met primaire sleutels, unieke beperkingen en unieke indices. Deze instelling geeft je de keuze om daar een strategie voor te kiezen: standaard wordt het importeren afgebroken en teruggedraaid, maar je kunt ook kiezen om conflicterende records te negeren en dus niet te importeren, of om bestaande records te laten overschrijven door geïmporteerde records. Abort import Importeren afbreken Ignore row Record negeren Replace existing row Bestaand record vervangen Conflict strategy Conflictstrategie Deselect All Alles deselecteren Match Similar Overeenkomende selecteren Select All Alles selecteren There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Er bestaat al een tabel met de naam '%1' en importeren in een al bestaande tabel is alleen mogelijk als het aantal kolommen overeenkomt. There is already a table named '%1'. Do you want to import the data into it? Er bestaat al een tabel met de naam '%1'. Wil je de gegevens hierin importeren? Creating restore point failed: %1 Maken van een herstelpunt is mislukt: %1 Creating the table failed: %1 Maken van de tabel is mislukt: %1 importing CSV CSV wordt geïmporteerd Could not prepare INSERT statement: %1 Inserting row failed: %1 Invoegen van record is mislukt: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Onverwachts einde van bestand bereikt. Verzeker je ervan dat je de juiste aanhalingstekens ingesteld hebt en dat de bestandsinhoud goed geformuleerd is. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Het importeren van het bestand '%1' duurde %2ms. Hiervan werd %3ms gebruikt voor de rijfunctie. MainWindow DB Browser for SQLite DB-browser voor SQLite This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Dit is de structuur van de geopende database. Je kunt SQL-instructies vanuit een objectrij naar andere applicaties of andere vensters van 'DB-browser voor SQLite' verslepen. Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Waarschuwing: dit pragma kan niet uitgelezen worden en de waarde is daarom afgeleid. Dit pragma wijzigen kan ervoor zorgen dat een door een SQLite-extensie hergedefinieerde LIKE overschreven wordt. toolBar1 werkbalk1 &File &Bestand &Import &Importeren &Export &Exporteren &Edit Be&werken &View Bee&ld &Help &Help Too&ls E&xtra DB Toolbar Databasewerkbalk Edit Database &Cell Database&cel bewerken SQL &Log SQL-&log Show S&QL submitted by Toon S&QL van User Gebruiker Application Applicatie Error Log Foutenlog This button clears the contents of the SQL logs Deze knop leegt de inhoud van de SQL-logs &Clear &Legen This panel lets you examine a log of all SQL commands issued by the application or by yourself In dit kader kun je de logs inspecteren van alle SQL-opdrachten die door de applicatie of door jezelf zijn uitgevoerd &Plot &Plot DB Sche&ma Databasesche&ma This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Dit is de structuur van de geopende database. Je kunt meerdere objectnamen vanuit de Naam-kolom naar de SQL-bewerker verslepen en je kunt hun eigenschappen dan bewerken met behulp van contextmenu's. Dit vergemakkelijkt het opstellen van SQL-instructies. Je kunt SQL-instructies vanuit de Schema-kolom naar de SQL-bewerker of naar andere applicaties verslepen. &Remote Toegang op &afstand Project Toolbar Projectwerkbalk Extra DB toolbar Werkbalk voor gekoppelde databases Close the current database file Sluit het huidige databasebestand &New Database... &Nieuwe database... Create a new database file Maak een nieuw databasebestand This option is used to create a new database file. Deze optie wordt gebruikt om een nieuw databasebestand te maken. Ctrl+N &Open Database... &Database openen... Open an existing database file Een bestaand databasebestand openen This option is used to open an existing database file. Deze optie wordt gebruikt om een bestaand databasebestand te openen. Ctrl+O &Close Database Database &sluiten This button closes the connection to the currently open database file Deze knop verbreekt de verbinding met het huidig geopende databasebestand Ctrl+F4 &Revert Changes Wijzigingen &terugdraaien Revert database to last saved state Database terugdraaien naar de laatst opgeslagen staat This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Deze optie wordt gebruikt om het huidig geopende databasebestand terug te draaien naar de laatst opgeslagen staat. Alle wijzigingen die gemaakt zijn sinds de laatste opslag gaan verloren. &Write Changes &Wijzigingen opslaan Write changes to the database file Wijzigingen opslaan in het databasebestand This option is used to save changes to the database file. Deze optie wordt gebruikt om wijzigingen op te slaan in het databasebestand. Ctrl+S Compact &Database... &Database comprimeren... Compact the database file, removing space wasted by deleted records Comprimeer het databasebestand door lege ruimte van verwijderde records te op te schonen Compact the database file, removing space wasted by deleted records. Comprimeer het databasebestand door lege ruimte van verwijderde records te op te schonen. E&xit A&fsluiten Ctrl+Q &Database from SQL file... &Database vanuit SQL-bestand... Import data from an .sql dump text file into a new or existing database. Importeer gegevens vanuit een .sql dump tekstbestand naar een nieuwe of bestaande database. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Deze optie stelt je in staat om gegevens vanuit een .sql dump tekstbestand te importeren naar een nieuwe of bestaande database. De meeste databaseprogramma's kunnen SQL-dumpbestanden maken, waaronder MySQL en PostgreSQL. &Table from CSV file... &Tabel vanuit CSV-bestand... Open a wizard that lets you import data from a comma separated text file into a database table. Open een assistent om gegevens uit een kommagescheiden tekstbestand te importeren naar een databasetabel. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Open een assistent om gegevens uit een kommagescheiden tekstbestand (CSV) te importeren naar een databasetabel. De meeste database- en spreadsheetprogramma's kunnen CSV-bestanden maken. &Database to SQL file... &Database naar SQL-bestand... Export a database to a .sql dump text file. Exporteer een database naar een .sql dump tekstbestand. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Deze optie stelt je in staat om een database te exporteren naar een .sql dump tekstbestand. SQL-dumpbestanden bevatten de benodigde gegevens om de database opnieuw te maken in de meeste databaseprogramma's, waaronder MySQL en PostgreSQL. &Table(s) as CSV file... &Tabel(-len) naar CSV-bestand... Export a database table as a comma separated text file. Exporteer een databasetabel naar een kommagescheiden tekstbestand. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Exporteer een databasetabel naar een kommagescheiden tekstbestand, om deze te kunnen importeren in ander database- of spreadsheetprogramma. &Create Table... Tabel &maken... Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Open de tabel-makenassistent, waarin je namen en velden voor een nieuwe databasetabel kunt definiëren &Delete Table... Tabel &verwijderen... Delete Table Tabel verwijderen Open the Delete Table wizard, where you can select a database table to be dropped. Open de tabel-verwijderassistent, waarin je databasetabellen kunt selecteren om te verwijderen. &Modify Table... Tabel &wijzigen... &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs E&xecute SQL This has to be equal to the tab title in all the main tabs &Recent Files &New Database &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Create &Index... &Index maken... Open the Create Index wizard, where it is possible to define a new index on an existing database table. Open de index-makenassistent, waarin je een nieuwe index voor een bestaande databasetabel kunt definiëren. &Preferences... I&nstellingen... Open the preferences window. Open het instellingenvenster. &DB Toolbar &Databasewerkbalk Shows or hides the Database toolbar. Toont of verbergt de databasewerkbalk. W&hat's This? W&at is dit? Shift+F1 &About &Over &Recently opened &Recent geopend New &tab Nieuw &tabblad This button opens a new tab for the SQL editor Deze knop opent een nieuw tabblad in de SQL-bewerker Ctrl+T &Execute SQL SQL &uitvoeren Execute all/selected SQL Voer alle of de geselecteerde SQL uit This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Deze knop voert de huidig geselecteerde SQL-instructies uit. Indien geen tekst geselecteerd is worden alle SQL-instructies uitgevoerd. Ctrl+Return Open SQL file(s) SQL-bestand(-en) openen This button opens files containing SQL statements and loads them in new editor tabs Deze knop opent bestanden die SQL-instructies bevatten en laadt deze in nieuwe bewerkerstabbladen Ctrl+Shift+T Save SQL file SQL-bestand opslaan &Load Extension... Extensie &laden... Execute current line Huidige regel uitvoeren Execute line Regel uitvoeren This button executes the SQL statement present in the current editor line Deze knop voert de SQL-instructies uit die zich op de huidige bewerkingsregel bevindt Shift+F5 Export as CSV file Exporteren als CSV-bestand Export table as comma separated values file Tabel exporteren als bestand met kommagescheiden waarden &Wiki &Wiki F1 Bug &Report... Bugs &rapporteren... Feature Re&quest... Functionaliteit &verzoeken... Web&site Web&site &Donate on Patreon... &Doneren op Patreon... Sa&ve Project P&roject opslaan &Save Project Save the current session to a file De huidige sessie oplaan in een bestand This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Deze knop stelt je in staat om alle instellingen met betrekking tot de geopende database op te slaan in een DB-browser voor SQLite-projectbestand Open &Project... &Project openen... Open &Project Load a working session from a file Een sessie laden vanuit een bestand This button lets you open a DB Browser for SQLite project file Deze knop stelt je in staat om DB-browser voor SQLite-projectbestand te openen &Attach Database... Database &koppelen... Add another database file to the current database connection Koppel nog een databasebestand aan de huidige databaseverbinding This button lets you add another database file to the current database connection Deze knop stelt je in staat om nog een databasebestand aan de huidige databaseverbinding te koppelen &Set Encryption... Encr&yptie instellen... Save SQL file as SQL-bestand opslaan als This button saves the content of the current SQL editor tab to a file Deze knop slaat de inhoud van het huidige SQL-bewerkingstabblad op in een bestand &Browse Table &Bladeren door tabel Copy Create statement CREATE-instructie kopiëren Copy the CREATE statement of the item to the clipboard De CREATE-instructie van het item kopiëren naar het klembord SQLCipher &FAQ SQLCipher &FAQ Opens the SQLCipher FAQ in a browser window Opent de SQLCipher FAQ in een browservenster Table(&s) to JSON... Tabel(-&len) naar JSON-bestand... Export one or more table(s) to a JSON file Exporteer een of meerdere tabel(-len) naar een JSON-bestand Open Data&base Read Only... Database als &alleen-lezen openen... Open an existing database file in read only mode Een bestaand databasebestand openen in alleen-lezenmodus Ctrl+Shift+O Save results Resultaten opslaan Save the results view Het resultatenoverzicht opslaan This button lets you save the results of the last executed query Deze knop stelt je in staat om de resultaten van de laatst uitgevoerde opdracht op te slaan Find text in SQL editor Tekst zoeken in de SQL-bewerker Find Zoeken This button opens the search bar of the editor Deze knop opent de zoekbalk van de bewerker Ctrl+F Find or replace text in SQL editor Tekst zoeken of vervangen in de SQL-bewerker Find or replace Zoeken of vervangen This button opens the find/replace dialog for the current editor tab Deze knop opent het zoek-en-vervangdialoogvenster voor het huidige bewerkerstabblad Ctrl+H Export to &CSV Exporteren naar &CSV Export to &JSON Save as &view Opslaan als &view Save as view Opslaan als view Shows or hides the Project toolbar. Toont of verbergt de projectwerkbalk. Extra DB Toolbar Gekoppelde-databaseswerkbalk &Open Database New In-&Memory Database Nieuwe werk&geheugendatabase Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Drag && Drop Qualified Names Gekwalificeerde namen verslepen Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Gebruik gekwalificeerde namen (bijv. "Tabel"."Veld") wanneer ik objecten versleep naar de bewerker Drag && Drop Enquoted Names Aangehaalde namen verslepen Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Gebruik aangehaalde entiteitsnamen (bijv. "Tabel1") wanneer ik objecten versleep naar de bewerker &Integrity Check &Integriteit controleren Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. Voert het pragma integrity_check uit op de geopende database en toont de resultaten in het tabblad SQL uitvoeren. Dit pragma doet een integriteitscontrole over de gehele database. &Foreign-Key Check &Vreemde sleutels controleren Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Voert het pragma foreign_key_check uit op de geopende database en toont de resultaten in het tabblad SQL uitvoeren &Quick Integrity Check Integriteit &snel controleren Run a quick integrity check over the open DB Voert een snelle integriteitscontrole uit op de geopende database Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. Voert het pragma quick_check uit op de geopende database en toont de resultaten in het tabblad SQL uitvoeren. Dit commando voert veel van de controles uit die het pragma integrity_check ook uitvoert, maar verloopt veel sneller. &Optimize &Optimaliseren Attempt to optimize the database Probeert de database te optimaliseren Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Voert het pragma optimize uit op de geopende database. Dit pragma kan optimalisaties uitvoeren die de prestaties van toekomstige SQL-opdrachten mogelijk verbeteren. Print Afdrukken Print text from current SQL editor tab Tekst uit het huidige SQL-bewerkerstabblad afdrukken Open a dialog for printing the text in the current SQL editor tab Opent een dialoogvenster voor het afdrukken van tekst uit het huidige SQL-bewerkerstabblad Ctrl+P Print the structure of the opened database De structuur van de geopende database afdrukken Open a dialog for printing the structure of the opened database Opent een dialoogvenster voor het afdrukken van de structuur van de geopende database Un/comment block of SQL code Blok SQL-code wel/niet commentaar Un/comment block Blok wel/niet commentaar Comment or uncomment current line or selected block of code De huidige regel of het geselecteerde codeblok wel/niet markeren als commentaar Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Markeert het geselecteerde codeblok, of de huidige regel indien er geen selectie is, wel/niet als commentaar. Het gehele blok wordt omgezet op basis van de eerste regel. Ctrl+/ Stop SQL execution SQL uitvoeren stoppen Stop execution Uitvoeren stoppen Stop the currently running SQL script Stop het SQL script dat nu uitgevoerd wordt &Save Project As... Pr&oject opslaan als... Save the project in a file selected in a dialog Het project opslaan in een bestand dat je selecteert in een dialoogvenster Save A&ll A&lles opslaan Save DB file, project file and opened SQL files Het databasebestand, projectbestand en alle geopende SQL-bestanden opslaan Ctrl+Shift+S Browse Table Bladeren door tabel Close Pro&ject Pro&ject sluiten Close project and database files and return to the initial state Het project en databasebestanden sluiten en terugkeren naar de oorspronkelijke staat Ctrl+Shift+W Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Refresh Verversen Reload the database structure Ctrl+Shift+F4 Detach Database Database ontkoppelen Detach database file attached to the current database connection Ontkoppel het databasebestand dat aan de huidige databaseverbinding gekoppeld is Ctrl+W Ctrl+Tab Ctrl+Shift+Tab Automatically load the last opened DB file at startup Clear List Lijst legen Ctrl+L Ctrl+D Ctrl+I Ctrl+E Window Layout Vensterindeling Reset Window Layout Vensterindeling herstellen Ctrl+Alt+0 Simplify Window Layout Vensterindeling versimpelen Alt+Shift+0 Dock Windows at Bottom Vensters dokken aan onderzijde Dock Windows at Left Side Vensters dokken aan de linkerzijde Dock Windows at Top Vensters dokken aan de bovenzijde The database is currently busy. De database is momenteel bezig. Click here to interrupt the currently running query. Klik hier om het SQL script dat nu uitgevoerd wordt te onderbreken. Encrypted Versleuteld Database is encrypted using SQLCipher Database is versleuteld met SQLCipher Read only Aleen-lezen Database file is read only. Editing the database is disabled. Het databasebestand is alleen-lezen. Het bewerken van de database is uitgeschakeld. Database encoding Databasecodering Ctrl+Alt+W Choose a database file Kies een databasebestand Could not open database file. Reason: %1 Kon het databasebestand niet openen. Reden: %1 Choose a filename to save under Kies een bestandsnaam om in op te slaan In-Memory database Werkgeheugendatabase Choose a database file to save under Error while saving the database to the new file. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Je voert nog steeds SQL-instructies uit. Het sluiten van de database zal het uitvoeren stoppen en de database daarmee mogelijk inconsistent maken. Weet je zeker dat je de database wilt sluiten? Do you want to save the changes made to the project file '%1'? Wil je de wijzigingen opslaan die je de gemaakt hebt voor projectbestand %1? Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Weet je zeker dat je de tabel '%1' wilt verwijderen? Alle gegevens die met deze tabel geassocieerd worden zullen verloren gaan. Are you sure you want to delete the view '%1'? Weet je zeker dat je de view '%1' wilt verwijderen? Are you sure you want to delete the trigger '%1'? Weet je zeker dat je de trigger '%1' wilt verwijderen? Are you sure you want to delete the index '%1'? Weet je zeker dat je de index '%1' wilt verwijderen? Error: could not delete the table. Fout: kon de tabel niet verwijderen. Error: could not delete the view. Fout: kon de view niet verwijderen. Error: could not delete the trigger. Fout: kon de trigger niet verwijderen. Error: could not delete the index. Fout: kon de index niet verwijderen. Message from database engine: %1 Melding van de database: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Het bewerken van de tabel vereist dat niet-opgeslagen wijzigingen nu opgeslagen worden. Weet je zeker dat de database op wilt slaan? Error checking foreign keys after table modification. The changes will be reverted. Fout bij het controleren van vreemde sleutels na tabelwijzigingen. De wijzigingen zullen teruggedraaid worden. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Deze tabel kwam niet door de vreemde-sleutelscontrole.<br/>Voer 'Extra | Vreemde sleutels controleren' uit en repareer de gerapporteerde problemen. Edit View %1 View %1 bewerken Edit Trigger %1 Trigger %1 bewerken You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. Je voert momenteel al SQL-instructies uit. Wil je deze stoppen en in plaats daarvan de huidige instructies uitvoeren? Wees je ervan bewust dat dit ervoor kan zorgen dat de database inconsistent wordt. -- EXECUTING SELECTION IN '%1' -- -- SELECTIE WORDT UITGEVOERD IN '%1' -- -- EXECUTING LINE IN '%1' -- -- REGEL WORDT UITGEVOERD IN '%1' -- -- EXECUTING ALL IN '%1' -- -- ALLES WORDT UITGEVOERD IN '%1' -- At line %1: In regel %1: Result: %1 Resultaat: %1 Result: %2 Resultaat: %2 %1 rows returned in %2ms %1 records geretourneerd in %2ms Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Vacuümeren of pragma's omzetten zal jouw huidige transactie committeren. Weet je het zeker? Execution finished with errors. Uitvoering voltooid met fouten. Execution finished without errors. Uitvoering voltooid zonder fouten. Choose text files Kies tekstbestanden Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Er zijn fouten opgetreden tijdens het opslaan van het databasebestand. Daarom zijn niet alle wijzigingen opgeslagen. Je dient de volgende fouten eerst op te lossen: %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? Weet je zeker dat je alle wijzigingen die je gemaakt hebt in databasebestand '%1', nadat je deze voor het laatst opgeslagen hebt, ongedaan wilt maken? Choose a file to import Kies een bestand om te importeren Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Wil je een nieuw databasebestand aanmaken om de geïmporteerde gegevens in te bewaren? Als je nee antwoordt, wordt geprobeerd om de gegevens uit het SQL-bestand te importeren in de huidige database. File %1 already exists. Please choose a different name. Bestand %1 bestaat al. Kies een andere naam. Error importing data: %1 Fout bij het importeren van de gegevens: %1 Import completed. Some foreign key constraints are violated. Please fix them before saving. Importeren voltooid. Sommige vreemde-sleutelbeperkingen werden echter geschonden. Repareer deze voordat je opslaat. Import completed. Importeren voltooid. Delete View View verwijderen Modify View View wijzigen Delete Trigger Trigger verwijderen Modify Trigger Trigger wijzigen Delete Index Index verwijderen Modify Index Index wijzigen Modify Table Tabel wijzigen Opened '%1' in read-only mode from recent file list '%1' geopend vanuit recent-geopende-bestandenlijst in alleen-lezenmodus Opened '%1' from recent file list '%1' geopend vanuit recent-geopende-bestandenlijst &%1 %2%3 &%1 %2%3 (read only) (alleen-lezen) Open Database or Project Database of project openen Attach Database... Database koppelen... Import CSV file(s)... CSV-bestand(-en) importeren... Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Selecteer de handeling die toegepast moet worden op het gesleepte bestand. <br/>Let op: alleen 'Importeren' kan op meerdere bestanden tegelijk toegepast worden. Selecteer de handeling die toegepast moet worden op de gesleepte bestanden). <br/>Let op: alleen 'Importeren' kan op meerdere bestanden tegelijk toegepast worden. Setting PRAGMA values will commit your current transaction. Are you sure? Pragma's omzetten zal jouw huidige transactie committeren. Weet je het zeker? Do you want to save the changes made to SQL tabs in a new project file? Wil je de wijzigingen die je in de SQL-tabbladen gemaakt hebt opslaan in een nieuw projectbestand? Do you want to save the changes made to SQL tabs in the project file '%1'? Wil je de wijzigingen die je in de SQL-tabbladen gemaakt hebt opslaan in het projectbestand '%1'? Do you want to save the changes made to the SQL file %1? Wil je de wijzigingen die je in SQL-bestand %1 gemaakt hebt opslaan? The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? De instructies in tabblad '%1' worden nog steeds uitgevoerd. Het sluiten van het tabblad zal het uitvoeren stoppen en de database daarmee mogelijk inconsistent maken. Weet je zeker dat je het tabblad wilt sluiten? Select SQL file to open Selecteer SQL-bestanden om te openen Text files(*.sql *.txt);;All files(*) Tekstbestanden(*.sql *.txt);;Alle bestanden(*) Select file name Selecteer bestandsnaam Select extension file Selecteer extensiebestand Extension successfully loaded. Extensie laden gelukt. Error loading extension: %1 Fout bij het laden van extensie: %1 Could not find resource file: %1 Kon het bronbestand niet vinden: %1 Don't show again Toon dit niet nogmaals New version available. Nieuwe versie beschikbaar. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Er is een nieuwe versie van DB-browser voor SQLite beschikbaar (%1.%2.%3).<br/><br/>Je kunt deze downloaden op <a href='%4'>%4</a>. Choose a project file to open Kies een projectbestand om te openen DB Browser for SQLite project file (*.sqbpro) DB-browser voor SQLite-projectbestanden (*.sqbpro) DB file '%1' could not be opened This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Dit projectbestand gebruikt een oud bestandsformaat omdat het gemaakt is met versie 3.10 of lager van DB-browser voor SQLite. Dit bestandsformaat wordt niet meer volledig ondersteund. Als je het volledig wilt kunnen laden, gebruik dan versie 3.12 van DB-browser voor SQLite om het om te zetten naar het nieuwe bestandsformaat. Table '%1' not found; settings ignored Could not open project file for writing. Reason: %1 Kon het projectbestand niet openen om naar te schrijven. Reden: %1 -- Reference to file "%1" (not supported by this version) -- Project saved to file '%1' Project opgeslagen in bestand '%1' Yes. Don't ask again Ja. Niet nogmaals vragen Collation needed! Proceed? Collatie vereist! Doorgaan? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Een table in deze database vereist een speciale collatiefunctie '%1' die deze applicatie niet kan bieden zonder extra informatie. Wees je er bewust van dat als je doorgaat er slechte dingen kunnen gebeuren met jouw database. Maak een backup! creating collation collatie aan het maken Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Geef een nieuwe naam voor het SQL-tabblad. Gebruik het '&&'-teken om de een van de volgende tekens als sneltoets in te stellen. Please specify the view name Geef de viewnaam op There is already an object with that name. Please choose a different name. Er bestaat al een object met die naam. Kies een andere naam. View successfully created. View maken gelukt. Error creating view: %1 Fout bij het maken van view: %1 This action will open a new SQL tab for running: Deze handeling opent een nieuw SQL-tabblad om het volgende uit te voeren: This action will open a new SQL tab with the following statements for you to edit and run: Deze handeling opent een nieuw SQL-tabblad met volgende instructies die je zodoende kunt bewerken en uitvoeren: Press Help for opening the corresponding SQLite reference page. Druk op Help om de bijbehorende SQLlite-referentiepagina te openen. Busy (%1) Bezig (%1) Rename Tab Tabblad hernoemen Duplicate Tab Tabblad dupliceren Close Tab Tabblad sluiten Opening '%1'... Opent '%1'... There was an error opening '%1'... Fout bij het openen van '%1'... Value is not a valid URL or filename: %1 Waarde is geen geldige URL of bestandsnaam: %1 NullLineEdit Set to NULL Omzetten naar NULL Alt+Del PlotDock Plot Plot <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Dit paneel toont de lijst van kolommen van de tabel die nu doorgebladerd wordt of van de zojuist uitgevoerde SQL-opdracht. Je kunt de kolommen selecteren die je wilt gebruiken als X- of Y-assen in de plot hieronder. De tabel toont gedetecteerde astypen die de plot zullen beïnvloeden. Voor de Y-as kun je alleen numerieke kolommen gebruiken, maar voor de X-as kun je de volgende gegevenstypen selecteren:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Datum/Tijd</span>: tekenreeksen volgens het formaat &quot;yyyy-MM-dd hh:mm:ss&quot; of &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Datum</span>: tekenreeksen volgens het formaat &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Tijd</span>: tekenreeksen volgens het formaat &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: andersoortige tekenreeksformaten. Als je dit selecteert voor de X-as dan wordt een staafdiagram geplot met de kolomwaarden als labels voor de staven</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeriek</span>: gehele of reële getallen</li></ul><p>Door dubbel te klikken op de Y-cellen kun je de kleur voor die grafiek aanpassen.</p></body></html> Columns Kolommen X X Y1 Y1 Y2 Y2 Axis Type Astype Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Hier wordt de plot getekend zodra je hierboven x- en y-waarden selecteert. Klik op punten om deze in de plot en in de tabel te selecteren. Ctrl+klik om meerdere punten te selecteren. Gebruik het muiswiel om te zoomen en sleep met de muis om het asbereik te veranderen. Selecteer de as of aslabels om alleen in die richting te slepen en te zoomen. Line type: Lijntype: None Geen Line Lijn StepLeft Stap links StepRight Stap rechts StepCenter Stap gecentreerd Impulse Impuls Point shape: Puntvorm: Cross Kruis Plus Plus Circle Cirkel Disc Discus Square Vierkant Diamond Diamant Star Ster Triangle Driehoek TriangleInverted Geïnverteerde driehoek CrossSquare Vierkant met kruis PlusSquare Vierkant met plus CrossCircle Cirkel met kruis PlusCircle Cirkel met plus Peace Vredesteken <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Huidige plot opslaan...</p><p>Bestandsformaat volgens extensie (png, jpg, pdf, bmp)</p></body></html> Save current plot... Huidige plot opslaan... Load all data and redraw plot Laad alle gegevens en teken plot opnieuw Copy Kopiëren Print... Afdrukken... Show legend Legenda tonen Stacked bars Gestapelde staven Fixed number format Date/Time Datum/Tijd Date Datum Time Tijd Numeric Numeriek Label Label Invalid Ongeldig Row # Record # Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Laad alle gegevens en teken plot opnieuw. Waarschuwing: door het partiële laadmechanisme zijn nog niet alle gegevens zijn uit de tabel opgehaald. Choose an axis color Kies een askleur Choose a filename to save under Kies een bestandsnaam om in op te slaan PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Alle bestanden(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Dit plot bevat curves, maar de geselecteerde lijnstijl kan alleen toegepast worden op diagrammen die gesorteerd worden op X. Sorteer daarom de tabel of SQL-opdracht op X of selecteer een stijl die curves ondersteunt: Geen of Lijn. Loading all remaining data for this table took %1ms. Het laden van alle overgebleven gegevens voor deze tabel duurde %1ms. PreferencesDialog Preferences Voorkeuren &General &Algemeen Default &location Standaard&locatie Remember last location Onthoud laatste locatie Always use this location Gebruik altijd deze locatie Remember last location for session only Onthoud laatste locatie alleen gedurende sessie ... ... Lan&guage &Taal Toolbar style Werkbalkstijl Only display the icon Toon alleen het icoon Only display the text Toon alleen de tekst The text appears beside the icon Toon de tekst naast het icoon The text appears under the icon Toon de tekst onder het icoon Follow the style Volg de stijl Show remote options Toon 'Toegang op afstand'-opties enabled inschakelen Automatic &updates Automatische &updates DB file extensions Databasebestandsextensies Manage Beheren Main Window Hoofdvenster Database Structure Databasestructuur Browse Data Gegevensbrowser Execute SQL SQL uitvoeren Edit Database Cell Databasecel bewerken When this value is changed, all the other color preferences are also set to matching colors. Indien deze waarde aangepast wordt, dan worden alle andere kleurvoorkeuren ook aangepast naar die stijl. Follow the desktop style Volg de desktopstijl Dark style Donkere stijl Application style Applicatiestijl This sets the font size for all UI elements which do not have their own font size option. Dit bepaalt het lettertypegrootte voor gebruikersinterface-elementen die geen eigen lettertypegrootte-instelling hebben. Font size Lettertypegrootte Max Recent Files Grootte recente bestandenlijst Prompt to save SQL tabs in new project file Vraag om SQL-tabbladen op te slaan in nieuw projectbestand If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Indien ingeschakeld toont de SQL-bewerker een dialoogvenster om het opslaan van het project mee te bevestigen zodra het SQL-bewerkingtabblad gesloten wordt. &Database &Database Database &encoding Database&codering Open databases with foreign keys enabled. Databases openen met vreemde-sleutelondersteuning ingeschakeld. &Foreign keys &Vreemde sleutels Remove line breaks in schema &view Verwijder regeleinden in schema&weergave Prefetch block si&ze Prefetch-&blokgrootte Default field type Standaard veldgegevenstype When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Indien geselecteerd worden de regeleinden verwijderd uit de schemakolom van het databasestructuurtabblad, -dock en uit geprinte afdrukken. Database structure font size Lettertypegrootte databasestructuur SQ&L to execute after opening database S&QL uitvoeren na het openen van database Data &Browser Gegevens&browser Font Lettertype &Font &Lettertype Font si&ze Lettertype&grootte Content Inhoud Symbol limit in cell Symboollimiet in cel This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Dit bepaalt het maximum aantal items dat voor sommige functionaliteiten met intensieve berekeningen toegestaan is: Het maximum aantal records in een tabel om waarde-aanvulling in te schakelen aan de hand van de huidige invoer in de kolom. Het maximaal aantal indices in een selectie om sommen en gemiddelden berekenen in te schakelen. Voer 0 in om deze functionaliteiten uit te schakelen. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Dit bepaalt het maximum aantal records in een tabel om waarde-aanvulling in te schakelen aan de hand van de huidige invoer in de kolom. Voer 0 in om waarde-aanvulling uit te schakelen. Threshold for completion and calculation on selection Drempelwaarde voor aanvullingen en berekeningen op selecties Show images in cell Toon afbeeldingen in cel Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Indien geselecteerd wordt in de cellen een voorvertoning getoond van BLOBs die afbeeldingsgegevens bevatten. Dit kan de prestaties van de gegevensbrowser echter beïnvloeden. Field display Veldweergave Displayed &text Weergegeven &tekst Binary Binair NULL NULL Regular Gewoon Click to set this color Klik om een kleur te selecteren Text color Tekstkleur Background color Achtergrondkleur Preview only (N/A) Enkel voorvertoning (N/B) Filters Filters Escape character Escape-teken Delay time (&ms) Vertragingstijd (&ms) Light style Formatted Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Bepaalt de tijd die gewacht wordt voordat een nieuw filter wordt toegepast. Voer 0 in om wachten uit te schakelen. &SQL &SQL Context Context Colour Kleur Bold Vet Italic Cursief Underline Onderstreept Keyword Sleutelwoord Function Functie Table Tabel Comment Commentaar Identifier Entiteitsnaam String Tekenreeks Current line Huidige regel Background Achtergrond Foreground Voorgrond Selection background Selectie-achtergrond Selection foreground Selectie-voorgrond Highlight Markering SQL editor &font &Lettertype SQL-bewerker SQL &editor font size Lettertypegrootte SQL-b&ewerker SQL &results font size Lettertypegrootte SQL-&resultaten Tab size Tabbreedte Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. &Wrap lines Regelteru&gloop toepassen Never Nooit At word boundaries Op woordbegrenzingen At character boundaries Op letterbegrenzingen At whitespace boundaries Op witruimtebegrenzingen &Quotes for identifiers &Aanhalingstekens voor entiteitsnamen Choose the quoting mechanism used by the application for identifiers in SQL code. Kies het aanhalingstekensbeleid van de applicatie voor het demarceren van entiteitsnamen in SQL-code. "Double quotes" - Standard SQL (recommended) "Dubbele aanhalingstekens" - Standaard SQL (aanbevolen) `Grave accents` - Traditional MySQL quotes `Accent graves` - Traditionele MySQL aanhalingstekens [Square brackets] - Traditional MS SQL Server quotes [Rechte haakjes] - Traditionele MS SQL-Server aanhalingstekens Code co&mpletion Code-aan&vulling Keywords in &UPPER CASE Sleutelwoorden in &BOVENKAST When set, the SQL keywords are completed in UPPER CASE letters. Indien geselecteerd worden SQL-sleutelwoorden voltooid in BOVENKAST-letters. Error indicators Foutindicatoren When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Indien geselecteerd dan worden de SQL-coderegels die de fouten tijdens de laatste uitvoering veroorzaakten gemarkeerd en het resultatenkader toont de fout op de achtergrond Hori&zontal tiling Hori&zontaal tegelen If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Indien geselecteerd worden de SQL-bewerker en de resultatenweergavetabel naast elkaar, in plaats van over elkaar heen, getoond. Close button on tabs Sluitknoppen op tabbladen If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Indien geselecteerd krijgen SQL-bewerkingstabbladen een sluitknop. Je kunt echter ook altijd het contextmenu of sneltoetsen gebruiken om ze te sluiten. &Extensions &Extensies Select extensions to load for every database: Selecteer extensies die voor iedere database geladen dienen te worden: Add extension Extensie toevoegen Remove extension Extensie verwijderen Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>Hoewel SQLite de REGEXP operator ondersteunt heeft ze geen reguliere-expressiesalgoritme<br/>geïmplementeerd, maar doet ze hiervoor een beroep op de hostapplicatie. DB-browser voor SQLite<br/>implementeert dit algoritme voor jou, zodat je REGEXP direct kunt gebruiken.<br/>Omdat er echter meerdere implementaties mogelijk zijn en je mogelijk een andere implementatie<br/>wilt gebruiken, staat het je vrij om onze implementatie uit te schakelen en je eigen implementatie te laden<br/>via een extensie. Hiervoor is een herstart van de applicatie nodig.</p></body></html> Disable Regular Expression extension Schakel extensie voor reguliere expressies uit <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite biedt een SQL-functie om extensies te laden vanuit een gedeelde bibliotheek. Activeer deze optie als je de <span style=" font-style:italic;">load_extension()</span> functie vanuit SQL-code wilt aanroepen.</p><p>Om veiligheidsredenen is deze manier van extensies laden standaard uitgeschakeld en dient via deze optie in te worden geschakeld. Je kunt extensies echter altijd laden via de gebruikersinterface, zelfs als deze optie uitgeschakeld is.</p></body></html> Allow loading extensions from SQL code Extensies laden vanuit SQL-code toestaan Remote Toegang op afstand Your certificates Jouw certificaten File Bestand Subject CN Subject GN Subject Common Name Subject Gebruikelijk Naam Issuer CN Verstrekker GN Issuer Common Name Verstrekker Gebruikelijke Naam Valid from Geldig vanaf Valid to Geldig tot Serial number Serienummer CA certificates CA-certificaten Common Name Gebruikelijke naam Subject O Subject O Organization Organisatie Clone databases into Database klonen naar Proxy Proxy Configure Instellen Export Settings Instellingen exporteren Import Settings Instellingen importeren Choose a directory Kies een map The language will change after you restart the application. De taal verandert nadat je de applicatie opnieuw hebt opgestart. Select extension file Selecteer extensiebestand Extensions(*.so *.dylib *.dll);;All files(*) Extensies(*.so *.dylib *.dll);;Alle bestanden(*) Import certificate file Certificaatbestand importeren No certificates found in this file. Geen certificaten gevonden in dit bestand. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Weet je zeker dat je dit certificaat wilt verwijderen? Alle certificaatgegevens zullen worden verwijderd uit de applicatie-instellingen! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Weet je zeker dat je alle opgeslagen instellingen wilt verwijderen? Al jouw instellingen zullen worden verwijderd en de standaardinstellingen zullen worden gebruikt. Save Settings File Instellingenbestand opslaan Initialization File (*.ini) Initialisatiebestand (*.ini) The settings file has been saved in location : Het instellingenbestand is opgeslagen in: Open Settings File Instellingenbestand openen The settings file was loaded properly. Het instellingenbestand is correct geladen. The selected settings file is not a normal settings file. Please check again. Het gekozen instellingenbestand is geen normaal instellingenbestand. Controleer het nogmaals. ProxyDialog Proxy Configuration Proxy-instellingen Pro&xy Type Pro&xytype Host Na&me &Hostnaam Port &Poort Authentication Re&quired &Authenticatie vereist &User Name &Gebruikersnaam Password &Wachtwoord None Geen System settings Systeeminstellingen HTTP HTTP SOCKS5 SOCKS5 QObject Left Links Right Rechts Center Gecentreerd Justify Uitgevuld All files (*) Alle bestanden (*) SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) SQLite-databasebestanden (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) DB-browser voor SQLite-projectbestanden (*.sqbpro) SQL Files (*.sql) SQL-bestanden (*.sql) All Files (*) Alle bestanden (*) Text Files (*.txt) Tekstbestanden (*.txt) Comma-Separated Values Files (*.csv) Kommagescheiden bestanden (*.csv) Tab-Separated Values Files (*.tsv) Tabgescheiden bestanden (*.tsv) Delimiter-Separated Values Files (*.dsv) Scheidingstekengescheiden bestanden (*.dsv) Concordance DAT files (*.dat) Concordance-DAT-bestanden (*.dat) JSON Files (*.json *.js) JSON-bestanden (*.json *.js) XML Files (*.xml) XML-bestanden (*.xml) Binary Files (*.bin *.dat) Binaire bestanden (*.bin *.dat) SVG Files (*.svg) SVG-bestanden (*.svg) Hex Dump Files (*.dat *.bin) Hexdump-bestand (*.dat *.bin) Extensions (*.so *.dylib *.dll) Extensies (*.so *.dylib *.dll) Initialization File (*.ini) Initialisatiebestand (*.ini) Error importing data Fout bij het importeren van de gegevens from record number %1 van recordnummer %1 . %1 . %1 Importing CSV file... CSV-bestand importeren... Cancel Annuleren SQLite database files (*.db *.sqlite *.sqlite3 *.db3) SQLite-databasebestanden (*.db *.sqlite *.sqlite3 *.db3) QsciCommand Paste Plakken Cancel Annuleren QsciLexerCPP Default Standaard Keyword Sleutelwoord Identifier Entiteitsnaam QsciLexerJSON Default Standaard String Tekenreeks QsciLexerJavaScript Regular expression Als reguliere expressie QsciLexerPython Default Standaard Comment Commentaar Keyword Sleutelwoord Identifier Entiteitsnaam QsciLexerSQL Default Standaard Comment Commentaar Keyword Sleutelwoord Identifier Entiteitsnaam QsciScintilla Select All Alles selecteren RemoteCommitsModel Commit ID Commit ID Message Bericht Date Datum Author Auteur Size Grootte Authored and committed by %1 Geautoriseerd en gecommitteerd door %1 Authored by %1, committed by %2 Geautoriseerd door %1, gecommitteerd door %2 RemoteDatabase Error opening local databases list. %1 Fout bij het openen van lijst met lokale databases. %1 Error creating local databases list. %1 Fout bij het maken van lijst met lokale databases. %1 RemoteDock Remote Toegang op afstand Identity Identiteit Push currently opened database to server Push huidig geopende database naar server Upload Uploaden DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>In dit paneel kun je externe databases van de dbhub.io website toevoegen aan DB-browser voor SQLite. Allereerst heb je een identiteit nodig:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Log in op de dbhub.io website (gebruik bijvoorbeeld jouw GitHub account of wat je maar wilt)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Klik de knop &quot;Generate client certificate&quot; (dat is jouw identiteit). Daarmee krijg je een certificaatbestand (sla deze op, op jouw lokale schijf).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ga vervolgens naar het tabblad 'Toegang op afstand', in het instellingenvenster van DB-browser voor SQLite. Klik op de knop om een nieuw certificaat toe te voegen aan DB-browser for SQLite en kies dan het zojuist gedownloade certificaatbestand.</li></ol><p>Nu toont het paneel 'Toegang op afstand' jouw identiteit en kun je externe databases toevoegen.</p></body></html> Local Lokaal Current Database Huidige database Clone Klonen &User &Database &Database Branch Tak Commits Commits Commits for Commits voor <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>Je gebruikt momenteel een ingebouwde, alleen-lezenindentiteit. Om jouw database te uploaden dien je jouw DBHub.io-account in te stellen en te gebruiken.</p><p>Nog geen DBHub.io account? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Maak er nu een aan</span></a> en importeer jouw certificaat <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">hier</span></a> om jouw databases te delen.</p><p>Bezoek <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">deze link</span></a> voor online hulp.</p></body></html> Back Terug Delete Database Database verwijderen Delete the local clone of this database De lokale kloon van deze database verwijderen Open in Web Browser In webbrowser openen Open the web page for the current database in your browser De webpagina van de huidige database openen in je browser Clone from Link Van link klonen Use this to download a remote database for local editing using a URL as provided on the web page of the database. Hiermee download je een externe database om lokaal te bewerken aan de hand van de URL die verstrekt werd op de webpagina van de database. Refresh Verversen Reload all data and update the views Alle gegevens herladen en de views updaten Clone Database Database klonen Open Database Database openen Open the local copy of this database Lokale kopie van deze database openen Check out Commit Commit inladen Download and open this specific commit Deze specifieke downloaden en openen Check out Latest Commit Laatste commit inladen Check out the latest commit of the current branch De laatste commit van de huidige tak inladen Save Revision to File Revisie opslaan in bestand Saves the selected revision of the database to another file Slaat de geselecteerde revisie van de database op in een ander bestand Upload Database Database uploaden Upload this database as a new commit Deze database uploaden als een nieuwe commit Select an identity to connect Selecteer een identiteit om te verbinden Public Openbaar This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Dit downloadt een database van een externe server om lokaal te bewerken. Voer een URL in van waaruit gekloond moet worden. Je kunt deze URL genereren door te klikken op de 'Clone Database in DB4S'-knop op de webpagina van de database. Invalid URL: The host name does not match the host name of the current identity. Ongeldige URL: De hostnaam komt niet overeen met de hostnaam van de huidige identiteit. Invalid URL: No branch name specified. Ongeldige URL: Geen taknaam opgegeven. Invalid URL: No commit ID specified. Ongeldige URL: Geen commit-ID opgegeven. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? Je hebt de lokale kloon van de database aangepast. Als je deze commit inlaadt overschrijft dit lokale wijzigingen. Weet je zeker dat je door wilt gaan? The database has unsaved changes. Are you sure you want to push it before saving? De database heeft niet-opgeslagen wijzigingen. Weet je zeker dat je wilt pushen voordat je opslaat? The database you are trying to delete is currently opened. Please close it before deleting. De database die je probeert te verwijderen is op het ogenblik geopend. Sluit deze voordat je deze verwijdert. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? Dit verwijdert de lokale database met alle wijzigingen die je nog niet gecommitteerd hebt. Weet je zeker dat je deze database wilt verwijderen? RemoteLocalFilesModel Name Naam Branch Tak Last modified Laatst gewijzigd Size Grootte Commit Commit File Bestand RemoteModel Name Naam Last modified Laatst gewijzigd Size Grootte Commit Commit Size: Grootte: Last Modified: Laatst gewijzigd: Licence: Licentie: Default Branch: Standaardtak: RemoteNetwork Choose a location to save the file Kies een locatie om het bestand in op te slaan Error opening remote file at %1. %2 Fout bij het openen van extern bestand %1. %2 Error: Invalid client certificate specified. Fout: ongeldig certificaatbestand opgegeven. Please enter the passphrase for this client certificate in order to authenticate. Geef de toegangsfrase voor dit client-certificaat op om te authenticeren. Cancel Annuleren Uploading remote database to %1 Externe database wordt geüploadt naar %1 Downloading remote database from %1 Externe database wordt gedownload vanaf %1 Error: Cannot open the file for sending. Fout: kan het te verzenden bestand niet openen. RemotePushDialog Push database Database pushen Database na&me to push to Database&naam om naar te pushen Commit message Commitbericht Database licence Databaselicentie Public Openbaar Branch Tak Force push Push forceren Username Gebruikersnaam Database will be public. Everyone has read access to it. Database wordt openbaar. Iedereen zal leestoegang hebben. Database will be private. Only you have access to it. Database wordt privé. Alleen jij zal leestoegang hebben. Use with care. This can cause remote commits to be deleted. Wees hier voorzichtig mee; dit kan ervoor zorgen dat externe commits verwijderd worden. RunSql Execution aborted by user Uitvoering afgebroken door gebruiker , %1 rows affected , %1 records getroffen query executed successfully. Took %1ms%2 Opdracht succesvol uitgevoerd. Duurde %1ms%2 executing query opdracht wordt uitgevoerd SelectItemsPopup A&vailable Beschi&kbaar Sele&cted Gese&lecteerd SqlExecutionArea Form Formulier Find previous match [Shift+F3] Vorige overeenkomst zoeken [Shift+F3] Find previous match with wrapping Vorige overeenkomst zoeken met terugloop Shift+F3 The found pattern must be a whole word Het gevonden patroon moet een heel woord zijn Whole Words Hele woorden Text pattern to find considering the checks in this frame Zoekterm die gezocht moet worden met de geselecteerde opties in dit kader Find in editor Zoek in bewerker The found pattern must match in letter case De gevonden overeenkomst moet identiek zijn in onder- en bovenkast Case Sensitive Identieke onder-/bovenkast Find next match [Enter, F3] Volgende overeenkomst zoeken [Enter, F3] Find next match with wrapping Volgende overeenkomst zoeken met terugloop F3 Interpret search pattern as a regular expression Interpreteer zoekterm als reguliere expressie <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Indien geselecteerd wordt de zoekterm geïnterpreteerd als een UNIX reguliere expressie. Zie hiervoor <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Reguliere Expressies in Wikibooks (Engels)</a>.</p></body></html> Regular Expression Reguliere expressie Close Find Bar Zoekbalk sluiten <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>Resultaten van de laatst uitgevoerde opdrachten.</p><p>Je kunt dit paneel ook inklappen en in plaats daarvan het <span style=" font-style:italic;">SQL-log</span>dock gebruiken met <span style=" font-style:italic;">Gebruiker</span> geselecteerd.</p></body></html> This field shows the results and status codes of the last executed statements. Dit veld toont de resultaten en statuscodes van de laatst uitgevoerde opdrachten. Results of the last executed statements Resultaten van de laatst uitgevoerde opdrachten Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Couldn't save file: %1. Kon het bestand niet opslaan: %1. Your changes will be lost when reloading it! Jouw wijzigingen zullen verloren gaan als je het opnieuw laadt! The file "%1" was modified by another program. Do you want to reload it?%2 Het bestand '%1' is aangepast door een ander programma. Wil je het herladen?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) De abs(X) functie retourneert de absolute waarde van het numerieke argument X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () De changes() functie retourneert het aantal databaserecords dat gewijzigd, ingevoegd of verwijderd is door de meest recent voltooide INSERT-, DELETE- of UPDATE-instructie. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) De char(X1,X2,...,XN) functie retourneert een tekenreeks bestaande uit tekens met de respectievelijke unicode-codepuntwaarden van de gehele getallen X1 tot en met XN. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) De coalesce(X,Y,...) functie retourneert een kopie van het eerste niet-NULL argument, of NULL als alle argument NULL zijn (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) De glob(X,Y) functie is het equivalent van de expressie "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) De ifnull(X,Y) functie retourneert een kopie van het eerste niet-NULL argument, of NULL als beide argumenten NULL zijn. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) De instr(X,Y) functie zoekt het eerste voorkomen van tekenreeks Y in tekenreeks X en retourneert het aantal voorgaande tekens plus 1, of 0 als Y niet voorkomt in X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) De hex(X) functie interpreteert het argument als een BLOB en retourneert de hexadecimale voorstelling van de BLOB-inhoud als tekenreeks in bovenkast. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) De iif(X,Y,Z) functie retourneert de waarde Y als X waar is, en anders Z. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () De last_insert_rowid() functie retourneert het ROWID van het laatste record dat door de databaseverbinding die de functie aanriep is ingevoegd. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) Voor een tekenreeks X, retourneert de length(X) functie het aantal tekens (en niet bytes) in X voor het eerste NUL-teken. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) De like(X,Y) functie wordt gebruikt als implementatie voor de expressie "Y LIKE X". (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) De like(X,Y,Z) functie wordt gebruikt als implementatie voor de expressie "Y LIKE X ESCAPE Z". (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) De load_extension(X) functie laadt SQLite extensies uit een gedeeld biblitheekbestand genaamd X. Voor het gebruik van deze functie is autorisatie vanuit Instellingen nodig. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) De load_extension(X,Y) functie laadt SQLite extensies uit een gedeeld biblitheekbestand genaamd X gebruikmakend van toegangspunt Y. Voor het gebruik van deze functie is autorisatie vanuit Instellingen nodig. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) De lower(X) functie retourneert een kopie van de tekenreeks X waarbij alle ASCII-tekens omgezet worden naar onderkast. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) verwijdert alle spaties aan de linkerkant van X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) De ltrim(X,Y) functie retourneert een tekenreeks die gevormd wordt door alle tekens die in Y voorkomen te verwijderen van de linkerkant van X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) De max(X,Y,...) functie accepteert een variabel aantal argumenten en retourneert het argument met de hoogste waarde, of NULL als enig argument NULL is. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) De min(X,Y,...) functie accepteert een variabel aantal argumenten en retourneert het argument met de laagste waarde. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) De nullif(X,Y) functie retourneert het eerste argument als de argumenten verschillend zijn en NULL als de argumenten hetzelfde zijn. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) De printf(FORMAT,...) SQL functie werkt zoals de sqlite3_mprintf() functie in de C-taal en de printf() functie uit de standaard C-bibliotheek. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) De quote(X) functie retourneert de tekst van een SQL literaal met de waarde van het argument, geschikt om in te sluiten in een SQL-instructie. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () De random() functie retourneert een pseudowillekeurig geheel getal tussen -9223372036854775808 en +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) De randomblob(N) functie retourneert een N-byte blob met pseudowillekeurige bytes. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) De replace(X,Y,Z) functie retourneert een tekenreeks samengesteld door alle voorvallen van tekenreeks Y in tekenreeks X te vervangen door tekenreeks Z. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) De round(X) functie retourneert het zwevendekommagetal X afgerond naar nul cijfers achter de komma. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) De round(X,Y) functie retourneert het zwevendekommagetal X afgerond naar Y cijfers achter de komma. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) verwijdert alle spaties aan de rechterkant van X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) De rtrim(X,Y) functie retourneert een tekenreeks die gevormd wordt door alle tekens die in Y voorkomen te verwijderen van de rechterkant van X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) De soundex(X) functie retourneert de soundex-codering van tekenreeks X als tekenreeks. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) retourneert alle tekens van de tekenreeks X, van het Y-ste teken tot en met het laatste. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) De substr(X,Y,Z) functie retourneert het deel van de tekenreeks X, vanaf het Y-ste teken, en met lengte Z. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () De total_changes() functie retourneert het aantal databaserecords dat gewijzigd is door INSERT-, DELETE- of UPDATE-instructies sinds de databaseconnectie geopend werd. (X) trim(X) removes spaces from both ends of X. (X) trim(X) verwijdert alle spaties aan beide kanten van X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) De trim(X,Y) functie retourneert een tekenreeks die gevormd wordt door alle tekens die in Y voorkomen te verwijderen van beide kanten van X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) De typeof(X) functie retourneert een tekenreeks die aangeeft wat het gegevenstype van expressie X is. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) De unicode(X) functie retourneert het numerieke unicode-codepunt van het eerste teken in de tekenreeks X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) De upper(X) functie retourneert een kopie van de tekenreeks X waarbij alle onderkast ASCII-tekens omgezet worden naar hun bovenkast equivalent. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) De zeroblob(N) functie retourneert een blob met N 0x00 bytes. (timestring,modifier,modifier,...) (tijdtekenreeks,modificator,modificator,...) (format,timestring,modifier,modifier,...) (formaat,tijdtekenreeks,modificator,modificator,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) De avg() functie retourneert de gemiddelde waarde van alle niet-NULL X in een groep. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) De count(X) functie retourneert het aantal maal dat X niet NULL is in een groep. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) De group_concat(X) functie retourneert een tekenreeks die de aaneenschakeling is van alle niet-NULL waarden van X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) De group_concat(X,Y) functie retourneert een tekenreeks die de aaneenschakeling is van alle niet-NULL waarden van X, met Y als scheidingsteken(-reeks). (X) The max() aggregate function returns the maximum value of all values in the group. (X) De max(X) aggregaatfunctie retourneert de hoogste waarde van alle waarden in de groep. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) De min(X) aggregaatfunctie retourneert de laagste niet-NULL waarde van alle waarden in de groep. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) De sum(X) en total(X) aggregaatfuncties retourneren de opsomming van alle niet-NULL waarden in de groep. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () Het nummer van de rij binnen de huidige partitie. Rijen worden genummerd vanaf 1 in de volgorde zoals gedefinieerd door de ORDER BY clausule in de vensterdefinitie, of anders in arbitraire volgorde. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Het row_number() van de eerste peer in elke groep - de rang van de huidige rij met hiaten. Als er geen ORDER BY clausule is, dan worden alle rijen als peer beschouwd en retourneert deze functie altijd 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Het nummer van de peergroep van de huidige rij, binnen diens partitie - de rang van de huidige rij zonder hiaten. Partities worden genummerd vanaf 1 in de volgorde zoals gedefinieerd door de ORDER BY clausule in de vensterdefinitie. Als er geen ORDER BY clausule is, dan worden alle rijen als peer beschouwd en retourneert deze functie altijd 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () Ondanks de naam retourneert deze functie altijd een waarde tussen 0,0 en 1,0 gelijk aan (rang - 1)/(partitierijen - 1), waarbij rang de waarde is die geretourneerd wordt door de ingebouwde vensterfunctie rank() en partitierijen het totaal aantal rijen in de partitie is. Wanneer de partitie maar een rij bevat dan retourneert deze functie 0,0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () De cumulatieve distributie. Berekend als rijnummer/partitierijen, waarbij rijnummer de waarde is die geretourneerd wordt door row_number() voor de laatste peer in de groep en partitierijen het aantal rijen in de partitie is. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) Argument N wordt behandeld als geheel getal. Deze functie deelt de partitie zo evenredig als mogelijk op in N groepen en kent aan elke groep een getal tussen 1 en N toe , in de volgorde zoals gedefinieerd door de ORDER BY clausule, indien aanwezig, en anders in arbitraire volgorde.. Indien nodig komen grote groepen eerst. Deze functie retourneert het gehele getal dat toegekend is aan de groep waar de huidige rij deel van uit maakt. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Evalueert de expressie expr tegen de vorige rij in de partitie en retourneert het resultaat. Of NULL, indien er geen vorige rij bestaat (omdat de huidige rij de eerste is). (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,verschuiving) Indien het argument verschuiving wordt meegegeven dan dient deze een niet-negatief geheel getal te zijn. In dat geval wordt de expressie expr tegen de rij met afstand verschuiving voor de huidige rij in de partitie geëvalueerd en het resultaat retourneerd. Als verschuiving 0 is dan wordt tegen de huidige rij geëvalueerd. Indien er geen rij met afstand verschuiving voor de huidige rij bestaat, wordt NULL geretourneerd. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,verschuiving,standaardwaarde) Retourneert standaardwaarde als deze meegegeven is of anders NULL wanneer de rij volgens de verschuiving niet bestaat. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Evalueert de expressie expr tegen de volgende rij in de partitie en retourneert het resultaat. Of NULL, indien er geen volgende rij bestaat (omdat de huidige rij de laatste is). (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,verschuiving) Indien het argument verschuiving wordt meegegeven dan dient deze een niet-negatief geheel getal te zijn. In dat geval wordt de expressie expr tegen de rij met afstand verschuiving na de huidige rij in de partitie geëvalueerd en het resultaat retourneerd. Als verschuiving 0 is dan wordt tegen de huidige rij geëvalueerd. Indien er geen rij met afstand verschuiving na de huidige rij bestaat, wordt NULL geretourneerd. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Deze ingebouwde vensterfunctie berekent het vensterkader voor elke rij, op dezelfde manier als een geaggregeerde vensterfunctie. Evalueert voor elke rij de expressie expr tegen de eerste rij in het vensterkader en retourneert de waarde. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Deze ingebouwde vensterfunctie berekent het vensterkader voor elke rij, op dezelfde manier als een geaggregeerde vensterfunctie. Evalueert voor elke rij de expressie expr tegen de laatste rij in het vensterkader en retourneert de waarde. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) Deze ingebouwde vensterfunctie berekent het vensterkader voor elke rij, op dezelfde manier als een geaggregeerde vensterfunctie. Evalueert de expressie expr tegen rij N van het vensterkader en retourneert de waarde. Rijen worden binnen het vensterkader genummerd vanaf 1 in de volgorde zoals gedefinieerd door de ORDER BY clausule,indien aanwezig, en anders in arbitraire volgorde. Als rij N niet bestaat in de partitie dan wordt NULL geretourneerd. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. SqliteTableModel reading rows records lezen loading... aan het laden... References %1(%2) Hold %3Shift and click to jump there Verwijst naar %1(%2) Houdt %3Shift ingedrukt terwijl je klikt om er naartoe te springen Error changing data: %1 Fout bij het aanpassen van gegevens: %1 retrieving list of columns lijst met kolommen aan het ophalen Fetching data... Gegevens aan het ophalen... Cancel Annuleren TableBrowser Browse Data Gegevensbrowser &Table: &Tabel: Select a table to browse data Selecteer een tabel om door gegevens te bladeren Use this list to select a table to be displayed in the database view Gebruik deze lijst om een tabel te selecteren die getoond zal worden in de gegevensbrowser This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Dit is het databasetabeloverzicht: Je kunt hier de volgende handelingen uitvoeren: - Beginnen met typen om waarden in de regel te bewerken. - Dubbelklikken op een willekeurig record om diens inhoud te bewerken in het celbewerkingsvenster. - Alt-Del om de celinhoud om te zetten naar NULL. - Ctrl+" om het huidige record te dupliceren. - Ctrl+' om de celwaarde boven te kopiëren. - Gebruikelijke kopiëren/plakken handelingen. Text pattern to find considering the checks in this frame Zoekterm die gezocht moet worden met de geselecteerde opties in dit kader Find in table Zoek in tabel Find previous match [Shift+F3] Vorige overeenkomst zoeken [Shift+F3] Find previous match with wrapping Vorige overeenkomst zoeken met terugloop Shift+F3 Find next match [Enter, F3] Volgende overeenkomst zoeken [Enter, F3] Find next match with wrapping Volgende overeenkomst zoeken met terugloop F3 The found pattern must match in letter case De gevonden overeenkomst moet identiek zijn in onder-/bovenkast Case Sensitive Identieke onder-/bovenkast The found pattern must be a whole word Het gevonden patroon moet een heel woord zijn Whole Cell Gehele cel Interpret search pattern as a regular expression Interpreteer zoekterm als reguliere expressie <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Indien geselecteerd wordt de zoekterm geïnterpreteerd als een UNIX reguliere expressie. Zie hiervoor <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Reguliere Expressies in Wikibooks (Engels)</a>.</p></body></html> Regular Expression Reguliere expressie Close Find Bar Zoekbalk sluiten Text to replace with Tekst om mee te vervangen Replace with Vervangen met Replace next match Vervang volgende overeenkomst Replace Vervangen Replace all matches Alle overeenkomsten vervangen Replace all Alles vervangen Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Copy column name Copy the database table column name to your clipboard New Data Browser Nieuwe gegevensbrowser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Blader naar het begin</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Klikken op deze knop brengt je naar het begin van het hierboven getoonde tabeloverzicht.</p></body></html> |< |< Scroll one page upwards Blader één pagina omhoog <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Klikken op deze knop bladert één pagina omhoog in het hierboven getoonde tabeloverzicht.</p></body></html> < < 0 - 0 of 0 0 - 0 van 0 Scroll one page downwards Blader één pagina omlaag <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Klikken op deze knop bladert één pagina omlaag in het hierboven getoonde tabeloverzicht.</p></body></html> > > Scroll to the end Blader naar het einde <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>Klikken op deze knop brengt je naar het einde van het hierboven getoonde tabeloverzicht.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>Klik op deze knop om naar een specifiek record te springen</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Deze knop wordt gebruikt om naar het specifieke record van het Ga-naar-veld te springen.</p></body></html> Go to: Ga naar: Enter record number to browse Voer een recordnummer in om te browsen Type a record number in this area and click the Go to: button to display the record in the database view Voer een specifiek recordnummer in dit veld in en klik op de Ga naar-knop, om het record in het tabeloverzicht te tonen 1 1 Show rowid column De rowid-kolom tonen Toggle the visibility of the rowid column De zichtbaarheid van de rowid-kolom omschakelen Unlock view editing Viewbewerking ontgrendelen This unlocks the current view for editing. However, you will need appropriate triggers for editing. Dit ontgrendelt de huidige view om deze te bewerken. Je hebt echter de juiste triggers nodig om te kunnen bewerken. Edit display format Opmaak bewerken Edit the display format of the data in this column De opmaak van de gegevens in deze kolom bewerken New Record Nieuw record Insert a new record in the current table Een nieuw record in de huidige tabel invoegen <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Deze knop maakt een nieuw record aan in de database. Houd de muis ingedrukt om een pop-upmenu met opties te openen:</p><ul><li><span style=" font-weight:600;">Nieuw record</span>: een nieuw record met standaardwaarden invoegen.</li><li><span style=" font-weight:600;">Waarden invoeren...</span>: opent een dialoogvenster om waarden in te voeren voordat ze in de database worden ingevoegd. Hiermee kun je waarden invoeren die aan de beperkingen voldoen. Dit dialoogvenster wordt tevens geopend als <span style=" font-weight:600;">Nieuw record</span> mislukte door deze beperkingen.</li></ul></body></html> Delete Record Record verwijderen Delete the current record Het huidige record verwijderen This button deletes the record or records currently selected in the table Deze knop verwijdert huidig in de tabel geselecteerde records Insert new record using default values in browsed table Nieuw record invoegen met de standaardwaarden die gelden voor de getoonde tabel Insert Values... Waarden invoeren... Open a dialog for inserting values in a new record Open een dialoogvenster om waarden voor een nieuw record in te voeren Export to &CSV Exporteren als &CSV Export the filtered data to CSV De gefilterde gegevens exporteren naar CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Deze knop exporteert de gegevens van de tabel zoals deze nu getoond worden (door filters, opmaak en kolomsorteringen) naar een CSV-bestand. Save as &view Opslaan als &view Save the current filter, sort column and display formats as a view De huidige filters, kolomsorteringen en opmaak opslaan als view This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Deze knop slaat de gegevens van de tabel zoals deze nu getoond worden (door filters, opmaak en kolomsorteringen) op als SQL-view zodat je er later doorheen kunt bladeren of deze in SQL-instructies kunt gebruiken. Save Table As... Tabel opslaan als... Save the table as currently displayed Tabel opslaan zoals deze op het ogenblik wordt getoond <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>Dit pop-upmenu biedt de volgende opties om toe te passen op de huidig getoonde en gefilterde tabel:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exporteren naar CSV: Deze optie exporteert de gegevens van de tabel zoals deze nu getoond worden (door filters, opmaak en kolomsorteringen) naar een CSV-bestand.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Opslaan als view: Deze optie slaat de gegevens van de tabel zoals deze nu getoond worden (door filters, opmaak en kolomsorteringen) op als SQL-view zodat je er later doorheen kunt bladeren of deze in SQL-instructies kunt gebruiken.</li></ul></body></html> Hide column(s) Kolom(-men) verbergen Hide selected column(s) Geselecteerde kolom(-men) verbergen Show all columns Alle kolommen tonen Show all columns that were hidden Alle kolommen tonen die verborgen waren Set encoding Encodering aanpassen Change the encoding of the text in the table cells Encodering van de tekst in de tabelcellen aanpassen Set encoding for all tables Encodering van alle tabellen aanpassen Change the default encoding assumed for all tables in the database De standaard veronderstelde encodering voor alle tabellen aanpassen Clear Filters Filters wissen Clear all filters Alle filters wissen This button clears all the filters set in the header input fields for the currently browsed table. Deze knop wist alle filters onder de kolomkoppen voor de huidig getoonde tabel. Clear Sorting Sortering opheffen Reset the order of rows to the default Herstelt de sortering van de records naar de standaardsortering This button clears the sorting columns specified for the currently browsed table and returns to the default order. Deze knop heft alle sorteringen voor de huidig getoonde tabel op en zet deze terug naar de standaardsortering. Print Afdrukken Print currently browsed table data De huidig getoonde tabelgegevens afdrukken Print currently browsed table data. Print selection if more than one cell is selected. De huidig getoonde tabelgegevens afdrukken. Drukt selectie af als meer dan één cel geselecteerd is. Ctrl+P Refresh Verversen Refresh the data in the selected table Ververs de gegevens van de huidig geselecteerde tabel This button refreshes the data in the currently selected table. Deze knop ververst de gegevens van de huidig geselecteerde tabel. F5 Find in cells In cellen zoeken Open the find tool bar which allows you to search for values in the table view below. Open de zoekwerkbalk die je in staat stelt waarden te zoeken in het hieronder getoonde overzicht. Bold Vet Ctrl+B Italic Cursief Underline Onderstreept Ctrl+U Align Right Rechts uitlijnen Align Left Links uitlijnen Center Horizontally Horizontaal centreren Justify Uitvullen Edit Conditional Formats... Voorwaardelijke opmaakregels bewerken... Edit conditional formats for the current column Voorwaardelijke opmaakregels voor de huidige kolom bewerken Clear Format Opmaak wissen Clear All Formats Alle opmaak wissen Clear all cell formatting from selected cells and all conditional formats from selected columns Wis alle celopmaak van geselecteerde cellen en wis alle voorwaardelijke opmaak van geselecteerde kolommen Font Color Tekstkleur Background Color Achtergrondkleur Toggle Format Toolbar Toon/verberg opmaakwerkbalk Show/hide format toolbar Toont of verbergt de opmaakwerkbalk This button shows or hides the formatting toolbar of the Data Browser Deze knop toont of verbergt de opmaakwerkbalk van de Gegevensbrowser Select column Kolom selecteren Ctrl+Space Replace text in cells Tekst in cellen vervangen Freeze columns Kolommen bevriezen Make all columns from the first column up to this column not move when scrolling horizontally Pin alle kolommen vanaf de eerste tot deze vast, zodat deze niet bewegen tijdens het horizontaal scrollen Filter in any column Willekeurige kolom filteren Ctrl+R %n row(s) %n record %n records , %n column(s) , %n kolom , %n kolommen . Sum: %1; Average: %2; Min: %3; Max: %4 . Som: %1; Gemiddelde: %2; Min.: %3; Max.: %4 Conditional formats for "%1" Voorwaardelijke opmaakregels voor "%1" determining row count... aantal records bepalen... %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Voer een pseudo-primaire sleutel in om het bewerken van deze view in te schakelen. Dit dient de naam van een unieke-waardenkolom in de view te zijn. Delete Records Records verwijderen Duplicate records Records dupliceren Duplicate record Record dupliceren Ctrl+" Adjust rows to contents Rijen aanpassen aan inhoud Error deleting record: %1 Fout bij het verwijderen van record: %1 Please select a record first Selecteer eerst een record Please choose a new encoding for all tables. Kies een nieuwe codering voor alle tabellen. Please choose a new encoding for this table. Kies een nieuwe codering voor deze tabel. %1 Leave the field empty for using the database encoding. %1 Laat het veld leeg om de databasecodering te gebruiken. This encoding is either not valid or not supported. De codering is niet geldig of wordt niet ondersteund. %1 replacement(s) made. %1 vervangin(-en) gedaan. TableBrowserDock New Data Browser Nieuwe gegevensbrowser Rename Data Browser Gegevensbrowser hernoemen Close Data Browser Gegevensbrowser sluiten Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. Geef een nieuwe naam voor de gegevensbrowser. Gebruik het '&&'-teken om de een van de volgende tekens als sneltoets in te stellen. VacuumDialog Compact Database Database comprimeren Warning: Compacting the database will commit all of your changes. Waarschuwing: wanneer je de database comprimeert zullen al jouw gemaakte wijzigingen gecommitteerd worden. Please select the databases to co&mpact: Selecteer de databases om te co&mprimeren: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_pl.ts000066400000000000000000013650651463772530400252300ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite O PrzeglÄ…darce SQLite Version Wersja <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Nowy rekord Enter values for the new record considering constraints. Fields in bold are mandatory. Podaj wartoÅ›ci dla nowego rekordu zwracajÄ…c uwagÄ™ na ograniczenia.Pola wytÅ‚usczone sÄ… obowiÄ…zkowe. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. W kolumnie Wartość możesz podać wartość dla pola identyfikowanego w kolumnie Nazwa. Kolumna Rodzaj wskazuje rodzaj pola. WartoÅ›ci domyÅ›lne sÄ… wyÅ›wietlane w tym samym stylu, co wartoÅ›ci NULL. Name Nazwa Type Rodzaj Value Wartość Values to insert. Pre-filled default values are inserted automatically unless they are changed. WartoÅ›ci do wstawienia. Uprzednio wypeÅ‚nione domyÅ›lne wartoÅ›ci sÄ… wstawiane samoczynnie, chyba że zostaÅ‚y zmienione. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Tutaj pokazana jest kwerenda SQL dla dodania nowego rekordu zawierajÄ…cego wartoÅ›ci wprowadzone w górnej ramce. Możesz jÄ… rÄ™cznie zmienić przed zapisem rekordu. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Zapisz</span> przekaże wyÅ›wietlone zapytanie SQL do bazy danych w celu zapisania nowego rekordu</p><p><span style=" font-weight:600;">Przywróć domyÅ›lne</span> przywróci wstÄ™pne wartoÅ›ci domyÅ›lne w kolumnie<span style=" font-weight:600;">Wartość</span></p><p><span style=" font-weight:600;">Zaniechaj</span> zamyka to okno bez robienia zmian.</p></body></html> Auto-increment Samoprzyrost Unique constraint Ograniczenie niepowtarzalnoÅ›ci Check constraint: %1 Ograniczenie sprawdzania: %1 Foreign key: %1 Klucz obcy: %1 Default value: %1 Wartość domyÅ›lna: %1 Error adding record. Message from database engine: %1 Nie można dodać rekordu. Wiadomość z silnika bazy danych: %1 Are you sure you want to restore all the entered values to their defaults? JesteÅ› pewien że chcesz przywrócić domyÅ›lne wartoÅ›ci dla wszystich wpisów? Application Possible command line arguments: Dozwolone argumenty wiersza poleceÅ„: The user settings file location is replaced with the argument value instead of the environment variable value. PoÅ‚ożenie pliku ustawieÅ„ użytkownika jest zastÄ™powane wartoÅ›ciÄ… argumentu zamiast wartoÅ›ciÄ… zmiennej Å›rodowiskowej. Ignored environment variable (DB4S_SETTINGS_FILE) value: Pomijana wartość zmiennej Å›rodowiskowej (DB4S_SETTINGS_FILE): The file %1 does not exist Plik %1 nie istnieje Usage Użycie options ustawienia database baza danych project projekt csv-file plik csv Show command line options Pokaż ustawienia wiersza poleceÅ„ Exit application after running scripts Wyjdź z aplikacji po wykonaniu skryptów file plik Execute this SQL file after opening the DB Wykonaj to polecenie SQL po otwarciu bazy danych Import this CSV file into the passed DB or into a new DB Zaimportuj ten plik CSV do podanej bazy danych lub do nowej bazy danych table tabela Browse this table, or use it as target of a data import PrzeglÄ…daj tÄ™ tabelÄ™ lub użyj jej jako miejsca docelowego importowania Open database in read-only mode Otwórz bazÄ™ danych w trybie tylko do odczytu settings_file plik_ustawieÅ„ Run application based on this settings file Uruchom tÄ™ aplikacjÄ™ na podstawie tego pliku ustawieÅ„ group grupa settings ustawienia value wartość Run application with this setting temporarily set to value Uruchom tÄ™ aplikacjÄ™ z wartoÅ›ciÄ… tego ustawienia tymczasowo na Run application saving this value for this setting Uruchom tÄ™ aplikacjÄ™ zapisujÄ…c, tÄ™ wartość w jej ustawieniach Display the current version WyÅ›wietl bieżącÄ… wersjÄ™ Open this SQLite database Otwórz tÄ™ bazÄ™ danych SQLite Open this project file (*.sqbpro) Otwórz ten plik projektu (*.sqbpro) Import this CSV file into an in-memory database Zaimportuj ten plik CSV do bazy danych w pamiÄ™ci The %1 option requires an argument SÅ‚owo kluczowe %1 wymaga argumentu The -S/--settings option requires an argument. The option is ignored. Ustawienie -S/-- wymaga argumentu. PominiÄ™to ustawienie. The -o/--option and -O/--save-option options require an argument in the form group/setting=value Ustawienia -o/--option oraz -O/--save-option wymagajÄ… argumentu w postaci group/setting=wartość Invalid option/non-existent file: %1 NieprawidÅ‚owa opcja lub nieistniejÄ…cy plik: %1 SQLite Version Wersja SQLite SQLCipher Version %1 (based on SQLite %2) Wersja SQLCipher %1 (oparta na SQLite %2) DB Browser for SQLite Version %1. PrzeglÄ…darka BD dla SQLite w wersji %1. Last commit hash when built: %1 Skrót zmiany, na której zbudowano: %1 Built for %1, running on %2 Zbudowane dla %1, uruchomione na %2 Qt Version %1 Wersja Qt %1 CipherDialog SQLCipher encryption Szyfrowanie SQLCipher &Password &HasÅ‚o &Reenter password Powtó&rz hasÅ‚o Encr&yption settings Ustawienia sz&yfrowania SQLCipher &3 defaults DomyÅ›lne SQLCipher &3 SQLCipher &4 defaults DomyÅ›lne SQLCipher &4 Custo&m WÅ‚as&ny Page si&ze Ro&zmiar strony &KDF iterations Powtórzenia &KDF HMAC algorithm Algorytm HMAC KDF algorithm Algorytm KDF Plaintext Header Size Rozmiar nagłówka zwykÅ‚ego tekstu Passphrase HasÅ‚o Raw key Klucz Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Ustaw klucz do zaszyfrowania bazy danych. Zwróć uwagÄ™ na to, że wszelkie zmiany wprowadzone tutaj do opcjonalnych ustawieÅ„ bÄ™dÄ… wymagane przy każdym otwarciu pliku. Aby pozbyć siÄ™ szyfrowania, pozostaw pola hasÅ‚a pustymi. Proces szyfrowania może zabrać dużo czasu w zależnoÅ›ci od wielkoÅ›ci bazy danych.
Zaleca siÄ™ aby przed rozpoczÄ™ciem tego procesu zrobić kopiÄ™ zapasowÄ… pliku. Wszelkie niezapisane zmiany bÄ™dÄ… wprowadzone do bazy danych zanim szyfrowanie siÄ™ rozpocznie. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. ProszÄ™ podać hasÅ‚o do zaszyfrowania bazy danych. JeÅ›li zostaÅ‚y zmienione jakiekolwiek dodatkowe ustawienia dla pliku tej bazy danych bÄ™dziesz musiaÅ‚ również podać tÄ… informacjÄ™. ColumnDisplayFormatDialog Choose display format Wybierz format wyÅ›wietlania Display format Format wyÅ›wietlania Choose a display format for the column '%1' which is applied to each value prior to showing it. Wybierz domyÅ›lny format wyÅ›wietlania dla kolumny '%1', który bÄ™dzie stosowany dla każdej wartoÅ›ci, zanim zostanie ona wyÅ›wietlona. Default DomyÅ›lny Decimal number Liczba dziesiÄ™tna Exponent notation Zapis wykÅ‚adniczy Hex blob Blob szestnastkowy Hex number Liczba szesnastkowa Octal number Liczba ósemkowa Round number Liczba zaokrÄ…glona Apple NSDate to date Apple NSDate do daty Java epoch (milliseconds) to date Java epoch (milisekundy) do daty .NET DateTime.Ticks to date .NET DateTime.Ticks na datÄ™ Julian day to date Data JuliaÅ„ska do daty Unix epoch to date Unix epoch do daty Unix epoch to local time Unix epoch do czasu lokalnego WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Windows DATE to date Windows DATE do daty Date as dd/mm/yyyy Data w formacie dd/mm/rrrr Lower case MaÅ‚e litery Upper case Duże litery Binary GUID to text Dwójkowy GUID na tekst SpatiaLite Geometry to SVG Geometria SpatiaLite do SVG Custom Niestandardowy Custom display format must contain a function call applied to %1 WÅ‚asny format wyÅ›wietlania musi zawierać wywoÅ‚anie funkcji zastosowanej na %1 Error in custom display format. Message from database engine: %1 Błąd we wÅ‚asnym formacie wyÅ›wietlania. Wiadomość z silnika bazy danych: %1 Custom display format must return only one column but it returned %1. WÅ‚asny format wyÅ›wietlania musi zwracać tylko jednÄ… kolumnÄ™, a zwróciÅ‚ %1. CondFormatManager Conditional Format Manager ZarzÄ…dzanie formatowaniem warunkowym This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. To okno dialogowe umożliwia tworzenie i zmianÄ™ formatowania warunkowego. WyglÄ…d komórki bÄ™dzie bÄ™dzie okreÅ›lony pierwszym speÅ‚nionym warunkiem dla danych komórki. Formatowania warunkowe można przesunąć w górÄ™ i w dół, gdzie te na górze sÄ… przetwarzane w pierwszej kolejnoÅ›ci. SkÅ‚adnia dla warunków jest taka sama jak dla filtrów, a pusty warunek bÄ™dzie pasowaÅ‚ do wszystkich wartoÅ›ci. Add new conditional format Dodaj nowe formatowanie warunkowe &Add Dod&aj Remove selected conditional format UsuÅ„ wybrane formatowanie warunkowe &Remove &UsuÅ„ Move selected conditional format up PrzesuÅ„ w górÄ™ wybrane formatowanie warunkowe Move &up PrzesuÅ„ w &górÄ™ Move selected conditional format down PrzesuÅ„ w dół wybrane formatowanie warunkowe Move &down PrzesuÅ„ w &dół Foreground Pierwszy plan Text color Barwa tekstu Background TÅ‚o Background color Barwa tÅ‚a Font Czcionka Size Rozmiar Bold Pogrubienie Italic Kursywa Underline PodkreÅ›lenie Alignment Wyrównanie Condition Warunek Click to select color Kliknij, aby wybrać barwÄ™ Are you sure you want to clear all the conditional formats of this field? Czy na pewno chcesz wyczyÅ›cić wszystkie formatowania warunkowe tego pola? DBBrowserDB Please specify the database name under which you want to access the attached database ProszÄ™ podaj nazwÄ™ bazy danych za pomocÄ… której chcesz uzyskać dostÄ™p do załączonej bazy Invalid file format NieprawidÅ‚owy format pliku Do you really want to close this temporary database? All data will be lost. Czy na pewno chcesz zamknąć tÄ™ tymczasowÄ… bazÄ™ danych? Wszelkie zmiany bedÄ… zapomniane. Do you want to save the changes made to the database file %1? Czy na pewno chcesz zapisać zmiany dokonane w pliku bazy danych %1? Database didn't close correctly, probably still busy Baza danych nie zostaÅ‚a zamkniÄ™ta poprawnie, prawdopodobnie byÅ‚a nadal zajÄ™ta Cannot open destination file: '%1' Nie można otworzyć pliku docelowego: '%1' Cannot backup to file: '%1'. Message: %2 Nie można utworzyć pliku kopii zapasowej: '%1'. Opis: %2 The database is currently busy: Baza danych jest obecnie zajÄ™ta: Do you want to abort that other operation? Czy na pewno chcesz przerwać tÄ… innÄ… operacjÄ™? Exporting database to SQL file... Eksportowanie bazy danych do pliku SQL… Cancel Zaniechaj No database file opened Plik z bazÄ… danych nie jest obecnie otwarty Executing SQL... Wykonywanie SQL… Action cancelled. Zaniechano dziaÅ‚ania. Error in statement #%1: %2. Aborting execution%3. Błąd w poleceniu #%1: %2. Przerywam wykonywanie%3. and rolling back i przywracam didn't receive any output from %1 nie otrzymano żadnego wyniku z %1 could not execute command: %1 nie można wykonać polecenia: %1 Cannot delete this object Nie można usunąć tego obiektu Cannot set data on this object Nie można ustawić danych na tym objekcie A table with the name '%1' already exists in schema '%2'. Tabela o nazwie '%1' już istnieje w schemacie '%2'. No table with name '%1' exists in schema '%2'. Tabela o nazwie '%1' nie istnieje w schemacie '%2'. Cannot find column %1. Nie można znaleźć kolumny %1. Creating savepoint failed. DB says: %1 Nie można utworzyć punktu zapisu. BD zwraca: %1 Renaming the column failed. DB says: %1 Nie można przemianować tej kolumny. BD zwraca: %1 Releasing savepoint failed. DB says: %1 Nie można zwolnić punktu zapisu. BD zwraca: %1 Creating new table failed. DB says: %1 Nie można utworzyć nowej tabeli. BD zwraca: %1 Copying data to new table failed. DB says: %1 Nie można skopiować nowej tabeli. BD zwraca: %1 Deleting old table failed. DB says: %1 Nie można usunąć starej tabeli. BD zwraca: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 Błąd przemianowywania tabeli z '%1' na '%2'. Wiadomość z silnika bazy danych: %3 could not get list of db objects: %1 nie można pobrać listy obiektów bd: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: WystÄ…piÅ‚ błąd przy odtworzeniu niektórych obiektów powiÄ…zanych z tÄ… bazÄ… danych. Błędy tego rodzaju wystÄ™pujÄ… za zwyczaj w przypadku zmiany nazw niektórych kolumn. Sprawdź dokÅ‚adnie nastÄ™pujÄ…cÄ… kwerendÄ™ SQL. Po dokonaniu zmian możesz jÄ… rÄ™cznie uruchomić: could not get list of databases: %1 nie mogÄ™ odczytać listy baz danych: %1 Error setting pragma %1 to %2: %3 Błąd przy ustawianiu pragmy %1 do %2: %3 File not found. Nie znaleziono pliku. Error loading extension: %1 Nie można wczytać rozszerzenia: %1 Error loading built-in extension: %1 could not get column information nie można uzyskać informacji o kolumnie DbStructureModel Name Nazwa Object Obiekt Type Rodzaj Schema Polecenie tworzÄ…ce Database Baza danych Browsables Obiekty do przeglÄ…dania All Wszystkie Temporary Tymczasowa Tables (%1) Tabele (%1) Indices (%1) Indeksy (%1) Views (%1) Widoki (%1) Triggers (%1) Wyzwalacze (%1) EditDialog Edit database cell Zmiana komórki bazy danych Mode: Tryb: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. To jest lista dostÄ™pnych trybów dla edytora komórek. Wybierz tryb do wyÅ›wietlania lub edycji danych dla tej komórki. Text Tekst RTL Text Tekst od prawej do lewej Binary Zapis dwójkowy Image Obraz JSON JSON XML XML Evaluation Obliczenie Automatically adjust the editor mode to the loaded data type Sam dostosuj tryb edytora w zależnoÅ›ci od wczytanych danych This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. To pole zaznaczane włącza lub wyłącza samoczynne przełączanie do trybu edytora. Po wybraniu nowej komórki lub zaimportowaniu nowych danych i przy włączonym samoczynnym przełączaniu, tryb dostosowuje siÄ™ do wykrytego rodzaju danych. NastÄ™pnie można zmienić tryb edytora rÄ™cznie. Aby zapamiÄ™tać ten try rÄ™czny przy przechodzeniu po komórkach, wystarczy odznaczyć to pole. Auto-switch Sam przełączaj This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Edytor Qt jest używany do pism od-prawej-do-lewej, które nie sÄ… obsÅ‚ugiwane przez domyÅ›lny edytor tekstu. Obecność znaków pism od-prawej-do-lewej jest wykrywana, a edytor sam przełącza siÄ™ do tego trybu. Identification of the cell currently in the editor Identyfikator komórki, bÄ™dÄ…cej obecnie w edytorze Type and size of data currently in table Rodzaj i rozmiar danych, bÄ™dÄ…cych obecnie w edytorze Open preview dialog for printing the data currently stored in the cell Otwiera okno dialogowe do podglÄ…du drukowanych danych z danej komórki Auto-format: pretty print on loading, compact on saving. Auto-formatowanie: upiÄ™ksza tekst przy wczytywaniu i Å›ciska przy zapisywaniu. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Po zaznaczeniu, dane sÄ… formatowane podczas ich wczytywania, Å‚amiÄ…c tekst w wierszach oraz wcinajÄ…c go dla najlepszej czytelnoÅ›ci. Przed zapisaniem, dane sÄ… oczyszczane poprzez usuniÄ™cie zakoÅ„czeÅ„ wierszy oraz niepotrzebnych biaÅ‚ych znaków. Word Wrap Zawijaj wiersze Wrap lines on word boundaries Zawijaj wiersze na granicach słów Open in default application or browser Otwórz w domyÅ›lnej aplikacji lub przeglÄ…darce Open in application Otwórz w aplikacji The value is interpreted as a file or URL and opened in the default application or web browser. Wartość jest traktowana jako plik lub adres URL i otwierana w domyÅ›lnej aplikacji lub przeglÄ…darce sieciowej. Save file reference... Zapisz odniesienie pliku... Save reference to file Zapisz odniesienie do pliku Open in external application Otwórz w zewnÄ™trznej aplikacji Autoformat Sam formatuj &Export... Wy&eksportuj... &Import... Za&importuj... Import from file Zaimportuj z pliku Opens a file dialog used to import any kind of data to this database cell. Otwiera okno wyboru pliku z danymi do zaimportowania w tej komórce. Export to file Wyeksportuj do pliku Opens a file dialog used to export the contents of this database cell to a file. Otwiera okno pozwalajÄ…ce na wyeksportowanie zawartoÅ›ci komórki do pliku. Erases the contents of the cell CzyÅ›ci zawartość komórki Set as &NULL Ustaw jako &NULL This area displays information about the data present in this database cell Tutaj wyÅ›wietlane sÄ… informacje o danych obecnych w tej komórce Apply data to cell Zapisz dane w komórce This button saves the changes performed in the cell editor to the database cell. Ten przycisk zapisuje zmiany wykonane w edytorze komórki w komórce bazy danych. Apply Zastosuj Print... Wydrukuj... Ctrl+P Ctrl+P Open preview dialog for printing displayed text Otwiera okno dialogowe do podglÄ…du wyÅ›wietlanego tekstu Copy Hex and ASCII Skopiuj Hex i ASCII Copy selected hexadecimal and ASCII columns to the clipboard Skopiuj zaznaczone kolumny szesnastkowe oraz ASCII do schowka Ctrl+Shift+C Ctrl+Shift+C Image data can't be viewed in this mode. Obrazy nie mogÄ… zostać wyÅ›wietlone w tym trybie. Try switching to Image or Binary mode. Przejdź do trybu obrazu lub wartoÅ›ci binarnej. Binary data can't be viewed in this mode. Wartość dwójkowa nie może być wyÅ›wietlona w tym trybie. Try switching to Binary mode. Przejdź do trybu wartoÅ›ci binarnej. Image files (%1) Piki graficzne (%1) Binary files (*.bin) Pliki Binarne (*.bin) Choose a file to import Wybierz plik do zaimportowania The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Tryby edytora tekstu umożliwiajÄ… zmianÄ™ zwykÅ‚ego tekstu, a także danych JSON, czy XML z jednoczesnym podÅ›wietlaniem skÅ‚adni, formatowaniem oraz sprawdzaniem poprawnoÅ›ci przez zpisem. Błędy sÄ… wskazywane czerwone zygzakowate podkreÅ›lenie. W trybie Obliczania, wpisane wyrażenia SQLite sÄ… obliczane, a ich wynik jest zapisywany do komórki. Unsaved data in the cell editor Niezapisane dane w edytorze komórki The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Edytor komórki zawiera dane jeszcze niazapisane do bazy danych. Czy chcesz zapisać zmienione dane w wierszu=%1, kolumnie=%2? Editing row=%1, column=%2 Zmienianie wiersza=%1, kolumny=%2 No cell active. Nie zostaÅ‚a wybrana żadna komórka. %1 Image %1 Grafika Choose a filename to export data Wybierz nazwÄ™ pliku dla wyeksportowanych danych Invalid data for this mode NieprawidÅ‚owe dane w tym trybie The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? Komórka zawiera nieprawidÅ‚owe dane %1. Powód: %2. Czy na pewno wstawić je do komórki? Type: NULL; Size: 0 bytes Rodzaj: NULL; Rozmiar: 0 bajtów Type: Text / Numeric; Size: %n character(s) Rodzaj: Tekst / Liczba; Rozmiar: %n znak Rodzaj: Tekst / Liczba; Rozmiar: %n znaki Rodzaj: Tekst / Liczba; Rozmiar: %n znaków Type: %1 Image; Size: %2x%3 pixel(s) Rodzaj: Obraz %1; Rozmiar: %2x%3 pikseli Type: Valid JSON; Size: %n character(s) Rodzaj: PrawidÅ‚owy JSON; Rozmiar: %n znak Rodzaj: PrawidÅ‚owy JSON; Rozmiar: %n znaki Rodzaj: PrawidÅ‚owy JSON; Rozmiar: %n znaków Type: Binary; Size: %n byte(s) Rodzaj: Dwójkowe; Rozmiar: %n bajt Rodzaj: Dwójkowe; Rozmiar: %n bajty Rodzaj: Dwójkowe; Rozmiar: %n bajtów Couldn't save file: %1. Nie można zapisać pliku: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Dane zostaÅ‚y zapisane do pliku tymczasowego i otwarte przy użyciu domyÅ›lnej aplikacji. Możesz teraz edytować plik, a gdy bÄ™dziesz gotowy, to zatwierdź lub wycofaj nowe dane w komórce. EditIndexDialog Edit Index Schema Edytor tworzenia indeksu &Name &Nazwa &Table &Tabela &Unique &Niepowtarzalność For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Aby ograniczyć indeks tylko do części tabeli można dopisać tutaj polecenie WHERE, które zaznacza część tabeli, która ma zostać zaindeksowana Partial inde&x clause Polecenie częściowego &indeksu Colu&mns Kolu&mny Table column Kolumna tabeli Type Rodzaj Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Dodaj nowÄ… kolumnÄ™ wyrażenia do indeksu. Kolumny wyrażeÅ„ zawierajÄ… raczej wyrażenia SQL niż nazwy kolumn. Index column Kolumna indeksu Order PorzÄ…dek Deleting the old index failed: %1 Usuwanie starego indeksu nie powiodÅ‚o siÄ™: %1 Creating the index failed: %1 Tworzenie indeksu nie powiodÅ‚o siÄ™: %1 EditTableDialog Edit table definition Edycja tworzenia tabeli Table Tabela Advanced Rozszerzone Without Rowid Bez ID wiersza Fields Pola Database sche&ma Sche&mat bazy danych Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict JeÅ›li sprzeczne Strict ÅšcisÅ‚e When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Po zaznaczeniu pola "Å›cisÅ‚e" SQLite wymusza rodzaje danych na każdej kolumnie przy uaktualnianiu lub wstawianiu do niej danych. Add Dodaj Remove UsuÅ„ Move to top PrzesuÅ„ na górÄ™ Move up PrzesuÅ„ w górÄ™ Move down PrzesuÅ„ w dół Move to bottom PrzesuÅ„ na dół Name Nazwa Type Rodzaj NN NN Not null Nie NULL PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> Klucz główny</p></body></html> AI AI Autoincrement Samoprzyrostowa U U Unique Niepowtarzalność Default DomyÅ›lna Default value DomyÅ›lna wartość Check Sprawdzenie Check constraint Ograniczenie sprawdzenia Collation Zestawienie Foreign Key Klucz obcy <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> Klucz obcy</p></body></html> Index Constraints Warunki indeksu Add constraint Dodaj ograniczenie Remove constraint UsuÅ„ ograniczenie Columns Kolumny SQL SQL Foreign Keys Klucze obce References Odniesienia Check Constraints Warunki sprawdzajÄ…ce <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Uwaga: </span>W okreÅ›leniu tabeli jest coÅ›, czego nasze przetwarzanie skÅ‚adni nie rozumie. Zmiana i zapis tej tabeli może skutkować kÅ‚opotami.</p></body></html> Primary Key Klucz główny Add a primary key constraint Dodaj ograniczenie klucza głównego Add a unique constraint Dodaj ograniczenie niepowtarzalnoÅ›ci There can only be one primary key for each table. Please modify the existing primary key instead. Dla każdej tabeli może być tylko jeden klucz główny. ZmieÅ„ istniejÄ…cy klucz główny. Error creating table. Message from database engine: %1 Nie można utworzyć tabeli. Wiadomość z silnika bazy danych: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Istnieje już pole o tej nazwie. Przemianuj je najpierw lub wybierz innÄ… nazwÄ™ dla tego pola. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Kolumna ma odwoÅ‚anie do klucza obcego w tabeli %1 wiÄ™c jej nazwa nie można zmienić jej nazwy. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. W tym polu istnieje co najmniej jeden wiersz z wartoÅ›ciÄ… równÄ… NULL. Czyni to niemożliwym ustawienie tej flagi. Najpierw zmieÅ„ dane tabeli. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. W tym polu istnieje co najmniej jeden wiersz z wartoÅ›ciÄ… nie bÄ™dÄ…cÄ… liczbÄ… caÅ‚kowitÄ…. Czyni to niemożliwym ustawienie flagi AI. Najpierw zmieÅ„ dane tabeli. Column '%1' has duplicate data. Kolumna '%1' zawiera powielone dane. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Czyni to niemożliwym nadanie flagi 'Unique'. UsuÅ„ powielone dane, aby móc nadać flagÄ™ 'Unique'. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Czy na pewno usunąć pole '%1'? Wszystkie dane przechowywane w tym polu zostanÄ… utracone. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Dodaj pola, które speÅ‚niajÄ… dane warunki przed ustawieniem flagi bez rowid: - Ustawiono flagÄ™ głównego klucza - Wyłączono samoprzyrost Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set Dodaj pole, które speÅ‚nia nastÄ™pujÄ…ce warunki przed ustawieniem dziaÅ‚ania w-przecznoÅ›ci: - Ustawiono flagÄ™ głównego klucza ExportDataDialog Export data as CSV Eksport danych jako CSV Tab&le(s) Tabe&la/e Colu&mn names in first line Nazwy kolu&mn w pierwszym wierszu Fie&ld separator Znak oddzie&lajÄ…cy pola , , ; ; Tab Tab | | Other Inny &Quote character &Znak cytatu " " ' ' New line characters Znak nowego wiersza Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print UpiÄ™ksz wydruk Export data as JSON Eksport danych jako JSON exporting CSV eksportowanie CSV Error while writing the file '%1': %2 Błąd przy zapisywaniu pliku '%1': %2 Could not open output file: %1 Nie można otworzyć pliku wyjÅ›ciowego: %1 exporting JSON eksportowanie JSON Choose a filename to export data Wybierz nazwÄ™ pliku dla eksportowanych danych Please select at least 1 table. Wybierz przynajmniej jednÄ… tabelÄ™. Choose a directory Wybierz poÅ‚ożenie Export completed. Eksportowanie zakoÅ„czone. Export finished with errors. Wyeksportuj ukoÅ„czone z błędami. ExportSqlDialog Export SQL... Wyeksportuj SQL... Tab&le(s) Tabel&a/e Select All Zaznacz wszystkie Deselect All Odznacz wszystkie &Options &Opcje Keep column names in INSERT INTO Pozostaw nazwy kolumn w INSERT INTO Multiple rows (VALUES) per INSERT statement Wiele rzÄ™dów (WartoÅ›ci) dla polecenia INSERT Export everything Wyeksportuj wszystko Export schema only Wyeksportuj tylko schemat Export data only Wyeksportuj tylko dane Keep original CREATE statements Zachowaj pierwotne polecenia CREATE Keep old schema (CREATE TABLE IF NOT EXISTS) Zachowaj poprzedni schemat (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) ZastÄ…p poprzedni schemat (DROP TABLE, then CREATE TABLE) Please select at least one table. Wybierz przynajmniej jednÄ… tabelÄ™. Choose a filename to export Wybierz nazwÄ™ eksportowanego pliku Export completed. Eksportowanie zakoÅ„czono. Export cancelled or failed. Eksportowanie nie udaÅ‚o siÄ™ lub zostaÅ‚o zaniechane. ExtendedScintilla Ctrl+H Ctrl+H Ctrl+F Ctrl+F Ctrl+P Ctrl+P Find... Znajdź... Find and Replace... Znajdź i zamień… Print... Wydrukuj... ExtendedTableWidget Use as Exact Filter Użyj jako dokÅ‚adnego filtra Containing Zawiera Not containing Nie zawiera Not equal to Nierówny Greater than WiÄ™kszy niż Less than Mniejszy niż Greater or equal WiÄ™kszy lub równy Less or equal Mniejszy lub równy Between this and... PomiÄ™dzy tym a... Regular expression Wyrażenie regularne Edit Conditional Formats... ZmieÅ„ formatowanie warunkowe... Set to NULL Ustaw jako NULL Cut Wytnij Copy Skopiuj Copy with Headers Skopiuj wraz z nagłówkami Copy as SQL Skopiuj jako SQL Paste Wklej Print... Wydrukuj... Use in Filter Expression Użyj w wyrażeniu filtra <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>Nie wczytano wszystkich danych. <b>Czu chcesz wczytać wszystkie dane przez zaznaczeniem wszystkich wierszy?</b><p><p>Odpowiedź <b>Nie</b> oznacza, że nie zostanie wczytanych wiÄ™cej danych i nie zostanie nic zaznaczone.<br/>Odpowiedź <b>Tak</b> oznacza, że trochÄ™ czasu może być potrzebne na wczytanie danych za to zaznaczenie bÄ™dzie peÅ‚ne.</p>Uwaga: Wczytanie wszystkich danych może wymagać dużej iloÅ›ci pamiÄ™ci dla dużych tabel. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. Nie można ustawić zaznaczonych na NULL. Kolumna %1 ma ograniczenie NOT NULL. Alt+Del Alt+Del Ctrl+Shift+C Ctrl+Shift+C Ctrl+Alt+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? Zawartość schowka jest wiÄ™ksza niż zaznaczony zakres. Czy chcesz go wstawić mimo tego? FileExtensionManager File Extension Manager ZarzÄ…dzanie Rozszerzeniami Plików &Up &W górÄ™ &Down W &dół &Add Dod&aj &Remove &UsuÅ„ Description Opis Extensions Rozszerzenia *.extension *.rozszerzenie FilterLineEdit Filter Filtr These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Te pola wejÅ›ciowe umożliwiajÄ… szybkie filtrowanie na bieżącej tabeli. DomyÅ›lnie, wiersze zawierajÄ…ce tekst wejÅ›ciowy sÄ… odfiltrowywane. ObsÅ‚ugiwane sÄ… nastÄ™pujÄ…ce operatory: % Znak wieloznaczny > WiÄ™ksze niż < Mniejsze niż >= Równe lub wiÄ™ksze <= Równe lub mniejsze = Równe: dokÅ‚adnie pasuje <> Nierówne: nie pasuje x~y Zakres: wartoÅ›ci pomiÄ™dzy x oraz y /regexp/ WartoÅ›ci pasujÄ…ce do wyrażenia regularnego Clear All Conditional Formats Wyczyść wszystkie formatowania warunkowe Use for Conditional Format Użyj do formatowania warunkowego Edit Conditional Formats... Edytuj formatowanie warunkowe... Set Filter Expression Ustaw wyrażenia filtra What's This? Co to jest? Is NULL Jest NULL Is not NULL Nie jest NULL Is empty Jest puste Is not empty Nie jest puste Not containing... Nie zawiera... Equal to... Równe... Not equal to... Nierówne... Greater than... WiÄ™ksze niż... Less than... Mniejsze niż... Greater or equal... WiÄ™ksze lub równe... Less or equal... Mniejsze lub równe... In range... W zakresie... Regular expression... Wyrażenie regularne... FindReplaceDialog Find and Replace Znajdź i zastÄ…p Fi&nd text: Z&najdź tekst: Re&place with: ZamieÅ„ &z: Match &exact case Rozróżniaj wielkość lit&er Match &only whole words Tylk&o caÅ‚e wyrazy When enabled, the search continues from the other end when it reaches one end of the page Po zaznaczeniu, wyszukiwanie jest wznawiane od przeciwlegÅ‚ego koÅ„ca strony po osiÄ…gniÄ™ciu koÅ„ca strony &Wrap around Za&wijaj When set, the search goes backwards from cursor position, otherwise it goes forward Po zaznaczeniu, wyszukiwanie postÄ™puje wstecz od poÅ‚ożenia wskaźnika, w przeciwnym przypadku postÄ™puje wprzód Search &backwards Szukaj &na odwrót <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>Po zaznaczeniu, wzorzec do znalezienia jest szukany tylko w bieżącym zaznaczeniu.</p></body></html> &Selection only Tylko &zaznaczenie <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Po zaznaczeniu, wzorzec do znalezienia jest rozważany jako wyrażenie regularne UNIX. Zajrzyj do <a href="https://en.wikibooks.org/wiki/Regular_Expressions">WyrażeÅ„ Regularnych w Wikibooks</a>.</p></body></html> Use regular e&xpressions Stosuj wyrażenie &regularne Find the next occurrence from the cursor position and in the direction set by "Search backwards" Szukaj kolejnego wystÄ…pienia od poÅ‚ożenia wskaźnika i w stronÄ™ okreÅ›lonÄ… poprzez "Wyszukiwanie wstecz" &Find Next Z&najdź nastÄ™pne F3 F3 &Replace &ZastÄ…p Highlight all the occurrences of the text in the page PodÅ›wietl wszystkie wystÄ…pienia tekstu na stronie F&ind All Znajdź wszystk&ie Replace all the occurrences of the text in the page ZastÄ…p wszystkie wystÄ…pienia w tekÅ›cie na stronie Replace &All Z&amieÅ„ wszystkie The searched text was not found Nie znaleziono szukanego tekstu The searched text was not found. Nie znaleziono szukanego tekstu. The searched text was found one time. Szukany tekst zostaÅ‚ znaleziony raz. The searched text was found %1 times. Szukany tekst zostaÅ‚ znaleziony %1 razy. The searched text was replaced one time. Szukany tekst zostaÅ‚ zamieniony raz. The searched text was replaced %1 times. Szukany tekst zostaÅ‚ zamieniony %1 razy. ForeignKeyEditor &Reset &Resetuj Foreign key clauses (ON UPDATE, ON DELETE etc.) Polecenia obcego klucza (ON UPDATE, ON DELETE itp.) ImageViewer Image Viewer PrzeglÄ…darka obrazów Reset the scaling to match the original size of the image. Wyzeruj podziaÅ‚kÄ™, aby byÅ‚a równa pierwotnemu rozmiarowi obrazu. Set the scaling to match the size of the viewport. Ustaw podziaÅ‚kÄ™, aby obraz zmieÅ›ciÅ‚ siÄ™ w widoku. Print... Wydrukuj... Open preview dialog for printing displayed image Otwórz okno podglÄ…du do wydrukowania wyÅ›wietlanego obrazu Ctrl+P Ctrl+P ImportCsvDialog Import CSV file Zaimportuj plik CSV Table na&me &Nazwa tabeli &Column names in first line &Nazwy kolumn w pierwszej linii Field &separator &Znak oddzielajÄ…cy pola , , ; ; Tab Tab | | Other Inny &Quote character Znak &cytatów Other (printable) Inne (drukowalne) Other (code) Inny (kod) " " ' ' &Encoding Kodowani&e UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? Przycinać pola? Separate tables Oddzielaj tabele Advanced Rozszerzone When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Przy importowaniu pustej wartoÅ›ci z pliku CSV do istniejÄ…cej tabeli z domyÅ›lnÄ… wartoÅ›ciÄ… dla tej kolumny, wstawiana jest ta domyÅ›lna wartość. Aby zamiast tego wstawić pustÄ… wartość, wystarczy zaznaczyć to pole. Ignore default &values Ignoruj domyÅ›lne &wartoÅ›ci Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Zaznacz to pole, aby zatrzymać importowanie, podczas importowania pustej wartoÅ›ci do kolumny NOT NULL bez domyÅ›lnej wartoÅ›ci. Fail on missing values ZgÅ‚aszaj błąd dla brakujÄ…cych wartoÅ›ci Disable data type detection Wyłącz wykrywanie rodzajów danych Disable the automatic data type detection when creating a new table. Wyłącz samowykrywanie rodzaju danych przy tworzeniu nowej tabeli. Use local number conventions Użyj zapisu liczb z mojego jÄ™zyka Use decimal and thousands separators according to the system locale. Użyj znaku dziesiÄ™tnego i do rozdzielania tysiÄ™cy z jÄ™zyka mojego systemu. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Przy importowaniu do istniejÄ…cej tabeli o głównym kluczu, ograniczeniu lub indeksie niepowtarzalnoÅ›ci istnieje szansa na sprzeczność. To ustawienie umożliwia wybranie strategii dla tego przypadku. DomyÅ›lnie importowanie jest przerywane, a zmiany wycofywane, lecz można także pominąć wiersze bÄ™dÄ…ce w sprzecznoÅ›ci lub zastÄ…pić istniejÄ…cy wiersz w tabeli. Abort import Przerwij importowanie Ignore row PomiÅ„ wiersz Replace existing row ZastÄ…p istniejÄ…cy wiersz Conflict strategy Strategia na sprzecznoÅ›ci Deselect All Odznacz wszystkie Match Similar Dopasuj do podobnych Select All Zaznacz wszystkie There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Tabela o nazwie '%1' już istnieje i importowanie do istniejÄ…cej tabeli jest możliwe tylko gdy liczba kolumn zgadza siÄ™. There is already a table named '%1'. Do you want to import the data into it? Tabela o nazwie '%1' już istnieje. Czy chcesz zaimportować dane do niej? Creating restore point failed: %1 Nie można utworzyć punktu przywracania: %1 Creating the table failed: %1 Tworzenie tabeli nie powiodÅ‚o siÄ™: %1 importing CSV importowanie CSV Could not prepare INSERT statement: %1 Nie można byÅ‚o przygotować polecania INSERT: %1 Inserting row failed: %1 Wstawianie rzÄ™du nie powiodÅ‚o siÄ™: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Nieoczekiwany koniec pliku. Upewnij siÄ™, że masz poprawnie ustawione znaki cytowania i że plik nie jest znieksztaÅ‚cony. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Importowanie pliku '%1' zajęło %2ms. Z tego %3ms spÄ™dzono na funkcji wiersza. MainWindow DB Browser for SQLite PrzeglÄ…darka SQLite Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Uwaga: to polecenie pragma nie jest czytelne, wiÄ™c ta wartość powstaÅ‚a z domysÅ‚u. Zapisanie polecenie pragma może zastÄ…pić LIKE dostarczony przez rozszerzenie SQLite. toolBar1 toolBar1 This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Oto ukÅ‚ad bieżącej bazy danych. Można przeciÄ…gać polecenia SQL z wiersza obiektu i upuszczać je na innych aplikacjach lub wstawiać je do innego wystÄ…pienia 'PrzeglÄ…darki SQLite'. Execute line Wykonaj wiersz Un/comment block of SQL code Dodaj/UsuÅ„ uwagÄ™ do kawaÅ‚ka kodu SQL Un/comment block Dodaj/UsuÅ„ uwagÄ™ do kawaÅ‚ka kodu Comment or uncomment current line or selected block of code Dodaj lub usuÅ„ uwagÄ™ do bieżącego wiersza lub zaznaczonego kawaÅ‚ka kodu Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Dodaj lub usuÅ„ uwagÄ™ do bieżącego wiersza lub zaznaczonych wierszy, gdy jest coÅ› zaznaczone. CaÅ‚y kawaÅ‚ek przełączany jest wg pierwszego wiersza. Ctrl+/ Ctrl+/ Stop SQL execution Zatrzymaj wykonywanie SQL Stop execution Zatrzymaj wykonywanie Stop the currently running SQL script Zatrzymaj wykonywanie bieżącego skryptu SQL &File &Plik &Import Za&importuj &Export Wy&eksportuj &Edit &Edycja &View &Widok &Help Po&moc Too&ls &NarzÄ™dzia DB Toolbar Pasek zadaÅ„ bazy danych Edit Database &Cell Zmiana komórki bazy dany&ch SQL &Log Dziennik SQ&L Show S&QL submitted by Pokaż S&QL wydane przez User Użytkownika Application AplikacjÄ™ Error Log Dziennik błędów This button clears the contents of the SQL logs Ten przycisk czyÅ›ci zawartość logów SQL &Clear Wy&czyść This panel lets you examine a log of all SQL commands issued by the application or by yourself Ten panel umożliwia przeglÄ…d dziennika wszystkich poleceÅ„ SQL wydanych przez aplikacjÄ™ lub przez ciebie &Plot &Wykres DB Sche&ma UkÅ‚ad da&nych &Remote &Zdalne BD Project Toolbar Pasek zadaÅ„ projektu Extra DB toolbar Dodatkowy pasek zadaÅ„ bazy danych Close the current database file Zamknij obecny plik bazy danych &New Database... &Nowa baza danych… Create a new database file Utwórz nowy plik bazy danych This option is used to create a new database file. Ta opcja jest wykorzystywana do tworzenia nowego pliku bazy danych. Ctrl+N Ctrl+N &Open Database... &Otwórz bazÄ™ danych… Open an existing database file Otwórz istniejÄ…cÄ… bazÄ™ danych This option is used to open an existing database file. Ta opcja otwiera istniejÄ…cy plik bazy danych. Ctrl+O Ctrl+O &Close Database Zamknij bazÄ™ dany&ch This button closes the connection to the currently open database file Ten przycisk koÅ„czy połączenie z obecnie otwartym plikiem bazy danych New &tab Nowa kar&ta Open SQL file(s) Otwórz plik(i) SQL This button opens files containing SQL statements and loads them in new editor tabs Przycisk ten otwiera pliki, zawierajÄ…ce polecenia SQL oraz wczytuje je do kart nowego edytora This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Przycisk ten umożliwia zapisanie wszystkich ustawieÅ„ zwiÄ…zanych z otwieraniem bazy danych w PrzeglÄ…darce BD w przypadku pliku projektu This button lets you open a DB Browser for SQLite project file Przycisk ten umożliwia ci otwarcie pliku projektu PrzeglÄ…darki BD &Open Database &Otwórz bazÄ™ danych Drag && Drop SELECT Query PrzeciÄ…gnij && upuść zapytanie SELECT When dragging fields from the same table or a single table, drop a SELECT query into the editor Przy przeciÄ…gniu pól z tej samej tabeli lub pojedynczej tabeli upuść zapytania SELECT na edytor Browse Table PrzeglÄ…daj tabelÄ™ Close Pro&ject Zamknij pro&jekt Close project and database files and return to the initial state Zamknij plik projektu i bazy danych oraz zwróć poczÄ…tkowy stan Ctrl+Shift+F4 Ctrl+Shift+F4 Detach Database Odłącz bazÄ™ danych Detach database file attached to the current database connection Odłącz plik bazy danych dołączony do bieżącego połączenia bazy danych Ctrl+W Ctrl+W &Revert Changes &Wycofaj zmiany Revert database to last saved state Przywróć bazÄ™ danych do ostatniego zapisanego stanu This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Ten dziaÅ‚anie sÅ‚uży do przywrócenia bieżącej bazy danych do ostatnio zapisanego stanu. Wszystkie zmiany od czasu ostatniego zapisu zostanÄ… utracone. &Write Changes &Zapisz zmiany Write changes to the database file Zapisz zmiany w pliku bazy danych This option is used to save changes to the database file. Ta opcja zapisuje zmiany w pliku bazy danych. Ctrl+S Ctrl+S Ctrl+Shift+O Ctrl+Shift+O &Save Project As... Zapi&sz projekt jako... Save the project in a file selected in a dialog Zapisuje projekt w pliku wskazanym w dialogu Save A&ll Zapisz w&szystko Save DB file, project file and opened SQL files Zapisuje plik bazy danych, projektu i otwarte pliki SQL Ctrl+Shift+S Ctrl+Shift+S This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Oto ukÅ‚ad bieżącej bazy danych. Można przeciÄ…gać wiele nazw obiektów z kolumny nazwy i upuszczać je w edytorze SQL. NastÄ™pnie można dostosować wÅ‚aÅ›ciwoÅ›ci upuszczonych nazw poprzez menu podrÄ™czne. To ma na celu pomoc w tworzeniu polecenia SQL. Można przeciÄ…gać polecenia SQL z kolumny schematu i upuszczać je w edytorze SQL lub innych aplikacjach. Compact &Database... ÅšciÅ›nij bazÄ™ &danych... Compact the database file, removing space wasted by deleted records ÅšciÅ›nij plik bazÄ™ danych, usuwajÄ…c przestrzenie marnowane przez usuniÄ™te rekordy Compact the database file, removing space wasted by deleted records. ÅšciÅ›nij plik bazÄ™ danych, usuwajÄ…c przestrzenie marnowane przez usuniÄ™te rekordy. E&xit &Wyjdź Ctrl+Q Ctrl+Q &Database from SQL file... BazÄ™ &danych z pliku SQL… Import data from an .sql dump text file into a new or existing database. Zaimportuj dane z pliku tekstowego zrzutu .sql do nowej lub istniejÄ…cej bazy danych. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. To dziaÅ‚anie, umożliwia importowanie danych z pliku tekstowego zrzutu .sql do nowej lub istniejÄ…cej bazy danych. Pliki zrzutu SQL można utworzyć w wiÄ™kszoÅ›ci silników baz danych, włączajÄ…c w to MySQL oraz PostgreSQL. &Table from CSV file... &TabelÄ™ z pliku CSV… Open a wizard that lets you import data from a comma separated text file into a database table. Otwiera okno pomocnika do importowania danych z pliku CSV do tabeli bazy danych. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Otwiera okno pomocnika do importowania danych z pliku CSV do tabeli bazy danych. Plik CSV można stworzyć na podstawie wiÄ™kszoÅ›ci baz danych i aplikacji arkuszy kalkulacyjnych. &Database to SQL file... BazÄ™ &danych do pliku SQL… Export a database to a .sql dump text file. Wyeksportuj bazÄ™ danych do pliku tekstowego zrzutu .sql. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. To dziaÅ‚anie umożliwia eksportowanie bazy danych do pliku tekstowego zrzutu .sql. Plik zrzutu SQL zawiera wszystkie dane niezbÄ™dne do odtworzenia bazy danych na wiÄ™kszoÅ›ci silników baz danych, włączajÄ…c w to MySQL oraz PostgreSQL. &Table(s) as CSV file... &TabelÄ™ do pliku CSV… Export a database table as a comma separated text file. Eksportuje tabelÄ™ bazy danych jako plik tekstowy, oddzielajÄ…c wartoÅ›ci przecinkami. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Eksportuje tabelÄ™ bazy danych jako plik tekstowym który można zaimportować w innych aplikacjach bazodanowych lub arkuszach kalkulacyjnych; oddzielajÄ…c wartoÅ›ci przecinkami. &Create Table... &Utwórz tabelę… Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Otwiera okno tworzenia tabel, gdzie można zdefiniować nazwÄ™ i pola w nowej tabeli w bazie danych &Delete Table... U&suÅ„ tabelę… Delete Table UsuÅ„ tabelÄ™ Open the Delete Table wizard, where you can select a database table to be dropped. Otwiera pomocnika do UsuniÄ™cia Tabeli, gdzie można wybrać tabelÄ™ bazy danych do usuniÄ™cia. &Modify Table... &Dostosuj tabelÄ™... Create &Index... Utwórz &indeks… Open the Create Index wizard, where it is possible to define a new index on an existing database table. Otwiera pomocnika do Tworzenia Indeksu, gdzie można okreÅ›lić nowy indeks na istniejÄ…cej tabeli bazy danych. &Preferences... U&stawienia... Open the preferences window. Otwórz okno ustawieÅ„. &DB Toolbar Pasek narzÄ™dzi bazy &danych Shows or hides the Database toolbar. Pokazuje lub ukrywa pasek narzÄ™dzi od bazy danych. Ctrl+T Ctrl+T W&hat's This? &Co to jest? Ctrl+F4 Ctrl+F4 Shift+F1 Shift+F1 &About O progr&amie &Load Extension... &Wczytaj rozszerzenia... &Wiki &Wiki F1 F1 Bug &Report... &ZgÅ‚oszenie błędu... Feature Re&quest... ZgÅ‚oszenie ż&yczenia... Web&site Strona &sieciowa &Donate on Patreon... &Darowizna na Patreon... Open &Project... Otwórz &projekt... &Attach Database... Dołącz bazÄ™ d&anych... &Set Encryption... U&staw szyfrowanie... This button saves the content of the current SQL editor tab to a file Ten przycisk zapisuje treść bieżącej karty edytora SQL do pliku SQLCipher &FAQ &Najczęściej zadawane pytania SQLCipher New In-&Memory Database Nowa baza danych w-pa&miÄ™ci Drag && Drop Qualified Names PrzeciÄ…gnij && upuść nazwy z ukÅ‚adu Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Używaj nazw z ukÅ‚adu (np. "Tabela"."Pole") przy przeciÄ…ganiu obiektów i upuszczaniu ich w edytorze Drag && Drop Enquoted Names PrzeciÄ…gnij && upuść nazw w cudzysÅ‚owach Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Używaj nazw w cudzysÅ‚owach (np. "Tabela1") przy przeciÄ…ganiu obiektów i upuszczaniu ich w edytorze &Integrity Check Sprawdzanie spójnoÅ›c&i Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. Wykonuje polecenie pragma integrity_check na bieżącej bazie danych i zwraca wynik na karcie Wykonywania SQL. To polecenie pragma wykonuje sprawdzenie spójnoÅ›ci caÅ‚ej bazy danych. &Foreign-Key Check &Sprawdzenie obcego klucza Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Wykonuje polecenie pragma foreign_key_check na bieżącej bazie danych i zwraca wynik na karcie Wykonywania SQL &Quick Integrity Check &Szybkie sprawdzenie spójnoÅ›ci Run a quick integrity check over the open DB Wykonaj sprawdzenie spójnoÅ›ci bieżącej bazy danych Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. Wykonuje polecenie pragma quick_check na bieżącej bazie danych i zwraca wynik na karcie Wykonywania SQL. To polecenie pragma wykonuje wiÄ™kszość tego, co wykonuje polecenie pragma integrity_check lecz robi to znacznie szybciej. &Optimize &Optymalizacja Attempt to optimize the database Próba optymalizacji bazy danych Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Wykonuje polecenie pragma optimize na bieżącej bazie danych. To polecenie może wykonać optymalizacje, które zwiÄ™kszÄ… wydajność przyszÅ‚ych zapytaÅ„. Print Wydrukuj Print text from current SQL editor tab Wydrukuj tekst z bieżącej karty edytora SQL Open a dialog for printing the text in the current SQL editor tab Otwiera okno dialogowe do drukowania tekstu w bieżącej karcie edytora SQL Print the structure of the opened database Wydrukuj ukÅ‚ad bieżącej bazy danych Open a dialog for printing the structure of the opened database Otwiera okno do drukowania ukÅ‚adu bieżącej bazy danych &Recently opened Ostatnio otwie&rane &Database Structure This has to be equal to the tab title in all the main tabs UkÅ‚ad bazy &danych &Browse Data This has to be equal to the tab title in all the main tabs Prze&glÄ…daj dane Edit P&ragmas This has to be equal to the tab title in all the main tabs Edytuj p&ragmy E&xecute SQL This has to be equal to the tab title in all the main tabs W&ykonaj SQL &Recent Files Os&tatnie pliki &New Database &Nowa baza danych &Undo &Cofnij Undo last change to the database Wycofaj ostatniÄ… zmianÄ™ w bazie danych This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. To dziaÅ‚anie wycofuje ostatniÄ… zmianÄ™ dokonanÄ… w bazie danych w PrzeglÄ…darce Bazy Danych lub poprzez Wykonanie Polecenia SQL. Ponowienie tego dziaÅ‚ania jest niemożliwe. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Otwiera pomocnika Zmiany Tabeli, gdzie można zmienić nazwÄ™ istniejÄ…cej tabeli. Można także dodawać i usuwać pola z tabeli, a także zmieniać nazwy oraz rodzaje pól. This button opens a new tab for the SQL editor Ten przycisk otwiera nowÄ… tabelÄ™ w edytorze SQL &Execute SQL &Wykonaj polecenie SQL Execute all/selected SQL Wykonaj wszystkie/zaznaczone SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Ten przycisk wykona obecnie zaznaczone polecenia SQL. JeÅ›li nie zaznaczone tekstu, to zostanÄ… wykonane wszystkie polecenia SQL. Ctrl+Shift+T Ctrl+Shift+T Save SQL file Zapisz plik SQL Execute current line Wykonaj bieżący wiersz This button executes the SQL statement present in the current editor line Ten przycisk wykonuje polecenie SQL z obecnego wiersza edytora Shift+F5 Shift+F5 Export as CSV file Wyeksportuj do pliku CSV Export table as comma separated values file Wyeksportuj tabelÄ™ jako plik z wartoÅ›ciami oddzielonymi przecinkami Sa&ve Project &Zapisz projekt &Save Project Zapi&sz projekt Save the current session to a file Zapisz obecnÄ… sesjÄ™ do pliku Open &Project Otwórz &projekt Load a working session from a file Wczytaj otoczenie pracy z pliku Add another database file to the current database connection Dodaj kolejny plik bazy danych do połączenia bieżącej bazy danych This button lets you add another database file to the current database connection Ten przycisk umożliwia dodanie kolejnego pliku bazy danych do połączenia bieżącej bazy danych Save SQL file as Zapisz plik SQL jako &Browse Table &PrzeglÄ…daj tabelÄ™ Copy Create statement Skopiuj polecenie tworzÄ…ce Copy the CREATE statement of the item to the clipboard Skopiuj polecenie CREATE elementu do schowka Opens the SQLCipher FAQ in a browser window Otwiera FAQ SQLCipher w oknie przeglÄ…darki Table(&s) to JSON... Tabele do pliku J&SON… Export one or more table(s) to a JSON file Wyeksportuj jednÄ… lub wiÄ™cej tabel do pliku JSON Open Data&base Read Only... Otwórz &bazÄ™ danych tylko do odczytu… Open an existing database file in read only mode Otwórz istniejÄ…cy plik bazy danych w trybie tylko do odczytu Save results Zapisz wyniki Save the results view Zapisuje widok wyniku This button lets you save the results of the last executed query Ten przycisk umożliwia zapisanie wyników ostatnio wykonanego zapytania Find text in SQL editor Znajdź tekst w edytorze SQL Find Znajdź This button opens the search bar of the editor Ten przycisk otwiera pasek wyszukiwania edytora Ctrl+F Ctrl+F Find or replace text in SQL editor Znajdź lub zastÄ…p tekst w edytorze SQL Find or replace Znajdź i zastÄ…p This button opens the find/replace dialog for the current editor tab Ten przycisk otwiera okno dialogowe znajdowania/zastÄ™powania dla bieżącej karty edytora Ctrl+H Ctrl+H Export to &CSV Wyeksportuj do &CSV Export to &JSON Wyeksportuj do &JSON Save as &view Zapisz jako &widok Save as view Zapisz jako widok Shows or hides the Project toolbar. Pokazuje lub ukrywa pasek narzÄ™dzi Projekt. Extra DB Toolbar Dodatkowy pasek narzÄ™dzi bazy danych Ctrl+Shift+W Ctrl+Shift+W Table from CSV data in Clipboard... Tabela z danych CSV ze schowka... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Traktuje to bieżącÄ… zawartość schowka jako plik CSV i otwiera tego samego pomocnika importowania, co w przypadku importowania danych CSV z pliku. Show &Row Counts Pokaż licznik wie&rszy This shows the number of rows for each table and view in the database. Pokazuje to liczbÄ™ wierszy dla każdej tabeli i wodku w bazie danych. Save Database &As... Z&apisz bazÄ™ danych jako... Save the current database as a different file Zapisz bieżącÄ… bazÄ™ danych do innego pliku Refresh OdÅ›wież Reload the database structure Wczytaj ponownie strukturÄ™ bazy danych Ctrl+Return Ctrl+Enter Ctrl+L Ctrl+L Ctrl+P Ctrl+P Ctrl+D Ctrl+D Ctrl+I Ctrl+I Ctrl+E Ctrl+E Reset Window Layout Wyzeruj ukÅ‚ad okien The database is currently busy. Baza danych jest obecnie zajÄ™ta. Click here to interrupt the currently running query. NaciÅ›nij tutaj, aby przerwać wykonywanie bieżącego zapytania. Encrypted Szyfrowana Database is encrypted using SQLCipher Baza danych jest zaszyfrowana z użyciem SQLCipher Read only Tylko do odczytu Database file is read only. Editing the database is disabled. Plik bazy danych jest tylko do odczytu. Edytowanie bazy danych jest wyłączone. Database encoding Kodowanie bazy danych Choose a database file Wybierz plik bazy danych Could not open database file. Reason: %1 Nie można otworzyć pliku bazy danych. Powód: %1 Choose a filename to save under Wybierz nazwÄ™ pliku do zapisu Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Ustawianie wartoÅ›ci PRAGMA lub odkurzanie spowoduje wdrożenie twoich zmian z bieżącej transakcji. Czy na pewno? In-Memory database Baza danych w-pamiÄ™ci Automatically load the last opened DB file at startup Ctrl+Alt+0 Ctrl+Alt+0 Ctrl+Alt+W Ctrl+Alt+W Choose a database file to save under Wybierz plik, do którego zapisać bazÄ™ danych Error while saving the database to the new file. Napotkano błąd podczas zapisywania bazy danych do nowego pliku. Do you want to save the changes made to the project file '%1'? Czy chcesz zapisać zmiany wprowadzone w plik projektu '%1'? Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Czy na pewno usunąć tabelÄ™ '%1'? Wszystkie dane skojarzone z tÄ… tabelÄ… zostanÄ… utracone. Are you sure you want to delete the view '%1'? Czy na pewno usunąć widok '%1'? Are you sure you want to delete the trigger '%1'? Czy na pewno usunąć wyzwalacz '%1'? Are you sure you want to delete the index '%1'? Czy na pewno usunąć indeks '%1'? Error: could not delete the table. Błąd: nie można usunąć bazy danych. Error: could not delete the view. Błąd: nie można usunąć widoku. Error: could not delete the trigger. Błąd: nie można usunąć wyzwalacza. Error: could not delete the index. Błąd: nie można usunąć indeksu. Message from database engine: %1 Wiadomość z silnika bazy danych: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Zmiana tabeli wymaga zapisania wszystkich oczekujÄ…cych zmian. Czy na pewno zapisać bazÄ™ danych? Error checking foreign keys after table modification. The changes will be reverted. Błąd sprawdzania kluczy obcych po zmianie tabeli. Zmiany zostanÄ… wycofane. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Tabela nie przeszÅ‚a sprawdzenia klucza obcego.<br/>Należy wykonać 'NarzÄ™dzia | Sprawdzenie obcego klucza' i naprawić zgÅ‚oszone kÅ‚opoty. Edit View %1 Edytuj widok %1 Edit Trigger %1 Edytuj wyzwalacz %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. Już wykonujesz polecenia SQL. Czy zatrzymać je, aby wykonać bieżące polecenia? DziaÅ‚anie to może spowodować niespójność w bazie danych. -- EXECUTING SELECTION IN '%1' -- -- WYKONYWANIE ZAZNACZENIA W '%1' -- -- EXECUTING LINE IN '%1' -- -- WYKONYWANIE WIERSZA W '%1' -- -- EXECUTING ALL IN '%1' -- -- WYKONYWANIE WSZYSTKIEGO W '%1' -- At line %1: W wierszu %1: Result: %1 Wynik: %1 Result: %2 Wynik: %2 %1 rows returned in %2ms Zwrócono %1 wierszy w czasie %2ms Choose text files Wybierz pliki tekstowe Opened '%1' in read-only mode from recent file list Otworzono '%1' w trybie tylko do odczytu ze spisu ostatnich plików Opened '%1' from recent file list Otwarto '%1' ze spisu ostatnich plików Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Wybierz dziaÅ‚anie dla upuszczonego pliku. <br/>Uwaga: tylko 'Import' przetworzy wiÄ™cej niż jeden plik. Wybierz dziaÅ‚anie dla upuszczonych %n plików. <br/>Uwaga: tylko 'Import' przetworzy wiÄ™cej niż jeden plik. Wybierz dziaÅ‚anie dla upuszczonych %n plików. <br/>Uwaga: tylko 'Import' przetworzy wiÄ™cej niż jeden plik. The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? Polecenia na karcie '%1' nadal sÄ… wykonywane. ZamkniÄ™cie tej karty przerwie ich wykonywanie. Może to pozostawić bazÄ™ danych w niespójnym stanie. Czy na pewno zamknąć tÄ™ kartÄ™? DB file '%1' could not be opened Nie można otworzyć pliku BD '%1' This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Projekt ten używa starego formatu pliku, bo zostaÅ‚ stworzony w PrzeglÄ…darce BD w wersji 3.10 lub wczeÅ›niejszej. Wczytywanie takich formatów plików nie jest już obsÅ‚ugiwane. JeÅ›li chcesz go wczytać caÅ‚kowicie, to użyj PrzeglÄ…darki BD w wersji 3.12 i przekształć go na nowy format pliku. Table '%1' not found; settings ignored Nie można byÅ‚o odnaleźć tabeli '%1'; pominiÄ™to ustawienia -- Reference to file "%1" (not supported by this version) -- -- Odniesienie do pliku "%1" (nieobsÅ‚ugiwane w tej wersji) -- Project saved to file '%1' Projekt zapisano do pliku '%1' Yes. Don't ask again Tak. Nie pytaj This action will open a new SQL tab with the following statements for you to edit and run: DziaÅ‚anie to otworzy nowÄ… kartÄ™ SQL z nastÄ™pujÄ…cymi poleceniami, które możesz dostosować i wykonać: Rename Tab Przemianuj kartÄ™ Duplicate Tab Powiel kartÄ™ Close Tab Zamknij kartÄ™ Opening '%1'... Otwieranie '%1'... There was an error opening '%1'... Błąd otwierania '%1'... Value is not a valid URL or filename: %1 Wartość nie jest prawidÅ‚owym adresem URL lub nazwÄ… pliku: %1 Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Nie można zapisać bazy danych. Oznacza to, że nie wszystkie zmiany daÅ‚o siÄ™ zapisać w bazie danych. Najpierw trzeba pozbyć siÄ™ nastÄ™pujÄ…cych kÅ‚opotów. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? Czy na pewno wycofać wszystkie zmiany wprowadzone w pliku bazy danych '%1' od czasu ostatniego zapisu? Choose a file to import Wybierz pliki do zaimportowania &%1 %2%3 &%1 %2%3 (read only) (tylko do odczytu) Open Database or Project Otwórz bazÄ™ danych lub projekt Attach Database... Dołącz bazÄ™ danych... Import CSV file(s)... Zaimportuj plik(i) CSV... Do you want to save the changes made to SQL tabs in the project file '%1'? Czy chcesz zapisać zmiany wprowadzone w tabelach SQL do pliku projektu '%1'? Text files(*.sql *.txt);;All files(*) Pliki tekstowe(*.sql *.txt);;Wszystkie pliki(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Czy utworzyć plik nowej bazy danych do przechowania zaimportowanych danych? JeÅ›li nie, to dane zostanÄ… zaimportowane do pliku bieżącej bazy danych. Ctrl+Tab Ctrl+Tab Ctrl+Shift+Tab Ctrl+Shift+Tab Clear List Wyczyść spis Window Layout UkÅ‚ad okna Simplify Window Layout Uprość ukÅ‚ad okien Alt+Shift+0 Alt+Shift+0 Dock Windows at Bottom Zadokuj okna na dole Dock Windows at Left Side Zadokuj okna po lewej stronie Dock Windows at Top Zadokuj okna na górze You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Nadal wykonujesz polecenia SQL. Wykonywanie tych poleceÅ„ zostanie zatrzymane, po zamkniÄ™ciu bazy danych, co może spowodować w niej niespójnoÅ›ci. Czy na pewno zamknąć tÄ™ bazÄ™ danych? File %1 already exists. Please choose a different name. Plik %1 już istnieje. Wybierz innÄ… nazwÄ™. Error importing data: %1 Błąd importowania danych: %1 Import completed. Some foreign key constraints are violated. Please fix them before saving. UkoÅ„czono import. NastÄ…piÅ‚o przekroczenie niektórych z ograniczeÅ„ obcego klucza. Napraw je przed zapisaniem. Import completed. Importowanie zakoÅ„czone. Delete View UsuÅ„ widok Modify View ZmieÅ„ widok Delete Trigger UsuÅ„ wyzwalacz Modify Trigger ZmieÅ„ wyzwalacz Delete Index UsuÅ„ indeks Modify Index ZmieÅ„ indeks Modify Table Dostosuj tabelÄ™ Setting PRAGMA values will commit your current transaction. Are you sure? Ustawianie wartoÅ›ci PRAGMA spowoduje wdrożenie twoich zmian z bieżącej transakcji. Czy na pewno? Select SQL file to open Wybierz plik SQL do otworzenia Select file name Wybierz nazwÄ™ pliku Select extension file Wybierz plik rozszerzenia Execution finished with errors. Wykonano z błędami. Execution finished without errors. Wykonano bez błędów. Do you want to save the changes made to SQL tabs in a new project file? Czy chcesz zapisać zmiany wprowadzone w tabelach SQL do nowego pliku projektu? Do you want to save the changes made to the SQL file %1? Czy chcesz zapisać zmiany wprowadzone w SQL do pliku %1? Extension successfully loaded. PomyÅ›lnie wczytano rozszerzenie. Error loading extension: %1 Nie można wczytać rozszerzenia: %1 Could not find resource file: %1 Nie można znaleźć pliku zasobów: %1 Don't show again Nie pokazuj ponownie New version available. Nowa wersja jest dostÄ™pna. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. DostÄ™pna jest nowa wersja PrzeglÄ…darki SQLite (%1.%2.%3).<br/><br/>Pobierz z <a href='%4'>%4</a>. Choose a project file to open Wybierz plik projektu do otworzenia DB Browser for SQLite project file (*.sqbpro) Plik projektu PrzeglÄ…darki SQLite (*.sqbpro) Could not open project file for writing. Reason: %1 Nie można otworzyć pliku projektu do zapisu. Powód: %1 Collation needed! Proceed? Potrzebne zestawianie! PostÄ…pić naprzód? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Tabela w tej bazie danych wymaga wyjÄ…tkowej funkcji zestawienia '%1' której ta aplikacja nie może dostarczyć bez dalszej wiedzy. PójÅ›cia z tym dalej, może spowodować uszkodzenia w bazie danych. Stwórz kopiÄ™ zapasowÄ…! creating collation tworzenie zestawienia Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Przemianowuje kartÄ™ SQL. Wstaw znaku '&&' aby móc wykorzystać nastÄ™pujÄ…cy po nim znak jako skrót klawiszowy. Please specify the view name OkreÅ›l nazwÄ™ widoku There is already an object with that name. Please choose a different name. Istnieje już obiekt o tej nazwie. Nadaj innÄ… nazwÄ™. View successfully created. PomyÅ›lnie utworzono widok. Error creating view: %1 Błąd tworzenia widoku: %1 This action will open a new SQL tab for running: To dziaÅ‚anie otworzy nowÄ… kartÄ™ SQL aby wykonać: Press Help for opening the corresponding SQLite reference page. NaciÅ›nij Pomoc, aby otworzyć powiÄ…zanÄ… stronÄ™ w podrÄ™czniku SQLite. Busy (%1) ZajÄ™ty (%1) NullLineEdit Set to NULL Ustaw na NULL Alt+Del Alt+Del PlotDock Plot Wykres <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Ten panel pokazuje listÄ™ kolumn obecnie przeglÄ…danej tabeli lub tylko dla wykonanego zapytania. Możesz wybrać kolumny, których chcesz użyć dla osi X lub Y dla panelu wykresu poniżej. Tabela pokaże wykryty rodzaj osi, który wpÅ‚ynie na wynikowy wykres. Dla osi Y możesz wybrać kolumny tylko liczbowe, a dla osi X możesz wybrać:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data/Czas</span>: Å‚aÅ„cuchy formatujÄ…ce &quot;yyyy-MM-dd hh:mm:ss&quot; lub &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data</span>: Å‚aÅ„cuchy formatujÄ…ce &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Czas</span>: Å‚aÅ„cuchy formatujÄ…ce &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Etykieta</span>: formatowanie innymi Å‚aÅ„cuchami. Zaznaczenie tej kolumny jako osi X stworzy wykres sÅ‚upkowy, gdzie wartoÅ›ci kolumn bÄ™dÄ… etykietami dla sÅ‚upków</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Liczba</span>: wartoÅ›ci caÅ‚kowite lub rzeczywiste</li></ul><p>Dwukrotne klikniÄ™cie na komórkach Y zmieni barwÄ™ użytÄ… dla wykresu.</p></body></html> Columns Kolumny X X Y1 Y1 Y2 Y2 Axis Type Rodzaj osi Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Tutaj rysowany jest wykres po wybraniu wartoÅ›ci x oraz y powyżej. Aby zaznaczyć punkt na wykresie i w tabeli, należy kliknąć na niego. Ctrl+Klik aby zaznaczyć zakres punktów. Aby zmienić zakres osi, należy kliknąć i przeciÄ…gnąć myszÄ…. Aby powiÄ™kszyć należy przewinąć rolkÄ… myszy. Aby przeciÄ…gnąć i powiÄ™kszyć tylko w jednÄ… stronÄ™, należy wybrać osie lub etykiety osi. Line type: Rodzaj linii: None Brak Line Linia StepLeft Krok w lewo StepRight Krok w prawo StepCenter Krok do Å›rodka Impulse Impuls Point shape: KsztaÅ‚t punktu: Cross Krzyż Plus Plus Circle Kółko Disc Dysk Square Kwadrat Diamond Diament Star Gwiazda Triangle TrójkÄ…t TriangleInverted TrójkÄ…t odwrócony CrossSquare Krzyż w kwadracie PlusSquare Plus w kwadracie CrossCircle Krzyż w okrÄ™gu PlusCircle Plus w okrÄ™gu Peace Znak pokoju <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Zapisz bieżący wykres...</p><p>Format pliku wybierany na podstawie rozszerzenia (png, jpg, pdf, bmp)</p></body></html> Save current plot... Zapisz bieżący wykres… Load all data and redraw plot Wczytaj wszystkie dane i przerysuj wykres Copy Skopiuj Print... Wydrukuj... Show legend Pokaż legendÄ™ Stacked bars SÅ‚upki na stosie Fixed number format Format staÅ‚ej liczby Date/Time Data/Czas Date Data Time Czas Numeric Liczbowa Label Podpis Invalid NieprawidÅ‚owy Row # Nr wiersza Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Wczytaj wszystkie dane i przerysuj wykres. Uwaga: jeszcze nie wczytano wszystkich danych z tabeli ze wzglÄ™du na mechanizm częściowego wczytywania. Choose an axis color Wybierz barwÄ™ osi Choose a filename to save under Wybierz nazwÄ™ pliku do zapisu PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Wszystkie pliki(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. W tym wykresie wystÄ™pujÄ… krzywe, a wybrany wyglÄ…d linii można zastosować tylko dla wykresów uszeregowanych po X. Uszereguj tabelÄ™ lub zapytaj po X, aby usunąć krzywe lub wybierz jeden z wyglÄ…dów obsÅ‚ugiwanych przez krzywe: Brak lub Linia. Loading all remaining data for this table took %1ms. Wczytywanie wszystkich pozostaÅ‚ych danych dla tej tabeli zajęło %1ms. PreferencesDialog Preferences Ustawienia &General O&gólne Default &location DomyÅ›&lne poÅ‚ożenie Remember last location PamiÄ™taj ostatnie poÅ‚ożenie Always use this location Zawsze używaj poniższego poÅ‚ożenia Remember last location for session only Zapomnij ostatnie poÅ‚ożenie, dopiero po zamkniÄ™ciu programu ... … Lan&guage &JÄ™zyk Toolbar style WyglÄ…d paska narzÄ™dzi Only display the icon WyÅ›wietl tylko ikonÄ™ Only display the text WyÅ›wietl tylko tekst The text appears beside the icon Tekst obok ikony The text appears under the icon Tekst pod ikonÄ… Follow the style DomyÅ›lnie dla wyglÄ…du Show remote options Pokaż ustawienia zdalnych BD enabled włączone Automatic &updates Sam &uaktualniaj DB file extensions Rozszerzenia plików bazy danych Manage ZarzÄ…dzaj Main Window Główne okno Database Structure UkÅ‚ad bazy danych Browse Data PrzeglÄ…darka danych Execute SQL Wykonaj polecenie SQL Edit Database Cell Zmiana komórki bazy danych When this value is changed, all the other color preferences are also set to matching colors. Po zmianie tej wartoÅ›ci, wszystkie inne ustawienia barw zostanÄ… także ustawione na pasujÄ…ce barwy. Follow the desktop style Zgodny z systemem Dark style Ciemny Light style Jasny Application style WyglÄ…d programu This sets the font size for all UI elements which do not have their own font size option. Ustawia to rozmiar czcionki dla wszystkich elementów interfejsu, które nie majÄ… swojego wÅ‚asnego ustawienia czcionki. Font size Rozmiar czcionki Max Recent Files Liczba ostatnich plików Prompt to save SQL tabs in new project file Zapytaj o zapisanie kart SQL w pliku nowego projektu If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Po włączeniu tego, zmiany w edytorze SQL wywoÅ‚ujÄ… okno, pytajÄ…ce o zapisanie projektu, przed zamkniÄ™ciem karty edytora SQL. &Database Baza &danych Database &encoding Kodowani&e bazy danych Open databases with foreign keys enabled. Otwiera bazy danych z włączonymi kluczami obcymi. &Foreign keys &Obce klucze Remove line breaks in schema &view UsuÅ„ podziaÅ‚y wierszy w &widoku schematu When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Po zaznaczeniu, usuwany jest znak Å‚amania wiersza w kolumnie schematu karty ukÅ‚adu bazy danych, doku oraz drukowanym wyniku. Formatted Sformatowane Use tabs for indentation Wcinaj tabulatorami When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. Po zaznaczeniu, klawisz Tab bÄ™dzie wstawiaÅ‚ znaki tabulatora oraz odstÄ™pu do wykonania wciÄ™cia. W przeciwnym przypadku bÄ™dÄ… używane tylko znaki odstÄ™pu. Select built-in extensions to load for every database: Export Settings Wyeksportuj ustawienia Import Settings Zaimportuj ustawienia Prefetch block si&ze Ro&zmiar obszaru wczytanego z wyprzedzeniem SQ&L to execute after opening database SQ&L do wykonania po otworzeniu bazy danych Default field type DomyÅ›lny rodzaj pola Data &Browser &PrzeglÄ…darka danych Font Czcionka &Font &Czcionka Font si&ze Ro&zmiar czcionki Content Zawartość Symbol limit in cell Graniczna liczba znaków w komórce This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Jest to graniczna liczba elementów, która jest dozwolona dla niektórych obliczeniowo pracochÅ‚onnych dziaÅ‚aÅ„: Graniczna liczba wierszy w tabeli do włączenia uzupeÅ‚niania wartoÅ›ci na podstawie bieżących wartoÅ›ci w kolumnie. Graniczna liczba indeksów w zaznaczeniu do obliczenia sumy i Å›redniej. Można ustawić na 0, aby wyłączyć wszystkie te dziaÅ‚ania. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Jest to graniczna liczba wierszy w tabeli do włączenia uzupeÅ‚niania wartoÅ›ci na podstawie wartoÅ›ci znajdujÄ…cych siÄ™ już w kolumnie. Można ustawić na 0, aby wyłączyć uzupeÅ‚nianie. Close button on tabs Przycisk zamykania na kartach If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Po włączeniu, karty edytora SQL bÄ™dÄ… zawierać przyciski zamykania. W pozostaÅ‚ych przypadkach, bÄ™dziesz musiaÅ‚ użyć menu podrÄ™cznego lub skrótu klawiszowego do ich zamykania. Proxy PoÅ›rednik Configure Ustawienia Field display WyÅ›wietlanie pola Displayed &text WyÅ›wietlany &tekst Binary Dane dwójkowe NULL WartoÅ›ci NULL Regular ZwykÅ‚e dane Click to set this color NaciÅ›nij, aby ustawić tÄ™ barwÄ™ Text color Barwa tekstu Background color Barwa tÅ‚a Preview only (N/A) Tylko do podglÄ…du (ND) Filters Filtry Escape character Znak sterujÄ…cy Delay time (&ms) Czas opóźnienia (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Ustaw czas oczekiwania przed zastosowaniem nowej wartoÅ›ci filtra. Może być ustawiony na 0, aby wyłączyć oczekiwanie. &SQL &SQL Context WystÄ™powanie Colour Barwa Bold Pogrubienie Italic Pochylenie Underline PodkreÅ›lenie Keyword SÅ‚owo kluczowe Function Funkcja Table Tabela Comment Uwaga Identifier Identyfikator String CiÄ…g znaków Current line Bieżący wiersz Background TÅ‚o Foreground Pierwszy plan Selection background Drugi plan zaznaczenia Selection foreground Pierwszy plan zaznaczenia Highlight PodÅ›wietlenie SQL &editor font size Rozmiar czcionki &edytora SQL SQL &results font size &Rozmiar czcionki wyników SQL Tab size Rozmiar tabulatora SQL editor &font &Czcionka edytora SQL Database structure font size Rozmiar czcionki ukÅ‚adu bazy danych Threshold for completion and calculation on selection UzupeÅ‚niaj i obliczaj do tej liczby wierszy Show images in cell Pokaż obrazy w komórce Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Włącz to, aby pokazać podglÄ…d obiektów BLOB zawierajÄ…cych dane obrazów w komórkach. Może to jednak wpÅ‚ynąć na wydajność przeglÄ…darki danych. &Wrap lines Za&wijaj wiersze &Quotes for identifiers &CudzysÅ‚owy dla identyfikatorów Choose the quoting mechanism used by the application for identifiers in SQL code. Wybierz zapis cudzysÅ‚owów stosowany w aplikacji do identyfikatorów w kodzie SQL. "Double quotes" - Standard SQL (recommended) "Podwójne cudzysÅ‚owy" - Standard SQL (zalecane) `Grave accents` - Traditional MySQL quotes `Pojedyncze cudzysÅ‚owy` - Tradycyjne cudzysÅ‚owy MySQL [Square brackets] - Traditional MS SQL Server quotes [Nawiasy kwadratowe] - Tradycyjne cudzysÅ‚owy MS SQL Server Code co&mpletion UzupeÅ‚nianie &kodu Keywords in &UPPER CASE SÅ‚owa kl&uczowe WIELKIMI LITERAMI When set, the SQL keywords are completed in UPPER CASE letters. Po zaznaczeniu, polecenia SQL sÄ… uzupeÅ‚niane wielkimi literami. Error indicators Wskaźniki błędów When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Po zaznaczeniu, wiersze kodu SQL, które powodowaÅ‚y błędy podczas ostatniego wykonywania, sÄ… podÅ›wietlana, a okno wyniku pokazuje błąd w tle Hori&zontal tiling Kafelki w po&ziomie If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Po zaznaczeniu, edytor kodu SQL oraz widok tabeli wynikowej bÄ™dÄ… wyÅ›wietlane obok siebie zamiast jedno nad drugim. Never Nigdy At word boundaries Na granicach słów At character boundaries Na granicach znaków At whitespace boundaries Na granicach biaÅ‚ych znaków &Extensions Rozsz&erzenia Select extensions to load for every database: Wybierz rozszerzenia wczytywane dla każdej bazy danych: Add extension Dodaj rozszerzenie Remove extension UsuÅ„ rozszerzenie <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>Mimo obsÅ‚ugi polecenia REGEXP, SQLite nie implementuje żadnego z algorytmu wyrażeÅ„ regularnych<br/>lecz zwraca siÄ™ z powrotem do aplikacji, która je uruchomiÅ‚a. PrzeglÄ…darka SQLite implementuje ten<br/>algorytm, aby móc od razu korzystać z REGEXP. Jednakże, ze wzglÄ™du na to, że istnieje wiele możliwych<br/>implementacji wyrażeÅ„ regularnych, to można wyłączyć ten wbudowany<br/>i wczytać swój wÅ‚asny. Wymaga to jednak ponownego uruchomienia aplikacji.</p></body></html> Disable Regular Expression extension Wyłącz rozszerzenie wyrażeÅ„ regularnych <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite dostarcza funkcjÄ™ SQL do wczytywania rozszerzeÅ„ z pliku biblioteki współdzielonej. Zaznacz to, aby używać funkcji <span style=" font-style:italic;">load_extension()</span> z kodu SQL.</p><p>Ze wzglÄ™du na bezpieczeÅ„stwo, wczytywanie rozszerzeÅ„ jest domyÅ›lnie wyłączone i musi zostać włączone przez to ustawienie. Zawsze można wczytywać rozszerzenia przez interfejs użytkownika, nawet gdy pole to jest odznaczone.</p></body></html> Allow loading extensions from SQL code Zezwól na wczytywanie rozszerzeÅ„ z kodu SQL Remote Zdalne BD CA certificates Certyfikaty UC Subject CN NP podmiotu Common Name Nazwa powszechna Subject O O podmiotu Organization Organizacja Valid from Ważny od Valid to Ważny do Serial number Numer seryjny Your certificates Twoje certyfikaty File Plik Subject Common Name Nazwa powszechna podmiotu Issuer CN NP wydawcy Issuer Common Name Nazwa powszechna wydawcy Clone databases into Pobieraj bazy danych do Choose a directory Wybierz katalog The language will change after you restart the application. JÄ™zyk zmieni siÄ™ po ponownym uruchomieniu aplikacji. Select extension file Wybierz plik rozszerzenia Extensions(*.so *.dylib *.dll);;All files(*) Rozszerzenia(*.so *.dylib *.dll);;Wszystkie pliki(*) Import certificate file Zaimportuj plik certyfikatu No certificates found in this file. Nie znaleziono certyfikatów w tym pliku. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Czy na pewno usunąć ten certyfikat? Wszystkie dane certyfikatu zostanÄ… usuniÄ™te z ustawieÅ„ aplikacji! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Czy na pewno wyczyÅ›cić wszystkie zapisane ustawienia? Wszystkie zapisane ustawienia zostanÄ… utracone i zastÄ…pione domyÅ›lnymi. Save Settings File Zapisz plik ustawieÅ„ Initialization File (*.ini) Plik przygotowujÄ…cy (*.ini) The settings file has been saved in location : Zapisano plik ustawieÅ„ w miejscu : Open Settings File Otwórz plik ustawieÅ„ The settings file was loaded properly. PomyÅ›lnie wczytano plik ustawieÅ„. The selected settings file is not a normal settings file. Please check again. Wybrany plik ustawieÅ„ nie jest zwykÅ‚ym plikiem ustawieÅ„. Sprawdź go ponownie. ProxyDialog Proxy Configuration Ustawienia proxy Pro&xy Type &Rodzaj poÅ›rednika Host Na&me Nazwa &gospodarza Port Port Authentication Re&quired &Wymagane uwierzytelnienie &User Name Nazwa &użytkownika Password HasÅ‚o None Brak System settings Ustawienia systemowe HTTP HTTP SOCKS5 SOCKS5 QObject All files (*) Wszystkie pliki (*) Error importing data Błąd importowania danych from record number %1 z rekordu o numerze %1 . %1 . %1 Importing CSV file... Importowanie pliku CSV… Cancel Zaniechaj SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Pliki bazy danych SQLite (*.db *.sqlite *.sqlite3 *.db3) Left Do lewej Right Do prawej Center Do Å›rodka Justify Wyjustuj SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) Pliki bazy danych SQLite (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) PrzeglÄ…darka BD dla plików projektu SQLite (*.sqbpro) SQL Files (*.sql) Pliki SQL (*.sql) All Files (*) Wszystkie pliki (*) Text Files (*.txt) Pliki tekstowe (*.txt) Comma-Separated Values Files (*.csv) Pliki z wartoÅ›ciami oddzielonymi przecinkiem (*.csv) Tab-Separated Values Files (*.tsv) Pliki z wartoÅ›ciami oddzielonymi tabulatorem (*.tsv) Delimiter-Separated Values Files (*.dsv) Pliki z wartoÅ›ciami oddzielonymi rozdzielaczem (*.dsv) Concordance DAT files (*.dat) Pliki Concordance DAT (*.dat) JSON Files (*.json *.js) Pliki JSON (*.json *.js) XML Files (*.xml) Pliki XML (*.xml) Binary Files (*.bin *.dat) Pliki dwójkowe (*.bin *.dat) SVG Files (*.svg) Pliki SVG (*.svg) Hex Dump Files (*.dat *.bin) Pliki zrzutu szesnastkowego (*.dat *.bin) Extensions (*.so *.dylib *.dll) Rozszerzenia (*.so *.dylib *.dll) Initialization File (*.ini) Plik przygotowujÄ…cy (*.ini) QsciCommand Paste Wklej Cancel Zaniechaj QsciLexerCPP Keyword SÅ‚owo kluczowe Identifier Identyfikator QsciLexerJSON String CiÄ…g znaków QsciLexerJavaScript Regular expression Wyrażenie regularne QsciLexerPython Comment Uwaga Keyword SÅ‚owo kluczowe Identifier Identyfikator QsciLexerSQL Comment Uwaga Keyword SÅ‚owo kluczowe Identifier Identyfikator QsciScintilla &Undo &Cofnij Select All Zaznacz wszystkie RemoteCommitsModel Commit ID ID zmiany Message Wiadomość Date Data Author Autor Size Rozmiar Authored and committed by %1 NapisaÅ‚ i wdrożyÅ‚ %1 Authored by %1, committed by %2 NapisaÅ‚ %1, wdrożyÅ‚ %2 RemoteDatabase Error opening local databases list. %1 Nie można otworzyć wykazu lokalnych baz danych. %1 Error creating local databases list. %1 Nie można utworzyć wykazu lokalnych baz danych. %1 RemoteDock Remote Zdalne BD Identity Tożsamość Push currently opened database to server Wypchnij bieżącÄ… bazÄ™ danych na serwer Upload WyÅ›lij DBHub.io DBHub.io Local Miejscowa Current Database Bieżąca baza danych Clone Powiel Branch Gałąź Commits Zmiany Commits for Zmiany dla Delete Database UsuÅ„ bazÄ™ danych Delete the local clone of this database UsuÅ„ miejscowÄ… kopiÄ™ tej bazy danych Open in Web Browser Otwórz w przeglÄ…darce sieciowej Open the web page for the current database in your browser Otwórz stronÄ™ sieciowÄ… bieżącej bazy danych w swojej przeglÄ…darce Clone from Link Powiel z odnoÅ›nika Use this to download a remote database for local editing using a URL as provided on the web page of the database. Użyj tego, aby pobrać zdalnÄ… bazÄ™ danych do miejscowego edytowania przy użyciu adresu URL podanego na stronie sieciowej bazy danych. Refresh OdÅ›wież Reload all data and update the views Wczytaj ponownie wszystkie dane i uaktualnij widoki Clone Database Powiel bazÄ™ danych Open Database Otwórz bazÄ™ danych Open the local copy of this database Otwórz miejscowÄ… kopiÄ™ bazy danych Check out Commit Ustaw na zmianie Download and open this specific commit Pobierz i otwórz danÄ… zmianÄ™ Check out Latest Commit Sprawdź ostatnie zmiany Check out the latest commit of the current branch Sprawdź ostatniÄ… zmianÄ™ w bieżącej gałęzi Save Revision to File Zapisz wersjÄ™ do pliku Saves the selected revision of the database to another file Zapisuje wybranÄ… wersjÄ™ bazy danych do innego pliku Upload Database WyÅ›lij bazÄ™ danych Upload this database as a new commit WyÅ›lij tÄ™ bazÄ™ danych jako nowÄ… zmianÄ™ <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>Obecnie używasz wbudowanej tożsamoÅ›ci, która jest tylko do odczytu. Aby wysÅ‚ać bazÄ™ danych musisz posÅ‚użyć siÄ™ kontem z DBHub.io.</p><p>Nie masz jeszcze konta DBHub.io? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Utwórz je teraz</span></a> i zaimportuj swój certyfikat<a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">tutaj</span></a>, aby móc dzielić siÄ™ swoimi bazami danych.</p><p>Aby uzyskać pomoc w sieci, zajrzyj <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">tutaj</span></a>.</p></body></html> <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>W tym panelu można dodać zdalne bazy danych ze strony sieciowej dbhub.io do PrzeglÄ…darki Baz Danych SQLite. Jednak najpierw potrzebujesz swojej tożsamoÅ›ci:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wejdź na stronÄ™ sieciowÄ… dbhub.io (użyj swoich danych dostÄ™powych z GitHuba lub dowolnych innych)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">NaciÅ›nij przycisk &quot;Utwórz certyfikat klienta&quot; (oto i ta tożsamość, której potrzebujesz). Dostaniesz plik certyfikatu (zapisz go na swój dysk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Przejdź do karty Zdalnych w PrzeglÄ…darce Baz Danych SQLite i wskaż co dopiero pobrany plik certyfikatu.</li></ol><p>Od teraz panel Zdalnych bÄ™dzie pokazywaÅ‚ twojÄ… tożsamość, a ty bÄ™dziesz mógÅ‚ dodawać zdalne bazy danych.</p></body></html> &User &Użytkownik &Database Baza &danych Back Wstecz Select an identity to connect Wybierz tożsamość do połączenia siÄ™ Public Publiczna This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Pobiera to bazÄ™ danych ze zdalnego serwera do edytowania miejscowo. Wpisz adres URL, z którego jÄ… powielić. Możesz utworzyć taki adres URL, naciskajÄ…c na przycisk 'Powiel bazÄ™ danych w DB4S' na stronie sieciowej
 bazy danych. Invalid URL: The host name does not match the host name of the current identity. NieprawidÅ‚owy adres URL: Nazwa gospodarza nie odpowiada nazwie gospodarza bieżącej tożsamoÅ›ci. Invalid URL: No branch name specified. NieprawidÅ‚owy adres URL: Nie podano nazwy gałęzi. Invalid URL: No commit ID specified. NieprawidÅ‚owy adres URL: Nie podano ID zmiany. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? ZmieniÅ‚eÅ› miejscowÄ… bazÄ™ danych. Pobranie tych zmian zastÄ…pi zmiany miejscowe. Czy na pewno chcesz kontynuować? The database has unsaved changes. Are you sure you want to push it before saving? Baza danych posiada niezapisane zmiany. Czy na pewno chcesz wypchnąć przed zapisaniem? The database you are trying to delete is currently opened. Please close it before deleting. Baza danych, którÄ… próbujesz usunąć, jest obecnie otwarta. Zamknij jÄ… przed jej usuniÄ™ciem. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? Usuwa to miejscowÄ… wersjÄ™ tej bazy danych wraz ze wszystkimi zmianami, których jeszcze nie wysÅ‚aÅ‚eÅ›. Czy na pewno usunąć tÄ™ bazÄ™ danych? RemoteLocalFilesModel Name Nazwa Branch Gałąź Last modified Ostatnio zmieniana Size Rozmiar Commit Zmiana File Plik RemoteModel Name Nazwa Commit Wdroż Last modified Ostatnia zmiana Size Rozmiar Size: Rozmiar: Last Modified: Ostatnio zmieniania: Licence: Licencja: Default Branch: DomyÅ›lna gałąź: RemoteNetwork Choose a location to save the file Wskaż miejsce do zapisania pliku Error opening remote file at %1. %2 Nie udaÅ‚o siÄ™ otworzyć pliku zdalnego w %1. %2 Error: Invalid client certificate specified. Błąd: Podano nieprawidÅ‚owy certyfikat klienta. Please enter the passphrase for this client certificate in order to authenticate. Wpisz hasÅ‚o dla certyfikatu tego klienta, aby siÄ™ uwierzytelnić. Cancel Zaniechaj Uploading remote database to %1 WysyÅ‚anie zdalnej bazy danych do %1 Downloading remote database from %1 Pobieranie zdalnej bazy danych z %1 Error: Cannot open the file for sending. Błąd: Nie można otworzyć pliku do wysÅ‚ania. RemotePushDialog Push database Wypchnij bazÄ™ danych Database na&me to push to &Nazwa bazy danych, do której wypchnąć Commit message Opis wdrożenia Database licence Licencja bazy danych Public Publiczna Branch Gałąź Force push WymuÅ› wypchniÄ™cie Username Nazwa użytkownika Database will be public. Everyone has read access to it. Baza danych bÄ™dzie publiczna. Każdy bÄ™dzie mógÅ‚ uzyskać do niej dostÄ™p. Database will be private. Only you have access to it. Baza danych bÄ™dzie prywatna. Tylko Ty bÄ™dziesz mieć do niej dostÄ™p. Use with care. This can cause remote commits to be deleted. BÄ…dź ostrożny. Może to usunąć wdrożenia ze zdalnych miejsc. RunSql Execution aborted by user Wykonywanie przerwane przez użytkownika , %1 rows affected , dotyczyÅ‚o %1 wiersza query executed successfully. Took %1ms%2 pomyÅ›lnie wykonano zapytanie. Zajęło to %1ms%2 executing query wykonywanie zapytania SelectItemsPopup A&vailable &DostÄ™pne Sele&cted &Wybrane SqlExecutionArea Form Formularz Find previous match [Shift+F3] Znajdź poprzednie trafienie [Shift+F3] Find previous match with wrapping Znajdź poprzednie pasujÄ…ce z zawijaniem Shift+F3 Shift+F3 The found pattern must be a whole word Wzorzec do znalezienia musi być caÅ‚ym sÅ‚owem Whole Words CaÅ‚e sÅ‚owa Text pattern to find considering the checks in this frame Wzorzec tekstu do znalezienia, biorÄ…c pod uwagÄ™ pola zaznaczone w tym oknie Find in editor Znajdź w edytorze The found pattern must match in letter case Wzorzec do znalezienia musi pasować wielkoÅ›ciÄ… liter Case Sensitive Rozróżniaj wielkość znaków Find next match [Enter, F3] Znajdź nastÄ™pne trafienie [Enter, F3] Find next match with wrapping Znajdź nastÄ™pne pasujÄ…ce z zawijaniem F3 F3 Interpret search pattern as a regular expression Rozpatrz wzorzec wyszukiwania jako wyrażenie regularne <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Po zaznaczeniu, wzorzec do znalezienia jest rozważany jako wyrażenie regularne UNIX. Zajrzyj do <a href="https://en.wikibooks.org/wiki/Regular_Expressions">WyrażeÅ„ Regularnych w Wikibooks</a>.</p></body></html> Regular Expression Wyrażenie regularne Close Find Bar Zamknij pasek wyszukiwania <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>Wynik ostatnio wykonanych poleceÅ„.</p><p>Zalecamy zwiniÄ™cie tego okna i otworzenie doku <span style=" font-style:italic;">Dziennika SQL</span> z wyborem <span style=" font-style:italic;">Użytkownika</span>.</p></body></html> Results of the last executed statements Wyniki ostatnio wykonanych poleceÅ„ This field shows the results and status codes of the last executed statements. To pole pokazuje wyniki i kody wyjÅ›cia ostatnio wykonanych poleceÅ„. Ctrl+PgUp Ctrl+PgUp Ctrl+PgDown Ctrl+PgDown Couldn't read file "%1": %2. Nie można odczytać pliku "%1": %2. Couldn't save file: %1. Nie można zapisać pliku: %1. Your changes will be lost when reloading it! Utracisz swoje zmiany po ponownym wczytaniu! The file "%1" was modified by another program. Do you want to reload it?%2 Inny program zmieniÅ‚ plik "%1". Czy chcesz wczytać go ponownie?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Odpowiedz "Tak na wszystko", aby bez dalszych pytaÅ„, wczytywać ponownie plik w przypadku dowolnego jego uaktualnienia z zewnÄ…trz. Answer "No to All" to ignore any external update without further prompting. Odpowiedz "Nie dla wszystkich", aby pominąć wszelkie zewnÄ™trzne uaktualnienia bez dalszego pytania o nie. Modifying and saving the file will restore prompting. Zmiana i zapisanie pliku przywróci pytania. SqlTextEdit Ctrl+/ Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) Funkcja abs(X) zwraca wartość bezwzglÄ™dnÄ… argumentu liczbowego X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () Funkcja changes() zwraca liczbÄ™ wierszy bazy danych, które zostaÅ‚y wstawiony lub usuniÄ™te przez ostatnio ukoÅ„czone polecenie INSERT, DELETE, or UPDATE. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) Funkcja char(X1,X2,...,XN) zwraca ciÄ…g znaków skÅ‚adajÄ…cy siÄ™ ze znaków majÄ…cych wartoÅ›ci punków kodu unikod bÄ™dÄ…cych liczbami caÅ‚kowitymi w zakresie od X1 do XN, odpowiednio. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) Funkcja coalesce() zwraca kopiÄ™ swojego pierwszego argumentu nie-NULL lub NULL, jeÅ›li wszystkie argumenty sÄ… NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) Funkcja glob(X,Y) jest tożsama wyrażeniu "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) Funkcja ifnull() zwraca kopiÄ™ swojego pierwszego argumentu nie-NULL lub NULL, jeÅ›li oba argumenty sÄ… NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) Funkcja instr(X,Y) znajduje pierwsze wystÄ…pienie ciÄ…gu znaków Y wewnÄ…trz ciÄ…gu znaków X i zwraca liczbÄ™ znaków poprzedzajÄ…cych plus 1, lub 0, jeÅ›li nie można znaleźć Y w X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) Funkcja hex() interpretuje swoje argumenty jako KAWAÅKI i zwraca ciÄ…gi znaków, które sÄ… przedstawieniem szesnastkowym treÅ›ci kawaÅ‚ka, zapisanym wielkimi literami. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) Funkcja iif(X,Y,Z) zwraca wartość Y jeÅ›li X jest prawdÄ… lub Z w przeciwnym przypadku. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () Funkcja last_insert_rowid() zwraca ROWID ostatniego wstawionego wiersza z połączenia bazy danych, która wywoÅ‚aÅ‚a tÄ™ funkcjÄ™. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) Dla wartoÅ›ci ciÄ…gu znaków X, funkcja length(X) zwraca liczbÄ™ znaków (nie bajtów) w X do chwili napotkania pierwszego znaku NUL. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) Funkcja like() jest używana do implementacji wyrażenia "Y LIKE X". (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) Funkcja like() jest używana do implementacji wyrażenia "Y LIKE X ESCAPE Z". (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) Funkcja load_extension(X) wczytuje rozszerzenia SQLite z pliku biblioteki współdzielonej o nazwie X. Aby użyć tej funkcji, należy wyrazić zgodÄ™ w Ustawieniach. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) Funkcja load_extension(X) wczytuje rozszerzenia SQLite z pliku biblioteki współdzielonej o nazwie X przy użyciu punktu wejÅ›ciowego Y. Aby użyć tej funkcji, należy wyrazić zgodÄ™ w Ustawieniach. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) Funkcja lower(X) zwraca kopiÄ™ ciÄ…gu znaków X po przeksztaÅ‚ceniu wszystkich znaków ASCII na pisane maÅ‚ymi literami. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) usuwa odstÄ™py z lewej strony X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) Funkcja ltrim(X,Y) zwraca ciÄ…g znaków utworzony po usuniÄ™ciu dowolnego i wszystkich znaków, które ukazujÄ… siÄ™ w Y z lewej strony X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) Funkcja wieloargumentowa max() zwraca argument o wartoÅ›ci najwiÄ™kszej lub NULL, jeÅ›li dowolny argument jest NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) Funkcja wieloargumentowa min() zwraca argument o wartoÅ›ci najmniejszej. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) Funkcja nullif(X,Y) zwraca swój pierwszy argument, jeÅ›li argumenty sÄ… różne i NULL, jeÅ›li argumenty sÄ… te same. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) Funkcja SQL printf(FORMAT,...) dziaÅ‚a jak funkcja sqlite3_mprintf() jÄ™zyka C oraz printf() ze standardowej biblioteki C. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) Funkcja quote(X) zwraca dosÅ‚owny tekst SQL, który jest wartoÅ›ciÄ… jego argumentów gotowÄ… do wstawienia w polecenie SQL. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () Funkcja random() zwraca pseudo-losowÄ… liczbÄ™ caÅ‚kowitÄ… z zakresu od -9223372036854775808 do +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) Funkcja randomblob(N) zwraca N-bajtowy kawaÅ‚ek zawierajÄ…cy pseudo-losowe bajty. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) Funkcja replace(X,Y,Z) zwraca ciÄ…g znaków utworzony poprzez podmianÄ™ ciÄ…gu znaków Z dla każdego wystÄ…pienia ciÄ…gu znaków Y w ciÄ…gu znaków X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) Funkcja round(X) zwraca wartość liczby zmiennoprzecinkowej X zaokrÄ…glonej do części caÅ‚kowitej. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) Funkcja round(X,Y) zwraca wartość liczby zmiennoprzecinkowej X zaokrÄ…glonej do liczby znaków dziesiÄ™tnych okreÅ›lonych przez Y. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) usuwa odstÄ™py z prawej strony X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) Funkcja rtrim(X,Y) zwraca ciÄ…g znaków utworzony po usuniÄ™ciu dowolnego i wszystkich znaków, które ukazujÄ… siÄ™ w Y z prawej strony X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) Funkcja soundex(X) zwraca ciÄ…g znaków X zakodowany jako soundex. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) zwraca wszystkie znaki do koÅ„ca ciÄ…gu znaków X zaczynajÄ…c od Y-tego. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) Funkcja substr(X,Y,Z) zwraca podciÄ…g znaków ciÄ…gu wejÅ›ciowego znaków X, który zaczyna siÄ™ na Y-tym znaku i który jest dÅ‚ugi na Z znaków. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () Funkcja total_changes() zwraca liczbÄ™ zmienionych wierszy przez polecenia INSERT, UPDATE lub DELETE od chwili nawiÄ…zania połączenia z bazÄ… danych. (X) trim(X) removes spaces from both ends of X. (X) trim(X) usuwa odstÄ™py z obu stron X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) Funkcja trim(X,Y) zwraca ciÄ…g znaków utworzony po usuniÄ™ciu dowolnego i wszystkich znaków, które ukazujÄ… siÄ™ w Y z obu stron X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) Funkcja typeof(X) zwraca ciÄ…g znaków, który wskazuje na rodzaj danych wyrażenia X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) Funkcja unicode(X) zwraca punkt numerycznego kodu unikodu odpowiadajÄ…cy pierwszemu znakowi ciÄ…gu X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) Funkcja upper(X) zwraca kopiÄ™ ciÄ…gu znaków X po przeksztaÅ‚ceniu wszystkich znaków ASCII na pisane wielkimi literami. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) Funkcja zeroblob(N) zwraca KAWAÅEK skÅ‚adajÄ…cy siÄ™ z N bajtów 0x00. (timestring,modifier,modifier,...) (ciÄ…g_znaków_czasu,zmieniacz,zmieniacz,...) (format,timestring,modifier,modifier,...) (format,ciÄ…g_znaków_czasu,zmieniacz,zmieniacz,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) Funkcja avg() zwraca wartość Å›redniÄ… wszystkich nie-NULL X wewnÄ…trz grupy. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) Funkcja count(X) zwraca liczbÄ™ tego ile razy X nie jest NULL w grupie. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) Funkcja group_concat() zwraca ciÄ…g znaków, który jest złączeniem wszystkich wartoÅ›ci nie-NULL X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) Funkcja group_concat() zwraca ciÄ…g znaków bÄ™dÄ…cy złączeniem wszystkich wartoÅ›ci nie-NULL X. JeÅ›li obecne jest Y, to sÅ‚uży jako znak oddzielajÄ…cy wystÄ…pienia X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) Funkcja max() zwraca najwyższÄ… wartość z wartoÅ›ci w grupie. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) Funkcja min() zwraca najmniejszÄ… wartość nie-NULL z wartoÅ›ci w grupie. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) Funkcje sum() oraz total() zwracajÄ… sumÄ™ wszystkich wartoÅ›ci nie-NULL w grupie. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () Numer wiersza wewnÄ…trz bieżącej partycji. Partycje sÄ… ponumerowane od 1 w kolejnoÅ›ci okreÅ›lonej przez wyrażenie ORDER BY w okreÅ›leniu okna lub w dowolnej kolejnoÅ›ci. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Numer wiersza row_number() pierwszego czÅ‚onka w każdej grupie - ranga bieżącego wiersza w rozstÄ™pach. JeÅ›li brak polecenia ORDER BY, to wszystkie wiersze sÄ… rozważane jako czÅ‚onkowie i funkcja zawsze zwraca 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Numer grupy bieżącego wiersza wewnÄ…trz jego partycji - ranga bieżącego wiersza bez przerw. Partycje sÄ… ponumerowane od 1 w kolejnoÅ›ci okreÅ›lonej przez wyrażenie ORDER BY w okreÅ›leniu okna. JeÅ›li brak wyrażenia ORDER BY, to wszystkie wiersze sÄ… rozważane jako leżące obok siebie, a funkcja ta zwraca 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () Pomimo nazwy, funkcja ta zawsze zwraca wartość pomiÄ™dzy 0.0 oraz 1.0 równÄ… (rank - 1)/(wiersze-partycji - 1), gdzie rank jest wartoÅ›ciÄ… zwracanÄ… przez wbudowanÄ… funkcjÄ™ rank() okna, a wiersze-partycji jest caÅ‚kowitÄ… liczbÄ… wierszy w partycji. JeÅ›li partycja zawiera tylko jeden wiersz, to ta funkcja zwraca 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () RozkÅ‚ad nagromadzony. Obliczany jako numer-wiersza/wiersze-partycji, gdzie numer-wiersza jest wartoÅ›ciÄ… zwracanÄ… przez row_number() dla ostatniego elementu w grupie, a wiersze-partycji to liczba wierszy w partycji. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) Argument N jest rozważany jako liczba caÅ‚kowita. Ta funkcja dzieli partycjÄ™ na N grup tak równo jak to możliwe i przypisuje liczbÄ™ caÅ‚kowitÄ… z zakresu od 1 do N każdej grupie w kolejnoÅ›ci okreÅ›lonej przez polecenie ORDER BY lub dowolnej. JeÅ›li zajdzie taka potrzeba, to wiÄ™ksze grupy wystÄ…piÄ… jako pierwsze. Ta funkcja zwraca liczbÄ™ caÅ‚kowitÄ… przypisanÄ… do grupy, do której bieżący wiersz należy. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Zwraca wynik obliczania wyrażenia expr na poprzednim wierszu w partycji. Lub, jeÅ›li nie ma poprzedniego wiersza (bo bieżący wiersz jest pierwszym), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,przesuniÄ™cie) JeÅ›li podano argument przesuniÄ™cia, to musi on być nieujemnÄ… liczbÄ… caÅ‚kowitÄ…. W tym przypadku wartoÅ›ciÄ… zwracanÄ… jest wynik obliczenia wyrażenia na wierszu przesuniÄ™tym o danÄ… liczbÄ™ wierszy wstecz wzglÄ™dem bieżącego wiersza. JeÅ›li nie bÄ™dzie takiego wiersza, to zwracane jest NULL. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,przesuniÄ™cie,domyÅ›lne) JeÅ›li podano także domyÅ›lne, to jest to wartoÅ›ci zwracana zamiast NULL, jeÅ›li wiersz okreÅ›lony przez przesuniÄ™cie nie istnieje. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Zwraca wynik obliczania wyrażenia expr na nastÄ™pnym wierszu w partycji. Lub, jeÅ›li nie ma nastÄ™pnego wiersza (bo bieżący wiersz jest ostatnim), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,przesuniÄ™cie) JeÅ›li podano argument przesuniÄ™cia, to musi on być nieujemnÄ… liczbÄ… caÅ‚kowitÄ…. W tym przypadku wartoÅ›ciÄ… zwracanÄ… jest wynik obliczenia wyrażenia na wierszu przesuniÄ™tym o danÄ… liczbÄ™ wierszy wprzód wzglÄ™dem bieżącego wiersza. JeÅ›li nie bÄ™dzie takiego wiersza, to zwracane jest NULL. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Ta wbudowana funkcja okna oblicza ramÄ™ okna dla każdego wiersza w ten sam sposób jak funkcja okna zÅ‚ożonego. Zwraca wartość expr obliczonÄ… na pierwszym wierszu ramy okna dla każdego wiersza. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Ta wbudowana funkcja okna oblicza ramÄ™ okna dla każdego wiersza w ten sam sposób jak funkcja okna zÅ‚ożonego. Zwraca wartość expr obliczonÄ… na ostatnim wierszu ramy okna dla każdego wiersza. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) Ta wbudowana funkcja okna oblicza ramÄ™ okna dla każdego wiersza w ten sam sposób jak funkcja okna zÅ‚ożonego. Zwraca wartość expr obliczonÄ… na N-tym wierszu ramy okna. Wiersze sÄ… numerowane wewnÄ…trz ramy okna poczynajÄ…c od 1 w kolejnoÅ›ci okreÅ›lonej przez polecenie ORDER BY jeÅ›li jest obecne lub w dowolnej kolejnoÅ›ci. JeÅ›li N-ty wiersz nie istnieje w partycji, to zwracane jest NULL. (X) Return the arccosine of X. The result is in radians. (X) Zwróć arkus kosinus z X. Wynik bÄ™dzie w radianach. (X) Return the hyperbolic arccosine of X. (X) Zwróć hiperboliczny arkus kosinus z X. (X) Return the arcsine of X. The result is in radians. (X) Zwróć arkus sinus z X. Wynik bÄ™dzie w radianach. (X) Return the hyperbolic arcsine of X. (X) Zwróć hiperboliczny arkus sinus z X. (X) Return the arctangent of X. The result is in radians. (X) Zwróć arkus tangens z X. Wynik bÄ™dzie w radianach. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X,Y) Zwróć arkus tangens z Y/X. Wynik bÄ™dzie w radianach. Wynik zostanie umieszony w odpowiednik kwadrancie w zależnoÅ›ci do znaków X oraz Y. (X) Return the hyperbolic arctangent of X. (X) Zwróć hiperboliczny arkus tangens z X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Zwróć pierwszÄ… przedstawialnÄ… liczbÄ™ caÅ‚kowitÄ… wiÄ™kszÄ… niż lub równÄ… X. Dla wartoÅ›ci dodatnich X, nastÄ™puje zaokrÄ…glanie w stronÄ™ od zera. Dla wartoÅ›ci X, nastÄ™puje zaokrÄ…glanie w stronÄ™ do zera. (X) Return the cosine of X. X is in radians. (X) Zwróć kosinus z X, gdzie X jest w radianach. (X) Return the hyperbolic cosine of X. (X) Zwróć hiperboliczny kosinus z X. (X) Convert value X from radians into degrees. (X) Przekształć wartość X z radianów na stopnie. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Oblicz e (Liczba Eulera, w przybliżeniu 2.71828182845905) podniesione do potÄ™gi X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Zwróć pierwszÄ… przedstawialnÄ… liczbÄ™ caÅ‚kowitÄ… mniejszÄ… niż lub równÄ… X. Dla wartoÅ›ci dodatnich X, nastÄ™puje zaokrÄ…glanie w stronÄ™ do zera. Dla wartoÅ›ci X, nastÄ™puje zaokrÄ…glanie w stronÄ™ od zera. (X) Return the natural logarithm of X. (X) Zwróć logarytm naturalny z X. (B,X) Return the base-B logarithm of X. (B, X) Zwróć logarytm o podstawie B z X. (X) Return the base-10 logarithm for X. (X) Zwróć logarytm o podstawie 10 z X. (X) Return the logarithm base-2 for the number X. (X) Zwróć logarytm o podstawie 2 z liczby X. (X,Y) Return the remainder after dividing X by Y. (X,Y) Zwróć resztÄ™ z dzielenia X przez Y. () Return an approximation for Ï€. () Zwróć przybliżenie liczby Ï€. (X,Y) Compute X raised to the power Y. (X,Y) Oblicz X podniesione do potÄ™gi Y. (X) Convert X from degrees into radians. (X) Przekształć wartość X ze stopni na radiany. (X) Return the sine of X. X is in radians. (X) Zwróć sinus z X, gdzie X jest w radianach. (X) Return the hyperbolic sine of X. (X) Zwróć hiperboliczny sinus z X. (X) Return the square root of X. NULL is returned if X is negative. (X) Zwróć pierwiastek kwadratowy z X. Zwróci NULL, gdy X bÄ™dzie ujemne. (X) Return the tangent of X. X is in radians. (X) Zwróć tangens z X, gdzie X jest w radianach. (X) Return the hyperbolic tangent of X. (X) Zwróć hiperboliczny tangens z X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) Zwróć pierwszÄ… przedstawialnÄ… liczbÄ™ caÅ‚kowitÄ… pomiÄ™dzy X, a 0 (włącznie), która jest najdalej o zera. Innymi sÅ‚owy, zwróć część caÅ‚kowitÄ… X, zaookrÄ…glajÄ…c jÄ… w stronÄ™ zera. SqliteTableModel reading rows czytanie wierszy loading... wczytywanie... References %1(%2) Hold %3Shift and click to jump there OdwoÅ‚ania %1(%2) PrzyciÅ›nij %3Shift i kliknij, aby tu przejść Error changing data: %1 WystÄ…piÅ‚ błąd podczas zmiany danych: %1 retrieving list of columns uzyskiwanie listy kolumn Fetching data... Uzyskiwanie danych… Cancel Zaniechaj TableBrowser Browse Data PrzeglÄ…daj dane &Table: &Tabela: Select a table to browse data Wybierz tabelÄ™, aby przeglÄ…dać dane Use this list to select a table to be displayed in the database view Użyj tej listy, aby zaznaczyć tabelÄ™ wyÅ›wietlanÄ… w widoku bazy danych This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Oto widok tabeli bazy danych. Możliwe sÄ… nastÄ™pujÄ…ce dziaÅ‚ania: - Pisanie do przeedytowania wartoÅ›ci w-wierszu. - Dwukrotne klikniÄ™cie na rekordzie, aby edytować jego zawartość w edytorze komórek. - Alt+Del do usuniÄ™cia treÅ›ci komórki i ustawienia NULL. - Ctrl+" do powielenia bieżącego rekordu. - Ctrl+' do skopiowania wartoÅ›ci z komórki powyżej. - Standardowe zaznaczanie/kopiowanie/wklejanie. Text pattern to find considering the checks in this frame Wzorzec tekstu do znalezienia, biorÄ…c pod uwagÄ™ pola zaznaczone w tym oknie Find in table Znajdź w tabeli Find previous match [Shift+F3] Znajdź poprzednie pasujÄ…ce [Shift+F3] Find previous match with wrapping Znajdź poprzednie pasujÄ…ce z mapowaniem Shift+F3 Shift+F3 Find next match [Enter, F3] Znajdź nastÄ™pne pasujÄ…ce [Enter, F3] Find next match with wrapping Znajdź nastÄ™pne pasujÄ…ce z nawracaniem F3 F3 The found pattern must match in letter case Wzorzec do znalezienia musi pasować wielkoÅ›ciÄ… liter Case Sensitive Rozróżniaj wielkość liter The found pattern must be a whole word Wzorzec do znalezienia musi być caÅ‚ym sÅ‚owem Whole Cell CaÅ‚a komórka Interpret search pattern as a regular expression Rozpatrz wzorzec wyszukiwania jako wyrażenie regularne <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Po zaznaczeniu, wzorzec do znalezienia jest rozważany jako wyrażenie regularne UNIX. Zajrzyj do <a href="https://en.wikibooks.org/wiki/Regular_Expressions">WyrażeÅ„ Regularnych w Wikibooks</a>.</p></body></html> Regular Expression Wyrażenie regularne Close Find Bar Zamknij pasek wyszukiwania Text to replace with Tekst do zastÄ…pienia Replace with ZastÄ…p Replace next match ZastÄ…p nastÄ™pne pasujÄ…ce wyrażenie Replace ZastÄ…p Replace all matches ZastÄ…p wszystkie pasujÄ…ce wyrażenia Replace all ZastÄ…p wszystkie Export to &JSON Wyeksportuj do &JSON Export the filtered data to JSON Wyeksportuj przefiltrowane dane do JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Ten przycisk wyeksportuje dane bieżącej tabeli tak jak sÄ… obecnie wyÅ›wietlane (po filtrach, z formatami wyÅ›wietlania i kolejnoÅ›ciÄ… kolumn) jako plik JSON. Copy column name Skopiuj nazwÄ™ kolumny Copy the database table column name to your clipboard Skopiuj nazwÄ™ kolumny tabeli do swojego schowka New Data Browser Nowa przeglÄ…darka danych Add a new docked Data Browser Dodaj nowÄ… zadokowanÄ… przeglÄ…darkÄ™ danych This button adds a new docked Data Browser, which you can detach and arrange in different layouts. Ten przycisk dodaje nowÄ… zadokowanÄ… PrzeglÄ…darkÄ™ Danych, którÄ… możesz odczepić i wstawić w różne ukÅ‚ady. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>PrzewiÅ„ do poczÄ…tku</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>NaciÅ›niÄ™cie tego przycisku kieruje na poczÄ…tek powyższego widoku tabeli.</p></body></html> |< |< Scroll one page upwards PrzewiÅ„ jednÄ… stronÄ™ w górÄ™ <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>NaciÅ›niÄ™cie tego przycisku przenosi o jednÄ… stronÄ™ wyżej w powyższym widoku tabeli.</p></body></html> < < 0 - 0 of 0 0 - 0 z 0 Scroll one page downwards PrzewiÅ„ jednÄ… stronÄ™ w dół <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>NaciÅ›niÄ™cie tego przycisku przenosi o jednÄ… stronÄ™ niżej w powyższym widoku tabeli.</p></body></html> > > Scroll to the end PrzewiÅ„ na koniec <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>NaciÅ›niÄ™cie tego przycisku przenosi na koniec powyższego widoku tabeli.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>NaciÅ›nij tutaj, aby przejść do danego rekordu</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Ten przycisk sÅ‚uży to przejÅ›cia do rekordu o numerze podanym w obszarze PrzejÅ›cia.</p></body></html> Go to: Przejdź do: Enter record number to browse Wprowadź numer rekordu do przejrzenia Type a record number in this area and click the Go to: button to display the record in the database view Wpisz numer rekordu w tym obszarze i naciÅ›nij na Przejdź Do, aby wyÅ›wietlić rekord w widoku bazy danych 1 1 Show rowid column Pokaż kolumnÄ™ ID wiersza Toggle the visibility of the rowid column Pokaż/Ukryj kolumnÄ™ ID wiersza Unlock view editing Odblokuj zmianÄ™ widoku This unlocks the current view for editing. However, you will need appropriate triggers for editing. To umożliwia wprowadzanie zmian w bieżącym widoku. Jednakże potrzebne bÄ™dÄ… odpowiednie wyzwalacze do zmiany. Edit display format ZmieÅ„ format wyÅ›wietlania Edit the display format of the data in this column ZmieÅ„ sposób wyÅ›wietlania danych w tej kolumnie New Record Nowy rekord Insert a new record in the current table Wstaw nowy rekord bieżącej tabeli <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Ten przycisk tworzy nowy rekord w bazie danych. PrzyciÅ›nij przycisk myszy, aby otworzyć menu podrÄ™czne z różnymi ustawieniami:</p><ul><li><span style=" font-weight:600;">Nowy rekord</span>: wstawia nowy rekord o domyÅ›lnych wartoÅ›ciach do bazy danych.</li><li><span style=" font-weight:600;">Wstaw wartoÅ›ci...</span>: otwiera okno dialogowe do wpisywania wartoÅ›ci przed ich wstawieniem do bazy danych. Umożliwia to wpisanie wartoÅ›ci przy zachowaniu różnych ograniczeÅ„. To okno dialogowe jest także otwarte, gdy nie powiedzie siÄ™ wykonanie polecenia <span style=" font-weight:600;">Nowy rekord</span> ze wzglÄ™du na te ograniczenia .</li></ul></body></html> Delete Record UsuÅ„ rekord Delete the current record UsuÅ„ bieżący rekord This button deletes the record or records currently selected in the table Ten przycisk usuwa obecnie zaznaczony rekord lub rekordy z tabeli Insert new record using default values in browsed table Wstaw nowy rekord przy użyciu domyÅ›lnych wartoÅ›ci bieżącej tabeli Insert Values... Wstaw wartoÅ›ci... Open a dialog for inserting values in a new record Otwiera okno dialogowe do wstawiania wartoÅ›ci do nowego rekordu Export to &CSV Wyeksportuj do &CSV Export the filtered data to CSV Wyeksportuj przefiltrowane dane do CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Ten przycisk wyeksportuje dane bieżącej tabeli tak jak sÄ… obecnie wyÅ›wietlane (po filtrach, z formatami wyÅ›wietlania i kolejnoÅ›ciÄ… kolumn) jako plik CSV. Save as &view Zapisz jako &widok Save the current filter, sort column and display formats as a view Zapisuje bieżący filtr, kolumnÄ™ do szeregowania oraz formaty wyÅ›wietlania jako widok This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Ten przycisk zapisuje bieżące ustawienia oglÄ…danej tabeli (filtry, formaty wyÅ›wietlania i kolejność kolumn) jako widok SQL, który można później przeglÄ…dać lub wstawić do polecenia SQL. Save Table As... Zapisz tabelÄ™ jako... Save the table as currently displayed Zapisz tabelÄ™ tak, jak jest obecnie wyÅ›wietlana <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>To menu podrÄ™czne zawiera nastÄ™pujÄ…ce ustawienie stosujÄ…ce siÄ™ do obecnie oglÄ…danej i filtrowanej tabeli:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Eksportuj do CSV: eksportuje dane oglÄ…danej tabeli tak jak jest obecnie wyÅ›wietlana (po filtrach, z formatami wyÅ›wietlania i kolejnoÅ›ciÄ… kolumn) do pliku CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Zapisz jako widok: zapisuje bieżące ustawienia oglÄ…danej tabeli (filtry, formaty wyÅ›wietlania i kolejność kolumn) jako widok SQL, który można później przeglÄ…dać lub wstawić do polecenia SQL.</li></ul></body></html> Hide column(s) Ukryj kolumnÄ™/y Hide selected column(s) Ukryj zaznaczonÄ…/e kolumnÄ™/y Show all columns Pokaż wszystkie kolumny Show all columns that were hidden Pokaż wszystkie ukryte kolumny Set encoding Ustaw kodowanie Change the encoding of the text in the table cells ZmieÅ„ kodowanie tekstu w komórkach tabeli Set encoding for all tables Ustaw kodowanie dla wszystkich tabel Change the default encoding assumed for all tables in the database ZmieÅ„ domyÅ›lne kodowanie przyjÄ™te dla wszystkich table w bazie danych Clear Filters Wyczyść filtry Clear all filters Wyczyść wszystkie filtry This button clears all the filters set in the header input fields for the currently browsed table. Ten przycisk wyczyÅ›ci wszystkie filtry ustawione na polach wejÅ›ciowych nagłówka dla bieżącej tabeli. Clear Sorting Wyczyść szeregowanie Reset the order of rows to the default Przywróć porzÄ…dek wierszy do domyÅ›lnego This button clears the sorting columns specified for the currently browsed table and returns to the default order. Ten przycisk czyÅ›ci kolumny szeregowania dla danej tabeli i powraca do domyÅ›lnego porzÄ…dku. Print Wydrukuj Print currently browsed table data WyÅ›wietl dane bieżącej tabeli Print currently browsed table data. Print selection if more than one cell is selected. Wydrukuj dane bieżącej tabeli. Wydrukuj zaznaczenie, jeÅ›li zaznaczono wiÄ™cej niż jednÄ… komórkÄ™. Ctrl+P Ctrl+P Refresh OdÅ›wież Refresh the data in the selected table OdÅ›wież dane w zaznaczonej tabeli This button refreshes the data in the currently selected table. Ten przycisk odÅ›wieża dane w obecnie zaznaczonej tabeli. F5 F5 Find in cells Znajdź w komórkach Open the find tool bar which allows you to search for values in the table view below. Otwórz pasek wyszukiwania, który umożliwi wyszukiwanie wartoÅ›ci w poniższym widoku tabeli. Freeze columns Zamroź kolumny Make all columns from the first column up to this column not move when scrolling horizontally Nie przesuwaj kolumn w poziomie od pierwszej kolumny do tej kolumny przy przewijaniu Bold Pogrubienie Ctrl+B Ctrl+B Italic Kursywa Underline PodkreÅ›lenie Ctrl+U Ctrl+U Align Right Wyrównaj do prawej Align Left Wyrównaj do lewej Center Horizontally WyÅ›rodkuj w poziomie Justify Justowanie Edit Conditional Formats... Edytuj formatowanie warunkowe... Edit conditional formats for the current column ZmieÅ„ formatowania warunkowe dla bieżącej kolumny Clear Format Wyczyść format Clear All Formats Wyczyść wszystkie formatowania Clear all cell formatting from selected cells and all conditional formats from selected columns Wyczyść wszystkie formatowania warunkowe dla zaznaczonej komórki i wszystkie formatowania warunkowe dla zaznaczonych kolumn Font Color Barwa czcionki Background Color Barwa tÅ‚a Toggle Format Toolbar Pokaż pasek formatowania Show/hide format toolbar Pokaż/ukryj pasek formatu This button shows or hides the formatting toolbar of the Data Browser Ten przycisk pokazuje lub ukrywa pasek formatowania dla przeglÄ…darki danych Select column Zaznacz kolumnÄ™ Ctrl+Space Ctrl+Space Replace text in cells ZastÄ…p tekst w komórkach Filter in any column Filtruj w dowolnej kolumnie Ctrl+R Ctrl+R %n row(s) %n wiersz %n wiersze %n wierszy , %n column(s) , %n kolumna , %n kolumny , %n kolumn . Sum: %1; Average: %2; Min: %3; Max: %4 . Suma: %1; Åšrednia: %2; Min: %3; Maks: %4 Conditional formats for "%1" Formatowania warunkowe dla "%1" determining row count... okreÅ›lanie liczby wierszy… %L1 - %L2 of >= %L3 %L1 - %L2 z >= %L3 %L1 - %L2 of %L3 %L1 - %L2 z %L3 (clipped at %L1 rows) (przyciÄ™ta na %L1 wirszach) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Podaj pseudo-główny klucz, aby rozpocząć edytowanie w tym widoku. Powinna to być nazwa niepowtarzalnej kolumny w widoku. Delete Records UsuÅ„ rekordy Duplicate records Powielone rekordy Duplicate record Powiel rekord Ctrl+" Ctrl+" Adjust rows to contents Dostosuj wiersze do treÅ›ci Error deleting record: %1 Błąd usuwania rekordu: %1 Please select a record first Najpierw wybierz rekord Please choose a new encoding for all tables. Wybierz nowe kodowanie dla wszystkich tabel. Please choose a new encoding for this table. Wybierz kodowanie dla tej tabeli. %1 Leave the field empty for using the database encoding. %1 Pozostaw pole pustym, aby użyć kodowania bazy danych. This encoding is either not valid or not supported. To kodowanie jest nieprawidÅ‚owe lub nieobsÅ‚ugiwane. %1 replacement(s) made. Wykonano %1 zastÄ…pieÅ„. TableBrowserDock New Data Browser Nowa przeglÄ…darka danych Rename Data Browser Przemianuj przeglÄ…darkÄ™ danych Close Data Browser Zamknij przeglÄ…darkÄ™ danych Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. Nadaj nowÄ… nazwÄ™ dla przeglÄ…darki danych. Użyj znaku '&&', aby móc użyć nastÄ™pujÄ…cego znaku jako skrótu klawiszowego. VacuumDialog Compact Database ÅšciÅ›nij bazÄ™ danych Warning: Compacting the database will commit all of your changes. Uwaga: Åšciskanie bazy danych spowoduje wdrożenie wszystkich twoich zmian. Please select the databases to co&mpact: Wybierz bazÄ™ danych do Å›ciÅ›&niÄ™cia: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_pt_BR.ts000066400000000000000000013330561463772530400256160ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Sobre DB Browser para SQLite Version Versão <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Adicionar novo registro Enter values for the new record considering constraints. Fields in bold are mandatory. Entre valores para o novo registro considerando as restriões. Campos em negrito são obrigatórios. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Na coluna Valor você pode especificar o valor para o campo identificado na coluna Nome. A coluna Tipo indica qual o tipo do campo. Valores padrão são exibidos no mesmo estilo que valores nulos. Name Nome Type Tipo Value Valor Values to insert. Pre-filled default values are inserted automatically unless they are changed. Valores para inserir. Valores padrão pré-preenchidos são inseridos automaticamente a não ser que sejam alterados. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Quando você edita os valores no frame acima, a consulta SQL para inserir esse novo registro é exibida aqui. Você pode editar manualmente a consulta antes de salvar. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Salvar</span> irá enviar o comando SQL exibido para o banco de dados para a inserção do novo registro.</p><p><span style=" font-weight:600;">Restaurar Padrões</span> irá restaurar os valores iniciais na coluna <span style=" font-weight:600;">Valor</span>.</p><p><span style=" font-weight:600;">Cancelar</span> irá fechar esse diálogo sem executar a consulta.</p></body></html> Auto-increment Auto-incremento Unique constraint Restrição de unicidade Check constraint: %1 Restrição de condição %1 Foreign key: %1 Chave estrangeira: %1 Default value: %1 Valor padrão: %1 Error adding record. Message from database engine: %1 Erro adicionando registro. Mensagem do banco de dados: %1 Are you sure you want to restore all the entered values to their defaults? Você tem certeza que deseja restaurar todos os valores inseridos para os seus valores padrão? Application Possible command line arguments: Possíveis argumentos da linha de comando: The user settings file location is replaced with the argument value instead of the environment variable value. Ignored environment variable (DB4S_SETTINGS_FILE) value: Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Browse this table, or use it as target of a data import Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The file %1 does not exist O arquivo %1 não existe The -S/--settings option requires an argument. The option is ignored. The -o/--option and -O/--save-option options require an argument in the form group/setting=value As opções -o/--option e -O/--save-option requerem um argumento no formato grupo/configuração=valor Invalid option/non-existent file: %1 Opção inválida/arquivo inexistente: %1 SQLite Version Versão do SQLite SQLCipher Version %1 (based on SQLite %2) SQLCipher versão %1 (baseado em SQLite %2) DB Browser for SQLite Version %1. Last commit hash when built: %1 Built for %1, running on %2 Compilado para %1, rodando em %2 Qt Version %1 CipherDialog SQLCipher encryption Encriptação SQLCipher &Password &Senha &Reenter password &Entre a senha novamente Encr&yption settings &Configurações de encriptação SQLCipher &3 defaults Padrões do SQLCipher &3 SQLCipher &4 defaults Padrões do SQLCipher &4 Custo&m Custo&mizado &KDF iterations Iterações &KDF HMAC algorithm Algoritmo de HMAC KDF algorithm Algoritmo de KDF Plaintext Header Size Tamanho do cabeçalho de texto Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Por favor, entre a chave usada para encriptar o banco de dados. Se quaisquer das outras configurações foram alteradas você terá de prover essas informações também. Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Por favor, selecione uma chave para encriptar o banco de dados. Note que se você alterar quaisquer configurações opcionais você terá de entrá-las todas as vezes que você abrir o arquivo do banco de dados. Deixe os campos de senha em branco para desativar a encriptação. O processo de encriptação pode demorar alguns minutos e você deve ter um backup do seu banco de dados! Alterações não salvas são aplicadas antes de se modificar a encriptação. Page si&ze &Tamanho da página Passphrase Palavra chave Raw key Chave desencriptada ColumnDisplayFormatDialog Choose display format Escolha um formato de exibição Display format Formato de exibição Choose a display format for the column '%1' which is applied to each value prior to showing it. Escolha um formato de exibição para a coluna '%1' que será aplicado a cada valor antes de exibí-lo. Default Padrão Decimal number Número decimal Exponent notation Notação exponencial Hex blob BLOB hexadecimal Hex number Número hexadecimal .NET DateTime.Ticks to date Julian day to date Dia juliano para data WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Lower case Caixa baixa Binary GUID to text SpatiaLite Geometry to SVG Custom display format must contain a function call applied to %1 Formato de exibição customizado precisa conter uma função aplicada a %1 Error in custom display format. Message from database engine: %1 Erro em formato de exibição customizado. Mensagem da engine da base de dados: %1 Custom display format must return only one column but it returned %1. Formato de exibição customizado precisa retornar apenas uma coluna mas retornou %1. Octal number Octal Round number Número arredondado Unix epoch to date Era unix para data Upper case Caixa alta Windows DATE to date DATE do Windows para data Custom Personalizado Apple NSDate to date NSDate da Apple para date Java epoch (milliseconds) to date Época Java (ms) para data Unix epoch to local time Época Unix para tempo local Date as dd/mm/yyyy Data como dd/mm/yyyy CondFormatManager Conditional Format Manager Gerenciador de formato condicional This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Esse diálogo permite a criação e edição de formatos condicionais. O estilo de cada célula será escolhido pela primeira condição satisfeita pelo valor daquela célula. Formatos condicionais podem ser movidos para cima e para baixo, tendo precedência os formatos localizados mais acima. A sintaxe para as condições é a mesma utilizada para os filtros e uma condição vazia é sempre satisfeita. Add new conditional format Adicionar novo formato condicional &Add &Adicionar Remove selected conditional format Remover formato condicional selecionado &Remove &Remover Move selected conditional format up Mover formato condicional selecionado para cima Move &up Mover para &cima Move selected conditional format down Mover formato condicional selecionado para baixo Move &down Mover para &baixo Foreground Plano de frente Text color Cor do texto Background Fundo Background color Cor do plano de fundo Font Fonte Size Tamanho Bold Negrito Italic Itálico Underline Sublinhado Alignment Alinhamento Condition Condição Click to select color Clique para selecionar a cor Are you sure you want to clear all the conditional formats of this field? Você tem certeza de que deseja limpar todos os formatos condicionais deste campo? DBBrowserDB Please specify the database name under which you want to access the attached database Por favor, especifique o nome do banco de dados sob o qual você quer acessar o banco de dados anexado Do you want to save the changes made to the database file %1? Você quer salvar as alterações feitas ao arquivo de banco de dados %1? Exporting database to SQL file... Exportando banco de dados para arquivo SQL... Cancel Cancelar Executing SQL... Executando SQL... Action cancelled. Ação cancelada. Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: A restauração de alguns dos objetos associados com essa tabela falhou. Provavelmente porque os nomes de algumas colunas mudaram. Aqui está a consulta que você pode querer corrigir e executar manualmente: Error setting pragma %1 to %2: %3 Erro definindo pragma %1 para %2: %3 File not found. Arquivo não encontrado. Invalid file format Formato de arquivo inválido Error in statement #%1: %2. Aborting execution%3. Erro no comando #%1: %2. Aborting execution%3. and rolling back e revertendo Cannot set data on this object Não se pode definir dados nesse objeto Error loading built-in extension: %1 could not get column information não pôde obter informação sobre a coluna Do you really want to close this temporary database? All data will be lost. Você realmente quer fechar esse banco de dados temporário? Todos os dados serão perdidos. Database didn't close correctly, probably still busy A base de dados não fechou corretamente, provavelmente ainda ocupada Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: O banco de dados está ocupado: Do you want to abort that other operation? Você quer abortar a outra operação? No database file opened Não há um arquivo de banco de dados aberto didn't receive any output from %1 não recebeu nenhuma saída de %1 could not execute command: %1 não pode executar comando: %1 Cannot delete this object Não pode deletar esse objeto A table with the name '%1' already exists in schema '%2'. Uma tabela com o nome '%1' já existe no esquema '%2'. No table with name '%1' exists in schema '%2'. Nem uma tabela chamada '%1' existe no esquema '%2'. Cannot find column %1. Não pode encontrar coluna %1. Creating savepoint failed. DB says: %1 Criação de savepoint falhou. BD diz: %1 Renaming the column failed. DB says: %1 Renomeação de coluna falhou. BD diz: %1 Releasing savepoint failed. DB says: %1 Liberação de savepoint falhou. BD diz: %1 Creating new table failed. DB says: %1 Criação de tabela falhou. BD diz: %1 Copying data to new table failed. DB says: %1 Cópia de dados para uma nova tabela falhou. BD diz: %1 Deleting old table failed. DB says: %1 Deletando tabela antiga falhou. BD diz: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 Erro renomeando tabela de '%1' para '%2'. Mensagem da engine do banco de dados: %3 could not get list of db objects: %1 não conseguiu listar objetos da BD: %1 could not get list of databases: %1 não pôde obter a lista de bancos de dados: %1 Error loading extension: %1 Erro carregado extensão: %1 DbStructureModel Name Nome Object Objeto Type Tipo Schema Esquema Tables (%1) Tabelas (%1) Indices (%1) Ãndices (%1) Views (%1) Vistas (%1) Triggers (%1) Gatilhos (%1) All Todos Database Banco de dados Browsables Navegáveis Temporary Temporário EditDialog Edit database cell Editar célula Text Texto Binary Binário Erases the contents of the cell Apaga os conteúdos da célula This area displays information about the data present in this database cell Essa área exibe informação sobre os dados presentes nessa célula Choose a filename to export data Escolha um arquivo para exportar dados Mode: Modo: Image Imagem Set as &NULL Definir como &NULL Apply Aplicar This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Essa é a lista de modos suportados pelo editor de célula. Escolha um modo para visualizar ou editar os dados da célula atual. RTL Text Texto para a esquerda JSON JSON XML XML Evaluation Automatically adjust the editor mode to the loaded data type Automaticamente ajustar o modo do editor para o tipo de dado carregado This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Esse botão assinalável ativa ou desativa a troca automática do modo do editor. Quando uma nova célula é selecionado ou novos dados são importados e a troca automática está habilitada, o modo ajusta para o tipo detectado. Você pode então mudar o modo do editor manualmente. Se você quer manter o modo manualmente escolhido enquanto movendo pelas células, desmarque essa opção. Auto-switch Auto-trocar This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Esse editor do QT é usado para scripts da direita para a esquerda, que não são suportados pelo editor de texto padrão. Quando a presença de caracteres da direita para a esquerda é detectada, esse modo é automaticamente selecionado. Identification of the cell currently in the editor Type and size of data currently in table Open preview dialog for printing the data currently stored in the cell Abrir diálogo de prévia para impressão dos dados atualmente armazenados na célula Auto-format: pretty print on loading, compact on saving. Auto-formatar: exibir formatado ao carregar, compactar ao salvar. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Quando ativado, a funcionalidade de auto-formatar formata os dados ao carregar, quebrando o texto em linhas e indentando ele para melhor legibilidade. Ao salvar os dados, o auto-formatador compacta os dados removendo espaços em branco desnecessários. Word Wrap Quebra de linha Wrap lines on word boundaries Quebra de linha em limites de palavras Open in default application or browser Abrir em aplicação padrão ou navegador Open in application Abrir em aplicação The value is interpreted as a file or URL and opened in the default application or web browser. O valor é interpretado como um arquivo ou URL e aberto na aplicação padrão ou navegador. Save file reference... Salvar referência de arquivo... Save reference to file Salvar referência para arquivo Open in external application Abrir em aplicação externa Autoformat Autoformatar &Export... &Exportar... &Import... &Importar... Import from file Importar do arquivo Opens a file dialog used to import any kind of data to this database cell. Abre um seletor de arquivos usado para importar qualquer tipo de dado para essa célula. Export to file Exportar para arquivo Opens a file dialog used to export the contents of this database cell to a file. Abre um seletor de arquivo para exportar os conteúdos dessa célula para um arquivo. Apply data to cell Aplicar dados à célula This button saves the changes performed in the cell editor to the database cell. Esse botão salva as modificações realizadas no editor da célula para a célula do banco de dados. Image data can't be viewed in this mode. Dados de imagem não podem ser visualizados nesse modo. Try switching to Image or Binary mode. Tente mudar para modo de Imagem ou Binário. Binary data can't be viewed in this mode. Dados binários não podem ser visualizados nesse modo. Try switching to Binary mode. Tente mudar para modo binário. Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) Couldn't save file: %1. Não pôde salvar arquivo: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Image files (%1) Arquivos de imagem (%1) Binary files (*.bin) Arquivos binários (*.bin) Choose a file to import Escolha um arquivo para importar The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Unsaved data in the cell editor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. %1 Image %1 Imagem Invalid data for this mode Dados inválidos para esse modo The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? A célula contém dados inválidos %1. Motivo: %2. Você realmente quer aplicar isso? Print... Imprimir... Ctrl+P Open preview dialog for printing displayed text Abrir diálogo de prévia para imprimir texto exibido Copy Hex and ASCII Copiar Hex e ASCII Copy selected hexadecimal and ASCII columns to the clipboard Copiar colunas hexadecimal e ASCII selecionadas para a área de transferência Ctrl+Shift+C EditIndexDialog &Name &Nome Order Ordem &Table &Tabela &Unique &Único Creating the index failed: %1 Criação de índice falhou: %1 Edit Index Schema Editar esquema do índice For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Para restringir o índice para somente uma parte da tabela você pode especificar uma cláusula WHERE aqui que seleciona a parte da tabela que deveria ser indexada Partial inde&x clause Cláusula de índi&ce parcial Colu&mns Colu&nas Table column Coluna da tabela Type Tipo Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Adicionar uma nova coluna de expressão para o índice. Colunas de expressão contêm expressões SQL em vez de nomes de coluna. Index column Indexar coluna Deleting the old index failed: %1 Deletar o índice antigo falhou: %1 EditTableDialog Edit table definition Editar definição da tabela Table Tabela Advanced Avançado Database sche&ma Esque&ma do banco de dados Without Rowid Sem Rowid Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Fields Campos Add Adicionar Remove Remover Move to top Mover para o topo Move up Mover para cima Move down Mover para baixo Move to bottom Mover para o fundo Name Nome Type Tipo Not null Não null PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> AI AI Autoincrement Autoincrement U U Unique Unique Default Default Default value Default value Check Check Check constraint Check constraint Collation Agrupamento Foreign Key Foreign Key <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Index Constraints Add constraint Adicionar restrição Remove constraint Remover restrição Columns Colunas SQL SQL Foreign Keys References Check Constraints Primary Key Chave primária Add a primary key constraint Adicionar restrição de chave primária Add a unique constraint Adicionar uma restrição de unicidade There can only be one primary key for each table. Please modify the existing primary key instead. Cada tabela pode ter apenas uma chave primária. Por favor, modifique a chave primária existente. Error creating table. Message from database engine: %1 Erro criando tabela. Mensagem da engine do banco de dados: %1 There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Há pelo menos uma linha com esse campo definido NULL. Logo, é impossível definir essa flag. Por favor, mude os dados da tabela primeiro. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Há pelo menos uma linha com um valor não-inteiro nesse campo. Logo, é impossível definir essa flag. Por favor, mude os dados da tabela primeiro. Column '%1' has duplicate data. Coluna '%1' tem dados duplicados. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Isso faz com que seja impossível de se habilitar a flag de unicidade. Por favor, remova os dados duplicados para permitir que a flag seja habilitada. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Você tem certeza de que deseja deletar o campo '%1? Todos os dados atualmente armazenados nesse campo serão perdidos. Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set There already is a field with that name. Please rename it first or choose a different name for this field. Já existe um campo com este nome. Por favor, renomeie-o primeiro ou escolha um nome diferente para esse campo. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Por favor, adicione um campo que atende aos seguintes critérios antes de definir a flag "without rowid": - Flag "primary key" definida - Incremento automático desativado This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Essa coluna é referenciada em uma chave estrangeira na tabela %1 e portanto seu nome não pode ser alterado. <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Alerta: </span>Nosso parser não entende algo dessa definição de tabela. Modificar e salvar essa tabela pode causar problemas.</p></body></html> NN NN ExportDataDialog Export data as CSV Exportar dados como CSV , , ; ; Tab Tab | | Other Outro &Quote character &Ãspas " " ' ' Could not open output file: %1 Não pôde abrir arquivo de saída: %1 Choose a filename to export data Escolha um arquivo para exportar dados Please select at least 1 table. Por favor, selecione pelo menos uma tabela. Choose a directory Escolha um diretório Export completed. Exportação completa. Export finished with errors. New line characters Caracteres de nova linha Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Tab&le(s) Tabe&las(s) Colu&mn names in first line &Nomes das colunas na primeira linha Fie&ld separator Se&parador de campo Pretty print Otimizar para leitura humana Export data as JSON Exportar dados como JSON exporting CSV exportando CSV Error while writing the file '%1': %2 exporting JSON exportando JSON ExportSqlDialog Export SQL... Exportar SQL... &Options &Opções Keep column names in INSERT INTO Manter nomes de colunas em INSERT INTO Export schema only Exportar somente esquema Choose a filename to export Escolha um arquivo para exportar Export completed. Exportação completa. Export cancelled or failed. Exportação falhou ou foi cancelada. Tab&le(s) Tabe&las(s) Select All Selecionar tudo Deselect All Limpar seleção Multiple rows (VALUES) per INSERT statement Múltiplas linhas (VALUES) por INSERT Export everything Exportar tudo Export data only Exportar somente dados Keep original CREATE statements Keep old schema (CREATE TABLE IF NOT EXISTS) Manter esquema antigo (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Sobrescrever esquema antigo (DROP TABLE, then CREATE TABLE) Please select at least one table. Por favor selecione pelo menos uma tabela. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Encontrar... Find and Replace... Encontrar e substituir... Print... Imprimir... ExtendedTableWidget Set to NULL Definir como NULL Copy Copiar Paste Colar The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? O conteúdo da área de transferência é maior do que o intervalo selecionado. Deseja inserir mesmo assim? Use as Exact Filter Usar como filtro exato Containing Contendo Not containing Não contendo Not equal to Diferente de Greater than Maior que Less than Menor que Greater or equal Maior ou igual a Less or equal Menor ou igual a Between this and... Entre isso e... Regular expression Expressão regular Edit Conditional Formats... Editar formatos condicionais... Cut Copy with Headers Copiar com cabeçalhos Copy as SQL Copiar como SQL Print... Imprimir... Use in Filter Expression Usar na expressão de filtro Alt+Del Ctrl+Shift+C Ctrl+Alt+C <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>Nem todos os dados foram carregados. <b>Você quer carregar todos os dados antes de selecionar todas as linhas?</b><p><p>Respondendo <b>Não</b> significa que mais dados não serão carregados e a seleção não será executada.<br/>Respondendo <b>Sim</b> pode levar algum tempo enquanto os dados são carregados mas a seleção será incompleta.</p>Aviso: carregar todos os dados pode exigir uma grande quantidade de memória para tabelas grandes. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. Não é possível definir a seleção como NULL. Coluna %1 tem uma restrição de nulidade. FileExtensionManager File Extension Manager Gerenciador de extensão de arquivo &Up &Subir &Down &Descer &Add &Adicionar &Remove &Remover Description Descrição Extensions Extensões *.extension *.extensão FilterLineEdit Filter Filtro These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Esses campos de entrada permitem você realizar filtros rápidos na tabela atualmente selecionada. Por padrão, as linhas que contém o texto de entrada são filtradas Os seguintes operadores também são suportados: % Curinga > Maior que < Menor que >= Maior ou igual a <= Menor ou igual a = Igual <> Diferente x~y Intervalo: valores entre x e y /regexp/ Valores satisfazendo a expressão regular Clear All Conditional Formats Limpar todos os formatos condicionais Use for Conditional Format Usar para formato condicional Edit Conditional Formats... Editar formatos condicionais... Set Filter Expression Definir expressão de filtro What's This? O que é isso? Is NULL É NULL Is not NULL Não é NULL Is empty É vazio Is not empty Não é vazio Not containing... Não contendo... Equal to... Igual a... Not equal to... Diferente de... Greater than... Maior que... Less than... Menor que... Greater or equal... Maior ou igual... Less or equal... Menor ou igual... In range... No intervalo... Regular expression... Expressão regular... FindReplaceDialog Find and Replace Encontrar e substituir Fi&nd text: E&ncontrar texto: Re&place with: Su&bstituir com: Match &exact case Casar caixa &exata Match &only whole words Casar s&omente palavras inteiras When enabled, the search continues from the other end when it reaches one end of the page Quando ativado, a busca continua do outro fim quando ela atinge um fim da página &Wrap around &Envolver em torno When set, the search goes backwards from cursor position, otherwise it goes forward Quando ativado, a busca retrocede a partir do cursor em vez de ir para frente Search &backwards Buscar para &trás <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>Quando selecionado, o padrão procurado é testado somente na seleção atual.</p></body></html> &Selection only &Somente seleção <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Quando selecionado, o padrão a ser encontrado é interpretado como uma expressão regular UNIX. Veja <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression nos Wikibooks</a>.</p></body></html> Use regular e&xpressions Usar e&xpressões regulares Find the next occurrence from the cursor position and in the direction set by "Search backwards" Encontrar a próxima ocorrência a partir da posição do cursor na direção selecionada por "Buscar para trás" &Find Next &Encontrar próximo F3 &Replace &Substituir Highlight all the occurrences of the text in the page Realçar todas as ocorrências do texto na página F&ind All Encontrar &todos Replace all the occurrences of the text in the page Substituir todas as ocorrências do texto na página Replace &All Substituir &todos The searched text was not found O texto procurado não foi encontrado The searched text was not found. O texto procurado não foi encontrado. The searched text was found one time. O texto procurado foi encontrado uma vez. The searched text was found %1 times. O texto procurado foi encontrado %1 vezes. The searched text was replaced one time. O texto procurado foi substituído uma vez. The searched text was replaced %1 times. O texto procurado foi substituído %1 vezes. ForeignKeyEditor &Reset &Resetar Foreign key clauses (ON UPDATE, ON DELETE etc.) Cláusulas de chave estrangeira (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Reset the scaling to match the original size of the image. Set the scaling to match the size of the viewport. Print... Imprimir... Open preview dialog for printing displayed image Abrir diálogo de prévia para imprimir imagem exibida Ctrl+P ImportCsvDialog Import CSV file Importar arquivo CSV &Column names in first line Nomes das &colunas na primeira linha Field &separator &Separador de campos , , ; ; Tab Tab | | Other Outro &Quote character &Ãspas Other (printable) Outro (imprimível) Other (code) Outro (código) " " ' ' &Encoding &Encoding UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? Trim fields? Creating restore point failed: %1 Criação de ponto de restauração falhou: %1 Creating the table failed: %1 Criação de tabela falhou: %1 Inserting row failed: %1 Inserir linha falhou: %1 Separate tables Tabelas separadas Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Quando importando em uma tabela existente com uma chave primária, restrições de unicidade ou índice único há uma chance para conflitos. Essa opção permite a você selecionar uma estratégia para esse caso. Por padrão, a importação é abortada e revertida, mas você também pode escolher ignorar e não importar linhas conflitantes ou substituir as entradas existentes na tabela. Abort import Abortar importação Ignore row Ignorar linha Replace existing row Substituir linhas existentes Conflict strategy Estratégia para conflitos Deselect All Limpar seleção Match Similar Detectar similares Select All Selecionar tudo Table na&me No&me da tabela Advanced Avançado When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Quando importando um valor em branco do arquivo CSV em uma tabela existente com um valor padrão para essa coluna, aquele valor padrão é inserido. Ative essa opção para inserir um valor em branco em vez. Ignore default &values Ignorar &valores padrão Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Ative essa opção para parar a importação quando tentando importar um valor em branco em uma coluna NOT NULL sem um valor padrão. Fail on missing values Falhar em valores faltando Disable data type detection Desativar detecção de tipo de dados Disable the automatic data type detection when creating a new table. Desativa a detecção automática de tipo de dados quando criando uma nova tabela. There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Já existe uma tabela chamada '%1' e uma importação em uma tabela existente só é possível se o número de colunas bate. There is already a table named '%1'. Do you want to import the data into it? Já existe uma tabela chamada '%1'. Você quer importar os dados nela? importing CSV Importando CSV Could not prepare INSERT statement: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Importando o arquivo '%1' levou %2 ms. Desses, %3 ms foram gastos na função da linha. MainWindow DB Browser for SQLite DB Browser para SQLite toolBar1 toolBar1 &File &Arquivo &Import &Importar &Export E&xportar &Edit &Editar &View &Exibir &Help A&juda DB Toolbar Barra de ferramentas do banco de dados User Usuário Application Aplicativo &Clear &Limpar &New Database... &Novo banco de dados... Create a new database file Criar um novo arquivo de banco de dados This option is used to create a new database file. Essa opção e utilizada para criar um novo arquivo de banco de dados. Ctrl+N &Open Database... &Abrir banco de dados... Open an existing database file Abre um arquivo de banco de dados existente This option is used to open an existing database file. Esta opção abre um arquivo de banco de dados existente. Ctrl+O &Close Database &Fechar banco de dados Ctrl+W Revert database to last saved state Reverter banco de dados para o último estado salvo This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Essa opção é usada para reverter o atual arquivo de banco de dados para seu último estado salvo. Todas as modificações feitas desde a última operação de salvamento são perdidas. Write changes to the database file Salva modificações para o arquivo de banco de dados This option is used to save changes to the database file. Essa opção é usada para salvar modificações para o arquivo de banco de dados. Ctrl+S Compact the database file, removing space wasted by deleted records Compactar o arquivo do banco de dados, removendo espaço desperdiçado por registros deletados Compact the database file, removing space wasted by deleted records. Compactar o arquivo do banco de dados, removendo espaço desperdiçado por registros deletados. E&xit &Sair Ctrl+Q Import data from an .sql dump text file into a new or existing database. Importar dados de um arquivo de texto .sql em um banco de dados. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Essa opção deixa você importar dados de um arquivo SQL em um banco de dados. Arquivos de SQL podem ser criados na maioria dos bancos de dados, como MySQL e PostgreSQL. Open a wizard that lets you import data from a comma separated text file into a database table. Abre um assistente que permite você importar dados de um arquivo CSV em uma tabela de banco de dados. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Abre um assistente que permite você importar dados de um arquivo CSV em uma tabela de banco de dados. Arquivos CSV podem ser criados pela maioria dos programas de banco de dados e planilhas. Export a database to a .sql dump text file. Exportar o banco de dados para um arquivo de texto .sql. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Essa opção permite você exportar um banco de dados para um arquivo de texto .sql. Arquivos de despejo SQL contêm todos os dados necessários para recriar o banco de dados na maioria dos motores de banco de dados, incluindo MySQL e PostgreSQL. Export a database table as a comma separated text file. Exportar uma tabela de banco de dados como um arquivo CSV. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Exportar uma tabela de banco de dados como um arquivo CSV, pronto para ser importado por outro banco de dados ou planilhas. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Abre o assistente de criação de tabelas, em que é possível definir o nome e os campos para uma nova tabela no banco de dados Delete Table Deletar tabela Open the Delete Table wizard, where you can select a database table to be dropped. Abre o assistente de deleção de tabelas, em que você pode selecionar uma tabela para ser eliminada. Open the Create Index wizard, where it is possible to define a new index on an existing database table. Abre o assistente de criação de índice, em que é possível definir um novo índice em um tabela de banco de dados já existente. &Preferences... &Configurações... Open the preferences window. Abre a janela de configurações. &DB Toolbar Barra de ferramentas do banco de &dados Shows or hides the Database toolbar. Exibe ou oculta a barra de ferramentas do banco de dados. Shift+F1 &Recently opened &Recentemente aberto Ctrl+T &Execute SQL &Executar SQL Save SQL file Salvar arquivo SQL Execute current line Executar linha atual Ctrl+E Export as CSV file Exportar como arquivo CSV Export table as comma separated values file Exportar tabela como CSV Save the current session to a file Salvar a atual sessão para um arquivo Load a working session from a file Carregar uma sessão de um arquivo Save SQL file as Salvar arquivo SQL como &Browse Table &Navegar tabela Copy Create statement Copiar comando Create Copy the CREATE statement of the item to the clipboard Copia o comando CREATE do item para a área de transferência Ctrl+Return Ctrl+L Ctrl+P Ctrl+D Ctrl+I Reset Window Layout Resetar layout da janela The database is currently busy. O banco de dados está ocupado. Click here to interrupt the currently running query. Clique aqui para interromper a consulta atual. Database encoding Codificação do banco de dados Database is encrypted using SQLCipher Banco de dados encriptado usando SQLCipher Choose a database file Escolha um arquivo de banco de dados Choose a filename to save under Escolha um nome de arquivo para salvar Are you sure you want to undo all changes made to the database file '%1' since the last save? Você tem certeza de que deseja desfazer todas as modificações feitas no arquivo de banco de dados '%1' desde o último salvamento? Choose a file to import Escolha um arquivo para importar Text files(*.sql *.txt);;All files(*) Arquivos de texto(*.sql *.txt);;Todos os arquivos(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Você deseja criar um novo arquivo de banco de dados para armazenar os dados importados? Se você disser que não, tentaremos importar os dados do arquivo SQL para o banco de dados atual. Ctrl+Tab Ctrl+Shift+Tab Clear List Window Layout Ctrl+Alt+0 Simplify Window Layout Alt+Shift+0 Dock Windows at Bottom Dock Windows at Left Side Dock Windows at Top Ctrl+Alt+W Choose a database file to save under Error while saving the database to the new file. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Você ainda está executando comandos SQL. Fechar o banco de dados agora fará a execução parar, talvez deixando o banco de dados em um estado inconsistente. Você tem certeza de que deseja fechar o banco de dados? Do you want to save the changes made to the project file '%1'? Você quer salvar as modificações feitas para o arquivo de projeto '%1'? Result: %1 Resulto: %1 File %1 already exists. Please choose a different name. Arquivo %1 já existe. Por favor, escolha um nome diferente. Error importing data: %1 Erro importando dados: %1 Import completed. Importação completa. Delete View Deletar vista Delete Trigger Deletar gatilho Delete Index Deletar índice Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Selecione a ação para aplicar ao %n arquivo dropado. <br/>Note que só 'Importar' vai processar mais de um arquivo. Selecione a ação para aplicar aos %n arquivos dropados. <br/>Note que só 'Importar' vai processar mais de um arquivo. Setting PRAGMA values will commit your current transaction. Are you sure? Definir valores de PRAGMA vai cometer sua transação atual. Você tem certeza? Do you want to save the changes made to SQL tabs in the project file '%1'? Você quer salvar as mudanças feitas nas abas de SQL no arquivo de projeto '%1'? Select SQL file to open Selecione arquivo SQL para abrir Select file name Selecione o nome do arquivo Select extension file Selecione o arquivo de extensão Extension successfully loaded. Extensão carregada com sucesso. Error loading extension: %1 Erro carregado extensão: %1 Don't show again Não mostrar novamente New version available. Nova versão disponível. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Uma nova vesão do DB Browser para SQLite está disponível (%1.%2.%3)<br/><br/>Por favor, baixe em <a href='%4'>%4</a>. DB Browser for SQLite project file (*.sqbpro) Arquivo de projeto DB Browser para SQLite (*.sqbpro) SQL &Log &Log do SQL Show S&QL submitted by Exibir S&QL enviado por &Plot &Plotar &Revert Changes &Reverter modificações &Write Changes &Escrever modificações &Database from SQL file... &Banco de dados a partir de arquivo SQL... &Table from CSV file... &Tabela a partir de arquivo CSV... &Database to SQL file... &Banco de dados para arquivo SQL... &Table(s) as CSV file... &Tabela para arquivo CSV... &Create Table... &Criar tabela... &Delete Table... &Deletar tabela... &Modify Table... &Modificar tabela... Create &Index... &Criar índice... W&hat's This? O &que é isso? Sa&ve Project &Salvar projeto Encrypted Encriptado Read only Somente leitura Database file is read only. Editing the database is disabled. Arquivo de banco de dados é somente leitura. Edição do banco de dados está desativada. Execution finished with errors. Execução finalizada com erros. Execution finished without errors. Execução finalizada sem erros. Edit Database &Cell Editar &célula do banco de dados DB Sche&ma Esque&ma do banco de dados Open SQL file(s) This button opens files containing SQL statements and loads them in new editor tabs Shift+F5 Opens the SQLCipher FAQ in a browser window Abre o FAQ do SQLCipher em uma janela do navegador Export one or more table(s) to a JSON file Exporta uma ou mais tabela(s) para um arquivo JSON Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Erro enquanto salvava o banco de dados. Isso indica que nem todas as mudanças foram salvas. Você precisa resolver o seguinte erro primeiro. %1 &Remote &Remoto Open an existing database file in read only mode Abre um banco de dados existente em modo somente leitura Could not open database file. Reason: %1 Não pôde abrir arquivo do banco de dados. Motivo: %1 Choose text files Escolha arquivos de texto Modify View Modificar vista Modify Trigger Modificar gatilho Modify Index Modificar índice Modify Table Modificar tabela Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Definir valores de PRAGMA ou fazer vacuum irá commitar sua transação atual. Deseja continuar? This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Essa é a estrutura do banco de dados aberto. Você pode arrastar comandos SQL de uma linha e soltá-los em outras aplicações ou em outra instância do DB Browser para SQLite. Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Alerta: esse pragma não é legível e esse valor foi inferido. Escrever o pragma pode sobrescrever um LIKE redefinido provido por uma extensão SQL. Too&ls Ferr&amentas Error Log Log de erros This button clears the contents of the SQL logs Esse botão limpa os logs do SQL This panel lets you examine a log of all SQL commands issued by the application or by yourself Esse painel deixa você examinar um log de todos os comandos SQL dados pela aplicação ou por você This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Essa é a estrutura do banco de dados aberto. Você pode arrastar múltiplos nomes de objetos da coluna Nome e largá-los no editor SQL e você pode ajustar as propriedades dos nomes largados usando o menu de contexto. Isso ajudaria você a compor comandos SQL. Você pode arrastar comandos SQL da coluna Esquema e largá-los no editor SQL ou em outras aplicações. Project Toolbar Barra de ferramentas do projeto Extra DB toolbar Barra de ferramentas do banco de dados extra Close the current database file Fechar o arquivo de banco de dados aberto &New Database This button closes the connection to the currently open database file Esse botão fecha a conexão com o arquivo aberto Ctrl+F4 &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Compact &Database... Compactar banco de &dados... Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. &About &Sobre New &tab This button opens a new tab for the SQL editor Esse botão abre uma nova aba para o editor SQL Execute all/selected SQL Executar todo/selecionado SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Esse botão executa o SQL selecionado. Se não existe SQL selecionado, todo o SQL é executado. Ctrl+Shift+T &Load Extension... &Carregar extensão... Execute line Executar linha This button executes the SQL statement present in the current editor line Esse botão executa o comando SQL presente na linha atual do editor &Wiki &Wiki F1 Bug &Report... &Reportar bug... Feature Re&quest... Re&quisitar feature... Web&site &Site &Donate on Patreon... &Doar no Patreon... &Save Project Open &Project... Abrir &projeto... Open &Project &Attach Database... &Anexar banco de dados... Add another database file to the current database connection Adiciona outro arquivo de banco de dados para a conexão atual This button lets you add another database file to the current database connection Esse botão deixa você adicionar outro banco de dados para a conexão atual com o banco de dados &Set Encryption... Definir en&criptação... This button saves the content of the current SQL editor tab to a file Esse botão salva o conteúdo do editor SQL para um arquivo SQLCipher &FAQ &FAQ do SQLCipher Table(&s) to JSON... Tabela(&s) para JSON... Open Data&base Read Only... Abrir &banco de dados somente leitura... Ctrl+Shift+O Save results Salvar resultados Save the results view Salvar a vista de resultados This button lets you save the results of the last executed query Esse botão deixa você salvar os resultados da última consulta executada Find text in SQL editor Encontrar texto no editor SQL Find Encontrar This button opens the search bar of the editor Esse botão abre a barra de busca do editor Ctrl+F Find or replace text in SQL editor Encontrar ou substituir texto no editor SQL Find or replace Encontrar ou substituir This button opens the find/replace dialog for the current editor tab Esse botão abre o diálogo de encontrar/substituir para a aba atual do editor Ctrl+H Export to &CSV Exportar para &CSV Export to &JSON Save as &view Salvar como &vista Save as view Salvar como vista Shows or hides the Project toolbar. Mostra ou oculta a barra de ferramentos do Projeto. Extra DB Toolbar Barra de ferramentas do banco de dados extra Ctrl+Shift+W Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Refresh Atualizar Reload the database structure This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Este botão lhe permite salvar todas as configurações associadas ao banco de dados aberto a um arquivo de projeto do DB Browser para SQLite &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs E&xecute SQL This has to be equal to the tab title in all the main tabs &Recent Files This button lets you open a DB Browser for SQLite project file Este botão lhe permite abrir um arquivo de projeto do DB Browser para SQLite &Open Database New In-&Memory Database Nova tabela em &memória Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Drag && Drop Qualified Names Arrastar e soltar nomes qualificados Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Use nomes qualificados (p.e. "Tabela"."Campo") quando arrastando objetos e soltando eles no editor Drag && Drop Enquoted Names Arrastar e soltar nomes entre áspas Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Use identificadores escapados (p.e. "Tabela1") quando arrastando e soltando objetos no editor &Integrity Check Teste de &integridade Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. Roda o teste de integridade sobre o banco de dados aberto e retorna os resultados na aba Executar SQL. &Foreign-Key Check Teste de chave &estrangeira Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Roda o teste de chave estrangeira sobre o banco de dados aberto e retorna os resultados na aba Executar SQL &Quick Integrity Check Teste de integridade &rápido Run a quick integrity check over the open DB Roda um teste de integridade rápido sobre o banco de dados aberto Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. Roda um outro pragma para a verificação de integridade do banco de dados. Faz quase tantos testes quando o outro PRAGMA mas executa muito mais rápido. &Optimize &Otimizar Attempt to optimize the database Tenta otimizar o banco de dados Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Roda o pragma de otimização sobre o banco de dados aberto. Esse pragma pode realizar otimizações que vão melhorar a performance de consultas futuras. Print Imprimir Print text from current SQL editor tab Imprimir texto do editor SQL Open a dialog for printing the text in the current SQL editor tab Abre um diálogo para imprimir o texto na aba atual do editor SQL Print the structure of the opened database Imprime a estrutura do banco de dados aberto Open a dialog for printing the structure of the opened database Abre um diálogo para imprimir a estrutura do banco de dados aberto Un/comment block of SQL code Comentar bloco de SQL Un/comment block Comentar bloco Comment or uncomment current line or selected block of code Comentar ou remover comentário da linha ou bloco atualmente selecionado Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Comentar ou remover comentários das linhas selecionadas ou da linha atual, se não há seleção. Todo o bloco é alterado de acordo com a primeira linha. Ctrl+/ Stop SQL execution Parar execução do SQL Stop execution Parar execução Stop the currently running SQL script Parar o script de SQL atualmente executando &Save Project As... &Salvar projeto como... Save the project in a file selected in a dialog Salvar o projeto em um arquivo selecionado em um diálogo Save A&ll Salvar &todos Save DB file, project file and opened SQL files Salvar arquivo do BD, arquivo do projeto e arquivos SQL abertos Ctrl+Shift+S Browse Table Navegar tabelas Close Pro&ject Close project and database files and return to the initial state Ctrl+Shift+F4 Detach Database Detach database file attached to the current database connection In-Memory database Banco de dados em memória Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Você tem certeza de que deseja deletar a tabela '%1'? Todos os dados associados com a tabela serão perdidos. Are you sure you want to delete the view '%1'? Você tem certeza que deseja deletar a vista '%1'? Are you sure you want to delete the trigger '%1'? Você tem certeza que deseja deletar o gatilho '%1'? Are you sure you want to delete the index '%1'? Você tem certeza que deseja deletar o índice '%1'? Error: could not delete the table. Erro: não pôde deletar a tabela. Error: could not delete the view. Erro: não pôde deletar a vista. Error: could not delete the trigger. Erro: não pôde deletar o gatilho. Error: could not delete the index. Erro: não pôde deletar o índice. Message from database engine: %1 Mensagem do banco de dados: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Editar a tabela requer salvar todas as mudanças pendentes agora. Você tem certeza que quer salvar o banco de dados? Edit View %1 Edit Trigger %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. Você já está executando comandos SQL. Você quer pará-los para executar os comandos atuais? Fechar o banco de dados agora pode deixá-lo em um estado inconsistente. -- EXECUTING SELECTION IN '%1' -- -- EXECUTANDO SELEÇÃO EM '%1' -- -- EXECUTING LINE IN '%1' -- -- EXECUTANDO LINHA EM '%1' -- -- EXECUTING ALL IN '%1' -- -- EXECUTANDO TUDO EM '%1' -- Opened '%1' in read-only mode from recent file list Opened '%1' from recent file list The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? DB file '%1' could not be opened This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Table '%1' not found; settings ignored -- Reference to file "%1" (not supported by this version) -- Project saved to file '%1' Projeto salvo no arquivo '%1' Yes. Don't ask again This action will open a new SQL tab with the following statements for you to edit and run: Rename Tab Renomear aba Duplicate Tab Duplicar aba Close Tab Fechar aba Opening '%1'... Abrindo '%1'... There was an error opening '%1'... Houve um erro abrindo '%1'... Value is not a valid URL or filename: %1 Valor não é uma URL ou nome de arquivo válido: %1 %1 rows returned in %2ms %1 linhas retornadas em %2 ms Automatically load the last opened DB file at startup At line %1: Na linha %1: Result: %2 Resultado: %2 Import completed. Some foreign key constraints are violated. Please fix them before saving. Importação completa. Algumas chaves estrangeiras são violadas. Por favor corrija-as antes de salvar. &%1 %2%3 &%1 %2%3 (read only) (somente leitura) Open Database or Project Abrir banco de dados ou projeto Attach Database... Anexar banco de dados... Import CSV file(s)... Importar arquivo(s) CSV... Do you want to save the changes made to SQL tabs in a new project file? Você quer salvar as mudanças feitas nas abas de SQL no arquivo de projeto? Do you want to save the changes made to the SQL file %1? Você quer salvar as alterações feitas ao arquivo SQL %1? Could not find resource file: %1 Não pôde encontrar o arquivo de recursos: %1 Choose a project file to open Escolha um arquivo de projeto para abrir Could not open project file for writing. Reason: %1 Não pôde abrir arquivo de projeto para a escrita. Motivo: %1 Collation needed! Proceed? Função de comparação necessária! Proceder? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Uma tabela nesse banco de dados requer uma função de comparação especial '%1' que esse aplicativo não pode prover. So você optar por proceder, esteja avisado de que coisas ruins podem acontecer para o seu banco de dados. Faça um backup! creating collation criando função de comparação Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Defina um novo nome para a aba de SQL. Use o caractere '&&' para poder usar o seguinte caractere como um atalho de teclado. Please specify the view name Por favor, especifique o nome da vista There is already an object with that name. Please choose a different name. Já existe um objeto com esse nome. Por favor, escolha um nome diferente. View successfully created. Vista criada com sucesso. Error creating view: %1 Erro criando vista: %1 This action will open a new SQL tab for running: Essa ação irá abrir uma nova aba SQL para rodar: Press Help for opening the corresponding SQLite reference page. Pressione Help para abrir a página de referência SQL correspondente. Busy (%1) Ocupado (%1) Error checking foreign keys after table modification. The changes will be reverted. Erro verificando as chaves estrangeiras após modificação. Mudanças serão revertidas. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Essa tabela não passou um teste de chave estrangeira.<br/>Você deveria rodar 'Ferramentas | Teste de Chave Estrangeira| e corrigir os problemas reportados. NullLineEdit Set to NULL Definir como NULL Alt+Del PlotDock Plot Plotar Columns Colunas X X Line type: Tipo da linha: None Nenhum Line Linha StepLeft Passo à esquerda StepRight Passo à direita StepCenter Passo centralizado Impulse Impulso Point shape: Ponto: Cross Cruz Plus Mais Circle Círculo Disc Disco Square Quadrado Diamond Diamante Star Estrela Triangle Triângulo TriangleInverted Triângulo Invertido CrossSquare Cruz Quadrado PlusSquare Mais Quadrado CrossCircle Cruz Círculo PlusCircle Mais Círculo Peace Paz <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Salvar plotagem atual...</p><p>Formato de arquivo definido pela extensão (png, jpg, pdf, bmp)</p></body></html> Save current plot... Salvar plotagem atual... Row # Coluna # Choose a filename to save under Escolha um nome de arquivo para salvar PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Todos os arquivos(*) <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Esse painel mostra a lista de colunas da tabela atualmente exibida ou a consulta recém executada. Você pode selecionar as colunas que você quer que sejam utilizadas como os eixos X e Y para o painel de plotagem abaixo. A tabela mostra o tipo detectado de exio que será utilizado na plotagem. For o eixo Y você só pode selecionar colunas numéricas, mas para o eixo X você pode selecionar:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data/Hora</span>: strings com o formato &quot;yyyy-MM-dd hh:mm:ss&quot; ou &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data</span>: strings com o formato &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hora</span>: strings com o formato &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Rótulo</span>: outros formatos de string. Selecionando essa coluna como X vai produzir um gráfico de barras com as colunas como rótulos para as barras</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numérico</span>: valores inteiros ou reais</li></ul><p>Clicando duas vezes nas células Y você pode mudar a cor usada para aquele gráfico.</p></body></html> Y1 Y1 Y2 Y2 Axis Type Tipo do eixo Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Aqui está um gráfico feito quando você seleciona os valores X e Y acima. Clique nos pontos para selecioná-los no gráfico e na tabela. Ctrl+Clique para selecionar um intervalo de pontos. Use o scroll do mouse para dar zoom e arraste o mouse para alterar o intervalo dos eixos. Selecione os eixos ou rótulos dos eixos para arrastar e dar zoom somente naquela orientação. Load all data and redraw plot Carregar todos os dados e plotar de novo Copy Copiar Show legend Mostrar legenda Stacked bars Barras empilhadas Fixed number format Date/Time Data/Hora Date Data Time Hora Numeric Numérico Label Rótulo Invalid Inválido Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Carregar todos os dados e plotar de novo. Aviso: nem todos os dados foram obtidos da tabela ainda devido ao mecanismo de obtenção parcial. Choose an axis color Escolher a cor do eixo There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Existem curvas nesse gráfico e o estilo de linha selecionado só pode ser aplicado para gráficos ordenados por X. Ou ordene a tabela ou consulte por X para remover curvas ou selecione um dos estilos suportados por curvas: Nenhum ou Linha. Loading all remaining data for this table took %1ms. Carregar os dados restantes para essa tabela levou %1ms. Print... Imprimir... PreferencesDialog Preferences Configurações &General &Geral Remember last location Lembrar do último diretório Always use this location Sempre usar esse diretório Remember last location for session only Lembrar do último diretório somente nessa sessão ... ... Default &location Diretório &padrão Lan&guage &Idioma Automatic &updates &Atualizações automáticas enabled ativado &Database &Banco de dados Database &encoding &Codificação do banco de dados Open databases with foreign keys enabled. Abrir bancos de dados com chaves estrangeiras ativado. &Foreign keys &Chaves estrangeiras Data &Browser Navegador de &dados &SQL &SQL Context Context Colour Cor Bold Negrito Italic Itálico Underline Underline Keyword Palavra-chave Function Função Table Tabela Comment Comentário Identifier Identificador String String Current line Linha atual SQL &editor font size Tamanho da fonte do &editor de SQL SQL editor &font &Fonte do editor de SQL &Extensions &Extensões Select extensions to load for every database: Selecione extensões para carregar para todos os bancos de dados: Add extension Adicionar extensão Remove extension Remover extensão <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>Embora suporte o operador REGEXP, SQLite não implementa expressões regulares mas recorre ao aplicativo em execução.<br/>DB Browser para SQLite implementa esse algoritmo para você poder utilizar REGEXP.<br/>Todavia, como existem múltiplas implementações possíveis desse algoritmo e você pode querer usar outra, você pode desativar a implementação do aplicativo e carregar a sua própria implementação através de uma extensão.<br/>Requer que o programa seja reiniciado.</p></body></html> Disable Regular Expression extension Desativar extensão de expressões regulares Choose a directory Escolha um diretório The language will change after you restart the application. A linguagem mudará após reiniciar o programa. Select extension file Selecione arquivo de extensão Extensions(*.so *.dylib *.dll);;All files(*) Extensões(*.so *.dylib *.dll);;Todos os arquivos(*) Save Settings File Initialization File (*.ini) The settings file has been saved in location : Open Settings File The settings file was loaded properly. The selected settings file is not a normal settings file. Please check again. Remove line breaks in schema &view Remover quebras de linhas em &vista de esquema Prefetch block si&ze &Tamanho de bloco de prefetch Default field type Tipo padrão de campo Font Fonte &Font &Fonte NULL NULL Regular Regular Binary Binário Background Fundo Filters Filtros Escape character Caractere de escape Delay time (&ms) Tempo de delay (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Definir o tempo de espera antes de aplicar um novo filtro de valor. Pode ser definido para zero para desativar espera. Tab size Tamanho de tabulação Error indicators Indicadores de erro Hori&zontal tiling Disposição &horizontal If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Se ativados, o editor de SQL e a tabela de resultados são exibidos lado a lado em vez de um sobre o outro. Code co&mpletion Co&mpletação de código Show remote options Mostrar opções remotas SQ&L to execute after opening database SQ&L para executar após abrir o banco de dados Content Conteúdo Symbol limit in cell Limite de símbolos na célula Threshold for completion and calculation on selection Limite de compleção e cálculo em seleção Show images in cell Mostrar imagens na célula Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Habilite essa opção para mostrar uma prévia de BLOBs contendo dados de imagens nas células. Isso pode afetar a performance do visualizados de dados. Remote Remoto CA certificates Certificados CA Subject CN Nome comum do sujeito Common Name Nome comum Subject O O do sujeito Organization Organização Valid from Válido de Valid to Válido para Serial number Número serial Your certificates Seus certificados File Arquivo Subject Common Name Nome comum do sujeito Issuer CN CN do emissor Issuer Common Name Nome Comum do emissor Import certificate file Importar certificado No certificates found in this file. Nem um certificado encontrado nesse arquivo. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Você tem certeza de que deseja remover esse certificado? Todos os dados do certificado serão deletados das configurações da aplicação! Clone databases into Clonar bancos de dados em Toolbar style Estilo da barra de ferramentas Only display the icon Exibir apenas o ícone Only display the text Exibir apenas o texto The text appears beside the icon O texto aparece ao lado do ícone The text appears under the icon O texto aparece sob o ícone Follow the style Seguir o estilo DB file extensions Extensões de arquivo de bancos de dados Manage Gerenciar Main Window Janela principal Database Structure Estrutura do banco de dados Browse Data Navegar dados Execute SQL Executar SQL Edit Database Cell Editar célula do banco de dados When this value is changed, all the other color preferences are also set to matching colors. Quando este valor é alterado, todas as outras preferências de cor são definidas para cores compatíveis. Follow the desktop style Seguir o estilo do desktop Dark style Estilo escuro Application style Estilo da aplicação This sets the font size for all UI elements which do not have their own font size option. Font size Max Recent Files Prompt to save SQL tabs in new project file If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Database structure font size Font si&ze &Tamanho da fonte This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Esse é o número máximo de itens permitidos para que algumas funcionalidades computacionalmente caras sejam habilitadas: Número máximo de linhas em uma tabela para habilitar compleção de valores baseada nos valores atualmente na coluna. Número máximo de índices em uma seleção para se calcular soma e média. Pode ser deixado em 0 para se desabilitar as funcionalidades. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Esse é o número máximo de linhas na tabela para preencher baseado nos valores atualmente na coluna. Pode ser 0 para desabilitar preenchimento. Field display Exibição do campo Light style Displayed &text &Texto exibido Formatted Click to set this color Clique para definir essa cor Text color Cor do texto Background color Cor do plano de fundo Preview only (N/A) Somente prévia (N/D) Foreground Plano de frente Selection background Selection foreground Highlight SQL &results font size Tamanho da fonte dos &resultados do SQL Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. &Wrap lines &Quebra de linhas Never Nunca At word boundaries Nos limites de palavras At character boundaries Nos limites de caractere At whitespace boundaries Nos limites de espaço em branco &Quotes for identifiers Ãspas &para identificadores Choose the quoting mechanism used by the application for identifiers in SQL code. Escolha as áspas utilizadas pela aplicação para identificadores no código SQL. "Double quotes" - Standard SQL (recommended) "Ãspas duplas" - SQL Padrão (recomendado) `Grave accents` - Traditional MySQL quotes `Crases`- MySQL tradicional [Square brackets] - Traditional MS SQL Server quotes [Colchetes] - MS SQL Server tradicional Keywords in &UPPER CASE Palavras-chave em &CAIXA ALTA When set, the SQL keywords are completed in UPPER CASE letters. Quando definido, as palavras-chave SQL serão completadas em CAIXA ALTA. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Quando definido, as linhas de código SQL que causaram erros durante a última execução são destacadas e os resultados indicam os erros no fundo Close button on tabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Select built-in extensions to load for every database: Proxy Proxy Configure Configurar Export Settings Import Settings Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Você tem certeza que deseja limpar as configurações salvas? Todas as suas preferências serão perdidas e os valores padrão serão utilizados. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Quando ativado, as quebras de linha na coluna Esquema da aba Estrutura do banco de dados e nas saídas impressas são removidas. <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite provê uma função SQL para carregar extensões de um arquivo de biblioteca. Ative isso se você quer usar a função <span style=" font-style:italic;">load_extension()</span> a partir de código SQL.</p><p>Por motivos de segurança, carregamento de extensões é desabilitado por padrão e precisa ser habilitado através dessa configuração. Você sempre pode carregar extensões através da interface gráfica, mesmo com essa opção desabilitada.</p></body></html> Allow loading extensions from SQL code Permitir o carregamento de extensões a partir de código SQL ProxyDialog Proxy Configuration Configuração do proxy Pro&xy Type Tipo do pro&xy Host Na&me No&me do host Port Porta Authentication Re&quired Au&tenticação necessária &User Name Nome do &usuário Password Senha None Nenhum System settings Configurações do sistema HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data Erro importando dados from record number %1 a partir de registro número %1 . %1 . %1 Cancel Cancelar All files (*) Todos arquivos (*) Importing CSV file... Importando arquivo CSV... SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Bancos de dados SQLite (*.db *.sqlite *.sqlite3 *.db3) Left Esquerda Right Direita Center Centro Justify Justificar SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) Arquivos de banco de dados SQL (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) Arquivo de projeto DB Browser para SQLite (*.sqbpro) SQL Files (*.sql) Arquivos SQL (*.sql) All Files (*) Todos arquivos (*) Text Files (*.txt) Arquivos de texto (*.txt) Comma-Separated Values Files (*.csv) Arquivos de valores separados por vírgulas (*.csv) Tab-Separated Values Files (*.tsv) Arquivos de valores separados por tabs (*.tsv) Delimiter-Separated Values Files (*.dsv) Arquivos de valores separados por delimitadores (*.dsv) Concordance DAT files (*.dat) Arquivos DAT Concordance (*.dat) JSON Files (*.json *.js) Arquivos JSON (*.json) XML Files (*.xml) Arquivos XML (*.xml) Binary Files (*.bin *.dat) Arquivos binários (*.bin) SVG Files (*.svg) Arquivos SVG (*.svg) Hex Dump Files (*.dat *.bin) Arquivos de dump hexadecimal (*.dat *.bin) Extensions (*.so *.dylib *.dll) Extensões (*.so *.dylib *.dll) Initialization File (*.ini) QsciCommand Paste Colar Cancel Cancelar QsciLexerCPP Keyword Palavra-chave Identifier Identificador QsciLexerJSON String String QsciLexerJavaScript Regular expression Expressão regular QsciLexerPython Comment Comentário Keyword Palavra-chave Identifier Identificador QsciLexerSQL Comment Comentário Keyword Palavra-chave Identifier Identificador QsciScintilla Select All Selecionar tudo RemoteCommitsModel Commit ID Message Date Data Author Size Tamanho Authored and committed by %1 Authored by %1, committed by %2 RemoteDatabase Error opening local databases list. %1 Erro abrindo lista local de bancos de dados. %1 Error creating local databases list. %1 Erro criando lista local de bancos de dados. %1 RemoteDock Remote Remoto Local Local Identity Identidade Push currently opened database to server Enviar o banco de dados aberto para o servidor Upload DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>Neste painel, bancos de dados remotos do dbhub.io podem ser adicionados ao DB Browser para SQLite. Primeiro você precisa adicionar uma identidade:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Entrar no dbhub.io (use suas credenciais do GitHub ou algum outro método)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Clique o botão para &quot;Gerar certificado do cliente&quot; (essa é sua identidade). Isto te dará um certificado (salve-o no disco local).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vá para a aba Remoto nas configurações do DB Browser para SQLite. Clique no botão para adicionar um novo certificado ao DB Browser para SQLite e escolha o arquivo recém baixado.</li></ol><p>Agora o painel remoto mostra sua identidade e você pode adicionar bancos de dados remotos.</p></body></html> Current Database Clone &User &Database &Banco de dados Branch Ramo Commits Commits for <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>Você está utilizando uma identidade somente leitura. Para fazer upload do seu banco de dados, você precisa configurar e usar a sua conta no DBHub.io.</p><p>Se você ainda não tem uma conta no DBHub, <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">crie uma agora</span></a> e importe seu certificado <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">aqui</span></a> para compartilhar os seus bancos de dados.</p><p>Para ajuda online, visite <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">este link</span></a>.</p></body></html> Back Voltar Delete Database Delete the local clone of this database Open in Web Browser Open the web page for the current database in your browser Clone from Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. Refresh Atualizar Reload all data and update the views Clone Database Open Database Open the local copy of this database Check out Commit Download and open this specific commit Check out Latest Commit Check out the latest commit of the current branch Save Revision to File Saves the selected revision of the database to another file Upload Database Upload this database as a new commit Select an identity to connect Public Público This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Invalid URL: The host name does not match the host name of the current identity. Invalid URL: No branch name specified. Invalid URL: No commit ID specified. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? The database has unsaved changes. Are you sure you want to push it before saving? The database you are trying to delete is currently opened. Please close it before deleting. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? RemoteLocalFilesModel Name Nome Branch Ramo Last modified Última modificação Size Tamanho Commit Commit File Arquivo RemoteModel Name Nome Last modified Última modificação Size Tamanho Size: Last Modified: Licence: Default Branch: Commit Commit RemoteNetwork Choose a location to save the file Error opening remote file at %1. %2 Erro abrindo arquivo remoto em %1. %2 Error: Invalid client certificate specified. Erro: Certificado de cliente inválido especificado. Please enter the passphrase for this client certificate in order to authenticate. Por favor entre a frase chave para esse certificado de cliente para se autenticar. Cancel Cancelar Uploading remote database to %1 Enviando banco de dados remoto para %1 Downloading remote database from %1 Baixando banco de dados remoto de %1 Error: Cannot open the file for sending. Erro: Não pôde abrir o arquivo para envio. RemotePushDialog Push database Enviar banco de dados Database na&me to push to No&me do banco de dados para enviar Commit message Mensagem de commit Username Database licence Licença do banco de dados Public Público Database will be public. Everyone has read access to it. Banco de dados será público. Todos poderão lê-lo. Database will be private. Only you have access to it. Banco de dados será privado. Somente você terá acesso a ele. Branch Ramo Force push Forçar envio Use with care. This can cause remote commits to be deleted. Use com cuidado. Isso pode causar a perda de commits remotos. RunSql Execution aborted by user Execução abortada pelo usuário , %1 rows affected , %1 linhas afetadas query executed successfully. Took %1ms%2 consulta executada com sucesso. Levou %1ms%2 executing query executando consulta SelectItemsPopup A&vailable &Disponível Sele&cted &Selecionado SqlExecutionArea Form Formulário <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>Resultados dos últimos comandos executados.</p><p>Você pode querer colapsar esse painel e usar o dock <span style=" font-style:italic;">Log SQL</span> com seleção <span style=" font-style:italic;">Usuário</span> em vez disso.</p></body></html> Results of the last executed statements Resultados dos últimos comandos executados This field shows the results and status codes of the last executed statements. Esse campo mostra os resultados e códigos de status dos últimos comandos executados. Find previous match [Shift+F3] Encontrar resultado anterior [Shift+F3] Find previous match with wrapping Encontrar resultado anterior com mapeamento Shift+F3 The found pattern must be a whole word O padrão encontrado precisa ser uma palavra inteira Whole Words Palavras inteiras Text pattern to find considering the checks in this frame Padrão de texto para encontrar considerando os testes nesse frame Find in editor Encontrar no editor The found pattern must match in letter case O padrão encontrado precisa casar em capitalização Case Sensitive Sensível à capitalização Find next match [Enter, F3] Encontrar próxima correspondência [Enter, F3] Find next match with wrapping Encontrar próxima correspondência no arquivo inteiro F3 Interpret search pattern as a regular expression Interpretar padrão de busca como expressão regular <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Quando assinalado, o padrão a ser buscado é interpretado como uma expressão regular UNIX. Veja <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression nos Wikibooks</a>.</p></body></html> Regular Expression Expressão Regular Close Find Bar Fechar barra de busca Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Couldn't save file: %1. Não pôde salvar arquivo: %1. Your changes will be lost when reloading it! Suas modificações serão perdidas quando recarregando! The file "%1" was modified by another program. Do you want to reload it?%2 O arquivo "%1" foi modificado por outro programa. Você quer recarregá-lo?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) A função abs(X) retorna o valor absoluto do argumento numérico X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) ltrim(X) removes spaces from the left side of X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X) rtrim(X) removes spaces from the right side of X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. (X) trim(X) removes spaces from both ends of X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () O número de linhas dentro da partição atual. Linhas são numeradas de 1 na ordem definida pela cláusula ORDER BY na definição da janela, ou de forma arbitrária. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () O row_number() do primeiro elemento de cada grupo - o rank da linha atual com gaps. Se não há uma cláusula ORDER BY, então todas as linhas são consideradas elementos e essa função sempre retorna 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () O número do grupo de colegas da linha atual dentro da sua partição - o rank da linha atual sem intervalos. Partições são numeradas a partir de 1 na ordem definida pela cláusula ORDER BY na definição. Se não há ORDER BY, então todas as linhas são consideradas colegas e essa função sempre retorna 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () Apesar do nome, essa função sempre retorna um valor entre 0.0 e 1.0 igual a (rank - 1)/(linhas-na-partição - 1), onde rank é o valor retornado pela built-in rank() e linhas-na-partição é o número total de linhas na partição. Se a partição contém somente uma linha, essa função retorna 0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () A distribuição cumulativa. Calculada como número-da-linha/linhas-na-partição em que número-da-linha é o valor retornado por row_number() para o último elemento do grupo e linhas-na-partição é o número de linhas na partição. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) Argumento N é interpretado como um inteiro. Essa função divide a partição em N grupos tão igualmente como possível e atribui um inteiro entre 1 e N para cada grupo, na ordem definida pela cláusula ORDER BY, ou em ordem arbitrária. Se necessário, grupos maiores ocorrem primeiro. Essa função retorna o valor inteiro atribuido ao grupo que a linha atual é parte de. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Retorna o resultado de avaliar expressão expr contra a linha anterior na partição. Ou, se não há linha anterior, NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) Se o offset é fornecido, então ele precisa ser um inteiro não-negativo. Nesse caso, o valor retornado é o resultado de avaliar expr contra a linha offset linhas antes da linha atual dentro da partição. Se offset é 0, então expr é avaliada contra a linha atual. Se não há linha offset linhas antes da linha atual, NULL é retornado. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) Se default também é fornecido, ele é retornado em vez de NULL se a linha identificada por offset não existe. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Retorna o resultado de avaliar a expressão expr contra a próxima linha na partição. Ou, se não há próxima linha, NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) Se o offset é fornecido, então ele precisa ser um inteiro não-negativo. Nesse caso, o valor retornado é o resultado de avaliar expr contra a linha offset linhas após a linha atual dentro da partição. Se offset é 0, então expr é avaliada contra a linha atual. Se não há linha offset linhas após a linha atual, NULL é retornado. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Essa função de janela built-in calcula o frame da janela para cada linha na mesma forma que uma função de janela agregada. Ela retorna o valor de expr avaliada contra a primeira linha do frame da janela para cada linha. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Essa função de janela built-in calcula o frame da janela para cada linha na mesma forma que uma função de janela agregada. Ela retorna o valor de expr avaliada contra a última linha do frame da janela para cada linha. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr) Essa função de janela built-in calcula o frame da janela para cada linha na mesma forma que uma função de janela agregada. Ela retorna o valor de expr avaliada contra a linha N do frame da janela para cada linha.Linhas são numeradas dentro do frame da janela começando em 1 na ordem definida pela cláusula ORDER BY se uma está presente, ou em ordem arbitrária, caso contrário. Se não há uma N-ésima linha na partição, NULL é retornado. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) A função load_extension(X) carrega extensões para SQLite a partir de um arquivo chamado X. Uso dessa função precisa ser autorizado em Preferências. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) A função load_extension(X) carrega extensões para SQLite a partir de um arquivo chamado X usando o ponto de entrada Y. Uso dessa função precisa ser autorizado em Preferências. SqliteTableModel Error changing data: %1 Erro modificando dados: %1 reading rows lendo linhas loading... carregando... References %1(%2) Hold %3Shift and click to jump there Referencia %1(%2) Segure %3Shift e clique para ir para lá retrieving list of columns obtendo lista de colunas Fetching data... Obtendo dados... Cancel Cancelar TableBrowser Browse Data Navegar dados &Table: &Tabela: Select a table to browse data Selecione uma tabela para navegar Use this list to select a table to be displayed in the database view Use esta lista para selecionar uma tabela para ser exibida na vista do banco de dados This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Essa é a vista de tabela do banco de dados. Você pode fazer as seguintes ações: - Começar a escrever para editar o valor. - Clicar duas vezes em qualquer registro para editar seus conteúdos no editor de célula. - Alt+Del para deletar o conteúdo da célula para NULL. - Ctrl+" para duplicar o registro atual. - Ctrl+' para copiar o valor da célula de cima. - Seleção normal para copiar e colar. Text pattern to find considering the checks in this frame Padrão de texto para encontrar considerando os testes nesse frame Find in table Encontrar na tabela Find previous match [Shift+F3] Encontrar resultado anterior [Shift+F3] Find previous match with wrapping Encontrar resultado anterior com mapeamento Shift+F3 Find next match [Enter, F3] Encontrar próxima correspondência [Enter, F3] Find next match with wrapping Encontrar próxima correspondência com quebra de linha F3 The found pattern must match in letter case O padrão encontrado precisa casar em capitalização Case Sensitive Sensível à capitalização The found pattern must be a whole word O padrão encontrado precisa ser uma palavra inteira Whole Cell Célula inteira Interpret search pattern as a regular expression Interpretar padrão de busca como expressão regular <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Quando marcado, o padrão para ser encontrado é interpretado como uma expressão regular do UNIX. Veja <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Expressão regular Close Find Bar Fechar barra de busca Text to replace with Texto para substituir com Replace with Substituir com Replace next match Substituir próxima correspondência Replace Substituir Replace all matches Substituir todas as correspondências Replace all Substituir todos Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Copy column name Copy the database table column name to your clipboard New Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Rolar para o começo</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Clicar nesse botão navega até o começo da vista de tabela acima.</p></body></html> |< |< Scroll one page upwards Rolar uma página para cima <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Clicando nesse botão navega uma página de registros para cima.</p></body></html> < < 0 - 0 of 0 0 - 0 de 0 Scroll one page downwards Rolar uma página para baixo <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Clicando nesse botão navega uma página de registros para baixo.</p></body></html> > > Scroll to the end Rolar para o fim <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>Clicar nesse botão navega para o fim da tabela acima.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>Clique aqui para pular para o registro especificado</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Esse botão navega para o registro especificado na área Ir para.</p></body></html> Go to: Ir para: Enter record number to browse Entre o número do registro para navegar Type a record number in this area and click the Go to: button to display the record in the database view Digite o número de um registro nessa área e clique no botão Ir para: para exibir o registro na vista do banco de dados 1 1 Show rowid column Mostrar coluna rowid Toggle the visibility of the rowid column Alternar a visibilidade da coluna rowid Unlock view editing Liberar edição da vista This unlocks the current view for editing. However, you will need appropriate triggers for editing. Isso libera a vista atual para edição. Todavia, você vai precisar dos gatilhos apropriados para editar. Edit display format Editar formato de exibição Edit the display format of the data in this column Editar o formato de exibição dos dados nessa coluna New Record Novo registro Insert a new record in the current table Inserir um novo registro na tabela atual <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Esse botão cria um novo registro no banco de dados. Segure o botão do mouse para abrir um menu de opções diferentes:</p><ul><li><span style=" font-weight:600;">Novo Registro</span>: insere um novo registro com valores padrão no banco de dados.</li><li><span style=" font-weight:600;">Inserir Valores...</span>: abre um diálogo para novos valores antes de serem inseridos no banco de dados. Isso permite a entrada de valores de acordo com as restrições. Esse diálogo também é abaerto se a opção<span style=" font-weight:600;">Novo Registro</span> falha devido a essas restrições.</li></ul></body></html> Delete Record Deletar registro Delete the current record Deletar o registro atual This button deletes the record or records currently selected in the table Esse botão deleta o registro ou registros selecionados Insert new record using default values in browsed table Inserir novo registro usando valores padrão na tabela Insert Values... Inserir valores... Open a dialog for inserting values in a new record Abre um diálogo para inserir valores em um novo registro Export to &CSV Exportar para &CSV Export the filtered data to CSV Exportar dados filtrados para CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Esse botão exporta os dados da tabela como atualmente exibidos como um arquivo CSV. Save as &view Salvar como &vista Save the current filter, sort column and display formats as a view Salva o filtro, ordenação e formato como uma vista This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Esse botão salva as configurações da tabela exibida como uma vista SQL que você pode utilizar em comandos SQL depois. Save Table As... Salvar tabela como... Save the table as currently displayed Salva a tabela como atualmente exibida <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>Esse Menu provê as seguintes opções para a tabela atual:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exportar para CSV: essa opção exporta os dados como estão exibidos para um arquivo CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Salvar como vista: essa opção salva a configuração atual da tabela como uma vista SQL que você depois pode consultar em comandos SQL.</li></ul></body></html> Hide column(s) Ocultar coluna(s) Hide selected column(s) Ocultar coluna(s) selecionada(s) Show all columns Mostrar todas as colunas Show all columns that were hidden Mostrar todas as colunas ocultas Set encoding Definir codificação Change the encoding of the text in the table cells Modificar a codificação do texto nas células da tabela Set encoding for all tables Modificar codificação para todas as tabelas Change the default encoding assumed for all tables in the database Modificar a codificação padrão assumida para todas as tabelas no banco de dados Clear Filters Limpar filtros Clear all filters Limpar todos os filtros This button clears all the filters set in the header input fields for the currently browsed table. Esse botão limpa todos os filtros definidos no cabeçalho para a tabela atualmente navegada. Clear Sorting Limpar ordenamento Reset the order of rows to the default Resetar a ordem das linhas para o padrão This button clears the sorting columns specified for the currently browsed table and returns to the default order. Esse botão limpa o ordenamento especificado para a tabela atual e volta para a ordem padrão. Print Imprimir Print currently browsed table data Imprimir dados da tabela atual Print currently browsed table data. Print selection if more than one cell is selected. Imprimir dados da tabela atual. Imprime a seleção se mais de uma célula está selecionada. Ctrl+P Refresh Atualizar Refresh the data in the selected table Atualizar os dados na tabela selecionada This button refreshes the data in the currently selected table. Este botão atualiza os dados na tabela atualmente selecionada. F5 Find in cells Encontrar em células Open the find tool bar which allows you to search for values in the table view below. Abre a barra de ferramentas para buscar que permite que você busque por valores na vista da tabela abaixo. Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally Bold Negrito Ctrl+B Italic Itálico Underline Sublinhado Ctrl+U Align Right Alinhar à direita Align Left Alinhar à esquerda Center Horizontally Centralizar horizontalmente Justify Justificar Edit Conditional Formats... Editar formatos condicionais... Edit conditional formats for the current column Editar os formatos condicionais para a coluna atual Clear Format Limpar formato Clear All Formats Limpar todos os formatos Clear all cell formatting from selected cells and all conditional formats from selected columns Limpa toda a formatação das células selecionadas e todos os formatos condicionais das colunas selecionadas Font Color Cor do texto Background Color Cor do plano de fundo Toggle Format Toolbar Alterar barra de ferramentas de formatação Show/hide format toolbar Mostrar/esconder barra de ferramentas de formatação This button shows or hides the formatting toolbar of the Data Browser Esse botão mostra ou esconde a barra de ferramentas de formatação do navegador de dados Select column Selecionar coluna Ctrl+Space Replace text in cells Substituir texto em células Filter in any column Ctrl+R %n row(s) %n linha(s) %n linhas , %n column(s) , %n coluna(s) , %n colunas . Sum: %1; Average: %2; Min: %3; Max: %4 . Soma: %1; Média: %2; Mínimo: %3; Máximo: %4 Conditional formats for "%1" Formatos condicionais para "%1" determining row count... determinando número de linhas... %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Por favor, entre uma pseudo-chave primária para habilitar edição nessa vista. Isso deveria ser o nome de uma coluna única na vista. Delete Records Deletar registros Duplicate records Duplicar registros Duplicate record Duplicar registro Ctrl+" Adjust rows to contents Ajustar linhas aos conteúdos Error deleting record: %1 Erro deletando registro: %1 Please select a record first Por favor, selecione um registro primeiro Please choose a new encoding for all tables. Por favor, escolha uma nova codificação para todas tabelas. Please choose a new encoding for this table. Por favor, escolha uma nova codificação para essa tabela. %1 Leave the field empty for using the database encoding. %1 Deixe o campo em branco para usar a codificação do banco de dados. This encoding is either not valid or not supported. Essa codificação é inválida ou não suportada. %1 replacement(s) made. %1 substituição(ões) feita(s). TableBrowserDock New Data Browser Rename Data Browser Close Data Browser Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. VacuumDialog Compact Database Compactar banco de dados Warning: Compacting the database will commit all of your changes. Alerta: compactando o banco de dados irá confirmar todas as suas modificações. Please select the databases to co&mpact: Por favor selecione o banco de dados para co&mpactar: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_ro.ts000066400000000000000000014074771463772530400252410ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Despre DB Browser for SQLite Version Versiune <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Adaugă ÃŽnregistrare Nouă Enter values for the new record considering constraints. Fields in bold are mandatory. IntroduceÈ›i valori pentru noua înregistrare luând în considerare constrângerile. Câmpurile îngroÈ™ate sunt obligatorii. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. ÃŽn coloana Valoare puteÈ›i specifica valoarea pentru câmpul identificat în coloana Nume. Coloana Tip indică tipul câmpului. Valorile implicite sunt afiÈ™ate în acelaÈ™i stil ca È™i valorile NULL. Name Nume Type Tip Value Valoare Values to insert. Pre-filled default values are inserted automatically unless they are changed. Valori de inserat. Valorile implicite precompletate sunt inserate automat, cu excepÈ›ia cazului în care sunt modificate. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Când editaÈ›i valorile din cadrul superior, interogarea SQL pentru inserarea acestei noi înregistrări este afiÈ™ată aici. PuteÈ›i edita manual interogarea înainte de a salva. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Salvează</span> va trimite instrucÈ›iunea SQL afiÈ™ată către baza de date pentru a insera noua înregistrare.</p><p><span style=" font-weight:600;">Restabilire Implicite</span> va restabili valorile iniÈ›iale din coloana<span style=" font-weight:600;">Valoare</span></p><p><span style=" font-weight:600;">Anulează</span> va închide acest dialog fără a executa interogarea.</p></body></html> Auto-increment Incrementare automată Unique constraint Constrângere unică Check constraint: %1 Verificare constrângere: %1 Foreign key: %1 Cheie străină: %1 Default value: %1 Valoare implicită: %1 Error adding record. Message from database engine: %1 Eroare la adăugarea înregistrării. Mesaj de la motorul bazei de date: %1 Are you sure you want to restore all the entered values to their defaults? Sigur doriÈ›i să restauraÈ›i toate valorile introduse la valorile implicite? Application Possible command line arguments: Posibile argumente ale liniei de comandă: The file %1 does not exist FiÈ™ierul %1 nu există The user settings file location is replaced with the argument value instead of the environment variable value. LocaÈ›ia fiÈ™ierului de setări al utilizatorului este înlocuită cu valoarea argumentului în loc de valoarea variabilei de mediu. Ignored environment variable (DB4S_SETTINGS_FILE) value: Valoare variabilă de mediu (DB4S_SETTINGS_FILE) ignorată: Usage Utilizare options opÈ›iuni database bază de date project proiect csv-file fiÈ™ier-csv Show command line options AfiÈ™ează opÈ›iunile liniei de comandă Exit application after running scripts IeÈ™ire din aplicaÈ›ie după rularea scripturilor file fiÈ™ier Execute this SQL file after opening the DB Execută acest fiÈ™ier SQL după deschiderea BD Import this CSV file into the passed DB or into a new DB Importă acest fiÈ™ier CSV în baza de date transmisă sau într-o bază de date nouă table tabel Browse this table, or use it as target of a data import RăsfoieÈ™te acest tabel sau utilizează-l ca È›intă a unui import de date Open database in read-only mode Deschide baza de date în modul doar-citire settings_file translation? fiÈ™ier_setări Run application based on this settings file Rulează aplicaÈ›ia pe baza acestui fiÈ™ier de setări group grup settings setări value valoare Run application with this setting temporarily set to value Rulează aplicaÈ›ia cu această setare temporar setată la valoare Run application saving this value for this setting Rulează aplicaÈ›ia salvând această valoare pentru această setare Display the current version AfiÈ™ează versiunea curentă Open this SQLite database Deschide această bază de date SQLite Open this project file (*.sqbpro) Deschide acest fiÈ™ier de proiect (*.sqbpro) Import this CSV file into an in-memory database translation? 'in-memory' Importă acest fiÈ™ier CSV într-o bază de date în-memorie The %1 option requires an argument OpÈ›iunea %1 necesită un argument The -S/--settings option requires an argument. The option is ignored. OpÈ›iunea -S/--settings necesită un argument. Această opÈ›iune este ignorată. The -o/--option and -O/--save-option options require an argument in the form group/setting=value OpÈ›iunile -o/--option È™i -O/--save-option necesită un argument în forma grup/setare=valoare Invalid option/non-existent file: %1 OpÈ›iune invalidă/fiÈ™ier inexistent: %1 SQLite Version Versiune SQLite SQLCipher Version %1 (based on SQLite %2) Versiune SQLCipher %1 (bazat pe SQLite %2) DB Browser for SQLite Version %1. DB Browser for SQLite Versiunea %1. Last commit hash when built: %1 Ultimul hash de comitere când a fost construit: %1 Built for %1, running on %2 Construit pentru %1, rulează pe %2 Qt Version %1 Versiune Qt %1 CipherDialog SQLCipher encryption Criptare SQLCipher &Password &Parolă &Reenter password &Reintroduce parola Passphrase visibility issue Frază De Acces Raw key unclear translation Cheia brută Encr&yption settings Setări de &criptare SQLCipher &3 defaults visibility issue SQLCipher &3 implicite SQLCipher &4 defaults visibility issue SQLCipher &4 implicite Custo&m Personaliza&t Page si&ze &Mărime pagină &KDF iterations IteraÈ›ii &KDF HMAC algorithm Algoritm HMAC KDF algorithm Algoritm KDF Plaintext Header Size Mărime Antet Text Simplu Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Vă rugăm să setaÈ›i o cheie pentru a cripta baza de date. ReÈ›ineÈ›i că, dacă modificaÈ›i oricare dintre celelalte setări opÈ›ionale, va trebui să le introduceÈ›i din nou de fiecare dată când deschideÈ›i fiÈ™ierul bazei de date. LăsaÈ›i câmpurile de parolă goale pentru a dezactiva criptarea. Procesul de criptare poate dura ceva timp È™i ar trebui să aveÈ›i o copie de rezervă a bazei de date! Modificările nesalvate sunt aplicate înainte de a modifica criptarea. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Vă rugăm să introduceÈ›i cheia utilizată pentru criptarea bazei de date. Dacă oricare dintre celelalte setări au fost modificate pentru acest fiÈ™ier de bază de date, trebuie să furnizaÈ›i È™i aceste informaÈ›ii. ColumnDisplayFormatDialog Choose display format Alege format de afiÈ™are Display format Format afiÈ™are Choose a display format for the column '%1' which is applied to each value prior to showing it. AlegeÈ›i un format de afiÈ™are pentru coloana '%1', care este aplicată fiecărei valori înainte de a o afiÈ™a. Default Implicit Decimal number Număr zecimal Exponent notation NotaÈ›ie exponentă Hex blob Blob Hex Hex number Număr Hex Octal number Numărul octal Round number Număr rotund Apple NSDate to date Apple NSDate în dată Java epoch (milliseconds) to date translation? 'Java epoch' Epoca Java (milisecunde) în dată .NET DateTime.Ticks to date .NET DateTime.Ticks în dată Julian day to date translation? 'Julian day' Zi Iuliană în dată Unix epoch to date translation? 'Unix epoch' Epoca Unix în dată Unix epoch to local time translation? 'Unix epoch Epoca unix în timp local WebKit / Chromium epoch to date translation? 'WebKit / Chromium epoch' Epoca WebKit / Chromium în dată WebKit / Chromium epoch to local time translation? 'WebKit / Chromium epoch' Epoca WebKit / Chromium în oră locală Windows DATE to date translation? 'Windows DATE' Windows DATE în dată Date as dd/mm/yyyy Dată ca dd/mm/yyyy Lower case Minusculă Upper case Majusculă Binary GUID to text GUID Binar în text SpatiaLite Geometry to SVG Geometrie SpatiaLite în SVG Custom Personalizat Custom display format must contain a function call applied to %1 unclear translation - 'call' Formatul de afiÈ™are personalizat trebuie să conÈ›ină un apel de funcÈ›ie aplicat la %1 Error in custom display format. Message from database engine: %1 Eroare în formatul de afiÈ™are personalizat. Mesaj de la motorul bazei de date: %1 Custom display format must return only one column but it returned %1. Formatul de afiÈ™are personalizat trebuie să returneze doar o singură coloană, dar a returnat %1. CondFormatManager Conditional Format Manager Manager Format CondiÈ›ional This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Acest dialog permite crearea È™i editarea formatelor condiÈ›ionale. Fiecare stil de celulă va fi selectat prin prima condiÈ›ie realizată pentru datele celulei respective. Formatele condiÈ›ionate pot fi mutate în sus È™i în jos, unde cele din rândurile superioare au prioritate față de cele din cele inferioare. Sintaxa pentru condiÈ›ii este aceeaÈ™i ca È™i pentru filtre È™i o condiÈ›ie goală se aplică tuturor valorilor. Add new conditional format Adaugă un nou format condiÈ›ional &Add &Adaugă Remove selected conditional format Elimină formatul condiÈ›ional selectat &Remove &Elimină Move selected conditional format up Mută formatul condiÈ›ional selectat în sus Move &up Mutare în &sus Move selected conditional format down Mută formatul condiÈ›ional selectat în jos Move &down Mutare în &jos Foreground Prim-plan Text color Culoare text Background Fundal Background color Culoare de fundal Font Font Size Mărime Bold ÃŽngroÈ™at Italic ÃŽnclinat Underline Subliniat Alignment Aliniere Condition CondiÈ›ie Click to select color FaceÈ›i clic pentru a selecta culoarea Are you sure you want to clear all the conditional formats of this field? SunteÈ›i sigur că doriÈ›i să È™tergeÈ›i toate formatele condiÈ›ionale ale acestui câmp? DBBrowserDB Please specify the database name under which you want to access the attached database Vă rugăm să specificaÈ›i numele bazei de date sub care doriÈ›i să accesaÈ›i baza de date ataÈ™ată Invalid file format Format fiÈ™ier invalid Do you really want to close this temporary database? All data will be lost. Chiar doriÈ›i să închideÈ›i această bază de date temporară? Toate datele vor fi pierdute. Do you want to save the changes made to the database file %1? DoriÈ›i să salvaÈ›i modificările aduse fiÈ™ierului bazei de date %1? Database didn't close correctly, probably still busy Baza de date nu s-a închis corect, probabil încă este ocupată Cannot open destination file: '%1' Nu se poate deschide fiÈ™ierul de destinaÈ›ie: '%1' Cannot backup to file: '%1'. Message: %2 Nu se poate face copie de rezervă în fiÈ™ierul: '%1'. Mesaj: %2 The database is currently busy: Baza de date este ocupată în prezent: Do you want to abort that other operation? Vrei să întrerupi cealaltă operaÈ›ie? Exporting database to SQL file... Exportând baza de date într-un fiÈ™ier SQL... Cancel Anulează No database file opened Nu este deschis niciun fiÈ™ier bază de date Executing SQL... Executând SQL... Action cancelled. AcÈ›iune anulată. Error in statement #%1: %2. Aborting execution%3. Eroare în instrucÈ›iunea #%1: %2. Se anulează execuÈ›ia%3. and rolling back unclear translation È™i derulând înapoi didn't receive any output from %1 nu s-a primit niciun rezultat de la %1 could not execute command: %1 nu se poate executa comanda: %1 Cannot delete this object Nu se poate È™terge acest obiect Cannot set data on this object Nu se pot seta date pe acest obiect A table with the name '%1' already exists in schema '%2'. Un tabel cu numele '%1' există deja în schema '%2'. No table with name '%1' exists in schema '%2'. Nu există tabel cu numele '%1' în schema '%2'. Cannot find column %1. Nu se poate găsi coloana %1. Creating savepoint failed. DB says: %1 Crearea punctului de salvare a eÈ™uat. BD spune: %1 Renaming the column failed. DB says: %1 Redenumirea coloanei a eÈ™uat. BD spune: %1 Releasing savepoint failed. DB says: %1 Eliberarea punctului de salvare a eÈ™uat. BD spune: %1 Creating new table failed. DB says: %1 Crearea unui nou tabel a eÈ™uat. BD spune: %1 Copying data to new table failed. DB says: %1 Copierea datelor într-un nou tabel a eÈ™uat. BD spune: %1 Deleting old table failed. DB says: %1 Ștergerea tabelului vechi a eÈ™uat. BD spune: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Restaurarea unora dintre obiectele asociate cu acest tabel a eÈ™uat. Acest lucru este cel mai probabil pentru că unele nume de coloane s-au schimbat. Aici este instrucÈ›iunea SQL pe care s-ar putea să doriÈ›i să o reparaÈ›i È™i să o executaÈ›i manual: Error renaming table '%1' to '%2'. Message from database engine: %3 Eroare la redenumirea tabelului '%1' la '%2'. Mesaj de la motorul bazei de date: %3 could not get list of db objects: %1 nu s-a putut obÈ›ine lista obiectelor bd: %1 could not get list of databases: %1 nu s-a putut obÈ›ine lista bazelor de date: %1 Error setting pragma %1 to %2: %3 Eroare la setarea pragma %1 la %2: %3 File not found. FiÈ™ierul nu a fost găsit. Error loading extension: %1 Eroare la încărcarea extensiei: %1 Error loading built-in extension: %1 could not get column information nu s-a putut obÈ›ine informaÈ›ia coloanei DbStructureModel Name Nume Object Obiect Type Tip Schema Schemă Database Bază De Date Browsables Navigabile All Toate Temporary Temporar Tables (%1) Tabele (%1) Indices (%1) Indici (%1) Views (%1) Vederi (%1) Triggers (%1) DeclanÈ™atoare (%1) EditDialog Edit database cell Editează celula bazei de date This area displays information about the data present in this database cell Această zonă afiÈ™ează informaÈ›ii despre datele prezente în această celulă a bazei de date Mode: Mod: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Aceasta este lista modurilor suportate pentru editorul de celule. Alege un mod pentru vizualizarea sau editarea datelor celulei curente. Text Text RTL Text Text RLT Binary Binar Image Imagine JSON JSON XML XML Automatically adjust the editor mode to the loaded data type Ajustează automat modul editorului la tipul de date încărcat This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Acest buton bifabil activează sau dezactivează comutarea automată a modului editorului. Când este selectată o celulă nouă sau sunt importate date noi È™i comutarea automată este activată, modul se ajustează la tipul de date detectat. Apoi puteÈ›i schimba manual modul editorului. Dacă doriÈ›i să păstraÈ›i acest mod de comutare manuală în timp ce vă deplasaÈ›i prin celule, dezactivaÈ›i butonul. Auto-switch Comutare automată This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Acest editor Qt este utilizat pentru scripturi de la dreapta la stânga, care nu sunt acceptate de editorul de text implicit. PrezenÈ›a caracterelor de la dreapta la stânga este detectată È™i acest mod de editor este selectat automat. Apply data to cell Aplică datele în celulă This button saves the changes performed in the cell editor to the database cell. Acest buton salvează modificările efectuate în editorul de celule la celula bazei de date. Apply Aplică Print... Imprimare... Ctrl+P Ctrl+P Open preview dialog for printing displayed text Deschidere dialog de previzualizare pentru imprimarea textului afiÈ™at Evaluation Evaluare Identification of the cell currently in the editor Identificarea celulei aflate în prezent în editor Type and size of data currently in table Tipul È™i mărimea datelor aflate în prezent în tabel Open preview dialog for printing the data currently stored in the cell Deschidere dialog de previzualizare pentru imprimarea datelor stocate în prezent în celulă Copy Hex and ASCII Copiază Hex È™i ASCII Copy selected hexadecimal and ASCII columns to the clipboard Copiază coloanele hexazecimale È™i ASCII selectate în clipboard Ctrl+Shift+C Ctrl+Shift+C Autoformat Formatare Automată Auto-format: pretty print on loading, compact on saving. Formatare automată: imprimare frumoasă la încărcare, compact la salvare. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Când este activată, funcÈ›ia de formatare automată formatează datele la încărcare, împărÈ›ind textul în linii È™i indentându-l pentru o lizibilitate maximă. La salvarea datelor, funcÈ›ia de formatare automată compactează datele, eliminând capetele liniilor È™i spaÈ›iile albe inutile. &Export... &Exportă... Export to file Exportă în fiÈ™ier Opens a file dialog used to export the contents of this database cell to a file. Deschide un dialog de fiÈ™ier utilizat pentru a exporta conÈ›inutul acestei celule a bazei de date într-un fiÈ™ier. &Import... &Importă... Import from file Importă din fiÈ™ier Opens a file dialog used to import any kind of data to this database cell. Deschide un dialog de fiÈ™ier utilizat pentru a importa orice tip de date în această celulă a bazei de date. Set as &NULL Setează ca &NULL Erases the contents of the cell Șterge conÈ›inutul celulei Word Wrap ÃŽnfășurare Cuvânt Wrap lines on word boundaries ÃŽnfășoară linii pe limitele cuvintelor Open in default application or browser Deschide în aplicaÈ›ia sau browserul implicit Open in application Deschide în aplicaÈ›ie The value is interpreted as a file or URL and opened in the default application or web browser. Valoarea este interpretată ca un fiÈ™ier sau o adresă URL È™i deschis în aplicaÈ›ia sau în browserul web implicit. Save file reference... Salvează referinÈ›a fiÈ™ierului... Save reference to file Salvează referinÈ›a în fiÈ™ier Open in external application Deschide într-o aplicaÈ›ie externă The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Modurile editorului de text vă permit să editaÈ›i text simplu, precum È™i date JSON sau XML cu evidenÈ›iere a sintaxei, formatare automată È™i validare înainte de salvare. Erorile sunt indicate cu o subliniere roÈ™ie. ÃŽn modul Evaluare, expresiile SQLite introduse sunt evaluate È™i rezultatul aplicat celulei. Unsaved data in the cell editor Date nesalvate în editorul de celule The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editorul de celule conÈ›ine date care nu au fost încă aplicate în baza de date. DoriÈ›i să aplicaÈ›i datele editate la rândul=%1, coloana=%2? Editing row=%1, column=%2 Editând rând=%1, coloană=%2 No cell active. Nicio celulă activă. Image data can't be viewed in this mode. Datele de imagine nu pot fi vizualizate în acest mod. Try switching to Image or Binary mode. ÃŽncercaÈ›i să comutaÈ›i la modul imagine sau binar. Binary data can't be viewed in this mode. Datele binare nu pot fi vizualizate în acest mod. Try switching to Binary mode. ÃŽncercaÈ›i să comutaÈ›i la modul binar. Image files (%1) FiÈ™iere de imagine (%1) Choose a file to import Alege un fiÈ™ier pentru import %1 Image %1 Imagine Binary files (*.bin) FiÈ™iere binare (*.bin) Choose a filename to export data Alege un nume de fiÈ™ier pentru a exporta datele Invalid data for this mode Date invalide pentru acest mod The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? Celula conÈ›ine date %1 invalide. Motiv: %2. Chiar doriÈ›i să o aplicaÈ›i celulei? Type: NULL; Size: 0 bytes Tip: NULL; Mărime: 0 octeÈ›i Type: Text / Numeric; Size: %n character(s) Tip: Text / Numeric; Mărime: %n caracter Tip: Text / Numeric; Mărime: %n caractere Tip: Text / Numeric; Mărime: %n caractere Type: %1 Image; Size: %2x%3 pixel(s) Tip: %1 Imagine; Mărime: %2x%3 pixel(i) Type: Valid JSON; Size: %n character(s) Tip: JSON Valid; Mărime: %n caracter Tip: JSON Valid; Mărime: %n caractere Tip: JSON Valid; Mărime: %n caractere Type: Binary; Size: %n byte(s) Tip: Binar; Mărime: %n octet Tip: Binar; Mărime: %n octeÈ›i Tip: Binar; Mărime: %n octeÈ›i Couldn't save file: %1. Nu s-a putut salva fiÈ™ierul: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Datele au fost salvate într-un fiÈ™ier temporar È™i au fost deschise cu aplicaÈ›ia implicită. Acum puteÈ›i edita fiÈ™ierul È™i, când sunteÈ›i gata, aplicaÈ›i noile date salvate în celulă sau anulaÈ›i orice modificare. EditIndexDialog Edit Index Schema Editează Schema Indicelui &Name &Nume &Table &Tabel &Unique &Unic For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Pentru restricÈ›ionarea indicelui doar la o parte a tabelului, puteÈ›i specifica aici o clauză WHERE care selectează partea din tabel care ar trebui indexată Partial inde&x clause Clauză &indice parÈ›ial Colu&mns &Coloane Table column Coloană tabel Type Tip Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Adăugă o nouă coloană de expresie la indice. Coloanele de expresie conÈ›in expresie SQL mai degrabă decât nume de coloane. Index column Coloană indice Order Ordine Deleting the old index failed: %1 Ștergerea indicelui vechi a eÈ™uat: %1 Creating the index failed: %1 Crearea indicelui a eÈ™uat: %1 EditTableDialog Edit table definition Editează definiÈ›ia tabelului Table Tabel Advanced Avansat Database sche&ma &Schemă bază de date Without Rowid Without Rowid Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict ÃŽn Caz De Conflict Strict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Când opÈ›iunea strict este activată, SQLite aplică tipurile de date ale fiecărei coloane la actualizarea sau inserarea datelor. Fields Câmpuri Add Adăuga Remove Elimină Move to top MutaÈ›i la început Move up Mutare în sus Move down Mutare în jos Move to bottom Mutare la capăt Name Nume Type Tip NN NN Not null Non-null PK translation? - clarification needed CP <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> Cheie primară</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> Cheie Străină</p></body></html> Index Constraints Constrângeri Indice AI AI Autoincrement Incrementare Automată U U Unique Unic Default Implicit Default value Valoare implicită Check Verificare Check constraint Verificare constrângere Collation ColaÈ›ionare Foreign Key Cheie Străină Add constraint Adaugă constrângere Remove constraint Elimină constrângere Columns Coloane SQL SQL Foreign Keys Chei Străine References ReferinÈ›e Check Constraints unclear translation Verificare Constrângeri <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> tentative translation 'parser' <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Avertisment: </span>Există ceva cu această definiÈ›ie a tabelului pe care analizatorul nostru nu îl înÈ›elege pe deplin. Modificarea È™i salvarea acestui tabel poate duce la probleme.</p></body></html> Primary Key Cheie Primară Add a primary key constraint Adaugă o constrângere de cheie primară Add a unique constraint Adaugă o constrângere unică There can only be one primary key for each table. Please modify the existing primary key instead. Nu poate exista decât o singură cheie primară pentru fiecare tabel. Vă rugăm să modificaÈ›i cheia primară existentă în schimb. Error creating table. Message from database engine: %1 Eroare la crearea tabelului. Mesaj de la motorul de baze de date: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Există deja un câmp cu acest nume. Vă rugăm să îl redenumiÈ›i mai întâi sau să alegeÈ›i un alt nume pentru acest câmp. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Această coloană este menÈ›ionată într-o cheie străină în tabelul %1 È™i, prin urmare, numele său nu poate fi schimbat. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Există cel puÈ›in un rând cu acest câmp setat la NULL. Acest lucru face imposibilă setarea acestui steag. Vă rugăm să modificaÈ›i mai întâi datele tabelului. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Există cel puÈ›in un rând cu o valoare non-întreagă în acest câmp. Acest lucru face imposibilă setarea steagului AI. Vă rugăm să modificaÈ›i mai întâi datele tabelului. Column '%1' has duplicate data. Coloana '%1' are date duplicate. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Acest lucru face imposibilă activarea steagului 'Unic'. Vă rugăm să eliminaÈ›i datele duplicate, ceea ce va permite activarea steagului 'Unic'. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Sigur doriÈ›i să È™tergeÈ›i câmpul '%1'? Toate datele stocate în prezent în acest câmp vor fi pierde. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Vă rugăm să adăugaÈ›i un câmp care îndeplineÈ™te următoarele criterii înainte de a seta steagul without rowid: - Steag de cheie primară setat - Incrementare automată dezactivată Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set Vă rugăm să adăugaÈ›i un câmp care îndeplineÈ™te următoarele criterii înainte de a seta acÈ›iunea on conflict: - Steag de cheie primară setat ExportDataDialog Export data as CSV Exportă date ca CSV Tab&le(s) &Tabel(e) Colu&mn names in first line Nume coloane în &prima linie Fie&ld separator &Separator câmp , , ; ; Tab Tab | | Other Altul &Quote character Caracter de &citatre " " ' ' New line characters Caractere linie nouă Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print Imprimare frumoasă Export data as JSON Exportă datele ca JSON exporting CSV exportând CSV Error while writing the file '%1': %2 Eroare la scrierea fiÈ™ierului '%1': %2 Could not open output file: %1 Nu s-a putut deschide fiÈ™ierul de ieÈ™ire: %1 exporting JSON exportând JSON Choose a filename to export data Alege un nume de fiÈ™ier pentru a exporta date Please select at least 1 table. Vă rugăm să selectaÈ›i cel puÈ›in 1 tabel. Choose a directory Alege un dosar Export completed. Export finalizat. Export finished with errors. Exportul finalizat cu erori. ExportSqlDialog Export SQL... Exportă SQL... Tab&le(s) &Tabel(e) Select All Selectează Toate Deselect All Deselectează Toate &Options &OpÈ›iuni Keep column names in INSERT INTO Păstrează numele coloanelor în INSERT INTO Multiple rows (VALUES) per INSERT statement Multiple rânduri (VALUES) per instrucÈ›iune INSERT Export everything Exportă totul Export schema only Exportă doar schema Export data only Exportă doar date Keep original CREATE statements Păstrează instrucÈ›iunile CREATE originale Keep old schema (CREATE TABLE IF NOT EXISTS) Păstrează schema veche (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Suprascrie schema veche (DROP TABLE, apoi CREATE TABLE) Please select at least one table. Vă rugăm să selectaÈ›i cel puÈ›in un tabel. Choose a filename to export Alege un nume de fiÈ™ier pentru a exporta Export completed. Export finalizat. Export cancelled or failed. Export anulat sau eÈ™uat. ExtendedScintilla Ctrl+H Ctrl+H Ctrl+F Ctrl+F Ctrl+P Ctrl+P Find... GăseÈ™te... Find and Replace... GăseÈ™te È™i ÃŽnlocuieÈ™te... Print... Imprimare... ExtendedTableWidget Use as Exact Filter FoloseÈ™te ca Filtru Exact Containing ConÈ›inând Not containing Nu conÈ›ine Not equal to Nu este egal cu Greater than Mai mare ca Less than Mai mic ca Greater or equal Mai mare sau egal Less or equal Mai mic sau egal Between this and... ÃŽntre asta È™i... Regular expression Expresie regulată Edit Conditional Formats... Editează Formatele CondiÈ›ionale... Set to NULL Setează la NULL Cut Taie Copy Copiază Copy with Headers Copiază cu anteturi Copy as SQL Copiază ca SQL Paste LipeÈ™te Print... Imprimare... Use in Filter Expression Utilizează în Filtru Expresie Alt+Del Alt+Del Ctrl+Shift+C Ctrl+Shift+C Ctrl+Alt+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? ConÈ›inutul clipboard-ului este mai mare decât intervalul selectat. DoriÈ›i să îl inseraÈ›i oricum? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>Nu toate datele au fost încărcate. <b>DoriÈ›i să încărcaÈ›i toate datele înainte de a selecta toate rândurile?</b><p><p>Răspunzând<b>Nu</b> înseamnă că nu vor mai fi încărcate date È™i selecÈ›ia nu va fi efectuată.<br/>Răspunzând <b>Da</b> ar putea dura ceva timp până când datele sunt încărcate, dar selecÈ›ia va fi completă.</p>Avertisment: ÃŽncărcarea tuturor datelor poate necesita o cantitate mare de memorie pentru tabelele mari. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. Nu se poate seta selecÈ›ia la NULL. Coloana %1 are o constrângere NOT NULL. FileExtensionManager File Extension Manager Manager Extensii De FiÈ™iere &Up &Sus &Down &Jos &Add &Adaugă &Remove &Elimină Description Descriere Extensions Extensii *.extension translation? *.extensie FilterLineEdit Filter Filtru These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression unclear translation - 'wildcard' Aceste câmpuri de intrare vă permit să efectuaÈ›i filtre rapide în tabelul selectat în prezent. ÃŽn mod implicit, rândurile care conÈ›in textul de intrare sunt filtrate. Următorii operatori sunt, de asemenea, suportaÈ›i: % Șablon > Mai mare ca < Mai mic ca >= Egal cu sau mai mare <= Egal cu sau mai mic = Egal cu: potrivire exactă <> Inegal: potrivire exactă inversă x~y Interval: valori între x È™i y / regexp/ Valori care se potrivesc cu expresia regulată Set Filter Expression Setează Expresie Filtru What's This? Ce este asta? Is NULL Este NULL Is not NULL Nu este NULL Is empty Este gol Is not empty Nu este gol Not containing... Nu conÈ›ine... Equal to... Egal cu... Not equal to... Nu este egal cu... Greater than... Mai mare ca... Less than... Mai mic ca... Greater or equal... Mai mare sau egal... Less or equal... Mai mic sau egal... In range... ÃŽn gamă... Regular expression... Expresie regulată... Clear All Conditional Formats Șterge Toate Formatele CondiÈ›ionate Use for Conditional Format Utilizare pentru Format CondiÈ›ionat Edit Conditional Formats... Editează Formatele CondiÈ›ionate... FindReplaceDialog Find and Replace GăseÈ™te È™i ÃŽnlocuieÈ™te Fi&nd text: &GăseÈ™te text: Re&place with: ÃŽn&locuieÈ™te cu: Match &exact case visibility issue Potrivire caz &exact Match &only whole words visibility issue PotrivÈ™ete numai cuvinte în&tregi When enabled, the search continues from the other end when it reaches one end of the page Când este activată, căutarea continuă de la celălalt capăt când ajunge la un capăt al paginii &Wrap around ÃŽn&fășoară în jur When set, the search goes backwards from cursor position, otherwise it goes forward Când este setat, căutarea merge în sens invers din poziÈ›ia cursorului, altfel merge înainte Search &backwards Căutare &inversă <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>Când este bifat, modelul de găsit este căutat numai în selecÈ›ia curentă.</p></body></html> &Selection only Numai &selecÈ›ie <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Când este bifat, modelul de găsit este interpretat ca o expresie regulată UNIX. Vezi <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Use regular e&xpressions visibility issue FoloseÈ™te expresii &regulate Find the next occurrence from the cursor position and in the direction set by "Search backwards" GăseÈ™te următoarea apariÈ›ie din poziÈ›ia cursorului È™i în direcÈ›ia setată de "Căutare inversă" &Find Next GăseÈ™te &Următorul F3 F3 &Replace ÃŽnlo&cuieÈ™te Highlight all the occurrences of the text in the page EvidenÈ›iază toate apariÈ›iile textului în pagină F&ind All GăseÈ™te T&oate Replace all the occurrences of the text in the page ÃŽnlocuieÈ™te toate apariÈ›iile textului în pagină Replace &All ÃŽnlocuieÈ™te To&ate The searched text was not found Textul căutat nu a fost găsit The searched text was not found. Textul căutat nu a fost găsit. The searched text was replaced one time. Textul căutat a fost înlocuit o dată. The searched text was found one time. Textul căutat a fost găsit o dată. The searched text was replaced %1 times. Textul căutat a fost înlocuit de %1 ori. The searched text was found %1 times. Textul căutat a fost găsit de %1 ori. ForeignKeyEditor &Reset &Resetează Foreign key clauses (ON UPDATE, ON DELETE etc.) Clauze Cheie Externă (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Vizualizator Imagine Reset the scaling to match the original size of the image. Resetează scalarea pentru a se potrivi cu mărimea originală a imaginii. Set the scaling to match the size of the viewport. Setează scalarea pentru a se potrivi cu mărimea ferestrei de vizualizare. Print... Imprimare... Open preview dialog for printing displayed image Deschide dialog de previzualizare pentru imprimarea imaginii afiÈ™ate Ctrl+P Ctrl+P ImportCsvDialog Import CSV file Importă fiÈ™ier CSV Table na&me &Nume tabel &Column names in first line Nume de coloane în &prima linie Field &separator &Separator câmp , , ; ; Tab Tab | | Other (printable) Altul (imprimabil) Other (code) Altul (cod) &Quote character Caracter de c&itare " " ' ' &Encoding &Codificare UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Other Altul Trim fields? Taie câmpurile? Separate tables Tabele separate Advanced Avansat When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Atunci când se importă o valoare goală din fiÈ™ierul CSV într-un tabel existent cu o valoare implicită pentru această coloană, valoarea implicită este inserată. ActivaÈ›i această opÈ›iune pentru a insera în schimb o valoare goală. Ignore default &values Ignoră &valorile implicite Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. ActivaÈ›i această opÈ›iune pentru a opri importul atunci când încercaÈ›i să importaÈ›i o valoare goală într-o coloană NOT NULL fără o valoare implicită. Fail on missing values EÈ™uează la valori lipsă Disable data type detection Dezactivează detectarea tipului de date Disable the automatic data type detection when creating a new table. DezactivaÈ›i detectarea automată a tipului de date la crearea unui tabel nou. Use local number conventions Utilizează convenÈ›iile numerice locale Use decimal and thousands separators according to the system locale. Utilizează separatori de zecimale È™i mii în funcÈ›ie de sistemul local. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Când importaÈ›i într-un tabel existent cu o cheie primară, constrângeri unice sau un indice unic, există È™ansa unui conflict. Această opÈ›iune vă permite să selectaÈ›i o strategie pentru acest caz: în mod implicit, importul este anulat È™i derulat înapoi, dar puteÈ›i alege, de asemenea, să ignoraÈ›i È™i să nu importaÈ›i rânduri conflictuale sau să înlocuiÈ›i rândul existent în tabel. Abort import Anulare import Ignore row Ignoră rând Replace existing row ÃŽnlocuire rând existent Conflict strategy Strategia conflictului Deselect All Deselectează Toate Match Similar Potrivire Similară Select All Selectează Toate There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Există deja un tabel numit '%1 ' È™i un import într-un tabel existent este posibil numai dacă numărul de coloane se potriveÈ™te. There is already a table named '%1'. Do you want to import the data into it? Există deja un tabel numit '%1'. DoriÈ›i să importaÈ›i datele în el? Creating restore point failed: %1 Crearea punctului de restaurare a eÈ™uat: %1 Creating the table failed: %1 Crearea tabelului a eÈ™uat: %1 importing CSV importând CSV Could not prepare INSERT statement: %1 Nu s-a putut pregăti instrucÈ›iunea INSERT: %1 Inserting row failed: %1 Inserarea rândului a eÈ™uat: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. SfârÈ™it neaÈ™teptat de fiÈ™ier. Vă rugăm să vă asiguraÈ›i că aÈ›i configurat caracterele de citare corecte È™i că fiÈ™ierul nu este malformat. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Importarea fiÈ™ierului '%1' a durat %2ms. Din aceasta, %3ms au fost petrecute în funcÈ›ia de rând. MainWindow DB Browser for SQLite DB Browser for SQLite This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Aceasta este structura bazei de date deschise. PuteÈ›i glisa instrucÈ›iuni SQL dintr-un rând de obiect È™i să le plasaÈ›i în alte aplicaÈ›ii sau într-o altă instanță 'DB Browser for SQLite'. Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Avertisment: acest pragma nu poate fi citit È™i această valoare a fost dedusă. Scrierea pragma ar putea suprascrie un LIKE redefinit furnizat de o extensie SQLite. toolBar1 barăDeInstrumente1 &File &FiÈ™ier &Import &Importă &Export &Exportă &Edit &Editează &View &Vizualizare &Help &Ajutor DB Toolbar Bară de instrumente BD Edit Database &Cell Editează &Celula Bazei De Date SQL &Log &Jurnal SQL Show S&QL submitted by Arată S&QL trimis de User Utilizator Application AplicaÈ›ie Error Log Jurnal De Erori This button clears the contents of the SQL logs Acest buton È™terge conÈ›inutul jurnalelor SQL &Clear &Golire This panel lets you examine a log of all SQL commands issued by the application or by yourself Acest panou vă permite să examinaÈ›i un jurnal al tuturor comenzilor SQL emise de către aplicaÈ›ie sau de către dumneavoastră &Plot G&rafic DB Sche&ma Sche&mă BD This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Aceasta este structura bazei de date deschise. PuteÈ›i să glisaÈ›i mai multe nume de obiecte din coloana Nume È™i să le plasaÈ›i în editorul SQL È™i puteÈ›i ajusta proprietățile numelor plasate utilizând meniul contextual. Acest lucru v-ar ajuta la compunerea instrucÈ›iunilor SQL. PuteÈ›i să glisaÈ›i instrucÈ›iunile SQL din coloana Schemă È™i să le plasaÈ›i în editorul SQL sau în alte aplicaÈ›ii. &Remote La &Distanță Project Toolbar Bară De Instrumente Proiect Extra DB toolbar Bară de instrumente suplimentară BD Close the current database file ÃŽnchide fiÈ™ierul bazei de date curente &New Database... &Bază De Date Nouă... Create a new database file Creează un nou fiÈ™ier de bază de date This option is used to create a new database file. Această opÈ›iune este utilizată pentru a crea un nou fiÈ™ier de bază de date. Ctrl+N Ctrl+N &Open Database... &Deschide Bază De Date... Open an existing database file Deschide un fiÈ™ier de bază de date existent This option is used to open an existing database file. Această opÈ›iune este utilizată pentru a deschide un fiÈ™ier de bază de date existent. Ctrl+O Ctrl+O &Close Database ÃŽnc&hide Bază De Date This button closes the connection to the currently open database file Acest buton închide conexiunea la fiÈ™ierul bazei de date deschis în prezent Ctrl+F4 Ctrl+F4 &Revert Changes &Revocare Modificări Revert database to last saved state Revocare bază de date la ultima stare salvată This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Această opÈ›iune este utilizată pentru a revoca fiÈ™ierul de bază de date curent la ultima sa stare salvată. Toate modificările efectuate de la ultima operaÈ›iune de salvare sunt pierdute. &Write Changes Scrie &Modificările Write changes to the database file Scrie modificările în fiÈ™ierul bazei de date This option is used to save changes to the database file. Această opÈ›iune este utilizată pentru a salva modificările la fiÈ™ierul bazei de date. Ctrl+S Ctrl+S Compact &Database... &Compactare Bază De Date... Compact the database file, removing space wasted by deleted records Compactează fiÈ™ierul bazei de date, eliminând spaÈ›iu irosit de înregistrări È™terse Compact the database file, removing space wasted by deleted records. Compactează fiÈ™ierul bazei de date, eliminând spaÈ›iu irosit de înregistrări È™terse. E&xit IeÈ™i&re Ctrl+Q Ctrl+Q &Database from SQL file... Bază de date din fiÈ™ier &SQL... Import data from an .sql dump text file into a new or existing database. Importă date dintr-un fiÈ™ier text .sql dump într-o bază de date nouă sau existentă. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Această opÈ›iune vă permite să importaÈ›i date dintr-un fiÈ™ier text .sql dump într-o bază de date nouă sau existentă. FiÈ™ierele SQL dump pot fi create pe majoritatea motoarelor de baze de date, inclusiv MySQL È™i PostgreSQL. &Table from CSV file... Tabel din fiÈ™ier &CSV... Open a wizard that lets you import data from a comma separated text file into a database table. Deschide un asistent care vă permite să importaÈ›i date dintr-un fiÈ™ier text separat prin virgulă într-un tabel de bază de date. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Deschide un asistent care vă permite să importaÈ›i date dintr-un fiÈ™ier text separat prin virgulă într-un tabel de bază de date. FiÈ™ierele CSV pot fi create în majoritatea aplicaÈ›iilor de baze de date È™i foi de calcul. &Database to SQL file... Bază de date în fiÈ™ier &SQL... Export a database to a .sql dump text file. Exportă o bază de date într-un fiÈ™ier text .sql dump. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Această opÈ›iune vă permite să exportaÈ›i o bază de date într-un fiÈ™ier text .sql dump. FiÈ™ierele SQL dump conÈ›in toate datele necesare pentru a recrea baza de date pe majoritatea motoarelor de baze de date, inclusiv MySQL È™i PostgreSQL. &Table(s) as CSV file... Tabel(e) ca fiÈ™ier &CSV... Export a database table as a comma separated text file. Exportă un tabel de bază de date sub forma unui fiÈ™ier text separat prin virgulă. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Exportă un tabel de bază de date sub forma unui fiÈ™ier text separat prin virgulă, gata să fie importat în alte aplicaÈ›ii de baze de date sau foi de calcul. &Create Table... Creează &Tabel... Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Deschide asistentul Creează Tabel, unde este posibilă definirea numelui È™i a câmpurilor pentru un tabel nou în baza de date &Delete Table... Șter&ge Tabel... Delete Table Șterge Tabel Open the Delete Table wizard, where you can select a database table to be dropped. Deschide asistentul Șterge Tabel, unde puteÈ›i selecta un tabel de bază de date pentru a fi È™ters. &Modify Table... &Modifică Tabel... Create &Index... Creează In&dice... Open the Create Index wizard, where it is possible to define a new index on an existing database table. Deschide asistentul Creează Indice, unde este posibil să definiÈ›i un nou indice pe un tabel existent de bază de date. &Preferences... &PreferinÅ£e... Open the preferences window. Deschide fereastra de preferinÈ›e. &DB Toolbar Bară De Instrumente &BD Shows or hides the Database toolbar. AfiÈ™ează sau ascunde bara de instrumente a Bazei De Date. W&hat's This? Ce Este &Asta? Shift+F1 Shift+F1 &About &Despre &Recently opened &Deschis recent This button opens a new tab for the SQL editor Acest buton deschide o filă nouă pentru editorul SQL Ctrl+T Ctrl+T &Execute SQL &Execută SQL Execute all/selected SQL Execută toate/selectat SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Acest buton execută instrucÈ›iunile SQL selectate în prezent. Dacă nu este selectat niciun text, sunt executate toate instrucÈ›iunile SQL. Ctrl+Return Ctrl+Return Save SQL file Salvează fiÈ™ier SQL &Load Extension... ÃŽncarcă &Extensie... Execute current line Execută linia curentă Execute line Execută linia This button executes the SQL statement present in the current editor line Acest buton execută instrucÈ›iunea SQL prezentă în linia curentă a editorului Shift+F5 Shift+F5 Export as CSV file Exportă ca fiÈ™ier CSV Export table as comma separated values file Exportă tabelul ca fiÈ™ier cu valori separate prin virgulă &Wiki &Wiki F1 F1 Bug &Report... &Raport De Eroare... Feature Re&quest... Cerere &Caracteristică... Web&site &Site web &Donate on Patreon... Donează pe &Patreon... Sa&ve Project Sal&vează Proiect Save the current session to a file Salvează sesiunea curentă într-un fiÈ™ier Open &Project... Deschide &Proiect... Load a working session from a file ÃŽncarcă o sesiune de lucru dintr-un fiÈ™ier &Database Structure This has to be equal to the tab title in all the main tabs &Structură BD &Browse Data This has to be equal to the tab title in all the main tabs &Răsfoire Date Edit P&ragmas This has to be equal to the tab title in all the main tabs Editează &Pragmele E&xecute SQL This has to be equal to the tab title in all the main tabs &Execută SQL &Recent Files &FiÈ™iere Recente Too&ls &Instrumente &New Database &Bază De Date Nouă &Undo &Anulează Undo last change to the database Anulează ultima modificare a bazei de date This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Această acÈ›iune anulează ultima modificare efectuată în baza de date în Navigator Bază De Date sau în Execută SQL. Refacerea nu este posibilă. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Deschide asistentul Modifică Tabel, unde este posibilă redenumirea unui tabel existent. De asemenea, este posibil să se adauge sau să se È™teargă câmpuri dintr-un tabel, precum È™i să se modifice numele È™i tipurile de câmpuri. New &tab &Fila nouă Open SQL file(s) Deschide fiÈ™ier(e) SQL This button opens files containing SQL statements and loads them in new editor tabs Acest buton deschide fiÈ™iere care conÈ›in instrucÈ›iuni SQL È™i le încarcă în file noi ale editorului Ctrl+Shift+T Ctrl+Shift+T &Save Project &Salvează Proiect This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Acest buton vă permite să salvaÈ›i toate setările asociate BD deschise într-un fiÈ™ier de proiect DB Browser for SQLite Open &Project &Deschide Proiect This button lets you open a DB Browser for SQLite project file Acest buton vă permite să deschideÈ›i un fiÈ™ier de proiect DB Browser for SQLite &Attach Database... &AtaÈ™ează Baza De Date... Add another database file to the current database connection Adaugă un alt fiÈ™ier de bază de date la conexiunea curentă a bazei de date This button lets you add another database file to the current database connection Acest buton vă permite să adăugaÈ›i un alt fiÈ™ier de bază de date la conexiunea curentă a bazei de date &Set Encryption... &Setează Criptarea... Save SQL file as Salvează fiÈ™ierul SQL ca This button saves the content of the current SQL editor tab to a file Acest buton salvează conÈ›inutul filei curente a editorului SQL într-un fiÈ™ier &Browse Table &Răsfoire Tabel Copy Create statement Copiază InstrucÈ›iunea De Creare Copy the CREATE statement of the item to the clipboard Copiază instrucÈ›iunea CREATE a elementului în clipboard SQLCipher &FAQ SQLCipher &FAQ Opens the SQLCipher FAQ in a browser window Deschide SQLCipher FAQ într-o fereastră de browser Table(&s) to JSON... Tabel(e) în &JSON... Export one or more table(s) to a JSON file Exportă unul sau mai multe tabele într-un fiÈ™ier JSON Open Data&base Read Only... abbreviated 'database' Deschide BD ÃŽn Modul Doar-&Citire... Open an existing database file in read only mode Deschide un fiÈ™ier de bază de date existent în modul doar-citire Ctrl+Shift+O Ctrl+Shift+O Save results Salvează rezultatele Save the results view Salvează vederea rezultatelor This button lets you save the results of the last executed query Acest buton vă permite să salvaÈ›i rezultatele ultimei interogări executate Find text in SQL editor GăseÈ™te text în editorul SQL Find GăseÈ™te This button opens the search bar of the editor Acest buton deschide bara de căutare a editorului Ctrl+F Ctrl+F Find or replace text in SQL editor GăseÈ™te sau înlocuieÈ™te text în editorul SQL Find or replace GăseÈ™te sau înlocuieÈ™te This button opens the find/replace dialog for the current editor tab Acest buton deschide dialogul de găsire/înlocuire pentru fila curentă a editorului Ctrl+H Ctrl+H Export to &CSV Exportă în &CSV Export to &JSON Exportă în &JSON Save as &view Salvează ca &vedere Save as view Salvează ca vedere Shows or hides the Project toolbar. AfiÈ™ează sau ascunde bara de instrumente Proiect. Extra DB Toolbar Bară De Instrumente Suplimentară BD &Open Database &Deschide Bază De Date New In-&Memory Database translation? 'In-Memory' Nouă Bază De Date ÃŽn Mem&orie Drag && Drop SELECT Query Glisează && Plasează Interogarea SELECT When dragging fields from the same table or a single table, drop a SELECT query into the editor Când glisaÈ›i câmpuri din acelaÈ™i tabel sau dintr-un singur tabel, plasaÈ›i o interogare SELECT în editor Drag && Drop Qualified Names Glisează && Plasează Nume Calificate Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Utilizează nume calificate (ex., "Tabel"." Câmp") atunci când glisaÈ›i obiectele È™i le plasaÈ›i în editor Drag && Drop Enquoted Names Glisează && Plasează Nume ÃŽntre Ghilimele Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Utilizează identificatori scăpaÈ›i (ex., "Tabel1") atunci când glisaÈ›i obiectele È™i le plasaÈ›i în editor &Integrity Check Verificare &Integritate Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. Rulează pragma integrity_check peste baza de date deschisă È™i returnează rezultatele în fila Execută SQL. Această pragma efectuează o verificare a integrității întregii baze de date. &Foreign-Key Check Verificare C&heie-Străină Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Rulează pragma foreign_key_check peste baza de date deschisă È™i returnează rezultatele în fila Execută SQL &Quick Integrity Check Verificare &Rapidă De Integritate Run a quick integrity check over the open DB Rulează o verificare rapidă a integrității peste BD deschisă Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. Rulează pragma quick_check peste baza de date deschisă È™i returnează rezultatele în fila Execută SQL. Această comandă face cea mai mare parte a verificării PRAGMA integrity_check, dar rulează mult mai repede. &Optimize &Optimizează Attempt to optimize the database ÃŽncercare de optimizare a bazei de date Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Rulează pragma de optimizare peste baza de date deschisă. Acest pragma ar putea efectua optimizări care vor îmbunătăți performanÈ›a interogărilor viitoare. Print Imprimare Print text from current SQL editor tab Imprimare text din fila curentă a editorului SQL Open a dialog for printing the text in the current SQL editor tab Deschide un dialog pentru imprimarea textului din fila curentă a editorului SQL Ctrl+P Ctrl+P Print the structure of the opened database Imprimează structura bazei de date deschise Open a dialog for printing the structure of the opened database Deschide un dialog pentru imprimarea structurii bazei de date deschise Un/comment block of SQL code De/comentează blocul de cod SQL Un/comment block De/comentează blocul Comment or uncomment current line or selected block of code Comentează sau decomentează linia curentă sau blocul de cod selectat Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Comentează sau decomentează liniile selectate sau linia curentă, atunci când nu există selecÈ›ie. Tot blocul este comutat conform primei linii. Ctrl+/ Ctrl+/ Stop SQL execution Oprire execuÈ›ie SQL Stop execution Oprire execuÈ›ie Stop the currently running SQL script Oprire script SQL care rulează în prezent &Save Project As... Salvea&ză Proiectul Ca... Save the project in a file selected in a dialog Salvează proiectul într-un fiÈ™ier selectat într-un dialog Save A&ll Salvează &Toate Save DB file, project file and opened SQL files Salvează fiÈ™ierul BD, fiÈ™ierul de proiect È™i fiÈ™ierele SQL deschise Ctrl+Shift+S Ctrl+Shift+S Browse Table Răsfoire Tabel Close Pro&ject ÃŽ&nchide Proiect Close project and database files and return to the initial state ÃŽnchide fiÈ™ierele proiectului È™i ale bazei de date È™i revenire la starea iniÈ›ială Ctrl+Shift+W Ctrl+Shift+W Detach Database DetaÈ™ează Baza De Date Detach database file attached to the current database connection DetaÈ™ează fiÈ™ierul de bază de date ataÈ™at la conexiunea curentă a bazei de date Table from CSV data in Clipboard... Tabel din date CSV din Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Asta tratează conÈ›inutul curent al clipboard-ului ca un fiÈ™ier CSV È™i deschide acelaÈ™i asistent de import care este utilizat pentru importarea datelor CSV dintr-un fiÈ™ier. Show &Row Counts AfiÈ™ează &Numărul De Rânduri This shows the number of rows for each table and view in the database. Asta arată numărul de rânduri pentru fiecare tabel È™i vedere în baza de date. Save Database &As... &Salvare Bază De Date Ca... Save the current database as a different file Salvează baza de date curentă ca un fiÈ™ier diferit Refresh Reîmprospătează Reload the database structure Reîncarcă structura bazei de date Ctrl+W Ctrl+W Ctrl+Tab Ctrl+Tab Ctrl+Shift+Tab Ctrl+Shift+Tab Automatically load the last opened DB file at startup Clear List Șterge Listă Ctrl+L Ctrl+L Ctrl+D Ctrl+D Ctrl+I Ctrl+I Ctrl+E Ctrl+E Window Layout Aspect Fereastră Reset Window Layout Resetare Aspect Fereastră Ctrl+Alt+0 Ctrl+Alt+0 Simplify Window Layout Simplifică Aspect Fereastră Alt+Shift+0 Alt+Shift+0 Dock Windows at Bottom Ancorează Ferestrele în Partea De Jos Dock Windows at Left Side Ancorează Ferestrele în Partea Stângă Dock Windows at Top Ancorează Ferestrele în Partea De Sus The database is currently busy. Baza de date este momentan ocupată. Click here to interrupt the currently running query. FaceÈ›i clic aici pentru a întrerupe interogarea care rulează în prezent. Encrypted Criptat Database is encrypted using SQLCipher Baza de date este criptată folosind SQLCipher Read only Doar citire Database file is read only. Editing the database is disabled. FiÈ™ierul bazei de date este în modul doar-citire Editarea bazei de date este dezactivată. Database encoding Codificarea bazei de date Ctrl+Alt+W Ctrl+Alt+W Ctrl+Shift+F4 Ctrl+Shift+F4 Choose a database file Alege un fiÈ™ier de bază de date Could not open database file. Reason: %1 Nu s-a putut deschide fiÈ™ierul bazei de date. Motiv: %1 Choose a filename to save under AlegeÈ›i un nume de fiÈ™ier sub care să salvaÈ›i In-Memory database translation? 'In-Memory' Bază de date ÃŽn-Memorie Choose a database file to save under Alege un fiÈ™ier de bază de date pentru a salva sub Error while saving the database to the new file. Eroare la salvarea bazei de date în fiÈ™ierul nou. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? ÃŽncă executaÈ›i instrucÈ›iuni SQL. ÃŽnchiderea bazei de date acum va opri executarea lor, lăsând eventual baza de date într-o stare inconsecventă. SunteÈ›i sigur că doriÈ›i să închideÈ›i baza de date? Do you want to save the changes made to the project file '%1'? DoriÈ›i să salvaÈ›i modificările făcute la fiÈ™ierul de proiect '%1'? Are you sure you want to delete the table '%1'? All data associated with the table will be lost. SunteÈ›i sigur că doriÈ›i să È™tergeÈ›i tabelul '%1'? Toate datele asociate cu tabelul vor fi pierdute. Are you sure you want to delete the view '%1'? SunteÈ›i sigur că doriÈ›i să È™tergeÈ›i vederea '%1'? Are you sure you want to delete the trigger '%1'? SunteÈ›i sigur că doriÈ›i să È™tergeÈ›i declanÈ™atorul '%1'? Are you sure you want to delete the index '%1'? SunteÈ›i sigur că doriÈ›i să È™tergeÈ›i indicele '%1'? Error: could not delete the table. Eroare: nu s-a putut È™terge tabelul. Error: could not delete the view. Eroare: nu s-a putut È™terge vederea. Error: could not delete the trigger. Eroare: nu s-a putut È™terge declanÈ™atorul. Error: could not delete the index. Eroare: nu s-a putut È™terge indicele. Message from database engine: %1 Mesaj de la motorul bazei de date: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Editarea tabelului necesită salvarea tuturor modificărilor în aÈ™teptare acum. SunteÈ›i sigur că doriÈ›i să salvaÈ›i baza de date? Error checking foreign keys after table modification. The changes will be reverted. Eroare la verificarea cheilor străine după modificarea tabelului. Modificările vor fi anulate. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Acest tabel nu a trecut o verificare a cheii străine.<br/>Ar trebui să rulaÈ›i 'Instrumente | Verificare Cheie Străină' È™i să remediaÈ›i problemele raportate. Edit View %1 Editează Vederea %1 Edit Trigger %1 Editează DeclanÈ™atorul %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. ExecutaÈ›i deja instrucÈ›iuni SQL. DoriÈ›i să le opriÈ›i pentru a executa în schimb instrucÈ›iunile curente? ReÈ›ineÈ›i că acest lucru ar putea lăsa baza de date într-o stare inconsecventă. -- EXECUTING SELECTION IN '%1' -- -- EXECUTÂND SELECÈšIA ÃŽN '%1' -- -- EXECUTING LINE IN '%1' -- -- EXECUTÂND LINIA ÃŽN '%1' -- -- EXECUTING ALL IN '%1' -- -- EXECUTÂND TOTUL ÃŽN '%1' -- At line %1: La linia %1: Result: %1 Rezultat: %1 Result: %2 Rezultat: %2 %1 rows returned in %2ms %1 rânduri returnate în %2ms Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Setarea valorilor PRAGMA sau aspirarea va comite tranzacÈ›ia curentă. EÈ™ti sigur? Execution finished with errors. ExecuÈ›ie terminată cu erori. Execution finished without errors. ExecuÈ›ie terminată fără erori. Choose text files Alege fiÈ™iere text Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Eroare la salvarea fiÈ™ierului bazei de date. Asta înseamnă că nu au fost salvate toate modificările aduse bazei de date. Trebuie să rezolvaÈ›i mai întâi următoarea eroare. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? SunteÈ›i sigur că doriÈ›i să anulaÈ›i toate modificările aduse fiÈ™ierului bazei de date '%1 ' de la ultima salvare? Choose a file to import Alege un fiÈ™ier pentru a importa Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. DoriÈ›i să creaÈ›i un nou fiÈ™ier de bază de date pentru a stoca datele importate? Dacă răspundeÈ›i nu, vom încerca să importăm datele din fiÈ™ierul SQL în baza de date curentă. File %1 already exists. Please choose a different name. FiÈ™ierul %1 există deja. Vă rugăm să alegeÈ›i un nume diferit. Error importing data: %1 Eroare la importarea datelor: %1 Import completed. Some foreign key constraints are violated. Please fix them before saving. Import finalizat. Unele constrângeri de cheie străină sunt încălcate. Vă rugăm să le remediaÈ›i înainte de salvare. Import completed. Import finalizat. Delete View Șterge Vedere Modify View Modifică Vedere Delete Trigger Șterge DeclanÈ™ator Modify Trigger Modifică DeclanÈ™ator Delete Index Șterge Indice Modify Index Modifică Indice Modify Table Modifică Tabel Opened '%1' in read-only mode from recent file list Deschis '%1' în modul doar-citire din lista de fiÈ™iere recente Opened '%1' from recent file list Deschis '%1' din lista de fiÈ™iere recente &%1 %2%3 &%1 %2%3 (read only) (doar-citire) Open Database or Project Deschide Bază De Date sau Proiect Attach Database... AtaÈ™are Bază De Date... Import CSV file(s)... Importă fiÈ™ier(e) CSV... Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Selectează acÈ›iunea de aplicat fiÈ™ierului plasat. <br/>Notă: numai 'Importă' va procesa mai mult de un fiÈ™ier. Selectează acÈ›iunea de aplicat fiÈ™ierelor plasate. <br/>Notă: numai 'Importă' va procesa mai multe fiÈ™iere. Selectează acÈ›iunea de aplicat fiÈ™ierelor plasate. <br/>Notă: numai 'Importă' va procesa mai multe fiÈ™iere. The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? InstrucÈ›iunile din fila '%1' sunt încă în curs de executare. ÃŽnchiderea filei va opri executarea. Acest lucru ar putea lăsa baza de date într-o stare inconsistentă. SunteÈ›i sigur că doriÈ›i să închideÈ›i fila? DB file '%1' could not be opened FiÈ™ierul BD '%1' nu a putut fi deschis This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Acest fiÈ™ier de proiect utilizează un format de fiÈ™ier vechi, deoarece a fost creat utilizând DB Browser for SQLite versiunea 3.10 sau mai mică. ÃŽncărcarea acestui format de fiÈ™ier nu mai este pe deplin suportată. Dacă doriÈ›i să îl încărcaÈ›i complet, vă rugăm să utilizaÈ›i DB Browser for SQLite versiunea 3.12 pentru a-l converti în noul format de fiÈ™ier. Table '%1' not found; settings ignored Tabelul '%1' nu a fost găsit; setări ignorate Setting PRAGMA values will commit your current transaction. Are you sure? Setarea valorilor PRAGMA va comite tranzacÈ›ia curentă. EÈ™ti sigur? Do you want to save the changes made to SQL tabs in a new project file? DoriÈ›i să salvaÈ›i modificările aduse filelor SQL într-un nou fiÈ™ier de proiect? Do you want to save the changes made to SQL tabs in the project file '%1'? DoriÈ›i să salvaÈ›i modificările aduse filelor SQL în fiÈ™ierul de proiect '%1'? Do you want to save the changes made to the SQL file %1? DoriÈ›i să salvaÈ›i modificările aduse în fiÈ™ierul SQL %1? Select SQL file to open Selectează fiÈ™ierul SQL pentru deschidere Text files(*.sql *.txt);;All files(*) FiÈ™iere text (*.sql *.txt);;Toate fiÈ™ierele (*) Select file name Selectează numele fiÈ™ierului Select extension file Selectează fiÈ™ierul de extensie Extension successfully loaded. Extensie încărcată cu succes. Error loading extension: %1 Eroare la încărcarea extensiei: %1 Could not find resource file: %1 Nu s-a putut găsi fiÈ™ierul resursă: %1 Don't show again Nu mai arăta New version available. Versiune nouă disponibilă. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. O nouă versiune DB Browser for SQLite este disponibilă (%1.%2.%3).<br/><br/>Vă rugăm să descărcaÈ›i la <a href='%4'>%4</a>. Choose a project file to open Alege un fiÈ™ier de proiect pentru a deschide DB Browser for SQLite project file (*.sqbpro) FiÈ™ier de proiect DB Browser for SQLite (*.sqbpro) Could not open project file for writing. Reason: %1 Nu s-a putut deschide fiÈ™ierul de proiect pentru scriere. Motiv: %1 -- Reference to file "%1" (not supported by this version) -- -- Referință la fiÈ™ierul "%1"(nu este suportat de această versiune) -- Project saved to file '%1' Proiect salvat în fiÈ™ierul '%1' Yes. Don't ask again Da. Nu întreba din nou Collation needed! Proceed? ColaÈ›ionare necesară! ContinuaÈ›i? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Un tabel din această bază de date necesită o funcÈ›ie specială de colaÈ›ionare '%1' pe care această aplicaÈ›ie nu o poate furniza fără cunoÈ™tinÈ›e suplimentare. Dacă alegeÈ›i să continuaÈ›i, fiÈ›i conÈ™tienÈ›i de faptul că se pot întâmpla lucruri rele cu baza dumneavoastră de date. Creează o copie de rezervă! creating collation creând coloÈ›ionare Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Setaează un nume nou pentru fila SQL. Utilizează caracterul '&&' pentru a permite utilizarea următorului caracter ca comandă rapidă de la tastatură. Please specify the view name Vă rugăm să specificaÈ›i numele vederii There is already an object with that name. Please choose a different name. Există deja un obiect cu acest nume. Vă rugăm să alegeÈ›i un nume diferit. View successfully created. Vedere creată cu succes. Error creating view: %1 Eroare la crearea vederii: %1 This action will open a new SQL tab for running: Această acÈ›iune va deschide o nouă filă SQL pentru rulare: This action will open a new SQL tab with the following statements for you to edit and run: Această acÈ›iune va deschide o nouă filă SQL cu următoarele instrucÈ›iuni pe care le puteÈ›i edita È™i executa: Press Help for opening the corresponding SQLite reference page. Apasă Ajutor pentru a deschide pagina de referință SQLite corespunzătoare. Busy (%1) Ocupat (%1) Rename Tab Redenumire Filă Duplicate Tab Duplicare Filă Close Tab ÃŽnchidere Filă Opening '%1'... Deschizând '%1'... There was an error opening '%1'... A apărut o eroare la deschiderea '%1'... Value is not a valid URL or filename: %1 Valoarea nu este o adresă URL sau un nume de fiÈ™ier valid: %1 NullLineEdit Set to NULL Setează la NULL Alt+Del Alt+Del PlotDock Plot Grafic <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Acest panou afiÈ™ează lista de coloane a tabelului navigat în prezent sau a interogării tocmai executate. PuteÈ›i selecta coloanele pe care doriÈ›i să le utilizaÈ›i ca axă X sau Y pentru panoul grafic de mai jos. Tabelul arată tipul de axă detectat care va afecta graficul rezultat. Pentru axa Y puteÈ›i selecta doar coloane numerice, dar pentru axa X veÈ›i putea selecta:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Dată/Oră</span>: È™iruri cu format &quot;yyyy-MM-dd hh:mm:ss&quot; sau &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Dată</span>: È™iruri cu format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Oră</span>: È™iruri cu format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Etichetă</span>: alte formate de È™ir. selectând această coloană ca axă X va produce un grafic de bare cu valorile coloanei ca etichete pentru bare</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: valori întregi sau reale</li></ul><p>Făcând dublu clic pe celulele Y, puteÈ›i schimba culoarea utilizată pentru graficul respectiv.</p></body></html> Columns Coloane X X Y1 Y1 Y2 Y2 Axis Type Tip Axă Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Aici este un grafic desenat atunci când selectaÈ›i valorile x È™i y de mai sus. FaceÈ›i clic pe puncte pentru a le selecta în grafic È™i în tabel. Ctrl+Click pentru selectarea unui interval de puncte. FoloseÈ™te rotiÈ›a mouse-ului pentru mărire È™i glisează cu mouse-ul pentru a schimba intervalul axei. Selectează axele sau etichetele axelor pentru a glisa È™i a mări doar în acea orientare. Line type: Tip linie: None Niciunul Line Linie StepLeft PasStânga StepRight PasDreapta StepCenter PasCentru Impulse Impuls Point shape: Forma punctului: Cross Cruce Plus Plus Circle Cerc Disc Disc Square Pătrat Diamond Diamant Star Stea Triangle Triunghi TriangleInverted TriunghiInversat CrossSquare CrucePătrat PlusSquare PlusPătrat CrossCircle CruceCerc PlusCircle PlusCerc Peace Pace <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Salvează graficul curent...</p><p>Format de fiÈ™ier ales de extensie (png, jpg, pdf, bmp)</p></body></html> Save current plot... Salvează graficul curent... Load all data and redraw plot ÃŽncarcă toate datele È™i redesenează graficul Copy Copiază Print... Imprimare... Show legend Arată legendă Stacked bars Bare suprapuse Fixed number format Format număr fix Date/Time Dată/Oră Date Dată Time Timp Numeric Numeric Label Etichetă Invalid Invalid Row # Rând # Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. unclear translation - 'fetch' ÃŽncarcă toate datele È™i redesenează graficul. Avertisment: nu toate datele au fost preluate din tabel încă din cauza mecanismului de preluare parÈ›ială. Choose an axis color Alege o culoare a axei Choose a filename to save under Alege un nume de fiÈ™ier sub care să salvezi PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);; JPG (*.jpg);; PDF(*.pdf);; BMP (*.bmp);; Toate FiÈ™ierele (*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Există curbe în acest grafic È™i stilul de linie selectat poate fi aplicat numai la graficele sortate de X. Fie sortaÈ›i tabelul sau interogarea de X pentru a elimina curbele sau selectaÈ›i unul dintre stilurile suportate de curbe: Niciunul sau Linie. Loading all remaining data for this table took %1ms. ÃŽncărcarea tuturor datelor rămase pentru acest tabel a durat %1ms. PreferencesDialog Preferences PreferinÅ£e &General &General Default &location &LocaÈ›ie implicită Remember last location ÈšineÈ›i minte ultima locaÈ›ie Always use this location Utilizează întotdeauna această locaÈ›ie Remember last location for session only ÈšineÈ›i minte ultima locaÈ›ie numai pentru sesiune ... ... Lan&guage Li&mbă Toolbar style Stilul barei de instrumente Only display the icon AfiÈ™ează numai pictograma Only display the text AfiÈ™ează numai textul The text appears beside the icon Textul apare lângă pictogramă The text appears under the icon Textul apare sub pictogramă Follow the style Urmează stilul Show remote options AfiÈ™ează opÈ›iunile de la distanță enabled activat Automatic &updates &Actualizări automate DB file extensions Extensii fiÈ™ier BD Manage Administrare Main Window Fereastră Principală Database Structure Structura Bazei De Date Browse Data Răsfoire Date Execute SQL Execută SQL Edit Database Cell Editează Celula Bazei De Date When this value is changed, all the other color preferences are also set to matching colors. Atunci când această valoare este modificată, toate celelalte preferinÈ›e de culoare sunt, de asemenea, setate la culori care se potrivesc. Follow the desktop style Urmează stilul desktopului Dark style Stil întunecat Light style Stil luminos Application style Stil aplicaÈ›ie This sets the font size for all UI elements which do not have their own font size option. Asta setează mărimea fontului pentru toate elementele interfeÈ›ei utilizatorului care nu au propria opÈ›iune de mărime a fontului. Font size Mărime font Max Recent Files Număr Maxim De FiÈ™iere Recente Prompt to save SQL tabs in new project file Solicitare la salvarea filelor SQL într-un fiÈ™ier de proiect nou If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Dacă asta este activat, atunci modificările aduse editorului SQL generează un dialog de confirmare a salvării unui proiect la închiderea filei editorului SQL. &Database &Bază De Date Database &encoding &Codificare bază de date Open databases with foreign keys enabled. Deschide baze de date cu chei străine activate. &Foreign keys Chei &străine Remove line breaks in schema &view Elimină întreruperile de linie în &vizualizarea schemei When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Când este activat, întreruperile de linie din coloana Schemă din fila Structură BD, docul È™i ieÈ™irea imprimată sunt eliminate. Prefetch block si&ze unclear translation - 'fetch' Preîncărcare &mărime bloc SQ&L to execute after opening database SQ&L de executat după deschiderea bazei de date Default field type Tip câmp implicit Database structure font size Mărime font structură bază de date Data &Browser &Navigator De Date Font Font &Font &Font Font si&ze &Mărime font Formatted Formatat Content ConÈ›inut Symbol limit in cell Limită simbol în celulă This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Acesta este numărul maxim de elemente permis pentru activarea unor funcÈ›ionalități costisitoare computaÈ›ionale: Numărul maxim de rânduri dintr-un tabel pentru activarea finalizării valorii pe baza valorilor curente din coloană. Numărul maxim de indici dintr-o selecÈ›ie pentru calcularea sumei È™i mediei. Poate fi setat la 0 pentru a dezactiva funcÈ›ionalitățile. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Acesta este numărul maxim de rânduri dintr-un tabel pentru activarea finalizării valorii pe baza valorilor curente din coloană. Poate fi setat la 0 pentru dezactivarea finalizării. Threshold for completion and calculation on selection Prag pentru finalizare È™i calcul la selecÈ›ie Show images in cell AfiÈ™ează imagini în celulă Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Activează această opÈ›iune pentru a afiÈ™a o previzualizare a BLOB-urilor care conÈ›in date de imagine în celule. TotuÈ™i, acest lucru poate afecta performanÈ›a navigatorului de date. Field display AfiÈ™are câmp Displayed &text &Text afiÈ™at Binary Binar NULL NULL Regular Regulat Click to set this color Click pentru a seta această culoare Text color Culoare text Background color Culoare fundal Preview only (N/A) visibility issue Numai previzualizare (N/A) Filters Filtre Escape character Caracter de scăpare Delay time (&ms) Timp de întâr&ziere (ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Setează timpul de aÈ™teptare înainte ca o nouă valoare a filtrului să fie aplicată. Poate fi setat la 0 pentru dezactivarea aÈ™teptării. &SQL &SQL Context Context Colour Culoare Bold ÃŽngroÈ™at Italic ÃŽnclinat Underline Subliniat Keyword Cuvânt Cheie Function FuncÅ£ie Table Tabel Comment Comentariu Identifier Identificator String Șir Current line Linia curentă Background Fundal Foreground Prim-plan Selection background Fundal de selecÈ›ie Selection foreground Prim-plan de selecÈ›ie Highlight EvidenÈ›iere SQL editor &font &Font editor SQL SQL &editor font size Mărime font e&ditor SQL SQL &results font size Mărime font &rezultate SQL Tab size Mărime filă Use tabs for indentation Utilizează taburi pentru indentare When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. Când este setat, tasta Tab va introduce caractere de tabulare È™i spaÈ›iu pentru indentare. ÃŽn caz contrar, se vor utiliza doar spaÈ›ii. &Wrap lines ÃŽnfășurare &linii Never Niciodată At word boundaries La limitele cuvintelor At character boundaries La limitele caracterelor At whitespace boundaries La limitele spaÈ›iilor albe &Quotes for identifiers &Ghilimele pentru identificatori Choose the quoting mechanism used by the application for identifiers in SQL code. AlegeÈ›i mecanismul de citare utilizat de aplicaÈ›ie pentru identificatori în codul SQL. "Double quotes" - Standard SQL (recommended) "Ghilimele duble" - SQL standard (recomandat) `Grave accents` - Traditional MySQL quotes `Accente grave` - Ghilimele tradiÈ›ionale MySQL [Square brackets] - Traditional MS SQL Server quotes [Paranteze pătrate] - Ghilimele tradiÈ›ionale MS SQL Server Code co&mpletion Finali&zarea codului Keywords in &UPPER CASE Cuvinte cheie în MA&JUSCULE When set, the SQL keywords are completed in UPPER CASE letters. Când este setat, cuvintele cheie SQL sunt completate cu litere MAJUSCULE. Error indicators Indicatori de eroare When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Când este setat, liniile de cod SQL care au cauzat erori în timpul ultimei execuÈ›ii sunt evidenÈ›iate È™i cadrul de rezultate indică eroarea în fundal Hori&zontal tiling Aranjare &orizontală If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Dacă este activat, editorul de cod SQL È™i vizualizarea tabelului de rezultate sunt afiÈ™ate una lângă alta, în loc de una peste cealaltă. Close button on tabs Buton de închidere pe file If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Dacă este activat, filele editorului SQL vor avea un buton de închidere. ÃŽn orice caz, puteÈ›i utiliza meniul contextual sau comanda rapidă de la tastatură pentru a le închide. &Extensions &Extensii Select extensions to load for every database: Selectează extensiile de încărcat pentru fiecare bază de date: Add extension Adaugă extensie Remove extension Elimină extensie Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>ÃŽn timp ce suportă operatorul REGEXP, SQLite nu implementează niciun algoritm de expresie regulată,<br/>dar apelează înapoi aplicaÈ›ia care rulează. DB Browser for SQLite implementează acest<br/>algoritm pentru dumneavoastră pentru a vă permite să utilizaÈ›i REGEXP nou scos din cutie. Cu toate acestea, deoarece există mai multe implementări posibile<br/>ale acestui lucru È™i este posibil să doriÈ›i să utilizaÈ›i alta, sunteÈ›i liber să dezactivaÈ›i<br/>implementarea aplicaÈ›iei È™i să vă încărcaÈ›i propria implementare utilizând o extensie. Necesită repornirea aplicaÈ›iei.</p></body></html> Disable Regular Expression extension Dezactivează extensia Expresiei Regulate <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite oferă o funcÈ›ie SQL pentru încărcarea extensiilor dintr-un fiÈ™ier de bibliotecă partajat. Activează asta dacă doriÈ›i să utilizezi funcÈ›ia <span style=" font-style:italic;">load_extension()</span> din codul SQL.</p><p>Din motive de securitate, încărcarea extensiei este dezactivată în mod implicit È™i trebuie activată prin această setare. PuteÈ›i încărca întotdeauna extensii prin intermediul interfeÈ›ei grafice, chiar dacă această opÈ›iune este dezactivată.</p></body></html> Allow loading extensions from SQL code Permite încărcarea extensiilor din codul SQL Remote La Distanță Your certificates Certificatele dumneavoastră File FiÅŸier Subject CN Subiect NC Subject Common Name Subiect Nume Comun Issuer CN Emitent NC Issuer Common Name Emitent Nume Comun Valid from Valabil din Valid to Valabil la Serial number Număr de serie CA certificates Certificate CA Common Name Nume Comun Subject O Subiect O Organization translation? - clarification needed Organizare Clone databases into Clonează bazele de date în Proxy Proxy Configure Configurează Export Settings Exportă Setările Import Settings Importă Setările Choose a directory Alege un dosar The language will change after you restart the application. Limba se va schimba după ce reporniÈ›i aplicaÈ›ia. Select extension file SelecteazÇŽ fiÈ™ierul de extensie Extensions(*.so *.dylib *.dll);;All files(*) Extensii(*.so *.dylib *.dll);;Toate fiÈ™ierele(*) Import certificate file Import fiÈ™ier de certificat No certificates found in this file. Nu s-au găsit certificate în acest fiÈ™ier. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! SunteÈ›i sigur că doriÈ›i să eliminaÈ›i acest certificat? Toate datele certificatului vor fi È™terse din setările aplicaÈ›iei! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. SunteÈ›i sigur că doriÈ›i să È™tergeÈ›i toate setările salvate? Toate preferinÈ›ele dumneavoastră vor fi pierdute È™i vor fi utilizate valorile implicite. Save Settings File Salvează FiÈ™ierul De Setări Initialization File (*.ini) FiÈ™ier De IniÈ›ializare (*.ini) The settings file has been saved in location : FiÈ™ierul de setări a fost salvat în locaÈ›ia : Open Settings File Deschide FiÈ™ierul De Setări The settings file was loaded properly. FiÈ™ierul de setări a fost încărcat corect. The selected settings file is not a normal settings file. Please check again. FiÈ™ierul de setări selectat nu este un fiÈ™ier de setări normal. Vă rugăm să verificaÈ›i din nou. ProxyDialog Proxy Configuration Configurare Proxy Pro&xy Type Tip Pro&xy Host Na&me Nume &Gazdă Port Port Authentication Re&quired &Autentificare Necesară &User Name Nume &Utilizator Password Parolă None Niciunul System settings Setări sistem HTTP HTTP SOCKS5 SOCKS5 QObject Left Stânga Right Dreapta Center Centru Justify Justifică All files (*) Toate fiÈ™ierele (*) SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) FiÈ™iere De Bază De Date SQLite (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) FiÈ™iere Proiect DB Browser for SQLite (*.sqbpro) SQL Files (*.sql) FiÈ™iere SQL (*.sql) All Files (*) Toate FiÈ™ierele (*) Text Files (*.txt) FiÈ™iere Text (*.txt) Comma-Separated Values Files (*.csv) FiÈ™iere Cu Valori Separat Prin Virgulă (*.csv) Tab-Separated Values Files (*.tsv) FiÈ™iere Cu Valori Separat Prin File (*.tsv) Delimiter-Separated Values Files (*.dsv) FiÈ™iere Cu Valori Separate Prin Delimitator (*.dsv) Concordance DAT files (*.dat) FiÈ™iere concordanță DAT (*.dat) JSON Files (*.json *.js) FiÈ™iere JSON (*.json *.js) XML Files (*.xml) FiÈ™iere XML (*.xml) Binary Files (*.bin *.dat) FiÈ™iere Binare (*.bin *.dat) SVG Files (*.svg) FiÈ™iere SVG (*.svg) Hex Dump Files (*.dat *.bin) FiÈ™iere Hex Dump (*.dat *.bin) Extensions (*.so *.dylib *.dll) Extensii (*.so *.dylib *.dll) Initialization File (*.ini) FiÈ™ier De IniÈ›ializare (*.ini) Error importing data Eroare la importul datelor from record number %1 de la numărul de înregistrare %1 . %1 . %1 Importing CSV file... Importând fiÈ™ier CSV... Cancel Anulare SQLite database files (*.db *.sqlite *.sqlite3 *.db3) FiÈ™iere de bază de date SQLite (*.db *.sqlite *.sqlite3 *.db3) QsciCommand Paste LipeÈ™te QsciLexerCPP Default Implicit Keyword Cuvânt Cheie Identifier Identificator QsciLexerJSON Default Implicit String Șir QsciLexerJavaScript Regular expression Expresie regulată QsciLexerPython Default Implicit Comment Comentariu Keyword Cuvânt Cheie Identifier Identificator QsciLexerSQL Default Implicit Comment Comentariu Keyword Cuvânt Cheie Identifier Identificator QsciScintilla &Undo &Anulează Select All Selectează Toate RemoteCommitsModel Commit ID ID de comitere Message Mesaj Date Dată Author Autor Size Mărime Authored and committed by %1 Scris È™i comis de %1 Authored by %1, committed by %2 Scris de %1, comis de %2 RemoteDatabase Error opening local databases list. %1 Eroare la deschiderea listei de baze de date locale. %1 Error creating local databases list. %1 Eroare la crearea listei de baze de date locale. %1 RemoteDock Remote La Distanță Identity Identitate Upload ÃŽncarcă DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>ÃŽn acest panou, bazele de date la distanță de pe site-ul web dbhub.io pot fi adăugate la DB Browser for SQLite. Mai întâi aveÈ›i nevoie de o identitate:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ConectaÈ›i-vă la site-ul web dbhub.io (utilizaÈ›i acreditările GitHub sau orice doriÈ›i)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">FaceÈ›i clic pe buton pentru a &quot;Generarea certificatului de client&quot; (aceasta este identitatea dumneavoastră). Asta vă va oferi un fiÈ™ier de certificat (salvaÈ›i-l pe discul local).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">MergeÈ›i la fila La Distanță din PreferinÈ›ele DB Browser for SQLite. FaceÈ›i clic pe buton pentru a adăuga un nou certificat la DB Browser for SQLite È™i alegeÈ›i fiÈ™ierul de certificat tocmai descărcat.</li></ol><p>Acum, panoul La Distanță arată identitatea dumneavoastră È™i puteÈ›i adăuga baze de date la distanță.</p></body></html> Local Local Current Database Bază De Date Curentă Clone Clonează &User &Utilizator &Database &Bază De Date Branch Ramură Commits Comiteri Commits for Comiteri pentru Delete Database Șterge Bază De Date Delete the local clone of this database Șterge clona locală a acestei baze de date Open in Web Browser Deschide în Browserul Web Open the web page for the current database in your browser Deschide pagina web pentru baza de date curentă în browserul dumneavoastră Clone from Link Clonează din Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. Utilizează asta pentru a descărca o bază de date la distanță pentru editare locală, utilizând o adresă URL furnizată pe pagina web a bazei de date. Refresh Reîmprospătează Reload all data and update the views Reîncărcă toate datele È™i actualizează vederile Clone Database Clonează Bază De Date Open Database Deschide Bază De Date Open the local copy of this database Deschide copia locală a acestei baze de date Check out Commit Verifică Comiterea Download and open this specific commit Descarcă È™i deschide acestă comitere specifică Check out Latest Commit Verifică Ultima Comitere Check out the latest commit of the current branch Verifică ultima comitere a ramurii curente Save Revision to File Salvează Revizia în FiÈ™ier Saves the selected revision of the database to another file Salvează revizia selectată a bazei de date într-un alt fiÈ™ier Upload Database ÃŽncarcă Baza De Date Upload this database as a new commit ÃŽncarcă această bază de date ca o comitere nouă Push currently opened database to server unclear translation - 'push' ÃŽmpingeÈ›i baza de date deschisă în prezent la server <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>ÃŽn prezent, utilizaÈ›i o identitate încorporată, în modul doar-citire. Pentru a vă încărca baza de date, trebuie să configuraÈ›i È™i să utilizaÈ›i contul dumneavoastră DBHub.io.</p><p>Nu aveÈ›i încă un cont DBHub.io? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">CreaÈ›i unul acum</span></a> È™i importaÈ›i certificatul dumneavoastră <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">aici</span></a> pentru a vă partaja bazele de date.</p><p>Pentru ajutor online vizitaÈ›i <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">aici</span></a>.</p></body></html> Back ÃŽnapoi Select an identity to connect Selectează o identitate pentru conectare Public Public This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Asta descarcă o bază de date de pe un server la distanță pentru editare locală. Vă rugăm să introduceÈ›i adresa URL de la care să se cloneze. PuteÈ›i genera această adresă URL făcând clic pe butonul 'Clonează Bază De Date în DB4S' de pe pagina web a bazei de date. Invalid URL: The host name does not match the host name of the current identity. Adresă URL invalidă: Numele de gazdă nu se potriveÈ™te cu numele de gazdă al identității curente. Invalid URL: No branch name specified. Adresă URL invalidă: Nume de ramură nespecificat. Invalid URL: No commit ID specified. Adresă URL invalidă: ID de comitere nespecificat. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? unclear translation - 'fetch' AÈ›i modificat clona locală a bazei de date. Preluarea acestei comiteri suprascrie aceste modificări locale. SunteÈ›i sigur că doriÈ›i să continuaÈ›i? The database has unsaved changes. Are you sure you want to push it before saving? unclear translation - 'push' Baza de date are modificări nesalvate. SunteÈ›i sigur că doriÈ›i să o împingeÈ›i înainte de a salva? The database you are trying to delete is currently opened. Please close it before deleting. Baza de date pe care încercaÈ›i să o È™tergeÈ›i este deschisă în prezent. Vă rugăm să o închideÈ›i înainte de a o È™terge. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? Asta È™terge versiunea locală a acestei baze de date cu toate modificările pe care nu le-aÈ›i comis încă. SunteÈ›i sigur că doriÈ›i să È™tergeÈ›i această bază de date? RemoteLocalFilesModel Name Nume Branch Ramură Last modified Modificat ultima dată Size Mărime Commit Comite File FiÅŸier RemoteModel Name Nume Commit Comite Last modified Modificat ultima dată Size Mărime Size: Mărime: Last Modified: Modificat Ultima Dată: Licence: Licență: Default Branch: Ramură Implicită: RemoteNetwork Choose a location to save the file Alege o locaÈ›ie pentru a salva fiÈ™ierul Error opening remote file at %1. %2 Eroare la deschiderea fiÈ™ierului la distanță la %1. %2 Error: Invalid client certificate specified. Eroare: Certificat de client invalid specificat. Please enter the passphrase for this client certificate in order to authenticate. Vă rugăm să introduceÈ›i fraza de acces pentru acest certificat de client pentru a vă autentifica. Cancel Anulează Uploading remote database to %1 ÃŽncărcare bază de date la distanță către %1 Downloading remote database from %1 Descărcare bază de date la distanță de la %1 Error: Cannot open the file for sending. Eroare: Nu se poate deschide fiÈ™ierul pentru trimitere. RemotePushDialog Push database unclear translation - 'push' ÃŽmpingere bază de date Database na&me to push to abbreviated 'database', unclear translation - 'push' &Nume BD pentru a împinge la Commit message Mesaj de comitere Database licence Licență bază de date Public Public Branch Ramură Force push unclear translation - 'push' ForÈ›are împingere Username Nume utilizator Database will be public. Everyone has read access to it. Baza de date va fi publică. Toată lumea are acces de citire la ea. Database will be private. Only you have access to it. Baza de date va fi privată. Numai dumneavoastră aveÈ›i acces la ea. Use with care. This can cause remote commits to be deleted. Utilizează cu grijă. Acest lucru poate cauza È™tergerea comiterilor de la distanță. RunSql Execution aborted by user ExecuÅ£ie întreruptă de utilizator , %1 rows affected , %1 rânduri afectate query executed successfully. Took %1ms%2 interogare executată cu succes. A luat %1ms%2 executing query executând interogare SelectItemsPopup A&vailable &Disponibil Sele&cted &Selectat SqlExecutionArea Form Formular Find previous match [Shift+F3] GăseÈ™te potrivirea anterioară [Shift+F3] Find previous match with wrapping GăseÈ™te potrivirea anterioară cu înfășurare Shift+F3 Shift+F3 The found pattern must be a whole word Modelul găsit trebuie să fie un cuvânt întreg Whole Words Cuvinte ÃŽntregi Text pattern to find considering the checks in this frame Model de text de găsit având în vedere verificările din acest cadru Find in editor GăseÈ™te în editor The found pattern must match in letter case Modelul găsit trebuie să se potrivească în cazul literelor Case Sensitive Caz Sensibil Find next match [Enter, F3] GăseÈ™te următoarea potrivire [Enter, F3] Find next match with wrapping GăseÈ™te următoarea potrivire cu înfășurare F3 F3 Interpret search pattern as a regular expression Interpretează modelul de căutare ca expresie regulată <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Când este bifat, modelul de găsit este interpretat ca o expresie regulată UNIX. Vezi <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Expresie Regulată Close Find Bar ÃŽnchide Bara De Căutare <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>Rezultatele ultimelor instrucÈ›iuni executate.</p><p>Poate doriÈ›i să restrângeÈ›i acest panou È™i să utilizaÈ›i docul<span style=" font-style:italic;">Jurnal SQL</span> cu selecÈ›ia <span style=" font-style:italic;">Utilizator</span> în schimb.</p></body></html> This field shows the results and status codes of the last executed statements. Acest câmp afiÈ™ează rezultatele È™i codurile de stare ale ultimelor instrucÈ›iuni executate. Results of the last executed statements Rezultatele ultimelor instrucÈ›iuni executate Ctrl+PgUp Ctrl+PgUp Ctrl+PgDown Ctrl+PgDown Couldn't read file "%1": %2. Nu s-a putut citi fiÈ™ierul "%1": %2. Couldn't save file: %1. Nu s-a putut salva fiÈ™ierul: %1. Your changes will be lost when reloading it! Modificările dumneavoastră vor fi pierdute când le reîncărcaÈ›i! The file "%1" was modified by another program. Do you want to reload it?%2 FiÈ™ierul "%1" a fost modificat de un alt program. DoriÈ›i să îl reîncărcaÈ›i?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Răspunde "Da la Toate" pentru a reîncărca fiÈ™ierul la orice actualizare externă fără alte solicitări. Answer "No to All" to ignore any external update without further prompting. Răspunde "Nu la Toate" pentru a ignora orice actualizare externă fără alte solicitări. Modifying and saving the file will restore prompting. Modificarea È™i salvarea fiÈ™ierului va restabili solicitarea. SqlTextEdit Ctrl+/ Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) FuncÈ›ia abs(X) returnează valoarea absolută a argumentului numeric X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () FuncÈ›ia changes() returnează numărul de rânduri ale bazei de date care au fost modificate sau inserate sau È™terse de instrucÈ›iunea INSERT, DELETE sau UPDATE completată cel mai recent. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) FuncÈ›ia char(X1,X2,...,XN) returnează un È™ir compus din caractere care au valorile punctului de cod unicode ale numerelor întregi X1 până la XN, respectiv. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) FuncÈ›ia coalesce() returnează o copie a primului său argument non-NULL sau NULL dacă toate argumentele sunt NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) FuncÈ›ia glob(X,Y) este echivalentă la expresia "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) FuncÈ›ia ifnull() returnează o copie a primului său argument non-NULL sau NULL dacă ambele argumente sunt NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) FuncÈ›ia instr(X,Y) găseÈ™te prima apariÈ›ie a È™irului Y în cadrul È™irului X È™i returnează numărul de caractere anterioare plus 1, sau 0 dacă Y nu se găseÈ™te nicăieri în cadrul lui X. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) FuncÈ›ia hex() își interpretează argumentul ca un BLOB È™i returnează un È™ir care este redarea hexazecimală cu majuscule a conÈ›inutului acelui blob. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) FuncÈ›ia iif(X,Y,Z) returnează valoarea Y dacă X este adevărat È™i Z în caz contrar. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () FuncÈ›ia last_insert_rowid() returnează ROWID al ultimului rând inserat din conexiunea bazei de date care a invocat funcÈ›ia. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) Pentru o valoare de È™ir X, funcÈ›ia length(X) returnează numărul de caractere (nu octeÈ›i) în X înainte de primul caracter NUL. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) FuncÈ›ia like() este utilizată la implementarea expresiei "Y LIKE X". (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) FuncÈ›ia like() este utilizată la implementarea expresiei "Y LIKE X ESCAPE Z". (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) FuncÈ›ia load_extension(X) încarcă extensiile SQLite din fiÈ™ierul bibliotecii partajate numit X. Utilizarea acestei funcÈ›ii trebuie autorizată din PreferinÈ›e. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) FuncÈ›ia load_extension(X) încarcă extensiile SQLite din fiÈ™ierul bibliotecii partajate numit X folosind punctul de intrare Y. Utilizarea acestei funcÈ›ii trebuie autorizată din PreferinÈ›e. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) FuncÈ›ia lower(X) returnează o copie a È™irului X cu toate caracterele ASCII convertite în minuscule. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) elimină spaÈ›iile din partea stângă a lui X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) FuncÈ›ia ltrim(X,Y) returnează un È™ir format prin eliminarea oricăror È™i tuturor caracterelor care apar în Y din partea stângă a lui X. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) FuncÈ›ia cu mai multe argumente max() returnează argumentul cu valoarea maximă sau returnează NULL dacă oricare argument este NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) FuncÈ›ia cu mai multe argumente min() returnează argumentul cu valoare minimă. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) FuncÈ›ia nullif(X,Y) returnează primul său argument dacă argumentele sunt diferite È™i NULL dacă argumentele sunt la fel. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. translate? 'C-language' (FORMAT,...) FuncÈ›ia SQL printf(FORMAT,...) funcÈ›ionează ca funcÈ›ia sqlite3_mprintf() limbaj-C È™i funcÈ›ia printf() din biblioteca standard C. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) FuncÈ›ia quote(X) returnează textul unui literal SQL care este valoarea argumentului său, potrivit pentru includerea într-o instrucÈ›iune SQL. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () FuncÈ›ia random() returnează un număr întreg pseudo-aleatoriu între -9223372036854775808 È™i + 9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) FuncÈ›ia randomblob(N) returnează un blob de N-octeÈ›i care conÈ›ine octeÈ›i pseudo-aleatori. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) FuncÈ›ia replace(X,Y,Z) returnează un È™ir format prin înlocuirea È™irului Z pentru fiecare apariÈ›ie a È™irului Y în È™irul X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) FuncÈ›ia round(X) returnează o valoare în virgulă mobilă X rotunjită la zero cifre la dreapta punctului zecimal. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) FuncÈ›ia round(X,Y) returnează o valoare în virgulă mobilă X rotunjită la Y cifre la dreapta punctului zecimal. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) elimină spaÈ›iile din partea dreaptă a lui X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) FuncÈ›ia rtrim(X,Y) returnează un È™ir format prin eliminarea oricăror È™i tuturor caracterelor care apar în Y din partea dreaptă a lui X. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) FuncÈ›ia soundex(X) returnează un È™ir care este codificarea soundex a È™irului X. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) returnează toate caracterele până la sfârÈ™itul È™irului X începând cu al Y-lea. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) FuncÈ›ia substr(X,Y,Z) returnează un subÈ™ir din È™irul de intrare X care începe cu al Y-lea caracter È™i care are o lungime de Z caractere. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () FuncÈ›ia total_changes() returnează numărul de modificări de rânduri cauzate de instrucÈ›iunile INSERT, UPDATE sau DELETE de când a fost deschisă conexiunea curentă la baza de date. (X) trim(X) removes spaces from both ends of X. (X) trim(X) elimină spaÈ›iile de la ambele capete ale lui X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) FuncÈ›ia trim(X,Y) returnează un È™ir format prin eliminarea oricăror È™i tuturor caracterelor care apar în Y de la ambele capete ale lui X. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) FuncÈ›ia typeof(X) returnează un È™ir care indică tipul de date al expresiei X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) FuncÈ›ia unicode(X) returnează punctul de cod numeric unicode corespunzător primului caracter al È™irului X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) FuncÈ›ia upper(X) returnează o copie a È™irului de intrare X în care toate caracterele ASCII minuscule sunt convertite în echivalentul lor în majuscule. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) FuncÈ›ia zeroblob(N) returnează un BLOB format din N octeÈ›i de 0x00. (timestring,modifier,modifier,...) translation in parentheses (È™ir de timp, modificator, modificator,...) (format,timestring,modifier,modifier,...) translation in parentheses (format, È™ir de timp, modificator, modificator,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) FuncÈ›ia avg() returnează valoarea medie a tuturor X non-NULL dintr-un grup. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) FuncÈ›ia count(X) returnează o numărătoare a numărului de ori în care X nu este NULL într-un grup. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) FuncÈ›ia group_concat() returnează un È™ir care este concatenarea tuturor valorilor non-NULL ale lui X. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) FuncÈ›ia group_concat() returnează un È™ir care este concatenarea tuturor valorilor non-NULL ale lui X. Dacă parametrul Y este prezent, atunci este utilizat ca separator între instanÈ›ele lui X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) FuncÈ›ia agregată max() returnează valoarea maximă a tuturor valorilor din grup. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) FuncÈ›ia agregată min() returnează valoarea minimă non-NULL a tuturor valorilor din grup. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) FuncÈ›iile agregate sum() È™i total() returnează suma tuturor valorilor non-NULL din grup. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () Numărul rândului din cadrul partiÈ›iei curente. Rândurile sunt numerotate începând de la 1 în ordinea definită de clauza ORDER BY din definiÈ›ia ferestrei sau în ordine arbitrară în caz contrar. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. unclear translation - 'peer' () row_number() al primei egalități din fiecare grup - rangul rândului curent cu goluri. Dacă nu există o clauză ORDER BY, atunci toate rândurile sunt considerate egale È™i această funcÈ›ie returnează întotdeauna 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. unclear translation - 'peer' () Numărul grupului egal al rândului curent în cadrul partiÈ›iei sale - rangul rândului curent fără goluri. PartiÈ›iile sunt numerotate începând cu 1 în ordinea definită de clauza ORDER BY în definiÈ›ia ferestrei. Dacă nu există o clauză ORDER BY, atunci toate rândurile sunt considerate egale, iar această funcÈ›ie returnează întotdeauna 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () ÃŽn ciuda numelui, această funcÈ›ie returnează întotdeauna o valoare între 0,0 È™i 1,0 egală cu (rang - 1)/(rânduri-partiÈ›ie - 1), unde rang este valoarea returnată de funcÈ›ia rank() încorporată în fereastră, iar rânduri-partiÈ›ie este numărul total de rânduri din partiÈ›ie. Dacă partiÈ›ia conÈ›ine doar un singur rând, această funcÈ›ie returnează 0,0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. unclear translation - 'peer' () DistribuÈ›ia cumulativă. Calculată ca număr-rând/rânduri-partiÈ›ie, unde număr-rând este valoarea returnată de row_number() pentru ultimul egal din grup, iar rânduri-partiÈ›ie, numărul de rânduri din partiÈ›ie. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) Argumentul N este tratat ca un număr întreg. Această funcÈ›ie împarte partiÈ›ia în N grupuri cât mai uniform posibil È™i atribuie fiecărui grup un număr întreg cuprins între 1 È™i N, în ordinea definită de clauza ORDER BY sau, în caz contrar, în ordine arbitrară. Dacă este necesar, grupurile mai mari apar primele. Această funcÈ›ie returnează valoarea întreagă atribuită grupului din care face parte rândul curent. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Returnează rezultatul evaluării expresiei expr în raport cu rândul anterior din partiÈ›ie. Sau, dacă nu există un rând anterior (deoarece rândul curent este primul), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) Dacă este furnizat argumentul offset, atunci acesta trebuie să fie un număr întreg non-negativ. ÃŽn acest caz, valoarea returnată este rezultatul evaluării expr împotriva rândurilor row offset înaintea rândului curent din partiÈ›ie. Dacă offset este 0, atunci expr este evaluat împotriva rândului curent. Dacă nu există rânduri row offset înaintea rândului curent, se returnează NULL. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) Dacă se furnizează È™i default, atunci acesta este returnat în loc de NULL dacă rândul identificat de offset nu există. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Returnează rezultatul evaluării expresiei expr în raport cu următorul rând din partiÈ›ie. Sau, dacă nu există un rând următor (deoarece rândul curent este ultimul), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) Dacă este furnizat argumentul offset, atunci acesta trebuie să fie un număr întreg non-negativ. ÃŽn acest caz, valoarea returnată este rezultatul evaluării expr împotriva rândurilor row offset după rândul curent din partiÈ›ie. Dacă offset este 0, atunci expr este evaluat împotriva rândului curent. Dacă nu există rânduri row offset după rândul curent, se returnează NULL. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Această funcÈ›ie windows încorporată calculează cadrul ferestrei pentru fiecare rând în acelaÈ™i mod ca o funcÈ›ie windows agregată. Returnează valoarea lui expr evaluată în raport cu primul rând din cadrul ferestrei pentru fiecare rând. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Această funcÈ›ie windows încorporată calculează cadrul ferestrei pentru fiecare rând în acelaÈ™i mod ca o funcÈ›ie windows agregată. Returnează valoarea lui expr evaluată în raport cu ultimul rând din cadrul ferestrei pentru fiecare rând. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) Această funcÈ›ie windows încorporată calculează cadrul ferestrei pentru fiecare rând în acelaÈ™i mod ca o funcÈ›ie windows agregată. Returnează valoarea lui expr evaluată în raport cu rândul N din cadrul ferestrei. Rândurile sunt numerotate în cadrul ferestrei începând de la 1 în ordinea definită de clauza ORDER BY, dacă este unul prezent, sau în ordine arbitrară în caz contrar. Dacă nu există al N-lea rând în partiÈ›ie, atunci se returnează NULL. (X) Return the arccosine of X. The result is in radians. (X) Returnează arccosinusul lui X. Rezultatul este în radiani. (X) Return the hyperbolic arccosine of X. (X) Returnează arccosinusul hiperbolic al lui X. (X) Return the arcsine of X. The result is in radians. (X) Returnează arcsinusul lui X. Rezultatul este în radiani. (X) Return the hyperbolic arcsine of X. (X) Returnează arcsinusul hiperbolic al lui X. (X) Return the arctangent of X. The result is in radians. (X) Returnează arctangenta lui X. Rezultatul este în radiani. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X,Y) Returnează arctangenta lui Y/X. Rezultatul este în radiani. Rezultatul este plasat în cadranul corect în funcÈ›ie de semnele lui X È™i Y. (X) Return the hyperbolic arctangent of X. (X) Returnează arctangenta hiperbolică a lui X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Returnează prima valoare întreagă reprezentabilă mai mare sau egală cu X. Pentru valori pozitive ale lui X, această rutină rotunjeÈ™te de la zero. Pentru valori negative ale lui X, această rutină rotunjeÈ™te spre zero. (X) Return the cosine of X. X is in radians. (X) Returnează cosinusul lui X. X este în radiani. (X) Return the hyperbolic cosine of X. (X) Returnează cosinusul hiperbolic al lui X. (X) Convert value X from radians into degrees. (X) ConverteÈ™te valoarea X din radiani în grade. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Calculează e (numărul lui Euler, aproximativ 2.71828182845905) ridicat la puterea X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Returnează prima valoare întreagă reprezentabilă mai mică sau egală cu X. Pentru numere pozitive, această funcÈ›ie rotunjeÈ™te spre zero. Pentru numere negative, această funcÈ›ie rotunjeÈ™te de la zero. (X) Return the natural logarithm of X. (X) Returnează logaritmul natural al lui X. (B,X) Return the base-B logarithm of X. (B,X) Returnează logaritmul în baza-B al lui X. (X) Return the base-10 logarithm for X. (X) Returnează logaritmul în baza-10 pentru X. (X) Return the logarithm base-2 for the number X. (X) Returnează logaritmul în baza-2 pentru numărul X. (X,Y) Return the remainder after dividing X by Y. (X,Y) Returnează restul după împărÈ›irea lui X la Y. () Return an approximation for Ï€. () Returnează o aproximare pentru Ï€. (X,Y) Compute X raised to the power Y. (X,Y) Calculează X ridicat la puterea Y. (X) Convert X from degrees into radians. (X) ConverteÈ™te X din grade în radiani. (X) Return the sine of X. X is in radians. (X) Returnează sinusul lui X. X este în radiani. (X) Return the hyperbolic sine of X. (X) Returnează sinusul hiperbolic al lui X. (X) Return the square root of X. NULL is returned if X is negative. (X) Returnează rădăcina pătrată a lui X. Este returnat NULL dacă X este negativ. (X) Return the tangent of X. X is in radians. (X) Returnează tangenta lui X. X este în radiani. (X) Return the hyperbolic tangent of X. (X) Returnează tangenta hiperbolică a lui X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) Returnează numărul întreg reprezentabil cuprins între X È™i 0 (inclusiv) care este cel mai îndepărtat de zero. Sau, cu alte cuvinte, returnează partea întreagă a lui X, rotunjind spre zero. SqliteTableModel reading rows citind rânduri loading... încărcare... References %1(%2) Hold %3Shift and click to jump there ReferinÈ›ele %1(%2) ÈšineÈ›i apăsat %3Shift È™i faceÈ›i clic pentru a sări acolo Error changing data: %1 Eroare la modificarea datelor: %1 retrieving list of columns recuperare listă de coloane Fetching data... unclear translation - 'fetch' Preluarea datelor... Cancel Anulare TableBrowser Browse Data Răsfoire Date &Table: &Tabel: Select a table to browse data Selectează un tabel pentru a răsfoi date Use this list to select a table to be displayed in the database view Utilizează această listă pentru a selecta un tabel care să fie afiÈ™at în vizualizarea bazei de date This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Aceasta este vizualizarea tabelului bazei de date. PuteÈ›i efectua următoarele acÈ›iuni: - ÃŽncepeÈ›i să scrieÈ›i pentru editarea în linie a valorii. - FaceÈ›i dublu clic pe orice înregistrare pentru a edita conÈ›inutul în fereastra editorului de celule. - Alt+Del pentru È™tergerea conÈ›inutului celulei la NULL. - Ctrl+" pentru duplicarea înregistrării curente. - Ctrl+' pentru copierea valorii din celula de mai sus. - OperaÈ›ii standard de selecÈ›ie È™i copiere/lipire. Text pattern to find considering the checks in this frame Model de text de găsit având în vedere verificările din acest cadru Find in table GăseÈ™te în tabel Find previous match [Shift+F3] GăseÈ™te potrivirea anterioară [Shift+F3] Find previous match with wrapping GăseÈ™te potrivirea anterioară cu înfășurare Shift+F3 Shift+F3 Find next match [Enter, F3] GăseÈ™te următoarea potrivire [Enter, F3] Find next match with wrapping GăseÈ™te următoarea potrivire cu înfășurare F3 F3 The found pattern must match in letter case Modelul găsit trebuie să se potrivească în cazul literelor Case Sensitive Caz Sensibil The found pattern must be a whole word Modelul găsit trebuie să fie un cuvânt întreg Whole Cell ÃŽntreaga Celulă Interpret search pattern as a regular expression Interpretează modelul de căutare ca expresie regulată <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>Când este bifat, modelul de găsit este interpretat ca o expresie regulată UNIX. Vezi <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Expresie Regulată Close Find Bar ÃŽnchide Bara De Căutare Text to replace with Text de înlocuit cu Replace with ÃŽnlocuire cu Replace next match ÃŽnlocuieÈ™te următoarea potrivire Replace ÃŽnlocuire Replace all matches ÃŽnlocuieÈ™te toate potrivirile Replace all ÃŽnlocuire toate <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Derulează până la început</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Făcând clic pe acest buton navighezi la început în vizualizarea tabelului de mai sus.</p></body></html> |< |< Scroll one page upwards Derulează o pagină în sus <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Făcând clic pe acest buton navighezi o pagină de înregistrări în sus în vizualizarea tabelului de mai sus.</p></body></html> < < 0 - 0 of 0 0 - 0 din 0 Scroll one page downwards Derulează o pagină în jos <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Făcând clic pe acest buton navighezi o pagină de înregistrări în jos în vizualizarea tabelului de mai sus.</p></body></html> > > Scroll to the end Derulează până la sfârÈ™it <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>Făcând clic pe acest buton navighezi până la capăt în vizualizarea tabelului de mai sus.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>FaceÈ›i clic aici pentru a trece la înregistrarea specificată</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Acest buton este utilizat pentru a naviga la numărul de înregistrare specificat în zona Mergi la.</p></body></html> Go to: Mergi la: Enter record number to browse IntroduceÈ›i numărul de înregistrare pentru a naviga Type a record number in this area and click the Go to: button to display the record in the database view IntroduceÈ›i un număr de înregistrare în această zonă È™i faceÈ›i clic pe butonul Mergi la: pentru a afiÈ™a înregistrarea în vizualizarea bazei de date 1 1 Show rowid column AfiÈ™ează coloana rowid Toggle the visibility of the rowid column Comută vizibilitatea coloanei rowid Unlock view editing Deblochează editarea vizualizării This unlocks the current view for editing. However, you will need appropriate triggers for editing. Acest lucru deblochează vizualizarea curentă pentru editare. Cu toate acestea, veÈ›i avea nevoie de declanÈ™atoare adecvate pentru editare. Edit display format Editează formatul de afiÈ™are Edit the display format of the data in this column Editează formatul de afiÈ™are a datelor din această coloană New Record ÃŽnregistrare Nouă Insert a new record in the current table Inserează o înregistrare nouă în tabelul curent <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Acest buton creează o înregistrare nouă în baza de date. ÈšineÈ›i apăsat butonul mouse-ului pentru a deschide un meniu pop-up cu diferite opÈ›iuni:</p><ul><li><span style=" font-weight:600;">ÃŽnregistrare Nouă</span>: inserează o înregistrare nouă cu valori implicite în baza de date.</li><li><span style=" font-weight:600;">Inserare Valori...</span>: deschide un dialog pentru introducerea valorilor înainte ca acestea să fie inserate în baza de date. Asta permite introducerea valorilor care îndeplinesc diferitele constrângeri. Acest dialog este, de asemenea, deschis dacă opÈ›iunea <span style=" font-weight:600;">ÃŽnregistrare Nouă</span> nu reuÈ™eÈ™te din cauza acestor constrângeri.</li></ul></body></html> Delete Record Șterge ÃŽnregistrare Delete the current record Șterge înregistrarea curentă This button deletes the record or records currently selected in the table Acest buton È™terge înregistrarea sau înregistrările selectate în prezent în tabel Insert new record using default values in browsed table Introduce o înregistrare nouă utilizănd valori implicite în tabelul navigat Insert Values... Inserează Valori... Open a dialog for inserting values in a new record Deschide un dialog pentru inserarea valorilor într-o înregistrare nouă Export to &CSV Exportă în &CSV Export the filtered data to CSV Exportă datele filtrate la CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Acest buton exportă datele din tabelul navigat, aÈ™a cum este afiÈ™at în prezent (după filtre, formate de afiÈ™are È™i coloană de ordine), ca fiÈ™ier CSV. Export to &JSON Exportă în &JSON Export the filtered data to JSON Exportă datele filtrate în JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Acest buton exportă datele tabelului navigat, aÈ™a cum este afiÈ™at în prezent (după filtre, formate de afiÈ™are È™i coloană de ordine), ca fiÈ™ier JSON. Save as &view Salvează ca &vedere Save the current filter, sort column and display formats as a view Salvează filtrul curent, coloana de sortare È™i formatele de afiÈ™are ca o vedere This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Acest buton salvează setarea curentă ale tabelului navigat (filtre, formate de afiÈ™are È™i coloană de ordine) ca vedere SQL pe care o puteÈ›i naviga ulterior sau utiliza în instrucÈ›iuni SQL. Save Table As... Salvează Tabelul Ca... Save the table as currently displayed Salvează tabelul aÈ™a cum este afiÈ™at în prezent <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>Acest meniu pop-up oferă următoarele opÈ›iuni care se aplică tabelului navigat È™i filtrat în prezent:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exportă în CSV: această opÈ›iune exportă datele din tabelul navigat, aÈ™a cum este afiÈ™ate în prezent (după filtre, formate de afiÈ™are È™i coloană de ordine) într-un fiÈ™ier CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Salvează ca vedere: această opÈ›iune salvează setarea curentă a tabelului navigat (filtre, formate de afiÈ™are È™i coloană de ordine) ca vedere SQL pe care o puteÈ›i răsfoi ulterior sau utiliza în instrucÈ›iuni SQL.</li></ul></body></html> Hide column(s) Ascunde coloană(e) Hide selected column(s) Ascunde coloana(ele) selectate Show all columns AfiÈ™ează toate coloanele Show all columns that were hidden AfiÈ™aÈ›i toate coloanele care au fost ascunse Set encoding Setează codificarea Change the encoding of the text in the table cells Modifică codificarea textului în celulele tabelului Set encoding for all tables Setează codificarea pentru toate tabelele Change the default encoding assumed for all tables in the database Modifică codificarea implicită asumată pentru toate tabelele din baza de date Copy column name Copiază numele coloanei Copy the database table column name to your clipboard Copiază numele coloanei tabelului bazei de date în clipboard-ul dumneavoastră Clear Filters Șterge Filtrele Clear all filters Șterge toate filtrele This button clears all the filters set in the header input fields for the currently browsed table. Acest buton È™terge toate filtrele setate în câmpurile de introducere a antetului pentru tabelul navigat în prezent. Clear Sorting Șterge Sortarea Reset the order of rows to the default Resetează ordinea rândurilor la cea implicită This button clears the sorting columns specified for the currently browsed table and returns to the default order. Acest buton È™terge coloanele de sortare specificate pentru tabelul navigat în prezent È™i revine la ordinea implicită. Print Imprimare Print currently browsed table data Imprimează datele tabelului navigat în prezent Print currently browsed table data. Print selection if more than one cell is selected. Imprimează datele tabelului navigat în prezent. Imprimează selecÈ›ia dacă este selectată mai mult de o celulă. Ctrl+P Ctrl+P New Data Browser Navigator De Date Nou Add a new docked Data Browser Adaugă un nou Navigator De Date ancorat This button adds a new docked Data Browser, which you can detach and arrange in different layouts. Acest buton adaugă un nou Navigator De Date ancorat, pe care îl puteÈ›i detaÈ™a È™i aranja în diferite aspecte. Refresh Reîmprospătare Refresh the data in the selected table Reîmprospătează datele in tabelul selectat This button refreshes the data in the currently selected table. Acest buton reîmprospătează datele din tabelul selectat în prezent. F5 F5 Find in cells GăseÈ™te în celule Open the find tool bar which allows you to search for values in the table view below. Deschide bara de instrumente de căutare care vă permite să căutaÈ›i valori în vizualizarea tabelului de mai jos. Bold ÃŽngroÈ™at Ctrl+B Ctrl+B Italic ÃŽnclinat Underline Subliniat Ctrl+U Ctrl+U Align Right Aliniere La Dreapta Align Left Aliniere La Stânga Center Horizontally Centrare Orizontală Justify Justifică Edit Conditional Formats... Editează formatele condiÈ›ionate ... Edit conditional formats for the current column Editează formatele condiÈ›ionate pentru coloana curentă Clear Format Șterge Format Clear All Formats Șterge Toate Formatele Clear all cell formatting from selected cells and all conditional formats from selected columns Șterge toate formatările de celulă din celulele selectate È™i toate formatele condiÈ›ionate din coloanele selectate Font Color Culoare Font Background Color Culoare Fundal Toggle Format Toolbar Comutare Bară De Instrumente De Format Show/hide format toolbar AfiÈ™ează/ascunde bara de instrumente de format This button shows or hides the formatting toolbar of the Data Browser Acest buton afiÈ™ează sau ascunde bara de instrumente de formatare a Navigatoruli De Date Select column Selectează coloana Ctrl+Space Ctrl+Space Replace text in cells ÃŽnlocuire text în celule Freeze columns ÃŽngheață coloanele Make all columns from the first column up to this column not move when scrolling horizontally FaceÈ›i toate coloanele de la prima coloană până la această coloană să nu se miÈ™te atunci când derulaÈ›i orizontal Ctrl+R Ctrl+R %n row(s) %n rând %n rânduri %n rânduri , %n column(s) , %n coloană , %n coloane , %n coloane . Sum: %1; Average: %2; Min: %3; Max: %4 . Sumă: %1; Medie: %2; Minim: %3; Maxim: %4 Conditional formats for "%1" Formate condiÈ›ionate pentru "%1" determining row count... determinând numărul de rânduri... Filter in any column Filtrează în orice coloană %L1 - %L2 of >= %L3 %L1 - %L2 din >= %L3 %L1 - %L2 of %L3 %L1 - %L2 din %L3 (clipped at %L1 rows) (tăiat la %L1 rânduri) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Vă rugăm introduceÈ›i o pseudo-cheie primară pentru a activa editarea în această vedere. Acesta ar trebui să fie numele unei coloane unice în vedere. Delete Records Șterge ÃŽnregistrările Duplicate records ÃŽnregistrări duplicate Duplicate record ÃŽnregistrare duplicată Ctrl+" Ctrl+" Adjust rows to contents Ajustează rândurile la conÈ›inut Error deleting record: %1 Eroare la È™tergerea înregistrării: %1 Please select a record first Vă rugăm să selectaÈ›i mai întâi o înregistrare Please choose a new encoding for all tables. Vă rugăm să alegeÈ›i o nouă codificare pentru toate tabelele. Please choose a new encoding for this table. Vă rugăm să alegeÈ›i o nouă codificare pentru acest tabel. %1 Leave the field empty for using the database encoding. %1 LăsaÈ›i câmpul gol pentru utilizarea codificării bazei de date. This encoding is either not valid or not supported. Această codificare nu este validă sau nu este suportată. %1 replacement(s) made. %1 înlocuire(i) efectuată. TableBrowserDock New Data Browser Navigator De Date Nou Rename Data Browser Redenumire Navigator De Date Close Data Browser ÃŽnchidere Navigator De Date Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. Setează un nume nou pentru navigatorul de date. Utilizează caracterul '&&' pentru a permite utilizarea următorului caracter ca o comandă rapidă de la tastatură. VacuumDialog Compact Database Compactare Bază De Date Warning: Compacting the database will commit all of your changes. Avertisment: Compactarea bazei de date va comite toate modificările. Please select the databases to co&mpact: Vă rugăm să selectaÈ›i bazele de date pentru co&mpactare: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_ru.ts000066400000000000000000014170531463772530400252360ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite О программе Обозреватель Ð´Ð»Ñ SQLite Version ВерÑÐ¸Ñ <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Добавить Ðовую ЗапиÑÑŒ Enter values for the new record considering constraints. Fields in bold are mandatory. Введите Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð¹ запиÑи Ñ ÑƒÑ‡ÐµÑ‚Ð¾Ð¼ ограничений. ПолÑ, выделенные жирным шрифтом, ÑвлÑÑŽÑ‚ÑÑ Ð¾Ð±Ñзательными. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Ð’ Ñтолбце "Значение" вы можете указать значение Ð´Ð»Ñ Ð¿Ð¾Ð»Ñ, указанного в Ñтолбце "ИмÑ". Ð’ Ñтолбце "Тип" указываетÑÑ Ñ‚Ð¸Ð¿ полÑ. Ð—Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию отображаютÑÑ Ð² том же Ñтиле, что и Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ NULL. Name Ð˜Ð¼Ñ Type Тип Value Значение Values to insert. Pre-filled default values are inserted automatically unless they are changed. Ð—Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð²Ñтавки. Предварительно заполненные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию вÑтавлÑÑŽÑ‚ÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки, еÑли они не изменены. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Когда вы редактируете Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² верхнем фрейме, здеÑÑŒ отображаетÑÑ Ð·Ð°Ð¿Ñ€Ð¾Ñ SQL Ð´Ð»Ñ Ð²Ñтавки Ñтой новой запиÑи. Ð’Ñ‹ можете вручную отредактировать Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿ÐµÑ€ÐµÐ´ Ñохранением. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Сохранение</span> отправит показанный оператор SQL в БД Ð´Ð»Ñ Ð²Ñтавки новой запиÑи.</p><p><span style=" font-weight:600;">ВоÑÑтановить Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию</span> воÑÑтановит иÑходные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² колонке <span style=" font-weight:600;">Значение</span>.</p><p><span style=" font-weight:600;">Отмена</span> закрывает Ñтот диалог без Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñов.</p></body></html> Auto-increment Ðвто-увеличение Unique constraint УникальноÑÑŒ Check constraint: %1 Проверка: %1 Foreign key: %1 Внешний ключ: %1 Default value: %1 Значение по умолчанию: %1 Error adding record. Message from database engine: %1 Ошибка Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ð¸Ñи. Сообщение из базы данных: %1 Are you sure you want to restore all the entered values to their defaults? Ð’Ñ‹ дейÑтвительно хотите воÑÑтановить вÑе введенные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию? Application Possible command line arguments: The user settings file location is replaced with the argument value instead of the environment variable value. Ignored environment variable (DB4S_SETTINGS_FILE) value: The file %1 does not exist Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Browse this table, or use it as target of a data import Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The -S/--settings option requires an argument. The option is ignored. The -o/--option and -O/--save-option options require an argument in the form group/setting=value Invalid option/non-existent file: %1 SQLite Version ВерÑÐ¸Ñ SQLite SQLCipher Version %1 (based on SQLite %2) DB Browser for SQLite Version %1. Last commit hash when built: %1 Built for %1, running on %2 Qt Version %1 CipherDialog SQLCipher encryption Шифрование SQLCipher &Password &Пароль &Reenter password Пароль &ещё раз Encr&yption settings SQLCipher &3 defaults SQLCipher &4 defaults Custo&m Page si&ze Размер &Ñтраницы &KDF iterations HMAC algorithm KDF algorithm Plaintext Header Size Passphrase Фраза Raw key Ключ Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. ПожалуйÑта укажите ключ шифрованиÑ. ЕÑли вы измените какую-либо опциональную наÑтройку, то ее нужно будет вводить при каждом открытии Ñтого файла базы данных. ОÑтавьте пароль пуÑтым еÑли шифрование не требуетÑÑ. ПроцеÑÑ Ð¼Ð¾Ð¶ÐµÑ‚ занÑть некоторое Ð²Ñ€ÐµÐ¼Ñ Ð¸ наÑтоÑтельно рекомендуем Ñоздать резервную копию перед продолжением! Ðе Ñохраненные Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки будут Ñохранены. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. ПожалуйÑта введите ключ Ð´Ð»Ñ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных. ЕÑли любые другие наÑтройки были изменены Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð¹ базы данный то нужно так же предоÑтавить данную информацию. ColumnDisplayFormatDialog Choose display format Выберите формат Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Display format Формат Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Choose a display format for the column '%1' which is applied to each value prior to showing it. Выберите формат Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ¸ '%1', который будет применен к каждому ее значению. Default По умолчанию Decimal number ДеÑÑтичное чиÑло Exponent notation ЭкÑÐ¿Ð¾Ð½ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ Hex blob Бинарные данные Hex number ШеÑтнадцатеричное чиÑло Apple NSDate to date Apple NSDate дата Java epoch (milliseconds) to date Java epoch дата .NET DateTime.Ticks to date Julian day to date ЮлианÑÐºÐ°Ñ Ð´Ð°Ñ‚Ð° Unix epoch to local time Unix-Ð²Ñ€ÐµÐ¼Ñ WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy Дата в формате дд/мм/гггг Lower case Ðижний региÑтр Binary GUID to text SpatiaLite Geometry to SVG Custom display format must contain a function call applied to %1 Error in custom display format. Message from database engine: %1 Custom display format must return only one column but it returned %1. Octal number ВоÑьмеричное чиÑло Round number Округленное чиÑло Unix epoch to date Unix-дата Upper case Верхний региÑтр Windows DATE to date Windows дата Custom Мой формат CondFormatManager Conditional Format Manager This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Add new conditional format &Add &Добавить Remove selected conditional format &Remove &Удалить Move selected conditional format up Move &up Move selected conditional format down Move &down Foreground Передний план Text color Цвет текÑта Background Фон Background color Цвет фона Font Шрифт Size Размер Bold Жирный Italic КурÑив Underline Подчёркивание Alignment Condition Click to select color Are you sure you want to clear all the conditional formats of this field? DBBrowserDB Please specify the database name under which you want to access the attached database Invalid file format Ошибочный формат файла Do you want to save the changes made to the database file %1? Сохранить Ñделанные Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² файле базы данных %1? Exporting database to SQL file... ЭкÑпорт базы данных в файл SQL... Cancel Отменить Executing SQL... Выполнить код SQL... Action cancelled. ДейÑтвие отменено. Do you really want to close this temporary database? All data will be lost. Ð’Ñ‹ дейÑтвительно хотите закрыть Ñту временную БД? Ð’Ñе данные будут потерÑны. Database didn't close correctly, probably still busy Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: БД занÑта: Do you want to abort that other operation? Ð’Ñ‹ хотите отменить Ñту операцию? No database file opened Файл БД не открыт Error in statement #%1: %2. Aborting execution%3. Ошибка в выражении #%1: %2. Прерываем выполнение%3. and rolling back и отменÑем didn't receive any output from %1 could not execute command: %1 Cannot delete this object Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ Ñтот объект Cannot set data on this object Ðевозможно назначить данные Ð´Ð»Ñ Ñтого объекта A table with the name '%1' already exists in schema '%2'. Таблица Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%1' уже ÑущеÑтвует в Ñхеме '%2'. No table with name '%1' exists in schema '%2'. Cannot find column %1. Creating savepoint failed. DB says: %1 Renaming the column failed. DB says: %1 Releasing savepoint failed. DB says: %1 Creating new table failed. DB says: %1 Copying data to new table failed. DB says: %1 Deleting old table failed. DB says: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 could not get list of db objects: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Ошибка воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð½ÐµÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… объектов, аÑÑоциированных Ñ Ñтой таблицей. Ðаиболее вероÑÑ‚Ð½Ð°Ñ Ð¿Ñ€Ð¸Ñ‡Ð¸Ð½Ð° Ñтого - изменение имён некоторых Ñтолбцов таблицы. Вот SQL оператор, который нужно иÑправить и выполнить вручную: could not get list of databases: %1 не могу получить ÑпиÑок БД: %1 Error loading extension: %1 Ошибка загрузки раÑширениÑ: %1 Error loading built-in extension: %1 could not get column information не могу получить информацию о колонке Error setting pragma %1 to %2: %3 Ошибка уÑтановки прагмы %1 в %2: %3 File not found. Файл не найден. DbStructureModel Name Ð˜Ð¼Ñ Object Объект Type Тип Schema Схема Database База данных Browsables ПроÑматриваемые All Ð’Ñе Temporary Временный Tables (%1) Таблицы (%1) Indices (%1) ИндекÑÑ‹ (%1) Views (%1) ПредÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ (%1) Triggers (%1) Триггеры (%1) EditDialog Edit database cell Редактирование Ñчейки базы данных Mode: Режим: Image Изображение Set as &NULL ПриÑвоить &NULL Apply data to cell Применить данные к Ñчейке This button saves the changes performed in the cell editor to the database cell. Ðажав Ñту кнопку, вы Ñохраните Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð½Ñ‹Ðµ в Ñтом редакторе, в ÑоответÑтвующую Ñчейку БД. Apply Применить Text ТекÑÑ‚ This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Это ÑпиÑок поддерживаемых режимов. Выберите режим Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра или Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… текущей Ñчейки. RTL Text Binary Двоичные данные JSON XML Evaluation Automatically adjust the editor mode to the loaded data type ÐвтоматичеÑки подбор режима редактора на оÑнове данных This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Эта кнопка позволÑет включать или отключать автоматичеÑкое переключение режима редактора. Когда выбрана Ð½Ð¾Ð²Ð°Ñ Ñчейка или импортированы новые данные, а автоматичеÑкое переключение включено, режим наÑтраиваетÑÑ Ð½Ð° обнаруженный тип данных. Ð’Ñ‹ можете вручную изменить режим редактора. ЕÑли вы хотите Ñохранить Ñтот режим ручного Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ перемещении по Ñчейкам, выключите кнопку. Auto-switch Ðвтопереключение This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Identification of the cell currently in the editor Type and size of data currently in table Open preview dialog for printing the data currently stored in the cell Auto-format: pretty print on loading, compact on saving. ÐвтоматичеÑкое форматирование: ÑтилиÑтичеÑкое форматирование при загрузке, компактноÑть - при Ñохранении. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Когда включено, Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑкого Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€ÑƒÐµÑ‚ данные по загрузке, Ñ€Ð°Ð·Ð±Ð¸Ð²Ð°Ñ Ñ‚ÐµÐºÑÑ‚ в Ñтроках и отÑтупы Ð´Ð»Ñ Ð¼Ð°ÐºÑимальной читаемоÑти. При Ñохранении данных Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑкого Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±ÑŠÐµÐ´Ð¸Ð½Ñет данные, удалÑющие конец Ñтрок, и ненужные пробелы. Word Wrap Wrap lines on word boundaries Open in default application or browser Open in application The value is interpreted as a file or URL and opened in the default application or web browser. Save file reference... Save reference to file Open in external application Autoformat Ðвтоформатирование &Export... &Import... Import from file Импортировать из файла Opens a file dialog used to import any kind of data to this database cell. Открывает диалоговое окно файла, иÑпользуемое Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° любых данных в Ñту Ñчейку базы данных. Export to file ЭкÑпортировать в файл Opens a file dialog used to export the contents of this database cell to a file. Открывает диалоговое окно файла, иÑпользуемое Ð´Ð»Ñ ÑкÑпорта Ñодержимого Ñтой Ñчейки базы данных в файл. Erases the contents of the cell ОчищаетÑÑ Ñодержимое Ñчейки This area displays information about the data present in this database cell Эта облаÑть отображает информацию о данных, находÑщихÑÑ Ð² Ñтой Ñчейке базы данных Print... Печать... Ctrl+P Open preview dialog for printing displayed text Открыть диалоговое окно предварительного проÑмотра Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ отображаемого текÑта Copy Hex and ASCII Копировать HEX и ASCII Copy selected hexadecimal and ASCII columns to the clipboard Копировать выбранные HEX и ASCII Ñтолбцы в буфер обмена Ctrl+Shift+C Choose a filename to export data Выбрать Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð´Ð»Ñ ÑкÑпорта данных Image data can't be viewed in this mode. Изображение не может быть отображено в Ñтом режиме. Try switching to Image or Binary mode. Попробуйте переключитьÑÑ Ð² Бинарный режим или режим ИзображениÑ. Binary data can't be viewed in this mode. Бинарные данные не могут быть отображены в Ñтом режиме. Try switching to Binary mode. Попробуйте переключитьÑÑ Ð² Бинарный режим. Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) Couldn't save file: %1. Ðе удалоÑÑŒ Ñохранить файл:%1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Image files (%1) Файлы изображений (%1) Binary files (*.bin) Бинарные файлы (*.bin) Choose a file to import Выбрать файл Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Unsaved data in the cell editor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. %1 Image %1 Изображение Invalid data for this mode Ошибочные данные Ð´Ð»Ñ Ñтого режима The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? Ячейка Ñодержит ошибочные %1 данные. Причина: %2. Ð’Ñ‹ дейÑтвительно хотите применить их? EditIndexDialog &Name &Ð˜Ð¼Ñ Order Сортировка &Table &Таблица Edit Index Schema Редактирование ИндекÑа &Unique &Уникальный For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Ð”Ð»Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа только чаÑтью таблицы вы можете указать здеÑÑŒ выражение WHERE, которое выбирает чаÑть таблицы, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° быть проиндекÑирована Partial inde&x clause &ЧаÑтичный Ð¸Ð½Ð´ÐµÐºÑ Colu&mns &Колонки Table column Колонка таблицы Type Тип Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Добавить новое колоночное выражение в индекÑ. Колоночное выражение может Ñодержать SQL Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð²Ð¼ÐµÑто имён колонок. Index column Колонка индекÑа Deleting the old index failed: %1 Удаление Ñтарого индекÑа завершилоÑÑŒ Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ¾Ð¹: %1 Creating the index failed: %1 Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа: %1 EditTableDialog Edit table definition Редактирование Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ Table Таблица Advanced Дополнительно Without Rowid Без rowid Database sche&ma Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Fields ÐŸÐ¾Ð»Ñ Add Remove Move to top Move up Move down Move to bottom Name Ð˜Ð¼Ñ Type Тип NN ÐП Not null Ðе пуÑтое (null) PK ПК <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> AI ÐИ Autoincrement Ðвтоинкремент U У Unique Уникальное Default По умолчанию Default value Значение по умолчанию Check Проверить Check constraint Проверить ограничение Collation Foreign Key Внешний ключ <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Index Constraints Add constraint Remove constraint Columns Столбцы SQL Foreign Keys References Check Constraints <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Внимание: </span>Ð’ опиÑании Ñтой таблицы еÑть что-то, что наш парÑер не понимает. ÐœÐ¾Ð´Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¸ Ñохранение Ñтой таблицы может породить проблемы.</p></body></html> Primary Key Add a primary key constraint Add a unique constraint Error creating table. Message from database engine: %1 Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹. Сообщение от движка базы данных: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Поле Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем уже ÑущеÑтвует. ПожалуйÑта переименуйте его, либо выберите другое Ð¸Ð¼Ñ Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ полÑ. There can only be one primary key for each table. Please modify the existing primary key instead. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Ðа данную колонку ÑÑылаетÑÑ Ð²Ð½ÐµÑˆÐ½Ð¸Ð¹ ключ в таблице %1, поÑтому ее Ð¸Ð¼Ñ Ð½Ðµ может быть изменено. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. СущеÑтвует по крайней мере одна Ñтрока, где Ñто поле уÑтановлено в NULL. УÑтановить Ñтот флаг нельзÑ. Сначала измените данные таблицы. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. СущеÑтвует по крайней мере одна Ñтрока, где Ñто поле Ñодержит нечиÑловое значение. УÑтановить флаг ÐИ нельзÑ. Сначала измените данные таблицы. Column '%1' has duplicate data. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Удалить поле '%1'? Ð’Ñе данные, которые в наÑтоÑщий момент Ñохранены в Ñтом поле, будут потерÑны. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Перед тем как применÑть флаг без rowid, пожалуйÑта убедитеÑÑŒ, что ÑущеÑтвует Ñтолбец, который: - ÑвлÑетÑÑ Ð¿ÐµÑ€Ð²Ð¸Ñ‡Ð½Ñ‹Ð¹ ключом - Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ отключен автоинкремент Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set ExportDataDialog Export data as CSV ЭкÑпортировать данные в формате CSV Tab&le(s) &Таблицы Colu&mn names in first line &Имена Ñтолбцов в первой Ñтроке Fie&ld separator &Разделитель полей , , ; ; Tab ТабулÑÑ†Ð¸Ñ | | Other Другой &Quote character &Символ кавычки " " ' ' New line characters Разделитель Ñтрок Windows: CR+LF (\r\n) Unix: LF (\n) Pretty print КраÑивый вывод Could not open output file: %1 Ðе удалоÑÑŒ открыть выходной файл: %1 Choose a filename to export data Выберите Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð´Ð»Ñ ÑкÑпорта данных Export data as JSON ЭкÑпортировать данные как JSON exporting CSV ÑкÑпортирование CSV Error while writing the file '%1': %2 exporting JSON ÑкÑпортирование JSON Please select at least 1 table. ПожалуйÑта, выберите Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одну таблицу. Choose a directory Выберите каталог Export completed. ЭкÑпорт завершён. Export finished with errors. ExportSqlDialog Export SQL... ЭкÑпорт SQL.... Tab&le(s) &Таблицы Select All Выбрать вÑе Deselect All Отменить выбор &Options &Опции Keep column names in INSERT INTO Ð˜Ð¼Ñ Ñтолбцов в выражении INSERT INTO Multiple rows (VALUES) per INSERT statement ÐеÑколько Ñтрок (VALUES) на INSERT выражение Export everything ЭкÑпортировать вÑе Export data only ЭкÑпортировать только данные Keep original CREATE statements Keep old schema (CREATE TABLE IF NOT EXISTS) ПроверÑть ÑущеÑтвование таблицы (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) УдалÑть Ñтарую таблицу перед Ñозданием (DROP TABLE, затем CREATE TABLE) Export schema only ЭкÑпортировать только Ñхему данных Please select at least one table. ПожалуйÑта, выберите Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одну таблицу. Choose a filename to export Выберите Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð´Ð»Ñ ÑкÑпорта Export completed. ЭкÑпорт завершён. Export cancelled or failed. ЭкÑпорт отменён или возникли ошибки. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Find and Replace... Ðайти и Заменить... Print... Печать... ExtendedTableWidget Use as Exact Filter ИÑпользовать как Точный Фильтр Containing Содержит Not containing Not equal to Ðе равно Greater than Больше чем Less than Меньше чем Greater or equal Больше или равно Less or equal Меньше или равно Between this and... Между Ñтим и... Regular expression Edit Conditional Formats... Set to NULL СброÑить в NULL Cut Copy Копировать Copy with Headers Копировать Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ°Ð¼Ð¸ Copy as SQL Копировать как SQL Paste Ð’Ñтавить Print... Печать... Use in Filter Expression ИÑпользовать в Выражении Фильтра Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? Содержимое буфера обмена больше чем выделенный диапазон. Ð’Ñе равно вÑтавить? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. FileExtensionManager File Extension Manager Менеджер раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² &Up &Выше &Down &Ðиже &Add &Добавить &Remove &Удалить Description ОпиÑание Extensions РаÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ *.extension FilterLineEdit Filter Фильтр These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Clear All Conditional Formats Use for Conditional Format Edit Conditional Formats... Set Filter Expression УÑтановить Выражение Фильтра What's This? Что Это? Is NULL NULL Is not NULL не NULL Is empty пуÑто Is not empty не пуÑто Not containing... Equal to... Равно... Not equal to... Ðе равно... Greater than... Больше чем... Less than... Меньше чем... Greater or equal... Больше или равно... Less or equal... Меньше или равно... In range... Ð’ диапазоне... Regular expression... FindReplaceDialog Find and Replace ПоиÑк и Замена Fi&nd text: &ТекÑÑ‚ Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка: Re&place with: ТекÑÑ‚ Ð´Ð»Ñ &замены: Match &exact case Учитывать &региÑтр Match &only whole words Слова &целиком When enabled, the search continues from the other end when it reaches one end of the page Когда отмечено, поиÑк продолжаетÑÑ Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð³Ð¾ конца, когда он доÑтигает противоположного конца Ñтраницы &Wrap around &Закольцевать When set, the search goes backwards from cursor position, otherwise it goes forward Когда отмечено, поиÑк возвращаетÑÑ Ð½Ð°Ð·Ð°Ð´ из Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐºÑƒÑ€Ñора, в противном Ñлучае он идет вперед Search &backwards ИÑкать в &обратном порÑдке <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> &Selection only <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>При проверке шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка интерпретируетÑÑ ÐºÐ°Ðº регулÑрное выражение UNIX. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Узнать больше о РегулÑрных выражениÑÑ… на Wikibooks.org</a>.</p></body></html> Use regular e&xpressions &РегулÑрные Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Find the next occurrence from the cursor position and in the direction set by "Search backwards" Ðайдите Ñледующее вхождение из позиции курÑора и в направлении, заданном "ИÑкать назад" &Find Next ИÑкать &дальше F3 &Replace &Замена Highlight all the occurrences of the text in the page Выделить вÑе Ð²Ñ…Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑта на Ñтранице F&ind All Ðайти &вÑе Replace all the occurrences of the text in the page Заменить вÑе Ð²Ñ…Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑта на Ñтранице Replace &All За&менить вÑе The searched text was not found ИÑкомый текÑÑ‚ не найден The searched text was not found. ИÑкомый текÑÑ‚ не найден. The searched text was found one time. ИÑкомый текÑÑ‚ найден один раз. The searched text was found %1 times. ИÑкомый текÑÑ‚ найден %1 раз. The searched text was replaced one time. ИÑкомый текÑÑ‚ заменен один раз. The searched text was replaced %1 times. ИÑкомый текÑÑ‚ заменен %1 раз. ForeignKeyEditor &Reset &Ð¡Ð±Ñ€Ð¾Ñ Foreign key clauses (ON UPDATE, ON DELETE etc.) УÑÐ»Ð¾Ð²Ð¸Ñ (ON UPDATE, ON DELETE и Ñ‚.д.) ImageViewer Image Viewer Reset the scaling to match the original size of the image. Set the scaling to match the size of the viewport. Print... Печать... Open preview dialog for printing displayed image Открыть диалоговое окно предварительного проÑмотра Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ отображаемого Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ctrl+P ImportCsvDialog Import CSV file Импортировать файл в формате CSV Table na&me &Ð˜Ð¼Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ &Column names in first line И&мена Ñтолбцов в первой Ñтроке Field &separator &Разделитель полей , ; Tab ТабулÑÑ†Ð¸Ñ | Other Другой &Quote character &Символ кавычки Other (printable) Other (code) " ' &Encoding &Кодировка UTF-8 UTF-16 ISO-8859-1 Trim fields? Обрезать полÑ? Separate tables Отдельные таблицы Advanced Дополнительно When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. При импорте пуÑтого Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¸Ð· файла CSV в ÑущеÑтвующую таблицу Ð´Ð»Ñ Ñтолбца Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ значением по умолчанию оно будет вÑтавлено. Ðктивируйте Ñту опцию, чтобы вмеÑто Ñтого вÑтавить пуÑтое значение. Ignore default &values Игнорировать значение &по-умолчанию Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Ðктивируйте Ñту опцию чтобы прекратить импорт при попытке импорта пуÑтого Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² NOT NULL колонку без Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾-умолчанию. Fail on missing values Ошибка при отÑутÑтвии значений Disable data type detection Отключить определение типа данных Disable the automatic data type detection when creating a new table. Отключить автоматичеÑкое определение типа при Ñоздании новой таблицы. Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Abort import Ignore row Replace existing row Conflict strategy Deselect All Отменить Выбор Match Similar Ðайти Ð¡Ð¾Ð²Ð¿Ð°Ð´ÐµÐ½Ð¸Ñ Select All Выбрать Ð’Ñе There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. Уже ÑущеÑтвует таблица Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%1' и импорт в ÑущеÑтвующую таблицу возможен, только еÑли чиÑло Ñтолбцов Ñовпадает. There is already a table named '%1'. Do you want to import the data into it? Уже ÑущеÑтвует таблица Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%1'. Ð’Ñ‹ хотите импортировать данные в нее? Creating restore point failed: %1 Ошибка ÑÐ¾Ð·Ð½Ð°Ð½Ð¸Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸ воÑÑтановлениÑ: %1 Creating the table failed: %1 Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹: %1 importing CSV импортирование CSV Could not prepare INSERT statement: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Импорт файла '%1' занÑл %2мÑ. Из них %3Ð¼Ñ Ð±Ñ‹Ð»Ð¾ потрачено в функции Ñтроки. Inserting row failed: %1 Ошибка вÑтавки Ñтроки: %1 MainWindow DB Browser for SQLite Обозреватель Ð´Ð»Ñ SQLite toolBar1 панельИнÑтрументов1 Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Предупреждение: Ñта прагма не читаетÑÑ, и Ñто значение было выведено. Применение прагмы может перезапиÑать переопределенный LIKE, предоÑтавлÑемый раÑширением SQLite. Too&ls &ИнÑтрументы Error Log This button clears the contents of the SQL logs Эта кнопка очищает Ñодержимое журналов SQL This panel lets you examine a log of all SQL commands issued by the application or by yourself Эта панель позволÑет вам проÑматривать журнал вÑех SQL-команд, выданных приложением или вами This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Это Ñтруктура открытой БД. Ð’Ñ‹ можете перетащить неÑколько имен объектов из Ñтолбца "ИмÑ" и отброÑить их в редактор SQL, и вы можете наÑтроить ÑвойÑтва Ñброшенных имен Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ контекÑтного меню. Это поможет вам при ÑоÑтавлении SQL-инÑтрукций. Ð’Ñ‹ можете перетаÑкивать операторы SQL из Ñтолбца "Схема" и переноÑить их в редактор SQL или в другие приложениÑ. Project Toolbar Панель ИнÑтрументов Проекта Extra DB toolbar Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÐŸÐ°Ð½ÐµÐ»ÑŒ ИнÑтрументов БД Close the current database file Закрыть файл текущей БД &New Database Ctrl+F4 &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. &About О &программе New &tab This button opens a new tab for the SQL editor Эта кнопка открывает новую вкладку Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¾Ñ€Ð° SQL Execute all/selected SQL Выполнить вÑе/выбранный SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Эта кнопка выполнÑет текущие выбранные операторы SQL. ЕÑли в текÑтовом редакторе ничего не выбрано , вÑе инÑтрукции SQL выполнÑÑŽÑ‚ÑÑ. Ctrl+Shift+T &Load Extension... &Загрузить раÑширение... Execute line This button executes the SQL statement present in the current editor line Эта кнопка выполнÑет оператор SQL, приÑутÑтвующий в текущей Ñтроке редактора &Wiki &Вики F1 Bug &Report... Баг &репорт... Feature Re&quest... ЗапроÑить &функцию... Web&site &Веб-Ñайт &Donate on Patreon... Сделать &пожертвование в Patreon... &Save Project Open &Project... Открыть &проект... Open &Project &Attach Database... &Прикрепить БД... Add another database file to the current database connection Добавить другой файл БД в текущее Ñоединение This button lets you add another database file to the current database connection Эта кнопка позволÑет добавить другой файл БД в текущее Ñоединение Ñ Ð‘Ð” &Set Encryption... Ðазначить &шифрование... This button saves the content of the current SQL editor tab to a file Эта кнопка ÑохранÑет Ñодержимое текущей вкладки редактора SQL в файл SQLCipher &FAQ Table(&s) to JSON... Таблицы в файл &JSON... Open Data&base Read Only... Открыть БД &только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ... Ctrl+Shift+O Save results Сохранить результаты Save the results view Сохранить результаты This button lets you save the results of the last executed query Эта кнопка позволÑет Ñохранить результаты поÑледнего выполненного запроÑа Find text in SQL editor Ðайти текÑÑ‚ в редакторе SQL Find This button opens the search bar of the editor Эта кнопка открывает панель поиÑка редактора Ctrl+F Find or replace text in SQL editor Ðайти или заменить текÑÑ‚ в редакторе SQL Find or replace This button opens the find/replace dialog for the current editor tab Эта кнопка открывает диалог поиÑка/замены Ð´Ð»Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ вкладки редактора Ctrl+H Export to &CSV ЭкÑпортировать в &CSV Export to &JSON Save as &view Сохранить как &предÑтавление Save as view Сохранить как предÑтавление Shows or hides the Project toolbar. Показывает или Ñкрывает панель инÑтрументов Проекта. Extra DB Toolbar Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÐŸÐ°Ð½ÐµÐ»ÑŒ ИнÑтрументов БД Ctrl+Shift+W Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Refresh Обновить Reload the database structure Open SQL file(s) &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs E&xecute SQL This has to be equal to the tab title in all the main tabs &Recent Files This button opens files containing SQL statements and loads them in new editor tabs This button lets you open a DB Browser for SQLite project file &Open Database New In-&Memory Database ÐÐ¾Ð²Ð°Ñ Ð‘Ð” в &ПамÑти Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Drag && Drop Qualified Names Квалифицированные имена при перетаÑкивании Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Квалифицированные имена (например, "Table"."Field") при перетаÑкивании объектов в редактор Drag && Drop Enquoted Names Экранированные имена при перетаÑкивании Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Экранировать имена идентификаторов (например, "Table1"), когда перетаÑкиваютÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚Ñ‹ в редактор &Integrity Check Проверка &ЦелоÑтноÑти Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. ВыполнÑет прагму integrity_check Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¾Ð¹ БД и возвращает результаты во вкладке "SQL". Эта прагма выполнÑет проверку целоÑтноÑти вÑей базы данных. &Foreign-Key Check Проверка &Внешних ключей Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab ЗапуÑкает прагму foreign_key_check Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¾Ð¹ БД и возвращает результаты во вкладке "SQL" &Quick Integrity Check &БыÑÑ‚Ñ€Ð°Ñ ÐŸÑ€Ð¾Ð²ÐµÑ€ÐºÐ° ЦелоÑтноÑти Run a quick integrity check over the open DB ЗапуÑк быÑтрой проверки целоÑтноÑти Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¹ БД Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. ЗапуÑкает прагму quick_check Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¾Ð¹ БД и возвращает результаты во вкладке "SQL". Эта команда выполнÑет большую чаÑть проверки PRAGMA integrity_check, но работает намного быÑтрее. &Optimize &ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Attempt to optimize the database Попытка оптимизации БД Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. ВыполнÑет прагму optimize Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¾Ð¹ БД. Эта прагма может выполнÑть оптимизацию, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐ¸Ñ‚ производительноÑть будущих запроÑов. Print Печать Print text from current SQL editor tab Печать текÑта из текущей вкладки редактора SQL Open a dialog for printing the text in the current SQL editor tab Открывает диалоговое окно Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ текÑта из текущей вкладки редактора SQL Print the structure of the opened database Печать Ñтруктуры открытой БД Open a dialog for printing the structure of the opened database Открывает диалоговое окно Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ Ñтруктуры текущей БД Un/comment block of SQL code Un/comment block Comment or uncomment current line or selected block of code Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Ctrl+/ Stop SQL execution Stop execution Stop the currently running SQL script Browse Table Close Pro&ject Close project and database files and return to the initial state Ctrl+Shift+F4 Detach Database Detach database file attached to the current database connection &Save Project As... Save the project in a file selected in a dialog Save A&ll Save DB file, project file and opened SQL files Ctrl+Shift+S &File &Файл &Import &Импорт &Export &ЭкÑпорт &Edit &Редактирование &View &Вид &Help &Справка DB Toolbar Панель инÑтрументов БД Edit Database &Cell Редактирование &Ñчейки БД DB Sche&ma Схе&ма БД &Remote &Удаленный Ñервер Execute current line Выполнить текущую Ñтроку Shift+F5 Sa&ve Project &Сохранить проект Open an existing database file in read only mode Открыть ÑущеÑтвующий файл базы данных в режиме только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Opens the SQLCipher FAQ in a browser window Открыть SQLCiphier FAQ в браузере Export one or more table(s) to a JSON file ЭкÑпортировать таблицы в JSON файл Save SQL file as Сохранить файл SQL как &Browse Table Пр&оÑмотр данных User Пользователем Application Приложением &Clear О&чиÑтить &New Database... &ÐÐ¾Ð²Ð°Ñ Ð±Ð°Ð·Ð° данных... Create a new database file Создать новый файл базы данных This option is used to create a new database file. Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¸ÑпользуетÑÑ, чтобы Ñоздать новый файл базы данных. Ctrl+N &Open Database... &Открыть базу данных... Open an existing database file Открыть ÑущеÑтвующий файл базы данных This option is used to open an existing database file. Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¸ÑпользуетÑÑ, чтобы открыть ÑущеÑтвующий файл базы данных. Ctrl+O &Close Database &Закрыть базу данных This button closes the connection to the currently open database file Эта кнопка закрывает Ñоединение Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼ файлом БД Ctrl+W Revert database to last saved state Вернуть базу данных в поÑледнее Ñохранённое ÑоÑтоÑние This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¸ÑпользуетÑÑ, чтобы вернуть текущий файл базы данных в его поÑледнее Ñохранённое ÑоÑтоÑние. Ð’Ñе изменениÑ, Ñделанные Ñ Ð¿Ð¾Ñледней операции ÑохранениÑ, терÑÑŽÑ‚ÑÑ. Write changes to the database file ЗапиÑать Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² файл базы данных This option is used to save changes to the database file. Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¸ÑпользуетÑÑ, чтобы Ñохранить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² файле базы данных. Ctrl+S Compact &Database... &Уплотнить базу данных... Compact the database file, removing space wasted by deleted records Уплотнить базу данных, удалÑÑ Ð¿Ñ€Ð¾ÑтранÑтво, занимаемое удалёнными запиÑÑми Compact the database file, removing space wasted by deleted records. Уплотнить базу данных, удалÑÑ Ð¿Ñ€Ð¾ÑтранÑтво, занимаемое удалёнными запиÑÑми. E&xit &Выход Ctrl+Q Import data from an .sql dump text file into a new or existing database. Импортировать данные из текÑтового файла sql в новую или ÑущеÑтвующую базу данных. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет импортировать данные из текÑтового файла sql в новую или ÑущеÑтвующую базу данных. Файл SQL может быть Ñоздан на большинÑтве движков баз данных, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ MySQL и PostgreSQL. Open a wizard that lets you import data from a comma separated text file into a database table. Открыть маÑтер, который позволÑет импортировать данные из файла CSV в таблицу базы данных. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Открыть маÑтер, который позволÑет импортировать данные из файла CSV в таблицу базы данных. Файлы CSV могут быть Ñозданы в большинÑтве приложений баз данных и Ñлектронных таблиц. Export a database to a .sql dump text file. ЭкÑпортировать базу данных в текÑтовый файл .sql. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет ÑкÑпортировать базу данных в текÑтовый файл .sql. Файлы SQL Ñодержат вÑе данные, необходимые Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных в большинÑтве движков баз данных, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ MySQL и PostgreSQL. Export a database table as a comma separated text file. ЭкÑпортировать таблицу базы данных как CSV текÑтовый файл. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. ЭкÑпортировать таблицу базы данных как CSV текÑтовый файл, готовый Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² другие базы данных или Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñлектронных таблиц. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Открыть маÑтер ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†, где возможно определить Ð¸Ð¼Ñ Ð¸ Ð¿Ð¾Ð»Ñ Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð¹ таблицы в базе данных Open the Delete Table wizard, where you can select a database table to be dropped. Открыть маÑтер ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹, где можно выбрать таблицу базы данных Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ. Open the Create Index wizard, where it is possible to define a new index on an existing database table. Открыть маÑтер ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа, в котором можно определить новый Ð¸Ð½Ð´ÐµÐºÑ Ð´Ð»Ñ ÑущеÑтвующей таблиц базы данных. &Preferences... &ÐаÑтройки... Open the preferences window. Открыть окно наÑтроек. &DB Toolbar &Панель инÑтрументов БД Shows or hides the Database toolbar. Показать или Ñкрыть панель инÑтрументов База данных. Shift+F1 &Recently opened &Ðедавно открываемые Ctrl+T This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Это Ñтруктура открытой БД. Ð’Ñ‹ можете перетаÑкивать операторы SQL из Ñтроки "объект" и переноÑить их в другие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ в другой ÑкземплÑÑ€ "Обозреватель Ð´Ð»Ñ SQLite". SQL &Log &Журнал SQL Show S&QL submitted by По&казывать SQL, выполненный &Plot &График &Revert Changes &Отменить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ &Write Changes &ЗапиÑать Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ &Database from SQL file... &База данных из файла SQL... &Table from CSV file... &Таблицы из файла CSV... &Database to SQL file... Базу &данных в файл SQL... &Table(s) as CSV file... &Таблицы в файл CSV... &Create Table... &Создать таблицу... &Delete Table... &Удалить таблицу... &Modify Table... &Изменить таблицу... Create &Index... Создать и&ндекÑ... W&hat's This? Что &Ñто такое? &Execute SQL Ð’&ыполнить код SQL Save SQL file Сохранить файл SQL Ctrl+E Export as CSV file ЭкÑпортировать в файл CSV Export table as comma separated values file ЭкÑпортировать таблицу как CSV файл Save the current session to a file Сохранить текущее ÑоÑтоÑние в файл This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Load a working session from a file Загрузить рабочее ÑоÑтоÑние из файла Copy Create statement Копировать CREATE выражение Copy the CREATE statement of the item to the clipboard Копировать CREATE выражение Ñлемента в буфер обмена Ctrl+Return Ctrl+L Ctrl+P Ctrl+D Ctrl+I Reset Window Layout The database is currently busy. Click here to interrupt the currently running query. Encrypted Зашифровано Read only Только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Database file is read only. Editing the database is disabled. База данных только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ. Редактирование запрещено. Database encoding Кодировка базы данных Database is encrypted using SQLCipher База данных зашифрована Ñ Ð¸Ñпользованием SQLCipher Choose a database file Выбрать файл базы данных Could not open database file. Reason: %1 Ðе удалоÑÑŒ открыть файл базы данных. Причина:%1 Choose a filename to save under Выбрать имÑ, под которым Ñохранить данные A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Вышла Ð½Ð¾Ð²Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ ÐžÐ±Ð¾Ð·Ñ€ÐµÐ²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ SQLite (%1.%2.%3).<br/><br/>Она доÑтупна Ð´Ð»Ñ ÑÐºÐ°Ñ‡Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ адреÑу <a href='%4'>%4</a>. DB Browser for SQLite project file (*.sqbpro) Файл проекта ÐžÐ±Ð¾Ð·Ñ€ÐµÐ²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ SQLite (*.sqbpro) Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Ошибка при Ñохранении файла базы данных. Это означает, что не вÑе Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² базе данных были Ñохранены. Сначала вам необходимо разрешить Ñледующую ошибку. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? Отменить вÑе изменениÑ, Ñделанные в файле базы данных '%1' поÑле поÑледнего ÑохранениÑ? Choose a file to import Выберите файл Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° Text files(*.sql *.txt);;All files(*) ТекÑтовые файлы(*.sql *.txt);;Ð’Ñе файлы(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Создать новый файл базы данных, чтобы Ñохранить импортированные данные? ЕÑли ответить Ðет, будет выполнена попытка импортировать данные файла SQL в текущую базу данных. Ctrl+Tab Ctrl+Shift+Tab Clear List Window Layout Ctrl+Alt+0 Simplify Window Layout Alt+Shift+0 Dock Windows at Bottom Dock Windows at Left Side Dock Windows at Top Ctrl+Alt+W Choose a database file to save under Error while saving the database to the new file. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Do you want to save the changes made to the project file '%1'? Edit View %1 Edit Trigger %1 File %1 already exists. Please choose a different name. Файл %1 уже ÑущеÑтвует. Выберите другое имÑ. Error importing data: %1 Ошибка Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ…: %1 Import completed. Импорт завершён. Delete View Удалить предÑтавление Modify View Модифицировать предÑтавление Delete Trigger Удалить триггер Modify Trigger Модифицировать триггер Delete Index Удалить Ð¸Ð½Ð´ÐµÐºÑ Opened '%1' in read-only mode from recent file list Opened '%1' from recent file list &%1 %2%3 &%1 %2%3 (read only) Open Database or Project Attach Database... Import CSV file(s)... Do you want to save the changes made to SQL tabs in a new project file? Do you want to save the changes made to the SQL file %1? Could not find resource file: %1 Choose a project file to open Выберите файл проекта Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ DB file '%1' could not be opened Table '%1' not found; settings ignored Could not open project file for writing. Reason: %1 -- Reference to file "%1" (not supported by this version) -- Busy (%1) Error checking foreign keys after table modification. The changes will be reverted. Ошибка проверки внешних ключей поÑле Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹. Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ отменены. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Эта таблица не прошла проверку внешнего ключа. <br/> Ð’Ñ‹ должны запуÑтить "ИнÑтрументы | Проверка внешнего ключа"и иÑправить Ñообщенные проблемы. Execution finished with errors. Execution finished without errors. Delete Table Удалить таблицу Setting PRAGMA values will commit your current transaction. Are you sure? УÑтановка значений PRAGMA завершит текущую транзакцию. УÑтановить значениÑ? In-Memory database БД в памÑти Automatically load the last opened DB file at startup Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Ð’Ñ‹ дейÑтвительно хотите удалить таблицу '%1'? Ð’Ñе данные, ÑвÑзанные Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†ÐµÐ¹, будут потерÑны. Are you sure you want to delete the view '%1'? Ð’Ñ‹ дейÑтвительно хотите удалить предÑтавление '%1'? Are you sure you want to delete the trigger '%1'? Ð’Ñ‹ дейÑтвительно хотите удалить триггер '%1'? Are you sure you want to delete the index '%1'? Ð’Ñ‹ дейÑтвительно хотите удалить Ð¸Ð½Ð´ÐµÐºÑ '%1'? Error: could not delete the table. Ошибка: не удалоÑÑŒ удалить таблицу. Error: could not delete the view. Ошибка: не удалоÑÑŒ удалить предÑтавление. Error: could not delete the trigger. Ошибка: не удалоÑÑŒ удалить триггер. Error: could not delete the index. Ошибка: не удалоÑÑŒ удалить индекÑ. Message from database engine: %1 Сообщение от СУБД: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Ð”Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ необходимо Ñохранить вÑе ожидающие Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑейчаÑ. Ð’Ñ‹ дейÑтвительно хотите Ñохранить БД? You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. -- EXECUTING SELECTION IN '%1' -- -- ВЫПОЛÐЕÐИЕ ВЫБОРКИ Ð’ '%1' -- -- EXECUTING LINE IN '%1' -- -- ВЫПОЛÐЕÐИЕ СТРОКИ Ð’ '%1' -- -- EXECUTING ALL IN '%1' -- -- ВЫПОЛÐЕÐИЕ ВСЕ Ð’ '%1' -- At line %1: Result: %1 Result: %2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? УÑтановка значений PRAGMA или Ð²Ð°ÐºÑƒÑƒÐ¼Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð²ÐµÐ´ÐµÑ‚ к фикÑации текущей транзакции. Уверены ли вы? Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Yes. Don't ask again This action will open a new SQL tab with the following statements for you to edit and run: Rename Tab Duplicate Tab Close Tab Opening '%1'... There was an error opening '%1'... Value is not a valid URL or filename: %1 %1 rows returned in %2ms %1 Ñтрок возвращено за %2Ð¼Ñ Choose text files Выберите текÑтовые файлы Import completed. Some foreign key constraints are violated. Please fix them before saving. Импорт завершен. Ðарушены некоторые Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð²Ð½ÐµÑˆÐ½Ð¸Ñ… ключей. ПожалуйÑта, иÑправьте их перед Ñохранением. Modify Index Модифицировать Ð˜Ð½Ð´ÐµÐºÑ Modify Table Модифицировать Таблицу Do you want to save the changes made to SQL tabs in the project file '%1'? Select SQL file to open Выбрать файл SQL Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Select file name Выбрать Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Select extension file Выбрать раÑширение файла Extension successfully loaded. РаÑширение уÑпешно загружено. Error loading extension: %1 Ошибка загрузки раÑширениÑ: %1 Don't show again Ðе показывать Ñнова New version available. ДоÑтупна Ð½Ð¾Ð²Ð°Ñ Ð²ÐµÑ€ÑиÑ. Project saved to file '%1' Collation needed! Proceed? Ðужно выполнить ÑопоÑтавление! Продолжить? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Таблица в базе данных требует Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ñпециальной функции ÑопоÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ '%1'. ЕÑли вы продолжите, то возможна порча вашей базы данных. Создайте резервную копию! creating collation Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Задайте новое Ð¸Ð¼Ñ Ð´Ð»Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ¸ SQL. ИÑпользуйте Ñимвол '&&', чтобы разрешить иÑпользование Ñледующего Ñимвола в качеÑтве ÑÐ¾Ñ‡ÐµÑ‚Ð°Ð½Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ. Please specify the view name Укажите Ð¸Ð¼Ñ Ð¿Ñ€ÐµÐ´ÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ There is already an object with that name. Please choose a different name. Объект Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ именем уже ÑущеÑтвует. Выберите другое имÑ. View successfully created. ПредÑтавление уÑпешно Ñоздано. Error creating view: %1 Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ñ€ÐµÐ´ÑтавлениÑ: %1 This action will open a new SQL tab for running: Это дейÑтвие откроет новую вкладку SQL Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑка: Press Help for opening the corresponding SQLite reference page. Ðажмите "Справка" Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ ÑоответÑтвующей Ñправочной Ñтраницы SQLite. NullLineEdit Set to NULL УÑтановить в NULL Alt+Del PlotDock Plot График <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>Ðа Ñтой панели отображаетÑÑ ÑпиÑок Ñтолбцов текущей проÑматриваемой таблицы или только что выполненного запроÑа. Ð’Ñ‹ можете выбрать Ñтолбцы, которые вы хотите иÑпользовать в качеÑтве оÑи X или Y Ð´Ð»Ñ Ð³Ñ€Ð°Ñ„Ð¸ÐºÐ° ниже. Ð’ таблице показан тип обнаруженной оÑи, который повлиÑет на итоговый график. Ð”Ð»Ñ Ð¾Ñи Y вы можете выбирать только чиÑловые Ñтолбцы, но Ð´Ð»Ñ Ð¾Ñи X вы можете выбрать:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Дата/ВремÑ</span>: Ñтроки Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ð¼ &quot;гггг-ММ-дд чч:мм:ÑÑ&quot; или &quot;гггг-ММ-ддTчч:мм:ÑÑ&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Дата</span>: Ñтроки Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ð¼ &quot;гггг-ММ-дд&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ВремÑ</span>: Ñтроки Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ð¼ &quot;чч:мм:ÑÑ&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ТекÑÑ‚</span>: Ñтроки лубого формата. Выбор Ñтого Ñтолбца по оÑи X приведет к Ñозданию графика Баров, Ñо значениÑми Ñтолбцов в качеÑтве меток Ð´Ð»Ñ Ð±Ð°Ñ€Ð¾Ð²</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ЧиÑла</span>: целочиÑленные или вещеÑтвенные значениÑ</li></ul><p>Дважды щелкните по Ñчейкам Y, вы можете изменить иÑпользуемый цвет Ð´Ð»Ñ Ñтого графика.</p></body></html> Columns Столбцы X X Y1 Y2 Axis Type ОÑÑŒ Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Вот график, нариÑованный, когда вы выбираете Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ x и y выше. Ðажмите на пункты, чтобы выбрать их на графике и в таблице. Ctrl + Click Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° диапазона точек. ИÑпользуйте колеÑико мыши Ð´Ð»Ñ Ð¼Ð°ÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ перетаÑÐºÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¼Ñ‹ÑˆÑŒÑŽ Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° оÑей. Выберите метки оÑей или оÑей Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ‚Ð°ÑÐºÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¸ маÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ в Ñтой ориентации. Line type: ЛиниÑ: None Ðет Line ÐžÐ±Ñ‹Ñ‡Ð½Ð°Ñ StepLeft СтупенчатаÑ, Ñлева StepRight СтупенчатаÑ, Ñправа StepCenter СтупенчатаÑ, по центру Impulse Ð˜Ð¼Ð¿ÑƒÐ»ÑŒÑ Point shape: ОтриÑовка точек: Cross КреÑÑ‚ Plus ÐŸÐ»ÑŽÑ Circle Круг Disc ДиÑк Square Квадрат Diamond Ромб Star Звезда Triangle Треугольник TriangleInverted Треугольник перевернутый CrossSquare КреÑÑ‚ в квадрате PlusSquare ÐŸÐ»ÑŽÑ Ð² квадрате CrossCircle КреÑÑ‚ в круге PlusCircle ÐŸÐ»ÑŽÑ Ð² круге Peace Мир <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Сохранить текущий график...</p><p>Формат файла выбираетÑÑ Ñ€Ð°Ñширением (png, jpg, pdf, bmp)</p></body></html> Save current plot... Сохранить текущий график... Load all data and redraw plot Загрузить вÑе данные и перериÑовать Row # Строка # Copy Копировать Print... Печать... Show legend Легенда Stacked bars Fixed number format Date/Time Дата/Ð’Ñ€ÐµÐ¼Ñ Date Дата Time Ð’Ñ€ÐµÐ¼Ñ Numeric ЧиÑло Label ТекÑÑ‚ Invalid Ошибка Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Загружает вÑе данные и перериÑовывает график. Предупреждение: не вÑе данные были получены из таблицы из-за механизма чаÑтичной выборки. Choose an axis color Выберите цвет оÑи Choose a filename to save under Выбрать Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°, под которым Ñохранить данные PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Ð’Ñе файлы(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Ðа Ñтом графике еÑть кривые, и выбранный Ñтиль линии может применÑтьÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ к графикам, отÑортированным по X. Либо Ñортируйте таблицу или Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾ X, чтобы удалить кривые, либо выберите один из Ñтилей, поддерживаемых кривыми: None или Line. Loading all remaining data for this table took %1ms. PreferencesDialog Preferences ÐаÑтройки &Database &База данных Database &encoding &Кодировка базы данных Open databases with foreign keys enabled. Открывать базы данных Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ‹Ð¼Ð¸ внешними ключами. &Foreign keys &Внешние ключи enabled включены Default &location &РаÑположение по умолчанию ... ... &General &Общие Remember last location Запоминать поÑледнюю директорию Always use this location Ð’Ñегда открывать указанную Remember last location for session only Запоминать поÑледнюю директорию только Ð´Ð»Ñ ÑеÑÑий Lan&guage &Язык Automatic &updates &Следить за обновлениÑми SQ&L to execute after opening database Data &Browser Обозреватель &данных Remove line breaks in schema &view Удалить переводы Ñтроки в &Ñхеме данных Show remote options Опции "облака" Prefetch block si&ze Размер блока &упреждающей выборки Default field type Тип данных по умолчанию Font Шрифт &Font &Шрифт Content Содержимое Symbol limit in cell КоличеÑтво Ñимволов в Ñчейке NULL Regular Обычные Binary Двоичные данные Background Фон Filters Фильтры Threshold for completion and calculation on selection Show images in cell Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Escape character Символ ÑÐºÑ€Ð°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Delay time (&ms) Ð’Ñ€ÐµÐ¼Ñ Ð·Ð°Ð´ÐµÑ€Ð¶ÐºÐ¸ (&мÑ) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Ð’Ñ€ÐµÐ¼Ñ Ð·Ð°Ð´ÐµÑ€Ð¶ÐºÐ¸ перед применением нового фильтра. Ðулевое значение отключает ожидание. &SQL Р&едактор SQL Context КонтекÑÑ‚ Colour Цвет Bold Жирный Italic КурÑив Underline Подчёркивание Keyword Ключевое Ñлово Function Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Table Таблица Comment Комментарий Identifier Идентификатор String Строка Current line Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ñтрока SQL &editor font size Размер шрифта в &редакторе SQL Tab size Размер табулÑции SQL editor &font &Шрифт в редакторе SQL Error indicators Индикаторы ошибок Hori&zontal tiling Гори&зонтальное раÑпределение If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. ЕÑли Ð´Ð°Ð½Ð½Ð°Ñ Ð¾Ð¿Ñ†Ð¸Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°, то SQL редактор и результат запроÑа будут раÑположены Ñ€Ñдом по горизонтали. Code co&mpletion Ðвто&дополнение кода Toolbar style Стиль тулбара Only display the icon Только иконки Only display the text Только текÑÑ‚ The text appears beside the icon ТекÑÑ‚ над иконкой The text appears under the icon ТекÑÑ‚ под иконкой Follow the style Указано в Ñтиле DB file extensions РаÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² БД Manage ÐаÑтроить Main Window Database Structure Структура БД Browse Data Данные Execute SQL SQL Edit Database Cell Редактирование Ñчейки БД When this value is changed, all the other color preferences are also set to matching colors. Follow the desktop style Dark style Application style This sets the font size for all UI elements which do not have their own font size option. Font size Max Recent Files Prompt to save SQL tabs in new project file If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Когда отмечено, переноÑÑ‹ Ñтрок в Ñтолбце 'Схема' во вкладке 'Структура базы данных', 'док' и 'печатный результат' удалÑÑŽÑ‚ÑÑ. Database structure font size Font si&ze Ра&змер шрифта This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. МакÑимальное количеÑтво Ñтрок в таблице Ð´Ð»Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð½Ð° оÑнове текущих значений в Ñтолбце. Может быть уÑтановлено в 0 Ð´Ð»Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ. Field display Отображение Ð¿Ð¾Ð»Ñ Light style Displayed &text Отображаемый &текÑÑ‚ Formatted Click to set this color Text color Цвет текÑта Background color Цвет фона Preview only (N/A) Предв. проÑмотр Foreground Передний план Selection background Selection foreground Highlight SQL &results font size &Размер шрифта Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. &Wrap lines &ÐŸÐµÑ€ÐµÐ½Ð¾Ñ Ñтрок Never Ðикогда At word boundaries Ðа границах Ñлов At character boundaries Ðа границах Ñимволов At whitespace boundaries Ðа границах пробелов &Quotes for identifiers Обрамление &идентификаторов Choose the quoting mechanism used by the application for identifiers in SQL code. Выберите механизм обрамлениÑ, иÑпользуемый приложением Ð´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ‚Ð¾Ñ€Ð¾Ð² в коде SQL. "Double quotes" - Standard SQL (recommended) "Двойные кавычки" - Cтандартный SQL (рекомендуетÑÑ) `Grave accents` - Traditional MySQL quotes `ГравиÑ` - Традиционные кавычки MySQL [Square brackets] - Traditional MS SQL Server quotes [Квадратные Ñкобки] - традиционные кавычки Ð´Ð»Ñ MS SQL Server Keywords in &UPPER CASE Ключевые Ñлова в &ВЕРХÐЕМ РЕГИСТРЕ When set, the SQL keywords are completed in UPPER CASE letters. Когда отмечено, ключевые Ñлова SQL будут в ВЕРХÐЕМ РЕГИСТРЕ. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Когда уÑтановлено, Ñтроки кода SQL, вызвавшие ошибки во Ð²Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ñледнего выполнениÑ, подÑвечиваютÑÑ, а виджет результатов указывает на ошибку в фоновом режиме Close button on tabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. &Extensions Р&аÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Select extensions to load for every database: Выберите раÑширениÑ, чтобы загружать их Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ базы данных: Add extension Добавить раÑширение Remove extension Удалить раÑширение Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>Обозреватель Ð´Ð»Ñ SQLite позволÑет иÑпользовать оператор REGEXP 'из коробки'. Ðо тем <br/>не менее, возможны неÑколько различных вариантов реализаций данного оператора и вы Ñвободны <br/>в выборе какую именно иÑпользовать. Можно отключить нашу реализацию и иÑпользовать другую - <br/>путем загрузки ÑоответÑтвующего раÑширениÑ. Ð’ Ñтом Ñлучае требуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ° приложениÑ.</p></body></html> Disable Regular Expression extension Отключить раÑширение РегулÑрных Выражений <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> Allow loading extensions from SQL code Remote Удаленный Ñервер CA certificates СРÑертификаты Proxy Configure Export Settings Import Settings Subject CN Common Name Subject O Organization Valid from Valid to Serial number Your certificates Ваши Ñертификаты File Файл Subject Common Name Issuer CN Issuer Common Name Clone databases into Путь Ð´Ð»Ñ ÐºÐ»Ð¾Ð½Ð¸Ñ€ÑƒÐµÐ¼Ñ‹Ñ… БД Choose a directory Выберите каталог The language will change after you restart the application. Язык будет применен поÑле перезапуÑка приложениÑ. Select extension file Выберите файл раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Extensions(*.so *.dylib *.dll);;All files(*) Import certificate file Импорт файла Ñертификата No certificates found in this file. Ð’ данном файле не найден Ñертификат. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Ð’Ñ‹ дейÑтвительно хотите удалить Ñтот Ñертификат? Ð’Ñе данные Ñертификата будут удалены из наÑтроек приложениÑ! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Ð’Ñ‹ дейÑтвительно хотите удалить вÑе Ñохраненные наÑтройки? Ð’Ñе ваши Ð¿Ñ€ÐµÐ´Ð¿Ð¾Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ потерÑны, и будут иÑпользоватьÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию. Save Settings File Initialization File (*.ini) The settings file has been saved in location : Open Settings File The settings file was loaded properly. The selected settings file is not a normal settings file. Please check again. ProxyDialog Proxy Configuration Pro&xy Type Host Na&me Port Authentication Re&quired &User Name Password None Ðет System settings HTTP SOCKS5 QObject Error importing data Ошибка Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… from record number %1 Ñ Ð·Ð°Ð¿Ð¸Ñи номер %1 . %1 Importing CSV file... Импортирование CSV файла... Cancel Отменить All files (*) Ð’Ñе файлы (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Файлы SQLite баз данных (*.db *.sqlite *.sqlite3 *.db3) Left Right Center Justify SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) SQL Files (*.sql) All Files (*) Text Files (*.txt) Comma-Separated Values Files (*.csv) Tab-Separated Values Files (*.tsv) Delimiter-Separated Values Files (*.dsv) Concordance DAT files (*.dat) JSON Files (*.json *.js) XML Files (*.xml) Binary Files (*.bin *.dat) SVG Files (*.svg) Hex Dump Files (*.dat *.bin) Extensions (*.so *.dylib *.dll) Initialization File (*.ini) QsciCommand Paste Ð’Ñтавить Cancel Отменить QsciLexerCPP Default По умолчанию Keyword Ключевое Ñлово Identifier Идентификатор QsciLexerJSON Default По умолчанию String Строка QsciLexerPython Default По умолчанию Comment Комментарий Keyword Ключевое Ñлово Identifier Идентификатор QsciLexerSQL Default По умолчанию Comment Комментарий Keyword Ключевое Ñлово Identifier Идентификатор RemoteCommitsModel Commit ID Message Date Дата Author Size Размер Authored and committed by %1 Authored by %1, committed by %2 RemoteDatabase Error opening local databases list. %1 Ошибка при открытии ÑпиÑка локальных БД. %1 Error creating local databases list. %1 Ошибка при Ñоздании ÑпиÑка локальных БД. %1 RemoteDock Remote Удаленный Ñервер Identity ID Push currently opened database to server Отправить текущую БД на Ñервер Upload DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> Local Current Database Clone Branch Ветка Commits Commits for Delete Database Delete the local clone of this database Open in Web Browser Open the web page for the current database in your browser Clone from Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. Refresh Обновить Reload all data and update the views Clone Database Open Database Open the local copy of this database Check out Commit Download and open this specific commit Check out Latest Commit Check out the latest commit of the current branch Save Revision to File Saves the selected revision of the database to another file Upload Database Upload this database as a new commit <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> &User &Database &База данных Back Select an identity to connect Public Публичный This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Invalid URL: The host name does not match the host name of the current identity. Invalid URL: No branch name specified. Invalid URL: No commit ID specified. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? The database has unsaved changes. Are you sure you want to push it before saving? The database you are trying to delete is currently opened. Please close it before deleting. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? RemoteLocalFilesModel Name Ð˜Ð¼Ñ Branch Ветка Last modified Изменен Size Размер Commit Коммит File Файл RemoteModel Name Ð˜Ð¼Ñ Last modified Изменен Size Размер Commit Коммит Size: Last Modified: Licence: Default Branch: RemoteNetwork Choose a location to save the file Error opening remote file at %1. %2 Ошибка Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° %1. %2 Error: Invalid client certificate specified. Ошибка: Указан неверный Ñертификат клиента. Please enter the passphrase for this client certificate in order to authenticate. ПожалуйÑта введите ключевую фразу Ð´Ð»Ñ Ñтого Ñертификата клиента. Cancel Отменить Uploading remote database to %1 ЗагружаетÑÑ ÑƒÐ´Ð°Ð»ÐµÐ½Ð½Ð°Ñ Ð‘Ð” в %1 Downloading remote database from %1 СкачиваетÑÑ ÑƒÐ´Ð°Ð»ÐµÐ½Ð½Ð°Ñ Ð‘Ð” из %1 Error: Cannot open the file for sending. Ошибка: не удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸. RemotePushDialog Push database Отправить БД Database na&me to push to &Ð˜Ð¼Ñ Ð‘Ð” Commit message Сообщение Database licence Ð›Ð¸Ñ†ÐµÐ½Ð·Ð¸Ñ Public Публичный Branch Ветка Force push Принудительно Username Database will be public. Everyone has read access to it. БД будет публичной. У каждого будет доÑтуп на чтение к ней. Database will be private. Only you have access to it. БД будет конфиденциальной. Только у Ð²Ð°Ñ Ð±ÑƒÐ´ÐµÑ‚ доÑтуп к ней. Use with care. This can cause remote commits to be deleted. ИÑпользуйте Ñ Ð¾ÑторожноÑтью. Это может привеÑти к удалению ÑущеÑтвующих коммитов. RunSql Execution aborted by user Выполнение прервано пользователем , %1 rows affected , %1 Ñтрок изменено query executed successfully. Took %1ms%2 Ð·Ð°Ð¿Ñ€Ð¾Ñ ÑƒÑпешно выполнен. ЗанÑло %1мÑ%2 executing query SelectItemsPopup A&vailable Sele&cted SqlExecutionArea Form Форма Find previous match [Shift+F3] Ðайти предыдущее Ñовпадение [Shift+F3] Find previous match with wrapping Ðайти предыдущее Ñовпадение, закольцевав поиÑк Shift+F3 The found pattern must be a whole word Ðайденный шаблон должен быть целым Ñловом Whole Words Слова ПолноÑтью Text pattern to find considering the checks in this frame Шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка, ÑƒÑ‡Ð¸Ñ‚Ñ‹Ð²Ð°Ñ Ð²Ñе проверки Find in editor Ðайти в редакторе The found pattern must match in letter case У найденного шаблона должен Ñовпадать региÑтр Case Sensitive Учитывать РегиÑтр Find next match [Enter, F3] Ðайти Ñледующее Ñовпадение [Enter, F3] Find next match with wrapping Ðайти Ñледующее Ñовпадение, закольцевав поиÑк F3 Interpret search pattern as a regular expression Интерпретировать шаблон поиÑка как регулÑрное выражение <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>При проверке шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка интерпретируетÑÑ ÐºÐ°Ðº регулÑрное выражение UNIX. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Узнать больше о РегулÑрных выражениÑÑ… на Wikibooks.org</a>.</p></body></html> Regular Expression РегулÑрное выражение Close Find Bar Закрыть ПоиÑковую Панель <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> Results of the last executed statements Результаты поÑледних выполненных операторов This field shows the results and status codes of the last executed statements. Это поле показывает результаты и коды ÑтатуÑов поÑледних выполненных операторов. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Couldn't save file: %1. Ðе удалоÑÑŒ Ñохранить файл:%1. Your changes will be lost when reloading it! The file "%1" was modified by another program. Do you want to reload it?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ abs(X) возвращает модуль чиÑла аргумента X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ changes() возвращает количеÑтво Ñтрок в базе данных, которые были изменены, вÑтавлены или удалены поÑле удачного Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ INSERT, DELETE или UPDATE. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ char(X1,X2,...,XN) возвращает Ñтроку ÑоÑтавленную из Ñимволов, переданных в качеÑтве аргументов. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ coalesce() возвращает копию первого аргумента не равного NULL иначе еÑли такого нет то возвращаетÑÑ NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ glob(X,Y) Ñквивалент выражению "Y GLOB X". (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ ifnull() возвращает копию первого аргумента не равного NULL иначе еÑли оба аргумента равны NULL то возвращает NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ instr(X,Y) возвращает количеÑтво Ñимволов, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð³Ð¾ в Ñтроке X найдена подÑтрока Y или 0 еÑли Ñ‚Ð°ÐºÐ¾Ð²Ð°Ñ Ð½Ðµ обнаружена. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ hex() интерпретирует аргумент как BLOB и возвращает Ñтроку в 16-ричной ÑиÑтеме ÑчиÑÐ»ÐµÐ½Ð¸Ñ Ñ Ñодержимым аргумента. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ last_insert_rowid() возвращает ROWID поÑледней вÑтавленной Ñтроки. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) Ð”Ð»Ñ Ñтрокового Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ X, Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ length(X) возвращает количеÑтво Ñимволов (не байт) от начала Ñтроки до первого Ñимвола '\0'. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ like() Ñквивалент выражению "Y LIKE X". (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ like() Ñквивалент Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ "Y LIKE X ESCAPE Z". (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ lower(X) возвращает копию Ñтроки X, в которой вÑе ACSII Ñимволы переведены в нижний региÑтр. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) удалÑет Ñимволы пробелов Ñлева Ð´Ð»Ñ Ñтроки X. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ ltrim(X,Y) возвращает новую Ñтроку путем ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð· Ñтроки X Ñлева любого Ñимвола из Y. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ max() возвращает аргумент Ñ Ð¼Ð°ÐºÑимальным значением, либо NULL еÑли Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ один аргумент равен NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ min() возвращает аргумент Ñ Ð¼Ð¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ñ‹Ð¼ значением. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ nullif(X,Y) возвращает первый аргумент еÑли аргументы различны либо NULL еÑли они одинаковы. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ printf(FORMAT,...) работает так же как printf() из Ñтандартной библиотеки Ñзыка Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¡Ð¸. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ quote(X) возвращает измененную Ñтроку X, которую можно иÑпользовать в SQL выражениÑÑ…. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ random() возвращает пÑевдо Ñлучайное целочиÑленное значение из диапазона от-9223372036854775808 до +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ randomblob(N) возвращает N-байтный BLOB, Ñодержащий пÑевдо Ñлучайные байты. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ replace(X,Y,Z) возвращает новую Ñтроку на оÑнове Ñтроки X, заменой вÑех подÑтрок Y на Z. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ round(X) округлÑет X до целого значениÑ. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ round(X,Y) округлÑет X до Y чиÑел поÑле запÑтой Ñправа. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) удалÑет Ñимволы пробела Ñправа Ñтроки X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ rtrim(X,Y) возвращает новую Ñтроку путем ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð· Ñтроки X Ñправа любого Ñимвола из Ñтроки Y. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ soundex(X) возвращает копию Ñтроки X, кодированную в формате soundex. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) возвращает подÑтроку из Ñтроки X, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Y-го Ñимвола. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ substr(X,Y,Z) возвращает подÑтроку из Ñтроки X, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Y-го Ñимвола, длинной Z-Ñимволов. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ total_changes() возвращает количеÑтво Ñтрок измененных Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ INSERT, UPDATE или DELETE, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Ñ‚Ð¾Ð³Ð¾ момента как текущее подключение к базе данных было открыто. (X) trim(X) removes spaces from both ends of X. (X) trim(X) удалÑет пробелы Ñ Ð¾Ð±Ð¾Ð¸Ñ… Ñторон Ñтроки X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ trim(X,Y) Ñоздает новую Ñтроку из X, путем ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ Ð¾Ð±Ð¾Ð¸Ñ… концов Ñимволов, которые приÑутÑтвуют в Ñтроке Y. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ typeof(X) возвращает Ñтроку Ñ Ñ‚Ð¸Ð¿Ð¾Ð¼ данных Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ unicode(X) возвращает чиÑловое значение UNICODE кода Ñимвола. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ upper(X) возвращает копию Ñтроки X, в которой Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ASCII Ñимвола региÑтр будет преобразован из нижнего в верхний. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ zeroblob(N) возвращает BLOB размером N байт Ñо значениÑми 0x00. (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ avg() возвращает Ñреднее значение Ð´Ð»Ñ Ð²Ñех не равных NULL значений группы. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ count(X) возвращает количеÑтво Ñтрок, в которых X не равно NULL в группе. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ group_concat() возвращает Ñтроку из вÑех значений X не равных NULL. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ group_concat() возвращает Ñтроку из вÑех значений X не равных NULL. Y - разделитель между значениÑми X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) ÐÐ³Ñ€ÐµÐ³Ð°Ñ‚Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ max() возвращает макÑимальное значение Ð´Ð»Ñ X. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) ÐÐ³Ñ€ÐµÐ³Ð°Ñ‚Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ min() возвращает минимальное значение Ð´Ð»Ñ X. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) Ðгрегатные функции sum() и total() возвращают Ñумму вÑех не NULL значений Ð´Ð»Ñ X. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () ЧиÑло Ñтрок в текущем разделе. Строки нумеруютÑÑ Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ 1 в порÑдке, определенном выражением ORDER BY, или иначе в произвольном порÑдке. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ row_number() возвращает номер первой Ñтроки в каждой группе - ранг текущей Ñтроки Ñ Ñ€Ð°Ð·Ñ€Ñ‹Ð²Ð°Ð¼Ð¸. ЕÑли не ÑущеÑтвует Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ORDER BY, вÑе Ñтроки ÑчитаютÑÑ Ð¾Ð´Ð½Ð¾Ñ€Ð°Ð½Ð³Ð¾Ð²Ñ‹Ð¼Ð¸, и Ñта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñегда возвращает 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () ЧиÑло одноранговой группы текущей Ñтроки в Ñвоем разделе - ранг текущей Ñтроки без пробелов. Разделы нумеруютÑÑ, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ 1 в порÑдке, определенном выражением ORDER BY в определении окна. ЕÑли не ÑущеÑтвует Ð¿Ñ€ÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ORDER BY, вÑе Ñтроки ÑчитаютÑÑ Ð¾Ð´Ð½Ð¾Ñ€Ð°Ð½Ð³Ð¾Ð²Ñ‹Ð¼Ð¸, и Ñта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñегда возвращает 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () ÐеÑÐ¼Ð¾Ñ‚Ñ€Ñ Ð½Ð° имÑ, Ñта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñегда возвращает значение между 0.0 и 1.0, равное (rank-1) / (partition-rows-1), где rank - Ñто значение, возвращаемое вÑтроенной функцией window rank () rows - Ñто общее количеÑтво Ñтрок в разделе. ЕÑли раздел Ñодержит только одну Ñтроку, Ñта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°ÐµÑ‚ 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () КумулÑтивное раÑпределение. РаÑÑчитываетÑÑ ÐºÐ°Ðº номер-Ñтроки / Ñтроки-раздела, где номер-Ñтроки - Ñто значение, возвращаемое row_number() Ð´Ð»Ñ Ð¿Ð¾Ñледнего однорангового узла в группе, а Ñтроки-раздела- количеÑтво Ñтрок в разделе. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) Ðргумент N обрабатываетÑÑ ÐºÐ°Ðº целое чиÑло. Эта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð´ÐµÐ»Ð¸Ñ‚ раздел на N групп как можно более равномерно и назначает целое чиÑло от 1 до N каждой группе в порÑдке, определенном выражением ORDER BY, или в произвольном порÑдке, при его отÑутÑтвии. При необходимоÑти Ñначала поÑвлÑÑŽÑ‚ÑÑ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ðµ группы. Эта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°ÐµÑ‚ целочиÑленное значение, приÑвоенное группе, в которой находитÑÑ Ñ‚ÐµÐºÑƒÑ‰Ð°Ñ Ñтрока. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Возвращает результат вычиÑÐ»ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr в предыдущей Ñтроке раздела. Или, еÑли нет предыдущей Ñтроки (поÑкольку Ñ‚ÐµÐºÑƒÑ‰Ð°Ñ Ñтрока ÑвлÑетÑÑ Ð¿ÐµÑ€Ð²Ð¾Ð¹), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr, offset) ЕÑли аргумент offset указан, то он должен быть неотрицательным целым чиÑлом. Ð’ Ñтом Ñлучае возвращаемое значение ÑвлÑетÑÑ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð¾Ð¼ вычиÑÐ»ÐµÐ½Ð¸Ñ expr в Ñтроках ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñтрок до текущей Ñтроки в разделе. ЕÑли Ñмещение равно 0, то expr вычиÑлÑетÑÑ Ð¾Ñ‚Ð½Ð¾Ñительно текущей Ñтроки. ЕÑли перед текущей Ñтрокой нет Ñтрок ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñтрок, возвращаетÑÑ NULL. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr, offset, default) ЕÑли задано значение по умолчанию, оно возвращаетÑÑ Ð²Ð¼ÐµÑто NULL, еÑли Ñтрока, Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸Ñ†Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ ÑмещениÑ, не ÑущеÑтвует. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Возвращает результат вычиÑÐ»ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr в Ñледующей Ñтроке раздела. Или, еÑли нет Ñледующей Ñтроки (поÑкольку поÑледнÑÑ Ñтрока ÑвлÑетÑÑ Ð¿Ð¾Ñледней), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr, offset) ЕÑли аргумент offset указан, то он должен быть неотрицательным целым чиÑлом. Ð’ Ñтом Ñлучае возвращаемое значение ÑвлÑетÑÑ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð¾Ð¼ вычиÑÐ»ÐµÐ½Ð¸Ñ expr в Ñтроках ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñтрок поÑле текущей Ñтроки в разделе. ЕÑли Ñмещение равно 0, то expr вычиÑлÑетÑÑ Ð¾Ñ‚Ð½Ð¾Ñительно текущей Ñтроки. ЕÑли поÑле текущей Ñтроки нет Ñтрок ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñтроки, возвращаетÑÑ NULL. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Эта вÑÑ‚Ñ€Ð¾ÐµÐ½Ð½Ð°Ñ ÐžÐºÐ¾Ð½Ð½Ð°Ñ Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñ‹Ñ‡Ð¸ÑлÑет Оконный Кадр Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки так же, как Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ ÐžÐºÐ½Ð° агрегата. Она возвращает значение Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr, оцениваемое по отношению к первой Ñтроке в оконном фрейме Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Эта вÑÑ‚Ñ€Ð¾ÐµÐ½Ð½Ð°Ñ ÐžÐºÐ¾Ð½Ð½Ð°Ñ Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñ‹Ñ‡Ð¸ÑлÑет Оконный Кадр Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки так же, как Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ ÐžÐºÐ½Ð° агрегата. Она возвращает значение Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr, оцениваемое по отношению к поÑледней Ñтроке в оконном фрейме Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки. (expr) Эта вÑÑ‚Ñ€Ð¾ÐµÐ½Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾ÐºÐ½Ð° вычиÑлÑет оконный кадр Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки так же, как Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾ÐºÐ½Ð° агрегата. Он возвращает значение expr, оцениваемое по поÑледней Ñтроке в оконном фрейме Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr, N) Эта вÑÑ‚Ñ€Ð¾ÐµÐ½Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾ÐºÐ½Ð° вычиÑлÑет оконный фрейм Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки так же, как Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾ÐºÐ½Ð° агрегата. Она возвращает значение Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr, оцениваемое по Ñтроке N оконного фрейма. Строки нумеруютÑÑ Ð² рамке окна, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ 1 в порÑдке, определенном выражением ORDER BY, еÑли оно приÑутÑтвует, или в произвольном порÑдке в противном Ñлучае. ЕÑли в разделе нет N-й Ñтроки, возвращаетÑÑ NULL. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. SqliteTableModel reading rows читаем Ñтроки loading... загрузка... References %1(%2) Hold %3Shift and click to jump there СÑылаетÑÑ Ð½Ð° %1(%2) Ðажмите %3Shift и клик чтобы перемеÑтитьÑÑ Ñ‚ÑƒÐ´Ð° Error changing data: %1 Ошибка Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ…: %1 retrieving list of columns получаем ÑпиÑок колонок Fetching data... Подгружаем данные... Cancel Отменить TableBrowser Browse Data Данные &Table: &Таблица: Select a table to browse data Выберите таблицу Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра данных Use this list to select a table to be displayed in the database view ИÑпользуйте Ñтот ÑпиÑок, чтобы выбрать таблицу, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° быть отображена в предÑтавлении базы данных This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Это предÑтавление таблицы БД. Ð’Ñ‹ можете выполнить Ñледующие дейÑтвиÑ: - Ðачните пиÑать Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ, Ð²Ð²ÐµÐ´Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ. - Дважды щелкните любую запиÑÑŒ, чтобы отредактировать ее Ñодержимое в окне редактора Ñчеек. - Alt + Del Ð´Ð»Ñ Ð¾Ð±Ð½ÑƒÐ»ÐµÐ½Ð¸Ñ Ñодержимого Ñчейки в NULL. - Ctrl + " Ð´Ð»Ñ Ð´ÑƒÐ±Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ запиÑи. - Ctrl + ' Ð´Ð»Ñ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¸Ð· Ñчейки выше. - Стандартные операции выбора и копированиÑ/вÑтавки. Text pattern to find considering the checks in this frame Шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка, ÑƒÑ‡Ð¸Ñ‚Ñ‹Ð²Ð°Ñ Ð²Ñе проверки Find in table Find previous match [Shift+F3] Ðайти предыдущее Ñовпадение [Shift+F3] Find previous match with wrapping Ðайти предыдущее Ñовпадение, закольцевав поиÑк Shift+F3 Find next match [Enter, F3] Ðайти Ñледующее Ñовпадение [Enter, F3] Find next match with wrapping Ðайти Ñледующее Ñовпадение, закольцевав поиÑк F3 The found pattern must match in letter case У найденного шаблона должен Ñовпадать региÑтр Case Sensitive Учитывать РегиÑтр The found pattern must be a whole word Ðайденный шаблон должен быть целым Ñловом Whole Cell Interpret search pattern as a regular expression Интерпретировать шаблон поиÑка как регулÑрное выражение <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>При проверке шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка интерпретируетÑÑ ÐºÐ°Ðº регулÑрное выражение UNIX. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Узнать больше о РегулÑрных выражениÑÑ… на Wikibooks.org</a>.</p></body></html> Regular Expression РегулÑрное выражение Close Find Bar Закрыть ПоиÑковую Панель Text to replace with Replace with Replace next match Replace Replace all matches Replace all Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Copy column name Copy the database table column name to your clipboard New Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Прокрутить к началу</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Ðажатие Ñтой кнопки переводит к началу в таблице выше.</p></body></html> |< Scroll one page upwards Страница вверх <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Ðажатие Ñтой кнопки перемещает одну Ñтраницу запиÑей вверх в виде таблицы выше.</p></body></html> < < 0 - 0 of 0 0 - 0 из 0 Scroll one page downwards Страница вниз <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Ðажатие Ñтой кнопки перемещает одну Ñтраницу запиÑей вниз в виде таблицы выше.</p></body></html> > > Scroll to the end Прокрутить к концу <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>Ðажмите здеÑÑŒ, чтобы перейти к указанной запиÑи</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Эта кнопка иÑпользуетÑÑ, чтобы перемеÑтитьÑÑ Ðº запиÑи, номер которой указан в облаÑти Перейти к</p></body></html> Go to: Перейти к: Enter record number to browse Введите номер запиÑи Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра Type a record number in this area and click the Go to: button to display the record in the database view Ðапечатайте номер запиÑи в Ñтой облаÑти и нажмите кнопку Перейти к:, чтобы отобразить запиÑÑŒ в предÑтавлении базы данных 1 1 Show rowid column Отображать колонку rowid Toggle the visibility of the rowid column Unlock view editing Разблокировать возможноÑть Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ This unlocks the current view for editing. However, you will need appropriate triggers for editing. Разблокировать текущий вид Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ. Однако Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð°Ð¼ понадобÑÑ‚ÑÑ ÑоответÑтвующие триггеры. Edit display format Формат Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Edit the display format of the data in this column Редактирование формата Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… из Ñтой колонки New Record Добавить запиÑÑŒ Insert a new record in the current table Добавить новую запиÑÑŒ в текущую таблицу <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>Эта кнопка Ñоздает новую запиÑÑŒ в базе данных. Удерживайте кнопку мыши, чтобы открыть вÑплывающее меню различных параметров:</p><ul><li><span style=" font-weight:600;">ÐÐ¾Ð²Ð°Ñ Ð—Ð°Ð¿Ð¸ÑÑŒ</span>: вÑтавлÑет новую запиÑÑŒ Ñо значениÑми по умолчанию.</li><li><span style=" font-weight:600;">Ð’Ñтавить ЗначениÑ...</span>: открывает диалог Ð´Ð»Ñ Ð²Ð²Ð¾Ð´Ð° значений перед тем, как они будут вÑтавлены в БД. Это позволÑет вводить значениÑ, Ð½Ð°Ð·Ð½Ð°Ñ‡Ð°Ñ Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð½Ñ‹Ðµ ограничениÑ. Этот диалог также открываетÑÑ, еÑли <span style=" font-weight:600;">ÐÐ¾Ð²Ð°Ñ Ð—Ð°Ð¿Ð¸ÑÑŒ</span> Ð¾Ð¿Ñ†Ð¸Ñ Ð½Ðµ Ñрабатывает из-за Ñтих ограничений.</li></ul></body></html> Delete Record Удалить запиÑÑŒ Delete the current record Удалить текущую запиÑÑŒ This button deletes the record or records currently selected in the table Эта кнопка удалÑет запиÑÑŒ или запиÑи, выбранные в наÑтоÑщее Ð²Ñ€ÐµÐ¼Ñ Ð² таблице Insert new record using default values in browsed table Ð’ÑтавлÑет новую запиÑÑŒ, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию в проÑматриваемой таблице Insert Values... Ð’Ñтавить ЗначениÑ... Open a dialog for inserting values in a new record Открывает диалоговое окно Ð´Ð»Ñ Ð²Ñтавки значений в новую запиÑÑŒ Export to &CSV ЭкÑпортировать в &CSV Export the filtered data to CSV ЭкÑпортировать отфильтрованные данные в CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Эта кнопка ÑкÑпортирует данные проÑматриваемой таблицы так как отображаетÑÑ (поÑле обработки фильтрами, форматами Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸ Ñ‚.д.) в виде файла CSV. Save as &view Сохранить как &предÑтавление Save the current filter, sort column and display formats as a view Сохранить текущие фильтры, Ñтолбцы Ñортировки и форматы Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² виде предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Эта кнопка ÑохранÑет текущие наÑтройки проÑматриваемой таблицы (фильтры, форматы Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸ Ñтолбец Ñортировки) в виде предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ SQL, которое вы можете впоÑледÑтвии проÑмотреть или иÑпользовать в операторах SQL. Save Table As... Save the table as currently displayed Сохранить таблицу так как ÑÐµÐ¹Ñ‡Ð°Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶Ð°ÐµÑ‚ÑÑ <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>Это вÑплывающее меню предоÑтавлÑет Ñледующие параметры, применÑемые к текущей проÑматриваемой и отфильтрованной таблице:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ЭкÑпортировать в виде CSV: данные проÑматриваемой таблицы ÑохранÑетÑÑ Ñ‚Ð°Ðº как отображаетÑÑ (поÑле Ð¿Ñ€Ð¸Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ„Ð¸Ð»ÑŒÑ‚Ñ€Ð¾Ð², форматов Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸ порÑдка колонок) в CSV файл.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Сохранить как вид: Ñта Ð¾Ð¿Ñ†Ð¸Ñ ÑохранÑет наÑтройки текущей отображаемой таблицы (фильтры, форматы Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸ порÑдок колонок) как SQL вид, который вы позже можете проÑматривать или иÑпользовать в SQL выражениÑÑ….</li></ul></body></html> Hide column(s) Скрыть колонки Hide selected column(s) Скрыть выбранные колонки Show all columns Показать вÑе колонки Show all columns that were hidden Показать вÑе колонки, которые были Ñкрыты Set encoding Кодировка Change the encoding of the text in the table cells Изменение кодировки текÑта в данной таблице Set encoding for all tables УÑтановить кодировку Ð´Ð»Ñ Ð²Ñех таблиц Change the default encoding assumed for all tables in the database Изменить кодировку по умолчанию Ð´Ð»Ñ Ð²Ñех таблиц в базе данных Clear Filters Clear all filters ОчиÑтить вÑе фильтры This button clears all the filters set in the header input fields for the currently browsed table. Эта кнопка очищает вÑе фильтры, уÑтановленные в полÑÑ… ввода заголовка Ð´Ð»Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ проÑматриваемой таблицы. Clear Sorting Reset the order of rows to the default This button clears the sorting columns specified for the currently browsed table and returns to the default order. Print Печать Print currently browsed table data Печатать отображаемую таблицу Print currently browsed table data. Print selection if more than one cell is selected. РаÑпечатывайте текущие данные таблицы. Выбор печати, еÑли выбрано неÑколько Ñчеек. Ctrl+P Refresh Обновить Refresh the data in the selected table Обновить данные в выбранной таблице This button refreshes the data in the currently selected table. Эта кнопка обновлÑет данные выбранной в данный момент таблицы. F5 Find in cells Open the find tool bar which allows you to search for values in the table view below. Bold Жирный Ctrl+B Italic КурÑив Underline Подчёркивание Ctrl+U Align Right Align Left Center Horizontally Justify Edit Conditional Formats... Edit conditional formats for the current column Clear Format Clear All Formats Clear all cell formatting from selected cells and all conditional formats from selected columns Font Color Background Color Toggle Format Toolbar Show/hide format toolbar This button shows or hides the formatting toolbar of the Data Browser Select column Ctrl+Space Replace text in cells Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally Filter in any column Ctrl+R %n row(s) , %n column(s) . Sum: %1; Average: %2; Min: %3; Max: %4 Conditional formats for "%1" determining row count... определÑем количеÑтво Ñтрок... %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. ПожалуйÑта, введите пÑевдо-первичный ключ, чтобы разрешить редактирование в Ñтом предÑтавлении. Это должно быть Ð¸Ð¼Ñ ÑƒÐ½Ð¸ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ Ñтолбца в предÑтавлении. Delete Records Удалить ЗапиÑи Duplicate records Дублированные запиÑи Duplicate record Дубликат запиÑи Ctrl+" Adjust rows to contents Error deleting record: %1 Ошибка ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ð¸Ñи: %1 Please select a record first Сначала выберите запиÑÑŒ Please choose a new encoding for all tables. ПожалуйÑта выберите новую кодировку Ð´Ð»Ñ Ð²Ñех таблиц. Please choose a new encoding for this table. ПожалуйÑта выберите новую кодировку Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð¹ таблицы. %1 Leave the field empty for using the database encoding. %1 ОÑтавьте Ñто поле пуÑтым еÑли хотите чтобы иÑпользовалаÑÑŒ кодировка по умолчанию. This encoding is either not valid or not supported. ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ° либо она не поддерживаетÑÑ. %1 replacement(s) made. TableBrowserDock New Data Browser Rename Data Browser Close Data Browser Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. VacuumDialog Compact Database Ðе понÑтно, что лучше "уплотнение" или "Ñжатие"? Уплотнение базы данных Warning: Compacting the database will commit all of your changes. Предупреждение: Уплотнение базы данных зафикÑирует вÑе изменениÑ, которые были Ñделаны. Please select the databases to co&mpact: Выберите объекты Ð´Ð»Ñ &уплотнениÑ: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_sv.ts000066400000000000000000007364321463772530400252440ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Om DB Browser för SQLite Version Version <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Enter values for the new record considering constraints. Fields in bold are mandatory. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Name Namn Type Typ Value Values to insert. Pre-filled default values are inserted automatically unless they are changed. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> Auto-increment Unique constraint Check constraint: %1 Foreign key: %1 Default value: %1 Error adding record. Message from database engine: %1 Are you sure you want to restore all the entered values to their defaults? Application Invalid option/non-existent file: %1 Felaktig parameter/icke existerande fil: %1 Possible command line arguments: Möjliga argument pÃ¥ kommandoraden: The file %1 does not exist Filen %1 finns inte The user settings file location is replaced with the argument value instead of the environment variable value. Ignored environment variable (DB4S_SETTINGS_FILE) value: Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The -S/--settings option requires an argument. The option is ignored. The -o/--option and -O/--save-option options require an argument in the form group/setting=value SQLite Version SQLite Version SQLCipher Version %1 (based on SQLite %2) DB Browser for SQLite Version %1. Built for %1, running on %2 Qt Version %1 Browse this table, or use it as target of a data import Last commit hash when built: %1 CipherDialog SQLCipher encryption SQLCipher kryptering Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Ange en nyckel för att kryptera databasen. Notera att om du ändrar nÃ¥gon annan valbar inställning sÃ¥ behöver du Ã¥ter igen ange dem igen varje gÃ¥ng du öppnar databasen. Lämna fältet för lösenord tomt för att avaktivera kryptering. Krypteringsprocessen behvöer lite tid och se till att ha en backupkopia av din databas! Osparade förändringar appliceras innan modifiering av krypteringen sker. &Password &Lösenord &Reenter password Ange lösenord &igen Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Ange nyckel som används för att kryptera databasen. Om nÃ¥gon annan inställning ändrades för denna databas behöver du ange och justera även det. Passphrase Raw key Encr&yption settings SQLCipher &3 defaults SQLCipher &4 defaults Custo&m Page si&ze &KDF iterations HMAC algorithm KDF algorithm Plaintext Header Size ColumnDisplayFormatDialog Choose display format Display format Choose a display format for the column '%1' which is applied to each value prior to showing it. Default Förvald Decimal number Exponent notation Hex blob Hex number Octal number Round number Apple NSDate to date Java epoch (milliseconds) to date .NET DateTime.Ticks to date Julian day to date Unix epoch to date Unix epoch to local time Windows DATE to date Date as dd/mm/yyyy Lower case Upper case Binary GUID to text Custom Custom display format must contain a function call applied to %1 Error in custom display format. Message from database engine: %1 Custom display format must return only one column but it returned %1. SpatiaLite Geometry to SVG WebKit / Chromium epoch to date WebKit / Chromium epoch to local time CondFormatManager Conditional Format Manager This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Add new conditional format &Add Remove selected conditional format &Remove Move selected conditional format up Move &up Move selected conditional format down Move &down Foreground Text color Background Background color Font Size Bold Fet Italic Kursiv Underline Understrykning Alignment Condition Click to select color Are you sure you want to clear all the conditional formats of this field? DBBrowserDB Action cancelled. Aktivitet avbruten. Please specify the database name under which you want to access the attached database Ange det databasnamn med vilket du vill komma Ã¥t ansluten databas Cancel Avbryt File not found. Hittar inte fil. Error setting pragma %1 to %2: %3 Kunde inte sätta pragma %1 till %2: %3 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Kunde inte Ã¥terställa nÃ¥gra objekt som är associerade med denna tabell. Toligast är att nÃ¥gra kolumnnamn ändrats. Här är SQL-uttrycket som du kan behöva Ã¥tgärda och köra manuellt: Exporting database to SQL file... Exporterar databas till SQL-fil... Do you want to save the changes made to the database file %1? Vill du spara ändringarna som gjorts i databasfilen %1? Executing SQL... Utför SQL... Invalid file format Do you really want to close this temporary database? All data will be lost. Database didn't close correctly, probably still busy Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: Do you want to abort that other operation? No database file opened Error in statement #%1: %2. Aborting execution%3. and rolling back didn't receive any output from %1 could not execute command: %1 Cannot delete this object Cannot set data on this object A table with the name '%1' already exists in schema '%2'. No table with name '%1' exists in schema '%2'. Cannot find column %1. Creating savepoint failed. DB says: %1 Renaming the column failed. DB says: %1 Releasing savepoint failed. DB says: %1 Creating new table failed. DB says: %1 Copying data to new table failed. DB says: %1 Deleting old table failed. DB says: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 could not get list of db objects: %1 could not get list of databases: %1 Error loading extension: %1 Fel när tillägg skulle laddas: %1 could not get column information Error loading built-in extension: %1 DbStructureModel Name Namn Type Typ Triggers (%1) Utlösare (%1) Object Objekt Schema Schema Indices (%1) Index (%1) Tables (%1) Tabeller (%1) Views (%1) Vyer (%1) Database Browsables All Temporary EditDialog Text Text Choose a filename to export data Välj ett filnamn att exportera data till Erases the contents of the cell Tar bort innehÃ¥llet frÃ¥n cellen Binary Binär Edit database cell Redigera databascell This area displays information about the data present in this database cell Detta omrÃ¥de visar information om data som finns i denna databascell Mode: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. RTL Text Image JSON XML Evaluation Automatically adjust the editor mode to the loaded data type This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Auto-switch The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Apply data to cell This button saves the changes performed in the cell editor to the database cell. Apply Print... Open preview dialog for printing displayed text Open preview dialog for printing the data currently stored in the cell Ctrl+P Copy Hex and ASCII Copy selected hexadecimal and ASCII columns to the clipboard Ctrl+Shift+C Autoformat Auto-format: pretty print on loading, compact on saving. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. &Export... Export to file Opens a file dialog used to export the contents of this database cell to a file. &Import... Import from file Opens a file dialog used to import any kind of data to this database cell. Set as &NULL Word Wrap Wrap lines on word boundaries Open in default application or browser Open in application The value is interpreted as a file or URL and opened in the default application or web browser. Save file reference... Save reference to file Open in external application Unsaved data in the cell editor Image data can't be viewed in this mode. Try switching to Image or Binary mode. Binary data can't be viewed in this mode. Try switching to Binary mode. Image files (%1) Choose a file to import Välj en fil att importera %1 Image Binary files (*.bin) Invalid data for this mode The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? Couldn't save file: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Identification of the cell currently in the editor Type and size of data currently in table The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) EditIndexDialog Edit Index Schema &Name &Namn &Table &Tabell &Unique &Unik For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Partial inde&x clause Colu&mns Table column Type Typ Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Index column Order Ordning Deleting the old index failed: %1 Creating the index failed: %1 Misslyckades att skapa index: %1 EditTableDialog U U AI AU PK PN Name Namn Type Typ Check Vald Table Tabell Autoincrement Autouppräkning Error creating table. Message from database engine: %1 Kunde inte skapa tabell. Meddelande frÃ¥n databasmotorn: %1 Check constraint Kontrollera förbehÃ¥ll Fields Fält Unique Unik Not null Inte tom There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Det finns Ã¥tminstoen en rad med deta fält satt till TOM. Det gör att det inte gÃ¥r markera detta val. Ändra data i tabellen först. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Är du säker pÃ¥ att du vill ta bort fältet '%1'? All sparad data i fältet försvinner. Without Rowid Utan radid Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Lägg till ett fält som möter följande kriterier innan radid markeras: - Primärnyckel är markerad - Autouppräkning är avmarkerad There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Det finns Ã¥tminstone en rad med icke-heltalsvärde för detta fält. Det gör att det är omöjligt att markera AU. Ändra data i tabellen först. Default Förvald Advanced Avancerad Default value Förvalt värde Edit table definition Redigera tabelldefinition Foreign Key Främmande nyckel Database sche&ma Add Remove Move to top Move up Move down Move to bottom NN <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> Collation <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Add constraint Remove constraint Columns Kolumner SQL <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> Primary Key Add a primary key constraint Add a unique constraint There can only be one primary key for each table. Please modify the existing primary key instead. There already is a field with that name. Please rename it first or choose a different name for this field. This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Column '%1' has duplicate data. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Index Constraints Foreign Keys References Check Constraints Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. ExportDataDialog Export data as CSV Exportera data som CSV Tab&le(s) Colu&mn names in first line Fie&ld separator , , ; ; Tab Tabb | | Other Annat &Quote character &Citattecken " " ' ' New line characters Windows: CR+LF (\r\n) Unix: LF (\n) Pretty print Export data as JSON exporting CSV Could not open output file: %1 Kunde inte öppna fil för utdata: %1 exporting JSON Choose a filename to export data Välj ett filnamn att exportera data till Please select at least 1 table. Välj minst 1 tabell. Choose a directory Välj en katalog Export completed. Export slutförd. Error while writing the file '%1': %2 Export finished with errors. ExportSqlDialog Export completed. Export slutförd. Export schema only Exportera endast schema Export cancelled or failed. Export avbruten eller mislyckades. &Options &Val Keep column names in INSERT INTO BehÃ¥ll kolunnamn i INSERT INTO Export SQL... Exportera SQL... Choose a filename to export Välj ett filnamn att exportera Tab&le(s) Select All Deselect All Multiple rows (VALUES) per INSERT statement Export everything Export data only Keep old schema (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Please select at least one table. Keep original CREATE statements ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Find and Replace... Print... ExtendedTableWidget Use as Exact Filter Containing Not containing Not equal to Greater than Less than Greater or equal Less or equal Between this and... Regular expression Edit Conditional Formats... Set to NULL Cut Copy Copy with Headers Copy as SQL Paste Print... Use in Filter Expression Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. FileExtensionManager File Extension Manager &Up &Down &Add &Remove Description Extensions *.extension FilterLineEdit Filter Filter These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Set Filter Expression What's This? Is NULL Is not NULL Is empty Is not empty Not containing... Equal to... Not equal to... Greater than... Less than... Greater or equal... Less or equal... In range... Regular expression... Clear All Conditional Formats Use for Conditional Format Edit Conditional Formats... FindReplaceDialog Find and Replace Fi&nd text: Re&place with: Match &exact case Match &only whole words When enabled, the search continues from the other end when it reaches one end of the page &Wrap around When set, the search goes backwards from cursor position, otherwise it goes forward Search &backwards <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> &Selection only <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Use regular e&xpressions Find the next occurrence from the cursor position and in the direction set by "Search backwards" &Find Next F3 &Replace Highlight all the occurrences of the text in the page F&ind All Replace all the occurrences of the text in the page Replace &All The searched text was not found The searched text was not found. The searched text was replaced one time. The searched text was found one time. The searched text was replaced %1 times. The searched text was found %1 times. ForeignKeyEditor &Reset Foreign key clauses (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Reset the scaling to match the original size of the image. Set the scaling to match the size of the viewport. Print... Open preview dialog for printing displayed image Ctrl+P ImportCsvDialog " " ' ' , , ; ; | | Tab Tabb Other Annat UTF-8 ISO-8859-1 Creating restore point failed: %1 Misslyckades att skapa Ã¥terställningspunkt: %1 Inserting row failed: %1 Misslyckades att infoga rad: %1 &Column names in first line &%Kolumnnamn pÃ¥ första raden Creating the table failed: %1 Misslyckades att skapa tabellen: %1 &Encoding &Teckenkodning Field &separator Fält&separator UTF-16 Trim fields? Beskär fält? &Quote character &Citattecken Import CSV file Importera CSV-fil Table na&me Other (printable) Other (code) Separate tables Advanced Avancerad When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Ignore default &values Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Fail on missing values Disable data type detection Disable the automatic data type detection when creating a new table. Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Abort import Ignore row Replace existing row Conflict strategy Deselect All Match Similar Select All There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. There is already a table named '%1'. Do you want to import the data into it? importing CSV Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Could not prepare INSERT statement: %1 MainWindow User Användare Import completed. Import slutförd. &Edit &Redigera &File &Fil &Help &Hjälp &View &Vy E&xit A&vsluta Open the preferences window. Öppna fönster för egenskaper. Export a database to a .sql dump text file. Exportera databas till en .sql-dump textfil. Error importing data: %1 Fel vid import av data: %1 &Recently opened &Nyligen öppnad Ctrl+Return Ctrl+Retur Load a working session from a file Ladda en fungerande session frÃ¥n en fil &New Database... &Ny databas... This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Detta val används för att Ã¥terställa nuvarande databas till sitt senaste sparade läge. Alla förändringar efter senaste sparning gÃ¥r förlorade. Choose a file to import Välj en fil att importera Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Exportera en databastabell som en kommaseparerad textfil, redo at importeras i en annan databas eller program för kalkylark. &Clear &Rensa Export table as comma separated values file Exportera tabell som en fil med kommaseparerad värden Copy the CREATE statement of the item to the clipboard Kopiera CREATE-satsen till urklipp This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Detta val lÃ¥ter dig importera data frÃ¥n en .sql-dump textfil till en ny eller existerande databas. SQL-dumpfiler kan skapas med de flesta databasmotererna, inklusive MySQL och PostgreSQL. Save the current session to a file Spara nuvarande session till en fil Delete Index Ta bort index Setting PRAGMA values will commit your current transaction. Are you sure? Om du ställer in värdet för PRAGMA kommer du att genomföra nuvarande transaktion. Är du säker? Delete Table Ta bort tabell Ctrl+D Ctrl+E Ctrl+I Ctrl+L Ctrl+N Ctrl+O Ctrl+P Ctrl+Q Ctrl+S Ctrl+T Ctrl+W A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. En ny version av DB Browser för SQLite är tillgänglig (%1.%2.%3).<br/><br/>Ladda ner den frÃ¥n <a href='%4'>%4</a>. Choose a database file Välj en databasfil Import data from an .sql dump text file into a new or existing database. Importera data frÃ¥n en .sql-dump textfil till en ny eller existerande databas. Revert database to last saved state Ã…terställ databasen till senaste sparade läget Shows or hides the Database toolbar. Visa eller dölj verktygsrad för databas. Compact the database file, removing space wasted by deleted records Minska storleken pÃ¥ databasfilen genom att ta bort onödigt tomrum som upptas av bortagna poster This option is used to create a new database file. Detta val används för att skapa en ny databasfil. toolBar1 Verktygsrad1 Don't show again Visa inte igen Delete Trigger Ta bort utlösare Text files(*.sql *.txt);;All files(*) Textfiler(*.sql *.txt);;Alla filer(*) Copy Create statement Kopiera CREATE-uttryck Select SQL file to open Välj SQL-fil att öppna Choose a filename to save under Visa ett filnamn att spara under Open the Create Index wizard, where it is possible to define a new index on an existing database table. Öppna guiden för att skapa index, där finns möjlighet att definiera ett nytt index för en existerande databastabell. Create a new database file Skapa en ny databasfil &Open Database... &Öppna databas... Open the Delete Table wizard, where you can select a database table to be dropped. Öppna guiden för att ta bort tabell, där du kan välja en databastabell att släppa. Select extension file Välj fil med tillägg DB Browser for SQLite project file (*.sqbpro) DB Browser för SQLite projektfil (*.sqbpro) Are you sure you want to undo all changes made to the database file '%1' since the last save? Är du säker pÃ¥ att du vill Ã¥ngra alla ändringar som gjorts i databasfilen '%1' sedan den sparades senaste? Select file name Välj filnamn Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Öppna guiden för att skapa tabell, där det är möjligt att ange filnamn och fält för en ny tabell i databasen Export a database table as a comma separated text file. Exportera en databastabell som en kommaseparerad textfil. Export as CSV file Exportera som CSV-fil Extension successfully loaded. Tillägget har laddats in. Open an existing database file Öppna en existerande databasfil Delete View Ta bort vy Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Öppna en guide för att importera data frÃ¥n en kommaseparerad textfil in i en databastabell. CSV-filer kan skapas med de flesta databaser och kalkylprogram. &Export &Exportera &Import &Importera File %1 already exists. Please choose a different name. Filen %1 finns redan. Välj ett annat namn. DB Toolbar DB Verktygsrad &DB Toolbar &DB Verktygsrad Save SQL file as Spara SQL-fil som &Close Database &Stäng databas This option is used to save changes to the database file. Detta val används för att spara förändringar till databasfilen. &Preferences... &Egenskaper... Write changes to the database file Skriv ändringar till databasfilen Database encoding Databasteckenkodning Save SQL file Spara SQL-fil Compact the database file, removing space wasted by deleted records. Töm databasfilen och ta bort tomrum av borttagna poster. Open a wizard that lets you import data from a comma separated text file into a database table. Öppna guide för at importera en kommaseparerad textfil till en databastabell. DB Browser for SQLite DB Browser för SQLite Execute current line Utför nuvarande rad &Browse Table &Visa tabell Database is encrypted using SQLCipher Databasen är krypterad med SQLCipher New version available. Ny version tillgänglig. &Execute SQL &Utför SQL This option is used to open an existing database file. Detta val används för att öppna en existerande databasfil. Error loading extension: %1 Fel när tillägg skulle laddas: %1 This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Valet lÃ¥ter dig exportera en databas till en .sql-dump textfil. SQL-dump textfiler innehÃ¥ller all data som behövs för att Ã¥terskapa databasen med de flesta databasmotorer, inklusive MySQL och PostgreSQL. Shift+F1 Skift+F1 Application Programvara Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Vill du skapa en ny databas med det importerade datat? Försöker importera datat i SQL-filen i nuvarande databas om du svarar nej. This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. &Recent Files Too&ls Edit Database &Cell SQL &Log Show S&QL submitted by Error Log This button clears the contents of the SQL logs This panel lets you examine a log of all SQL commands issued by the application or by yourself &Plot DB Sche&ma This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. &Remote Project Toolbar Extra DB toolbar Close the current database file This button closes the connection to the currently open database file Ctrl+F4 &Revert Changes &Write Changes Compact &Database... &Database from SQL file... &Table from CSV file... &Database to SQL file... &Table(s) as CSV file... &Create Table... &Delete Table... &Modify Table... Create &Index... W&hat's This? &About New &tab This button opens a new tab for the SQL editor Execute all/selected SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Open SQL file(s) This button opens files containing SQL statements and loads them in new editor tabs &Load Extension... Execute line This button executes the SQL statement present in the current editor line Shift+F5 Skift+F5 &Wiki F1 Bug &Report... Feature Re&quest... Web&site &Donate on Patreon... Sa&ve Project This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Open &Project... This button lets you open a DB Browser for SQLite project file &Attach Database... Add another database file to the current database connection This button lets you add another database file to the current database connection &Set Encryption... This button saves the content of the current SQL editor tab to a file SQLCipher &FAQ Opens the SQLCipher FAQ in a browser window Table(&s) to JSON... Export one or more table(s) to a JSON file Open Data&base Read Only... Open an existing database file in read only mode Ctrl+Shift+O Save results Save the results view This button lets you save the results of the last executed query Find text in SQL editor Find This button opens the search bar of the editor Ctrl+F Find or replace text in SQL editor Find or replace This button opens the find/replace dialog for the current editor tab Ctrl+H Export to &CSV Exportera till &CSV Export to &JSON Save as &view Spara som &vy Save as view Spara som vy Shows or hides the Project toolbar. Extra DB Toolbar New In-&Memory Database Drag && Drop Qualified Names Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Drag && Drop Enquoted Names Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor &Integrity Check Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. &Foreign-Key Check Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab &Quick Integrity Check Run a quick integrity check over the open DB Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. &Optimize Attempt to optimize the database Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Print Print text from current SQL editor tab Open a dialog for printing the text in the current SQL editor tab Print the structure of the opened database Open a dialog for printing the structure of the opened database Un/comment block of SQL code Un/comment block Comment or uncomment current line or selected block of code Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Ctrl+/ Stop SQL execution Stop execution Stop the currently running SQL script &Save Project As... Save the project in a file selected in a dialog Save A&ll Save DB file, project file and opened SQL files Ctrl+Shift+S Browse Table Close Pro&ject Close project and database files and return to the initial state Ctrl+Shift+W Detach Database Detach database file attached to the current database connection Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Ctrl+Tab Ctrl+Shift+Tab Clear List Window Layout Reset Window Layout Simplify Window Layout Alt+Shift+0 Dock Windows at Bottom Dock Windows at Left Side Dock Windows at Top The database is currently busy. Click here to interrupt the currently running query. Encrypted Read only Database file is read only. Editing the database is disabled. Ctrl+Alt+W Ctrl+Shift+F4 Could not open database file. Reason: %1 In-Memory database Choose a database file to save under Error while saving the database to the new file. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Do you want to save the changes made to the project file '%1'? Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Are you sure you want to delete the view '%1'? Are you sure you want to delete the trigger '%1'? Are you sure you want to delete the index '%1'? Error: could not delete the table. Error: could not delete the view. Error: could not delete the trigger. Error: could not delete the index. Message from database engine: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Error checking foreign keys after table modification. The changes will be reverted. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Edit View %1 Edit Trigger %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. -- EXECUTING SELECTION IN '%1' -- -- EXECUTING LINE IN '%1' -- -- EXECUTING ALL IN '%1' -- At line %1: Result: %1 Result: %2 %1 rows returned in %2ms Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Execution finished with errors. Execution finished without errors. Choose text files Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Import completed. Some foreign key constraints are violated. Please fix them before saving. Modify View Modify Trigger Modify Index Modify Table Opened '%1' in read-only mode from recent file list Opened '%1' from recent file list &%1 %2%3 (read only) Open Database or Project Attach Database... Import CSV file(s)... Do you want to save the changes made to SQL tabs in a new project file? Do you want to save the changes made to SQL tabs in the project file '%1'? Do you want to save the changes made to the SQL file %1? The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? Could not find resource file: %1 Choose a project file to open This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Could not open project file for writing. Reason: %1 Project saved to file '%1' Yes. Don't ask again Collation needed! Proceed? Sortering behövs! Fortsätt? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! En tabell i databasen behöver en speciell sorteringsfunktion '%1' som detta program inte tillhandahÃ¥ller utan ytterligare kunskap. Skadliga skare kan inträffa med din databas om du väljer att fortsätta. Skapa en backup! creating collation Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Please specify the view name Ange namn pÃ¥ vy There is already an object with that name. Please choose a different name. Det finns redan ett objekt med det namnet. Ange ett annat namn. View successfully created. Vy skapades. Error creating view: %1 Misslyckades skapa vy: %1 This action will open a new SQL tab for running: This action will open a new SQL tab with the following statements for you to edit and run: Press Help for opening the corresponding SQLite reference page. Busy (%1) Rename Tab Duplicate Tab Close Tab Opening '%1'... There was an error opening '%1'... Value is not a valid URL or filename: %1 &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs E&xecute SQL This has to be equal to the tab title in all the main tabs &New Database &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Ctrl+Shift+T &Save Project Open &Project &Open Database Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Refresh Reload the database structure Ctrl+Alt+0 DB file '%1' could not be opened Table '%1' not found; settings ignored -- Reference to file "%1" (not supported by this version) -- Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Automatically load the last opened DB file at startup NullLineEdit Set to NULL Alt+Del PlotDock Plot <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> Columns Kolumner X Y1 Y2 Axis Type Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Line type: Radtyp: None Ingen Line Rad StepLeft Vänstersteg StepRight Högersteg StepCenter Stegcentrum Impulse Impuls Point shape: Punktform: Cross Kors Plus Circle Cirkel Disc Skiva Square Fyrkant Diamond Diamant Star Stjärna Triangle Triangel TriangleInverted InverteradTriangel CrossSquare Korsfyrkant PlusSquare Plusfyrkant CrossCircle Korscirkel PlusCircle Pluscirkel Peace Fred <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Spara nuvarande plan...</p><p>Filformat valt utifrÃ¥n filändelse (png, jpg, pdf, bmp)</p></body></html> Save current plot... Spara nuvarande plan... Load all data and redraw plot Copy Print... Show legend Stacked bars Fixed number format Date/Time Date Time Numeric Label Invalid Row # Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Choose an axis color Choose a filename to save under Visa ett filnamn att spara under PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Alla Filer(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Loading all remaining data for this table took %1ms. PreferencesDialog ... ... &SQL &SQL Bold Fet SQL &editor font size SQL &redigera fontstorlek Automatic &updates Automatisk &uppdatering Table Tabell Lan&guage Spr&Ã¥k Current line Nuvarande rad Keyword Nyckelord The language will change after you restart the application. SprÃ¥ket ändras efter du startar om programmet. SQL editor &font &Font SQL redigerare Data &Browser Data&visare Open databases with foreign keys enabled. Öppna databaser med främmande nycklar aktiverade. Remember last location for session only Kom endast ihÃ¥g senaste plats för sessionen Colour Färg Italic Kursiv Disable Regular Expression extension Avaktivera tillägg för reguljära uttryck Identifier Identifierare String Sträng &Database &Databas Database &encoding Databas&teckenkodning &Foreign keys &Främmande nycklar Select extension file Välj tilläggsfil Default &location Förvald &placering <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>SQLite stödjer REGEXP med hanterar inte nÃ¥gra<br/>algoritmer för reguljära uttryck, utan använder det som tillhandahÃ¥lls av programmet som körs. DB Browser för SQLite hanterar <br/>en algoritm Ã¥t dig sÃ¥ du kan använda REGEXP pÃ¥ en gÃ¥ng. Dock finns det en uppsjö möjliga olika varianter att välja mellan<br/> av vilken du kanske vill använda en annan, sÃ¥ är du fri at avaktivera <br/>programmets variant och ladda in din egen genom ett tillägg. Omstart av programmet är dÃ¥ nödvändigt.</p></body></html> Comment Kommentar Context Sammanhang Underline Understrykning Remember last location Kom ihÃ¥g senaste plats Choose a directory Välj en katalog Select extensions to load for every database: Välj tillägg att ladda in för varje databas: enabled aktiverad Function Funktion &Extensions &Tillägg Remove extension Ta bort tillägg Preferences Egenskaper Add extension Lägg till tillägg &General &Generell Always use this location Använd alltid den här platsen Toolbar style Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style Show remote options DB file extensions Manage Main Window Database Structure Browse Data Execute SQL Edit Database Cell When this value is changed, all the other color preferences are also set to matching colors. Follow the desktop style Dark style Application style This sets the font size for all UI elements which do not have their own font size option. Font size Max Recent Files Prompt to save SQL tabs in new project file If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. Remove line breaks in schema &view Prefetch block si&ze Default field type When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Database structure font size SQ&L to execute after opening database Font &Font Font si&ze Content Symbol limit in cell This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Threshold for completion and calculation on selection Show images in cell Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Field display Displayed &text Binary Binär NULL Regular Click to set this color Text color Background color Preview only (N/A) Filters Escape character Delay time (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Background Foreground Selection background Selection foreground Highlight SQL &results font size Tab size &Wrap lines Never At word boundaries At character boundaries At whitespace boundaries &Quotes for identifiers Choose the quoting mechanism used by the application for identifiers in SQL code. "Double quotes" - Standard SQL (recommended) `Grave accents` - Traditional MySQL quotes [Square brackets] - Traditional MS SQL Server quotes Code co&mpletion Keywords in &UPPER CASE When set, the SQL keywords are completed in UPPER CASE letters. Error indicators When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Hori&zontal tiling If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Close button on tabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> Allow loading extensions from SQL code Remote Your certificates File Fil Subject CN Subject Common Name Issuer CN Issuer Common Name Valid from Valid to Serial number CA certificates Common Name Subject O Organization Clone databases into Proxy Configure Export Settings Import Settings Extensions(*.so *.dylib *.dll);;All files(*) Import certificate file No certificates found in this file. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Save Settings File Initialization File (*.ini) The settings file has been saved in location : Open Settings File The settings file was loaded properly. The selected settings file is not a normal settings file. Please check again. Light style Formatted Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. Select built-in extensions to load for every database: ProxyDialog Proxy Configuration Pro&xy Type Host Na&me Port Authentication Re&quired &User Name Password None Ingen System settings HTTP SOCKS5 QObject . %1 .%1 from record number %1 frÃ¥n post nummer %1 Cancel Avbryt Error importing data Fel vid import av data Left Right Center Justify All files (*) SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) SQL Files (*.sql) All Files (*) Text Files (*.txt) Comma-Separated Values Files (*.csv) Tab-Separated Values Files (*.tsv) Delimiter-Separated Values Files (*.dsv) Concordance DAT files (*.dat) JSON Files (*.json *.js) XML Files (*.xml) Binary Files (*.bin *.dat) SVG Files (*.svg) Hex Dump Files (*.dat *.bin) Extensions (*.so *.dylib *.dll) Initialization File (*.ini) Importing CSV file... SQLite database files (*.db *.sqlite *.sqlite3 *.db3) QsciCommand Cancel Avbryt QsciLexerCPP Default Förvald Keyword Nyckelord Identifier Identifierare QsciLexerJSON Default Förvald String Sträng QsciLexerPython Default Förvald Comment Kommentar Keyword Nyckelord Identifier Identifierare QsciLexerSQL Default Förvald Comment Kommentar Keyword Nyckelord Identifier Identifierare QsciScintilla Delete Ta bort RemoteCommitsModel Commit ID Message Date Author Size Authored and committed by %1 Authored by %1, committed by %2 RemoteDatabase Error opening local databases list. %1 Error creating local databases list. %1 RemoteDock Remote Identity Push currently opened database to server Upload DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> Local Current Database Clone &User &Database &Databas Branch Commits Commits for <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> Back Delete Database Delete the local clone of this database Open in Web Browser Open the web page for the current database in your browser Clone from Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. Refresh Reload all data and update the views Clone Database Open Database Open the local copy of this database Check out Commit Download and open this specific commit Check out Latest Commit Check out the latest commit of the current branch Save Revision to File Saves the selected revision of the database to another file Upload Database Upload this database as a new commit Select an identity to connect Public This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Invalid URL: The host name does not match the host name of the current identity. Invalid URL: No branch name specified. Invalid URL: No commit ID specified. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? The database has unsaved changes. Are you sure you want to push it before saving? The database you are trying to delete is currently opened. Please close it before deleting. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? RemoteLocalFilesModel Name Namn Branch Last modified Size Commit File Fil RemoteModel Name Namn Last modified Size Commit Size: Last Modified: Licence: Default Branch: RemoteNetwork Choose a location to save the file Error opening remote file at %1. %2 Error: Invalid client certificate specified. Please enter the passphrase for this client certificate in order to authenticate. Cancel Avbryt Uploading remote database to %1 Downloading remote database from %1 Error: Cannot open the file for sending. RemotePushDialog Push database Database na&me to push to Commit message Database licence Public Branch Force push Username Database will be public. Everyone has read access to it. Database will be private. Only you have access to it. Use with care. This can cause remote commits to be deleted. RunSql Execution aborted by user , %1 rows affected query executed successfully. Took %1ms%2 executing query SelectItemsPopup A&vailable Sele&cted SqlExecutionArea Form Formulär Results of the last executed statements Resultat av senast utförda uttrycket This field shows the results and status codes of the last executed statements. Fältet visar resultat och statuskoder av senast utförda uttryck. Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 Skift+F3 The found pattern must be a whole word Whole Words Text pattern to find considering the checks in this frame Find in editor The found pattern must match in letter case Case Sensitive Find next match [Enter, F3] Find next match with wrapping F3 Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Close Find Bar <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> Couldn't save file: %1. Your changes will be lost when reloading it! The file "%1" was modified by another program. Do you want to reload it?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. Couldn't read file "%1": %2. Ctrl+PgUp Ctrl+PgDown SqlTextEdit Ctrl+/ SqlUiLexer (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) Funktionen group_concat() returnerar en sträng som slÃ¥r samman alla icke-TOMMA värden av X. (timestring,modifier,modifier,...) (tidssträng,modifierare,modifierare...) (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) Flerargumentsfunktionen max() returnerar argumentet med det största värdet, eller NULL om nÃ¥got argument är TOMT (NULL). (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) Funktioen count(X) returnerar antalet gÃ¥nger somX inte är TOMT (NULL) i en gruppering. (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) Funktionen ifnull() returnerar en kopia av dess första icke-TOMMA argument, eller NULL om bÃ¥da argumenten är TOMMA (NULL). (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) Flerargumentsfunktionen min() returnerar argument med lägst värde. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) SQL-funktionen printf(FORMAT,...) fungerar som funktionen sqlite3_mprintf() i C-sprÃ¥k och funktionsnamnet printf() kommer frÃ¥n standardbiblioteket för C. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () Funktionen last_insert_rowid() returnerar radid (ROWID) för senast tillagda rad för ansluten databas som senast använde funktionen. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) Funktionen coalesce() returnerar en kopia av dess första icke-TOMMA argument, eller NULL om alla argument är TOMMA (NULL) (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) Funktionen group_concat() returnerar en sträng sammanfogad av alla icke-TOMMA värden av X. Parametern Y används som avdelare mellan värden av X om den angivits. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) Funktionen hex() tolkar argumenten som en BLOB och returnerar en sträng av hexadecimal som versaler som representerar innehÃ¥llet av blob:en. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) Funktionen quote(X) returnerar texten som innehÃ¥llet av värdet för argumentet sÃ¥ att det kan stättas in i en SQL-stats. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) funktionen typeof(X) returnerar en sträng som anger datatyp för uttrycket X. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) Funktionen instr(X,Y) söker efter första förekomsten av strängen Y inom strängen X och returnerar dess början som antal tecken före plus 1, eller 0 om Y inte kan hittas inom X. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () Funktionen random() returnerar ett nÃ¥gorlunda genererat slumptal som heltal i intervallet -9223372036854775808 och +9223372036854775807. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) Funktionen lower(X) returnerar en kopia av strängen X med alla ASCII-tecken ändrade till gemener. (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) Funktionen like() används för att Ã¥stadkomma uttrycket "Y LIKE X ESCAPE Z". (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) Funktionen like() används för att Ã¥stadkomma uttrycket "Y LIKE X". (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) Funktionen ltrim(X,Y) returnerar en sträng som rensats pÃ¥ alla tecken som ingÃ¥r i Y frÃ¥n vänstra sidan av X. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) Funktionen round(X) returnerar et decimaltal X som avrundats till noll decimaler. (X) The abs(X) function returns the absolute value of the numeric argument X. (X) Funktionen abs(X) returnerar absolutvärdt av det numeriska argumentet X. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) tar bort mellanslag frÃ¥n höger sida av X. (format,timestring,modifier,modifier,...) (format,tidssträng,modifierare,modifierare...) () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () Funtionen total_changes() returnerar antalet rader som ändrats av INSERT, UPDATE eller DELETE sedan databasen öppnades. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) Aggregat-funktionerna sum() och total() returnerar summan av alla icke-TOMMA värden i en grupp. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) Funktionen length(X) returnerar antalet tecken (inte byte) som strängen X innehÃ¥ller före det första tom-tecknet (NUL). (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) tar bort mellanslag frÃ¥n höger sida av X. (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) Funktionen glob(X,Y) motsvarar uttrycket "Y GLOB X". (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) Funktionen soundex(X) returnerar en sträng som motsvarar uttalet av strängen X. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) Funktionen upper(X) returnerar en kopia av indatasträngen X där alla gemener av ASCII-tecken görs om till sina motsvarigheter som versaler. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) Funktionen zeroblob(N) returnerar en BLOB som bestÃ¥r av N byte av 0x00. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) Funktionen rtrim(X,Y) returnerar en sträng som rensats pÃ¥ alla tecken som ingÃ¥r i Y frÃ¥n högra sidan av X. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) Aggregatfunktionen min() returnerar mininsta värde som inte är TOMT (NULL) av alla värden i en gruppering. (X) trim(X) removes spaces from both ends of X. (X) trim(X) tar bort mellanslag frÃ¥n bÃ¥da ändar av X. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) Funktionen replace(X,Y,Z) returnerar en sträng där varje förekomst av strängen Y ersatts med Z i strängen X. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) Funktionen round(X,Y) returnerar ett decimaltal X avrundat till Y decimaler. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) Funktionen nullif(X,Y) returnerar dess första argument om argumenten är olika och TOMT (NULL) om argumenten är lika. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) Funktionen trim(X,Y) returnerar en sträng där alla förekomster av Y tagits bort i bÃ¥da ändar av X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) Aggregatfunktionen max() returnerar det största av värdena i grupperingen. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) Funktionen randomblob(N) returnerar en blob som är N-byte stor och innehÃ¥ller nÃ¥gorlunda slumpmässiga byte. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) Funktionen substr(X,Y,Z) returnerar en del av indatasträngen X och börjar pÃ¥ teckenposition Y och är Z tecken lÃ¥ng. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) Funktionen char(X1,X2,...,XN) returnerar en sträng med tecken skapad av tal för unicode-värden frÃ¥n X1 till XN. (X) The avg() function returns the average value of all non-NULL X within a group. (X) Funktionen avg() returnerar medelvärdet av alla icke-TOMMA X inom en gruppering. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) Funktionen unicode(X) returnerar det numeriska unicode-värdet som motsvarar det första tecknet i strängen X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () Funktionen changes() returnerar antalet rader i databasen som förändrades, infogades eller togs bort av den senast genomförda INSERT, DELETE, eller UPDATE-satsen. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) returnerar alla tecken till slutet av strängen X med början pÃ¥ tecken Y. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. SqliteTableModel Error changing data: %1 Misslyckades ändra data: %1 reading rows loading... References %1(%2) Hold %3Shift and click to jump there retrieving list of columns Fetching data... Cancel Avbryt TableBrowser Browse Data &Table: Select a table to browse data Välj en tabell för att visa data Use this list to select a table to be displayed in the database view Använd denna lista för att välja en tabell at visa i databasvyn This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Text pattern to find considering the checks in this frame Find in table Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 Skift+F3 Find next match [Enter, F3] Find next match with wrapping F3 The found pattern must match in letter case Case Sensitive The found pattern must be a whole word Whole Cell Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Close Find Bar Text to replace with Replace with Replace next match Replace Replace all matches Replace all <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Rulla till början</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Klicka pÃ¥ denna knapp för att navigera till början av tabellen ovan.</p></body></html> |< Scroll one page upwards <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> < 0 - 0 of 0 0 - 0 av 0 Scroll one page downwards <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> > Scroll to the end Rulla till slutet <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>Klick här för att hoppa till angiven post</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Denna knapp används för att navigera till posten med angivet nummer i ytan för GÃ¥ till.</p></body></html> Go to: GÃ¥ till: Enter record number to browse Ange post nummer att visa Type a record number in this area and click the Go to: button to display the record in the database view Ange ett nummer för post i detta fält och klicka pÃ¥ kanppen GÃ¥ till: för att visa posten i databasvyn 1 Show rowid column Toggle the visibility of the rowid column Unlock view editing This unlocks the current view for editing. However, you will need appropriate triggers for editing. Edit display format Edit the display format of the data in this column New Record Ny post Insert a new record in the current table Infoga en ny post i nuvarande tabell <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> Delete Record Ta bort post Delete the current record Ta bort nuvarande post This button deletes the record or records currently selected in the table Insert new record using default values in browsed table Insert Values... Open a dialog for inserting values in a new record Export to &CSV Exportera till &CSV Export the filtered data to CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Save as &view Spara som &vy Save the current filter, sort column and display formats as a view This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Save Table As... Save the table as currently displayed <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> Hide column(s) Hide selected column(s) Show all columns Show all columns that were hidden Set encoding Change the encoding of the text in the table cells Set encoding for all tables Change the default encoding assumed for all tables in the database Clear Filters Clear all filters Rensa alla filter This button clears all the filters set in the header input fields for the currently browsed table. Clear Sorting Reset the order of rows to the default This button clears the sorting columns specified for the currently browsed table and returns to the default order. Print Print currently browsed table data Print currently browsed table data. Print selection if more than one cell is selected. Ctrl+P Refresh Refresh the data in the selected table This button refreshes the data in the currently selected table. Denna knapp uppdaterar datat i vald tabell. F5 Find in cells Open the find tool bar which allows you to search for values in the table view below. Bold Fet Ctrl+B Italic Kursiv Underline Understrykning Ctrl+U Align Right Align Left Center Horizontally Justify Edit Conditional Formats... Edit conditional formats for the current column Clear Format Clear All Formats Clear all cell formatting from selected cells and all conditional formats from selected columns Font Color Background Color Toggle Format Toolbar Show/hide format toolbar This button shows or hides the formatting toolbar of the Data Browser Select column Ctrl+Space Replace text in cells Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally Filter in any column Ctrl+R %n row(s) , %n column(s) . Sum: %1; Average: %2; Min: %3; Max: %4 Conditional formats for "%1" determining row count... Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Delete Records Duplicate records Duplicate record Ctrl+" Adjust rows to contents Error deleting record: %1 Fel när post skulle tas bort: %1 Please select a record first Välj en post först Please choose a new encoding for all tables. Please choose a new encoding for this table. %1 Leave the field empty for using the database encoding. This encoding is either not valid or not supported. %1 replacement(s) made. Copy column name Copy the database table column name to your clipboard New Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) TableBrowserDock New Data Browser Rename Data Browser Close Data Browser Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. VacuumDialog Compact Database Komprimera databas Warning: Compacting the database will commit all of your changes. Please select the databases to co&mpact: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_tr.ts000066400000000000000000013471551463772530400252420ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite SQLite DB Browser Hakkında Version Versiyon <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Yeni Kayıt Ekle Enter values for the new record considering constraints. Fields in bold are mandatory. Yeni kayıt için kısıtlamaları göz önüne alarak yeni deÄŸerleri giriniz. Kalın vurgulu alanlar zorunludur. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. DeÄŸer sütununda, isim sütunuyla belirtilen alan için deÄŸer belirtebilirsiniz. Tip sütunu alanın tipini belirtir. Varsayılan deÄŸerler NULL ile aynı stilde görüntülenir. Name İsim Type Tip Value DeÄŸer Values to insert. Pre-filled default values are inserted automatically unless they are changed. Eklenecek deÄŸerler. Varsayılan olarak doldurulmuÅŸ deÄŸerler, deÄŸiÅŸtirilmedikleri takdirde otomatik olarak ekleneceklerdir. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. Üstteki bölümdeki deÄŸerleri deÄŸiÅŸtirdiÄŸinizde, yeni kaydı eklemek için kullanılacak sorgu burada görüntülenir. Kaydet butonuna basmadan önce manuel olarak bu sorguyu düzenleyebilirsiniz. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html> <head /> <body> <p> <span style=" font-weight:600;">Kaydet</span> butonu yeni kaydı eklemek için ilgili SQL ifadesini veritabanına gönderir. </p> <p> <span style=" font-weight:600;">Varsayılanları Yükle</span> butonu <span style=" font-weight:600;">DeÄŸer</span> sütunundakileri varsayılanlarına yükler. </p> <p> <span style=" font-weight:600;">İptal</span> butonu sorguyu çalıştırmadan bu pencereyi kapatır. </p> </body> </html> Auto-increment Otomatik-Artan Unique constraint Benzersiz kısıtı Check constraint: %1 Kısıtlamayı kontrol et: %1 Foreign key: %1 Yabancı anahatar: %1 Default value: %1 Varsayılan deÄŸer: %1 Error adding record. Message from database engine: %1 Kayıt eklenirken hata oluÅŸtu. Veritabanı motoru mesajı: %1 Are you sure you want to restore all the entered values to their defaults? Girilen bütün deÄŸerleri varsayılanlarına döndürmek istediÄŸinize emin misiniz? Application Possible command line arguments: Muhtemel komut satırı argümanları: The user settings file location is replaced with the argument value instead of the environment variable value. Ignored environment variable (DB4S_SETTINGS_FILE) value: The file %1 does not exist %1 dosyası mevcut deÄŸil Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Browse this table, or use it as target of a data import Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The -S/--settings option requires an argument. The option is ignored. The -o/--option and -O/--save-option options require an argument in the form group/setting=value -o/--option ve -O/--save-option opsiyonları grup/ayar=deÄŸer formatında bir argüman gerektirir Invalid option/non-existent file: %1 Geçersiz seçenek veya mevcut olmayan dosya: %1 SQLite Version SQLite Versiyonu SQLCipher Version %1 (based on SQLite %2) DB Browser for SQLite Version %1. Last commit hash when built: %1 Built for %1, running on %2 %1 için derlendi, %2 üzerinde çalışıyor Qt Version %1 CipherDialog SQLCipher encryption SQLCipher ÅŸifrelemesi &Password &Parola &Reenter password Pa&rolayı tekrar girin Encr&yption settings Åžifreleme A&yarları SQLCipher &3 defaults SQLCipher &3 varsayılanları SQLCipher &4 defaults SQLCipher &4 varsayılanları Custo&m &Özel Page si&ze &Sayfa boyutu &KDF iterations &KDF yinelemeleri HMAC algorithm HMAC algoritması KDF algorithm KDF algoritması Plaintext Header Size Düz Metin Üstbilgi Boyutu Passphrase Parola Raw key Ham anahtar Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Lütfen veritabanını ÅŸifrelemek için anahtar ayarlayın. Unutmayın, bunun dışında isteÄŸe baÄŸlı yapacağınız herhangi deÄŸiÅŸikliklerde, veritabanı dosyasını her açtığınızda ÅŸifrenizi yeniden girmeniz gerekecektir. Åžifrelemeyi devre dışı bırakmak için parola alanını boÅŸ bırakınız. Åžifreleme iÅŸlemi biraz zaman alabilir ve bu iÅŸlemi yapmadan önce veritabanınızın yedeÄŸini almalısınız! KaydedilmemiÅŸ deÄŸiÅŸiklikler ÅŸifreniz deÄŸiÅŸtirilmeden önce kaydedilir. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Lütfen veritabanınızı ÅŸifrelemek için kullandığınız anahtarı giriniz. Bu veritabanı için herhangi bir baÅŸka ayar daha yapılmışsa, bu bilgileri de saÄŸlamalısınız. ColumnDisplayFormatDialog Choose display format Görüntüleme formatını seçiniz Display format Görüntüleme formatı Choose a display format for the column '%1' which is applied to each value prior to showing it. '%1' sütunu için görüntülemeden önce uygulanacak bir görüntüleme formatı seçin. Default Varsayılan Decimal number Ondalık sayı Exponent notation Üslü gösterim Hex blob Onaltılık ikili veri Hex number Onaltılık sayı Apple NSDate to date Apple NSDate tipinden tarih tipine Java epoch (milliseconds) to date Java epoch (milisaniye) tipinden tarih tipine .NET DateTime.Ticks to date Julian day to date Julian day tipinden tarih tipine Unix epoch to local time Unix epoch tipinden yerel zaman tipine WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy dd/mm/yyyy tarih formatı Lower case Küçük harf Binary GUID to text SpatiaLite Geometry to SVG Custom display format must contain a function call applied to %1 Özel görüntüleme formatı, %1 için uygulanan fonksiyon çaÄŸrısı içermelidir Error in custom display format. Message from database engine: %1 Özel görüntüleme formatınde hata oluÅŸtu. Veritabanı motoru mesajı: %1 Custom display format must return only one column but it returned %1. Özel görüntüleme formatı sadece bir sütun döndürmeli: %1. Octal number Sekizlik sayı Round number Küsüratsız sayı Unix epoch to date Unix epoch tipinden tarih tipine Upper case Büyük harf Windows DATE to date Windows DATE tipinden tarih tipine Custom Özel CondFormatManager Conditional Format Manager KoÅŸullu Biçim Yöneticisi This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Bu iletiÅŸim kutusu koÅŸullu biçimler oluÅŸturmaya ve düzenlemeye izin verir. Her hücre stili, hücre verisi için ilk saÄŸlanan koÅŸul tarafından seçilecektir. KoÅŸullu biçimler yukarı ve aÅŸağı taşınabilir, üst sıralardakiler alt sıralardakilere göre önceliklidir. KoÅŸullar için sözdizimi, filtreler ile aynıdır ve boÅŸ koÅŸullar tüm hücreler için geçerlidir. Add new conditional format Yeni koÅŸullu biçim oluÅŸtur &Add &Ekle Remove selected conditional format Seçilen koÅŸullu biçimi sil &Remove &Sil Move selected conditional format up Seçilen koÅŸullu biçimi yukarı taşı Move &up Y&ukarı taşı Move selected conditional format down Seçilen koÅŸullu biçimi aÅŸağı taşı Move &down AÅŸağı &Taşı Foreground Ön plan Text color Yazı rengi Background Arka plan Background color Arka plan rengi Font Yazı tipi Size Boyut Bold Kalın Italic İtalik Underline Altı çizili Alignment Hizalama Condition KoÅŸul Click to select color Renk seçmek için tıklayın Are you sure you want to clear all the conditional formats of this field? Bu alanın tüm koÅŸullu biçimlerini silmek istediÄŸinizden emin misiniz? DBBrowserDB Please specify the database name under which you want to access the attached database Lütfen veritabanının ismini eriÅŸmek istediÄŸiniz baÄŸlı veritabanının altında belirtin Invalid file format Geçersiz dosya formatı Do you want to save the changes made to the database file %1? %1 veritabanı dosyasında yaptığınız deÄŸiÅŸiklikleri kaydetmek istiyor musunuz? Exporting database to SQL file... veritabanı, SQL dosyası olarak dışa aktarılıyor... Cancel İptal Executing SQL... SQL yürütülüyor... Action cancelled. İşlem iptal edildi. Do you really want to close this temporary database? All data will be lost. Gerçekten geçici veritabanını kapatmak istiyor musunuz? Bütün veriler kaybedilecek. Database didn't close correctly, probably still busy Veritabanı doÄŸru bir ÅŸekilde kapatılamadı, muhtemelen hâlâ kullanımda Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: Veritabanı ÅŸu anda meÅŸgul: Do you want to abort that other operation? DiÄŸer iÅŸlemi iptal etmek istiyor musunuz? No database file opened Hiçbir veritabanı dosyası açılmamış Error in statement #%1: %2. Aborting execution%3. Belirtilen ifadede hata oluÅŸtu: #%1: %2 Yürütme durduruluyor %3. and rolling back ve iÅŸlem geri alınıyor didn't receive any output from %1 %1 sorgusundan herhangi bir çıktı alınamadı could not execute command: %1 komut iÅŸletilemedi: %1 Cannot delete this object Bu obje silinemiyor Cannot set data on this object Bu objeye veri atanamıyor A table with the name '%1' already exists in schema '%2'. '%2' ÅŸemasında '%1' isimli tablo zaten mevcut. No table with name '%1' exists in schema '%2'. '%2' ÅŸeması içerisinde '%1' isminde bir tablo yok. Cannot find column %1. %1 sütunu bulunamadı. Creating savepoint failed. DB says: %1 Kayıt noktası oluÅŸturulamadı. Veritabanı mesajı: %1 Renaming the column failed. DB says: %1 Sütun yeniden adlandırılamadı. Veritabanı motoru mesajı: %1 Releasing savepoint failed. DB says: %1 Kayıt noktası serbest bırakılamadı. Veritabanı motoru mesajı: %1 Creating new table failed. DB says: %1 Veri tabanı oluÅŸturulamadı. Veritabanı mesajı: %1 Copying data to new table failed. DB says: %1 Yeni tabloya veri kopyalanamadı. Veritabanı mesajı: %1 Deleting old table failed. DB says: %1 Eski tablolar silinemedi: Veritabanı mesajı: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 '%1' tablosu '%2' olarak adlandırılırken hata oluÅŸtu. Veritabanı motoru mesajı: %3 could not get list of db objects: %1 veritabanı objelerinin listesi alınamadı: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Bu tabloyla iliÅŸkili bazı objelerin restore iÅŸlemi baÅŸarısız. Bu hata büyük olasılıkla sütunların isminin deÄŸiÅŸimden kaynaklanıyor. SQL sorgusunu elle düzeltmek ve yürütmek isterseniz: could not get list of databases: %1 veri tabanı listesi alınamadı: %1 Error loading extension: %1 Eklenti yüklenirken hata oluÅŸtu: %1 Error loading built-in extension: %1 could not get column information sütun bilgisi alınamadı Error setting pragma %1 to %2: %3 Belirtilen pragma ayarlanırken hata oluÅŸtu: %1 > %2: %3 File not found. Dosya bulunamadı. DbStructureModel Name İsim Object Obje Type Tip Schema Åžema Database Veritabanı Browsables Görüntülenebilir olanlar All Tümü Temporary Geçici Tables (%1) Tablolar (%1) Indices (%1) İndisler (%1) Views (%1) Görünümler (%1) Triggers (%1) Tetikleyiciler (%1) EditDialog Edit database cell Veritabanı hücresini düzenle Mode: Mod: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. Bu, hücre düzenleyicisi için desteklenen modların listesidir. Geçerli hücrenin verilerini görüntülemek veya düzenlemek için bir mod seçin. RTL Text SaÄŸdan Sola Okunan Metin Image Görüntü JSON JSON XML XML Evaluation Automatically adjust the editor mode to the loaded data type Düzenleyici modunu otomatik olarak yüklenen veri tipine ayarlar This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Bu onay kutusu, editör modunun otomatik olarak deÄŸiÅŸtirilmesini etkinleÅŸtirir veya devre dışı bırakır. Bu kutucuk iÅŸaretliyken, yeni bir hücre seçildiÄŸinde veya yeni veriler içe aktarıldığında, mod algılanan veri türüne göre ayarlanır. Daha sonra editör modunu manuel olarak deÄŸiÅŸtirebilirsiniz. Hücreler arasında hareket ederken bu manuel modu korumak isterseniz, kutucuÄŸun iÅŸaretini kaldırın. Auto-switch Otomatik geçiÅŸ This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Qt editör, varsayılan metin editörü tarafından desteklenmeyen saÄŸdan sola okunan dillde yazılmış betikleri için kullanılır. Identification of the cell currently in the editor Type and size of data currently in table Open preview dialog for printing the data currently stored in the cell Åžu anda hücrede saklanan veriyi yazdırmak için önizleme penceresini aç Auto-format: pretty print on loading, compact on saving. Otomatik format: yüklenirken aÅŸamasında kaliteli baskı, kayıt açısından da tasarrufludur. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. EtkinleÅŸtirildiÄŸinde, otomatik biçimlendirme özelliÄŸi yükleme sırasında verileri biçimlendirir, metni satırlara böler ve maksimum okunabilirlik için girintili yapar. Veri kaydederken otomatik biçimlendirme özelliÄŸi, satır sonu karakterlerini ve gereksiz boÅŸlukları kaldırarak verileri sıkıştırır. Word Wrap Kelime Kaydırma Wrap lines on word boundaries Kelime sınırlarında kelimeyi kaydırır Open in default application or browser Varsayılan program veya görüntüleyicide aç Open in application Uygualamada aç The value is interpreted as a file or URL and opened in the default application or web browser. DeÄŸe,r bir dosya veya URL olarak yorumlanır ve varsayılan uygulamada veya web tarayıcısında açılır. Save file reference... Dosya referansını kaydet... Save reference to file Referansı dosyaya kaydet Open in external application Harici bir programda aç Autoformat Otomatik format &Export... D&ışa aktar... &Import... &İçe aktar... Import from file Dosyadan içe aktar Opens a file dialog used to import any kind of data to this database cell. Veritabanı hücresine herhangi bir tipte veri yüklemek için bir dosya iletiÅŸim kutusu açar. Export to file Dosyaya aktar Opens a file dialog used to export the contents of this database cell to a file. Veritabanı hücresinin içeriÄŸini bir dosyaya aktarmak için kullanılan bir dosya iletiÅŸim kutusu açar. Print... Yazdır... Ctrl+P Open preview dialog for printing displayed text Görüntülenen yazıyı yazdırmak için önizleme penceresini aç Copy Hex and ASCII Onaltılık ve ASCII deÄŸerini kopyala Copy selected hexadecimal and ASCII columns to the clipboard Seçilen onaltılık ve ASCII sütunlarını panoya kopyala Ctrl+Shift+C Set as &NULL &NULL olarak ayarla Apply data to cell Veriyi hücreye uygula This button saves the changes performed in the cell editor to the database cell. Bu buton, hücre editöründe yapılan deÄŸiÅŸiklikleri veritabanı hücresine kaydeder. Apply Uygula Text Metin Binary İkili Erases the contents of the cell Hücre içeriÄŸini siler This area displays information about the data present in this database cell Bu alan veritabanı hücresinin içindeki içerik hakkında bilgileri görüntüler Choose a filename to export data Veriyi dışa aktarmak için dosya ismi seçiniz Image data can't be viewed in this mode. Imaj verisi bu modda görüntülenemiyor. The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Unsaved data in the cell editor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. Try switching to Image or Binary mode. Görüntü veya İkili mod arasında geçiÅŸ yapın. Binary data can't be viewed in this mode. İkili veri bu modda görüntülenemiyor. Try switching to Binary mode. İkili veri moduna geçmeyi deneyin. Image files (%1) Görüntü dosyaları (%1) Binary files (*.bin) İkili dosyalar (*.bin) Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) Choose a file to import İçe aktarmak için dosya seçiniz %1 Image %1 imajı Invalid data for this mode Bu mod için geçersiz veri The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? Hücre geçersiz %1 verisi içeriyor. Sebep: %2. Bu deÄŸiÅŸikliÄŸi hücreye gerçekten uygulamak istiyor musunuz? Couldn't save file: %1. Dosya kaydedilemedi: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. EditIndexDialog &Name &İsim Order Sırala &Table &Tablo Edit Index Schema Index Åžemasını Düzenle &Unique Benzersi&z For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Index'i tablonun yalnızca bir bölümüyle sınırlamak için, burada tablonun dizine alınması gereken kısmını seçen bir WHERE deyimi belirtebilirsiniz Partial inde&x clause Kısmi inde&x hükmü Colu&mns Sütu&nlar Table column Tablo sütunu Type Tip Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Index için yeni bir ifade sütunu ekleyin. İfade sütunları, sütun adları deÄŸil SQL ifadesi içerir. Index column Index sütunu Deleting the old index failed: %1 Eski index silinemedi: %1 Creating the index failed: %1 İndeks oluÅŸturma hatası: %1 EditTableDialog Edit table definition Tablo tanımını düzenle Table Tablo Advanced GeliÅŸmiÅŸ Without Rowid Satır ID(Rowid) Kullanma Database sche&ma Veritabanı &Åžeması Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Fields Alanlar Add Ekle Remove Sil Move to top En yukarı taşı Move up Yukarı taşı Move down AÅŸağı taşı Move to bottom En aÅŸağı taşı Name İsim Type Tip NN NN Not null NULL Olamaz PK Birincil Anahtar <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> AI Otomatik Arttırma Autoincrement Otomatik Arttırma U Benzersiz Unique Benzersiz Default Varsayılan Default value Varsayılan deÄŸer Check Kontrol Check constraint Kısıtlama Kontrol Collation KarşılaÅŸtırma Foreign Key Yabancı Anahtar <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Index Constraints Add constraint Kısıt ekle Remove constraint Kısıtı kaldır Columns Sütunlar SQL SQL Foreign Keys References Check Constraints <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html> <head /> <body> <p> <span style=" font-weight:600; color:#ff0000;">Uyarı: </span>Bu tablo tanımında ayrıştırıcının tam olarak anlayamadığı bir ÅŸey var. Bu tabloyu deÄŸiÅŸtirmek ve kaydetmek sorunlara neden olabilir. </p> </body> </html> Primary Key Birincil Anahtar Add a primary key constraint Birinci anahtar kısıtlaması ekle Add a unique constraint Benzersiz kısıtı ekle There can only be one primary key for each table. Please modify the existing primary key instead. Her tabloda yalnızca bir birincil anahtar bulunabilir. Mevcut birincil anahtarı düzenlemeyi denedin. Error creating table. Message from database engine: %1 Tablo oluÅŸturma hatası. veritabanı motorunun mesajı: %1 There already is a field with that name. Please rename it first or choose a different name for this field. Bu isme sahip alan zaten var. Lütfen bu alan için farklı bir isim kullanın veya aynı isme sahip alanı yeniden adlandırın. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. Tablonuzun en az bir satırında boÅŸ bırakılmış alan var. Bu sebeple bu özelliÄŸi etkinleÅŸtirmek imkansız. Lütfen ilk önce tablonuzdaki veriyi deÄŸiÅŸtirin. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. Tablonuzun en az bir satırında tamsayı dışında deÄŸer içeren alan var. Bu sebeÄŸle otomatik arttır özelliÄŸini etkinleÅŸtirmek imkansız. Lütfen ilk önce tablonuzdaki veriyi deÄŸiÅŸtirin. Column '%1' has duplicate data. '%1' sütununda yinelenen veriler var. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Åžu anda 'Benzersiz' kısıtı eklenmesi imkansız.'Benzersiz' kısıtını ekleyebilmek için lütfen yinelenen deÄŸerleri silin. Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Bu sütun%1 tablosundaki yabancı bir anahtar tarafından referans alınıyor, bu nedenle adı deÄŸiÅŸtirilemez. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Gerçekten '%1' alanını silmek istediÄŸinize emin misiniz? Bu alanda mevcut bütün verilerinizi kaybedeceksiniz. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Lütfen 'Satır ID(Rowid) Kullanma' özelliÄŸini etkinleÅŸtirmek için öncelikle aÅŸağıdaki ölçütleri karşılayan alan ekleyin: - Birincil anahtar ayarlayın - Otomatik arttır ayarını devre dışı bırakın ExportDataDialog Export data as CSV Veriyi CSV olarak dışa aktar Tab&le(s) Tab&lolar Colu&mn names in first line Sütu&n isimleri ilk satırda Fie&ld separator &Alan ayracı , , ; ; Tab Tab karakteri | | Other DiÄŸer &Quote character &Tırnak karakteri " " ' ' New line characters Yeni satır karakterleri Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print Düzenli baskı Could not open output file: %1 OluÅŸturulan dosya açılamadı: %1 Choose a filename to export data Verileri dışarı aktarmak için dosya ismi seçiniz Export data as JSON Veriyi JSON olarak dışa aktar exporting CSV CSV dışa aktarılıyor Error while writing the file '%1': %2 exporting JSON JSON dışa aktarılıyor Please select at least 1 table. Lütfen en az 1 tablo seçiniz. Choose a directory Dizin seçiniz Export completed. Dışa aktarma tamamlandı. Export finished with errors. ExportSqlDialog Export SQL... SQL dosyasını dışa aktar... Tab&le(s) Tablo&lar Select All Tümünü Seç Deselect All Tüm Seçimi İptal Et &Options &Seçenekler Keep column names in INSERT INTO INSERT ve INTO komutlarında sütun isimlerini tut Multiple rows (VALUES) per INSERT statement Tek INSERT ifadesi için çok satırlı (VALUES) ifade Export everything Her ÅŸeyi dışa aktar Export data only Sadece veriyi dışa aktar Keep original CREATE statements Keep old schema (CREATE TABLE IF NOT EXISTS) Eski ÅŸemayı tut (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) Eski ÅŸemanın üzerine yaz (DROP TABLE, then CREATE TABLE) Export schema only Sadece ÅŸemayı dışa aktar Please select at least one table. Lütfen en az bir tablo seçiniz. Choose a filename to export Dışa aktarmak için dosya ismi seçiniz Export completed. Dışa aktarma tamamlandı. Export cancelled or failed. Dışa aktarma iptal edildi veya baÅŸarısız. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Bul... Find and Replace... Bul ve DeÄŸiÅŸtir... Print... Yazdır... ExtendedTableWidget Use as Exact Filter Tam Filtre Olarak Kullan Containing İçersin Not containing İçermesin Not equal to EÅŸit deÄŸil Greater than Büyüktür Less than Küçüktür Greater or equal Büyük eÅŸit Less or equal Küçük eÅŸit Between this and... Åžunların arasında... Regular expression Düzenli ifadeler (RegEx) Edit Conditional Formats... KoÅŸullu Biçimleri Düzenle... Set to NULL NULL olarak ayarla Cut Copy Kopyala Copy with Headers Üst BaÅŸlıklarla Kopyala Copy as SQL SQL olarak Kopyala Paste Yapıştır Print... Yazdır... Use in Filter Expression Filtre İfadesinde Kullan Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? Pano içeriÄŸi seçilen aralıktan daha büyük. Yine de eklemek istiyor musunuz? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p> Tüm veriler yüklenmedi. <b>Tüm satırları seçmeden önce tüm verileri yüklemek istiyor musunuz?</b> </p> <p></p> <p> <b>Hayır</b> olarak cevaplamak, tüm verileri yüklemeyecek ve seçim iÅŸlemini uygulanmayacak. <br /> <b>Evet</b> seçeneÄŸi biraz zaman alabilir ama seçim iÅŸlemini gerçekleÅŸtirecektir. </p> Uyarı: Tüm verilerin yüklenmesi büyük tablolar için büyük miktarda bellek gerektirebilir. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. Seçim NULL olarak ayarlanamıyor. %1 sütununda NOT NULL kısıtlaması var. FileExtensionManager File Extension Manager Dosya Uzantı Yöneticisi &Up &Yukarı &Down &AÅŸağı &Add &Ekle &Remove &Sil Description Açıklama Extensions Uzantılar *.extension *.uzantı FilterLineEdit Filter Filtre These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Bu giriÅŸ alanları, seçili tabloda hızlı filtreler gerçekleÅŸtirmenizi saÄŸlar. Varsayılan olarak, metin içeren satırlar filtrelenir. Ayrıca aÅŸağıdaki operatörler de destekleniyor: % Joker > Büyüktür < Küçüktür >= Büyük eÅŸit <= Küçük eÅŸit = EÅŸittir <> EÅŸit deÄŸil x~y Aralık: deÄŸerler x ve y arasında /regexp/ Kurallı ifadelerle(RegExp) eÅŸleÅŸen deÄŸerler Clear All Conditional Formats Tüm KoÅŸullu Biçimleri Temizle Use for Conditional Format KoÅŸullu Biçim için Kullan Edit Conditional Formats... KoÅŸullu Biçimleri Düzenle... Set Filter Expression Filtre İfadesi Ayarla What's This? Bu nedir? Is NULL NULL mu Is not NULL NULL deÄŸil mi Is empty BoÅŸ mu Is not empty BoÅŸ deÄŸil mi Not containing... İçermiyor... Equal to... Åžuna eÅŸit... Not equal to... Åžuna eÅŸit deÄŸil... Greater than... Büyüktür... Less than... Küçüktür... Greater or equal... Büyük eÅŸit... Less or equal... Küçük eÅŸit... In range... Aralıkta mı... Regular expression... Düzenli ifade (RegEx)... FindReplaceDialog Find and Replace Bul ve DeÄŸiÅŸtir Fi&nd text: &Aranan Metin: Re&place with: Åžununla d&eÄŸiÅŸtir: Match &exact case Büyük kü&çük harfe duyarlı Match &only whole words Kelimenin ta&mamını eÅŸleÅŸtir When enabled, the search continues from the other end when it reaches one end of the page EtkinleÅŸtirildiÄŸinde, arama sayfanın bir ucuna ulaÅŸtığında diÄŸer uçtan devam eder &Wrap around Ba&ÅŸa dön When set, the search goes backwards from cursor position, otherwise it goes forward Ayarlandığında, arama imleç konumundan geriye doÄŸru gider, aksi takdirde ileri gider Search &backwards Geri&ye doÄŸru ara <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>İşaretlendiÄŸinde, girilen desen yalnızca geçerli seçimde aranır.</p></body></html> &Selection only Sadece se&çimde ara <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html> <head /> <body> <p> İşaretlendiÄŸinde, girilen desen UNIX düzenli ifadesi olarak yorumlanır. <a href="https://en.wikibooks.org/wiki/Regular_Expressions" >Wikibooks</a > üzerinden düzenli ifadeleri inceleyebilirsiniz. </p> </body> </html> Use regular e&xpressions Düzenli ifadeleri &kullan Find the next occurrence from the cursor position and in the direction set by "Search backwards" İmleç konumundan itibaren belirtilen yönde bir sonraki eÅŸleÅŸmeyi bulur &Find Next Sonrakini &Bul F3 &Replace &DeÄŸiÅŸtir Highlight all the occurrences of the text in the page EÅŸleÅŸen tüm kelimeleri vurgula F&ind All Tüm&ünü Bul Replace all the occurrences of the text in the page Sayfadaki bulunan metinlerin tümünü deÄŸiÅŸtir Replace &All &Tümünü DeÄŸiÅŸtir The searched text was not found Aranan metin bulunamadı The searched text was not found. The searched text was not found. The searched text was found one time. Aranan metin bir kez bulundu. The searched text was found %1 times. Aranan metin %1 kez bulundu. The searched text was replaced one time. Aranan metin bir kez deÄŸiÅŸtirildi. The searched text was replaced %1 times. Aranan metin %1 kez deÄŸiÅŸtirildi. ForeignKeyEditor &Reset &Sıfırla Foreign key clauses (ON UPDATE, ON DELETE etc.) Yabancı anahtar hükümleri (ON UPDATE, ON DELETE vb.) ImageViewer Image Viewer Reset the scaling to match the original size of the image. Set the scaling to match the size of the viewport. Print... Yazdır... Open preview dialog for printing displayed image Görüntülenen resmi yazdırmak için önizleme penceresini aç Ctrl+P ImportCsvDialog Import CSV file CSV dosyasını içe aktar Table na&me Tablo İs&mi &Column names in first line İlk satır &sütun isimleri içeriyor Field &separator Alan &ayracı , , ; ; Tab Tab karakteri | | Other DiÄŸer &Quote character &Tırnak karakteri Other (printable) DiÄŸer (yazdırılabilir) Other (code) DiÄŸer (Kod) " " ' ' &Encoding &Kodlama UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? Alanlar biçimlendirilsin mi? Separate tables Tablolar ayrılmış Advanced GeliÅŸmiÅŸ When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. CSV dosyasından boÅŸ bir deÄŸer alındığında, sütunun varsayılan deÄŸeri kullanılır. Varsayılan deÄŸer yerine boÅŸ bir deÄŸer eklemek için bu seçeneÄŸi etkinleÅŸtirin. Ignore default &values &Varsayılan deÄŸerleri yoksay Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Varsayılan deÄŸeri olmayan NOT NULL kısıtına sahip bir sütuna, boÅŸ bir deÄŸer içe aktarmaya çalışırken içe aktarmayı durdurmak için bu seçeneÄŸi etkinleÅŸtirin. Fail on missing values Eksik deÄŸerde iÅŸlemi durdur Disable data type detection Veri tipi algılamayı devre dışı bırak Disable the automatic data type detection when creating a new table. Yeni bir tablo oluÅŸtururken otomatik veri tipi algılamayı devre dışı bırakın. Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Birincil anahtar, benzersiz kısıtı veya benzersiz index kısıtına sahip mevcut bir tablo içe aktarırken çakışma meydana gelebilir. Bu seçenek, bu durum için bir strateji seçmenize olanak tanır: Varsayılan olarak iÅŸlem iptal edilir ve geri alınır, ancak isterseniz çakışmaları yoksayıp içe aktarmazsınız veya yeni satırları mevcut olanlarla deÄŸiÅŸtirebilirsiniz. Abort import İçe aktarmayı iptal et Ignore row Satırı yoksay Replace existing row Varolan kaydı deÄŸiÅŸtir Conflict strategy Çakışma stratejisi Deselect All Tüm seçimi iptal et Match Similar Benzerleri EÅŸleÅŸtir Select All Tümünü Seç There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. '%1' isminde bir tablo zaten var, var olan bir tablo için içe aktarma, yalnızca sütun sayıları eÅŸitse mümkün olabilir. There is already a table named '%1'. Do you want to import the data into it? '%1' adında bir tablo zaten var. Verileri içe aktarmak istiyor musunuz? Creating restore point failed: %1 Geri yükleme noktası oluÅŸturma baÅŸarısız: %1 Creating the table failed: %1 Tablo oluÅŸturma baÅŸarısız: %1 importing CSV CSV İçe Aktarma Could not prepare INSERT statement: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. '%1' dosyasını içe aktarmak %2ms sürdü. %3ms satır fonksiyonunda harcandı. Inserting row failed: %1 Satır ekleme baÅŸarısız: %1 MainWindow DB Browser for SQLite SQLite DB Browser toolBar1 toolBar1 Opens the SQLCipher FAQ in a browser window SQLCipher Hakkında SSS bölümünü tarayıcı penceresinde açar Export one or more table(s) to a JSON file Bir veya daha fazla tabloyu JSON dosyası olarak dışa aktarın Open an existing database file in read only mode Mevcut bir veritabanı dosyasını salt okunur modda açar &File &Dosya &Import &İçe Aktar &Export &Dışa Aktar &Edit Düz&enle &View &Görünüm &Help &Yardım DB Toolbar Veritabanı Araç ÇubuÄŸu Edit Database &Cell Veritabanı Hü&cresini Düzenle DB Sche&ma Veritabanı Åže&ması &Remote &Uzak Bilgisayar Execute current line Geçerli satırı yürüt This button executes the SQL statement present in the current editor line Bu buton, geçerli editör satırında bulunan SQL ifadesini yürütür Shift+F5 Sa&ve Project Projeyi &Kaydet User Kullanıcı Application Uygulama &Clear &Temizle &New Database... Ye&ni Veritabanı... Create a new database file Yeni bir veritabanı dosyası oluÅŸtur This option is used to create a new database file. Bu seçenek yeni bir veritabanı dosyası oluÅŸturmak için kullanılır. Ctrl+N &Open Database... &Veritabanı Aç... Open an existing database file Mevcut veritabanı dosyasını aç This option is used to open an existing database file. Bu seçenek mevcut veritabanı dosyasını açmak için kullanılır. Ctrl+O &Close Database Veritabanı &Kapat Ctrl+W Revert database to last saved state Veritabanını en son kaydedilen duruma döndür This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Bu seçenek veritabanını en son kaydedilen durumuna döndürür. Geçerli kayıttan sonra yaptığınız tüm deÄŸiÅŸiklikler kaybolacaktır. Write changes to the database file DeÄŸiÅŸiklikleri veritabanı dosyasına kaydet This option is used to save changes to the database file. Bu seçenek deÄŸiÅŸiklikleri veritabanı dosyasına kaydetmenizi saÄŸlar. Ctrl+S Compact the database file, removing space wasted by deleted records Veritabanı dosyasını geniÅŸletmek, silinen kayıtlardan dolayı meydana gelen boÅŸlukları temizler Compact the database file, removing space wasted by deleted records. Veritabanı dosyasını geniÅŸletmek, silinen kayıtlardan dolayı meydana gelen boÅŸlukları temizler. E&xit &Çıkış Ctrl+Q Import data from an .sql dump text file into a new or existing database. Verileri .sql uzantılı döküm dosyasından varolan veya yeni veritabanına aktarın. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Bu seçenek verileri .sql döküm dosyasından varolan veya yeni veritabanına aktarmanıza olanak saÄŸlar. SQL dosyaları MySQL ve PostgreSQL dahil olmak üzere birçok veritabanı motorları tarafından oluÅŸtururlar. Open a wizard that lets you import data from a comma separated text file into a database table. Virgülle ayrılmış metin dosyalarını veritabanınızın içine aktarmanızı saÄŸlayan sihirbazı açar. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Virgülle ayrılmış metin dosyalarını veritabanınızın içine aktarmanızı saÄŸlayan sihirbazı açar. CSV dosyaları çoÄŸu veritabanı motorları ve elektronik tablo uygulamaları tarafından oluÅŸtururlar. Export a database to a .sql dump text file. Veritabanını .sql döküm dosyası olarak dışa aktar. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Bu seçenek veritabanını .sql döküm dosyası olarak dışa aktarmanızı saÄŸlar. SQL döküm dosyaları veritabanını, MySQL ve PostgreSQL dahil birçok veritabanı motorunda yeniden oluÅŸturmak için gereken verilerin tümünü içerir. Export a database table as a comma separated text file. Veritabanı tablosunu virgülle ayrılmış metin dosyası olarak dışa aktar. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. Veritabanını virgülle ayrılmış metin dosyası olarak diÄŸer veritabanı veya elektronik tablo uygulamalarına aktarmaya hazır olacak ÅŸekilde dışa aktarın. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Tablo OluÅŸturma sihirbazı, veritabanı için alanlarını ve ismini ayarlayabileceÄŸiniz, yeni bir tablo oluÅŸturmanızı saÄŸlar Delete Table Tabloyu Sil Open the Delete Table wizard, where you can select a database table to be dropped. Tablo Silme sihirbazı, seçtiÄŸiniz tabloları silmenizi saÄŸlar. Open the Create Index wizard, where it is possible to define a new index on an existing database table. İndeks OluÅŸturma sihirbazı, varolan veritabanı tablosuna yeni indeks tanımlamanıza olanak saÄŸlar. &Preferences... &Tercihler... Open the preferences window. Tercihler penceresini açar. &DB Toolbar &Veritabanı Araç ÇubuÄŸu Shows or hides the Database toolbar. Veritabanı araç çubuÄŸunu gösterir veya gizler. Shift+F1 &Recently opened En son açılanla&r Ctrl+T This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Bu, açılan veritabanının yapısıdır. SQL ifadelerini bir nesne satırından sürükleyip baÅŸka uygulamalara veya 'DB Browser for SQLite programının baÅŸka bir penceresine bırakabilirsiniz. Un/comment block of SQL code Kod bloÄŸunu yorum satırına dönüştür/yorum satırını iptal et Un/comment block Yorum satırına dönüştür/yorum satırını iptal et Comment or uncomment current line or selected block of code Geçerli satırı veya kod bloÄŸunu, yorum satırına dönüştür veya yorum satırını iptal et Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Geçerli satırı veya kod bloÄŸunu, yorum satırına dönüştür veya yorum satırını iptal et. Hiç seçim yoksa tüm bloklar ilk satır baz alınarak deÄŸiÅŸtirilir. Ctrl+/ Stop SQL execution SQL yürütmesini durdur Stop execution Yürütmeyi durdur Stop the currently running SQL script Åžu anda çalışan SQL betiÄŸini durdur Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. Uyarı: Bu pragma okunamaz ve bu deÄŸer çıkartıldı. Bu pragmayı yazmak, bir SQLite eklentisi tarafından saÄŸlanan yeniden tanımlanmış bir LIKE'nin üzerine yazabilir. Too&ls Ara&çlar SQL &Log SQL &Günlüğü Show S&QL submitted by Åžuna ait S&QL'i göster Error Log Hata Günlüğü This button clears the contents of the SQL logs Bu buton SQL günlüğünün içeriÄŸini temizler This panel lets you examine a log of all SQL commands issued by the application or by yourself Bu panel, uygulama veya kendiniz tarafından verilen tüm SQL komutlarının bir günlüğünü incelemenizi saÄŸlar &Plot &Çizim This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Bu, açılan veritabanının yapısıdır. Birden çok nesne adını Ad sütunundan sürükleyip SQL editörüne bırakabilir ve bırakılan adların özelliklerini baÄŸlam menüsünü kullanarak ayarlayabilirsiniz. Bu, SQL ifadeleri oluÅŸturmanıza yardımcı olacaktır. SQL deyimlerini Åžema sütunundan sürükleyip SQL editörüne veya diÄŸer uygulamalara bırakabilirsiniz. Project Toolbar Proje Araç ÇubuÄŸu Extra DB toolbar Ekstra Veritabanı araç çubuÄŸu Close the current database file Geçerli veritabano dosyasını kapat This button closes the connection to the currently open database file Bu buton, ÅŸu anda açık olan veritabanı dosyasına ait baÄŸlantıyı kapatır Ctrl+F4 &Revert Changes DeÄŸiÅŸiklikleri &Geri Al &Write Changes DeÄŸiÅŸiklikleri &Kaydet Compact &Database... Veriabanını &Sıkıştır... New &tab Execute all/selected SQL Tüm/seçin SQL sorgusunu yürüt This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Bu buton seçili olan SQL ifadesini yürütür. Hiçbir metin seçilmezse, tüm SQL ifadeleri yürütülür. Open SQL file(s) This button opens files containing SQL statements and loads them in new editor tabs &Load Extension... Ek&lenti Yükle... Execute line Tek satır yürüt &Wiki &Wiki F1 Bug &Report... Hata &Raporu... Feature Re&quest... &Özellik Talebi... Web&site Web &Sitesi &Donate on Patreon... &Patreon üzerinden Bağış Yapın... Close Pro&ject Close project and database files and return to the initial state Ctrl+Shift+F4 Detach Database Detach database file attached to the current database connection Open &Project... &Proje Aç... &Attach Database... &Veritabanı Ekle... Add another database file to the current database connection Åžu anki veritabanı baÄŸÄŸlantısına baÅŸka bir veritabanı dosyası ekle This button lets you add another database file to the current database connection Bu buton, geçerli veritabanı baÄŸlantısına baÅŸka bir veritabanı dosyası eklemenizi saÄŸlar &Set Encryption... &Åžifreleme Belirtle... SQLCipher &FAQ SQLCipher &SSS Table(&s) to JSON... Tablodan &JSON dosyasına... Open Data&base Read Only... Salt &Okunur Veritabanı Aç... Ctrl+Shift+O Save results Sonuçları kaydet Save the results view Sonuç görünümünü kaydet This button lets you save the results of the last executed query Bu buton son yürütülen sorgunun sonuçlarını kaydetmenizi saÄŸlar Find text in SQL editor SQL editörünte metin ara Find Bul This button opens the search bar of the editor Bu buton editörün arama çubuÄŸunu açar Ctrl+F Find or replace text in SQL editor SQL editöründe metin bul veya deÄŸiÅŸtir Find or replace Bul veya deÄŸiÅŸtir This button opens the find/replace dialog for the current editor tab Bu buton, geçerli editör sekmesi için bul / deÄŸiÅŸtir iletiÅŸim kutusunu açar Ctrl+H Export to &CSV &CSV dosyası olarak dışa aktar Save as &view &Görünüm olarak kaydet Save as view Görünüm olarak kaydet Browse Table Tabloyu Görüntüle Shows or hides the Project toolbar. Proje araç çubuÄŸunu gösterir veya gizler. &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs E&xecute SQL This has to be equal to the tab title in all the main tabs &Recent Files &New Database &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Ctrl+Shift+T &Save Project This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file Open &Project This button lets you open a DB Browser for SQLite project file Export to &JSON Extra DB Toolbar Ekstra Veritabanı Araç ÇubuÄŸu &Open Database New In-&Memory Database &Yeni Bellek İçi Veritabanı Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Drag && Drop Qualified Names Nitelikli İsimleri Sürükle && Bırak Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Nesneleri sürükleyip düzenleyiciye bırakırken özel isimleri kullanın (örn. "Tablo". "Alan") Drag && Drop Enquoted Names İsimleri Sürükle && Bırak Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor Nesneleri sürükleyip editöre bırakırken çıkış karakter belirleyicilerini kullanın(ör. "Tablo1") kullanın &Integrity Check &Bütünlük Denetimi Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. integrity_check pragmasını açılan veritabanı üzerinde çalıştırır ve 'SQL Kodunu Yürüt' sekmesinde sonuçları döndürür. Bu pragma veritabanının tamamının bütünlüğünü kontrol eder. &Foreign-Key Check &Yabancı anahtar kontrolü Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab Foreign_key_check pragmasını açık veritabanı üzerinde çalıştırır ve 'SQL Kodunu Yürüt' sekmesinde sonuçları döndürür &Quick Integrity Check &Hızlı Bütünlük Testi Run a quick integrity check over the open DB Açık veritabanı üzerinde hızlı bir bütünlük denetimi yapın Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. quick_check pragmasını açık veritabanı üzerinde çalıştırır ve 'SQL Kodunu Yürüt' sekmesinde sonuçları döndürür. Bu komut PRAGMA integrity_check denetiminin çoÄŸunu yapar, ancak çok daha hızlı çalışır. &Optimize &Optimize Attempt to optimize the database Veritabanını optimize etmeyi dene Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Açılan veritabanı üzerinden optimizasyon pragmasını çalıştırır. Bu uygulama gelecekteki sorguların performansını artırmaya yardımcı olabilir. Print Yazdır Print text from current SQL editor tab Geçerli SQL düzenleyici sekmesinden metni yazdırın Open a dialog for printing the text in the current SQL editor tab Geçerli SQL düzenleyici sekmesindeki metni yazdırmak için bir iletiÅŸim kutusu açın Print the structure of the opened database Åžu anda açık olan veritabanı yapısını yazdırın Open a dialog for printing the structure of the opened database Açılan veritabanının yapısını yazdırmak için bir bir iletiÅŸim kutusu açın &Save Project As... Projeyi &Farklı Kaydet... Save the project in a file selected in a dialog Projeyi iletiÅŸim kutusunda seçilen bir dosyaya kaydedin Save A&ll Tümünü &Kaydet Save DB file, project file and opened SQL files Veritabanı dosyasını, proje dosyasını ve açılan SQL dosyalarını kaydedin Ctrl+Shift+S Ctrl+Shift+W Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Refresh Yenile Reload the database structure &Database from SQL file... SQL &dosyasından veritabanı... &Table from CSV file... CSV dosyasından &tablo... &Database to SQL file... Veritabanından SQL &dosyası... &Table(s) as CSV file... &Tablodan CSV dosyası olarak... &Create Table... &Tablo OluÅŸtur... &Delete Table... &Tabloyu Sil... &Modify Table... Tabloyu &Düzenle... Create &Index... &Index OluÅŸtur... W&hat's This? Bu &nedir? &About &İptal This button opens a new tab for the SQL editor Bu buton SQL editörü için yeni bir sekme açar &Execute SQL &SQL kodunu yürüt Save SQL file SQL dosyasını kaydet Ctrl+E Export as CSV file CSV dosyası olarak dışa aktar Export table as comma separated values file Tabloyu virgülle ayrılmış girdiler dosyası olarak dışa aktar Save the current session to a file Geçerli oturumu dosyaya kaydet Load a working session from a file Dosyadan çalışma oturumunu yükle Save SQL file as SQL dosyasını bu ÅŸekilde kaydet This button saves the content of the current SQL editor tab to a file Bu buton geçerli SQL editörü sekmesinin içeriÄŸini bir dosyaya kaydeder &Browse Table &Tabloyu Görüntüle Copy Create statement 'Create' ifadesini kopyala Copy the CREATE statement of the item to the clipboard Objenin 'Create' ifadesini panoya kopyala Ctrl+Return Ctrl+L Ctrl+P Ctrl+D Ctrl+I Encrypted ÅžifrelenmiÅŸ Read only Salt okunur Database file is read only. Editing the database is disabled. Veritabanı salt okunur. Veritabanı düzenleme devre dışı. Database encoding Veritabanı kodlaması Database is encrypted using SQLCipher Veritabanı SQLCipher kullanılırak ÅŸifrelendi Choose a database file Veritabanı dosyasını seçiniz Choose a filename to save under Kaydetmek için dosya ismi seçiniz Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Veritabanı dosyası kaydedilirken hata oluÅŸtu. Bu, veritabanındaki tüm deÄŸiÅŸikliklerin kaydedilmediÄŸi anlamına gelir. Önce aÅŸağıdaki hatayı çözmeniz gerekir. %1 Are you sure you want to undo all changes made to the database file '%1' since the last save? Son kayıttan itibaren '%1' dosyasına yaptığınız deÄŸiÅŸiklikleri geri almak istediÄŸinize emin misiniz? Choose a file to import İçe aktarmak için dosya seçiniz &%1 %2%3 &%1 %2%3 (read only) (salt okunur) Open Database or Project Veritabanı veya Proje Açın Attach Database... Veritabanı Ekle... Import CSV file(s)... CSV dosyalarını içe aktarın... Do you want to save the changes made to SQL tabs in the project file '%1'? SQL sekmelerinde yapılan deÄŸiÅŸiklikleri '%1' proje dosyasına kaydetmek istiyor musunuz? Text files(*.sql *.txt);;All files(*) Metin dosyaları(*.sql *.txt);;Tüm dosyalar(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. İçeri aktarılan verileri tutmak için yeni bir veritabanı dosyası oluÅŸturmak istiyor musunuz? EÄŸer cevabınız hayır ise biz SQL dosyasındaki verileri geçerli veritabanına aktarmaya baÅŸlayacağız. You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Åžu anda SQL sorgularını yürütüyorsunuz. Veritabanının ÅŸimdi kapatılması, muhtemelen veritabanını tutarsız bir durumda bırakarak yürütmeyi durduracaktır. Veritabanını kapatmak istediÄŸinizden emin misiniz? Do you want to save the changes made to the project file '%1'? '%1' proje dosyasında yapılan deÄŸiÅŸiklikleri kaydetmek istiyor musunuz? File %1 already exists. Please choose a different name. %1 dosyası zaten mevcut. Lütfen farklı bir isim seçiniz. Error importing data: %1 Dosya içeri aktarılırken hata oluÅŸtu: %1 Import completed. İçeri aktarma tamamlandı. Delete View Görünümü Sil Modify View Görünümü Düzenle Delete Trigger Tetikleyiciyi Sil Modify Trigger Tetikleyiciyi Düzenle Delete Index İndeksi Sil Modify Index Index'i Düzenle Modify Table Tabloyu Düzenle Do you want to save the changes made to SQL tabs in a new project file? SQL sekmelerinde yapılan deÄŸiÅŸiklikleri yeni bir proje dosyasına kaydetmek istiyor musunuz? Do you want to save the changes made to the SQL file %1? %1 SQL dosyasında yapılan deÄŸiÅŸiklikleri kaydetmek istiyor musunuz? Could not find resource file: %1 Kaynak dosya bulunamadı: %1 Choose a project file to open Açmak için bir proje dosyası seçin Could not open project file for writing. Reason: %1 Proje dosyası yazmaya açılamadı. Nedeni: %1 Busy (%1) MeÅŸgul (%1) Setting PRAGMA values will commit your current transaction. Are you sure? PRAGMA deÄŸerlerini ayarlamak geçerli iÅŸleminizi yürütmeye alacaktır. Bunu yapmak istediÄŸinize emin misiniz? Ctrl+Tab Ctrl+Shift+Tab Clear List Window Layout Reset Window Layout Pencere Düzenini Sıfırla Simplify Window Layout Alt+Shift+0 Dock Windows at Bottom Dock Windows at Left Side Dock Windows at Top The database is currently busy. VerÅŸtabanı ÅŸu anda meÅŸgul. Click here to interrupt the currently running query. Çalışmakta olan sorguyu kesmek için burayı tıklayın. Ctrl+Alt+W Could not open database file. Reason: %1 Veritabanı dosyası açılamadı. Nedeni: %1 In-Memory database Bellek İçi Veritabanı Choose a database file to save under Error while saving the database to the new file. Are you sure you want to delete the table '%1'? All data associated with the table will be lost. '%1' tablosunu silmek istediÄŸinizden emin misiniz? Tabloyla iliÅŸkili tüm veriler kaybedilecektir. Are you sure you want to delete the view '%1'? '%1' görünümünü silmek istediÄŸinizden emin misiniz? Are you sure you want to delete the trigger '%1'? '%1' tetikleyicisini silmek istediÄŸinizden emin misiniz? Are you sure you want to delete the index '%1'? '%1' indexsini silmek istediÄŸinizden emin misiniz? Error: could not delete the table. Hata: tablo silinemedi. Error: could not delete the view. Hata: görünüm silinemedi. Error: could not delete the trigger. Hata: tetikleyici silinemedi. Error: could not delete the index. Hata: index silinemedi. Message from database engine: %1 Veritabanı motorundan mesaj: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Tabloyu düzenlemek için bekleyen tüm deÄŸiÅŸikliklerin ÅŸimdi kaydedilmesi gerekir. Veritabanını kaydetmek istediÄŸinizden emin misiniz? Edit View %1 Edit Trigger %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. Åžu anda zaten yürütülen SQL sorguları var. Bunun yerine, ÅŸimdiki sorguları çalıştırmak için ÅŸu anda yürütülen sorguyu durdurmak istiyor musunuz? Bunun veritabanını tutarsız bir durumda bırakabileceÄŸini unutmayın. -- EXECUTING SELECTION IN '%1' -- -- SEÇİM '%1' İÇERİSİNDE YÜRÜTÜLÜYOR -- -- EXECUTING LINE IN '%1' -- -- SATIR '%1' İÇERİSİNDE YÜRÜTÜLÜYOR -- -- EXECUTING ALL IN '%1' -- -- TÜMÜ '%1' İÇERİSİNDE YÜRÜTÜLÜYOR -- At line %1: %1. satırda: Result: %1 Sonuç: %1 Result: %2 Sonuç: %2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? PRAGMA deÄŸerlerini ayarlamak veya vakumlamak mevcut iÅŸleminizi kaydeder. Emin misiniz? Opened '%1' in read-only mode from recent file list Opened '%1' from recent file list Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Bırakılan dosyalara uygulanacak eylemi seçin. <br/>Not: yalnızca 'İçe Aktar' birden fazla dosyayı iÅŸleyecektir. The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? DB file '%1' could not be opened This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Table '%1' not found; settings ignored -- Reference to file "%1" (not supported by this version) -- Yes. Don't ask again This action will open a new SQL tab with the following statements for you to edit and run: Rename Tab Sekmeyi Yeniden Adlandır Duplicate Tab Sekmeyi Klonla Close Tab Sekmeyi Kapat Opening '%1'... '%1' açılıyor... There was an error opening '%1'... '%1' açılırken hata oluÅŸtu... Value is not a valid URL or filename: %1 Geçersiz bir URL veya dosya adı: %1 %1 rows returned in %2ms %2ms içerisinde %1 tane satır döndürüldü Automatically load the last opened DB file at startup Ctrl+Alt+0 Choose text files Metin dosyaları seçin Import completed. Some foreign key constraints are violated. Please fix them before saving. İçe aktarma tamamlandı. Bazı yabancı anahtar kısıtları ihlal edildi. Lütfen kaydetmeden önce bunları çözün. Select SQL file to open Açmak için SQL dosyasını seçiniz Select file name Dosya ismi seçiniz Select extension file Eklenti dosyasını seçiniz Extension successfully loaded. Eklenti baÅŸarıyla yüklendi. Error loading extension: %1 Eklenti yüklenirken hata oluÅŸtu: %1 Don't show again Bir daha gös'terme New version available. Yeni sürüm mevcut. A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Yeni bir SQLite DB Browser sürümü mevcut (%1.%2.%3).<br/><br/>Lütfen buradan indiriniz: <a href='%4'>%4</a>. Project saved to file '%1' Proje '%1' dosyasına kaydedildi Collation needed! Proceed? Harmanlama gerekli! Devam edilsin mi? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Bu veritabanınındaki bir tablo özel '%1' koleksiyon fonksiyonu gerektirmektedir. Daha fazla bilgi olmadan program bunu saÄŸlayamaz. EÄŸer bu ÅŸekilde devam edecekseniz, veritabanınıza kötü ÅŸeyler olabileceÄŸinin farkında olun ve yedek oluÅŸturun. Bir yedek oluÅŸturun! creating collation harmanlama oluÅŸturuluyor Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. SQL sekmesi için yeni bir ad belirleyin. AÅŸağıdaki karakteri klavye kısayolu olarak kullanmak için '&&' karakterini kullanın. Please specify the view name Lütfen görünüm ismini belirtin There is already an object with that name. Please choose a different name. Bu isme sahip obje zaten mevcut. Lütfen farklı bir isim seçiniz. View successfully created. Görünüm baÅŸarıyla oluÅŸturuldu. Error creating view: %1 Görünüm oluÅŸturma hatası: %1 This action will open a new SQL tab for running: Bu iÅŸlem çalıştırmak için yeni bir SQL sekmesi açar: Press Help for opening the corresponding SQLite reference page. İlgili SQLite referans sayfasını açmak için Yardım'a basın. DB Browser for SQLite project file (*.sqbpro) SQLite DB Browser proje dosyası (*.sqbpro) Error checking foreign keys after table modification. The changes will be reverted. Tablo deÄŸiÅŸikliÄŸinden sonra yabancı anahtarlar kontrol edilirken hata oluÅŸtu. DeÄŸiÅŸiklikler geri alınacak. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Bu tablo birincil anahtar kontrolünden geçmedi.<br/>'Araçlar | Birinci Anahat Kontrolü' komutunu çalıştırın ve raporlanan sorunları düzeltin. Execution finished with errors. Yürütme hatalarla tamamlandı. Execution finished without errors. Yürütme hatasız tamamlandı. NullLineEdit Set to NULL NULL olarak ayarlar Alt+Del PlotDock Plot Grafik Çizimi <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html> <head /> <body> <p> Bu bölme, o anda taranan tablonun sütunları listesini veya yürütülen sorguyu gösterir. AÅŸağıdaki çizim bölmesi için X veya Y ekseni olarak kullanılmasını istediÄŸiniz sütunları seçebilirsiniz. Tablo, ortaya çıkan grafiÄŸi etkileyecek algılanan eksen tipini gösterir. Y ekseni için yalnızca sayısal sütunlar seçebilirsiniz, ancak X ekseni için aÅŸağıdakileri seçebilirsiniz: </p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;" > <li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">Tarih/Saat</span>: &quot;yyyy-MM-dd hh:mm:ss&quot; veya &quot;yyyy-MM-ddThh:mm:ss&quot; ve string formatında </li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">Tarih</span>: &quot;yyyy-MM-dd&quot; ve string formatında </li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">Saat</span>: &quot;hh:mm:ss&quot; ve string formatında </li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">BaÅŸlık</span>: diÄŸer string formatları. Bu sütunun X ekseni için seçilmesi, sütun deÄŸerlerinin çubukları için etiket oluÅŸturur. </li> <li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">Nümerik</span>: integer veya real tipindeki deÄŸerler </li> </ul> <p> Y hücrelerini çift tıklatarak o grafik için kullanılan rengi deÄŸiÅŸtirebilirsiniz. </p> </body> </html> Columns Sütun X X Y1 Y2 Axis Type Eksen Tipi Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Yukarıdaki x ve y deÄŸerlerini seçtiÄŸinizde çizilen bir grafik. Noktaları grafikte ve tabloda seçmek için üzerine tıklayın. Nokta aralığı seçmek için Ctrl+Tıklama yapın. YakınlaÅŸtırma için fare tekerleÄŸini ve eksen aralığını deÄŸiÅŸtirmek için fare tekerini kullanın. Yalnızca geçerli yönde sürüklemek ve yakınlaÅŸtırmak için eksen veya eksen etiketlerini seçin. Line type: Çizgi Tipi: None Hiçbiri Line Çizgi StepLeft Sola Basamakla StepRight SaÄŸa Basamakla StepCenter Merkeze Basamakla Impulse Kaydırmalı Point shape: Nokta ÅŸekli: Cross Çarpı Plus Artı Circle Daire Disc Disk Square Kare Diamond Elmas Star Yıldız Triangle Üçgen TriangleInverted Ters Üçgen CrossSquare Çapraz Kare PlusSquare Kare İçinde Artı CrossCircle Daire İçinde Çarpı PlusCircle Daire İçinde Artı Peace Barış Simgesi <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Geçerli çizimi kaydet...</p><p>Uzantıya göre seçilen dosya formatları (png, jpg, pdf, bmp)</p></body></html> Save current plot... Geçerli çizimi kaydet... Load all data and redraw plot Tüm verileri yükle ve grafiÄŸi yeniden çiz Row # Satır # Copy Kopyala Print... Yazdır... Show legend Göstergeyi göster Stacked bars Yığılmış çubuklar Fixed number format Date/Time Tarih/Saat Date Tarih Time Saat Numeric Nümerik Label Etiket Invalid Geçersiz Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Tüm verileri yükle ve grafiÄŸi yeniden çiz. Uyarı: Kısmi yükleme mekanizması nedeniyle tüm veriler tablodan henüz alınmadı. Choose an axis color Bir eksen rengi seçin Choose a filename to save under Altına kaydetmek için dosya ismi seçiniz PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Tüm dosyalar(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Bu grafikte eÄŸriler var ve seçilen çizgi stili yalnızca X'e göre sıralanmış grafiklere uygulanabilir. EÄŸrileri kaldırmak için tabloyu veya sorguyu X'e göre sıralayın veya eÄŸriler tarafından desteklenen stillerden birini seçin: 'Hiçbiri' veya 'Çizgi'. Loading all remaining data for this table took %1ms. Bu tablo için kalan tüm verilerin yüklenmesi %1ms sürdü. PreferencesDialog Preferences Tercihler &General &Genel Remember last location Son dizini hatırla Always use this location Her zaman bu dizini kullan Remember last location for session only Aynı oturum için son dizini hatırla ... ... Default &location Varsayılan &dizin Lan&guage Di&l Automatic &updates Otomatik &güncellemeler enabled etkin Show remote options Uzak bilgisayar opsiyonlarını göster &Database &Veritabanı Database &encoding &Veritabanı kodlaması Open databases with foreign keys enabled. Veritabanlarını Yabancı Anahtarlar etkin olacak ÅŸekilde aç. &Foreign keys &Yabancı Anahtarlar Data &Browser Veri &Görüntüleyici Remove line breaks in schema &view Åžema &görünümde satır sonlarını kaldır Prefetch block si&ze Önceden getirme blo&k boyutu SQ&L to execute after opening database Veritabanı açıldıktan sonra yürütülecek SQ&L Default field type Varsayılan dosya tipi Font Yazı &Font &Yazı Content İçerik Symbol limit in cell Hücredeki sembol limiti Threshold for completion and calculation on selection Seçimdeki tamamlama ve hesaplama eÅŸiÄŸi Show images in cell Resimleri hücrede göster Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Hücrelerde görüntü verileri içeren BLOB tipindeki verilerin önizlemesini göstermek için bu seçeneÄŸi etkinleÅŸtirin. Ancak bu, veri görüntüleyicisinin performansını etkileyebilir. NULL NULL Regular Kurallı Binary İkili veri Background Arka plan Filters Filtreler Toolbar style Araç çubuÄŸu stili Only display the icon Sadece ikonu göster Only display the text Sadece metni göster The text appears beside the icon Metin simgenin yanında görünsün The text appears under the icon Metin simgenin altında görünsün Follow the style Stili baz al DB file extensions Veritabanı dosya uzantıları Manage Yönet Main Window Ana Pencere Database Structure Veritabanı Yapısı Browse Data Verileri Görüntüle Execute SQL SQL kodunu yürütme Edit Database Cell Veritabanı Hücresini Düzenleme When this value is changed, all the other color preferences are also set to matching colors. Bu deÄŸer deÄŸiÅŸtirildiÄŸinde, diÄŸer tüm renk tercihleri de eÅŸleÅŸen renklere ayarlanır. Follow the desktop style Masaüstü stilini baz al Dark style Koyu Tema Light style Application style Uygulama stili This sets the font size for all UI elements which do not have their own font size option. Font size Max Recent Files Prompt to save SQL tabs in new project file If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. EtkinleÅŸtirildiÄŸinde, Veritabanı Yapısı sekmesinin Åžema sütununda satır sonu karakterleri ve yazdırılan çıktılar kaldırılır. Database structure font size Font si&ze Yazı B&oyutu Formatted This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. Bu, bazı hesaplama açısından pahalı iÅŸlevlerin etkinleÅŸtirilmesine izin verilen maksimum öğe sayısıdır: Sütundaki geçerli deÄŸerlere dayalı olarak deÄŸer tamamlamayı etkinleÅŸtirmek için bir tablodaki maksimum satır sayısı. Toplam ve ortalamayı hesaplamak için bir seçimdeki maksimum index sayısı. İşlevleri devre dışı bırakmak için 0 olarak ayarlanabilir. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Bu, sütundaki geçerli deÄŸerlere dayalı olarak deÄŸer tamamlamayı etkinleÅŸtirmek için bir tablodaki maksimum satır sayısıdır. Tamamlamayı devre dışı bırakmak için 0 olarak ayarlanabilir. Selection background Selection foreground Highlight Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. Close button on tabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. Select built-in extensions to load for every database: Proxy Proxy Configure Yapılandır Export Settings Import Settings Field display Alan görünümü Displayed &text Görün&tülenen metin Click to set this color Bu rengi ayarlamak için tıklayın Text color Metin rengi Background color Arka plan rengi Preview only (N/A) Sadece önizleme (N/A) Escape character Kaçış karakteri Delay time (&ms) Gecikme süresi (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Yeni bir filtre deÄŸeri uygulanmadan önce bekleme süresini ayarlayın. Beklemeyi devre dışı bırakmak için 0 olarak ayarlanabilir. &SQL &SQL Context Özellik Colour Renk Bold Kalın Italic İtalik Underline Altı çizili Keyword Anahtar Kelime Function Fonksiyon Table Tablo Comment Yorum Identifier Kimlik String String Current line Geçerli satır SQL &editor font size SQL &Editör yazı boyutu Tab size TAB karakter boyutu &Wrap lines &Satırları kaydır Never Asla At word boundaries Kelime dahilinde At character boundaries Karakter dahilinde At whitespace boundaries Beyaz boÅŸluk dahilinde &Quotes for identifiers Tanımlıyıcılar için &tırnaklar Choose the quoting mechanism used by the application for identifiers in SQL code. Uygulama tarafından SQL kodundaki tanımlayıcılar için kullanılan tırnak stilini seçin. "Double quotes" - Standard SQL (recommended) "Çift tırnak" - Standart SQL (önerilir) `Grave accents` - Traditional MySQL quotes `Ters tırnaklar` - Geleneksel MySQL tırnakları [Square brackets] - Traditional MS SQL Server quotes [Köşeli parantezler] - Geleneksel MS SQL Server Keywords in &UPPER CASE Anahtar kelimeler B&ÜYÜK HARFLİ When set, the SQL keywords are completed in UPPER CASE letters. Ayarlandığında, SQL anahtar kelimeleri BÜYÜK HARFLERLE tamamlanır. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Ayarlandığında, son yürütme sırasında hatalara neden olan SQL kod satırları vurgulanır ve sonuç çerçevesi arka plandaki hatayı gösterir <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html> <head /> <body> <p> SQLite, paylaşılmış kütüphane dosyasından eklenti yüklemeye yarayan bir fonksiyon sunar. <span style=" font-style:italic;">load_extension()</span> fonksiyonunu SQL kodu içerisinde kullanmak istiyorsanız fonksiyonu aktive edin. </p> <p> Güvenlik nedeniyle, uzantı yüklemesi varsayılan olarak kapalıdır ve bu ayar ile etkinleÅŸtirilmelidir. Bu seçenek devre dışı bırakılmış olsa bile, uzantıları her zaman GUI üzerinden yükleyebilirsiniz. </p> </body> </html> Allow loading extensions from SQL code SQL kodundan eklenti yüklemeye izin ver Remote Uzak Bilgisayar CA certificates CA sertifikaları Subject CN CN Konusu Common Name Yaygın İsim Subject O Konu O Organization Organizasyon Valid from Åžundan tarihten itibaren geçerli Valid to Åžu tarihe kadar geçerli Serial number Seri numarası Your certificates Sertifikalarınız File Dosya Subject Common Name Ortak Konu Adı Issuer CN CN SaÄŸlayıcısı Issuer Common Name Ortak SaÄŸlayıcı Adı Clone databases into Veritabanını ÅŸuraya kopyala SQL editor &font SQL Editör &yazı boyutu Error indicators Hata belirteçleri Hori&zontal tiling Ya&tay Döşeme If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. EtkinleÅŸtirilirse, SQL kod düzenleyicisi ve sonuç tablosu görünümü üst üste yerine yan yana gösterilir. Code co&mpletion Kod ta&mamlama Foreground Ön plan SQL &results font size S&QL sonuçları yazı tipi boyutu &Extensions &Eklentiler Select extensions to load for every database: Her veritabanında kullanmak için eklenti seçiniz: Add extension Eklenti Ekle Remove extension Eklenti Sil <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>Kurallı ifade(REGEXP) operatörü aktif edildiÄŸinde SQLite, herhangi bir kurallı ifade uygulamaz ama ÅŸuan da çalışan uygulamayı geri çağırır. <br/>SQLite DB Browser kurallı ifadeyi kutunun dışında kullanmanıza izin vermek için bu algoritmayı uygular. <br/>Birden çok muhtemel uygulama olduÄŸu gibi sizde farklı birini kullanabilirsiniz.<br/>Programın uygulamalarını devre dışı bırakmakta ve kendi eklentinizle kendi uygulamanızı yüklemekte özgürsünüz.<br/>Ayrıca uygulamayı yeniden baÅŸlatmak gerekir.</p></body></html> Disable Regular Expression extension Kurallı İfade eklentisini devre dışı bırak Choose a directory Dizin seçiniz The language will change after you restart the application. Seçilen dil uygulama yeniden baÅŸlatıldıktan sonra uygulanacaktır. Select extension file Eklenti dosyası seçiniz Extensions(*.so *.dylib *.dll);;All files(*) Eklentiler(*.so *.dylib *.dll);;Tüm dosyalar(*) Import certificate file Sertifika dosyası içe aktar No certificates found in this file. Bu dosyada sertifika bulunamadı. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Bu sertifikayı kaldırmak istediÄŸinizden emin misiniz? Tüm sertifika verileri uygulama ayarlarından silinecektir! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Kaydedilen tüm ayarları silmek istediÄŸinizden emin misiniz? Tüm tercihleriniz kaybolacak ve varsayılan deÄŸerler kullanılacak. Save Settings File Initialization File (*.ini) The settings file has been saved in location : Open Settings File The settings file was loaded properly. The selected settings file is not a normal settings file. Please check again. ProxyDialog Proxy Configuration Proxy Yapılandırması Pro&xy Type Pro&xy Tipi Host Na&me A&na Bilgisayar Adı Port Port Authentication Re&quired Kimlik &DoÄŸrulaması Gerekli &User Name K&ullanıcı Adı Password Parola None Hiçbiri System settings Sistem ayarları HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data Veriyi içe aktarılırken hata oluÅŸtu from record number %1 kayıt numarasından: %1 . %1 . %1 Importing CSV file... CSV dosyası içe aktarılıyor... Cancel İptal All files (*) Tüm dosyalar (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) SQLite veritabanı dosyaları (*.db *.sqlite *.sqlite3 *.db3) Left Sola Hizala Right SaÄŸa Hizala Center Ortala Justify İki yana yasla SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) SQLite Veritabanı Dosyaları (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) DB Browser for SQLite Proje Dosyaları (*.sqbpro) SQL Files (*.sql) SQL Dosyaları (*.sql) All Files (*) Tüm Dosyalar (*) Text Files (*.txt) Metin Dosyaları (*.txt) Comma-Separated Values Files (*.csv) Virgülle Ayrılmış DeÄŸerler Dosyaları (* .csv) Tab-Separated Values Files (*.tsv) Tab ile Ayrılmış DeÄŸerler Dosyaları (*.tsv) Delimiter-Separated Values Files (*.dsv) Sınırlayıcı ile Ayrılmış DeÄŸerler Dosyaları (* .dsv) Concordance DAT files (*.dat) Uyumluluk DAT dosyaları (* .dat) JSON Files (*.json *.js) JSON dosyaları (*.json *.js) XML Files (*.xml) XML Dosyaları (*.xml) Binary Files (*.bin *.dat) İkili Dosyalar (*.bin *.dat) SVG Files (*.svg) SVG Dosyaları (*.svg) Hex Dump Files (*.dat *.bin) Onaltılık Döküm Dosyaları (* .dat * .bin) Extensions (*.so *.dylib *.dll) Eklentiler (* .so * .dylib * .dll) Initialization File (*.ini) QsciCommand Paste Yapıştır Cancel İptal QsciLexerCPP Default Varsayılan Keyword Anahtar Kelime Identifier Kimlik QsciLexerJSON Default Varsayılan String String QsciLexerJavaScript Regular expression Düzenli ifadeler (RegEx) QsciLexerPython Default Varsayılan Comment Yorum Keyword Anahtar Kelime Identifier Kimlik QsciLexerSQL Default Varsayılan Comment Yorum Keyword Anahtar Kelime Identifier Kimlik QsciScintilla Select All Tümünü Seç RemoteCommitsModel Commit ID Message Date Tarih Author Size Boyut Authored and committed by %1 Authored by %1, committed by %2 RemoteDatabase Error opening local databases list. %1 Yerel veritabanı listesi açılamadı. %1 Error creating local databases list. %1 Yerel veritabanı listesi oluÅŸturulamadı. %1 RemoteDock Remote Uzak Bilgisayar Identity Kmlik Push currently opened database to server Åžu anda açık olan veritabanını sunucuya aktar Upload DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> Local Current Database Clone Branch Branch Commits Commits for Delete Database Delete the local clone of this database Open in Web Browser Open the web page for the current database in your browser Clone from Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. Refresh Yenile Reload all data and update the views Clone Database Open Database Open the local copy of this database Check out Commit Download and open this specific commit Check out Latest Commit Check out the latest commit of the current branch Save Revision to File Saves the selected revision of the database to another file Upload Database Upload this database as a new commit <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html> <head /> <body> <p> Åžu anda dahili, salt okunur kimlik kullanıyorsunuz. Kendi veritabanınızı yüklemek için DBHub.io hesabı kullanıp konfigure etmeniz gerekiyor. </p> <p> Henüz DBHub.io hesabınız yok mu? <a href="https://dbhub.io/" ><span style=" text-decoration: underline; color:#007af4;" >Åžimdi bir tane oluÅŸturun</span ></a > ve veritabanınızı paylaÅŸmak için <a href="#preferences" ><span style=" text-decoration: underline; color:#007af4;" >buradan</span ></a > sertifikanızı içe aktarın. </p> <p> Çevrimiçi yardım için <a href="https://dbhub.io/about" ><span style=" text-decoration: underline; color:#007af4;" >burayı</span ></a > ziyaret edin. </p> </body> </html> &User &Database &Veritabanı Back Geri Select an identity to connect Public This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Invalid URL: The host name does not match the host name of the current identity. Invalid URL: No branch name specified. Invalid URL: No commit ID specified. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? The database has unsaved changes. Are you sure you want to push it before saving? The database you are trying to delete is currently opened. Please close it before deleting. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? RemoteLocalFilesModel Name İsim Branch Branch Last modified Son deÄŸiÅŸtirilme Size Boyut Commit Commit File Dosya RemoteModel Name İsim Commit Commit Last modified Son deÄŸiÅŸtirilme Size Boyut Size: Last Modified: Licence: Default Branch: RemoteNetwork Choose a location to save the file Error opening remote file at %1. %2 %1 adresinde bulunan dosya açılamadı. %2 Error: Invalid client certificate specified. Hata: Geçersiz istemci sertifikası belirtildi. Please enter the passphrase for this client certificate in order to authenticate. Kimlik doÄŸrulaması için lütfen istemci sertifikasının parolasını girin. Cancel İptal Uploading remote database to %1 Uzak veritabanı karşıya yükleniyor %1 Downloading remote database from %1 Uzaktaki sunucu indiriliyor: %1 Error: Cannot open the file for sending. Hata: Dosya gönderim için açılamadı. RemotePushDialog Push database Veritabanını aktar Database na&me to push to Aktarılacak veritaba&nı adı Commit message Commit mesajı Database licence Veritabanı lisansı Public Halka açık Branch Branch Force push Aktarmaya zorla Username Database will be public. Everyone has read access to it. Veritabanı halka açık olacak. Herkes okuma iznine sahip olacak. Database will be private. Only you have access to it. Veritabanı özel olacak. Sadece sizin eriÅŸiminiz olacak. Use with care. This can cause remote commits to be deleted. Dikkatlice kullanın. Bu, uzaktaki deÄŸiÅŸikliklerin silinmesine sebep olabilir. RunSql Execution aborted by user Yürütme kullanıcı tarafından durduruldu , %1 rows affected , %1 satır etkilendi query executed successfully. Took %1ms%2 sorgu baÅŸarıyla yürütüldü. %1ms%2 sürdü executing query sorgu yürütülüyor SelectItemsPopup A&vailable &Kullanılabilir Sele&cted &Seçilen SqlExecutionArea Form Form Find previous match [Shift+F3] Önceki eÅŸleÅŸmeyi bul [Shift, F3] Find previous match with wrapping Sarmalayarak bir önceki eÅŸleÅŸmeyi bul Shift+F3 The found pattern must be a whole word Bulunan desen tam bir kelime olmalıdır Whole Words Kelimenin Tamamı Text pattern to find considering the checks in this frame Bu alandaki kontrolleri baz alarak bulunacak metin deseni Find in editor Editörde ara The found pattern must match in letter case Bulunan desen büyük küçük harfe duyarlı olmalıdır Case Sensitive Büyük küçük harfe duyarı Find next match [Enter, F3] Sonraki eÅŸleÅŸmeyi bul [Enter, F3] Find next match with wrapping Sarmalayarak bir sonraki eÅŸleÅŸmeyi bul F3 Interpret search pattern as a regular expression Arama desenini düzenli ifade(RegEx) olarak yorumla <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html> <head /> <body> <p> İşaretlendiÄŸinde, girilen desen UNIX düzenli ifadesi olarak yorumlanır. <a href="https://en.wikibooks.org/wiki/Regular_Expressions" >Wikibooks</a > üzerinden düzenli ifadeleri inceleyebilirsiniz. </p> </body> </html> Regular Expression Kurallı İfade (RegEx) Close Find Bar Araba çubuÄŸunu kapat <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html> <head /> <body> <p>Son yürütülen ifadelerin sonuçları.</p> <p> Bu paneli daraltmak ve bunun yerine <span style=" font-style:italic;">SQL Log Günlüğünü</span> <span style=" font-style:italic;">Kullanıcı</span> seçimi ile kullanmak isteyebilirsiniz. </p> </body> </html> Results of the last executed statements Son yürütülen ifadenin sonucu This field shows the results and status codes of the last executed statements. Bu alan son yürütülen ifadenin durum kodlarını ve sonuçlarını gösterir. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Couldn't save file: %1. Dosya kaydedilemedi: %1. Your changes will be lost when reloading it! Yeniden yüklerken deÄŸiÅŸiklikleriniz kaybolacak! The file "%1" was modified by another program. Do you want to reload it?%2 "%1" dosyası baÅŸka bir program tarafından deÄŸiÅŸtirildi. Yeniden yüklemek istiyor musunuz?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) abs(X) fonksiyonu X sayısal argümanının mutlak deÄŸerini döndürür. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () changes() fonksiyonu en son yürütülen INSERT, DELETE veya UPDATE ifadesinden etkilenen veritabanı satırlarının sayısını döndürür. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) char(X1,X2,...,XN) fonksiyonu sırasıyla X1'den XN'e kadar olan tamsayıların unicode karakter karşılıklarından oluÅŸan dizeyi döndürür. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) coalesce() fonksiyonu NULL olmayan ilk argümanı döndürür. EÄŸer tüm argümanlar NULL ise NULL deÄŸerini döndürür (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) glob(X,Y) fonksiyonu "Y GLOB X" ifadesinin eÅŸdeÄŸerini döndürür. (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) ifnull() fonksiyonu NULL olmayan ilk argümanı döndürür. EÄŸer her iki argüman da NULL ise NULL deÄŸerini döndürür. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) instr(X,Y) fonksiyonu ilk önce X dizesinin içinde Y dizesinin içeriÄŸini arar ve eÅŸleÅŸen yerden önceki karakterlerin sayısının 1 fazlasını döndürür. EÄŸer Y, X içerisinde bulunmazsa 0 deÄŸerini döndürür. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) hex() fonksiyonu argümanı BLOB olarak yorumlar ve BLOB içeriÄŸinin büyük harf onaltılık kısmını dize olarak döndürür. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () last_insert_rowid() fonksiyonu çaÄŸrılan veritabanı baÄŸlantısından en son eklenen satırın ROWID deÄŸerini döndürür. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) length() fonksiyonu X dize deÄŸeri için NULL ifadesine kadar olan karakter sayısını döndürür (bayt olarak deÄŸil). (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) like() fonksiyonu "Y LIKE X" ifadesini uygulamak için kullanılır. (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) like() fonksiyonu "Y LIKE X ESCAPE Z" ifadesini uygulamak için kullanılır. (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) load_extension(X) fonksiyonu, SQLite eklentilerini X adlı paylaşılan kitaplık dosyasından yükler. Bu iÅŸlevin kullanımına Tercihler'den izin verilmelidir. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X, Y) load_extension(X) iÅŸlevi, Y giriÅŸ noktasını kullanarak X adlı paylaşılan kitaplık dosyasından SQLite eklentilerini yükler. Bu iÅŸlevin kullanımına Tercihler'den izin verilmelidir. (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) lower(X) fonksiyonu tüm X dizesinin tüm ASCII karakterlerinin küçük harfe dönüştürülmüş karşılığını döndürür. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) fonksiyonu X'in sol tarafındaki boÅŸlukları siler. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) ltrim(X,Y) fonksiyonu X'in sol tarafındaki Y'de bulunan tüm karakterlerin silinmiÅŸ halini dize halinde döndürür. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) Çok argümanlı max() fonksiyonu en büyük deÄŸere sahip argümanı döndürür. EÄŸer herhangi bir argüman NULL ise NULL deÄŸerini döndürür. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) Çok argümanlı min() fonksiyonu en küçük deÄŸere sahip argümanı döndürür. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) nullif(X,Y) fonksiyonu eÄŸer argümanlar farklı ise ilk argümanı, eÄŸer argümanlar aynı ise NULL döndürür. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) printf(FORMAT,...) SQL fonksiyonu C dilindeki sqlite3_mprintf() fonksiyonu ve standard C kütüphanesindeki printf() fonksiyonu ile aynı mantıkta çalışır. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) quote(X) fonksiyonu girilen argümanlardan SQL ifadesi olarak tam anlamıyla dahil edilmeye uygun olanları döndürür. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () random() fonksiyonu -9223372036854775808 ve +9223372036854775807 tamsayı deÄŸerli arasında rastgele deÄŸer döndürür. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) randomblob(N) fonksiyonu rastgele bayt içeren N-byte türünde blob döndürür. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) replace(X,Y,Z) fonksiyonu X içindeki her Y argümanını, Z argümanıyla deÄŸiÅŸtirmesiyle oluÅŸan dizeyi döndürür. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) round(X) fonksiyonu X ondalıklı sayısının ondalıklı kısmın sıfıra yuvarlanmasıyla oluÅŸan deÄŸeri döndürür. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) round(X,Y) fonksiyonu X ondalıklı sayısının Y kadar sağındaki ondalıklı kısmı sıfıra yuvarlanmasıyla oluÅŸan deÄŸeri döndürür. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) fonksiyonu X'in saÄŸ tarafındaki boÅŸlukları siler. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) rtrim(X,Y) fonksiyonu X'in saÄŸ tarafındaki Y'de bulunan tüm karakterlerin silinmiÅŸ halini dize halinde döndürür. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) soundex(X) fonksiyonu X dizesinin soundex kodlamasını string olarak döndürür. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) fonksiyonu X dizesinin baÅŸlangıcından Y. indekse kadar olan string bölümünü döndürür. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) substr(X,Y,Z) fonksiyonu X dizesinin Y. indeksinden baÅŸlayarak Z uzunluÄŸu kadar olan string bölümünü döndürür. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () total_changes() fonksiyonu geçerli veritabanı baÄŸlantısı açıldığından itibaren INSERT, UPDATE veya DELETE ifadelerinden etkilenen toplam satır sayısını döndürür. (X) trim(X) removes spaces from both ends of X. (X) trim(X) fonksiyonu X'in içinde bulunan boÅŸlukları siler. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) trim(X,Y) fonksiyonu X'in içindeki Y'de bulunan tüm karakterlerin silinmiÅŸ halini dize halinde döndürür. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) typeof(X) fonksiyonu X ifadesinin veri tipini gösteren dizeyi döndürür. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) unicode(X) fonksiyonu X'in ilk karakterine karşılık gelen unicode kod noktasını döndürür. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) upper(X) fonksiyonu tüm X dizesinin tüm küçük ASCII karakterlerinin büyük harf karşılığına çevrilmiÅŸ kopyasını döndürür. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) zeroblob(N) fonksiyonu 0x00'ın N bayt kadar meydana gelmiÅŸ halini BLOB olarak döndürür. (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) avg() fonksiyonu bir gruptaki NULL olmayan tüm X deÄŸerlerinin ortalama deÄŸerini döndürür. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) count(X) fonksiyonu bir gruptaki X'in kaç kere NULL olmadığının sayısını döndürür. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) group_concat() fonksiyonu X'in NULL olmayan tüm deÄŸerlerle birleÅŸimini dize olarak döndürür. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) group_concat() fonksiyonu X'in NULL olmayan tüm deÄŸerlerle birleÅŸimini dize olarak döndürür. EÄŸer Y parametresi mevcutsa X'in örnekleri arasında ayraç olarak kullanılır. (X) The max() aggregate function returns the maximum value of all values in the group. (X) max() küme fonksiyonu gruptaki tüm deÄŸerler arasından en büyük deÄŸeri döndürür. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) min() küme fonksiyonu gruptaki NULL olmayan tüm deÄŸerler arasından en küçük deÄŸeri döndürür. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) sum() ve total() küme fonksiyonları gruptaki NULL olmayan tüm deÄŸerlerin toplamını döndürür. () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () Geçerli bölümdeki satır sayısı. Satırlar, 1'den baÅŸlayarak, tanım penceresinde ORDER BY ifadesi tarafından tanımlanan sırada veya aksi takdirde rastgele sırada numaralandırılır. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () row_number() her gruptaki ilk eÅŸin - boÅŸlukları olan geçerli satırın sırası. ORDER BY ifadesi yoksa, tüm satırlar eÅŸ olarak kabul edilir ve bu iÅŸlev her zaman 1 deÄŸerini döndürür. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Geçerli satırın kendi bölümündeki eÅŸ grubunun sayısı - boÅŸluklar olmadan geçerli satırın sırası. Bölümler, 1'den baÅŸlayarak, tanım penceresindeki ORDER BY ifadesi tarafından tanımlanan sırada numaralandırılır. ORDER BY iifadesi yoksa, tüm satırlar eÅŸ olarak kabul edilir ve bu iÅŸlev her zaman 1 deÄŸerini döndürür. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () İsme raÄŸmen, bu iÅŸlev her zaman 0.0 ile 1.0 arasında (sıralama - 1) / (bölüm satırları - 1) deÄŸerine bir deÄŸer döndürür; burada sıralama, yerleÅŸik pencere rank() fonksiyonu ve bölüm- tarafından döndürülen deÄŸerdir. satırlar, bölümdeki toplam satır sayısıdır. Bölüm yalnızca bir satır içeriyorsa, bu iÅŸlev 0,0 deÄŸerini döndürür. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () Kümülatif dağılım. Satır-sayısı/bölüm-satırları olarak hesaplanır; burada satır-sayısı, gruptaki son eÅŸ için row_number() tarafından döndürülen deÄŸerdir ve bölüm-satırdaki bölüm sayısıdır. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) N argümanı bir tamsayı olarak ele alınır. Bu iÅŸlev, bölümü olabildiÄŸince eÅŸit bir ÅŸekilde N gruplarına böler ve ORDER BY ifadesi tarafından tanımlanan sırada veya aksi takdirde rasgele sırayla her gruba 1 ve N arasında bir tam sayı atar. Gerekirse, önce daha büyük gruplar oluÅŸur. Bu iÅŸlev, geçerli satırın parçası olduÄŸu gruba atanan tamsayı deÄŸerini döndürür. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) Bölümdeki önceki satıra göre expr ifade deÄŸerlendirmesinin sonucunu döndürür. Veya, önceki satır yoksa (geçerli satır ilk satır olduÄŸu için), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) Uzaklık deÄŸiÅŸkeni saÄŸlanırsa, negatif olmayan bir tam sayı olmalıdır. Bu durumda, döndürülen deÄŸer, bölüm içindeki geçerli satırdan önce satır ofseti satırlarına göre ifade deÄŸerlendirmesinin sonucudur. Ofset 0 ise, ifade geçerli satıra göre deÄŸerlendirilir. Geçerli satırdan önce satır kaydırma satırları yoksa, NULL döndürülür. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) Varsayılan da saÄŸlanmışsa, ofset ile tanımlanan satır yoksa NULL döndürülür. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) Bölümdeki bir sonraki satıra göre expr ifade deÄŸerlendirmesinin sonucunu döndürür. Veya, bir sonraki satır yoksa (geçerli satır son olduÄŸu için), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) Uzaklık deÄŸiÅŸkeni saÄŸlanırsa, negatif olmayan bir tam sayı olmalıdır. Bu durumda, döndürülen deÄŸer, bölüm içindeki geçerli satırdan sonra ifade ofset satırlarına göre ifade deÄŸerlendirmesinin sonucudur. Ofset 0 ise, ifade geçerli satıra göre deÄŸerlendirilir. Geçerli satırdan sonra satır ofseti satırı yoksa, NULL döndürülür. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) Bu yerleÅŸik pencere iÅŸlevi, her satır için pencere çerçevesini birleÅŸtirilmiÅŸ pencere iÅŸlevi ile aynı ÅŸekilde hesaplar. Her satır için pencere çerçevesindeki ilk satıra karşı deÄŸerlendirilen ifade deÄŸerini döndürür. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) Bu yerleÅŸik pencere iÅŸlevi, her satır için pencere çerçevesini birleÅŸtirilmiÅŸ pencere iÅŸlevi ile aynı ÅŸekilde hesaplar. Her satır için pencere çerçevesindeki son satıra göre deÄŸerlendirilen ifade deÄŸerini döndürür. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) Bu yerleÅŸik pencere iÅŸlevi, her satır için pencere çerçevesini birleÅŸtirilmiÅŸ pencere iÅŸlevi ile aynı ÅŸekilde hesaplar. Pencere çerçevesinin N satırına göre deÄŸerlendirilen ifade deÄŸerini döndürür. Satırlar, pencere çerçevesi içinde 1'den baÅŸlayarak, ORDER BY deyimi tarafından varsa veya baÅŸka bir ÅŸekilde rastgele sırada numaralandırılır. Bölümde N'inci satırı yoksa, NULL döndürülür. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. SqliteTableModel reading rows satırlar okunuyor loading... yükleniyor... References %1(%2) Hold %3Shift and click to jump there Referanslar %1(%2) Buraya atlamak için %3Shift'e basılı tutun ve tıklayın Error changing data: %1 Veri deÄŸiÅŸtirme hatası: %1 retrieving list of columns sütunların listesi alınıyor Fetching data... Veri alınıyor... Cancel İptal TableBrowser Browse Data Veriyi Görüntüle &Table: &Tablo: Select a table to browse data Verileri görüntülemek için tablo seçiniz Use this list to select a table to be displayed in the database view Veritabanı görünümünde gösterilecek tabloyu seçmek için bu listeyi kullanın This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Bu veritabanı tablosu görünümüdür. AÅŸağıdaki iÅŸlemleri yapabilirsiniz:   - Satır içi deÄŸeri düzenlemek için yazmaya baÅŸlayın.   - İçeriklerini hücre düzenleyici penceresinde düzenlemek için herhangi bir kaydı çift tıklayın.   - Hücre içeriÄŸini NULL'a dönüştürmek için Alt + Del tuÅŸlarına basın.   - Geçerli kaydı çoÄŸaltmak için Ctrl + "tuÅŸlarına basın.   - Yukarıdaki hücreden deÄŸeri kopyalamak için Ctrl + '.   - Standart seçim ve kopyalama / yapıştırma iÅŸlemleri. Text pattern to find considering the checks in this frame Bu çerçevedeki kontrolleri baz alarak bulmak için metin deseni Find in table Tabloda ara Find previous match [Shift+F3] Önceki eÅŸleÅŸmeyi bul [Shift,F3] Find previous match with wrapping Sarmalayarak bir önceki eÅŸleÅŸmeyi bul Shift+F3 Find next match [Enter, F3] Sonraki eÅŸleÅŸmeyi bul [Enter, F3] Find next match with wrapping Sarmalayarak bir sonraki eÅŸleÅŸmeyi bul F3 The found pattern must match in letter case Bulunan desen büyük küçük harfe duyarlı ÅŸekilde eÅŸleÅŸmelidir Case Sensitive Büyük Küçük Harfe Duyarlı The found pattern must be a whole word Bulunan kalıp tam bir kelime olmalıdır Whole Cell Tüm hücre Interpret search pattern as a regular expression Arama desenini düzenliifade olarak yorumlama <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html> <head /> <body> <p> İşaretlendiÄŸinde, girilen desen UNIX düzenli ifadesi olarak yorumlanır. <a href="https://en.wikibooks.org/wiki/Regular_Expressions" >Wikibooks</a > üzerinden düzenli ifadeleri inceleyebilirsiniz. </p> </body> </html> Regular Expression Düzenli İfade (RegEx) Close Find Bar Arama ÇubuÄŸunu Kapat Text to replace with DeÄŸiÅŸtirilecek metin Replace with Åžununla deÄŸiÅŸtir Replace next match Sonraki eÅŸleÅŸmeyi deÄŸiÅŸtir Replace DeÄŸiÅŸtir Replace all matches Tüm eÅŸleÅŸenleri deÄŸiÅŸtir Replace all Tümünü DeÄŸiÅŸtir Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Copy column name Copy the database table column name to your clipboard New Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>BaÅŸa sürükle</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>Bu butona basıldığında üstteki tablo görünümünün baÅŸlangıcına kaydırılır.</p></body></html> |< |< Scroll one page upwards Bir sayfa yukarı kaydır <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>Bu butona tıklamak, yukarıdaki tablo görünümünde kayıt sayfasını yukarı doÄŸru kaydırır.</p></body></html> < < 0 - 0 of 0 0 - 0 / 0 Scroll one page downwards Bir sayfa aÅŸağı kaydır <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>Bu butona tıklamak, yukarıdaki tablo görünümünde kayıt sayfasını aÅŸağıya doÄŸru kaydırır.</p></body></html> > > Scroll to the end Sona sürükle <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>İstediÄŸiniz kayda atlamak için buraya tıklayın</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Bu buton belirtilen kayıt numarasına gitmek için kullanılır.</p></body></html> Go to: Bu kayda gidin: Enter record number to browse Görüntülemek için kayıt numarasını giriniz Type a record number in this area and click the Go to: button to display the record in the database view Bu alana veritabanı görünümünde görüntülemek istediÄŸiniz kayıt numarasını giriniz ve Bu kayda gidin butonuna tıklayınız 1 1 Show rowid column rowid sütununu göster Toggle the visibility of the rowid column Rowid sütununun görünürlüğünü ayarla Unlock view editing Görünüm düzenlemenin kilidini aç This unlocks the current view for editing. However, you will need appropriate triggers for editing. Bu, geçerli görünümün düzenleme için kilidini açar. Ancak, düzenleme için uygun tetikleyicilere ihtiyacınız olacaktır. Edit display format Görüntüleme formatını düzenle Edit the display format of the data in this column Bu sütundaki verilerin görüntüleme biçimini düzenleyin New Record Yeni Kayıt Insert a new record in the current table Geçerli tabloya yeni bir kayıt ekle <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html> <head /> <body> <p> Bu düğme veritabanında yeni bir kayıt oluÅŸturur. Farklı seçeneklerin olduÄŸu açılır menüsüyü görüntülemek için fare düğmesini basılı tutun: </p> <ul> <li> <span style=" font-weight:600;">Yeni Kayıt</span>: veritabanına varsayılan deÄŸerleri olan yeni bir kayıt ekler. </li> <li> <span style=" font-weight:600;">DeÄŸerler Ekleyin...</span>: veritabanına eklenmeden önce deÄŸerleri girmek için bir iletiÅŸim kutusu açın. Bu, farklı kısıtlamaları karşılayan deÄŸerlerin girilmesine izin verir. Bu iletiÅŸim kutusu, bu kısıtlamalar nedeniyle <span style=" font-weight:600;">Yeni Kayıt</span> seçeneÄŸi baÅŸarısız olursa da açılır. </li> </ul> </body> </html> Delete Record Kaydı Sil Delete the current record Geçerli kaydı sil This button deletes the record or records currently selected in the table Bu buton tabloda seçili olan kaydı veya kayıtları siler Insert new record using default values in browsed table Görüntülenen tablosundaki varsayılan deÄŸerleri kullanarak yeni kayıt ekle Insert Values... DeÄŸerler Ekle... Open a dialog for inserting values in a new record Yeni bir kayda deÄŸer eklemek için bir iletiÅŸim kutusu açın Export to &CSV &CSV dosyası olarak dışa aktar Export the filtered data to CSV FiltrelenmiÅŸ veriyi CSV olarak dışa aktar This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Bu buton, görüntülenen tablonun verilerini ÅŸu anda görüntülendiÄŸi ÅŸekliyle (filtrelerden, görüntüleme biçimlerinden ve sütunların sıralamasına kadar) bir CSV dosyası olarak dışa aktarır. Save as &view &Görünüm olarak kaydet Save the current filter, sort column and display formats as a view Geçerli filtreyi, sütunu ve görüntüleme biçimlerini bir görünüm olarak kaydedin This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Bu buton, görüntülenen tablonun geçerli ayarlarını (filtreler, görüntü formatları ve sütunların sırasına kadar) daha sonra göz atabileceÄŸiniz veya SQL ifadelerinde kullanabileceÄŸiniz bir SQL görünümü olarak kaydeder. Save Table As... Tabloyu Farklı Kaydet... Save the table as currently displayed Tabloyu ÅŸu anda gösterilen ÅŸekilde kaydet <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html> <head /> <body> <p> Bu açılır menü, o anda görüntülenen ve filtrelenen tablo için geçerli olan aÅŸağıdaki seçenekleri sunar: </p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;" > <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > CSV olarak Dışa Aktar: Bu seçenek, görüntülenen tablonun verilerini ÅŸu anda görüntülendiÄŸi ÅŸekliyle (filtrelerden, görüntüleme biçimlerinden ve sipariÅŸ sütunun sıralamasına kadar) bir CSV dosyasına aktarır. </li> <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > Görünüm olarak kaydet: Bu seçenek, göz atılan tablonun geçerli ayarlarını (filtreler, görüntü formatları ve sipariÅŸ sütun sıralamasına kadar) daha sonra göz atabileceÄŸiniz veya SQL ifadelerinde kullanabileceÄŸiniz bir SQL görünümü olarak kaydeder. </li> </ul> </body> </html> Hide column(s) Sütunları gizle Hide selected column(s) Seçilen sütunları gizle Show all columns Tüm sütunları göster Show all columns that were hidden Gizlenen tüm sütunları göster Set encoding Kodlama seç Change the encoding of the text in the table cells Tablo hücrelerindeki metnin kodlamasını deÄŸiÅŸtirme Set encoding for all tables Tüm tablolar için kodlama seç Change the default encoding assumed for all tables in the database Veritabanındaki tüm tablolar için varsayılan kodlamayı deÄŸiÅŸtirme Clear Filters Filtreleri Temizle Clear all filters Tüm filtreleri temizle This button clears all the filters set in the header input fields for the currently browsed table. Bu buton, o anda görüntülenen tablonun baÅŸlık giriÅŸ alanlarında ayarlanan tüm filtreleri temizler. Clear Sorting Sıralamayı Temizle Reset the order of rows to the default Satırların sırasını varsayılana sıfırla This button clears the sorting columns specified for the currently browsed table and returns to the default order. Bu buton, o anda görüntülenen tablo için belirtilen sıralama sütunlarını temizler ve varsayılan sıraya geri döner. Print Yazdır Print currently browsed table data Åžu anda görüntülenen tablo verilerini yazdır Print currently browsed table data. Print selection if more than one cell is selected. Åžu anda görüntülenen tablo verilerini yazdırın. Birden fazla hücre seçilirse seçimi yazdırın. Ctrl+P Refresh Yenile Refresh the data in the selected table Seçilen tablodaki verileri yenile This button refreshes the data in the currently selected table. Bu buton, seçilen tablodaki verileri yeniler. F5 Find in cells Hücrelerde ara Open the find tool bar which allows you to search for values in the table view below. AÅŸağıdaki tablo görünümünde deÄŸerleri aramanıza izin veren bul araç çubuÄŸunu açın. Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally Bold Kalın Ctrl+B Italic İtalik Underline Altı çizili Ctrl+U Align Right SaÄŸa Hizala Align Left Sola Hizala Center Horizontally Yatayda Ortala Justify İki yana yasla Edit Conditional Formats... KoÅŸullu Biçimlendirmeyi Düzenle... Edit conditional formats for the current column Geçerli sütun için koÅŸullu biçimlendirmeyi düzenle Clear Format Biçimlendirmeleri Temizle Clear All Formats Tüm Biçimlendirmeleri Temizle Clear all cell formatting from selected cells and all conditional formats from selected columns Seçilen hücrelerdeki tüm hücre biçimlendirmelerini ve seçilen sütunlardaki tüm koÅŸullu biçimleri temizle Font Color Yazı Rengi Background Color Arka Plan Rengi Toggle Format Toolbar Biçim Araç ÇubuÄŸunu Aç/Kapat Show/hide format toolbar Biçim araç çubuÄŸunu göster/gizle This button shows or hides the formatting toolbar of the Data Browser Bu düğme Veri Görüntüleyici'nin biçimlendirme araç çubuÄŸunu gösterir veya gizler Select column Sütun seç Ctrl+Space Replace text in cells Hücrelerdeki metinleri deÄŸiÅŸtir Filter in any column Ctrl+R %n row(s) %n satır , %n column(s) , %n sütun . Sum: %1; Average: %2; Min: %3; Max: %4 . Toplam: %1; Ortalama: %2; Min: %3; Maks: %4 Conditional formats for "%1" "%1" için koÅŸullu biçimlendirme determining row count... satır sayısı belirleniyor... %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Bu görünümde düzenlemeyi etkinleÅŸtirmek için lütfen sözde birincil anahtar girin. Bu, görünümdeki benzersiz bir sütunun adı olmalıdır. Delete Records Kayıtları Sil Duplicate records Yinelenen kayıtlar Duplicate record Yinelenen kayıt Ctrl+" Adjust rows to contents Satırları içeriklere göre ayarlama Error deleting record: %1 Kayıt silme hatası: %1 Please select a record first Lütfen öncelikle kaydı seçiniz Please choose a new encoding for all tables. Lütfen tüm tablolar için yeni bir kodlama seçin. Please choose a new encoding for this table. Lütfen bu tablo için yeni bir kodlama seçin. %1 Leave the field empty for using the database encoding. %1 Veritabanı kodlamasını kullanmak için alanı boÅŸ bırakın. This encoding is either not valid or not supported. Bu kodlama geçerli deÄŸil veya desteklenmiyor. %1 replacement(s) made. %1 deÄŸiÅŸimi yapıldı. TableBrowserDock New Data Browser Rename Data Browser Close Data Browser Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. VacuumDialog Compact Database Veritabanını Sıkıştır Warning: Compacting the database will commit all of your changes. Uyarı: Veritabanını sıkıştırmak bütün deÄŸiÅŸikliklerinizi kaydedecektir. Please select the databases to co&mpact: Sıkıştır&mak istediÄŸiniz veritabanını seçiniz: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_uk_UA.ts000066400000000000000000013047021463772530400256100ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite Про ОглÑдач БД Ð´Ð»Ñ SQLite Version ВерÑÑ–Ñ <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record Enter values for the new record considering constraints. Fields in bold are mandatory. In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. Name Ім'Ñ Type Тип Value Values to insert. Pre-filled default values are inserted automatically unless they are changed. When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> Auto-increment Unique constraint Check constraint: %1 Foreign key: %1 Default value: %1 Error adding record. Message from database engine: %1 Are you sure you want to restore all the entered values to their defaults? Application Possible command line arguments: ДоÑтупні ключі командного Ñ€Ñдку: The user settings file location is replaced with the argument value instead of the environment variable value. Ignored environment variable (DB4S_SETTINGS_FILE) value: Usage options database project csv-file Show command line options Exit application after running scripts file Execute this SQL file after opening the DB Import this CSV file into the passed DB or into a new DB table Browse this table, or use it as target of a data import Open database in read-only mode settings_file Run application based on this settings file group settings value Run application with this setting temporarily set to value Run application saving this value for this setting Display the current version Open this SQLite database Open this project file (*.sqbpro) Import this CSV file into an in-memory database The %1 option requires an argument The -S/--settings option requires an argument. The option is ignored. The -o/--option and -O/--save-option options require an argument in the form group/setting=value Invalid option/non-existent file: %1 Ðевірна опціÑ/файл не Ñ–Ñнує: %1 SQLite Version ВерÑÑ–Ñ SQLite SQLCipher Version %1 (based on SQLite %2) DB Browser for SQLite Version %1. Last commit hash when built: %1 Built for %1, running on %2 Qt Version %1 The file %1 does not exist Файл %1 не Ñ–Ñнує CipherDialog SQLCipher encryption Ð¨Ð¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ SQLCipher &Password &Пароль &Reenter password &Пароль ще раз Encr&yption settings SQLCipher &3 defaults SQLCipher &4 defaults Custo&m Page si&ze &Розмір Ñторінки &KDF iterations HMAC algorithm KDF algorithm Plaintext Header Size Passphrase Парольна фраза Raw key Ðеоброблений ключ Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. Будь лаÑка, вкажіть ключ шифруваннÑ. Якщо Ви зміните будь-Ñке опційне налаштуваннÑ, то його доведетьÑÑ Ð²Ð²Ð¾Ð´Ð¸Ñ‚Ð¸ під Ñ‡Ð°Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу бази даних. Залиште Ð¿Ð¾Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»ÑŽ порожніми, щоб відімкнути шифруваннÑ. ÐŸÑ€Ð¾Ñ†ÐµÑ Ð¼Ð¾Ð¶Ðµ тривати деÑкий чаÑ. РекомендуєтьÑÑ Ñтворити резервну копію перед продовженнÑм! Ð’ÑÑ– незбережені зміни збережутьÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾. Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. Будь лаÑка, введіть ключ Ð´Ð»Ñ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних. Якщо будь-Ñкі інші Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÑƒÐ»Ð¸ змінені Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— бази даних, то потрібно надати цю інформацію також. ColumnDisplayFormatDialog Choose display format Оберіть формат показу Display format Формат показу Choose a display format for the column '%1' which is applied to each value prior to showing it. Оберіть формат показу Ð´Ð»Ñ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ¸ '%1'. Формат заÑтоÑуєтьÑÑ Ð´Ð¾ кожного Ñ—Ñ— значеннÑм. Default За замовчуваннÑм Decimal number ДеÑÑткове чиÑло Exponent notation ЕкÑпоненціальний Ð·Ð°Ð¿Ð¸Ñ Hex blob Бінарні дані Hex number ШіÑтнадцÑткове чиÑло Apple NSDate to date Дата Apple NSDate Java epoch (milliseconds) to date .NET DateTime.Ticks to date Julian day to date Дата за ЮліанÑьким календарем Unix epoch to local time WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy Lower case Ðижній регіÑтр Binary GUID to text SpatiaLite Geometry to SVG Custom display format must contain a function call applied to %1 Error in custom display format. Message from database engine: %1 Custom display format must return only one column but it returned %1. Octal number Ð’Ñ–Ñімкове чиÑло Round number Округлене чиÑло Unix epoch to date Unix-Ñ‡Ð°Ñ Upper case Верхній регіÑтр Windows DATE to date Windows дата Custom Мій формат CondFormatManager Conditional Format Manager This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. Add new conditional format &Add Remove selected conditional format &Remove Move selected conditional format up Move &up Move selected conditional format down Move &down Foreground Text color Background Фон Background color Font Шрифт Size Розмір Bold Жирний Italic КурÑив Underline ПідкреÑÐ»ÐµÐ½Ð½Ñ Alignment Condition Click to select color Are you sure you want to clear all the conditional formats of this field? DBBrowserDB Please specify the database name under which you want to access the attached database Будь лаÑка, вкажіть ім'Ñ Ð±Ð°Ð·Ð¸ даних, під Ñким Ви хочете отримати доÑтуп до під'єднаних баз даних Invalid file format Ðеправильний формат файлу Do you really want to close this temporary database? All data will be lost. Do you want to save the changes made to the database file %1? Зберегти зроблені зміни у файлі бази даних %1? Database didn't close correctly, probably still busy Cannot open destination file: '%1' Cannot backup to file: '%1'. Message: %2 The database is currently busy: Do you want to abort that other operation? Exporting database to SQL file... ЕкÑпорт бази даних у файл SQL... Cancel СкаÑувати No database file opened Executing SQL... Виконати код SQL... Action cancelled. Дію ÑкаÑовано. Error in statement #%1: %2. Aborting execution%3. Помилка в операторі #%1: %2. Ð’Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑкаÑовано%3. and rolling back Ñ– відкочено didn't receive any output from %1 could not execute command: %1 Cannot delete this object Cannot set data on this object Ðе вдаєтьÑÑ Ð²Ñтановити дані в цей об'єкт A table with the name '%1' already exists in schema '%2'. No table with name '%1' exists in schema '%2'. Cannot find column %1. Creating savepoint failed. DB says: %1 Renaming the column failed. DB says: %1 Releasing savepoint failed. DB says: %1 Creating new table failed. DB says: %1 Copying data to new table failed. DB says: %1 Deleting old table failed. DB says: %1 Error renaming table '%1' to '%2'. Message from database engine: %3 could not get list of db objects: %1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: Ðе вдалоÑÑ ÑкаÑувати Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð´ÐµÑких об'єктів, аÑоційованих із цією таблицею. Ðайімовірніша причина цього - зміна імен деÑких Ñтовпців таблиці. ОÑÑŒ SQL оператор, Ñкий потрібно виправити Ñ– виконати вручну: could not get list of databases: %1 Error loading extension: %1 Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ: %1 Error loading built-in extension: %1 could not get column information неможливо отримати інформацію про Ñтовпець Error setting pragma %1 to %2: %3 Помилка вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÐŸÑ€Ð°Ð³Ð¼Ð¸ %1 в %2: %3 File not found. Файл не знайдено. DbStructureModel Name Ім'Ñ Object Об'єкт Type Тип Schema Схема Database Browsables All Ð’Ñе Temporary Tables (%1) Таблиці (%1) Indices (%1) ІндекÑи (%1) Views (%1) ПереглÑди (%1) Triggers (%1) Тригери (%1) EditDialog Edit database cell Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ€ÐºÐ¸ бази даних Mode: Режим: This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. RTL Text Image Ð—Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ JSON XML Evaluation Automatically adjust the editor mode to the loaded data type This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. Auto-switch This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. Identification of the cell currently in the editor Type and size of data currently in table Open preview dialog for printing the data currently stored in the cell Auto-format: pretty print on loading, compact on saving. When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. Word Wrap Wrap lines on word boundaries Open in default application or browser Open in application The value is interpreted as a file or URL and opened in the default application or web browser. Save file reference... Save reference to file Open in external application Autoformat &Export... &Import... Import from file Opens a file dialog used to import any kind of data to this database cell. Export to file Opens a file dialog used to export the contents of this database cell to a file. Print... Ctrl+P Open preview dialog for printing displayed text Copy Hex and ASCII Copy selected hexadecimal and ASCII columns to the clipboard Ctrl+Shift+C Set as &NULL ПриÑвоїти &NULL Apply data to cell This button saves the changes performed in the cell editor to the database cell. Apply ЗаÑтоÑувати Text ТекÑÑ‚ Binary Двійкові дані Erases the contents of the cell ÐžÑ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð²Ð¼Ñ–Ñту комірки This area displays information about the data present in this database cell Ð¦Ñ Ð·Ð¾Ð½Ð° показує інформацію про дані, що Ñ” в цій комірці бази даних Choose a filename to export data Вибрати ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ Ð´Ð»Ñ ÐµÐºÑпорту даних Image data can't be viewed in this mode. Try switching to Image or Binary mode. Binary data can't be viewed in this mode. Try switching to Binary mode. Image files (%1) Binary files (*.bin) Type: NULL; Size: 0 bytes Type: Text / Numeric; Size: %n character(s) Type: %1 Image; Size: %2x%3 pixel(s) Type: Valid JSON; Size: %n character(s) Type: Binary; Size: %n byte(s) Couldn't save file: %1. Ðеможливо зберегти файл: %1. The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. Choose a file to import Оберіть файл Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. Unsaved data in the cell editor The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? Editing row=%1, column=%2 No cell active. %1 Image Invalid data for this mode The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? EditIndexDialog &Name &Ім'Ñ Order Ð¡Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ &Table &Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ Edit Index Schema Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑу Ñхеми &Unique &Унікальний For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed Ð”Ð»Ñ Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑу чаÑтиною таблиці оберіть пункт WHERE, Ñкий обере чаÑтину таблиці Ð´Ð»Ñ Ñ–Ð½Ð´ÐµÐºÑації Partial inde&x clause ЧаÑтковий ÐºÐ»Ð°Ñ Ñ–Ð½Ð´Ðµ&кÑа Colu&mns Стов&пці Table column Стовпець таблиці Type Тип Add a new expression column to the index. Expression columns contain SQL expression rather than column names. Додати новий Ñтовпець виразу до індекÑа. Стовпці виразів міÑÑ‚Ñть SQL вирази, а не імена Ñтовпців Index column Стовпець індекÑу Deleting the old index failed: %1 Ðевдале Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñтарого індекÑу: %1 Creating the index failed: %1 Ðевдале ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑу EditTableDialog Edit table definition Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– Table Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ Advanced Додатково Without Rowid Без ідентифікатора Fields ÐŸÐ¾Ð»Ñ Database sche&ma Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict Strict When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. Add Remove Move to top Move up Move down Move to bottom Name Ім'Ñ Type Тип NN Not null Ðе (null) PK ПК <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> AI ÐІ Autoincrement Ðвтоінкремент U У Unique Унікальне Default За замовчуваннÑм Default value Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм Check Перевірити Check constraint Перевірити Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Collation Foreign Key Зовнішній ключ <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> Index Constraints Add constraint Remove constraint Columns Стовпці SQL Foreign Keys References Check Constraints <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> Primary Key Add a primary key constraint Add a unique constraint There already is a field with that name. Please rename it first or choose a different name for this field. Поле з таким ім'Ñм уже Ñ–Ñнує. Будь лаÑка, переіменуйте його або виберіть інше ім'Ñ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ полÑ. There can only be one primary key for each table. Please modify the existing primary key instead. Error creating table. Message from database engine: %1 Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–. ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ Ñдра бази даних: %1 This column is referenced in a foreign key in table %1 and thus its name cannot be changed. Ðа цей Ñтовпець поÑилаєтьÑÑ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ–Ð¹ ключ у таблиці %1, тому Ñ—Ñ— ім'Ñ Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ змінити. There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. ІÑнує принаймні один Ñ€Ñдок, де це поле вÑтановлено в NULL. Ð’Ñтановити цей прапорець неможливо. Спочатку змініть дані таблиці. There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. ІÑнує принаймні один Ñ€Ñдок, де це поле міÑтить нечиÑлове значеннÑ. Ð’Ñтановити прапорець ÐІ неможливо. Спочатку змініть дані таблиці. Column '%1' has duplicate data. This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. Ви впевнені, що хочете видалити поле '%1'? Ð’ÑÑ– дані, Ñкі міÑÑ‚ÑтьÑÑ Ð² цьому полі, будуть втрачені. Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled Будь лаÑка, перед вÑтановленнÑм Ð¿Ñ€Ð°Ð¿Ð¾Ñ€Ñ†Ñ Ð±ÐµÐ· rowid додайте поле, Ñке має такі критерії: - вÑтановлено прапорець первинного ключа - відімкнений автоінкремент Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set ExportDataDialog Export data as CSV ЕкÑпортувати дані у форматі CSV Tab&le(s) &Таблиці Colu&mn names in first line &Імена Ñтовпців у першому Ñ€Ñдку Fie&ld separator &Роздільник полів , , ; ; Tab ТабулÑÑ†Ñ–Ñ | | Other Інший &Quote character &Символ лапок " " ' ' New line characters Ðовий роздільник Ñ€Ñдків Windows: CR+LF (\r\n) Windows: CR+LF (\r\n) Unix: LF (\n) Unix: LF (\n) Pretty print Гарний виÑновок Could not open output file: %1 Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ вихідний файл: %1 Choose a filename to export data Виберіть ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ Ð´Ð»Ñ ÐµÐºÑпорту даних Export data as JSON ЕкÑпортувати дані у форматі JSON exporting CSV Error while writing the file '%1': %2 exporting JSON Please select at least 1 table. Будь лаÑка, оберіть хоча б 1 таблицю. Choose a directory Оберіть каталог Export completed. ЕкÑпорт завершено. Export finished with errors. ExportSqlDialog Export SQL... ЕкÑпорт SQL... Tab&le(s) &Таблиці Select All Обрати вÑе Deselect All СкаÑувати вибір &Options &Опції Keep column names in INSERT INTO Імена Ñтовпців у виразі INSERT INTO Multiple rows (VALUES) per INSERT statement Кілька Ñ€Ñдків (VALUES) на INSERT вираз Export everything ЕкÑпортувати вÑÑ– Export data only ЕкÑпортувати тільки дані Keep original CREATE statements Keep old schema (CREATE TABLE IF NOT EXISTS) Стара Ñхема (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) ПерезапиÑати Ñтару Ñхему (DROP TABLE, тоді CREATE TABLE) Export schema only ЕкÑпортувати тільки Ñхему даних Please select at least one table. Choose a filename to export Оберіть ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ Ð´Ð»Ñ ÐµÐºÑпорту Export completed. ЕкÑпорт завершено. Export cancelled or failed. ЕкÑпорт ÑкаÑовано або виникла помилка. ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... Find and Replace... Print... ExtendedTableWidget Use as Exact Filter Containing Not containing Not equal to Greater than Less than Greater or equal Less or equal Between this and... Regular expression Edit Conditional Formats... Set to NULL Ð’Ñтановити в NULL Cut Copy Копіювати Copy with Headers Copy as SQL Paste Ð’Ñтавити Print... Use in Filter Expression Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? ВміÑÑ‚ буфера обміну більше ніж обраний діапазон. Ð’Ñе одно вÑтавити? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. Cannot set selection to NULL. Column %1 has a NOT NULL constraint. FileExtensionManager File Extension Manager &Up &Down &Add &Remove Description Extensions *.extension FilterLineEdit Filter Фільтр These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression Clear All Conditional Formats Use for Conditional Format Edit Conditional Formats... Set Filter Expression What's This? Is NULL Is not NULL Is empty Is not empty Not containing... Equal to... Not equal to... Greater than... Less than... Greater or equal... Less or equal... In range... Regular expression... FindReplaceDialog Find and Replace Fi&nd text: Re&place with: Match &exact case Match &only whole words When enabled, the search continues from the other end when it reaches one end of the page &Wrap around When set, the search goes backwards from cursor position, otherwise it goes forward Search &backwards <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> &Selection only <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Use regular e&xpressions Find the next occurrence from the cursor position and in the direction set by "Search backwards" &Find Next F3 &Replace Highlight all the occurrences of the text in the page F&ind All Replace all the occurrences of the text in the page Replace &All The searched text was not found The searched text was not found. The searched text was found one time. The searched text was found %1 times. The searched text was replaced one time. The searched text was replaced %1 times. ForeignKeyEditor &Reset &Скинути Foreign key clauses (ON UPDATE, ON DELETE etc.) ImageViewer Image Viewer Reset the scaling to match the original size of the image. Set the scaling to match the size of the viewport. Print... Open preview dialog for printing displayed image Ctrl+P ImportCsvDialog Import CSV file Імпортувати файл у форматі CSV Table na&me &Column names in first line І&мена Ñтовпців у першому Ñ€Ñдку Field &separator &Роздільник полів , , ; ; Tab ТабулÑÑ†Ñ–Ñ | | Other Інший &Quote character &Символ лапок Other (printable) Other (code) " " ' ' &Encoding &ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? Обрізати полÑ? Separate tables Розділити таблиці Advanced Додатково When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. Ignore default &values Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. Fail on missing values Disable data type detection Disable the automatic data type detection when creating a new table. Use local number conventions Use decimal and thousands separators according to the system locale. When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. Abort import Ignore row Replace existing row Conflict strategy Deselect All СкаÑувати вибір Match Similar Ð¡Ð¿Ñ–Ð²Ð¿Ð°Ð´Ñ–Ð½Ð½Ñ Select All Обрати вÑе There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. There is already a table named '%1'. Do you want to import the data into it? Creating restore point failed: %1 Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸ відновленнÑ: %1 Creating the table failed: %1 Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–: %1 importing CSV Could not prepare INSERT statement: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. Inserting row failed: %1 Помилка вÑтавки Ñ€Ñдка: %1 MainWindow DB Browser for SQLite ОглÑдач Ð´Ð»Ñ SQLite toolBar1 панельІнÑтрументів1 &Remote &Віддалений &File &Файл &Database Structure This has to be equal to the tab title in all the main tabs &Browse Data This has to be equal to the tab title in all the main tabs Edit P&ragmas This has to be equal to the tab title in all the main tabs &Import &Імпорт &Export &ЕкÑпорт &Edit &Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ &View &Вид &Help &Довідка Too&ls DB Toolbar Панель інÑтрументів БД Edit Database &Cell Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ &комірки БД Error Log This button clears the contents of the SQL logs This panel lets you examine a log of all SQL commands issued by the application or by yourself DB Sche&ma Схе&ма БД Execute current line Виконати поточний Ñ€Ñдок This button executes the SQL statement present in the current editor line Shift+F5 Sa&ve Project &Зберегти проект Opens the SQLCipher FAQ in a browser window Відкрити SQLCiphier ЧаПи в браузері Export one or more table(s) to a JSON file ЕкÑпортувати таблиці в JSON файл Save SQL file as Зберегти файл SQL Ñк This button saves the content of the current SQL editor tab to a file &Browse Table Пе&реглÑд таблиці User КориÑтувачем Application Додатком &Clear О&чиÑтити &New Database... &Ðова база даних... Create a new database file Створити новий файл бази даних This option is used to create a new database file. Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтовуєтьÑÑ Ñ‰Ð¾Ð± Ñтворити новий файл бази даних. Ctrl+N &Open Database... &Відкрити базу даних... Open an existing database file Відкрити Ñ–Ñнуючий файл бази даних This option is used to open an existing database file. Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтовуєтьÑÑ, щоб відкрити Ñ–Ñнуючий файл бази даних. Ctrl+O &Close Database &Закрити базу даних This button closes the connection to the currently open database file Ctrl+W Revert database to last saved state Повернути базу даних до оÑтаннього збереженого Ñтану This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтовуєтьÑÑ, щоб повернути поточний файл бази даних до його оÑтаннього збереженого Ñтану. Ð’ÑÑ– зміни, зроблені з оÑтанньої операції збереженнÑ, буде втрачено. Write changes to the database file ЗапиÑати зміни у файл бази даних This option is used to save changes to the database file. Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтовуєтьÑÑ, щоб зберегти зміни у файлі бази даних. Ctrl+S Compact &Database... Compact the database file, removing space wasted by deleted records Ущільнити базу даних, видаливши проÑтір, зайнÑтий видаленими запиÑами Compact the database file, removing space wasted by deleted records. Ущільнити базу даних, видаливши проÑтір, зайнÑтий видаленими запиÑами. E&xit &Вихід Ctrl+Q Import data from an .sql dump text file into a new or existing database. Імпортувати дані з текÑтового файлу .sql в нову або Ñ–Ñнуючу базу даних. This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð´Ð°Ñ” змогу імпортувати дані з текÑтового файлу .sql у нову або Ñ–Ñнуючу базу даних. Файл SQL можна Ñтворити на більшоÑті двигунів баз даних, включно з MySQL Ñ– PostgreSQL. Open a wizard that lets you import data from a comma separated text file into a database table. Відкрити майÑтер, Ñкий дає змогу імпортувати дані з файлу CSV у таблицю бази даних. Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. Відкрити майÑтер, Ñкий дає змогу імпортувати дані з файлу CSV у таблицю бази даних. Файли CSV можна Ñтворити в більшоÑті програм баз даних Ñ– електронних таблиць. Export a database to a .sql dump text file. ЕкÑпортувати базу даних у текÑтовий файл .sql. This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð´Ð°Ñ” змогу екÑпортувати базу даних у текÑтовий файл .sql. Файли SQL міÑÑ‚Ñть вÑÑ– дані, необхідні Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð±Ð°Ð·Ð¸ даних у більшоÑті движків баз даних, включно з MySQL Ñ– PostgreSQL. &Table(s) as CSV file... Таблиці у файл CSV... Export a database table as a comma separated text file. ЕкÑпортувати таблицю бази даних Ñк CSV текÑтовий файл. Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. ЕкÑпортувати таблицю бази даних Ñк CSV текÑтовий файл, готовий Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð² інші бази даних або програми електронних таблиць. Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database Відкрити майÑтер ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†ÑŒ, де можливо визначити ім'Ñ Ñ– Ð¿Ð¾Ð»Ñ Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ñ— таблиці в базі даних Open the Delete Table wizard, where you can select a database table to be dropped. Відкрити майÑтер Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–, де можна вибрати таблицю бази даних Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ. Open the Create Index wizard, where it is possible to define a new index on an existing database table. Відкрити майÑтер ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð†Ð½Ð´ÐµÐºÑу, в Ñкому можна визначити новий Ñ–Ð½Ð´ÐµÐºÑ Ð´Ð»Ñ Ñ–Ñнуючої таблиці бази даних. &Preferences... &ÐалаштуваннÑ... Open the preferences window. Відкрити вікно налаштувань. &DB Toolbar &Панель інÑтрументів БД Shows or hides the Database toolbar. Показати або приховати панель інÑтрументів БД. Shift+F1 New &tab Execute all/selected SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. Open SQL file(s) This button opens files containing SQL statements and loads them in new editor tabs Ctrl+Shift+T Execute line &Wiki F1 Bug &Report... Feature Re&quest... Web&site &Donate on Patreon... &Save Project Open &Project &Attach Database... Add another database file to the current database connection This button lets you add another database file to the current database connection &Set Encryption... SQLCipher &FAQ Table(&s) to JSON... Open Data&base Read Only... Ctrl+Shift+O Save results Save the results view This button lets you save the results of the last executed query Find text in SQL editor Find This button opens the search bar of the editor Ctrl+F Find or replace text in SQL editor Find or replace This button opens the find/replace dialog for the current editor tab Ctrl+H Export to &CSV ЕкÑпортувати в &CSV Export to &JSON Save as &view Зберегти Ñк &виглÑд Save as view Зберегти Ñк виглÑд &Open Database Drag && Drop SELECT Query When dragging fields from the same table or a single table, drop a SELECT query into the editor Browse Table Close Pro&ject Close project and database files and return to the initial state Ctrl+Shift+W Table from CSV data in Clipboard... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. Show &Row Counts This shows the number of rows for each table and view in the database. Save Database &As... Save the current database as a different file Refresh Оновити Reload the database structure Ctrl+Shift+F4 Detach Database Detach database file attached to the current database connection Shows or hides the Project toolbar. This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file This button lets you open a DB Browser for SQLite project file Extra DB Toolbar New In-&Memory Database Drag && Drop Qualified Names Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor Drag && Drop Enquoted Names Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor &Integrity Check Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. &Foreign-Key Check Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab &Quick Integrity Check Run a quick integrity check over the open DB Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. &Optimize Attempt to optimize the database Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. Print Print text from current SQL editor tab Open a dialog for printing the text in the current SQL editor tab Print the structure of the opened database Open a dialog for printing the structure of the opened database &Save Project As... Save the project in a file selected in a dialog Save A&ll Save DB file, project file and opened SQL files Ctrl+Shift+S &Recently opened &Ðедавно відкриті Open an existing database file in read only mode Відкрити Ñ–Ñнуючий файл БД у режимі тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ctrl+T This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. Un/comment block of SQL code Un/comment block Comment or uncomment current line or selected block of code Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. Ctrl+/ Stop SQL execution Stop execution Stop the currently running SQL script Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. E&xecute SQL This has to be equal to the tab title in all the main tabs &Recent Files SQL &Log &Журнал SQL Show S&QL submitted by По&казати SQL, Ñкий виконано &Plot &Графік This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. Project Toolbar Extra DB toolbar Close the current database file &New Database Ctrl+F4 &Revert Changes &СкаÑувати зміни &Undo Undo last change to the database This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. &Write Changes &ЗапиÑати зміни &Database from SQL file... &База даних з файлу SQL... &Table from CSV file... &Таблиці з файлу CSV... &Database to SQL file... Базу &даних в файл SQL... &Create Table... &Створити таблицю... &Delete Table... &Видалити таблицю... &Modify Table... &Змінити таблицю... Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. Create &Index... Створити Ñ–&ндекÑ... W&hat's This? Що &це таке? &About This button opens a new tab for the SQL editor &Execute SQL Ви&конати код SQL Save SQL file Зберегти файл SQL &Load Extension... Ctrl+E Export as CSV file ЕкÑпортувати у файл CSV Export table as comma separated values file ЕкÑпортувати таблицю Ñк CSV файл Save the current session to a file Зберегти поточний Ñтан у файл Open &Project... Load a working session from a file Завантажити робочий Ñтан із файлу Copy Create statement Копіювати CREATE вираз Copy the CREATE statement of the item to the clipboard Копіювати CREATE вираз елемента в буффер обміну Ctrl+Return Ctrl+L Ctrl+P Ctrl+D Ctrl+I Encrypted Зашифрований Read only Тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Database file is read only. Editing the database is disabled. База даних тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ. Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð±Ð¾Ñ€Ð¾Ð½ÐµÐ½Ðµ. Database encoding ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних Database is encrypted using SQLCipher База даних зашифрована з викориÑтаннÑм SQLCipher Choose a database file Вибрати файл бази даних Could not open database file. Reason: %1 Ðеможливо відкрити файл бази даних. Причина: %1 Choose a filename to save under Вибрати ім'Ñ, під Ñким зберегти дані A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. Вийшла нова верÑÑ–Ñ Ð¾Ð³Ð»Ñдача Ð´Ð»Ñ SQLite (%1.%2.%3).<br/><br/>Вона доÑтупна Ð´Ð»Ñ ÑÐºÐ°Ñ‡ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° поÑиланнÑм <a href='%4'>%4</a>. DB Browser for SQLite project file (*.sqbpro) Файл проекту оглÑдача Ð´Ð»Ñ SQLite (*.sqbpro) Are you sure you want to undo all changes made to the database file '%1' since the last save? СкаÑувати вÑÑ– зміни, зроблені у файлі бази даних '%1' піÑÐ»Ñ Ð¾Ñтаннього збереженнÑ? Choose a file to import Оберіть файл Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. Створити новий файл бази даних Ð´Ð»Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ð¾Ð²Ð°Ð½Ð¸Ñ… даних? Якщо відповідь ÐÑ–, то здійÑнитьÑÑ Ñпроба імпортувати дані файлу SQL в поточну базу даних. File %1 already exists. Please choose a different name. Файл %1 вже Ñ–Ñнує. Оберіть інше ім'Ñ. Error importing data: %1 Помилка Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ…: %1 Import completed. Імпорт завершено. Delete View Видалити переглÑд Delete Trigger Видалити тригер Delete Index Видалити Ñ–Ð½Ð´ÐµÐºÑ Reset Window Layout Automatically load the last opened DB file at startup The database is currently busy. Click here to interrupt the currently running query. Ctrl+Alt+W In-Memory database Choose a database file to save under Error while saving the database to the new file. Do you want to save the changes made to the project file '%1'? Are you sure you want to delete the table '%1'? All data associated with the table will be lost. Are you sure you want to delete the view '%1'? Are you sure you want to delete the trigger '%1'? Are you sure you want to delete the index '%1'? Error: could not delete the table. Error: could not delete the view. Error: could not delete the trigger. Error: could not delete the index. Message from database engine: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? Error checking foreign keys after table modification. The changes will be reverted. This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. Edit View %1 Edit Trigger %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. -- EXECUTING SELECTION IN '%1' -- -- EXECUTING LINE IN '%1' -- -- EXECUTING ALL IN '%1' -- At line %1: Result: %1 Result: %2 Execution finished with errors. Execution finished without errors. Opened '%1' in read-only mode from recent file list Opened '%1' from recent file list &%1 %2%3 &%1 %2%3 (read only) Open Database or Project Attach Database... Import CSV file(s)... Do you want to save the changes made to SQL tabs in the project file '%1'? The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? DB file '%1' could not be opened This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. Table '%1' not found; settings ignored -- Reference to file "%1" (not supported by this version) -- Project saved to file '%1' Yes. Don't ask again This action will open a new SQL tab with the following statements for you to edit and run: Busy (%1) Rename Tab Duplicate Tab Close Tab Opening '%1'... There was an error opening '%1'... Value is not a valid URL or filename: %1 %1 rows returned in %2ms Ctrl+Tab Ctrl+Shift+Tab Clear List Window Layout Ctrl+Alt+0 Simplify Window Layout Alt+Shift+0 Dock Windows at Bottom Dock Windows at Left Side Dock Windows at Top You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? Import completed. Some foreign key constraints are violated. Please fix them before saving. Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. Do you want to save the changes made to SQL tabs in a new project file? Do you want to save the changes made to the SQL file %1? Could not find resource file: %1 Choose a project file to open Could not open project file for writing. Reason: %1 Collation needed! Proceed? Потрібно виконати зіÑтавленнÑ! Продовжити? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ Ð² базі даних вимагає Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñпеціальної функції зіÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð½Ñ '%1'. Якщо Ви продовжите, то можливе пÑÑƒÐ²Ð°Ð½Ð½Ñ Ð’Ð°ÑˆÐ¾Ñ— бази даних. Створіть резервну копію! creating collation Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. Please specify the view name Вкажіть ім'Ñ Ð²Ð¸Ð³Ð»Ñду There is already an object with that name. Please choose a different name. Об'єкт із зазначеним ім'Ñм уже Ñ–Ñнує. Виберіть інше ім'Ñ. View successfully created. ВиглÑд уÑпішно Ñтворений. Error creating view: %1 Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð²Ð¸Ð³Ð»Ñду: %1 This action will open a new SQL tab for running: Press Help for opening the corresponding SQLite reference page. Delete Table Видалити таблицю Setting PRAGMA values will commit your current transaction. Are you sure? Ð’ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½ÑŒ PRAGMA завершить поточну транзакцію. Ð’Ñтановити значеннÑ? Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? Choose text files Оберіть текÑтові файли Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 Помилка під Ñ‡Ð°Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ бази даних. Це означає, що не вÑÑ– зміни в базу даних було збережено. Спочатку Вам необхідно розв'Ñзати таку помилку. %1 Text files(*.sql *.txt);;All files(*) ТекÑтові файли(*.sql *.txt);;Ð’ÑÑ– файли(*) Modify View Змінити вид Modify Trigger Змінити тригер Modify Index Змінити Ñ–Ð½Ð´ÐµÐºÑ Modify Table Змінити таблицю Select SQL file to open Обрати файл SQL Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ð²Ð°Ð½Ð½Ñ Select file name Обрати ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ Select extension file Обрати Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ Extension successfully loaded. Ð Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ ÑƒÑпішно завантажено. Error loading extension: %1 Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ: %1 Don't show again Ðе показувати наÑтупного разу New version available. ДоÑтупна нова верÑÑ–Ñ. NullLineEdit Set to NULL Ð’Ñтановити в NULL Alt+Del PlotDock Plot Графік <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> Columns Стовпці X X Y1 Y2 Axis Type Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. Line type: Тип лінії: None ÐÑ– Line Звичайна StepLeft Ступенева, зліва StepRight Ступенева, Ñправа StepCenter Ступенева, по центру Impulse Ð†Ð¼Ð¿ÑƒÐ»ÑŒÑ Point shape: Форма точок: Cross ХреÑÑ‚ Plus ÐŸÐ»ÑŽÑ Circle Коло Disc ДиÑк Square Квадрат Diamond Ромб Star Зірка Triangle Трикутник TriangleInverted Трикутник перевернутий CrossSquare ХреÑÑ‚ у квадраті PlusSquare ÐŸÐ»ÑŽÑ Ñƒ квадраті CrossCircle ХреÑÑ‚ у колі PlusCircle ÐŸÐ»ÑŽÑ Ñƒ колі Peace Світ <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>Зберегти поточний графік...</p><p>Формат файлу вибираєтьÑÑ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñм (png, jpg, pdf, bmp)</p></body></html> Save current plot... Зберегти поточний графік... Load all data and redraw plot Row # РÑдок # Copy Копіювати Print... Show legend Stacked bars Fixed number format Date/Time Date Time Numeric Label Invalid Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. Choose an axis color Choose a filename to save under Вибрати ім'Ñ, під Ñким зберегти дані PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Ð’ÑÑ– файли(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. Loading all remaining data for this table took %1ms. PreferencesDialog Preferences ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ &Database &База даних Database &encoding &ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних Open databases with foreign keys enabled. Відкривати бази даних з увімкненими зовнішніми ключами. &Foreign keys &Зовнішні ключі enabled увімкнені Default &location &Ð Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовчуваннÑм ... ... &General &Загальні Remember last location Запам'Ñтовувати оÑтанню директорію Always use this location Завжди відкривати це Ñ€Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Remember last location for session only Запам'Ñтовувати оÑтанню директорію тільки Ð´Ð»Ñ ÑеÑÑ–Ñ— Lan&guage &Мова Toolbar style Only display the icon Only display the text The text appears beside the icon The text appears under the icon Follow the style Automatic &updates &Стежити за оновленнÑми DB file extensions Manage SQ&L to execute after opening database SQ&L,Ñкий треба Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¿Ñ–ÑÐ»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ð²Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних Data &Browser ОглÑдач &даних Remove line breaks in schema &view Видалити розрив Ñ€Ñдка в &Ñхемі даних Show remote options Показати віддалені опції Prefetch block si&ze Розмір блоку &вибірки Default field type Тип даних за замовчуваннÑм Font Шрифт &Font &Шрифт Content ВміÑÑ‚ Symbol limit in cell КількіÑть Ñимволів у оÑередку NULL NULL Regular Звичайні Binary Двійкові дані Background Фон Filters Фільтри Threshold for completion and calculation on selection Show images in cell Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. Escape character Символ ÐµÐºÑ€Ð°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Delay time (&ms) Ð§Ð°Ñ Ð·Ð°Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸ (&мÑ) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. Ð§Ð°Ñ Ð·Ð°Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸ перед заÑтоÑуваннÑм нового фільтра. Ðульове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÑÑ” очікуваннÑ. &SQL Р&едактор SQL Context КонтекÑÑ‚ Colour Колір Bold Жирний Italic КурÑив Underline ПідкреÑÐ»ÐµÐ½Ð½Ñ Keyword Ключове Ñлово Function Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ Table Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ Comment Коментар Identifier Ідентифікатор String РÑдок Current line Поточна Ñ€Ñдок SQL &editor font size Розмір шрифту в &редакторі SQL Tab size Розмір табулÑції SQL editor &font &Шрифт у редакторі SQL Error indicators Індикатори помилок Hori&zontal tiling Гори&зонтальний розподіл If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. Якщо Ñ†Ñ Ð¾Ð¿Ñ†Ñ–Ñ ÑƒÐ²Ñ–Ð¼ÐºÐ½ÐµÐ½Ð°, то SQL редактор Ñ– результат запиту будуть розташовані поруч по горизонталі. Code co&mpletion Ðвто&Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÐºÐ¾Ð´Ñƒ Main Window Database Structure Структура БД Browse Data ПереглÑнути дані Execute SQL Виконати SQL Edit Database Cell Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ€ÐºÐ¸ БД When this value is changed, all the other color preferences are also set to matching colors. Follow the desktop style Dark style Application style This sets the font size for all UI elements which do not have their own font size option. Font size Max Recent Files Prompt to save SQL tabs in new project file If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. Database structure font size Font si&ze This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. Field display Light style Displayed &text Formatted Click to set this color Text color Background color Preview only (N/A) Foreground Selection background Selection foreground Highlight SQL &results font size Use tabs for indentation When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. &Wrap lines Never At word boundaries At character boundaries At whitespace boundaries &Quotes for identifiers Choose the quoting mechanism used by the application for identifiers in SQL code. "Double quotes" - Standard SQL (recommended) `Grave accents` - Traditional MySQL quotes [Square brackets] - Traditional MS SQL Server quotes Keywords in &UPPER CASE When set, the SQL keywords are completed in UPPER CASE letters. When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background Close button on tabs If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. &Extensions Р&Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Select extensions to load for every database: Оберіть розширеннÑ, щоб завантажувати Ñ—Ñ… Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ñ— бази даних: Add extension Додати Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Remove extension Видалити Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>ОглÑдач Ð´Ð»Ñ SQLite дає змогу викориÑтовувати оператор REGEXP 'з коробки'. Ðле попри<br/>це, можливі кілька різних варіантів реалізацій цього оператора й Ви вільні<br/>у виборі, Ñкий Ñаме викориÑтовувати. Можна відімкнути нашу реалізацію та викориÑтовувати іншу -<br/>шлÑхом Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð½Ð¾Ð³Ð¾ розширеннÑ. Ð’ цьому випадку потрібно перезавантажити програму.</p></body></html> <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> Allow loading extensions from SQL code Clone databases into Клонувати бази даних до Proxy Configure Export Settings Import Settings Disable Regular Expression extension Відімкнути Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð ÐµÐ³ÑƒÐ»Ñрних Виразів Remote Віддалений Ñервер CA certificates СÐ-Ñертифікати Subject CN Об'єкт CN Common Name Звичайне ім'Ñ Subject O Об'єкт O Organization ÐžÑ€Ð³Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Valid from ДійÑний з Valid to ДійÑний до Serial number Серійний номер Your certificates Ваш Ñертифікат File Файл Subject Common Name Звичайне ім'Ñ Ð¾Ð±'єкта Issuer CN РозповÑюдник CN Issuer Common Name Звичайне ім'Ñ Ñ€Ð¾Ð·Ð¿Ð¾Ð²Ñюдника Choose a directory Оберіть каталог The language will change after you restart the application. Мова змінитьÑÑ Ð¿Ñ–ÑÐ»Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿ÑƒÑку програми. Select extension file Обираємо файл Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Extensions(*.so *.dylib *.dll);;All files(*) Import certificate file Імпортувати файл Ñертифіката No certificates found in this file. Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу не знайдено Ñертифікатів. Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! Ви впевнені, що хочете видалити цей Ñертифікат? Ð’ÑÑ– дані Ñертифіката видалÑтьÑÑ Ð· налаштувань програми! Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. Save Settings File Initialization File (*.ini) The settings file has been saved in location : Open Settings File The settings file was loaded properly. The selected settings file is not a normal settings file. Please check again. ProxyDialog Proxy Configuration Pro&xy Type Host Na&me Port Authentication Re&quired &User Name Password None ÐÑ– System settings HTTP SOCKS5 QObject Error importing data Помилка Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… from record number %1 з запиÑу номер %1 . %1 . %1 Importing CSV file... Cancel СкаÑувати All files (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) Left Right Center Justify SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) SQL Files (*.sql) All Files (*) Text Files (*.txt) Comma-Separated Values Files (*.csv) Tab-Separated Values Files (*.tsv) Delimiter-Separated Values Files (*.dsv) Concordance DAT files (*.dat) JSON Files (*.json *.js) XML Files (*.xml) Binary Files (*.bin *.dat) SVG Files (*.svg) Hex Dump Files (*.dat *.bin) Extensions (*.so *.dylib *.dll) Initialization File (*.ini) QsciCommand Paste Ð’Ñтавити Cancel СкаÑувати QsciLexerCPP Default За замовчуваннÑм Keyword Ключове Ñлово Identifier Ідентифікатор QsciLexerJSON Default За замовчуваннÑм String РÑдок QsciLexerPython Default За замовчуваннÑм Comment Коментар Keyword Ключове Ñлово Identifier Ідентифікатор QsciLexerSQL Default За замовчуваннÑм Comment Коментар Keyword Ключове Ñлово Identifier Ідентифікатор QsciScintilla Select All Обрати вÑе RemoteCommitsModel Commit ID Message Date Author Size Розмір Authored and committed by %1 Authored by %1, committed by %2 RemoteDatabase Error opening local databases list. %1 Помилка Ð²Ñ–Ð´ÐºÑ€Ð¸Ð²Ð°Ð½Ð½Ñ ÑпиÑку локальних баз даних. %1 Error creating local databases list. %1 Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÑпиÑку локальних баз даних. %1 RemoteDock Remote Віддалений Local Локальний Identity Ідентичний Push currently opened database to server Upload DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> Current Database Clone &User &Database &База даних Branch Commits Commits for <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> Back Delete Database Delete the local clone of this database Open in Web Browser Open the web page for the current database in your browser Clone from Link Use this to download a remote database for local editing using a URL as provided on the web page of the database. Refresh Оновити Reload all data and update the views Clone Database Open Database Open the local copy of this database Check out Commit Download and open this specific commit Check out Latest Commit Check out the latest commit of the current branch Save Revision to File Saves the selected revision of the database to another file Upload Database Upload this database as a new commit Select an identity to connect Public This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. Invalid URL: The host name does not match the host name of the current identity. Invalid URL: No branch name specified. Invalid URL: No commit ID specified. You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? The database has unsaved changes. Are you sure you want to push it before saving? The database you are trying to delete is currently opened. Please close it before deleting. This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? RemoteLocalFilesModel Name Ім'Ñ Branch Last modified ВоÑтаннє змінений Size Розмір Commit File Файл RemoteModel Name Ім'Ñ Last modified ВоÑтаннє змінений Size Розмір Commit Size: Last Modified: Licence: Default Branch: RemoteNetwork Choose a location to save the file Error opening remote file at %1. %2 Помилка під Ñ‡Ð°Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ð²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð¾Ð³Ð¾ файлу %1. %2 Error: Invalid client certificate specified. Помилка: Вказано неправильний Ñертифікат клієнта. Please enter the passphrase for this client certificate in order to authenticate. Будь лаÑка, введіть парольну фразу Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ñертифіката клієнта, Ð´Ð»Ñ Ð°Ð²Ñ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ— Cancel СкаÑувати Uploading remote database to %1 Ð’Ð¸Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð¾Ñ— бази даних до %1. {1?} Downloading remote database from %1 Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð¾Ñ— бази даних із %1. {1?} Error: Cannot open the file for sending. Помилка: Ðеможливо відкрити файл Ð´Ð»Ñ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ. RemotePushDialog Push database Database na&me to push to Commit message Database licence Public Branch Force push Username Database will be public. Everyone has read access to it. Database will be private. Only you have access to it. Use with care. This can cause remote commits to be deleted. RunSql Execution aborted by user Ð’Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑкаÑовано кориÑтувачем , %1 rows affected , %1 Ñ€Ñдків поÑтраждало query executed successfully. Took %1ms%2 executing query SelectItemsPopup A&vailable Sele&cted SqlExecutionArea Form Форма Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 The found pattern must be a whole word Whole Words Text pattern to find considering the checks in this frame Find in editor The found pattern must match in letter case Case Sensitive Find next match [Enter, F3] Find next match with wrapping F3 Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Close Find Bar <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> Results of the last executed statements Результати оÑтанніх виконаних операторів This field shows the results and status codes of the last executed statements. Це поле показує результати та коди ÑтатуÑів оÑтанніх виконаних операторів. Ctrl+PgUp Ctrl+PgDown Couldn't read file "%1": %2. Couldn't save file: %1. Ðеможливо зберегти файл: %1. Your changes will be lost when reloading it! The file "%1" was modified by another program. Do you want to reload it?%2 Answer "Yes to All" to reload the file on any external update without further prompting. Answer "No to All" to ignore any external update without further prompting. Modifying and saving the file will restore prompting. SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ abs(X) повертає модуль чиÑла аргументу X. () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ changes() повертає кількіÑть Ñ€Ñдків у базі даних, Ñкі було змінено, вÑтавлено або видалено піÑÐ»Ñ Ð²Ð´Ð°Ð»Ð¾Ð³Ð¾ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ INSERT, DELETE або UPDATE. (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ coalesce() повертає копію першого аргументу не-NULL, Ñкщо такого немає, то повертає NULL (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ ifnull() повертає копію першого аргументу не-NULL, або Ñкщо обидва аргумента NULL, то повертає NULL. (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ instr(X,Y) повертає кількіÑть Ñимволів, починаючи з Ñкого в Ñ€Ñдку X знайдено підрÑдок Y, або 0, Ñкщо такого не знайдено. (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ hex() інтерпретує аргумент Ñк BLOB Ñ– повертає Ñ€Ñдок в 16-ричній ÑиÑтемі чиÑÐ»ÐµÐ½Ð½Ñ Ñ–Ð· вміÑтом аргументу. (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ last_insert_rowid() повертає ROWID оÑтаннього вÑтавленого Ñ€Ñдка. (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) Ð”Ð»Ñ Ñтрокового Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ X, Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ length(X) повертає кількіÑть Ñимволів (ÐЕ байтів) від початку Ñ€Ñдка до першого Ñимволу '\0'. (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) Ñ„ÑƒÐºÐ½Ñ†Ñ–Ñ like() еквівалентна виразу "Y LIKE X". (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ like() еквівалент Ð²Ð¸Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ "Y LIKE X ESCAPE Z". (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ lower(X) повертає копію Ñ€Ñдка X, в Ñкій уÑÑ– ACSII Ñимволи переведені в нижній регіÑтр. (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) видалÑÑ” Ñимволи пробілів зліва Ð´Ð»Ñ Ñ€Ñдка X. (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ char(X1,X2,...,XN) повертає Ñ€Ñдок, Ñкладений із Ñимволів, переданих Ñк аргументи. (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ glob(X,Y) еквівалент Ð²Ð¸Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ "Y GLOB X". (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ ltrim (X,Y) повертає новий Ñ€Ñдок шлÑхом Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð· Ñ€Ñдка X зліва будь-Ñкого Ñимволу з Y. (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ max() повертає аргумент з макÑимальним значеннÑм, або NULL, Ñкщо хоча б один аргумент дорівнює NULL. (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ min() повертає аргумент з мінімальним значеннÑм. (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ nullif(X,Y) повертає перший аргумент, Ñкщо аргументи різні, або NULL, Ñкщо вони однакові. (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ printf(FORMAT,...) працює так Ñамо, Ñк printf() зі Ñтандартної бібліотеки мови Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼ÑƒÐ²Ð°Ð½Ð½Ñ Ð¡Ñ–. (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ quote(X) повертає змінений Ñ€Ñдок X, Ñкий можна викориÑтовувати в SQL виразах. () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ random() повертає пÑевдовипадкове цілочиÑельне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð· діапозона від -9223372036854775808 до +9223372036854775807. (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ randomblob(N) повертає N-байтний BLOB, що міÑтить пÑевдовипадкові байти. (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ replace(X,Y,Z) повертає новий Ñ€Ñдок на оÑнові Ñ€Ñдка X, заміною вÑÑ–Ñ… підрÑдків Y на Z. (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ round(X) округлює X до цілого значеннÑ. (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ round(X,Y) округлює X до Y чиÑел піÑÐ»Ñ ÐºÐ¾Ð¼Ð¸ праворуч. (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) видалÑÑ” Ñимволи пробілу праворуч від Ñ€Ñдка X. (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ rtrim(X,Y) повертає новий Ñ€Ñдок шлÑхом Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð· Ñ€Ñдка X праворуч будь-Ñкого Ñимволу з Ñ€Ñдка Y. (timestring,modifier,modifier,...) (timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) (format,timestring,modifier,modifier,...) () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (X) Return the arccosine of X. The result is in radians. (X) Return the hyperbolic arccosine of X. (X) Return the arcsine of X. The result is in radians. (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. () Return an approximation for Ï€. (X,Y) Compute X raised to the power Y. (X) Convert X from degrees into radians. (X) Return the sine of X. X is in radians. (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ soundex(X) повертає копію Ñ€Ñдка X, кодовану в форматі soundex. (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) повертає підрÑдок з Ñ€Ñдка X, починаючи з Y-го Ñимволу. (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ substr(X,Y,Z) повертає підрÑдок з Ñ€Ñдка X, починаючи з Y-го Ñимволу, завдовжки Z-Ñимволів. () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ total_changes() повертає кількіÑть Ñ€Ñдків, змінених за допомогою INSERT, UPDATE або DELETE, починаючи з того моменту, коли під'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð´Ð¾ бази даних було відкрито. (X) trim(X) removes spaces from both ends of X. (X) trim(X) видалÑÑ” пробіли з обох Ñторін Ñ€Ñдка X. (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ trim(X,Y) Ñтворює новий Ñ€Ñдок з X шлÑхом Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð· обох кінців Ñимволів, Ñкі приÑутні в Ñ€Ñдку Y. (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ typeof(X) повертає Ñ€Ñдок із типом даних Ð²Ð¸Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ X. (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ unicode(X) повертає чиÑлове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ UNICODE коду Ñимволу. (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ upper(X) повертає копію Ñ€Ñдка X, в Ñкій Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ ASCII Ñимволу регіÑтр буде перетворений з нижнього у верхній. (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ zeroblob(N) повертає BLOB розміром N байт зі значеннÑми 0x00. (X) The avg() function returns the average value of all non-NULL X within a group. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ avg() повертає Ñереднє Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²ÑÑ–Ñ… не-NULL значень групи. (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ count(X) повертає кількіÑть Ñ€Ñдків, у Ñких X не-NULL у групі. (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ group_concat() повертає Ñ€Ñдок з уÑÑ–Ñ… значень X не-NULL. (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ group_concat() повертає Ñ€Ñдок з уÑÑ–Ñ… значень X не-NULL. Y - роздільник між значеннÑми X. (X) The max() aggregate function returns the maximum value of all values in the group. (X) Ðгрегатна Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ max() повертає макÑимальне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ X. (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) Ðгрегатна Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ min() повертає мінімальне не-NULL Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ X. (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) Ðгрегатні функції sum() Ñ– total() повертають Ñуму вÑÑ–Ñ… не-NULL значень Ð´Ð»Ñ X. SqliteTableModel reading rows loading... References %1(%2) Hold %3Shift and click to jump there Error changing data: %1 Помилка зміни даних: %1 retrieving list of columns Fetching data... Cancel СкаÑувати TableBrowser Browse Data ПереглÑнути дані &Table: &ТаблицÑ: Select a table to browse data Оберіть таблицю Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду даних Use this list to select a table to be displayed in the database view ВикориÑтовуйте цей ÑпиÑок, щоб вибрати таблицю, Ñку буде показано в переглÑдачі баз даних This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. Text pattern to find considering the checks in this frame Find in table Find previous match [Shift+F3] Find previous match with wrapping Shift+F3 Find next match [Enter, F3] Find next match with wrapping F3 The found pattern must match in letter case Case Sensitive The found pattern must be a whole word Whole Cell Interpret search pattern as a regular expression <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> Regular Expression Close Find Bar Text to replace with Replace with Replace next match Replace Replace all matches Replace all Export to &JSON Export the filtered data to JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. Copy column name Copy the database table column name to your clipboard New Data Browser Add a new docked Data Browser This button adds a new docked Data Browser, which you can detach and arrange in different layouts. <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>Прокрутити на початок</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>ÐатиÑÐºÐ°Ð½Ð½Ñ Ñ†Ñ–Ñ”Ñ— кнопки переміщує до початку таблиці.</p></body></html> |< |< Scroll one page upwards <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> < < 0 - 0 of 0 0 - 0 з 0 Scroll one page downwards <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> > > Scroll to the end Прокрутити до ÐºÑ–Ð½Ñ†Ñ <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>ÐатиÑніть тут, щоб перейти до зазначеного запиÑу</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>Ð¦Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° викориÑтовуєтьÑÑ, щоб переміÑтитиÑÑ Ð´Ð¾ запиÑу, номер Ñкого зазначений в зоні Перейти до </p></body></html> Go to: Перейти до: Enter record number to browse Введіть номер запиÑу Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду Type a record number in this area and click the Go to: button to display the record in the database view Ðадрукуйте номер запиÑу в цій зоні й натиÑніть кнопку Перейти до:, щоб показати Ð·Ð°Ð¿Ð¸Ñ Ñƒ базі даних 1 1 Show rowid column Показати Ñтовпець rowid Toggle the visibility of the rowid column Змінити видиміÑть ÑÑ‚Ð¾Ð²Ð¿Ñ†Ñ rowid Unlock view editing Розблокувати Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð³Ð»Ñду This unlocks the current view for editing. However, you will need appropriate triggers for editing. Це розблоковує поточний виглÑд Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ. Проте вам необхідно виділити тригери Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Edit display format Формат показу Edit the display format of the data in this column Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ñƒ показу Ð´Ð»Ñ Ð´Ð°Ð½Ð¸Ñ… у цьому Ñтовпці New Record Додати Ð·Ð°Ð¿Ð¸Ñ Insert a new record in the current table Додати новий Ð·Ð°Ð¿Ð¸Ñ Ñƒ поточну таблицю <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> Delete Record Видалити Ð·Ð°Ð¿Ð¸Ñ Delete the current record Видалити поточний Ð·Ð°Ð¿Ð¸Ñ This button deletes the record or records currently selected in the table Insert new record using default values in browsed table Insert Values... Open a dialog for inserting values in a new record Export to &CSV ЕкÑпортувати в &CSV Export the filtered data to CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. Save as &view Зберегти Ñк &виглÑд Save the current filter, sort column and display formats as a view This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. Save Table As... Save the table as currently displayed <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> Hide column(s) Hide selected column(s) Show all columns Show all columns that were hidden Set encoding ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Change the encoding of the text in the table cells Змінити ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚ÐµÐºÑту в цій комірці таблиці Set encoding for all tables Ð’Ñтановити ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²ÑÑ–Ñ… таблиць Change the default encoding assumed for all tables in the database Змінити ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовчуваннÑм Ð´Ð»Ñ Ð²ÑÑ–Ñ… таблиць у базі даних Clear Filters Clear all filters ОчиÑтити вÑÑ– фільтри This button clears all the filters set in the header input fields for the currently browsed table. Clear Sorting Reset the order of rows to the default This button clears the sorting columns specified for the currently browsed table and returns to the default order. Print Print currently browsed table data Print currently browsed table data. Print selection if more than one cell is selected. Ctrl+P Refresh Оновити Refresh the data in the selected table This button refreshes the data in the currently selected table. Ð¦Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° оновлює дані обраної на цей момент таблиці. F5 Find in cells Open the find tool bar which allows you to search for values in the table view below. Bold Жирний Ctrl+B Italic КурÑив Underline ПідкреÑÐ»ÐµÐ½Ð½Ñ Ctrl+U Align Right Align Left Center Horizontally Justify Edit Conditional Formats... Edit conditional formats for the current column Clear Format Clear All Formats Clear all cell formatting from selected cells and all conditional formats from selected columns Font Color Background Color Toggle Format Toolbar Show/hide format toolbar This button shows or hides the formatting toolbar of the Data Browser Select column Ctrl+Space Replace text in cells Freeze columns Make all columns from the first column up to this column not move when scrolling horizontally Filter in any column Ctrl+R %n row(s) , %n column(s) . Sum: %1; Average: %2; Min: %3; Max: %4 Conditional formats for "%1" determining row count... %L1 - %L2 of >= %L3 %L1 - %L2 of %L3 (clipped at %L1 rows) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. Будь лаÑка, введіть пÑевдо-первинний ключ Ð´Ð»Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾Ñті Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñƒ цьому виді. Це має бути Ñ–'Ð¼Ñ ÑƒÐ½Ñ–ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ ÑÑ‚Ð¾Ð²Ð¿Ñ†Ñ Ñƒ виді Delete Records Duplicate records Duplicate record Дублікат запиÑу Ctrl+" Adjust rows to contents Error deleting record: %1 Помилка Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу: %1 Please select a record first Будь лаÑка, Ñпочатку оберіть Ð·Ð°Ð¿Ð¸Ñ Please choose a new encoding for all tables. Оберіть нову ÑиÑтему ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²ÑÑ–Ñ… таблиць. Please choose a new encoding for this table. Оберіть нову ÑиÑтему ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— таблиці. %1 Leave the field empty for using the database encoding. %1 Залиште це поле порожнім Ñкщо хочете, щоб викориÑтовувалоÑÑ ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовчуваннÑм. This encoding is either not valid or not supported. ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð½ÐµÐ²Ñ–Ñ€Ð½Ðµ або не підтримуєтьÑÑ. %1 replacement(s) made. TableBrowserDock New Data Browser Rename Data Browser Close Data Browser Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. VacuumDialog Compact Database Ð£Ñ‰Ñ–Ð»ÑŒÐ½ÐµÐ½Ð½Ñ Ð‘Ð” Ð£Ñ‰Ñ–Ð»ÑŒÐ½ÐµÐ½Ð½Ñ Ð±Ð°Ð·Ð¸ даних Warning: Compacting the database will commit all of your changes. Please select the databases to co&mpact: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_zh.ts000066400000000000000000013233221463772530400252240ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite 关于 DB Browser for SQLite Version 版本 <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record 新增记录 Enter values for the new record considering constraints. Fields in bold are mandatory. 为新增的记录填写满足约æŸçš„值。加粗的字段必须填写。 In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. 在“值â€åˆ—中指定对应“åç§°â€åˆ—çš„å€¼ã€‚â€œç±»åž‹â€æä¾›å­—æ®µçš„ç±»åž‹ã€‚é»˜è®¤å€¼çš„æ˜¾ç¤ºæ ·å¼ç­‰åŒ NULL 值。 Name åç§° Type 类型 Value 值 Values to insert. Pre-filled default values are inserted automatically unless they are changed. è¦æ’入的值。ä¸åšä¿®æ”¹åˆ™ä¼šä½¿ç”¨é»˜è®¤å¡«å¥½çš„默认值。 When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. 你在上方编辑值时,这里会显示æ’入新记录所用的 SQL 语å¥ã€‚ä½ å¯ä»¥åœ¨ä¿å­˜å‰æ‰‹åŠ¨ä¿®æ”¹è¯­å¥ã€‚ <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">ä¿å­˜</span> 将会把显示的 SQL è¯­å¥æäº¤åˆ°æ•°æ®åº“以æ’入新记录。</p><p><span style=" font-weight:600;">æ¢å¤é»˜è®¤</span> 将会把 <span style=" font-weight:600;">值</span> 列æ¢å¤ä¸ºåˆå§‹å€¼ã€‚</p><p><span style=" font-weight:600;">å–æ¶ˆ</span> 将会关闭此界é¢ï¼Œä¸æ‰§è¡Œè¯­å¥ã€‚</p></body></html> Auto-increment 自增 Unique constraint å”¯ä¸€çº¦æŸ Check constraint: %1 检查约æŸ: %1 Foreign key: %1 外键: %1 Default value: %1 默认值: %1 Error adding record. Message from database engine: %1 添加记录失败。æ¥è‡ªæ•°æ®åº“引擎的消æ¯: %1 Are you sure you want to restore all the entered values to their defaults? ä½ ç¡®å®šè¦æŠŠè¾“å…¥çš„æ‰€æœ‰å€¼éƒ½æ¢å¤æˆé»˜è®¤å€¼å—? Application Possible command line arguments: å¯ç”¨å‘½ä»¤è¡Œå‚æ•°: The -o/--option and -O/--save-option options require an argument in the form group/setting=value -o/--option å’Œ -O/--save-option é€‰é¡¹éœ€è¦ group/setting=value æ ¼å¼çš„傿•° The user settings file location is replaced with the argument value instead of the environment variable value. 用户设置文件的ä½ç½®å°†ä½¿ç”¨å‚数值而éžçŽ¯å¢ƒå˜é‡å€¼ã€‚ Ignored environment variable (DB4S_SETTINGS_FILE) value: 忽略的环境å˜é‡ (DB4S_SETTINGS_FILE) 值 : The file %1 does not exist 文件 %1 ä¸å­˜åœ¨ Usage 用法 options 选项 database æ•°æ®åº“ project 项目 csv-file csv文件 Show command line options 显示命令行选项 Exit application after running scripts 脚本è¿è¡Œå®Œæ¯•åŽé€€å‡º file 文件 Execute this SQL file after opening the DB 打开数æ®åº“åŽæ‰§è¡Œè¯¥ SQL 文件 Import this CSV file into the passed DB or into a new DB 将该 CSV 文件导入传递过æ¥çš„æ•°æ®åº“或者新数æ®åº“ table 表 Browse this table, or use it as target of a data import æµè§ˆè¯¥è¡¨ï¼Œæˆ–用它作为数æ®å¯¼å…¥ç›®æ ‡ Open database in read-only mode 用åªè¯»æ¨¡å¼æ‰“开数æ®åº“ settings_file 设置文件 Run application based on this settings file 基于该设置文件è¿è¡Œç¨‹åº group 组 settings 设置 value 值 Run application with this setting temporarily set to value 临时设定该值并è¿è¡Œç¨‹åº Run application saving this value for this setting ä¿å­˜è¯¥è®¾ç½®å€¼å¹¶è¿è¡Œç¨‹åº Display the current version 显示当å‰ç‰ˆæœ¬ Open this SQLite database 打开该 SQLite æ•°æ®åº“ Open this project file (*.sqbpro) 打开该项目文件 (*.sqbpro) Import this CSV file into an in-memory database 导入该 CSV 文件到一个内存数æ®åº“ The %1 option requires an argument 选项 %1 需è¦ä¸€ä¸ªå‚æ•° The -S/--settings option requires an argument. The option is ignored. -S/--settings 选项需è¦ä¸€ä¸ªå‚数。此选项已忽略。 Invalid option/non-existent file: %1 无效选项/ä¸å­˜åœ¨çš„æ–‡ä»¶: %1 SQLite Version SQLite 版本 SQLCipher Version %1 (based on SQLite %2) SQLCipher 版本 %1 (基于 SQLite %2) DB Browser for SQLite Version %1. DB Browser for SQLite 版本 %1。 Last commit hash when built: %1 构建时的最新æäº¤: %1 Built for %1, running on %2 为 %1 构建,è¿è¡ŒäºŽ %2 Qt Version %1 Qt 版本 %1 CipherDialog SQLCipher encryption SQLCipher 加密 &Password 密ç (&P) &Reenter password 确认密ç (&R) Encr&yption settings 加密设置(&Y) SQLCipher &3 defaults SQLCipher &3 默认 SQLCipher &4 defaults SQLCipher &4 默认 Custo&m 自定义(&M) Page si&ze 页大å°(&Z) &KDF iterations KDF迭代(&K) HMAC algorithm HMAC算法 KDF algorithm KDF算法 Plaintext Header Size çº¯æ–‡æœ¬æ–‡ä»¶å¤´å¤§å° Passphrase å£ä»¤ Raw key 原始密钥 Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. 请设置密ç ä»¥åŠ å¯†æ•°æ®åº“。 注æ„å¦‚æžœä¿®æ”¹äº†ä»»ä½•å…¶ä»–é€‰é¡¹è®¾ç½®ï¼Œä»¥åŠæ¯æ¬¡æ‰“开数æ®åº“时,您都需è¦é‡æ–°è¾“入此密ç ã€‚ ä¸å¡«å¯†ç è¡¨ç¤ºç¦ç”¨åŠ å¯†ã€‚ 加密过程将花费一些时间,您应该在加密之å‰å¤‡ä»½æ•°æ®åº“ï¼ä¿®æ”¹åР坆å‰ï¼Œæœªä¿å­˜çš„æ›´æ”¹å°†ä¼šè¢«åº”用。 Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. 请输入加密数æ®åº“的密ç ã€‚ 如果此数æ®åº“的任何其他设置å‘生å˜åŒ–ï¼Œæ‚¨ä¹Ÿéœ€è¦æä¾›æ­¤ä¿¡æ¯ã€‚ ColumnDisplayFormatDialog Choose display format é€‰æ‹©æ˜¾ç¤ºæ ¼å¼ Display format æ˜¾ç¤ºæ ¼å¼ Choose a display format for the column '%1' which is applied to each value prior to showing it. 为列 '%1' 选择显示格å¼ï¼Œå°†åœ¨æ˜¾ç¤ºæ¯ä¸ªå€¼æ—¶ä½¿ç”¨ã€‚ Default 默认 Decimal number å进制数 Exponent notation 指数表示法 Hex blob å六进制大型对象 Hex number å六进制数 Apple NSDate to date 苹果 NSDate 到日期 Java epoch (milliseconds) to date Java 时间戳(毫秒)到日期 .NET DateTime.Ticks to date .NET DateTime.Ticks 到日期 Julian day to date 儒略日 (Julian day) 到日期 Unix epoch to local time Unix 时间戳到本地时间 WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy 日期,格å¼ä¸º dd/mm/yyyy Lower case å°å†™ Binary GUID to text 二进制 GUID 到文本 SpatiaLite Geometry to SVG SpatiaLite Geometry 到 SVG Custom display format must contain a function call applied to %1 自定义显示格å¼å¿…须包å«å¤„ç† %1 的函数 Error in custom display format. Message from database engine: %1 è‡ªå®šä¹‰æ˜¾ç¤ºæ ¼å¼æœ‰è¯¯ã€‚æ•°æ®åº“引擎æä¾›çš„错误信æ¯ä¸ºï¼š\n\n%1 Custom display format must return only one column but it returned %1. 自定义显示格å¼å¿…é¡»åªè¿”回1列,但目å‰è¿”回 %1 。 Octal number 八进制数 Round number å–æ•´æ•° Unix epoch to date Unix 时间到日期 Upper case 大写 Windows DATE to date Windows 日期到日期 Custom 自定义 CondFormatManager Conditional Format Manager æ¡ä»¶æ ¼å¼ç®¡ç†å™¨ This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. æ­¤å¯¹è¯æ¡†ç”¨äºŽåˆ›å»ºå’Œç¼–辑æ¡ä»¶æ ¼å¼ã€‚æ¯ä¸ªå•元格的样å¼å°†è¢«è®¾ç½®ä¸ºé¦–ä¸ªåŒ¹é…æ¡ä»¶çš„æ ¼å¼ã€‚æ¡ä»¶æ ¼å¼å¯ä»¥ä¸Šä¸‹ç§»åŠ¨ï¼Œé å‰çš„行优先生效。æ¡ä»¶çš„语法与过滤器相åŒã€‚空æ¡ä»¶å°†é€‚用于所有值。 Add new conditional format 创建新的æ¡ä»¶æ ¼å¼ &Add 添加(&A) Remove selected conditional format 删除选中的æ¡ä»¶æ ¼å¼ &Remove 删除(&R) Move selected conditional format up 上移选中的æ¡ä»¶æ ¼å¼ Move &up 上移(&U) Move selected conditional format down 下移选中的æ¡ä»¶æ ¼å¼ Move &down 下移(&D) Foreground 剿™¯ Text color 文本颜色 Background 背景 Background color 背景颜色 Font 字体 Size å¤§å° Bold 粗体 Italic 斜体 Underline 下划线 Alignment å¯¹é½ Condition æ¡ä»¶ Click to select color 点击选择颜色 Are you sure you want to clear all the conditional formats of this field? ç¡®å®žè¦æ¸…除全部æ¡ä»¶æ ¼å¼å—? DBBrowserDB Please specify the database name under which you want to access the attached database 请指明想è¦é™„加的数æ®åº“å Invalid file format æ— æ•ˆçš„æ–‡ä»¶æ ¼å¼ Do you want to save the changes made to the database file %1? æ‚¨æ˜¯å¦æƒ³ä¿å­˜å¯¹æ•°æ®åº“文件 %1 åšå‡ºçš„æ›´æ”¹? Exporting database to SQL file... 正在导出数æ®åº“到 SQL 文件... Cancel å–æ¶ˆ Executing SQL... 正在执行 SQL... Action cancelled. æ“ä½œå·²å–æ¶ˆã€‚ Do you really want to close this temporary database? All data will be lost. 你确定è¦å…³é—­æ­¤ä¸´æ—¶æ•°æ®åº“å—?所有数æ®éƒ½ä¼šä¸¢å¤±ã€‚ Database didn't close correctly, probably still busy æ•°æ®åº“未正确关闭,å¯èƒ½æ­£å¿™ Cannot open destination file: '%1' 无法打开目标文件: '%1' Cannot backup to file: '%1'. Message: %2 无法备份到文件: '%1'。消æ¯: %2 The database is currently busy: æ•°æ®åº“正忙: Do you want to abort that other operation? ç¡®å®šè¦æ”¾å¼ƒæ“作å—? No database file opened 没有打开数æ®åº“文件 Error in statement #%1: %2. Aborting execution%3. é”™è¯¯åœ¨è¯­å¥ #%1: %2. 正在放弃执行%3. and rolling back 并回滚 didn't receive any output from %1 未收到æ¥è‡ª %1 的任何输出 could not execute command: %1 未能执行命令: %1 Cannot delete this object 无法删除此对象 Cannot set data on this object ä¸èƒ½ä¸ºæ­¤æ•°æ®è®¾ç½®å¯¹è±¡ A table with the name '%1' already exists in schema '%2'. 一个与 '%1' åŒå的表已ç»å­˜åœ¨äºŽæž¶æž„ '%2' 中。 No table with name '%1' exists in schema '%2'. æž¶æž„ '%2' 中ä¸å­˜åœ¨è¡¨ '%1' 。 Cannot find column %1. 找ä¸åˆ°åˆ— %1 。 Creating savepoint failed. DB says: %1 创建ä¿å­˜ç‚¹å¤±è´¥ã€‚æ•°æ®åº“显示:%1 Renaming the column failed. DB says: %1 é‡å‘½å列失败。数æ®åº“显示:\n%1 Releasing savepoint failed. DB says: %1 释放ä¿å­˜ç‚¹å¤±è´¥ã€‚æ•°æ®åº“显示:%1 Creating new table failed. DB says: %1 建立新表失败。数æ®åº“显示:%1 Copying data to new table failed. DB says: %1 å¤åˆ¶æ•°æ®åˆ°æ–°è¡¨å¤±è´¥ã€‚æ•°æ®åº“显示:\n%1 Deleting old table failed. DB says: %1 删除旧表失败。数æ®åº“显示:%1 Error renaming table '%1' to '%2'. Message from database engine: %3 将表 '%1' é‡å‘½å为 '%2' 时出错。 æ•°æ®åº“引擎给出的错误信æ¯ï¼š %1 could not get list of db objects: %1 æœªèƒ½èŽ·å–æ•°æ®åº“对象列表:%1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: 还原æŸäº›å’Œè¿™ä¸ªè¡¨å…³è”的对象失败。这个最å¯èƒ½æ˜¯å› ä¸ºæŸäº›åˆ—çš„å称更改了。这里是您å¯èƒ½éœ€è¦æ‰‹åŠ¨ä¿®å¤å’Œæ‰§è¡Œçš„ SQL 语å¥: could not get list of databases: %1 æ— æ³•èŽ·å–æ•°æ®åº“列表: %1 Error loading extension: %1 加载扩展时出错: %1 Error loading built-in extension: %1 could not get column information 无法获å–åˆ—ä¿¡æ¯ Error setting pragma %1 to %2: %3 è®¾ç½®æ‚æ³¨ %1 为 %2 时出错: %3 File not found. 文件找ä¸åˆ°ã€‚ DbStructureModel Name åç§° Object 对象 Type 类型 Schema æž¶æž„ Database æ•°æ®åº“ Browsables 坿µè§ˆçš„ All 所有 Temporary 临时的 Tables (%1) 表 (%1) Indices (%1) 索引 (%1) Views (%1) 视图 (%1) Triggers (%1) 触å‘器 (%1) EditDialog Edit database cell 编辑数æ®åº“å•元格 Mode: 模å¼: Image å›¾åƒ Set as &NULL 设为&空 Apply data to cell 将数æ®åº”用到å•元格 This button saves the changes performed in the cell editor to the database cell. 此按钮把å•元格编辑器中的修改应用到数æ®åº“å•元格中。 Apply 应用 Text 文本 This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. 这是å•元格编辑器支æŒçš„æ¨¡å¼åˆ—è¡¨ã€‚é€‰æ‹©ä¸€ç§æ¨¡å¼ä»¥æŸ¥çœ‹æˆ–编辑当å‰å•元格的数æ®ã€‚ RTL Text å³åˆ°å·¦æ–‡æœ¬ Binary 二进制 JSON JSON XML XML Evaluation 求值 Automatically adjust the editor mode to the loaded data type 自动调整编辑器模å¼ä¸ºåŠ è½½çš„æ•°æ®çš„类型 This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. æ­¤å¤é€‰æŒ‰é’®å¯å¯ç”¨æˆ–ç¦ç”¨ç¼–辑器模å¼çš„自动切æ¢ã€‚当新å•元格被选中或新数æ®è¢«å¯¼å…¥æ—¶ï¼Œå¦‚æžœå¯ç”¨äº†è‡ªåŠ¨åˆ‡æ¢ï¼Œæ¨¡å¼ä¼šè°ƒæ•´ä¸ºæ£€æµ‹åˆ°çš„æ•°æ®ç±»åž‹ã€‚之åŽä½ ä¹Ÿæ‰‹åŠ¨åˆ‡æ¢ç¼–辑器的模å¼ã€‚如果你希望æµè§ˆå„å•å…ƒæ ¼çš„æ—¶å€™éƒ½ä¿æŒæ‰‹åŠ¨é€‰æ‹©çš„æ¨¡å¼ï¼Œè¯·æŠŠæ­¤æŒ‰é’®åˆ‡åˆ°å…³é—­çжæ€ã€‚ Auto-switch è‡ªåŠ¨åˆ‡æ¢ This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. æ­¤Qt编辑器用于å³åˆ°å·¦çš„æ–‡æœ¬ï¼ˆé»˜è®¤æ–‡æœ¬ç¼–è¾‘å™¨ä¸æ”¯æŒè¿™ç§æ ¼å¼ï¼‰ã€‚当检测到å³åˆ°å·¦å­—符时,会自动选择这ç§ç¼–辑器模å¼ã€‚ Identification of the cell currently in the editor ç›®å‰åœ¨ç¼–辑器中展示的å•元格的识别结果 Type and size of data currently in table è¡¨ä¸­å½“å‰æ•°æ®çš„ç±»åž‹å’Œå¤§å° Open preview dialog for printing the data currently stored in the cell 为此å•元格中目å‰å­˜å‚¨çš„æ•°æ®æ‰“开“打å°é¢„览â€å¯¹è¯æ¡† Auto-format: pretty print on loading, compact on saving. 自动格å¼: è¯»å–æ—¶æ ¼å¼åŒ–,存储时紧凑化。 When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. 当å¯ç”¨æ—¶ï¼Œè‡ªåŠ¨æ ¼å¼ç‰¹æ€§å°†åœ¨æ•°æ®åŠ è½½æ—¶æ ¼å¼åŒ–æ•°æ®ï¼Œå¢žåŠ æ¢è¡Œå¹¶ç¼©è¿›ä»¥æé«˜å¯è¯»æ€§ã€‚在ä¿å­˜æ•°æ®æ—¶ï¼Œè‡ªåŠ¨æ ¼å¼ç‰¹æ€§ä¼šé€šè¿‡åˆ é™¤æ¢è¡Œã€ä¸å¿…è¦çš„ç©ºç™½å­—ç¬¦çš„æ–¹å¼æ¥ç´§å‡‘化数æ®ã€‚ Word Wrap 自动æ¢è¡Œ Wrap lines on word boundaries 在å•è¯è¾¹ç•Œè‡ªåЍæ¢è¡Œ Open in default application or browser ç”¨é»˜è®¤ç¨‹åºæˆ–æµè§ˆå™¨æ‰“å¼€ Open in application ç”¨å¤–éƒ¨ç¨‹åºæ‰“å¼€ The value is interpreted as a file or URL and opened in the default application or web browser. å°†å•元格的值视为文件路径或URLï¼Œåœ¨é»˜è®¤ç¨‹åºæˆ–æµè§ˆå™¨ä¸­æ‰“开。 Save file reference... ä¿ç•™æ–‡ä»¶å¼•用... Save reference to file I'm not sure 将引用ä¿å­˜åˆ°æ–‡ä»¶ Open in external application 在外部程åºä¸­ç¼–辑 Autoformat è‡ªåŠ¨æ ¼å¼ &Export... 导出(&E)... &Import... 导入(&I)... Import from file 从文件导入 Opens a file dialog used to import any kind of data to this database cell. æ‰“å¼€æ–‡ä»¶é€‰æ‹©å¯¹è¯æ¡†ï¼Œå¯¼å…¥ä»»ä½•类型的数æ®åˆ°æ­¤æ•°æ®åº“å•元格。 Export to file 导出到文件 Opens a file dialog used to export the contents of this database cell to a file. æ‰“å¼€æ–‡ä»¶é€‰æ‹©å¯¹è¯æ¡†ï¼Œå¯¼å‡ºæ­¤æ•°æ®åº“å•元格的内容到一个文件里。 Erases the contents of the cell 删除å•元格的内容 This area displays information about the data present in this database cell 这个区域显示存在于这个数æ®åº“å•元格中的数æ®çš„ç›¸å…³ä¿¡æ¯ Print... 打å°... Ctrl+P Open preview dialog for printing displayed text 打开打å°é¢„è§ˆå¯¹è¯æ¡†ï¼Œé¢„览文本 Copy Hex and ASCII æ‹·è´å六进制和 ASCII Copy selected hexadecimal and ASCII columns to the clipboard æ‹·è´é€‰ä¸­çš„å六进制和 ASCII 列到剪贴æ¿ä¸­ Ctrl+Shift+C Choose a filename to export data 选择一个导出数æ®çš„æ–‡ä»¶å Image data can't be viewed in this mode. 此模å¼ä¸‹æ— æ³•æŸ¥çœ‹å›¾åƒæ•°æ®ã€‚ Try switching to Image or Binary mode. å°è¯•切æ¢åˆ°å›¾åƒæˆ–二进制模å¼ã€‚ Binary data can't be viewed in this mode. 此模å¼ä¸‹æ— æ³•查看二进制数æ®ã€‚ Try switching to Binary mode. å°è¯•切æ¢åˆ°äºŒè¿›åˆ¶æ¨¡å¼ã€‚ Type: NULL; Size: 0 bytes 类型: NULL; 大å°: 0 字节 Type: Text / Numeric; Size: %n character(s) 类型: 文本 / æ•°å­—; 大å°: %n 个字符 Type: %1 Image; Size: %2x%3 pixel(s) 类型: %1 图åƒ; 大å°: %2x%3 åƒç´  Type: Valid JSON; Size: %n character(s) 类型: 有效的 JSON; 大å°: %n 个字符 Type: Binary; Size: %n byte(s) 类型: 二进制; 大å°: %n 字节 Couldn't save file: %1. ä¿å­˜æ–‡ä»¶å¤±è´¥ï¼š%1。 The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. æ•°æ®å·²ä¿å­˜åˆ°ä¸´æ—¶æ–‡ä»¶ï¼Œå¹¶ä½¿ç”¨é»˜è®¤åº”ç”¨ç¨‹åºæ‰“开。您现在å¯ä»¥ç¼–辑该文件,并在准备就绪åŽå°†æ–°æ•°æ®åº”用到å•å…ƒæ ¼æˆ–å–æ¶ˆæ›´æ”¹ã€‚ Image files (%1) å›¾åƒæ–‡ä»¶ (%1) Binary files (*.bin) 二进制文件 (*.bin) Choose a file to import 选择一个è¦å¯¼å…¥çš„æ–‡ä»¶ The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. 文本编辑器å…è®¸æ‚¨ç¼–è¾‘æ–‡æœ¬ï¼Œå¹¶æ”¯æŒ JSON 或 XML æ•°æ®çš„语法高亮,ä¿å­˜å‰è‡ªåŠ¨æ ¼å¼åŒ–和验è¯ã€‚ 错误会标记红色波浪下划线。 求值模å¼ä¸‹ä¼šè®¡ç®—输入的 SQLite 表达å¼ï¼Œè®¡ç®—结果应用于å•元格。 Unsaved data in the cell editor å•元格编辑器中的未ä¿å­˜æ•°æ® The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? å•元格编辑器包å«çš„æ•°æ®å°šæœªåº”用到数æ®åº“。 是å¦å°†ç¼–辑åŽçš„æ•°æ®åº”用到 行=%1 : 列=%2? Editing row=%1, column=%2 编辑 行=%1 : 列=%2 No cell active. 未选中å•元格。 %1 Image %1 å›¾åƒ Invalid data for this mode æ•°æ®å¯¹æ­¤æ¨¡å¼éžæ³• The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? å•元格中包å«éžæ³•çš„ %1 æ•°æ®ã€‚原因: %2. 你确实想把它应用到å•元格中å—? EditIndexDialog &Name åç§°(&N) Order é¡ºåº &Table 表(&T) Edit Index Schema 编辑索引架构 &Unique 唯一(&U) For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed 为了将索引范围é™åˆ¶åˆ°è¡¨ä¸­çš„一部分,您å¯ä»¥åœ¨æ­¤æŒ‡å®š WHERE å­å¥æ¥åœ¨è¡¨ä¸­é€‰æ‹©éœ€è¦ç´¢å¼•的部分 Partial inde&x clause 部分索引å­å¥(&x) Colu&mns 列(&m) Table column 表中的列 Type 类型 Add a new expression column to the index. Expression columns contain SQL expression rather than column names. å‘索引中添加一个新的表达å¼åˆ—。表达å¼åˆ—åŒ…å« SQL 表达å¼è€Œä¸æ˜¯åˆ—å。 Index column 索引列 Deleting the old index failed: %1 删除旧索引失败: %1 Creating the index failed: %1 创建索引时失败: %1 EditTableDialog Edit table definition 编辑表定义 Table 表 Advanced 高级 Without Rowid æ—  Rowid Fields 字段 Database sche&ma æ•°æ®åº“æž¶æž„(&M) Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict å†²çªæ—¶ Strict 严格 When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. å¯ç”¨ä¸¥æ ¼é€‰é¡¹åŽï¼ŒSQLite 更新或æ’å…¥æ•°æ®æ—¶ä¼šä¸¥æ ¼æ‰§è¡Œæ¯ä¸ªåˆ—的数æ®ç±»åž‹ã€‚ Add 增加 Remove 删除 Move to top 移到最上 Move up 上移 Move down 下移 Move to bottom 移到最下 Name åç§° Type 类型 NN éžç©º Not null éžNULL PK 主键 <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> 主键</p></body></html> AI 自增 Autoincrement 自动增值 U 唯一 Unique 唯一 Default 默认 Default value 默认值 Check 检查 Check constraint æ£€æŸ¥çº¦æŸæ¡ä»¶ Collation 排åºè§„则 Foreign Key 外键 <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> 外键</p></body></html> Index Constraints ç´¢å¼•çº¦æŸ Add constraint å¢žåŠ çº¦æŸ Remove constraint åˆ é™¤çº¦æŸ Columns 列 SQL SQL Foreign Keys 外键 References 引用 Check Constraints æ£€æŸ¥çº¦æŸ <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">警告: </span>表中有一些无法解æžçš„定义。编辑并ä¿å­˜è¡¨å¯èƒ½ä¼šå¸¦æ¥é—®é¢˜ã€‚</p></body></html> Primary Key 主键 Add a primary key constraint å¢žåŠ ä¸»é”®çº¦æŸ Add a unique constraint å¢žåŠ å”¯ä¸€æ€§çº¦æŸ Error creating table. Message from database engine: %1 创建表时出错。æ¥è‡ªæ•°æ®åº“引擎的消æ¯: %1 There already is a field with that name. Please rename it first or choose a different name for this field. 已存在åŒå字段。请先é‡å‘½å已有字段,或为此字段选一个ä¸åŒçš„å字。 There can only be one primary key for each table. Please modify the existing primary key instead. æ¯ä¸ªè¡¨åªèƒ½æœ‰ä¸€ä¸ªä¸»é”®ã€‚请修改已有的主键。 This column is referenced in a foreign key in table %1 and thus its name cannot be changed. 此列是表 %1 的外键,因此它的åå­—ä¸èƒ½æ”¹å˜ã€‚ There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. 至少有一行带本字段的记录被设为空。这使得它ä¸å¯èƒ½è®¾ç½®è¿™ä¸ªæ ‡å¿—。请首先更改表数æ®ã€‚ There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. åœ¨è¿™ä¸ªå­—æ®µä¸­è‡³å°‘æœ‰ä¸€è¡Œå¸¦æœ‰ä¸€ä¸ªéžæ•´æ•°çš„值。这使得它ä¸å¯èƒ½è®¾ç½®è‡ªå¢žæ ‡å¿—。请首先更改表数æ®ã€‚ Column '%1' has duplicate data. 列 '%1' 有é‡å¤æ•°æ®ã€‚ This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. 所以无法å¯ç”¨â€œå”¯ä¸€â€æ ‡è®°ã€‚请删除é‡å¤æ•°æ®æ‰èƒ½å¯ç”¨ã€‚ Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. 您是å¦ç¡®è®¤æ‚¨æƒ³åˆ é™¤å­—段 '%1'? 当å‰å­˜å‚¨åœ¨è¿™ä¸ªå­—段中的所有数æ®å°†ä¼šä¸¢å¤±ã€‚ Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled 在设置为无 rowid å‰ï¼Œè¯·å…ˆæ·»åŠ ä¸€ä¸ªæ»¡è¶³ä»¥ä¸‹å‡†åˆ™çš„å­—æ®µ: - 设置为主键 - ç¦æ­¢è‡ªå¢ž Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set è®¾å®šå†²çªæ“作å‰ï¼Œè¯·æ·»åŠ æ»¡è¶³ä¸‹åˆ—æ¡ä»¶çš„字段: - è®¾å®šâ€œä¸»é”®â€æ ‡å¿— ExportDataDialog Export data as CSV 导出数æ®ä¸º CSV Tab&le(s) 表(&l) Colu&mn names in first line 第一行列å(&m) Fie&ld separator 字段分隔符(&l) , , ; ; Tab Tab | | Other 其它 &Quote character 引å·(&Q) " " ' ' New line characters æ¢è¡Œç¬¦ Windows: CR+LF (\r\n) Windows: 回车+æ¢è¡Œ (\r\n) Unix: LF (\n) Unix: æ¢è¡Œ (\n) Pretty print 美化输出 Could not open output file: %1 打ä¸å¼€è¾“出文件: %1 Choose a filename to export data 选择导出数æ®çš„æ–‡ä»¶å Export data as JSON 导出为 JSON exporting CSV 导出 CSV Error while writing the file '%1': %2 写入文件 '%1' 出错:%2 exporting JSON 导出 JSON Please select at least 1 table. 请选择至少1个表。 Choose a directory 选择一个目录 Export completed. 导出完æˆã€‚ Export finished with errors. 导出完æˆï¼Œä½†æœ‰é”™è¯¯ã€‚ ExportSqlDialog Export SQL... 导出 SQL... Tab&le(s) 表(&L) Select All 全选 Deselect All å…¨ä¸é€‰ &Options 选项(&O) Keep column names in INSERT INTO 在 INSERT INTO 语å¥ä¸­ä¿ç•™åˆ—å Multiple rows (VALUES) per INSERT statement æ¯æ¡ INSERT 语å¥ä¸­åŒ…å«å¤šè¡Œ (VALUES) Export everything 导出所有 Export schema only 仅导出架构 Export data only ä»…å¯¼å‡ºæ•°æ® Keep original CREATE statements ä¿ç•™åŽŸå§‹ CREATE è¯­å¥ Keep old schema (CREATE TABLE IF NOT EXISTS) ä¿æŒæ—§æž¶æž„ (CREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) 覆盖旧架构 (DROP TABLE, ç„¶åŽ CREATE TABLE) Please select at least one table. 请至少选一个表。 Choose a filename to export 选择è¦å¯¼å‡ºçš„æ–‡ä»¶å Export completed. 导出完æˆã€‚ Export cancelled or failed. å¯¼å‡ºè¢«å–æ¶ˆæˆ–失败。 ExtendedScintilla Ctrl+H Ctrl+F Ctrl+P Find... 查找... Find and Replace... 查找并替æ¢... Print... 打å°... ExtendedTableWidget Use as Exact Filter 用于精确过滤 Containing åŒ…å« Not containing ä¸åŒ…å« Not equal to ä¸ç­‰äºŽ Greater than 大于 Less than å°äºŽ Greater or equal 大于等于 Less or equal å°äºŽç­‰äºŽ Between this and... 在此值和...之间 Regular expression æ­£åˆ™è¡¨è¾¾å¼ Edit Conditional Formats... 编辑æ¡ä»¶æ ¼å¼... Set to NULL 设置为 NULL Cut 剪切 Copy å¤åˆ¶ Copy with Headers å¤åˆ¶ï¼ˆå¸¦è¡¨å¤´ï¼‰ Copy as SQL å¤åˆ¶ä¸º SQL Paste 粘贴 Print... 打å°... Use in Filter Expression 在过滤器表达å¼ä¸­ä½¿ç”¨ Alt+Del Ctrl+Shift+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? 剪贴æ¿ä¸­çš„æ•°æ®èŒƒå›´è¶…过了选择的范围。 是å¦ä»è¦æ’入? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>éƒ¨åˆ†æ•°æ®æ²¡æœ‰è¢«åŠ è½½ã€‚<b>åœ¨é€‰æ‹©æ‰€æœ‰è¡Œä¹‹å‰æ˜¯å¦è¦åŠ è½½æ‰€æœ‰æ•°æ®ï¼Ÿ</b><p><p>选择<b>å¦</b>表示ä¸åŠ è½½æ•°æ®å¹¶æ”¾å¼ƒå…¨é€‰ã€‚<br/>选择<b>是</b>表示加载所有数æ®ï¼ˆå¯èƒ½èŠ±è´¹ä¸€äº›æ—¶é—´ï¼‰å¹¶è¿›è¡Œå…¨é€‰ã€‚</p>警告:加载所有数æ®å¯¹äºŽå¤§è¡¨æ ¼å¯èƒ½å ç”¨å¤§é‡å†…存。 Cannot set selection to NULL. Column %1 has a NOT NULL constraint. ä¸èƒ½å°†å½“å‰å•元格设置为 NULL。列 %1 有 NOT NULL 约æŸã€‚ FileExtensionManager File Extension Manager 文件扩展å管ç†å™¨ &Up 上(&U) &Down 下(&D) &Add 添加(&A) &Remove 删除(&R) Description æè¿° Extensions 扩展å *.extension *.扩展å FilterLineEdit Filter 过滤 These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression è¿™äº›è¾“å…¥æ¡†èƒ½è®©ä½ å¿«é€Ÿåœ¨å½“å‰æ‰€é€‰è¡¨ä¸­è¿›è¡Œè¿‡æ»¤ã€‚ 默认情况下,包å«è¾“入文本的行会被过滤出æ¥ã€‚ 以下æ“作也支æŒ: % 通é…符 > 大于 < å°äºŽ >= 大于等于 <= å°äºŽç­‰äºŽ = 等于: ç²¾ç¡®åŒ¹é… <> ä¸ç­‰äºŽ: 精确åå‘åŒ¹é… x~y 范围: 值在 x å’Œ y 之间 /regexp/ å€¼ç¬¦åˆæ­£åˆ™è¡¨è¾¾å¼ Clear All Conditional Formats 清除所有æ¡ä»¶æ ¼å¼ Use for Conditional Format 用于æ¡ä»¶æ ¼å¼ Edit Conditional Formats... 编辑æ¡ä»¶æ ¼å¼... Set Filter Expression è®¾ç½®è¿‡æ»¤è¡¨è¾¾å¼ What's This? 这是什么? Is NULL 为 NULL Is not NULL éž NULL Is empty 为空 Is not empty éžç©º Not containing... ä¸åŒ…å«... Equal to... 等于... Not equal to... ä¸ç­‰äºŽ... Greater than... 大于... Less than... å°äºŽ... Greater or equal... 大于等于... Less or equal... å°äºŽç­‰äºŽ... In range... 在范围内... Regular expression... 正则表达å¼... FindReplaceDialog Find and Replace æŸ¥æ‰¾å¹¶æ›¿æ¢ Fi&nd text: 查找文本(&N): Re&place with: 替æ¢ä¸º(&P): Match &exact case 精确匹é…(&E) Match &only whole words 全字匹é…(&O) When enabled, the search continues from the other end when it reaches one end of the page 如果å¯ç”¨ï¼Œæœç´¢åˆ°æœ«ç«¯æ—¶ï¼Œæœç´¢ç»§ç»­ä»Žå¦ä¸€ç«¯å¼€å§‹ &Wrap around 循环查找(&W) When set, the search goes backwards from cursor position, otherwise it goes forward 如果å¯ç”¨ï¼Œæœç´¢ä»Žå½“å‰å…‰æ ‡ä½ç½®å‘å‰ã€‚未å¯ç”¨æ—¶å‘åŽ Search &backwards å呿Ÿ¥æ‰¾(&B) <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>选中时,åªåœ¨å½“å‰é€‰æ‹©çš„内容中进行æœç´¢ã€‚</p></body></html> &Selection only 在所选内容中查找(&S) <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>é€‰ä¸­æ—¶ï¼Œè¦æŸ¥æ‰¾çš„æ¨¡å¼è¢«è§£é‡Šä¸º UNIX 正则表达å¼ã€‚å‚阅 <a href="https://en.wikibooks.org/wiki/Regular_Expressions"> Wikibooks 中的正则表达å¼</a>.</p></body></html> Use regular e&xpressions 使用正则表达å¼(&X) Find the next occurrence from the cursor position and in the direction set by "Search backwards" 从当å‰ä½ç½®å¼€å§‹æŸ¥æ‰¾ä¸‹ä¸€æ¬¡å‡ºçŽ°çš„ä½ç½®ã€‚查找方å‘éµå¾ªâ€œå呿Ÿ¥æ‰¾â€çš„è®¾ç½®çŠ¶æ€ &Find Next 查找下一个(&F) F3 &Replace 替æ¢(&R) Highlight all the occurrences of the text in the page 高亮本页中所有出现的文本 F&ind All 全部高亮(&I) Replace all the occurrences of the text in the page æ›¿æ¢æœ¬é¡µä¸­æ‰€æœ‰å‡ºçŽ°çš„æ–‡æœ¬ Replace &All 全部替æ¢(&A) The searched text was not found æ— æ³•æ‰¾åˆ°è¦æŸ¥æ‰¾çš„æ–‡æœ¬ The searched text was not found. æ— æ³•æ‰¾åˆ°è¦æŸ¥æ‰¾çš„æ–‡æœ¬ã€‚ The searched text was found one time. 查找的文本被找到了 1 次。 The searched text was found %1 times. 查找的文本被找到了 %1 次。 The searched text was replaced one time. 查找的文本被替æ¢äº† 1 次。 The searched text was replaced %1 times. 查找的文本被替æ¢äº† %1 次。 ForeignKeyEditor &Reset é‡ç½®(&R) Foreign key clauses (ON UPDATE, ON DELETE etc.) 外键å­å¥ (ON UPDATE, ON DELETE 等等) ImageViewer Image Viewer å›¾åƒæŸ¥çœ‹å™¨ Reset the scaling to match the original size of the image. é‡ç½®ç¼©æ”¾æ¯”例以匹é…图åƒçš„原始尺寸。 Set the scaling to match the size of the viewport. 设定缩放比例以匹é…视界的大å°ã€‚ Print... 打å°... Open preview dialog for printing displayed image 打开“打å°é¢„览â€å¯¹è¯æ¡†ä»¥æ‰“å°æ˜¾ç¤ºçš„å›¾åƒ Ctrl+P Ctrl+P ImportCsvDialog Import CSV file 导入 CSV 文件 Table na&me 表åç§°(&M) &Column names in first line 列å在首行(&C) Field &separator 字段分隔符(&S) , , ; ; Tab Tab | ; Other 其它 &Quote character 引å·(&Q) Other (printable) å…¶ä»–(坿‰“å°) Other (code) å…¶ä»–(代ç ) " " ' ' &Encoding ç¼–ç (&E) UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? 删除字段头尾空白? Separate tables 分离表 Advanced 高级 When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. 当从 CSV 文件导入空值到已有表中,并且该列有默认值时,默认值会被æ’å…¥ã€‚é€‰ä¸­æ­¤é¡¹ä»¥åœ¨è¿™ç§æƒ…况下æ’入空值。 Ignore default &values 忽略默认值(&V) Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. é€‰ä¸­æ­¤é¡¹ä»¥åœ¨å¾€æ²¡æœ‰é»˜è®¤å€¼çš„éž NULL 列导入空值时终止导入。 Fail on missing values 缺值时失败 Disable data type detection ç¦ç”¨ç±»åž‹æ£€æµ‹ Disable the automatic data type detection when creating a new table. ç¦æ­¢åœ¨åˆ›å»ºæ–°è¡¨æ—¶è‡ªåŠ¨æ£€æµ‹æ•°æ®ç±»åž‹ã€‚ Use local number conventions 使用本地数字习俗 Use decimal and thousands separators according to the system locale. ä½¿ç”¨ç³»ç»ŸåŒºåŸŸè®¾ç½®ä¸­å®šä¹‰çš„å°æ•°ç‚¹å’Œåƒä½åˆ†éš”符。 When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. 当呿œ‰ä¸»é”®çš„è¡¨ä¸­å¯¼å…¥æ•°æ®æ—¶ï¼Œå¯èƒ½ä¼šäº§ç”Ÿå”¯ä¸€æ€§çº¦æŸæˆ–索引的冲çªã€‚此选项å…许你选择处ç†å†²çªçš„ç­–ç•¥ï¼šé»˜è®¤æƒ…å†µä¸‹ä¼šå–æ¶ˆå¯¼å…¥å¹¶å·å›žï¼Œä¹Ÿå¯ä»¥é€‰æ‹©å¿½ç•¥å¹¶è·³è¿‡å†²çªçš„行,或替æ¢è¡¨ä¸­çŽ°æœ‰çš„è¡Œã€‚ Abort import å–æ¶ˆå¯¼å…¥ Ignore row 忽略冲çªçš„行 Replace existing row 替æ¢çŽ°æœ‰çš„è¡Œ Conflict strategy 冲çªç­–ç•¥ Deselect All å…¨ä¸é€‰ Match Similar 匹é…相似 Select All 全选 There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. å·²ç»æœ‰ä¸€å¼ å«åš '%1' çš„è¡¨ã€‚åªæœ‰åˆ—æ•°åŒ¹é…æ—¶ï¼Œæ‰èƒ½å¯¼å…¥åˆ°å·²ç»å­˜åœ¨çš„表中。 There is already a table named '%1'. Do you want to import the data into it? å·²ç»æœ‰ä¸€å¼ å«åš '%1' 的表。你想把数æ®å¯¼å…¥åˆ°æ­¤è¡¨ä¸­å—? Creating restore point failed: %1 创建还原点失败: %1 Creating the table failed: %1 创建表失败: %1 importing CSV 导入 CSV Could not prepare INSERT statement: %1 无法准备 INSERT 语å¥: %1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. æ„外的文件结æŸã€‚请确认已正确é…置引å·å­—符,并确认文件没有格å¼é”™è¯¯ã€‚ Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. 导入文件 '%1' 用时 %2ms. 其中 %3ms 用在行方程上。 Inserting row failed: %1 æ’入行失败: %1 MainWindow DB Browser for SQLite DB Browser for SQLite toolBar1 工具æ 1 &Wiki 百科(&W) Bug &Report... Bug 上报(&R)... Feature Re&quest... 特性请求(&Q)... Web&site 网站(&S) &Donate on Patreon... 在 Patreon 上æèµ (&D)... Open &Project... 打开项目(&P)... &Attach Database... 附加数æ®åº“(&A)... Add another database file to the current database connection 添加å¦ä¸€ä¸ªæ•°æ®åº“到当å‰çš„æ•°æ®åº“连接中 This button lets you add another database file to the current database connection 此按钮能添加å¦ä¸€ä¸ªæ•°æ®åº“到当å‰çš„æ•°æ®åº“连接中 &Set Encryption... 设置加密(&S)... This button saves the content of the current SQL editor tab to a file æ­¤æŒ‰é’®æŠŠå½“å‰ SQL 编辑器页的内容ä¿å­˜åˆ°ä¸€ä¸ªæ–‡ä»¶ SQLCipher &FAQ SQLCipher 常è§é—®é¢˜(&F) Table(&s) to JSON... 表到 JSON (&S)... Export one or more table(s) to a JSON file 导出一个或多个表到 JSON 文件 Un/comment block of SQL code 注释/å–æ¶ˆæ³¨é‡Š SQL ä»£ç  Un/comment block 注释/å–æ¶ˆæ³¨é‡Š Comment or uncomment current line or selected block of code 注释/å–æ¶ˆæ³¨é‡Šå½“å‰è¡Œæˆ–é€‰ä¸­çš„ä»£ç æ®µ Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. 注释/å–æ¶ˆæ³¨é‡Šé€‰ä¸­çš„ä»£ç æ®µï¼Œæ²¡æœ‰é€‰ä¸­æ—¶ä¸ºå½“å‰è¡Œã€‚ä»£ç æ®µçš„æ³¨é‡Šçжæ€ç”±ç¬¬ä¸€è¡Œå†³å®šã€‚ Ctrl+/ Stop SQL execution åœæ­¢ SQL 执行 Stop execution åœæ­¢æ‰§è¡Œ Stop the currently running SQL script åœæ­¢å½“å‰è¿è¡Œçš„ SQL 脚本 &File 文件(&F) &Import 导入(&I) &Export 导出(&E) &Edit 编辑(&E) &View 查看(&V) &Help 帮助(&H) &Remote 远程(&R) Execute all/selected SQL 执行所有/选中的 SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. 此按钮执行当å‰é€‰ä¸­çš„ SQL 语å¥ã€‚如果没有选中文本,就执行所有的 SQL 语å¥ã€‚ &Load Extension... 加载扩展(&L)... This button executes the SQL statement present in the current editor line 此按钮执行编辑器当å‰è¡Œä¸­çš„ SQL è¯­å¥ Shift+F5 Sa&ve Project ä¿å­˜é¡¹ç›®(&V) Save SQL file as SQL 文件å¦å­˜ä¸º &Browse Table æµè§ˆè¡¨(&B) Copy Create statement å¤åˆ¶ Create è¯­å¥ Copy the CREATE statement of the item to the clipboard å¤åˆ¶é€‰ä¸­é¡¹çš„ CREATE 语å¥åˆ°å‰ªè´´æ¿ Open an existing database file in read only mode 用åªè¯»æ–¹å¼æ‰“开一个已有的数æ®åº“文件 Opens the SQLCipher FAQ in a browser window 用æµè§ˆå™¨çª—壿‰“å¼€ SQLCipher 常è§é—®é¢˜ User 用户 Application åº”ç”¨ç¨‹åº &Clear 清除(&C) DB Sche&ma æ•°æ®åº“æž¶æž„(&M) &New Database... 新建数æ®åº“(&N)... Create a new database file 创建一个新的数æ®åº“文件 This option is used to create a new database file. 这个选项用于创建一个新的数æ®åº“文件。 Ctrl+N &Open Database... 打开数æ®åº“(&O)... Open an existing database file 打开一个现有的数æ®åº“文件 This option is used to open an existing database file. 这个选项用于打开一个现有的数æ®åº“文件。 Ctrl+O &Close Database 关闭数æ®åº“(&C) Ctrl+W Revert database to last saved state 把数æ®åº“会退到先å‰ä¿å­˜çš„çŠ¶æ€ This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. 这个选项用于倒退当å‰çš„æ•°æ®åº“文件为它最åŽçš„ä¿å­˜çжæ€ã€‚从最åŽä¿å­˜æ“作开始åšå‡ºçš„æ‰€æœ‰æ›´æ”¹å°†ä¼šä¸¢å¤±ã€‚ Write changes to the database file 把更改写入到数æ®åº“文件 This option is used to save changes to the database file. 这个选项用于ä¿å­˜æ›´æ”¹åˆ°æ•°æ®åº“文件。 Ctrl+S Compact &Database... 压缩数æ®åº“(&D)... Compact the database file, removing space wasted by deleted records 压缩数æ®åº“文件,去除已删除记录所å ç”¨çš„空间 Compact the database file, removing space wasted by deleted records. 压缩数æ®åº“文件,去除已删除记录所å ç”¨çš„空间。 E&xit 退出(&X) Ctrl+Q Import data from an .sql dump text file into a new or existing database. 从一个 .sql 转储文本文件中导入数æ®åˆ°ä¸€ä¸ªæ–°çš„æˆ–已有的数æ®åº“。 This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. 这个选项让你从一个 .sql 转储文本文件中导入数æ®åˆ°ä¸€ä¸ªæ–°çš„æˆ–现有的数æ®åº“。SQL 转储文件å¯ä»¥åœ¨å¤§å¤šæ•°æ•°æ®åº“引擎上创建,包括 MySQL å’Œ PostgreSQL。 Open a wizard that lets you import data from a comma separated text file into a database table. 打开一个å‘导让您从一个逗å·é—´éš”的文本文件导入数æ®åˆ°ä¸€ä¸ªæ•°æ®åº“表中。 Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. 打开一个å‘导让您从一个逗å·é—´éš”的文本文件导入数æ®åˆ°ä¸€ä¸ªæ•°æ®åº“表中。CSV 文件å¯ä»¥åœ¨å¤§å¤šæ•°æ•°æ®åº“和电å­è¡¨æ ¼åº”用程åºä¸Šåˆ›å»ºã€‚ Export a database to a .sql dump text file. 导出一个数æ®åº“导一个 .sql 转储文本文件。 This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. 这个选项让你导出一个数æ®åº“导一个 .sql 转储文本文件。SQL 转储文件包å«åœ¨å¤§å¤šæ•°æ•°æ®åº“引擎上(包括 MySQL å’Œ PostgreSQL)釿–°åˆ›å»ºæ•°æ®åº“所需的所有数æ®ã€‚ Export a database table as a comma separated text file. 导出一个数æ®åº“表为逗å·é—´éš”的文本文件。 Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. 导出一个数æ®åº“表为逗å·é—´éš”的文本文件,准备好被导入到其他数æ®åº“或电å­è¡¨æ ¼åº”用程åºã€‚ Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database 打开“创建表â€å‘导,在那里å¯ä»¥å®šä¹‰åœ¨æ•°æ®åº“中的一个新表的å称和字段 Open the Delete Table wizard, where you can select a database table to be dropped. 打开“删除表â€å‘导,在那里你å¯ä»¥é€‰æ‹©è¦ä¸¢å¼ƒçš„一个数æ®åº“表。 Open the Create Index wizard, where it is possible to define a new index on an existing database table. 打开“创建索引â€å‘导,在那里å¯ä»¥åœ¨ä¸€ä¸ªçŽ°æœ‰çš„æ•°æ®åº“表上定义一个新索引。 &Preferences... 首选项(&P)... Open the preferences window. 打开首选项窗å£ã€‚ &DB Toolbar æ•°æ®åº“工具æ (&D) Shows or hides the Database toolbar. 显示或éšè—æ•°æ®åº“工具æ ã€‚ Shift+F1 &Recently opened 最近打开(&R) Ctrl+T This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. 这是打开的数æ®åº“的结构。 ä½ å¯ä»¥ä»Žä¸€ä¸ªå¯¹è±¡è¡Œä¸­æ‹–动 SQL 语å¥ï¼Œç„¶åŽæ‹–到其他应用中,或者拖到其他 'DB Browser for SQLite' 的实例中。 Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. 警告: æ­¤æ‚æ³¨æ— æ³•读å–ï¼Œæ­¤å€¼ä¸ºæŽ¨æ–­å¾—åˆ°ã€‚ç¼–è¾‘æ‚æ³¨å¯èƒ½ä¼šè¦†ç›–ç”± SQLite 扩展é‡å®šä¹‰çš„ LIKE。 Too&ls 工具(&T) DB Toolbar æ•°æ®åº“å·¥å…·æ  Edit Database &Cell 编辑数æ®åº“å•元格(&C) SQL &Log SQL 日志(&L) Show S&QL submitted by 显示 SQL æäº¤è‡ª(&Q) Error Log 错误记录 This button clears the contents of the SQL logs 此按钮清除 SQL 日志的内容 This panel lets you examine a log of all SQL commands issued by the application or by yourself æ­¤é¢æ¿å¯ä»¥è®©ä½ è‡ªè¡Œæ£€æŸ¥æœ¬åº”ç”¨ç¨‹åºæ‰§è¡Œçš„æ‰€æœ‰ SQL 命令的日志 &Plot 图表(&P) This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. 这是已打开数æ®åº“的结构。 ä½ å¯ä»¥ä»Žå字列拖拽多个对象å称到 SQL 编辑器中,并å¯ä»¥ç”¨å³é”®èœå•调节所拖拽å称的属性。这å¯ä»¥å¸®åŠ©ä½ ç¼–å†™ SQL 语å¥ã€‚ ä½ å¯ä»¥ä»Žæž¶æž„列拖拽 SQL 语å¥åˆ° SQL 编辑器或其他的应用程åºã€‚ Project Toolbar é¡¹ç›®å·¥å…·æ  Extra DB toolbar å…¶ä»–æ•°æ®åº“å·¥å…·æ  Close the current database file 关闭当剿•°æ®åº“文件 &New Database 新建数æ®åº“(&N) This button closes the connection to the currently open database file æ­¤æŒ‰é’®å…³é—­åˆ°å½“å‰æ‰“开的数æ®åº“文件的连接 Ctrl+F4 &Revert Changes 倒退更改(&R) &Undo 撤销(&U) Undo last change to the database 撤销对数æ®åº“çš„æœ€åŽæ›´æ”¹ This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. æ­¤æ“作将撤销上一次在数æ®åº“æµè§ˆå™¨æˆ– SQL 执行中对数æ®åº“所执行的更改。ä¸èƒ½æ’¤é”€ï¼ˆé‡åšï¼‰æœ¬æ¬¡æ’¤é”€ã€‚ &Write Changes 写入更改(&W) Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. 打开修改表å‘导,å¯ä»¥åœ¨é‡Œé¢é‡å‘½å现有表,添加或删除字段,修改字段å称和类型。 New &tab 新建标签页(&T) Open SQL file(s) 打开 SQL 文件 This button opens files containing SQL statements and loads them in new editor tabs æ­¤æŒ‰é’®å¯æ‰“å¼€åŒ…å« SQL 语å¥çš„一个或多个文件,将它们加载到新的编辑器标签页中 Ctrl+Shift+T Ctrl+Shift+T Execute line 执行行 F1 &Save Project ä¿å­˜é¡¹ç›®(&S) This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file 此按钮å…许你将与已打开的数æ®åº“相关è”的所有设置ä¿å­˜åˆ°ä¸€ä¸ªæœ¬è½¯ä»¶å¯ç”¨çš„项目文件中 Open &Project 打开项目(&P) This button lets you open a DB Browser for SQLite project file 此按钮å…许你打开一个 DB Browser for SQLite 的项目文件 Open Data&base Read Only... åªè¯»æ‰“开数æ®åº“(&B)... Ctrl+Shift+O Save results ä¿å­˜ç»“æžœ Save the results view ä¿å­˜ç»“果视图 This button lets you save the results of the last executed query 此按钮让你ä¿å­˜ä¸Šæ¬¡æ‰§è¡Œçš„æŸ¥è¯¢çš„结果 Find text in SQL editor 在 SQL 编辑器中查找文本 Find 查找 This button opens the search bar of the editor æ­¤æŒ‰é’®æ‰“å¼€ç¼–è¾‘å™¨çš„æŸ¥æ‰¾æ  Ctrl+F Find or replace text in SQL editor 在 SQL ç¼–è¾‘å™¨ä¸­æŸ¥æ‰¾æˆ–æ›¿æ¢æ–‡æœ¬ Find or replace æŸ¥æ‰¾æˆ–æ›¿æ¢ This button opens the find/replace dialog for the current editor tab 此按钮为当å‰çš„编辑器标签页打开查找/替æ¢å¯¹è¯æ¡† Ctrl+H Export to &CSV 导出到 &CSV Export to &JSON 导出到 &JSON Save as &view ä¿å­˜ä¸ºè§†å›¾(&V) Save as view ä¿å­˜ä¸ºè§†å›¾ &Open Database 打开数æ®åº“(&O) Drag && Drop SELECT Query 拖放 SELECT 查询(&&) When dragging fields from the same table or a single table, drop a SELECT query into the editor 在åŒä¸€ä¸ªæˆ–å•ä¸ªè¡¨ä¸­æ‹–æ‹½å­—æ®µï¼Œé‡Šæ”¾æ—¶å°†ä¸€æ¡ SELECT 查询æ’入编辑器 Browse Table æµè§ˆè¡¨ Close Pro&ject 关闭项目(&J) Close project and database files and return to the initial state 关闭项目和数æ®åº“文件并返回åˆå§‹çŠ¶æ€ Ctrl+Shift+W Ctrl+Shift+W Table from CSV data in Clipboard... 剪贴æ¿ä¸­ CSV 的数æ®åˆ¶è¡¨... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. 这会将剪贴æ¿å†…容视作 CSV 文件,打开从文件导入 CSV æ•°æ®çš„å‘导æ¥å¤„ç†å®ƒã€‚ Show &Row Counts 显示行数(&R) This shows the number of rows for each table and view in the database. 显示数æ®åº“中æ¯ä¸ªè¡¨å’Œè§†å›¾çš„行数。 Save Database &As... å¦å­˜ä¸ºæ•°æ®åº“(&A)... Save the current database as a different file 将当剿•°æ®åº“ä¿å­˜åˆ°å¦ä¸€ä¸ªæ–‡ä»¶ Refresh 刷新 Reload the database structure 釿–°è½½å…¥æ•°æ®åº“结构 Ctrl+Shift+F4 Ctrl+Shift+F4 Detach Database 断开数æ®åº“ Detach database file attached to the current database connection æ–­å¼€å·²é™„åŠ åˆ°å½“å‰æ•°æ®åº“连接的数æ®åº“文件 Shows or hides the Project toolbar. 显示或éšè—项目工具æ ã€‚ &Database Structure This has to be equal to the tab title in all the main tabs æ•°æ®åº“结构(&D) &Browse Data This has to be equal to the tab title in all the main tabs æµè§ˆæ•°æ®(&B) Edit P&ragmas This has to be equal to the tab title in all the main tabs ç¼–è¾‘æ‚æ³¨(&R) E&xecute SQL This has to be equal to the tab title in all the main tabs 执行 SQL(&X) &Recent Files 最近的文件(&R) Extra DB Toolbar å…¶ä»–æ•°æ®åº“å·¥å…·æ  New In-&Memory Database 新建内存数æ®åº“(&M) Drag && Drop Qualified Names 拖拽é™å®šåç§° Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor 当拖拽对象到编辑器中时,使用é™å®šåç§° (例如 "Table"."Field") Drag && Drop Enquoted Names 拖拽引用åå­— Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor 当拖拽对象到编辑器中时,使用转义的标识符 (例如 "Table1") &Integrity Check 完全性检查(&I) Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. 对打开的数æ®åº“è¿è¡Œ integrity_check æ‚æ³¨å¹¶åœ¨æ‰§è¡Œ SQL æ ‡ç­¾é¡µè¿”å›žç»“æžœã€‚æ­¤æ‚æ³¨å¯¹æ•´ä¸ªæ•°æ®åº“进行完全性检查。 &Foreign-Key Check 外键检查(&F) Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab 对打开的数æ®åº“è¿è¡Œ foreign_key_check æ‚æ³¨å¹¶åœ¨â€œæ‰§è¡Œ SQLâ€æ ‡ç­¾é¡µä¸­è¿”回结果 &Quick Integrity Check 快速完全性检查(&Q) Run a quick integrity check over the open DB 对打开的数æ®åº“执行快速完全性检查 Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. 对打开的数æ®åº“è¿è¡Œ quick_check æ‚æ³¨å¹¶åœ¨æ‰§è¡Œ SQL 标签页返回结果。此命令会执行 integrity_check 的多数检查,但是è¦å¿«å¾—多。 &Optimize 优化(&O) Attempt to optimize the database å°è¯•优化数æ®åº“ Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. 对打开的数æ®åº“è¿è¡Œ optimize æ‚æ³¨ã€‚å¯èƒ½ä¼šæ‰§è¡Œå¯¹æœªæ¥æŸ¥è¯¢æ€§èƒ½æœ‰å¸®åŠ©çš„ä¼˜åŒ–ã€‚ Print æ‰“å° Print text from current SQL editor tab 从当å‰çš„ SQL ç¼–è¾‘å™¨æ ‡ç­¾é¡µæ‰“å°æ–‡æœ¬ Open a dialog for printing the text in the current SQL editor tab æ‰“å¼€å¯¹è¯æ¡†ä»¥ä»Žå½“å‰çš„ SQL ç¼–è¾‘å™¨æ ‡ç­¾é¡µæ‰“å°æ–‡ Print the structure of the opened database 打å°å½“剿‰“开的数æ®åº“的结构 Open a dialog for printing the structure of the opened database æ‰“å¼€å¯¹è¯æ¡†ä»¥æ‰“å°å½“剿‰“开的数æ®åº“的结构 &Save Project As... å¦å­˜ä¸ºé¡¹ç›®(&S)... Save the project in a file selected in a dialog 将项目ä¿å­˜ä¸ºæ–‡ä»¶ Save A&ll 全部ä¿å­˜(&L) Save DB file, project file and opened SQL files ä¿å­˜æ•°æ®åº“文件ã€é¡¹ç›®æ–‡ä»¶å’Œæ‰“开的 SQL 文件 Ctrl+Shift+S &Database from SQL file... 从 SQL 文件导入数æ®åº“(&D)... &Table from CSV file... 从 CSV 文件导入表(&T)... &Database to SQL file... 导出数æ®åº“到 SQL 文件(&D)... &Table(s) as CSV file... 导出表到 CSV 文件(&T)... &Create Table... 创建表(&C)... &Delete Table... 删除表(&D)... &Modify Table... 修改表(&M)... Create &Index... 创建索引(&I)... W&hat's This? 这是什么(&W)? &About 关于(&A) This button opens a new tab for the SQL editor 此按钮打开一个 SQL 编辑器的新标签页 &Execute SQL 执行 SQL(&E) Save the current session to a file ä¿å­˜å½“å‰ä¼šè¯åˆ°ä¸€ä¸ªæ–‡ä»¶ Load a working session from a file ä»Žä¸€ä¸ªæ–‡ä»¶åŠ è½½å·¥ä½œä¼šè¯ Save SQL file ä¿å­˜ SQL 文件 Execute current line 执行当å‰è¡Œ Ctrl+E Export as CSV file 导出为 CSV 文件 Export table as comma separated values file 导出表为逗å·é—´éš”值文件 Ctrl+L Ctrl+P Database encoding æ•°æ®åº“ç¼–ç  Choose a database file 选择一个数æ®åº“文件 Ctrl+Return Ctrl+D Ctrl+I Encrypted 加密的 Database is encrypted using SQLCipher æ•°æ®åº“使用 SQLCipher 进行了加密 Read only åªè¯» Database file is read only. Editing the database is disabled. æ•°æ®åº“是åªè¯»çš„ã€‚ç¼–è¾‘è¢«ç¦æ­¢ã€‚ Could not open database file. Reason: %1 无法打开数æ®åº“文件。 原因: %1 Choose a filename to save under 选择一个文件åä¿å­˜ Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? è®¾ç½®æˆ–æ¸…é™¤æ‚æ³¨å€¼ä¼šæäº¤ä½ çš„当å‰äº‹åŠ¡ã€‚ 你确定å—? Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 ä¿å­˜æ•°æ®åº“æ–‡ä»¶æ—¶å‡ºé”™ã€‚è¿™è¡¨æ˜Žä¸æ˜¯æ‰€æœ‰å¯¹æ•°æ®åº“的更改都被ä¿å­˜äº†ã€‚你需è¦å…ˆè§£å†³ä»¥ä¸‹é”™è¯¯ã€‚ %1 A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. 有新版本的 DB Browser for SQLite (%1.%2.%3)å¯ç”¨ã€‚<br/><br/>请从 <a href='%4'>%4</a> 下载。 DB Browser for SQLite project file (*.sqbpro) DB Browser for SQLite 项目文件 (*.sqbpro) Reset Window Layout é‡ç½®çª—å£å¸ƒå±€ The database is currently busy. æ•°æ®åº“正忙。 Click here to interrupt the currently running query. 点击此处中断当å‰è¿è¡Œçš„æŸ¥è¯¢ã€‚ You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? 你正在执行SQL语å¥ã€‚关闭数æ®åº“ä¼šåœæ­¢æ‰§è¡Œï¼Œå¯èƒ½ä½¿æ•°æ®åº“处于ä¸å‡†ç¡®çš„状æ€ã€‚确实è¦å…³é—­æ•°æ®åº“å—? Do you want to save the changes made to the project file '%1'? 是å¦è¦ä¿å­˜å¯¹é¡¹ç›®æ–‡ä»¶ '%1' 的修改? Error checking foreign keys after table modification. The changes will be reverted. 修改表格åŽçš„外键检查错误。修改会被回退。 This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. 此表格没有通过外键检查。<br/>ä½ éœ€è¦æ‰§è¡Œ '工具 | 外键检查' å¹¶ä¿®å¤å‘现的问题。 Edit View %1 编辑视图 %1 Edit Trigger %1 编辑触å‘器 %1 At line %1: 在行 %1: Result: %1 结果: %1 Result: %2 结果: %2 Execution finished with errors. 执行已完æˆï¼Œä½†æœ‰é”™è¯¯ã€‚ Execution finished without errors. 执行完æˆï¼Œæ— é”™è¯¯ã€‚ Opened '%1' in read-only mode from recent file list 已从最近文件列表中打开 '%1' (åªè¯»æ¨¡å¼) Opened '%1' from recent file list 已从最近文件列表中打开 '%1' &%1 %2%3 &%1 %2%3 (read only) (åªè¯») Open Database or Project 打开数æ®åº“或项目 Attach Database... 附加数æ®åº“... Import CSV file(s)... 导入CSV文件... Do you want to save the changes made to SQL tabs in a new project file? 是å¦è¦å°†å¯¹ SQL 标签页的修改ä¿å­˜ä¸ºé¡¹ç›®æ–‡ä»¶ï¼Ÿ The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? 标签页 '%1' 中的语å¥ä»åœ¨æ‰§è¡Œã€‚å…³é—­è¯¥æ ‡ç­¾é¡µå°†åœæ­¢æ‰§è¡Œã€‚è¿™å¯èƒ½ä½¿æ•°æ®åº“处于ä¸ä¸€è‡´çжæ€ã€‚确定关闭标签页å—? This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. 此项目文件使用了 DB Browser for SQLite 3.10 或更旧版本使用的旧文件格å¼ã€‚è¿™ç§æ–‡ä»¶æ ¼å¼çš„加载已ä¸å†å……分支æŒã€‚如è¦å®Œå…¨åŠ è½½è¯¥æ–‡ä»¶ï¼Œè¯·ä½¿ç”¨ DB Browser for SQLite 3.12 版本将其转æ¢ä¸ºæ–°åž‹æ–‡ä»¶æ ¼å¼ã€‚ Yes. Don't ask again 是,ä¸å†è¯¢é—® This action will open a new SQL tab with the following statements for you to edit and run: æ­¤æ“作将打开一个新的 SQL 标签页,其中包å«ä»¥ä¸‹è¯­å¥ä¾›æ‚¨ç¼–辑和è¿è¡Œï¼š Rename Tab é‡å‘½å标签 Duplicate Tab å¤åˆ¶æ ‡ç­¾ Close Tab 关闭标签 Opening '%1'... 正在打开 '%1'... There was an error opening '%1'... 打开 '%1' 时出错... Value is not a valid URL or filename: %1 䏿˜¯æ­£ç¡®çš„URL或文件å:%1 Do you want to save the changes made to the SQL file %1? 是å¦è¦ä¿å­˜å¯¹SQL文件 %1 的修改? Could not find resource file: %1 ä¸èƒ½æ‰¾åˆ°èµ„æºæ–‡ä»¶ï¼š%1 Choose a project file to open é€‰æ‹©ä¸€ä¸ªè¦æ‰“开的项目文件 Could not open project file for writing. Reason: %1 未能写入项目文件。 原因:%1 Busy (%1) 正忙 (%1) Are you sure you want to undo all changes made to the database file '%1' since the last save? 您是å¦ç¡®å®šæƒ³æ’¤é”€è‡ªä¸Šæ¬¡ä¿å­˜ä»¥æ¥å¯¹æ•°æ®åº“文件“%1â€æ‰€åšçš„æ‰€æœ‰æ›´æ”¹ï¼Ÿ Choose a file to import 选择è¦å¯¼å…¥çš„一个文件 Text files(*.sql *.txt);;All files(*) 文本文件(*.sql *.txt);;所有文件(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. 您是å¦ç¡®è®¤æ‚¨æƒ³åˆ›å»ºä¸€ä¸ªæ–°çš„æ•°æ®åº“文件用æ¥å­˜æ”¾å¯¼å…¥çš„æ•°æ®? 如果您会到“å¦â€çš„è¯ï¼Œæˆ‘们将å°è¯•导入 SQL 文件中的数æ®åˆ°å½“剿•°æ®åº“。 Ctrl+Tab Ctrl+Tab Ctrl+Shift+Tab Ctrl+Shift+Tab Clear List 清除列表 Window Layout 窗å£å¸ƒå±€ Simplify Window Layout 简化窗å£å¸ƒå±€ Alt+Shift+0 Alt+Shift+0 Dock Windows at Bottom 窗å£åœé åº•部 Dock Windows at Left Side 窗å£åœé å·¦ä¾§ Dock Windows at Top 窗å£åœé é¡¶éƒ¨ File %1 already exists. Please choose a different name. 文件 %1 已存在。请选择一个ä¸åŒçš„å称。 Error importing data: %1 å¯¼å…¥æ•°æ®æ—¶å‡ºé”™: %1 Import completed. 导入完æˆã€‚ Delete View 删除视图 Modify View 修改视图 Delete Trigger 删除触å‘器 Modify Trigger 修改触å‘器 Delete Index 删除索引 Delete Table 删除表 Setting PRAGMA values will commit your current transaction. Are you sure? 设置 PRAGMA 值将会æäº¤æ‚¨çš„当å‰äº‹åŠ¡ã€‚ 您确定å—? In-Memory database 内存数æ®åº“ Automatically load the last opened DB file at startup Ctrl+Alt+0 Ctrl+Alt+0 Ctrl+Alt+W Ctrl+Alt+W Choose a database file to save under 选择数æ®åº“文件ä¿å­˜ä½ç½® Error while saving the database to the new file. ä¿å­˜æ•°æ®åº“到新文件时出错。 Are you sure you want to delete the table '%1'? All data associated with the table will be lost. 你确定è¦åˆ é™¤è¡¨ '%1' å—? 所有关è”的数æ®éƒ½ä¼šä¸¢å¤±ã€‚ Are you sure you want to delete the view '%1'? 你确定è¦åˆ é™¤è§†å›¾ '%1' å—? Are you sure you want to delete the trigger '%1'? 你确定è¦åˆ é™¤è§¦å‘器 '%1' å—? Are you sure you want to delete the index '%1'? 你确定è¦åˆ é™¤ç´¢å¼• '%1' å—? Error: could not delete the table. 错误: 无法删除表。 Error: could not delete the view. 错误: 无法删除视图。 Error: could not delete the trigger. 错误: 无法删除触å‘器。 Error: could not delete the index. 错误: 无法删除索引。 Message from database engine: %1 æ¥è‡ªæ•°æ®åº“引擎的消æ¯: %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? 编辑表格之å‰éœ€è¦ç«‹åˆ»ä¿å­˜æ‰€æœ‰ä¿®æ”¹ã€‚ 你确定è¦ä¿å­˜æ•°æ®åº“å—? You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. ä½ å·²ç»åœ¨æ‰§è¡ŒSQL语å¥ã€‚是å¦è¦åœæ­¢æ‰§è¡Œå¹¶æ”¹ä¸ºæ‰§è¡Œå½“å‰è¯­å¥ï¼Ÿæ³¨æ„,这å¯èƒ½ä½¿æ•°æ®åº“处于ä¸å‡†ç¡®çš„状æ€ã€‚ -- EXECUTING SELECTION IN '%1' -- -- 执行 '%1' 中所选 -- -- EXECUTING LINE IN '%1' -- -- 执行 '%1' 中的行 -- -- EXECUTING ALL IN '%1' -- -- 执行 '%1' 中所有 -- %1 rows returned in %2ms %1 行返回,耗时 %2ms Choose text files 选择文本文件 Import completed. Some foreign key constraints are violated. Please fix them before saving. 导入完æˆã€‚一些外键约æŸè¢«è¿å了。请在ä¿å­˜ä¹‹å‰ä¿®å¤ã€‚ Modify Index 修改索引 Modify Table 修改表 Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. 选择拖放一些文件所è¦åº”用的æ“作。<br/>注æ„ï¼šåªæœ‰â€œå¯¼å…¥â€ä¼šå¤„ç†å¤šä¸ªæ–‡ä»¶ã€‚ Do you want to save the changes made to SQL tabs in the project file '%1'? 是å¦è¦å°†å¯¹ SQL 标签页的修改ä¿å­˜åˆ°é¡¹ç›®æ–‡ä»¶ '%1'? Select SQL file to open é€‰æ‹©è¦æ‰“开的 SQL 文件 Select file name 选择文件å Select extension file 选择扩展文件 Extension successfully loaded. 扩展æˆåŠŸåŠ è½½ã€‚ Error loading extension: %1 加载扩展时出错: %1 Don't show again ä¸å†æ˜¾ç¤º New version available. 新版本å¯ç”¨ã€‚ DB file '%1' could not be opened 无法打开数æ®åº“文件 '%1' Table '%1' not found; settings ignored 找ä¸åˆ°è¡¨ '%1'; 设置已忽略 -- Reference to file "%1" (not supported by this version) -- -- 引用文件 "%1" (æ­¤ç‰ˆæœ¬æš‚ä¸æ”¯æŒ) -- Project saved to file '%1' 项目已ä¿å­˜åˆ°æ–‡ä»¶ '%1' Collation needed! Proceed? éœ€è¦æ•´ç†! ç»§ç»­? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! æ•°æ®åº“中的一个表需è¦ç‰¹å®šçš„æ•´ç†æ–¹æ³• '%1' 但本应用程åºä¸äº†è§£æ•…无法æä¾›ã€‚ 如果您选择继续,å°å¿ƒå¯èƒ½ä¼šæœ‰ä¸å¥½çš„事情å‘生。 记得备份! creating collation åˆ›å»ºæ•´ç† Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. 为 SQL 标签页设置新å称。使用 '&&' 字符æ¥å…许它作为键盘快æ·é”®ã€‚ Please specify the view name 请指定视图åç§° There is already an object with that name. Please choose a different name. 已有åŒå的对象。请选择一个ä¸åŒçš„å称。 View successfully created. 视图创建æˆåŠŸã€‚ Error creating view: %1 创建视图出错: %1 This action will open a new SQL tab for running: 此动作会打开新的 SQL 标签页以è¿è¡Œ: Press Help for opening the corresponding SQLite reference page. 按下帮助以打开对应的 SQLite å‚考页。 NullLineEdit Set to NULL 设置为 NULL Alt+Del PlotDock Plot 绘图 <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>æ­¤é¢æ¿æ˜¾ç¤ºå½“å‰è¡¨æˆ–者刚刚执行的查询的列。你å¯ä»¥é€‰æ‹©åˆ—用åšåœ¨ä¸‹é¢ç”»å›¾æ—¶çš„ X è½´å’Œ Y 轴。表中显示检测到的会影å“绘图结果的轴类型。Y è½´åªå…许选择数值类型,但 X è½´å¯ä»¥é€‰æ‹©:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日期/æ—¶é—´</span>: æ ¼å¼åŒ–的字符串 &quot;yyyy-MM-dd hh:mm:ss&quot; 或 &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日期</span>: æ ¼å¼åŒ–的字符串 &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">æ—¶é—´</span>: æ ¼å¼åŒ–的字符串 &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">标签</span>: å…¶ä»–æ ¼å¼çš„字符串。选这项作为x轴,会绘制æ¡å½¢å›¾ï¼Œå¹¶ç”¨å€¼ä½œä¸ºæ¡å½¢çš„æ ‡ç­¾</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">数值</span>: 整数或实数值</li></ul><p>åŒå‡» Y å•元格å¯ä»¥æ”¹å˜å›¾ä¸­æ‰€ç”¨çš„颜色。</p></body></html> Columns 列 X X Y1 Y1 Y2 Y2 Axis Type 轴类型 Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. 这是在你在上é¢é€‰æ‹© x å’Œ y 值åŽç»˜åˆ¶å‡ºçš„图。 点击点å¯ä»¥åœ¨å›¾å’Œè¡¨æ ¼ä¸­é€‰ä¸­å®ƒä»¬ã€‚Ctrl+点击以选中一批点。 使用鼠标滚轮å¯ä»¥ç¼©æ”¾ï¼Œé¼ æ ‡æ‹–拽å¯ä»¥æ”¹å˜å标轴的范围。 选择轴或者轴上的标签并拖拽å¯ä»¥ç¼©æ”¾æ­¤æ–¹å‘。 Line type: 线形: None æ—  Line 折线 StepLeft 左阶梯 StepRight å³é˜¶æ¢¯ StepCenter 中阶梯 Impulse 脉冲 Point shape: 点形: Cross å‰ Plus 加 Circle 圈 Disc 实心点 Square 方形 Diamond è±å½¢ Star 星 Triangle 三角 TriangleInverted 倒三角 CrossSquare å‰ä¸Žæ–¹å½¢ PlusSquare 加与方形 CrossCircle å‰ä¸Žåœˆ PlusCircle 加与圈 Peace å’Œå¹³ç¬¦å· <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>ä¿å­˜å½“å‰å›¾è¡¨...</p><p>æ–‡ä»¶æ ¼å¼æŒ‰æ‰©å±•å选择(png, jpg, pdf, bmp)</p></body></html> Save current plot... ä¿å­˜å½“å‰å›¾è¡¨... Load all data and redraw plot 载入所有数æ®å¹¶é‡æ–°ç»˜å›¾ Row # 行 # Copy å¤åˆ¶ Print... 打å°... Show legend 显示图例 Stacked bars å †å çš„æ¡å½¢ Fixed number format å›ºå®šæ•°å­—æ ¼å¼ Date/Time 日期/æ—¶é—´ Date 日期 Time æ—¶é—´ Numeric 数值 Label 标签 Invalid 无效的 Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. 载入所有数æ®å¹¶é‡æ–°ç»˜å›¾ã€‚ 警告:由于部分加载机制,现在并没有加载所有的数æ®ã€‚ Choose an axis color é€‰ä¸€ä¸ªåæ ‡è½´é¢œè‰² Choose a filename to save under 选择一个文件åä¿å­˜ PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;所有文件(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. 图中有曲线,选择的线形åªèƒ½ç”¨åˆ°æŒ‰ X 排列的图中。è¦ä¹ˆå¯¹è¡¨æŽ’åºæˆ–者用 X 查询,è¦ä¹ˆé€‰ä¸€ç§æ›²çº¿æ”¯æŒçš„线形:无或者折线。 Loading all remaining data for this table took %1ms. 加载表中全部剩余数æ®èŠ±è´¹äº†%1毫秒。 PreferencesDialog Preferences 首选项 &General 通用(&G) Remember last location è®°ä½ä¸Šæ¬¡çš„ä½ç½® Always use this location 总是使用此ä½ç½® Remember last location for session only 仅在会è¯ä¸­è®°ä½ä¸Šæ¬¡çš„ä½ç½® Lan&guage 语言(&G) Automatic &updates 自动更新(&A) &Database æ•°æ®åº“(&D) Database &encoding æ•°æ®åº“ç¼–ç (&E) Open databases with foreign keys enabled. 打开å¯ç”¨äº†å¤–键的数æ®åº“。 &Foreign keys 外键(&F) enabled å¯ç”¨ Default &location 默认ä½ç½®(&L) ... ... Remove line breaks in schema &view 删除架构视图中的æ¢è¡Œ(&V) Show remote options 显示远程选项 Prefetch block si&ze 预å–å—尺寸(&Z) SQ&L to execute after opening database 打开数æ®åº“åŽæ‰§è¡Œçš„ SQL(&L) Default field type 默认字段类型 Data &Browser æ•°æ®æµè§ˆå™¨(&B) Font 字体 &Font 字体(&F) Content 内容 Symbol limit in cell å•元格字符数é™åˆ¶ NULL 空 Regular 常规 Binary 二进制 Background 背景 Filters 过滤 Threshold for completion and calculation on selection 自动完æˆä¸Žæ±‡æ€»é™åˆ¶ Show images in cell 显示å•元格中图片 Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. å¯ç”¨æ­¤é€‰é¡¹å¯ä»¥é¢„览å•元格BOLB中包å«çš„å›¾ç‰‡ã€‚ä½†è¿™ä¼šå½±å“æµè§ˆæ•°æ®çš„æ€§èƒ½ã€‚ Escape character 转义字符 Delay time (&ms) å»¶æ—¶(毫秒)(&M) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. 设置应用新过滤值å‰çš„等待时间。设为0以ç¦ç”¨ç­‰å¾…。 &SQL &SQL Context 上下文 Colour 颜色 Bold 粗体 Italic 斜体 Underline 下划线 Keyword 关键字 Function 函数 Table 表 Comment 注释 Identifier 识别符 String 字符串 Current line 当å‰è¡Œ SQL &editor font size SQL 编辑器字体大å°(&E) Tab size Tab 长度 SQL editor &font SQL 编辑器字体(&F) Error indicators 显示代ç é”™è¯¯ Hori&zontal tiling 水平平铺(&Z) If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. 如果å¯ç”¨ï¼ŒSQL ç¼–è¾‘å™¨å’Œç»“æžœè¡¨è§†å›¾å°†å¹¶æŽ’æ˜¾ç¤ºï¼Œè€Œä¸æ˜¯ä¸Šä¸‹æ˜¾ç¤ºã€‚ Code co&mpletion 自动补全(&M) Toolbar style 工具æ é£Žæ ¼ Only display the icon 仅显示图标 Only display the text 仅显示文本 The text appears beside the icon æ–‡æœ¬åœ¨å›¾æ ‡æ— The text appears under the icon 文本在图标下 Follow the style éµå¾ªé£Žæ ¼ DB file extensions æ•°æ®åº“文件扩展 Manage ç®¡ç† Main Window ä¸»çª—å£ Database Structure æ•°æ®åº“结构 Browse Data æµè§ˆæ•°æ® Execute SQL 执行 SQL Edit Database Cell 编辑数æ®åº“å•元格 When this value is changed, all the other color preferences are also set to matching colors. 改å˜è¿™ä¸ªé€‰é¡¹ä¹Ÿä¼šæ”¹å˜å…¶ä»–的颜色风格。 Follow the desktop style è·Ÿéšæ¡Œé¢é£Žæ ¼ Dark style 黑暗风格 Application style 界é¢é£Žæ ¼ This sets the font size for all UI elements which do not have their own font size option. 此项设定所有无专门字å·é€‰é¡¹çš„界é¢å…ƒç´ çš„å­—å·ã€‚ Font size å­—ä½“å¤§å° Max Recent Files “最近的文件â€ä¸Šé™ Prompt to save SQL tabs in new project file 关闭 SQL 标签页时æç¤ºä¿å­˜åˆ°é¡¹ç›®æ–‡ä»¶ If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. 如果å¯ç”¨ï¼Œåœ¨ SQL 编辑器的标签页中åšå‡ºæ›´æ”¹åŽï¼Œå…³é—­é‚£äº›æ ‡ç­¾é¡µå°†å¼•出一个是å¦ä¿å­˜æ–°â€œé¡¹ç›®æ–‡ä»¶â€çš„ç¡®è®¤å¯¹è¯æ¡†ã€‚ When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. 当å¯ç”¨æ—¶ï¼Œæ•°æ®åº“结构标签页中的架构列里的æ¢è¡Œï¼Œæ˜¾ç¤ºã€æ‰“å°æ—¶è¢«ç§»é™¤ã€‚ Database structure font size æ•°æ®åº“ç»“æž„å­—ä½“å¤§å° Font si&ze 字体大å°(&Z) This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. å¯ç”¨ä¸€äº›è€—费资æºçš„计算的最大行数,包括: å¯ç”¨è‡ªåŠ¨å®Œæˆçš„表中最大行数。 自动进行求和与平å‡å€¼çš„æœ€å¤§é€‰æ‹©å•元格数é‡ã€‚ å¯ä»¥è®¾ç½®ä¸º0以ç¦ç”¨è¿™äº›åŠŸèƒ½ã€‚ This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. 这是表å¯ç”¨æ ¹æ®å½“å‰å€¼çš„自动补完的最大的列数é‡ã€‚ 设置æˆ0以ç¦ç”¨è¡¥å®Œã€‚ Field display 字段显示 Light style 亮色 Displayed &text 显示的文本(&T) Formatted æ ¼å¼åŒ–åŽ Click to set this color 点击设置颜色 Text color 文本颜色 Background color 背景颜色 Preview only (N/A) 仅预览 (N/A) Foreground 剿™¯ Selection background 选中项背景色 Selection foreground 选䏭项剿™¯è‰² Highlight 高亮 SQL &results font size SQL 结果的字体大å°(&R) Use tabs for indentation 使用制表符缩进 When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. å¯ç”¨åŽï¼ŒTab 键将æ’入制表符和空格字符用于缩进。ä¸å¯ç”¨åˆ™åªä½¿ç”¨ç©ºæ ¼ã€‚ &Wrap lines æ¢è¡Œ(&W) Never æ°¸ä¸ At word boundaries 按照è¯è¾¹ç•Œ At character boundaries 按照字æ¯è¾¹ç•Œ At whitespace boundaries 按照空白字符边界 &Quotes for identifiers 标识转义(&Q) Choose the quoting mechanism used by the application for identifiers in SQL code. 选择 SQL 代ç ä¸­æ ‡è¯†çš„转义方å¼ã€‚ "Double quotes" - Standard SQL (recommended) "åŒå¼•å·" - 标准 SQL (推è) `Grave accents` - Traditional MySQL quotes `é‡éŸ³ç¬¦` - ç»å…¸çš„ MySQL 转义 [Square brackets] - Traditional MS SQL Server quotes [方括å·] - ç»å…¸çš„ MS SQL Server 转义 Keywords in &UPPER CASE 关键字大写(&U) When set, the SQL keywords are completed in UPPER CASE letters. 设置时,SQL 关键字被自动补全为大写字æ¯ã€‚ When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background 设置时,导致上次执行期间出错的 SQL 代ç è¡Œä¼šè¢«é«˜äº®ï¼Œå¹¶åœ¨ç»“æžœé¢æ¿ä¸­æ ‡äº® Close button on tabs 标签页上的关闭按钮 If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. 如果å¯ç”¨ï¼ŒSQL 编辑器的标签页将有一个关闭按钮。无论该项是å¦å¯ç”¨ï¼Œå³é”®èœå•和键盘快æ·é”®éƒ½å¯å…³é—­æ ‡ç­¾é¡µã€‚ &Extensions 扩展(&E) Select extensions to load for every database: 选择æ¯ä¸ªæ•°æ®åº“è¦åŠ è½½çš„æ‰©å±•: Add extension 添加扩展 Remove extension 删除扩展 Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>è™½ç„¶æ”¯æŒ REGEXP è¿ç®—符,但是 SQLite 并没有实现任何正则表达å¼ç®—法,<br/>而是回调应用程åºã€‚DB Browser for SQLite 为您实现了算法,以便您å¯ä»¥<br/>打破常规使用 REGEXP。由于算法有多ç§å¯èƒ½çš„实现,您å¯èƒ½æƒ³ç”¨å…¶ä»–的,<br/>所以您å¯ä»¥ç¦ç”¨ç®—法实现并通过扩展加载您的实现。需è¦é‡å¯åº”用程åºã€‚</p></body></html> Disable Regular Expression extension ç¦ç”¨æ­£åˆ™è¡¨è¾¾å¼æ‰©å±• <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite æä¾›äº† SQL 函数用于从共享库中加载扩展。å¯ç”¨è¿™ä¸ªé€‰é¡¹ä»¥åœ¨SQL代ç ä¸­ä½¿ç”¨ <span style=" font-style:italic;">load_extension()</span> 函数。</p><p>因安全原因,加载扩展功能默认被关闭,须在此处手动å¯ç”¨ã€‚但å³ä½¿æ­¤é€‰é¡¹æœªå¯ç”¨ï¼Œä»èƒ½é€šè¿‡ä¸Šæ–¹çš„界é¢åŠ è½½æ‰©å±•ã€‚</p></body></html> Allow loading extensions from SQL code å…许在SQL代ç é‡ŒåŠ è½½æ‰©å±• Remote 远程 CA certificates CA è¯ä¹¦ Proxy ä»£ç†æœåС噍 Configure é…ç½® Export Settings 导出设置 Import Settings 导入设置 Subject CN 主题 CN (Subject CN) Common Name 公用åç§° (Common Name) Subject O 主题 O (Subject O) Organization 组织 (Organization) Valid from 有效期从 Valid to 有效期到 Serial number åºåˆ—å· Your certificates 您的è¯ä¹¦ File 文件 Subject Common Name 主题公用åç§° (Subject Common Name) Issuer CN ç­¾å‘人 CN (Issuer CN) Issuer Common Name ç­¾å‘人公用åç§° (Issuer Common Name) Clone databases into 克隆数æ®åº“ä¿¡æ¯ Choose a directory 选择一个目录 The language will change after you restart the application. 语言将在é‡å¯åº”用程åºåŽæ”¹å˜ã€‚ Select extension file 选择扩展文件 Extensions(*.so *.dylib *.dll);;All files(*) 扩展(*.so *.dylib *.dll);;所有文件(*) Import certificate file 导入è¯ä¹¦æ–‡ä»¶ No certificates found in this file. 在文件中找ä¸åˆ°è¯ä¹¦ã€‚ Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! 您确定è¦åˆ é™¤æ­¤è¯ä¹¦å—?所有的è¯ä¹¦æ•°æ®éƒ½ä¼šè¢«ä»Žåº”ç”¨è®¾ç½®ä¸­åˆ é™¤ï¼ Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. ä½ ç¡®å®šè¦æ¸…除所有ä¿å­˜çš„设置å—? 所有你åšçš„设置都会丢失,并使用默认值。 Save Settings File ä¿å­˜è®¾ç½®æ–‡ä»¶ Initialization File (*.ini) åˆå§‹åŒ–文件 (*.ini) The settings file has been saved in location : 设置文件已ä¿å­˜åˆ°ï¼š Open Settings File 打开设置文件 The settings file was loaded properly. 设置文件æˆåŠŸåŠ è½½ã€‚ The selected settings file is not a normal settings file. Please check again. 所选的设置文件格å¼ä¸æ­£å¸¸ã€‚ è¯·å¤æŸ¥ã€‚ ProxyDialog Proxy Configuration ä»£ç†æœåС噍é…ç½® Pro&xy Type ä»£ç†æœåŠ¡å™¨ç±»åž‹(&X) Host Na&me 主机å(&M) Port ç«¯å£ Authentication Re&quired 需è¦èº«ä»½éªŒè¯(&Q) &User Name 用户å(&U) Password å¯†ç  None æ—  System settings è·Ÿéšç³»ç»Ÿè®¾ç½® HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data å¯¼å…¥æ•°æ®æ—¶å‡ºé”™ from record number %1 è‡ªè®°å½•ç¼–å· %1 . %1 . %1 Importing CSV file... 导入 CSV 文件... Cancel å–æ¶ˆ All files (*) 所有文件 (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) SQLite æ•°æ®åº“文件 (*.db *.sqlite *.sqlite3 *.db3) Left å·¦ Right å³ Center 居中 Justify 两段 SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) SQLite æ•°æ®åº“文件 (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) DB Browser for SQLite 项目文件 (*.sqbpro) SQL Files (*.sql) SQL 文件 (*.sql) All Files (*) 所有文件 (*) Text Files (*.txt) 纯文本文件 (*.txt) Comma-Separated Values Files (*.csv) CSV (逗å·åˆ†éš”)(*.csv) Tab-Separated Values Files (*.tsv) TSV (制表符分隔)(*.tsv) Delimiter-Separated Values Files (*.dsv) DSV (分隔符分隔)(*.dsv) Concordance DAT files (*.dat) Concordance DAT 文件 (*.dat) JSON Files (*.json *.js) JSON 文件 (*.json *.js) XML Files (*.xml) XML 文件 (*.xml) Binary Files (*.bin *.dat) 二进制文件 (*.bin *.dat) SVG Files (*.svg) SVG 文件 (*.svg) Hex Dump Files (*.dat *.bin) å六进制转储文件 (*.dat *.bin) Extensions (*.so *.dylib *.dll) 扩展 (*.so *.dylib *.dll) Initialization File (*.ini) åˆå§‹åŒ–文件 (*.ini) QsciCommand Paste 粘贴 Cancel å–æ¶ˆ QsciLexerCPP Default 默认 Keyword 关键字 Identifier 识别符 QsciLexerJSON Default 默认 String 字符串 QsciLexerJavaScript Regular expression æ­£åˆ™è¡¨è¾¾å¼ QsciLexerPython Default 默认 Comment 注释 Keyword 关键字 Identifier 识别符 QsciLexerSQL Default 默认 Comment 注释 Keyword 关键字 Identifier 识别符 QsciScintilla &Undo 撤销(&U) Select All 全选 RemoteCommitsModel Commit ID æäº¤ ID Message æ¶ˆæ¯ Date 日期 Author 作者 Size å¤§å° Authored and committed by %1 ç» %1 认è¯å¹¶æäº¤ Authored by %1, committed by %2 ç”± %1 认è¯ï¼Œç”± %2 æäº¤ RemoteDatabase Error opening local databases list. %1 打开本地数æ®åº“列表时出错。 %1 Error creating local databases list. %1 创建本地数æ®åº“列表时出错。 %1 RemoteDock Remote 远程 Local 本地 Identity 身份 Push currently opened database to server 推é€å½“剿‰“开的数æ®åº“到æœåС噍 Upload 上传 DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>åœ¨æ­¤é¢æ¿ï¼Œæ¥è‡ª dbhub.io 网站的远程数æ®åº“å¯ä»¥è¢«æ·»åŠ åˆ° DB4S。首先你需è¦ä¸€ä¸ªèº«ä»½:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">登录 dbhub.io 网站 (使用你的 GitHub è®¤è¯æˆ–其他什么)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">点击按钮创建 DB4S è¯ä¹¦ (那是你的身份)。 这会给你一个è¯ä¹¦æ–‡ä»¶ (ä¿å­˜åˆ°ä½ çš„æœ¬åœ°ç¡¬ç›˜é‡Œ)。</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">å‰å¾€ DB4S 的设置中的远程选项å¡ã€‚点击添加è¯ä¹¦ï¼Œé€‰æ‹©åˆšæ‰ä¸‹è½½çš„æ–‡ä»¶ã€‚</li></ol><p>è¿™æ ·ï¼Œè¿œç¨‹é¢æ¿å°±ä¼šæ˜¾ç¤ºä½ çš„身份,之åŽå¯ä»¥æ·»åŠ è¿œç¨‹æ•°æ®åº“。</p></body></html> Current Database 当剿•°æ®åº“ Clone 克隆 Branch 分支 Commits æäº¤ Commits for æäº¤äºŽ Delete Database 删除数æ®åº“ Delete the local clone of this database 删除此数æ®åº“的本地副本 Open in Web Browser 在网页æµè§ˆå™¨ä¸­æ‰“å¼€ Open the web page for the current database in your browser 在您的网页æµè§ˆå™¨ä¸­æ‰“å¼€ç½‘é¡µä»¥æŸ¥çœ‹å½“å‰æ•°æ®åº“ Clone from Link 从链接克隆 Use this to download a remote database for local editing using a URL as provided on the web page of the database. 用它æ¥ä»Žæ•°æ®åº“网页æä¾›çš„链接æ¥ä¸‹è½½ä¸€ä¸ªè¿œç¨‹æ•°æ®åº“以供本地编辑。 Refresh 刷新 Reload all data and update the views 刷新所有数æ®å¹¶æ›´æ–°è§†å›¾ Clone Database 克隆数æ®åº“ Open Database 打开数æ®åº“ Open the local copy of this database 打开此数æ®åº“的本地副本 Check out Commit 检出æäº¤ Download and open this specific commit 下载并打开此æäº¤ Check out Latest Commit 检出最新æäº¤ Check out the latest commit of the current branch 检出当å‰åˆ†æ”¯çš„æœ€æ–°æäº¤ Save Revision to File ä¿å­˜ä¿®è®¢ç‰ˆæœ¬åˆ°æ–‡ä»¶ Saves the selected revision of the database to another file ä¿å­˜æ‰€é€‰çš„æ•°æ®åº“修订版本到其他文件 Upload Database 上传数æ®åº“ Upload this database as a new commit 上传此数æ®åº“为新的æäº¤ <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>你正在使用内置的,åªè¯»çš„凭æ®ã€‚è¦ä¸Šä¼ ä½ çš„æ•°æ®åº“,你需è¦é…置使用你的 DBHub.io è´¦å·ã€‚</p><p>还没有 DBHub.io è´¦å·ï¼Ÿ<a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">注册一个</span></a> 并在 <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">此处</span></a> 导入你的è¯ä¹¦ã€‚</p><p>è¦èŽ·å¾—åœ¨çº¿å¸®åŠ©ï¼Œç‚¹å‡»<a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">这里</span></a>。</p></body></html> &User 用户(&U) &Database æ•°æ®åº“(&D) Back 返回 Select an identity to connect 选择用æ¥è¿žæŽ¥çš„身份 Public 公用è¯ä¹¦ This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. 这将从远程æœåŠ¡å™¨ä¸‹è½½æ•°æ®åº“以供本地编辑。 请输入è¦ä»Žå“ªä¸ªç½‘å€å…‹éš†ã€‚您å¯ä»¥ç»å¦‚下方å¼ç”Ÿæˆæ­¤ç½‘å€ï¼šç‚¹å‡»æ•°æ®åº“的网页所æä¾›çš„“在 DB4S 中克隆数æ®åº“â€ï¼ˆClone Database in DB4S)的按钮。 Invalid URL: The host name does not match the host name of the current identity. 无效网å€ï¼šä¸»æœºå称与当å‰èº«ä»½çš„主机åç§°ä¸åŒ¹é…。 Invalid URL: No branch name specified. 无效网å€ï¼šæœªæŒ‡å®šåˆ†æ”¯å称。 Invalid URL: No commit ID specified. 无效网å€ï¼šæœªæŒ‡å®šæäº¤ ID。 You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? 您已修改了这个数æ®åº“çš„æœ¬åœ°å‰¯æœ¬ã€‚èŽ·å–æ­¤æäº¤å°†è¦†ç›–本地的更改。 是å¦ç»§ç»­ï¼Ÿ The database has unsaved changes. Are you sure you want to push it before saving? æ•°æ®åº“有未ä¿å­˜çš„æ›´æ”¹ã€‚确定è¦åœ¨ä¿å­˜å‰æŽ¨é€å—? The database you are trying to delete is currently opened. Please close it before deleting. 您å°è¯•删除的数æ®åº“ç›®å‰ä»æ˜¯æ‰“开状æ€ã€‚请先关闭,å†å°è¯•删除。 This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? 这将删除此数æ®åº“的本地副本,包括其中未æäº¤çš„æ‰€æœ‰æ›´æ”¹ã€‚确定删除å—? RemoteLocalFilesModel Name åç§° Branch 分支 Last modified 上次修改 Size å¤§å° Commit æäº¤ File 文件 RemoteModel Name åç§° Last modified 上次修改 Size å¤§å° Commit æäº¤ Size: 大å°: Last Modified: 上次修改: Licence: 许å¯åè®®: Default Branch: 默认分支: RemoteNetwork Choose a location to save the file 选择ä¿å­˜è¯¥æ–‡ä»¶çš„ä½ç½® Error opening remote file at %1. %2 打开远程文件 %1 时出错。 %2 Error: Invalid client certificate specified. 错误:指定的客户端è¯ä¹¦æ— æ•ˆã€‚ Please enter the passphrase for this client certificate in order to authenticate. 请输入此客户端è¯ä¹¦çš„å£ä»¤ä»¥è¿›è¡Œèº«ä»½éªŒè¯ã€‚ Cancel å–æ¶ˆ Uploading remote database to %1 正在上传远程数æ®åº“到 %1 Downloading remote database from %1 正在下载远程数æ®åº“自 %1 Error: Cannot open the file for sending. 错误:无法打开文件以进行å‘é€ã€‚ RemotePushDialog Push database æŽ¨é€æ•°æ®åº“ Database na&me to push to 推é€çš„æ•°æ®åº“å(&m) Commit message æäº¤ä¿¡æ¯ Database licence æ•°æ®åº“许å¯åè®® Public 公开 Branch 分支 Force push å¼ºåˆ¶æŽ¨é€ Username 用户å Database will be public. Everyone has read access to it. æ•°æ®åº“将是公有的。所有人都å¯ä»¥è¯»å–它。 Database will be private. Only you have access to it. æ•°æ®åº“å°†æ˜¯ç§æœ‰çš„ã€‚åªæœ‰æ‚¨å¯ä»¥è®¿é—®å®ƒã€‚ Use with care. This can cause remote commits to be deleted. å°å¿ƒä½¿ç”¨ã€‚è¿™å¯èƒ½ä¼šå¯¼è‡´è¿œç¨‹æäº¤è¢«åˆ é™¤ã€‚ RunSql Execution aborted by user æ“作被用户终止 , %1 rows affected ,%1 行数æ®å—å½±å“ query executed successfully. Took %1ms%2 查询执行æˆåŠŸã€‚è€—æ—¶ %1ms%2 executing query 执行查询 SelectItemsPopup A&vailable å¯ç”¨(&V) Sele&cted 已选(&C) SqlExecutionArea Form è¡¨å• Find previous match [Shift+F3] 查找上一个 [Shift+F3] Find previous match with wrapping æŒ‰é¡ºåºæŸ¥æ‰¾ä¸Šä¸€é¡¹ Shift+F3 The found pattern must be a whole word æ‰¾åˆ°çš„å¿…é¡»æ˜¯ä¸€ä¸ªå®Œæ•´çš„è¯ Whole Words å…¨å­—åŒ¹é… Text pattern to find considering the checks in this frame 符åˆè¿™é‡Œçš„é€‰æ‹©è¦æŸ¥æ‰¾çš„æ–‡æœ¬ Find in editor 在编辑器中查找 The found pattern must match in letter case æœç´¢å¿…须大å°å†™åŒ¹é… Case Sensitive 大å°å†™æ•感 Find next match [Enter, F3] 查找下一个 [Enter, F3] Find next match with wrapping 循环查找下一个 F3 Interpret search pattern as a regular expression è§£æžæŸ¥æ‰¾ç›®æ ‡ä¸ºæ­£åˆ™è¡¨è¾¾å¼ <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>é€‰ä¸­æ—¶ï¼Œè¦æŸ¥æ‰¾çš„æ¨¡å¼è¢«è§£é‡Šä¸º UNIX 正则表达å¼ã€‚å‚阅 <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Wikibooks 中的正则表达å¼</a>.</p></body></html> Regular Expression æ­£åˆ™è¡¨è¾¾å¼ Close Find Bar å…³é—­æŸ¥æ‰¾æ  <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>上次执行的语å¥çš„结果。</p><p>ä½ å¯èƒ½å¸Œæœ›æŠ˜å è¿™ä¸ªçª—格并使用 <span style=" font-style:italic;">SQL 日志</span> 区域查看æäº¤è‡ª <span style=" font-style:italic;">用户</span> 的结果。</p></body></html> Results of the last executed statements 上次执行语å¥çš„结果 This field shows the results and status codes of the last executed statements. è¿™ä¸ªå­—æ®µæ˜¾ç¤ºæœ€åŽæ‰§è¡Œçš„语å¥çš„结果和状æ€ç ã€‚ Ctrl+PgUp Ctrl+PgUp Ctrl+PgDown Ctrl+PgDown Couldn't read file "%1": %2. æ— æ³•è¯»å–æ–‡ä»¶â€œ%1â€ï¼š%2。 Couldn't save file: %1. 无法ä¿å­˜æ–‡ä»¶: %1。 Your changes will be lost when reloading it! 釿–°åŠ è½½æ—¶ï¼Œä½ çš„æ›´æ”¹å°†ä¼šä¸¢å¤±ï¼ The file "%1" was modified by another program. Do you want to reload it?%2 文件 "%1" 已被其他程åºä¿®æ”¹ã€‚是å¦è¦é‡æ–°åŠ è½½ï¼Ÿ%2 Answer "Yes to All" to reload the file on any external update without further prompting. 选择“全是â€å°†è‡ªåЍ釿–°åŠ è½½æœ‰å¤–éƒ¨æ›´æ–°çš„æ–‡ä»¶ï¼Œæ— è¿›ä¸€æ­¥æç¤ºã€‚ Answer "No to All" to ignore any external update without further prompting. 选择“全å¦â€å°†å¿½ç•¥æ–‡ä»¶çš„外部更新,无进一步æç¤ºã€‚ Modifying and saving the file will restore prompting. 修改并ä¿å­˜æ–‡ä»¶å°†é‡æ–°å¼€å¯æç¤ºã€‚ SqlTextEdit Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) abs(X) å‡½æ•°è¿”å›žæ•°å­—å‚æ•° X çš„ç»å¯¹å€¼ã€‚ () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () changes() 函数返回最åŽå®Œæˆçš„ INSERTã€DELETE 或 UPDATE è¯­å¥æ‰€æ›´æ”¹ã€æ’入或删除的数æ®åº“行数。 (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) char(X1,X2,...,XN) 函数返回一个字符串,分别由整数 X1 至 XN 所代表的特定 Unicode ç ç‚¹çš„字符组æˆã€‚ (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) coalesce() å‡½æ•°è¿”å›žç¬¬ä¸€ä¸ªéž NULL çš„å‚æ•°çš„å‰¯æœ¬ï¼Œæ‰€æœ‰å‚æ•°å‡ä¸º NULL 则返回 NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) glob(X,Y) å‡½æ•°ç­‰æ•ˆäºŽè¡¨è¾¾å¼ "Y GLOB X"。 (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) ifnull() å‡½æ•°è¿”å›žç¬¬ä¸€ä¸ªéž NULL çš„å‚æ•°çš„å‰¯æœ¬ï¼Œä¸¤ä¸ªå‚æ•°å‡ä¸º NULL 则返回 NULL。 (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) instr(X,Y) 函数查找字符串 Y 在字符串 X 中的第一处匹é…,返回之å‰å­—符数加 1;如果 X 中找ä¸åˆ° Y,则返回 0。 (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) hex() å‡½æ•°å°†å…¶å‚æ•°è§£é‡Šä¸ºä¸€ä¸ª BLOB 并返回一个字符串,该字符串是该 Blob 内容的大写å六进制表现形å¼ã€‚ (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) iif(X,Y,Z) 函数在 X 为真(true)时返回 Y,å¦åˆ™è¿”回 Z。 () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () last_insert_rowid() 函数返回调用该函数的数æ®åº“连接所æ’入的最åŽä¸€è¡Œçš„ ROWID。 (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) 对字符串值 X,length(X) 函数返回 X 的字符数(éžå­—节数)(截至首个 NUL 字符)。 (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) like() 函数用于实现"Y LIKE X" 表达å¼ã€‚ (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) like() 函数用于实现 "Y LIKE X ESCAPE Z" 表达å¼ã€‚ (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) load_extension(X) 函数从共享库文件 X 加载 SQLite 扩展。 必须在“首选项â€ä¸­æŽˆæƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚ (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) load_extension(X) 函数从共享库文件 X çš„ å…¥å£ç‚¹ Y 加载 SQLite 扩展。 必须在“首选项â€ä¸­æŽˆæƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚ (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) lower(X) 函数返回字符串 X 的副本,其中将所有 ASCII 字符转æ¢ä¸ºå°å†™ã€‚ (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) 移除 X 中左侧的空白字符。 (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) ltrim(X,Y) 函数返回一个字符串,该字符串是从 X 中的左侧删除所有 Y 而组æˆã€‚ (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) å¤šå‚æ•°çš„ max() å‡½æ•°è¿”å›žæœ‰æœ€å¤§å€¼çš„å‚æ•°ï¼Œå¦‚æœ‰ä»»ä½•å‚æ•°ä¸º NULL 则返回 NULL。 (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) å¤šå‚æ•°çš„ min() 函数返回有最å°å€¼çš„傿•°ã€‚ (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) nullif(X,Y) å‡½æ•°åœ¨ä¼ å…¥çš„ä¸¤ä¸ªå‚æ•°ä¸åŒæ—¶è¿”å›žé¦–ä¸ªå‚æ•°ï¼›ä¸¤ä¸ªå‚数相åŒåˆ™è¿”回 NULL。 (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) printf(FORMAT,...) SQL 函数的功效类似 sqlite3_mprintf() C 语言函数和标准 C 语言库中的 printf() 函数。 (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) quote(X) 函数返回一个 SQL 语法的文本形å¼ï¼Œé€‚åˆåœ¨å„ç§ SQL 语å¥ä¸­ç”¨ä½œå‚数值。 () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () random() å‡½æ•°è¿”å›žä¸€ä¸ªä¼ªéšæœºæ•´æ•°ï¼ŒèŒƒå›´åœ¨ -9223372036854775808 至 +9223372036854775807 之间。 (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) randomblob(N) 函数返回一个长度为 N 字节的 Blob,包å«ä¼ªéšæœºçš„å­—èŠ‚ã€‚ (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) replace(X,Y,Z) 函数返回一个字符串,其中是将字符串 X 中的æ¯ä¸ª Y 字符串替æ¢ä¸º Z 字符串。 (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) round(X) 函数返回一个浮点值,X 被四èˆäº”入为 0 ä¸ªå°æ•°ã€‚ (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X) round(X) 函数返回一个浮点值,X 被四èˆäº”入为 Y ä¸ªå°æ•°ã€‚ (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) 移除 X 中å³ä¾§çš„空白字符。 (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) rtrim(X,Y) 函数返回一个字符串,该字符串是从 X 中的å³ä¾§åˆ é™¤æ‰€æœ‰ Y 而组æˆã€‚ (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) soundex(X) 函数返回一个字符串,由字符串 X çš„ soundex ç¼–ç ç»„æˆã€‚ (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) 函数返回字符串 X 中第 Y 个字符开始的所有字符。 (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) substr(X,Y,Z) 函数返回输入字符串 X 中第 Y 个字符开始的 Z 个长字符。 () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () total_changes() å‡½æ•°è¿”å›žå½“å‰æ•°æ®åº“è¿žæŽ¥æ‰“å¼€ä»¥æ¥ INSERTã€UPDATE 或 DELETE è¯­å¥æ›´æ”¹çš„行数总计。 (X) trim(X) removes spaces from both ends of X. (X) trim(X) 移除 X 中左å³ä¸¤ä¾§çš„空白字符。 (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) trim(X,Y) 函数返回一个字符串,从 X 的左å³ä¸¤ç«¯åˆ é™¤æ‰€æœ‰ Y 字符。 (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) typeof(X) å‡½æ•°è¿”å›žä¸€ä¸ªå­—ç¬¦ä¸²ï¼Œè¡¨ç¤ºè¡¨è¾¾å¼ X 的数æ®ç±»åž‹ã€‚ (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) unicode(X) 函数字符串 X 的第一个字符所对应的 Unicode 代ç ç‚¹æ•°å­—。 (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) upper(X) 函数返回输入字符串的副本,其中所有å°å†™ ASCII 字符转æ¢ä¸ºç­‰æ•ˆçš„大写字æ¯ã€‚ (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) zeroblob(N) 函数返回一个 BLOB,由 N 个字节的 0x00 组æˆã€‚ (timestring,modifier,modifier,...) (时间字符串,修饰符,修饰符,...) (format,timestring,modifier,modifier,...) (æ ¼å¼,时间字符串,修饰符,修饰符,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) avg() å‡½æ•°è¿”å›žä¸€ä¸ªç»„ä¸­æ‰€æœ‰éž NULL çš„ X 的平å‡å€¼ã€‚ (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) count(X) å‡½æ•°è¿”å›žä¸€ä¸ªç»„ä¸­æ‰€æœ‰éž NULL çš„ X 的数é‡ã€‚ (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) group_concat() 函数返回一个字符串,由 X çš„æ‰€æœ‰éž NULL 值串è”而æˆã€‚ (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) group_concat() 函数返回一个字符串,由 X çš„æ‰€æœ‰éž NULL 值串è”而æˆã€‚如果æä¾›äº† Y,Y ä½œä¸ºä¸²è” X 时的分隔符。 (X) The max() aggregate function returns the maximum value of all values in the group. (X) max() èšåˆå‡½æ•°è¿”回组中所有值的最大值。 (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) min() èšåˆå‡½æ•°è¿”å›žç»„ä¸­æ‰€æœ‰å€¼çš„éž NULL 的最å°å€¼ã€‚ (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) sum() å’Œ total() èšåˆå‡½æ•°è¿”å›žç»„ä¸­æ‰€æœ‰å€¼çš„éž NULL 值的总计。 () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () 当å‰åˆ†åŒºå†…的行数。行数从 1 开始,以 ORDER BY å­å¥æŒ‡å®šçš„é¡ºåºæŽ’åˆ—ï¼ˆæœªæä¾›åˆ™ä»¥ä»»æ„é¡ºåºæŽ’åˆ—ï¼‰ã€‚ () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) 傿•° N 被视为一个整数。此函数将分区尽å¯èƒ½å‡åŒ€åœ°åˆ’分为 N 个组,并按照 ORDER BY å­—å¥å®šä¹‰çš„顺åºï¼ˆæˆ–ä»»æ„顺åºï¼‰ï¼Œä¸ºæ¯ä¸ªç»„分é…一个 1 至 N 之间的整数。如ä¸å¾—已,较大的组会先出现。此函数返回分é…给当å‰è¡Œçš„代表所属组的整数值。 (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (表达å¼) è¿”å›žå¯¹åˆ†åŒºä¸­ä¸Šä¸€è¡Œçš„è¡¨è¾¾å¼æ±‚值结果。如果当å‰è¡Œæ˜¯ç¬¬ä¸€è¡Œï¼Œè¿”回 NULL。 (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (表达å¼,åç§») 如果æä¾›åç§»å‚æ•°ï¼Œå®ƒé¡»æ˜¯éžè´Ÿæ•°æ•´æ•°ã€‚此时返回针对分区中当å‰è¡Œå‡åŽ»è¡Œåç§»æ‰€å¯¹åº”çš„è¡Œæ¥æ±‚值表达å¼çš„结果。如果å移为0,则求值当å‰è¡Œã€‚如果当å‰è¡Œä¹‹å‰æ²¡æœ‰å¯¹åº”å移的行,返回 NULL。 (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (表达å¼,åç§»,默认值) 如果还æä¾›é»˜è®¤å€¼å‚数,在å移所标定的行ä¸å­˜åœ¨æ—¶ï¼Œè¿”å›žé»˜è®¤å€¼è€Œéž NULL。 (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (表达å¼) è¿”å›žå¯¹åˆ†åŒºä¸­ä¸‹ä¸€è¡Œçš„è¡¨è¾¾å¼æ±‚值结果。如果没有下一行,返回 NULL。 (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (表达å¼,åç§») 如果æä¾›åç§»å‚æ•°ï¼Œå®ƒé¡»æ˜¯éžè´Ÿæ•°æ•´æ•°ã€‚此时返回针对分区中当å‰è¡ŒåŠ ä¸Šè¡Œåç§»æ‰€å¯¹åº”çš„è¡Œæ¥æ±‚值表达å¼çš„结果。如果å移为0,则求值当å‰è¡Œã€‚如果当å‰è¡Œä¹‹å‰æ²¡æœ‰å¯¹åº”å移的行,返回 NULL。 (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (X) Return the arccosine of X. The result is in radians. (X) 返回 X çš„å余弦。结果以弧度为å•ä½ã€‚ (X) Return the hyperbolic arccosine of X. (X) 返回 X çš„ååŒæ›²ä½™å¼¦ã€‚ (X) Return the arcsine of X. The result is in radians. (X) 返回 X çš„åæ­£å¼¦ã€‚结果以弧度为å•ä½ã€‚ (X) Return the hyperbolic arcsine of X. (X) Return the arctangent of X. The result is in radians. (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X) Return the hyperbolic arctangent of X. (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) Return the cosine of X. X is in radians. (X) 返回 X 的余弦。X çš„å•使˜¯å¼§åº¦ã€‚ (X) Return the hyperbolic cosine of X. (X) Convert value X from radians into degrees. (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) Return the natural logarithm of X. (B,X) Return the base-B logarithm of X. (X) Return the base-10 logarithm for X. (X) Return the logarithm base-2 for the number X. (X,Y) Return the remainder after dividing X by Y. (X,Y) 返回 X 除以 Y åŽçš„余数。 () Return an approximation for Ï€. () 返回 Ï€ 的近似值。 (X,Y) Compute X raised to the power Y. (X,Y) 计算 X çš„ Y 次方。 (X) Convert X from degrees into radians. (X) å°† X 从角度转æ¢ä¸ºå¼§åº¦ã€‚ (X) Return the sine of X. X is in radians. (X) 返回 X 的正弦值。X çš„å•使˜¯å¼§åº¦ã€‚ (X) Return the hyperbolic sine of X. (X) Return the square root of X. NULL is returned if X is negative. (X) Return the tangent of X. X is in radians. (X) Return the hyperbolic tangent of X. (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. SqliteTableModel reading rows 读å–行 loading... 正在加载... References %1(%2) Hold %3Shift and click to jump there 引用 %1(%2) æŒ‰ä½ %3Shift 并点击以跳转 Error changing data: %1 更改数æ®åº“时出错: %1 retrieving list of columns 正在检索列的列表 Fetching data... æ­£åœ¨æ‹‰å–æ•°æ®... Cancel å–æ¶ˆ TableBrowser Browse Data æµè§ˆæ•°æ® &Table: 表(&T): Select a table to browse data 选择一个表以æµè§ˆæ•°æ® Use this list to select a table to be displayed in the database view ä½¿ç”¨è¿™ä¸ªåˆ—è¡¨é€‰æ‹©ä¸€ä¸ªè¦æ˜¾ç¤ºåœ¨æ•°æ®åº“视图中的表 This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. 这是数æ®åº“表视图。你å¯ä»¥è¿›è¡Œä»¥ä¸‹æ“作: - 直接打字以在这里直接编辑。 - åŒå‡»è®°å½•以打开å•元格编辑窗å£ã€‚ - Alt+Del 删除å•å…ƒæ ¼å†…å®¹ï¼Œå˜æˆNULL。 - Ctrl+" é‡å¤ä¸€ä»½å½“å‰è®°å½•。 - Ctrl+' 从上é¢çš„å•元格拷è´ã€‚ - 标准的å¤åˆ¶/粘贴æ“作。 Text pattern to find considering the checks in this frame 符åˆè¿™é‡Œçš„é€‰æ‹©è¦æŸ¥æ‰¾çš„æ–‡æœ¬ Find in table 在表中查找 Find previous match [Shift+F3] 查找上一个 [Shift+F3] Find previous match with wrapping æŒ‰é¡ºåºæŸ¥æ‰¾ä¸Šä¸€é¡¹ Shift+F3 Find next match [Enter, F3] 查找下一个 [Enter, F3] Find next match with wrapping 循环查找下一个 F3 The found pattern must match in letter case 查找结果须是相åŒçš„大å°å†™å½¢å¼ Case Sensitive 大å°å†™æ•感 The found pattern must be a whole word 查找结果需是完整字è¯è€Œéžæ‹†åˆ†å‡ºçš„一部分 Whole Cell å…¨è¯åŒ¹é… Interpret search pattern as a regular expression 查找内容解æžä¸ºä¸€ä¸ªæ­£åˆ™è¡¨è¾¾å¼ <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>选中时,æœç´¢å…³é”®è¯è¢«è§†ä¸ºUNIX正则表达å¼ã€‚å‚阅<a href="https://en.wikibooks.org/wiki/Regular_Expressions">Wikibooks 上对正则表达å¼çš„介ç»</a>。</p></body></html> Regular Expression æ­£åˆ™è¡¨è¾¾å¼ Close Find Bar å…³é—­æŸ¥æ‰¾æ  Text to replace with è¦æ›¿æ¢çš„æ–‡æœ¬ Replace with æ›¿æ¢ Replace next match 替æ¢ä¸‹ä¸ªåŒ¹é…的文本 Replace æ›¿æ¢ Replace all matches æ›¿æ¢æ‰€æœ‰åŒ¹é… Replace all å…¨éƒ¨æ›¿æ¢ Export to &JSON 导出到 &JSON Export the filtered data to JSON å¯¼å‡ºè¿‡æ»¤åŽæ•°æ®åˆ° JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. 此按钮是将当å‰è¢«æ˜¾ç¤ºã€è¢«æµè§ˆçš„表的数æ®å¯¼å‡ºåˆ°ä¸€ä¸ª JSON 文件。数æ®ç»è¿‡æ»¤å™¨ã€æ˜¾ç¤ºæ ¼å¼å’Œåˆ—顺åºé¡ºåˆ©ã€‚ Copy column name å¤åˆ¶åˆ—å Copy the database table column name to your clipboard å¤åˆ¶æ•°æ®åº“表的列ååˆ°ä½ çš„å‰ªè´´æ¿ New Data Browser æ–°å»ºæ•°æ®æµè§ˆå™¨ Add a new docked Data Browser æ–°å¢žä¸€ä¸ªæ•°æ®æµè§ˆå™¨æ ‡ç­¾é¡µ This button adds a new docked Data Browser, which you can detach and arrange in different layouts. æ­¤æŒ‰é’®ä¼šæ·»åŠ ä¸€ä¸ªæ–°çš„æ•°æ®æµè§ˆå™¨æ ‡ç­¾é¡µï¼Œæ‚¨å¯ä»¥å°†å…¶åˆ†ç¦»å¹¶ç½®å…¥å…¶ä»–布局。 <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>滚动到开始</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>点击这个按钮在上é¢çš„表视图中导航到最å‰ã€‚</p></body></html> |< |< Scroll one page upwards 上翻一页 <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>点击按钮将表中显示的记录å‘上翻一页。</p></body></html> < < 0 - 0 of 0 0 - 0 / 0 Scroll one page downwards 下翻一页 <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>点击按钮将表中显示的记录å‘下翻一页。</p></body></html> > > Scroll to the end æ»šåŠ¨åˆ°ç»“æŸ <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>点击这个按钮在上é¢çš„表视图中导航到最åŽã€‚</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>点击这里跳到指定的记录</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>这个按钮用于导航到在“转到â€åŒºåŸŸä¸­æŒ‡å®šçš„记录å·ã€‚</p></body></html> Go to: 转到: Enter record number to browse è¾“å…¥è¦æµè§ˆçš„è®°å½•å· Type a record number in this area and click the Go to: button to display the record in the database view 在这个区域中输入一个记录å·ï¼Œå¹¶ç‚¹å‡»â€œè½¬åˆ°:â€æŒ‰é’®ä»¥åœ¨æ•°æ®åº“视图中显示记录 1 1 Show rowid column 显示 rowid 列 Toggle the visibility of the rowid column åˆ‡æ¢ rowid 列的å¯è§æ€§ Unlock view editing è§£é”视图编辑 This unlocks the current view for editing. However, you will need appropriate triggers for editing. è§£é”当å‰è§†å›¾ä»¥ç¼–辑。然而,你需è¦åˆé€‚的触å‘器æ¥ç¼–辑。 Edit display format ç¼–è¾‘æ˜¾ç¤ºæ ¼å¼ Edit the display format of the data in this column 编辑列中数æ®çš„æ˜¾ç¤ºæ ¼å¼ New Record 新建记录 Insert a new record in the current table 在当å‰è¡¨ä¸­æ’å…¥ä¸€æ¡æ–°è®°å½• <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>此按钮在数æ®åº“中创建新记录。按ä½é¼ æ ‡æŒ‰é’®ä»¥æ‰“å¼€èœå•选择ä¸åŒé€‰é¡¹ï¼š</p><ul><li><span style=" font-weight:600;">新记录</span>: 用默认值æ’å…¥ä¸€æ¡æ–°è®°å½•到数æ®åº“中。</li><li><span style=" font-weight:600;">æ’入值...</span>: æ‰“å¼€å¯¹è¯æ¡†ç¼–è¾‘è¦æ’入的值。å¯ä»¥è¾“入满足约æŸçš„值。如果 <span style=" font-weight:600;">新记录</span> é€‰é¡¹å¤±è´¥ï¼Œå¯¹è¯æ¡†ä¹Ÿä¼šæ‰“开。</li></ul></body></html> Delete Record 删除记录 Delete the current record 删除当å‰è®°å½• This button deletes the record or records currently selected in the table 此按钮删除表里当å‰é€‰ä¸­çš„记录 Insert new record using default values in browsed table 用默认值æ’å…¥ä¸€æ¡æ–°è®°å½•åˆ°å½“å‰æµè§ˆçš„表中 Insert Values... æ’入值... Open a dialog for inserting values in a new record æ‰“å¼€å¯¹è¯æ¡†ä»¥æ’入值到新记录中 Export to &CSV 导出到 &CSV Export the filtered data to CSV å¯¼å‡ºå½“å‰æ•°æ®åˆ° CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. æ­¤æŒ‰é’®å¯¼å‡ºå½“å‰æµè§ˆã€è¿‡æ»¤çš„è¡¨çš„æ•°æ® (过滤åŽï¼Œæ˜¾ç¤ºæ ¼å¼å’Œåˆ—的顺åº) 到一个CSV文件。 Save as &view ä¿å­˜ä¸ºè§†å›¾(&V) Save the current filter, sort column and display formats as a view ä¿å­˜å½“å‰è¿‡æ»¤ï¼Œåˆ—排åºå’Œæ˜¾ç¤ºæ ¼å¼ä¸ºè§†å›¾ This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. 此按钮ä¿å­˜å½“剿µè§ˆè¡¨æ ¼çš„设置 (过滤,显示格å¼å’Œåˆ—的顺åº) 为SQL视图,之åŽå¯ä»¥å†ç”¨SQLè¯­å¥æµè§ˆã€‚ Save Table As... 表å¦å­˜ä¸º... Save the table as currently displayed æŒ‰å½“å‰æ˜¾ç¤ºçš„æ ·å­ä¿å­˜è¡¨ <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>æ­¤èœå•æä¾›ä»¥ä¸‹å¯åº”ç”¨åˆ°å½“å‰æµè§ˆã€è¿‡æ»¤çš„表的选项:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">导出到CSV: å¯¼å‡ºå½“å‰æµè§ˆã€è¿‡æ»¤çš„è¡¨çš„æ•°æ® (过滤åŽï¼Œæ˜¾ç¤ºæ ¼å¼å’Œåˆ—的顺åº) 到一个CSV文件。</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ä¿å­˜ä¸ºè§†å›¾: 此选项ä¿å­˜å½“剿µè§ˆè¡¨æ ¼çš„设置 (过滤,显示格å¼å’Œåˆ—的顺åº) 为SQL视图,之åŽå¯ä»¥å†ç”¨SQLè¯­å¥æµè§ˆã€‚</li></ul></body></html> Hide column(s) éšè—列 Hide selected column(s) éšè—选中的列 Show all columns 显示所有列 Show all columns that were hidden 显示所有被éšè—的列 Set encoding è®¾ç½®ç¼–ç  Change the encoding of the text in the table cells 更改表å•å…ƒæ ¼ä¸­æ–‡æœ¬çš„ç¼–ç  Set encoding for all tables è®¾ç½®æ‰€æœ‰è¡¨çš„ç¼–ç  Change the default encoding assumed for all tables in the database 修改数æ®åº“ä¸­æ‰€æœ‰è¡¨çš„é»˜è®¤ç¼–ç  Clear Filters 清除过滤 Clear all filters 清除所有过滤 This button clears all the filters set in the header input fields for the currently browsed table. æ­¤æŒ‰é’®å°†æ¸…é™¤å½“å‰æµè§ˆè¡¨çš„æ‰€æœ‰åœ¨å¤´éƒ¨è¾“入区的过滤器。 Clear Sorting æ¸…é™¤æŽ’åº Reset the order of rows to the default 将行的顺åºé‡ç½®ä¸ºé»˜è®¤ This button clears the sorting columns specified for the currently browsed table and returns to the default order. æ­¤æŒ‰é’®æ¸…é™¤å½“å‰æµè§ˆçš„表的列排åºï¼Œé‡ç½®ä¸ºé»˜è®¤å€¼ã€‚ Print æ‰“å° Print currently browsed table data 打å°å½“剿µè§ˆè¡¨ä¸­çš„æ•°æ® Print currently browsed table data. Print selection if more than one cell is selected. 打å°å½“剿­£åœ¨æµè§ˆçš„表中的数æ®ã€‚如果选中了多于一个的å•元格,就打å°é€‰ä¸­åŒºåŸŸã€‚ Ctrl+P Refresh 刷新 Refresh the data in the selected table åˆ·æ–°é€‰ä¸­è¡¨ä¸­çš„æ•°æ® This button refreshes the data in the currently selected table. 这个按钮刷新在当å‰é€‰æ‹©çš„表中的数æ®ã€‚ F5 Find in cells ç¼©å‡æ–‡æœ¬æ ‡ç­¾é•¿åº¦ å•元格查找 Open the find tool bar which allows you to search for values in the table view below. 打开查找工具æ ï¼Œä½ å¯ä»¥ç”¨å®ƒæœç´¢å½“å‰è¡¨ä¸­çš„æ•°æ®ã€‚ Freeze columns 冻结列 Make all columns from the first column up to this column not move when scrolling horizontally æ°´å¹³æ»šåŠ¨æ—¶ï¼Œç¬¬ä¸€åˆ—è‡³æ­¤åˆ—çš„æ‰€æœ‰åˆ—ä¿æŒä¸åЍ Bold 粗体 Ctrl+B Italic 斜体 Underline 下划线 Ctrl+U Align Right å³å¯¹é½ Align Left å·¦å¯¹é½ Center Horizontally 垂直居中 Justify ä¸¤ç«¯å¯¹é½ Edit Conditional Formats... 编辑æ¡ä»¶æ ¼å¼... Edit conditional formats for the current column 为当å‰åˆ—设置æ¡ä»¶æ ¼å¼ Clear Format æ¸…é™¤æ ¼å¼ Clear All Formats æ¸…é™¤å…¨éƒ¨æ ¼å¼ Clear all cell formatting from selected cells and all conditional formats from selected columns 清除当å‰é€‰æ‹©çš„å•元格的格å¼å’Œå½“å‰é€‰æ‹©çš„列的æ¡ä»¶æ ¼å¼ Font Color 字体颜色 Background Color 背景颜色 Toggle Format Toolbar ç¼©å‡æ–‡æœ¬æ ‡ç­¾é•¿åº¦ï¼Œä¸å¤±è¯­ä¹‰ æ ¼å¼å·¥å…·æ  Show/hide format toolbar 显示或éšè—æ ¼å¼å·¥å…·æ  This button shows or hides the formatting toolbar of the Data Browser 此按钮显示或éšè—æµè§ˆæ•°æ®çª—å£çš„æ ¼å¼å·¥å…·æ  Select column 选择列 Ctrl+Space Replace text in cells 在å•å…ƒæ ¼ä¸­æ›¿æ¢ Filter in any column 过滤任何列 Ctrl+R %n row(s) %n 行 , %n column(s) , %n 列 . Sum: %1; Average: %2; Min: %3; Max: %4 . 求和: %1; å¹³å‡å€¼: %2; 最å°å€¼: %3; 最大值: %4 . Sum: %1; Average: %2; Min: %3; Max: %4 Conditional formats for "%1" "%1" çš„æ¡ä»¶æ ¼å¼ determining row count... 正在决定行数... %L1 - %L2 of >= %L3 %L1 - %L2 / 至少 %L3 %L1 - %L2 of %L3 %L1 - %L2 / %L3 (clipped at %L1 rows) (%L1 行的一部分) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. 请输入一个伪主键以在当å‰è§†å›¾å¯ç”¨ç¼–è¾‘ã€‚è¿™éœ€è¦æ˜¯è§†å›¾ä¸­çš„一个满足唯一性的列的å字。 Delete Records 删除记录 Duplicate records é‡å¤è®°å½• Duplicate record é‡å¤çš„记录 Ctrl+" Adjust rows to contents 按内容调整行高 Error deleting record: %1 删除记录时出错: %1 Please select a record first 请首先选择一æ¡è®°å½• Please choose a new encoding for all tables. 请为所有表选择新的编ç ã€‚ Please choose a new encoding for this table. 请为此表选择新的编ç ã€‚ %1 Leave the field empty for using the database encoding. %1 留空此字段以使用数æ®åº“默认编ç ã€‚ This encoding is either not valid or not supported. è¿™ç§ç¼–ç éžæ³•æˆ–è€…ä¸æ”¯æŒã€‚ %1 replacement(s) made. 进行了 %1 次替æ¢ã€‚ TableBrowserDock New Data Browser æ–°å»ºæ•°æ®æµè§ˆå™¨ Rename Data Browser æ›´åæ•°æ®æµè§ˆå™¨ Close Data Browser å…³é—­æ•°æ®æµè§ˆå™¨ Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. è®¾å®šæ•°æ®æµè§ˆå™¨çš„æ–°å称。被“&&â€æ ‡è®°çš„字符å¯ä½œä¸ºé”®ç›˜å¿«æ·é”®çš„字符。 VacuumDialog Compact Database 压缩数æ®åº“ Warning: Compacting the database will commit all of your changes. 警告: 压缩数æ®åº“会æäº¤ä½ çš„æ‰€æœ‰ä¿®æ”¹ã€‚ Please select the databases to co&mpact: 请选择è¦åŽ‹ç¼©çš„æ•°æ®åº“(&M): sqlitebrowser-sqlitebrowser-5733cb7/src/translations/sqlb_zh_TW.ts000066400000000000000000013367101463772530400256430ustar00rootroot00000000000000 AboutDialog About DB Browser for SQLite 關於 DB Browser for SQLite Version 版本 <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="https://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a> for details.</p><p>For more information on this program please visit our website at: <a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">http://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="https://doc.qt.io/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:8pt;">We use the nalgeon/sqlean library for SQLite extensions support.<br/>This library is licensed under the MIT license, see the following for more information:<br/></span><a href="https://github.com/nalgeon/sqlean"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">https://github.com/nalgeon/sqlean</span></a></p><p><span style=" font-size:small;">It also uses the Pastel SVG icon set by Michael Buckley under a Creative Commons Attribution Share Alike 4.0 license.<br/>See </span><a href="https://codefisher.org/pastel-svg/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">https://codefisher.org/pastel-svg/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> AddRecordDialog Add New Record 新增記錄 Enter values for the new record considering constraints. Fields in bold are mandatory. 輸入新記錄的值,並考慮到æ¢ä»¶ã€‚ç²—é«”çš„æ¬„ä½æ˜¯å¿…填的。 In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. åœ¨ã€Œå€¼ã€æ¬„ä½ä¸­ï¼Œæ‚¨å¯ä»¥ç‚ºã€Œåç¨±ã€æ¬„ä½ä¸­æŒ‡å®šçš„æ¬„使Œ‡å®šå€¼ã€‚ã€Œé¡žåž‹ã€æ¬„ä½è¡¨ç¤ºæ¬„ä½çš„類型。é è¨­å€¼ä»¥èˆ‡ NULL 值相åŒçš„æ¨£å¼é¡¯ç¤ºã€‚ Name å稱 Type 類型 Value 值 Values to insert. Pre-filled default values are inserted automatically unless they are changed. è¦æ’入的值。é å¡«çš„é è¨­å€¼æœƒè‡ªå‹•æ’入,除éžå®ƒå€‘被更改。 When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. 當您在上方框架中編輯值時,用於æ’入此新記錄的 SQL 查詢將在此處顯示。您å¯ä»¥åœ¨å„²å­˜ä¹‹å‰æ‰‹å‹•編輯查詢。 <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">儲存</span> 將會æäº¤é¡¯ç¤ºçš„ SQL 陳述å¼åˆ°è³‡æ–™åº«ä»¥æ’入新記錄。</p><p><span style=" font-weight:600;">還原é è¨­å€¼</span> 將會在 <span style=" font-weight:600;">值</span>欄ä½ä¸­é‚„原åˆå§‹å€¼ã€‚</p><p><span style=" font-weight:600;">å–æ¶ˆ</span> 將會關閉此å°è©±æ¡†ï¼Œä¸¦ä¸åŸ·è¡ŒæŸ¥è©¢ã€‚</p></body></html> Auto-increment 自動éžå¢ž Unique constraint 唯一æ¢ä»¶ Check constraint: %1 檢查æ¢ä»¶ï¼š %1 Foreign key: %1 外éµï¼š %1 Default value: %1 é è¨­å€¼ï¼š %1 Error adding record. Message from database engine: %1 新增記錄時出錯。來自資料庫引擎的訊æ¯ï¼š %1 Are you sure you want to restore all the entered values to their defaults? 您確定è¦å°‡æ‰€æœ‰è¼¸å…¥çš„值還原為é è¨­å€¼å—Žï¼Ÿ Application Possible command line arguments: å¯ç”¨çš„å‘½ä»¤åˆ—åƒæ•¸ï¼š The user settings file location is replaced with the argument value instead of the environment variable value. 使用者設定檔的ä½ç½®å·²è¢«åƒæ•¸å€¼å–代,而éžç’°å¢ƒè®Šæ•¸çš„值。 Ignored environment variable (DB4S_SETTINGS_FILE) value: 忽略環境變數 (DB4S_SETTINGS_FILE) 的值: The file %1 does not exist 檔案 %1 ä¸å­˜åœ¨ Usage ä½¿ç”¨æ–¹å¼ options é¸é … database 資料庫 project 專案 csv-file CSV 檔案 Show command line options 顯示命令列é¸é … Exit application after running scripts åŸ·è¡ŒæŒ‡ä»¤ç¢¼å¾Œé€€å‡ºæ‡‰ç”¨ç¨‹å¼ file 檔案 Execute this SQL file after opening the DB 開啟資料庫後執行此 SQL 檔案 Import this CSV file into the passed DB or into a new DB 將此 CSV 檔案匯入到指定的資料庫或新資料庫 table 資料表 Browse this table, or use it as target of a data import ç€è¦½æ­¤è³‡æ–™è¡¨ï¼Œæˆ–將其作為資料匯入的目標 Open database in read-only mode 以唯讀模å¼é–‹å•Ÿè³‡æ–™åº« settings_file 設定檔 Run application based on this settings file æ ¹æ“šæ­¤è¨­å®šæª”åŸ·è¡Œæ‡‰ç”¨ç¨‹å¼ group 群組 settings 設定 value 值 Run application with this setting temporarily set to value æš«æ™‚å°‡æ­¤è¨­å®šè¨­ç‚ºç‰¹å®šå€¼ä¸¦åŸ·è¡Œæ‡‰ç”¨ç¨‹å¼ Run application saving this value for this setting å„²å­˜æ­¤è¨­å®šå€¼ä¸¦åŸ·è¡Œæ‡‰ç”¨ç¨‹å¼ Display the current version 顯示目å‰ç‰ˆæœ¬ Open this SQLite database 開啟此 SQLite 資料庫 Open this project file (*.sqbpro) 開啟此專案檔案(*.sqbpro) Import this CSV file into an in-memory database 將此 CSV 檔案匯入到記憶體內部資料庫 The %1 option requires an argument %1 é¸é …需è¦ä¸€å€‹åƒæ•¸ The -S/--settings option requires an argument. The option is ignored. -S/--settings é¸é …需è¦ä¸€å€‹åƒæ•¸ã€‚æ­¤é¸é …已被忽略。 The -o/--option and -O/--save-option options require an argument in the form group/setting=value -o/--option å’Œ -O/--save-option é¸é …需è¦ä¸€å€‹ä»¥ group/setting=value å½¢å¼çš„åƒæ•¸ Invalid option/non-existent file: %1 無效é¸é …或ä¸å­˜åœ¨çš„æª”案:%1 SQLite Version SQLite 版本 SQLCipher Version %1 (based on SQLite %2) SQLCipher 版本 %1(基於 SQLite %2) DB Browser for SQLite Version %1. DB Browser for SQLite 版本 %1。 Last commit hash when built: %1 建置時最後æäº¤çš„雜湊:%1 Built for %1, running on %2 為 %1 建置,執行於 %2 Qt Version %1 Qt 版本 %1 CipherDialog SQLCipher encryption SQLCipher 加密 &Password &密碼 &Reenter password &釿–°è¼¸å…¥å¯†ç¢¼ Encr&yption settings 加密設定 SQLCipher &3 defaults SQLCipher &3 é è¨­ SQLCipher &4 defaults SQLCipher &4 é è¨­ Custo&m 自訂 Page si&ze é é¢å¤§å° &KDF iterations &KDF 迭代 HMAC algorithm HMAC 演算法 KDF algorithm KDF 演算法 Plaintext Header Size ç´”æ–‡å­—æ¨™é ­å¤§å° Passphrase 密碼 Raw key 原始金鑰 Please set a key to encrypt the database. Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. Leave the password fields empty to disable the encryption. The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. 請設定一個金鑰來加密資料庫。 請注æ„,如果您更改了任何其他的é¸é …è¨­å®šï¼Œæ¯æ¬¡é–‹å•Ÿè³‡æ–™åº«æª”案時,您都需è¦é‡æ–°è¼¸å…¥å®ƒå€‘。 將密碼欄ä½ç•™ç©ºä»¥åœç”¨åŠ å¯†ã€‚ 加密éŽç¨‹å¯èƒ½éœ€è¦ä¸€äº›æ™‚é–“ï¼Œæ‚¨æ‡‰è©²è¦æœ‰è³‡æ–™åº«çš„備份ï¼åœ¨ä¿®æ”¹åР坆之å‰ï¼Œæœªå„²å­˜çš„變更將會被套用。 Please enter the key used to encrypt the database. If any of the other settings were altered for this database file you need to provide this information as well. 請輸入用於加密資料庫的金鑰。 å¦‚æžœæ­¤è³‡æ–™åº«æª”æ¡ˆçš„ä»»ä½•å…¶ä»–è¨­å®šå·²è¢«æ›´æ”¹ï¼Œæ‚¨ä¹Ÿéœ€è¦æä¾›é€™äº›è³‡è¨Šã€‚ ColumnDisplayFormatDialog Choose display format 鏿“‡é¡¯ç¤ºæ ¼å¼ Display format é¡¯ç¤ºæ ¼å¼ Choose a display format for the column '%1' which is applied to each value prior to showing it. 鏿“‡æ¬„ä½ '%1' 的顯示格å¼ï¼Œè©²æ ¼å¼å°‡åœ¨é¡¯ç¤ºæ¯å€‹å€¼ä¹‹å‰å¥—用。 Default é è¨­ Decimal number å進使•¸å­— Exponent notation 指數表示法 Hex blob å六進ä½åˆ¶ BLOB Hex number å六進使•¸å­— Apple NSDate to date Apple NSDate 轉æ›ç‚ºæ—¥æœŸ Java epoch (milliseconds) to date Java epoch (毫秒)轉æ›ç‚ºæ—¥æœŸ .NET DateTime.Ticks to date .NET DateTime.Ticks 轉æ›ç‚ºæ—¥æœŸ Julian day to date 儒略日轉æ›ç‚ºæ—¥æœŸ Unix epoch to local time Unix epoch 轉æ›ç‚ºæœ¬åœ°æ™‚é–“ WebKit / Chromium epoch to date WebKit / Chromium epoch to local time Date as dd/mm/yyyy 日期格å¼ç‚º dd/mm/yyyy Lower case å°å¯« Binary GUID to text 二進ä½åˆ¶ GUID 轉æ›ç‚ºæ–‡å­— SpatiaLite Geometry to SVG SpatiaLite 幾何資料轉 SVG Custom display format must contain a function call applied to %1 自訂顯示格å¼å¿…須包å«å¥—用於 %1 的函å¼å‘¼å« Error in custom display format. Message from database engine: %1 自訂顯示格å¼éŒ¯èª¤ã€‚來自資料庫引擎的訊æ¯ï¼š %1 Custom display format must return only one column but it returned %1. 自訂顯示格å¼åªèƒ½å›žå‚³ä¸€å€‹æ¬„ä½ï¼Œä½†å®ƒå›žå‚³äº† %1。 Octal number 八進使•¸å­— Round number å››æ¨äº”入數字 Unix epoch to date Unix epoch 轉æ›ç‚ºæ—¥æœŸ Upper case 大寫 Windows DATE to date Windows DATE 轉æ›ç‚ºæ—¥æœŸ Custom 自訂 CondFormatManager Conditional Format Manager æ¢ä»¶æ ¼å¼ç®¡ç†å™¨ This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. æ­¤å°è©±æ¡†å…許建立和編輯æ¢ä»¶æ ¼å¼ã€‚æ¯å€‹å„²å­˜æ ¼æ¨£å¼å°‡ç”±è©²å„²å­˜æ ¼è³‡æ–™çš„第一個符åˆçš„æ¢ä»¶é¸å®šã€‚æ¢ä»¶æ ¼å¼å¯ä»¥ä¸Šä¸‹ç§»å‹•,其中較高行的優先權高於較低行的。æ¢ä»¶çš„語法與篩é¸å™¨çš„語法相åŒï¼Œç©ºæ¢ä»¶é©ç”¨æ–¼ä¸¦ä¸”空的æ¢ä»¶é©ç”¨æ–¼æ‰€æœ‰å€¼æ‰€æœ‰å€¼ã€‚ Add new conditional format 新增æ¢ä»¶æ ¼å¼ &Add &新增 Remove selected conditional format 移除é¸å®šçš„æ¢ä»¶æ ¼å¼ &Remove &移除 Move selected conditional format up 上移é¸å®šçš„æ¢ä»¶æ ¼å¼ Move &up å‘上移動 Move selected conditional format down 下移é¸å®šçš„æ¢ä»¶æ ¼å¼ Move &down å‘下移動 Foreground 剿™¯ Text color 文字é¡è‰² Background 背景 Background color 背景é¡è‰² Font å­—åž‹ Size å¤§å° Bold ç²—é«” Italic 斜體 Underline 底線 Alignment å°é½Š Condition æ¢ä»¶ Click to select color 點é¸ä»¥é¸æ“‡é¡è‰² Are you sure you want to clear all the conditional formats of this field? æ‚¨ç¢ºå®šè¦æ¸…除此欄ä½çš„æ‰€æœ‰æ¢ä»¶æ ¼å¼å—Žï¼Ÿ DBBrowserDB Please specify the database name under which you want to access the attached database 請指定您è¦å­˜å–附加資料庫的資料庫å稱 Invalid file format ç„¡æ•ˆçš„æª”æ¡ˆæ ¼å¼ Do you want to save the changes made to the database file %1? æ‚¨æ˜¯å¦æƒ³å„²å­˜å°è³‡æ–™åº«æª”案 %1 åšå‡ºçš„修改? Exporting database to SQL file... 正在匯出資料庫到 SQL 檔案... Cancel å–æ¶ˆ Executing SQL... 正在執行 SQL... Action cancelled. æ“ä½œå·²å–æ¶ˆã€‚ Do you really want to close this temporary database? All data will be lost. 您確定è¦é—œé–‰æ­¤è‡¨æ™‚資料庫嗎?所有資料將會éºå¤±ã€‚ Database didn't close correctly, probably still busy 資料庫未正確關閉,å¯èƒ½ä»åœ¨å¿™ç¢Œä¸­ Cannot open destination file: '%1' 無法開啟目標檔案:'%1' Cannot backup to file: '%1'. Message: %2 無法備份到檔案:'%1'。訊æ¯ï¼š%2 The database is currently busy: 資料庫目å‰å¿™ç¢Œä¸­ï¼š Do you want to abort that other operation? 您是å¦è¦ä¸­æ­¢å…¶ä»–æ“作? No database file opened 沒有開啟的資料庫檔案 Error in statement #%1: %2. Aborting execution%3. é™³è¿°å¼ #%1 中的錯誤:%2。 正在中止執行%3。 and rolling back 並正在回滾 didn't receive any output from %1 未從 %1 收到任何輸出 could not execute command: %1 無法執行命令:%1 Cannot delete this object 無法刪除此物件 Cannot set data on this object 無法在此物件上設定資料 A table with the name '%1' already exists in schema '%2'. åœ¨çµæ§‹ '%2' 中已存在å為 '%1' 的資料表。 No table with name '%1' exists in schema '%2'. åœ¨çµæ§‹ '%2' 中ä¸å­˜åœ¨å為 '%1' 的資料表。 Cannot find column %1. 找ä¸åˆ°åˆ— %1。 Creating savepoint failed. DB says: %1 建立儲存點失敗。資料庫顯示:%1 Renaming the column failed. DB says: %1 釿–°å‘½å欄ä½å¤±æ•—。資料庫顯示: %1 Releasing savepoint failed. DB says: %1 釋放儲存點失敗。資料庫顯示:%1 Creating new table failed. DB says: %1 建立新資料表失敗。資料庫顯示:%1 Copying data to new table failed. DB says: %1 複製資料到新資料表失敗。資料庫顯示: %1 Deleting old table failed. DB says: %1 刪除舊資料表失敗。資料庫顯示:%1 Error renaming table '%1' to '%2'. Message from database engine: %3 將資料表 '%1' 釿–°å‘½å為 '%2' 時出ç¾éŒ¯èª¤ã€‚ 來自資料庫引擎的訊æ¯ï¼š %3 could not get list of db objects: %1 無法å–得資料庫物件的列表:%1 Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: 還原æŸäº›å’Œé€™å€‹è³‡æ–™è¡¨é—œè¯çš„物件失敗。這個最å¯èƒ½æ˜¯å› ç‚ºæŸäº›åˆ—çš„å稱修改了。這裡是您å¯èƒ½éœ€è¦æ‰‹å‹•修復和執行的 SQL 陳述å¼: could not get list of databases: %1 無法å–得資料庫的列表:%1 Error loading extension: %1 載入擴充套件時出ç¾éŒ¯èª¤: %1 Error loading built-in extension: %1 could not get column information 無法å–得列資訊 Error setting pragma %1 to %2: %3 設定 pragma %1 為 %2 時出ç¾éŒ¯èª¤: %3 File not found. 找ä¸åˆ°æª”案。 DbStructureModel Name å稱 Object 物件 Type 類型 Schema çµæ§‹ Database 資料庫 Browsables å¯ç€è¦½çš„ All 全部 Temporary 臨時的 Tables (%1) 資料表 (%1) Indices (%1) 索引 (%1) Views (%1) 檢視表 (%1) Triggers (%1) 觸發器 (%1) EditDialog Edit database cell 編輯資料庫儲存格 Mode: 模å¼ï¼š This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. 這是儲存格編輯器支æ´çš„æ¨¡å¼åˆ—è¡¨ã€‚é¸æ“‡ä¸€ç¨®æ¨¡å¼ä¾†æª¢è¦–或編輯目å‰å„²å­˜æ ¼çš„資料。 RTL Text 從å³åˆ°å·¦çš„æ–‡å­— Image 圖片 JSON JSON XML XML Evaluation è©•ä¼° Automatically adjust the editor mode to the loaded data type 自動調整編輯器模å¼ä»¥é©æ‡‰è¼‰å…¥çš„資料類型 This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. 這個å¯é¸æ“‡çš„æŒ‰éˆ•å¯ä»¥å•Ÿç”¨æˆ–åœç”¨ç·¨è¼¯å™¨æ¨¡å¼çš„自動切æ›ã€‚ç•¶é¸æ“‡æ–°çš„å„²å­˜æ ¼æˆ–åŒ¯å…¥æ–°çš„è³‡æ–™ä¸¦å•Ÿç”¨è‡ªå‹•åˆ‡æ›æ™‚,模å¼å°‡èª¿æ•´ç‚ºæª¢æ¸¬åˆ°çš„資料類型。您å¯ä»¥æ‰‹å‹•更改編輯器模å¼ã€‚å¦‚æžœæ‚¨å¸Œæœ›åœ¨ç§»å‹•å„²å­˜æ ¼æ™‚ä¿æŒé€™ç¨®æ‰‹å‹•切æ›çš„æ¨¡å¼ï¼Œè«‹åˆ‡æ›æŒ‰éˆ•至關閉狀態。 Auto-switch è‡ªå‹•åˆ‡æ› This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. 這個 Qt 編輯器用於從å³åˆ°å·¦çš„腳本,這些腳本ä¸è¢«é è¨­çš„æ–‡å­—編輯器支æ´ã€‚檢測到從å³åˆ°å·¦çš„å­—å…ƒæ™‚ï¼Œå°‡è‡ªå‹•é¸æ“‡æ­¤ç·¨è¼¯å™¨æ¨¡å¼ã€‚ Identification of the cell currently in the editor ç›®å‰åœ¨ç·¨è¼¯å™¨ä¸­çš„儲存格識別資訊 Type and size of data currently in table ç›®å‰è¡¨æ ¼ä¸­çš„è³‡æ–™é¡žåž‹å’Œå¤§å° Open preview dialog for printing the data currently stored in the cell 開啟é è¦½å°è©±æ¡†ä»¥åˆ—å°ç›®å‰å„²å­˜åœ¨å„²å­˜æ ¼ä¸­çš„資料 Auto-format: pretty print on loading, compact on saving. 自動格å¼åŒ–:載入時進行美觀列å°ï¼Œå„²å­˜æ™‚進行壓縮。 When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. 當啟用時,自動格å¼åŒ–功能會在載入時格å¼åŒ–資料,將文字分æˆè¡Œä¸¦ç¸®æŽ’以ç²å¾—最大的å¯è®€æ€§ã€‚在儲存資料時,自動格å¼åŒ–功能會壓縮資料,移除行尾和ä¸å¿…è¦çš„空白。 Word Wrap 自動æ›è¡Œ Wrap lines on word boundaries 在單詞邊界æ›è¡Œ Open in default application or browser 在é è¨­æ‡‰ç”¨ç¨‹å¼æˆ–ç€è¦½å™¨ä¸­é–‹å•Ÿ Open in application 在應用程å¼ä¸­é–‹å•Ÿ The value is interpreted as a file or URL and opened in the default application or web browser. 該值被解釋為檔案或 URL 並在é è¨­æ‡‰ç”¨ç¨‹å¼æˆ–ç¶²é ç€è¦½å™¨ä¸­é–‹å•Ÿã€‚ Save file reference... 儲存檔案åƒè€ƒ... Save reference to file 儲存到檔案的åƒè€ƒ Open in external application 在外部應用程å¼ä¸­é–‹å•Ÿ Autoformat 自動格å¼åŒ– &Export... &匯出... &Import... &匯入... Import from file 從檔案匯入 Opens a file dialog used to import any kind of data to this database cell. 開啟一個檔案å°è©±æ¡†ï¼Œç”¨æ–¼å°‡ä»»ä½•類型的資料匯入到這個資料庫儲存格。 Export to file 匯出到檔案 Opens a file dialog used to export the contents of this database cell to a file. 開啟一個檔案å°è©±æ¡†ï¼Œç”¨æ–¼å°‡é€™å€‹è³‡æ–™åº«å„²å­˜æ ¼çš„內容匯出到一個檔案。 Print... 列å°... Ctrl+P Ctrl+P Open preview dialog for printing displayed text 開啟é è¦½å°è©±æ¡†ä»¥åˆ—å°é¡¯ç¤ºçš„æ–‡å­— Copy Hex and ASCII 複製å六進ä½å’Œ ASCII Copy selected hexadecimal and ASCII columns to the clipboard 將鏿“‡çš„å六進ä½å’Œ ASCII 列複製到剪貼簿 Ctrl+Shift+C Ctrl+Shift+C Set as &NULL 設為 &NULL Apply data to cell 將資料套用到儲存格 This button saves the changes performed in the cell editor to the database cell. 此按鈕將在儲存格編輯器中進行的更改儲存到資料庫儲存格。 Apply 套用 Text 純文字檔案 Binary äºŒé€²ä½ Erases the contents of the cell 刪除儲存格的內容 This area displays information about the data present in this database cell 這個å€åŸŸé¡¯ç¤ºå­˜åœ¨æ–¼é€™å€‹è³‡æ–™åº«å„²å­˜æ ¼ä¸­çš„資料的相關資訊 Choose a filename to export data 鏿“‡ä¸€å€‹åŒ¯å‡ºè³‡æ–™çš„æª”案å稱 Image data can't be viewed in this mode. 此模å¼ä¸‹ç„¡æ³•檢視圖片資料。 Try switching to Image or Binary mode. 嘗試切æ›åˆ°åœ–ç‰‡æˆ–äºŒé€²ä½æ¨¡å¼ã€‚ Binary data can't be viewed in this mode. 此模å¼ä¸‹ç„¡æ³•檢視二進ä½è³‡æ–™ã€‚ Try switching to Binary mode. 嘗試切æ›åˆ°äºŒé€²ä½æ¨¡å¼ã€‚ Image files (%1) 圖片檔案 (%1) Binary files (*.bin) äºŒé€²ä½æª”案 (*.bin) Type: NULL; Size: 0 bytes 類型:NULL;大å°ï¼š0 ä½å…ƒçµ„ Type: Text / Numeric; Size: %n character(s) 類型:文字 / 數值;大å°ï¼š%n å­—å…ƒ Type: %1 Image; Size: %2x%3 pixel(s) 類型:%1 圖片;大å°ï¼š%2x%3 åƒç´  Type: Valid JSON; Size: %n character(s) 類型:有效的 JSON;大å°ï¼š%n å­—å…ƒ Type: Binary; Size: %n byte(s) 類型:二進ä½ï¼›å¤§å°ï¼š%n ä½å…ƒçµ„ Couldn't save file: %1. 無法儲存檔案:%1。 The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell or cancel any changes. 資料已被儲存到臨時檔案並已用é è¨­æ‡‰ç”¨ç¨‹å¼é–‹å•Ÿã€‚您ç¾åœ¨å¯ä»¥ç·¨è¼¯æª”æ¡ˆï¼Œæº–å‚™å¥½å¾Œï¼Œå°‡å„²å­˜çš„æ–°è³‡æ–™å¥—ç”¨åˆ°å„²å­˜æ ¼æˆ–å–æ¶ˆä»»ä½•更改。 Choose a file to import 鏿“‡ä¸€å€‹è¦åŒ¯å…¥çš„æª”案 The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. Errors are indicated with a red squiggle underline. In the Evaluation mode, entered SQLite expressions are evaluated and the result applied to the cell. 文字編輯器模å¼è®“您å¯ä»¥ç·¨è¼¯ç´”文字,以åŠå…·æœ‰èªžæ³•高亮ã€è‡ªå‹•æ ¼å¼åŒ–和儲存å‰é©—證的 JSON 或 XML 資料。 在評估模å¼ä¸­ï¼Œè¼¸å…¥çš„ SQLite 表é”弿œƒè¢«è©•ä¼°ï¼Œä¸¦å°‡çµæžœå¥—用至該儲存格。 Unsaved data in the cell editor 儲存格編輯器中有未儲存的資料 The cell editor contains data not yet applied to the database. Do you want to apply the edited data to row=%1, column=%2? 儲存格編輯器內å«å°šæœªå¥—用至資料庫的資料。 æ‚¨æ˜¯å¦æƒ³å°‡ç·¨è¼¯éŽçš„資料套用到第 %1 行,第 %2 列? Editing row=%1, column=%2 正在編輯第 %1 行,第 %2 列 No cell active. 沒有活動的儲存格。 %1 Image %1 圖片 Invalid data for this mode 此模å¼çš„資料無效 The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? 儲存格包å«ç„¡æ•ˆçš„ %1 資料。原因:%2。您確實è¦å°‡å…¶å¥—用到儲存格嗎? EditIndexDialog &Name å稱(&N) Order é †åº &Table 資料表(&T) Edit Index Schema ç·¨è¼¯ç´¢å¼•çµæ§‹ &Unique 唯一(&U) For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed è‹¥è¦å°‡ç´¢å¼•é™åˆ¶ç‚ºè³‡æ–™è¡¨çš„一部分,您å¯ä»¥åœ¨æ­¤æŒ‡å®š WHERE å­å¥ï¼Œé¸æ“‡æ‡‰è©²è¢«ç´¢å¼•的資料表部分 Partial inde&x clause 部分索引å­å¥(&X) Colu&mns 欄ä½(&M) Table column è³‡æ–™è¡¨æ¬„ä½ Type 類型 Add a new expression column to the index. Expression columns contain SQL expression rather than column names. å‘索引新增新的表é”弿¬„ä½ã€‚表é”弿¬„ä½åŒ…å« SQL 表é”å¼ï¼Œè€Œä¸æ˜¯æ¬„ä½å稱。 Index column ç´¢å¼•æ¬„ä½ Deleting the old index failed: %1 刪除舊索引失敗: %1 Creating the index failed: %1 建立索引失敗: %1 EditTableDialog Edit table definition 編輯資料表定義 Table 資料表 Advanced 進階 Without Rowid ç„¡ Rowid Database sche&ma è³‡æ–™åº«çµæ§‹(&M) Make this a 'WITHOUT ROWID' table. Setting this flag requires specifying a PRIMARY KEY (which can be of any type, and can be composite), and forbids the AUTOINCREMENT flag. On Conflict è¡çªæ™‚ Strict åš´æ ¼æ¨¡å¼ When the strict option is enabled SQLite enforces the data types of each column when updating or inserting data. 啟用嚴格模å¼å¾Œï¼ŒSQLite 在更新或æ’入資料時會強制執行æ¯ä¸€æ¬„ä½çš„資料型態。 Fields æ¬„ä½ Add 新增 Remove 移除 Move to top 移至頂端 Move up 上移 Move down 下移 Move to bottom 移至底端 Name å稱 Type 類型 NN NN Not null éžç©º PK PK <html><head/><body><p><img src=":/icons/field_key"/> Primary key</p></body></html> <html><head/><body><p><img src=":/icons/field_key"/> 主éµ</p></body></html> AI AI Autoincrement 自動éžå¢ž U U Unique 唯一 Default é è¨­ Default value é è¨­å€¼ Check 檢查 Check constraint 檢查æ¢ä»¶ Collation 定åºè¦å‰‡ Foreign Key å¤–éµ <html><head/><body><p><img src=":/icons/field_fk"/> Foreign Key</p></body></html> <html><head/><body><p><img src=":/icons/field_fk"/> 外éµ</p></body></html> Index Constraints 索引æ¢ä»¶ç´„æŸ Add constraint 新增æ¢ä»¶ Remove constraint 移除æ¢ä»¶ Columns æ¬„ä½ SQL SQL Foreign Keys å¤–éµ References åƒç…§ Check Constraints 檢查æ¢ä»¶ç´„æŸ <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">警告:</span>我們的解æžå™¨ç„¡æ³•完全ç†è§£æ­¤è³‡æ–™è¡¨å®šç¾©çš„æŸäº›å…§å®¹ã€‚ä¿®æ”¹ä¸¦å„²å­˜æ­¤è³‡æ–™è¡¨å¯èƒ½æœƒå°Žè‡´å•題。</p></body></html> Primary Key ä¸»éµ Add a primary key constraint æ–°å¢žä¸»éµæ¢ä»¶ Add a unique constraint 新增唯一æ¢ä»¶ Error creating table. Message from database engine: %1 建立資料表時出ç¾éŒ¯èª¤ã€‚來自資料庫引擎的訊æ¯: %1 There already is a field with that name. Please rename it first or choose a different name for this field. 已經存在具有該å稱的欄ä½ã€‚è«‹å…ˆé‡æ–°å‘½å它或為此欄ä½é¸æ“‡ä¸€å€‹ä¸åŒçš„å稱。 There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. 至少有一行將此欄ä½è¨­å®šç‚º NULL。這使得它無法設定此標記。請先修改資料表資料。 There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. 至少有一行在此欄ä½ä¸­å…·æœ‰éžæ•´æ•¸å€¼ã€‚這使得它無法設定 AI 標記。請先修改資料表資料。 Column '%1' has duplicate data. æ¬„ä½ '%1' 有é‡è¤‡çš„資料。 This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. 這使得無法啟用 '唯一' 標記。請移除é‡è¤‡çš„資料,這將å…許然後啟用 '唯一' 標記。 Please add a field which meets the following criteria before setting the on conflict action: - Primary key flag set 在設定è¡çªæ™‚的動作之å‰ï¼Œè«‹æ–°å¢žä¸€å€‹ç¬¦åˆä»¥ä¸‹æ¢ä»¶çš„æ¬„ä½ï¼š - å·²è¨­å®šä¸»éµæ¨™è¨˜ This column is referenced in a foreign key in table %1 and thus its name cannot be changed. 此欄ä½åœ¨è³‡æ–™è¡¨ %1 的外éµä¸­è¢«å¼•用,因此其å稱無法更改。 There can only be one primary key for each table. Please modify the existing primary key instead. æ¯å€‹è³‡æ–™è¡¨åªèƒ½æœ‰ä¸€å€‹ä¸»éµã€‚è«‹æ”¹ç‚ºä¿®æ”¹ç¾æœ‰çš„主éµã€‚ Are you sure you want to delete the field '%1'? All data currently stored in this field will be lost. 您確定è¦åˆªé™¤æ¬„ä½ '%1' 嗎? ç›®å‰å„²å­˜åœ¨æ­¤æ¬„ä½ä¸­çš„æ‰€æœ‰è³‡æ–™å°‡æœƒéºå¤±ã€‚ Please add a field which meets the following criteria before setting the without rowid flag: - Primary key flag set - Auto increment disabled 在設定 without rowid 標記之å‰ï¼Œè«‹æ–°å¢žæ»¿è¶³ä»¥ä¸‹æ¢ä»¶çš„æ¬„ä½ï¼š - è¨­å®šä¸»éµæ¨™è¨˜ - åœç”¨è‡ªå‹•éžå¢ž ExportDataDialog Export data as CSV 將資料匯出為 CSV Tab&le(s) 資料表(&L) Colu&mn names in first line 在第一行中的欄ä½å稱(&M) Fie&ld separator 欄ä½åˆ†éš”符號(&L) , , ; ; Tab Tab | | Other 其它 &Quote character 引號字元(&Q) " " ' ' New line characters æ›è¡Œå­—å…ƒ Windows: CR+LF (\r\n) Windows:CR+LF (\r\n) Unix: LF (\n) Unix:LF (\n) Pretty print ç¾Žè§€åˆ—å° Could not open output file: %1 無法開啟輸出檔案:%1 Choose a filename to export data 鏿“‡ä¸€å€‹åŒ¯å‡ºè³‡æ–™çš„æª”案å稱 Export data as JSON 將資料匯出為 JSON exporting CSV 正在匯出 CSV Error while writing the file '%1': %2 寫入檔案 '%1' 時發生錯誤:%2 exporting JSON 正在匯出 JSON Please select at least 1 table. è«‹è‡³å°‘é¸æ“‡ 1 個資料表。 Choose a directory 鏿“‡ä¸€å€‹ç›®éŒ„ Export completed. 匯出完æˆã€‚ Export finished with errors. 匯出完æˆï¼Œä½†éŽç¨‹ä¸­æœ‰éŒ¯èª¤ã€‚ ExportSqlDialog Export SQL... 匯出 SQL... Tab&le(s) 資料表(&L) Select All å…¨é¸ Deselect All å–æ¶ˆå…¨é¸ &Options é¸é …(&O) Keep column names in INSERT INTO 在 INSERT INTO 中ä¿ç•™æ¬„ä½å稱 Multiple rows (VALUES) per INSERT statement æ¯å€‹ INSERT 陳述å¼ä¸­åŒ…å«å¤šå€‹è³‡æ–™åˆ—(VALUES) Export everything 匯出全部 Export schema only åƒ…åŒ¯å‡ºçµæ§‹ Export data only 僅匯出資料 Keep original CREATE statements ä¿ç•™åŽŸå§‹çš„ CREATE é™³è¿°å¼ Keep old schema (CREATE TABLE IF NOT EXISTS) ä¿ç•™èˆŠçµæ§‹ï¼ˆCREATE TABLE IF NOT EXISTS) Overwrite old schema (DROP TABLE, then CREATE TABLE) è¦†è“‹èˆŠçµæ§‹ï¼ˆDROP TABLE,然後 CREATE TABLE) Please select at least one table. è«‹è‡³å°‘é¸æ“‡ä¸€å€‹è³‡æ–™è¡¨ã€‚ Choose a filename to export 鏿“‡è¦åŒ¯å‡ºçš„æª”案å稱 Export completed. 匯出完æˆã€‚ Export cancelled or failed. åŒ¯å‡ºå–æ¶ˆæˆ–失敗。 ExtendedScintilla Ctrl+H Ctrl+H Ctrl+F Ctrl+F Ctrl+P Ctrl+P Find... 尋找... Find and Replace... 尋找和å–代... Print... 列å°... ExtendedTableWidget Use as Exact Filter 作為精確篩é¸ä½¿ç”¨ Containing åŒ…å« Not containing ä¸åŒ…å« Not equal to ä¸ç­‰æ–¼ Greater than 大於 Less than å°æ–¼ Greater or equal 大於或等於 Less or equal å°æ–¼æˆ–等於 Between this and... 介於此和... Regular expression æ­£è¦è¡¨é”å¼ Edit Conditional Formats... 編輯æ¢ä»¶æ ¼å¼... Set to NULL 設定為 NULL Cut 剪下 Copy 複製 Copy with Headers é€£åŒæ¨™é ­è¤‡è£½ Copy as SQL 複製為 SQL Paste 貼上 Print... 列å°... Use in Filter Expression 在篩é¸è¡¨é”å¼ä¸­ä½¿ç”¨ Alt+Del Alt+Del Ctrl+Shift+C Ctrl+Shift+C Ctrl+Alt+C Ctrl+Alt+C The content of the clipboard is bigger than the range selected. Do you want to insert it anyway? 剪貼簿的內容大於所é¸çš„範åœã€‚ 您ä»ç„¶è¦æ’入嗎? <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. <p>並未載入所有資料。<b>您是å¦è¦åœ¨é¸æ“‡æ‰€æœ‰è¡Œä¹‹å‰è¼‰å…¥æ‰€æœ‰è³‡æ–™ï¼Ÿ</b><p><p>回答 <b>å¦</b> 表示將ä¸å†è¼‰å…¥æ›´å¤šè³‡æ–™ï¼Œä¸¦ä¸”䏿œƒé€²è¡Œé¸æ“‡ã€‚<br/>回答 <b>是</b> å¯èƒ½éœ€è¦ä¸€äº›æ™‚é–“ä¾†è¼‰å…¥è³‡æ–™ï¼Œä½†é¸æ“‡å°‡æœƒå®Œæˆã€‚</p>警告:載入所有資料å¯èƒ½éœ€è¦å¤§é‡è¨˜æ†¶é«”來處ç†å¤§åž‹è³‡æ–™è¡¨ã€‚ Cannot set selection to NULL. Column %1 has a NOT NULL constraint. ç„¡æ³•å°‡é¸æ“‡è¨­å®šç‚º NULLã€‚æ¬„ä½ %1 有一個 NOT NULL æ¢ä»¶ã€‚ FileExtensionManager File Extension Manager 檔案副檔å管ç†å™¨ &Up 上移(&U) &Down 下移(&D) &Add 新增(&A) &Remove 移除(&R) Description æè¿° Extensions 副檔å *.extension *.副檔å FilterLineEdit Filter ç¯©é¸ These input fields allow you to perform quick filters in the currently selected table. By default, the rows containing the input text are filtered out. The following operators are also supported: % Wildcard > Greater than < Less than >= Equal to or greater <= Equal to or less = Equal to: exact match <> Unequal: exact inverse match x~y Range: values between x and y /regexp/ Values matching the regular expression 這些輸入欄ä½å…許您在目å‰é¸æ“‡çš„資料表中進行快速篩é¸ã€‚ é è¨­æƒ…æ³ä¸‹ï¼ŒåŒ…å«è¼¸å…¥æ–‡å­—的行將被篩é¸å‡ºä¾†ã€‚ 也支æ´ä»¥ä¸‹é‹ç®—å­ï¼š % è¬ç”¨å­—å…ƒ > 大於 < å°æ–¼ >= 大於或等於 <= å°æ–¼æˆ–等於 = 等於:完全相符 <> ä¸ç­‰æ–¼ï¼šå®Œå…¨ä¸ç›¸ç¬¦ x~y 範åœï¼šä»‹æ–¼ x å’Œ y 之間的值 /regexp/ ç¬¦åˆæ­£è¦è¡¨é”å¼çš„值 Clear All Conditional Formats 清除所有æ¢ä»¶æ ¼å¼ Use for Conditional Format 用於æ¢ä»¶æ ¼å¼ Edit Conditional Formats... 編輯æ¢ä»¶æ ¼å¼... Set Filter Expression 設定篩é¸è¡¨é”å¼ What's This? 這是什麼? Is NULL 是 NULL Is not NULL 䏿˜¯ NULL Is empty 是空的 Is not empty 䏿˜¯ç©ºçš„ Not containing... ä¸åŒ…å«... Equal to... 等於... Not equal to... ä¸ç­‰æ–¼... Greater than... 大於... Less than... å°æ–¼... Greater or equal... 大於或等於... Less or equal... å°æ–¼æˆ–等於... In range... 在範åœå…§... Regular expression... æ­£è¦è¡¨é”å¼... FindReplaceDialog Find and Replace 尋找與å–代 Fi&nd text: 尋找文字: Re&place with: å–代為: Match &exact case 符åˆå®Œå…¨å¤§å°å¯« Match &only whole words åƒ…ç¬¦åˆæ•´å€‹å–®å­— When enabled, the search continues from the other end when it reaches one end of the page 啟用時,æœå°‹åˆ°é”é é¢ä¸€ç«¯å¾Œå°‡å¾žå¦ä¸€ç«¯ç¹¼çºŒ &Wrap around 循環æœå°‹ When set, the search goes backwards from cursor position, otherwise it goes forward 設定時,æœå°‹å°‡å¾žæ¸¸æ¨™ä½ç½®å‘後進行,å¦å‰‡å°‡å‘å‰é€²è¡Œ Search &backwards å‘後æœå°‹ <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> <html><head/><body><p>勾鏿™‚,åªåœ¨ç›®å‰é¸å–的範åœå…§æœå°‹è¦å°‹æ‰¾çš„æ¨¡å¼ã€‚</p></body></html> &Selection only 僅é¸å–ç¯„åœ <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>勾鏿™‚,將è¦å°‹æ‰¾çš„æ¨¡å¼è§£è®€ç‚º UNIX æ­£è¦è¡¨é”å¼ã€‚è«‹åƒé–± <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Wikibooks 中的正è¦è¡¨é”å¼</a>。</p></body></html> Use regular e&xpressions 使用正è¦è¡¨é”å¼ Find the next occurrence from the cursor position and in the direction set by "Search backwards" 從游標ä½ç½®ä»¥ã€Œå‘後æœå°‹ã€è¨­å®šçš„æ–¹å‘尋找下一個符åˆçš„æ–‡å­— &Find Next 尋找下一個 F3 F3 &Replace å–代 Highlight all the occurrences of the text in the page 在é é¢ä¸­çªé¡¯æ‰€æœ‰å‡ºç¾çš„æ–‡å­— F&ind All 尋找所有 Replace all the occurrences of the text in the page å–代é é¢ä¸­æ‰€æœ‰å‡ºç¾çš„æ–‡å­— Replace &All 全部å–代 The searched text was not found 找ä¸åˆ°æœå°‹çš„æ–‡å­— The searched text was not found. 找ä¸åˆ°æœå°‹çš„æ–‡å­—。 The searched text was found one time. 找到æœå°‹çš„æ–‡å­—一次。 The searched text was found %1 times. 找到æœå°‹çš„æ–‡å­— %1 次。 The searched text was replaced one time. å–代æœå°‹çš„æ–‡å­—一次。 The searched text was replaced %1 times. å–代æœå°‹çš„æ–‡å­— %1 次。 ForeignKeyEditor &Reset é‡è¨­ Foreign key clauses (ON UPDATE, ON DELETE etc.) 外éµå­å¥ï¼ˆON UPDATEã€ON DELETE 等) ImageViewer Image Viewer 圖片檢視器 Reset the scaling to match the original size of the image. é‡è¨­ç¸®æ”¾æ¯”例以符åˆåœ–片的原始大å°ã€‚ Set the scaling to match the size of the viewport. è¨­å®šç¸®æ”¾æ¯”ä¾‹ä»¥ç¬¦åˆæª¢è¦–å€çš„大å°ã€‚ Print... 列å°... Open preview dialog for printing displayed image 開啟é è¦½å°è©±æ¡†ä»¥åˆ—å°é¡¯ç¤ºçš„圖片 Ctrl+P Ctrl+P ImportCsvDialog Import CSV file 匯入 CSV 檔案 Table na&me 表格å稱 &Column names in first line 首行為欄ä½å稱(&C) Field &separator 欄ä½åˆ†éš”符號(&S) , , ; ; Tab Tab | | Other 其它 &Quote character 引號字元(&Q) Other (printable) 其他(å¯åˆ—å°ï¼‰ Other (code) 其他(代碼) " " ' ' &Encoding 編碼(&E) UTF-8 UTF-8 UTF-16 UTF-16 ISO-8859-1 ISO-8859-1 Trim fields? 是å¦ä¿®æ•´æ¬„ä½ï¼Ÿ Separate tables 分開表格 Advanced 進階 When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. 從 CSV æª”æ¡ˆåŒ¯å…¥ç©ºå€¼åˆ°å·²å­˜åœ¨çš„è¡¨æ ¼ä¸”è©²æ¬„ä½æœ‰é è¨­å€¼æ™‚,將æ’入該é è¨­å€¼ã€‚啟用此é¸é …以æ’入空值。 Ignore default &values 忽略é è¨­å€¼(&V) Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. 啟用此é¸é …以在嘗試匯入空值到沒有é è¨­å€¼çš„ NOT NULL æ¬„ä½æ™‚åœæ­¢åŒ¯å…¥ã€‚ Fail on missing values é‡ç¼ºå¤±å€¼å‰‡å¤±æ•— Disable data type detection åœç”¨è³‡æ–™åž‹æ…‹åµæ¸¬ Disable the automatic data type detection when creating a new table. 建立新表格時,åœç”¨è‡ªå‹•è³‡æ–™åž‹æ…‹åµæ¸¬ã€‚ Use local number conventions ä½¿ç”¨æœ¬åœ°æ•¸å­—æ ¼å¼ Use decimal and thousands separators according to the system locale. 根據系統å€åŸŸè¨­å®šä½¿ç”¨å°æ•¸é»žå’Œåƒä½åˆ†éš”符號。 When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. 當匯入到具有主éµã€å”¯ä¸€æ¢ä»¶æˆ–å”¯ä¸€ç´¢å¼•çš„ç¾æœ‰è¡¨æ ¼æ™‚,å¯èƒ½æœƒç™¼ç”Ÿè¡çªã€‚æ­¤é¸é …å…è¨±æ‚¨é¸æ“‡è©²æƒ…æ³çš„策略:é è¨­æƒ…æ³ä¸‹ï¼ŒåŒ¯å…¥å°‡è¢«ä¸­æ­¢ä¸¦å›žæ»¾ï¼Œä½†æ‚¨ä¹Ÿå¯ä»¥é¸æ“‡å¿½ç•¥ä¸¦ä¸åŒ¯å…¥è¡çªçš„資料列,或å–ä»£è¡¨æ ¼ä¸­çš„ç¾æœ‰è³‡æ–™åˆ—。 Abort import 終止匯入 Ignore row 忽略資料列 Replace existing row å–ä»£ç¾æœ‰è³‡æ–™åˆ— Conflict strategy è¡çªç­–ç•¥ Deselect All å…¨éƒ¨å–æ¶ˆé¸å– Match Similar 符åˆç›¸ä¼¼ Select All 全部é¸å– There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. 已存在å為 '%1' çš„è¡¨æ ¼ï¼Œåªæœ‰åœ¨æ¬„使•¸é‡ç¬¦åˆçš„æƒ…æ³ä¸‹æ‰èƒ½åŒ¯å…¥åˆ°ç¾æœ‰è¡¨æ ¼ã€‚ There is already a table named '%1'. Do you want to import the data into it? 已存在å為 '%1' 的表格。您è¦å°‡è³‡æ–™åŒ¯å…¥å…¶ä¸­å—Žï¼Ÿ Creating restore point failed: %1 建立還原點失敗:%1 Creating the table failed: %1 建立表格失敗:%1 importing CSV 正在匯入 CSV Could not prepare INSERT statement: %1 無法準備 INSERT 陳述å¼ï¼š%1 Unexpected end of file. Please make sure that you have configured the correct quote characters and the file is not malformed. 檔案æ„å¤–çµæŸã€‚è«‹ç¢ºä¿æ‚¨å·²è¨­å®šæ­£ç¢ºçš„å¼•è™Ÿå­—å…ƒï¼Œä¸¦ä¸”æª”æ¡ˆæ ¼å¼æ­£ç¢ºã€‚ Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. 匯入檔案 '%1' 花費了 %2ms。其中 %3ms 花在行函å¼ä¸Šã€‚ Inserting row failed: %1 æ’入資料列失敗%1 MainWindow toolBar1 工具列1 Opens the SQLCipher FAQ in a browser window 在ç€è¦½å™¨è¦–窗中開啟 SQLCipher 常見å•題 Export one or more table(s) to a JSON file 匯出一個或多個資料表到 JSON 檔案 DB Browser for SQLite DB Browser for SQLite Open an existing database file in read only mode 以唯讀模å¼é–‹å•Ÿç¾æœ‰çš„資料庫檔案 &File 檔案(&F) &Database Structure This has to be equal to the tab title in all the main tabs &è³‡æ–™åº«çµæ§‹ &Browse Data This has to be equal to the tab title in all the main tabs &ç€è¦½è³‡æ–™ Edit P&ragmas This has to be equal to the tab title in all the main tabs 編輯 P&ragmas E&xecute SQL This has to be equal to the tab title in all the main tabs 執&行 SQL &Import 匯入(&I) &Export 匯出(&E) &Recent Files 最近使用的檔案 &Edit 編輯(&E) &View 檢視(&V) &Help 幫助(&H) Edit Database &Cell 編輯資料庫儲存格(&C) DB Sche&ma è³‡æ–™åº«çµæ§‹(&M) &Remote é ç«¯(&R) Execute current line 執行目å‰é€™ä¸€è¡Œ This button executes the SQL statement present in the current editor line 這個按鈕執行目å‰ç·¨è¼¯å™¨é€™ä¸€è¡Œçš„ SQL é™³è¿°å¼ Shift+F5 Shift+F5 Sa&ve Project 儲存專案(&V) Save SQL file as å°‡ SQL 檔案儲存為 This button saves the content of the current SQL editor tab to a file é€™å€‹æŒ‰éˆ•å°‡ç›®å‰ SQL 編輯器分é çš„內容儲存到一個檔案 &Browse Table ç€è¦½è³‡æ–™è¡¨(&B) Copy Create statement è¤‡è£½å»ºç«‹é™³è¿°å¼ Copy the CREATE statement of the item to the clipboard 將項目的 CREATE 陳述å¼è¤‡è£½åˆ°å‰ªè²¼ç°¿ User 使用者 Application æ‡‰ç”¨ç¨‹å¼ &Clear 清除(&C) &New Database... 新建資料庫(&N)... Create a new database file 建立一個新的資料庫檔 This option is used to create a new database file. 這個é¸é …用於建立一個新的資料庫檔案。 Ctrl+N Ctrl+N &Open Database... 開啟資料庫(&O)... Open an existing database file é–‹å•Ÿä¸€å€‹ç¾æœ‰çš„資料庫檔 This option is used to open an existing database file. 這個é¸é …ç”¨æ–¼é–‹å•Ÿä¸€å€‹ç¾æœ‰çš„資料庫檔案。 Ctrl+O Ctrl+O &Close Database 關閉資料庫(&C) Ctrl+W Ctrl+W Revert database to last saved state 把資料庫退回到先å‰å„²å­˜çš„狀態 This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. 這個é¸é …用於倒退目å‰çš„資料庫檔為它最後的儲存狀態。從最後儲存æ“作開始åšå‡ºçš„æ‰€æœ‰ä¿®æ”¹å°‡æœƒéºå¤±ã€‚ Write changes to the database file 把修改寫入到資料庫檔 This option is used to save changes to the database file. 這個é¸é …用於儲存修改到資料庫檔案。 Ctrl+S Ctrl+S Compact the database file, removing space wasted by deleted records 壓縮資料庫檔案,é€éŽåˆªé™¤è¨˜éŒ„去掉浪費的空間 Compact the database file, removing space wasted by deleted records. 壓縮資料庫檔案,é€éŽåˆªé™¤è¨˜éŒ„去掉浪費的空間。 E&xit 退出(&X) Ctrl+Q Ctrl+Q Import data from an .sql dump text file into a new or existing database. 從一個 .sql 轉儲文字檔中匯入資料到一個新的或已有的資料庫。 This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. 這個é¸é …讓您從一個 .sql è½‰å„²æ–‡å­—æª”ä¸­åŒ¯å…¥è³‡æ–™åˆ°ä¸€å€‹æ–°çš„æˆ–ç¾æœ‰çš„資料庫。SQL 轉儲檔å¯ä»¥åœ¨å¤§å¤šæ•¸è³‡æ–™åº«å¼•擎上建立,包括 MySQL å’Œ PostgreSQL。 Open a wizard that lets you import data from a comma separated text file into a database table. 開啟一個引導精éˆè®“您從一個逗號間隔的文字檔匯入資料到一個資料庫資料表中。 Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. 開啟一個引導精éˆè®“您從一個逗號間隔的文字檔匯入資料到一個資料庫資料表中。CSV 檔å¯ä»¥åœ¨å¤§å¤šæ•¸è³‡æ–™åº«å’Œè©¦ç®—資料表應用程å¼ä¸Šå»ºç«‹ã€‚ Export a database to a .sql dump text file. 匯出一個資料庫導一個 .sql 轉儲文字檔案。 This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. 這個é¸é …讓您匯出一個資料庫導一個 .sql 轉儲文字檔案。SQL 轉儲檔包å«åœ¨å¤§å¤šæ•¸è³‡æ–™åº«å¼•擎上(包括 MySQL å’Œ PostgreSQL)釿–°å»ºç«‹è³‡æ–™åº«æ‰€éœ€çš„æ‰€æœ‰è³‡æ–™ã€‚ Export a database table as a comma separated text file. 匯出一個資料庫資料表為逗號間隔的文字檔案。 Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. 匯出一個資料庫資料表為逗號間隔的文字檔,準備好被匯入到其他資料庫或試算資料表應用程å¼ã€‚ Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database 開啟「建立資料表ã€å¼•å°Žç²¾éˆï¼Œåœ¨é‚£è£¡å¯ä»¥å®šç¾©åœ¨è³‡æ–™åº«ä¸­çš„一個新資料表的åç¨±å’Œæ¬„ä½ Open the Delete Table wizard, where you can select a database table to be dropped. 開啟「刪除資料表ã€å¼•å°Žç²¾éˆï¼Œåœ¨é‚£è£¡æ‚¨å¯ä»¥é¸æ“‡è¦ä¸Ÿæ£„的一個資料庫資料表。 Open the Create Index wizard, where it is possible to define a new index on an existing database table. 開啟「建立索引ã€å¼•å°Žç²¾éˆï¼Œåœ¨é‚£è£¡å¯ä»¥åœ¨ä¸€å€‹ç¾æœ‰çš„資料庫資料表上定義一個新索引。 &Preferences... å好設定(&P)... Open the preferences window. 開啟å好設定視窗。 &DB Toolbar 資料庫工具列(&D) Shows or hides the Database toolbar. 顯示或隱è—資料庫工具列。 Shift+F1 Shift+F1 &Recently opened 最近開啟(&R) Ctrl+T Ctrl+T This is the structure of the opened database. You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. é€™æ˜¯å·²é–‹å•Ÿè³‡æ–™åº«çš„çµæ§‹ã€‚ 您å¯ä»¥å¾žç‰©ä»¶åˆ—中拖曳 SQL 陳述å¼ï¼Œä¸¦å°‡å®ƒå€‘æ‹–æ›³åˆ°å…¶ä»–æ‡‰ç”¨ç¨‹å¼æˆ–å¦ä¸€å€‹ã€ŒDB Browser for SQLiteã€ä¸­ã€‚ Un/comment block of SQL code 註解/å–æ¶ˆè¨»è§£ SQL 程å¼ç¢¼å€å¡Š Un/comment block 註解/å–æ¶ˆè¨»è§£å€å¡Š Comment or uncomment current line or selected block of code å°é€™ä¸€è¡Œæˆ–é¸å®šå€å¡Šçš„程å¼ç¢¼é€²è¡Œè¨»è§£æˆ–å–æ¶ˆè¨»è§£ Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. å°é¸å–的行數或目å‰é€™ä¸€è¡Œï¼ˆç•¶æ²’有é¸å–任何æ±è¥¿æ™‚ï¼‰è¨»è§£æˆ–å–æ¶ˆè¨»è§£ã€‚所有的å€å¡Šå°‡æ ¹æ“šç¬¬ä¸€è¡Œé€²è¡Œåˆ‡æ›ã€‚ Ctrl+/ Ctrl+/ Stop SQL execution åœæ­¢ SQL 執行 Stop execution åœæ­¢åŸ·è¡Œ Stop the currently running SQL script åœæ­¢ç›®å‰æ­£åœ¨åŸ·è¡Œçš„ SQL 腳本 Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. 警告:這個 pragma 是ä¸å¯è®€çš„,並且這個值已經被推斷出來。寫入 pragma å¯èƒ½æœƒè¦†è“‹ç”± SQLite 擴充套件æä¾›çš„已釿–°å®šç¾©çš„ LIKE。 Too&ls 工具(&T) DB Toolbar 資料庫工具列 SQL &Log SQL 日誌(&L) Show S&QL submitted by 顯示æäº¤çš„ SQL(&Q) Error Log 錯誤日誌 This button clears the contents of the SQL logs 這個按鈕清除 SQL 日誌的內容 This panel lets you examine a log of all SQL commands issued by the application or by yourself 這個颿¿è®“æ‚¨æª¢è¦–ç”±æ‡‰ç”¨ç¨‹å¼æˆ–您自己發出的所有 SQL 命令的日誌 &Plot 繪圖(&P) This is the structure of the opened database. You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. é€™æ˜¯å·²é–‹å•Ÿè³‡æ–™åº«çš„çµæ§‹ã€‚ 您å¯ä»¥å¾žå稱欄ä½ä¸­æ‹–曳多個物件å稱,並將它們拖曳到 SQL 編輯器,您å¯ä»¥ä½¿ç”¨å³éµé¸å–®èª¿æ•´æ‹–曳的å稱的屬性。這將有助於您撰寫 SQL 陳述å¼ã€‚ 您å¯ä»¥å¾žçµæ§‹æ¬„ä½ä¸­æ‹–曳 SQL 陳述å¼ï¼Œä¸¦å°‡å®ƒå€‘拖曳到 SQL 編輯器或其他應用程å¼ã€‚ Project Toolbar 專案工具列 Extra DB toolbar é¡å¤–的資料庫工具列 Close the current database file 關閉目å‰çš„資料庫檔案 &New Database &新建資料庫 This button closes the connection to the currently open database file 這個按鈕會關閉目å‰é–‹å•Ÿçš„資料庫檔案的連線 Ctrl+F4 Ctrl+F4 &Revert Changes &還原變更 &Undo &復原 Undo last change to the database 復原資料庫的最後一次變更 This action undoes the last change performed to the database in the Database Browser or in Execute SQL. Redoing is not possible. 這個動作會復原在 Database Browser 或執行 SQL 中å°è³‡æ–™åº«é€²è¡Œçš„æœ€å¾Œä¸€æ¬¡è®Šæ›´ã€‚無法é‡åšã€‚ &Write Changes 寫入變更(&W) Compact &Database... 壓縮資料庫(&D)... Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields from a table, as well as modify field names and types. 開啟「修改表格ã€ç²¾éˆï¼Œåœ¨æ­¤æ‚¨å¯ä»¥é‡æ–°å‘½å已存在的表格。您也å¯ä»¥æ–°å¢žæˆ–刪除表格中的欄ä½ï¼Œä»¥åŠä¿®æ”¹æ¬„ä½å稱和類型。 Execute all/selected SQL 執行所有/é¸å–çš„ SQL This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. 這個按鈕執行目å‰é¸å–çš„ SQL 陳述å¼ã€‚如果沒有é¸å–任何文字,則執行所有 SQL 陳述å¼ã€‚ Ctrl+Shift+T Ctrl+Shift+T &Load Extension... 載入擴充套件(&L)... Execute line 執行這一行 &Wiki 維基(&W) F1 F1 Bug &Report... 錯誤回報(&R)... Feature Re&quest... 功能請求(&Q)... Web&site 網站(&S) &Donate on Patreon... 在 Patreon 上贊助(&D)... &Save Project 儲存專案(&S) Open &Project... 開啟專案(&P)... Open &Project 開啟專案(&P) &Attach Database... 附加資料庫(&A)... Add another database file to the current database connection å°‡å¦ä¸€å€‹è³‡æ–™åº«æª”案加到目å‰çš„資料庫連線 This button lets you add another database file to the current database connection 這個按鈕讓您將å¦ä¸€å€‹è³‡æ–™åº«æª”案加到目å‰çš„資料庫連線 &Set Encryption... 設定加密(&S)... SQLCipher &FAQ SQLCipher 常見å•題(&F) Table(&s) to JSON... 資料表(&S)轉æ›ç‚º JSON... Open Data&base Read Only... 以唯讀模å¼é–‹å•Ÿè³‡æ–™åº«(&B)... Ctrl+Shift+O Ctrl+Shift+O Save results å„²å­˜çµæžœ Save the results view å„²å­˜çµæžœé¡¯ç¤º This button lets you save the results of the last executed query é€™å€‹æŒ‰éˆ•è®“æ‚¨å„²å­˜æœ€å¾ŒåŸ·è¡ŒæŸ¥è©¢çš„çµæžœ Find text in SQL editor 在 SQL 編輯器中尋找文字 Find 尋找 This button opens the search bar of the editor 這個按鈕開啟編輯器的æœå°‹åˆ— Ctrl+F Ctrl+F Find or replace text in SQL editor 在 SQL 編輯器中尋找或å–代文字 Find or replace 尋找或å–代 This button opens the find/replace dialog for the current editor tab 這個按鈕開啟目å‰ç·¨è¼¯å™¨åˆ†é çš„尋找/å–代å°è©±æ¡† Ctrl+H Ctrl+H Export to &CSV 匯出為 &CSV Export to &JSON 匯出為 &JSON Save as &view 儲存為檢視表(&V) Save as view 儲存為檢視表 &Open Database &開啟資料庫 Drag && Drop SELECT Query 拖曳 && 放下 SELECT 查詢 When dragging fields from the same table or a single table, drop a SELECT query into the editor 當從åŒä¸€è³‡æ–™è¡¨æˆ–å–®ä¸€è³‡æ–™è¡¨æ‹–æ›³æ¬„ä½æ™‚,將 SELECT 查詢放入編輯器 Browse Table ç€è¦½è³‡æ–™è¡¨ Ctrl+Shift+W Ctrl+Shift+W Table from CSV data in Clipboard... 從剪貼簿中的 CSV 資料建立資料表... This treats the current clipboard contents as a CSV file and opens the same import wizard that is used for importing CSV data from a file. 將目å‰å‰ªè²¼ç°¿çš„內容視為 CSV 檔案,並開啟與從檔案匯入 CSV 資料相åŒçš„匯入精éˆã€‚ Show &Row Counts 顯示 &列計數 This shows the number of rows for each table and view in the database. 顯示資料庫中æ¯å€‹è³‡æ–™è¡¨å’Œæª¢è¦–表的列數。 Save Database &As... å¦å­˜è³‡æ–™åº« &為... Save the current database as a different file 將目å‰çš„資料庫å¦å­˜ç‚ºä¸åŒçš„æª”案 Refresh 釿–°æ•´ç† Reload the database structure 釿–°è¼‰å…¥è³‡æ–™åº«çµæ§‹ Shows or hides the Project toolbar. 顯示或隱è—專案工具列。 New &tab 新分é (&T) Open SQL file(s) 開啟 SQL 檔案 This button opens files containing SQL statements and loads them in new editor tabs é€™å€‹æŒ‰éˆ•é–‹å•ŸåŒ…å« SQL 陳述å¼çš„æª”案,並在新的編輯器分é ä¸­è¼‰å…¥å®ƒå€‘ This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file 這個按鈕讓您儲存所有與開啟的資料庫相關的設定到一個 DB Browser for SQLite 的專案檔 This button lets you open a DB Browser for SQLite project file 這個按鈕讓您開啟一個 DB Browser for SQLite 的專案檔 Extra DB Toolbar é¡å¤–的資料庫工具列 New In-&Memory Database 新建記憶體中的資料庫 Drag && Drop Qualified Names 拖曳並放下完全é™å®šå稱 Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor 在拖曳物件並將其放入編輯器時,使用完全é™å®šå稱(例如「Tableã€.「Fieldã€ï¼‰ Drag && Drop Enquoted Names 拖曳並放下引號å稱 Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor 在拖曳物件並將其放入編輯器時,使用轉義識別符號(例如「Table1ã€ï¼‰ &Integrity Check &完整性檢查 Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. 在已開啟的資料庫上執行 integrity_check pragma,並在執行 SQL æ¨™ç±¤ä¸­å›žå‚³çµæžœã€‚æ­¤ pragma å°æ•´å€‹è³‡æ–™åº«é€²è¡Œå®Œæ•´æ€§æª¢æŸ¥ã€‚ &Foreign-Key Check &外鵿ª¢æŸ¥ Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab 在已開啟的資料庫上執行 foreign_key_check pragma,並在執行 SQL æ¨™ç±¤ä¸­å›žå‚³çµæžœ &Quick Integrity Check &快速完整性檢查 Run a quick integrity check over the open DB å°é–‹å•Ÿçš„資料庫進行快速完整性檢查 Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. 在已開啟的資料庫上執行 quick_check pragma,並在執行 SQL æ¨™ç±¤ä¸­å›žå‚³çµæžœã€‚此命令執行 PRAGMA integrity_check 的大部分檢查,但執行速度更快。 &Optimize &最佳化 Attempt to optimize the database 嘗試最佳化資料庫 Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. 在已開啟的資料庫上執行 optimize pragma。此 pragma å¯èƒ½æœƒåŸ·è¡Œæœ€ä½³åŒ–,以æé«˜æœªä¾†æŸ¥è©¢çš„æ•ˆèƒ½ã€‚ Print åˆ—å° Print text from current SQL editor tab 列å°ç›®å‰ SQL 編輯器標籤中的文字 Open a dialog for printing the text in the current SQL editor tab 開啟一個å°è©±æ¡†ä»¥åˆ—å°ç›®å‰ SQL 編輯器標籤中的文字 Print the structure of the opened database 列å°å·²é–‹å•Ÿçš„è³‡æ–™åº«çµæ§‹ Open a dialog for printing the structure of the opened database 開啟一個å°è©±æ¡†ä»¥åˆ—å°å·²é–‹å•Ÿçš„è³‡æ–™åº«çµæ§‹ &Save Project As... &å¦å­˜å°ˆæ¡ˆç‚º... Save the project in a file selected in a dialog 在å°è©±æ¡†ä¸­é¸æ“‡çš„æª”案中儲存專案 Save A&ll 全部儲存 Save DB file, project file and opened SQL files 儲存資料庫檔案ã€å°ˆæ¡ˆæª”案和已開啟的 SQL 檔案 Ctrl+Shift+S Ctrl+Shift+S Close Pro&ject 關閉專案 Close project and database files and return to the initial state 關閉專案和資料庫檔案,並返回åˆå§‹ç‹€æ…‹ Ctrl+Shift+F4 Ctrl+Shift+F4 Detach Database 分離資料庫 Detach database file attached to the current database connection 分離目å‰è³‡æ–™åº«é€£ç·šæ‰€é™„加的資料庫檔案 &Database from SQL file... &從 SQL 檔案建立資料庫... &Table from CSV file... &從 CSV 檔案建立資料表... &Database to SQL file... &資料庫轉æ›ç‚º SQL 檔案... &Table(s) as CSV file... &資料表轉æ›ç‚º CSV 檔案... &Create Table... &建立資料表... &Delete Table... &刪除資料表... &Modify Table... &修改資料表... Create &Index... 建立 &索引... W&hat's This? 這是什麼? &About &關於 This button opens a new tab for the SQL editor 此按鈕將開啟 SQL 編輯器的新標籤 &Execute SQL 執行 SQL(&E) Save the current session to a file 儲存目å‰å·¥ä½œéšŽæ®µåˆ°æª”案 Load a working session from a file 從一檔案載入工作階段 Save SQL file 儲存 SQL 檔案 Ctrl+E Ctrl+E Export as CSV file 匯出為 CSV 檔案 Export table as comma separated values file 將資料表匯出為逗號分隔值檔案 Ctrl+L Ctrl+L Ctrl+P Ctrl+P Database encoding 資料庫編碼 Choose a database file 鏿“‡ä¸€å€‹è³‡æ–™åº«æª”案 Ctrl+Return Ctrl+Return Ctrl+D Ctrl+D Ctrl+I Ctrl+I Reset Window Layout é‡è¨­è¦–窗é…ç½® The database is currently busy. 資料庫目å‰å¿™ç¢Œä¸­ã€‚ Click here to interrupt the currently running query. 點é¸é€™è£¡ä¸­æ–·ç›®å‰æ­£åœ¨åŸ·è¡Œçš„æŸ¥è©¢ã€‚ Encrypted 已加密 Database is encrypted using SQLCipher 資料庫已使用 SQLCipher 加密 Read only 唯讀 Database file is read only. Editing the database is disabled. 資料庫檔案是唯讀的。已åœç”¨ç·¨è¼¯è³‡æ–™åº«ã€‚ Could not open database file. Reason: %1 無法開啟資料庫檔案。 原因: %1 Choose a filename to save under 鏿“‡ä¸€å€‹è¦å„²å­˜çš„æª”案å稱 Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. %1 儲存資料庫檔案時出ç¾éŒ¯èª¤ã€‚é€™è¡¨ç¤ºä¸¦éžæ‰€æœ‰å°è³‡æ–™åº«çš„變更都已儲存。您需è¦å…ˆè§£æ±ºä»¥ä¸‹çš„錯誤。 %1 Do you want to save the changes made to SQL tabs in the project file '%1'? 您是å¦è¦å„²å­˜å°å°ˆæ¡ˆæª”案「%1ã€ä¸­çš„ SQL åˆ†é æ‰€åšçš„變更? A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. 有新版的 DB Browser for SQLite å¯ç”¨ (%1.%2.%3)。<br/><br/>請在 <a href='%4'>%4</a> 下載。 DB Browser for SQLite project file (*.sqbpro) DB Browser for SQLite 專案檔案 (*.sqbpro) Error checking foreign keys after table modification. The changes will be reverted. ä¿®æ”¹è³‡æ–™è¡¨å¾Œæª¢æŸ¥å¤–éµæ™‚出ç¾éŒ¯èª¤ã€‚將會還原變更。 This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. 這個資料表未通éŽå¤–鵿ª¢æŸ¥ã€‚<br/>您應該執行「工具 | 外鵿ª¢æŸ¥ã€ä¸¦ä¿®æ­£å ±å‘Šçš„å•題。 Execution finished with errors. 執行完æˆä¸¦å‡ºç¾éŒ¯èª¤ã€‚ Execution finished without errors. 執行完æˆä¸¦æœªå‡ºç¾éŒ¯èª¤ã€‚ Are you sure you want to undo all changes made to the database file '%1' since the last save? 您是å¦ç¢ºèªæ‚¨æƒ³æ’¤éŠ·å¾žä¸Šæ¬¡å„²å­˜ä»¥ä¾†å°è³‡æ–™åº«æª”‘%1’åšå‡ºçš„æ‰€æœ‰ä¿®æ”¹ã€‚? Choose a file to import 鏿“‡è¦åŒ¯å…¥çš„一個檔案 Text files(*.sql *.txt);;All files(*) 文字檔案(*.sql *.txt);;所有擋檔案(*) Do you want to create a new database file to hold the imported data? If you answer no we will attempt to import the data in the SQL file to the current database. æ‚¨æ˜¯å¦æƒ³è¦å»ºç«‹ä¸€å€‹æ–°çš„資料庫檔案來儲存匯入的資料? å¦‚æžœæ‚¨é¸æ“‡ã€Œå¦ã€ï¼Œæˆ‘們將嘗試將 SQL 檔中的資料匯入到目å‰çš„資料庫。 File %1 already exists. Please choose a different name. 檔案 %1 å·²å­˜åœ¨ã€‚è«‹é¸æ“‡ä¸€å€‹ä¸åŒçš„å稱。 Error importing data: %1 匯入資料時出ç¾éŒ¯èª¤: %1 Import completed. 匯入完æˆã€‚ Delete View 刪除檢視表 Delete Trigger 刪除觸發器 Delete Index 刪除索引 Delete Table 刪除資料表 Setting PRAGMA values will commit your current transaction. Are you sure? 設定 PRAGMA 值將會æäº¤æ‚¨çš„ç›®å‰äº¤æ˜“。. 您確èªå—Ž? In-Memory database 記憶體內部資料庫 Ctrl+Tab Ctrl+Tab Ctrl+Shift+Tab Ctrl+Shift+Tab Clear List 清除清單 Window Layout 視窗é…ç½® Ctrl+Alt+0 Ctrl+Alt+0 Simplify Window Layout 簡化視窗é…ç½® Alt+Shift+0 Alt+Shift+0 Dock Windows at Bottom 在底端åœé§è¦–窗 Dock Windows at Left Side 在左å´åœé§è¦–窗 Dock Windows at Top 在頂端åœé§è¦–窗 Ctrl+Alt+W Ctrl+Alt+W Choose a database file to save under 鏿“‡ä¸€å€‹è³‡æ–™åº«æª”案進行儲存 Error while saving the database to the new file. 儲存資料庫到新檔案時發生錯誤。 Are you sure you want to delete the table '%1'? All data associated with the table will be lost. 您是å¦ç¢ºèªæ‚¨æƒ³åˆªé™¤è³‡æ–™è¡¨ã€Œ%1ã€? 所有與資料表相關的資料將會éºå¤±ã€‚ Are you sure you want to delete the view '%1'? 您是å¦ç¢ºèªæ‚¨æƒ³åˆªé™¤æª¢è¦–表「%1ã€? Are you sure you want to delete the trigger '%1'? 您是å¦ç¢ºèªæ‚¨æƒ³åˆªé™¤è§¸ç™¼å™¨ã€Œ%1ã€? Are you sure you want to delete the index '%1'? 您是å¦ç¢ºèªæ‚¨æƒ³åˆªé™¤ç´¢å¼•「%1ã€? Error: could not delete the table. 錯誤:無法刪除資料表。 Error: could not delete the view. 錯誤:無法刪除檢視表。 Error: could not delete the trigger. 錯誤:無法刪除觸發器。 Error: could not delete the index. 錯誤:無法刪除索引。 Message from database engine: %1 來自資料庫引擎的訊æ¯ï¼š %1 Editing the table requires to save all pending changes now. Are you sure you want to save the database? 編輯表格å‰å¿…須先儲存所有尚未完æˆçš„修改。 您確定è¦å„²å­˜é€™å€‹è³‡æ–™åº«å—Žï¼Ÿ Edit View %1 編輯檢視表 %1 Edit Trigger %1 編輯觸發器 %1 You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. 您已經在執行 SQL 陳述å¼ã€‚您是å¦è¦åœæ­¢å®ƒå€‘,以便改為執行目å‰çš„陳述å¼? 請注æ„,這å¯èƒ½æœƒä½¿è³‡æ–™åº«è™•æ–¼ä¸ä¸€è‡´çš„狀態。 -- EXECUTING SELECTION IN '%1' -- -- 在「%1ã€ä¸­åŸ·è¡Œé¸å–的部份 -- -- EXECUTING LINE IN '%1' -- -- 在「%1ã€ä¸­åŸ·è¡Œé€™ä¸€è¡Œ -- -- EXECUTING ALL IN '%1' -- -- 在「%1ã€ä¸­åŸ·è¡Œæ‰€æœ‰ -- At line %1: 在第 %1 行: Result: %1 çµæžœï¼š%1 Result: %2 çµæžœï¼š%2 Setting PRAGMA values or vacuuming will commit your current transaction. Are you sure? 設定 PRAGMA 值或清ç†å°‡æœƒæäº¤æ‚¨çš„ç›®å‰äº¤æ˜“。. 您確èªå—Ž? Opened '%1' in read-only mode from recent file list 從最近的檔案列表中以唯讀模å¼é–‹å•Ÿ '%1' Opened '%1' from recent file list 從最近的檔案列表中開啟 '%1' Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. Note for translation: Although there is no %n in the original, you can use the numerus-form to adjust 'files(s)' and remove the note when n = 1. Including %n in the translation will also work. 鏿“‡è¦å¥—用於拖放的檔案的動作。 <br/>注æ„ï¼šåªæœ‰ '匯入' 將處ç†å¤šå€‹æª”案。 The statements in the tab '%1' are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? 標籤 '%1' 中的指令ä»åœ¨åŸ·è¡Œã€‚é—œé–‰æ¨™ç±¤å°‡æœƒåœæ­¢åŸ·è¡Œã€‚這å¯èƒ½æœƒä½¿è³‡æ–™åº«è™•æ–¼ä¸ä¸€è‡´çš„狀態。您確定è¦é—œé–‰æ¨™ç±¤å—Žï¼Ÿ DB file '%1' could not be opened 無法開啟資料庫檔案 '%1' This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is no longer fully supported. If you want to load it completely, please use DB Browser for SQLite version 3.12 to convert it to the new file format. 此專案檔案使用舊的檔案格å¼ï¼Œå› ç‚ºå®ƒæ˜¯ä½¿ç”¨ DB Browser for SQLite 3.10 版或更舊的版本建立的。我們已經ä¸å†å®Œå…¨æ”¯æ´è¼‰å…¥æ­¤æª”案格å¼ã€‚如果您想完全載入,請使用 DB Browser for SQLite 3.12 版將其轉æ›ç‚ºæ–°çš„æª”案格å¼ã€‚ Table '%1' not found; settings ignored 找ä¸åˆ°è³‡æ–™è¡¨ '%1';設定已忽略 -- Reference to file "%1" (not supported by this version) -- -- æŒ‡å‘æª”案 "%1"ï¼ˆæœ¬ç‰ˆæœ¬ä¸æ”¯æ´ï¼‰-- Project saved to file '%1' 專案已儲存到檔案 '%1' Yes. Don't ask again 是的。ä¸å†è©¢å• This action will open a new SQL tab with the following statements for you to edit and run: 此動作將開啟一個新的 SQL 標籤,供您編輯和執行以下指令: Rename Tab 釿–°å‘½å標籤 Duplicate Tab 複製標籤 Close Tab 關閉標籤 Opening '%1'... 正在開啟 '%1'... There was an error opening '%1'... 開啟 '%1' 時發生錯誤... Value is not a valid URL or filename: %1 值䏿˜¯æœ‰æ•ˆçš„ URL 或檔案å稱:%1 %1 rows returned in %2ms %2ms 內回傳 %1 行 Automatically load the last opened DB file at startup You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? 您ä»åœ¨åŸ·è¡Œ SQL 指令。ç¾åœ¨é—œé–‰è³‡æ–™åº«å°‡æœƒåœæ­¢ä»–們的執行,å¯èƒ½æœƒä½¿è³‡æ–™åº«è™•æ–¼ä¸ä¸€è‡´çš„狀態。您確定è¦é—œé–‰è³‡æ–™åº«å—Žï¼Ÿ Do you want to save the changes made to the project file '%1'? 您是å¦è¦å„²å­˜å°å°ˆæ¡ˆæª”案 '%1' 所åšçš„æ›´æ”¹ï¼Ÿ Choose text files 鏿“‡æ–‡å­—檔案 Import completed. Some foreign key constraints are violated. Please fix them before saving. 匯入完æˆã€‚é•åäº†ä¸€äº›å¤–éµæ¢ä»¶ã€‚請在儲存之å‰ä¿®æ­£å®ƒå€‘。 Modify View 修改檢視表 Modify Trigger 修改觸發器 Modify Index 修改索引 Modify Table 修改表格 &%1 %2%3 &%1 %2%3 (read only) (唯讀) Open Database or Project 開啟資料庫或專案 Attach Database... 附加資料庫... Import CSV file(s)... 匯入 CSV 檔案... Do you want to save the changes made to SQL tabs in a new project file? 您是å¦è¦åœ¨æ–°çš„å°ˆæ¡ˆæª”ä¸­å„²å­˜å° SQL åˆ†é æ‰€åšçš„變更? Do you want to save the changes made to the SQL file %1? 您是å¦è¦å„²å­˜å° SQL 檔案 %1 所åšçš„變更? Select SQL file to open 鏿“‡è¦é–‹å•Ÿçš„ SQL 檔案 Select file name 鏿“‡æª”案å稱 Select extension file 鏿“‡æ“´å……套件檔案 Extension successfully loaded. 擴充套件æˆåŠŸè¼‰å…¥ã€‚ Error loading extension: %1 載入擴充套件時出ç¾éŒ¯èª¤: %1 Could not find resource file: %1 找ä¸åˆ°è³‡æºæª”案: %1 Don't show again ä¸å†é¡¯ç¤º New version available. 有新版本å¯ç”¨ã€‚ Choose a project file to open 鏿“‡è¦é–‹å•Ÿçš„專案檔 Could not open project file for writing. Reason: %1 無法開啟專案檔以進行寫入。 原因:%1 Collation needed! Proceed? 需è¦å®šåº! 繼續? A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. If you choose to proceed, be aware bad things can happen to your database. Create a backup! 這個資料庫中的一個資料表需è¦ä¸€å€‹ç‰¹æ®Šçš„定åºå‡½å¼ã€Œ%1ã€ï¼Œè€Œé€™å€‹æ‡‰ç”¨ç¨‹å¼åœ¨æ²’有進一步的知識下無法æä¾›ã€‚ å¦‚æžœæ‚¨é¸æ“‡ç¹¼çºŒï¼Œè«‹æ³¨æ„å¯èƒ½æœƒå°æ‚¨çš„資料庫發生å•題。 建立備份! creating collation 建立定åºè¦å‰‡ Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. 為 SQL 分é è¨­å®šä¸€å€‹æ–°å稱。使用「&&ã€å­—元以å…許使用後é¢çš„字元作為éµç›¤å¿«æ·éµã€‚ Please specify the view name 請指定檢視表å稱 There is already an object with that name. Please choose a different name. 已有相åŒåç¨±çš„ç‰©ä»¶ã€‚è«‹é¸æ“‡ä¸€å€‹ä¸åŒçš„å稱。 View successfully created. æˆåŠŸå»ºç«‹æª¢è¦–è¡¨ã€‚ Error creating view: %1 建立檢視表時出ç¾éŒ¯èª¤: %1 This action will open a new SQL tab for running: 這個動作將會開啟一個新的 SQL 分é ä»¥é€²è¡ŒåŸ·è¡Œï¼š Press Help for opening the corresponding SQLite reference page. 按下「說明ã€ä»¥é–‹å•Ÿå°æ‡‰çš„ SQLite åƒè€ƒé é¢ã€‚ Busy (%1) 忙碌 (%1) NullLineEdit Set to NULL 設定為 NULL Alt+Del Alt+Del PlotDock Plot 圖表 <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> <html><head/><body><p>æ­¤é¢æ¿é¡¯ç¤ºç›®å‰ç€è¦½çš„表格或剛執行的查詢的資料列清單。您å¯ä»¥é¸æ“‡æ‚¨æƒ³è¦ç”¨ä½œä¸‹æ–¹ç¹ªåœ–颿¿çš„ X 或 Y è»¸çš„è³‡æ–™åˆ—ã€‚è¡¨æ ¼é¡¯ç¤ºæœƒå½±éŸ¿çµæžœåœ–è¡¨çš„åµæ¸¬åˆ°çš„åº§æ¨™è»¸é¡žåž‹ã€‚å°æ–¼ Y 軸,您åªèƒ½é¸æ“‡æ•¸å€¼åˆ—ï¼Œä½†å°æ–¼ X è»¸ï¼Œæ‚¨å°‡èƒ½å¤ é¸æ“‡ï¼š</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日期/時間</span>:格å¼ç‚º &quot;yyyy-MM-dd hh:mm:ss&quot; 或 &quot;yyyy-MM-ddThh:mm:ss&quot; 的字串</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日期</span>:格å¼ç‚º &quot;yyyy-MM-dd&quot; 的字串</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">時間</span>:格å¼ç‚º &quot;hh:mm:ss&quot; 的字串</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">標籤</span>:其他字串格å¼ã€‚鏿“‡æ­¤åˆ—作為 X 軸將產生一個柱狀圖,列值作為柱å­çš„æ¨™ç±¤</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">數值</span>:整數或實數值</li></ul><p>點é¸å…©ä¸‹ Y 儲存格,您å¯ä»¥æ›´æ”¹è©²åœ–形使用的é¡è‰²ã€‚</p></body></html> Columns 列 X X Y1 Y1 Y2 Y2 Axis Type 座標軸類型 Here is a plot drawn when you select the x and y values above. Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. Use mouse-wheel for zooming and mouse drag for changing the axis range. Select the axes or axes labels to drag and zoom only in that orientation. é€™æ˜¯ç•¶æ‚¨é¸æ“‡ä¸Šæ–¹çš„ x å’Œ y 值時繪製的圖表。 在圖表點é¸å®ƒå€‘å’Œåœ¨è¡¨æ ¼ä¸­é¸æ“‡å®ƒå€‘。 使用 Ctrl + 點é¸ä¾†é¸æ“‡ä¸€ç³»åˆ—的點。 使用滑鼠滾輪進行縮放,並拖動滑鼠以改變座標軸範åœã€‚ åªé¸æ“‡åº§æ¨™è»¸æˆ–座標軸標籤以在該方å‘上拖動和縮放。 Line type: 線型: None ç„¡ Line ç·šæ¢ StepLeft 左步驟 StepRight 峿­¥é©Ÿ StepCenter 中心步驟 Impulse è„ˆè¡ Point shape: 點形狀: Cross åå­— Plus 加號 Circle 圓形 Disc 圓盤 Square 方形 Diamond è±å½¢ Star 星形 Triangle 三角形 TriangleInverted 倒三角形 CrossSquare å字方形 PlusSquare 加號方形 CrossCircle å字圓形 PlusCircle 加號圓形 Peace 和平 <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> <html><head/><body><p>儲存目å‰çš„圖表...</p><p>檔案格å¼ç”±å‰¯æª”å鏿“‡ (png, jpg, pdf, bmp)</p></body></html> Save current plot... 儲存目å‰çš„圖表... Load all data and redraw plot 載入所有資料並é‡ç¹ªåœ–表 Row # 列 # Copy 複製 Print... 列å°... Show legend 顯示圖例 Stacked bars 堆疊長æ¢åœ– Fixed number format å›ºå®šæ•¸å­—æ ¼å¼ Date/Time 日期/時間 Date 日期 Time 時間 Numeric 數值 Label 標籤 Invalid 無效 Load all data and redraw plot. Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. 載入所有資料並é‡ç¹ªåœ–表。 警告:由於部分å–得機制,尚未從表格å–得所有資料。 Choose an axis color 鏿“‡åº§æ¨™è»¸é¡è‰² Choose a filename to save under 鏿“‡è¦å„²å­˜çš„æª”案å稱 PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;所有檔案(*) There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. 此圖表中有曲線,且所é¸çš„ç·šåž‹åªèƒ½å¥—用於按 X 排åºçš„圖形。請按 X 排åºè¡¨æ ¼æˆ–æŸ¥è©¢ä»¥ç§»é™¤æ›²ç·šï¼Œæˆ–é¸æ“‡æ›²ç·šæ”¯æ´çš„其中一種樣å¼ï¼šç„¡æˆ–ç·šæ¢ã€‚ Loading all remaining data for this table took %1ms. 載入此表格所有剩餘資料花了 %1ms。 PreferencesDialog Preferences å好é¸é … &General &一般 Remember last location 記ä½ä¸Šæ¬¡çš„ä½ç½® Always use this location 總是使用此ä½ç½® Remember last location for session only åªè¨˜ä½æ­¤æ¬¡å·¥ä½œéšŽæ®µçš„ä½ç½® Lan&guage 語言(&G) Show remote options 顯示é ç«¯é¸é … Automatic &updates 自動更新(&U) &Database 資料庫(&D) Database &encoding 資料庫編碼(&E) Open databases with foreign keys enabled. 開啟啟用了外éµçš„資料庫。 &Foreign keys 外éµ(&F) enabled 啟用 Default &location é è¨­ä½ç½®(&L) ... ... Remove line breaks in schema &view åœ¨çµæ§‹æª¢è¦–中移除æ›è¡Œ(&V) Prefetch block si&ze é å–å€å¡Šå¤§å°(&Z) SQ&L to execute after opening database 開啟資料庫後執行的 SQL(&L) Default field type é è¨­æ¬„ä½é¡žåž‹ Data &Browser 資料ç€è¦½å™¨(&B) Font å­—åž‹ &Font å­—åž‹(&F) Content 內容 Symbol limit in cell 儲存格中的符號é™åˆ¶ Threshold for completion and calculation on selection 鏿“‡å®Œæˆèˆ‡è¨ˆç®—的閾值 Show images in cell 在儲存格中顯示圖片 Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. 啟用此é¸é …以在儲存格中顯示包å«åœ–片資料的 BLOB é è¦½ã€‚然而,這å¯èƒ½æœƒå½±éŸ¿è³‡æ–™ç€è¦½å™¨çš„æ•ˆèƒ½ã€‚ NULL NULL Regular 一般 Binary äºŒé€²ä½ Background 背景 Filters 篩é¸å™¨ Escape character 跳脫字元 Delay time (&ms) 延鲿™‚é–“ (&ms) Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. 設定新的篩é¸å€¼æ‡‰ç”¨å‰çš„等待時間。å¯ä»¥è¨­å®šç‚º 0 以åœç”¨ç­‰å¾…。 &SQL &SQL Context 上下文 Colour é¡è‰² Bold ç²—é«” Italic 斜體 Underline 底線 Keyword é—œéµå­— Function å‡½å¼ Table 資料表 Comment 注釋 Identifier 識別符號 String 字串 Current line 這一行 SQL &editor font size SQL 編輯器字型大å°(&E) Tab size æ¨™ç±¤å¤§å° SQL editor &font SQL 編輯器字型(&F) Error indicators 錯誤指示器 Hori&zontal tiling 水平平鋪(&Z) If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. 如果啟用,則 SQL 程å¼ç¢¼ç·¨è¼¯å™¨å’Œçµæžœè¡¨æ ¼æª¢è¦–å°‡ä¸¦æŽ’é¡¯ç¤ºï¼Œè€Œä¸æ˜¯ä¸€å€‹åœ¨å¦ä¸€å€‹ä¸Šé¢ã€‚ Code co&mpletion 程å¼ç¢¼è£œå®Œ(&M) Toolbar style å·¥å…·åˆ—æ¨£å¼ Only display the icon åªé¡¯ç¤ºåœ–示 Only display the text åªé¡¯ç¤ºæ–‡å­— The text appears beside the icon 文字出ç¾åœ¨åœ–示æ—邊 The text appears under the icon 文字出ç¾åœ¨åœ–示下方 Follow the style è·Ÿéš¨æ¨£å¼ DB file extensions 資料庫檔案副檔å Manage ç®¡ç† Main Window 主視窗 Database Structure è³‡æ–™åº«çµæ§‹ Browse Data ç€è¦½è³‡æ–™ Execute SQL 執行 SQL Edit Database Cell 編輯資料庫儲存格 When this value is changed, all the other color preferences are also set to matching colors. 當此值變更時,所有其他é¡è‰²å好設定也將設定為相符的é¡è‰²ã€‚ Follow the desktop style è·Ÿéš¨æ¡Œé¢æ¨£å¼ Dark style æ·±è‰²æ¨£å¼ Application style æ‡‰ç”¨ç¨‹å¼æ¨£å¼ This sets the font size for all UI elements which do not have their own font size option. 此設定為所有沒有自己的字型大å°é¸é …çš„ UI 元素設定字型大å°ã€‚ Font size å­—åž‹å¤§å° Max Recent Files æœ€è¿‘çš„æª”æ¡ˆæœ€å¤§æ•¸é‡ Prompt to save SQL tabs in new project file æç¤ºå„²å­˜ SQL åˆ†é  åœ¨æ–°çš„å°ˆæ¡ˆæª”æ¡ˆä¸­ If this is turned on, then changes to the SQL editor generate a save a project confirmation dialog when closing the SQL editor tab. 如果此é¸é …開啟,則在關閉 SQL ç·¨è¼¯å™¨åˆ†é æ™‚ï¼Œå° SQL 編輯器的變更將產生儲存專案的確èªå°è©±æ¡†ã€‚ When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. 當啟用時,將移除 DB çµæ§‹åˆ†é ã€ç¢¼é ­å’Œåˆ—å°è¼¸å‡ºä¸­ç¶±è¦æ¬„ä½çš„æ›è¡Œã€‚ Database structure font size è³‡æ–™åº«çµæ§‹å­—åž‹å¤§å° Font si&ze 字型大å°(&Z) This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: Maximum number of rows in a table for enabling the value completion based on current values in the column. Maximum number of indexes in a selection for calculating sum and average. Can be set to 0 for disabling the functionalities. 這是為了啟用一些高密度計算功能所å…許的項目最大數é‡ï¼š å•Ÿç”¨ä¾æ“šç›®å‰æ¬„ä½å€¼å®Œæˆæ•¸å€¼çš„表格所å…許的最大行數。 鏿“‡ç¯„åœä¸­ç”¨ä»¥è¨ˆç®—總和和平å‡å€¼çš„索引的最大數é‡ã€‚ å¯ä»¥è¨­å®šç‚º 0 以åœç”¨é€™äº›åŠŸèƒ½ã€‚ This is the maximum number of rows in a table for enabling the value completion based on current values in the column. Can be set to 0 for disabling completion. é€™æ˜¯ç‚ºäº†å•Ÿç”¨ä¾æ“šç›®å‰æ¬„ä½å€¼çš„自動完æˆåŠŸèƒ½æ‰€å…許的最大行數。 設定為 0 å¯ä»¥åœç”¨è‡ªå‹•完æˆåŠŸèƒ½ã€‚ Field display 欄ä½é¡¯ç¤º Light style 淺色風格 Displayed &text 顯示的文字(&T) Formatted 已格å¼åŒ– Click to set this color 點é¸ä»¥è¨­å®šæ­¤é¡è‰² Text color 文字é¡è‰² Background color 背景é¡è‰² Preview only (N/A) 僅é è¦½ï¼ˆä¸é©ç”¨ï¼‰ Foreground 剿™¯ Selection background 鏿“‡çš„背景 Selection foreground 鏿“‡çš„剿™¯ Highlight 醒目顯示 SQL &results font size SQL çµæžœå­—型大å°(&R) Use tabs for indentation 使用 Tab 進行縮排 When set, the Tab key will insert tab and space characters for indentation. Otherwise, just spaces will be used. 設定後,按下 Tab 鵿œƒç”¨ Tab å’Œç©ºæ ¼é€²è¡Œç¸®æŽ’ï¼›å¦‚æžœæœªè¨­å®šï¼Œå‰‡åªæœƒç”¨ç©ºæ ¼ä¾†ç¸®æŽ’。 &Wrap lines æ›è¡Œ(&W) Never æ°¸ä¸ At word boundaries 在字詞邊界 At character boundaries 在字元邊界 At whitespace boundaries 在空白邊界 &Quotes for identifiers 識別符號的引號(&Q) Choose the quoting mechanism used by the application for identifiers in SQL code. 鏿“‡æ‡‰ç”¨ç¨‹å¼åœ¨ SQL 程å¼ç¢¼ä¸­ç”¨æ–¼è­˜åˆ¥ç¬¦è™Ÿçš„引號機制。 "Double quotes" - Standard SQL (recommended) "雙引號" - 標準 SQL(推薦) `Grave accents` - Traditional MySQL quotes `é‡éŸ³ç¬¦è™Ÿ` - 傳統 MySQL 引號 [Square brackets] - Traditional MS SQL Server quotes [方括號] - 傳統 MS SQL Server 引號 Keywords in &UPPER CASE é—œéµå­—使用 &大寫 When set, the SQL keywords are completed in UPPER CASE letters. 當設定時,SQL é—œéµå­—將以大寫字æ¯å®Œæˆã€‚ When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background 當設定時,上次執行期間造æˆéŒ¯èª¤çš„ SQL 程å¼ç¢¼è¡Œå°‡è¢«é†’ç›®é¡¯ç¤ºï¼Œä¸¦ä¸”çµæžœæ¡†æž¶åœ¨èƒŒæ™¯ä¸­æŒ‡ç¤ºéŒ¯èª¤ Close button on tabs 分é ä¸Šçš„關閉按鈕 If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. 如果啟用,SQL 編輯器分é å°‡æœ‰ä¸€å€‹é—œé–‰æŒ‰éˆ•。無論如何,您都å¯ä»¥ä½¿ç”¨ä¸Šä¸‹æ–‡é¸å–®æˆ–éµç›¤å¿«é€Ÿéµä¾†é—œé–‰å®ƒå€‘。 &Extensions 擴充套件(&E) Select extensions to load for every database: 鏿“‡æ¯å€‹è³‡æ–™åº«è¦è¼‰å…¥çš„æ“´å……套件: Add extension 加入擴充套件 Remove extension 移除擴充套件 Select built-in extensions to load for every database: <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> <html><head/><body><p>é›–ç„¶ SQLite æ”¯æ´ REGEXP é‹ç®—å­ï¼Œä½†ä¸¦æœªå¯¦ä½œä»»ä½•æ­£è¦è¡¨é”å¼<br/>演算法,而是回呼正在執行的應用程å¼ã€‚DB Browser for SQLite 為您實作了此<br/>演算法,讓您å¯ä»¥ç›´æŽ¥ä½¿ç”¨ REGEXP。然而,由於此有多種å¯èƒ½çš„<br/>實作方å¼ï¼Œæ‚¨å¯èƒ½æƒ³è¦ä½¿ç”¨å¦ä¸€ç¨®ï¼Œæ‚¨å¯ä»¥è‡ªç”±åœ°åœç”¨<br/>應用程å¼çš„實作,並使用擴充套件載入您自己的實作。需è¦é‡æ–°å•Ÿå‹•應用程å¼ã€‚</p></body></html> Disable Regular Expression extension åœç”¨æ­£è¦è¡¨é”弿“´å……套件 <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> <html><head/><body><p>SQLite æä¾›äº†ä¸€å€‹ SQL 函å¼ï¼Œç”¨æ–¼å¾žå…±äº«å‡½å¼åº«æª”案載入擴充套件。如果您想è¦å¾ž SQL 程å¼ç¢¼ä½¿ç”¨ <span style=" font-style:italic;">load_extension()</span> 函å¼ï¼Œè«‹å•Ÿç”¨æ­¤é¸é …。</p><p>出於安全考é‡ï¼Œé è¨­æœƒé—œé–‰æ“´å……套件載入,必須é€éŽæ­¤è¨­å®šä¾†å•Ÿç”¨ã€‚å³ä½¿æ­¤é¸é …被åœç”¨ï¼Œæ‚¨ä»ç„¶å¯ä»¥é€éŽ GUI 載入擴充套件。</p></body></html> Allow loading extensions from SQL code å…許從 SQL 程å¼ç¢¼è¼‰å…¥æ“´å……套件 Remote é ç«¯ CA certificates CA 憑證 Proxy 代ç†ä¼ºæœå™¨ Configure 設定 Export Settings 匯出設定 Import Settings 匯入設定 Subject CN 主題 CN Common Name 一般å稱 Subject O 主體 O Organization 組織 Valid from 有效期é™å¾ž Valid to 有效期é™è‡³ Serial number åºè™Ÿ Your certificates 您的憑證 File 檔案 Subject Common Name 主體通用å稱 Issuer CN 簽發者 CN Issuer Common Name 簽發者通用å稱 Clone databases into 複製資料庫到 Choose a directory 鏿“‡ä¸€å€‹ç›®éŒ„ The language will change after you restart the application. 釿–°å•Ÿå‹•應用程å¼å¾Œï¼Œèªžè¨€å°‡æœƒè®Šæ›´ã€‚ Select extension file 鏿“‡æ“´å……套件檔案 Extensions(*.so *.dylib *.dll);;All files(*) 擴充套件(*.so *.dylib *.dll);;所有檔案(*) Import certificate file 匯入憑證檔案 No certificates found in this file. 在此檔案中未找到憑證。 Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! 您確定è¦ç§»é™¤æ­¤æ†‘證嗎?所有憑證資料將從應用程å¼è¨­å®šä¸­åˆªé™¤ï¼ Are you sure you want to clear all the saved settings? All your preferences will be lost and default values will be used. æ‚¨ç¢ºå®šè¦æ¸…除所有已儲存的設定嗎? 所有的å好設定將會éºå¤±ï¼Œä¸¦ä¸”將使用é è¨­å€¼ã€‚ Save Settings File 儲存設定檔 Initialization File (*.ini) åˆå§‹åŒ–檔案(*.ini) The settings file has been saved in location : 設定檔已儲存於以下ä½ç½®ï¼š Open Settings File 開啟設定檔 The settings file was loaded properly. 設定檔已正確載入。 The selected settings file is not a normal settings file. Please check again. 所é¸çš„è¨­å®šæª”ä¸¦éžæ­£å¸¸çš„設定檔。 è«‹å†æ¬¡æª¢æŸ¥ã€‚ ProxyDialog Proxy Configuration 代ç†ä¼ºæœå™¨è¨­å®š Pro&xy Type 代ç†ä¼ºæœå™¨é¡žåž‹ Host Na&me 主機å稱 Port 連接埠 Authentication Re&quired 需è¦é©—è­‰ &User Name 使用者å稱 Password 密碼 None ç„¡ System settings 系統設定 HTTP HTTP SOCKS5 SOCKS5 QObject Error importing data 匯入資料時發生錯誤 from record number %1 從記錄編號 %1 . %1 . %1 Importing CSV file... 正在匯入 CSV 檔案... Cancel å–æ¶ˆ All files (*) 所有檔案 (*) SQLite database files (*.db *.sqlite *.sqlite3 *.db3) SQLite 資料庫檔案 (*.db *.sqlite *.sqlite3 *.db3) Left é å·¦ Right é å³ Center 置中 Justify å·¦å³å°é½Š SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) SQLite 資料庫檔案 (*.db *.sqlite *.sqlite3 *.db3) DB Browser for SQLite Project Files (*.sqbpro) DB Browser for SQLite 專案檔案 (*.sqbpro) SQL Files (*.sql) SQL 檔案 (*.sql) All Files (*) 所有檔案 (*) Text Files (*.txt) 文字檔案 (*.txt) Comma-Separated Values Files (*.csv) 逗點分隔值檔案 (*.csv) Tab-Separated Values Files (*.tsv) 定ä½å­—元分隔值檔案 (*.tsv) Delimiter-Separated Values Files (*.dsv) 分隔符號分隔值檔案 (*.dsv) Concordance DAT files (*.dat) Concordance DAT 檔案 (*.dat) JSON Files (*.json *.js) JSON 檔案 (*.json *.js) XML Files (*.xml) XML 檔案 (*.xml) Binary Files (*.bin *.dat) äºŒé€²ä½æª”案 (*.bin *.dat) SVG Files (*.svg) SVG 檔案 (*.svg) Hex Dump Files (*.dat *.bin) å六進ä½è½‰å„²æª”案 (*.dat *.bin) Extensions (*.so *.dylib *.dll) 擴充套件 (*.so *.dylib *.dll) Initialization File (*.ini) åˆå§‹åŒ–檔案 (*.ini) QsciCommand Paste 貼上 Cancel å–æ¶ˆ QsciLexerCPP Default é è¨­ Keyword é—œéµå­— Identifier 識別符號 QsciLexerJSON Default é è¨­ String 字串 QsciLexerJavaScript Regular expression æ­£è¦è¡¨é”å¼ QsciLexerPython Default é è¨­ Comment 注釋 Keyword é—œéµå­— Identifier 識別符號 QsciLexerSQL Default é è¨­ Comment 注釋 Keyword é—œéµå­— Identifier 識別符號 QsciScintilla &Undo &復原 RemoteCommitsModel Commit ID æäº¤ ID Message è¨Šæ¯ Date 日期 Author 作者 Size å¤§å° Authored and committed by %1 ç”± %1 撰寫並æäº¤ Authored by %1, committed by %2 ç”± %1 撰寫,由 %2 æäº¤ RemoteDatabase Error opening local databases list. %1 開啟本機資料庫清單時發生錯誤。 %1 Error creating local databases list. %1 建立本機資料庫清單時發生錯誤。 %1 RemoteDock Remote é ç«¯ Identity 身份 Push currently opened database to server 將目å‰é–‹å•Ÿçš„資料庫推é€åˆ°ä¼ºæœå™¨ Upload 上傳 DBHub.io DBHub.io <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> <html><head/><body><p>åœ¨æ­¤é¢æ¿ä¸­ï¼Œæ‚¨å¯ä»¥å°‡ä¾†è‡ª dbhub.io 網站的é ç«¯è³‡æ–™åº«æ–°å¢žè‡³ DB Browser for SQLite。首先,您需è¦ä¸€å€‹èº«ä»½è­˜åˆ¥ï¼š</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">登入 dbhub.io 網站(å¯ä½¿ç”¨æ‚¨çš„ GitHub æ†‘è­‰æˆ–å…¶ä»–æ‚¨é¸æ“‡çš„æ–¹å¼ï¼‰</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">點é¸ã€Œç”¢ç”Ÿå®¢æˆ¶ç«¯æ†‘è­‰ã€æŒ‰éˆ•(這就是您的身份識別)。這會æä¾›æ‚¨ä¸€å€‹æ†‘證檔案(請將其儲存至您的本機ç£ç¢Ÿï¼‰</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">å‰å¾€ DB Browser for SQLite å好設定中的é ç«¯æ¨™ç±¤ã€‚é»žé¸æŒ‰éˆ•以將新的憑證新增至 DB Browser for SQLiteï¼Œä¸¦é¸æ“‡æ‚¨å‰›ä¸‹è¼‰çš„æ†‘證檔案。</li></ol><p>ç¾åœ¨ï¼Œé ç«¯é¢æ¿æœƒé¡¯ç¤ºæ‚¨çš„身份識別,您便å¯ä»¥æ–°å¢žé ç«¯è³‡æ–™åº«ã€‚</p></body></html> Local 本機 Current Database ç›®å‰çš„資料庫 Clone 複製 &User 使用者 &Database 資料庫(&D) Branch 分支 Commits æäº¤ Commits for æäº¤çµ¦ <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> <html><head/><body><p>æ‚¨ç›®å‰æ­£åœ¨ä½¿ç”¨å…§å»ºçš„唯讀身份。è¦ä¸Šå‚³æ‚¨çš„資料庫,您需è¦è¨­å®šä¸¦ä½¿ç”¨æ‚¨çš„ DBHub.io 帳戶。</p><p>還沒有 DBHub.io 帳戶嗎? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">ç¾åœ¨å°±å»ºç«‹ä¸€å€‹</span></a>,並將您的憑證匯入 <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">此處</span></a>,以分享您的資料庫。</p><p>如需線上支æ´ï¼Œè«‹é€ è¨ª <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">此處</span></a>。</p></body></html> Back 返回 Delete Database 刪除資料庫 Delete the local clone of this database 刪除此資料庫的本機複製 Open in Web Browser 在網é ç€è¦½å™¨ä¸­é–‹å•Ÿ Open the web page for the current database in your browser 在您的ç€è¦½å™¨ä¸­é–‹å•Ÿç›®å‰è³‡æ–™åº«çš„ç¶²é  Clone from Link 從連çµè¤‡è£½ Use this to download a remote database for local editing using a URL as provided on the web page of the database. 使用此功能,é€éŽè³‡æ–™åº«ç¶²é ä¸Šæä¾›çš„ URL 下載é ç«¯è³‡æ–™åº«é€²è¡Œæœ¬æ©Ÿç·¨è¼¯ã€‚ Refresh 釿–°æ•´ç† Reload all data and update the views 釿–°è¼‰å…¥æ‰€æœ‰è³‡æ–™ä¸¦æ›´æ–°æª¢è¦–表 Clone Database 複製資料庫 Open Database 開啟資料庫 Open the local copy of this database 開啟此資料庫的本機複製 Check out Commit 查看æäº¤ Download and open this specific commit 下載並開啟此特定æäº¤ Check out Latest Commit 查看最新æäº¤ Check out the latest commit of the current branch 查看目å‰åˆ†æ”¯çš„æœ€æ–°æäº¤ Save Revision to File 將修訂版本儲存到檔案 Saves the selected revision of the database to another file 將鏿“‡çš„資料庫修訂版本儲存到å¦ä¸€å€‹æª”案 Upload Database 上傳資料庫 Upload this database as a new commit 將此資料庫作為新的æäº¤ä¸Šå‚³ Select an identity to connect 鏿“‡ä¸€å€‹èº«ä»½é€²è¡Œé€£æŽ¥ Public 公開 This downloads a database from a remote server for local editing. Please enter the URL to clone from. You can generate this URL by clicking the 'Clone Database in DB4S' button on the web page of the database. 這將從é ç«¯ä¼ºæœå™¨ä¸‹è¼‰è³‡æ–™åº«é€²è¡Œæœ¬æ©Ÿç·¨è¼¯ã€‚ 請輸入è¦è¤‡è£½çš„ URL。您å¯ä»¥åœ¨è³‡æ–™åº«çš„ç¶²é ä¸Š 點é¸ã€Œåœ¨ DB4S ä¸­è¤‡è£½è³‡æ–™åº«ã€æŒ‰éˆ•來產生此 URL。 Invalid URL: The host name does not match the host name of the current identity. 無效的 URL:主機å稱與目å‰èº«ä»½çš„主機å稱ä¸ç¬¦ã€‚ Invalid URL: No branch name specified. 無效的 URL:未指定分支å稱。 Invalid URL: No commit ID specified. 無效的 URL:未指定æäº¤ ID。 You have modified the local clone of the database. Fetching this commit overrides these local changes. Are you sure you want to proceed? 您已修改資料庫的本機複製版本。å–得這個æäº¤å°‡è¦†è“‹é€™äº›æœ¬æ©Ÿä¿®æ”¹ã€‚ 您確定è¦ç¹¼çºŒå—Žï¼Ÿ The database has unsaved changes. Are you sure you want to push it before saving? 資料庫有未儲存的變更。您確定è¦åœ¨å„²å­˜ä¹‹å‰æŽ¨é€å®ƒå—Žï¼Ÿ The database you are trying to delete is currently opened. Please close it before deleting. 您嘗試刪除的資料庫目å‰å·²é–‹å•Ÿã€‚請在刪除之å‰é—œé–‰å®ƒã€‚ This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? 這將刪除此資料庫的本機版本,包括所有您尚未æäº¤çš„變更。您確定è¦åˆªé™¤æ­¤è³‡æ–™åº«å—Žï¼Ÿ RemoteLocalFilesModel Name å稱 Branch 分支 Last modified 最後修改 Size å¤§å° Commit æäº¤ File 檔案 RemoteModel Name å稱 Commit æäº¤ Last modified 最後修改 Size å¤§å° Size: 大å°ï¼š Last Modified: 最後修改: Licence: 授權: Default Branch: é è¨­åˆ†æ”¯ï¼š RemoteNetwork Choose a location to save the file 鏿“‡å„²å­˜æª”案的ä½ç½® Error opening remote file at %1. %2 開啟é ç«¯æª”案 %1 錯誤。 %2 Error: Invalid client certificate specified. 錯誤:指定的客戶端憑證無效。 Please enter the passphrase for this client certificate in order to authenticate. 請輸入此客戶端憑證的密碼以進行驗證。 Cancel å–æ¶ˆ Uploading remote database to %1 正在上傳é ç«¯è³‡æ–™åº«åˆ° %1 Downloading remote database from %1 正在從 %1 下載é ç«¯è³‡æ–™åº« Error: Cannot open the file for sending. 錯誤:無法開啟è¦å‚³é€çš„æª”案。 RemotePushDialog Push database 推é€è³‡æ–™åº« Database na&me to push to è¦æŽ¨é€çš„資料庫å稱 Commit message æäº¤è¨Šæ¯ Database licence 資料庫授權 Public 公開 Branch 分支 Force push å¼·åˆ¶æŽ¨é€ Username 使用者å稱 Database will be public. Everyone has read access to it. 資料庫將會公開。æ¯å€‹äººéƒ½æœ‰è®€å–權é™ã€‚ Database will be private. Only you have access to it. è³‡æ–™åº«å°‡æœƒç§æœ‰åŒ–ã€‚åªæœ‰æ‚¨æœ‰å­˜å–權é™ã€‚ Use with care. This can cause remote commits to be deleted. è«‹å°å¿ƒä½¿ç”¨ã€‚這å¯èƒ½æœƒå°Žè‡´é ç«¯çš„æäº¤è¢«åˆªé™¤ã€‚ RunSql Execution aborted by user 使用者已中止執行 , %1 rows affected ,影響了 %1 行 query executed successfully. Took %1ms%2 查詢æˆåŠŸåŸ·è¡Œã€‚èŠ±è²»äº† %1ms%2 executing query 正在執行查詢 SelectItemsPopup A&vailable å¯ç”¨çš„ Sele&cted 已鏿“‡çš„ SqlExecutionArea Form 表單 Find previous match [Shift+F3] 尋找å‰ä¸€å€‹ç¬¦åˆ [Shift+F3] Find previous match with wrapping 尋找上一個符åˆä¸¦æ›è¡Œ Shift+F3 Shift+F3 The found pattern must be a whole word æœå°‹åˆ°çš„字串必須是一個完整的單詞 Whole Words 完整單詞 Text pattern to find considering the checks in this frame è€ƒæ…®æ­¤æ¡†æž¶ä¸­çš„æª¢æŸ¥ä¾†å°‹æ‰¾æ–‡å­—æ¨¡å¼ Find in editor 在編輯器中尋找 The found pattern must match in letter case æœå°‹åˆ°çš„字串必須符åˆå¤§å°å¯« Case Sensitive å€åˆ†å¤§å°å¯« Find next match [Enter, F3] å°‹æ‰¾ä¸‹ä¸€å€‹ç¬¦åˆ [Enter, F3] Find next match with wrapping 尋找下一個符åˆä¸¦æ›è¡Œ F3 F3 Interpret search pattern as a regular expression å°‡æœå°‹æ¨¡å¼è§£é‡‹ç‚ºæ­£è¦è¡¨é”å¼ <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>ç•¶é¸å–時,將尋找的模å¼è§£é‡‹ç‚º UNIX æ­£è¦è¡¨é”å¼ã€‚è«‹åƒè¦‹ <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Wikibooks 中的正è¦è¡¨é”å¼</a>。</p></body></html> Regular Expression æ­£è¦è¡¨é”å¼ Close Find Bar 關閉尋找工具列 <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> <html><head/><body><p>最後執行陳述å¼çš„çµæžœã€‚</p><p>您å¯èƒ½æƒ³è¦æ‘ºç–Šæ­¤é¢æ¿ï¼Œä¸¦ä½¿ç”¨ <span style=" font-style:italic;">SQL 日誌</span> ç¢¼é ­ï¼Œä¸¦é¸æ“‡ <span style=" font-style:italic;">使用者</span>。</p></body></html> Results of the last executed statements 最後執行陳述å¼çš„çµæžœ This field shows the results and status codes of the last executed statements. 此欄ä½é¡¯ç¤ºæœ€å¾ŒåŸ·è¡Œçš„陳述å¼çš„çµæžœå’Œç‹€æ…‹ç¢¼ã€‚ Ctrl+PgUp Ctrl+PgUp Ctrl+PgDown Ctrl+PgDown Couldn't read file "%1": %2. ç„¡æ³•è®€å–æª”案「%1ã€ï¼š%2。 Couldn't save file: %1. 無法儲存檔案:%1。 Your changes will be lost when reloading it! 釿–°è¼‰å…¥æ™‚,您的變更將會éºå¤±ï¼ The file "%1" was modified by another program. Do you want to reload it?%2 檔案「%1ã€å·²è¢«å…¶ä»–程å¼ä¿®æ”¹ã€‚您è¦é‡æ–°è¼‰å…¥å—Žï¼Ÿ%2 Answer "Yes to All" to reload the file on any external update without further prompting. 回答「全部皆是ã€ä»¥åœ¨ä»»ä½•å¤–éƒ¨æ›´æ–°æ™‚ç„¡éœ€å†æ¬¡æç¤ºä¾¿é‡æ–°è¼‰å…¥æª”案。 Answer "No to All" to ignore any external update without further prompting. 回答「全部皆å¦ã€ä»¥åœ¨ä»»ä½•å¤–éƒ¨æ›´æ–°æ™‚ç„¡éœ€å†æ¬¡æç¤ºä¾¿å¿½ç•¥ã€‚ Modifying and saving the file will restore prompting. 修改並儲存檔案將會æ¢å¾©æç¤ºã€‚ SqlTextEdit Ctrl+/ Ctrl+/ SqlUiLexer (X) The abs(X) function returns the absolute value of the numeric argument X. (X) abs(X) 函å¼å›žå‚³æ•¸å€¼åƒæ•¸ X 的絕å°å€¼ã€‚ () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. () changes() 函å¼å›žå‚³æœ€è¿‘完æˆçš„ INSERTã€DELETE 或 UPDATE é™³è¿°å¼æ‰€è®Šæ›´ã€æ’入或刪除的資料庫列數。 (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. (X1,X2,...) char(X1,X2,...,XN) 函å¼å›žå‚³ä¸€å€‹å­—串,該字串由具有整數 X1 到 XN çš„ unicode 碼點值的字元組æˆã€‚ (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL (X,Y,...) coalesce() 函å¼å›žå‚³å…¶ç¬¬ä¸€å€‹éž NULL åƒæ•¸çš„å‰¯æœ¬ï¼Œå¦‚æžœæ‰€æœ‰åƒæ•¸éƒ½æ˜¯ NULL 則回傳 NULL (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". (X,Y) glob(X,Y) 函å¼ç­‰åŒæ–¼è¡¨é”å¼ã€ŒY GLOB Xã€ã€‚ (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. (X,Y) ifnull() 函å¼å›žå‚³å…¶ç¬¬ä¸€å€‹éž NULL åƒæ•¸çš„å‰¯æœ¬ï¼Œå¦‚æžœå…©å€‹åƒæ•¸éƒ½æ˜¯ NULL 則回傳 NULL。 (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. (X,Y) instr(X,Y) 函å¼åœ¨å­—串 X 中找到字串 Y 的第一個出ç¾è™•,並回傳å‰é¢å­—元的數é‡åŠ  1,如果在 X 中找ä¸åˆ° Y 則回傳 0。 (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. (X) hex() 函å¼å°‡å…¶åƒæ•¸è§£é‡‹ç‚º BLOB,並回傳該 BLOB 內容的大寫å六進ä½å‘ˆç¾çš„字串。 (X,Y,Z) The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. (X,Y,Z) iif(X,Y,Z) 函å¼å¦‚æžœ X 為真,則回傳值 Y,å¦å‰‡å›žå‚³ Z。 () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. () last_insert_rowid() 函å¼å›žå‚³å¾žå‘¼å«è©²å‡½å¼çš„資料庫連線æ’入的最後一列的 ROWID。 (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. (X) å°æ–¼å­—串值 X,length(X) 函å¼å›žå‚³ X 中第一個 NUL 字元之å‰çš„字元數é‡ï¼ˆä¸æ˜¯ä½å…ƒçµ„)。 (X,Y) The like() function is used to implement the "Y LIKE X" expression. (X,Y) like() 函å¼ç”¨æ–¼å¯¦ç¾ã€ŒY LIKE Xã€è¡¨é”å¼ã€‚ (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. (X,Y,Z) like() 函å¼ç”¨æ–¼å¯¦ç¾ã€ŒY LIKE X ESCAPE Zã€è¡¨é”å¼ã€‚ (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. Use of this function must be authorized from Preferences. (X) load_extension(X) 函å¼å¾žå為 X 的共享函å¼åº«æª”案中載入 SQLite 擴充功能。 必須從å好設定中授權使用此函å¼ã€‚ (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. Use of this function must be authorized from Preferences. (X,Y) load_extension(X) 函å¼ä½¿ç”¨å…¥å£é»ž Y 從å為 X 的共享函å¼åº«æª”案中載入 SQLite 擴充功能。 必須從å好設定中授權使用此函å¼ã€‚ (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. (X) lower(X) 函å¼å›žå‚³ä¸€å€‹å­—串 X 的副本,其中所有 ASCII 字元都轉æ›ç‚ºå°å¯«ã€‚ (X) ltrim(X) removes spaces from the left side of X. (X) ltrim(X) 從 X 的左å´ç§»é™¤ç©ºæ ¼ã€‚ (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. (X,Y) ltrim(X,Y) 函å¼å›žå‚³ä¸€å€‹å­—串,該字串由從 X 的左å´ç§»é™¤åœ¨ Y 中出ç¾çš„任何和所有字元形æˆã€‚ (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. (X,Y,...) å¤šåƒæ•¸ max() 函å¼å›žå‚³å…·æœ‰æœ€å¤§å€¼çš„åƒæ•¸ï¼Œå¦‚æžœä»»ä½•åƒæ•¸ç‚º NULL 則回傳 NULL。 (X,Y,...) The multi-argument min() function returns the argument with the minimum value. (X,Y,...) å¤šåƒæ•¸ min() 函å¼å›žå‚³å…·æœ‰æœ€å°å€¼çš„åƒæ•¸ã€‚ (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. (X,Y) nullif(X,Y) 函å¼å¦‚æžœåƒæ•¸ä¸åŒå‰‡å›žå‚³å…¶ç¬¬ä¸€å€‹åƒæ•¸ï¼Œå¦‚æžœåƒæ•¸ç›¸åŒå‰‡å›žå‚³ NULL。 (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. (FORMAT,...) printf(FORMAT,...) SQL 函å¼çš„工作方å¼é¡žä¼¼æ–¼ C èªžè¨€å‡½å¼ sqlite3_mprintf() 和標準 C 函å¼åº«çš„ printf() 函å¼ã€‚ (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. (X) quote(X) 函å¼å›žå‚³ä¸€å€‹ SQL å­—é¢å€¼çš„æ–‡å­—,該值é©åˆåŒ…å«åˆ° SQL 陳述å¼ä¸­ã€‚ () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. () random() 函å¼å›žå‚³ä¸€å€‹ä»‹æ–¼ -9223372036854775808 å’Œ +9223372036854775807 之間的å½éš¨æ©Ÿæ•´æ•¸ã€‚ (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. (N) randomblob(N) 函å¼å›žå‚³ä¸€å€‹åŒ…å«å½éš¨æ©Ÿä½å…ƒçµ„çš„ N ä½å…ƒçµ„ blob。 (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. (X,Y,Z) replace(X,Y,Z) 函å¼å›žå‚³ä¸€å€‹å­—串,該字串由在字串 X 中的æ¯å€‹å­—串 Y 出ç¾è™•å–代為字串 Z å½¢æˆã€‚ (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. (X) round(X) 函å¼å›žå‚³ä¸€å€‹æµ®é»žå€¼ X,該值四æ¨äº”å…¥åˆ°å°æ•¸é»žå³é‚Šçš„零使•¸ã€‚ (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. (X,Y) round(X,Y) 函å¼å›žå‚³ä¸€å€‹æµ®é»žå€¼ X,該值四æ¨äº”å…¥åˆ°å°æ•¸é»žå³é‚Šçš„ Y 使•¸ã€‚ (X) rtrim(X) removes spaces from the right side of X. (X) rtrim(X) 從 X çš„å³å´ç§»é™¤ç©ºæ ¼ã€‚ (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. (X,Y) rtrim(X,Y) 函å¼å›žå‚³ä¸€å€‹å­—串,該字串由從 X çš„å³å´ç§»é™¤åœ¨ Y 中出ç¾çš„任何和所有字元形æˆã€‚ (X) The soundex(X) function returns a string that is the soundex encoding of the string X. (X) soundex(X) 函å¼å›žå‚³ä¸€å€‹å­—串,該字串是字串 X çš„ soundex 編碼。 (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. (X,Y) substr(X,Y) 回傳從字串 X çš„ Y-th é–‹å§‹åˆ°çµæŸçš„æ‰€æœ‰å­—元。 (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. (X,Y,Z) substr(X,Y,Z) 函å¼å›žå‚³è¼¸å…¥å­—串 X 的一個å­å­—串,該å­å­—串從 Y-th 字元開始,並且長度為 Z 字元。 () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. () total_changes() 函å¼å›žå‚³è‡ªå¾žç›®å‰çš„資料庫連線被開啟以來,由 INSERTã€UPDATE 或 DELETE é™³è¿°å¼æ‰€é€ æˆçš„資料列變更數é‡ã€‚ (X) trim(X) removes spaces from both ends of X. (X) trim(X) 從 X 的兩端移除空格。 (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. (X,Y) trim(X,Y) 函å¼å›žå‚³ä¸€å€‹å­—串,該字串由從 X 的兩端移除在 Y 中出ç¾çš„任何和所有字元形æˆã€‚ (X) The typeof(X) function returns a string that indicates the datatype of the expression X. (X) typeof(X) 函å¼å›žå‚³ä¸€å€‹å­—串,該字串指示表é”å¼ X 的資料類型。 (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. (X) unicode(X) 函å¼å›žå‚³èˆ‡å­—串 X çš„ç¬¬ä¸€å€‹å­—å…ƒç›¸å°æ‡‰çš„æ•¸å€¼ unicode 碼點。 (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. (X) upper(X) 函å¼å›žå‚³ä¸€å€‹è¼¸å…¥å­—串 X 的副本,其中所有å°å¯« ASCII 字元都轉æ›ç‚ºå…¶å¤§å¯«ç­‰æ•ˆå­—元。 (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. (N) zeroblob(N) 函å¼å›žå‚³ä¸€å€‹ç”± N ä½å…ƒçµ„çš„ 0x00 組æˆçš„ BLOB。 (timestring,modifier,modifier,...) (時間字串,修飾符,修飾符,...) (format,timestring,modifier,modifier,...) (æ ¼å¼,時間字串,修飾符,修飾符,...) (X) The avg() function returns the average value of all non-NULL X within a group. (X) avg() 函å¼å›žå‚³ç¾¤çµ„å…§æ‰€æœ‰éž NULL X 的平å‡å€¼ã€‚ (X) The count(X) function returns a count of the number of times that X is not NULL in a group. (X) count(X) 函å¼å›žå‚³ç¾¤çµ„å…§ X ä¸ç‚º NULL 的次數。 (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. (X) group_concat() 函å¼å›žå‚³ä¸€å€‹å­—ä¸²ï¼Œè©²å­—ä¸²æ˜¯æ‰€æœ‰éž NULL X 值的連接。 (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. (X,Y) group_concat() 函å¼å›žå‚³ä¸€å€‹å­—ä¸²ï¼Œè©²å­—ä¸²æ˜¯æ‰€æœ‰éž NULL X å€¼çš„é€£æŽ¥ã€‚å¦‚æžœå­˜åœ¨åƒæ•¸ Y,則將其用作 X 實例之間的分隔符。 (X) The max() aggregate function returns the maximum value of all values in the group. (X) max() èšåˆå‡½å¼å›žå‚³ç¾¤çµ„中所有值的最大值。 (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. (X) min() èšåˆå‡½å¼å›žå‚³ç¾¤çµ„中所有值的最å°éž NULL 值。 (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. (X) sum() å’Œ total() èšåˆå‡½å¼å›žå‚³ç¾¤çµ„ä¸­æ‰€æœ‰éž NULL 值的總和。 () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. () ç›®å‰åˆ†å€å…§çš„列數。列的編號從 1 開始,按照視窗定義中的 ORDER BY å­å¥æ‰€å®šç¾©çš„é †åºï¼Œæˆ–者以其他任æ„é †åºã€‚ () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () æ¯å€‹ç¾¤çµ„中第一個å°ç­‰çš„ row_number() - ç›®å‰åˆ—çš„æŽ’åæœ‰é–“隔。如果沒有 ORDER BY å­å¥ï¼Œå‰‡æ‰€æœ‰åˆ—都被視為å°ç­‰ï¼Œæ­¤å‡½å¼å§‹çµ‚回傳 1。 () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. () ç›®å‰åˆ—çš„å°ç­‰ç¾¤çµ„在其分å€å…§çš„æ•¸é‡ - ç›®å‰åˆ—çš„æŽ’åæ²’有間隔。分å€çš„編號從 1 開始,按照視窗定義中的 ORDER BY å­å¥æ‰€å®šç¾©çš„é †åºã€‚如果沒有 ORDER BY å­å¥ï¼Œå‰‡æ‰€æœ‰åˆ—都被視為å°ç­‰ï¼Œæ­¤å‡½å¼å§‹çµ‚回傳 1。 () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. () 儘管å稱如此,此函å¼ç¸½æ˜¯å›žå‚³ä¸€å€‹ä»‹æ–¼ 0.0 å’Œ 1.0 之間的值,該值等於 (rank - 1)/(partition-rows - 1),其中 rank æ˜¯å…§å»ºè¦–çª—å‡½å¼ rank() 回傳的值,partition-rows 是分å€ä¸­çš„總列數。如果分å€åªåŒ…å«ä¸€åˆ—,此函å¼å›žå‚³ 0.0。 () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. () ç´¯ç©åˆ†ä½ˆã€‚計算為 row-number/partition-rows,其中 row-number 是 row_number() 為群組中的最後一個å°ç­‰å›žå‚³çš„值,partition-rows 是分å€ä¸­çš„列數。 (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. (N) åƒæ•¸ N 被處ç†ç‚ºæ•´æ•¸ã€‚此函å¼å°‡åˆ†å€åŠƒåˆ†ç‚º N 個群組,盡å¯èƒ½å‡å‹»ï¼Œä¸¦æŒ‰ç…§ ORDER BY å­å¥å®šç¾©çš„é †åºï¼Œæˆ–者以其他任æ„é †åºï¼Œå°‡ 1 到 N 之間的整數分é…給æ¯å€‹ç¾¤çµ„。如果需è¦ï¼Œè¼ƒå¤§çš„群組先出ç¾ã€‚此函å¼å›žå‚³åˆ†é…給目å‰åˆ—所屬的群組的整數值。 (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. (expr) 回傳å°åˆ†å€ä¸­çš„å‰ä¸€åˆ—評估表é”å¼ expr çš„çµæžœã€‚或者,如果沒有å‰ä¸€åˆ—(因為目å‰åˆ—是第一列),則為 NULL。 (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. (expr,offset) 如果æä¾›äº† offset åƒæ•¸ï¼Œå‰‡å®ƒå¿…須是éžè² æ•´æ•¸ã€‚在這種情æ³ä¸‹ï¼Œå›žå‚³çš„值是å°åˆ†å€ä¸­çš„ç›®å‰åˆ—之å‰çš„ offset 列評估 expr çš„çµæžœã€‚如果 offset 為 0,則å°ç›®å‰åˆ—è©•ä¼° expr。如果目å‰åˆ—之剿²’有 offset 列,則回傳 NULL。 (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. (expr,offset,default) 如果也æä¾›äº† default,則如果由 offset 標識的資料列ä¸å­˜åœ¨ï¼Œå‰‡å›žå‚³ default è€Œä¸æ˜¯ NULL。 (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. (expr) 回傳å°åˆ†å€ä¸­çš„下一列評估表é”å¼ expr çš„çµæžœã€‚或者,如果沒有下一列(因為目å‰åˆ—是最後一列),則為 NULL。 (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. (expr,offset) 如果æä¾›äº† offset åƒæ•¸ï¼Œå‰‡å®ƒå¿…須是éžè² æ•´æ•¸ã€‚在這種情æ³ä¸‹ï¼Œå›žå‚³çš„值是å°åˆ†å€ä¸­çš„ç›®å‰åˆ—之後的 offset 列評估 expr çš„çµæžœã€‚如果 offset 為 0,則å°ç›®å‰åˆ—è©•ä¼° expr。如果目å‰åˆ—之後沒有 offset 列,則回傳 NULL。 (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. (expr) 這個內建視窗函å¼ä»¥èˆ‡èšåˆè¦–窗函å¼ç›¸åŒçš„æ–¹å¼è¨ˆç®—æ¯ä¸€åˆ—çš„è¦–çª—æ¡†æž¶ã€‚å®ƒå›žå‚³å°æ¯ä¸€åˆ—的視窗框架中的第一列評估 expr 的值。 (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. (expr) 這個內建視窗函å¼ä»¥èˆ‡èšåˆè¦–窗函å¼ç›¸åŒçš„æ–¹å¼è¨ˆç®—æ¯ä¸€åˆ—çš„è¦–çª—æ¡†æž¶ã€‚å®ƒå›žå‚³å°æ¯ä¸€åˆ—的視窗框架中的最後一列評估 expr 的值。 (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. (expr,N) 這個內建視窗函å¼ä»¥èˆ‡èšåˆè¦–窗函å¼ç›¸åŒçš„æ–¹å¼è¨ˆç®—æ¯ä¸€åˆ—的視窗框架。它回傳å°è¦–窗框架的第 N 列評估 expr 的值。如果存在 ORDER BY å­å¥ï¼Œå‰‡è¦–窗框架內的資料列從 1 開始編號,按照由 ORDER BY å­å¥å®šç¾©çš„é †åºï¼Œæˆ–者以其他任æ„é †åºã€‚如果分å€ä¸­æ²’有第 N 列,則回傳 NULL。 (X) Return the arccosine of X. The result is in radians. (X) 回傳 X çš„åé¤˜å¼¦å€¼ã€‚çµæžœä»¥å¼§åº¦ç‚ºå–®ä½ã€‚ (X) Return the hyperbolic arccosine of X. (X) 回傳 X 的雙曲å餘弦值。 (X) Return the arcsine of X. The result is in radians. (X) 回傳 X çš„åæ­£å¼¦å€¼ã€‚çµæžœä»¥å¼§åº¦ç‚ºå–®ä½ã€‚ (X) Return the hyperbolic arcsine of X. (X) 回傳 X çš„é›™æ›²åæ­£å¼¦å€¼ã€‚ (X) Return the arctangent of X. The result is in radians. (X) 回傳 X çš„åæ­£åˆ‡å€¼ã€‚çµæžœä»¥å¼§åº¦ç‚ºå–®ä½ã€‚ (X,Y) Return the arctangent of Y/X. The result is in radians. The result is placed into correct quadrant depending on the signs of X and Y. (X,Y) 回傳 Y/X çš„åæ­£åˆ‡å€¼ã€‚çµæžœä»¥å¼§åº¦ç‚ºå–®ä½ã€‚çµæžœæœƒæ ¹æ“š X å’Œ Y 的符號放在正確的象é™ã€‚ (X) Return the hyperbolic arctangent of X. (X) 回傳 X çš„é›™æ›²åæ­£åˆ‡å€¼ã€‚ (X) Return the first representable integer value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. (X) 回傳大於或等於 X 的第一個å¯è¡¨ç¤ºçš„æ•´æ•¸å€¼ã€‚å°æ–¼ X çš„æ­£å€¼ï¼Œæ­¤å‡½å¼æœƒé é›¢é›¶é€²ä½ã€‚å°æ–¼ X çš„è² å€¼ï¼Œæ­¤å‡½å¼æœƒæœå‘零進ä½ã€‚ (X) Return the cosine of X. X is in radians. (X) 回傳 X 的餘弦值。X 以弧度為單ä½ã€‚ (X) Return the hyperbolic cosine of X. (X) 回傳 X 的雙曲餘弦值。 (X) Convert value X from radians into degrees. (X) å°‡ X 從弧度轉æ›ç‚ºåº¦ã€‚ (X) Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. (X) 計算 eï¼ˆæ­æ‹‰æ•¸ï¼Œç´„為 2.71828182845905)的 X 次方。 (X) Return the first representable integer value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. (X) å›žå‚³å°æ–¼æˆ–等於 X 的第一個å¯è¡¨ç¤ºçš„æ•´æ•¸å€¼ã€‚å°æ–¼æ­£æ•¸ï¼Œæ­¤å‡½å¼æœƒæœå‘零進ä½ã€‚å°æ–¼è² æ•¸ï¼Œæ­¤å‡½å¼æœƒé é›¢é›¶é€²ä½ã€‚ (X) Return the natural logarithm of X. (X) 回傳 X çš„è‡ªç„¶å°æ•¸ã€‚ (B,X) Return the base-B logarithm of X. (B,X) 回傳以 B 為底的 X çš„å°æ•¸ã€‚ (X) Return the base-10 logarithm for X. (X) 回傳以 10 為底的 X çš„å°æ•¸ã€‚ (X) Return the logarithm base-2 for the number X. (X) 回傳以 2 為底的 X çš„å°æ•¸ã€‚ (X,Y) Return the remainder after dividing X by Y. (X,Y) 回傳 X 除以 Y 的餘數。 () Return an approximation for Ï€. () 回傳 Ï€ 的近似值。 (X,Y) Compute X raised to the power Y. (X,Y) 計算 X çš„ Y 次方。 (X) Convert X from degrees into radians. (X) å°‡ X 從度數轉æ›ç‚ºå¼§åº¦ã€‚ (X) Return the sine of X. X is in radians. (X) 回傳 X 的正弦值。X 是以弧度為單ä½ã€‚ (X) Return the hyperbolic sine of X. (X) 回傳 X 的雙曲正弦值。 (X) Return the square root of X. NULL is returned if X is negative. (X) 回傳 X 的平方根。如果 X 是負數,則回傳 NULL。 (X) Return the tangent of X. X is in radians. (X) 回傳 X 的正切值。X 是以弧度為單ä½ã€‚ (X) Return the hyperbolic tangent of X. (X) 回傳 X 的雙曲正切值。 (X) Return the representable integer in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the integer part of X, rounding toward zero. (X) 回傳介於 X å’Œ 0(包å«ï¼‰ä¹‹é–“ã€è·é›¢é›¶æœ€é çš„å¯è¡¨ç¤ºæ•´æ•¸ã€‚æ›å¥è©±èªªï¼Œå›žå‚³ X 的整數部分,四æ¨äº”å…¥æœå‘零。 SqliteTableModel reading rows æ­£åœ¨è®€å–æ¬„ä½ loading... 正在載入... References %1(%2) Hold %3Shift and click to jump there åƒè€ƒ %1(%2) æŒ‰ä½ %3Shift 並點é¸ä»¥è·³è‡³è©²è™• Error changing data: %1 變更資料時出ç¾éŒ¯èª¤ï¼š %1 retrieving list of columns æ­£åœ¨æ“·å–æ¬„使¸…å–® Fetching data... 正在擷å–資料... Cancel å–æ¶ˆ TableBrowser Browse Data ç€è¦½è³‡æ–™ &Table: &資料表: Select a table to browse data 鏿“‡ä¸€å€‹è³‡æ–™è¡¨ä»¥ç€è¦½è³‡æ–™ Use this list to select a table to be displayed in the database view ä½¿ç”¨é€™å€‹æ¸…å–®é¸æ“‡ä¸€å€‹è¦é¡¯ç¤ºåœ¨è³‡æ–™åº«æª¢è¦–中的資料表 This is the database table view. You can do the following actions: - Start writing for editing inline the value. - Double-click any record to edit its contents in the cell editor window. - Alt+Del for deleting the cell content to NULL. - Ctrl+" for duplicating the current record. - Ctrl+' for copying the value from the cell above. - Standard selection and copy/paste operations. 這是資料庫表格檢視。您å¯ä»¥é€²è¡Œä»¥ä¸‹æ“作: - 開始編輯值。 - 點é¸å…©ä¸‹ä»»ä½•記錄以在儲存格編輯器視窗中編輯其內容。 - Alt+Del 以將儲存格內容刪除為 NULL。 - Ctrl+" 以複製目å‰è¨˜éŒ„。 - Ctrl+' 以從上方儲存格複製值。 - æ¨™æº–é¸æ“‡å’Œè¤‡è£½/貼上æ“作。 Text pattern to find considering the checks in this frame è€ƒæ…®æ­¤æ¡†æž¶ä¸­çš„æª¢æŸ¥ä¾†å°‹æ‰¾çš„æ–‡å­—æ¨¡å¼ Find in table 在表格中尋找 Find previous match [Shift+F3] 尋找å‰ä¸€å€‹ç¬¦åˆ [Shift+F3] Find previous match with wrapping 尋找å‰ä¸€å€‹ç¬¦åˆä¸¦æ›è¡Œ Shift+F3 Shift+F3 Find next match [Enter, F3] å°‹æ‰¾ä¸‹ä¸€å€‹ç¬¦åˆ [Enter, F3] Find next match with wrapping 尋找下一個符åˆä¸¦æ›è¡Œ F3 F3 The found pattern must match in letter case æœå°‹åˆ°çš„字串必須符åˆå¤§å°å¯« Case Sensitive å€åˆ†å¤§å°å¯« The found pattern must be a whole word æœå°‹åˆ°çš„字串必須是一個完整的單詞 Whole Cell 整個儲存格 Interpret search pattern as a regular expression å°‡æœå°‹æ¨¡å¼è§£é‡‹ç‚ºæ­£è¦è¡¨é”å¼ <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> <html><head/><body><p>勾鏿™‚,將會將尋找的模å¼è§£é‡‹ç‚º UNIX æ­£è¦è¡¨é”å¼ã€‚è«‹åƒè¦‹ <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Wikibooks 中的正è¦è¡¨é”å¼</a>。</p></body></html> Regular Expression æ­£è¦è¡¨é”å¼ Close Find Bar 關閉尋找工具列 Text to replace with è¦å–代的文字 Replace with å–代為 Replace next match å–ä»£ä¸‹ä¸€å€‹ç¬¦åˆ Replace å–代 Replace all matches å–ä»£æ‰€æœ‰ç¬¦åˆ Replace all 全部å–代 Export to &JSON 匯出為 &JSON Export the filtered data to JSON 將篩é¸å¾Œçš„資料匯出為 JSON This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a JSON file. 此按鈕會將目å‰é¡¯ç¤ºçš„ç€è¦½è¡¨æ ¼è³‡æ–™ï¼ˆç¶“éŽç¯©é¸ã€é¡¯ç¤ºæ ¼å¼å’ŒæŽ’åºåˆ—)匯出為 JSON 檔案。 Copy column name 複製欄ä½å稱 Copy the database table column name to your clipboard 將資料庫表格的欄ä½å稱複製到剪貼簿 New Data Browser 新資料ç€è¦½å™¨ Add a new docked Data Browser 新增一個固定的資料ç€è¦½å™¨ This button adds a new docked Data Browser, which you can detach and arrange in different layouts. 這個按鈕å¯ä»¥æ–°å¢žä¸€å€‹å›ºå®šçš„資料ç€è¦½å™¨ï¼Œæ‚¨å¯ä»¥å°‡å…¶è§£é™¤å›ºå®šä¸¦åœ¨ä¸åŒçš„é…ç½®ä¸­é‡æ–°æŽ’列。 <html><head/><body><p>Scroll to the beginning</p></body></html> <html><head/><body><p>æ²å‹•到開始</p></body></html> <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> <html><head/><body><p>é»žé¸æ­¤æŒ‰éˆ•會在上方的資料表中移至開始。</p></body></html> |< |< Scroll one page upwards å‘上æ²å‹•ä¸€é  <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> <html><head/><body><p>é»žé¸æ­¤æŒ‰éˆ•會在上方的資料表中å‘上移動一é è¨˜éŒ„。</p></body></html> < < 0 - 0 of 0 0 - 0 / 0 Scroll one page downwards å‘下æ²å‹•ä¸€é  <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> <html><head/><body><p>é»žé¸æ­¤æŒ‰éˆ•會在上方的資料表中å‘下移動一é è¨˜éŒ„。</p></body></html> > > Scroll to the end æ²å‹•到末端 <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> <html><head/><body><p>é»žé¸æ­¤æŒ‰éˆ•會在上方的資料表中移至末端。</p></body></html> >| >| <html><head/><body><p>Click here to jump to the specified record</p></body></html> <html><head/><body><p>點é¸é€™è£¡ä»¥è·³è½‰è‡³æŒ‡å®šçš„記錄</p></body></html> <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> <html><head/><body><p>這個按鈕用於移至「跳轉到ã€å€åŸŸä¸­æŒ‡å®šçš„記錄編號。</p></body></html> Go to: 跳轉到: Enter record number to browse 輸入è¦ç€è¦½çš„記錄編號 Type a record number in this area and click the Go to: button to display the record in the database view 在這個å€åŸŸä¸­è¼¸å…¥ä¸€å€‹è¨˜éŒ„編號,並點é¸ã€Œè·³è½‰åˆ°:ã€æŒ‰éˆ•以在資料庫檢視中顯示記錄 1 1 Show rowid column 顯示 rowid 列 Toggle the visibility of the rowid column åˆ‡æ› rowid 欄ä½çš„å¯è¦‹åº¦ Unlock view editing 解鎖檢視表編輯 This unlocks the current view for editing. However, you will need appropriate triggers for editing. 這將解鎖目å‰çš„æª¢è¦–表以進行編輯。然而,您將需è¦é©ç•¶çš„觸發器來進行編輯。 Edit display format ç·¨è¼¯é¡¯ç¤ºæ ¼å¼ Edit the display format of the data in this column 編輯此欄ä½ä¸­è³‡æ–™çš„é¡¯ç¤ºæ ¼å¼ New Record 新記錄 Insert a new record in the current table 在目å‰çš„資料表中æ’入新記錄 <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> <html><head/><body><p>æ­¤æŒ‰éˆ•åœ¨è³‡æ–™åº«ä¸­å»ºç«‹æ–°è¨˜éŒ„ã€‚æŒ‰ä½æ»‘鼠按鈕以開啟ä¸åŒé¸é …的彈出å¼é¸å–®ï¼š</p><ul><li><span style=" font-weight:600;">新記錄</span>:在資料庫中æ’入具有é è¨­å€¼çš„æ–°è¨˜éŒ„。</li><li><span style=" font-weight:600;">æ’入值...</span>:在將值æ’入資料庫之å‰ï¼Œé–‹å•Ÿä¸€å€‹å°è©±æ¡†ä»¥è¼¸å…¥å€¼ã€‚這å…許輸入滿足ä¸åŒç´„æŸçš„值。如果 <span style=" font-weight:600;">新記錄</span> é¸é …由於這些約æŸè€Œå¤±æ•—,則也會開啟此å°è©±æ¡†ã€‚</li></ul></body></html> Delete Record 刪除記錄 Delete the current record 刪除目å‰çš„記錄 This button deletes the record or records currently selected in the table 此按鈕刪除目å‰åœ¨è³‡æ–™è¡¨ä¸­é¸æ“‡çš„記錄或記錄 Insert new record using default values in browsed table 在ç€è¦½çš„資料表中使用é è¨­å€¼æ’入新記錄 Insert Values... æ’入值... Open a dialog for inserting values in a new record 開啟一個å°è©±æ¡†ä»¥åœ¨æ–°è¨˜éŒ„中æ’入值 Export to &CSV 匯出為 &CSV Export the filtered data to CSV 將篩é¸å¾Œçš„資料匯出為 CSV This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. 此按鈕將ç€è¦½çš„資料表的資料匯出為 CSV 檔,其內容為目å‰é¡¯ç¤ºçš„內容(篩é¸ã€é¡¯ç¤ºæ ¼å¼å’ŒæŽ’åºæ¬„ä½ä¹‹å¾Œï¼‰ã€‚ Save as &view å¦å­˜ç‚ºæª¢è¦–表(&V) Save the current filter, sort column and display formats as a view 將目å‰çš„篩é¸ã€æŽ’åºæ¬„ä½å’Œé¡¯ç¤ºæ ¼å¼å¦å­˜ç‚ºæª¢è¦–表 This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. 此按鈕將ç€è¦½çš„資料表的目å‰è¨­å®šï¼ˆç¯©é¸ã€é¡¯ç¤ºæ ¼å¼å’ŒæŽ’åºæ¬„ä½ï¼‰å¦å­˜ç‚º SQL 檢視表,您ç¨å¾Œå¯ä»¥ç€è¦½æˆ–在 SQL 陳述å¼ä¸­ä½¿ç”¨ã€‚ Save Table As... 將資料表å¦å­˜ç‚º... Save the table as currently displayed 將資料表å¦å­˜ç‚ºç›®å‰é¡¯ç¤ºçš„內容 <html><head/><body><p>This pop-up menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> <html><head/><body><p>此彈出å¼é¸å–®æä¾›ä»¥ä¸‹é©ç”¨æ–¼ç›®å‰ç€è¦½å’Œç¯©é¸çš„資料表的é¸é …:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">匯出至 CSV:此é¸é …å°‡ç€è¦½çš„資料表的資料匯出為 CSV 檔,其內容為目å‰é¡¯ç¤ºçš„內容(篩é¸ã€é¡¯ç¤ºæ ¼å¼å’ŒæŽ’åºæ¬„ä½ä¹‹å¾Œï¼‰ã€‚</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">å¦å­˜ç‚ºæª¢è¦–表:此é¸é …å°‡ç€è¦½çš„資料表的目å‰è¨­å®šï¼ˆç¯©é¸ã€é¡¯ç¤ºæ ¼å¼å’ŒæŽ’åºæ¬„ä½ï¼‰å¦å­˜ç‚º SQL 檢視表,您ç¨å¾Œå¯ä»¥ç€è¦½æˆ–在 SQL 陳述å¼ä¸­ä½¿ç”¨ã€‚</li></ul></body></html> Hide column(s) éš±è—æ¬„ä½ Hide selected column(s) éš±è—鏿“‡çš„æ¬„ä½ Show all columns é¡¯ç¤ºæ‰€æœ‰æ¬„ä½ Show all columns that were hidden 顯示所有被隱è—çš„æ¬„ä½ Set encoding 設定編碼 Change the encoding of the text in the table cells 變更資料表格中的文字編碼 Set encoding for all tables 設定所有資料表的編碼 Change the default encoding assumed for all tables in the database 變更資料庫中所有資料表é è¨­çš„編碼 Clear Filters æ¸…é™¤ç¯©é¸ Clear all filters æ¸…é™¤æ‰€æœ‰ç¯©é¸ This button clears all the filters set in the header input fields for the currently browsed table. 此按鈕清除目å‰ç€è¦½çš„資料表的標頭輸入欄ä½ä¸­è¨­å®šçš„æ‰€æœ‰ç¯©é¸ã€‚ Clear Sorting æ¸…é™¤æŽ’åº Reset the order of rows to the default 將列的順åºé‡è¨­ç‚ºé è¨­ This button clears the sorting columns specified for the currently browsed table and returns to the default order. 此按鈕清除目å‰ç€è¦½çš„è³‡æ–™è¡¨ä¸­æŒ‡å®šçš„æŽ’åºæ¬„ä½ï¼Œä¸¦å›žåˆ°é è¨­çš„é †åºã€‚ Print åˆ—å° Print currently browsed table data 列å°ç›®å‰ç€è¦½çš„資料表資料 Print currently browsed table data. Print selection if more than one cell is selected. 列å°ç›®å‰ç€è¦½çš„è³‡æ–™è¡¨è³‡æ–™ã€‚å¦‚æžœé¸æ“‡äº†å¤šå€‹å„²å­˜æ ¼ï¼Œå‰‡åˆ—å°é¸æ“‡çš„內容。 Ctrl+P Ctrl+P Refresh 釿–°æ•´ç† Refresh the data in the selected table 釿–°æ•´ç†é¸æ“‡çš„資料表中的資料 This button refreshes the data in the currently selected table. æ­¤æŒ‰éˆ•é‡æ–°æ•´ç†ç›®å‰é¸æ“‡çš„資料表中的資料。 F5 F5 Find in cells 在儲存格中尋找 Open the find tool bar which allows you to search for values in the table view below. 開啟尋找工具列,讓您å¯ä»¥åœ¨ä¸‹æ–¹çš„資料表檢視表中æœå°‹æ•¸å€¼ã€‚ Bold ç²—é«” Ctrl+B Ctrl+B Italic 斜體 Underline 底線 Ctrl+U Ctrl+U Align Right é å³å°é½Š Align Left é å·¦å°é½Š Center Horizontally 水平置中 Justify å·¦å³å°é½Š Edit Conditional Formats... 編輯æ¢ä»¶æ ¼å¼... Edit conditional formats for the current column ç·¨è¼¯ç›®å‰æ¬„ä½çš„æ¢ä»¶æ ¼å¼ Clear Format æ¸…é™¤æ ¼å¼ Clear All Formats æ¸…é™¤æ‰€æœ‰æ ¼å¼ Clear all cell formatting from selected cells and all conditional formats from selected columns æ¸…é™¤é¸æ“‡çš„儲存格中的所有儲存格格å¼ï¼Œä»¥åŠé¸æ“‡çš„æ¬„ä½ä¸­çš„æ‰€æœ‰æ¢ä»¶æ ¼å¼ Font Color å­—åž‹é¡è‰² Background Color 背景é¡è‰² Toggle Format Toolbar åˆ‡æ›æ ¼å¼å·¥å…·åˆ— Show/hide format toolbar 顯示/éš±è—æ ¼å¼å·¥å…·åˆ— This button shows or hides the formatting toolbar of the Data Browser 此按鈕顯示或隱è—資料ç€è¦½å™¨çš„æ ¼å¼å·¥å…·åˆ— Select column 鏿“‡æ¬„ä½ Ctrl+Space Ctrl+ç©ºç™½éµ Replace text in cells å–代儲存格中的文字 Freeze columns å‡çµæ¬„ä½ Make all columns from the first column up to this column not move when scrolling horizontally 讓從第一個欄ä½åˆ°æ­¤æ¬„ä½çš„æ‰€æœ‰æ¬„ä½åœ¨æ°´å¹³æ²å‹•時ä¸ç§»å‹• Filter in any column 在任何欄ä½ä¸­ç¯©é¸ Ctrl+R Ctrl+R %n row(s) %n 列 , %n column(s) ,%n æ¬„ä½ . Sum: %1; Average: %2; Min: %3; Max: %4 . 總計:%1;平å‡ï¼š%2;最å°å€¼ï¼š%3;最大值:%4 Conditional formats for "%1" "%1" çš„æ¢ä»¶å¼æ ¼å¼ determining row count... 正在計算列數... %L1 - %L2 of >= %L3 %L1 - %L2 / 總數 >= %L3 %L1 - %L2 of %L3 %L1 - %L2 / 總數 %L3 (clipped at %L1 rows) (在 %L1 列處截斷) Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. 請輸入一個å½ä¸»éµä»¥å•Ÿç”¨æ­¤æª¢è¦–表的編輯功能。這應該是檢視表中一個唯一欄ä½çš„å稱。 Delete Records 刪除記錄 Duplicate records 複製記錄 Duplicate record 複製記錄 Ctrl+" Ctrl+" Adjust rows to contents èª¿æ•´åˆ—ä»¥é©æ‡‰å…§å®¹ Error deleting record: %1 刪除記錄時出ç¾éŒ¯èª¤ï¼š %1 Please select a record first è«‹å…ˆé¸æ“‡ä¸€ç­†è¨˜éŒ„ Please choose a new encoding for all tables. è«‹ç‚ºæ‰€æœ‰è³‡æ–™è¡¨é¸æ“‡æ–°çš„編碼。 Please choose a new encoding for this table. è«‹ç‚ºæ­¤è³‡æ–™è¡¨é¸æ“‡æ–°çš„編碼。 %1 Leave the field empty for using the database encoding. %1 留空此欄ä½ä»¥ä½¿ç”¨è³‡æ–™åº«ç·¨ç¢¼ã€‚ This encoding is either not valid or not supported. 此編碼無效或ä¸è¢«æ”¯æ´ã€‚ %1 replacement(s) made. 已進行 %1 次å–代。 TableBrowserDock New Data Browser 新資料ç€è¦½å™¨ Rename Data Browser 釿–°å‘½å資料ç€è¦½å™¨ Close Data Browser 關閉資料ç€è¦½å™¨ Set a new name for the data browser. Use the '&&' character to allow using the following character as a keyboard shortcut. 為資料ç€è¦½å™¨è¨­å®šæ–°å稱。使用 '&&' 字元以å…許使用後續字元作為éµç›¤å¿«æ·éµã€‚ VacuumDialog Compact Database 壓縮資料庫 Warning: Compacting the database will commit all of your changes. 警告:壓縮資料庫將會æäº¤æ‰€æœ‰æ‚¨çš„變更。 Please select the databases to co&mpact: è«‹é¸æ“‡è¦å£“縮的資料庫: sqlitebrowser-sqlitebrowser-5733cb7/src/translations/translations.qrc000066400000000000000000000020371463772530400264360ustar00rootroot00000000000000 sqlb_ar_SA.qm sqlb_cs.qm sqlb_ru.qm sqlb_de.qm sqlb_fr.qm sqlb_zh.qm sqlb_zh_TW.qm sqlb_pl.qm sqlb_pt_BR.qm sqlb_en_GB.qm sqlb_es_ES.qm sqlb_ko_KR.qm sqlb_tr.qm sqlb_uk_UA.qm sqlb_it.qm sqlb_ja.qm sqlb_nl.qm sqlb_id.qm sqlb_sv.qm sqlb_ro.qm sqlitebrowser-sqlitebrowser-5733cb7/src/version.h.in000066400000000000000000000006541463772530400227330ustar00rootroot00000000000000// version file to be preprocessed by CMake #ifndef GEN_VERSION_H #define GEN_VERSION_H #define MAJOR_VERSION @PROJECT_VERSION_MAJOR@ #define MINOR_VERSION @PROJECT_VERSION_MINOR@ #define PATCH_VERSION @PROJECT_VERSION_PATCH@ #define APP_VERSION "@PROJECT_VERSION@" // If it is defined by the compiler, then it is a nightly build, and in the YYYYMMDD format. #ifndef BUILD_VERSION #define BUILD_VERSION "0" #endif #endif sqlitebrowser-sqlitebrowser-5733cb7/src/winapp.rc000066400000000000000000000017601463772530400223130ustar00rootroot00000000000000#include #include "version.h" VS_VERSION_INFO VERSIONINFO FILEVERSION MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, 0 PRODUCTVERSION MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, 0 FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "000004B0" BEGIN VALUE "FileVersion", APP_VERSION "." BUILD_VERSION VALUE "ProductVersion", APP_VERSION "." BUILD_VERSION VALUE "FileDescription", "DB Browser for SQLite" VALUE "ProductName", "DB Browser for SQLite" VALUE "InternalName", "DB Browser for SQLite" VALUE "OriginalFilename", "DB Browser for SQLite.exe" VALUE "CompanyName", "DB Browser for SQLite Team" VALUE "LegalCopyright", "Copyright © DB Browser for SQLite Team" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0000, 0x04B0 END END IDI_DB4S ICON "iconwin.ico" sqlitebrowser-sqlitebrowser-5733cb7/tests/000077500000000000000000000000001463772530400210365ustar00rootroot00000000000000sqlitebrowser-sqlitebrowser-5733cb7/tests/createtestdb.py000077500000000000000000000015321463772530400240650ustar00rootroot00000000000000#!/usr/bin/python import sys import os import random import string import sqlite3 CREATE = """ CREATE TABLE IF NOT EXISTS hugetable ( id INTEGER PRIMARY KEY AUTOINCREMENT, weirdtext TEXT, crazynumber REAL ); """ def main(): if len(sys.argv) != 2: sys.exit("please specify the db filename") with sqlite3.connect(sys.argv[1]) as c: c.executescript(CREATE) rowcount = 1000000 for i in range(rowcount): text = "".join( [random.choice(string.ascii_letters) for i in range(200)] ) num = random.random() * random.randint(0, 2930) c.execute("INSERT INTO hugetable(weirdtext, crazynumber) VALUES ( :t, :n);", {"t": text, "n": num}) if i % 1000 == 0: print("inserted", i, "of", rowcount) c.commit() if __name__ == "__main__": main()